From 0312df1ba53d29a6951cb7c87a75e75798bebcda Mon Sep 17 00:00:00 2001 From: TARKZiM Date: Thu, 5 Nov 2020 10:30:47 +0800 Subject: [PATCH 001/528] Revert "arm: dts: msm8994-v2: underclock a57 cores to 1.5GHz and a53 cores to 1.3GHz." This reverts commit cc60ad48c121b237a52334d64f26d8cfbbfb9b97. --- arch/arm/boot/dts/qcom/msm8994-v2.dtsi | 54 ++++++++++++++++++++------ 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8994-v2.dtsi b/arch/arm/boot/dts/qcom/msm8994-v2.dtsi index 9c078cceabaa..add83045413a 100644 --- a/arch/arm/boot/dts/qcom/msm8994-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-v2.dtsi @@ -81,7 +81,9 @@ < 864000000 8>, < 960000000 9>, < 1248000000 10>, - < 1344000000 11>; + < 1344000000 11>, + < 1478400000 12>, + < 1555200000 13>; qcom,a57-speedbin0-v0 = < 0 0>, < 384000000 5>, @@ -93,7 +95,11 @@ < 1248000000 9>, < 1344000000 10>, < 1440000000 11>, - < 1536000000 12>; + < 1536000000 12>, + < 1632000000 13>, + < 1728000000 14>, + < 1824000000 16>, + < 1958400000 17>; qcom,a57-speedbin1-v0 = < 0 0>, < 384000000 5>, @@ -105,7 +111,9 @@ < 1248000000 9>, < 1344000000 10>, < 1440000000 11>, - < 1536000000 12>; + < 1536000000 12>, + < 1632000000 13>, + < 1766400000 15>; qcom,cci-speedbin0-v0 = < 0 0>, < 300000000 4>, @@ -136,7 +144,9 @@ < 864000 >, < 960000 >, < 1248000 >, - < 1344000 >; + < 1344000 >, + < 1478400 >, + < 1555200 >; qcom,cpufreq-table-4 = < 384000 >, @@ -148,7 +158,11 @@ < 1248000 >, < 1344000 >, < 1440000 >, - < 1536000 >; + < 1536000 >, + < 1632000 >, + < 1728000 >, + < 1824000 >, + < 1958400 >; }; &devfreq_cpufreq { @@ -162,7 +176,9 @@ < 864000 4066 >, < 960000 5928 >, < 1248000 7904 >, - < 1344000 9887 >; + < 1344000 9887 >, + < 1478400 11863 >, + < 1555200 11863 >; cpu-to-dev-map-4 = < 384000 1525 >, < 480000 2288 >, @@ -173,7 +189,11 @@ < 1248000 5928 >, < 1344000 7904 >, < 1440000 7904 >, - < 1536000 7904 >; + < 1536000 7904 >, + < 1632000 9887 >, + < 1728000 9887 >, + < 1824000 11863 >, + < 1958400 11863 >; }; mincpubw-cpufreq { @@ -187,7 +207,9 @@ < 864000 1525 >, < 960000 1525 >, < 1248000 1525 >, - < 1344000 1525 >; + < 1344000 1525 >, + < 1478400 1525 >, + < 1555200 1525 >; cpu-to-dev-map-4 = < 384000 1525 >, < 480000 1525 >, @@ -198,7 +220,11 @@ < 1248000 1525 >, < 1344000 1525 >, < 1440000 1525 >, - < 1536000 1525 >; + < 1536000 1525 >, + < 1632000 1525 >, + < 1728000 1525 >, + < 1824000 1525 >, + < 1958400 7904 >; }; cci-cpufreq { @@ -211,7 +237,9 @@ < 864000 537600 >, < 960000 600000 >, < 1248000 729600 >, - < 1344000 787200 >; + < 1344000 787200 >, + < 1478400 787200 >, + < 1555200 787200 >; cpu-to-dev-map-4 = < 384000 300000 >, < 480000 300000 >, @@ -222,7 +250,11 @@ < 1248000 729600 >, < 1344000 729600 >, < 1440000 729600 >, - < 1536000 787200 >; + < 1536000 787200 >, + < 1632000 787200 >, + < 1728000 787200 >, + < 1824000 787200 >, + < 1958400 787200 >; }; }; -- GitLab From ced7acdc4d1bf7af8343b2aa715a1770cca961c1 Mon Sep 17 00:00:00 2001 From: "Kevin F. Haggerty" Date: Fri, 11 Dec 2020 07:27:25 -0700 Subject: [PATCH 002/528] fs: sdfat: Update to version 2.4.5 * Samsung source G981USQU1CTKH Signed-off-by: Kevin F. Haggerty Change-Id: I79b75d2e47e9be33b311b8d72ac92c66b45a7df1 --- fs/sdfat/Kconfig | 9 +- fs/sdfat/amap_smart.c | 3 +- fs/sdfat/blkdev.c | 30 ++++-- fs/sdfat/core.c | 39 ++++---- fs/sdfat/core.h | 10 +- fs/sdfat/core_exfat.c | 63 ++++++++----- fs/sdfat/core_fat.c | 144 ++++++++++++++--------------- fs/sdfat/fatent.c | 7 -- fs/sdfat/misc.c | 25 ++--- fs/sdfat/mpage.c | 177 ++++++++++++++++++++++++++--------- fs/sdfat/sdfat.c | 209 +++++++++++++++++++++++++++++++----------- fs/sdfat/sdfat.h | 36 +++++++- fs/sdfat/sdfat_fs.h | 73 +++++++-------- fs/sdfat/version.h | 2 +- fs/sdfat/xattr.c | 10 ++ 15 files changed, 546 insertions(+), 291 deletions(-) diff --git a/fs/sdfat/Kconfig b/fs/sdfat/Kconfig index 683f1213ef7f..a5f4d669b09f 100644 --- a/fs/sdfat/Kconfig +++ b/fs/sdfat/Kconfig @@ -69,15 +69,18 @@ config SDFAT_CHECK_RO_ATTR config SDFAT_ALIGNED_MPAGE_WRITE bool "Enable supporting aligned mpage_write" - default y + default y if SDFAT_FS=y + default n if SDFAT_FS=m depends on SDFAT_FS config SDFAT_VIRTUAL_XATTR bool "Virtual xattr support for sdFAT" - default y + default n depends on SDFAT_FS help - To support virtual xattr. + If you enable this feature, it supports virtual xattr. + This feature will be deprecated because it might be the same with + "context" mount option. config SDFAT_VIRTUAL_XATTR_SELINUX_LABEL string "Default string for SELinux label" diff --git a/fs/sdfat/amap_smart.c b/fs/sdfat/amap_smart.c index 5a76bd96bd44..46c35894a5f2 100644 --- a/fs/sdfat/amap_smart.c +++ b/fs/sdfat/amap_smart.c @@ -705,7 +705,8 @@ static inline AU_INFO_T *amap_get_packing_au(AMAP_T *amap, int dest, int num_to_ } } - if ((PACKING_HARDLIMIT) && amap->n_need_packing >= PACKING_HARDLIMIT) { + if ((PACKING_HARDLIMIT != 0) && + amap->n_need_packing >= PACKING_HARDLIMIT) { /* Compulsory SLC flushing: * If there was no chance to do best-fit packing * and the # of AU-aligned allocation exceeds HARD threshold, diff --git a/fs/sdfat/blkdev.c b/fs/sdfat/blkdev.c index 264c670df0f0..788b7c034afc 100644 --- a/fs/sdfat/blkdev.c +++ b/fs/sdfat/blkdev.c @@ -96,7 +96,6 @@ s32 bdev_check_bdi_valid(struct super_block *sb) fsi->prev_eio |= SDFAT_EIO_BDI; sdfat_log_msg(sb, KERN_ERR, "%s: block device is " "eliminated.(bdi:%p)", __func__, sb->s_bdi); - sdfat_debug_warn_on(1); } return -ENXIO; } @@ -104,18 +103,13 @@ s32 bdev_check_bdi_valid(struct super_block *sb) return 0; } - -/* Make a readahead request */ -s32 bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) +#if IS_BUILTIN(CONFIG_SDFAT_FS) +static void __bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) { - FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); u32 sects_per_page = (PAGE_SIZE >> sb->s_blocksize_bits); struct blk_plug plug; u64 i; - if (!fsi->bd_opened) - return -EIO; - blk_start_plug(&plug); for (i = 0; i < num_secs; i++) { if (i && !(i & (sects_per_page - 1))) @@ -123,6 +117,26 @@ s32 bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) sb_breadahead(sb, (sector_t)(secno + i)); } blk_finish_plug(&plug); +} +#else +static void __bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) +{ + u64 i; + + for (i = 0; i < num_secs; i++) + sb_breadahead(sb, (sector_t)(secno + i)); +} +#endif + +/* Make a readahead request */ +s32 bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) +{ + FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + + if (!fsi->bd_opened) + return -EIO; + + __bdev_readahead(sb, secno, num_secs); return 0; } diff --git a/fs/sdfat/core.c b/fs/sdfat/core.c index 5a1e0e41591a..a1f7feeffcb8 100644 --- a/fs/sdfat/core.c +++ b/fs/sdfat/core.c @@ -158,7 +158,7 @@ static s32 __fs_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_s /* skip updating volume dirty flag, * if this volume has been mounted with read-only */ - if (sb->s_flags & MS_RDONLY) + if (sb_rdonly(sb)) return 0; if (!fsi->pbr_bh) { @@ -177,7 +177,8 @@ static s32 __fs_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_s bpb->bsx.state = new_flag & VOL_DIRTY ? FAT_VOL_DIRTY : 0x00; } else { /* FAT16/12 */ pbr16_t *bpb = (pbr16_t *) fsi->pbr_bh->b_data; - bpb->bpb.state = new_flag & VOL_DIRTY ? FAT_VOL_DIRTY : 0x00; + bpb->bpb.f16.state = new_flag & VOL_DIRTY ? + FAT_VOL_DIRTY : 0x00; } if (always_sync) @@ -1655,7 +1656,7 @@ static bool is_exfat(pbr_t *pbr) static bool is_fat32(pbr_t *pbr) { - if (le16_to_cpu(pbr->bpb.f16.num_fat_sectors)) + if (le16_to_cpu(pbr->bpb.fat.num_fat_sectors)) return false; return true; } @@ -1668,7 +1669,7 @@ pbr_t *read_pbr_with_logical_sector(struct super_block *sb, struct buffer_head * if (is_exfat(p_pbr)) logical_sect = 1 << p_pbr->bsx.f64.sect_size_bits; else - logical_sect = get_unaligned_le16(&p_pbr->bpb.f16.sect_size); + logical_sect = get_unaligned_le16(&p_pbr->bpb.fat.sect_size); /* is x a power of 2? * (x) != 0 && (((x) & ((x) - 1)) == 0) @@ -1780,18 +1781,6 @@ s32 fscore_mount(struct super_block *sb) opts->improved_allocation = 0; opts->defrag = 0; ret = mount_exfat(sb, p_pbr); - } else if (is_fat32(p_pbr)) { - if (opts->fs_type && opts->fs_type != FS_TYPE_VFAT) { - sdfat_log_msg(sb, KERN_ERR, - "not specified filesystem type " - "(media:vfat, opts:%s)", - FS_TYPE_STR[opts->fs_type]); - ret = -EINVAL; - goto free_bh; - } - /* set maximum file size for FAT */ - sb->s_maxbytes = 0xffffffff; - ret = mount_fat32(sb, p_pbr); } else { if (opts->fs_type && opts->fs_type != FS_TYPE_VFAT) { sdfat_log_msg(sb, KERN_ERR, @@ -1803,9 +1792,14 @@ s32 fscore_mount(struct super_block *sb) } /* set maximum file size for FAT */ sb->s_maxbytes = 0xffffffff; - opts->improved_allocation = 0; - opts->defrag = 0; - ret = mount_fat16(sb, p_pbr); + + if (is_fat32(p_pbr)) { + ret = mount_fat32(sb, p_pbr); + } else { + opts->improved_allocation = 0; + opts->defrag = 0; + ret = mount_fat16(sb, p_pbr); + } } free_bh: brelse(tmp_bh); @@ -1817,8 +1811,9 @@ free_bh: /* warn misaligned data data start sector must be a multiple of clu_size */ sdfat_log_msg(sb, KERN_INFO, "detected volume info : %s " - "(bps : %lu, spc : %u, data start : %llu, %s)", + "(%04hX-%04hX, bps : %lu, spc : %u, data start : %llu, %s)", sdfat_get_vol_type_str(fsi->vol_type), + (fsi->vol_id >> 16) & 0xffff, fsi->vol_id & 0xffff, sb->s_blocksize, fsi->sect_per_clus, fsi->data_start_sector, (fsi->data_start_sector & (fsi->sect_per_clus - 1)) ? "misaligned" : "aligned"); @@ -2374,7 +2369,7 @@ s32 fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 cou ep2 = ep; } - fsi->fs_func->set_entry_time(ep, tm_now(SDFAT_SB(sb), &tm), TM_MODIFY); + fsi->fs_func->set_entry_time(ep, tm_now(inode, &tm), TM_MODIFY); fsi->fs_func->set_entry_attr(ep, fid->attr); if (modified) { @@ -2581,7 +2576,7 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size) ep2 = ep; } - fsi->fs_func->set_entry_time(ep, tm_now(SDFAT_SB(sb), &tm), TM_MODIFY); + fsi->fs_func->set_entry_time(ep, tm_now(inode, &tm), TM_MODIFY); fsi->fs_func->set_entry_attr(ep, fid->attr); /* diff --git a/fs/sdfat/core.h b/fs/sdfat/core.h index 1f8ed5a28ef3..a03f8c0a168a 100644 --- a/fs/sdfat/core.h +++ b/fs/sdfat/core.h @@ -60,7 +60,15 @@ typedef struct { void *__buf; // __buf should be the last member } ENTRY_SET_CACHE_T; - +/*----------------------------------------------------------------------*/ +/* Inline Functions */ +/*----------------------------------------------------------------------*/ +static inline bool is_valid_clus(FS_INFO_T *fsi, u32 clus) +{ + if (clus < CLUS_BASE || fsi->num_clusters <= clus) + return false; + return true; +} /*----------------------------------------------------------------------*/ /* External Function Declarations */ diff --git a/fs/sdfat/core_exfat.c b/fs/sdfat/core_exfat.c index cde772057445..da401bbbed22 100644 --- a/fs/sdfat/core_exfat.c +++ b/fs/sdfat/core_exfat.c @@ -220,20 +220,27 @@ static void exfat_set_entry_size(DENTRY_T *p_entry, u64 size) ep->size = cpu_to_le64(size); } /* end of exfat_set_entry_size */ + +#define TENS_MS_PER_SEC (100) +#define SEC_TO_TENS_MS(sec) (((sec) & 0x01) ? TENS_MS_PER_SEC : 0) +#define TENS_MS_TO_SEC(tens_ms) (((tens_ms) / TENS_MS_PER_SEC) ? 1 : 0) + static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) { - u16 t = 0x00, d = 0x21, tz = 0x00; + u16 t = 0x00, d = 0x21, tz = 0x00, s = 0x00; FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry; switch (mode) { case TM_CREATE: t = le16_to_cpu(ep->create_time); d = le16_to_cpu(ep->create_date); + s = TENS_MS_TO_SEC(ep->create_time_ms); tz = ep->create_tz; break; case TM_MODIFY: t = le16_to_cpu(ep->modify_time); d = le16_to_cpu(ep->modify_date); + s = TENS_MS_TO_SEC(ep->modify_time_ms); tz = ep->modify_tz; break; case TM_ACCESS: @@ -244,7 +251,7 @@ static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) } tp->tz.value = tz; - tp->sec = (t & 0x001F) << 1; + tp->sec = ((t & 0x001F) << 1) + s; tp->min = (t >> 5) & 0x003F; tp->hour = (t >> 11); tp->day = (d & 0x001F); @@ -263,12 +270,14 @@ static void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) switch (mode) { case TM_CREATE: ep->create_time = cpu_to_le16(t); + ep->create_time_ms = SEC_TO_TENS_MS(tp->sec); ep->create_date = cpu_to_le16(d); ep->create_tz = tp->tz.value; break; case TM_MODIFY: ep->modify_time = cpu_to_le16(t); ep->modify_date = cpu_to_le16(d); + ep->modify_time_ms = (tp->sec & 0x1) ? TENS_MS_PER_SEC : 0; ep->modify_tz = tp->tz.value; break; case TM_ACCESS: @@ -286,12 +295,10 @@ static void __init_file_entry(struct super_block *sb, FILE_DENTRY_T *ep, u32 typ exfat_set_entry_type((DENTRY_T *) ep, type); - tp = tm_now(SDFAT_SB(sb), &tm); + tp = tm_now_sb(sb, &tm); exfat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); exfat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS); - ep->create_time_ms = 0; - ep->modify_time_ms = 0; } /* end of __init_file_entry */ static void __init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size) @@ -1279,7 +1286,7 @@ static s32 exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_r } /* check cluster validation */ - if ((p_chain->dir < 2) && (p_chain->dir >= fsi->num_clusters)) { + if (!is_valid_clus(fsi, p_chain->dir)) { EMSG("%s: invalid start cluster (%u)\n", __func__, p_chain->dir); sdfat_debug_bug_on(1); return -EIO; @@ -1367,9 +1374,13 @@ static s32 exfat_alloc_cluster(struct super_block *sb, u32 num_alloc, CHAIN_T *p } /* check cluster validation */ - if ((hint_clu < CLUS_BASE) && (hint_clu >= fsi->num_clusters)) { - EMSG("%s: hint_cluster is invalid (%u)\n", __func__, hint_clu); - ASSERT(0); + if (!is_valid_clus(fsi, hint_clu)) { + /* "last + 1" can be passed as hint_clu. Otherwise, bug_on */ + if (hint_clu != fsi->num_clusters) { + EMSG("%s: hint_cluster is invalid (%u)\n", + __func__, hint_clu); + sdfat_debug_bug_on(1); + } hint_clu = CLUS_BASE; if (p_chain->flags == 0x03) { if (exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters)) @@ -1508,43 +1519,53 @@ s32 mount_exfat(struct super_block *sb, pbr_t *p_pbr) pbr64_t *p_bpb = (pbr64_t *)p_pbr; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + fsi->sect_per_clus = 1 << p_bpb->bsx.sect_per_clus_bits; + fsi->sect_per_clus_bits = p_bpb->bsx.sect_per_clus_bits; + fsi->cluster_size_bits = fsi->sect_per_clus_bits + sb->s_blocksize_bits; + fsi->cluster_size = 1 << fsi->cluster_size_bits; + if (!p_bpb->bsx.num_fats) { sdfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); return -EINVAL; } - fsi->sect_per_clus = 1 << p_bpb->bsx.sect_per_clus_bits; - fsi->sect_per_clus_bits = p_bpb->bsx.sect_per_clus_bits; - fsi->cluster_size_bits = fsi->sect_per_clus_bits + sb->s_blocksize_bits; - fsi->cluster_size = 1 << fsi->cluster_size_bits; + if (p_bpb->bsx.num_fats >= 2) { + sdfat_msg(sb, KERN_WARNING, + "unsupported number of FAT structure :%u, try with 1", + p_bpb->bsx.num_fats); + } fsi->num_FAT_sectors = le32_to_cpu(p_bpb->bsx.fat_length); + if (!fsi->num_FAT_sectors) { + sdfat_msg(sb, KERN_ERR, "bogus fat size"); + return -EINVAL; + } fsi->FAT1_start_sector = le32_to_cpu(p_bpb->bsx.fat_offset); - if (p_bpb->bsx.num_fats == 1) - fsi->FAT2_start_sector = fsi->FAT1_start_sector; - else - fsi->FAT2_start_sector = fsi->FAT1_start_sector + fsi->num_FAT_sectors; + fsi->FAT2_start_sector = fsi->FAT1_start_sector; fsi->root_start_sector = le32_to_cpu(p_bpb->bsx.clu_offset); fsi->data_start_sector = fsi->root_start_sector; fsi->num_sectors = le64_to_cpu(p_bpb->bsx.vol_length); - fsi->num_clusters = le32_to_cpu(p_bpb->bsx.clu_count) + 2; + if (!fsi->num_sectors) { + sdfat_msg(sb, KERN_ERR, "bogus number of total sector count"); + return -EINVAL; + } + /* because the cluster index starts with 2 */ + fsi->num_clusters = le32_to_cpu(p_bpb->bsx.clu_count) + CLUS_BASE; - fsi->vol_type = EXFAT; fsi->vol_id = le32_to_cpu(p_bpb->bsx.vol_serial); - fsi->root_dir = le32_to_cpu(p_bpb->bsx.root_cluster); fsi->dentries_in_root = 0; fsi->dentries_per_clu = 1 << (fsi->cluster_size_bits - DENTRY_SIZE_BITS); - fsi->vol_flag = (u32) le16_to_cpu(p_bpb->bsx.vol_flags); fsi->clu_srch_ptr = CLUS_BASE; fsi->used_clusters = (u32) ~0; fsi->fs_func = &exfat_fs_func; + fsi->vol_type = EXFAT; fat_ent_ops_init(sb); if (p_bpb->bsx.vol_flags & VOL_DIRTY) { diff --git a/fs/sdfat/core_fat.c b/fs/sdfat/core_fat.c index 5e0a196ae42b..23c134fc5541 100644 --- a/fs/sdfat/core_fat.c +++ b/fs/sdfat/core_fat.c @@ -176,7 +176,7 @@ static s32 fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_rel } /* check cluster validation */ - if ((p_chain->dir < 2) && (p_chain->dir >= fsi->num_clusters)) { + if (!is_valid_clus(fsi, p_chain->dir)) { EMSG("%s: invalid start cluster (%u)\n", __func__, p_chain->dir); sdfat_debug_bug_on(1); return -EIO; @@ -479,7 +479,7 @@ static void __init_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, u32 type, ep->start_clu_hi = cpu_to_le16(CLUSTER_16(start_clu >> 16)); ep->size = 0; - tp = tm_now(SDFAT_SB(sb), &tm); + tp = tm_now_sb(sb, &tm); fat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); fat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); ep->access_date = 0; @@ -1238,36 +1238,70 @@ static FS_FUNC_T amap_fat_fs_func = { .get_au_stat = amap_get_au_stat, }; -s32 mount_fat16(struct super_block *sb, pbr_t *p_pbr) +static s32 mount_fat_common(struct super_block *sb, FS_INFO_T *fsi, + bpb_t *p_bpb, u32 root_sects) { - s32 num_root_sectors; - bpb16_t *p_bpb = &(p_pbr->bpb.f16); - FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + bool fat32 = root_sects == 0 ? true : false; - if (!p_bpb->num_fats) { - sdfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); + fsi->sect_per_clus = p_bpb->sect_per_clus; + if (!is_power_of_2(fsi->sect_per_clus)) { + sdfat_msg(sb, KERN_ERR, "bogus sectors per cluster %u", + fsi->sect_per_clus); return -EINVAL; } - num_root_sectors = get_unaligned_le16(p_bpb->num_root_entries) << DENTRY_SIZE_BITS; - num_root_sectors = ((num_root_sectors-1) >> sb->s_blocksize_bits) + 1; - - fsi->sect_per_clus = p_bpb->sect_per_clus; fsi->sect_per_clus_bits = ilog2(p_bpb->sect_per_clus); fsi->cluster_size_bits = fsi->sect_per_clus_bits + sb->s_blocksize_bits; fsi->cluster_size = 1 << fsi->cluster_size_bits; + fsi->dentries_per_clu = 1 << + (fsi->cluster_size_bits - DENTRY_SIZE_BITS); + + fsi->vol_flag = VOL_CLEAN; + fsi->clu_srch_ptr = CLUS_BASE; + fsi->used_clusters = (u32)~0; + fsi->fs_func = &fat_fs_func; fsi->num_FAT_sectors = le16_to_cpu(p_bpb->num_fat_sectors); + if (fat32) { + u32 fat32_len = le32_to_cpu(p_bpb->f32.num_fat32_sectors); + + if (fat32_len) { + fsi->num_FAT_sectors = fat32_len; + } else if (fsi->num_FAT_sectors) { + /* SPEC violation for compatibility */ + sdfat_msg(sb, KERN_WARNING, + "no fatsz32, try with fatsz16: %u", + fsi->num_FAT_sectors); + } + } + + if (!fsi->num_FAT_sectors) { + sdfat_msg(sb, KERN_ERR, "bogus fat size"); + return -EINVAL; + } + + if (!p_bpb->num_fats) { + sdfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); + return -EINVAL; + } + + if (p_bpb->num_fats > 2) { + sdfat_msg(sb, KERN_WARNING, + "unsupported number of FAT structure :%u, try with 2", + p_bpb->num_fats); + } fsi->FAT1_start_sector = le16_to_cpu(p_bpb->num_reserved); if (p_bpb->num_fats == 1) fsi->FAT2_start_sector = fsi->FAT1_start_sector; else - fsi->FAT2_start_sector = fsi->FAT1_start_sector + fsi->num_FAT_sectors; + fsi->FAT2_start_sector = fsi->FAT1_start_sector + + fsi->num_FAT_sectors; fsi->root_start_sector = fsi->FAT2_start_sector + fsi->num_FAT_sectors; - fsi->data_start_sector = fsi->root_start_sector + num_root_sectors; + fsi->data_start_sector = fsi->root_start_sector + root_sects; + /* SPEC violation for compatibility */ fsi->num_sectors = get_unaligned_le16(p_bpb->num_sectors); if (!fsi->num_sectors) fsi->num_sectors = le32_to_cpu(p_bpb->num_huge_sectors); @@ -1277,15 +1311,20 @@ s32 mount_fat16(struct super_block *sb, pbr_t *p_pbr) return -EINVAL; } - fsi->num_clusters = (u32)((fsi->num_sectors - fsi->data_start_sector) >> fsi->sect_per_clus_bits) + CLUS_BASE; /* because the cluster index starts with 2 */ + fsi->num_clusters = (u32)((fsi->num_sectors - fsi->data_start_sector) >> + fsi->sect_per_clus_bits) + CLUS_BASE; - fsi->vol_type = FAT16; - if (fsi->num_clusters < FAT12_THRESHOLD) - fsi->vol_type = FAT12; + return 0; +} - fsi->vol_id = get_unaligned_le32(p_bpb->vol_serial); +s32 mount_fat16(struct super_block *sb, pbr_t *p_pbr) +{ + u32 num_root_sectors; + bpb_t *p_bpb = &(p_pbr->bpb.fat); + FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + fsi->vol_id = get_unaligned_le32(p_bpb->f16.vol_serial); fsi->root_dir = 0; fsi->dentries_in_root = get_unaligned_le16(p_bpb->num_root_entries); if (!fsi->dentries_in_root) { @@ -1294,16 +1333,18 @@ s32 mount_fat16(struct super_block *sb, pbr_t *p_pbr) return -EINVAL; } - fsi->dentries_per_clu = 1 << (fsi->cluster_size_bits - DENTRY_SIZE_BITS); + num_root_sectors = fsi->dentries_in_root << DENTRY_SIZE_BITS; + num_root_sectors = ((num_root_sectors - 1) >> sb->s_blocksize_bits) + 1; - fsi->vol_flag = VOL_CLEAN; - fsi->clu_srch_ptr = 2; - fsi->used_clusters = (u32) ~0; + if (mount_fat_common(sb, fsi, p_bpb, num_root_sectors)) + return -EINVAL; - fsi->fs_func = &fat_fs_func; + fsi->vol_type = FAT16; + if (fsi->num_clusters < FAT12_THRESHOLD) + fsi->vol_type = FAT12; fat_ent_ops_init(sb); - if (p_bpb->state & FAT_VOL_DIRTY) { + if (p_bpb->f16.state & FAT_VOL_DIRTY) { fsi->vol_flag |= VOL_DIRTY; sdfat_log_msg(sb, KERN_WARNING, "Volume was not properly " "unmounted. Some data may be corrupt. " @@ -1347,67 +1388,26 @@ s32 mount_fat32(struct super_block *sb, pbr_t *p_pbr) pbr32_t *p_bpb = (pbr32_t *)p_pbr; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); - if (!p_bpb->bpb.num_fats) { - sdfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); - return -EINVAL; - } - - fsi->sect_per_clus = p_bpb->bpb.sect_per_clus; - fsi->sect_per_clus_bits = ilog2(p_bpb->bpb.sect_per_clus); - fsi->cluster_size_bits = fsi->sect_per_clus_bits + sb->s_blocksize_bits; - fsi->cluster_size = 1 << fsi->cluster_size_bits; - - fsi->num_FAT_sectors = le32_to_cpu(p_bpb->bpb.num_fat32_sectors); - - fsi->FAT1_start_sector = le16_to_cpu(p_bpb->bpb.num_reserved); - if (p_bpb->bpb.num_fats == 1) - fsi->FAT2_start_sector = fsi->FAT1_start_sector; - else - fsi->FAT2_start_sector = fsi->FAT1_start_sector + fsi->num_FAT_sectors; - - fsi->root_start_sector = fsi->FAT2_start_sector + fsi->num_FAT_sectors; - fsi->data_start_sector = fsi->root_start_sector; - - /* SPEC violation for compatibility */ - fsi->num_sectors = get_unaligned_le16(p_bpb->bpb.num_sectors); - if (!fsi->num_sectors) - fsi->num_sectors = le32_to_cpu(p_bpb->bpb.num_huge_sectors); - - /* 2nd check */ - if (!fsi->num_sectors) { - sdfat_msg(sb, KERN_ERR, "bogus number of total sector count"); - return -EINVAL; - } - - fsi->num_clusters = (u32)((fsi->num_sectors - fsi->data_start_sector) >> fsi->sect_per_clus_bits) + CLUS_BASE; - /* because the cluster index starts with 2 */ - - fsi->vol_type = FAT32; fsi->vol_id = get_unaligned_le32(p_bpb->bsx.vol_serial); - - fsi->root_dir = le32_to_cpu(p_bpb->bpb.root_cluster); + fsi->root_dir = le32_to_cpu(p_bpb->bpb.f32.root_cluster); fsi->dentries_in_root = 0; - fsi->dentries_per_clu = 1 << (fsi->cluster_size_bits - DENTRY_SIZE_BITS); - fsi->vol_flag = VOL_CLEAN; - fsi->clu_srch_ptr = 2; - fsi->used_clusters = (u32) ~0; + if (mount_fat_common(sb, fsi, &p_bpb->bpb, 0)) + return -EINVAL; - fsi->fs_func = &fat_fs_func; + /* Should be initialized before calling amap_create() */ + fsi->vol_type = FAT32; + fat_ent_ops_init(sb); /* Delayed / smart allocation related init */ fsi->reserved_clusters = 0; - /* Should be initialized before calling amap_create() */ - fat_ent_ops_init(sb); - /* AU Map Creation */ if (SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_SMART) { u32 hidden_sectors = le32_to_cpu(p_bpb->bpb.num_hid_sectors); u32 calc_hid_sect = 0; int ret; - /* calculate hidden sector size */ calc_hid_sect = __calc_hidden_sect(sb); if (calc_hid_sect != hidden_sectors) { diff --git a/fs/sdfat/fatent.c b/fs/sdfat/fatent.c index fca32a50d336..442a3797fd6e 100644 --- a/fs/sdfat/fatent.c +++ b/fs/sdfat/fatent.c @@ -355,13 +355,6 @@ static inline bool is_reserved_clus(u32 clus) return false; } -static inline bool is_valid_clus(FS_INFO_T *fsi, u32 clus) -{ - if (clus < CLUS_BASE || fsi->num_clusters <= clus) - return false; - return true; -} - s32 fat_ent_get(struct super_block *sb, u32 loc, u32 *content) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); diff --git a/fs/sdfat/misc.c b/fs/sdfat/misc.c index ac1de710b58a..ce08c594f0cb 100644 --- a/fs/sdfat/misc.c +++ b/fs/sdfat/misc.c @@ -55,15 +55,6 @@ /************************************************************************* * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) -#define CURRENT_TIME_SEC timespec64_trunc(current_kernel_time64(), NSEC_PER_SEC) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) -#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC) -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */ - /* EMPTY */ -#endif - - #ifdef CONFIG_SDFAT_UEVENT static struct kobject sdfat_uevent_kobj; @@ -94,6 +85,10 @@ void sdfat_uevent_ro_remount(struct super_block *sb) char major[16], minor[16]; char *envp[] = { major, minor, NULL }; + /* Do not trigger uevent if a device has been ejected */ + if (fsapi_check_bdi_valid(sb)) + return; + snprintf(major, sizeof(major), "MAJOR=%d", MAJOR(bd_dev)); snprintf(minor, sizeof(minor), "MINOR=%d", MINOR(bd_dev)); @@ -127,7 +122,7 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) pr_err("[SDFAT](%s[%d:%d]):ERR: %pV\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); #ifdef CONFIG_SDFAT_SUPPORT_STLOG - if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) { + if (opts->errors == SDFAT_ERRORS_RO && !sb_rdonly(sb)) { ST_LOG("[SDFAT](%s[%d:%d]):ERR: %pV\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); } @@ -138,8 +133,8 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) if (opts->errors == SDFAT_ERRORS_PANIC) { panic("[SDFAT](%s[%d:%d]): fs panic from previous error\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); - } else if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) { - sb->s_flags |= MS_RDONLY; + } else if (opts->errors == SDFAT_ERRORS_RO && !sb_rdonly(sb)) { + sb->s_flags |= SB_RDONLY; sdfat_statistics_set_mnt_ro(); pr_err("[SDFAT](%s[%d:%d]): Filesystem has been set " "read-only\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); @@ -333,12 +328,12 @@ void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, tp->Year = year; } -TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp) +TIMESTAMP_T *tm_now(struct inode *inode, TIMESTAMP_T *tp) { - sdfat_timespec_t ts = CURRENT_TIME_SEC; + sdfat_timespec_t ts = current_time(inode); DATE_TIME_T dt; - sdfat_time_unix2fat(sbi, &ts, &dt); + sdfat_time_unix2fat(SDFAT_SB(inode->i_sb), &ts, &dt); tp->year = dt.Year; tp->mon = dt.Month; diff --git a/fs/sdfat/mpage.c b/fs/sdfat/mpage.c index f550fbb2204a..4f5037768fa5 100644 --- a/fs/sdfat/mpage.c +++ b/fs/sdfat/mpage.c @@ -70,6 +70,9 @@ #ifdef CONFIG_SDFAT_ALIGNED_MPAGE_WRITE +#define MIN_ALIGNED_SIZE (PAGE_SIZE) +#define MIN_ALIGNED_SIZE_MASK (MIN_ALIGNED_SIZE - 1) + /************************************************************************* * INNER FUNCTIONS FOR FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ @@ -97,6 +100,14 @@ static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_ { unmap_underlying_metadata(bdev, block); } + +static inline int wbc_to_write_flags(struct writeback_control *wbc) +{ + if (wbc->sync_mode == WB_SYNC_ALL) + return WRITE_SYNC; + + return 0; +} #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) @@ -236,6 +247,9 @@ static inline unsigned int __calc_size_to_align(struct super_block *sb) if (aligned && (max_sectors & (aligned - 1))) aligned = 0; + + if (aligned && aligned < (MIN_ALIGNED_SIZE >> SECTOR_SIZE_BITS)) + aligned = 0; out: return aligned; } @@ -248,6 +262,24 @@ struct mpage_data { unsigned int size_to_align; }; +/* + * After completing I/O on a page, call this routine to update the page + * flags appropriately + */ +static void __page_write_endio(struct page *page, int err) +{ + if (err) { + struct address_space *mapping; + + SetPageError(page); + mapping = page_mapping(page); + if (mapping) + mapping_set_error(mapping, err); + } + __dfr_writepage_end_io(page); + end_page_writeback(page); +} + /* * I/O completion handler for multipage BIOs. * @@ -262,25 +294,37 @@ struct mpage_data { */ static void __mpage_write_end_io(struct bio *bio, int err) { - struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + struct bio_vec *bv; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) + struct bvec_iter_all iter_all; ASSERT(bio_data_dir(bio) == WRITE); /* only write */ + /* Use bio_for_each_segemnt_all() to support multi-page bvec */ + bio_for_each_segment_all(bv, bio, iter_all) + __page_write_endio(bv->bv_page, err); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) + struct bvec_iter_all iter_all; + int i; + + ASSERT(bio_data_dir(bio) == WRITE); /* only write */ + + /* Use bio_for_each_segemnt_all() to support multi-page bvec */ + bio_for_each_segment_all(bv, bio, i, iter_all) + __page_write_endio(bv->bv_page, err); +#else + ASSERT(bio_data_dir(bio) == WRITE); /* only write */ + bv = bio->bi_io_vec + bio->bi_vcnt - 1; + do { - struct page *page = bvec->bv_page; - - if (--bvec >= bio->bi_io_vec) - prefetchw(&bvec->bv_page->flags); - if (err) { - SetPageError(page); - if (page->mapping) - mapping_set_error(page->mapping, err); - } + struct page *page = bv->bv_page; - __dfr_writepage_end_io(page); + if (--bv >= bio->bi_io_vec) + prefetchw(&bv->bv_page->flags); - end_page_writeback(page); - } while (bvec >= bio->bi_io_vec); + __page_write_endio(page, err); + } while (bv >= bio->bi_io_vec); +#endif bio_put(bio); } @@ -312,6 +356,65 @@ mpage_alloc(struct block_device *bdev, return bio; } + +#if IS_BUILTIN(CONFIG_SDFAT_FS) +#define __write_boundary_block write_boundary_block +#define sdfat_buffer_heads_over_limit buffer_heads_over_limit +#else + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) +/* + * Called when we've recently written block `bblock', and it is known that + * `bblock' was for a buffer_boundary() buffer. This means that the block at + * `bblock + 1' is probably a dirty indirect block. Hunt it down and, if it's + * dirty, schedule it for IO. So that indirects merge nicely with their data. + */ +static void __write_boundary_block(struct block_device *bdev, + sector_t bblock, unsigned int blocksize) +{ + struct buffer_head *bh = __find_get_block(bdev, bblock + 1, blocksize); + + if (bh) { + if (buffer_dirty(bh)) + ll_rw_block(REQ_OP_WRITE, 0, 1, &bh); + put_bh(bh); + } +} +#else +#warning "Need an alternative of write_boundary_block function" +#define __write_boundary_block write_boundary_block +#endif + +#warning "sdfat could not check buffer_heads_over_limit on module. Assumed zero" +#define sdfat_buffer_heads_over_limit (0) +#endif + +static void clean_buffers(struct page *page, unsigned int first_unmapped) +{ + unsigned int buffer_counter = 0; + struct buffer_head *bh, *head; + + if (!page_has_buffers(page)) + return; + head = page_buffers(page); + bh = head; + + do { + if (buffer_counter++ == first_unmapped) + break; + clear_buffer_dirty(bh); + bh = bh->b_this_page; + } while (bh != head); + + /* + * we cannot drop the bh if the page is not uptodate or a concurrent + * readpage would fail to serialize with the bh and it would read from + * disk before we reach the platter. + */ + if (sdfat_buffer_heads_over_limit && PageUptodate(page)) + try_to_free_buffers(page); +} + static int sdfat_mpage_writepage(struct page *page, struct writeback_control *wbc, void *data) { @@ -335,6 +438,7 @@ static int sdfat_mpage_writepage(struct page *page, loff_t i_size = i_size_read(inode); unsigned long end_index = i_size >> PAGE_SHIFT; int ret = 0; + int op_flags = wbc_to_write_flags(wbc); if (page_has_buffers(page)) { struct buffer_head *head = page_buffers(page); @@ -490,22 +594,25 @@ page_is_mapped: */ if (bio) { if (mpd->last_block_in_bio != blocks[0] - 1) { - bio = mpage_bio_submit_write(0, bio); + bio = mpage_bio_submit_write(op_flags, bio); } else if (mpd->size_to_align) { unsigned int mask = mpd->size_to_align - 1; sector_t max_end_block = (__sdfat_bio_sector(bio) & ~(mask)) + mask; - if ((__sdfat_bio_size(bio) != (1 << (mask + 1))) && + if ((__sdfat_bio_size(bio) & MIN_ALIGNED_SIZE_MASK) && (mpd->last_block_in_bio == max_end_block)) { + int op_nomerge = op_flags | REQ_NOMERGE; + MMSG("%s(inode:%p) alignment mpage_bio_submit" - "(start:%u, len:%u aligned:%u)\n", + "(start:%u, len:%u size:%u aligned:%u)\n", __func__, inode, (unsigned int)__sdfat_bio_sector(bio), (unsigned int)(mpd->last_block_in_bio - __sdfat_bio_sector(bio) + 1), + (unsigned int)__sdfat_bio_size(bio), (unsigned int)mpd->size_to_align); - bio = mpage_bio_submit_write(REQ_NOMERGE, bio); + bio = mpage_bio_submit_write(op_nomerge, bio); } } } @@ -525,7 +632,7 @@ alloc_new: */ length = first_unmapped << blkbits; if (bio_add_page(bio, page, length, 0) < length) { - bio = mpage_bio_submit_write(0, bio); + bio = mpage_bio_submit_write(op_flags, bio); goto alloc_new; } @@ -533,26 +640,7 @@ alloc_new: * OK, we have our BIO, so we can now mark the buffers clean. Make * sure to only clean buffers which we know we'll be writing. */ - if (page_has_buffers(page)) { - struct buffer_head *head = page_buffers(page); - struct buffer_head *bh = head; - unsigned int buffer_counter = 0; - - do { - if (buffer_counter++ == first_unmapped) - break; - clear_buffer_dirty(bh); - bh = bh->b_this_page; - } while (bh != head); - - /* - * we cannot drop the bh if the page is not uptodate - * or a concurrent readpage would fail to serialize with the bh - * and it would read from disk before we reach the platter. - */ - if (buffer_heads_over_limit && PageUptodate(page)) - try_to_free_buffers(page); - } + clean_buffers(page, first_unmapped); BUG_ON(PageWriteback(page)); set_page_writeback(page); @@ -579,9 +667,9 @@ alloc_new: unlock_page(page); if (boundary || (first_unmapped != blocks_per_page)) { - bio = mpage_bio_submit_write(0, bio); + bio = mpage_bio_submit_write(op_flags, bio); if (boundary_block) { - write_boundary_block(boundary_bdev, + __write_boundary_block(boundary_bdev, boundary_block, 1 << blkbits); } } else { @@ -592,7 +680,7 @@ alloc_new: confused: if (bio) - bio = mpage_bio_submit_write(0, bio); + bio = mpage_bio_submit_write(op_flags, bio); if (mpd->use_writepage) { ret = mapping->a_ops->writepage(page, wbc); @@ -625,8 +713,11 @@ int sdfat_mpage_writepages(struct address_space *mapping, BUG_ON(!get_block); blk_start_plug(&plug); ret = write_cache_pages(mapping, wbc, sdfat_mpage_writepage, &mpd); - if (mpd.bio) - mpage_bio_submit_write(0, mpd.bio); + if (mpd.bio) { + int op_flags = wbc_to_write_flags(wbc); + + mpage_bio_submit_write(op_flags, mpd.bio); + } blk_finish_plug(&plug); return ret; } diff --git a/fs/sdfat/sdfat.c b/fs/sdfat/sdfat.c index 37630f662fab..9b7a63581160 100644 --- a/fs/sdfat/sdfat.c +++ b/fs/sdfat/sdfat.c @@ -190,6 +190,14 @@ static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_ { unmap_underlying_metadata(bdev, block); } + +static inline int wbc_to_write_flags(struct writeback_control *wbc) +{ + if (wbc->sync_mode == WB_SYNC_ALL) + return WRITE_SYNC; + + return 0; +} #endif @@ -224,9 +232,12 @@ static int setattr_prepare(struct dentry *dentry, struct iattr *attr) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) -static inline void __sdfat_submit_bio_write(struct bio *bio) +static inline void __sdfat_submit_bio_write(struct bio *bio, + struct writeback_control *wbc) { - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + int write_flags = wbc_to_write_flags(wbc); + + bio_set_op_attrs(bio, REQ_OP_WRITE, write_flags); submit_bio(bio); } @@ -240,9 +251,12 @@ static inline unsigned long __sdfat_init_name_hash(const struct dentry *dentry) return init_name_hash(dentry); } #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) */ -static inline void __sdfat_submit_bio_write(struct bio *bio) +static inline void __sdfat_submit_bio_write(struct bio *bio, + struct writeback_control *wbc) { - submit_bio(WRITE, bio); + int write_flags = wbc_to_write_flags(wbc); + + submit_bio(write_flags, bio); } static inline unsigned int __sdfat_full_name_hash(const struct dentry *unused, const char *name, unsigned int len) @@ -289,6 +303,15 @@ static inline int sdfat_remount_syncfs(struct super_block *sb) } #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + /* EMPTY */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) */ +static inline void truncate_inode_pages_final(struct address_space *mapping) +{ + truncate_inode_pages(mapping, 0); +} +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) static inline sector_t __sdfat_bio_sector(struct bio *bio) @@ -904,15 +927,6 @@ static int sdfat_file_fsync(struct file *filp, int datasync) /************************************************************************* * MORE FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) -#define CURRENT_TIME_SEC timespec64_trunc(current_kernel_time64(), NSEC_PER_SEC) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) -#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC) -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */ - /* EMPTY */ -#endif - - #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) static void sdfat_writepage_end_io(struct bio *bio) { @@ -2186,7 +2200,7 @@ static int sdfat_dfr_ioctl(struct inode *inode, struct file *filp, __lock_super(sb); /* Check if FS_ERROR occurred */ - if (sb->s_flags & MS_RDONLY) { + if (sb_rdonly(sb)) { dfr_err("RDONLY partition (err %d)", -EPERM); __unlock_super(sb); return -EPERM; @@ -2397,7 +2411,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); err = fsapi_create(dir, (u8 *) dentry->d_name.name, FM_REGULAR, &fid); if (err) @@ -2556,7 +2570,7 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); SDFAT_I(inode)->fid.size = i_size_read(inode); @@ -2605,7 +2619,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); err = fsapi_create(dir, (u8 *) dentry->d_name.name, FM_SYMLINK, &fid); if (err) @@ -2666,7 +2680,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); err = fsapi_mkdir(dir, (u8 *) dentry->d_name.name, &fid); if (err) @@ -2715,7 +2729,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); SDFAT_I(inode)->fid.size = i_size_read(inode); @@ -2760,7 +2774,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, old_inode = old_dentry->d_inode; new_inode = new_dentry->d_inode; - ts = CURRENT_TIME_SEC; + ts = current_time(old_inode); SDFAT_I(old_inode)->fid.size = i_size_read(old_inode); @@ -2838,7 +2852,7 @@ static int sdfat_cont_expand(struct inode *inode, loff_t size) if (err) return err; - inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; + inode->i_ctime = inode->i_mtime = current_time(inode); mark_inode_dirty(inode); if (!IS_SYNC(inode)) @@ -3096,7 +3110,7 @@ static void sdfat_truncate(struct inode *inode, loff_t old_size) if (err) goto out; - inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; + inode->i_ctime = inode->i_mtime = current_time(inode); if (IS_DIRSYNC(inode)) (void) sdfat_sync_inode(inode); else @@ -3524,7 +3538,8 @@ static int sdfat_readpages(struct file *file, struct address_space *mapping, } static inline void sdfat_submit_fullpage_bio(struct block_device *bdev, - sector_t sector, unsigned int length, struct page *page) + sector_t sector, unsigned int length, + struct page *page, struct writeback_control *wbc) { /* Single page bio submit */ struct bio *bio; @@ -3548,7 +3563,7 @@ static inline void sdfat_submit_fullpage_bio(struct block_device *bdev, __sdfat_set_bio_iterate(bio, sector, length, 0, 0); bio->bi_end_io = sdfat_writepage_end_io; - __sdfat_submit_bio_write(bio); + __sdfat_submit_bio_write(bio, wbc); } static int sdfat_writepage(struct page *page, struct writeback_control *wbc) @@ -3683,7 +3698,7 @@ static int sdfat_writepage(struct page *page, struct writeback_control *wbc) sdfat_submit_fullpage_bio(head->b_bdev, head->b_blocknr << (sb->s_blocksize_bits - SECTOR_SIZE_BITS), nr_blocks_towrite << inode->i_blkbits, - page); + page, wbc); unlock_page(page); @@ -3748,7 +3763,7 @@ static int sdfat_check_writable(struct super_block *sb) if (fsapi_check_bdi_valid(sb)) return -EIO; - if (sb->s_flags & MS_RDONLY) + if (sb_rdonly(sb)) return -EROFS; return 0; @@ -3823,7 +3838,7 @@ static int sdfat_write_end(struct file *file, struct address_space *mapping, sdfat_write_failed(mapping, pos+len); if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { - inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; + inode->i_mtime = inode->i_ctime = current_time(inode); fid->attr |= ATTR_ARCHIVE; mark_inode_dirty(inode); } @@ -4035,7 +4050,7 @@ static struct inode *sdfat_alloc_inode(struct super_block *sb) return &ei->vfs_inode; } -static void sdfat_destroy_inode(struct inode *inode) +static void sdfat_free_inode(struct inode *inode) { if (SDFAT_I(inode)->target) { kfree(SDFAT_I(inode)->target); @@ -4045,6 +4060,28 @@ static void sdfat_destroy_inode(struct inode *inode) kmem_cache_free(sdfat_inode_cachep, SDFAT_I(inode)); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) +/* Use free_inode instead of destroy_inode */ +#define sdfat_destroy_inode (NULL) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) +static void sdfat_i_callback(struct rcu_head *head) +{ + struct inode *inode = container_of(head, struct inode, i_rcu); + + sdfat_free_inode(inode); +} + +static void sdfat_destroy_inode(struct inode *inode) +{ + call_rcu(&inode->i_rcu, sdfat_i_callback); +} +#else +static void sdfat_destroy_inode(struct inode *inode) +{ + sdfat_free_inode(inode); +} +#endif + static int __sdfat_write_inode(struct inode *inode, int sync) { struct super_block *sb = inode->i_sb; @@ -4080,7 +4117,7 @@ static int sdfat_write_inode(struct inode *inode, struct writeback_control *wbc) static void sdfat_evict_inode(struct inode *inode) { - truncate_inode_pages(&inode->i_data, 0); + truncate_inode_pages_final(&inode->i_data); if (!inode->i_nlink) { loff_t old_size = i_size_read(inode); @@ -4108,23 +4145,8 @@ static void sdfat_evict_inode(struct inode *inode) /* remove_inode_hash(inode); */ } - - -static void sdfat_put_super(struct super_block *sb) +static void sdfat_free_sb_info(struct sdfat_sb_info *sbi) { - struct sdfat_sb_info *sbi = SDFAT_SB(sb); - int err; - - sdfat_log_msg(sb, KERN_INFO, "trying to unmount..."); - - __cancel_delayed_work_sync(sbi); - - if (__is_sb_dirty(sb)) - sdfat_write_super(sb); - - __free_dfr_mem_if_required(sb); - err = fsapi_umount(sb); - if (sbi->nls_disk) { unload_nls(sbi->nls_disk); sbi->nls_disk = NULL; @@ -4139,14 +4161,63 @@ static void sdfat_put_super(struct super_block *sb) sbi->options.iocharset = sdfat_default_iocharset; } + if (sbi->use_vmalloc) { + vfree(sbi); + return; + } + kfree(sbi); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) +static void delayed_free(struct rcu_head *p) +{ + struct sdfat_sb_info *sbi = container_of(p, struct sdfat_sb_info, rcu); + + sdfat_free_sb_info(sbi); +} + +static void __sdfat_destroy_sb_info(struct super_block *sb) +{ + struct sdfat_sb_info *sbi = SDFAT_SB(sb); + + call_rcu(&sbi->rcu, delayed_free); +} +#else +static void __sdfat_destroy_sb_info(struct super_block *sb) +{ + struct sdfat_sb_info *sbi = SDFAT_SB(sb); + + sdfat_free_sb_info(sbi); sb->s_fs_info = NULL; +} +#endif + +static void sdfat_destroy_sb_info(struct super_block *sb) +{ + struct sdfat_sb_info *sbi = SDFAT_SB(sb); kobject_del(&sbi->sb_kobj); kobject_put(&sbi->sb_kobj); - if (!sbi->use_vmalloc) - kfree(sbi); - else - vfree(sbi); + + __sdfat_destroy_sb_info(sb); +} + +static void sdfat_put_super(struct super_block *sb) +{ + struct sdfat_sb_info *sbi = SDFAT_SB(sb); + int err; + + sdfat_log_msg(sb, KERN_INFO, "trying to unmount..."); + + __cancel_delayed_work_sync(sbi); + + if (__is_sb_dirty(sb)) + sdfat_write_super(sb); + + __free_dfr_mem_if_required(sb); + err = fsapi_umount(sb); + + sdfat_destroy_sb_info(sb); sdfat_log_msg(sb, KERN_INFO, "unmounted successfully! %s", err ? "(with previous I/O errors)" : ""); @@ -4177,7 +4248,7 @@ static void sdfat_write_super(struct super_block *sb) /* flush delayed FAT/DIR dirty */ __flush_delayed_meta(sb, 0); - if (!(sb->s_flags & MS_RDONLY)) + if (!sb_rdonly(sb)) fsapi_sync_fs(sb, 0); __unlock_super(sb); @@ -4305,7 +4376,8 @@ static int sdfat_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bavail = info.FreeClusters; buf->f_fsid.val[0] = (u32)id; buf->f_fsid.val[1] = (u32)(id >> 32); - buf->f_namelen = 260; + /* Unicode utf8 255 characters */ + buf->f_namelen = MAX_NAME_LENGTH * MAX_CHARSET_SIZE; return 0; } @@ -4317,7 +4389,7 @@ static int sdfat_remount(struct super_block *sb, int *flags, char *data) struct sdfat_sb_info *sbi = SDFAT_SB(sb); FS_INFO_T *fsi = &(sbi->fsi); - *flags |= MS_NODIRATIME; + *flags |= SB_NODIRATIME; prev_sb_flags = sb->s_flags; @@ -4326,8 +4398,8 @@ static int sdfat_remount(struct super_block *sb, int *flags, char *data) fsapi_set_vol_flags(sb, VOL_CLEAN, 1); sdfat_log_msg(sb, KERN_INFO, "re-mounted(%s->%s), eio=0x%x, Opts: %s", - (prev_sb_flags & MS_RDONLY) ? "ro" : "rw", - (*flags & MS_RDONLY) ? "ro" : "rw", + (prev_sb_flags & SB_RDONLY) ? "ro" : "rw", + (*flags & SB_RDONLY) ? "ro" : "rw", fsi->prev_eio, orig_data); kfree(orig_data); return 0; @@ -4390,7 +4462,11 @@ static int __sdfat_show_options(struct seq_file *m, struct super_block *sb) static const struct super_operations sdfat_sops = { .alloc_inode = sdfat_alloc_inode, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) + .free_inode = sdfat_free_inode, +#else .destroy_inode = sdfat_destroy_inode, +#endif .write_inode = sdfat_write_inode, .evict_inode = sdfat_evict_inode, .put_super = sdfat_put_super, @@ -4833,7 +4909,7 @@ static int sdfat_read_root(struct inode *inode) FS_INFO_T *fsi = &(sbi->fsi); DIR_ENTRY_T info; - ts = CURRENT_TIME_SEC; + ts = current_time(inode); SDFAT_I(inode)->fid.dir.dir = fsi->root_dir; SDFAT_I(inode)->fid.dir.flags = 0x01; @@ -4917,11 +4993,18 @@ static int sdfat_fill_super(struct super_block *sb, void *data, int silent) mutex_init(&sbi->s_vlock); sb->s_fs_info = sbi; - sb->s_flags |= MS_NODIRATIME; + sb->s_flags |= SB_NODIRATIME; sb->s_magic = SDFAT_SUPER_MAGIC; sb->s_op = &sdfat_sops; ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) + sb->s_time_gran = NSEC_PER_SEC; /* the same with default */ + sb->s_time_min = SDFAT_MIN_TIMESTAMP_SECS; + sb->s_time_max = SDFAT_MAX_TIMESTAMP_SECS; +#endif + err = parse_options(sb, data, silent, &debug, &sbi->options); if (err) { sdfat_log_msg(sb, KERN_ERR, "failed to parse options"); @@ -5068,6 +5151,13 @@ static int __init sdfat_init_inodecache(void) static void sdfat_destroy_inodecache(void) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); +#endif kmem_cache_destroy(sdfat_inode_cachep); } @@ -5216,6 +5306,13 @@ error: static void __exit exit_sdfat_fs(void) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); +#endif sdfat_uevent_uninit(); sdfat_statistics_uninit(); diff --git a/fs/sdfat/sdfat.h b/fs/sdfat/sdfat.h index 60f7811c7b99..8a18aa5b798e 100644 --- a/fs/sdfat/sdfat.h +++ b/fs/sdfat/sdfat.h @@ -142,6 +142,9 @@ struct sdfat_sb_info { struct mutex s_vlock; /* volume lock */ int use_vmalloc; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + struct rcu_head rcu; +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) int s_dirt; struct mutex s_lock; /* superblock lock */ @@ -215,6 +218,30 @@ typedef struct timespec64 sdfat_timespec_t; typedef struct timespec sdfat_timespec_t; #endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */ +/* + * sb->s_flags. Note that these mirror the equivalent MS_* flags where + * represented in both. + */ +#define SB_RDONLY 1 /* Mount read-only */ +#define SB_NODIRATIME 2048 /* Do not update directory access times */ +static inline bool sb_rdonly(const struct super_block *sb) +{ + return sb->s_flags & MS_RDONLY; +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) + /* EMPTY */ +#else +static inline sdfat_timespec_t current_time(struct inode *inode) +{ + return CURRENT_TIME_SEC; +} +#endif /* * FIXME : needs on-disk-slot in-memory data */ @@ -387,7 +414,14 @@ extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, DATE_TIME_T *tp); extern void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, DATE_TIME_T *tp); -extern TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tm); +extern TIMESTAMP_T *tm_now(struct inode *inode, TIMESTAMP_T *tm); +static inline TIMESTAMP_T *tm_now_sb(struct super_block *sb, TIMESTAMP_T *tm) +{ + struct inode fake_inode; + + fake_inode.i_sb = sb; + return tm_now(&fake_inode, tm); +} #ifdef CONFIG_SDFAT_DEBUG diff --git a/fs/sdfat/sdfat_fs.h b/fs/sdfat/sdfat_fs.h index b012e406fb23..5debaa9617b2 100644 --- a/fs/sdfat/sdfat_fs.h +++ b/fs/sdfat/sdfat_fs.h @@ -145,6 +145,13 @@ #define CS_PBR_SECTOR 1 #define CS_DEFAULT 2 +/* time min/max */ +/* Jan 1 GMT 00:00:00 1980 */ +#define SDFAT_MIN_TIMESTAMP_SECS 315532800LL +/* Dec 31 GMT 23:59:59 2107 */ +#define SDFAT_MAX_TIMESTAMP_SECS 4354819199LL + + /* * ioctl command */ @@ -179,7 +186,7 @@ /* On-Disk Type Definitions */ /*----------------------------------------------------------------------*/ -/* FAT12/16 BIOS parameter block (64 bytes) */ +/* FAT12/16/32 BIOS parameter block (64 bytes) */ typedef struct { __u8 jmp_boot[3]; __u8 oem_name[8]; @@ -197,41 +204,28 @@ typedef struct { __le32 num_hid_sectors; /* . */ __le32 num_huge_sectors; - __u8 phy_drv_no; - __u8 state; /* used by WindowsNT for mount state */ - __u8 ext_signature; - __u8 vol_serial[4]; - __u8 vol_label[11]; - __u8 vol_type[8]; - __le16 dummy; -} bpb16_t; - -/* FAT32 BIOS parameter block (64 bytes) */ -typedef struct { - __u8 jmp_boot[3]; - __u8 oem_name[8]; - - __u8 sect_size[2]; /* unaligned */ - __u8 sect_per_clus; - __le16 num_reserved; - __u8 num_fats; - __u8 num_root_entries[2]; /* unaligned */ - __u8 num_sectors[2]; /* unaligned */ - __u8 media_type; - __le16 num_fat_sectors; /* zero */ - __le16 sectors_in_track; - __le16 num_heads; - __le32 num_hid_sectors; /* . */ - __le32 num_huge_sectors; - - __le32 num_fat32_sectors; - __le16 ext_flags; - __u8 fs_version[2]; - __le32 root_cluster; /* . */ - __le16 fsinfo_sector; - __le16 backup_sector; - __le16 reserved[6]; /* . */ -} bpb32_t; + union { + struct { + __u8 phy_drv_no; + __u8 state; /* used by WinNT for mount state */ + __u8 ext_signature; + __u8 vol_serial[4]; + __u8 vol_label[11]; + __u8 vol_type[8]; + __le16 nouse; + } f16; + + struct { + __le32 num_fat32_sectors; + __le16 ext_flags; + __u8 fs_version[2]; + __le32 root_cluster; /* . */ + __le16 fsinfo_sector; + __le16 backup_sector; + __le16 reserved[6]; /* . */ + } f32; + }; +} bpb_t; /* FAT32 EXTEND BIOS parameter block (32 bytes) */ typedef struct { @@ -273,12 +267,12 @@ typedef struct { /* FAT32 PBR (64 bytes) */ typedef struct { - bpb16_t bpb; + bpb_t bpb; } pbr16_t; /* FAT32 PBR[BPB+BSX] (96 bytes) */ typedef struct { - bpb32_t bpb; + bpb_t bpb; bsx32_t bsx; } pbr32_t; @@ -292,8 +286,7 @@ typedef struct { typedef struct { union { __u8 raw[64]; - bpb16_t f16; - bpb32_t f32; + bpb_t fat; bpb64_t f64; } bpb; union { diff --git a/fs/sdfat/version.h b/fs/sdfat/version.h index ab0459a38982..92e99621143f 100644 --- a/fs/sdfat/version.h +++ b/fs/sdfat/version.h @@ -22,4 +22,4 @@ /* PURPOSE : sdFAT File Manager */ /* */ /************************************************************************/ -#define SDFAT_VERSION "2.3.0" +#define SDFAT_VERSION "2.4.5-lineage" diff --git a/fs/sdfat/xattr.c b/fs/sdfat/xattr.c index 40bb850711be..bd037358b644 100644 --- a/fs/sdfat/xattr.c +++ b/fs/sdfat/xattr.c @@ -79,12 +79,22 @@ ssize_t __sdfat_getxattr(const char *name, void *value, size_t size) * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) +#if defined(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +static int sdfat_xattr_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, void *buffer, size_t size, + int flags) +{ + return __sdfat_getxattr(name, buffer, size); +} +#else static int sdfat_xattr_get(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, void *buffer, size_t size) { return __sdfat_getxattr(name, buffer, size); } +#endif static int sdfat_xattr_set(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, -- GitLab From fde799185980e18fd5ccecbfee15bd4f47d21ee3 Mon Sep 17 00:00:00 2001 From: Diogo Ferreira Date: Sat, 6 May 2017 17:14:00 +0100 Subject: [PATCH 003/528] qpnp-smbcharger: Publish charger voltage to the usb psy Since N, the Keyguard uses watt data rather than amperage alone. It needs both voltage and amperage information for the power supply subsystem to do so. This brings back the "Charging slowly", "Charging" and "Charging rapidly" texts on the lock screen. Change-Id: Iac37d8b69d2acc048e8c132b2c26c2bed3676d75 --- drivers/power/qpnp-smbcharger.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c index b9cc66d298bc..3bb952692ca0 100644 --- a/drivers/power/qpnp-smbcharger.c +++ b/drivers/power/qpnp-smbcharger.c @@ -2133,6 +2133,8 @@ static void smbchg_parallel_usb_enable(struct smbchg_chip *chip) rc); goto disable_parallel; } + rc = power_supply_set_voltage_limit(chip->usb_psy, + (chip->vfloat_mv + 50) * 1000); chip->target_fastchg_current_ma = chip->cfg_fastchg_current_ma / 2; smbchg_set_fastchg_current(chip, chip->target_fastchg_current_ma); pval.intval = chip->target_fastchg_current_ma * 1000; @@ -2906,8 +2908,11 @@ static int smbchg_float_voltage_set(struct smbchg_chip *chip, int vfloat_mv) if (rc) dev_err(chip->dev, "Couldn't set float voltage rc = %d\n", rc); - else + else { chip->vfloat_mv = vfloat_mv; + power_supply_set_voltage_limit(chip->usb_psy, + chip->vfloat_mv * 1000); + } return rc; } -- GitLab From ec43a60b6f2615f753cd59ac124093777fd2381f Mon Sep 17 00:00:00 2001 From: Wang Han <416810799@qq.com> Date: Tue, 29 Aug 2017 14:08:30 +0200 Subject: [PATCH 004/528] qpnp-smbcharger: Extend USB fast charge playground Allow fast charge up to 900mA, when the original param is smaller than 150mA. Signed-off-by: Wang Han <416810799@qq.com> Signed-off-by: zachariasmaladroit --- drivers/power/qpnp-smbcharger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c index 3bb952692ca0..51ca054562ec 100644 --- a/drivers/power/qpnp-smbcharger.c +++ b/drivers/power/qpnp-smbcharger.c @@ -1674,7 +1674,7 @@ static int smbchg_set_usb_current_max(struct smbchg_chip *chip, } chip->usb_max_current_ma = 500; } - if (current_ma == CURRENT_900_MA) { + if ((current_ma <= CURRENT_150_MA) || (current_ma == CURRENT_500_MA) || (current_ma == CURRENT_900_MA)) { // AP: Fast charge for USB rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, CFG_USB_2_3_SEL_BIT, CFG_USB_3); -- GitLab From 374c31cabf2f314e338eb2ccb5919a7fcee638fc Mon Sep 17 00:00:00 2001 From: Zhao Xuewen Date: Wed, 23 Sep 2015 18:14:34 +0800 Subject: [PATCH 005/528] power:qpnp-charger: extended charge time from 30s to 100s when battery status is near to full When charger is online for a long time, such as 12 hour, the battery status changes from charging to full and resumes charging. The reason is that battery is not full at the first full state. So increse charge time from 30s to 100s when battery status is near to full. This methods will reduce the number of recharging times BUG:24316771 Signed-off-by: l00228880 Signed-off-by: Pranav Vashi Signed-off-by: Joe Maples --- drivers/power/qpnp-charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c index 8d5e61bc7bda..ff14da862ee8 100644 --- a/drivers/power/qpnp-charger.c +++ b/drivers/power/qpnp-charger.c @@ -3778,7 +3778,7 @@ qpnp_chg_adjust_vddmax(struct qpnp_chg_chip *chip, int vbat_mv) qpnp_chg_set_appropriate_vddmax(chip); } -#define CONSECUTIVE_COUNT 3 +#define CONSECUTIVE_COUNT 10 #define VBATDET_MAX_ERR_MV 50 static void qpnp_eoc_work(struct work_struct *work) -- GitLab From 9eb87d9bf2880aa928b4f364d0e40ea156dc6866 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 20 Apr 2015 17:54:37 +0800 Subject: [PATCH 006/528] power: qpnp-charger: Avoid override USBIN_COMP in reverse boost for SMBBP When SMBBP working at reverse boost mode with a charger connected, USBIN comparator can be used to turn off the OVP FET and trigger an USBIN_VALID IRQ to detect the charger removal. Avoid overriding USBIN comparator when SMBBP working at reverse boost mode, to ensure the charger insertion and removal can be detected. Change-Id: If705bc5cb7132ab2ce9b97ac4b887a4cdc201b52 Signed-off-by: Fenglin Wu --- drivers/power/qpnp-charger.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c index ff14da862ee8..a6c463fd7855 100644 --- a/drivers/power/qpnp-charger.c +++ b/drivers/power/qpnp-charger.c @@ -3452,14 +3452,15 @@ qpnp_chg_regulator_boost_enable(struct regulator_dev *rdev) pr_err("failed to write SEC_ACCESS rc=%d\n", rc); return rc; } - - rc = qpnp_chg_masked_write(chip, - chip->usb_chgpth_base + COMP_OVR1, - 0xFF, - 0x2F, 1); - if (rc) { - pr_err("failed to write COMP_OVR1 rc=%d\n", rc); - return rc; + if (chip->type != SMBBP) { + rc = qpnp_chg_masked_write(chip, + chip->usb_chgpth_base + COMP_OVR1, + 0xFF, + 0x2F, 1); + if (rc) { + pr_err("failed to write COMP_OVR1 rc=%d\n", rc); + return rc; + } } } @@ -3558,16 +3559,16 @@ qpnp_chg_regulator_boost_disable(struct regulator_dev *rdev) pr_err("failed to write SEC_ACCESS rc=%d\n", rc); return rc; } - - rc = qpnp_chg_masked_write(chip, - chip->usb_chgpth_base + COMP_OVR1, - 0xFF, - 0x00, 1); - if (rc) { - pr_err("failed to write COMP_OVR1 rc=%d\n", rc); - return rc; + if (chip->type != SMBBP) { + rc = qpnp_chg_masked_write(chip, + chip->usb_chgpth_base + COMP_OVR1, + 0xFF, + 0x00, 1); + if (rc) { + pr_err("failed to write COMP_OVR1 rc=%d\n", rc); + return rc; + } } - usleep(1000); qpnp_chg_usb_suspend_enable(chip, 0); -- GitLab From 06b98184eb257735ad13e27cc16b836c995fe49a Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Tue, 28 Mar 2017 15:50:37 +0530 Subject: [PATCH 007/528] power: qpnp-smbcharger: handle charger removal during APSD re-run During APSD re-run software ignores all USB insertion/removal interrupts, there could be a possibility of actual removal of USB during APSD re-run which will be missed by software. Fix this by checking and updating USB status after APSD re-run. Change-Id: I25248ffd5b5a4c2831460605fed402381961f41d Signed-off-by: Ashay Jaiswal [Resolved trivial merge conflicts] Signed-off-by: Andrey Cherepkov --- drivers/power/qpnp-smbcharger.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c index 51ca054562ec..3c69b1f6c317 100644 --- a/drivers/power/qpnp-smbcharger.c +++ b/drivers/power/qpnp-smbcharger.c @@ -6910,6 +6910,7 @@ static int smbchg_probe(struct spmi_device *spmi) power_supply_set_present(chip->usb_psy, chip->usb_present); + update_usb_status(chip, is_usb_present(chip), false); dump_regs(chip); create_debugfs_entries(chip); dev_info(chip->dev, -- GitLab From 9b611da7b508a398a4887ad458df130472d8338f Mon Sep 17 00:00:00 2001 From: Bernhard Thoben Date: Wed, 3 Feb 2021 14:35:05 +0100 Subject: [PATCH 008/528] arm: dts: msm8994-kitakami_common: Battery temperature thresholds changed. - This should reduce the battery temperature while using and charging. Change-Id: I8f89830e2c3a24df4fa921b9e19b21aa5c67c976 --- arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi index ede44a88c6c2..c4ab74e8e0fc 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi @@ -788,7 +788,7 @@ }; &pmi8994_fg { - qcom,hot-bat-decidegc = <550>; + qcom,hot-bat-decidegc = <500>; qcom,warm-bat-decidegc = <450>; qcom,cool-bat-decidegc = <100>; qcom,cold-bat-decidegc = <50>; -- GitLab From 7ac0ebe041e6b04f3932b37aff1021fc818577d1 Mon Sep 17 00:00:00 2001 From: Bernhard Thoben Date: Wed, 3 Feb 2021 15:46:27 +0100 Subject: [PATCH 009/528] arm: dts: msm8994-kitakami_common: More battery charging thresholds changed. - This should reduce the battery temperature too while charging. Change-Id: I14fb1ec79c8ad02239596b6f2858c8549b003783 --- arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi index c4ab74e8e0fc..ac7102c962b8 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi @@ -792,6 +792,10 @@ qcom,warm-bat-decidegc = <450>; qcom,cool-bat-decidegc = <100>; qcom,cold-bat-decidegc = <50>; + qcom,warm-bat-ma = <350>; + qcom,cool-bat-ma = <350>; + qcom,warm-bat-mv = <4100>; + qcom,cool-bat-mv = <4100>; qcom,irq-volt-empty-mv = <3100>; qcom,fg-cutoff-voltage-mv = <3200>; qcom,resume-soc = <0xFD>; -- GitLab From be5863de6fbef91ef374eefbc949127b727e691f Mon Sep 17 00:00:00 2001 From: Bernhard Thoben Date: Sat, 6 Feb 2021 12:07:34 +0100 Subject: [PATCH 010/528] Revert "arm: dts: msm8994-kitakami_common: More battery charging thresholds changed." This reverts commit 7ac0ebe041e6b04f3932b37aff1021fc818577d1. --- arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi index ac7102c962b8..c4ab74e8e0fc 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi @@ -792,10 +792,6 @@ qcom,warm-bat-decidegc = <450>; qcom,cool-bat-decidegc = <100>; qcom,cold-bat-decidegc = <50>; - qcom,warm-bat-ma = <350>; - qcom,cool-bat-ma = <350>; - qcom,warm-bat-mv = <4100>; - qcom,cool-bat-mv = <4100>; qcom,irq-volt-empty-mv = <3100>; qcom,fg-cutoff-voltage-mv = <3200>; qcom,resume-soc = <0xFD>; -- GitLab From b0bf64fca20b190a511a5505ed9fc0511965fc81 Mon Sep 17 00:00:00 2001 From: switchgott Date: Mon, 1 Feb 2021 17:29:40 +0100 Subject: [PATCH 011/528] fs: sdfat: disable sdfat debug Change-Id: I8aae9dcacf7e5f15dd9b6efefc4c7f18257dfb5f --- fs/sdfat/blkdev.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/sdfat/blkdev.c b/fs/sdfat/blkdev.c index 788b7c034afc..7a275ac19e1f 100644 --- a/fs/sdfat/blkdev.c +++ b/fs/sdfat/blkdev.c @@ -173,7 +173,9 @@ s32 bdev_mread(struct super_block *sb, u64 secno, struct buffer_head **bh, u64 n if (!(fsi->prev_eio & SDFAT_EIO_READ)) { fsi->prev_eio |= SDFAT_EIO_READ; sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__); +#ifdef CONFIG_SDFAT_DEBUG sdfat_debug_warn_on(1); +#endif } return -EIO; @@ -227,7 +229,9 @@ no_bh: if (!(fsi->prev_eio & SDFAT_EIO_WRITE)) { fsi->prev_eio |= SDFAT_EIO_WRITE; sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__); +#ifdef CONFIG_SDFAT_DEBUG sdfat_debug_warn_on(1); +#endif } return -EIO; -- GitLab From f493abd65c871f2e3c986229ad3a9c52ade18d3e Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 21 May 2019 14:56:39 -0700 Subject: [PATCH 012/528] fs: sdcardfs: Add missing option to show_options unshared_obb was missing from show_options bug: 133257717 Change-Id: I1bc49d1b4098052382a518540e5965e037aa39f1 Signed-off-by: Kevin F. Haggerty --- fs/sdcardfs/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index cffcdb11cb8a..a4ac84e0c01d 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -311,6 +311,8 @@ static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m, seq_puts(m, ",default_normal"); if (opts->reserved_mb != 0) seq_printf(m, ",reserved=%uMB", opts->reserved_mb); + if (opts->unshared_obb) + seq_printf(m, ",unshared_obb"); return 0; }; -- GitLab From 04b6193c1094aa01c36309bff6a5f2b49ec5a9ad Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sun, 18 Nov 2018 19:21:35 +0100 Subject: [PATCH 013/528] fix commit: "fs: sdcardfs: Hold i_mutex for i_size_write" I accidentally merged the 3.18 patch, using a different way to access the lower file's inode. Use the 3.10 technique instead. Change-Id: Iea18abcb24cce9afa23e870af8beb31767d67250 Signed-off-by: Corinna Vinschen (cherry picked from commit 279bf918a4b7e0a0a346e6b1e8d6a2067c885ab6) --- fs/sdcardfs/file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 6c8ffaab7352..39fe0426f61d 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -76,8 +76,10 @@ static ssize_t sdcardfs_write(struct file *file, const char __user *buf, if (err >= 0) { if (sizeof(loff_t) > sizeof(long)) mutex_lock(&inode->i_mutex); - fsstack_copy_inode_size(inode, file_inode(lower_file)); - fsstack_copy_attr_times(inode, file_inode(lower_file)); + fsstack_copy_inode_size(inode, + lower_file->f_path.dentry->d_inode); + fsstack_copy_attr_times(inode, + lower_file->f_path.dentry->d_inode); if (sizeof(loff_t) > sizeof(long)) mutex_unlock(&inode->i_mutex); } -- GitLab From 57d551c6bb0a978b8873e5f704fb59f9a573cfc5 Mon Sep 17 00:00:00 2001 From: Mike B Date: Tue, 23 Feb 2021 22:58:44 +0100 Subject: [PATCH 014/528] Kernel: Implement HARDENED_USERCOPY --- arch/arm64/Kconfig | 1 + arch/arm64/configs/kitakami_ivy_defconfig | 2 + arch/arm64/configs/kitakami_satsuki_defconfig | 2 + arch/arm64/configs/kitakami_sumire_defconfig | 2 + arch/arm64/configs/kitakami_suzuran_defconfig | 2 + include/linux/slab.h | 12 + include/linux/thread_info.h | 14 + init/Kconfig | 2 + mm/Makefile | 1 + mm/slab.c | 31 ++ mm/slub.c | 40 +++ mm/usercopy.c | 298 ++++++++++++++++++ security/Kconfig | 31 ++ 13 files changed, 438 insertions(+) create mode 100644 mm/usercopy.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1a107383436f..f678b9a02b83 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -30,6 +30,7 @@ config ARM64 select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select HARDIRQS_SW_RESEND + select HAVE_ARCH_HARDENED_USERCOPY select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS diff --git a/arch/arm64/configs/kitakami_ivy_defconfig b/arch/arm64/configs/kitakami_ivy_defconfig index 7c99523ce1dd..548a432ac2ce 100644 --- a/arch/arm64/configs/kitakami_ivy_defconfig +++ b/arch/arm64/configs/kitakami_ivy_defconfig @@ -2,6 +2,8 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HARDENED_USERCOPY=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_LOG_BUF_SHIFT=18 CONFIG_CGROUPS=y diff --git a/arch/arm64/configs/kitakami_satsuki_defconfig b/arch/arm64/configs/kitakami_satsuki_defconfig index cba0995c5d2d..64778f4cfd95 100644 --- a/arch/arm64/configs/kitakami_satsuki_defconfig +++ b/arch/arm64/configs/kitakami_satsuki_defconfig @@ -2,6 +2,8 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HARDENED_USERCOPY=y CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index 9cd120d430fe..d8eca1c5bfdc 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -2,6 +2,8 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HARDENED_USERCOPY=y CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y diff --git a/arch/arm64/configs/kitakami_suzuran_defconfig b/arch/arm64/configs/kitakami_suzuran_defconfig index e77ee7762b0f..6682cb8f1a00 100644 --- a/arch/arm64/configs/kitakami_suzuran_defconfig +++ b/arch/arm64/configs/kitakami_suzuran_defconfig @@ -2,6 +2,8 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HARDENED_USERCOPY=y CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y diff --git a/include/linux/slab.h b/include/linux/slab.h index 0c621752caa6..0756780e3401 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -133,6 +133,18 @@ void kfree(const void *); void kzfree(const void *); size_t ksize(const void *); +#ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR +const char *__check_heap_object(const void *ptr, unsigned long n, + struct page *page); +#else +static inline const char *__check_heap_object(const void *ptr, + unsigned long n, + struct page *page) +{ + return NULL; +} +#endif + /* * Some archs want to perform DMA into kmalloc caches and need a guaranteed * alignment larger than the alignment of a 64-bit integer. diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 4ae6f32c8033..1a292c4aea9e 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -149,6 +149,20 @@ static inline bool test_and_clear_restore_sigmask(void) #ifndef HAVE_SET_RESTORE_SIGMASK #error "no set_restore_sigmask() provided and default one won't work" #endif +#ifdef CONFIG_HARDENED_USERCOPY +extern void __check_object_size(const void *ptr, unsigned long n, + bool to_user); + +static inline void check_object_size(const void *ptr, unsigned long n, + bool to_user) +{ + __check_object_size(ptr, n, to_user); +} +#else +static inline void check_object_size(const void *ptr, unsigned long n, + bool to_user) +{ } +#endif /* CONFIG_HARDENED_USERCOPY */ #endif /* __KERNEL__ */ diff --git a/init/Kconfig b/init/Kconfig index be1c0ceca228..012ff71e4530 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1572,6 +1572,7 @@ choice config SLAB bool "SLAB" + select HAVE_HARDENED_USERCOPY_ALLOCATOR help The regular slab allocator that is established and known to work well in all environments. It organizes cache hot objects in @@ -1579,6 +1580,7 @@ config SLAB config SLUB bool "SLUB (Unqueued Allocator)" + select HAVE_HARDENED_USERCOPY_ALLOCATOR help SLUB is a slab allocator that minimizes cache line usage instead of managing queues of cached objects (SLAB approach). diff --git a/mm/Makefile b/mm/Makefile index 55fff061a125..76d6cceb18d0 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -66,3 +66,4 @@ obj-$(CONFIG_Z3FOLD) += z3fold.o obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o obj-$(CONFIG_ZPOOL) += zpool.o obj-$(CONFIG_ZSMALLOC) += zsmalloc.o +obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o diff --git a/mm/slab.c b/mm/slab.c index bd88411595b9..5d0d88ad6ea7 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -4483,6 +4483,37 @@ static int __init slab_proc_init(void) module_init(slab_proc_init); #endif +#ifdef CONFIG_HARDENED_USERCOPY +/* + * Rejects objects that are incorrectly sized. + * + * Returns NULL if check passes, otherwise const char * to name of cache + * to indicate an error. + */ +const char *__check_heap_object(const void *ptr, unsigned long n, + struct page *page) +{ + struct kmem_cache *cachep; + unsigned int objnr; + unsigned long offset; + + /* Find and validate object. */ + cachep = page->slab_cache; + objnr = obj_to_index(cachep, page->slab_page, (void *)ptr); + BUG_ON(objnr >= cachep->num); + + /* Find offset within object. */ + offset = ptr - index_to_obj(cachep, page->slab_page, objnr) - + obj_offset(cachep); + + /* Allow address range falling entirely within object size. */ + if (offset <= cachep->object_size && n <= cachep->object_size - offset) + return NULL; + + return cachep->name; +} +#endif /* CONFIG_HARDENED_USERCOPY */ + /** * ksize - get the actual amount of memory allocated for a given object * @objp: Pointer to the object diff --git a/mm/slub.c b/mm/slub.c index bc6d52865a37..60399d50f27c 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3297,6 +3297,46 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node) EXPORT_SYMBOL(__kmalloc_node); #endif +#ifdef CONFIG_HARDENED_USERCOPY +/* + * Rejects objects that are incorrectly sized. + * + * Returns NULL if check passes, otherwise const char * to name of cache + * to indicate an error. + */ +const char *__check_heap_object(const void *ptr, unsigned long n, + struct page *page) +{ + struct kmem_cache *s; + unsigned long offset; + size_t object_size; + + /* Find object and usable object size. */ + s = page->slab_cache; + object_size = slab_ksize(s); + + /* Reject impossible pointers. */ + if (ptr < page_address(page)) + return s->name; + + /* Find offset within object. */ + offset = (ptr - page_address(page)) % s->size; + + /* Adjust for redzone and reject if within the redzone. */ + if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) { + if (offset < s->red_left_pad) + return s->name; + offset -= s->red_left_pad; + } + + /* Allow address range falling entirely within object size. */ + if (offset <= object_size && n <= object_size - offset) + return NULL; + + return s->name; +} +#endif /* CONFIG_HARDENED_USERCOPY */ + size_t ksize(const void *object) { struct page *page; diff --git a/mm/usercopy.c b/mm/usercopy.c new file mode 100644 index 000000000000..a6a0111cfba9 --- /dev/null +++ b/mm/usercopy.c @@ -0,0 +1,298 @@ +/* + * This implements the various checks for CONFIG_HARDENED_USERCOPY*, + * which are designed to protect kernel memory from needless exposure + * and overwrite under many unintended conditions. This code is based + * on PAX_USERCOPY, which is: + * + * Copyright (C) 2001-2016 PaX Team, Bradley Spengler, Open Source + * Security Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +/* + * Checks if a given pointer and length is contained by the current + * stack frame (if possible). + * + * Returns: + * NOT_STACK: not at all on the stack + * GOOD_FRAME: fully within a valid stack frame + * GOOD_STACK: fully on the stack (when can't do frame-checking) + * BAD_STACK: error condition (invalid stack position or bad stack frame) + */ +static noinline int check_stack_object(const void *obj, unsigned long len) +{ + const void * const stack = task_stack_page(current); + const void * const stackend = stack + THREAD_SIZE; + int ret; + + /* Object is not on the stack at all. */ + if (obj + len <= stack || stackend <= obj) + return NOT_STACK; + + /* + * Reject: object partially overlaps the stack (passing the + * the check above means at least one end is within the stack, + * so if this check fails, the other end is outside the stack). + */ + if (obj < stack || stackend < obj + len) + return BAD_STACK; + + /* Check if object is safely within a valid frame. */ + ret = arch_within_stack_frames(stack, stackend, obj, len); + if (ret) + return ret; + + return GOOD_STACK; +} + +static void report_usercopy(const void *ptr, unsigned long len, + bool to_user, const char *type) +{ + pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n", + to_user ? "exposure" : "overwrite", + to_user ? "from" : "to", ptr, type ? : "unknown", len); + /* + * For greater effect, it would be nice to do do_group_exit(), + * but BUG() actually hooks all the lock-breaking and per-arch + * Oops code, so that is used here instead. + */ + BUG(); +} + +/* Returns true if any portion of [ptr,ptr+n) over laps with [low,high). */ +static bool overlaps(const void *ptr, unsigned long n, unsigned long low, + unsigned long high) +{ + unsigned long check_low = (uintptr_t)ptr; + unsigned long check_high = check_low + n; + + /* Does not overlap if entirely above or entirely below. */ + if (check_low >= high || check_high <= low) + return false; + + return true; +} + +/* Is this address range in the kernel text area? */ +static inline const char *check_kernel_text_object(const void *ptr, + unsigned long n) +{ + unsigned long textlow = (unsigned long)_stext; + unsigned long texthigh = (unsigned long)_etext; + unsigned long textlow_linear, texthigh_linear; + + if (overlaps(ptr, n, textlow, texthigh)) + return ""; + + /* + * Some architectures have virtual memory mappings with a secondary + * mapping of the kernel text, i.e. there is more than one virtual + * kernel address that points to the kernel image. It is usually + * when there is a separate linear physical memory mapping, in that + * __pa() is not just the reverse of __va(). This can be detected + * and checked: + */ + textlow_linear = (unsigned long)__va(__pa(textlow)); + /* No different mapping: we're done. */ + if (textlow_linear == textlow) + return NULL; + + /* Check the secondary mapping... */ + texthigh_linear = (unsigned long)__va(__pa(texthigh)); + if (overlaps(ptr, n, textlow_linear, texthigh_linear)) + return ""; + + return NULL; +} + +static inline const char *check_bogus_address(const void *ptr, unsigned long n) +{ + /* Reject if object wraps past end of memory. */ + if (ptr + n < ptr) + return ""; + + /* Reject if NULL or ZERO-allocation. */ + if (ZERO_OR_NULL_PTR(ptr)) + return ""; + + return NULL; +} + +/* Checks for allocs that are marked in some way as spanning multiple pages. */ +static inline const char *check_page_span(const void *ptr, unsigned long n, + struct page *page, bool to_user) +{ +#ifdef CONFIG_HARDENED_USERCOPY_PAGESPAN + const void *end = ptr + n - 1; + struct page *endpage; + bool is_reserved, is_cma; + + /* + * Sometimes the kernel data regions are not marked Reserved (see + * check below). And sometimes [_sdata,_edata) does not cover + * rodata and/or bss, so check each range explicitly. + */ + + /* Allow reads of kernel rodata region (if not marked as Reserved). */ + if (ptr >= (const void *)__start_rodata && + end <= (const void *)__end_rodata) { + if (!to_user) + return ""; + return NULL; + } + + /* Allow kernel data region (if not marked as Reserved). */ + if (ptr >= (const void *)_sdata && end <= (const void *)_edata) + return NULL; + + /* Allow kernel bss region (if not marked as Reserved). */ + if (ptr >= (const void *)__bss_start && + end <= (const void *)__bss_stop) + return NULL; + + /* Is the object wholly within one base page? */ + if (likely(((unsigned long)ptr & (unsigned long)PAGE_MASK) == + ((unsigned long)end & (unsigned long)PAGE_MASK))) + return NULL; + + /* Allow if fully inside the same compound (__GFP_COMP) page. */ + endpage = virt_to_head_page(end); + if (likely(endpage == page)) + return NULL; + + /* + * Reject if range is entirely either Reserved (i.e. special or + * device memory), or CMA. Otherwise, reject since the object spans + * several independently allocated pages. + */ + is_reserved = PageReserved(page); + is_cma = is_migrate_cma_page(page); + if (!is_reserved && !is_cma) + return ""; + + for (ptr += PAGE_SIZE; ptr <= end; ptr += PAGE_SIZE) { + page = virt_to_head_page(ptr); + if (is_reserved && !PageReserved(page)) + return ""; + if (is_cma && !is_migrate_cma_page(page)) + return ""; + } +#endif + + return NULL; +} + +static inline const char *check_heap_object(const void *ptr, unsigned long n, + bool to_user) +{ + struct page *page; + + /* + * Some architectures (arm64) return true for virt_addr_valid() on + * vmalloced addresses. Work around this by checking for vmalloc + * first. + */ + if (is_vmalloc_addr(ptr)) + return NULL; + + if (!virt_addr_valid(ptr)) + return NULL; + + page = virt_to_head_page(ptr); + + /* Check slab allocator for flags and size. */ + if (PageSlab(page)) + return __check_heap_object(ptr, n, page); + + /* Verify object does not incorrectly span multiple pages. */ + return check_page_span(ptr, n, page, to_user); +} + +static struct static_key bypass_usercopy_checks = STATIC_KEY_INIT_FALSE; + +/* + * Validates that the given object is: + * - not bogus address + * - known-safe heap or stack object + * - not in kernel text + */ +void __check_object_size(const void *ptr, unsigned long n, bool to_user) +{ + const char *err; + + if (static_key_enabled(&bypass_usercopy_checks)) + return; + + /* Skip all tests if size is zero. */ + if (!n) + return; + + /* Check for invalid addresses. */ + err = check_bogus_address(ptr, n); + if (err) + goto report; + + /* Check for bad heap object. */ + err = check_heap_object(ptr, n, to_user); + if (err) + goto report; + + /* Check for bad stack object. */ + switch (check_stack_object(ptr, n)) { + case NOT_STACK: + /* Object is not touching the current process stack. */ + break; + case GOOD_FRAME: + case GOOD_STACK: + /* + * Object is either in the correct frame (when it + * is possible to check) or just generally on the + * process stack (when frame checking not available). + */ + return; + default: + err = ""; + goto report; + } + + /* Check for object in kernel to avoid text exposure. */ + err = check_kernel_text_object(ptr, n); + if (!err) + return; + +report: + report_usercopy(ptr, n, to_user, err); +} +EXPORT_SYMBOL(__check_object_size); + + +static bool enable_checks __initdata = true; + +static int __init parse_hardened_usercopy(char *str) +{ + return strtobool(str, &enable_checks); +} + +__setup("hardened_usercopy=", parse_hardened_usercopy); + +static int __init set_hardened_usercopy(void) +{ + if (enable_checks == false) + static_key_slow_inc(&bypass_usercopy_checks); + return 1; +} + +late_initcall(set_hardened_usercopy); diff --git a/security/Kconfig b/security/Kconfig index 66a5f8082971..9735d90c0ff6 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -136,6 +136,37 @@ config LSM_MMAP_MIN_ADDR this low address space will need the permission specific to the systems running LSM. +config HAVE_HARDENED_USERCOPY_ALLOCATOR + bool "Harden memory copies between kernel and userspace" + help + The heap allocator implements __check_heap_object() for + validating memory ranges against heap object sizes in + support of CONFIG_HARDENED_USERCOPY. + +config HARDENED_USERCOPY + bool "Harden memory copies between kernel and userspace" + depends on HAVE_HARDENED_USERCOPY_ALLOCATOR + depends on STRICT_DEVMEM + help + This option checks for obviously wrong memory regions when + copying memory to/from the kernel (via copy_to_user() and + copy_from_user() functions) by rejecting memory ranges that + are larger than the specified heap object, span multiple + separately allocated pages, are not on the process stack, + or are part of the kernel text. This kills entire classes + of heap overflow exploits and similar kernel memory exposures. + +config HARDENED_USERCOPY_PAGESPAN + bool "Refuse to copy allocations that span multiple pages" + depends on HARDENED_USERCOPY + depends on !COMPILE_TEST + help + When a multi-page allocation is done without __GFP_COMP, + hardened usercopy will reject attempts to copy it. There are, + however, several cases of this in the kernel that have not all + been removed. This config is intended to be used only while + trying to find such users. + source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig -- GitLab From 5bbefe4e9c15ee3b448b9856f8b4c23a1b411051 Mon Sep 17 00:00:00 2001 From: Mike B Date: Tue, 23 Feb 2021 23:59:10 +0100 Subject: [PATCH 015/528] Kernel: Satisfy HARDEN_USERCOPY --- include/linux/slub_def.h | 1 + include/linux/thread_info.h | 22 +++++++++++++++ mm/slub.c | 54 +++++++++++++++++++++++++++++++++---- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index 027276fa8713..8f603d498ec0 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -85,6 +85,7 @@ struct kmem_cache { int inuse; /* Offset to metadata */ int align; /* Alignment */ int reserved; /* Reserved bytes at the end of slabs */ + int red_left_pad; /* Left redzone padding size */ const char *name; /* Name (only for display!) */ struct list_head list; /* List of slab caches */ #ifdef CONFIG_SYSFS diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 1a292c4aea9e..b9b269dbf693 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -51,6 +51,18 @@ struct restart_block { extern long do_no_restart_syscall(struct restart_block *parm); #include + +/* + * For per-arch arch_within_stack_frames() implementations, defined in + * asm/thread_info.h. + */ +enum { + BAD_STACK = -1, + NOT_STACK = 0, + GOOD_FRAME, + GOOD_STACK, +}; + #include #ifdef __KERNEL__ @@ -149,6 +161,16 @@ static inline bool test_and_clear_restore_sigmask(void) #ifndef HAVE_SET_RESTORE_SIGMASK #error "no set_restore_sigmask() provided and default one won't work" #endif + +#ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES +static inline int arch_within_stack_frames(const void * const stack, + const void * const stackend, + const void *obj, unsigned long len) +{ + return 0; +} +#endif + #ifdef CONFIG_HARDENED_USERCOPY extern void __check_object_size(const void *ptr, unsigned long n, bool to_user); diff --git a/mm/slub.c b/mm/slub.c index 60399d50f27c..c0530a31dd4d 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -123,6 +123,14 @@ static inline int kmem_cache_debug(struct kmem_cache *s) #endif } +static inline void *fixup_red_left(struct kmem_cache *s, void *p) +{ + if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) + p += s->red_left_pad; + + return p; +} + /* * Issues still to be resolved: * @@ -275,8 +283,14 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) /* Loop over all objects in a slab */ #define for_each_object(__p, __s, __addr, __objects) \ - for (__p = (__addr); __p < (__addr) + (__objects) * (__s)->size;\ - __p += (__s)->size) + for (__p = fixup_red_left(__s, __addr); \ + __p < (__addr) + (__objects) * (__s)->size; \ + __p += (__s)->size) + +#define for_each_object_idx(__p, __idx, __s, __addr, __objects) \ + for (__p = fixup_red_left(__s, __addr), __idx = 1; \ + __idx <= __objects; \ + __p += (__s)->size, __idx++) /* Determine object index from a given position */ static inline int slab_index(void *p, struct kmem_cache *s, void *addr) @@ -439,6 +453,22 @@ static void get_map(struct kmem_cache *s, struct page *page, unsigned long *map) set_bit(slab_index(p, s, addr), map); } +static inline int size_from_object(struct kmem_cache *s) +{ + if (s->flags & SLAB_RED_ZONE) + return s->size - s->red_left_pad; + + return s->size; +} + +static inline void *restore_red_left(struct kmem_cache *s, void *p) +{ + if (s->flags & SLAB_RED_ZONE) + p -= s->red_left_pad; + + return p; +} + /* * Debug settings: */ @@ -589,7 +619,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) printk(KERN_ERR "INFO: Object 0x%p @offset=%tu fp=0x%p\n\n", p, p - addr, get_freepointer(s, p)); - if (p > addr + 16) + if (s->flags & SLAB_RED_ZONE) + print_section("Redzone ", p - s->red_left_pad, s->red_left_pad); + else if (p > addr + 16) print_section("Bytes b4 ", p - 16, 16); print_section("Object ", p, min_t(unsigned long, s->object_size, @@ -648,6 +680,9 @@ static void init_object(struct kmem_cache *s, void *object, u8 val) { u8 *p = object; + if (s->flags & SLAB_RED_ZONE) + memset(p - s->red_left_pad, val, s->red_left_pad); + if (s->flags & __OBJECT_POISON) { memset(p, POISON_FREE, s->object_size - 1); p[s->object_size - 1] = POISON_END; @@ -785,6 +820,10 @@ static int check_object(struct kmem_cache *s, struct page *page, u8 *endobject = object + s->object_size; if (s->flags & SLAB_RED_ZONE) { + if (!check_bytes_and_report(s, page, object, "Redzone", + object - s->red_left_pad, val, s->red_left_pad)) + return 0; + if (!check_bytes_and_report(s, page, object, "Redzone", endobject, val, s->inuse - s->object_size)) return 0; @@ -1391,7 +1430,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) setup_object(s, page, last); set_freepointer(s, last, NULL); - page->freelist = start; + page->freelist = fixup_red_left(s, start); page->inuse = page->objects; page->frozen = 1; out: @@ -2973,7 +3012,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) */ size += 2 * sizeof(struct track); - if (flags & SLAB_RED_ZONE) + if (flags & SLAB_RED_ZONE) { /* * Add some empty padding so that we can catch * overwrites from earlier objects rather than let @@ -2982,6 +3021,11 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) * of the object. */ size += sizeof(void *); + + s->red_left_pad = sizeof(void *); + s->red_left_pad = ALIGN(s->red_left_pad, s->align); + size += s->red_left_pad; + } #endif /* -- GitLab From c7375842e15ee97659b42c82ad771cd25b3a5433 Mon Sep 17 00:00:00 2001 From: Mike B Date: Wed, 24 Feb 2021 00:02:16 +0100 Subject: [PATCH 016/528] Android: Implement new binder, taken from CAF with some fixes from master --- .../configs/kitakami_karin_windy_defconfig | 2 + drivers/android/Kconfig | 21 +- drivers/android/Makefile | 3 +- drivers/android/binder.c | 4929 +++++++++++------ drivers/android/binder.h | 26 + drivers/android/binder_alloc.c | 833 +++ drivers/android/binder_alloc.h | 167 + drivers/android/binder_alloc_selftest.c | 270 + drivers/android/binder_trace.h | 127 +- include/uapi/linux/android/binder.h | 112 +- 10 files changed, 4738 insertions(+), 1752 deletions(-) create mode 100644 drivers/android/binder.h create mode 100644 drivers/android/binder_alloc.c create mode 100644 drivers/android/binder_alloc.h create mode 100644 drivers/android/binder_alloc_selftest.c diff --git a/arch/arm64/configs/kitakami_karin_windy_defconfig b/arch/arm64/configs/kitakami_karin_windy_defconfig index 212cc4b42ccb..f96f41e7a804 100644 --- a/arch/arm64/configs/kitakami_karin_windy_defconfig +++ b/arch/arm64/configs/kitakami_karin_windy_defconfig @@ -2,6 +2,8 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HARDENED_USERCOPY=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_LOG_BUF_SHIFT=18 CONFIG_CGROUPS=y diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 4d4cdc1a6e25..a8e55b756d7d 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -9,7 +9,7 @@ if ANDROID config ANDROID_BINDER_IPC bool "Android Binder IPC Driver" - depends on MMU + depends on MMU && !M68K default n ---help--- Binder is used in Android for both communication between processes, @@ -31,18 +31,15 @@ config ANDROID_BINDER_DEVICES created. Each binder device has its own context manager, and is therefore logically separated from the other devices. -config ANDROID_BINDER_IPC_32BIT - bool - depends on !64BIT && ANDROID_BINDER_IPC - default y - ---help--- - The Binder API has been changed to support both 32 and 64bit - applications in a mixed environment. - - Enable this to support an old 32-bit Android user-space (v4.4 and - earlier). +config ANDROID_BINDER_IPC_SELFTEST + bool "Android Binder IPC Driver Selftest" + depends on ANDROID_BINDER_IPC + ---help--- + This feature allows binder selftest to run. - Note that enabling this will break newer Android user-space. + Binder selftest checks the allocation and free of binder buffers + exhaustively with combinations of various buffer sizes and + alignments. endif # if ANDROID diff --git a/drivers/android/Makefile b/drivers/android/Makefile index 3b7e4b072c58..0eae34092aca 100644 --- a/drivers/android/Makefile +++ b/drivers/android/Makefile @@ -1,3 +1,4 @@ ccflags-y += -I$(src) # needed for trace events -obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o +obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o +obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o \ No newline at end of file diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 5eb31c760d28..14aa274a3865 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -15,6 +15,40 @@ * */ +/* + * Locking overview + * + * There are 3 main spinlocks which must be acquired in the + * order shown: + * + * 1) proc->outer_lock : protects binder_ref + * binder_proc_lock() and binder_proc_unlock() are + * used to acq/rel. + * 2) node->lock : protects most fields of binder_node. + * binder_node_lock() and binder_node_unlock() are + * used to acq/rel + * 3) proc->inner_lock : protects the thread and node lists + * (proc->threads, proc->waiting_threads, proc->nodes) + * and all todo lists associated with the binder_proc + * (proc->todo, thread->todo, proc->delivered_death and + * node->async_todo), as well as thread->transaction_stack + * binder_inner_proc_lock() and binder_inner_proc_unlock() + * are used to acq/rel + * + * Any lock under procA must never be nested under any lock at the same + * level or below on procB. + * + * Functions that require a lock held on entry indicate which lock + * in the suffix of the function name: + * + * foo_olocked() : requires node->outer_lock + * foo_nlocked() : requires node->lock + * foo_ilocked() : requires proc->inner_lock + * foo_oilocked(): requires proc->outer_lock and proc->inner_lock + * foo_nilocked(): requires node->lock and proc->inner_lock + * ... + */ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -25,7 +59,6 @@ #include #include #include -#include #include #include #include @@ -33,27 +66,32 @@ #include #include #include +#include #include #include -#include -#include #include #include +#include +#include -#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT -#define BINDER_IPC_32BIT 1 -#endif - -#include +#include "binder.h" +#include "binder_alloc.h" #include "binder_trace.h" -#define BINDER_MIN_ALLOC (1 * PAGE_SIZE) +static HLIST_HEAD(binder_deferred_list); +static DEFINE_MUTEX(binder_deferred_lock); static HLIST_HEAD(binder_devices); +static HLIST_HEAD(binder_procs); +static DEFINE_MUTEX(binder_procs_lock); + +static HLIST_HEAD(binder_dead_nodes); +static DEFINE_SPINLOCK(binder_dead_nodes_lock); static struct dentry *binder_debugfs_dir_entry_root; static struct dentry *binder_debugfs_dir_entry_proc; -atomic_t binder_last_id; +static atomic_t binder_last_id; +static struct workqueue_struct *binder_deferred_workqueue; #define BINDER_DEBUG_ENTRY(name) \ static int binder_##name##_open(struct inode *inode, struct file *file) \ @@ -85,6 +123,9 @@ BINDER_DEBUG_ENTRY(proc); #define BINDER_SMALL_BUF_SIZE (PAGE_SIZE * 64) +#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20) +#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) + enum { BINDER_DEBUG_USER_ERROR = 1U << 0, BINDER_DEBUG_FAILED_TRANSACTION = 1U << 1, @@ -99,16 +140,12 @@ enum { BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10, BINDER_DEBUG_FREE_BUFFER = 1U << 11, BINDER_DEBUG_INTERNAL_REFS = 1U << 12, - BINDER_DEBUG_BUFFER_ALLOC = 1U << 13, - BINDER_DEBUG_PRIORITY_CAP = 1U << 14, - BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15, + BINDER_DEBUG_PRIORITY_CAP = 1U << 13, + BINDER_DEBUG_SPINLOCKS = 1U << 14, }; -static uint32_t binder_debug_mask; - -module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); - -static bool binder_debug_no_lock; -module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO); +static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | + BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; +module_param_named(debug_mask, binder_debug_mask, uint, 0644); static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; module_param_named(devices, binder_devices_param, charp, S_IRUGO); @@ -127,18 +164,18 @@ static int binder_set_stop_on_user_error(const char *val, return ret; } module_param_call(stop_on_user_error, binder_set_stop_on_user_error, - param_get_int, &binder_stop_on_user_error, S_IWUSR | S_IRUGO); + param_get_int, &binder_stop_on_user_error, 0644); #define binder_debug(mask, x...) \ do { \ if (binder_debug_mask & mask) \ - pr_info(x); \ + pr_info_ratelimited(x); \ } while (0) #define binder_user_error(x...) \ do { \ if (binder_debug_mask & BINDER_DEBUG_USER_ERROR) \ - pr_info(x); \ + pr_info_ratelimited(x); \ if (binder_stop_on_user_error) \ binder_stop_on_user_error = 2; \ } while (0) @@ -166,30 +203,27 @@ enum binder_stat_types { }; struct binder_stats { - int br[_IOC_NR(BR_FAILED_REPLY) + 1]; - int bc[_IOC_NR(BC_REPLY_SG) + 1]; -}; - -/* These are still global, since it's not always easy to get the context */ -struct binder_obj_stats { + atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; + atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; atomic_t obj_created[BINDER_STAT_COUNT]; atomic_t obj_deleted[BINDER_STAT_COUNT]; }; -static struct binder_obj_stats binder_obj_stats; +static struct binder_stats binder_stats; static inline void binder_stats_deleted(enum binder_stat_types type) { - atomic_inc(&binder_obj_stats.obj_deleted[type]); + atomic_inc(&binder_stats.obj_deleted[type]); } static inline void binder_stats_created(enum binder_stat_types type) { - atomic_inc(&binder_obj_stats.obj_created[type]); + atomic_inc(&binder_stats.obj_created[type]); } struct binder_transaction_log_entry { int debug_id; + int debug_id_done; int call_type; int from_proc; int from_thread; @@ -199,48 +233,46 @@ struct binder_transaction_log_entry { int to_node; int data_size; int offsets_size; + int return_error_line; + uint32_t return_error; + uint32_t return_error_param; const char *context_name; }; struct binder_transaction_log { - int next; - int full; + atomic_t cur; + bool full; struct binder_transaction_log_entry entry[32]; }; +static struct binder_transaction_log binder_transaction_log; +static struct binder_transaction_log binder_transaction_log_failed; static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) { struct binder_transaction_log_entry *e; + unsigned int cur = atomic_inc_return(&log->cur); - e = &log->entry[log->next]; + if (cur >= ARRAY_SIZE(log->entry)) + log->full = true; + e = &log->entry[cur % ARRAY_SIZE(log->entry)]; + WRITE_ONCE(e->debug_id_done, 0); + /* + * write-barrier to synchronize access to e->debug_id_done. + * We make sure the initialized 0 value is seen before + * memset() other fields are zeroed by memset. + */ + smp_wmb(); memset(e, 0, sizeof(*e)); - log->next++; - if (log->next == ARRAY_SIZE(log->entry)) { - log->next = 0; - log->full = 1; - } return e; } struct binder_context { struct binder_node *binder_context_mgr_node; + struct mutex context_mgr_node_lock; + kuid_t binder_context_mgr_uid; const char *name; - - struct mutex binder_main_lock; - struct mutex binder_deferred_lock; - struct mutex binder_mmap_lock; - - struct hlist_head binder_procs; - struct hlist_head binder_dead_nodes; - struct hlist_head binder_deferred_list; - - struct work_struct deferred_work; - struct workqueue_struct *binder_deferred_workqueue; - struct binder_transaction_log transaction_log; - struct binder_transaction_log transaction_log_failed; - - struct binder_stats binder_stats; + bool inherit_fifo_prio; }; struct binder_device { @@ -249,11 +281,20 @@ struct binder_device { struct binder_context context; }; +/** + * struct binder_work - work enqueued on a worklist + * @entry: node enqueued on list + * @type: type of work to be performed + * + * There are separate work lists for proc, thread, and node (async). + */ struct binder_work { struct list_head entry; + enum { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, + BINDER_WORK_RETURN_ERROR, BINDER_WORK_NODE, BINDER_WORK_DEAD_BINDER, BINDER_WORK_DEAD_BINDER_AND_CLEAR, @@ -261,8 +302,77 @@ struct binder_work { } type; }; +struct binder_error { + struct binder_work work; + uint32_t cmd; +}; + +/** + * struct binder_node - binder node bookkeeping + * @debug_id: unique ID for debugging + * (invariant after initialized) + * @lock: lock for node fields + * @work: worklist element for node work + * (protected by @proc->inner_lock) + * @rb_node: element for proc->nodes tree + * (protected by @proc->inner_lock) + * @dead_node: element for binder_dead_nodes list + * (protected by binder_dead_nodes_lock) + * @proc: binder_proc that owns this node + * (invariant after initialized) + * @refs: list of references on this node + * (protected by @lock) + * @internal_strong_refs: used to take strong references when + * initiating a transaction + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_weak_refs: weak user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_strong_refs: strong user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @tmp_refs: temporary kernel refs + * (protected by @proc->inner_lock while @proc + * is valid, and by binder_dead_nodes_lock + * if @proc is NULL. During inc/dec and node release + * it is also protected by @lock to provide safety + * as the node dies and @proc becomes NULL) + * @ptr: userspace pointer for node + * (invariant, no lock needed) + * @cookie: userspace cookie for node + * (invariant, no lock needed) + * @has_strong_ref: userspace notified of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_strong_ref: userspace has acked notification of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_weak_ref: userspace notified of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_weak_ref: userspace has acked notification of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_async_transaction: async transaction to node in progress + * (protected by @lock) + * @sched_policy: minimum scheduling policy for node + * (invariant after initialized) + * @accept_fds: file descriptor operations supported for node + * (invariant after initialized) + * @min_priority: minimum scheduling priority + * (invariant after initialized) + * @inherit_rt: inherit RT scheduling policy from caller + * @txn_security_ctx: require sender's security context + * (invariant after initialized) + * @async_todo: list of async work items + * (protected by @proc->inner_lock) + * + * Bookkeeping structure for binder nodes. + */ struct binder_node { int debug_id; + spinlock_t lock; struct binder_work work; union { struct rb_node rb_node; @@ -273,99 +383,200 @@ struct binder_node { int internal_strong_refs; int local_weak_refs; int local_strong_refs; + int tmp_refs; binder_uintptr_t ptr; binder_uintptr_t cookie; - unsigned has_strong_ref:1; - unsigned pending_strong_ref:1; - unsigned has_weak_ref:1; - unsigned pending_weak_ref:1; - unsigned has_async_transaction:1; - unsigned accept_fds:1; - unsigned min_priority:8; + struct { + /* + * bitfield elements protected by + * proc inner_lock + */ + u8 has_strong_ref:1; + u8 pending_strong_ref:1; + u8 has_weak_ref:1; + u8 pending_weak_ref:1; + }; + struct { + /* + * invariant after initialization + */ + u8 sched_policy:2; + u8 inherit_rt:1; + u8 accept_fds:1; + u8 txn_security_ctx:1; + u8 min_priority; + }; + bool has_async_transaction; struct list_head async_todo; }; struct binder_ref_death { + /** + * @work: worklist element for death notifications + * (protected by inner_lock of the proc that + * this ref belongs to) + */ struct binder_work work; binder_uintptr_t cookie; }; +/** + * struct binder_ref_data - binder_ref counts and id + * @debug_id: unique ID for the ref + * @desc: unique userspace handle for ref + * @strong: strong ref count (debugging only if not locked) + * @weak: weak ref count (debugging only if not locked) + * + * Structure to hold ref count and ref id information. Since + * the actual ref can only be accessed with a lock, this structure + * is used to return information about the ref to callers of + * ref inc/dec functions. + */ +struct binder_ref_data { + int debug_id; + uint32_t desc; + int strong; + int weak; +}; + +/** + * struct binder_ref - struct to track references on nodes + * @data: binder_ref_data containing id, handle, and current refcounts + * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree + * @rb_node_node: node for lookup by @node in proc's rb_tree + * @node_entry: list entry for node->refs list in target node + * (protected by @node->lock) + * @proc: binder_proc containing ref + * @node: binder_node of target node. When cleaning up a + * ref for deletion in binder_cleanup_ref, a non-NULL + * @node indicates the node must be freed + * @death: pointer to death notification (ref_death) if requested + * (protected by @node->lock) + * + * Structure to track references from procA to target node (on procB). This + * structure is unsafe to access without holding @proc->outer_lock. + */ struct binder_ref { /* Lookups needed: */ /* node + proc => ref (transaction) */ /* desc + proc => ref (transaction, inc/dec ref) */ /* node => refs + procs (proc exit) */ - int debug_id; + struct binder_ref_data data; struct rb_node rb_node_desc; struct rb_node rb_node_node; struct hlist_node node_entry; struct binder_proc *proc; struct binder_node *node; - uint32_t desc; - int strong; - int weak; struct binder_ref_death *death; }; -struct binder_buffer { - struct list_head entry; /* free and allocated entries by address */ - struct rb_node rb_node; /* free entry by size or allocated entry */ - /* by address */ - unsigned free:1; - unsigned allow_user_free:1; - unsigned async_transaction:1; - unsigned debug_id:29; - - struct binder_transaction *transaction; - - struct binder_node *target_node; - size_t data_size; - size_t offsets_size; - size_t extra_buffers_size; - void *data; -}; - enum binder_deferred_state { BINDER_DEFERRED_PUT_FILES = 0x01, BINDER_DEFERRED_FLUSH = 0x02, BINDER_DEFERRED_RELEASE = 0x04, }; +/** + * struct binder_priority - scheduler policy and priority + * @sched_policy scheduler policy + * @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT + * + * The binder driver supports inheriting the following scheduler policies: + * SCHED_NORMAL + * SCHED_BATCH + * SCHED_FIFO + * SCHED_RR + */ +struct binder_priority { + unsigned int sched_policy; + int prio; +}; + +/** + * struct binder_proc - binder process bookkeeping + * @proc_node: element for binder_procs list + * @threads: rbtree of binder_threads in this proc + * (protected by @inner_lock) + * @nodes: rbtree of binder nodes associated with + * this proc ordered by node->ptr + * (protected by @inner_lock) + * @refs_by_desc: rbtree of refs ordered by ref->desc + * (protected by @outer_lock) + * @refs_by_node: rbtree of refs ordered by ref->node + * (protected by @outer_lock) + * @waiting_threads: threads currently waiting for proc work + * (protected by @inner_lock) + * @pid PID of group_leader of process + * (invariant after initialized) + * @tsk task_struct for group_leader of process + * (invariant after initialized) + * @files files_struct for process + * (protected by @files_lock) + * @files_lock mutex to protect @files + * @deferred_work_node: element for binder_deferred_list + * (protected by binder_deferred_lock) + * @deferred_work: bitmap of deferred work to perform + * (protected by binder_deferred_lock) + * @is_dead: process is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @inner_lock) + * @todo: list of work for this process + * (protected by @inner_lock) + * @stats: per-process binder statistics + * (atomics, no lock needed) + * @delivered_death: list of delivered death notification + * (protected by @inner_lock) + * @max_threads: cap on number of binder threads + * (protected by @inner_lock) + * @requested_threads: number of binder threads requested but not + * yet started. In current implementation, can + * only be 0 or 1. + * (protected by @inner_lock) + * @requested_threads_started: number binder threads started + * (protected by @inner_lock) + * @tmp_ref: temporary reference to indicate proc is in use + * (atomic since @proc->inner_lock cannot + * always be acquired) + * @default_priority: default scheduler priority + * (invariant after initialized) + * @debugfs_entry: debugfs node + * @alloc: binder allocator bookkeeping + * @context: binder_context for this proc + * (invariant after initialized) + * @inner_lock: can nest under outer_lock and/or node lock + * @outer_lock: no nesting under innor or node lock + * Lock order: 1) outer, 2) node, 3) inner + * + * Bookkeeping structure for binder processes + */ struct binder_proc { struct hlist_node proc_node; struct rb_root threads; struct rb_root nodes; struct rb_root refs_by_desc; struct rb_root refs_by_node; + struct list_head waiting_threads; int pid; - struct vm_area_struct *vma; - struct mm_struct *vma_vm_mm; struct task_struct *tsk; struct files_struct *files; + struct mutex files_lock; struct hlist_node deferred_work_node; int deferred_work; - void *buffer; - ptrdiff_t user_buffer_offset; - - struct list_head buffers; - struct rb_root free_buffers; - struct rb_root allocated_buffers; - size_t free_async_space; + bool is_dead; - struct page **pages; - size_t buffer_size; - uint32_t buffer_free; struct list_head todo; - wait_queue_head_t wait; struct binder_stats stats; struct list_head delivered_death; int max_threads; int requested_threads; int requested_threads_started; - int ready_threads; - long default_priority; + atomic_t tmp_ref; + struct binder_priority default_priority; struct dentry *debugfs_entry; + struct binder_alloc alloc; struct binder_context *context; + spinlock_t inner_lock; + spinlock_t outer_lock; }; enum { @@ -374,22 +585,63 @@ enum { BINDER_LOOPER_STATE_EXITED = 0x04, BINDER_LOOPER_STATE_INVALID = 0x08, BINDER_LOOPER_STATE_WAITING = 0x10, - BINDER_LOOPER_STATE_NEED_RETURN = 0x20 + BINDER_LOOPER_STATE_POLL = 0x20, }; +/** + * struct binder_thread - binder thread bookkeeping + * @proc: binder process for this thread + * (invariant after initialization) + * @rb_node: element for proc->threads rbtree + * (protected by @proc->inner_lock) + * @waiting_thread_node: element for @proc->waiting_threads list + * (protected by @proc->inner_lock) + * @pid: PID for this thread + * (invariant after initialization) + * @looper: bitmap of looping state + * (only accessed by this thread) + * @looper_needs_return: looping thread needs to exit driver + * (no lock needed) + * @transaction_stack: stack of in-progress transactions for this thread + * (protected by @proc->inner_lock) + * @todo: list of work to do for this thread + * (protected by @proc->inner_lock) + * @process_todo: whether work in @todo should be processed + * (protected by @proc->inner_lock) + * @return_error: transaction errors reported by this thread + * (only accessed by this thread) + * @reply_error: transaction errors reported by target thread + * (protected by @proc->inner_lock) + * @wait: wait queue for thread work + * @stats: per-thread statistics + * (atomics, no lock needed) + * @tmp_ref: temporary reference to indicate thread is in use + * (atomic since @proc->inner_lock cannot + * always be acquired) + * @is_dead: thread is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @proc->inner_lock) + * @task: struct task_struct for this thread + * + * Bookkeeping structure for binder threads. + */ struct binder_thread { struct binder_proc *proc; struct rb_node rb_node; + struct list_head waiting_thread_node; int pid; - int looper; + int looper; /* only modified by this thread */ + bool looper_need_return; /* can be written by other thread */ struct binder_transaction *transaction_stack; struct list_head todo; - uint32_t return_error; /* Write failed, return error code in read buf */ - uint32_t return_error2; /* Write failed, return error code in read */ - /* buffer. Used when sending a reply to a dead process that */ - /* we are also waiting on */ + bool process_todo; + struct binder_error return_error; + struct binder_error reply_error; wait_queue_head_t wait; struct binder_stats stats; + atomic_t tmp_ref; + bool is_dead; + struct task_struct *task; }; struct binder_transaction { @@ -406,633 +658,641 @@ struct binder_transaction { struct binder_buffer *buffer; unsigned int code; unsigned int flags; - long priority; - long saved_priority; + struct binder_priority priority; + struct binder_priority saved_priority; + bool set_priority_called; kuid_t sender_euid; + binder_uintptr_t security_ctx; + /** + * @lock: protects @from, @to_proc, and @to_thread + * + * @from, @to_proc, and @to_thread can be set to NULL + * during thread teardown + */ + spinlock_t lock; }; +/** + * binder_proc_lock() - Acquire outer lock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Acquires proc->outer_lock. Used to protect binder_ref + * structures associated with the given proc. + */ +#define binder_proc_lock(proc) _binder_proc_lock(proc, __LINE__) static void -binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); - -static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) +_binder_proc_lock(struct binder_proc *proc, int line) { - struct files_struct *files = proc->files; - unsigned long rlim_cur; - unsigned long irqs; - int ret; - - if (files == NULL) - return -ESRCH; - - if (!lock_task_sighand(proc->tsk, &irqs)) - return -EMFILE; - - rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); - unlock_task_sighand(proc->tsk, &irqs); - - preempt_enable_no_resched(); - ret = __alloc_fd(files, 0, rlim_cur, flags); - preempt_disable(); - - return ret; + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&proc->outer_lock); } -/* - * copied from fd_install +/** + * binder_proc_unlock() - Release spinlock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Release lock acquired via binder_proc_lock() */ -static void task_fd_install( - struct binder_proc *proc, unsigned int fd, struct file *file) +#define binder_proc_unlock(_proc) _binder_proc_unlock(_proc, __LINE__) +static void +_binder_proc_unlock(struct binder_proc *proc, int line) { - if (proc->files) { - preempt_enable_no_resched(); - __fd_install(proc->files, fd, file); - preempt_disable(); - } + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_unlock(&proc->outer_lock); } -/* - * copied from sys_close +/** + * binder_inner_proc_lock() - Acquire inner lock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Acquires proc->inner_lock. Used to protect todo lists */ -static long task_close_fd(struct binder_proc *proc, unsigned int fd) +#define binder_inner_proc_lock(proc) _binder_inner_proc_lock(proc, __LINE__) +static void +_binder_inner_proc_lock(struct binder_proc *proc, int line) { - int retval; - - if (proc->files == NULL) - return -ESRCH; - - retval = __close_fd(proc->files, fd); - /* can't restart close syscall because file table entry was cleared */ - if (unlikely(retval == -ERESTARTSYS || - retval == -ERESTARTNOINTR || - retval == -ERESTARTNOHAND || - retval == -ERESTART_RESTARTBLOCK)) - retval = -EINTR; - - return retval; + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&proc->inner_lock); } -static inline void binder_lock(struct binder_context *context, const char *tag) +/** + * binder_inner_proc_unlock() - Release inner lock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Release lock acquired via binder_inner_proc_lock() + */ +#define binder_inner_proc_unlock(proc) _binder_inner_proc_unlock(proc, __LINE__) +static void +_binder_inner_proc_unlock(struct binder_proc *proc, int line) { - trace_binder_lock(tag); - mutex_lock(&context->binder_main_lock); - preempt_disable(); - trace_binder_locked(tag); + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_unlock(&proc->inner_lock); } -static inline void binder_unlock(struct binder_context *context, - const char *tag) +/** + * binder_node_lock() - Acquire spinlock for given binder_node + * @node: struct binder_node to acquire + * + * Acquires node->lock. Used to protect binder_node fields + */ +#define binder_node_lock(node) _binder_node_lock(node, __LINE__) +static void +_binder_node_lock(struct binder_node *node, int line) { - trace_binder_unlock(tag); - mutex_unlock(&context->binder_main_lock); - preempt_enable(); + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&node->lock); } -static inline void *kzalloc_preempt_disabled(size_t size) +/** + * binder_node_unlock() - Release spinlock for given binder_proc + * @node: struct binder_node to acquire + * + * Release lock acquired via binder_node_lock() + */ +#define binder_node_unlock(node) _binder_node_unlock(node, __LINE__) +static void +_binder_node_unlock(struct binder_node *node, int line) { - void *ptr; + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_unlock(&node->lock); +} - ptr = kzalloc(size, GFP_NOWAIT); - if (ptr) - return ptr; +/** + * binder_node_inner_lock() - Acquire node and inner locks + * @node: struct binder_node to acquire + * + * Acquires node->lock. If node->proc also acquires + * proc->inner_lock. Used to protect binder_node fields + */ +#define binder_node_inner_lock(node) _binder_node_inner_lock(node, __LINE__) +static void +_binder_node_inner_lock(struct binder_node *node, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&node->lock); + if (node->proc) + binder_inner_proc_lock(node->proc); +} - preempt_enable_no_resched(); - ptr = kzalloc(size, GFP_KERNEL); - preempt_disable(); +/** + * binder_node_unlock() - Release node and inner locks + * @node: struct binder_node to acquire + * + * Release lock acquired via binder_node_lock() + */ +#define binder_node_inner_unlock(node) _binder_node_inner_unlock(node, __LINE__) +static void +_binder_node_inner_unlock(struct binder_node *node, int line) +{ + struct binder_proc *proc = node->proc; - return ptr; + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + if (proc) + binder_inner_proc_unlock(proc); + spin_unlock(&node->lock); } -static inline long copy_to_user_preempt_disabled(void __user *to, const void *from, long n) +static bool binder_worklist_empty_ilocked(struct list_head *list) { - long ret; - - preempt_enable_no_resched(); - ret = copy_to_user(to, from, n); - preempt_disable(); - return ret; + return list_empty(list); } -static inline long copy_from_user_preempt_disabled(void *to, const void __user *from, long n) +/** + * binder_worklist_empty() - Check if no items on the work list + * @proc: binder_proc associated with list + * @list: list to check + * + * Return: true if there are no items on list, else false + */ +static bool binder_worklist_empty(struct binder_proc *proc, + struct list_head *list) { - long ret; + bool ret; - preempt_enable_no_resched(); - ret = copy_from_user(to, from, n); - preempt_disable(); + binder_inner_proc_lock(proc); + ret = binder_worklist_empty_ilocked(list); + binder_inner_proc_unlock(proc); return ret; } -#define get_user_preempt_disabled(x, ptr) \ -({ \ - int __ret; \ - preempt_enable_no_resched(); \ - __ret = get_user(x, ptr); \ - preempt_disable(); \ - __ret; \ -}) - -#define put_user_preempt_disabled(x, ptr) \ -({ \ - int __ret; \ - preempt_enable_no_resched(); \ - __ret = put_user(x, ptr); \ - preempt_disable(); \ - __ret; \ -}) +/** + * binder_enqueue_work_ilocked() - Add an item to the work list + * @work: struct binder_work to add to list + * @target_list: list to add work to + * + * Adds the work to the specified list. Asserts that work + * is not already on a list. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_work_ilocked(struct binder_work *work, + struct list_head *target_list) +{ + BUG_ON(target_list == NULL); + BUG_ON(work->entry.next && !list_empty(&work->entry)); + list_add_tail(&work->entry, target_list); +} -static void binder_set_nice(long nice) +/** + * binder_enqueue_deferred_thread_work_ilocked() - Add deferred thread work + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread. Doesn't set the process_todo + * flag, which means that (if it wasn't already set) the thread will go to + * sleep without handling this work when it calls read. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread, + struct binder_work *work) { - long min_nice; + WARN_ON(!list_empty(&thread->waiting_thread_node)); + binder_enqueue_work_ilocked(work, &thread->todo); +} - if (can_nice(current, nice)) { - set_user_nice(current, nice); - return; - } - min_nice = 20 - current->signal->rlim[RLIMIT_NICE].rlim_cur; - binder_debug(BINDER_DEBUG_PRIORITY_CAP, - "%d: nice value %ld not allowed use %ld instead\n", - current->pid, nice, min_nice); - set_user_nice(current, min_nice); - if (min_nice < 20) - return; - binder_user_error("%d RLIMIT_NICE not set\n", current->pid); +/** + * binder_enqueue_thread_work_ilocked() - Add an item to the thread work list + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread, and enables processing + * of the todo queue. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_thread_work_ilocked(struct binder_thread *thread, + struct binder_work *work) +{ + WARN_ON(!list_empty(&thread->waiting_thread_node)); + binder_enqueue_work_ilocked(work, &thread->todo); + thread->process_todo = true; } -static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer) +/** + * binder_enqueue_thread_work() - Add an item to the thread work list + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread, and enables processing + * of the todo queue. + */ +static void +binder_enqueue_thread_work(struct binder_thread *thread, + struct binder_work *work) { - return list_entry(buffer->entry.next, struct binder_buffer, entry); + binder_inner_proc_lock(thread->proc); + binder_enqueue_thread_work_ilocked(thread, work); + binder_inner_proc_unlock(thread->proc); } -static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer) +static void +binder_dequeue_work_ilocked(struct binder_work *work) { - return list_entry(buffer->entry.prev, struct binder_buffer, entry); + list_del_init(&work->entry); } -static size_t binder_buffer_size(struct binder_proc *proc, - struct binder_buffer *buffer) +/** + * binder_dequeue_work() - Removes an item from the work list + * @proc: binder_proc associated with list + * @work: struct binder_work to remove from list + * + * Removes the specified work item from whatever list it is on. + * Can safely be called if work is not on any list. + */ +static void +binder_dequeue_work(struct binder_proc *proc, struct binder_work *work) { - if (list_is_last(&buffer->entry, &proc->buffers)) - return (u8 *)proc->buffer + - proc->buffer_size - (u8 *)buffer->data; - return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data; + binder_inner_proc_lock(proc); + binder_dequeue_work_ilocked(work); + binder_inner_proc_unlock(proc); } -static void binder_insert_free_buffer(struct binder_proc *proc, - struct binder_buffer *new_buffer) +static struct binder_work *binder_dequeue_work_head_ilocked( + struct list_head *list) { - struct rb_node **p = &proc->free_buffers.rb_node; - struct rb_node *parent = NULL; - struct binder_buffer *buffer; - size_t buffer_size; - size_t new_buffer_size; + struct binder_work *w; - BUG_ON(!new_buffer->free); + w = list_first_entry_or_null(list, struct binder_work, entry); + if (w) + list_del_init(&w->entry); + return w; +} - new_buffer_size = binder_buffer_size(proc, new_buffer); +/** + * binder_dequeue_work_head() - Dequeues the item at head of list + * @proc: binder_proc associated with list + * @list: list to dequeue head + * + * Removes the head of the list if there are items on the list + * + * Return: pointer dequeued binder_work, NULL if list was empty + */ +static struct binder_work *binder_dequeue_work_head( + struct binder_proc *proc, + struct list_head *list) +{ + struct binder_work *w; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: add free buffer, size %zd, at %pK\n", - proc->pid, new_buffer_size, new_buffer); + binder_inner_proc_lock(proc); + w = binder_dequeue_work_head_ilocked(list); + binder_inner_proc_unlock(proc); + return w; +} - while (*p) { - parent = *p; - buffer = rb_entry(parent, struct binder_buffer, rb_node); - BUG_ON(!buffer->free); +static void +binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); +static void binder_free_thread(struct binder_thread *thread); +static void binder_free_proc(struct binder_proc *proc); +static void binder_inc_node_tmpref_ilocked(struct binder_node *node); - buffer_size = binder_buffer_size(proc, buffer); +static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) +{ + unsigned long rlim_cur; + unsigned long irqs; + int ret; - if (new_buffer_size < buffer_size) - p = &parent->rb_left; - else - p = &parent->rb_right; + mutex_lock(&proc->files_lock); + if (proc->files == NULL) { + ret = -ESRCH; + goto err; + } + if (!lock_task_sighand(proc->tsk, &irqs)) { + ret = -EMFILE; + goto err; } - rb_link_node(&new_buffer->rb_node, parent, p); - rb_insert_color(&new_buffer->rb_node, &proc->free_buffers); + rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); + unlock_task_sighand(proc->tsk, &irqs); + + ret = __alloc_fd(proc->files, 0, rlim_cur, flags); +err: + mutex_unlock(&proc->files_lock); + return ret; } -static void binder_insert_allocated_buffer(struct binder_proc *proc, - struct binder_buffer *new_buffer) +/* + * copied from fd_install + */ +static void task_fd_install( + struct binder_proc *proc, unsigned int fd, struct file *file) { - struct rb_node **p = &proc->allocated_buffers.rb_node; - struct rb_node *parent = NULL; - struct binder_buffer *buffer; - - BUG_ON(new_buffer->free); - - while (*p) { - parent = *p; - buffer = rb_entry(parent, struct binder_buffer, rb_node); - BUG_ON(buffer->free); - - if (new_buffer->data < buffer->data) - p = &parent->rb_left; - else if (new_buffer->data > buffer->data) - p = &parent->rb_right; - else - BUG(); - } - rb_link_node(&new_buffer->rb_node, parent, p); - rb_insert_color(&new_buffer->rb_node, &proc->allocated_buffers); + mutex_lock(&proc->files_lock); + if (proc->files) + __fd_install(proc->files, fd, file); + mutex_unlock(&proc->files_lock); } -static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, - uintptr_t user_ptr) +/* + * copied from sys_close + */ +static long task_close_fd(struct binder_proc *proc, unsigned int fd) { - struct rb_node *n = proc->allocated_buffers.rb_node; - struct binder_buffer *buffer; - void *kern_ptr; - - kern_ptr = (void *)(user_ptr - proc->user_buffer_offset); - - while (n) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - BUG_ON(buffer->free); + int retval; - if (kern_ptr < buffer->data) - n = n->rb_left; - else if (kern_ptr > buffer->data) - n = n->rb_right; - else - return buffer; + mutex_lock(&proc->files_lock); + if (proc->files == NULL) { + retval = -ESRCH; + goto err; } - return NULL; + retval = __close_fd(proc->files, fd); + /* can't restart close syscall because file table entry was cleared */ + if (unlikely(retval == -ERESTARTSYS || + retval == -ERESTARTNOINTR || + retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK)) + retval = -EINTR; +err: + mutex_unlock(&proc->files_lock); + return retval; } -static int __binder_update_page_range(struct binder_proc *proc, int allocate, - void *start, void *end, - struct vm_area_struct *vma) +static bool binder_has_work_ilocked(struct binder_thread *thread, + bool do_proc_work) { - void *page_addr; - unsigned long user_page_addr; - struct vm_struct tmp_area; - struct page **page; - struct mm_struct *mm; + return thread->process_todo || + thread->looper_need_return || + (do_proc_work && + !binder_worklist_empty_ilocked(&thread->proc->todo)); +} - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: %s pages %pK-%pK\n", proc->pid, - allocate ? "allocate" : "free", start, end); +static bool binder_has_work(struct binder_thread *thread, bool do_proc_work) +{ + bool has_work; - if (end <= start) - return 0; + binder_inner_proc_lock(thread->proc); + has_work = binder_has_work_ilocked(thread, do_proc_work); + binder_inner_proc_unlock(thread->proc); - trace_binder_update_page_range(proc, allocate, start, end); + return has_work; +} - if (vma) - mm = NULL; - else - mm = get_task_mm(proc->tsk); +static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread) +{ + return !thread->transaction_stack && + binder_worklist_empty_ilocked(&thread->todo) && + (thread->looper & (BINDER_LOOPER_STATE_ENTERED | + BINDER_LOOPER_STATE_REGISTERED)); +} - preempt_enable_no_resched(); +static void binder_wakeup_poll_threads_ilocked(struct binder_proc *proc, + bool sync) +{ + struct rb_node *n; + struct binder_thread *thread; - if (mm) { - down_write(&mm->mmap_sem); - if (!mmget_still_valid(mm)) { - if (allocate == 0) - goto free_range; - goto err_no_vma; - } - vma = proc->vma; - if (vma && mm != proc->vma_vm_mm) { - pr_err("%d: vma mm and task mm mismatch\n", - proc->pid); - vma = NULL; + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { + thread = rb_entry(n, struct binder_thread, rb_node); + if (thread->looper & BINDER_LOOPER_STATE_POLL && + binder_available_for_proc_work_ilocked(thread)) { + if (sync) + wake_up_interruptible_sync(&thread->wait); + else + wake_up_interruptible(&thread->wait); } } +} - if (allocate == 0) - goto free_range; - - if (vma == NULL) { - pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", - proc->pid); - goto err_no_vma; - } - - for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { - int ret; - struct page **page_array_ptr; +/** + * binder_select_thread_ilocked() - selects a thread for doing proc work. + * @proc: process to select a thread from + * + * Note that calling this function moves the thread off the waiting_threads + * list, so it can only be woken up by the caller of this function, or a + * signal. Therefore, callers *should* always wake up the thread this function + * returns. + * + * Return: If there's a thread currently waiting for process work, + * returns that thread. Otherwise returns NULL. + */ +static struct binder_thread * +binder_select_thread_ilocked(struct binder_proc *proc) +{ + struct binder_thread *thread; - page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; + assert_spin_locked(&proc->inner_lock); + thread = list_first_entry_or_null(&proc->waiting_threads, + struct binder_thread, + waiting_thread_node); - BUG_ON(*page); - *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); - if (*page == NULL) { - pr_err("%d: binder_alloc_buf failed for page at %pK\n", - proc->pid, page_addr); - goto err_alloc_page_failed; - } - tmp_area.addr = page_addr; - tmp_area.size = PAGE_SIZE + PAGE_SIZE /* guard page? */; - page_array_ptr = page; - ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr); - if (ret) { - pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n", - proc->pid, page_addr); - goto err_map_kernel_failed; - } - user_page_addr = - (uintptr_t)page_addr + proc->user_buffer_offset; - ret = vm_insert_page(vma, user_page_addr, page[0]); - if (ret) { - pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", - proc->pid, user_page_addr); - goto err_vm_insert_page_failed; - } - /* vm_insert_page does not seem to increment the refcount */ - } - if (mm) { - up_write(&mm->mmap_sem); - mmput(mm); - } + if (thread) + list_del_init(&thread->waiting_thread_node); - preempt_disable(); + return thread; +} - return 0; +/** + * binder_wakeup_thread_ilocked() - wakes up a thread for doing proc work. + * @proc: process to wake up a thread in + * @thread: specific thread to wake-up (may be NULL) + * @sync: whether to do a synchronous wake-up + * + * This function wakes up a thread in the @proc process. + * The caller may provide a specific thread to wake-up in + * the @thread parameter. If @thread is NULL, this function + * will wake up threads that have called poll(). + * + * Note that for this function to work as expected, callers + * should first call binder_select_thread() to find a thread + * to handle the work (if they don't have a thread already), + * and pass the result into the @thread parameter. + */ +static void binder_wakeup_thread_ilocked(struct binder_proc *proc, + struct binder_thread *thread, + bool sync) +{ + assert_spin_locked(&proc->inner_lock); -free_range: - for (page_addr = end - PAGE_SIZE; page_addr >= start; - page_addr -= PAGE_SIZE) { - page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; - if (vma) - zap_page_range(vma, (uintptr_t)page_addr + - proc->user_buffer_offset, PAGE_SIZE, NULL); -err_vm_insert_page_failed: - unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); -err_map_kernel_failed: - __free_page(*page); - *page = NULL; -err_alloc_page_failed: - ; - } -err_no_vma: - if (mm) { - up_write(&mm->mmap_sem); - mmput(mm); + if (thread) { + if (sync) + wake_up_interruptible_sync(&thread->wait); + else + wake_up_interruptible(&thread->wait); + return; } - preempt_disable(); - - return -ENOMEM; + /* Didn't find a thread waiting for proc work; this can happen + * in two scenarios: + * 1. All threads are busy handling transactions + * In that case, one of those threads should call back into + * the kernel driver soon and pick up this work. + * 2. Threads are using the (e)poll interface, in which case + * they may be blocked on the waitqueue without having been + * added to waiting_threads. For this case, we just iterate + * over all threads not handling transaction work, and + * wake them all up. We wake all because we don't know whether + * a thread that called into (e)poll is handling non-binder + * work currently. + */ + binder_wakeup_poll_threads_ilocked(proc, sync); } -static int binder_update_page_range(struct binder_proc *proc, int allocate, - void *start, void *end, - struct vm_area_struct *vma) +static void binder_wakeup_proc_ilocked(struct binder_proc *proc) { - /* - * For regular updates, move up start if needed since MIN_ALLOC pages - * are always mapped - */ - if (start - proc->buffer < BINDER_MIN_ALLOC) - start = proc->buffer + BINDER_MIN_ALLOC; + struct binder_thread *thread = binder_select_thread_ilocked(proc); - return __binder_update_page_range(proc, allocate, start, end, vma); + binder_wakeup_thread_ilocked(proc, thread, /* sync = */false); } -static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, - size_t data_size, - size_t offsets_size, - size_t extra_buffers_size, - int is_async) +static bool is_rt_policy(int policy) { - struct rb_node *n = proc->free_buffers.rb_node; - struct binder_buffer *buffer; - size_t buffer_size; - struct rb_node *best_fit = NULL; - void *has_page_addr; - void *end_page_addr; - size_t size, data_offsets_size; - - if (proc->vma == NULL) { - pr_err("%d: binder_alloc_buf, no vma\n", - proc->pid); - return NULL; - } - - data_offsets_size = ALIGN(data_size, sizeof(void *)) + - ALIGN(offsets_size, sizeof(void *)); - - if (data_offsets_size < data_size || data_offsets_size < offsets_size) { - binder_user_error("%d: got transaction with invalid size %zd-%zd\n", - proc->pid, data_size, offsets_size); - return NULL; - } - size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); - if (size < data_offsets_size || size < extra_buffers_size) { - binder_user_error("%d: got transaction with invalid extra_buffers_size %zd\n", - proc->pid, extra_buffers_size); - return NULL; - } - if (is_async && - proc->free_async_space < size + sizeof(struct binder_buffer)) { - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd failed, no async space left\n", - proc->pid, size); - return NULL; - } - - /* Pad 0-size buffers so they get assigned unique addresses */ - size = max(size, sizeof(void *)); - - while (n) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - BUG_ON(!buffer->free); - buffer_size = binder_buffer_size(proc, buffer); - - if (size < buffer_size) { - best_fit = n; - n = n->rb_left; - } else if (size > buffer_size) - n = n->rb_right; - else { - best_fit = n; - break; - } - } - if (best_fit == NULL) { - pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", - proc->pid, size); - return NULL; - } - if (n == NULL) { - buffer = rb_entry(best_fit, struct binder_buffer, rb_node); - buffer_size = binder_buffer_size(proc, buffer); - } + return policy == SCHED_FIFO || policy == SCHED_RR; +} - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n", - proc->pid, size, buffer, buffer_size); +static bool is_fair_policy(int policy) +{ + return policy == SCHED_NORMAL || policy == SCHED_BATCH; +} - has_page_addr = - (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); - WARN_ON(n && buffer_size != size); - end_page_addr = - (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); - if (end_page_addr > has_page_addr) - end_page_addr = has_page_addr; - if (binder_update_page_range(proc, 1, - (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL)) - return NULL; - if (buffer_size != size) { - struct binder_buffer *new_buffer; - - new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (!new_buffer) { - pr_err("%s: %d failed to alloc new buffer struct\n", - __func__, proc->pid); - goto err_alloc_buf_struct_failed; - } - new_buffer->data = (u8 *)buffer->data + size; - list_add(&new_buffer->entry, &buffer->entry); - new_buffer->free = 1; - binder_insert_free_buffer(proc, new_buffer); - } - - rb_erase(best_fit, &proc->free_buffers); - buffer->free = 0; - binder_insert_allocated_buffer(proc, buffer); - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd got %pK\n", - proc->pid, size, buffer); - buffer->data_size = data_size; - buffer->offsets_size = offsets_size; - buffer->extra_buffers_size = extra_buffers_size; - buffer->async_transaction = is_async; - if (is_async) { - proc->free_async_space -= size + sizeof(struct binder_buffer); - binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, - "%d: binder_alloc_buf size %zd async free %zd\n", - proc->pid, size, proc->free_async_space); - } - - return buffer; - -err_alloc_buf_struct_failed: - binder_update_page_range(proc, 0, - (void *)PAGE_ALIGN((uintptr_t)buffer->data), - end_page_addr, NULL); - return NULL; +static bool binder_supported_policy(int policy) +{ + return is_fair_policy(policy) || is_rt_policy(policy); } -static void *buffer_start_page(struct binder_buffer *buffer) +static int to_userspace_prio(int policy, int kernel_priority) { - return (void *)((uintptr_t)buffer->data & PAGE_MASK); + if (is_fair_policy(policy)) + return PRIO_TO_NICE(kernel_priority); + else + return MAX_USER_RT_PRIO - 1 - kernel_priority; } -static void *prev_buffer_end_page(struct binder_buffer *buffer) +static int to_kernel_prio(int policy, int user_priority) { - return (void *)(((uintptr_t)(buffer->data) - 1) & PAGE_MASK); + if (is_fair_policy(policy)) + return NICE_TO_PRIO(user_priority); + else + return MAX_USER_RT_PRIO - 1 - user_priority; } -static void binder_delete_free_buffer(struct binder_proc *proc, - struct binder_buffer *buffer) +static void binder_do_set_priority(struct task_struct *task, + struct binder_priority desired, + bool verify) { - struct binder_buffer *prev, *next = NULL; - bool to_free = true; + int priority; /* user-space prio value */ + bool has_cap_nice; + unsigned int policy = desired.sched_policy; - BUG_ON(proc->buffers.next == &buffer->entry); - prev = binder_buffer_prev(buffer); - BUG_ON(!prev->free); - if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) { - to_free = false; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %pK share page with %pK\n", - proc->pid, buffer->data, prev->data); - } + if (task->policy == policy && task->normal_prio == desired.prio) + return; + + has_cap_nice = has_capability_noaudit(task, CAP_SYS_NICE); + + priority = to_userspace_prio(policy, desired.prio); - if (!list_is_last(&buffer->entry, &proc->buffers)) { - next = binder_buffer_next(buffer); - if (buffer_start_page(next) == buffer_start_page(buffer)) { - to_free = false; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %pK share page with %pK\n", - proc->pid, - buffer->data, - next->data); + if (verify && is_rt_policy(policy) && !has_cap_nice) { + long max_rtprio = task_rlimit(task, RLIMIT_RTPRIO); + + if (max_rtprio == 0) { + policy = SCHED_NORMAL; + priority = -20; + } else if (priority > max_rtprio) { + priority = max_rtprio; } } - if (PAGE_ALIGNED(buffer->data)) { - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer start %pK is page aligned\n", - proc->pid, buffer->data); - to_free = false; + if (verify && is_fair_policy(policy) && !has_cap_nice) { + long min_nice = 20 - task_rlimit(task, RLIMIT_NICE); + + if (min_nice > 19) { + binder_user_error("%d RLIMIT_NICE not set\n", + task->pid); + return; + } else if (priority < min_nice) { + priority = min_nice; + } } - if (to_free) { - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %pK do not share page with %pK or %pK\n", - proc->pid, buffer->data, - prev->data, next->data); - binder_update_page_range(proc, 0, buffer_start_page(buffer), - buffer_start_page(buffer) + PAGE_SIZE, - NULL); + if (policy != desired.sched_policy || + to_kernel_prio(policy, priority) != desired.prio) + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "%d: priority %d not allowed, using %d instead\n", + task->pid, desired.prio, + to_kernel_prio(policy, priority)); + + /* Set the actual priority */ + if (task->policy != policy || is_rt_policy(policy)) { + struct sched_param params; + + params.sched_priority = is_rt_policy(policy) ? priority : 0; + + sched_setscheduler_nocheck(task, + policy | SCHED_RESET_ON_FORK, + ¶ms); } - list_del(&buffer->entry); - kfree(buffer); + if (is_fair_policy(policy)) + set_user_nice(task, priority); } -static void binder_free_buf(struct binder_proc *proc, - struct binder_buffer *buffer) +static void binder_set_priority(struct task_struct *task, + struct binder_priority desired) { - size_t size, buffer_size; - - buffer_size = binder_buffer_size(proc, buffer); + binder_do_set_priority(task, desired, /* verify = */ true); +} - size = ALIGN(buffer->data_size, sizeof(void *)) + - ALIGN(buffer->offsets_size, sizeof(void *)) + - ALIGN(buffer->extra_buffers_size, sizeof(void *)); +static void binder_restore_priority(struct task_struct *task, + struct binder_priority desired) +{ + binder_do_set_priority(task, desired, /* verify = */ false); +} - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_free_buf %pK size %zd buffer_size %zd\n", - proc->pid, buffer, size, buffer_size); +static void binder_transaction_priority(struct task_struct *task, + struct binder_transaction *t, + struct binder_priority node_prio, + bool inherit_rt) +{ + bool inherit_fifo = t->buffer->target_node->proc->context->inherit_fifo_prio; + struct binder_priority desired_prio; - BUG_ON(buffer->free); - BUG_ON(size > buffer_size); - BUG_ON(buffer->transaction != NULL); - BUG_ON(buffer->data < proc->buffer); - BUG_ON(buffer->data > proc->buffer + proc->buffer_size); + if (t->set_priority_called) + return; - if (buffer->async_transaction) { - proc->free_async_space += size + sizeof(struct binder_buffer); + t->set_priority_called = true; + t->saved_priority.sched_policy = task->policy; + t->saved_priority.prio = task->normal_prio; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, - "%d: binder_free_buf size %zd async free %zd\n", - proc->pid, size, proc->free_async_space); + if (!inherit_rt && is_rt_policy(desired_prio.sched_policy) && !inherit_fifo) { + desired_prio.prio = NICE_TO_PRIO(0); + desired_prio.sched_policy = SCHED_NORMAL; + } else { + desired_prio.prio = t->priority.prio; + desired_prio.sched_policy = t->priority.sched_policy; } - binder_update_page_range(proc, 0, - (void *)PAGE_ALIGN((uintptr_t)buffer->data), - (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), - NULL); - rb_erase(&buffer->rb_node, &proc->allocated_buffers); - buffer->free = 1; - if (!list_is_last(&buffer->entry, &proc->buffers)) { - struct binder_buffer *next = binder_buffer_next(buffer); - - if (next->free) { - rb_erase(&next->rb_node, &proc->free_buffers); - binder_delete_free_buffer(proc, next); - } + if (node_prio.prio < t->priority.prio || + (node_prio.prio == t->priority.prio && + node_prio.sched_policy == SCHED_FIFO)) { + /* + * In case the minimum priority on the node is + * higher (lower value), use that priority. If + * the priority is the same, but the node uses + * SCHED_FIFO, prefer SCHED_FIFO, since it can + * run unbounded, unlike SCHED_RR. + */ + desired_prio = node_prio; } - if (proc->buffers.next != &buffer->entry) { - struct binder_buffer *prev = binder_buffer_prev(buffer); - if (prev->free) { - binder_delete_free_buffer(proc, buffer); - rb_erase(&prev->rb_node, &proc->free_buffers); - buffer = prev; - } - } - binder_insert_free_buffer(proc, buffer); + binder_set_priority(task, desired_prio); } -static struct binder_node *binder_get_node(struct binder_proc *proc, - binder_uintptr_t ptr) +static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc, + binder_uintptr_t ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; + assert_spin_locked(&proc->inner_lock); + while (n) { node = rb_entry(n, struct binder_node, rb_node); @@ -1040,21 +1300,47 @@ static struct binder_node *binder_get_node(struct binder_proc *proc, n = n->rb_left; else if (ptr > node->ptr) n = n->rb_right; - else + else { + /* + * take an implicit weak reference + * to ensure node stays alive until + * call to binder_put_node() + */ + binder_inc_node_tmpref_ilocked(node); return node; + } } return NULL; } -static struct binder_node *binder_new_node(struct binder_proc *proc, - binder_uintptr_t ptr, - binder_uintptr_t cookie) +static struct binder_node *binder_get_node(struct binder_proc *proc, + binder_uintptr_t ptr) +{ + struct binder_node *node; + + binder_inner_proc_lock(proc); + node = binder_get_node_ilocked(proc, ptr); + binder_inner_proc_unlock(proc); + return node; +} + +static struct binder_node *binder_init_node_ilocked( + struct binder_proc *proc, + struct binder_node *new_node, + struct flat_binder_object *fp) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; struct binder_node *node; + binder_uintptr_t ptr = fp ? fp->binder : 0; + binder_uintptr_t cookie = fp ? fp->cookie : 0; + __u32 flags = fp ? fp->flags : 0; + s8 priority; + + assert_spin_locked(&proc->inner_lock); while (*p) { + parent = *p; node = rb_entry(parent, struct binder_node, rb_node); @@ -1062,14 +1348,19 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, p = &(*p)->rb_left; else if (ptr > node->ptr) p = &(*p)->rb_right; - else - return NULL; + else { + /* + * A matching node is already in + * the rb tree. Abandon the init + * and return it. + */ + binder_inc_node_tmpref_ilocked(node); + return node; + } } - - node = kzalloc_preempt_disabled(sizeof(*node)); - if (node == NULL) - return NULL; + node = new_node; binder_stats_created(BINDER_STAT_NODE); + node->tmp_refs++; rb_link_node(&node->rb_node, parent, p); rb_insert_color(&node->rb_node, &proc->nodes); node->debug_id = atomic_inc_return(&binder_last_id); @@ -1077,18 +1368,59 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, node->ptr = ptr; node->cookie = cookie; node->work.type = BINDER_WORK_NODE; + priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK; + node->sched_policy = (flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK) >> + FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT; + node->min_priority = to_kernel_prio(node->sched_policy, priority); + node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); + node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT); + node->txn_security_ctx = !!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX); + spin_lock_init(&node->lock); INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "%d:%d node %d u%016llx c%016llx created\n", proc->pid, current->pid, node->debug_id, (u64)node->ptr, (u64)node->cookie); + return node; } -static int binder_inc_node(struct binder_node *node, int strong, int internal, - struct list_head *target_list) +static struct binder_node *binder_new_node(struct binder_proc *proc, + struct flat_binder_object *fp) { + struct binder_node *node; + struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL); + + if (!new_node) + return NULL; + binder_inner_proc_lock(proc); + node = binder_init_node_ilocked(proc, new_node, fp); + binder_inner_proc_unlock(proc); + if (node != new_node) + /* + * The node was already added by another thread + */ + kfree(new_node); + + return node; +} + +static void binder_free_node(struct binder_node *node) +{ + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); +} + +static int binder_inc_node_nilocked(struct binder_node *node, int strong, + int internal, + struct list_head *target_list) +{ + struct binder_proc *proc = node->proc; + + assert_spin_locked(&node->lock); + if (proc) + assert_spin_locked(&proc->inner_lock); if (strong) { if (internal) { if (target_list == NULL && @@ -1105,8 +1437,12 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, } else node->local_strong_refs++; if (!node->has_strong_ref && target_list) { - list_del_init(&node->work.entry); - list_add_tail(&node->work.entry, target_list); + struct binder_thread *thread = container_of(target_list, + struct binder_thread, todo); + binder_dequeue_work_ilocked(&node->work); + BUG_ON(&thread->todo != target_list); + binder_enqueue_deferred_thread_work_ilocked(thread, + &node->work); } } else { if (!internal) @@ -1117,58 +1453,172 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, node->debug_id); return -EINVAL; } - list_add_tail(&node->work.entry, target_list); + /* + * See comment above + */ + binder_enqueue_work_ilocked(&node->work, target_list); } } return 0; } -static int binder_dec_node(struct binder_node *node, int strong, int internal) +static int binder_inc_node(struct binder_node *node, int strong, int internal, + struct list_head *target_list) { + int ret; + + binder_node_inner_lock(node); + ret = binder_inc_node_nilocked(node, strong, internal, target_list); + binder_node_inner_unlock(node); + + return ret; +} + +static bool binder_dec_node_nilocked(struct binder_node *node, + int strong, int internal) +{ + struct binder_proc *proc = node->proc; + + assert_spin_locked(&node->lock); + if (proc) + assert_spin_locked(&proc->inner_lock); if (strong) { if (internal) node->internal_strong_refs--; else node->local_strong_refs--; if (node->local_strong_refs || node->internal_strong_refs) - return 0; + return false; } else { if (!internal) node->local_weak_refs--; - if (node->local_weak_refs || !hlist_empty(&node->refs)) - return 0; + if (node->local_weak_refs || node->tmp_refs || + !hlist_empty(&node->refs)) + return false; } - if (node->proc && (node->has_strong_ref || node->has_weak_ref)) { + + if (proc && (node->has_strong_ref || node->has_weak_ref)) { if (list_empty(&node->work.entry)) { - list_add_tail(&node->work.entry, &node->proc->todo); - wake_up_interruptible(&node->proc->wait); + binder_enqueue_work_ilocked(&node->work, &proc->todo); + binder_wakeup_proc_ilocked(proc); } } else { if (hlist_empty(&node->refs) && !node->local_strong_refs && - !node->local_weak_refs) { - list_del_init(&node->work.entry); - if (node->proc) { - rb_erase(&node->rb_node, &node->proc->nodes); + !node->local_weak_refs && !node->tmp_refs) { + if (proc) { + binder_dequeue_work_ilocked(&node->work); + rb_erase(&node->rb_node, &proc->nodes); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "refless node %d deleted\n", node->debug_id); } else { + BUG_ON(!list_empty(&node->work.entry)); + spin_lock(&binder_dead_nodes_lock); + /* + * tmp_refs could have changed so + * check it again + */ + if (node->tmp_refs) { + spin_unlock(&binder_dead_nodes_lock); + return false; + } hlist_del(&node->dead_node); + spin_unlock(&binder_dead_nodes_lock); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "dead node %d deleted\n", node->debug_id); } - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); + return true; } } + return false; +} - return 0; +static void binder_dec_node(struct binder_node *node, int strong, int internal) +{ + bool free_node; + + binder_node_inner_lock(node); + free_node = binder_dec_node_nilocked(node, strong, internal); + binder_node_inner_unlock(node); + if (free_node) + binder_free_node(node); } +static void binder_inc_node_tmpref_ilocked(struct binder_node *node) +{ + /* + * No call to binder_inc_node() is needed since we + * don't need to inform userspace of any changes to + * tmp_refs + */ + node->tmp_refs++; +} -static struct binder_ref *binder_get_ref(struct binder_proc *proc, - uint32_t desc, bool need_strong_ref) +/** + * binder_inc_node_tmpref() - take a temporary reference on node + * @node: node to reference + * + * Take reference on node to prevent the node from being freed + * while referenced only by a local variable. The inner lock is + * needed to serialize with the node work on the queue (which + * isn't needed after the node is dead). If the node is dead + * (node->proc is NULL), use binder_dead_nodes_lock to protect + * node->tmp_refs against dead-node-only cases where the node + * lock cannot be acquired (eg traversing the dead node list to + * print nodes) + */ +static void binder_inc_node_tmpref(struct binder_node *node) +{ + binder_node_lock(node); + if (node->proc) + binder_inner_proc_lock(node->proc); + else + spin_lock(&binder_dead_nodes_lock); + binder_inc_node_tmpref_ilocked(node); + if (node->proc) + binder_inner_proc_unlock(node->proc); + else + spin_unlock(&binder_dead_nodes_lock); + binder_node_unlock(node); +} + +/** + * binder_dec_node_tmpref() - remove a temporary reference on node + * @node: node to reference + * + * Release temporary reference on node taken via binder_inc_node_tmpref() + */ +static void binder_dec_node_tmpref(struct binder_node *node) +{ + bool free_node; + + binder_node_inner_lock(node); + if (!node->proc) + spin_lock(&binder_dead_nodes_lock); + node->tmp_refs--; + BUG_ON(node->tmp_refs < 0); + if (!node->proc) + spin_unlock(&binder_dead_nodes_lock); + /* + * Call binder_dec_node() to check if all refcounts are 0 + * and cleanup is needed. Calling with strong=0 and internal=1 + * causes no actual reference to be released in binder_dec_node(). + * If that changes, a change is needed here too. + */ + free_node = binder_dec_node_nilocked(node, 0, 1); + binder_node_inner_unlock(node); + if (free_node) + binder_free_node(node); +} + +static void binder_put_node(struct binder_node *node) +{ + binder_dec_node_tmpref(node); +} + +static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc, + u32 desc, bool need_strong_ref) { struct rb_node *n = proc->refs_by_desc.rb_node; struct binder_ref *ref; @@ -1176,11 +1626,11 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc, while (n) { ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (desc < ref->desc) { + if (desc < ref->data.desc) { n = n->rb_left; - } else if (desc > ref->desc) { + } else if (desc > ref->data.desc) { n = n->rb_right; - } else if (need_strong_ref && !ref->strong) { + } else if (need_strong_ref && !ref->data.strong) { binder_user_error("tried to use weak ref as strong ref\n"); return NULL; } else { @@ -1190,14 +1640,34 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc, return NULL; } -static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, - struct binder_node *node) +/** + * binder_get_ref_for_node_olocked() - get the ref associated with given node + * @proc: binder_proc that owns the ref + * @node: binder_node of target + * @new_ref: newly allocated binder_ref to be initialized or %NULL + * + * Look up the ref for the given node and return it if it exists + * + * If it doesn't exist and the caller provides a newly allocated + * ref, initialize the fields of the newly allocated ref and insert + * into the given proc rb_trees and node refs list. + * + * Return: the ref for node. It is possible that another thread + * allocated/initialized the ref first in which case the + * returned ref would be different than the passed-in + * new_ref. new_ref must be kfree'd by the caller in + * this case. + */ +static struct binder_ref *binder_get_ref_for_node_olocked( + struct binder_proc *proc, + struct binder_node *node, + struct binder_ref *new_ref) { - struct rb_node *n; + struct binder_context *context = proc->context; struct rb_node **p = &proc->refs_by_node.rb_node; struct rb_node *parent = NULL; - struct binder_ref *ref, *new_ref; - struct binder_context *context = proc->context; + struct binder_ref *ref; + struct rb_node *n; while (*p) { parent = *p; @@ -1210,22 +1680,22 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, else return ref; } - new_ref = kzalloc_preempt_disabled(sizeof(*ref)); - if (new_ref == NULL) + if (!new_ref) return NULL; + binder_stats_created(BINDER_STAT_REF); - new_ref->debug_id = atomic_inc_return(&binder_last_id); + new_ref->data.debug_id = atomic_inc_return(&binder_last_id); new_ref->proc = proc; new_ref->node = node; rb_link_node(&new_ref->rb_node_node, parent, p); rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node); - new_ref->desc = (node == context->binder_context_mgr_node) ? 0 : 1; + new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1; for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (ref->desc > new_ref->desc) + if (ref->data.desc > new_ref->data.desc) break; - new_ref->desc = ref->desc + 1; + new_ref->data.desc = ref->data.desc + 1; } p = &proc->refs_by_desc.rb_node; @@ -1233,126 +1703,443 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, parent = *p; ref = rb_entry(parent, struct binder_ref, rb_node_desc); - if (new_ref->desc < ref->desc) + if (new_ref->data.desc < ref->data.desc) p = &(*p)->rb_left; - else if (new_ref->desc > ref->desc) + else if (new_ref->data.desc > ref->data.desc) p = &(*p)->rb_right; else BUG(); } rb_link_node(&new_ref->rb_node_desc, parent, p); rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc); - if (node) { - hlist_add_head(&new_ref->node_entry, &node->refs); - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d new ref %d desc %d for node %d\n", - proc->pid, new_ref->debug_id, new_ref->desc, - node->debug_id); - } else { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d new ref %d desc %d for dead node\n", - proc->pid, new_ref->debug_id, new_ref->desc); - } + binder_node_lock(node); + hlist_add_head(&new_ref->node_entry, &node->refs); + + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d new ref %d desc %d for node %d\n", + proc->pid, new_ref->data.debug_id, new_ref->data.desc, + node->debug_id); + binder_node_unlock(node); return new_ref; } -static void binder_delete_ref(struct binder_ref *ref) +static void binder_cleanup_ref_olocked(struct binder_ref *ref) { + bool delete_node = false; + binder_debug(BINDER_DEBUG_INTERNAL_REFS, "%d delete ref %d desc %d for node %d\n", - ref->proc->pid, ref->debug_id, ref->desc, + ref->proc->pid, ref->data.debug_id, ref->data.desc, ref->node->debug_id); rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc); rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node); - if (ref->strong) - binder_dec_node(ref->node, 1, 1); + + binder_node_inner_lock(ref->node); + if (ref->data.strong) + binder_dec_node_nilocked(ref->node, 1, 1); + hlist_del(&ref->node_entry); - binder_dec_node(ref->node, 0, 1); + delete_node = binder_dec_node_nilocked(ref->node, 0, 1); + binder_node_inner_unlock(ref->node); + /* + * Clear ref->node unless we want the caller to free the node + */ + if (!delete_node) { + /* + * The caller uses ref->node to determine + * whether the node needs to be freed. Clear + * it since the node is still alive. + */ + ref->node = NULL; + } + if (ref->death) { binder_debug(BINDER_DEBUG_DEAD_BINDER, "%d delete ref %d desc %d has death notification\n", - ref->proc->pid, ref->debug_id, ref->desc); - list_del(&ref->death->work.entry); - kfree(ref->death); + ref->proc->pid, ref->data.debug_id, + ref->data.desc); + binder_dequeue_work(ref->proc, &ref->death->work); binder_stats_deleted(BINDER_STAT_DEATH); } - kfree(ref); binder_stats_deleted(BINDER_STAT_REF); } -static int binder_inc_ref(struct binder_ref *ref, int strong, - struct list_head *target_list) +/** + * binder_inc_ref_olocked() - increment the ref for given handle + * @ref: ref to be incremented + * @strong: if true, strong increment, else weak + * @target_list: list to queue node work on + * + * Increment the ref. @ref->proc->outer_lock must be held on entry + * + * Return: 0, if successful, else errno + */ +static int binder_inc_ref_olocked(struct binder_ref *ref, int strong, + struct list_head *target_list) { int ret; if (strong) { - if (ref->strong == 0) { + if (ref->data.strong == 0) { ret = binder_inc_node(ref->node, 1, 1, target_list); if (ret) return ret; } - ref->strong++; + ref->data.strong++; } else { - if (ref->weak == 0) { + if (ref->data.weak == 0) { ret = binder_inc_node(ref->node, 0, 1, target_list); if (ret) return ret; } - ref->weak++; + ref->data.weak++; } return 0; } - -static int binder_dec_ref(struct binder_ref **ptr_to_ref, int strong) +/** + * binder_dec_ref() - dec the ref for given handle + * @ref: ref to be decremented + * @strong: if true, strong decrement, else weak + * + * Decrement the ref. + * + * Return: true if ref is cleaned up and ready to be freed + */ +static bool binder_dec_ref_olocked(struct binder_ref *ref, int strong) { - struct binder_ref *ref = *ptr_to_ref; if (strong) { - if (ref->strong == 0) { + if (ref->data.strong == 0) { binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n", - ref->proc->pid, ref->debug_id, - ref->desc, ref->strong, ref->weak); - return -EINVAL; - } - ref->strong--; - if (ref->strong == 0) { - int ret; - - ret = binder_dec_node(ref->node, strong, 1); - if (ret) - return ret; + ref->proc->pid, ref->data.debug_id, + ref->data.desc, ref->data.strong, + ref->data.weak); + return false; } + ref->data.strong--; + if (ref->data.strong == 0) + binder_dec_node(ref->node, strong, 1); } else { - if (ref->weak == 0) { + if (ref->data.weak == 0) { binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n", - ref->proc->pid, ref->debug_id, - ref->desc, ref->strong, ref->weak); - return -EINVAL; + ref->proc->pid, ref->data.debug_id, + ref->data.desc, ref->data.strong, + ref->data.weak); + return false; } - ref->weak--; + ref->data.weak--; } - if (ref->strong == 0 && ref->weak == 0) { - binder_delete_ref(ref); - *ptr_to_ref = NULL; + if (ref->data.strong == 0 && ref->data.weak == 0) { + binder_cleanup_ref_olocked(ref); + return true; } - return 0; + return false; +} + +/** + * binder_get_node_from_ref() - get the node from the given proc/desc + * @proc: proc containing the ref + * @desc: the handle associated with the ref + * @need_strong_ref: if true, only return node if ref is strong + * @rdata: the id/refcount data for the ref + * + * Given a proc and ref handle, return the associated binder_node + * + * Return: a binder_node or NULL if not found or not strong when strong required + */ +static struct binder_node *binder_get_node_from_ref( + struct binder_proc *proc, + u32 desc, bool need_strong_ref, + struct binder_ref_data *rdata) +{ + struct binder_node *node; + struct binder_ref *ref; + + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, desc, need_strong_ref); + if (!ref) + goto err_no_ref; + node = ref->node; + /* + * Take an implicit reference on the node to ensure + * it stays alive until the call to binder_put_node() + */ + binder_inc_node_tmpref(node); + if (rdata) + *rdata = ref->data; + binder_proc_unlock(proc); + + return node; + +err_no_ref: + binder_proc_unlock(proc); + return NULL; +} + +/** + * binder_free_ref() - free the binder_ref + * @ref: ref to free + * + * Free the binder_ref. Free the binder_node indicated by ref->node + * (if non-NULL) and the binder_ref_death indicated by ref->death. + */ +static void binder_free_ref(struct binder_ref *ref) +{ + if (ref->node) + binder_free_node(ref->node); + kfree(ref->death); + kfree(ref); } -static void binder_pop_transaction(struct binder_thread *target_thread, - struct binder_transaction *t) +/** + * binder_update_ref_for_handle() - inc/dec the ref for given handle + * @proc: proc containing the ref + * @desc: the handle associated with the ref + * @increment: true=inc reference, false=dec reference + * @strong: true=strong reference, false=weak reference + * @rdata: the id/refcount data for the ref + * + * Given a proc and ref handle, increment or decrement the ref + * according to "increment" arg. + * + * Return: 0 if successful, else errno + */ +static int binder_update_ref_for_handle(struct binder_proc *proc, + uint32_t desc, bool increment, bool strong, + struct binder_ref_data *rdata) { - if (target_thread) { - BUG_ON(target_thread->transaction_stack != t); - BUG_ON(target_thread->transaction_stack->from != target_thread); - target_thread->transaction_stack = - target_thread->transaction_stack->from_parent; - t->from = NULL; + int ret = 0; + struct binder_ref *ref; + bool delete_ref = false; + + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, desc, strong); + if (!ref) { + ret = -EINVAL; + goto err_no_ref; + } + if (increment) + ret = binder_inc_ref_olocked(ref, strong, NULL); + else + delete_ref = binder_dec_ref_olocked(ref, strong); + + if (rdata) + *rdata = ref->data; + binder_proc_unlock(proc); + + if (delete_ref) + binder_free_ref(ref); + return ret; + +err_no_ref: + binder_proc_unlock(proc); + return ret; +} + +/** + * binder_dec_ref_for_handle() - dec the ref for given handle + * @proc: proc containing the ref + * @desc: the handle associated with the ref + * @strong: true=strong reference, false=weak reference + * @rdata: the id/refcount data for the ref + * + * Just calls binder_update_ref_for_handle() to decrement the ref. + * + * Return: 0 if successful, else errno + */ +static int binder_dec_ref_for_handle(struct binder_proc *proc, + uint32_t desc, bool strong, struct binder_ref_data *rdata) +{ + return binder_update_ref_for_handle(proc, desc, false, strong, rdata); +} + + +/** + * binder_inc_ref_for_node() - increment the ref for given proc/node + * @proc: proc containing the ref + * @node: target node + * @strong: true=strong reference, false=weak reference + * @target_list: worklist to use if node is incremented + * @rdata: the id/refcount data for the ref + * + * Given a proc and node, increment the ref. Create the ref if it + * doesn't already exist + * + * Return: 0 if successful, else errno + */ +static int binder_inc_ref_for_node(struct binder_proc *proc, + struct binder_node *node, + bool strong, + struct list_head *target_list, + struct binder_ref_data *rdata) +{ + struct binder_ref *ref; + struct binder_ref *new_ref = NULL; + int ret = 0; + + binder_proc_lock(proc); + ref = binder_get_ref_for_node_olocked(proc, node, NULL); + if (!ref) { + binder_proc_unlock(proc); + new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!new_ref) + return -ENOMEM; + binder_proc_lock(proc); + ref = binder_get_ref_for_node_olocked(proc, node, new_ref); + } + ret = binder_inc_ref_olocked(ref, strong, target_list); + *rdata = ref->data; + binder_proc_unlock(proc); + if (new_ref && ref != new_ref) + /* + * Another thread created the ref first so + * free the one we allocated + */ + kfree(new_ref); + return ret; +} + +static void binder_pop_transaction_ilocked(struct binder_thread *target_thread, + struct binder_transaction *t) +{ + BUG_ON(!target_thread); + assert_spin_locked(&target_thread->proc->inner_lock); + BUG_ON(target_thread->transaction_stack != t); + BUG_ON(target_thread->transaction_stack->from != target_thread); + target_thread->transaction_stack = + target_thread->transaction_stack->from_parent; + t->from = NULL; +} + +/** + * binder_thread_dec_tmpref() - decrement thread->tmp_ref + * @thread: thread to decrement + * + * A thread needs to be kept alive while being used to create or + * handle a transaction. binder_get_txn_from() is used to safely + * extract t->from from a binder_transaction and keep the thread + * indicated by t->from from being freed. When done with that + * binder_thread, this function is called to decrement the + * tmp_ref and free if appropriate (thread has been released + * and no transaction being processed by the driver) + */ +static void binder_thread_dec_tmpref(struct binder_thread *thread) +{ + /* + * atomic is used to protect the counter value while + * it cannot reach zero or thread->is_dead is false + */ + binder_inner_proc_lock(thread->proc); + atomic_dec(&thread->tmp_ref); + if (thread->is_dead && !atomic_read(&thread->tmp_ref)) { + binder_inner_proc_unlock(thread->proc); + binder_free_thread(thread); + return; + } + binder_inner_proc_unlock(thread->proc); +} + +/** + * binder_proc_dec_tmpref() - decrement proc->tmp_ref + * @proc: proc to decrement + * + * A binder_proc needs to be kept alive while being used to create or + * handle a transaction. proc->tmp_ref is incremented when + * creating a new transaction or the binder_proc is currently in-use + * by threads that are being released. When done with the binder_proc, + * this function is called to decrement the counter and free the + * proc if appropriate (proc has been released, all threads have + * been released and not currenly in-use to process a transaction). + */ +static void binder_proc_dec_tmpref(struct binder_proc *proc) +{ + binder_inner_proc_lock(proc); + atomic_dec(&proc->tmp_ref); + if (proc->is_dead && RB_EMPTY_ROOT(&proc->threads) && + !atomic_read(&proc->tmp_ref)) { + binder_inner_proc_unlock(proc); + binder_free_proc(proc); + return; + } + binder_inner_proc_unlock(proc); +} + +/** + * binder_get_txn_from() - safely extract the "from" thread in transaction + * @t: binder transaction for t->from + * + * Atomically return the "from" thread and increment the tmp_ref + * count for the thread to ensure it stays alive until + * binder_thread_dec_tmpref() is called. + * + * Return: the value of t->from + */ +static struct binder_thread *binder_get_txn_from( + struct binder_transaction *t) +{ + struct binder_thread *from; + + spin_lock(&t->lock); + from = t->from; + if (from) + atomic_inc(&from->tmp_ref); + spin_unlock(&t->lock); + return from; +} + +/** + * binder_get_txn_from_and_acq_inner() - get t->from and acquire inner lock + * @t: binder transaction for t->from + * + * Same as binder_get_txn_from() except it also acquires the proc->inner_lock + * to guarantee that the thread cannot be released while operating on it. + * The caller must call binder_inner_proc_unlock() to release the inner lock + * as well as call binder_dec_thread_txn() to release the reference. + * + * Return: the value of t->from + */ +static struct binder_thread *binder_get_txn_from_and_acq_inner( + struct binder_transaction *t) +{ + struct binder_thread *from; + + from = binder_get_txn_from(t); + if (!from) + return NULL; + binder_inner_proc_lock(from->proc); + if (t->from) { + BUG_ON(from != t->from); + return from; + } + binder_inner_proc_unlock(from->proc); + binder_thread_dec_tmpref(from); + return NULL; +} + +static void binder_free_transaction(struct binder_transaction *t) +{ + struct binder_proc *target_proc; + + spin_lock(&t->lock); + target_proc = t->to_proc; + if (target_proc) { + atomic_inc(&target_proc->tmp_ref); + spin_unlock(&t->lock); + + binder_inner_proc_lock(target_proc); + if (t->buffer) + t->buffer->transaction = NULL; + binder_inner_proc_unlock(target_proc); + binder_proc_dec_tmpref(target_proc); + } else { + /* + * If the transaction has no target_proc, then + * t->buffer->transaction * has already been cleared. + */ + spin_unlock(&t->lock); } - t->need_reply = 0; - if (t->buffer) - t->buffer->transaction = NULL; kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); } @@ -1365,30 +2152,34 @@ static void binder_send_failed_reply(struct binder_transaction *t, BUG_ON(t->flags & TF_ONE_WAY); while (1) { - target_thread = t->from; + target_thread = binder_get_txn_from_and_acq_inner(t); if (target_thread) { - if (target_thread->return_error != BR_OK && - target_thread->return_error2 == BR_OK) { - target_thread->return_error2 = - target_thread->return_error; - target_thread->return_error = BR_OK; - } - if (target_thread->return_error == BR_OK) { - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "send failed reply for transaction %d to %d:%d\n", - t->debug_id, - target_thread->proc->pid, - target_thread->pid); - - binder_pop_transaction(target_thread, t); - target_thread->return_error = error_code; + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "send failed reply for transaction %d to %d:%d\n", + t->debug_id, + target_thread->proc->pid, + target_thread->pid); + + binder_pop_transaction_ilocked(target_thread, t); + if (target_thread->reply_error.cmd == BR_OK) { + target_thread->reply_error.cmd = error_code; + binder_enqueue_thread_work_ilocked( + target_thread, + &target_thread->reply_error.work); wake_up_interruptible(&target_thread->wait); } else { - pr_err("reply failed, target thread, %d:%d, has error code %d already\n", - target_thread->proc->pid, - target_thread->pid, - target_thread->return_error); + /* + * Cannot get here for normal operation, but + * we can if multiple synchronous transactions + * are sent without blocking for responses. + * Just ignore the 2nd error in this case. + */ + pr_warn("Unexpected reply error: %u\n", + target_thread->reply_error.cmd); } + binder_inner_proc_unlock(target_thread->proc); + binder_thread_dec_tmpref(target_thread); + binder_free_transaction(t); return; } next = t->from_parent; @@ -1397,7 +2188,7 @@ static void binder_send_failed_reply(struct binder_transaction *t, "send failed reply for transaction %d, target dead\n", t->debug_id); - binder_pop_transaction(target_thread, t); + binder_free_transaction(t); if (next == NULL) { binder_debug(BINDER_DEBUG_DEAD_BINDER, "reply failed, no target thread at root\n"); @@ -1410,6 +2201,26 @@ static void binder_send_failed_reply(struct binder_transaction *t, } } +/** + * binder_cleanup_transaction() - cleans up undelivered transaction + * @t: transaction that needs to be cleaned up + * @reason: reason the transaction wasn't delivered + * @error_code: error to return to caller (if synchronous call) + */ +static void binder_cleanup_transaction(struct binder_transaction *t, + const char *reason, + uint32_t error_code) +{ + if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) { + binder_send_failed_reply(t, error_code); + } else { + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered transaction %d, %s\n", + t->debug_id, reason); + binder_free_transaction(t); + } +} + /** * binder_validate_object() - checks for a valid metadata object in a buffer. * @buffer: binder_buffer that we're parsing. @@ -1424,8 +2235,8 @@ static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset) struct binder_object_header *hdr; size_t object_size = 0; - if (offset > buffer->data_size - sizeof(*hdr) || - buffer->data_size < sizeof(*hdr) || + if (buffer->data_size < sizeof(*hdr) || + offset > buffer->data_size - sizeof(*hdr) || !IS_ALIGNED(offset, sizeof(u32))) return 0; @@ -1606,24 +2417,26 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, node->debug_id, (u64)node->ptr); binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER, 0); + binder_put_node(node); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct flat_binder_object *fp; - struct binder_ref *ref; + struct binder_ref_data rdata; + int ret; fp = to_flat_binder_object(hdr); - ref = binder_get_ref(proc, fp->handle, - hdr->type == BINDER_TYPE_HANDLE); - if (ref == NULL) { - pr_err("transaction release %d bad handle %d\n", - debug_id, fp->handle); + ret = binder_dec_ref_for_handle(proc, fp->handle, + hdr->type == BINDER_TYPE_HANDLE, &rdata); + + if (ret) { + pr_err("transaction release %d bad handle %d, ret = %d\n", + debug_id, fp->handle, ret); break; } binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, ref->node->debug_id); - binder_dec_ref(&ref, hdr->type == BINDER_TYPE_HANDLE); + " ref %d desc %d\n", + rdata.debug_id, rdata.desc); } break; case BINDER_TYPE_FD: { @@ -1662,7 +2475,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, * back to kernel address space to access it */ parent_buffer = parent->buffer - - proc->user_buffer_offset; + binder_alloc_get_user_buffer_offset( + &proc->alloc); fd_buf_size = sizeof(u32) * fda->num_fds; if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { @@ -1677,7 +2491,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, debug_id, (u64)fda->num_fds); continue; } - fd_array = (u32 *)(parent_buffer + fda->parent_offset); + fd_array = (u32 *)(uintptr_t) + (parent_buffer + fda->parent_offset); for (fd_index = 0; fd_index < fda->num_fds; fd_index++) task_close_fd(proc, fd_array[fd_index]); } break; @@ -1694,102 +2509,121 @@ static int binder_translate_binder(struct flat_binder_object *fp, struct binder_thread *thread) { struct binder_node *node; - struct binder_ref *ref; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; + struct binder_ref_data rdata; + int ret = 0; node = binder_get_node(proc, fp->binder); if (!node) { - node = binder_new_node(proc, fp->binder, fp->cookie); + node = binder_new_node(proc, fp); if (!node) return -ENOMEM; - - node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK; - node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, (u64)fp->binder, node->debug_id, (u64)fp->cookie, (u64)node->cookie); - return -EINVAL; + ret = -EINVAL; + goto done; + } + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { + ret = -EPERM; + goto done; } - if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) - return -EPERM; - ref = binder_get_ref_for_node(target_proc, node); - if (!ref) - return -EINVAL; + ret = binder_inc_ref_for_node(target_proc, node, + fp->hdr.type == BINDER_TYPE_BINDER, + &thread->todo, &rdata); + if (ret) + goto done; if (fp->hdr.type == BINDER_TYPE_BINDER) fp->hdr.type = BINDER_TYPE_HANDLE; else fp->hdr.type = BINDER_TYPE_WEAK_HANDLE; fp->binder = 0; - fp->handle = ref->desc; + fp->handle = rdata.desc; fp->cookie = 0; - binder_inc_ref(ref, fp->hdr.type == BINDER_TYPE_HANDLE, &thread->todo); - trace_binder_transaction_node_to_ref(t, node, ref); + trace_binder_transaction_node_to_ref(t, node, &rdata); binder_debug(BINDER_DEBUG_TRANSACTION, " node %d u%016llx -> ref %d desc %d\n", node->debug_id, (u64)node->ptr, - ref->debug_id, ref->desc); - - return 0; + rdata.debug_id, rdata.desc); +done: + binder_put_node(node); + return ret; } static int binder_translate_handle(struct flat_binder_object *fp, struct binder_transaction *t, struct binder_thread *thread) { - struct binder_ref *ref; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; + struct binder_node *node; + struct binder_ref_data src_rdata; + int ret = 0; - ref = binder_get_ref(proc, fp->handle, - fp->hdr.type == BINDER_TYPE_HANDLE); - if (!ref) { + node = binder_get_node_from_ref(proc, fp->handle, + fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata); + if (!node) { binder_user_error("%d:%d got transaction with invalid handle, %d\n", proc->pid, thread->pid, fp->handle); return -EINVAL; } - if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) - return -EPERM; + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { + ret = -EPERM; + goto done; + } - if (ref->node->proc == target_proc) { + binder_node_lock(node); + if (node->proc == target_proc) { if (fp->hdr.type == BINDER_TYPE_HANDLE) fp->hdr.type = BINDER_TYPE_BINDER; else fp->hdr.type = BINDER_TYPE_WEAK_BINDER; - fp->binder = ref->node->ptr; - fp->cookie = ref->node->cookie; - binder_inc_node(ref->node, fp->hdr.type == BINDER_TYPE_BINDER, - 0, NULL); - trace_binder_transaction_ref_to_node(t, ref); + fp->binder = node->ptr; + fp->cookie = node->cookie; + if (node->proc) + binder_inner_proc_lock(node->proc); + binder_inc_node_nilocked(node, + fp->hdr.type == BINDER_TYPE_BINDER, + 0, NULL); + if (node->proc) + binder_inner_proc_unlock(node->proc); + trace_binder_transaction_ref_to_node(t, node, &src_rdata); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> node %d u%016llx\n", - ref->debug_id, ref->desc, ref->node->debug_id, - (u64)ref->node->ptr); + src_rdata.debug_id, src_rdata.desc, node->debug_id, + (u64)node->ptr); + binder_node_unlock(node); } else { - struct binder_ref *new_ref; + struct binder_ref_data dest_rdata; - new_ref = binder_get_ref_for_node(target_proc, ref->node); - if (!new_ref) - return -EINVAL; + binder_node_unlock(node); + ret = binder_inc_ref_for_node(target_proc, node, + fp->hdr.type == BINDER_TYPE_HANDLE, + NULL, &dest_rdata); + if (ret) + goto done; fp->binder = 0; - fp->handle = new_ref->desc; + fp->handle = dest_rdata.desc; fp->cookie = 0; - binder_inc_ref(new_ref, fp->hdr.type == BINDER_TYPE_HANDLE, - NULL); - trace_binder_transaction_ref_to_ref(t, ref, new_ref); + trace_binder_transaction_ref_to_ref(t, node, &src_rdata, + &dest_rdata); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, new_ref->debug_id, - new_ref->desc, ref->node->debug_id); + src_rdata.debug_id, src_rdata.desc, + dest_rdata.debug_id, dest_rdata.desc, + node->debug_id); } - return 0; +done: + binder_put_node(node); + return ret; } static int binder_translate_fd(int fd, @@ -1880,8 +2714,9 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda, * Since the parent was already fixed up, convert it * back to the kernel address space to access it */ - parent_buffer = parent->buffer - target_proc->user_buffer_offset; - fd_array = (u32 *)(parent_buffer + fda->parent_offset); + parent_buffer = parent->buffer - + binder_alloc_get_user_buffer_offset(&target_proc->alloc); + fd_array = (u32 *)(uintptr_t)(parent_buffer + fda->parent_offset); if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) { binder_user_error("%d:%d parent offset not aligned correctly.\n", proc->pid, thread->pid); @@ -1947,13 +2782,126 @@ static int binder_fixup_parent(struct binder_transaction *t, proc->pid, thread->pid); return -EINVAL; } - parent_buffer = (u8 *)(parent->buffer - - target_proc->user_buffer_offset); + parent_buffer = (u8 *)(uintptr_t)(parent->buffer - + binder_alloc_get_user_buffer_offset( + &target_proc->alloc)); *(binder_uintptr_t *)(parent_buffer + bp->parent_offset) = bp->buffer; return 0; } +/** + * binder_proc_transaction() - sends a transaction to a process and wakes it up + * @t: transaction to send + * @proc: process to send the transaction to + * @thread: thread in @proc to send the transaction to (may be NULL) + * + * This function queues a transaction to the specified process. It will try + * to find a thread in the target process to handle the transaction and + * wake it up. If no thread is found, the work is queued to the proc + * waitqueue. + * + * If the @thread parameter is not NULL, the transaction is always queued + * to the waitlist of that specific thread. + * + * Return: true if the transactions was successfully queued + * false if the target process or thread is dead + */ +static bool binder_proc_transaction(struct binder_transaction *t, + struct binder_proc *proc, + struct binder_thread *thread) +{ + struct binder_node *node = t->buffer->target_node; + struct binder_priority node_prio; + bool oneway = !!(t->flags & TF_ONE_WAY); + bool pending_async = false; + + BUG_ON(!node); + binder_node_lock(node); + node_prio.prio = node->min_priority; + node_prio.sched_policy = node->sched_policy; + + if (oneway) { + BUG_ON(thread); + if (node->has_async_transaction) { + pending_async = true; + } else { + node->has_async_transaction = true; + } + } + + binder_inner_proc_lock(proc); + + if (proc->is_dead || (thread && thread->is_dead)) { + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + return false; + } + + if (!thread && !pending_async) + thread = binder_select_thread_ilocked(proc); + + if (thread) { + binder_transaction_priority(thread->task, t, node_prio, + node->inherit_rt); + binder_enqueue_thread_work_ilocked(thread, &t->work); + } else if (!pending_async) { + binder_enqueue_work_ilocked(&t->work, &proc->todo); + } else { + binder_enqueue_work_ilocked(&t->work, &node->async_todo); + } + + if (!pending_async) + binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); + + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + + return true; +} + +/** + * binder_get_node_refs_for_txn() - Get required refs on node for txn + * @node: struct binder_node for which to get refs + * @proc: returns @node->proc if valid + * @error: if no @proc then returns BR_DEAD_REPLY + * + * User-space normally keeps the node alive when creating a transaction + * since it has a reference to the target. The local strong ref keeps it + * alive if the sending process dies before the target process processes + * the transaction. If the source process is malicious or has a reference + * counting bug, relying on the local strong ref can fail. + * + * Since user-space can cause the local strong ref to go away, we also take + * a tmpref on the node to ensure it survives while we are constructing + * the transaction. We also need a tmpref on the proc while we are + * constructing the transaction, so we take that here as well. + * + * Return: The target_node with refs taken or NULL if no @node->proc is NULL. + * Also sets @proc if valid. If the @node->proc is NULL indicating that the + * target proc has died, @error is set to BR_DEAD_REPLY + */ +static struct binder_node *binder_get_node_refs_for_txn( + struct binder_node *node, + struct binder_proc **procp, + uint32_t *error) +{ + struct binder_node *target_node = NULL; + + binder_node_inner_lock(node); + if (node->proc) { + target_node = node; + binder_inc_node_nilocked(node, 1, 0, NULL); + binder_inc_node_tmpref_ilocked(node); + atomic_inc(&node->proc->tmp_ref); + *procp = node->proc; + } else + *error = BR_DEAD_REPLY; + binder_node_inner_unlock(node); + + return target_node; +} + static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply, @@ -1961,23 +2909,28 @@ static void binder_transaction(struct binder_proc *proc, { int ret; struct binder_transaction *t; + struct binder_work *w; struct binder_work *tcomplete; binder_size_t *offp, *off_end, *off_start; binder_size_t off_min; u8 *sg_bufp, *sg_buf_end; - struct binder_proc *target_proc; + struct binder_proc *target_proc = NULL; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; - struct list_head *target_list; - wait_queue_head_t *target_wait; struct binder_transaction *in_reply_to = NULL; struct binder_transaction_log_entry *e; - uint32_t return_error; + uint32_t return_error = 0; + uint32_t return_error_param = 0; + uint32_t return_error_line = 0; struct binder_buffer_object *last_fixup_obj = NULL; binder_size_t last_fixup_min_off = 0; struct binder_context *context = proc->context; + int t_debug_id = atomic_inc_return(&binder_last_id); + char *secctx = NULL; + u32 secctx_sz = 0; - e = binder_transaction_log_add(&context->transaction_log); + e = binder_transaction_log_add(&binder_transaction_log); + e->debug_id = t_debug_id; e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); e->from_proc = proc->pid; e->from_thread = thread->pid; @@ -1987,29 +2940,39 @@ static void binder_transaction(struct binder_proc *proc, e->context_name = proc->context->name; if (reply) { + binder_inner_proc_lock(proc); in_reply_to = thread->transaction_stack; if (in_reply_to == NULL) { + binder_inner_proc_unlock(proc); binder_user_error("%d:%d got reply transaction with no transaction stack\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; goto err_empty_call_stack; } - binder_set_nice(in_reply_to->saved_priority); if (in_reply_to->to_thread != thread) { + spin_lock(&in_reply_to->lock); binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, in_reply_to->debug_id, in_reply_to->to_proc ? in_reply_to->to_proc->pid : 0, in_reply_to->to_thread ? in_reply_to->to_thread->pid : 0); + spin_unlock(&in_reply_to->lock); + binder_inner_proc_unlock(proc); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; in_reply_to = NULL; goto err_bad_call_stack; } thread->transaction_stack = in_reply_to->to_parent; - target_thread = in_reply_to->from; + binder_inner_proc_unlock(proc); + target_thread = binder_get_txn_from_and_acq_inner(in_reply_to); if (target_thread == NULL) { return_error = BR_DEAD_REPLY; + return_error_line = __LINE__; goto err_dead_binder; } if (target_thread->transaction_stack != in_reply_to) { @@ -2018,88 +2981,160 @@ static void binder_transaction(struct binder_proc *proc, target_thread->transaction_stack ? target_thread->transaction_stack->debug_id : 0, in_reply_to->debug_id); + binder_inner_proc_unlock(target_thread->proc); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; in_reply_to = NULL; target_thread = NULL; goto err_dead_binder; } target_proc = target_thread->proc; + atomic_inc(&target_proc->tmp_ref); + binder_inner_proc_unlock(target_thread->proc); } else { if (tr->target.handle) { struct binder_ref *ref; - ref = binder_get_ref(proc, tr->target.handle, true); - if (ref == NULL) { + /* + * There must already be a strong ref + * on this node. If so, do a strong + * increment on the node to ensure it + * stays alive until the transaction is + * done. + */ + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, tr->target.handle, + true); + if (ref) { + target_node = binder_get_node_refs_for_txn( + ref->node, &target_proc, + &return_error); + } else { binder_user_error("%d:%d got transaction to invalid handle\n", - proc->pid, thread->pid); + proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - goto err_invalid_target_handle; } - target_node = ref->node; + binder_proc_unlock(proc); } else { + mutex_lock(&context->context_mgr_node_lock); target_node = context->binder_context_mgr_node; - if (target_node == NULL) { + if (target_node) + target_node = binder_get_node_refs_for_txn( + target_node, &target_proc, + &return_error); + else return_error = BR_DEAD_REPLY; - goto err_no_context_mgr_node; + mutex_unlock(&context->context_mgr_node_lock); + if (target_node && target_proc == proc) { + binder_user_error("%d:%d got transaction to context manager from process owning it\n", + proc->pid, thread->pid); + return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; + goto err_invalid_target_handle; } } - e->to_node = target_node->debug_id; - target_proc = target_node->proc; - if (target_proc == NULL) { - return_error = BR_DEAD_REPLY; + if (!target_node) { + /* + * return_error is set above + */ + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_dead_binder; } - if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) { + e->to_node = target_node->debug_id; + if (security_binder_transaction(proc->tsk, + target_proc->tsk) < 0) { return_error = BR_FAILED_REPLY; + return_error_param = -EPERM; + return_error_line = __LINE__; goto err_invalid_target_handle; } + binder_inner_proc_lock(proc); + + w = list_first_entry_or_null(&thread->todo, + struct binder_work, entry); + if (!(tr->flags & TF_ONE_WAY) && w && + w->type == BINDER_WORK_TRANSACTION) { + /* + * Do not allow new outgoing transaction from a + * thread that has a transaction at the head of + * its todo list. Only need to check the head + * because binder_select_thread_ilocked picks a + * thread from proc->waiting_threads to enqueue + * the transaction, and nothing is queued to the + * todo list while the thread is on waiting_threads. + */ + binder_user_error("%d:%d new transaction not allowed when there is a transaction on thread todo\n", + proc->pid, thread->pid); + binder_inner_proc_unlock(proc); + return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; + goto err_bad_todo_list; + } + if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; tmp = thread->transaction_stack; if (tmp->to_thread != thread) { + spin_lock(&tmp->lock); binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, tmp->debug_id, tmp->to_proc ? tmp->to_proc->pid : 0, tmp->to_thread ? tmp->to_thread->pid : 0); + spin_unlock(&tmp->lock); + binder_inner_proc_unlock(proc); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; goto err_bad_call_stack; } while (tmp) { - if (tmp->from && tmp->from->proc == target_proc) - target_thread = tmp->from; + struct binder_thread *from; + + spin_lock(&tmp->lock); + from = tmp->from; + if (from && from->proc == target_proc) { + atomic_inc(&from->tmp_ref); + target_thread = from; + spin_unlock(&tmp->lock); + break; + } + spin_unlock(&tmp->lock); tmp = tmp->from_parent; } } + binder_inner_proc_unlock(proc); } - if (target_thread) { + if (target_thread) e->to_thread = target_thread->pid; - target_list = &target_thread->todo; - target_wait = &target_thread->wait; - } else { - target_list = &target_proc->todo; - target_wait = &target_proc->wait; - } e->to_proc = target_proc->pid; /* TODO: reuse incoming transaction for reply */ - t = kzalloc_preempt_disabled(sizeof(*t)); + t = kzalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) { return_error = BR_FAILED_REPLY; + return_error_param = -ENOMEM; + return_error_line = __LINE__; goto err_alloc_t_failed; } binder_stats_created(BINDER_STAT_TRANSACTION); + spin_lock_init(&t->lock); - tcomplete = kzalloc_preempt_disabled(sizeof(*tcomplete)); + tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); if (tcomplete == NULL) { return_error = BR_FAILED_REPLY; + return_error_param = -ENOMEM; + return_error_line = __LINE__; goto err_alloc_tcomplete_failed; } binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); - t->debug_id = atomic_inc_return(&binder_last_id); - e->debug_id = t->debug_id; + t->debug_id = t_debug_id; if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, @@ -2129,47 +3164,100 @@ static void binder_transaction(struct binder_proc *proc, t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; - t->priority = task_nice(current); + if (!(t->flags & TF_ONE_WAY) && + binder_supported_policy(current->policy)) { + /* Inherit supported policies for synchronous transactions */ + t->priority.sched_policy = current->policy; + t->priority.prio = current->normal_prio; + } else { + /* Otherwise, fall back to the default priority */ + t->priority = target_proc->default_priority; + } + + if (target_node && target_node->txn_security_ctx) { + u32 secid; + size_t added_size; + + security_task_getsecid(proc->tsk, &secid); + ret = security_secid_to_secctx(secid, &secctx, &secctx_sz); + if (ret) { + return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; + goto err_get_secctx_failed; + } + added_size = ALIGN(secctx_sz, sizeof(u64)); + extra_buffers_size += added_size; + if (extra_buffers_size < added_size) { + /* integer overflow of extra_buffers_size */ + return_error = BR_FAILED_REPLY; + return_error_param = EINVAL; + return_error_line = __LINE__; + goto err_bad_extra_size; + } + } trace_binder_transaction(reply, t, target_node); - t->buffer = binder_alloc_buf(target_proc, tr->data_size, + t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, tr->offsets_size, extra_buffers_size, !reply && (t->flags & TF_ONE_WAY)); - if (t->buffer == NULL) { - return_error = BR_FAILED_REPLY; + if (IS_ERR(t->buffer)) { + /* + * -ESRCH indicates VMA cleared. The target is dying. + */ + return_error_param = PTR_ERR(t->buffer); + return_error = return_error_param == -ESRCH ? + BR_DEAD_REPLY : BR_FAILED_REPLY; + return_error_line = __LINE__; + t->buffer = NULL; goto err_binder_alloc_buf_failed; } - t->buffer->allow_user_free = 0; + if (secctx) { + size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) + + ALIGN(tr->offsets_size, sizeof(void *)) + + ALIGN(extra_buffers_size, sizeof(void *)) - + ALIGN(secctx_sz, sizeof(u64)); + char *kptr = t->buffer->data + buf_offset; + + t->security_ctx = (uintptr_t)kptr + + binder_alloc_get_user_buffer_offset(&target_proc->alloc); + memcpy(kptr, secctx, secctx_sz); + security_release_secctx(secctx, secctx_sz); + secctx = NULL; + } t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; trace_binder_transaction_alloc_buf(t->buffer); - if (target_node) - binder_inc_node(target_node, 1, 0, NULL); - off_start = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); offp = off_start; - if (copy_from_user_preempt_disabled(t->buffer->data, (const void __user *)(uintptr_t) + if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) tr->data.ptr.buffer, tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EFAULT; + return_error_line = __LINE__; goto err_copy_data_failed; } - if (copy_from_user_preempt_disabled(offp, (const void __user *)(uintptr_t) + if (copy_from_user(offp, (const void __user *)(uintptr_t) tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EFAULT; + return_error_line = __LINE__; goto err_copy_data_failed; } if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", proc->pid, thread->pid, (u64)tr->offsets_size); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } if (!IS_ALIGNED(extra_buffers_size, sizeof(u64))) { @@ -2177,11 +3265,14 @@ static void binder_transaction(struct binder_proc *proc, proc->pid, thread->pid, (u64)extra_buffers_size); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } off_end = (void *)off_start + tr->offsets_size; sg_bufp = (u8 *)(PTR_ALIGN(off_end, sizeof(void *))); - sg_buf_end = sg_bufp + extra_buffers_size; + sg_buf_end = sg_bufp + extra_buffers_size - + ALIGN(secctx_sz, sizeof(u64)); off_min = 0; for (; offp < off_end; offp++) { struct binder_object_header *hdr; @@ -2193,6 +3284,8 @@ static void binder_transaction(struct binder_proc *proc, (u64)off_min, (u64)t->buffer->data_size); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } @@ -2207,6 +3300,8 @@ static void binder_transaction(struct binder_proc *proc, ret = binder_translate_binder(fp, t, thread); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } } break; @@ -2218,6 +3313,8 @@ static void binder_transaction(struct binder_proc *proc, ret = binder_translate_handle(fp, t, thread); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } } break; @@ -2229,6 +3326,8 @@ static void binder_transaction(struct binder_proc *proc, if (target_fd < 0) { return_error = BR_FAILED_REPLY; + return_error_param = target_fd; + return_error_line = __LINE__; goto err_translate_failed; } fp->pad_binder = 0; @@ -2245,6 +3344,8 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with invalid parent offset or type\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_parent; } if (!binder_validate_fixup(t->buffer, off_start, @@ -2254,12 +3355,16 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_parent; } ret = binder_translate_fd_array(fda, parent, t, thread, in_reply_to); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } last_fixup_obj = parent; @@ -2275,20 +3380,24 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with too large buffer\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } - if (copy_from_user_preempt_disabled( - sg_bufp, - (const void __user *)(uintptr_t) - bp->buffer, bp->length)) { + if (copy_from_user(sg_bufp, + (const void __user *)(uintptr_t) + bp->buffer, bp->length)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); + return_error_param = -EFAULT; return_error = BR_FAILED_REPLY; + return_error_line = __LINE__; goto err_copy_data_failed; } /* Fixup buffer pointer to target proc address space */ bp->buffer = (uintptr_t)sg_bufp + - target_proc->user_buffer_offset; + binder_alloc_get_user_buffer_offset( + &target_proc->alloc); sg_bufp += ALIGN(bp->length, sizeof(u64)); ret = binder_fixup_parent(t, thread, bp, off_start, @@ -2297,6 +3406,8 @@ static void binder_transaction(struct binder_proc *proc, last_fixup_min_off); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } last_fixup_obj = bp; @@ -2306,40 +3417,73 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with invalid object type, %x\n", proc->pid, thread->pid, hdr->type); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_object_type; } } + tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; + t->work.type = BINDER_WORK_TRANSACTION; + if (reply) { + binder_enqueue_thread_work(thread, tcomplete); + binder_inner_proc_lock(target_proc); + if (target_thread->is_dead) { + binder_inner_proc_unlock(target_proc); + goto err_dead_proc_or_thread; + } BUG_ON(t->buffer->async_transaction != 0); - binder_pop_transaction(target_thread, in_reply_to); + binder_pop_transaction_ilocked(target_thread, in_reply_to); + binder_enqueue_thread_work_ilocked(target_thread, &t->work); + binder_inner_proc_unlock(target_proc); + wake_up_interruptible_sync(&target_thread->wait); + binder_restore_priority(current, in_reply_to->saved_priority); + binder_free_transaction(in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { BUG_ON(t->buffer->async_transaction != 0); + binder_inner_proc_lock(proc); + /* + * Defer the TRANSACTION_COMPLETE, so we don't return to + * userspace immediately; this allows the target process to + * immediately start processing this transaction, reducing + * latency. We will then return the TRANSACTION_COMPLETE when + * the target replies (or there is an error). + */ + binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete); t->need_reply = 1; t->from_parent = thread->transaction_stack; thread->transaction_stack = t; + binder_inner_proc_unlock(proc); + if (!binder_proc_transaction(t, target_proc, target_thread)) { + binder_inner_proc_lock(proc); + binder_pop_transaction_ilocked(thread, t); + binder_inner_proc_unlock(proc); + goto err_dead_proc_or_thread; + } } else { BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); - if (target_node->has_async_transaction) { - target_list = &target_node->async_todo; - target_wait = NULL; - } else - target_node->has_async_transaction = 1; - } - t->work.type = BINDER_WORK_TRANSACTION; - list_add_tail(&t->work.entry, target_list); - tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; - list_add_tail(&tcomplete->entry, &thread->todo); - if (target_wait) { - if (reply || !(t->flags & TF_ONE_WAY)) { - wake_up_interruptible_sync(target_wait); - } - else { - wake_up_interruptible(target_wait); - } + binder_enqueue_thread_work(thread, tcomplete); + if (!binder_proc_transaction(t, target_proc, NULL)) + goto err_dead_proc_or_thread; } + if (target_thread) + binder_thread_dec_tmpref(target_thread); + binder_proc_dec_tmpref(target_proc); + if (target_node) + binder_dec_node_tmpref(target_node); + /* + * write barrier to synchronize with initialization + * of log entry + */ + smp_wmb(); + WRITE_ONCE(e->debug_id_done, t_debug_id); return; +err_dead_proc_or_thread: + return_error = BR_DEAD_REPLY; + return_error_line = __LINE__; + binder_dequeue_work(proc, tcomplete); err_translate_failed: err_bad_object_type: err_bad_offset: @@ -2347,42 +3491,72 @@ err_bad_parent: err_copy_data_failed: trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); + if (target_node) + binder_dec_node_tmpref(target_node); + target_node = NULL; t->buffer->transaction = NULL; - binder_free_buf(target_proc, t->buffer); + binder_alloc_free_buf(&target_proc->alloc, t->buffer); err_binder_alloc_buf_failed: +err_bad_extra_size: + if (secctx) + security_release_secctx(secctx, secctx_sz); +err_get_secctx_failed: kfree(tcomplete); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); err_alloc_tcomplete_failed: kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); err_alloc_t_failed: +err_bad_todo_list: err_bad_call_stack: err_empty_call_stack: err_dead_binder: err_invalid_target_handle: -err_no_context_mgr_node: + if (target_thread) + binder_thread_dec_tmpref(target_thread); + if (target_proc) + binder_proc_dec_tmpref(target_proc); + if (target_node) { + binder_dec_node(target_node, 1, 0); + binder_dec_node_tmpref(target_node); + } + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d transaction failed %d, size %lld-%lld\n", - proc->pid, thread->pid, return_error, - (u64)tr->data_size, (u64)tr->offsets_size); + "%d:%d transaction failed %d/%d, size %lld-%lld line %d\n", + proc->pid, thread->pid, return_error, return_error_param, + (u64)tr->data_size, (u64)tr->offsets_size, + return_error_line); { struct binder_transaction_log_entry *fe; - fe = binder_transaction_log_add( - &context->transaction_log_failed); + e->return_error = return_error; + e->return_error_param = return_error_param; + e->return_error_line = return_error_line; + fe = binder_transaction_log_add(&binder_transaction_log_failed); *fe = *e; + /* + * write barrier to synchronize with initialization + * of log entry + */ + smp_wmb(); + WRITE_ONCE(e->debug_id_done, t_debug_id); + WRITE_ONCE(fe->debug_id_done, t_debug_id); } - BUG_ON(thread->return_error != BR_OK); + BUG_ON(thread->return_error.cmd != BR_OK); if (in_reply_to) { - thread->return_error = BR_TRANSACTION_COMPLETE; + binder_restore_priority(current, in_reply_to->saved_priority); + thread->return_error.cmd = BR_TRANSACTION_COMPLETE; + binder_enqueue_thread_work(thread, &thread->return_error.work); binder_send_failed_reply(in_reply_to, return_error); - } else - thread->return_error = return_error; + } else { + thread->return_error.cmd = return_error; + binder_enqueue_thread_work(thread, &thread->return_error.work); + } } -int binder_thread_write(struct binder_proc *proc, +static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed) @@ -2393,15 +3567,17 @@ int binder_thread_write(struct binder_proc *proc, void __user *ptr = buffer + *consumed; void __user *end = buffer + size; - while (ptr < end && thread->return_error == BR_OK) { - if (get_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) + while (ptr < end && thread->return_error.cmd == BR_OK) { + int ret; + + if (get_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); trace_binder_command(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(context->binder_stats.bc)) { - context->binder_stats.bc[_IOC_NR(cmd)]++; - proc->stats.bc[_IOC_NR(cmd)]++; - thread->stats.bc[_IOC_NR(cmd)]++; + if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { + atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]); + atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]); + atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]); } switch (cmd) { case BC_INCREFS: @@ -2409,72 +3585,74 @@ int binder_thread_write(struct binder_proc *proc, case BC_RELEASE: case BC_DECREFS: { uint32_t target; - struct binder_ref *ref; const char *debug_string; + bool strong = cmd == BC_ACQUIRE || cmd == BC_RELEASE; + bool increment = cmd == BC_INCREFS || cmd == BC_ACQUIRE; + struct binder_ref_data rdata; - if (get_user_preempt_disabled(target, (uint32_t __user *)ptr)) + if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; + ptr += sizeof(uint32_t); - if (target == 0 && context->binder_context_mgr_node && - (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) { - ref = binder_get_ref_for_node(proc, - context->binder_context_mgr_node); - if (ref->desc != target) { - binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n", - proc->pid, thread->pid, - ref->desc); - } - } else - ref = binder_get_ref(proc, target, - cmd == BC_ACQUIRE || - cmd == BC_RELEASE); - if (ref == NULL) { - binder_user_error("%d:%d refcount change on invalid ref %d\n", - proc->pid, thread->pid, target); - break; + ret = -1; + if (increment && !target) { + struct binder_node *ctx_mgr_node; + mutex_lock(&context->context_mgr_node_lock); + ctx_mgr_node = context->binder_context_mgr_node; + if (ctx_mgr_node) + ret = binder_inc_ref_for_node( + proc, ctx_mgr_node, + strong, NULL, &rdata); + mutex_unlock(&context->context_mgr_node_lock); + } + if (ret) + ret = binder_update_ref_for_handle( + proc, target, increment, strong, + &rdata); + if (!ret && rdata.desc != target) { + binder_user_error("%d:%d tried to acquire reference to desc %d, got %d instead\n", + proc->pid, thread->pid, + target, rdata.desc); } switch (cmd) { case BC_INCREFS: debug_string = "IncRefs"; - binder_inc_ref(ref, 0, NULL); break; case BC_ACQUIRE: debug_string = "Acquire"; - binder_inc_ref(ref, 1, NULL); break; case BC_RELEASE: debug_string = "Release"; - binder_dec_ref(&ref, 1); break; case BC_DECREFS: default: debug_string = "DecRefs"; - binder_dec_ref(&ref, 0); break; } - if (ref == NULL) { - binder_debug(BINDER_DEBUG_USER_REFS, - "binder: %d:%d %s ref deleted", - proc->pid, thread->pid, debug_string); - } else { + if (ret) { + binder_user_error("%d:%d %s %d refcount change on invalid ref %d ret %d\n", + proc->pid, thread->pid, debug_string, + strong, target, ret); + break; + } binder_debug(BINDER_DEBUG_USER_REFS, - "binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n", - proc->pid, thread->pid, debug_string, - ref->debug_id, ref->desc, ref->strong, - ref->weak, ref->node->debug_id); - } - break; + "%d:%d %s ref %d desc %d s %d w %d\n", + proc->pid, thread->pid, debug_string, + rdata.debug_id, rdata.desc, rdata.strong, + rdata.weak); + break; } case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { binder_uintptr_t node_ptr; binder_uintptr_t cookie; struct binder_node *node; + bool free_node; - if (get_user_preempt_disabled(node_ptr, (binder_uintptr_t __user *)ptr)) + if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); node = binder_get_node(proc, node_ptr); @@ -2494,13 +3672,17 @@ int binder_thread_write(struct binder_proc *proc, "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", (u64)node_ptr, node->debug_id, (u64)cookie, (u64)node->cookie); + binder_put_node(node); break; } + binder_node_inner_lock(node); if (cmd == BC_ACQUIRE_DONE) { if (node->pending_strong_ref == 0) { binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", proc->pid, thread->pid, node->debug_id); + binder_node_inner_unlock(node); + binder_put_node(node); break; } node->pending_strong_ref = 0; @@ -2509,16 +3691,23 @@ int binder_thread_write(struct binder_proc *proc, binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", proc->pid, thread->pid, node->debug_id); + binder_node_inner_unlock(node); + binder_put_node(node); break; } node->pending_weak_ref = 0; } - binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); + free_node = binder_dec_node_nilocked(node, + cmd == BC_ACQUIRE_DONE, 0); + WARN_ON(free_node); binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s node %d ls %d lw %d\n", + "%d:%d %s node %d ls %d lw %d tr %d\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node->debug_id, node->local_strong_refs, node->local_weak_refs); + node->debug_id, node->local_strong_refs, + node->local_weak_refs, node->tmp_refs); + binder_node_inner_unlock(node); + binder_put_node(node); break; } case BC_ATTEMPT_ACQUIRE: @@ -2532,19 +3721,24 @@ int binder_thread_write(struct binder_proc *proc, binder_uintptr_t data_ptr; struct binder_buffer *buffer; - if (get_user_preempt_disabled(data_ptr, (binder_uintptr_t __user *)ptr)) + if (get_user(data_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - buffer = binder_buffer_lookup(proc, data_ptr); - if (buffer == NULL) { - binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", - proc->pid, thread->pid, (u64)data_ptr); - break; - } - if (!buffer->allow_user_free) { - binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n", - proc->pid, thread->pid, (u64)data_ptr); + buffer = binder_alloc_prepare_to_free(&proc->alloc, + data_ptr); + if (IS_ERR_OR_NULL(buffer)) { + if (PTR_ERR(buffer) == -EPERM) { + binder_user_error( + "%d:%d BC_FREE_BUFFER u%016llx matched unreturned or currently freeing buffer\n", + proc->pid, thread->pid, + (u64)data_ptr); + } else { + binder_user_error( + "%d:%d BC_FREE_BUFFER u%016llx no match\n", + proc->pid, thread->pid, + (u64)data_ptr); + } break; } binder_debug(BINDER_DEBUG_FREE_BUFFER, @@ -2553,20 +3747,34 @@ int binder_thread_write(struct binder_proc *proc, buffer->debug_id, buffer->transaction ? "active" : "finished"); + binder_inner_proc_lock(proc); if (buffer->transaction) { buffer->transaction->buffer = NULL; buffer->transaction = NULL; } + binder_inner_proc_unlock(proc); if (buffer->async_transaction && buffer->target_node) { - BUG_ON(!buffer->target_node->has_async_transaction); - if (list_empty(&buffer->target_node->async_todo)) - buffer->target_node->has_async_transaction = 0; - else - list_move_tail(buffer->target_node->async_todo.next, &thread->todo); + struct binder_node *buf_node; + struct binder_work *w; + + buf_node = buffer->target_node; + binder_node_inner_lock(buf_node); + BUG_ON(!buf_node->has_async_transaction); + BUG_ON(buf_node->proc != proc); + w = binder_dequeue_work_head_ilocked( + &buf_node->async_todo); + if (!w) { + buf_node->has_async_transaction = false; + } else { + binder_enqueue_work_ilocked( + w, &proc->todo); + binder_wakeup_proc_ilocked(proc); + } + binder_node_inner_unlock(buf_node); } trace_binder_transaction_buffer_release(buffer); binder_transaction_buffer_release(proc, buffer, NULL); - binder_free_buf(proc, buffer); + binder_alloc_free_buf(&proc->alloc, buffer); break; } @@ -2574,8 +3782,7 @@ int binder_thread_write(struct binder_proc *proc, case BC_REPLY_SG: { struct binder_transaction_data_sg tr; - if (copy_from_user_preempt_disabled(&tr, ptr, - sizeof(tr))) + if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr); binder_transaction(proc, thread, &tr.transaction_data, @@ -2586,7 +3793,7 @@ int binder_thread_write(struct binder_proc *proc, case BC_REPLY: { struct binder_transaction_data tr; - if (copy_from_user_preempt_disabled(&tr, ptr, sizeof(tr))) + if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr); binder_transaction(proc, thread, &tr, @@ -2598,6 +3805,7 @@ int binder_thread_write(struct binder_proc *proc, binder_debug(BINDER_DEBUG_THREADS, "%d:%d BC_REGISTER_LOOPER\n", proc->pid, thread->pid); + binder_inner_proc_lock(proc); if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n", @@ -2611,6 +3819,7 @@ int binder_thread_write(struct binder_proc *proc, proc->requested_threads_started++; } thread->looper |= BINDER_LOOPER_STATE_REGISTERED; + binder_inner_proc_unlock(proc); break; case BC_ENTER_LOOPER: binder_debug(BINDER_DEBUG_THREADS, @@ -2635,15 +3844,36 @@ int binder_thread_write(struct binder_proc *proc, uint32_t target; binder_uintptr_t cookie; struct binder_ref *ref; - struct binder_ref_death *death; + struct binder_ref_death *death = NULL; - if (get_user_preempt_disabled(target, (uint32_t __user *)ptr)) + if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - ref = binder_get_ref(proc, target, false); + if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { + /* + * Allocate memory for death notification + * before taking lock + */ + death = kzalloc(sizeof(*death), GFP_KERNEL); + if (death == NULL) { + WARN_ON(thread->return_error.cmd != + BR_OK); + thread->return_error.cmd = BR_ERROR; + binder_enqueue_thread_work( + thread, + &thread->return_error.work); + binder_debug( + BINDER_DEBUG_FAILED_TRANSACTION, + "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", + proc->pid, thread->pid); + break; + } + } + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, target, false); if (ref == NULL) { binder_user_error("%d:%d %s invalid ref %d\n", proc->pid, thread->pid, @@ -2651,6 +3881,8 @@ int binder_thread_write(struct binder_proc *proc, "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", target); + binder_proc_unlock(proc); + kfree(death); break; } @@ -2660,21 +3892,18 @@ int binder_thread_write(struct binder_proc *proc, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", - (u64)cookie, ref->debug_id, ref->desc, - ref->strong, ref->weak, ref->node->debug_id); + (u64)cookie, ref->data.debug_id, + ref->data.desc, ref->data.strong, + ref->data.weak, ref->node->debug_id); + binder_node_lock(ref->node); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { if (ref->death) { binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n", proc->pid, thread->pid); - break; - } - death = kzalloc_preempt_disabled(sizeof(*death)); - if (death == NULL) { - thread->return_error = BR_ERROR; - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", - proc->pid, thread->pid); + binder_node_unlock(ref->node); + binder_proc_unlock(proc); + kfree(death); break; } binder_stats_created(BINDER_STAT_DEATH); @@ -2683,17 +3912,19 @@ int binder_thread_write(struct binder_proc *proc, ref->death = death; if (ref->node->proc == NULL) { ref->death->work.type = BINDER_WORK_DEAD_BINDER; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&ref->death->work.entry, &thread->todo); - } else { - list_add_tail(&ref->death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); - } + + binder_inner_proc_lock(proc); + binder_enqueue_work_ilocked( + &ref->death->work, &proc->todo); + binder_wakeup_proc_ilocked(proc); + binder_inner_proc_unlock(proc); } } else { if (ref->death == NULL) { binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n", proc->pid, thread->pid); + binder_node_unlock(ref->node); + binder_proc_unlock(proc); break; } death = ref->death; @@ -2702,34 +3933,52 @@ int binder_thread_write(struct binder_proc *proc, proc->pid, thread->pid, (u64)death->cookie, (u64)cookie); + binder_node_unlock(ref->node); + binder_proc_unlock(proc); break; } ref->death = NULL; + binder_inner_proc_lock(proc); if (list_empty(&death->work.entry)) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&death->work.entry, &thread->todo); - } else { - list_add_tail(&death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); + if (thread->looper & + (BINDER_LOOPER_STATE_REGISTERED | + BINDER_LOOPER_STATE_ENTERED)) + binder_enqueue_thread_work_ilocked( + thread, + &death->work); + else { + binder_enqueue_work_ilocked( + &death->work, + &proc->todo); + binder_wakeup_proc_ilocked( + proc); } } else { BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; } + binder_inner_proc_unlock(proc); } + binder_node_unlock(ref->node); + binder_proc_unlock(proc); } break; case BC_DEAD_BINDER_DONE: { struct binder_work *w; binder_uintptr_t cookie; struct binder_ref_death *death = NULL; - if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(cookie); - list_for_each_entry(w, &proc->delivered_death, entry) { - struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); + binder_inner_proc_lock(proc); + list_for_each_entry(w, &proc->delivered_death, + entry) { + struct binder_ref_death *tmp_death = + container_of(w, + struct binder_ref_death, + work); if (tmp_death->cookie == cookie) { death = tmp_death; @@ -2738,23 +3987,30 @@ int binder_thread_write(struct binder_proc *proc, } binder_debug(BINDER_DEBUG_DEAD_BINDER, "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n", - proc->pid, thread->pid, (u64)cookie, death); + proc->pid, thread->pid, (u64)cookie, + death); if (death == NULL) { binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", proc->pid, thread->pid, (u64)cookie); + binder_inner_proc_unlock(proc); break; } - - list_del_init(&death->work.entry); + binder_dequeue_work_ilocked(&death->work); if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&death->work.entry, &thread->todo); - } else { - list_add_tail(&death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); + if (thread->looper & + (BINDER_LOOPER_STATE_REGISTERED | + BINDER_LOOPER_STATE_ENTERED)) + binder_enqueue_thread_work_ilocked( + thread, &death->work); + else { + binder_enqueue_work_ilocked( + &death->work, + &proc->todo); + binder_wakeup_proc_ilocked(proc); } } + binder_inner_proc_unlock(proc); } break; default: @@ -2771,24 +4027,74 @@ static void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, uint32_t cmd) { trace_binder_return(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(proc->stats.br)) { - proc->context->binder_stats.br[_IOC_NR(cmd)]++; - proc->stats.br[_IOC_NR(cmd)]++; - thread->stats.br[_IOC_NR(cmd)]++; + if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { + atomic_inc(&binder_stats.br[_IOC_NR(cmd)]); + atomic_inc(&proc->stats.br[_IOC_NR(cmd)]); + atomic_inc(&thread->stats.br[_IOC_NR(cmd)]); } } -static int binder_has_proc_work(struct binder_proc *proc, - struct binder_thread *thread) +static int binder_put_node_cmd(struct binder_proc *proc, + struct binder_thread *thread, + void __user **ptrp, + binder_uintptr_t node_ptr, + binder_uintptr_t node_cookie, + int node_debug_id, + uint32_t cmd, const char *cmd_name) { - return !list_empty(&proc->todo) || - (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); + void __user *ptr = *ptrp; + + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + + if (put_user(node_ptr, (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + + if (put_user(node_cookie, (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + + binder_stat_br(proc, thread, cmd); + binder_debug(BINDER_DEBUG_USER_REFS, "%d:%d %s %d u%016llx c%016llx\n", + proc->pid, thread->pid, cmd_name, node_debug_id, + (u64)node_ptr, (u64)node_cookie); + + *ptrp = ptr; + return 0; } -static int binder_has_thread_work(struct binder_thread *thread) +static int binder_wait_for_work(struct binder_thread *thread, + bool do_proc_work) { - return !list_empty(&thread->todo) || thread->return_error != BR_OK || - (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); + DEFINE_WAIT(wait); + struct binder_proc *proc = thread->proc; + int ret = 0; + + freezer_do_not_count(); + binder_inner_proc_lock(proc); + for (;;) { + prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE); + if (binder_has_work_ilocked(thread, do_proc_work)) + break; + if (do_proc_work) + list_add(&thread->waiting_thread_node, + &proc->waiting_threads); + binder_inner_proc_unlock(proc); + schedule(); + binder_inner_proc_lock(proc); + list_del_init(&thread->waiting_thread_node); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + finish_wait(&thread->wait, &wait); + binder_inner_proc_unlock(proc); + freezer_count(); + + return ret; } static int binder_thread_read(struct binder_proc *proc, @@ -2804,43 +4110,21 @@ static int binder_thread_read(struct binder_proc *proc, int wait_for_proc_work; if (*consumed == 0) { - if (put_user_preempt_disabled(BR_NOOP, (uint32_t __user *)ptr)) + if (put_user(BR_NOOP, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); } retry: - wait_for_proc_work = thread->transaction_stack == NULL && - list_empty(&thread->todo); - - if (thread->return_error != BR_OK && ptr < end) { - if (thread->return_error2 != BR_OK) { - if (put_user_preempt_disabled(thread->return_error2, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - binder_stat_br(proc, thread, thread->return_error2); - if (ptr == end) - goto done; - thread->return_error2 = BR_OK; - } - if (put_user_preempt_disabled(thread->return_error, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - binder_stat_br(proc, thread, thread->return_error); - thread->return_error = BR_OK; - goto done; - } - + binder_inner_proc_lock(proc); + wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); + binder_inner_proc_unlock(proc); thread->looper |= BINDER_LOOPER_STATE_WAITING; - if (wait_for_proc_work) - proc->ready_threads++; - - binder_unlock(proc->context, __func__); trace_binder_wait_for_work(wait_for_proc_work, !!thread->transaction_stack, - !list_empty(&thread->todo)); + !binder_worklist_empty(proc, &thread->todo)); if (wait_for_proc_work) { if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) { @@ -2849,24 +4133,16 @@ retry: wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); } - binder_set_nice(proc->default_priority); - if (non_block) { - if (!binder_has_proc_work(proc, thread)) - ret = -EAGAIN; - } else - ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread)); - } else { - if (non_block) { - if (!binder_has_thread_work(thread)) - ret = -EAGAIN; - } else - ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); + binder_restore_priority(current, proc->default_priority); } - binder_lock(proc->context, __func__); + if (non_block) { + if (!binder_has_work(thread, wait_for_proc_work)) + ret = -EAGAIN; + } else { + ret = binder_wait_for_work(thread, wait_for_proc_work); + } - if (wait_for_proc_work) - proc->ready_threads--; thread->looper &= ~BINDER_LOOPER_STATE_WAITING; if (ret) @@ -2874,34 +4150,62 @@ retry: while (1) { uint32_t cmd; - struct binder_transaction_data tr; - struct binder_work *w; + struct binder_transaction_data_secctx tr; + struct binder_transaction_data *trd = &tr.transaction_data; + struct binder_work *w = NULL; + struct list_head *list = NULL; struct binder_transaction *t = NULL; + struct binder_thread *t_from; + size_t trsize = sizeof(*trd); + + binder_inner_proc_lock(proc); + if (!binder_worklist_empty_ilocked(&thread->todo)) + list = &thread->todo; + else if (!binder_worklist_empty_ilocked(&proc->todo) && + wait_for_proc_work) + list = &proc->todo; + else { + binder_inner_proc_unlock(proc); - if (!list_empty(&thread->todo)) { - w = list_first_entry(&thread->todo, struct binder_work, - entry); - } else if (!list_empty(&proc->todo) && wait_for_proc_work) { - w = list_first_entry(&proc->todo, struct binder_work, - entry); - } else { /* no data added */ - if (ptr - buffer == 4 && - !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) + if (ptr - buffer == 4 && !thread->looper_need_return) goto retry; break; } - if (end - ptr < sizeof(tr) + 4) + if (end - ptr < sizeof(tr) + 4) { + binder_inner_proc_unlock(proc); break; + } + w = binder_dequeue_work_head_ilocked(list); + if (binder_worklist_empty_ilocked(&thread->todo)) + thread->process_todo = false; switch (w->type) { case BINDER_WORK_TRANSACTION: { + binder_inner_proc_unlock(proc); t = container_of(w, struct binder_transaction, work); } break; + case BINDER_WORK_RETURN_ERROR: { + struct binder_error *e = container_of( + w, struct binder_error, work); + + WARN_ON(e->cmd == BR_OK); + binder_inner_proc_unlock(proc); + if (put_user(e->cmd, (uint32_t __user *)ptr)) + return -EFAULT; + cmd = e->cmd; + e->cmd = BR_OK; + ptr += sizeof(uint32_t); + + binder_stat_br(proc, thread, e->cmd); + } break; case BINDER_WORK_TRANSACTION_COMPLETE: { + binder_inner_proc_unlock(proc); cmd = BR_TRANSACTION_COMPLETE; - if (put_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) + kfree(w); + binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); + if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); @@ -2909,113 +4213,132 @@ retry: binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, "%d:%d BR_TRANSACTION_COMPLETE\n", proc->pid, thread->pid); - - list_del(&w->entry); - kfree(w); - binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); } break; case BINDER_WORK_NODE: { struct binder_node *node = container_of(w, struct binder_node, work); - uint32_t cmd = BR_NOOP; - const char *cmd_name; - int strong = node->internal_strong_refs || node->local_strong_refs; - int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; - - if (weak && !node->has_weak_ref) { - cmd = BR_INCREFS; - cmd_name = "BR_INCREFS"; + int strong, weak; + binder_uintptr_t node_ptr = node->ptr; + binder_uintptr_t node_cookie = node->cookie; + int node_debug_id = node->debug_id; + int has_weak_ref; + int has_strong_ref; + void __user *orig_ptr = ptr; + + BUG_ON(proc != node->proc); + strong = node->internal_strong_refs || + node->local_strong_refs; + weak = !hlist_empty(&node->refs) || + node->local_weak_refs || + node->tmp_refs || strong; + has_strong_ref = node->has_strong_ref; + has_weak_ref = node->has_weak_ref; + + if (weak && !has_weak_ref) { node->has_weak_ref = 1; node->pending_weak_ref = 1; node->local_weak_refs++; - } else if (strong && !node->has_strong_ref) { - cmd = BR_ACQUIRE; - cmd_name = "BR_ACQUIRE"; + } + if (strong && !has_strong_ref) { node->has_strong_ref = 1; node->pending_strong_ref = 1; node->local_strong_refs++; - } else if (!strong && node->has_strong_ref) { - cmd = BR_RELEASE; - cmd_name = "BR_RELEASE"; + } + if (!strong && has_strong_ref) node->has_strong_ref = 0; - } else if (!weak && node->has_weak_ref) { - cmd = BR_DECREFS; - cmd_name = "BR_DECREFS"; + if (!weak && has_weak_ref) node->has_weak_ref = 0; - } - if (cmd != BR_NOOP) { - if (put_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - if (put_user_preempt_disabled(node->ptr, - (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - if (put_user_preempt_disabled(node->cookie, - (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - - binder_stat_br(proc, thread, cmd); - binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s %d u%016llx c%016llx\n", - proc->pid, thread->pid, cmd_name, - node->debug_id, - (u64)node->ptr, (u64)node->cookie); - } else { - list_del_init(&w->entry); - if (!weak && !strong) { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%016llx c%016llx deleted\n", - proc->pid, thread->pid, - node->debug_id, - (u64)node->ptr, - (u64)node->cookie); - rb_erase(&node->rb_node, &proc->nodes); - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); - } else { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%016llx c%016llx state unchanged\n", - proc->pid, thread->pid, - node->debug_id, - (u64)node->ptr, - (u64)node->cookie); - } - } + if (!weak && !strong) { + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx deleted\n", + proc->pid, thread->pid, + node_debug_id, + (u64)node_ptr, + (u64)node_cookie); + rb_erase(&node->rb_node, &proc->nodes); + binder_inner_proc_unlock(proc); + binder_node_lock(node); + /* + * Acquire the node lock before freeing the + * node to serialize with other threads that + * may have been holding the node lock while + * decrementing this node (avoids race where + * this thread frees while the other thread + * is unlocking the node after the final + * decrement) + */ + binder_node_unlock(node); + binder_free_node(node); + } else + binder_inner_proc_unlock(proc); + + if (weak && !has_weak_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_INCREFS, "BR_INCREFS"); + if (!ret && strong && !has_strong_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_ACQUIRE, "BR_ACQUIRE"); + if (!ret && !strong && has_strong_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_RELEASE, "BR_RELEASE"); + if (!ret && !weak && has_weak_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_DECREFS, "BR_DECREFS"); + if (orig_ptr == ptr) + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx state unchanged\n", + proc->pid, thread->pid, + node_debug_id, + (u64)node_ptr, + (u64)node_cookie); + if (ret) + return ret; } break; case BINDER_WORK_DEAD_BINDER: case BINDER_WORK_DEAD_BINDER_AND_CLEAR: case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { struct binder_ref_death *death; uint32_t cmd; + binder_uintptr_t cookie; death = container_of(w, struct binder_ref_death, work); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; else cmd = BR_DEAD_BINDER; - if (put_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - if (put_user_preempt_disabled(death->cookie, - (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - binder_stat_br(proc, thread, cmd); + cookie = death->cookie; + binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, "%d:%d %s %016llx\n", proc->pid, thread->pid, cmd == BR_DEAD_BINDER ? "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE", - (u64)death->cookie); - + (u64)cookie); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { - list_del(&w->entry); + binder_inner_proc_unlock(proc); kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); - } else - list_move(&w->entry, &proc->delivered_death); + } else { + binder_enqueue_work_ilocked( + w, &proc->delivered_death); + binder_inner_proc_unlock(proc); + } + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (put_user(cookie, + (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + binder_stat_br(proc, thread, cmd); if (cmd == BR_DEAD_BINDER) goto done; /* DEAD_BINDER notifications can cause transactions */ } break; @@ -3027,50 +4350,69 @@ retry: BUG_ON(t->buffer == NULL); if (t->buffer->target_node) { struct binder_node *target_node = t->buffer->target_node; - - tr.target.ptr = target_node->ptr; - tr.cookie = target_node->cookie; - t->saved_priority = task_nice(current); - if (t->priority < target_node->min_priority && - !(t->flags & TF_ONE_WAY)) - binder_set_nice(t->priority); - else if (!(t->flags & TF_ONE_WAY) || - t->saved_priority > target_node->min_priority) - binder_set_nice(target_node->min_priority); + struct binder_priority node_prio; + + trd->target.ptr = target_node->ptr; + trd->cookie = target_node->cookie; + node_prio.sched_policy = target_node->sched_policy; + node_prio.prio = target_node->min_priority; + binder_transaction_priority(current, t, node_prio, + target_node->inherit_rt); cmd = BR_TRANSACTION; } else { - tr.target.ptr = 0; - tr.cookie = 0; + trd->target.ptr = 0; + trd->cookie = 0; cmd = BR_REPLY; } - tr.code = t->code; - tr.flags = t->flags; - tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); + trd->code = t->code; + trd->flags = t->flags; + trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid); - if (t->from) { - struct task_struct *sender = t->from->proc->tsk; + t_from = binder_get_txn_from(t); + if (t_from) { + struct task_struct *sender = t_from->proc->tsk; - tr.sender_pid = task_tgid_nr_ns(sender, - task_active_pid_ns(current)); + trd->sender_pid = + task_tgid_nr_ns(sender, + task_active_pid_ns(current)); } else { - tr.sender_pid = 0; + trd->sender_pid = 0; } - tr.data_size = t->buffer->data_size; - tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (binder_uintptr_t)( - (uintptr_t)t->buffer->data + - proc->user_buffer_offset); - tr.data.ptr.offsets = tr.data.ptr.buffer + + trd->data_size = t->buffer->data_size; + trd->offsets_size = t->buffer->offsets_size; + trd->data.ptr.buffer = (binder_uintptr_t) + ((uintptr_t)t->buffer->data + + binder_alloc_get_user_buffer_offset(&proc->alloc)); + trd->data.ptr.offsets = trd->data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); - if (put_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) + tr.secctx = t->security_ctx; + if (t->security_ctx) { + cmd = BR_TRANSACTION_SEC_CTX; + trsize = sizeof(tr); + } + if (put_user(cmd, (uint32_t __user *)ptr)) { + if (t_from) + binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "put_user failed", + BR_FAILED_REPLY); + return -EFAULT; + } ptr += sizeof(uint32_t); - if (copy_to_user_preempt_disabled(ptr, &tr, sizeof(tr))) + if (copy_to_user(ptr, &tr, trsize)) { + if (t_from) + binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "copy_to_user failed", + BR_FAILED_REPLY); + return -EFAULT; - ptr += sizeof(tr); + } + ptr += trsize; trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); @@ -3078,22 +4420,25 @@ retry: "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : - "BR_REPLY", - t->debug_id, t->from ? t->from->proc->pid : 0, - t->from ? t->from->pid : 0, cmd, + (cmd == BR_TRANSACTION_SEC_CTX) ? + "BR_TRANSACTION_SEC_CTX" : "BR_REPLY", + t->debug_id, t_from ? t_from->proc->pid : 0, + t_from ? t_from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, - (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); + (u64)trd->data.ptr.buffer, + (u64)trd->data.ptr.offsets); - list_del(&t->work.entry); + if (t_from) + binder_thread_dec_tmpref(t_from); t->buffer->allow_user_free = 1; - if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { + if (cmd != BR_REPLY && !(t->flags & TF_ONE_WAY)) { + binder_inner_proc_lock(thread->proc); t->to_parent = thread->transaction_stack; t->to_thread = thread; thread->transaction_stack = t; + binder_inner_proc_unlock(thread->proc); } else { - t->buffer->transaction = NULL; - kfree(t); - binder_stats_deleted(BINDER_STAT_TRANSACTION); + binder_free_transaction(t); } break; } @@ -3101,45 +4446,52 @@ retry: done: *consumed = ptr - buffer; - if (proc->requested_threads + proc->ready_threads == 0 && + binder_inner_proc_lock(proc); + if (proc->requested_threads == 0 && + list_empty(&thread->proc->waiting_threads) && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) { proc->requested_threads++; + binder_inner_proc_unlock(proc); binder_debug(BINDER_DEBUG_THREADS, "%d:%d BR_SPAWN_LOOPER\n", proc->pid, thread->pid); - if (put_user_preempt_disabled(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) + if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) return -EFAULT; binder_stat_br(proc, thread, BR_SPAWN_LOOPER); - } + } else + binder_inner_proc_unlock(proc); return 0; } -static void binder_release_work(struct list_head *list) +static void binder_release_work(struct binder_proc *proc, + struct list_head *list) { struct binder_work *w; - while (!list_empty(list)) { - w = list_first_entry(list, struct binder_work, entry); - list_del_init(&w->entry); + while (1) { + w = binder_dequeue_work_head(proc, list); + if (!w) + return; + switch (w->type) { case BINDER_WORK_TRANSACTION: { struct binder_transaction *t; t = container_of(w, struct binder_transaction, work); - if (t->buffer->target_node && - !(t->flags & TF_ONE_WAY)) { - binder_send_failed_reply(t, BR_DEAD_REPLY); - } else { - binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered transaction %d\n", - t->debug_id); - t->buffer->transaction = NULL; - kfree(t); - binder_stats_deleted(BINDER_STAT_TRANSACTION); - } + + binder_cleanup_transaction(t, "process died.", + BR_DEAD_REPLY); + } break; + case BINDER_WORK_RETURN_ERROR: { + struct binder_error *e = container_of( + w, struct binder_error, work); + + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered TRANSACTION_ERROR: %u\n", + e->cmd); } break; case BINDER_WORK_TRANSACTION_COMPLETE: { binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, @@ -3167,7 +4519,8 @@ static void binder_release_work(struct list_head *list) } -static struct binder_thread *binder_get_thread(struct binder_proc *proc) +static struct binder_thread *binder_get_thread_ilocked( + struct binder_proc *proc, struct binder_thread *new_thread) { struct binder_thread *thread = NULL; struct rb_node *parent = NULL; @@ -3182,38 +4535,102 @@ static struct binder_thread *binder_get_thread(struct binder_proc *proc) else if (current->pid > thread->pid) p = &(*p)->rb_right; else - break; + return thread; } - if (*p == NULL) { - thread = kzalloc_preempt_disabled(sizeof(*thread)); - if (thread == NULL) + if (!new_thread) + return NULL; + thread = new_thread; + binder_stats_created(BINDER_STAT_THREAD); + thread->proc = proc; + thread->pid = current->pid; + get_task_struct(current); + thread->task = current; + atomic_set(&thread->tmp_ref, 0); + init_waitqueue_head(&thread->wait); + INIT_LIST_HEAD(&thread->todo); + rb_link_node(&thread->rb_node, parent, p); + rb_insert_color(&thread->rb_node, &proc->threads); + thread->looper_need_return = true; + thread->return_error.work.type = BINDER_WORK_RETURN_ERROR; + thread->return_error.cmd = BR_OK; + thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR; + thread->reply_error.cmd = BR_OK; + INIT_LIST_HEAD(&new_thread->waiting_thread_node); + return thread; +} + +static struct binder_thread *binder_get_thread(struct binder_proc *proc) +{ + struct binder_thread *thread; + struct binder_thread *new_thread; + + binder_inner_proc_lock(proc); + thread = binder_get_thread_ilocked(proc, NULL); + binder_inner_proc_unlock(proc); + if (!thread) { + new_thread = kzalloc(sizeof(*thread), GFP_KERNEL); + if (new_thread == NULL) return NULL; - binder_stats_created(BINDER_STAT_THREAD); - thread->proc = proc; - thread->pid = current->pid; - init_waitqueue_head(&thread->wait); - INIT_LIST_HEAD(&thread->todo); - rb_link_node(&thread->rb_node, parent, p); - rb_insert_color(&thread->rb_node, &proc->threads); - thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; - thread->return_error = BR_OK; - thread->return_error2 = BR_OK; + binder_inner_proc_lock(proc); + thread = binder_get_thread_ilocked(proc, new_thread); + binder_inner_proc_unlock(proc); + if (thread != new_thread) + kfree(new_thread); } return thread; } -static int binder_free_thread(struct binder_proc *proc, - struct binder_thread *thread) +static void binder_free_proc(struct binder_proc *proc) +{ + BUG_ON(!list_empty(&proc->todo)); + BUG_ON(!list_empty(&proc->delivered_death)); + binder_alloc_deferred_release(&proc->alloc); + put_task_struct(proc->tsk); + binder_stats_deleted(BINDER_STAT_PROC); + kfree(proc); +} + +static void binder_free_thread(struct binder_thread *thread) +{ + BUG_ON(!list_empty(&thread->todo)); + binder_stats_deleted(BINDER_STAT_THREAD); + binder_proc_dec_tmpref(thread->proc); + put_task_struct(thread->task); + kfree(thread); +} + +static int binder_thread_release(struct binder_proc *proc, + struct binder_thread *thread) { struct binder_transaction *t; struct binder_transaction *send_reply = NULL; int active_transactions = 0; + struct binder_transaction *last_t = NULL; + binder_inner_proc_lock(thread->proc); + /* + * take a ref on the proc so it survives + * after we remove this thread from proc->threads. + * The corresponding dec is when we actually + * free the thread in binder_free_thread() + */ + atomic_inc(&proc->tmp_ref); + /* + * take a ref on this thread to ensure it + * survives while we are releasing it + */ + atomic_inc(&thread->tmp_ref); rb_erase(&thread->rb_node, &proc->threads); t = thread->transaction_stack; - if (t && t->to_thread == thread) - send_reply = t; + if (t) { + spin_lock(&t->lock); + if (t->to_thread == thread) + send_reply = t; + } + thread->is_dead = true; + while (t) { + last_t = t; active_transactions++; binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, "release %d:%d transaction %d %s, still active\n", @@ -3234,12 +4651,37 @@ static int binder_free_thread(struct binder_proc *proc, t = t->from_parent; } else BUG(); + spin_unlock(&last_t->lock); + if (t) + spin_lock(&t->lock); + } + + /* + * If this thread used poll, make sure we remove the waitqueue + * from any epoll data structures holding it with POLLFREE. + * waitqueue_active() is safe to use here because we're holding + * the inner lock. + */ + if ((thread->looper & BINDER_LOOPER_STATE_POLL) && + waitqueue_active(&thread->wait)) { + wake_up_poll(&thread->wait, POLLHUP | POLLFREE); } + + binder_inner_proc_unlock(thread->proc); + + /* + * This is needed to avoid races between wake_up_poll() above and + * and ep_remove_waitqueue() called for other reasons (eg the epoll file + * descriptor being closed); ep_remove_waitqueue() holds an RCU read + * lock, so we can be sure it's done after calling synchronize_rcu(). + */ + if (thread->looper & BINDER_LOOPER_STATE_POLL) + synchronize_rcu(); + if (send_reply) binder_send_failed_reply(send_reply, BR_DEAD_REPLY); - binder_release_work(&thread->todo); - kfree(thread); - binder_stats_deleted(BINDER_STAT_THREAD); + binder_release_work(proc, &thread->todo); + binder_thread_dec_tmpref(thread); return active_transactions; } @@ -3248,30 +4690,23 @@ static unsigned int binder_poll(struct file *filp, { struct binder_proc *proc = filp->private_data; struct binder_thread *thread = NULL; - int wait_for_proc_work; - - binder_lock(proc->context, __func__); + bool wait_for_proc_work; thread = binder_get_thread(proc); + if (!thread) + return POLLERR; - wait_for_proc_work = thread->transaction_stack == NULL && - list_empty(&thread->todo) && thread->return_error == BR_OK; + binder_inner_proc_lock(thread->proc); + thread->looper |= BINDER_LOOPER_STATE_POLL; + wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); - binder_unlock(proc->context, __func__); + binder_inner_proc_unlock(thread->proc); + + poll_wait(filp, &thread->wait, wait); + + if (binder_has_work(thread, wait_for_proc_work)) + return POLLIN; - if (wait_for_proc_work) { - if (binder_has_proc_work(proc, thread)) - return POLLIN; - poll_wait(filp, &proc->wait, wait); - if (binder_has_proc_work(proc, thread)) - return POLLIN; - } else { - if (binder_has_thread_work(thread)) - return POLLIN; - poll_wait(filp, &thread->wait, wait); - if (binder_has_thread_work(thread)) - return POLLIN; - } return 0; } @@ -3289,7 +4724,7 @@ static int binder_ioctl_write_read(struct file *filp, ret = -EINVAL; goto out; } - if (copy_from_user_preempt_disabled(&bwr, ubuf, sizeof(bwr))) { + if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { ret = -EFAULT; goto out; } @@ -3307,7 +4742,7 @@ static int binder_ioctl_write_read(struct file *filp, trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; - if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto out; } @@ -3318,10 +4753,12 @@ static int binder_ioctl_write_read(struct file *filp, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); trace_binder_read_done(ret); - if (!list_empty(&proc->todo)) - wake_up_interruptible(&proc->wait); + binder_inner_proc_lock(proc); + if (!binder_worklist_empty_ilocked(&proc->todo)) + binder_wakeup_proc_ilocked(proc); + binder_inner_proc_unlock(proc); if (ret < 0) { - if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto out; } @@ -3331,7 +4768,7 @@ static int binder_ioctl_write_read(struct file *filp, proc->pid, thread->pid, (u64)bwr.write_consumed, (u64)bwr.write_size, (u64)bwr.read_consumed, (u64)bwr.read_size); - if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) { + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto out; } @@ -3339,14 +4776,43 @@ out: return ret; } -static int binder_ioctl_set_ctx_mgr(struct file *filp) +static int binder_ioctl_set_inherit_fifo_prio(struct file *filp) { int ret = 0; struct binder_proc *proc = filp->private_data; struct binder_context *context = proc->context; + kuid_t curr_euid = current_euid(); + mutex_lock(&context->context_mgr_node_lock); + + if (uid_valid(context->binder_context_mgr_uid)) { + if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) { + pr_err("BINDER_SET_INHERIT_FIFO_PRIO bad uid %d != %d\n", + from_kuid(&init_user_ns, curr_euid), + from_kuid(&init_user_ns, + context->binder_context_mgr_uid)); + ret = -EPERM; + goto out; + } + } + + context->inherit_fifo_prio = true; + + out: + mutex_unlock(&context->context_mgr_node_lock); + return ret; +} + +static int binder_ioctl_set_ctx_mgr(struct file *filp, + struct flat_binder_object *fbo) +{ + int ret = 0; + struct binder_proc *proc = filp->private_data; + struct binder_context *context = proc->context; + struct binder_node *new_node; kuid_t curr_euid = current_euid(); + mutex_lock(&context->context_mgr_node_lock); if (context->binder_context_mgr_node) { pr_err("BINDER_SET_CONTEXT_MGR already set\n"); ret = -EBUSY; @@ -3367,24 +4833,88 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) } else { context->binder_context_mgr_uid = curr_euid; } - context->binder_context_mgr_node = binder_new_node(proc, 0, 0); - if (!context->binder_context_mgr_node) { - ret = -ENOMEM; - goto out; + new_node = binder_new_node(proc, fbo); + if (!new_node) { + ret = -ENOMEM; + goto out; + } + binder_node_lock(new_node); + new_node->local_weak_refs++; + new_node->local_strong_refs++; + new_node->has_strong_ref = 1; + new_node->has_weak_ref = 1; + context->binder_context_mgr_node = new_node; + binder_node_unlock(new_node); + binder_put_node(new_node); +out: + mutex_unlock(&context->context_mgr_node_lock); + return ret; +} + +static int binder_ioctl_get_node_info_for_ref(struct binder_proc *proc, + struct binder_node_info_for_ref *info) +{ + struct binder_node *node; + struct binder_context *context = proc->context; + __u32 handle = info->handle; + + if (info->strong_count || info->weak_count || info->reserved1 || + info->reserved2 || info->reserved3) { + binder_user_error("%d BINDER_GET_NODE_INFO_FOR_REF: only handle may be non-zero.", + proc->pid); + return -EINVAL; + } + + /* This ioctl may only be used by the context manager */ + mutex_lock(&context->context_mgr_node_lock); + if (!context->binder_context_mgr_node || + context->binder_context_mgr_node->proc != proc) { + mutex_unlock(&context->context_mgr_node_lock); + return -EPERM; } - context->binder_context_mgr_node->local_weak_refs++; - context->binder_context_mgr_node->local_strong_refs++; - context->binder_context_mgr_node->has_strong_ref = 1; - context->binder_context_mgr_node->has_weak_ref = 1; -out: - return ret; + mutex_unlock(&context->context_mgr_node_lock); + + node = binder_get_node_from_ref(proc, handle, true, NULL); + if (!node) + return -EINVAL; + + info->strong_count = node->local_strong_refs + + node->internal_strong_refs; + info->weak_count = node->local_weak_refs; + + binder_put_node(node); + + return 0; +} + +static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, + struct binder_node_debug_info *info) { + struct rb_node *n; + binder_uintptr_t ptr = info->ptr; + + memset(info, 0, sizeof(*info)); + + binder_inner_proc_lock(proc); + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { + struct binder_node *node = rb_entry(n, struct binder_node, + rb_node); + if (node->ptr > ptr) { + info->ptr = node->ptr; + info->cookie = node->cookie; + info->has_strong_ref = node->has_strong_ref; + info->has_weak_ref = node->has_weak_ref; + break; + } + } + binder_inner_proc_unlock(proc); + + return 0; } static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; struct binder_proc *proc = filp->private_data; - struct binder_context *context = proc->context; struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg; @@ -3392,13 +4922,14 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /*pr_info("binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/ + binder_selftest_alloc(&proc->alloc); + trace_binder_ioctl(cmd, arg); ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret) goto err_unlocked; - binder_lock(context, __func__); thread = binder_get_thread(proc); if (thread == NULL) { ret = -ENOMEM; @@ -3411,21 +4942,46 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (ret) goto err; break; - case BINDER_SET_MAX_THREADS: - if (copy_from_user_preempt_disabled(&proc->max_threads, ubuf, sizeof(proc->max_threads))) { + case BINDER_SET_MAX_THREADS: { + int max_threads; + + if (copy_from_user(&max_threads, ubuf, + sizeof(max_threads))) { + ret = -EINVAL; + goto err; + } + binder_inner_proc_lock(proc); + proc->max_threads = max_threads; + binder_inner_proc_unlock(proc); + break; + } + case BINDER_SET_CONTEXT_MGR_EXT: { + struct flat_binder_object fbo; + + if (copy_from_user(&fbo, ubuf, sizeof(fbo))) { ret = -EINVAL; goto err; } + ret = binder_ioctl_set_ctx_mgr(filp, &fbo); + if (ret) + goto err; break; + } case BINDER_SET_CONTEXT_MGR: - ret = binder_ioctl_set_ctx_mgr(filp); + ret = binder_ioctl_set_ctx_mgr(filp, NULL); + if (ret) + goto err; + break; + case BINDER_SET_INHERIT_FIFO_PRIO: + ret = binder_ioctl_set_inherit_fifo_prio(filp); if (ret) goto err; break; + case BINDER_THREAD_EXIT: binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n", proc->pid, thread->pid); - binder_free_thread(proc, thread); + binder_thread_release(proc, thread); thread = NULL; break; case BINDER_VERSION: { @@ -3435,12 +4991,50 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = -EINVAL; goto err; } - if (put_user_preempt_disabled(BINDER_CURRENT_PROTOCOL_VERSION, &ver->protocol_version)) { + if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, + &ver->protocol_version)) { ret = -EINVAL; goto err; } break; } + case BINDER_GET_NODE_INFO_FOR_REF: { + struct binder_node_info_for_ref info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_node_info_for_ref(proc, &info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + break; + } + case BINDER_GET_NODE_DEBUG_INFO: { + struct binder_node_debug_info info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_node_debug_info(proc, &info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; + goto err; + } + break; + } default: ret = -EINVAL; goto err; @@ -3448,8 +5042,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = 0; err: if (thread) - thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; - binder_unlock(context, __func__); + thread->looper_need_return = false; wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret && ret != -ERESTARTSYS) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); @@ -3478,8 +5071,7 @@ static void binder_vma_close(struct vm_area_struct *vma) proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); - proc->vma = NULL; - proc->vma_vm_mm = NULL; + binder_alloc_vma_close(&proc->alloc); binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); } @@ -3488,7 +5080,7 @@ static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } -static struct vm_operations_struct binder_vm_ops = { +static const struct vm_operations_struct binder_vm_ops = { .open = binder_vma_open, .close = binder_vma_close, .fault = binder_vm_fault, @@ -3497,11 +5089,8 @@ static struct vm_operations_struct binder_vm_ops = { static int binder_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; - - struct vm_struct *area; struct binder_proc *proc = filp->private_data; const char *failure_string; - struct binder_buffer *buffer; if (proc->tsk != current->group_leader) return -EINVAL; @@ -3510,8 +5099,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_end = vma->vm_start + SZ_4M; binder_debug(BINDER_DEBUG_OPEN_CLOSE, - "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", - proc->pid, vma->vm_start, vma->vm_end, + "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", + __func__, proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); @@ -3520,95 +5109,22 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) failure_string = "bad vm_flags"; goto err_bad_arg; } - vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; - - mutex_lock(&proc->context->binder_mmap_lock); - if (proc->buffer) { - ret = -EBUSY; - failure_string = "already mapped"; - goto err_already_mapped; - } - - area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); - if (area == NULL) { - ret = -ENOMEM; - failure_string = "get_vm_area"; - goto err_get_vm_area_failed; - } - proc->buffer = area->addr; - proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; - mutex_unlock(&proc->context->binder_mmap_lock); - -#ifdef CONFIG_CPU_CACHE_VIPT - if (cache_is_vipt_aliasing()) { - while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { - pr_info("binder_mmap: %d %lx-%lx maps %pK bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); - vma->vm_start += PAGE_SIZE; - } - } -#endif - if (vma->vm_end - vma->vm_start < BINDER_MIN_ALLOC) { - ret = -EINVAL; - failure_string = "VMA size < BINDER_MIN_ALLOC"; - goto err_vma_too_small; - } - proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL); - if (proc->pages == NULL) { - ret = -ENOMEM; - failure_string = "alloc page array"; - goto err_alloc_pages_failed; - } - proc->buffer_size = vma->vm_end - vma->vm_start; + vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP; + vma->vm_flags &= ~VM_MAYWRITE; vma->vm_ops = &binder_vm_ops; vma->vm_private_data = proc; - buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - failure_string = "alloc buffer struct"; - goto err_alloc_buf_struct_failed; - } - - /* binder_update_page_range assumes preemption is disabled */ - preempt_disable(); - ret = __binder_update_page_range(proc, 1, proc->buffer, - proc->buffer + BINDER_MIN_ALLOC, vma); - preempt_enable_no_resched(); - if (ret) { - ret = -ENOMEM; - failure_string = "alloc small buf"; - goto err_alloc_small_buf_failed; - } - buffer->data = proc->buffer; - list_add(&buffer->entry, &proc->buffers); - buffer->free = 1; - binder_insert_free_buffer(proc, buffer); - proc->free_async_space = proc->buffer_size / 2; - barrier(); + ret = binder_alloc_mmap_handler(&proc->alloc, vma); + if (ret) + return ret; + mutex_lock(&proc->files_lock); proc->files = get_files_struct(current); - proc->vma = vma; - proc->vma_vm_mm = vma->vm_mm; - - /*pr_info("binder_mmap: %d %lx-%lx maps %pK\n", - proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ + mutex_unlock(&proc->files_lock); return 0; -err_alloc_small_buf_failed: - kfree(buffer); -err_alloc_buf_struct_failed: - kfree(proc->pages); - proc->pages = NULL; -err_alloc_pages_failed: -err_vma_too_small: - mutex_lock(&proc->context->binder_mmap_lock); - vfree(proc->buffer); - proc->buffer = NULL; -err_get_vm_area_failed: -err_already_mapped: - mutex_unlock(&proc->context->binder_mmap_lock); err_bad_arg: - pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", + pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; } @@ -3618,31 +5134,41 @@ static int binder_open(struct inode *nodp, struct file *filp) struct binder_proc *proc; struct binder_device *binder_dev; - binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", + binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__, current->group_leader->pid, current->pid); proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) return -ENOMEM; + spin_lock_init(&proc->inner_lock); + spin_lock_init(&proc->outer_lock); + atomic_set(&proc->tmp_ref, 0); get_task_struct(current->group_leader); proc->tsk = current->group_leader; + mutex_init(&proc->files_lock); INIT_LIST_HEAD(&proc->todo); - init_waitqueue_head(&proc->wait); - proc->default_priority = task_nice(current); - INIT_LIST_HEAD(&proc->buffers); + if (binder_supported_policy(current->policy)) { + proc->default_priority.sched_policy = current->policy; + proc->default_priority.prio = current->normal_prio; + } else { + proc->default_priority.sched_policy = SCHED_NORMAL; + proc->default_priority.prio = NICE_TO_PRIO(0); + } + binder_dev = container_of(filp->private_data, struct binder_device, miscdev); proc->context = &binder_dev->context; - - binder_lock(proc->context, __func__); + binder_alloc_init(&proc->alloc); binder_stats_created(BINDER_STAT_PROC); - hlist_add_head(&proc->proc_node, &proc->context->binder_procs); proc->pid = current->group_leader->pid; INIT_LIST_HEAD(&proc->delivered_death); + INIT_LIST_HEAD(&proc->waiting_threads); filp->private_data = proc; - binder_unlock(proc->context, __func__); + mutex_lock(&binder_procs_lock); + hlist_add_head(&proc->proc_node, &binder_procs); + mutex_unlock(&binder_procs_lock); if (binder_debugfs_dir_entry_proc) { char strbuf[11]; @@ -3655,7 +5181,7 @@ static int binder_open(struct inode *nodp, struct file *filp) * anyway print all contexts that a given PID has, so this * is not a problem. */ - proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, + proc->debugfs_entry = debugfs_create_file(strbuf, 0444, binder_debugfs_dir_entry_proc, (void *)(unsigned long)proc->pid, &binder_proc_fops); @@ -3678,16 +5204,17 @@ static void binder_deferred_flush(struct binder_proc *proc) struct rb_node *n; int wake_count = 0; + binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); - thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; + thread->looper_need_return = true; if (thread->looper & BINDER_LOOPER_STATE_WAITING) { wake_up_interruptible(&thread->wait); wake_count++; } } - wake_up_interruptible_all(&proc->wait); + binder_inner_proc_unlock(proc); binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_flush: %d woke %d threads\n", proc->pid, @@ -3707,15 +5234,22 @@ static int binder_release(struct inode *nodp, struct file *filp) static int binder_node_release(struct binder_node *node, int refs) { struct binder_ref *ref; - struct binder_context *context = node->proc->context; int death = 0; + struct binder_proc *proc = node->proc; - list_del_init(&node->work.entry); - binder_release_work(&node->async_todo); + binder_release_work(proc, &node->async_todo); - if (hlist_empty(&node->refs)) { - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); + binder_node_lock(node); + binder_inner_proc_lock(proc); + binder_dequeue_work_ilocked(&node->work); + /* + * The caller must have taken a temporary ref on the node, + */ + BUG_ON(!node->tmp_refs); + if (hlist_empty(&node->refs) && node->tmp_refs == 1) { + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + binder_free_node(node); return refs; } @@ -3723,46 +5257,58 @@ static int binder_node_release(struct binder_node *node, int refs) node->proc = NULL; node->local_strong_refs = 0; node->local_weak_refs = 0; - hlist_add_head(&node->dead_node, &context->binder_dead_nodes); + binder_inner_proc_unlock(proc); + + spin_lock(&binder_dead_nodes_lock); + hlist_add_head(&node->dead_node, &binder_dead_nodes); + spin_unlock(&binder_dead_nodes_lock); hlist_for_each_entry(ref, &node->refs, node_entry) { refs++; - - if (!ref->death) + /* + * Need the node lock to synchronize + * with new notification requests and the + * inner lock to synchronize with queued + * death notifications. + */ + binder_inner_proc_lock(ref->proc); + if (!ref->death) { + binder_inner_proc_unlock(ref->proc); continue; + } death++; - if (list_empty(&ref->death->work.entry)) { - ref->death->work.type = BINDER_WORK_DEAD_BINDER; - list_add_tail(&ref->death->work.entry, - &ref->proc->todo); - wake_up_interruptible(&ref->proc->wait); - } else - BUG(); + BUG_ON(!list_empty(&ref->death->work.entry)); + ref->death->work.type = BINDER_WORK_DEAD_BINDER; + binder_enqueue_work_ilocked(&ref->death->work, + &ref->proc->todo); + binder_wakeup_proc_ilocked(ref->proc); + binder_inner_proc_unlock(ref->proc); } binder_debug(BINDER_DEBUG_DEAD_BINDER, "node %d now dead, refs %d, death %d\n", node->debug_id, refs, death); + binder_node_unlock(node); + binder_put_node(node); return refs; } static void binder_deferred_release(struct binder_proc *proc) { - struct binder_transaction *t; struct binder_context *context = proc->context; struct rb_node *n; - struct binder_buffer *buffer; - int threads, nodes, incoming_refs, outgoing_refs, buffers, - active_transactions, page_count; + int threads, nodes, incoming_refs, outgoing_refs, active_transactions; - BUG_ON(proc->vma); BUG_ON(proc->files); + mutex_lock(&binder_procs_lock); hlist_del(&proc->proc_node); + mutex_unlock(&binder_procs_lock); + mutex_lock(&context->context_mgr_node_lock); if (context->binder_context_mgr_node && context->binder_context_mgr_node->proc == proc) { binder_debug(BINDER_DEBUG_DEAD_BINDER, @@ -3770,15 +5316,25 @@ static void binder_deferred_release(struct binder_proc *proc) __func__, proc->pid); context->binder_context_mgr_node = NULL; } + mutex_unlock(&context->context_mgr_node_lock); + binder_inner_proc_lock(proc); + /* + * Make sure proc stays alive after we + * remove all the threads + */ + atomic_inc(&proc->tmp_ref); + proc->is_dead = true; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { struct binder_thread *thread; thread = rb_entry(n, struct binder_thread, rb_node); + binder_inner_proc_unlock(proc); threads++; - active_transactions += binder_free_thread(proc, thread); + active_transactions += binder_thread_release(proc, thread); + binder_inner_proc_lock(proc); } nodes = 0; @@ -3788,104 +5344,56 @@ static void binder_deferred_release(struct binder_proc *proc) node = rb_entry(n, struct binder_node, rb_node); nodes++; + /* + * take a temporary ref on the node before + * calling binder_node_release() which will either + * kfree() the node or call binder_put_node() + */ + binder_inc_node_tmpref_ilocked(node); rb_erase(&node->rb_node, &proc->nodes); - incoming_refs = binder_node_release(node, - incoming_refs); + binder_inner_proc_unlock(proc); + incoming_refs = binder_node_release(node, incoming_refs); + binder_inner_proc_lock(proc); } + binder_inner_proc_unlock(proc); outgoing_refs = 0; + binder_proc_lock(proc); while ((n = rb_first(&proc->refs_by_desc))) { struct binder_ref *ref; ref = rb_entry(n, struct binder_ref, rb_node_desc); outgoing_refs++; - binder_delete_ref(ref); - } - - binder_release_work(&proc->todo); - binder_release_work(&proc->delivered_death); - - buffers = 0; - while ((n = rb_first(&proc->allocated_buffers))) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - - t = buffer->transaction; - if (t) { - t->buffer = NULL; - buffer->transaction = NULL; - pr_err("release proc %d, transaction %d, not freed\n", - proc->pid, t->debug_id); - /*BUG();*/ - } - - binder_free_buf(proc, buffer); - buffers++; - } - - binder_stats_deleted(BINDER_STAT_PROC); - - while (!list_empty(&proc->buffers)) { - buffer = list_first_entry(&proc->buffers, - struct binder_buffer, entry); - WARN_ON(!buffer->free); - - list_del(&buffer->entry); - WARN_ON_ONCE(!list_empty(&proc->buffers)); - kfree(buffer); + binder_cleanup_ref_olocked(ref); + binder_proc_unlock(proc); + binder_free_ref(ref); + binder_proc_lock(proc); } + binder_proc_unlock(proc); - page_count = 0; - if (proc->pages) { - int i; - - for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { - void *page_addr; - - if (!proc->pages[i]) - continue; - - page_addr = proc->buffer + i * PAGE_SIZE; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%s: %d: page %d at %pK not freed\n", - __func__, proc->pid, i, page_addr); - unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); - __free_page(proc->pages[i]); - page_count++; - } - kfree(proc->pages); - vfree(proc->buffer); - } - - put_task_struct(proc->tsk); + binder_release_work(proc, &proc->todo); + binder_release_work(proc, &proc->delivered_death); binder_debug(BINDER_DEBUG_OPEN_CLOSE, - "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n", + "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d\n", __func__, proc->pid, threads, nodes, incoming_refs, - outgoing_refs, active_transactions, buffers, page_count); + outgoing_refs, active_transactions); - kfree(proc); + binder_proc_dec_tmpref(proc); } static void binder_deferred_func(struct work_struct *work) { struct binder_proc *proc; struct files_struct *files; - struct binder_context *context = - container_of(work, struct binder_context, deferred_work); int defer; do { - trace_binder_lock(__func__); - mutex_lock(&context->binder_main_lock); - trace_binder_locked(__func__); - - mutex_lock(&context->binder_deferred_lock); - preempt_disable(); - if (!hlist_empty(&context->binder_deferred_list)) { - proc = hlist_entry(context->binder_deferred_list.first, - struct binder_proc, - deferred_work_node); + mutex_lock(&binder_deferred_lock); + if (!hlist_empty(&binder_deferred_list)) { + proc = hlist_entry(binder_deferred_list.first, + struct binder_proc, deferred_work_node); hlist_del_init(&proc->deferred_work_node); defer = proc->deferred_work; proc->deferred_work = 0; @@ -3893,13 +5401,15 @@ static void binder_deferred_func(struct work_struct *work) proc = NULL; defer = 0; } - mutex_unlock(&context->binder_deferred_lock); + mutex_unlock(&binder_deferred_lock); files = NULL; if (defer & BINDER_DEFERRED_PUT_FILES) { + mutex_lock(&proc->files_lock); files = proc->files; if (files) proc->files = NULL; + mutex_unlock(&proc->files_lock); } if (defer & BINDER_DEFERRED_FLUSH) @@ -3908,63 +5418,71 @@ static void binder_deferred_func(struct work_struct *work) if (defer & BINDER_DEFERRED_RELEASE) binder_deferred_release(proc); /* frees proc */ - trace_binder_unlock(__func__); - mutex_unlock(&context->binder_main_lock); - preempt_enable_no_resched(); if (files) put_files_struct(files); } while (proc); } +static DECLARE_WORK(binder_deferred_work, binder_deferred_func); static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) { - mutex_lock(&proc->context->binder_deferred_lock); + mutex_lock(&binder_deferred_lock); proc->deferred_work |= defer; if (hlist_unhashed(&proc->deferred_work_node)) { hlist_add_head(&proc->deferred_work_node, - &proc->context->binder_deferred_list); - queue_work(proc->context->binder_deferred_workqueue, - &proc->context->deferred_work); + &binder_deferred_list); + queue_work(binder_deferred_workqueue, &binder_deferred_work); } - mutex_unlock(&proc->context->binder_deferred_lock); + mutex_unlock(&binder_deferred_lock); } -static void print_binder_transaction(struct seq_file *m, const char *prefix, - struct binder_transaction *t) +static void print_binder_transaction_ilocked(struct seq_file *m, + struct binder_proc *proc, + const char *prefix, + struct binder_transaction *t) { + struct binder_proc *to_proc; + struct binder_buffer *buffer = t->buffer; + + spin_lock(&t->lock); + to_proc = t->to_proc; seq_printf(m, - "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d", + "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %d:%d r%d", prefix, t->debug_id, t, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, - t->to_proc ? t->to_proc->pid : 0, + to_proc ? to_proc->pid : 0, t->to_thread ? t->to_thread->pid : 0, - t->code, t->flags, t->priority, t->need_reply); - if (t->buffer == NULL) { + t->code, t->flags, t->priority.sched_policy, + t->priority.prio, t->need_reply); + spin_unlock(&t->lock); + + if (proc != to_proc) { + /* + * Can only safely deref buffer if we are holding the + * correct proc inner lock for this node + */ + seq_puts(m, "\n"); + return; + } + + if (buffer == NULL) { seq_puts(m, " buffer free\n"); return; } - if (t->buffer->target_node) - seq_printf(m, " node %d", - t->buffer->target_node->debug_id); + if (buffer->target_node) + seq_printf(m, " node %d", buffer->target_node->debug_id); seq_printf(m, " size %zd:%zd data %pK\n", - t->buffer->data_size, t->buffer->offsets_size, - t->buffer->data); -} - -static void print_binder_buffer(struct seq_file *m, const char *prefix, - struct binder_buffer *buffer) -{ - seq_printf(m, "%s %d: %pK size %zd:%zd %s\n", - prefix, buffer->debug_id, buffer->data, buffer->data_size, buffer->offsets_size, - buffer->transaction ? "active" : "delivered"); + buffer->data); } -static void print_binder_work(struct seq_file *m, const char *prefix, - const char *transaction_prefix, - struct binder_work *w) +static void print_binder_work_ilocked(struct seq_file *m, + struct binder_proc *proc, + const char *prefix, + const char *transaction_prefix, + struct binder_work *w) { struct binder_node *node; struct binder_transaction *t; @@ -3972,8 +5490,16 @@ static void print_binder_work(struct seq_file *m, const char *prefix, switch (w->type) { case BINDER_WORK_TRANSACTION: t = container_of(w, struct binder_transaction, work); - print_binder_transaction(m, transaction_prefix, t); + print_binder_transaction_ilocked( + m, proc, transaction_prefix, t); break; + case BINDER_WORK_RETURN_ERROR: { + struct binder_error *e = container_of( + w, struct binder_error, work); + + seq_printf(m, "%stransaction error: %u\n", + prefix, e->cmd); + } break; case BINDER_WORK_TRANSACTION_COMPLETE: seq_printf(m, "%stransaction complete\n", prefix); break; @@ -3998,40 +5524,46 @@ static void print_binder_work(struct seq_file *m, const char *prefix, } } -static void print_binder_thread(struct seq_file *m, - struct binder_thread *thread, - int print_always) +static void print_binder_thread_ilocked(struct seq_file *m, + struct binder_thread *thread, + int print_always) { struct binder_transaction *t; struct binder_work *w; size_t start_pos = m->count; size_t header_pos; - seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper); + seq_printf(m, " thread %d: l %02x need_return %d tr %d\n", + thread->pid, thread->looper, + thread->looper_need_return, + atomic_read(&thread->tmp_ref)); header_pos = m->count; t = thread->transaction_stack; while (t) { if (t->from == thread) { - print_binder_transaction(m, - " outgoing transaction", t); + print_binder_transaction_ilocked(m, thread->proc, + " outgoing transaction", t); t = t->from_parent; } else if (t->to_thread == thread) { - print_binder_transaction(m, + print_binder_transaction_ilocked(m, thread->proc, " incoming transaction", t); t = t->to_parent; } else { - print_binder_transaction(m, " bad transaction", t); + print_binder_transaction_ilocked(m, thread->proc, + " bad transaction", t); t = NULL; } } list_for_each_entry(w, &thread->todo, entry) { - print_binder_work(m, " ", " pending transaction", w); + print_binder_work_ilocked(m, thread->proc, " ", + " pending transaction", w); } if (!print_always && m->count == header_pos) m->count = start_pos; } -static void print_binder_node(struct seq_file *m, struct binder_node *node) +static void print_binder_node_nilocked(struct seq_file *m, + struct binder_node *node) { struct binder_ref *ref; struct binder_work *w; @@ -4041,27 +5573,35 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) hlist_for_each_entry(ref, &node->refs, node_entry) count++; - seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", + seq_printf(m, " node %d: u%016llx c%016llx pri %d:%d hs %d hw %d ls %d lw %d is %d iw %d tr %d", node->debug_id, (u64)node->ptr, (u64)node->cookie, + node->sched_policy, node->min_priority, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, - node->internal_strong_refs, count); + node->internal_strong_refs, count, node->tmp_refs); if (count) { seq_puts(m, " proc"); hlist_for_each_entry(ref, &node->refs, node_entry) seq_printf(m, " %d", ref->proc->pid); } seq_puts(m, "\n"); - list_for_each_entry(w, &node->async_todo, entry) - print_binder_work(m, " ", - " pending async transaction", w); + if (node->proc) { + list_for_each_entry(w, &node->async_todo, entry) + print_binder_work_ilocked(m, node->proc, " ", + " pending async transaction", w); + } } -static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) +static void print_binder_ref_olocked(struct seq_file *m, + struct binder_ref *ref) { + binder_node_lock(ref->node); seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %pK\n", - ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", - ref->node->debug_id, ref->strong, ref->weak, ref->death); + ref->data.debug_id, ref->data.desc, + ref->node->proc ? "" : "dead ", + ref->node->debug_id, ref->data.strong, + ref->data.weak, ref->death); + binder_node_unlock(ref->node); } static void print_binder_proc(struct seq_file *m, @@ -4071,36 +5611,63 @@ static void print_binder_proc(struct seq_file *m, struct rb_node *n; size_t start_pos = m->count; size_t header_pos; + struct binder_node *last_node = NULL; seq_printf(m, "proc %d\n", proc->pid); seq_printf(m, "context %s\n", proc->context->name); header_pos = m->count; + binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) - print_binder_thread(m, rb_entry(n, struct binder_thread, + print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread, rb_node), print_all); + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { struct binder_node *node = rb_entry(n, struct binder_node, rb_node); - if (print_all || node->has_async_transaction) - print_binder_node(m, node); - } + if (!print_all && !node->has_async_transaction) + continue; + + /* + * take a temporary reference on the node so it + * survives and isn't removed from the tree + * while we print it. + */ + binder_inc_node_tmpref_ilocked(node); + /* Need to drop inner lock to take node lock */ + binder_inner_proc_unlock(proc); + if (last_node) + binder_put_node(last_node); + binder_node_inner_lock(node); + print_binder_node_nilocked(m, node); + binder_node_inner_unlock(node); + last_node = node; + binder_inner_proc_lock(proc); + } + binder_inner_proc_unlock(proc); + if (last_node) + binder_put_node(last_node); + if (print_all) { + binder_proc_lock(proc); for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) - print_binder_ref(m, rb_entry(n, struct binder_ref, - rb_node_desc)); + print_binder_ref_olocked(m, rb_entry(n, + struct binder_ref, + rb_node_desc)); + binder_proc_unlock(proc); } - for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) - print_binder_buffer(m, " buffer", - rb_entry(n, struct binder_buffer, rb_node)); + binder_alloc_print_allocated(m, &proc->alloc); + binder_inner_proc_lock(proc); list_for_each_entry(w, &proc->todo, entry) - print_binder_work(m, " ", " pending transaction", w); + print_binder_work_ilocked(m, proc, " ", + " pending transaction", w); list_for_each_entry(w, &proc->delivered_death, entry) { seq_puts(m, " has delivered dead binder\n"); break; } + binder_inner_proc_unlock(proc); if (!print_all && m->count == header_pos) m->count = start_pos; } @@ -4158,54 +5725,45 @@ static const char * const binder_objstat_strings[] = { "transaction_complete" }; -static void add_binder_stats(struct binder_stats *from, struct binder_stats *to) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(to->bc); i++) - to->bc[i] += from->bc[i]; - - for (i = 0; i < ARRAY_SIZE(to->br); i++) - to->br[i] += from->br[i]; -} - static void print_binder_stats(struct seq_file *m, const char *prefix, - struct binder_stats *stats, - struct binder_obj_stats *obj_stats) + struct binder_stats *stats) { int i; BUILD_BUG_ON(ARRAY_SIZE(stats->bc) != ARRAY_SIZE(binder_command_strings)); for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { - if (stats->bc[i]) + int temp = atomic_read(&stats->bc[i]); + + if (temp) seq_printf(m, "%s%s: %d\n", prefix, - binder_command_strings[i], stats->bc[i]); + binder_command_strings[i], temp); } BUILD_BUG_ON(ARRAY_SIZE(stats->br) != ARRAY_SIZE(binder_return_strings)); for (i = 0; i < ARRAY_SIZE(stats->br); i++) { - if (stats->br[i]) + int temp = atomic_read(&stats->br[i]); + + if (temp) seq_printf(m, "%s%s: %d\n", prefix, - binder_return_strings[i], stats->br[i]); + binder_return_strings[i], temp); } - if (!obj_stats) - return; - - BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) != + BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != ARRAY_SIZE(binder_objstat_strings)); - BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) != - ARRAY_SIZE(obj_stats->obj_deleted)); - for (i = 0; i < ARRAY_SIZE(obj_stats->obj_created); i++) { - int obj_created = atomic_read(&obj_stats->obj_created[i]); - int obj_deleted = atomic_read(&obj_stats->obj_deleted[i]); - - if (obj_created || obj_deleted) - seq_printf(m, "%s%s: active %d total %d\n", prefix, - binder_objstat_strings[i], - obj_created - obj_deleted, obj_created); + BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != + ARRAY_SIZE(stats->obj_deleted)); + for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { + int created = atomic_read(&stats->obj_created[i]); + int deleted = atomic_read(&stats->obj_deleted[i]); + + if (created || deleted) + seq_printf(m, "%s%s: active %d total %d\n", + prefix, + binder_objstat_strings[i], + created - deleted, + created); } } @@ -4213,226 +5771,194 @@ static void print_binder_proc_stats(struct seq_file *m, struct binder_proc *proc) { struct binder_work *w; + struct binder_thread *thread; struct rb_node *n; - int count, strong, weak; + int count, strong, weak, ready_threads; + size_t free_async_space = + binder_alloc_get_free_async_space(&proc->alloc); seq_printf(m, "proc %d\n", proc->pid); seq_printf(m, "context %s\n", proc->context->name); + seq_printf(m, "context FIFO: %d\n", proc->context->inherit_fifo_prio); count = 0; + ready_threads = 0; + binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) count++; + + list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node) + ready_threads++; + seq_printf(m, " threads: %d\n", count); seq_printf(m, " requested threads: %d+%d/%d\n" " ready threads %d\n" " free async space %zd\n", proc->requested_threads, proc->requested_threads_started, proc->max_threads, - proc->ready_threads, proc->free_async_space); + ready_threads, + free_async_space); count = 0; for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) count++; + binder_inner_proc_unlock(proc); seq_printf(m, " nodes: %d\n", count); count = 0; strong = 0; weak = 0; + binder_proc_lock(proc); for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { struct binder_ref *ref = rb_entry(n, struct binder_ref, rb_node_desc); count++; - strong += ref->strong; - weak += ref->weak; + strong += ref->data.strong; + weak += ref->data.weak; } + binder_proc_unlock(proc); seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak); - count = 0; - for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) - count++; + count = binder_alloc_get_allocated_count(&proc->alloc); seq_printf(m, " buffers: %d\n", count); count = 0; + binder_inner_proc_lock(proc); list_for_each_entry(w, &proc->todo, entry) { - switch (w->type) { - case BINDER_WORK_TRANSACTION: + if (w->type == BINDER_WORK_TRANSACTION) count++; - break; - default: - break; - } } + binder_inner_proc_unlock(proc); seq_printf(m, " pending transactions: %d\n", count); - print_binder_stats(m, " ", &proc->stats, NULL); + print_binder_stats(m, " ", &proc->stats); } static int binder_state_show(struct seq_file *m, void *unused) { - struct binder_device *device; - struct binder_context *context; struct binder_proc *proc; struct binder_node *node; - int do_lock = !binder_debug_no_lock; - bool wrote_dead_nodes_header = false; + struct binder_node *last_node = NULL; seq_puts(m, "binder state:\n"); - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); - if (!wrote_dead_nodes_header && - !hlist_empty(&context->binder_dead_nodes)) { - seq_puts(m, "dead nodes:\n"); - wrote_dead_nodes_header = true; - } - hlist_for_each_entry(node, &context->binder_dead_nodes, - dead_node) - print_binder_node(m, node); - - if (do_lock) - binder_unlock(context, __func__); - } - - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); + spin_lock(&binder_dead_nodes_lock); + if (!hlist_empty(&binder_dead_nodes)) + seq_puts(m, "dead nodes:\n"); + hlist_for_each_entry(node, &binder_dead_nodes, dead_node) { + /* + * take a temporary reference on the node so it + * survives and isn't removed from the list + * while we print it. + */ + node->tmp_refs++; + spin_unlock(&binder_dead_nodes_lock); + if (last_node) + binder_put_node(last_node); + binder_node_lock(node); + print_binder_node_nilocked(m, node); + binder_node_unlock(node); + last_node = node; + spin_lock(&binder_dead_nodes_lock); + } + spin_unlock(&binder_dead_nodes_lock); + if (last_node) + binder_put_node(last_node); + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc(m, proc, 1); + mutex_unlock(&binder_procs_lock); - hlist_for_each_entry(proc, &context->binder_procs, proc_node) - print_binder_proc(m, proc, 1); - if (do_lock) - binder_unlock(context, __func__); - } return 0; } static int binder_stats_show(struct seq_file *m, void *unused) { - struct binder_device *device; - struct binder_context *context; struct binder_proc *proc; - struct binder_stats total_binder_stats; - int do_lock = !binder_debug_no_lock; - - memset(&total_binder_stats, 0, sizeof(struct binder_stats)); - - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); - - add_binder_stats(&context->binder_stats, &total_binder_stats); - - if (do_lock) - binder_unlock(context, __func__); - } seq_puts(m, "binder stats:\n"); - print_binder_stats(m, "", &total_binder_stats, &binder_obj_stats); - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); + print_binder_stats(m, "", &binder_stats); + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc_stats(m, proc); + mutex_unlock(&binder_procs_lock); - hlist_for_each_entry(proc, &context->binder_procs, proc_node) - print_binder_proc_stats(m, proc); - if (do_lock) - binder_unlock(context, __func__); - } return 0; } static int binder_transactions_show(struct seq_file *m, void *unused) { - struct binder_device *device; - struct binder_context *context; struct binder_proc *proc; - int do_lock = !binder_debug_no_lock; seq_puts(m, "binder transactions:\n"); - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc(m, proc, 0); + mutex_unlock(&binder_procs_lock); - hlist_for_each_entry(proc, &context->binder_procs, proc_node) - print_binder_proc(m, proc, 0); - if (do_lock) - binder_unlock(context, __func__); - } return 0; } static int binder_proc_show(struct seq_file *m, void *unused) { - struct binder_device *device; - struct binder_context *context; struct binder_proc *itr; int pid = (unsigned long)m->private; - int do_lock = !binder_debug_no_lock; - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); - - hlist_for_each_entry(itr, &context->binder_procs, proc_node) { - if (itr->pid == pid) { - seq_puts(m, "binder proc state:\n"); - print_binder_proc(m, itr, 1); - } + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(itr, &binder_procs, proc_node) { + if (itr->pid == pid) { + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, itr, 1); } - if (do_lock) - binder_unlock(context, __func__); } + mutex_unlock(&binder_procs_lock); + return 0; } static void print_binder_transaction_log_entry(struct seq_file *m, struct binder_transaction_log_entry *e) { + int debug_id = READ_ONCE(e->debug_id_done); + /* + * read barrier to guarantee debug_id_done read before + * we print the log values + */ + smp_rmb(); seq_printf(m, - "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d\n", + "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d ret %d/%d l=%d", e->debug_id, (e->call_type == 2) ? "reply" : ((e->call_type == 1) ? "async" : "call "), e->from_proc, e->from_thread, e->to_proc, e->to_thread, e->context_name, - e->to_node, e->target_handle, e->data_size, e->offsets_size); -} - -static int print_binder_transaction_log(struct seq_file *m, - struct binder_transaction_log *log) -{ - int i; - if (log->full) { - for (i = log->next; i < ARRAY_SIZE(log->entry); i++) - print_binder_transaction_log_entry(m, &log->entry[i]); - } - for (i = 0; i < log->next; i++) - print_binder_transaction_log_entry(m, &log->entry[i]); - return 0; + e->to_node, e->target_handle, e->data_size, e->offsets_size, + e->return_error, e->return_error_param, + e->return_error_line); + /* + * read-barrier to guarantee read of debug_id_done after + * done printing the fields of the entry + */ + smp_rmb(); + seq_printf(m, debug_id && debug_id == READ_ONCE(e->debug_id_done) ? + "\n" : " (incomplete)\n"); } static int binder_transaction_log_show(struct seq_file *m, void *unused) { - struct binder_device *device; - struct binder_context *context; - - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - print_binder_transaction_log(m, &context->transaction_log); - } - return 0; -} + struct binder_transaction_log *log = m->private; + unsigned int log_cur = atomic_read(&log->cur); + unsigned int count; + unsigned int cur; + int i; -static int binder_failed_transaction_log_show(struct seq_file *m, void *unused) -{ - struct binder_device *device; - struct binder_context *context; + count = log_cur + 1; + cur = count < ARRAY_SIZE(log->entry) && !log->full ? + 0 : count % ARRAY_SIZE(log->entry); + if (count > ARRAY_SIZE(log->entry) || log->full) + count = ARRAY_SIZE(log->entry); + for (i = 0; i < count; i++) { + unsigned int index = cur++ % ARRAY_SIZE(log->entry); - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - print_binder_transaction_log(m, - &context->transaction_log_failed); + print_binder_transaction_log_entry(m, &log->entry[index]); } return 0; } @@ -4452,20 +5978,11 @@ BINDER_DEBUG_ENTRY(state); BINDER_DEBUG_ENTRY(stats); BINDER_DEBUG_ENTRY(transactions); BINDER_DEBUG_ENTRY(transaction_log); -BINDER_DEBUG_ENTRY(failed_transaction_log); - -static void __init free_binder_device(struct binder_device *device) -{ - if (device->context.binder_deferred_workqueue) - destroy_workqueue(device->context.binder_deferred_workqueue); - kfree(device); -} static int __init init_binder_device(const char *name) { int ret; struct binder_device *binder_device; - struct binder_context *context; binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL); if (!binder_device) @@ -4475,65 +5992,34 @@ static int __init init_binder_device(const char *name) binder_device->miscdev.minor = MISC_DYNAMIC_MINOR; binder_device->miscdev.name = name; - context = &binder_device->context; - context->binder_context_mgr_uid = INVALID_UID; - context->name = name; - - mutex_init(&context->binder_main_lock); - mutex_init(&context->binder_deferred_lock); - mutex_init(&context->binder_mmap_lock); - - context->binder_deferred_workqueue = - create_singlethread_workqueue(name); - - if (!context->binder_deferred_workqueue) { - ret = -ENOMEM; - goto err_create_singlethread_workqueue_failed; - } - - INIT_HLIST_HEAD(&context->binder_procs); - INIT_HLIST_HEAD(&context->binder_dead_nodes); - INIT_HLIST_HEAD(&context->binder_deferred_list); - INIT_WORK(&context->deferred_work, binder_deferred_func); + binder_device->context.binder_context_mgr_uid = INVALID_UID; + binder_device->context.name = name; + mutex_init(&binder_device->context.context_mgr_node_lock); ret = misc_register(&binder_device->miscdev); if (ret < 0) { - goto err_misc_register_failed; + kfree(binder_device); + return ret; } hlist_add_head(&binder_device->hlist, &binder_devices); - return ret; - -err_create_singlethread_workqueue_failed: -err_misc_register_failed: - free_binder_device(binder_device); return ret; } static int __init binder_init(void) { - int ret = 0; - char *device_name, *device_names; + int ret; + char *device_name, *device_names, *device_tmp; struct binder_device *device; struct hlist_node *tmp; - /* - * Copy the module_parameter string, because we don't want to - * tokenize it in-place. - */ - device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); - if (!device_names) + atomic_set(&binder_transaction_log.cur, ~0U); + atomic_set(&binder_transaction_log_failed.cur, ~0U); + binder_deferred_workqueue = create_singlethread_workqueue("binder"); + if (!binder_deferred_workqueue) return -ENOMEM; - strcpy(device_names, binder_devices_param); - - while ((device_name = strsep(&device_names, ","))) { - ret = init_binder_device(device_name); - if (ret) - goto err_init_binder_device_failed; - } - binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); if (binder_debugfs_dir_entry_root) binder_debugfs_dir_entry_proc = debugfs_create_dir("proc", @@ -4541,30 +6027,48 @@ static int __init binder_init(void) if (binder_debugfs_dir_entry_root) { debugfs_create_file("state", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_state_fops); debugfs_create_file("stats", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_stats_fops); debugfs_create_file("transactions", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_transactions_fops); debugfs_create_file("transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, - NULL, + &binder_transaction_log, &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, - NULL, - &binder_failed_transaction_log_fops); + &binder_transaction_log_failed, + &binder_transaction_log_fops); + } + + /* + * Copy the module_parameter string, because we don't want to + * tokenize it in-place. + */ + device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); + if (!device_names) { + ret = -ENOMEM; + goto err_alloc_device_names_failed; + } + strcpy(device_names, binder_devices_param); + + device_tmp = device_names; + while ((device_name = strsep(&device_tmp, ","))) { + ret = init_binder_device(device_name); + if (ret) + goto err_init_binder_device_failed; } return ret; @@ -4573,9 +6077,16 @@ err_init_binder_device_failed: hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) { misc_deregister(&device->miscdev); hlist_del(&device->hlist); - free_binder_device(device); + kfree(device); } + kfree(device_names); + +err_alloc_device_names_failed: + debugfs_remove_recursive(binder_debugfs_dir_entry_root); + + destroy_workqueue(binder_deferred_workqueue); + return ret; } diff --git a/drivers/android/binder.h b/drivers/android/binder.h new file mode 100644 index 000000000000..cb2cb7cf7a15 --- /dev/null +++ b/drivers/android/binder.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008 Google, Inc. + * + * Based on, but no longer compatible with, the original + * OpenBinder.org binder driver interface, which is: + * + * Copyright (c) 2005 Palmsource, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_BINDER_H +#define _LINUX_BINDER_H + +#include + +#endif /* _LINUX_BINDER_H */ + diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c new file mode 100644 index 000000000000..0ea0233fb88d --- /dev/null +++ b/drivers/android/binder_alloc.c @@ -0,0 +1,833 @@ +/* binder_alloc.c + * + * Android IPC Subsystem + * + * Copyright (C) 2007-2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "binder_alloc.h" +#include "binder_trace.h" + +static DEFINE_MUTEX(binder_alloc_mmap_lock); + +enum { + BINDER_DEBUG_OPEN_CLOSE = 1U << 1, + BINDER_DEBUG_BUFFER_ALLOC = 1U << 2, + BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 3, +}; +static uint32_t binder_alloc_debug_mask; + +module_param_named(debug_mask, binder_alloc_debug_mask, + uint, S_IWUSR | S_IRUGO); + +#define binder_alloc_debug(mask, x...) \ + do { \ + if (binder_alloc_debug_mask & mask) \ + pr_info(x); \ + } while (0) + +static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer) +{ + return list_entry(buffer->entry.next, struct binder_buffer, entry); +} + +static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer) +{ + return list_entry(buffer->entry.prev, struct binder_buffer, entry); +} + +static size_t binder_alloc_buffer_size(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + if (list_is_last(&buffer->entry, &alloc->buffers)) + return (u8 *)alloc->buffer + + alloc->buffer_size - (u8 *)buffer->data; + return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data; +} + +static void binder_insert_free_buffer(struct binder_alloc *alloc, + struct binder_buffer *new_buffer) +{ + struct rb_node **p = &alloc->free_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + size_t buffer_size; + size_t new_buffer_size; + + BUG_ON(!new_buffer->free); + + new_buffer_size = binder_alloc_buffer_size(alloc, new_buffer); + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: add free buffer, size %zd, at %pK\n", + alloc->pid, new_buffer_size, new_buffer); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + + buffer_size = binder_alloc_buffer_size(alloc, buffer); + + if (new_buffer_size < buffer_size) + p = &parent->rb_left; + else + p = &parent->rb_right; + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &alloc->free_buffers); +} + +static void binder_insert_allocated_buffer_locked( + struct binder_alloc *alloc, struct binder_buffer *new_buffer) +{ + struct rb_node **p = &alloc->allocated_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + + BUG_ON(new_buffer->free); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (new_buffer->data < buffer->data) + p = &parent->rb_left; + else if (new_buffer->data > buffer->data) + p = &parent->rb_right; + else + BUG(); + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &alloc->allocated_buffers); +} + +static struct binder_buffer *binder_alloc_prepare_to_free_locked( + struct binder_alloc *alloc, + uintptr_t user_ptr) +{ + struct rb_node *n = alloc->allocated_buffers.rb_node; + struct binder_buffer *buffer; + void *kern_ptr; + + kern_ptr = (void *)(user_ptr - alloc->user_buffer_offset); + + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (kern_ptr < buffer->data) + n = n->rb_left; + else if (kern_ptr > buffer->data) + n = n->rb_right; + else { + /* + * Guard against user threads attempting to + * free the buffer when in use by kernel or + * after it's already been freed. + */ + if (!buffer->allow_user_free) + return ERR_PTR(-EPERM); + buffer->allow_user_free = 0; + return buffer; + } + } + return NULL; +} + +/** + * binder_alloc_buffer_lookup() - get buffer given user ptr + * @alloc: binder_alloc for this proc + * @user_ptr: User pointer to buffer data + * + * Validate userspace pointer to buffer data and return buffer corresponding to + * that user pointer. Search the rb tree for buffer that matches user data + * pointer. + * + * Return: Pointer to buffer or NULL + */ +struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc, + uintptr_t user_ptr) +{ + struct binder_buffer *buffer; + + mutex_lock(&alloc->mutex); + buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr); + mutex_unlock(&alloc->mutex); + return buffer; +} + +static int binder_update_page_range(struct binder_alloc *alloc, int allocate, + void *start, void *end, + struct vm_area_struct *vma) +{ + void *page_addr; + unsigned long user_page_addr; + struct page **page; + struct mm_struct *mm; + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: %s pages %pK-%pK\n", alloc->pid, + allocate ? "allocate" : "free", start, end); + + if (end <= start) + return 0; + + trace_binder_update_page_range(alloc, allocate, start, end); + + if (vma) + mm = NULL; + else + mm = get_task_mm(alloc->tsk); + + if (mm) { + down_read(&mm->mmap_sem); + vma = alloc->vma; + if (vma && mm != alloc->vma_vm_mm) { + pr_err("%d: vma mm and task mm mismatch\n", + alloc->pid); + vma = NULL; + } + } + + if (allocate == 0) + goto free_range; + + if (vma == NULL) { + pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", + alloc->pid); + goto err_no_vma; + } + + for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { + int ret; + + page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE]; + + BUG_ON(*page); + *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); + if (*page == NULL) { + pr_err("%d: binder_alloc_buf failed for page at %pK\n", + alloc->pid, page_addr); + goto err_alloc_page_failed; + } + ret = map_kernel_range_noflush((unsigned long)page_addr, + PAGE_SIZE, PAGE_KERNEL, page); + flush_cache_vmap((unsigned long)page_addr, + (unsigned long)page_addr + PAGE_SIZE); + if (ret != 1) { + pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n", + alloc->pid, page_addr); + goto err_map_kernel_failed; + } + user_page_addr = + (uintptr_t)page_addr + alloc->user_buffer_offset; + ret = vm_insert_page(vma, user_page_addr, page[0]); + if (ret) { + pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", + alloc->pid, user_page_addr); + goto err_vm_insert_page_failed; + } + /* vm_insert_page does not seem to increment the refcount */ + } + if (mm) { + up_read(&mm->mmap_sem); + mmput(mm); + } + return 0; + +free_range: + for (page_addr = end - PAGE_SIZE; page_addr >= start; + page_addr -= PAGE_SIZE) { + page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE]; + if (vma) + zap_page_range(vma, (uintptr_t)page_addr + + alloc->user_buffer_offset, PAGE_SIZE, NULL); +err_vm_insert_page_failed: + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); +err_map_kernel_failed: + __free_page(*page); + *page = NULL; +err_alloc_page_failed: + ; + } +err_no_vma: + if (mm) { + up_read(&mm->mmap_sem); + mmput(mm); + } + return vma ? -ENOMEM : -ESRCH; +} + +struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async) +{ + struct rb_node *n = alloc->free_buffers.rb_node; + struct binder_buffer *buffer; + size_t buffer_size; + struct rb_node *best_fit = NULL; + void *has_page_addr; + void *end_page_addr; + size_t size, data_offsets_size; + int ret; + + if (alloc->vma == NULL) { + pr_err("%d: binder_alloc_buf, no vma\n", + alloc->pid); + return ERR_PTR(-ESRCH); + } + + data_offsets_size = ALIGN(data_size, sizeof(void *)) + + ALIGN(offsets_size, sizeof(void *)); + + if (data_offsets_size < data_size || data_offsets_size < offsets_size) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: got transaction with invalid size %zd-%zd\n", + alloc->pid, data_size, offsets_size); + return ERR_PTR(-EINVAL); + } + size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); + if (size < data_offsets_size || size < extra_buffers_size) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: got transaction with invalid extra_buffers_size %zd\n", + alloc->pid, extra_buffers_size); + return ERR_PTR(-EINVAL); + } + if (is_async && + alloc->free_async_space < size + sizeof(struct binder_buffer)) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd failed, no async space left\n", + alloc->pid, size); + return ERR_PTR(-ENOSPC); + } + + /* Pad 0-size buffers so they get assigned unique addresses */ + size = max(size, sizeof(void *)); + + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + + if (size < buffer_size) { + best_fit = n; + n = n->rb_left; + } else if (size > buffer_size) + n = n->rb_right; + else { + best_fit = n; + break; + } + } + if (best_fit == NULL) { + size_t allocated_buffers = 0; + size_t largest_alloc_size = 0; + size_t total_alloc_size = 0; + size_t free_buffers = 0; + size_t largest_free_size = 0; + size_t total_free_size = 0; + + for (n = rb_first(&alloc->allocated_buffers); n != NULL; + n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + allocated_buffers++; + total_alloc_size += buffer_size; + if (buffer_size > largest_alloc_size) + largest_alloc_size = buffer_size; + } + for (n = rb_first(&alloc->free_buffers); n != NULL; + n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + free_buffers++; + total_free_size += buffer_size; + if (buffer_size > largest_free_size) + largest_free_size = buffer_size; + } + pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", + alloc->pid, size); + pr_err("allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n", + total_alloc_size, allocated_buffers, largest_alloc_size, + total_free_size, free_buffers, largest_free_size); + return ERR_PTR(-ENOSPC); + } + if (n == NULL) { + buffer = rb_entry(best_fit, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + } + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n", + alloc->pid, size, buffer, buffer_size); + + has_page_addr = + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); + WARN_ON(n && buffer_size != size); + end_page_addr = + (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); + if (end_page_addr > has_page_addr) + end_page_addr = has_page_addr; + ret = binder_update_page_range(alloc, 1, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL); + if (ret) + return ERR_PTR(ret); + + if (buffer_size != size) { + struct binder_buffer *new_buffer; + + new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!new_buffer) { + pr_err("%s: %d failed to alloc new buffer struct\n", + __func__, alloc->pid); + goto err_alloc_buf_struct_failed; + } + new_buffer->data = (u8 *)buffer->data + size; + list_add(&new_buffer->entry, &buffer->entry); + new_buffer->free = 1; + binder_insert_free_buffer(alloc, new_buffer); + } + + rb_erase(best_fit, &alloc->free_buffers); + buffer->free = 0; + buffer->allow_user_free = 0; + binder_insert_allocated_buffer_locked(alloc, buffer); + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got %pK\n", + alloc->pid, size, buffer); + buffer->data_size = data_size; + buffer->offsets_size = offsets_size; + buffer->async_transaction = is_async; + buffer->extra_buffers_size = extra_buffers_size; + if (is_async) { + alloc->free_async_space -= size + sizeof(struct binder_buffer); + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_alloc_buf size %zd async free %zd\n", + alloc->pid, size, alloc->free_async_space); + } + return buffer; + +err_alloc_buf_struct_failed: + binder_update_page_range(alloc, 0, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), + end_page_addr, NULL); + return ERR_PTR(-ENOMEM); +} + +/** + * binder_alloc_new_buf() - Allocate a new binder buffer + * @alloc: binder_alloc for this proc + * @data_size: size of user data buffer + * @offsets_size: user specified buffer offset + * @extra_buffers_size: size of extra space for meta-data (eg, security context) + * @is_async: buffer for async transaction + * + * Allocate a new buffer given the requested sizes. Returns + * the kernel version of the buffer pointer. The size allocated + * is the sum of the three given sizes (each rounded up to + * pointer-sized boundary) + * + * Return: The allocated buffer or %NULL if error + */ +struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async) +{ + struct binder_buffer *buffer; + + mutex_lock(&alloc->mutex); + buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size, + extra_buffers_size, is_async); + mutex_unlock(&alloc->mutex); + return buffer; +} + +static void *buffer_start_page(struct binder_buffer *buffer) +{ + return (void *)((uintptr_t)buffer->data & PAGE_MASK); +} + +static void *prev_buffer_end_page(struct binder_buffer *buffer) +{ + return (void *)(((uintptr_t)(buffer->data) - 1) & PAGE_MASK); +} + +static void binder_delete_free_buffer(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + struct binder_buffer *prev, *next = NULL; + bool to_free = true; + BUG_ON(alloc->buffers.next == &buffer->entry); + prev = binder_buffer_prev(buffer); + BUG_ON(!prev->free); + if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) { + to_free = false; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %pK share page with %pK\n", + alloc->pid, buffer->data, prev->data); + } + + if (!list_is_last(&buffer->entry, &alloc->buffers)) { + next = binder_buffer_next(buffer); + if (buffer_start_page(next) == buffer_start_page(buffer)) { + to_free = false; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %pK share page with %pK\n", + alloc->pid, + buffer->data, + next->data); + } + } + + if (IS_ALIGNED((unsigned long)buffer->data, PAGE_SIZE)) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer start %pK is page aligned\n", + alloc->pid, buffer->data); + to_free = false; + } + + if (to_free) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %pK do not share page with %pK or %pK\n", + alloc->pid, buffer->data, + prev->data, next ? next->data : NULL); + binder_update_page_range(alloc, 0, buffer_start_page(buffer), + buffer_start_page(buffer) + PAGE_SIZE, + NULL); + } + list_del(&buffer->entry); + kfree(buffer); +} + +static void binder_free_buf_locked(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + size_t size, buffer_size; + + buffer_size = binder_alloc_buffer_size(alloc, buffer); + + size = ALIGN(buffer->data_size, sizeof(void *)) + + ALIGN(buffer->offsets_size, sizeof(void *)) + + ALIGN(buffer->extra_buffers_size, sizeof(void *)); + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_free_buf %pK size %zd buffer_size %zd\n", + alloc->pid, buffer, size, buffer_size); + + BUG_ON(buffer->free); + BUG_ON(size > buffer_size); + BUG_ON(buffer->transaction != NULL); + BUG_ON(buffer->data < alloc->buffer); + BUG_ON(buffer->data > alloc->buffer + alloc->buffer_size); + + if (buffer->async_transaction) { + alloc->free_async_space += size + sizeof(struct binder_buffer); + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_free_buf size %zd async free %zd\n", + alloc->pid, size, alloc->free_async_space); + } + + binder_update_page_range(alloc, 0, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), + NULL); + + rb_erase(&buffer->rb_node, &alloc->allocated_buffers); + buffer->free = 1; + if (!list_is_last(&buffer->entry, &alloc->buffers)) { + struct binder_buffer *next = binder_buffer_next(buffer); + + if (next->free) { + rb_erase(&next->rb_node, &alloc->free_buffers); + binder_delete_free_buffer(alloc, next); + } + } + if (alloc->buffers.next != &buffer->entry) { + struct binder_buffer *prev = binder_buffer_prev(buffer); + + if (prev->free) { + binder_delete_free_buffer(alloc, buffer); + rb_erase(&prev->rb_node, &alloc->free_buffers); + buffer = prev; + } + } + binder_insert_free_buffer(alloc, buffer); +} + +/** + * binder_alloc_free_buf() - free a binder buffer + * @alloc: binder_alloc for this proc + * @buffer: kernel pointer to buffer + * + * Free the buffer allocated via binder_alloc_new_buffer() + */ +void binder_alloc_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + mutex_lock(&alloc->mutex); + binder_free_buf_locked(alloc, buffer); + mutex_unlock(&alloc->mutex); +} + +/** + * binder_alloc_mmap_handler() - map virtual address space for proc + * @alloc: alloc structure for this proc + * @vma: vma passed to mmap() + * + * Called by binder_mmap() to initialize the space specified in + * vma for allocating binder buffers + * + * Return: + * 0 = success + * -EBUSY = address space already mapped + * -ENOMEM = failed to map memory to given address space + */ +int binder_alloc_mmap_handler(struct binder_alloc *alloc, + struct vm_area_struct *vma) +{ + int ret; + struct vm_struct *area; + const char *failure_string; + struct binder_buffer *buffer; + + mutex_lock(&binder_alloc_mmap_lock); + if (alloc->buffer) { + ret = -EBUSY; + failure_string = "already mapped"; + goto err_already_mapped; + } + + area = get_vm_area(vma->vm_end - vma->vm_start, VM_ALLOC); + if (area == NULL) { + ret = -ENOMEM; + failure_string = "get_vm_area"; + goto err_get_vm_area_failed; + } + alloc->buffer = area->addr; + alloc->user_buffer_offset = + vma->vm_start - (uintptr_t)alloc->buffer; + mutex_unlock(&binder_alloc_mmap_lock); + +#ifdef CONFIG_CPU_CACHE_VIPT + if (cache_is_vipt_aliasing()) { + while (CACHE_COLOUR( + (vma->vm_start ^ (uint32_t)alloc->buffer))) { + pr_info("binder_mmap: %d %lx-%lx maps %pK bad alignment\n", + alloc->pid, vma->vm_start, vma->vm_end, + alloc->buffer); + vma->vm_start += PAGE_SIZE; + } + } +#endif + alloc->pages = kzalloc(sizeof(alloc->pages[0]) * + ((vma->vm_end - vma->vm_start) / PAGE_SIZE), + GFP_KERNEL); + if (alloc->pages == NULL) { + ret = -ENOMEM; + failure_string = "alloc page array"; + goto err_alloc_pages_failed; + } + alloc->buffer_size = vma->vm_end - vma->vm_start; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) { + ret = -ENOMEM; + failure_string = "alloc buffer struct"; + goto err_alloc_buf_struct_failed; + } + + buffer->data = alloc->buffer; + list_add(&buffer->entry, &alloc->buffers); + buffer->free = 1; + binder_insert_free_buffer(alloc, buffer); + alloc->free_async_space = alloc->buffer_size / 2; + barrier(); + alloc->vma = vma; + alloc->vma_vm_mm = vma->vm_mm; + /* Same as mmgrab() in later kernel versions */ + atomic_inc(&alloc->vma_vm_mm->mm_count); + + return 0; + +err_alloc_buf_struct_failed: + kfree(alloc->pages); + alloc->pages = NULL; +err_alloc_pages_failed: + mutex_lock(&binder_alloc_mmap_lock); + vfree(alloc->buffer); + alloc->buffer = NULL; +err_get_vm_area_failed: +err_already_mapped: + mutex_unlock(&binder_alloc_mmap_lock); + pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, + alloc->pid, vma->vm_start, vma->vm_end, failure_string, ret); + return ret; +} + + +void binder_alloc_deferred_release(struct binder_alloc *alloc) +{ + struct rb_node *n; + int buffers, page_count; + struct binder_buffer *buffer; + + BUG_ON(alloc->vma); + + buffers = 0; + mutex_lock(&alloc->mutex); + while ((n = rb_first(&alloc->allocated_buffers))) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + + /* Transaction should already have been freed */ + BUG_ON(buffer->transaction); + + binder_free_buf_locked(alloc, buffer); + buffers++; + } + + while (!list_empty(&alloc->buffers)) { + buffer = list_first_entry(&alloc->buffers, + struct binder_buffer, entry); + WARN_ON(!buffer->free); + + list_del(&buffer->entry); + WARN_ON_ONCE(!list_empty(&alloc->buffers)); + kfree(buffer); + } + + page_count = 0; + if (alloc->pages) { + int i; + + for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { + void *page_addr; + + if (!alloc->pages[i]) + continue; + + page_addr = alloc->buffer + i * PAGE_SIZE; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%s: %d: page %d at %pK not freed\n", + __func__, alloc->pid, i, page_addr); + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); + __free_page(alloc->pages[i]); + page_count++; + } + kfree(alloc->pages); + vfree(alloc->buffer); + } + mutex_unlock(&alloc->mutex); + + binder_alloc_debug(BINDER_DEBUG_OPEN_CLOSE, + "%s: %d buffers %d, pages %d\n", + __func__, alloc->pid, buffers, page_count); +} + +static void print_binder_buffer(struct seq_file *m, const char *prefix, + struct binder_buffer *buffer) +{ + seq_printf(m, "%s %d: %pK size %zd:%zd:%zd %s\n", + prefix, buffer->debug_id, buffer->data, + buffer->data_size, buffer->offsets_size, + buffer->extra_buffers_size, + buffer->transaction ? "active" : "delivered"); +} + +/** + * binder_alloc_print_allocated() - print buffer info + * @m: seq_file for output via seq_printf() + * @alloc: binder_alloc for this proc + * + * Prints information about every buffer associated with + * the binder_alloc state to the given seq_file + */ +void binder_alloc_print_allocated(struct seq_file *m, + struct binder_alloc *alloc) +{ + struct rb_node *n; + + mutex_lock(&alloc->mutex); + for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) + print_binder_buffer(m, " buffer", + rb_entry(n, struct binder_buffer, rb_node)); + mutex_unlock(&alloc->mutex); +} + +/** + * binder_alloc_get_allocated_count() - return count of buffers + * @alloc: binder_alloc for this proc + * + * Return: count of allocated buffers + */ +int binder_alloc_get_allocated_count(struct binder_alloc *alloc) +{ + struct rb_node *n; + int count = 0; + + mutex_lock(&alloc->mutex); + for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) + count++; + mutex_unlock(&alloc->mutex); + return count; +} + + +/** + * binder_alloc_vma_close() - invalidate address space + * @alloc: binder_alloc for this proc + * + * Called from binder_vma_close() when releasing address space. + * Clears alloc->vma to prevent new incoming transactions from + * allocating more buffers. + */ +void binder_alloc_vma_close(struct binder_alloc *alloc) +{ + WRITE_ONCE(alloc->vma, NULL); + WRITE_ONCE(alloc->vma_vm_mm, NULL); +} + +/** + * binder_alloc_init() - called by binder_open() for per-proc initialization + * @alloc: binder_alloc for this proc + * + * Called from binder_open() to initialize binder_alloc fields for + * new binder proc + */ +void binder_alloc_init(struct binder_alloc *alloc) +{ + alloc->tsk = current->group_leader; + alloc->pid = current->group_leader->pid; + mutex_init(&alloc->mutex); + INIT_LIST_HEAD(&alloc->buffers); +} + diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h new file mode 100644 index 000000000000..4dabd77369d1 --- /dev/null +++ b/drivers/android/binder_alloc.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_BINDER_ALLOC_H +#define _LINUX_BINDER_ALLOC_H + +#include +#include +#include +#include +#include +#include + +struct binder_transaction; + +/** + * struct binder_buffer - buffer used for binder transactions + * @entry: entry alloc->buffers + * @rb_node: node for allocated_buffers/free_buffers rb trees + * @free: %true if buffer is free + * @allow_user_free: %true if user is allowed to free buffer + * @async_transaction: %true if buffer is in use for an async txn + * @debug_id: unique ID for debugging + * @transaction: pointer to associated struct binder_transaction + * @target_node: struct binder_node associated with this buffer + * @data_size: size of @transaction data + * @offsets_size: size of array of offsets + * @extra_buffers_size: size of space for other objects (like sg lists) + * @data: pointer to base of buffer space + * + * Bookkeeping structure for binder transaction buffers + */ +struct binder_buffer { + struct list_head entry; /* free and allocated entries by address */ + struct rb_node rb_node; /* free entry by size or allocated entry */ + /* by address */ + unsigned free:1; + unsigned allow_user_free:1; + unsigned async_transaction:1; + unsigned debug_id:29; + + struct binder_transaction *transaction; + + struct binder_node *target_node; + size_t data_size; + size_t offsets_size; + size_t extra_buffers_size; + void *data; +}; + +/** + * struct binder_alloc - per-binder proc state for binder allocator + * @vma: vm_area_struct passed to mmap_handler + * (invarient after mmap) + * @tsk: tid for task that called init for this proc + * (invariant after init) + * @vma_vm_mm: copy of vma->vm_mm (invarient after mmap) + * @buffer: base of per-proc address space mapped via mmap + * @user_buffer_offset: offset between user and kernel VAs for buffer + * @buffers: list of all buffers for this proc + * @free_buffers: rb tree of buffers available for allocation + * sorted by size + * @allocated_buffers: rb tree of allocated buffers sorted by address + * @free_async_space: VA space available for async buffers. This is + * initialized at mmap time to 1/2 the full VA space + * @pages: array of physical page addresses for each + * page of mmap'd space + * @buffer_size: size of address space specified via mmap + * @pid: pid for associated binder_proc (invariant after init) + * + * Bookkeeping structure for per-proc address space management for binder + * buffers. It is normally initialized during binder_init() and binder_mmap() + * calls. The address space is used for both user-visible buffers and for + * struct binder_buffer objects used to track the user buffers + */ +struct binder_alloc { + struct mutex mutex; + struct task_struct *tsk; + struct vm_area_struct *vma; + struct mm_struct *vma_vm_mm; + void *buffer; + ptrdiff_t user_buffer_offset; + struct list_head buffers; + struct rb_root free_buffers; + struct rb_root allocated_buffers; + size_t free_async_space; + struct page **pages; + size_t buffer_size; + uint32_t buffer_free; + int pid; +}; + +#ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST +void binder_selftest_alloc(struct binder_alloc *alloc); +#else +static inline void binder_selftest_alloc(struct binder_alloc *alloc) {} +#endif +extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async); +extern void binder_alloc_init(struct binder_alloc *alloc); +extern void binder_alloc_vma_close(struct binder_alloc *alloc); +extern struct binder_buffer * +binder_alloc_prepare_to_free(struct binder_alloc *alloc, + uintptr_t user_ptr); +extern void binder_alloc_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer); +extern int binder_alloc_mmap_handler(struct binder_alloc *alloc, + struct vm_area_struct *vma); +extern void binder_alloc_deferred_release(struct binder_alloc *alloc); +extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc); +extern void binder_alloc_print_allocated(struct seq_file *m, + struct binder_alloc *alloc); + +/** + * binder_alloc_get_free_async_space() - get free space available for async + * @alloc: binder_alloc for this proc + * + * Return: the bytes remaining in the address-space for async transactions + */ +static inline size_t +binder_alloc_get_free_async_space(struct binder_alloc *alloc) +{ + size_t free_async_space; + + mutex_lock(&alloc->mutex); + free_async_space = alloc->free_async_space; + mutex_unlock(&alloc->mutex); + return free_async_space; +} + +/** + * binder_alloc_get_user_buffer_offset() - get offset between kernel/user addrs + * @alloc: binder_alloc for this proc + * + * Return: the offset between kernel and user-space addresses to use for + * virtual address conversion + */ +static inline ptrdiff_t +binder_alloc_get_user_buffer_offset(struct binder_alloc *alloc) +{ + /* + * user_buffer_offset is constant if vma is set and + * undefined if vma is not set. It is possible to + * get here with !alloc->vma if the target process + * is dying while a transaction is being initiated. + * Returning the old value is ok in this case and + * the transaction will fail. + */ + return alloc->user_buffer_offset; +} + +#endif /* _LINUX_BINDER_ALLOC_H */ + diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c new file mode 100644 index 000000000000..0bf72079a9da --- /dev/null +++ b/drivers/android/binder_alloc_selftest.c @@ -0,0 +1,270 @@ +/* binder_alloc_selftest.c + * + * Android IPC Subsystem + * + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include "binder_alloc.h" + +#define BUFFER_NUM 5 +#define BUFFER_MIN_SIZE (PAGE_SIZE / 8) + +static bool binder_selftest_run = true; +static int binder_selftest_failures; +static DEFINE_MUTEX(binder_selftest_lock); + +/** + * enum buf_end_align_type - Page alignment of a buffer + * end with regard to the end of the previous buffer. + * + * In the pictures below, buf2 refers to the buffer we + * are aligning. buf1 refers to previous buffer by addr. + * Symbol [ means the start of a buffer, ] means the end + * of a buffer, and | means page boundaries. + */ +enum buf_end_align_type { + /** + * @SAME_PAGE_UNALIGNED: The end of this buffer is on + * the same page as the end of the previous buffer and + * is not page aligned. Examples: + * buf1 ][ buf2 ][ ... + * buf1 ]|[ buf2 ][ ... + */ + SAME_PAGE_UNALIGNED = 0, + /** + * @SAME_PAGE_ALIGNED: When the end of the previous buffer + * is not page aligned, the end of this buffer is on the + * same page as the end of the previous buffer and is page + * aligned. When the previous buffer is page aligned, the + * end of this buffer is aligned to the next page boundary. + * Examples: + * buf1 ][ buf2 ]| ... + * buf1 ]|[ buf2 ]| ... + */ + SAME_PAGE_ALIGNED, + /** + * @NEXT_PAGE_UNALIGNED: The end of this buffer is on + * the page next to the end of the previous buffer and + * is not page aligned. Examples: + * buf1 ][ buf2 | buf2 ][ ... + * buf1 ]|[ buf2 | buf2 ][ ... + */ + NEXT_PAGE_UNALIGNED, + /** + * @NEXT_PAGE_ALIGNED: The end of this buffer is on + * the page next to the end of the previous buffer and + * is page aligned. Examples: + * buf1 ][ buf2 | buf2 ]| ... + * buf1 ]|[ buf2 | buf2 ]| ... + */ + NEXT_PAGE_ALIGNED, + /** + * @NEXT_NEXT_UNALIGNED: The end of this buffer is on + * the page that follows the page after the end of the + * previous buffer and is not page aligned. Examples: + * buf1 ][ buf2 | buf2 | buf2 ][ ... + * buf1 ]|[ buf2 | buf2 | buf2 ][ ... + */ + NEXT_NEXT_UNALIGNED, + LOOP_END, +}; + +static void pr_err_size_seq(size_t *sizes, int *seq) +{ + int i; + + pr_err("alloc sizes: "); + for (i = 0; i < BUFFER_NUM; i++) + pr_cont("[%zu]", sizes[i]); + pr_cont("\n"); + pr_err("free seq: "); + for (i = 0; i < BUFFER_NUM; i++) + pr_cont("[%d]", seq[i]); + pr_cont("\n"); +} + +static bool check_buffer_pages_allocated(struct binder_alloc *alloc, + struct binder_buffer *buffer, + size_t size) +{ + void *page_addr, *end; + int page_index; + + end = (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); + page_addr = buffer->data; + for (; page_addr < end; page_addr += PAGE_SIZE) { + page_index = (page_addr - alloc->buffer) / PAGE_SIZE; + if (!alloc->pages[page_index]) { + pr_err("incorrect alloc state at page index %d\n", + page_index); + return false; + } + } + return true; +} + +static void binder_selftest_alloc_buf(struct binder_alloc *alloc, + struct binder_buffer *buffers[], + size_t *sizes, int *seq) +{ + int i; + + for (i = 0; i < BUFFER_NUM; i++) { + buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0); + if (IS_ERR(buffers[i]) || + !check_buffer_pages_allocated(alloc, buffers[i], + sizes[i])) { + pr_err_size_seq(sizes, seq); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffers[], + size_t *sizes, int *seq) +{ + int i; + + for (i = 0; i < BUFFER_NUM; i++) + binder_alloc_free_buf(alloc, buffers[seq[i]]); + + for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) { + if ((!alloc->pages[i]) == (i == 0)) { + pr_err("incorrect free state at page index %d\n", i); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_alloc_free(struct binder_alloc *alloc, + size_t *sizes, int *seq) +{ + struct binder_buffer *buffers[BUFFER_NUM]; + + binder_selftest_alloc_buf(alloc, buffers, sizes, seq); + binder_selftest_free_buf(alloc, buffers, sizes, seq); +} + +static bool is_dup(int *seq, int index, int val) +{ + int i; + + for (i = 0; i < index; i++) { + if (seq[i] == val) + return true; + } + return false; +} + +/* Generate BUFFER_NUM factorial free orders. */ +static void binder_selftest_free_seq(struct binder_alloc *alloc, + size_t *sizes, int *seq, int index) +{ + int i; + + if (index == BUFFER_NUM) { + binder_selftest_alloc_free(alloc, sizes, seq); + return; + } + for (i = 0; i < BUFFER_NUM; i++) { + if (is_dup(seq, index, i)) + continue; + seq[index] = i; + binder_selftest_free_seq(alloc, sizes, seq, index + 1); + } +} + +static void binder_selftest_alloc_size(struct binder_alloc *alloc, + size_t *end_offset) +{ + int i; + int seq[BUFFER_NUM] = {0}; + size_t front_sizes[BUFFER_NUM]; + size_t back_sizes[BUFFER_NUM]; + size_t last_offset, offset = 0; + + for (i = 0; i < BUFFER_NUM; i++) { + last_offset = offset; + offset = end_offset[i]; + front_sizes[i] = offset - last_offset; + back_sizes[BUFFER_NUM - i - 1] = front_sizes[i]; + } + /* + * Buffers share the first or last few pages. + * Only BUFFER_NUM - 1 buffer sizes are adjustable since + * we need one giant buffer before getting to the last page. + */ + back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1]; + binder_selftest_free_seq(alloc, front_sizes, seq, 0); + binder_selftest_free_seq(alloc, back_sizes, seq, 0); +} + +static void binder_selftest_alloc_offset(struct binder_alloc *alloc, + size_t *end_offset, int index) +{ + int align; + size_t end, prev; + + if (index == BUFFER_NUM) { + binder_selftest_alloc_size(alloc, end_offset); + return; + } + prev = index == 0 ? 0 : end_offset[index - 1]; + end = prev; + + BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE); + + for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) { + if (align % 2) + end = ALIGN(end, PAGE_SIZE); + else + end += BUFFER_MIN_SIZE; + end_offset[index] = end; + binder_selftest_alloc_offset(alloc, end_offset, index + 1); + } +} + +/** + * binder_selftest_alloc() - Test alloc and free of buffer pages. + * @alloc: Pointer to alloc struct. + * + * Allocate BUFFER_NUM buffers to cover all page alignment cases, + * then free them in all orders possible. Check that pages are + * allocated after buffer alloc and freed after freeing buffer. + */ +void binder_selftest_alloc(struct binder_alloc *alloc) +{ + size_t end_offset[BUFFER_NUM]; + + if (!binder_selftest_run) + return; + mutex_lock(&binder_selftest_lock); + if (!binder_selftest_run || !alloc->vma) + goto done; + pr_info("STARTED\n"); + binder_selftest_alloc_offset(alloc, end_offset, 0); + binder_selftest_run = false; + if (binder_selftest_failures > 0) + pr_info("%d tests FAILED\n", binder_selftest_failures); + else + pr_info("PASSED\n"); + +done: + mutex_unlock(&binder_selftest_lock); +} diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h index 7f20f3dc8369..7d8beb77f532 100644 --- a/drivers/android/binder_trace.h +++ b/drivers/android/binder_trace.h @@ -23,7 +23,8 @@ struct binder_buffer; struct binder_node; struct binder_proc; -struct binder_ref; +struct binder_alloc; +struct binder_ref_data; struct binder_thread; struct binder_transaction; @@ -84,6 +85,30 @@ DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_ioctl_done); DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_write_done); DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_read_done); +TRACE_EVENT(binder_set_priority, + TP_PROTO(int proc, int thread, unsigned int old_prio, + unsigned int desired_prio, unsigned int new_prio), + TP_ARGS(proc, thread, old_prio, new_prio, desired_prio), + + TP_STRUCT__entry( + __field(int, proc) + __field(int, thread) + __field(unsigned int, old_prio) + __field(unsigned int, new_prio) + __field(unsigned int, desired_prio) + ), + TP_fast_assign( + __entry->proc = proc; + __entry->thread = thread; + __entry->old_prio = old_prio; + __entry->new_prio = new_prio; + __entry->desired_prio = desired_prio; + ), + TP_printk("proc=%d thread=%d old=%d => new=%d desired=%d", + __entry->proc, __entry->thread, __entry->old_prio, + __entry->new_prio, __entry->desired_prio) +); + TRACE_EVENT(binder_wait_for_work, TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo), TP_ARGS(proc_work, transaction_stack, thread_todo), @@ -146,8 +171,8 @@ TRACE_EVENT(binder_transaction_received, TRACE_EVENT(binder_transaction_node_to_ref, TP_PROTO(struct binder_transaction *t, struct binder_node *node, - struct binder_ref *ref), - TP_ARGS(t, node, ref), + struct binder_ref_data *rdata), + TP_ARGS(t, node, rdata), TP_STRUCT__entry( __field(int, debug_id) @@ -160,8 +185,8 @@ TRACE_EVENT(binder_transaction_node_to_ref, __entry->debug_id = t->debug_id; __entry->node_debug_id = node->debug_id; __entry->node_ptr = node->ptr; - __entry->ref_debug_id = ref->debug_id; - __entry->ref_desc = ref->desc; + __entry->ref_debug_id = rdata->debug_id; + __entry->ref_desc = rdata->desc; ), TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d", __entry->debug_id, __entry->node_debug_id, @@ -170,8 +195,9 @@ TRACE_EVENT(binder_transaction_node_to_ref, ); TRACE_EVENT(binder_transaction_ref_to_node, - TP_PROTO(struct binder_transaction *t, struct binder_ref *ref), - TP_ARGS(t, ref), + TP_PROTO(struct binder_transaction *t, struct binder_node *node, + struct binder_ref_data *rdata), + TP_ARGS(t, node, rdata), TP_STRUCT__entry( __field(int, debug_id) @@ -182,10 +208,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, ), TP_fast_assign( __entry->debug_id = t->debug_id; - __entry->ref_debug_id = ref->debug_id; - __entry->ref_desc = ref->desc; - __entry->node_debug_id = ref->node->debug_id; - __entry->node_ptr = ref->node->ptr; + __entry->ref_debug_id = rdata->debug_id; + __entry->ref_desc = rdata->desc; + __entry->node_debug_id = node->debug_id; + __entry->node_ptr = node->ptr; ), TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx", __entry->debug_id, __entry->node_debug_id, @@ -194,9 +220,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, ); TRACE_EVENT(binder_transaction_ref_to_ref, - TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref, - struct binder_ref *dest_ref), - TP_ARGS(t, src_ref, dest_ref), + TP_PROTO(struct binder_transaction *t, struct binder_node *node, + struct binder_ref_data *src_ref, + struct binder_ref_data *dest_ref), + TP_ARGS(t, node, src_ref, dest_ref), TP_STRUCT__entry( __field(int, debug_id) @@ -208,7 +235,7 @@ TRACE_EVENT(binder_transaction_ref_to_ref, ), TP_fast_assign( __entry->debug_id = t->debug_id; - __entry->node_debug_id = src_ref->node->debug_id; + __entry->node_debug_id = node->debug_id; __entry->src_ref_debug_id = src_ref->debug_id; __entry->src_ref_desc = src_ref->desc; __entry->dest_ref_debug_id = dest_ref->debug_id; @@ -245,14 +272,17 @@ DECLARE_EVENT_CLASS(binder_buffer_class, __field(int, debug_id) __field(size_t, data_size) __field(size_t, offsets_size) + __field(size_t, extra_buffers_size) ), TP_fast_assign( __entry->debug_id = buf->debug_id; __entry->data_size = buf->data_size; __entry->offsets_size = buf->offsets_size; + __entry->extra_buffers_size = buf->extra_buffers_size; ), - TP_printk("transaction=%d data_size=%zd offsets_size=%zd", - __entry->debug_id, __entry->data_size, __entry->offsets_size) + TP_printk("transaction=%d data_size=%zd offsets_size=%zd extra_buffers_size=%zd", + __entry->debug_id, __entry->data_size, __entry->offsets_size, + __entry->extra_buffers_size) ); DEFINE_EVENT(binder_buffer_class, binder_transaction_alloc_buf, @@ -268,9 +298,9 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, TP_ARGS(buffer)); TRACE_EVENT(binder_update_page_range, - TP_PROTO(struct binder_proc *proc, bool allocate, + TP_PROTO(struct binder_alloc *alloc, bool allocate, void *start, void *end), - TP_ARGS(proc, allocate, start, end), + TP_ARGS(alloc, allocate, start, end), TP_STRUCT__entry( __field(int, proc) __field(bool, allocate) @@ -278,9 +308,9 @@ TRACE_EVENT(binder_update_page_range, __field(size_t, size) ), TP_fast_assign( - __entry->proc = proc->pid; + __entry->proc = alloc->pid; __entry->allocate = allocate; - __entry->offset = start - proc->buffer; + __entry->offset = start - alloc->buffer; __entry->size = end - start; ), TP_printk("proc=%d allocate=%d offset=%zu size=%zu", @@ -288,6 +318,61 @@ TRACE_EVENT(binder_update_page_range, __entry->offset, __entry->size) ); +DECLARE_EVENT_CLASS(binder_lru_page_class, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index), + TP_STRUCT__entry( + __field(int, proc) + __field(size_t, page_index) + ), + TP_fast_assign( + __entry->proc = alloc->pid; + __entry->page_index = page_index; + ), + TP_printk("proc=%d page_index=%zu", + __entry->proc, __entry->page_index) +); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_free_lru_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_free_lru_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + TRACE_EVENT(binder_command, TP_PROTO(uint32_t cmd), TP_ARGS(cmd), diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 0c146917c049..3f4b536fc549 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -20,6 +20,7 @@ #ifndef _UAPI_LINUX_BINDER_H #define _UAPI_LINUX_BINDER_H +#include #include #define B_PACK_CHARS(c1, c2, c3, c4) \ @@ -36,9 +37,64 @@ enum { BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE), }; -enum { +/** + * enum flat_binder_object_shifts: shift values for flat_binder_object_flags + * @FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT: shift for getting scheduler policy. + * + */ +enum flat_binder_object_shifts { + FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT = 9, +}; + +/** + * enum flat_binder_object_flags - flags for use in flat_binder_object.flags + */ +enum flat_binder_object_flags { + /** + * @FLAT_BINDER_FLAG_PRIORITY_MASK: bit-mask for min scheduler priority + * + * These bits can be used to set the minimum scheduler priority + * at which transactions into this node should run. Valid values + * in these bits depend on the scheduler policy encoded in + * @FLAT_BINDER_FLAG_SCHED_POLICY_MASK. + * + * For SCHED_NORMAL/SCHED_BATCH, the valid range is between [-20..19] + * For SCHED_FIFO/SCHED_RR, the value can run between [1..99] + */ FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, + /** + * @FLAT_BINDER_FLAG_ACCEPTS_FDS: whether the node accepts fds. + */ FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, + /** + * @FLAT_BINDER_FLAG_SCHED_POLICY_MASK: bit-mask for scheduling policy + * + * These two bits can be used to set the min scheduling policy at which + * transactions on this node should run. These match the UAPI + * scheduler policy values, eg: + * 00b: SCHED_NORMAL + * 01b: SCHED_FIFO + * 10b: SCHED_RR + * 11b: SCHED_BATCH + */ + FLAT_BINDER_FLAG_SCHED_POLICY_MASK = + 3U << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT, + + /** + * @FLAT_BINDER_FLAG_INHERIT_RT: whether the node inherits RT policy + * + * Only when set, calls into this node will inherit a real-time + * scheduling policy from the caller (for synchronous transactions). + */ + FLAT_BINDER_FLAG_INHERIT_RT = 0x800, + + /** + * @FLAT_BINDER_FLAG_TXN_SECURITY_CTX: request security contexts + * + * Only when set, causes senders to include their security + * context + */ + FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000, }; #ifdef BINDER_IPC_32BIT @@ -185,13 +241,39 @@ struct binder_version { #define BINDER_CURRENT_PROTOCOL_VERSION 8 #endif +/* + * Use with BINDER_GET_NODE_DEBUG_INFO, driver reads ptr, writes to all fields. + * Set ptr to NULL for the first call to get the info for the first node, and + * then repeat the call passing the previously returned value to get the next + * nodes. ptr will be 0 when there are no more nodes. + */ +struct binder_node_debug_info { + binder_uintptr_t ptr; + binder_uintptr_t cookie; + __u32 has_strong_ref; + __u32 has_weak_ref; +}; + +struct binder_node_info_for_ref { + __u32 handle; + __u32 strong_count; + __u32 weak_count; + __u32 reserved1; + __u32 reserved2; + __u32 reserved3; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) -#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) -#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) -#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32) -#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) -#define BINDER_THREAD_EXIT _IOW('b', 8, __s32) +#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) +#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) +#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32) +#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) +#define BINDER_THREAD_EXIT _IOW('b', 8, __s32) #define BINDER_VERSION _IOWR('b', 9, struct binder_version) +#define BINDER_SET_INHERIT_FIFO_PRIO _IO('b', 10) +#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) +#define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) +#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) /* * NOTE: Two special error codes you should check for when calling @@ -250,6 +332,11 @@ struct binder_transaction_data { } data; }; +struct binder_transaction_data_secctx { + struct binder_transaction_data transaction_data; + binder_uintptr_t secctx; +}; + struct binder_transaction_data_sg { struct binder_transaction_data transaction_data; binder_size_t buffers_size; @@ -263,7 +350,7 @@ struct binder_ptr_cookie { struct binder_handle_cookie { __u32 handle; binder_uintptr_t cookie; -} __packed; +} __attribute__((packed)); struct binder_pri_desc { __s32 priority; @@ -285,6 +372,11 @@ enum binder_driver_return_protocol { BR_OK = _IO('r', 1), /* No parameters! */ + BR_TRANSACTION_SEC_CTX = _IOR('r', 2, + struct binder_transaction_data_secctx), + /* + * binder_transaction_data_secctx: the received command. + */ BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), BR_REPLY = _IOR('r', 3, struct binder_transaction_data), /* @@ -421,13 +513,15 @@ enum binder_driver_command_protocol { * of looping threads it has available. */ - BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_handle_cookie), + BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, + struct binder_handle_cookie), /* * int: handle * void *: cookie */ - BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_handle_cookie), + BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, + struct binder_handle_cookie), /* * int: handle * void *: cookie -- GitLab From 7f7c84f127ea055cbb188575c072b4bad853ca12 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 23 Mar 2017 13:36:42 -0400 Subject: [PATCH 017/528] arm64: zero the leading stack canary byte (cherry picked from commit 9cc0093cbd93029ad0b5423705e7e0048db331cc) --- arch/arm64/include/asm/stackprotector.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/include/asm/stackprotector.h b/arch/arm64/include/asm/stackprotector.h index de003327be97..330412e1fb3d 100644 --- a/arch/arm64/include/asm/stackprotector.h +++ b/arch/arm64/include/asm/stackprotector.h @@ -31,6 +31,9 @@ static __always_inline void boot_init_stack_canary(void) get_random_bytes(&canary, sizeof(canary)); canary ^= LINUX_VERSION_CODE; + /* Sacrifice 8 bits of entropy to mitigate non-terminated C string overflows */ + canary &= ~(unsigned long)0xff; + current->stack_canary = canary; __stack_chk_guard = current->stack_canary; } -- GitLab From 24b17d24cf745f3646c771518c5aeff4156ae059 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 23 Jan 2017 22:40:10 -0500 Subject: [PATCH 018/528] add slub sanitization (cherry picked from commit 8c7db68c04d3f36f2e1590c8224201dd722c9634) --- mm/slub.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/slub.c b/mm/slub.c index c0530a31dd4d..f52061230811 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2647,6 +2647,13 @@ static __always_inline void slab_free(struct kmem_cache *s, slab_free_hook(s, x); + if (!(s->flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON))) { + size_t offset = s->offset ? 0 : sizeof(void *); + memset(x + offset, 0, s->object_size - offset); + if (s->ctor) + s->ctor(x); + } + redo: /* * Determine the currently cpus per cpu slab. -- GitLab From cd533cefe3e5a0d84157117ccf921ffb1b022098 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 2 Apr 2017 19:45:55 -0400 Subject: [PATCH 019/528] slub: add check for write-after-free (cherry picked from commit 5d9ce6c3e23f3054df4034ba40bb4e745d58cd00) --- mm/slub.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mm/slub.c b/mm/slub.c index f52061230811..a9aa01b0c33e 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2441,6 +2441,11 @@ redo: stat(s, ALLOC_FASTPATH); } + if (!(s->flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) && !s->ctor && object) { + size_t offset = s->offset ? 0 : sizeof(void *); + BUG_ON(memchr_inv((void *)object + offset, 0, s->object_size - offset)); + } + if (unlikely(gfpflags & __GFP_ZERO) && object) memset(object, 0, s->object_size); -- GitLab From f61ed50bd966976f3027cab5077e8d2dc8c3ac92 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 10 Jan 2017 20:45:59 -0500 Subject: [PATCH 020/528] disable slab merging by default (cherry picked from commit 3f71ec2e645a7faa6e6bcbae71612732d897923e) --- mm/slub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index a9aa01b0c33e..7cdb83904a8c 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2726,7 +2726,7 @@ static int slub_min_objects; * Merge control. If this is set then no merging of slab caches will occur. * (Could be removed. This was introduced to pacify the merge skeptics.) */ -static int slub_nomerge; +static int slub_nomerge = 1; /* * Calculate the order of allocation given an slab object size. -- GitLab From 25f62c3ed5c38f453f2131bfbf649626d55e1f00 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 26 Mar 2017 23:42:31 -0400 Subject: [PATCH 021/528] slub: add multi-purpose random cookies This provides basic double-free detection and acts as padding to absorb small overflows, which are then detected on free. On 64-bit, the least significant byte is zero to mitigate non-terminated C string overflows. (cherry picked from commit f9f8f333eb4bb5ab4cde3a9448d0742b2780ba03) --- include/linux/slub_def.h | 4 +++ mm/slub.c | 61 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index 8f603d498ec0..6899e8412436 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -96,6 +96,10 @@ struct kmem_cache { int max_attr_size; /* for propagation, maximum size of a stored attr */ #endif + unsigned long random; + unsigned long random_active; + unsigned long random_inactive; + #ifdef CONFIG_NUMA /* * Defragmentation by allocating from a remote node. diff --git a/mm/slub.c b/mm/slub.c index 7cdb83904a8c..db3512809927 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -206,6 +206,8 @@ struct track { enum track_item { TRACK_ALLOC, TRACK_FREE }; +static const bool slub_cookie = true; + #ifdef CONFIG_SYSFS static int sysfs_slab_add(struct kmem_cache *); static int sysfs_slab_alias(struct kmem_cache *, const char *); @@ -281,6 +283,36 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) *(void **)(object + s->offset) = fp; } +#ifdef CONFIG_64BIT +static const unsigned long canary_mask = ~0xFFUL; +#else +static const unsigned long canary_mask = ~0UL; +#endif + +static inline unsigned long *get_cookie(struct kmem_cache *s, void *object) +{ + if (s->offset) + return object + s->offset + sizeof(void *); + else + return object + s->inuse; +} + +static inline void set_cookie(struct kmem_cache *s, void *object, unsigned long value) +{ + if (slub_cookie) { + unsigned long *cookie = get_cookie(s, object); + *cookie = (value ^ (unsigned long)cookie) & canary_mask; + } +} + +static inline void check_cookie(struct kmem_cache *s, void *object, unsigned long value) +{ + if (slub_cookie) { + unsigned long *cookie = get_cookie(s, object); + BUG_ON(*cookie != ((value ^ (unsigned long)cookie) & canary_mask)); + } +} + /* Loop over all objects in a slab */ #define for_each_object(__p, __s, __addr, __objects) \ for (__p = fixup_red_left(__s, __addr); \ @@ -314,7 +346,7 @@ static inline size_t slab_ksize(const struct kmem_cache *s) * back there or track user information then we can * only use the space before that information. */ - if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER)) + if ((s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER)) || slub_cookie) return s->inuse; /* * Else we can use all the padding etc for the allocation @@ -496,9 +528,9 @@ static struct track *get_track(struct kmem_cache *s, void *object, struct track *p; if (s->offset) - p = object + s->offset + sizeof(void *); + p = object + s->offset + sizeof(void *) + sizeof(void *) * slub_cookie; else - p = object + s->inuse; + p = object + s->inuse + sizeof(void *) * slub_cookie; return p + alloc; } @@ -635,6 +667,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) else off = s->inuse; + if (slub_cookie) + off += sizeof(void *); + if (s->flags & SLAB_STORE_USER) off += 2 * sizeof(struct track); @@ -770,6 +805,9 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) /* Freepointer is placed after the object. */ off += sizeof(void *); + if (slub_cookie) + off += sizeof(void *); + if (s->flags & SLAB_STORE_USER) /* We also have user information there */ off += 2 * sizeof(struct track); @@ -1389,6 +1427,7 @@ static void setup_object(struct kmem_cache *s, struct page *page, void *object) { setup_object_debug(s, page, object); + set_cookie(s, object, s->random_inactive); if (unlikely(s->ctor)) s->ctor(object); } @@ -2451,6 +2490,11 @@ redo: slab_post_alloc_hook(s, gfpflags, object); + if (object) { + check_cookie(s, object, s->random_inactive); + set_cookie(s, object, s->random_active); + } + return object; } @@ -2652,6 +2696,9 @@ static __always_inline void slab_free(struct kmem_cache *s, slab_free_hook(s, x); + check_cookie(s, object, s->random_active); + set_cookie(s, object, s->random_inactive); + if (!(s->flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON))) { size_t offset = s->offset ? 0 : sizeof(void *); memset(x + offset, 0, s->object_size - offset); @@ -2903,6 +2950,7 @@ static void early_kmem_cache_node_alloc(int node) init_object(kmem_cache_node, n, SLUB_RED_ACTIVE); init_tracking(kmem_cache_node, n); #endif + set_cookie(kmem_cache_node, n, kmem_cache_node->random_active); init_kmem_cache_node(n); inc_slabs_node(kmem_cache_node, node, page->objects); @@ -3016,6 +3064,9 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) size += sizeof(void *); } + if (slub_cookie) + size += sizeof(void *); + #ifdef CONFIG_SLUB_DEBUG if (flags & SLAB_STORE_USER) /* @@ -3857,6 +3908,10 @@ int __kmem_cache_create(struct kmem_cache *s, unsigned long flags) if (err) kmem_cache_close(s); + s->random = get_random_long(); + s->random_active = get_random_long(); + s->random_inactive = get_random_long(); + return err; } -- GitLab From 61a2e57c2e11dab47c2e2b467fae6886aad18572 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 26 Mar 2017 16:24:45 -0400 Subject: [PATCH 022/528] panic on !PageSlab && !PageCompound in ksize (cherry picked from commit 6c0f2cff1a4b82942e2147660d83647b5b2e2db5) --- mm/slub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index db3512809927..d2b6c6f51583 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3454,7 +3454,7 @@ size_t ksize(const void *object) page = virt_to_head_page(object); if (unlikely(!PageSlab(page))) { - WARN_ON(!PageCompound(page)); + BUG_ON(!PageCompound(page)); return PAGE_SIZE << compound_order(page); } -- GitLab From 7c83ee52388bbd12df70c4c4d83917f621e13242 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 14 Mar 2017 15:32:03 -0400 Subject: [PATCH 023/528] gather extra early boot entropy like PaX (cherry picked from commit 2760811ff52cd2a1bd9facb9818ee4ce8c24e4c4) --- mm/page_alloc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 8d646deb9516..352b2766c153 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -792,6 +793,16 @@ void __free_pages_bootmem(struct page *page, unsigned int order) set_page_count(p, 0); } + if (!PageHighMem(page) && page_to_pfn(page) < 0x100000) { + unsigned long hash = 0; + size_t index, end = PAGE_SIZE * nr_pages / sizeof hash; + const unsigned long *data = lowmem_page_address(page); + + for (index = 0; index < end; index++) + hash ^= hash + data[index]; + add_device_randomness((const void *)&hash, sizeof(hash)); + } + page_zone(page)->managed_pages += 1 << order; set_page_refcounted(page); __free_pages(page, order); -- GitLab From 78babe9c8f1a49e5f953adc9d9c6df961d3286e5 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 20 Jan 2017 16:51:25 -0500 Subject: [PATCH 024/528] add page sanitization / verification (cherry picked from commit 51a69b67949810212ab70550b1fb08525509a0a1) --- include/linux/highmem.h | 22 ++++++++++++++++++++++ mm/page_alloc.c | 12 ++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 35cd6c330795..56543d480592 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -211,6 +212,27 @@ static inline void clear_highpage(struct page *page) kunmap_atomic(kaddr); } +static inline void sanitize_highpage(struct page *page) +{ + void *kaddr; + unsigned long flags; + + local_irq_save(flags); + kaddr = kmap_atomic(page); + clear_page(kaddr); + kunmap_atomic(kaddr); + local_irq_restore(flags); +} + +static inline void sanitize_highpage_verify(struct page *page) +{ + void *kaddr; + + kaddr = kmap_atomic(page); + BUG_ON(memchr_inv(kaddr, 0, PAGE_SIZE)); + kunmap_atomic(kaddr); +} + static inline void zero_user_segments(struct page *page, unsigned start1, unsigned end1, unsigned start2, unsigned end2) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 352b2766c153..07188883cac1 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -727,6 +727,8 @@ static bool free_pages_prepare(struct page *page, unsigned int order) int i; int bad = 0; + unsigned long index = 1UL << order; + trace_mm_page_free(page, order); kmemcheck_free_shadow(page, order); @@ -749,6 +751,10 @@ static bool free_pages_prepare(struct page *page, unsigned int order) debug_check_no_obj_freed(page_address(page), PAGE_SIZE << order); } + + for (; index; --index) + sanitize_highpage(page + index - 1); + arch_free_page(page, order); kernel_map_pages(page, 1 << order, 0); @@ -908,6 +914,8 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) { int i; + unsigned long index = 1UL << order; + for (i = 0; i < (1 << order); i++) { struct page *p = page + i; if (unlikely(check_new_page(p))) @@ -920,8 +928,8 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) arch_alloc_page(page, order); kernel_map_pages(page, 1 << order, 1); - if (gfp_flags & __GFP_ZERO) - prep_zero_page(page, order, gfp_flags); + for (; index; --index) + sanitize_highpage_verify(page + index - 1); if (order && (gfp_flags & __GFP_COMP)) prep_compound_page(page, order); -- GitLab From d38194f447f9c62af588caf32a71776b9f4a096d Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 22 Jan 2017 22:22:34 -0500 Subject: [PATCH 025/528] add missing cache_from_obj !PageSlab check Taken from PaX. (cherry picked from commit d206e406453b4a6a7cf806e813d72dfa3b6440f5) --- mm/slab.h | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/slab.h b/mm/slab.h index 4d6d836247dd..7905396cc71e 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -231,6 +231,7 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) return s; page = virt_to_head_page(x); + BUG_ON(!PageSlab(page)); cachep = page->slab_cache; if (slab_equal_or_root(cachep, s)) return cachep; -- GitLab From cf4b9c9c629f0f76c57ef988214efd6eb442e72c Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 30 Mar 2017 23:05:53 -0400 Subject: [PATCH 026/528] real slab_equal_or_root check for !MEMCG_KMEM (cherry picked from commit cd0831fbb3f8b07912a86c5816afa22633dc083c) --- mm/slab.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slab.h b/mm/slab.h index 7905396cc71e..0c113379cbfd 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -196,7 +196,7 @@ static inline void memcg_release_pages(struct kmem_cache *s, int order) static inline bool slab_equal_or_root(struct kmem_cache *s, struct kmem_cache *p) { - return true; + return p == s; } static inline const char *cache_name(struct kmem_cache *s) -- GitLab From b021d448d305c725f2e570f0ef9408c582817220 Mon Sep 17 00:00:00 2001 From: Mike B Date: Thu, 25 Feb 2021 21:00:39 +0100 Subject: [PATCH 027/528] mm: Missing include random --- mm/slub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/slub.c b/mm/slub.c index d2b6c6f51583..976978832fac 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -33,6 +33,7 @@ #include #include #include +#include #include -- GitLab From 7f271da3844bd61b5138098700d864c8a71aecf5 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 30 Mar 2017 23:07:09 -0400 Subject: [PATCH 028/528] always perform cache_from_obj sanity checks (cherry picked from commit 3b1e73f178380fce19307d821486496ecf857709) --- mm/slab.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/mm/slab.h b/mm/slab.h index 0c113379cbfd..95c880cbe293 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -220,16 +220,6 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) struct kmem_cache *cachep; struct page *page; - /* - * When kmemcg is not being used, both assignments should return the - * same value. but we don't want to pay the assignment price in that - * case. If it is not compiled in, the compiler should be smart enough - * to not do even the assignment. In that case, slab_equal_or_root - * will also be a constant. - */ - if (!memcg_kmem_enabled() && !unlikely(s->flags & SLAB_DEBUG_FREE)) - return s; - page = virt_to_head_page(x); BUG_ON(!PageSlab(page)); cachep = page->slab_cache; -- GitLab From c8a5bd98e0f318358c0f47addb0f5a9ab5326fe5 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 25 Mar 2017 02:46:12 -0400 Subject: [PATCH 029/528] panic on kmem_cache_free with the wrong cache (cherry picked from commit b8288dbdaf01a12ad6063bde53eebd82ff567ce8) --- mm/slab.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mm/slab.h b/mm/slab.h index 95c880cbe293..db27e9349076 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -226,10 +226,8 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) if (slab_equal_or_root(cachep, s)) return cachep; - pr_err("%s: Wrong slab cache. %s but object is from %s\n", + panic("%s: Wrong slab cache. %s but object is from %s\n", __FUNCTION__, cachep->name, s->name); - WARN_ON_ONCE(1); - return s; } #endif -- GitLab From 4e2bd34b968f17b7e67ee947711c10b240c0bb03 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Fri, 10 Nov 2017 07:23:27 +0300 Subject: [PATCH 030/528] power: qpnp-smbcharger_extension: Fix direct references to HZ Thank you for the realization of humberos and zachariasmaladroit! (cherry picked from commit 8dc27e3e961e6a7393df75e31b9872fb4f8fec0c) --- drivers/power/qpnp-smbcharger_extension.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/power/qpnp-smbcharger_extension.c b/drivers/power/qpnp-smbcharger_extension.c index 1167428e308d..14b789902536 100644 --- a/drivers/power/qpnp-smbcharger_extension.c +++ b/drivers/power/qpnp-smbcharger_extension.c @@ -1333,7 +1333,7 @@ static void somc_chg_aicl_reset_params(void) } #define AICL_PERIOD_MS 200 -#define AICL_WAKE_PERIOD (10 * HZ) +#define AICL_WAKE_PERIOD (10000) static void somc_chg_aicl_work(struct work_struct *work) { if (!*chg_params->usb_present) @@ -1353,7 +1353,8 @@ static void somc_chg_aicl_work(struct work_struct *work) *chg_params->usb_suspended, chg_params->last_therm_lvl_sel, *chg_params->thermal.lvl_sel); - wake_lock_timeout(&chg_params->aicl_wakelock, AICL_WAKE_PERIOD); + wake_lock_timeout(&chg_params->aicl_wakelock, + msecs_to_jiffies(AICL_WAKE_PERIOD)); somc_chg_aicl_reset_params(); somc_chg_set_thermal_limited_iusb_max(IUSBMAX_MIN_0MA); chg_params->last_usb_target_current_ma = @@ -1409,7 +1410,7 @@ void somc_chg_aicl_start_work(void) *chg_params->usb_present) { pr_info("Start aicl worker\n"); wake_lock_timeout(&chg_params->aicl_wakelock, - AICL_WAKE_PERIOD); + msecs_to_jiffies(AICL_WAKE_PERIOD)); somc_chg_set_thermal_limited_iusb_max(IUSBMAX_MIN_0MA); somc_chg_forced_iusb_dec_clear_params(); schedule_delayed_work(&chg_params->aicl_work, @@ -2849,10 +2850,11 @@ void somc_batfet_open(struct device *dev, bool open) } } -#define UNPLUG_WAKE_PERIOD (3 * HZ) +#define UNPLUG_WAKE_PERIOD (3000) void somc_unplug_wakelock(void) { - wake_lock_timeout(&chg_params->unplug_wakelock, UNPLUG_WAKE_PERIOD); + wake_lock_timeout(&chg_params->unplug_wakelock, + msecs_to_jiffies(UNPLUG_WAKE_PERIOD)); } #define VFLOAT_CMP_CFG_REG 0xF5 -- GitLab From 4f5491ad70693b46832b2392466cc01be6210271 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Mon, 8 Jan 2018 07:58:32 +0300 Subject: [PATCH 031/528] power: qpnp-smbcharger_extension: check the validity of the thermal parameter * Cherry is taken from the Xperia XZ (cherry picked from commit ca916c6e8817017ce9eef5fc5891ae4aeba59894) --- drivers/power/qpnp-smbcharger_extension.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/power/qpnp-smbcharger_extension.c b/drivers/power/qpnp-smbcharger_extension.c index 14b789902536..f16fc9c8f024 100644 --- a/drivers/power/qpnp-smbcharger_extension.c +++ b/drivers/power/qpnp-smbcharger_extension.c @@ -2406,6 +2406,11 @@ static unsigned int *somc_chg_therm_create_tb(struct device *dev, if (of_find_property(node, thermal, &thermal_levels)) { thermal_size = thermal_levels / sizeof(int); + if (!thermal_levels || !thermal_size) { + dev_err(dev, "Invalid thermal parameters\n"); + *size = -EINVAL; + return NULL; + } thermal_tb = devm_kzalloc(dev, thermal_levels, GFP_KERNEL); if (thermal_tb == NULL) { dev_err(dev, "thermal mitigation kzalloc() failed.\n"); -- GitLab From 2756280c8cbec13fd54780d87f82d33eb19708a3 Mon Sep 17 00:00:00 2001 From: Hikari-no-Tenshi Date: Sat, 26 Nov 2016 21:47:45 +0200 Subject: [PATCH 032/528] drivers: power: Fix 2% battery level drop Signed-off-by: Joe Maples (cherry picked from commit 813350fe935def2b18456bfec146aa66f7d361ca) --- drivers/power/qpnp-fg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c index 93c35d203cb7..75cec5dc8dc5 100644 --- a/drivers/power/qpnp-fg.c +++ b/drivers/power/qpnp-fg.c @@ -5397,7 +5397,7 @@ static int fg_common_hw_init(struct fg_chip *chip) settings[FG_MEM_DELTA_SOC].offset); #else rc = fg_mem_masked_write(chip, settings[FG_MEM_DELTA_SOC].address, 0xFF, - soc_to_setpoint(settings[FG_MEM_DELTA_SOC].value), + settings[FG_MEM_DELTA_SOC].value == 1 ? 1 : soc_to_setpoint(settings[FG_MEM_DELTA_SOC].value), settings[FG_MEM_DELTA_SOC].offset); #endif -- GitLab From b7f8383bfc171aa0a9fe7b8706f3cd353515be7b Mon Sep 17 00:00:00 2001 From: xiewen3 Date: Fri, 22 Sep 2017 23:43:48 +0200 Subject: [PATCH 033/528] fg: bms_charge_full contains an incorrect value. bms_charge_full is recalculated after full charging cycles, but it contains an incorrect value. because the int type calculates overflow. Change-Id: Ia61af9893d4588dfce9cd50c656a6194ce8a464b Signed-off-by: xiewen3 Reviewed-on: https://gerrit.mot.com/990132 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Haijian Ma Reviewed-by: Lu Chai Reviewed-by: Yonghua Yan Reviewed-by: Xiangpo Zhao Submit-Approved: Jira Key Signed-off-by: zachariasmaladroit (cherry picked from commit d2797c36648f7136b74520866411cb53da5f2bd1) --- drivers/power/qpnp-fg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c index 75cec5dc8dc5..ac123fb7f1aa 100644 --- a/drivers/power/qpnp-fg.c +++ b/drivers/power/qpnp-fg.c @@ -2717,20 +2717,20 @@ static void fg_cap_learning_post_process(struct fg_chip *chip) #ifdef CONFIG_QPNP_FG_EXTENSION max_inc_val = chip->learning_data.max_increment ? - chip->learning_data.learned_cc_uah + (int64_t)chip->learning_data.learned_cc_uah * (1000 + chip->learning_data.max_increment) : ((int64_t)chip->nom_cap_uah) * 1000; #else - max_inc_val = chip->learning_data.learned_cc_uah + max_inc_val = (int64_t)chip->learning_data.learned_cc_uah * (1000 + chip->learning_data.max_increment); #endif do_div(max_inc_val, 1000); - min_dec_val = chip->learning_data.learned_cc_uah + min_dec_val = (int64_t)chip->learning_data.learned_cc_uah * (1000 - chip->learning_data.max_decrement); do_div(min_dec_val, 1000); - old_cap = chip->learning_data.learned_cc_uah; + old_cap = (int64_t)chip->learning_data.learned_cc_uah; if (chip->learning_data.cc_uah > max_inc_val) chip->learning_data.learned_cc_uah = max_inc_val; else if (chip->learning_data.cc_uah < min_dec_val) -- GitLab From 283ac95f0788fe0038a9b497b6f190509571170d Mon Sep 17 00:00:00 2001 From: Chao Chen Date: Tue, 1 Sep 2015 15:00:14 -0700 Subject: [PATCH 034/528] drivers:power: Fix the soc update delay The soc value is the fg controller is 0-255. Reported soc is 0-100. Current delta-soc = 255/100 = 3. That will skip some soc point. I do have my doubts about this patch, but the charger code is spaghetti and a bit hard to understand what does what and when. Change-Id: I72b62fc8943322f31da6220e7401d6d9854314f7 Signed-off-by: Francisco Franco (cherry picked from commit 2d507ba0f77f425188e04d7adcaab95a16dfeea7) --- drivers/power/qpnp-fg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c index ac123fb7f1aa..31137b292003 100644 --- a/drivers/power/qpnp-fg.c +++ b/drivers/power/qpnp-fg.c @@ -1110,7 +1110,10 @@ static int fg_mem_masked_write(struct fg_chip *chip, u16 addr, static int soc_to_setpoint(int soc) { - return DIV_ROUND_CLOSEST(soc * 255, 100); + if (soc == 0) + return 1; + else + return DIV_ROUND_CLOSEST(soc * 255, 100); } static void batt_to_setpoint_adc(int vbatt_mv, u8 *data) -- GitLab From 01110dcb1bddceda4ea206eb5312729e50ebd2f1 Mon Sep 17 00:00:00 2001 From: zachariasmaladroit Date: Thu, 11 May 2017 22:13:13 +0200 Subject: [PATCH 035/528] qpnp-fg: [kitakami] 2% drop fix this is the adapted (assumed) fix for too quick battery state dropping Signed-off-by: zachariasmaladroit (cherry picked from commit 374482a756e393a1dbb8a4fa2bd8389cc424d9d5) --- drivers/power/qpnp-fg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c index 31137b292003..b31390d7b23f 100644 --- a/drivers/power/qpnp-fg.c +++ b/drivers/power/qpnp-fg.c @@ -5396,7 +5396,7 @@ static int fg_common_hw_init(struct fg_chip *chip) #ifdef CONFIG_QPNP_FG_EXTENSION rc = fg_mem_masked_write(chip, settings[FG_MEM_DELTA_SOC].address, 0xFF, - settings[FG_MEM_DELTA_SOC].value, + settings[FG_MEM_DELTA_SOC].value == 1 ? 1 : soc_to_setpoint(settings[FG_MEM_DELTA_SOC].value), settings[FG_MEM_DELTA_SOC].offset); #else rc = fg_mem_masked_write(chip, settings[FG_MEM_DELTA_SOC].address, 0xFF, -- GitLab From 13544d537075af8a70dccfbf6a6029900aa04bcc Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 11 Jun 2015 10:32:01 +0200 Subject: [PATCH 036/528] power: qpnp-fg: Use cancel_delayed_work_sync for suspend work This follows the original status before the wakeup sources are added. In previous cleanups, I did not revert this. This will help avoid some corner cases that cause instability. Signed-off-by: Wang Han <416810799@qq.com> (cherry picked from commit 3465c071edd3ed3ccbb0fdfdc1c2f5c6dfeff0ec) --- drivers/power/qpnp-fg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c index b31390d7b23f..a33f6ff38d72 100644 --- a/drivers/power/qpnp-fg.c +++ b/drivers/power/qpnp-fg.c @@ -5976,8 +5976,8 @@ static int fg_suspend(struct device *dev) if (!chip->sw_rbias_ctrl) return 0; - cancel_delayed_work(&chip->update_temp_work); - cancel_delayed_work(&chip->update_sram_data); + cancel_delayed_work_sync(&chip->update_temp_work); + cancel_delayed_work_sync(&chip->update_sram_data); return 0; } -- GitLab From e97aa1d5fa0f124f48731762b49ea97f3a5e0b12 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Thu, 21 Apr 2016 12:17:05 +0800 Subject: [PATCH 037/528] power: qpnp-fg: Add SOC_REPORTING_READY to indicate actual SOC reporting Before battery profile has been loaded, FG reports a default capacity instead of the actual battery capacity. Add SOC_REPORTING_READY to indicate if the actual battery capacity is ready. CRs-Fixed: 1001496 Change-Id: If6cdbc2b5d413e7f2a5c664b2909059afa4dbd44 Signed-off-by: Fenglin Wu Signed-off-by: GreyLeshy (cherry picked from commit 0a998fd5b2416c34d37412ce4f1cf13f8c329243) --- drivers/power/qpnp-fg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c index a33f6ff38d72..53f482da7c36 100644 --- a/drivers/power/qpnp-fg.c +++ b/drivers/power/qpnp-fg.c @@ -2343,6 +2343,7 @@ static enum power_supply_property fg_power_props[] = { POWER_SUPPLY_PROP_VOLTAGE_MIN, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_CYCLE_COUNT_ID, + POWER_SUPPLY_PROP_SOC_REPORTING_READY, #ifdef CONFIG_QPNP_FG_EXTENSION POWER_SUPPLY_PROP_BATT_AGING, #endif @@ -2438,6 +2439,9 @@ static int fg_power_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_NOW_RAW: val->intval = get_sram_prop_now(chip, FG_DATA_CC_CHARGE); break; + case POWER_SUPPLY_PROP_SOC_REPORTING_READY: + val->intval = !!chip->profile_loaded; + break; #ifdef CONFIG_QPNP_FG_EXTENSION case POWER_SUPPLY_PROP_BATT_AGING: val->intval = chip->somc_params.batt_aging; -- GitLab From 1e8de9b488179c0c382d35278ef3e77a07e002b8 Mon Sep 17 00:00:00 2001 From: Bruno Martins Date: Wed, 5 Apr 2017 19:17:23 +0100 Subject: [PATCH 038/528] power: qpnp-fg: Use default DELTA_SOC without rounding the value * Using soc_to_setpoint function to determine DELTA_SOC value is resulting into a value of 3, which sometimes causes the battery percentage to instantly drop 2% instead of 1% Change-Id: I56156a51dbd8c67e362fce28e408234bbf6211cb Signed-off-by: Davide Garberi Revert "qpnp-fg: [kitakami] 2% drop fix" This reverts commit 374482a756e393a1dbb8a4fa2bd8389cc424d9d5. Signed-off-by: Andrey Cherepkov (cherry picked from commit 3e0d7d35c6fda5c46a3b069452b3bcc756889b7e) --- drivers/power/qpnp-fg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c index 53f482da7c36..8e3c958e714b 100644 --- a/drivers/power/qpnp-fg.c +++ b/drivers/power/qpnp-fg.c @@ -5400,7 +5400,7 @@ static int fg_common_hw_init(struct fg_chip *chip) #ifdef CONFIG_QPNP_FG_EXTENSION rc = fg_mem_masked_write(chip, settings[FG_MEM_DELTA_SOC].address, 0xFF, - settings[FG_MEM_DELTA_SOC].value == 1 ? 1 : soc_to_setpoint(settings[FG_MEM_DELTA_SOC].value), + settings[FG_MEM_DELTA_SOC].value, settings[FG_MEM_DELTA_SOC].offset); #else rc = fg_mem_masked_write(chip, settings[FG_MEM_DELTA_SOC].address, 0xFF, -- GitLab From b60f365ca8080b0cfe31e16a8cc57eb26466acad Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Thu, 21 Apr 2016 12:04:28 +0800 Subject: [PATCH 039/528] power_supply: Add SOC_REPORTING_READY property Add SOC_REORTING_READY property to indicate if the reporting SOC is the actual battery capacity. CRs-Fixed: 1001496 Change-Id: Ie0b17be6c9c4f2bf00d9902a597f4d41c7311857 Signed-off-by: Fenglin Wu Signed-off-by: GreyLeshy (cherry picked from commit 86ea05812ef89111d5b1be6770a5567a7d44931e) --- drivers/power/power_supply_sysfs.c | 1 + include/linux/power_supply.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 48755ffb4b7b..172dd9ea31f3 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -244,6 +244,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(vfloat_mv), POWER_SUPPLY_ATTR(fv_cmp_cfg), POWER_SUPPLY_ATTR(batt_aging), + POWER_SUPPLY_ATTR(soc_reporting_ready), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 8fa2eea87f6a..5d2ad5cb800a 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -196,6 +196,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_FV_CFG, POWER_SUPPLY_PROP_FV_CMP_CFG, POWER_SUPPLY_PROP_BATT_AGING, + POWER_SUPPLY_PROP_SOC_REPORTING_READY, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ -- GitLab From 500be43b16608a4d6d9f3122f745f8f45ac57f32 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 23 Jan 2017 17:33:53 -0500 Subject: [PATCH 040/528] add slub free list XOR encryption Based on the grsecurity feature, but with a per-cache random value. (cherry picked from commit 80ee3d9d0eff88de44c657a1a503e04e076ffc1b) --- mm/slub.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 976978832fac..f435c94e0573 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -259,20 +259,28 @@ static inline int check_valid_pointer(struct kmem_cache *s, static inline void *get_freepointer(struct kmem_cache *s, void *object) { - return *(void **)(object + s->offset); + unsigned long freepointer_addr = (unsigned long)object + s->offset; + return (void *)(*(unsigned long *)freepointer_addr ^ s->random ^ freepointer_addr); } static void prefetch_freepointer(const struct kmem_cache *s, void *object) { - prefetch(object + s->offset); + unsigned long freepointer_addr = (unsigned long)object + s->offset; + if (object) { + void **freepointer_ptr = (void **)(*(unsigned long *)freepointer_addr ^ s->random ^ freepointer_addr); + prefetch(freepointer_ptr); + } } static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) { + unsigned long __maybe_unused freepointer_addr; void *p; #ifdef CONFIG_DEBUG_PAGEALLOC - probe_kernel_read(&p, (void **)(object + s->offset), sizeof(p)); + freepointer_addr = (unsigned long)object + s->offset; + probe_kernel_read(&p, (void **)freepointer_addr, sizeof(p)); + return (void *)((unsigned long)p ^ s->random ^ freepointer_addr); #else p = get_freepointer(s, object); #endif @@ -281,7 +289,8 @@ static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) { - *(void **)(object + s->offset) = fp; + unsigned long freepointer_addr = (unsigned long)object + s->offset; + *(void **)freepointer_addr = (void *)((unsigned long)fp ^ s->random ^ freepointer_addr); } #ifdef CONFIG_64BIT -- GitLab From 916c8d4092d415855a4600c41d70114bf53ce3d3 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 1 Feb 2017 11:48:58 +0000 Subject: [PATCH 041/528] BACKPORT: arm64: Add CNTVCT_EL0 trap handler Since people seem to make a point in breaking the userspace visible counter, we have no choice but to trap the access. Add the required handler. Bug: 68266545 Acked-by: Thomas Gleixner Acked-by: Mark Rutland Signed-off-by: Marc Zyngier (cherry picked from commit 6126ce0588eb5a0752d5c8b5796a7fca324fd887) Change-Id: I0705f47c85a78040df38df18f51a4a22500b904d (cherry picked from commit 01ce9dd0848eb4677c92c50fb01631f45c535a43) --- arch/arm64/include/asm/esr.h | 37 ++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/entry.S | 11 ++++++++++- arch/arm64/kernel/traps.c | 21 ++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index 72674f4c3871..0cfad81d93f1 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -54,4 +54,41 @@ #define ESR_EL1_EC_BKPT32 (0x38) #define ESR_EL1_EC_BRK64 (0x3C) +/* ISS field definitions for System instruction traps */ +#define ESR_ELx_SYS64_ISS_RES0_SHIFT 22 +#define ESR_ELx_SYS64_ISS_RES0_MASK (UL(0x7) << ESR_ELx_SYS64_ISS_RES0_SHIFT) +#define ESR_ELx_SYS64_ISS_DIR_MASK 0x1 +#define ESR_ELx_SYS64_ISS_DIR_READ 0x1 +#define ESR_ELx_SYS64_ISS_DIR_WRITE 0x0 + +#define ESR_ELx_SYS64_ISS_RT_SHIFT 5 +#define ESR_ELx_SYS64_ISS_RT_MASK (UL(0x1f) << ESR_ELx_SYS64_ISS_RT_SHIFT) +#define ESR_ELx_SYS64_ISS_CRM_SHIFT 1 +#define ESR_ELx_SYS64_ISS_CRM_MASK (UL(0xf) << ESR_ELx_SYS64_ISS_CRM_SHIFT) +#define ESR_ELx_SYS64_ISS_CRN_SHIFT 10 +#define ESR_ELx_SYS64_ISS_CRN_MASK (UL(0xf) << ESR_ELx_SYS64_ISS_CRN_SHIFT) +#define ESR_ELx_SYS64_ISS_OP1_SHIFT 14 +#define ESR_ELx_SYS64_ISS_OP1_MASK (UL(0x7) << ESR_ELx_SYS64_ISS_OP1_SHIFT) +#define ESR_ELx_SYS64_ISS_OP2_SHIFT 17 +#define ESR_ELx_SYS64_ISS_OP2_MASK (UL(0x7) << ESR_ELx_SYS64_ISS_OP2_SHIFT) +#define ESR_ELx_SYS64_ISS_OP0_SHIFT 20 +#define ESR_ELx_SYS64_ISS_OP0_MASK (UL(0x3) << ESR_ELx_SYS64_ISS_OP0_SHIFT) +#define ESR_ELx_SYS64_ISS_SYS_MASK (ESR_ELx_SYS64_ISS_OP0_MASK | \ + ESR_ELx_SYS64_ISS_OP1_MASK | \ + ESR_ELx_SYS64_ISS_OP2_MASK | \ + ESR_ELx_SYS64_ISS_CRN_MASK | \ + ESR_ELx_SYS64_ISS_CRM_MASK) +#define ESR_ELx_SYS64_ISS_SYS_VAL(op0, op1, op2, crn, crm) \ + (((op0) << ESR_ELx_SYS64_ISS_OP0_SHIFT) | \ + ((op1) << ESR_ELx_SYS64_ISS_OP1_SHIFT) | \ + ((op2) << ESR_ELx_SYS64_ISS_OP2_SHIFT) | \ + ((crn) << ESR_ELx_SYS64_ISS_CRN_SHIFT) | \ + ((crm) << ESR_ELx_SYS64_ISS_CRM_SHIFT)) + +#define ESR_ELx_SYS64_ISS_SYS_OP_MASK (ESR_ELx_SYS64_ISS_SYS_MASK | \ + ESR_ELx_SYS64_ISS_DIR_MASK) + +#define ESR_ELx_SYS64_ISS_SYS_CNTVCT (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 2, 14, 0) | \ + ESR_ELx_SYS64_ISS_DIR_READ) + #endif /* __ASM_ESR_H */ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 17b99ae8dbd9..d050409057db 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -378,7 +378,7 @@ el0_sync: cmp x24, #ESR_EL1_EC_FP_EXC64 // FP/ASIMD exception b.eq el0_fpsimd_exc cmp x24, #ESR_EL1_EC_SYS64 // configurable trap - b.eq el0_undef + b.eq el0_sys cmp x24, #ESR_EL1_EC_SP_ALIGN // stack alignment exception b.eq el0_sp_pc cmp x24, #ESR_EL1_EC_PC_ALIGN // pc alignment exception @@ -491,6 +491,15 @@ el0_undef: enable_dbg_and_irq mov x0, sp b do_undefinstr +el0_sys: + /* + * System instructions, for trapped cache maintenance instructions + */ + enable_dbg + enable_irq + mov x0, x25 + mov x1, sp + b do_sysinstr el0_dbg: /* * Debug exception handling diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 0e1447cbadd7..85c176cf92b4 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -32,8 +32,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -381,6 +383,25 @@ die_sig: arm64_notify_die("Oops - undefined instruction", regs, &info, 0); } +static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs) +{ + int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT; + + if (rt != 31) + regs->regs[rt] = arch_counter_get_cntvct(); + regs->pc += 4; +} + +asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs) +{ + if ((esr & ESR_ELx_SYS64_ISS_SYS_OP_MASK) == ESR_ELx_SYS64_ISS_SYS_CNTVCT) { + cntvct_read_handler(esr, regs); + return; + } + + do_undefinstr(regs); +} + long compat_arm_syscall(struct pt_regs *regs); asmlinkage long do_ni_syscall(struct pt_regs *regs) -- GitLab From a91c8f7ef699a84b87f1a56d8f7380e68da9abf1 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 28 Nov 2014 05:26:35 +0000 Subject: [PATCH 042/528] arm64: ptrace: allow tracer to skip a system call If tracer modifies a syscall number to -1, this traced system call should be skipped with a return value specified in x0. This patch implements this semantics. Please note: * syscall entry tracing and syscall exit tracing (ftrace tracepoint and audit) are always executed, if enabled, even when skipping a system call (that is, -1). In this way, we can avoid a potential bug where audit_syscall_entry() might be called without audit_syscall_exit() at the previous system call being called, that would cause OOPs in audit_syscall_entry(). Signed-off-by: AKASHI Takahiro [will: fixed up conflict with blr rework] Signed-off-by: Will Deacon (cherry picked from commit 6c552f2c72849c6f45904587d9643cfed57aee40) --- arch/arm64/kernel/entry.S | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index d050409057db..2a24662ef9d9 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -651,12 +651,15 @@ ENDPROC(el0_svc) * switches, and waiting for our parent to respond. */ __sys_trace: - mov x0, sp + mov w0, #-1 // set default errno for + cmp scno, x0 // user-issued syscall(-1) + b.ne 1f + mov x0, #-ENOSYS + str x0, [sp, #S_X0] +1: mov x0, sp bl syscall_trace_enter adr lr, __sys_trace_return // return address - cmp w0, #RET_SKIP_SYSCALL_TRACE // skip syscall and tracing? - b.eq ret_to_user - cmp w0, #RET_SKIP_SYSCALL // skip syscall? + cmp w0, #-1 // skip the syscall? b.eq __sys_trace_return_skipped uxtw scno, w0 // syscall number (possibly new) mov x1, sp // pointer to regs @@ -670,8 +673,8 @@ __sys_trace: br x16 // call sys_* routine __sys_trace_return: - str x0, [sp] // save returned x0 -__sys_trace_return_skipped: // x0 already in regs[0] + str x0, [sp, #S_X0] // save returned x0 +__sys_trace_return_skipped: mov x0, sp bl syscall_trace_exit b ret_to_user -- GitLab From 48141858f8192d2669406aba0ced38f280b4aafb Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 14 Feb 2014 19:35:15 +0000 Subject: [PATCH 043/528] ARM64: unwind: Fix PC calculation The frame PC value in the unwind code used to just take the saved LR value and use that. That's incorrect as a stack trace, since it shows the return path stack, not the call path stack. In particular, it shows faulty information in case the bl is done as the very last instruction of one label, since the return point will be in the next label. That can easily be seen with tail calls to panic(), which is marked __noreturn and thus doesn't have anything useful after it. Easiest here is to just correct the unwind code and do a -4, to get the actual call site for the backtrace instead of the return site. Signed-off-by: Olof Johansson Cc: stable@vger.kernel.org Signed-off-by: Catalin Marinas Git-commit: e306dfd06fcb44d21c80acb8e5a88d55f3d1cf63 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Ian Maund (cherry picked from commit d330609f4832d5699c6727b18b1a15baf3aecbed) --- arch/arm64/kernel/stacktrace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 54122c4fd19a..55437ba1f5a4 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -48,7 +48,11 @@ int notrace unwind_frame(struct stackframe *frame) frame->sp = fp + 0x10; frame->fp = *(unsigned long *)(fp); - frame->pc = *(unsigned long *)(fp + 8); + /* + * -4 here because we care about the PC at time of bl, + * not where the return will go. + */ + frame->pc = *(unsigned long *)(fp + 8) - 4; return 0; } -- GitLab From 6ae8623538f0e824be71018b9ce5302956b2229f Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Mon, 23 Feb 2015 19:43:51 -0800 Subject: [PATCH 044/528] power: add partial-resume framework Partial resume refers to the concept of not waking up userspace when the kernel comes out of suspend for certain types of events that we wish to discard. An example is a network packet that can be disacarded in the kernel, or spurious wakeup event that we wish to ignore. Partial resume allows drivers to register callbacks, one one hand, and provides hooks into the PM's suspend/resume mechanism, on the other. When a device resumes from suspend, the core suspend/resume code invokes partialresume to check to see if the set of wakeup interrupts all have matching handlers. If this is not the case, the PM subsystem can continue to resume as before. If all of the wakeup sources have matching handlers, then those are invoked in turn (and can block), and if all of them reach consensus that the reason for the wakeup can be ignored, they say so to the PM subsystem, which goes right back into suspend. This latter support is implemented in a separate change. Signed-off-by: Iliyan Malchev Change-Id: Id50940bb22a550b413412264508d259f7121d442 (cherry picked from commit f2d448b9923ffa70871ab6b6eff35d78521bac16) --- include/linux/partialresume.h | 54 ++++++++++ kernel/power/Kconfig | 11 ++ kernel/power/Makefile | 1 + kernel/power/partialresume.c | 189 ++++++++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+) create mode 100644 include/linux/partialresume.h create mode 100644 kernel/power/partialresume.c diff --git a/include/linux/partialresume.h b/include/linux/partialresume.h new file mode 100644 index 000000000000..69dfa0bc0009 --- /dev/null +++ b/include/linux/partialresume.h @@ -0,0 +1,54 @@ +/* include/linux/partialresume.h + * + * Copyright (C) 2015 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_PARTIALRESUME_H +#define _LINUX_PARTIALRESUME_H + +#ifdef CONFIG_PARTIALRESUME + +#include + +struct partial_resume_stats { + unsigned total; + unsigned total_yes; +}; + +struct partial_resume { + struct list_head next_handler; + struct list_head next_match; + int irq; + struct partial_resume_stats stats; + bool (*partial_resume)(struct partial_resume *); +}; + +int register_partial_resume(struct partial_resume *handler); +void unregister_partial_resume(struct partial_resume *handler); + +bool suspend_again_match(const struct list_head *irqs, + const struct list_head *unfinished); +bool suspend_again_consensus(void); + +#else /* !CONFIG_PARTIALRESUME */ + +struct partial_resume; +static inline int register_partial_resume(struct partial_resume *handler) { return 0; } +static inline void unregister_partial_resume(struct partial_resume *handler) {} +static inline bool suspend_again_match(const struct list_head *irqs, size_t irqs_len) { return false; } +static inline bool suspend_again_consensus(void) { return false; } + +#endif + +#endif + diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 6a9d6af4dd86..3955bef8f3bc 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -327,3 +327,14 @@ config WAKEUP_IRQ_DEBUG ---help--- This enables debug information about wakeup interrupts using sysfs (/sys/kernel/). + +config PARTIALRESUME + bool "Partial-resume framework" + ---help--- + Provides hooks for drivers to register partial-resume handlers. + Similar to suspend_again support already in kernel, except that it + operates with kernel threads unfrozen and userspace still frozen, + allowing callbacks to block on work queues and kernel threads. + Partial resume will occur only if all wakeup sources have + partial-resume handlers associated with them, and they all return + true. diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 845b34bcd4d5..6dcf5bd75a7b 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o obj-$(CONFIG_SUSPEND) += wakeup_reason.o obj-$(CONFIG_WAKEUP_IRQ_DEBUG) += wakeup_irq_debug.o +obj-$(CONFIG_PARTIALRESUME) += partialresume.o diff --git a/kernel/power/partialresume.c b/kernel/power/partialresume.c new file mode 100644 index 000000000000..295c3f755000 --- /dev/null +++ b/kernel/power/partialresume.c @@ -0,0 +1,189 @@ +/* kernel/power/partialresume.c + * + * Copyright (C) 2015 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static DEFINE_MUTEX(pr_handlers_lock); +static LIST_HEAD(pr_handlers); +static LIST_HEAD(pr_matches); +static struct partial_resume_stats match_stats; +static struct partial_resume_stats consensus_stats; +static struct kobject *partialresume; + +bool suspend_again_match(const struct list_head *irqs, + const struct list_head *unfinished) +{ + const struct wakeup_irq_node *i; + struct partial_resume *h, *match; + + INIT_LIST_HEAD(&pr_matches); + + match_stats.total++; + + if (!irqs || list_empty(irqs)) + return false; + + list_for_each_entry(i, irqs, next) { + match = NULL; + list_for_each_entry(h, &pr_handlers, next_handler) { + if (i->irq == h->irq) { + match = h; + break; + } + } + if (!match) { + pr_debug("%s: wakeup irq %d does not have a handler\n", __func__, i->irq); + return false; + } + list_add(&match->next_match, &pr_matches); + } + + match_stats.total_yes++; + + return true; +} + + +bool suspend_again_consensus(void) +{ + struct partial_resume *h; + + BUG_ON(list_empty(&pr_matches)); + list_for_each_entry(h, &pr_matches, next_match) { + h->stats.total++; + if (!h->partial_resume(h)) { + pr_debug("%s: partial-resume for %d: false\n", __func__, h->irq); + return false; + } + h->stats.total_yes++; + pr_debug("%s: partial-resume for %d: true\n", __func__, h->irq); + } + + consensus_stats.total_yes++; + + return true; +} + + +int register_partial_resume(struct partial_resume *handler) +{ + struct partial_resume *e; + + if (!handler || !handler->irq || !handler->partial_resume) + return -EINVAL; + + mutex_lock(&pr_handlers_lock); + list_for_each_entry(e, &pr_handlers, next_handler) { + if (e->irq == handler->irq) { + if (e->partial_resume == handler->partial_resume) + return 0; + pr_err("%s: error registering %pF for irq %d: "\ + "%pF already registered\n", + __func__, + handler->partial_resume, + e->irq, + e->partial_resume); + mutex_unlock(&pr_handlers_lock); + return -EIO; + } + } + + list_add(&handler->next_handler, &pr_handlers); + mutex_unlock(&pr_handlers_lock); + return 0; +} + +void unregister_partial_resume(struct partial_resume *handler) +{ + mutex_lock(&pr_handlers_lock); + list_del(&handler->next_handler); + mutex_unlock(&pr_handlers_lock); +} + + +static ssize_t partialresume_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + ssize_t offset = 0; + struct partial_resume *h; + + offset += sprintf(buf + offset, "global: %d %d %d \n", + match_stats.total, + match_stats.total_yes, + consensus_stats.total_yes); + + mutex_lock(&pr_handlers_lock); + + list_for_each_entry(h, &pr_handlers, next_handler) { + offset += sprintf(buf + offset, "%d: %d %d\n", + h->irq, + h->stats.total, + h->stats.total_yes); + } + + mutex_unlock(&pr_handlers_lock); + + return offset; +} + +static struct kobj_attribute partialresume_stats = __ATTR_RO(partialresume_stats); + +static struct attribute *partialresume_stats_attrs[] = { + &partialresume_stats.attr, + NULL, +}; +static struct attribute_group partialresume_stats_attr_group = { + .attrs = partialresume_stats_attrs, +}; + +int __init partial_resume_init(void) +{ + int rc = -EIO; + + partialresume = kobject_create_and_add("partialresume", kernel_kobj); + if (!partialresume) { + pr_warning("%s: failed to create a sysfs kobject\n", __func__); + goto fail; + } + + rc = sysfs_create_group(partialresume, &partialresume_stats_attr_group); + if (rc) { + pr_warning("%s: failed to create a sysfs group\n", __func__); + goto fail_kobject_put; + } + + return 0; + +#if 0 +fail_remove_group: + sysfs_remove_group(partialresume, &partialresume_stats_attr_group); +#endif +fail_kobject_put: + kobject_put(partialresume); +fail: + return rc; +} + +subsys_initcall(partial_resume_init); -- GitLab From 5902544d5394f72f5439078b344a5d6d2082340c Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Wed, 7 Mar 2018 16:00:07 -0700 Subject: [PATCH 045/528] drivers: qcom: lpm-stats: Fix undefined access error In cleanup_stats(), a freed memory pointer pos might be accessed for list traversal. Switch to using _safe() variant of the list API to prevent undefined accesses. Bug: 79421260 Change-Id: I7d068cb7813ccb9bfdbcab4646b4ec890145828a Signed-off-by: Mahesh Sivasubramanian (cherry picked from commit 13af073dc34ebfbb888e03b96bb9b204088ed7c2) --- drivers/power/qcom/lpm-stats.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/power/qcom/lpm-stats.c b/drivers/power/qcom/lpm-stats.c index 321e13c2b7ea..f4f22007b4cb 100644 --- a/drivers/power/qcom/lpm-stats.c +++ b/drivers/power/qcom/lpm-stats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -590,11 +590,14 @@ static void cleanup_stats(struct lpm_stats *stats) { struct list_head *centry = NULL; struct lpm_stats *pos = NULL; + struct lpm_stats *n = NULL; centry = &stats->child; - list_for_each_entry_reverse(pos, centry, sibling) { - if (!list_empty(&pos->child)) + list_for_each_entry_safe_reverse(pos, n, centry, sibling) { + if (!list_empty(&pos->child)) { cleanup_stats(pos); + continue; + } list_del_init(&pos->child); -- GitLab From 10202544fed54dfccf0d7a3fce262302baf14dfa Mon Sep 17 00:00:00 2001 From: annamraj Date: Wed, 11 Apr 2018 10:42:13 +0530 Subject: [PATCH 046/528] msm: camera: Fix for Possible information leak issue Fix for possible information leak issue because of unintialised variable Which can be accesed from userspace in camera fd driver Bug: 73889358 Signed-off-by: annamraj Change-Id: I4552c4829e9532d848e46fd123316b26105e310e (cherry picked from commit 641b8546fe4d4e00381c7b141ca07cf8b8873f21) --- drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c index b4616f60dce1..7dd00e1c8825 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -384,7 +384,7 @@ static int msm_fd_open(struct file *file) ctx->mem_pool.fd_device = ctx->fd_device; ctx->mem_pool.domain_num = ctx->fd_device->iommu_domain_num; - ctx->stats = vmalloc(sizeof(*ctx->stats) * MSM_FD_MAX_RESULT_BUFS); + ctx->stats = vzalloc(sizeof(*ctx->stats) * MSM_FD_MAX_RESULT_BUFS); if (!ctx->stats) { dev_err(device->dev, "No memory for face statistics\n"); ret = -ENOMEM; -- GitLab From 42c08285ffa3a1a8289753a19327b2ca486345ba Mon Sep 17 00:00:00 2001 From: Harsh Sahu Date: Fri, 23 Mar 2018 00:15:52 -0700 Subject: [PATCH 047/528] msm: mdss: check buffer size before writing to user buffer Check the number of bytes to copy against the size of the user buffer before copy to user to avoid buffer overflow. Bug: 79422277 Change-Id: Icdd3d4e755deca19fa431e903620bd9e4c701c89 Signed-off-by: Harsh Sahu Signed-off-by: Siqi Lin (cherry picked from commit 0f94e29a9bced8b163b7057b777579182a81fa0c) --- drivers/video/msm/mdss/mdss_debug_xlog.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/video/msm/mdss/mdss_debug_xlog.c b/drivers/video/msm/mdss/mdss_debug_xlog.c index 3c31de418292..008ba402d52b 100644 --- a/drivers/video/msm/mdss/mdss_debug_xlog.c +++ b/drivers/video/msm/mdss/mdss_debug_xlog.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -546,6 +546,11 @@ static ssize_t mdss_xlog_dump_read(struct file *file, char __user *buff, if (__mdss_xlog_dump_calc_range()) { len = mdss_xlog_dump_entry(xlog_buf, MDSS_XLOG_BUF_MAX); + if (len < 0 || len > count) { + pr_err("len is more than the size of user buffer\n"); + return 0; + } + if (copy_to_user(buff, xlog_buf, len)) return -EFAULT; *ppos += len; -- GitLab From cb54b9dbf455d51ff391ff8a71ea05438f892cd3 Mon Sep 17 00:00:00 2001 From: Katish Paran Date: Mon, 11 May 2015 15:33:28 +0530 Subject: [PATCH 048/528] diag: dci: Add mutex protection while accessing client details Currently while extracting events and logs information from the data read over peripherals, the clients details are accessed without mutex protection. As the client access may happen from multiple context, mutex protection is needed. This patch resolves the same. Bug: 62378232 Change-Id: I9bd115e1cd9eebc625f4a68854d554ff874d866d Signed-off-by: Katish Paran (cherry picked from commit ab17770625ffe74df3b423311fa717225d1a445e) --- drivers/char/diag/diag_dci.c | 2 +- drivers/char/diag/diagchar_core.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index a46f4eef3537..97f4f3b34d74 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index ab9d5fb4d955..dd7cf2821d32 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1585,6 +1585,7 @@ exit: goto end; } } + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) { if (driver->smd_dci[i].ch) { queue_work(driver->diag_dci_wq, @@ -1602,6 +1603,7 @@ exit: } } } + mutex_unlock(&driver->diagchar_mutex); mutex_unlock(&driver->dci_mutex); goto end; } -- GitLab From be64e222f0ba07f45304cb2356371e198af3101b Mon Sep 17 00:00:00 2001 From: Mohit Aggarwal Date: Mon, 21 Mar 2016 12:57:38 +0530 Subject: [PATCH 049/528] diag: Fix for possible dci stale entries This patch provides the protection to dci client entries from corruption. CRs-Fixed: 984942 992683 Bug: 62378232 Change-Id: Ifcd9f14dc03d9e42a31b3e126839489881e98303 Signed-off-by: Manoj Prabhu B Signed-off-by: Mohit Aggarwal (cherry picked from commit 1ede4694d5b28e1992c61613d67a6e3a18f96222) --- drivers/char/diag/diag_dci.c | 4 +-- drivers/char/diag/diagchar_core.c | 50 +++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 97f4f3b34d74..6080698302ed 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1325,6 +1325,7 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) * which log entries in the cumulative logs that need * to be updated on the peripheral. */ + mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); if (entry->client_info.token != DCI_LOCAL_PROC) @@ -1336,6 +1337,7 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) client_log_mask_ptr += 514; } } + mutex_unlock(&driver->dci_mutex); mutex_lock(&dci_log_mask_mutex); /* Update the appropriate dirty bits in the cumulative mask */ @@ -3122,8 +3124,6 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) } queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work); - mutex_unlock(&driver->dci_mutex); - return DIAG_DCI_NO_ERROR; } diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index dd7cf2821d32..d96a67f1e489 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -348,9 +348,11 @@ static int diagchar_close(struct inode *inode, struct file *file) * This will specially help in case of ungraceful exit of any DCI client * This call will remove any pending registrations of such client */ - dci_entry = dci_lookup_client_entry_pid(current->tgid); + mutex_lock(&driver->dci_mutex); + dci_entry = dci_lookup_client_entry_pid(current->pid); if (dci_entry) diag_dci_deinit_client(dci_entry); + mutex_unlock(&driver->dci_mutex); /* If the exiting process is the socket process */ mutex_lock(&driver->diagchar_mutex); if (driver->socket_process && @@ -1263,16 +1265,25 @@ long diagchar_compat_ioctl(struct file *filp, dci_client = diag_dci_get_client_entry(client_id); if (!dci_client) return DIAG_DCI_NOT_SUPPORTED; +<<<<<<< HEAD +======= + } +>>>>>>> 1ede4694d5b2 (diag: Fix for possible dci stale entries) result = diag_dci_deinit_client(dci_client); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_SUPPORT: result = diag_ioctl_dci_support(ioarg); break; case DIAG_IOCTL_DCI_HEALTH_STATS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_health_stats(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_LOG_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_log_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_EVENT_STATUS: mutex_lock(&driver->dci_mutex); @@ -1280,16 +1291,24 @@ long diagchar_compat_ioctl(struct file *filp, mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_LOGS: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_log_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_EVENTS: + mutex_lock(&driver->dci_mutex); if (copy_from_user(&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_event_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_LSM_DEINIT: result = diag_ioctl_lsm_deinit(); @@ -1309,7 +1328,9 @@ long diagchar_compat_ioctl(struct file *filp, result = 1; break; case DIAG_IOCTL_VOTE_REAL_TIME: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_vote_real_time(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_GET_REAL_TIME: result = diag_ioctl_get_real_time(ioarg); @@ -1362,16 +1383,25 @@ long diagchar_ioctl(struct file *filp, dci_client = diag_dci_get_client_entry(client_id); if (!dci_client) return DIAG_DCI_NOT_SUPPORTED; +<<<<<<< HEAD +======= + } +>>>>>>> 1ede4694d5b2 (diag: Fix for possible dci stale entries) result = diag_dci_deinit_client(dci_client); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_SUPPORT: result = diag_ioctl_dci_support(ioarg); break; case DIAG_IOCTL_DCI_HEALTH_STATS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_health_stats(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_LOG_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_log_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_EVENT_STATUS: mutex_lock(&driver->dci_mutex); @@ -1379,16 +1409,24 @@ long diagchar_ioctl(struct file *filp, mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_LOGS: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_log_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_EVENTS: + mutex_lock(&driver->dci_mutex); if (copy_from_user(&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_event_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_LSM_DEINIT: result = diag_ioctl_lsm_deinit(); @@ -1408,7 +1446,9 @@ long diagchar_ioctl(struct file *filp, result = 1; break; case DIAG_IOCTL_VOTE_REAL_TIME: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_vote_real_time(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_GET_REAL_TIME: result = diag_ioctl_get_real_time(ioarg); -- GitLab From 01059ed0ac638074e8d1e9f5d4a4c25aab8b3ed0 Mon Sep 17 00:00:00 2001 From: Mohit Aggarwal Date: Thu, 6 Jul 2017 10:16:52 +0530 Subject: [PATCH 050/528] diag: Add protection while de-initializing clients Currently, while de-initializing clients, there is a possibility of using already freed memory. The patch adds proper protection to fix the issue. CRs-Fixed: 2068569 Bug: 68870904 Change-Id: I4b397a82e03fa2f1c84cfa8ca912cdb6a51ba08b Signed-off-by: Mohit Aggarwal (cherry picked from commit 51639fdeb18a0ab7a98c4466f6db84d5062b1060) --- drivers/char/diag/diagchar_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index d96a67f1e489..6201968ab6f9 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1051,14 +1051,18 @@ static int diag_ioctl_lsm_deinit(void) { int i; + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; - if (i == driver->num_clients) + if (i == driver->num_clients) { + mutex_unlock(&driver->diagchar_mutex); return -EINVAL; + } driver->data_ready[i] |= DEINIT_TYPE; + mutex_unlock(&driver->diagchar_mutex); wake_up_interruptible(&driver->wait_q); return 1; -- GitLab From 50745e4788a866ec2a4eb52d9b6761ced6109109 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Tue, 23 Jan 2018 13:11:41 -0800 Subject: [PATCH 051/528] diag: Protect the decrement of number of diag clients In diagchar_open() protect the decrement of number of diag clients so that there will be no race conditions while reading the value from other functions. Bug: 79421261 Change-Id: I0e2fb5331eec9c7bba39e7d881b69559256833a3 Signed-off-by: Sreelakshmi Gownipalli (cherry picked from commit eb2a2fb1584f0d6338902d375f1d3838a124799f) --- drivers/char/diag/diagchar_core.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 6201968ab6f9..d3b7242db1dc 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2015, 2017-2018 The Linux Foundation. + * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -322,9 +323,9 @@ static int diagchar_open(struct inode *inode, struct file *file) return -ENOMEM; fail: - mutex_unlock(&driver->diagchar_mutex); driver->num_clients--; - pr_alert("diag: Insufficient memory for new client"); + mutex_unlock(&driver->diagchar_mutex); + pr_err_ratelimited("diag: Insufficient memory for new client"); return -ENOMEM; } @@ -1269,10 +1270,6 @@ long diagchar_compat_ioctl(struct file *filp, dci_client = diag_dci_get_client_entry(client_id); if (!dci_client) return DIAG_DCI_NOT_SUPPORTED; -<<<<<<< HEAD -======= - } ->>>>>>> 1ede4694d5b2 (diag: Fix for possible dci stale entries) result = diag_dci_deinit_client(dci_client); mutex_unlock(&driver->dci_mutex); break; -- GitLab From 435b5558335480526ee46ceb1303f5bf9fdcf529 Mon Sep 17 00:00:00 2001 From: Mike B Date: Fri, 26 Feb 2021 22:13:51 +0100 Subject: [PATCH 052/528] diag: not finding original commit. adding mutex locks --- drivers/char/diag/diagchar_core.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index d3b7242db1dc..4e3c28606875 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1264,12 +1264,17 @@ long diagchar_compat_ioctl(struct file *filp, result = diag_ioctl_dci_reg(ioarg); break; case DIAG_IOCTL_DCI_DEINIT: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } dci_client = diag_dci_get_client_entry(client_id); - if (!dci_client) + if (!dci_client) { + mutex_unlock(&driver->dci_mutex); return DIAG_DCI_NOT_SUPPORTED; + } result = diag_dci_deinit_client(dci_client); mutex_unlock(&driver->dci_mutex); break; @@ -1378,16 +1383,17 @@ long diagchar_ioctl(struct file *filp, result = diag_ioctl_dci_reg(ioarg); break; case DIAG_IOCTL_DCI_DEINIT: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } dci_client = diag_dci_get_client_entry(client_id); - if (!dci_client) + if (!dci_client) { + mutex_unlock(&driver->dci_mutex); return DIAG_DCI_NOT_SUPPORTED; -<<<<<<< HEAD -======= } ->>>>>>> 1ede4694d5b2 (diag: Fix for possible dci stale entries) result = diag_dci_deinit_client(dci_client); mutex_unlock(&driver->dci_mutex); break; -- GitLab From f71c1b1ae3e04b4a57d46a1b3094a4b667070f24 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Thu, 18 Feb 2016 14:15:04 +0530 Subject: [PATCH 053/528] diag: dci: Add protection while de-initializing clients Currently, while de-initializing dci clients, there is a possibility to access stale entries. This patch fixes this issue by adding proper protection mechanism. CRs-Fixed: 961469 Bug: 62378232 Change-Id: I829c9497eeb356662a6531592c66108e615ce6e4 Signed-off-by: Mohit Aggarwal Signed-off-by: Manoj Prabhu B (cherry picked from commit 652f01eb8b5e24190c9ea0ca31e5fc7ff4150636) --- drivers/char/diag/diag_dci.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 6080698302ed..91c4b2f65a49 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -3010,14 +3010,15 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) if (!entry) return DIAG_DCI_NOT_SUPPORTED; - token = entry->client_info.token; - mutex_lock(&driver->dci_mutex); + + token = entry->client_info.token; /* * Remove the entry from the list before freeing the buffers * to ensure that we don't have any invalid access. */ - list_del(&entry->track); + if (!list_empty(&entry->track)) + list_del(&entry->track); driver->num_dci_client--; /* * Clear the client's log and event masks, update the cumulative @@ -3046,7 +3047,8 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) req_entry = list_entry(start, struct dci_pkt_req_entry_t, track); if (req_entry->client_id == entry->client_info.client_id) { - list_del(&req_entry->track); + if (!list_empty(&req_entry->track)) + list_del(&req_entry->track); kfree(req_entry); } } @@ -3055,7 +3057,8 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) mutex_lock(&entry->write_buf_mutex); list_for_each_entry_safe(buf_entry, temp, &entry->list_write_buf, buf_track) { - list_del(&buf_entry->buf_track); + if (!list_empty(&buf_entry->buf_track)) + list_del(&buf_entry->buf_track); if (buf_entry->buf_type == DCI_BUF_SECONDARY) { mutex_lock(&buf_entry->data_mutex); diagmem_free(driver, buf_entry->data, POOL_TYPE_DCI); -- GitLab From 4238c1364db60534792f07803749bfd46a56c210 Mon Sep 17 00:00:00 2001 From: Mohit Aggarwal Date: Mon, 21 Mar 2016 12:57:38 +0530 Subject: [PATCH 054/528] diag: Fix for possible dci stale entries This patch provides the protection to dci client entries from corruption. CRs-Fixed: 984942 992683 Bug: 62378232 Change-Id: Ifcd9f14dc03d9e42a31b3e126839489881e98303 Signed-off-by: Manoj Prabhu B Signed-off-by: Mohit Aggarwal (cherry picked from commit 1ede4694d5b28e1992c61613d67a6e3a18f96222) --- drivers/char/diag/diag_dci.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 91c4b2f65a49..560d753c5439 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -3010,8 +3010,6 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) if (!entry) return DIAG_DCI_NOT_SUPPORTED; - mutex_lock(&driver->dci_mutex); - token = entry->client_info.token; /* * Remove the entry from the list before freeing the buffers -- GitLab From 60ec1b77a8dc0092a75b284b115ef29fd6a74d9b Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Wed, 17 Jan 2018 21:03:52 +0530 Subject: [PATCH 055/528] diag: Validate copying length against source buffer length There a possibility of out-of-bound read because of not validating source buffer length against length that about to be copied. The patch adds proper check for validating length before copying data Bug: 70399602 CRs-Fixed: 2163793 Change-Id: I7c93839d0c4d83024ce23a0ce494d09dd08567a9 Signed-off-by: Hardik Arya (cherry picked from commit 1cc5ac5cbc03ed28f9b6bee781fbf988f3513875) --- drivers/char/diag/diag_dci.c | 96 ++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 26 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 560d753c5439..8f68db8e09a0 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1106,18 +1106,32 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; - length = *(uint16_t *)(buf + 1); /* total length of event series */ - if (length == 0) { - pr_err("diag: Incoming dci event length is invalid\n"); + if (!buf) { + pr_err("diag: In %s buffer is NULL\n", __func__); return; } - /* Move directly to the start of the event series. 1 byte for - * event code and 2 bytes for the length field. - */ - /* The length field indicates the total length removing the cmd_code - * and the lenght field. The event parsing in that case should happen + + /* + * 1 byte for event code and 2 bytes for the length field. + * The length field indicates the total length removing the cmd_code + * and the length field. The event parsing in that case should happen * till the end. */ + if (len < 3) { + pr_err("diag: In %s invalid len: %d\n", __func__, len); + return; + } + length = *(uint16_t *)(buf + 1); /* total length of event series */ + if ((length == 0) || (len != (length + 3))) { + pr_err("diag: Incoming dci event length: %d is invalid\n", + length); + return; + } + /* + * Move directly to the start of the event series. + * The event parsing should happen from start of event + * series till the end. + */ temp_len = 3; while (temp_len < length) { event_id_packet = *(uint16_t *)(buf + temp_len); @@ -1134,30 +1148,60 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) * necessary. */ timestamp_len = 8; - memcpy(timestamp, buf + temp_len + 2, timestamp_len); + if ((temp_len + timestamp_len + 2) <= len) + memcpy(timestamp, buf + temp_len + 2, + timestamp_len); + else { + pr_err("diag: Invalid length in %s, len: %d, temp_len: %d", + __func__, len, temp_len); + return; + } } /* 13th and 14th bit represent the payload length */ if (((event_id_packet & 0x6000) >> 13) == 3) { payload_len_field = 1; - payload_len = *(uint8_t *) + if ((temp_len + timestamp_len + 3) <= len) { + payload_len = *(uint8_t *) (buf + temp_len + 2 + timestamp_len); - if (payload_len < (MAX_EVENT_SIZE - 13)) { - /* copy the payload length and the payload */ + } else { + pr_err("diag: Invalid length in %s, len: %d, temp_len: %d", + __func__, len, temp_len); + return; + } + if ((payload_len < (MAX_EVENT_SIZE - 13)) && + ((temp_len + timestamp_len + payload_len + 3) <= len)) { + /* + * Copy the payload length and the payload + * after skipping temp_len bytes for already + * parsed packet, timestamp_len for timestamp + * buffer, 2 bytes for event_id_packet. + */ memcpy(event_data + 12, buf + temp_len + 2 + timestamp_len, 1); memcpy(event_data + 13, buf + temp_len + 2 + timestamp_len + 1, payload_len); } else { - pr_err("diag: event > %d, payload_len = %d\n", - (MAX_EVENT_SIZE - 13), payload_len); + pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n", + (MAX_EVENT_SIZE - 13), payload_len, temp_len); return; } } else { payload_len_field = 0; payload_len = (event_id_packet & 0x6000) >> 13; - /* copy the payload */ - memcpy(event_data + 12, buf + temp_len + 2 + + /* + * Copy the payload after skipping temp_len bytes + * for already parsed packet, timestamp_len for + * timestamp buffer, 2 bytes for event_id_packet. + */ + if ((payload_len < (MAX_EVENT_SIZE - 12)) && + ((temp_len + timestamp_len + payload_len + 2) <= len)) + memcpy(event_data + 12, buf + temp_len + 2 + timestamp_len, payload_len); + else { + pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n", + (MAX_EVENT_SIZE - 12), payload_len, temp_len); + return; + } } /* Before copying the data to userspace, check if we are still @@ -1275,19 +1319,19 @@ void extract_dci_log(unsigned char *buf, int len, int data_source, int token) pr_err("diag: In %s buffer is NULL\n", __func__); return; } - - /* The first six bytes for the incoming log packet contains - * Command code (2), the length of the packet (2) and the length - * of the log (2) + /* + * The first eight bytes for the incoming log packet contains + * Command code (2), the length of the packet (2), the length + * of the log (2) and log code (2) */ - log_code = *(uint16_t *)(buf + 6); - read_bytes += sizeof(uint16_t) + 6; - if (read_bytes > len) { - pr_err("diag: Invalid length in %s, len: %d, read: %d", - __func__, len, read_bytes); + if (len < 8) { + pr_err("diag: In %s invalid len: %d\n", __func__, len); return; } + log_code = *(uint16_t *)(buf + 6); + read_bytes += sizeof(uint16_t) + 6; + /* parse through log mask table of each client and check mask */ mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { -- GitLab From e6dbf6f5deb93cb9325757fa7c9e041cd930b2a0 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Mon, 29 Jan 2018 13:17:13 -0800 Subject: [PATCH 056/528] diag: Add conditional check for len in dci_process_ctrl_status() Add correct conditional check for len in dci_process_ctrl_status() to prevent buffer overflow. Bug: 70528036 Change-Id: Id73ed1c8b104428eceef0544ce2858160cc08fd2 Signed-off-by: Sreelakshmi Gownipalli (cherry picked from commit 58e7effda1fc189c1e5f76d5fa8f62bf486d3814) --- drivers/char/diag/diag_dci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 8f68db8e09a0..365a8f1c2268 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -824,7 +824,7 @@ static void dci_process_ctrl_status(unsigned char *buf, int len, int token) read_len += sizeof(struct diag_ctrl_dci_status); for (i = 0; i < header->count; i++) { - if (read_len > len) { + if (read_len > (len - 2)) { pr_err("diag: In %s, Invalid length len: %d\n", __func__, len); return; -- GitLab From 3111c96031cfff0f3d6e062d6958ddc4823349bd Mon Sep 17 00:00:00 2001 From: Andrew Chant Date: Fri, 6 Apr 2018 16:14:42 -0700 Subject: [PATCH 057/528] diag: dci: check signed values for negativity when comparing a signed value vs sizeof, make sure it's >= 0 so that when promoted to signed for comparison it won't lead to unexpected results. Bug: 70528036 Change-Id: I99a1220598e67e3ce5c99d425e84c79639121838 Signed-off-by: Andrew Chant (cherry picked from commit 7970e95b194b8e4da3c959e899c82c1402f29ea3) --- drivers/char/diag/diag_dci.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 365a8f1c2268..b5fa46591dc2 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -804,12 +804,12 @@ static void dci_process_ctrl_status(unsigned char *buf, int len, int token) { struct diag_ctrl_dci_status *header = NULL; unsigned char *temp = buf; - uint32_t read_len = 0; + unsigned int read_len = 0; uint8_t i; int peripheral_mask, status; - if (!buf || (len < sizeof(struct diag_ctrl_dci_status))) { - pr_err("diag: In %s, invalid buf %pK or length: %d\n", + if (!buf || len < 2 || (len < sizeof(struct diag_ctrl_dci_status))) { + pr_err("diag: In %s, invalid buf %p or length: %d\n", __func__, buf, len); return; } @@ -866,7 +866,9 @@ static void dci_process_ctrl_handshake_pkt(unsigned char *buf, int len, unsigned char *temp = buf; int err = 0; - if (!buf || (len < sizeof(struct diag_ctrl_dci_handshake_pkt))) + if (!buf) + return; + if (len < 0 || len < sizeof(struct diag_ctrl_dci_handshake_pkt)) return; if (!VALID_DCI_TOKEN(token)) -- GitLab From 1f96cce151f7853f8f74dcca25de58d63cba9a67 Mon Sep 17 00:00:00 2001 From: Karthikeyan Mani Date: Tue, 6 Mar 2018 11:04:49 -0800 Subject: [PATCH 058/528] ASoC: msm: qdsp6v2: check for buffer size before read Check for debugfs ops buf size passed before reading to eliminate the possibility of reading out of bounds. Bug: 77528653 Change-Id: I28fd60ce93256b6b0bad62b449092a891cc15463 Signed-off-by: Karthikeyan Mani (cherry picked from commit d94553d4eba910b534770c257f13ad98bcf2828d) --- sound/soc/msm/qdsp6v2/q6asm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index b9ea67c427ae..b58a5612cad1 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -149,6 +149,11 @@ static ssize_t audio_output_latency_dbgfs_read(struct file *file, pr_err("%s: out_buffer is null\n", __func__); return 0; } + if (count < OUT_BUFFER_SIZE) { + pr_err("%s: read size %d exceeds buf size %zd\n", __func__, + OUT_BUFFER_SIZE, count); + return 0; + } snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",\ out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,\ out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec); @@ -202,6 +207,11 @@ static ssize_t audio_input_latency_dbgfs_read(struct file *file, pr_err("%s: in_buffer is null\n", __func__); return 0; } + if (count < IN_BUFFER_SIZE) { + pr_err("%s: read size %d exceeds buf size %zd\n", __func__, + IN_BUFFER_SIZE, count); + return 0; + } snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",\ in_cont_tv.tv_sec, in_cont_tv.tv_usec); return simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos, -- GitLab From 91f1a8cb9ae059cccb7a64e991d846bb240518b5 Mon Sep 17 00:00:00 2001 From: raghavendra ambadas Date: Fri, 19 Jan 2018 13:49:21 +0530 Subject: [PATCH 059/528] msm: mdss: fix race condition between rotator api's current code does not have locking mechanism between rotator play and rotator unset, due to which race condition can occur when concurrent threads invoke rotator play and unset ioctl cmd. So use mutex lock to avoid such issues. Bug: 77527701 Change-Id: I6a7cd16ee8a8f3a4c9397e87b8c109809ec6f573 Signed-off-by: Raghavendra Ambadas Signed-off-by: Steve Pfetsch (cherry picked from commit 113a9f5cdb5c52c856de4c09180df9a99b813658) --- drivers/video/msm/mdss/mdss_mdp_rotator.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c index 1019016a5828..136375cf0cf6 100644 --- a/drivers/video/msm/mdss/mdss_mdp_rotator.c +++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -43,6 +43,7 @@ struct mdss_mdp_rot_pipe { struct mdss_mdp_rot_session_mgr { struct list_head queue; struct mutex session_lock; + struct mutex req_lock; int session_id; int session_count; @@ -77,6 +78,7 @@ int mdss_mdp_rot_mgr_init(void) mutex_init(&rot_mgr->session_lock); mutex_init(&rot_mgr->pipe_lock); + mutex_init(&rot_mgr->req_lock); INIT_LIST_HEAD(&rot_mgr->queue); rot_mgr->rot_work_queue = create_workqueue("rot_commit_workq"); if (!rot_mgr->rot_work_queue) { @@ -1017,9 +1019,11 @@ int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd, u32 flgs; struct mdss_mdp_data src_buf; + mutex_lock(&rot_mgr->req_lock); rot = mdss_mdp_rot_mgr_get_session(req->id); if (!rot) { pr_err("invalid session id=%x\n", req->id); + mutex_unlock(&rot_mgr->req_lock); return -ENOENT; } @@ -1070,6 +1074,7 @@ int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd, dst_buf_fail: mutex_unlock(&rot->lock); + mutex_unlock(&rot_mgr->req_lock); mdss_iommu_ctrl(0); return ret; } @@ -1079,9 +1084,11 @@ int mdss_mdp_rotator_unset(int ndx) struct mdss_mdp_rotator_session *rot; int ret = 0; + mutex_lock(&rot_mgr->req_lock); rot = mdss_mdp_rot_mgr_get_session(ndx); if (rot) ret = mdss_mdp_rotator_release(rot); + mutex_unlock(&rot_mgr->req_lock); return ret; } -- GitLab From 1d4bc24230b94d88f1430fe7130f6a35a393b256 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Tue, 9 Feb 2016 11:15:14 -0800 Subject: [PATCH 060/528] BACKPORT: futex: Remove requirement for lock_page() in get_futex_key() commit 65d8fc777f6dcfee12785c057a6b57f679641c90 upstream. When dealing with key handling for shared futexes, we can drastically reduce the usage/need of the page lock. 1) For anonymous pages, the associated futex object is the mm_struct which does not require the page lock. 2) For inode based, keys, we can check under RCU read lock if the page mapping is still valid and take reference to the inode. This just leaves one rare race that requires the page lock in the slow path when examining the swapcache. Additionally realtime users currently have a problem with the page lock being contended for unbounded periods of time during futex operations. Task A get_futex_key() lock_page() ---> preempted Now any other task trying to lock that page will have to wait until task A gets scheduled back in, which is an unbound time. With this patch, we pretty much have a lockless futex_get_key(). Experiments show that this patch can boost/speedup the hashing of shared futexes with the perf futex benchmarks (which is good for measuring such change) by up to 45% when there are high (> 100) thread counts on a 60 core Westmere. Lower counts are pretty much in the noise range or less than 10%, but mid range can be seen at over 30% overall throughput (hash ops/sec). This makes anon-mem shared futexes much closer to its private counterpart. Signed-off-by: Mel Gorman [ Ported on top of thp refcount rework, changelog, comments, fixes. ] Signed-off-by: Davidlohr Bueso Reviewed-by: Thomas Gleixner Cc: Chris Mason Cc: Darren Hart Cc: Hugh Dickins Cc: Linus Torvalds Cc: Mel Gorman Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: dave@stgolabs.net Link: http://lkml.kernel.org/r/1455045314-8305-3-git-send-email-dave@stgolabs.net Signed-off-by: Ingo Molnar Signed-off-by: Chenbo Feng Signed-off-by: Greg Kroah-Hartman Bug: 74250718 Change-Id: I80e300aa740a553fbbbf84143d6a4165f31c8a90 Signed-off-by: David Lin (cherry picked from commit 9aa7fc852b3da486a781b177ecab96a7b420a491) --- kernel/futex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/futex.c b/kernel/futex.c index f1b1a81f9cff..9ece806f173a 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -456,7 +456,7 @@ again: key->both.offset |= FUT_OFF_INODE; /* inode-based key */ key->shared.inode = inode; - key->shared.pgoff = basepage_index(page); + key->shared.pgoff = page_head->index; rcu_read_unlock(); } -- GitLab From 280a92b9dde09f309ce81b7a6d869d0ce09da937 Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Tue, 28 Nov 2017 10:06:17 -0700 Subject: [PATCH 061/528] drivers: cpuidle: lpm-levels: Fix untrusted pointer dereference. The list_for_each macro was not used correctly, where the intermediate variable would be LIST_POISON, resulting in a untrusted pointer dereference. Switch to using list_for_each_entry_safe to for safe removal of a list entry. Bug: 72956998 Change-Id: I0e0fd5dd9f251b5093d6e9d6335387512ec59249 Signed-off-by: Mahesh Sivasubramanian (cherry picked from commit aeb0104f34e66518ddebd3360c75b3a98af0df8d) --- drivers/cpuidle/lpm-levels-of.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 5926916fce5f..b6979cd744cf 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -574,14 +574,12 @@ failed: void free_cluster_node(struct lpm_cluster *cluster) { - struct list_head *list; int i; + struct lpm_cluster *cl, *m; - list_for_each(list, &cluster->child) { - struct lpm_cluster *n; - n = list_entry(list, typeof(*n), list); - list_del(list); - free_cluster_node(n); + list_for_each_entry_safe(cl, m, &cluster->child, list) { + list_del(&cl->list); + free_cluster_node(cl); }; if (cluster->cpu) { -- GitLab From fbeba09eeeefa2b5f6838be8569db5c4e8cb459a Mon Sep 17 00:00:00 2001 From: Dennis Cagle Date: Fri, 13 Apr 2018 11:49:03 -0700 Subject: [PATCH 062/528] BACKPORT: msm: adsprpc: Use unsigned integer for length values As the length datatype is signed, an attacker can both overflow the calculation or supply a negative number to trick the check into returning an chosen chunk. This can have undesired consequences. Always use unsigned integer types for length values. Change-Id: Ifde2f0d35129014b976507f7723a319c53fabddf Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu Bug: 63165135 CRs-Fixed: 2139538 Signed-off-by: Dennis Cagle (cherry picked from commit c29e11c774b3c59660c1c599b73b7fabf1492d43) Signed-off-by: David Lin (cherry picked from commit 157a921e39321002220e040ef8a07dce8e0eccbf) --- drivers/char/adsprpc.c | 95 ++++++++++++++++++----------------- drivers/char/adsprpc_compat.c | 14 +++--- drivers/char/adsprpc_shared.h | 25 ++++----- 3 files changed, 68 insertions(+), 66 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 815d822565a7..63f4780f1fb7 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -77,7 +77,7 @@ static inline uintptr_t buf_page_offset(void *buf) return offset; } -static inline int buf_num_pages(void *buf, ssize_t len) +static inline int buf_num_pages(void *buf, size_t len) { uintptr_t start = buf_page_start(buf) >> PAGE_SHIFT; uintptr_t end = (((uintptr_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT; @@ -142,7 +142,7 @@ struct fastrpc_buf { struct ion_handle *handle; void *virt; ion_phys_addr_t phys; - ssize_t size; + size_t size; int used; }; @@ -225,7 +225,7 @@ struct fastrpc_mmap { ion_phys_addr_t phys; uintptr_t *vaddrin; uintptr_t vaddrout; - ssize_t size; + size_t size; int refs; }; @@ -273,7 +273,7 @@ static int map_iommu_mem(struct ion_handle *handle, struct file_data *fdata, ion_phys_addr_t *iova, unsigned long size) { struct fastrpc_apps *me = &gfa; - struct fastrpc_mmap *map = 0, *mapmatch = 0; + struct fastrpc_mmap *map = NULL, *mapmatch = NULL; struct hlist_node *n; unsigned long len = size; int cid = fdata->cid; @@ -307,7 +307,7 @@ static void unmap_iommu_mem(struct ion_handle *handle, struct file_data *fdata, int cached) { struct fastrpc_apps *me = &gfa; - struct fastrpc_mmap *map = 0, *mapmatch = 0; + struct fastrpc_mmap *map = NULL, *mapmatch = NULL; struct hlist_node *n; int cid = fdata->cid; @@ -342,10 +342,10 @@ static void free_mem(struct fastrpc_buf *buf, struct file_data *fd) } if (!IS_ERR_OR_NULL(buf->virt)) { ion_unmap_kernel(me->iclient, buf->handle); - buf->virt = 0; + buf->virt = NULL; } ion_free(me->iclient, buf->handle); - buf->handle = 0; + buf->handle = NULL; } } @@ -361,11 +361,11 @@ static void free_map(struct fastrpc_mmap *map, struct file_data *fdata) } if (!IS_ERR_OR_NULL(map->virt)) { ion_unmap_kernel(me->iclient, map->handle); - map->virt = 0; + map->virt = NULL; } ion_free(me->iclient, map->handle); } - map->handle = 0; + map->handle = NULL; } static int alloc_mem(struct fastrpc_buf *buf, struct file_data *fdata) @@ -376,8 +376,8 @@ static int alloc_mem(struct fastrpc_buf *buf, struct file_data *fdata) int err = 0; int cid = fdata->cid; unsigned int heap; - buf->handle = 0; - buf->virt = 0; + buf->handle = NULL; + buf->virt = NULL; buf->phys = 0; heap = me->channel[cid].smmu.enabled ? ION_HEAP(ION_IOMMU_HEAP_ID) : ION_HEAP(ION_ADSP_HEAP_ID); @@ -412,7 +412,7 @@ static int context_restore_interrupted(struct fastrpc_apps *me, struct smq_invoke_ctx **po) { int err = 0; - struct smq_invoke_ctx *ctx = 0, *ictx = 0; + struct smq_invoke_ctx *ctx = NULL, *ictx = NULL; struct hlist_node *n; struct fastrpc_ioctl_invoke *invoke = &invokefd->inv; spin_lock(&me->clst.hlock); @@ -507,9 +507,10 @@ static int context_alloc(struct fastrpc_apps *me, uint32_t kernel, struct file_data *fdata, struct smq_invoke_ctx **po) { - int err = 0, bufs, size = 0; - struct smq_invoke_ctx *ctx = 0; + int err = 0, bufs, ii, size = 0; + struct smq_invoke_ctx *ctx = NULL; struct smq_context_list *clst = &me->clst; + struct fastrpc_ioctl_invoke *invoke = &invokefd->inv; bufs = REMOTE_SCALARS_INBUFS(invoke->sc) + @@ -521,7 +522,7 @@ static int context_alloc(struct fastrpc_apps *me, uint32_t kernel, bufs * sizeof(*ctx->handles); } - VERIFY(err, 0 != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL))); + VERIFY(err, NULL != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL))); if (err) goto bail; @@ -530,8 +531,8 @@ static int context_alloc(struct fastrpc_apps *me, uint32_t kernel, ctx->apps = me; ctx->fdata = fdata; ctx->pra = (remote_arg_t *)(&ctx[1]); - ctx->fds = invokefd->fds == 0 ? 0 : (int *)(&ctx->pra[bufs]); - ctx->handles = invokefd->fds == 0 ? 0 : + ctx->fds = invokefd->fds == NULL ? NULL : (int *)(&ctx->pra[bufs]); + ctx->handles = invokefd->fds == NULL ? NULL : (struct ion_handle **)(&ctx->fds[bufs]); if (!kernel) { VERIFY(err, 0 == copy_from_user(ctx->pra, invoke->pra, @@ -638,7 +639,7 @@ static void context_notify_user(struct smq_invoke_ctx *ctx, int retval) static void context_notify_all_users(struct smq_context_list *me, int cid) { - struct smq_invoke_ctx *ictx = 0; + struct smq_invoke_ctx *ictx = NULL; struct hlist_node *n; spin_lock(&me->hlock); hlist_for_each_entry_safe(ictx, n, &me->pending, hn) { @@ -663,10 +664,10 @@ static void context_list_ctor(struct smq_context_list *me) static void context_list_dtor(struct fastrpc_apps *me, struct smq_context_list *clst) { - struct smq_invoke_ctx *ictx = 0, *ctxfree; + struct smq_invoke_ctx *ictx = NULL, *ctxfree; struct hlist_node *n; do { - ctxfree = 0; + ctxfree = NULL; spin_lock(&clst->hlock); hlist_for_each_entry_safe(ictx, n, &clst->interrupted, hn) { hlist_del(&ictx->hn); @@ -699,7 +700,7 @@ static int get_page_list(uint32_t kernel, struct smq_invoke_ctx *ctx) struct fastrpc_buf *ibuf = &ctx->dev->buf; struct fastrpc_buf *obuf = &ctx->obuf; remote_arg_t *pra = ctx->pra; - ssize_t rlen; + size_t rlen; uint32_t sc = ctx->sc; int cid = ctx->fdata->cid; int i, err = 0; @@ -726,7 +727,7 @@ static int get_page_list(uint32_t kernel, struct smq_invoke_ctx *ctx) for (i = 0; i < inbufs + outbufs; ++i) { void *buf; int num; - ssize_t len; + size_t len; list[i].num = 0; list[i].pgidx = 0; @@ -833,14 +834,14 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx, { struct fastrpc_apps *me = &gfa; struct smq_invoke_buf *list; - struct fastrpc_buf *pbuf = &ctx->obuf, *obufs = 0; + struct fastrpc_buf *pbuf = &ctx->obuf, *obufs = NULL; struct smq_phy_page *pages; struct vm_area_struct *vma; struct ion_handle **handles = ctx->handles; void *args; remote_arg_t *pra = ctx->pra; remote_arg_t *rpra = ctx->rpra; - ssize_t rlen, used, size, copylen = 0; + size_t rlen, used, size, copylen = 0; uint32_t sc = ctx->sc, start; int i, inh, bufs = 0, err = 0, oix; int inbufs = REMOTE_SCALARS_INBUFS(sc); @@ -933,7 +934,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx, /* copy non ion buffers */ for (oix = 0; oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; - ssize_t mlen = ctx->overps[oix]->mend - ctx->overps[oix]->mstart; + size_t mlen = ctx->overps[oix]->mend - ctx->overps[oix]->mstart; if (!pra[i].buf.len) continue; if (list[i].num) @@ -1208,7 +1209,7 @@ static void free_dev(struct fastrpc_device *dev, struct file_data *fdata) static int alloc_dev(struct fastrpc_device **dev, struct file_data *fdata) { int err = 0; - struct fastrpc_device *fd = 0; + struct fastrpc_device *fd = NULL; VERIFY(err, 0 != try_module_get(THIS_MODULE)); if (err) @@ -1236,7 +1237,7 @@ static int get_dev(struct fastrpc_apps *me, struct file_data *fdata, struct fastrpc_device **rdev) { struct hlist_head *head; - struct fastrpc_device *dev = 0, *devfree = 0; + struct fastrpc_device *dev = NULL, *devfree = NULL; struct hlist_node *n; uint32_t h = hash_32(current->tgid, RPC_HASH_BITS); int err = 0; @@ -1282,7 +1283,7 @@ static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode, struct fastrpc_ioctl_invoke_fd *invokefd, struct file_data *fdata) { - struct smq_invoke_ctx *ctx = 0; + struct smq_invoke_ctx *ctx = NULL; struct fastrpc_ioctl_invoke *invoke = &invokefd->inv; int cid = fdata->cid; int interrupted = 0; @@ -1371,8 +1372,8 @@ static int fastrpc_init_process(struct file_data *fdata, { int err = 0; struct fastrpc_ioctl_invoke_fd ioctl; - struct smq_phy_page *pages = 0; - struct fastrpc_mmap *map = 0; + struct smq_phy_page *pages = NULL; + struct fastrpc_mmap *map = NULL; int npages = 0; struct fastrpc_apps *me = &gfa; if (init->flags == FASTRPC_INIT_ATTACH) { @@ -1521,7 +1522,7 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me, struct { int pid; uintptr_t vaddrout; - ssize_t size; + size_t size; } inargs; inargs.pid = current->tgid; @@ -1575,9 +1576,9 @@ static int map_buffer(struct fastrpc_apps *me, struct file_data *fdata, struct smq_phy_page **ppages, int *pnpages) { struct ion_client *clnt = gfa.iclient; - struct ion_handle *handle = 0; - struct fastrpc_mmap *map = 0, *mapmatch = 0; - struct smq_phy_page *pages = 0; + struct ion_handle *handle = NULL; + struct fastrpc_mmap *map = NULL, *mapmatch = NULL; + struct smq_phy_page *pages = NULL; struct hlist_node *n; uintptr_t vaddrout = 0; int num; @@ -1654,8 +1655,8 @@ static int fastrpc_internal_mmap(struct fastrpc_apps *me, struct fastrpc_ioctl_mmap *mmap) { - struct fastrpc_mmap *map = 0; - struct smq_phy_page *pages = 0; + struct fastrpc_mmap *map = NULL; + struct smq_phy_page *pages = NULL; int num = 0; int err = 0; VERIFY(err, 0 == map_buffer(me, fdata, mmap->fd, (char *)mmap->vaddrin, @@ -1685,7 +1686,7 @@ static void cleanup_current_dev(struct file_data *fdata) struct fastrpc_device *dev, *devfree; rnext: - devfree = dev = 0; + devfree = dev = NULL; spin_lock(&me->hlock); head = &me->htbl[h]; hlist_for_each_entry_safe(dev, n, head, hn) { @@ -1723,9 +1724,9 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) struct file_data *fdata = (struct file_data *)file->private_data; struct fastrpc_apps *me = &gfa; struct smq_context_list *clst = &me->clst; - struct smq_invoke_ctx *ictx = 0, *ctxfree; + struct smq_invoke_ctx *ictx = NULL, *ctxfree; struct hlist_node *n; - struct fastrpc_mmap *map = 0; + struct fastrpc_mmap *map = NULL; int cid = MINOR(inode->i_rdev); if (!fdata) @@ -1733,7 +1734,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) (void)fastrpc_release_current_dsp_process(fdata); do { - ctxfree = 0; + ctxfree = NULL; spin_lock(&clst->hlock); hlist_for_each_entry_safe(ictx, n, &clst->interrupted, hn) { if ((ictx->tgid == current->tgid) && @@ -1771,7 +1772,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) mutex_lock(&me->smd_mutex); ssrcount = me->channel[cid].ssrcount; if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) || - (me->channel[cid].chan == 0)) { + (me->channel[cid].chan == NULL)) { VERIFY(err, 0 == smd_named_open_on_edge( FASTRPC_SMD_GUID, gcinfo[cid].channel, @@ -1791,9 +1792,9 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) } mutex_unlock(&me->smd_mutex); - filp->private_data = 0; + filp->private_data = NULL; if (0 != try_module_get(THIS_MODULE)) { - struct file_data *fdata = 0; + struct file_data *fdata = NULL; /* This call will cause a dev to be created * which will addref this module */ @@ -1823,7 +1824,7 @@ bail: completion_bail: smd_close(me->channel[cid].chan); - me->channel[cid].chan = 0; + me->channel[cid].chan = NULL; smd_bail: mutex_unlock(&me->smd_mutex); return err; @@ -1845,7 +1846,7 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, switch (ioctl_num) { case FASTRPC_IOCTL_INVOKE_FD: case FASTRPC_IOCTL_INVOKE: - invokefd.fds = 0; + invokefd.fds = NULL; size = (ioctl_num == FASTRPC_IOCTL_INVOKE) ? sizeof(invokefd.inv) : sizeof(invokefd); VERIFY(err, 0 == copy_from_user(&invokefd, param, size)); @@ -1923,7 +1924,7 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, ctx->ssrcount++; if (ctx->chan) { smd_close(ctx->chan); - ctx->chan = 0; + ctx->chan = NULL; pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); } diff --git a/drivers/char/adsprpc_compat.c b/drivers/char/adsprpc_compat.c index ee324dcf91f0..160ad1851c9a 100644 --- a/drivers/char/adsprpc_compat.c +++ b/drivers/char/adsprpc_compat.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -33,7 +33,7 @@ struct compat_remote_buf { compat_uptr_t pv; /* buffer pointer */ - compat_ssize_t len; /* length of buffer */ + compat_size_t len; /* length of buffer */ }; union compat_remote_arg { @@ -56,13 +56,13 @@ struct compat_fastrpc_ioctl_mmap { compat_int_t fd; /* ion fd */ compat_uint_t flags; /* flags for dsp to map with */ compat_uptr_t vaddrin; /* optional virtual address */ - compat_ssize_t size; /* size */ + compat_size_t size; /* size */ compat_uptr_t vaddrout; /* dsps virtual address */ }; struct compat_fastrpc_ioctl_munmap { compat_uptr_t vaddrout; /* address to unmap */ - compat_ssize_t size; /* size */ + compat_size_t size; /* size */ }; struct compat_fastrpc_ioctl_init { @@ -81,7 +81,7 @@ static int compat_get_fastrpc_ioctl_invoke( unsigned int cmd) { compat_uint_t u, sc; - compat_ssize_t s; + compat_size_t s; compat_uptr_t p; struct fastrpc_ioctl_invoke_fd *inv; union compat_remote_arg *pra32; @@ -164,7 +164,7 @@ static int compat_get_fastrpc_ioctl_mmap( { compat_uint_t u; compat_int_t i; - compat_ssize_t s; + compat_size_t s; compat_uptr_t p; int err; @@ -198,7 +198,7 @@ static int compat_get_fastrpc_ioctl_munmap( struct fastrpc_ioctl_munmap __user *unmap) { compat_uptr_t p; - compat_ssize_t s; + compat_size_t s; int err; err = get_user(p, &unmap32->vaddrout); diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index c0f8d3cc8c4e..244553c6999f 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -93,7 +93,7 @@ do {\ struct remote_buf { void *pv; /* buffer pointer */ - ssize_t len; /* length of buffer */ + size_t len; /* length of buffer */ }; union remote_arg { @@ -114,25 +114,25 @@ struct fastrpc_ioctl_invoke_fd { struct fastrpc_ioctl_init { uint32_t flags; /* one of FASTRPC_INIT_* macros */ - uintptr_t __user file; /* pointer to elf file */ - int32_t filelen; /* elf file length */ + uintptr_t file; /* pointer to elf file */ + uint32_t filelen; /* elf file length */ int32_t filefd; /* ION fd for the file */ - uintptr_t __user mem; /* mem for the PD */ - int32_t memlen; /* mem length */ + uintptr_t mem; /* mem for the PD */ + uint32_t memlen; /* mem length */ int32_t memfd; /* ION fd for the mem */ }; struct fastrpc_ioctl_munmap { uintptr_t vaddrout; /* address to unmap */ - ssize_t size; /* size */ + size_t size; /* size */ }; struct fastrpc_ioctl_mmap { int fd; /* ion fd */ uint32_t flags; /* flags for dsp to map with */ - uintptr_t __user *vaddrin; /* optional virtual address */ - ssize_t size; /* size */ + uintptr_t vaddrin; /* optional virtual address */ + size_t size; /* size */ uintptr_t vaddrout; /* dsps virtual address */ }; @@ -144,7 +144,7 @@ struct smq_null_invoke { struct smq_phy_page { unsigned long addr; /* physical address */ - ssize_t size; /* size of contiguous region */ + size_t size; /* size of contiguous region */ }; struct smq_invoke_buf { @@ -171,14 +171,15 @@ struct smq_invoke_rsp { static inline struct smq_invoke_buf *smq_invoke_buf_start(remote_arg_t *pra, uint32_t sc) { - int len = REMOTE_SCALARS_LENGTH(sc); + unsigned int len = REMOTE_SCALARS_LENGTH(sc); + return (struct smq_invoke_buf *)(&pra[len]); } static inline struct smq_phy_page *smq_phy_page_start(uint32_t sc, struct smq_invoke_buf *buf) { - int nTotal = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc); + uint32_t nTotal = REMOTE_SCALARS_INBUFS(sc)+REMOTE_SCALARS_OUTBUFS(sc); return (struct smq_phy_page *)(&buf[nTotal]); } -- GitLab From 7728503b9a0bc8e98f494f8524498836983d6ba1 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 10 Aug 2017 12:29:19 -0400 Subject: [PATCH 063/528] udp: consistently apply ufo or fragmentation commit 85f1bd9a7b5a79d5baa8bf44af19658f7bf77bfa upstream. When iteratively building a UDP datagram with MSG_MORE and that datagram exceeds MTU, consistently choose UFO or fragmentation. Once skb_is_gso, always apply ufo. Conversely, once a datagram is split across multiple skbs, do not consider ufo. Sendpage already maintains the first invariant, only add the second. IPv6 does not have a sendpage implementation to modify. A gso skb must have a partial checksum, do not follow sk_no_check_tx in udp_send_skb. Found by syzkaller. [gregkh - tweaks for 3.18 for ipv6, hopefully they are correct...] [wt: s/skb_is_gso/skb_has_frags for 3.10] Fixes: e89e9cf539a2 ("[IPv4/IPv6]: UFO Scatter-gather approach") Reported-by: Andrey Konovalov Bug: 68806309 Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Change-Id: Iac75f1be3304c7400e1c5d221a56476a0d60aba3 Signed-off-by: Suren Baghdasaryan (cherry picked from commit f6cbd739d6bfdca6bf98e40beb1ce393d38a314b) --- net/ipv4/ip_output.c | 2 +- net/ipv6/ip6_output.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 7ad943e475b6..a15b080130a3 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -850,7 +850,7 @@ static int __ip_append_data(struct sock *sk, ((length > mtu) && (skb_queue_len(queue) <= 1) && (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO) && !dst_xfrm(&rt->dst) && + (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len && (sk->sk_type == SOCK_DGRAM))) { err = ip_ufo_append_data(sk, queue, getfrag, from, length, hh_len, fragheaderlen, transhdrlen, diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c681f4f760e6..7ac2d712b4ed 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1299,7 +1299,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, (((length + fragheaderlen) > mtu) && (skb_queue_len(&sk->sk_write_queue) <= 1) && (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO) && !dst_xfrm(&rt->dst) && + (rt->dst.dev->features & NETIF_F_UFO) && (sk->sk_type == SOCK_DGRAM))) { err = ip6_ufo_append_data(sk, getfrag, from, length, hh_len, fragheaderlen, -- GitLab From 9d987cf521d7e7910e49c9167bfb5832bfdd7800 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 27 Feb 2021 01:44:00 +0100 Subject: [PATCH 064/528] udp: part of previous patch already applied --- net/ipv4/ip_output.c | 2 +- net/ipv6/ip6_output.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index a15b080130a3..7ad943e475b6 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -850,7 +850,7 @@ static int __ip_append_data(struct sock *sk, ((length > mtu) && (skb_queue_len(queue) <= 1) && (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len && + (rt->dst.dev->features & NETIF_F_UFO) && !dst_xfrm(&rt->dst) && (sk->sk_type == SOCK_DGRAM))) { err = ip_ufo_append_data(sk, queue, getfrag, from, length, hh_len, fragheaderlen, transhdrlen, diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 7ac2d712b4ed..c681f4f760e6 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1299,7 +1299,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, (((length + fragheaderlen) > mtu) && (skb_queue_len(&sk->sk_write_queue) <= 1) && (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO) && + (rt->dst.dev->features & NETIF_F_UFO) && !dst_xfrm(&rt->dst) && (sk->sk_type == SOCK_DGRAM))) { err = ip6_ufo_append_data(sk, getfrag, from, length, hh_len, fragheaderlen, -- GitLab From ff8a15df5ceb3d99b58d32b780ac670b6bcd9b3d Mon Sep 17 00:00:00 2001 From: Banajit Goswami Date: Mon, 10 Apr 2017 19:56:25 -0700 Subject: [PATCH 065/528] soc: q6dspv2: apr: fix client registration refcount Audio Packet Router (APR) is used by multiple audio services to communicate between APSS and ADSP. These audio services registers for service level APR communication (port 0xFFFFFFFF), or for session level APR communication (using port 0x101 etc.). The services might choose to call apr_register for any port at random. The expectation is that the refcounting for the number of ports registered with APR for any specific service, is handled irrespective of the order in which registrations are done. The current logic fails to handle the refcounting when apr_register is called for 0xFFFFFFFF before other session based ports. Fix this correctly using the service count (svc_cnt) variable in apr_svc. CRs-fixed: 2022490 Bug: 34088848 Change-Id: I2fcd1269facf24d509db0d90314e0d2545a2ad67 Signed-off-by: Banajit Goswami (cherry picked from commit ecb46273d1ba357ad48ab4456a80438b1a2454aa) --- drivers/soc/qcom/qdsp6v2/apr.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c index 4ca07a589cf3..c3eb411c89f9 100644 --- a/drivers/soc/qcom/qdsp6v2/apr.c +++ b/drivers/soc/qcom/qdsp6v2/apr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2015, 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2015, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -404,19 +404,19 @@ struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn, mutex_unlock(&svc->m_lock); return NULL; } - if (!svc->port_cnt && !svc->svc_cnt) + if (!svc->svc_cnt) clnt->svc_cnt++; svc->port_cnt++; svc->port_fn[temp_port] = svc_fn; svc->port_priv[temp_port] = priv; + svc->svc_cnt++; } else { if (!svc->fn) { - if (!svc->port_cnt && !svc->svc_cnt) + if (!svc->svc_cnt) clnt->svc_cnt++; svc->fn = svc_fn; - if (svc->port_cnt) - svc->svc_cnt++; svc->priv = priv; + svc->svc_cnt++; } } @@ -621,24 +621,17 @@ int apr_deregister(void *handle) client_id = svc->client_id; clnt = &client[dest_id][client_id]; - if (svc->port_cnt > 0 || svc->svc_cnt > 0) { + if (svc->svc_cnt > 0) { if (svc->port_cnt) svc->port_cnt--; - else if (svc->svc_cnt) - svc->svc_cnt--; - if (!svc->port_cnt && !svc->svc_cnt) { + svc->svc_cnt--; + if (!svc->svc_cnt) { client[dest_id][client_id].svc_cnt--; - svc->need_reset = 0x0; - } - } else if (client[dest_id][client_id].svc_cnt > 0) { - client[dest_id][client_id].svc_cnt--; - if (!client[dest_id][client_id].svc_cnt) { - svc->need_reset = 0x0; pr_debug("%s: service is reset %pK\n", __func__, svc); } } - if (!svc->port_cnt && !svc->svc_cnt) { + if (!svc->svc_cnt) { svc->priv = NULL; svc->id = 0; svc->fn = NULL; -- GitLab From 5d4a93e17c940acc34af140148575c1f99423888 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 30 Jan 2018 15:43:36 +0530 Subject: [PATCH 066/528] msm: ADSPRPC: Use ID in response to get context pointer Send context ID in rpc header instead of context pointer. Validate context ID received in response and get context pointer. Bug: 74237782 Change-Id: I9cfd10d0c1b25c3085b8e15c7ca1c8ff214bf10d Acked-by: Viswanatham Paduchuri Signed-off-by: Tharun Kumar Merugu Signed-off-by: Steve Pfetsch (cherry picked from commit 71a0cf4c75b116497246e27279afa54365349332) --- drivers/char/adsprpc.c | 70 +++++++++++++++++++++++++++++++++-- drivers/char/adsprpc_shared.h | 4 +- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 63f4780f1fb7..6010a43e9226 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -62,6 +62,9 @@ up_read(¤t->mm->mmap_sem);\ } while (0) +#define FASTRPC_CTX_MAGIC (0xbeeddeed) +#define FASTRPC_CTX_MAX (256) +#define FASTRPC_CTXID_MASK (0xFF0) #define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0) @@ -91,6 +94,13 @@ static inline uint32_t buf_page_size(uint32_t size) return sz > PAGE_SIZE ? sz : PAGE_SIZE; } +static inline uint64_t ptr_to_uint64(void *ptr) +{ + uint64_t addr = (uint64_t)((uintptr_t)ptr); + + return addr; +} + static inline int buf_get_pages(void *addr, ssize_t sz, int nr_pages, int access, struct smq_phy_page *pages, int nr_elems, struct smq_phy_page *range) @@ -178,6 +188,8 @@ struct smq_invoke_ctx { uint32_t sc; struct overlap *overs; struct overlap **overps; + unsigned int magic; + uint64_t ctxid; }; struct smq_context_list { @@ -216,6 +228,8 @@ struct fastrpc_apps { spinlock_t wrlock; spinlock_t hlock; struct hlist_head htbl[RPC_HASH_SZ]; + spinlock_t ctxlock; + struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX]; }; struct fastrpc_mmap { @@ -564,10 +578,26 @@ static int context_alloc(struct fastrpc_apps *me, uint32_t kernel, ctx->pid = current->pid; ctx->tgid = current->tgid; init_completion(&ctx->work); + ctx->magic = FASTRPC_CTX_MAGIC; spin_lock(&clst->hlock); hlist_add_head(&ctx->hn, &clst->pending); spin_unlock(&clst->hlock); + spin_lock(&me->ctxlock); + for (ii = 0; ii < FASTRPC_CTX_MAX; ii++) { + if (!me->ctxtable[ii]) { + me->ctxtable[ii] = ctx; + ctx->ctxid = (ptr_to_uint64(ctx) & ~0xFFF)|(ii << 4); + break; + } + } + spin_unlock(&me->ctxlock); + VERIFY(err, ii < FASTRPC_CTX_MAX); + if (err) { + pr_err("adsprpc: out of context memory\n"); + goto bail; + } + *po = ctx; bail: if (ctx && err) @@ -595,6 +625,7 @@ static void context_free(struct smq_invoke_ctx *ctx, int remove) int ssrcount = ctx->fdata->ssrcount; struct fastrpc_smmu *smmu = &apps->channel[cid].smmu; struct fastrpc_buf *b; + struct fastrpc_apps *me = &gfa; int i, bufs; if (ctx->smmu) { bufs = REMOTE_SCALARS_INBUFS(ctx->sc) + @@ -616,6 +647,17 @@ static void context_free(struct smq_invoke_ctx *ctx, int remove) free_mem(b, ctx->fdata); kfree(ctx->abufs); + ctx->magic = 0; + ctx->ctxid = 0; + + spin_lock(&me->ctxlock); + for (i = 0; i < FASTRPC_CTX_MAX; i++) { + if (me->ctxtable[i] == ctx) { + me->ctxtable[i] = NULL; + break; + } + } + spin_unlock(&me->ctxlock); if (ctx->dev) { add_dev(apps, ctx->dev); if (ctx->obuf.handle != ctx->dev->buf.handle) @@ -1094,7 +1136,7 @@ static int fastrpc_invoke_send(struct fastrpc_apps *me, msg.tid = current->pid; if (kernel) msg.pid = 0; - msg.invoke.header.ctx = ctx; + msg.invoke.header.ctx = ctx->ctxid; msg.invoke.header.handle = handle; msg.invoke.header.sc = sc; msg.invoke.page.addr = buf->phys; @@ -1124,16 +1166,35 @@ static void fastrpc_deinit(void) static void fastrpc_read_handler(int cid) { struct fastrpc_apps *me = &gfa; - struct smq_invoke_rsp rsp; - int ret = 0; + struct smq_invoke_rsp rsp = {0}; + int ret = 0, err = 0; + uint32_t index; do { ret = smd_read_from_cb(me->channel[cid].chan, &rsp, sizeof(rsp)); if (ret != sizeof(rsp)) break; - context_notify_user(rsp.ctx, rsp.retval); + index = (uint32_t)((rsp.ctx & FASTRPC_CTXID_MASK) >> 4); + VERIFY(err, index < FASTRPC_CTX_MAX); + if (err) + goto bail; + + VERIFY(err, !IS_ERR_OR_NULL(me->ctxtable[index])); + if (err) + goto bail; + + VERIFY(err, ((me->ctxtable[index]->ctxid == (rsp.ctx)) && + me->ctxtable[index]->magic == FASTRPC_CTX_MAGIC)); + if (err) + goto bail; + + context_notify_user(me->ctxtable[index], rsp.retval); } while (ret == sizeof(rsp)); + +bail: + if (err) + pr_err("adsprpc: invalid response or context\n"); } static void smd_event_handler(void *priv, unsigned event) @@ -1164,6 +1225,7 @@ static int fastrpc_init(void) spin_lock_init(&me->hlock); spin_lock_init(&me->wrlock); + spin_lock_init(&me->ctxlock); mutex_init(&me->smd_mutex); context_list_ctor(&me->clst); for (i = 0; i < RPC_HASH_SZ; ++i) diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index 244553c6999f..b8e5f23a56c0 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -137,7 +137,7 @@ struct fastrpc_ioctl_mmap { }; struct smq_null_invoke { - struct smq_invoke_ctx *ctx; /* invoke caller context */ + uint64_t ctx; /* invoke caller context */ uint32_t handle; /* handle to invoke */ uint32_t sc; /* scalars structure describing the data */ }; @@ -164,7 +164,7 @@ struct smq_msg { }; struct smq_invoke_rsp { - struct smq_invoke_ctx *ctx; /* invoke caller context */ + uint64_t ctx; /* invoke caller context */ int retval; /* invoke return value */ }; -- GitLab From d44b2e58108070cd3004e85de7849267c2bd9ab0 Mon Sep 17 00:00:00 2001 From: Sean Callanan Date: Mon, 2 Apr 2018 19:17:14 -0700 Subject: [PATCH 067/528] msm: ADSPRPC: use access_ok to validate pointers The FASTRPC_IOCTL_INIT ioctl registers a pointer for later access without checking that it is a user pointer. This could allow arbitrary kernel memory access. This patch verifies that the pointer is a user pointer. Bug: 63165064 Change-Id: I936f73a2c2029f9e7ca12cc8fc06d0698e6710c0 Signed-off-by: Tharun Kumar Merugu Signed-off-by: Sean Callanan (cherry picked from commit 1748f845ef8567d166bc959d44368b541d95f587) --- drivers/char/adsprpc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 6010a43e9226..e08f4c6d65f5 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1463,6 +1463,12 @@ static int fastrpc_init_process(struct file_data *fdata, inbuf.pgid = current->tgid; inbuf.namelen = strlen(current->comm); inbuf.filelen = init->filelen; + if (!access_ok(0, (void const __user *)init->file, + init->filelen)) + goto bail; + if (!access_ok(1, (void const __user *)init->mem, + init->memlen)) + goto bail; VERIFY(err, 0 == map_buffer(me, fdata, init->memfd, (char *)init->mem, init->memlen, &map, &pages, &npages)); -- GitLab From a974fceda95c8ac6045eeabd28b7eb6c96de0476 Mon Sep 17 00:00:00 2001 From: Vaishnavi Kommaraju Date: Fri, 19 Jan 2018 17:31:10 +0530 Subject: [PATCH 068/528] ASoC: wcd_cpe_core: Add mutex lock for CPE session Add mutex lock to ensure atomic access to core handle in CPE alloc and dealloc sessions. CRs-Fixed: 2169403 Bug: 62536960 Signed-off-by: Vaishnavi Kommaraju Change-Id: Ic0bb7e1646cbeafe507680c39bb8de56086df47a (cherry picked from commit 3607a994a967f1b3c176e616c6723c45b0cefd44) --- sound/soc/codecs/wcd_cpe_core.c | 31 +++++++++++++++++++++++++------ sound/soc/codecs/wcd_cpe_core.h | 5 ++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c index 965caf8d4e8a..9d8e20b7ed6b 100644 --- a/sound/soc/codecs/wcd_cpe_core.c +++ b/sound/soc/codecs/wcd_cpe_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1604,6 +1604,7 @@ struct wcd_cpe_core *wcd_cpe_init(const char *img_fname, init_completion(&core->online_compl); init_waitqueue_head(&core->ssr_entry.offline_poll_wait); mutex_init(&core->ssr_lock); + mutex_init(&core->session_lock); core->cpe_users = 0; /* @@ -2559,6 +2560,7 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( * If this is the first session to be allocated, * only then register the afe service. */ + WCD_CPE_GRAB_LOCK(&core->session_lock, "session_lock"); if (!wcd_cpe_lsm_session_active()) afe_register_service = true; @@ -2570,6 +2572,7 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( dev_err(core->dev, "%s: max allowed sessions already allocated\n", __func__); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return NULL; } @@ -2578,6 +2581,7 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( dev_err(core->dev, "%s: Failed to enable cpe, err = %d\n", __func__, ret); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return NULL; } @@ -2618,6 +2622,8 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( init_completion(&session->cmd_comp); lsm_sessions[session_id] = session; + + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return session; err_afe_svc_reg: @@ -2629,6 +2635,7 @@ err_ret: err_session_alloc: wcd_cpe_vote(core, false); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return NULL; } @@ -2944,9 +2951,11 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, struct wcd_cpe_core *core = core_handle; int ret = 0; + WCD_CPE_GRAB_LOCK(&core->session_lock, "session_lock"); if (!session) { dev_err(core->dev, "%s: Invalid lsm session\n", __func__); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return -EINVAL; } @@ -2957,6 +2966,7 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, "%s: Wrong session id %d max allowed = %d\n", __func__, session->id, WCD_CPE_LSM_MAX_SESSIONS); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return -EINVAL; } @@ -2965,17 +2975,26 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, lsm_sessions[session->id] = NULL; kfree(session); + if (!wcd_cpe_lsm_session_active()) { + cmi_deregister(core->cmi_afe_handle); + core->cmi_afe_handle = NULL; + wcd_cpe_deinitialize_afe_port_data(); + } + ret = wcd_cpe_vote(core, false); if (ret) dev_dbg(core->dev, "%s: Failed to un-vote cpe, err = %d\n", __func__, ret); - if (!wcd_cpe_lsm_session_active()) { - cmi_deregister(core->cmi_afe_handle); - core->cmi_afe_handle = NULL; - wcd_cpe_deinitialize_afe_port_data(); - } + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); + return ret; +} + +static int wcd_cpe_cdc_lab_enable(void *core_handle) +{ + struct wcd_cpe_core *core = (struct wcd_cpe_core *)core_handle; + int rc; return ret; } diff --git a/sound/soc/codecs/wcd_cpe_core.h b/sound/soc/codecs/wcd_cpe_core.h index 050b0296b4b0..4a8a28caf5f7 100644 --- a/sound/soc/codecs/wcd_cpe_core.h +++ b/sound/soc/codecs/wcd_cpe_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -134,6 +134,9 @@ struct wcd_cpe_core { /* mutex to protect cpe ssr status variables */ struct mutex ssr_lock; + /* mutex to protect cpe session status variables */ + struct mutex session_lock; + /* Store the calibration data needed for cpe */ struct cal_type_data *cal_data[WCD_CPE_LSM_CAL_MAX]; -- GitLab From 3efc0dbd84c8fabf10653e23875343d5fe1593d8 Mon Sep 17 00:00:00 2001 From: Benjamin Chan Date: Tue, 14 Nov 2017 00:27:17 -0500 Subject: [PATCH 069/528] msm: mdss: adjust mdss_mdp_get_plane_sizes parameters init order Parameter mdss_mdp_plane_sizes must be cleared to 0 before returning under an error condition, otherwise caller function will use the uninitialized mdss_mdp_plane_sizes values and caused incorrect operation. Bug: 71501679 Change-Id: I856b17ce9e917cc450040463ec34b7309d34b9b5 Signed-off-by: Benjamin Chan (cherry picked from commit f2b84d261b9c6700bd39d4f9d41ba058083ffe9f) --- drivers/video/msm/mdss/mdss_mdp_util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c index d8878ff6a2ae..b17c66ef6977 100644 --- a/drivers/video/msm/mdss/mdss_mdp_util.c +++ b/drivers/video/msm/mdss/mdss_mdp_util.c @@ -438,6 +438,8 @@ int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, if (ps == NULL) return -EINVAL; + memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes)); + if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT)) return -ERANGE; @@ -446,7 +448,6 @@ int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, return -EINVAL; bpp = fmt->bpp; - memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes)); if (bwc_mode) { u32 height, meta_size; -- GitLab From 3f2652213544b1bdba0801dddb619d6427e8e3f8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 23 Oct 2017 16:46:00 -0700 Subject: [PATCH 070/528] Input: gtco - fix potential out-of-bound access commit a50829479f58416a013a4ccca791336af3c584c7 upstream. parse_hid_report_descriptor() has a while (i < length) loop, which only guarantees that there's at least 1 byte in the buffer, but the loop body can read multiple bytes which causes out-of-bounds access. Bug: 69916367 Change-Id: Ic6a2fda77685b90d7642c09b20f5d57d6d48b726 Reported-by: Andrey Konovalov Reviewed-by: Andrey Konovalov Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Siqi Lin (cherry picked from commit 1b1e6586e98801a14021b6a6d5e62a19560e7a5a) --- drivers/input/tablet/gtco.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index a9f8f925ba2b..5a7be4c559f3 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -232,13 +232,17 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, /* Walk this report and pull out the info we need */ while (i < length) { - prefix = report[i]; - - /* Skip over prefix */ - i++; + prefix = report[i++]; /* Determine data size and save the data in the proper variable */ - size = PREF_SIZE(prefix); + size = (1U << PREF_SIZE(prefix)) >> 1; + if (i + size > length) { + dev_err(ddev, + "Not enough data (need %d, have %d)\n", + i + size, length); + break; + } + switch (size) { case 1: data = report[i]; @@ -246,8 +250,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, case 2: data16 = get_unaligned_le16(&report[i]); break; - case 3: - size = 4; + case 4: data32 = get_unaligned_le32(&report[i]); break; } -- GitLab From e0396ad3ec210f160d06f00476f5607529708c73 Mon Sep 17 00:00:00 2001 From: Haibin Liu Date: Thu, 28 Dec 2017 20:42:37 +0800 Subject: [PATCH 071/528] msm: sensor: actuator: fix out of bound read for region params Issue: the region index is not validated against the region size. this cause out-of-bound read on the KASAN kernel. Fix: Add restriction that region index smaller than region size. CRs-Fixed: 2153841 Bug: 65122765 Change-Id: I141bba45662769f0661c947fb642c2671578f32e Signed-off-by: Haibin Liu Signed-off-by: VijayaKumar T M (cherry picked from commit cb9cb79750eb2a7324476cdfa549482f65e9ce5f) --- .../platform/msm/camera_v2/sensor/actuator/msm_actuator.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index a07e4f61ab14..e55aaedd13db 100755 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -614,6 +614,8 @@ static int32_t msm_actuator_move_focus( a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos); while (a_ctrl->curr_step_pos != dest_step_pos) { + if (a_ctrl->curr_region_index >= a_ctrl->region_size) + break; step_boundary = a_ctrl->region_params[a_ctrl->curr_region_index]. step_bound[dir]; @@ -710,6 +712,8 @@ static int32_t msm_actuator_bivcm_move_focus( a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos); while (a_ctrl->curr_step_pos != dest_step_pos) { + if (a_ctrl->curr_region_index >= a_ctrl->region_size) + break; step_boundary = a_ctrl->region_params[a_ctrl->curr_region_index]. step_bound[dir]; -- GitLab From 653f02052754d62257fdc91db3c09b4759ab250d Mon Sep 17 00:00:00 2001 From: Haibin Liu Date: Tue, 5 Dec 2017 15:06:18 +0800 Subject: [PATCH 072/528] msm: sensor: actuator: add null pointer check for i2c array Issue: i2c_reg_tbl may be null under error condition when set param. then, other actuator function still may use the i2c_reg_tbl as null. Fix: 1) the assignment total_steps follow on kmalloc buffer. 2) Add NULL pointer check for i2c tbl. CRs-Fixed: 2152401 Bug: 65122765 Change-Id: Ieec3d88e6dae0177787da0906f53d59ac4f5a624 Signed-off-by: Haibin Liu Signed-off-by: VijayaKumar T M (cherry picked from commit 5339a138ca82cdb36921216bf258e4db69b068cb) --- .../camera_v2/sensor/actuator/msm_actuator.c | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index e55aaedd13db..75dd0474317d 100755 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -52,6 +52,11 @@ static int32_t msm_actuator_piezo_set_default_focus( struct msm_camera_i2c_reg_setting reg_setting; CDBG("Enter\n"); + if (a_ctrl->i2c_reg_tbl == NULL) { + pr_err("failed. i2c reg tabl is NULL"); + return -EFAULT; + } + if (a_ctrl->curr_step_pos != 0) { a_ctrl->i2c_tbl_index = 0; a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, @@ -533,6 +538,11 @@ static int32_t msm_actuator_piezo_move_focus( return -EFAULT; } + if (a_ctrl->i2c_reg_tbl == NULL) { + pr_err("failed. i2c reg tabl is NULL"); + return -EFAULT; + } + if (dest_step_position > a_ctrl->total_steps) { pr_err("Step pos greater than total steps = %d\n", dest_step_position); @@ -603,6 +613,10 @@ static int32_t msm_actuator_move_focus( pr_err("Invalid direction = %d\n", dir); return -EFAULT; } + if (a_ctrl->i2c_reg_tbl == NULL) { + pr_err("failed. i2c reg tabl is NULL"); + return -EFAULT; + } if (dest_step_pos > a_ctrl->total_steps) { pr_err("Step pos greater than total steps = %d\n", dest_step_pos); @@ -701,6 +715,10 @@ static int32_t msm_actuator_bivcm_move_focus( pr_err("Invalid direction = %d\n", dir); return -EFAULT; } + if (a_ctrl->i2c_reg_tbl == NULL) { + pr_err("failed. i2c reg tabl is NULL"); + return -EFAULT; + } if (dest_step_pos > a_ctrl->total_steps) { pr_err("Step pos greater than total steps = %d\n", dest_step_pos); @@ -1101,6 +1119,18 @@ static int32_t msm_actuator_set_position( return -EFAULT; } + if (!a_ctrl || !a_ctrl->func_tbl || + !a_ctrl->func_tbl->actuator_parse_i2c_params || + !a_ctrl->i2c_reg_tbl) { + pr_err("failed. NULL actuator pointers."); + return -EFAULT; + } + + if (a_ctrl->actuator_state != ACT_OPS_ACTIVE) { + pr_err("failed. Invalid actuator state."); + return -EFAULT; + } + a_ctrl->i2c_tbl_index = 0; for (index = 0; index < set_pos->number_of_steps; index++) { next_lens_position = set_pos->pos[index]; @@ -1189,12 +1219,10 @@ static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, a_ctrl->region_size = set_info->af_tuning_params.region_size; a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step; - a_ctrl->total_steps = set_info->af_tuning_params.total_steps; if (copy_from_user(&a_ctrl->region_params, (void *)set_info->af_tuning_params.region_params, a_ctrl->region_size * sizeof(struct region_params_t))) { - a_ctrl->total_steps = 0; pr_err("Error copying region_params\n"); return -EFAULT; } @@ -1225,6 +1253,7 @@ static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, (a_ctrl->i2c_reg_tbl != NULL)) { kfree(a_ctrl->i2c_reg_tbl); } + a_ctrl->i2c_reg_tbl = NULL; a_ctrl->i2c_reg_tbl = kzalloc(sizeof(struct msm_camera_i2c_reg_array) * @@ -1234,6 +1263,8 @@ static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, return -ENOMEM; } + a_ctrl->total_steps = set_info->af_tuning_params.total_steps; + if (copy_from_user(&a_ctrl->reg_tbl, (void *)set_info->actuator_params.reg_tbl_params, a_ctrl->reg_tbl_size * -- GitLab From aad0684f7c1992f98df33aafb8c99eb0ebc62ba2 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 27 Feb 2021 02:58:36 +0100 Subject: [PATCH 073/528] ASoC: butchered part of commit d7fe7edcbc206c6c4704c6d17765ce3c5775aa0d --- sound/soc/codecs/wcd_cpe_core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c index 9d8e20b7ed6b..44a08946fef5 100644 --- a/sound/soc/codecs/wcd_cpe_core.c +++ b/sound/soc/codecs/wcd_cpe_core.c @@ -2996,7 +2996,12 @@ static int wcd_cpe_cdc_lab_enable(void *core_handle) struct wcd_cpe_core *core = (struct wcd_cpe_core *)core_handle; int rc; - return ret; + rc = cpe_svc_toggle_lab(core->cpe_handle, true); + if (rc) + dev_err(core->dev, + "%s: lab enable failed, err = %d\n", + __func__, rc); + return rc; } static int slim_master_read_enable(void *core_handle, -- GitLab From 74ffa2b1a325c505edbfe25159f75522a350029a Mon Sep 17 00:00:00 2001 From: Neeti Desai Date: Fri, 14 Nov 2014 17:42:49 -0800 Subject: [PATCH 074/528] msm: ion: Add system secure heap Add infrastructure to support a new system secure heap, needed for secure use cases. The new heap essentially allocates from the system heap, and assigns the memory to the correct VM before returning back to the client. Change-Id: I2cd900e4399eecc3a9510139c4ebea0b713c39fc Signed-off-by: Neeti Desai [imaund@codeaurora.org: resolved context conflicts] Signed-off-by: Ian Maund (cherry picked from commit 54584acdad15ca927bd28fbe754bf3f9671f8bd2) --- drivers/staging/android/ion/Makefile | 2 +- drivers/staging/android/ion/ion.c | 5 - .../staging/android/ion/ion_cma_secure_heap.c | 3 +- drivers/staging/android/ion/ion_priv.h | 1 + .../android/ion/ion_system_secure_heap.c | 210 ++++++++++++++++++ drivers/staging/android/ion/msm/msm_ion.c | 32 ++- drivers/staging/android/ion/msm_ion_priv.h | 5 + drivers/staging/android/uapi/msm_ion.h | 3 +- 8 files changed, 252 insertions(+), 9 deletions(-) create mode 100644 drivers/staging/android/ion/ion_system_secure_heap.c diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index c3c2144d0d78..126c5cab73e5 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \ - ion_carveout_heap.o ion_chunk_heap.o + ion_carveout_heap.o ion_chunk_heap.o ion_system_secure_heap.o obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o obj-$(CONFIG_ION_TEST) += ion_test.o ifdef CONFIG_COMPAT diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 298f28f99782..ac2f0e0507ff 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -572,7 +572,6 @@ static struct ion_handle *__ion_alloc(struct ion_client *client, size_t len, struct ion_buffer *buffer = NULL; struct ion_heap *heap; int ret; - unsigned long secure_allocation = flags & ION_FLAG_SECURE; const unsigned int MAX_DBG_STR_LEN = 64; char dbg_str[MAX_DBG_STR_LEN]; unsigned int dbg_str_idx = 0; @@ -605,10 +604,6 @@ static struct ion_handle *__ion_alloc(struct ion_client *client, size_t len, /* if the caller didn't specify this heap id */ if (!((1 << heap->id) & heap_id_mask)) continue; - /* Do not allow un-secure heap if secure is specified */ - if (secure_allocation && - !ion_heap_allow_secure_allocation(heap->type)) - continue; trace_ion_alloc_buffer_start(client->name, heap->name, len, heap_id_mask, flags); buffer = ion_buffer_create(heap, dev, len, align, flags); diff --git a/drivers/staging/android/ion/ion_cma_secure_heap.c b/drivers/staging/android/ion/ion_cma_secure_heap.c index ba3adb7666cd..a03092078ca7 100644 --- a/drivers/staging/android/ion/ion_cma_secure_heap.c +++ b/drivers/staging/android/ion/ion_cma_secure_heap.c @@ -654,7 +654,8 @@ static int ion_secure_cma_allocate(struct ion_heap *heap, struct ion_secure_cma_buffer_info *buf = NULL; unsigned long allow_non_contig = flags & ION_FLAG_ALLOW_NON_CONTIG; - if (!secure_allocation) { + if (!secure_allocation && + !ion_heap_allow_secure_allocation(heap->type)) { pr_err("%s: non-secure allocation disallowed from heap %s %lx\n", __func__, heap->name, flags); return -ENOMEM; diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 57c33c13bbde..61a870a6fb92 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -257,6 +257,7 @@ int ion_heap_map_user(struct ion_heap *, struct ion_buffer *, int ion_heap_buffer_zero(struct ion_buffer *buffer); int msm_ion_heap_high_order_page_zero(struct page *page, int order); +struct ion_heap *get_ion_heap(int heap_id); int msm_ion_heap_buffer_zero(struct ion_buffer *buffer); int msm_ion_heap_pages_zero(struct page **pages, int num_pages); int msm_ion_heap_alloc_pages_mem(struct pages_mem *pages_mem); diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c new file mode 100644 index 000000000000..4c3a00e3db09 --- /dev/null +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -0,0 +1,210 @@ +/* + * + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include "ion.h" +#include "ion_priv.h" + +struct ion_system_secure_heap { + struct ion_heap *sys_heap; + struct ion_heap heap; +}; + +#define VMID_HLOS 0x3 +#define VMID_CP_TOUCH 0x8 +#define VMID_CP_BITSTREAM 0x9 +#define VMID_CP_PIXEL 0xA +#define VMID_CP_NON_PIXEL 0xB +#define VMID_CP_CAMERA 0xD +#define VMID_HLOS_FREE 0xE + +static bool is_cp_flag_present(unsigned long flags) +{ + return flags && (ION_FLAG_CP_TOUCH || + ION_FLAG_CP_BITSTREAM || + ION_FLAG_CP_PIXEL || + ION_FLAG_CP_NON_PIXEL || + ION_FLAG_CP_CAMERA); +} + +static int get_secure_vmid(unsigned long flags) +{ + if (flags & ION_FLAG_CP_TOUCH) + return VMID_CP_TOUCH; + if (flags & ION_FLAG_CP_BITSTREAM) + return VMID_CP_BITSTREAM; + if (flags & ION_FLAG_CP_PIXEL) + return VMID_CP_PIXEL; + if (flags & ION_FLAG_CP_NON_PIXEL) + return VMID_CP_NON_PIXEL; + if (flags & ION_FLAG_CP_CAMERA) + return VMID_CP_CAMERA; + + return -EINVAL; +} + +static void ion_system_secure_heap_free(struct ion_buffer *buffer) +{ + int ret; + u64 source_vm; + u64 dest_vm; + struct ion_heap *heap = buffer->heap; + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + source_vm = get_secure_vmid(buffer->flags); + dest_vm = VMID_HLOS; + + ret = msm_ion_hyp_assign_call(buffer->priv_virt, &source_vm, + sizeof(source_vm), &dest_vm, + sizeof(dest_vm)); + + if (ret) { + pr_err("%s: Not freeing memory since assign call failed\n", + __func__); + return; + } + buffer->heap = secure_heap->sys_heap; + secure_heap->sys_heap->ops->free(buffer); +} + +static int ion_system_secure_heap_allocate(struct ion_heap *heap, + struct ion_buffer *buffer, + unsigned long size, unsigned long align, + unsigned long flags) +{ + int ret; + u64 source_vm; + u64 dest_vm; + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + if (!ion_heap_is_system_secure_heap_type(secure_heap->heap.type) || + !is_cp_flag_present(flags)) { + pr_info("%s: Incorrect heap type or incorrect flags\n", + __func__); + return -EINVAL; + } + + source_vm = VMID_HLOS; + dest_vm = get_secure_vmid(flags); + if (dest_vm < 0) { + pr_info("%s: Unable to get secure VMID\n", __func__); + return -EINVAL; + } + + ret = secure_heap->sys_heap->ops->allocate(secure_heap->sys_heap, + buffer, size, align, flags); + if (ret) { + pr_info("%s: Failed to get allocation for %s, ret = %d\n", + __func__, heap->name, ret); + return ret; + } + ret = msm_ion_hyp_assign_call(buffer->priv_virt, &source_vm, + sizeof(source_vm), &dest_vm, + sizeof(dest_vm)); + + if (ret) + ion_system_secure_heap_free(buffer); + + return ret; +} + +static struct sg_table *ion_system_secure_heap_map_dma(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + return secure_heap->sys_heap->ops->map_dma(secure_heap->sys_heap, + buffer); +} + +static void ion_system_secure_heap_unmap_dma(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + secure_heap->sys_heap->ops->map_dma(secure_heap->sys_heap, + buffer); +} + +static void *ion_system_secure_heap_map_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + pr_info("%s: Kernel mapping from secure heap %s disallowed\n", + __func__, heap->name); + return ERR_PTR(-EINVAL); +} + +static void ion_system_secure_heap_unmap_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ +} + +static int ion_system_secure_heap_map_user(struct ion_heap *mapper, + struct ion_buffer *buffer, + struct vm_area_struct *vma) +{ + pr_info("%s: Mapping from secure heap %s disallowed\n", + __func__, mapper->name); + return -EINVAL; +} + +static int ion_system_secure_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, + int nr_to_scan) +{ + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + return secure_heap->sys_heap->ops->shrink(secure_heap->sys_heap, + gfp_mask, nr_to_scan); +} + +static struct ion_heap_ops system_secure_heap_ops = { + .allocate = ion_system_secure_heap_allocate, + .free = ion_system_secure_heap_free, + .map_dma = ion_system_secure_heap_map_dma, + .unmap_dma = ion_system_secure_heap_unmap_dma, + .map_kernel = ion_system_secure_heap_map_kernel, + .unmap_kernel = ion_system_secure_heap_unmap_kernel, + .map_user = ion_system_secure_heap_map_user, + .shrink = ion_system_secure_heap_shrink, +}; + +struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *unused) +{ + struct ion_system_secure_heap *heap; + + heap = kzalloc(sizeof(struct ion_system_secure_heap), GFP_KERNEL); + if (!heap) + return ERR_PTR(-ENOMEM); + heap->heap.ops = &system_secure_heap_ops; + heap->heap.type = ION_HEAP_TYPE_SYSTEM_SECURE; + heap->sys_heap = get_ion_heap(ION_SYSTEM_HEAP_ID); + return &heap->heap; +} + +void ion_system_secure_heap_destroy(struct ion_heap *heap) +{ + kfree(heap); +} diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c index e1ff23777c21..fd67158512a5 100644 --- a/drivers/staging/android/ion/msm/msm_ion.c +++ b/drivers/staging/android/ion/msm/msm_ion.c @@ -59,6 +59,10 @@ static struct ion_heap_desc ion_heap_meta[] = { .id = ION_SYSTEM_CONTIG_HEAP_ID, .name = ION_KMALLOC_HEAP_NAME, }, + { + .id = ION_SECURE_HEAP_ID, + .name = ION_SECURE_HEAP_NAME, + }, { .id = ION_CP_MM_HEAP_ID, .name = ION_MM_HEAP_NAME, @@ -366,6 +370,7 @@ static struct heap_types_info { MAKE_HEAP_TYPE_MAPPING(DMA), MAKE_HEAP_TYPE_MAPPING(SECURE_DMA), MAKE_HEAP_TYPE_MAPPING(REMOVED), + MAKE_HEAP_TYPE_MAPPING(SYSTEM_SECURE), }; static int msm_ion_get_heap_type_from_dt_node(struct device_node *node, @@ -644,6 +649,11 @@ out: return ret; } +int ion_heap_is_system_secure_heap_type(enum ion_heap_type type) +{ + return type == ((enum ion_heap_type) ION_HEAP_TYPE_SYSTEM_SECURE); +} + int ion_heap_allow_secure_allocation(enum ion_heap_type type) { return type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA); @@ -921,7 +931,9 @@ static struct ion_heap *msm_ion_heap_create(struct ion_platform_heap *heap_data) case ION_HEAP_TYPE_REMOVED: heap = ion_removed_heap_create(heap_data); break; - + case ION_HEAP_TYPE_SYSTEM_SECURE: + heap = ion_system_secure_heap_create(heap_data); + break; default: heap = ion_heap_create(heap_data); } @@ -953,11 +965,29 @@ static void msm_ion_heap_destroy(struct ion_heap *heap) case ION_HEAP_TYPE_REMOVED: ion_removed_heap_destroy(heap); break; + case ION_HEAP_TYPE_SYSTEM_SECURE: + ion_system_secure_heap_destroy(heap); + break; default: ion_heap_destroy(heap); } } +struct ion_heap *get_ion_heap(int heap_id) +{ + int i; + struct ion_heap *heap; + + for (i = 0; i < num_heaps; i++) { + heap = heaps[i]; + if (heap->id == heap_id) + return heap; + } + + pr_err("%s: heap_id %d not found\n", __func__, heap_id); + return NULL; +} + static int msm_ion_probe(struct platform_device *pdev) { static struct ion_device *new_dev; diff --git a/drivers/staging/android/ion/msm_ion_priv.h b/drivers/staging/android/ion/msm_ion_priv.h index cb9b35c29ed5..c2e97ef39fc6 100644 --- a/drivers/staging/android/ion/msm_ion_priv.h +++ b/drivers/staging/android/ion/msm_ion_priv.h @@ -49,6 +49,9 @@ void ion_iommu_heap_destroy(struct ion_heap *); struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *); void ion_cp_heap_destroy(struct ion_heap *); +struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *); +void ion_system_secure_heap_destroy(struct ion_heap *); + long msm_ion_custom_ioctl(struct ion_client *client, unsigned int cmd, unsigned long arg); @@ -106,6 +109,8 @@ void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base, void ion_mem_map_show(struct ion_heap *heap); +int ion_heap_is_system_secure_heap_type(enum ion_heap_type type); + int ion_heap_allow_secure_allocation(enum ion_heap_type type); int ion_heap_allow_heap_secure(enum ion_heap_type type); diff --git a/drivers/staging/android/uapi/msm_ion.h b/drivers/staging/android/uapi/msm_ion.h index d1b0df383e0d..9a39738a1705 100644 --- a/drivers/staging/android/uapi/msm_ion.h +++ b/drivers/staging/android/uapi/msm_ion.h @@ -6,6 +6,7 @@ enum msm_ion_heap_types { ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1, ION_HEAP_TYPE_SECURE_DMA = ION_HEAP_TYPE_MSM_START, + ION_HEAP_TYPE_SYSTEM_SECURE, ION_HEAP_TYPE_REMOVED, /* * if you add a heap type here you should also add it to @@ -130,8 +131,8 @@ enum cp_mem_usage { #define ION_MM_FIRMWARE_HEAP_NAME "mm_fw" #define ION_PIL1_HEAP_NAME "pil_1" #define ION_PIL2_HEAP_NAME "pil_2" -#define ION_SECURE_HEAP_NAME "secure_heap" #define ION_QSECOM_HEAP_NAME "qsecom" +#define ION_SECURE_HEAP_NAME "secure_heap" #define ION_SET_CACHED(__cache) (__cache | ION_FLAG_CACHED) #define ION_SET_UNCACHED(__cache) (__cache & ~ION_FLAG_CACHED) -- GitLab From e5b7544f7ffb3c7d40706efb3182c3b689b709e4 Mon Sep 17 00:00:00 2001 From: Neeti Desai Date: Mon, 1 Dec 2014 17:50:35 -0800 Subject: [PATCH 075/528] msm: ion: Define the source and destination vm parameters as u32 TZ expects the source and destination vm parameters as u32 integers. Define the parameters as u32 instead of u64. Change-Id: I819427a1ebbb5823cf68acdbb5ea0c451ed313ea Signed-off-by: Neeti Desai (cherry picked from commit 03b590611c5503917a349c1817959a31561ed41a) --- .../android/ion/ion_system_secure_heap.c | 8 +-- drivers/staging/android/ion/msm/msm_ion.h | 9 +++ .../staging/android/ion/msm/secure_buffer.c | 65 +++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index 4c3a00e3db09..bfda753ca3c6 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -59,8 +59,8 @@ static int get_secure_vmid(unsigned long flags) static void ion_system_secure_heap_free(struct ion_buffer *buffer) { int ret; - u64 source_vm; - u64 dest_vm; + u32 source_vm; + u32 dest_vm; struct ion_heap *heap = buffer->heap; struct ion_system_secure_heap *secure_heap = container_of(heap, struct ion_system_secure_heap, @@ -88,8 +88,8 @@ static int ion_system_secure_heap_allocate(struct ion_heap *heap, unsigned long flags) { int ret; - u64 source_vm; - u64 dest_vm; + u32 source_vm; + u32 dest_vm; struct ion_system_secure_heap *secure_heap = container_of(heap, struct ion_system_secure_heap, heap); diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h index ac4840920351..619e9cbe043c 100644 --- a/drivers/staging/android/ion/msm/msm_ion.h +++ b/drivers/staging/android/ion/msm/msm_ion.h @@ -153,6 +153,9 @@ int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, int msm_ion_secure_table(struct sg_table *table); int msm_ion_unsecure_table(struct sg_table *table); +int msm_ion_hyp_assign_call(struct sg_table *table, + u32 *source_vm_list, u32 source_list_size, + u32 *dest_vm_list, u32 dest_list_size); #else static inline struct ion_client *msm_ion_client_create(const char *name) { @@ -182,6 +185,12 @@ static inline int msm_ion_unsecure_table(struct sg_table *table) return -ENODEV; } +static inline int msm_ion_hyp_assign_call(struct sg_table *table, + u32 *source_vm_list, u32 source_list_size, + u32 *dest_vm_list, u32 dest_list_size) +{ + return -ENODEV; +} #endif /* CONFIG_ION */ diff --git a/drivers/staging/android/ion/msm/secure_buffer.c b/drivers/staging/android/ion/msm/secure_buffer.c index 39eb7a944696..7f8d876b0047 100644 --- a/drivers/staging/android/ion/msm/secure_buffer.c +++ b/drivers/staging/android/ion/msm/secure_buffer.c @@ -172,6 +172,71 @@ int msm_ion_unsecure_table(struct sg_table *table) } +<<<<<<< HEAD +======= +static struct info_list *get_info_list(struct sg_table *table) +{ + int i; + struct scatterlist *sg; + struct mem_prot_info *info; + struct info_list *list; + + info = kmalloc_array(table->nents, (sizeof(struct mem_prot_info)), + GFP_KERNEL | __GFP_ZERO); + if (!info) + return NULL; + + for_each_sg(table->sgl, sg, table->nents, i) { + info[i].addr = page_to_phys(sg_page(sg)); + info[i].size = sg->length; + } + + list = kzalloc(sizeof(struct info_list), GFP_KERNEL); + if (!list) { + kfree(info); + return NULL; + } + + list->list_head = info; + list->list_size = table->nents * sizeof(struct mem_prot_info); + return list; +} + +static void destroy_info_list(struct info_list *info_list) +{ + kfree(info_list->list_head); + kfree(info_list); +} + +int msm_ion_hyp_assign_call(struct sg_table *table, + u32 *source_vm_list, u32 source_list_size, + u32 *dest_vm_list, u32 dest_list_size) +{ + struct info_list *info_list = NULL; + int ret; + struct scm_desc desc = {0}; + + info_list = get_info_list(table); + + desc.args[0] = virt_to_phys(info_list->list_head); + desc.args[1] = info_list->list_size; + desc.args[2] = virt_to_phys(source_vm_list); + desc.args[3] = source_list_size; + desc.args[4] = virt_to_phys(dest_vm_list); + desc.args[5] = dest_list_size; + desc.args[6] = 0; + desc.arginfo = SCM_ARGS(7, SCM_RO, SCM_VAL, SCM_RO, SCM_VAL, SCM_RO, + SCM_VAL, SCM_VAL); + + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + MEM_PROT_ASSIGN_ID), &desc); + if (ret) + pr_info("%s: Failed to assign memory protection, ret = %d\n", + __func__, ret); + destroy_info_list(info_list); + return ret; +} + #define MAKE_CP_VERSION(major, minor, patch) \ (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF)) -- GitLab From 327aa7870d29839aaf2bc43666e43ac1ff0e2b51 Mon Sep 17 00:00:00 2001 From: Mitchel Humpherys Date: Tue, 6 Jan 2015 17:56:50 -0800 Subject: [PATCH 076/528] ion: system_secure_heap: add DEFER_FREE heap flag Ion's deferred freeing feature has been shown to greatly improve user experience for some use cases. Enable the feature in the system secure heap by adding the appropriate heap flag. Change-Id: I9be7f2b3365b2d1a086acc3d182d46bfee2e6cfe Signed-off-by: Mitchel Humpherys (cherry picked from commit 3776ca43a9bc5937312d14ed7002c6a409d9cbb5) --- drivers/staging/android/ion/ion_system_secure_heap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index bfda753ca3c6..b7f765715980 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -200,6 +200,7 @@ struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *unused) return ERR_PTR(-ENOMEM); heap->heap.ops = &system_secure_heap_ops; heap->heap.type = ION_HEAP_TYPE_SYSTEM_SECURE; + heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; heap->sys_heap = get_ion_heap(ION_SYSTEM_HEAP_ID); return &heap->heap; } -- GitLab From 37c1cee7fca17a4e9c41df5e2b5a8ec9197f549e Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Mon, 4 Dec 2017 10:58:55 -0800 Subject: [PATCH 077/528] ion: ensure CMO target is valid Cleanup ION cache maintenance code to properly validate the target of userspace cache maintenance requests. Change-Id: I55b8e3584c59634f95250bc7c0bce5d8d70e6a13 Signed-off-by: Liam Mark Signed-off-by: Swetha Chikkaboraiah (cherry picked from commit ec1cbda3c6c2f31c2197347582f0e5ebb056644b) --- drivers/staging/android/ion/ion.c | 5 +++++ drivers/staging/android/ion/ion_system_secure_heap.c | 4 ++-- drivers/staging/android/ion/msm/msm_ion.c | 12 ++++++------ drivers/staging/android/ion/msm_ion_priv.h | 3 ++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index ac2f0e0507ff..25ff062ff523 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1486,6 +1486,11 @@ static int ion_sync_for_device(struct ion_client *client, int fd) } buffer = dmabuf->priv; + if ((buffer->flags & ION_FLAG_SECURE) || (get_secure_vmid(buffer->flags) > 0)) { + pr_err("%s: cannot sync a secure dmabuf\n", __func__); + dma_buf_put(dmabuf); + return -EINVAL; + } dma_sync_sg_for_device(NULL, buffer->sg_table->sgl, buffer->sg_table->nents, DMA_BIDIRECTIONAL); dma_buf_put(dmabuf); diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index b7f765715980..6b55611dcd0d 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -40,7 +40,7 @@ static bool is_cp_flag_present(unsigned long flags) ION_FLAG_CP_CAMERA); } -static int get_secure_vmid(unsigned long flags) +int get_secure_vmid(unsigned long flags) { if (flags & ION_FLAG_CP_TOUCH) return VMID_CP_TOUCH; diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c index fd67158512a5..be9c5af4ea7d 100644 --- a/drivers/staging/android/ion/msm/msm_ion.c +++ b/drivers/staging/android/ion/msm/msm_ion.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014,2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2014, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -281,7 +281,7 @@ int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, if (!ION_IS_CACHED(flags)) return 0; - if (flags & ION_FLAG_SECURE) + if ((flags & ION_FLAG_SECURE) || (get_secure_vmid(flags) > 0)) return 0; table = ion_sg_table(client, handle); @@ -732,11 +732,11 @@ long msm_ion_custom_ioctl(struct ion_client *client, down_read(&mm->mmap_sem); - start = (unsigned long) data.flush_data.vaddr; - end = (unsigned long) data.flush_data.vaddr - + data.flush_data.length; + start = (unsigned long)data.flush_data.vaddr + + data.flush_data.offset; + end = start + data.flush_data.length; - if (start && check_vaddr_bounds(start, end)) { + if (check_vaddr_bounds(start, end)) { pr_err("%s: virtual address %pK is out of bounds\n", __func__, data.flush_data.vaddr); ret = -EINVAL; diff --git a/drivers/staging/android/ion/msm_ion_priv.h b/drivers/staging/android/ion/msm_ion_priv.h index c2e97ef39fc6..9256758c46bd 100644 --- a/drivers/staging/android/ion/msm_ion_priv.h +++ b/drivers/staging/android/ion/msm_ion_priv.h @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_priv.h * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 2018 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -117,6 +117,7 @@ int ion_heap_allow_heap_secure(enum ion_heap_type type); int ion_heap_allow_handle_secure(enum ion_heap_type type); +int get_secure_vmid(unsigned long flags); /** * ion_create_chunked_sg_table - helper function to create sg table * with specified chunk size -- GitLab From e80feb536de78ed22d3384bbbb01add1f66b6fd4 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 20 Mar 2021 18:26:31 +0100 Subject: [PATCH 078/528] ion: cleanup merge --- drivers/staging/android/ion/msm/secure_buffer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/android/ion/msm/secure_buffer.c b/drivers/staging/android/ion/msm/secure_buffer.c index 7f8d876b0047..7d17a8982593 100644 --- a/drivers/staging/android/ion/msm/secure_buffer.c +++ b/drivers/staging/android/ion/msm/secure_buffer.c @@ -172,8 +172,6 @@ int msm_ion_unsecure_table(struct sg_table *table) } -<<<<<<< HEAD -======= static struct info_list *get_info_list(struct sg_table *table) { int i; -- GitLab From df26289d186b18491daec08a4067f4b18be7ca5e Mon Sep 17 00:00:00 2001 From: Neeti Desai Date: Fri, 24 Oct 2014 18:41:45 -0700 Subject: [PATCH 079/528] msm: ion: Add hypervisor call to assign memory protection For certain secure use cases, the memory allocated using ion needs to be re-assigned from one VM's MMU to another VM's MMU. Call into the hypervisor to make this assingment. Change-Id: I172f054e1b4385b8fcdaf7fdc2869034dbbd2db3 Signed-off-by: Neeti Desai (cherry picked from commit 86d5fb38df7f6d8ffad2deb30ab1589e223b91bb) --- drivers/staging/android/ion/msm/msm_ion.h | 9 +++++++-- drivers/staging/android/ion/msm/secure_buffer.c | 17 +++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h index 619e9cbe043c..5613dbc1ec85 100644 --- a/drivers/staging/android/ion/msm/msm_ion.h +++ b/drivers/staging/android/ion/msm/msm_ion.h @@ -154,8 +154,8 @@ int msm_ion_secure_table(struct sg_table *table); int msm_ion_unsecure_table(struct sg_table *table); int msm_ion_hyp_assign_call(struct sg_table *table, - u32 *source_vm_list, u32 source_list_size, - u32 *dest_vm_list, u32 dest_list_size); + u64 *source_vm_list, u32 source_list_size, + u64 *dest_vm_list, u32 dest_list_size); #else static inline struct ion_client *msm_ion_client_create(const char *name) { @@ -186,8 +186,13 @@ static inline int msm_ion_unsecure_table(struct sg_table *table) } static inline int msm_ion_hyp_assign_call(struct sg_table *table, +<<<<<<< HEAD u32 *source_vm_list, u32 source_list_size, u32 *dest_vm_list, u32 dest_list_size) +======= + u64 *source_vm_list, u32 source_list_size, + u64 *dest_vm_list, u32 dest_list_size) +>>>>>>> 86d5fb38df7f (msm: ion: Add hypervisor call to assign memory protection) { return -ENODEV; } diff --git a/drivers/staging/android/ion/msm/secure_buffer.c b/drivers/staging/android/ion/msm/secure_buffer.c index 7d17a8982593..04fe38a84a78 100644 --- a/drivers/staging/android/ion/msm/secure_buffer.c +++ b/drivers/staging/android/ion/msm/secure_buffer.c @@ -37,6 +37,19 @@ struct cp2_lock_req { u32 lock; } __attribute__ ((__packed__)); + +struct mem_prot_info { + phys_addr_t addr; + u64 size; +}; + +struct info_list { + struct mem_prot_info *list_head; + u64 list_size; +}; + + +#define MEM_PROT_ASSIGN_ID 0x16 #define MEM_PROTECT_LOCK_ID2 0x0A #define MEM_PROTECT_LOCK_ID2_FLAT 0x11 #define V2_CHUNK_SIZE SZ_1M @@ -207,8 +220,8 @@ static void destroy_info_list(struct info_list *info_list) } int msm_ion_hyp_assign_call(struct sg_table *table, - u32 *source_vm_list, u32 source_list_size, - u32 *dest_vm_list, u32 dest_list_size) + u64 *source_vm_list, u32 source_list_size, + u64 *dest_vm_list, u32 dest_list_size) { struct info_list *info_list = NULL; int ret; -- GitLab From d9fc3abeb73a7faa5534e9a5aa908a4303715e40 Mon Sep 17 00:00:00 2001 From: Neeti Desai Date: Mon, 1 Dec 2014 17:50:35 -0800 Subject: [PATCH 080/528] msm: ion: Define the source and destination vm parameters as u32 TZ expects the source and destination vm parameters as u32 integers. Define the parameters as u32 instead of u64. Change-Id: I819427a1ebbb5823cf68acdbb5ea0c451ed313ea Signed-off-by: Neeti Desai (cherry picked from commit 03b590611c5503917a349c1817959a31561ed41a) --- drivers/staging/android/ion/msm/msm_ion.h | 9 ++------- drivers/staging/android/ion/msm/secure_buffer.c | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h index 5613dbc1ec85..619e9cbe043c 100644 --- a/drivers/staging/android/ion/msm/msm_ion.h +++ b/drivers/staging/android/ion/msm/msm_ion.h @@ -154,8 +154,8 @@ int msm_ion_secure_table(struct sg_table *table); int msm_ion_unsecure_table(struct sg_table *table); int msm_ion_hyp_assign_call(struct sg_table *table, - u64 *source_vm_list, u32 source_list_size, - u64 *dest_vm_list, u32 dest_list_size); + u32 *source_vm_list, u32 source_list_size, + u32 *dest_vm_list, u32 dest_list_size); #else static inline struct ion_client *msm_ion_client_create(const char *name) { @@ -186,13 +186,8 @@ static inline int msm_ion_unsecure_table(struct sg_table *table) } static inline int msm_ion_hyp_assign_call(struct sg_table *table, -<<<<<<< HEAD u32 *source_vm_list, u32 source_list_size, u32 *dest_vm_list, u32 dest_list_size) -======= - u64 *source_vm_list, u32 source_list_size, - u64 *dest_vm_list, u32 dest_list_size) ->>>>>>> 86d5fb38df7f (msm: ion: Add hypervisor call to assign memory protection) { return -ENODEV; } diff --git a/drivers/staging/android/ion/msm/secure_buffer.c b/drivers/staging/android/ion/msm/secure_buffer.c index 04fe38a84a78..264e4950446c 100644 --- a/drivers/staging/android/ion/msm/secure_buffer.c +++ b/drivers/staging/android/ion/msm/secure_buffer.c @@ -220,8 +220,8 @@ static void destroy_info_list(struct info_list *info_list) } int msm_ion_hyp_assign_call(struct sg_table *table, - u64 *source_vm_list, u32 source_list_size, - u64 *dest_vm_list, u32 dest_list_size) + u32 *source_vm_list, u32 source_list_size, + u32 *dest_vm_list, u32 dest_list_size) { struct info_list *info_list = NULL; int ret; -- GitLab From e51548fc0ba58638eaf122b046c51210787c09e9 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Thu, 18 Jun 2015 11:52:24 +0530 Subject: [PATCH 081/528] msm: ion: fix NULL pointer dereference Fixes a NULL pointer dereference case in msm_ion_hyp_assign_call. Change-Id: Ibcb3f661bcce6472b0f26e9465700650c1cab090 Signed-off-by: Vinayak Menon (cherry picked from commit 28f8498d442fb36eb461f9d52c88c0210e2516e5) --- drivers/staging/android/ion/msm/secure_buffer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/msm/secure_buffer.c b/drivers/staging/android/ion/msm/secure_buffer.c index 264e4950446c..c0523bea1192 100644 --- a/drivers/staging/android/ion/msm/secure_buffer.c +++ b/drivers/staging/android/ion/msm/secure_buffer.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 Google, Inc - * Copyright (c) 2011-2014,2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -229,6 +229,11 @@ int msm_ion_hyp_assign_call(struct sg_table *table, info_list = get_info_list(table); + if (!info_list) { + pr_info("%s: Failed to assign memory protection\n", __func__); + return -ENOMEM; + } + desc.args[0] = virt_to_phys(info_list->list_head); desc.args[1] = info_list->list_size; desc.args[2] = virt_to_phys(source_vm_list); -- GitLab From a1d615c048d1193889d8109846d904d8768e49ef Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 20 Mar 2021 18:36:46 +0100 Subject: [PATCH 082/528] ion: pick up call to unmap instead of map_dma, noticed when comparing with 3.18 --- drivers/staging/android/ion/ion_system_secure_heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index 6b55611dcd0d..7419c0c79fd2 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -143,7 +143,7 @@ static void ion_system_secure_heap_unmap_dma(struct ion_heap *heap, struct ion_system_secure_heap, heap); - secure_heap->sys_heap->ops->map_dma(secure_heap->sys_heap, + secure_heap->sys_heap->ops->unmap_dma(secure_heap->sys_heap, buffer); } -- GitLab From 81e8bc24fba306c389806fc7fa693d257450446e Mon Sep 17 00:00:00 2001 From: Mitchel Humpherys Date: Thu, 12 Feb 2015 15:43:16 -0800 Subject: [PATCH 083/528] ion: remove stale field from struct ion_buffer The dmap_cnt field in struct ion_buffer is not used. Remove it. Change-Id: I8a5d388a0e7df8612e424ca15cee27498c018508 Signed-off-by: Mitchel Humpherys (cherry picked from commit e5e64597e622e4509f9f6974140cb412647c0cdc) --- drivers/staging/android/ion/ion_priv.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 61a870a6fb92..fe59a9a110ad 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -2,7 +2,7 @@ * drivers/staging/android/ion/ion_priv.h * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2014,2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -51,8 +51,7 @@ struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); * @lock: protects the buffers cnt fields * @kmap_cnt: number of times the buffer is mapped to the kernel * @vaddr: the kenrel mapping if kmap_cnt is not zero - * @dmap_cnt: number of times the buffer is mapped for dma - * @sg_table: the sg table for the buffer if dmap_cnt is not zero + * @sg_table: the sg table for the buffer * @pages: flat array of pages in the buffer -- used by fault * handler and only valid for buffers that are faulted in * @vmas: list of vma's mapping this buffer @@ -80,7 +79,6 @@ struct ion_buffer { struct mutex lock; int kmap_cnt; void *vaddr; - int dmap_cnt; struct sg_table *sg_table; struct page **pages; struct list_head vmas; -- GitLab From 0e8ff3fa587e2ed0794879bb0efd506d4fd16f5c Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 20 Mar 2021 18:51:14 +0100 Subject: [PATCH 084/528] arm64: entry-fpsimd.S: fix typo reffering to fpsimd_load instead of fpsimd_save --- arch/arm64/kernel/entry-fpsimd.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S index d358ccacfc00..c44a82f146b1 100644 --- a/arch/arm64/kernel/entry-fpsimd.S +++ b/arch/arm64/kernel/entry-fpsimd.S @@ -52,7 +52,7 @@ ENDPROC(fpsimd_load_state) ENTRY(fpsimd_save_partial_state) fpsimd_save_partial x0, 1, 8, 9 ret -ENDPROC(fpsimd_load_partial_state) +ENDPROC(fpsimd_save_partial_state) /* * Load the bottom n FP registers. -- GitLab From 9e095cb0e79764ad0a26cad10495e0797f4bc085 Mon Sep 17 00:00:00 2001 From: Mitchel Humpherys Date: Thu, 12 Feb 2015 21:28:07 -0800 Subject: [PATCH 085/528] ion: return a fresh sg_table from ion_map_dma_buf DMA mappers often (always?) modify the scatterlist they are given (e.g. dma_address and dma_length) when their dma_map_ops.map_sg operation is called. Currently Ion always returns the same sg_table when it's dma_buf_ops.map_dma_buf operation is called. The result is that when Ion is used as a DMA buf exporter to multiple clients (a common scenario during zero-copy buffer-sharing) those clients will be stomping all over each other since they're both trying to put their mappings into the same sg_table. Fix this by always duplicating the buffer's sg_table in ion_map_dma_buf and returning the duplicate. Each buffer will still always have a single "master" sg_table that should never be exported to the DMA buf framework. Test case (pseudo-code): handle = ion_alloc(); dbuf = ion_share_dma_buf(handle); attach = dma_buf_attach(dbuf); table1 = dma_buf_map_attachment(attach); table2 = dma_buf_map_attachment(attach); dma_map_sg(table1); table2 = dma_buf_map_attachment(attach); dma_map_sg(table2); /* table1 is now hosed */ check_mappings(table1); /* KABOOM */ Change-Id: Ifefa06ecd464c00819b4ae7ac32ad37f1491373b Signed-off-by: Mitchel Humpherys (cherry picked from commit 78b8b7cac5bcdc6ea09ed60c4371dce76ec9951e) --- drivers/staging/android/ion/ion.c | 40 +++++++++++++++++++++++++- drivers/staging/android/ion/ion_priv.h | 6 +++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 25ff062ff523..02f11cbef664 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1090,6 +1090,13 @@ int ion_handle_get_size(struct ion_client *client, struct ion_handle *handle, } EXPORT_SYMBOL(ion_handle_get_size); +/** + * ion_sg_table - get an sg_table for the buffer + * + * NOTE: most likely you should NOT being using this API. + * You should be using Ion as a DMA Buf exporter and using + * the sg_table returned by dma_buf_map_attachment. + */ struct sg_table *ion_sg_table(struct ion_client *client, struct ion_handle *handle) { @@ -1140,6 +1147,30 @@ err0: return ERR_PTR(ret); } +static struct sg_table *ion_dupe_sg_table(struct sg_table *orig_table) +{ + int ret, i; + struct scatterlist *sg, *sg_orig; + struct sg_table *table; + + table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!table) + return NULL; + + ret = sg_alloc_table(table, orig_table->nents, GFP_KERNEL); + if (ret) { + kfree(table); + return NULL; + } + + sg_orig = orig_table->sgl; + for_each_sg(table->sgl, sg, table->nents, i) { + memcpy(sg, sg_orig, sizeof(*sg)); + sg_orig = sg_next(sg_orig); + } + return table; +} + static void ion_buffer_sync_for_device(struct ion_buffer *buffer, struct device *dev, enum dma_data_direction direction); @@ -1149,15 +1180,22 @@ static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment, { struct dma_buf *dmabuf = attachment->dmabuf; struct ion_buffer *buffer = dmabuf->priv; + struct sg_table *table; + + table = ion_dupe_sg_table(buffer->sg_table); + if (!table) + return NULL; ion_buffer_sync_for_device(buffer, attachment->dev, direction); - return buffer->sg_table; + return table; } static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, struct sg_table *table, enum dma_data_direction direction) { + sg_free_table(table); + kfree(table); } void ion_pages_sync_for_device(struct device *dev, struct page *page, diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index fe59a9a110ad..6661cb010890 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -51,7 +51,11 @@ struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); * @lock: protects the buffers cnt fields * @kmap_cnt: number of times the buffer is mapped to the kernel * @vaddr: the kenrel mapping if kmap_cnt is not zero - * @sg_table: the sg table for the buffer + * @sg_table: the sg table for the buffer. Note that if you need + * an sg_table for this buffer, you should likely be + * using Ion as a DMA Buf exporter and using + * dma_buf_map_attachment rather than trying to use this + * field directly. * @pages: flat array of pages in the buffer -- used by fault * handler and only valid for buffers that are faulted in * @vmas: list of vma's mapping this buffer -- GitLab From cb0dbee0affdd9226ae433cff7881591128d8286 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Fri, 30 Oct 2015 15:04:35 +0530 Subject: [PATCH 086/528] ion: fix compile time error with !CONFIG_CMA Let ION compile when CONFIG_CMA is not defined. Change-Id: I6f3cf19a94e3f966c0973c9f8d765ecb752b7a48 Signed-off-by: Vinayak Menon (cherry picked from commit 08dc4d346e45f36b434e2dfb9ed3c13af791abcf) --- drivers/staging/android/ion/ion_priv.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 6661cb010890..3d8575ec8589 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -355,8 +355,16 @@ void ion_carveout_heap_destroy(struct ion_heap *); struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *); void ion_chunk_heap_destroy(struct ion_heap *); +#ifdef CONFIG_CMA struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *); void ion_cma_heap_destroy(struct ion_heap *); +#else +static inline struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *h) +{ + return NULL; +} +static inline void ion_cma_heap_destroy(struct ion_heap *h) {} +#endif /** * kernel api to allocate/free from carveout -- used when carveout is -- GitLab From 71be2099ebdde022e9fe1bd6f13b6c0dfcb150f9 Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Mon, 29 Feb 2016 09:57:46 -0800 Subject: [PATCH 087/528] ion: adjust system heap pool orders As part of the change to fix unmovable block migration over time, we need to reduce the orders requested by ion to under order-5 allocations. In a future CL, we can add fixed-size larger-order pools to improve performance when allocating large buffers. bug 26916944 Change-Id: I1ca336c8057b984987a5a5c28a86ab36488e08ea (cherry picked from commit 086f8db9d250bea5d32d3a2b8e2bfb1790ba690d) --- drivers/staging/android/ion/ion_system_heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 144c3294959e..73994cb2eba6 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -35,7 +35,7 @@ static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_NOWARN | static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_NOWARN); #ifndef CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS -static const unsigned int orders[] = {9, 8, 4, 0}; +static const unsigned int orders[] = {4, 0}; #else static const unsigned int orders[] = {0}; #endif -- GitLab From 5daa2ff96ef6dde03d456306e59d428f28b36a81 Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Wed, 30 Sep 2015 11:07:35 +0530 Subject: [PATCH 088/528] UPSTREAM: staging: ion: Fix error handling in ion_buffer_create This patch fixes error handling case when buffer->pages allocation fails. Also, it removes unreachable code of checking ret variable although it is not updated. Signed-off-by: Rohit kumar Reviewed-by: Laura Abbott Suggested-by: Pintu Kumar Reviewed-by: Pintu Kumar Reviewed-by: Gioh Kim Signed-off-by: Greg Kroah-Hartman (cherry picked from commit a56d092aa94ebcc9452ddaa47423b9a478aa6aa5) Change-Id: Ic38b8e3ef0a21de4e38e58b4bb942535fe671ae5 Bug: 34283718 Git-commit: ad592ac248aeb91448c398dcea5eaeef66790b53 Git-repo: https://android.googlesource.com/kernel/common.git Signed-off-by: Srinivasarao P (cherry picked from commit 0bfa1af9e5c419f798ca821eabe37f9bf33c8b4a) --- drivers/staging/android/ion/ion.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 02f11cbef664..aa617196bf76 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -228,10 +228,10 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, "heap->ops->map_dma should return ERR_PTR on error")) table = ERR_PTR(-EINVAL); if (IS_ERR(table)) { - heap->ops->free(buffer); - kfree(buffer); - return ERR_PTR(PTR_ERR(table)); + ret = -EINVAL; + goto err1; } + buffer->sg_table = table; if (ion_buffer_fault_user_mappings(buffer)) { int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; @@ -241,7 +241,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, buffer->pages = vmalloc(sizeof(struct page *) * num_pages); if (!buffer->pages) { ret = -ENOMEM; - goto err1; + goto err; } for_each_sg(table->sgl, sg, table->nents, i) { @@ -250,9 +250,6 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, for (j = 0; j < sg->length / PAGE_SIZE; j++) buffer->pages[k++] = page++; } - - if (ret) - goto err; } mutex_init(&buffer->lock); @@ -276,10 +273,8 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, err: heap->ops->unmap_dma(heap, buffer); - heap->ops->free(buffer); err1: - if (buffer->pages) - vfree(buffer->pages); + heap->ops->free(buffer); err2: kfree(buffer); return ERR_PTR(ret); -- GitLab From b190319102792224cf7f4c93e1d9d00663964127 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Tue, 26 Jan 2016 17:39:06 +0800 Subject: [PATCH 089/528] BACKPORT: ion:synchronize debugfs callback and ion_client_destroy (cherry picked from commit 948c4db4ee10d85fe78ed3755dcaeb85cd37a148) There are race condition B/T ion_client_destroy and debugfs callbacks. Let's use a mutex to synchronize them. Change-Id: I4d73b258ac1fb67604b62f237da0e004275fd3da Signed-off-by: Neil Zhang Signed-off-by: Greg Kroah-Hartman Git-commit: e5e4ee1de3cdc0a1bed86806afb03643bf547e94 Git-repo: https://android.googlesource.com/kernel/common.git [resolved trivial merge conflicts] Signed-off-by: Srinivasarao P (cherry picked from commit dcca1892fadb9c311d91ccafc0094c219f63406f) --- drivers/staging/android/ion/ion.c | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index aa617196bf76..7df347049c9e 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -845,6 +845,34 @@ void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle) } EXPORT_SYMBOL(ion_unmap_kernel); +static struct mutex debugfs_mutex; +static struct rb_root *ion_root_client; +static int is_client_alive(struct ion_client *client) +{ + struct rb_node *node; + struct ion_client *tmp; + struct ion_device *dev; + + node = ion_root_client->rb_node; + dev = container_of(ion_root_client, struct ion_device, clients); + + down_read(&dev->lock); + while (node) { + tmp = rb_entry(node, struct ion_client, node); + if (client < tmp) { + node = node->rb_left; + } else if (client > tmp) { + node = node->rb_right; + } else { + up_read(&dev->lock); + return 1; + } + } + + up_read(&dev->lock); + return 0; +} + static int ion_debug_client_show(struct seq_file *s, void *unused) { struct ion_client *client = s->private; @@ -877,6 +905,14 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) "heap_name", "size_in_bytes", "handle refcount", "buffer"); + mutex_lock(&debugfs_mutex); + if (!is_client_alive(client)) { + seq_printf(s, "ion_client 0x%p dead, can't dump its buffers\n", + client); + mutex_unlock(&debugfs_mutex); + return 0; + } + mutex_lock(&client->lock); for (n = rb_first(&client->handles); n; n = rb_next(n)) { struct ion_handle *handle = rb_entry(n, struct ion_handle, @@ -891,6 +927,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) seq_printf(s, "\n"); } mutex_unlock(&client->lock); + mutex_unlock(&debugfs_mutex); up_write(&ion_dev->lock); return 0; } @@ -1019,6 +1056,11 @@ void ion_client_destroy(struct ion_client *client) struct rb_node *n; pr_debug("%s: %d\n", __func__, __LINE__); +<<<<<<< HEAD +======= + mutex_lock(&debugfs_mutex); + mutex_lock(&client->lock); +>>>>>>> dcca1892fadb (BACKPORT: ion:synchronize debugfs callback and ion_client_destroy) while ((n = rb_first(&client->handles))) { struct ion_handle *handle = rb_entry(n, struct ion_handle, node); @@ -1038,6 +1080,7 @@ void ion_client_destroy(struct ion_client *client) kfree(client->display_name); kfree(client->name); kfree(client); + mutex_unlock(&debugfs_mutex); } EXPORT_SYMBOL(ion_client_destroy); @@ -1835,6 +1878,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size"); seq_printf(s, "----------------------------------------------------\n"); + mutex_lock(&debugfs_mutex); down_read(&dev->lock); for (n = rb_first(&dev->clients); n; n = rb_next(n)) { struct ion_client *client = rb_entry(n, struct ion_client, @@ -1855,6 +1899,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) } } up_read(&dev->lock); + mutex_unlock(&debugfs_mutex); + seq_printf(s, "----------------------------------------------------\n"); seq_printf(s, "orphaned allocations (info is from last known client):" "\n"); @@ -2090,6 +2136,8 @@ debugfs_done: plist_head_init(&idev->heaps); idev->clients = RB_ROOT; ion_dev = idev; + ion_root_client = &idev->clients; + mutex_init(&debugfs_mutex); return idev; } -- GitLab From bbd8aa6592708633d0d07e1bb3718bdb739ca666 Mon Sep 17 00:00:00 2001 From: Srinivasarao P Date: Thu, 5 Oct 2017 15:48:36 +0530 Subject: [PATCH 090/528] Revert "BACKPORT: ion:synchronize debugfs callback and ion_client_destroy" This reverts commit dcca1892fadb9c311d91ccafc0094c219f63406f. UI freeze issues are observed with this locking so reverting Change-Id: I03ab45a93e5f85b064f82cdc6a7cb316012c9b87 Signed-off-by: Srinivasarao P (cherry picked from commit f9c8e551be19c9d14ae7e98558ef08255fbaadd8) --- drivers/staging/android/ion/ion.c | 48 ------------------------------- 1 file changed, 48 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 7df347049c9e..aa617196bf76 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -845,34 +845,6 @@ void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle) } EXPORT_SYMBOL(ion_unmap_kernel); -static struct mutex debugfs_mutex; -static struct rb_root *ion_root_client; -static int is_client_alive(struct ion_client *client) -{ - struct rb_node *node; - struct ion_client *tmp; - struct ion_device *dev; - - node = ion_root_client->rb_node; - dev = container_of(ion_root_client, struct ion_device, clients); - - down_read(&dev->lock); - while (node) { - tmp = rb_entry(node, struct ion_client, node); - if (client < tmp) { - node = node->rb_left; - } else if (client > tmp) { - node = node->rb_right; - } else { - up_read(&dev->lock); - return 1; - } - } - - up_read(&dev->lock); - return 0; -} - static int ion_debug_client_show(struct seq_file *s, void *unused) { struct ion_client *client = s->private; @@ -905,14 +877,6 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) "heap_name", "size_in_bytes", "handle refcount", "buffer"); - mutex_lock(&debugfs_mutex); - if (!is_client_alive(client)) { - seq_printf(s, "ion_client 0x%p dead, can't dump its buffers\n", - client); - mutex_unlock(&debugfs_mutex); - return 0; - } - mutex_lock(&client->lock); for (n = rb_first(&client->handles); n; n = rb_next(n)) { struct ion_handle *handle = rb_entry(n, struct ion_handle, @@ -927,7 +891,6 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) seq_printf(s, "\n"); } mutex_unlock(&client->lock); - mutex_unlock(&debugfs_mutex); up_write(&ion_dev->lock); return 0; } @@ -1056,11 +1019,6 @@ void ion_client_destroy(struct ion_client *client) struct rb_node *n; pr_debug("%s: %d\n", __func__, __LINE__); -<<<<<<< HEAD -======= - mutex_lock(&debugfs_mutex); - mutex_lock(&client->lock); ->>>>>>> dcca1892fadb (BACKPORT: ion:synchronize debugfs callback and ion_client_destroy) while ((n = rb_first(&client->handles))) { struct ion_handle *handle = rb_entry(n, struct ion_handle, node); @@ -1080,7 +1038,6 @@ void ion_client_destroy(struct ion_client *client) kfree(client->display_name); kfree(client->name); kfree(client); - mutex_unlock(&debugfs_mutex); } EXPORT_SYMBOL(ion_client_destroy); @@ -1878,7 +1835,6 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size"); seq_printf(s, "----------------------------------------------------\n"); - mutex_lock(&debugfs_mutex); down_read(&dev->lock); for (n = rb_first(&dev->clients); n; n = rb_next(n)) { struct ion_client *client = rb_entry(n, struct ion_client, @@ -1899,8 +1855,6 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) } } up_read(&dev->lock); - mutex_unlock(&debugfs_mutex); - seq_printf(s, "----------------------------------------------------\n"); seq_printf(s, "orphaned allocations (info is from last known client):" "\n"); @@ -2136,8 +2090,6 @@ debugfs_done: plist_head_init(&idev->heaps); idev->clients = RB_ROOT; ion_dev = idev; - ion_root_client = &idev->clients; - mutex_init(&debugfs_mutex); return idev; } -- GitLab From 695f4326a608bb467dec65d4981c8a631f8634a8 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 20 Mar 2021 19:20:25 +0100 Subject: [PATCH 091/528] ion: cannot find commit - converting spinlock to mutex --- drivers/staging/android/ion/ion.c | 2 ++ drivers/staging/android/ion/ion_page_pool.c | 33 +++++++++------------ 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index aa617196bf76..eabe1b7a1e72 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1019,6 +1019,7 @@ void ion_client_destroy(struct ion_client *client) struct rb_node *n; pr_debug("%s: %d\n", __func__, __LINE__); + mutex_lock(&client->lock); while ((n = rb_first(&client->handles))) { struct ion_handle *handle = rb_entry(n, struct ion_handle, node); @@ -1026,6 +1027,7 @@ void ion_client_destroy(struct ion_client *client) } idr_destroy(&client->idr); + mutex_unlock(&client->lock); down_write(&dev->lock); if (client->task) diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 2bd59fbfb5f6..c2bf067833f4 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "ion_priv.h" static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) @@ -52,7 +53,7 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool, static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) { - spin_lock(&pool->lock); + mutex_lock(&pool->mutex); if (PageHighMem(page)) { list_add_tail(&page->lru, &pool->high_items); pool->high_count++; @@ -60,7 +61,7 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) list_add_tail(&page->lru, &pool->low_items); pool->low_count++; } - spin_unlock(&pool->lock); + mutex_unlock(&pool->mutex); return 0; } @@ -90,13 +91,13 @@ void *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool) *from_pool = true; - spin_lock(&pool->lock); - if (pool->high_count) - page = ion_page_pool_remove(pool, true); - else if (pool->low_count) - page = ion_page_pool_remove(pool, false); - spin_unlock(&pool->lock); - + if (mutex_trylock(&pool->mutex)) { + if (pool->high_count) + page = ion_page_pool_remove(pool, true); + else if (pool->low_count) + page = ion_page_pool_remove(pool, false); + mutex_unlock(&pool->mutex); + } if (!page) { page = ion_page_pool_alloc_pages(pool); *from_pool = false; @@ -137,22 +138,16 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, for (i = 0; i < nr_to_scan; i++) { struct page *page; - /* - * If the lock is taken, it's better to let other shrinkers - * do their job, rather than spin here. We'll catch up - * next time. - */ - if (!spin_trylock(&pool->lock)) - break; + mutex_lock(&pool->mutex); if (pool->low_count) { page = ion_page_pool_remove(pool, false); } else if (high && pool->high_count) { page = ion_page_pool_remove(pool, true); } else { - spin_unlock(&pool->lock); + mutex_unlock(&pool->mutex); break; } - spin_unlock(&pool->lock); + mutex_unlock(&pool->mutex); ion_page_pool_free_pages(pool, page); } @@ -171,7 +166,7 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) INIT_LIST_HEAD(&pool->high_items); pool->gfp_mask = gfp_mask; pool->order = order; - spin_lock_init(&pool->lock); + mutex_init(&pool->mutex); plist_node_init(&pool->list, order); return pool; -- GitLab From 40c0bb82444b519e091ac085ff961b0f2d9e8d3d Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 20 Mar 2021 19:23:35 +0100 Subject: [PATCH 092/528] ion: part of previous commmit - missed the header - converting spinlock to mutex --- drivers/staging/android/ion/ion_priv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 3d8575ec8589..371b8a7ad5d2 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -393,7 +393,7 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, * @low_count: number of lowmem items in the pool * @high_items: list of highmem items * @low_items: list of lowmem items - * @lock: lock protecting this struct and especially the count + * @mutex: lock protecting this struct and especially the count * item list * @gfp_mask: gfp_mask to use from alloc * @order: order of pages in the pool @@ -409,7 +409,7 @@ struct ion_page_pool { int low_count; struct list_head high_items; struct list_head low_items; - spinlock_t lock; + struct mutex mutex; gfp_t gfp_mask; unsigned int order; struct plist_node list; -- GitLab From e14f6b0a3075909e5250e57b4b1ad402f1da7012 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Mon, 23 Feb 2015 16:04:11 +0530 Subject: [PATCH 093/528] ion: add debug log to clearly account memory held in pools Presently ion debug interface provides total memory held in system heap for cached and uncached pool corresponding to per page order list. Add additional logs to also print total cumulative bytes held together in these pools so that it can be accounted easily. Change-Id: I07dbc45fa99870904cca9b2067b371f4d7247ec5 Signed-off-by: Shiraz Hashim (cherry picked from commit c2f41c6a0abc38add56debda024d1fa7055e7957) --- drivers/staging/android/ion/ion_system_heap.c | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 73994cb2eba6..179182c6441f 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_system_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -411,13 +411,12 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, pool->low_count, pool->order, (1 << pool->order) * PAGE_SIZE * pool->low_count); - } else { - uncached_total += (1 << pool->order) * PAGE_SIZE * - pool->high_count; - uncached_total += (1 << pool->order) * PAGE_SIZE * - pool->low_count; } + uncached_total += (1 << pool->order) * PAGE_SIZE * + pool->high_count; + uncached_total += (1 << pool->order) * PAGE_SIZE * + pool->low_count; } for (i = 0; i < num_orders; i++) { @@ -432,17 +431,29 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, pool->low_count, pool->order, (1 << pool->order) * PAGE_SIZE * pool->low_count); - } else { - cached_total += (1 << pool->order) * PAGE_SIZE * - pool->high_count; - cached_total += (1 << pool->order) * PAGE_SIZE * - pool->low_count; } + + cached_total += (1 << pool->order) * PAGE_SIZE * + pool->high_count; + cached_total += (1 << pool->order) * PAGE_SIZE * + pool->low_count; } - if (!use_seq) - pr_info("uncached pool total = %lu cached pool total %lu\n", + if (use_seq) { + seq_puts(s, "--------------------------------------------\n"); + seq_printf(s, "uncached pool = %lu cached pool = %lu\n", uncached_total, cached_total); + seq_printf(s, "pool total (uncached + cached) = %lu\n", + uncached_total + cached_total); + seq_puts(s, "--------------------------------------------\n"); + } else { + pr_info("-------------------------------------------------\n"); + pr_info("uncached pool = %lu cached pool = %lu\n", + uncached_total, cached_total); + pr_info("pool total (uncached + cached) = %lu\n", + uncached_total + cached_total); + pr_info("-------------------------------------------------\n"); + } return 0; } -- GitLab From 4a1476a38e99849ca3ce19df19615a5c308d6caf Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Wed, 20 May 2015 19:16:19 +0530 Subject: [PATCH 094/528] sync: Permit out-of order sync users A sync user like oneshot may wish to signal points on a timeline out of order. In this case, the sync points cannot be collapsed while merging. Don't collapse these points so they can be signaled as intended by the user. Change-Id: Ia191dc7812fd42a31d39dae17b0b14923fe67e78 Signed-off-by: Lynus Vaz Signed-off-by: Sunil Khatri (cherry picked from commit 2ee121b8ad37cb45a4e3ff1108f841d30e0e0e4e) --- drivers/staging/android/sync.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index b15188623ef9..c60d9060609f 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -345,8 +345,21 @@ static int sync_fence_merge_pts(struct sync_fence *dst, struct sync_fence *src) * the later of the two */ if (dst_pt->parent == src_pt->parent) { - if (dst_pt->parent->ops->compare(dst_pt, src_pt) - == -1) { + int cmp_val; + int (*cmp_fn) + (struct sync_pt *, struct sync_pt *); + + cmp_fn = dst_pt->parent->ops->compare; + cmp_val = cmp_fn(dst_pt, src_pt); + + /* + * Out-of-order users like oneshot don't follow + * a timeline ordering. + */ + if (cmp_val != -cmp_fn(src_pt, dst_pt)) + break; + + if (cmp_val == -1) { struct sync_pt *new_pt = sync_pt_dup(src_pt); if (new_pt == NULL) -- GitLab From 9ab447c6d9921c359fbf82b520890a00ca0d2d0a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 28 Oct 2014 18:22:00 +0530 Subject: [PATCH 095/528] cfg80211: Convert del_station() callback to use a param struct This makes it easier to add new parameters for the del_station calls without having to modify all drivers that use this. Change-Id: Ie3da671f0f41bf1d84dfd99cef87c06b91b522c5 CRs-Fixed: 743605 Git-commit: 89c771e5a62b856f4705f189892c489190edaec1 Git-repo: https://git.kernel.org/cgit/linux/kernel/git/linville/wireless-next.git Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg [asunka@codeaurora.org: resolve trivial merge conflicts and add flag CFG80211_DEL_STA_V2 in include/net/cfg80211.h for backward compatibility] Signed-off-by: Anand N Sunkad Conflicts: include/net/cfg80211.h due to 'cfg80211: Define macro to indicate bssid hint backport support' Signed-off-by: zachariasmaladroit (cherry picked from commit 1d2389ba9332008a2b4a92f20ed39cee75417a95) --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 4 +-- drivers/net/wireless/ath/wil6210/cfg80211.c | 6 +++-- .../wireless/brcm80211/brcmfmac/wl_cfg80211.c | 8 +++--- include/net/cfg80211.h | 22 ++++++++++++++-- net/mac80211/cfg.c | 6 ++--- net/wireless/nl80211.c | 8 +++--- net/wireless/rdev-ops.h | 7 +++--- net/wireless/trace.h | 25 ++++++++++++++++--- 8 files changed, 64 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 008b4d92b29a..be6d096ff945 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2977,11 +2977,11 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac) + struct station_del_parameters *params) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); - const u8 *addr = mac ? mac : bcast_addr; + const u8 *addr = params->mac ? params->mac : bcast_addr; return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 152cecef0378..786451bd29d1 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -792,12 +792,14 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, } static int wil_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *dev, u8 *mac) + struct net_device *dev, + struct station_del_parameters *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); mutex_lock(&wil->mutex); - wil6210_disconnect(wil, mac, WLAN_REASON_UNSPECIFIED, false); + wil6210_disconnect(wil, (u8 *)params->mac, WLAN_REASON_UNSPECIFIED, + false); mutex_unlock(&wil->mutex); return 0; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 8afb60925332..fef9ab790d19 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -3918,24 +3918,24 @@ brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, static int brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, - u8 *mac) + struct station_del_parameters *params) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_scb_val_le scbval; struct brcmf_if *ifp = netdev_priv(ndev); s32 err; - if (!mac) + if (!params->mac) return -EFAULT; - brcmf_dbg(TRACE, "Enter %pM\n", mac); + brcmf_dbg(TRACE, "Enter %pM\n", params->mac); if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; if (!check_vif_up(ifp->vif)) return -EIO; - memcpy(&scbval.ea, mac, ETH_ALEN); + memcpy(&scbval.ea, params->mac, ETH_ALEN); scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, sizeof(scbval)); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e3241dedc1c0..daac3ecc1fe0 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -63,6 +63,8 @@ struct wiphy; #define TDLS_MGMT_VERSION2 1 #define CFG80211_BSSID_HINT_BACKPORT 1 +#define CFG80211_DEL_STA_V2 1 + /* * wireless hardware capability structures */ @@ -699,6 +701,22 @@ struct station_parameters { u8 supported_oper_classes_len; }; +/** + * struct station_del_parameters - station deletion parameters + * + * Used to delete a station entry (or all stations). + * + * @mac: MAC address of the station to remove or NULL to remove all stations + * @subtype: Management frame subtype to use for indicating removal + * (10 = Disassociation, 12 = Deauthentication) + * @reason_code: Reason code for the Disassociation/Deauthentication frame + */ +struct station_del_parameters { + const u8 *mac; + u8 subtype; + u16 reason_code; +}; + /** * enum cfg80211_station_type - the type of station being modified * @CFG80211_STA_AP_CLIENT: client of an AP interface @@ -1915,7 +1933,7 @@ struct cfg80211_qos_map { * @stop_ap: Stop being an AP, including stopping beaconing. * * @add_station: Add a new station. - * @del_station: Remove a station; @mac may be NULL to remove all stations. + * @del_station: Remove a station * @change_station: Modify a given station. Note that flags changes are not much * validated in cfg80211, in particular the auth/assoc/authorized flags * might come to the driver in invalid combinations -- make sure to check @@ -2140,7 +2158,7 @@ struct cfg80211_ops { int (*add_station)(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); int (*del_station)(struct wiphy *wiphy, struct net_device *dev, - u8 *mac); + struct station_del_parameters *params); int (*change_station)(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); int (*get_station)(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b24cfa39bb94..643be8b0f00d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1423,14 +1423,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac) + struct station_del_parameters *params) { struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (mac) - return sta_info_destroy_addr_bss(sdata, mac); + if (params->mac) + return sta_info_destroy_addr_bss(sdata, params->mac); sta_info_flush(sdata); return 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bc0c98754f04..48d7f53eba18 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4274,10 +4274,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; - u8 *mac_addr = NULL; + struct station_del_parameters params; + + memset(¶ms, 0, sizeof(params)); if (info->attrs[NL80211_ATTR_MAC]) - mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]); if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && @@ -4288,7 +4290,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->del_station) return -EOPNOTSUPP; - return rdev_del_station(rdev, dev, mac_addr); + return rdev_del_station(rdev, dev, ¶ms); } static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 6ca590090513..9f5ac1eddf40 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -177,11 +177,12 @@ static inline int rdev_add_station(struct cfg80211_registered_device *rdev, } static inline int rdev_del_station(struct cfg80211_registered_device *rdev, - struct net_device *dev, u8 *mac) + struct net_device *dev, + struct station_del_parameters *params) { int ret; - trace_rdev_del_station(&rdev->wiphy, dev, mac); - ret = rdev->ops->del_station(&rdev->wiphy, dev, mac); + trace_rdev_del_station(&rdev->wiphy, dev, params); + ret = rdev->ops->del_station(&rdev->wiphy, dev, params); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 6a56998af66c..523da67661cf 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -690,9 +690,28 @@ DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) ); -DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_station, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac), - TP_ARGS(wiphy, netdev, mac) +DECLARE_EVENT_CLASS(station_del, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct station_del_parameters *params), + TP_ARGS(wiphy, netdev, params), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(sta_mac) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(sta_mac, params->mac); + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) +); + +DEFINE_EVENT(station_del, rdev_del_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct station_del_parameters *params), + TP_ARGS(wiphy, netdev, params) ); DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station, -- GitLab From 40cde6b996413e2e8d4f474d39553b24b963d4cc Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 29 Oct 2014 18:31:21 +0530 Subject: [PATCH 096/528] cfg80211: Specify frame and reason code for NL80211_CMD_DEL_STATION The optional NL80211_ATTR_MGMT_SUBTYPE and NL80211_ATTR_REASON_CODE attributes can now be included in NL80211_CMD_DEL_STATION to indicate to the driver which frame (Deauthentication/Disassociation) and reason code in that frame should be used to indicate removal to the specific station. This is used by drivers that implement AP SME and generate those frames internally. Change-Id: Ic1b8ba98b5154909c2886a3e130f2846d9e88e76 CRs-Fixed: 743605 Git-commit: 988568669d171774b96e59fe35ef575df7f8cffd Git-repo: https://git.kernel.org/cgit/linux/kernel/git/linville/wireless-next.git Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: Anand N Sunkad (cherry picked from commit 1b8ab919c496311587642b4ec5090ec3bbcd989d) --- include/uapi/linux/nl80211.h | 6 +++++- net/wireless/nl80211.c | 21 +++++++++++++++++++++ net/wireless/trace.h | 10 ++++++++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index a5d54770b91f..98b0ba077c7c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -205,7 +205,11 @@ * the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC * or, if no MAC address given, all stations, on the interface identified - * by %NL80211_ATTR_IFINDEX. + * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and + * %NL80211_ATTR_REASON_CODE can optionally be used to specify which type + * of disconnection indication should be sent to the station + * (Deauthentication or Disassociation frame and reason code for that + * frame). * * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to * destination %NL80211_ATTR_MAC on the interface identified by diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 48d7f53eba18..5b8a81b5ebd7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4290,6 +4290,27 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->del_station) return -EOPNOTSUPP; + if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) { + params.subtype = + nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]); + if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 && + params.subtype != IEEE80211_STYPE_DEAUTH >> 4) + return -EINVAL; + } else { + /* Default to Deauthentication frame */ + params.subtype = IEEE80211_STYPE_DEAUTH >> 4; + } + + if (info->attrs[NL80211_ATTR_REASON_CODE]) { + params.reason_code = + nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (params.reason_code == 0) + return -EINVAL; /* 0 is reserved */ + } else { + /* Default to reason code 2 */ + params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID; + } + return rdev_del_station(rdev, dev, ¶ms); } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 523da67661cf..a378484fd413 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -698,14 +698,20 @@ DECLARE_EVENT_CLASS(station_del, WIPHY_ENTRY NETDEV_ENTRY MAC_ENTRY(sta_mac) + __field(u8, subtype) + __field(u16, reason_code) ), TP_fast_assign( WIPHY_ASSIGN; NETDEV_ASSIGN; MAC_ASSIGN(sta_mac, params->mac); + __entry->subtype = params->subtype; + __entry->reason_code = params->reason_code; ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT, - WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT + ", subtype: %u, reason_code: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), + __entry->subtype, __entry->reason_code) ); DEFINE_EVENT(station_del, rdev_del_station, -- GitLab From 0b7a2d507d634725fa5eaab9fda1a3c7d4f5bfb6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 2 Nov 2014 06:19:33 -0800 Subject: [PATCH 097/528] net: less interrupt masking in NAPI net_rx_action() can mask irqs a single time to transfert sd->poll_list into a private list, for a very short duration. Then, napi_complete() can avoid masking irqs again, and net_rx_action() only needs to mask irq again in slow path. This patch removes 2 couples of irq mask/unmask per typical NAPI run, more if multiple napi were triggered. Note this also allows to give control back to caller (do_softirq()) more often, so that other softirq handlers can be called a bit earlier, or ksoftirqd can be wakeup earlier under pressure. This was developed while testing an alternative to RX interrupt mitigation to reduce latencies while keeping or improving GRO aggregation on fast NIC. Idea is to test napi->gro_list at the end of a napi->poll() and reschedule one NAPI poll, but after servicing a full round of softirqs (timers, TX, rcu, ...). This will be allowed only if softirq is currently serviced by idle task or ksoftirqd, and resched not needed. Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Francisco Franco (cherry picked from commit b65f8ab61282981ae258c3dc25e5dcd15b18fe3f) --- net/core/dev.c | 68 +++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 85e4a9460a95..6824606441b9 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4061,20 +4061,28 @@ static void net_rps_action_and_irq_enable(struct softnet_data *sd) local_irq_enable(); } +static bool sd_has_rps_ipi_waiting(struct softnet_data *sd) +{ +#ifdef CONFIG_RPS + return sd->rps_ipi_list != NULL; +#else + return false; +#endif +} + static int process_backlog(struct napi_struct *napi, int quota) { int work = 0; struct softnet_data *sd = container_of(napi, struct softnet_data, backlog); -#ifdef CONFIG_RPS /* Check if we have pending ipi, its better to send them now, * not waiting net_rx_action() end. */ - if (sd->rps_ipi_list) { + if (sd_has_rps_ipi_waiting(sd)) { local_irq_disable(); net_rps_action_and_irq_enable(sd); } -#endif + napi->weight = weight_p; local_irq_disable(); while (work < quota) { @@ -4108,7 +4116,6 @@ static int process_backlog(struct napi_struct *napi, int quota) * we can use a plain write instead of clear_bit(), * and we dont need an smp_mb() memory barrier. */ - list_del(&napi->poll_list); napi->state = 0; quota = work + qlen; @@ -4141,7 +4148,7 @@ void __napi_complete(struct napi_struct *n) BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); BUG_ON(n->gro_list); - list_del(&n->poll_list); + list_del_init(&n->poll_list); smp_mb__before_atomic(); clear_bit(NAPI_STATE_SCHED, &n->state); } @@ -4159,9 +4166,15 @@ void napi_complete(struct napi_struct *n) return; napi_gro_flush(n, false); - local_irq_save(flags); - __napi_complete(n); - local_irq_restore(flags); + + if (likely(list_empty(&n->poll_list))) { + WARN_ON_ONCE(!test_and_clear_bit(NAPI_STATE_SCHED, &n->state)); + } else { + /* If n->poll_list is not empty, we need to mask irqs */ + local_irq_save(flags); + __napi_complete(n); + local_irq_restore(flags); + } } EXPORT_SYMBOL(napi_complete); @@ -4210,29 +4223,28 @@ static void net_rx_action(struct softirq_action *h) struct softnet_data *sd = &__get_cpu_var(softnet_data); unsigned long time_limit = jiffies + 2; int budget = netdev_budget; + LIST_HEAD(list); + LIST_HEAD(repoll); void *have; local_irq_disable(); + list_splice_init(&sd->poll_list, &list); + local_irq_enable(); - while (!list_empty(&sd->poll_list)) { + while (!list_empty(&list)) { struct napi_struct *n; int work, weight; - /* If softirq window is exhuasted then punt. + /* If softirq window is exhausted then punt. * Allow this to run for 2 jiffies since which will allow * an average latency of 1.5/HZ. */ if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit))) goto softnet_break; - local_irq_enable(); - /* Even though interrupts have been re-enabled, this - * access is safe because interrupts can only add new - * entries to the tail of this list, and only ->poll() - * calls can remove this head entry from the list. - */ - n = list_first_entry(&sd->poll_list, struct napi_struct, poll_list); + n = list_first_entry(&list, struct napi_struct, poll_list); + list_del_init(&n->poll_list); have = netpoll_poll_lock(n); @@ -4254,8 +4266,6 @@ static void net_rx_action(struct softirq_action *h) budget -= work; - local_irq_disable(); - /* Drivers must not modify the NAPI state if they * consume the entire weight. In such cases this code * still "owns" the NAPI instance and therefore can @@ -4263,25 +4273,34 @@ static void net_rx_action(struct softirq_action *h) */ if (unlikely(work == weight)) { if (unlikely(napi_disable_pending(n))) { - local_irq_enable(); napi_complete(n); - local_irq_disable(); } else { if (n->gro_list) { /* flush too old packets * If HZ < 1000, flush all packets. */ - local_irq_enable(); napi_gro_flush(n, HZ >= 1000); - local_irq_disable(); } - list_move_tail(&n->poll_list, &sd->poll_list); + list_add_tail(&n->poll_list, &repoll); } } netpoll_poll_unlock(have); } + + if (!sd_has_rps_ipi_waiting(sd) && + list_empty(&list) && + list_empty(&repoll)) + return; out: + local_irq_disable(); + + list_splice_tail_init(&sd->poll_list, &list); + list_splice_tail(&repoll, &list); + list_splice(&list, &sd->poll_list); + if (!list_empty(&sd->poll_list)) + __raise_softirq_irqoff(NET_RX_SOFTIRQ); + net_rps_action_and_irq_enable(sd); #ifdef CONFIG_NET_DMA @@ -4296,7 +4315,6 @@ out: softnet_break: sd->time_squeeze++; - __raise_softirq_irqoff(NET_RX_SOFTIRQ); goto out; } -- GitLab From 87cc81a9da160ea3d35eac7dfbbac0c2928c7f40 Mon Sep 17 00:00:00 2001 From: Ravinder Konka Date: Tue, 27 Oct 2015 20:31:25 +0530 Subject: [PATCH 098/528] net: rest NAPI bit if IPI failed During hotplug if an RPS CPU goes offline, then there is a possibility that the IPI delivery to the RPS core might fail, this happens in the cases when unruly drivers use netif_rx API in the wrong context. This happens due to two reasons a) Firstly using netif_rx API in non preemptive context leads to enough latencies that the IPI delivery might fail to an RPS core. This is because the softIRQ trigger will become unpredictable. b) by using netif_rx it becomes an architectural issue where we are trying to do two things in two different contexts. We set the NAPI bit in context and sent the IPI in other context. Now since the context switch is allowed, the remote CPU is allowed to go finish its hotplug. If there was no context switch in the first place, which typically happens by either using the correct version of netif_rx or switching to NAPI framework, then the remote CPU is not allowed to go to CPU_DOWN state. This is by design since hotplug framework causes the remote dying CPU to wait until atleast one context switch happens on all other CPUS. If preemption is disabled then the dying CPU has to wait until preemption is enabled and a context switch happens. This patch catches these unruly drivers and handles IPI misses by clearing NAPI sate on remote RPS CPUs. Please refere here for more documentation on hotplug and preemption cases https://lwn.net/Articles/569686/ Change-Id: I072f91bdb4d7e444e3624e8e010ef1b66a67b1ed Acked-by: Abhishek Chauhan Signed-off-by: Ravinder Konka Signed-off-by: franciscofranco (cherry picked from commit 460161223b50c76133878d1063af8dc7bf1c1fcf) --- net/core/dev.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 6824606441b9..0037a6601218 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4051,9 +4051,16 @@ static void net_rps_action_and_irq_enable(struct softnet_data *sd) while (remsd) { struct softnet_data *next = remsd->rps_ipi_next; - if (cpu_online(remsd->cpu)) + if (cpu_online(remsd->cpu)) { __smp_call_function_single(remsd->cpu, &remsd->csd, 0); + } else { + pr_err("%s(), cpu was offline and IPI was not " + "delivered so clean up NAPI", __func__); + rps_lock(remsd); + remsd->backlog.state = 0; + rps_unlock(remsd); + } remsd = next; } } else -- GitLab From 1175abf4358b6b0cfe1618503118b07f7cb1dd3c Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 24 Oct 2017 13:30:13 +0300 Subject: [PATCH 099/528] net: wireless: bcmdhd*: fix warning: initialization from incompatible pointer type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c:7459:17: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types] .del_station = wl_cfg80211_del_station, ^~~~~~~~~~~~~~~~~~~~~~~ drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c:7459:17: note: (near initialization for ‘wl_cfg80211_ops.del_station’) Fix warning due to patch: 1d2389ba9332008a2b4a92f20ed39cee75417a95 ("cfg80211: Convert del_station() callback to use a param struct") Signed-off-by: GreyLeshy (cherry picked from commit b345ceaf217d20b0bdc16af0af3625349535e961) --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 12 +++++++----- drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 5e38c7f33f97..b2a1e240bd0d 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -377,8 +377,9 @@ static s32 wl_cfg80211_resume(struct wiphy *wiphy); 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); -static s32 wl_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *ndev, u8* mac_addr); +static s32 wl_cfg80211_del_station( + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params); static s32 wl_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ @@ -7531,9 +7532,8 @@ static s32 wl_cfg80211_hostapd_sec( 2, 0)) static s32 wl_cfg80211_del_station( - struct wiphy *wiphy, - struct net_device *ndev, - u8* mac_addr) + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params) { struct net_device *dev; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -7545,6 +7545,8 @@ wl_cfg80211_del_station( struct maclist *assoc_maclist = (struct maclist *)mac_buf; int num_associated = 0; + const u8 *mac_addr = params->mac; + WL_DBG(("Entry\n")); if (mac_addr == NULL) { WL_DBG(("mac_addr is NULL ignore it\n")); diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c index 85d6aea376b9..5fb6179e8440 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c @@ -378,8 +378,9 @@ static s32 wl_cfg80211_resume(struct wiphy *wiphy); 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); -static s32 wl_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *ndev, u8* mac_addr); +static s32 wl_cfg80211_del_station( + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params); static s32 wl_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ @@ -6796,9 +6797,8 @@ static s32 wl_cfg80211_hostapd_sec( 2, 0)) static s32 wl_cfg80211_del_station( - struct wiphy *wiphy, - struct net_device *ndev, - u8* mac_addr) + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params) { struct net_device *dev; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -6810,6 +6810,8 @@ wl_cfg80211_del_station( struct maclist *assoc_maclist = (struct maclist *)mac_buf; int num_associated = 0; + const u8 *mac_addr = params->mac; + WL_DBG(("Entry\n")); if (mac_addr == NULL) { WL_DBG(("mac_addr is NULL ignore it\n")); -- GitLab From 4975db1f0a3f50f377d73a3792d97f9d4cb7422c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 1 Nov 2015 16:22:53 +0000 Subject: [PATCH 100/528] drivers: net: fix merge barf --- drivers/net/can/sja1000/sja1000.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 732a8ed571c2..c2d0559115d3 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -187,9 +187,6 @@ static void sja1000_start(struct net_device *dev) /* clear interrupt flags */ priv->read_reg(priv, SJA1000_IR); - /* clear interrupt flags */ - priv->read_reg(priv, SJA1000_IR); - /* leave reset mode */ set_normal_mode(dev); } -- GitLab From 563f234602a19ebae2e0b451756fdd2e1b1ff6ae Mon Sep 17 00:00:00 2001 From: zachariasmaladroit Date: Mon, 2 Oct 2017 01:30:41 +0200 Subject: [PATCH 101/528] bcmdhd, bcmdhd_suzuran: Fix direct references to HZ inspired by work from humberos, kudos ! Signed-off-by: zachariasmaladroit (cherry picked from commit 48f0f48cdaef05be90c6421d105c749dba94d970) --- drivers/net/wireless/bcmdhd/dhd_linux.c | 6 +++--- drivers/net/wireless/bcmdhd/include/linux_osl.h | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c | 4 ++-- drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h | 2 +- drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index f51a04081148..b318dd142773 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -7330,7 +7330,7 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); #endif DHD_PERIM_UNLOCK(pub); @@ -7361,7 +7361,7 @@ dhd_os_d3ack_wait(dhd_pub_t *pub, uint *condition, bool *pending) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); #endif DHD_PERIM_UNLOCK(pub); @@ -7704,7 +7704,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); #else - int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; + int timeout = IOCTL_RESP_TIMEOUT * msecs_to_jiffies(1); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ dhd_os_sdunlock(dhd); diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h index 99e8dffe35e7..c766d4d20eb7 100644 --- a/drivers/net/wireless/bcmdhd/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h @@ -243,7 +243,7 @@ extern int osl_error(int bcmerror); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) #define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) #else -#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#define OSL_SYSUPTIME() ((uint32)jiffies * msecs_to_jiffies(1)) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ #define printf(fmt, args...) printk(fmt , ## args) #include /* for vsn/printf's */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c index c4f6a6461c20..b048b8434e38 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c @@ -5861,7 +5861,7 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); #endif timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); @@ -6233,7 +6233,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); #else - int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; + int timeout = IOCTL_RESP_TIMEOUT * msecs_to_jiffies(1); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ dhd_os_sdunlock(dhd); diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h b/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h index d586e5f8ba60..9b844be2c953 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h @@ -199,7 +199,7 @@ extern int osl_error(int bcmerror); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) #define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) #else -#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#define OSL_SYSUPTIME() ((uint32)jiffies * msecs_to_jiffies(1)) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ #define printf(fmt, args...) printk(fmt , ## args) #include /* for vsn/printf's */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c index 5fb6179e8440..d0a3fb448c3e 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c @@ -9843,7 +9843,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, int max_wait_timeout = 2; int max_wait_count = 100; int refcnt = 0; - unsigned long limit = jiffies + max_wait_timeout * HZ; + unsigned long limit = jiffies + max_wait_timeout * msecs_to_jiffies(1000); while (work_pending(&wdev->cleanup_work)) { if (refcnt%5 == 0) { WL_ERR(("[NETDEV_DOWN] wait for " -- GitLab From d76437a3b635eb6d1734e06d5f2c22682b253c89 Mon Sep 17 00:00:00 2001 From: Komal Seelam Date: Fri, 6 May 2016 13:06:00 +0530 Subject: [PATCH 102/528] cnss: Disable wlan irq when PCIe link down is detected Interrupt Storm is observed on the APPS side, when PCIe link down is simulated, as FW keeps generating interrupts to host, as it's not aware of the PCIe link down. When PCIe link down is identified, wlan platform driver schedules work to start recovery. During Recovery we cut down power to Rome, which stops the interrupt storm. During the window where platform driver schedule work and the work actually gets schedules, interrupt storm happened and the APPS triggered watchdog. Change-Id: Ica3c32007bc9b8acce79c5bb2175790ff27180d0 CRs-Fixed: 967956 Signed-off-by: Komal Kumar Signed-off-by: engstk (cherry picked from commit c2ef09a02d15e330e7680727f28773ed144955b5) --- drivers/net/wireless/cnss/cnss_pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index a9bde7b4f02d..c3a3d9d41475 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -1592,6 +1592,13 @@ void cnss_schedule_recovery_work(void) } EXPORT_SYMBOL(cnss_schedule_recovery_work); +static inline void __cnss_disable_irq(void *data) +{ + struct pci_dev *pdev = data; + + disable_irq(pdev->irq); +} + void cnss_pci_events_cb(struct msm_pcie_notify *notify) { unsigned long flags; @@ -1612,6 +1619,7 @@ void cnss_pci_events_cb(struct msm_pcie_notify *notify) spin_unlock_irqrestore(&pci_link_down_lock, flags); pr_err("PCI link down, schedule recovery\n"); + __cnss_disable_irq(notify->user); schedule_work(&recovery_work); break; -- GitLab From e29a9660fe9ac2ed00975353db23fac4dd9febba Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Tue, 2 Feb 2016 18:02:40 -0800 Subject: [PATCH 103/528] cnss: Fix a boundary check bug in cnss prealloc driver Currently the driver gives a memory slot only if its size is greater than the memory requested by the caller. This will waste a bigger slot if the memory requested is equal to the slot size. Hence fix it by adding the equal check when a memory slot is requested. Change-Id: Ib48477607e9332c8942894301ead606a31fa3284 Signed-off-by: Yue Ma (cherry picked from commit 3fecdddeb30769d038decc6a6f4c110004abd98b) --- drivers/net/wireless/cnss_prealloc/cnss_prealloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c index 8cf48edbe592..d5e419faa1f1 100644 --- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c +++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c @@ -157,7 +157,7 @@ void *wcnss_prealloc_get(unsigned int size) if (wcnss_allocs[i].occupied) continue; - if (wcnss_allocs[i].size > size) { + if (wcnss_allocs[i].size >= size) { /* we found the slot */ wcnss_allocs[i].occupied = 1; spin_unlock_irqrestore(&alloc_lock, flags); -- GitLab From 5bfe444faf6d233ea5f5a226ed0470d29c3a52f1 Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Tue, 20 Jun 2017 13:55:07 +0300 Subject: [PATCH 104/528] wil6210: protect against invalid length of tx management frame Validate buffer length has the minimum needed size when sending management frame to protect against possible buffer overrun. Change-Id: Ib5aed79694100597d7f71a9e8d4e8dba91be538a Signed-off-by: Hamad Kadmany (cherry picked from commit 6d2a904b038749dba724856bc6f3316321891620) --- drivers/net/wireless/ath/wil6210/cfg80211.c | 3 +++ drivers/net/wireless/ath/wil6210/debugfs.c | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 786451bd29d1..9748737082b6 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -495,6 +495,9 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct wmi_sw_tx_complete_event evt; } __packed evt; + if (len < sizeof(struct ieee80211_mgmt)) + return -EINVAL; + cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); if (!cmd) { rc = -ENOMEM; diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 148ae0349222..218508d92bb4 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -697,8 +697,12 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, struct wiphy *wiphy = wil_to_wiphy(wil); struct wireless_dev *wdev = wil_to_wdev(wil); int rc; - void *frame = kmalloc(len, GFP_KERNEL); + void *frame; + if (!len) + return -EINVAL; + + frame = kmalloc(len, GFP_KERNEL); if (!frame) return -ENOMEM; -- GitLab From d0ef8d302ae41a779266bc11a5a90ced085eb2c5 Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Mon, 17 Apr 2017 14:48:16 +0530 Subject: [PATCH 105/528] wcnss: fix the race condition issue during cal data extraction The wcnss platform driver update the wlan calibration data by the user space wlan daemon. The wlan user space daemon store the updated wlan calibration data reported by wlan firmware in user space and write it back to the wcnss platform calibration data buffer for the calibration data download and update. During the wlan calibration data extraction there are some potential race condition which leads to memory leak and buffer overflow during the context switch. Fix the above issue by adding protection code. CRs-Fixed: 2015791 Change-Id: I231807f6b2d8094d7138b95c659ed6272897ba2d Signed-off-by: Sarada Prasanna Garnayak (cherry picked from commit 90ee6c5cce18168d53749a27846ab1c611c0c4dd) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 153d4738ff00..5a714ba55532 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -1991,21 +1991,23 @@ void extract_cal_data(int len) return; } + mutex_lock(&penv->dev_lock); rc = smd_read(penv->smd_ch, (unsigned char *)&calhdr, sizeof(struct cal_data_params)); if (rc < sizeof(struct cal_data_params)) { pr_err("wcnss: incomplete cal header read from smd\n"); + mutex_unlock(&penv->dev_lock); return; } if (penv->fw_cal_exp_frag != calhdr.frag_number) { pr_err("wcnss: Invalid frgament"); - goto exit; + goto unlock_exit; } if (calhdr.frag_size > WCNSS_MAX_FRAME_SIZE) { pr_err("wcnss: Invalid fragment size"); - goto exit; + goto unlock_exit; } if (penv->fw_cal_available) { @@ -2014,8 +2016,9 @@ void extract_cal_data(int len) penv->fw_cal_exp_frag++; if (calhdr.msg_flags & LAST_FRAGMENT) { penv->fw_cal_exp_frag = 0; - goto exit; + goto unlock_exit; } + mutex_unlock(&penv->dev_lock); return; } @@ -2023,7 +2026,7 @@ void extract_cal_data(int len) if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) { pr_err("wcnss: Invalid cal data size %d", calhdr.total_size); - goto exit; + goto unlock_exit; } kfree(penv->fw_cal_data); penv->fw_cal_rcvd = 0; @@ -2031,11 +2034,10 @@ void extract_cal_data(int len) GFP_KERNEL); if (penv->fw_cal_data == NULL) { smd_read(penv->smd_ch, NULL, calhdr.frag_size); - goto exit; + goto unlock_exit; } } - mutex_lock(&penv->dev_lock); if (penv->fw_cal_rcvd + calhdr.frag_size > MAX_CALIBRATED_DATA_SIZE) { pr_err("calibrated data size is more than expected %d", @@ -2070,8 +2072,6 @@ void extract_cal_data(int len) unlock_exit: mutex_unlock(&penv->dev_lock); - -exit: wcnss_send_cal_rsp(fw_status); return; } -- GitLab From dc36eb7b71b86b9e430abe91cf2446891eb4cefb Mon Sep 17 00:00:00 2001 From: Lior David Date: Tue, 17 Oct 2017 11:13:36 +0300 Subject: [PATCH 106/528] wil6210: add block size checks during FW load When loading FW from file add block size checks to ensure a corrupted FW file will not cause the driver to write outside the device memory. Change-Id: I6d7342cd33b2c47b701bcca4ee3cd84febbc56a2 Signed-off-by: Lior David (cherry picked from commit ba89ac2e9ca72600193c780b1d911b418038b028) --- drivers/net/wireless/ath/wil6210/fw_inc.c | 58 ++++++++++++++-------- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + drivers/net/wireless/ath/wil6210/wmi.c | 11 +++- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index d4acf93a9a02..519887a0a513 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -26,14 +26,17 @@ prefix_type, rowsize, \ groupsize, buf, len, ascii) -#define FW_ADDR_CHECK(ioaddr, val, msg) do { \ - ioaddr = wmi_buffer(wil, val); \ - if (!ioaddr) { \ - wil_err_fw(wil, "bad " msg ": 0x%08x\n", \ - le32_to_cpu(val)); \ - return -EINVAL; \ - } \ - } while (0) +static bool wil_fw_addr_check(struct wil6210_priv *wil, + void __iomem **ioaddr, __le32 val, + u32 size, const char *msg) +{ + *ioaddr = wmi_buffer_block(wil, val, size); + if (!(*ioaddr)) { + wil_err_fw(wil, "bad %s: 0x%08x\n", msg, le32_to_cpu(val)); + return false; + } + return true; +} /** * wil_fw_verify - verify firmware file validity @@ -138,7 +141,8 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data, return -EINVAL; } - FW_ADDR_CHECK(dst, d->addr, "address"); + if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address")) + return -EINVAL; wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr), s); wil_memcpy_toio_32(dst, d->data, s); @@ -170,7 +174,8 @@ static int fw_handle_fill(struct wil6210_priv *wil, const void *data, return -EINVAL; } - FW_ADDR_CHECK(dst, d->addr, "address"); + if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address")) + return -EINVAL; v = le32_to_cpu(d->value); wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n", @@ -219,7 +224,8 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data, u32 v = le32_to_cpu(block[i].value); u32 x, y; - FW_ADDR_CHECK(dst, block[i].addr, "address"); + if (!wil_fw_addr_check(wil, &dst, block[i].addr, 0, "address")) + return -EINVAL; x = ioread32(dst); y = (x & m) | (v & ~m); @@ -285,10 +291,15 @@ static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data, wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n", n, gw_cmd); - FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr"); - FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr"); - FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr"); - FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address"); + if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0, + "gateway_addr_addr") || + !wil_fw_addr_check(wil, &gwa_val, d->gateway_value_addr, 0, + "gateway_value_addr") || + !wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0, + "gateway_cmd_addr") || + !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0, + "gateway_ctrl_address")) + return -EINVAL; wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x" " cmd 0x%08x ctl 0x%08x\n", @@ -344,12 +355,19 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data, wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n", n, gw_cmd); - FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr"); + if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0, + "gateway_addr_addr")) + return -EINVAL; for (k = 0; k < ARRAY_SIZE(block->value); k++) - FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k], - "gateway_value_addr"); - FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr"); - FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address"); + if (!wil_fw_addr_check(wil, &gwa_val[k], + d->gateway_value_addr[k], + 0, "gateway_value_addr")) + return -EINVAL; + if (!wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0, + "gateway_cmd_addr") || + !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0, + "gateway_ctrl_address")) + return -EINVAL; wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n", le32_to_cpu(d->gateway_addr_addr), diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0c5170c023c0..6059946709d3 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -655,6 +655,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); void wil_set_ethtoolops(struct net_device *ndev); +void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size); void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c8ac1a17c181..1cae1ea1c37f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -113,13 +113,15 @@ static u32 wmi_addr_remap(u32 x) /** * Check address validity for WMI buffer; remap if needed * @ptr - internal (linker) fw/ucode address + * @size - if non zero, validate the block does not + * exceed the device memory (bar) * * Valid buffer should be DWORD aligned * * return address for accessing buffer from the host; * if buffer is not valid, return NULL. */ -void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) +void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size) { u32 off; u32 ptr = le32_to_cpu(ptr_); @@ -134,10 +136,17 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) off = HOSTADDR(ptr); if (off > WIL6210_MEM_SIZE - 4) return NULL; + if (size && ((off + size > WIL6210_MEM_SIZE) || (off + size < off))) + return NULL; return wil->csr + off; } +void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) +{ + return wmi_buffer_block(wil, ptr_, 0); +} + /** * Check address validity */ -- GitLab From 0cca0c091d28529de4bdcfcc844857fe59366c49 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Thu, 21 Dec 2017 23:28:33 +0300 Subject: [PATCH 107/528] net: wireless: bcmdhd: Update to 1.71.26 * Sony package version: 32.1.D.0.442 [Xperia Z5 (501SO)] Signed-off-by: GreyLeshy (cherry picked from commit 8ee042d1b35b7f011f9e16852e08a0f5200f3cfa) --- drivers/net/wireless/bcmdhd/Makefile | 22 +++-- drivers/net/wireless/bcmdhd/bcmevent.c | 2 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 8 +- drivers/net/wireless/bcmdhd/dhd_pno.c | 48 +++++------ drivers/net/wireless/bcmdhd/dhd_pno.h | 31 ++++--- drivers/net/wireless/bcmdhd/dhd_rtt.c | 29 +++++-- drivers/net/wireless/bcmdhd/include/epivers.h | 10 +-- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 81 ++++++++++--------- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 7 +- 9 files changed, 129 insertions(+), 109 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index cfde5d2da846..e3f6899bef54 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -92,9 +92,6 @@ DHDCFLAGS += -DROAM_ENABLE DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - - - # SoftAP DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP DHDCFLAGS += -DDISABLE_11H_SOFTAP @@ -211,8 +208,6 @@ DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT ANDROID_OFILES := wl_cfgvendor.o - - ########################## # driver type # m: module type driver @@ -293,7 +288,7 @@ endif DHDCFLAGS += -DDISABLE_TXBFR ifeq ($(CONFIG_BCM4356),y) DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD -# DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC endif ifeq ($(BUS_IFACE_SDIO),y) DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 @@ -341,7 +336,6 @@ ifeq ($(BUS_IFACE_PCIE),y) endif - # New Features DHDCFLAGS += -DWL11U DHDCFLAGS += -DBCMCCX @@ -354,7 +348,7 @@ endif DHDCFLAGS += -DSUPPORT_WL_TXPOWER ifeq ($(CONFIG_BCM4354),y) DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD -# DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC endif ifeq ($(BUS_IFACE_SDIO),y) @@ -405,6 +399,7 @@ endif DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP endif endif + ############################# # Platform dependent feature ############################# @@ -447,6 +442,11 @@ ifneq ($(CONFIG_SOMC_WLAN_LOW_POWER_NV_PATH),) endif endif +# Disable to delay link down event +#ifeq ($(CONFIG_SOMC_WLAN_DISABLE_BCM_DLY),y) +# DHDCFLAGS += -DDISABLE_BCN_DLY +#endif + # Change scan time ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) DHDCFLAGS += -DCHANGE_SCAN_TIME @@ -461,6 +461,12 @@ endif ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" endif + +# Enable Disconnection timing log +ifeq ($(CONFIG_SOMC_WLAN_ENABLE_DISC_TIME_LOG),y) + DHDCFLAGS += -DDHD_ENABLE_DISC_TIME_LOG +endif + ######### # Others ######### diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c index 09c569891041..5cc06ac65796 100644 --- a/drivers/net/wireless/bcmdhd/bcmevent.c +++ b/drivers/net/wireless/bcmdhd/bcmevent.c @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmevent.c 642286 2016-06-08 05:57:20Z $ + * $Id: bcmevent.c 718504 2017-08-31 02:38:08Z $ */ #include diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index b318dd142773..7e7263967e65 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -23,7 +23,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 676009 2016-12-20 02:54:41Z $ + * $Id: dhd_linux.c 718504 2017-08-31 02:38:08Z $ */ #include @@ -8175,12 +8175,12 @@ void * dhd_dev_hotlist_scan_event(struct net_device *dev, /* Linux wrapper to call common dhd_process_full_gscan_result */ void * dhd_dev_process_full_gscan_result(struct net_device *dev, -const void *data, uint32 len, int *send_evt_bytes) + + const void *data, uint32 len, int *send_evt_bytes) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return dhd_process_full_gscan_result(&dhd->pub, data, len, - send_evt_bytes); + return (dhd_process_full_gscan_result(&dhd->pub, data, len, send_evt_bytes)); } void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c index 5566f7019ae7..143e280bc190 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd/dhd_pno.c @@ -91,8 +91,7 @@ #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") #define TIME_MIN_DIFF 5 - -#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) +#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) #define EVENT_MAX_NETCNT \ ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_t)) \ / sizeof(wl_pfn_net_info_t) + 1) @@ -2109,8 +2108,7 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); - pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) - MALLOCZ(dhd->osh, gscan_param_size); + pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size); if (!pfn_gscan_cfg_t) { DHD_ERROR(("%s: failed to malloc memory of size %d\n", @@ -2229,7 +2227,6 @@ exit: (tot_num_buckets * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); } return err; - } static wl_pfn_gscan_ch_bucket_cfg_t * @@ -3489,8 +3486,8 @@ dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) } void * -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, - int *size) + +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size) { wl_bss_info_t *bi = NULL; wl_gscan_result_t *gscan_result; @@ -3511,16 +3508,18 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); goto exit; } +<<<<<<< HEAD +======= +>>>>>>> 8ee042d1b35b (net: wireless: bcmdhd: Update to 1.71.26) if ((len < sizeof(*gscan_result)) || (len < dtoh32(gscan_result->buflen)) || (dtoh32(gscan_result->buflen) > (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { - DHD_ERROR(("%s: invalid gscan buflen:%u\n", __func__, - dtoh32(gscan_result->buflen))); + DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__, + dtoh32(gscan_result->buflen))); goto exit; } - if (!gscan_result->bss_info) { DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); goto exit; @@ -3532,31 +3531,16 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } - bi_ie_offset = dtoh32(bi->ie_offset); bi_ie_length = dtoh32(bi->ie_length); if ((bi_ie_offset + bi_ie_length) > bi_length) { DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n", - __func__, bi_ie_length, bi_ie_offset)); + __FUNCTION__, bi_ie_length, bi_ie_offset)); goto exit; } - - if ((bi->SSID_len > DOT11_MAX_SSID_LEN)|| - (bi->ie_length > (*size - sizeof(wl_bss_info_t))) || - (bi->ie_offset < sizeof(wl_bss_info_t)) || - (bi->ie_offset > (sizeof(wl_bss_info_t) + bi->ie_length))){ - DHD_ERROR(("%s: tot:%d,SSID:%d,ie_len:%d,ie_off:%d\n", - __FUNCTION__, *size, bi->SSID_len, - bi->ie_length, bi->ie_offset)); - return NULL; - } - - gas_data = (wl_event_gas_t *)((uint8 *)data + bi->ie_offset + bi->ie_length); - - if (gas_data->data_len > (*size - (bi->ie_offset + bi->ie_length))) { - DHD_ERROR(("%s: wrong gas_data_len:%d\n", - __FUNCTION__, gas_data->data_len)); - return NULL; + if (bi->SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length:%u\n", __FUNCTION__, bi->SSID_len)); + goto exit; } mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi_ie_length; @@ -3654,6 +3638,12 @@ dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int } if (pfn_result->version != PFN_SCANRESULT_VERSION) { + /* Check if count of pfn results is corrupted */ + if (pfn_result->count > EVENT_MAX_NETCNT) { + DHD_ERROR(("%s event %d: pfn results count %d" + "exceeds the max limit\n", __FUNCTION__, event, pfn_result->count)); + return NULL; + } DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, pfn_result->version, PFN_SCANRESULT_VERSION)); return NULL; diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h index c05b3f361b14..dc99441fa47a 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd/dhd_pno.h @@ -349,18 +349,18 @@ typedef struct gscan_results_cache { } gscan_results_cache_t; typedef struct dhd_pno_gscan_capabilities { - int max_scan_cache_size; - int max_scan_buckets; - int max_ap_cache_per_scan; - int max_rssi_sample_size; - int max_scan_reporting_threshold; - int max_hotlist_bssids; - int max_hotlist_ssids; - int max_significant_wifi_change_aps; - int max_bssid_history_entries; - int max_epno_ssid_crc32; - int max_epno_hidden_ssid; - int max_white_list_ssid; + int max_scan_cache_size; + int max_scan_buckets; + int max_ap_cache_per_scan; + int max_rssi_sample_size; + int max_scan_reporting_threshold; + int max_hotlist_bssids; + int max_hotlist_ssids; + int max_significant_wifi_change_aps; + int max_bssid_history_entries; + int max_epno_ssid_crc32; + int max_epno_hidden_ssid; + int max_white_list_ssid; } dhd_pno_gscan_capabilities_t; struct dhd_pno_gscan_params { @@ -483,7 +483,7 @@ int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes, hotlist_type_t type); void * dhd_dev_process_full_gscan_result(struct net_device *dev, - const void *data, uint32 len, int *send_evt_bytes); + const void *data, uint32 len, int *send_evt_bytes); extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); @@ -527,9 +527,8 @@ extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, hotlist_type_t type); -extern void * -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, - uint32 len, int *send_evt_bytes); +extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, + uint32 len, int *send_evt_bytes); extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); diff --git a/drivers/net/wireless/bcmdhd/dhd_rtt.c b/drivers/net/wireless/bcmdhd/dhd_rtt.c index f546079d7fd9..2e74c22b8a82 100644 --- a/drivers/net/wireless/bcmdhd/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd/dhd_rtt.c @@ -1601,22 +1601,36 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) gfp_t kflags; bool is_new = TRUE; + DHD_RTT(("Enter %s \n", __FUNCTION__)); NULL_CHECK(dhd, "dhd is NULL", ret); + +#ifdef WL_CFG80211 rtt_status = GET_RTTSTATE(dhd); NULL_CHECK(rtt_status, "rtt_status is NULL", ret); - event_type = ntoh32_ua((void *)&event->event_type); - - if (event_type != WLC_E_PROXD) { - goto exit; - } if (RTT_IS_STOPPED(rtt_status)) { /* Ignore the Proxd event */ + DHD_RTT((" event handler rtt is stopped \n")); goto exit; } +#endif /* WL_CFG80211 */ + if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) { + DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__, + ntoh32_ua((void *)&event->datalen))); + ret = -EINVAL; + goto exit; + } + event_type = ntoh32_ua((void *)&event->event_type); + if (event_type != WLC_E_PROXD) { + DHD_ERROR((" failed event \n")); + ret = -EINVAL; + goto exit; + } + if (!event_data) { - DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); - return -EINVAL; + DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); + ret = -EINVAL; + goto exit; } p_event = (wl_proxd_event_t *) event_data; version = ltoh16(p_event->version); @@ -1637,6 +1651,7 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) p_loginfo = ftm_get_event_type_loginfo(event_type); if (p_loginfo == NULL) { DHD_ERROR(("receive an invalid FTM event %d\n", event_type)); + ret = -EINVAL; goto exit; /* ignore this event */ } /* get TLVs len, skip over event header */ diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 5d7e6a0d633b..8624621913d9 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -30,19 +30,19 @@ #define EPI_MINOR_VERSION 71 -#define EPI_RC_NUMBER 21 +#define EPI_RC_NUMBER 26 #define EPI_INCREMENTAL_NUMBER 0 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 71, 21, 0 +#define EPI_VERSION 1, 71, 26, 0 -#define EPI_VERSION_NUM 0x01471500 +#define EPI_VERSION_NUM 0x01471a00 -#define EPI_VERSION_DEV 1.71.21 +#define EPI_VERSION_DEV 1.71.26 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.71.21 (r)" +#define EPI_VERSION_STR "1.71.26 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index b2a1e240bd0d..c891e35965e6 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 676010 2016-12-20 03:01:18Z $ + * $Id: wl_cfg80211.c 718504 2017-08-31 02:38:08Z $ */ /* */ #include @@ -377,9 +377,8 @@ static s32 wl_cfg80211_resume(struct wiphy *wiphy); 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); -static s32 wl_cfg80211_del_station( - struct wiphy *wiphy, struct net_device *ndev, - struct station_del_parameters *params); +static s32 wl_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *ndev, u8* mac_addr); static s32 wl_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ @@ -7532,8 +7531,9 @@ static s32 wl_cfg80211_hostapd_sec( 2, 0)) static s32 wl_cfg80211_del_station( - struct wiphy *wiphy, struct net_device *ndev, - struct station_del_parameters *params) + struct wiphy *wiphy, + struct net_device *ndev, + u8* mac_addr) { struct net_device *dev; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -7545,8 +7545,6 @@ wl_cfg80211_del_station( struct maclist *assoc_maclist = (struct maclist *)mac_buf; int num_associated = 0; - const u8 *mac_addr = params->mac; - WL_DBG(("Entry\n")); if (mac_addr == NULL) { WL_DBG(("mac_addr is NULL ignore it\n")); @@ -9134,6 +9132,10 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, s32 err = 0; u32 event = ntoh32(e->event_type); +#ifdef DHD_ENABLE_DISC_TIME_LOG + struct timeval tv_now; + do_gettimeofday(&tv_now); +#endif /* DHD_ENABLE_DISC_TIME_LOG */ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { @@ -9174,6 +9176,10 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; +#ifdef DHD_ENABLE_DISC_TIME_LOG + printk("KERN_ERR [Log]%s: current time=%lu\n", __FUNCTION__, + (unsigned long int) tv_now.tv_sec*1000000+tv_now.tv_usec); +#endif /* DHD_ENABLE_DISC_TIME_LOG */ printk("link down if %s may call cfg80211_disconnected. " "event : %d, reason=%d from " MACDBG "\n", ndev->name, event, ntoh32(e->reason), @@ -9873,9 +9879,7 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } break; case WLC_E_PFN_GSCAN_FULL_RESULT: - ptr = - dhd_dev_process_full_gscan_result(ndev, data, len, - &send_evt_bytes); + ptr = dhd_dev_process_full_gscan_result(ndev, data, len, &send_evt_bytes); if (ptr) { wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, @@ -10066,21 +10070,26 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wifi_p2p_pub_act_frame_t *act_frm = NULL; wifi_p2p_action_frame_t *p2p_act_frm = NULL; wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; - wl_event_rx_frame_data_t *rxframe = - (wl_event_rx_frame_data_t*)data; - u32 event = ntoh32(e->event_type); + wl_event_rx_frame_data_t *rxframe; + u32 event; u8 *mgmt_frame; - u8 bsscfgidx = e->bsscfgidx; - u32 mgmt_frame_len = ntoh32(e->datalen); - u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); + u8 bsscfgidx; + u32 mgmt_frame_len; + u16 channel; bool retval; - - if (mgmt_frame_len < sizeof(wl_event_rx_frame_data_t)) { - WL_ERR(("wrong datalen:%d\n", mgmt_frame_len)); + if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) { + WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen))); return -EINVAL; } - mgmt_frame_len -= sizeof(wl_event_rx_frame_data_t); - + mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); + event = ntoh32(e->event_type); + bsscfgidx = e->bsscfgidx; + rxframe = (wl_event_rx_frame_data_t *)data; + if (!rxframe) { + WL_ERR(("rxframe: NULL\n")); + return -EINVAL; + } + channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK); memset(&bssid, 0, ETHER_ADDR_LEN); ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); @@ -10219,11 +10228,9 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, mgmt_frame_len = ntoh32(e->datalen); if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) { - WL_ERR(("WLC_E_PROBREQ_MSG - wrong datalen:%d\n", - mgmt_frame_len)); + WL_ERR(("wrong datalen:%d\n", mgmt_frame_len)); return -EINVAL; } - prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN; /* Parse prob_req IEs */ @@ -10947,11 +10954,9 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("Invalid escan result (NULL pointer)\n")); goto exit; } - if ((dtoh32(escan_result->buflen) > ESCAN_BUF_SIZE) || - (dtoh32(escan_result->buflen) < - sizeof(wl_escan_result_t))) { - WL_ERR(("Invalid escan buffer len:%d\n", - dtoh32(escan_result->buflen))); + if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) || + (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) { + WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen))); goto exit; } if (dtoh16(escan_result->bss_count) != 1) { @@ -12922,7 +12927,7 @@ static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *i { u8 *ssidie; int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); - int32 remaining_ie_buf_len, available_buffer_len; + int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len; ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); /* ERROR out if * 1. No ssid IE is FOUND or @@ -12936,24 +12941,28 @@ static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *i } available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream); remaining_ie_buf_len = available_buffer_len - (int)ssidie[1]; - if ((ssid_len > ssidie[1]) || - (ssidie[1] > available_buffer_len)) { + unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size); + if (ssidie[1] > available_buffer_len) { + WL_ERR(("%s: skip wl_update_hidden_ap_ie : overflow\n", __FUNCTION__)); return; } if (ssidie[1] != ssid_len) { if (ssidie[1]) { - WL_ERR(("%s: Wrong SSID len: %d != %d\n", + WL_INFORM(("%s: Wrong SSID len: %d != %d\n", __FUNCTION__, ssidie[1], bi->SSID_len)); } - if (roam) { - WL_ERR(("Changing the SSID Info.\n")); + if ((roam && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) { + WL_INFORM(("Changing the SSID Info.\n")); memmove(ssidie + ssid_len + 2, (ssidie + 2) + ssidie[1], remaining_ie_buf_len); memcpy(ssidie + 2, bi->SSID, ssid_len); *ie_size = *ie_size + ssid_len - ssidie[1]; ssidie[1] = ssid_len; + } else if (ssid_len < ssidie[1]) { + WL_ERR(("%s: Invalid SSID len: %d < %d\n", + __FUNCTION__, ssidie[1], bi->SSID_len)); } return; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index af10ad5d4d18..6d0efd046d00 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfgp2p.c 528497 2015-01-22 10:58:38Z $ + * $Id: wl_cfgp2p.c 711632 2017-07-19 04:24:04Z $ * */ #include @@ -2321,8 +2321,9 @@ wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib) return pAttrib; } else { - parse += (ie->len + TLV_HDR_LEN); - len -= (ie->len + TLV_HDR_LEN); + /* move to next IE */ + len -= (u32)((u8 *)ie + TLV_HDR_LEN + ie->len - parse); + parse = (uint8 *)ie + TLV_HDR_LEN + ie->len; CFGP2P_INFO(("P2P Attribute %d not found Moving parse" " to %p len to %d", attrib, parse, len)); } -- GitLab From 4b5fdc7649a3e92d4ecd3a0fccba6b50acba781e Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Sun, 7 Jan 2018 10:25:18 +0300 Subject: [PATCH 108/528] wireless: bcmdhd*: fix warning "tautological-compare" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /drivers/net/wireless/bcmdhd_suzuran/siutils.c: In function ‘si_doattach’: /drivers/net/wireless/bcmdhd_suzuran/siutils.c:404:14: warning: self-comparison always evaluates to false [-Wtautological-compare] if (bustype != BUSTYPE(bustype)) { ^~ (cherry picked from commit 80c01907e71605b80ebe0098c9579d0633b4fbb2) --- drivers/net/wireless/bcmdhd/siutils.c | 3 ++- drivers/net/wireless/bcmdhd_suzuran/siutils.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c index 6ae7c4c323d2..c2ba1fbd68e6 100644 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd/siutils.c @@ -495,12 +495,13 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, } sih->bustype = bustype; +#ifdef BCMBUSTYPE if (bustype != BUSTYPE(bustype)) { SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); return NULL; } - +#endif /* bus/core/clk setup for register access */ if (!si_buscore_prep(sii, bustype, devid, sdh)) { SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); diff --git a/drivers/net/wireless/bcmdhd_suzuran/siutils.c b/drivers/net/wireless/bcmdhd_suzuran/siutils.c index 822161a5fbe7..64c2ba14b607 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/siutils.c +++ b/drivers/net/wireless/bcmdhd_suzuran/siutils.c @@ -401,12 +401,13 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, } sih->bustype = bustype; +#ifdef BCMBUSTYPE if (bustype != BUSTYPE(bustype)) { SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); return NULL; } - +#endif /* bus/core/clk setup for register access */ if (!si_buscore_prep(sii, bustype, devid, sdh)) { SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); -- GitLab From fa29d807b4068ff8997727b0ceac36fc9cb8922e Mon Sep 17 00:00:00 2001 From: Jingxiang Ge Date: Mon, 17 Jul 2017 11:37:55 +0800 Subject: [PATCH 109/528] cnss: ignore pci suspend/resume when target is power down Ignore pci suspend/resume operation when target is power down. Change-Id: I805e34f27e31b17a1afb4e579aa56e9ee94f68ea CRs-Fixed: 2050280 Signed-off-by: Jingxiang Ge (cherry picked from commit 0d74d8ff363c0ee094b99b5f3a8d5a197a91e689) --- drivers/net/wireless/cnss/cnss_pci.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index c3a3d9d41475..98e5a989a6aa 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -1364,6 +1364,9 @@ static int cnss_wlan_pci_suspend(struct device *dev) if (!penv) goto out; + if (!penv->pcie_link_state) + goto out; + wdriver = penv->driver; if (!wdriver) goto out; @@ -1391,6 +1394,9 @@ static int cnss_wlan_pci_resume(struct device *dev) if (!penv) goto out; + if (!penv->pcie_link_state) + goto out; + wdriver = penv->driver; if (!wdriver) goto out; -- GitLab From 0553dad481423323ca8a0d43418efc429e9e0a94 Mon Sep 17 00:00:00 2001 From: Monam Agarwal Date: Mon, 24 Mar 2014 00:05:56 +0530 Subject: [PATCH 110/528] iwlwifi: mvm: Use RCU_INIT_POINTER(x, NULL) rcu_assign_pointer() ensures that the initialization of a structure is carried out before storing a pointer to that structure. However, in the case that NULL is assigned there's no structure to initialize so using RCU_INIT_POINTER instead is safe and more efficient. Signed-off-by: Monam Agarwal [rewrite commit log] Signed-off-by: Emmanuel Grumbach (cherry picked from commit 88b0ee2b6a8d98b9c580d0c9130aa1ba922e0638) --- drivers/net/wireless/iwlwifi/mvm/sta.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 68f0bbe1f381..9f2d8c8e22bd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -365,7 +365,7 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk) sta_id); continue; } - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); clear_bit(sta_id, mvm->sta_drained); } @@ -420,7 +420,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, } else { spin_unlock_bh(&mvm_sta->lock); ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); - rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); } return ret; @@ -434,7 +434,7 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); return ret; } @@ -456,7 +456,7 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) { - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); sta->sta_id = IWL_MVM_STATION_COUNT; } -- GitLab From 2b54b5329727e6ad916b9be29f9031bd3f0738be Mon Sep 17 00:00:00 2001 From: Insun Song Date: Mon, 3 Aug 2015 16:41:42 -0700 Subject: [PATCH 111/528] net: wireless: bcmdhd: fix for watch dog issue in wifi connect test bug => 22666437 fix for watchdog issue in fast switching APs. preventing numerous escan result which trigger watchdog. Change-Id: I835401008a644290df947e4bab1cedbd1599f6e6 Signed-off-by: Insun Song (cherry picked from commit 7109d83163506fd4edf298a6826c29ac26571d60) --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index c891e35965e6..d45f5a01e2af 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -11192,16 +11192,7 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); } -#ifdef GSCAN_SUPPORT - else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN)) { - if (status == WLC_E_STATUS_NEWSCAN) { - WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, - escan_result->bss_count)); - } -#else else if (status == WLC_E_STATUS_ABORT) { -#endif /* GSCAN_SUPPORT */ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; wl_escan_print_sync_id(status, escan_result->sync_id, cfg->escan_info.cur_sync_id); -- GitLab From 75138117456771d028e35612cf417f197aa0d03f Mon Sep 17 00:00:00 2001 From: Ashwin Date: Fri, 16 Oct 2015 15:53:47 -0700 Subject: [PATCH 112/528] net: wireless: bcmdhd: add a NULL check Check if the gscan result buffer was succesfully allocated Bug: 24469238 Change-Id: I1e896faed42ce53bc36ada449cc4e1c975830159 Signed-off-by: Ashwin (cherry picked from commit eef7880f87af1c16eb3a1ddeaee48db3a78c6fc8) --- drivers/net/wireless/bcmdhd/dhd_pno.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c index 143e280bc190..1fda5f924087 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd/dhd_pno.c @@ -2587,6 +2587,12 @@ _dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) } plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + if (!plbestnet) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, + PNO_BESTNET_LEN)); + err = BCME_NOMEM; + goto exit; + } mutex_lock(&_pno_state->pno_mutex); -- GitLab From 36870ecf480cfe108ee030d09289756851ae112d Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Sat, 5 Mar 2016 19:51:40 -0800 Subject: [PATCH 113/528] net: bcmdhd: Fix CONFIG_HZ dependency in wifi driver. Sleep for HZ jiffies, not 100. bug 27419732 Change-Id: I9717f2b539a7fe2e2ba2cd6c3fd231f987ec38a4 (cherry picked from commit 5697b1456ca44928ab3faed159cd415ed1077e24) --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index d45f5a01e2af..38234161118b 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -10718,7 +10718,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } set_current_state(TASK_INTERRUPTIBLE); - (void)schedule_timeout(100); + (void)schedule_timeout(HZ); set_current_state(TASK_RUNNING); refcnt++; } -- GitLab From dcf0ac1650e4fc310fd9c0ab1d2e552f90376448 Mon Sep 17 00:00:00 2001 From: Mir Ali Date: Mon, 20 Jun 2016 15:23:42 +0530 Subject: [PATCH 114/528] net: wireless: bcmdhd: Check to avoid sending Disassoc in unassociated state The change is meant to send a Disassoc request only in the connected state thereby handling the case of a erroneous Diassoc from firmware BUG=28336924 Signed-off-by: Mir Ali Signed-off-by: Andrey Cherepkov (cherry picked from commit b0db2ebd357c370505028e45ba3f88cf0e5f47c1) --- drivers/net/wireless/bcmdhd/wldev_common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c index 5684326bd1db..a8713802fb0e 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/bcmdhd/wldev_common.c @@ -31,6 +31,7 @@ #include #include +#include #define htod32(i) (i) #define htod16(i) (i) @@ -413,6 +414,9 @@ int wldev_set_country( wl_country_t cspec = {{0}, 0, {0}}; scb_val_t scbval; char smbuf[WLC_IOCTL_SMLEN]; + struct wireless_dev *wdev = ndev_to_wdev(dev); + struct wiphy *wiphy = wdev->wiphy; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); if (!country_code) return error; @@ -427,7 +431,7 @@ int wldev_set_country( if ((error < 0) || (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { - if (user_enforced) { + if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) { bzero(&scbval, sizeof(scb_val_t)); error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); if (error < 0) { -- GitLab From 91062b7a94290956ff574b6c5324a5d0e9236308 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Thu, 14 Jul 2016 14:49:48 -0700 Subject: [PATCH 115/528] net: wireless: bcmdhd: add boundary check while getting channel spec [PORT][angler] Adding check for chanspec-list count. If count is over than maximum, then cancel current process and immediately return. This will also prevent kernel panic once caused by watchdog timeout. bug=29863589 Change-Id: Ib2de9d71ca39c3fd97a7d684db9925940904e404 Signed-off-by: Insun Song Conflicts: drivers/net/wireless/bcmdhd/wl_cfg80211.c due to ' band = array_size = n_2g = n_5g = 0;' Signed-off-by: zachariasmaladroit (cherry picked from commit 150d2bb3422399abbd39a1a152c117351483dbb3) --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 38234161118b..f372d6aee357 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -12175,6 +12175,13 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) #undef LOCAL_BUF_LEN list = (wl_uint32_list_t *)(void *)pbuf; + + if ((list) && (dtoh32(list->count) > htod32(WL_NUMCHANSPECS))) { + WL_ERR(("Invalid channel list : %d\n", dtoh32(list->count))); + kfree(pbuf); + return INVCHANSPEC; + } + band = array_size = n_2g = n_5g = 0; for (i = 0; i < dtoh32(list->count); i++) { index = 0; -- GitLab From 10abae3d55c7c0b9fb8942d6bb9d3b282594cae2 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Tue, 31 Jan 2017 16:18:40 -0800 Subject: [PATCH 116/528] net: wireless: bcmdhd: fix buffer overrun in wl_android_set_roampref added boundary check not to override allocated buffer. Specially when user input corrupted or manipulated. Bug: 34469904 Change-Id: Id6196da10111517696eda5f186b1e2dd19f66085 Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit e29c82cfdbf5b1b033a586a4a9a84b8ce24ac675) --- drivers/net/wireless/bcmdhd/wl_android.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index d02169804c49..90d97896ce90 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -1627,8 +1627,8 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); if (num_ucipher_suites > MAX_NUM_SUITES) { - WL_ERR(("wrong num_ucipher_suites:%d.\n", num_ucipher_suites)); - return BCME_ERROR; + DHD_ERROR(("too many UCIPHER suites = %d\n", num_ucipher_suites)); + return -1; } /* Increment for number of cipher suites field + space */ pcmd += 3; -- GitLab From b5bb5a2d03c2cf5052c056a3881627cc6c7424c1 Mon Sep 17 00:00:00 2001 From: Joe Maples Date: Mon, 1 May 2017 09:47:29 -0500 Subject: [PATCH 117/528] net: bcmdhd: We get it, negative 30 is invalid Stop log spam when return value is -30 Signed-off-by: Joe Maples Signed-off-by: Andrey Cherepkov (cherry picked from commit 6786660577450e3ec22777a8ee779744e8010f29) --- drivers/net/wireless/bcmdhd/dhd_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index feafd315824d..92c16c32366d 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -1645,7 +1645,7 @@ wl_host_event_get_data(void *pktdata, uint pktlen, void *evt) int ret; ret = is_wlc_event_frame(pktdata, pktlen, 0, evt); - if (ret != BCME_OK) { + if (ret != BCME_OK && ret != -30) { DHD_ERROR(("%s: Invalid event frame, err = %d\n", __FUNCTION__, ret)); } -- GitLab From e93afb3dc8f65d197f56c48671e38f6683540e84 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Fri, 19 May 2017 17:34:10 -0700 Subject: [PATCH 118/528] net: wireless: bcmdhd: fix RTT report of providing wrong information adding exception handling for RX rate/bitrate translation in RTT report. The missing error check resulted in wrong interpretation and it caused legacy HAL layer crash. Bug:37505450 Change-Id: I088e20d882b76afd8c8ba5db0390de4df57fd7ea Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit 7c1bbb5c4ab953f476dcb2ad00af0280758120ea) --- drivers/net/wireless/bcmdhd/dhd_rtt.c | 33 ++++++++++++++++++++++----- drivers/net/wireless/bcmdhd/dhd_rtt.h | 8 +++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_rtt.c b/drivers/net/wireless/bcmdhd/dhd_rtt.c index 2e74c22b8a82..23e712aef69e 100644 --- a/drivers/net/wireless/bcmdhd/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd/dhd_rtt.c @@ -448,7 +448,7 @@ rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) int rate_rspec2rate(uint32 rspec) { - int rate = -1; + int rate = 0; if (RSPEC_ISLEGACY(rspec)) { rate = 500 * (rspec & WL_RSPEC_RATE_MASK); @@ -474,7 +474,7 @@ rate_rspec2rate(uint32 rspec) ASSERT(0); } - return (rate == 0) ? -1 : rate; + return rate; } char resp_buf[WLC_IOCTL_SMLEN]; @@ -1453,17 +1453,38 @@ static wifi_rate_t dhd_rtt_convert_rate_to_host(uint32 rspec) { wifi_rate_t host_rate; - if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { + uint32 bandwidth; + memset(&host_rate, 0, sizeof(wifi_rate_t)); + if (RSPEC_ISLEGACY(rspec)) { host_rate.preamble = 0; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { + } else if (RSPEC_ISHT(rspec)) { host_rate.preamble = 2; host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { + } else if (RSPEC_ISVHT(rspec)) { host_rate.preamble = 3; host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; } - host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1; + + bandwidth = RSPEC_BW(rspec); + switch (bandwidth) { + case WL_RSPEC_BW_20MHZ: + host_rate.bw = RTT_RATE_20M; + break; + case WL_RSPEC_BW_40MHZ: + host_rate.bw = RTT_RATE_40M; + break; + case WL_RSPEC_BW_80MHZ: + host_rate.bw = RTT_RATE_80M; + break; + case WL_RSPEC_BW_160MHZ: + host_rate.bw = RTT_RATE_160M; + break; + default: + host_rate.bw = RTT_RATE_20M; + break; + } + host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); return host_rate; diff --git a/drivers/net/wireless/bcmdhd/dhd_rtt.h b/drivers/net/wireless/bcmdhd/dhd_rtt.h index 308f657391a5..08216dbc8d08 100644 --- a/drivers/net/wireless/bcmdhd/dhd_rtt.h +++ b/drivers/net/wireless/bcmdhd/dhd_rtt.h @@ -128,6 +128,14 @@ enum { RTT_BW_80 = BIT(4), RTT_BW_160 = BIT(5) }; + +enum rtt_rate_bw { + RTT_RATE_20M, + RTT_RATE_40M, + RTT_RATE_80M, + RTT_RATE_160M +}; + #define FTM_MAX_NUM_BURST_EXP 14 #define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) #define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) -- GitLab From 7dc13497b1a49e0ef706ea90761c12db7cf975eb Mon Sep 17 00:00:00 2001 From: Gautam Date: Fri, 28 Jul 2017 01:32:39 +0200 Subject: [PATCH 119/528] net: wireless: bcmdhd: Disable debug trace event WLC_E_TRACE [PORT] WLC_E_TRACE event is not required when device goes to suspend. This event is for debugging purpose and can be enabled back using wlutil command. BUG:24270601 Change-Id: Ic28cf5c0f88c831537c5e6c0b6b727c33de281b1 Signed-off-by: Gautam apply to both bcmdhd for kitakami v1, v2 Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit a7c341e5841d7b62046e4798edadb87e1162a1f5) --- drivers/net/wireless/bcmdhd/dhd_linux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 7e7263967e65..6282ed582980 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -6154,7 +6154,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLAIBSS setbit(eventmask, WLC_E_AIBSS_TXFAIL); #endif /* WLAIBSS */ +#ifdef SHOW_LOGTRACE setbit(eventmask, WLC_E_TRACE); +#else + clrbit(eventmask, WLC_E_TRACE); +#endif /* SHOW_LOGTRACE */ setbit(eventmask, WLC_E_CSA_COMPLETE_IND); /* Write updated Event mask */ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); -- GitLab From aa1e96e4f6e9696a865ae675a2e3ed3845bd5efa Mon Sep 17 00:00:00 2001 From: Insun Song Date: Mon, 3 Aug 2015 16:41:42 -0700 Subject: [PATCH 120/528] net: wireless: bcmdhd_suzuran: fix for watch dog issue in wifi connect test bug => 22666437 fix for watchdog issue in fast switching APs. preventing numerous escan result which trigger watchdog. Change-Id: I835401008a644290df947e4bab1cedbd1599f6e6 Signed-off-by: Insun Song [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit 722fea5afe22ea58038cf93ef1bced176052bed1) --- drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c index d0a3fb448c3e..35f16a6e9a29 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c @@ -10234,16 +10234,7 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); } -#ifdef GSCAN_SUPPORT - else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN)) { - if (status == WLC_E_STATUS_NEWSCAN) { - WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, - escan_result->bss_count)); - } -#else else if (status == WLC_E_STATUS_ABORT) { -#endif /* GSCAN_SUPPORT */ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; wl_escan_print_sync_id(status, escan_result->sync_id, cfg->escan_info.cur_sync_id); -- GitLab From 220f4355623050c6b6985ada93301e96b6ae2482 Mon Sep 17 00:00:00 2001 From: Ashwin Date: Fri, 16 Oct 2015 15:53:47 -0700 Subject: [PATCH 121/528] net: wireless: bcmdhd_suzuran: add a NULL check Check if the gscan result buffer was succesfully allocated Bug: 24469238 Change-Id: I1e896faed42ce53bc36ada449cc4e1c975830159 Signed-off-by: Ashwin [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit e788a585d23521afde8efc94e01edbe401b0fedb) --- drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c index 5f91924c2580..0c74d7021218 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c @@ -2607,6 +2607,12 @@ _dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) } plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + if (!plbestnet) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, + PNO_BESTNET_LEN)); + err = BCME_NOMEM; + goto exit; + } mutex_lock(&_pno_state->pno_mutex); -- GitLab From 3ece01261b59acd88a16e319a72d2b0969b9af2e Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Sat, 5 Mar 2016 19:51:40 -0800 Subject: [PATCH 122/528] net: wireless: bcmdhd_suzuran: Fix CONFIG_HZ dependency in wifi driver Sleep for HZ jiffies, not 100. bug 27419732 Change-Id: I9717f2b539a7fe2e2ba2cd6c3fd231f987ec38a4 [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit ff36d769875a060613c38e5686dfefab95788632) --- drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c index 35f16a6e9a29..1deab30f15ba 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c @@ -9865,7 +9865,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100); + (void)schedule_timeout(HZ); set_current_state(TASK_RUNNING); refcnt++; } -- GitLab From 634ea529cdc4190088e41f244edcbcd65899abe9 Mon Sep 17 00:00:00 2001 From: Mir Ali Date: Mon, 20 Jun 2016 15:23:42 +0530 Subject: [PATCH 123/528] net: wireless: bcmdhd_suzuran: Check to avoid sending Disassoc in unassociated state The change is meant to send a Disassoc request only in the connected state thereby handling the case of a erroneous Diassoc from firmware BUG=28336924 Signed-off-by: Mir Ali [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit 9ff9e434ecd90b65a1d9aa3dc58375c2bfbf5be7) --- drivers/net/wireless/bcmdhd_suzuran/wldev_common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c b/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c index 08a5ecaf6560..f57cce3c7c79 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c @@ -31,6 +31,7 @@ #include #include +#include #define htod32(i) (i) #define htod16(i) (i) @@ -369,6 +370,9 @@ int wldev_set_country( wl_country_t cspec = {{0}, 0, {0}}; scb_val_t scbval; char smbuf[WLC_IOCTL_SMLEN]; + struct wireless_dev *wdev = ndev_to_wdev(dev); + struct wiphy *wiphy = wdev->wiphy; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); if (!country_code) return error; @@ -383,7 +387,7 @@ int wldev_set_country( if ((error < 0) || (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { - if (user_enforced) { + if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) { bzero(&scbval, sizeof(scb_val_t)); error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); if (error < 0) { -- GitLab From 31760f832cec54433072f14f35d2c0b2d3b75aed Mon Sep 17 00:00:00 2001 From: Insun Song Date: Thu, 14 Jul 2016 14:49:48 -0700 Subject: [PATCH 124/528] net: wireless: bcmdhd_suzuran: add boundary check while getting channel spec [PORT][angler] Adding check for chanspec-list count. If count is over than maximum, then cancel current process and immediately return. This will also prevent kernel panic once caused by watchdog timeout. bug=29863589 Change-Id: Ib2de9d71ca39c3fd97a7d684db9925940904e404 Signed-off-by: Insun Song Signed-off-by: zachariasmaladroit [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit c9eda22e0f90ac617961c15a0370f22b095efae5) --- drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c index 1deab30f15ba..78081df71a87 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c @@ -11204,6 +11204,13 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) #undef LOCAL_BUF_LEN list = (wl_uint32_list_t *)(void *)pbuf; + + if ((list) && (dtoh32(list->count) > htod32(WL_NUMCHANSPECS))) { + WL_ERR(("Invalid channel list : %d\n", dtoh32(list->count))); + kfree(pbuf); + return INVCHANSPEC; + } + band = array_size = n_2g = n_5g = 0; for (i = 0; i < dtoh32(list->count); i++) { index = 0; -- GitLab From 2577b392c8d020e7129f8d8f81d486576abd4a80 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Tue, 25 Oct 2016 13:33:18 -0700 Subject: [PATCH 125/528] net: wireless: bcmdhd_suzuran: fix buffer overrun in private command path buffer overrun case found when length parameter manipulated. 1. if input parameter buffer length is less than 4k, then allocate 4k by default. It help to get enough margin for output string overwritten. 2. added additional length check not to override user space allocated buffer size. bug=29000183 Change-Id: I0c15d764c1648920f0214ec47ada689ca44ebfba Signed-off-by: Insun Song [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit 0dc02aaf817f9113e703df0985ae9a91831a11e1) --- .../net/wireless/bcmdhd_suzuran/wl_android.c | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c b/drivers/net/wireless/bcmdhd_suzuran/wl_android.c index 5924e82e83f8..990ee8e0100a 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_android.c @@ -294,19 +294,22 @@ static int wl_android_get_rssi(struct net_device *net, char *command, int total_ return -1; if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); - } else if (total_len <= ssid.SSID_len) { - return -ENOMEM; } else { - memcpy(command, ssid.SSID, ssid.SSID_len); - bytes_written = ssid.SSID_len; + if (total_len > ssid.SSID_len) { + memcpy(command, ssid.SSID, ssid.SSID_len); + bytes_written = ssid.SSID_len; + } else { + return BCME_ERROR; + } } - if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1)) - return -ENOMEM; - - bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written, + if ((total_len - bytes_written) >= (strlen(" rssi -XXX") + 1)) { + bytes_written += snprintf(&command[bytes_written], total_len - bytes_written, " rssi %d", rssi); - command[bytes_written] = '\0'; + command[bytes_written] = '\0'; + } else { + return BCME_ERROR; + } DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); return bytes_written; @@ -2015,13 +2018,18 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) } } if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) { - DHD_ERROR(("%s: invalid length of private command : %d\n", + DHD_ERROR(("%s: invalid length of private command : %d \n", __FUNCTION__, priv_cmd.total_len)); ret = -EINVAL; goto exit; } - buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN); + if (priv_cmd.total_len < PRIVATE_COMMAND_DEF_LEN) { + buf_size = PRIVATE_COMMAND_DEF_LEN; + } else { + buf_size = priv_cmd.total_len; + } + command = kmalloc((buf_size + 1), GFP_KERNEL); if (!command) @@ -2263,19 +2271,22 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) #endif else { DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); - bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); + snprintf(command, 5, "FAIL"); + bytes_written = strlen("FAIL"); } if (bytes_written >= 0) { - if ((bytes_written == 0) && (priv_cmd.total_len > 0)) + if ((bytes_written == 0) && (priv_cmd.total_len > 0)) { command[0] = '\0'; + } if (bytes_written >= priv_cmd.total_len) { - DHD_ERROR(("%s: err. bytes_written:%d >= buf_size:%d \n", - __FUNCTION__, bytes_written, buf_size)); + DHD_ERROR(("%s: not enough for output. bytes_written:%d >= total_len:%d \n", + __FUNCTION__, bytes_written, priv_cmd.total_len)); ret = BCME_BUFTOOSHORT; goto exit; + } else { + bytes_written++; } - bytes_written++; priv_cmd.used_len = bytes_written; if (copy_to_user(priv_cmd.buf, command, bytes_written)) { DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); @@ -2288,7 +2299,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) exit: net_os_wake_unlock(net); - kfree(command); + if (command) { + kfree(command); + } return ret; } -- GitLab From 778dfa2df57cbfe064ae78d9e4d99e142053cbf2 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Tue, 31 Jan 2017 16:18:40 -0800 Subject: [PATCH 126/528] net: wireless: bcmdhd_suzuran: fix buffer overrun in wl_android_set_roampref added boundary check not to override allocated buffer. Specially when user input corrupted or manipulated. Bug: 34469904 Change-Id: Id6196da10111517696eda5f186b1e2dd19f66085 Signed-off-by: Insun Song [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit df518def4ef2249c00565c181a3dc5d19964ed48) --- drivers/net/wireless/bcmdhd_suzuran/wl_android.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c b/drivers/net/wireless/bcmdhd_suzuran/wl_android.c index 990ee8e0100a..25a69bd765b7 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_android.c @@ -1289,6 +1289,10 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); + if (num_ucipher_suites > MAX_NUM_SUITES) { + DHD_ERROR(("too many UCIPHER suites = %d\n", num_ucipher_suites)); + return -1; + } /* Increment for number of cipher suites field + space */ pcmd += 3; total_len_left -= 3; -- GitLab From cc9b942a451fb909c19127f756255febbd48b33d Mon Sep 17 00:00:00 2001 From: Joe Maples Date: Mon, 1 May 2017 09:47:29 -0500 Subject: [PATCH 127/528] net: wireless: bcmdhd_suzuran: We get it, negative 30 is invalid Stop log spam when return value is -30 Signed-off-by: Joe Maples [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit 040f3362036a991e973af025204583535b1ac726) --- drivers/net/wireless/bcmdhd_suzuran/dhd_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c index 5d817e7221f8..d3a490113de2 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c @@ -1217,7 +1217,7 @@ wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu) int ret; ret = is_wlc_event_frame(pktdata, pktlen, 0, evu); - if (ret != BCME_OK) { + if (ret != BCME_OK && ret != -30) { DHD_ERROR(("%s: Invalid event frame, err = %d\n", __FUNCTION__, ret)); } -- GitLab From e1ca67400a45660209e2e458df14ffd2c3da8c3d Mon Sep 17 00:00:00 2001 From: Insun Song Date: Wed, 3 May 2017 16:20:41 -0700 Subject: [PATCH 128/528] net: wireless: bcmdhd_suzuran: adding boundary check in wl_cfg80211_mgmt_tx added boundary check for user-input parameter not to corrupt kernel memmory. Bug: 35195787 Change-Id: Ia497feae5f502c9a650e50a39fd0620fa976d908 Signed-off-by: Insun Song Signed-off-by: Joe Maples Signed-off-by: zachariasmaladroit [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit be793f42264ddc79d4a643e5e4a5ae89e2a031c1) --- drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c index 78081df71a87..dd5fb0275d80 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c @@ -5594,7 +5594,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, WL_DBG(("Enter \n")); - if (len > ACTION_FRAME_SIZE) { + if (len > (ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN)) { WL_ERR(("bad length:%zu\n", len)); return BCME_BADLEN; } -- GitLab From 8565032b93e2f31120157ae236d5c02fa9c9b476 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Fri, 19 May 2017 17:34:10 -0700 Subject: [PATCH 129/528] net: wireless: bcmdhd_suzuran: fix RTT report of providing wrong information adding exception handling for RX rate/bitrate translation in RTT report. The missing error check resulted in wrong interpretation and it caused legacy HAL layer crash. Bug:37505450 Change-Id: I088e20d882b76afd8c8ba5db0390de4df57fd7ea Signed-off-by: Insun Song [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit 537629eb0daa218b0a24828339c6f2bd239b68e4) --- drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c | 33 +++++++++++++++---- drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h | 8 +++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c index d1d29dea61be..b80fffe86ae1 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c @@ -448,7 +448,7 @@ rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) int rate_rspec2rate(uint32 rspec) { - int rate = -1; + int rate = 0; if (RSPEC_ISLEGACY(rspec)) { rate = 500 * (rspec & WL_RSPEC_RATE_MASK); @@ -474,7 +474,7 @@ rate_rspec2rate(uint32 rspec) ASSERT(0); } - return (rate == 0) ? -1 : rate; + return rate; } char resp_buf[WLC_IOCTL_SMLEN]; @@ -1387,17 +1387,38 @@ static wifi_rate_t dhd_rtt_convert_rate_to_host(uint32 rspec) { wifi_rate_t host_rate; - if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { + uint32 bandwidth; + memset(&host_rate, 0, sizeof(wifi_rate_t)); + if (RSPEC_ISLEGACY(rspec)) { host_rate.preamble = 0; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { + } else if (RSPEC_ISHT(rspec)) { host_rate.preamble = 2; host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { + } else if (RSPEC_ISVHT(rspec)) { host_rate.preamble = 3; host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; } - host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1; + + bandwidth = RSPEC_BW(rspec); + switch (bandwidth) { + case WL_RSPEC_BW_20MHZ: + host_rate.bw = RTT_RATE_20M; + break; + case WL_RSPEC_BW_40MHZ: + host_rate.bw = RTT_RATE_40M; + break; + case WL_RSPEC_BW_80MHZ: + host_rate.bw = RTT_RATE_80M; + break; + case WL_RSPEC_BW_160MHZ: + host_rate.bw = RTT_RATE_160M; + break; + default: + host_rate.bw = RTT_RATE_20M; + break; + } + host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); return host_rate; diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h index 308f657391a5..08216dbc8d08 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h @@ -128,6 +128,14 @@ enum { RTT_BW_80 = BIT(4), RTT_BW_160 = BIT(5) }; + +enum rtt_rate_bw { + RTT_RATE_20M, + RTT_RATE_40M, + RTT_RATE_80M, + RTT_RATE_160M +}; + #define FTM_MAX_NUM_BURST_EXP 14 #define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) #define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) -- GitLab From 6f72e636ebe569eacca0b7fd6bc94952c27ed86a Mon Sep 17 00:00:00 2001 From: Gautam Date: Fri, 28 Jul 2017 01:32:39 +0200 Subject: [PATCH 130/528] net: wireless: bcmdhd_suzuran: Disable debug trace event WLC_E_TRACE [PORT] WLC_E_TRACE event is not required when device goes to suspend. This event is for debugging purpose and can be enabled back using wlutil command. BUG:24270601 Change-Id: Ic28cf5c0f88c831537c5e6c0b6b727c33de281b1 Signed-off-by: Gautam apply to both bcmdhd for kitakami v1, v2 Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit 596bb1146b619128309c1a94ed689d8fae193967) --- drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c index b048b8434e38..5f0a4ef5907c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c @@ -4784,7 +4784,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLAIBSS setbit(eventmask, WLC_E_AIBSS_TXFAIL); #endif /* WLAIBSS */ +#ifdef SHOW_LOGTRACE setbit(eventmask, WLC_E_TRACE); +#else + clrbit(eventmask, WLC_E_TRACE); +#endif /* SHOW_LOGTRACE */ #ifdef DHD_LOSSLESS_ROAMING setbit(eventmask, WLC_E_ROAM_PREP); #endif /* DHD_LOSSLESS_ROAMING */ -- GitLab From 50cb53bc62be3541045b3728e2b4827976fe9673 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Mon, 11 Dec 2017 22:32:41 +0300 Subject: [PATCH 131/528] net: wireless: bcmdhd_suzuran: Add ability to pass flags to get_country_code Change-Id: Ifff040c88c2e268cf67293b51c5bcda1c5b15910 Signed-off-by: Dmitry Shmidt Signed-off-by: Andrey Cherepkov (cherry picked from commit 13a23f0aade8080e0d107e86412029ba16475862) --- drivers/net/wireless/bcmdhd_suzuran/dhd.h | 15 ++++++++- .../wireless/bcmdhd_suzuran/dhd_custom_gpio.c | 9 ++++++ .../net/wireless/bcmdhd_suzuran/dhd_linux.c | 24 ++++++++++++++ .../net/wireless/bcmdhd_suzuran/dhd_linux.h | 25 +++++++++++++++ .../bcmdhd_suzuran/dhd_linux_platdev.c | 18 +++++------ .../wireless/bcmdhd_suzuran/wl_cfgvendor.c | 32 +++++++++++++++++++ 6 files changed, 112 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd.h b/drivers/net/wireless/bcmdhd_suzuran/dhd.h index 743fa9c40863..454f6f58c0b2 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd.h @@ -263,6 +263,10 @@ typedef struct dhd_pub { int pktfilter_count; wl_country_t dhd_cspec; /* Current Locale info */ +#ifdef CUSTOM_FORCE_NODFS_FLAG + uint dhd_cflags; +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + bool force_country_change; char eventmask[WL_EVENTING_MASK_LEN]; int op_mode; /* STA, HostAPD, WFD, SoftAP */ @@ -584,6 +588,9 @@ extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); extern int dhd_dev_get_feature_set(struct net_device *dev); extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); +#ifdef CUSTOM_FORCE_NODFS_FLAG +extern int dhd_dev_set_nodfs(struct net_device *dev, uint nodfs); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ extern int dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui); extern int dhd_set_rand_mac_oui(dhd_pub_t *dhd); @@ -641,7 +648,13 @@ extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff); extern int somc_get_mac_address(unsigned char *buf); #endif /* GET_CUSTOM_MAC_ENABLE */ extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf); -extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec); +#ifdef CUSTOM_FORCE_NODFS_FLAG +extern void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec, u32 flags); +#else +extern void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c index 883c1e205db3..7cdfad423c80 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c @@ -546,7 +546,12 @@ const struct cntry_locales_custom translate_custom_table[] = { * input : ISO 3166-1 country abbreviation * output: customized cspec */ +#ifdef CUSTOM_FORCE_NODFS_FLAG +void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec, u32 flags) +#else void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec) +#endif /* CUSTOM_FORCE_NODFS_FLAG */ { #if 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))) @@ -555,7 +560,11 @@ void get_customized_country_code(void *adapter, char *country_iso_code, wl_count if (!cspec) return; +#ifdef CUSTOM_FORCE_NODFS_FLAG + cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code, flags); +#else cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ if (cloc_ptr) { strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); cspec->rev = cloc_ptr->custom_locale_rev; diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c index 5f0a4ef5907c..2e6676346388 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c @@ -3594,6 +3594,10 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #ifdef GET_CUSTOM_MAC_ENABLE wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet); #endif /* GET_CUSTOM_MAC_ENABLE */ +#ifdef CUSTOM_FORCE_NODFS_FLAG + dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; + dhd->pub.force_country_change = TRUE; +#endif #ifdef CUSTOM_COUNTRY_CODE cloc_ptr = wifi_platform_get_country_code(dhd->adapter, dhd->pub.dhd_cspec.ccode); if (cloc_ptr) { @@ -6557,6 +6561,21 @@ dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num) return ret; } +#ifdef CUSTOM_FORCE_NODFS_FLAG +int +dhd_dev_set_nodfs(struct net_device *dev, u32 nodfs) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (nodfs) + dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; + else + dhd->pub.dhd_cflags &= ~WLAN_PLAT_NODFS_FLAG; + dhd->pub.force_country_change = TRUE; + return 0; +} +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + #ifdef PNO_SUPPORT /* Linux wrapper to call common dhd_pno_stop_for_ssid */ int @@ -7274,7 +7293,12 @@ void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_c wl_country_t *cspec) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); +#ifdef CUSTOM_FORCE_NODFS_FLAG + get_customized_country_code(dhd->adapter, country_iso_code, cspec, + dhd->pub.dhd_cflags); +#else get_customized_country_code(dhd->adapter, country_iso_code, cspec); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ } void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) { diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h index af6517b8de7b..5129d8d1225b 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h @@ -37,6 +37,27 @@ #include #include +#if defined(CONFIG_WIFI_CONTROL_FUNC) +#include +#endif +#ifdef CUSTOM_FORCE_NODFS_FLAG +#define WLAN_PLAT_NODFS_FLAG 0x01 +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +#if !defined(CONFIG_WIFI_CONTROL_FUNC) +struct wifi_platform_data { + int (*set_power)(int val); + int (*set_reset)(int val); + int (*set_carddetect)(int val); + void *(*mem_prealloc)(int section, unsigned long size); + int (*get_mac_addr)(unsigned char *buf); +#ifdef CUSTOM_FORCE_NODFS_FLAG + void *(*get_country_code)(char *ccode, u32 flags); +#else + void *(*get_country_code)(char *ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +}; +#endif /* CONFIG_WIFI_CONTROL_FUNC */ + #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ typedef struct wifi_adapter_info { @@ -64,7 +85,11 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present); int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr); int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf); +#ifdef CUSTOM_FORCE_NODFS_FLAG +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags); +#else void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size); void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter); diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c index a25ce6f51beb..447578a0439c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c @@ -47,16 +47,6 @@ #ifdef CONFIG_SOMC_WIFI_CONTROL #include #endif /* CONFIG_SOMC_WIFI_CONTROL */ -#if !defined(CONFIG_WIFI_CONTROL_FUNC) -struct wifi_platform_data { - int (*set_power)(int val); - int (*set_reset)(int val); - int (*set_carddetect)(int val); - void *(*mem_prealloc)(int section, unsigned long size); - int (*get_mac_addr)(unsigned char *buf); - void *(*get_country_code)(char *ccode); -}; -#endif /* CONFIG_WIFI_CONTROL_FUNC */ #define WIFI_PLAT_NAME "bcmdhd_wlan" #define WIFI_PLAT_NAME2 "bcm4329_wlan" @@ -239,7 +229,11 @@ int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf) #endif } +#ifdef CUSTOM_FORCE_NODFS_FLAG +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags) +#else void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) +#endif /* CUSTOM_FORCE_NODFS_FLAG */ { /* get_country_code was added after 2.6.39 */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) @@ -251,7 +245,11 @@ void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) DHD_TRACE(("%s\n", __FUNCTION__)); if (plat_data->get_country_code) { +#ifdef CUSTOM_FORCE_NODFS_FLAG /* CUSTOM_COUNTRY_CODE */ + return plat_data->get_country_code(ccode, flags); +#else return plat_data->get_country_code(ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ } #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c index d1b5543b07e8..eb4c63e15980 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c @@ -213,6 +213,27 @@ wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy, return err; } +#ifdef CUSTOM_FORCE_NODFS_FLAG +static int +wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + u32 nodfs; + + type = nla_type(data); + if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) { + nodfs = nla_get_u32(data); + err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs); + } else { + err = -1; + } + return err; +} +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + #ifdef GSCAN_SUPPORT int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, @@ -2198,6 +2219,17 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = { .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = wl_cfgvendor_set_rand_mac_oui }, +#ifdef CUSTOM_FORCE_NODFS_FLAG + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_NODFS_CHANNELS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_nodfs_flag + + }, +#endif /* CUSTOM_FORCE_NODFS_FLAG */ #ifdef LINKSTAT_SUPPORT { { -- GitLab From 2ad021c35d1f301467b626e08b5afa44e9e0ba29 Mon Sep 17 00:00:00 2001 From: Siddharth Bhal Date: Tue, 7 Apr 2015 16:31:04 +0530 Subject: [PATCH 132/528] wcnss: Ensure wcnss clocks are present before register dump Adding wcnss 'measure' and 'debug' clock checks before dumping wcnss pronto registers. This is required to ensure that registers are dumped only when required clocks are present, otherwise it could lead to undefined behavior. CRs-Fixed: 815208 Change-Id: Iaa920b7f9ad02ef0a4e9e1537f2cd5de8be60b63 Signed-off-by: Siddharth Bhal (cherry picked from commit 2c8471b9148f206a0af06985974fcbf64e3e4b97) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 19 +++++++++++++++++++ include/linux/wcnss_wlan.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 5a714ba55532..2c1b0115bd11 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -1156,6 +1156,25 @@ void wcnss_reset_intr(void) } EXPORT_SYMBOL(wcnss_reset_intr); +void wcnss_reset_fiq(bool clk_chk_en) +{ + if (wcnss_hardware_type() == WCNSS_PRONTO_HW) { + if (clk_chk_en) { + wcnss_log_debug_regs_on_bite(); + } else { + wcnss_pronto_log_debug_regs(); + if (wcnss_get_mux_control()) + wcnss_log_iris_regs(); + } + /* Insert memory barrier before writing fiq register */ + wmb(); + __raw_writel(1 << 16, penv->fiq_reg); + } else { + wcnss_riva_log_debug_regs(); + } +} +EXPORT_SYMBOL(wcnss_reset_fiq); + static int wcnss_create_sysfs(struct device *dev) { int ret; diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index b88fb02066e8..dd2a9b84b2de 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -99,6 +99,7 @@ int wcnss_hardware_type(void); void *wcnss_prealloc_get(unsigned int size); int wcnss_prealloc_put(void *ptr); void wcnss_reset_intr(void); +void wcnss_reset_fiq(bool clk_chk_en); void wcnss_suspend_notify(void); void wcnss_resume_notify(void); void wcnss_riva_log_debug_regs(void); -- GitLab From a36657939c4efc2e508de9638f007714888bbd30 Mon Sep 17 00:00:00 2001 From: Hardik Kantilal Patel Date: Fri, 20 Mar 2015 14:50:44 +0530 Subject: [PATCH 133/528] wcnss: Add condition to check for pronto ver4 hardware Add support to check for pronto ver4 hardware is present by reading a device tree entry. CRs-Fixed: 810392 Change-Id: Ia0ac79047015bf078bc9a52470dd8fd1a2ba33b9 Signed-off-by: Hardik Kantilal Patel [Resolved trivial merge conflicts] Signed-off-by: Andrey Cherepkov (cherry picked from commit 6b7017c62404e65f40ef048f5360f9f7d7dea1fe) --- .../devicetree/bindings/wcnss/wcnss-wlan.txt | 3 +++ drivers/net/wireless/wcnss/wcnss_wlan.c | 13 +++++++++++-- include/linux/wcnss_wlan.h | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index 2ed34baeae35..f2d0445cfd37 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -42,6 +42,9 @@ according to the ponto HW version - qcom,is-pronto-v3: boolean flag to determine the pronto hardware version in use. subsequently correct workqueue will be used by DXE engine to push frames in TX data path and correct voting to RPM will be decided for booting. +- qcom,is-pronto-v4: boolean flag to determine the pronto hardware version +in use. subsequently correct workqueue will be used by DXE engine to push frames +in TX data path. - qcom,wcnss-pm : Power manager related parameter for LDO configuration. diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 2c1b0115bd11..df7cf6362736 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -1552,8 +1552,12 @@ EXPORT_SYMBOL(wcnss_get_wlan_config); int wcnss_is_hw_pronto_ver3(void) { - if (penv && penv->pdev) - return penv->wlan_config.is_pronto_v3; + if (penv && penv->pdev) { + if (penv->wlan_config.is_pronto_v3) + return penv->wlan_config.is_pronto_v3; + else if (penv->wlan_config.is_pronto_v4) + return penv->wlan_config.is_pronto_v4; + } return 0; } EXPORT_SYMBOL(wcnss_is_hw_pronto_ver3); @@ -2642,6 +2646,7 @@ wcnss_trigger_config(struct platform_device *pdev) struct resource *res; int is_pronto_vt; int is_pronto_v3; + int is_pronto_v4; int pil_retry = 0; int has_pronto_hw = of_property_read_bool(pdev->dev.of_node, "qcom,has-pronto-hw"); @@ -2652,6 +2657,9 @@ wcnss_trigger_config(struct platform_device *pdev) is_pronto_v3 = of_property_read_bool(pdev->dev.of_node, "qcom,is-pronto-v3"); + is_pronto_v4 = of_property_read_bool(pdev->dev.of_node, + "qcom,is-pronto-v4"); + if (of_property_read_u32(pdev->dev.of_node, "qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) { penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT; @@ -2676,6 +2684,7 @@ wcnss_trigger_config(struct platform_device *pdev) penv->wlan_config.use_48mhz_xo = has_48mhz_xo; penv->wlan_config.is_pronto_vt = is_pronto_vt; penv->wlan_config.is_pronto_v3 = is_pronto_v3; + penv->wlan_config.is_pronto_v4 = is_pronto_v4; if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) { has_autodetect_xo = of_property_read_bool(pdev->dev.of_node, diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index dd2a9b84b2de..3c0642620c9a 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -30,6 +30,7 @@ struct wcnss_wlan_config { int use_48mhz_xo; int is_pronto_vt; int is_pronto_v3; + int is_pronto_v4; void __iomem *msm_wcnss_base; }; -- GitLab From b94d7878dd67dcaef0310b596100105b3bad6308 Mon Sep 17 00:00:00 2001 From: Anand N Sunkad Date: Mon, 9 Mar 2015 16:27:13 +0530 Subject: [PATCH 134/528] wcnss: Add wrapper functions for work queue functionalities WLAN prop driver cannot access following functions directly. To mitigate issue add wrapper functions in platform driver for cancel_work_sync and cancel_delayed_work_sync kernel APIs. CRs-Fixed: 804860 Change-Id: I990b3abd1fd678802e0728c882c18f83582a4075 Signed-off-by: Anand N Sunkad (cherry picked from commit 76f4ee22eef78665a19cbe8b839246ec4d772fc4) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 24 ++++++++++++++++++++++++ include/linux/wcnss_wlan.h | 3 +++ 2 files changed, 27 insertions(+) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index df7cf6362736..687ac9141d01 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -3021,6 +3021,30 @@ fail_gpio_res: return ret; } +/* wlan prop driver cannot invoke cancel_work_sync + * function directly, so to invoke this function it + * call wcnss_flush_work function + */ +void wcnss_flush_work(struct work_struct *work) +{ + struct work_struct *cnss_work = work; + if (cnss_work != NULL) + cancel_work_sync(cnss_work); +} +EXPORT_SYMBOL(wcnss_flush_work); + +/* wlan prop driver cannot invoke cancel_delayed_work_sync + * function directly, so to invoke this function it call + * wcnss_flush_delayed_work function + */ +void wcnss_flush_delayed_work(struct delayed_work *dwork) +{ + struct delayed_work *cnss_dwork = dwork; + if (cnss_dwork != NULL) + cancel_delayed_work_sync(cnss_dwork); +} +EXPORT_SYMBOL(wcnss_flush_delayed_work); + static int wcnss_node_open(struct inode *inode, struct file *file) { struct platform_device *pdev; diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 3c0642620c9a..1fc3626a56dd 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -112,6 +112,9 @@ void wcnss_riva_dump_pmic_regs(void); int wcnss_xo_auto_detect_enabled(void); u32 wcnss_get_wlan_rx_buff_count(void); int wcnss_wlan_iris_xo_mode(void); +void wcnss_flush_work(struct work_struct *work); +void wcnss_flush_delayed_work(struct delayed_work *dwork); + #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE void wcnss_log_debug_regs_on_bite(void); #else -- GitLab From 4b45ae987566c969427dcac2db75bf22127dd157 Mon Sep 17 00:00:00 2001 From: Siddharth Bhal Date: Fri, 10 Oct 2014 21:53:47 +0530 Subject: [PATCH 135/528] wcnss: handle CBC complete event from firmware Add case to handle cold boot calibration complete event from firmware. Change-Id: I3d3dce178fadd7f993ee31667c89bcebb02c388c CRs-Fixed: 796303 Signed-off-by: Siddharth Bhal (cherry picked from commit fcabfd55ae1a42260d3b673ca08b076b7ea6825f) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 19 +++++++++++++++++++ include/linux/wcnss_wlan.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 687ac9141d01..03f40d9adfa8 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -56,6 +56,7 @@ #define WCNSS_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE #define WCNSS_PM_QOS_TIMEOUT 15000 #define IS_CAL_DATA_PRESENT 0 +#define WAIT_FOR_CBC_IND 2 /* module params */ #define WCNSS_CONFIG_UNSPECIFIED (-1) @@ -214,6 +215,7 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_BUILD_VER_REQ (WCNSS_CTRL_MSG_START + 9) #define WCNSS_BUILD_VER_RSP (WCNSS_CTRL_MSG_START + 10) #define WCNSS_PM_CONFIG_REQ (WCNSS_CTRL_MSG_START + 11) +#define WCNSS_CBC_COMPLETE_IND (WCNSS_CTRL_MSG_START + 12) /* max 20mhz channel count */ #define WCNSS_MAX_CH_NUM 45 @@ -399,6 +401,7 @@ static struct { void __iomem *alarms_tactl; void __iomem *fiq_reg; int nv_downloaded; + int is_cbc_done; unsigned char *fw_cal_data; unsigned char *user_cal_data; int fw_cal_rcvd; @@ -1295,6 +1298,7 @@ static void wcnss_smd_notify_event(void *data, unsigned int event) pr_debug("wcnss: closing WCNSS SMD channel :%s", WCNSS_CTRL_CHANNEL); penv->nv_downloaded = 0; + penv->is_cbc_done = 0; break; default: @@ -1571,6 +1575,15 @@ int wcnss_device_ready(void) } EXPORT_SYMBOL(wcnss_device_ready); +bool wcnss_cbc_complete(void) +{ + if (penv && penv->pdev && penv->is_cbc_done && + !wcnss_device_is_shutdown()) + return true; + return false; +} +EXPORT_SYMBOL(wcnss_cbc_complete); + int wcnss_device_is_shutdown(void) { if (penv && penv->is_shutdown) @@ -2206,6 +2219,8 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) fw_status = wcnss_fw_status(); pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n", fw_status); + if (fw_status != WAIT_FOR_CBC_IND) + penv->is_cbc_done = 1; wcnss_setup_vbat_monitoring(); break; @@ -2215,6 +2230,10 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n", fw_status); break; + case WCNSS_CBC_COMPLETE_IND: + penv->is_cbc_done = 1; + pr_debug("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n"); + break; case WCNSS_CALDATA_UPLD_REQ: extract_cal_data(len); diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 1fc3626a56dd..ae0ecd60151d 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -53,6 +53,7 @@ enum { #define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1 #define HAVE_WCNSS_RESET_INTR 1 #define HAVE_WCNSS_CAL_DOWNLOAD 1 +#define HAVE_CBC_DONE 1 #define HAVE_WCNSS_RX_BUFF_COUNT 1 #define WLAN_MAC_ADDR_SIZE (6) #define WLAN_RF_REG_ADDR_START_OFFSET 0x3 @@ -107,6 +108,7 @@ void wcnss_riva_log_debug_regs(void); void wcnss_pronto_log_debug_regs(void); int wcnss_is_hw_pronto_ver3(void); int wcnss_device_ready(void); +bool wcnss_cbc_complete(void); int wcnss_device_is_shutdown(void); void wcnss_riva_dump_pmic_regs(void); int wcnss_xo_auto_detect_enabled(void); -- GitLab From 879d911074dabac045eecfb5db44f40463a83b64 Mon Sep 17 00:00:00 2001 From: Hardik Kantilal Patel Date: Thu, 7 May 2015 05:40:10 -0700 Subject: [PATCH 136/528] wcnss: Avoid crash during shutdown in SSR Wlan driver should not read registers from wcnss or try to communicate with the chip when it is undergoing a subsystem-restart. this flag will be used by the wlan driver to protect register access and other prohibited operations. CRs-Fixed: 834133 Change-Id: I638ee9e6cbc25da77ca931191718cec3a7aa87d6 Signed-off-by: Hardik Kantilal Patel (cherry picked from commit 6098936d9a0f7c0d3d868b3a8aa926371060c5ef) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 03f40d9adfa8..b62084cd8797 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -3219,6 +3219,7 @@ static int wcnss_notif_cb(struct notifier_block *this, unsigned long code, wcnss_disable_pc_add_req(); schedule_delayed_work(&penv->wcnss_pm_qos_del_req, msecs_to_jiffies(WCNSS_PM_QOS_TIMEOUT)); + penv->is_shutdown = 1; wcnss_log_debug_regs_on_bite(); } else if (code == SUBSYS_POWERUP_FAILURE) { if (pdev && pwlanconfig) -- GitLab From c5aadf7cdd04bec1b9761db4ba0fd0368a2549d4 Mon Sep 17 00:00:00 2001 From: Hardik Kantilal Patel Date: Wed, 22 Apr 2015 13:21:17 -0700 Subject: [PATCH 137/528] wcnss: Add iris chip id for MSM8909 target Add iris chip id to support new IRIS card for MSM8909 target. CRs-Fixed: 827135 Change-Id: I465a8deb826b41462f0ff136bdf209313846b5f3 Signed-off-by: Hardik Kantilal Patel (cherry picked from commit 0c2b2ab199d2b9df2821ca8858a73fdea3567994) --- drivers/net/wireless/wcnss/wcnss_vreg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c index d46c54143b89..e5a09cc20411 100644 --- a/drivers/net/wireless/wcnss/wcnss_vreg.c +++ b/drivers/net/wireless/wcnss/wcnss_vreg.c @@ -48,6 +48,7 @@ static int is_power_on; #define WCN3620 0x5111 #define WCN3620A 0x5112 #define WCN3610 0x9101 +#define WCN3610V1 0x9110 #define WCNSS_PMU_CFG_IRIS_XO_CFG BIT(3) #define WCNSS_PMU_CFG_IRIS_XO_EN BIT(4) @@ -197,6 +198,7 @@ int validate_iris_chip_id(u32 reg) case WCN3620: case WCN3620A: case WCN3610: + case WCN3610V1: return 0; default: return 1; -- GitLab From a0a697d326e0ca02b5f3fe55622462cdff0c2fc9 Mon Sep 17 00:00:00 2001 From: Anand N Sunkad Date: Thu, 30 Apr 2015 21:27:06 +0530 Subject: [PATCH 138/528] wcnss: Add API to send IRIS name As per requirment, user need to check WLAN RF card preset on device at run time. WLAN host driver use this API to get the IRIS card name. CRs-Fixed: 831585 Change-Id: I8bd71cab7f998cde01bd43068b8dfbfc5817fb7f Signed-off-by: Anand N Sunkad Signed-off-by: Andrey Cherepkov (cherry picked from commit eb76e0fd6aba538a887e307650f21fb3ed21a8d3) --- drivers/net/wireless/wcnss/wcnss_vreg.c | 46 +++++++++++++++++++++++++ include/linux/wcnss_wlan.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c index e5a09cc20411..588676efb9c3 100644 --- a/drivers/net/wireless/wcnss/wcnss_vreg.c +++ b/drivers/net/wireless/wcnss/wcnss_vreg.c @@ -186,6 +186,50 @@ int xo_auto_detect(u32 reg) } } +int wcnss_get_iris_name(char *iris_name) +{ + struct wcnss_wlan_config *cfg = NULL; + int iris_id; + + cfg = wcnss_get_wlan_config(); + + if (cfg) { + iris_id = cfg->iris_id; + iris_id = iris_id >> 16; + } else { + return 1; + } + + switch (iris_id) { + case WCN3660: + memcpy(iris_name, "WCN3660", sizeof("WCN3660")); + break; + case WCN3660A: + memcpy(iris_name, "WCN3660A", sizeof("WCN3660A")); + break; + case WCN3660B: + memcpy(iris_name, "WCN3660B", sizeof("WCN3660B")); + break; + case WCN3620: + memcpy(iris_name, "WCN3620", sizeof("WCN3620")); + break; + case WCN3620A: + memcpy(iris_name, "WCN3620A", sizeof("WCN3620A")); + break; + case WCN3610: + memcpy(iris_name, "WCN3610", sizeof("WCN3610")); + break; + case WCN3610V1: + memcpy(iris_name, "WCN3610V1", sizeof("WCN3610V1")); + break; + default: + return 1; + } + + return 0; +} +EXPORT_SYMBOL(wcnss_get_iris_name); + int validate_iris_chip_id(u32 reg) { int iris_id; @@ -346,6 +390,8 @@ configure_iris_xo(struct device *dev, else auto_detect = WCNSS_XO_INVALID; + cfg->iris_id = iris_reg; + /* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */ reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE); diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index ae0ecd60151d..ceee6be1ce7e 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -32,6 +32,7 @@ struct wcnss_wlan_config { int is_pronto_v3; int is_pronto_v4; void __iomem *msm_wcnss_base; + int iris_id; }; enum { @@ -116,6 +117,7 @@ u32 wcnss_get_wlan_rx_buff_count(void); int wcnss_wlan_iris_xo_mode(void); void wcnss_flush_work(struct work_struct *work); void wcnss_flush_delayed_work(struct delayed_work *dwork); +int wcnss_get_iris_name(char *iris_version); #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE void wcnss_log_debug_regs_on_bite(void); -- GitLab From 382562d58c711209a8775e48685b7f494926fa96 Mon Sep 17 00:00:00 2001 From: Siddharth Bhal Date: Thu, 21 May 2015 14:38:55 +0530 Subject: [PATCH 139/528] wcnss: updating driver to use wcnss_reset_fiq api Updating wcnss platform driver to use safer api wcnss_reset_fiq instead of older api wcnss_reset_intr and removing the deprecated api. Change-Id: Ica6d91e6b62e03d83afddd521e78bf90e000ced7 CRs-Fixed: 841553 Signed-off-by: Siddharth Bhal (cherry picked from commit 77eb3293fec21cb7944d7c7f4c148e2a2044a4c1) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 18 ++---------------- include/linux/wcnss_wlan.h | 1 - 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index b62084cd8797..699cc5a1f18e 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -569,7 +569,7 @@ void wcnss_riva_dump_pmic_regs(void) } } -/* wcnss_reset_intr() is invoked when host drivers fails to +/* wcnss_reset_fiq() is invoked when host drivers fails to * communicate with WCNSS over SMD; so logging these registers * helps to know WCNSS failure reason */ @@ -1145,20 +1145,6 @@ void wcnss_log_debug_regs_on_bite(void) #endif /* interface to reset wcnss by sending the reset interrupt */ -void wcnss_reset_intr(void) -{ - if (wcnss_hardware_type() == WCNSS_PRONTO_HW) { - wcnss_pronto_log_debug_regs(); - if (wcnss_get_mux_control()) - wcnss_log_iris_regs(); - wmb(); - __raw_writel(1 << 16, penv->fiq_reg); - } else { - wcnss_riva_log_debug_regs(); - } -} -EXPORT_SYMBOL(wcnss_reset_intr); - void wcnss_reset_fiq(bool clk_chk_en) { if (wcnss_hardware_type() == WCNSS_PRONTO_HW) { @@ -3010,7 +2996,7 @@ wcnss_trigger_config(struct platform_device *pdev) } while (pil_retry++ < WCNSS_MAX_PIL_RETRY && IS_ERR(penv->pil)); if (IS_ERR(penv->pil)) { - wcnss_reset_intr(); + wcnss_reset_fiq(false); if (penv->wcnss_notif_hdle) subsys_notif_unregister_notifier(penv->wcnss_notif_hdle, &wnb); diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index ceee6be1ce7e..89a78b498838 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -101,7 +101,6 @@ void wcnss_prevent_suspend(void); int wcnss_hardware_type(void); void *wcnss_prealloc_get(unsigned int size); int wcnss_prealloc_put(void *ptr); -void wcnss_reset_intr(void); void wcnss_reset_fiq(bool clk_chk_en); void wcnss_suspend_notify(void); void wcnss_resume_notify(void); -- GitLab From 34d72bd2b172c64b406f114dc81acfd8d50ea4c0 Mon Sep 17 00:00:00 2001 From: Anand N Sunkad Date: Tue, 2 Jun 2015 15:29:39 +0530 Subject: [PATCH 140/528] wcnss: Add wrapper functions for init work functionalities WLAN prop driver cannot access INIT_WORK and INIT_DELAYED_WORK API's. To mitigate issue add wrapper functions in platform driver for INIT_WORK and INIT_DELAYED_WORK kernel APIs. CRs-Fixed: 847627 Change-Id: Ife3c4d2abe0109fdfa0c908a3ca619cbf8b666ee Signed-off-by: Anand N Sunkad (cherry picked from commit 10bfabf11746a5490b382face44523806f4ccf38) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 22 ++++++++++++++++++++++ include/linux/wcnss_wlan.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 699cc5a1f18e..f4aca900fd8f 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -3050,6 +3050,28 @@ void wcnss_flush_delayed_work(struct delayed_work *dwork) } EXPORT_SYMBOL(wcnss_flush_delayed_work); +/* wlan prop driver cannot invoke INIT_WORK function + * directly, so to invoke this function call + * wcnss_init_work function. + */ +void wcnss_init_work(struct work_struct *work , void *callbackptr) +{ + if (work && callbackptr) + INIT_WORK(work, callbackptr); +} +EXPORT_SYMBOL(wcnss_init_work); + +/* wlan prop driver cannot invoke INIT_DELAYED_WORK + * function directly, so to invoke this function + * call wcnss_init_delayed_work function. + */ +void wcnss_init_delayed_work(struct delayed_work *dwork , void *callbackptr) +{ + if (dwork && callbackptr) + INIT_DELAYED_WORK(dwork, callbackptr); +} +EXPORT_SYMBOL(wcnss_init_delayed_work); + static int wcnss_node_open(struct inode *inode, struct file *file) { struct platform_device *pdev; diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 89a78b498838..2a63e5fac712 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -116,6 +116,8 @@ u32 wcnss_get_wlan_rx_buff_count(void); int wcnss_wlan_iris_xo_mode(void); void wcnss_flush_work(struct work_struct *work); void wcnss_flush_delayed_work(struct delayed_work *dwork); +void wcnss_init_work(struct work_struct *work , void *callbackptr); +void wcnss_init_delayed_work(struct delayed_work *dwork , void *callbackptr); int wcnss_get_iris_name(char *iris_version); #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE -- GitLab From 2edec4f34477caeb701de927b77a21f702f7e4fc Mon Sep 17 00:00:00 2001 From: Shimrit Malichi Date: Mon, 8 Jun 2015 16:27:26 +0300 Subject: [PATCH 141/528] wcnss: Add support to WLAN indication LED Turn on/off WLAN indication LED when WLAN service is on/off respectively. Change-Id: I5d11720a892b8914c758eec9c798e2bd93c233ef Signed-off-by: Shimrit Malichi Signed-off-by: Andrey Cherepkov (cherry picked from commit 97a1c9e1305d2909f7528473291473a5fc75af43) --- .../devicetree/bindings/wcnss/wcnss-wlan.txt | 3 ++- drivers/net/wireless/wcnss/wcnss_vreg.c | 14 ++++++++++++++ drivers/net/wireless/wcnss/wcnss_wlan.c | 4 ++++ include/linux/wcnss_wlan.h | 1 + 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index f2d0445cfd37..5a49e6c9cff2 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -54,7 +54,8 @@ in TX data path. 1 - WCN RPM power collapse enabled 1 - WCN standalone power collapse enabled 6 - GPIO strength value - +- qcom,wlan-indication-enabled: boolean flag to determine if WLAN indication-LED +will be turned on/off when WLAN is enabled/disabled respectively. Example: diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c index 588676efb9c3..a581cb07a920 100644 --- a/drivers/net/wireless/wcnss/wcnss_vreg.c +++ b/drivers/net/wireless/wcnss/wcnss_vreg.c @@ -24,6 +24,7 @@ #include #include #include +#include static void __iomem *msm_wcnss_base; @@ -32,6 +33,7 @@ static DEFINE_MUTEX(list_lock); static DEFINE_SEMAPHORE(wcnss_power_on_lock); static int auto_detect; static int is_power_on; +DEFINE_LED_TRIGGER(wlan_indication_led); #define RIVA_PMU_OFFSET 0x28 @@ -750,6 +752,9 @@ int wcnss_req_power_on_lock(char *driver_name) list_add(&node->list, &power_on_lock_list); mutex_unlock(&list_lock); + if (wlan_indication_led) + led_trigger_event(wlan_indication_led, LED_FULL); + return 0; err: @@ -776,6 +781,15 @@ int wcnss_free_power_on_lock(char *driver_name) up(&wcnss_power_on_lock); mutex_unlock(&list_lock); + if (wlan_indication_led) + led_trigger_event(wlan_indication_led, LED_OFF); + return ret; } EXPORT_SYMBOL(wcnss_free_power_on_lock); + +void wcnss_en_wlan_led_trigger(void) +{ + led_trigger_register_simple("wlan-indication-led", + &wlan_indication_led); +} diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index f4aca900fd8f..c8281f76afbf 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -3006,6 +3006,10 @@ wcnss_trigger_config(struct platform_device *pdev) /* Remove pm_qos request */ wcnss_disable_pc_remove_req(); + if (of_property_read_bool(pdev->dev.of_node, + "qcom,wlan-indication-enabled")) + wcnss_en_wlan_led_trigger(); + return 0; fail_ioremap2: diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 2a63e5fac712..463302d18ff2 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -119,6 +119,7 @@ void wcnss_flush_delayed_work(struct delayed_work *dwork); void wcnss_init_work(struct work_struct *work , void *callbackptr); void wcnss_init_delayed_work(struct delayed_work *dwork , void *callbackptr); int wcnss_get_iris_name(char *iris_version); +void wcnss_en_wlan_led_trigger(void); #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE void wcnss_log_debug_regs_on_bite(void); -- GitLab From c88055c0fc8b14a7341c06acbbdb9154fe1b0a19 Mon Sep 17 00:00:00 2001 From: Anand N Sunkad Date: Tue, 11 Aug 2015 18:41:25 +0530 Subject: [PATCH 142/528] wcnss: Avoid sending FIQ to pronto subsystem Avoid sending FIQ to pronto subsystem during power up sequence. CRs-Fixed: 888411 Change-Id: Ia9c14d32bfcba93bb704d07f284cb3c618de8fbf Signed-off-by: Anand N Sunkad (cherry picked from commit e529ceaa8c196ed4fe2c88aa22273a8d5f961220) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index c8281f76afbf..510c37a11b5d 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -1155,9 +1155,14 @@ void wcnss_reset_fiq(bool clk_chk_en) if (wcnss_get_mux_control()) wcnss_log_iris_regs(); } - /* Insert memory barrier before writing fiq register */ - wmb(); - __raw_writel(1 << 16, penv->fiq_reg); + if (!wcnss_device_is_shutdown()) { + /* Insert memory barrier before writing fiq register */ + wmb(); + __raw_writel(1 << 16, penv->fiq_reg); + } else { + pr_info("%s: Block FIQ during power up sequence\n", + __func__); + } } else { wcnss_riva_log_debug_regs(); } -- GitLab From a66554991b2df2be83fecd589e0ad0fe81bca057 Mon Sep 17 00:00:00 2001 From: Anand N Sunkad Date: Mon, 17 Aug 2015 12:55:23 +0530 Subject: [PATCH 143/528] wcnss: Add NULL check before accessing pronto register Avoid accessing of pronto register base address if wcnss platform driver is not triggered by wlan. CRs-Fixed: 891378 Change-Id: Idcad44bffcb4315c5d97db510f58592b4913e6ab Signed-off-by: Anand N Sunkad Signed-off-by: Andrey Cherepkov (cherry picked from commit 9bc8d3c690b520309cbeceafbd154c69a5ffb829) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 510c37a11b5d..cc6b69948948 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -629,6 +629,10 @@ void wcnss_pronto_log_debug_regs(void) u32 reg = 0, reg2 = 0, reg3 = 0, reg4 = 0, offset_addr = 0; int i; + if (!penv || !penv->triggered || !penv->msm_wcnss_base) { + pr_info(DEVICE " WCNSS driver is not triggered by userspace\n"); + return; + } reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET; reg = readl_relaxed(reg_addr); @@ -1092,7 +1096,7 @@ int wcnss_get_mux_control(void) void __iomem *pmu_conf_reg; u32 reg = 0; - if (NULL == penv) + if (!penv || !penv->triggered || !penv->msm_wcnss_base) return 0; pmu_conf_reg = penv->msm_wcnss_base + PRONTO_PMU_OFFSET; @@ -1128,7 +1132,7 @@ void wcnss_log_debug_regs_on_bite(void) } clk_rate = clk_get_rate(measure); - pr_debug("wcnss: clock frequency is: %luHz\n", clk_rate); + pr_info("wcnss: clock frequency is: %luHz\n", clk_rate); if (clk_rate) { wcnss_pronto_log_debug_regs(); -- GitLab From c52b3b12f6bf8e731afc0fece2e5caef5ced96f5 Mon Sep 17 00:00:00 2001 From: "Padma, Santhosh Kumar" Date: Wed, 25 Nov 2015 12:30:19 +0530 Subject: [PATCH 144/528] wcnss: Expose dump stack functionality Add changes to expose dump stack functionality which can be used by driver to dump stack information when it requires. CRs-Fixed: 943322 Change-Id: I0fde7142dea2c18daf6b1fb0c5ee4bb8a31a6be0 Signed-off-by: Padma, Santhosh Kumar Signed-off-by: Andrey Cherepkov (cherry picked from commit 1d71851353dac5646dde9db7c1ef6b3cc05f1f57) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 10 ++++++++++ include/linux/wcnss_wlan.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index cc6b69948948..8f3fb9897551 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -3051,6 +3051,16 @@ void wcnss_flush_work(struct work_struct *work) } EXPORT_SYMBOL(wcnss_flush_work); +/* wlan prop driver cannot invoke show_stack + * function directly, so to invoke this function it + * call wcnss_dump_stack function + */ +void wcnss_dump_stack(struct task_struct *task) +{ + show_stack(task, NULL); +} +EXPORT_SYMBOL(wcnss_dump_stack); + /* wlan prop driver cannot invoke cancel_delayed_work_sync * function directly, so to invoke this function it call * wcnss_flush_delayed_work function diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 463302d18ff2..9bcb9a414ce7 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -15,6 +15,7 @@ #define _WCNSS_WLAN_H_ #include +#include enum wcnss_opcode { WCNSS_WLAN_SWITCH_OFF = 0, @@ -120,6 +121,7 @@ void wcnss_init_work(struct work_struct *work , void *callbackptr); void wcnss_init_delayed_work(struct delayed_work *dwork , void *callbackptr); int wcnss_get_iris_name(char *iris_version); void wcnss_en_wlan_led_trigger(void); +void wcnss_dump_stack(struct task_struct *task); #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE void wcnss_log_debug_regs_on_bite(void); -- GitLab From 4fe631afa5610c92be15d339a0bcea05a6fda72c Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Tue, 2 Feb 2016 18:14:19 -0800 Subject: [PATCH 145/528] cnss: Update prealloc memory table The memory size of a slot in the prealloc table should be order of 2, otherwise some memory will be wasted since kernel only allocates contiguous physical memory in pages by order of 2. Change-Id: I762ad490d300f8b622a3ed1f9ccbe2af2d926c49 Signed-off-by: Yue Ma (cherry picked from commit 36676a62e0eea3e08233e0dc19ab7a175d7c3be4) --- .../wireless/cnss_prealloc/cnss_prealloc.c | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c index d5e419faa1f1..590c1cda96bc 100644 --- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c +++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c @@ -42,50 +42,50 @@ static struct wcnss_prealloc wcnss_allocs[] = { {0, 8 * 1024, NULL}, {0, 8 * 1024, NULL}, {0, 8 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 24 * 1024, NULL}, - {0, 24 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 32 * 1024, NULL}, + {0, 32 * 1024, NULL}, {0, 32 * 1024, NULL}, {0, 32 * 1024, NULL}, {0, 32 * 1024, NULL}, @@ -98,7 +98,7 @@ static struct wcnss_prealloc wcnss_allocs[] = { {0, 64 * 1024, NULL}, {0, 64 * 1024, NULL}, {0, 64 * 1024, NULL}, - {0, 76 * 1024, NULL}, + {0, 128 * 1024, NULL}, }; int wcnss_prealloc_init(void) -- GitLab From c09df3540a54622fce188954f514c90832df5492 Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Wed, 17 Feb 2016 19:06:23 +0530 Subject: [PATCH 146/528] net: cnss_prealloc: Add memory for high latency SDIO interface wlan driver transport layer pdev handler needs 128kb pre allocated memory in a single block memory allocation for transmit/receive descriptor initialization in wlan startup for the wlan module with high latency(SDIO) based hardware interface. CRs-Fixed: 978073 Change-Id: I0dbe047a7b64e96bf32470702d1b3e3088bffcf7 Signed-off-by: Sarada Prasanna Garnayak (cherry picked from commit 8179f93187bae960412136ab22bdaf38e97a604d) --- drivers/net/wireless/cnss_prealloc/cnss_prealloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c index 590c1cda96bc..f666bf841e3f 100644 --- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c +++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012,2014-2016 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -99,6 +99,7 @@ static struct wcnss_prealloc wcnss_allocs[] = { {0, 64 * 1024, NULL}, {0, 64 * 1024, NULL}, {0, 128 * 1024, NULL}, + {0, 128 * 1024, NULL}, }; int wcnss_prealloc_init(void) -- GitLab From 29f354b1eb609788bf14c12fe2128c093e5f5e49 Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Mon, 17 Apr 2017 19:40:24 +0530 Subject: [PATCH 147/528] wcnss: fix the buffer overflow in MAC address store sysfs Invalid typecast in MAC address store sysfs entry method causing device crash due to the buffer overflow. To fix the above issue check the length of the userspace MAC address before write. Update the datatype and parsing method to store the userspace MAC address. CRs-Fixed: 2034549 Change-Id: I0d4709c5b623c8333a99991c042552df1e7da923 Signed-off-by: Sarada Prasanna Garnayak (cherry picked from commit af5fa7438f244b43380f97a5aebfc328953accd9) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 8f3fb9897551..a984d76846a2 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -200,6 +200,8 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_USR_WLAN_MAC_ADDR (WCNSS_USR_CTRL_MSG_START + 3) #define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define SHOW_MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x\n" +#define WCNSS_USER_MAC_ADDR_LENGTH 18 /* message types */ #define WCNSS_CTRL_MSG_START 0x01000000 @@ -440,23 +442,28 @@ static struct { static ssize_t wcnss_wlan_macaddr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - char macAddr[WLAN_MAC_ADDR_SIZE]; + int index; + int macAddr[WLAN_MAC_ADDR_SIZE]; if (!penv) return -ENODEV; - pr_debug("%s: Receive MAC Addr From user space: %s\n", __func__, buf); + if (WCNSS_USER_MAC_ADDR_LENGTH != strlen(buf)) { + dev_err(dev, "%s: Invalid MAC addr length\n", __func__); + return -EINVAL; + } if (WLAN_MAC_ADDR_SIZE != sscanf(buf, MAC_ADDRESS_STR, - (int *)&macAddr[0], (int *)&macAddr[1], - (int *)&macAddr[2], (int *)&macAddr[3], - (int *)&macAddr[4], (int *)&macAddr[5])) { - + &macAddr[0], &macAddr[1], &macAddr[2], + &macAddr[3], &macAddr[4], &macAddr[5])) { pr_err("%s: Failed to Copy MAC\n", __func__); return -EINVAL; } - memcpy(penv->wlan_nv_macAddr, macAddr, sizeof(penv->wlan_nv_macAddr)); + for (index = 0; index < WLAN_MAC_ADDR_SIZE; index++) { + memcpy(&penv->wlan_nv_macAddr[index], + (char *)&macAddr[index], sizeof(char)); + } pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__, penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], @@ -472,7 +479,7 @@ static ssize_t wcnss_wlan_macaddr_show(struct device *dev, if (!penv) return -ENODEV; - return scnprintf(buf, PAGE_SIZE, MAC_ADDRESS_STR, + return scnprintf(buf, PAGE_SIZE, SHOW_MAC_ADDRESS_STR, penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); -- GitLab From f1e2f0d867ebdb2056ec82e57048dcbdd55a5dae Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Sat, 3 Mar 2018 08:58:08 +0300 Subject: [PATCH 148/528] net: wireless: bcmdhd_suzuran: Update to 1.141.67.32 * Sony package version: 34.4.A.2.19 (Xperia X) Signed-off-by: Andrey Cherepkov (cherry picked from commit f9e3a06214298dd8d174e8263f291648842fc42e) --- .../net/wireless/bcmdhd_suzuran/dhd_common.c | 40 ++++---- .../wireless/bcmdhd_suzuran/include/epivers.h | 8 +- .../net/wireless/bcmdhd_suzuran/wl_android.c | 4 +- .../wireless/bcmdhd_suzuran/wl_cfgvendor.c | 93 +++++++++++++------ 4 files changed, 91 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c index d3a490113de2..2e48feddbb35 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c 701450 2017-05-25 02:10:23Z $ + * $Id: dhd_common.c 732203 2017-11-16 05:18:28Z $ */ #include #include @@ -2106,13 +2106,18 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte { char* str; int idx = 0; + uint8 len; if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; + return BCME_BADARG; } str = *list_str; while (*bytes_left > 0) { + if (idx >= max) { + DHD_ERROR(("%s number of SSIDs more than %d\n", __FUNCTION__, idx)); + return BCME_BADARG; + } if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { *list_str = str; @@ -2122,9 +2127,14 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte /* Get proper CSCAN_TLV_TYPE_SSID_IE */ *bytes_left -= 1; + if (*bytes_left == 0) { + DHD_ERROR(("%s no length field.\n", __FUNCTION__)); + return BCME_BADARG; + } str += 1; ssid[idx].rssi_thresh = 0; - if (str[0] == 0) { + len = str[0]; + if (len == 0) { /* Broadcast SSID */ ssid[idx].SSID_len = 0; memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); @@ -2132,20 +2142,17 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte str += 1; DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); - } - else if (str[0] <= DOT11_MAX_SSID_LEN) { + } else if (len <= DOT11_MAX_SSID_LEN) { /* Get proper SSID size */ - ssid[idx].SSID_len = str[0]; + ssid[idx].SSID_len = len; *bytes_left -= 1; - str += 1; - /* Get SSID */ if (ssid[idx].SSID_len > *bytes_left) { DHD_ERROR(("%s out of memory range len=%d but left=%d\n", __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); - return -1; + return BCME_BADARG; } - + str += 1; memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); *bytes_left -= ssid[idx].SSID_len; @@ -2154,16 +2161,11 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte DHD_TRACE(("%s :size=%d left=%d\n", (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); + } else { + DHD_ERROR(("### SSID size more than %d\n", str[0])); + return BCME_BADARG; } - else { - DHD_ERROR(("### SSID size more that %d\n", str[0])); - return -1; - } - - if (idx++ > max) { - DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); - return -1; - } + idx++; } *list_str = str; diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h b/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h index 99277f8b9fb9..caa82f18aed9 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h @@ -32,17 +32,17 @@ #define EPI_RC_NUMBER 67 -#define EPI_INCREMENTAL_NUMBER 30 +#define EPI_INCREMENTAL_NUMBER 32 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 141, 67, 30 +#define EPI_VERSION 1, 141, 67, 32 -#define EPI_VERSION_NUM 0x018d431e +#define EPI_VERSION_NUM 0x018d4320 #define EPI_VERSION_DEV 1.141.67 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.141.67.30 (r)" +#define EPI_VERSION_STR "1.141.67.32 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c b/drivers/net/wireless/bcmdhd_suzuran/wl_android.c index 25a69bd765b7..a7ac9103077a 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_android.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_android.c 701450 2017-05-25 02:10:23Z $ + * $Id: wl_android.c 736234 2017-12-14 04:22:25Z $ */ #include @@ -381,7 +381,7 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) int err = BCME_OK; uint i, tokens; char *pos, *pos2, *token, *token2, *delim; - char param[PNO_PARAM_SIZE], value[VALUE_SIZE]; + char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1]; struct dhd_pno_batch_params batch_params; DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); if (total_len < strlen(CMD_WLS_BATCHING)) { diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c index eb4c63e15980..8449e39c276d 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c @@ -1299,53 +1299,88 @@ wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, int err = 0; int type, tmp; const struct nlattr *iter; - uint32 mem_needed = 0, flush = 0, i = 0, num = 0; + uint32 mem_needed = 0, flush = 0, num = 0; /* Assumption: NUM attribute must come first */ nla_for_each_attr(iter, data, len, tmp) { type = nla_type(iter); switch (type) { case GSCAN_ATTRIBUTE_NUM_BSSID: + if (num != 0) { + WL_ERR(("attempt to change BSSID num\n")); + err = -EINVAL; + goto exit; + } + if (nla_len(iter) != sizeof(uint32)) { + WL_ERR(("not matching nla_len.\n")); + err = -EINVAL; + goto exit; + } num = nla_get_u32(iter); - if (num > MAX_BSSID_BLACKLIST_NUM) { - WL_ERR(("Too many Blacklist BSSIDs!\n")); + if (num == 0 || num > MAX_BSSID_BLACKLIST_NUM) { + WL_ERR(("wrong BSSID count:%d\n", num)); err = -EINVAL; goto exit; } + if (!blacklist) { + mem_needed = OFFSETOF(maclist_t, ea) + + sizeof(struct ether_addr) * (num); + blacklist = (maclist_t *) + kzalloc(mem_needed, GFP_KERNEL); + if (!blacklist) { + WL_ERR(("kzalloc failed.\n")); + err = -ENOMEM; + goto exit; + } + } break; case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH: + if (nla_len(iter) != sizeof(uint32)) { + WL_ERR(("not matching nla_len.\n")); + err = -EINVAL; + goto exit; + } flush = nla_get_u32(iter); + if (flush != 1) { + WL_ERR(("flush arg is worng:%d\n", flush)); + err = -EINVAL; + goto exit; + } break; case GSCAN_ATTRIBUTE_BLACKLIST_BSSID: - if (num) { - if (!blacklist) { - mem_needed = sizeof(maclist_t) + - sizeof(struct ether_addr) * (num - 1); - blacklist = (maclist_t *) - kmalloc(mem_needed, GFP_KERNEL); - if (!blacklist) { - WL_ERR(("%s: Can't malloc %d bytes\n", - __FUNCTION__, mem_needed)); - err = -ENOMEM; - goto exit; - } - blacklist->count = num; - } - if (i >= num) { - WL_ERR(("CFGs don't seem right!\n")); - err = -EINVAL; - goto exit; - } - memcpy(&(blacklist->ea[i]), - nla_data(iter), ETHER_ADDR_LEN); - i++; + if (num == 0 || !blacklist) { + WL_ERR(("number of BSSIDs not received.\n")); + err = -EINVAL; + goto exit; } + if (nla_len(iter) != ETHER_ADDR_LEN) { + WL_ERR(("not matching nla_len.\n")); + err = -EINVAL; + goto exit; + } + if (blacklist->count >= num) { + WL_ERR(("too many BSSIDs than expected:%d\n", + blacklist->count)); + err = -EINVAL; + goto exit; + } + memcpy(&(blacklist->ea[blacklist->count]), nla_data(iter), + ETHER_ADDR_LEN); + blacklist->count++; break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - break; - } + default: + WL_ERR(("No such attribute:%d\n", type)); + break; + } + } + + if (blacklist && (blacklist->count != num)) { + WL_ERR(("not matching bssid count:%d to expected:%d\n", + blacklist->count, num)); + err = -EINVAL; + goto exit; } + err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg), blacklist, mem_needed, flush); exit: -- GitLab From 1e41fd573e6b4834504a1a914d0ce2a771880078 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Tue, 22 Jul 2014 14:43:51 -0700 Subject: [PATCH 149/528] mac80211_hwsim: fix compiler warning on MIPS commit 5d26b50813ea6206a7bbab2e645e68044f101ac5 upstream. The dividend in do_div() is expected to be an unsigned 64-bit integer, which leads to the following warning when building for 32-bit MIPS: drivers/net/wireless/mac80211_hwsim.c: In function 'mac80211_hwsim_set_tsf': drivers/net/wireless/mac80211_hwsim.c:664:98: warning: comparison of distinct pointer types lacks a cast [enabled by default] data->bcn_delta = do_div(delta, bcn_int); Since we care about the signedness of delta when adjusting tsf_offset and bcm_delta, use the absolute value for the division and compare the two timestamps to determine the sign. Signed-off-by: Andrew Bresticker Signed-off-by: John W. Linville Signed-off-by: Ben Hutchings (cherry picked from commit ef0d8a14c361e22c44b5b22b6748cf3989acc7cc) --- drivers/net/wireless/mac80211_hwsim.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 735c26620387..886904bab9a2 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -441,11 +441,16 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, struct mac80211_hwsim_data *data = hw->priv; u64 now = mac80211_hwsim_get_tsf(hw, vif); u32 bcn_int = data->beacon_int; - s64 delta = tsf - now; + u64 delta = abs64(tsf - now); - data->tsf_offset += delta; /* adjust after beaconing with new timestamp at old TBTT */ - data->bcn_delta = do_div(delta, bcn_int); + if (tsf > now) { + data->tsf_offset += delta; + data->bcn_delta = do_div(delta, bcn_int); + } else { + data->tsf_offset -= delta; + data->bcn_delta = -do_div(delta, bcn_int); + } } static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, -- GitLab From 7c6445dcb4e8a4bbdc252a29a555902c4cad138f Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Sat, 3 Mar 2018 21:47:05 +0300 Subject: [PATCH 150/528] bcmdhd_suzuran: move ReleaseNote to the ChangeLog folder (cherry picked from commit 4cb35fc3b4b84fec748bad9e7f742b7a83d78fb2) --- .../{ => ChangeLog}/ReleaseNote.txt | 98 ++++++++++--------- 1 file changed, 51 insertions(+), 47 deletions(-) rename drivers/net/wireless/bcmdhd_suzuran/{ => ChangeLog}/ReleaseNote.txt (86%) diff --git a/drivers/net/wireless/bcmdhd_suzuran/ReleaseNote.txt b/drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt similarity index 86% rename from drivers/net/wireless/bcmdhd_suzuran/ReleaseNote.txt rename to drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt index a1fd76fc81ed..56101af582d0 100644 --- a/drivers/net/wireless/bcmdhd_suzuran/ReleaseNote.txt +++ b/drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt @@ -3,16 +3,23 @@ DHD 1.141.X Release for BCM4339, 4354, 43455 SDIO Projects. -------------------------------- Change History -------------------------------- +DHD 1.141.67.32 - 2017-12-14 + - Fixed buffer overrun issue in wl_parse_ssid_list_tlv() + - Fixed parsing issue on wl_parse_ssid_list_tlv() for PNO setup + - Fixed memory leak in PNO + - Fix potential buffer overflow + - Fixed missed SSID/MAC filtering in log for security reason + DHD 1.141.67.30 - 2017.8.31 - Security fix - - CVE-2017-0786 A-37351060 Added boundary check in wl_escan_handler() - - CVE-2017-0787 A-37722970 Added boundary check in dhd_pno_process_epno_result() - - CVE-2017-0788 A-37722328 Added boundary check in dhd_handle_hotlist_scan_evt() - - CVE-2017-0789 A-37685267 Removed unused SWC feature - - CVE-2017-0790 A-37357704 Added boundary check in dhd_process_full_gscan_result() - - CVE-2017-0791 A-37306719 Added event length check in wl_notify_rx_mgmt_frame() - - CVE-2017-0792 A-37305578 Added event length check in dhd_rtt_event_handler() - - V2017070601 Added P2P IE length check in parsing routine + - CVE-2017-0786 A-37351060 Added boundary check in wl_escan_handler() + - CVE-2017-0787 A-37722970 Added boundary check in dhd_pno_process_epno_result() + - CVE-2017-0788 A-37722328 Added boundary check in dhd_handle_hotlist_scan_evt() + - CVE-2017-0789 A-37685267 Removed unused SWC feature + - CVE-2017-0790 A-37357704 Added boundary check in dhd_process_full_gscan_result() + - CVE-2017-0791 A-37306719 Added event length check in wl_notify_rx_mgmt_frame() + - CVE-2017-0792 A-37305578 Added event length check in dhd_rtt_event_handler() + - V2017070601 Added P2P IE length check in parsing routine DHD 1.141.67.29 - 2017.6.27 - Security fix @@ -25,7 +32,7 @@ DHD 1.141.67.28 - 2017.5.26 - CVE-2016-0802 Code enhancement for prevention of overflow DHD 1.141.67.27 - 2017.3.24 - - Google security fix + - Google security fix - Fix buffer overrun in wl_cfg80211_add_iw_ie, CVE-2017-0567, A-32125310. - Fix buffer overrun in wl_run_escan, CVE-2017-0568, A-34197514. - Fix buffer overrun in dhd_wlfc_reorderinfo_indicate, CVE-2017-0571, A-34203305. @@ -35,7 +42,7 @@ DHD 1.141.67.27 - 2017.3.24 DHD 1.141.67.26 - 2017.2.24 - Google security fix - Prevent buffer overflow of "default_chan_list" in wl_run_escan(). - Google security fix - Check a "results->pkt_count" length not to exceed allocated memory length. - - Google security fix - Removing the unused WEXT file, A-32124445 + - Google security fix - Removing the unused WEXT file, A-32124445 DHD 1.141.67.25 - 2017.1.24 - Google Security Patch - fix possible use-after-free case, A-32838767 @@ -85,18 +92,18 @@ DHD 1.141.67.16 - 2015.11.20 DHD 1.141.67.15 - 2015.11.10 - Additional Android M updates for Loire - - 11mc ftm - - ePNO - - RSSI Monitoring + - 11mc ftm + - ePNO + - RSSI Monitoring - ANQP offload DHD 1.141.67.14 - 2015.11.04 - Android M updates - - Add mkeep_alive feature - - 5GHz Softap - - Gscan Updates - - LinkStat DHD Updates - + - Add mkeep_alive feature + - 5GHz Softap + - Gscan Updates + - LinkStat DHD Updates + DHD 1.141.67.13 - 2015.08.17 - Not to forward BRCM event as a network pkt '0x886c' [CASE# 952625], Shinano 2.1, Kitakami R2,43455 @@ -104,28 +111,28 @@ DHD 1.141.67.12 - 2015.07.15 - Add srl/lrl value setting in Softap, fix the issue not set properly. [CASE# 912911, 930776], Shinano 2.1, Kitakami R2,43455 - Fix for P2P TA issue[ CASE#943732], Kitakami R2, 43455 - Fix for linkstat buffer corruption causing android framework crash [CASE # 940151], Shinano R2.1(4354), Kitakami R2, 43455 - -DHD 1.141.67.11 - 2015.07.08 + +DHD 1.141.67.11 - 2015.07.08 - 4-way handshake delayed when roaming due to uplink traffic (Shinano 2.1 BCM4339 CASE#886484) - Add bcn_to_dly iovar to control link_down event,(Kitakami R2 43455 CASE#912211) - GSCAN fix only for Kitakami R2 43455 - -DHD 1.141.67.10 - 2015.05.29 + +DHD 1.141.67.10 - 2015.05.29 - Add DHD flag to disable 11N proprietary rates. (Kitakami R2 43455 CASE#927300) - Disable TX Beamforming (tx only). (Kitakami R2 43455 CASE#925270) -DHD 1.141.67.9 - 2015.04.30 - - TDLS mgmt build error fix CASE#844655 (CASE#911280) - -DHD 1.141.67.8 - 2015.04.14 +DHD 1.141.67.9 - 2015.04.30 + - TDLS mgmt build error fix CASE#844655 (CASE#911280) + +DHD 1.141.67.8 - 2015.04.14 - Firmware not responding (when running batch scan while in dhcp negotiation (CASE#907419) - Question regarding a huge kmalloc barely used (CASE#903335) - Code questions (CASE#896789) - WL_VENDOR_EXT_SUPPORT definition (CASE#901912) - Release wake lock("wlan_wake") when terminating event thread -DHD 1.141.67.7 - 2015.03.13 - - Use if_counters for connection statistics per interface when available, CSP:892522, Only available in Kitakami R2 43455. +DHD 1.141.67.7 - 2015.03.13 + - Use if_counters for connection statistics per interface when available, CSP:892522, Only available in Kitakami R2 43455. - Fix for ARP stuck issue in multihoming CSP:895926 DHD 1.141.67.6 - 2015.02.03 @@ -141,47 +148,46 @@ DHD 1.141.67.5 - 2015.01.09 - Allow to scan for p2p on passive channel, CSP #868771 - Fix trap in dhd_free(), CSP #874320 - Creating P2P group in available bandwidths in passive channels on 5GHz region, CSP #830497 - + DHD 1.141.67.4 - 2014.12.5 - - Fix build errors caused by Android L updates, - - Fix some warning and potential build error with Kernel 3.8 above. + - Fix build errors caused by Android L updates + - Fix some warning and potential build error with Kernel 3.8 above. DHD 1.141.67.3 - 2014.11.20 (Google L support) - Including android Google L adaptation code (Gscan, Linkstat, Private PNO and RTT which can be selectable in Makefie) - Makefile(Google Android L), Makefile.kk (for Kitkat) - - Enable Dongle memory dump feature. - - Increase max nvram buffer size. - + - Enable Dongle memory dump feature. + - Increase max nvram buffer size. + DHD 1.141.67.2 - 2014.09.05 - Fix for WFA PMF_AP certification. CSP #824822 - Netif packet counters are not updated in wlfc flow control - Adding check routine , wakelock, during softap - - WiFi Direct Certification 5.1.20 change GAS frame handling. - - hostapd ap_info null ptr check added. + - WiFi Direct Certification 5.1.20 change GAS frame handling + - hostapd ap_info null ptr check added DHD 1.141.67.1 - 2014.07.28 - Update Ccode translate table for SOMC - Don't use wlfc info exchange when a device is asleep on SDIO - Increase MAX_CNTL_TX_TIMEOUT to 3 from 2 by specifying it in Makefile. CSP # 800769 - + DHD 1.141.67 - 2014.07.09 - Keep connection while regulatory code change - CSP #803478 - Including action code for tunneled prob req to set wfd ie. CSP # 809533 - MAX_KSO_ATTEMPTS changed to 64, same as R1's - Prevent running wl_event_handler while HANG is occurred - Fix for hostapd buffer free - -DHD 1.141.65 - 2014.06.05 + +DHD 1.141.65 - 2014.06.05 - Fix mmc error at re-loading dhd driver CSP#779847 - Add supports for tdls management frames CSP#778769 - P2P fails after a driver stop / start in the kernel 3.10 - - Increase assoc_retry_max from 3 to 7 to increase a connection rate in very noisy environmnet. + - Increase assoc_retry_max from 3 to 7 to increase a connection rate in very noisy environmnet. - Added definition SUPPORT_P2P_GO_PS in checking bus_sleep code - - Fix multi-AC detection logic to look at rx packets as well as tx packets - -DHD 1.141.60 - 2014.05.16 + - Fix multi-AC detection logic to look at rx packets as well as tx packets +DHD 1.141.60 - 2014.05.16 - CSP 791385, tdls auto enable delete in Makefile - CSP 796606, SOFTAP WPS tethering issue fixed - CSP:779847 Fix mmc error at re-loading dhd driver @@ -198,16 +204,14 @@ DHD 1.141.60 - 2014.05.16 - Packet was freed before both proptxstatus and txcomplete finished - Fix chanspec mismatch - Fix multicast recive in P2P mode - - Kernel 3.14 support + - Kernel 3.14 support - Remove the duplicated kfree of ndev->ieee80211_ptr pointer in wl_dealloc_netinfo - Prevent the RTNL assertion when calling the cfg80211_unregister_wdev function while dhd_module_cleanup - Remove the kernel version dependency in case of using wl_cfg80211_remove_if in wl_cfg80211_handle_ifdel function. - Country/Revision is not initialized after Wi-Fi off->on - Fix the incorrect channel extraction from chanspec when 0 is given as a control channel while scanning - Supporting WNM Notification for HS20 REL2 - - Applying Interaction with MFP by Spec HS2.0 REL2 - + - Applying Interaction with MFP by Spec HS2.0 REL2 2014.03.19 - DHD 1.141.48 - Initial Release for Shinano R2, BCM4339 & BCM4354 - -- GitLab From 08ce485f7b08ee55e1bb9906453252258ecef211 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Wed, 3 Jan 2018 13:57:12 -0800 Subject: [PATCH 151/528] net: wireless: bcmdhd: fix integer overflow in wl_get_assoc_ies integer overflow case found where signed integer variable converted to unsigned one without proper bounds checking. Then this would result in kernel memory corruption by OOB write. CVE-2017-13292 Bug: 70722061 Change-Id: Idb1aa16ae1bae9c3f601e6688cd263fa95a93bdf Signed-off-by: Insun Song (cherry picked from commit 0c25842aa11f56ca623f53452750c395b801415d) --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 76 ++++++++++++++--------- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 6 +- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index f372d6aee357..4d9b84165553 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -9381,6 +9381,32 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.req_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.req_len > 0) && + (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0)))) { + err = BCME_BADLEN; + goto exit; + } + if (assoc_info.resp_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.resp_len > 0) && + (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -9389,48 +9415,42 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) conn_info->resp_ie_len = 0; bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); } + if (assoc_info.req_len) { - err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - return err; + goto exit; } - conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); + conn_info->req_ie_len = assoc_info.req_len - + sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - if (conn_info->req_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->req_ie_len, MAX_REQ_LINE)); - return err; - } - } else { - conn_info->req_ie_len = 0; + memcpy(conn_info->req_ie, cfg->extra_buf, + conn_info->req_ie_len); } + if (assoc_info.resp_len) { - err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - return err; - } - conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); - if (conn_info->resp_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->resp_ie_len, MAX_REQ_LINE)); - return err; + goto exit; } - } else { - conn_info->resp_ie_len = 0; + conn_info->resp_ie_len = + assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + memcpy(conn_info->resp_ie, cfg->extra_buf, + conn_info->resp_ie_len); } - WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, - conn_info->resp_ie_len)); +exit: + if (err) { + WL_ERR(("err:%d assoc-req:%u,resp:%u conn-req:%u,resp:%u\n", + err, assoc_info.req_len, assoc_info.resp_len, + conn_info->req_ie_len, conn_info->resp_ie_len)); + } return err; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 326700e4b5ff..f1dfe77b95ef 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -373,12 +373,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024 +#define MAX_REQ_LINE 1024u struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - s32 req_ie_len; + u32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - s32 resp_ie_len; + u32 resp_ie_len; }; /* firmware /nvram downloading controller */ -- GitLab From 2a3cd59e0669750438e3fccbddd6cad5c0736a9d Mon Sep 17 00:00:00 2001 From: Insun Song Date: Wed, 3 Jan 2018 13:57:12 -0800 Subject: [PATCH 152/528] net: wireless: bcmdhd_suzuran: fix integer overflow in wl_get_assoc_ies integer overflow case found where signed integer variable converted to unsigned one without proper bounds checking. Then this would result in kernel memory corruption by OOB write. CVE-2017-13292 Bug: 70722061 Change-Id: Idb1aa16ae1bae9c3f601e6688cd263fa95a93bdf Signed-off-by: Insun Song [bcmdhd -> bcmdhd_suzuran] Signed-off-by: Andrey Cherepkov (cherry picked from commit 07ea1e5e4509c4dcd4404b4fe8026e2c633cbc76) --- .../net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 76 ++++++++++++------- .../net/wireless/bcmdhd_suzuran/wl_cfg80211.h | 6 +- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c index dd5fb0275d80..e4e1fc8cde2d 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c @@ -8526,6 +8526,32 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.req_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.req_len > 0) && + (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0)))) { + err = BCME_BADLEN; + goto exit; + } + if (assoc_info.resp_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.resp_len > 0) && + (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -8534,48 +8560,42 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) conn_info->resp_ie_len = 0; bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); } + if (assoc_info.req_len) { - err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - return err; + goto exit; } - conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); + conn_info->req_ie_len = assoc_info.req_len - + sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - if (conn_info->req_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->req_ie_len, MAX_REQ_LINE)); - return err; - } - } else { - conn_info->req_ie_len = 0; + memcpy(conn_info->req_ie, cfg->extra_buf, + conn_info->req_ie_len); } + if (assoc_info.resp_len) { - err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - return err; - } - conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); - if (conn_info->resp_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->resp_ie_len, MAX_REQ_LINE)); - return err; + goto exit; } - } else { - conn_info->resp_ie_len = 0; + conn_info->resp_ie_len = + assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + memcpy(conn_info->resp_ie, cfg->extra_buf, + conn_info->resp_ie_len); } - WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, - conn_info->resp_ie_len)); +exit: + if (err) { + WL_ERR(("err:%d assoc-req:%u,resp:%u conn-req:%u,resp:%u\n", + err, assoc_info.req_len, assoc_info.resp_len, + conn_info->req_ie_len, conn_info->resp_ie_len)); + } return err; } diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h index 069eda344e49..d62792b0d2e5 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h @@ -364,12 +364,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024 +#define MAX_REQ_LINE 1024u struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - s32 req_ie_len; + u32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - s32 resp_ie_len; + u32 resp_ie_len; }; /* firmware /nvram downloading controller */ -- GitLab From 3c522c314816316f011c8c35f745336f6c935e06 Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Tue, 18 Feb 2014 21:36:00 +0800 Subject: [PATCH 153/528] rndis_wlan: replace function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} Replace ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} with more generic ieee80211_{channel_to_frequency, frequency_to_channel}. File has already been included. It's safe to use IEEE80211_BAND_2GHZ here. This change is a preparation for the removal of function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan}. Cc: Jussi Kivilinna Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville (cherry picked from commit b2edf88c1591e1ce832a0a143a34c5f4a70f5bc3) --- drivers/net/wireless/rndis_wlan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 8169a85c4498..b74e1081f56e 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1292,7 +1292,8 @@ static int set_channel(struct usbnet *usbdev, int channel) if (is_associated(usbdev)) return 0; - dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000; + dsconfig = 1000 * + ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); len = sizeof(config); ret = rndis_query_oid(usbdev, -- GitLab From ca9a8695b8c4af1a1af9509bcbf2cca4a0ed87ee Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 14 May 2015 11:37:50 +0300 Subject: [PATCH 154/528] rndis_wlan: harmless issue calling set_bit() These are used like: set_bit(WORK_LINK_UP, &priv->work_pending); The problem is that set_bit() takes the actual bit number and not a mask so static checkers get upset. It doesn't affect run time because we do it consistently, but we may as well clean it up. Fixes: 6010ce07a66c ('rndis_wlan: do link-down state change in worker thread') Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo (cherry picked from commit 33ee860c8d1e1c31602388419fb171bd8f05dbf4) --- drivers/net/wireless/rndis_wlan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index b74e1081f56e..0f49d1f82304 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -358,9 +358,9 @@ struct ndis_80211_pmkid { #define CAP_MODE_80211G 4 #define CAP_MODE_MASK 7 -#define WORK_LINK_UP (1<<0) -#define WORK_LINK_DOWN (1<<1) -#define WORK_SET_MULTICAST_LIST (1<<2) +#define WORK_LINK_UP 0 +#define WORK_LINK_DOWN 1 +#define WORK_SET_MULTICAST_LIST 2 #define RNDIS_WLAN_ALG_NONE 0 #define RNDIS_WLAN_ALG_WEP (1<<0) -- GitLab From 171ae691d4a84e6b36138359c0db1ccc5969243c Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 21 Sep 2015 15:33:55 +0200 Subject: [PATCH 155/528] rndis_wlan: fix checking for default value Thresholds uses -1 to indicate that default value should be used. Since thresholds are unsigned sign checking makes no sense. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2038576 Signed-off-by: Andrzej Hajda Signed-off-by: David S. Miller (cherry picked from commit 127eacec777eac719217cb219f502c003ed6d62f) --- drivers/net/wireless/rndis_wlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 0f49d1f82304..1b7117e4c84d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1238,7 +1238,7 @@ static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold); - if (rts_threshold < 0 || rts_threshold > 2347) + if (rts_threshold == -1 || rts_threshold > 2347) rts_threshold = 2347; tmp = cpu_to_le32(rts_threshold); -- GitLab From 7729c6c8e322fb0a2bb3b6f94083454eddd68d50 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 25 Jan 2015 10:52:42 +0200 Subject: [PATCH 156/528] wil6210: sync WMI with firmware Incorporate changes from firmware. Change-Id: I86816d8470cc1448ac1345d87f5fe951ddf9c8db Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 8c6796758f0abd8ee2b4d7e8c6ca5f7adf737ee6 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 0b3aee06bd8928c876fade7ea484e3cf19cc2fa4) --- drivers/net/wireless/ath/wil6210/wmi.c | 15 +++---- drivers/net/wireless/ath/wil6210/wmi.h | 58 ++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 1cae1ea1c37f..3285c45760b3 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1143,12 +1143,13 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) return rc; } -int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) +int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) { int rc; struct wmi_temp_sense_cmd cmd = { - .measure_marlon_m_en = cpu_to_le32(!!t_m), - .measure_marlon_r_en = cpu_to_le32(!!t_r), + .measure_baseband_en = cpu_to_le32(!!t_bb), + .measure_rf_en = cpu_to_le32(!!t_rf), + .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW), }; struct { struct wil6210_mbox_hdr_wmi wmi; @@ -1160,10 +1161,10 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) if (rc) return rc; - if (t_m) - *t_m = le32_to_cpu(reply.evt.marlon_m_t1000); - if (t_r) - *t_r = le32_to_cpu(reply.evt.marlon_r_t1000); + if (t_bb) + *t_bb = le32_to_cpu(reply.evt.baseband_t1000); + if (t_rf) + *t_rf = le32_to_cpu(reply.evt.rf_t1000); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index b5102f0b97f4..8a4af613e191 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -29,8 +29,10 @@ /* General */ #define WILOCITY_MAX_ASSOC_STA (8) +#define WILOCITY_DEFAULT_ASSOC_STA (1) #define WMI_MAC_LEN (6) #define WMI_PROX_RANGE_NUM (3) +#define WMI_MAX_LOSS_DMG_BEACONS (32) /* List of Commands */ enum wmi_command_id { @@ -48,7 +50,7 @@ enum wmi_command_id { WMI_SET_WSC_STATUS_CMDID = 0x0041, WMI_PXMT_RANGE_CFG_CMDID = 0x0042, WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043, - WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, +/* WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, */ WMI_MEM_READ_CMDID = 0x0800, WMI_MEM_WR_CMDID = 0x0801, WMI_ECHO_CMDID = 0x0803, @@ -102,6 +104,8 @@ enum wmi_command_id { WMI_MAINTAIN_RESUME_CMDID = 0x0851, WMI_RS_MGMT_CMDID = 0x0852, WMI_RF_MGMT_CMDID = 0x0853, + WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x0854, + WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x0855, /* Performance monitoring commands */ WMI_BF_CTRL_CMDID = 0x0862, WMI_NOTIFY_REQ_CMDID = 0x0863, @@ -136,6 +140,7 @@ enum wmi_command_id { WMI_EAPOL_TX_CMDID = 0xf04c, WMI_MAC_ADDR_REQ_CMDID = 0xf04d, WMI_FW_VER_CMDID = 0xf04e, + WMI_PMC_CMDID = 0xf04f, }; /* @@ -283,8 +288,8 @@ enum wmi_scan_type { WMI_LONG_SCAN = 0, WMI_SHORT_SCAN = 1, WMI_PBC_SCAN = 2, - WMI_ACTIVE_SCAN = 3, - WMI_DIRECT_SCAN = 4, + WMI_DIRECT_SCAN = 3, + WMI_ACTIVE_SCAN = 4, }; struct wmi_start_scan_cmd { @@ -374,6 +379,17 @@ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; +/* + * WMI_THERMAL_THROTTLING_CTRL_CMDID + */ +#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF) + +struct wmi_thermal_throttling_ctrl_cmd { + __le32 time_on_usec; + __le32 time_off_usec; + __le32 max_txop_length_usec; +} __packed; + /* * WMI_RF_RX_TEST_CMDID */ @@ -648,6 +664,7 @@ enum wmi_cfg_rx_chain_cmd_action { enum wmi_cfg_rx_chain_cmd_decap_trans_type { WMI_DECAP_TYPE_802_3 = 0, WMI_DECAP_TYPE_NATIVE_WIFI = 1, + WMI_DECAP_TYPE_NONE = 2, }; enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type { @@ -785,9 +802,17 @@ struct wmi_echo_cmd { * * Measure MAC and radio temperatures */ + +/* Possible modes for temperature measurement */ +enum wmi_temperature_measure_mode { + TEMPERATURE_USE_OLD_VALUE = 0x1, + TEMPERATURE_MEASURE_NOW = 0x2, +}; + struct wmi_temp_sense_cmd { - __le32 measure_marlon_m_en; - __le32 measure_marlon_r_en; + __le32 measure_baseband_en; + __le32 measure_rf_en; + __le32 measure_mode; } __packed; /* @@ -843,6 +868,7 @@ enum wmi_event_id { WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, WMI_RS_MGMT_DONE_EVENTID = 0x1852, WMI_RF_MGMT_STATUS_EVENTID = 0x1853, + WMI_THERMAL_THROTTLING_STATUS_EVENTID = 0x1855, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_RX_MGMT_PACKET_EVENTID = 0x1840, WMI_TX_MGMT_PACKET_EVENTID = 0x1841, @@ -859,6 +885,7 @@ enum wmi_event_id { WMI_FLASH_READ_DONE_EVENTID = 0x1902, WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, /*P2P*/ + WMI_P2P_CFG_DONE_EVENTID = 0x1910, WMI_PORT_ALLOCATED_EVENTID = 0x1911, WMI_PORT_DELETED_EVENTID = 0x1912, WMI_LISTEN_STARTED_EVENTID = 0x1914, @@ -898,6 +925,15 @@ struct wmi_rf_mgmt_status_event { __le32 rf_status; } __packed; +/* + * WMI_THERMAL_THROTTLING_STATUS_EVENTID + */ +struct wmi_thermal_throttling_status_event { + __le32 time_on_usec; + __le32 time_off_usec; + __le32 max_txop_length_usec; +} __packed; + /* * WMI_GET_STATUS_DONE_EVENTID */ @@ -1154,6 +1190,14 @@ struct wmi_get_pcp_channel_event { u8 reserved[3]; } __packed; +/* + * WMI_P2P_CFG_DONE_EVENTID + */ +struct wmi_p2p_cfg_done_event { + u8 status; /* wmi_fw_status */ + u8 reserved[3]; +} __packed; + /* * WMI_PORT_ALLOCATED_EVENTID */ @@ -1282,8 +1326,8 @@ struct wmi_echo_event { * Measure MAC and radio temperatures */ struct wmi_temp_sense_done_event { - __le32 marlon_m_t1000; - __le32 marlon_r_t1000; + __le32 baseband_t1000; + __le32 rf_t1000; } __packed; #endif /* __WILOCITY_WMI_H__ */ -- GitLab From 008706300fe7e3aa397f15fd5750d80d4aa0f3a7 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 25 Jan 2015 10:52:43 +0200 Subject: [PATCH 157/528] wil6210: fix timing of netif_carrier_on indication netif_carrier_on indication was too late. In case Rx packet received before netif_carrier_on indication, upper layers could not send Tx packet back. The fix is to indicate netif_carrier_on earlier: for STA, indicate netif_carrier_on when association starts. for AP/PCP, indicate netif_carrier_on upon starting AP/PCP. Change-Id: I488aa0363812f7705413a89ba2569e8457a52b4f Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: c5e96c91fa8f98ddceac16f410fc741648585401 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit ea429726b3099a02a373d03235f934a9914e76b0) --- drivers/net/wireless/ath/wil6210/cfg80211.c | 8 +++--- drivers/net/wireless/ath/wil6210/main.c | 30 +++++---------------- drivers/net/wireless/ath/wil6210/netdev.c | 4 +-- drivers/net/wireless/ath/wil6210/wil6210.h | 2 -- drivers/net/wireless/ath/wil6210/wmi.c | 2 -- 5 files changed, 12 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 9748737082b6..dd30491f37b6 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -454,6 +454,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); if (rc == 0) { + netif_carrier_on(ndev); /* Connect can take lots of time */ mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); @@ -760,12 +761,12 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil->secure_pcp = info->privacy; + netif_carrier_on(ndev); + rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) - goto out; - - netif_carrier_on(ndev); + netif_carrier_off(ndev); out: mutex_unlock(&wil->mutex); @@ -780,6 +781,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wil_dbg_misc(wil, "%s()\n", __func__); + netif_carrier_off(ndev); wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 1f829541f16e..89bc3982ec78 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -248,7 +248,9 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid, switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - wil_link_off(wil); + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); + if (test_bit(wil_status_fwconnected, wil->status)) { clear_bit(wil_status_fwconnected, wil->status); cfg80211_disconnected(ndev, reason_code, @@ -395,6 +397,8 @@ static void wil_connect_worker(struct work_struct *work) int rc; struct wil6210_priv *wil = container_of(work, struct wil6210_priv, connect_worker); + struct net_device *ndev = wil_to_ndev(wil); + int cid = wil->pending_connect_cid; int ringid = wil_find_free_vring(wil); @@ -409,7 +413,7 @@ static void wil_connect_worker(struct work_struct *work) wil->pending_connect_cid = -1; if (rc == 0) { wil->sta[cid].status = wil_sta_connected; - wil_link_on(wil); + netif_tx_wake_all_queues(ndev); } else { wil->sta[cid].status = wil_sta_unused; } @@ -741,28 +745,6 @@ void wil_fw_error_recovery(struct wil6210_priv *wil) schedule_work(&wil->fw_error_worker); } -void wil_link_on(struct wil6210_priv *wil) -{ - struct net_device *ndev = wil_to_ndev(wil); - - wil_dbg_misc(wil, "%s()\n", __func__); - - netif_carrier_on(ndev); - wil_dbg_misc(wil, "netif_tx_wake : link on\n"); - netif_tx_wake_all_queues(ndev); -} - -void wil_link_off(struct wil6210_priv *wil) -{ - struct net_device *ndev = wil_to_ndev(wil); - - wil_dbg_misc(wil, "%s()\n", __func__); - - netif_tx_stop_all_queues(ndev); - wil_dbg_misc(wil, "netif_tx_stop : link off\n"); - netif_carrier_off(ndev); -} - int __wil_up(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 75bff317b20c..a49d42fd63a4 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -174,7 +174,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, WIL6210_NAPI_BUDGET); - wil_link_off(wil); + netif_tx_stop_all_queues(ndev); return wil; @@ -217,8 +217,6 @@ int wil_if_add(struct wil6210_priv *wil) return rc; } - wil_link_off(wil); - return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 6059946709d3..c3730fffa44d 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -645,8 +645,6 @@ void wil_priv_deinit(struct wil6210_priv *wil); int wil_reset(struct wil6210_priv *wil); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); -void wil_link_on(struct wil6210_priv *wil); -void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); int __wil_up(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 3285c45760b3..9f0fac384093 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -576,7 +576,6 @@ static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize) static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) { - struct net_device *ndev = wil_to_ndev(wil); struct wmi_data_port_open_event *evt = d; u8 cid = evt->cid; @@ -590,7 +589,6 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) wil->sta[cid].data_port_open = true; if (agg_wsize >= 0) wil_addba_tx_cid(wil, cid, agg_wsize); - netif_carrier_on(ndev); } static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len) -- GitLab From d15314f6081307d3cfb84851fa7d111174eb48cc Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 25 Jan 2015 10:52:44 +0200 Subject: [PATCH 158/528] wil6210: ignore firmware failure to gracefully stop AP upon cfg80211_stop_ap, a graceful AP shutdown is requested from firmware followed by firmware reset. In case graceful request failed, error was returned to cfg80211. The change is to return success in this scenario, because firmware reset will anyhow shutdown the AP. Change-Id: I9d4e2909dad47d64f33b0c5522970dd4e6a92e46 Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 32a20d46b3dcb2f96ffcd5f967616cc599bdf542 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 8585839cee9c2d847f74a6eac74af464636549b5) --- drivers/net/wireless/ath/wil6210/cfg80211.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index dd30491f37b6..2865b54722f9 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -776,7 +776,6 @@ out: static int wil_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { - int rc, rc1; struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s()\n", __func__); @@ -786,14 +785,17 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, mutex_lock(&wil->mutex); - rc = wmi_pcp_stop(wil); + wmi_pcp_stop(wil); __wil_down(wil); - rc1 = __wil_up(wil); + __wil_up(wil); mutex_unlock(&wil->mutex); - return min(rc, rc1); + /* some functions above might fail (e.g. __wil_up). Nevertheless, we + * return success because AP has stopped + */ + return 0; } static int wil_cfg80211_del_station(struct wiphy *wiphy, -- GitLab From f056de7151e1868bb5640f4d465815a1dd799a2a Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Sun, 25 Jan 2015 10:52:45 +0200 Subject: [PATCH 159/528] wil6210: Add Tx queue len configuration Tx queue was hard-coded to 1000 in ether_setup. Add wil_dev_setup function which configures tx queue len to chosen default value after calling ether_setup. Change-Id: I1ace7e8540c8aa76993c92e7a4d9b08f1506746c Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: f1871cd95067eb695ae126d43c12bc738627a90e Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git [hkadmany@codeaurora.org: trivial backport to kernel 3.10] Signed-off-by: Hamad Kadmany (cherry picked from commit 1fe250fa538f4b0c4d17d3e11ee85f73ed0530a6) --- drivers/net/wireless/ath/wil6210/netdev.c | 11 ++++++++--- drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index a49d42fd63a4..2533101d90e8 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,6 @@ */ #include - #include "wil6210.h" #include "txrx.h" @@ -122,6 +121,12 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) return min(tx_done, budget); } +static void wil_dev_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; +} + void *wil_if_alloc(struct device *dev, void __iomem *csr) { struct net_device *ndev; @@ -153,7 +158,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); - ndev = alloc_netdev(0, "wlan%d", ether_setup); + ndev = alloc_netdev(0, "wlan%d", wil_dev_setup); if (!ndev) { dev_err(dev, "alloc_netdev_mqs failed\n"); rc = -ENOMEM; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c3730fffa44d..25cc4d53e6ea 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -44,6 +44,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) +#define WIL_TX_Q_LEN_DEFAULT (4000) #define WIL_RX_RING_SIZE_ORDER_DEFAULT (9) #define WIL_TX_RING_SIZE_ORDER_DEFAULT (9) /* limit ring size in range [32..32k] */ -- GitLab From 31e67af413a86d4f15ea419c6b5bccbdac13f8cb Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Sun, 25 Jan 2015 10:52:46 +0200 Subject: [PATCH 160/528] wil6210: tuning rings size Tuning rings size for performance optimization. Increasing Tx ring size, allows buffering more packets for HW, thus eliminating idle periods which were observed with smaller ring at high throughput, because HW was fetching packets faster than driver was filling them into the TX ring. Rx ring was similarly increased to avoid same problems in Rx. Change-Id: I6afc0b22744aca776ba0e3746ea753479fe2c489 Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 3baedd9167c2e3a3593c20769256b700aba929da Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 24025b1b2197a86a7deeafb8dbe1531a34d43d42) --- drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 25cc4d53e6ea..2f2a85aaa530 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -45,8 +45,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) #define WIL_TX_Q_LEN_DEFAULT (4000) -#define WIL_RX_RING_SIZE_ORDER_DEFAULT (9) -#define WIL_TX_RING_SIZE_ORDER_DEFAULT (9) +#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) +#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10) /* limit ring size in range [32..32k] */ #define WIL_RING_SIZE_ORDER_MIN (5) #define WIL_RING_SIZE_ORDER_MAX (15) -- GitLab From 78d810419cd2de3b9e093583ff1972ddd3806da0 Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Sun, 25 Jan 2015 10:52:47 +0200 Subject: [PATCH 161/528] wil6210: interrupt moderation configuration update Due to HW limitation, inter-packet gap timeout max value is 13 usec. Update of current thresholds from 15 to 13 usec. Change-Id: I01562a3ef2fa87e5066e8bb2315b5e89c8a16e46 Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 918465a3c2f7f28926821500152d89511d82166a Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit cbe4b6f00662d1e39aa1c9dbe4b776fe4d02f7d2) --- drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 2f2a85aaa530..a681d8272bc0 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -78,8 +78,8 @@ static inline u32 wil_mtu2macbuf(u32 mtu) #define WIL_MAX_ETH_MTU (IEEE80211_MAX_DATA_LEN_DMG - 8) /* Max supported by wil6210 value for interrupt threshold is 5sec. */ #define WIL6210_ITR_TRSH_MAX (5000000) -#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */ -#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */ +#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */ +#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */ #define WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ #define WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ #define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */ -- GitLab From 6ea7176e83b13ee2f69090028287918eecbda708 Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Sun, 25 Jan 2015 10:52:48 +0200 Subject: [PATCH 162/528] wil6210: remove unnecessary interrupt moderation module parameters Interrupt moderation parameters will never be passed as module parameters. For product, they will be hard-coded after lab testing, and for debugging, they can be altered via debugfs. Change-Id: I04eed84994caaaa8877955385617077669f08eb1 Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 1f80af2e38f7a1f66b75c63ba83f968da62f5985 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit dd7b423ec2fca28ad99a5e0122e6831cbf37d308) --- drivers/net/wireless/ath/wil6210/main.c | 38 ++++--------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 89bc3982ec78..e2fe55f0a26d 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,34 +33,6 @@ static bool no_fw_load = true; module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash."); -static unsigned int tx_interframe_timeout = - WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT; - -module_param(tx_interframe_timeout, uint, S_IRUGO); -MODULE_PARM_DESC(tx_interframe_timeout, - " Interrupt moderation TX interframe timeout, usecs."); - -static unsigned int rx_interframe_timeout = - WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT; - -module_param(rx_interframe_timeout, uint, S_IRUGO); -MODULE_PARM_DESC(rx_interframe_timeout, - " Interrupt moderation RX interframe timeout, usecs."); - -static unsigned int tx_max_burst_duration = - WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT; - -module_param(tx_max_burst_duration, uint, S_IRUGO); -MODULE_PARM_DESC(tx_max_burst_duration, - " Interrupt moderation TX max burst duration, usecs."); - -static unsigned int rx_max_burst_duration = - WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT; - -module_param(rx_max_burst_duration, uint, S_IRUGO); -MODULE_PARM_DESC(rx_max_burst_duration, - " Interrupt moderation RX max burst duration, usecs."); - /* if not set via modparam, will be set to default value of 1/8 of * rx ring size during init flow */ @@ -463,10 +435,10 @@ int wil_priv_init(struct wil6210_priv *wil) goto out_wmi_wq; wil->last_fw_recovery = jiffies; - wil->tx_interframe_timeout = tx_interframe_timeout; - wil->rx_interframe_timeout = rx_interframe_timeout; - wil->tx_max_burst_duration = tx_max_burst_duration; - wil->rx_max_burst_duration = rx_max_burst_duration; + wil->tx_interframe_timeout = WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT; + wil->rx_interframe_timeout = WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT; + wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT; + wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT; if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT) rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT; -- GitLab From fbdb43a8b9753e0c130c2afb23c65aac509b1aa8 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 25 Jan 2015 10:52:49 +0200 Subject: [PATCH 163/528] wil6210: implement skb Tx status reporting Implement Tx status reporting using skb_complete_wifi_ack(). Change-Id: I66fb238a5ef5cde1ab5b9df0f3f4bfa85ae0c1c7 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 713c8a29e4d869f7ca4cadc8a6ac2c12de532ed9 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git [hkadmany@codeaurora.org: trivial backport to kernel 3.10] Signed-off-by: Hamad Kadmany (cherry picked from commit b68c83a87e29addc176eaff7cb8489edee4c4f73) --- drivers/net/wireless/ath/wil6210/cfg80211.c | 1 + drivers/net/wireless/ath/wil6210/txrx.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 2865b54722f9..83d886144f93 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -862,6 +862,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->cipher_suites = wil_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); wiphy->mgmt_stypes = wil_mgmt_stypes; + wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; } struct wireless_dev *wil_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index b58ee52e1860..b5f33e9560b3 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1121,6 +1121,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NET_XMIT_DROP; } +static inline bool wil_need_txstat(struct sk_buff *skb) +{ + struct ethhdr *eth = (void *)skb->data; + + return is_unicast_ether_addr(eth->h_dest) && skb->sk && + (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS); +} + +static inline void wil_consume_skb(struct sk_buff *skb, bool acked) +{ + if (unlikely(wil_need_txstat(skb))) + skb_complete_wifi_ack(skb, acked); + else + dev_kfree_skb_any(skb); +} + /** * Clean up transmitted skb's from the Tx VRING * @@ -1199,8 +1215,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) ndev->stats.tx_errors++; stats->tx_errors++; } - - dev_kfree_skb_any(skb); + wil_consume_skb(skb, d->dma.error == 0); } memset(ctx, 0, sizeof(*ctx)); /* There is no need to touch HW descriptor: -- GitLab From f80d5c94c862dffe2c5560e0461faa5170c53fd2 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 25 Jan 2015 10:52:50 +0200 Subject: [PATCH 164/528] wil6210: implement cfg80211 probe_client() op Access point require this API to check peer alive status. Assume peer is alive when it is connected, because firmware implements keep alive checks and will disconnect peer if it is not alive. Change-Id: I3a421e008417442f9b52c2417199b59106f6ea72 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 40822a901e3c07e50fe9f6a0cbbe77cba9fbc898 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit b224c12f6028a1ac5a4955543c04394b3efd6b74) --- drivers/net/wireless/ath/wil6210/cfg80211.c | 91 +++++++++++++++++++++ drivers/net/wireless/ath/wil6210/main.c | 5 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 12 +++ 3 files changed, 108 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 83d886144f93..1d52e63e4865 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -812,6 +812,96 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy, return 0; } +/* probe_client handling */ +static void wil_probe_client_handle(struct wil6210_priv *wil, + struct wil_probe_client_req *req) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct wil_sta_info *sta = &wil->sta[req->cid]; + /* assume STA is alive if it is still connected, + * else FW will disconnect it + */ + bool alive = (sta->status == wil_sta_connected); + + cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL); +} + +static struct list_head *next_probe_client(struct wil6210_priv *wil) +{ + struct list_head *ret = NULL; + + mutex_lock(&wil->probe_client_mutex); + + if (!list_empty(&wil->probe_client_pending)) { + ret = wil->probe_client_pending.next; + list_del(ret); + } + + mutex_unlock(&wil->probe_client_mutex); + + return ret; +} + +void wil_probe_client_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, + probe_client_worker); + struct wil_probe_client_req *req; + struct list_head *lh; + + while ((lh = next_probe_client(wil)) != NULL) { + req = list_entry(lh, struct wil_probe_client_req, list); + + wil_probe_client_handle(wil, req); + kfree(req); + } +} + +void wil_probe_client_flush(struct wil6210_priv *wil) +{ + struct wil_probe_client_req *req, *t; + + wil_dbg_misc(wil, "%s()\n", __func__); + + mutex_lock(&wil->probe_client_mutex); + + list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) { + list_del(&req->list); + kfree(req); + } + + mutex_unlock(&wil->probe_client_mutex); +} + +static int wil_cfg80211_probe_client(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u64 *cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil_probe_client_req *req; + int cid = wil_find_cid(wil, peer); + + wil_dbg_misc(wil, "%s(%pM => CID %d)\n", __func__, peer, cid); + + if (cid < 0) + return -ENOLINK; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->cid = cid; + req->cookie = cid; + + mutex_lock(&wil->probe_client_mutex); + list_add_tail(&req->list, &wil->probe_client_pending); + mutex_unlock(&wil->probe_client_mutex); + + *cookie = req->cookie; + queue_work(wil->wq_service, &wil->probe_client_worker); + return 0; +} + static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, @@ -831,6 +921,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, + .probe_client = wil_cfg80211_probe_client, }; static void wil_wiphy_init(struct wiphy *wiphy) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index e2fe55f0a26d..86f06806f1df 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -405,6 +405,7 @@ int wil_priv_init(struct wil6210_priv *wil) mutex_init(&wil->wmi_mutex); mutex_init(&wil->back_rx_mutex); mutex_init(&wil->back_tx_mutex); + mutex_init(&wil->probe_client_mutex); init_completion(&wil->wmi_ready); init_completion(&wil->wmi_call); @@ -419,10 +420,12 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker); INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker); + INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); INIT_LIST_HEAD(&wil->back_rx_pending); INIT_LIST_HEAD(&wil->back_tx_pending); + INIT_LIST_HEAD(&wil->probe_client_pending); spin_lock_init(&wil->wmi_ev_lock); init_waitqueue_head(&wil->wq); @@ -485,6 +488,8 @@ void wil_priv_deinit(struct wil6210_priv *wil) cancel_work_sync(&wil->back_rx_worker); wil_back_tx_flush(wil); cancel_work_sync(&wil->back_tx_worker); + wil_probe_client_flush(wil); + cancel_work_sync(&wil->probe_client_worker); destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wmi_wq); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index a681d8272bc0..19e440ad645a 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -504,6 +504,12 @@ struct wil_back_tx { u16 agg_timeout; }; +struct wil_probe_client_req { + struct list_head list; + u64 cookie; + u8 cid; +}; + struct wil6210_priv { struct pci_dev *pdev; int n_msi; @@ -564,6 +570,10 @@ struct wil6210_priv { struct list_head back_tx_pending; struct mutex back_tx_mutex; /* protect @back_tx_pending */ struct work_struct back_tx_worker; + /* keep alive */ + struct list_head probe_client_pending; + struct mutex probe_client_mutex; /* protect @probe_client_pending */ + struct work_struct probe_client_worker; /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; @@ -721,6 +731,8 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); int wmi_pcp_stop(struct wil6210_priv *wil); void wil6210_disconnect(struct wil6210_priv *wil, void *bssid, u16 reason_code, bool from_event); +void wil_probe_client_flush(struct wil6210_priv *wil); +void wil_probe_client_worker(struct work_struct *work); int wil_rx_init(struct wil6210_priv *wil, u16 size); void wil_rx_fini(struct wil6210_priv *wil); -- GitLab From 56d19b48338290edac51163214c0eb2253708181 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 25 Jan 2015 10:52:51 +0200 Subject: [PATCH 165/528] wil6210: move Rx reorder buffer allocation out of spinlock This fixes issue reported by Dan Carpenter: The patch 3277213feb1b: "wil6210: ADDBA/DELBA flows" from Dec 23, 2014, leads to the following static checker warning: drivers/net/wireless/ath/wil6210/rx_reorder.c:205 wil_tid_ampdu_rx_alloc() error: scheduling with locks held: 'spin_lock:tid_rx_lock' drivers/net/wireless/ath/wil6210/rx_reorder.c 202 struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, 203 int size, u16 ssn) 204 { 205 struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL); ^^^^^^^^^^ 206 207 if (!r) 208 return NULL; 209 210 r->reorder_buf = 211 kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); ^^^^^^^^^^^ 212 r->reorder_time = 213 kcalloc(size, sizeof(unsigned long), GFP_KERNEL); ^^^^^^^^^^^ 214 if (!r->reorder_buf || !r->reorder_time) { 215 kfree(r->reorder_buf); 216 kfree(r->reorder_time); 217 kfree(r); 218 return NULL; 219 } 220 [ snip ] 331 spin_lock_bh(&sta->tid_rx_lock); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ spin lock held. 332 333 wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); 334 sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function called with the lock held. 335 336 spin_unlock_bh(&sta->tid_rx_lock); Change-Id: I4b75e8c2b672fe783de9b7c117ff6482cc6a566f Reported-by: Dan Carpenter Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 382afc3d055b9ac4d175a4b5b9352128fc091aa3 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 4f0160e825ab051b880fba301c31837e8d2db8d9) --- drivers/net/wireless/ath/wil6210/rx_reorder.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 552209227de9..ca10dcf0986e 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -292,6 +292,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) u16 agg_timeout = req->ba_timeout; u16 status = WLAN_STATUS_SUCCESS; u16 ssn = req->ba_seq_ctrl >> 4; + struct wil_tid_ampdu_rx *r; int rc; might_sleep(); @@ -328,11 +329,10 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) return; /* apply */ + r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); spin_lock_bh(&sta->tid_rx_lock); - wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); - sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); - + sta->tid_rx[tid] = r; spin_unlock_bh(&sta->tid_rx_lock); } -- GitLab From 2a2261511cbf5aced0da1e883d3b7505f3b2d4dc Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:11 +0200 Subject: [PATCH 166/528] wil6210: remove old Tx work-around In the Tx, work around used to force destination index 0 to be used. This is no more necessary, as firmware supports multiple destinations Change-Id: I2f2a12b835363141d581cea2f1e4dfeddcb6de80 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: a3c74902082c0e77aaf1065b5489867508db44ca Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 8152fda41874b740401772ee8ab22b262d7398d7) --- drivers/net/wireless/ath/wil6210/txrx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index b5f33e9560b3..bb1aecd91dc2 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -873,9 +873,6 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, d->mac.d[1] = 0; d->mac.d[2] = 0; d->mac.ucode_cmd = 0; - /* use dst index 0 */ - d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) | - (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS); /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); -- GitLab From ede238b6a1df184efb359a92ba43ffc4d6381dd8 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:12 +0200 Subject: [PATCH 167/528] wil6210: avoid Tx descriptor double write Non-cacheable Tx descriptor for the last fragment of multi-fragment frame used to be written back twice. Refactor code to always write non-cacheable descriptor only once Change-Id: Ib599de1f3f384704d70729d6523a9ba05e79e678 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: e59d16c08b3aa147f5c3c664d5dfda77fa93a827 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 52113fc58446d1d6b115c311142c0a08abb39196) --- drivers/net/wireless/ath/wil6210/txrx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index bb1aecd91dc2..16beaf965c0a 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -981,8 +981,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, vring->ctx[i].nr_frags = nr_frags; wil_tx_desc_set_nr_frags(d, nr_frags); - if (nr_frags) - *_d = *d; /* middle segments */ for (; f < nr_frags; f++) { @@ -990,6 +988,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, &skb_shinfo(skb)->frags[f]; int len = skb_frag_size(frag); + *_d = *d; i = (swhead + f + 1) % vring->size; _d = &vring->va[i].tx; pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), @@ -1003,7 +1002,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, * it will succeed here too */ wil_tx_desc_offload_cksum_set(wil, d, skb); - *_d = *d; } /* for the last seg only */ d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); -- GitLab From 8e901ec6a4095a7c31aa70b8434f30ce12c3290d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:13 +0200 Subject: [PATCH 168/528] wil6210: fix race between xmit and Tx vring de-allocation Use spinlock, this should not impact Tx as lock is always free except for de-allocation. Change-Id: I5bcd5074f1ceeecab5b6535e48e1ee3892ac91f0 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 5933a06dc96cad21b7c125995791c93a86be7915 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 784e9557e4cb496d3754357e42a693bc2221cb89) --- drivers/net/wireless/ath/wil6210/txrx.c | 25 +++++++++++++++++++--- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 16beaf965c0a..59ab72742289 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -671,6 +671,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, } memset(txdata, 0, sizeof(*txdata)); + spin_lock_init(&txdata->lock); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -718,8 +719,10 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) wil_dbg_misc(wil, "%s() id=%d\n", __func__, id); + spin_lock_bh(&txdata->lock); + txdata->enabled = 0; /* no Tx can be in progress or start anew */ + spin_unlock_bh(&txdata->lock); /* make sure NAPI won't touch this vring */ - wil->vring_tx_data[id].enabled = 0; if (test_bit(wil_status_napi_en, wil->status)) napi_synchronize(&wil->napi_tx); @@ -935,8 +938,8 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, return 0; } -static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, - struct sk_buff *skb) +static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) { struct device *dev = wil_to_dev(wil); struct vring_tx_desc dd, *d = ⅆ @@ -952,6 +955,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_dbg_txrx(wil, "%s()\n", __func__); + if (unlikely(!txdata->enabled)) + return -EINVAL; + if (avail < 1 + nr_frags) { wil_err_ratelimited(wil, "Tx ring full. No space for %d fragments\n", @@ -1050,6 +1056,19 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, return -EINVAL; } +static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) +{ + int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; + int rc; + + spin_lock(&txdata->lock); + rc = __wil_tx_vring(wil, vring, skb); + spin_unlock(&txdata->lock); + return rc; +} + netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 19e440ad645a..d29ece4cec8f 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -385,6 +385,7 @@ struct vring_tx_data { u16 agg_timeout; u8 agg_amsdu; bool addba_in_progress; /* if set, agg_xxx is for request in progress */ + spinlock_t lock; }; enum { /* for wil6210_priv.status */ -- GitLab From 6704b60e221d8661ed02719f1bc6dfeb11418499 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:14 +0200 Subject: [PATCH 169/528] wil6210: more Tx debug Print Tx descriptors Print ring index for all Tx related messages Sort prefixes: Tx for transmit, TxC for completion, added "D" for descriptor related prints Change-Id: I9a011b068c37785c8b2d2391a305c11e81bee3fb Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 5b29c573f3dcb22534489194ba97aeb495cc65ca Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 55d0ada2b55eaa256e4b287160276712ac945efb) --- drivers/net/wireless/ath/wil6210/txrx.c | 30 ++++++++++++++----------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 59ab72742289..5eaac2b8bff4 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -960,16 +960,16 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, if (avail < 1 + nr_frags) { wil_err_ratelimited(wil, - "Tx ring full. No space for %d fragments\n", - 1 + nr_frags); + "Tx ring[%2d] full. No space for %d fragments\n", + vring_index, 1 + nr_frags); return -ENOMEM; } _d = &vring->va[i].tx; pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb), - skb->data, &pa); + wil_dbg_txrx(wil, "Tx[%2d] skb %d bytes 0x%p -> %pad\n", vring_index, + skb_headlen(skb), skb->data, &pa); wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); @@ -980,7 +980,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); /* Process TCP/UDP checksum offloading */ if (wil_tx_desc_offload_cksum_set(wil, d, skb)) { - wil_err(wil, "VRING #%d Failed to set cksum, drop packet\n", + wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", vring_index); goto dma_error; } @@ -995,6 +995,9 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, int len = skb_frag_size(frag); *_d = *d; + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); i = (swhead + f + 1) % vring->size; _d = &vring->va[i].tx; pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), @@ -1014,6 +1017,9 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS); d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); *_d = *d; + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); /* hold reference to skb * to prevent skb release before accounting @@ -1021,15 +1027,13 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, */ vring->ctx[i].skb = skb_get(skb); - wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, - (const void *)d, sizeof(*d), false); - if (wil_vring_is_empty(vring)) /* performance monitoring */ txdata->idle += get_cycles() - txdata->last_idle; /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); - wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); + wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead, + vring->swhead); trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); @@ -1211,10 +1215,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) trace_wil6210_tx_done(ringid, vring->swtail, dmalen, d->dma.error); wil_dbg_txrx(wil, - "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", - vring->swtail, dmalen, d->dma.status, - d->dma.error); - wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, + "TxC[%2d][%3d] : %d bytes, status 0x%02x err 0x%02x\n", + ringid, vring->swtail, dmalen, + d->dma.status, d->dma.error); + wil_hex_dump_txrx("TxCD ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); wil_txdesc_unmap(dev, d, ctx); -- GitLab From 6221061b978e6209d19a44b36092e8b3700c6578 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:15 +0200 Subject: [PATCH 170/528] wil6210: print ciphers in debug info Print (at debug level) all cipher and AKM suites Change-Id: I5034b255123f480f3f4396262b933675fabb0eef Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: feeac225bed91c8da221e32a433780a5edcb14e8 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit f8302c79ed760b27054b543f670dc3f7c2a17e49) --- drivers/net/wireless/ath/wil6210/cfg80211.c | 37 ++++++++++++++------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 1d52e63e4865..5f083a2cf591 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -334,6 +334,30 @@ out: return rc; } +static void wil_print_crypto(struct wil6210_priv *wil, + struct cfg80211_crypto_settings *c) +{ + int i, n; + + wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", + c->wpa_versions, c->cipher_group); + wil_dbg_misc(wil, "Pairwise ciphers [%d] {\n", c->n_ciphers_pairwise); + n = min_t(int, c->n_ciphers_pairwise, ARRAY_SIZE(c->ciphers_pairwise)); + for (i = 0; i < n; i++) + wil_dbg_misc(wil, " [%d] = 0x%08x\n", i, + c->ciphers_pairwise[i]); + wil_dbg_misc(wil, "}\n"); + wil_dbg_misc(wil, "AKM suites [%d] {\n", c->n_akm_suites); + n = min_t(int, c->n_akm_suites, ARRAY_SIZE(c->akm_suites)); + for (i = 0; i < n; i++) + wil_dbg_misc(wil, " [%d] = 0x%08x\n", i, + c->akm_suites[i]); + wil_dbg_misc(wil, "}\n"); + wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", + c->control_port, be16_to_cpu(c->control_port_ethertype), + c->control_port_no_encrypt); +} + static void wil_print_connect_params(struct wil6210_priv *wil, struct cfg80211_connect_params *sme) { @@ -348,6 +372,7 @@ static void wil_print_connect_params(struct wil6210_priv *wil, print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET, 16, 1, sme->ssid, sme->ssid_len, true); wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open"); + wil_print_crypto(wil, &sme->crypto); } static int wil_cfg80211_connect(struct wiphy *wiphy, @@ -622,18 +647,6 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b) b->assocresp_ies, b->assocresp_ies_len); } -static void wil_print_crypto(struct wil6210_priv *wil, - struct cfg80211_crypto_settings *c) -{ - wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", - c->wpa_versions, c->cipher_group); - wil_dbg_misc(wil, "Pairwise ciphers [%d]\n", c->n_ciphers_pairwise); - wil_dbg_misc(wil, "AKM suites [%d]\n", c->n_akm_suites); - wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", - c->control_port, be16_to_cpu(c->control_port_ethertype), - c->control_port_no_encrypt); -} - static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { -- GitLab From 26181747962002fddacd88f0a5b14dd32a6c0e16 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Feb 2015 14:02:30 +0200 Subject: [PATCH 171/528] wil6210: boot loader Introduce boot loader. Instead of the operational firmware, very small boot loader is burned to the on-board flash. Boot loader initializes hardware upon reset, and prepares for low power mode. Boot loader reports MAC address and detects radio chip connected. Driver loads firmware only when bringing up interface. All information required to set up network interface, most important is MAC address, reported by the boot loader The firmware composed of 2 files: - wil6210.fw - firmware itself (compiled code + data) - wil6210.board - board file (various board and radio dependent calibrations and parameters) Change-Id: I7a7d5791fc044551a22c229aa5899440e19f4701 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 2cd0f021b847c4c366dcb064600d8e37944ad84f Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 10da6eca441a07cea66a9264bdce6360e7891068) --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- drivers/net/wireless/ath/wil6210/fw.c | 3 +- drivers/net/wireless/ath/wil6210/fw_inc.c | 4 +- drivers/net/wireless/ath/wil6210/main.c | 104 +++++++++++++------- drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 +- drivers/net/wireless/ath/wil6210/wil6210.h | 16 ++- drivers/net/wireless/ath/wil6210/wmi.c | 7 +- 7 files changed, 88 insertions(+), 50 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 218508d92bb4..1b6410e37e31 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -549,7 +549,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, dev_close(ndev); ndev->flags &= ~IFF_UP; rtnl_unlock(); - wil_reset(wil); + wil_reset(wil, true); return len; } diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c index 93c5cc16c515..4428345e5a47 100644 --- a/drivers/net/wireless/ath/wil6210/fw.c +++ b/drivers/net/wireless/ath/wil6210/fw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,7 @@ #include "fw.h" MODULE_FIRMWARE(WIL_FW_NAME); +MODULE_FIRMWARE(WIL_FW2_NAME); /* target operations */ /* register read */ diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 519887a0a513..69109f0d4764 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -469,8 +469,6 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size) } return -EINVAL; } - /* Mark FW as loaded from host */ - S(RGF_USER_USAGE_6, 1); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 86f06806f1df..2d5c1b2ba95a 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -29,10 +29,6 @@ bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery"); -static bool no_fw_load = true; -module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash."); - /* if not set via modparam, will be set to default value of 1/8 of * rx ring size during init flow */ @@ -532,6 +528,8 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_halt_cpu(wil); + /* clear all boot loader "ready" bits */ + W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0); /* Clear Fw Download notification */ C(RGF_USER_USAGE_6, BIT(0)); @@ -583,16 +581,16 @@ static int wil_target_reset(struct wil6210_priv *wil) /* TODO: check order here!!! Erez code is different */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - /* wait until device ready. typical time is 200..250 msec */ + /* wait until device ready. typical time is 20..80 msec */ do { msleep(RST_DELAY); - x = R(RGF_USER_HW_MACHINE_STATE); + x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready)); if (delay++ > RST_COUNT) { - wil_err(wil, "Reset not completed, hw_state 0x%08x\n", + wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", x); return -ETIME; } - } while (x != HW_MACHINE_BOOT_DONE); + } while (!(x & BIT_BL_READY)); if (!is_reset_v2) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); @@ -603,11 +601,6 @@ static int wil_target_reset(struct wil6210_priv *wil) return 0; } -#undef R -#undef W -#undef S -#undef C - void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) { le32_to_cpus(&r->base); @@ -617,6 +610,32 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) le32_to_cpus(&r->head); } +static int wil_get_bl_info(struct wil6210_priv *wil) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct RGF_BL bl; + + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl)); + le32_to_cpus(&bl.ready); + le32_to_cpus(&bl.version); + le32_to_cpus(&bl.rf_type); + le32_to_cpus(&bl.baseband_type); + + if (!is_valid_ether_addr(bl.mac_address)) { + wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address); + return -EINVAL; + } + + ether_addr_copy(ndev->perm_addr, bl.mac_address); + if (!is_valid_ether_addr(ndev->dev_addr)) + ether_addr_copy(ndev->dev_addr, bl.mac_address); + wil_info(wil, + "Boot Loader: ver = %d MAC = %pM RF = 0x%08x bband = 0x%08x\n", + bl.version, bl.mac_address, bl.rf_type, bl.baseband_type); + + return 0; +} + static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); @@ -637,7 +656,7 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) * After calling this routine, you're expected to reload * the firmware. */ -int wil_reset(struct wil6210_priv *wil) +int wil_reset(struct wil6210_priv *wil, bool load_fw) { int rc; @@ -675,30 +694,36 @@ int wil_reset(struct wil6210_priv *wil) if (rc) return rc; - if (!no_fw_load) { - wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME); + rc = wil_get_bl_info(wil); + if (rc) + return rc; + + if (load_fw) { + wil_info(wil, "Use firmware <%s> + board <%s>\n", WIL_FW_NAME, + WIL_FW2_NAME); + wil_halt_cpu(wil); /* Loading f/w from the file */ rc = wil_request_firmware(wil, WIL_FW_NAME); if (rc) return rc; + rc = wil_request_firmware(wil, WIL_FW2_NAME); + if (rc) + return rc; + + /* Mark FW as loaded from host */ + S(RGF_USER_USAGE_6, 1); - /* clear any interrupts which on-card-firmware may have set */ + /* clear any interrupts which on-card-firmware + * may have set + */ wil6210_clear_irq(wil); - { /* CAF_ICR - clear and mask */ - u32 a = HOSTADDR(RGF_CAF_ICR) + - offsetof(struct RGF_ICR, ICR); - u32 m = HOSTADDR(RGF_CAF_ICR) + - offsetof(struct RGF_ICR, IMV); - u32 icr = ioread32(wil->csr + a); - - iowrite32(icr, wil->csr + a); /* W1C */ - iowrite32(~0, wil->csr + m); - wmb(); /* wait for completion */ - } + /* CAF_ICR - clear and mask */ + /* it is W1C, clear by writing back same value */ + S(RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); + W(RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + wil_release_cpu(wil); - } else { - wil_info(wil, "Use firmware from on-card flash\n"); } /* init after reset */ @@ -706,15 +731,22 @@ int wil_reset(struct wil6210_priv *wil) INIT_COMPLETION(wil->wmi_ready); INIT_COMPLETION(wil->wmi_call); - wil_configure_interrupt_moderation(wil); - wil_unmask_irq(wil); + if (load_fw) { + wil_configure_interrupt_moderation(wil); + wil_unmask_irq(wil); - /* we just started MAC, wait for FW ready */ - rc = wil_wait_for_fw_ready(wil); + /* we just started MAC, wait for FW ready */ + rc = wil_wait_for_fw_ready(wil); + } return rc; } +#undef R +#undef W +#undef S +#undef C + void wil_fw_error_recovery(struct wil6210_priv *wil) { wil_dbg_misc(wil, "starting fw error recovery\n"); @@ -730,7 +762,7 @@ int __wil_up(struct wil6210_priv *wil) WARN_ON(!mutex_is_locked(&wil->mutex)); - rc = wil_reset(wil); + rc = wil_reset(wil, true); if (rc) return rc; @@ -837,7 +869,7 @@ int __wil_down(struct wil6210_priv *wil) if (!iter) wil_err(wil, "timeout waiting for idle FW/HW\n"); - wil_rx_fini(wil); + wil_reset(wil, false); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 465175435134..7444c1f652b6 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -152,7 +152,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) /* need reset here to obtain MAC */ mutex_lock(&wil->mutex); - rc = wil_reset(wil); + rc = wil_reset(wil, false); mutex_unlock(&wil->mutex); if (debug_fw) rc = 0; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index d29ece4cec8f..9967a3a3cf76 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -29,7 +29,8 @@ extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; #define WIL_NAME "wil6210" -#define WIL_FW_NAME "wil6210.fw" +#define WIL_FW_NAME "wil6210.fw" /* code */ +#define WIL_FW2_NAME "wil6210.board" /* board & radio parameters */ #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ @@ -120,6 +121,16 @@ struct RGF_ICR { u32 IMC; /* Mask Clear, write 1 to clear */ } __packed; +struct RGF_BL { + u32 ready; /* 0x880A3C bit [0] */ +#define BIT_BL_READY BIT(0) + u32 version; /* 0x880A40 version of the BL struct */ + u32 rf_type; /* 0x880A44 ID of the connected RF */ + u32 baseband_type; /* 0x880A48 ID of the baseband */ + u8 mac_address[ETH_ALEN]; /* 0x880A4C permanent MAC */ + u8 pad[2]; +} __packed; + /* registers - FW addresses */ #define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_USAGE_6 (0x880018) @@ -130,6 +141,7 @@ struct RGF_ICR { #define RGF_USER_MAC_CPU_0 (0x8801fc) #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */ #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) +#define RGF_USER_BL (0x880A3C) /* Boot Loader */ #define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ #define RGF_USER_CLKS_CTL_0 (0x880abc) #define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */ @@ -654,7 +666,7 @@ int wil_if_add(struct wil6210_priv *wil); void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); -int wil_reset(struct wil6210_priv *wil); +int wil_reset(struct wil6210_priv *wil, bool no_fw); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); int wil_up(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 9f0fac384093..a356754f4599 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -290,7 +290,6 @@ int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) /*=== Event handlers ===*/ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) { - struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; struct wmi_ready_event *evt = d; @@ -299,11 +298,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, evt->mac, wil->n_mids); - - if (!is_valid_ether_addr(ndev->dev_addr)) { - memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); - memcpy(ndev->perm_addr, evt->mac, ETH_ALEN); - } + /* ignore MAC address, we already have it from the boot loader */ snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version), "%d", wil->fw_version); } -- GitLab From 34b5c4217fe2725fbd2fec522bbe0c18da12f471 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Feb 2015 14:02:31 +0200 Subject: [PATCH 172/528] wil6210: remove support for old hardware Hardware older than Sparrow B0 obsolete. There is no WiFi product that uses this hardware. Recent firmware does not support it either. Remove driver support. Change-Id: Icdeb7c69be37fbf4b140c18eadac631afa17b8a8 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 9a5511b58b25aaf4cba61d9144229d2987a5135c Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit bb7452032eeddea86531b85029386cdf184173fe) --- drivers/net/wireless/ath/wil6210/ethtool.c | 34 +++++------- drivers/net/wireless/ath/wil6210/interrupt.c | 45 +++------------ drivers/net/wireless/ath/wil6210/main.c | 58 +++++++------------- drivers/net/wireless/ath/wil6210/pcie_bus.c | 20 ------- drivers/net/wireless/ath/wil6210/wil6210.h | 8 --- 5 files changed, 42 insertions(+), 123 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index 4c44a82c34d7..0ea695ff98ad 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -50,27 +50,19 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev, wil_dbg_misc(wil, "%s()\n", __func__); - if (test_bit(hw_capability_advanced_itr_moderation, - wil->hw_capabilities)) { - tx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); - if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) - tx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); - - rx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); - if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) - rx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); - } else { - rx_itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); - if (rx_itr_en & BIT_DMA_ITR_CNT_CRL_EN) - rx_itr_val = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); - } + tx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); + if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) + tx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); + + rx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); + if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) + rx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); cp->tx_coalesce_usecs = tx_itr_val; cp->rx_coalesce_usecs = rx_itr_val; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index a6f923086f31..d5a651bb800e 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -166,9 +166,16 @@ void wil_unmask_irq(struct wil6210_priv *wil) /* target write operation */ #define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -static -void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil) +void wil_configure_interrupt_moderation(struct wil6210_priv *wil) { + wil_dbg_irq(wil, "%s()\n", __func__); + + /* disable interrupt moderation for monitor + * to get better timestamp precision + */ + if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) + return; + /* Disable and clear tx counter before (re)configuration */ W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); @@ -206,42 +213,8 @@ void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil) BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); } -static -void wil_configure_interrupt_moderation_lgc(struct wil6210_priv *wil) -{ - /* disable, use usec resolution */ - W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_CLR); - - wil_info(wil, "set ITR_TRSH = %d usec\n", wil->rx_max_burst_duration); - W(RGF_DMA_ITR_CNT_TRSH, wil->rx_max_burst_duration); - /* start it */ - W(RGF_DMA_ITR_CNT_CRL, - BIT_DMA_ITR_CNT_CRL_EN | BIT_DMA_ITR_CNT_CRL_EXT_TICK); -} - #undef W -void wil_configure_interrupt_moderation(struct wil6210_priv *wil) -{ - wil_dbg_irq(wil, "%s()\n", __func__); - - /* disable interrupt moderation for monitor - * to get better timestamp precision - */ - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) - return; - - if (test_bit(hw_capability_advanced_itr_moderation, - wil->hw_capabilities)) - wil_configure_interrupt_moderation_new(wil); - else { - /* Advanced interrupt moderation is not available before - * Sparrow v2. Will use legacy interrupt moderation - */ - wil_configure_interrupt_moderation_lgc(wil); - } -} - static irqreturn_t wil6210_irq_rx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 2d5c1b2ba95a..14f217ef29bd 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -516,8 +516,6 @@ static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; u32 x; - bool is_reset_v2 = test_bit(hw_capability_reset_v2, - wil->hw_capabilities); wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); @@ -533,52 +531,39 @@ static int wil_target_reset(struct wil6210_priv *wil) /* Clear Fw Download notification */ C(RGF_USER_USAGE_6, BIT(0)); - if (is_reset_v2) { - S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); - /* XTAL stabilization should take about 3ms */ - usleep_range(5000, 7000); - x = R(RGF_CAF_PLL_LOCK_STATUS); - if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { - wil_err(wil, "Xtal stabilization timeout\n" - "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); - return -ETIME; - } - /* switch 10k to XTAL*/ - C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); - /* 40 MHz */ - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); - - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); + S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); + /* XTAL stabilization should take about 3ms */ + usleep_range(5000, 7000); + x = R(RGF_CAF_PLL_LOCK_STATUS); + if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { + wil_err(wil, "Xtal stabilization timeout\n" + "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); + return -ETIME; } + /* switch 10k to XTAL*/ + C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); + /* 40 MHz */ + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); + + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, - is_reset_v2 ? 0x000000f0 : 0x00000170); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); - if (is_reset_v2) { - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); - } + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - if (is_reset_v2) { - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); - /* reset A2 PCIE AHB */ - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } else { - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */ - /* TODO: check order here!!! Erez code is different */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); /* wait until device ready. typical time is 20..80 msec */ @@ -592,9 +577,6 @@ static int wil_target_reset(struct wil6210_priv *wil) } } while (!(x & BIT_BL_READY)); - if (!is_reset_v2) - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 7444c1f652b6..9bb1e5b47169 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -39,18 +39,6 @@ void wil_set_capabilities(struct wil6210_priv *wil) bitmap_zero(wil->hw_capabilities, hw_capability_last); switch (rev_id) { - case JTAG_DEV_ID_MARLON_B0: - wil->hw_name = "Marlon B0"; - wil->hw_version = HW_VER_MARLON_B0; - break; - case JTAG_DEV_ID_SPARROW_A0: - wil->hw_name = "Sparrow A0"; - wil->hw_version = HW_VER_SPARROW_A0; - break; - case JTAG_DEV_ID_SPARROW_A1: - wil->hw_name = "Sparrow A1"; - wil->hw_version = HW_VER_SPARROW_A1; - break; case JTAG_DEV_ID_SPARROW_B0: wil->hw_name = "Sparrow B0"; wil->hw_version = HW_VER_SPARROW_B0; @@ -62,13 +50,6 @@ void wil_set_capabilities(struct wil6210_priv *wil) } wil_info(wil, "Board hardware is %s\n", wil->hw_name); - - if (wil->hw_version >= HW_VER_SPARROW_A0) - set_bit(hw_capability_reset_v2, wil->hw_capabilities); - - if (wil->hw_version >= HW_VER_SPARROW_B0) - set_bit(hw_capability_advanced_itr_moderation, - wil->hw_capabilities); } void wil_disable_irq(struct wil6210_priv *wil) @@ -307,7 +288,6 @@ static void wil_pcie_remove(struct pci_dev *pdev) } static const struct pci_device_id wil6210_pcie_ids[] = { - { PCI_DEVICE(0x1ae9, 0x0301) }, { PCI_DEVICE(0x1ae9, 0x0310) }, { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ { /* end: all zeroes */ }, diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 9967a3a3cf76..59f8745f113f 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -241,16 +241,10 @@ struct RGF_BL { #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) #define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ - #define JTAG_DEV_ID_MARLON_B0 (0x0612072f) - #define JTAG_DEV_ID_SPARROW_A0 (0x0632072f) - #define JTAG_DEV_ID_SPARROW_A1 (0x1632072f) #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f) enum { HW_VER_UNKNOWN, - HW_VER_MARLON_B0, /* JTAG_DEV_ID_MARLON_B0 */ - HW_VER_SPARROW_A0, /* JTAG_DEV_ID_SPARROW_A0 */ - HW_VER_SPARROW_A1, /* JTAG_DEV_ID_SPARROW_A1 */ HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */ }; @@ -494,8 +488,6 @@ enum { }; enum { - hw_capability_reset_v2 = 0, - hw_capability_advanced_itr_moderation = 1, hw_capability_last }; -- GitLab From 35fccc44736a0a3e0459abb3eb424a8735afaecc Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Feb 2015 14:02:32 +0200 Subject: [PATCH 173/528] wil6210: enable fix for HW bug in 802.11->803.3 transform In the old hardware, bug existed that caused DA and SA for every Rx packet to be swapped in the AP mode. New hardware has fix for this bug. Enable this fix in the hardware. Change-Id: Ic2894f54430a1f5e5085a23890e44f1c08ca5229 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: e3351277ac585df77ac2454c518205897c01a184 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit a016b1cc10603ebcf9d44a787c69b1e282ef76b7) --- drivers/net/wireless/ath/wil6210/main.c | 4 +++ drivers/net/wireless/ath/wil6210/txrx.c | 31 ---------------------- drivers/net/wireless/ath/wil6210/wil6210.h | 7 +++++ 3 files changed, 11 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 14f217ef29bd..ddcc291d0ff7 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -579,6 +579,10 @@ static int wil_target_reset(struct wil6210_priv *wil) C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + /* enable fix for HW bug related to the SA/DA swap in AP Rx */ + S(RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | + BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 5eaac2b8bff4..33fb06bb6478 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -346,27 +346,6 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, } } -/* - * Fast swap in place between 2 registers - */ -static void wil_swap_u16(u16 *a, u16 *b) -{ - *a ^= *b; - *b ^= *a; - *a ^= *b; -} - -static void wil_swap_ethaddr(void *data) -{ - struct ethhdr *eth = data; - u16 *s = (u16 *)eth->h_source; - u16 *d = (u16 *)eth->h_dest; - - wil_swap_u16(s++, d++); - wil_swap_u16(s++, d++); - wil_swap_u16(s, d); -} - /** * reap 1 frame from @swhead * @@ -386,7 +365,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, unsigned int sz = mtu_max + ETH_HLEN; u16 dmalen; u8 ftype; - u8 ds_bits; int cid; struct wil_net_stats *stats; @@ -474,15 +452,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, */ } - ds_bits = wil_rxdesc_ds_bits(d); - if (ds_bits == 1) { - /* - * HW bug - in ToDS mode, i.e. Rx on AP side, - * addresses get swapped - */ - wil_swap_ethaddr(skb->data); - } - return skb; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 59f8745f113f..6f1b58e4bf24 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -181,6 +181,13 @@ struct RGF_BL { #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) +/* Offload control (Sparrow B0+) */ +#define RGF_DMA_OFUL_NID_0 (0x881cd4) + #define BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN BIT(0) + #define BIT_DMA_OFUL_NID_0_TX_EXT_TR_EN BIT(1) + #define BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC BIT(2) + #define BIT_DMA_OFUL_NID_0_TX_EXT_A3_SRC BIT(3) + /* New (sparrow v2+) interrupt moderation control */ #define RGF_DMA_ITR_TX_DESQ_NO_MOD (0x881d40) #define RGF_DMA_ITR_TX_CNT_TRSH (0x881d34) -- GitLab From 2eaffdb949709860a480a09efb35ffd6e5b88f1b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Feb 2015 14:02:33 +0200 Subject: [PATCH 174/528] wil6210: branch prediction hints Mark expected branches using likely()/unlikely(). Do it on high performance route - data path and interrupts Change-Id: Iff50ac593ad650cde99a9bf4a373dc3fdfa4370b Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 33c477fdab257efcad139ac2a5031708aad2a1e7 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 2033e1f296406a2aaea132310e92ebaf61f86fdc) --- drivers/net/wireless/ath/wil6210/interrupt.c | 25 ++++++------ drivers/net/wireless/ath/wil6210/txrx.c | 40 ++++++++++---------- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index d5a651bb800e..28ffc18466c4 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -226,7 +226,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) trace_wil6210_irq_rx(isr); wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); - if (!isr) { + if (unlikely(!isr)) { wil_err(wil, "spurious IRQ: RX\n"); return IRQ_NONE; } @@ -239,17 +239,18 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) * action is always the same - should empty the accumulated * packets from the RX ring. */ - if (isr & (BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH)) { + if (likely(isr & (BIT_DMA_EP_RX_ICR_RX_DONE | + BIT_DMA_EP_RX_ICR_RX_HTRSH))) { wil_dbg_irq(wil, "RX done\n"); - if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH) + if (unlikely(isr & BIT_DMA_EP_RX_ICR_RX_HTRSH)) wil_err_ratelimited(wil, "Received \"Rx buffer is in risk of overflow\" interrupt\n"); isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH); - if (test_bit(wil_status_reset_done, wil->status)) { - if (test_bit(wil_status_napi_en, wil->status)) { + if (likely(test_bit(wil_status_reset_done, wil->status))) { + if (likely(test_bit(wil_status_napi_en, wil->status))) { wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_rx); @@ -262,7 +263,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) } } - if (isr) + if (unlikely(isr)) wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); /* Rx IRQ will be enabled when NAPI processing finished */ @@ -286,19 +287,19 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) trace_wil6210_irq_tx(isr); wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); - if (!isr) { + if (unlikely(!isr)) { wil_err(wil, "spurious IRQ: TX\n"); return IRQ_NONE; } wil6210_mask_irq_tx(wil); - if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { + if (likely(isr & BIT_DMA_EP_TX_ICR_TX_DONE)) { wil_dbg_irq(wil, "TX done\n"); isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; /* clear also all VRING interrupts */ isr &= ~(BIT(25) - 1UL); - if (test_bit(wil_status_reset_done, wil->status)) { + if (likely(test_bit(wil_status_reset_done, wil->status))) { wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_tx); @@ -307,7 +308,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) } } - if (isr) + if (unlikely(isr)) wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); /* Tx IRQ will be enabled when NAPI processing finished */ @@ -496,11 +497,11 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) /** * pseudo_cause is Clear-On-Read, no need to ACK */ - if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)) + if (unlikely((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff))) return IRQ_NONE; /* FIXME: IRQ mask debug */ - if (wil6210_debug_irq_mask(wil, pseudo_cause)) + if (unlikely(wil6210_debug_irq_mask(wil, pseudo_cause))) return IRQ_NONE; trace_wil6210_irq_pseudo(pseudo_cause); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 33fb06bb6478..2ad21a887ce0 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -370,11 +370,11 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); - if (wil_vring_is_empty(vring)) + if (unlikely(wil_vring_is_empty(vring))) return NULL; _d = &vring->va[vring->swhead].rx; - if (!(_d->dma.status & RX_DMA_STATUS_DU)) { + if (unlikely(!(_d->dma.status & RX_DMA_STATUS_DU))) { /* it is not error, we just reached end of Rx done area */ return NULL; } @@ -394,7 +394,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); - if (dmalen > sz) { + if (unlikely(dmalen > sz)) { wil_err(wil, "Rx size too large: %d bytes!\n", dmalen); kfree_skb(skb); return NULL; @@ -423,14 +423,14 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, * in Rx descriptor. If type is not data, it is 802.11 frame as is */ ftype = wil_rxdesc_ftype(d) << 2; - if (ftype != IEEE80211_FTYPE_DATA) { + if (unlikely(ftype != IEEE80211_FTYPE_DATA)) { wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); /* TODO: process it */ kfree_skb(skb); return NULL; } - if (skb->len < ETH_HLEN) { + if (unlikely(skb->len < ETH_HLEN)) { wil_err(wil, "Short frame, len = %d\n", skb->len); /* TODO: process it (i.e. BAR) */ kfree_skb(skb); @@ -441,9 +441,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, * and in case of error drop the packet * higher stack layers will handle retransmission (if required) */ - if (d->dma.status & RX_DMA_STATUS_L4I) { + if (likely(d->dma.status & RX_DMA_STATUS_L4I)) { /* L4 protocol identified, csum calculated */ - if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0) + if (likely((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0)) skb->ip_summed = CHECKSUM_UNNECESSARY; /* If HW reports bad checksum, let IP stack re-check it * For example, HW don't understand Microsoft IP stack that @@ -472,7 +472,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) (next_tail != v->swhead) && (count-- > 0); v->swtail = next_tail) { rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom); - if (rc) { + if (unlikely(rc)) { wil_err(wil, "Error %d in wil_rx_refill[%d]\n", rc, v->swtail); break; @@ -534,7 +534,7 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) struct vring *v = &wil->vring_rx; struct sk_buff *skb; - if (!v->va) { + if (unlikely(!v->va)) { wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); return; } @@ -927,7 +927,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, if (unlikely(!txdata->enabled)) return -EINVAL; - if (avail < 1 + nr_frags) { + if (unlikely(avail < 1 + nr_frags)) { wil_err_ratelimited(wil, "Tx ring[%2d] full. No space for %d fragments\n", vring_index, 1 + nr_frags); @@ -948,7 +948,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, /* 1-st segment */ wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); /* Process TCP/UDP checksum offloading */ - if (wil_tx_desc_offload_cksum_set(wil, d, skb)) { + if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) { wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", vring_index); goto dma_error; @@ -1051,18 +1051,18 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) int rc; wil_dbg_txrx(wil, "%s()\n", __func__); - if (!test_bit(wil_status_fwready, wil->status)) { + if (unlikely(!test_bit(wil_status_fwready, wil->status))) { if (!pr_once_fw) { wil_err(wil, "FW not ready\n"); pr_once_fw = true; } goto drop; } - if (!test_bit(wil_status_fwconnected, wil->status)) { + if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) { wil_err(wil, "FW not connected\n"); goto drop; } - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { + if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) { wil_err(wil, "Xmit in monitor mode not supported\n"); goto drop; } @@ -1078,7 +1078,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) else vring = wil_tx_bcast(wil, skb); } - if (!vring) { + if (unlikely(!vring)) { wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } @@ -1086,7 +1086,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) rc = wil_tx_vring(wil, vring, skb); /* do we still have enough room in the vring? */ - if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) { + if (unlikely(wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring))) { netif_tx_stop_all_queues(wil_to_ndev(wil)); wil_dbg_txrx(wil, "netif_tx_stop : ring full\n"); } @@ -1142,12 +1142,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) struct wil_net_stats *stats = &wil->sta[cid].stats; volatile struct vring_tx_desc *_d; - if (!vring->va) { + if (unlikely(!vring->va)) { wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); return 0; } - if (!txdata->enabled) { + if (unlikely(!txdata->enabled)) { wil_info(wil, "Tx irq[%d]: vring disabled\n", ringid); return 0; } @@ -1165,7 +1165,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) /* TODO: check we are not past head */ _d = &vring->va[lf].tx; - if (!(_d->dma.status & TX_DMA_STATUS_DU)) + if (unlikely(!(_d->dma.status & TX_DMA_STATUS_DU))) break; new_swtail = (lf + 1) % vring->size; @@ -1193,7 +1193,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) wil_txdesc_unmap(dev, d, ctx); if (skb) { - if (d->dma.error == 0) { + if (likely(d->dma.error == 0)) { ndev->stats.tx_packets++; stats->tx_packets++; ndev->stats.tx_bytes += skb->len; -- GitLab From 65fc4d0d29e6bf0fdf0a8abeb7a966d2ffe892ba Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Sun, 15 Feb 2015 14:02:34 +0200 Subject: [PATCH 175/528] wil6210: Change of threshold for tx vring idleness measurement Change threshold to be variable debugfs entry from hard-coded 0. Default threshold value is 16 descriptors because HW is capable of fetching up to 16 descriptors at once. Change-Id: I429eac71885a1cab2c5a44f4e68bca4c348ad497 Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 0436fd9a2d1e0c87a621841ab48e779cf8f237b4 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 19bd1f37cb318beec8055de9e5489136fe88947c) --- drivers/net/wireless/ath/wil6210/debugfs.c | 3 ++ drivers/net/wireless/ath/wil6210/txrx.c | 52 +++++++++++++++------- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 1b6410e37e31..e404d17f0822 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -29,6 +29,7 @@ static u32 mem_addr; static u32 dbg_txdesc_index; static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ +u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */ enum dbg_off_type { doff_u32 = 0, @@ -1412,6 +1413,8 @@ static const struct dbg_off dbg_statics[] = { {"desc_index", S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32}, {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32}, {"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32}, + {"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh, + doff_u32}, {}, }; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 2ad21a887ce0..1f7da54b8bba 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -53,34 +53,38 @@ static inline int wil_vring_is_full(struct vring *vring) return wil_vring_next_tail(vring) == vring->swhead; } -/* - * Available space in Tx Vring - */ -static inline int wil_vring_avail_tx(struct vring *vring) +/* Used space in Tx Vring */ +static inline int wil_vring_used_tx(struct vring *vring) { u32 swhead = vring->swhead; u32 swtail = vring->swtail; - int used = (vring->size + swhead - swtail) % vring->size; + return (vring->size + swhead - swtail) % vring->size; +} - return vring->size - used - 1; +/* Available space in Tx Vring */ +static inline int wil_vring_avail_tx(struct vring *vring) +{ + return vring->size - wil_vring_used_tx(vring) - 1; } -/** - * wil_vring_wmark_low - low watermark for available descriptor space - */ +/* wil_vring_wmark_low - low watermark for available descriptor space */ static inline int wil_vring_wmark_low(struct vring *vring) { return vring->size/8; } -/** - * wil_vring_wmark_high - high watermark for available descriptor space - */ +/* wil_vring_wmark_high - high watermark for available descriptor space */ static inline int wil_vring_wmark_high(struct vring *vring) { return vring->size/4; } +/* wil_val_in_range - check if value in [min,max) */ +static inline bool wil_val_in_range(int val, int min, int max) +{ + return val >= min && val < max; +} + static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) { struct device *dev = wil_to_dev(wil); @@ -98,8 +102,7 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) vring->va = NULL; return -ENOMEM; } - /* - * vring->va should be aligned on its size rounded up to power of 2 + /* vring->va should be aligned on its size rounded up to power of 2 * This is granted by the dma_alloc_coherent */ vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL); @@ -921,6 +924,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; uint i = swhead; dma_addr_t pa; + int used; wil_dbg_txrx(wil, "%s()\n", __func__); @@ -996,8 +1000,14 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, */ vring->ctx[i].skb = skb_get(skb); - if (wil_vring_is_empty(vring)) /* performance monitoring */ + /* performance monitoring */ + used = wil_vring_used_tx(vring); + if (wil_val_in_range(vring_idle_trsh, + used, used + nr_frags + 1)) { txdata->idle += get_cycles() - txdata->last_idle; + wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n", + vring_index, used, used + nr_frags + 1); + } /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); @@ -1141,6 +1151,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) int cid = wil->vring2cid_tid[ringid][0]; struct wil_net_stats *stats = &wil->sta[cid].stats; volatile struct vring_tx_desc *_d; + int used_before_complete; + int used_new; if (unlikely(!vring->va)) { wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); @@ -1154,6 +1166,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); + used_before_complete = wil_vring_used_tx(vring); + while (!wil_vring_is_empty(vring)) { int new_swtail; struct wil_ctx *ctx = &vring->ctx[vring->swtail]; @@ -1215,8 +1229,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) } } - if (wil_vring_is_empty(vring)) { /* performance monitoring */ - wil_dbg_txrx(wil, "Ring[%2d] empty\n", ringid); + /* performance monitoring */ + used_new = wil_vring_used_tx(vring); + if (wil_val_in_range(vring_idle_trsh, + used_new, used_before_complete)) { + wil_dbg_txrx(wil, "Ring[%2d] idle %d -> %d\n", + ringid, used_before_complete, used_new); txdata->last_idle = get_cycles(); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 6f1b58e4bf24..842cf660a853 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -27,6 +27,7 @@ extern bool no_fw_recovery; extern unsigned int mtu_max; extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; +extern u32 vring_idle_trsh; #define WIL_NAME "wil6210" #define WIL_FW_NAME "wil6210.fw" /* code */ -- GitLab From 31d1cb9bba62415629c356cccb6a3b4b6e8f409b Mon Sep 17 00:00:00 2001 From: Boris Sorochkin Date: Sun, 15 Feb 2015 14:02:35 +0200 Subject: [PATCH 176/528] wil6210: Fix division by zero in wil_vring_debugfs_show On some platforms get_cycles() implemented to allways return 0. On such platforms "Division by zero" bug was triggered. Change-Id: I4c0b1c86c2a822506cc6a58ee62e820f47629a17 Signed-off-by: Boris Sorochkin Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 8f55cbec7f8856438eef80e23f26331bea124128 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 3b3bd05e1e98ebecfc8a795014335012a1169594) --- drivers/net/wireless/ath/wil6210/debugfs.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index e404d17f0822..f5b7e2599110 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -103,23 +103,30 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) % vring->size; int avail = vring->size - used - 1; char name[10]; + char sidle[10]; /* performance monitoring */ cycles_t now = get_cycles(); uint64_t idle = txdata->idle * 100; uint64_t total = now - txdata->begin; - do_div(idle, total); + if (total != 0) { + do_div(idle, total); + snprintf(sidle, sizeof(sidle), "%3d%%", + (int)idle); + } else { + snprintf(sidle, sizeof(sidle), "N/A"); + } txdata->begin = now; txdata->idle = 0ULL; snprintf(name, sizeof(name), "tx_%2d", i); seq_printf(s, - "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %3d%%\n", - wil->sta[cid].addr, cid, tid, - txdata->agg_wsize, txdata->agg_timeout, - txdata->agg_amsdu ? "+" : "-", - used, avail, (int)idle); + "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n", + wil->sta[cid].addr, cid, tid, + txdata->agg_wsize, txdata->agg_timeout, + txdata->agg_amsdu ? "+" : "-", + used, avail, sidle); wil_print_vring(s, wil, name, vring, '_', 'H'); } -- GitLab From db4ff5db8ea6759365f6447daec0c730189ad685 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Feb 2015 14:02:36 +0200 Subject: [PATCH 177/528] wil6210: rename 'secure_pcp' to 'privacy' Make this field to track privacy attribute for all interface types Change-Id: Ib69def4a32cc02f54ff4a4cd113250fd4500cbf2 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 774974e50432c8d7210c337152afb4d646344d8a Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit be180b8d6e9955725c3c7a648ed0eec74ea06f1e) --- drivers/net/wireless/ath/wil6210/cfg80211.c | 2 +- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- drivers/net/wireless/ath/wil6210/wil6210.h | 2 +- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 5f083a2cf591..1d4e029ab7ef 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -772,7 +772,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, bcon->assocresp_ies); - wil->secure_pcp = info->privacy; + wil->privacy = info->privacy; netif_carrier_on(ndev); diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index f5b7e2599110..bc755c4b59d6 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1400,7 +1400,7 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, /* fields in struct wil6210_priv */ static const struct dbg_off dbg_wil_off[] = { - WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32), + WIL_FIELD(privacy, S_IRUGO, doff_u32), WIL_FIELD(status[0], S_IRUGO | S_IWUSR, doff_ulong), WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 842cf660a853..efbf8fb85652 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -540,7 +540,7 @@ struct wil6210_priv { wait_queue_head_t wq; /* for all wait_event() use */ /* profile */ u32 monitor_flags; - u32 secure_pcp; /* create secure PCP? */ + u32 privacy; /* secure connection? */ int sinfo_gen; /* interrupt moderation */ u32 tx_max_burst_duration; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index a356754f4599..c6574f22a3cf 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -884,7 +884,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) struct wmi_pcp_started_event evt; } __packed reply; - if (!wil->secure_pcp) + if (!wil->privacy) cmd.disable_sec = 1; if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) || -- GitLab From 9323827a3877e8798e157ee77b3ec88d822f9295 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Feb 2015 14:02:37 +0200 Subject: [PATCH 178/528] wil6210: track privacy connection attribute For the STA interface, track 'privacy'. Refactor safety checks to: - always print connection params - always check IE size validity - require RSN IE for secure connection Change-Id: I3a0de85509279c621f48372ed45781f8b5b4843f Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo Git-commit: 344a7024e01fc45a5ff52b171596f702815bd6eb Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git Signed-off-by: Hamad Kadmany (cherry picked from commit 4e5c89aaab77f749c3e96936e05173856e375ac3) --- drivers/net/wireless/ath/wil6210/cfg80211.c | 30 ++++++++++++--------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 1d4e029ab7ef..390d088ebdae 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -387,11 +387,25 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; + wil_print_connect_params(wil, sme); + if (test_bit(wil_status_fwconnecting, wil->status) || test_bit(wil_status_fwconnected, wil->status)) return -EALREADY; - wil_print_connect_params(wil, sme); + if (sme->ie_len > WMI_MAX_IE_LEN) { + wil_err(wil, "IE too large (%td bytes)\n", sme->ie_len); + return -ERANGE; + } + + rsn_eid = sme->ie ? + cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : + NULL; + + if (sme->privacy && !rsn_eid) { + wil_err(wil, "Missing RSN IE for secure connection\n"); + return -EINVAL; + } bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, @@ -407,17 +421,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rc = -ENOENT; goto out; } + wil->privacy = sme->privacy; - rsn_eid = sme->ie ? - cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : - NULL; - if (rsn_eid) { - if (sme->ie_len > WMI_MAX_IE_LEN) { - rc = -ERANGE; - wil_err(wil, "IE too large (%td bytes)\n", - sme->ie_len); - goto out; - } + if (wil->privacy) { /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */ rc = wmi_del_cipher_key(wil, 0, bss->bssid); if (rc) { @@ -450,7 +456,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, bss->capability); goto out; } - if (rsn_eid) { + if (wil->privacy) { conn.dot11_auth_mode = WMI_AUTH11_SHARED; conn.auth_mode = WMI_AUTH_WPA2_PSK; conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP; -- GitLab From ec4f876a1b914aef2ea35fabff9406993e37137d Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 29 May 2018 22:14:27 +0300 Subject: [PATCH 179/528] bcmdhd_suzuran: Makefile: return to the original kitakami configuration (cherry picked from commit da0bc7e415bdc4ea4cc9fb6ca657c1477042de53) --- drivers/net/wireless/bcmdhd_suzuran/Makefile | 70 ++++++-------------- 1 file changed, 19 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile b/drivers/net/wireless/bcmdhd_suzuran/Makefile index 58940b8b5710..c1d46590e9a8 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile +++ b/drivers/net/wireless/bcmdhd_suzuran/Makefile @@ -133,11 +133,11 @@ DHDCFLAGS += -DDISABLE_BCN_DLY #ABSOLUTE_BCM_SRC_DIR := $(WLAN_ROOT)/bcmdhd_suzuran BCM_SRC_DIR := ./ -############################### -# Android M -############################### +########### +# Lollipop +########### DHDCFLAGS += -DWL_ENABLE_P2P_IF - +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES # Default definitions for KitKat DHDCFLAGS += -DWL_CFG80211_STA_EVENT DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS @@ -165,42 +165,34 @@ endif ifneq ($(CONFIG_BCM43455),) # To support RTT -DHDCFLAGS += -DRTT_SUPPORT +#DHDCFLAGS += -DRTT_SUPPORT # To support GSCAN DHDCFLAGS += -DGSCAN_SUPPORT -# To support ePNO -DHDCFLAGS += -DEPNO_SUPPORT # To support Link Statictics DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support Rssi Monitor -DHDCFLAGS += -DRSSI_MONITOR_SUPPORT # To support WL_VENDOR_EXT_SUPPORT DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT -# To support ANQPO - GSCAN must be supported -DHDCFLAGS += -DANQPO_SUPPORT -# Extra file list for Android M, SOMC -ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o bcmxtlv.o +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o endif ifneq ($(CONFIG_BCM4354),) # To support RTT -#DHDCFLAGS += -DRTT_SUPPORT +DHDCFLAGS += -DRTT_SUPPORT # To support Link Statictics DHDCFLAGS += -DLINKSTAT_SUPPORT # To support GSCAN -DHDCFLAGS += -DGSCAN_SUPPORT +#DHDCFLAGS += -DGSCAN_SUPPORT # To support WL_VENDOR_EXT_SUPPORT DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT -# Extra file list for Android M -ANDROID_OFILES := wl_cfgvendor.o +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o endif - - ######################### # Chip dependent feature ######################### @@ -348,7 +340,7 @@ endif # Radio_stat v2 - data structure is updated DHDCFLAGS += -DLINKSTAT_V2 - DHDCFLAGS += -DWL_ABORT_SCAN +# DHDCFLAGS += -DWL_ABORT_SCAN endif # Read custom mac address function @@ -395,37 +387,13 @@ KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) MODNAME := bcmdhd -DHDOFILES := bcmsdh.o \ - bcmsdh_linux.o \ - bcmsdh_sdmmc.o \ - bcmsdh_sdmmc_linux.o \ - dhd_cdc.o \ - dhd_cfg80211.o \ - dhd_common.o \ - dhd_custom_gpio.o \ - dhd_ip.o \ - dhd_linux.o \ - dhd_linux_sched.o \ - dhd_sdio.o \ - dhd_pno.o \ - dhd_wlfc.o \ - dhd_linux_wq.o \ - aiutils.o \ - bcmevent.o \ - bcmutils.o \ - bcmwifi_channels.o \ - hndpmu.o \ - linux_osl.o \ - sbutils.o \ - siutils.o \ - wldev_common.o \ - wl_cfg_btcoex.o \ - wl_android.o \ - wl_cfg80211.o \ - wl_cfgp2p.o \ - wl_linux_mon.o \ - dhd_linux_platdev.o \ - dhd_somc_custom.o +DHDOFILES := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o \ + dhd_linux_wq.o aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o \ + hndpmu.o linux_osl.o sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o \ + dhd_somc_custom.o DHDOFILES += $(ANDROID_OFILES) -- GitLab From a62f03d0a4666eb5f1a849c6d1f40ff94fd44879 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 29 May 2018 22:17:41 +0300 Subject: [PATCH 180/528] bcmdhd_suzuran: add Makefile for Nougat (cherry picked from commit e79062b971441d5a8608f99e38ebbb1e79b5aa23) --- .../wireless/bcmdhd_suzuran/Makefile.Nougat | 415 ++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 drivers/net/wireless/bcmdhd_suzuran/Makefile.Nougat diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile.Nougat b/drivers/net/wireless/bcmdhd_suzuran/Makefile.Nougat new file mode 100644 index 000000000000..7999faaca146 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_suzuran/Makefile.Nougat @@ -0,0 +1,415 @@ +# bcmdhd + +##################### +# SDIO Basic feature +##################### +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ + -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ + -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ + -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ + -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ + -DCONFIG_DTS + +#################### +# Common feature +#################### +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 +# For Kernel ver > 3.6 or Kernel Patch required +DHDCFLAGS += -DWL_SUPPORT_CHAN_BW + +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# DPC priority +#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# idle count +DHDCFLAGS += -DDHD_USE_IDLECOUNT + +# custom specific value define +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# set keep alive period +ifneq ($(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING),) +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=$(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING) +else +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 +endif +# set roam setting values +DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 +DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +# SKB TAILPAD to avoid out of boundary memory access +DHDCFLAGS += -DDHDENABLE_TAILPAD + +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS + +DHDCFLAGS += -DSUPPORT_P2P_GO_PS + +# Disable TXBF sending +DHDCFLAGS += -DDISABLE_TXBFR + +DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + +# Disable to delay link down event +DHDCFLAGS += -DDISABLE_BCN_DLY + +############################## +# Android Platform Definition +############################## +#ABSOLUTE_BCM_SRC_DIR := $(WLAN_ROOT)/bcmdhd_suzuran +BCM_SRC_DIR := ./ + +############################### +# Android M +############################### +DHDCFLAGS += -DWL_ENABLE_P2P_IF + +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS +# To support p2p private command on kernel 3.8 or above +DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT + +ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD +endif + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +ifneq ($(CONFIG_BCM4339),) +# To support GSCAN +#DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o +endif + +ifneq ($(CONFIG_BCM43455),) +# To support RTT +DHDCFLAGS += -DRTT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT +# To support ePNO +DHDCFLAGS += -DEPNO_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support Rssi Monitor +DHDCFLAGS += -DRSSI_MONITOR_SUPPORT +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT +# To support ANQPO - GSCAN must be supported +DHDCFLAGS += -DANQPO_SUPPORT + +# Extra file list for Android M, SOMC +ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o bcmxtlv.o +endif + +ifneq ($(CONFIG_BCM4354),) +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Android M +ANDROID_OFILES := wl_cfgvendor.o +endif + + +######################### +# Chip dependent feature +######################### +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DSDIO_CRC_ERROR_FIX + +# tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DREPEAT_READFRAME + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +# DRIVER_TYPE = y +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # for 4339 only currently - need test for 4354, 43455 + DHDCFLAGS += -DDHD_LOSSLESS_ROAMING + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM43455),) + DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM43455),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + + # Radio_stat v2 - data structure is updated + DHDCFLAGS += -DLINKSTAT_V2 + + DHDCFLAGS += -DWL_ABORT_SCAN +endif + +# Read custom mac address function +DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE + +# Default Beacon timeout +ifneq ($(CONFIG_SOMC_WLAN_BCN_TIMEOUT),) + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=$(CONFIG_SOMC_WLAN_BCN_TIMEOUT) +else + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=3 +endif + +# The number of the maximum devices which phone can associate +DHDCFLAGS += -DSOMC_MAX_ASSOC_NUM=10 + +# Default Listen Interval in Beacons +ifneq ($(CONFIG_SOMC_WLAN_LISTEN_INTERVAL),) + DHDCFLAGS += -DCUSTOM_LISTEN_INTERVAL=$(CONFIG_SOMC_WLAN_LISTEN_INTERVAL) +endif + +# WAPI +DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI + +# Set the number of probe requests per channel +ifneq ($(CONFIG_SOMC_WLAN_SCAN_NPROBES),) + DHDCFLAGS += -DSOMC_WLAN_SCAN_NPROBES=$(CONFIG_SOMC_WLAN_SCAN_NPROBES) +endif + +# Set default nvram path +ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) + DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" +endif + +# Change scan time +ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) + DHDCFLAGS += -DCHANGE_SCAN_TIME +endif + +# Get country code +#DHDCFLAGS += -DCUSTOM_FORCE_NODFS_FLAG + +# Enable to use Ukraine CODE (UA/999) +DHDCFLAGS += -DENABLE_80211AC_FOR_UA + +#EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +MODNAME := wlan + +DHDOFILES := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o \ + dhd_linux_wq.o aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o \ + hndpmu.o linux_osl.o sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o \ + dhd_somc_custom.o + +DHDOFILES += $(ANDROID_OFILES) + +# Module information used by KBuild framework +obj-$(CONFIG_BCMDHD_SUZURAN) += $(MODNAME).o + +$(MODNAME)-objs := $(DHDOFILES) -- GitLab From 6963b4e62c9584d861cfa0af4e95530a2fee9c8e Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 29 May 2018 21:47:39 +0300 Subject: [PATCH 181/528] net: wireless: bcmdhd_suzuran: Revert "fix integer overflow in wl_get_assoc_ies" This reverts commit 07ea1e5e4509c4dcd4404b4fe8026e2c633cbc76. This fix is present in 1.141.67.33. (cherry picked from commit 626f5a65bdfd80fe943e679d836575004624b39c) --- .../net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 76 +++++++------------ .../net/wireless/bcmdhd_suzuran/wl_cfg80211.h | 6 +- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c index e4e1fc8cde2d..dd5fb0275d80 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c @@ -8526,32 +8526,6 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); - - if (assoc_info.req_len > - (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + - ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? - ETHER_ADDR_LEN : 0))) { - err = BCME_BADLEN; - goto exit; - } - if ((assoc_info.req_len > 0) && - (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + - ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? - ETHER_ADDR_LEN : 0)))) { - err = BCME_BADLEN; - goto exit; - } - if (assoc_info.resp_len > - (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { - err = BCME_BADLEN; - goto exit; - } - if ((assoc_info.resp_len > 0) && - (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { - err = BCME_BADLEN; - goto exit; - } - if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -8560,42 +8534,48 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) conn_info->resp_ie_len = 0; bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); } - if (assoc_info.req_len) { - err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, - cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - goto exit; + return err; } - conn_info->req_ie_len = assoc_info.req_len - - sizeof(struct dot11_assoc_req); + conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - memcpy(conn_info->req_ie, cfg->extra_buf, - conn_info->req_ie_len); + if (conn_info->req_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); + else { + WL_ERR(("IE size %d above max %d size \n", + conn_info->req_ie_len, MAX_REQ_LINE)); + return err; + } + } else { + conn_info->req_ie_len = 0; } - if (assoc_info.resp_len) { - err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, - cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - goto exit; + return err; + } + conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); + if (conn_info->resp_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); + else { + WL_ERR(("IE size %d above max %d size \n", + conn_info->resp_ie_len, MAX_REQ_LINE)); + return err; } - conn_info->resp_ie_len = - assoc_info.resp_len - sizeof(struct dot11_assoc_resp); - memcpy(conn_info->resp_ie, cfg->extra_buf, - conn_info->resp_ie_len); + } else { + conn_info->resp_ie_len = 0; } + WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, + conn_info->resp_ie_len)); -exit: - if (err) { - WL_ERR(("err:%d assoc-req:%u,resp:%u conn-req:%u,resp:%u\n", - err, assoc_info.req_len, assoc_info.resp_len, - conn_info->req_ie_len, conn_info->resp_ie_len)); - } return err; } diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h index d62792b0d2e5..069eda344e49 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h @@ -364,12 +364,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024u +#define MAX_REQ_LINE 1024 struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - u32 req_ie_len; + s32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - u32 resp_ie_len; + s32 resp_ie_len; }; /* firmware /nvram downloading controller */ -- GitLab From bdc7eeb3415f44ac936a08bb4e5f19821dcf5e3c Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 29 May 2018 21:52:23 +0300 Subject: [PATCH 182/528] net: wireless: bcmdhd_suzuran: Update to 1.141.67.33 * Sony package version: 34.4.A.2.70 (Xperia X) Changelog: DHD 1.141.67.33 - 2018-03-09 - CVE-2017-13292 A-70722061 Fix integer overflow in wl_get_assoc_ies - CVE-2017-13303 A-71359108 Remove obsoleted wl_cfgvendor_priv_string_handler Signed-off-by: Andrey Cherepkov (cherry picked from commit 70702ec26dc4fbf6bb8cf8a00ab04a6da57da7fe) --- drivers/net/wireless/bcmdhd_suzuran/aiutils.c | 2 +- .../net/wireless/bcmdhd_suzuran/bcmevent.c | 2 +- drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c | 2 +- .../wireless/bcmdhd_suzuran/bcmsdh_linux.c | 2 +- .../wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c | 2 +- .../bcmdhd_suzuran/bcmsdh_sdmmc_linux.c | 2 +- .../wireless/bcmdhd_suzuran/bcmsdspi_linux.c | 2 +- .../net/wireless/bcmdhd_suzuran/bcmspibrcm.c | 2 +- .../net/wireless/bcmdhd_suzuran/bcmutils.c | 2 +- .../bcmdhd_suzuran/bcmwifi_channels.c | 2 +- .../bcmdhd_suzuran/bcmwifi_channels.h | 2 +- .../wireless/bcmdhd_suzuran/bcmwifi_rates.h | 2 +- drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd.h | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c | 2 +- .../wireless/bcmdhd_suzuran/dhd_cfg80211.c | 2 +- .../wireless/bcmdhd_suzuran/dhd_cfg80211.h | 2 +- .../net/wireless/bcmdhd_suzuran/dhd_common.c | 2 +- .../wireless/bcmdhd_suzuran/dhd_custom_gpio.c | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h | 2 +- .../net/wireless/bcmdhd_suzuran/dhd_linux.c | 2 +- .../net/wireless/bcmdhd_suzuran/dhd_linux.h | 2 +- .../bcmdhd_suzuran/dhd_linux_platdev.c | 2 +- .../wireless/bcmdhd_suzuran/dhd_linux_sched.c | 2 +- .../wireless/bcmdhd_suzuran/dhd_linux_wq.c | 2 +- .../wireless/bcmdhd_suzuran/dhd_linux_wq.h | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c | 2 +- drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h | 2 +- .../net/wireless/bcmdhd_suzuran/dhd_proto.h | 2 +- .../net/wireless/bcmdhd_suzuran/dhd_sdio.c | 2 +- .../net/wireless/bcmdhd_suzuran/dhd_wlfc.c | 2 +- .../net/wireless/bcmdhd_suzuran/dhd_wlfc.h | 2 +- .../net/wireless/bcmdhd_suzuran/dngl_stats.h | 2 +- .../net/wireless/bcmdhd_suzuran/dngl_wlhdr.h | 2 +- drivers/net/wireless/bcmdhd_suzuran/hndpmu.c | 2 +- .../wireless/bcmdhd_suzuran/include/Makefile | 2 +- .../wireless/bcmdhd_suzuran/include/aidmp.h | 2 +- .../wireless/bcmdhd_suzuran/include/bcm_cfg.h | 2 +- .../bcmdhd_suzuran/include/bcm_mpool_pub.h | 2 +- .../wireless/bcmdhd_suzuran/include/bcmcdc.h | 2 +- .../wireless/bcmdhd_suzuran/include/bcmdefs.h | 2 +- .../wireless/bcmdhd_suzuran/include/bcmdevs.h | 2 +- .../bcmdhd_suzuran/include/bcmendian.h | 2 +- .../bcmdhd_suzuran/include/bcmnvram.h | 2 +- .../bcmdhd_suzuran/include/bcmpcispi.h | 2 +- .../wireless/bcmdhd_suzuran/include/bcmperf.h | 2 +- .../bcmdhd_suzuran/include/bcmsdbus.h | 2 +- .../wireless/bcmdhd_suzuran/include/bcmsdh.h | 2 +- .../bcmdhd_suzuran/include/bcmsdh_sdmmc.h | 2 +- .../bcmdhd_suzuran/include/bcmsdpcm.h | 2 +- .../bcmdhd_suzuran/include/bcmsdspi.h | 2 +- .../bcmdhd_suzuran/include/bcmsdstd.h | 2 +- .../wireless/bcmdhd_suzuran/include/bcmspi.h | 2 +- .../bcmdhd_suzuran/include/bcmspibrcm.h | 2 +- .../bcmdhd_suzuran/include/bcmsrom_fmt.h | 2 +- .../bcmdhd_suzuran/include/bcmsrom_tbl.h | 2 +- .../bcmdhd_suzuran/include/bcmutils.h | 2 +- .../bcmdhd_suzuran/include/brcm_nl80211.h | 2 +- .../wireless/bcmdhd_suzuran/include/dbus.h | 2 +- .../include/devctrl_if/wlioctl_defs.h | 2 +- .../bcmdhd_suzuran/include/dhdioctl.h | 2 +- .../wireless/bcmdhd_suzuran/include/epivers.h | 10 +-- .../wireless/bcmdhd_suzuran/include/hndpmu.h | 2 +- .../bcmdhd_suzuran/include/hndrte_armtrap.h | 2 +- .../bcmdhd_suzuran/include/hndrte_cons.h | 2 +- .../wireless/bcmdhd_suzuran/include/hndsoc.h | 2 +- .../bcmdhd_suzuran/include/linux_osl.h | 2 +- .../bcmdhd_suzuran/include/linuxver.h | 2 +- .../wireless/bcmdhd_suzuran/include/miniopt.h | 2 +- .../bcmdhd_suzuran/include/msgtrace.h | 2 +- .../net/wireless/bcmdhd_suzuran/include/osl.h | 2 +- .../include/packed_section_end.h | 2 +- .../include/packed_section_start.h | 2 +- .../wireless/bcmdhd_suzuran/include/pcicfg.h | 2 +- .../bcmdhd_suzuran/include/proto/802.11.h | 2 +- .../bcmdhd_suzuran/include/proto/802.11_bta.h | 2 +- .../bcmdhd_suzuran/include/proto/802.11e.h | 2 +- .../bcmdhd_suzuran/include/proto/802.1d.h | 2 +- .../bcmdhd_suzuran/include/proto/802.3.h | 2 +- .../bcmdhd_suzuran/include/proto/bcmeth.h | 2 +- .../bcmdhd_suzuran/include/proto/bcmevent.h | 2 +- .../bcmdhd_suzuran/include/proto/bcmip.h | 2 +- .../bcmdhd_suzuran/include/proto/bcmipv6.h | 2 +- .../bcmdhd_suzuran/include/proto/bcmtcp.h | 2 +- .../bcmdhd_suzuran/include/proto/bt_amp_hci.h | 2 +- .../bcmdhd_suzuran/include/proto/dnglevent.h | 2 +- .../bcmdhd_suzuran/include/proto/eapol.h | 2 +- .../bcmdhd_suzuran/include/proto/ethernet.h | 2 +- .../bcmdhd_suzuran/include/proto/nan.h | 2 +- .../bcmdhd_suzuran/include/proto/p2p.h | 2 +- .../bcmdhd_suzuran/include/proto/sdspi.h | 2 +- .../bcmdhd_suzuran/include/proto/vlan.h | 2 +- .../bcmdhd_suzuran/include/proto/wpa.h | 2 +- .../bcmdhd_suzuran/include/proto/wps.h | 2 +- .../wireless/bcmdhd_suzuran/include/sbchipc.h | 2 +- .../bcmdhd_suzuran/include/sbconfig.h | 2 +- .../bcmdhd_suzuran/include/sbhnddma.h | 2 +- .../bcmdhd_suzuran/include/sbpcmcia.h | 2 +- .../wireless/bcmdhd_suzuran/include/sbsdio.h | 2 +- .../bcmdhd_suzuran/include/sbsdpcmdev.h | 2 +- .../bcmdhd_suzuran/include/sbsocram.h | 2 +- .../wireless/bcmdhd_suzuran/include/sdio.h | 2 +- .../wireless/bcmdhd_suzuran/include/sdioh.h | 2 +- .../wireless/bcmdhd_suzuran/include/sdiovar.h | 2 +- .../wireless/bcmdhd_suzuran/include/siutils.h | 2 +- .../wireless/bcmdhd_suzuran/include/spid.h | 2 +- .../wireless/bcmdhd_suzuran/include/trxhdr.h | 2 +- .../bcmdhd_suzuran/include/typedefs.h | 2 +- .../bcmdhd_suzuran/include/wlfc_proto.h | 2 +- .../wireless/bcmdhd_suzuran/include/wlioctl.h | 2 +- .../net/wireless/bcmdhd_suzuran/linux_osl.c | 2 +- drivers/net/wireless/bcmdhd_suzuran/sbutils.c | 2 +- drivers/net/wireless/bcmdhd_suzuran/siutils.c | 2 +- .../wireless/bcmdhd_suzuran/siutils_priv.h | 2 +- .../net/wireless/bcmdhd_suzuran/uamp_api.h | 2 +- .../net/wireless/bcmdhd_suzuran/wl_android.c | 2 +- .../net/wireless/bcmdhd_suzuran/wl_android.h | 2 +- .../net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 64 +++++++++++-------- .../net/wireless/bcmdhd_suzuran/wl_cfg80211.h | 10 +-- .../wireless/bcmdhd_suzuran/wl_cfg_btcoex.c | 2 +- .../net/wireless/bcmdhd_suzuran/wl_cfgnan.c | 2 +- .../net/wireless/bcmdhd_suzuran/wl_cfgnan.h | 2 +- .../net/wireless/bcmdhd_suzuran/wl_cfgp2p.c | 2 +- .../net/wireless/bcmdhd_suzuran/wl_cfgp2p.h | 2 +- .../wireless/bcmdhd_suzuran/wl_cfgvendor.c | 40 +----------- .../wireless/bcmdhd_suzuran/wl_cfgvendor.h | 5 +- drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h | 2 +- .../wireless/bcmdhd_suzuran/wl_linux_mon.c | 2 +- drivers/net/wireless/bcmdhd_suzuran/wl_roam.c | 2 +- .../wireless/bcmdhd_suzuran/wldev_common.c | 2 +- .../wireless/bcmdhd_suzuran/wldev_common.h | 2 +- 136 files changed, 180 insertions(+), 211 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/aiutils.c b/drivers/net/wireless/bcmdhd_suzuran/aiutils.c index 54a0376747c5..e1f833ad28be 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/aiutils.c +++ b/drivers/net/wireless/bcmdhd_suzuran/aiutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmevent.c b/drivers/net/wireless/bcmdhd_suzuran/bcmevent.c index 1447d2baa983..3f9f8390424a 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmevent.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmevent.c @@ -1,7 +1,7 @@ /* * bcmevent read-only data shared by kernel or app layers * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c index 98e561b6c3b3..ea4edda2c8b3 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c @@ -2,7 +2,7 @@ * BCMSDH interface glue * implement bcmsdh API for SDIOH driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c index e57a2cfa1869..5cab16b98d93 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c @@ -1,7 +1,7 @@ /* * SDIO access interface for drivers - linux specific (pci only) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c index b2a8e8087d8d..87aaeee7c10f 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c index 17c42b4f7ac4..27a48afb523b 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c index 5f152518cd8e..689115a51b6f 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c @@ -1,7 +1,7 @@ /* * Broadcom SPI Host Controller Driver - Linux Per-port * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c b/drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c index 19cd1828eaf5..da16dccf71aa 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c @@ -1,7 +1,7 @@ /* * Broadcom BCMSDH to gSPI Protocol Conversion Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmutils.c b/drivers/net/wireless/bcmdhd_suzuran/bcmutils.c index 6b1a5f7c0d42..0f1631300f95 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmutils.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmutils.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c index 4cc23b825abf..33ec4f8db860 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c @@ -3,7 +3,7 @@ * Contents are wifi-specific, used by any kernel or app-level * software that might want wifi things as it grows. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h index 9defecab9993..82d59f47ba51 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h @@ -3,7 +3,7 @@ * This header file housing the define and function prototype use by * both the wl driver, tools & Apps. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h index 9a29f929361c..40852cb02b29 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h @@ -1,7 +1,7 @@ /* * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c b/drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c index 3f8e67cd5cf6..2312c94c4187 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c +++ b/drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd.h b/drivers/net/wireless/bcmdhd_suzuran/dhd.h index 454f6f58c0b2..8156ad66c11c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2013 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c index 62b78e61d309..e2a891c1e2f8 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c @@ -1,7 +1,7 @@ /* * BT-AMP support routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h index 0c5e9de534e9..000d4eee6a51 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h @@ -1,7 +1,7 @@ /* * BT-AMP support routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h index 14515e12b1e7..0887b0ee9bdf 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c index 00d4821d7e5e..153cffbce0b7 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c @@ -1,7 +1,7 @@ /* * DHD Protocol Module for CDC and BDC. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c index ed3a7690b342..bac72e4d560f 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h index a160571ad8c9..fbc10f211adc 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c index 2e48feddbb35..d89d8220ae11 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), common DHD core. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c index 7cdfad423c80..b266c5e7006a 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c @@ -1,6 +1,6 @@ /* * Customer code to add GPIO control during WLAN start/stop -* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2013 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h index 796d5598acd1..8216dba67297 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h @@ -1,7 +1,7 @@ /* * Debug/trace/assert driver definitions for Dongle Host Driver. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c index b7760c5cd1bb..06167ab86cf8 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c @@ -1,7 +1,7 @@ /* * IP Packet Parser Module. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h index 08765033c0be..62ce6b5700ff 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h @@ -3,7 +3,7 @@ * * Provides type definitions and function prototypes used to parse ip packet. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c index 2e6676346388..ac136f6867f6 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface * Basically selected code segments from usb-cdc.c and usb-rndis.c * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2014 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h index 5129d8d1225b..e97929afe083 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h @@ -1,7 +1,7 @@ /* * DHD Linux header file (dhd_linux exports for cfg80211 and other components) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c index 447578a0439c..3dca697c1f17 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c @@ -1,7 +1,7 @@ /* * Linux platform device for DHD WLAN adapter * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2013 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c index 4b62ee40c2f1..a24b32124fba 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c @@ -1,7 +1,7 @@ /* * Expose some of the kernel scheduler routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c index ea4d567b1941..bd0b7afad022 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Generic work queue framework * Generic interface to handle dhd deferred work events * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h index 1066250b2824..66f237fb7002 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Generic work queue framework * Generic interface to handle dhd deferred work events * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c index 0c74d7021218..ea97317f040c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD) * Prefered Network Offload and Wi-Fi Location Service(WLS) code. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h index 361c5cecd34d..62425da6c1e6 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h @@ -1,7 +1,7 @@ /* * Header file of Broadcom Dongle Host Driver (DHD) * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h index 6b95755938bb..61b95d13a747 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c index 44ec2b607ab8..f04512680089 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c @@ -1,7 +1,7 @@ /* * DHD Bus Module for SDIO * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2014 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c index 52700ac94ff9..1152ce9dfd23 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c @@ -1,7 +1,7 @@ /* * DHD PROP_TXSTATUS Module. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h index ee5d00489bd5..347c1bcbea46 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h b/drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h index 73024f1e4274..cd499133dcc7 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h @@ -2,7 +2,7 @@ * Common stats definitions for clients of dongle * ports * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h index f5f5148cd5b3..74047430fff4 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h +++ b/drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h @@ -1,7 +1,7 @@ /* * Dongle WL Header definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/hndpmu.c b/drivers/net/wireless/bcmdhd_suzuran/hndpmu.c index 31fcf91f0223..cfbbea8a854c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/hndpmu.c +++ b/drivers/net/wireless/bcmdhd_suzuran/hndpmu.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing PMU corerev specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/Makefile b/drivers/net/wireless/bcmdhd_suzuran/include/Makefile index 797ee2563e33..3b8291471203 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/Makefile +++ b/drivers/net/wireless/bcmdhd_suzuran/include/Makefile @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (C) 1999-2017, Broadcom Corporation +# Copyright (C) 1999-2018, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h b/drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h index 831865dd8817..cc4fe830c965 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h @@ -1,7 +1,7 @@ /* * Broadcom AMBA Interconnect definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h index 7c6e70f449ef..fe1622268957 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h @@ -1,7 +1,7 @@ /* * BCM common config options * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h index b05ba3704aeb..bbb4e6699b73 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h @@ -35,7 +35,7 @@ * and instrumentation on top of the heap, without modifying the heap * allocation implementation. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h index c93b6f619b20..3759e362f1be 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h index 15c00f718a31..d7a14c094aa5 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h @@ -1,7 +1,7 @@ /* * Misc system wide definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h index ebc57c71d56f..d950bc71355e 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h @@ -1,7 +1,7 @@ /* * Broadcom device-specific manifest constants. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h index 970989e38f6b..3e783eae32be 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h @@ -1,7 +1,7 @@ /* * Byte order utilities * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h index 3fbc303bd528..e4b785c84f4c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h @@ -1,7 +1,7 @@ /* * NVRAM variable manipulation * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h index d4781abb982a..49790c24ae22 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h @@ -1,7 +1,7 @@ /* * Broadcom PCI-SPI Host Controller Register Definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h index 84c232f8a059..9cc62882fe40 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h @@ -1,7 +1,7 @@ /* * Performance counters software interface. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h index 4d4634ba6585..267c974cb33d 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h @@ -2,7 +2,7 @@ * Definitions for API from sdio common code (bcmsdh) to individual * host controller drivers. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h index 099120a34d60..9946acfb7ea2 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h @@ -3,7 +3,7 @@ * export functions to client drivers * abstract OS and BUS specific details of SDIO * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h index 5ad8ae077270..c98171fd3015 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h index 2bfac6693ec4..9c9c32e1ed24 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h @@ -2,7 +2,7 @@ * Broadcom SDIO/PCMCIA * Software-specific definitions shared between device and host side * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h index 1fc1fd4eef6b..559a7c2bb630 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h index 9edb37286712..318a6a8fc85d 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h index 193dc8e0c9ca..0b4d7bdb6d6d 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h @@ -1,7 +1,7 @@ /* * Broadcom SPI Low-Level Hardware Driver API * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h index c81e6049ae03..833fd261705d 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h index 1baebcdf90bb..3e485d519581 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h @@ -1,7 +1,7 @@ /* * SROM format definition. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h index c8335b56eb5f..be43a7c5ef18 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h @@ -1,7 +1,7 @@ /* * Table that encodes the srom formats for PCI/PCIe NICs. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h index 1743d1f8e927..1103739f30f2 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h @@ -1,7 +1,7 @@ /* * Misc useful os-independent macros and functions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h index edb22d53ea84..f17c05d52521 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h @@ -1,7 +1,7 @@ /* * Definitions for nl80211 testmode access to host driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/dbus.h b/drivers/net/wireless/bcmdhd_suzuran/include/dbus.h index fe898da34ac9..80ef80bd97e9 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/dbus.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/dbus.h @@ -2,7 +2,7 @@ * Dongle BUS interface Abstraction layer * target serial buses like USB, SDIO, SPI, etc. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h index 7d7f8c86e99c..6001a497ce81 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h b/drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h index 2adfaf89bf1b..cffb2f3b1de4 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h @@ -5,7 +5,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h b/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h index caa82f18aed9..d60c79139364 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -32,17 +32,17 @@ #define EPI_RC_NUMBER 67 -#define EPI_INCREMENTAL_NUMBER 32 +#define EPI_INCREMENTAL_NUMBER 33 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 141, 67, 32 +#define EPI_VERSION 1, 141, 67, 33 -#define EPI_VERSION_NUM 0x018d4320 +#define EPI_VERSION_NUM 0x018d4321 #define EPI_VERSION_DEV 1.141.67 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.141.67.32 (r)" +#define EPI_VERSION_STR "1.141.67.33 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h b/drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h index 9e236d789f01..a22f39bbf831 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h @@ -1,7 +1,7 @@ /* * HND SiliconBackplane PMU support. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h index eee716db5fcf..5c305023d629 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h @@ -1,7 +1,7 @@ /* * HNDRTE arm trap handling. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h index 7dcde5ff37cd..40731bf78102 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h @@ -1,7 +1,7 @@ /* * Console support for hndrte. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h b/drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h index 1dbe9c19e0ab..948f9af92149 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h @@ -1,7 +1,7 @@ /* * Broadcom HND chip & on-chip-interconnect-related definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h b/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h index 9b844be2c953..228e231a9955 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h b/drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h index f6e08bc85f14..363fb5caa7f5 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h @@ -2,7 +2,7 @@ * Linux-specific abstractions to gain some independence from linux kernel versions. * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h b/drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h index ab6668097ec0..722e5737564a 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h @@ -1,7 +1,7 @@ /* * Command line options parser. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h b/drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h index 6119bbba09a8..4105585989a4 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h @@ -1,7 +1,7 @@ /* * Trace messages sent over HBUS * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/osl.h b/drivers/net/wireless/bcmdhd_suzuran/include/osl.h index 9a1f8a5960b0..7a101e506e88 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/osl.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/osl.h @@ -1,7 +1,7 @@ /* * OS Abstraction Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h b/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h index 27e39b53e9eb..cad72104470b 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h @@ -15,7 +15,7 @@ * #include * * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h b/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h index 61c14a69401e..18f48270fa8c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h @@ -15,7 +15,7 @@ * #include * * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h b/drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h index 99ebf063f345..13774d0e510c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h @@ -1,7 +1,7 @@ /* * pcicfg.h: PCI configuration constants and structures. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h index e18cc6ef19d0..a501d8206f87 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h index 9de5616ab024..7b9baf3c6550 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h @@ -1,7 +1,7 @@ /* * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h index ded6b7612415..879fa84f3168 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h @@ -1,7 +1,7 @@ /* * 802.11e protocol header file * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h index efb390bfc09e..ceddd5c767d0 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h index dc1626aa667a..e7728e307f0b 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h index 4947e533cb8a..8611c682791c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h @@ -1,7 +1,7 @@ /* * Broadcom Ethernettype protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h index 352916ba33a8..006213bfff73 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h @@ -1,7 +1,7 @@ /* * Broadcom Event protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h index f5ee807c1c96..a95a6131324e 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h index 86226102e455..42068ef5ebc9 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h index 850c5b4e8f2f..2be771af44e7 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to TCP Protocol * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h index f1ea2909971c..096794592a8e 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h @@ -1,7 +1,7 @@ /* * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h index 549566e58950..d6a84f24fbc2 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h @@ -1,7 +1,7 @@ /* * Broadcom Event protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h index ed3310cd37f9..7b012eecb110 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h @@ -5,7 +5,7 @@ * IEEE Std 802.1X-2001 * IEEE 802.1X RADIUS Usage Guidelines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h index 68eb83f5330b..3542492743ec 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h @@ -1,7 +1,7 @@ /* * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h index f7179b6a3cd4..0c2d922a6d77 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h index 41c037274901..0ae7ef47e7bf 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h index 35e8180d67dd..98af94328abf 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Standard * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h index fc6e13b6cd48..643a73a76a4b 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h @@ -1,7 +1,7 @@ /* * 802.1Q VLAN protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h index 1a3ae0e8a6e1..147016f3730f 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to WPA * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h index e3d653ababe8..aa3d19a38236 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h @@ -1,7 +1,7 @@ /* * WPS IE definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h index 00512bd0aa3a..51a07435bd51 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h @@ -7,7 +7,7 @@ * * $Id: sbchipc.h 527121 2015-01-16 03:22:32Z $ * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h index 8de9b0942577..569b0c9b731e 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h @@ -1,7 +1,7 @@ /* * Broadcom SiliconBackplane hardware register definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h index afe82680838f..43ec49c47a39 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h @@ -2,7 +2,7 @@ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface * This supports the following chips: BCM42xx, 44xx, 47xx . * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h index 20bb1748273b..27d2f83f7c0a 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h @@ -1,7 +1,7 @@ /* * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h index 56e5f14fe34f..cca84bc18f28 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h @@ -4,7 +4,7 @@ * * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h index f24d0a3c4e76..958436e3c45e 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h @@ -2,7 +2,7 @@ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific * device core support * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h index 1f4ab45b2e1c..f9bfa969dc1b 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h @@ -1,7 +1,7 @@ /* * BCM47XX Sonics SiliconBackplane embedded ram core * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sdio.h b/drivers/net/wireless/bcmdhd_suzuran/include/sdio.h index 8b85c3593c82..4b9573953bdf 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sdio.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sdio.h @@ -2,7 +2,7 @@ * SDIO spec header file * Protocol and standard (common) device definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h b/drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h index 62a5c4cc3179..754e01f6d6db 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h @@ -2,7 +2,7 @@ * SDIO Host Controller Spec header file * Register map and definitions for the Standard Host Controller * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h b/drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h index 326b32d8dfb0..734a17d6a34c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h @@ -2,7 +2,7 @@ * Structure used by apps whose drivers access SDIO drivers. * Pulled out separately so dhdu and wlu can both use it. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/siutils.h b/drivers/net/wireless/bcmdhd_suzuran/include/siutils.h index 19a18ee50a99..5ea12f196284 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/siutils.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/siutils.h @@ -2,7 +2,7 @@ * Misc utility routines for accessing the SOC Interconnects * of Broadcom HNBU chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/spid.h b/drivers/net/wireless/bcmdhd_suzuran/include/spid.h index b5d7b675748d..87d8291c1987 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/spid.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/spid.h @@ -1,7 +1,7 @@ /* * SPI device spec header file * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h b/drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h index 5ea40e739e31..3cd08f8e1686 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h @@ -1,7 +1,7 @@ /* * TRX image file header format. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h b/drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h index 0222b8824c5f..236b22862049 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h index 90624b6a5b48..4355e72a3e29 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h b/drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h index cec5d1eb5672..226d38a2bcd8 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/linux_osl.c b/drivers/net/wireless/bcmdhd_suzuran/linux_osl.c index 0bd42de1f62b..03d490dc8da2 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/linux_osl.c +++ b/drivers/net/wireless/bcmdhd_suzuran/linux_osl.c @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/sbutils.c b/drivers/net/wireless/bcmdhd_suzuran/sbutils.c index c0364f608466..a625d65993d3 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/sbutils.c +++ b/drivers/net/wireless/bcmdhd_suzuran/sbutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/siutils.c b/drivers/net/wireless/bcmdhd_suzuran/siutils.c index 64c2ba14b607..bf91a266e74b 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/siutils.c +++ b/drivers/net/wireless/bcmdhd_suzuran/siutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h b/drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h index e553ce355404..1712409c7d70 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h +++ b/drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h @@ -1,7 +1,7 @@ /* * Include file private to the SOC Interconnect support files. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/uamp_api.h b/drivers/net/wireless/bcmdhd_suzuran/uamp_api.h index 93d1d2eb208b..01935148ee9b 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/uamp_api.h +++ b/drivers/net/wireless/bcmdhd_suzuran/uamp_api.h @@ -3,7 +3,7 @@ * * Description: Universal AMP API * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c b/drivers/net/wireless/bcmdhd_suzuran/wl_android.c index a7ac9103077a..8c62fe4545b6 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_android.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2015 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_android.h b/drivers/net/wireless/bcmdhd_suzuran/wl_android.h index fb3cba9cf17b..1045e6ea2e32 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_android.h +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_android.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c index dd5fb0275d80..cff5b0b42ac4 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2015 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 718508 2017-08-31 02:48:38Z $ + * $Id: wl_cfg80211.c 751081 2018-03-09 08:06:41Z $ */ /* */ #include @@ -8526,6 +8526,27 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.req_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.req_len > 0) && + (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0)))) { + err = BCME_BADLEN; + goto exit; + } + if (assoc_info.resp_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.resp_len > 0) && (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -8536,45 +8557,34 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) } if (assoc_info.req_len) { err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + assoc_info.req_len, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - return err; + goto exit; } conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - if (conn_info->req_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->req_ie_len, MAX_REQ_LINE)); - return err; - } - } else { - conn_info->req_ie_len = 0; + memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); } if (assoc_info.resp_len) { err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + assoc_info.resp_len, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - return err; - } - conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); - if (conn_info->resp_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->resp_ie_len, MAX_REQ_LINE)); - return err; + goto exit; } - } else { - conn_info->resp_ie_len = 0; + conn_info->resp_ie_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); + } + +exit: + if (err) { + WL_ERR(("err:%d, assoc_info-req:%u,resp:%u conn_info-req:%u,resp:%u\n", + err, assoc_info.req_len, assoc_info.resp_len, + conn_info->req_ie_len, conn_info->resp_ie_len)); } - WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, - conn_info->resp_ie_len)); return err; } diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h index 069eda344e49..08a8c258e0f1 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.h 596861 2015-11-03 08:54:58Z $ + * $Id: wl_cfg80211.h 751081 2018-03-09 08:06:41Z $ */ #ifndef _wl_cfg80211_h_ @@ -364,12 +364,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024 +#define MAX_REQ_LINE 1024u struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - s32 req_ie_len; + u32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - s32 resp_ie_len; + u32 resp_ie_len; }; /* firmware /nvram downloading controller */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c index 9ed1748463ab..eb02ffaf2b1c 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c index 723211896d50..974548ae33c3 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c @@ -3,7 +3,7 @@ * * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h index 44484eba1d68..bec3b72be0b0 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h @@ -3,7 +3,7 @@ * * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c index f7b8c2b99ee5..d6c063f22656 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c @@ -1,7 +1,7 @@ /* * Linux cfgp2p driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h index cca3f7b339cb..40fa2a169708 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h @@ -1,7 +1,7 @@ /* * Linux cfgp2p driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c index 8449e39c276d..114c68d26db7 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 Vendor Extension Code * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -1908,36 +1908,6 @@ static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_de } #endif /* defined(KEEP_ALIVE) */ -static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int err = 0; - int data_len = 0; - - WL_INFO(("%s: Enter \n", __func__)); - - if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) { - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - data_len = strlen(cfg->ioctl_buf); - cfg->ioctl_buf[data_len] = '\0'; - } - - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - cfg->ioctl_buf, data_len+1); - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - else - WL_INFO(("Vendor Command reply sent successfully!\n")); - - return err; -} - #ifdef LINKSTAT_SUPPORT #define NUM_RATE 32 #define NUM_PEER 1 @@ -2130,14 +2100,6 @@ static int wl_cfgvendor_set_country(struct wiphy *wiphy, } static const struct wiphy_vendor_command wl_vendor_cmds [] = { - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_PRIV_STR - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_priv_string_handler - }, #ifdef GSCAN_SUPPORT { { diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h index a352a9b1415d..2212ec3beae9 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 Vendor Extension Code * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -341,9 +341,6 @@ enum mkeep_alive_attributes { MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC }; -/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */ -#define BRCM_VENDOR_SCMD_CAPA "cap" - #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) extern int wl_cfgvendor_attach(struct wiphy *wiphy); extern int wl_cfgvendor_detach(struct wiphy *wiphy); diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h b/drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h index 02d653e4e1d6..e41c479a0835 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h @@ -2,7 +2,7 @@ * Minimal debug/trace/assert driver definitions for * Broadcom 802.11 Networking Adapter. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c b/drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c index a15c132b7dff..271dfc250a03 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), Linux monitor network interface * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_roam.c b/drivers/net/wireless/bcmdhd_suzuran/wl_roam.c index 957640888266..50180753ad77 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_roam.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wl_roam.c @@ -1,7 +1,7 @@ /* * Linux roam cache * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c b/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c index f57cce3c7c79..decaf3560d42 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c +++ b/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c @@ -1,7 +1,7 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.h b/drivers/net/wireless/bcmdhd_suzuran/wldev_common.h index d1746dd0d9cc..07f3d56b4cb2 100755 --- a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.h +++ b/drivers/net/wireless/bcmdhd_suzuran/wldev_common.h @@ -1,7 +1,7 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you -- GitLab From 07eb5048da974f4df0d55a6efe834e3e56a1dc3b Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Thu, 31 May 2018 23:30:24 +0300 Subject: [PATCH 183/528] bcmdhd_suzuran: Add Release Note 1.141.67.33 (cherry picked from commit 896517673861b65cee85c7927a47406ea178559c) --- .../bcmdhd_suzuran/ChangeLog/ReleaseNote.txt | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt b/drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt index 56101af582d0..ddcd4f5c65de 100644 --- a/drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt +++ b/drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt @@ -3,11 +3,30 @@ DHD 1.141.X Release for BCM4339, 4354, 43455 SDIO Projects. -------------------------------- Change History -------------------------------- + +Additional fixes: + - A-37505450 Fix RTT report of providing wrong information + - CVE-2017-0706 A-35195787 Adding boundary check in wl_cfg80211_mgmt_tx + - CVE-2017-0573 A-34469904 Fix buffer overrun in wl_android_set_roampref + - CVE-2016-8464 A-29000183 Fix buffer overrun in private command path + - A-29863589 Add boundary check while getting channel spec + - A-28336924 Check to avoid sending Disassoc in unassociated state + - A-27419732 Fix CONFIG_HZ dependency in wifi driver + - A-24469238 Add a NULL check in dhd_pno_get_gscan_batch_from_fw + - A-24270601 Disable debug trace event WLC_E_TRACE + - A-22666437 Fix for watch dog issue in wifi connect test + - Add ability to pass flags to get_country_code + + +DHD 1.141.67.33 - 2018-03-09 + - CVE-2017-13292 A-70722061 Fix integer overflow in wl_get_assoc_ies + - CVE-2017-13303 A-71359108 Remove obsoleted wl_cfgvendor_priv_string_handler + DHD 1.141.67.32 - 2017-12-14 - Fixed buffer overrun issue in wl_parse_ssid_list_tlv() - Fixed parsing issue on wl_parse_ssid_list_tlv() for PNO setup - Fixed memory leak in PNO - - Fix potential buffer overflow + - Fixed potential buffer overflow - Fixed missed SSID/MAC filtering in log for security reason DHD 1.141.67.30 - 2017.8.31 -- GitLab From 1e6bd5d46aa6e0c077679bef0df7ee6ec41a5935 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Wed, 27 Jun 2018 21:07:44 +0300 Subject: [PATCH 184/528] drivers/net: remove bcmdhd (cherry picked from commit ba0b569bc80bf8931c3eb90e6046e40aab281123) --- arch/arm64/configs/diffconfig/ivy_diffconfig | 2 +- .../configs/diffconfig/ivy_dsds_diffconfig | 2 +- .../configs/diffconfig/suzuran_diffconfig | 1 + drivers/net/wireless/Kconfig | 2 - drivers/net/wireless/Makefile | 2 - drivers/net/wireless/bcmdhd/Kconfig | 74 - drivers/net/wireless/bcmdhd/Makefile | 538 - drivers/net/wireless/bcmdhd/Makefile.kk | 430 - drivers/net/wireless/bcmdhd/Makefile_Shamu | 439 - drivers/net/wireless/bcmdhd/aiutils.c | 1123 -- drivers/net/wireless/bcmdhd/bcmevent.c | 297 - drivers/net/wireless/bcmdhd/bcmsdh.c | 705 - drivers/net/wireless/bcmdhd/bcmsdh_linux.c | 457 - drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c | 1456 -- .../net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c | 387 - drivers/net/wireless/bcmdhd/bcmsdspi_linux.c | 249 - drivers/net/wireless/bcmdhd/bcmspibrcm.c | 1810 -- drivers/net/wireless/bcmdhd/bcmutils.c | 3064 ---- .../net/wireless/bcmdhd/bcmwifi_channels.c | 1229 -- .../net/wireless/bcmdhd/bcmwifi_channels.h | 548 - drivers/net/wireless/bcmdhd/bcmwifi_rates.h | 466 - drivers/net/wireless/bcmdhd/bcmxtlv.c | 399 - drivers/net/wireless/bcmdhd/dhd.h | 1337 -- drivers/net/wireless/bcmdhd/dhd_bta.c | 337 - drivers/net/wireless/bcmdhd/dhd_bta.h | 39 - drivers/net/wireless/bcmdhd/dhd_bus.h | 199 - drivers/net/wireless/bcmdhd/dhd_cdc.c | 811 - drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 219 - drivers/net/wireless/bcmdhd/dhd_cfg80211.h | 48 - drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c | 171 - drivers/net/wireless/bcmdhd/dhd_common.c | 2723 --- drivers/net/wireless/bcmdhd/dhd_custom_gpio.c | 594 - .../wireless/bcmdhd/dhd_custom_memprealloc.c | 361 - drivers/net/wireless/bcmdhd/dhd_dbg.h | 128 - drivers/net/wireless/bcmdhd/dhd_flowring.c | 831 - drivers/net/wireless/bcmdhd/dhd_flowring.h | 177 - drivers/net/wireless/bcmdhd/dhd_ip.c | 1318 -- drivers/net/wireless/bcmdhd/dhd_ip.h | 76 - drivers/net/wireless/bcmdhd/dhd_linux.c | 10889 ------------ drivers/net/wireless/bcmdhd/dhd_linux.h | 124 - .../net/wireless/bcmdhd/dhd_linux_platdev.c | 839 - drivers/net/wireless/bcmdhd/dhd_linux_sched.c | 48 - drivers/net/wireless/bcmdhd/dhd_linux_wq.c | 317 - drivers/net/wireless/bcmdhd/dhd_linux_wq.h | 65 - drivers/net/wireless/bcmdhd/dhd_msgbuf.c | 5046 ------ drivers/net/wireless/bcmdhd/dhd_pcie.c | 5253 ------ drivers/net/wireless/bcmdhd/dhd_pcie.h | 258 - drivers/net/wireless/bcmdhd/dhd_pcie_linux.c | 1392 -- drivers/net/wireless/bcmdhd/dhd_pno.c | 3899 ----- drivers/net/wireless/bcmdhd/dhd_pno.h | 540 - drivers/net/wireless/bcmdhd/dhd_proto.h | 150 - drivers/net/wireless/bcmdhd/dhd_rtt.c | 2015 --- drivers/net/wireless/bcmdhd/dhd_rtt.h | 292 - drivers/net/wireless/bcmdhd/dhd_sdio.c | 8588 --------- drivers/net/wireless/bcmdhd/dhd_somc_custom.c | 352 - drivers/net/wireless/bcmdhd/dhd_somc_custom.h | 18 - drivers/net/wireless/bcmdhd/dhd_wlfc.c | 4104 ----- drivers/net/wireless/bcmdhd/dhd_wlfc.h | 517 - drivers/net/wireless/bcmdhd/dngl_stats.h | 271 - drivers/net/wireless/bcmdhd/dngl_wlhdr.h | 40 - drivers/net/wireless/bcmdhd/hnd_pktpool.c | 751 - drivers/net/wireless/bcmdhd/hnd_pktq.c | 602 - drivers/net/wireless/bcmdhd/hndpmu.c | 274 - drivers/net/wireless/bcmdhd/include/Makefile | 71 - drivers/net/wireless/bcmdhd/include/aidmp.h | 387 - drivers/net/wireless/bcmdhd/include/bcm_cfg.h | 29 - .../wireless/bcmdhd/include/bcm_mpool_pub.h | 361 - drivers/net/wireless/bcmdhd/include/bcmcdc.h | 132 - drivers/net/wireless/bcmdhd/include/bcmdefs.h | 399 - drivers/net/wireless/bcmdhd/include/bcmdevs.h | 731 - .../net/wireless/bcmdhd/include/bcmendian.h | 329 - .../net/wireless/bcmdhd/include/bcmmsgbuf.h | 749 - .../net/wireless/bcmdhd/include/bcmnvram.h | 272 - drivers/net/wireless/bcmdhd/include/bcmpcie.h | 227 - .../net/wireless/bcmdhd/include/bcmpcispi.h | 181 - drivers/net/wireless/bcmdhd/include/bcmperf.h | 36 - .../net/wireless/bcmdhd/include/bcmsdbus.h | 143 - drivers/net/wireless/bcmdhd/include/bcmsdh.h | 252 - .../wireless/bcmdhd/include/bcmsdh_sdmmc.h | 117 - .../net/wireless/bcmdhd/include/bcmsdpcm.h | 278 - .../net/wireless/bcmdhd/include/bcmsdspi.h | 135 - .../net/wireless/bcmdhd/include/bcmsdstd.h | 282 - drivers/net/wireless/bcmdhd/include/bcmspi.h | 40 - .../net/wireless/bcmdhd/include/bcmspibrcm.h | 162 - .../net/wireless/bcmdhd/include/bcmsrom_fmt.h | 633 - .../net/wireless/bcmdhd/include/bcmsrom_tbl.h | 1029 -- .../net/wireless/bcmdhd/include/bcmutils.h | 1174 -- .../wireless/bcmdhd/include/brcm_nl80211.h | 64 - drivers/net/wireless/bcmdhd/include/dbus.h | 582 - .../bcmdhd/include/devctrl_if/wlioctl_defs.h | 2110 --- .../net/wireless/bcmdhd/include/dhdioctl.h | 136 - drivers/net/wireless/bcmdhd/include/epivers.h | 48 - .../net/wireless/bcmdhd/include/hnd_armtrap.h | 88 - .../net/wireless/bcmdhd/include/hnd_cons.h | 77 - .../net/wireless/bcmdhd/include/hnd_pktpool.h | 204 - .../net/wireless/bcmdhd/include/hnd_pktq.h | 186 - drivers/net/wireless/bcmdhd/include/hndpmu.h | 41 - drivers/net/wireless/bcmdhd/include/hndsoc.h | 286 - .../net/wireless/bcmdhd/include/linux_osl.h | 986 -- .../net/wireless/bcmdhd/include/linuxver.h | 748 - drivers/net/wireless/bcmdhd/include/miniopt.h | 79 - .../net/wireless/bcmdhd/include/msgtrace.h | 78 - drivers/net/wireless/bcmdhd/include/osl.h | 149 - .../net/wireless/bcmdhd/include/osl_decl.h | 34 - .../bcmdhd/include/packed_section_end.h | 59 - .../bcmdhd/include/packed_section_start.h | 63 - drivers/net/wireless/bcmdhd/include/pcicfg.h | 260 - .../net/wireless/bcmdhd/include/pcie_core.h | 642 - .../wireless/bcmdhd/include/proto/802.11.h | 3853 ----- .../bcmdhd/include/proto/802.11_bta.h | 45 - .../wireless/bcmdhd/include/proto/802.11e.h | 138 - .../wireless/bcmdhd/include/proto/802.1d.h | 50 - .../net/wireless/bcmdhd/include/proto/802.3.h | 52 - .../wireless/bcmdhd/include/proto/bcmdhcp.h | 89 - .../wireless/bcmdhd/include/proto/bcmeth.h | 113 - .../wireless/bcmdhd/include/proto/bcmevent.h | 529 - .../net/wireless/bcmdhd/include/proto/bcmip.h | 245 - .../wireless/bcmdhd/include/proto/bcmipv6.h | 160 - .../wireless/bcmdhd/include/proto/bcmtcp.h | 90 - .../wireless/bcmdhd/include/proto/bcmudp.h | 58 - .../bcmdhd/include/proto/bt_amp_hci.h | 441 - .../net/wireless/bcmdhd/include/proto/eapol.h | 212 - .../wireless/bcmdhd/include/proto/ethernet.h | 228 - .../net/wireless/bcmdhd/include/proto/nan.h | 238 - .../net/wireless/bcmdhd/include/proto/p2p.h | 710 - .../net/wireless/bcmdhd/include/proto/sdspi.h | 75 - .../net/wireless/bcmdhd/include/proto/vlan.h | 95 - .../net/wireless/bcmdhd/include/proto/wpa.h | 217 - .../net/wireless/bcmdhd/include/proto/wps.h | 386 - drivers/net/wireless/bcmdhd/include/sbchipc.h | 3646 ---- .../net/wireless/bcmdhd/include/sbconfig.h | 282 - .../net/wireless/bcmdhd/include/sbhnddma.h | 417 - .../net/wireless/bcmdhd/include/sbpcmcia.h | 131 - drivers/net/wireless/bcmdhd/include/sbsdio.h | 186 - .../net/wireless/bcmdhd/include/sbsdpcmdev.h | 295 - .../net/wireless/bcmdhd/include/sbsocram.h | 200 - drivers/net/wireless/bcmdhd/include/sdio.h | 622 - drivers/net/wireless/bcmdhd/include/sdioh.h | 445 - drivers/net/wireless/bcmdhd/include/sdiovar.h | 58 - drivers/net/wireless/bcmdhd/include/siutils.h | 589 - drivers/net/wireless/bcmdhd/include/spid.h | 165 - drivers/net/wireless/bcmdhd/include/trxhdr.h | 92 - .../net/wireless/bcmdhd/include/typedefs.h | 339 - .../net/wireless/bcmdhd/include/wlfc_proto.h | 301 - drivers/net/wireless/bcmdhd/include/wlioctl.h | 6675 ------- drivers/net/wireless/bcmdhd/linux_osl.c | 1815 -- drivers/net/wireless/bcmdhd/pcie_core.c | 88 - drivers/net/wireless/bcmdhd/sbutils.c | 1105 -- drivers/net/wireless/bcmdhd/siutils.c | 3048 ---- drivers/net/wireless/bcmdhd/siutils_priv.h | 283 - drivers/net/wireless/bcmdhd/uamp_api.h | 178 - drivers/net/wireless/bcmdhd/wl_android.c | 3226 ---- drivers/net/wireless/bcmdhd/wl_android.h | 120 - drivers/net/wireless/bcmdhd/wl_cfg80211.c | 14416 ---------------- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 1040 -- drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c | 545 - drivers/net/wireless/bcmdhd/wl_cfgnan.c | 2060 --- drivers/net/wireless/bcmdhd/wl_cfgnan.h | 207 - drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 2743 --- drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 422 - drivers/net/wireless/bcmdhd/wl_cfgvendor.c | 2214 --- drivers/net/wireless/bcmdhd/wl_cfgvendor.h | 354 - drivers/net/wireless/bcmdhd/wl_dbg.h | 206 - drivers/net/wireless/bcmdhd/wl_linux_mon.c | 403 - drivers/net/wireless/bcmdhd/wl_roam.c | 306 - drivers/net/wireless/bcmdhd/wldev_common.c | 460 - drivers/net/wireless/bcmdhd/wldev_common.h | 121 - .../bcmdhd_suzuran/ChangeLog/ReleaseNote.txt | 236 - drivers/net/wireless/bcmdhd_suzuran/Kconfig | 57 - drivers/net/wireless/bcmdhd_suzuran/Makefile | 403 - .../wireless/bcmdhd_suzuran/Makefile.Nougat | 415 - .../net/wireless/bcmdhd_suzuran/Makefile.kk | 307 - .../net/wireless/bcmdhd_suzuran/Makefile.lp | 351 - .../net/wireless/bcmdhd_suzuran/Makefile.mm | 360 - drivers/net/wireless/bcmdhd_suzuran/aiutils.c | 1004 -- .../net/wireless/bcmdhd_suzuran/bcmevent.c | 294 - drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c | 705 - .../wireless/bcmdhd_suzuran/bcmsdh_linux.c | 466 - .../wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c | 1386 -- .../bcmdhd_suzuran/bcmsdh_sdmmc_linux.c | 390 - .../wireless/bcmdhd_suzuran/bcmsdspi_linux.c | 249 - .../net/wireless/bcmdhd_suzuran/bcmspibrcm.c | 1810 -- .../net/wireless/bcmdhd_suzuran/bcmutils.c | 3092 ---- .../bcmdhd_suzuran/bcmwifi_channels.c | 1246 -- .../bcmdhd_suzuran/bcmwifi_channels.h | 516 - .../wireless/bcmdhd_suzuran/bcmwifi_rates.h | 458 - drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c | 410 - drivers/net/wireless/bcmdhd_suzuran/dhd.h | 1020 -- drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c | 328 - drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h | 39 - drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h | 158 - drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c | 795 - .../wireless/bcmdhd_suzuran/dhd_cfg80211.c | 301 - .../wireless/bcmdhd_suzuran/dhd_cfg80211.h | 59 - .../net/wireless/bcmdhd_suzuran/dhd_common.c | 2356 --- .../wireless/bcmdhd_suzuran/dhd_custom_gpio.c | 597 - drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h | 126 - drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c | 953 - drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h | 71 - .../net/wireless/bcmdhd_suzuran/dhd_linux.c | 8431 --------- .../net/wireless/bcmdhd_suzuran/dhd_linux.h | 99 - .../bcmdhd_suzuran/dhd_linux_platdev.c | 758 - .../wireless/bcmdhd_suzuran/dhd_linux_sched.c | 48 - .../wireless/bcmdhd_suzuran/dhd_linux_wq.c | 316 - .../wireless/bcmdhd_suzuran/dhd_linux_wq.h | 64 - drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c | 3977 ----- drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h | 562 - .../net/wireless/bcmdhd_suzuran/dhd_proto.h | 115 - drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c | 1951 --- drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h | 292 - .../net/wireless/bcmdhd_suzuran/dhd_sdio.c | 8334 --------- .../wireless/bcmdhd_suzuran/dhd_somc_custom.c | 352 - .../wireless/bcmdhd_suzuran/dhd_somc_custom.h | 18 - .../net/wireless/bcmdhd_suzuran/dhd_wlfc.c | 4046 ----- .../net/wireless/bcmdhd_suzuran/dhd_wlfc.h | 513 - .../net/wireless/bcmdhd_suzuran/dngl_stats.h | 309 - .../net/wireless/bcmdhd_suzuran/dngl_wlhdr.h | 40 - drivers/net/wireless/bcmdhd_suzuran/hndpmu.c | 282 - .../wireless/bcmdhd_suzuran/include/Makefile | 71 - .../wireless/bcmdhd_suzuran/include/aidmp.h | 386 - .../wireless/bcmdhd_suzuran/include/bcm_cfg.h | 29 - .../bcmdhd_suzuran/include/bcm_mpool_pub.h | 361 - .../wireless/bcmdhd_suzuran/include/bcmcdc.h | 132 - .../wireless/bcmdhd_suzuran/include/bcmdefs.h | 348 - .../wireless/bcmdhd_suzuran/include/bcmdevs.h | 689 - .../bcmdhd_suzuran/include/bcmendian.h | 329 - .../bcmdhd_suzuran/include/bcmnvram.h | 272 - .../bcmdhd_suzuran/include/bcmpcispi.h | 181 - .../wireless/bcmdhd_suzuran/include/bcmperf.h | 36 - .../bcmdhd_suzuran/include/bcmsdbus.h | 143 - .../wireless/bcmdhd_suzuran/include/bcmsdh.h | 251 - .../bcmdhd_suzuran/include/bcmsdh_sdmmc.h | 117 - .../bcmdhd_suzuran/include/bcmsdpcm.h | 281 - .../bcmdhd_suzuran/include/bcmsdspi.h | 135 - .../bcmdhd_suzuran/include/bcmsdstd.h | 282 - .../wireless/bcmdhd_suzuran/include/bcmspi.h | 40 - .../bcmdhd_suzuran/include/bcmspibrcm.h | 162 - .../bcmdhd_suzuran/include/bcmsrom_fmt.h | 633 - .../bcmdhd_suzuran/include/bcmsrom_tbl.h | 1014 -- .../bcmdhd_suzuran/include/bcmutils.h | 1238 -- .../bcmdhd_suzuran/include/brcm_nl80211.h | 64 - .../wireless/bcmdhd_suzuran/include/dbus.h | 582 - .../include/devctrl_if/wlioctl_defs.h | 2030 --- .../bcmdhd_suzuran/include/dhdioctl.h | 136 - .../wireless/bcmdhd_suzuran/include/epivers.h | 48 - .../wireless/bcmdhd_suzuran/include/hndpmu.h | 36 - .../bcmdhd_suzuran/include/hndrte_armtrap.h | 88 - .../bcmdhd_suzuran/include/hndrte_cons.h | 69 - .../wireless/bcmdhd_suzuran/include/hndsoc.h | 282 - .../bcmdhd_suzuran/include/linux_osl.h | 688 - .../bcmdhd_suzuran/include/linuxver.h | 748 - .../wireless/bcmdhd_suzuran/include/miniopt.h | 77 - .../bcmdhd_suzuran/include/msgtrace.h | 77 - .../net/wireless/bcmdhd_suzuran/include/osl.h | 142 - .../include/packed_section_end.h | 59 - .../include/packed_section_start.h | 63 - .../wireless/bcmdhd_suzuran/include/pcicfg.h | 101 - .../bcmdhd_suzuran/include/proto/802.11.h | 3814 ---- .../bcmdhd_suzuran/include/proto/802.11_bta.h | 45 - .../bcmdhd_suzuran/include/proto/802.11e.h | 138 - .../bcmdhd_suzuran/include/proto/802.1d.h | 50 - .../bcmdhd_suzuran/include/proto/802.3.h | 52 - .../bcmdhd_suzuran/include/proto/bcmeth.h | 113 - .../bcmdhd_suzuran/include/proto/bcmevent.h | 538 - .../bcmdhd_suzuran/include/proto/bcmip.h | 231 - .../bcmdhd_suzuran/include/proto/bcmipv6.h | 159 - .../bcmdhd_suzuran/include/proto/bcmtcp.h | 90 - .../bcmdhd_suzuran/include/proto/bt_amp_hci.h | 441 - .../bcmdhd_suzuran/include/proto/dnglevent.h | 98 - .../bcmdhd_suzuran/include/proto/eapol.h | 211 - .../bcmdhd_suzuran/include/proto/ethernet.h | 220 - .../bcmdhd_suzuran/include/proto/nan.h | 237 - .../bcmdhd_suzuran/include/proto/p2p.h | 608 - .../bcmdhd_suzuran/include/proto/sdspi.h | 75 - .../bcmdhd_suzuran/include/proto/vlan.h | 95 - .../bcmdhd_suzuran/include/proto/wpa.h | 214 - .../bcmdhd_suzuran/include/proto/wps.h | 379 - .../wireless/bcmdhd_suzuran/include/sbchipc.h | 3304 ---- .../bcmdhd_suzuran/include/sbconfig.h | 282 - .../bcmdhd_suzuran/include/sbhnddma.h | 416 - .../bcmdhd_suzuran/include/sbpcmcia.h | 113 - .../wireless/bcmdhd_suzuran/include/sbsdio.h | 186 - .../bcmdhd_suzuran/include/sbsdpcmdev.h | 295 - .../bcmdhd_suzuran/include/sbsocram.h | 200 - .../wireless/bcmdhd_suzuran/include/sdio.h | 619 - .../wireless/bcmdhd_suzuran/include/sdioh.h | 445 - .../wireless/bcmdhd_suzuran/include/sdiovar.h | 58 - .../wireless/bcmdhd_suzuran/include/siutils.h | 440 - .../wireless/bcmdhd_suzuran/include/spid.h | 165 - .../wireless/bcmdhd_suzuran/include/trxhdr.h | 92 - .../bcmdhd_suzuran/include/typedefs.h | 344 - .../bcmdhd_suzuran/include/wlfc_proto.h | 304 - .../wireless/bcmdhd_suzuran/include/wlioctl.h | 5854 ------- .../net/wireless/bcmdhd_suzuran/linux_osl.c | 1352 -- drivers/net/wireless/bcmdhd_suzuran/sbutils.c | 1063 -- drivers/net/wireless/bcmdhd_suzuran/siutils.c | 2840 --- .../wireless/bcmdhd_suzuran/siutils_priv.h | 272 - .../net/wireless/bcmdhd_suzuran/uamp_api.h | 176 - .../net/wireless/bcmdhd_suzuran/wl_android.c | 2357 --- .../net/wireless/bcmdhd_suzuran/wl_android.h | 72 - .../net/wireless/bcmdhd_suzuran/wl_cfg80211.c | 13226 -------------- .../net/wireless/bcmdhd_suzuran/wl_cfg80211.h | 1016 -- .../wireless/bcmdhd_suzuran/wl_cfg_btcoex.c | 551 - .../net/wireless/bcmdhd_suzuran/wl_cfgnan.c | 1856 -- .../net/wireless/bcmdhd_suzuran/wl_cfgnan.h | 189 - .../net/wireless/bcmdhd_suzuran/wl_cfgp2p.c | 2726 --- .../net/wireless/bcmdhd_suzuran/wl_cfgp2p.h | 416 - .../wireless/bcmdhd_suzuran/wl_cfgvendor.c | 2396 --- .../wireless/bcmdhd_suzuran/wl_cfgvendor.h | 356 - drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h | 67 - .../wireless/bcmdhd_suzuran/wl_linux_mon.c | 403 - drivers/net/wireless/bcmdhd_suzuran/wl_roam.c | 304 - .../wireless/bcmdhd_suzuran/wldev_common.c | 425 - .../wireless/bcmdhd_suzuran/wldev_common.h | 120 - 314 files changed, 3 insertions(+), 259579 deletions(-) delete mode 100644 drivers/net/wireless/bcmdhd/Kconfig delete mode 100644 drivers/net/wireless/bcmdhd/Makefile delete mode 100644 drivers/net/wireless/bcmdhd/Makefile.kk delete mode 100644 drivers/net/wireless/bcmdhd/Makefile_Shamu delete mode 100644 drivers/net/wireless/bcmdhd/aiutils.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmevent.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmsdh.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmsdh_linux.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmsdspi_linux.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmspibrcm.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmutils.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmwifi_channels.c delete mode 100644 drivers/net/wireless/bcmdhd/bcmwifi_channels.h delete mode 100644 drivers/net/wireless/bcmdhd/bcmwifi_rates.h delete mode 100644 drivers/net/wireless/bcmdhd/bcmxtlv.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_bta.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_bta.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_bus.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_cdc.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_cfg80211.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_cfg80211.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_common.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_custom_gpio.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_dbg.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_flowring.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_flowring.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_ip.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_ip.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_linux.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_linux.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_linux_platdev.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_linux_sched.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_linux_wq.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_linux_wq.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_msgbuf.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_pcie.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_pcie.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_pcie_linux.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_pno.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_pno.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_proto.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_rtt.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_rtt.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_sdio.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_somc_custom.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_somc_custom.h delete mode 100644 drivers/net/wireless/bcmdhd/dhd_wlfc.c delete mode 100644 drivers/net/wireless/bcmdhd/dhd_wlfc.h delete mode 100644 drivers/net/wireless/bcmdhd/dngl_stats.h delete mode 100644 drivers/net/wireless/bcmdhd/dngl_wlhdr.h delete mode 100644 drivers/net/wireless/bcmdhd/hnd_pktpool.c delete mode 100644 drivers/net/wireless/bcmdhd/hnd_pktq.c delete mode 100644 drivers/net/wireless/bcmdhd/hndpmu.c delete mode 100644 drivers/net/wireless/bcmdhd/include/Makefile delete mode 100644 drivers/net/wireless/bcmdhd/include/aidmp.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcm_cfg.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmcdc.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmdefs.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmdevs.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmendian.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmnvram.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmpcie.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmpcispi.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmperf.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmsdbus.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmsdh.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmsdpcm.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmsdspi.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmsdstd.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmspi.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmspibrcm.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h delete mode 100644 drivers/net/wireless/bcmdhd/include/bcmutils.h delete mode 100644 drivers/net/wireless/bcmdhd/include/brcm_nl80211.h delete mode 100644 drivers/net/wireless/bcmdhd/include/dbus.h delete mode 100644 drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h delete mode 100644 drivers/net/wireless/bcmdhd/include/dhdioctl.h delete mode 100644 drivers/net/wireless/bcmdhd/include/epivers.h delete mode 100644 drivers/net/wireless/bcmdhd/include/hnd_armtrap.h delete mode 100644 drivers/net/wireless/bcmdhd/include/hnd_cons.h delete mode 100644 drivers/net/wireless/bcmdhd/include/hnd_pktpool.h delete mode 100644 drivers/net/wireless/bcmdhd/include/hnd_pktq.h delete mode 100644 drivers/net/wireless/bcmdhd/include/hndpmu.h delete mode 100644 drivers/net/wireless/bcmdhd/include/hndsoc.h delete mode 100644 drivers/net/wireless/bcmdhd/include/linux_osl.h delete mode 100644 drivers/net/wireless/bcmdhd/include/linuxver.h delete mode 100644 drivers/net/wireless/bcmdhd/include/miniopt.h delete mode 100644 drivers/net/wireless/bcmdhd/include/msgtrace.h delete mode 100644 drivers/net/wireless/bcmdhd/include/osl.h delete mode 100644 drivers/net/wireless/bcmdhd/include/osl_decl.h delete mode 100644 drivers/net/wireless/bcmdhd/include/packed_section_end.h delete mode 100644 drivers/net/wireless/bcmdhd/include/packed_section_start.h delete mode 100644 drivers/net/wireless/bcmdhd/include/pcicfg.h delete mode 100644 drivers/net/wireless/bcmdhd/include/pcie_core.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/802.11.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/802.11e.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/802.1d.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/802.3.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/bcmeth.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/bcmevent.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/bcmip.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/bcmudp.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/eapol.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/ethernet.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/nan.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/p2p.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/sdspi.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/vlan.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/wpa.h delete mode 100644 drivers/net/wireless/bcmdhd/include/proto/wps.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sbchipc.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sbconfig.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sbhnddma.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sbpcmcia.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sbsdio.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sbsocram.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sdio.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sdioh.h delete mode 100644 drivers/net/wireless/bcmdhd/include/sdiovar.h delete mode 100644 drivers/net/wireless/bcmdhd/include/siutils.h delete mode 100644 drivers/net/wireless/bcmdhd/include/spid.h delete mode 100644 drivers/net/wireless/bcmdhd/include/trxhdr.h delete mode 100644 drivers/net/wireless/bcmdhd/include/typedefs.h delete mode 100644 drivers/net/wireless/bcmdhd/include/wlfc_proto.h delete mode 100644 drivers/net/wireless/bcmdhd/include/wlioctl.h delete mode 100644 drivers/net/wireless/bcmdhd/linux_osl.c delete mode 100644 drivers/net/wireless/bcmdhd/pcie_core.c delete mode 100644 drivers/net/wireless/bcmdhd/sbutils.c delete mode 100644 drivers/net/wireless/bcmdhd/siutils.c delete mode 100644 drivers/net/wireless/bcmdhd/siutils_priv.h delete mode 100644 drivers/net/wireless/bcmdhd/uamp_api.h delete mode 100644 drivers/net/wireless/bcmdhd/wl_android.c delete mode 100644 drivers/net/wireless/bcmdhd/wl_android.h delete mode 100644 drivers/net/wireless/bcmdhd/wl_cfg80211.c delete mode 100644 drivers/net/wireless/bcmdhd/wl_cfg80211.h delete mode 100644 drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c delete mode 100644 drivers/net/wireless/bcmdhd/wl_cfgnan.c delete mode 100644 drivers/net/wireless/bcmdhd/wl_cfgnan.h delete mode 100644 drivers/net/wireless/bcmdhd/wl_cfgp2p.c delete mode 100644 drivers/net/wireless/bcmdhd/wl_cfgp2p.h delete mode 100644 drivers/net/wireless/bcmdhd/wl_cfgvendor.c delete mode 100644 drivers/net/wireless/bcmdhd/wl_cfgvendor.h delete mode 100644 drivers/net/wireless/bcmdhd/wl_dbg.h delete mode 100644 drivers/net/wireless/bcmdhd/wl_linux_mon.c delete mode 100644 drivers/net/wireless/bcmdhd/wl_roam.c delete mode 100644 drivers/net/wireless/bcmdhd/wldev_common.c delete mode 100644 drivers/net/wireless/bcmdhd/wldev_common.h delete mode 100644 drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/Kconfig delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/Makefile delete mode 100644 drivers/net/wireless/bcmdhd_suzuran/Makefile.Nougat delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/Makefile.kk delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/Makefile.lp delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/Makefile.mm delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/aiutils.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmevent.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmutils.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_common.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/hndpmu.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/Makefile delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/dbus.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/epivers.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/osl.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sdio.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/siutils.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/spid.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/linux_osl.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/sbutils.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/siutils.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/uamp_api.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_android.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_android.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wl_roam.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wldev_common.c delete mode 100755 drivers/net/wireless/bcmdhd_suzuran/wldev_common.h diff --git a/arch/arm64/configs/diffconfig/ivy_diffconfig b/arch/arm64/configs/diffconfig/ivy_diffconfig index fcf91fba741b..178a4fa90905 100644 --- a/arch/arm64/configs/diffconfig/ivy_diffconfig +++ b/arch/arm64/configs/diffconfig/ivy_diffconfig @@ -15,4 +15,4 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y # CONFIG_CNSS is not set -# CONFIG_CNSS_PCI is not set \ No newline at end of file +# CONFIG_CNSS_PCI is not set diff --git a/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig b/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig index 478f7ed52b8e..a6bfe8cdb107 100644 --- a/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig +++ b/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig @@ -13,4 +13,4 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y # CONFIG_CNSS is not set -# CONFIG_CNSS_PCI is not set \ No newline at end of file +# CONFIG_CNSS_PCI is not set diff --git a/arch/arm64/configs/diffconfig/suzuran_diffconfig b/arch/arm64/configs/diffconfig/suzuran_diffconfig index 737bd7db0129..c24925483d17 100644 --- a/arch/arm64/configs/diffconfig/suzuran_diffconfig +++ b/arch/arm64/configs/diffconfig/suzuran_diffconfig @@ -15,3 +15,4 @@ CONFIG_LZ4_DECOMPRESS=y CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y +# CONFIG_BCMDHD_PCIE is not set diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 470cdb9817ed..542ef0717bb3 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -356,8 +356,6 @@ config SOMC_WIFI_CONTROL source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/b43legacy/Kconfig" -source "drivers/net/wireless/bcmdhd/Kconfig" -source "drivers/net/wireless/bcmdhd_suzuran/Kconfig" source "drivers/net/wireless/brcm80211/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/ipw2x00/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 93a6aa23cfcf..1a1e05e1a159 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -57,8 +57,6 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/ obj-$(CONFIG_SOMC_WIFI_CONTROL) += somcwifictrl/ -obj-$(CONFIG_BCMDHD) += bcmdhd/ -obj-$(CONFIG_BCMDHD_SUZURAN) += bcmdhd_suzuran/ obj-$(CONFIG_BRCMFMAC) += brcm80211/ obj-$(CONFIG_BRCMSMAC) += brcm80211/ diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig deleted file mode 100644 index c35b821553b6..000000000000 --- a/drivers/net/wireless/bcmdhd/Kconfig +++ /dev/null @@ -1,74 +0,0 @@ -config BCMDHD - tristate "Broadcom wireless cards support" - depends on MMC || PCI - ---help--- - This module adds support for wireless adapters based on - Broadcom chipset. -config BCMDHD_SDIO - bool "SDIO bus interface support" - depends on BCMDHD && MMC && !BCMDHD_PCIE - -config BCMDHD_PCIE - bool "PCIe bus interface support" - depends on BCMDHD && PCI - -config BCM4339 - bool "Broadcom 4339 wireless cards support" - depends on BCMDHD && BCMDHD_SDIO - ---help--- - This module adds support for wireless adapters based on - Broadcom 4339 chipset. - -config BCM4354 - bool "Broadcom 4354 wireless cards support" - depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) - ---help--- - This module adds support for wireless adapters based on - Broadcom 4354 chipset. - -config BCM4356 - bool "Broadcom 4356 wireless cards support" - depends on BCMDHD && BCMDHD_PCIE - ---help--- - This module adds support for wireless adapters based on - Broadcom 4356 chipset. - -config BCMDHD_FW_PATH - depends on BCMDHD - string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" - ---help--- - Path to the firmware file. - -config BCMDHD_NVRAM_PATH - depends on BCMDHD - string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" - ---help--- - Path to the calibration file. - -config DHD_USE_STATIC_BUF - bool "Enable memory preallocation" - depends on BCMDHD - default n - ---help--- - Use memory preallocated in platform - -config DHD_USE_SCHED_SCAN - bool "Use CFG80211 sched scan" - depends on BCMDHD && CFG80211 - default n - ---help--- - Use CFG80211 sched scan - -config BROADCOM_WIFI_RESERVED_MEM - bool "BROADCOM Reserved memory for wifi device" - depends on BCMDHD - ---help--- - This is a configuration for broadcom WLAN driver. -config BCMDHD_DEBUG_PAGEALLOC - bool "Enable Memory Pagealloc Debugging Support" - depends on (BCM4354 || BCM4356) - ---help--- - Enable Memory Pagealloc Debugging - diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile deleted file mode 100644 index e3f6899bef54..000000000000 --- a/drivers/net/wireless/bcmdhd/Makefile +++ /dev/null @@ -1,538 +0,0 @@ -# bcmdhd -##################### -# Basic feature -##################### - -DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG -DWLP2P \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DKEEP_ALIVE -DCSCAN \ - -DPKT_FILTER_SUPPORT -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ - -DCONFIG_DTS - -##################### -# Bus Interface Type -##################### -ifneq ($(CONFIG_BCMDHD_PCIE),) - BUS_IFACE_PCIE=y -else - BUS_IFACE_SDIO=y -endif - -##################### -# SDIO I/F -##################### -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT - DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR - DHDCFLAGS += -U__ARM_ARCH_7A__ - # DPC priority - DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 - # idle count - DHDCFLAGS += -DDHD_USE_IDLECOUNT - # SKB TAILPAD to avoid out of boundary memory access - DHDCFLAGS += -DDHDENABLE_TAILPAD - DHDCFLAGS += -DSUPPORT_P2P_GO_PS -endif - -##################### -# PCIE I/F -##################### -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE - # DPC priority - DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=-1 - # Enable Link down recovery - DHDCFLAGS += -DSUPPORT_LINKDOWN_RECOVERY - # Enable Firmware Coredump - DHDCFLAGS += -DDHD_FW_COREDUMP - # Enable packet audit at host side - DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED -endif - - - -################# -# Common feature -################# - -DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 -DHDCFLAGS += -DWL_CFG80211 - - -# Debug -DHDCFLAGS += -DSIMPLE_MAC_PRINT -DHDCFLAGS += -DDEBUGFS_CFG80211 -# Enable wakelock debug function -DHDCFLAGS += -DDHD_TRACE_WAKE_LOCK -# Print out kernel panic point of file and line info when assertion happened -DHDCFLAGS += -DBCMASSERT_LOG - -# Print 8021X -DHDCFLAGS += -DDHD_8021X_DUMP - -# VSDB -DHDCFLAGS += -DVSDB -DHDCFLAGS += -DPROP_TXSTATUS - -# Wi-Fi Direct -DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -# For p2p connection issue -DHDCFLAGS += -DWL_SCB_TIMEOUT=10 -# For TDLS tear down inactive time 10 sec -DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 -# for TDLS RSSI HIGH for establishing TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 -# for TDLS RSSI HIGH for tearing down TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 - -# Roaming -DHDCFLAGS += -DROAM_AP_ENV_DETECTION -DHDCFLAGS += -DROAM_ENABLE -DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - - -# SoftAP -DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP -DHDCFLAGS += -DDISABLE_11H_SOFTAP -DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE -DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -# For setting custom short & long retry limit -DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 - -# HW5 specific features -DHDCFLAGS += -DSUPPORT_PM2_ONLY -DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD -DHDCFLAGS += -DBLOCK_IPV6_PACKET -DPASS_IPV4_SUSPEND - -# Support MAC ACL setting -DHDCFLAGS += -DWL_CFG80211_ACL -# Connection statistics -DHDCFLAGS += -DCONNECTION_STATISTICS -# END HW5 specific features - - -# For special PNO Event keep wake lock for 10sec -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 -# For Passing all multicast packets to host when not in suspend mode. -DHDCFLAGS += -DPASS_ALL_MCAST_PKTS - - -# Early suspend -DHDCFLAGS += -DDHD_USE_EARLYSUSPEND - -# WiFi turn off delay -DHDCFLAGS += -DWIFI_TURNOFF_DELAY=100 - -# For Scan result patch -DHDCFLAGS += -DESCAN_RESULT_PATCH -DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER -DHDCFLAGS += -DESCAN_BUF_OVERFLOW_MGMT - -# For Static Buffer -ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) - DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF - DHDCFLAGS += -DENHANCED_STATIC_BUF - DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DDHD_USE_STATIC_IOCTLBUF -endif -ifeq ($(CONFIG_BCMDHD_DEBUG_PAGEALLOC),y) -# Preallocation for memory dump - DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP -endif -endif - -# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) -DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 - -# Ioctl timeout 5000ms -DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 - -# Ioctl Rx count timeout -DHDCFLAGS += -DMAX_CNTL_RX_TIMEOUT=3 - -# Priority mismatch fix with kernel stack -DHDCFLAGS += -DPKTPRIO_OVERRIDE - -# Prevent rx thread monopolize -DHDCFLAGS += -DWAIT_DEQUEUE - -# Config PM Control -DHDCFLAGS += -DCONFIG_CONTROL_PM - -# Use Android wake lock mechanism -DHDCFLAGS += -DCONFIG_HAS_WAKELOCK - -# Used short dwell time during initial scan -DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME - -DHDCFLAGS += -DWL_ABORT_SCAN - -# Disable to delay link down event -DHDCFLAGS += -DDISABLE_BCN_DLY - -############################## -# Android Platform Definition -############################## -BCM_SRC_DIR := ./ - -########### -# Lollipop -########### -DHDCFLAGS += -DWL_ENABLE_P2P_IF -#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES -# Default definitions for KitKat -DHDCFLAGS += -DWL_CFG80211_STA_EVENT -DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS - -ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD -endif - -ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) -DHDCFLAGS += -DWL_SCHED_SCAN -endif - -# To support RTT -#DHDCFLAGS += -DRTT_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support GSCAN -DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o - - -########################## -# driver type -# m: module type driver -# y: built-in type driver -########################## -DRIVER_TYPE ?= m - -######################### -# Chip dependent feature -######################### - -# Chipsets supported both SDIO and PCIE -ifneq ($(CONFIG_BCM4356),) - DHDCFLAGS += -DSOMC_MIMO - DHDCFLAGS += -DBCM4356_CHIP - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - -# tput enhancement for common - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - DHDCFLAGS += -DDISABLE_FRAMEBURST_VSDB - DHDCFLAGS += -DDISABLE_PM_BCNRX - -# tput enhancement for SDIO -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DHW_OOB - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - DHDCFLAGS += -DDHDTCPACK_SUPPRESS -endif - -# tput enhancement for PCIE -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 - DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 -# DHDCFLAGS += -DCUSTOM_AMSDU_AGGSF=4 -# DHDCFLAGS += -DSET_PCIEIRQ_CPU0 -endif - - -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE - DHDCFLAGS += -DCUSTOM_DHD_WATCHDOG_MS=125 - DHDCFLAGS += -DDHD_USE_IDLECOUNT -DMAX_IDLE_COUNT=16 -DMAX_RESUME_WAIT=500 -endif - -ifeq ($(CONFIG_ARCH_MSM),y) - #DHDCFLAGS += -DSET_RPS_CPUS -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DBCMPCIE_DISABLE_ASYNC_SUSPEND -endif -endif - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -# DHDCFLAGS += -DDISABLE_IF_COUNTERS - DHDCFLAGS += -DDISABLE_TXBFR -ifeq ($(CONFIG_BCM4356),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 -endif -endif - -ifneq ($(CONFIG_BCM4354),) - DHDCFLAGS += -DBCM4354_CHIP - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - -# tput enhancement for common - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - -# tput enhancement for SDIO -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DHW_OOB - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - DHDCFLAGS += -DDHDTCPACK_SUPPRESS -endif - -# tput enhancement for PCIE -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 - DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 -endif - -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE -endif - - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC -# DHDCFLAGS += -DWLAIBSS - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4354),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 -endif -endif - -# Chipsets supported SDIO only -ifeq ($(BUS_IFACE_SDIO),y) -ifneq ($(CONFIG_BCM4339),) - DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4339),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -endif -endif - -############################# -# Platform dependent feature -############################# -# read custom mac address function -DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE - -# Default Beacon timeout -ifneq ($(CONFIG_SOMC_WLAN_BCN_TIMEOUT),) - DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=$(CONFIG_SOMC_WLAN_BCN_TIMEOUT) -else - DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=3 -endif - -# The number of the maximum devices which phone can associate -DHDCFLAGS += -DSOMC_MAX_ASSOC_NUM=10 - -# Default Listen Interval in Beacons -ifneq ($(CONFIG_SOMC_WLAN_LISTEN_INTERVAL),) - DHDCFLAGS += -DCUSTOM_LISTEN_INTERVAL=$(CONFIG_SOMC_WLAN_LISTEN_INTERVAL) -endif - -# WAPI -DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI - -# Set keep alive period -ifneq ($(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING),) - DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=$(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING) -endif - -# Set the number of probe requests per channel -ifneq ($(CONFIG_SOMC_WLAN_SCAN_NPROBES),) - DHDCFLAGS += -DSOMC_WLAN_SCAN_NPROBES=$(CONFIG_SOMC_WLAN_SCAN_NPROBES) -endif - -# Set special NV paths for 1DK chip -ifneq ($(CONFIG_SOMC_WLAN_1DK_NV_PATH),) - DHDCFLAGS += -DSOMC_1DK_NV_PATH=\"$(CONFIG_SOMC_WLAN_1DK_NV_PATH)\" -ifneq ($(CONFIG_SOMC_WLAN_LOW_POWER_NV_PATH),) - DHDCFLAGS += -DSOMC_LOW_POWER_NV_PATH=\"$(CONFIG_SOMC_WLAN_LOW_POWER_NV_PATH)\" -endif -endif - -# Disable to delay link down event -#ifeq ($(CONFIG_SOMC_WLAN_DISABLE_BCM_DLY),y) -# DHDCFLAGS += -DDISABLE_BCN_DLY -#endif - -# Change scan time -ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) - DHDCFLAGS += -DCHANGE_SCAN_TIME -endif - -# Enable scan ps(scan power optimization) -ifeq ($(CONFIG_SOMC_WLAN_ENABLE_SCAN_PS),y) - DHDCFLAGS += -DSOMC_WLAN_ENABLE_SCAN_PS -endif - -# Set default nvram path -ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) - DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" -endif - -# Enable Disconnection timing log -ifeq ($(CONFIG_SOMC_WLAN_ENABLE_DISC_TIME_LOG),y) - DHDCFLAGS += -DDHD_ENABLE_DISC_TIME_LOG -endif - -######### -# Others -######### - - -EXTRA_LDFLAGS += --strip-debug -EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG -EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" -EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ -KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) - -MODNAME := bcmdhd - -DHDOFILES := dhd_pno.o \ - dhd_common.o \ - dhd_ip.o \ - dhd_custom_gpio.o \ - dhd_linux.o \ - dhd_linux_sched.o \ - dhd_cfg80211.o \ - dhd_linux_wq.o \ - aiutils.o \ - bcmevent.o \ - bcmutils.o \ - bcmwifi_channels.o \ - hndpmu.o \ - linux_osl.o \ - sbutils.o \ - siutils.o \ - wl_android.o \ - wl_cfg80211.o \ - wl_cfgp2p.o \ - wl_cfg_btcoex.o \ - wldev_common.o \ - wl_linux_mon.o \ - wl_roam.o \ - dhd_linux_platdev.o \ - dhd_wlfc.o \ - hnd_pktq.o \ - hnd_pktpool.o \ - wl_cfgnan.o \ - bcmxtlv.o \ - dhd_somc_custom.o - -ifeq ($(BUS_IFACE_SDIO),y) -DHDOFILES += bcmsdh.o \ - bcmsdh_linux.o \ - bcmsdh_sdmmc.o \ - bcmsdh_sdmmc_linux.o \ - dhd_cdc.o \ - dhd_sdio.o -endif - - -ifeq ($(BUS_IFACE_PCIE),y) -DHDOFILES += dhd_pcie.o \ - dhd_pcie_linux.o \ - pcie_core.o \ - dhd_flowring.o \ - dhd_msgbuf.o -endif - - -DHDOFILES += $(ANDROID_OFILES) - -# Module information used by KBuild framework -obj-$(CONFIG_BCMDHD) += $(MODNAME).o - -$(MODNAME)-objs := $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd/Makefile.kk b/drivers/net/wireless/bcmdhd/Makefile.kk deleted file mode 100644 index 841621adc0cb..000000000000 --- a/drivers/net/wireless/bcmdhd/Makefile.kk +++ /dev/null @@ -1,430 +0,0 @@ -# bcmdhd -##################### -# Basic feature -##################### - -DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG -DWLP2P \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DKEEP_ALIVE -DCSCAN \ - -DPKT_FILTER_SUPPORT -DEMBEDDED_PLATFORM -DPNO_SUPPORT - -##################### -# Bus Interface Type -##################### -ifneq ($(CONFIG_BCMDHD_PCIE),) - BUS_IFACE_PCIE=y -else - BUS_IFACE_SDIO=y -endif - -##################### -# SDIO I/F -##################### -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT - DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR - DHDCFLAGS += -U__ARM_ARCH_7A__ - # DPC priority - DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 - # idle count - DHDCFLAGS += -DDHD_USE_IDLECOUNT - # SKB TAILPAD to avoid out of boundary memory access - DHDCFLAGS += -DDHDENABLE_TAILPAD - DHDCFLAGS += -DSUPPORT_P2P_GO_PS -endif - -##################### -# PCIE I/F -##################### -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE - # DPC priority - DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=-1 - # Enable Link down recovery - DHDCFLAGS += -DSUPPORT_LINKDOWN_RECOVERY - # Enable Firmware Coredump - DHDCFLAGS += -DDHD_FW_COREDUMP - - # Enable packet audit at host side - DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED -endif - - - -################# -# Common feature -################# - -DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 -DHDCFLAGS += -DWL_CFG80211 - - -# Debug -DHDCFLAGS += -DSIMPLE_MAC_PRINT -DHDCFLAGS += -DDEBUGFS_CFG80211 -# Enable wakelock debug function -DHDCFLAGS += -DDHD_TRACE_WAKE_LOCK -# Print out kernel panic point of file and line info when assertion happened -DHDCFLAGS += -DBCMASSERT_LOG - -# Print 8021X -DHDCFLAGS += -DDHD_8021X_DUMP - -# VSDB -DHDCFLAGS += -DVSDB -DHDCFLAGS += -DPROP_TXSTATUS - -# Wi-Fi Direct -DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -# For p2p connection issue -DHDCFLAGS += -DWL_SCB_TIMEOUT=10 -# For TDLS tear down inactive time 10 sec -DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 -# for TDLS RSSI HIGH for establishing TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 -# for TDLS RSSI HIGH for tearing down TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 - -# Roaming -DHDCFLAGS += -DROAM_AP_ENV_DETECTION -DHDCFLAGS += -DROAM_ENABLE -DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - - - - - -# SoftAP -DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP -DHDCFLAGS += -DDISABLE_11H_SOFTAP -DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE -DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -# For setting custom short & long retry limit -DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 - -# HW5 specific features -DHDCFLAGS += -DSUPPORT_PM2_ONLY -DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD -DHDCFLAGS += -DBLOCK_IPV6_PACKET -DPASS_IPV4_SUSPEND - -# Support MAC ACL setting -DHDCFLAGS += -DWL_CFG80211_ACL -# Connection statistics -DHDCFLAGS += -DCONNECTION_STATISTICS -# END HW5 specific features - - -# For special PNO Event keep wake lock for 10sec -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 -# For Passing all multicast packets to host when not in suspend mode. -DHDCFLAGS += -DPASS_ALL_MCAST_PKTS - - -# Early suspend -DHDCFLAGS += -DDHD_USE_EARLYSUSPEND - -# WiFi turn off delay -DHDCFLAGS += -DWIFI_TURNOFF_DELAY=100 - -# For Scan result patch -DHDCFLAGS += -DESCAN_RESULT_PATCH -DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER -DHDCFLAGS += -DESCAN_BUF_OVERFLOW_MGMT - -# For Static Buffer -ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) - DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF - DHDCFLAGS += -DENHANCED_STATIC_BUF - DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DDHD_USE_STATIC_IOCTLBUF -endif -ifeq ($(CONFIG_BCMDHD_DEBUG_PAGEALLOC),y) -# Preallocation for memory dump - DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP -endif -endif - -# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) -DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 - -# Ioctl timeout 5000ms -DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 - -# Ioctl Rx count timeout -DHDCFLAGS += -DMAX_CNTL_RX_TIMEOUT=3 - -# Priority mismatch fix with kernel stack -DHDCFLAGS += -DPKTPRIO_OVERRIDE - -# Prevent rx thread monopolize -DHDCFLAGS += -DWAIT_DEQUEUE - -# Config PM Control -DHDCFLAGS += -DCONFIG_CONTROL_PM - -# Use Android wake lock mechanism -DHDCFLAGS += -DCONFIG_HAS_WAKELOCK - -# Used short dwell time during initial scan -DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME - -#DHDCFLAGS += -DWL_ABORT_SCAN - -############################## -# Android Platform Definition -############################## - -## Andrioid KitKat ## - -DHDCFLAGS += -DWL_ENABLE_P2P_IF -#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES -# Default definitions for KitKat -DHDCFLAGS += -DWL_CFG80211_STA_EVENT -DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS - - - - -########################## -# driver type -# m: module type driver -# y: built-in type driver -########################## -DRIVER_TYPE ?= m - -######################### -# Chip dependent feature -######################### - -# Chipsets supported both SDIO and PCIE -ifneq ($(CONFIG_BCM4356),) - DHDCFLAGS += -DBCM4356_CHIP - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - -# tput enhancement for common - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - DHDCFLAGS += -DDISABLE_FRAMEBURST_VSDB - DHDCFLAGS += -DDISABLE_PM_BCNRX - -# tput enhancement for SDIO -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DHW_OOB - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - DHDCFLAGS += -DDHDTCPACK_SUPPRESS -endif - -# tput enhancement for PCIE -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 - DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 -# DHDCFLAGS += -DCUSTOM_AMSDU_AGGSF=4 -# DHDCFLAGS += -DSET_PCIEIRQ_CPU0 -endif - - -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE - DHDCFLAGS += -DCUSTOM_DHD_WATCHDOG_MS=125 - DHDCFLAGS += -DDHD_USE_IDLECOUNT -DMAX_IDLE_COUNT=16 -DMAX_RESUME_WAIT=500 -endif - -ifeq ($(CONFIG_ARCH_MSM),y) - #DHDCFLAGS += -DSET_RPS_CPUS -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DBCMPCIE_DISABLE_ASYNC_SUSPEND -endif -endif - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -# DHDCFLAGS += -DDISABLE_IF_COUNTERS - DHDCFLAGS += -DDISABLE_TXBFR - -ifeq ($(CONFIG_BCM4356),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 -endif -endif - -ifneq ($(CONFIG_BCM4354),) - DHDCFLAGS += -DBCM4354_CHIP - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - -# tput enhancement for common - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - -# tput enhancement for SDIO -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DHW_OOB - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - DHDCFLAGS += -DDHDTCPACK_SUPPRESS -endif - -# tput enhancement for PCIE -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 - DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 -endif - -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE -endif - - - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC -# DHDCFLAGS += -DWLAIBSS - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4354),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 -endif -endif - -# Chipsets supported SDIO only -ifeq ($(BUS_IFACE_SDIO),y) -ifneq ($(CONFIG_BCM4339),) - DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4339),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -endif -endif -############################# -# Platform dependent feature -############################# -######### -# Others -######### - - -EXTRA_LDFLAGS += --strip-debug -EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG -EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" -EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ -KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) - -DHDOFILES := dhd_pno.o dhd_common.o dhd_ip.o dhd_custom_gpio.o \ - dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_linux_wq.o aiutils.o bcmevent.o \ - bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \ - wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_cfg_btcoex.o wldev_common.o \ - wl_linux_mon.o wl_roam.o dhd_linux_platdev.o dhd_linux_wq.o wl_cfg_btcoex.o \ - dhd_wlfc.o hnd_pktq.o hnd_pktpool.o wl_cfgnan.o bcmxtlv.o - - -ifeq ($(BUS_IFACE_SDIO),y) -DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o -DHDOFILES += dhd_cdc.o dhd_sdio.o -endif - - -ifeq ($(BUS_IFACE_PCIE),y) -DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o dhd_msgbuf.o -endif - - -DHDOFILES += $(ANDROID_OFILES) - -bcmdhd-objs := $(DHDOFILES) -obj-$(DRIVER_TYPE) += bcmdhd.o - -all: - @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules" - @$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules - -clean: - rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd \ - Module.symvers modules.order .tmp_versions modules.builtin - -install: - @$(MAKE) --no-print-directory -C $(KDIR) \ - SUBDIRS=$(CURDIR) modules_install diff --git a/drivers/net/wireless/bcmdhd/Makefile_Shamu b/drivers/net/wireless/bcmdhd/Makefile_Shamu deleted file mode 100644 index b007f79ff33a..000000000000 --- a/drivers/net/wireless/bcmdhd/Makefile_Shamu +++ /dev/null @@ -1,439 +0,0 @@ -# bcmdhd -##################### -# Basic feature -##################### - -DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG -DWLP2P \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DKEEP_ALIVE -DCSCAN \ - -DPKT_FILTER_SUPPORT -DEMBEDDED_PLATFORM -DPNO_SUPPORT - -##################### -# Bus Interface Type -##################### -ifneq ($(CONFIG_BCMDHD_PCIE),) - BUS_IFACE_PCIE=y -else - BUS_IFACE_SDIO=y -endif - -##################### -# SDIO I/F -##################### -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT - DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR - DHDCFLAGS += -U__ARM_ARCH_7A__ - # DPC priority - DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 - # idle count - DHDCFLAGS += -DDHD_USE_IDLECOUNT - # SKB TAILPAD to avoid out of boundary memory access - DHDCFLAGS += -DDHDENABLE_TAILPAD - DHDCFLAGS += -DSUPPORT_P2P_GO_PS -endif - -##################### -# PCIE I/F -##################### -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE - # DPC priority - DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=-1 - # Enable Link down recovery - DHDCFLAGS += -DSUPPORT_LINKDOWN_RECOVERY - # Enable Firmware Coredump - DHDCFLAGS += -DDHD_FW_COREDUMP -endif - - - -################# -# Common feature -################# - -DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 -DHDCFLAGS += -DWL_CFG80211 - - -# Debug -DHDCFLAGS += -DSIMPLE_MAC_PRINT -DHDCFLAGS += -DDEBUGFS_CFG80211 -# Print out kernel panic point of file and line info when assertion happened -DHDCFLAGS += -DBCMASSERT_LOG - -# Print 8021X -DHDCFLAGS += -DDHD_8021X_DUMP - -# VSDB -DHDCFLAGS += -DVSDB -DHDCFLAGS += -DPROP_TXSTATUS - -# Wi-Fi Direct -DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -# For p2p connection issue -DHDCFLAGS += -DWL_SCB_TIMEOUT=10 -# For TDLS tear down inactive time 10 sec -DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 -# for TDLS RSSI HIGH for establishing TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 -# for TDLS RSSI HIGH for tearing down TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 - -# Roaming -DHDCFLAGS += -DROAM_AP_ENV_DETECTION -DHDCFLAGS += -DROAM_ENABLE -DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - - - - - -# SoftAP -DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP -DHDCFLAGS += -DDISABLE_11H_SOFTAP -DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE -DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - -# HW5 specific features -DHDCFLAGS += -DSUPPORT_PM2_ONLY -DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD -DHDCFLAGS += -DBLOCK_IPV6_PACKET -DPASS_IPV4_SUSPEND - -# Support MAC ACL setting -DHDCFLAGS += -DWL_CFG80211_ACL -# Connection statistics -DHDCFLAGS += -DCONNECTION_STATISTICS -# END HW5 specific features - - -# For special PNO Event keep wake lock for 10sec -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 -# For Passing all multicast packets to host when not in suspend mode. -DHDCFLAGS += -DPASS_ALL_MCAST_PKTS - - -# Early suspend -DHDCFLAGS += -DDHD_USE_EARLYSUSPEND - -# WiFi turn off delay -DHDCFLAGS += -DWIFI_TURNOFF_DELAY=100 - -# For Scan result patch -DHDCFLAGS += -DESCAN_RESULT_PATCH -DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER -DHDCFLAGS += -DESCAN_BUF_OVERFLOW_MGMT - -# For Static Buffer -ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) - DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF - DHDCFLAGS += -DENHANCED_STATIC_BUF - DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DDHD_USE_STATIC_IOCTLBUF -endif -ifeq ($(CONFIG_BCMDHD_DEBUG_PAGEALLOC),y) -# Preallocation for memory dump - DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP -endif -endif - -# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) -DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 - -# Ioctl timeout 5000ms -DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 - -# Ioctl Rx count timeout -DHDCFLAGS += -DMAX_CNTL_RX_TIMEOUT=3 - -# Priority mismatch fix with kernel stack -DHDCFLAGS += -DPKTPRIO_OVERRIDE - -# Prevent rx thread monopolize -DHDCFLAGS += -DWAIT_DEQUEUE - -# Config PM Control -DHDCFLAGS += -DCONFIG_CONTROL_PM - -# Use Android wake lock mechanism -DHDCFLAGS += -DCONFIG_HAS_WAKELOCK - -# Used short dwell time during initial scan -DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME - -############################## -# Android Platform Definition -############################## - -########### -# Lollipop -########### -DHDCFLAGS += -DWL_ENABLE_P2P_IF -#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES -# Default definitions for KitKat -DHDCFLAGS += -DWL_CFG80211_STA_EVENT -DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS - -ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) -DHDCFLAGS += -DWL_SCHED_SCAN -endif - -# To support RTT -#DHDCFLAGS += -DRTT_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support GSCAN -DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o - - - - -########################## -# driver type -# m: module type driver -# y: built-in type driver -########################## -DRIVER_TYPE ?= m - -######################### -# Chip dependent feature -######################### - -# Chipsets supported both SDIO and PCIE -ifneq ($(CONFIG_BCM4356),) - DHDCFLAGS += -DBCM4356_CHIP - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - -# tput enhancement for common - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - DHDCFLAGS += -DDISABLE_FRAMEBURST_VSDB - DHDCFLAGS += -DDISABLE_PM_BCNRX - -# tput enhancement for SDIO -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DHW_OOB - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - DHDCFLAGS += -DDHDTCPACK_SUPPRESS -endif - -# tput enhancement for PCIE -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 - DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 -# DHDCFLAGS += -DCUSTOM_AMSDU_AGGSF=4 -# DHDCFLAGS += -DSET_PCIEIRQ_CPU0 -endif - - -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE - DHDCFLAGS += -DCUSTOM_DHD_WATCHDOG_MS=0 -# DHDCFLAGS += -DDHD_USE_IDLECOUNT -DMAX_IDLE_COUNT=16 -DMAX_RESUME_WAIT=100 -endif - -ifeq ($(CONFIG_ARCH_MSM),y) - #DHDCFLAGS += -DSET_RPS_CPUS -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DBCMPCIE_DISABLE_ASYNC_SUSPEND -endif -endif - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -# DHDCFLAGS += -DDISABLE_IF_COUNTERS - DHDCFLAGS += -DDISABLE_TXBFR - -ifeq ($(CONFIG_BCM4356),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD -# DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 -endif -endif - -ifneq ($(CONFIG_BCM4354),) - DHDCFLAGS += -DBCM4354_CHIP - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - -# tput enhancement for common - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - -# tput enhancement for SDIO -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DHW_OOB - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - DHDCFLAGS += -DDHDTCPACK_SUPPRESS -endif - -# tput enhancement for PCIE -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 - DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 -endif - -ifeq ($(BUS_IFACE_PCIE),y) - DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE -endif - - - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC -# DHDCFLAGS += -DWLAIBSS - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4354),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - -ifeq ($(BUS_IFACE_SDIO),y) - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 -endif -endif - -# Chipsets supported SDIO only -ifeq ($(BUS_IFACE_SDIO),y) -ifneq ($(CONFIG_BCM4339),) - DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4339),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -endif -endif -############################# -# Platform dependent feature -############################# -######### -# Others -######### - - -EXTRA_LDFLAGS += --strip-debug -EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG -EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" -EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ -KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) - -DHDOFILES := dhd_pno.o dhd_common.o dhd_ip.o dhd_custom_gpio.o \ - dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_linux_wq.o aiutils.o bcmevent.o \ - bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \ - wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_cfg_btcoex.o wldev_common.o \ - wl_linux_mon.o wl_roam.o dhd_linux_platdev.o dhd_linux_wq.o wl_cfg_btcoex.o \ - dhd_wlfc.o hnd_pktq.o hnd_pktpool.o wl_cfgnan.o bcmxtlv.o - - -ifeq ($(BUS_IFACE_SDIO),y) -DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o -DHDOFILES += dhd_cdc.o dhd_sdio.o -endif - - -ifeq ($(BUS_IFACE_PCIE),y) -DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o dhd_msgbuf.o -endif - - -DHDOFILES += $(ANDROID_OFILES) - -bcmdhd-objs := $(DHDOFILES) -obj-$(DRIVER_TYPE) += bcmdhd.o - -all: - @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules" - @$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules - -clean: - rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd \ - Module.symvers modules.order .tmp_versions modules.builtin - -install: - @$(MAKE) --no-print-directory -C $(KDIR) \ - SUBDIRS=$(CURDIR) modules_install diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c deleted file mode 100644 index 3f061ab4093d..000000000000 --- a/drivers/net/wireless/bcmdhd/aiutils.c +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: aiutils.c 511882 2014-10-31 06:08:29Z $ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "siutils_priv.h" - -#define BCM47162_DMP() (0) -#define BCM5357_DMP() (0) -#define BCM4707_DMP() (0) -#define PMU_DMP() (0) -#define remap_coreid(sih, coreid) (coreid) -#define remap_corerev(sih, corerev) (corerev) - -/* EROM parsing */ - -static uint32 -get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) -{ - uint32 ent; - uint inv = 0, nom = 0; - uint32 size = 0; - - while (TRUE) { - ent = R_REG(si_osh(sih), *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; - - /* escape condition related EROM size if it has invalid values */ - size += sizeof(*eromptr); - if (size >= ER_SZ_MAX) { - SI_ERROR(("Failed to find end of EROM marker\n")); - break; - } - - nom++; - } - - SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); - if (inv + nom) { - SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); - } - return ent; -} - -static uint32 -get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, - uint32 *sizel, uint32 *sizeh) -{ - uint32 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); - - SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", - sp, ad, st, *sizeh, *sizel, *addrh, *addrl)); - - return asd; -} - -static void -ai_hwfixup(si_info_t *sii) -{ -} - - -/* parse the enumeration rom to identify all cores */ -void -ai_scan(si_t *sih, void *regs, uint devid) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - chipcregs_t *cc = (chipcregs_t *)regs; - uint32 erombase, *eromptr, *eromlim; - - erombase = R_REG(sii->osh, &cc->eromptr); - - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); - break; - - case PCI_BUS: - /* Set wrappers address */ - sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); - - /* Now point the window at the erom */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); - eromptr = regs; - break; - -#ifdef BCMSDIO - case SPI_BUS: - case SDIO_BUS: - eromptr = (uint32 *)(uintptr)erombase; - break; -#endif /* BCMSDIO */ - - case PCMCIA_BUS: - default: - SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype)); - ASSERT(0); - return; - } - eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); - - SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", - regs, erombase, eromptr, eromlim)); - while (eromptr < eromlim) { - uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; - uint32 mpd, asd, addrl, addrh, sizel, sizeh; - 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)) { - SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); - ai_hwfixup(sii); - return; - } - - cib = get_erom_ent(sih, &eromptr, 0, 0); - - if ((cib & ER_TAG) != ER_CI) { - SI_ERROR(("CIA not followed by CIB\n")); - 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; - -#ifdef BCMDBG_SI - SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " - "nsw = %d, nmp = %d & nsp = %d\n", - mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp)); -#else - BCM_REFERENCE(crev); -#endif - - 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; - } - } - if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID && - cid != PMU_CORE_ID && cid != GCI_CORE_ID) - continue; - } - - idx = sii->numcores; - - cores_info->cia[idx] = cia; - cores_info->cib[idx] = cib; - cores_info->coreid[idx] = remap_coreid(sih, cid); - - for (i = 0; i < nmp; i++) { - mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); - if ((mpd & ER_TAG) != ER_MP) { - SI_ERROR(("Not enough MP entries for component 0x%x\n", cid)); - goto error; - } - SI_VMSG((" Master port %d, mp: %d id: %d\n", i, - (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, - (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); - } - - /* 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) { - do { - /* 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 (br == TRUE) { - break; - } - else if ((addrh != 0) || (sizeh != 0) || - (sizel != SI_CORE_SIZE)) { - SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 =" - "0x%x\n", addrh, sizeh, sizel)); - SI_ERROR(("First Slave ASD for" - "core 0x%04x malformed " - "(0x%08x)\n", cid, asd)); - goto error; - } - } - } while (1); - } - cores_info->coresba[idx] = addrl; - cores_info->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)) { - cores_info->coresba2[idx] = addrl; - cores_info->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); - - if (asd == 0) - break; - j++; - } while (1); - if (j == 0) { - SI_ERROR((" SP %d has no address descriptors\n", i)); - 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) { - SI_ERROR(("Missing descriptor for MW %d\n", i)); - goto error; - } - if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { - SI_ERROR(("Master wrapper %d is not 4KB\n", i)); - goto error; - } - if (i == 0) - cores_info->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) { - SI_ERROR(("Missing descriptor for SW %d\n", i)); - goto error; - } - if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { - SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); - goto error; - } - if ((nmw == 0) && (i == 0)) - cores_info->wrapba[idx] = addrl; - } - - - /* Don't record bridges */ - if (br) - continue; - - /* Done with core */ - sii->numcores++; - } - - SI_ERROR(("Reached end of erom without finding END")); - -error: - sii->numcores = 0; - return; -} - -#define AI_SETCOREIDX_MAPSIZE(coreid) \ - (((coreid) == NS_CCB_CORE_ID) ? 15 * SI_CORE_SIZE : SI_CORE_SIZE) - -/* This function changes the logical "focus" to the indicated core. - * Return the current core's virtual address. - */ -void * -ai_setcoreidx(si_t *sih, uint coreidx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 addr, wrap; - void *regs; - - if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) - return (NULL); - - addr = cores_info->coresba[coreidx]; - wrap = cores_info->wrapba[coreidx]; - - /* - * If the user has provided an interrupt mask enabled function, - * then assert interrupts are disabled before switching the core. - */ - ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); - - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - /* map new one */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(addr, - AI_SETCOREIDX_MAPSIZE(cores_info->coreid[coreidx])); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - sii->curmap = regs = cores_info->regs[coreidx]; - if (!cores_info->wrappers[coreidx] && (wrap != 0)) { - cores_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->wrappers[coreidx])); - } - sii->curwrap = cores_info->wrappers[coreidx]; - break; - - case PCI_BUS: - /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); - regs = sii->curmap; - /* point bar0 2nd 4KB window to the primary wrapper */ - if (PCIE_GEN2(sii)) - OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap); - else - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); - break; - -#ifdef BCMSDIO - case SPI_BUS: - case SDIO_BUS: - sii->curmap = regs = (void *)((uintptr)addr); - sii->curwrap = (void *)((uintptr)wrap); - break; -#endif /* BCMSDIO */ - - case PCMCIA_BUS: - default: - ASSERT(0); - regs = NULL; - break; - } - - sii->curmap = regs; - sii->curidx = coreidx; - - return regs; -} - - -void -ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - chipcregs_t *cc = NULL; - uint32 erombase, *eromptr, *eromlim; - uint i, j, cidx; - uint32 cia, cib, nmp, nsp; - uint32 asd, addrl, addrh, sizel, sizeh; - - for (i = 0; i < sii->numcores; i++) { - if (cores_info->coreid[i] == CC_CORE_ID) { - cc = (chipcregs_t *)cores_info->regs[i]; - break; - } - } - if (cc == NULL) - goto error; - - erombase = R_REG(sii->osh, &cc->eromptr); - eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); - eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); - - cidx = sii->curidx; - cia = cores_info->cia[cidx]; - cib = cores_info->cib[cidx]; - - nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; - nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; - - /* scan for cores */ - while (eromptr < eromlim) { - if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && - (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { - break; - } - } - - /* skip master ports */ - for (i = 0; i < nmp; i++) - get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); - - /* Skip ASDs in port 0 */ - 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); - } - - j = 1; - do { - asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, - &sizel, &sizeh); - 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); - if (asd == 0) - break; - - if (!asidx--) { - *addr = addrl; - *size = sizel; - return; - } - j++; - } while (1); - - if (j == 0) { - SI_ERROR((" SP %d has no address descriptors\n", i)); - break; - } - } - -error: - *size = 0; - return; -} - -/* Return the number of address spaces in current core */ -int -ai_numaddrspaces(si_t *sih) -{ - return 2; -} - -/* Return the address of the nth address space in the current core */ -uint32 -ai_addrspace(si_t *sih, uint asidx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint cidx; - - cidx = sii->curidx; - - if (asidx == 0) - return cores_info->coresba[cidx]; - else if (asidx == 1) - return cores_info->coresba2[cidx]; - else { - SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", - __FUNCTION__, asidx)); - return 0; - } -} - -/* Return the size of the nth address space in the current core */ -uint32 -ai_addrspacesize(si_t *sih, uint asidx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint cidx; - - cidx = sii->curidx; - - if (asidx == 0) - return cores_info->coresba_size[cidx]; - else if (asidx == 1) - return cores_info->coresba2_size[cidx]; - else { - SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", - __FUNCTION__, asidx)); - return 0; - } -} - -uint -ai_flag(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); - return sii->curidx; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); - return sii->curidx; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", - __FUNCTION__)); - return sii->curidx; - } - -#ifdef REROUTE_OOBINT - if (PMU_DMP()) { - SI_ERROR(("%s: Attempting to read PMU DMP registers\n", - __FUNCTION__)); - return PMU_OOB_BIT; - } -#endif /* REROUTE_OOBINT */ - - ai = sii->curwrap; - ASSERT(ai != NULL); - - return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); -} - -uint -ai_flag_alt(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); - return sii->curidx; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); - return sii->curidx; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", - __FUNCTION__)); - return sii->curidx; - } -#ifdef REROUTE_OOBINT - if (PMU_DMP()) { - SI_ERROR(("%s: Attempting to read PMU DMP registers\n", - __FUNCTION__)); - return PMU_OOB_BIT; - } -#endif /* REROUTE_OOBINT */ - - ai = sii->curwrap; - - return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK); -} - -void -ai_setint(si_t *sih, int siflag) -{ -} - -uint -ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - uint32 *map = (uint32 *) sii->curwrap; - - if (mask || val) { - uint32 w = R_REG(sii->osh, map+(offset/4)); - w &= ~mask; - w |= val; - W_REG(sii->osh, map+(offset/4), w); - } - - return (R_REG(sii->osh, map+(offset/4))); -} - -uint -ai_corevendor(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 cia; - - cia = cores_info->cia[sii->curidx]; - return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); -} - -uint -ai_corerev(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 cib; - - - cib = cores_info->cib[sii->curidx]; - return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); -} - -bool -ai_iscoreup(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - - ai = sii->curwrap; - - return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && - ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); -} - -/* - * 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(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -{ - uint origidx = 0; - uint32 *r = NULL; - uint w; - uint intr_val = 0; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - ASSERT((val & ~mask) == 0); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sih->bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (uint32 *)((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 = si_coreidx(&sii->pub); - - /* switch core */ - r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); - } - ASSERT(r != NULL); - - /* mask and set */ - if (mask || val) { - w = (R_REG(sii->osh, r) & ~mask) | val; - W_REG(sii->osh, r, w); - } - - /* readback */ - w = R_REG(sii->osh, r); - - if (!fast) { - /* restore core index */ - if (origidx != coreidx) - ai_setcoreidx(&sii->pub, origidx); - - INTR_RESTORE(sii, intr_val); - } - - return (w); -} - -/* - * If there is no need for fiddling with interrupts or core switches (typically silicon - * back plane registers, pci registers and chipcommon registers), this function - * returns the register offset on this core to a mapped address. This address can - * be used for W_REG/R_REG directly. - * - * For accessing registers that would need a core switch, this function will return - * NULL. - */ -uint32 * -ai_corereg_addr(si_t *sih, uint coreidx, uint regoff) -{ - uint32 *r = NULL; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sih->bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (uint32 *)((char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + - regoff); - } - } - - if (!fast) - return 0; - - return (r); -} - -void -ai_core_disable(si_t *sih, uint32 bits) -{ - si_info_t *sii = SI_INFO(sih); - volatile uint32 dummy; - uint32 status; - aidmp_t *ai; - - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - /* if core is already in reset, just return */ - if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) - return; - - /* ensure there are no pending backplane operations */ - SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - /* if pending backplane ops still, try waiting longer */ - if (status != 0) { - /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ - /* during driver load we may need more time */ - SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); - /* if still pending ops, continue on and try disable anyway */ - /* this is in big hammer path, so don't call wl_reinit in this case... */ - } - - W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); - dummy = R_REG(sii->osh, &ai->resetctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - - W_REG(sii->osh, &ai->ioctrl, bits); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(10); -} - -/* 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(si_t *sih, uint32 bits, uint32 resetbits) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - volatile uint32 dummy; - uint loop_counter = 10; - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - - /* put core into reset state */ - W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); - OSL_DELAY(10); - - /* ensure there are no pending backplane operations */ - SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); - - W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN)); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - - /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - - while (R_REG(sii->osh, &ai->resetctrl) != 0 && --loop_counter != 0) { - /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - - /* take core out of reset */ - W_REG(sii->osh, &ai->resetctrl, 0); - - /* ensure there are no pending backplane operations */ - SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); - } - - - W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(1); -} - -void -ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 w; - - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", - __FUNCTION__)); - return; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", - __FUNCTION__)); - return; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", - __FUNCTION__)); - return; - } - if (PMU_DMP()) { - SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", - __FUNCTION__)); - return; - } - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - ASSERT((val & ~mask) == 0); - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); - W_REG(sii->osh, &ai->ioctrl, w); - } -} - -uint32 -ai_core_cflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 w; - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", - __FUNCTION__)); - return 0; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", - __FUNCTION__)); - return 0; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", - __FUNCTION__)); - return 0; - } - - if (PMU_DMP()) { - SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", - __FUNCTION__)); - return 0; - } - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - ASSERT((val & ~mask) == 0); - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); - W_REG(sii->osh, &ai->ioctrl, w); - } - - return R_REG(sii->osh, &ai->ioctrl); -} - -uint32 -ai_core_sflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 w; - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", - __FUNCTION__)); - return 0; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", - __FUNCTION__)); - return 0; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", - __FUNCTION__)); - return 0; - } - if (PMU_DMP()) { - SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", - __FUNCTION__)); - return 0; - } - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - ASSERT((val & ~mask) == 0); - ASSERT((mask & ~SISF_CORE_BITS) == 0); - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); - W_REG(sii->osh, &ai->iostatus, w); - } - - return R_REG(sii->osh, &ai->iostatus); -} - -#if defined(BCMDBG_PHYDUMP) -/* print interesting aidmp registers */ -void -ai_dumpregs(si_t *sih, struct bcmstrbuf *b) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - osl_t *osh; - aidmp_t *ai; - uint i; - - osh = sii->osh; - - for (i = 0; i < sii->numcores; i++) { - si_setcoreidx(&sii->pub, i); - ai = sii->curwrap; - - bcm_bprintf(b, "core 0x%x: \n", cores_info->coreid[i]); - if (BCM47162_DMP()) { - bcm_bprintf(b, "Skipping mips74k in 47162a0\n"); - continue; - } - if (BCM5357_DMP()) { - bcm_bprintf(b, "Skipping usb20h in 5357\n"); - continue; - } - if (BCM4707_DMP()) { - bcm_bprintf(b, "Skipping chipcommonb in 4707\n"); - continue; - } - - if (PMU_DMP()) { - bcm_bprintf(b, "Skipping pmu core\n"); - continue; - } - - bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x" - "ioctrlwidth 0x%x iostatuswidth 0x%x\n" - "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n" - "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x" - "errlogaddrlo 0x%x errlogaddrhi 0x%x\n" - "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n" - "intstatus 0x%x config 0x%x itcr 0x%x\n", - R_REG(osh, &ai->ioctrlset), - R_REG(osh, &ai->ioctrlclear), - R_REG(osh, &ai->ioctrl), - R_REG(osh, &ai->iostatus), - R_REG(osh, &ai->ioctrlwidth), - R_REG(osh, &ai->iostatuswidth), - R_REG(osh, &ai->resetctrl), - R_REG(osh, &ai->resetstatus), - R_REG(osh, &ai->resetreadid), - R_REG(osh, &ai->resetwriteid), - R_REG(osh, &ai->errlogctrl), - R_REG(osh, &ai->errlogdone), - R_REG(osh, &ai->errlogstatus), - R_REG(osh, &ai->errlogaddrlo), - R_REG(osh, &ai->errlogaddrhi), - R_REG(osh, &ai->errlogid), - R_REG(osh, &ai->errloguser), - R_REG(osh, &ai->errlogflags), - R_REG(osh, &ai->intstatus), - R_REG(osh, &ai->config), - R_REG(osh, &ai->itcr)); - } -} -#endif diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c deleted file mode 100644 index 5cc06ac65796..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmevent.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * bcmevent read-only data shared by kernel or app layers - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmevent.c 718504 2017-08-31 02:38:08Z $ - */ - -#include -#include -#include -#include -#include -#include -#include - -/* Table of event name strings for UIs and debugging dumps */ -typedef struct { - uint event; - const char *name; -} bcmevent_name_str_t; - -/* Use the actual name for event tracing */ -#define BCMEVENT_NAME(_event) {(_event), #_event} - -static const bcmevent_name_str_t bcmevent_names[] = { - BCMEVENT_NAME(WLC_E_SET_SSID), - BCMEVENT_NAME(WLC_E_JOIN), - BCMEVENT_NAME(WLC_E_START), - BCMEVENT_NAME(WLC_E_AUTH), - BCMEVENT_NAME(WLC_E_AUTH_IND), - BCMEVENT_NAME(WLC_E_DEAUTH), - BCMEVENT_NAME(WLC_E_DEAUTH_IND), - BCMEVENT_NAME(WLC_E_ASSOC), - BCMEVENT_NAME(WLC_E_ASSOC_IND), - BCMEVENT_NAME(WLC_E_REASSOC), - BCMEVENT_NAME(WLC_E_REASSOC_IND), - BCMEVENT_NAME(WLC_E_DISASSOC), - BCMEVENT_NAME(WLC_E_DISASSOC_IND), - BCMEVENT_NAME(WLC_E_QUIET_START), - BCMEVENT_NAME(WLC_E_QUIET_END), - BCMEVENT_NAME(WLC_E_BEACON_RX), - BCMEVENT_NAME(WLC_E_LINK), - BCMEVENT_NAME(WLC_E_MIC_ERROR), - BCMEVENT_NAME(WLC_E_NDIS_LINK), - BCMEVENT_NAME(WLC_E_ROAM), - BCMEVENT_NAME(WLC_E_TXFAIL), - BCMEVENT_NAME(WLC_E_PMKID_CACHE), - BCMEVENT_NAME(WLC_E_RETROGRADE_TSF), - BCMEVENT_NAME(WLC_E_PRUNE), - BCMEVENT_NAME(WLC_E_AUTOAUTH), - BCMEVENT_NAME(WLC_E_EAPOL_MSG), - BCMEVENT_NAME(WLC_E_SCAN_COMPLETE), - BCMEVENT_NAME(WLC_E_ADDTS_IND), - BCMEVENT_NAME(WLC_E_DELTS_IND), - BCMEVENT_NAME(WLC_E_BCNSENT_IND), - BCMEVENT_NAME(WLC_E_BCNRX_MSG), - BCMEVENT_NAME(WLC_E_BCNLOST_MSG), - BCMEVENT_NAME(WLC_E_ROAM_PREP), - BCMEVENT_NAME(WLC_E_PFN_NET_FOUND), - BCMEVENT_NAME(WLC_E_PFN_NET_LOST), -#if defined(IBSS_PEER_DISCOVERY_EVENT) - BCMEVENT_NAME(WLC_E_IBSS_ASSOC), -#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */ - BCMEVENT_NAME(WLC_E_RADIO), - BCMEVENT_NAME(WLC_E_PSM_WATCHDOG), - BCMEVENT_NAME(WLC_E_PROBREQ_MSG), - BCMEVENT_NAME(WLC_E_SCAN_CONFIRM_IND), - BCMEVENT_NAME(WLC_E_PSK_SUP), - BCMEVENT_NAME(WLC_E_COUNTRY_CODE_CHANGED), - BCMEVENT_NAME(WLC_E_EXCEEDED_MEDIUM_TIME), - BCMEVENT_NAME(WLC_E_ICV_ERROR), - BCMEVENT_NAME(WLC_E_UNICAST_DECODE_ERROR), - BCMEVENT_NAME(WLC_E_MULTICAST_DECODE_ERROR), - BCMEVENT_NAME(WLC_E_TRACE), - BCMEVENT_NAME(WLC_E_IF), -#ifdef WLP2P - BCMEVENT_NAME(WLC_E_P2P_DISC_LISTEN_COMPLETE), -#endif - BCMEVENT_NAME(WLC_E_RSSI), - BCMEVENT_NAME(WLC_E_PFN_SCAN_COMPLETE), - BCMEVENT_NAME(WLC_E_EXTLOG_MSG), -#ifdef WIFI_ACT_FRAME - BCMEVENT_NAME(WLC_E_ACTION_FRAME), - BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX), - BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE), -#endif -#ifdef BCMWAPI_WAI - BCMEVENT_NAME(WLC_E_WAI_STA_EVENT), - BCMEVENT_NAME(WLC_E_WAI_MSG), -#endif /* BCMWAPI_WAI */ - BCMEVENT_NAME(WLC_E_ESCAN_RESULT), - BCMEVENT_NAME(WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE), -#ifdef WLP2P - BCMEVENT_NAME(WLC_E_PROBRESP_MSG), - BCMEVENT_NAME(WLC_E_P2P_PROBREQ_MSG), -#endif -#ifdef PROP_TXSTATUS - BCMEVENT_NAME(WLC_E_FIFO_CREDIT_MAP), -#endif - BCMEVENT_NAME(WLC_E_WAKE_EVENT), - BCMEVENT_NAME(WLC_E_DCS_REQUEST), - BCMEVENT_NAME(WLC_E_RM_COMPLETE), -#ifdef WLMEDIA_HTSF - BCMEVENT_NAME(WLC_E_HTSFSYNC), -#endif - BCMEVENT_NAME(WLC_E_OVERLAY_REQ), - BCMEVENT_NAME(WLC_E_CSA_COMPLETE_IND), - BCMEVENT_NAME(WLC_E_EXCESS_PM_WAKE_EVENT), - BCMEVENT_NAME(WLC_E_PFN_SCAN_NONE), - BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE), -#ifdef SOFTAP - BCMEVENT_NAME(WLC_E_GTK_PLUMBED), -#endif - BCMEVENT_NAME(WLC_E_ASSOC_REQ_IE), - BCMEVENT_NAME(WLC_E_ASSOC_RESP_IE), - BCMEVENT_NAME(WLC_E_BEACON_FRAME_RX), -#ifdef WLTDLS - BCMEVENT_NAME(WLC_E_TDLS_PEER_EVENT), -#endif /* WLTDLS */ - BCMEVENT_NAME(WLC_E_NATIVE), -#ifdef WLPKTDLYSTAT - BCMEVENT_NAME(WLC_E_PKTDELAY_IND), -#endif /* WLPKTDLYSTAT */ - BCMEVENT_NAME(WLC_E_SERVICE_FOUND), - BCMEVENT_NAME(WLC_E_GAS_FRAGMENT_RX), - BCMEVENT_NAME(WLC_E_GAS_COMPLETE), - BCMEVENT_NAME(WLC_E_P2PO_ADD_DEVICE), - BCMEVENT_NAME(WLC_E_P2PO_DEL_DEVICE), -#ifdef WLWNM - BCMEVENT_NAME(WLC_E_WNM_STA_SLEEP), -#endif /* WLWNM */ -#if defined(WL_PROXDETECT) - BCMEVENT_NAME(WLC_E_PROXD), -#endif - BCMEVENT_NAME(WLC_E_CCA_CHAN_QUAL), - BCMEVENT_NAME(WLC_E_BSSID), -#ifdef PROP_TXSTATUS - BCMEVENT_NAME(WLC_E_BCMC_CREDIT_SUPPORT), -#endif - BCMEVENT_NAME(WLC_E_TXFAIL_THRESH), -#ifdef GSCAN_SUPPORT - BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT), -#endif /* GSCAN_SUPPORT */ -#ifdef WLBSSLOAD_REPORT - BCMEVENT_NAME(WLC_E_BSS_LOAD), -#endif -#if defined(BT_WIFI_HANDOVER) || defined(WL_TBOW) - BCMEVENT_NAME(WLC_E_BT_WIFI_HANDOVER_REQ), -#endif -#ifdef GSCAN_SUPPORT - BCMEVENT_NAME(WLC_E_PFN_SSID_EXT), -#endif /* GSCAN_SUPPORT */ -#ifdef WLFBT - BCMEVENT_NAME(WLC_E_FBT_AUTH_REQ_IND), -#endif /* WLFBT */ - BCMEVENT_NAME(WLC_E_RMC_EVENT), -}; - - -const char *bcmevent_get_name(uint event_type) -{ - /* note: first coded this as a static const but some - * ROMs already have something called event_name so - * changed it so we don't have a variable for the - * 'unknown string - */ - const char *event_name = NULL; - - uint idx; - for (idx = 0; idx < (uint)ARRAYSIZE(bcmevent_names); idx++) { - - if (bcmevent_names[idx].event == event_type) { - event_name = bcmevent_names[idx].name; - break; - } - } - - /* if we find an event name in the array, return it. - * otherwise return unknown string. - */ - return ((event_name) ? event_name : "Unknown Event"); -} - -/* - * Validate if the event is proper and if valid copy event header to event. - * If proper event pointer is passed, to just validate, pass NULL to event. - * - * Return values are - * BCME_OK - It is a BRCM event or BRCM dongle event - * BCME_NOTFOUND - Not BRCM, not an event, may be okay - * BCME_BADLEN - Bad length, should not process, just drop - */ -int -is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, - void *out_event) -{ - uint16 evlen; - uint16 subtype; - uint16 usr_subtype; - bcm_event_t *bcm_event; - uint8 *pktend; - uint8 *evend; - int err = BCME_OK; - uint32 data_len; - - pktend = (uint8 *)pktdata + pktlen; - bcm_event = (bcm_event_t *)pktdata; - - /* only care about 16-bit subtype / length versions */ - if ((uint8 *)&bcm_event->bcm_hdr < pktend) { - uint8 short_subtype = *(uint8 *)&bcm_event->bcm_hdr; - if (!(short_subtype & 0x80)) { - err = BCME_NOTFOUND; - goto done; - } - } - - /* must have both ether_header and bcmeth_hdr */ - if (pktlen < OFFSETOF(bcm_event_t, event)) { - err = BCME_BADLEN; - goto done; - } - - /* check length in bcmeth_hdr */ - evlen = ntoh16_ua((void *)&bcm_event->bcm_hdr.length); - evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen; - if (evend != pktend) { - err = BCME_BADLEN; - goto done; - } - - /* match on subtype, oui and usr subtype for BRCM events */ - subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.subtype); - if (subtype != BCMILCP_SUBTYPE_VENDOR_LONG) { - err = BCME_NOTFOUND; - goto done; - } - - if (bcmp(BRCM_OUI, &bcm_event->bcm_hdr.oui[0], DOT11_OUI_LEN)) { - err = BCME_NOTFOUND; - goto done; - } - - /* if it is a bcm_event, validate it */ - usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype); - switch (usr_subtype) { - case BCMILCP_BCM_SUBTYPE_EVENT: - if ((pktlen < sizeof(bcm_event_t)) || - (evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) { - err = BCME_BADLEN; - goto done; - } - - data_len = ntoh32_ua((void *)&bcm_event->event.datalen); - if ((sizeof(bcm_event_t) + data_len + - BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) { - err = BCME_BADLEN; - goto done; - } - - if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) { - err = BCME_NOTFOUND; - goto done; - } - - if (out_event) { - /* ensure BRCM event pkt aligned */ - memcpy(out_event, &bcm_event->event, sizeof(wl_event_msg_t)); - } - - break; - default: - err = BCME_NOTFOUND; - goto done; - } - -done: - return err; -} diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c deleted file mode 100644 index 920f3a51f5ea..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmsdh.c +++ /dev/null @@ -1,705 +0,0 @@ -/* - * BCMSDH interface glue - * implement bcmsdh API for SDIOH driver - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh.c 450676 2014-01-22 22:45:13Z $ - */ - -/** - * @file bcmsdh.c - */ - -/* ****************** BCMSDH Interface Functions *************************** */ - -#include -#include -#include -#include -#include -#include -#include - -#include /* BRCM API for SDIO clients (such as wl, dhd) */ -#include /* common SDIO/controller interface */ -#include /* SDIO device core hardware definitions. */ -#include /* SDIO Device and Protocol Specs */ - -#define SDIOH_API_ACCESS_RETRY_LIMIT 2 -const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; - -/* local copy of bcm sd handler */ -bcmsdh_info_t * l_bcmsdh = NULL; - - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) -extern int -sdioh_enable_hw_oob_intr(void *sdioh, bool enable); - -void -bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) -{ - sdioh_enable_hw_oob_intr(sdh->sdioh, enable); -} -#endif - -/* Attach BCMSDH layer to SDIO Host Controller Driver - * - * @param osh OSL Handle. - * @param cfghdl Configuration Handle. - * @param regsva Virtual address of controller registers. - * @param irq Interrupt number of SDIO controller. - * - * @return bcmsdh_info_t Handle to BCMSDH context. - */ -bcmsdh_info_t * -bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva) -{ - bcmsdh_info_t *bcmsdh; - - if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) { - BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); - return NULL; - } - bzero((char *)bcmsdh, sizeof(bcmsdh_info_t)); - bcmsdh->sdioh = sdioh; - bcmsdh->osh = osh; - bcmsdh->init_success = TRUE; - *regsva = SI_ENUM_BASE; - - /* Report the BAR, to fix if needed */ - bcmsdh->sbwad = SI_ENUM_BASE; - - /* save the handler locally */ - l_bcmsdh = bcmsdh; - - return bcmsdh; -} - -int -bcmsdh_detach(osl_t *osh, void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - if (bcmsdh != NULL) { - MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t)); - } - - l_bcmsdh = NULL; - - return 0; -} - -int -bcmsdh_iovar_op(void *sdh, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set); -} - -bool -bcmsdh_intr_query(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - bool on; - - ASSERT(bcmsdh); - status = sdioh_interrupt_query(bcmsdh->sdioh, &on); - if (SDIOH_API_SUCCESS(status)) - return FALSE; - else - return on; -} - -int -bcmsdh_intr_enable(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - ASSERT(bcmsdh); - - status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE); - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_intr_disable(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - ASSERT(bcmsdh); - - status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE); - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - ASSERT(bcmsdh); - - status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh); - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_intr_dereg(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - ASSERT(bcmsdh); - - status = sdioh_interrupt_deregister(bcmsdh->sdioh); - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -#if defined(DHD_DEBUG) -bool -bcmsdh_intr_pending(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - ASSERT(sdh); - return sdioh_interrupt_pending(bcmsdh->sdioh); -} -#endif - - -int -bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) -{ - ASSERT(sdh); - - /* don't support yet */ - return BCME_UNSUPPORTED; -} - -/** - * Read from SDIO Configuration Space - * @param sdh SDIO Host context. - * @param func_num Function number to read from. - * @param addr Address to read from. - * @param err Error return. - * @return value read from SDIO configuration space. - */ -uint8 -bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - int32 retry = 0; -#endif - uint8 data = 0; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - do { - if (retry) /* wait for 1 ms till bus get settled down */ - OSL_DELAY(1000); -#endif - status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); -#endif - if (err) - *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, - fnc_num, addr, data)); - - return data; -} - -void -bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - int32 retry = 0; -#endif - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - do { - if (retry) /* wait for 1 ms till bus get settled down */ - OSL_DELAY(1000); -#endif - status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); -#endif - if (err) - *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR; - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, - fnc_num, addr, data)); -} - -uint32 -bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - uint32 data = 0; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - - status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num, - addr, &data, 4); - - if (err) - *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, - fnc_num, addr, data)); - - return data; -} - -void -bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - - status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num, - addr, &data, 4); - - if (err) - *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num, - addr, data)); -} - - -int -bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - - uint8 *tmp_buf, *tmp_ptr; - uint8 *ptr; - bool ascii = func & ~0xf; - func &= 0x7; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - ASSERT(cis); - ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT); - - status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length); - - if (ascii) { - /* Move binary bits to tmp and format them into the provided buffer. */ - if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) { - BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__)); - return BCME_NOMEM; - } - bcopy(cis, tmp_buf, length); - for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) { - ptr += snprintf((char*)ptr, (cis + length - ptr - 4), - "%.2x ", *tmp_ptr & 0xff); - if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) - ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n"); - } - MFREE(bcmsdh->osh, tmp_buf, length); - } - - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - - -int -bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set) -{ - int err = 0; - uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK; - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - if (bar0 != bcmsdh->sbwad || force_set) { - bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, - (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); - if (!err) - bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, - (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); - if (!err) - bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, - (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); - - if (!err) - bcmsdh->sbwad = bar0; - else - /* invalidate cached window var */ - bcmsdh->sbwad = 0; - - } - - return err; -} - -uint32 -bcmsdh_reg_read(void *sdh, uint32 addr, uint size) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - uint32 word = 0; - - BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr)); - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - - if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)) - return 0xFFFFFFFF; - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - if (size == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - - status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, - SDIOH_READ, SDIO_FUNC_1, addr, &word, size); - - bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); - - BCMSDH_INFO(("uint32data = 0x%x\n", word)); - - /* if ok, return appropriately masked word */ - if (SDIOH_API_SUCCESS(status)) { - switch (size) { - case sizeof(uint8): - return (word & 0xff); - case sizeof(uint16): - return (word & 0xffff); - case sizeof(uint32): - return word; - default: - bcmsdh->regfail = TRUE; - - } - } - - /* otherwise, bad sdio access or invalid size */ - BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size)); - return 0xFFFFFFFF; -} - -uint32 -bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - int err = 0; - - BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", - __FUNCTION__, addr, size*8, data)); - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - - if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) - return err; - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - if (size == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1, - addr, &data, size); - bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); - - if (SDIOH_API_SUCCESS(status)) - return 0; - - BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n", - __FUNCTION__, data, addr, size)); - return 0xFFFFFFFF; -} - -bool -bcmsdh_regfail(void *sdh) -{ - return ((bcmsdh_info_t *)sdh)->regfail; -} - -int -bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete_fn, void *handle) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - uint incr_fix; - uint width; - int err = 0; - - ASSERT(bcmsdh); - ASSERT(bcmsdh->init_success); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", - __FUNCTION__, fn, addr, nbytes)); - - /* Async not implemented yet */ - ASSERT(!(flags & SDIO_REQ_ASYNC)); - if (flags & SDIO_REQ_ASYNC) - return BCME_UNSUPPORTED; - - if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) - return err; - - 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 = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, - SDIOH_READ, fn, addr, width, nbytes, buf, pkt); - - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); -} - -int -bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete_fn, void *handle) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - uint incr_fix; - uint width; - int err = 0; - - ASSERT(bcmsdh); - ASSERT(bcmsdh->init_success); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", - __FUNCTION__, fn, addr, nbytes)); - - /* Async not implemented yet */ - ASSERT(!(flags & SDIO_REQ_ASYNC)); - if (flags & SDIO_REQ_ASYNC) - return BCME_UNSUPPORTED; - - if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) - return err; - - 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 = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, - SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt); - - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - - ASSERT(bcmsdh); - ASSERT(bcmsdh->init_success); - ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0); - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - - status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC, - (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, - addr, 4, nbytes, buf, NULL); - - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_abort(void *sdh, uint fn) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_abort(bcmsdh->sdioh, fn); -} - -int -bcmsdh_start(void *sdh, int stage) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_start(bcmsdh->sdioh, stage); -} - -int -bcmsdh_stop(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_stop(bcmsdh->sdioh); -} - -int -bcmsdh_waitlockfree(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_waitlockfree(bcmsdh->sdioh); -} - - -int -bcmsdh_query_device(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0; - return (bcmsdh->vendevid); -} - -uint -bcmsdh_query_iofnum(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - return (sdioh_query_iofnum(bcmsdh->sdioh)); -} - -int -bcmsdh_reset(bcmsdh_info_t *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_sdio_reset(bcmsdh->sdioh); -} - -void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh) -{ - ASSERT(sdh); - return sdh->sdioh; -} - -/* Function to pass device-status bits to DHD. */ -uint32 -bcmsdh_get_dstatus(void *sdh) -{ - return 0; -} -uint32 -bcmsdh_cur_sbwad(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - return (bcmsdh->sbwad); -} - -void -bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev) -{ - return; -} - - -int -bcmsdh_sleep(void *sdh, bool enab) -{ -#ifdef SDIOH_SLEEP_ENABLED - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_sleep(sd, enab); -#else - return BCME_UNSUPPORTED; -#endif -} - -int -bcmsdh_gpio_init(void *sdh) -{ - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_gpio_init(sd); -} - -bool -bcmsdh_gpioin(void *sdh, uint32 gpio) -{ - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_gpioin(sd, gpio); -} - -int -bcmsdh_gpioouten(void *sdh, uint32 gpio) -{ - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_gpioouten(sd, gpio); -} - -int -bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) -{ - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_gpioout(sd, gpio, enab); -} diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c deleted file mode 100644 index c9efdb77874c..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * SDIO access interface for drivers - linux specific (pci only) - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh_linux.c 461444 2014-03-12 02:55:28Z $ - */ - -/** - * @file bcmsdh_linux.c - */ - -#define __UNDEF_NO_VERSION__ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -extern void dhdsdio_isr(void * args); -#include -#include -#include -#include - -/* driver info, initialized when bcmsdh_register is called */ -static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL}; - -typedef enum { - DHD_INTR_INVALID = 0, - DHD_INTR_INBAND, - DHD_INTR_HWOOB, - DHD_INTR_SWOOB -} DHD_HOST_INTR_TYPE; - -/* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g. - * bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather - * than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this - * structure. - */ -typedef struct bcmsdh_os_info { - DHD_HOST_INTR_TYPE intr_type; - int oob_irq_num; /* valid when hardware or software oob in use */ - unsigned long oob_irq_flags; /* valid when hardware or software oob in use */ - bool oob_irq_registered; - bool oob_irq_enabled; - bool oob_irq_wake_enabled; - spinlock_t oob_irq_spinlock; - bcmsdh_cb_fn_t oob_irq_handler; - void *oob_irq_handler_context; - void *context; /* context returned from upper layer */ - void *sdioh; /* handle to lower layer (sdioh) */ - void *dev; /* handle to the underlying device */ - bool dev_wake_enabled; -} bcmsdh_os_info_t; - -/* debugging macros */ -#define SDLX_MSG(x) - -/** - * Checks to see if vendor and device IDs match a supported SDIO Host Controller. - */ -bool -bcmsdh_chipmatch(uint16 vendor, uint16 device) -{ - /* Add other vendors and devices as required */ - -#ifdef BCMSDIOH_STD - /* Check for Arasan host controller */ - if (vendor == VENDOR_SI_IMAGE) { - return (TRUE); - } - /* Check for BRCM 27XX Standard host controller */ - if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) { - return (TRUE); - } - /* Check for BRCM Standard host controller */ - if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) { - return (TRUE); - } - /* Check for TI PCIxx21 Standard host controller */ - if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) { - return (TRUE); - } - if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) { - return (TRUE); - } - /* Ricoh R5C822 Standard SDIO Host */ - if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) { - return (TRUE); - } - /* JMicron Standard SDIO Host */ - if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) { - return (TRUE); - } - -#endif /* BCMSDIOH_STD */ -#ifdef BCMSDIOH_SPI - /* This is the PciSpiHost. */ - if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) { - printf("Found PCI SPI Host Controller\n"); - return (TRUE); - } - -#endif /* BCMSDIOH_SPI */ - - return (FALSE); -} - -void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, - uint bus_num, uint slot_num) -{ - ulong regs; - bcmsdh_info_t *bcmsdh; - uint32 vendevid; - bcmsdh_os_info_t *bcmsdh_osinfo = NULL; - - bcmsdh = bcmsdh_attach(osh, sdioh, ®s); - if (bcmsdh == NULL) { - SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__)); - goto err; - } - bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t)); - if (bcmsdh_osinfo == NULL) { - SDLX_MSG(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__)); - goto err; - } - bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); - bcmsdh->os_cxt = bcmsdh_osinfo; - bcmsdh_osinfo->sdioh = sdioh; - bcmsdh_osinfo->dev = dev; - osl_set_bus_handle(osh, bcmsdh); - -#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - if (dev && device_init_wakeup(dev, true) == 0) - bcmsdh_osinfo->dev_wake_enabled = TRUE; -#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ - -#if defined(OOB_INTR_ONLY) - spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock); - /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */ - bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info, - &bcmsdh_osinfo->oob_irq_flags); - if (bcmsdh_osinfo->oob_irq_num < 0) { - SDLX_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__)); - goto err; - } -#endif /* defined(BCMLXSDMMC) */ - - /* Read the vendor/device ID from the CIS */ - vendevid = bcmsdh_query_device(bcmsdh); - /* try to attach to the target device */ - bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num, - slot_num, 0, bus_type, (void *)regs, osh, bcmsdh); - if (bcmsdh_osinfo->context == NULL) { - SDLX_MSG(("%s: device attach failed\n", __FUNCTION__)); - goto err; - } - - return bcmsdh; - - /* error handling */ -err: - if (bcmsdh != NULL) - bcmsdh_detach(osh, bcmsdh); - if (bcmsdh_osinfo != NULL) - MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); - return NULL; -} - -int bcmsdh_remove(bcmsdh_info_t *bcmsdh) -{ - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - -#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - if (bcmsdh_osinfo->dev) - device_init_wakeup(bcmsdh_osinfo->dev, false); - bcmsdh_osinfo->dev_wake_enabled = FALSE; -#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ - - drvinfo.remove(bcmsdh_osinfo->context); - MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t)); - bcmsdh_detach(bcmsdh->osh, bcmsdh); - - return 0; -} - -int bcmsdh_suspend(bcmsdh_info_t *bcmsdh) -{ - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context)) - return -EBUSY; - return 0; -} - -int bcmsdh_resume(bcmsdh_info_t *bcmsdh) -{ - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - if (drvinfo.resume) - return drvinfo.resume(bcmsdh_osinfo->context); - return 0; -} - -extern int bcmsdh_register_client_driver(void); -extern void bcmsdh_unregister_client_driver(void); -extern int sdio_func_reg_notify(void* semaphore); -extern void sdio_func_unreg_notify(void); - -#if defined(BCMLXSDMMC) -int bcmsdh_reg_sdio_notify(void* semaphore) -{ - return sdio_func_reg_notify(semaphore); -} - -void bcmsdh_unreg_sdio_notify(void) -{ - sdio_func_unreg_notify(); -} -#endif /* defined(BCMLXSDMMC) */ - -int -bcmsdh_register(bcmsdh_driver_t *driver) -{ - int error = 0; - - drvinfo = *driver; - SDLX_MSG(("%s: register client driver\n", __FUNCTION__)); - error = bcmsdh_register_client_driver(); - if (error) - SDLX_MSG(("%s: failed %d\n", __FUNCTION__, error)); - - return error; -} - -void -bcmsdh_unregister(void) -{ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) - if (bcmsdh_pci_driver.node.next == NULL) - return; -#endif - - bcmsdh_unregister_client_driver(); -} - -void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh) -{ -#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - pm_stay_awake(bcmsdh_osinfo->dev); -#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ -} - -void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh) -{ -#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - pm_relax(bcmsdh_osinfo->dev); -#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ -} - -bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh) -{ - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - return bcmsdh_osinfo->dev_wake_enabled; -} - -#if defined(OOB_INTR_ONLY) -void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable) -{ - unsigned long flags; - bcmsdh_os_info_t *bcmsdh_osinfo; - - if (!bcmsdh) - return; - - bcmsdh_osinfo = bcmsdh->os_cxt; - spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags); - if (bcmsdh_osinfo->oob_irq_enabled != enable) { - if (enable) - enable_irq(bcmsdh_osinfo->oob_irq_num); - else - disable_irq_nosync(bcmsdh_osinfo->oob_irq_num); - bcmsdh_osinfo->oob_irq_enabled = enable; - } - spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags); -} - -static irqreturn_t wlan_oob_irq(int irq, void *dev_id) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id; - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - bcmsdh_oob_intr_set(bcmsdh, FALSE); - bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context); - - return IRQ_HANDLED; -} - -int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, - void* oob_irq_handler_context) -{ - int err = 0; - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - SDLX_MSG(("%s: Enter\n", __FUNCTION__)); - if (bcmsdh_osinfo->oob_irq_registered) { - SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__)); - return -EBUSY; - } - SDLX_MSG(("%s OOB irq=%d flags=%X \n", __FUNCTION__, - (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags)); - bcmsdh_osinfo->oob_irq_handler = oob_irq_handler; - bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context; - err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, - bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); - if (err) { - SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err)); - return err; - } - - err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num); - if (!err) - bcmsdh_osinfo->oob_irq_wake_enabled = TRUE; - bcmsdh_osinfo->oob_irq_enabled = TRUE; - bcmsdh_osinfo->oob_irq_registered = TRUE; - return err; -} - -void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh) -{ - int err = 0; - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - SDLX_MSG(("%s: Enter\n", __FUNCTION__)); - if (!bcmsdh_osinfo->oob_irq_registered) { - SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__)); - return; - } - if (bcmsdh_osinfo->oob_irq_wake_enabled) { - err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num); - if (!err) - bcmsdh_osinfo->oob_irq_wake_enabled = FALSE; - } - if (bcmsdh_osinfo->oob_irq_enabled) { - disable_irq(bcmsdh_osinfo->oob_irq_num); - bcmsdh_osinfo->oob_irq_enabled = FALSE; - } - free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh); - bcmsdh_osinfo->oob_irq_registered = FALSE; -} -#endif - -/* Module parameters specific to each host-controller driver */ - -extern uint sd_msglevel; /* Debug message level */ -module_param(sd_msglevel, uint, 0); - -extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */ -module_param(sd_power, uint, 0); - -extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */ -module_param(sd_clock, uint, 0); - -extern uint sd_divisor; /* Divisor (-1 means external clock) */ -module_param(sd_divisor, uint, 0); - -extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */ -module_param(sd_sdmode, uint, 0); - -extern uint sd_hiok; /* Ok to use hi-speed mode */ -module_param(sd_hiok, uint, 0); - -extern uint sd_f2_blocksize; -module_param(sd_f2_blocksize, int, 0); - -#ifdef BCMSDIOH_STD -extern int sd_uhsimode; -module_param(sd_uhsimode, int, 0); -extern uint sd_tuning_period; -module_param(sd_tuning_period, uint, 0); -extern int sd_delay_value; -module_param(sd_delay_value, uint, 0); - -/* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */ -extern char dhd_sdiod_uhsi_ds_override[2]; -module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0); - -#endif - -#ifdef BCMSDH_MODULE -EXPORT_SYMBOL(bcmsdh_attach); -EXPORT_SYMBOL(bcmsdh_detach); -EXPORT_SYMBOL(bcmsdh_intr_query); -EXPORT_SYMBOL(bcmsdh_intr_enable); -EXPORT_SYMBOL(bcmsdh_intr_disable); -EXPORT_SYMBOL(bcmsdh_intr_reg); -EXPORT_SYMBOL(bcmsdh_intr_dereg); - -#if defined(DHD_DEBUG) -EXPORT_SYMBOL(bcmsdh_intr_pending); -#endif - -EXPORT_SYMBOL(bcmsdh_devremove_reg); -EXPORT_SYMBOL(bcmsdh_cfg_read); -EXPORT_SYMBOL(bcmsdh_cfg_write); -EXPORT_SYMBOL(bcmsdh_cis_read); -EXPORT_SYMBOL(bcmsdh_reg_read); -EXPORT_SYMBOL(bcmsdh_reg_write); -EXPORT_SYMBOL(bcmsdh_regfail); -EXPORT_SYMBOL(bcmsdh_send_buf); -EXPORT_SYMBOL(bcmsdh_recv_buf); - -EXPORT_SYMBOL(bcmsdh_rwdata); -EXPORT_SYMBOL(bcmsdh_abort); -EXPORT_SYMBOL(bcmsdh_query_device); -EXPORT_SYMBOL(bcmsdh_query_iofnum); -EXPORT_SYMBOL(bcmsdh_iovar_op); -EXPORT_SYMBOL(bcmsdh_register); -EXPORT_SYMBOL(bcmsdh_unregister); -EXPORT_SYMBOL(bcmsdh_chipmatch); -EXPORT_SYMBOL(bcmsdh_reset); -EXPORT_SYMBOL(bcmsdh_waitlockfree); - -EXPORT_SYMBOL(bcmsdh_get_dstatus); -EXPORT_SYMBOL(bcmsdh_cfg_read_word); -EXPORT_SYMBOL(bcmsdh_cfg_write_word); -EXPORT_SYMBOL(bcmsdh_cur_sbwad); -EXPORT_SYMBOL(bcmsdh_chipinfo); - -#endif /* BCMSDH_MODULE */ diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c deleted file mode 100644 index cb042eba94af..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ /dev/null @@ -1,1456 +0,0 @@ -/* - * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh_sdmmc.c 459285 2014-03-03 02:54:39Z $ - */ -#include - -#include -#include -#include -#include -#include /* SDIO Device and Protocol Specs */ -#include /* Standard SDIO Host Controller Specification */ -#include /* bcmsdh to/from specific controller APIs */ -#include /* ioctl/iovars */ - -#include -#include -#include -#include -#include - -#include -#include - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -#include -extern volatile bool dhd_mmc_suspend; -#endif -#include "bcmsdh_sdmmc.h" - -#ifndef BCMSDH_MODULE -extern int sdio_function_init(void); -extern void sdio_function_cleanup(void); -#endif /* BCMSDH_MODULE */ - -#if !defined(OOB_INTR_ONLY) -static void IRQHandler(struct sdio_func *func); -static void IRQHandlerF2(struct sdio_func *func); -#endif /* !defined(OOB_INTR_ONLY) */ -static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); -extern int sdio_reset_comm(struct mmc_card *card); - -#define DEFAULT_SDIO_F2_BLKSIZE 512 -#ifndef CUSTOM_SDIO_F2_BLKSIZE -#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE -#endif - -#define MAX_IO_RW_EXTENDED_BLK 511 - -uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ -uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; -uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ - -uint sd_power = 1; /* Default to SD Slot powered ON */ -uint sd_clock = 1; /* Default to SD Clock turned ON */ -uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ -uint sd_msglevel = 0x01; -uint sd_use_dma = TRUE; - -#ifndef CUSTOM_RXCHAIN -#define CUSTOM_RXCHAIN 0 -#endif - -DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); -DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); -DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); -DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); - -#define DMA_ALIGN_MASK 0x03 -#define MMC_SDIO_ABORT_RETRY_LIMIT 5 - -int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); - -static int -sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) -{ - int err_ret; - uint32 fbraddr; - uint8 func; - - sd_trace(("%s\n", __FUNCTION__)); - - /* Get the Card's common CIS address */ - sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); - sd->func_cis_ptr[0] = sd->com_cis_ptr; - sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); - - /* Get the Card's function CIS (for each function) */ - for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; - func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { - sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); - sd_info(("%s: Function %d CIS Ptr = 0x%x\n", - __FUNCTION__, func, sd->func_cis_ptr[func])); - } - - sd->func_cis_ptr[0] = sd->com_cis_ptr; - sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); - - /* Enable Function 1 */ - sdio_claim_host(sd->func[1]); - err_ret = sdio_enable_func(sd->func[1]); - sdio_release_host(sd->func[1]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret)); - } - - return FALSE; -} - -/* - * Public entry points & extern's - */ -extern sdioh_info_t * -sdioh_attach(osl_t *osh, struct sdio_func *func) -{ - sdioh_info_t *sd = NULL; - int err_ret; - - sd_trace(("%s\n", __FUNCTION__)); - - if (func == NULL) { - sd_err(("%s: sdio function device is NULL\n", __FUNCTION__)); - return NULL; - } - - if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { - sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); - return NULL; - } - bzero((char *)sd, sizeof(sdioh_info_t)); - sd->osh = osh; - sd->fake_func0.num = 0; - sd->fake_func0.card = func->card; - sd->func[0] = &sd->fake_func0; - sd->func[1] = func->card->sdio_func[0]; - sd->func[2] = func->card->sdio_func[1]; - sd->num_funcs = 2; - sd->sd_blockmode = TRUE; - sd->use_client_ints = TRUE; - sd->client_block_size[0] = 64; - sd->use_rxchain = CUSTOM_RXCHAIN; - if (sd->func[1] == NULL || sd->func[2] == NULL) { - sd_err(("%s: func 1 or 2 is null \n", __FUNCTION__)); - goto fail; - } - sdio_set_drvdata(sd->func[1], sd); - - sdio_claim_host(sd->func[1]); - sd->client_block_size[1] = 64; - err_ret = sdio_set_block_size(sd->func[1], 64); - sdio_release_host(sd->func[1]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize(%d)\n", err_ret)); - goto fail; - } - - sdio_claim_host(sd->func[2]); - sd->client_block_size[2] = sd_f2_blocksize; - err_ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); - sdio_release_host(sd->func[2]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d(%d)\n", - sd_f2_blocksize, err_ret)); - goto fail; - } - - sdioh_sdmmc_card_enablefuncs(sd); - - sd_trace(("%s: Done\n", __FUNCTION__)); - return sd; - -fail: - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return NULL; -} - - -extern SDIOH_API_RC -sdioh_detach(osl_t *osh, sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - - if (sd) { - - /* Disable Function 2 */ - if (sd->func[2]) { - sdio_claim_host(sd->func[2]); - sdio_disable_func(sd->func[2]); - sdio_release_host(sd->func[2]); - } - - /* Disable Function 1 */ - if (sd->func[1]) { - sdio_claim_host(sd->func[1]); - sdio_disable_func(sd->func[1]); - sdio_release_host(sd->func[1]); - } - - sd->func[1] = NULL; - sd->func[2] = NULL; - - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - } - return SDIOH_API_RC_SUCCESS; -} - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) - -extern SDIOH_API_RC -sdioh_enable_func_intr(sdioh_info_t *sd) -{ - uint8 reg; - int err; - - if (sd->func[0] == NULL) { - sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - sdio_claim_host(sd->func[0]); - reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); - if (err) { - sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - sdio_release_host(sd->func[0]); - return SDIOH_API_RC_FAIL; - } - /* Enable F1 and F2 interrupts, clear master enable */ - reg &= ~INTR_CTL_MASTER_EN; - reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); - sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); - sdio_release_host(sd->func[0]); - - if (err) { - sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - return SDIOH_API_RC_FAIL; - } - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_disable_func_intr(sdioh_info_t *sd) -{ - uint8 reg; - int err; - - if (sd->func[0] == NULL) { - sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - sdio_claim_host(sd->func[0]); - reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); - if (err) { - sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - sdio_release_host(sd->func[0]); - return SDIOH_API_RC_FAIL; - } - reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); - /* Disable master interrupt with the last function interrupt */ - if (!(reg & 0xFE)) - reg = 0; - sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); - sdio_release_host(sd->func[0]); - - if (err) { - sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - return SDIOH_API_RC_FAIL; - } - - return SDIOH_API_RC_SUCCESS; -} -#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ - -/* Configure callback to client when we recieve client interrupt */ -extern SDIOH_API_RC -sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - if (fn == NULL) { - sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } -#if !defined(OOB_INTR_ONLY) - sd->intr_handler = fn; - sd->intr_handler_arg = argh; - sd->intr_handler_valid = TRUE; - - /* register and unmask irq */ - if (sd->func[2]) { - sdio_claim_host(sd->func[2]); - sdio_claim_irq(sd->func[2], IRQHandlerF2); - sdio_release_host(sd->func[2]); - } - - if (sd->func[1]) { - sdio_claim_host(sd->func[1]); - sdio_claim_irq(sd->func[1], IRQHandler); - sdio_release_host(sd->func[1]); - } -#elif defined(HW_OOB) - sdioh_enable_func_intr(sd); -#endif /* !defined(OOB_INTR_ONLY) */ - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_deregister(sdioh_info_t *sd) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - -#if !defined(OOB_INTR_ONLY) - if (sd->func[1]) { - /* register and unmask irq */ - sdio_claim_host(sd->func[1]); - sdio_release_irq(sd->func[1]); - sdio_release_host(sd->func[1]); - } - - if (sd->func[2]) { - /* Claim host controller F2 */ - sdio_claim_host(sd->func[2]); - sdio_release_irq(sd->func[2]); - /* Release host controller F2 */ - sdio_release_host(sd->func[2]); - } - - sd->intr_handler_valid = FALSE; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; -#elif defined(HW_OOB) - sdioh_disable_func_intr(sd); -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - *onoff = sd->client_intr_enabled; - return SDIOH_API_RC_SUCCESS; -} - -#if defined(DHD_DEBUG) -extern bool -sdioh_interrupt_pending(sdioh_info_t *sd) -{ - return (0); -} -#endif - -uint -sdioh_query_iofnum(sdioh_info_t *sd) -{ - return sd->num_funcs; -} - -/* IOVar table */ -enum { - IOV_MSGLEVEL = 1, - IOV_BLOCKMODE, - IOV_BLOCKSIZE, - IOV_DMA, - IOV_USEINTS, - IOV_NUMINTS, - IOV_NUMLOCALINTS, - IOV_HOSTREG, - IOV_DEVREG, - IOV_DIVISOR, - IOV_SDMODE, - IOV_HISPEED, - IOV_HCIREGS, - IOV_POWER, - IOV_CLOCK, - IOV_RXCHAIN -}; - -const bcm_iovar_t sdioh_iovars[] = { - {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, - {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, - {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ - {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, - {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, - {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, - {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, - {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, - {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, - {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, - {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, - {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 }, - {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -int -sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - int32 int_val = 0; - bool bool_val; - uint32 actionid; - - ASSERT(name); - ASSERT(len >= 0); - - /* Get must have return space; Set does not take qualifiers */ - ASSERT(set || (arg && len)); - ASSERT(!set || (!params && !plen)); - - sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); - - if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) - goto exit; - - /* Set up params so get and set can share the convenience variables */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - val_size = sizeof(int); - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - BCM_REFERENCE(bool_val); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - switch (actionid) { - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)sd_msglevel; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): - sd_msglevel = int_val; - break; - - case IOV_GVAL(IOV_BLOCKMODE): - int_val = (int32)si->sd_blockmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_BLOCKMODE): - si->sd_blockmode = (bool)int_val; - /* Haven't figured out how to make non-block mode with DMA */ - break; - - case IOV_GVAL(IOV_BLOCKSIZE): - if ((uint32)int_val > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - int_val = (int32)si->client_block_size[int_val]; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_BLOCKSIZE): - { - uint func = ((uint32)int_val >> 16); - uint blksize = (uint16)int_val; - uint maxsize; - - if (func > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - - switch (func) { - case 0: maxsize = 32; break; - case 1: maxsize = BLOCK_SIZE_4318; break; - case 2: maxsize = BLOCK_SIZE_4328; break; - default: maxsize = 0; - } - if (blksize > maxsize) { - bcmerror = BCME_BADARG; - break; - } - if (!blksize) { - blksize = maxsize; - } - - /* Now set it */ - si->client_block_size[func] = blksize; - - break; - } - - case IOV_GVAL(IOV_RXCHAIN): - int_val = (int32)si->use_rxchain; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DMA): - int_val = (int32)si->sd_use_dma; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DMA): - si->sd_use_dma = (bool)int_val; - break; - - case IOV_GVAL(IOV_USEINTS): - int_val = (int32)si->use_client_ints; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_USEINTS): - si->use_client_ints = (bool)int_val; - if (si->use_client_ints) - si->intmask |= CLIENT_INTR; - else - si->intmask &= ~CLIENT_INTR; - - break; - - case IOV_GVAL(IOV_DIVISOR): - int_val = (uint32)sd_divisor; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DIVISOR): - sd_divisor = int_val; - break; - - case IOV_GVAL(IOV_POWER): - int_val = (uint32)sd_power; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POWER): - sd_power = int_val; - break; - - case IOV_GVAL(IOV_CLOCK): - int_val = (uint32)sd_clock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CLOCK): - sd_clock = int_val; - break; - - case IOV_GVAL(IOV_SDMODE): - int_val = (uint32)sd_sdmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDMODE): - sd_sdmode = int_val; - break; - - case IOV_GVAL(IOV_HISPEED): - int_val = (uint32)sd_hiok; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HISPEED): - sd_hiok = int_val; - break; - - case IOV_GVAL(IOV_NUMINTS): - int_val = (int32)si->intrcount; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_NUMLOCALINTS): - int_val = (int32)0; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_HOSTREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - - if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { - sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); - bcmerror = BCME_BADARG; - break; - } - - sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__, - (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), - sd_ptr->offset)); - if (sd_ptr->offset & 1) - int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */ - else if (sd_ptr->offset & 2) - int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */ - else - int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */ - - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_HOSTREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - - if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { - sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); - bcmerror = BCME_BADARG; - break; - } - - sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value, - (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), - sd_ptr->offset)); - break; - } - - case IOV_GVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = 0; - - if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - - int_val = (int)data; - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = (uint8)sd_ptr->value; - - if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - } - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } -exit: - - return bcmerror; -} - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) - -SDIOH_API_RC -sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) -{ - SDIOH_API_RC status; - uint8 data; - - if (enable) - data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; - else - data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ - - status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); - return status; -} -#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ - -extern SDIOH_API_RC -sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - SDIOH_API_RC status; - /* No lock needed since sdioh_request_byte does locking */ - status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - /* No lock needed since sdioh_request_byte does locking */ - SDIOH_API_RC status; - status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); - return status; -} - -static int -sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) -{ - /* read 24 bits and return valid 17 bit addr */ - int i; - uint32 scratch, regdata; - uint8 *ptr = (uint8 *)&scratch; - for (i = 0; i < 3; i++) { - if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) - sd_err(("%s: Can't read!\n", __FUNCTION__)); - - *ptr++ = (uint8) regdata; - regaddr++; - } - - /* Only the lower 17-bits are valid */ - scratch = ltoh32(scratch); - scratch &= 0x0001FFFF; - return (scratch); -} - -extern SDIOH_API_RC -sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) -{ - uint32 count; - int offset; - uint32 foo; - uint8 *cis = cisd; - - sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); - - if (!sd->func_cis_ptr[func]) { - bzero(cis, length); - sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); - return SDIOH_API_RC_FAIL; - } - - sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); - - for (count = 0; count < length; count++) { - offset = sd->func_cis_ptr[func] + count; - if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { - sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - *cis = (uint8)(foo & 0xff); - cis++; - } - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) -{ - int err_ret = 0; -#if defined(MMC_SDIO_ABORT) - int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; -#endif - - sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); - - DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - if(rw) { /* CMD52 Write */ - if (func == 0) { - /* Can only directly write to some F0 registers. Handle F2 enable - * as a special case. - */ - if (regaddr == SDIOD_CCCR_IOEN) { - if (sd->func[2]) { - sdio_claim_host(sd->func[2]); - if (*byte & SDIO_FUNC_ENABLE_2) { - /* Enable Function 2 */ - err_ret = sdio_enable_func(sd->func[2]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: enable F2 failed:%d", - err_ret)); - } - } else { - /* Disable Function 2 */ - err_ret = sdio_disable_func(sd->func[2]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d", - err_ret)); - } - } - sdio_release_host(sd->func[2]); - } - } -#if defined(MMC_SDIO_ABORT) - /* to allow abort command through F1 */ - else if (regaddr == SDIOD_CCCR_IOABORT) { - while (sdio_abort_retry--) { - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - /* - * this sdio_f0_writeb() can be replaced with - * another api depending upon MMC driver change. - * As of this time, this is temporaray one - */ - sdio_writeb(sd->func[func], - *byte, regaddr, &err_ret); - sdio_release_host(sd->func[func]); - } - if (!err_ret) - break; - } - } -#endif /* MMC_SDIO_ABORT */ - else if (regaddr < 0xF0) { - sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); - } else { - /* Claim host controller, perform F0 write, and release */ - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - sdio_f0_writeb(sd->func[func], - *byte, regaddr, &err_ret); - sdio_release_host(sd->func[func]); - } - } - } else { - /* Claim host controller, perform Fn write, and release */ - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - sdio_writeb(sd->func[func], *byte, regaddr, &err_ret); - sdio_release_host(sd->func[func]); - } - } - } else { /* CMD52 Read */ - /* Claim host controller, perform Fn read, and release */ - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - if (func == 0) { - *byte = sdio_f0_readb(sd->func[func], regaddr, &err_ret); - } else { - *byte = sdio_readb(sd->func[func], regaddr, &err_ret); - } - sdio_release_host(sd->func[func]); - } - } - - if (err_ret) { - if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ))) { - } else { - sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", - rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); - } - } - - return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -extern SDIOH_API_RC -sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, - uint32 *word, uint nbytes) -{ - int err_ret = SDIOH_API_RC_FAIL; -#if defined(MMC_SDIO_ABORT) - int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; -#endif - - if (func == 0) { - sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", - __FUNCTION__, cmd_type, rw, func, addr, nbytes)); - - DHD_PM_RESUME_WAIT(sdioh_request_word_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - /* Claim host controller */ - sdio_claim_host(sd->func[func]); - - if(rw) { /* CMD52 Write */ - if (nbytes == 4) { - sdio_writel(sd->func[func], *word, addr, &err_ret); - } else if (nbytes == 2) { - sdio_writew(sd->func[func], (*word & 0xFFFF), addr, &err_ret); - } else { - sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); - } - } else { /* CMD52 Read */ - if (nbytes == 4) { - *word = sdio_readl(sd->func[func], addr, &err_ret); - } else if (nbytes == 2) { - *word = sdio_readw(sd->func[func], addr, &err_ret) & 0xFFFF; - } else { - sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); - } - } - - /* Release host controller */ - sdio_release_host(sd->func[func]); - - if (err_ret) { -#if defined(MMC_SDIO_ABORT) - /* Any error on CMD53 transaction should abort that function using function 0. */ - while (sdio_abort_retry--) { - if (sd->func[0]) { - sdio_claim_host(sd->func[0]); - /* - * this sdio_f0_writeb() can be replaced with another api - * depending upon MMC driver change. - * As of this time, this is temporaray one - */ - sdio_writeb(sd->func[0], - func, SDIOD_CCCR_IOABORT, &err_ret); - sdio_release_host(sd->func[0]); - } - if (!err_ret) - break; - } - if (err_ret) -#endif /* MMC_SDIO_ABORT */ - { - sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x", - rw ? "Write" : "Read", err_ret)); - } - } - - return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -static SDIOH_API_RC -sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func, - uint addr, void *pkt) -{ - bool fifo = (fix_inc == SDIOH_DATA_FIX); - int err_ret = 0; - void *pnext; - uint ttl_len, pkt_offset; - uint blk_num; - uint blk_size; - uint max_blk_count; - uint max_req_size; - struct mmc_request mmc_req; - struct mmc_command mmc_cmd; - struct mmc_data mmc_dat; - uint32 sg_count; - struct sdio_func *sdio_func = sd->func[func]; - struct mmc_host *host = sdio_func->card->host; - - sd_trace(("%s: Enter\n", __FUNCTION__)); - ASSERT(pkt); - DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - - blk_size = sd->client_block_size[func]; - max_blk_count = min(host->max_blk_count, (uint)MAX_IO_RW_EXTENDED_BLK); - max_req_size = min(max_blk_count * blk_size, host->max_req_size); - - pkt_offset = 0; - pnext = pkt; - - while (pnext != NULL) { - ttl_len = 0; - sg_count = 0; - memset(&mmc_req, 0, sizeof(struct mmc_request)); - memset(&mmc_cmd, 0, sizeof(struct mmc_command)); - memset(&mmc_dat, 0, sizeof(struct mmc_data)); - sg_init_table(sd->sg_list, ARRAYSIZE(sd->sg_list)); - - /* Set up scatter-gather DMA descriptors. this loop is to find out the max - * data we can transfer with one command 53. blocks per command is limited by - * host max_req_size and 9-bit max block number. when the total length of this - * packet chain is bigger than max_req_size, use multiple SD_IO_RW_EXTENDED - * commands (each transfer is still block aligned) - */ - while (pnext != NULL && ttl_len < max_req_size) { - int pkt_len; - int sg_data_size; - uint8 *pdata = (uint8*)PKTDATA(sd->osh, pnext); - - ASSERT(pdata != NULL); - pkt_len = PKTLEN(sd->osh, pnext); - sd_trace(("%s[%d] data=%p, len=%d\n", __FUNCTION__, write, pdata, pkt_len)); - /* sg_count is unlikely larger than the array size, and this is - * NOT something we can handle here, but in case it happens, PLEASE put - * a restriction on max tx/glom count (based on host->max_segs). - */ - if (sg_count >= ARRAYSIZE(sd->sg_list)) { - sd_err(("%s: sg list entries exceed limit\n", __FUNCTION__)); - return (SDIOH_API_RC_FAIL); - } - pdata += pkt_offset; - - sg_data_size = pkt_len - pkt_offset; - if (sg_data_size > max_req_size - ttl_len) - sg_data_size = max_req_size - ttl_len; - /* some platforms put a restriction on the data size of each scatter-gather - * DMA descriptor, use multiple sg buffers when xfer_size is bigger than - * max_seg_size - */ - if (sg_data_size > host->max_seg_size) - sg_data_size = host->max_seg_size; - sg_set_buf(&sd->sg_list[sg_count++], pdata, sg_data_size); - - ttl_len += sg_data_size; - pkt_offset += sg_data_size; - if (pkt_offset == pkt_len) { - pnext = PKTNEXT(sd->osh, pnext); - pkt_offset = 0; - } - } - - if (ttl_len % blk_size != 0) { - sd_err(("%s, data length %d not aligned to block size %d\n", - __FUNCTION__, ttl_len, blk_size)); - return SDIOH_API_RC_FAIL; - } - blk_num = ttl_len / blk_size; - mmc_dat.sg = sd->sg_list; - mmc_dat.sg_len = sg_count; - mmc_dat.blksz = blk_size; - mmc_dat.blocks = blk_num; - mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; - mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ - mmc_cmd.arg = write ? 1<<31 : 0; - mmc_cmd.arg |= (func & 0x7) << 28; - mmc_cmd.arg |= 1<<27; - mmc_cmd.arg |= fifo ? 0 : 1<<26; - mmc_cmd.arg |= (addr & 0x1FFFF) << 9; - mmc_cmd.arg |= blk_num & 0x1FF; - mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; - mmc_req.cmd = &mmc_cmd; - mmc_req.data = &mmc_dat; - if (!fifo) - addr += ttl_len; - - sdio_claim_host(sdio_func); - mmc_set_data_timeout(&mmc_dat, sdio_func->card); - mmc_wait_for_req(host, &mmc_req); - sdio_release_host(sdio_func); - - err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; - if (0 != err_ret) { - sd_err(("%s:CMD53 %s failed with code %d\n", - __FUNCTION__, write ? "write" : "read", err_ret)); - return SDIOH_API_RC_FAIL; - } - } - - sd_trace(("%s: Exit\n", __FUNCTION__)); - return SDIOH_API_RC_SUCCESS; -} - -static SDIOH_API_RC -sdioh_buffer_tofrom_bus(sdioh_info_t *sd, uint fix_inc, uint write, uint func, - uint addr, uint8 *buf, uint len) -{ - bool fifo = (fix_inc == SDIOH_DATA_FIX); - int err_ret = 0; - - sd_trace(("%s: Enter\n", __FUNCTION__)); - ASSERT(buf); - - /* NOTE: - * For all writes, each packet length is aligned to 32 (or 4) - * bytes in dhdsdio_txpkt_preprocess, and for glom the last packet length - * is aligned to block boundary. If you want to align each packet to - * a custom size, please do it in dhdsdio_txpkt_preprocess, NOT here - * - * For reads, the alignment is doen in sdioh_request_buffer. - * - */ - sdio_claim_host(sd->func[func]); - - if ((write) && (!fifo)) - err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); - else if (write) - err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); - else if (fifo) - err_ret = sdio_readsb(sd->func[func], buf, addr, len); - else - err_ret = sdio_memcpy_fromio(sd->func[func], buf, addr, len); - - sdio_release_host(sd->func[func]); - - if (err_ret) - sd_err(("%s: %s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=%d\n", __FUNCTION__, - (write) ? "TX" : "RX", buf, addr, len, err_ret)); - else - sd_trace(("%s: %s xfr'd %p, addr=0x%05x, len=%d\n", __FUNCTION__, - (write) ? "TX" : "RX", buf, addr, len)); - - sd_trace(("%s: Exit\n", __FUNCTION__)); - return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - - -/* - * 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. - * - */ -extern SDIOH_API_RC -sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, - uint addr, uint reg_width, uint buf_len, uint8 *buffer, void *pkt) -{ - SDIOH_API_RC status; - void *tmppkt; - - sd_trace(("%s: Enter\n", __FUNCTION__)); - DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - - if (pkt) { - /* packet chain, only used for tx/rx glom, all packets length - * are aligned, total length is a block multiple - */ - if (PKTNEXT(sd->osh, pkt)) - return sdioh_request_packet_chain(sd, fix_inc, write, func, addr, pkt); - - /* non-glom mode, ignore the buffer parameter and use the packet pointer - * (this shouldn't happen) - */ - buffer = PKTDATA(sd->osh, pkt); - buf_len = PKTLEN(sd->osh, pkt); - } - - ASSERT(buffer); - - /* buffer and length are aligned, use it directly so we can avoid memory copy */ - if (((ulong)buffer & DMA_ALIGN_MASK) == 0 && (buf_len & DMA_ALIGN_MASK) == 0) - return sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, buffer, buf_len); - - sd_err(("%s: [%d] doing memory copy buf=%p, len=%d\n", - __FUNCTION__, write, buffer, buf_len)); - - /* otherwise, a memory copy is needed as the input buffer is not aligned */ - tmppkt = PKTGET_STATIC(sd->osh, buf_len + DEFAULT_SDIO_F2_BLKSIZE, write ? TRUE : FALSE); - if (tmppkt == NULL) { - sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, buf_len)); - return SDIOH_API_RC_FAIL; - } - - if (write) - bcopy(buffer, PKTDATA(sd->osh, tmppkt), buf_len); - - status = sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, - PKTDATA(sd->osh, tmppkt), ROUNDUP(buf_len, (DMA_ALIGN_MASK+1))); - - if (!write) - bcopy(PKTDATA(sd->osh, tmppkt), buffer, buf_len); - - PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE); - - return status; -} - -/* this function performs "abort" for both of host & device */ -extern int -sdioh_abort(sdioh_info_t *sd, uint func) -{ -#if defined(MMC_SDIO_ABORT) - char t_func = (char) func; -#endif /* defined(MMC_SDIO_ABORT) */ - sd_trace(("%s: Enter\n", __FUNCTION__)); - -#if defined(MMC_SDIO_ABORT) - /* issue abort cmd52 command through F1 */ - sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); -#endif /* defined(MMC_SDIO_ABORT) */ - - sd_trace(("%s: Exit\n", __FUNCTION__)); - return SDIOH_API_RC_SUCCESS; -} - -/* Reset and re-initialize the device */ -int sdioh_sdio_reset(sdioh_info_t *si) -{ - sd_trace(("%s: Enter\n", __FUNCTION__)); - sd_trace(("%s: Exit\n", __FUNCTION__)); - return SDIOH_API_RC_SUCCESS; -} - -/* Disable device interrupt */ -void -sdioh_sdmmc_devintr_off(sdioh_info_t *sd) -{ - sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); - sd->intmask &= ~CLIENT_INTR; -} - -/* Enable device interrupt */ -void -sdioh_sdmmc_devintr_on(sdioh_info_t *sd) -{ - sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); - sd->intmask |= CLIENT_INTR; -} - -/* Read client card reg */ -int -sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - - if ((func == 0) || (regsize == 1)) { - uint8 temp = 0; - - sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); - *data = temp; - *data &= 0xff; - sd_data(("%s: byte read data=0x%02x\n", - __FUNCTION__, *data)); - } else { - sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize); - if (regsize == 2) - *data &= 0xffff; - - sd_data(("%s: word read data=0x%08x\n", - __FUNCTION__, *data)); - } - - return SUCCESS; -} - -#if !defined(OOB_INTR_ONLY) -/* bcmsdh_sdmmc interrupt handler */ -static void IRQHandler(struct sdio_func *func) -{ - sdioh_info_t *sd; - - sd = sdio_get_drvdata(func); - - ASSERT(sd != NULL); - sdio_release_host(sd->func[0]); - - if (sd->use_client_ints) { - sd->intrcount++; - ASSERT(sd->intr_handler); - ASSERT(sd->intr_handler_arg); - (sd->intr_handler)(sd->intr_handler_arg); - } else { - sd_err(("bcmsdh_sdmmc: ***IRQHandler\n")); - - sd_err(("%s: Not ready for intr: enabled %d, handler %p\n", - __FUNCTION__, sd->client_intr_enabled, sd->intr_handler)); - } - - sdio_claim_host(sd->func[0]); -} - -/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ -static void IRQHandlerF2(struct sdio_func *func) -{ - sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n")); -} -#endif /* !defined(OOB_INTR_ONLY) */ - -#ifdef NOTUSED -/* Write client card reg */ -static int -sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) -{ - - if ((func == 0) || (regsize == 1)) { - uint8 temp; - - temp = data & 0xff; - sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); - sd_data(("%s: byte write data=0x%02x\n", - __FUNCTION__, data)); - } else { - if (regsize == 2) - data &= 0xffff; - - sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); - - sd_data(("%s: word write data=0x%08x\n", - __FUNCTION__, data)); - } - - return SUCCESS; -} -#endif /* NOTUSED */ - -int -sdioh_start(sdioh_info_t *sd, int stage) -{ - int ret; - - if (!sd) { - sd_err(("%s Failed, sd is NULL\n", __FUNCTION__)); - return (0); - } - - /* Need to do this stages as we can't enable the interrupt till - downloading of the firmware is complete, other wise polling - sdio access will come in way - */ - if (sd->func[0]) { - if (stage == 0) { - /* Since the power to the chip is killed, we will have - re enumerate the device again. Set the block size - and enable the fucntion 1 for in preparation for - downloading the code - */ - /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux - 2.6.27. The implementation prior to that is buggy, and needs broadcom's - patch for it - */ - if ((ret = sdio_reset_comm(sd->func[0]->card))) { - sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); - return ret; - } - else { - sd->num_funcs = 2; - sd->sd_blockmode = TRUE; - sd->use_client_ints = TRUE; - sd->client_block_size[0] = 64; - - if (sd->func[1]) { - /* Claim host controller */ - sdio_claim_host(sd->func[1]); - - sd->client_block_size[1] = 64; - ret = sdio_set_block_size(sd->func[1], 64); - if (ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 " - "blocksize(%d)\n", ret)); - } - - /* Release host controller F1 */ - sdio_release_host(sd->func[1]); - } - - if (sd->func[2]) { - /* Claim host controller F2 */ - sdio_claim_host(sd->func[2]); - - sd->client_block_size[2] = sd_f2_blocksize; - ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); - if (ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F2 " - "blocksize to %d(%d)\n", sd_f2_blocksize, ret)); - } - - /* Release host controller F2 */ - sdio_release_host(sd->func[2]); - } - - sdioh_sdmmc_card_enablefuncs(sd); - } - } else { -#if !defined(OOB_INTR_ONLY) - sdio_claim_host(sd->func[0]); - if (sd->func[2]) - sdio_claim_irq(sd->func[2], IRQHandlerF2); - if (sd->func[1]) - sdio_claim_irq(sd->func[1], IRQHandler); - sdio_release_host(sd->func[0]); -#else /* defined(OOB_INTR_ONLY) */ -#if defined(HW_OOB) - sdioh_enable_func_intr(sd); -#endif - bcmsdh_oob_intr_set(sd->bcmsdh, TRUE); -#endif /* !defined(OOB_INTR_ONLY) */ - } - } - else - sd_err(("%s Failed\n", __FUNCTION__)); - - return (0); -} - -int -sdioh_stop(sdioh_info_t *sd) -{ - /* MSM7201A Android sdio stack has bug with interrupt - So internaly within SDIO stack they are polling - which cause issue when device is turned off. So - unregister interrupt with SDIO stack to stop the - polling - */ - if (sd->func[0]) { -#if !defined(OOB_INTR_ONLY) - sdio_claim_host(sd->func[0]); - if (sd->func[1]) - sdio_release_irq(sd->func[1]); - if (sd->func[2]) - sdio_release_irq(sd->func[2]); - sdio_release_host(sd->func[0]); -#else /* defined(OOB_INTR_ONLY) */ -#if defined(HW_OOB) - sdioh_disable_func_intr(sd); -#endif - bcmsdh_oob_intr_set(sd->bcmsdh, FALSE); -#endif /* !defined(OOB_INTR_ONLY) */ - } - else - sd_err(("%s Failed\n", __FUNCTION__)); - return (0); -} - -int -sdioh_waitlockfree(sdioh_info_t *sd) -{ - return (1); -} - - -SDIOH_API_RC -sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) -{ - return SDIOH_API_RC_FAIL; -} - -SDIOH_API_RC -sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) -{ - return SDIOH_API_RC_FAIL; -} - -bool -sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) -{ - return FALSE; -} - -SDIOH_API_RC -sdioh_gpio_init(sdioh_info_t *sd) -{ - return SDIOH_API_RC_FAIL; -} diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c deleted file mode 100644 index 9753e2c6981a..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh_sdmmc_linux.c 434777 2013-11-07 09:30:27Z $ - */ - -#include -#include -#include /* SDIO Device and Protocol Specs */ -#include /* bcmsdh to/from specific controller APIs */ -#include /* to get msglevel bit values */ - -#include /* request_irq() */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(SDIO_VENDOR_ID_BROADCOM) -#define SDIO_VENDOR_ID_BROADCOM 0x02d0 -#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ - -#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 - -#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) -#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4325) -#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4329) -#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) -#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) -#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) -#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4324) -#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) -#define SDIO_DEVICE_ID_BROADCOM_43239 43239 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ - -extern void wl_cfg80211_set_parent_dev(void *dev); -extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); -extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); -extern void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, - uint bus_num, uint slot_num); -extern int bcmsdh_remove(bcmsdh_info_t *bcmsdh); - -int sdio_function_init(void); -void sdio_function_cleanup(void); - -#define DESCRIPTION "bcmsdh_sdmmc Driver" -#define AUTHOR "Broadcom Corporation" - -/* module param defaults */ -static int clockoverride = 0; - -module_param(clockoverride, int, 0644); -MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); - -/* Maximum number of bcmsdh_sdmmc devices supported by driver */ -#define BCMSDH_SDMMC_MAX_DEVICES 1 - -extern volatile bool dhd_mmc_suspend; - -static int sdioh_probe(struct sdio_func *func) -{ - int host_idx = func->card->host->index; - uint32 rca = func->card->rca; - wifi_adapter_info_t *adapter; - osl_t *osh = NULL; - sdioh_info_t *sdioh = NULL; - - sd_err(("bus num (host idx)=%d, slot num (rca)=%d\n", host_idx, rca)); - adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca); - if (adapter != NULL) - sd_err(("found adapter info '%s'\n", adapter->name)); - else - sd_err(("can't find adapter info for this chip\n")); - -#ifdef WL_CFG80211 - wl_cfg80211_set_parent_dev(&func->dev); -#endif - - /* allocate SDIO Host Controller state info */ - osh = osl_attach(&func->dev, SDIO_BUS, TRUE); - if (osh == NULL) { - sd_err(("%s: osl_attach failed\n", __FUNCTION__)); - goto fail; - } - osl_static_mem_init(osh, adapter); - sdioh = sdioh_attach(osh, func); - if (sdioh == NULL) { - sd_err(("%s: sdioh_attach failed\n", __FUNCTION__)); - goto fail; - } - sdioh->bcmsdh = bcmsdh_probe(osh, &func->dev, sdioh, adapter, SDIO_BUS, host_idx, rca); - if (sdioh->bcmsdh == NULL) { - sd_err(("%s: bcmsdh_probe failed\n", __FUNCTION__)); - goto fail; - } - - sdio_set_drvdata(func, sdioh); - return 0; - -fail: - if (sdioh != NULL) - sdioh_detach(osh, sdioh); - if (osh != NULL) - osl_detach(osh); - return -ENOMEM; -} - -static void sdioh_remove(struct sdio_func *func) -{ - sdioh_info_t *sdioh; - osl_t *osh; - - sdioh = sdio_get_drvdata(func); - if (sdioh == NULL) { - sd_err(("%s: error, no sdioh handler found\n", __FUNCTION__)); - return; - } - - osh = sdioh->osh; - bcmsdh_remove(sdioh->bcmsdh); - sdioh_detach(osh, sdioh); - osl_detach(osh); -} - -static int bcmsdh_sdmmc_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - int ret = 0; - - if (func == NULL) - return -EINVAL; - - sd_err(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); - sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); - sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); - sd_info(("sdio_device: 0x%04x\n", func->device)); - sd_info(("Function#: 0x%04x\n", func->num)); - - /* 4318 doesn't have function 2 */ - if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) - ret = sdioh_probe(func); - - return ret; -} - -static void bcmsdh_sdmmc_remove(struct sdio_func *func) -{ - if (func == NULL) { - sd_err(("%s is called with NULL SDIO function pointer\n", __FUNCTION__)); - return; - } - - sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); - sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); - sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); - sd_info(("sdio_device: 0x%04x\n", func->device)); - sd_info(("Function#: 0x%04x\n", func->num)); - - if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) - sdioh_remove(func); -} - -/* devices we support, null terminated */ -static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, - { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, - { /* end: all zeroes */ }, -}; - -MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) -static int bcmsdh_sdmmc_suspend(struct device *pdev) -{ - int err; - sdioh_info_t *sdioh; - struct sdio_func *func = dev_to_sdio_func(pdev); - mmc_pm_flag_t sdio_flags; - - sd_err(("%s Enter\n", __FUNCTION__)); - if (func->num != 2) - return 0; - - sdioh = sdio_get_drvdata(func); - err = bcmsdh_suspend(sdioh->bcmsdh); - if (err) - return err; - - sdio_flags = sdio_get_host_pm_caps(func); - if (!(sdio_flags & MMC_PM_KEEP_POWER)) { - sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__)); - return -EINVAL; - } - - /* keep power while host suspended */ - err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); - if (err) { - sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); - return err; - } -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE); -#endif - dhd_mmc_suspend = TRUE; - smp_mb(); - - return 0; -} - -static int bcmsdh_sdmmc_resume(struct device *pdev) -{ - sdioh_info_t *sdioh; - struct sdio_func *func = dev_to_sdio_func(pdev); - - sd_err(("%s Enter\n", __FUNCTION__)); - if (func->num != 2) - return 0; - - sdioh = sdio_get_drvdata(func); - dhd_mmc_suspend = FALSE; -#if defined(OOB_INTR_ONLY) - bcmsdh_resume(sdioh->bcmsdh); -#endif - - smp_mb(); - return 0; -} - -static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { - .suspend = bcmsdh_sdmmc_suspend, - .resume = bcmsdh_sdmmc_resume, -}; -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ - -#if defined(BCMLXSDMMC) -static struct semaphore *notify_semaphore = NULL; - -static int dummy_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - if (func && (func->num != 2)) { - return 0; - } - - if (notify_semaphore) - up(notify_semaphore); - return 0; -} - -static void dummy_remove(struct sdio_func *func) -{ -} - -static struct sdio_driver dummy_sdmmc_driver = { - .probe = dummy_probe, - .remove = dummy_remove, - .name = "dummy_sdmmc", - .id_table = bcmsdh_sdmmc_ids, - }; - -int sdio_func_reg_notify(void* semaphore) -{ - notify_semaphore = semaphore; - return sdio_register_driver(&dummy_sdmmc_driver); -} - -void sdio_func_unreg_notify(void) -{ - OSL_SLEEP(15); - sdio_unregister_driver(&dummy_sdmmc_driver); -} - -#endif /* defined(BCMLXSDMMC) */ - -static struct sdio_driver bcmsdh_sdmmc_driver = { - .probe = bcmsdh_sdmmc_probe, - .remove = bcmsdh_sdmmc_remove, - .name = "bcmsdh_sdmmc", - .id_table = bcmsdh_sdmmc_ids, -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) - .drv = { - .pm = &bcmsdh_sdmmc_pm_ops, - }, -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ - }; - -struct sdos_info { - sdioh_info_t *sd; - spinlock_t lock; -}; - -/* Interrupt enable/disable */ -SDIOH_API_RC -sdioh_interrupt_set(sdioh_info_t *sd, bool enable) -{ - if (!sd) - return BCME_BADARG; - - sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); - return SDIOH_API_RC_SUCCESS; -} - -#ifdef BCMSDH_MODULE -static int __init -bcmsdh_module_init(void) -{ - int error = 0; - error = sdio_function_init(); - return error; -} - -static void __exit -bcmsdh_module_cleanup(void) -{ - sdio_function_cleanup(); -} - -module_init(bcmsdh_module_init); -module_exit(bcmsdh_module_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION(DESCRIPTION); -MODULE_AUTHOR(AUTHOR); - -#endif /* BCMSDH_MODULE */ -/* - * module init -*/ -int bcmsdh_register_client_driver(void) -{ - return sdio_register_driver(&bcmsdh_sdmmc_driver); -} - -/* - * module cleanup -*/ -void bcmsdh_unregister_client_driver(void) -{ - sdio_unregister_driver(&bcmsdh_sdmmc_driver); -} diff --git a/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c deleted file mode 100644 index 5f152518cd8e..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Broadcom SPI Host Controller Driver - Linux Per-port - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdspi_linux.c 406045 2013-06-05 22:09:52Z $ - */ - -#include -#include - -#include /* bcmsdh to/from specific controller APIs */ -#include /* to get msglevel bit values */ - -#include -#include /* SDIO Device and Protocol Specs */ -#include /* request_irq(), free_irq() */ -#include -#include - -extern uint sd_crc; -module_param(sd_crc, uint, 0); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define KERNEL26 -#endif - -struct sdos_info { - sdioh_info_t *sd; - spinlock_t lock; - wait_queue_head_t intr_wait_queue; -}; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define BLOCKABLE() (!in_atomic()) -#else -#define BLOCKABLE() (!in_interrupt()) -#endif - -/* Interrupt handler */ -static irqreturn_t -sdspi_isr(int irq, void *dev_id -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -, struct pt_regs *ptregs -#endif -) -{ - sdioh_info_t *sd; - struct sdos_info *sdos; - bool ours; - - sd = (sdioh_info_t *)dev_id; - sd->local_intrcount++; - - if (!sd->card_init_done) { - sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq)); - return IRQ_RETVAL(FALSE); - } else { - ours = spi_check_client_intr(sd, NULL); - - /* For local interrupts, wake the waiting process */ - if (ours && sd->got_hcint) { - sdos = (struct sdos_info *)sd->sdos_info; - wake_up_interruptible(&sdos->intr_wait_queue); - } - - return IRQ_RETVAL(ours); - } -} - - -/* Register with Linux for interrupts */ -int -spi_register_irq(sdioh_info_t *sd, uint irq) -{ - sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq)); - if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) { - sd_err(("%s: request_irq() failed\n", __FUNCTION__)); - return ERROR; - } - return SUCCESS; -} - -/* Free Linux irq */ -void -spi_free_irq(uint irq, sdioh_info_t *sd) -{ - free_irq(irq, sd); -} - -/* Map Host controller registers */ -uint32 * -spi_reg_map(osl_t *osh, uintptr addr, int size) -{ - return (uint32 *)REG_MAP(addr, size); -} - -void -spi_reg_unmap(osl_t *osh, uintptr addr, int size) -{ - REG_UNMAP((void*)(uintptr)addr); -} - -int -spi_osinit(sdioh_info_t *sd) -{ - struct sdos_info *sdos; - - sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); - sd->sdos_info = (void*)sdos; - if (sdos == NULL) - return BCME_NOMEM; - - sdos->sd = sd; - spin_lock_init(&sdos->lock); - init_waitqueue_head(&sdos->intr_wait_queue); - return BCME_OK; -} - -void -spi_osfree(sdioh_info_t *sd) -{ - struct sdos_info *sdos; - ASSERT(sd && sd->sdos_info); - - sdos = (struct sdos_info *)sd->sdos_info; - MFREE(sd->osh, sdos, sizeof(struct sdos_info)); -} - -/* Interrupt enable/disable */ -SDIOH_API_RC -sdioh_interrupt_set(sdioh_info_t *sd, bool enable) -{ - ulong flags; - struct sdos_info *sdos; - - sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); - - sdos = (struct sdos_info *)sd->sdos_info; - ASSERT(sdos); - - if (!(sd->host_init_done && sd->card_init_done)) { - sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { - sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - /* Ensure atomicity for enable/disable calls */ - spin_lock_irqsave(&sdos->lock, flags); - - sd->client_intr_enabled = enable; - if (enable && !sd->lockcount) - spi_devintr_on(sd); - else - spi_devintr_off(sd); - - spin_unlock_irqrestore(&sdos->lock, flags); - - return SDIOH_API_RC_SUCCESS; -} - -/* Protect against reentrancy (disable device interrupts while executing) */ -void -spi_lock(sdioh_info_t *sd) -{ - ulong flags; - struct sdos_info *sdos; - - sdos = (struct sdos_info *)sd->sdos_info; - ASSERT(sdos); - - sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount)); - - spin_lock_irqsave(&sdos->lock, flags); - if (sd->lockcount) { - sd_err(("%s: Already locked!\n", __FUNCTION__)); - ASSERT(sd->lockcount == 0); - } - spi_devintr_off(sd); - sd->lockcount++; - spin_unlock_irqrestore(&sdos->lock, flags); -} - -/* Enable client interrupt */ -void -spi_unlock(sdioh_info_t *sd) -{ - ulong flags; - struct sdos_info *sdos; - - sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled)); - ASSERT(sd->lockcount > 0); - - sdos = (struct sdos_info *)sd->sdos_info; - ASSERT(sdos); - - spin_lock_irqsave(&sdos->lock, flags); - if (--sd->lockcount == 0 && sd->client_intr_enabled) { - spi_devintr_on(sd); - } - spin_unlock_irqrestore(&sdos->lock, flags); -} - -void spi_waitbits(sdioh_info_t *sd, bool yield) -{ -#ifndef BCMSDYIELD - ASSERT(!yield); -#endif - sd_trace(("%s: yield %d canblock %d\n", - __FUNCTION__, yield, BLOCKABLE())); - - /* Clear the "interrupt happened" flag and last intrstatus */ - sd->got_hcint = FALSE; - -#ifdef BCMSDYIELD - if (yield && BLOCKABLE()) { - struct sdos_info *sdos; - sdos = (struct sdos_info *)sd->sdos_info; - /* Wait for the indication, the interrupt will be masked when the ISR fires. */ - wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint)); - } else -#endif /* BCMSDYIELD */ - { - spi_spinbits(sd); - } - -} diff --git a/drivers/net/wireless/bcmdhd/bcmspibrcm.c b/drivers/net/wireless/bcmdhd/bcmspibrcm.c deleted file mode 100644 index 19cd1828eaf5..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmspibrcm.c +++ /dev/null @@ -1,1810 +0,0 @@ -/* - * Broadcom BCMSDH to gSPI Protocol Conversion Layer - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmspibrcm.c 373331 2012-12-07 04:46:22Z $ - */ - -#define HSMODE - -#include - -#include -#include -#include -#include -#include -#include -#include -#include /* SDIO device core hardware definitions. */ -#include - -#include /* bcmsdh to/from specific controller APIs */ -#include /* ioctl/iovars */ -#include /* SDIO Device and Protocol Specs */ - -#include - - -#include -#include - -/* these are for the older cores... for newer cores we have control for each of them */ -#define F0_RESPONSE_DELAY 16 -#define F1_RESPONSE_DELAY 16 -#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY - - -#define GSPI_F0_RESP_DELAY 0 -#define GSPI_F1_RESP_DELAY F1_RESPONSE_DELAY -#define GSPI_F2_RESP_DELAY 0 -#define GSPI_F3_RESP_DELAY 0 - -#define CMDLEN 4 - -#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE) - -/* Globals */ -#if defined(DHD_DEBUG) -uint sd_msglevel = SDH_ERROR_VAL; -#else -uint sd_msglevel = 0; -#endif - -uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ -uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ -uint sd_f2_blocksize = 64; /* Default blocksize */ - - -uint sd_divisor = 2; -uint sd_power = 1; /* Default to SD Slot powered ON */ -uint sd_clock = 1; /* Default to SD Clock turned ON */ -uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ -uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ - -uint8 spi_outbuf[SPI_MAX_PKT_LEN]; -uint8 spi_inbuf[SPI_MAX_PKT_LEN]; - -/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits - * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. - */ -#define BUF2_PKT_LEN 128 -uint8 spi_outbuf2[BUF2_PKT_LEN]; -uint8 spi_inbuf2[BUF2_PKT_LEN]; - -#define SPISWAP_WD4(x) bcmswap32(x); -#define SPISWAP_WD2(x) (bcmswap16(x & 0xffff)) | \ - (bcmswap16((x & 0xffff0000) >> 16) << 16); - -/* Prototypes */ -static bool bcmspi_test_card(sdioh_info_t *sd); -static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); -static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); -static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, - uint32 *data, uint32 datalen); -static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 *data); -static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 data); -static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, - uint8 *data); -static int bcmspi_driver_init(sdioh_info_t *sd); -static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, - uint32 addr, int nbytes, uint32 *data); -static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, - uint32 *data); -static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); -static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); - -/* - * Public entry points & extern's - */ -extern sdioh_info_t * -sdioh_attach(osl_t *osh, void *bar0, uint irq) -{ - sdioh_info_t *sd; - - sd_trace(("%s\n", __FUNCTION__)); - if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { - sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); - return NULL; - } - bzero((char *)sd, sizeof(sdioh_info_t)); - sd->osh = osh; - if (spi_osinit(sd) != 0) { - sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return NULL; - } - - sd->bar0 = bar0; - sd->irq = irq; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; - sd->intr_handler_valid = FALSE; - - /* Set defaults */ - sd->use_client_ints = TRUE; - sd->sd_use_dma = FALSE; /* DMA Not supported */ - - /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit - * mode - */ - sd->wordlen = 2; - - - if (!spi_hw_attach(sd)) { - sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - if (bcmspi_driver_init(sd) != SUCCESS) { - sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - if (spi_register_irq(sd, irq) != SUCCESS) { - sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - sd_trace(("%s: Done\n", __FUNCTION__)); - - return sd; -} - -extern SDIOH_API_RC -sdioh_detach(osl_t *osh, sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - if (sd) { - sd_err(("%s: detaching from hardware\n", __FUNCTION__)); - spi_free_irq(sd->irq, sd); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - } - return SDIOH_API_RC_SUCCESS; -} - -/* Configure callback to client when we recieve client interrupt */ -extern SDIOH_API_RC -sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); -#if !defined(OOB_INTR_ONLY) - sd->intr_handler = fn; - sd->intr_handler_arg = argh; - sd->intr_handler_valid = TRUE; -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_deregister(sdioh_info_t *sd) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); -#if !defined(OOB_INTR_ONLY) - sd->intr_handler_valid = FALSE; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - *onoff = sd->client_intr_enabled; - return SDIOH_API_RC_SUCCESS; -} - -#if defined(DHD_DEBUG) -extern bool -sdioh_interrupt_pending(sdioh_info_t *sd) -{ - return 0; -} -#endif - -extern SDIOH_API_RC -sdioh_query_device(sdioh_info_t *sd) -{ - /* Return a BRCM ID appropriate to the dongle class */ - return (sd->num_funcs > 1) ? BCM4329_D11N_ID : BCM4318_D11G_ID; -} - -/* Provide dstatus bits of spi-transaction for dhd layers. */ -extern uint32 -sdioh_get_dstatus(sdioh_info_t *sd) -{ - return sd->card_dstatus; -} - -extern void -sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) -{ - sd->chip = chip; - sd->chiprev = chiprev; -} - -extern void -sdioh_dwordmode(sdioh_info_t *sd, bool set) -{ - uint8 reg = 0; - int status; - - if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != - SUCCESS) { - sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); - return; - } - - if (set) { - reg |= DWORD_PKT_LEN_EN; - sd->dwordmode = TRUE; - sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ - } else { - reg &= ~DWORD_PKT_LEN_EN; - sd->dwordmode = FALSE; - sd->client_block_size[SPI_FUNC_2] = 2048; - } - - if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != - SUCCESS) { - sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); - return; - } -} - - -uint -sdioh_query_iofnum(sdioh_info_t *sd) -{ - return sd->num_funcs; -} - -/* IOVar table */ -enum { - IOV_MSGLEVEL = 1, - IOV_BLOCKMODE, - IOV_BLOCKSIZE, - IOV_DMA, - IOV_USEINTS, - IOV_NUMINTS, - IOV_NUMLOCALINTS, - IOV_HOSTREG, - IOV_DEVREG, - IOV_DIVISOR, - IOV_SDMODE, - IOV_HISPEED, - IOV_HCIREGS, - IOV_POWER, - IOV_CLOCK, - IOV_SPIERRSTATS, - IOV_RESP_DELAY_ALL -}; - -const bcm_iovar_t sdioh_iovars[] = { - {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, - {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ - {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, - {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, - {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, - {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, - {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, - {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, - {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, - {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, - {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, - {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, - {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -int -sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - int32 int_val = 0; - bool bool_val; - uint32 actionid; -/* - sdioh_regs_t *regs; -*/ - - ASSERT(name); - ASSERT(len >= 0); - - /* Get must have return space; Set does not take qualifiers */ - ASSERT(set || (arg && len)); - ASSERT(!set || (!params && !plen)); - - sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); - - if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) - goto exit; - - /* Set up params so get and set can share the convenience variables */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - val_size = sizeof(int); - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - switch (actionid) { - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)sd_msglevel; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): - sd_msglevel = int_val; - break; - - case IOV_GVAL(IOV_BLOCKSIZE): - if ((uint32)int_val > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - int_val = (int32)si->client_block_size[int_val]; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DMA): - int_val = (int32)si->sd_use_dma; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DMA): - si->sd_use_dma = (bool)int_val; - break; - - case IOV_GVAL(IOV_USEINTS): - int_val = (int32)si->use_client_ints; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_USEINTS): - break; - - case IOV_GVAL(IOV_DIVISOR): - int_val = (uint32)sd_divisor; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DIVISOR): - sd_divisor = int_val; - if (!spi_start_clock(si, (uint16)sd_divisor)) { - sd_err(("%s: set clock failed\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - } - break; - - case IOV_GVAL(IOV_POWER): - int_val = (uint32)sd_power; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POWER): - sd_power = int_val; - break; - - case IOV_GVAL(IOV_CLOCK): - int_val = (uint32)sd_clock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CLOCK): - sd_clock = int_val; - break; - - case IOV_GVAL(IOV_SDMODE): - int_val = (uint32)sd_sdmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDMODE): - sd_sdmode = int_val; - break; - - case IOV_GVAL(IOV_HISPEED): - int_val = (uint32)sd_hiok; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HISPEED): - sd_hiok = int_val; - - if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { - sd_err(("%s: Failed changing highspeed mode to %d.\n", - __FUNCTION__, sd_hiok)); - bcmerror = BCME_ERROR; - return ERROR; - } - break; - - case IOV_GVAL(IOV_NUMINTS): - int_val = (int32)si->intrcount; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_NUMLOCALINTS): - int_val = (int32)si->local_intrcount; - bcopy(&int_val, arg, val_size); - break; - case IOV_GVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data; - - if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - - int_val = (int)data; - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = (uint8)sd_ptr->value; - - if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - } - - - case IOV_GVAL(IOV_SPIERRSTATS): - { - bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); - break; - } - - case IOV_SVAL(IOV_SPIERRSTATS): - { - bzero(&si->spierrstats, sizeof(struct spierrstats_t)); - break; - } - - case IOV_GVAL(IOV_RESP_DELAY_ALL): - int_val = (int32)si->resp_delay_all; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RESP_DELAY_ALL): - si->resp_delay_all = (bool)int_val; - int_val = STATUS_ENABLE|INTR_WITH_STATUS; - if (si->resp_delay_all) - int_val |= RESP_DELAY_ALL; - else { - if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, - F1_RESPONSE_DELAY) != SUCCESS) { - sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - break; - } - } - - if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) - != SUCCESS) { - sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } -exit: - - return bcmerror; -} - -extern SDIOH_API_RC -sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - SDIOH_API_RC status; - /* No lock needed since sdioh_request_byte does locking */ - status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - /* No lock needed since sdioh_request_byte does locking */ - SDIOH_API_RC status; - - if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { - uint8 dummy_data; - status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); - if (status) { - sd_err(("sdioh_cfg_read() failed.\n")); - return status; - } - } - - status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) -{ - uint32 count; - int offset; - uint32 cis_byte; - uint16 *cis = (uint16 *)cisd; - uint bar0 = SI_ENUM_BASE; - int status; - uint8 data; - - sd_trace(("%s: Func %d\n", __FUNCTION__, func)); - - spi_lock(sd); - - /* Set sb window address to 0x18000000 */ - data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); - if (status == SUCCESS) { - data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); - } else { - sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - if (status == SUCCESS) { - data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); - } else { - sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - - offset = CC_SROM_OTP; /* OTP offset in chipcommon. */ - for (count = 0; count < length/2; count++) { - if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { - sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - - *cis = (uint16)cis_byte; - cis++; - offset += 2; - } - - spi_unlock(sd); - - return (BCME_OK); -} - -extern SDIOH_API_RC -sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) -{ - int status; - uint32 cmd_arg; - uint32 dstatus; - uint32 data = (uint32)(*byte); - - spi_lock(sd); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); - - if (rw == SDIOH_READ) { - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr)); - } else { - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, data)); - } - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) { - spi_unlock(sd); - return status; - } - - if (rw == SDIOH_READ) { - *byte = (uint8)data; - sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *byte)); - } - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus=0x%x\n", dstatus)); - - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, - uint32 *word, uint nbytes) -{ - int status; - - spi_lock(sd); - - if (rw == SDIOH_READ) - status = bcmspi_card_regread(sd, func, addr, nbytes, word); - else - status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); - - spi_unlock(sd); - return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -extern SDIOH_API_RC -sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, - uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) -{ - int len; - int buflen = (int)buflen_u; - bool fifo = (fix_inc == SDIOH_DATA_FIX); - - spi_lock(sd); - - ASSERT(reg_width == 4); - ASSERT(buflen_u < (1 << 30)); - ASSERT(sd->client_block_size[func]); - - sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", - __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', - buflen_u, sd->r_cnt, sd->t_cnt, pkt)); - - /* Break buffer down into blocksize chunks. */ - while (buflen > 0) { - len = MIN(sd->client_block_size[func], buflen); - if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { - sd_err(("%s: bcmspi_card_buf %s failed\n", - __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); - spi_unlock(sd); - return SDIOH_API_RC_FAIL; - } - buffer += len; - buflen -= len; - if (!fifo) - addr += len; - } - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. - * Its main aim is to have simpler spi writes rather than recursive writes. - * e.g. When there is a need to program response delay on the fly after detecting the SPI-func - * this call will allow to program the response delay. - */ -static int -bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) -{ - uint32 cmd_arg; - uint32 datalen = 1; - uint32 hostlen; - - cmd_arg = 0; - - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); - - sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); - - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - ASSERT(sd->wordlen == 4 || sd->wordlen == 2); - datalen = ROUNDUP(datalen, sd->wordlen); - - /* Start by copying command in the spi-outbuffer */ - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)spi_outbuf2 = SPISWAP_WD4(cmd_arg); - if (datalen & 0x3) - datalen += (4 - (datalen & 0x3)); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)spi_outbuf2 = SPISWAP_WD2(cmd_arg); - if (datalen & 0x1) - datalen++; - } else { - sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - /* for Write, put the data into the output buffer */ - if (datalen != 0) { - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD4(byte); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD2(byte); - } - } - - /* +4 for cmd, +4 for dstatus */ - hostlen = datalen + 8; - hostlen += (4 - (hostlen & 0x3)); - spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); - - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else { - sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - if (sd->card_dstatus) - sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); - - return (BCME_OK); -} - -/* Program the response delay corresponding to the spi function */ -static int -bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) -{ - if (sd->resp_delay_all == FALSE) - return (BCME_OK); - - if (sd->prev_fun == func) - return (BCME_OK); - - if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) - return (BCME_OK); - - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); - - /* Remember function for which to avoid reprogramming resp-delay in next iteration */ - sd->prev_fun = func; - - return (BCME_OK); - -} - -#define GSPI_RESYNC_PATTERN 0x0 - -/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. - * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is - * synchronised and all queued resuests are cancelled. - */ -static int -bcmspi_resync_f1(sdioh_info_t *sd) -{ - uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; - - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - ASSERT(sd->wordlen == 4 || sd->wordlen == 2); - datalen = ROUNDUP(datalen, sd->wordlen); - - /* Start by copying command in the spi-outbuffer */ - *(uint32 *)spi_outbuf2 = cmd_arg; - - /* for Write, put the data into the output buffer */ - *(uint32 *)&spi_outbuf2[CMDLEN] = data; - - /* +4 for cmd, +4 for dstatus */ - spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); - - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else { - sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - if (sd->card_dstatus) - sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); - - return (BCME_OK); -} - -uint32 dstatus_count = 0; - -static int -bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) -{ - uint32 dstatus = sd->card_dstatus; - struct spierrstats_t *spierrstats = &sd->spierrstats; - int err = SUCCESS; - - sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); - - /* Store dstatus of last few gSPI transactions */ - spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; - spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; - dstatus_count++; - - if (sd->card_init_done == FALSE) - return err; - - if (dstatus & STATUS_DATA_NOT_AVAILABLE) { - spierrstats->dna++; - sd_trace(("Read data not available on F1 addr = 0x%x\n", - GFIELD(cmd_arg, SPI_REG_ADDR))); - /* Clear dna bit */ - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); - } - - if (dstatus & STATUS_UNDERFLOW) { - spierrstats->rdunderflow++; - sd_err(("FIFO underflow happened due to current F2 read command.\n")); - } - - if (dstatus & STATUS_OVERFLOW) { - spierrstats->wroverflow++; - sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); - bcmspi_resync_f1(sd); - sd_err(("Recovering from F1 FIFO overflow.\n")); - } - - if (dstatus & STATUS_F2_INTR) { - spierrstats->f2interrupt++; - sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); - } - - if (dstatus & STATUS_F3_INTR) { - spierrstats->f3interrupt++; - sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); - } - - if (dstatus & STATUS_HOST_CMD_DATA_ERR) { - spierrstats->hostcmddataerr++; - sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); - } - - if (dstatus & STATUS_F2_PKT_AVAILABLE) { - spierrstats->f2pktavailable++; - sd_trace(("Packet is available/ready in F2 TX FIFO\n")); - sd_trace(("Packet length = %d\n", sd->dwordmode ? - ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : - ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); - } - - if (dstatus & STATUS_F3_PKT_AVAILABLE) { - spierrstats->f3pktavailable++; - sd_err(("Packet is available/ready in F3 TX FIFO\n")); - sd_err(("Packet length = %d\n", - (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); - } - - return err; -} - -extern int -sdioh_abort(sdioh_info_t *sd, uint func) -{ - return 0; -} - -int -sdioh_start(sdioh_info_t *sd, int stage) -{ - return SUCCESS; -} - -int -sdioh_stop(sdioh_info_t *sd) -{ - return SUCCESS; -} - -int -sdioh_waitlockfree(sdioh_info_t *sd) -{ - return SUCCESS; -} - - -/* - * Private/Static work routines - */ -static int -bcmspi_host_init(sdioh_info_t *sd) -{ - - /* Default power on mode */ - sd->sd_mode = SDIOH_MODE_SPI; - sd->polled_mode = TRUE; - sd->host_init_done = TRUE; - sd->card_init_done = FALSE; - sd->adapter_slot = 1; - - return (SUCCESS); -} - -static int -get_client_blocksize(sdioh_info_t *sd) -{ - uint32 regdata[2]; - int status; - - /* Find F1/F2/F3 max packet size */ - if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, - 8, regdata)) != SUCCESS) { - return status; - } - - sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", - regdata[0], regdata[1])); - - sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; - sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); - ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); - - sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; - sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); - ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); - - sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; - sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); - ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); - - return 0; -} - -static int -bcmspi_client_init(sdioh_info_t *sd) -{ - uint32 status_en_reg = 0; - sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); - -#ifdef HSMODE - if (!spi_start_clock(sd, (uint16)sd_divisor)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#else - /* Start at ~400KHz clock rate for initialization */ - if (!spi_start_clock(sd, 128)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#endif /* HSMODE */ - - if (!bcmspi_host_device_init_adapt(sd)) { - sd_err(("bcmspi_host_device_init_adapt failed\n")); - return ERROR; - } - - if (!bcmspi_test_card(sd)) { - sd_err(("bcmspi_test_card failed\n")); - return ERROR; - } - - sd->num_funcs = SPI_MAX_IOFUNCS; - - get_client_blocksize(sd); - - /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ - bcmspi_resync_f1(sd); - - sd->dwordmode = FALSE; - - bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); - - sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); - status_en_reg |= INTR_WITH_STATUS; - - if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, - status_en_reg & 0xff) != SUCCESS) { - sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); - return ERROR; - } - -#ifndef HSMODE - /* After configuring for High-Speed mode, set the desired clock rate. */ - if (!spi_start_clock(sd, 4)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#endif /* HSMODE */ - - /* check to see if the response delay needs to be programmed properly */ - { - uint32 f1_respdelay = 0; - bcmspi_card_regread(sd, 0, SPID_RESP_DELAY_F1, 1, &f1_respdelay); - if ((f1_respdelay == 0) || (f1_respdelay == 0xFF)) { - /* older sdiodevice core and has no separte resp delay for each of */ - sd_err(("older corerev < 4 so use the same resp delay for all funcs\n")); - sd->resp_delay_new = FALSE; - } - else { - /* older sdiodevice core and has no separte resp delay for each of */ - int ret_val; - sd->resp_delay_new = TRUE; - sd_err(("new corerev >= 4 so set the resp delay for each of the funcs\n")); - sd_trace(("resp delay for funcs f0(%d), f1(%d), f2(%d), f3(%d)\n", - GSPI_F0_RESP_DELAY, GSPI_F1_RESP_DELAY, - GSPI_F2_RESP_DELAY, GSPI_F3_RESP_DELAY)); - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F0, 1, - GSPI_F0_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F0\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F1, 1, - GSPI_F1_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F1\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F2, 1, - GSPI_F2_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F3, 1, - GSPI_F3_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); - return ERROR; - } - } - } - - - sd->card_init_done = TRUE; - - /* get the device rev to program the prop respdelays */ - - return SUCCESS; -} - -static int -bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) -{ - uint32 regdata; - int status; - - if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, - 4, ®data)) != SUCCESS) - return status; - - sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); - - - if (hsmode == TRUE) { - sd_trace(("Attempting to enable High-Speed mode.\n")); - - if (regdata & HIGH_SPEED_MODE) { - sd_trace(("Device is already in High-Speed mode.\n")); - return status; - } else { - regdata |= HIGH_SPEED_MODE; - sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); - if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, - 4, regdata)) != SUCCESS) { - return status; - } - } - } else { - sd_trace(("Attempting to disable High-Speed mode.\n")); - - if (regdata & HIGH_SPEED_MODE) { - regdata &= ~HIGH_SPEED_MODE; - sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); - if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, - 4, regdata)) != SUCCESS) - return status; - } - else { - sd_trace(("Device is already in Low-Speed mode.\n")); - return status; - } - } - spi_controller_highspeed_mode(sd, hsmode); - - return TRUE; -} - -#define bcmspi_find_curr_mode(sd) { \ - sd->wordlen = 2; \ - status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ - regdata &= 0xff; \ - if ((regdata == 0xad) || (regdata == 0x5b) || \ - (regdata == 0x5d) || (regdata == 0x5a)) \ - break; \ - sd->wordlen = 4; \ - status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ - regdata &= 0xff; \ - if ((regdata == 0xad) || (regdata == 0x5b) || \ - (regdata == 0x5d) || (regdata == 0x5a)) \ - break; \ - sd_trace(("Silicon testability issue: regdata = 0x%x." \ - " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ - OSL_DELAY(100000); \ -} - -#define INIT_ADAPT_LOOP 100 - -/* Adapt clock-phase-speed-bitwidth between host and device */ -static bool -bcmspi_host_device_init_adapt(sdioh_info_t *sd) -{ - uint32 wrregdata, regdata = 0; - int status; - int i; - - /* Due to a silicon testability issue, the first command from the Host - * to the device will get corrupted (first bit will be lost). So the - * Host should poll the device with a safe read request. ie: The Host - * should try to read F0 addr 0x14 using the Fixed address mode - * (This will prevent a unintended write command to be detected by device) - */ - for (i = 0; i < INIT_ADAPT_LOOP; i++) { - /* If device was not power-cycled it will stay in 32bit mode with - * response-delay-all bit set. Alternate the iteration so that - * read either with or without response-delay for F0 to succeed. - */ - bcmspi_find_curr_mode(sd); - sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; - - bcmspi_find_curr_mode(sd); - sd->dwordmode = TRUE; - - bcmspi_find_curr_mode(sd); - sd->dwordmode = FALSE; - } - - /* Bail out, device not detected */ - if (i == INIT_ADAPT_LOOP) - return FALSE; - - /* Softreset the spid logic */ - if ((sd->dwordmode) || (sd->wordlen == 4)) { - bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); - bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); - sd_trace(("reset reg read = 0x%x\n", regdata)); - sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, - sd->wordlen, sd->resp_delay_all)); - /* Restore default state after softreset */ - sd->wordlen = 2; - sd->dwordmode = FALSE; - } - - if (sd->wordlen == 4) { - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != - SUCCESS) - return FALSE; - if (regdata == TEST_RO_DATA_32BIT_LE) { - sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", - regdata)); - sd_trace(("Spid power was left on.\n")); - } else { - sd_err(("Spid power was left on but signature read failed." - " Value read = 0x%x\n", regdata)); - return FALSE; - } - } else { - sd->wordlen = 2; - -#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ - - wrregdata = (CTRL_REG_DEFAULT); - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); - -#ifndef HSMODE - wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); - wrregdata &= ~HIGH_SPEED_MODE; - bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); -#endif /* HSMODE */ - - for (i = 0; i < INIT_ADAPT_LOOP; i++) { - if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { - sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, - ®data)) != SUCCESS) - return FALSE; - } - OSL_DELAY(1000); - } - - /* Change to host controller intr-polarity of active-low */ - wrregdata &= ~INTR_POLARITY; - sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", - wrregdata)); - /* Change to 32bit mode */ - wrregdata |= WORD_LENGTH_32; - bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); - - /* Change command/data packaging in 32bit LE mode */ - sd->wordlen = 4; - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - - if (regdata == TEST_RO_DATA_32BIT_LE) { - sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); - sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); - } else { - sd_err(("Stale spid reg values read as it was kept powered. Value read =" - "0x%x\n", regdata)); - return FALSE; - } - } - - - return TRUE; -} - -static bool -bcmspi_test_card(sdioh_info_t *sd) -{ - uint32 regdata; - int status; - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - - if (regdata == (TEST_RO_DATA_32BIT_LE)) - sd_trace(("32bit LE regdata = 0x%x\n", regdata)); - else { - sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); - return FALSE; - } - - -#define RW_PATTERN1 0xA0A1A2A3 -#define RW_PATTERN2 0x4B5B6B7B - - regdata = RW_PATTERN1; - if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) - return FALSE; - regdata = 0; - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) - return FALSE; - if (regdata != RW_PATTERN1) { - sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", - RW_PATTERN1, regdata)); - return FALSE; - } else - sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); - - regdata = RW_PATTERN2; - if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) - return FALSE; - regdata = 0; - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) - return FALSE; - if (regdata != RW_PATTERN2) { - sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", - RW_PATTERN2, regdata)); - return FALSE; - } else - sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); - - return TRUE; -} - -static int -bcmspi_driver_init(sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - if ((bcmspi_host_init(sd)) != SUCCESS) { - return ERROR; - } - - if (bcmspi_client_init(sd) != SUCCESS) { - return ERROR; - } - - return SUCCESS; -} - -/* Read device reg */ -static int -bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - int status; - uint32 cmd_arg, dstatus; - - ASSERT(regsize); - - if (func == 2) - sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); - - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus =0x%x\n", dstatus)); - - return SUCCESS; -} - -static int -bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - - int status; - uint32 cmd_arg; - uint32 dstatus; - - ASSERT(regsize); - - if (func == 2) - sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); - - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) - return status; - - sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *data)); - - bcmspi_cmd_getdstatus(sd, &dstatus); - sd_trace(("dstatus =0x%x\n", dstatus)); - return SUCCESS; -} - -/* write a device register */ -static int -bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) -{ - int status; - uint32 cmd_arg, dstatus; - - ASSERT(regsize); - - cmd_arg = 0; - - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); - - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize, data)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus=0x%x\n", dstatus)); - - return SUCCESS; -} - -/* write a device register - 1 byte */ -static int -bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) -{ - int status; - uint32 cmd_arg; - uint32 dstatus; - uint32 data = (uint32)(*byte); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); - - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, data)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus =0x%x\n", dstatus)); - - return SUCCESS; -} - -void -bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) -{ - *dstatus_buffer = sd->card_dstatus; -} - -/* 'data' is of type uint32 whereas other buffers are of type uint8 */ -static int -bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, - uint32 *data, uint32 datalen) -{ - uint32 i, j; - uint8 resp_delay = 0; - int err = SUCCESS; - uint32 hostlen; - uint32 spilen = 0; - uint32 dstatus_idx = 0; - uint16 templen, buslen, len, *ptr = NULL; - - sd_trace(("spi cmd = 0x%x\n", cmd_arg)); - - if (DWORDMODE_ON) { - spilen = GFIELD(cmd_arg, SPI_LEN); - if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) || - (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1)) - dstatus_idx = spilen * 3; - - if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && - (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { - spilen = spilen << 2; - dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0; - /* convert len to mod16 size */ - spilen = ROUNDUP(spilen, 16); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); - } - } - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)spi_outbuf = SPISWAP_WD4(cmd_arg); - if (datalen & 0x3) - datalen += (4 - (datalen & 0x3)); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)spi_outbuf = SPISWAP_WD2(cmd_arg); - if (datalen & 0x1) - datalen++; - if (datalen < 4) - datalen = ROUNDUP(datalen, 4); - } else { - sd_err(("Host is %d bit spid, could not create SPI command.\n", - 8 * sd->wordlen)); - return ERROR; - } - - /* for Write, put the data into the output buffer */ - if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { - /* We send len field of hw-header always a mod16 size, both from host and dongle */ - if (DWORDMODE_ON) { - if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) { - ptr = (uint16 *)&data[0]; - templen = *ptr; - /* ASSERT(*ptr == ~*(ptr + 1)); */ - templen = ROUNDUP(templen, 16); - *ptr = templen; - sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1)))); - } - } - - if (datalen != 0) { - for (i = 0; i < datalen/4; i++) { - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = - SPISWAP_WD4(data[i]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = - SPISWAP_WD2(data[i]); - } - } - } - } - - /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ - if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 0)) { - int func = GFIELD(cmd_arg, SPI_FUNCTION); - switch (func) { - case 0: - if (sd->resp_delay_new) - resp_delay = GSPI_F0_RESP_DELAY; - else - resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; - break; - case 1: - if (sd->resp_delay_new) - resp_delay = GSPI_F1_RESP_DELAY; - else - resp_delay = F1_RESPONSE_DELAY; - break; - case 2: - if (sd->resp_delay_new) - resp_delay = GSPI_F2_RESP_DELAY; - else - resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; - break; - default: - ASSERT(0); - break; - } - /* Program response delay */ - if (sd->resp_delay_new == FALSE) - bcmspi_prog_resp_delay(sd, func, resp_delay); - } - - /* +4 for cmd and +4 for dstatus */ - hostlen = datalen + 8 + resp_delay; - hostlen += dstatus_idx; - hostlen += (4 - (hostlen & 0x3)); - spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); - - /* for Read, get the data into the input buffer */ - if (datalen != 0) { - if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ - for (j = 0; j < datalen/4; j++) { - if (sd->wordlen == 4) { /* 32bit spid */ - data[j] = SPISWAP_WD4(*(uint32 *)&spi_inbuf[j * 4 + - CMDLEN + resp_delay]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - data[j] = SPISWAP_WD2(*(uint32 *)&spi_inbuf[j * 4 + - CMDLEN + resp_delay]); - } - } - - if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { - ptr = (uint16 *)&data[0]; - templen = *ptr; - buslen = len = ~(*(ptr + 1)); - buslen = ROUNDUP(buslen, 16); - /* populate actual len in hw-header */ - if (templen == buslen) - *ptr = len; - } - } - } - - /* Restore back the len field of the hw header */ - if (DWORDMODE_ON) { - if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && - (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { - ptr = (uint16 *)&data[0]; - *ptr = (uint16)(~*(ptr+1)); - } - } - - dstatus_idx += (datalen + CMDLEN + resp_delay); - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf[dstatus_idx]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf[dstatus_idx]); - } else { - sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", - 8 * sd->wordlen)); - return ERROR; - } - if (sd->card_dstatus == 0xffffffff) { - sd_err(("looks like not a GSPI device or device is not powered.\n")); - } - - err = bcmspi_update_stats(sd, cmd_arg); - - return err; - -} - -static int -bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, - uint32 addr, int nbytes, uint32 *data) -{ - int status; - uint32 cmd_arg; - bool write = rw == SDIOH_READ ? 0 : 1; - uint retries = 0; - - bool enable; - uint32 spilen; - - cmd_arg = 0; - - ASSERT(nbytes); - ASSERT(nbytes <= sd->client_block_size[func]); - - if (write) sd->t_cnt++; else sd->r_cnt++; - - if (func == 2) { - /* Frame len check limited by gSPI. */ - if ((nbytes > 2000) && write) { - sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); - } - /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ - /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ - if (write) { - uint32 dstatus; - /* check F2 ready with cached one */ - bcmspi_cmd_getdstatus(sd, &dstatus); - if ((dstatus & STATUS_F2_RX_READY) == 0) { - retries = WAIT_F2RXFIFORDY; - enable = 0; - while (retries-- && !enable) { - OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); - bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, - &dstatus); - if (dstatus & STATUS_F2_RX_READY) - enable = TRUE; - } - if (!enable) { - struct spierrstats_t *spierrstats = &sd->spierrstats; - spierrstats->f2rxnotready++; - sd_err(("F2 FIFO is not ready to receive data.\n")); - return ERROR; - } - sd_trace(("No of retries on F2 ready %d\n", - (WAIT_F2RXFIFORDY - retries))); - } - } - } - - /* F2 transfers happen on 0 addr */ - addr = (func == 2) ? 0 : addr; - - /* In pio mode buffer is read using fixed address fifo in func 1 */ - if ((func == 1) && (fifo)) - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); - else - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); - - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); - spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); - if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { - /* convert len to mod4 size */ - spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); - } else - cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); - - if ((func == 2) && (fifo == 1)) { - sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - } - - sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); - sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, nbytes)) != SUCCESS) { - sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, - (write ? "write" : "read"))); - return status; - } - - /* gSPI expects that hw-header-len is equal to spi-command-len */ - if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { - ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); - ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); - } - - if ((nbytes > 2000) && !write) { - sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); - } - - return SUCCESS; -} - -/* Reset and re-initialize the device */ -int -sdioh_sdio_reset(sdioh_info_t *si) -{ - si->card_init_done = FALSE; - return bcmspi_client_init(si); -} - -SDIOH_API_RC -sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) -{ - return SDIOH_API_RC_FAIL; -} - -SDIOH_API_RC -sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) -{ - return SDIOH_API_RC_FAIL; -} - -bool -sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) -{ - return FALSE; -} - -SDIOH_API_RC -sdioh_gpio_init(sdioh_info_t *sd) -{ - return SDIOH_API_RC_FAIL; -} diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c deleted file mode 100644 index d110b6f062de..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmutils.c +++ /dev/null @@ -1,3064 +0,0 @@ -/* - * Driver O/S-independent utility routines - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmutils.c 617200 2016-02-04 12:23:42Z $ - */ - -#include -#include -#include -#include -#ifdef BCMDRIVER - -#include -#include - -#else /* !BCMDRIVER */ - -#include -#include -#include - -#if defined(BCMEXTSUP) -#include -#endif - -#ifndef ASSERT -#define ASSERT(exp) -#endif - -#endif /* !BCMDRIVER */ - -#include -#include -#include -#include -#include -#include -#include - - -void *_bcmutils_dummy_fn = NULL; - - - - -#ifdef BCMDRIVER - - - -/* copy a pkt buffer chain into a buffer */ -uint -pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) -{ - uint n, ret = 0; - - if (len < 0) - len = 4096; /* "infinite" */ - - /* skip 'offset' bytes */ - for (; p && offset; p = PKTNEXT(osh, p)) { - if (offset < (uint)PKTLEN(osh, p)) - break; - offset -= PKTLEN(osh, p); - } - - if (!p) - return 0; - - /* copy the data */ - for (; p && len; p = PKTNEXT(osh, p)) { - n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); - bcopy(PKTDATA(osh, p) + offset, buf, n); - buf += n; - len -= n; - ret += n; - offset = 0; - } - - return ret; -} - -/* copy a buffer into a pkt buffer chain */ -uint -pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) -{ - uint n, ret = 0; - - - /* skip 'offset' bytes */ - for (; p && offset; p = PKTNEXT(osh, p)) { - if (offset < (uint)PKTLEN(osh, p)) - break; - offset -= PKTLEN(osh, p); - } - - if (!p) - return 0; - - /* copy the data */ - for (; p && len; p = PKTNEXT(osh, p)) { - n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); - bcopy(buf, PKTDATA(osh, p) + offset, n); - buf += n; - len -= n; - ret += n; - offset = 0; - } - - return ret; -} - - - -/* return total length of buffer chain */ -uint BCMFASTPATH -pkttotlen(osl_t *osh, void *p) -{ - uint total; - int len; - - total = 0; - for (; p; p = PKTNEXT(osh, p)) { - len = PKTLEN(osh, p); - total += len; -#ifdef BCMLFRAG - if (BCMLFRAG_ENAB()) { - if (PKTISFRAG(osh, p)) { - total += PKTFRAGTOTLEN(osh, p); - } - } -#endif - } - - return (total); -} - -/* return the last buffer of chained pkt */ -void * -pktlast(osl_t *osh, void *p) -{ - for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) - ; - - return (p); -} - -/* count segments of a chained packet */ -uint BCMFASTPATH -pktsegcnt(osl_t *osh, void *p) -{ - uint cnt; - - for (cnt = 0; p; p = PKTNEXT(osh, p)) { - cnt++; -#ifdef BCMLFRAG - if (BCMLFRAG_ENAB()) { - if (PKTISFRAG(osh, p)) { - cnt += PKTFRAGTOTNUM(osh, p); - } - } -#endif - } - - return cnt; -} - - -/* count segments of a chained packet */ -uint BCMFASTPATH -pktsegcnt_war(osl_t *osh, void *p) -{ - uint cnt; - uint8 *pktdata; - uint len, remain, align64; - - for (cnt = 0; p; p = PKTNEXT(osh, p)) { - cnt++; - len = PKTLEN(osh, p); - if (len > 128) { - pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ - /* Check for page boundary straddle (2048B) */ - if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) - cnt++; - - align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ - align64 = (64 - align64) & 0x3f; - len -= align64; /* bytes from aligned 64B to end */ - /* if aligned to 128B, check for MOD 128 between 1 to 4B */ - remain = len % 128; - if (remain > 0 && remain <= 4) - cnt++; /* add extra seg */ - } - } - - return cnt; -} - -uint8 * BCMFASTPATH -pktdataoffset(osl_t *osh, void *p, uint offset) -{ - uint total = pkttotlen(osh, p); - uint pkt_off = 0, len = 0; - uint8 *pdata = (uint8 *) PKTDATA(osh, p); - - if (offset > total) - return NULL; - - for (; p; p = PKTNEXT(osh, p)) { - pdata = (uint8 *) PKTDATA(osh, p); - pkt_off = offset - len; - len += PKTLEN(osh, p); - if (len > offset) - break; - } - return (uint8*) (pdata+pkt_off); -} - - -/* given a offset in pdata, find the pkt seg hdr */ -void * -pktoffset(osl_t *osh, void *p, uint offset) -{ - uint total = pkttotlen(osh, p); - uint len = 0; - - if (offset > total) - return NULL; - - for (; p; p = PKTNEXT(osh, p)) { - len += PKTLEN(osh, p); - if (len > offset) - break; - } - return p; -} - -#endif /* BCMDRIVER */ - -#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) -const unsigned char bcm_ctype[] = { - - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ - _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, - _BCM_C, /* 8-15 */ - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ - _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ - _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ - _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ - _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ - _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, - _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ - _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, - _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ - _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ - _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ - _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ - _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ -}; - -ulong -bcm_strtoul(const char *cp, char **endp, uint base) -{ - ulong result, last_result = 0, value; - bool minus; - - minus = FALSE; - - while (bcm_isspace(*cp)) - cp++; - - if (cp[0] == '+') - cp++; - else if (cp[0] == '-') { - minus = TRUE; - cp++; - } - - if (base == 0) { - if (cp[0] == '0') { - if ((cp[1] == 'x') || (cp[1] == 'X')) { - base = 16; - cp = &cp[2]; - } else { - base = 8; - cp = &cp[1]; - } - } else - base = 10; - } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { - cp = &cp[2]; - } - - result = 0; - - while (bcm_isxdigit(*cp) && - (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { - result = result*base + value; - /* Detected overflow */ - if (result < last_result && !minus) - return (ulong)-1; - last_result = result; - cp++; - } - - if (minus) - result = (ulong)(-(long)result); - - if (endp) - *endp = DISCARD_QUAL(cp, char); - - return (result); -} - -int -bcm_atoi(const char *s) -{ - return (int)bcm_strtoul(s, NULL, 10); -} - -/* return pointer to location of substring 'needle' in 'haystack' */ -char * -bcmstrstr(const char *haystack, const char *needle) -{ - int len, nlen; - int i; - - if ((haystack == NULL) || (needle == NULL)) - return DISCARD_QUAL(haystack, char); - - nlen = (int)strlen(needle); - len = (int)strlen(haystack) - nlen + 1; - - for (i = 0; i < len; i++) - if (memcmp(needle, &haystack[i], nlen) == 0) - return DISCARD_QUAL(&haystack[i], char); - return (NULL); -} - -char * -bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len) -{ - for (; s_len >= substr_len; s++, s_len--) - if (strncmp(s, substr, substr_len) == 0) - return DISCARD_QUAL(s, char); - - return NULL; -} - -char * -bcmstrcat(char *dest, const char *src) -{ - char *p; - - p = dest + strlen(dest); - - while ((*p++ = *src++) != '\0') - ; - - return (dest); -} - -char * -bcmstrncat(char *dest, const char *src, uint size) -{ - char *endp; - char *p; - - p = dest + strlen(dest); - endp = p + size; - - while (p != endp && (*p++ = *src++) != '\0') - ; - - return (dest); -} - - -/**************************************************************************** -* Function: bcmstrtok -* -* Purpose: -* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), -* but allows strToken() to be used by different strings or callers at the same -* time. Each call modifies '*string' by substituting a NULL character for the -* first delimiter that is encountered, and updates 'string' to point to the char -* after the delimiter. Leading delimiters are skipped. -* -* Parameters: -* string (mod) Ptr to string ptr, updated by token. -* delimiters (in) Set of delimiter characters. -* tokdelim (out) Character that delimits the returned token. (May -* be set to NULL if token delimiter is not required). -* -* Returns: Pointer to the next token found. NULL when no more tokens are found. -***************************************************************************** -*/ -char * -bcmstrtok(char **string, const char *delimiters, char *tokdelim) -{ - unsigned char *str; - unsigned long map[8]; - int count; - char *nextoken; - - if (tokdelim != NULL) { - /* Prime the token delimiter */ - *tokdelim = '\0'; - } - - /* Clear control map */ - for (count = 0; count < 8; count++) { - map[count] = 0; - } - - /* Set bits in delimiter table */ - do { - map[*delimiters >> 5] |= (1 << (*delimiters & 31)); - } - while (*delimiters++); - - str = (unsigned char*)*string; - - /* Find beginning of token (skip over leading delimiters). Note that - * there is no token iff this loop sets str to point to the terminal - * null (*str == '\0') - */ - while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { - str++; - } - - nextoken = (char*)str; - - /* Find the end of the token. If it is not the end of the string, - * put a null there. - */ - for (; *str; str++) { - if (map[*str >> 5] & (1 << (*str & 31))) { - if (tokdelim != NULL) { - *tokdelim = *str; - } - - *str++ = '\0'; - break; - } - } - - *string = (char*)str; - - /* Determine if a token has been found. */ - if (nextoken == (char *) str) { - return NULL; - } - else { - return nextoken; - } -} - - -#define xToLower(C) \ - ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) - - -/**************************************************************************** -* Function: bcmstricmp -* -* Purpose: Compare to strings case insensitively. -* -* Parameters: s1 (in) First string to compare. -* s2 (in) Second string to compare. -* -* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if -* t1 > t2, when ignoring case sensitivity. -***************************************************************************** -*/ -int -bcmstricmp(const char *s1, const char *s2) -{ - char dc, sc; - - while (*s2 && *s1) { - dc = xToLower(*s1); - sc = xToLower(*s2); - if (dc < sc) return -1; - if (dc > sc) return 1; - s1++; - s2++; - } - - if (*s1 && !*s2) return 1; - if (!*s1 && *s2) return -1; - return 0; -} - - -/**************************************************************************** -* Function: bcmstrnicmp -* -* Purpose: Compare to strings case insensitively, upto a max of 'cnt' -* characters. -* -* Parameters: s1 (in) First string to compare. -* s2 (in) Second string to compare. -* cnt (in) Max characters to compare. -* -* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if -* t1 > t2, when ignoring case sensitivity. -***************************************************************************** -*/ -int -bcmstrnicmp(const char* s1, const char* s2, int cnt) -{ - char dc, sc; - - while (*s2 && *s1 && cnt) { - dc = xToLower(*s1); - sc = xToLower(*s2); - if (dc < sc) return -1; - if (dc > sc) return 1; - s1++; - s2++; - cnt--; - } - - if (!cnt) return 0; - if (*s1 && !*s2) return 1; - if (!*s1 && *s2) return -1; - return 0; -} - -/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ -int -bcm_ether_atoe(const char *p, struct ether_addr *ea) -{ - int i = 0; - char *ep; - - for (;;) { - ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); - p = ep; - if (!*p++ || i == 6) - break; - } - - return (i == 6); -} - -int -bcm_atoipv4(const char *p, struct ipv4_addr *ip) -{ - - int i = 0; - char *c; - for (;;) { - ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0); - if (*c++ != '.' || i == IPV4_ADDR_LEN) - break; - p = c; - } - return (i == IPV4_ADDR_LEN); -} -#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ - - -#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) -/* registry routine buffer preparation utility functions: - * parameter order is like strncpy, but returns count - * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) - */ -ulong -wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) -{ - ulong copyct = 1; - ushort i; - - if (abuflen == 0) - return 0; - - /* wbuflen is in bytes */ - wbuflen /= sizeof(ushort); - - for (i = 0; i < wbuflen; ++i) { - if (--abuflen == 0) - break; - *abuf++ = (char) *wbuf++; - ++copyct; - } - *abuf = '\0'; - - return copyct; -} -#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ - -char * -bcm_ether_ntoa(const struct ether_addr *ea, char *buf) -{ - static const char hex[] = - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - const uint8 *octet = ea->octet; - char *p = buf; - int i; - - for (i = 0; i < 6; i++, octet++) { - *p++ = hex[(*octet >> 4) & 0xf]; - *p++ = hex[*octet & 0xf]; - *p++ = ':'; - } - - *(p-1) = '\0'; - - return (buf); -} - -char * -bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) -{ - snprintf(buf, 16, "%d.%d.%d.%d", - ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); - return (buf); -} - -char * -bcm_ipv6_ntoa(void *ipv6, char *buf) -{ - /* Implementing RFC 5952 Sections 4 + 5 */ - /* Not thoroughly tested */ - uint16 tmp[8]; - uint16 *a = &tmp[0]; - char *p = buf; - int i, i_max = -1, cnt = 0, cnt_max = 1; - uint8 *a4 = NULL; - memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN); - - for (i = 0; i < IPV6_ADDR_LEN/2; i++) { - if (a[i]) { - if (cnt > cnt_max) { - cnt_max = cnt; - i_max = i - cnt; - } - cnt = 0; - } else - cnt++; - } - if (cnt > cnt_max) { - cnt_max = cnt; - i_max = i - cnt; - } - if (i_max == 0 && - /* IPv4-translated: ::ffff:0:a.b.c.d */ - ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || - /* IPv4-mapped: ::ffff:a.b.c.d */ - (cnt_max == 5 && a[5] == 0xffff))) - a4 = (uint8*) (a + 6); - - for (i = 0; i < IPV6_ADDR_LEN/2; i++) { - if ((uint8*) (a + i) == a4) { - snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); - break; - } else if (i == i_max) { - *p++ = ':'; - i += cnt_max - 1; - p[0] = ':'; - p[1] = '\0'; - } else { - if (i) - *p++ = ':'; - p += snprintf(p, 8, "%x", ntoh16(a[i])); - } - } - - return buf; -} -#ifdef BCMDRIVER - -void -bcm_mdelay(uint ms) -{ - uint i; - - for (i = 0; i < ms; i++) { - OSL_DELAY(1000); - } -} - - - - - -#if defined(DHD_DEBUG) -/* pretty hex print a pkt buffer chain */ -void -prpkt(const char *msg, osl_t *osh, void *p0) -{ - void *p; - - if (msg && (msg[0] != '\0')) - printf("%s:\n", msg); - - for (p = p0; p; p = PKTNEXT(osh, p)) - prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); -} -#endif - -/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. - * Also updates the inplace vlan tag if requested. - * For debugging, it returns an indication of what it did. - */ -uint BCMFASTPATH -pktsetprio(void *pkt, bool update_vtag) -{ - struct ether_header *eh; - struct ethervlan_header *evh; - uint8 *pktdata; - int priority = 0; - int rc = 0; - - pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); - ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); - - eh = (struct ether_header *) pktdata; - - if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { - uint16 vlan_tag; - int vlan_prio, dscp_prio = 0; - - evh = (struct ethervlan_header *)eh; - - vlan_tag = ntoh16(evh->vlan_tag); - vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; - - if ((evh->ether_type == hton16(ETHER_TYPE_IP)) || - (evh->ether_type == hton16(ETHER_TYPE_IPV6))) { - uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); - uint8 tos_tc = IP_TOS46(ip_body); - dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); - } - - /* DSCP priority gets precedence over 802.1P (vlan tag) */ - if (dscp_prio != 0) { - priority = dscp_prio; - rc |= PKTPRIO_VDSCP; - } else { - priority = vlan_prio; - rc |= PKTPRIO_VLAN; - } - /* - * If the DSCP priority is not the same as the VLAN priority, - * then overwrite the priority field in the vlan tag, with the - * DSCP priority value. This is required for Linux APs because - * the VLAN driver on Linux, overwrites the skb->priority field - * with the priority value in the vlan tag - */ - if (update_vtag && (priority != vlan_prio)) { - vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); - vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; - evh->vlan_tag = hton16(vlan_tag); - rc |= PKTPRIO_UPD; - } - } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) || - (eh->ether_type == hton16(ETHER_TYPE_IPV6))) { - uint8 *ip_body = pktdata + sizeof(struct ether_header); - uint8 tos_tc = IP_TOS46(ip_body); - uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; - switch (dscp) { - case DSCP_EF: - priority = PRIO_8021D_VO; - break; - case DSCP_AF31: - case DSCP_AF32: - case DSCP_AF33: - priority = PRIO_8021D_CL; - break; - case DSCP_AF21: - case DSCP_AF22: - case DSCP_AF23: - case DSCP_AF11: - case DSCP_AF12: - case DSCP_AF13: - priority = PRIO_8021D_EE; - break; - default: - priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); - break; - } - - rc |= PKTPRIO_DSCP; - } - - ASSERT(priority >= 0 && priority <= MAXPRIO); - PKTSETPRIO(pkt, priority); - return (rc | priority); -} - -/* Returns TRUE and DSCP if IP header found, FALSE otherwise. - */ -bool BCMFASTPATH -pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp) -{ - struct ether_header *eh; - struct ethervlan_header *evh; - uint8 *ip_body; - bool rc = FALSE; - - /* minimum length is ether header and IP header */ - if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN) - return FALSE; - - eh = (struct ether_header *) pktdata; - - if (eh->ether_type == HTON16(ETHER_TYPE_IP)) { - ip_body = pktdata + sizeof(struct ether_header); - *dscp = IP_DSCP46(ip_body); - rc = TRUE; - } - else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) { - evh = (struct ethervlan_header *)eh; - - /* minimum length is ethervlan header and IP header */ - if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN && - evh->ether_type == HTON16(ETHER_TYPE_IP)) { - ip_body = pktdata + sizeof(struct ethervlan_header); - *dscp = IP_DSCP46(ip_body); - rc = TRUE; - } - } - - return rc; -} - -/* The 0.5KB string table is not removed by compiler even though it's unused */ - -static char bcm_undeferrstr[32]; -static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; - -/* Convert the error codes into related error strings */ -const char * -bcmerrorstr(int bcmerror) -{ - /* check if someone added a bcmerror code but forgot to add errorstring */ - ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); - - if (bcmerror > 0 || bcmerror < BCME_LAST) { - snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); - return bcm_undeferrstr; - } - - ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); - - return bcmerrorstrtable[-bcmerror]; -} - - - -/* iovar table lookup */ -/* could mandate sorted tables and do a binary search */ -const bcm_iovar_t* -bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) -{ - const bcm_iovar_t *vi; - const char *lookup_name; - - /* skip any ':' delimited option prefixes */ - lookup_name = strrchr(name, ':'); - if (lookup_name != NULL) - lookup_name++; - else - lookup_name = name; - - ASSERT(table != NULL); - - for (vi = table; vi->name; vi++) { - if (!strcmp(vi->name, lookup_name)) - return vi; - } - /* ran to end of table */ - - return NULL; /* var name not found */ -} - -int -bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) -{ - int bcmerror = 0; - - /* length check on io buf */ - switch (vi->type) { - case IOVT_BOOL: - case IOVT_INT8: - case IOVT_INT16: - case IOVT_INT32: - case IOVT_UINT8: - case IOVT_UINT16: - case IOVT_UINT32: - /* all integers are int32 sized args at the ioctl interface */ - if (len < (int)sizeof(int)) { - bcmerror = BCME_BUFTOOSHORT; - } - break; - - case IOVT_BUFFER: - /* buffer must meet minimum length requirement */ - if (len < vi->minlen) { - bcmerror = BCME_BUFTOOSHORT; - } - break; - - case IOVT_VOID: - if (!set) { - /* Cannot return nil... */ - bcmerror = BCME_UNSUPPORTED; - } else if (len) { - /* Set is an action w/o parameters */ - bcmerror = BCME_BUFTOOLONG; - } - break; - - default: - /* unknown type for length check in iovar info */ - ASSERT(0); - bcmerror = BCME_UNSUPPORTED; - } - - return bcmerror; -} - -#endif /* BCMDRIVER */ - - -uint8 * -bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst) -{ - uint8 *new_dst = dst; - bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst; - - /* dst buffer should always be valid */ - ASSERT(dst); - - /* data len must be within valid range */ - ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)); - - /* source data buffer pointer should be valid, unless datalen is 0 - * meaning no data with this TLV - */ - ASSERT((data != NULL) || (datalen == 0)); - - /* only do work if the inputs are valid - * - must have a dst to write to AND - * - datalen must be within range AND - * - the source data pointer must be non-NULL if datalen is non-zero - * (this last condition detects datalen > 0 with a NULL data pointer) - */ - if ((dst != NULL) && - ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) && - ((data != NULL) || (datalen == 0))) { - - /* write type, len fields */ - dst_tlv->id = (uint8)type; - dst_tlv->len = (uint8)datalen; - - /* if data is present, copy to the output buffer and update - * pointer to output buffer - */ - if (datalen > 0) { - - memcpy(dst_tlv->data, data, datalen); - } - - /* update the output destination poitner to point past - * the TLV written - */ - new_dst = dst + BCM_TLV_HDR_SIZE + datalen; - } - - return (new_dst); -} - -uint8 * -bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen) -{ - uint8 *new_dst = dst; - - if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) { - - /* if len + tlv hdr len is more than destlen, don't do anything - * just return the buffer untouched - */ - if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) { - - new_dst = bcm_write_tlv(type, data, datalen, dst); - } - } - - return (new_dst); -} - -uint8 * -bcm_copy_tlv(const void *src, uint8 *dst) -{ - uint8 *new_dst = dst; - const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; - uint totlen; - - ASSERT(dst && src); - if (dst && src) { - - totlen = BCM_TLV_HDR_SIZE + src_tlv->len; - memcpy(dst, src_tlv, totlen); - new_dst = dst + totlen; - } - - return (new_dst); -} - - -uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen) -{ - uint8 *new_dst = dst; - const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; - - ASSERT(src); - if (src) { - if (bcm_valid_tlv(src_tlv, dst_maxlen)) { - new_dst = bcm_copy_tlv(src, dst); - } - } - - return (new_dst); -} - - -#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) -/******************************************************************************* - * crc8 - * - * Computes a crc8 over the input data using the polynomial: - * - * x^8 + x^7 +x^6 + x^4 + x^2 + 1 - * - * The caller provides the initial value (either CRC8_INIT_VALUE - * or the previous returned value) to allow for processing of - * discontiguous blocks of data. When generating the CRC the - * caller is responsible for complementing the final return value - * and inserting it into the byte stream. When checking, a final - * return value of CRC8_GOOD_VALUE indicates a valid CRC. - * - * Reference: Dallas Semiconductor Application Note 27 - * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", - * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., - * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt - * - * **************************************************************************** - */ - -static const uint8 crc8_table[256] = { - 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, - 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, - 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, - 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, - 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, - 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, - 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, - 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, - 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, - 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, - 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, - 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, - 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, - 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, - 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, - 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, - 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, - 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, - 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, - 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, - 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, - 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, - 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, - 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, - 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, - 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, - 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, - 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, - 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, - 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, - 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, - 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F -}; - -#define CRC_INNER_LOOP(n, c, x) \ - (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] - -uint8 -hndcrc8( - uint8 *pdata, /* pointer to array of data to process */ - uint nbytes, /* number of input data bytes to process */ - uint8 crc /* either CRC8_INIT_VALUE or previous return value */ -) -{ - /* hard code the crc loop instead of using CRC_INNER_LOOP macro - * to avoid the undefined and unnecessary (uint8 >> 8) operation. - */ - while (nbytes-- > 0) - crc = crc8_table[(crc ^ *pdata++) & 0xff]; - - return crc; -} - -/******************************************************************************* - * crc16 - * - * Computes a crc16 over the input data using the polynomial: - * - * x^16 + x^12 +x^5 + 1 - * - * The caller provides the initial value (either CRC16_INIT_VALUE - * or the previous returned value) to allow for processing of - * discontiguous blocks of data. When generating the CRC the - * caller is responsible for complementing the final return value - * and inserting it into the byte stream. When checking, a final - * return value of CRC16_GOOD_VALUE indicates a valid CRC. - * - * Reference: Dallas Semiconductor Application Note 27 - * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", - * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., - * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt - * - * **************************************************************************** - */ - -static const uint16 crc16_table[256] = { - 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, - 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, - 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, - 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, - 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, - 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, - 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, - 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, - 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, - 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, - 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, - 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, - 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, - 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, - 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, - 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, - 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, - 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, - 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, - 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, - 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, - 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, - 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, - 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, - 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, - 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, - 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, - 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, - 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, - 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, - 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, - 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 -}; - -uint16 -hndcrc16( - uint8 *pdata, /* pointer to array of data to process */ - uint nbytes, /* number of input data bytes to process */ - uint16 crc /* either CRC16_INIT_VALUE or previous return value */ -) -{ - while (nbytes-- > 0) - CRC_INNER_LOOP(16, crc, *pdata++); - return crc; -} - -static const uint32 crc32_table[256] = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -}; - -/* - * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if - * accumulating over multiple pieces. - */ -uint32 -hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) -{ - uint8 *pend; - pend = pdata + nbytes; - while (pdata < pend) - CRC_INNER_LOOP(32, crc, *pdata++); - - return crc; -} - -#ifdef notdef -#define CLEN 1499 /* CRC Length */ -#define CBUFSIZ (CLEN+4) -#define CNBUFS 5 /* # of bufs */ - -void -testcrc32(void) -{ - uint j, k, l; - uint8 *buf; - uint len[CNBUFS]; - uint32 crcr; - uint32 crc32tv[CNBUFS] = - {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; - - ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); - - /* step through all possible alignments */ - for (l = 0; l <= 4; l++) { - for (j = 0; j < CNBUFS; j++) { - len[j] = CLEN; - for (k = 0; k < len[j]; k++) - *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; - } - - for (j = 0; j < CNBUFS; j++) { - crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); - ASSERT(crcr == crc32tv[j]); - } - } - - MFREE(buf, CBUFSIZ*CNBUFS); - return; -} -#endif /* notdef */ - -/* - * Advance from the current 1-byte tag/1-byte length/variable-length value - * triple, to the next, returning a pointer to the next. - * If the current or next TLV is invalid (does not fit in given buffer length), - * NULL is returned. - * *buflen is not modified if the TLV elt parameter is invalid, or is decremented - * by the TLV parameter's length if it is valid. - */ -bcm_tlv_t * -bcm_next_tlv(bcm_tlv_t *elt, int *buflen) -{ - int len; - - /* validate current elt */ - if (!bcm_valid_tlv(elt, *buflen)) { - return NULL; - } - - /* advance to next elt */ - len = elt->len; - elt = (bcm_tlv_t*)(elt->data + len); - *buflen -= (TLV_HDR_LEN + len); - - /* validate next elt */ - if (!bcm_valid_tlv(elt, *buflen)) { - return NULL; - } - - return elt; -} - -/* - * 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 - */ -bcm_tlv_t * -bcm_parse_tlvs(void *buf, int buflen, uint key) -{ - bcm_tlv_t *elt; - int totlen; - - if ((elt = (bcm_tlv_t*)buf) == NULL) { - return NULL; - } - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - int len = elt->len; - - /* validate remaining totlen */ - if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { - - return (elt); - } - - elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - } - - return NULL; -} - -/* - * 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 - * return NULL if not found or length field < min_varlen - */ -bcm_tlv_t * -bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen) -{ - bcm_tlv_t * ret = bcm_parse_tlvs(buf, buflen, key); - if (ret == NULL || ret->len < min_bodylen) { - return NULL; - } - return ret; -} - -/* - * 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. Stop parsing when we see an element whose ID is greater - * than the target key. - */ -bcm_tlv_t * -bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) -{ - bcm_tlv_t *elt; - int totlen; - - elt = (bcm_tlv_t*)buf; - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - uint id = elt->id; - int len = elt->len; - - /* Punt if we start seeing IDs > than target key */ - if (id > key) { - return (NULL); - } - - /* validate remaining totlen */ - if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { - return (elt); - } - - elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - } - return NULL; -} -#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ - -#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ - defined(DHD_DEBUG) -int -bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len) -{ - int i, slen = 0; - uint32 bit, mask; - const char *name; - mask = bd->mask; - if (len < 2 || !buf) - return 0; - - buf[0] = '\0'; - - for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) { - bit = bd->bitfield[i].bit; - if ((flags & mask) == bit) { - if (len > (int)strlen(name)) { - slen = strlen(name); - strncpy(buf, name, slen+1); - } - break; - } - } - return slen; -} - -int -bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) -{ - int i; - char* p = buf; - char hexstr[16]; - int slen = 0, nlen = 0; - uint32 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, " "); - } - - /* 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 - -/* print bytes formatted as hex to a string. return the resulting string length */ -int -bcm_format_hex(char *str, const void *bytes, int len) -{ - int i; - char *p = str; - const uint8 *src = (const uint8*)bytes; - - for (i = 0; i < len; i++) { - p += snprintf(p, 3, "%02X", *src); - src++; - } - return (int)(p - str); -} - -/* pretty hex print a contiguous buffer */ -void -prhex(const char *msg, uchar *buf, uint nbytes) -{ - char line[128], *p; - int len = sizeof(line); - int nchar; - uint i; - - if (msg && (msg[0] != '\0')) - printf("%s:\n", msg); - - p = line; - for (i = 0; i < nbytes; i++) { - if (i % 16 == 0) { - nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ - p += nchar; - len -= nchar; - } - if (len > 0) { - nchar = snprintf(p, len, "%02x ", buf[i]); - p += nchar; - len -= nchar; - } - - if (i % 16 == 15) { - printf("%s\n", line); /* flush line */ - p = line; - len = sizeof(line); - } - } - - /* flush last partial line */ - if (p != line) - printf("%s\n", line); -} - -static const char *crypto_algo_names[] = { - "NONE", - "WEP1", - "TKIP", - "WEP128", - "AES_CCM", - "AES_OCB_MSDU", - "AES_OCB_MPDU", -#ifdef BCMCCX - "CKIP", - "CKIP_MMH", - "WEP_MMH", - "NALG", -#else - "NALG", - "UNDEF", - "UNDEF", - "UNDEF", -#endif /* BCMCCX */ - "WAPI", - "PMK", - "BIP", - "AES_GCM", - "AES_CCM256", - "AES_GCM256", - "BIP_CMAC256", - "BIP_GMAC", - "BIP_GMAC256", - "UNDEF" -}; - -const char * -bcm_crypto_algo_name(uint algo) -{ - return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; -} - - -char * -bcm_chipname(uint chipid, char *buf, uint len) -{ - const char *fmt; - - fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; - snprintf(buf, len, fmt, chipid); - return buf; -} - -/* Produce a human-readable string for boardrev */ -char * -bcm_brev_str(uint32 brev, char *buf) -{ - if (brev < 0x100) - snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); - else - snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); - - return (buf); -} - -#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ - -/* dump large strings to console */ -void -printbig(char *buf) -{ - uint len, max_len; - char c; - - len = (uint)strlen(buf); - - max_len = BUFSIZE_TODUMP_ATONCE; - - while (len > max_len) { - c = buf[max_len]; - buf[max_len] = '\0'; - printf("%s", buf); - buf[max_len] = c; - - buf += max_len; - len -= max_len; - } - /* print the remaining string */ - printf("%s\n", buf); - return; -} - -/* routine to dump fields in a fileddesc structure */ -uint -bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, - char *buf, uint32 bufsize) -{ - uint filled_len; - int len; - struct fielddesc *cur_ptr; - - filled_len = 0; - cur_ptr = fielddesc_array; - - while (bufsize > 1) { - if (cur_ptr->nameandfmt == NULL) - break; - len = snprintf(buf, bufsize, cur_ptr->nameandfmt, - read_rtn(arg0, arg1, cur_ptr->offset)); - /* check for snprintf overflow or error */ - if (len < 0 || (uint32)len >= bufsize) - len = bufsize - 1; - buf += len; - bufsize -= len; - filled_len += len; - cur_ptr++; - } - return filled_len; -} - -uint -bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) -{ - uint len; - - len = (uint)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; -} - -/* 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 uint16. - */ - -#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 uint16 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 -}; - -uint16 -bcm_qdbm_to_mw(uint8 qdbm) -{ - uint factor = 1; - int idx = qdbm - QDBM_OFFSET; - - if (idx >= QDBM_TABLE_LEN) { - /* clamp to max uint16 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); -} - -uint8 -bcm_mw_to_qdbm(uint16 mw) -{ - uint8 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 += (uint8)offset; - - return (qdbm); -} - - -uint -bcm_bitcount(uint8 *bitmap, uint length) -{ - uint bitcount = 0, i; - uint8 tmp; - for (i = 0; i < length; i++) { - tmp = bitmap[i]; - while (tmp) { - bitcount++; - tmp &= (tmp - 1); - } - } - return bitcount; -} - -#ifdef BCMDRIVER - -/* Initialization of bcmstrbuf structure */ -void -bcm_binit(struct bcmstrbuf *b, char *buf, uint size) -{ - b->origsize = b->size = size; - b->origbuf = b->buf = buf; -} - -/* Buffer sprintf wrapper to guard against buffer overflow */ -int -bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) -{ - va_list ap; - int r; - - va_start(ap, fmt); - - r = vsnprintf(b->buf, b->size, fmt, ap); - - /* Non Ansi C99 compliant returns -1, - * Ansi compliant return r >= b->size, - * bcmstdlib returns 0, handle all - */ - /* r == 0 is also the case when strlen(fmt) is zero. - * typically the case when "" is passed as argument. - */ - if ((r == -1) || (r >= (int)b->size)) { - b->size = 0; - } else { - b->size -= r; - b->buf += r; - } - - va_end(ap); - - return r; -} - -void -bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len) -{ - int i; - - if (msg != NULL && msg[0] != '\0') - bcm_bprintf(b, "%s", msg); - for (i = 0; i < len; i ++) - bcm_bprintf(b, "%02X", buf[i]); - if (newline) - bcm_bprintf(b, "\n"); -} - -void -bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) -{ - int i; - - for (i = 0; i < num_bytes; i++) { - num[i] += amount; - if (num[i] >= amount) - break; - amount = 1; - } -} - -int -bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) -{ - int i; - - for (i = nbytes - 1; i >= 0; i--) { - if (arg1[i] != arg2[i]) - return (arg1[i] - arg2[i]); - } - return 0; -} - -void -bcm_print_bytes(const char *name, const uchar *data, int len) -{ - int i; - int per_line = 0; - - printf("%s: %d \n", name ? name : "", len); - for (i = 0; i < len; i++) { - printf("%02x ", *data++); - per_line++; - if (per_line == 16) { - per_line = 0; - printf("\n"); - } - } - printf("\n"); -} - -/* Look for vendor-specific IE with specified OUI and optional type */ -bcm_tlv_t * -bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len) -{ - bcm_tlv_t *ie; - uint8 ie_len; - - ie = (bcm_tlv_t*)tlvs; - - /* make sure we are looking at a valid IE */ - if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) { - return NULL; - } - - /* Walk through the IEs looking for an OUI match */ - do { - ie_len = ie->len; - if ((ie->id == DOT11_MNG_PROPR_ID) && - (ie_len >= (DOT11_OUI_LEN + type_len)) && - !bcmp(ie->data, voui, DOT11_OUI_LEN)) - { - /* compare optional type */ - if (type_len == 0 || - !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { - return (ie); /* a match */ - } - } - } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL); - - return NULL; -} - -#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ - defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) -#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) - -int -bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) -{ - uint i, c; - char *p = buf; - char *endp = buf + SSID_FMT_BUF_LEN; - - if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; - - for (i = 0; i < ssid_len; i++) { - c = (uint)ssid[i]; - if (c == '\\') { - *p++ = '\\'; - *p++ = '\\'; - } else if (bcm_isprint((uchar)c)) { - *p++ = (char)c; - } else { - p += snprintf(p, (endp - p), "\\x%02X", c); - } - } - *p = '\0'; - ASSERT(p < endp); - - return (int)(p - buf); -} -#endif - -#endif /* BCMDRIVER */ - -/* - * ProcessVars:Takes a buffer of "=\n" lines read from a file and ending in a NUL. - * also accepts nvram files which are already in the format of =\0\=\0 - * 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. -*/ - -unsigned int -process_nvram_vars(char *varbuf, unsigned int len) -{ - char *dp; - bool findNewline; - int column; - unsigned int buf_len, n; - unsigned int pad = 0; - - dp = varbuf; - - findNewline = FALSE; - column = 0; - - for (n = 0; n < len; n++) { - 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 = (unsigned int)(dp - varbuf); - if (buf_len % 4) { - pad = 4 - buf_len % 4; - if (pad && (buf_len + pad <= len)) { - buf_len += pad; - } - } - - while (dp < varbuf + n) - *dp++ = 0; - - return buf_len; -} - -/* calculate a * b + c */ -void -bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c) -{ -#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;} - uint32 r1, r0; - uint32 a1, a0, b1, b0, t, cc = 0; - - a1 = a >> 16; - a0 = a & 0xffff; - b1 = b >> 16; - b0 = b & 0xffff; - - r0 = a0 * b0; - FORMALIZE(r0); - - t = (a1 * b0) << 16; - FORMALIZE(t); - - r0 += t; - FORMALIZE(r0); - - t = (a0 * b1) << 16; - FORMALIZE(t); - - r0 += t; - FORMALIZE(r0); - - FORMALIZE(c); - - r0 += c; - FORMALIZE(r0); - - r0 |= (cc % 2) ? 0x80000000 : 0; - r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2); - - *r_high = r1; - *r_low = r0; -} - -/* calculate a / b */ -void -bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b) -{ - uint32 a1 = a_high, a0 = a_low, r0 = 0; - - if (b < 2) - return; - - while (a1 != 0) { - r0 += (0xffffffff / b) * a1; - bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0); - } - - r0 += a0 / b; - *r = r0; -} - -#ifndef setbit /* As in the header file */ -#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS -/* Set bit in byte array. */ -void -setbit(void *array, uint bit) -{ - ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY); -} - -/* Clear bit in byte array. */ -void -clrbit(void *array, uint bit) -{ - ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY)); -} - -/* Test if bit is set in byte array. */ -bool -isset(const void *array, uint bit) -{ - return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))); -} - -/* Test if bit is clear in byte array. */ -bool -isclr(const void *array, uint bit) -{ - return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0); -} -#endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */ -#endif /* setbit */ - -void -set_bitrange(void *array, uint start, uint end, uint maxbit) -{ - uint startbyte = start/NBBY; - uint endbyte = end/NBBY; - uint i, startbytelastbit, endbytestartbit; - - if (end >= start) { - if (endbyte - startbyte > 1) - { - startbytelastbit = (startbyte+1)*NBBY - 1; - endbytestartbit = endbyte*NBBY; - for (i = startbyte+1; i < endbyte; i++) - ((uint8 *)array)[i] = 0xFF; - for (i = start; i <= startbytelastbit; i++) - setbit(array, i); - for (i = endbytestartbit; i <= end; i++) - setbit(array, i); - } else { - for (i = start; i <= end; i++) - setbit(array, i); - } - } - else { - set_bitrange(array, start, maxbit, maxbit); - set_bitrange(array, 0, end, maxbit); - } -} - -void -bcm_bitprint32(const uint32 u32) -{ - int i; - for (i = NBITS(uint32) - 1; i >= 0; i--) { - isbitset(u32, i) ? printf("1") : printf("0"); - if ((i % NBBY) == 0) printf(" "); - } - printf("\n"); -} - -/* calculate checksum for ip header, tcp / udp header / data */ -uint16 -bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum) -{ - while (len > 1) { - sum += (buf[0] << 8) | buf[1]; - buf += 2; - len -= 2; - } - - if (len > 0) { - sum += (*buf) << 8; - } - - while (sum >> 16) { - sum = (sum & 0xffff) + (sum >> 16); - } - - return ((uint16)~sum); -} - -#ifdef BCMDRIVER -/* - * Hierarchical Multiword bitmap based small id allocator. - * - * Multilevel hierarchy bitmap. (maximum 2 levels) - * First hierarchy uses a multiword bitmap to identify 32bit words in the - * second hierarchy that have at least a single bit set. Each bit in a word of - * the second hierarchy represents a unique ID that may be allocated. - * - * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed. - * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word - * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs. - * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non - * non-zero bitmap word carrying at least one free ID. - * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations. - * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID - * - * Design Notes: - * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many - * bits are computed each time on allocation and deallocation, requiring 4 - * array indexed access and 3 arithmetic operations. When not defined, a runtime - * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed. - * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation. - * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may - * be used by defining BCM_MWBMAP_USE_CNTSETBITS. - * - * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array - * size is fixed. No intention to support larger than 4K indice allocation. ID - * allocators for ranges smaller than 4K will have a wastage of only 12Bytes - * with savings in not having to use an indirect access, had it been dynamically - * allocated. - */ -#ifdef DHD_PKTID_AUDIT_ENABLED -#define BCM_MWBMAP_ITEMS_MAX (16 * 1024) /* May increase to 16K */ -#else -#define BCM_MWBMAP_ITEMS_MAX (4 * 1024) /* May increase to 16K */ -#endif /* DHD_PKTID_AUDIT_ENABLED */ - -#define BCM_MWBMAP_BITS_WORD (NBITS(uint32)) -#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD) -#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD) -#define BCM_MWBMAP_SHIFT_OP (5) -#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1)) -#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP) -#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP) - -/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */ -#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl)) -#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr)) - -#if defined(BCM_MWBMAP_DEBUG) -#define BCM_MWBMAP_AUDIT(mwb) \ - do { \ - ASSERT((mwb != NULL) && \ - (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \ - bcm_mwbmap_audit(mwb); \ - } while (0) -#define MWBMAP_ASSERT(exp) ASSERT(exp) -#define MWBMAP_DBG(x) printf x -#else /* !BCM_MWBMAP_DEBUG */ -#define BCM_MWBMAP_AUDIT(mwb) do {} while (0) -#define MWBMAP_ASSERT(exp) do {} while (0) -#define MWBMAP_DBG(x) -#endif /* !BCM_MWBMAP_DEBUG */ - - -typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ - uint16 wmaps; /* Total number of words in free wd bitmap */ - uint16 imaps; /* Total number of words in free id bitmap */ - int16 ifree; /* Count of free indices. Used only in audits */ - uint16 total; /* Total indices managed by multiword bitmap */ - - void * magic; /* Audit handle parameter from user */ - - uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */ -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */ -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - - uint32 id_bitmap[0]; /* Second level bitmap */ -} bcm_mwbmap_t; - -/* Incarnate a hierarchical multiword bitmap based small index allocator. */ -struct bcm_mwbmap * -bcm_mwbmap_init(osl_t *osh, uint32 items_max) -{ - struct bcm_mwbmap * mwbmap_p; - uint32 wordix, size, words, extra; - - /* Implementation Constraint: Uses 32bit word bitmap */ - MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U); - MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U); - MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX)); - MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U); - - ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX); - - /* Determine the number of words needed in the multiword bitmap */ - extra = BCM_MWBMAP_MODOP(items_max); - words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U); - - /* Allocate runtime state of multiword bitmap */ - /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ - size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); - mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); - if (mwbmap_p == (bcm_mwbmap_t *)NULL) { - ASSERT(0); - goto error1; - } - memset(mwbmap_p, 0, size); - - /* Initialize runtime multiword bitmap state */ - mwbmap_p->imaps = (uint16)words; - mwbmap_p->ifree = (int16)items_max; - mwbmap_p->total = (uint16)items_max; - - /* Setup magic, for use in audit of handle */ - mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p); - - /* Setup the second level bitmap of free indices */ - /* Mark all indices as available */ - for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) { - mwbmap_p->id_bitmap[wordix] = (uint32)(~0U); -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD; -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - } - - /* Ensure that extra indices are tagged as un-available */ - if (extra) { /* fixup the free ids in last bitmap and wd_count */ - uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1]; - *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */ -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - } - - /* Setup the first level bitmap hierarchy */ - extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps); - words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U); - - mwbmap_p->wmaps = (uint16)words; - - for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) - mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U); - if (extra) { - uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1]; - *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ - } - - return mwbmap_p; - -error1: - return BCM_MWBMAP_INVALID_HDL; -} - -/* Release resources used by multiword bitmap based small index allocator. */ -void -bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap) - + (sizeof(uint32) * mwbmap_p->imaps)); - return; -} - -/* Allocate a unique small index using a multiword bitmap index allocator. */ -uint32 BCMFASTPATH -bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - /* Start with the first hierarchy */ - for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) { - - bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */ - - if (bitmap != 0U) { - - uint32 count, bitix, *bitmap_p; - - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - - /* clear all except trailing 1 */ - bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); - MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == - bcm_count_leading_zeros(bitmap)); - bitix = (BCM_MWBMAP_BITS_WORD - 1) - - bcm_count_leading_zeros(bitmap); /* use asm clz */ - wordix = BCM_MWBMAP_MULOP(wordix) + bitix; - - /* Clear bit if wd count is 0, without conditional branch */ -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1; -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - mwbmap_p->wd_count[wordix]--; - count = mwbmap_p->wd_count[wordix]; - MWBMAP_ASSERT(count == - (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1)); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - MWBMAP_ASSERT(count >= 0); - - /* clear wd_bitmap bit if id_map count is 0 */ - bitmap = (count == 0) << bitix; - - MWBMAP_DBG(( - "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count)); - - *bitmap_p ^= bitmap; - - /* Use bitix in the second hierarchy */ - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */ - MWBMAP_ASSERT(bitmap != 0U); - - /* clear all except trailing 1 */ - bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); - MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == - bcm_count_leading_zeros(bitmap)); - bitix = BCM_MWBMAP_MULOP(wordix) - + (BCM_MWBMAP_BITS_WORD - 1) - - bcm_count_leading_zeros(bitmap); /* use asm clz */ - - mwbmap_p->ifree--; /* decrement system wide free count */ - MWBMAP_ASSERT(mwbmap_p->ifree >= 0); - - MWBMAP_DBG(( - "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, - mwbmap_p->ifree)); - - *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */ - - return bitix; - } - } - - ASSERT(mwbmap_p->ifree == 0); - - return BCM_MWBMAP_INVALID_IDX; -} - -/* Force an index at a specified position to be in use */ -void -bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 count, wordix, bitmap, *bitmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - /* Start with second hierarchy */ - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - ASSERT((*bitmap_p & bitmap) == bitmap); - - mwbmap_p->ifree--; /* update free count */ - ASSERT(mwbmap_p->ifree >= 0); - - MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, - mwbmap_p->ifree)); - - *bitmap_p ^= bitmap; /* mark as in use */ - - /* Update first hierarchy */ - bitix = wordix; - - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - mwbmap_p->wd_count[bitix]--; - count = mwbmap_p->wd_count[bitix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - MWBMAP_ASSERT(count >= 0); - - bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix); - - MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", - BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, - (*bitmap_p) ^ bitmap, count)); - - *bitmap_p ^= bitmap; /* mark as in use */ - - return; -} - -/* Free a previously allocated index back into the multiword bitmap allocator */ -void BCMFASTPATH -bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap, *bitmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - /* Start with second level hierarchy */ - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */ - - mwbmap_p->ifree++; /* update free count */ - ASSERT(mwbmap_p->ifree <= mwbmap_p->total); - - MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, - mwbmap_p->ifree)); - - *bitmap_p |= bitmap; /* mark as available */ - - /* Now update first level hierarchy */ - - bitix = wordix; - - wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */ - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[bitix]++; -#endif - -#if defined(BCM_MWBMAP_DEBUG) - { - uint32 count; -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[bitix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - - MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD); - - MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count)); - } -#endif /* BCM_MWBMAP_DEBUG */ - - *bitmap_p |= bitmap; - - return; -} - -/* Fetch the toal number of free indices in the multiword bitmap allocator */ -uint32 -bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(mwbmap_p->ifree >= 0); - - return mwbmap_p->ifree; -} - -/* Determine whether an index is inuse or free */ -bool -bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - - return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U); -} - -/* Debug dump a multiword bitmap allocator */ -void -bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl) -{ - uint32 ix, count; - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p, - mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total); - for (ix = 0U; ix < mwbmap_p->wmaps; ix++) { - printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]); - bcm_bitprint32(mwbmap_p->wd_bitmap[ix]); - printf("\n"); - } - for (ix = 0U; ix < mwbmap_p->imaps; ix++) { -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[ix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count); - bcm_bitprint32(mwbmap_p->id_bitmap[ix]); - printf("\n"); - } - - return; -} - -/* Audit a hierarchical multiword bitmap */ -void -bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p; - - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) { - - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - - for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { - if ((*bitmap_p) & (1 << bitix)) { - idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[idmap_ix]; - ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - ASSERT(count != 0U); - free_cnt += count; - } - } - } - - ASSERT((int)free_cnt == mwbmap_p->ifree); -} -/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ - -/* Simple 16bit Id allocator using a stack implementation. */ -typedef struct id16_map { - uint16 total; /* total number of ids managed by allocator */ - uint16 start; /* start value of 16bit ids to be managed */ - uint32 failures; /* count of failures */ - void *dbg; /* debug placeholder */ - int stack_idx; /* index into stack of available ids */ - uint16 stack[0]; /* stack of 16 bit ids */ -} id16_map_t; - -#define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \ - (sizeof(uint16) * (items))) - -#if defined(BCM_DBG) - -/* Uncomment BCM_DBG_ID16 to debug double free */ -/* #define BCM_DBG_ID16 */ - -typedef struct id16_map_dbg { - uint16 total; - bool avail[0]; -} id16_map_dbg_t; -#define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \ - (sizeof(bool) * (items))) -#define ID16_MAP_MSG(x) print x -#else -#define ID16_MAP_MSG(x) -#endif /* BCM_DBG */ - -void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */ -id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16) -{ - uint16 idx, val16; - id16_map_t * id16_map; - - ASSERT(total_ids > 0); - ASSERT((start_val16 + total_ids) < ID16_INVALID); - - id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids)); - if (id16_map == NULL) { - return NULL; - } - - id16_map->total = total_ids; - id16_map->start = start_val16; - id16_map->failures = 0; - id16_map->dbg = NULL; - - /* Populate stack with 16bit id values, commencing with start_val16 */ - id16_map->stack_idx = 0; - val16 = start_val16; - - for (idx = 0; idx < total_ids; idx++, val16++) { - id16_map->stack_idx = idx; - id16_map->stack[id16_map->stack_idx] = val16; - } - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids)); - - if (id16_map->dbg) { - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - id16_map_dbg->total = total_ids; - for (idx = 0; idx < total_ids; idx++) { - id16_map_dbg->avail[idx] = TRUE; - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - return (void *)id16_map; -} - -void * /* Destruct an id16 allocator instance */ -id16_map_fini(osl_t *osh, void * id16_map_hndl) -{ - uint16 total_ids; - id16_map_t * id16_map; - - if (id16_map_hndl == NULL) - return NULL; - - id16_map = (id16_map_t *)id16_map_hndl; - - total_ids = id16_map->total; - ASSERT(total_ids > 0); - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids)); - id16_map->dbg = NULL; - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - id16_map->total = 0; - MFREE(osh, id16_map, ID16_MAP_SZ(total_ids)); - - return NULL; -} - -void -id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16) -{ - uint16 idx, val16; - id16_map_t * id16_map; - - ASSERT(total_ids > 0); - ASSERT((start_val16 + total_ids) < ID16_INVALID); - - id16_map = (id16_map_t *)id16_map_hndl; - if (id16_map == NULL) { - return; - } - - id16_map->total = total_ids; - id16_map->start = start_val16; - id16_map->failures = 0; - - /* Populate stack with 16bit id values, commencing with start_val16 */ - id16_map->stack_idx = 0; - val16 = start_val16; - - for (idx = 0; idx < total_ids; idx++, val16++) { - id16_map->stack_idx = idx; - id16_map->stack[id16_map->stack_idx] = val16; - } - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - id16_map_dbg->total = total_ids; - for (idx = 0; idx < total_ids; idx++) { - id16_map_dbg->avail[idx] = TRUE; - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ -} - -uint16 BCMFASTPATH /* Allocate a unique 16bit id */ -id16_map_alloc(void * id16_map_hndl) -{ - uint16 val16; - id16_map_t * id16_map; - - ASSERT(id16_map_hndl != NULL); - - id16_map = (id16_map_t *)id16_map_hndl; - - ASSERT(id16_map->total > 0); - - if (id16_map->stack_idx < 0) { - id16_map->failures++; - return ID16_INVALID; - } - - val16 = id16_map->stack[id16_map->stack_idx]; - id16_map->stack_idx--; - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - - ASSERT(val16 < (id16_map->start + id16_map->total)); - - if (id16_map->dbg) { /* Validate val16 */ - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE); - id16_map_dbg->avail[val16 - id16_map->start] = FALSE; - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - return val16; -} - - -void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */ -id16_map_free(void * id16_map_hndl, uint16 val16) -{ - id16_map_t * id16_map; - - ASSERT(id16_map_hndl != NULL); - - id16_map = (id16_map_t *)id16_map_hndl; - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - - ASSERT(val16 < (id16_map->start + id16_map->total)); - - if (id16_map->dbg) { /* Validate val16 */ - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE); - id16_map_dbg->avail[val16 - id16_map->start] = TRUE; - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - if (id16_map->stack_idx >= id16_map->total) - return; - - id16_map->stack_idx++; - id16_map->stack[id16_map->stack_idx] = val16; -} - -uint32 /* Returns number of failures to allocate an unique id16 */ -id16_map_failures(void * id16_map_hndl) -{ - ASSERT(id16_map_hndl != NULL); - return ((id16_map_t *)id16_map_hndl)->failures; -} - -bool -id16_map_audit(void * id16_map_hndl) -{ - int idx; - int insane = 0; - id16_map_t * id16_map; - - ASSERT(id16_map_hndl != NULL); - - id16_map = (id16_map_t *)id16_map_hndl; - - ASSERT((id16_map->stack_idx > 0) && (id16_map->stack_idx < id16_map->total)); - for (idx = 0; idx <= id16_map->stack_idx; idx++) { - ASSERT(id16_map->stack[idx] >= id16_map->start); - ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total)); - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - uint16 val16 = id16_map->stack[idx]; - if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) { - insane |= 1; - ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n", - id16_map_hndl, idx, val16)); - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - } - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - uint16 avail = 0; /* Audit available ids counts */ - for (idx = 0; idx < id16_map_dbg->total; idx++) { - if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE) - avail++; - } - if (avail && (avail != (id16_map->stack_idx + 1))) { - insane |= 1; - ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n", - id16_map_hndl, avail, id16_map->stack_idx)); - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - return (!!insane); -} -/* END: Simple id16 allocator */ - - -#endif /* BCMDRIVER */ - -/* calculate a >> b; and returns only lower 32 bits */ -void -bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b) -{ - uint32 a1 = a_high, a0 = a_low, r0 = 0; - - if (b == 0) { - r0 = a_low; - *r = r0; - return; - } - - if (b < 32) { - a0 = a0 >> b; - a1 = a1 & ((1 << b) - 1); - a1 = a1 << (32 - b); - r0 = a0 | a1; - *r = r0; - return; - } else { - r0 = a1 >> (b - 32); - *r = r0; - return; - } - -} - -/* calculate a + b where a is a 64 bit number and b is a 32 bit number */ -void -bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset) -{ - uint32 r1_lo = *r_lo; - (*r_lo) += offset; - if (*r_lo < r1_lo) - (*r_hi) ++; -} - -/* calculate a - b where a is a 64 bit number and b is a 32 bit number */ -void -bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset) -{ - uint32 r1_lo = *r_lo; - (*r_lo) -= offset; - if (*r_lo > r1_lo) - (*r_hi) --; -} - -#ifdef DEBUG_COUNTER -#if (OSL_SYSUPTIME_SUPPORT == TRUE) -void counter_printlog(counter_tbl_t *ctr_tbl) -{ - uint32 now; - - if (!ctr_tbl->enabled) - return; - - now = OSL_SYSUPTIME(); - - if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) { - uint8 i = 0; - printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print); - - for (i = 0; i < ctr_tbl->needed_cnt; i++) { - printf(" %u", ctr_tbl->cnt[i]); - } - printf("\n"); - - ctr_tbl->prev_log_print = now; - bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint)); - } -} -#else -/* OSL_SYSUPTIME is not supported so no way to get time */ -#define counter_printlog(a) do {} while (0) -#endif /* OSL_SYSUPTIME_SUPPORT == TRUE */ -#endif /* DEBUG_COUNTER */ - -#ifdef BCMDRIVER -void -dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size) -{ - uint32 mem_size; - mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); - if (pool) - MFREE(osh, pool, mem_size); -} -dll_pool_t * -dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size) -{ - uint32 mem_size, i; - dll_pool_t * dll_pool_p; - dll_t * elem_p; - - ASSERT(elem_size > sizeof(dll_t)); - - mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); - - if ((dll_pool_p = (dll_pool_t *)MALLOC(osh, mem_size)) == NULL) { - printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n", - elems_max, elem_size); - ASSERT(0); - return dll_pool_p; - } - - bzero(dll_pool_p, mem_size); - - dll_init(&dll_pool_p->free_list); - dll_pool_p->elems_max = elems_max; - dll_pool_p->elem_size = elem_size; - - elem_p = dll_pool_p->elements; - for (i = 0; i < elems_max; i++) { - dll_append(&dll_pool_p->free_list, elem_p); - elem_p = (dll_t *)((uintptr)elem_p + elem_size); - } - - dll_pool_p->free_count = elems_max; - - return dll_pool_p; -} - - -void * -dll_pool_alloc(dll_pool_t * dll_pool_p) -{ - dll_t * elem_p; - - if (dll_pool_p->free_count == 0) { - ASSERT(dll_empty(&dll_pool_p->free_list)); - return NULL; - } - - elem_p = dll_head_p(&dll_pool_p->free_list); - dll_delete(elem_p); - dll_pool_p->free_count -= 1; - - return (void *)elem_p; -} - -void -dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p) -{ - dll_t * node_p = (dll_t *)elem_p; - dll_prepend(&dll_pool_p->free_list, node_p); - dll_pool_p->free_count += 1; -} - - -void -dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p) -{ - dll_t * node_p = (dll_t *)elem_p; - dll_append(&dll_pool_p->free_list, node_p); - dll_pool_p->free_count += 1; -} - -#endif /* BCMDRIVER */ diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd/bcmwifi_channels.c deleted file mode 100644 index 1a4b0f8992ac..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmwifi_channels.c +++ /dev/null @@ -1,1229 +0,0 @@ -/* - * Misc utility routines used by kernel or app-level. - * Contents are wifi-specific, used by any kernel or app-level - * software that might want wifi things as it grows. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ - */ - -#include -#include -#include - -#ifdef BCMDRIVER -#include -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) -#else -#include -#include -#include -#ifndef ASSERT -#define ASSERT(exp) -#endif -#endif /* BCMDRIVER */ - -#include - -#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) -#include /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ -#endif - -/* Definitions for D11AC capable Chanspec type */ - -/* Chanspec ASCII representation with 802.11ac capability: - * [ 'g'] ['/' []['/'<1st80channel>'-'<2nd80channel>]] - * - * : - * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. - * Default value is 2g if channel <= 14, otherwise 5g. - * : - * channel number of the 5MHz, 10MHz, 20MHz channel, - * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. - * : - * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. - * : - * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. - * - * For 2.4GHz band 40MHz channels, the same primary channel may be the - * upper sideband for one 40MHz channel, and the lower sideband for an - * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel - * is being specified. - * - * For 40MHz in the 5GHz band and all channel bandwidths greater than - * 40MHz, the U/L specificaion is not allowed since the channels are - * non-overlapping and the primary sub-band is derived from its - * position in the wide bandwidth channel. - * - * <1st80Channel>: - * <2nd80Channel>: - * Required for 80+80, otherwise not allowed. - * Specifies the center channel of the first and second 80MHz band. - * - * In its simplest form, it is a 20MHz channel number, with the implied band - * of 2.4GHz if channel number <= 14, and 5GHz otherwise. - * - * To allow for backward compatibility with scripts, the old form for - * 40MHz channels is also allowed: - * - * : - * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz - * : - * "U" for upper, "L" for lower (or lower case "u" "l") - * - * 5 GHz Examples: - * Chanspec BW Center Ch Channel Range Primary Ch - * 5g8 20MHz 8 - - - * 52 20MHz 52 - - - * 52/40 40MHz 54 52-56 52 - * 56/40 40MHz 54 52-56 56 - * 52/80 80MHz 58 52-64 52 - * 56/80 80MHz 58 52-64 56 - * 60/80 80MHz 58 52-64 60 - * 64/80 80MHz 58 52-64 64 - * 52/160 160MHz 50 36-64 52 - * 36/160 160MGz 50 36-64 36 - * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 - * - * 2 GHz Examples: - * Chanspec BW Center Ch Channel Range Primary Ch - * 2g8 20MHz 8 - - - * 8 20MHz 8 - - - * 6 20MHz 6 - - - * 6/40l 40MHz 8 6-10 6 - * 6l 40MHz 8 6-10 6 - * 6/40u 40MHz 4 2-6 6 - * 6u 40MHz 4 2-6 6 - */ - -/* bandwidth ASCII string */ -static const char *wf_chspec_bw_str[] = -{ - "5", - "10", - "20", - "40", - "80", - "160", - "80+80", - "na" -}; - -static const uint8 wf_chspec_bw_mhz[] = -{5, 10, 20, 40, 80, 160, 160}; - -#define WF_NUM_BW \ - (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) - -/* 40MHz channels in 5GHz band */ -static const uint8 wf_5g_40m_chans[] = -{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; -#define WF_NUM_5G_40M_CHANS \ - (sizeof(wf_5g_40m_chans)/sizeof(uint8)) - -/* 80MHz channels in 5GHz band */ -static const uint8 wf_5g_80m_chans[] = -{42, 58, 106, 122, 138, 155}; -#define WF_NUM_5G_80M_CHANS \ - (sizeof(wf_5g_80m_chans)/sizeof(uint8)) - -/* 160MHz channels in 5GHz band */ -static const uint8 wf_5g_160m_chans[] = -{50, 114}; -#define WF_NUM_5G_160M_CHANS \ - (sizeof(wf_5g_160m_chans)/sizeof(uint8)) - - -/* convert bandwidth from chanspec to MHz */ -static uint -bw_chspec_to_mhz(chanspec_t chspec) -{ - uint bw; - - bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; - return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); -} - -/* bw in MHz, return the channel count from the center channel to the - * the channel at the edge of the band - */ -static uint8 -center_chan_to_edge(uint bw) -{ - /* edge channels separated by BW - 10MHz on each side - * delta from cf to edge is half of that, - * MHz to channel num conversion is 5MHz/channel - */ - return (uint8)(((bw - 20) / 2) / 5); -} - -/* return channel number of the low edge of the band - * given the center channel and BW - */ -static uint8 -channel_low_edge(uint center_ch, uint bw) -{ - return (uint8)(center_ch - center_chan_to_edge(bw)); -} - -/* return side band number given center channel and control channel - * return -1 on error - */ -static int -channel_to_sb(uint center_ch, uint ctl_ch, uint bw) -{ - uint lowest = channel_low_edge(center_ch, bw); - uint sb; - - if ((ctl_ch - lowest) % 4) { - /* bad ctl channel, not mult 4 */ - return -1; - } - - sb = ((ctl_ch - lowest) / 4); - - /* sb must be a index to a 20MHz channel in range */ - if (sb >= (bw / 20)) { - /* ctl_ch must have been too high for the center_ch */ - return -1; - } - - return sb; -} - -/* return control channel given center channel and side band */ -static uint8 -channel_to_ctl_chan(uint center_ch, uint bw, uint sb) -{ - return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); -} - -/* return index of 80MHz channel from channel number - * return -1 on error - */ -static int -channel_80mhz_to_id(uint ch) -{ - uint i; - for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { - if (ch == wf_5g_80m_chans[i]) - return i; - } - - return -1; -} - -/* wrapper function for wf_chspec_ntoa. In case of an error it puts - * the original chanspec in the output buffer, prepended with "invalid". - * Can be directly used in print routines as it takes care of null - */ -char * -wf_chspec_ntoa_ex(chanspec_t chspec, char *buf) -{ - if (wf_chspec_ntoa(chspec, buf) == NULL) - snprintf(buf, CHANSPEC_STR_LEN, "invalid 0x%04x", chspec); - return buf; -} - -/* given a chanspec and a string buffer, format the chanspec as a - * string, and return the original pointer a. - * Min buffer length must be CHANSPEC_STR_LEN. - * On error return NULL - */ -char * -wf_chspec_ntoa(chanspec_t chspec, char *buf) -{ - const char *band; - uint ctl_chan; - - if (wf_chspec_malformed(chspec)) - return NULL; - - band = ""; - - /* check for non-default band spec */ - if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || - (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) - band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; - - /* ctl channel */ - ctl_chan = wf_chspec_ctlchan(chspec); - - /* bandwidth and ctl sideband */ - if (CHSPEC_IS20(chspec)) { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); - } else if (!CHSPEC_IS8080(chspec)) { - const char *bw; - const char *sb = ""; - - bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; - -#ifdef CHANSPEC_NEW_40MHZ_FORMAT - /* ctl sideband string if needed for 2g 40MHz */ - if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { - sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; - } - - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); -#else - /* ctl sideband string instead of BW for 40MHz */ - if (CHSPEC_IS40(chspec)) { - sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; - snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); - } else { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); - } -#endif /* CHANSPEC_NEW_40MHZ_FORMAT */ - - } else { - /* 80+80 */ - uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; - uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; - - /* convert to channel number */ - chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; - chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; - - /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ - snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); - } - - return (buf); -} - -static int -read_uint(const char **p, unsigned int *num) -{ - unsigned long val; - char *endp = NULL; - - val = strtoul(*p, &endp, 10); - /* if endp is the initial pointer value, then a number was not read */ - if (endp == *p) - return 0; - - /* advance the buffer pointer to the end of the integer string */ - *p = endp; - /* return the parsed integer */ - *num = (unsigned int)val; - - return 1; -} - -/* given a chanspec string, convert to a chanspec. - * On error return 0 - */ -chanspec_t -wf_chspec_aton(const char *a) -{ - chanspec_t chspec; - uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; - uint num, ctl_ch; - uint ch1, ch2; - char c, sb_ul = '\0'; - int i; - - bw = 20; - chspec_sb = 0; - chspec_ch = ch1 = ch2 = 0; - - /* parse channel num or band */ - if (!read_uint(&a, &num)) - return 0; - - /* if we are looking at a 'g', then the first number was a band */ - c = tolower((int)a[0]); - if (c == 'g') { - a ++; /* consume the char */ - - /* band must be "2" or "5" */ - if (num == 2) - chspec_band = WL_CHANSPEC_BAND_2G; - else if (num == 5) - chspec_band = WL_CHANSPEC_BAND_5G; - else - return 0; - - /* read the channel number */ - if (!read_uint(&a, &ctl_ch)) - return 0; - - c = tolower((int)a[0]); - } - else { - /* first number is channel, use default for band */ - ctl_ch = num; - chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); - } - - if (c == '\0') { - /* default BW of 20MHz */ - chspec_bw = WL_CHANSPEC_BW_20; - goto done_read; - } - - a ++; /* consume the 'u','l', or '/' */ - - /* check 'u'/'l' */ - if (c == 'u' || c == 'l') { - sb_ul = c; - chspec_bw = WL_CHANSPEC_BW_40; - goto done_read; - } - - /* next letter must be '/' */ - if (c != '/') - return 0; - - /* read bandwidth */ - if (!read_uint(&a, &bw)) - return 0; - - /* convert to chspec value */ - if (bw == 20) { - chspec_bw = WL_CHANSPEC_BW_20; - } else if (bw == 40) { - chspec_bw = WL_CHANSPEC_BW_40; - } else if (bw == 80) { - chspec_bw = WL_CHANSPEC_BW_80; - } else if (bw == 160) { - chspec_bw = WL_CHANSPEC_BW_160; - } else { - return 0; - } - - /* So far we have g/ - * Can now be followed by u/l if bw = 40, - * or '+80' if bw = 80, to make '80+80' bw. - */ - - c = tolower((int)a[0]); - - /* if we have a 2g/40 channel, we should have a l/u spec now */ - if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { - if (c == 'u' || c == 'l') { - a ++; /* consume the u/l char */ - sb_ul = c; - goto done_read; - } - } - - /* check for 80+80 */ - if (c == '+') { - /* 80+80 */ - static const char *plus80 = "80/"; - - /* must be looking at '+80/' - * check and consume this string. - */ - chspec_bw = WL_CHANSPEC_BW_8080; - - a ++; /* consume the char '+' */ - - /* consume the '80/' string */ - for (i = 0; i < 3; i++) { - if (*a++ != *plus80++) { - return 0; - } - } - - /* read primary 80MHz channel */ - if (!read_uint(&a, &ch1)) - return 0; - - /* must followed by '-' */ - if (a[0] != '-') - return 0; - a ++; /* consume the char */ - - /* read secondary 80MHz channel */ - if (!read_uint(&a, &ch2)) - return 0; - } - -done_read: - /* skip trailing white space */ - while (a[0] == ' ') { - a ++; - } - - /* must be end of string */ - if (a[0] != '\0') - return 0; - - /* Now have all the chanspec string parts read; - * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. - * chspec_band and chspec_bw are chanspec values. - * Need to convert ctl_ch, sb_ul, and ch1,ch2 into - * a center channel (or two) and sideband. - */ - - /* if a sb u/l string was given, just use that, - * guaranteed to be bw = 40 by sting parse. - */ - if (sb_ul != '\0') { - if (sb_ul == 'l') { - chspec_ch = UPPER_20_SB(ctl_ch); - chspec_sb = WL_CHANSPEC_CTL_SB_LLL; - } else if (sb_ul == 'u') { - chspec_ch = LOWER_20_SB(ctl_ch); - chspec_sb = WL_CHANSPEC_CTL_SB_LLU; - } - } - /* if the bw is 20, center and sideband are trivial */ - else if (chspec_bw == WL_CHANSPEC_BW_20) { - chspec_ch = ctl_ch; - chspec_sb = WL_CHANSPEC_CTL_SB_NONE; - } - /* if the bw is 40/80/160, not 80+80, a single method - * can be used to to find the center and sideband - */ - else if (chspec_bw != WL_CHANSPEC_BW_8080) { - /* figure out ctl sideband based on ctl channel and bandwidth */ - const uint8 *center_ch = NULL; - int num_ch = 0; - int sb = -1; - - if (chspec_bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - } else { - return 0; - } - - for (i = 0; i < num_ch; i ++) { - sb = channel_to_sb(center_ch[i], ctl_ch, bw); - if (sb >= 0) { - chspec_ch = center_ch[i]; - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; - break; - } - } - - /* check for no matching sb/center */ - if (sb < 0) { - return 0; - } - } - /* Otherwise, bw is 80+80. Figure out channel pair and sb */ - else { - int ch1_id = 0, ch2_id = 0; - int sb; - - /* look up the channel ID for the specified channel numbers */ - ch1_id = channel_80mhz_to_id(ch1); - ch2_id = channel_80mhz_to_id(ch2); - - /* validate channels */ - if (ch1_id < 0 || ch2_id < 0) - return 0; - - /* combine 2 channel IDs in channel field of chspec */ - chspec_ch = (((uint)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | - ((uint)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); - - /* figure out primary 20 MHz sideband */ - - /* is the primary channel contained in the 1st 80MHz channel? */ - sb = channel_to_sb(ch1, ctl_ch, bw); - if (sb < 0) { - /* no match for primary channel 'ctl_ch' in segment0 80MHz channel */ - return 0; - } - - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; - } - - chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); - - if (wf_chspec_malformed(chspec)) - return 0; - - return chspec; -} - -/* - * 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. - */ -bool -wf_chspec_malformed(chanspec_t chanspec) -{ - uint chspec_bw = CHSPEC_BW(chanspec); - uint chspec_ch = CHSPEC_CHANNEL(chanspec); - - /* must be 2G or 5G band */ - if (CHSPEC_IS2G(chanspec)) { - /* must be valid bandwidth */ - if (chspec_bw != WL_CHANSPEC_BW_20 && - chspec_bw != WL_CHANSPEC_BW_40) { - return TRUE; - } - } else if (CHSPEC_IS5G(chanspec)) { - if (chspec_bw == WL_CHANSPEC_BW_8080) { - uint ch1_id, ch2_id; - - /* channel IDs in 80+80 must be in range */ - ch1_id = CHSPEC_CHAN1(chanspec); - ch2_id = CHSPEC_CHAN2(chanspec); - if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) - return TRUE; - - } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || - chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { - - if (chspec_ch > MAXCHANNEL) { - return TRUE; - } - } else { - /* invalid bandwidth */ - return TRUE; - } - } else { - /* must be 2G or 5G band */ - return TRUE; - } - - /* side band needs to be consistent with bandwidth */ - if (chspec_bw == WL_CHANSPEC_BW_20) { - if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_40) { - if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_80 || - chspec_bw == WL_CHANSPEC_BW_8080) { - if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) - return TRUE; - } - else if (chspec_bw == WL_CHANSPEC_BW_160) { - ASSERT(CHSPEC_CTL_SB(chanspec) <= WL_CHANSPEC_CTL_SB_UUU); - } - return FALSE; -} - -/* - * Verify the chanspec specifies a valid channel according to 802.11. - * RETURNS: TRUE if the chanspec is a valid 802.11 channel - */ -bool -wf_chspec_valid(chanspec_t chanspec) -{ - uint chspec_bw = CHSPEC_BW(chanspec); - uint chspec_ch = CHSPEC_CHANNEL(chanspec); - - if (wf_chspec_malformed(chanspec)) - return FALSE; - - if (CHSPEC_IS2G(chanspec)) { - /* must be valid bandwidth and channel range */ - if (chspec_bw == WL_CHANSPEC_BW_20) { - if (chspec_ch >= 1 && chspec_ch <= 14) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_40) { - if (chspec_ch >= 3 && chspec_ch <= 11) - return TRUE; - } - } else if (CHSPEC_IS5G(chanspec)) { - if (chspec_bw == WL_CHANSPEC_BW_8080) { - uint16 ch1, ch2; - - ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; - ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; - - /* the two channels must be separated by more than 80MHz by VHT req */ - if ((ch2 > ch1 + CH_80MHZ_APART) || - (ch1 > ch2 + CH_80MHZ_APART)) - return TRUE; - } else { - const uint8 *center_ch; - uint num_ch, i; - - if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - } else { - /* invalid bandwidth */ - return FALSE; - } - - /* check for a valid center channel */ - if (chspec_bw == WL_CHANSPEC_BW_20) { - /* We don't have an array of legal 20MHz 5G channels, but they are - * each side of the legal 40MHz channels. Check the chanspec - * channel against either side of the 40MHz channels. - */ - for (i = 0; i < num_ch; i ++) { - if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || - chspec_ch == (uint)UPPER_20_SB(center_ch[i])) - break; /* match found */ - } - - if (i == num_ch) { - /* check for channel 165 which is not the side band - * of 40MHz 5G channel - */ - if (chspec_ch == 165) - i = 0; - - /* check for legacy JP channels on failure */ - if (chspec_ch == 34 || chspec_ch == 38 || - chspec_ch == 42 || chspec_ch == 46) - i = 0; - } - } else { - /* check the chanspec channel to each legal channel */ - for (i = 0; i < num_ch; i ++) { - if (chspec_ch == center_ch[i]) - break; /* match found */ - } - } - - if (i < num_ch) { - /* match found */ - return TRUE; - } - } - } - - return FALSE; -} - -/* - * This function returns the channel number that control traffic is being sent on, for 20MHz - * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ - * sideband depending on the chanspec selected - */ -uint8 -wf_chspec_ctlchan(chanspec_t chspec) -{ - uint center_chan; - uint bw_mhz; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - - /* Is there a sideband ? */ - if (CHSPEC_IS20(chspec)) { - return CHSPEC_CHANNEL(chspec); - } else { - sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; - - if (CHSPEC_IS8080(chspec)) { - /* For an 80+80 MHz channel, the sideband 'sb' field is an 80 MHz sideband - * (LL, LU, UL, LU) for the 80 MHz frequency segment 0. - */ - uint chan_id = CHSPEC_CHAN1(chspec); - - bw_mhz = 80; - - /* convert from channel index to channel number */ - center_chan = wf_5g_80m_chans[chan_id]; - } - else { - bw_mhz = bw_chspec_to_mhz(chspec); - center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; - } - - return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); - } -} - -/* given a chanspec, return the bandwidth string */ -char * -wf_chspec_to_bw_str(chanspec_t chspec) -{ - return (char *)wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)]; -} - -/* - * This function returns the chanspec of the control channel of a given chanspec - */ -chanspec_t -wf_chspec_ctlchspec(chanspec_t chspec) -{ - chanspec_t ctl_chspec = chspec; - uint8 ctl_chan; - - ASSERT(!wf_chspec_malformed(chspec)); - - /* Is there a sideband ? */ - if (!CHSPEC_IS20(chspec)) { - ctl_chan = wf_chspec_ctlchan(chspec); - ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; - ctl_chspec |= CHSPEC_BAND(chspec); - } - return ctl_chspec; -} - -/* return chanspec given control channel and bandwidth - * return 0 on error - */ -uint16 -wf_channel2chspec(uint ctl_ch, uint bw) -{ - uint16 chspec; - const uint8 *center_ch = NULL; - int num_ch = 0; - int sb = -1; - int i = 0; - - chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); - - chspec |= bw; - - if (bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - bw = 40; - } else if (bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - bw = 80; - } else if (bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - bw = 160; - } else if (bw == WL_CHANSPEC_BW_20) { - chspec |= ctl_ch; - return chspec; - } else { - return 0; - } - - for (i = 0; i < num_ch; i ++) { - sb = channel_to_sb(center_ch[i], ctl_ch, bw); - if (sb >= 0) { - chspec |= center_ch[i]; - chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); - break; - } - } - - /* check for no matching sb/center */ - if (sb < 0) { - return 0; - } - - return chspec; -} - -/* - * This function returns the chanspec for the primary 40MHz of an 80MHz channel. - * The control sideband specifies the same 20MHz channel that the 80MHz channel is using - * as the primary 20MHz channel. - */ -extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) -{ - chanspec_t chspec40 = chspec; - uint center_chan; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - - /* if the chanspec is > 80MHz, use the helper routine to find the primary 80 MHz channel */ - if (CHSPEC_IS8080(chspec) || CHSPEC_IS160(chspec)) { - chspec = wf_chspec_primary80_chspec(chspec); - } - - /* determine primary 40 MHz sub-channel of an 80 MHz chanspec */ - if (CHSPEC_IS80(chspec)) { - center_chan = CHSPEC_CHANNEL(chspec); - sb = CHSPEC_CTL_SB(chspec); - - if (sb < WL_CHANSPEC_CTL_SB_UL) { - /* Primary 40MHz is on lower side */ - center_chan -= CH_20MHZ_APART; - /* sideband bits are the same for LL/LU and L/U */ - } else { - /* Primary 40MHz is on upper side */ - center_chan += CH_20MHZ_APART; - /* sideband bits need to be adjusted by UL offset */ - sb -= WL_CHANSPEC_CTL_SB_UL; - } - - /* Create primary 40MHz chanspec */ - chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | - sb | center_chan); - } - - return chspec40; -} - -/* - * Return the channel number for a given frequency and base frequency. - * The returned channel number is relative to the given base frequency. - * If the given base frequency is zero, a base frequency of 5 GHz is assumed for - * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. - * - * Frequency is specified in MHz. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for - * 2.4 GHz and 5 GHz bands. - * - * The returned channel will be in the range [1, 14] in the 2.4 GHz band - * and [0, 200] otherwise. - * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the - * frequency is not a 2.4 GHz channel, or if the frequency is not and even - * multiple of 5 MHz from the base frequency to the base plus 1 GHz. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - */ -int -wf_mhz2channel(uint freq, uint start_factor) -{ - int ch = -1; - uint base; - int offset; - - /* take the default channel start frequency */ - if (start_factor == 0) { - if (freq >= 2400 && freq <= 2500) - start_factor = WF_CHAN_FACTOR_2_4_G; - else if (freq >= 5000 && freq <= 6000) - start_factor = WF_CHAN_FACTOR_5_G; - } - - if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) - return 14; - - base = start_factor / 2; - - /* check that the frequency is in 1GHz range of the base */ - if ((freq < base) || (freq > base + 1000)) - return -1; - - offset = freq - base; - ch = offset / 5; - - /* check that frequency is a 5MHz multiple from the base */ - if (offset != (ch * 5)) - return -1; - - /* restricted channel range check for 2.4G */ - if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) - return -1; - - return ch; -} - -/* - * Return the center frequency in MHz of the given channel and base frequency. - * The channel number is interpreted relative to the given base frequency. - * - * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G - * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands. - * The channel range of [1, 14] is only checked for a start_factor of - * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2). - * Odd start_factors produce channels on .5 MHz boundaries, in which case - * the answer is rounded down to an integral MHz. - * -1 is returned for an out of range channel. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - */ -int -wf_channel2mhz(uint ch, uint start_factor) -{ - int freq; - - if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || - (ch > 200)) - freq = -1; - else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) - freq = 2484; - else - freq = ch * 5 + start_factor / 2; - - return freq; -} - -static const uint16 sidebands[] = { - WL_CHANSPEC_CTL_SB_LLL, WL_CHANSPEC_CTL_SB_LLU, - WL_CHANSPEC_CTL_SB_LUL, WL_CHANSPEC_CTL_SB_LUU, - WL_CHANSPEC_CTL_SB_ULL, WL_CHANSPEC_CTL_SB_ULU, - WL_CHANSPEC_CTL_SB_UUL, WL_CHANSPEC_CTL_SB_UUU -}; - -/* - * Returns the chanspec 80Mhz channel corresponding to the following input - * parameters - * - * primary_channel - primary 20Mhz channel - * center_channel - center frequecny of the 80Mhz channel - * - * The center_channel can be one of {42, 58, 106, 122, 138, 155} - * - * returns INVCHANSPEC in case of error - */ -chanspec_t -wf_chspec_80(uint8 center_channel, uint8 primary_channel) -{ - - chanspec_t chanspec = INVCHANSPEC; - chanspec_t chanspec_cur; - uint i; - - for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) { - chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]); - if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) { - chanspec = chanspec_cur; - break; - } - } - /* If the loop ended early, we are good, otherwise we did not - * find a 80MHz chanspec with the given center_channel that had a primary channel - *matching the given primary_channel. - */ - return chanspec; -} - -/* - * Returns the 80+80 chanspec corresponding to the following input parameters - * - * primary_20mhz - Primary 20 MHz channel - * chan0 - center channel number of one frequency segment - * chan1 - center channel number of the other frequency segment - * - * Parameters chan0 and chan1 are channel numbers in {42, 58, 106, 122, 138, 155}. - * The primary channel must be contained in one of the 80MHz channels. This routine - * will determine which frequency segment is the primary 80 MHz segment. - * - * Returns INVCHANSPEC in case of error. - * - * Refer to IEEE802.11ac section 22.3.14 "Channelization". - */ -chanspec_t -wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan0, uint8 chan1) -{ - int sb = 0; - uint16 chanspec = 0; - int chan0_id = 0, chan1_id = 0; - int seg0, seg1; - - chan0_id = channel_80mhz_to_id(chan0); - chan1_id = channel_80mhz_to_id(chan1); - - /* make sure the channel numbers were valid */ - if (chan0_id == -1 || chan1_id == -1) - return INVCHANSPEC; - - /* does the primary channel fit with the 1st 80MHz channel ? */ - sb = channel_to_sb(chan0, primary_20mhz, 80); - if (sb >= 0) { - /* yes, so chan0 is frequency segment 0, and chan1 is seg 1 */ - seg0 = chan0_id; - seg1 = chan1_id; - } else { - /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ - sb = channel_to_sb(chan1, primary_20mhz, 80); - if (sb < 0) { - /* no match for ctl_ch to either 80MHz center channel */ - return INVCHANSPEC; - } - /* swapped, so chan1 is frequency segment 0, and chan0 is seg 1 */ - seg0 = chan1_id; - seg1 = chan0_id; - } - - chanspec = ((seg0 << WL_CHANSPEC_CHAN1_SHIFT) | - (seg1 << WL_CHANSPEC_CHAN2_SHIFT) | - (sb << WL_CHANSPEC_CTL_SB_SHIFT) | - WL_CHANSPEC_BW_8080 | - WL_CHANSPEC_BAND_5G); - - return chanspec; -} - -/* - * This function returns the 80Mhz channel for the given id. - */ -static uint8 -wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id) -{ - if (chan_80Mhz_id < WF_NUM_5G_80M_CHANS) - return wf_5g_80m_chans[chan_80Mhz_id]; - - return 0; -} - -/* - * Returns the primary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ - -uint8 -wf_chspec_primary80_channel(chanspec_t chanspec) -{ - uint8 primary80_chan; - - if (CHSPEC_IS80(chanspec)) { - primary80_chan = CHSPEC_CHANNEL(chanspec); - } - else if (CHSPEC_IS8080(chanspec)) { - /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ - primary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); - } - else if (CHSPEC_IS160(chanspec)) { - uint8 center_chan = CHSPEC_CHANNEL(chanspec); - uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; - - /* based on the sb value primary 80 channel can be retrieved - * if sb is in range 0 to 3 the lower band is the 80Mhz primary band - */ - if (sb < 4) { - primary80_chan = center_chan - CH_40MHZ_APART; - } - /* if sb is in range 4 to 7 the upper band is the 80Mhz primary band */ - else - { - primary80_chan = center_chan + CH_40MHZ_APART; - } - } - else { - /* for 20 and 40 Mhz */ - primary80_chan = -1; - } - return primary80_chan; -} - -/* - * Returns the secondary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40/80 Mhz chanspec - */ -uint8 -wf_chspec_secondary80_channel(chanspec_t chanspec) -{ - uint8 secondary80_chan; - - if (CHSPEC_IS8080(chanspec)) { - secondary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); - } - else if (CHSPEC_IS160(chanspec)) { - uint8 center_chan = CHSPEC_CHANNEL(chanspec); - uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; - - /* based on the sb value secondary 80 channel can be retrieved - * if sb is in range 0 to 3 upper band is the secondary 80Mhz band - */ - if (sb < 4) { - secondary80_chan = center_chan + CH_40MHZ_APART; - } - /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */ - else - { - secondary80_chan = center_chan - CH_40MHZ_APART; - } - } - else { - /* for 20, 40, and 80 Mhz */ - secondary80_chan = -1; - } - return secondary80_chan; -} - -/* - * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. - * - * chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived - * - * returns the input chanspec in case the provided chanspec is an 80 MHz chanspec - * returns INVCHANSPEC in case the provided channel is 20/40 MHz chanspec - */ -chanspec_t -wf_chspec_primary80_chspec(chanspec_t chspec) -{ - chanspec_t chspec80; - uint center_chan; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - if (CHSPEC_IS80(chspec)) { - chspec80 = chspec; - } - else if (CHSPEC_IS8080(chspec)) { - - /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ - center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); - - sb = CHSPEC_CTL_SB(chspec); - - /* Create primary 80MHz chanspec */ - chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); - } - else if (CHSPEC_IS160(chspec)) { - center_chan = CHSPEC_CHANNEL(chspec); - sb = CHSPEC_CTL_SB(chspec); - - if (sb < WL_CHANSPEC_CTL_SB_ULL) { - /* Primary 80MHz is on lower side */ - center_chan -= CH_40MHZ_APART; - } - else { - /* Primary 80MHz is on upper side */ - center_chan += CH_40MHZ_APART; - sb -= WL_CHANSPEC_CTL_SB_ULL; - } - /* Create primary 80MHz chanspec */ - chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); - } - else { - chspec80 = INVCHANSPEC; - } - - return chspec80; -} - -#ifdef WL11AC_80P80 -uint8 -wf_chspec_channel(chanspec_t chspec) -{ - if (CHSPEC_IS8080(chspec)) { - return wf_chspec_primary80_channel(chspec); - } - else { - return ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)); - } -} -#endif /* WL11AC_80P80 */ diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd/bcmwifi_channels.h deleted file mode 100644 index 44852f9ea30e..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmwifi_channels.h +++ /dev/null @@ -1,548 +0,0 @@ -/* - * Misc utility routines for WL and Apps - * This header file housing the define and function prototype use by - * both the wl driver, tools & Apps. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ - */ - -#ifndef _bcmwifi_channels_h_ -#define _bcmwifi_channels_h_ - - -/* A chanspec holds the channel number, band, bandwidth and control sideband */ -typedef uint16 chanspec_t; - -/* channel defines */ -#define CH_UPPER_SB 0x01 -#define CH_LOWER_SB 0x02 -#define CH_EWA_VALID 0x04 -#define CH_80MHZ_APART 16 -#define CH_40MHZ_APART 8 -#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 MAXCHANNEL 224 /* max # supported channels. The max channel no is above, - * this is that + 1 rounded up to a multiple of NBBY (8). - * DO NOT MAKE it > 255: channels are uint8's all over - */ -#define MAXCHANNEL_NUM (MAXCHANNEL - 1) /* max channel number */ - -/* make sure channel num is within valid range */ -#define CH_NUM_VALID_RANGE(ch_num) ((ch_num) > 0 && (ch_num) <= MAXCHANNEL_NUM) - -#define CHSPEC_CTLOVLP(sp1, sp2, sep) (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < \ - (sep)) - -/* All builds use the new 11ac ratespec/chanspec */ -#undef D11AC_IOTYPES -#define D11AC_IOTYPES - -#define WL_CHANSPEC_CHAN_MASK 0x00ff -#define WL_CHANSPEC_CHAN_SHIFT 0 -#define WL_CHANSPEC_CHAN1_MASK 0x000f -#define WL_CHANSPEC_CHAN1_SHIFT 0 -#define WL_CHANSPEC_CHAN2_MASK 0x00f0 -#define WL_CHANSPEC_CHAN2_SHIFT 4 - -#define WL_CHANSPEC_CTL_SB_MASK 0x0700 -#define WL_CHANSPEC_CTL_SB_SHIFT 8 -#define WL_CHANSPEC_CTL_SB_LLL 0x0000 -#define WL_CHANSPEC_CTL_SB_LLU 0x0100 -#define WL_CHANSPEC_CTL_SB_LUL 0x0200 -#define WL_CHANSPEC_CTL_SB_LUU 0x0300 -#define WL_CHANSPEC_CTL_SB_ULL 0x0400 -#define WL_CHANSPEC_CTL_SB_ULU 0x0500 -#define WL_CHANSPEC_CTL_SB_UUL 0x0600 -#define WL_CHANSPEC_CTL_SB_UUU 0x0700 -#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL -#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU -#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL - -#define WL_CHANSPEC_BW_MASK 0x3800 -#define WL_CHANSPEC_BW_SHIFT 11 -#define WL_CHANSPEC_BW_5 0x0000 -#define WL_CHANSPEC_BW_10 0x0800 -#define WL_CHANSPEC_BW_20 0x1000 -#define WL_CHANSPEC_BW_40 0x1800 -#define WL_CHANSPEC_BW_80 0x2000 -#define WL_CHANSPEC_BW_160 0x2800 -#define WL_CHANSPEC_BW_8080 0x3000 - -#define WL_CHANSPEC_BAND_MASK 0xc000 -#define WL_CHANSPEC_BAND_SHIFT 14 -#define WL_CHANSPEC_BAND_2G 0x0000 -#define WL_CHANSPEC_BAND_3G 0x4000 -#define WL_CHANSPEC_BAND_4G 0x8000 -#define WL_CHANSPEC_BAND_5G 0xc000 -#define INVCHANSPEC 255 - -/* channel defines */ -#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ - ((channel) - CH_10MHZ_APART) : 0) -#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ - ((channel) + CH_10MHZ_APART) : 0) - -#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) -#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ - ((channel) + 3 * CH_10MHZ_APART) : 0) -#define LU_20_SB(channel) LOWER_20_SB(channel) -#define UL_20_SB(channel) UPPER_20_SB(channel) - -#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) -#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) -#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) -#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ - (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ - ((channel) + CH_20MHZ_APART) : 0) -#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ - ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ - WL_CHANSPEC_BAND_5G)) -#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | \ - WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) -#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | \ - WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) - -/* simple MACROs to get different fields of chanspec */ -#ifdef WL11AC_80P80 -#define CHSPEC_CHANNEL(chspec) wf_chspec_channel(chspec) -#else -#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) -#endif -#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT -#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT -#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) - -#ifdef WL11N_20MHZONLY - -#define CHSPEC_IS10(chspec) 0 -#define CHSPEC_IS20(chspec) 1 -#ifndef CHSPEC_IS40 -#define CHSPEC_IS40(chspec) 0 -#endif -#ifndef CHSPEC_IS80 -#define CHSPEC_IS80(chspec) 0 -#endif -#ifndef CHSPEC_IS160 -#define CHSPEC_IS160(chspec) 0 -#endif -#ifndef CHSPEC_IS8080 -#define CHSPEC_IS8080(chspec) 0 -#endif - -#else /* !WL11N_20MHZONLY */ - -#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 -#ifndef CHSPEC_IS80 -#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) -#endif -#ifndef CHSPEC_IS160 -#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) -#endif -#ifndef CHSPEC_IS8080 -#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) -#endif - -#endif /* !WL11N_20MHZONLY */ - -#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_UPPER(chspec) \ - ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ - (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#define CHSPEC_SB_LOWER(chspec) \ - ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ - (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) - -/** - * Number of chars needed for wf_chspec_ntoa() destination character buffer. - */ -#define CHANSPEC_STR_LEN 20 - - -#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\ - CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080) - -/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made -* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80, -* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080). -* -* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide. -* If both chspec bandwidth and bw is not 160 wide, then the comparison is made. -*/ -#define CHSPEC_BW_GE(chspec, bw) \ - ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ - (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ - (CHSPEC_BW(chspec) >= bw)) - -#define CHSPEC_BW_LE(chspec, bw) \ - ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ - (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ - (CHSPEC_BW(chspec) <= bw)) - -#define CHSPEC_BW_GT(chspec, bw) \ - (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ - (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ - (CHSPEC_BW(chspec) > bw)) - -#define CHSPEC_BW_LT(chspec, bw) \ - (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ - (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ - (CHSPEC_BW(chspec) < bw)) - -/* Legacy Chanspec defines - * These are the defines for the previous format of the chanspec_t - */ -#define WL_LCHANSPEC_CHAN_MASK 0x00ff -#define WL_LCHANSPEC_CHAN_SHIFT 0 - -#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 -#define WL_LCHANSPEC_CTL_SB_SHIFT 8 -#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 -#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 -#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 - -#define WL_LCHANSPEC_BW_MASK 0x0C00 -#define WL_LCHANSPEC_BW_SHIFT 10 -#define WL_LCHANSPEC_BW_10 0x0400 -#define WL_LCHANSPEC_BW_20 0x0800 -#define WL_LCHANSPEC_BW_40 0x0C00 - -#define WL_LCHANSPEC_BAND_MASK 0xf000 -#define WL_LCHANSPEC_BAND_SHIFT 12 -#define WL_LCHANSPEC_BAND_5G 0x1000 -#define WL_LCHANSPEC_BAND_2G 0x2000 - -#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) -#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) -#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) -#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) -#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) -#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) -#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) -#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) -#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) - -#define LCHSPEC_SB_UPPER(chspec) \ - ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \ - (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) -#define LCHSPEC_SB_LOWER(chspec) \ - ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \ - (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) - -#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) - -#define CH20MHZ_LCHSPEC(channel) \ - (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \ - WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G)) - -/* - * WF_CHAN_FACTOR_* constants are used to calculate channel frequency - * given a channel number. - * chan_freq = chan_factor * 500Mhz + chan_number * 5 - */ - -/** - * Channel Factor for the starting frequence of 2.4 GHz channels. - * The value corresponds to 2407 MHz. - */ -#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ - -/** - * Channel Factor for the starting frequence of 5 GHz channels. - * The value corresponds to 5000 MHz. - */ -#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ - -/** - * Channel Factor for the starting frequence of 4.9 GHz channels. - * The value corresponds to 4000 MHz. - */ -#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ - -#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ - -/** - * No of sub-band vlaue of the specified Mhz chanspec - */ -#define WF_NUM_SIDEBANDS_40MHZ 2 -#define WF_NUM_SIDEBANDS_80MHZ 4 -#define WF_NUM_SIDEBANDS_8080MHZ 4 -#define WF_NUM_SIDEBANDS_160MHZ 8 - -/** - * Convert chanspec to ascii string - * - * @param chspec chanspec format - * @param buf ascii string of chanspec - * - * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes - * Original chanspec in case of error - * - * @see CHANSPEC_STR_LEN - */ -extern char * wf_chspec_ntoa_ex(chanspec_t chspec, char *buf); - -/** - * Convert chanspec to ascii string - * - * @param chspec chanspec format - * @param buf ascii string of chanspec - * - * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes - * NULL in case of error - * - * @see CHANSPEC_STR_LEN - */ -extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); - -/** - * Convert ascii string to chanspec - * - * @param a pointer to input string - * - * @return >= 0 if successful or 0 otherwise - */ -extern chanspec_t wf_chspec_aton(const char *a); - -/** - * Verify the chanspec fields are valid. - * - * Verify the chanspec is using a legal set field values, i.e. that the chanspec - * specified a band, bw, ctl_sb and channel and that the combination could be - * legal given some set of circumstances. - * - * @param chanspec input chanspec to verify - * - * @return TRUE if the chanspec is malformed, FALSE if it looks good. - */ -extern bool wf_chspec_malformed(chanspec_t chanspec); - -/** - * Verify the chanspec specifies a valid channel according to 802.11. - * - * @param chanspec input chanspec to verify - * - * @return TRUE if the chanspec is a valid 802.11 channel - */ -extern bool wf_chspec_valid(chanspec_t chanspec); - -/** - * Return the primary (control) channel. - * - * This function returns the channel number of the primary 20MHz channel. For - * 20MHz channels this is just the channel number. For 40MHz or wider channels - * it is the primary 20MHz channel specified by the chanspec. - * - * @param chspec input chanspec - * - * @return Returns the channel number of the primary 20MHz channel - */ -extern uint8 wf_chspec_ctlchan(chanspec_t chspec); - -/** - * Return the bandwidth string. - * - * This function returns the bandwidth string for the passed chanspec. - * - * @param chspec input chanspec - * - * @return Returns the bandwidth string - */ -extern char * wf_chspec_to_bw_str(chanspec_t chspec); - -/** - * Return the primary (control) chanspec. - * - * This function returns the chanspec of the primary 20MHz channel. For 20MHz - * channels this is just the chanspec. For 40MHz or wider channels it is the - * chanspec of the primary 20MHZ channel specified by the chanspec. - * - * @param chspec input chanspec - * - * @return Returns the chanspec of the primary 20MHz channel - */ -extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); - -/** - * Return a channel number corresponding to a frequency. - * - * This function returns the chanspec for the primary 40MHz of an 80MHz channel. - * The control sideband specifies the same 20MHz channel that the 80MHz channel is using - * as the primary 20MHz channel. - */ -extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); - -/* - * Return the channel number for a given frequency and base frequency. - * The returned channel number is relative to the given base frequency. - * If the given base frequency is zero, a base frequency of 5 GHz is assumed for - * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. - * - * Frequency is specified in MHz. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for - * 2.4 GHz and 5 GHz bands. - * - * The returned channel will be in the range [1, 14] in the 2.4 GHz band - * and [0, 200] otherwise. - * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the - * frequency is not a 2.4 GHz channel, or if the frequency is not and even - * multiple of 5 MHz from the base frequency to the base plus 1 GHz. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - * - * @param freq frequency in MHz - * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz - * - * @return Returns a channel number - * - * @see WF_CHAN_FACTOR_2_4_G - * @see WF_CHAN_FACTOR_5_G - */ -extern int wf_mhz2channel(uint freq, uint start_factor); - -/** - * Return the center frequency in MHz of the given channel and base frequency. - * - * Return the center frequency in MHz of the given channel and base frequency. - * The channel number is interpreted relative to the given base frequency. - * - * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for - * 2.4 GHz and 5 GHz bands. - * The channel range of [1, 14] is only checked for a start_factor of - * WF_CHAN_FACTOR_2_4_G (4814). - * Odd start_factors produce channels on .5 MHz boundaries, in which case - * the answer is rounded down to an integral MHz. - * -1 is returned for an out of range channel. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - * - * @param channel input channel number - * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz - * - * @return Returns a frequency in MHz - * - * @see WF_CHAN_FACTOR_2_4_G - * @see WF_CHAN_FACTOR_5_G - */ -extern int wf_channel2mhz(uint channel, uint start_factor); - -/** - * Returns the chanspec 80Mhz channel corresponding to the following input - * parameters - * - * primary_channel - primary 20Mhz channel - * center_channel - center frequecny of the 80Mhz channel - * - * The center_channel can be one of {42, 58, 106, 122, 138, 155} - * - * returns INVCHANSPEC in case of error - */ -extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel); - -/** - * Convert ctl chan and bw to chanspec - * - * @param ctl_ch channel - * @param bw bandwidth - * - * @return > 0 if successful or 0 otherwise - * - */ -extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); - -extern uint wf_channel2freq(uint channel); -extern uint wf_freq2channel(uint freq); - -/* - * Returns the 80+80 MHz chanspec corresponding to the following input parameters - * - * primary_20mhz - Primary 20 MHz channel - * chan0_80MHz - center channel number of one frequency segment - * chan1_80MHz - center channel number of the other frequency segment - * - * Parameters chan0_80MHz and chan1_80MHz are channel numbers in {42, 58, 106, 122, 138, 155}. - * The primary channel must be contained in one of the 80MHz channels. This routine - * will determine which frequency segment is the primary 80 MHz segment. - * - * Returns INVCHANSPEC in case of error. - * - * Refer to IEEE802.11ac section 22.3.14 "Channelization". - */ -extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz, - uint8 chan0_80Mhz, uint8 chan1_80Mhz); - -/* - * Returns the primary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ -extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec); - -/* - * Returns the secondary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ -extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec); - -/* - * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. - */ -extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec); - -#ifdef WL11AC_80P80 -/* - * This function returns the centre chanel for the given chanspec. - * In case of 80+80 chanspec it returns the primary 80 Mhz centre channel - */ -extern uint8 wf_chspec_channel(chanspec_t chspec); -#endif -#endif /* _bcmwifi_channels_h_ */ diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd/bcmwifi_rates.h deleted file mode 100644 index 04575dfaeb71..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmwifi_rates.h +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmwifi_rates.h 5187 2012-06-29 06:17:50Z $ - */ - -#ifndef _bcmwifi_rates_h_ -#define _bcmwifi_rates_h_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -#define WL_RATESET_SZ_DSSS 4 -#define WL_RATESET_SZ_OFDM 8 -#define WL_RATESET_SZ_VHT_MCS 10 - -#define WL_RATESET_SZ_HT_MCS 8 - -#define WL_RATESET_SZ_HT_IOCTL 8 /* MAC histogram, compatibility with wl utility */ - -#define WL_TX_CHAINS_MAX 3 - -#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */ - -/* Transmit channel bandwidths */ -typedef enum wl_tx_bw { - WL_TX_BW_20, - WL_TX_BW_40, - WL_TX_BW_80, - WL_TX_BW_20IN40, - WL_TX_BW_20IN80, - WL_TX_BW_40IN80, - WL_TX_BW_160, - WL_TX_BW_20IN160, - WL_TX_BW_40IN160, - WL_TX_BW_80IN160, - WL_TX_BW_ALL, - WL_TX_BW_8080, - WL_TX_BW_8080CHAN2, - WL_TX_BW_20IN8080, - WL_TX_BW_40IN8080, - WL_TX_BW_80IN8080 -} wl_tx_bw_t; - - -/* - * Transmit modes. - * Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed - */ -typedef enum wl_tx_mode { - WL_TX_MODE_NONE, - WL_TX_MODE_STBC, - WL_TX_MODE_CDD, - WL_TX_MODE_TXBF, - WL_NUM_TX_MODES -} wl_tx_mode_t; - - -/* Number of transmit chains */ -typedef enum wl_tx_chains { - WL_TX_CHAINS_1 = 1, - WL_TX_CHAINS_2, - WL_TX_CHAINS_3 -} wl_tx_chains_t; - - -/* Number of transmit streams */ -typedef enum wl_tx_nss { - WL_TX_NSS_1 = 1, - WL_TX_NSS_2, - WL_TX_NSS_3 -} wl_tx_nss_t; - - -typedef enum clm_rates { - /************ - * 1 chain * - ************ - */ - - /* 1 Stream */ - WL_RATE_1X1_DSSS_1 = 0, - WL_RATE_1X1_DSSS_2 = 1, - WL_RATE_1X1_DSSS_5_5 = 2, - WL_RATE_1X1_DSSS_11 = 3, - - WL_RATE_1X1_OFDM_6 = 4, - WL_RATE_1X1_OFDM_9 = 5, - WL_RATE_1X1_OFDM_12 = 6, - WL_RATE_1X1_OFDM_18 = 7, - WL_RATE_1X1_OFDM_24 = 8, - WL_RATE_1X1_OFDM_36 = 9, - WL_RATE_1X1_OFDM_48 = 10, - WL_RATE_1X1_OFDM_54 = 11, - - WL_RATE_1X1_MCS0 = 12, - WL_RATE_1X1_MCS1 = 13, - WL_RATE_1X1_MCS2 = 14, - WL_RATE_1X1_MCS3 = 15, - WL_RATE_1X1_MCS4 = 16, - WL_RATE_1X1_MCS5 = 17, - WL_RATE_1X1_MCS6 = 18, - WL_RATE_1X1_MCS7 = 19, - - WL_RATE_1X1_VHT0SS1 = 12, - WL_RATE_1X1_VHT1SS1 = 13, - WL_RATE_1X1_VHT2SS1 = 14, - WL_RATE_1X1_VHT3SS1 = 15, - WL_RATE_1X1_VHT4SS1 = 16, - WL_RATE_1X1_VHT5SS1 = 17, - WL_RATE_1X1_VHT6SS1 = 18, - WL_RATE_1X1_VHT7SS1 = 19, - WL_RATE_1X1_VHT8SS1 = 20, - WL_RATE_1X1_VHT9SS1 = 21, - - - /************ - * 2 chains * - ************ - */ - - /* 1 Stream expanded + 1 */ - WL_RATE_1X2_DSSS_1 = 22, - WL_RATE_1X2_DSSS_2 = 23, - WL_RATE_1X2_DSSS_5_5 = 24, - WL_RATE_1X2_DSSS_11 = 25, - - WL_RATE_1X2_CDD_OFDM_6 = 26, - WL_RATE_1X2_CDD_OFDM_9 = 27, - WL_RATE_1X2_CDD_OFDM_12 = 28, - WL_RATE_1X2_CDD_OFDM_18 = 29, - WL_RATE_1X2_CDD_OFDM_24 = 30, - WL_RATE_1X2_CDD_OFDM_36 = 31, - WL_RATE_1X2_CDD_OFDM_48 = 32, - WL_RATE_1X2_CDD_OFDM_54 = 33, - - WL_RATE_1X2_CDD_MCS0 = 34, - WL_RATE_1X2_CDD_MCS1 = 35, - WL_RATE_1X2_CDD_MCS2 = 36, - WL_RATE_1X2_CDD_MCS3 = 37, - WL_RATE_1X2_CDD_MCS4 = 38, - WL_RATE_1X2_CDD_MCS5 = 39, - WL_RATE_1X2_CDD_MCS6 = 40, - WL_RATE_1X2_CDD_MCS7 = 41, - - WL_RATE_1X2_VHT0SS1 = 34, - WL_RATE_1X2_VHT1SS1 = 35, - WL_RATE_1X2_VHT2SS1 = 36, - WL_RATE_1X2_VHT3SS1 = 37, - WL_RATE_1X2_VHT4SS1 = 38, - WL_RATE_1X2_VHT5SS1 = 39, - WL_RATE_1X2_VHT6SS1 = 40, - WL_RATE_1X2_VHT7SS1 = 41, - WL_RATE_1X2_VHT8SS1 = 42, - WL_RATE_1X2_VHT9SS1 = 43, - - /* 2 Streams */ - WL_RATE_2X2_STBC_MCS0 = 44, - WL_RATE_2X2_STBC_MCS1 = 45, - WL_RATE_2X2_STBC_MCS2 = 46, - WL_RATE_2X2_STBC_MCS3 = 47, - WL_RATE_2X2_STBC_MCS4 = 48, - WL_RATE_2X2_STBC_MCS5 = 49, - WL_RATE_2X2_STBC_MCS6 = 50, - WL_RATE_2X2_STBC_MCS7 = 51, - - WL_RATE_2X2_STBC_VHT0SS1 = 44, - WL_RATE_2X2_STBC_VHT1SS1 = 45, - WL_RATE_2X2_STBC_VHT2SS1 = 46, - WL_RATE_2X2_STBC_VHT3SS1 = 47, - WL_RATE_2X2_STBC_VHT4SS1 = 48, - WL_RATE_2X2_STBC_VHT5SS1 = 49, - WL_RATE_2X2_STBC_VHT6SS1 = 50, - WL_RATE_2X2_STBC_VHT7SS1 = 51, - WL_RATE_2X2_STBC_VHT8SS1 = 52, - WL_RATE_2X2_STBC_VHT9SS1 = 53, - - WL_RATE_2X2_SDM_MCS8 = 54, - WL_RATE_2X2_SDM_MCS9 = 55, - WL_RATE_2X2_SDM_MCS10 = 56, - WL_RATE_2X2_SDM_MCS11 = 57, - WL_RATE_2X2_SDM_MCS12 = 58, - WL_RATE_2X2_SDM_MCS13 = 59, - WL_RATE_2X2_SDM_MCS14 = 60, - WL_RATE_2X2_SDM_MCS15 = 61, - - WL_RATE_2X2_VHT0SS2 = 54, - WL_RATE_2X2_VHT1SS2 = 55, - WL_RATE_2X2_VHT2SS2 = 56, - WL_RATE_2X2_VHT3SS2 = 57, - WL_RATE_2X2_VHT4SS2 = 58, - WL_RATE_2X2_VHT5SS2 = 59, - WL_RATE_2X2_VHT6SS2 = 60, - WL_RATE_2X2_VHT7SS2 = 61, - WL_RATE_2X2_VHT8SS2 = 62, - WL_RATE_2X2_VHT9SS2 = 63, - - /************ - * 3 chains * - ************ - */ - - /* 1 Stream expanded + 2 */ - WL_RATE_1X3_DSSS_1 = 64, - WL_RATE_1X3_DSSS_2 = 65, - WL_RATE_1X3_DSSS_5_5 = 66, - WL_RATE_1X3_DSSS_11 = 67, - - WL_RATE_1X3_CDD_OFDM_6 = 68, - WL_RATE_1X3_CDD_OFDM_9 = 69, - WL_RATE_1X3_CDD_OFDM_12 = 70, - WL_RATE_1X3_CDD_OFDM_18 = 71, - WL_RATE_1X3_CDD_OFDM_24 = 72, - WL_RATE_1X3_CDD_OFDM_36 = 73, - WL_RATE_1X3_CDD_OFDM_48 = 74, - WL_RATE_1X3_CDD_OFDM_54 = 75, - - WL_RATE_1X3_CDD_MCS0 = 76, - WL_RATE_1X3_CDD_MCS1 = 77, - WL_RATE_1X3_CDD_MCS2 = 78, - WL_RATE_1X3_CDD_MCS3 = 79, - WL_RATE_1X3_CDD_MCS4 = 80, - WL_RATE_1X3_CDD_MCS5 = 81, - WL_RATE_1X3_CDD_MCS6 = 82, - WL_RATE_1X3_CDD_MCS7 = 83, - - WL_RATE_1X3_VHT0SS1 = 76, - WL_RATE_1X3_VHT1SS1 = 77, - WL_RATE_1X3_VHT2SS1 = 78, - WL_RATE_1X3_VHT3SS1 = 79, - WL_RATE_1X3_VHT4SS1 = 80, - WL_RATE_1X3_VHT5SS1 = 81, - WL_RATE_1X3_VHT6SS1 = 82, - WL_RATE_1X3_VHT7SS1 = 83, - WL_RATE_1X3_VHT8SS1 = 84, - WL_RATE_1X3_VHT9SS1 = 85, - - /* 2 Streams expanded + 1 */ - WL_RATE_2X3_STBC_MCS0 = 86, - WL_RATE_2X3_STBC_MCS1 = 87, - WL_RATE_2X3_STBC_MCS2 = 88, - WL_RATE_2X3_STBC_MCS3 = 89, - WL_RATE_2X3_STBC_MCS4 = 90, - WL_RATE_2X3_STBC_MCS5 = 91, - WL_RATE_2X3_STBC_MCS6 = 92, - WL_RATE_2X3_STBC_MCS7 = 93, - - WL_RATE_2X3_STBC_VHT0SS1 = 86, - WL_RATE_2X3_STBC_VHT1SS1 = 87, - WL_RATE_2X3_STBC_VHT2SS1 = 88, - WL_RATE_2X3_STBC_VHT3SS1 = 89, - WL_RATE_2X3_STBC_VHT4SS1 = 90, - WL_RATE_2X3_STBC_VHT5SS1 = 91, - WL_RATE_2X3_STBC_VHT6SS1 = 92, - WL_RATE_2X3_STBC_VHT7SS1 = 93, - WL_RATE_2X3_STBC_VHT8SS1 = 94, - WL_RATE_2X3_STBC_VHT9SS1 = 95, - - WL_RATE_2X3_SDM_MCS8 = 96, - WL_RATE_2X3_SDM_MCS9 = 97, - WL_RATE_2X3_SDM_MCS10 = 98, - WL_RATE_2X3_SDM_MCS11 = 99, - WL_RATE_2X3_SDM_MCS12 = 100, - WL_RATE_2X3_SDM_MCS13 = 101, - WL_RATE_2X3_SDM_MCS14 = 102, - WL_RATE_2X3_SDM_MCS15 = 103, - - WL_RATE_2X3_VHT0SS2 = 96, - WL_RATE_2X3_VHT1SS2 = 97, - WL_RATE_2X3_VHT2SS2 = 98, - WL_RATE_2X3_VHT3SS2 = 99, - WL_RATE_2X3_VHT4SS2 = 100, - WL_RATE_2X3_VHT5SS2 = 101, - WL_RATE_2X3_VHT6SS2 = 102, - WL_RATE_2X3_VHT7SS2 = 103, - WL_RATE_2X3_VHT8SS2 = 104, - WL_RATE_2X3_VHT9SS2 = 105, - - /* 3 Streams */ - WL_RATE_3X3_SDM_MCS16 = 106, - WL_RATE_3X3_SDM_MCS17 = 107, - WL_RATE_3X3_SDM_MCS18 = 108, - WL_RATE_3X3_SDM_MCS19 = 109, - WL_RATE_3X3_SDM_MCS20 = 110, - WL_RATE_3X3_SDM_MCS21 = 111, - WL_RATE_3X3_SDM_MCS22 = 112, - WL_RATE_3X3_SDM_MCS23 = 113, - - WL_RATE_3X3_VHT0SS3 = 106, - WL_RATE_3X3_VHT1SS3 = 107, - WL_RATE_3X3_VHT2SS3 = 108, - WL_RATE_3X3_VHT3SS3 = 109, - WL_RATE_3X3_VHT4SS3 = 110, - WL_RATE_3X3_VHT5SS3 = 111, - WL_RATE_3X3_VHT6SS3 = 112, - WL_RATE_3X3_VHT7SS3 = 113, - WL_RATE_3X3_VHT8SS3 = 114, - WL_RATE_3X3_VHT9SS3 = 115, - - - /**************************** - * TX Beamforming, 2 chains * - **************************** - */ - - /* 1 Stream expanded + 1 */ - - WL_RATE_1X2_TXBF_OFDM_6 = 116, - WL_RATE_1X2_TXBF_OFDM_9 = 117, - WL_RATE_1X2_TXBF_OFDM_12 = 118, - WL_RATE_1X2_TXBF_OFDM_18 = 119, - WL_RATE_1X2_TXBF_OFDM_24 = 120, - WL_RATE_1X2_TXBF_OFDM_36 = 121, - WL_RATE_1X2_TXBF_OFDM_48 = 122, - WL_RATE_1X2_TXBF_OFDM_54 = 123, - - WL_RATE_1X2_TXBF_MCS0 = 124, - WL_RATE_1X2_TXBF_MCS1 = 125, - WL_RATE_1X2_TXBF_MCS2 = 126, - WL_RATE_1X2_TXBF_MCS3 = 127, - WL_RATE_1X2_TXBF_MCS4 = 128, - WL_RATE_1X2_TXBF_MCS5 = 129, - WL_RATE_1X2_TXBF_MCS6 = 130, - WL_RATE_1X2_TXBF_MCS7 = 131, - - WL_RATE_1X2_TXBF_VHT0SS1 = 124, - WL_RATE_1X2_TXBF_VHT1SS1 = 125, - WL_RATE_1X2_TXBF_VHT2SS1 = 126, - WL_RATE_1X2_TXBF_VHT3SS1 = 127, - WL_RATE_1X2_TXBF_VHT4SS1 = 128, - WL_RATE_1X2_TXBF_VHT5SS1 = 129, - WL_RATE_1X2_TXBF_VHT6SS1 = 130, - WL_RATE_1X2_TXBF_VHT7SS1 = 131, - WL_RATE_1X2_TXBF_VHT8SS1 = 132, - WL_RATE_1X2_TXBF_VHT9SS1 = 133, - - /* 2 Streams */ - - WL_RATE_2X2_TXBF_SDM_MCS8 = 134, - WL_RATE_2X2_TXBF_SDM_MCS9 = 135, - WL_RATE_2X2_TXBF_SDM_MCS10 = 136, - WL_RATE_2X2_TXBF_SDM_MCS11 = 137, - WL_RATE_2X2_TXBF_SDM_MCS12 = 138, - WL_RATE_2X2_TXBF_SDM_MCS13 = 139, - WL_RATE_2X2_TXBF_SDM_MCS14 = 140, - WL_RATE_2X2_TXBF_SDM_MCS15 = 141, - - WL_RATE_2X2_TXBF_VHT0SS2 = 134, - WL_RATE_2X2_TXBF_VHT1SS2 = 135, - WL_RATE_2X2_TXBF_VHT2SS2 = 136, - WL_RATE_2X2_TXBF_VHT3SS2 = 137, - WL_RATE_2X2_TXBF_VHT4SS2 = 138, - WL_RATE_2X2_TXBF_VHT5SS2 = 139, - WL_RATE_2X2_TXBF_VHT6SS2 = 140, - WL_RATE_2X2_TXBF_VHT7SS2 = 141, - - - /**************************** - * TX Beamforming, 3 chains * - **************************** - */ - - /* 1 Stream expanded + 2 */ - - WL_RATE_1X3_TXBF_OFDM_6 = 142, - WL_RATE_1X3_TXBF_OFDM_9 = 143, - WL_RATE_1X3_TXBF_OFDM_12 = 144, - WL_RATE_1X3_TXBF_OFDM_18 = 145, - WL_RATE_1X3_TXBF_OFDM_24 = 146, - WL_RATE_1X3_TXBF_OFDM_36 = 147, - WL_RATE_1X3_TXBF_OFDM_48 = 148, - WL_RATE_1X3_TXBF_OFDM_54 = 149, - - WL_RATE_1X3_TXBF_MCS0 = 150, - WL_RATE_1X3_TXBF_MCS1 = 151, - WL_RATE_1X3_TXBF_MCS2 = 152, - WL_RATE_1X3_TXBF_MCS3 = 153, - WL_RATE_1X3_TXBF_MCS4 = 154, - WL_RATE_1X3_TXBF_MCS5 = 155, - WL_RATE_1X3_TXBF_MCS6 = 156, - WL_RATE_1X3_TXBF_MCS7 = 157, - - WL_RATE_1X3_TXBF_VHT0SS1 = 150, - WL_RATE_1X3_TXBF_VHT1SS1 = 151, - WL_RATE_1X3_TXBF_VHT2SS1 = 152, - WL_RATE_1X3_TXBF_VHT3SS1 = 153, - WL_RATE_1X3_TXBF_VHT4SS1 = 154, - WL_RATE_1X3_TXBF_VHT5SS1 = 155, - WL_RATE_1X3_TXBF_VHT6SS1 = 156, - WL_RATE_1X3_TXBF_VHT7SS1 = 157, - WL_RATE_1X3_TXBF_VHT8SS1 = 158, - WL_RATE_1X3_TXBF_VHT9SS1 = 159, - - /* 2 Streams expanded + 1 */ - - WL_RATE_2X3_TXBF_SDM_MCS8 = 160, - WL_RATE_2X3_TXBF_SDM_MCS9 = 161, - WL_RATE_2X3_TXBF_SDM_MCS10 = 162, - WL_RATE_2X3_TXBF_SDM_MCS11 = 163, - WL_RATE_2X3_TXBF_SDM_MCS12 = 164, - WL_RATE_2X3_TXBF_SDM_MCS13 = 165, - WL_RATE_2X3_TXBF_SDM_MCS14 = 166, - WL_RATE_2X3_TXBF_SDM_MCS15 = 167, - - WL_RATE_2X3_TXBF_VHT0SS2 = 160, - WL_RATE_2X3_TXBF_VHT1SS2 = 161, - WL_RATE_2X3_TXBF_VHT2SS2 = 162, - WL_RATE_2X3_TXBF_VHT3SS2 = 163, - WL_RATE_2X3_TXBF_VHT4SS2 = 164, - WL_RATE_2X3_TXBF_VHT5SS2 = 165, - WL_RATE_2X3_TXBF_VHT6SS2 = 166, - WL_RATE_2X3_TXBF_VHT7SS2 = 167, - WL_RATE_2X3_TXBF_VHT8SS2 = 168, - WL_RATE_2X3_TXBF_VHT9SS2 = 169, - - /* 3 Streams */ - - WL_RATE_3X3_TXBF_SDM_MCS16 = 170, - WL_RATE_3X3_TXBF_SDM_MCS17 = 171, - WL_RATE_3X3_TXBF_SDM_MCS18 = 172, - WL_RATE_3X3_TXBF_SDM_MCS19 = 173, - WL_RATE_3X3_TXBF_SDM_MCS20 = 174, - WL_RATE_3X3_TXBF_SDM_MCS21 = 175, - WL_RATE_3X3_TXBF_SDM_MCS22 = 176, - WL_RATE_3X3_TXBF_SDM_MCS23 = 177, - - WL_RATE_3X3_TXBF_VHT0SS3 = 170, - WL_RATE_3X3_TXBF_VHT1SS3 = 171, - WL_RATE_3X3_TXBF_VHT2SS3 = 172, - WL_RATE_3X3_TXBF_VHT3SS3 = 173, - WL_RATE_3X3_TXBF_VHT4SS3 = 174, - WL_RATE_3X3_TXBF_VHT5SS3 = 175, - WL_RATE_3X3_TXBF_VHT6SS3 = 176, - WL_RATE_3X3_TXBF_VHT7SS3 = 177 -} clm_rates_t; - -/* Number of rate codes */ -#define WL_NUMRATES 178 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* _bcmwifi_rates_h_ */ diff --git a/drivers/net/wireless/bcmdhd/bcmxtlv.c b/drivers/net/wireless/bcmdhd/bcmxtlv.c deleted file mode 100644 index 2514d965d6ab..000000000000 --- a/drivers/net/wireless/bcmdhd/bcmxtlv.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Driver O/S-independent utility routines - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmxtlv.c 487603 2014-06-26 12:33:22Z $ - */ - -#include - -#include -#include - -#include - -#ifdef BCMDRIVER -#include -#else /* !BCMDRIVER */ -#include -#include -#include -#ifndef ASSERT -#define ASSERT(exp) -#endif -inline void* MALLOCZ(void *o, size_t s) { BCM_REFERENCE(o); return calloc(1, s); } -inline void MFREE(void *o, void *p, size_t s) { BCM_REFERENCE(o); BCM_REFERENCE(s); free(p); } -#endif /* !BCMDRIVER */ - -#include -#include - -bcm_xtlv_t * -bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen) -{ - int sz; - - /* validate current elt */ - if (!bcm_valid_xtlv(elt, *buflen)) - return NULL; - - /* advance to next elt */ - sz = BCM_XTLV_SIZE(elt); - elt = (bcm_xtlv_t*)((uint8 *)elt + sz); - *buflen -= sz; - - /* validate next elt */ - if (!bcm_valid_xtlv(elt, *buflen)) - return NULL; - - return elt; -} - -struct bcm_tlvbuf * -bcm_xtlv_buf_alloc(void *osh, uint16 len) -{ - struct bcm_tlvbuf *tbuf = MALLOCZ(osh, sizeof(struct bcm_tlvbuf) + len); - if (tbuf == NULL) { - return NULL; - } - tbuf->size = len; - tbuf->head = tbuf->buf = (uint8 *)(tbuf + 1); - return tbuf; -} -void -bcm_xtlv_buf_free(void *osh, struct bcm_tlvbuf *tbuf) -{ - if (tbuf == NULL) - return; - MFREE(osh, tbuf, (tbuf->size + sizeof(struct bcm_tlvbuf))); -} -uint16 -bcm_xtlv_buf_len(struct bcm_tlvbuf *tbuf) -{ - if (tbuf == NULL) return 0; - return (tbuf->buf - tbuf->head); -} -uint16 -bcm_xtlv_buf_rlen(struct bcm_tlvbuf *tbuf) -{ - if (tbuf == NULL) return 0; - return tbuf->size - bcm_xtlv_buf_len(tbuf); -} -uint8 * -bcm_xtlv_buf(struct bcm_tlvbuf *tbuf) -{ - if (tbuf == NULL) return NULL; - return tbuf->buf; -} -uint8 * -bcm_xtlv_head(struct bcm_tlvbuf *tbuf) -{ - if (tbuf == NULL) return NULL; - return tbuf->head; -} -int -bcm_xtlv_put_data(struct bcm_tlvbuf *tbuf, uint16 type, const void *data, uint16 dlen) -{ - bcm_xtlv_t *xtlv; - if (tbuf == NULL || bcm_xtlv_buf_rlen(tbuf) < (dlen + BCM_XTLV_HDR_SIZE)) - return BCME_BADARG; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(dlen); - memcpy(xtlv->data, data, dlen); - tbuf->buf += BCM_XTLV_SIZE(xtlv); - return BCME_OK; -} -int -bcm_xtlv_put_8(struct bcm_tlvbuf *tbuf, uint16 type, const int8 data) -{ - bcm_xtlv_t *xtlv; - if (tbuf == NULL || bcm_xtlv_buf_rlen(tbuf) < (1 + BCM_XTLV_HDR_SIZE)) - return BCME_BADARG; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - xtlv->data[0] = data; - tbuf->buf += BCM_XTLV_SIZE(xtlv); - return BCME_OK; -} -int -bcm_xtlv_put_16(struct bcm_tlvbuf *tbuf, uint16 type, const int16 data) -{ - bcm_xtlv_t *xtlv; - if (tbuf == NULL || bcm_xtlv_buf_rlen(tbuf) < (2 + BCM_XTLV_HDR_SIZE)) - return BCME_BADARG; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - htol16_ua_store(data, xtlv->data); - tbuf->buf += BCM_XTLV_SIZE(xtlv); - return BCME_OK; -} -int -bcm_xtlv_put_32(struct bcm_tlvbuf *tbuf, uint16 type, const int32 data) -{ - bcm_xtlv_t *xtlv; - if (tbuf == NULL || bcm_xtlv_buf_rlen(tbuf) < (4 + BCM_XTLV_HDR_SIZE)) - return BCME_BADARG; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - htol32_ua_store(data, xtlv->data); - tbuf->buf += BCM_XTLV_SIZE(xtlv); - return BCME_OK; -} - -int -bcm_skip_xtlv(void **tlv_buf) -{ - bcm_xtlv_t *ptlv = *tlv_buf; - uint16 len; - uint16 type; - - ASSERT(ptlv); - /* tlv headr is always packed in LE order */ - len = ltoh16(ptlv->len); - type = ltoh16(ptlv->id); - - printf("xtlv_skip: Skipping tlv [type:%d,len:%d]\n", type, len); - - *tlv_buf += BCM_XTLV_SIZE(ptlv); - return BCME_OK; -} - -/* - * upacks xtlv record from buf checks the type - * copies data to callers buffer - * advances tlv pointer to next record - * caller's resposible for dst space check - */ -int -bcm_unpack_xtlv_entry(void **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst) -{ - bcm_xtlv_t *ptlv = *tlv_buf; - uint16 len; - uint16 type; - - ASSERT(ptlv); - /* tlv headr is always packed in LE order */ - len = ltoh16(ptlv->len); - type = ltoh16(ptlv->id); - if (len == 0) { - /* z-len tlv headers: allow, but don't process */ - printf("z-len, skip unpack\n"); - } else { - if ((type != xpct_type) || - (len > xpct_len)) { - printf("xtlv_unpack Error: found[type:%d,len:%d] != xpct[type:%d,len:%d]\n", - type, len, xpct_type, xpct_len); - return BCME_BADARG; - } - /* copy tlv record to caller's buffer */ - memcpy(dst, ptlv->data, ptlv->len); - } - *tlv_buf += BCM_XTLV_SIZE(ptlv); - return BCME_OK; -} - -/* - * packs user data into tlv record - * advances tlv pointer to next xtlv slot - * buflen is used for tlv_buf space check - */ -int -bcm_pack_xtlv_entry(void **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src) -{ - bcm_xtlv_t *ptlv = *tlv_buf; - - /* copy data from tlv buffer to dst provided by user */ - - ASSERT(ptlv); - ASSERT(src); - - if ((BCM_XTLV_HDR_SIZE + len) > *buflen) { - printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n", - ((int)BCM_XTLV_HDR_SIZE + len), *buflen); - return BCME_BADLEN; - } - ptlv->id = htol16(type); - ptlv->len = htol16(len); - - /* copy callers data */ - memcpy(ptlv->data, src, len); - - /* advance callers pointer to tlv buff */ - *tlv_buf += BCM_XTLV_SIZE(ptlv); - /* decrement the len */ - *buflen -= BCM_XTLV_SIZE(ptlv); - return BCME_OK; -} - -/* - * unpack all xtlv records from the issue a callback - * to set function one call per found tlv record - */ -int -bcm_unpack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_set_var_from_tlv_cbfn_t *cbfn) -{ - uint16 len; - uint16 type; - int res = 0; - bcm_xtlv_t *ptlv = tlv_buf; - int sbuflen = buflen; - - ASSERT(ptlv); - ASSERT(cbfn); - - while (sbuflen >= 0) { - ptlv = tlv_buf; - - /* tlv header is always packed in LE order */ - len = ltoh16(ptlv->len); - if (len == 0) /* can't be zero */ - break; - type = ltoh16(ptlv->id); - - sbuflen -= (BCM_XTLV_HDR_SIZE + len); - - /* check for possible buffer overrun */ - if (sbuflen < 0) - break; - - if ((res = cbfn(ctx, &tlv_buf, type, len)) != BCME_OK) - break; - } - return res; -} - -/* - * pack xtlv buffer from memory according to xtlv_desc_t - */ -int -bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items) -{ - int res = 0; - void *ptlv = *tlv_buf; - - while (items->len != 0) { - if ((res = bcm_pack_xtlv_entry(&ptlv, - buflen, items->type, - items->len, items->ptr) != BCME_OK)) { - break; - } - items++; - } - *tlv_buf = ptlv; /* update the external pointer */ - return res; -} - -/* - * unpack xtlv buffer to memory according to xtlv_desc_t - * - */ -int -bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items) -{ - int res = 0; - bcm_xtlv_t *elt = tlv_buf; - - /* iterate through tlvs in the buffer */ - while ((elt = bcm_next_xtlv(elt, buflen)) != NULL) { - - /* find matches in desc_t items */ - xtlv_desc_t *dst_desc = items; - while (dst_desc->len != 0) { - - if ((elt->id == dst_desc->type) && - (elt->len == dst_desc->len)) { - /* copy xtlv data to mem dst */ - memcpy(dst_desc->ptr, elt->data, elt->len); - if ((*buflen -= elt->len) < 0) { - printf("%s:Error: dst buf overrun\n", __FUNCTION__); - return BCME_NOMEM; - } - } - } - } - return res; -} - -/* - * packs user data (in hex string) into tlv record - * advances tlv pointer to next xtlv slot - * buflen is used for tlv_buf space check - */ -static int -get_ie_data(uchar *data_str, uchar *ie_data, int len) -{ - uchar *src, *dest; - uchar val; - int idx; - char hexstr[3]; - - src = data_str; - dest = ie_data; - - for (idx = 0; idx < len; idx++) { - hexstr[0] = src[0]; - hexstr[1] = src[1]; - hexstr[2] = '\0'; - -#ifdef BCMDRIVER - val = (uchar) simple_strtoul(hexstr, NULL, 16); -#else - val = (uchar) strtoul(hexstr, NULL, 16); -#endif - - *dest++ = val; - src += 2; - } - - return 0; -} - -int -bcm_pack_xtlv_entry_from_hex_string(void **tlv_buf, uint16 *buflen, uint16 type, char *hex) -{ - bcm_xtlv_t *ptlv = *tlv_buf; - uint16 len = strlen(hex)/2; - - /* copy data from tlv buffer to dst provided by user */ - - if ((BCM_XTLV_HDR_SIZE + len) > *buflen) { - printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n", - ((int)BCM_XTLV_HDR_SIZE + len), *buflen); - return BCME_BADLEN; - } - ptlv->id = htol16(type); - ptlv->len = htol16(len); - - /* copy callers data */ - if (get_ie_data((uchar*)hex, ptlv->data, len)) { - return BCME_BADARG; - } - - /* advance callers pointer to tlv buff */ - *tlv_buf += BCM_XTLV_SIZE(ptlv); - /* decrement the len */ - *buflen -= BCM_XTLV_SIZE(ptlv); - return BCME_OK; -} diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h deleted file mode 100644 index 14ee1ad2ac8b..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ /dev/null @@ -1,1337 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd.h 676009 2016-12-20 02:54:41Z $ - */ - -/**************** - * Common types * - */ - -#ifndef _dhd_h_ -#define _dhd_h_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) -#include -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -/* The kernel threading is sdio-specific */ -struct task_struct; -struct sched_param; -int setScheduler(struct task_struct *p, int policy, struct sched_param *param); -int get_scheduler_policy(struct task_struct *p); -#define MAX_EVENT 16 - -#define ALL_INTERFACES 0xff - -#include -#include - -#if defined(BCMWDF) -#include -#include -#endif /* (BCMWDF) */ - -#ifdef CONFIG_BCM_WLAN_RAMDUMP -#include -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - -#if defined(WL11U) && !defined(MFP) -#define MFP /* Applying interaction with MFP by spec HS2.0 REL2 */ -#endif /* WL11U */ - -#if defined(KEEP_ALIVE) -/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ -#define KEEP_ALIVE_PERIOD 55000 -#define NULL_PKT_STR "null_pkt" -#endif /* KEEP_ALIVE */ -/* Forward decls */ -struct dhd_bus; -struct dhd_prot; -struct dhd_info; -struct dhd_ioctl; - -/* The level of bus communication with the dongle */ -enum dhd_bus_state { - DHD_BUS_DOWN, /* Not ready for frame transfers */ - DHD_BUS_LOAD, /* Download access only (CPU reset) */ - DHD_BUS_DATA, /* Ready for frame transfers */ - DHD_BUS_SUSPEND, /* Bus has been suspended */ -}; - - -#define DHD_IF_ROLE_STA(role) (role == WLC_E_IF_ROLE_STA ||\ - role == WLC_E_IF_ROLE_P2P_CLIENT) - -/* For supporting multiple interfaces */ -#define DHD_MAX_IFS 16 -#define DHD_DEL_IF -0xE -#define DHD_BAD_IF -0xF - -enum dhd_op_flags { -/* Firmware requested operation mode */ - DHD_FLAG_STA_MODE = (1 << (0)), /* STA only */ - DHD_FLAG_HOSTAP_MODE = (1 << (1)), /* SOFTAP only */ - DHD_FLAG_P2P_MODE = (1 << (2)), /* P2P Only */ - /* STA + P2P */ - DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), - DHD_FLAG_CONCURR_MULTI_CHAN_MODE = (1 << (4)), /* STA + P2P */ - /* Current P2P mode for P2P connection */ - DHD_FLAG_P2P_GC_MODE = (1 << (5)), - DHD_FLAG_P2P_GO_MODE = (1 << (6)), - DHD_FLAG_MBSS_MODE = (1 << (7)), /* MBSS in future */ - DHD_FLAG_IBSS_MODE = (1 << (8)), - DHD_FLAG_MFG_MODE = (1 << (9)) -}; - -/* Max sequential TX/RX Control timeouts to set HANG event */ -#ifndef MAX_CNTL_TX_TIMEOUT -#define MAX_CNTL_TX_TIMEOUT 2 -#endif /* MAX_CNTL_TX_TIMEOUT */ -#ifndef MAX_CNTL_RX_TIMEOUT -#define MAX_CNTL_RX_TIMEOUT 1 -#endif /* MAX_CNTL_RX_TIMEOUT */ - -#ifdef BCMPCIE -#ifndef MAX_CNTL_D3ACK_TIMEOUT -#define MAX_CNTL_D3ACK_TIMEOUT 2 -#endif /* MAX_CNTL_D3ACK_TIMEOUT */ -#endif /* BCMPCIE */ - -#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ -#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ -#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ - -#ifndef POWERUP_MAX_RETRY -#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ -#endif -#ifndef POWERUP_WAIT_MS -#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ -#endif - -enum dhd_bus_wake_state { - WAKE_LOCK_OFF, - WAKE_LOCK_PRIV, - WAKE_LOCK_DPC, - WAKE_LOCK_IOCTL, - WAKE_LOCK_DOWNLOAD, - WAKE_LOCK_TMOUT, - WAKE_LOCK_WATCHDOG, - WAKE_LOCK_LINK_DOWN_TMOUT, - WAKE_LOCK_PNO_FIND_TMOUT, - WAKE_LOCK_SOFTAP_SET, - WAKE_LOCK_SOFTAP_STOP, - WAKE_LOCK_SOFTAP_START, - WAKE_LOCK_SOFTAP_THREAD -}; - -enum dhd_prealloc_index { - DHD_PREALLOC_PROT = 0, - DHD_PREALLOC_RXBUF, - DHD_PREALLOC_DATABUF, - DHD_PREALLOC_OSL_BUF, -#if defined(STATIC_WL_PRIV_STRUCT) - DHD_PREALLOC_WIPHY_ESCAN0 = 5, -#endif /* STATIC_WL_PRIV_STRUCT */ - DHD_PREALLOC_DHD_INFO = 7, - DHD_PREALLOC_DHD_WLFC_INFO = 8, - DHD_PREALLOC_IF_FLOW_LKUP = 9, - /* 10 */ - DHD_PREALLOC_MEMDUMP_RAM = 11, - DHD_PREALLOC_PKTID_MAP = 12 -}; - -/* Packet alignment for most efficient SDIO (can change based on platform) */ -#ifndef DHD_SDALIGN -#define DHD_SDALIGN 32 -#endif - -/* host reordering packts logic */ -/* followed the structure to hold the reorder buffers (void **p) */ -typedef struct reorder_info { - void **p; - uint8 flow_id; - uint8 cur_idx; - uint8 exp_idx; - uint8 max_idx; - uint8 pend_pkts; -} reorder_info_t; - -#ifdef DHDTCPACK_SUPPRESS - -enum { - /* TCPACK suppress off */ - TCPACK_SUP_OFF, - /* Replace TCPACK in txq when new coming one has higher ACK number. */ - TCPACK_SUP_REPLACE, - /* TCPACK_SUP_REPLACE + delayed TCPACK TX unless ACK to PSH DATA. - * This will give benefits to Half-Duplex bus interface(e.g. SDIO) that - * 1. we are able to read TCP DATA packets first from the bus - * 2. TCPACKs that don't need to hurry delivered remains longer in TXQ so can be suppressed. - */ - TCPACK_SUP_DELAYTX, - TCPACK_SUP_HOLD, - TCPACK_SUP_LAST_MODE -}; -#endif /* DHDTCPACK_SUPPRESS */ - - -/* DMA'ing r/w indices for rings supported */ -#ifdef BCM_INDX_TCM /* FW gets r/w indices in TCM */ -#define DMA_INDX_ENAB(dma_indxsup) 0 -#elif defined BCM_INDX_DMA /* FW gets r/w indices from Host memory */ -#define DMA_INDX_ENAB(dma_indxsup) 1 -#else /* r/w indices in TCM or host memory based on FW/Host agreement */ -#define DMA_INDX_ENAB(dma_indxsup) dma_indxsup -#endif /* BCM_INDX_TCM */ - -#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) -struct tdls_peer_node { - uint8 addr[ETHER_ADDR_LEN]; - struct tdls_peer_node *next; -}; -typedef struct tdls_peer_node tdls_peer_node_t; -typedef struct { - tdls_peer_node_t *node; - uint8 tdls_peer_count; -} tdls_peer_tbl_t; -#endif /* defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */ - -/* Common structure for module and instance linkage */ -typedef struct dhd_pub { - /* Linkage ponters */ - osl_t *osh; /* OSL handle */ - struct dhd_bus *bus; /* Bus module handle */ - struct dhd_prot *prot; /* Protocol module handle */ - struct dhd_info *info; /* Info module handle */ - - /* to NDIS developer, the structure dhd_common is redundant, - * please do NOT merge it back from other branches !!! - */ - - - /* Internal dhd items */ - bool up; /* Driver up/down (to OS) */ - bool txoff; /* Transmit flow-controlled */ - bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ - uint8 ioctl_state; - - enum dhd_bus_state busstate; - uint hdrlen; /* Total DHD header length (proto + bus) */ - uint maxctl; /* Max size rxctl request from proto to bus */ - uint rxsz; /* Rx buffer size bus module should use */ - uint8 wme_dp; /* wme discard priority */ - - /* Dongle media info */ - bool iswl; /* Dongle-resident driver is wl */ - ulong drv_version; /* Version of dongle-resident driver */ - struct ether_addr mac; /* MAC address obtained from dongle */ - dngl_stats_t dstats; /* Stats for dongle-based data */ - - /* Additional stats for the bus level */ - ulong tx_packets; /* Data packets sent to dongle */ - ulong tx_dropped; /* Data packets dropped in dhd */ - ulong tx_multicast; /* Multicast data packets sent to dongle */ - ulong tx_errors; /* Errors in sending data to dongle */ - ulong tx_ctlpkts; /* Control packets sent to dongle */ - ulong tx_ctlerrs; /* Errors sending control frames to dongle */ - ulong rx_packets; /* Packets sent up the network interface */ - ulong rx_multicast; /* Multicast packets sent up the network interface */ - ulong rx_errors; /* Errors processing rx data packets */ - ulong rx_ctlpkts; /* Control frames processed from dongle */ - ulong rx_ctlerrs; /* Errors in processing rx control frames */ - ulong rx_dropped; /* Packets dropped locally (no memory) */ - ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ - ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ - - ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ - ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ - ulong fc_packets; /* Number of flow control pkts recvd */ - - /* Last error return */ - int bcmerror; - uint tickcnt; - - /* Last error from dongle */ - int dongle_error; - - uint8 country_code[WLC_CNTRY_BUF_SZ]; - - /* Suspend disable flag and "in suspend" flag */ - int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ - int in_suspend; /* flag set to 1 when early suspend called */ -#ifdef PNO_SUPPORT - int pno_enable; /* pno status : "1" is pno enable */ - int pno_suspend; /* pno suspend status : "1" is pno suspended */ -#endif /* PNO_SUPPORT */ - /* DTIM skip value, default 0(or 1) means wake each DTIM - * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) - */ - int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ -#ifdef PKT_FILTER_SUPPORT - int early_suspended; /* Early suspend status */ - int dhcp_in_progress; /* DHCP period */ -#endif - - /* Pkt filter defination */ - char * pktfilter[100]; - int pktfilter_count; - - wl_country_t dhd_cspec; /* Current Locale info */ -#ifdef CUSTOM_FORCE_NODFS_FLAG - uint dhd_cflags; -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - bool force_country_change; - char eventmask[WL_EVENTING_MASK_LEN]; - int op_mode; /* STA, HostAPD, WFD, SoftAP */ - -/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. - * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework - * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile - */ -/* #define WL_ENABLE_P2P_IF 1 */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ - struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ -#endif - -#ifdef PROP_TXSTATUS - bool wlfc_enabled; - int wlfc_mode; - void* wlfc_state; - /* - Mode in which the dhd flow control shall operate. Must be set before - traffic starts to the device. - 0 - Do not do any proptxtstatus flow control - 1 - Use implied credit from a packet status - 2 - Use explicit credit - 3 - Only AMPDU hostreorder used. no wlfc. - */ - uint8 proptxstatus_mode; - bool proptxstatus_txoff; - bool proptxstatus_module_ignore; - bool proptxstatus_credit_ignore; - bool proptxstatus_txstatus_ignore; - - bool wlfc_rxpkt_chk; - /* - * implement below functions in each platform if needed. - */ - /* platform specific function whether to skip flow control */ - bool (*skip_fc)(void); - /* platform specific function for wlfc_enable and wlfc_deinit */ - void (*plat_init)(void *dhd); - void (*plat_deinit)(void *dhd); -#endif /* PROP_TXSTATUS */ -#ifdef PNO_SUPPORT - void *pno_state; -#endif -#ifdef RTT_SUPPORT - void *rtt_state; -#endif -#ifdef ROAM_AP_ENV_DETECTION - bool roam_env_detection; -#endif - bool dongle_isolation; - bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ - int hang_was_sent; - int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ - int txcnt_timeout; /* counter txcnt timeout to send HANG */ -#ifdef BCMPCIE - int d3ackcnt_timeout; /* counter d3ack timeout to send HANG */ -#endif /* BCMPCIE */ - bool hang_report; /* enable hang report by default */ -#ifdef WLMEDIA_HTSF - uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ -#endif -#ifdef WLTDLS - bool tdls_enable; -#endif - struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; - char fw_capabilities[WLC_IOCTL_SMLEN]; - #define MAXSKBPEND 1024 - void *skbbuf[MAXSKBPEND]; - uint32 store_idx; - uint32 sent_idx; -#ifdef DHDTCPACK_SUPPRESS - uint8 tcpack_sup_mode; /* TCPACK suppress mode */ - void *tcpack_sup_module; /* TCPACK suppress module */ - uint32 tcpack_sup_ratio; - uint32 tcpack_sup_delay; -#endif /* DHDTCPACK_SUPPRESS */ -#if defined(ARP_OFFLOAD_SUPPORT) - uint32 arp_version; -#endif -#ifdef CUSTOM_SET_CPUCORE - struct task_struct * current_dpc; - struct task_struct * current_rxf; - int chan_isvht80; -#endif /* CUSTOM_SET_CPUCORE */ - - void *sta_pool; /* pre-allocated pool of sta objects */ - void *staid_allocator; /* allocator of sta indexes */ - - void *flowid_allocator; /* unique flowid allocator */ - void *flow_ring_table; /* flow ring table, include prot and bus info */ - void *if_flow_lkup; /* per interface flowid lkup hash table */ - void *flowid_lock; /* per os lock for flowid info protection */ - uint32 num_flow_rings; - - uint32 d2h_sync_mode; /* D2H DMA completion sync mode */ - - uint8 flow_prio_map[NUMPRIO]; - uint8 flow_prio_map_type; - char enable_log[MAX_EVENT]; - bool dma_d2h_ring_upd_support; - bool dma_h2d_ring_upd_support; -#ifdef DHD_WMF - bool wmf_ucast_igmp; -#ifdef DHD_IGMP_UCQUERY - bool wmf_ucast_igmp_query; -#endif -#ifdef DHD_UCAST_UPNP - bool wmf_ucast_upnp; -#endif -#endif /* DHD_WMF */ -#ifdef DHD_UNICAST_DHCP - bool dhcp_unicast; -#endif /* DHD_UNICAST_DHCP */ -#ifdef DHD_L2_FILTER - bool block_ping; -#endif -#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) - tdls_peer_tbl_t peer_tbl; -#endif /* defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */ -#ifdef CONFIG_BCM_WLAN_RAMDUMP - char crash_reason[BCM_WLAN_CRASH_REASON_LEN]; -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ -#ifdef GSCAN_SUPPORT - bool lazy_roam_enable; -#endif /* GSCAN_SUPPORT */ - uint8 *soc_ram; - uint32 soc_ram_length; - bool tx_in_progress; - uint8 rand_mac_oui[DOT11_OUI_LEN]; -} dhd_pub_t; - -#if defined(BCMWDF) -typedef struct { - dhd_pub_t *dhd_pub; -} dhd_workitem_context_t; - -WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(dhd_workitem_context_t, dhd_get_dhd_workitem_context) -#endif /* (BCMWDF) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) - -#define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); -#define _DHD_PM_RESUME_WAIT(a, b) do {\ - int retry = 0; \ - SMP_RD_BARRIER_DEPENDS(); \ - while (dhd_mmc_suspend && retry++ != b) { \ - SMP_RD_BARRIER_DEPENDS(); \ - wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ - } \ - } while (0) -#define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) -#define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) -#define DHD_PM_RESUME_RETURN_ERROR(a) do { \ - if (dhd_mmc_suspend) return a; } while (0) -#define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) - -#define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); -#define SPINWAIT_SLEEP(a, exp, us) do { \ - uint countdown = (us) + 9999; \ - while ((exp) && (countdown >= 10000)) { \ - wait_event_interruptible_timeout(a, FALSE, 1); \ - countdown -= 10000; \ - } \ -} while (0) - -#else - -#define DHD_PM_RESUME_WAIT_INIT(a) -#define DHD_PM_RESUME_WAIT(a) -#define DHD_PM_RESUME_WAIT_FOREVER(a) -#define DHD_PM_RESUME_RETURN_ERROR(a) -#define DHD_PM_RESUME_RETURN - -#define DHD_SPINWAIT_SLEEP_INIT(a) -#define SPINWAIT_SLEEP(a, exp, us) do { \ - uint countdown = (us) + 9; \ - while ((exp) && (countdown >= 10)) { \ - OSL_DELAY(10); \ - countdown -= 10; \ - } \ -} while (0) - -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - -#ifdef CONFIG_BCM_WLAN_RAMDUMP -extern char bcm_wlan_ver_info[BCM_WLAN_CRASH_REASON_LEN]; -#define bcm_add_crash_reason(dst, fmt, ...) do { \ - int rest = 0; \ - int pos = strnlen(dst, sizeof(dst)); \ - if (pos == 0) \ - pos += snprintf(&dst[0], sizeof(dst), "%s", bcm_wlan_ver_info); \ - rest = sizeof(dst) - pos; \ - if (rest > 1) { \ - snprintf(&dst[pos], rest, (fmt), ##__VA_ARGS__); \ - } \ - } while (0) -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - -#ifndef OSL_SLEEP -#define OSL_SLEEP(ms) OSL_DELAY(ms*1000) -#endif /* OSL_SLEEP */ - -#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ - -#ifdef PNO_SUPPORT -int dhd_pno_clean(dhd_pub_t *dhd); -#endif /* PNO_SUPPORT */ -/* - * Wake locks are an Android power management concept. They are used by applications and services - * to request CPU resources. - */ -extern int dhd_os_wake_lock(dhd_pub_t *pub); -extern int dhd_os_wake_unlock(dhd_pub_t *pub); -extern int dhd_os_wake_lock_waive(dhd_pub_t *pub); -extern int dhd_os_wake_lock_restore(dhd_pub_t *pub); -extern void dhd_os_wake_lock_init(struct dhd_info *dhd); -extern void dhd_os_wake_lock_destroy(struct dhd_info *dhd); -extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); -extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); -extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); -extern int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub); -extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); -extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); -extern int dhd_event_wake_lock(dhd_pub_t *pub); -extern int dhd_event_wake_unlock(dhd_pub_t *pub); -extern void dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val); -extern void dhd_txfl_wake_unlock(dhd_pub_t *pub); - -#ifdef BCMPCIE_OOB_HOST_WAKE -extern int dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val); -extern int dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - -inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_init(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_lock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -#ifdef DHD_DEBUG_WAKE_LOCK -#define DHD_OS_WAKE_LOCK(pub) \ - do { \ - printf("call wake_lock: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_lock(pub); \ - } while (0) -#define DHD_OS_WAKE_UNLOCK(pub) \ - do { \ - printf("call wake_unlock: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_unlock(pub); \ - } while (0) -#define DHD_EVENT_WAKE_LOCK(pub) \ - do { \ - printf("call event wake_lock: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_event_wake_lock(pub); \ - } while (0) -#define DHD_EVENT_WAKE_UNLOCK(pub) \ - do { \ - printf("call event wake_unlock: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_event_wake_unlock(pub); \ - } while (0) -#define DHD_TXFL_WAKE_LOCK_TIMEOUT(pub, val) \ - do { \ - printf("call txfl wake_lock_timeout[%d]: %s %d\n", \ - val, __FUNCTION__, __LINE__); \ - dhd_txfl_wake_lock_timeout(pub, val); \ - } while (0) -#define DHD_TXFL_WAKE_UNLOCK(pub) \ - do { \ - printf("call txfl wake_unlock: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_txfl_wake_unlock(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) \ - do { \ - printf("call wake_lock_timeout: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_timeout(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ - do { \ - printf("call wake_lock_rx_timeout_enable[%d]: %s %d\n", \ - val, __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_rx_timeout_enable(pub, val); \ - } while (0) -#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ - do { \ - printf("call wake_lock_ctrl_timeout_enable[%d]: %s %d\n", \ - val, __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_ctrl_timeout_enable(pub, val); \ - } while (0) -#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \ - do { \ - printf("call wake_lock_ctrl_timeout_cancel: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_ctrl_timeout_cancel(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_WAIVE(pub) \ - do { \ - printf("call wake_lock_waive: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_waive(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_RESTORE(pub) \ - do { \ - printf("call wake_lock_restore: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_restore(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_INIT(dhd) \ - do { \ - printf("call wake_lock_init: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_init(dhd); \ - } while (0) -#define DHD_OS_WAKE_LOCK_DESTROY(dhd) \ - do { \ - printf("call wake_lock_destroy: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_destroy(dhd); \ - } while (0) -#else -#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) -#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) -#define DHD_EVENT_WAKE_LOCK(pub) dhd_event_wake_lock(pub) -#define DHD_EVENT_WAKE_UNLOCK(pub) dhd_event_wake_unlock(pub) -#define DHD_TXFL_WAKE_LOCK_TIMEOUT(pub, val) dhd_txfl_wake_lock_timeout(pub, val) -#define DHD_TXFL_WAKE_UNLOCK(pub) dhd_txfl_wake_unlock(pub) -#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) -#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ - dhd_os_wake_lock_rx_timeout_enable(pub, val) -#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ - dhd_os_wake_lock_ctrl_timeout_enable(pub, val) -#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \ - dhd_os_wake_lock_ctrl_timeout_cancel(pub) -#define DHD_OS_WAKE_LOCK_WAIVE(pub) dhd_os_wake_lock_waive(pub) -#define DHD_OS_WAKE_LOCK_RESTORE(pub) dhd_os_wake_lock_restore(pub) -#define DHD_OS_WAKE_LOCK_INIT(dhd) dhd_os_wake_lock_init(dhd) -#define DHD_OS_WAKE_LOCK_DESTROY(dhd) dhd_os_wake_lock_destroy(dhd) -#endif /* DHD_DEBUG_WAKE_LOCK */ - -#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub) -#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub) -#ifdef BCMPCIE_OOB_HOST_WAKE -#define OOB_WAKE_LOCK_TIMEOUT 500 -#define DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(pub, val) dhd_os_oob_irq_wake_lock_timeout(pub, val) -#define DHD_OS_OOB_IRQ_WAKE_UNLOCK(pub) dhd_os_oob_irq_wake_unlock(pub) -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#define DHD_PACKET_TIMEOUT_MS 500 -#define DHD_EVENT_TIMEOUT_MS 1500 -#define MAX_TX_TIMEOUT 500 - -/* interface operations (register, remove) should be atomic, use this lock to prevent race - * condition among wifi on/off and interface operation functions - */ -void dhd_net_if_lock(struct net_device *dev); -void dhd_net_if_unlock(struct net_device *dev); - - -typedef enum dhd_attach_states -{ - DHD_ATTACH_STATE_INIT = 0x0, - DHD_ATTACH_STATE_NET_ALLOC = 0x1, - DHD_ATTACH_STATE_DHD_ALLOC = 0x2, - DHD_ATTACH_STATE_ADD_IF = 0x4, - DHD_ATTACH_STATE_PROT_ATTACH = 0x8, - DHD_ATTACH_STATE_WL_ATTACH = 0x10, - DHD_ATTACH_STATE_THREADS_CREATED = 0x20, - DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, - DHD_ATTACH_STATE_CFG80211 = 0x80, - DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, - DHD_ATTACH_STATE_DONE = 0x200 -} dhd_attach_states_t; - -/* Value -1 means we are unsuccessful in creating the kthread. */ -#define DHD_PID_KT_INVALID -1 -/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ -#define DHD_PID_KT_TL_INVALID -2 - -/* - * Exported from dhd OS modules (dhd_linux/dhd_ndis) - */ - -/* Indication from bus module regarding presence/insertion of dongle. - * Return dhd_pub_t 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 dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); -#if defined(WLP2P) && defined(WL_CFG80211) -/* To allow attach/detach calls corresponding to p2p0 interface */ -extern int dhd_attach_p2p(dhd_pub_t *); -extern int dhd_detach_p2p(dhd_pub_t *); -#endif /* WLP2P && WL_CFG80211 */ -extern int dhd_register_if(dhd_pub_t *dhdp, int idx, bool need_rtnl_lock); - -/* Indication from bus module regarding removal/absence of dongle */ -extern void dhd_detach(dhd_pub_t *dhdp); -extern void dhd_free(dhd_pub_t *dhdp); -extern void dhd_clear(dhd_pub_t *dhdp); - -/* Indication from bus module to change flow-control state */ -extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); - -/* Store the status of a connection attempt for later retrieval by an iovar */ -extern void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason); - -extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); - -/* Receive frame for delivery to OS. Callee disposes of rxp. */ -extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); - -/* Return pointer to interface name */ -extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); - -/* Request scheduling of the bus dpc */ -extern void dhd_sched_dpc(dhd_pub_t *dhdp); - -/* Notify tx completion */ -extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); - -#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */ -#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */ -#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */ -#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */ -#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */ -#define WIFI_FEATURE_GSCAN 0x0020 /* Google-Scan APIs */ -#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness Networking */ -#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */ -#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */ -#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */ -#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */ -#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */ -#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link setup */ -#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off channel */ -#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */ -#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA Concurrency */ -#define WIFI_FEATURE_LINKSTAT 0x10000 /* Support for Linkstats */ -#define WIFI_FEATURE_HAL_EPNO 0x40000 /* WiFi PNO enhanced */ -#define WIFI_FEATURE_RSSI_MONITOR 0x80000 /* RSSI Monitor */ - -#define MAX_FEATURE_SET_CONCURRRENT_GROUPS 3 - -extern int dhd_dev_get_feature_set(struct net_device *dev); -extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); -#ifdef CUSTOM_FORCE_NODFS_FLAG -extern int dhd_dev_set_nodfs(struct net_device *dev, uint nodfs); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -extern int dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui); -extern int dhd_set_rand_mac_oui(dhd_pub_t *dhd); - -#ifdef GSCAN_SUPPORT -extern int dhd_dev_set_lazy_roam_cfg(struct net_device *dev, - wlc_roam_exp_params_t *roam_param); -extern int dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable); -extern int dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, - wl_bssid_pref_cfg_t *bssid_pref, uint32 flush); -extern int dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, - uint32 len, uint32 flush); -extern int dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *whitelist, - uint32 len, uint32 flush); -#endif /* GSCAN_SUPPORT */ - -extern int dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, - int8 max_rssi, int8 min_rssi); - -#define DHD_RSSI_MONITOR_EVT_VERSION 1 -typedef struct { - uint8 version; - int8 cur_rssi; - struct ether_addr BSSID; -} dhd_rssi_monitor_evt_t; - -/* OS independent layer functions */ -extern int dhd_os_proto_block(dhd_pub_t * pub); -extern int dhd_os_proto_unblock(dhd_pub_t * pub); -extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending); -extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); -extern unsigned int dhd_os_get_ioctl_resp_timeout(void); -extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); - -extern int dhd_os_get_image_block(char * buf, int len, void * image); -extern void * dhd_os_open_image(char * filename); -extern void dhd_os_close_image(void * image); -extern void dhd_os_wd_timer(void *bus, uint wdtick); -extern void dhd_os_sdlock(dhd_pub_t * pub); -extern void dhd_os_sdunlock(dhd_pub_t * pub); -extern void dhd_os_sdlock_txq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); -extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); -extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); -#ifdef DHDTCPACK_SUPPRESS -extern void dhd_os_tcpacklock(dhd_pub_t *pub); -extern void dhd_os_tcpackunlock(dhd_pub_t *pub); -#endif /* DHDTCPACK_SUPPRESS */ - -extern int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr); -extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff); -#ifdef GET_CUSTOM_MAC_ENABLE -extern int somc_get_mac_address(unsigned char *buf); -#endif /* GET_CUSTOM_MAC_ENABLE */ -extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf); -#ifdef CUSTOM_FORCE_NODFS_FLAG -extern void get_customized_country_code(void *adapter, char *country_iso_code, - wl_country_t *cspec, u32 flags); -#else -extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); -extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); -extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); -extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); -extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); -extern bool dhd_os_check_if_up(dhd_pub_t *pub); -extern int dhd_os_check_wakelock(dhd_pub_t *pub); -extern int dhd_os_check_wakelock_all(dhd_pub_t *pub); -extern int dhd_get_instance(dhd_pub_t *pub); -#ifdef CUSTOM_SET_CPUCORE -extern void dhd_set_cpucore(dhd_pub_t *dhd, int set); -#endif /* CUSTOM_SET_CPUCORE */ - -#if defined(KEEP_ALIVE) -extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); -#endif /* KEEP_ALIVE */ - -#if defined(DHD_FW_COREDUMP) -void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size); -#endif /* DHD_FW_COREDUMP */ - - - - -#ifdef PKT_FILTER_SUPPORT -#define DHD_UNICAST_FILTER_NUM 0 -#define DHD_BROADCAST_FILTER_NUM 1 -#define DHD_MULTICAST4_FILTER_NUM 2 -#define DHD_MULTICAST6_FILTER_NUM 3 -#define DHD_MDNS_FILTER_NUM 4 -#define DHD_ARP_FILTER_NUM 5 - - -extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val); -extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); -extern int net_os_enable_packet_filter(struct net_device *dev, int val); -extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); -#endif /* PKT_FILTER_SUPPORT */ - -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); -extern bool dhd_support_sta_mode(dhd_pub_t *dhd); - -extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); - -typedef struct { - uint32 limit; /* Expiration time (usec) */ - uint32 increment; /* Current expiration increment (usec) */ - uint32 elapsed; /* Current elapsed time (usec) */ - uint32 tick; /* O/S tick time (usec) */ -} dhd_timeout_t; - -#ifdef SHOW_LOGTRACE -typedef struct { - int num_fmts; - char **fmts; - char *raw_fmts; -} dhd_event_log_t; -#endif /* SHOW_LOGTRACE */ - -#if defined(KEEP_ALIVE) -extern int dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, - u16 ip_pkt_len, u8* src_mac_addr, u8* dst_mac_addr, u32 period_msec); -extern int dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id); -#endif /* defined(KEEP_ALIVE) */ - -extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); -extern int dhd_timeout_expired(dhd_timeout_t *tmo); - -extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); -extern int dhd_ifidx2hostidx(struct dhd_info *dhd, int ifidx); -extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); -extern struct net_device * dhd_idx2net(void *pub, int ifidx); -extern int net_os_send_hang_message(struct net_device *dev); -extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, size_t pktlen, - wl_event_msg_t *, void **data_ptr, void *); -extern void wl_event_to_host_order(wl_event_msg_t * evt); -extern int wl_host_event_get_data(void *pktdata, uint pktlen, void *evt); - -extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); -extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, - int ifindex); -extern void dhd_common_init(osl_t *osh); - -extern int dhd_do_driver_init(struct net_device *net); -extern int dhd_event_ifadd(struct dhd_info *dhd, struct wl_event_data_if *ifevent, - char *name, uint8 *mac); -extern int dhd_event_ifdel(struct dhd_info *dhd, struct wl_event_data_if *ifevent, - char *name, uint8 *mac); -extern struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name, - uint8 *mac, uint8 bssidx, bool need_rtnl_lock); -extern int dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock); -extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); -extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); -extern void dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx); -extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); - -/* Send packet to dongle via data channel */ -extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); - -/* send up locally generated event */ -extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -/* Send event to host */ -extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -#ifdef LOG_INTO_TCPDUMP -extern void dhd_sendup_log(dhd_pub_t *dhdp, void *data, int len); -#endif /* LOG_INTO_TCPDUMP */ -extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); -extern uint dhd_bus_status(dhd_pub_t *dhdp); -extern int dhd_bus_start(dhd_pub_t *dhdp); -extern int dhd_bus_suspend(dhd_pub_t *dhdpub); -extern int dhd_bus_resume(dhd_pub_t *dhdpub, int stage); -extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); -extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); -extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); -#if defined(BCMSDIO) || defined(BCMPCIE) -extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); -extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); -extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); -#endif /* defined(BCMSDIO) || defined(BCMPCIE) */ - -#if defined(KEEP_ALIVE) -extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); -#endif /* KEEP_ALIVE */ - -/* OS spin lock API */ -extern void *dhd_os_spin_lock_init(osl_t *osh); -extern void dhd_os_spin_lock_deinit(osl_t *osh, void *lock); -extern unsigned long dhd_os_spin_lock(void *lock); -void dhd_os_spin_unlock(void *lock, unsigned long flags); - -/* - * Manage sta objects in an interface. Interface is identified by an ifindex and - * sta(s) within an interfaces are managed using a MacAddress of the sta. - */ -struct dhd_sta; -extern struct dhd_sta *dhd_findadd_sta(void *pub, int ifidx, void *ea); -extern void dhd_del_sta(void *pub, int ifidx, void *ea); -extern int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx); -extern int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val); -extern int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx); -extern int dhd_os_d3ack_wait(dhd_pub_t * pub, uint * condition, bool * pending); -extern int dhd_os_d3ack_wake(dhd_pub_t * pub); - -extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); -extern int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set); -extern int dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, - uint cmd_len, char **resptr, uint resp_len); -typedef enum cust_gpio_modes { - WLAN_RESET_ON, - WLAN_RESET_OFF, - WLAN_POWER_ON, - WLAN_POWER_OFF -} cust_gpio_modes_t; - -extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); -extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); -/* - * Insmod parameters for debug/test - */ - -/* Watchdog timer interval */ -extern uint dhd_watchdog_ms; - -#if defined(DHD_DEBUG) -/* Console output poll interval */ -extern uint dhd_console_ms; -extern uint wl_msg_level; -#endif /* defined(DHD_DEBUG) */ - -extern uint dhd_slpauto; - -/* Use interrupts */ -extern uint dhd_intr; - -/* Use polling */ -extern uint dhd_poll; - -/* ARP offload agent mode */ -extern uint dhd_arp_mode; - -/* ARP offload enable */ -extern uint dhd_arp_enable; - -/* Pkt filte enable control */ -extern uint dhd_pkt_filter_enable; - -/* Pkt filter init setup */ -extern uint dhd_pkt_filter_init; - -/* Pkt filter mode control */ -extern uint dhd_master_mode; - -/* Roaming mode control */ -extern uint dhd_roam_disable; - -/* Roaming mode control */ -extern uint dhd_radio_up; - -/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ -extern int dhd_idletime; -#ifdef DHD_USE_IDLECOUNT -#define DHD_IDLETIME_TICKS 5 -#else -#define DHD_IDLETIME_TICKS 1 -#endif /* DHD_USE_IDLECOUNT */ - -/* SDIO Drive Strength */ -extern uint dhd_sdiod_drive_strength; - -/* Override to force tx queueing all the time */ -extern uint dhd_force_tx_queueing; -/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ -#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */ -#ifndef CUSTOM_KEEP_ALIVE_SETTING -#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE -#endif /* DEFAULT_KEEP_ALIVE_VALUE */ - -#define NULL_PKT_STR "null_pkt" - -/* hooks for custom glom setting option via Makefile */ -#define DEFAULT_GLOM_VALUE -1 -#ifndef CUSTOM_GLOM_SETTING -#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE -#endif -#define WL_AUTO_ROAM_TRIGGER -75 -/* hooks for custom Roaming Trigger setting via Makefile */ -#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ -#define DEFAULT_ROAM_TRIGGER_SETTING -1 -#ifndef CUSTOM_ROAM_TRIGGER_SETTING -#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE -#endif - -/* hooks for custom Roaming Romaing setting via Makefile */ -#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ -#define DEFAULT_ROAM_DELTA_SETTING -1 -#ifndef CUSTOM_ROAM_DELTA_SETTING -#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE -#endif - -/* hooks for custom PNO Event wake lock to guarantee enough time - for the Platform to detect Event before system suspended -*/ -#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */ -#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME -#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME -#endif -/* hooks for custom dhd_dpc_prio setting option via Makefile */ -#define DEFAULT_DHP_DPC_PRIO 1 -#ifndef CUSTOM_DPC_PRIO_SETTING -#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO -#endif - -#ifndef CUSTOM_LISTEN_INTERVAL -#define CUSTOM_LISTEN_INTERVAL LISTEN_INTERVAL -#endif /* CUSTOM_LISTEN_INTERVAL */ - -#define DEFAULT_SUSPEND_BCN_LI_DTIM 3 -#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM -#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM -#endif - -#ifndef CUSTOM_RXF_PRIO_SETTING -#define CUSTOM_RXF_PRIO_SETTING MAX((CUSTOM_DPC_PRIO_SETTING - 1), 1) -#endif - -#define DEFAULT_WIFI_TURNOFF_DELAY 0 -#ifndef WIFI_TURNOFF_DELAY -#define WIFI_TURNOFF_DELAY DEFAULT_WIFI_TURNOFF_DELAY -#endif /* WIFI_TURNOFF_DELAY */ - -#define DEFAULT_WIFI_TURNON_DELAY 200 -#ifndef WIFI_TURNON_DELAY -#define WIFI_TURNON_DELAY DEFAULT_WIFI_TURNON_DELAY -#endif /* WIFI_TURNON_DELAY */ - -#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS 10 /* msec */ -#ifndef CUSTOM_DHD_WATCHDOG_MS -#define CUSTOM_DHD_WATCHDOG_MS DEFAULT_DHD_WATCHDOG_INTERVAL_MS -#endif /* DEFAULT_DHD_WATCHDOG_INTERVAL_MS */ - -#ifdef WLTDLS -#ifndef CUSTOM_TDLS_IDLE_MODE_SETTING -#define CUSTOM_TDLS_IDLE_MODE_SETTING 60000 /* 60sec to tear down TDLS of not active */ -#endif -#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_HIGH -#define CUSTOM_TDLS_RSSI_THRESHOLD_HIGH -70 /* rssi threshold for establishing TDLS link */ -#endif -#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_LOW -#define CUSTOM_TDLS_RSSI_THRESHOLD_LOW -80 /* rssi threshold for tearing down TDLS link */ -#endif -#endif /* WLTDLS */ - -#define DEFAULT_BCN_TIMEOUT 8 -#ifndef CUSTOM_BCN_TIMEOUT -#define CUSTOM_BCN_TIMEOUT DEFAULT_BCN_TIMEOUT -#endif - -#ifdef SET_RETRY_LIMIT -#define DEFAULT_SHORT_RETRY_LIMIT 13 -#ifndef CUSTOM_SRL_SETTING -#define CUSTOM_SRL_SETTING DEFAULT_SHORT_RETRY_LIMIT -#endif - -#define DEFAULT_LONG_RETRY_LIMIT 13 -#ifndef CUSTOM_LRL_SETTING -#define CUSTOM_LRL_SETTING DEFAULT_LONG_RETRY_LIMIT -#endif -#endif /* SET_RETRY_LIMIT */ - -#define MAX_DTIM_SKIP_BEACON_INTERVAL 100 /* max allowed associated AP beacon for DTIM skip */ -#ifndef MAX_DTIM_ALLOWED_INTERVAL -#define MAX_DTIM_ALLOWED_INTERVAL 600 /* max allowed total beacon interval for DTIM skip */ -#endif -#define NO_DTIM_SKIP 1 -#ifdef SDTEST -/* Echo packet generator (SDIO), pkts/s */ -extern uint dhd_pktgen; - -/* Echo packet len (0 => sawtooth, max 1800) */ -extern uint dhd_pktgen_len; -#define MAX_PKTGEN_LEN 1800 -#endif - - -/* optionally set by a module_param_string() */ -#define MOD_PARAM_PATHLEN 2048 -#define MOD_PARAM_INFOLEN 512 - -#ifdef SOFTAP -extern char fw_path2[MOD_PARAM_PATHLEN]; -#endif - -/* Flag to indicate if we should download firmware on driver load */ -extern uint dhd_download_fw_on_driverload; - - -extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); -extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); - -#define IFLOCK_INIT(lock) *lock = 0 -#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ - NdisStallExecution(1); -#define IFUNLOCK(lock) InterlockedExchange((lock), 0) -#define IFLOCK_FREE(lock) -#define FW_SUPPORTED(dhd, capa) ((strstr(dhd->fw_capabilities, #capa) != NULL)) -#ifdef ARP_OFFLOAD_SUPPORT -#define MAX_IPV4_ENTRIES 8 -void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); -void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); - -/* dhd_commn arp offload wrapers */ -void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx); -void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); -int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); -void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef WLTDLS -int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac); -#ifdef PCIE_FULL_DONGLE -void dhd_tdls_update_peer_info(struct net_device *dev, bool connect_disconnect, uint8 *addr); -#endif /* PCIE_FULL_DONGLE */ -#endif /* WLTDLS */ -/* Neighbor Discovery Offload Support */ -int dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable); -int dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipaddr, int idx); -int dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx); -/* ioctl processing for nl80211 */ -int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, struct dhd_ioctl *ioc, void *data_buf); - -#if defined(SUPPORT_MULTIPLE_REVISION) -extern int -concate_revision(struct dhd_bus *bus, char *fwpath, char *nvpath); -#endif /* SUPPORT_MULTIPLE_REVISION */ -void dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path); -void dhd_set_bus_state(void *bus, uint32 state); - -/* Remove proper pkts(either one no-frag pkt or whole fragmented pkts) */ -typedef int (*f_droppkt_t)(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ); -extern bool dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn); - -#ifdef PROP_TXSTATUS -int dhd_os_wlfc_block(dhd_pub_t *pub); -int dhd_os_wlfc_unblock(dhd_pub_t *pub); -extern const uint8 prio2fifo[]; -#endif /* PROP_TXSTATUS */ - -uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail); -void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size); - -int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost); - -#if defined(CONFIG_DHD_USE_STATIC_BUF) -#define DHD_OS_PREALLOC(dhdpub, section, size) dhd_os_prealloc(dhdpub, section, size, FALSE) -#define DHD_OS_PREFREE(dhdpub, addr, size) dhd_os_prefree(dhdpub, addr, size) -#else -#define DHD_OS_PREALLOC(dhdpub, section, size) MALLOC(dhdpub->osh, size) -#define DHD_OS_PREFREE(dhdpub, addr, size) MFREE(dhdpub->osh, addr, size) -#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ - - -#define dhd_add_flowid(pub, ifidx, ac_prio, ea, flowid) do {} while (0) -#define dhd_del_flowid(pub, ifidx, flowid) do {} while (0) - -extern unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub); -extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags); - -/** Miscellaenous DHD Spin Locks */ - -/* Disable router 3GMAC bypass path perimeter lock */ -#define DHD_PERIM_LOCK(dhdp) do {} while (0) -#define DHD_PERIM_UNLOCK(dhdp) do {} while (0) - -/* Enable DHD general spin lock/unlock */ -#define DHD_GENERAL_LOCK(dhdp, flags) \ - (flags) = dhd_os_general_spin_lock(dhdp) -#define DHD_GENERAL_UNLOCK(dhdp, flags) \ - dhd_os_general_spin_unlock((dhdp), (flags)) - -/* Enable DHD flowring spin lock/unlock */ -#define DHD_FLOWRING_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_FLOWRING_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) - -/* Enable DHD common flowring info spin lock/unlock */ -#define DHD_FLOWID_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_FLOWID_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) - - - -typedef struct wl_io_pport { - dhd_pub_t *dhd_pub; - uint ifidx; -} wl_io_pport_t; - -extern void *dhd_pub_wlinfo(dhd_pub_t *dhd_pub); -#ifdef CONFIG_MACH_UNIVERSAL5433 -extern int check_rev(void); -#endif - -#if defined(SET_RPS_CPUS) -int dhd_rps_cpus_enable(struct net_device *net, int enable); -int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len); -void custom_rps_map_clear(struct netdev_rx_queue *queue); -#define PRIMARY_INF 0 -#define VIRTUAL_INF 1 -#ifdef CONFIG_MACH_UNIVERSAL5433 -#define RPS_CPUS_MASK "10" -#define RPS_CPUS_MASK_P2P "10" -#define RPS_CPUS_MASK_IBSS "10" -#define RPS_CPUS_WLAN_CORE_ID 4 -#else -#define RPS_CPUS_MASK "6" -#define RPS_CPUS_MASK_P2P "6" -#define RPS_CPUS_MASK_IBSS "6" -#endif /* CONFIG_MACH_UNIVERSAL5433 */ -#endif /* SET_RPS_CPUS */ - -#ifdef DHD_FW_COREDUMP -void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length); -#endif /* DHD_FW_COREDUMP */ -#if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) -extern int dhdpcie_set_suspend_resume(struct pci_dev *dev, bool state); -#endif /* DHD_USE_IDLECOUNT && BCMPCIE */ - -/* - * Enable this macro if you want to track the calls to wake lock - * This records can be printed using the following command - * cat /sys/bcm-dhd/wklock_trace - * DHD_TRACE_WAKE_LOCK supports over linux 2.6.0 version - */ -/* #define DHD_TRACE_WAKE_LOCK */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -#ifdef DHD_TRACE_WAKE_LOCK -#undef DHD_TRACE_WAKE_LOCK -#warning according to Kernel version DHD_TRACE_WAKE_LOCK cannot be supported -#endif -#endif /* KERNEL_VER < KERNEL_VERSION(2, 6, 0) */ - -#if defined(DHD_TRACE_WAKE_LOCK) -void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp); -#endif - -#if defined(CONFIG_64BIT) -#define DHD_SUPPORT_64BIT -#elif defined(DHD_EFI) -#define DHD_SUPPORT_64BIT -/* by default disabled for other platforms, can enable appropriate macro to enable 64 bit support */ -#endif /* (linux || LINUX) && CONFIG_64BIT */ - -#endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.c b/drivers/net/wireless/bcmdhd/dhd_bta.c deleted file mode 100644 index c4a9835ae332..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_bta.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * BT-AMP support routines - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_bta.c 434434 2013-11-06 07:16:02Z $ - */ -#error "WLBTAMP is not defined" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -#ifdef SEND_HCI_CMD_VIA_IOCTL -#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE - -/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */ -int -dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) -{ - amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; - uint8 buf[BTA_HCI_CMD_MAX_LEN + 16]; - uint len = sizeof(buf); - wl_ioctl_t ioc; - - if (cmd_len < HCI_CMD_PREAMBLE_SIZE) - return BCME_BADLEN; - - if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) - return BCME_BADLEN; - - len = bcm_mkiovar("HCI_cmd", - (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len); - - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = len; - ioc.set = TRUE; - - return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len); -} -#else /* !SEND_HCI_CMD_VIA_IOCTL */ - -static void -dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh) -{ - int prec; - struct pktq *q; - uint count = 0; - - q = dhd_bus_txq(pub->bus); - if (q == NULL) - return; - - DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh)); - - dhd_os_sdlock_txq(pub); - - /* Walk through the txq and toss all HCI ACL data packets */ - PKTQ_PREC_ITER(q, prec) { - void *head_pkt = NULL; - - while (pktq_ppeek(q, prec) != head_pkt) { - void *pkt = pktq_pdeq(q, prec); - int ifidx; - - dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL); - - if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) { - struct ether_header *eh = - (struct ether_header *)PKTDATA(pub->osh, pkt); - - if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { - struct dot11_llc_snap_header *lsh = - (struct dot11_llc_snap_header *)&eh[1]; - - if (bcmp(lsh, BT_SIG_SNAP_MPROT, - DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && - ntoh16(lsh->type) == BTA_PROT_L2CAP) { - amp_hci_ACL_data_t *ACL_data = - (amp_hci_ACL_data_t *)&lsh[1]; - uint16 handle = ltoh16(ACL_data->handle); - - if (HCI_ACL_DATA_HANDLE(handle) == llh) { - PKTFREE(pub->osh, pkt, TRUE); - count ++; - continue; - } - } - } - } - - dhd_prot_hdrpush(pub, ifidx, pkt); - - if (head_pkt == NULL) - head_pkt = pkt; - pktq_penq(q, prec, pkt); - } - } - - dhd_os_sdunlock_txq(pub); - - DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh)); -} - -/* Handle HCI cmd locally. - * Return 0: continue to send the cmd across SDIO - * < 0: stop, fail - * > 0: stop, succuess - */ -static int -_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd) -{ - int status = 0; - - switch (ltoh16_ua((uint8 *)&cmd->opcode)) { - case HCI_Enhanced_Flush: { - eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms; - dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh)); - break; - } - default: - break; - } - - return status; -} - -/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */ -int -dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) -{ - amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; - struct ether_header *eh; - struct dot11_llc_snap_header *lsh; - osl_t *osh = pub->osh; - uint len; - void *p; - int status; - - if (cmd_len < HCI_CMD_PREAMBLE_SIZE) { - DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len)); - return BCME_BADLEN; - } - - if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) { - DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n", - len, cmd_len)); - /* return BCME_BADLEN; */ - } - - p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); - if (p == NULL) { - DHD_ERROR(("dhd_bta_docmd: out of memory\n")); - return BCME_NOMEM; - } - - - /* intercept and handle the HCI cmd locally */ - if ((status = _dhd_bta_docmd(pub, cmd)) > 0) - return 0; - else if (status < 0) - return status; - - /* copy in HCI cmd */ - PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); - bcopy(cmd, PKTDATA(osh, p), len); - - /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ - PKTPUSH(osh, p, RFC1042_HDR_LEN); - eh = (struct ether_header *)PKTDATA(osh, p); - bzero(eh->ether_dhost, ETHER_ADDR_LEN); - ETHER_SET_LOCALADDR(eh->ether_dhost); - bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); - eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); - lsh = (struct dot11_llc_snap_header *)&eh[1]; - bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); - lsh->type = 0; - - return dhd_sendpkt(pub, 0, p); -} -#endif /* !SEND_HCI_CMD_VIA_IOCTL */ - -/* Send HCI ACL data to dongle via data channel */ -int -dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len) -{ - amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf; - struct ether_header *eh; - struct dot11_llc_snap_header *lsh; - osl_t *osh = pub->osh; - uint len; - void *p; - - if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) { - DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len)); - return BCME_BADLEN; - } - - if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) { - DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n", - len, data_len)); - /* return BCME_BADLEN; */ - } - - p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); - if (p == NULL) { - DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n")); - return BCME_NOMEM; - } - - - /* copy in HCI ACL data header and HCI ACL data */ - PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); - bcopy(data, PKTDATA(osh, p), len); - - /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ - PKTPUSH(osh, p, RFC1042_HDR_LEN); - eh = (struct ether_header *)PKTDATA(osh, p); - bzero(eh->ether_dhost, ETHER_ADDR_LEN); - bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); - eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); - lsh = (struct dot11_llc_snap_header *)&eh[1]; - bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); - lsh->type = HTON16(BTA_PROT_L2CAP); - - return dhd_sendpkt(pub, 0, p); -} - -/* txcomplete callback */ -void -dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success) -{ - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp); - amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN); - uint16 handle = ltoh16(ACL_data->handle); - uint16 llh = HCI_ACL_DATA_HANDLE(handle); - - wl_event_msg_t event; - uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)]; - amp_hci_event_t *evt; - num_completed_data_blocks_evt_parms_t *parms; - - uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t); - - /* update the event struct */ - memset(&event, 0, sizeof(event)); - event.version = hton16(BCM_EVENT_MSG_VERSION); - event.event_type = hton32(WLC_E_BTA_HCI_EVENT); - event.status = 0; - event.reason = 0; - event.auth_type = 0; - event.datalen = hton32(len); - event.flags = 0; - - /* generate Number of Completed Blocks event */ - evt = (amp_hci_event_t *)data; - evt->ecode = HCI_Number_of_Completed_Data_Blocks; - evt->plen = sizeof(num_completed_data_blocks_evt_parms_t); - - parms = (num_completed_data_blocks_evt_parms_t *)evt->parms; - htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks); - parms->num_handles = 1; - htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle); - parms->completed[0].pkts = 1; - parms->completed[0].blocks = 1; - - dhd_sendup_event_common(dhdp, &event, data); -} - -/* event callback */ -void -dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) -{ - amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; - - ASSERT(dhdp); - ASSERT(evt); - - switch (evt->ecode) { - case HCI_Command_Complete: { - cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; - switch (ltoh16_ua((uint8 *)&parms->opcode)) { - case HCI_Read_Data_Block_Size: { - read_data_block_size_evt_parms_t *parms2 = - (read_data_block_size_evt_parms_t *)parms->parms; - dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num); - break; - } - } - break; - } - - case HCI_Flush_Occurred: { - flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms; - dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle)); - break; - } - default: - break; - } -} diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.h b/drivers/net/wireless/bcmdhd/dhd_bta.h deleted file mode 100644 index 0c5e9de534e9..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_bta.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * BT-AMP support routines - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_bta.h 291086 2011-10-21 01:17:24Z $ - */ -#ifndef __dhd_bta_h__ -#define __dhd_bta_h__ - -struct dhd_pub; - -extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len); - -extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len); - -extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len); -extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success); - - -#endif /* __dhd_bta_h__ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_bus.h b/drivers/net/wireless/bcmdhd/dhd_bus.h deleted file mode 100644 index 971ac1a73166..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_bus.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_bus.h 619942 2016-02-19 02:20:35Z $ - */ - -#ifndef _dhd_bus_h_ -#define _dhd_bus_h_ - -/* - * Exported from dhd bus module (dhd_usb, dhd_sdio) - */ - -/* Indicate (dis)interest in finding dongles. */ -extern int dhd_bus_register(void); -extern void dhd_bus_unregister(void); - -/* Download firmware image and nvram image */ -extern int dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, char *fw_path, char *nv_path); - -/* Stop bus module: clear pending frames, disable data flow */ -extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); - -/* Initialize bus module: prepare for communication w/dongle */ -extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); - -/* Get the Bus Idle Time */ -extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); - -/* Set the Bus Idle Time */ -extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); - -/* Send a data frame to the dongle. Callee disposes of txp. */ -#ifdef BCMPCIE -extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx); -#else -extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); -#endif - - -/* Send/receive a control message to/from the dongle. - * Expects caller to enforce a single outstanding transaction. - */ -extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); -extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); - -/* Watchdog timer function */ -extern bool dhd_bus_watchdog(dhd_pub_t *dhd); - -extern int dhd_bus_oob_intr_register(dhd_pub_t *dhdp); -extern void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp); -extern void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable); -extern void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub); -extern void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub); -extern bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub); - -#if defined(DHD_DEBUG) -/* Device console input function */ -extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); -extern int dhd_bus_mem_dump(dhd_pub_t *dhd); -#endif /* defined(DHD_DEBUG) */ - -/* Deferred processing for the bus, return TRUE requests reschedule */ -extern bool dhd_bus_dpc(struct dhd_bus *bus); -extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); - - -/* Check for and handle local prot-specific iovar commands */ -extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Add bus dump output to a buffer */ -extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); - -/* Clear any bus counters */ -extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); - -/* return the dongle chipid */ -extern uint dhd_bus_chip(struct dhd_bus *bus); - -/* return the dongle chiprev */ -extern uint dhd_bus_chiprev(struct dhd_bus *bus); - -/* Set user-specified nvram parameters. */ -extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); - -extern void *dhd_bus_pub(struct dhd_bus *bus); -extern void *dhd_bus_txq(struct dhd_bus *bus); -extern void *dhd_bus_sih(struct dhd_bus *bus); -extern uint dhd_bus_hdrlen(struct dhd_bus *bus); -#ifdef BCMSDIO -extern void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val); -#else -#define dhd_bus_set_dotxinrx(a, b) do {} while (0) -#endif - -#define DHD_SET_BUS_STATE_DOWN(_bus) do { \ - (_bus)->dhd->busstate = DHD_BUS_DOWN; \ -} while (0) - -/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ -extern int dhd_bus_reg_sdio_notify(void* semaphore); -extern void dhd_bus_unreg_sdio_notify(void); -extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable); -extern int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, - uint32 *slot_num); - -#ifdef BCMPCIE -enum { - DNGL_TO_HOST_BUF_IOCT, - DNGL_TO_HOST_DMA_SCRATCH_BUFFER, - DNGL_TO_HOST_DMA_SCRATCH_BUFFER_LEN, - HOST_TO_DNGL_DMA_WRITEINDX_BUFFER, - HOST_TO_DNGL_DMA_READINDX_BUFFER, - DNGL_TO_HOST_DMA_WRITEINDX_BUFFER, - DNGL_TO_HOST_DMA_READINDX_BUFFER, - TOTAL_LFRAG_PACKET_CNT, - HTOD_MB_DATA, - DTOH_MB_DATA, - RING_BUF_ADDR, - H2D_DMA_WRITEINDX, - H2D_DMA_READINDX, - D2H_DMA_WRITEINDX, - D2H_DMA_READINDX, - RING_READ_PTR, - RING_WRITE_PTR, - RING_LEN_ITEMS, - RING_MAX_ITEM, - MAX_HOST_RXBUFS -}; -typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32); -extern void dhd_bus_cmn_writeshared(struct dhd_bus *bus, void * data, uint32 len, uint8 type, - uint16 ringid); -extern void dhd_bus_ringbell(struct dhd_bus *bus, uint32 value); -extern void dhd_bus_cmn_readshared(struct dhd_bus *bus, void* data, uint8 type, uint16 ringid); -extern uint32 dhd_bus_get_sharedflags(struct dhd_bus *bus); -extern void dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count); -extern void dhd_bus_start_queue(struct dhd_bus *bus); -extern void dhd_bus_stop_queue(struct dhd_bus *bus); -extern void dhd_bus_update_retlen(struct dhd_bus *bus, uint32 retlen, uint32 cmd_id, uint16 status, - uint32 resp_len); -extern dhd_mb_ring_t dhd_bus_get_mbintr_fn(struct dhd_bus *bus); -extern void dhd_bus_write_flow_ring_states(struct dhd_bus *bus, - void * data, uint16 flowid); -extern void dhd_bus_read_flow_ring_states(struct dhd_bus *bus, - void * data, uint8 flowid); -extern int dhd_bus_flow_ring_create_request(struct dhd_bus *bus, void *flow_ring_node); -extern void dhd_bus_clean_flow_ring(struct dhd_bus *bus, void *flow_ring_node); -extern void dhd_bus_flow_ring_create_response(struct dhd_bus *bus, uint16 flow_id, int32 status); -extern int dhd_bus_flow_ring_delete_request(struct dhd_bus *bus, void *flow_ring_node); -extern void dhd_bus_flow_ring_delete_response(struct dhd_bus *bus, uint16 flowid, uint32 status); -extern int dhd_bus_flow_ring_flush_request(struct dhd_bus *bus, void *flow_ring_node); -extern void dhd_bus_flow_ring_flush_response(struct dhd_bus *bus, uint16 flowid, uint32 status); -extern uint8 dhd_bus_is_txmode_push(struct dhd_bus *bus); -extern uint32 dhd_bus_max_h2d_queues(struct dhd_bus *bus, uint8 *txpush); -extern int dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs); -extern int dhdpcie_bus_clock_start(struct dhd_bus *bus); -extern int dhdpcie_bus_clock_stop(struct dhd_bus *bus); -extern int dhdpcie_bus_enable_device(struct dhd_bus *bus); -extern int dhdpcie_bus_disable_device(struct dhd_bus *bus); -extern int dhdpcie_bus_alloc_resource(struct dhd_bus *bus); -extern void dhdpcie_bus_free_resource(struct dhd_bus *bus); -extern bool dhdpcie_bus_dongle_attach(struct dhd_bus *bus); -extern int dhd_bus_release_dongle(struct dhd_bus *bus); -extern int dhd_bus_request_irq(struct dhd_bus *bus); - - -#ifdef DHD_USE_IDLECOUNT -extern bool dhd_bus_is_resume_done(dhd_pub_t *dhdp); -extern bool bus_wake(struct dhd_bus *bus); -extern bool bus_wakeup(struct dhd_bus *bus); -extern bool dhd_bus_wake(dhd_pub_t *dhdp); -extern bool dhd_bus_wakeup(dhd_pub_t *dhdp); -#endif /* DHD_USE_IDLECOUNT */ -#endif /* BCMPCIE */ -#endif /* _dhd_bus_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c deleted file mode 100644 index bb88f46a51d6..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ /dev/null @@ -1,811 +0,0 @@ -/* - * DHD Protocol Module for CDC and BDC. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_cdc.c 492377 2014-07-21 19:54:06Z $ - * - * BDC is like CDC, except it includes a header for data packets to convey - * packet priority over the bus, and flags (e.g. to indicate checksum status - * for dongle offload.) - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - - -#ifdef PROP_TXSTATUS -#include -#include -#endif - - -#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ -#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE - * defined in dhd_sdio.c (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 - */ - -typedef struct dhd_prot { - uint16 reqid; - uint8 pending; - uint32 lastcmd; - uint8 bus_header[BUS_HEADER_LEN]; - cdc_ioctl_t msg; - unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; -} dhd_prot_t; - - -static int -dhdcdc_msg(dhd_pub_t *dhd) -{ - int err = 0; - dhd_prot_t *prot = dhd->prot; - int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - DHD_OS_WAKE_LOCK(dhd); - - /* 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 */ - err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); - - DHD_OS_WAKE_UNLOCK(dhd); - return err; -} - -static int -dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) -{ - int ret; - int cdc_len = len + sizeof(cdc_ioctl_t); - dhd_prot_t *prot = dhd->prot; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - - do { - ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); - if (ret < 0) - break; - } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); - - - return ret; -} - -static int -dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - dhd_prot_t *prot = dhd->prot; - cdc_ioctl_t *msg = &prot->msg; - int ret = 0, retries = 0; - uint32 id, flags = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); - - - /* Respond "bcmerror" and "bcmerrorstr" with local cache */ - if (cmd == WLC_GET_VAR && buf) - { - if (!strcmp((char *)buf, "bcmerrorstr")) - { - strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN); - goto done; - } - else if (!strcmp((char *)buf, "bcmerror")) - { - *(int *)buf = dhd->dongle_error; - goto done; - } - } - - memset(msg, 0, sizeof(cdc_ioctl_t)); - - msg->cmd = htol32(cmd); - msg->len = htol32(len); - msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); - CDC_SET_IF_IDX(msg, ifidx); - /* add additional action bits */ - action &= WL_IOCTL_ACTION_MASK; - msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); - msg->flags = htol32(msg->flags); - - if (buf) - memcpy(prot->buf, buf, len); - - if ((ret = dhdcdc_msg(dhd)) < 0) { - if (!dhd->hang_was_sent) - DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret)); - goto done; - } - -retry: - /* wait for interrupt and get first fragment */ - if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) - goto done; - - flags = ltoh32(msg->flags); - id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; - - if ((id < prot->reqid) && (++retries < RETRIES)) - goto retry; - if (id != prot->reqid) { - DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", - dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); - ret = -EINVAL; - goto done; - } - - /* Copy info buffer */ - if (buf) - { - if (ret < (int)len) - len = ret; - memcpy(buf, (void*) prot->buf, len); - } - - /* Check the ERROR flag */ - if (flags & CDCF_IOC_ERROR) - { - ret = ltoh32(msg->status); - /* Cache error from dongle */ - dhd->dongle_error = ret; - } - -done: - return ret; -} - - -static int -dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - dhd_prot_t *prot = dhd->prot; - cdc_ioctl_t *msg = &prot->msg; - int ret = 0; - uint32 flags, id; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - return -EIO; - } - - /* don't talk to the dongle if fw is about to be reloaded */ - if (dhd->hang_was_sent) { - DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", - __FUNCTION__)); - return -EIO; - } - - memset(msg, 0, sizeof(cdc_ioctl_t)); - - msg->cmd = htol32(cmd); - msg->len = htol32(len); - msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); - CDC_SET_IF_IDX(msg, ifidx); - /* add additional action bits */ - action &= WL_IOCTL_ACTION_MASK; - msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; - msg->flags = htol32(msg->flags); - - if (buf) - memcpy(prot->buf, buf, len); - - if ((ret = dhdcdc_msg(dhd)) < 0) { - DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret)); - goto done; - } - - if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) - goto done; - - flags = ltoh32(msg->flags); - id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; - - if (id != prot->reqid) { - DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", - dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); - ret = -EINVAL; - goto done; - } - - /* Check the ERROR flag */ - if (flags & CDCF_IOC_ERROR) - { - ret = ltoh32(msg->status); - /* Cache error from dongle */ - dhd->dongle_error = ret; - } - -done: - return ret; -} - - -int -dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) -{ - dhd_prot_t *prot = dhd->prot; - int ret = -1; - uint8 action; - - if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - goto done; - } - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(len <= WLC_IOCTL_MAXLEN); - - if (len > WLC_IOCTL_MAXLEN) - goto done; - - if (prot->pending == TRUE) { - DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", - ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, - (unsigned long)prot->lastcmd)); - if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { - DHD_TRACE(("iovar cmd=%s\n", (char*)buf)); - } - goto done; - } - - prot->pending = TRUE; - prot->lastcmd = ioc->cmd; - action = ioc->set; - if (action & WL_IOCTL_ACTION_SET) - ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - else { - ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - if (ret > 0) - ioc->used = ret - sizeof(cdc_ioctl_t); - } - - /* Too many programs assume ioctl() returns 0 on success */ - if (ret >= 0) - ret = 0; - else { - cdc_ioctl_t *msg = &prot->msg; - ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ - } - - /* Intercept the wme_dp ioctl here */ - if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { - int slen, val = 0; - - slen = strlen("wme_dp") + 1; - if (len >= (int)(slen + sizeof(int))) - bcopy(((char *)buf + slen), &val, sizeof(int)); - dhd->wme_dp = (uint8) ltoh32(val); - } - - prot->pending = FALSE; - -done: - - return ret; -} - -int -dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - return BCME_UNSUPPORTED; -} - -void -dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); -#ifdef PROP_TXSTATUS - dhd_wlfc_dump(dhdp, strbuf); -#endif -} - -/* The FreeBSD PKTPUSH could change the packet buf pinter - so we need to make it changable -*/ -#define PKTBUF pktbuf -void -dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) -{ -#ifdef BDC - struct bdc_header *h; -#endif /* BDC */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BDC - /* Push BDC header used to convey priority for buses that don't */ - - PKTPUSH(dhd->osh, PKTBUF, BDC_HEADER_LEN); - - h = (struct bdc_header *)PKTDATA(dhd->osh, PKTBUF); - - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (PKTSUMNEEDED(PKTBUF)) - h->flags |= BDC_FLAG_SUM_NEEDED; - - - h->priority = (PKTPRIO(PKTBUF) & BDC_PRIORITY_MASK); - h->flags2 = 0; - h->dataOffset = 0; -#endif /* BDC */ - BDC_SET_IF_IDX(h, ifidx); -} -#undef PKTBUF /* Only defined in the above routine */ - -uint -dhd_prot_hdrlen(dhd_pub_t *dhd, void *PKTBUF) -{ - uint hdrlen = 0; -#ifdef BDC - /* Length of BDC(+WLFC) headers pushed */ - hdrlen = BDC_HEADER_LEN + (((struct bdc_header *)PKTBUF)->dataOffset * 4); -#endif - return hdrlen; -} - -int -dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, - uint *reorder_info_len) -{ -#ifdef BDC - struct bdc_header *h; -#endif - uint8 data_offset = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BDC - if (reorder_info_len) - *reorder_info_len = 0; - /* Pop BDC header used to convey priority for buses that don't */ - - if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { - DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN)); - return BCME_ERROR; - } - - h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); - - if (!ifidx) { - /* for tx packet, skip the analysis */ - data_offset = h->dataOffset; - PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); - goto exit; - } - - if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { - DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", - __FUNCTION__, *ifidx)); - return BCME_ERROR; - } - - if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { - DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", - dhd_ifname(dhd, *ifidx), h->flags)); - if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) - h->dataOffset = 0; - else - return BCME_ERROR; - } - - if (h->flags & BDC_FLAG_SUM_GOOD) { - DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n", - dhd_ifname(dhd, *ifidx), h->flags)); - PKTSETSUMGOOD(pktbuf, TRUE); - } - - PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); - data_offset = h->dataOffset; - PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); -#endif /* BDC */ - - -#ifdef PROP_TXSTATUS - if (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf))) { - /* - - parse txstatus only for packets that came from the firmware - */ - dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), - reorder_buf_info, reorder_info_len); - - } -#endif /* PROP_TXSTATUS */ - -exit: - PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); - return 0; -} - - -int -dhd_prot_attach(dhd_pub_t *dhd) -{ - dhd_prot_t *cdc; - - if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - memset(cdc, 0, sizeof(dhd_prot_t)); - - /* ensure that the msg buf directly follows the cdc msg struct */ - if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) { - DHD_ERROR(("dhd_prot_t is not correctly defined\n")); - goto fail; - } - - dhd->prot = cdc; -#ifdef BDC - dhd->hdrlen += BDC_HEADER_LEN; -#endif - dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN; - return 0; - -fail: - if (cdc != NULL) - DHD_OS_PREFREE(dhd, cdc, sizeof(dhd_prot_t)); - return BCME_NOMEM; -} - -/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ -void -dhd_prot_detach(dhd_pub_t *dhd) -{ -#ifdef PROP_TXSTATUS - dhd_wlfc_deinit(dhd); -#endif - DHD_OS_PREFREE(dhd, dhd->prot, sizeof(dhd_prot_t)); - dhd->prot = NULL; -} - -void -dhd_prot_dstats(dhd_pub_t *dhd) -{ - /* copy bus stats */ - - dhd->dstats.tx_packets = dhd->tx_packets; - dhd->dstats.tx_errors = dhd->tx_errors; - dhd->dstats.rx_packets = dhd->rx_packets; - dhd->dstats.rx_errors = dhd->rx_errors; - dhd->dstats.rx_dropped = dhd->rx_dropped; - dhd->dstats.multicast = dhd->rx_multicast; - return; -} - -int -dhd_sync_with_dongle(dhd_pub_t *dhd) -{ - int ret = 0; - wlc_rev_info_t revinfo; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - - /* Get the device rev info */ - memset(&revinfo, 0, sizeof(revinfo)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); - if (ret < 0) - goto done; - - - dhd_process_cid_mac(dhd, TRUE); - - ret = dhd_preinit_ioctls(dhd); - - if (!ret) - dhd_process_cid_mac(dhd, FALSE); - - /* Always assumes wl for now */ - dhd->iswl = TRUE; - -done: - return ret; -} - -int dhd_prot_init(dhd_pub_t *dhd) -{ - return TRUE; -} - -void -dhd_prot_stop(dhd_pub_t *dhd) -{ -/* Nothing to do for CDC */ -} - - -static void -dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, - uint32 *pkt_count, void **pplast, uint8 start, uint8 end) -{ - void *plast = NULL, *p; - uint32 pkt_cnt = 0; - - if (ptr->pend_pkts == 0) { - DHD_REORDER(("%s: no packets in reorder queue \n", __FUNCTION__)); - *pplast = NULL; - *pkt_count = 0; - *pkt = NULL; - return; - } - do { - p = (void *)(ptr->p[start]); - ptr->p[start] = NULL; - - if (p != NULL) { - if (plast == NULL) - *pkt = p; - else - PKTSETNEXT(osh, plast, p); - - plast = p; - pkt_cnt++; - } - start++; - if (start > ptr->max_idx) - start = 0; - } while (start != end); - *pplast = plast; - *pkt_count = pkt_cnt; - ptr->pend_pkts -= (uint8)pkt_cnt; -} - -int -dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, - void **pkt, uint32 *pkt_count) -{ - uint8 flow_id, max_idx, cur_idx, exp_idx; - struct reorder_info *ptr; - uint8 flags; - void *cur_pkt, *plast = NULL; - uint32 cnt = 0; - - if (pkt == NULL) { - if (pkt_count != NULL) - *pkt_count = 0; - return 0; - } - - flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; - flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; - - DHD_REORDER(("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags, - reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET], - reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET], - reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET])); - - /* validate flags and flow id */ - if (flags == 0xFF) { - DHD_ERROR(("%s: invalid flags...so ignore this packet\n", __FUNCTION__)); - *pkt_count = 1; - return 0; - } - - cur_pkt = *pkt; - *pkt = NULL; - - ptr = dhd->reorder_bufs[flow_id]; - if (flags & WLHOST_REORDERDATA_DEL_FLOW) { - uint32 buf_size = sizeof(struct reorder_info); - - DHD_REORDER(("%s: Flags indicating to delete a flow id %d\n", - __FUNCTION__, flow_id)); - - if (ptr == NULL) { - DHD_REORDER(("%s: received flags to cleanup, but no flow (%d) yet\n", - __FUNCTION__, flow_id)); - *pkt_count = 1; - *pkt = cur_pkt; - return 0; - } - - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - ptr->exp_idx, ptr->exp_idx); - /* set it to the last packet */ - if (plast) { - PKTSETNEXT(dhd->osh, plast, cur_pkt); - cnt++; - } - else { - if (cnt != 0) { - DHD_ERROR(("%s: del flow: something fishy, pending packets %d\n", - __FUNCTION__, cnt)); - } - *pkt = cur_pkt; - cnt = 1; - } - buf_size += ((ptr->max_idx + 1) * sizeof(void *)); - MFREE(dhd->osh, ptr, buf_size); - dhd->reorder_bufs[flow_id] = NULL; - *pkt_count = cnt; - return 0; - } - /* all the other cases depend on the existance of the reorder struct for that flow id */ - if (ptr == NULL) { - uint32 buf_size_alloc = sizeof(reorder_info_t); - max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; - - buf_size_alloc += ((max_idx + 1) * sizeof(void*)); - /* allocate space to hold the buffers, index etc */ - - DHD_REORDER(("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n", - __FUNCTION__, buf_size_alloc, flow_id, max_idx)); - ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc); - if (ptr == NULL) { - DHD_ERROR(("%s: Malloc failed to alloc buffer\n", __FUNCTION__)); - *pkt_count = 1; - return 0; - } - bzero(ptr, buf_size_alloc); - dhd->reorder_bufs[flow_id] = ptr; - ptr->p = (void *)(ptr+1); - ptr->max_idx = max_idx; - } - if (flags & WLHOST_REORDERDATA_NEW_HOLE) { - DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__)); - if (ptr->pend_pkts) { - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - ptr->exp_idx, ptr->exp_idx); - ptr->pend_pkts = 0; - } - ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; - ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; - ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; - ptr->p[ptr->cur_idx] = cur_pkt; - ptr->pend_pkts++; - *pkt_count = cnt; - } - else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) { - cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; - exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; - - - if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) { - /* still in the current hole */ - /* enqueue the current on the buffer chain */ - if (ptr->p[cur_idx] != NULL) { - DHD_REORDER(("%s: HOLE: ERROR buffer pending..free it\n", - __FUNCTION__)); - PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); - ptr->p[cur_idx] = NULL; - } - ptr->p[cur_idx] = cur_pkt; - ptr->pend_pkts++; - ptr->cur_idx = cur_idx; - DHD_REORDER(("%s: fill up a hole..pending packets is %d\n", - __FUNCTION__, ptr->pend_pkts)); - *pkt_count = 0; - *pkt = NULL; - } - else if (ptr->exp_idx == cur_idx) { - /* got the right one ..flush from cur to exp and update exp */ - DHD_REORDER(("%s: got the right one now, cur_idx is %d\n", - __FUNCTION__, cur_idx)); - if (ptr->p[cur_idx] != NULL) { - DHD_REORDER(("%s: Error buffer pending..free it\n", - __FUNCTION__)); - PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); - ptr->p[cur_idx] = NULL; - } - ptr->p[cur_idx] = cur_pkt; - ptr->pend_pkts++; - - ptr->cur_idx = cur_idx; - ptr->exp_idx = exp_idx; - - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - cur_idx, exp_idx); - *pkt_count = cnt; - DHD_REORDER(("%s: freeing up buffers %d, still pending %d\n", - __FUNCTION__, cnt, ptr->pend_pkts)); - } - else { - uint8 end_idx; - bool flush_current = FALSE; - /* both cur and exp are moved now .. */ - DHD_REORDER(("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n", - __FUNCTION__, flow_id, ptr->cur_idx, cur_idx, - ptr->exp_idx, exp_idx)); - if (flags & WLHOST_REORDERDATA_FLUSH_ALL) - end_idx = ptr->exp_idx; - else - end_idx = exp_idx; - - /* flush pkts first */ - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - ptr->exp_idx, end_idx); - - if (cur_idx == ptr->max_idx) { - if (exp_idx == 0) - flush_current = TRUE; - } else { - if (exp_idx == cur_idx + 1) - flush_current = TRUE; - } - if (flush_current) { - if (plast) - PKTSETNEXT(dhd->osh, plast, cur_pkt); - else - *pkt = cur_pkt; - cnt++; - } - else { - ptr->p[cur_idx] = cur_pkt; - ptr->pend_pkts++; - } - ptr->exp_idx = exp_idx; - ptr->cur_idx = cur_idx; - *pkt_count = cnt; - } - } - else { - uint8 end_idx; - /* no real packet but update to exp_seq...that means explicit window move */ - exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; - - DHD_REORDER(("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n", - __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx)); - if (flags & WLHOST_REORDERDATA_FLUSH_ALL) - end_idx = ptr->exp_idx; - else - end_idx = exp_idx; - - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx); - if (plast) - PKTSETNEXT(dhd->osh, plast, cur_pkt); - else - *pkt = cur_pkt; - cnt++; - *pkt_count = cnt; - /* set the new expected idx */ - ptr->exp_idx = exp_idx; - } - return 0; -} diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c deleted file mode 100644 index 4dd551754756..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ - */ - -#include -#include - -#include -#include -#include -#include - -#ifdef PKT_FILTER_SUPPORT -#include -#include -#endif - -extern struct bcm_cfg80211 *g_bcm_cfg; - -#ifdef PKT_FILTER_SUPPORT -extern uint dhd_pkt_filter_enable; -extern uint dhd_master_mode; -extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -#endif - -static int dhd_dongle_up = FALSE; - -#include -#include -#include -#include -#include -#include - -static s32 wl_dongle_up(struct net_device *ndev); -static s32 wl_dongle_down(struct net_device *ndev); - -/** - * Function implementations - */ - -s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg) -{ - dhd_dongle_up = FALSE; - return 0; -} - -s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg) -{ - dhd_dongle_up = FALSE; - return 0; -} - -s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg) -{ - struct net_device *ndev; - s32 err = 0; - - WL_TRACE(("In\n")); - if (!dhd_dongle_up) { - WL_ERR(("Dongle is already down\n")); - return err; - } - - ndev = bcmcfg_to_prmry_ndev(cfg); - wl_dongle_down(ndev); - dhd_dongle_up = FALSE; - return 0; -} - -s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val) -{ - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - dhd->op_mode |= val; - WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode)); -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd->arp_version == 1) { - /* IF P2P is enabled, disable arpoe */ - dhd_arp_offload_set(dhd, 0); - dhd_arp_offload_enable(dhd, false); - } -#endif /* ARP_OFFLOAD_SUPPORT */ - - return 0; -} - -s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg) -{ - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); - WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode)); - -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd->arp_version == 1) { - /* IF P2P is disabled, enable arpoe back for STA mode. */ - dhd_arp_offload_set(dhd, dhd_arp_mode); - dhd_arp_offload_enable(dhd, true); - } -#endif /* ARP_OFFLOAD_SUPPORT */ - - return 0; -} - -struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, - uint8 *mac, uint8 bssidx) -{ - return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE); -} - -int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) -{ - return dhd_register_if(cfg->pub, ifidx, FALSE); -} - -int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) -{ - return dhd_remove_if(cfg->pub, ifidx, FALSE); -} - -struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev) -{ - if (ndev) { - if (ndev->ieee80211_ptr) { - kfree(ndev->ieee80211_ptr); - ndev->ieee80211_ptr = NULL; - } - free_netdev(ndev); - return NULL; - } - - return ndev; -} - -void dhd_netdev_free(struct net_device *ndev) -{ -#ifdef WL_CFG80211 - ndev = dhd_cfg80211_netdev_free(ndev); -#endif - if (ndev) - free_netdev(ndev); -} - -static s32 -wl_dongle_up(struct net_device *ndev) -{ - s32 err = 0; - u32 up = 0; - - err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); - if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); - } - return err; -} - -static s32 -wl_dongle_down(struct net_device *ndev) -{ - s32 err = 0; - u32 down = 0; - - err = wldev_ioctl(ndev, WLC_DOWN, &down, sizeof(down), true); - if (unlikely(err)) { - WL_ERR(("WLC_DOWN error (%d)\n", err)); - } - return err; -} - - -s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) -{ -#ifndef DHD_SDALIGN -#define DHD_SDALIGN 32 -#endif - struct net_device *ndev; - s32 err = 0; - - WL_TRACE(("In\n")); - if (dhd_dongle_up) { - WL_ERR(("Dongle is already up\n")); - return err; - } - - ndev = bcmcfg_to_prmry_ndev(cfg); - - err = wl_dongle_up(ndev); - if (unlikely(err)) { - WL_ERR(("wl_dongle_up failed\n")); - goto default_conf_out; - } - dhd_dongle_up = true; - -default_conf_out: - - return err; - -} diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h deleted file mode 100644 index 2bdde11bcfdc..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ - */ - - -#ifndef __DHD_CFG80211__ -#define __DHD_CFG80211__ - -#include -#include - -#ifndef WL_ERR -#define WL_ERR CFG80211_ERR -#endif -#ifndef WL_TRACE -#define WL_TRACE CFG80211_TRACE -#endif - -s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg); -s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg); -s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg); -s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val); -s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg); -s32 dhd_config_dongle(struct bcm_cfg80211 *cfg); - -#endif /* __DHD_CFG80211__ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c b/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c deleted file mode 100644 index a84f2ff910e4..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Linux cfg80211 vendor command/event handlers of DHD - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_cfg_vendor.c 514708 2014-11-11 23:59:07Z $ - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef VENDOR_EXT_SUPPORT -static int dhd_cfgvendor_priv_string_handler(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - const struct bcm_nlmsg_hdr *nlioc = data; - struct net_device *ndev = NULL; - struct bcm_cfg80211 *cfg; - struct sk_buff *reply; - void *buf = NULL, *cur; - dhd_pub_t *dhd; - dhd_ioctl_t ioc = { 0 }; - int ret = 0, ret_len, payload, msglen; - int maxmsglen = PAGE_SIZE - 0x100; - int8 index; - - WL_TRACE(("entry: cmd = %d\n", nlioc->cmd)); - DHD_ERROR(("entry: cmd = %d\n", nlioc->cmd)); - - cfg = wiphy_priv(wiphy); - dhd = cfg->pub; - - DHD_OS_WAKE_LOCK(dhd); - - /* send to dongle only if we are not waiting for reload already */ - if (dhd->hang_was_sent) { - WL_ERR(("HANG was sent up earlier\n")); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS); - DHD_OS_WAKE_UNLOCK(dhd); - return OSL_ERROR(BCME_DONGLE_DOWN); - } - - len -= sizeof(struct bcm_nlmsg_hdr); - ret_len = nlioc->len; - if (ret_len > 0 || len > 0) { - if (len > DHD_IOCTL_MAXLEN) { - WL_ERR(("oversize input buffer %d\n", len)); - len = DHD_IOCTL_MAXLEN; - } - if (ret_len > DHD_IOCTL_MAXLEN) { - WL_ERR(("oversize return buffer %d\n", ret_len)); - ret_len = DHD_IOCTL_MAXLEN; - } - payload = max(ret_len, len) + 1; - buf = vzalloc(payload); - if (!buf) { - DHD_OS_WAKE_UNLOCK(dhd); - return -ENOMEM; - } - memcpy(buf, (void *)nlioc + nlioc->offset, len); - *(char *)(buf + len) = '\0'; - } - - ndev = wdev_to_wlc_ndev(wdev, cfg); - index = dhd_net2idx(dhd->info, ndev); - if (index == DHD_BAD_IF) { - WL_ERR(("Bad ifidx from wdev:%p\n", wdev)); - ret = BCME_ERROR; - goto done; - } - - ioc.cmd = nlioc->cmd; - ioc.len = nlioc->len; - ioc.set = nlioc->set; - ioc.driver = nlioc->magic; - ret = dhd_ioctl_process(dhd, index, &ioc, buf); - if (ret) { - WL_TRACE(("dhd_ioctl_process return err %d\n", ret)); - ret = OSL_ERROR(ret); - goto done; - } - - cur = buf; - while (ret_len > 0) { - msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len; - ret_len -= msglen; - payload = msglen + sizeof(msglen); - reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload); - if (!reply) { - WL_ERR(("Failed to allocate reply msg\n")); - ret = -ENOMEM; - break; - } - - if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) || - nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) { - kfree_skb(reply); - ret = -ENOBUFS; - break; - } - - ret = cfg80211_vendor_cmd_reply(reply); - if (ret) { - WL_ERR(("testmode reply failed:%d\n", ret)); - break; - } - cur += msglen; - } - -done: - vfree(buf); - DHD_OS_WAKE_UNLOCK(dhd); - return ret; -} - -const struct wiphy_vendor_command dhd_cfgvendor_cmds [] = { - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_PRIV_STR - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = dhd_cfgvendor_priv_string_handler - }, -}; - -int cfgvendor_attach(struct wiphy *wiphy) -{ - wiphy->vendor_commands = dhd_cfgvendor_cmds; - wiphy->n_vendor_commands = ARRAY_SIZE(dhd_cfgvendor_cmds); - - return 0; -} - -int cfgvendor_detach(struct wiphy *wiphy) -{ - wiphy->vendor_commands = NULL; - wiphy->n_vendor_commands = 0; - - return 0; -} -#endif /* VENDOR_EXT_SUPPORT */ diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c deleted file mode 100644 index 92c16c32366d..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ /dev/null @@ -1,2723 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), common DHD core. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_common.c 642286 2016-06-08 05:57:20Z $ - */ -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef SHOW_LOGTRACE -#include -#endif /* SHOW_LOGTRACE */ - -#ifdef BCMPCIE -#include -#endif - -#include -#include -#include -#include - -#ifdef WL_CFG80211 -#include -#endif -#ifdef PNO_SUPPORT -#include -#endif -#ifdef RTT_SUPPORT -#include -#endif - -#define htod32(i) (i) -#define htod16(i) (i) -#define dtoh32(i) (i) -#define dtoh16(i) (i) -#define htodchanspec(i) (i) -#define dtohchanspec(i) (i) - -#ifdef PROP_TXSTATUS -#include -#include -#endif - -#ifdef DHD_WMF -#include -#include -#endif /* DHD_WMF */ - - -#ifdef WLMEDIA_HTSF -extern void htsf_update(struct dhd_info *dhd, void *data); -#endif -int dhd_msg_level = DHD_ERROR_VAL; - - -#ifdef SOFTAP -char fw_path2[MOD_PARAM_PATHLEN]; -extern bool softap_enabled; -#endif - -/* Last connection success/failure status */ -uint32 dhd_conn_event; -uint32 dhd_conn_status; -uint32 dhd_conn_reason; - -#if defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE) -static int check_event_log_sequence_number(uint32 seq_no); -#endif /* defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE) */ -extern int dhd_iscan_request(void * dhdp, uint16 action); -extern void dhd_ind_scan_confirm(void *h, bool status); -extern int dhd_iscan_in_progress(void *h); -void dhd_iscan_lock(void); -void dhd_iscan_unlock(void); -extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); -#if !defined(AP) && defined(WLP2P) -extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); -#endif -bool ap_cfg_running = FALSE; -bool ap_fw_loaded = FALSE; - -/* Version string to report */ -#ifdef DHD_DEBUG -#ifndef SRCBASE -#define SRCBASE "drivers/net/wireless/bcmdhd" -#endif -#define DHD_COMPILED "\nCompiled in " SRCBASE -#endif /* DHD_DEBUG */ - -#if defined(DHD_DEBUG) -const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR - DHD_COMPILED " on " __DATE__ " at " __TIME__; -#else -const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nCompiled from "; -#endif - -void dhd_set_timer(void *bus, uint wdtick); - - - -/* IOVar table */ -enum { - IOV_VERSION = 1, - IOV_MSGLEVEL, - IOV_BCMERRORSTR, - IOV_BCMERROR, - IOV_WDTICK, - IOV_DUMP, - IOV_CLEARCOUNTS, - IOV_LOGDUMP, - IOV_LOGCAL, - IOV_LOGSTAMP, - IOV_GPIOOB, - IOV_IOCTLTIMEOUT, -#if defined(DHD_DEBUG) - IOV_CONS, - IOV_DCONSOLE_POLL, -#endif /* defined(DHD_DEBUG) */ -#ifdef PROP_TXSTATUS - IOV_PROPTXSTATUS_ENABLE, - IOV_PROPTXSTATUS_MODE, - IOV_PROPTXSTATUS_OPT, - IOV_PROPTXSTATUS_MODULE_IGNORE, - IOV_PROPTXSTATUS_CREDIT_IGNORE, - IOV_PROPTXSTATUS_TXSTATUS_IGNORE, - IOV_PROPTXSTATUS_RXPKT_CHK, -#endif /* PROP_TXSTATUS */ - IOV_BUS_TYPE, -#ifdef WLMEDIA_HTSF - IOV_WLPKTDLYSTAT_SZ, -#endif - IOV_CHANGEMTU, - IOV_HOSTREORDER_FLOWS, -#ifdef DHDTCPACK_SUPPRESS - IOV_TCPACK_SUPPRESS, -#endif /* DHDTCPACK_SUPPRESS */ -#ifdef DHD_WMF - IOV_WMF_BSS_ENAB, - IOV_WMF_UCAST_IGMP, - IOV_WMF_MCAST_DATA_SENDUP, -#ifdef WL_IGMP_UCQUERY - IOV_WMF_UCAST_IGMP_QUERY, -#endif /* WL_IGMP_UCQUERY */ -#ifdef DHD_UCAST_UPNP - IOV_WMF_UCAST_UPNP, -#endif /* DHD_UCAST_UPNP */ -#endif /* DHD_WMF */ - IOV_AP_ISOLATE, -#ifdef DHD_UNICAST_DHCP - IOV_DHCP_UNICAST, -#endif /* DHD_UNICAST_DHCP */ -#ifdef DHD_L2_FILTER - IOV_BLOCK_PING, -#endif - IOV_LMTEST, - IOV_LAST -}; - -const bcm_iovar_t dhd_iovars[] = { - {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, -#ifdef DHD_DEBUG - {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, -#endif /* DHD_DEBUG */ - {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, - {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, - {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, - {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, -#ifdef DHD_DEBUG - {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, - {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, -#endif - {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, - {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, - {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, -#ifdef PROP_TXSTATUS - {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_BOOL, 0 }, - /* - set the proptxtstatus operation mode: - 0 - Do not do any proptxtstatus flow control - 1 - Use implied credit from a packet status - 2 - Use explicit credit - */ - {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, - {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, IOVT_UINT32, 0 }, - {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, IOVT_BOOL, 0 }, - {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, IOVT_BOOL, 0 }, - {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, IOVT_BOOL, 0 }, - {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, IOVT_BOOL, 0 }, -#endif /* PROP_TXSTATUS */ - {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, -#ifdef WLMEDIA_HTSF - {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, -#endif - {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, - {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER, - (WLHOST_REORDERDATA_MAXFLOWS + 1) }, -#ifdef DHDTCPACK_SUPPRESS - {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, IOVT_UINT8, 0 }, -#endif /* DHDTCPACK_SUPPRESS */ -#ifdef DHD_WMF - {"wmf_bss_enable", IOV_WMF_BSS_ENAB, 0, IOVT_BOOL, 0 }, - {"wmf_ucast_igmp", IOV_WMF_UCAST_IGMP, 0, IOVT_BOOL, 0 }, - {"wmf_mcast_data_sendup", IOV_WMF_MCAST_DATA_SENDUP, 0, IOVT_BOOL, 0 }, -#ifdef WL_IGMP_UCQUERY - {"wmf_ucast_igmp_query", IOV_WMF_UCAST_IGMP_QUERY, (0), IOVT_BOOL, 0 }, -#endif /* WL_IGMP_UCQUERY */ -#ifdef DHD_UCAST_UPNP - {"wmf_ucast_upnp", IOV_WMF_UCAST_UPNP, (0), IOVT_BOOL, 0 }, -#endif /* DHD_UCAST_UPNP */ -#endif /* DHD_WMF */ -#ifdef DHD_UNICAST_DHCP - {"dhcp_unicast", IOV_DHCP_UNICAST, (0), IOVT_BOOL, 0 }, -#endif /* DHD_UNICAST_DHCP */ - {"ap_isolate", IOV_AP_ISOLATE, (0), IOVT_BOOL, 0}, -#ifdef DHD_L2_FILTER - {"block_ping", IOV_BLOCK_PING, (0), IOVT_BOOL, 0}, -#endif - {"lmtest", IOV_LMTEST, 0, IOVT_UINT32, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -#define DHD_IOVAR_BUF_SIZE 128 - -#ifdef DHD_FW_COREDUMP -void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length) -{ - if (!dhd_pub->soc_ram) { -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - dhd_pub->soc_ram = (uint8*)DHD_OS_PREALLOC(dhd_pub, - DHD_PREALLOC_MEMDUMP_RAM, length); -#else - dhd_pub->soc_ram = (uint8*) MALLOC(dhd_pub->osh, length); -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ - } - - if (dhd_pub->soc_ram == NULL) { - DHD_ERROR(("%s: Failed to allocate memory for fw crash snap shot.\n", - __FUNCTION__)); - dhd_pub->soc_ram_length = 0; - } else { - memset(dhd_pub->soc_ram, 0, length); - dhd_pub->soc_ram_length = length; - } - - /* soc_ram free handled in dhd_{free,clear} */ - return dhd_pub->soc_ram; -} -#endif /* DHD_FW_COREDUMP */ - -/* to NDIS developer, the structure dhd_common is redundant, - * please do NOT merge it back from other branches !!! - */ - -static int -dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) -{ - char eabuf[ETHER_ADDR_STR_LEN]; - - struct bcmstrbuf b; - struct bcmstrbuf *strbuf = &b; - - bcm_binit(strbuf, buf, buflen); - - /* Base DHD info */ - bcm_bprintf(strbuf, "%s\n", dhd_version); - bcm_bprintf(strbuf, "\n"); - bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", - dhdp->up, dhdp->txoff, dhdp->busstate); - bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n", - dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); - bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", - dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); - bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt); - - bcm_bprintf(strbuf, "dongle stats:\n"); - bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n", - dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, - dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); - bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n", - dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, - dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); - bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast); - - bcm_bprintf(strbuf, "bus stats:\n"); - bcm_bprintf(strbuf, "tx_packets %lu tx_dropped %lu tx_multicast %lu tx_errors %lu\n", - dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast, dhdp->tx_errors); - bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", - dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); - bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n", - dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); - bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n", - dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); - bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n", - dhdp->rx_readahead_cnt, dhdp->tx_realloc); - bcm_bprintf(strbuf, "\n"); - - /* Add any prot info */ - dhd_prot_dump(dhdp, strbuf); - bcm_bprintf(strbuf, "\n"); - - /* Add any bus info */ - dhd_bus_dump(dhdp, strbuf); - - - return (!strbuf->size ? BCME_BUFTOOSHORT : 0); -} - -int -dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifidx) -{ - wl_ioctl_t ioc; - - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; - ioc.set = set; - - return dhd_wl_ioctl(dhd_pub, ifidx, &ioc, arg, len); -} - -int -dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) -{ - int ret = BCME_ERROR; - - if (dhd_pub->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s Bus is down: %d(%s)\n", __FUNCTION__, ioc->cmd, (char*)(ioc->buf))); - return BCME_NOTUP; - } - - if (dhd_os_proto_block(dhd_pub)) - { -#if defined(WL_WLC_SHIM) - wl_info_t *wl = dhd_pub_wlinfo(dhd_pub); - - wl_io_pport_t io_pport; - io_pport.dhd_pub = dhd_pub; - io_pport.ifidx = ifidx; - - ret = wl_shim_ioctl(wl->shim, ioc, &io_pport); - if (ret != BCME_OK) { - DHD_ERROR(("%s: wl_shim_ioctl(%d) ERR %d\n", __FUNCTION__, ioc->cmd, ret)); - } -#else - ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len); -#endif /* defined(WL_WLC_SHIM) */ - - if (ret && dhd_pub->up) { - /* Send hang event only if dhd_open() was success */ - dhd_os_check_hang(dhd_pub, ifidx, ret); - } - - if (ret == -ETIMEDOUT && !dhd_pub->up) { - DHD_ERROR(("%s: 'resumed on timeout' error is " - "occurred before the interface does not" - " bring up\n", __FUNCTION__)); - dhd_pub->busstate = DHD_BUS_DOWN; - } - - dhd_os_proto_unblock(dhd_pub); - - } - - return ret; -} - -uint wl_get_port_num(wl_io_pport_t *io_pport) -{ - return 0; -} - -/* Get bssidx from iovar params - * Input: dhd_pub - pointer to dhd_pub_t - * params - IOVAR params - * Output: idx - BSS index - * val - ponter to the IOVAR arguments - */ -static int -dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, char *params, int *idx, char **val) -{ - char *prefix = "bsscfg:"; - uint32 bssidx; - - if (!(strncmp(params, prefix, strlen(prefix)))) { - /* per bss setting should be prefixed with 'bsscfg:' */ - char *p = (char *)params + strlen(prefix); - - /* Skip Name */ - while (*p != '\0') - p++; - /* consider null */ - p = p + 1; - bcopy(p, &bssidx, sizeof(uint32)); - /* Get corresponding dhd index */ - bssidx = dhd_bssidx2idx(dhd_pub, bssidx); - - if (bssidx >= DHD_MAX_IFS) { - DHD_ERROR(("%s Wrong bssidx provided\n", __FUNCTION__)); - return BCME_ERROR; - } - - /* skip bss idx */ - p += sizeof(uint32); - *val = p; - *idx = bssidx; - } else { - DHD_ERROR(("%s: bad parameter for per bss iovar\n", __FUNCTION__)); - return BCME_ERROR; - } - - return BCME_OK; -} - -static int -dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - switch (actionid) { - case IOV_GVAL(IOV_VERSION): - /* Need to have checked buffer length */ - bcm_strncpy_s((char*)arg, len, dhd_version, len); - break; - - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)dhd_msg_level; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): -#ifdef WL_CFG80211 - /* Enable DHD and WL logs in oneshot */ - if (int_val & DHD_WL_VAL2) - wl_cfg80211_enable_trace(TRUE, int_val & (~DHD_WL_VAL2)); - else if (int_val & DHD_WL_VAL) - wl_cfg80211_enable_trace(FALSE, WL_DBG_DBG); - if (!(int_val & DHD_WL_VAL2)) -#endif /* WL_CFG80211 */ - dhd_msg_level = int_val; - break; - case IOV_GVAL(IOV_BCMERRORSTR): - bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); - ((char *)arg)[BCME_STRLEN - 1] = 0x00; - break; - - case IOV_GVAL(IOV_BCMERROR): - int_val = (int32)dhd_pub->bcmerror; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_WDTICK): - int_val = (int32)dhd_watchdog_ms; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WDTICK): - if (!dhd_pub->up) { - bcmerror = BCME_NOTUP; - break; - } - dhd_os_wd_timer(dhd_pub, (uint)int_val); - break; - - case IOV_GVAL(IOV_DUMP): - bcmerror = dhd_dump(dhd_pub, arg, len); - break; - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_DCONSOLE_POLL): - int_val = (int32)dhd_console_ms; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DCONSOLE_POLL): - dhd_console_ms = (uint)int_val; - break; - - case IOV_SVAL(IOV_CONS): - if (len > 0) - bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); - break; -#endif /* DHD_DEBUG */ - - case IOV_SVAL(IOV_CLEARCOUNTS): - dhd_pub->tx_packets = dhd_pub->rx_packets = 0; - dhd_pub->tx_errors = dhd_pub->rx_errors = 0; - dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; - dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; - dhd_pub->tx_dropped = 0; - dhd_pub->rx_dropped = 0; - dhd_pub->rx_readahead_cnt = 0; - dhd_pub->tx_realloc = 0; - dhd_pub->wd_dpc_sched = 0; - memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); - dhd_bus_clearcounts(dhd_pub); -#ifdef PROP_TXSTATUS - /* clear proptxstatus related counters */ - dhd_wlfc_clear_counts(dhd_pub); -#endif /* PROP_TXSTATUS */ - break; - - - case IOV_GVAL(IOV_IOCTLTIMEOUT): { - int_val = (int32)dhd_os_get_ioctl_resp_timeout(); - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_IOCTLTIMEOUT): { - if (int_val <= 0) - bcmerror = BCME_BADARG; - else - dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); - break; - } - - -#ifdef PROP_TXSTATUS - case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): { - bool wlfc_enab = FALSE; - bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); - if (bcmerror != BCME_OK) - goto exit; - int_val = wlfc_enab ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): { - bool wlfc_enab = FALSE; - bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); - if (bcmerror != BCME_OK) - goto exit; - - /* wlfc is already set as desired */ - if (wlfc_enab == (int_val == 0 ? FALSE : TRUE)) - goto exit; - - if (int_val == TRUE) - bcmerror = dhd_wlfc_init(dhd_pub); - else - bcmerror = dhd_wlfc_deinit(dhd_pub); - - break; - } - case IOV_GVAL(IOV_PROPTXSTATUS_MODE): - bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_MODE): - dhd_wlfc_set_mode(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): - bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): - dhd_wlfc_set_module_ignore(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): - bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): - dhd_wlfc_set_credit_ignore(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): - bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): - dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK): - bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK): - dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val); - break; - -#endif /* PROP_TXSTATUS */ - - case IOV_GVAL(IOV_BUS_TYPE): - /* The dhd application queries the driver to check if its usb or sdio. */ -#ifdef BCMDHDUSB - int_val = BUS_TYPE_USB; -#endif -#ifdef BCMSDIO - int_val = BUS_TYPE_SDIO; -#endif -#ifdef PCIE_FULL_DONGLE - int_val = BUS_TYPE_PCIE; -#endif - bcopy(&int_val, arg, val_size); - break; - - -#ifdef WLMEDIA_HTSF - case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): - int_val = dhd_pub->htsfdlystat_sz; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): - dhd_pub->htsfdlystat_sz = int_val & 0xff; - printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); - break; -#endif - case IOV_SVAL(IOV_CHANGEMTU): - int_val &= 0xffff; - bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); - break; - - case IOV_GVAL(IOV_HOSTREORDER_FLOWS): - { - uint i = 0; - uint8 *ptr = (uint8 *)arg; - uint8 count = 0; - - ptr++; - for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { - if (dhd_pub->reorder_bufs[i] != NULL) { - *ptr = dhd_pub->reorder_bufs[i]->flow_id; - ptr++; - count++; - } - } - ptr = (uint8 *)arg; - *ptr = count; - break; - } -#ifdef DHDTCPACK_SUPPRESS - case IOV_GVAL(IOV_TCPACK_SUPPRESS): { - int_val = (uint32)dhd_pub->tcpack_sup_mode; - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_TCPACK_SUPPRESS): { - bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val); - break; - } -#endif /* DHDTCPACK_SUPPRESS */ -#ifdef DHD_WMF - case IOV_GVAL(IOV_WMF_BSS_ENAB): { - uint32 bssidx; - dhd_wmf_t *wmf; - char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - wmf = dhd_wmf_conf(dhd_pub, bssidx); - int_val = wmf->wmf_enable ? 1 :0; - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_WMF_BSS_ENAB): { - /* Enable/Disable WMF */ - uint32 bssidx; - dhd_wmf_t *wmf; - char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - ASSERT(val); - bcopy(val, &int_val, sizeof(uint32)); - wmf = dhd_wmf_conf(dhd_pub, bssidx); - if (wmf->wmf_enable == int_val) - break; - if (int_val) { - /* Enable WMF */ - if (dhd_wmf_instance_add(dhd_pub, bssidx) != BCME_OK) { - DHD_ERROR(("%s: Error in creating WMF instance\n", - __FUNCTION__)); - break; - } - if (dhd_wmf_start(dhd_pub, bssidx) != BCME_OK) { - DHD_ERROR(("%s: Failed to start WMF\n", __FUNCTION__)); - break; - } - wmf->wmf_enable = TRUE; - } else { - /* Disable WMF */ - wmf->wmf_enable = FALSE; - dhd_wmf_stop(dhd_pub, bssidx); - dhd_wmf_instance_del(dhd_pub, bssidx); - } - break; - } - case IOV_GVAL(IOV_WMF_UCAST_IGMP): - int_val = dhd_pub->wmf_ucast_igmp ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_WMF_UCAST_IGMP): - if (dhd_pub->wmf_ucast_igmp == int_val) - break; - - if (int_val >= OFF && int_val <= ON) - dhd_pub->wmf_ucast_igmp = int_val; - else - bcmerror = BCME_RANGE; - break; - case IOV_GVAL(IOV_WMF_MCAST_DATA_SENDUP): - int_val = dhd_wmf_mcast_data_sendup(dhd_pub, 0, FALSE, FALSE); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_WMF_MCAST_DATA_SENDUP): - dhd_wmf_mcast_data_sendup(dhd_pub, 0, TRUE, int_val); - break; - -#ifdef WL_IGMP_UCQUERY - case IOV_GVAL(IOV_WMF_UCAST_IGMP_QUERY): - int_val = dhd_pub->wmf_ucast_igmp_query ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_WMF_UCAST_IGMP_QUERY): - if (dhd_pub->wmf_ucast_igmp_query == int_val) - break; - - if (int_val >= OFF && int_val <= ON) - dhd_pub->wmf_ucast_igmp_query = int_val; - else - bcmerror = BCME_RANGE; - break; -#endif /* WL_IGMP_UCQUERY */ -#ifdef DHD_UCAST_UPNP - case IOV_GVAL(IOV_WMF_UCAST_UPNP): - int_val = dhd_pub->wmf_ucast_upnp ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_WMF_UCAST_UPNP): - if (dhd_pub->wmf_ucast_upnp == int_val) - break; - - if (int_val >= OFF && int_val <= ON) - dhd_pub->wmf_ucast_upnp = int_val; - else - bcmerror = BCME_RANGE; - break; -#endif /* DHD_UCAST_UPNP */ -#endif /* DHD_WMF */ - - -#ifdef DHD_UNICAST_DHCP - case IOV_GVAL(IOV_DHCP_UNICAST): - int_val = dhd_pub->dhcp_unicast; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_DHCP_UNICAST): - if (dhd_pub->dhcp_unicast == int_val) - break; - - if (int_val >= OFF || int_val <= ON) { - dhd_pub->dhcp_unicast = int_val; - } else { - bcmerror = BCME_RANGE; - } - break; -#endif /* DHD_UNICAST_DHCP */ -#ifdef DHD_L2_FILTER - case IOV_GVAL(IOV_BLOCK_PING): - int_val = dhd_pub->block_ping; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_BLOCK_PING): - if (dhd_pub->block_ping == int_val) - break; - if (int_val >= OFF || int_val <= ON) { - dhd_pub->block_ping = int_val; - } else { - bcmerror = BCME_RANGE; - } - break; -#endif - - case IOV_GVAL(IOV_AP_ISOLATE): { - uint32 bssidx; - char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - int_val = dhd_get_ap_isolate(dhd_pub, bssidx); - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_AP_ISOLATE): { - uint32 bssidx; - char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - ASSERT(val); - bcopy(val, &int_val, sizeof(uint32)); - dhd_set_ap_isolate(dhd_pub, bssidx, int_val); - break; - } - - case IOV_GVAL(IOV_LMTEST): { - *(uint32 *)arg = (uint32)lmtest; - break; - } - - case IOV_SVAL(IOV_LMTEST): { - uint32 val = *(uint32 *)arg; - if (val > 50) - bcmerror = BCME_BADARG; - else { - lmtest = (uint)val; - DHD_ERROR(("%s: lmtest %s\n", __FUNCTION__, - (lmtest == FALSE)? "OFF" : "ON")); - } - break; - } - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } - -exit: - DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); - return bcmerror; -} - -/* Store the status of a connection attempt for later retrieval by an iovar */ -void -dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) -{ - /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID - * because an encryption/rsn mismatch results in both events, and - * the important information is in the WLC_E_PRUNE. - */ - if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && - dhd_conn_event == WLC_E_PRUNE)) { - dhd_conn_event = event; - dhd_conn_status = status; - dhd_conn_reason = reason; - } -} - -bool -dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) -{ - void *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)) { - 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 = pktq_peek_tail(q, &eprec); - ASSERT(p); - if (eprec > prec || eprec < 0) - return FALSE; - } - - /* Evict if needed */ - if (eprec >= 0) { - /* Detect queueing to unconfigured precedence */ - ASSERT(!pktq_pempty(q, eprec)); - discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); - if (eprec == prec && !discard_oldest) - return FALSE; /* refuse newer (incoming) packet */ - /* Evict packet according to discard policy */ - p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); - ASSERT(p); -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - PKTFREE(dhdp->osh, p, TRUE); - } - - /* Enqueue */ - p = pktq_penq(q, prec, pkt); - ASSERT(p); - - return TRUE; -} - -/* - * Functions to drop proper pkts from queue: - * If one pkt in queue is non-fragmented, drop first non-fragmented pkt only - * If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts - * If can't find pkts matching upper 2 cases, drop first pkt anyway - */ -bool -dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn) -{ - struct pktq_prec *q = NULL; - void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL; - pkt_frag_t frag_info; - - ASSERT(dhdp && pq); - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - p = q->head; - - if (p == NULL) - return FALSE; - - while (p) { - frag_info = pkt_frag_info(dhdp->osh, p); - if (frag_info == DHD_PKT_FRAG_NONE) { - break; - } else if (frag_info == DHD_PKT_FRAG_FIRST) { - if (first) { - /* No last frag pkt, use prev as last */ - last = prev; - break; - } else { - first = p; - prev_first = prev; - } - } else if (frag_info == DHD_PKT_FRAG_LAST) { - if (first) { - last = p; - break; - } - } - - prev = p; - p = PKTLINK(p); - } - - if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) { - /* Not found matching pkts, use oldest */ - prev = NULL; - p = q->head; - frag_info = 0; - } - - if (frag_info == DHD_PKT_FRAG_NONE) { - first = last = p; - prev_first = prev; - } - - p = first; - while (p) { - next = PKTLINK(p); - q->len--; - pq->len--; - - PKTSETLINK(p, NULL); - - if (fn) - fn(dhdp, prec, p, TRUE); - - if (p == last) - break; - - p = next; - } - - if (prev_first == NULL) { - if ((q->head = next) == NULL) - q->tail = NULL; - } else { - PKTSETLINK(prev_first, next); - if (!next) - q->tail = prev_first; - } - - return TRUE; -} - -static int -dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - int bcmerror = 0; - int val_size; - const bcm_iovar_t *vi = NULL; - uint32 actionid; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - - bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} - -int -dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) -{ - int bcmerror = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!buf) { - return BCME_BADARG; - } - - switch (ioc->cmd) { - case DHD_GET_MAGIC: - if (buflen < sizeof(int)) - bcmerror = BCME_BUFTOOSHORT; - else - *(int*)buf = DHD_IOCTL_MAGIC; - break; - - case DHD_GET_VERSION: - if (buflen < sizeof(int)) - bcmerror = BCME_BUFTOOSHORT; - else - *(int*)buf = DHD_IOCTL_VERSION; - break; - - case DHD_GET_VAR: - case DHD_SET_VAR: { - char *arg; - uint arglen; - - /* scan past the name to any arguments */ - for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) - ; - - if (*arg) { - bcmerror = BCME_BUFTOOSHORT; - break; - } - - /* account for the NUL terminator */ - arg++, arglen--; - - /* call with the appropriate arguments */ - if (ioc->cmd == DHD_GET_VAR) - bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, - buf, buflen, IOV_GET); - else - bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); - if (bcmerror != BCME_UNSUPPORTED) - break; - - /* not in generic table, try protocol module */ - if (ioc->cmd == DHD_GET_VAR) - bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, - arglen, buf, buflen, IOV_GET); - else - bcmerror = dhd_prot_iovar_op(dhd_pub, buf, - NULL, 0, arg, arglen, IOV_SET); - if (bcmerror != BCME_UNSUPPORTED) - break; - - /* if still not found, try bus module */ - if (ioc->cmd == DHD_GET_VAR) { - bcmerror = dhd_bus_iovar_op(dhd_pub, buf, - arg, arglen, buf, buflen, IOV_GET); - } else { - bcmerror = dhd_bus_iovar_op(dhd_pub, buf, - NULL, 0, arg, arglen, IOV_SET); - } - - break; - } - - default: - bcmerror = BCME_UNSUPPORTED; - } - - return bcmerror; -} - -#ifdef SHOW_EVENTS -#ifdef SHOW_LOGTRACE - -#define AVOID_BYTE 64 -#define MAX_NO_OF_ARG 16 - -static int -check_event_log_sequence_number(uint32 seq_no) -{ - int32 diff; - uint32 ret; - static uint32 logtrace_seqnum_prev = 0; - - diff = ntoh32(seq_no)-logtrace_seqnum_prev; - switch (diff) - { - case 0: - ret = -1; /* duplicate packet . drop */ - break; - - case 1: - ret =0; /* in order */ - break; - - default: - if ((ntoh32(seq_no) == 0) && - (logtrace_seqnum_prev == 0xFFFFFFFF) ) { /* in-order - Roll over */ - ret = 0; - } else { - - if (diff > 0) { - DHD_EVENT(("WLC_E_TRACE:" - "Event lost (log) seqnum %d nblost %d\n", - ntoh32(seq_no), (diff-1))); - } else { - DHD_EVENT(("WLC_E_TRACE:" - "Event Packets coming out of order!!\n")); - } - ret = 0; - } - } - - logtrace_seqnum_prev = ntoh32(seq_no); - - return ret; -} -#endif /* SHOW_LOGTRACE */ - -static void -wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, - void *raw_event_ptr, char *eventmask) -{ - uint i, status, reason; - bool group = FALSE, flush_txq = FALSE, link = FALSE; - const char *auth_str; - const char *event_name; - uchar *buf; - char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; - uint event_type, flags, auth_type, datalen; - - event_type = ntoh32(event->event_type); - flags = ntoh16(event->flags); - status = ntoh32(event->status); - reason = ntoh32(event->reason); - BCM_REFERENCE(reason); - auth_type = ntoh32(event->auth_type); - datalen = ntoh32(event->datalen); - - /* debug dump of event messages */ - snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", - (uchar)event->addr.octet[0]&0xff, - (uchar)event->addr.octet[1]&0xff, - (uchar)event->addr.octet[2]&0xff, - (uchar)event->addr.octet[3]&0xff, - (uchar)event->addr.octet[4]&0xff, - (uchar)event->addr.octet[5]&0xff); - - event_name = bcmevent_get_name(event_type); - BCM_REFERENCE(event_name); - - if (flags & WLC_EVENT_MSG_LINK) - link = TRUE; - if (flags & WLC_EVENT_MSG_GROUP) - group = TRUE; - if (flags & WLC_EVENT_MSG_FLUSHTXQ) - flush_txq = TRUE; - - switch (event_type) { - case WLC_E_START: - case WLC_E_DEAUTH: - case WLC_E_DISASSOC: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - - case WLC_E_ASSOC_IND: - case WLC_E_REASSOC_IND: - - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - - case WLC_E_ASSOC: - case WLC_E_REASSOC: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", - event_name, eabuf, (int)reason)); - } else { - DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n", - event_name, eabuf, (int)status)); - } - break; - - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC_IND: - DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); - break; - - case WLC_E_AUTH: - case WLC_E_AUTH_IND: - if (auth_type == DOT11_OPEN_SYSTEM) - auth_str = "Open System"; - else if (auth_type == DOT11_SHARED_KEY) - auth_str = "Shared Key"; - else { - snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); - auth_str = err_msg; - } - if (event_type == WLC_E_AUTH_IND) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", - event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", - event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", - event_name, eabuf, auth_str, (int)reason)); - } - BCM_REFERENCE(auth_str); - - break; - - case WLC_E_JOIN: - case WLC_E_ROAM: - case WLC_E_SET_SSID: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, failed\n", event_name)); - } else if (status == WLC_E_STATUS_NO_NETWORKS) { - DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name)); - } else { - DHD_EVENT(("MACEVENT: %s, unexpected status %d\n", - event_name, (int)status)); - } - break; - - case WLC_E_BEACON_RX: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); - } else { - DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); - } - break; - - case WLC_E_LINK: - DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); - BCM_REFERENCE(link); - break; - - case WLC_E_MIC_ERROR: - DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", - event_name, eabuf, group, flush_txq)); - BCM_REFERENCE(group); - BCM_REFERENCE(flush_txq); - break; - - case WLC_E_ICV_ERROR: - case WLC_E_UNICAST_DECODE_ERROR: - case WLC_E_MULTICAST_DECODE_ERROR: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", - event_name, eabuf)); - break; - - case WLC_E_TXFAIL: - case WLC_E_AIBSS_TXFAIL: - DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf)); - break; - - case WLC_E_SCAN_COMPLETE: - case WLC_E_ASSOC_REQ_IE: - case WLC_E_ASSOC_RESP_IE: - case WLC_E_PMKID_CACHE: - DHD_EVENT(("MACEVENT: %s\n", event_name)); - break; - - case WLC_E_PFN_NET_FOUND: - case WLC_E_PFN_NET_LOST: - case WLC_E_PFN_SCAN_COMPLETE: - case WLC_E_PFN_SCAN_NONE: - case WLC_E_PFN_SCAN_ALLGONE: - DHD_EVENT(("PNOEVENT: %s\n", event_name)); - break; - - case WLC_E_PSK_SUP: - case WLC_E_PRUNE: - DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason)); - break; - -#ifdef WIFI_ACT_FRAME - case WLC_E_ACTION_FRAME: - DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); - break; -#endif /* WIFI_ACT_FRAME */ - -#ifdef SHOW_LOGTRACE - case WLC_E_TRACE: - { - msgtrace_hdr_t hdr; - uint32 nblost; - uint8 count; - char *s, *p; - static uint32 seqnum_prev = 0; - uint32 *record = NULL; - uint32 *log_ptr = NULL; - uint32 writeindex = 0; - event_log_hdr_t event_hdr; - int no_of_fmts = 0; - char *fmt = NULL; - dhd_event_log_t *raw_event = (dhd_event_log_t *) raw_event_ptr; - - buf = (uchar *) event_data; - memcpy(&hdr, buf, MSGTRACE_HDRLEN); - - if (hdr.version != MSGTRACE_VERSION) { - DHD_EVENT(("\nMACEVENT: %s [unsupported version --> " - "dhd version:%d dongle version:%d]\n", - event_name, MSGTRACE_VERSION, hdr.version)); - /* Reset datalen to avoid display below */ - datalen = 0; - break; - } - - if (hdr.trace_type == MSGTRACE_HDR_TYPE_MSG) { - /* There are 2 bytes available at the end of data */ - buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; - - if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { - DHD_EVENT(("WLC_E_TRACE: [Discarded traces in dongle -->" - "discarded_bytes %d discarded_printf %d]\n", - ntoh32(hdr.discarded_bytes), - ntoh32(hdr.discarded_printf))); - } - - nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; - if (nblost > 0) { - DHD_EVENT(("WLC_E_TRACE:" - "[Event lost (msg) --> seqnum %d nblost %d\n", - ntoh32(hdr.seqnum), nblost)); - } - seqnum_prev = ntoh32(hdr.seqnum); - - /* Display the trace buffer. Advance from - * \n to \n to avoid display big - * printf (issue with Linux printk ) - */ - p = (char *)&buf[MSGTRACE_HDRLEN]; - while (*p != '\0' && (s = strstr(p, "\n")) != NULL) { - *s = '\0'; - DHD_EVENT(("%s\n", p)); - p = s+1; - } - if (*p) - DHD_EVENT(("%s", p)); - - /* Reset datalen to avoid display below */ - datalen = 0; - - } else if (hdr.trace_type == MSGTRACE_HDR_TYPE_LOG) { - /* Let the standard event printing work for now */ - uint32 timestamp, w, malloc_len; - - if (check_event_log_sequence_number(hdr.seqnum)) { - - DHD_EVENT(("%s: WLC_E_TRACE:" - "[Event duplicate (log) %d] dropping!!\n", - __FUNCTION__, hdr.seqnum)); - return; /* drop duplicate events */ - } - - p = (char *)&buf[MSGTRACE_HDRLEN]; - datalen -= MSGTRACE_HDRLEN; - w = ntoh32((uint32)*p); - p += 4; - datalen -= 4; - timestamp = ntoh32((uint32)*p); - BCM_REFERENCE(timestamp); - BCM_REFERENCE(w); - - DHD_EVENT(("timestamp %x%x\n", timestamp, w)); - - if (raw_event->fmts) { - malloc_len = datalen+ AVOID_BYTE; - record = (uint32 *)MALLOC(dhd_pub->osh, malloc_len); - if (record == NULL) { - DHD_EVENT(("MSGTRACE_HDR_TYPE_LOG:" - "malloc failed\n")); - return; - } - log_ptr = (uint32 *) (p + datalen); - writeindex = datalen/4; - - if (record) { - while (datalen > 4) { - log_ptr--; - datalen -= 4; - event_hdr.t = *log_ptr; - /* - * Check for partially overriten entries - */ - if (log_ptr - (uint32 *) p < event_hdr.count) { - break; - } - /* - * Check for end of the Frame. - */ - if (event_hdr.tag == EVENT_LOG_TAG_NULL) { - continue; - } - /* - * Check For Special Time Stamp Packet - */ - if (event_hdr.tag == EVENT_LOG_TAG_TS) { - datalen -= 12; - log_ptr = log_ptr - 3; - continue; - } - - log_ptr[0] = event_hdr.t; - if (event_hdr.count > MAX_NO_OF_ARG) { - break; - } - /* Now place the header at the front - * and copy back. - */ - log_ptr -= event_hdr.count; - - writeindex = writeindex - event_hdr.count; - record[writeindex++] = event_hdr.t; - for (count = 0; count < (event_hdr.count-1); - count++) { - record[writeindex++] = log_ptr[count]; - } - writeindex = writeindex - event_hdr.count; - datalen = datalen - (event_hdr.count * 4); - no_of_fmts++; - } - } - - while (no_of_fmts--) - { - event_log_hdr_t event_hdr; - event_hdr.t = record[writeindex]; - - if ((event_hdr.fmt_num>>2) < raw_event->num_fmts) { - fmt = raw_event->fmts[event_hdr.fmt_num>>2]; - DHD_EVENT((fmt, - record[writeindex + 1], - record[writeindex + 2], - record[writeindex + 3], - record[writeindex + 4], - record[writeindex + 5], - record[writeindex + 6], - record[writeindex + 7], - record[writeindex + 8], - record[writeindex + 9], - record[writeindex + 10], - record[writeindex + 11], - record[writeindex + 12], - record[writeindex + 13], - record[writeindex + 14], - record[writeindex + 15], - record[writeindex + 16])); - - if (fmt[strlen(fmt) - 1] != '\n') { - /* Add newline if missing */ - DHD_EVENT(("\n")); - } - } - - writeindex = writeindex + event_hdr.count; - } - - if (record) { - MFREE(dhd_pub->osh, record, malloc_len); - record = NULL; - } - } else { - while (datalen > 4) { - p += 4; - datalen -= 4; - /* Print each word. DO NOT ntoh it. */ - DHD_EVENT((" %8.8x", *((uint32 *) p))); - } - DHD_EVENT(("\n")); - } - datalen = 0; - } - break; - } -#endif /* SHOW_LOGTRACE */ - - case WLC_E_RSSI: - DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); - break; - - case WLC_E_SERVICE_FOUND: - case WLC_E_P2PO_ADD_DEVICE: - case WLC_E_P2PO_DEL_DEVICE: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - -#ifdef BT_WIFI_HANDOBER - case WLC_E_BT_WIFI_HANDOVER_REQ: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; -#endif - - default: - DHD_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 (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen) { - buf = (uchar *) event_data; - BCM_REFERENCE(buf); - DHD_EVENT((" data (%d) : ", datalen)); - for (i = 0; i < datalen; i++) - DHD_EVENT((" 0x%02x ", *buf++)); - DHD_EVENT(("\n")); - } -} -#endif /* SHOW_EVENTS */ - -/* Check whether packet is a BRCM event pkt. If it is, record event data. */ -int -wl_host_event_get_data(void *pktdata, uint pktlen, void *evt) -{ - int ret; - - ret = is_wlc_event_frame(pktdata, pktlen, 0, evt); - if (ret != BCME_OK && ret != -30) { - DHD_ERROR(("%s: Invalid event frame, err = %d\n", - __FUNCTION__, ret)); - } - - return ret; -} - -int -wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, size_t pktlen, - wl_event_msg_t *event, void **data_ptr, void *raw_event) -{ - bcm_event_t *pvt_data = (bcm_event_t *)pktdata; - uint8 *event_data; - uint32 type, status, datalen; - uint16 flags; - uint evlen; - int hostidx; - int ret; - uint16 usr_subtype; - wl_event_msg_t evtmsg; - - ret = wl_host_event_get_data(pktdata, pktlen, &evtmsg); - if (ret != BCME_OK) { - return ret; - } - - usr_subtype = ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype); - switch (usr_subtype) { - case BCMILCP_BCM_SUBTYPE_EVENT: - memcpy(event, &evtmsg, sizeof(wl_event_msg_t)); - *data_ptr = &pvt_data[1]; - break; - default: - return BCME_NOTFOUND; - } - - /* start wl_event_msg process */ - event_data = *data_ptr; - - type = ntoh32_ua((void *)&event->event_type); - flags = ntoh16_ua((void *)&event->flags); - status = ntoh32_ua((void *)&event->status); - datalen = ntoh32_ua((void *)&event->datalen); - - evlen = datalen + sizeof(bcm_event_t); - - /* find equivalent host index for event ifidx */ - hostidx = dhd_ifidx2hostidx(dhd_pub->info, event->ifidx); - - switch (type) { -#ifdef PROP_TXSTATUS - case WLC_E_FIFO_CREDIT_MAP: - dhd_wlfc_enable(dhd_pub); - dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data); - WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " - "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], - event_data[2], - event_data[3], event_data[4], event_data[5])); - break; - - case WLC_E_BCMC_CREDIT_SUPPORT: - dhd_wlfc_BCMCCredit_support_event(dhd_pub); - break; -#endif - - case WLC_E_IF: - { - struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data; - - /* Ignore the event if NOIF is set */ - if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) { - DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n")); - return (BCME_UNSUPPORTED); - } -#ifdef PCIE_FULL_DONGLE - dhd_update_interface_flow_info(dhd_pub, ifevent->ifidx, - ifevent->opcode, ifevent->role); -#endif -#ifdef PROP_TXSTATUS - { - uint8* ea = pvt_data->eth.ether_dhost; - WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " - "[%02x:%02x:%02x:%02x:%02x:%02x]\n", - ifevent->ifidx, - ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD":"DEL"), - ((ifevent->role == 0) ? "STA":"AP "), - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); - (void)ea; - - if (ifevent->opcode == WLC_E_IF_CHANGE) - dhd_wlfc_interface_event(dhd_pub, - eWLFC_MAC_ENTRY_ACTION_UPDATE, - ifevent->ifidx, ifevent->role, ea); - else - dhd_wlfc_interface_event(dhd_pub, - ((ifevent->opcode == WLC_E_IF_ADD) ? - eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), - ifevent->ifidx, ifevent->role, ea); - - /* dhd already has created an interface by default, for 0 */ - if (ifevent->ifidx == 0) - break; - } -#endif /* PROP_TXSTATUS */ - - if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { - if (ifevent->opcode == WLC_E_IF_ADD) { - if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname, - event->addr.octet)) { - - DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d %s\n", - __FUNCTION__, ifevent->ifidx, event->ifname)); - return (BCME_ERROR); - } - } else if (ifevent->opcode == WLC_E_IF_DEL) { - dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname, - event->addr.octet); - } else if (ifevent->opcode == WLC_E_IF_CHANGE) { -#ifdef WL_CFG80211 - wl_cfg80211_notify_ifchange(ifevent->ifidx, - event->ifname, event->addr.octet, ifevent->bssidx); -#endif /* WL_CFG80211 */ - } - } else { -#if !defined(PROP_TXSTATUS) || !defined(PCIE_FULL_DONGLE) - DHD_ERROR(("%s: Invalid ifidx %d for %s\n", - __FUNCTION__, ifevent->ifidx, event->ifname)); -#endif /* !PROP_TXSTATUS */ - } - /* send up the if event: btamp user needs it */ - *ifidx = hostidx; - /* push up to external supp/auth */ - dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); - break; - } - -#ifdef WLMEDIA_HTSF - case WLC_E_HTSFSYNC: - htsf_update(dhd_pub->info, event_data); - break; -#endif /* WLMEDIA_HTSF */ - case WLC_E_PFN_NET_FOUND: - case WLC_E_PFN_NET_LOST: - break; -#if defined(PNO_SUPPORT) - case WLC_E_PFN_BSSID_NET_FOUND: - case WLC_E_PFN_BSSID_NET_LOST: - case WLC_E_PFN_BEST_BATCHING: - dhd_pno_event_handler(dhd_pub, event, (void *)event_data); - break; -#endif -#if defined(RTT_SUPPORT) - case WLC_E_PROXD: - dhd_rtt_event_handler(dhd_pub, event, (void *)event_data); - break; -#endif /* RTT_SUPPORT */ - /* These are what external supplicant/authenticator wants */ - case WLC_E_ASSOC_IND: - case WLC_E_AUTH_IND: - case WLC_E_REASSOC_IND: - dhd_findadd_sta(dhd_pub, hostidx, &event->addr.octet); - break; - case WLC_E_LINK: -#ifdef PCIE_FULL_DONGLE - if (dhd_update_interface_link_status(dhd_pub, (uint8)hostidx, - (uint8)flags) != BCME_OK) - break; - if (!flags) { - dhd_flow_rings_delete(dhd_pub, hostidx); - } - /* fall through */ -#endif - case WLC_E_DEAUTH: - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC: - case WLC_E_DISASSOC_IND: - if (type != WLC_E_LINK) { - dhd_del_sta(dhd_pub, hostidx, &event->addr.octet); - } - DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); -#ifdef PCIE_FULL_DONGLE - if (type != WLC_E_LINK) { - uint8 ifindex = (uint8)hostidx; - uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex); - if (DHD_IF_ROLE_STA(role)) { - dhd_flow_rings_delete(dhd_pub, ifindex); - } else { - dhd_flow_rings_delete_for_peer(dhd_pub, ifindex, - &event->addr.octet[0]); - } - } -#endif - /* fall through */ - default: - *ifidx = hostidx; - /* push up to external supp/auth */ - dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); - DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); - BCM_REFERENCE(flags); - BCM_REFERENCE(status); - - break; - } - -#ifdef SHOW_EVENTS - wl_show_host_event(dhd_pub, event, - (void *)event_data, raw_event, dhd_pub->enable_log); -#endif /* SHOW_EVENTS */ - - return (BCME_OK); -} - -void -wl_event_to_host_order(wl_event_msg_t * evt) -{ - /* Event struct members passed from dongle to host are stored in network - * byte order. Convert all members to host-order. - */ - evt->event_type = ntoh32(evt->event_type); - evt->flags = ntoh16(evt->flags); - evt->status = ntoh32(evt->status); - evt->reason = ntoh32(evt->reason); - evt->auth_type = ntoh32(evt->auth_type); - evt->datalen = ntoh32(evt->datalen); - evt->version = ntoh16(evt->version); -} - -void -dhd_print_buf(void *pbuf, int len, int bytes_per_line) -{ -#ifdef DHD_DEBUG - int i, j = 0; - unsigned char *buf = pbuf; - - if (bytes_per_line == 0) { - bytes_per_line = len; - } - - for (i = 0; i < len; i++) { - printf("%2.2x", *buf++); - j++; - if (j == bytes_per_line) { - printf("\n"); - j = 0; - } else { - printf(":"); - } - } - printf("\n"); -#endif /* DHD_DEBUG */ -} -#ifndef strtoul -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -#endif - -#ifdef PKT_FILTER_SUPPORT -/* Convert user's input in hex pattern to byte-size mask */ -static int -wl_pattern_atoh(char *src, char *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && - strncmp(src, "0X", 2) != 0) { - DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); - return -1; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); - return -1; - } - for (i = 0; *src != '\0'; i++) { - char num[3]; - bcm_strncpy_s(num, sizeof(num), src, 2); - num[2] = '\0'; - dst[i] = (uint8)strtoul(num, NULL, 16); - src += 2; - } - return i; -} - -void -dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) -{ - char *argv[8]; - int i = 0; - const char *str; - int buf_len; - int str_len; - char *arg_save = 0, *arg_org = 0; - int rc; - char buf[32] = {0}; - wl_pkt_filter_enable_t enable_parm; - wl_pkt_filter_enable_t * pkt_filterp; - - if (!arg) - return; - - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { - DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); - goto fail; - } - arg_org = arg_save; - memcpy(arg_save, arg, strlen(arg) + 1); - - argv[i] = bcmstrtok(&arg_save, " ", 0); - - i = 0; - if (argv[i] == NULL) { - DHD_ERROR(("No args provided\n")); - goto fail; - } - - str = "pkt_filter_enable"; - str_len = strlen(str); - bcm_strncpy_s(buf, sizeof(buf) - 1, str, sizeof(buf) - 1); - buf[ sizeof(buf) - 1 ] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); - - /* Parse packet filter id. */ - enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); - - /* Parse enable/disable value. */ - enable_parm.enable = htod32(enable); - - buf_len += sizeof(enable_parm); - memcpy((char *)pkt_filterp, - &enable_parm, - sizeof(enable_parm)); - - /* Enable/disable the specified filter. */ - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - rc = rc >= 0 ? 0 : rc; - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); - else - DHD_TRACE(("%s: successfully added pktfilter %s\n", - __FUNCTION__, arg)); - - /* Contorl the master mode */ - bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf)); - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - rc = rc >= 0 ? 0 : rc; - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); - -fail: - if (arg_org) - MFREE(dhd->osh, arg_org, strlen(arg) + 1); -} - -void -dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) -{ - const char *str; - wl_pkt_filter_t pkt_filter; - wl_pkt_filter_t *pkt_filterp; - int buf_len; - int str_len; - int rc; - uint32 mask_size; - uint32 pattern_size; - char *argv[8], * buf = 0; - int i = 0; - char *arg_save = 0, *arg_org = 0; -#define BUF_SIZE 2048 - - if (!arg) - return; - - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { - DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); - goto fail; - } - - arg_org = arg_save; - - if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { - DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); - goto fail; - } - - memcpy(arg_save, arg, strlen(arg) + 1); - - if (strlen(arg) > BUF_SIZE) { - DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); - goto fail; - } - - argv[i] = bcmstrtok(&arg_save, " ", 0); - while (argv[i++]) - argv[i] = bcmstrtok(&arg_save, " ", 0); - - i = 0; - if (argv[i] == NULL) { - DHD_ERROR(("No args provided\n")); - goto fail; - } - - str = "pkt_filter_add"; - str_len = strlen(str); - bcm_strncpy_s(buf, BUF_SIZE, str, str_len); - buf[ str_len ] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); - - /* Parse packet filter id. */ - pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Polarity not provided\n")); - goto fail; - } - - /* Parse filter polarity. */ - pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Filter type not provided\n")); - goto fail; - } - - /* Parse filter type. */ - pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Offset not provided\n")); - goto fail; - } - - /* Parse pattern filter offset. */ - pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Bitmask not provided\n")); - goto fail; - } - - /* Parse pattern filter mask. */ - mask_size = - htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Pattern not provided\n")); - goto fail; - } - - /* Parse pattern filter pattern. */ - pattern_size = - htod32(wl_pattern_atoh(argv[i], - (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); - - if (mask_size != pattern_size) { - DHD_ERROR(("Mask and pattern not the same size\n")); - goto fail; - } - - pkt_filter.u.pattern.size_bytes = mask_size; - buf_len += WL_PKT_FILTER_FIXED_LEN; - buf_len += (WL_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, - WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); - - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - rc = rc >= 0 ? 0 : rc; - - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); - else - DHD_TRACE(("%s: successfully added pktfilter %s\n", - __FUNCTION__, arg)); - -fail: - if (arg_org) - MFREE(dhd->osh, arg_org, strlen(arg) + 1); - - if (buf) - MFREE(dhd->osh, buf, BUF_SIZE); -} - -void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id) -{ - char iovbuf[32]; - int ret; - - bcm_mkiovar("pkt_filter_delete", (char *)&id, 4, iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n", - __FUNCTION__, id, ret)); - } -} -#endif /* PKT_FILTER_SUPPORT */ - -/* ========================== */ -/* ==== ARP OFFLOAD SUPPORT = */ -/* ========================== */ -#ifdef ARP_OFFLOAD_SUPPORT -void -dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) -{ - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int iovar_len; - int retcode; - - iovar_len = bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); - if (!iovar_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0); - retcode = retcode >= 0 ? 0 : retcode; - if (retcode) - DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", - __FUNCTION__, arp_mode, retcode)); - else - DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", - __FUNCTION__, arp_mode)); -} - -void -dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) -{ - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int iovar_len; - int retcode; - - iovar_len = bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); - if (!iovar_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0); - retcode = retcode >= 0 ? 0 : retcode; - if (retcode) - DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n", - __FUNCTION__, arp_enable, retcode)); - else - DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", - __FUNCTION__, arp_enable)); - if (arp_enable) { - uint32 version; - bcm_mkiovar("arp_version", 0, 0, iovbuf, sizeof(iovbuf)); - retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); - if (retcode) { - DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n", - __FUNCTION__, retcode)); - dhd->arp_version = 1; - } - else { - memcpy(&version, iovbuf, sizeof(version)); - DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version)); - dhd->arp_version = version; - } - } -} - -void -dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) -{ - int ret = 0; - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; - - if (dhd == NULL) return; - if (dhd->arp_version == 1) - idx = 0; - - iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -} - -void -dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) -{ - int ret = 0; - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; - - if (dhd == NULL) return; - if (dhd->arp_version == 1) - idx = 0; - - iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -} - -void -dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) -{ - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int retcode; - - - if (dhd == NULL) return; - if (dhd->arp_version == 1) - idx = 0; - iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, - sizeof(ipaddr), iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); - - if (retcode) - DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n", - __FUNCTION__, retcode)); - else - DHD_TRACE(("%s: sARP H ipaddr entry added \n", - __FUNCTION__)); -} - -int -dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) -{ - int retcode, i; - int iov_len; - uint32 *ptr32 = buf; - bool clr_bottom = FALSE; - - if (!buf) - return -1; - if (dhd == NULL) return -1; - if (dhd->arp_version == 1) - idx = 0; - - iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); - BCM_REFERENCE(iov_len); - retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx); - - if (retcode) { - DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", - __FUNCTION__, retcode)); - - return -1; - } - - /* clean up the buf, ascii reminder */ - for (i = 0; i < MAX_IPV4_ENTRIES; i++) { - if (!clr_bottom) { - if (*ptr32 == 0) - clr_bottom = TRUE; - } else { - *ptr32 = 0; - } - ptr32++; - } - - return 0; -} -#endif /* ARP_OFFLOAD_SUPPORT */ - -/* - * Neighbor Discovery Offload: enable NDO feature - * Called by ipv6 event handler when interface comes up/goes down - */ -int -dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable) -{ - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int iov_len; - int retcode; - - if (dhd == NULL) - return -1; - - iov_len = bcm_mkiovar("ndoe", (char *)&ndo_enable, 4, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return -1; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0); - if (retcode) - DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n", - __FUNCTION__, ndo_enable, retcode)); - else - DHD_TRACE(("%s: successfully enabed ndo offload to %d\n", - __FUNCTION__, ndo_enable)); - - return retcode; -} - -/* - * Neighbor Discover Offload: enable NDO feature - * Called by ipv6 event handler when interface comes up - */ -int -dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx) -{ - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int retcode; - - if (dhd == NULL) - return -1; - - iov_len = bcm_mkiovar("nd_hostip", (char *)ipv6addr, - IPV6_ADDR_LEN, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return -1; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); - - if (retcode) - DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n", - __FUNCTION__, retcode)); - else - DHD_TRACE(("%s: ndo ipaddr entry added \n", - __FUNCTION__)); - - return retcode; -} -/* - * Neighbor Discover Offload: enable NDO feature - * Called by ipv6 event handler when interface goes down - */ -int -dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx) -{ - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int retcode; - - if (dhd == NULL) - return -1; - - iov_len = bcm_mkiovar("nd_hostip_clear", NULL, - 0, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return -1; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); - - if (retcode) - DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n", - __FUNCTION__, retcode)); - else - DHD_TRACE(("%s: ndo ipaddr entry removed \n", - __FUNCTION__)); - - return retcode; -} - -/* send up locally generated event */ -void -dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) -{ - switch (ntoh32(event->event_type)) { - default: - break; - } - - /* Call per-port handler. */ - dhd_sendup_event(dhdp, event, data); -} - - -/* - * returns = TRUE if associated, FALSE if not associated - */ -bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) -{ - char bssid[6], zbuf[6]; - int ret = -1; - - bzero(bssid, 6); - bzero(zbuf, 6); - - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0); - DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); - - if (ret == BCME_NOTASSOCIATED) { - DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); - } - - if (retval) - *retval = ret; - - if (ret < 0) - return FALSE; - - if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { - /* STA is assocoated BSSID is non zero */ - - if (bss_buf) { - /* return bss if caller provided buf */ - memcpy(bss_buf, bssid, ETHER_ADDR_LEN); - } - return TRUE; - } else { - DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); - return FALSE; - } -} - -/* Function to estimate possible DTIM_SKIP value */ -int -dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) -{ - int bcn_li_dtim = 1; /* deafult no dtim skip setting */ - int ret = -1; - int dtim_period = 0; - int ap_beacon = 0; - int allowed_skip_dtim_cnt = 0; - /* Check if associated */ - if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { - DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* read associated AP beacon interval */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, - &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) { - DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* read associated ap's dtim setup */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, - &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) { - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* if not assocated just eixt */ - if (dtim_period == 0) { - goto exit; - } - - /* attemp to use platform defined dtim skip interval */ - bcn_li_dtim = dhd->suspend_bcn_li_dtim; - - /* check if sta listen interval fits into AP dtim */ - if (dtim_period > CUSTOM_LISTEN_INTERVAL) { - /* AP DTIM to big for our Listen Interval : no dtim skiping */ - bcn_li_dtim = NO_DTIM_SKIP; - DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", - __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL)); - goto exit; - } - - if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { - allowed_skip_dtim_cnt = MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon); - bcn_li_dtim = (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; - } - - if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) { - /* Round up dtim_skip to fit into STAs Listen Interval */ - bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period); - DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); - } - - DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", - __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL)); - -exit: - return bcn_li_dtim; -} - -/* Check if the mode supports STA MODE */ -bool dhd_support_sta_mode(dhd_pub_t *dhd) -{ - -#ifdef WL_CFG80211 - if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) - return FALSE; - else -#endif /* WL_CFG80211 */ - return TRUE; -} - -#if defined(KEEP_ALIVE) -int dhd_keep_alive_onoff(dhd_pub_t *dhd) -{ - char buf[32] = {0}; - const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0}; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = -1; - - if (!dhd_support_sta_mode(dhd)) - return res; - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(buf, str, sizeof(buf) - 1); - buf[ sizeof(buf) - 1 ] = '\0'; - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); - mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING; - buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - /* Setup keep alive zero for null packet generation */ - mkeep_alive_pkt.keep_alive_id = 0; - mkeep_alive_pkt.len_bytes = 0; - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); - /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - - return res; -} -#endif /* defined(KEEP_ALIVE) */ -/* Android ComboSCAN support */ - -/* - * data parsing from ComboScan tlv list -*/ -int -wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, - int input_size, int *bytes_left) -{ - char* str; - uint16 short_temp; - uint32 int_temp; - - if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - str = *list_str; - - /* Clean all dest bytes */ - memset(dst, 0, dst_size); - while (*bytes_left > 0) { - - if (str[0] != token) { - DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", - __FUNCTION__, token, str[0], *bytes_left)); - return -1; - } - - *bytes_left -= 1; - str += 1; - - if (input_size == 1) { - memcpy(dst, str, input_size); - } - else if (input_size == 2) { - memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), - input_size); - } - else if (input_size == 4) { - memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), - input_size); - } - - *bytes_left -= input_size; - str += input_size; - *list_str = str; - return 1; - } - return 1; -} - -#define CSCAN_TLV_TYPE_SSID_IE 'S' - -/* - * SSIDs list parsing from cscan tlv list - */ -int -wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left) -{ - char* str; - int idx = 0; - - if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - str = *list_str; - while (*bytes_left > 0) { - - if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { - *list_str = str; - DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); - return idx; - } - - /* Get proper CSCAN_TLV_TYPE_SSID_IE */ - *bytes_left -= 1; - str += 1; - ssid[idx].rssi_thresh = 0; - if (str[0] == 0) { - /* Broadcast SSID */ - ssid[idx].SSID_len = 0; - memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); - *bytes_left -= 1; - str += 1; - - DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); - } - else if (str[0] <= DOT11_MAX_SSID_LEN) { - /* Get proper SSID size */ - ssid[idx].SSID_len = str[0]; - *bytes_left -= 1; - str += 1; - - /* Get SSID */ - if (ssid[idx].SSID_len > *bytes_left) { - DHD_ERROR(("%s out of memory range len=%d but left=%d\n", - __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); - return -1; - } - - memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); - - *bytes_left -= ssid[idx].SSID_len; - str += ssid[idx].SSID_len; - ssid[idx].hidden = TRUE; - - DHD_TRACE(("%s :size=%d left=%d\n", - (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); - } - else { - DHD_ERROR(("### SSID size more that %d\n", str[0])); - return -1; - } - - if (idx++ > max) { - DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); - return -1; - } - } - - *list_str = str; - return idx; -} diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c deleted file mode 100644 index f1482f89f343..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c +++ /dev/null @@ -1,594 +0,0 @@ -/* -* Customer code to add GPIO control during WLAN start/stop -* Copyright (C) 1999-2017, Broadcom Corporation -* Copyright (C) 2013 Sony Mobile Communications Inc. -* -* Unless you and Broadcom execute a separate written software license -* agreement governing use of this software, this software is licensed to you -* under the terms of the GNU General Public License version 2 (the "GPL"), -* available at http://www.broadcom.com/licenses/GPLv2.php, with the -* following added to such license: -* -* As a special exception, the copyright holders of this software give you -* permission to link this software with independent modules, and to copy and -* distribute the resulting executable under terms of your choice, provided that -* you also meet, for each linked independent module, the terms and conditions of -* the license of that module. An independent module is a module which is not -* derived from this software. The special exception does not apply to any -* modifications of the software. -* -* Notwithstanding the above, under no circumstances may you combine this -* software in any way with any other Broadcom software provided under a license -* other than the GPL, without Broadcom's express prior written consent. -* -* $Id: dhd_custom_gpio.c 595011 2015-10-26 05:41:56Z $ -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define WL_ERROR(x) printf x -#define WL_TRACE(x) - -#if defined(CUSTOMER_HW2) - - -#endif - -#ifdef GET_CUSTOM_MAC_ENABLE -#define MACADDR_BUF_LEN 64 -#define MACADDR_PATH "/data/etc/wlan_macaddr0" -#endif /* GET_CUSTOM_MAC_ENABLE */ - -#if defined(OOB_INTR_ONLY) - -#if defined(BCMLXSDMMC) -extern int sdioh_mmc_irq(int irq); -#endif /* (BCMLXSDMMC) */ - -#if defined(CUSTOMER_HW3) -#include -#endif - -/* Customer specific Host GPIO defintion */ -static int dhd_oob_gpio_num = -1; - -module_param(dhd_oob_gpio_num, int, 0644); -MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); - -/* This function will return: - * 1) return : Host gpio interrupt number per customer platform - * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge - * - * NOTE : - * Customer should check his platform definitions - * and his Host Interrupt spec - * to figure out the proper setting for his platform. - * Broadcom provides just reference settings as example. - * - */ -int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr) -{ - int host_oob_irq = 0; - -#if defined(CUSTOMER_HW2) - host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr); - -#else -#if defined(CUSTOM_OOB_GPIO_NUM) - if (dhd_oob_gpio_num < 0) { - dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; - } -#endif /* CUSTOMER_OOB_GPIO_NUM */ - - if (dhd_oob_gpio_num < 0) { - WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", - __FUNCTION__)); - return (dhd_oob_gpio_num); - } - - WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", - __FUNCTION__, dhd_oob_gpio_num)); - -#if defined CUSTOMER_HW3 - gpio_request(dhd_oob_gpio_num, "oob irq"); - host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); - gpio_direction_input(dhd_oob_gpio_num); -#endif -#endif - - return (host_oob_irq); -} -#endif - -/* Customer function to control hw specific wlan gpios */ -int -dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff) -{ - int err = 0; - - return err; -} - -#ifdef GET_CUSTOM_MAC_ENABLE -int somc_get_mac_address(unsigned char *buf) -{ - int ret = -EINVAL; - int len; - unsigned char macaddr_buf[MACADDR_BUF_LEN]; - void *fp = NULL; - struct ether_addr eth; - - if (!buf) - return -EINVAL; - - fp = dhd_os_open_image(MACADDR_PATH); - if (!fp) { - WL_ERROR(("%s: file open error\n", __FUNCTION__)); - goto err; - } - - len = dhd_os_get_image_block(macaddr_buf, MACADDR_BUF_LEN, fp); - if (len <= 0 || MACADDR_BUF_LEN <= len) { - WL_ERROR(("%s: file read error\n", __FUNCTION__)); - goto err; - } - macaddr_buf[len] = '\0'; - - /* convert mac address */ - ret = !bcm_ether_atoe(macaddr_buf, ð); - if (ret) { - WL_ERROR(("%s: convert mac value fail\n", __FUNCTION__)); - goto err; - } - - memcpy(buf, eth.octet, ETHER_ADDR_LEN); -err: - if (fp) - dhd_os_close_image(fp); - return ret; -} - -/* Function to get custom MAC address */ -int -dhd_custom_get_mac_address(void *adapter, unsigned char *buf) -{ - int ret = 0; - - WL_TRACE(("%s Enter\n", __FUNCTION__)); - if (!buf) - return -EINVAL; - - /* Customer access to MAC address stored outside of DHD driver */ -#if defined(CUSTOMER_HW2) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) - ret = wifi_platform_get_mac_addr(adapter, buf); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) */ -#endif - -#ifdef EXAMPLE_GET_MAC - /* EXAMPLE code */ - { - struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; - bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); - } -#endif /* EXAMPLE_GET_MAC */ - - return ret; -} -#endif /* GET_CUSTOM_MAC_ENABLE */ - -struct cntry_locales_custom { - char iso_abbrev[WLC_CNTRY_BUF_SZ]; - char custom_locale[WLC_CNTRY_BUF_SZ]; - int32 custom_locale_rev; -}; - -/* Customized Locale table : OPTIONAL feature */ -const struct cntry_locales_custom translate_custom_table[] = { -/* Table should be filled out based on custom platform regulatory requirement */ -#ifdef EXAMPLE_TABLE - {"", "XY", 4}, /* Universal if Country code is unknown or empty */ - {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ - {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ - {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ - {"AT", "EU", 5}, - {"BE", "EU", 5}, - {"BG", "EU", 5}, - {"CY", "EU", 5}, - {"CZ", "EU", 5}, - {"DK", "EU", 5}, - {"EE", "EU", 5}, - {"FI", "EU", 5}, - {"FR", "EU", 5}, - {"DE", "EU", 5}, - {"GR", "EU", 5}, - {"HU", "EU", 5}, - {"IE", "EU", 5}, - {"IT", "EU", 5}, - {"LV", "EU", 5}, - {"LI", "EU", 5}, - {"LT", "EU", 5}, - {"LU", "EU", 5}, - {"MT", "EU", 5}, - {"NL", "EU", 5}, - {"PL", "EU", 5}, - {"PT", "EU", 5}, - {"RO", "EU", 5}, - {"SK", "EU", 5}, - {"SI", "EU", 5}, - {"ES", "EU", 5}, - {"SE", "EU", 5}, - {"GB", "EU", 5}, - {"KR", "XY", 3}, - {"AU", "XY", 3}, - {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ - {"TW", "XY", 3}, - {"AR", "XY", 3}, - {"MX", "XY", 3}, - {"IL", "IL", 0}, - {"CH", "CH", 0}, - {"TR", "TR", 0}, - {"NO", "NO", 0}, -#endif /* EXMAPLE_TABLE */ -#if defined(CUSTOMER_HW2) && !defined(CUSTOMER_HW5) -#if defined(BCM4335_CHIP) - {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ -#endif - {"AE", "AE", 1}, - {"AR", "AR", 1}, - {"AT", "AT", 1}, - {"AU", "AU", 2}, - {"BE", "BE", 1}, - {"BG", "BG", 1}, - {"BN", "BN", 1}, - {"CA", "CA", 2}, - {"CH", "CH", 1}, - {"CY", "CY", 1}, - {"CZ", "CZ", 1}, - {"DE", "DE", 3}, - {"DK", "DK", 1}, - {"EE", "EE", 1}, - {"ES", "ES", 1}, - {"FI", "FI", 1}, - {"FR", "FR", 1}, - {"GB", "GB", 1}, - {"GR", "GR", 1}, - {"HR", "HR", 1}, - {"HU", "HU", 1}, - {"IE", "IE", 1}, - {"IS", "IS", 1}, - {"IT", "IT", 1}, - {"ID", "ID", 1}, - {"JP", "JP", 8}, - {"KR", "KR", 24}, - {"KW", "KW", 1}, - {"LI", "LI", 1}, - {"LT", "LT", 1}, - {"LU", "LU", 1}, - {"LV", "LV", 1}, - {"MA", "MA", 1}, - {"MT", "MT", 1}, - {"MX", "MX", 1}, - {"NL", "NL", 1}, - {"NO", "NO", 1}, - {"PL", "PL", 1}, - {"PT", "PT", 1}, - {"PY", "PY", 1}, - {"RO", "RO", 1}, - {"SE", "SE", 1}, - {"SI", "SI", 1}, - {"SK", "SK", 1}, - {"TR", "TR", 7}, - {"TW", "TW", 1}, - {"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ - {"SD", "XZ", 11}, /* Universal if Country code is SUDAN */ - {"SY", "XZ", 11}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ - {"GL", "XZ", 11}, /* Universal if Country code is GREENLAND */ - {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ - {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ - {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ -#ifdef BCM4330_CHIP - {"RU", "RU", 1}, - {"US", "US", 5} -#endif - -#elif defined(CUSTOMER_HW5) - /* default ccode/regrev */ - {"", "XT", 54}, /* Universal if Country code is unknown or empty */ - {"IR", "XT", 54}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ - {"SD", "XT", 54}, /* Universal if Country code is SUDAN */ - {"SY", "XT", 54}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ - {"GL", "E0", 979}, /* Universal if Country code is GREENLAND */ - {"PS", "XT", 54}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ - {"TL", "XT", 54}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ - {"MH", "XT", 54}, /* Universal if Country code is MARSHALL ISLANDS */ - {"CK", "XT", 54}, /* Universal if Country code is Cook Islands */ - {"CU", "XT", 54}, /* Universal if Country code is Cuba */ - {"FO", "XT", 54}, /* Universal if Country code is Faroe Islands */ - {"GI", "XT", 54}, /* Universal if Country code is Gibraltar */ - {"KP", "XT", 54}, /* Universal if Country code is North Korea */ - {"NE", "XT", 54}, /* Universal if Country code is Niger (Republic of the) */ - {"PM", "XT", 54}, /* Universal if Country code is Saint Pierre and Miquelon */ - {"WF", "XT", 54}, /* Universal if Country code is Wallis and Futuna */ - - {"XA", "XX", 4}, /* Default country code for INDONESIA */ - {"XC", "XT", 998}, /* Default country code for RUSSIA */ - - {"AD", "AD", 0}, - {"AE", "AE", 212}, - {"AF", "AF", 0}, - {"AG", "XT", 54}, - {"AI", "AI", 2}, - {"AL", "AL", 2}, - {"AM", "AM", 0}, - {"AN", "AN", 3}, - {"AO", "AO", 0}, - {"AR", "AR", 212}, - {"AS", "AS", 15}, - {"AT", "E0", 979}, - {"AU", "AU", 212}, - {"AW", "XT", 54}, - {"AZ", "XT", 54}, - {"BA", "BA", 2}, - {"BB", "BB", 0}, - {"BD", "XT", 54}, - {"BE", "E0", 979}, - {"BF", "XT", 54}, - {"BG", "E0", 979}, - {"BH", "BH", 4}, - {"BI", "BI", 0}, - {"BJ", "BJ", 0}, - {"BM", "BM", 15}, - {"BN", "BN", 4}, - {"BO", "XT", 54}, - {"BR", "BR", 212}, - {"BS", "XT", 54}, - {"BT", "XT", 54}, - {"BW", "BW", 1}, - {"BY", "XT", 54}, - {"BZ", "XT", 54}, - {"CA", "CA", 212}, - {"CD", "CD", 0}, - {"CF", "CF", 0}, - {"CG", "CG", 0}, - {"CH", "E0", 979}, - {"CI", "CI", 0}, - {"CL", "CL", 212}, - {"CM", "CM", 0}, - {"CN", "CN", 212}, - {"CO", "CO", 212}, - {"CR", "CR", 21}, - {"CV", "CV", 0}, - {"CX", "CX", 1}, - {"CY", "E0", 979}, - {"CZ", "E0", 979}, - {"DE", "E0", 979}, - {"DJ", "DJ", 0}, - {"DK", "E0", 979}, - {"DM", "XT", 54}, - {"DO", "XT", 54}, - {"DZ", "DZ", 1}, - {"EC", "EC", 23}, - {"EE", "E0", 979}, - {"EG", "EG", 212}, - {"ER", "ER", 0}, - {"ES", "E0", 979}, - {"ET", "ET", 2}, - {"FI", "E0", 979}, - {"FJ", "XT", 54}, - {"FK", "FK", 0}, - {"FM", "XT", 54}, - {"FR", "E0", 979}, - {"GA", "GA", 0}, - {"GB", "E0", 979}, - {"GD", "XT", 54}, - {"GE", "GE", 0}, - {"GF", "GF", 2}, - {"GH", "GH", 0}, - {"GM", "GM", 0}, - {"GN", "GN", 0}, - {"GP", "GP", 2}, - {"GQ", "GQ", 0}, - {"GR", "E0", 979}, - {"GT", "XT", 54}, - {"GU", "GU", 17}, - {"GW", "GW", 0}, - {"GY", "GY", 0}, - {"HK", "HK", 212}, - {"HN", "HN", 0}, - {"HR", "E0", 979}, - {"HT", "HT", 0}, - {"HU", "E0", 979}, - {"ID", "ID", 212}, - {"IE", "E0", 979}, - {"IL", "IL", 7}, - {"IN", "IN", 212}, - {"IQ", "IQ", 0}, - {"IS", "E0", 979}, - {"IT", "E0", 979}, - {"JM", "JM", 0}, - {"JO", "JO", 3}, - {"JP", "JP", 212}, - {"KE", "KE", 0}, - {"KG", "KG", 0}, - {"KH", "KH", 4}, - {"KI", "KI", 1}, - {"KM", "KM", 0}, - {"KN", "XT", 54}, - {"KR", "KR", 212}, - {"KW", "KW", 5}, - {"KY", "KY", 4}, - {"KZ", "KZ", 212}, - {"LA", "LA", 4}, - {"LB", "LB", 6}, - {"LC", "XT", 54}, - {"LI", "E0", 979}, - {"LK", "XT", 54}, - {"LR", "LR", 2}, - {"LS", "LS", 2}, - {"LT", "E0", 979}, - {"LU", "E0", 979}, - {"LV", "E0", 979}, - {"LY", "LY", 0}, - {"MA", "MA", 2}, - {"MC", "E0", 979}, - {"MD", "MD", 2}, - {"ME", "ME", 2}, - {"MF", "XT", 54}, - {"MG", "MG", 0}, - {"MK", "E0", 979}, - {"ML", "ML", 0}, - {"MM", "MM", 0}, - {"MN", "XT", 54}, - {"MO", "MO", 2}, - {"MP", "XT", 54}, - {"MQ", "MQ", 2}, - {"MR", "MR", 2}, - {"MS", "MS", 0}, - {"MT", "E0", 979}, - {"MU", "MU", 2}, - {"MV", "MV", 3}, - {"MW", "XT", 54}, - {"MX", "MX", 212}, - {"MY", "MY", 998}, - {"MZ", "XT", 54}, - {"NA", "XT", 54}, - {"NC", "NC", 0}, - {"NG", "NG", 0}, - {"NI", "NI", 0}, - {"NL", "E0", 979}, - {"NO", "E0", 979}, - {"NP", "NP", 3}, - {"NR", "NR", 0}, - {"NZ", "NZ", 9}, - {"OM", "OM", 4}, - {"PA", "PA", 17}, - {"PE", "PE", 212}, - {"PF", "PF", 0}, - {"PG", "PG", 2}, - {"PH", "PH", 212}, - {"PK", "PK", 0}, - {"PL", "E0", 979}, - {"PR", "PR", 25}, - {"PT", "E0", 979}, - {"PW", "XT", 54}, - {"PY", "PY", 4}, - {"QA", "QA", 0}, - {"RE", "RE", 2}, - {"RO", "E0", 979}, - {"RS", "RS", 2}, - {"RU", "RU", 212}, - {"RW", "XT", 54}, - {"SA", "SA", 212}, - {"SB", "SB", 0}, - {"SC", "XT", 54}, - {"SE", "E0", 979}, - {"SG", "SG", 212}, - {"SI", "E0", 979}, - {"SK", "E0", 979}, - {"SL", "SL", 0}, - {"SM", "SM", 0}, - {"SN", "SN", 2}, - {"SO", "SO", 0}, - {"SR", "SR", 0}, - {"ST", "ST", 0}, - {"SV", "XT", 54}, - {"SZ", "SZ", 0}, - {"TC", "TC", 0}, - {"TD", "TD", 0}, - {"TF", "TF", 0}, - {"TG", "TG", 0}, - {"TH", "TH", 212}, - {"TJ", "TJ", 0}, - {"TM", "TM", 0}, - {"TN", "TN", 0}, - {"TO", "TO", 0}, - {"TR", "E0", 979}, - {"TT", "TT", 5}, - {"TV", "TV", 0}, - {"TW", "TW", 996}, - {"TZ", "XT", 54}, - {"UA", "UA", 212}, - {"UG", "XT", 54}, - {"US", "US", 996}, - {"UY", "UY", 5}, - {"UZ", "XT", 54}, - {"VA", "VA", 2}, - {"VC", "XT", 54}, - {"VE", "VE", 3}, - {"VG", "XT", 54}, - {"VI", "VI", 18}, - {"VN", "XT", 54}, - {"VU", "XT", 54}, - {"WS", "XT", 54}, - {"YE", "XT", 54}, - {"YT", "YT", 2}, - {"ZA", "ZA", 212}, - {"ZM", "ZM", 2}, - {"ZW", "XT", 54}, -#endif /* CUSTOMER_HW2 and CUSTOMER_HW5 */ -}; - - -/* Customized Locale convertor -* input : ISO 3166-1 country abbreviation -* output: customized cspec -*/ -#ifdef CUSTOM_FORCE_NODFS_FLAG -void get_customized_country_code(void *adapter, char *country_iso_code, - wl_country_t *cspec, u32 flags) -#else -void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec) -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -{ -#if 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))) - - struct cntry_locales_custom *cloc_ptr; - - if (!cspec) - return; - -#ifdef CUSTOM_FORCE_NODFS_FLAG - cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code, - flags); -#else - cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - if (cloc_ptr) { - strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = cloc_ptr->custom_locale_rev; - } - return; -#else - int size, i; - - size = ARRAYSIZE(translate_custom_table); - - if (cspec == 0) - return; - - if (size == 0) - return; - - for (i = 0; i < size; i++) { - if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { - memcpy(cspec->ccode, - translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[i].custom_locale_rev; - return; - } - } - /* if no country code matched return first universal code from translate_custom_table */ - memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[0].custom_locale_rev; - return; -#endif /* 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))) */ -} diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c b/drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c deleted file mode 100644 index e164beec85aa..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Platform Dependent file for usage of Preallocted Memory - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_custom_memprealloc.c 536912 2015-02-24 16:09:31Z $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - -#define WLAN_STATIC_SCAN_BUF0 5 -#define WLAN_STATIC_SCAN_BUF1 6 -#define WLAN_STATIC_DHD_INFO_BUF 7 -#define WLAN_STATIC_DHD_WLFC_BUF 8 -#define WLAN_STATIC_DHD_IF_FLOW_LKUP 9 -#define WLAN_STATIC_DHD_MEMDUMP_RAM 11 -#define WLAN_STATIC_DHD_PKTID_MAP 12 - -#define WLAN_SCAN_BUF_SIZE (64 * 1024) - -#if defined(CONFIG_64BIT) -#define WLAN_DHD_INFO_BUF_SIZE (24 * 1024) -#define WLAN_DHD_WLFC_BUF_SIZE (64 * 1024) -#define WLAN_DHD_IF_FLOW_LKUP_SIZE (64 * 1024) -#else -#define WLAN_DHD_INFO_BUF_SIZE (16 * 1024) -#define WLAN_DHD_WLFC_BUF_SIZE (16 * 1024) -#define WLAN_DHD_IF_FLOW_LKUP_SIZE (20 * 1024) -#endif /* CONFIG_64BIT */ -#define WLAN_DHD_MEMDUMP_SIZE (800 * 1024) - -#define PREALLOC_WLAN_SEC_NUM 4 -#define PREALLOC_WLAN_BUF_NUM 160 -#define PREALLOC_WLAN_SECTION_HEADER 24 - -#ifdef CONFIG_BCMDHD_PCIE -#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1) -#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2) -#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4) - -#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) -#define WLAN_SECTION_SIZE_1 0 -#define WLAN_SECTION_SIZE_2 0 -#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) - -#define DHD_SKB_1PAGE_BUF_NUM 0 -#define DHD_SKB_2PAGE_BUF_NUM 64 -#define DHD_SKB_4PAGE_BUF_NUM 0 - -#else -#define DHD_SKB_HDRSIZE 336 -#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) -#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) -#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) - -#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) -#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128) -#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512) -#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) - -#define DHD_SKB_1PAGE_BUF_NUM 8 -#define DHD_SKB_2PAGE_BUF_NUM 8 -#define DHD_SKB_4PAGE_BUF_NUM 1 -#endif /* CONFIG_BCMDHD_PCIE */ - -#define WLAN_SKB_1_2PAGE_BUF_NUM ((DHD_SKB_1PAGE_BUF_NUM) + \ - (DHD_SKB_2PAGE_BUF_NUM)) -#define WLAN_SKB_BUF_NUM ((WLAN_SKB_1_2PAGE_BUF_NUM) + \ - (DHD_SKB_4PAGE_BUF_NUM)) - -#define DHD_PKTIDMAP_FIFO_MAX 4 -#define WLAN_MAX_PKTID_ITEMS (8192) -#if defined(CONFIG_64BIT) -#define WLAN_DHD_PKTID_MAP_HDR_SIZE (64) -#define WLAN_DHD_PKTID_MAP_ITEM_SIZE (48) -#else -#define WLAN_DHD_PKTID_MAP_HDR_SIZE (36) -#define WLAN_DHD_PKTID_MAP_ITEM_SIZE (28) -#endif /* CONFIG_64BIT */ -#define WLAN_DHD_PKTID_MAP_SIZE ((WLAN_DHD_PKTID_MAP_HDR_SIZE) + \ - (DHD_PKTIDMAP_FIFO_MAX * (WLAN_MAX_PKTID_ITEMS+1) * WLAN_DHD_PKTID_MAP_ITEM_SIZE)) - - -static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM]; - -struct wlan_mem_prealloc { - void *mem_ptr; - unsigned long size; -}; - -static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = { - {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)}, - {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)}, - {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)}, - {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)} -}; - -void *wlan_static_scan_buf0 = NULL; -void *wlan_static_scan_buf1 = NULL; -void *wlan_static_dhd_info_buf = NULL; -void *wlan_static_dhd_wlfc_buf = NULL; -void *wlan_static_if_flow_lkup = NULL; -void *wlan_static_dhd_memdump_ram = NULL; -void *wlan_static_dhd_pktid_map = NULL; - -static void -*dhd_wlan_mem_prealloc(int section, unsigned long size) -{ - if (section == PREALLOC_WLAN_SEC_NUM) { - return wlan_static_skb; - } - - if (section == WLAN_STATIC_SCAN_BUF0) { - return wlan_static_scan_buf0; - } - - if (section == WLAN_STATIC_SCAN_BUF1) { - return wlan_static_scan_buf1; - } - - if (section == WLAN_STATIC_DHD_INFO_BUF) { - if (size > WLAN_DHD_INFO_BUF_SIZE) { - pr_err("request DHD_INFO size(%lu) is bigger than" - " static size(%d).\n", size, - WLAN_DHD_INFO_BUF_SIZE); - return NULL; - } - return wlan_static_dhd_info_buf; - } - - if (section == WLAN_STATIC_DHD_WLFC_BUF) { - if (size > WLAN_DHD_WLFC_BUF_SIZE) { - pr_err("request DHD_WLFC size(%lu) is bigger than" - " static size(%d).\n", - size, WLAN_DHD_WLFC_BUF_SIZE); - return NULL; - } - return wlan_static_dhd_wlfc_buf; - } - - if (section == WLAN_STATIC_DHD_IF_FLOW_LKUP) { - if (size > WLAN_DHD_IF_FLOW_LKUP_SIZE) { - pr_err("request DHD_WLFC size(%lu) is bigger than" - " static size(%d).\n", - size, WLAN_DHD_WLFC_BUF_SIZE); - return NULL; - } - return wlan_static_if_flow_lkup; - } - - if (section == WLAN_STATIC_DHD_MEMDUMP_RAM) { - if (size > WLAN_DHD_MEMDUMP_SIZE) { - pr_err("request DHD_MEMDUMP_RAM size(%lu) is bigger" - " than static size(%d).\n", - size, WLAN_DHD_MEMDUMP_SIZE); - return NULL; - } - return wlan_static_dhd_memdump_ram; - } - - if (section == WLAN_STATIC_DHD_PKTID_MAP) { - if (size > WLAN_DHD_PKTID_MAP_SIZE) { - pr_err("request DHD_PKTID_MAP size(%lu) is bigger than" - " static size(%d).\n", - size, WLAN_DHD_PKTID_MAP_SIZE); - return NULL; - } - return wlan_static_dhd_pktid_map; - } - - if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM)) { - return NULL; - } - - if (wlan_mem_array[section].size < size) { - return NULL; - } - - return wlan_mem_array[section].mem_ptr; -} -EXPORT_SYMBOL(dhd_wlan_mem_prealloc); - -static int -dhd_init_wlan_mem(void) -{ - int i; - int j; - - for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) { - wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE); - if (!wlan_static_skb[i]) { - goto err_skb_alloc; - } - } - - for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) { - wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE); - if (!wlan_static_skb[i]) { - goto err_skb_alloc; - } - } - -#if !defined(CONFIG_BCMDHD_PCIE) - wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE); - if (!wlan_static_skb[i]) { - goto err_skb_alloc; - } -#endif /* !CONFIG_BCMDHD_PCIE */ - - for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) { - if (wlan_mem_array[i].size > 0) { - wlan_mem_array[i].mem_ptr = - kmalloc(wlan_mem_array[i].size, GFP_KERNEL); - - if (!wlan_mem_array[i].mem_ptr) { - goto err_mem_alloc; - } - } - } - - wlan_static_scan_buf0 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); - if (!wlan_static_scan_buf0) { - pr_err("Failed to alloc wlan_static_scan_buf0\n"); - goto err_mem_alloc; - } - - wlan_static_scan_buf1 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); - if (!wlan_static_scan_buf1) { - pr_err("Failed to alloc wlan_static_scan_buf1\n"); - goto err_mem_alloc; - } - - wlan_static_dhd_info_buf = kmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL); - if (!wlan_static_dhd_info_buf) { - pr_err("Failed to alloc wlan_static_dhd_info_buf\n"); - goto err_mem_alloc; - } - -#ifdef CONFIG_BCMDHD_PCIE - wlan_static_if_flow_lkup = kmalloc(WLAN_DHD_IF_FLOW_LKUP_SIZE, - GFP_KERNEL); - if (!wlan_static_if_flow_lkup) { - pr_err("Failed to alloc wlan_static_if_flow_lkup\n"); - goto err_mem_alloc; - } - -#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP - wlan_static_dhd_pktid_map = kmalloc(WLAN_DHD_PKTID_MAP_SIZE, - GFP_KERNEL); - if (!wlan_static_dhd_pktid_map) { - pr_err("Failed to alloc wlan_static_dhd_pktid_map\n"); - goto err_mem_alloc; - } - -#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */ -#else - wlan_static_dhd_wlfc_buf = kmalloc(WLAN_DHD_WLFC_BUF_SIZE, - GFP_KERNEL); - if (!wlan_static_dhd_wlfc_buf) { - pr_err("Failed to alloc wlan_static_dhd_wlfc_buf\n"); - goto err_mem_alloc; - } -#endif /* CONFIG_BCMDHD_PCIE */ - -#ifdef CONFIG_BCMDHD_DEBUG_PAGEALLOC - wlan_static_dhd_memdump_ram = kmalloc(WLAN_DHD_MEMDUMP_SIZE, GFP_KERNEL); - if (!wlan_static_dhd_memdump_ram) { - pr_err("Failed to alloc wlan_static_dhd_memdump_ram\n"); - goto err_mem_alloc; - } -#endif /* CONFIG_BCMDHD_DEBUG_PAGEALLOC */ - - pr_err("%s: WIFI MEM Allocated\n", __FUNCTION__); - return 0; - -err_mem_alloc: -#ifdef CONFIG_BCMDHD_DEBUG_PAGEALLOC - if (wlan_static_dhd_memdump_ram) { - kfree(wlan_static_dhd_memdump_ram); - } - -#endif /* CONFIG_BCMDHD_DEBUG_PAGEALLOC */ - -#ifdef CONFIG_BCMDHD_PCIE - if (wlan_static_if_flow_lkup) { - kfree(wlan_static_if_flow_lkup); - } - -#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP - if (wlan_static_dhd_pktid_map) { - kfree(wlan_static_dhd_pktid_map); - } - -#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */ -#else - if (wlan_static_dhd_wlfc_buf) { - kfree(wlan_static_dhd_wlfc_buf); - } -#endif /* CONFIG_BCMDHD_PCIE */ - if (wlan_static_dhd_info_buf) { - kfree(wlan_static_dhd_info_buf); - } - - if (wlan_static_scan_buf1) { - kfree(wlan_static_scan_buf1); - } - - if (wlan_static_scan_buf0) { - kfree(wlan_static_scan_buf0); - } - - pr_err("Failed to mem_alloc for WLAN\n"); - - for (j = 0; j < i; j++) { - kfree(wlan_mem_array[j].mem_ptr); - } - - i = WLAN_SKB_BUF_NUM; - -err_skb_alloc: - pr_err("Failed to skb_alloc for WLAN\n"); - for (j = 0; j < i; j++) { - dev_kfree_skb(wlan_static_skb[j]); - } - - return -ENOMEM; -} -EXPORT_SYMBOL(dhd_init_wlan_mem); -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ diff --git a/drivers/net/wireless/bcmdhd/dhd_dbg.h b/drivers/net/wireless/bcmdhd/dhd_dbg.h deleted file mode 100644 index 1784e44df708..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_dbg.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Debug/trace/assert driver definitions for Dongle Host Driver. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_dbg.h 518127 2014-11-28 08:44:47Z $ - */ - -#ifndef _dhd_dbg_ -#define _dhd_dbg_ - -#define USE_NET_RATELIMIT 1 - -#if defined(DHD_DEBUG) - -#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && USE_NET_RATELIMIT) \ - printf args;} while (0) -#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) -#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) -#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) -#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0) -#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0) -#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0) -#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0) -#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0) -#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) -#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) -#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0) -#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) -#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) -#define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) -#define DHD_PNO(args) do {if (dhd_msg_level & DHD_PNO_VAL) printf args;} while (0) -#define DHD_RTT(args) do {if (dhd_msg_level & DHD_RTT_VAL) printf args;} while (0) - -#define DHD_TRACE_HW4 DHD_TRACE -#define DHD_INFO_HW4 DHD_INFO - -#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) -#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) -#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) -#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL) -#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL) -#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL) -#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL) -#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL) -#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL) -#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) -#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) -#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) -#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) -#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL) -#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL) -#define DHD_NOCHECKDIED_ON() (dhd_msg_level & DHD_NOCHECKDIED_VAL) -#define DHD_PNO_ON() (dhd_msg_level & DHD_PNO_VAL) -#define DHD_RTT_ON() (dhd_msg_level & DHD_RTT_VAL) - -#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ - -#define DHD_ERROR(args) do {if (USE_NET_RATELIMIT) printf args;} while (0) -#define DHD_TRACE(args) -#define DHD_INFO(args) -#define DHD_DATA(args) -#define DHD_CTL(args) -#define DHD_TIMER(args) -#define DHD_HDRS(args) -#define DHD_BYTES(args) -#define DHD_INTR(args) -#define DHD_GLOM(args) -#define DHD_EVENT(args) -#define DHD_BTA(args) -#define DHD_ISCAN(args) -#define DHD_ARPOE(args) -#define DHD_REORDER(args) -#define DHD_PNO(args) - -#define DHD_TRACE_HW4 DHD_TRACE -#define DHD_INFO_HW4 DHD_INFO - -#define DHD_ERROR_ON() 0 -#define DHD_TRACE_ON() 0 -#define DHD_INFO_ON() 0 -#define DHD_DATA_ON() 0 -#define DHD_CTL_ON() 0 -#define DHD_TIMER_ON() 0 -#define DHD_HDRS_ON() 0 -#define DHD_BYTES_ON() 0 -#define DHD_INTR_ON() 0 -#define DHD_GLOM_ON() 0 -#define DHD_EVENT_ON() 0 -#define DHD_BTA_ON() 0 -#define DHD_ISCAN_ON() 0 -#define DHD_ARPOE_ON() 0 -#define DHD_REORDER_ON() 0 -#define DHD_NOCHECKDIED_ON() 0 -#define DHD_PNO_ON() 0 -#define DHD_RTT_ON() 0 - -#endif - -#define DHD_LOG(args) - -#define DHD_BLOG(cp, size) - -#define DHD_NONE(args) -extern int dhd_msg_level; - -/* Defines msg bits */ -#include - -#endif /* _dhd_dbg_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_flowring.c b/drivers/net/wireless/bcmdhd/dhd_flowring.c deleted file mode 100644 index 2612552a818e..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_flowring.c +++ /dev/null @@ -1,831 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Flow ring specific code at top level - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_flowrings.c jaganlv $ - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -static INLINE uint16 dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, - uint8 prio, char *sa, char *da); - -static INLINE int dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, - uint8 prio, char *sa, char *da, uint16 *flowid); -int BCMFASTPATH dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt); - -#define FLOW_QUEUE_PKT_NEXT(p) PKTLINK(p) -#define FLOW_QUEUE_PKT_SETNEXT(p, x) PKTSETLINK((p), (x)) - -const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 }; -const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - -int BCMFASTPATH -dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt) -{ - return BCME_NORESOURCE; -} - -/* Flow ring's queue management functions */ - -void /* Initialize a flow ring's queue */ -dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max) -{ - ASSERT((queue != NULL) && (max > 0)); - - dll_init(&queue->list); - queue->head = queue->tail = NULL; - queue->len = 0; - queue->max = max - 1; - queue->failures = 0U; - queue->cb = &dhd_flow_queue_overflow; -} - -void /* Register an enqueue overflow callback handler */ -dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb) -{ - ASSERT(queue != NULL); - queue->cb = cb; -} - - -int BCMFASTPATH /* Enqueue a packet in a flow ring's queue */ -dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt) -{ - int ret = BCME_OK; - - ASSERT(queue != NULL); - - if (queue->len >= queue->max) { - queue->failures++; - ret = (*queue->cb)(queue, pkt); - goto done; - } - - if (queue->head) { - FLOW_QUEUE_PKT_SETNEXT(queue->tail, pkt); - } else { - queue->head = pkt; - } - - FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); - - queue->tail = pkt; /* at tail */ - - queue->len++; - -done: - return ret; -} - -void * BCMFASTPATH /* Dequeue a packet from a flow ring's queue, from head */ -dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue) -{ - void * pkt; - - ASSERT(queue != NULL); - - pkt = queue->head; /* from head */ - - if (pkt == NULL) { - ASSERT((queue->len == 0) && (queue->tail == NULL)); - goto done; - } - - queue->head = FLOW_QUEUE_PKT_NEXT(pkt); - if (queue->head == NULL) - queue->tail = NULL; - - queue->len--; - - FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); /* dettach packet from queue */ - -done: - return pkt; -} - -void BCMFASTPATH /* Reinsert a dequeued packet back at the head */ -dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt) -{ - if (queue->head == NULL) { - queue->tail = pkt; - } - - FLOW_QUEUE_PKT_SETNEXT(pkt, queue->head); - queue->head = pkt; - queue->len++; -} - - -/* Init Flow Ring specific data structures */ -int -dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings) -{ - uint32 idx; - uint32 flow_ring_table_sz; - uint32 if_flow_lkup_sz; - void * flowid_allocator; - flow_ring_table_t *flow_ring_table; - if_flow_lkup_t *if_flow_lkup = NULL; -#ifdef PCIE_TX_DEFERRAL - uint32 count; -#endif - void *lock = NULL; - unsigned long flags; - - DHD_INFO(("%s\n", __FUNCTION__)); - - /* Construct a 16bit flow1d allocator */ - flowid_allocator = id16_map_init(dhdp->osh, - num_flow_rings - FLOW_RING_COMMON, FLOWID_RESERVED); - if (flowid_allocator == NULL) { - DHD_ERROR(("%s: flowid allocator init failure\n", __FUNCTION__)); - return BCME_NOMEM; - } - - /* Allocate a flow ring table, comprising of requested number of rings */ - flow_ring_table_sz = (num_flow_rings * sizeof(flow_ring_node_t)); - flow_ring_table = (flow_ring_table_t *)MALLOCZ(dhdp->osh, flow_ring_table_sz); - if (flow_ring_table == NULL) { - DHD_ERROR(("%s: flow ring table alloc failure\n", __FUNCTION__)); - goto fail; - } - - /* Initialize flow ring table state */ - for (idx = 0; idx < num_flow_rings; idx++) { - flow_ring_table[idx].status = FLOW_RING_STATUS_CLOSED; - flow_ring_table[idx].flowid = (uint16)idx; - flow_ring_table[idx].lock = dhd_os_spin_lock_init(dhdp->osh); - if (flow_ring_table[idx].lock == NULL) { - DHD_ERROR(("%s: Failed to init spinlock for queue!\n", __FUNCTION__)); - goto fail; - } - - dll_init(&flow_ring_table[idx].list); - - /* Initialize the per flow ring backup queue */ - dhd_flow_queue_init(dhdp, &flow_ring_table[idx].queue, - FLOW_RING_QUEUE_THRESHOLD); - } - - /* Allocate per interface hash table */ - if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS; - if_flow_lkup = (if_flow_lkup_t *)DHD_OS_PREALLOC(dhdp, - DHD_PREALLOC_IF_FLOW_LKUP, if_flow_lkup_sz); - if (if_flow_lkup == NULL) { - DHD_ERROR(("%s: if flow lkup alloc failure\n", __FUNCTION__)); - goto fail; - } - - /* Initialize per interface hash table */ - bzero((uchar *)if_flow_lkup, if_flow_lkup_sz); - for (idx = 0; idx < DHD_MAX_IFS; idx++) { - int hash_ix; - if_flow_lkup[idx].status = 0; - if_flow_lkup[idx].role = 0; - for (hash_ix = 0; hash_ix < DHD_FLOWRING_HASH_SIZE; hash_ix++) - if_flow_lkup[idx].fl_hash[hash_ix] = NULL; - } - -#ifdef PCIE_TX_DEFERRAL - count = BITS_TO_LONGS(num_flow_rings); - dhdp->bus->delete_flow_map = kzalloc(count, GFP_ATOMIC); - if (!dhdp->bus->delete_flow_map) { - DHD_ERROR(("%s: delete_flow_map alloc failure\n", __FUNCTION__)); - goto fail; - } -#endif - - lock = dhd_os_spin_lock_init(dhdp->osh); - if (lock == NULL) - goto fail; - - dhdp->flow_prio_map_type = DHD_FLOW_PRIO_AC_MAP; - bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); - - /* Now populate into dhd pub */ - DHD_FLOWID_LOCK(lock, flags); - dhdp->num_flow_rings = num_flow_rings; - dhdp->flowid_allocator = (void *)flowid_allocator; - dhdp->flow_ring_table = (void *)flow_ring_table; - dhdp->if_flow_lkup = (void *)if_flow_lkup; - dhdp->flowid_lock = lock; - DHD_FLOWID_UNLOCK(lock, flags); - - DHD_INFO(("%s done\n", __FUNCTION__)); - return BCME_OK; - -fail: - -#ifdef PCIE_TX_DEFERRAL - if (dhdp->bus->delete_flow_map) - kfree(dhdp->bus->delete_flow_map); -#endif - /* Destruct the per interface flow lkup table */ - if (dhdp->if_flow_lkup != NULL) { - DHD_OS_PREFREE(dhdp, if_flow_lkup, if_flow_lkup_sz); - } - if (flow_ring_table != NULL) { - for (idx = 0; idx < num_flow_rings; idx++) { - if (flow_ring_table[idx].lock != NULL) - dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock); - } - MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz); - } - id16_map_fini(dhdp->osh, flowid_allocator); - - return BCME_NOMEM; -} - -/* Deinit Flow Ring specific data structures */ -void dhd_flow_rings_deinit(dhd_pub_t *dhdp) -{ - uint16 idx; - uint32 flow_ring_table_sz; - uint32 if_flow_lkup_sz; - flow_ring_table_t *flow_ring_table; - unsigned long flags; - void *lock; - - DHD_INFO(("dhd_flow_rings_deinit\n")); - - if (dhdp->flow_ring_table != NULL) { - - ASSERT(dhdp->num_flow_rings > 0); - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; - dhdp->flow_ring_table = NULL; - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - for (idx = 0; idx < dhdp->num_flow_rings; idx++) { - if (flow_ring_table[idx].active) { - dhd_bus_clean_flow_ring(dhdp->bus, &flow_ring_table[idx]); - } - ASSERT(flow_queue_empty(&flow_ring_table[idx].queue)); - - /* Deinit flow ring queue locks before destroying flow ring table */ - if (flow_ring_table[idx].lock != NULL) { - dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock); - } - flow_ring_table[idx].lock = NULL; - } - - /* Destruct the flow ring table */ - flow_ring_table_sz = dhdp->num_flow_rings * sizeof(flow_ring_table_t); - MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz); - } - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - - /* Destruct the per interface flow lkup table */ - if (dhdp->if_flow_lkup != NULL) { - if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS; - bzero(dhdp->if_flow_lkup, sizeof(if_flow_lkup_sz)); - DHD_OS_PREFREE(dhdp, dhdp->if_flow_lkup, if_flow_lkup_sz); - dhdp->if_flow_lkup = NULL; - } - -#ifdef PCIE_TX_DEFERRAL - if (dhdp->bus->delete_flow_map) - kfree(dhdp->bus->delete_flow_map); -#endif - - /* Destruct the flowid allocator */ - if (dhdp->flowid_allocator != NULL) - dhdp->flowid_allocator = id16_map_fini(dhdp->osh, dhdp->flowid_allocator); - - dhdp->num_flow_rings = 0U; - lock = dhdp->flowid_lock; - dhdp->flowid_lock = NULL; - - if (lock) { - DHD_FLOWID_UNLOCK(lock, flags); - dhd_os_spin_lock_deinit(dhdp->osh, lock); - } -} - -uint8 -dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex) -{ - if_flow_lkup_t *if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - ASSERT(if_flow_lkup); - return if_flow_lkup[ifindex].role; -} - -#ifdef WLTDLS -bool is_tdls_destination(dhd_pub_t *dhdp, uint8 *da) -{ - tdls_peer_node_t *cur = dhdp->peer_tbl.node; - while (cur != NULL) { - if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { - return TRUE; - } - cur = cur->next; - } - return FALSE; -} -#endif /* WLTDLS */ - -/* For a given interface, search the hash table for a matching flow */ -uint16 -dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) -{ - int hash; - bool ismcast = FALSE; - flow_hash_info_t *cur; - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) { -#ifdef WLTDLS - if (dhdp->peer_tbl.tdls_peer_count && !(ETHER_ISMULTI(da)) && - is_tdls_destination(dhdp, da)) { - hash = DHD_FLOWRING_HASHINDEX(da, prio); - cur = if_flow_lkup[ifindex].fl_hash[hash]; - while (cur != NULL) { - if (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN)) { - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - return cur->flowid; - } - cur = cur->next; - } - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - return FLOWID_INVALID; - } -#endif /* WLTDLS */ - cur = if_flow_lkup[ifindex].fl_hash[prio]; - if (cur) { - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - return cur->flowid; - } - - } else { - - if (ETHER_ISMULTI(da)) { - ismcast = TRUE; - hash = 0; - } else { - hash = DHD_FLOWRING_HASHINDEX(da, prio); - } - - cur = if_flow_lkup[ifindex].fl_hash[hash]; - - while (cur) { - if ((ismcast && ETHER_ISMULTI(cur->flow_info.da)) || - (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN) && - (cur->flow_info.tid == prio))) { - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - return cur->flowid; - } - cur = cur->next; - } - } - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - return FLOWID_INVALID; -} - -/* Allocate Flow ID */ -static INLINE uint16 -dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) -{ - flow_hash_info_t *fl_hash_node, *cur; - if_flow_lkup_t *if_flow_lkup; - int hash; - uint16 flowid; - unsigned long flags; - - fl_hash_node = (flow_hash_info_t *) MALLOC(dhdp->osh, sizeof(flow_hash_info_t)); - memcpy(fl_hash_node->flow_info.da, da, sizeof(fl_hash_node->flow_info.da)); - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - ASSERT(dhdp->flowid_allocator != NULL); - flowid = id16_map_alloc(dhdp->flowid_allocator); - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - if (flowid == FLOWID_INVALID) { - MFREE(dhdp->osh, fl_hash_node, sizeof(flow_hash_info_t)); - DHD_ERROR(("%s: cannot get free flowid \n", __FUNCTION__)); - return FLOWID_INVALID; - } - - fl_hash_node->flowid = flowid; - fl_hash_node->flow_info.tid = prio; - fl_hash_node->flow_info.ifindex = ifindex; - fl_hash_node->next = NULL; - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) { - /* For STA non TDLS dest we allocate entry based on prio only */ -#ifdef WLTDLS - if (dhdp->peer_tbl.tdls_peer_count && - (is_tdls_destination(dhdp, da))) { - hash = DHD_FLOWRING_HASHINDEX(da, prio); - cur = if_flow_lkup[ifindex].fl_hash[hash]; - if (cur) { - while (cur->next) { - cur = cur->next; - } - cur->next = fl_hash_node; - } else { - if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; - } - } else -#endif /* WLTDLS */ - if_flow_lkup[ifindex].fl_hash[prio] = fl_hash_node; - } else { - - /* For bcast/mcast assign first slot in in interface */ - hash = ETHER_ISMULTI(da) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio); - cur = if_flow_lkup[ifindex].fl_hash[hash]; - if (cur) { - while (cur->next) { - cur = cur->next; - } - cur->next = fl_hash_node; - } else - if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; - } - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid)); - - return fl_hash_node->flowid; -} - -/* Get flow ring ID, if not present try to create one */ -static INLINE int -dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, - uint8 prio, char *sa, char *da, uint16 *flowid) -{ - uint16 id; - flow_ring_node_t *flow_ring_node; - flow_ring_table_t *flow_ring_table; - unsigned long flags; - - DHD_INFO(("%s\n", __FUNCTION__)); - - if (!dhdp->flow_ring_table) - return BCME_ERROR; - - flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; - - id = dhd_flowid_find(dhdp, ifindex, prio, sa, da); - - if (id == FLOWID_INVALID) { - - if_flow_lkup_t *if_flow_lkup; - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - if (!if_flow_lkup[ifindex].status) - return BCME_ERROR; - - id = dhd_flowid_alloc(dhdp, ifindex, prio, sa, da); - if (id == FLOWID_INVALID) { - DHD_ERROR(("%s: alloc flowid ifindex %u status %u\n", - __FUNCTION__, ifindex, if_flow_lkup[ifindex].status)); - return BCME_ERROR; - } - - /* register this flowid in dhd_pub */ - dhd_add_flowid(dhdp, ifindex, prio, da, id); - } - - ASSERT(id < dhdp->num_flow_rings); - - flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id]; - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - if (flow_ring_node->active) { - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - *flowid = id; - return BCME_OK; - } - /* Init Flow info */ - memcpy(flow_ring_node->flow_info.sa, sa, sizeof(flow_ring_node->flow_info.sa)); - memcpy(flow_ring_node->flow_info.da, da, sizeof(flow_ring_node->flow_info.da)); - flow_ring_node->flow_info.tid = prio; - flow_ring_node->flow_info.ifindex = ifindex; - flow_ring_node->active = TRUE; - flow_ring_node->status = FLOW_RING_STATUS_PENDING; - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - dll_prepend(&dhdp->bus->const_flowring, &flow_ring_node->list); - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - /* Create and inform device about the new flow */ - if (dhd_bus_flow_ring_create_request(dhdp->bus, (void *)flow_ring_node) - != BCME_OK) { - DHD_ERROR(("%s: create error %d\n", __FUNCTION__, id)); - return BCME_ERROR; - } - - *flowid = id; - return BCME_OK; -} - -/* Update flowid information on the packet */ -int BCMFASTPATH -dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void *pktbuf) -{ - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); - struct ether_header *eh = (struct ether_header *)pktdata; - uint16 flowid; - - if (dhd_bus_is_txmode_push(dhdp->bus)) - return BCME_OK; - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) { - return BCME_BADARG; - } - - if (!dhdp->flowid_allocator) { - DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); - return BCME_ERROR; - } - if (dhd_flowid_lookup(dhdp, ifindex, prio, eh->ether_shost, eh->ether_dhost, - &flowid) != BCME_OK) { - return BCME_ERROR; - } - - DHD_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid)); - - /* Tag the packet with flowid */ - DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(pktbuf), flowid); - return BCME_OK; -} - -void -dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid) -{ - int hashix; - bool found = FALSE; - flow_hash_info_t *cur, *prev; - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - for (hashix = 0; hashix < DHD_FLOWRING_HASH_SIZE; hashix++) { - - cur = if_flow_lkup[ifindex].fl_hash[hashix]; - - if (cur) { - if (cur->flowid == flowid) { - found = TRUE; - } - - prev = NULL; - while (!found && cur) { - if (cur->flowid == flowid) { - found = TRUE; - break; - } - prev = cur; - cur = cur->next; - } - if (found) { - if (!prev) { - if_flow_lkup[ifindex].fl_hash[hashix] = cur->next; - } else { - prev->next = cur->next; - } - - /* deregister flowid from dhd_pub. */ - dhd_del_flowid(dhdp, ifindex, flowid); - - id16_map_free(dhdp->flowid_allocator, flowid); - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - MFREE(dhdp->osh, cur, sizeof(flow_hash_info_t)); - - return; - } - } - } - - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - DHD_ERROR(("%s: could not free flow ring hash entry flowid %d\n", - __FUNCTION__, flowid)); -} - - -/* Delete all Flow rings assocaited with the given Interface */ -void -dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex) -{ - uint32 id; - flow_ring_table_t *flow_ring_table; - - DHD_INFO(("%s: ifindex %u\n", __FUNCTION__, ifindex)); - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return; - - if (!dhdp->flow_ring_table) - return; - - flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; - for (id = 0; id < dhdp->num_flow_rings; id++) { - if (flow_ring_table[id].active && - (flow_ring_table[id].flow_info.ifindex == ifindex) && - (flow_ring_table[id].status != FLOW_RING_STATUS_DELETE_PENDING)) { - DHD_INFO(("%s: deleting flowid %d\n", - __FUNCTION__, flow_ring_table[id].flowid)); - dhd_bus_flow_ring_delete_request(dhdp->bus, - (void *) &flow_ring_table[id]); - } - } -} - -/* Delete flow/s for given peer address */ -void -dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr) -{ - uint32 id; - flow_ring_table_t *flow_ring_table; - - DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex)); - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return; - - if (!dhdp->flow_ring_table) - return; - - flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; - for (id = 0; id < dhdp->num_flow_rings; id++) { - if (flow_ring_table[id].active && - (flow_ring_table[id].flow_info.ifindex == ifindex) && - (!memcmp(flow_ring_table[id].flow_info.da, addr, ETHER_ADDR_LEN)) && - (flow_ring_table[id].status != FLOW_RING_STATUS_DELETE_PENDING)) { - DHD_INFO(("%s: deleting flowid %d\n", - __FUNCTION__, flow_ring_table[id].flowid)); - dhd_bus_flow_ring_delete_request(dhdp->bus, - (void *) &flow_ring_table[id]); - } - } -} - -/* Handle Interface ADD, DEL operations */ -void -dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex, - uint8 op, uint8 role) -{ - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return; - - DHD_INFO(("%s: ifindex %u op %u role is %u \n", - __FUNCTION__, ifindex, op, role)); - if (!dhdp->flowid_allocator) { - DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); - return; - } - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - if (op == WLC_E_IF_ADD || op == WLC_E_IF_CHANGE) { - - if_flow_lkup[ifindex].role = role; - - if (!(DHD_IF_ROLE_STA(role))) { - if_flow_lkup[ifindex].status = TRUE; - DHD_INFO(("%s: Mcast Flow ring for ifindex %d role is %d \n", - __FUNCTION__, ifindex, role)); - /* Create Mcast Flow */ - } - } else if (op == WLC_E_IF_DEL) { - if_flow_lkup[ifindex].status = FALSE; - DHD_INFO(("%s: cleanup all Flow rings for ifindex %d role is %d \n", - __FUNCTION__, ifindex, role)); - } - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); -} - -/* Handle a STA interface link status update */ -int -dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, uint8 status) -{ - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return BCME_BADARG; - - DHD_INFO(("%s: ifindex %d status %d\n", __FUNCTION__, ifindex, status)); - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) { - if (status) - if_flow_lkup[ifindex].status = TRUE; - else - if_flow_lkup[ifindex].status = FALSE; - } - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - return BCME_OK; -} -/* Update flow priority mapping */ -int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map) -{ - uint16 flowid; - flow_ring_node_t *flow_ring_node; - - if (map > DHD_FLOW_PRIO_TID_MAP) - return BCME_BADOPTION; - - /* Check if we need to change prio map */ - if (map == dhdp->flow_prio_map_type) - return BCME_OK; - - /* If any ring is active we cannot change priority mapping for flow rings */ - for (flowid = 0; flowid < dhdp->num_flow_rings; flowid++) { - flow_ring_node = DHD_FLOW_RING(dhdp, flowid); - if (flow_ring_node->active) - return BCME_EPERM; - } - /* Infor firmware about new mapping type */ - if (BCME_OK != dhd_flow_prio_map(dhdp, &map, TRUE)) - return BCME_ERROR; - - /* update internal structures */ - dhdp->flow_prio_map_type = map; - if (dhdp->flow_prio_map_type == DHD_FLOW_PRIO_TID_MAP) - bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); - else - bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); - - return BCME_OK; -} - -/* Set/Get flwo ring priority map */ -int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set) -{ - uint8 iovbuf[24]; - if (!set) { - bcm_mkiovar("bus:fl_prio_map", NULL, 0, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) { - DHD_ERROR(("%s: failed to get fl_prio_map\n", __FUNCTION__)); - return BCME_ERROR; - } - *map = iovbuf[0]; - return BCME_OK; - } - bcm_mkiovar("bus:fl_prio_map", (char *)map, 4, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { - DHD_ERROR(("%s: failed to set fl_prio_map \n", - __FUNCTION__)); - return BCME_ERROR; - } - return BCME_OK; -} diff --git a/drivers/net/wireless/bcmdhd/dhd_flowring.h b/drivers/net/wireless/bcmdhd/dhd_flowring.h deleted file mode 100644 index e0d6bca22084..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_flowring.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Header file describing the flow rings DHD interfaces. - * - * Provides type definitions and function prototypes used to create, delete and manage - * - * flow rings at high level - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_flowrings.h jaganlv $ - */ - -/**************** - * Common types * - */ - -#ifndef _dhd_flowrings_h_ -#define _dhd_flowrings_h_ - -/* Max pkts held in a flow ring's backup queue */ -#define FLOW_RING_QUEUE_THRESHOLD (2048) - -/* Number of H2D common rings : PCIE Spec Rev? */ -#define FLOW_RING_COMMON 2 - -#define FLOWID_INVALID (ID16_INVALID) -#define FLOWID_RESERVED (FLOW_RING_COMMON) - -#define FLOW_RING_STATUS_OPEN 0 -#define FLOW_RING_STATUS_PENDING 1 -#define FLOW_RING_STATUS_CLOSED 2 -#define FLOW_RING_STATUS_DELETE_PENDING 3 -#define FLOW_RING_STATUS_FLUSH_PENDING 4 - -#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 2048 - -#define DHD_FLOW_PRIO_AC_MAP 0 -#define DHD_FLOW_PRIO_TID_MAP 1 - - -/* Pkttag not compatible with PROP_TXSTATUS or WLFC */ -typedef struct dhd_pkttag_fr { - uint16 flowid; - int dataoff; -} dhd_pkttag_fr_t; - -#define DHD_PKTTAG_SET_FLOWID(tag, flow) ((tag)->flowid = (uint16)(flow)) -#define DHD_PKTTAG_SET_DATAOFF(tag, offset) ((tag)->dataoff = (int)(offset)) - -#define DHD_PKTTAG_FLOWID(tag) ((tag)->flowid) -#define DHD_PKTTAG_DATAOFF(tag) ((tag)->dataoff) - -/* Hashing a MacAddress for lkup into a per interface flow hash table */ -#define DHD_FLOWRING_HASH_SIZE 256 -#define DHD_FLOWRING_HASHINDEX(ea, prio) \ - ((((uint8 *)(ea))[3] ^ ((uint8 *)(ea))[4] ^ ((uint8 *)(ea))[5] ^ ((uint8)(prio))) \ - % DHD_FLOWRING_HASH_SIZE) - -#define DHD_IF_ROLE(pub, idx) (((if_flow_lkup_t *)(pub)->if_flow_lkup)[idx].role) -#define DHD_IF_ROLE_AP(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_AP) -#define DHD_IF_ROLE_P2PGO(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_P2P_GO) -#define DHD_FLOW_RING(dhdp, flowid) \ - (flow_ring_node_t *)&(((flow_ring_node_t *)((dhdp)->flow_ring_table))[flowid]) - -struct flow_queue; - -/* Flow Ring Queue Enqueue overflow callback */ -typedef int (*flow_queue_cb_t)(struct flow_queue * queue, void * pkt); - -typedef struct flow_queue { - dll_t list; /* manage a flowring queue in a dll */ - void * head; /* first packet in the queue */ - void * tail; /* last packet in the queue */ - uint16 len; /* number of packets in the queue */ - uint16 max; /* maximum number of packets, queue may hold */ - uint32 failures; /* enqueue failures due to queue overflow */ - flow_queue_cb_t cb; /* callback invoked on threshold crossing */ -} flow_queue_t; - -#define flow_queue_len(queue) ((int)(queue)->len) -#define flow_queue_max(queue) ((int)(queue)->max) -#define flow_queue_avail(queue) ((int)((queue)->max - (queue)->len)) -#define flow_queue_full(queue) ((queue)->len >= (queue)->max) -#define flow_queue_empty(queue) ((queue)->len == 0) - -typedef struct flow_info { - uint8 tid; - uint8 ifindex; - char sa[ETHER_ADDR_LEN]; - char da[ETHER_ADDR_LEN]; -} flow_info_t; - -typedef struct flow_ring_node { - dll_t list; /* manage a constructed flowring in a dll, must be at first place */ - flow_queue_t queue; - bool active; - uint8 status; - uint16 flowid; - flow_info_t flow_info; - void *prot_info; - void *lock; /* lock for flowring access protection */ -} flow_ring_node_t; -typedef flow_ring_node_t flow_ring_table_t; - -typedef struct flow_hash_info { - uint16 flowid; - flow_info_t flow_info; - struct flow_hash_info *next; -} flow_hash_info_t; - -typedef struct if_flow_lkup { - bool status; - uint8 role; /* Interface role: STA/AP */ - flow_hash_info_t *fl_hash[DHD_FLOWRING_HASH_SIZE]; /* Lkup Hash table */ -} if_flow_lkup_t; - -static INLINE flow_ring_node_t * -dhd_constlist_to_flowring(dll_t *item) -{ - return ((flow_ring_node_t *)item); -} - -/* Exported API */ - -/* Flow ring's queue management functions */ -extern void dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max); -extern void dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb); -extern int dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt); -extern void * dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue); -extern void dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt); - -extern int dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings); - -extern void dhd_flow_rings_deinit(dhd_pub_t *dhdp); - -extern uint16 dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da); - -extern int dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, - void *pktbuf); - -extern void dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid); - -extern void dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex); - -extern void dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, - char *addr); - -/* Handle Interface ADD, DEL operations */ -extern void dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex, - uint8 op, uint8 role); - -/* Handle a STA interface link status update */ -extern int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, - uint8 status); -extern int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set); -extern int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map); - -extern uint8 dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex); -#endif /* _dhd_flowrings_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_ip.c b/drivers/net/wireless/bcmdhd/dhd_ip.c deleted file mode 100644 index 2d21052601f9..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_ip.c +++ /dev/null @@ -1,1318 +0,0 @@ -/* - * IP Packet Parser Module. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_ip.c 528525 2015-01-22 12:50:08Z $ - */ -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#ifdef DHDTCPACK_SUPPRESS -#include -#include -#include -#endif /* DHDTCPACK_SUPPRESS */ - -/* special values */ -/* 802.3 llc/snap header */ -static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; - -pkt_frag_t pkt_frag_info(osl_t *osh, void *p) -{ - uint8 *frame; - int length; - uint8 *pt; /* Pointer to type field */ - uint16 ethertype; - struct ipv4_hdr *iph; /* IP frame pointer */ - int ipl; /* IP frame length */ - uint16 iph_frag; - - ASSERT(osh && p); - - frame = PKTDATA(osh, p); - length = PKTLEN(osh, p); - - /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ - if (length < ETHER_HDR_LEN) { - DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length)); - return DHD_PKT_FRAG_NONE; - } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { - /* Frame is Ethernet II */ - pt = frame + ETHER_TYPE_OFFSET; - } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && - !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { - pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; - } else { - DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__)); - return DHD_PKT_FRAG_NONE; - } - - ethertype = ntoh16(*(uint16 *)pt); - - /* Skip VLAN tag, if any */ - if (ethertype == ETHER_TYPE_8021Q) { - pt += VLAN_TAG_LEN; - - if (pt + ETHER_TYPE_LEN > frame + length) { - DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length)); - return DHD_PKT_FRAG_NONE; - } - - ethertype = ntoh16(*(uint16 *)pt); - } - - if (ethertype != ETHER_TYPE_IP) { - DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n", - __FUNCTION__, ethertype, length)); - return DHD_PKT_FRAG_NONE; - } - - iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); - ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame)); - - /* We support IPv4 only */ - if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) { - DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl)); - return DHD_PKT_FRAG_NONE; - } - - iph_frag = ntoh16(iph->frag); - - if (iph_frag & IPV4_FRAG_DONT) { - return DHD_PKT_FRAG_NONE; - } else if ((iph_frag & IPV4_FRAG_MORE) == 0) { - return DHD_PKT_FRAG_LAST; - } else { - return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST; - } -} - -bool pkt_is_dhcp(osl_t *osh, void *p) -{ - uint8 *frame; - int length; - uint8 *pt; /* Pointer to type field */ - uint16 ethertype; - struct ipv4_hdr *iph; /* IP frame pointer */ - int ipl; /* IP frame length */ - uint16 src_port; - - ASSERT(osh && p); - - frame = PKTDATA(osh, p); - length = PKTLEN(osh, p); - - /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ - if (length < ETHER_HDR_LEN) { - DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length)); - return FALSE; - } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { - /* Frame is Ethernet II */ - pt = frame + ETHER_TYPE_OFFSET; - } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && - !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { - pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; - } else { - DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__)); - return FALSE; - } - - ethertype = ntoh16(*(uint16 *)pt); - - /* Skip VLAN tag, if any */ - if (ethertype == ETHER_TYPE_8021Q) { - pt += VLAN_TAG_LEN; - - if (pt + ETHER_TYPE_LEN > frame + length) { - DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length)); - return FALSE; - } - - ethertype = ntoh16(*(uint16 *)pt); - } - - if (ethertype != ETHER_TYPE_IP) { - DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n", - __FUNCTION__, ethertype, length)); - return FALSE; - } - - iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); - ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame)); - - /* We support IPv4 only */ - if ((ipl < (IPV4_OPTIONS_OFFSET + 2)) || (IP_VER(iph) != IP_VER_4)) { - DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl)); - return FALSE; - } - - src_port = ntoh16(*(uint16 *)(pt + ETHER_TYPE_LEN + IPV4_OPTIONS_OFFSET)); - - return (src_port == 0x43 || src_port == 0x44); -} - -#ifdef DHDTCPACK_SUPPRESS - -typedef struct { - void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */ - void *pkt_ether_hdr; /* Ethernet header pointer of pkt_in_q */ - int ifidx; - uint8 supp_cnt; - dhd_pub_t *dhdp; - struct timer_list timer; -} tcpack_info_t; - -typedef struct _tdata_psh_info_t { - uint32 end_seq; /* end seq# of a received TCP PSH DATA pkt */ - struct _tdata_psh_info_t *next; /* next pointer of the link chain */ -} tdata_psh_info_t; - -typedef struct { - uint8 src_ip_addr[IPV4_ADDR_LEN]; /* SRC ip addrs of this TCP stream */ - uint8 dst_ip_addr[IPV4_ADDR_LEN]; /* DST ip addrs of this TCP stream */ - uint8 src_tcp_port[TCP_PORT_LEN]; /* SRC tcp ports of this TCP stream */ - uint8 dst_tcp_port[TCP_PORT_LEN]; /* DST tcp ports of this TCP stream */ - tdata_psh_info_t *tdata_psh_info_head; /* Head of received TCP PSH DATA chain */ - tdata_psh_info_t *tdata_psh_info_tail; /* Tail of received TCP PSH DATA chain */ - uint32 last_used_time; /* The last time this tcpdata_info was used(in ms) */ -} tcpdata_info_t; - -/* TCPACK SUPPRESS module */ -typedef struct { - int tcpack_info_cnt; - tcpack_info_t tcpack_info_tbl[TCPACK_INFO_MAXNUM]; /* Info of TCP ACK to send */ - int tcpdata_info_cnt; - tcpdata_info_t tcpdata_info_tbl[TCPDATA_INFO_MAXNUM]; /* Info of received TCP DATA */ - tdata_psh_info_t *tdata_psh_info_pool; /* Pointer to tdata_psh_info elements pool */ - tdata_psh_info_t *tdata_psh_info_free; /* free tdata_psh_info elements chain in pool */ -#ifdef DHDTCPACK_SUP_DBG - int psh_info_enq_num; /* Number of free TCP PSH DATA info elements in pool */ -#endif /* DHDTCPACK_SUP_DBG */ -} tcpack_sup_module_t; - -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) -counter_tbl_t tack_tbl = {"tcpACK", 0, 1000, 10, {0, }, 1}; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - -static void -_tdata_psh_info_pool_enq(tcpack_sup_module_t *tcpack_sup_mod, - tdata_psh_info_t *tdata_psh_info) -{ - if ((tcpack_sup_mod == NULL) || (tdata_psh_info == NULL)) { - DHD_ERROR(("%s %d: ERROR %p %p\n", __FUNCTION__, __LINE__, - tcpack_sup_mod, tdata_psh_info)); - return; - } - - ASSERT(tdata_psh_info->next == NULL); - tdata_psh_info->next = tcpack_sup_mod->tdata_psh_info_free; - tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info; -#ifdef DHDTCPACK_SUP_DBG - tcpack_sup_mod->psh_info_enq_num++; -#endif -} - -static tdata_psh_info_t* -_tdata_psh_info_pool_deq(tcpack_sup_module_t *tcpack_sup_mod) -{ - tdata_psh_info_t *tdata_psh_info = NULL; - - if (tcpack_sup_mod == NULL) { - DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__, __LINE__, - tcpack_sup_mod)); - return NULL; - } - - tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free; - if (tdata_psh_info == NULL) - DHD_ERROR(("%s %d: Out of tdata_disc_grp\n", __FUNCTION__, __LINE__)); - else { - tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; - tdata_psh_info->next = NULL; -#ifdef DHDTCPACK_SUP_DBG - tcpack_sup_mod->psh_info_enq_num--; -#endif /* DHDTCPACK_SUP_DBG */ - } - - return tdata_psh_info; -} - -#ifdef BCMSDIO -static int _tdata_psh_info_pool_init(dhd_pub_t *dhdp, - tcpack_sup_module_t *tcpack_sup_mod) -{ - tdata_psh_info_t *tdata_psh_info_pool = NULL; - uint i; - - DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); - - if (tcpack_sup_mod == NULL) - return BCME_ERROR; - - ASSERT(tcpack_sup_mod->tdata_psh_info_pool == NULL); - ASSERT(tcpack_sup_mod->tdata_psh_info_free == NULL); - - tdata_psh_info_pool = - MALLOC(dhdp->osh, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); - - if (tdata_psh_info_pool == NULL) - return BCME_NOMEM; - bzero(tdata_psh_info_pool, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); -#ifdef DHDTCPACK_SUP_DBG - tcpack_sup_mod->psh_info_enq_num = 0; -#endif /* DHDTCPACK_SUP_DBG */ - - /* Enqueue newly allocated tcpdata psh info elements to the pool */ - for (i = 0; i < TCPDATA_PSH_INFO_MAXNUM; i++) - _tdata_psh_info_pool_enq(tcpack_sup_mod, &tdata_psh_info_pool[i]); - - ASSERT(tcpack_sup_mod->tdata_psh_info_free != NULL); - tcpack_sup_mod->tdata_psh_info_pool = tdata_psh_info_pool; - - return BCME_OK; -} - -static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp, - tcpack_sup_module_t *tcpack_sup_mod) -{ - uint i; - tdata_psh_info_t *tdata_psh_info; - - DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); - - if (tcpack_sup_mod == NULL) { - DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n", - __FUNCTION__, __LINE__)); - return; - } - - for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { - tcpdata_info_t *tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; - /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */ - while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { - tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; - tdata_psh_info->next = NULL; - _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); - } - tcpdata_info->tdata_psh_info_tail = NULL; - } -#ifdef DHDTCPACK_SUP_DBG - DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - - i = 0; - /* Be sure we recollected all tdata_psh_info elements */ - while ((tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free)) { - tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; - tdata_psh_info->next = NULL; - i++; - } - ASSERT(i == TCPDATA_PSH_INFO_MAXNUM); - MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool, - sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); - tcpack_sup_mod->tdata_psh_info_pool = NULL; - - return; -} -#endif /* BCMSDIO */ - -static void dhd_tcpack_send(ulong data) -{ - tcpack_sup_module_t *tcpack_sup_mod; - tcpack_info_t *cur_tbl = (tcpack_info_t *)data; - dhd_pub_t *dhdp; - int ifidx; - void* pkt; - - if (!cur_tbl) { - return; - } - - dhdp = cur_tbl->dhdp; - if (!dhdp) { - return; - } - - dhd_os_tcpacklock(dhdp); - - tcpack_sup_mod = dhdp->tcpack_sup_module; - pkt = cur_tbl->pkt_in_q; - ifidx = cur_tbl->ifidx; - if (!pkt) { - dhd_os_tcpackunlock(dhdp); - return; - } - cur_tbl->pkt_in_q = NULL; - cur_tbl->pkt_ether_hdr = NULL; - cur_tbl->ifidx = 0; - cur_tbl->supp_cnt = 0; - if (--tcpack_sup_mod->tcpack_info_cnt < 0) { - DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); - } - - dhd_os_tcpackunlock(dhdp); - - dhd_sendpkt(dhdp, ifidx, pkt); -} - -int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode) -{ - int ret = BCME_OK; - - dhd_os_tcpacklock(dhdp); - - if (dhdp->tcpack_sup_mode == mode) { - DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode)); - goto exit; - } - - if (mode >= TCPACK_SUP_LAST_MODE || -#ifndef BCMSDIO - mode == TCPACK_SUP_DELAYTX || -#endif /* !BCMSDIO */ - FALSE) { - DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__, __LINE__, mode)); - ret = BCME_BADARG; - goto exit; - } - - DHD_TRACE(("%s: %d -> %d\n", - __FUNCTION__, dhdp->tcpack_sup_mode, mode)); - -#ifdef BCMSDIO - /* Old tcpack_sup_mode is TCPACK_SUP_DELAYTX */ - if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX) { - tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; - /* We won't need tdata_psh_info pool and tcpddata_info_tbl anymore */ - _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_mod); - tcpack_sup_mod->tcpdata_info_cnt = 0; - bzero(tcpack_sup_mod->tcpdata_info_tbl, - sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM); - /* For half duplex bus interface, tx precedes rx by default */ - if (dhdp->bus) - dhd_bus_set_dotxinrx(dhdp->bus, TRUE); - } -#endif - dhdp->tcpack_sup_mode = mode; - - if (mode == TCPACK_SUP_OFF) { - ASSERT(dhdp->tcpack_sup_module != NULL); - /* Clean up timer/data structure for any remaining/pending packet or timer. */ - dhd_tcpack_info_tbl_clean(dhdp); - MFREE(dhdp->osh, dhdp->tcpack_sup_module, sizeof(tcpack_sup_module_t)); - dhdp->tcpack_sup_module = NULL; - goto exit; - } - - if (dhdp->tcpack_sup_module == NULL) { - tcpack_sup_module_t *tcpack_sup_mod = - MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t)); - if (tcpack_sup_mod == NULL) { - DHD_ERROR(("%s %d: No MEM\n", __FUNCTION__, __LINE__)); - dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; - ret = BCME_NOMEM; - goto exit; - } - bzero(tcpack_sup_mod, sizeof(tcpack_sup_module_t)); - dhdp->tcpack_sup_module = tcpack_sup_mod; - } - -#ifdef BCMSDIO - if (mode == TCPACK_SUP_DELAYTX) { - ret = _tdata_psh_info_pool_init(dhdp, dhdp->tcpack_sup_module); - if (ret != BCME_OK) - DHD_ERROR(("%s %d: pool init fail with %d\n", __FUNCTION__, __LINE__, ret)); - else if (dhdp->bus) - dhd_bus_set_dotxinrx(dhdp->bus, FALSE); - } -#endif /* BCMSDIO */ - - if (mode == TCPACK_SUP_HOLD) { - int i; - tcpack_sup_module_t *tcpack_sup_mod = - (tcpack_sup_module_t *)dhdp->tcpack_sup_module; - dhdp->tcpack_sup_ratio = TCPACK_SUPP_RATIO; - dhdp->tcpack_sup_delay = TCPACK_DELAY_TIME; - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) - { - tcpack_sup_mod->tcpack_info_tbl[i].dhdp = dhdp; - init_timer(&tcpack_sup_mod->tcpack_info_tbl[i].timer); - tcpack_sup_mod->tcpack_info_tbl[i].timer.data = - (ulong)&tcpack_sup_mod->tcpack_info_tbl[i]; - tcpack_sup_mod->tcpack_info_tbl[i].timer.function = dhd_tcpack_send; - } - } - -exit: - dhd_os_tcpackunlock(dhdp); - return ret; -} - -void -dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp) -{ - tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; - int i; - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) - goto exit; - - dhd_os_tcpacklock(dhdp); - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", - __FUNCTION__, __LINE__)); - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) { - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { - if (tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q) { - PKTFREE(dhdp->osh, tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q, - TRUE); - tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q = NULL; - tcpack_sup_mod->tcpack_info_tbl[i].pkt_ether_hdr = NULL; - tcpack_sup_mod->tcpack_info_tbl[i].ifidx = 0; - tcpack_sup_mod->tcpack_info_tbl[i].supp_cnt = 0; - } - } - } else { - tcpack_sup_mod->tcpack_info_cnt = 0; - bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM); - } - - dhd_os_tcpackunlock(dhdp); - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) { - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { - del_timer_sync(&tcpack_sup_mod->tcpack_info_tbl[i].timer); - } - } - -exit: - return; -} - -inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt) -{ - uint8 i; - tcpack_sup_module_t *tcpack_sup_mod; - tcpack_info_t *tcpack_info_tbl; - int tbl_cnt; - int ret = BCME_OK; - void *pdata; - uint32 pktlen; - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) - goto exit; - - pdata = PKTDATA(dhdp->osh, pkt); - pktlen = PKTLEN(dhdp->osh, pkt) - dhd_prot_hdrlen(dhdp, pdata); - - if (pktlen < TCPACKSZMIN || pktlen > TCPACKSZMAX) { - DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", - __FUNCTION__, __LINE__, pktlen)); - goto exit; - } - - dhd_os_tcpacklock(dhdp); - tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp); - goto exit; - } - tbl_cnt = tcpack_sup_mod->tcpack_info_cnt; - tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; - - ASSERT(tbl_cnt <= TCPACK_INFO_MAXNUM); - - for (i = 0; i < tbl_cnt; i++) { - if (tcpack_info_tbl[i].pkt_in_q == pkt) { - DHD_TRACE(("%s %d: pkt %p sent out. idx %d, tbl_cnt %d\n", - __FUNCTION__, __LINE__, pkt, i, tbl_cnt)); - /* This pkt is being transmitted so remove the tcp_ack_info of it. */ - if (i < tbl_cnt - 1) { - bcopy(&tcpack_info_tbl[tbl_cnt - 1], - &tcpack_info_tbl[i], sizeof(tcpack_info_t)); - } - bzero(&tcpack_info_tbl[tbl_cnt - 1], sizeof(tcpack_info_t)); - if (--tcpack_sup_mod->tcpack_info_cnt < 0) { - DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); - ret = BCME_ERROR; - } - break; - } - } - dhd_os_tcpackunlock(dhdp); - -exit: - return ret; -} - -static INLINE bool dhd_tcpdata_psh_acked(dhd_pub_t *dhdp, uint8 *ip_hdr, - uint8 *tcp_hdr, uint32 tcp_ack_num) -{ - tcpack_sup_module_t *tcpack_sup_mod; - int i; - tcpdata_info_t *tcpdata_info = NULL; - tdata_psh_info_t *tdata_psh_info = NULL; - bool ret = FALSE; - - if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) - goto exit; - - tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - goto exit; - } - - DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d, ack %u\n", __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), - tcp_ack_num)); - - for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { - tcpdata_info_t *tcpdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; - DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, i, - IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->src_ip_addr)), - IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->dst_ip_addr)), - ntoh16_ua(tcpdata_info_tmp->src_tcp_port), - ntoh16_ua(tcpdata_info_tmp->dst_tcp_port))); - - /* If either IP address or TCP port number does not match, skip. */ - if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], - tcpdata_info_tmp->dst_ip_addr, IPV4_ADDR_LEN) == 0 && - memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET], - tcpdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN) == 0 && - memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], - tcpdata_info_tmp->dst_tcp_port, TCP_PORT_LEN) == 0 && - memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET], - tcpdata_info_tmp->src_tcp_port, TCP_PORT_LEN) == 0) { - tcpdata_info = tcpdata_info_tmp; - break; - } - } - - if (tcpdata_info == NULL) { - DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__, __LINE__)); - goto exit; - } - - if (tcpdata_info->tdata_psh_info_head == NULL) { - DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__, __LINE__)); - } - - while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { - if (IS_TCPSEQ_GE(tcp_ack_num, tdata_psh_info->end_seq)) { - DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n", - __FUNCTION__, __LINE__, tcp_ack_num, tdata_psh_info->end_seq)); - tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; - tdata_psh_info->next = NULL; - _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); - ret = TRUE; - } else - break; - } - if (tdata_psh_info == NULL) - tcpdata_info->tdata_psh_info_tail = NULL; - -#ifdef DHDTCPACK_SUP_DBG - DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - -exit: - return ret; -} - -bool -dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt) -{ - uint8 *new_ether_hdr; /* Ethernet header of the new packet */ - uint16 new_ether_type; /* Ethernet type of the new packet */ - uint8 *new_ip_hdr; /* IP header of the new packet */ - uint8 *new_tcp_hdr; /* TCP header of the new packet */ - uint32 new_ip_hdr_len; /* IP header length of the new packet */ - uint32 cur_framelen; - uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ - uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ - uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ - tcpack_sup_module_t *tcpack_sup_mod; - tcpack_info_t *tcpack_info_tbl; - int i; - bool ret = FALSE; - bool set_dotxinrx = TRUE; - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) - goto exit; - - new_ether_hdr = PKTDATA(dhdp->osh, pkt); - cur_framelen = PKTLEN(dhdp->osh, pkt); - - if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { - DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", - __FUNCTION__, __LINE__, cur_framelen)); - goto exit; - } - - new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; - - if (new_ether_type != ETHER_TYPE_IP) { - DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", - __FUNCTION__, __LINE__, new_ether_type)); - goto exit; - } - - DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); - - new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; - cur_framelen -= ETHER_HDR_LEN; - - ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); - - new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); - if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { - DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", - __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); - goto exit; - } - - new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; - cur_framelen -= new_ip_hdr_len; - - ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); - - DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); - - /* is it an ack ? Allow only ACK flag, not to suppress others. */ - if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { - DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", - __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); - goto exit; - } - - new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); - new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); - - /* This packet has TCP data, so just send */ - if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { - DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); - goto exit; - } - - ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); - - new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - DHD_TRACE(("%s %d: TCP ACK with zero DATA length" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", - __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ - dhd_os_tcpacklock(dhdp); -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - counter_printlog(&tack_tbl); - tack_tbl.cnt[0]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - - tcpack_sup_mod = dhdp->tcpack_sup_module; - tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - if (dhd_tcpdata_psh_acked(dhdp, new_ip_hdr, new_tcp_hdr, new_tcp_ack_num)) { - /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */ -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[5]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - } else - set_dotxinrx = FALSE; - - for (i = 0; i < tcpack_sup_mod->tcpack_info_cnt; i++) { - void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ - uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; - uint32 old_ip_hdr_len, old_tcp_hdr_len; - uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ - - if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { - DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); - break; - } - - if (PKTDATA(dhdp->osh, oldpkt) == NULL) { - DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); - break; - } - - old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; - old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; - old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); - old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; - old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); - - DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* If either of IP address or TCP port number does not match, skip. */ - if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], - &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || - memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], - &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) - continue; - - old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - if (IS_TCPSEQ_GT(new_tcp_ack_num, old_tcpack_num)) { - /* New packet has higher TCP ACK number, so it replaces the old packet */ - if (new_ip_hdr_len == old_ip_hdr_len && - new_tcp_hdr_len == old_tcp_hdr_len) { - ASSERT(memcmp(new_ether_hdr, old_ether_hdr, ETHER_HDR_LEN) == 0); - bcopy(new_ip_hdr, old_ip_hdr, new_ip_total_len); - PKTFREE(dhdp->osh, pkt, FALSE); - DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n", - __FUNCTION__, __LINE__, old_tcpack_num, new_tcp_ack_num)); -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[2]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - ret = TRUE; - } else { -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[6]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d" - " ACK %u -> %u\n", __FUNCTION__, __LINE__, - new_ip_hdr_len, old_ip_hdr_len, - new_tcp_hdr_len, old_tcp_hdr_len, - old_tcpack_num, new_tcp_ack_num)); - } - } else if (new_tcp_ack_num == old_tcpack_num) { - set_dotxinrx = TRUE; - /* TCPACK retransmission */ -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[3]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - } else { - DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n", - __FUNCTION__, __LINE__, old_tcpack_num, oldpkt, - new_tcp_ack_num, pkt)); - } - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - if (i == tcpack_sup_mod->tcpack_info_cnt && i < TCPACK_INFO_MAXNUM) { - /* No TCPACK packet with the same IP addr and TCP port is found - * in tcp_ack_info_tbl. So add this packet to the table. - */ - DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", - __FUNCTION__, __LINE__, pkt, new_ether_hdr, - tcpack_sup_mod->tcpack_info_cnt)); - - tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_in_q = pkt; - tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_ether_hdr = new_ether_hdr; - tcpack_sup_mod->tcpack_info_cnt++; -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[1]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - } else { - ASSERT(i == tcpack_sup_mod->tcpack_info_cnt); - DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", - __FUNCTION__, __LINE__)); - } - dhd_os_tcpackunlock(dhdp); - -exit: - /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */ - if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX && set_dotxinrx) - dhd_bus_set_dotxinrx(dhdp->bus, TRUE); - - return ret; -} - -bool -dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt) -{ - uint8 *ether_hdr; /* Ethernet header of the new packet */ - uint16 ether_type; /* Ethernet type of the new packet */ - uint8 *ip_hdr; /* IP header of the new packet */ - uint8 *tcp_hdr; /* TCP header of the new packet */ - uint32 ip_hdr_len; /* IP header length of the new packet */ - uint32 cur_framelen; - uint16 ip_total_len; /* Total length of IP packet for the new packet */ - uint32 tcp_hdr_len; /* TCP header length of the new packet */ - uint32 tcp_seq_num; /* TCP sequence number of the new packet */ - uint16 tcp_data_len; /* TCP DATA length that excludes IP and TCP headers */ - uint32 end_tcp_seq_num; /* TCP seq number of the last byte in the new packet */ - tcpack_sup_module_t *tcpack_sup_mod; - tcpdata_info_t *tcpdata_info = NULL; - tdata_psh_info_t *tdata_psh_info; - - int i; - bool ret = FALSE; - - if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) - goto exit; - - ether_hdr = PKTDATA(dhdp->osh, pkt); - cur_framelen = PKTLEN(dhdp->osh, pkt); - - ether_type = ether_hdr[12] << 8 | ether_hdr[13]; - - if (ether_type != ETHER_TYPE_IP) { - DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", - __FUNCTION__, __LINE__, ether_type)); - goto exit; - } - - DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, ether_type)); - - ip_hdr = ether_hdr + ETHER_HDR_LEN; - cur_framelen -= ETHER_HDR_LEN; - - ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); - - ip_hdr_len = IPV4_HLEN(ip_hdr); - if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { - DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", - __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr))); - goto exit; - } - - tcp_hdr = ip_hdr + ip_hdr_len; - cur_framelen -= ip_hdr_len; - - ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); - - DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); - - ip_total_len = ntoh16_ua(&ip_hdr[IPV4_PKTLEN_OFFSET]); - tcp_hdr_len = 4 * TCP_HDRLEN(tcp_hdr[TCP_HLEN_OFFSET]); - - /* This packet is mere TCP ACK, so do nothing */ - if (ip_total_len == ip_hdr_len + tcp_hdr_len) { - DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__, __LINE__)); - goto exit; - } - - ASSERT(ip_total_len > ip_hdr_len + tcp_hdr_len); - - if ((tcp_hdr[TCP_FLAGS_OFFSET] & TCP_FLAG_PSH) == 0) { - DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__, __LINE__)); - goto exit; - } - - DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d, flag 0x%x\n", - __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), - tcp_hdr[TCP_FLAGS_OFFSET])); - - dhd_os_tcpacklock(dhdp); - tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */ - i = 0; - while (i < tcpack_sup_mod->tcpdata_info_cnt) { - tcpdata_info_t *tdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; - uint32 now_in_ms = OSL_SYSUPTIME(); - DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, i, - IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->src_ip_addr)), - IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->dst_ip_addr)), - ntoh16_ua(tdata_info_tmp->src_tcp_port), - ntoh16_ua(tdata_info_tmp->dst_tcp_port))); - - /* If both IP address and TCP port number match, we found it so break. */ - if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], tdata_info_tmp->src_ip_addr, - IPV4_ADDR_LEN) == 0 && - memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET], tdata_info_tmp->dst_ip_addr, - IPV4_ADDR_LEN) == 0 && - memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], tdata_info_tmp->src_tcp_port, - TCP_PORT_LEN) == 0 && - memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET], tdata_info_tmp->dst_tcp_port, - TCP_PORT_LEN) == 0) { - tcpdata_info = tdata_info_tmp; - tcpdata_info->last_used_time = now_in_ms; - break; - } - - if (now_in_ms - tdata_info_tmp->last_used_time > TCPDATA_INFO_TIMEOUT) { - tdata_psh_info_t *tdata_psh_info_tmp; - tcpdata_info_t *last_tdata_info; - - while ((tdata_psh_info_tmp = tdata_info_tmp->tdata_psh_info_head)) { - tdata_info_tmp->tdata_psh_info_head = tdata_psh_info_tmp->next; - tdata_psh_info_tmp->next = NULL; - DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n", - __FUNCTION__, __LINE__, tdata_psh_info_tmp->end_seq)); - _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info_tmp); - } -#ifdef DHDTCPACK_SUP_DBG - DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - tcpack_sup_mod->tcpdata_info_cnt--; - ASSERT(tcpack_sup_mod->tcpdata_info_cnt >= 0); - - last_tdata_info = - &tcpack_sup_mod->tcpdata_info_tbl[tcpack_sup_mod->tcpdata_info_cnt]; - if (i < tcpack_sup_mod->tcpdata_info_cnt) { - ASSERT(last_tdata_info != tdata_info_tmp); - bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t)); - } - bzero(last_tdata_info, sizeof(tcpdata_info_t)); - DHD_INFO(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt)); - /* Don't increase "i" here, so that the prev last tcpdata_info is checked */ - } else - i++; - } - - tcp_seq_num = ntoh32_ua(&tcp_hdr[TCP_SEQ_NUM_OFFSET]); - tcp_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len; - end_tcp_seq_num = tcp_seq_num + tcp_data_len; - - if (tcpdata_info == NULL) { - ASSERT(i == tcpack_sup_mod->tcpdata_info_cnt); - if (i >= TCPDATA_INFO_MAXNUM) { - DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); - dhd_os_tcpackunlock(dhdp); - goto exit; - } - tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; - - /* No TCP flow with the same IP addr and TCP port is found - * in tcp_data_info_tbl. So add this flow to the table. - */ - DHD_INFO(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - bcopy(&ip_hdr[IPV4_SRC_IP_OFFSET], tcpdata_info->src_ip_addr, - IPV4_ADDR_LEN); - bcopy(&ip_hdr[IPV4_DEST_IP_OFFSET], tcpdata_info->dst_ip_addr, - IPV4_ADDR_LEN); - bcopy(&tcp_hdr[TCP_SRC_PORT_OFFSET], tcpdata_info->src_tcp_port, - TCP_PORT_LEN); - bcopy(&tcp_hdr[TCP_DEST_PORT_OFFSET], tcpdata_info->dst_tcp_port, - TCP_PORT_LEN); - - tcpdata_info->last_used_time = OSL_SYSUPTIME(); - tcpack_sup_mod->tcpdata_info_cnt++; - } - - ASSERT(tcpdata_info != NULL); - - tdata_psh_info = _tdata_psh_info_pool_deq(tcpack_sup_mod); -#ifdef DHDTCPACK_SUP_DBG - DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - - if (tdata_psh_info == NULL) { - DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp); - goto exit; - } - tdata_psh_info->end_seq = end_tcp_seq_num; - -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[4]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - - DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n", - __FUNCTION__, __LINE__, tdata_psh_info->end_seq)); - - ASSERT(tdata_psh_info->next == NULL); - - if (tcpdata_info->tdata_psh_info_head == NULL) - tcpdata_info->tdata_psh_info_head = tdata_psh_info; - else { - ASSERT(tcpdata_info->tdata_psh_info_tail); - tcpdata_info->tdata_psh_info_tail->next = tdata_psh_info; - } - tcpdata_info->tdata_psh_info_tail = tdata_psh_info; - - dhd_os_tcpackunlock(dhdp); - -exit: - return ret; -} - -bool -dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx) -{ - uint8 *new_ether_hdr; /* Ethernet header of the new packet */ - uint16 new_ether_type; /* Ethernet type of the new packet */ - uint8 *new_ip_hdr; /* IP header of the new packet */ - uint8 *new_tcp_hdr; /* TCP header of the new packet */ - uint32 new_ip_hdr_len; /* IP header length of the new packet */ - uint32 cur_framelen; - uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ - uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ - uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ - tcpack_sup_module_t *tcpack_sup_mod; - tcpack_info_t *tcpack_info_tbl; - int i, free_slot = TCPACK_INFO_MAXNUM; - bool hold = FALSE; - - if (dhdp->tcpack_sup_mode != TCPACK_SUP_HOLD) { - goto exit; - } - - if (dhdp->tcpack_sup_ratio == 1) { - goto exit; - } - - new_ether_hdr = PKTDATA(dhdp->osh, pkt); - cur_framelen = PKTLEN(dhdp->osh, pkt); - - if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { - DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", - __FUNCTION__, __LINE__, cur_framelen)); - goto exit; - } - - new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; - - if (new_ether_type != ETHER_TYPE_IP) { - DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", - __FUNCTION__, __LINE__, new_ether_type)); - goto exit; - } - - DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); - - new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; - cur_framelen -= ETHER_HDR_LEN; - - ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); - - new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); - if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { - DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", - __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); - goto exit; - } - - new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; - cur_framelen -= new_ip_hdr_len; - - ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); - - DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); - - /* is it an ack ? Allow only ACK flag, not to suppress others. */ - if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { - DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", - __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); - goto exit; - } - - new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); - new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); - - /* This packet has TCP data, so just send */ - if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { - DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); - goto exit; - } - - ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); - - new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - DHD_TRACE(("%s %d: TCP ACK with zero DATA length" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", - __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ - dhd_os_tcpacklock(dhdp); - - tcpack_sup_mod = dhdp->tcpack_sup_module; - tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - hold = TRUE; - - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { - void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ - uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; - uint32 old_ip_hdr_len, old_tcp_hdr_len; - uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ - - if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { - if (free_slot == TCPACK_INFO_MAXNUM) { - free_slot = i; - } - continue; - } - - if (PKTDATA(dhdp->osh, oldpkt) == NULL) { - DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d\n", - __FUNCTION__, __LINE__, i)); - hold = FALSE; - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; - old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; - old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); - old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; - old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); - - DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* If either of IP address or TCP port number does not match, skip. */ - if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], - &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || - memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], - &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) { - continue; - } - - old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - if (IS_TCPSEQ_GE(new_tcp_ack_num, old_tcpack_num)) { - tcpack_info_tbl[i].supp_cnt++; - if (tcpack_info_tbl[i].supp_cnt >= dhdp->tcpack_sup_ratio) { - tcpack_info_tbl[i].pkt_in_q = NULL; - tcpack_info_tbl[i].pkt_ether_hdr = NULL; - tcpack_info_tbl[i].ifidx = 0; - tcpack_info_tbl[i].supp_cnt = 0; - hold = FALSE; - } else { - tcpack_info_tbl[i].pkt_in_q = pkt; - tcpack_info_tbl[i].pkt_ether_hdr = new_ether_hdr; - tcpack_info_tbl[i].ifidx = ifidx; - } - PKTFREE(dhdp->osh, oldpkt, TRUE); - } else { - PKTFREE(dhdp->osh, pkt, TRUE); - } - dhd_os_tcpackunlock(dhdp); - - if (!hold) { - del_timer_sync(&tcpack_info_tbl[i].timer); - } - goto exit; - } - - if (free_slot < TCPACK_INFO_MAXNUM) { - /* No TCPACK packet with the same IP addr and TCP port is found - * in tcp_ack_info_tbl. So add this packet to the table. - */ - DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", - __FUNCTION__, __LINE__, pkt, new_ether_hdr, - free_slot)); - - tcpack_info_tbl[free_slot].pkt_in_q = pkt; - tcpack_info_tbl[free_slot].pkt_ether_hdr = new_ether_hdr; - tcpack_info_tbl[free_slot].ifidx = ifidx; - tcpack_info_tbl[free_slot].supp_cnt = 1; - mod_timer(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer, - jiffies + msecs_to_jiffies(dhdp->tcpack_sup_delay)); - tcpack_sup_mod->tcpack_info_cnt++; - } else { - DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", - __FUNCTION__, __LINE__)); - } - dhd_os_tcpackunlock(dhdp); - -exit: - return hold; -} -#endif /* DHDTCPACK_SUPPRESS */ diff --git a/drivers/net/wireless/bcmdhd/dhd_ip.h b/drivers/net/wireless/bcmdhd/dhd_ip.h deleted file mode 100644 index af715710f474..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_ip.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Header file describing the common ip parser function. - * - * Provides type definitions and function prototypes used to parse ip packet. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_ip.h 502735 2014-09-16 00:53:02Z $ - */ - -#ifndef _dhd_ip_h_ -#define _dhd_ip_h_ - -#ifdef DHDTCPACK_SUPPRESS -#include -#include -#include -#endif /* DHDTCPACK_SUPPRESS */ - -typedef enum pkt_frag -{ - DHD_PKT_FRAG_NONE = 0, - DHD_PKT_FRAG_FIRST, - DHD_PKT_FRAG_CONT, - DHD_PKT_FRAG_LAST -} pkt_frag_t; - -extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p); -extern bool pkt_is_dhcp(osl_t *osh, void *p); - -#ifdef DHDTCPACK_SUPPRESS -#define TCPACKSZMIN (ETHER_HDR_LEN + IPV4_MIN_HEADER_LEN + TCP_MIN_HEADER_LEN) -/* Size of MAX possible TCP ACK packet. Extra bytes for IP/TCP option fields */ -#define TCPACKSZMAX (TCPACKSZMIN + 100) - -/* Max number of TCP streams that have own src/dst IP addrs and TCP ports */ -#define TCPACK_INFO_MAXNUM 4 -#define TCPDATA_INFO_MAXNUM 4 -#define TCPDATA_PSH_INFO_MAXNUM (8 * TCPDATA_INFO_MAXNUM) - -#define TCPDATA_INFO_TIMEOUT 5000 /* Remove tcpdata_info if inactive for this time (in ms) */ - -#define TCPACK_SUPP_RATIO 3 -#define TCPACK_DELAY_TIME 10 /* ms */ - -extern int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 on); -extern void dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp); -extern int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt); -extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt); -extern bool dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt); -extern bool dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx); -/* #define DHDTCPACK_SUP_DBG */ -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) -extern counter_tbl_t tack_tbl; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ -#endif /* DHDTCPACK_SUPPRESS */ - -#endif /* _dhd_ip_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c deleted file mode 100644 index 6282ed582980..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ /dev/null @@ -1,10889 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Linux-specific network interface - * Basically selected code segments from usb-cdc.c and usb-rndis.c - * - * Copyright (C) 1999-2017, Broadcom Corporation - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux.c 718504 2017-08-31 02:38:08Z $ - */ - -#include -#include -#include -#ifdef SHOW_LOGTRACE -#include -#include -#endif /* SHOW_LOGTRACE */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef ENABLE_ADAPTIVE_SCHED -#include -#endif /* ENABLE_ADAPTIVE_SCHED */ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#ifdef DHD_L2_FILTER -#include -#endif -#include - -#include -#include -#include -#include -#ifdef PCIE_FULL_DONGLE -#include -#endif -#include -#include -#include -#ifdef CONFIG_HAS_WAKELOCK -#include -#endif -#ifdef WL_CFG80211 -#include -#endif -#ifdef PNO_SUPPORT -#include -#endif -#ifdef RTT_SUPPORT -#include -#endif - -#ifdef CONFIG_COMPAT -#include -#endif - -#ifdef DHD_WMF -#include -#endif /* DHD_WMF */ - -#ifdef AMPDU_VO_ENABLE -#include -#endif /* AMPDU_VO_ENABLE */ -#ifdef DHDTCPACK_SUPPRESS -#include -#endif /* DHDTCPACK_SUPPRESS */ - - -#ifdef WLMEDIA_HTSF -#include -#include - -#define HTSF_MINLEN 200 /* min. packet length to timestamp */ -#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ -#define TSMAX 1000 /* max no. of timing record kept */ -#define NUMBIN 34 - -static uint32 tsidx = 0; -static uint32 htsf_seqnum = 0; -uint32 tsfsync; -struct timeval tsync; -static uint32 tsport = 5010; - -typedef struct histo_ { - uint32 bin[NUMBIN]; -} histo_t; - -#if !ISPOWEROF2(DHD_SDALIGN) -#error DHD_SDALIGN is not a power of 2! -#endif - -static histo_t vi_d1, vi_d2, vi_d3, vi_d4; -#endif /* WLMEDIA_HTSF */ - - - -#if defined(SOFTAP) -extern bool ap_cfg_running; -extern bool ap_fw_loaded; -#endif - - -#ifdef ENABLE_ADAPTIVE_SCHED -#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */ -#ifndef CUSTOM_CPUFREQ_THRESH -#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH -#endif /* CUSTOM_CPUFREQ_THRESH */ -#endif /* ENABLE_ADAPTIVE_SCHED */ - -/* enable HOSTIP cache update from the host side when an eth0:N is up */ -#define AOE_IP_ALIAS_SUPPORT 1 - -#ifdef BCM_FD_AGGR -#include -#include -#endif -#ifdef PROP_TXSTATUS -#include -#include -#endif - -#include - -#include - -#ifdef SOMC_MIMO -#define SOMC_TXPWR_5G 0x20 -#define SOMC_TXPWR_OVERRIDE 0x80 -#endif - -/* Maximum STA per radio */ -#define DHD_MAX_STA 32 - - -const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; -const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; -#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] - -#ifdef ARP_OFFLOAD_SUPPORT -void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); -static int dhd_inetaddr_notifier_call(struct notifier_block *this, - unsigned long event, void *ptr); -static struct notifier_block dhd_inetaddr_notifier = { - .notifier_call = dhd_inetaddr_notifier_call -}; -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool dhd_inetaddr_notifier_registered = FALSE; -#endif /* ARP_OFFLOAD_SUPPORT */ - -#ifdef CONFIG_IPV6 -static int dhd_inet6addr_notifier_call(struct notifier_block *this, - unsigned long event, void *ptr); -static struct notifier_block dhd_inet6addr_notifier = { - .notifier_call = dhd_inet6addr_notifier_call -}; -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool dhd_inet6addr_notifier_registered = FALSE; -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -#include -volatile bool dhd_mmc_suspend = FALSE; -DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - -#if defined(OOB_INTR_ONLY) -extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -static void dhd_hang_process(void *dhd_info, void *event_data, u8 event); -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -MODULE_LICENSE("GPL and additional rights"); -#endif /* LinuxVer */ - -#include - -#ifdef BCM_FD_AGGR -#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) -#else -#ifndef PROP_TXSTATUS -#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) -#else -#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) -#endif -#endif /* BCM_FD_AGGR */ - -#ifdef PROP_TXSTATUS -extern bool dhd_wlfc_skip_fc(void); -extern void dhd_wlfc_plat_init(void *dhd); -extern void dhd_wlfc_plat_deinit(void *dhd); -#endif /* PROP_TXSTATUS */ - -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) -const char * -print_tainted() -{ - return ""; -} -#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -#include -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ - -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); - -#ifdef PKT_FILTER_SUPPORT -extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); -extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id); -#endif - - -#ifdef READ_MACADDR -extern int dhd_read_macaddr(struct dhd_info *dhd); -#else -static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; } -#endif -#ifdef WRITE_MACADDR -extern int dhd_write_macaddr(struct ether_addr *mac); -#else -static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; } -#endif - - - - -#if defined(DHD_DEBUG) -static void dhd_mem_dump(void *dhd_info, void *event_info, u8 event); -#endif /* DHD_DEBUG */ - -static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused); -static struct notifier_block dhd_reboot_notifier = { - .notifier_call = dhd_reboot_callback, - .priority = 1, -}; - - -typedef struct dhd_if_event { - struct list_head list; - wl_event_data_if_t event; - char name[IFNAMSIZ+1]; - uint8 mac[ETHER_ADDR_LEN]; -} dhd_if_event_t; - -/* Interface control information */ -typedef struct dhd_if { - struct dhd_info *info; /* back pointer to dhd_info */ - /* OS/stack specifics */ - struct net_device *net; - int idx; /* iface idx in dongle */ - uint subunit; /* subunit */ - uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ - bool set_macaddress; - bool set_multicast; - uint8 bssidx; /* bsscfg index for the interface */ - bool attached; /* Delayed attachment when unset */ - bool txflowcontrol; /* Per interface flow control indicator */ - char name[IFNAMSIZ+1]; /* linux interface name */ - struct net_device_stats stats; -#ifdef DHD_WMF - dhd_wmf_t wmf; /* per bsscfg wmf setting */ -#endif /* DHD_WMF */ -#ifdef PCIE_FULL_DONGLE - struct list_head sta_list; /* sll of associated stations */ -#if !defined(BCM_GMAC3) - spinlock_t sta_list_lock; /* lock for manipulating sll */ -#endif /* ! BCM_GMAC3 */ -#endif /* PCIE_FULL_DONGLE */ - uint32 ap_isolate; /* ap-isolation settings */ -} dhd_if_t; - -#ifdef WLMEDIA_HTSF -typedef struct { - uint32 low; - uint32 high; -} tsf_t; - -typedef struct { - uint32 last_cycle; - uint32 last_sec; - uint32 last_tsf; - uint32 coef; /* scaling factor */ - uint32 coefdec1; /* first decimal */ - uint32 coefdec2; /* second decimal */ -} htsf_t; - -typedef struct { - uint32 t1; - uint32 t2; - uint32 t3; - uint32 t4; -} tstamp_t; - -static tstamp_t ts[TSMAX]; -static tstamp_t maxdelayts; -static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; - -#endif /* WLMEDIA_HTSF */ - -struct ipv6_work_info_t { - uint8 if_idx; - char ipv6_addr[16]; - unsigned long event; -}; - - -#if defined(DHD_DEBUG) -typedef struct dhd_dump { - uint8 *buf; - int bufsize; -} dhd_dump_t; -#endif /* DHD_DEBUG */ - -/* When Perimeter locks are deployed, any blocking calls must be preceeded - * with a PERIM UNLOCK and followed by a PERIM LOCK. - * Examples of blocking calls are: schedule_timeout(), down_interruptible(), - * wait_event_timeout(). - */ - -/* Local private structure (extension of pub) */ -typedef struct dhd_info { - dhd_pub_t pub; - dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */ - - void *adapter; /* adapter information, interrupt, fw path etc. */ - char fw_path[PATH_MAX]; /* path to firmware image */ - char nv_path[PATH_MAX]; /* path to nvram vars file */ - - struct semaphore proto_sem; -#ifdef PROP_TXSTATUS - spinlock_t wlfc_spinlock; - -#endif /* PROP_TXSTATUS */ -#ifdef WLMEDIA_HTSF - htsf_t htsf; -#endif - wait_queue_head_t ioctl_resp_wait; - wait_queue_head_t d3ack_wait; - uint32 default_wd_interval; - - struct timer_list timer; - bool wd_timer_valid; - struct tasklet_struct tasklet; - spinlock_t sdlock; - spinlock_t txqlock; - spinlock_t dhd_lock; - - struct semaphore sdsem; - tsk_ctl_t thr_dpc_ctl; - tsk_ctl_t thr_wdt_ctl; - - tsk_ctl_t thr_rxf_ctl; - spinlock_t rxf_lock; - bool rxthread_enabled; - - /* Wakelocks */ -#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - struct wake_lock wl_wifi; /* Wifi wakelock */ - struct wake_lock wl_rxwake; /* Wifi rx wakelock */ - struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */ - struct wake_lock wl_wdwake; /* Wifi wd wakelock */ - struct wake_lock wl_evtwake; /* Wifi event wakelock */ - struct wake_lock wl_txflwake; /* Wifi tx flow wakelock */ -#ifdef BCMPCIE_OOB_HOST_WAKE - struct wake_lock wl_intrwake; /* Host wakeup wakelock */ -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#endif /* CONFIG_HAS_WAKELOCK && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - /* net_device interface lock, prevent race conditions among net_dev interface - * calls and wifi_on or wifi_off - */ - struct mutex dhd_net_if_mutex; - struct mutex dhd_suspend_mutex; -#endif - spinlock_t wakelock_spinlock; - spinlock_t wakelock_evt_spinlock; - uint32 wakelock_event_counter; - uint32 wakelock_counter; - int wakelock_wd_counter; - int wakelock_rx_timeout_enable; - int wakelock_ctrl_timeout_enable; - bool waive_wakelock; - uint32 wakelock_before_waive; - - /* Thread to issue ioctl for multicast */ - wait_queue_head_t ctrl_wait; - atomic_t pend_8021x_cnt; - dhd_attach_states_t dhd_state; -#ifdef SHOW_LOGTRACE - dhd_event_log_t event_data; -#endif /* SHOW_LOGTRACE */ - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - struct early_suspend early_suspend; -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -#ifdef ARP_OFFLOAD_SUPPORT - u32 pend_ipaddr; -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef BCM_FD_AGGR - void *rpc_th; - void *rpc_osh; - struct timer_list rpcth_timer; - bool rpcth_timer_active; - bool fdaggr; -#endif -#ifdef DHDTCPACK_SUPPRESS - spinlock_t tcpack_lock; -#endif /* DHDTCPACK_SUPPRESS */ - void *dhd_deferred_wq; -#ifdef DEBUG_CPU_FREQ - struct notifier_block freq_trans; - int __percpu *new_freq; -#endif - unsigned int unit; - struct notifier_block pm_notifier; -#if defined(BCMPCIE) && defined(CUSTOMER_HW5) - bool register_if_done; -#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ - struct kobject dhd_kobj; -} dhd_info_t; - -#define DHDIF_FWDER(dhdif) FALSE - -/* Flag to indicate if we should download firmware on driver load */ -uint dhd_download_fw_on_driverload = TRUE; - -/* Definitions to provide path to the firmware and nvram - * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" - */ -char firmware_path[MOD_PARAM_PATHLEN]; -char nvram_path[MOD_PARAM_PATHLEN]; - -/* backup buffer for firmware and nvram path */ -char fw_bak_path[MOD_PARAM_PATHLEN]; -char nv_bak_path[MOD_PARAM_PATHLEN]; - -/* information string to keep firmware, chio, cheip version info visiable from log */ -char info_string[MOD_PARAM_INFOLEN]; -module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); -#ifdef CONFIG_BCM_WLAN_RAMDUMP -char bcm_wlan_ver_info[BCM_WLAN_CRASH_REASON_LEN]; -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ -int op_mode = 0; -int disable_proptx = 0; -module_param(op_mode, int, 0644); -extern int wl_control_wl_start(struct net_device *dev); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC) -struct semaphore dhd_registration_sem; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - -/* deferred handlers */ -static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event); -static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event); -static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event); -static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event); -#ifdef CONFIG_IPV6 -static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event); -#endif -#if defined(DHD_TRACE_WAKE_LOCK) -static void dhd_wk_lock_trace_init(struct dhd_info *dhd); -static void dhd_wk_lock_trace_deinit(struct dhd_info *dhd); -#endif /* DHD_TRACE_WAKE_LOCK */ - -/* Functions to manage sysfs interface for dhd */ -static int dhd_sysfs_init(dhd_info_t *dhd); -static void dhd_sysfs_exit(dhd_info_t *dhd); - -#ifdef WL_CFG80211 -extern void dhd_netdev_free(struct net_device *ndev); -#endif /* WL_CFG80211 */ - -/* Error bits */ -module_param(dhd_msg_level, int, 0); - -#ifdef ARP_OFFLOAD_SUPPORT -/* ARP offload enable */ -uint dhd_arp_enable = TRUE; -module_param(dhd_arp_enable, uint, 0); - -/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ - -uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; - -module_param(dhd_arp_mode, uint, 0); -#endif /* ARP_OFFLOAD_SUPPORT */ - -/* Disable Prop tx */ -module_param(disable_proptx, int, 0644); -/* load firmware and/or nvram values from the filesystem */ -module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); -module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660); - -/* Disable VHT(11ac) mode */ -#if !defined(DISABLE_11AC) -int somc_disable_vht = 0; -module_param(somc_disable_vht, int, 0660); -#endif /* ! DISABLE_11AC */ - -/* Watchdog interval */ - -/* extend watchdog expiration to 2 seconds when DPC is running */ -#define WATCHDOG_EXTEND_INTERVAL (2000) - -uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS; -module_param(dhd_watchdog_ms, uint, 0); - -#if defined(DHD_DEBUG) -/* Console poll interval */ -uint dhd_console_ms = 0; -module_param(dhd_console_ms, uint, 0644); -#endif /* defined(DHD_DEBUG) */ - - -uint dhd_slpauto = TRUE; -module_param(dhd_slpauto, uint, 0); - -#ifdef PKT_FILTER_SUPPORT -/* Global Pkt filter enable control */ -uint dhd_pkt_filter_enable = TRUE; -module_param(dhd_pkt_filter_enable, uint, 0); -#endif - -/* Pkt filter init setup */ -uint dhd_pkt_filter_init = 0; -module_param(dhd_pkt_filter_init, uint, 0); - -/* Pkt filter mode control */ -uint dhd_master_mode = TRUE; -module_param(dhd_master_mode, uint, 0); - -int dhd_watchdog_prio = 0; -module_param(dhd_watchdog_prio, int, 0); - -/* DPC thread priority */ -int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; -module_param(dhd_dpc_prio, int, 0); - -/* RX frame thread priority */ -int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; -module_param(dhd_rxf_prio, int, 0); - -int passive_channel_skip = 0; -module_param(passive_channel_skip, int, (S_IRUSR|S_IWUSR)); - -#if !defined(BCMDHDUSB) -extern int dhd_dongle_ramsize; -module_param(dhd_dongle_ramsize, int, 0); -#endif /* BCMDHDUSB */ - -/* Keep track of number of instances */ -static int dhd_found = 0; -static int instance_base = 0; /* Starting instance number */ -module_param(instance_base, int, 0644); - - - - -/* DHD Perimiter lock only used in router with bypass forwarding. */ -#define DHD_PERIM_RADIO_INIT() do { /* noop */ } while (0) -#define DHD_PERIM_LOCK_TRY(unit, flag) do { /* noop */ } while (0) -#define DHD_PERIM_UNLOCK_TRY(unit, flag) do { /* noop */ } while (0) -#define DHD_PERIM_LOCK_ALL() do { /* noop */ } while (0) -#define DHD_PERIM_UNLOCK_ALL() do { /* noop */ } while (0) - -#ifdef PCIE_FULL_DONGLE -#if defined(BCM_GMAC3) -#define DHD_IF_STA_LIST_LOCK_INIT(ifp) do { /* noop */ } while (0) -#define DHD_IF_STA_LIST_LOCK(ifp, flags) ({ BCM_REFERENCE(flags); }) -#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) ({ BCM_REFERENCE(flags); }) -#else /* ! BCM_GMAC3 */ -#define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock) -#define DHD_IF_STA_LIST_LOCK(ifp, flags) \ - spin_lock_irqsave(&(ifp)->sta_list_lock, (flags)) -#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \ - spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags)) -#endif /* ! BCM_GMAC3 */ -#endif /* PCIE_FULL_DONGLE */ - -/* Control fw roaming */ -#ifdef BCMCCX -uint dhd_roam_disable = 0; -#else -uint dhd_roam_disable = 0; -#endif /* BCMCCX */ - -/* Control radio state */ -uint dhd_radio_up = 1; - -/* Network inteface name */ -char iface_name[IFNAMSIZ] = {'\0'}; -module_param_string(iface_name, iface_name, IFNAMSIZ, 0); - -/* The following are specific to the SDIO dongle */ - -/* IOCTL response timeout */ -int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; - -/* Idle timeout for backplane clock */ -int dhd_idletime = DHD_IDLETIME_TICKS; -module_param(dhd_idletime, int, 0); - -/* Use polling */ -uint dhd_poll = FALSE; -module_param(dhd_poll, uint, 0); - -/* Use interrupts */ -uint dhd_intr = TRUE; -module_param(dhd_intr, uint, 0); - -/* SDIO Drive Strength (in milliamps) */ -uint dhd_sdiod_drive_strength = 6; -module_param(dhd_sdiod_drive_strength, uint, 0); - -#ifdef BCMSDIO -/* Tx/Rx bounds */ -extern uint dhd_txbound; -extern uint dhd_rxbound; -module_param(dhd_txbound, uint, 0); -module_param(dhd_rxbound, uint, 0); - -/* Deferred transmits */ -extern uint dhd_deferred_tx; -module_param(dhd_deferred_tx, uint, 0); - -#ifdef BCMDBGFS -extern void dhd_dbg_init(dhd_pub_t *dhdp); -extern void dhd_dbg_remove(void); -#endif /* BCMDBGFS */ - -#endif /* BCMSDIO */ - - -#ifdef SDTEST -/* Echo packet generator (pkts/s) */ -uint dhd_pktgen = 0; -module_param(dhd_pktgen, uint, 0); - -/* Echo packet len (0 => sawtooth, max 2040) */ -uint dhd_pktgen_len = 0; -module_param(dhd_pktgen_len, uint, 0); -#endif /* SDTEST */ - - -extern char dhd_version[]; - -int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); -static void dhd_net_if_lock_local(dhd_info_t *dhd); -static void dhd_net_if_unlock_local(dhd_info_t *dhd); -static void dhd_suspend_lock(dhd_pub_t *dhdp); -static void dhd_suspend_unlock(dhd_pub_t *dhdp); - -#ifdef WLMEDIA_HTSF -void htsf_update(dhd_info_t *dhd, void *data); -tsf_t prev_tsf, cur_tsf; - -uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); -static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); -static void dhd_dump_latency(void); -static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); -static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); -static void dhd_dump_htsfhisto(histo_t *his, char *s); -#endif /* WLMEDIA_HTSF */ - -/* Monitor interface */ -int dhd_monitor_init(void *dhd_pub); -int dhd_monitor_uninit(void); - -static void dhd_dpc(ulong data); -/* forward decl */ -extern int dhd_wait_pend8021x(struct net_device *dev); -void dhd_os_wd_timer_extend(void *bus, bool extend); - -#ifdef TOE -#ifndef BDC -#error TOE requires BDC -#endif /* !BDC */ -static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); -static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); -#endif /* TOE */ - -static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, - wl_event_msg_t *event_ptr, void **data_ptr); -#ifdef DHD_UNICAST_DHCP -static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; -static int dhd_get_pkt_ip_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr, - int *len_ptr, uint8 *prot_ptr); -static int dhd_get_pkt_ether_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr, - int *len_ptr, uint16 *et_ptr, bool *snap_ptr); - -static int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx); -#endif /* DHD_UNICAST_DHCP */ -#ifdef DHD_L2_FILTER -static int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx); -#endif -#if defined(CONFIG_PM_SLEEP) -static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) -{ - int ret = NOTIFY_DONE; - bool suspend = FALSE; - dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier); - - BCM_REFERENCE(dhdinfo); - switch (action) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - suspend = TRUE; - break; - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - suspend = FALSE; - break; - } - -#if defined(SUPPORT_P2P_GO_PS) -#ifdef PROP_TXSTATUS - if (suspend) { - DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub); - dhd_wlfc_suspend(&dhdinfo->pub); - DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub); - } else - dhd_wlfc_resume(&dhdinfo->pub); -#endif -#endif /* defined(SUPPORT_P2P_GO_PS) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ - KERNEL_VERSION(2, 6, 39)) - dhd_mmc_suspend = suspend; - smp_mb(); -#endif - - return ret; -} - -static struct notifier_block dhd_pm_notifier = { - .notifier_call = dhd_pm_callback, - .priority = 10 -}; -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool dhd_pm_notifier_registered = FALSE; - -extern int register_pm_notifier(struct notifier_block *nb); -extern int unregister_pm_notifier(struct notifier_block *nb); -#endif /* CONFIG_PM_SLEEP */ - -/* Request scheduling of the bus rx frame */ -static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb); -static void dhd_os_rxflock(dhd_pub_t *pub); -static void dhd_os_rxfunlock(dhd_pub_t *pub); - -/** priv_link is the link between netdev and the dhdif and dhd_info structs. */ -typedef struct dhd_dev_priv { - dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */ - dhd_if_t * ifp; /* cached pointer to dhd_if in netdevice priv */ - int ifidx; /* interface index */ -} dhd_dev_priv_t; - -#define DHD_DEV_PRIV_SIZE (sizeof(dhd_dev_priv_t)) -#define DHD_DEV_PRIV(dev) ((dhd_dev_priv_t *)DEV_PRIV(dev)) -#define DHD_DEV_INFO(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd) -#define DHD_DEV_IFP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp) -#define DHD_DEV_IFIDX(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx) - -/** Clear the dhd net_device's private structure. */ -static inline void -dhd_dev_priv_clear(struct net_device * dev) -{ - dhd_dev_priv_t * dev_priv; - ASSERT(dev != (struct net_device *)NULL); - dev_priv = DHD_DEV_PRIV(dev); - dev_priv->dhd = (dhd_info_t *)NULL; - dev_priv->ifp = (dhd_if_t *)NULL; - dev_priv->ifidx = DHD_BAD_IF; -} - -/** Setup the dhd net_device's private structure. */ -static inline void -dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp, - int ifidx) -{ - dhd_dev_priv_t * dev_priv; - ASSERT(dev != (struct net_device *)NULL); - dev_priv = DHD_DEV_PRIV(dev); - dev_priv->dhd = dhd; - dev_priv->ifp = ifp; - dev_priv->ifidx = ifidx; -} - -#ifdef PCIE_FULL_DONGLE - -/** Dummy objects are defined with state representing bad|down. - * Performance gains from reducing branch conditionals, instruction parallelism, - * dual issue, reducing load shadows, avail of larger pipelines. - * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer - * is accessed via the dhd_sta_t. - */ - -/* Dummy dhd_info object */ -dhd_info_t dhd_info_null = { -#if defined(BCM_GMAC3) - .fwdh = FWDER_NULL, -#endif - .pub = { - .info = &dhd_info_null, -#ifdef DHDTCPACK_SUPPRESS - .tcpack_sup_mode = TCPACK_SUP_REPLACE, -#endif /* DHDTCPACK_SUPPRESS */ - .up = FALSE, .busstate = DHD_BUS_DOWN - } -}; -#define DHD_INFO_NULL (&dhd_info_null) -#define DHD_PUB_NULL (&dhd_info_null.pub) - -/* Dummy netdevice object */ -struct net_device dhd_net_dev_null = { - .reg_state = NETREG_UNREGISTERED -}; -#define DHD_NET_DEV_NULL (&dhd_net_dev_null) - -/* Dummy dhd_if object */ -dhd_if_t dhd_if_null = { -#if defined(BCM_GMAC3) - .fwdh = FWDER_NULL, -#endif -#ifdef WMF - .wmf = { .wmf_enable = TRUE }, -#endif - .info = DHD_INFO_NULL, - .net = DHD_NET_DEV_NULL, - .idx = DHD_BAD_IF -}; -#define DHD_IF_NULL (&dhd_if_null) - -#define DHD_STA_NULL ((dhd_sta_t *)NULL) - -/** Interface STA list management. */ - -/** Fetch the dhd_if object, given the interface index in the dhd. */ -static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx); - -/** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */ -static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta); -static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp); - -/* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */ -static void dhd_if_del_sta_list(dhd_if_t * ifp); -static void dhd_if_flush_sta(dhd_if_t * ifp); - -/* Construct/Destruct a sta pool. */ -static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta); -static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta); -static void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta); - - -/* Return interface pointer */ -static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx) -{ - ASSERT(ifidx < DHD_MAX_IFS); - - if (ifidx >= DHD_MAX_IFS) - return NULL; - - return dhdp->info->iflist[ifidx]; -} - -/** Reset a dhd_sta object and free into the dhd pool. */ -static void -dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta) -{ - int prio; - - ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID)); - - ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL)); - id16_map_free(dhdp->staid_allocator, sta->idx); - for (prio = 0; prio < (int)NUMPRIO; prio++) - sta->flowid[prio] = FLOWID_INVALID; - sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */ - sta->ifidx = DHD_BAD_IF; - bzero(sta->ea.octet, ETHER_ADDR_LEN); - INIT_LIST_HEAD(&sta->list); - sta->idx = ID16_INVALID; /* implying free */ -} - -/** Allocate a dhd_sta object from the dhd pool. */ -static dhd_sta_t * -dhd_sta_alloc(dhd_pub_t * dhdp) -{ - uint16 idx; - dhd_sta_t * sta; - dhd_sta_pool_t * sta_pool; - - ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL)); - - idx = id16_map_alloc(dhdp->staid_allocator); - if (idx == ID16_INVALID) { - DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__)); - return DHD_STA_NULL; - } - - sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool); - sta = &sta_pool[idx]; - - ASSERT((sta->idx == ID16_INVALID) && - (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF)); - sta->idx = idx; /* implying allocated */ - - return sta; -} - -/** Delete all STAs in an interface's STA list. */ -static void -dhd_if_del_sta_list(dhd_if_t *ifp) -{ - dhd_sta_t *sta, *next; - unsigned long flags; - - DHD_IF_STA_LIST_LOCK(ifp, flags); - - list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { -#if defined(BCM_GMAC3) - if (ifp->fwdh) { - /* Remove sta from WOFA forwarder. */ - fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (wofa_t)sta); - } -#endif /* BCM_GMAC3 */ - list_del(&sta->list); - dhd_sta_free(&ifp->info->pub, sta); - } - - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - - return; -} - -/** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */ -static void -dhd_if_flush_sta(dhd_if_t * ifp) -{ -#if defined(BCM_GMAC3) - - if (ifp && (ifp->fwdh != FWDER_NULL)) { - dhd_sta_t *sta, *next; - unsigned long flags; - - DHD_IF_STA_LIST_LOCK(ifp, flags); - - list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { - /* Remove any sta entry from WOFA forwarder. */ - fwder_flush(ifp->fwdh, (wofa_t)sta); - } - - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - } -#endif /* BCM_GMAC3 */ -} - -/** Construct a pool of dhd_sta_t objects to be used by interfaces. */ -static int -dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) -{ - int idx, sta_pool_memsz; - dhd_sta_t * sta; - dhd_sta_pool_t * sta_pool; - void * staid_allocator; - - ASSERT(dhdp != (dhd_pub_t *)NULL); - ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL)); - - /* dhd_sta objects per radio are managed in a table. id#0 reserved. */ - staid_allocator = id16_map_init(dhdp->osh, max_sta, 1); - if (staid_allocator == NULL) { - DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__)); - return BCME_ERROR; - } - - /* Pre allocate a pool of dhd_sta objects (one extra). */ - sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */ - sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz); - if (sta_pool == NULL) { - DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__)); - id16_map_fini(dhdp->osh, staid_allocator); - return BCME_ERROR; - } - - dhdp->sta_pool = sta_pool; - dhdp->staid_allocator = staid_allocator; - - /* Initialize all sta(s) for the pre-allocated free pool. */ - bzero((uchar *)sta_pool, sta_pool_memsz); - for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */ - sta = &sta_pool[idx]; - sta->idx = id16_map_alloc(staid_allocator); - ASSERT(sta->idx <= max_sta); - } - /* Now place them into the pre-allocated free pool. */ - for (idx = 1; idx <= max_sta; idx++) { - sta = &sta_pool[idx]; - dhd_sta_free(dhdp, sta); - } - - return BCME_OK; -} - -/** Destruct the pool of dhd_sta_t objects. - * Caller must ensure that no STA objects are currently associated with an if. - */ -static void -dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) -{ - dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool; - - if (sta_pool) { - int idx; - int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); - for (idx = 1; idx <= max_sta; idx++) { - ASSERT(sta_pool[idx].ifp == DHD_IF_NULL); - ASSERT(sta_pool[idx].idx == ID16_INVALID); - } - MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz); - dhdp->sta_pool = NULL; - } - - id16_map_fini(dhdp->osh, dhdp->staid_allocator); - dhdp->staid_allocator = NULL; -} - -/* Clear the pool of dhd_sta_t objects for built-in type driver */ -static void -dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) -{ - int idx, sta_pool_memsz; - dhd_sta_t * sta; - dhd_sta_pool_t * sta_pool; - void *staid_allocator; - - if (!dhdp) { - DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); - return; - } - - sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool; - staid_allocator = dhdp->staid_allocator; - - if (!sta_pool) { - DHD_ERROR(("%s: sta_pool is NULL\n", __FUNCTION__)); - return; - } - - if (!staid_allocator) { - DHD_ERROR(("%s: staid_allocator is NULL\n", __FUNCTION__)); - return; - } - - /* clear free pool */ - sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); - bzero((uchar *)sta_pool, sta_pool_memsz); - - /* dhd_sta objects per radio are managed in a table. id#0 reserved. */ - id16_map_clear(staid_allocator, max_sta, 1); - - /* Initialize all sta(s) for the pre-allocated free pool. */ - for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */ - sta = &sta_pool[idx]; - sta->idx = id16_map_alloc(staid_allocator); - ASSERT(sta->idx <= max_sta); - } - /* Now place them into the pre-allocated free pool. */ - for (idx = 1; idx <= max_sta; idx++) { - sta = &sta_pool[idx]; - dhd_sta_free(dhdp, sta); - } -} - -/** Find STA with MAC address ea in an interface's STA list. */ -dhd_sta_t * -dhd_find_sta(void *pub, int ifidx, void *ea) -{ - dhd_sta_t *sta, *next; - dhd_if_t *ifp; - unsigned long flags; - - ASSERT(ea != NULL); - ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); - if (ifp == NULL) - return DHD_STA_NULL; - - DHD_IF_STA_LIST_LOCK(ifp, flags); - - list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { - if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - return sta; - } - } - - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - - return DHD_STA_NULL; -} - -/** Add STA into the interface's STA list. */ -dhd_sta_t * -dhd_add_sta(void *pub, int ifidx, void *ea) -{ - dhd_sta_t *sta; - dhd_if_t *ifp; - unsigned long flags; - - ASSERT(ea != NULL); - ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); - if (ifp == NULL) - return DHD_STA_NULL; - - sta = dhd_sta_alloc((dhd_pub_t *)pub); - if (sta == DHD_STA_NULL) { - DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__)); - return DHD_STA_NULL; - } - - memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN); - - /* link the sta and the dhd interface */ - sta->ifp = ifp; - sta->ifidx = ifidx; - INIT_LIST_HEAD(&sta->list); - - DHD_IF_STA_LIST_LOCK(ifp, flags); - - list_add_tail(&sta->list, &ifp->sta_list); - -#if defined(BCM_GMAC3) - if (ifp->fwdh) { - ASSERT(ISALIGNED(ea, 2)); - /* Add sta to WOFA forwarder. */ - fwder_reassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta); - } -#endif /* BCM_GMAC3 */ - - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - - return sta; -} - -/** Delete STA from the interface's STA list. */ -void -dhd_del_sta(void *pub, int ifidx, void *ea) -{ - dhd_sta_t *sta, *next; - dhd_if_t *ifp; - unsigned long flags; - - ASSERT(ea != NULL); - ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); - if (ifp == NULL) - return; - - DHD_IF_STA_LIST_LOCK(ifp, flags); - - list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { - if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { -#if defined(BCM_GMAC3) - if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */ - ASSERT(ISALIGNED(ea, 2)); - fwder_deassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta); - } -#endif /* BCM_GMAC3 */ - list_del(&sta->list); - dhd_sta_free(&ifp->info->pub, sta); - } - } - - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - - return; -} - -/** Add STA if it doesn't exist. Not reentrant. */ -dhd_sta_t* -dhd_findadd_sta(void *pub, int ifidx, void *ea) -{ - dhd_sta_t *sta; - - sta = dhd_find_sta(pub, ifidx, ea); - - if (!sta) { - /* Add entry */ - sta = dhd_add_sta(pub, ifidx, ea); - } - - return sta; -} -#else -static inline void dhd_if_flush_sta(dhd_if_t * ifp) { } -static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {} -static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; } -static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {} -static inline void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) {} -dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; } -void dhd_del_sta(void *pub, int ifidx, void *ea) {} -#endif /* PCIE_FULL_DONGLE */ - - -/* Returns dhd iflist index correspondig the the bssidx provided by apps */ -int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx) -{ - dhd_if_t *ifp; - dhd_info_t *dhd = dhdp->info; - int i; - - ASSERT(bssidx < DHD_MAX_IFS); - ASSERT(dhdp); - - for (i = 0; i < DHD_MAX_IFS; i++) { - ifp = dhd->iflist[i]; - if (ifp && (ifp->bssidx == bssidx)) { - DHD_TRACE(("Index manipulated for %s from %d to %d\n", - ifp->name, bssidx, i)); - break; - } - } - return i; -} - -static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb) -{ - uint32 store_idx; - uint32 sent_idx; - - if (!skb) { - DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n")); - return BCME_ERROR; - } - - dhd_os_rxflock(dhdp); - store_idx = dhdp->store_idx; - sent_idx = dhdp->sent_idx; - if (dhdp->skbbuf[store_idx] != NULL) { - /* Make sure the previous packets are processed */ - dhd_os_rxfunlock(dhdp); - DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", - skb, store_idx, sent_idx)); - /* removed msleep here, should use wait_event_timeout if we - * want to give rx frame thread a chance to run - */ -#if defined(WAIT_DEQUEUE) - OSL_SLEEP(1); -#endif - return BCME_ERROR; - } - DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n", - skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1))); - dhdp->skbbuf[store_idx] = skb; - dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1); - dhd_os_rxfunlock(dhdp); - - return BCME_OK; -} - -static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp) -{ - uint32 store_idx; - uint32 sent_idx; - void *skb; - - dhd_os_rxflock(dhdp); - - store_idx = dhdp->store_idx; - sent_idx = dhdp->sent_idx; - skb = dhdp->skbbuf[sent_idx]; - - if (skb == NULL) { - dhd_os_rxfunlock(dhdp); - DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n", - store_idx, sent_idx)); - return NULL; - } - - dhdp->skbbuf[sent_idx] = NULL; - dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1); - - DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n", - skb, sent_idx)); - - dhd_os_rxfunlock(dhdp); - - return skb; -} - -int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - if (prepost) { /* pre process */ - dhd_read_macaddr(dhd); - } else { /* post process */ - dhd_write_macaddr(&dhd->pub.mac); - } - - return 0; -} - -#if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) -static bool -_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode) -{ - bool _apply = FALSE; - /* In case of IBSS mode, apply arp pkt filter */ - if (op_mode & DHD_FLAG_IBSS_MODE) { - _apply = TRUE; - goto exit; - } - /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */ - if ((dhd->arp_version == 1) && - (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { - _apply = TRUE; - goto exit; - } - -exit: - return _apply; -} -#endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */ - - -void dhd_set_packet_filter(dhd_pub_t *dhd) -{ -#ifdef PKT_FILTER_SUPPORT - int i; - - DHD_TRACE(("%s: enter\n", __FUNCTION__)); - if (dhd_pkt_filter_enable) { - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); - } - } -#endif /* PKT_FILTER_SUPPORT */ -} - -void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) -{ -#ifdef PKT_FILTER_SUPPORT - int i; - - DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value)); - - - /* 1 - Enable packet filter, only allow unicast packet to send up */ - /* 0 - Disable packet filter */ - if (dhd_pkt_filter_enable && (!value || - (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) - { - for (i = 0; i < dhd->pktfilter_count; i++) { -#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER - if (value && (i == DHD_ARP_FILTER_NUM) && - !_turn_on_arp_filter(dhd, dhd->op_mode)) { - DHD_TRACE(("Do not turn on ARP white list pkt filter:" - "val %d, cnt %d, op_mode 0x%x\n", - value, i, dhd->op_mode)); - continue; - } -#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - value, dhd_master_mode); - } - } -#endif /* PKT_FILTER_SUPPORT */ -} - -static int dhd_set_suspend(int value, dhd_pub_t *dhd) -{ -#ifndef SUPPORT_PM2_ONLY - int power_mode = PM_MAX; -#endif /* SUPPORT_PM2_ONLY */ - /* wl_pkt_filter_enable_t enable_parm; */ - char iovbuf[32]; - int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ -#ifndef ENABLE_FW_ROAM_SUSPEND - uint roamvar = 1; -#endif /* ENABLE_FW_ROAM_SUSPEND */ - uint nd_ra_filter = 0; - int ret = 0; - - if (!dhd) - return -ENODEV; - - - DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", - __FUNCTION__, value, dhd->in_suspend)); - - dhd_suspend_lock(dhd); - -#ifdef CUSTOM_SET_CPUCORE - DHD_TRACE(("%s set cpucore(suspend%d)\n", __FUNCTION__, value)); - /* set specific cpucore */ - dhd_set_cpucore(dhd, TRUE); -#endif /* CUSTOM_SET_CPUCORE */ - if (dhd->up) { - if (value && dhd->in_suspend) { -#ifdef PKT_FILTER_SUPPORT - dhd->early_suspended = 1; -#endif - /* Kernel suspended */ - DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); - -#ifndef SUPPORT_PM2_ONLY - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); -#endif /* SUPPORT_PM2_ONLY */ - - /* Enable packet filter, only allow unicast packet to send up */ - dhd_enable_packet_filter(1, dhd); - - - /* If DTIM skip is set up as default, force it to wake - * each third DTIM for better power savings. Note that - * one side effect is a chance to miss BC/MC packet. - */ - bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), - TRUE, 0) < 0) - DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); - -#ifndef ENABLE_FW_ROAM_SUSPEND - /* Disable firmware roaming during suspend */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, - iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* ENABLE_FW_ROAM_SUSPEND */ - if (FW_SUPPORTED(dhd, ndoe)) { - /* enable IPv6 RA filter in firmware during suspend */ - nd_ra_filter = 1; - bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4, - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("failed to set nd_ra_filter (%d)\n", - ret)); - } - } else { -#ifdef PKT_FILTER_SUPPORT - dhd->early_suspended = 0; -#endif - /* Kernel resumed */ - DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__)); - -#ifndef SUPPORT_PM2_ONLY - power_mode = PM_FAST; - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); -#endif /* SUPPORT_PM2_ONLY */ -#ifdef PKT_FILTER_SUPPORT - /* disable pkt filter */ - dhd_enable_packet_filter(0, dhd); -#endif /* PKT_FILTER_SUPPORT */ - - /* restore pre-suspend setting for dtim_skip */ - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#ifndef ENABLE_FW_ROAM_SUSPEND - roamvar = dhd_roam_disable; - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, - sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* ENABLE_FW_ROAM_SUSPEND */ - if (FW_SUPPORTED(dhd, ndoe)) { - /* disable IPv6 RA filter in firmware during suspend */ - nd_ra_filter = 0; - bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4, - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("failed to set nd_ra_filter (%d)\n", - ret)); - } - } - } - dhd_suspend_unlock(dhd); - - return 0; -} - -static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) -{ - dhd_pub_t *dhdp = &dhd->pub; - int ret = 0; - - DHD_OS_WAKE_LOCK(dhdp); - DHD_PERIM_LOCK(dhdp); - - /* Set flag when early suspend was called */ - dhdp->in_suspend = val; - if ((force || !dhdp->suspend_disable_flag) && - dhd_support_sta_mode(dhdp)) - { - ret = dhd_set_suspend(val, dhdp); - } - - DHD_PERIM_UNLOCK(dhdp); - DHD_OS_WAKE_UNLOCK(dhdp); - return ret; -} - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -static void dhd_early_suspend(struct early_suspend *h) -{ - struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); - - if (dhd) - dhd_suspend_resume_helper(dhd, 1, 0); -} - -static void dhd_late_resume(struct early_suspend *h) -{ - struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); - - if (dhd) - dhd_suspend_resume_helper(dhd, 0, 0); -} -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -/* - * Generalized timeout mechanism. Uses spin sleep with exponential back-off until - * the sleep time reaches one jiffy, then switches over to task delay. Usage: - * - * dhd_timeout_start(&tmo, usec); - * while (!dhd_timeout_expired(&tmo)) - * if (poll_something()) - * break; - * if (dhd_timeout_expired(&tmo)) - * fatal(); - */ - -void -dhd_timeout_start(dhd_timeout_t *tmo, uint usec) -{ - tmo->limit = usec; - tmo->increment = 0; - tmo->elapsed = 0; - tmo->tick = jiffies_to_usecs(1); -} - -int -dhd_timeout_expired(dhd_timeout_t *tmo) -{ - /* Does nothing the first call */ - if (tmo->increment == 0) { - tmo->increment = 1; - return 0; - } - - if (tmo->elapsed >= tmo->limit) - return 1; - - /* Add the delay that's about to take place */ - tmo->elapsed += tmo->increment; - - if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) { - OSL_DELAY(tmo->increment); - tmo->increment *= 2; - if (tmo->increment > tmo->tick) - tmo->increment = tmo->tick; - } else { - wait_queue_head_t delay_wait; - DECLARE_WAITQUEUE(wait, current); - init_waitqueue_head(&delay_wait); - add_wait_queue(&delay_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - (void)schedule_timeout(1); - remove_wait_queue(&delay_wait, &wait); - set_current_state(TASK_RUNNING); - } - - return 0; -} - -int -dhd_net2idx(dhd_info_t *dhd, struct net_device *net) -{ - int i = 0; - - if (!dhd) { - DHD_ERROR(("%s : DHD_BAD_IF return\n", __FUNCTION__)); - return DHD_BAD_IF; - } - while (i < DHD_MAX_IFS) { - if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net)) - return i; - i++; - } - - return DHD_BAD_IF; -} - -struct net_device * dhd_idx2net(void *pub, int ifidx) -{ - struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; - struct dhd_info *dhd_info; - - if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) - return NULL; - dhd_info = dhd_pub->info; - if (dhd_info && dhd_info->iflist[ifidx]) - return dhd_info->iflist[ifidx]->net; - return NULL; -} - -int -dhd_ifname2idx(dhd_info_t *dhd, char *name) -{ - int i = DHD_MAX_IFS; - - ASSERT(dhd); - - if (name == NULL || *name == '\0') - return 0; - - while (--i > 0) - if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ)) - break; - - DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name)); - - return i; /* default - the primary interface */ -} - -int -dhd_ifidx2hostidx(dhd_info_t *dhd, int ifidx) -{ - int i = DHD_MAX_IFS; - - ASSERT(dhd); - - while (--i > 0) - if (dhd->iflist[i] && (dhd->iflist[i]->idx == ifidx)) - break; - - DHD_TRACE(("%s: return hostidx %d for ifidx %d\n", __FUNCTION__, i, ifidx)); - - return i; /* default - the primary interface */ -} - -char * -dhd_ifname(dhd_pub_t *dhdp, int ifidx) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - ASSERT(dhd); - - if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { - DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); - return ""; - } - - if (dhd->iflist[ifidx] == NULL) { - DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); - return ""; - } - - if (dhd->iflist[ifidx]->net) - return dhd->iflist[ifidx]->net->name; - - return ""; -} - -uint8 * -dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) -{ - int i; - dhd_info_t *dhd = (dhd_info_t *)dhdp; - - ASSERT(dhd); - for (i = 0; i < DHD_MAX_IFS; i++) - if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) - return dhd->iflist[i]->mac_addr; - - return NULL; -} - - -static void -_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) -{ - struct net_device *dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - struct netdev_hw_addr *ha; -#else - struct dev_mc_list *mclist; -#endif - uint32 allmulti, cnt; - - wl_ioctl_t ioc; - char *buf, *bufp; - uint buflen; - int ret; - -#ifdef MCAST_LIST_ACCUMULATION - int i; - uint32 cnt_iface[DHD_MAX_IFS]; - cnt = 0; - allmulti = 0; - - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - dev = dhd->iflist[i]->net; - if (!dev) - continue; -#else - ASSERT(dhd && dhd->iflist[ifidx]); - dev = dhd->iflist[ifidx]->net; - if (!dev) - return; -#endif /* MCAST_LIST_ACCUMULATION */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) -#ifdef MCAST_LIST_ACCUMULATION - cnt_iface[i] = netdev_mc_count(dev); - cnt += cnt_iface[i]; -#else - cnt = netdev_mc_count(dev); -#endif /* MCAST_LIST_ACCUMULATION */ -#else -#ifdef MCAST_LIST_ACCUMULATION - cnt += dev->mc_count; -#else - cnt = dev->mc_count; -#endif /* MCAST_LIST_ACCUMULATION */ -#endif /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); -#endif - - /* Determine initial value of allmulti flag */ -#ifdef MCAST_LIST_ACCUMULATION - allmulti |= (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; - } - } -#else - allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; -#endif /* MCAST_LIST_ACCUMULATION */ - - /* Send down the multicast list first. */ - - - buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); - if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { - DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", - dhd_ifname(&dhd->pub, ifidx), cnt)); - return; - } - - strncpy(bufp, "mcast_list", buflen - 1); - bufp[buflen - 1] = '\0'; - bufp += strlen("mcast_list") + 1; - - cnt = htol32(cnt); - memcpy(bufp, &cnt, sizeof(cnt)); - bufp += sizeof(cnt); - -#ifdef MCAST_LIST_ACCUMULATION - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - DHD_TRACE(("_dhd_set_multicast_list: ifidx %d\n", i)); - dev = dhd->iflist[i]->net; -#endif /* MCAST_LIST_ACCUMULATION */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - netdev_for_each_mc_addr(ha, dev) { -#ifdef MCAST_LIST_ACCUMULATION - if (!cnt_iface[i]) -#else - if (!cnt) -#endif /* MCAST_LIST_ACCUMULATION */ - break; - memcpy(bufp, ha->addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; -#ifdef MCAST_LIST_ACCUMULATION - DHD_TRACE(("_dhd_set_multicast_list: cnt " - "%d " MACDBG "\n", - cnt_iface[i], MAC2STRDBG(ha->addr))); - cnt_iface[i]--; -#else - cnt--; -#endif /* MCAST_LIST_ACCUMULATION */ - } -#else -#ifdef MCAST_LIST_ACCUMULATION - for (mclist = dev->mc_list; (mclist && (cnt_iface[i] > 0)); - cnt_iface[i]--, mclist = mclist->next) { -#else - for (mclist = dev->mc_list; (mclist && (cnt > 0)); - cnt--, mclist = mclist->next) { -#endif /* MCAST_LIST_ACCUMULATION */ - memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; - } -#endif /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); -#endif -#ifdef MCAST_LIST_ACCUMULATION - } - } -#endif /* MCAST_LIST_ACCUMULATION */ - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = buflen; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", - dhd_ifname(&dhd->pub, ifidx), cnt)); - allmulti = cnt ? TRUE : allmulti; - } - - MFREE(dhd->pub.osh, buf, buflen); - - /* 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(allmulti); - if (!(buf = MALLOC(dhd->pub.osh, buflen))) { - DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx))); - return; - } - allmulti = htol32(allmulti); - - if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) { - DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n", - dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen)); - MFREE(dhd->pub.osh, buf, buflen); - return; - } - - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = buflen; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set allmulti %d failed\n", - dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); - } - - MFREE(dhd->pub.osh, buf, buflen); - - /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ - -#ifdef MCAST_LIST_ACCUMULATION - allmulti = 0; - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - dev = dhd->iflist[i]->net; - allmulti |= (dev->flags & IFF_PROMISC) ? TRUE : FALSE; - } - } -#else - allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; -#endif /* MCAST_LIST_ACCUMULATION */ - - allmulti = htol32(allmulti); - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_PROMISC; - ioc.buf = &allmulti; - ioc.len = sizeof(allmulti); - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set promisc %d failed\n", - dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); - } -} - -int -_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr) -{ - char buf[32]; - wl_ioctl_t ioc; - int ret; - - if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) { - DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx))); - return -1; - } - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = 32; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); - } else { - memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); - if (ifidx == 0) - memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); - } - - return ret; -} - -#ifdef SOFTAP -extern struct net_device *ap_net_dev; -extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ -#endif - -static void -dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_if_event_t *if_event = event_info; - struct net_device *ndev; - int ifidx, bssidx; - int ret; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) - struct wireless_dev *vwdev, *primary_wdev; - struct net_device *primary_ndev; -#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ - - if (event != DHD_WQ_WORK_IF_ADD) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (!if_event) { - DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - ifidx = if_event->event.ifidx; - bssidx = if_event->event.bssidx; - DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx)); - - ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name, - if_event->mac, bssidx, TRUE); - if (!ndev) { - DHD_ERROR(("%s: net device alloc failed \n", __FUNCTION__)); - goto done; - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) - vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); - if (unlikely(!vwdev)) { - WL_ERR(("Could not allocate wireless device\n")); - goto done; - } - primary_ndev = dhd->pub.info->iflist[0]->net; - primary_wdev = ndev_to_wdev(primary_ndev); - vwdev->wiphy = primary_wdev->wiphy; - vwdev->iftype = if_event->event.role; - vwdev->netdev = ndev; - ndev->ieee80211_ptr = vwdev; - SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy)); - DHD_ERROR(("virtual interface(%s) is created\n", if_event->name)); -#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ - - DHD_PERIM_UNLOCK(&dhd->pub); - ret = dhd_register_if(&dhd->pub, ifidx, TRUE); - DHD_PERIM_LOCK(&dhd->pub); - if (ret != BCME_OK) { - DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__)); - dhd_remove_if(&dhd->pub, ifidx, TRUE); - goto done; - } -#ifndef PCIE_FULL_DONGLE - /* Turn on AP isolation in the firmware for interfaces operating in AP mode */ - if (FW_SUPPORTED((&dhd->pub), ap) && !(DHD_IF_ROLE_STA(if_event->event.role))) { - char iovbuf[WLC_IOCTL_SMLEN]; - uint32 var_int = 1; - - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("ap_isolate", (char *)&var_int, 4, iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx); - - if (ret != BCME_OK) { - DHD_ERROR(("%s: Failed to set ap_isolate to dongle\n", __FUNCTION__)); - dhd_remove_if(&dhd->pub, ifidx, TRUE); - } - } -#endif /* PCIE_FULL_DONGLE */ -done: - MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static void -dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - int ifidx; - dhd_if_event_t *if_event = event_info; - - - if (event != DHD_WQ_WORK_IF_DEL) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (!if_event) { - DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - ifidx = if_event->event.ifidx; - DHD_TRACE(("Removing interface with idx %d\n", ifidx)); - - dhd_remove_if(&dhd->pub, ifidx, TRUE); - - MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static void -dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_if_t *ifp = event_info; - - if (event != DHD_WQ_WORK_SET_MAC) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - -#ifdef SOFTAP - { - unsigned long flags; - bool in_ap = FALSE; - DHD_GENERAL_LOCK(&dhd->pub, flags); - in_ap = (ap_net_dev != NULL); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - - if (in_ap) { - DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n", - ifp->net->name)); - goto done; - } - } -#endif /* SOFTAP */ - - if (ifp == NULL || !dhd->pub.up) { - DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); - goto done; - } - - DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__)); - ifp->set_macaddress = FALSE; - if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0) - DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); - else - DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); - -done: - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static void -dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_if_t *ifp = event_info; - int ifidx; - - if (event != DHD_WQ_WORK_SET_MCAST_LIST) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - -#ifdef SOFTAP - { - bool in_ap = FALSE; - unsigned long flags; - DHD_GENERAL_LOCK(&dhd->pub, flags); - in_ap = (ap_net_dev != NULL); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - - if (in_ap) { - DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n", - ifp->net->name)); - ifp->set_multicast = FALSE; - goto done; - } - } -#endif /* SOFTAP */ - - if (ifp == NULL || !dhd->pub.up) { - DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); - goto done; - } - - ifidx = ifp->idx; - -#ifdef MCAST_LIST_ACCUMULATION - ifidx = 0; -#endif /* MCAST_LIST_ACCUMULATION */ - - _dhd_set_multicast_list(dhd, ifidx); - DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx)); - -done: - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static int -dhd_set_mac_address(struct net_device *dev, void *addr) -{ - int ret = 0; - - dhd_info_t *dhd = DHD_DEV_INFO(dev); - struct sockaddr *sa = (struct sockaddr *)addr; - int ifidx; - dhd_if_t *dhdif; - - ifidx = dhd_net2idx(dhd, dev); - if (ifidx == DHD_BAD_IF) - return -1; - - dhdif = dhd->iflist[ifidx]; - - dhd_net_if_lock_local(dhd); - memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN); - dhdif->set_macaddress = TRUE; - dhd_net_if_unlock_local(dhd); - dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC, - dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW); - return ret; -} - -static void -dhd_set_multicast_list(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ifidx; - - ifidx = dhd_net2idx(dhd, dev); - if (ifidx == DHD_BAD_IF) - return; - - dhd->iflist[ifidx]->set_multicast = TRUE; - dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx], - DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW); -} - -#ifdef PROP_TXSTATUS -int -dhd_os_wlfc_block(dhd_pub_t *pub) -{ - dhd_info_t *di = (dhd_info_t *)(pub->info); - ASSERT(di != NULL); - spin_lock_bh(&di->wlfc_spinlock); - return 1; -} - -int -dhd_os_wlfc_unblock(dhd_pub_t *pub) -{ - dhd_info_t *di = (dhd_info_t *)(pub->info); - - ASSERT(di != NULL); - spin_unlock_bh(&di->wlfc_spinlock); - return 1; -} - -#endif /* PROP_TXSTATUS */ - -#if defined(DHD_8021X_DUMP) -void -dhd_tx_dump(osl_t *osh, void *pkt) -{ - uint8 *dump_data; - uint16 protocol; - - dump_data = PKTDATA(osh, pkt); - protocol = (dump_data[12] << 8) | dump_data[13]; - - if (protocol == ETHER_TYPE_802_1X) { - DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n", - dump_data[14], dump_data[15], dump_data[30])); - } -} -#endif /* DHD_8021X_DUMP */ - -int BCMFASTPATH -dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) -{ - int ret = BCME_OK; - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh = NULL; - - /* Reject if down */ - if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { - /* free the packet here since the caller won't */ - PKTFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - -#if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) - if (bus_wakeup(dhdp->bus) == TRUE) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); - PKTFREE(dhdp->osh, pktbuf, TRUE); - return -EBUSY; - } -#endif /* DHD_USE_IDLECOUNT && BCMPCIE */ - -#ifdef PCIE_FULL_DONGLE - if (dhdp->busstate == DHD_BUS_SUSPEND) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); - PKTFREE(dhdp->osh, pktbuf, TRUE); - return -EBUSY; - } -#endif /* PCIE_FULL_DONGLE */ - -#ifdef DHD_UNICAST_DHCP - /* if dhcp_unicast is enabled, we need to convert the */ - /* broadcast DHCP ACK/REPLY packets to Unicast. */ - if (dhdp->dhcp_unicast) { - dhd_convert_dhcp_broadcast_ack_to_unicast(dhdp, pktbuf, ifidx); - } -#endif /* DHD_UNICAST_DHCP */ - /* Update multicast statistic */ - if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); - eh = (struct ether_header *)pktdata; - - if (ETHER_ISMULTI(eh->ether_dhost)) - dhdp->tx_multicast++; - if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) - atomic_inc(&dhd->pend_8021x_cnt); -#ifdef DHD_DHCP_DUMP - if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { - uint16 dump_hex; - uint16 source_port; - uint16 dest_port; - uint16 udp_port_pos; - uint8 *ptr8 = (uint8 *)&pktdata[ETHER_HDR_LEN]; - uint8 ip_header_len = (*ptr8 & 0x0f)<<2; - - udp_port_pos = ETHER_HDR_LEN + ip_header_len; - source_port = (pktdata[udp_port_pos] << 8) | pktdata[udp_port_pos+1]; - dest_port = (pktdata[udp_port_pos+2] << 8) | pktdata[udp_port_pos+3]; - if (source_port == 0x0044 || dest_port == 0x0044) { - dump_hex = (pktdata[udp_port_pos+249] << 8) | - pktdata[udp_port_pos+250]; - if (dump_hex == 0x0101) { - DHD_ERROR(("DHCP - DISCOVER [TX]\n")); - } else if (dump_hex == 0x0102) { - DHD_ERROR(("DHCP - OFFER [TX]\n")); - } else if (dump_hex == 0x0103) { - DHD_ERROR(("DHCP - REQUEST [TX]\n")); - } else if (dump_hex == 0x0105) { - DHD_ERROR(("DHCP - ACK [TX]\n")); - } else { - DHD_ERROR(("DHCP - 0x%X [TX]\n", dump_hex)); - } - } else if (source_port == 0x0043 || dest_port == 0x0043) { - DHD_ERROR(("DHCP - BOOTP [RX]\n")); - } - } -#endif /* DHD_DHCP_DUMP */ - } else { - PKTFREE(dhd->pub.osh, pktbuf, TRUE); - return BCME_ERROR; - } - - /* Look into the packet and update the packet priority */ -#ifndef PKTPRIO_OVERRIDE - if (PKTPRIO(pktbuf) == 0) -#endif - pktsetprio(pktbuf, FALSE); - - -#if defined(PCIE_FULL_DONGLE) && !defined(PCIE_TX_DEFERRAL) - /* - * Lkup the per interface hash table, for a matching flowring. If one is not - * available, allocate a unique flowid and add a flowring entry. - * The found or newly created flowid is placed into the pktbuf's tag. - */ - ret = dhd_flowid_update(dhdp, ifidx, dhdp->flow_prio_map[(PKTPRIO(pktbuf))], pktbuf); - if (ret != BCME_OK) { - PKTCFREE(dhd->pub.osh, pktbuf, TRUE); - return ret; - } -#endif - -#ifdef PROP_TXSTATUS - if (dhd_wlfc_is_supported(dhdp)) { - /* store the interface ID */ - DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); - - /* store destination MAC in the tag as well */ - DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); - - /* decide which FIFO this packet belongs to */ - if (ETHER_ISMULTI(eh->ether_dhost)) - /* one additional queue index (highest AC + 1) is used for bc/mc queue */ - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); - else - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); - } else -#endif /* PROP_TXSTATUS */ - /* If the protocol uses a data header, apply it */ - dhd_prot_hdrpush(dhdp, ifidx, pktbuf); - - /* Use bus module to send data frame */ -#ifdef WLMEDIA_HTSF - dhd_htsf_addtxts(dhdp, pktbuf); -#endif -#if defined(DHD_8021X_DUMP) - dhd_tx_dump(dhdp->osh, pktbuf); -#endif -#ifdef PROP_TXSTATUS - { - if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata, - dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) { - /* non-proptxstatus way */ -#ifdef BCMPCIE - ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); -#else - ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#endif /* BCMPCIE */ - } - } -#else -#ifdef BCMPCIE - ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); -#else - ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#endif /* BCMPCIE */ -#endif /* PROP_TXSTATUS */ - - return ret; -} - -int BCMFASTPATH -dhd_start_xmit(struct sk_buff *skb, struct net_device *net) -{ - int ret; - uint datalen; - void *pktbuf; - dhd_info_t *dhd = DHD_DEV_INFO(net); - dhd_if_t *ifp = NULL; - int ifidx; - unsigned long flags; -#ifdef WLMEDIA_HTSF - uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; -#else - uint8 htsfdlystat_sz = 0; -#endif -#ifdef DHD_WMF - struct ether_header *eh; - uint8 *iph; -#endif /* DHD_WMF */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -#if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) - if (dhd_bus_wakeup(&dhd->pub)) { - /* In order to avoid pkt loss. Return NETDEV_TX_BUSY until run-time resumed. */ - /* stop the network queue temporarily until resume done */ - if (!dhd_bus_is_resume_done(&dhd->pub)) { - netif_stop_queue(net); - } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } -#endif /* DHD_USE_IDLECOUNT && BCMPCIE */ - - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->pub.tx_in_progress = TRUE; -#ifdef PCIE_FULL_DONGLE - if (dhd->pub.busstate == DHD_BUS_SUSPEND) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); - dev_kfree_skb(skb); - ifp = DHD_DEV_IFP(net); - ifp->stats.tx_dropped++; - dhd->pub.tx_dropped++; - dhd->pub.tx_in_progress = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - return -EBUSY; - } -#endif /* PCIE_FULL_DONGLE */ - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); - - DHD_GENERAL_LOCK(&dhd->pub, flags); - /* Reject if down */ - if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) { - DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", - __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); - netif_stop_queue(net); - /* Send Event when bus down detected during data session */ - if (dhd->pub.up) { - DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); - net_os_send_hang_message(net); - } - dhd->pub.tx_in_progress = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - - ifp = DHD_DEV_IFP(net); - ifidx = DHD_DEV_IFIDX(net); - - ASSERT(ifidx == dhd_net2idx(dhd, net)); - ASSERT((ifp != NULL) && (ifp == dhd->iflist[ifidx])); - - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); - netif_stop_queue(net); - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->pub.tx_in_progress = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } - - /* re-align socket buffer if "skb->data" is odd address */ - if (((unsigned long)(skb->data)) & 0x1) { - unsigned char *data = skb->data; - uint32 length = skb->len; - PKTPUSH(dhd->pub.osh, skb, 1); - memmove(skb->data, data, length); - PKTSETLEN(dhd->pub.osh, skb, length); - } - - datalen = PKTLEN(dhd->pub.osh, skb); - - /* Make sure there's enough room for any header */ - - if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { - struct sk_buff *skb2; - - DHD_INFO(("%s: insufficient headroom\n", - dhd_ifname(&dhd->pub, ifidx))); - dhd->pub.tx_realloc++; - - skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); - - dev_kfree_skb(skb); - if ((skb = skb2) == NULL) { - DHD_ERROR(("%s: skb_realloc_headroom failed\n", - dhd_ifname(&dhd->pub, ifidx))); - ret = -ENOMEM; - goto done; - } - } - - /* Convert to packet */ - if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { - DHD_ERROR(("%s: PKTFRMNATIVE failed\n", - dhd_ifname(&dhd->pub, ifidx))); - dev_kfree_skb_any(skb); - ret = -ENOMEM; - goto done; - } -#ifdef WLMEDIA_HTSF - if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { - uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); - struct ether_header *eh = (struct ether_header *)pktdata; - - if (!ETHER_ISMULTI(eh->ether_dhost) && - (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { - eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); - } - } -#endif -#ifdef DHD_WMF - eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf); - iph = (uint8 *)eh + ETHER_HDR_LEN; - - /* WMF processing for multicast packets - * Only IPv4 packets are handled - */ - if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) && - (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) || - ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) { -#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) - void *sdu_clone; - bool ucast_convert = FALSE; -#ifdef DHD_UCAST_UPNP - uint32 dest_ip; - - dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET))); - ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip); -#endif /* DHD_UCAST_UPNP */ -#ifdef DHD_IGMP_UCQUERY - ucast_convert |= dhd->pub.wmf_ucast_igmp_query && - (IPV4_PROT(iph) == IP_PROT_IGMP) && - (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY); -#endif /* DHD_IGMP_UCQUERY */ - if (ucast_convert) { - dhd_sta_t *sta; - unsigned long flags; - - DHD_IF_STA_LIST_LOCK(ifp, flags); - - /* Convert upnp/igmp query to unicast for each assoc STA */ - list_for_each_entry(sta, &ifp->sta_list, list) { - if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) { - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->pub.tx_in_progress = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return (WMF_NOP); - } - dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1); - } - - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->pub.tx_in_progress = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - PKTFREE(dhd->pub.osh, pktbuf, TRUE); - return NETDEV_TX_OK; - } else -#endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */ - { - /* There will be no STA info if the packet is coming from LAN host - * Pass as NULL - */ - ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0); - switch (ret) { - case WMF_TAKEN: - case WMF_DROP: - /* Either taken by WMF or we should drop it. - * Exiting send path - */ - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->pub.tx_in_progress = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return NETDEV_TX_OK; - default: - /* Continue the transmit path */ - break; - } - } - } -#endif /* DHD_WMF */ - -#ifdef DHDTCPACK_SUPPRESS - if (dhd->pub.tcpack_sup_mode == TCPACK_SUP_HOLD) { - /* If this packet has been hold or got freed, just return */ - if (dhd_tcpack_hold(&dhd->pub, pktbuf, ifidx)) { - ret = 0; - goto done; - } - } else { - /* If this packet has replaced another packet and got freed, just return */ - if (dhd_tcpack_suppress(&dhd->pub, pktbuf)) { - ret = 0; - goto done; - } - } -#endif /* DHDTCPACK_SUPPRESS */ - - ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); - -done: - if (ret) { - ifp->stats.tx_dropped++; - dhd->pub.tx_dropped++; - } - else { - -#ifdef PROP_TXSTATUS - /* tx_packets counter can counted only when wlfc is disabled */ - if (!dhd_wlfc_is_supported(&dhd->pub)) -#endif - { - dhd->pub.tx_packets++; - ifp->stats.tx_packets++; - ifp->stats.tx_bytes += datalen; - } - } - - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->pub.tx_in_progress = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - /* Return ok: we always eat the packet */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return 0; -#else - return NETDEV_TX_OK; -#endif -} - - -void -dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) -{ - struct net_device *net; - dhd_info_t *dhd = dhdp->info; - int i; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(dhd); - - if (ifidx == ALL_INTERFACES) { - /* Flow control on all active interfaces */ - dhdp->txoff = state; - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - net = dhd->iflist[i]->net; - if (state == ON) - netif_stop_queue(net); - else - netif_wake_queue(net); - } - } - } - else { - if (dhd->iflist[ifidx]) { - net = dhd->iflist[ifidx]->net; - if (state == ON) - netif_stop_queue(net); - else - netif_wake_queue(net); - } - } -} - -#ifdef DHD_RX_DUMP -typedef struct { - uint16 type; - const char *str; -} PKTTYPE_INFO; - -static const PKTTYPE_INFO packet_type_info[] = -{ - { ETHER_TYPE_IP, "IP" }, - { ETHER_TYPE_ARP, "ARP" }, - { ETHER_TYPE_BRCM, "BRCM" }, - { ETHER_TYPE_802_1X, "802.1X" }, - { ETHER_TYPE_WAI, "WAPI" }, - { 0, ""} -}; - -static const char *_get_packet_type_str(uint16 type) -{ - int i; - int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; - - for (i = 0; i < n; i++) { - if (packet_type_info[i].type == type) - return packet_type_info[i].str; - } - - return packet_type_info[n].str; -} -#endif /* DHD_RX_DUMP */ - - -#ifdef DHD_WMF -bool -dhd_is_rxthread_enabled(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - - return dhd->rxthread_enabled; -} -#endif /* DHD_WMF */ - -void -dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - uchar *eth; - uint len; - void *data, *pnext = NULL; - int i; - dhd_if_t *ifp; - wl_event_msg_t event; - int tout_rx = 0; - int tout_ctrl = 0; - void *skbhead = NULL; - void *skbprev = NULL; -#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) - char *dump_data; - uint16 protocol; -#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { - struct ether_header *eh; - - pnext = PKTNEXT(dhdp->osh, pktbuf); - PKTSETNEXT(dhdp->osh, pktbuf, NULL); - - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) { - DHD_ERROR(("%s: ifp is NULL. drop packet\n", - __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - - eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); - - /* Dropping only data packets before registering net device to avoid kernel panic */ -#ifndef PROP_TXSTATUS_VSDB - if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) && - (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { -#else - if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) && - (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { -#endif /* PROP_TXSTATUS_VSDB */ - DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", - __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - - -#ifdef PROP_TXSTATUS - if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) { - /* WLFC may send header only packet when - there is an urgent message but no packet to - piggy-back on - */ - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } -#endif -#ifdef DHD_L2_FILTER - /* If block_ping is enabled drop the ping packet */ - if (dhdp->block_ping) { - if (dhd_l2_filter_block_ping(dhdp, pktbuf, ifidx) == BCME_OK) { - PKTFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - } -#endif -#ifdef DHD_WMF - /* WMF processing for multicast packets */ - if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) { - dhd_sta_t *sta; - int ret; - - sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost); - ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1); - switch (ret) { - case WMF_TAKEN: - /* The packet is taken by WMF. Continue to next iteration */ - continue; - case WMF_DROP: - /* Packet DROP decision by WMF. Toss it */ - DHD_ERROR(("%s: WMF decides to drop packet\n", - __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - default: - /* Continue the transmit path */ - break; - } - } -#endif /* DHD_WMF */ -#ifdef DHDTCPACK_SUPPRESS - dhd_tcpdata_info_get(dhdp, pktbuf); -#endif - skb = PKTTONATIVE(dhdp->osh, pktbuf); - - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) - ifp = dhd->iflist[0]; - - ASSERT(ifp); - skb->dev = ifp->net; - -#ifdef PCIE_FULL_DONGLE - if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) && - (!ifp->ap_isolate)) { - eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); - if (ETHER_ISUCAST(eh->ether_dhost)) { - if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) { - dhd_sendpkt(dhdp, ifidx, pktbuf); - continue; - } - } else { - void *npktbuf = PKTDUP(dhdp->osh, pktbuf); - dhd_sendpkt(dhdp, ifidx, npktbuf); - } - } -#endif /* PCIE_FULL_DONGLE */ - - /* 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; - -#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_DHCP_DUMP) - dump_data = skb->data; - protocol = (dump_data[12] << 8) | dump_data[13]; -#endif /* DHD_RX_DUMP || DHD_8021X_DUMP || DHD_DHCP_DUMP */ -#ifdef DHD_8021X_DUMP - if (protocol == ETHER_TYPE_802_1X) { - DHD_ERROR(("ETHER_TYPE_802_1X [RX]: " - "ver %d, type %d, replay %d\n", - dump_data[14], dump_data[15], - dump_data[30])); - } -#endif /* DHD_8021X_DUMP */ -#ifdef DHD_DHCP_DUMP - if (protocol != ETHER_TYPE_BRCM && protocol == ETHER_TYPE_IP) { - uint16 dump_hex; - uint16 source_port; - uint16 dest_port; - uint16 udp_port_pos; - uint8 *ptr8 = (uint8 *)&dump_data[ETHER_HDR_LEN]; - uint8 ip_header_len = (*ptr8 & 0x0f)<<2; - - udp_port_pos = ETHER_HDR_LEN + ip_header_len; - source_port = (dump_data[udp_port_pos] << 8) | dump_data[udp_port_pos+1]; - dest_port = (dump_data[udp_port_pos+2] << 8) | dump_data[udp_port_pos+3]; - if (source_port == 0x0044 || dest_port == 0x0044) { - dump_hex = (dump_data[udp_port_pos+249] << 8) | - dump_data[udp_port_pos+250]; - if (dump_hex == 0x0101) { - DHD_ERROR(("DHCP - DISCOVER [RX]\n")); - } else if (dump_hex == 0x0102) { - DHD_ERROR(("DHCP - OFFER [RX]\n")); - } else if (dump_hex == 0x0103) { - DHD_ERROR(("DHCP - REQUEST [RX]\n")); - } else if (dump_hex == 0x0105) { - DHD_ERROR(("DHCP - ACK [RX]\n")); - } else { - DHD_ERROR(("DHCP - 0x%X [RX]\n", dump_hex)); - } - } else if (source_port == 0x0043 || dest_port == 0x0043) { - DHD_ERROR(("DHCP - BOOTP [RX]\n")); - } - } -#endif /* DHD_DHCP_DUMP */ -#if defined(DHD_RX_DUMP) - DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol))); - if (protocol != ETHER_TYPE_BRCM) { - if (dump_data[0] == 0xFF) { - DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__)); - - if ((dump_data[12] == 8) && - (dump_data[13] == 6)) { - DHD_ERROR(("%s: ARP %d\n", - __FUNCTION__, dump_data[0x15])); - } - } else if (dump_data[0] & 1) { - DHD_ERROR(("%s: MULTICAST: " MACDBG "\n", - __FUNCTION__, MAC2STRDBG(dump_data))); - } -#ifdef DHD_RX_FULL_DUMP - { - int k; - for (k = 0; k < skb->len; k++) { - DHD_ERROR(("%02X ", dump_data[k])); - if ((k & 15) == 15) - DHD_ERROR(("\n")); - } - DHD_ERROR(("\n")); - } -#endif /* DHD_RX_FULL_DUMP */ - } -#endif /* DHD_RX_DUMP */ - - skb->protocol = eth_type_trans(skb, skb->dev); - - if (skb->pkt_type == PACKET_MULTICAST) { - dhd->pub.rx_multicast++; - ifp->stats.multicast++; - } - - skb->data = eth; - skb->len = len; - -#ifdef WLMEDIA_HTSF - dhd_htsf_addrxts(dhdp, pktbuf); -#endif - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* Process special event packets and then discard them */ - memset(&event, 0, sizeof(event)); - if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { - int ret_event; - - ret_event = dhd_wl_host_event(dhd, &ifidx, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) - skb_mac_header(skb), -#else - skb->mac.raw, -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ - len, - &event, - &data); - - if (ret_event != BCME_OK) { - PKTFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - - wl_event_to_host_order(&event); - if (!tout_ctrl) - tout_ctrl = DHD_PACKET_TIMEOUT_MS; - -#if defined(PNO_SUPPORT) - if (event.event_type == WLC_E_PFN_NET_FOUND) { - /* enforce custom wake lock to garantee that Kernel not suspended */ - tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; - } -#endif /* PNO_SUPPORT */ - -#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - PKTFREE(dhdp->osh, pktbuf, FALSE); - - continue; -#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ - } else { - tout_rx = DHD_PACKET_TIMEOUT_MS; - -#ifdef PROP_TXSTATUS - dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb)); -#endif /* PROP_TXSTATUS */ - } - - ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); - ifp = dhd->iflist[ifidx]; - - if (ifp->net) - ifp->net->last_rx = jiffies; - - if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { - dhdp->dstats.rx_bytes += skb->len; - dhdp->rx_packets++; /* Local count */ - ifp->stats.rx_bytes += skb->len; - ifp->stats.rx_packets++; - } - - if (in_interrupt()) { - netif_rx(skb); - } else { - if (dhd->rxthread_enabled) { - if (!skbhead) - skbhead = skb; - else - PKTSETNEXT(dhdp->osh, skbprev, skb); - skbprev = 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. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - netif_rx_ni(skb); -#else - ulong flags; - netif_rx(skb); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ - } - } - } - - if (dhd->rxthread_enabled && skbhead) - dhd_sched_rxf(dhdp, skbhead); - - DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); -} - -void -dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx) -{ - /* Linux version has nothing to do */ - return; -} - -void -dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh; - uint16 type; - - dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); - - eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); - type = ntoh16(eh->ether_type); - - if (type == ETHER_TYPE_802_1X) - atomic_dec(&dhd->pend_8021x_cnt); - -#ifdef PROP_TXSTATUS - if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) { - dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))]; - uint datalen = PKTLEN(dhd->pub.osh, txp); - - if (success) { - dhd->pub.tx_packets++; - ifp->stats.tx_packets++; - ifp->stats.tx_bytes += datalen; - } else { - ifp->stats.tx_dropped++; - } - } -#endif -} - -static struct net_device_stats * -dhd_get_stats(struct net_device *net) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); - dhd_if_t *ifp; - int ifidx; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); - - memset(&net->stats, 0, sizeof(net->stats)); - return &net->stats; - } - - ifp = dhd->iflist[ifidx]; - ASSERT(dhd && ifp); - - if (dhd->pub.up) { - /* Use the protocol to get dongle stats */ - dhd_prot_dstats(&dhd->pub); - } - return &ifp->stats; -} - -static int -dhd_watchdog_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_watchdog_prio > 0) { - struct sched_param param; - param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? - dhd_watchdog_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - - while (1) - if (down_interruptible (&tsk->sema) == 0) { - unsigned long flags; - unsigned long jiffies_at_start = jiffies; - unsigned long time_lapse; - - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - if (dhd->pub.dongle_reset == FALSE) { - DHD_TIMER(("%s:\n", __FUNCTION__)); - - /* Call the bus module watchdog */ - dhd_bus_watchdog(&dhd->pub); - - - DHD_GENERAL_LOCK(&dhd->pub, flags); - /* Count the tick for reference */ - dhd->pub.tickcnt++; - time_lapse = jiffies - jiffies_at_start; - - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, - jiffies + - msecs_to_jiffies(dhd_watchdog_ms) - - min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - } - } else { - break; - } - - complete_and_exit(&tsk->completed, 0); -} - -static void dhd_watchdog(ulong data) -{ - dhd_info_t *dhd = (dhd_info_t *)data; - unsigned long flags; - - if (dhd->pub.dongle_reset) { - return; - } - - if (dhd->thr_wdt_ctl.thr_pid >= 0) { - up(&dhd->thr_wdt_ctl.sema); - return; - } - - /* Call the bus module watchdog */ - dhd_bus_watchdog(&dhd->pub); - - DHD_GENERAL_LOCK(&dhd->pub, flags); - /* Count the tick for reference */ - dhd->pub.tickcnt++; - - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - -} - -#ifdef ENABLE_ADAPTIVE_SCHED -static void -dhd_sched_policy(int prio) -{ - struct sched_param param; - if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) { - param.sched_priority = 0; - setScheduler(current, SCHED_NORMAL, ¶m); - } else { - if (get_scheduler_policy(current) != SCHED_FIFO) { - param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - } -} -#endif /* ENABLE_ADAPTIVE_SCHED */ -#ifdef DEBUG_CPU_FREQ -static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) -{ - dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans); - struct cpufreq_freqs *freq = data; - if (dhd) { - if (!dhd->new_freq) - goto exit; - if (val == CPUFREQ_POSTCHANGE) { - DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n", - freq->new, freq->cpu)); - *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new; - } - } -exit: - return 0; -} -#endif /* DEBUG_CPU_FREQ */ -static int -dhd_dpc_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_dpc_prio > 0) - { - struct sched_param param; - param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - -#ifdef CUSTOM_DPC_CPUCORE - set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE)); -#endif -#ifdef CUSTOM_SET_CPUCORE - dhd->pub.current_dpc = current; -#endif /* CUSTOM_SET_CPUCORE */ - /* Run until signal received */ - while (1) { - if (!binary_sema_down(tsk)) { -#ifdef ENABLE_ADAPTIVE_SCHED - dhd_sched_policy(dhd_dpc_prio); -#endif /* ENABLE_ADAPTIVE_SCHED */ - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - /* Call bus dpc unless it indicated down (then clean stop) */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { - dhd_os_wd_timer_extend(&dhd->pub, TRUE); - while (dhd_bus_dpc(dhd->pub.bus)) { - /* process all data */ - } - dhd_os_wd_timer_extend(&dhd->pub, FALSE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } else { - if (dhd->pub.up) - dhd_bus_stop(dhd->pub.bus, TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } - } - else - break; - } - complete_and_exit(&tsk->completed, 0); -} - -static int -dhd_rxf_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; -#if defined(WAIT_DEQUEUE) -#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */ - ulong watchdogTime = OSL_SYSUPTIME(); /* msec */ -#endif - dhd_pub_t *pub = &dhd->pub; - - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_rxf_prio > 0) - { - struct sched_param param; - param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - - DAEMONIZE("dhd_rxf"); - /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ - - /* signal: thread has started */ - complete(&tsk->completed); -#ifdef CUSTOM_SET_CPUCORE - dhd->pub.current_rxf = current; -#endif /* CUSTOM_SET_CPUCORE */ - /* Run until signal received */ - while (1) { - if (down_interruptible(&tsk->sema) == 0) { - void *skb; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) - ulong flags; -#endif -#ifdef ENABLE_ADAPTIVE_SCHED - dhd_sched_policy(dhd_rxf_prio); -#endif /* ENABLE_ADAPTIVE_SCHED */ - - SMP_RD_BARRIER_DEPENDS(); - - if (tsk->terminated) { - break; - } - skb = dhd_rxf_dequeue(pub); - - if (skb == NULL) { - continue; - } - while (skb) { - void *skbnext = PKTNEXT(pub->osh, skb); - PKTSETNEXT(pub->osh, skb, NULL); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - netif_rx_ni(skb); -#else - netif_rx(skb); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); - -#endif - skb = skbnext; - } -#if defined(WAIT_DEQUEUE) - if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) { - OSL_SLEEP(1); - watchdogTime = OSL_SYSUPTIME(); - } -#endif - - DHD_OS_WAKE_UNLOCK(pub); - } - else - break; - } - complete_and_exit(&tsk->completed, 0); -} - -#ifdef BCMPCIE -void dhd_dpc_kill(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - - if (!dhdp) - return; - - dhd = dhdp->info; - - if (!dhd) - return; - - tasklet_kill(&dhd->tasklet); - DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__)); -} -#endif /* BCMPCIE */ - -static void -dhd_dpc(ulong data) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)data; - - /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] - * down below , wake lock is set, - * the tasklet is initialized in dhd_attach() - */ - /* Call bus dpc unless it indicated down (then clean stop) */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { - if (dhd_bus_dpc(dhd->pub.bus)) - tasklet_schedule(&dhd->tasklet); - else - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } else { - dhd_bus_stop(dhd->pub.bus, TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } -} - -void -dhd_sched_dpc(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - DHD_OS_WAKE_LOCK(dhdp); - if (dhd->thr_dpc_ctl.thr_pid >= 0) { - /* If the semaphore does not get up, - * wake unlock should be done here - */ - if (!binary_sema_up(&dhd->thr_dpc_ctl)) - DHD_OS_WAKE_UNLOCK(dhdp); - return; - } else { - tasklet_schedule(&dhd->tasklet); - } -} - -static void -dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - DHD_OS_WAKE_LOCK(dhdp); - - DHD_TRACE(("dhd_sched_rxf: Enter\n")); - do { - if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK) - break; - } while (1); - if (dhd->thr_rxf_ctl.thr_pid >= 0) { - up(&dhd->thr_rxf_ctl.sema); - } - return; -} - -#ifdef TOE -/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ -static int -dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) -{ - wl_ioctl_t ioc; - char buf[32]; - int ret; - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = (uint)sizeof(buf); - ioc.set = FALSE; - - strncpy(buf, "toe_ol", sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { - /* Check for older dongle image that doesn't support toe_ol */ - if (ret == -EIO) { - DHD_ERROR(("%s: toe not supported by device\n", - dhd_ifname(&dhd->pub, ifidx))); - return -EOPNOTSUPP; - } - - DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - memcpy(toe_ol, buf, sizeof(uint32)); - return 0; -} - -/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ -static int -dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) -{ - wl_ioctl_t ioc; - char buf[32]; - int toe, ret; - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = (uint)sizeof(buf); - ioc.set = TRUE; - - /* Set toe_ol as requested */ - - strncpy(buf, "toe_ol", sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32)); - - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { - DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", - dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - /* Enable toe globally only if any components are enabled. */ - - toe = (toe_ol != 0); - - strcpy(buf, "toe"); - memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32)); - - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { - DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - return 0; -} -#endif /* TOE */ - -#if defined(WL_CFG80211) -void dhd_set_scb_probe(dhd_pub_t *dhd) -{ -#define NUM_SCB_MAX_PROBE 3 - int ret = 0; - wl_scb_probe_t scb_probe; - char iovbuf[WL_EVENTING_MASK_LEN + 12]; - - memset(&scb_probe, 0, sizeof(wl_scb_probe_t)); - - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) - return; - - bcm_mkiovar("scb_probe", NULL, 0, iovbuf, sizeof(iovbuf)); - - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__)); - - memcpy(&scb_probe, iovbuf, sizeof(wl_scb_probe_t)); - - scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE; - - bcm_mkiovar("scb_probe", (char *)&scb_probe, - sizeof(wl_scb_probe_t), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__)); -#undef NUM_SCB_MAX_PROBE - return; -} -#endif /* WL_CFG80211 */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -static void -dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); - - snprintf(info->driver, sizeof(info->driver), "wl"); - snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); -} - -struct ethtool_ops dhd_ethtool_ops = { - .get_drvinfo = dhd_ethtool_get_drvinfo -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) -static int -dhd_ethtool(dhd_info_t *dhd, void *uaddr) -{ - struct ethtool_drvinfo info; - char drvname[sizeof(info.driver)]; - uint32 cmd; -#ifdef TOE - struct ethtool_value edata; - uint32 toe_cmpnt, csum_dir; - int ret; -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* all ethtool calls start with a cmd word */ - if (copy_from_user(&cmd, uaddr, sizeof (uint32))) - 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 dhd requested, identify ourselves */ - if (strcmp(drvname, "?dhd") == 0) { - snprintf(info.driver, sizeof(info.driver), "dhd"); - strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); - info.version[sizeof(info.version) - 1] = '\0'; - } - - /* otherwise, require dongle to be up */ - else if (!dhd->pub.up) { - DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); - return -ENODEV; - } - - /* finally, report dongle driver type */ - else if (dhd->pub.iswl) - snprintf(info.driver, sizeof(info.driver), "wl"); - else - snprintf(info.driver, sizeof(info.driver), "xx"); - - snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); - if (copy_to_user(uaddr, &info, sizeof(info))) - return -EFAULT; - DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, - (int)sizeof(drvname), drvname, info.driver)); - break; - -#ifdef TOE - /* Get toe offload components from dongle */ - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 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 */ - if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 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; - - if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) - return ret; - - /* If setting TX checksum mode, tell Linux the new mode */ - if (cmd == ETHTOOL_STXCSUM) { - if (edata.data) - dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; - else - dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; - } - - break; -#endif /* TOE */ - - default: - return -EOPNOTSUPP; - } - - return 0; -} -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - -static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) -{ - dhd_info_t *dhd; - - if (!dhdp) { - DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); - return FALSE; - } - - if (!dhdp->up) - return FALSE; - - dhd = (dhd_info_t *)dhdp->info; -#if !defined(BCMPCIE) - if (dhd->thr_dpc_ctl.thr_pid < 0) { - DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); - return FALSE; - } -#endif - -#ifdef CONFIG_MACH_UNIVERSAL5433 - /* old revision does not send hang message */ - if ((check_rev() && (error == -ETIMEDOUT)) || (error == -EREMOTEIO) || -#else - if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || -#endif /* CONFIG_MACH_UNIVERSAL5433 */ - ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { -#ifdef BCMPCIE - DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d d3acke=%d e=%d s=%d\n", - __FUNCTION__, dhdp->rxcnt_timeout, dhdp->txcnt_timeout, - dhdp->d3ackcnt_timeout, error, dhdp->busstate)); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(dhd->pub.crash_reason, - "%s: Event HANG send up due to re=%d te=%d d3acke=%d e=%d s=%d\n", - __FUNCTION__, dhdp->rxcnt_timeout, dhdp->txcnt_timeout, - dhdp->d3ackcnt_timeout, error, dhdp->busstate); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ -#else - DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, - dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(dhd->pub.crash_reason, - "%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, - dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ -#endif /* BCMPCIE */ - - net_os_send_hang_message(net); - return TRUE; - } - return FALSE; -} - -int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf) -{ - int bcmerror = BCME_OK; - int buflen = 0; - struct net_device *net; - - net = dhd_idx2net(pub, ifidx); - if (!net) { - bcmerror = BCME_BADARG; - goto done; - } - - if (data_buf) - buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN); - - /* check for local dhd ioctl and handle it */ - if (ioc->driver == DHD_IOCTL_MAGIC) { - bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen); - if (bcmerror) - pub->bcmerror = bcmerror; - goto done; - } - - /* send to dongle (must be up, and wl). */ - if (pub->busstate != DHD_BUS_DATA) { - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - - if (!pub->iswl) { - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - - /* - * Flush the TX queue if required for proper message serialization: - * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to - * prevent M4 encryption and - * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to - * prevent disassoc frame being sent before WPS-DONE frame. - */ - if (ioc->cmd == WLC_SET_KEY || - (ioc->cmd == WLC_SET_VAR && data_buf != NULL && - strncmp("wsec_key", data_buf, 9) == 0) || - (ioc->cmd == WLC_SET_VAR && data_buf != NULL && - strncmp("bsscfg:wsec_key", data_buf, 15) == 0) || - ioc->cmd == WLC_DISASSOC) - dhd_wait_pend8021x(net); - -#ifdef WLMEDIA_HTSF - if (data_buf) { - /* short cut wl ioctl calls here */ - if (strcmp("htsf", data_buf) == 0) { - dhd_ioctl_htsf_get(dhd, 0); - return BCME_OK; - } - - if (strcmp("htsflate", data_buf) == 0) { - if (ioc->set) { - memset(ts, 0, sizeof(tstamp_t)*TSMAX); - memset(&maxdelayts, 0, sizeof(tstamp_t)); - maxdelay = 0; - tspktcnt = 0; - maxdelaypktno = 0; - memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); - } else { - dhd_dump_latency(); - } - return BCME_OK; - } - if (strcmp("htsfclear", data_buf) == 0) { - memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); - htsf_seqnum = 0; - return BCME_OK; - } - if (strcmp("htsfhis", data_buf) == 0) { - dhd_dump_htsfhisto(&vi_d1, "H to D"); - dhd_dump_htsfhisto(&vi_d2, "D to D"); - dhd_dump_htsfhisto(&vi_d3, "D to H"); - dhd_dump_htsfhisto(&vi_d4, "H to H"); - return BCME_OK; - } - if (strcmp("tsport", data_buf) == 0) { - if (ioc->set) { - memcpy(&tsport, data_buf + 7, 4); - } else { - DHD_ERROR(("current timestamp port: %d \n", tsport)); - } - return BCME_OK; - } - } -#endif /* WLMEDIA_HTSF */ - - if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) && - data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) { -#ifdef BCM_FD_AGGR - bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); -#else - bcmerror = BCME_UNSUPPORTED; -#endif - goto done; - } - - if (ioc->cmd == WLC_SET_VAR && data_buf != NULL && - strncmp("qtxpower", data_buf, 8) == 0) { -#ifdef SOMC_MIMO - if (*((char *)data_buf + 12) & SOMC_TXPWR_5G && - *((char *)data_buf + 9) != WLC_TXPWR_MAX && - *((char *)data_buf + 10) != WLC_TXPWR_MAX) { - *((char *)data_buf + 12) |= SOMC_TXPWR_OVERRIDE; - } -#endif - if (somc_update_qtxpower((char *)data_buf + 9, *((char *)data_buf + 12), 0) != 0) { - DHD_ERROR(("qtxpower on chain0 failed\n")); - bcmerror = BCME_ERROR; - goto done; - } -#ifdef SOMC_MIMO - if (somc_update_qtxpower((char *)data_buf + 10, *((char *)data_buf + 12), 1) != 0) { - DHD_ERROR(("qtxpower on chain1 failed\n")); - bcmerror = BCME_ERROR; - goto done; - } -#else - /* initialize chain1 value just in case since it's not needed for SISO */ - *((char *)data_buf + 10) = 0; -#endif - } - - bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); - -done: - dhd_check_hang(net, pub, bcmerror); - - return bcmerror; -} - -static int -dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); - dhd_ioctl_t ioc; - int bcmerror = 0; - int ifidx; - int ret; - void *local_buf = NULL; - u16 buflen = 0; - -#if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) - /* Just wake watchdog and wait. Don't care the return value here. */ - dhd_bus_wake(&dhd->pub); -#endif /* DHD_USE_IDLECOUNT && BCMPCIE */ - - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - /* Interface up check for built-in type */ - if (!dhd_download_fw_on_driverload && dhd->pub.up == 0) { - DHD_TRACE(("%s: Interface is down \n", __FUNCTION__)); - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return BCME_NOTUP; - } - - /* send to dongle only if we are not waiting for reload already */ - if (dhd->pub.hang_was_sent) { - DHD_TRACE(("%s: HANG was sent up earlier\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return OSL_ERROR(BCME_DONGLE_DOWN); - } - - ifidx = dhd_net2idx(dhd, net); - DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); - - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -1; - } - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) - if (cmd == SIOCETHTOOL) { - ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - - if (cmd == SIOCDEVPRIVATE+1) { - ret = wl_android_priv_cmd(net, ifr, cmd); - dhd_check_hang(net, &dhd->pub, ret); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } - - if (cmd != SIOCDEVPRIVATE) { - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -EOPNOTSUPP; - } - - memset(&ioc, 0, sizeof(ioc)); - -#ifdef CONFIG_COMPAT - if (is_compat_task()) { - compat_wl_ioctl_t compat_ioc; - if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) { - bcmerror = BCME_BADADDR; - goto done; - } - ioc.cmd = compat_ioc.cmd; - ioc.buf = compat_ptr(compat_ioc.buf); - ioc.len = compat_ioc.len; - ioc.set = compat_ioc.set; - ioc.used = compat_ioc.used; - ioc.needed = compat_ioc.needed; - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), - sizeof(uint)) != 0)) { - bcmerror = BCME_BADADDR; - goto done; - } - } else -#endif /* CONFIG_COMPAT */ - { - /* Copy the ioc control structure part of ioctl request */ - if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { - bcmerror = BCME_BADADDR; - goto done; - } - - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), - sizeof(uint)) != 0)) { - bcmerror = BCME_BADADDR; - goto done; - } - } - - if (!capable(CAP_NET_ADMIN)) { - bcmerror = BCME_EPERM; - goto done; - } - - if (ioc.len > 0) { - buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); - if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) { - bcmerror = BCME_NOMEM; - goto done; - } - - DHD_PERIM_UNLOCK(&dhd->pub); - if (copy_from_user(local_buf, ioc.buf, buflen)) { - DHD_PERIM_LOCK(&dhd->pub); - bcmerror = BCME_BADADDR; - goto done; - } - DHD_PERIM_LOCK(&dhd->pub); - - *(char *)(local_buf + buflen) = '\0'; - } - - bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf); - - if (!bcmerror && buflen && local_buf && ioc.buf) { - DHD_PERIM_UNLOCK(&dhd->pub); - if (copy_to_user(ioc.buf, local_buf, buflen)) - bcmerror = -EFAULT; - DHD_PERIM_LOCK(&dhd->pub); - } - -done: - if (local_buf) - MFREE(dhd->pub.osh, local_buf, buflen+1); - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - return OSL_ERROR(bcmerror); -} - - - -static int -dhd_stop(struct net_device *net) -{ - int ifidx = 0; - dhd_info_t *dhd = DHD_DEV_INFO(net); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); - dhd->pub.rxcnt_timeout = 0; - dhd->pub.txcnt_timeout = 0; - - if (dhd->pub.up == 0) { - goto exit; - } - - dhd_if_flush_sta(DHD_DEV_IFP(net)); - - - ifidx = dhd_net2idx(dhd, net); - BCM_REFERENCE(ifidx); - - /* Stop OS transmissions */ - netif_stop_queue(net); - -#ifdef WL_CFG80211 - if (ifidx == 0) { - wl_cfg80211_down(NULL); - - /* - * For CFG80211: Clean up all the left over virtual interfaces - * when the primary Interface is brought down. [ifconfig wlan0 down] - */ - if (!dhd_download_fw_on_driverload) { - if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && - (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { - int i; - - - dhd_net_if_lock_local(dhd); - for (i = 1; i < DHD_MAX_IFS; i++) - dhd_remove_if(&dhd->pub, i, FALSE); - dhd_net_if_unlock_local(dhd); - } - } - } -#endif /* WL_CFG80211 */ - -#ifdef PROP_TXSTATUS - dhd_wlfc_cleanup(&dhd->pub, NULL, 0); -#endif - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - - OLD_MOD_DEC_USE_COUNT; -exit: -#if defined(WL_CFG80211) - if (ifidx == 0 && !dhd_download_fw_on_driverload) - wl_android_wifi_off(net); -#endif - /* Set state */ - dhd->pub.up = 0; - -#ifdef BCMPCIE - dhd->pub.d3ackcnt_timeout = 0; -#endif /* BCMPCIE */ - - dhd->pub.hang_was_sent = 0; - dhd->pub.ioctl_state = 0; - - /* Clear country spec for for built-in type driver */ - if (!dhd_download_fw_on_driverload) { - dhd->pub.dhd_cspec.country_abbrev[0] = 0x00; - dhd->pub.dhd_cspec.rev = 0; - dhd->pub.dhd_cspec.ccode[0] = 0x00; - } - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - /* Destroy wakelock */ - if (!dhd_download_fw_on_driverload && - (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - DHD_OS_WAKE_LOCK_DESTROY(dhd); - dhd->dhd_state &= ~DHD_ATTACH_STATE_WAKELOCKS_INIT; - } - - return 0; -} - -#if defined(WL_CFG80211) && (defined(USE_INITIAL_2G_SCAN) || \ - defined(USE_INITIAL_SHORT_DWELL_TIME)) -extern bool g_first_broadcast_scan; -#endif /* OEM_ANDROID && WL_CFG80211 && (USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME) */ - -#ifdef WL11U -static int dhd_interworking_enable(dhd_pub_t *dhd) -{ - char iovbuf[WLC_IOCTL_SMLEN]; - uint32 enable = true; - int ret = BCME_OK; - - bcm_mkiovar("interworking", (char *)&enable, sizeof(enable), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret)); - } - - if (ret == BCME_OK) { - /* basic capabilities for HS20 REL2 */ - uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF; - bcm_mkiovar("wnm", (char *)&cap, sizeof(cap), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret)); - } - } - - return ret; -} -#endif /* WL11u */ - -static int -dhd_open(struct net_device *net) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); -#ifdef TOE - uint32 toe_ol; -#endif - int ifidx; - int32 ret = 0; - - /* Init wakelock */ - if (!dhd_download_fw_on_driverload && - !(dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - DHD_OS_WAKE_LOCK_INIT(dhd); - dhd->dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; - } - - - - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - dhd->pub.dongle_trap_occured = 0; - dhd->pub.hang_was_sent = 0; - dhd->pub.ioctl_state = 0; - -#if !defined(WL_CFG80211) - /* - * Force start if ifconfig_up gets called before START command - * We keep WEXT's wl_control_wl_start to provide backward compatibility - * This should be removed in the future - */ - ret = wl_control_wl_start(net); - if (ret != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - ret = -1; - goto exit; - } - -#endif - - ifidx = dhd_net2idx(dhd, net); - DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - - if (ifidx < 0) { - DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__)); - ret = -1; - goto exit; - } - - if (!dhd->iflist[ifidx]) { - DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); - ret = -1; - goto exit; - } - - if (ifidx == 0) { - -#if defined(BCMPCIE) && defined(CUSTOMER_HW5) - if (!dhd->register_if_done) { - DHD_ERROR(("%s: Registering interface has not done yet\n", __FUNCTION__)); - ret = -1; - goto exit; - } -#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ - - atomic_set(&dhd->pend_8021x_cnt, 0); -#if defined(WL_CFG80211) - if (!dhd_download_fw_on_driverload) { - DHD_ERROR(("\n%s\n", dhd_version)); -#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) - g_first_broadcast_scan = TRUE; -#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ - ret = wl_android_wifi_on(net); - if (ret != 0) { - DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n", - __FUNCTION__, ret)); - ret = -1; - goto exit; - } - } -#endif - - if (dhd->pub.busstate != DHD_BUS_DATA) { - - /* try to bring up bus */ - DHD_PERIM_UNLOCK(&dhd->pub); - ret = dhd_bus_start(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - if (ret) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - ret = -1; - goto exit; - } - - } - - /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */ - memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); - -#ifdef TOE - /* Get current TOE mode from dongle */ - if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) - dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; - else - dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; -#endif /* TOE */ - -#if defined(WL_CFG80211) - if (unlikely(wl_cfg80211_up(NULL))) { - DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); - ret = -1; - goto exit; - } - dhd_set_scb_probe(&dhd->pub); -#endif /* WL_CFG80211 */ - } - - /* Allow transmit calls */ - netif_start_queue(net); - dhd->pub.up = 1; - -#ifdef BCMDBGFS - dhd_dbg_init(&dhd->pub); -#endif - - OLD_MOD_INC_USE_COUNT; -exit: - if (ret) - dhd_stop(net); - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - - return ret; -} - -int dhd_do_driver_init(struct net_device *net) -{ - dhd_info_t *dhd = NULL; - - if (!net) { - DHD_ERROR(("Primary Interface not initialized \n")); - return -EINVAL; - } - - - /* && defined(OEM_ANDROID) && defined(BCMSDIO) */ - dhd = DHD_DEV_INFO(net); - - /* If driver is already initialized, do nothing - */ - if (dhd->pub.busstate == DHD_BUS_DATA) { - DHD_TRACE(("Driver already Inititalized. Nothing to do")); - return 0; - } - - if (dhd_open(net) < 0) { - DHD_ERROR(("Driver Init Failed \n")); - return -1; - } - - return 0; -} - -int -dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) -{ - -#ifdef WL_CFG80211 - if (wl_cfg80211_notify_ifadd(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) - return BCME_OK; -#endif - - /* handle IF event caused by wl commands, SoftAP, WEXT and - * anything else. This has to be done asynchronously otherwise - * DPC will be blocked (and iovars will timeout as DPC has no chance - * to read the response back) - */ - if (ifevent->ifidx > 0) { - dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); - - memcpy(&if_event->event, ifevent, sizeof(if_event->event)); - memcpy(if_event->mac, mac, ETHER_ADDR_LEN); - strncpy(if_event->name, name, IFNAMSIZ); - if_event->name[IFNAMSIZ - 1] = '\0'; - dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, - DHD_WQ_WORK_IF_ADD, dhd_ifadd_event_handler, DHD_WORK_PRIORITY_LOW); - } - - return BCME_OK; -} - -int -dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) -{ - dhd_if_event_t *if_event; - -#if defined(WL_CFG80211) - if (wl_cfg80211_notify_ifdel(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) - return BCME_OK; -#endif /* WL_CFG80211 */ - - /* handle IF event caused by wl commands, SoftAP, WEXT and - * anything else - */ - if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); - memcpy(&if_event->event, ifevent, sizeof(if_event->event)); - memcpy(if_event->mac, mac, ETHER_ADDR_LEN); - strncpy(if_event->name, name, IFNAMSIZ); - if_event->name[IFNAMSIZ - 1] = '\0'; - dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_DEL, - dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW); - - return BCME_OK; -} - -/* unregister and free the existing net_device interface (if any) in iflist and - * allocate a new one. the slot is reused. this function does NOT register the - * new interface to linux kernel. dhd_register_if does the job - */ -struct net_device* -dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name, - uint8 *mac, uint8 bssidx, bool need_rtnl_lock) -{ - dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; - dhd_if_t *ifp; - - ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS)); - ifp = dhdinfo->iflist[ifidx]; - - if (ifp != NULL) { - if (ifp->net != NULL) { - DHD_ERROR(("%s: free existing IF %s\n", __FUNCTION__, ifp->net->name)); - - dhd_dev_priv_clear(ifp->net); /* clear net_device private */ - - /* in unregister_netdev case, the interface gets freed by net->destructor - * (which is set to free_netdev) - */ - if (ifp->net->reg_state == NETREG_UNINITIALIZED) { - free_netdev(ifp->net); - } else { - netif_stop_queue(ifp->net); - if (need_rtnl_lock) - unregister_netdev(ifp->net); - else - unregister_netdevice(ifp->net); - } - ifp->net = NULL; - } - } else { - ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t)); - if (ifp == NULL) { - DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t))); - return NULL; - } - } - - memset(ifp, 0, sizeof(dhd_if_t)); - ifp->info = dhdinfo; - ifp->idx = ifidx; - ifp->bssidx = bssidx; - if (mac != NULL) - memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN); - - /* Allocate etherdev, including space for private structure */ - ifp->net = alloc_etherdev(DHD_DEV_PRIV_SIZE); - if (ifp->net == NULL) { - DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo))); - goto fail; - } - - /* Setup the dhd interface's netdevice private structure. */ - dhd_dev_priv_save(ifp->net, dhdinfo, ifp, ifidx); - - if (name && name[0]) { - strncpy(ifp->net->name, name, IFNAMSIZ); - ifp->net->name[IFNAMSIZ - 1] = '\0'; - } -#ifdef WL_CFG80211 - if (ifidx == 0) - ifp->net->destructor = free_netdev; - else - ifp->net->destructor = dhd_netdev_free; -#else - ifp->net->destructor = free_netdev; -#endif /* WL_CFG80211 */ - strncpy(ifp->name, ifp->net->name, IFNAMSIZ); - ifp->name[IFNAMSIZ - 1] = '\0'; - dhdinfo->iflist[ifidx] = ifp; - -#ifdef PCIE_FULL_DONGLE - /* Initialize STA info list */ - INIT_LIST_HEAD(&ifp->sta_list); - DHD_IF_STA_LIST_LOCK_INIT(ifp); -#endif /* PCIE_FULL_DONGLE */ - - return ifp->net; - -fail: - if (ifp != NULL) { - if (ifp->net != NULL) { - dhd_dev_priv_clear(ifp->net); - free_netdev(ifp->net); - ifp->net = NULL; - } - MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); - ifp = NULL; - } - dhdinfo->iflist[ifidx] = NULL; - return NULL; -} - -/* unregister and free the the net_device interface associated with the indexed - * slot, also free the slot memory and set the slot pointer to NULL - */ -int -dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) -{ - dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; - dhd_if_t *ifp; - - ifp = dhdinfo->iflist[ifidx]; - if (ifp != NULL) { - if (ifp->net != NULL) { - DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx)); - - /* in unregister_netdev case, the interface gets freed by net->destructor - * (which is set to free_netdev) - */ - if (ifp->net->reg_state == NETREG_UNINITIALIZED) { - free_netdev(ifp->net); - } else { - netif_stop_queue(ifp->net); - - - -#ifdef SET_RPS_CPUS - custom_rps_map_clear(ifp->net->_rx); -#endif /* SET_RPS_CPUS */ - if (need_rtnl_lock) - unregister_netdev(ifp->net); - else - unregister_netdevice(ifp->net); - } - ifp->net = NULL; -#if defined(BCMPCIE) && defined(CUSTOMER_HW5) - if (ifidx == 0) - dhdinfo->register_if_done = FALSE; -#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ - } -#ifdef DHD_WMF - dhd_wmf_cleanup(dhdpub, ifidx); -#endif /* DHD_WMF */ - - dhd_if_del_sta_list(ifp); - - dhdinfo->iflist[ifidx] = NULL; - MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); - - } - - return BCME_OK; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -static struct net_device_ops dhd_ops_pri = { - .ndo_open = dhd_open, - .ndo_stop = dhd_stop, - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - .ndo_set_rx_mode = dhd_set_multicast_list, -#else - .ndo_set_multicast_list = dhd_set_multicast_list, -#endif -}; - -static struct net_device_ops dhd_ops_virt = { - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - .ndo_set_rx_mode = dhd_set_multicast_list, -#else - .ndo_set_multicast_list = dhd_set_multicast_list, -#endif -}; - -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ - -#ifdef DEBUGGER -extern void debugger_init(void *bus_handle); -#endif - - -#ifdef SHOW_LOGTRACE -static char *logstrs_path = "/root/logstrs.bin"; -module_param(logstrs_path, charp, S_IRUGO); - -int -dhd_init_logstrs_array(dhd_event_log_t *temp) -{ - struct file *filep = NULL; - struct kstat stat; - mm_segment_t fs; - char *raw_fmts = NULL; - int logstrs_size = 0; - - logstr_header_t *hdr = NULL; - uint32 *lognums = NULL; - char *logstrs = NULL; - int ram_index = 0; - char **fmts; - int num_fmts = 0; - uint32 i = 0; - int error = 0; - set_fs(KERNEL_DS); - fs = get_fs(); - filep = filp_open(logstrs_path, O_RDONLY, 0); - if (IS_ERR(filep)) { - DHD_ERROR(("Failed to open the file logstrs.bin in %s", __FUNCTION__)); - goto fail; - } - error = vfs_stat(logstrs_path, &stat); - if (error) { - DHD_ERROR(("Failed in %s to find file stat", __FUNCTION__)); - goto fail; - } - logstrs_size = (int) stat.size; - - raw_fmts = kmalloc(logstrs_size, GFP_KERNEL); - if (raw_fmts == NULL) { - DHD_ERROR(("Failed to allocate raw_fmts memory")); - goto fail; - } - if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) { - DHD_ERROR(("Error: Log strings file read failed")); - goto fail; - } - - /* Remember header from the logstrs.bin file */ - hdr = (logstr_header_t *) (raw_fmts + logstrs_size - - sizeof(logstr_header_t)); - - if (hdr->log_magic == LOGSTRS_MAGIC) { - /* - * logstrs.bin start with header. - */ - num_fmts = hdr->rom_logstrs_offset / sizeof(uint32); - ram_index = (hdr->ram_lognums_offset - - hdr->rom_lognums_offset) / sizeof(uint32); - lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset]; - logstrs = (char *) &raw_fmts[hdr->rom_logstrs_offset]; - } else { - /* - * Legacy logstrs.bin format without header. - */ - num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32); - if (num_fmts == 0) { - /* Legacy ROM/RAM logstrs.bin format: - * - ROM 'lognums' section - * - RAM 'lognums' section - * - ROM 'logstrs' section. - * - RAM 'logstrs' section. - * - * 'lognums' is an array of indexes for the strings in the - * 'logstrs' section. The first uint32 is 0 (index of first - * string in ROM 'logstrs' section). - * - * The 4324b5 is the only ROM that uses this legacy format. Use the - * fixed number of ROM fmtnums to find the start of the RAM - * 'lognums' section. Use the fixed first ROM string ("Con\n") to - * find the ROM 'logstrs' section. - */ - #define NUM_4324B5_ROM_FMTS 186 - #define FIRST_4324B5_ROM_LOGSTR "Con\n" - ram_index = NUM_4324B5_ROM_FMTS; - lognums = (uint32 *) raw_fmts; - num_fmts = ram_index; - logstrs = (char *) &raw_fmts[num_fmts << 2]; - while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) { - num_fmts++; - logstrs = (char *) &raw_fmts[num_fmts << 2]; - } - } else { - /* Legacy RAM-only logstrs.bin format: - * - RAM 'lognums' section - * - RAM 'logstrs' section. - * - * 'lognums' is an array of indexes for the strings in the - * 'logstrs' section. The first uint32 is an index to the - * start of 'logstrs'. Therefore, if this index is divided - * by 'sizeof(uint32)' it provides the number of logstr - * entries. - */ - ram_index = 0; - lognums = (uint32 *) raw_fmts; - logstrs = (char *) &raw_fmts[num_fmts << 2]; - } - } - fmts = kmalloc(num_fmts * sizeof(char *), GFP_KERNEL); - if (fmts == NULL) { - DHD_ERROR(("Failed to allocate fmts memory")); - goto fail; - } - - for (i = 0; i < num_fmts; i++) { - /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base - * (they are 0-indexed relative to 'rom_logstrs_offset'). - * - * RAM lognums are already indexed to point to the correct RAM logstrs (they - * are 0-indexed relative to the start of the logstrs.bin file). - */ - if (i == ram_index) { - logstrs = raw_fmts; - } - fmts[i] = &logstrs[lognums[i]]; - } - temp->fmts = fmts; - temp->raw_fmts = raw_fmts; - temp->num_fmts = num_fmts; - filp_close(filep, NULL); - set_fs(fs); - return 0; -fail: - if (raw_fmts) { - kfree(raw_fmts); - raw_fmts = NULL; - } - if (!IS_ERR(filep)) - filp_close(filep, NULL); - set_fs(fs); - temp->fmts = NULL; - return -1; -} -#endif /* SHOW_LOGTRACE */ - - -dhd_pub_t * -dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) -{ - dhd_info_t *dhd = NULL; - struct net_device *net = NULL; - char if_name[IFNAMSIZ] = {'\0'}; - uint32 bus_type = -1; - uint32 bus_num = -1; - uint32 slot_num = -1; - wifi_adapter_info_t *adapter = NULL; - - dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* will implement get_ids for DBUS later */ -#if defined(BCMSDIO) - dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); -#endif - adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); - - /* Allocate primary dhd_info */ - dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t)); - if (dhd == NULL) { - dhd = MALLOC(osh, sizeof(dhd_info_t)); - if (dhd == NULL) { - DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); - goto fail; - } - } - memset(dhd, 0, sizeof(dhd_info_t)); - dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; - - dhd->unit = dhd_found + instance_base; /* do not increment dhd_found, yet */ - - dhd->pub.osh = osh; - dhd->adapter = adapter; - -#ifdef GET_CUSTOM_MAC_ENABLE - wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet); -#endif /* GET_CUSTOM_MAC_ENABLE */ -#ifdef CUSTOM_FORCE_NODFS_FLAG - dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; - dhd->pub.force_country_change = TRUE; -#endif - dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; - dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; - - /* Initialize thread based operation and lock */ - sema_init(&dhd->sdsem, 1); - - /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name. - * This is indeed a hack but we have to make it work properly before we have a better - * solution - */ - dhd_update_fw_nv_path(dhd); - - /* Link to info module */ - dhd->pub.info = dhd; - - - /* Link to bus module */ - dhd->pub.bus = bus; - dhd->pub.hdrlen = bus_hdrlen; - - /* Set network interface name if it was provided as module parameter */ - if (iface_name[0]) { - int len; - char ch; - strncpy(if_name, iface_name, IFNAMSIZ); - if_name[IFNAMSIZ - 1] = 0; - len = strlen(if_name); - ch = if_name[len - 1]; - if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) - strcat(if_name, "%d"); - } - net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE); - if (net == NULL) - goto fail; - dhd_state |= DHD_ATTACH_STATE_ADD_IF; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - net->open = NULL; -#else - net->netdev_ops = NULL; -#endif - - sema_init(&dhd->proto_sem, 1); - -#ifdef PROP_TXSTATUS - spin_lock_init(&dhd->wlfc_spinlock); - - dhd->pub.skip_fc = dhd_wlfc_skip_fc; - dhd->pub.plat_init = dhd_wlfc_plat_init; - dhd->pub.plat_deinit = dhd_wlfc_plat_deinit; -#endif /* PROP_TXSTATUS */ - - /* Initialize other structure content */ - init_waitqueue_head(&dhd->ioctl_resp_wait); - init_waitqueue_head(&dhd->d3ack_wait); - init_waitqueue_head(&dhd->ctrl_wait); - - /* Initialize the spinlocks */ - spin_lock_init(&dhd->sdlock); - spin_lock_init(&dhd->txqlock); - spin_lock_init(&dhd->dhd_lock); - spin_lock_init(&dhd->rxf_lock); -#if defined(RXFRAME_THREAD) - dhd->rxthread_enabled = TRUE; -#endif /* defined(RXFRAME_THREAD) */ - -#ifdef DHDTCPACK_SUPPRESS - spin_lock_init(&dhd->tcpack_lock); -#endif /* DHDTCPACK_SUPPRESS */ - - /* Initialize Wakelock stuff */ - spin_lock_init(&dhd->wakelock_spinlock); - spin_lock_init(&dhd->wakelock_evt_spinlock); - DHD_OS_WAKE_LOCK_INIT(dhd); - dhd->wakelock_wd_counter = 0; -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); -#endif /* CONFIG_HAS_WAKELOCK */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_init(&dhd->dhd_net_if_mutex); - mutex_init(&dhd->dhd_suspend_mutex); -#endif - dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; - - /* Attach and link in the protocol */ - if (dhd_prot_attach(&dhd->pub) != 0) { - DHD_ERROR(("dhd_prot_attach failed\n")); - goto fail; - } - dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; - -#ifdef WL_CFG80211 - /* Attach and link in the cfg80211 */ - if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { - DHD_ERROR(("wl_cfg80211_attach failed\n")); - goto fail; - } - - dhd_monitor_init(&dhd->pub); - dhd_state |= DHD_ATTACH_STATE_CFG80211; -#endif - -#ifdef SHOW_LOGTRACE - dhd_init_logstrs_array(&dhd->event_data); -#endif /* SHOW_LOGTRACE */ - - if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) { - DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA)); - goto fail; - } - - - /* Set up the watchdog timer */ - init_timer(&dhd->timer); - dhd->timer.data = (ulong)dhd; - dhd->timer.function = dhd_watchdog; - dhd->default_wd_interval = dhd_watchdog_ms; - - if (dhd_watchdog_prio >= 0) { - /* Initialize watchdog thread */ - PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); - - } else { - dhd->thr_wdt_ctl.thr_pid = -1; - } - -#ifdef DEBUGGER - debugger_init((void *) bus); -#endif - - /* Set up the bottom half handler */ - if (dhd_dpc_prio >= 0) { - /* Initialize DPC thread */ - PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); - } else { - /* use tasklet for dpc */ - tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); - dhd->thr_dpc_ctl.thr_pid = -1; - } - - if (dhd->rxthread_enabled) { - bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND); - /* Initialize RXF thread */ - PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf"); - } - - dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; - -#if defined(CONFIG_PM_SLEEP) - if (!dhd_pm_notifier_registered) { - dhd_pm_notifier_registered = TRUE; - register_pm_notifier(&dhd_pm_notifier); - } -#endif /* CONFIG_PM_SLEEP */ - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; - dhd->early_suspend.suspend = dhd_early_suspend; - dhd->early_suspend.resume = dhd_late_resume; - register_early_suspend(&dhd->early_suspend); - dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -#ifdef ARP_OFFLOAD_SUPPORT - dhd->pend_ipaddr = 0; - if (!dhd_inetaddr_notifier_registered) { - dhd_inetaddr_notifier_registered = TRUE; - register_inetaddr_notifier(&dhd_inetaddr_notifier); - } -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef CONFIG_IPV6 - if (!dhd_inet6addr_notifier_registered) { - dhd_inet6addr_notifier_registered = TRUE; - register_inet6addr_notifier(&dhd_inet6addr_notifier); - } -#endif - dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd); -#ifdef DEBUG_CPU_FREQ - dhd->new_freq = alloc_percpu(int); - dhd->freq_trans.notifier_call = dhd_cpufreq_notifier; - cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); -#endif -#ifdef DHDTCPACK_SUPPRESS -#ifdef BCMSDIO - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DELAYTX); -#elif defined(BCMPCIE) - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_HOLD); -#else - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); -#endif /* BCMSDIO */ -#endif /* DHDTCPACK_SUPPRESS */ - - dhd_state |= DHD_ATTACH_STATE_DONE; - dhd->dhd_state = dhd_state; - - dhd_found++; - - (void)dhd_sysfs_init(dhd); - - return &dhd->pub; - -fail: - if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) { - DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", - __FUNCTION__, dhd_state, &dhd->pub)); - dhd->dhd_state = dhd_state; - dhd_detach(&dhd->pub); - dhd_free(&dhd->pub); - } - - return NULL; -} - -int dhd_get_fw_mode(dhd_info_t *dhdinfo) -{ - if (strstr(dhdinfo->fw_path, "_apsta") != NULL) - return DHD_FLAG_HOSTAP_MODE; - if (strstr(dhdinfo->fw_path, "_p2p") != NULL) - return DHD_FLAG_P2P_MODE; - if (strstr(dhdinfo->fw_path, "_ibss") != NULL) - return DHD_FLAG_IBSS_MODE; - if (strstr(dhdinfo->fw_path, "_mfg") != NULL) - return DHD_FLAG_MFG_MODE; - - return DHD_FLAG_STA_MODE; -} - -bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) -{ - int fw_len; - int nv_len; - const char *fw = NULL; - const char *nv = NULL; - wifi_adapter_info_t *adapter = dhdinfo->adapter; - - - /* Update firmware and nvram path. The path may be from adapter info or module parameter - * The path from adapter info is used for initialization only (as it won't change). - * - * The firmware_path/nvram_path module parameter may be changed by the system at run - * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private - * command may change dhdinfo->fw_path. As such we need to clear the path info in - * module parameter after it is copied. We won't update the path until the module parameter - * is changed again (first character is not '\0') - */ - - /* set default firmware and nvram path for built-in type driver */ - if (!dhd_download_fw_on_driverload) { -#ifdef CONFIG_BCMDHD_FW_PATH - fw = CONFIG_BCMDHD_FW_PATH; -#endif /* CONFIG_BCMDHD_FW_PATH */ -#ifdef CONFIG_BCMDHD_NVRAM_PATH - nv = CONFIG_BCMDHD_NVRAM_PATH; -#endif /* CONFIG_BCMDHD_NVRAM_PATH */ - } - - /* check if we need to initialize the path */ - if (dhdinfo->fw_path[0] == '\0') { - if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0') - fw = adapter->fw_path; - - } - if (dhdinfo->nv_path[0] == '\0') { - if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0') - nv = adapter->nv_path; - } - - /* Use module parameter if it is valid, EVEN IF the path has not been initialized - * - * TODO: need a solution for multi-chip, can't use the same firmware for all chips - */ - if (firmware_path[0] != '\0') - fw = firmware_path; - if (nvram_path[0] != '\0') - nv = nvram_path; - - if (fw && fw[0] != '\0') { - fw_len = strlen(fw); - if (fw_len >= sizeof(dhdinfo->fw_path)) { - DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n")); - return FALSE; - } - strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path)); - if (dhdinfo->fw_path[fw_len-1] == '\n') - dhdinfo->fw_path[fw_len-1] = '\0'; - } - if (nv && nv[0] != '\0') { - nv_len = strlen(nv); - if (nv_len >= sizeof(dhdinfo->nv_path)) { - DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n")); - return FALSE; - } - strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path)); - if (dhdinfo->nv_path[nv_len-1] == '\n') - dhdinfo->nv_path[nv_len-1] = '\0'; - } - - /* clear the path in module parameter */ - firmware_path[0] = '\0'; - nvram_path[0] = '\0'; - -#ifndef BCMEMBEDIMAGE - /* fw_path and nv_path are not mandatory for BCMEMBEDIMAGE */ - if (dhdinfo->fw_path[0] == '\0') { - DHD_ERROR(("firmware path not found\n")); - return FALSE; - } - if (dhdinfo->nv_path[0] == '\0') { - DHD_ERROR(("nvram path not found\n")); - return FALSE; - } -#endif /* BCMEMBEDIMAGE */ - - return TRUE; -} - - -int -dhd_bus_start(dhd_pub_t *dhdp) -{ - int ret = -1; - dhd_info_t *dhd = (dhd_info_t*)dhdp->info; - unsigned long flags; - - ASSERT(dhd); - - DHD_TRACE(("Enter %s:\n", __FUNCTION__)); - - DHD_PERIM_LOCK(dhdp); - - /* try to download image and nvram to the dongle */ - if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) { - DHD_INFO(("%s download fw %s, nv %s\n", __FUNCTION__, dhd->fw_path, dhd->nv_path)); - ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, - dhd->fw_path, dhd->nv_path); - if (ret < 0) { - DHD_ERROR(("%s: failed to download firmware %s\n", - __FUNCTION__, dhd->fw_path)); - DHD_PERIM_UNLOCK(dhdp); - return ret; - } - } - if (dhd->pub.busstate != DHD_BUS_LOAD) { - DHD_PERIM_UNLOCK(dhdp); - return -ENETDOWN; - } - - dhd_os_sdlock(dhdp); - - /* Start the watchdog timer */ - dhd->pub.tickcnt = 0; - dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - - /* Bring up the bus */ - if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { - - DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); - dhd_os_sdunlock(dhdp); - DHD_PERIM_UNLOCK(dhdp); - return ret; - } -#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE) -#if defined(BCMPCIE_OOB_HOST_WAKE) - dhd_os_sdunlock(dhdp); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - /* Host registration for OOB interrupt */ - if (dhd_bus_oob_intr_register(dhdp)) { - /* deactivate timer and wait for the handler to finish */ -#if !defined(BCMPCIE_OOB_HOST_WAKE) - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->wd_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - del_timer_sync(&dhd->timer); - - dhd_os_sdunlock(dhdp); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - DHD_PERIM_UNLOCK(dhdp); - DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); - DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); - return -ENODEV; - } - -#if defined(BCMPCIE_OOB_HOST_WAKE) - dhd_os_sdlock(dhdp); - dhd_bus_oob_intr_set(dhdp, TRUE); -#else - /* Enable oob at firmware */ - dhd_enable_oob_intr(dhd->pub.bus, TRUE); -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#endif -#ifdef PCIE_FULL_DONGLE - { - uint8 txpush = 0; - uint32 num_flowrings; /* includes H2D common rings */ - num_flowrings = dhd_bus_max_h2d_queues(dhd->pub.bus, &txpush); - DHD_ERROR(("%s: Initializing %u flowrings\n", __FUNCTION__, - num_flowrings)); - if ((ret = dhd_flow_rings_init(&dhd->pub, num_flowrings)) != BCME_OK) { - dhd_os_sdunlock(dhdp); - DHD_PERIM_UNLOCK(dhdp); - return ret; - } - } -#endif /* PCIE_FULL_DONGLE */ - - /* Do protocol initialization necessary for IOCTL/IOVAR */ - dhd_prot_init(&dhd->pub); - - /* If bus is not ready, can't come up */ - if (dhd->pub.busstate != DHD_BUS_DATA) { - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->wd_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - del_timer_sync(&dhd->timer); - DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); - dhd_os_sdunlock(dhdp); - DHD_PERIM_UNLOCK(dhdp); - DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); - return -ENODEV; - } - - dhd_os_sdunlock(dhdp); - - /* Bus is ready, query any dongle information */ - if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) { - DHD_PERIM_UNLOCK(dhdp); - return ret; - } - -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd->pend_ipaddr) { -#ifdef AOE_IP_ALIAS_SUPPORT - aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); -#endif /* AOE_IP_ALIAS_SUPPORT */ - dhd->pend_ipaddr = 0; - } -#endif /* ARP_OFFLOAD_SUPPORT */ - - DHD_PERIM_UNLOCK(dhdp); - return 0; -} -#ifdef WLTDLS -int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac) -{ - char iovbuf[WLC_IOCTL_SMLEN]; - uint32 tdls = tdls_on; - int ret = 0; - uint32 tdls_auto_op = 0; - uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING; - int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH; - int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW; - BCM_REFERENCE(mac); - if (!FW_SUPPORTED(dhd, tdls)) - return BCME_ERROR; - - if (dhd->tdls_enable == tdls_on) - goto auto_mode; - bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret)); - goto exit; - } - dhd->tdls_enable = tdls_on; -auto_mode: - - tdls_auto_op = auto_on; - bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); - goto exit; - } - - if (tdls_auto_op) { - bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time, - sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); - goto exit; - } - bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret)); - goto exit; - } - bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret)); - goto exit; - } - } - -exit: - return ret; -} -int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - if (dhd) - ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac); - else - ret = BCME_ERROR; - return ret; -} -#ifdef PCIE_FULL_DONGLE -void dhd_tdls_update_peer_info(struct net_device *dev, bool connect, uint8 *da) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - dhd_pub_t *dhdp = (dhd_pub_t *)&dhd->pub; - tdls_peer_node_t *cur = dhdp->peer_tbl.node; - tdls_peer_node_t *new = NULL, *prev = NULL; - dhd_if_t *dhdif; - uint8 sa[ETHER_ADDR_LEN]; - int ifidx = dhd_net2idx(dhd, dev); - - if (ifidx == DHD_BAD_IF) - return; - - dhdif = dhd->iflist[ifidx]; - memcpy(sa, dhdif->mac_addr, ETHER_ADDR_LEN); - - if (connect) { - while (cur != NULL) { - if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { - DHD_ERROR(("%s: TDLS Peer exist already %d\n", - __FUNCTION__, __LINE__)); - return; - } - cur = cur->next; - } - - new = MALLOC(dhdp->osh, sizeof(tdls_peer_node_t)); - if (new == NULL) { - DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__)); - return; - } - memcpy(new->addr, da, ETHER_ADDR_LEN); - new->next = dhdp->peer_tbl.node; - dhdp->peer_tbl.node = new; - dhdp->peer_tbl.tdls_peer_count++; - - } else { - while (cur != NULL) { - if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { - dhd_flow_rings_delete_for_peer(dhdp, ifidx, da); - if (prev) - prev->next = cur->next; - else - dhdp->peer_tbl.node = cur->next; - MFREE(dhdp->osh, cur, sizeof(tdls_peer_node_t)); - dhdp->peer_tbl.tdls_peer_count--; - return; - } - prev = cur; - cur = cur->next; - } - DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__)); - } -} -#endif /* PCIE_FULL_DONGLE */ -#endif - -bool dhd_is_concurrent_mode(dhd_pub_t *dhd) -{ - if (!dhd) - return FALSE; - - if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) - return TRUE; - else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == - DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) - return TRUE; - else - return FALSE; -} -#if !defined(AP) && defined(WLP2P) -/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware - * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA - * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware - * would still be named as fw_bcmdhd_apsta. - */ -uint32 -dhd_get_concurrent_capabilites(dhd_pub_t *dhd) -{ - int32 ret = 0; - char buf[WLC_IOCTL_SMLEN]; - bool mchan_supported = FALSE; - /* if dhd->op_mode is already set for HOSTAP and Manufacturing - * test mode, that means we only will use the mode as it is - */ - if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE)) - return 0; - if (FW_SUPPORTED(dhd, vsdb)) { - mchan_supported = TRUE; - } - if (!FW_SUPPORTED(dhd, p2p)) { - DHD_TRACE(("Chip does not support p2p\n")); - return 0; - } - else { - /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), - FALSE, 0)) < 0) { - DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); - return 0; - } - else { - if (buf[0] == 1) { - /* By default, chip supports single chan concurrency, - * now lets check for mchan - */ - ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; - if (mchan_supported) - ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; -#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) - /* For customer_hw4, although ICS, - * we still support concurrent mode - */ - return ret; -#else - return 0; -#endif - } - } - } - return 0; -} -#endif - - - - -int -dhd_preinit_ioctls(dhd_pub_t *dhd) -{ - int ret = 0; - char eventmask[WL_EVENTING_MASK_LEN]; - char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - uint32 buf_key_b4_m4 = 1; - uint8 msglen; - eventmsgs_ext_t *eventmask_msg = NULL; - char* iov_buf = NULL; - int ret2 = 0; -#ifdef WLAIBSS - aibss_bcn_force_config_t bcn_config; - uint32 aibss; -#ifdef WLAIBSS_PS - uint32 aibss_ps; -#endif /* WLAIBSS_PS */ -#endif /* WLAIBSS */ -#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ - defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) - uint32 ampdu_ba_wsize = 0; -#endif /* CUSTOM_AMPDU_BA_WSIZE ||(WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ -#if defined(CUSTOM_AMPDU_MPDU) - int32 ampdu_mpdu = 0; -#endif -#if defined(CUSTOM_AMPDU_RELEASE) - int32 ampdu_release = 0; -#endif -#if defined(CUSTOM_AMSDU_AGGSF) - int32 amsdu_aggsf = 0; -#endif - -#if defined(BCMSDIO) -#ifdef PROP_TXSTATUS - int wlfc_enable = TRUE; -#ifndef DISABLE_11N - uint32 hostreorder = 1; -#endif /* DISABLE_11N */ -#endif /* PROP_TXSTATUS */ -#endif -#ifndef PCIE_FULL_DONGLE - uint32 wl_ap_isolate; -#endif /* PCIE_FULL_DONGLE */ - -#ifdef DHD_ENABLE_LPC - uint32 lpc = 1; -#endif /* DHD_ENABLE_LPC */ - uint power_mode = PM_FAST; - uint32 dongle_align = DHD_SDALIGN; -#if defined(BCMSDIO) - uint32 glom = CUSTOM_GLOM_SETTING; -#endif /* defined(BCMSDIO) */ -#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) - uint32 credall = 1; -#endif -#ifdef SOMC_WLAN_BCN_TIMEOUT - uint bcn_timeout = SOMC_WLAN_BCN_TIMEOUT; -#else -#if defined(VSDB) || defined(ROAM_ENABLE) - uint bcn_timeout = CUSTOM_BCN_TIMEOUT; -#else - uint bcn_timeout = 4; -#endif -#endif /* SOMC_WLAN_BCN_TIMEOUT */ - uint retry_max = 3; -#if defined(ARP_OFFLOAD_SUPPORT) - int arpoe = 1; -#endif - int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; - int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; - int scan_passive_time = DHD_SCAN_PASSIVE_TIME; - char buf[WLC_IOCTL_SMLEN]; - char *ptr; - uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ -#ifdef ROAM_ENABLE - uint roamvar = 0; - int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; - int roam_scan_period[2] = {10, WLC_BAND_ALL}; - int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; -#ifdef ROAM_AP_ENV_DETECTION - int roam_env_mode = AP_ENV_INDETERMINATE; -#endif /* ROAM_AP_ENV_DETECTION */ -#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC - int roam_fullscan_period = 60; -#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ - int roam_fullscan_period = 120; -#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ -#else -#ifdef DISABLE_BUILTIN_ROAM - uint roamvar = 1; -#endif /* DISABLE_BUILTIN_ROAM */ -#endif /* ROAM_ENABLE */ - -#if defined(SOFTAP) - uint dtim = 1; -#endif -#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) - uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ - struct ether_addr p2p_ea; -#endif -#ifdef BCMCCX - uint32 ccx = 1; -#endif -#ifdef SOFTAP_UAPSD_OFF - uint32 wme_apsd = 0; -#endif /* SOFTAP_UAPSD_OFF */ -#ifdef SET_RETRY_LIMIT - uint srl = CUSTOM_SRL_SETTING; - uint lrl = CUSTOM_LRL_SETTING; -#endif /* SET_RETRY_LIMIT */ -#if (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) - uint32 apsta = 1; /* Enable APSTA mode */ -#elif defined(SOFTAP_AND_GC) - uint32 apsta = 0; - int ap_mode = 1; -#endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */ -#ifdef GET_CUSTOM_MAC_ENABLE - struct ether_addr ea_addr; -#endif /* GET_CUSTOM_MAC_ENABLE */ - -#ifdef DISABLE_11N - uint32 nmode = 0; -#endif /* DISABLE_11N */ - - uint32 vhtmode = 0; -#ifdef USE_WL_TXBF - uint32 txbf = 1; -#endif /* USE_WL_TXBF */ -#ifdef DISABLE_TXBFR - uint32 txbf_bfr_cap = 0; -#endif /* DISABLE_TXBFR */ -#ifdef AMPDU_VO_ENABLE - struct ampdu_tid_control tid; -#endif -#ifdef USE_WL_FRAMEBURST - uint32 frameburst = 1; -#endif /* USE_WL_FRAMEBURST */ -#ifdef DHD_SET_FW_HIGHSPEED - uint32 ack_ratio = 250; - uint32 ack_ratio_depth = 64; -#endif /* DHD_SET_FW_HIGHSPEED */ -#ifdef SUPPORT_2G_VHT - uint32 vht_features = 0x3; /* 2G enable | rates all */ -#endif /* SUPPORT_2G_VHT */ -#ifdef CUSTOM_PSPRETEND_THR - uint32 pspretend_thr = CUSTOM_PSPRETEND_THR; -#endif -#ifdef DISABLE_BCN_DLY - uint bcn_to_dly = 0; -#endif -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = TRUE; -#endif /* PKT_FILTER_SUPPORT */ -#ifdef WLTDLS - dhd->tdls_enable = FALSE; -#endif /* WLTDLS */ - dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; - DHD_TRACE(("Enter %s\n", __FUNCTION__)); - dhd->op_mode = 0; - if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || - (op_mode == DHD_FLAG_MFG_MODE)) { - /* Check and adjust IOCTL response timeout for Manufactring firmware */ - dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT); - DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n", - __FUNCTION__)); - } - else { - dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); - DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__)); - } -#ifdef GET_CUSTOM_MAC_ENABLE - ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet); - if (!ret) { - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); - ret = BCME_NOTUP; - goto done; - } - memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN); - } else { -#endif /* GET_CUSTOM_MAC_ENABLE */ - /* Get the default device MAC address directly from firmware */ - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), - FALSE, 0)) < 0) { - DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); - ret = BCME_NOTUP; - goto done; - } - /* Update public MAC address after reading from Firmware */ - memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); - -#ifdef GET_CUSTOM_MAC_ENABLE - } -#endif /* GET_CUSTOM_MAC_ENABLE */ - - /* get a capabilities from firmware */ - memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities)); - bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities, - sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) { - DHD_ERROR(("%s: Get Capability failed (error=%d)\n", - __FUNCTION__, ret)); - goto done; - } - if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) || - (op_mode == DHD_FLAG_HOSTAP_MODE)) { -#ifdef SET_RANDOM_MAC_SOFTAP - uint rand_mac; -#endif - dhd->op_mode = DHD_FLAG_HOSTAP_MODE; -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; -#endif -#ifdef SET_RANDOM_MAC_SOFTAP - SRANDOM32((uint)jiffies); - rand_mac = RANDOM32(); - iovbuf[0] = 0x02; /* locally administered bit */ - iovbuf[1] = 0x1A; - iovbuf[2] = 0x11; - iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; - iovbuf[4] = (unsigned char)(rand_mac >> 8); - iovbuf[5] = (unsigned char)(rand_mac >> 16); - - bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); - } else - memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); -#endif /* SET_RANDOM_MAC_SOFTAP */ -#if !defined(AP) && defined(WL_CFG80211) - /* Turn off MPC in AP mode */ - bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); - } -#endif -#ifdef SOFTAP_UAPSD_OFF - bcm_mkiovar("wme_apsd", (char *)&wme_apsd, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n", __FUNCTION__, ret)); -#endif /* SOFTAP_UAPSD_OFF */ -#ifdef SET_RETRY_LIMIT - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SRL, (char *)&srl, - sizeof(srl), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set SRL failed %d\n", __FUNCTION__, ret)); - } - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_LRL, (char *)&lrl, - sizeof(lrl), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set LRL failed %d\n", __FUNCTION__, ret)); - } -#endif /* SET_RETRY_LIMIT */ - } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || - (op_mode == DHD_FLAG_MFG_MODE)) { -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; -#endif /* PKT_FILTER_SUPPORT */ - dhd->op_mode = DHD_FLAG_MFG_MODE; - } else { - uint32 concurrent_mode = 0; - if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) || - (op_mode == DHD_FLAG_P2P_MODE)) { -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; -#endif - dhd->op_mode = DHD_FLAG_P2P_MODE; - } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) || - (op_mode == DHD_FLAG_IBSS_MODE)) { - dhd->op_mode = DHD_FLAG_IBSS_MODE; - } else - dhd->op_mode = DHD_FLAG_STA_MODE; -#if !defined(AP) && defined(WLP2P) - if (dhd->op_mode != DHD_FLAG_IBSS_MODE && - (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 1; -#endif - dhd->op_mode |= concurrent_mode; - } - - /* Check if we are enabling p2p */ - if (dhd->op_mode & DHD_FLAG_P2P_MODE) { - bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret)); - } - -#if defined(SOFTAP_AND_GC) - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP, - (char *)&ap_mode, sizeof(ap_mode), TRUE, 0)) < 0) { - DHD_ERROR(("%s WLC_SET_AP failed %d\n", __FUNCTION__, ret)); - } -#endif - memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); - ETHER_SET_LOCALADDR(&p2p_ea); - bcm_mkiovar("p2p_da_override", (char *)&p2p_ea, - ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); - } else { - DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); - } - } -#else - (void)concurrent_mode; -#endif - } - - DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n", - dhd->op_mode, MAC2STRDBG(dhd->mac.octet))); - /* Set Country code */ - if (dhd->dhd_cspec.ccode[0] != 0) { - bcm_mkiovar("country", (char *)&dhd->dhd_cspec, - sizeof(wl_country_t), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); - } - -#if !defined(DISABLE_11AC) - if (somc_disable_vht) - { -#endif /* ! DISABLE_11AC */ - bcm_mkiovar("vhtmode", (char *)&vhtmode, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s wl vhtmode 0 failed %d\n", __FUNCTION__, ret)); - else - DHD_ERROR(("%s VHT(11ac) mode is disabled\n", __FUNCTION__)); -#if !defined(DISABLE_11AC) - } -#endif /* ! DISABLE_11AC */ - - /* Set Listen Interval */ - bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); - -#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) - /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ -#if defined(ROAM_ENABLE) - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, - sizeof(roam_trigger), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, - sizeof(roam_scan_period), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret)); - if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, - sizeof(roam_delta), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); - bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); -#ifdef ROAM_AP_ENV_DETECTION - if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) { - bcm_mkiovar("roam_env_detection", (char *)&roam_env_mode, - 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) == BCME_OK) - dhd->roam_env_detection = TRUE; - else { - dhd->roam_env_detection = FALSE; - } - } -#endif /* ROAM_AP_ENV_DETECTION */ -#endif /* ROAM_ENABLE */ - -#ifdef BCMCCX - bcm_mkiovar("ccx_enable", (char *)&ccx, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* BCMCCX */ -#ifdef WLTDLS - /* by default TDLS on and auto mode off */ - _dhd_tdls_enable(dhd, true, false, NULL); -#endif /* WLTDLS */ - -#ifdef DHD_ENABLE_LPC - /* Set lpc 1 */ - bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); - } -#endif /* DHD_ENABLE_LPC */ - - /* Set PowerSave mode */ - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); - - /* Match Host and Dongle rx alignment */ - bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - -#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) - /* enable credall to reduce the chance of no bus credit happened. */ - bcm_mkiovar("bus:credall", (char *)&credall, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif - -#if defined(BCMSDIO) - if (glom != DEFAULT_GLOM_VALUE) { - DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom)); - bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - } -#endif /* defined(BCMSDIO) */ - - /* Setup timeout if Beacons are lost and roam is off to report link down */ - bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#ifdef SOMC_WLAN_SCAN_NPROBES - { - const uint32 scan_nprobes = SOMC_WLAN_SCAN_NPROBES; - if (( ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_NPROBES, (char *)&scan_nprobes, - sizeof(scan_nprobes), TRUE, 0)) < 0) - DHD_ERROR(("%s: set scan_nprobes failed %d\n", __FUNCTION__, ret)); - } -#endif - -#ifdef SOMC_WLAN_ENABLE_SCAN_PS - { - const uint32 scan_ps = 1; - bcm_mkiovar("scan_ps", (char *)&scan_ps, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s scan_ps failed %d\n", __FUNCTION__, ret)); - } -#endif - -#ifdef DISABLE_BCN_DLY - /* Set bcn_to_dly to delay link down until roam complete */ - bcm_mkiovar("bcn_to_dly", (char *)&bcn_to_dly, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif - /* Setup assoc_retry_max count to reconnect target AP in dongle */ - bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#if defined(AP) && !defined(WLP2P) - /* Turn off MPC in AP mode */ - bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* defined(AP) && !defined(WLP2P) */ - - -#if defined(SOFTAP) - if (ap_fw_loaded == TRUE) { - dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); - } -#endif - -#if defined(KEEP_ALIVE) - { - /* Set Keep Alive : be sure to use FW with -keepalive */ - int res; - -#if defined(SOFTAP) - if (ap_fw_loaded == FALSE) -#endif - if (!(dhd->op_mode & - (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) { - if ((res = dhd_keep_alive_onoff(dhd)) < 0) - DHD_ERROR(("%s set keeplive failed %d\n", - __FUNCTION__, res)); - } - } -#endif /* defined(KEEP_ALIVE) */ - -#ifdef USE_WL_TXBF - bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret)); - } -#endif /* USE_WL_TXBF */ -#ifdef DISABLE_TXBFR - bcm_mkiovar("txbf_bfr_cap", (char *)&txbf_bfr_cap, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Clear txbf_bfr_cap failed %d\n", __FUNCTION__, ret)); - } -#endif /* DISABLE_TXBFR */ -#ifdef USE_WL_FRAMEBURST - /* Set frameburst to value */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst, - sizeof(frameburst), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set frameburst failed %d\n", __FUNCTION__, ret)); - } -#endif /* USE_WL_FRAMEBURST */ -#ifdef DHD_SET_FW_HIGHSPEED - /* Set ack_ratio */ - bcm_mkiovar("ack_ratio", (char *)&ack_ratio, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set ack_ratio failed %d\n", __FUNCTION__, ret)); - } - - /* Set ack_ratio_depth */ - bcm_mkiovar("ack_ratio_depth", (char *)&ack_ratio_depth, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set ack_ratio_depth failed %d\n", __FUNCTION__, ret)); - } -#endif /* DHD_SET_FW_HIGHSPEED */ -#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ - defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) - /* Set ampdu ba wsize to 64 or 16 */ -#ifdef CUSTOM_AMPDU_BA_WSIZE - ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE; -#endif -#if defined(WLAIBSS) && defined(CUSTOM_IBSS_AMPDU_BA_WSIZE) - if (dhd->op_mode == DHD_FLAG_IBSS_MODE) - ampdu_ba_wsize = CUSTOM_IBSS_AMPDU_BA_WSIZE; -#endif /* WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE */ - if (ampdu_ba_wsize != 0) { - bcm_mkiovar("ampdu_ba_wsize", (char *)&du_ba_wsize, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n", - __FUNCTION__, ampdu_ba_wsize, ret)); - } - } -#endif /* CUSTOM_AMPDU_BA_WSIZE || (WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ - - iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); - if (iov_buf == NULL) { - DHD_ERROR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN)); - ret = BCME_NOMEM; - goto done; - } -#ifdef WLAIBSS - /* Configure custom IBSS beacon transmission */ - if (dhd->op_mode & DHD_FLAG_IBSS_MODE) - { - aibss = 1; - bcm_mkiovar("aibss", (char *)&aibss, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set aibss to %d failed %d\n", - __FUNCTION__, aibss, ret)); - } -#ifdef WLAIBSS_PS - aibss_ps = 1; - bcm_mkiovar("aibss_ps", (char *)&aibss_ps, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set aibss PS to %d failed %d\n", - __FUNCTION__, aibss, ret)); - } -#endif /* WLAIBSS_PS */ - } - memset(&bcn_config, 0, sizeof(bcn_config)); - bcn_config.initial_min_bcn_dur = AIBSS_INITIAL_MIN_BCN_DUR; - bcn_config.min_bcn_dur = AIBSS_MIN_BCN_DUR; - bcn_config.bcn_flood_dur = AIBSS_BCN_FLOOD_DUR; - bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0; - bcn_config.len = sizeof(bcn_config); - - bcm_mkiovar("aibss_bcn_force_config", (char *)&bcn_config, - sizeof(aibss_bcn_force_config_t), iov_buf, WLC_IOCTL_SMLEN); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iov_buf, - WLC_IOCTL_SMLEN, TRUE, 0)) < 0) { - DHD_ERROR(("%s Set aibss_bcn_force_config to %d, %d, %d failed %d\n", - __FUNCTION__, AIBSS_INITIAL_MIN_BCN_DUR, AIBSS_MIN_BCN_DUR, - AIBSS_BCN_FLOOD_DUR, ret)); - } -#endif /* WLAIBSS */ - -#if defined(CUSTOM_AMPDU_MPDU) - ampdu_mpdu = CUSTOM_AMPDU_MPDU; - if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) { - bcm_mkiovar("ampdu_mpdu", (char *)&du_mpdu, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n", - __FUNCTION__, CUSTOM_AMPDU_MPDU, ret)); - } - } -#endif /* CUSTOM_AMPDU_MPDU */ - -#if defined(CUSTOM_AMPDU_RELEASE) - ampdu_release = CUSTOM_AMPDU_RELEASE; - if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) { - bcm_mkiovar("ampdu_release", (char *)&du_release, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set ampdu_release to %d failed %d\n", - __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret)); - } - } -#endif /* CUSTOM_AMPDU_RELEASE */ - -#if defined(CUSTOM_AMSDU_AGGSF) - amsdu_aggsf = CUSTOM_AMSDU_AGGSF; - if (amsdu_aggsf != 0) { - bcm_mkiovar("amsdu_aggsf", (char *)&amsdu_aggsf, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set amsdu_aggsf to %d failed %d\n", - __FUNCTION__, CUSTOM_AMSDU_AGGSF, ret)); - } - } -#endif /* CUSTOM_AMSDU_AGGSF */ - -#ifdef SUPPORT_2G_VHT - bcm_mkiovar("vht_features", (char *)&vht_features, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret)); - } -#endif /* SUPPORT_2G_VHT */ -#ifdef CUSTOM_PSPRETEND_THR - /* Turn off MPC in AP mode */ - bcm_mkiovar("pspretend_threshold", (char *)&pspretend_thr, 4, - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n", - __FUNCTION__, ret)); - } -#endif - - bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret)); - } - - /* Read event_msgs mask */ - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { - DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret)); - goto done; - } - bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); - - /* Setup event_msgs */ - setbit(eventmask, WLC_E_SET_SSID); - setbit(eventmask, WLC_E_PRUNE); - setbit(eventmask, WLC_E_AUTH); - setbit(eventmask, WLC_E_AUTH_IND); - setbit(eventmask, WLC_E_ASSOC); - setbit(eventmask, WLC_E_REASSOC); - setbit(eventmask, WLC_E_REASSOC_IND); - setbit(eventmask, WLC_E_DEAUTH); - setbit(eventmask, WLC_E_DEAUTH_IND); - setbit(eventmask, WLC_E_DISASSOC_IND); - setbit(eventmask, WLC_E_DISASSOC); - setbit(eventmask, WLC_E_JOIN); - setbit(eventmask, WLC_E_START); - setbit(eventmask, WLC_E_ASSOC_IND); - setbit(eventmask, WLC_E_PSK_SUP); - setbit(eventmask, WLC_E_LINK); - setbit(eventmask, WLC_E_NDIS_LINK); - setbit(eventmask, WLC_E_MIC_ERROR); - setbit(eventmask, WLC_E_ASSOC_REQ_IE); - setbit(eventmask, WLC_E_ASSOC_RESP_IE); -#ifndef WL_CFG80211 - setbit(eventmask, WLC_E_PMKID_CACHE); - setbit(eventmask, WLC_E_TXFAIL); -#endif - setbit(eventmask, WLC_E_JOIN_START); - setbit(eventmask, WLC_E_SCAN_COMPLETE); -#ifdef WLMEDIA_HTSF - setbit(eventmask, WLC_E_HTSFSYNC); -#endif /* WLMEDIA_HTSF */ -#ifdef PNO_SUPPORT - setbit(eventmask, WLC_E_PFN_NET_FOUND); - setbit(eventmask, WLC_E_PFN_BEST_BATCHING); - setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND); - setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST); -#endif /* PNO_SUPPORT */ - /* enable dongle roaming event */ - setbit(eventmask, WLC_E_ROAM); - setbit(eventmask, WLC_E_BSSID); -#ifdef BCMCCX - setbit(eventmask, WLC_E_ADDTS_IND); - setbit(eventmask, WLC_E_DELTS_IND); -#endif /* BCMCCX */ -#ifdef WLTDLS - setbit(eventmask, WLC_E_TDLS_PEER_EVENT); -#endif /* WLTDLS */ -#ifdef RTT_SUPPORT - setbit(eventmask, WLC_E_PROXD); -#endif /* RTT_SUPPORT */ -#ifdef WL_CFG80211 - setbit(eventmask, WLC_E_ESCAN_RESULT); - if (dhd->op_mode & DHD_FLAG_P2P_MODE) { - setbit(eventmask, WLC_E_ACTION_FRAME_RX); - setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); - } -#endif /* WL_CFG80211 */ -#ifdef WLAIBSS - setbit(eventmask, WLC_E_AIBSS_TXFAIL); -#endif /* WLAIBSS */ -#ifdef SHOW_LOGTRACE - setbit(eventmask, WLC_E_TRACE); -#else - clrbit(eventmask, WLC_E_TRACE); -#endif /* SHOW_LOGTRACE */ - setbit(eventmask, WLC_E_CSA_COMPLETE_IND); - /* Write updated Event mask */ - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret)); - goto done; - } - - /* make up event mask ext message iovar for event larger than 128 */ - msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE; - eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL); - if (eventmask_msg == NULL) { - DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen)); - ret = BCME_NOMEM; - goto done; - } - bzero(eventmask_msg, msglen); - eventmask_msg->ver = EVENTMSGS_VER; - eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; - - /* Read event_msgs_ext mask */ - bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, WLC_IOCTL_SMLEN); - ret2 = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, WLC_IOCTL_SMLEN, FALSE, 0); - if (ret2 != BCME_UNSUPPORTED) - ret = ret2; - if (ret2 == 0) { /* event_msgs_ext must be supported */ - bcopy(iov_buf, eventmask_msg, msglen); -#ifdef GSCAN_SUPPORT - setbit(eventmask_msg->mask, WLC_E_PFN_GSCAN_FULL_RESULT); - setbit(eventmask_msg->mask, WLC_E_PFN_SCAN_COMPLETE); - setbit(eventmask_msg->mask, WLC_E_PFN_SSID_EXT); -#endif /* GSCAN_SUPPORT */ -#ifdef BT_WIFI_HANDOVER - setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ); -#endif /* BT_WIFI_HANDOVER */ - - /* Write updated Event mask */ - eventmask_msg->ver = EVENTMSGS_VER; - eventmask_msg->command = EVENTMSGS_SET_MASK; - eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; - bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, - msglen, iov_buf, WLC_IOCTL_SMLEN); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iov_buf, WLC_IOCTL_SMLEN, TRUE, 0)) < 0) { - DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret)); - goto done; - } - } else if (ret2 < 0 && ret2 != BCME_UNSUPPORTED) { - DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2)); - goto done; - } /* unsupported is ok */ - - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, - sizeof(scan_assoc_time), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, - sizeof(scan_unassoc_time), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, - sizeof(scan_passive_time), TRUE, 0); - -#ifdef ARP_OFFLOAD_SUPPORT - /* Set and enable ARP offload feature for STA only */ -#if defined(SOFTAP) - if (arpoe && !ap_fw_loaded) { -#else - if (arpoe) { -#endif - dhd_arp_offload_enable(dhd, TRUE); - dhd_arp_offload_set(dhd, dhd_arp_mode); - } else { - dhd_arp_offload_enable(dhd, FALSE); - dhd_arp_offload_set(dhd, 0); - } - dhd_arp_enable = arpoe; -#endif /* ARP_OFFLOAD_SUPPORT */ - -#ifdef PKT_FILTER_SUPPORT - /* Setup default defintions for pktfilter , enable in suspend */ - dhd->pktfilter_count = 6; - /* Setup filter to allow only unicast */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; - dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; - /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ - dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; - /* apply APP pktfilter */ - dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; - - -#if defined(SOFTAP) - if (ap_fw_loaded) { - dhd_enable_packet_filter(0, dhd); - } -#endif /* defined(SOFTAP) */ - dhd_set_packet_filter(dhd); -#endif /* PKT_FILTER_SUPPORT */ -#ifdef DISABLE_11N - bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); -#endif /* DISABLE_11N */ - -#ifdef AMPDU_VO_ENABLE - tid.tid = PRIO_8021D_VO; /* Enable TID(6) for voice */ - tid.enable = TRUE; - bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - tid.tid = PRIO_8021D_NC; /* Enable TID(7) for voice */ - tid.enable = TRUE; - bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif -#ifdef SOMC_MAX_ASSOC_NUM - { - /* Set the maximum number of stations for P2P / SoftAP */ - const uint32 max = SOMC_MAX_ASSOC_NUM; - bcm_mkiovar("maxassoc", (char*)&max, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s: maxassoc set failed %d\n", __FUNCTION__, ret)); - } -#endif /* SOMC_MAX_ASSOC_NUM */ - - /* query for 'ver' to get version info from firmware */ - memset(buf, 0, sizeof(buf)); - ptr = buf; - bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) - DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); - else { - bcmstrtok(&ptr, "\n", 0); - /* Print fw version info */ - DHD_ERROR(("Firmware version = %s\n", buf)); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - snprintf(bcm_wlan_ver_info, sizeof(bcm_wlan_ver_info), - "firmware_version %s\ndhd_version %s\n", - buf, EPI_VERSION_STR); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ -#if defined(BCMSDIO) - dhd_set_version_info(dhd, buf); -#endif /* defined(BCMSDIO) */ - } - -#if defined(BCMSDIO) - dhd_txglom_enable(dhd, TRUE); -#endif /* defined(BCMSDIO) */ - -#if defined(BCMSDIO) -#ifdef PROP_TXSTATUS - if (disable_proptx || -#ifdef PROP_TXSTATUS_VSDB - /* enable WLFC only if the firmware is VSDB when it is in STA mode */ - (dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) || -#endif /* PROP_TXSTATUS_VSDB */ - FALSE) { - wlfc_enable = FALSE; - } - -#ifndef DISABLE_11N - bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, iovbuf, sizeof(iovbuf)); - if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2)); - if (ret2 != BCME_UNSUPPORTED) - ret = ret2; -#if defined(CUSTOMER_HW5) - if (ret == BCME_NOTDOWN) { - uint wl_down = 1; - ret2 = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, - sizeof(wl_down), TRUE, 0); - DHD_ERROR(("%s ampdu_hostreorder fail WL_DOWN : %d, hostreorder :%d\n", - __FUNCTION__, ret2, hostreorder)); - - bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, - iovbuf, sizeof(iovbuf)); - ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - DHD_ERROR(("%s wl ampdu_hostreorder. ret --> %d\n", __FUNCTION__, ret2)); - if (ret2 != BCME_UNSUPPORTED) - ret = ret2; - } -#endif - if (ret2 != BCME_OK) - hostreorder = 0; - } -#endif /* DISABLE_11N */ - - - if (wlfc_enable) - dhd_wlfc_init(dhd); -#ifndef DISABLE_11N - else if (hostreorder) - dhd_wlfc_hostreorder_init(dhd); -#endif /* DISABLE_11N */ - -#endif /* PROP_TXSTATUS */ -#endif /* BCMSDIO || BCMBUS */ -#ifndef PCIE_FULL_DONGLE - /* For FD we need all the packets at DHD to handle intra-BSS forwarding */ - if (FW_SUPPORTED(dhd, ap)) { - wl_ap_isolate = AP_ISOLATE_SENDUP_ALL; - bcm_mkiovar("ap_isolate", (char *)&wl_ap_isolate, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); - } -#endif /* PCIE_FULL_DONGLE */ -#ifdef PNO_SUPPORT - if (!dhd->pno_state) { - dhd_pno_init(dhd); - } -#endif -#ifdef RTT_SUPPORT - if (!dhd->rtt_state) { - ret = dhd_rtt_init(dhd); - if (ret < 0) { - DHD_ERROR(("%s failed to initialize RTT\n", __FUNCTION__)); - } - } -#endif -#ifdef WL11U - dhd_interworking_enable(dhd); -#endif /* WL11U */ - -done: - - if (eventmask_msg) - kfree(eventmask_msg); - if (iov_buf) - kfree(iov_buf); - - return ret; -} - - -int -dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set) -{ - char buf[strlen(name) + 1 + cmd_len]; - int len = sizeof(buf); - wl_ioctl_t ioc; - int ret; - - len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR; - ioc.buf = buf; - ioc.len = len; - ioc.set = set; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - if (!set && ret >= 0) - memcpy(cmd_buf, buf, cmd_len); - - return ret; -} - -int -dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, - uint cmd_len, char **resptr, uint resp_len) -{ - int len = resp_len; - int ret; - char *buf = *resptr; - wl_ioctl_t ioc; - if (resp_len > WLC_IOCTL_MAXLEN) - return BCME_BADARG; - - memset(buf, 0, resp_len); - - bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = len; - ioc.set = 0; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - - return ret; -} - -int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) -{ - struct dhd_info *dhd = dhdp->info; - struct net_device *dev = NULL; - - ASSERT(dhd && dhd->iflist[ifidx]); - dev = dhd->iflist[ifidx]->net; - ASSERT(dev); - - if (netif_running(dev)) { - DHD_ERROR(("%s: Must be down to change its MTU", dev->name)); - return BCME_NOTDOWN; - } - -#define DHD_MIN_MTU 1500 -#define DHD_MAX_MTU 1752 - - if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { - DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu)); - return BCME_BADARG; - } - - dev->mtu = new_mtu; - return 0; -} - -#ifdef ARP_OFFLOAD_SUPPORT -/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ -void -aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx) -{ - u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ - int i; - int ret; - - bzero(ipv4_buf, sizeof(ipv4_buf)); - - /* display what we've got */ - ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); - DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__)); - if (ret) { - DHD_ERROR(("%s failed\n", __FUNCTION__)); - return; - } -#ifdef AOE_DBG - dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -#endif - /* now we saved hoste_ip table, clr it in the dongle AOE */ - dhd_aoe_hostip_clr(dhd_pub, idx); - - for (i = 0; i < MAX_IPV4_ENTRIES; i++) { - if (add && (ipv4_buf[i] == 0)) { - ipv4_buf[i] = ipa; - add = FALSE; /* added ipa to local table */ - DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n", - __FUNCTION__, i)); - } else if (ipv4_buf[i] == ipa) { - ipv4_buf[i] = 0; - DHD_ARPOE(("%s: removed IP:%x from temp table %d\n", - __FUNCTION__, ipa, i)); - } - - if (ipv4_buf[i] != 0) { - /* add back host_ip entries from our local cache */ - dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx); - DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n", - __FUNCTION__, ipv4_buf[i], i)); - } - } -#ifdef AOE_DBG - /* see the resulting hostip table */ - dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); - DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__)); - dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -#endif -} - -/* - * Notification mechanism from kernel to our driver. This function is called by the Linux kernel - * whenever there is an event related to an IP address. - * ptr : kernel provided pointer to IP address that has changed - */ -static int dhd_inetaddr_notifier_call(struct notifier_block *this, - unsigned long event, - void *ptr) -{ - struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; - - dhd_info_t *dhd; - dhd_pub_t *dhd_pub; - int idx; - - if (!dhd_arp_enable) - return NOTIFY_DONE; - if (!ifa || !(ifa->ifa_dev->dev)) - return NOTIFY_DONE; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) - /* Filter notifications meant for non Broadcom devices */ - if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) && - (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) { -#if defined(WL_ENABLE_P2P_IF) - if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) -#endif /* WL_ENABLE_P2P_IF */ - return NOTIFY_DONE; - } -#endif /* LINUX_VERSION_CODE */ - - dhd = DHD_DEV_INFO(ifa->ifa_dev->dev); - if (!dhd) - return NOTIFY_DONE; - - dhd_pub = &dhd->pub; - - if (dhd_pub->arp_version == 1) { - idx = 0; - } - else { - for (idx = 0; idx < DHD_MAX_IFS; idx++) { - if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev) - break; - } - if (idx < DHD_MAX_IFS) - DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net, - dhd->iflist[idx]->name, dhd->iflist[idx]->idx)); - else { - DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label)); - idx = 0; - } - } - - switch (event) { - case NETDEV_UP: - DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - - if (dhd->pub.busstate != DHD_BUS_DATA) { - DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); - if (dhd->pend_ipaddr) { - DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", - __FUNCTION__, dhd->pend_ipaddr)); - } - dhd->pend_ipaddr = ifa->ifa_address; - break; - } - -#ifdef AOE_IP_ALIAS_SUPPORT - DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", - __FUNCTION__)); - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx); -#endif /* AOE_IP_ALIAS_SUPPORT */ - break; - - case NETDEV_DOWN: - DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - dhd->pend_ipaddr = 0; -#ifdef AOE_IP_ALIAS_SUPPORT - DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n", - __FUNCTION__)); - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx); -#else - dhd_aoe_hostip_clr(&dhd->pub, idx); - dhd_aoe_arp_clr(&dhd->pub, idx); -#endif /* AOE_IP_ALIAS_SUPPORT */ - break; - - default: - DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n", - __func__, ifa->ifa_label, event)); - break; - } - return NOTIFY_DONE; -} -#endif /* ARP_OFFLOAD_SUPPORT */ - -#ifdef CONFIG_IPV6 -/* Neighbor Discovery Offload: defered handler */ -static void -dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event) -{ - struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data; - dhd_pub_t *pub = &((dhd_info_t *)dhd_info)->pub; - int ret; - - if (event != DHD_WQ_WORK_IPV6_NDO) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!ndo_work) { - DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__)); - return; - } - - if (!pub) { - DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__)); - return; - } - - if (ndo_work->if_idx) { - DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx)); - return; - } - - switch (ndo_work->event) { - case NETDEV_UP: - DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__)); - ret = dhd_ndo_enable(pub, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret)); - } - - ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx); - if (ret < 0) { - DHD_ERROR(("%s: Adding host ip for NDO failed %d\n", - __FUNCTION__, ret)); - } - break; - case NETDEV_DOWN: - DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__)); - ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx); - if (ret < 0) { - DHD_ERROR(("%s: Removing host ip for NDO failed %d\n", - __FUNCTION__, ret)); - goto done; - } - - ret = dhd_ndo_enable(pub, FALSE); - if (ret < 0) { - DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret)); - goto done; - } - break; - default: - DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__)); - break; - } -done: - /* free ndo_work. alloced while scheduling the work */ - kfree(ndo_work); - - return; -} - -/* - * Neighbor Discovery Offload: Called when an interface - * is assigned with ipv6 address. - * Handles only primary interface - */ -static int dhd_inet6addr_notifier_call(struct notifier_block *this, - unsigned long event, - void *ptr) -{ - dhd_info_t *dhd; - dhd_pub_t *dhd_pub; - struct inet6_ifaddr *inet6_ifa = ptr; - struct in6_addr *ipv6_addr = &inet6_ifa->addr; - struct ipv6_work_info_t *ndo_info; - int idx = 0; /* REVISIT */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) - /* Filter notifications meant for non Broadcom devices */ - if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) { - return NOTIFY_DONE; - } -#endif /* LINUX_VERSION_CODE */ - - dhd = DHD_DEV_INFO(inet6_ifa->idev->dev); - if (!dhd) - return NOTIFY_DONE; - - if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev) - return NOTIFY_DONE; - dhd_pub = &dhd->pub; - if (!FW_SUPPORTED(dhd_pub, ndoe)) - return NOTIFY_DONE; - - ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC); - if (!ndo_info) { - DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__)); - return NOTIFY_DONE; - } - - ndo_info->event = event; - ndo_info->if_idx = idx; - memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN); - - /* defer the work to thread as it may block kernel */ - dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)ndo_info, DHD_WQ_WORK_IPV6_NDO, - dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW); - return NOTIFY_DONE; -} -#endif /* #ifdef CONFIG_IPV6 */ - -int -dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - dhd_if_t *ifp; - struct net_device *net = NULL; - int err = 0; - uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; - - DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - - ASSERT(dhd && dhd->iflist[ifidx]); - ifp = dhd->iflist[ifidx]; - net = ifp->net; - ASSERT(net && (ifp->idx == ifidx)); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - ASSERT(!net->open); - net->get_stats = dhd_get_stats; - net->do_ioctl = dhd_ioctl_entry; - net->hard_start_xmit = dhd_start_xmit; - net->set_mac_address = dhd_set_mac_address; - net->set_multicast_list = dhd_set_multicast_list; - net->open = net->stop = NULL; -#else - ASSERT(!net->netdev_ops); - net->netdev_ops = &dhd_ops_virt; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - - /* Ok, link into the network layer... */ - if (ifidx == 0) { -#if defined(BCMPCIE) && defined(CUSTOMER_HW5) - dhd->register_if_done = FALSE; -#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ - /* - * device functions for the primary interface only - */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - net->open = dhd_open; - net->stop = dhd_stop; -#else - net->netdev_ops = &dhd_ops_pri; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) - memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); - } else { - /* - * We have to use the primary MAC for virtual interfaces - */ - memcpy(temp_addr, ifp->mac_addr, ETHER_ADDR_LEN); - /* - * Android sets the locally administered bit to indicate that this is a - * portable hotspot. This will not work in simultaneous AP/STA mode, - * nor with P2P. Need to set the Donlge's MAC address, and then use that. - */ - if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, - ETHER_ADDR_LEN)) { - DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", - __func__, net->name)); - temp_addr[0] |= 0x02; - } - } - - net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - net->ethtool_ops = &dhd_ethtool_ops; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - - dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); - - memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); - - if (ifidx == 0) - printf("%s\n", dhd_version); - - if (need_rtnl_lock) - err = register_netdev(net); - else - err = register_netdevice(net); - - if (err != 0) { - DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err)); - goto fail; - } - - - - printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name, - MAC2STRDBG(net->dev_addr)); - -#if defined(SOFTAP) && !defined(WL_CFG80211) - wl_iw_iscan_set_scan_broadcast_prep(net, 1); -#endif - -#if (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \ - KERNEL_VERSION(2, 6, 27)))) - if (ifidx == 0) { -#ifdef BCMLXSDMMC - up(&dhd_registration_sem); -#endif - if (!dhd_download_fw_on_driverload) { -#ifdef WL_CFG80211 - wl_reinit_event_handler(); -#endif /* WL_CFG80211 */ - - dhd_net_bus_devreset(net, TRUE); -#ifdef BCMLXSDMMC - dhd_net_bus_suspend(net); -#endif /* BCMLXSDMMC */ - wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY); - } - -#if defined(BCMPCIE) && defined(CUSTOMER_HW5) - dhd->register_if_done = TRUE; -#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ - } -#endif /* OEM_ANDROID && (BCMPCIE || (BCMLXSDMMC && KERNEL_VERSION >= 2.6.27)) */ - - return 0; - -fail: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - net->open = NULL; -#else - net->netdev_ops = NULL; -#endif - return err; -} - -void -dhd_bus_detach(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - dhd = (dhd_info_t *)dhdp->info; - if (dhd) { - - /* - * In case of Android cfg80211 driver, the bus is down in dhd_stop, - * calling stop again will cuase SD read/write errors. - */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - - /* Stop the bus module */ - dhd_bus_stop(dhd->pub.bus, TRUE); - } - -#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE) - dhd_bus_oob_intr_unregister(dhdp); -#endif - } - } -} - - -void dhd_detach(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - unsigned long flags; - int timer_valid = FALSE; - - if (!dhdp) - return; - - dhd = (dhd_info_t *)dhdp->info; - if (!dhd) - return; - - - DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); - - dhd->pub.up = 0; - if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { - /* Give sufficient time for threads to start running in case - * dhd_attach() has failed - */ - OSL_SLEEP(100); - } - - if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { - dhd_bus_detach(dhdp); -#ifdef PCIE_FULL_DONGLE - dhd_flow_rings_deinit(dhdp); -#endif - - if (dhdp->prot) - dhd_prot_detach(dhdp); - } - -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd_inetaddr_notifier_registered) { - dhd_inetaddr_notifier_registered = FALSE; - unregister_inetaddr_notifier(&dhd_inetaddr_notifier); - } -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef CONFIG_IPV6 - if (dhd_inet6addr_notifier_registered) { - dhd_inet6addr_notifier_registered = FALSE; - unregister_inet6addr_notifier(&dhd_inet6addr_notifier); - } -#endif - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { - if (dhd->early_suspend.suspend) - unregister_early_suspend(&dhd->early_suspend); - } -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - - /* delete all interfaces, start with virtual */ - if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { - int i = 1; - dhd_if_t *ifp; - - /* Cleanup virtual interfaces */ - dhd_net_if_lock_local(dhd); - for (i = 1; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) - dhd_remove_if(&dhd->pub, i, TRUE); - } - dhd_net_if_unlock_local(dhd); - - /* delete primary interface 0 */ - ifp = dhd->iflist[0]; - ASSERT(ifp); - ASSERT(ifp->net); - if (ifp && ifp->net) { - - - - /* in unregister_netdev case, the interface gets freed by net->destructor - * (which is set to free_netdev) - */ - if (ifp->net->reg_state == NETREG_UNINITIALIZED) - free_netdev(ifp->net); - else { -#ifdef SET_RPS_CPUS - custom_rps_map_clear(ifp->net->_rx); -#endif /* SET_RPS_CPUS */ - unregister_netdev(ifp->net); - } - ifp->net = NULL; -#ifdef DHD_WMF - dhd_wmf_cleanup(dhdp, 0); -#endif /* DHD_WMF */ - - dhd_if_del_sta_list(ifp); - - MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); - dhd->iflist[0] = NULL; - } - } - - /* Clear the watchdog timer */ - DHD_GENERAL_LOCK(&dhd->pub, flags); - timer_valid = dhd->wd_timer_valid; - dhd->wd_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - if (timer_valid) - del_timer_sync(&dhd->timer); - - if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { - if (dhd->thr_wdt_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_wdt_ctl); - } - - if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_rxf_ctl); - } - - if (dhd->thr_dpc_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_dpc_ctl); - } else - tasklet_kill(&dhd->tasklet); - } -#ifdef WL_CFG80211 - if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { - wl_cfg80211_detach(NULL); - dhd_monitor_uninit(); - } -#endif - /* free deferred work queue */ - dhd_deferred_work_deinit(dhd->dhd_deferred_wq); - dhd->dhd_deferred_wq = NULL; - -#ifdef SHOW_LOGTRACE - if (dhd->event_data.fmts) - kfree(dhd->event_data.fmts); - if (dhd->event_data.raw_fmts) - kfree(dhd->event_data.raw_fmts); -#endif /* SHOW_LOGTRACE */ - -#ifdef PNO_SUPPORT - if (dhdp->pno_state) - dhd_pno_deinit(dhdp); -#endif -#ifdef RTT_SUPPORT - if (dhdp->rtt_state) { - dhd_rtt_deinit(dhdp); - } -#endif -#if defined(CONFIG_PM_SLEEP) - if (dhd_pm_notifier_registered) { - unregister_pm_notifier(&dhd_pm_notifier); - dhd_pm_notifier_registered = FALSE; - } -#endif /* CONFIG_PM_SLEEP */ -#ifdef DEBUG_CPU_FREQ - if (dhd->new_freq) - free_percpu(dhd->new_freq); - dhd->new_freq = NULL; - cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); -#endif - - DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); - dhd->wakelock_wd_counter = 0; -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_destroy(&dhd->wl_wdwake); -#endif /* CONFIG_HAS_WAKELOCK */ - - if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { - DHD_OS_WAKE_LOCK_DESTROY(dhd); - } - - - - -#ifdef DHDTCPACK_SUPPRESS - /* This will free all MEM allocated for TCPACK SUPPRESS */ - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); -#endif /* DHDTCPACK_SUPPRESS */ - - dhd_sysfs_exit(dhd); -} - - -void -dhd_free(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - int i; - for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { - if (dhdp->reorder_bufs[i]) { - reorder_info_t *ptr; - uint32 buf_size = sizeof(struct reorder_info); - - ptr = dhdp->reorder_bufs[i]; - - buf_size += ((ptr->max_idx + 1) * sizeof(void*)); - DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", - i, ptr->max_idx, buf_size)); - - MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); - dhdp->reorder_bufs[i] = NULL; - } - } - - dhd_sta_pool_fini(dhdp, DHD_MAX_STA); - - dhd = (dhd_info_t *)dhdp->info; - if (dhdp->soc_ram) { -#ifdef DHD_USE_STATIC_MEMDUMP - DHD_OS_PREFREE(dhdp, dhdp->soc_ram, dhdp->soc_ram_length); -#else - MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length); -#endif /* DHD_USE_STATIC_MEMDUMP */ - dhdp->soc_ram = NULL; - } - - /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */ - if (dhd && - dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE)) - MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); - dhd = NULL; - } -} - -void -dhd_clear(dhd_pub_t *dhdp) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - int i; - dhd_if_t *ifp; -#ifdef DHDTCPACK_SUPPRESS - /* Clean up timer/data structure for any remaining/pending packet or timer. */ - dhd_tcpack_info_tbl_clean(dhdp); -#endif /* DHDTCPACK_SUPPRESS */ - for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { - if (dhdp->reorder_bufs[i]) { - reorder_info_t *ptr; - uint32 buf_size = sizeof(struct reorder_info); - - ptr = dhdp->reorder_bufs[i]; - - buf_size += ((ptr->max_idx + 1) * sizeof(void*)); - DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", - i, ptr->max_idx, buf_size)); - - MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); - dhdp->reorder_bufs[i] = NULL; - } - } - - /* It would only need to delete iflist[0] because all other dynamically - * generated interfaces' iflists will be deleted in interface removal - */ - ifp = dhdp->info->iflist[0]; - if (ifp && ifp->net) { - DHD_ERROR(("%s: Delete sta list before clear\n", __FUNCTION__)); - dhd_if_del_sta_list(ifp); - } - - dhd_sta_pool_clear(dhdp, DHD_MAX_STA); - - if (dhdp->soc_ram) { -#ifdef DHD_USE_STATIC_MEMDUMP - DHD_OS_PREFREE(dhdp, dhdp->soc_ram, dhdp->soc_ram_length); -#else - MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length); -#endif /* DHD_USE_STATIC_MEMDUMP */ - dhdp->soc_ram = NULL; - } - } -} - -static void -dhd_module_cleanup(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - dhd_bus_unregister(); - - wl_android_exit(); - - dhd_wifi_platform_unregister_drv(); -} - -static void __exit -dhd_module_exit(void) -{ - dhd_module_cleanup(); - unregister_reboot_notifier(&dhd_reboot_notifier); -} - -#define BCMCONF "/data/misc/wifi/bcm_debug.conf" - -static int __init -dhd_module_init(void) -{ - int err; - int retry = POWERUP_MAX_RETRY; - void *fp = NULL; - - DHD_ERROR(("%s in\n", __FUNCTION__)); - - DHD_PERIM_RADIO_INIT(); - - if (firmware_path[0] != '\0') { - strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN); - fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0'; - } - - if (nvram_path[0] != '\0') { - strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN); - nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0'; - } - - do { - err = dhd_wifi_platform_register_drv(); - if (!err) { - register_reboot_notifier(&dhd_reboot_notifier); - break; - } - else { - DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n", - __FUNCTION__, retry)); - strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN); - firmware_path[MOD_PARAM_PATHLEN-1] = '\0'; - strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN); - nvram_path[MOD_PARAM_PATHLEN-1] = '\0'; - } - } while (retry--); - - if (err) - DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__)); - - fp = dhd_os_open_image(BCMCONF); - if (fp) { - unsigned char buf[7]; - long res = 0; - int len = dhd_os_get_image_block(buf, 7, fp); - if (len > 0 && len < 7) { - buf[len] = '\0'; - if (!kstrtol(buf, 16, &res)) - dhd_msg_level = (int)res; - } else { - DHD_ERROR(("Error in dbg level pattern\n")); - } - dhd_os_close_image(fp); - } - - DHD_ERROR(("%s out\n", __FUNCTION__)); - - return err; -} - -static int -dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused) -{ - DHD_TRACE(("%s: code = %ld\n", __FUNCTION__, code)); - if (code == SYS_RESTART) { - } - - return NOTIFY_DONE; -} - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -#if defined(CONFIG_DEFERRED_INITCALLS) -deferred_module_init(dhd_module_init); -#elif defined(USE_LATE_INITCALL_SYNC) -late_initcall_sync(dhd_module_init); -#else -late_initcall(dhd_module_init); -#endif /* USE_LATE_INITCALL_SYNC */ -#else -module_init(dhd_module_init); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ - -module_exit(dhd_module_exit); - -/* - * OS specific functions required to implement DHD driver in OS independent way - */ -int -dhd_os_proto_block(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - DHD_PERIM_UNLOCK(pub); - - down(&dhd->proto_sem); - - DHD_PERIM_LOCK(pub); - return 1; - } - - return 0; -} - -int -dhd_os_proto_unblock(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - up(&dhd->proto_sem); - return 1; - } - - return 0; -} - -unsigned int -dhd_os_get_ioctl_resp_timeout(void) -{ - return ((unsigned int)dhd_ioctl_timeout_msec); -} - -void -dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) -{ - dhd_ioctl_timeout_msec = (int)timeout_msec; -} - -int -dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout; - - /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); -#else - timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); -#endif - - DHD_PERIM_UNLOCK(pub); - - timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); - - DHD_PERIM_LOCK(pub); - - return timeout; -} - -int -dhd_os_ioctl_resp_wake(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - wake_up(&dhd->ioctl_resp_wait); - return 0; -} - -int -dhd_os_d3ack_wait(dhd_pub_t *pub, uint *condition, bool *pending) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout; - - /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); -#else - timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); -#endif - - DHD_PERIM_UNLOCK(pub); - - timeout = wait_event_timeout(dhd->d3ack_wait, (*condition), timeout); - - DHD_PERIM_LOCK(pub); - - return timeout; -} - -int -dhd_os_d3ack_wake(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - wake_up(&dhd->d3ack_wait); - return 0; -} - -void -dhd_os_wd_timer_extend(void *bus, bool extend) -{ - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - - if (extend) - dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL); - else - dhd_os_wd_timer(bus, dhd->default_wd_interval); -} - - -void -dhd_os_wd_timer(void *bus, uint wdtick) -{ - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - unsigned long flags; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!dhd) { - DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); - return; - } - - DHD_GENERAL_LOCK(pub, flags); - - /* don't start the wd until fw is loaded */ - if (pub->busstate == DHD_BUS_DOWN) { - DHD_GENERAL_UNLOCK(pub, flags); -#if !defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) - if (!wdtick) - DHD_OS_WD_WAKE_UNLOCK(pub); -#endif /* !DHD_USE_IDLECOUNT && BCMPCIE */ - return; - } - - /* Totally stop the timer */ - if (!wdtick && dhd->wd_timer_valid == TRUE) { - dhd->wd_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(pub, flags); - del_timer_sync(&dhd->timer); -#if !defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) - DHD_OS_WD_WAKE_UNLOCK(pub); -#endif /* !DHD_USE_IDLECOUNT && BCMPCIE */ - return; - } - - if (wdtick) { -#if !defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) - DHD_OS_WD_WAKE_LOCK(pub); -#endif /* !DHD_USE_IDLECOUNT && BCMPCIE */ - dhd_watchdog_ms = (uint)wdtick; - /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); - dhd->wd_timer_valid = TRUE; - } - DHD_GENERAL_UNLOCK(pub, flags); -} - -void * -dhd_os_open_image(char *filename) -{ - struct file *fp; - - fp = filp_open(filename, O_RDONLY, 0); - /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? - * Alternative: - * fp = open_namei(AT_FDCWD, filename, O_RD, 0); - * ??? - */ - if (IS_ERR(fp)) - fp = NULL; - - return fp; -} - -int -dhd_os_get_image_block(char *buf, int len, void *image) -{ - struct file *fp = (struct file *)image; - int rdlen; - - if (!image) - return 0; - - rdlen = kernel_read(fp, fp->f_pos, buf, len); - if (rdlen > 0) - fp->f_pos += rdlen; - - return rdlen; -} - -void -dhd_os_close_image(void *image) -{ - if (image) - filp_close((struct file *)image, NULL); -} - -void -dhd_os_sdlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - - if (dhd_dpc_prio >= 0) - down(&dhd->sdsem); - else - spin_lock_bh(&dhd->sdlock); -} - -void -dhd_os_sdunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - - if (dhd_dpc_prio >= 0) - up(&dhd->sdsem); - else - spin_unlock_bh(&dhd->sdlock); -} - -void -dhd_os_sdlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->txqlock); -} - -void -dhd_os_sdunlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->txqlock); -} - -void -dhd_os_sdlock_rxq(dhd_pub_t *pub) -{ -} - -void -dhd_os_sdunlock_rxq(dhd_pub_t *pub) -{ -} - -static void -dhd_os_rxflock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->rxf_lock); - -} - -static void -dhd_os_rxfunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->rxf_lock); -} - -#ifdef DHDTCPACK_SUPPRESS -void -dhd_os_tcpacklock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->tcpack_lock); - -} - -void -dhd_os_tcpackunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->tcpack_lock); -} -#endif /* DHDTCPACK_SUPPRESS */ - -uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail) -{ - uint8* buf; - gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; - - buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size); - if (buf == NULL) { - DHD_ERROR(("%s: failed to alloc memory, section: %d," - " size: %dbytes", __FUNCTION__, section, size)); - if (kmalloc_if_fail) - buf = kmalloc(size, flags); - } - - return buf; -} - -void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size) -{ -} - -static int -dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, - wl_event_msg_t *event, void **data) -{ - int bcmerror = 0; - - ASSERT(dhd != NULL); - - -#ifdef SHOW_LOGTRACE - bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data, &dhd->event_data); -#else - bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data, NULL); -#endif /* SHOW_LOGTRACE */ - - if (bcmerror != BCME_OK) - return (bcmerror); - -#ifdef WL_CFG80211 - ASSERT(dhd->iflist[*ifidx] != NULL); - ASSERT(dhd->iflist[*ifidx]->net != NULL); - if (dhd->iflist[*ifidx]->net) - wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); -#endif /* defined(WL_CFG80211) */ - - return (bcmerror); -} - -/* send up locally generated event */ -void -dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) -{ - switch (ntoh32(event->event_type)) { - - default: - break; - } -} - -#ifdef LOG_INTO_TCPDUMP -void -dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len) -{ - struct sk_buff *p, *skb; - uint32 pktlen; - int len; - dhd_if_t *ifp; - dhd_info_t *dhd; - uchar *skb_data; - int ifidx = 0; - struct ether_header eth; - - pktlen = sizeof(eth) + data_len; - dhd = dhdp->info; - - if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { - ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); - - bcopy(&dhdp->mac, ð.ether_dhost, ETHER_ADDR_LEN); - bcopy(&dhdp->mac, ð.ether_shost, ETHER_ADDR_LEN); - ETHER_TOGGLE_LOCALADDR(ð.ether_shost); - eth.ether_type = hton16(ETHER_TYPE_BRCM); - - bcopy((void *)ð, PKTDATA(dhdp->osh, p), sizeof(eth)); - bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len); - skb = PKTTONATIVE(dhdp->osh, p); - skb_data = skb->data; - len = skb->len; - - ifidx = dhd_ifname2idx(dhd, "wlan0"); - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) - ifp = dhd->iflist[0]; - - ASSERT(ifp); - skb->dev = ifp->net; - skb->protocol = eth_type_trans(skb, skb->dev); - skb->data = skb_data; - skb->len = len; - - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* Send the packet */ - if (in_interrupt()) { - netif_rx(skb); - } else { - netif_rx_ni(skb); - } - } - else { - /* Could not allocate a sk_buf */ - DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__)); - } -} -#endif /* LOG_INTO_TCPDUMP */ - -void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) -{ -#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); -#else - int timeout = IOCTL_RESP_TIMEOUT * msecs_to_jiffies(1); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - - dhd_os_sdunlock(dhd); - wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); - dhd_os_sdlock(dhd); -#endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ - return; -} - -void dhd_wait_event_wakeup(dhd_pub_t *dhd) -{ -#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - if (waitqueue_active(&dhdinfo->ctrl_wait)) - wake_up(&dhdinfo->ctrl_wait); -#endif - return; -} - -#if defined(BCMSDIO) || defined(BCMPCIE) -int -dhd_net_bus_devreset(struct net_device *dev, uint8 flag) -{ - int ret = 0; - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (flag == TRUE) { - /* Issue wl down command before resetting the chip */ - if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { - DHD_TRACE(("%s: wl down failed\n", __FUNCTION__)); - } -#ifdef PROP_TXSTATUS - if (dhd->pub.wlfc_enabled) - dhd_wlfc_deinit(&dhd->pub); -#endif /* PROP_TXSTATUS */ -#ifdef PNO_SUPPORT - if (dhd->pub.pno_state) - dhd_pno_deinit(&dhd->pub); -#endif -#ifdef RTT_SUPPORT - if (dhd->pub.rtt_state) { - dhd_rtt_deinit(&dhd->pub); - } -#endif /* RTT_SUPPORT */ - } - -#ifdef BCMSDIO - if (!flag) { - dhd_update_fw_nv_path(dhd); - /* update firmware and nvram path to sdio bus */ - dhd_bus_update_fw_nv_path(dhd->pub.bus, - dhd->fw_path, dhd->nv_path); - } -#endif /* BCMSDIO */ - - ret = dhd_bus_devreset(&dhd->pub, flag); - if (ret) { - DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); - return ret; - } - - return ret; -} - -#ifdef BCMSDIO -int -dhd_net_bus_suspend(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return dhd_bus_suspend(&dhd->pub); -} - -int -dhd_net_bus_resume(struct net_device *dev, uint8 stage) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return dhd_bus_resume(&dhd->pub, stage); -} - -#endif /* BCMSDIO */ -#endif /* BCMSDIO || BCMPCIE */ - -int net_os_set_suspend_disable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) { - ret = dhd->pub.suspend_disable_flag; - dhd->pub.suspend_disable_flag = val; - } - return ret; -} - -int net_os_set_suspend(struct net_device *dev, int val, int force) -{ - int ret = 0; - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd) { -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - ret = dhd_set_suspend(val, &dhd->pub); -#else - ret = dhd_suspend_resume_helper(dhd, val, force); -#endif -#ifdef WL_CFG80211 - wl_cfg80211_update_power_mode(dev); -#endif - } - return ret; -} - -int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd) - dhd->pub.suspend_bcn_li_dtim = val; - - return 0; -} - -#ifdef PKT_FILTER_SUPPORT -int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - char *filterp = NULL; - int filter_id = 0; - int ret = 0; - - if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || - (num == DHD_MDNS_FILTER_NUM)) - return ret; - if (num >= dhd->pub.pktfilter_count) - return -EINVAL; - switch (num) { - case DHD_BROADCAST_FILTER_NUM: - filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; - filter_id = 101; - break; - case DHD_MULTICAST4_FILTER_NUM: - filterp = "102 0 0 0 0xFFFFFF 0x01005E"; - filter_id = 102; - break; - case DHD_MULTICAST6_FILTER_NUM: - filterp = "103 0 0 0 0xFFFF 0x3333"; - filter_id = 103; - break; - default: - return -EINVAL; - } - - /* Add filter */ - if (add_remove) { - dhd->pub.pktfilter[num] = filterp; - dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); - } else { /* Delete filter */ - if (dhd->pub.pktfilter[num] != NULL) { - dhd_pktfilter_offload_delete(&dhd->pub, filter_id); - dhd->pub.pktfilter[num] = NULL; - } - } - return ret; -} - -int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) - -{ - int ret = 0; - - /* Packet filtering is set only if we still in early-suspend and - * we need either to turn it ON or turn it OFF - * We can always turn it OFF in case of early-suspend, but we turn it - * back ON only if suspend_disable_flag was not set - */ - if (dhdp && dhdp->up) { - if (dhdp->in_suspend) { - if (!val || (val && !dhdp->suspend_disable_flag)) - dhd_enable_packet_filter(val, dhdp); - } - } - return ret; -} - -/* function to enable/disable packet for Network device */ -int net_os_enable_packet_filter(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - return dhd_os_enable_packet_filter(&dhd->pub, val); -} -#endif /* PKT_FILTER_SUPPORT */ - -int -dhd_dev_init_ioctl(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret; - - if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) - goto done; - -done: - return ret; -} - -int dhd_dev_get_feature_set(struct net_device *dev) -{ - dhd_info_t *ptr = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhd = (&ptr->pub); - int feature_set = 0; - - if (!dhd) - return feature_set; - - if (FW_SUPPORTED(dhd, sta)) - feature_set |= WIFI_FEATURE_INFRA; - if (FW_SUPPORTED(dhd, dualband)) - feature_set |= WIFI_FEATURE_INFRA_5G; - if (FW_SUPPORTED(dhd, p2p)) - feature_set |= WIFI_FEATURE_P2P; - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) - feature_set |= WIFI_FEATURE_SOFT_AP; - if (FW_SUPPORTED(dhd, tdls)) - feature_set |= WIFI_FEATURE_TDLS; - if (FW_SUPPORTED(dhd, vsdb)) - feature_set |= WIFI_FEATURE_TDLS_OFFCHANNEL; - if (FW_SUPPORTED(dhd, nan)) { - feature_set |= WIFI_FEATURE_NAN; - /* NAN is essentail for d2d rtt */ - if (FW_SUPPORTED(dhd, rttd2d)) { - feature_set |= WIFI_FEATURE_D2D_RTT; - } - } -#ifdef RTT_SUPPORT - feature_set |= WIFI_FEATURE_D2AP_RTT; -#endif /* RTT_SUPPORT */ -#ifdef LINKSTAT_SUPPORT - feature_set |= WIFI_FEATURE_LINKSTAT; -#endif /* LINKSTAT_SUPPORT */ - /* Supports STA + STA always */ - feature_set |= WIFI_FEATURE_ADDITIONAL_STA; -#ifdef PNO_SUPPORT - if (dhd_is_pno_supported(dhd)) { - feature_set |= WIFI_FEATURE_PNO; - feature_set |= WIFI_FEATURE_BATCH_SCAN; -#ifdef GSCAN_SUPPORT - feature_set |= WIFI_FEATURE_GSCAN; -#endif /* GSCAN_SUPPORT */ - } - if (FW_SUPPORTED(dhd, rssi_mon)) { - feature_set |= WIFI_FEATURE_RSSI_MONITOR; - } -#endif /* PNO_SUPPORT */ -#ifdef WL11U - feature_set |= WIFI_FEATURE_HOTSPOT; -#endif /* WL11U */ - return feature_set; -} - -int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num) -{ - int feature_set_full, mem_needed; - int *ret; - - *num = 0; - mem_needed = sizeof(int) * MAX_FEATURE_SET_CONCURRRENT_GROUPS; - ret = (int *) kmalloc(mem_needed, GFP_KERNEL); - - if (!ret) { - DHD_ERROR(("%s: failed to allocate %d bytes\n", __FUNCTION__, - mem_needed)); - return ret; - } - - feature_set_full = dhd_dev_get_feature_set(dev); - - ret[0] = (feature_set_full & WIFI_FEATURE_INFRA) | - (feature_set_full & WIFI_FEATURE_INFRA_5G) | - (feature_set_full & WIFI_FEATURE_NAN) | - (feature_set_full & WIFI_FEATURE_D2D_RTT) | - (feature_set_full & WIFI_FEATURE_D2AP_RTT) | - (feature_set_full & WIFI_FEATURE_PNO) | - (feature_set_full & WIFI_FEATURE_HAL_EPNO) | - (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | - (feature_set_full & WIFI_FEATURE_BATCH_SCAN) | - (feature_set_full & WIFI_FEATURE_GSCAN) | - (feature_set_full & WIFI_FEATURE_HOTSPOT) | - (feature_set_full & WIFI_FEATURE_ADDITIONAL_STA) | - (feature_set_full & WIFI_FEATURE_EPR); - - ret[1] = (feature_set_full & WIFI_FEATURE_INFRA) | - (feature_set_full & WIFI_FEATURE_INFRA_5G) | - (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | - /* Not yet verified NAN with P2P */ - /* (feature_set_full & WIFI_FEATURE_NAN) | */ - (feature_set_full & WIFI_FEATURE_P2P) | - (feature_set_full & WIFI_FEATURE_D2AP_RTT) | - (feature_set_full & WIFI_FEATURE_D2D_RTT) | - (feature_set_full & WIFI_FEATURE_EPR); - - ret[2] = (feature_set_full & WIFI_FEATURE_INFRA) | - (feature_set_full & WIFI_FEATURE_INFRA_5G) | - (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | - (feature_set_full & WIFI_FEATURE_NAN) | - (feature_set_full & WIFI_FEATURE_D2D_RTT) | - (feature_set_full & WIFI_FEATURE_D2AP_RTT) | - (feature_set_full & WIFI_FEATURE_TDLS) | - (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL) | - (feature_set_full & WIFI_FEATURE_EPR); - *num = MAX_FEATURE_SET_CONCURRRENT_GROUPS; - - return ret; -} -#ifdef CUSTOM_FORCE_NODFS_FLAG -int -dhd_dev_set_nodfs(struct net_device *dev, u32 nodfs) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (nodfs) - dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; - else - dhd->pub.dhd_cflags &= ~WLAN_PLAT_NODFS_FLAG; - dhd->pub.force_country_change = TRUE; - return 0; -} -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -#ifdef PNO_SUPPORT -/* Linux wrapper to call common dhd_pno_stop_for_ssid */ -int -dhd_dev_pno_stop_for_ssid(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - return (dhd_pno_stop_for_ssid(&dhd->pub)); -} -/* Linux wrapper to call common dhd_pno_set_for_ssid */ -int -dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, - uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr, - pno_repeat, pno_freq_expo_max, channel_list, nchan)); -} - -/* Linux wrapper to call common dhd_pno_enable */ -int -dhd_dev_pno_enable(struct net_device *dev, int enable) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - return (dhd_pno_enable(&dhd->pub, enable)); -} - -/* Linux wrapper to call common dhd_pno_set_for_hotlist */ -int -dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, - struct dhd_pno_hotlist_params *hotlist_params) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params)); -} -/* Linux wrapper to call common dhd_dev_pno_stop_for_batch */ -int -dhd_dev_pno_stop_for_batch(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return (dhd_pno_stop_for_batch(&dhd->pub)); -} -/* Linux wrapper to call common dhd_dev_pno_set_for_batch */ -int -dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return (dhd_pno_set_for_batch(&dhd->pub, batch_params)); -} -/* Linux wrapper to call common dhd_dev_pno_get_for_batch */ -int -dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL)); -} - -bool -dhd_dev_is_legacy_pno_enabled(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_is_legacy_pno_enabled(&dhd->pub)); -} -#endif /* PNO_SUPPORT */ - -#ifdef GSCAN_SUPPORT -/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ -int -dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, - void *buf, uint8 flush) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_set_cfg_gscan(&dhd->pub, type, buf, flush)); -} - -/* Linux wrapper to call common dhd_pno_get_gscan */ -void * -dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, - void *info, uint32 *len) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_get_gscan(&dhd->pub, type, info, len)); -} - -/* Linux wrapper to call common dhd_wait_batch_results_complete */ -int -dhd_dev_wait_batch_results_complete(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_wait_batch_results_complete(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_pno_lock_batch_results */ -int -dhd_dev_pno_lock_access_batch_results(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_lock_batch_results(&dhd->pub)); -} -/* Linux wrapper to call common dhd_pno_unlock_batch_results */ -void -dhd_dev_pno_unlock_access_batch_results(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_unlock_batch_results(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_pno_initiate_gscan_request */ -int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_initiate_gscan_request(&dhd->pub, run, flush)); -} - -/* Linux wrapper to call common dhd_pno_enable_full_scan_result */ -int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time_flag) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_enable_full_scan_result(&dhd->pub, real_time_flag)); -} - -/* Linux wrapper to call common dhd_handle_hotlist_scan_evt */ -void * dhd_dev_hotlist_scan_event(struct net_device *dev, - const void *data, int *send_evt_bytes, hotlist_type_t type) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_handle_hotlist_scan_evt(&dhd->pub, data, send_evt_bytes, type)); -} - -/* Linux wrapper to call common dhd_process_full_gscan_result */ -void * dhd_dev_process_full_gscan_result(struct net_device *dev, - - const void *data, uint32 len, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_process_full_gscan_result(&dhd->pub, data, len, send_evt_bytes)); -} - -void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - dhd_gscan_hotlist_cache_cleanup(&dhd->pub, type); - - return; -} - -int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_gscan_batch_cache_cleanup(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_retreive_batch_scan_results */ -int dhd_dev_retrieve_batch_scan(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_retreive_batch_scan_results(&dhd->pub)); -} -/* Linux wrapper to call common dhd_pno_process_epno_result */ -void * dhd_dev_process_epno_result(struct net_device *dev, - const void *data, uint32 event, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_process_epno_result(&dhd->pub, data, event, send_evt_bytes)); -} - -int -dhd_dev_set_lazy_roam_cfg(struct net_device *dev, - wlc_roam_exp_params_t *roam_param) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - wl_roam_exp_cfg_t roam_exp_cfg; - int err; - - if (!roam_param) { - return BCME_BADARG; - } - - DHD_ERROR(("a_band_boost_thr %d a_band_penalty_thr %d\n", - roam_param->a_band_boost_threshold, roam_param->a_band_penalty_threshold)); - DHD_ERROR(("a_band_boost_factor %d a_band_penalty_factor %d cur_bssid_boost %d\n", - roam_param->a_band_boost_factor, roam_param->a_band_penalty_factor, - roam_param->cur_bssid_boost)); - DHD_ERROR(("alert_roam_trigger_thr %d a_band_max_boost %d\n", - roam_param->alert_roam_trigger_threshold, roam_param->a_band_max_boost)); - - memcpy(&roam_exp_cfg.params, roam_param, sizeof(*roam_param)); - roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; - roam_exp_cfg.flags = ROAM_EXP_CFG_PRESENT; - if (dhd->pub.lazy_roam_enable) { - roam_exp_cfg.flags |= ROAM_EXP_ENABLE_FLAG; - } - err = dhd_iovar(&(dhd->pub), 0, "roam_exp_params", (char *)&roam_exp_cfg, - sizeof(roam_exp_cfg), 1); - if (err < 0) { - DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); - } - return err; -} - -int -dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - wl_roam_exp_cfg_t roam_exp_cfg; - - memset(&roam_exp_cfg, 0, sizeof(roam_exp_cfg)); - roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; - if (enable) { - roam_exp_cfg.flags = ROAM_EXP_ENABLE_FLAG; - } - - err = dhd_iovar(&(dhd->pub), 0, "roam_exp_params", (char *)&roam_exp_cfg, - sizeof(roam_exp_cfg), 1); - if (err < 0) { - DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); - } else { - dhd->pub.lazy_roam_enable = (enable != 0); - } - return err; -} -int -dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, - wl_bssid_pref_cfg_t *bssid_pref, uint32 flush) -{ - int err; - int len; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - bssid_pref->version = BSSID_PREF_LIST_VERSION; - /* By default programming bssid pref flushes out old values */ - bssid_pref->flags = (flush && !bssid_pref->count) ? ROAM_EXP_CLEAR_BSSID_PREF: 0; - len = sizeof(wl_bssid_pref_cfg_t); - len += (bssid_pref->count - 1) * sizeof(wl_bssid_pref_list_t); - err = dhd_iovar(&(dhd->pub), 0, "roam_exp_bssid_pref", (char *)bssid_pref, - len, 1); - if (err != BCME_OK) { - DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); - } - return err; -} -int -dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, - uint32 len, uint32 flush) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int macmode; - - if (blacklist) { - err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACLIST, (char *)blacklist, - len, TRUE, 0); - if (err != BCME_OK) { - DHD_ERROR(("%s : WLC_SET_MACLIST failed %d\n", __FUNCTION__, err)); - return err; - } - } - /* By default programming blacklist flushes out old values */ - macmode = (flush && !blacklist) ? WLC_MACMODE_DISABLED : WLC_MACMODE_DENY; - err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACMODE, (char *)&macmode, - sizeof(macmode), TRUE, 0); - if (err != BCME_OK) { - DHD_ERROR(("%s : WLC_SET_MACMODE failed %d\n", __FUNCTION__, err)); - } - return err; -} -int -dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid_whitelist, - uint32 len, uint32 flush) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - wl_ssid_whitelist_t whitelist_ssid_flush; - - if (!ssid_whitelist) { - if (flush) { - ssid_whitelist = &whitelist_ssid_flush; - ssid_whitelist->ssid_count = 0; - } else { - DHD_ERROR(("%s : Nothing to do here\n", __FUNCTION__)); - return BCME_BADARG; - } - } - ssid_whitelist->version = SSID_WHITELIST_VERSION; - ssid_whitelist->flags = flush ? ROAM_EXP_CLEAR_SSID_WHITELIST : 0; - err = dhd_iovar(&(dhd->pub), 0, "roam_exp_ssid_whitelist", (char *)ssid_whitelist, - len, 1); - if (err != BCME_OK) { - DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); - } - return err; -} -#endif /* GSCAN_SUPPORT */ - -#if defined(KEEP_ALIVE) -#define TEMP_BUF_SIZE 512 -#define FRAME_SIZE 300 -int -dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, u16 ip_pkt_len, - u8* src_mac, u8* dst_mac, u32 period_msec) -{ - char *pbuf; - const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0}; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = BCME_ERROR; - int len_bytes = 0; - int i; - - /* ether frame to have both max IP pkt (256 bytes) and ether header */ - char *pmac_frame; - - /* - * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, - * dongle shall reject a mkeep_alive request. - */ - if (!dhd_support_sta_mode(dhd_pub)) - return res; - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - if ((pbuf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { - DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE)); - res = BCME_NOMEM; - return res; - } - - if ((pmac_frame = kzalloc(FRAME_SIZE, GFP_KERNEL)) == NULL) { - DHD_ERROR(("failed to allocate mac_frame with size %d\n", FRAME_SIZE)); - res = BCME_NOMEM; - goto exit; - } - - /* - * Get current mkeep-alive status. - */ - bcm_mkiovar("mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), - pbuf, TEMP_BUF_SIZE); - - if ((res = dhd_wl_ioctl_cmd(dhd_pub, WLC_GET_VAR, pbuf, TEMP_BUF_SIZE, - FALSE, 0)) < 0) { - DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); - goto exit; - } else { - /* Check available ID whether it is occupied */ - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; - if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { - DHD_ERROR(("%s: Get mkeep_alive failed, ID %u is in use.\n", - __FUNCTION__, mkeep_alive_id)); - - /* Current occupied ID info */ - DHD_ERROR(("%s: mkeep_alive\n", __FUNCTION__)); - DHD_ERROR((" Id : %d\n" - " Period: %d msec\n" - " Length: %d\n" - " Packet: 0x", - mkeep_alive_pktp->keep_alive_id, - dtoh32(mkeep_alive_pktp->period_msec), - dtoh16(mkeep_alive_pktp->len_bytes))); - - for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { - DHD_ERROR(("%02x", mkeep_alive_pktp->data[i])); - } - DHD_ERROR(("\n")); - - res = BCME_NOTFOUND; - goto exit; - } - } - - /* Request the specified ID */ - memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - memset(pbuf, 0, TEMP_BUF_SIZE); - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(pbuf, str, str_len); - pbuf[str_len] = '\0'; - - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1); - mkeep_alive_pkt.period_msec = htod32(period_msec); - buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - - /* ID assigned */ - mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; - - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - - /* - * Build up Ethernet Frame - */ - - /* Mapping dest mac addr */ - memcpy(pmac_frame, dst_mac, ETHER_ADDR_LEN); - pmac_frame += ETHER_ADDR_LEN; - - /* Mapping src mac addr */ - memcpy(pmac_frame, src_mac, ETHER_ADDR_LEN); - pmac_frame += ETHER_ADDR_LEN; - - /* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */ - *(pmac_frame++) = 0x08; - *(pmac_frame++) = 0x00; - - /* Mapping IP pkt */ - memcpy(pmac_frame, ip_pkt, ip_pkt_len); - pmac_frame += ip_pkt_len; - - /* - * Length of ether frame (assume to be all hexa bytes) - * = src mac + dst mac + ether type + ip pkt len - */ - len_bytes = ETHER_ADDR_LEN*2 + ETHER_TYPE_LEN + ip_pkt_len; - /* Get back to the beginning. */ - pmac_frame -= len_bytes; - memcpy(mkeep_alive_pktp->data, pmac_frame, len_bytes); - buf_len += len_bytes; - mkeep_alive_pkt.len_bytes = htod16(len_bytes); - - /* - * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0); -exit: - kfree(pmac_frame); - kfree(pbuf); - return res; -} - -int -dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id) -{ - char *pbuf; - const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = BCME_ERROR; - int i; - - /* - * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, - * dongle shall reject a mkeep_alive request. - */ - if (!dhd_support_sta_mode(dhd_pub)) - return res; - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - /* - * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt. - */ - if ((pbuf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { - DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE)); - return res; - } - - bcm_mkiovar("mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, TEMP_BUF_SIZE); - - if ((res = dhd_wl_ioctl_cmd(dhd_pub, WLC_GET_VAR, pbuf, TEMP_BUF_SIZE, FALSE, 0)) < 0) { - DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); - goto exit; - } else { - /* Check occupied ID */ - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; - DHD_INFO(("%s: mkeep_alive\n", __FUNCTION__)); - DHD_INFO((" Id : %d\n" - " Period: %d msec\n" - " Length: %d\n" - " Packet: 0x", - mkeep_alive_pktp->keep_alive_id, - dtoh32(mkeep_alive_pktp->period_msec), - dtoh16(mkeep_alive_pktp->len_bytes))); - - for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { - DHD_INFO(("%02x", mkeep_alive_pktp->data[i])); - } - DHD_INFO(("\n")); - } - - /* Make it stop if available */ - if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { - DHD_INFO(("stop mkeep_alive on ID %d\n", mkeep_alive_id)); - memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - memset(pbuf, 0, TEMP_BUF_SIZE); - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(pbuf, str, str_len); - pbuf[str_len] = '\0'; - - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1); - - mkeep_alive_pkt.period_msec = 0; - buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - - /* - * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0); - } else { - DHD_ERROR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id)); - res = BCME_NOTFOUND; - } -exit: - kfree(pbuf); - return res; -} -#endif /* defined(KEEP_ALIVE) */ - -int -dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, - int8 max_rssi, int8 min_rssi) -{ - int err; - wl_rssi_monitor_cfg_t rssi_monitor; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - rssi_monitor.version = RSSI_MONITOR_VERSION; - rssi_monitor.max_rssi = max_rssi; - rssi_monitor.min_rssi = min_rssi; - rssi_monitor.flags = start ? 0: RSSI_MONITOR_STOP; - err = dhd_iovar(&(dhd->pub), 0, "rssi_monitor", (char *)&rssi_monitor, - sizeof(rssi_monitor), 1); - if (err < 0 && err != BCME_UNSUPPORTED) { - DHD_ERROR(("%s : Failed to execute rssi_monitor %d\n", __FUNCTION__, err)); - } - return err; -} - -int -dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhdp = &dhd->pub; - - if (!dhdp || !oui) { - DHD_ERROR(("NULL POINTER : %s\n", - __FUNCTION__)); - return BCME_ERROR; - } - if (ETHER_ISMULTI(oui)) { - DHD_ERROR(("Expected unicast OUI\n")); - return BCME_ERROR; - } else { - uint8 *rand_mac_oui = dhdp->rand_mac_oui; - memcpy(rand_mac_oui, oui, DOT11_OUI_LEN); - DHD_ERROR(("Random MAC OUI to be used - %02x:%02x:%02x\n", rand_mac_oui[0], - rand_mac_oui[1], rand_mac_oui[2])); - } - return BCME_OK; -} - -int -dhd_set_rand_mac_oui(dhd_pub_t *dhd) -{ - int err; - wl_pfn_macaddr_cfg_t cfg; - uint8 *rand_mac_oui = dhd->rand_mac_oui; - - memset(&cfg.macaddr, 0, ETHER_ADDR_LEN); - memcpy(&cfg.macaddr, rand_mac_oui, DOT11_OUI_LEN); - cfg.version = WL_PFN_MACADDR_CFG_VER; - if (ETHER_ISNULLADDR(&cfg.macaddr)) - cfg.flags = 0; - else - cfg.flags = (WL_PFN_MAC_OUI_ONLY_MASK | WL_PFN_SET_MAC_UNASSOC_MASK); - - DHD_ERROR(("Setting rand mac oui to FW - %02x:%02x:%02x\n", rand_mac_oui[0], - rand_mac_oui[1], rand_mac_oui[2])); - - err = dhd_iovar(dhd, 0, "pfn_macaddr", (char *)&cfg, sizeof(cfg), 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_macaddr %d\n", __FUNCTION__, err)); - } - return err; -} - -#ifdef RTT_SUPPORT -/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ -int -dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_set_cfg(&dhd->pub, buf)); -} -int -dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_stop(&dhd->pub, mac_list, mac_cnt)); -} - -int -dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, dhd_rtt_compl_noti_fn noti_fn) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_register_noti_callback(&dhd->pub, ctx, noti_fn)); -} -int -dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_unregister_noti_callback(&dhd->pub, noti_fn)); -} - -int -dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_capability(&dhd->pub, capa)); -} -#endif /* RTT_SUPPORT */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -static void dhd_hang_process(void *dhd_info, void *event_info, u8 event) -{ - dhd_info_t *dhd; - struct net_device *dev; - - dhd = (dhd_info_t *)dhd_info; - dev = dhd->iflist[0]->net; - - if (dev) { - rtnl_lock(); - dev_close(dev); - rtnl_unlock(); -#if defined(WL_CFG80211) - wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -#endif - } -} - - -int dhd_os_send_hang_message(dhd_pub_t *dhdp) -{ - int ret = 0; - if (dhdp) { - if (!dhdp->hang_was_sent) { - dhdp->hang_was_sent = 1; - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dhdp, - DHD_WQ_WORK_HANG_MSG, dhd_hang_process, DHD_WORK_PRIORITY_HIGH); - } - } - return ret; -} - -int net_os_send_hang_message(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) { - /* Report FW problem when enabled */ - if (dhd->pub.hang_report) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - ret = dhd_os_send_hang_message(&dhd->pub); -#else - ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -#endif - } else { - DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n", - __FUNCTION__)); - /* Enforce bus down to stop any future traffic */ - dhd->pub.busstate = DHD_BUS_DOWN; - } - } - return ret; -} -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ - - -int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return wifi_platform_set_power(dhd->adapter, on, delay_msec); -} - -void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, - wl_country_t *cspec) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); -#ifdef CUSTOM_FORCE_NODFS_FLAG - get_customized_country_code(dhd->adapter, country_iso_code, cspec, - dhd->pub.dhd_cflags); - -#else - get_customized_country_code(dhd->adapter, country_iso_code, cspec); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - -} -void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - if (dhd && dhd->pub.up) { - memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); -#ifdef WL_CFG80211 - wl_update_wiphybands(NULL, notify); -#endif - } -} - -void dhd_bus_band_set(struct net_device *dev, uint band) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - if (dhd && dhd->pub.up) { -#ifdef WL_CFG80211 - wl_update_wiphybands(NULL, true); -#endif - } -} - -int dhd_net_set_fw_path(struct net_device *dev, char *fw) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (!fw || fw[0] == '\0') - return -EINVAL; - - strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1); - dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0'; - -#if defined(SOFTAP) - if (strstr(fw, "apsta") != NULL) { - DHD_INFO(("GOT APSTA FIRMWARE\n")); - ap_fw_loaded = TRUE; - } else { - DHD_INFO(("GOT STA FIRMWARE\n")); - ap_fw_loaded = FALSE; - } -#endif - return 0; -} - -void dhd_net_if_lock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - dhd_net_if_lock_local(dhd); -} - -void dhd_net_if_unlock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - dhd_net_if_unlock_local(dhd); -} - -static void dhd_net_if_lock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (dhd) - mutex_lock(&dhd->dhd_net_if_mutex); -#endif -} - -static void dhd_net_if_unlock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (dhd) - mutex_unlock(&dhd->dhd_net_if_mutex); -#endif -} - -static void dhd_suspend_lock(dhd_pub_t *pub) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - if (dhd) - mutex_lock(&dhd->dhd_suspend_mutex); -#endif -} - -static void dhd_suspend_unlock(dhd_pub_t *pub) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - if (dhd) - mutex_unlock(&dhd->dhd_suspend_mutex); -#endif -} - -unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags = 0; - - if (dhd) - spin_lock_irqsave(&dhd->dhd_lock, flags); - - return flags; -} - -void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) - spin_unlock_irqrestore(&dhd->dhd_lock, flags); -} - -/* Linux specific multipurpose spinlock API */ -void * -dhd_os_spin_lock_init(osl_t *osh) -{ - /* Adding 4 bytes since the sizeof(spinlock_t) could be 0 */ - /* if CONFIG_SMP and CONFIG_DEBUG_SPINLOCK are not defined */ - /* and this results in kernel asserts in internal builds */ - spinlock_t * lock = MALLOC(osh, sizeof(spinlock_t) + 4); - if (lock) - spin_lock_init(lock); - return ((void *)lock); -} -void -dhd_os_spin_lock_deinit(osl_t *osh, void *lock) -{ - MFREE(osh, lock, sizeof(spinlock_t) + 4); -} -unsigned long -dhd_os_spin_lock(void *lock) -{ - unsigned long flags = 0; - - if (lock) - spin_lock_irqsave((spinlock_t *)lock, flags); - - return flags; -} -void -dhd_os_spin_unlock(void *lock, unsigned long flags) -{ - if (lock) - spin_unlock_irqrestore((spinlock_t *)lock, flags); -} - -static int -dhd_get_pend_8021x_cnt(dhd_info_t *dhd) -{ - return (atomic_read(&dhd->pend_8021x_cnt)); -} - -#define MAX_WAIT_FOR_8021X_TX 100 - -int -dhd_wait_pend8021x(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int timeout = msecs_to_jiffies(10); - int ntimes = MAX_WAIT_FOR_8021X_TX; - int pend = dhd_get_pend_8021x_cnt(dhd); - - while (ntimes && pend) { - if (pend) { - set_current_state(TASK_INTERRUPTIBLE); - DHD_PERIM_UNLOCK(&dhd->pub); - schedule_timeout(timeout); - DHD_PERIM_LOCK(&dhd->pub); - set_current_state(TASK_RUNNING); - ntimes--; - } - pend = dhd_get_pend_8021x_cnt(dhd); - } - if (ntimes == 0) - { - atomic_set(&dhd->pend_8021x_cnt, 0); - DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__)); - } - return pend; -} - -#ifdef DHD_DEBUG -int -write_to_file(dhd_pub_t *dhd, uint8 *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 */ -#if defined(CUSTOMER_HW5) - fp = filp_open("/data/mem_dump", O_WRONLY|O_CREAT, 0640); -#else - fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640); -#endif - - if (IS_ERR(fp)) { - fp = NULL; - printf("%s: open file error\n", __FUNCTION__); - ret = -1; - goto exit; - } - - /* Write buf to file */ - fp->f_op->write(fp, buf, size, &pos); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) - fp->f_op->fsync(fp, 0, size-1, 1); -#else - fp->f_op->fsync(fp, 1); -#endif /* KERNEL_VERSION(3, 1, 0) */ - -exit: - /* buf is actually dhd_pub->soc_ram and freed in in dhd_{free,clear} */ - - /* close file before return */ - if (fp) - filp_close(fp, current->files); - /* restore previous address limit */ - set_fs(old_fs); - - return ret; -} -#endif /* DHD_DEBUG */ - -int dhd_os_wake_lock_timeout(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? - dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; -#ifdef CONFIG_HAS_WAKELOCK - if (dhd->wakelock_rx_timeout_enable) - wake_lock_timeout(&dhd->wl_rxwake, - msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); - if (dhd->wakelock_ctrl_timeout_enable) - wake_lock_timeout(&dhd->wl_ctrlwake, - msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); -#endif - dhd->wakelock_rx_timeout_enable = 0; - dhd->wakelock_ctrl_timeout_enable = 0; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int net_os_wake_lock_timeout(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_timeout(&dhd->pub); - return ret; -} - -int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_rx_timeout_enable) - dhd->wakelock_rx_timeout_enable = val; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_ctrl_timeout_enable) - dhd->wakelock_ctrl_timeout_enable = val; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - dhd->wakelock_ctrl_timeout_enable = 0; -#ifdef CONFIG_HAS_WAKELOCK - if (wake_lock_active(&dhd->wl_ctrlwake)) - wake_unlock(&dhd->wl_ctrlwake); -#endif - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); - return ret; -} - -int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); - return ret; -} -#if defined(DHD_TRACE_WAKE_LOCK) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -#include -#else -#include -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -/* Define 2^5 = 32 bucket size hash table */ -DEFINE_HASHTABLE(wklock_history, 5); -#else -/* Define 2^5 = 32 bucket size hash table */ -struct hlist_head wklock_history[32] = { [0 ... 31] = HLIST_HEAD_INIT }; -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - -int trace_wklock_onoff = 1; -typedef enum dhd_wklock_type { - DHD_WAKE_LOCK, - DHD_WAKE_UNLOCK, - DHD_WAIVE_LOCK, - DHD_RESTORE_LOCK -} dhd_wklock_t; - -struct wk_trace_record { - unsigned long addr; /* Address of the instruction */ - dhd_wklock_t lock_type; /* lock_type */ - unsigned long long counter; /* counter information */ - struct hlist_node wklock_node; /* hash node */ -}; - -static struct wk_trace_record *find_wklock_entry(unsigned long addr) -{ - struct wk_trace_record *wklock_info; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_for_each_possible(wklock_history, wklock_info, wklock_node, addr) -#else - struct hlist_node *entry; - int index = hash_long(addr, ilog2(ARRAY_SIZE(wklock_history))); - hlist_for_each_entry(wklock_info, entry, &wklock_history[index], wklock_node) -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - { - if (wklock_info->addr == addr) { - return wklock_info; - } - } - return NULL; -} -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -#define HASH_ADD(hashtable, node, key) \ - do { \ - hash_add(hashtable, node, key); \ - } while (0); - -#else /* KERNEL_VER < KERNEL_VERSION(3, 7, 0) */ -#define HASH_ADD(hashtable, node, key) \ - do { \ - int index = hash_long(key, ilog2(ARRAY_SIZE(hashtable))); \ - hlist_add_head(node, &hashtable[index]); \ - } while (0); -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ -#define STORE_WKLOCK_RECORD(wklock_type) \ - do { \ - struct wk_trace_record *wklock_info = NULL; \ - unsigned long func_addr = (unsigned long)__builtin_return_address(0); \ - wklock_info = find_wklock_entry(func_addr); \ - if (wklock_info) { \ - if (wklock_type == DHD_WAIVE_LOCK || wklock_type == DHD_RESTORE_LOCK) { \ - wklock_info->counter = dhd->wakelock_counter; \ - } else { \ - wklock_info->counter++; \ - } \ - } else { \ - wklock_info = kzalloc(sizeof(*wklock_info), GFP_ATOMIC); \ - if (!wklock_info) {\ - printk("Can't allocate wk_trace_record \n"); \ - } else { \ - wklock_info->addr = func_addr; \ - wklock_info->lock_type = wklock_type; \ - if (wklock_type == DHD_WAIVE_LOCK || \ - wklock_type == DHD_RESTORE_LOCK) { \ - wklock_info->counter = dhd->wakelock_counter; \ - } else { \ - wklock_info->counter++; \ - } \ - HASH_ADD(wklock_history, &wklock_info->wklock_node, func_addr); \ - } \ - } \ - } while (0); -static inline void dhd_wk_lock_rec_dump(void) -{ - int bkt; - struct wk_trace_record *wklock_info; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_for_each(wklock_history, bkt, wklock_info, wklock_node) -#else - struct hlist_node *entry = NULL; - int max_index = ARRAY_SIZE(wklock_history); - for (bkt = 0; bkt < max_index; bkt++) - hlist_for_each_entry(wklock_info, entry, &wklock_history[bkt], wklock_node) -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - { - switch (wklock_info->lock_type) { - case DHD_WAKE_LOCK: - printk("wakelock lock : %pS lock_counter : %llu \n", - (void *)wklock_info->addr, wklock_info->counter); - break; - case DHD_WAKE_UNLOCK: - printk("wakelock unlock : %pS, unlock_counter : %llu \n", - (void *)wklock_info->addr, wklock_info->counter); - break; - case DHD_WAIVE_LOCK: - printk("wakelock waive : %pS before_waive : %llu \n", - (void *)wklock_info->addr, wklock_info->counter); - break; - case DHD_RESTORE_LOCK: - printk("wakelock restore : %pS, after_waive : %llu \n", - (void *)wklock_info->addr, wklock_info->counter); - break; - } - } -} - -static void dhd_wk_lock_trace_init(struct dhd_info *dhd) -{ - unsigned long flags; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) - int i; -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_init(wklock_history); -#else - for (i = 0; i < ARRAY_SIZE(wklock_history); i++) - INIT_HLIST_HEAD(&wklock_history[i]); -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -} - -static void dhd_wk_lock_trace_deinit(struct dhd_info *dhd) -{ - int bkt; - struct wk_trace_record *wklock_info; - struct hlist_node *tmp; - unsigned long flags; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) - struct hlist_node *entry = NULL; - int max_index = ARRAY_SIZE(wklock_history); -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_for_each_safe(wklock_history, bkt, tmp, wklock_info, wklock_node) -#else - for (bkt = 0; bkt < max_index; bkt++) - hlist_for_each_entry_safe(wklock_info, entry, tmp, - &wklock_history[bkt], wklock_node) -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0)) */ - { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_del(&wklock_info->wklock_node); -#else - hlist_del_init(&wklock_info->wklock_node); -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0)) */ - kfree(wklock_info); - } - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -} - -void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - unsigned long flags; - - printk(KERN_ERR"DHD Printing wl_wake Lock/Unlock Record \r\n"); - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - dhd_wk_lock_rec_dump(); - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - DHD_ERROR((KERN_ERR"Event wakelock counter %u\n", dhd->wakelock_event_counter)); -} -#else -#define STORE_WKLOCK_RECORD(wklock_type) -#endif /* ! DHD_TRACE_WAKE_LOCK */ - - -int dhd_os_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - - if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { -#ifdef CONFIG_HAS_WAKELOCK - wake_lock(&dhd->wl_wifi); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_stay_awake(pub); -#endif - } -#ifdef DHD_TRACE_WAKE_LOCK - if (trace_wklock_onoff) { - STORE_WKLOCK_RECORD(DHD_WAKE_LOCK); - } -#endif /* DHD_TRACE_WAKE_LOCK */ - dhd->wakelock_counter++; - ret = dhd->wakelock_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int dhd_event_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_evt_spinlock, flags); - if (dhd->wakelock_event_counter == 0) { -#ifdef CONFIG_HAS_WAKELOCK - wake_lock(&dhd->wl_evtwake); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_stay_awake(pub); -#endif - } - dhd->wakelock_event_counter++; - ret = dhd->wakelock_event_counter; - spin_unlock_irqrestore(&dhd->wakelock_evt_spinlock, flags); - } - - return ret; -} - -void dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - wake_lock_timeout(&dhd->wl_txflwake, msecs_to_jiffies(val)); - } -#endif /* CONFIG_HAS_WAKE_LOCK */ -} - -int net_os_wake_lock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock(&dhd->pub); - return ret; -} - -int dhd_os_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - dhd_os_wake_lock_timeout(pub); - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (dhd->wakelock_counter > 0) { - dhd->wakelock_counter--; -#ifdef DHD_TRACE_WAKE_LOCK - if (trace_wklock_onoff) { - STORE_WKLOCK_RECORD(DHD_WAKE_UNLOCK); - } -#endif /* DHD_TRACE_WAKE_LOCK */ - if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_wifi); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_relax(pub); -#endif - } - ret = dhd->wakelock_counter; - } - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int dhd_event_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_evt_spinlock, flags); - - if (dhd->wakelock_event_counter > 0) { - dhd->wakelock_event_counter--; - if (dhd->wakelock_event_counter == 0) { -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_evtwake); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_relax(pub); -#endif - } - ret = dhd->wakelock_event_counter; - } - spin_unlock_irqrestore(&dhd->wakelock_evt_spinlock, flags); - } - return ret; -} - -void dhd_txfl_wake_unlock(dhd_pub_t *pub) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - /* if wl_txflwake is active, unlock it */ - if (wake_lock_active(&dhd->wl_txflwake)) { - wake_unlock(&dhd->wl_txflwake); - } - } -#endif /* CONFIG_HAS_WAKELOCK */ -} - -int dhd_os_check_wakelock(dhd_pub_t *pub) -{ -#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \ - KERNEL_VERSION(2, 6, 36))) - dhd_info_t *dhd; - - if (!pub) - return 0; - dhd = (dhd_info_t *)(pub->info); -#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ - -#ifdef CONFIG_HAS_WAKELOCK - /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ - if (dhd && (wake_lock_active(&dhd->wl_wifi) || - (wake_lock_active(&dhd->wl_wdwake)))) - return 1; -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) - return 1; -#endif - return 0; -} - -int dhd_os_check_wakelock_all(dhd_pub_t *pub) -{ -#ifdef CONFIG_HAS_WAKELOCK - int l1, l2, l3, l4, l6, l7; - int l5 = 0; - int c, lock_active; -#endif /* CONFIG_HAS_WAKELOCK */ - -#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \ - KERNEL_VERSION(2, 6, 36))) - dhd_info_t *dhd; - - if (!pub) - return 0; - - dhd = (dhd_info_t *)(pub->info); - if (!dhd) { - return 0; - } -#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ - -#ifdef CONFIG_HAS_WAKELOCK - c = dhd->wakelock_counter; - l1 = wake_lock_active(&dhd->wl_wifi); - l2 = wake_lock_active(&dhd->wl_wdwake); - l3 = wake_lock_active(&dhd->wl_rxwake); - l4 = wake_lock_active(&dhd->wl_ctrlwake); -#ifdef BCMPCIE_OOB_HOST_WAKE - l5 = wake_lock_active(&dhd->wl_intrwake); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - l6 = wake_lock_active(&dhd->wl_evtwake); - l7 = wake_lock_active(&dhd->wl_txflwake); - - lock_active = (l1 || l2 || l3 || l4 || l5 || l6 || l7); - - /* Indicate to the Host to avoid going to suspend if internal locks are up */ - if (dhd && lock_active) { - DHD_ERROR(("%s wakelock c-%d wl-%d wd-%d rx-%d " - "ctl-%d intr-%d evt-%d txfl-%d\n", - __FUNCTION__, c, l1, l2, l3, l4, l5, l6, l7)); - - return 1; - } -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) - return 1; -#endif /* CONFIG_HAS_WAKELOCK */ - return 0; -} - -int net_os_wake_unlock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_unlock(&dhd->pub); - return ret; -} - -int dhd_os_wd_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -#ifdef CONFIG_HAS_WAKELOCK - /* if wakelock_wd_counter was never used : lock it at once */ - if (!dhd->wakelock_wd_counter) - wake_lock(&dhd->wl_wdwake); -#endif - dhd->wakelock_wd_counter++; - ret = dhd->wakelock_wd_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int dhd_os_wd_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (dhd->wakelock_wd_counter) { - dhd->wakelock_wd_counter = 0; -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_wdwake); -#endif - } - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -#ifdef BCMPCIE_OOB_HOST_WAKE -int dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - int ret = 0; - - if (dhd) { -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_timeout(&dhd->wl_intrwake, msecs_to_jiffies(val)); -#endif - } - return ret; -} - -int dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - int ret = 0; - - if (dhd) { -#ifdef CONFIG_HAS_WAKELOCK - /* if wl_intrwake is active, unlock it */ - if (wake_lock_active(&dhd->wl_intrwake)) { - wake_unlock(&dhd->wl_intrwake); - } -#endif - } - return ret; -} -#endif /* BCMPCIE_OOB_HOST_WAKE */ - -/* waive wakelocks for operations such as IOVARs in suspend function, must be closed - * by a paired function call to dhd_wakelock_restore. returns current wakelock counter - */ -int dhd_os_wake_lock_waive(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ - if (dhd->waive_wakelock == FALSE) { -#ifdef DHD_TRACE_WAKE_LOCK - if (trace_wklock_onoff) { - STORE_WKLOCK_RECORD(DHD_WAIVE_LOCK); - } -#endif /* DHD_TRACE_WAKE_LOCK */ - /* record current lock status */ - dhd->wakelock_before_waive = dhd->wakelock_counter; - dhd->waive_wakelock = TRUE; - } - ret = dhd->wakelock_wd_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int dhd_os_wake_lock_restore(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (!dhd) - return 0; - - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ - if (!dhd->waive_wakelock) - goto exit; - - dhd->waive_wakelock = FALSE; - /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore, - * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases - * the lock in between, do the same by calling wake_unlock or pm_relax - */ -#ifdef DHD_TRACE_WAKE_LOCK - if (trace_wklock_onoff) { - STORE_WKLOCK_RECORD(DHD_RESTORE_LOCK); - } -#endif /* DHD_TRACE_WAKE_LOCK */ - - if (dhd->wakelock_before_waive == 0 && dhd->wakelock_counter > 0) { -#ifdef CONFIG_HAS_WAKELOCK - wake_lock(&dhd->wl_wifi); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_stay_awake(&dhd->pub); -#endif - } else if (dhd->wakelock_before_waive > 0 && dhd->wakelock_counter == 0) { -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_wifi); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_relax(&dhd->pub); -#endif - } - dhd->wakelock_before_waive = 0; -exit: - ret = dhd->wakelock_wd_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - return ret; -} - -void dhd_os_wake_lock_init(struct dhd_info *dhd) -{ - DHD_TRACE(("%s: initialize wake_lock_counters\n", __FUNCTION__)); - dhd->wakelock_event_counter = 0; - dhd->wakelock_counter = 0; - dhd->wakelock_rx_timeout_enable = 0; - dhd->wakelock_ctrl_timeout_enable = 0; -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); - wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); - wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); - wake_lock_init(&dhd->wl_evtwake, WAKE_LOCK_SUSPEND, "wlan_evt_wake"); - wake_lock_init(&dhd->wl_txflwake, WAKE_LOCK_SUSPEND, "wlan_txfl_wake"); -#ifdef BCMPCIE_OOB_HOST_WAKE - wake_lock_init(&dhd->wl_intrwake, WAKE_LOCK_SUSPEND, "wlan_oob_irq_wake"); -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#ifdef DHD_TRACE_WAKE_LOCK - dhd_wk_lock_trace_init(dhd); -#endif /* DHD_TRACE_WAKE_LOCK */ -#endif /* CONFIG_HAS_WAKELOCK */ -} - -void dhd_os_wake_lock_destroy(struct dhd_info *dhd) -{ - DHD_TRACE(("%s: deinit wake_lock_counters\n", __FUNCTION__)); - dhd->wakelock_event_counter = 0; - dhd->wakelock_counter = 0; - dhd->wakelock_rx_timeout_enable = 0; - dhd->wakelock_ctrl_timeout_enable = 0; -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_destroy(&dhd->wl_wifi); - wake_lock_destroy(&dhd->wl_rxwake); - wake_lock_destroy(&dhd->wl_ctrlwake); - wake_lock_destroy(&dhd->wl_evtwake); - wake_lock_destroy(&dhd->wl_txflwake); -#ifdef BCMPCIE_OOB_HOST_WAKE - wake_lock_destroy(&dhd->wl_intrwake); -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#ifdef DHD_TRACE_WAKE_LOCK - dhd_wk_lock_trace_deinit(dhd); -#endif /* DHD_TRACE_WAKE_LOCK */ -#endif /* CONFIG_HAS_WAKELOCK */ -} - -bool dhd_os_check_if_up(dhd_pub_t *pub) -{ - if (!pub) - return FALSE; - return pub->up; -} - -#if defined(BCMSDIO) -/* function to collect firmware, chip id and chip version info */ -void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) -{ - int i; - - i = snprintf(info_string, sizeof(info_string), - " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); - - if (!dhdp) - return; - - i = snprintf(&info_string[i], sizeof(info_string) - i, - "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), - dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); -} -#endif /* defined(BCMSDIO) */ -int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) -{ - int ifidx; - int ret = 0; - dhd_info_t *dhd = NULL; - - if (!net || !DEV_PRIV(net)) { - DHD_ERROR(("%s invalid parameter\n", __FUNCTION__)); - return -EINVAL; - } - - dhd = DHD_DEV_INFO(net); - if (!dhd) - return -EINVAL; - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); - dhd_check_hang(net, &dhd->pub, ret); - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - return ret; -} - -bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) -{ - struct net_device *net; - - net = dhd_idx2net(dhdp, ifidx); - if (!net) { - DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx)); - return -EINVAL; - } - - return dhd_check_hang(net, dhdp, ret); -} - -/* Return instance */ -int dhd_get_instance(dhd_pub_t *dhdp) -{ - return dhdp->info->unit; -} - - -#ifdef PROP_TXSTATUS - -void dhd_wlfc_plat_init(void *dhd) -{ - return; -} - -void dhd_wlfc_plat_deinit(void *dhd) -{ - return; -} - -bool dhd_wlfc_skip_fc(void) -{ - return FALSE; -} -#endif /* PROP_TXSTATUS */ - -#ifdef BCMDBGFS - -#include - -extern uint32 dhd_readregl(void *bp, uint32 addr); -extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); - -typedef struct dhd_dbgfs { - struct dentry *debugfs_dir; - struct dentry *debugfs_mem; - dhd_pub_t *dhdp; - uint32 size; -} dhd_dbgfs_t; - -dhd_dbgfs_t g_dbgfs; - -static int -dhd_dbg_state_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t -dhd_dbg_state_read(struct file *file, char __user *ubuf, - size_t count, loff_t *ppos) -{ - ssize_t rval; - uint32 tmp; - loff_t pos = *ppos; - size_t ret; - - if (pos < 0) - return -EINVAL; - if (pos >= g_dbgfs.size || !count) - return 0; - if (count > g_dbgfs.size - pos) - count = g_dbgfs.size - pos; - - /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ - tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); - - ret = copy_to_user(ubuf, &tmp, 4); - if (ret == count) - return -EFAULT; - - count -= ret; - *ppos = pos + count; - rval = count; - - return rval; -} - - -static ssize_t -dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) -{ - loff_t pos = *ppos; - size_t ret; - uint32 buf; - - if (pos < 0) - return -EINVAL; - if (pos >= g_dbgfs.size || !count) - return 0; - if (count > g_dbgfs.size - pos) - count = g_dbgfs.size - pos; - - ret = copy_from_user(&buf, ubuf, sizeof(uint32)); - if (ret == count) - return -EFAULT; - - /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ - dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); - - return count; -} - - -loff_t -dhd_debugfs_lseek(struct file *file, loff_t off, int whence) -{ - loff_t pos = -1; - - switch (whence) { - case 0: - pos = off; - break; - case 1: - pos = file->f_pos + off; - break; - case 2: - pos = g_dbgfs.size - off; - } - return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); -} - -static const struct file_operations dhd_dbg_state_ops = { - .read = dhd_dbg_state_read, - .write = dhd_debugfs_write, - .open = dhd_dbg_state_open, - .llseek = dhd_debugfs_lseek -}; - -static void dhd_dbg_create(void) -{ - if (g_dbgfs.debugfs_dir) { - g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, - NULL, &dhd_dbg_state_ops); - } -} - -void dhd_dbg_init(dhd_pub_t *dhdp) -{ - int err; - - g_dbgfs.dhdp = dhdp; - g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ - - g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); - if (IS_ERR(g_dbgfs.debugfs_dir)) { - err = PTR_ERR(g_dbgfs.debugfs_dir); - g_dbgfs.debugfs_dir = NULL; - return; - } - - dhd_dbg_create(); - - return; -} - -void dhd_dbg_remove(void) -{ - debugfs_remove(g_dbgfs.debugfs_mem); - debugfs_remove(g_dbgfs.debugfs_dir); - - bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); - -} -#endif /* ifdef BCMDBGFS */ - -#ifdef WLMEDIA_HTSF - -static -void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct sk_buff *skb; - uint32 htsf = 0; - uint16 dport = 0, oldmagic = 0xACAC; - char *p1; - htsfts_t ts; - - /* timestamp packet */ - - p1 = (char*) PKTDATA(dhdp->osh, pktbuf); - - if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { -/* memcpy(&proto, p1+26, 4); */ - memcpy(&dport, p1+40, 2); -/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ - dport = ntoh16(dport); - } - - /* timestamp only if icmp or udb iperf with port 5555 */ -/* if (proto == 17 && dport == tsport) { */ - if (dport >= tsport && dport <= tsport + 20) { - - skb = (struct sk_buff *) pktbuf; - - htsf = dhd_get_htsf(dhd, 0); - memset(skb->data + 44, 0, 2); /* clear checksum */ - memcpy(skb->data+82, &oldmagic, 2); - memcpy(skb->data+84, &htsf, 4); - - memset(&ts, 0, sizeof(htsfts_t)); - ts.magic = HTSFMAGIC; - ts.prio = PKTPRIO(pktbuf); - ts.seqnum = htsf_seqnum++; - ts.c10 = get_cycles(); - ts.t10 = htsf; - ts.endmagic = HTSFENDMAGIC; - - memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); - } -} - -static void dhd_dump_htsfhisto(histo_t *his, char *s) -{ - int pktcnt = 0, curval = 0, i; - for (i = 0; i < (NUMBIN-2); i++) { - curval += 500; - printf("%d ", his->bin[i]); - pktcnt += his->bin[i]; - } - printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, - his->bin[NUMBIN-1], s); -} - -static -void sorttobin(int value, histo_t *histo) -{ - int i, binval = 0; - - if (value < 0) { - histo->bin[NUMBIN-1]++; - return; - } - if (value > histo->bin[NUMBIN-2]) /* store the max value */ - histo->bin[NUMBIN-2] = value; - - for (i = 0; i < (NUMBIN-2); i++) { - binval += 500; /* 500m s bins */ - if (value <= binval) { - histo->bin[i]++; - return; - } - } - histo->bin[NUMBIN-3]++; -} - -static -void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - char *p1; - uint16 old_magic; - int d1, d2, d3, end2end; - htsfts_t *htsf_ts; - uint32 htsf; - - skb = PKTTONATIVE(dhdp->osh, pktbuf); - p1 = (char*)PKTDATA(dhdp->osh, pktbuf); - - if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { - memcpy(&old_magic, p1+78, 2); - htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); - } - else - return; - - if (htsf_ts->magic == HTSFMAGIC) { - htsf_ts->tE0 = dhd_get_htsf(dhd, 0); - htsf_ts->cE0 = get_cycles(); - } - - if (old_magic == 0xACAC) { - - tspktcnt++; - htsf = dhd_get_htsf(dhd, 0); - memcpy(skb->data+92, &htsf, sizeof(uint32)); - - memcpy(&ts[tsidx].t1, skb->data+80, 16); - - d1 = ts[tsidx].t2 - ts[tsidx].t1; - d2 = ts[tsidx].t3 - ts[tsidx].t2; - d3 = ts[tsidx].t4 - ts[tsidx].t3; - end2end = ts[tsidx].t4 - ts[tsidx].t1; - - sorttobin(d1, &vi_d1); - sorttobin(d2, &vi_d2); - sorttobin(d3, &vi_d3); - sorttobin(end2end, &vi_d4); - - if (end2end > 0 && end2end > maxdelay) { - maxdelay = end2end; - maxdelaypktno = tspktcnt; - memcpy(&maxdelayts, &ts[tsidx], 16); - } - if (++tsidx >= TSMAX) - tsidx = 0; - } -} - -uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) -{ - uint32 htsf = 0, cur_cycle, delta, delta_us; - uint32 factor, baseval, baseval2; - cycles_t t; - - t = get_cycles(); - cur_cycle = t; - - if (cur_cycle > dhd->htsf.last_cycle) - delta = cur_cycle - dhd->htsf.last_cycle; - else { - delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); - } - - delta = delta >> 4; - - if (dhd->htsf.coef) { - /* times ten to get the first digit */ - factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); - baseval = (delta*10)/factor; - baseval2 = (delta*10)/(factor+1); - delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); - htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; - } - else { - DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n")); - } - - return htsf; -} - -static void dhd_dump_latency(void) -{ - int i, max = 0; - int d1, d2, d3, d4, d5; - - printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); - for (i = 0; i < TSMAX; i++) { - d1 = ts[i].t2 - ts[i].t1; - d2 = ts[i].t3 - ts[i].t2; - d3 = ts[i].t4 - ts[i].t3; - d4 = ts[i].t4 - ts[i].t1; - d5 = ts[max].t4-ts[max].t1; - if (d4 > d5 && d4 > 0) { - max = i; - } - printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", - ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, - d1, d2, d3, d4, i); - } - - printf("current idx = %d \n", tsidx); - - printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); - printf("%08X %08X %08X %08X \t%d %d %d %d\n", - maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, - maxdelayts.t2 - maxdelayts.t1, - maxdelayts.t3 - maxdelayts.t2, - maxdelayts.t4 - maxdelayts.t3, - maxdelayts.t4 - maxdelayts.t1); -} - - -static int -dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) -{ - wl_ioctl_t ioc; - char buf[32]; - int ret; - uint32 s1, s2; - - struct tsf { - uint32 low; - uint32 high; - } tsf_buf; - - memset(&ioc, 0, sizeof(ioc)); - memset(&tsf_buf, 0, sizeof(tsf_buf)); - - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = (uint)sizeof(buf); - ioc.set = FALSE; - - strncpy(buf, "tsf", sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - s1 = dhd_get_htsf(dhd, 0); - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { - if (ret == -EIO) { - DHD_ERROR(("%s: tsf is not supported by device\n", - dhd_ifname(&dhd->pub, ifidx))); - return -EOPNOTSUPP; - } - return ret; - } - s2 = dhd_get_htsf(dhd, 0); - - memcpy(&tsf_buf, buf, sizeof(tsf_buf)); - printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", - tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, - dhd->htsf.coefdec2, s2-tsf_buf.low); - printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); - return 0; -} - -void htsf_update(dhd_info_t *dhd, void *data) -{ - static ulong cur_cycle = 0, prev_cycle = 0; - uint32 htsf, tsf_delta = 0; - uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; - ulong b, a; - cycles_t t; - - /* cycles_t in inlcude/mips/timex.h */ - - t = get_cycles(); - - prev_cycle = cur_cycle; - cur_cycle = t; - - if (cur_cycle > prev_cycle) - cyc_delta = cur_cycle - prev_cycle; - else { - b = cur_cycle; - a = prev_cycle; - cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); - } - - if (data == NULL) - printf(" tsf update ata point er is null \n"); - - memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); - memcpy(&cur_tsf, data, sizeof(tsf_t)); - - if (cur_tsf.low == 0) { - DHD_INFO((" ---- 0 TSF, do not update, return\n")); - return; - } - - if (cur_tsf.low > prev_tsf.low) - tsf_delta = (cur_tsf.low - prev_tsf.low); - else { - DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", - cur_tsf.low, prev_tsf.low)); - if (cur_tsf.high > prev_tsf.high) { - tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); - DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta)); - } - else - return; /* do not update */ - } - - if (tsf_delta) { - hfactor = cyc_delta / tsf_delta; - tmp = (cyc_delta - (hfactor * tsf_delta))*10; - dec1 = tmp/tsf_delta; - dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; - tmp = (tmp - (dec1*tsf_delta))*10; - dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; - - if (dec3 > 4) { - if (dec2 == 9) { - dec2 = 0; - if (dec1 == 9) { - dec1 = 0; - hfactor++; - } - else { - dec1++; - } - } - else - dec2++; - } - } - - if (hfactor) { - htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; - dhd->htsf.coef = hfactor; - dhd->htsf.last_cycle = cur_cycle; - dhd->htsf.last_tsf = cur_tsf.low; - dhd->htsf.coefdec1 = dec1; - dhd->htsf.coefdec2 = dec2; - } - else { - htsf = prev_tsf.low; - } -} - -#endif /* WLMEDIA_HTSF */ - -#ifdef CUSTOM_SET_CPUCORE -void dhd_set_cpucore(dhd_pub_t *dhd, int set) -{ - int e_dpc = 0, e_rxf = 0, retry_set = 0; - - if (!(dhd->chan_isvht80)) { - DHD_ERROR(("%s: chan_status(%d) cpucore!!!\n", __FUNCTION__, dhd->chan_isvht80)); - return; - } - - if (DPC_CPUCORE) { - do { - if (set == TRUE) { - e_dpc = set_cpus_allowed_ptr(dhd->current_dpc, - cpumask_of(DPC_CPUCORE)); - } else { - e_dpc = set_cpus_allowed_ptr(dhd->current_dpc, - cpumask_of(PRIMARY_CPUCORE)); - } - if (retry_set++ > MAX_RETRY_SET_CPUCORE) { - DHD_ERROR(("%s: dpc(%d) invalid cpu!\n", __FUNCTION__, e_dpc)); - return; - } - if (e_dpc < 0) - OSL_SLEEP(1); - } while (e_dpc < 0); - } - if (RXF_CPUCORE) { - do { - if (set == TRUE) { - e_rxf = set_cpus_allowed_ptr(dhd->current_rxf, - cpumask_of(RXF_CPUCORE)); - } else { - e_rxf = set_cpus_allowed_ptr(dhd->current_rxf, - cpumask_of(PRIMARY_CPUCORE)); - } - if (retry_set++ > MAX_RETRY_SET_CPUCORE) { - DHD_ERROR(("%s: rxf(%d) invalid cpu!\n", __FUNCTION__, e_rxf)); - return; - } - if (e_rxf < 0) - OSL_SLEEP(1); - } while (e_rxf < 0); - } -#ifdef DHD_OF_SUPPORT - interrupt_set_cpucore(set); -#endif /* DHD_OF_SUPPORT */ - DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set)); - - return; -} -#endif /* CUSTOM_SET_CPUCORE */ - -/* Get interface specific ap_isolate configuration */ -int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - return ifp->ap_isolate; -} - -/* Set interface specific ap_isolate configuration */ -int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - if (ifp) - ifp->ap_isolate = val; - - return 0; -} - -#ifdef DHD_DEBUG -void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size) -{ - dhd_dump_t *dump = NULL; - dump = (dhd_dump_t *)MALLOC(dhdp->osh, sizeof(dhd_dump_t)); - if (dump == NULL) { - DHD_ERROR(("%s: dhd dump memory allocation failed\n", __FUNCTION__)); - return; - } - dump->buf = buf; - dump->bufsize = size; - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dump, - DHD_WQ_WORK_SOC_RAM_DUMP, dhd_mem_dump, DHD_WORK_PRIORITY_HIGH); -} - -static void -dhd_mem_dump(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_dump_t *dump = event_info; - - if (!dhd || !dump) - return; - -#ifndef CONFIG_BCM_WLAN_RAMDUMP - if (write_to_file(&dhd->pub, dump->buf, dump->bufsize)) { - DHD_ERROR(("%s: writing SoC_RAM dump to the file failed\n", __FUNCTION__)); - } -#else - bcm_wlan_crash_reason(dhd->pub.crash_reason); - bcm_wlan_ramdump(dump->buf, dump->bufsize); - memset(dhd->pub.crash_reason, 0 , sizeof(dhd->pub.crash_reason)); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - MFREE(dhd->pub.osh, dump, sizeof(dhd_dump_t)); -} -#endif /* DHD_DEBUG */ - -#ifdef DHD_WMF -/* Returns interface specific WMF configuration */ -dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - return &ifp->wmf; -} -#endif /* DHD_WMF */ - - -#ifdef DHD_UNICAST_DHCP -static int -dhd_get_pkt_ether_type(dhd_pub_t *pub, void *pktbuf, - uint8 **data_ptr, int *len_ptr, uint16 *et_ptr, bool *snap_ptr) -{ - uint8 *frame = PKTDATA(pub->osh, pktbuf); - int length = PKTLEN(pub->osh, pktbuf); - uint8 *pt; /* Pointer to type field */ - uint16 ethertype; - bool snap = FALSE; - /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ - if (length < ETHER_HDR_LEN) { - DHD_ERROR(("dhd: %s: short eth frame (%d)\n", - __FUNCTION__, length)); - return BCME_ERROR; - } else if (ntoh16_ua(frame + ETHER_TYPE_OFFSET) >= ETHER_TYPE_MIN) { - /* Frame is Ethernet II */ - pt = frame + ETHER_TYPE_OFFSET; - } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && - !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { - pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; - snap = TRUE; - } else { - DHD_INFO(("DHD: %s: non-SNAP 802.3 frame\n", - __FUNCTION__)); - return BCME_ERROR; - } - - ethertype = ntoh16_ua(pt); - - /* Skip VLAN tag, if any */ - if (ethertype == ETHER_TYPE_8021Q) { - pt += VLAN_TAG_LEN; - - if ((pt + ETHER_TYPE_LEN) > (frame + length)) { - DHD_ERROR(("dhd: %s: short VLAN frame (%d)\n", - __FUNCTION__, length)); - return BCME_ERROR; - } - - ethertype = ntoh16_ua(pt); - } - - *data_ptr = pt + ETHER_TYPE_LEN; - *len_ptr = length - (pt + ETHER_TYPE_LEN - frame); - *et_ptr = ethertype; - *snap_ptr = snap; - return BCME_OK; -} - -static int -dhd_get_pkt_ip_type(dhd_pub_t *pub, void *pktbuf, - uint8 **data_ptr, int *len_ptr, uint8 *prot_ptr) -{ - struct ipv4_hdr *iph; /* IP frame pointer */ - int iplen; /* IP frame length */ - uint16 ethertype, iphdrlen, ippktlen; - uint16 iph_frag; - uint8 prot; - bool snap; - - if (dhd_get_pkt_ether_type(pub, pktbuf, (uint8 **)&iph, - &iplen, ðertype, &snap) != 0) - return BCME_ERROR; - - if (ethertype != ETHER_TYPE_IP) { - return BCME_ERROR; - } - - /* We support IPv4 only */ - if (iplen < IPV4_OPTIONS_OFFSET || (IP_VER(iph) != IP_VER_4)) { - return BCME_ERROR; - } - - /* Header length sanity */ - iphdrlen = IPV4_HLEN(iph); - - /* - * Packet length sanity; sometimes we receive eth-frame size bigger - * than the IP content, which results in a bad tcp chksum - */ - ippktlen = ntoh16(iph->tot_len); - if (ippktlen < iplen) { - - DHD_INFO(("%s: extra frame length ignored\n", - __FUNCTION__)); - iplen = ippktlen; - } else if (ippktlen > iplen) { - DHD_ERROR(("dhd: %s: truncated IP packet (%d)\n", - __FUNCTION__, ippktlen - iplen)); - return BCME_ERROR; - } - - if (iphdrlen < IPV4_OPTIONS_OFFSET || iphdrlen > iplen) { - DHD_ERROR(("DHD: %s: IP-header-len (%d) out of range (%d-%d)\n", - __FUNCTION__, iphdrlen, IPV4_OPTIONS_OFFSET, iplen)); - return BCME_ERROR; - } - - /* - * We don't handle fragmented IP packets. A first frag is indicated by the MF - * (more frag) bit and a subsequent frag is indicated by a non-zero frag offset. - */ - iph_frag = ntoh16(iph->frag); - - if ((iph_frag & IPV4_FRAG_MORE) || (iph_frag & IPV4_FRAG_OFFSET_MASK) != 0) { - DHD_INFO(("DHD:%s: IP fragment not handled\n", - __FUNCTION__)); - return BCME_ERROR; - } - - prot = IPV4_PROT(iph); - - *data_ptr = (((uint8 *)iph) + iphdrlen); - *len_ptr = iplen - iphdrlen; - *prot_ptr = prot; - return BCME_OK; -} - -/** check the packet type, if it is DHCP ACK/REPLY, convert into unicast packet */ -static -int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx) -{ - dhd_sta_t* stainfo; - uint8 *eh = PKTDATA(pub->osh, pktbuf); - uint8 *udph; - uint8 *dhcp; - uint8 *chaddr; - int udpl; - int dhcpl; - uint16 port; - uint8 prot; - - if (!ETHER_ISMULTI(eh + ETHER_DEST_OFFSET)) - return BCME_ERROR; - if (dhd_get_pkt_ip_type(pub, pktbuf, &udph, &udpl, &prot) != 0) - return BCME_ERROR; - if (prot != IP_PROT_UDP) - return BCME_ERROR; - /* check frame length, at least UDP_HDR_LEN */ - if (udpl < UDP_HDR_LEN) { - DHD_ERROR(("DHD: %s: short UDP frame, ignored\n", - __FUNCTION__)); - return BCME_ERROR; - } - port = ntoh16_ua(udph + UDP_DEST_PORT_OFFSET); - /* only process DHCP packets from server to client */ - if (port != DHCP_PORT_CLIENT) - return BCME_ERROR; - - dhcp = udph + UDP_HDR_LEN; - dhcpl = udpl - UDP_HDR_LEN; - - if (dhcpl < DHCP_CHADDR_OFFSET + ETHER_ADDR_LEN) { - DHD_ERROR(("DHD: %s: short DHCP frame, ignored\n", - __FUNCTION__)); - return BCME_ERROR; - } - /* only process DHCP reply(offer/ack) packets */ - if (*(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY) - return BCME_ERROR; - chaddr = dhcp + DHCP_CHADDR_OFFSET; - stainfo = dhd_find_sta(pub, ifidx, chaddr); - if (stainfo) { - bcopy(chaddr, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); - return BCME_OK; - } - return BCME_ERROR; -} -#endif /* DHD_UNICAST_DHD */ -#ifdef DHD_L2_FILTER -/* Check if packet type is ICMP ECHO */ -static -int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx) -{ - struct bcmicmp_hdr *icmph; - int udpl; - uint8 prot; - - if (dhd_get_pkt_ip_type(pub, pktbuf, (uint8 **)&icmph, &udpl, &prot) != 0) - return BCME_ERROR; - if (prot == IP_PROT_ICMP) { - if (icmph->type == ICMP_TYPE_ECHO_REQUEST) - return BCME_OK; - } - return BCME_ERROR; -} -#endif /* DHD_L2_FILTER */ - -#if defined(SET_RPS_CPUS) -int dhd_rps_cpus_enable(struct net_device *net, int enable) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); - dhd_if_t *ifp; - int ifidx; - char * RPS_CPU_SETBUF; - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - if (ifidx == PRIMARY_INF) { - if (dhd->pub.op_mode == DHD_FLAG_IBSS_MODE) { - DHD_INFO(("%s : set for IBSS.\n", __FUNCTION__)); - RPS_CPU_SETBUF = RPS_CPUS_MASK_IBSS; - } else { - DHD_INFO(("%s : set for BSS.\n", __FUNCTION__)); - RPS_CPU_SETBUF = RPS_CPUS_MASK; - } - } else if (ifidx == VIRTUAL_INF) { - DHD_INFO(("%s : set for P2P.\n", __FUNCTION__)); - RPS_CPU_SETBUF = RPS_CPUS_MASK_P2P; - } else { - DHD_ERROR(("%s : Invalid index : %d.\n", __FUNCTION__, ifidx)); - return -EINVAL; - } - - ifp = dhd->iflist[ifidx]; - if (ifp) { - if (enable) { - DHD_INFO(("%s : set rps_cpus as [%s]\n", __FUNCTION__, RPS_CPU_SETBUF)); - custom_rps_map_set(ifp->net->_rx, RPS_CPU_SETBUF, strlen(RPS_CPU_SETBUF)); - } else { - custom_rps_map_clear(ifp->net->_rx); - } - } else { - DHD_ERROR(("%s : ifp is NULL!!\n", __FUNCTION__)); - return -ENODEV; - } - return BCME_OK; -} - -int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len) -{ - struct rps_map *old_map, *map; - cpumask_var_t mask; - int err, cpu, i; - static DEFINE_SPINLOCK(rps_map_lock); - - DHD_INFO(("%s : Entered.\n", __FUNCTION__)); - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { - DHD_ERROR(("%s : alloc_cpumask_var fail.\n", __FUNCTION__)); - return -ENOMEM; - } - - err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); - if (err) { - free_cpumask_var(mask); - DHD_ERROR(("%s : bitmap_parse fail.\n", __FUNCTION__)); - return err; - } - - map = kzalloc(max_t(unsigned int, - RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), - GFP_KERNEL); - if (!map) { - free_cpumask_var(mask); - DHD_ERROR(("%s : map malloc fail.\n", __FUNCTION__)); - return -ENOMEM; - } - - i = 0; - for_each_cpu(cpu, mask) - map->cpus[i++] = cpu; - - if (i) - map->len = i; - else { - kfree(map); - map = NULL; - free_cpumask_var(mask); - DHD_ERROR(("%s : mapping cpu fail.\n", __FUNCTION__)); - return -1; - } - - spin_lock(&rps_map_lock); - old_map = rcu_dereference_protected(queue->rps_map, - lockdep_is_held(&rps_map_lock)); - rcu_assign_pointer(queue->rps_map, map); - spin_unlock(&rps_map_lock); - - if (map) - static_key_slow_inc(&rps_needed); - if (old_map) { - kfree_rcu(old_map, rcu); - static_key_slow_dec(&rps_needed); - } - free_cpumask_var(mask); - - DHD_INFO(("%s : Done. mapping cpu nummber : %d\n", __FUNCTION__, map->len)); - return map->len; -} - -void custom_rps_map_clear(struct netdev_rx_queue *queue) -{ - struct rps_map *map; - - DHD_INFO(("%s : Entered.\n", __FUNCTION__)); - - map = rcu_dereference_protected(queue->rps_map, 1); - if (map) { - RCU_INIT_POINTER(queue->rps_map, NULL); - kfree_rcu(map, rcu); - DHD_INFO(("%s : rps_cpus map clear.\n", __FUNCTION__)); - } -} -#endif /* SET_RPS_CPUS */ - - -/* ---------------------------------------------------------------------------- - * Infrastructure code for sysfs interface support for DHD - * - * What is sysfs interface? - * https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt - * - * Why sysfs interface? - * This is the Linux standard way of changing/configuring Run Time parameters - * for a driver. We can use this interface to control "linux" specific driver - * parameters. - * - * ----------------------------------------------------------------------------- - */ - -#include -#include - -#if defined(DHD_TRACE_WAKE_LOCK) - -/* Function to show the history buffer */ -static ssize_t -show_wklock_trace(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - dhd_info_t *dhd = (dhd_info_t *)dev; - - buf[ret] = '\n'; - buf[ret+1] = 0; - - dhd_wk_lock_stats_dump(&dhd->pub); - return ret+1; -} - -/* Function to enable/disable wakelock trace */ -static ssize_t -wklock_trace_onoff(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned long onoff; - unsigned long flags; - dhd_info_t *dhd = (dhd_info_t *)dev; - - onoff = bcm_strtoul(buf, NULL, 10); - if (onoff != 0 && onoff != 1) { - return -EINVAL; - } - - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - trace_wklock_onoff = onoff; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - if (trace_wklock_onoff) { - printk("ENABLE WAKELOCK TRACE\n"); - } else { - printk("DISABLE WAKELOCK TRACE\n"); - } - - return (ssize_t)(onoff+1); -} -#endif /* DHD_TRACE_WAKE_LOCK */ - -/* - * Generic Attribute Structure for DHD. - * If we have to add a new sysfs entry under /sys/bcm-dhd/, we have - * to instantiate an object of type dhd_attr, populate it with - * the required show/store functions (ex:- dhd_attr_cpumask_primary) - * and add the object to default_attrs[] array, that gets registered - * to the kobject of dhd (named bcm-dhd). - */ - -struct dhd_attr { - struct attribute attr; - ssize_t(*show)(struct dhd_info *, char *); - ssize_t(*store)(struct dhd_info *, const char *, size_t count); -}; - -#if defined(DHD_TRACE_WAKE_LOCK) -static struct dhd_attr dhd_attr_wklock = - __ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff); -#endif /* defined(DHD_TRACE_WAKE_LOCK */ - -/* Attribute object that gets registered with "bcm-dhd" kobject tree */ -static struct attribute *default_attrs[] = { -#if defined(DHD_TRACE_WAKE_LOCK) - &dhd_attr_wklock.attr, -#endif - NULL -}; - -#define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj) -#define to_attr(a) container_of(a, struct dhd_attr, attr) - -/* - * bcm-dhd kobject show function, the "attr" attribute specifices to which - * node under "bcm-dhd" the show function is called. - */ -static ssize_t dhd_show(struct kobject *kobj, struct attribute *attr, char *buf) -{ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - - dhd_info_t *dhd = to_dhd(kobj); - struct dhd_attr *d_attr = to_attr(attr); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - int ret; - - if (d_attr->show) - ret = d_attr->show(dhd, buf); - else - ret = -EIO; - - return ret; -} - - -/* - * bcm-dhd kobject show function, the "attr" attribute specifices to which - * node under "bcm-dhd" the store function is called. - */ -static ssize_t dhd_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - dhd_info_t *dhd = to_dhd(kobj); - struct dhd_attr *d_attr = to_attr(attr); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - int ret; - - if (d_attr->store) - ret = d_attr->store(dhd, buf, count); - else - ret = -EIO; - - return ret; - -} - -static struct sysfs_ops dhd_sysfs_ops = { - .show = dhd_show, - .store = dhd_store, -}; - -static struct kobj_type dhd_ktype = { - .sysfs_ops = &dhd_sysfs_ops, - .default_attrs = default_attrs, -}; - -/* Create a kobject and attach to sysfs interface */ -static int dhd_sysfs_init(dhd_info_t *dhd) -{ - int ret = -1; - - if (dhd == NULL) { - DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__)); - return ret; - } - - /* Initialize the kobject */ - ret = kobject_init_and_add(&dhd->dhd_kobj, &dhd_ktype, NULL, "bcm-dhd"); - if (ret) { - kobject_put(&dhd->dhd_kobj); - DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__)); - return ret; - } - - /* - * We are always responsible for sending the uevent that the kobject - * was added to the system. - */ - kobject_uevent(&dhd->dhd_kobj, KOBJ_ADD); - - return ret; -} - -/* Done with the kobject and detach the sysfs interface */ -static void dhd_sysfs_exit(dhd_info_t *dhd) -{ - if (dhd == NULL) { - DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__)); - return; - } - - /* Releae the kobject */ - kobject_put(&dhd->dhd_kobj); -} - -/* ---------------------------- End of sysfs implementation ------------------------------------- */ diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.h b/drivers/net/wireless/bcmdhd/dhd_linux.h deleted file mode 100644 index a245854db304..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_linux.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * DHD Linux header file (dhd_linux exports for cfg80211 and other components) - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux.h 399301 2013-04-29 21:41:52Z $ - */ - -/* wifi platform functions for power, interrupt and pre-alloc, either - * from Android-like platform device data, or Broadcom wifi platform - * device data. - * - */ -#ifndef __DHD_LINUX_H__ -#define __DHD_LINUX_H__ - -#include -#include -#include -#include -#include -#ifdef DHD_WMF -#include -#endif - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -#include -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ -#if defined(CONFIG_WIFI_CONTROL_FUNC) -#include -#endif -#ifdef CUSTOM_FORCE_NODFS_FLAG -#define WLAN_PLAT_NODFS_FLAG 0x01 -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -#if !defined(CONFIG_WIFI_CONTROL_FUNC) -struct wifi_platform_data { - int (*set_power)(int val); - int (*set_reset)(int val); - int (*set_carddetect)(int val); - void *(*mem_prealloc)(int section, unsigned long size); - int (*get_mac_addr)(unsigned char *buf); -#ifdef DHD_WAKE_STATUS - int (*get_wake_irq)(void); -#endif /* DHD_WAKE_STATUS */ -#ifdef CUSTOM_FORCE_NODFS_FLAG - void *(*get_country_code)(char *ccode, u32 flags); -#else - void *(*get_country_code)(char *ccode); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -}; -#endif /* CONFIG_WIFI_CONTROL_FUNC */ - -#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ - -typedef struct wifi_adapter_info { - const char *name; - uint irq_num; - uint intr_flags; - const char *fw_path; - const char *nv_path; - void *wifi_plat_data; /* wifi ctrl func, for backward compatibility */ - uint bus_type; - uint bus_num; - uint slot_num; -} wifi_adapter_info_t; - -typedef struct bcmdhd_wifi_platdata { - uint num_adapters; - wifi_adapter_info_t *adapters; -} bcmdhd_wifi_platdata_t; - -/** Per STA params. A list of dhd_sta objects are managed in dhd_if */ -typedef struct dhd_sta { - uint16 flowid[NUMPRIO]; /* allocated flow ring ids (by priority) */ - void * ifp; /* associated dhd_if */ - struct ether_addr ea; /* stations ethernet mac address */ - struct list_head list; /* link into dhd_if::sta_list */ - int idx; /* index of self in dhd_pub::sta_pool[] */ - int ifidx; /* index of interface in dhd */ -} dhd_sta_t; -typedef dhd_sta_t dhd_sta_pool_t; - -int dhd_wifi_platform_register_drv(void); -void dhd_wifi_platform_unregister_drv(void); -wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, - uint32 slot_num); -int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec); -int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present); -int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr); -int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf); -#ifdef CUSTOM_FORCE_NODFS_FLAG -void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, - u32 flags); -#else -void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size); -void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter); - -int dhd_get_fw_mode(struct dhd_info *dhdinfo); -bool dhd_update_fw_nv_path(struct dhd_info *dhdinfo); - -#ifdef DHD_WMF -dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx); -#endif /* DHD_WMF */ -#endif /* __DHD_LINUX_H__ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c deleted file mode 100644 index 1e4e72d4b9ae..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - * Linux platform device for DHD WLAN adapter - * - * Copyright (C) 1999-2017, Broadcom Corporation - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux_platdev.c 401742 2013-05-13 15:03:21Z $ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_WIFI_CONTROL_FUNC) -#include -#endif -#ifdef CONFIG_DTS -#include -#include -#endif /* CONFIG_DTS */ -#ifdef CONFIG_SOMC_WIFI_CONTROL -#include -#endif /* CONFIG_SOMC_WIFI_CONTROL */ - -#define WIFI_PLAT_NAME "bcmdhd_wlan" -#define WIFI_PLAT_NAME2 "bcm4329_wlan" -#define WIFI_PLAT_EXT "bcmdhd_wifi_platform" - -#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) -struct regulator *wifi_regulator = NULL; -#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ - -bool cfg_multichip = FALSE; -bcmdhd_wifi_platdata_t *dhd_wifi_platdata = NULL; -static int wifi_plat_dev_probe_ret = 0; -static bool is_power_on = FALSE; -#if !defined(CONFIG_DTS) -#if defined(DHD_OF_SUPPORT) -static bool dts_enabled = TRUE; -extern struct resource dhd_wlan_resources; -extern struct wifi_platform_data dhd_wlan_control; -#else -static bool dts_enabled = FALSE; -struct resource dhd_wlan_resources = {0}; -struct wifi_platform_data dhd_wlan_control = {0}; -#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */ -#endif /* !defind(CONFIG_DTS) */ - -static int dhd_wifi_platform_load(void); - -extern void* wl_cfg80211_get_dhdp(void); - -#ifdef ENABLE_4335BT_WAR -extern int bcm_bt_lock(int cookie); -extern void bcm_bt_unlock(int cookie); -static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ -#endif /* ENABLE_4335BT_WAR */ - -wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num) -{ - int i; - - if (dhd_wifi_platdata == NULL) - return NULL; - - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; - if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && - (adapter->bus_num == -1 || adapter->bus_num == bus_num) && - (adapter->slot_num == -1 || adapter->slot_num == slot_num)) { - DHD_TRACE(("found adapter info '%s'\n", adapter->name)); - return adapter; - } - } - return NULL; -} - -void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size) -{ - void *alloc_ptr = NULL; - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return NULL; - plat_data = adapter->wifi_plat_data; - if (plat_data->mem_prealloc) { - alloc_ptr = plat_data->mem_prealloc(section, size); - if (alloc_ptr) { - DHD_INFO(("success alloc section %d\n", section)); - if (size != 0L) - bzero(alloc_ptr, size); - return alloc_ptr; - } - } - - DHD_ERROR(("%s: failed to alloc static mem section %d\n", __FUNCTION__, section)); - return NULL; -} - -void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter) -{ - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return NULL; - plat_data = adapter->wifi_plat_data; - return plat_data->mem_prealloc; -} - -int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr) -{ - if (adapter == NULL) - return -1; - if (irq_flags_ptr) - *irq_flags_ptr = adapter->intr_flags; - return adapter->irq_num; -} - -int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec) -{ - int err = 0; -#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) - if (on) { - err = regulator_enable(wifi_regulator); - is_power_on = TRUE; - } - else { - err = regulator_disable(wifi_regulator); - is_power_on = FALSE; - } - if (err < 0) - DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__)); -#else - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return -EINVAL; - plat_data = adapter->wifi_plat_data; - - DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); - if (plat_data->set_power) { -#ifdef ENABLE_4335BT_WAR - if (on) { - printk("WiFi: trying to acquire BT lock\n"); - if (bcm_bt_lock(lock_cookie_wifi) != 0) - printk("** WiFi: timeout in acquiring bt lock**\n"); - printk("%s: btlock acquired\n", __FUNCTION__); - } - else { - /* For a exceptional case, release btlock */ - bcm_bt_unlock(lock_cookie_wifi); - } -#endif /* ENABLE_4335BT_WAR */ - - err = plat_data->set_power(on); - } - - if (msec && !err) - OSL_SLEEP(msec); - - if (on && !err) - is_power_on = TRUE; - else - is_power_on = FALSE; - -#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ - - return err; -} - -int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present) -{ - int err = 0; - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return -EINVAL; - plat_data = adapter->wifi_plat_data; - - DHD_ERROR(("%s device present %d\n", __FUNCTION__, device_present)); - if (plat_data->set_carddetect) { - err = plat_data->set_carddetect(device_present); - } - return err; - -} - -int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf) -{ - struct wifi_platform_data *plat_data; - - DHD_ERROR(("%s\n", __FUNCTION__)); - if (!buf || !adapter || !adapter->wifi_plat_data) - return -EINVAL; - plat_data = adapter->wifi_plat_data; - if (plat_data->get_mac_addr) { - return plat_data->get_mac_addr(buf); - } -#ifdef GET_CUSTOM_MAC_ENABLE - return somc_get_mac_address(buf); -#else - return -EOPNOTSUPP; -#endif -} -#ifdef CUSTOM_FORCE_NODFS_FLAG -void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, - u32 flags) -#else -void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -{ - /* get_country_code was added after 2.6.39 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) - struct wifi_platform_data *plat_data; - - if (!ccode || !adapter || !adapter->wifi_plat_data) - return NULL; - plat_data = adapter->wifi_plat_data; - - DHD_TRACE(("%s\n", __FUNCTION__)); - if (plat_data->get_country_code) { -#ifdef CUSTOM_FORCE_NODFS_FLAG - return plat_data->get_country_code(ccode, flags); -#else - return plat_data->get_country_code(ccode); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - } -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ - - return NULL; -} - -static int wifi_plat_dev_drv_probe(struct platform_device *pdev) -{ - struct resource *resource; - wifi_adapter_info_t *adapter; -#ifdef CONFIG_DTS - int irq, gpio; -#endif /* CONFIG_DTS */ - - /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") - * is kept for backward compatibility and supports only 1 adapter - */ - ASSERT(dhd_wifi_platdata != NULL); - ASSERT(dhd_wifi_platdata->num_adapters == 1); - adapter = &dhd_wifi_platdata->adapters[0]; -#ifdef CONFIG_SOMC_WIFI_CONTROL - adapter->wifi_plat_data = (void *)&somc_wifi_control; -#else - adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data); -#endif /* CONFIG_SOMC_WIFI_CONTROL */ - resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); - if (resource == NULL) - resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); - if (resource) { - adapter->irq_num = resource->start; - adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK; - } -#ifdef CONFIG_SOMC_WIFI_CONTROL - somc_wifi_init(pdev); -#endif /* CONFIG_SOMC_WIFI_CONTROL */ -#ifdef CONFIG_DTS -#ifndef CUSTOMER_HW5 - wifi_regulator = regulator_get(&pdev->dev, "wlreg_on"); - if (wifi_regulator == NULL) { - DHD_ERROR(("%s regulator is null\n", __FUNCTION__)); - return -1; - } -#endif /* CUSTOMER_HW5 */ - /* This is to get the irq for the OOB */ -#ifdef CONFIG_SOMC_WIFI_CONTROL - gpio = of_get_gpio(pdev->dev.of_node, 1); -#else - gpio = of_get_gpio(pdev->dev.of_node, 0); -#endif /* CONFIG_SOMC_WIFI_CONTROL */ - if (gpio < 0) { - DHD_ERROR(("%s gpio information is incorrect\n", __FUNCTION__)); - return -1; - } - irq = gpio_to_irq(gpio); - if (irq < 0) { - DHD_ERROR(("%s irq information is incorrect\n", __FUNCTION__)); - return -1; - } - adapter->irq_num = irq; - - /* need to change the flags according to our requirement */ - adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE; -#endif /* CONFIG_DTS */ - - wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); - return wifi_plat_dev_probe_ret; -} - -static int wifi_plat_dev_drv_remove(struct platform_device *pdev) -{ - wifi_adapter_info_t *adapter; - - /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") - * is kept for backward compatibility and supports only 1 adapter - */ - ASSERT(dhd_wifi_platdata != NULL); - ASSERT(dhd_wifi_platdata->num_adapters == 1); - adapter = &dhd_wifi_platdata->adapters[0]; - if (is_power_on) { -#ifdef BCMPCIE - wifi_platform_bus_enumerate(adapter, FALSE); - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); -#else - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); -#endif /* BCMPCIE */ - } - -#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) - regulator_put(wifi_regulator); -#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ -#ifdef CONFIG_SOMC_WIFI_CONTROL - somc_wifi_deinit(pdev); -#endif /* CONFIG_SOMC_WIFI_CONTROL */ - return 0; -} - -static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t state) -{ - DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \ - defined(BCMSDIO) - bcmsdh_oob_intr_set(0); -#endif /* (OOB_INTR_ONLY) */ - return 0; -} - -static int wifi_plat_dev_drv_resume(struct platform_device *pdev) -{ - DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \ - defined(BCMSDIO) - if (dhd_os_check_if_up(wl_cfg80211_get_dhdp())) - bcmsdh_oob_intr_set(1); -#endif /* (OOB_INTR_ONLY) */ - return 0; -} - -#ifdef CONFIG_DTS -static const struct of_device_id wifi_device_dt_match[] = { - { .compatible = "android,bcmdhd_wlan", }, - {}, -}; -#endif /* CONFIG_DTS */ -static struct platform_driver wifi_platform_dev_driver = { - .probe = wifi_plat_dev_drv_probe, - .remove = wifi_plat_dev_drv_remove, - .suspend = wifi_plat_dev_drv_suspend, - .resume = wifi_plat_dev_drv_resume, - .driver = { - .name = WIFI_PLAT_NAME, -#ifdef CONFIG_DTS - .of_match_table = wifi_device_dt_match, -#endif /* CONFIG_DTS */ - } -}; - -static struct platform_driver wifi_platform_dev_driver_legacy = { - .probe = wifi_plat_dev_drv_probe, - .remove = wifi_plat_dev_drv_remove, - .suspend = wifi_plat_dev_drv_suspend, - .resume = wifi_plat_dev_drv_resume, - .driver = { - .name = WIFI_PLAT_NAME2, - } -}; - -static int wifi_platdev_match(struct device *dev, void *data) -{ - char *name = (char*)data; - struct platform_device *pdev = to_platform_device(dev); - - if (strcmp(pdev->name, name) == 0) { - DHD_ERROR(("found wifi platform device %s\n", name)); - return TRUE; - } - - return FALSE; -} - -static int wifi_ctrlfunc_register_drv(void) -{ - int err = 0; - struct device *dev1, *dev2; - wifi_adapter_info_t *adapter; - - dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); - dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); - -#if !defined(CONFIG_DTS) - if (!dts_enabled) { - if (dev1 == NULL && dev2 == NULL) { - DHD_ERROR(("no wifi platform data, skip\n")); - return -ENXIO; - } - } -#endif /* !defined(CONFIG_DTS) */ - - /* multi-chip support not enabled, build one adapter information for - * DHD (either SDIO, USB or PCIe) - */ - adapter = kzalloc(sizeof(wifi_adapter_info_t), GFP_KERNEL); - adapter->name = "DHD generic adapter"; - adapter->bus_type = -1; - adapter->bus_num = -1; - adapter->slot_num = -1; - adapter->irq_num = -1; - is_power_on = FALSE; - wifi_plat_dev_probe_ret = 0; - dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL); - dhd_wifi_platdata->num_adapters = 1; - dhd_wifi_platdata->adapters = adapter; - - if (dev1) { - err = platform_driver_register(&wifi_platform_dev_driver); - if (err) { - DHD_ERROR(("%s: failed to register wifi ctrl func driver\n", - __FUNCTION__)); - return err; - } - } - if (dev2) { - err = platform_driver_register(&wifi_platform_dev_driver_legacy); - if (err) { - DHD_ERROR(("%s: failed to register wifi ctrl func legacy driver\n", - __FUNCTION__)); - return err; - } - } - -#if !defined(CONFIG_DTS) - if (dts_enabled) { - struct resource *resource; - adapter->wifi_plat_data = (void *)&dhd_wlan_control; - resource = &dhd_wlan_resources; - adapter->irq_num = resource->start; - adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK; - wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); - } -#endif /* !defined(CONFIG_DTS) */ - - -#ifdef CONFIG_DTS - wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver); -#endif /* CONFIG_DTS */ - - /* return probe function's return value if registeration succeeded */ - return wifi_plat_dev_probe_ret; -} - -void wifi_ctrlfunc_unregister_drv(void) -{ - -#ifdef CONFIG_DTS - DHD_ERROR(("unregister wifi platform drivers\n")); - platform_driver_unregister(&wifi_platform_dev_driver); -#else - struct device *dev1, *dev2; - dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); - dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); - if (!dts_enabled) - if (dev1 == NULL && dev2 == NULL) - return; - - DHD_ERROR(("unregister wifi platform drivers\n")); - if (dev1) - platform_driver_unregister(&wifi_platform_dev_driver); - if (dev2) - platform_driver_unregister(&wifi_platform_dev_driver_legacy); - if (dts_enabled) { - wifi_adapter_info_t *adapter; - adapter = &dhd_wifi_platdata->adapters[0]; - if (is_power_on) { - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } - } -#endif /* !defined(CONFIG_DTS) */ - - kfree(dhd_wifi_platdata->adapters); - dhd_wifi_platdata->adapters = NULL; - dhd_wifi_platdata->num_adapters = 0; - kfree(dhd_wifi_platdata); - dhd_wifi_platdata = NULL; -} - -static int bcmdhd_wifi_plat_dev_drv_probe(struct platform_device *pdev) -{ - dhd_wifi_platdata = (bcmdhd_wifi_platdata_t *)(pdev->dev.platform_data); - - return dhd_wifi_platform_load(); -} - -static int bcmdhd_wifi_plat_dev_drv_remove(struct platform_device *pdev) -{ - int i; - wifi_adapter_info_t *adapter; - ASSERT(dhd_wifi_platdata != NULL); - - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } - return 0; -} - -static struct platform_driver dhd_wifi_platform_dev_driver = { - .probe = bcmdhd_wifi_plat_dev_drv_probe, - .remove = bcmdhd_wifi_plat_dev_drv_remove, - .driver = { - .name = WIFI_PLAT_EXT, - } -}; - -int dhd_wifi_platform_register_drv(void) -{ - int err = 0; - struct device *dev; - - /* register Broadcom wifi platform data driver if multi-chip is enabled, - * otherwise use Android style wifi platform data (aka wifi control function) - * if it exists - * - * to support multi-chip DHD, Broadcom wifi platform data device must - * be added in kernel early boot (e.g. board config file). - */ - if (cfg_multichip) { - dev = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_EXT, wifi_platdev_match); - if (dev == NULL) { - DHD_ERROR(("bcmdhd wifi platform data device not found!!\n")); - return -ENXIO; - } - err = platform_driver_register(&dhd_wifi_platform_dev_driver); - } else { - err = wifi_ctrlfunc_register_drv(); - - /* no wifi ctrl func either, load bus directly and ignore this error */ - if (err) { - if (err == -ENXIO) { - /* wifi ctrl function does not exist */ - err = dhd_wifi_platform_load(); - } else { - /* unregister driver due to initialization failure */ - wifi_ctrlfunc_unregister_drv(); - } - } - } - - return err; -} - -#ifdef BCMPCIE -static int dhd_wifi_platform_load_pcie(void) -{ - int err = 0; - int i; - wifi_adapter_info_t *adapter; - - BCM_REFERENCE(i); - BCM_REFERENCE(adapter); - - if (dhd_wifi_platdata == NULL) { - err = dhd_bus_register(); - } else { -#ifndef CUSTOMER_HW5 - if (dhd_download_fw_on_driverload) { -#else - { -#endif /* CUSTOMER_HW5 */ - /* power up all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - int retry = POWERUP_MAX_RETRY; - adapter = &dhd_wifi_platdata->adapters[i]; - - DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); - DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", - adapter->irq_num, adapter->intr_flags, adapter->fw_path, - adapter->nv_path)); - DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", - adapter->bus_type, adapter->bus_num, adapter->slot_num)); - - do { - err = wifi_platform_set_power(adapter, - TRUE, WIFI_TURNON_DELAY); - if (err) { - DHD_ERROR(("failed to power up %s," - " %d retry left\n", - adapter->name, retry)); - /* WL_REG_ON state unknown, Power off forcely */ - wifi_platform_set_power(adapter, - FALSE, WIFI_TURNOFF_DELAY); - continue; - } else { - err = wifi_platform_bus_enumerate(adapter, TRUE); - if (err) { - DHD_ERROR(("failed to enumerate bus %s, " - "%d retry left\n", - adapter->name, retry)); - wifi_platform_set_power(adapter, FALSE, - WIFI_TURNOFF_DELAY); - } else { - break; - } - } - } while (retry--); - - if (retry < 0) { - DHD_ERROR(("failed to power up %s, max retry reached**\n", - adapter->name)); - return -ENODEV; - } - } - } - - err = dhd_bus_register(); - - if (err) { - DHD_ERROR(("%s: pcie_register_driver failed\n", __FUNCTION__)); -#ifndef CUSTOMER_HW5 - if (dhd_download_fw_on_driverload) { -#else - { -#endif /* CUSTOMER_HW5 */ - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_bus_enumerate(adapter, FALSE); - wifi_platform_set_power(adapter, - FALSE, WIFI_TURNOFF_DELAY); - } - } - } - } - - return err; -} -#else -static int dhd_wifi_platform_load_pcie(void) -{ - return 0; -} -#endif /* BCMPCIE */ - - -void dhd_wifi_platform_unregister_drv(void) -{ - if (cfg_multichip) - platform_driver_unregister(&dhd_wifi_platform_dev_driver); - else - wifi_ctrlfunc_unregister_drv(); -} - -extern int dhd_watchdog_prio; -extern int dhd_dpc_prio; -extern uint dhd_deferred_tx; -#if defined(BCMLXSDMMC) -extern struct semaphore dhd_registration_sem; -#endif - -#ifdef BCMSDIO -static int dhd_wifi_platform_load_sdio(void) -{ - int i; - int err = 0; - wifi_adapter_info_t *adapter; - - BCM_REFERENCE(i); - BCM_REFERENCE(adapter); - /* Sanity check on the module parameters - * - Both watchdog and DPC as tasklets are ok - * - If both watchdog and DPC are threads, TX must be deferred - */ - if (!(dhd_watchdog_prio < 0 && dhd_dpc_prio < 0) && - !(dhd_watchdog_prio >= 0 && dhd_dpc_prio >= 0 && dhd_deferred_tx)) - return -EINVAL; - -#if defined(BCMLXSDMMC) - if (dhd_wifi_platdata == NULL) { - DHD_ERROR(("DHD wifi platform data is required for Android build\n")); - return -EINVAL; - } - - sema_init(&dhd_registration_sem, 0); - /* power up all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - bool chip_up = FALSE; - int retry = POWERUP_MAX_RETRY; - struct semaphore dhd_chipup_sem; - - adapter = &dhd_wifi_platdata->adapters[i]; - - DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); - DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", - adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); - DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", - adapter->bus_type, adapter->bus_num, adapter->slot_num)); - - do { - sema_init(&dhd_chipup_sem, 0); - err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); - if (err) { - DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n", - __FUNCTION__, err)); - return err; - } - err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); - if (err) { - /* WL_REG_ON state unknown, Power off forcely */ - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - continue; - } else { - wifi_platform_bus_enumerate(adapter, TRUE); - err = 0; - } - - if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { - dhd_bus_unreg_sdio_notify(); - chip_up = TRUE; - break; - } - - DHD_ERROR(("failed to power up %s, %d retry left\n", adapter->name, retry)); - dhd_bus_unreg_sdio_notify(); - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } while (retry--); - - if (!chip_up) { - DHD_ERROR(("failed to power up %s, max retry reached**\n", adapter->name)); - return -ENODEV; - } - - } - - err = dhd_bus_register(); - - if (err) { - DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); - goto fail; - } - - - /* - * Wait till MMC sdio_register_driver callback called and made driver attach. - * It's needed to make sync up exit from dhd insmod and - * Kernel MMC sdio device callback registration - */ - err = down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); - if (err) { - DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__)); - dhd_bus_unregister(); - goto fail; - } - - return err; - -fail: - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } -#else - - /* x86 bring-up PC needs no power-up operations */ - err = dhd_bus_register(); - -#endif - - return err; -} -#else /* BCMSDIO */ -static int dhd_wifi_platform_load_sdio(void) -{ - return 0; -} -#endif /* BCMSDIO */ - -static int dhd_wifi_platform_load_usb(void) -{ - return 0; -} - -static int dhd_wifi_platform_load() -{ - int err = 0; - - wl_android_init(); - - if ((err = dhd_wifi_platform_load_usb())) - goto end; - else if ((err = dhd_wifi_platform_load_sdio())) - goto end; - else - err = dhd_wifi_platform_load_pcie(); - -end: - if (err) - wl_android_exit(); - else - wl_android_post_init(); - - return err; -} diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c deleted file mode 100644 index 753cb64236d6..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Expose some of the kernel scheduler routines - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux_sched.c 457570 2014-02-23 13:54:46Z $ - */ -#include -#include -#include -#include -#include - -int setScheduler(struct task_struct *p, int policy, struct sched_param *param) -{ - int rc = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - rc = sched_setscheduler(p, policy, param); -#endif /* LinuxVer */ - return rc; -} - -int get_scheduler_policy(struct task_struct *p) -{ - int rc = SCHED_NORMAL; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - rc = p->policy; -#endif /* LinuxVer */ - return rc; -} diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd/dhd_linux_wq.c deleted file mode 100644 index 8b86bc6122c8..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_linux_wq.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Generic work queue framework - * Generic interface to handle dhd deferred work events - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux_wq.c 449578 2014-01-17 13:53:20Z $ - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct dhd_deferred_event_t { - u8 event; /* holds the event */ - void *event_data; /* Holds event specific data */ - event_handler_t event_handler; -}; -#define DEFRD_EVT_SIZE sizeof(struct dhd_deferred_event_t) - -struct dhd_deferred_wq { - struct work_struct deferred_work; /* should be the first member */ - - /* - * work events may occur simultaneously. - * Can hold upto 64 low priority events and 4 high priority events - */ -#define DHD_PRIO_WORK_FIFO_SIZE (4 * sizeof(struct dhd_deferred_event_t)) -#define DHD_WORK_FIFO_SIZE (64 * sizeof(struct dhd_deferred_event_t)) - struct kfifo *prio_fifo; - struct kfifo *work_fifo; - u8 *prio_fifo_buf; - u8 *work_fifo_buf; - spinlock_t work_lock; - void *dhd_info; /* review: does it require */ -}; - -static inline struct kfifo* -dhd_kfifo_init(u8 *buf, int size, spinlock_t *lock) -{ - struct kfifo *fifo; - gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) - fifo = kfifo_init(buf, size, flags, lock); -#else - fifo = (struct kfifo *)kzalloc(sizeof(struct kfifo), flags); - if (!fifo) { - return NULL; - } - kfifo_init(fifo, buf, size); -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ - return fifo; -} - -static inline void -dhd_kfifo_free(struct kfifo *fifo) -{ - kfifo_free(fifo); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) - /* FC11 releases the fifo memory */ - kfree(fifo); -#endif -} - -/* deferred work functions */ -static void dhd_deferred_work_handler(struct work_struct *data); - -void* -dhd_deferred_work_init(void *dhd_info) -{ - struct dhd_deferred_wq *work = NULL; - u8* buf; - unsigned long fifo_size = 0; - gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC; - - if (!dhd_info) { - DHD_ERROR(("%s: dhd info not initialized\n", __FUNCTION__)); - goto return_null; - } - - work = (struct dhd_deferred_wq *)kzalloc(sizeof(struct dhd_deferred_wq), - flags); - - if (!work) { - DHD_ERROR(("%s: work queue creation failed \n", __FUNCTION__)); - goto return_null; - } - - INIT_WORK((struct work_struct *)work, dhd_deferred_work_handler); - - /* initialize event fifo */ - spin_lock_init(&work->work_lock); - - /* allocate buffer to hold prio events */ - fifo_size = DHD_PRIO_WORK_FIFO_SIZE; - fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); - buf = (u8*)kzalloc(fifo_size, flags); - if (!buf) { - DHD_ERROR(("%s: prio work fifo allocation failed \n", __FUNCTION__)); - goto return_null; - } - - /* Initialize prio event fifo */ - work->prio_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); - if (!work->prio_fifo) { - kfree(buf); - goto return_null; - } - - /* allocate buffer to hold work events */ - fifo_size = DHD_WORK_FIFO_SIZE; - fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); - buf = (u8*)kzalloc(fifo_size, flags); - if (!buf) { - DHD_ERROR(("%s: work fifo allocation failed \n", __FUNCTION__)); - goto return_null; - } - - /* Initialize event fifo */ - work->work_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); - if (!work->work_fifo) { - kfree(buf); - goto return_null; - } - - work->dhd_info = dhd_info; - DHD_ERROR(("%s: work queue initialized \n", __FUNCTION__)); - return work; - -return_null: - - if (work) - dhd_deferred_work_deinit(work); - - return NULL; -} - -void -dhd_deferred_work_deinit(void *work) -{ - struct dhd_deferred_wq *deferred_work = work; - - - if (!deferred_work) { - DHD_ERROR(("%s: deferred work has been freed alread \n", __FUNCTION__)); - return; - } - - /* cancel the deferred work handling */ - cancel_work_sync((struct work_struct *)deferred_work); - - /* - * free work event fifo. - * kfifo_free frees locally allocated fifo buffer - */ - if (deferred_work->prio_fifo) - dhd_kfifo_free(deferred_work->prio_fifo); - - if (deferred_work->work_fifo) - dhd_kfifo_free(deferred_work->work_fifo); - - kfree(deferred_work); -} - -/* - * Prepares event to be queued - * Schedules the event - */ -int -dhd_deferred_schedule_work(void *workq, void *event_data, u8 event, - event_handler_t event_handler, u8 priority) -{ - struct dhd_deferred_wq *deferred_wq = (struct dhd_deferred_wq *) workq; - struct dhd_deferred_event_t deferred_event; - int status; - - if (!deferred_wq) { - DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); - ASSERT(0); - return DHD_WQ_STS_UNINITIALIZED; - } - - if (!event || (event >= DHD_MAX_WQ_EVENTS)) { - DHD_ERROR(("%s: Unknown event \n", __FUNCTION__)); - return DHD_WQ_STS_UNKNOWN_EVENT; - } - - /* - * default element size is 1, which can be changed - * using kfifo_esize(). Older kernel(FC11) doesn't support - * changing element size. For compatibility changing - * element size is not prefered - */ - ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); - ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); - - deferred_event.event = event; - deferred_event.event_data = event_data; - deferred_event.event_handler = event_handler; - - if (priority == DHD_WORK_PRIORITY_HIGH) { - status = kfifo_in_spinlocked(deferred_wq->prio_fifo, &deferred_event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - } else { - status = kfifo_in_spinlocked(deferred_wq->work_fifo, &deferred_event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - } - - if (!status) { - return DHD_WQ_STS_SCHED_FAILED; - } - schedule_work((struct work_struct *)deferred_wq); - return DHD_WQ_STS_OK; -} - -static int -dhd_get_scheduled_work(struct dhd_deferred_wq *deferred_wq, struct dhd_deferred_event_t *event) -{ - int status = 0; - - if (!deferred_wq) { - DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); - return DHD_WQ_STS_UNINITIALIZED; - } - - /* - * default element size is 1 byte, which can be changed - * using kfifo_esize(). Older kernel(FC11) doesn't support - * changing element size. For compatibility changing - * element size is not prefered - */ - ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); - ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); - - /* first read priorit event fifo */ - status = kfifo_out_spinlocked(deferred_wq->prio_fifo, event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - - if (!status) { - /* priority fifo is empty. Now read low prio work fifo */ - status = kfifo_out_spinlocked(deferred_wq->work_fifo, event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - } - - return status; -} - -/* - * Called when work is scheduled - */ -static void -dhd_deferred_work_handler(struct work_struct *work) -{ - struct dhd_deferred_wq *deferred_work = (struct dhd_deferred_wq *)work; - struct dhd_deferred_event_t work_event; - int status; - - if (!deferred_work) { - DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); - return; - } - - do { - status = dhd_get_scheduled_work(deferred_work, &work_event); - DHD_TRACE(("%s: event to handle %d \n", __FUNCTION__, status)); - if (!status) { - DHD_TRACE(("%s: No event to handle %d \n", __FUNCTION__, status)); - break; - } - - if (work_event.event > DHD_MAX_WQ_EVENTS) { - DHD_TRACE(("%s: Unknown event %d \n", __FUNCTION__, work_event.event)); - break; - } - - if (work_event.event_handler) { - work_event.event_handler(deferred_work->dhd_info, - work_event.event_data, work_event.event); - } else { - DHD_ERROR(("%s: event not defined %d\n", __FUNCTION__, work_event.event)); - } - } while (1); - return; -} diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd/dhd_linux_wq.h deleted file mode 100644 index 7e06ac8cea92..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_linux_wq.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Generic work queue framework - * Generic interface to handle dhd deferred work events - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux_wq.h 513049 2014-11-05 09:36:42Z $ - */ -#ifndef _dhd_linux_wq_h_ -#define _dhd_linux_wq_h_ -/* - * Work event definitions - */ -enum _wq_event { - DHD_WQ_WORK_IF_ADD = 1, - DHD_WQ_WORK_IF_DEL, - DHD_WQ_WORK_SET_MAC, - DHD_WQ_WORK_SET_MCAST_LIST, - DHD_WQ_WORK_IPV6_NDO, - DHD_WQ_WORK_HANG_MSG, - DHD_WQ_WORK_SOC_RAM_DUMP, - - DHD_MAX_WQ_EVENTS -}; - -/* - * Work event priority - */ -#define DHD_WORK_PRIORITY_LOW 0 -#define DHD_WORK_PRIORITY_HIGH 1 - -/* - * Error definitions - */ -#define DHD_WQ_STS_OK 0 -#define DHD_WQ_STS_FAILED -1 /* General failure */ -#define DHD_WQ_STS_UNINITIALIZED -2 -#define DHD_WQ_STS_SCHED_FAILED -3 -#define DHD_WQ_STS_UNKNOWN_EVENT -4 - -typedef void (*event_handler_t)(void *handle, void *event_data, u8 event); - -void *dhd_deferred_work_init(void *dhd); -void dhd_deferred_work_deinit(void *workq); -int dhd_deferred_schedule_work(void *workq, void *event_data, u8 event, - event_handler_t evt_handler, u8 priority); -#endif /* _dhd_linux_wq_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_msgbuf.c b/drivers/net/wireless/bcmdhd/dhd_msgbuf.c deleted file mode 100644 index bc7222eb276b..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_msgbuf.c +++ /dev/null @@ -1,5046 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_msgbuf.c 676009 2016-12-20 02:54:41Z $ - */ -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - - -#include - -#include -#include -#include -#include - -/* - * PCIE D2H DMA Complete Sync Modes - * - * Firmware may interrupt the host, prior to the D2H Mem2Mem DMA completes into - * Host system memory. A WAR using one of 3 approaches is needed: - * 1. Dongle places ia modulo-253 seqnum in last word of each D2H message - * 2. XOR Checksum, with epoch# in each work item. Dongle builds an XOR checksum - * writes in the last word of each work item. Each work item has a seqnum - * number = sequence num % 253. - * 3. Read Barrier: Dongle does a host memory read access prior to posting an - * interrupt. - * Host does not participate with option #3, other than reserving a host system - * memory location for the dongle to read. - */ -#define PCIE_D2H_SYNC -#define PCIE_D2H_SYNC_WAIT_TRIES (512UL) -#define PCIE_D2H_SYNC_NUM_OF_STEPS (3UL) -#define PCIE_D2H_SYNC_DELAY (50UL) /* in terms of usecs */ - -#if !defined(CONFIG_ARCH_MSM8994) -#define PCIE_D2H_SYNC_BZERO /* bzero a message before updating the RD offset */ -#endif - -#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ -#define IOCTL_HDR_LEN 12 - -#define DEFAULT_RX_BUFFERS_TO_POST 256 -#define RXBUFPOST_THRESHOLD 32 -#define RX_BUF_BURST 16 - -#define DHD_STOP_QUEUE_THRESHOLD 200 -#define DHD_START_QUEUE_THRESHOLD 100 - -#define MODX(x, n) ((x) & ((n) -1)) -#define align(x, n) (MODX(x, n) ? ((x) - MODX(x, n) + (n)) : ((x) - MODX(x, n))) -#define RX_DMA_OFFSET 8 -#define IOCT_RETBUF_SIZE (RX_DMA_OFFSET + WLC_IOCTL_MAXLEN) - -/* flags for ioctl pending status */ -#define MSGBUF_IOCTL_ACK_PENDING (1<<0) -#define MSGBUF_IOCTL_RESP_PENDING (1<<1) - -#define DMA_D2H_SCRATCH_BUF_LEN 8 -#define DMA_ALIGN_LEN 4 -#define DMA_XFER_LEN_LIMIT 0x400000 - -#define DHD_FLOWRING_IOCTL_BUFPOST_PKTSZ 8192 - -#define DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D 1 -#define DHD_FLOWRING_MAX_EVENTBUF_POST 8 -#define DHD_FLOWRING_MAX_IOCTLRESPBUF_POST 8 - -#define DHD_PROT_FUNCS 22 - -typedef struct dhd_mem_map { - void *va; - dmaaddr_t pa; - void *dmah; -} dhd_mem_map_t; - -typedef struct dhd_dmaxfer { - dhd_mem_map_t srcmem; - dhd_mem_map_t destmem; - uint32 len; - uint32 srcdelay; - uint32 destdelay; -} dhd_dmaxfer_t; - -#define TXP_FLUSH_NITEMS -#define TXP_FLUSH_MAX_ITEMS_FLUSH_CNT 48 - -typedef struct msgbuf_ring { - bool inited; - uint16 idx; - uchar name[24]; - dhd_mem_map_t ring_base; -#ifdef TXP_FLUSH_NITEMS - void* start_addr; - uint16 pend_items_count; -#endif /* TXP_FLUSH_NITEMS */ - ring_mem_t *ringmem; - ring_state_t *ringstate; -#if defined(PCIE_D2H_SYNC) - uint32 seqnum; -#endif /* PCIE_D2H_SYNC */ -} msgbuf_ring_t; - -#if defined(PCIE_D2H_SYNC) -/* Custom callback attached based upon D2H DMA Sync mode used in dongle. */ -typedef uint8 (* d2h_sync_cb_t)(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen); -#endif /* PCIE_D2H_SYNC */ - -typedef struct dhd_prot { - osl_t *osh; /* OSL handle */ - uint32 reqid; - uint32 lastcmd; - uint32 pending; - uint16 rxbufpost; - uint16 max_rxbufpost; - uint16 max_eventbufpost; - uint16 max_ioctlrespbufpost; - uint16 cur_event_bufs_posted; - uint16 cur_ioctlresp_bufs_posted; - uint16 active_tx_count; - uint16 max_tx_count; - uint16 txp_threshold; - /* Ring info */ - msgbuf_ring_t *h2dring_txp_subn; - msgbuf_ring_t *h2dring_rxp_subn; - msgbuf_ring_t *h2dring_ctrl_subn; /* Cbuf handle for H2D ctrl ring */ - msgbuf_ring_t *d2hring_tx_cpln; - msgbuf_ring_t *d2hring_rx_cpln; - msgbuf_ring_t *d2hring_ctrl_cpln; /* Cbuf handle for D2H ctrl ring */ - uint32 rx_dataoffset; - dhd_mem_map_t retbuf; - dhd_mem_map_t ioctbuf; /* For holding ioct request buf */ - dhd_mb_ring_t mb_ring_fn; - - uint32 d2h_dma_scratch_buf_len; /* For holding ioct request buf */ - dhd_mem_map_t d2h_dma_scratch_buf; /* For holding ioct request buf */ - - uint32 h2d_dma_writeindx_buf_len; /* For holding dma ringupd buf - submission write */ - dhd_mem_map_t h2d_dma_writeindx_buf; /* For holding dma ringupd buf - submission write */ - - uint32 h2d_dma_readindx_buf_len; /* For holding dma ringupd buf - submission read */ - dhd_mem_map_t h2d_dma_readindx_buf; /* For holding dma ringupd buf - submission read */ - - uint32 d2h_dma_writeindx_buf_len; /* For holding dma ringupd buf - completion write */ - dhd_mem_map_t d2h_dma_writeindx_buf; /* For holding dma ringupd buf - completion write */ - - uint32 d2h_dma_readindx_buf_len; /* For holding dma ringupd buf - completion read */ - dhd_mem_map_t d2h_dma_readindx_buf; /* For holding dma ringupd buf - completion read */ - -#if defined(PCIE_D2H_SYNC) - d2h_sync_cb_t d2h_sync_cb; /* Sync on D2H DMA done: SEQNUM or XORCSUM */ - ulong d2h_sync_wait_max; /* max number of wait loops to receive one msg */ - ulong d2h_sync_wait_tot; /* total wait loops */ -#endif /* PCIE_D2H_SYNC */ - dhd_dmaxfer_t dmaxfer; - bool dmaxfer_in_progress; - - uint16 ioctl_seq_no; - uint16 data_seq_no; - uint16 ioctl_trans_id; - void *pktid_map_handle; - uint16 rx_metadata_offset; - uint16 tx_metadata_offset; - uint16 rx_cpln_early_upd_idx; - struct mutex ioctl_mutex; /* Make IOCTL singleton in Prot Layer */ -} dhd_prot_t; - -static int dhdmsgbuf_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, - void *buf, uint len, uint8 action); -static int dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, - void *buf, uint len, uint8 action); -static int dhdmsgbuf_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len, void* buf, void* retbuf); - -static int dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd); -static int dhd_prot_rxbufpost(dhd_pub_t *dhd, uint16 count); -static void dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint16 rxcnt); -static void dhd_prot_rxcmplt_process(dhd_pub_t *dhd, void* buf, uint16 msglen); -static void dhd_prot_event_process(dhd_pub_t *dhd, void* buf, uint16 len); -static int dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len); -static int dhd_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len); - -static void dhd_prot_noop(dhd_pub_t *dhd, void * buf, uint16 msglen); -static void dhd_prot_txstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen); -static void dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void * buf, uint16 msglen); -static void dhd_prot_ioctack_process(dhd_pub_t *dhd, void * buf, uint16 msglen); -static void dhd_prot_ringstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen); -static void dhd_prot_genstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen); -static void* dhd_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, - uint16 msglen, uint16 *alloced); -static int dhd_fillup_ioct_reqst_ptrbased(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, - int ifidx); -#ifdef DHD_FW_COREDUMP -extern int dhdpcie_mem_dump(dhd_bus_t *bus); -#endif /* DHD_FW_COREDUMP */ -static INLINE void dhd_prot_packet_free(dhd_pub_t *dhd, uint32 pktid, uint8 buf_type); -static INLINE void *dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid, uint8 buf_type); -static void dmaxfer_free_dmaaddr(dhd_pub_t *dhd, dhd_dmaxfer_t *dma); -static int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, uint srcdelay, - uint destdelay, dhd_dmaxfer_t *dma); -static void dhdmsgbuf_dmaxfer_compare(dhd_pub_t *dhd, void *buf, uint16 msglen); -static void dhd_prot_process_flow_ring_create_response(dhd_pub_t *dhd, void* buf, uint16 msglen); -static void dhd_prot_process_flow_ring_delete_response(dhd_pub_t *dhd, void* buf, uint16 msglen); -static void dhd_prot_process_flow_ring_flush_response(dhd_pub_t *dhd, void* buf, uint16 msglen); - - - - -#ifdef DHD_RX_CHAINING -#define PKT_CTF_CHAINABLE(dhd, ifidx, evh, prio, h_sa, h_da, h_prio) \ - (!ETHER_ISNULLDEST(((struct ether_header *)(evh))->ether_dhost) && \ - !ETHER_ISMULTI(((struct ether_header *)(evh))->ether_dhost) && \ - !eacmp((h_da), ((struct ether_header *)(evh))->ether_dhost) && \ - !eacmp((h_sa), ((struct ether_header *)(evh))->ether_shost) && \ - ((h_prio) == (prio)) && (dhd_ctf_hotbrc_check((dhd), (evh), (ifidx))) && \ - ((((struct ether_header *)(evh))->ether_type == HTON16(ETHER_TYPE_IP)) || \ - (((struct ether_header *)(evh))->ether_type == HTON16(ETHER_TYPE_IPV6)))) - -static INLINE void BCMFASTPATH dhd_rxchain_reset(rxchain_info_t *rxchain); -static void BCMFASTPATH dhd_rxchain_frame(dhd_pub_t *dhd, void *pkt, uint ifidx); -static void BCMFASTPATH dhd_rxchain_commit(dhd_pub_t *dhd); - -#define DHD_PKT_CTF_MAX_CHAIN_LEN 64 -#endif /* DHD_RX_CHAINING */ - -static uint16 dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, bool event_buf, uint32 max_to_post); -static int dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd_pub_t *pub); -static int dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *pub); - -static void dhd_prot_ring_detach(dhd_pub_t *dhd, msgbuf_ring_t * ring); -static void dhd_ring_init(dhd_pub_t *dhd, msgbuf_ring_t *ring); -static msgbuf_ring_t* prot_ring_attach(dhd_prot_t * prot, char* name, uint16 max_item, - uint16 len_item, uint16 ringid); -static void* prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced); -static void dhd_set_dmaed_index(dhd_pub_t *dhd, uint8 type, uint16 ringid, uint16 new_index); -static uint16 dhd_get_dmaed_index(dhd_pub_t *dhd, uint8 type, uint16 ringid); -static void prot_ring_write_complete(dhd_pub_t *dhd, msgbuf_ring_t * ring, void* p, uint16 len); -static void prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring); -static uint8* prot_get_src_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint16 *available_len); -static void prot_store_rxcpln_read_idx(dhd_pub_t *dhd, msgbuf_ring_t *ring); -static void prot_early_upd_rxcpln_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring); - -typedef void (*dhd_msgbuf_func_t)(dhd_pub_t *dhd, void * buf, uint16 msglen); -static dhd_msgbuf_func_t table_lookup[DHD_PROT_FUNCS] = { - dhd_prot_noop, /* 0 is invalid message type */ - dhd_prot_genstatus_process, /* MSG_TYPE_GEN_STATUS */ - dhd_prot_ringstatus_process, /* MSG_TYPE_RING_STATUS */ - NULL, - dhd_prot_process_flow_ring_create_response, /* MSG_TYPE_FLOW_RING_CREATE_CMPLT */ - NULL, - dhd_prot_process_flow_ring_delete_response, /* MSG_TYPE_FLOW_RING_DELETE_CMPLT */ - NULL, - dhd_prot_process_flow_ring_flush_response, /* MSG_TYPE_FLOW_RING_FLUSH_CMPLT */ - NULL, - dhd_prot_ioctack_process, /* MSG_TYPE_IOCTLPTR_REQ_ACK */ - NULL, - dhd_prot_ioctcmplt_process, /* MSG_TYPE_IOCTL_CMPLT */ - NULL, - dhd_prot_event_process, /* MSG_TYPE_WL_EVENT */ - NULL, - dhd_prot_txstatus_process, /* MSG_TYPE_TX_STATUS */ - NULL, - dhd_prot_rxcmplt_process, /* MSG_TYPE_RX_CMPLT */ - NULL, - dhdmsgbuf_dmaxfer_compare, /* MSG_TYPE_LPBK_DMAXFER_CMPLT */ - NULL, -}; - - -#if defined(PCIE_D2H_SYNC) - -/* - * D2H DMA to completion callback handlers. Based on the mode advertised by the - * dongle through the PCIE shared region, the appropriate callback will be - * registered in the proto layer to be invoked prior to precessing any message - * from a D2H DMA ring. If the dongle uses a read barrier or another mode that - * does not require host participation, then a noop callback handler will be - * bound that simply returns the msgtype. - */ -static void dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, msgbuf_ring_t *ring, - uint32 tries, uchar *msg, int msglen); -static uint8 dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen); -static uint8 dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen); -static uint8 dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen); -static void dhd_prot_d2h_sync_init(dhd_pub_t *dhd, dhd_prot_t * prot); - -/* Debug print a livelock avert by dropping a D2H message */ -static void -dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 tries, - uchar *msg, int msglen) -{ - uint32 seqnum = ring->seqnum; - DHD_ERROR(("LIVELOCK DHD<%p> name<%s> seqnum<%u:%u> tries<%u> max<%lu> tot<%lu>" - "msg<%p>\n", - dhd, ring->name, seqnum, seqnum% D2H_EPOCH_MODULO, tries, - dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot, - msg)); - prhex("D2H MsgBuf Failure", (uchar *)msg, msglen); - -#if defined(SUPPORT_LINKDOWN_RECOVERY) && defined(CONFIG_ARCH_MSM) - dhd->bus->islinkdown = TRUE; - dhd_os_check_hang(dhd, 0, -ETIMEDOUT); -#endif /* SUPPORT_LINKDOWN_RECOVERY && CONFIG_ARCH_MSM */ - -} - -/* Sync on a D2H DMA to complete using SEQNUM mode */ -static uint8 BCMFASTPATH -dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen) -{ - uint32 tries; - uint32 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO; - int num_words = msglen / sizeof(uint32); /* num of 32bit words */ - volatile uint32 *marker = (uint32 *)msg + (num_words - 1); /* last word */ - dhd_prot_t *prot = dhd->prot; - uint32 step = 0; - uint32 delay = PCIE_D2H_SYNC_DELAY; - uint32 total_tries = 0; - - ASSERT(msglen == RING_LEN_ITEMS(ring)); - - BCM_REFERENCE(delay); - - /* - * For retries we have to make some sort of stepper algorithm. - * We see that every time when the Dongle comes out of the D3 - * Cold state, the first D2H mem2mem DMA takes more time to - * complete, leading to livelock issues. - * - * Case 1 - Apart from Host CPU some other bus master is - * accessing the DDR port, probably page close to the ring - * so, PCIE does not get a change to update the memory. - * Solution - Increase the number of tries. - * - * Case 2 - The 50usec delay given by the Host CPU is not - * sufficient for the PCIe RC to start its work. - * In this case the breathing time of 50usec given by - * the Host CPU is not sufficient. - * Solution: Increase the delay in a stepper fashion. - * This is done to ensure that there are no - * unwanted extra delay introdcued in normal conditions. - */ - for (step = 1; step <= PCIE_D2H_SYNC_NUM_OF_STEPS; step++) { - for (tries = 1; tries <= PCIE_D2H_SYNC_WAIT_TRIES; tries++) { - uint32 msg_seqnum = *marker; - if (ltoh32(msg_seqnum) == ring_seqnum) { /* dma upto last word done */ - ring->seqnum++; /* next expected sequence number */ - goto dma_completed; - } - - total_tries = ((step-1) * PCIE_D2H_SYNC_WAIT_TRIES) + tries; - - if (total_tries > prot->d2h_sync_wait_max) - prot->d2h_sync_wait_max = total_tries; - - OSL_CACHE_INV(msg, msglen); /* invalidate and try again */ - OSL_CPU_RELAX(); /* CPU relax for msg_seqnum value to update */ -#if defined(CONFIG_ARCH_MSM8994) - /* For ARM there is no pause in cpu_relax, so add extra delay */ - OSL_DELAY(delay * step); -#endif /* defined(CONFIG_ARCH_MSM8994) */ - } /* for PCIE_D2H_SYNC_WAIT_TRIES */ - } /* for number of steps */ - - dhd_prot_d2h_sync_livelock(dhd, ring, total_tries, (uchar *)msg, msglen); - - ring->seqnum++; /* skip this message ... leak of a pktid */ - return 0; /* invalid msgtype 0 -> noop callback */ - -dma_completed: - - prot->d2h_sync_wait_tot += total_tries; - return msg->msg_type; -} - -/* Sync on a D2H DMA to complete using XORCSUM mode */ -static uint8 BCMFASTPATH -dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen) -{ - uint32 tries; - uint32 prot_checksum = 0; /* computed checksum */ - int num_words = msglen / sizeof(uint32); /* num of 32bit words */ - uint8 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO; - dhd_prot_t *prot = dhd->prot; - uint32 step = 0; - uint32 delay = PCIE_D2H_SYNC_DELAY; - uint32 total_tries = 0; - - ASSERT(msglen == RING_LEN_ITEMS(ring)); - - BCM_REFERENCE(delay); - - /* - * For retries we have to make some sort of stepper algorithm. - * We see that every time when the Dongle comes out of the D3 - * Cold state, the first D2H mem2mem DMA takes more time to - * complete, leading to livelock issues. - * - * Case 1 - Apart from Host CPU some other bus master is - * accessing the DDR port, probably page close to the ring - * so, PCIE does not get a change to update the memory. - * Solution - Increase the number of tries. - * - * Case 2 - The 50usec delay given by the Host CPU is not - * sufficient for the PCIe RC to start its work. - * In this case the breathing time of 50usec given by - * the Host CPU is not sufficient. - * Solution: Increase the delay in a stepper fashion. - * This is done to ensure that there are no - * unwanted extra delay introdcued in normal conditions. - */ - for (step = 1; step <= PCIE_D2H_SYNC_NUM_OF_STEPS; step++) { - for (tries = 1; tries <= PCIE_D2H_SYNC_WAIT_TRIES; tries++) { - prot_checksum = bcm_compute_xor32((volatile uint32 *)msg, num_words); - if (prot_checksum == 0U) { /* checksum is OK */ - if (msg->epoch == ring_seqnum) { - ring->seqnum++; /* next expected sequence number */ - goto dma_completed; - } - } - - total_tries = ((step-1) * PCIE_D2H_SYNC_WAIT_TRIES) + tries; - - if (total_tries > prot->d2h_sync_wait_max) - prot->d2h_sync_wait_max = total_tries; - - OSL_CACHE_INV(msg, msglen); /* invalidate and try again */ - OSL_CPU_RELAX(); /* CPU relax for msg_seqnum value to update */ -#if defined(CONFIG_ARCH_MSM8994) - /* For ARM there is no pause in cpu_relax, so add extra delay */ - OSL_DELAY(delay * step); -#endif /* defined(CONFIG_ARCH_MSM8994) */ - } /* for PCIE_D2H_SYNC_WAIT_TRIES */ - } /* for number of steps */ - - dhd_prot_d2h_sync_livelock(dhd, ring, total_tries, (uchar *)msg, msglen); - - ring->seqnum++; /* skip this message ... leak of a pktid */ - return 0; /* invalid msgtype 0 -> noop callback */ - -dma_completed: - - prot->d2h_sync_wait_tot += total_tries; - return msg->msg_type; -} - -/* Do not sync on a D2H DMA */ -static uint8 BCMFASTPATH -dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen) -{ - return msg->msg_type; -} - -/* Initialize the D2H DMA Sync mode, per D2H ring seqnum and dhd stats */ -static void -dhd_prot_d2h_sync_init(dhd_pub_t *dhd, dhd_prot_t * prot) -{ - prot->d2h_sync_wait_max = 0UL; - prot->d2h_sync_wait_tot = 0UL; - - prot->d2hring_tx_cpln->seqnum = D2H_EPOCH_INIT_VAL; - prot->d2hring_rx_cpln->seqnum = D2H_EPOCH_INIT_VAL; - prot->d2hring_ctrl_cpln->seqnum = D2H_EPOCH_INIT_VAL; - - if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM) - prot->d2h_sync_cb = dhd_prot_d2h_sync_seqnum; - else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM) - prot->d2h_sync_cb = dhd_prot_d2h_sync_xorcsum; - else - prot->d2h_sync_cb = dhd_prot_d2h_sync_none; -} - -#endif /* PCIE_D2H_SYNC */ - -/* - * +---------------------------------------------------------------------------+ - * PktId Map: Provides a native packet pointer to unique 32bit PktId mapping. - * The packet id map, also includes storage for some packet parameters that - * may be saved. A native packet pointer along with the parameters may be saved - * and a unique 32bit pkt id will be returned. Later, the saved packet pointer - * and the metadata may be retrieved using the previously allocated packet id. - * +---------------------------------------------------------------------------+ - */ - -/* - * PktId (Locker) #0 is never allocated and is considered invalid. - * - * On request for a pktid, a value DHD_PKTID_INVALID must be treated as a - * depleted pktid pool and must not be used by the caller. - * - * Likewise, a caller must never free a pktid of value DHD_PKTID_INVALID. - */ -#define DHD_PKTID_INVALID (0U) -#define DHD_IOCTL_REQ_PKTID 0xFFFE - - -#define MAX_PKTID_ITEMS (8192) /* Maximum number of pktids supported */ - -/* - * DHD_PKTID_AUDIT_ENABLED: Audit of PktIds in DHD for duplicate alloc and frees - * - * DHD_PKTID_AUDIT_MAP: Audit the LIFO or FIFO PktIdMap allocator - * DHD_PKTID_AUDIT_RING: Audit the pktid during producer/consumer ring operation - * - * CAUTION: When DHD_PKTID_AUDIT_ENABLED is defined, - * either DHD_PKTID_AUDIT_MAP or DHD_PKTID_AUDIT_RING may be selected. - */ - -/* Disable Host side Pktid Audit, enabling this makes the mem corruption - * problem disappear - */ -/* #define DHD_PKTID_AUDIT_ENABLED */ - -#if defined(DHD_PKTID_AUDIT_ENABLED) - -/* Audit the pktidmap allocator */ -/* #define DHD_PKTID_AUDIT_MAP */ - -/* Audit the pktid during production/consumption of workitems */ -#define DHD_PKTID_AUDIT_RING - -#if defined(DHD_PKTID_AUDIT_MAP) && defined(DHD_PKTID_AUDIT_RING) -#error "May only enabled audit of MAP or RING, at a time." -#endif /* DHD_PKTID_AUDIT_MAP && DHD_PKTID_AUDIT_RING */ - -#define DHD_DUPLICATE_ALLOC 1 -#define DHD_DUPLICATE_FREE 2 -#define DHD_TEST_IS_ALLOC 3 -#define DHD_TEST_IS_FREE 4 - -#define USE_DHD_PKTID_AUDIT_LOCK 1 - -#ifdef USE_DHD_PKTID_AUDIT_LOCK -#define DHD_PKTID_AUDIT_LOCK_INIT(osh) dhd_os_spin_lock_init(osh) -#define DHD_PKTID_AUDIT_LOCK_DEINIT(osh, lock) dhd_os_spin_lock_deinit(osh, lock) -#define DHD_PKTID_AUDIT_LOCK(lock) dhd_os_spin_lock(lock) -#define DHD_PKTID_AUDIT_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, flags) - -#else - -#define DHD_PKTID_AUDIT_LOCK_INIT(osh) (void *)(1) -#define DHD_PKTID_AUDIT_LOCK_DEINIT(osh, lock) do { /* noop */ } while (0) -#define DHD_PKTID_AUDIT_LOCK(lock) 0 -#define DHD_PKTID_AUDIT_UNLOCK(lock, flags) do { /* noop */ } while (0) - -#endif /* !USE_DHD_PKTID_AUDIT_LOCK */ - -#endif /* DHD_PKTID_AUDIT_ENABLED */ - -#if defined(DHD_PKTID_AUDIT_ENABLED) -/* - * Going back to 1 from 2, we are any way using LIFO method now. - * Also note that if this is 2 then our times would 2 * 8192 + 1 - * But the bit map is only for 16K. Increasing the bitmap size for - * more than 16K failed. So doing this change to fit in into the - * bit map size. - */ -#define DHD_PKTIDMAP_FIFO 1 - -#else /* DHD_PKTID_AUDIT_ENABLED */ - -/* - * Uses a FIFO dll with Nx more pktids instead of a LIFO stack. - * If you wish to enable pktidaudit in firmware with FIFO PktId allocator, then - * the total number of PktIds managed by the pktidaudit must be multiplied by - * this DHD_PKTIDMAP_FIFO factor. - */ -#define DHD_PKTIDMAP_FIFO 4 - -#endif /* DHD_PKTID_AUDIT_ENABLED */ - -typedef void * dhd_pktid_map_handle_t; /* opaque handle to a pktid map */ - -/* Construct a packet id mapping table, returning an opaque map handle */ -static dhd_pktid_map_handle_t *dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items); - -/* Destroy a packet id mapping table, freeing all packets active in the table */ -static void dhd_pktid_map_fini(dhd_pktid_map_handle_t *map); - -/* Determine number of pktids that are available */ -static INLINE uint32 dhd_pktid_map_avail_cnt(dhd_pktid_map_handle_t *handle); - -/* Allocate a unique pktid against which a pkt and some metadata is saved */ -static INLINE uint32 dhd_pktid_map_reserve(dhd_pktid_map_handle_t *handle, - void *pkt); -static INLINE void dhd_pktid_map_save(dhd_pktid_map_handle_t *handle, void *pkt, - uint32 nkey, dmaaddr_t physaddr, uint32 len, uint8 dma, - uint8 buf_type); -static uint32 dhd_pktid_map_alloc(dhd_pktid_map_handle_t *map, void *pkt, - dmaaddr_t physaddr, uint32 len, uint8 dma, - uint8 buf_type); -/* Return an allocated pktid, retrieving previously saved pkt and metadata */ -static void *dhd_pktid_map_free(dhd_pktid_map_handle_t *map, uint32 id, - dmaaddr_t *physaddr, uint32 *len, - uint8 buf_type); - -#ifdef USE_DHD_PKTID_LOCK -#define DHD_PKTID_LOCK_INIT(osh) dhd_os_spin_lock_init(osh) -#define DHD_PKTID_LOCK_DEINIT(osh, lock) dhd_os_spin_lock_deinit(osh, lock) -#define DHD_PKTID_LOCK(lock) dhd_os_spin_lock(lock) -#define DHD_PKTID_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, flags) -#else -#define DHD_PKTID_LOCK_INIT(osh) (void *)(1) -#define DHD_PKTID_LOCK_DEINIT(osh, lock) do { \ - BCM_REFERENCE(osh); \ - BCM_REFERENCE(lock); \ - } while (0) -#define DHD_PKTID_LOCK(lock) 0 -#define DHD_PKTID_UNLOCK(lock, flags) do { \ - BCM_REFERENCE(lock); \ - BCM_REFERENCE(flags); \ - } while (0) -#endif /* !USE_DHD_PKTID_LOCK */ - -/* Packet metadata saved in packet id mapper */ - -typedef enum pkt_buf_type { - BUFF_TYPE_DATA_TX = 0, - BUFF_TYPE_DATA_RX, - BUFF_TYPE_IOCTL_RX, - BUFF_TYPE_EVENT_RX, - BUFF_TYPE_NO_CHECK -} pkt_buf_type_t; - -typedef struct dhd_pktid_item { -#if defined(DHD_PKTIDMAP_FIFO) - dll_t list_node; /* MUST BE FIRST field */ - uint32 nkey; -#endif - bool inuse; /* tag an item to be in use */ - uint8 dma; /* map direction: flush or invalidate */ - uint8 buf_type; - /* This filed is used to colour the - * buffer pointers held in the locker. - */ - uint16 len; /* length of mapped packet's buffer */ - void *pkt; /* opaque native pointer to a packet */ - dmaaddr_t physaddr; /* physical address of mapped packet's buffer */ -} dhd_pktid_item_t; - -typedef struct dhd_pktid_map { - dhd_pub_t *dhd; - uint32 items; /* total items in map */ - uint32 avail; /* total available items */ - uint32 failures; /* lockers unavailable count */ - /* Spinlock to protect dhd_pktid_map in process/tasklet context */ - void *pktid_lock; /* Used when USE_DHD_PKTID_LOCK is defined */ - -#if defined(DHD_PKTID_AUDIT_ENABLED) - void *pktid_audit_lock; - struct bcm_mwbmap *pktid_audit; /* multi word bitmap based audit */ -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - /* Unique PktId Allocator: FIFO dll, or LIFO:stack of keys */ -#if defined(DHD_PKTIDMAP_FIFO) - dll_t list_free; /* allocate from head, free to tail */ - dll_t list_inuse; -#else /* ! DHD_PKTIDMAP_FIFO */ - uint32 keys[MAX_PKTID_ITEMS + 1]; /* stack of unique pkt ids */ -#endif /* ! DHD_PKTIDMAP_FIFO */ - dhd_pktid_item_t lockers[0]; /* metadata storage */ -} dhd_pktid_map_t; - -#define DHD_PKTID_ITEM_SZ (sizeof(dhd_pktid_item_t)) - -#if defined(DHD_PKTIDMAP_FIFO) -/* A 4x pool of pktids are managed with FIFO allocation. */ -#define DHD_PKIDMAP_ITEMS(items) (items * DHD_PKTIDMAP_FIFO) -#define DHD_PKTID_MAP_SZ(items) (sizeof(dhd_pktid_map_t) + \ - (DHD_PKTID_ITEM_SZ * ((DHD_PKTIDMAP_FIFO * (items)) + 1))) -#else /* ! DHD_PKTIDMAP_FIFO */ -#define DHD_PKIDMAP_ITEMS(items) (items) -#define DHD_PKTID_MAP_SZ(items) (sizeof(dhd_pktid_map_t) + \ - (DHD_PKTID_ITEM_SZ * ((items) + 1))) -#endif /* ! DHD_PKTIDMAP_FIFO */ - -#define NATIVE_TO_PKTID_INIT(dhd, items) dhd_pktid_map_init((dhd), (items)) -#define NATIVE_TO_PKTID_FINI(map) dhd_pktid_map_fini(map) -#define NATIVE_TO_PKTID_CLEAR(map) dhd_pktid_map_clear(map) - -#define NATIVE_TO_PKTID_RSV(map, pkt) dhd_pktid_map_reserve((map), (pkt)) -#define NATIVE_TO_PKTID_SAVE(map, pkt, nkey, pa, len, dma, buf_type) \ - dhd_pktid_map_save((map), (void *)(pkt), (nkey), (pa), (uint32)(len), \ - (uint8)dma, (uint8)buf_type) -#define NATIVE_TO_PKTID(map, pkt, pa, len, dma, buf_type) \ - dhd_pktid_map_alloc((map), (void *)(pkt), (pa), (uint32)(len), \ - (uint8)dma, (uint8)buf_type) -#define PKTID_TO_NATIVE(map, pktid, pa, len, buf_type) \ - dhd_pktid_map_free((map), (uint32)(pktid), \ - (dmaaddr_t *)&(pa), (uint32 *)&(len), (uint8)buf_type) - -#define PKTID_AVAIL(map) dhd_pktid_map_avail_cnt(map) - -#if defined(DHD_PKTID_AUDIT_ENABLED) - -static int dhd_pktid_audit(dhd_pktid_map_t *pktid_map, uint32 pktid, - const int test_for, const char *errmsg); - -static int -dhd_pktid_audit(dhd_pktid_map_t *pktid_map, uint32 pktid, const int test_for, - const char *errmsg) -{ -#define DHD_PKT_AUDIT_STR "ERROR: %16s Host PktId Audit: " - -#if defined(DHD_PKTIDMAP_FIFO) - const uint32 max_pktid_items = (MAX_PKTID_ITEMS * DHD_PKTIDMAP_FIFO); -#else - const uint32 max_pktid_items = (MAX_PKTID_ITEMS); -#endif /* DHD_PKTIDMAP_FIFO */ - struct bcm_mwbmap *handle; - u32 flags; - - if (pktid_map == (dhd_pktid_map_t *)NULL) { - DHD_ERROR((DHD_PKT_AUDIT_STR "Pkt id map NULL\n", errmsg)); - return BCME_OK; - } - - flags = DHD_PKTID_AUDIT_LOCK(pktid_map->pktid_audit_lock); - - handle = pktid_map->pktid_audit; - if (handle == (struct bcm_mwbmap *)NULL) { - DHD_ERROR((DHD_PKT_AUDIT_STR "Handle NULL\n", errmsg)); - DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); - return BCME_OK; - } - - if ((pktid == DHD_PKTID_INVALID) || (pktid > max_pktid_items)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> invalid\n", errmsg, pktid)); - /* lock is released in "error" */ - goto error; - } - - if (pktid == DHD_IOCTL_REQ_PKTID) { - DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); - return BCME_OK; - } - - switch (test_for) { - case DHD_DUPLICATE_ALLOC: - if (!bcm_mwbmap_isfree(handle, pktid)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> alloc duplicate\n", - errmsg, pktid)); - goto error; - } - bcm_mwbmap_force(handle, pktid); - break; - - case DHD_DUPLICATE_FREE: - if (bcm_mwbmap_isfree(handle, pktid)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> free duplicate\n", - errmsg, pktid)); - goto error; - } - bcm_mwbmap_free(handle, pktid); - break; - - case DHD_TEST_IS_ALLOC: - if (bcm_mwbmap_isfree(handle, pktid)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> is not allocated\n", - errmsg, pktid)); - goto error; - } - break; - - case DHD_TEST_IS_FREE: - if (!bcm_mwbmap_isfree(handle, pktid)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> is not free", - errmsg, pktid)); - goto error; - } - break; - - default: - goto error; - } - - DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); - return BCME_OK; - -error: - - DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); - /* May insert any trap mechanism here ! */ - ASSERT(0); - return BCME_ERROR; -} - -#define DHD_PKTID_AUDIT(map, pktid, test_for) \ - dhd_pktid_audit((dhd_pktid_map_t *)(map), (pktid), (test_for), __FUNCTION__) - -#endif /* DHD_PKTID_AUDIT_ENABLED */ - -/* - * +---------------------------------------------------------------------------+ - * Packet to Packet Id mapper using a paradigm. - * - * dhd_pktid_map manages a set of unique Packet Ids range[1..MAX_PKTID_ITEMS]. - * - * dhd_pktid_map_alloc() may be used to save some packet metadata, and a unique - * packet id is returned. This unique packet id may be used to retrieve the - * previously saved packet metadata, using dhd_pktid_map_free(). On invocation - * of dhd_pktid_map_free(), the unique packet id is essentially freed. A - * subsequent call to dhd_pktid_map_alloc() may reuse this packet id. - * - * Implementation Note: - * Convert this into a abstraction and place into bcmutils ! - * Locker abstraction should treat contents as opaque storage, and a - * callback should be registered to handle inuse lockers on destructor. - * - * +---------------------------------------------------------------------------+ - */ - -/* Allocate and initialize a mapper of num_items */ -static dhd_pktid_map_handle_t * -dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items) -{ - uint32 nkey; - dhd_pktid_map_t *map; - uint32 dhd_pktid_map_sz; - uint32 map_items; - - ASSERT((num_items >= 1) && (num_items <= MAX_PKTID_ITEMS)); - dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(num_items); - - if ((map = (dhd_pktid_map_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PKTID_MAP, - dhd_pktid_map_sz)) == NULL) { - DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", - __FUNCTION__, __LINE__, dhd_pktid_map_sz)); - goto error; - } - bzero(map, dhd_pktid_map_sz); - - /* Initialize the lock that protects this structure */ - map->pktid_lock = DHD_PKTID_LOCK_INIT(dhd->osh); - if (map->pktid_lock == NULL) { - DHD_ERROR(("%s:%d: Lock init failed \r\n", __FUNCTION__, __LINE__)); - goto error; - } - - map->dhd = dhd; - map->items = num_items; - map->avail = num_items; - - map_items = DHD_PKIDMAP_ITEMS(map->items); - -#if defined(DHD_PKTID_AUDIT_ENABLED) - /* Incarnate a hierarchical multiword bitmap for auditing pktid allocator */ - map->pktid_audit = bcm_mwbmap_init(dhd->osh, map_items + 1); - if (map->pktid_audit == (struct bcm_mwbmap *)NULL) { - DHD_ERROR(("%s:%d: pktid_audit init failed\r\n", __FUNCTION__, __LINE__)); - goto error; - } - - map->pktid_audit_lock = DHD_PKTID_AUDIT_LOCK_INIT(dhd->osh); -#endif /* DHD_PKTID_AUDIT_ENABLED */ - -#if defined(DHD_PKTIDMAP_FIFO) - - /* Initialize all dll */ - dll_init(&map->list_free); - dll_init(&map->list_inuse); - - /* Initialize and place all 4 x items in map's list_free */ - for (nkey = 0; nkey <= map_items; nkey++) { - dll_init(&map->lockers[nkey].list_node); - map->lockers[nkey].inuse = FALSE; - map->lockers[nkey].nkey = nkey; - map->lockers[nkey].pkt = NULL; /* bzero: redundant */ - map->lockers[nkey].len = 0; - /* Free at tail */ - dll_append(&map->list_free, &map->lockers[nkey].list_node); - } - - /* Reserve pktid #0, i.e. DHD_PKTID_INVALID to be inuse */ - map->lockers[DHD_PKTID_INVALID].inuse = TRUE; - dll_delete(&map->lockers[DHD_PKTID_INVALID].list_node); - dll_append(&map->list_inuse, &map->lockers[DHD_PKTID_INVALID].list_node); - -#else /* ! DHD_PKTIDMAP_FIFO */ - - map->lockers[DHD_PKTID_INVALID].inuse = TRUE; /* tag locker #0 as inuse */ - - for (nkey = 1; nkey <= map_items; nkey++) { /* locker #0 is reserved */ - map->keys[nkey] = nkey; /* populate with unique keys */ - map->lockers[nkey].inuse = FALSE; - map->lockers[nkey].pkt = NULL; /* bzero: redundant */ - map->lockers[nkey].len = 0; - } - -#endif /* ! DHD_PKTIDMAP_FIFO */ - - /* Reserve pktid #0, i.e. DHD_PKTID_INVALID to be inuse */ - map->lockers[DHD_PKTID_INVALID].inuse = TRUE; /* tag locker #0 as inuse */ - map->lockers[DHD_PKTID_INVALID].pkt = NULL; /* bzero: redundant */ - map->lockers[DHD_PKTID_INVALID].len = 0; - -#if defined(DHD_PKTID_AUDIT_ENABLED) - /* do not use dhd_pktid_audit() here, use bcm_mwbmap_force directly */ - bcm_mwbmap_force(map->pktid_audit, DHD_PKTID_INVALID); -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - return (dhd_pktid_map_handle_t *)map; /* opaque handle */ - -error: - - if (map) { -#if defined(DHD_PKTID_AUDIT_ENABLED) - if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { - bcm_mwbmap_fini(dhd->osh, map->pktid_audit); /* Destruct pktid_audit */ - map->pktid_audit = (struct bcm_mwbmap *)NULL; - if (map->pktid_audit_lock) { - DHD_PKTID_AUDIT_LOCK_DEINIT(dhd->osh, map->pktid_audit_lock); - } - } -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - if (map->pktid_lock) { - DHD_PKTID_LOCK_DEINIT(dhd->osh, map->pktid_lock); - } - - DHD_OS_PREFREE(map->dhd, map, dhd_pktid_map_sz); - } - - return (dhd_pktid_map_handle_t *)NULL; -} - -/* - * Retrieve all allocated keys and free all . - * Freeing implies: unmapping the buffers and freeing the native packet - * This could have been a callback registered with the pktid mapper. - */ -static void -dhd_pktid_map_fini(dhd_pktid_map_handle_t *handle) -{ - void *osh; - int nkey; - dhd_pktid_map_t *map; - uint32 dhd_pktid_map_sz; - dhd_pktid_item_t *locker; - uint32 map_items; - unsigned long flags; - - if (handle == NULL) - return; - - map = (dhd_pktid_map_t *)handle; - flags = DHD_PKTID_LOCK(map->pktid_lock); - - osh = map->dhd->osh; - dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(map->items); - - nkey = 1; /* skip reserved KEY #0, and start from 1 */ - locker = &map->lockers[nkey]; - - map_items = DHD_PKIDMAP_ITEMS(map->items); - - for (; nkey <= map_items; nkey++, locker++) { - if (locker->inuse == TRUE) { /* numbered key still in use */ - locker->inuse = FALSE; /* force open the locker */ - -#if defined(DHD_PKTID_AUDIT_ENABLED) - DHD_PKTID_AUDIT(map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */ -#endif /* DHD_PKTID_AUDIT_ENABLED */ - { - if (!PHYSADDRISZERO(locker->physaddr)) { - /* This could be a callback registered with dhd_pktid_map */ - DMA_UNMAP(osh, locker->physaddr, locker->len, - locker->dma, 0, 0); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - if (locker->buf_type == BUFF_TYPE_IOCTL_RX) { - PKTFREE_STATIC(osh, (ulong*)locker->pkt, FALSE); - } else { -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - PKTFREE(osh, (ulong*)locker->pkt, FALSE); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - } -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - } else { - DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__)); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - if (locker->buf_type == BUFF_TYPE_IOCTL_RX) { - PKTINVALIDATE_STATIC(osh, (ulong*)locker->pkt); - } else { -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - PKTFREE(osh, (ulong*)locker->pkt, FALSE); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - } -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - } - } - } -#if defined(DHD_PKTID_AUDIT_ENABLED) - else { - DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_FREE); - } -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - locker->pkt = NULL; /* clear saved pkt */ - locker->len = 0; - } - -#if defined(DHD_PKTID_AUDIT_ENABLED) - if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { - bcm_mwbmap_fini(osh, map->pktid_audit); /* Destruct pktid_audit */ - map->pktid_audit = (struct bcm_mwbmap *)NULL; - if (map->pktid_audit_lock) { - DHD_PKTID_AUDIT_LOCK_DEINIT(osh, map->pktid_audit_lock); - } - } -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - DHD_PKTID_UNLOCK(map->pktid_lock, flags); - DHD_PKTID_LOCK_DEINIT(map->dhd->osh, map->pktid_lock); - - DHD_OS_PREFREE(map->dhd, map, dhd_pktid_map_sz); -} - -static void -dhd_pktid_map_clear(dhd_pktid_map_handle_t *handle) -{ - void *osh; - int nkey; - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - uint32 map_items; - unsigned long flags; - - DHD_TRACE(("%s\n", __FUNCTION__)); - - if (handle == NULL) - return; - - map = (dhd_pktid_map_t *)handle; - flags = DHD_PKTID_LOCK(map->pktid_lock); - - osh = map->dhd->osh; - map->failures = 0; - - nkey = 1; /* skip reserved KEY #0, and start from 1 */ - locker = &map->lockers[nkey]; - - map_items = DHD_PKIDMAP_ITEMS(map->items); - for (; nkey <= map_items; nkey++, locker++) { - -#if !defined(DHD_PKTIDMAP_FIFO) - map->keys[nkey] = nkey; /* populate with unique keys */ -#endif /* ! DHD_PKTIDMAP_FIFO */ - - if (locker->inuse == TRUE) { /* numbered key still in use */ - locker->inuse = FALSE; /* force open the locker */ -#if defined(DHD_PKTID_AUDIT_ENABLED) - DHD_PKTID_AUDIT(map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */ -#endif /* DHD_PKTID_AUDIT_ENABLED */ - -#if defined(DHD_PKTIDMAP_FIFO) - ASSERT(locker->nkey == nkey); - dll_delete(&locker->list_node); - dll_append(&map->list_free, &locker->list_node); -#endif /* DHD_PKTIDMAP_FIFO */ - - DHD_TRACE(("%s free id%d\n", __FUNCTION__, nkey)); - if (!PHYSADDRISZERO(locker->physaddr)) { - DMA_UNMAP(osh, locker->physaddr, locker->len, - locker->dma, 0, 0); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - if (locker->buf_type == BUFF_TYPE_IOCTL_RX) { - PKTFREE_STATIC(osh, (ulong*)locker->pkt, FALSE); - } else { -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - PKTFREE(osh, (ulong*)locker->pkt, FALSE); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - } -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - } else { - DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__)); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - if (locker->buf_type == BUFF_TYPE_IOCTL_RX) { - PKTINVALIDATE_STATIC(osh, (ulong*)locker->pkt); - } else { -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - PKTFREE(osh, (ulong*)locker->pkt, FALSE); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - } -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - } - } -#if defined(DHD_PKTID_AUDIT_ENABLED) - else { - DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_FREE); - } -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - locker->pkt = NULL; /* clear saved pkt */ - locker->len = 0; - - } - map->avail = map->items; - - DHD_PKTID_UNLOCK(map->pktid_lock, flags); -} - -/* Get the pktid free count */ -static INLINE uint32 BCMFASTPATH -dhd_pktid_map_avail_cnt(dhd_pktid_map_handle_t *handle) -{ - dhd_pktid_map_t *map; - unsigned long flags; - uint32 avail; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - - flags = DHD_PKTID_LOCK(map->pktid_lock); - avail = map->avail; - DHD_PKTID_UNLOCK(map->pktid_lock, flags); - - return avail; -} - -/* - * Allocate locker, save pkt contents, and return the locker's numbered key. - * dhd_pktid_map_alloc() is not reentrant, and is the caller's responsibility. - * Caller must treat a returned value DHD_PKTID_INVALID as a failure case, - * implying a depleted pool of pktids. - */ -static INLINE uint32 -__dhd_pktid_map_reserve(dhd_pktid_map_handle_t *handle, void *pkt) -{ - uint32 nkey; - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - - if (map->avail <= 0) { /* no more pktids to allocate */ - map->failures++; - DHD_ERROR(("%s:%d: failed, no free keys\n", __FUNCTION__, __LINE__)); - return DHD_PKTID_INVALID; /* failed alloc request */ - } - ASSERT(map->avail <= map->items); - -#if defined(DHD_PKTIDMAP_FIFO) - - ASSERT(!dll_empty(&map->list_free)); - - /* Move list_free head item to inuse list, fetch key in head node */ - locker = (dhd_pktid_item_t *)dll_head_p(&map->list_free); - dll_delete(&locker->list_node); - nkey = locker->nkey; - dll_append(&map->list_inuse, &locker->list_node); - -#else /* ! DHD_PKTIDMAP_FIFO */ - - nkey = map->keys[map->avail]; /* fetch a free locker, pop stack */ - locker = &map->lockers[nkey]; /* save packet metadata in locker */ - -#endif /* ! DHD_PKTIDMAP_FIFO */ - - if (nkey > DHD_PKIDMAP_ITEMS(map->items)) { - DHD_ERROR(("%s:%d: invalid nkey (%d)\n", __FUNCTION__, __LINE__, nkey)); - return DHD_PKTID_INVALID; /* failed alloc request */ - } - map->avail--; - - locker->inuse = TRUE; /* reserve this locker */ - locker->pkt = pkt; /* pkt is saved, other params not yet saved. */ - locker->len = 0; - -#if defined(DHD_PKTID_AUDIT_MAP) - DHD_PKTID_AUDIT(map, nkey, DHD_DUPLICATE_ALLOC); /* Audit duplicate alloc */ -#endif /* DHD_PKTID_AUDIT_MAP */ - - ASSERT(nkey != DHD_PKTID_INVALID); - return nkey; /* return locker's numbered key */ -} - -/* Wrapper that takes the required lock when called directly */ -static INLINE uint32 -dhd_pktid_map_reserve(dhd_pktid_map_handle_t *handle, void *pkt) -{ - dhd_pktid_map_t *map; - unsigned long flags; - uint32 ret; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - flags = DHD_PKTID_LOCK(map->pktid_lock); - ret = __dhd_pktid_map_reserve(handle, pkt); - DHD_PKTID_UNLOCK(map->pktid_lock, flags); - - return ret; -} - -static INLINE void -__dhd_pktid_map_save(dhd_pktid_map_handle_t *handle, void *pkt, uint32 nkey, - dmaaddr_t physaddr, uint32 len, uint8 dma, uint8 buf_type) -{ - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - - ASSERT((nkey != DHD_PKTID_INVALID) && (nkey <= DHD_PKIDMAP_ITEMS(map->items))); - - locker = &map->lockers[nkey]; - ASSERT((locker->pkt == pkt) && (locker->inuse == TRUE)); - -#if defined(DHD_PKTID_AUDIT_MAP) - DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_ALLOC); /* apriori, reservation */ -#endif /* DHD_PKTID_AUDIT_MAP */ - - locker->dma = dma; /* store contents in locker */ - locker->buf_type = buf_type; - locker->physaddr = physaddr; - locker->len = (uint16)len; /* 16bit len */ -} - -/* Wrapper that takes the required lock when called directly */ -static INLINE void -dhd_pktid_map_save(dhd_pktid_map_handle_t *handle, void *pkt, uint32 nkey, - dmaaddr_t physaddr, uint32 len, uint8 dma, uint8 buf_type) -{ - dhd_pktid_map_t *map; - unsigned long flags; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - flags = DHD_PKTID_LOCK(map->pktid_lock); - __dhd_pktid_map_save(handle, pkt, nkey, physaddr, len, dma, buf_type); - DHD_PKTID_UNLOCK(map->pktid_lock, flags); -} - -static uint32 BCMFASTPATH -dhd_pktid_map_alloc(dhd_pktid_map_handle_t *handle, void *pkt, - dmaaddr_t physaddr, uint32 len, uint8 dma, uint8 buf_type) -{ - uint32 nkey; - unsigned long flags; - dhd_pktid_map_t *map; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - - flags = DHD_PKTID_LOCK(map->pktid_lock); - - nkey = __dhd_pktid_map_reserve(handle, pkt); - if (nkey != DHD_PKTID_INVALID) { - __dhd_pktid_map_save(handle, pkt, nkey, physaddr, len, - dma, buf_type); -#if defined(DHD_PKTID_AUDIT_MAP) - DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_ALLOC); /* apriori, reservation */ -#endif /* DHD_PKTID_AUDIT_MAP */ - } - - DHD_PKTID_UNLOCK(map->pktid_lock, flags); - - return nkey; -} - -/* - * Given a numbered key, return the locker contents. - * dhd_pktid_map_free() is not reentrant, and is the caller's responsibility. - * Caller may not free a pktid value DHD_PKTID_INVALID or an arbitrary pktid - * value. Only a previously allocated pktid may be freed. - */ -static void * BCMFASTPATH -dhd_pktid_map_free(dhd_pktid_map_handle_t *handle, uint32 nkey, - dmaaddr_t *physaddr, uint32 *len, uint8 buf_type) -{ - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - void * pkt; - unsigned long flags; - - ASSERT(handle != NULL); - - map = (dhd_pktid_map_t *)handle; - flags = DHD_PKTID_LOCK(map->pktid_lock); - -#ifdef CUSTOMER_HW5 - if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { - DHD_ERROR(("%s:%d: Error! freeing out of range pktid<%u>\n", - __FUNCTION__, __LINE__, nkey)); - ASSERT((nkey != DHD_PKTID_INVALID) && (nkey <= DHD_PKIDMAP_ITEMS(map->items))); - DHD_PKTID_UNLOCK(map->pktid_lock, flags); - return NULL; - } -#endif /* CUSTOMER_HW5 */ - - locker = &map->lockers[nkey]; - -#if defined(DHD_PKTID_AUDIT_MAP) - DHD_PKTID_AUDIT(map, nkey, DHD_DUPLICATE_FREE); /* Audit duplicate FREE */ -#endif /* DHD_PKTID_AUDIT_MAP */ - - if (locker->inuse == FALSE) { /* Debug check for cloned numbered key */ - DHD_ERROR(("%s:%d: Error! freeing invalid pktid<%u>\n", - __FUNCTION__, __LINE__, nkey)); - DHD_ERROR(("%s:%d: locker->pkt=%p locker->len=%d\n", - __FUNCTION__, __LINE__, locker->pkt, locker->len)); - ASSERT(locker->inuse != FALSE); - /* dump free list */ - { - dll_t *elem_p = NULL; - dll_t *next_p = NULL; - dhd_pktid_item_t *lr; - int i = 0; - - for (elem_p = dll_head_p(&map->list_free); - !dll_end(&map->list_free, elem_p); elem_p = next_p) { - /* in case the list is broken... */ - if (i > 65535) break; - i++; - next_p = dll_next_p(elem_p); - lr = (dhd_pktid_item_t *)elem_p; - if (locker == lr) { - printf("locker is found in free list.\n"); - } - if (lr->pkt) { - printf("locker(%p) pkt(%p) is not null.\n", lr, lr->pkt); - } - } - } - dump_stack(); - DHD_PKTID_UNLOCK(map->pktid_lock, flags); - return NULL; - } - - /* Check for the colour of the buffer i.e The buffer posted for TX, - * should be freed for TX completion. Similarly the buffer posted for - * IOCTL should be freed for IOCT completion etc. - */ - if ((buf_type != BUFF_TYPE_NO_CHECK) && (locker->buf_type != buf_type)) { - DHD_ERROR(("%s:%d: Error! Invalid Buffer Free for pktid<%u> \n", - __FUNCTION__, __LINE__, nkey)); - ASSERT(locker->buf_type == buf_type); - - DHD_PKTID_UNLOCK(map->pktid_lock, flags); - return NULL; - } - - map->avail++; - -#if defined(DHD_PKTIDMAP_FIFO) - ASSERT(locker->nkey == nkey); - - dll_delete(&locker->list_node); /* Free locker to "tail" of free list */ - dll_append(&map->list_free, &locker->list_node); -#else /* ! DHD_PKTIDMAP_FIFO */ - map->keys[map->avail] = nkey; /* make this numbered key available */ -#endif /* ! DHD_PKTIDMAP_FIFO */ - - locker->inuse = FALSE; /* open and free Locker */ - -#if defined(DHD_PKTID_AUDIT_MAP) - DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_FREE); -#endif /* DHD_PKTID_AUDIT_MAP */ - - *physaddr = locker->physaddr; /* return contents of locker */ - *len = (uint32)locker->len; - - pkt = locker->pkt; - locker->pkt = NULL; /* Clear pkt */ - locker->len = 0; - - DHD_PKTID_UNLOCK(map->pktid_lock, flags); - - return pkt; -} - -/* Linkage, sets prot link and updates hdrlen in pub */ -int dhd_prot_attach(dhd_pub_t *dhd) -{ - uint alloced = 0; - - dhd_prot_t *prot; - - /* Allocate prot structure */ - if (!(prot = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, - sizeof(dhd_prot_t)))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - memset(prot, 0, sizeof(*prot)); - - prot->osh = dhd->osh; - dhd->prot = prot; - - /* DMAing ring completes supported? FALSE by default */ - dhd->dma_d2h_ring_upd_support = FALSE; - dhd->dma_h2d_ring_upd_support = FALSE; - - /* Ring Allocations */ - /* 1.0 H2D TXPOST ring */ - if (!(prot->h2dring_txp_subn = prot_ring_attach(prot, "h2dtxp", - H2DRING_TXPOST_MAX_ITEM, H2DRING_TXPOST_ITEMSIZE, - BCMPCIE_H2D_TXFLOWRINGID))) { - DHD_ERROR(("%s: kmalloc for H2D TXPOST ring failed\n", __FUNCTION__)); - goto fail; - } - - /* 2.0 H2D RXPOST ring */ - if (!(prot->h2dring_rxp_subn = prot_ring_attach(prot, "h2drxp", - H2DRING_RXPOST_MAX_ITEM, H2DRING_RXPOST_ITEMSIZE, - BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT))) { - DHD_ERROR(("%s: kmalloc for H2D RXPOST ring failed\n", __FUNCTION__)); - goto fail; - - } - - /* 3.0 H2D CTRL_SUBMISSION ring */ - if (!(prot->h2dring_ctrl_subn = prot_ring_attach(prot, "h2dctrl", - H2DRING_CTRL_SUB_MAX_ITEM, H2DRING_CTRL_SUB_ITEMSIZE, - BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT))) { - DHD_ERROR(("%s: kmalloc for H2D CTRL_SUBMISSION ring failed\n", - __FUNCTION__)); - goto fail; - - } - - /* 4.0 D2H TX_COMPLETION ring */ - if (!(prot->d2hring_tx_cpln = prot_ring_attach(prot, "d2htxcpl", - D2HRING_TXCMPLT_MAX_ITEM, D2HRING_TXCMPLT_ITEMSIZE, - BCMPCIE_D2H_MSGRING_TX_COMPLETE))) { - DHD_ERROR(("%s: kmalloc for D2H TX_COMPLETION ring failed\n", - __FUNCTION__)); - goto fail; - - } - - /* 5.0 D2H RX_COMPLETION ring */ - if (!(prot->d2hring_rx_cpln = prot_ring_attach(prot, "d2hrxcpl", - D2HRING_RXCMPLT_MAX_ITEM, D2HRING_RXCMPLT_ITEMSIZE, - BCMPCIE_D2H_MSGRING_RX_COMPLETE))) { - DHD_ERROR(("%s: kmalloc for D2H RX_COMPLETION ring failed\n", - __FUNCTION__)); - goto fail; - - } - - /* 6.0 D2H CTRL_COMPLETION ring */ - if (!(prot->d2hring_ctrl_cpln = prot_ring_attach(prot, "d2hctrl", - D2HRING_CTRL_CMPLT_MAX_ITEM, D2HRING_CTRL_CMPLT_ITEMSIZE, - BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE))) { - DHD_ERROR(("%s: kmalloc for D2H CTRL_COMPLETION ring failed\n", - __FUNCTION__)); - goto fail; - } - - /* Return buffer for ioctl */ - prot->retbuf.va = DMA_ALLOC_CONSISTENT(dhd->osh, IOCT_RETBUF_SIZE, DMA_ALIGN_LEN, - &alloced, &prot->retbuf.pa, &prot->retbuf.dmah); - if (prot->retbuf.va == NULL) { - ASSERT(0); - DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", - __FUNCTION__, __LINE__, IOCT_RETBUF_SIZE)); - return BCME_NOMEM; - } - - ASSERT(MODX((unsigned long)prot->retbuf.va, DMA_ALIGN_LEN) == 0); - bzero(prot->retbuf.va, IOCT_RETBUF_SIZE); - OSL_CACHE_FLUSH((void *) prot->retbuf.va, IOCT_RETBUF_SIZE); - - /* IOCTL request buffer */ - prot->ioctbuf.va = DMA_ALLOC_CONSISTENT(dhd->osh, IOCT_RETBUF_SIZE, DMA_ALIGN_LEN, - &alloced, &prot->ioctbuf.pa, &prot->ioctbuf.dmah); - - if (prot->ioctbuf.va == NULL) { - ASSERT(0); - DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", - __FUNCTION__, __LINE__, IOCT_RETBUF_SIZE)); - return BCME_NOMEM; - } - - ASSERT(MODX((unsigned long)prot->ioctbuf.va, DMA_ALIGN_LEN) == 0); - bzero(prot->ioctbuf.va, IOCT_RETBUF_SIZE); - OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, IOCT_RETBUF_SIZE); - - /* Scratch buffer for dma rx offset */ - prot->d2h_dma_scratch_buf_len = DMA_D2H_SCRATCH_BUF_LEN; - prot->d2h_dma_scratch_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, DMA_D2H_SCRATCH_BUF_LEN, - DMA_ALIGN_LEN, &alloced, &prot->d2h_dma_scratch_buf.pa, - &prot->d2h_dma_scratch_buf.dmah); - - if (prot->d2h_dma_scratch_buf.va == NULL) { - ASSERT(0); - DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", - __FUNCTION__, __LINE__, DMA_D2H_SCRATCH_BUF_LEN)); - return BCME_NOMEM; - } - ASSERT(MODX((unsigned long)prot->d2h_dma_scratch_buf.va, DMA_ALIGN_LEN) == 0); - bzero(prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); - OSL_CACHE_FLUSH((void *)prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); - - - /* PKTID handle INIT */ - prot->pktid_map_handle = NATIVE_TO_PKTID_INIT(dhd, MAX_PKTID_ITEMS); - if (prot->pktid_map_handle == NULL) { - ASSERT(0); - return BCME_NOMEM; - } - - prot->dmaxfer.srcmem.va = NULL; - prot->dmaxfer.destmem.va = NULL; - prot->dmaxfer_in_progress = FALSE; - - prot->rx_metadata_offset = 0; - prot->tx_metadata_offset = 0; - -#ifdef DHD_RX_CHAINING - dhd_rxchain_reset(&prot->rxchain); -#endif - - return 0; - -fail: -#ifndef CONFIG_DHD_USE_STATIC_BUF - if (prot != NULL) - dhd_prot_detach(dhd); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - return BCME_NOMEM; -} - -/* Init memory block on host DMA'ing indices */ -int -dhd_prot_init_index_dma_block(dhd_pub_t *dhd, uint8 type, uint32 length) -{ - uint alloced = 0; - - dhd_prot_t *prot = dhd->prot; - uint32 dma_block_size = 4 * length; - - if (prot == NULL) { - DHD_ERROR(("prot is not inited\n")); - return BCME_ERROR; - } - - switch (type) { - case HOST_TO_DNGL_DMA_WRITEINDX_BUFFER: - /* ring update dma buffer for submission write */ - prot->h2d_dma_writeindx_buf_len = dma_block_size; - prot->h2d_dma_writeindx_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, - dma_block_size, DMA_ALIGN_LEN, &alloced, - &prot->h2d_dma_writeindx_buf.pa, - &prot->h2d_dma_writeindx_buf.dmah); - - if (prot->h2d_dma_writeindx_buf.va == NULL) { - return BCME_NOMEM; - } - - ASSERT(ISALIGNED(prot->h2d_dma_writeindx_buf.va, 4)); - bzero(prot->h2d_dma_writeindx_buf.va, dma_block_size); - OSL_CACHE_FLUSH((void *)prot->h2d_dma_writeindx_buf.va, dma_block_size); - DHD_ERROR(("H2D_WRITEINDX_ARRAY_HOST: %d-bytes " - "inited for dma'ing h2d-w indices\n", - prot->h2d_dma_writeindx_buf_len)); - break; - - case HOST_TO_DNGL_DMA_READINDX_BUFFER: - /* ring update dma buffer for submission read */ - prot->h2d_dma_readindx_buf_len = dma_block_size; - prot->h2d_dma_readindx_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, - dma_block_size, DMA_ALIGN_LEN, &alloced, - &prot->h2d_dma_readindx_buf.pa, - &prot->h2d_dma_readindx_buf.dmah); - if (prot->h2d_dma_readindx_buf.va == NULL) { - return BCME_NOMEM; - } - - ASSERT(ISALIGNED(prot->h2d_dma_readindx_buf.va, 4)); - bzero(prot->h2d_dma_readindx_buf.va, dma_block_size); - OSL_CACHE_FLUSH((void *)prot->h2d_dma_readindx_buf.va, dma_block_size); - DHD_ERROR(("H2D_READINDX_ARRAY_HOST %d-bytes " - "inited for dma'ing h2d-r indices\n", - prot->h2d_dma_readindx_buf_len)); - break; - - case DNGL_TO_HOST_DMA_WRITEINDX_BUFFER: - /* ring update dma buffer for completion write */ - prot->d2h_dma_writeindx_buf_len = dma_block_size; - prot->d2h_dma_writeindx_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, - dma_block_size, DMA_ALIGN_LEN, &alloced, - &prot->d2h_dma_writeindx_buf.pa, - &prot->d2h_dma_writeindx_buf.dmah); - - if (prot->d2h_dma_writeindx_buf.va == NULL) { - return BCME_NOMEM; - } - - ASSERT(ISALIGNED(prot->d2h_dma_writeindx_buf.va, 4)); - bzero(prot->d2h_dma_writeindx_buf.va, dma_block_size); - OSL_CACHE_FLUSH((void *)prot->d2h_dma_writeindx_buf.va, dma_block_size); - DHD_ERROR(("D2H_WRITEINDX_ARRAY_HOST %d-bytes " - "inited for dma'ing d2h-w indices\n", - prot->d2h_dma_writeindx_buf_len)); - break; - - case DNGL_TO_HOST_DMA_READINDX_BUFFER: - /* ring update dma buffer for completion read */ - prot->d2h_dma_readindx_buf_len = dma_block_size; - prot->d2h_dma_readindx_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, - dma_block_size, DMA_ALIGN_LEN, &alloced, - &prot->d2h_dma_readindx_buf.pa, - &prot->d2h_dma_readindx_buf.dmah); - - if (prot->d2h_dma_readindx_buf.va == NULL) { - return BCME_NOMEM; - } - - ASSERT(ISALIGNED(prot->d2h_dma_readindx_buf.va, 4)); - bzero(prot->d2h_dma_readindx_buf.va, dma_block_size); - OSL_CACHE_FLUSH((void *)prot->d2h_dma_readindx_buf.va, dma_block_size); - DHD_ERROR(("D2H_READINDX_ARRAY_HOST %d-bytes " - "inited for dma'ing d2h-r indices\n", - prot->d2h_dma_readindx_buf_len)); - break; - - default: - DHD_ERROR(("%s: Unexpected option\n", __FUNCTION__)); - return BCME_BADOPTION; - } - - return BCME_OK; - -} - -/* Unlink, frees allocated protocol memory (including dhd_prot) */ -void dhd_prot_detach(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - /* Stop the protocol module */ - if (dhd->prot) { - - /* free up scratch buffer */ - if (prot->d2h_dma_scratch_buf.va) { - DMA_FREE_CONSISTENT(dhd->osh, prot->d2h_dma_scratch_buf.va, - DMA_D2H_SCRATCH_BUF_LEN, prot->d2h_dma_scratch_buf.pa, - prot->d2h_dma_scratch_buf.dmah); - prot->d2h_dma_scratch_buf.va = NULL; - } - /* free up ring upd buffer for submission writes */ - if (prot->h2d_dma_writeindx_buf.va) { - DMA_FREE_CONSISTENT(dhd->osh, prot->h2d_dma_writeindx_buf.va, - prot->h2d_dma_writeindx_buf_len, prot->h2d_dma_writeindx_buf.pa, - prot->h2d_dma_writeindx_buf.dmah); - prot->h2d_dma_writeindx_buf.va = NULL; - } - - /* free up ring upd buffer for submission reads */ - if (prot->h2d_dma_readindx_buf.va) { - DMA_FREE_CONSISTENT(dhd->osh, prot->h2d_dma_readindx_buf.va, - prot->h2d_dma_readindx_buf_len, prot->h2d_dma_readindx_buf.pa, - prot->h2d_dma_readindx_buf.dmah); - prot->h2d_dma_readindx_buf.va = NULL; - } - - /* free up ring upd buffer for completion writes */ - if (prot->d2h_dma_writeindx_buf.va) { - DMA_FREE_CONSISTENT(dhd->osh, prot->d2h_dma_writeindx_buf.va, - prot->d2h_dma_writeindx_buf_len, prot->d2h_dma_writeindx_buf.pa, - prot->d2h_dma_writeindx_buf.dmah); - prot->d2h_dma_writeindx_buf.va = NULL; - } - - /* free up ring upd buffer for completion writes */ - if (prot->d2h_dma_readindx_buf.va) { - DMA_FREE_CONSISTENT(dhd->osh, prot->d2h_dma_readindx_buf.va, - prot->d2h_dma_readindx_buf_len, prot->d2h_dma_readindx_buf.pa, - prot->d2h_dma_readindx_buf.dmah); - prot->d2h_dma_readindx_buf.va = NULL; - } - - /* ioctl return buffer */ - if (prot->retbuf.va) { - DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->retbuf.va, - IOCT_RETBUF_SIZE, dhd->prot->retbuf.pa, dhd->prot->retbuf.dmah); - dhd->prot->retbuf.va = NULL; - } - - /* ioctl request buffer */ - if (prot->ioctbuf.va) { - DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->ioctbuf.va, - IOCT_RETBUF_SIZE, dhd->prot->ioctbuf.pa, dhd->prot->ioctbuf.dmah); - - dhd->prot->ioctbuf.va = NULL; - } - - - /* 1.0 H2D TXPOST ring */ - dhd_prot_ring_detach(dhd, prot->h2dring_txp_subn); - /* 2.0 H2D RXPOST ring */ - dhd_prot_ring_detach(dhd, prot->h2dring_rxp_subn); - /* 3.0 H2D CTRL_SUBMISSION ring */ - dhd_prot_ring_detach(dhd, prot->h2dring_ctrl_subn); - /* 4.0 D2H TX_COMPLETION ring */ - dhd_prot_ring_detach(dhd, prot->d2hring_tx_cpln); - /* 5.0 D2H RX_COMPLETION ring */ - dhd_prot_ring_detach(dhd, prot->d2hring_rx_cpln); - /* 6.0 D2H CTRL_COMPLETION ring */ - dhd_prot_ring_detach(dhd, prot->d2hring_ctrl_cpln); - - NATIVE_TO_PKTID_FINI(dhd->prot->pktid_map_handle); - -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - - /* No need to do anything to prot->ioctl_mutex - * Unlike semaphores no memory is allocated during mutex_init - * So there is no call to free up the same. - */ - dhd->prot = NULL; - } -} - -void -dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 rx_offset) -{ - dhd_prot_t *prot = dhd->prot; - prot->rx_dataoffset = rx_offset; -} - -/* Initialize protocol: sync w/dongle state. - * Sets dongle media info (iswl, drv_version, mac address). - */ -int dhd_sync_with_dongle(dhd_pub_t *dhd) -{ - int ret = 0; - wlc_rev_info_t revinfo; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Post event buffer after shim layer is attached */ - ret = dhd_msgbuf_rxbuf_post_event_bufs(dhd); - if (ret <= 0) { - DHD_ERROR(("%s : Post event buffer fail. ret = %d\n", __FUNCTION__, ret)); - return ret; - } - - dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); - - - /* Get the device rev info */ - memset(&revinfo, 0, sizeof(revinfo)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); - if (ret < 0) - goto done; - - dhd_process_cid_mac(dhd, TRUE); - - ret = dhd_preinit_ioctls(dhd); - - if (!ret) - dhd_process_cid_mac(dhd, FALSE); - - /* Always assumes wl for now */ - dhd->iswl = TRUE; -done: - return ret; -} - -/* This function does all necessary initialization needed -* for IOCTL/IOVAR path -*/ -int dhd_prot_init(dhd_pub_t *dhd) -{ - int ret = 0; - dhd_prot_t *prot = dhd->prot; - - /* Max pkts in ring */ - prot->max_tx_count = H2DRING_TXPOST_MAX_ITEM; - - DHD_INFO(("%s:%d: MAX_TX_COUNT = %d\n", __FUNCTION__, __LINE__, prot->max_tx_count)); - - /* Read max rx packets supported by dongle */ - dhd_bus_cmn_readshared(dhd->bus, &prot->max_rxbufpost, MAX_HOST_RXBUFS, 0); - if (prot->max_rxbufpost == 0) { - /* This would happen if the dongle firmware is not */ - /* using the latest shared structure template */ - prot->max_rxbufpost = DEFAULT_RX_BUFFERS_TO_POST; - } - DHD_INFO(("%s:%d: MAX_RXBUFPOST = %d\n", __FUNCTION__, __LINE__, prot->max_rxbufpost)); - - prot->max_eventbufpost = DHD_FLOWRING_MAX_EVENTBUF_POST; - prot->max_ioctlrespbufpost = DHD_FLOWRING_MAX_IOCTLRESPBUF_POST; - - prot->active_tx_count = 0; - prot->data_seq_no = 0; - prot->ioctl_seq_no = 0; - prot->txp_threshold = TXP_FLUSH_MAX_ITEMS_FLUSH_CNT; - - prot->ioctl_trans_id = 1; - - /* - * Initialize the mutex that serializes the calls to - * dhd_prot_ioctl, if the ioctls are issued from - * multiple process/CPU contexts - */ - mutex_init(&prot->ioctl_mutex); - - /* Register the interrupt function upfront */ - /* remove corerev checks in data path */ - prot->mb_ring_fn = dhd_bus_get_mbintr_fn(dhd->bus); - - /* Initialise rings */ - /* 1.0 H2D TXPOST ring */ - if (dhd_bus_is_txmode_push(dhd->bus)) { - dhd_ring_init(dhd, prot->h2dring_txp_subn); - } - - /* 2.0 H2D RXPOST ring */ - dhd_ring_init(dhd, prot->h2dring_rxp_subn); - /* 3.0 H2D CTRL_SUBMISSION ring */ - dhd_ring_init(dhd, prot->h2dring_ctrl_subn); - /* 4.0 D2H TX_COMPLETION ring */ - dhd_ring_init(dhd, prot->d2hring_tx_cpln); - /* 5.0 D2H RX_COMPLETION ring */ - dhd_ring_init(dhd, prot->d2hring_rx_cpln); - /* 6.0 D2H CTRL_COMPLETION ring */ - dhd_ring_init(dhd, prot->d2hring_ctrl_cpln); - -#if defined(PCIE_D2H_SYNC) - dhd_prot_d2h_sync_init(dhd, prot); -#endif /* PCIE_D2H_SYNC */ - - /* init the scratch buffer */ - dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_scratch_buf.pa, - sizeof(prot->d2h_dma_scratch_buf.pa), DNGL_TO_HOST_DMA_SCRATCH_BUFFER, 0); - dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_scratch_buf_len, - sizeof(prot->d2h_dma_scratch_buf_len), DNGL_TO_HOST_DMA_SCRATCH_BUFFER_LEN, 0); - - /* If supported by the host, indicate the memory block - * for comletion writes / submission reads to shared space - */ - if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) { - dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_writeindx_buf.pa, - sizeof(prot->d2h_dma_writeindx_buf.pa), - DNGL_TO_HOST_DMA_WRITEINDX_BUFFER, 0); - dhd_bus_cmn_writeshared(dhd->bus, &prot->h2d_dma_readindx_buf.pa, - sizeof(prot->h2d_dma_readindx_buf.pa), - HOST_TO_DNGL_DMA_READINDX_BUFFER, 0); - } - - if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) { - dhd_bus_cmn_writeshared(dhd->bus, &prot->h2d_dma_writeindx_buf.pa, - sizeof(prot->h2d_dma_writeindx_buf.pa), - HOST_TO_DNGL_DMA_WRITEINDX_BUFFER, 0); - dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_readindx_buf.pa, - sizeof(prot->d2h_dma_readindx_buf.pa), - DNGL_TO_HOST_DMA_READINDX_BUFFER, 0); - - } - - ret = dhd_msgbuf_rxbuf_post(dhd); - ret = dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd); - - return ret; -} - -#define DHD_DBG_SHOW_METADATA 0 -#if DHD_DBG_SHOW_METADATA -static void BCMFASTPATH -dhd_prot_print_metadata(dhd_pub_t *dhd, void *ptr, int len) -{ - uint8 tlv_t; - uint8 tlv_l; - uint8 *tlv_v = (uint8 *)ptr; - - if (len <= BCMPCIE_D2H_METADATA_HDRLEN) - return; - - len -= BCMPCIE_D2H_METADATA_HDRLEN; - tlv_v += BCMPCIE_D2H_METADATA_HDRLEN; - - while (len > TLV_HDR_LEN) { - tlv_t = tlv_v[TLV_TAG_OFF]; - tlv_l = tlv_v[TLV_LEN_OFF]; - - len -= TLV_HDR_LEN; - tlv_v += TLV_HDR_LEN; - if (len < tlv_l) - break; - if ((tlv_t == 0) || (tlv_t == WLFC_CTL_TYPE_FILLER)) - break; - - switch (tlv_t) { - case WLFC_CTL_TYPE_TXSTATUS: - bcm_print_bytes("METADATA TX_STATUS", tlv_v, tlv_l); - break; - - case WLFC_CTL_TYPE_RSSI: - bcm_print_bytes("METADATA RX_RSSI", tlv_v, tlv_l); - break; - - case WLFC_CTL_TYPE_FIFO_CREDITBACK: - bcm_print_bytes("METADATA FIFO_CREDITBACK", tlv_v, tlv_l); - break; - - case WLFC_CTL_TYPE_TX_ENTRY_STAMP: - bcm_print_bytes("METADATA TX_ENTRY", tlv_v, tlv_l); - break; - - case WLFC_CTL_TYPE_RX_STAMP: - bcm_print_bytes("METADATA RX_TIMESTAMP", tlv_v, tlv_l); - break; - - case WLFC_CTL_TYPE_TRANS_ID: - bcm_print_bytes("METADATA TRANS_ID", tlv_v, tlv_l); - break; - - case WLFC_CTL_TYPE_COMP_TXSTATUS: - bcm_print_bytes("METADATA COMP_TXSTATUS", tlv_v, tlv_l); - break; - - default: - bcm_print_bytes("METADATA UNKNOWN", tlv_v, tlv_l); - break; - } - - len -= tlv_l; - tlv_v += tlv_l; - } -} -#endif /* DHD_DBG_SHOW_METADATA */ - -static INLINE void BCMFASTPATH -dhd_prot_packet_free(dhd_pub_t *dhd, uint32 pktid, uint8 buf_type) -{ - void *PKTBUF; - dmaaddr_t pa; - uint32 pa_len; - PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, - pa_len, buf_type); - - if (PKTBUF) { - if (!PHYSADDRISZERO(pa)) { - if (buf_type == BUFF_TYPE_DATA_TX) { - DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_TX, 0, 0); - } else { - DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_RX, 0, 0); - } -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - if (buf_type == BUFF_TYPE_IOCTL_RX) { - PKTFREE_STATIC(dhd->osh, PKTBUF, FALSE); - } else { -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - PKTFREE(dhd->osh, PKTBUF, FALSE); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - } -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - } else { - DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__)); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - if (buf_type == BUFF_TYPE_IOCTL_RX) { - PKTINVALIDATE_STATIC(dhd->osh, PKTBUF); - } else { -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - PKTFREE(dhd->osh, PKTBUF, FALSE); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - } -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - } - } else { - printf("%s: pkt id invaild. dump dongle memory.\n", __FUNCTION__); - /* write core dump to file */ -#ifdef DHD_FW_COREDUMP - dhdpcie_mem_dump(dhd->bus); -#endif /* DHD_FW_COREDUMP */ - } - - return; -} - -static INLINE void * BCMFASTPATH -dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid, uint8 buf_type) -{ - void *PKTBUF; - dmaaddr_t pa; - uint32 pa_len; - PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, pa_len, buf_type); - if (PKTBUF) { - if (!PHYSADDRISZERO(pa)) { - if (buf_type == BUFF_TYPE_DATA_TX) { - DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_TX, 0, 0); - } else { - DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_RX, 0, 0); - } - } else { - DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__)); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - if (buf_type == BUFF_TYPE_IOCTL_RX || - buf_type == BUFF_TYPE_EVENT_RX) { - PKTINVALIDATE_STATIC(dhd->osh, PKTBUF); - } -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - } - } - - return PKTBUF; -} - -static int BCMFASTPATH -dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - int16 fillbufs; - uint16 cnt = 64; - int retcount = 0; - - fillbufs = prot->max_rxbufpost - prot->rxbufpost; - while (fillbufs > 0) { - cnt--; - if (cnt == 0) { - /* find a better way to reschedule rx buf post if space not available */ - DHD_ERROR(("h2d rx post ring not available to post host buffers \n")); - DHD_ERROR(("Current posted host buf count %d \n", prot->rxbufpost)); - break; - } - - /* Post in a burst of 8 buffers ata time */ - fillbufs = MIN(fillbufs, RX_BUF_BURST); - - /* Post buffers */ - retcount = dhd_prot_rxbufpost(dhd, fillbufs); - - if (retcount > 0) { - prot->rxbufpost += (uint16)retcount; - - /* how many more to post */ - fillbufs = prot->max_rxbufpost - prot->rxbufpost; - } else { - /* Make sure we don't run loop any further */ - fillbufs = 0; - } - } - - return 0; -} - -/* Post count no of rx buffers down to dongle */ -static int BCMFASTPATH -dhd_prot_rxbufpost(dhd_pub_t *dhd, uint16 count) -{ - void *p; - uint16 pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; - uint8 *rxbuf_post_tmp; - host_rxbuf_post_t *rxbuf_post; - void* msg_start; - dmaaddr_t physaddr; - uint32 pktlen; - dhd_prot_t *prot = dhd->prot; - msgbuf_ring_t * ring = prot->h2dring_rxp_subn; - uint8 i = 0; - uint16 alloced = 0; - unsigned long flags; - uint32 pktid; - - DHD_GENERAL_LOCK(dhd, flags); - /* Claim space for 'count' no of messages */ - msg_start = (void *)dhd_alloc_ring_space(dhd, ring, count, &alloced); - DHD_GENERAL_UNLOCK(dhd, flags); - - if (msg_start == NULL) { - DHD_INFO(("%s:%d: Rxbufpost Msgbuf Not available\n", __FUNCTION__, __LINE__)); - return -1; - } - /* if msg_start != NULL, we should have alloced space for atleast 1 item */ - ASSERT(alloced > 0); - - rxbuf_post_tmp = (uint8*)msg_start; - - /* loop through each message */ - for (i = 0; i < alloced; i++) { - rxbuf_post = (host_rxbuf_post_t *)rxbuf_post_tmp; - /* Create a rx buffer */ - if ((p = PKTGET(dhd->osh, pktsz, FALSE)) == NULL) { - DHD_ERROR(("%s:%d: PKTGET for rxbuf failed\n", __FUNCTION__, __LINE__)); - break; - } - - pktlen = PKTLEN(dhd->osh, p); - physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0); - if (PHYSADDRISZERO(physaddr)) { - PKTFREE(dhd->osh, p, FALSE); - DHD_ERROR(("Invalid phyaddr 0\n")); - ASSERT(0); - break; - } - - PKTPULL(dhd->osh, p, prot->rx_metadata_offset); - pktlen = PKTLEN(dhd->osh, p); - - /* CMN msg header */ - rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_RXBUF_POST; - rxbuf_post->cmn_hdr.if_id = 0; - - /* get the lock before calling NATIVE_TO_PKTID */ - DHD_GENERAL_LOCK(dhd, flags); - - pktid = htol32(NATIVE_TO_PKTID(dhd->prot->pktid_map_handle, p, physaddr, - pktlen, DMA_RX, BUFF_TYPE_DATA_RX)); - - /* free lock */ - DHD_GENERAL_UNLOCK(dhd, flags); - - if (pktid == DHD_PKTID_INVALID) { - DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0); - PKTFREE(dhd->osh, p, FALSE); - DHD_ERROR(("Pktid pool depleted.\n")); - break; - } - - /* CMN msg header */ - rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_RXBUF_POST; - rxbuf_post->cmn_hdr.if_id = 0; - - rxbuf_post->data_buf_len = htol16((uint16)pktlen); - rxbuf_post->data_buf_addr.high_addr = htol32(PHYSADDRHI(physaddr)); - rxbuf_post->data_buf_addr.low_addr = - htol32(PHYSADDRLO(physaddr) + prot->rx_metadata_offset); - - if (prot->rx_metadata_offset) { - rxbuf_post->metadata_buf_len = prot->rx_metadata_offset; - rxbuf_post->metadata_buf_addr.high_addr = htol32(PHYSADDRHI(physaddr)); - rxbuf_post->metadata_buf_addr.low_addr = htol32(PHYSADDRLO(physaddr)); - } else { - rxbuf_post->metadata_buf_len = 0; - rxbuf_post->metadata_buf_addr.high_addr = 0; - rxbuf_post->metadata_buf_addr.low_addr = 0; - } - -#if defined(DHD_PKTID_AUDIT_RING) - DHD_PKTID_AUDIT(prot->pktid_map_handle, pktid, DHD_DUPLICATE_ALLOC); -#endif /* DHD_PKTID_AUDIT_RING */ - - rxbuf_post->cmn_hdr.request_id = htol32(pktid); - - /* Move rxbuf_post_tmp to next item */ - rxbuf_post_tmp = rxbuf_post_tmp + RING_LEN_ITEMS(ring); - } - - if (i < alloced) { - if (RING_WRITE_PTR(ring) < (alloced - i)) - RING_WRITE_PTR(ring) = RING_MAX_ITEM(ring) - (alloced - i); - else - RING_WRITE_PTR(ring) -= (alloced - i); - - alloced = i; - } - - /* Update the write pointer in TCM & ring bell */ - if (alloced > 0) - prot_ring_write_complete(dhd, prot->h2dring_rxp_subn, msg_start, alloced); - - return alloced; -} - -static int -dhd_prot_rxbufpost_ctrl(dhd_pub_t *dhd, bool event_buf) -{ - void *p; - uint16 pktsz; - ioctl_resp_evt_buf_post_msg_t *rxbuf_post; - dmaaddr_t physaddr; - uint32 pktlen; - dhd_prot_t *prot = dhd->prot; - uint16 alloced = 0; - unsigned long flags; - uint8 buf_type; - uint32 pktid; - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); - return -1; - } - - if (event_buf) { - /* Allocate packet for event buffer post */ - pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; - } else { - /* Allocate packet for ctrl/ioctl buffer post */ - pktsz = DHD_FLOWRING_IOCTL_BUFPOST_PKTSZ; - } - -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - if (!event_buf) { - p = PKTGET_STATIC(dhd->osh, pktsz, FALSE); - } else { -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - p = PKTGET(dhd->osh, pktsz, FALSE); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - } -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - - if (p == NULL) { - DHD_ERROR(("%s:%d: PKTGET for %s rxbuf failed\n", - __FUNCTION__, __LINE__, event_buf ? "event" : - "ioctl")); - return -1; - } - - pktlen = PKTLEN(dhd->osh, p); - physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0); - if (PHYSADDRISZERO(physaddr)) { - - DHD_ERROR(("Invalid phyaddr 0\n")); - ASSERT(0); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - PKTINVALIDATE_STATIC(dhd->osh, p); - return -1; -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - goto free_pkt_return; - } - - DHD_GENERAL_LOCK(dhd, flags); - rxbuf_post = (ioctl_resp_evt_buf_post_msg_t *)dhd_alloc_ring_space(dhd, - prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); - if (rxbuf_post == NULL) { - DHD_GENERAL_UNLOCK(dhd, flags); - DHD_ERROR(("%s:%d: Ctrl submit Msgbuf Not available to post buffer" - " for %s\n", __FUNCTION__, __LINE__, event_buf ? "event" : - "ioctl")); - DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0); - - goto free_pkt_return; - } - - buf_type = ((event_buf == 1) ? BUFF_TYPE_EVENT_RX : - BUFF_TYPE_IOCTL_RX); - - pktid = htol32(NATIVE_TO_PKTID(dhd->prot->pktid_map_handle, p, physaddr, - pktlen, DMA_RX, buf_type)); - - if (pktid == DHD_PKTID_INVALID) { - if (RING_WRITE_PTR(prot->h2dring_ctrl_subn) == 0) { - RING_WRITE_PTR(prot->h2dring_ctrl_subn) = - RING_MAX_ITEM(prot->h2dring_ctrl_subn) - 1; - } else { - RING_WRITE_PTR(prot->h2dring_ctrl_subn)--; - } - DHD_GENERAL_UNLOCK(dhd, flags); - DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0); - - goto free_pkt_return; - } - -#if defined(DHD_PKTID_AUDIT_RING) - DHD_PKTID_AUDIT(prot->pktid_map_handle, pktid, DHD_DUPLICATE_ALLOC); -#endif /* DHD_PKTID_AUDIT_RING */ - - /* CMN msg header */ - if (event_buf) { - rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_EVENT_BUF_POST; - } else { - rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_IOCTLRESP_BUF_POST; - } - - rxbuf_post->cmn_hdr.if_id = 0; - rxbuf_post->cmn_hdr.flags = 0; - - rxbuf_post->host_buf_len = htol16((uint16)PKTLEN(dhd->osh, p)); - rxbuf_post->host_buf_addr.high_addr = htol32(PHYSADDRHI(physaddr)); - rxbuf_post->host_buf_addr.low_addr = htol32(PHYSADDRLO(physaddr)); - rxbuf_post->cmn_hdr.request_id = htol32(pktid); - - /* Update the write pointer in TCM & ring bell */ - prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, rxbuf_post, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - DHD_GENERAL_UNLOCK(dhd, flags); - - return 1; - -free_pkt_return: -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - if (!event_buf) { - PKTFREE_STATIC(dhd->osh, p, FALSE); - } else { -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - - PKTFREE(dhd->osh, p, FALSE); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - } -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - - return -1; -} - -static uint16 -dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, bool event_buf, uint32 max_to_post) -{ - uint32 i = 0; - int32 ret_val; - - DHD_INFO(("max to post %d, event %d \n", max_to_post, event_buf)); - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); - return 0; - } - - while (i < max_to_post) { - ret_val = dhd_prot_rxbufpost_ctrl(dhd, event_buf); - if (ret_val < 0) - break; - i++; - } - DHD_INFO(("posted %d buffers to event_pool/ioctl_resp_pool %d\n", i, event_buf)); - return (uint16)i; -} - -static int -dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - uint16 retcnt = 0; - - DHD_INFO(("ioctl resp buf post\n")); - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); - return 0; - } - - retcnt = dhd_msgbuf_rxbuf_post_ctrlpath(dhd, FALSE, - prot->max_ioctlrespbufpost - prot->cur_ioctlresp_bufs_posted); - prot->cur_ioctlresp_bufs_posted += retcnt; - return retcnt; -} - -static int -dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - uint16 retcnt = 0; - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); - return 0; - } - - retcnt = dhd_msgbuf_rxbuf_post_ctrlpath(dhd, TRUE, - prot->max_eventbufpost - prot->cur_event_bufs_posted); - - prot->cur_event_bufs_posted += retcnt; - return retcnt; -} - -bool BCMFASTPATH -dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound) -{ - dhd_prot_t *prot = dhd->prot; - bool more = TRUE; - uint n = 0; - - /* Process all the messages - DTOH direction */ - while (TRUE) { - uint8 *src_addr; - uint16 src_len; - - if (dhd->hang_was_sent) { - more = FALSE; - break; - } - - /* Store current read pointer */ - /* Read pointer will be updated in prot_early_upd_rxcpln_read_idx */ - prot_store_rxcpln_read_idx(dhd, prot->d2hring_rx_cpln); - - /* Get the message from ring */ - src_addr = prot_get_src_addr(dhd, prot->d2hring_rx_cpln, &src_len); - if (src_addr == NULL) { - more = FALSE; - break; - } - - /* Prefetch data to populate the cache */ - OSL_PREFETCH(src_addr); - - if (dhd_prot_process_msgtype(dhd, prot->d2hring_rx_cpln, src_addr, - src_len) != BCME_OK) { - prot_upd_read_idx(dhd, prot->d2hring_rx_cpln); - DHD_ERROR(("%s: Error at process rxpl msgbuf of len %d\n", - __FUNCTION__, src_len)); - } - - /* After batch processing, check RX bound */ - n += src_len/RING_LEN_ITEMS(prot->d2hring_rx_cpln); - if (n >= bound) { - break; - } - } - - return more; -} - -void -dhd_prot_update_txflowring(dhd_pub_t *dhd, uint16 flow_id, void *msgring_info) -{ - uint16 r_index = 0; - msgbuf_ring_t *ring = (msgbuf_ring_t *)msgring_info; - - /* Update read pointer */ - if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) { - r_index = dhd_get_dmaed_index(dhd, H2D_DMA_READINDX, ring->idx); - ring->ringstate->r_offset = r_index; - } - - DHD_TRACE(("flow %d, write %d read %d \n\n", flow_id, RING_WRITE_PTR(ring), - RING_READ_PTR(ring))); - - /* Need more logic here, but for now use it directly */ - dhd_bus_schedule_queue(dhd->bus, flow_id, TRUE); -} - - -bool BCMFASTPATH -dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound) -{ - dhd_prot_t *prot = dhd->prot; - bool more = TRUE; - uint n = 0; - - /* Process all the messages - DTOH direction */ - while (TRUE) { - uint8 *src_addr; - uint16 src_len; - - if (dhd->hang_was_sent) { - more = FALSE; - break; - } - - src_addr = prot_get_src_addr(dhd, prot->d2hring_tx_cpln, &src_len); - if (src_addr == NULL) { - more = FALSE; - break; - } - - /* Prefetch data to populate the cache */ - OSL_PREFETCH(src_addr); - - if (dhd_prot_process_msgtype(dhd, prot->d2hring_tx_cpln, src_addr, - src_len) != BCME_OK) { - DHD_ERROR(("%s: Error at process txcmpl msgbuf of len %d\n", - __FUNCTION__, src_len)); - } - - /* Write to dngl rd ptr */ - prot_upd_read_idx(dhd, prot->d2hring_tx_cpln); - - /* After batch processing, check bound */ - n += src_len/RING_LEN_ITEMS(prot->d2hring_tx_cpln); - if (n >= bound) { - break; - } - } - - return more; -} - -int BCMFASTPATH -dhd_prot_process_ctrlbuf(dhd_pub_t * dhd) -{ - dhd_prot_t *prot = dhd->prot; - - /* Process all the messages - DTOH direction */ - while (TRUE) { - uint8 *src_addr; - uint16 src_len; - - if (dhd->hang_was_sent) { - break; - } - - src_addr = prot_get_src_addr(dhd, prot->d2hring_ctrl_cpln, &src_len); - - if (src_addr == NULL) { - break; - } - - /* Prefetch data to populate the cache */ - OSL_PREFETCH(src_addr); - if (dhd_prot_process_msgtype(dhd, prot->d2hring_ctrl_cpln, src_addr, - src_len) != BCME_OK) { - DHD_ERROR(("%s: Error at process ctrlmsgbuf of len %d\n", - __FUNCTION__, src_len)); - } - - /* Write to dngl rd ptr */ - prot_upd_read_idx(dhd, prot->d2hring_ctrl_cpln); - } - - return 0; -} - -static int BCMFASTPATH -dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len) -{ - dhd_prot_t *prot = dhd->prot; - uint32 cur_dma_len = 0; - int ret = BCME_OK; - - DHD_INFO(("%s: process msgbuf of len %d\n", __FUNCTION__, len)); - - while (len > 0) { - ASSERT(len > (sizeof(cmn_msg_hdr_t) + prot->rx_dataoffset)); - - if (dhd->hang_was_sent) { - ret = BCME_ERROR; - break; - } - - if (prot->rx_dataoffset) { - cur_dma_len = *(uint32 *) buf; - ASSERT(cur_dma_len <= len); - buf += prot->rx_dataoffset; - len -= (uint16)prot->rx_dataoffset; - } - else { - cur_dma_len = len; - } - if (dhd_process_msgtype(dhd, ring, buf, (uint16)cur_dma_len) != BCME_OK) { - DHD_ERROR(("%s: Error at process msg of dmalen %d\n", - __FUNCTION__, cur_dma_len)); - ret = BCME_ERROR; - } - - len -= (uint16)cur_dma_len; - buf += cur_dma_len; - } - return ret; -} - -static int BCMFASTPATH -dhd_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len) -{ - uint16 pktlen = len; - uint16 msglen; - uint8 msgtype; - cmn_msg_hdr_t *msg = NULL; - int ret = BCME_OK; - -#if defined(PCIE_D2H_SYNC_BZERO) - uint8 *buf_head = buf; -#endif /* PCIE_D2H_SYNC_BZERO */ - - ASSERT(ring && ring->ringmem); - msglen = RING_LEN_ITEMS(ring); - if (msglen == 0) { - DHD_ERROR(("%s: ringidx %d, msglen is %d, pktlen is %d \n", - __FUNCTION__, ring->idx, msglen, pktlen)); - return BCME_ERROR; - } - - while (pktlen > 0) { - if (dhd->hang_was_sent) { - ret = BCME_ERROR; - goto done; - } - - msg = (cmn_msg_hdr_t *)buf; - -#if defined(PCIE_D2H_SYNC) - /* Wait until DMA completes, then fetch msgtype */ - msgtype = dhd->prot->d2h_sync_cb(dhd, ring, msg, msglen); -#else - msgtype = msg->msg_type; -#endif /* !PCIE_D2H_SYNC */ - - DHD_INFO(("msgtype %d, msglen is %d, pktlen is %d \n", - msgtype, msglen, pktlen)); - if (msgtype == MSG_TYPE_LOOPBACK) { - bcm_print_bytes("LPBK RESP: ", (uint8 *)msg, msglen); - DHD_ERROR((" MSG_TYPE_LOOPBACK, len %d\n", msglen)); - } - - - if (msgtype >= DHD_PROT_FUNCS) { - DHD_ERROR(("%s: msgtype %d, msglen is %d, pktlen is %d \n", - __FUNCTION__, msgtype, msglen, pktlen)); - ret = BCME_ERROR; - goto done; - } - - if (table_lookup[msgtype]) { - table_lookup[msgtype](dhd, buf, msglen); - } - - if (pktlen < msglen) { - ret = BCME_ERROR; - goto done; - } - pktlen = pktlen - msglen; - buf = buf + msglen; - - if (ring->idx == BCMPCIE_D2H_MSGRING_RX_COMPLETE) - prot_early_upd_rxcpln_read_idx(dhd, ring); - } -done: - -#if defined(PCIE_D2H_SYNC_BZERO) - OSL_CACHE_FLUSH(buf_head, len - pktlen); /* Flush the bzeroed msg */ -#endif /* PCIE_D2H_SYNC_BZERO */ - -#ifdef DHD_RX_CHAINING - dhd_rxchain_commit(dhd); -#endif - - return ret; -} - -static void -dhd_prot_noop(dhd_pub_t *dhd, void * buf, uint16 msglen) -{ - return; -} - -static void -dhd_prot_ringstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen) -{ - pcie_ring_status_t * ring_status = (pcie_ring_status_t *)buf; - DHD_ERROR(("ring status: request_id %d, status 0x%04x, flow ring %d, w_offset %d \n", - ring_status->cmn_hdr.request_id, ring_status->compl_hdr.status, - ring_status->compl_hdr.flow_ring_id, ring_status->write_idx)); - /* How do we track this to pair it with ??? */ - return; -} - -static void -dhd_prot_genstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen) -{ - pcie_gen_status_t * gen_status = (pcie_gen_status_t *)buf; - DHD_ERROR(("gen status: request_id %d, status 0x%04x, flow ring %d \n", - gen_status->cmn_hdr.request_id, gen_status->compl_hdr.status, - gen_status->compl_hdr.flow_ring_id)); - - /* How do we track this to pair it with ??? */ - return; -} - -static void -dhd_prot_ioctack_process(dhd_pub_t *dhd, void * buf, uint16 msglen) -{ - ioctl_req_ack_msg_t * ioct_ack = (ioctl_req_ack_msg_t *)buf; - unsigned long flags; - -#if defined(DHD_PKTID_AUDIT_RING) - uint32 pktid; - pktid = ltoh32(ioct_ack->cmn_hdr.request_id); - if (pktid != DHD_IOCTL_REQ_PKTID) { - DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pktid, - DHD_TEST_IS_ALLOC); - } -#endif /* DHD_PKTID_AUDIT_RING */ - DHD_GENERAL_LOCK(dhd, flags); - if ((dhd->ioctl_state & MSGBUF_IOCTL_ACK_PENDING) && - (dhd->ioctl_state & MSGBUF_IOCTL_RESP_PENDING)) { - dhd->ioctl_state &= ~MSGBUF_IOCTL_ACK_PENDING; - } else { - DHD_ERROR(("%s: received ioctl ACK with state %02x trans_id = %d\n", - __FUNCTION__, dhd->ioctl_state, dhd->prot->ioctl_trans_id)); - prhex("dhd_prot_ioctack_process:", - (uchar *)buf, D2HRING_CTRL_CMPLT_ITEMSIZE); - } - DHD_GENERAL_UNLOCK(dhd, flags); - - DHD_CTL(("ioctl req ack: request_id %d, status 0x%04x, flow ring %d \n", - ioct_ack->cmn_hdr.request_id, ioct_ack->compl_hdr.status, - ioct_ack->compl_hdr.flow_ring_id)); - if (ioct_ack->compl_hdr.status != 0) { - DHD_ERROR(("got an error status for the ioctl request...need to handle that\n")); - } - -#if defined(PCIE_D2H_SYNC_BZERO) - memset(buf, 0, msglen); -#endif /* PCIE_D2H_SYNC_BZERO */ -} - -static void -dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void * buf, uint16 msglen) -{ - uint16 status; - uint32 resp_len = 0; - uint32 pkt_id, xt_id; - ioctl_comp_resp_msg_t * ioct_resp = (ioctl_comp_resp_msg_t *)buf; - unsigned long flags; - - resp_len = ltoh16(ioct_resp->resp_len); - xt_id = ltoh16(ioct_resp->trans_id); - BCM_REFERENCE(xt_id); - pkt_id = ltoh32(ioct_resp->cmn_hdr.request_id); - status = ioct_resp->compl_hdr.status; - -#if defined(PCIE_D2H_SYNC_BZERO) - memset(buf, 0, msglen); -#endif /* PCIE_D2H_SYNC_BZERO */ - -#if defined(DHD_PKTID_AUDIT_RING) - /* will be freed later */ - DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pkt_id, - DHD_TEST_IS_ALLOC); -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_GENERAL_LOCK(dhd, flags); - if ((dhd->ioctl_state & MSGBUF_IOCTL_ACK_PENDING) || - !(dhd->ioctl_state & MSGBUF_IOCTL_RESP_PENDING)) { - DHD_ERROR(("%s: received ioctl response with state %02x trans_id = %d\n", - __FUNCTION__, dhd->ioctl_state, dhd->prot->ioctl_trans_id)); - prhex("dhd_prot_ioctcmplt_process:", - (uchar *)buf, D2HRING_CTRL_CMPLT_ITEMSIZE); - DHD_GENERAL_UNLOCK(dhd, flags); - return; - } - DHD_GENERAL_UNLOCK(dhd, flags); - - DHD_CTL(("IOCTL_COMPLETE: pktid %x xtid %d status %x resplen %d\n", - pkt_id, xt_id, status, resp_len)); - - dhd_bus_update_retlen(dhd->bus, sizeof(ioctl_comp_resp_msg_t), pkt_id, status, resp_len); - dhd_os_ioctl_resp_wake(dhd); -} - -static void BCMFASTPATH -dhd_prot_txstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen) -{ - dhd_prot_t *prot = dhd->prot; - host_txbuf_cmpl_t * txstatus; - unsigned long flags; - uint32 pktid; - void *pkt; - /* locks required to protect circular buffer accesses */ - DHD_GENERAL_LOCK(dhd, flags); - - txstatus = (host_txbuf_cmpl_t *)buf; - pktid = ltoh32(txstatus->cmn_hdr.request_id); -#if defined(DHD_PKTID_AUDIT_RING) - DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pktid, - DHD_DUPLICATE_FREE); -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_INFO(("txstatus for pktid 0x%04x\n", pktid)); - if (prot->active_tx_count) { - prot->active_tx_count--; - /* Release the Lock when no more tx packets are pending */ - if (prot->active_tx_count == 0) - DHD_TXFL_WAKE_UNLOCK(dhd); - } else { - DHD_ERROR(("Extra packets are freed\n")); - } - - ASSERT(pktid != 0); - - pkt = dhd_prot_packet_get(dhd, pktid, BUFF_TYPE_DATA_TX); - if (pkt) { -#if defined(BCMPCIE) - dhd_txcomplete(dhd, pkt, true); -#endif - -#if DHD_DBG_SHOW_METADATA - if (dhd->prot->tx_metadata_offset && txstatus->metadata_len) { - uchar *ptr; - /* The Ethernet header of TX frame was copied and removed. - * Here, move the data pointer forward by Ethernet header size. - */ - PKTPULL(dhd->osh, pkt, ETHER_HDR_LEN); - ptr = PKTDATA(dhd->osh, pkt) - (dhd->prot->tx_metadata_offset); - bcm_print_bytes("txmetadata", ptr, txstatus->metadata_len); - dhd_prot_print_metadata(dhd, ptr, txstatus->metadata_len); - } -#endif /* DHD_DBG_SHOW_METADATA */ - PKTFREE(dhd->osh, pkt, TRUE); - } - -#if defined(PCIE_D2H_SYNC_BZERO) - memset(buf, 0, msglen); -#endif /* PCIE_D2H_SYNC_BZERO */ - - DHD_GENERAL_UNLOCK(dhd, flags); - - return; -} - -static void -dhd_msgbuf_dump_ctrlrings(dhd_pub_t *dhd) -{ - int i; - msgbuf_ring_t *ring; - uchar *msg; - - ring = dhd->prot->h2dring_ctrl_subn; - DHD_ERROR(("%s: ctrl post ring RP %d, WP %d\n", - __FUNCTION__, RING_READ_PTR(ring), RING_WRITE_PTR(ring))); - msg = (uchar *)ring->ring_base.va; - for (i = 0; i < RING_MAX_ITEM(ring); i++) { - prhex(NULL, msg, RING_LEN_ITEMS(ring)); - msg += RING_LEN_ITEMS(ring); - } - - ring = dhd->prot->d2hring_ctrl_cpln; - DHD_ERROR(("%s: ctrl complete ring RP %d, WP %d\n", - __FUNCTION__, RING_READ_PTR(ring), RING_WRITE_PTR(ring))); - msg = (uchar *)ring->ring_base.va; - for (i = 0; i < RING_MAX_ITEM(ring); i++) { - prhex(NULL, msg, RING_LEN_ITEMS(ring)); - msg += RING_LEN_ITEMS(ring); - } -} - -static void -dhd_prot_event_process(dhd_pub_t *dhd, void* buf, uint16 len) -{ - wlevent_req_msg_t *evnt; - uint32 pktid; - uint16 buflen; - int ifidx = 0; - void* pkt; - unsigned long flags; - dhd_prot_t *prot = dhd->prot; - int post_cnt = 0; - bool zero_posted = FALSE; - - /* Event complete header */ - evnt = (wlevent_req_msg_t *)buf; - pktid = ltoh32(evnt->cmn_hdr.request_id); - -#if defined(DHD_PKTID_AUDIT_RING) - DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pktid, - DHD_DUPLICATE_FREE); -#endif /* DHD_PKTID_AUDIT_RING */ - - buflen = ltoh16(evnt->event_data_len); - - ifidx = BCMMSGBUF_API_IFIDX(&evnt->cmn_hdr); - - /* Post another rxbuf to the device */ - if (prot->cur_event_bufs_posted) - prot->cur_event_bufs_posted--; - else - zero_posted = TRUE; - - - post_cnt = dhd_msgbuf_rxbuf_post_event_bufs(dhd); - if (zero_posted && (post_cnt <= 0)) { - return; - } - -#if defined(PCIE_D2H_SYNC_BZERO) - memset(buf, 0, len); -#endif /* PCIE_D2H_SYNC_BZERO */ - - /* locks required to protect pktid_map */ - DHD_GENERAL_LOCK(dhd, flags); - pkt = dhd_prot_packet_get(dhd, pktid, BUFF_TYPE_EVENT_RX); - - DHD_GENERAL_UNLOCK(dhd, flags); - - if (!pkt) { - DHD_ERROR(("%s: pkt is NULL\n", __FUNCTION__)); - dhd_msgbuf_dump_ctrlrings(dhd); - return; - } - - /* DMA RX offset updated through shared area */ - if (dhd->prot->rx_dataoffset) - PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset); - - PKTSETLEN(dhd->osh, pkt, buflen); - - dhd_bus_rx_frame(dhd->bus, pkt, ifidx, 1); -} - -static void BCMFASTPATH -dhd_prot_rxcmplt_process(dhd_pub_t *dhd, void* buf, uint16 msglen) -{ - host_rxbuf_cmpl_t *rxcmplt_h; - uint16 data_offset; /* offset at which data starts */ - void * pkt; - unsigned long flags; - static uint8 current_phase = 0; - uint ifidx; - uint32 pktid; - - /* RXCMPLT HDR */ - rxcmplt_h = (host_rxbuf_cmpl_t *)buf; - - /* Post another set of rxbufs to the device */ - dhd_prot_return_rxbuf(dhd, 1); - - pktid = ltoh32(rxcmplt_h->cmn_hdr.request_id); - -#if defined(DHD_PKTID_AUDIT_RING) - DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pktid, - DHD_DUPLICATE_FREE); -#endif /* DHD_PKTID_AUDIT_RING */ - - /* offset from which data starts is populated in rxstatus0 */ - data_offset = ltoh16(rxcmplt_h->data_offset); - - DHD_GENERAL_LOCK(dhd, flags); - pkt = dhd_prot_packet_get(dhd, pktid, BUFF_TYPE_DATA_RX); - DHD_GENERAL_UNLOCK(dhd, flags); - - if (!pkt) { - return; - } - - DHD_INFO(("id 0x%04x, offset %d, len %d, idx %d, phase 0x%02x, pktdata %p, metalen %d\n", - pktid, data_offset, ltoh16(rxcmplt_h->data_len), - rxcmplt_h->cmn_hdr.if_id, rxcmplt_h->cmn_hdr.flags, PKTDATA(dhd->osh, pkt), - ltoh16(rxcmplt_h->metadata_len))); - -#if DHD_DBG_SHOW_METADATA - if (dhd->prot->rx_metadata_offset && rxcmplt_h->metadata_len) { - uchar *ptr; - ptr = PKTDATA(dhd->osh, pkt) - (dhd->prot->rx_metadata_offset); - /* header followed by data */ - bcm_print_bytes("rxmetadata", ptr, rxcmplt_h->metadata_len); - dhd_prot_print_metadata(dhd, ptr, rxcmplt_h->metadata_len); - } -#endif /* DHD_DBG_SHOW_METADATA */ - - if (current_phase != rxcmplt_h->cmn_hdr.flags) { - current_phase = rxcmplt_h->cmn_hdr.flags; - } - if (rxcmplt_h->flags & BCMPCIE_PKT_FLAGS_FRAME_802_11) - DHD_INFO(("D11 frame rxed \n")); - /* data_offset from buf start */ - if (data_offset) { - /* data offset given from dongle after split rx */ - PKTPULL(dhd->osh, pkt, data_offset); /* data offset */ - } else { - /* DMA RX offset updated through shared area */ - if (dhd->prot->rx_dataoffset) - PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset); - } - /* Actual length of the packet */ - PKTSETLEN(dhd->osh, pkt, ltoh16(rxcmplt_h->data_len)); - - ifidx = rxcmplt_h->cmn_hdr.if_id; - -#if defined(PCIE_D2H_SYNC_BZERO) - memset(buf, 0, msglen); -#endif /* PCIE_D2H_SYNC_BZERO */ - -#ifdef DHD_RX_CHAINING - /* Chain the packets */ - dhd_rxchain_frame(dhd, pkt, ifidx); -#else /* ! DHD_RX_CHAINING */ - /* offset from which data starts is populated in rxstatus0 */ - dhd_bus_rx_frame(dhd->bus, pkt, ifidx, 1); -#endif /* ! DHD_RX_CHAINING */ - -} - -/* Stop protocol: sync w/dongle state. */ -void dhd_prot_stop(dhd_pub_t *dhd) -{ - /* nothing to do for pcie */ -} - -/* Add any protocol-specific data header. - * Caller must reserve prot_hdrlen prepend space. - */ -void BCMFASTPATH -dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) -{ - return; -} - -uint -dhd_prot_hdrlen(dhd_pub_t *dhd, void *PKTBUF) -{ - return 0; -} - - -#define PKTBUF pktbuf - -int BCMFASTPATH -dhd_prot_txdata(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) -{ - unsigned long flags; - dhd_prot_t *prot = dhd->prot; - dhd_pktid_map_handle_t *map; - host_txbuf_post_t *txdesc = NULL; - dmaaddr_t physaddr, meta_physaddr; - uint8 *pktdata; - uint32 pktlen; - uint32 pktid; - uint8 prio; - uint16 flowid = 0; - uint16 alloced = 0; - uint16 headroom; - - msgbuf_ring_t *msg_ring; - - if (!dhd->flow_ring_table) { - return BCME_NORESOURCE; - } - - map = dhd->prot->pktid_map_handle; - - if (!dhd_bus_is_txmode_push(dhd->bus)) { - flow_ring_table_t *flow_ring_table; - flow_ring_node_t *flow_ring_node; - - flowid = (uint16)DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(PKTBUF)); - - flow_ring_table = (flow_ring_table_t *)dhd->flow_ring_table; - flow_ring_node = (flow_ring_node_t *)&flow_ring_table[flowid]; - - msg_ring = (msgbuf_ring_t *)flow_ring_node->prot_info; - } else { - msg_ring = prot->h2dring_txp_subn; - } - - - - DHD_GENERAL_LOCK(dhd, flags); - - /* Create a unique 32-bit packet id */ - pktid = NATIVE_TO_PKTID_RSV(map, PKTBUF); - if (pktid == DHD_PKTID_INVALID) { - DHD_ERROR(("Pktid pool depleted.\n")); - /* - * If we return error here, the caller would queue the packet - * again. So we'll just free the skb allocated in DMA Zone. - * Since we have not freed the original SKB yet the caller would - * requeue the same. - */ - goto err_no_res_pktfree; - } - - /* Reserve space in the circular buffer */ - txdesc = (host_txbuf_post_t *)dhd_alloc_ring_space(dhd, - msg_ring, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); - if (txdesc == NULL) { - void *PKTBUF; - DHD_INFO(("%s:%d: HTOD Msgbuf Not available TxCount = %d\n", - __FUNCTION__, __LINE__, prot->active_tx_count)); - /* Free up the PKTID */ - PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, physaddr, - pktlen, BUFF_TYPE_NO_CHECK); - if (!PKTBUF) { - printf("%s: PKT ID invaild. dump dongle memory.\n", __FUNCTION__); - /* write core dump to file */ -#ifdef DHD_FW_COREDUMP - dhdpcie_mem_dump(dhd->bus); -#endif /* DHD_FW_COREDUMP */ - } - goto err_no_res_pktfree; - } - - /* Extract the data pointer and length information */ - pktdata = PKTDATA(dhd->osh, PKTBUF); - pktlen = PKTLEN(dhd->osh, PKTBUF); - - /* Ethernet header: Copy before we cache flush packet using DMA_MAP */ - bcopy(pktdata, txdesc->txhdr, ETHER_HDR_LEN); - - /* Extract the ethernet header and adjust the data pointer and length */ - pktdata = PKTPULL(dhd->osh, PKTBUF, ETHER_HDR_LEN); - pktlen -= ETHER_HDR_LEN; - - /* Map the data pointer to a DMA-able address */ - physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), pktlen, DMA_TX, PKTBUF, 0); - if (PHYSADDRISZERO(physaddr)) { - DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n")); - ASSERT(0); - } - - /* No need to lock. Save the rest of the packet's metadata */ - NATIVE_TO_PKTID_SAVE(map, PKTBUF, pktid, physaddr, pktlen, - DMA_TX, BUFF_TYPE_DATA_TX); - -#ifdef TXP_FLUSH_NITEMS - if (msg_ring->pend_items_count == 0) - msg_ring->start_addr = (void *)txdesc; - msg_ring->pend_items_count++; -#endif - - /* Form the Tx descriptor message buffer */ - - /* Common message hdr */ - txdesc->cmn_hdr.msg_type = MSG_TYPE_TX_POST; - txdesc->cmn_hdr.if_id = ifidx; - txdesc->flags = BCMPCIE_PKT_FLAGS_FRAME_802_3; - prio = (uint8)PKTPRIO(PKTBUF); - - - txdesc->flags |= (prio & 0x7) << BCMPCIE_PKT_FLAGS_PRIO_SHIFT; - txdesc->seg_cnt = 1; - - txdesc->data_len = htol16((uint16)pktlen); - txdesc->data_buf_addr.high_addr = htol32(PHYSADDRHI(physaddr)); - txdesc->data_buf_addr.low_addr = htol32(PHYSADDRLO(physaddr)); - - /* Move data pointer to keep ether header in local PKTBUF for later reference */ - PKTPUSH(dhd->osh, PKTBUF, ETHER_HDR_LEN); - - /* Handle Tx metadata */ - headroom = (uint16)PKTHEADROOM(dhd->osh, PKTBUF); - if (prot->tx_metadata_offset && (headroom < prot->tx_metadata_offset)) - DHD_ERROR(("No headroom for Metadata tx %d %d\n", - prot->tx_metadata_offset, headroom)); - - if (prot->tx_metadata_offset && (headroom >= prot->tx_metadata_offset)) { - DHD_TRACE(("Metadata in tx %d\n", prot->tx_metadata_offset)); - - /* Adjust the data pointer to account for meta data in DMA_MAP */ - PKTPUSH(dhd->osh, PKTBUF, prot->tx_metadata_offset); - meta_physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), - prot->tx_metadata_offset, DMA_RX, PKTBUF, 0); - if (PHYSADDRISZERO(meta_physaddr)) { - DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n")); - ASSERT(0); - } - - /* Adjust the data pointer back to original value */ - PKTPULL(dhd->osh, PKTBUF, prot->tx_metadata_offset); - - txdesc->metadata_buf_len = prot->tx_metadata_offset; - txdesc->metadata_buf_addr.high_addr = htol32(PHYSADDRHI(meta_physaddr)); - txdesc->metadata_buf_addr.low_addr = htol32(PHYSADDRLO(meta_physaddr)); - } - else { - txdesc->metadata_buf_len = htol16(0); - txdesc->metadata_buf_addr.high_addr = 0; - txdesc->metadata_buf_addr.low_addr = 0; - } - -#if defined(DHD_PKTID_AUDIT_RING) - DHD_PKTID_AUDIT(prot->pktid_map_handle, pktid, - DHD_DUPLICATE_ALLOC); -#endif /* DHD_PKTID_AUDIT_RING */ - - txdesc->cmn_hdr.request_id = htol32(pktid); - - DHD_TRACE(("txpost: data_len %d, pktid 0x%04x\n", txdesc->data_len, - txdesc->cmn_hdr.request_id)); - - /* Update the write pointer in TCM & ring bell */ -#ifdef TXP_FLUSH_NITEMS - /* Flush if we have either hit the txp_threshold or if this msg is */ - /* occupying the last slot in the flow_ring - before wrap around. */ - if ((msg_ring->pend_items_count == prot->txp_threshold) || - ((uint8 *) txdesc == (uint8 *) HOST_RING_END(msg_ring))) { - dhd_prot_txdata_write_flush(dhd, flowid, TRUE); - } -#else - prot_ring_write_complete(dhd, msg_ring, txdesc, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); -#endif - - prot->active_tx_count++; - - /* - * Take a wake lock, do not sleep if we have atleast one packet - * to finish. - */ - if (prot->active_tx_count >= 1) - DHD_TXFL_WAKE_LOCK_TIMEOUT(dhd, MAX_TX_TIMEOUT); - - DHD_GENERAL_UNLOCK(dhd, flags); - - return BCME_OK; - -err_no_res_pktfree: - - - - DHD_GENERAL_UNLOCK(dhd, flags); - return BCME_NORESOURCE; - -} - -/* called with a lock */ -void BCMFASTPATH -dhd_prot_txdata_write_flush(dhd_pub_t *dhd, uint16 flowid, bool in_lock) -{ -#ifdef TXP_FLUSH_NITEMS - unsigned long flags = 0; - flow_ring_table_t *flow_ring_table; - flow_ring_node_t *flow_ring_node; - msgbuf_ring_t *msg_ring; - - if (!dhd->flow_ring_table) - return; - - if (!in_lock) { - DHD_GENERAL_LOCK(dhd, flags); - } - - flow_ring_table = (flow_ring_table_t *)dhd->flow_ring_table; - flow_ring_node = (flow_ring_node_t *)&flow_ring_table[flowid]; - msg_ring = (msgbuf_ring_t *)flow_ring_node->prot_info; - - /* Update the write pointer in TCM & ring bell */ - if (msg_ring->pend_items_count) { - prot_ring_write_complete(dhd, msg_ring, msg_ring->start_addr, - msg_ring->pend_items_count); - msg_ring->pend_items_count = 0; - msg_ring->start_addr = NULL; - } - - if (!in_lock) { - DHD_GENERAL_UNLOCK(dhd, flags); - } -#endif /* TXP_FLUSH_NITEMS */ -} - -#undef PKTBUF /* Only defined in the above routine */ -int BCMFASTPATH -dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pkt, uchar *buf, uint *len) -{ - return 0; -} - -static void BCMFASTPATH -dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint16 rxcnt) -{ - dhd_prot_t *prot = dhd->prot; - - if (prot->rxbufpost >= rxcnt) { - prot->rxbufpost -= rxcnt; - } else { - /* ASSERT(0); */ - prot->rxbufpost = 0; - } - - if (prot->rxbufpost <= (prot->max_rxbufpost - RXBUFPOST_THRESHOLD)) - dhd_msgbuf_rxbuf_post(dhd); - - return; -} - - - -/* Use protocol to issue ioctl to dongle */ -int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) -{ - dhd_prot_t *prot = dhd->prot; - int ret = -1; - uint8 action; - - if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - goto done; - } - -#ifdef DHD_USE_IDLECOUNT - if (!bus_wake(dhd->bus)) { - DHD_ERROR(("%s : bus_wake returns 0\n", __FUNCTION__)); - } -#endif /* DHD_USE_IDLECOUNT */ - - if (dhd->busstate == DHD_BUS_SUSPEND) { - DHD_ERROR(("%s : bus is suspended, bus->suspend[%d], bus->host_suspended[%d]\n", - __FUNCTION__, dhd->bus->suspended, dhd->bus->host_suspend)); - goto done; - } - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(len <= WLC_IOCTL_MAXLEN); - - if (len > WLC_IOCTL_MAXLEN) - goto done; - - /* All sanity done ... we either go ahead and run the IOCTL or - * wait for our turn based on the availability of the mutex. - */ - mutex_lock(&prot->ioctl_mutex); - - if (prot->pending == TRUE) { - DHD_ERROR(("packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", - ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, - (unsigned long)prot->lastcmd)); - if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { - DHD_TRACE(("iovar cmd=%s\n", (char*)buf)); - } - /* With mutex in place we should never see this. That is - * we make prot->pending = TRUE only after grabbing the - * mutex, and release the mutex only after making pending - * as FALSE. So there won't be a scenario where we get - * the mutex and find prot->pending as TRUE. Neverthless - * handling this scenario. - */ - mutex_unlock(&prot->ioctl_mutex); - goto done; - } - - prot->pending = TRUE; - prot->lastcmd = ioc->cmd; - action = ioc->set; - - - if (action & WL_IOCTL_ACTION_SET) { - ret = dhd_msgbuf_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - } else { - ret = dhdmsgbuf_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - if (ret > 0) - ioc->used = ret; - } - /* Too many programs assume ioctl() returns 0 on success */ - if (ret >= 0) { - ret = 0; - } else { -#ifndef CUSTOMER_HW5 - DHD_ERROR(("%s: status ret value is %d \n", __FUNCTION__, ret)); -#endif /* CUSTOMER_HW5 */ - dhd->dongle_error = ret; - } - - /* Intercept the wme_dp ioctl here */ - if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { - int slen, val = 0; - - slen = strlen("wme_dp") + 1; - if (len >= (int)(slen + sizeof(int))) - bcopy(((char *)buf + slen), &val, sizeof(int)); - dhd->wme_dp = (uint8) ltoh32(val); - } - - - prot->pending = FALSE; - - /* Release the lock if there are other contexts waiting to fire an - * IOCTL, they'll grab this lock and proceed. - */ - mutex_unlock(&prot->ioctl_mutex); -done: - return ret; - -} - -int -dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len) -{ - unsigned long flags; - dhd_prot_t *prot = dhd->prot; - uint16 alloced = 0; - - ioct_reqst_hdr_t *ioct_rqst; - - uint16 hdrlen = sizeof(ioct_reqst_hdr_t); - uint16 msglen = len + hdrlen; - - - if (msglen > MSGBUF_MAX_MSG_SIZE) - msglen = MSGBUF_MAX_MSG_SIZE; - - msglen = align(msglen, DMA_ALIGN_LEN); - - DHD_GENERAL_LOCK(dhd, flags); - ioct_rqst = (ioct_reqst_hdr_t *)dhd_alloc_ring_space(dhd, - prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); - - if (ioct_rqst == NULL) { - DHD_GENERAL_UNLOCK(dhd, flags); - return 0; - } - - { - uint8 *ptr; - uint16 i; - - ptr = (uint8 *)ioct_rqst; - for (i = 0; i < msglen; i++) { - ptr[i] = i % 256; - } - } - - - /* Common msg buf hdr */ - ioct_rqst->msg.msg_type = MSG_TYPE_LOOPBACK; - ioct_rqst->msg.if_id = 0; - - bcm_print_bytes("LPBK REQ: ", (uint8 *)ioct_rqst, msglen); - - /* Update the write pointer in TCM & ring bell */ - prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, ioct_rqst, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - DHD_GENERAL_UNLOCK(dhd, flags); - - return 0; -} - -void dmaxfer_free_dmaaddr(dhd_pub_t *dhd, dhd_dmaxfer_t *dma) -{ - if (dma == NULL) - return; - - if (dma->srcmem.va) { - DMA_FREE_CONSISTENT(dhd->osh, dma->srcmem.va, - dma->len, dma->srcmem.pa, dma->srcmem.dmah); - dma->srcmem.va = NULL; - } - if (dma->destmem.va) { - DMA_FREE_CONSISTENT(dhd->osh, dma->destmem.va, - dma->len + 8, dma->destmem.pa, dma->destmem.dmah); - dma->destmem.va = NULL; - } -} - -int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, - uint srcdelay, uint destdelay, dhd_dmaxfer_t *dma) -{ - uint i; - - if (!dma) - return BCME_ERROR; - - /* First free up exisiting buffers */ - dmaxfer_free_dmaaddr(dhd, dma); - - dma->srcmem.va = DMA_ALLOC_CONSISTENT(dhd->osh, len, DMA_ALIGN_LEN, - &i, &dma->srcmem.pa, &dma->srcmem.dmah); - if (dma->srcmem.va == NULL) { - return BCME_NOMEM; - } - - /* Populate source with a pattern */ - for (i = 0; i < len; i++) { - ((uint8*)dma->srcmem.va)[i] = i % 256; - } - OSL_CACHE_FLUSH(dma->srcmem.va, len); - - dma->destmem.va = DMA_ALLOC_CONSISTENT(dhd->osh, len + 8, DMA_ALIGN_LEN, - &i, &dma->destmem.pa, &dma->destmem.dmah); - if (dma->destmem.va == NULL) { - DMA_FREE_CONSISTENT(dhd->osh, dma->srcmem.va, - dma->len, dma->srcmem.pa, dma->srcmem.dmah); - dma->srcmem.va = NULL; - return BCME_NOMEM; - } - - - /* Clear the destination buffer */ - bzero(dma->destmem.va, len +8); - OSL_CACHE_FLUSH(dma->destmem.va, len+8); - - dma->len = len; - dma->srcdelay = srcdelay; - dma->destdelay = destdelay; - - return BCME_OK; -} - -static void -dhdmsgbuf_dmaxfer_compare(dhd_pub_t *dhd, void * buf, uint16 msglen) -{ - dhd_prot_t *prot = dhd->prot; - - OSL_CACHE_INV(prot->dmaxfer.destmem.va, prot->dmaxfer.len); - if (prot->dmaxfer.srcmem.va && prot->dmaxfer.destmem.va) { - if (memcmp(prot->dmaxfer.srcmem.va, - prot->dmaxfer.destmem.va, - prot->dmaxfer.len)) { - bcm_print_bytes("XFER SRC: ", - prot->dmaxfer.srcmem.va, prot->dmaxfer.len); - bcm_print_bytes("XFER DEST: ", - prot->dmaxfer.destmem.va, prot->dmaxfer.len); - } - else { - DHD_INFO(("DMA successful\n")); - } - } - dmaxfer_free_dmaaddr(dhd, &prot->dmaxfer); - dhd->prot->dmaxfer_in_progress = FALSE; -} - -int -dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd, uint len, uint srcdelay, uint destdelay) -{ - unsigned long flags; - int ret = BCME_OK; - dhd_prot_t *prot = dhd->prot; - pcie_dma_xfer_params_t *dmap; - uint32 xferlen = len > DMA_XFER_LEN_LIMIT ? DMA_XFER_LEN_LIMIT : len; - uint16 msglen = sizeof(pcie_dma_xfer_params_t); - uint16 alloced = 0; - - if (prot->dmaxfer_in_progress) { - DHD_ERROR(("DMA is in progress...\n")); - return ret; - } - prot->dmaxfer_in_progress = TRUE; - if ((ret = dmaxfer_prepare_dmaaddr(dhd, xferlen, srcdelay, destdelay, - &prot->dmaxfer)) != BCME_OK) { - prot->dmaxfer_in_progress = FALSE; - return ret; - } - - - if (msglen > MSGBUF_MAX_MSG_SIZE) - msglen = MSGBUF_MAX_MSG_SIZE; - - msglen = align(msglen, DMA_ALIGN_LEN); - - DHD_GENERAL_LOCK(dhd, flags); - dmap = (pcie_dma_xfer_params_t *)dhd_alloc_ring_space(dhd, - prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); - - if (dmap == NULL) { - dmaxfer_free_dmaaddr(dhd, &prot->dmaxfer); - prot->dmaxfer_in_progress = FALSE; - DHD_GENERAL_UNLOCK(dhd, flags); - return BCME_NOMEM; - } - - /* Common msg buf hdr */ - dmap->cmn_hdr.msg_type = MSG_TYPE_LPBK_DMAXFER; - dmap->cmn_hdr.request_id = 0x1234; - - dmap->host_input_buf_addr.high = htol32(PHYSADDRHI(prot->dmaxfer.srcmem.pa)); - dmap->host_input_buf_addr.low = htol32(PHYSADDRLO(prot->dmaxfer.srcmem.pa)); - dmap->host_ouput_buf_addr.high = htol32(PHYSADDRHI(prot->dmaxfer.destmem.pa)); - dmap->host_ouput_buf_addr.low = htol32(PHYSADDRLO(prot->dmaxfer.destmem.pa)); - dmap->xfer_len = htol32(prot->dmaxfer.len); - dmap->srcdelay = htol32(prot->dmaxfer.srcdelay); - dmap->destdelay = htol32(prot->dmaxfer.destdelay); - - /* Update the write pointer in TCM & ring bell */ - prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, dmap, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - DHD_GENERAL_UNLOCK(dhd, flags); - - DHD_ERROR(("DMA Started...\n")); - - return BCME_OK; -} - -static int -dhdmsgbuf_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - dhd_prot_t *prot = dhd->prot; - - int ret = 0; - uint copylen = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (cmd == WLC_GET_VAR && buf) - { - if (!len || !*(uint8 *)buf) { - DHD_ERROR(("%s(): Zero length bailing\n", __FUNCTION__)); - ret = BCME_BADARG; - goto done; - } - - /* Respond "bcmerror" and "bcmerrorstr" with local cache */ - copylen = MIN(len, BCME_STRLEN); - - if ((len >= strlen("bcmerrorstr")) && - (!strcmp((char *)buf, "bcmerrorstr"))) { - - strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), copylen); - *(uint8 *)((uint8 *)buf + (copylen - 1)) = '\0'; - - goto done; - } else if ((len >= strlen("bcmerror")) && - !strcmp((char *)buf, "bcmerror")) { - - *(uint32 *)(uint32 *)buf = dhd->dongle_error; - - goto done; - } - } - - ret = dhd_fillup_ioct_reqst_ptrbased(dhd, (uint16)len, cmd, buf, ifidx); - if (ret < 0) { - DHD_ERROR(("%s : dhd_fillup_ioct_reqst_ptrbased error : %d\n", __FUNCTION__, ret)); - return ret; - } - - DHD_INFO(("ACTION %d ifdix %d cmd %d len %d \n", - action, ifidx, cmd, len)); - - /* wait for interrupt and get first fragment */ - ret = dhdmsgbuf_cmplt(dhd, prot->reqid, len, buf, prot->retbuf.va); - -done: - return ret; -} -static int -dhdmsgbuf_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len, void* buf, void* retbuf) -{ - dhd_prot_t *prot = dhd->prot; - ioctl_comp_resp_msg_t ioct_resp; - void* pkt = NULL; - int retlen; - int msgbuf_len = 0; - int post_cnt = 0; - unsigned long flags; - bool zero_posted = FALSE; - uint32 pktid; - int ret = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); - ret = -1; - goto out; - } - - if (prot->cur_ioctlresp_bufs_posted) - prot->cur_ioctlresp_bufs_posted--; - else - zero_posted = TRUE; - - post_cnt = dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd); - if (zero_posted && (post_cnt <= 0)) { - ret = -1; - goto out; - } - - memset(&ioct_resp, 0, sizeof(ioctl_comp_resp_msg_t)); - - retlen = dhd_bus_rxctl(dhd->bus, (uchar*)&ioct_resp, msgbuf_len); - if (retlen <= 0) { - DHD_ERROR(("IOCTL request failed with error code %d\n", retlen)); - ret = retlen; - goto out; - } - - pktid = ioct_resp.cmn_hdr.request_id; /* no need for ltoh32 */ - -#if defined(DHD_PKTID_AUDIT_RING) - DHD_PKTID_AUDIT(prot->pktid_map_handle, pktid, DHD_DUPLICATE_FREE); -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_INFO(("ioctl resp retlen %d status %d, resp_len %d, pktid %d\n", - retlen, ioct_resp.compl_hdr.status, ioct_resp.resp_len, pktid)); - if (ioct_resp.resp_len != 0) { - DHD_GENERAL_LOCK(dhd, flags); - pkt = dhd_prot_packet_get(dhd, pktid, BUFF_TYPE_IOCTL_RX); - DHD_GENERAL_UNLOCK(dhd, flags); - - DHD_INFO(("ioctl ret buf %p retlen %d status %x \n", pkt, retlen, - ioct_resp.compl_hdr.status)); - /* get ret buf */ - if ((buf) && (pkt)) { - /* bcopy(PKTDATA(dhd->osh, pkt), buf, ioct_resp.resp_len); */ - /* ioct_resp.resp_len could have been changed to make it > 8 bytes */ - bcopy(PKTDATA(dhd->osh, pkt), buf, len); - } - if (pkt) { -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) - PKTFREE_STATIC(dhd->osh, pkt, FALSE); -#else - PKTFREE(dhd->osh, pkt, FALSE); -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ - } - } else { - DHD_GENERAL_LOCK(dhd, flags); - dhd_prot_packet_free(dhd, pktid, BUFF_TYPE_IOCTL_RX); - DHD_GENERAL_UNLOCK(dhd, flags); - } - - ret = (int)(ioct_resp.compl_hdr.status); - -out: - DHD_GENERAL_LOCK(dhd, flags); - dhd->ioctl_state = 0; - DHD_GENERAL_UNLOCK(dhd, flags); - - return ret; -} -static int -dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - dhd_prot_t *prot = dhd->prot; - - int ret = 0; - - DHD_TRACE(("%s: Enter \n", __FUNCTION__)); - DHD_TRACE(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - return -EIO; - } - - /* don't talk to the dongle if fw is about to be reloaded */ - if (dhd->hang_was_sent) { - DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", - __FUNCTION__)); - return -EIO; - } - - /* Fill up msgbuf for ioctl req */ - ret = dhd_fillup_ioct_reqst_ptrbased(dhd, (uint16)len, cmd, buf, ifidx); - if (ret < 0) { - DHD_ERROR(("%s : dhd_fillup_ioct_reqst_ptrbased error : %d\n", __FUNCTION__, ret)); - return ret; - } - - DHD_INFO(("ACTIOn %d ifdix %d cmd %d len %d \n", - action, ifidx, cmd, len)); - - ret = dhdmsgbuf_cmplt(dhd, prot->reqid, len, buf, prot->retbuf.va); - - return ret; -} -/* Handles a protocol control response asynchronously */ -int dhd_prot_ctl_complete(dhd_pub_t *dhd) -{ - return 0; -} - -/* Check for and handle local prot-specific iovar commands */ -int dhd_prot_iovar_op(dhd_pub_t *dhd, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - return BCME_UNSUPPORTED; -} - -/* Add prot dump output to a buffer */ -void dhd_prot_dump(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) -{ -#if defined(PCIE_D2H_SYNC) - if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM) - bcm_bprintf(strbuf, "\nd2h_sync: SEQNUM:"); - else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM) - bcm_bprintf(strbuf, "\nd2h_sync: XORCSUM:"); - else - bcm_bprintf(strbuf, "\nd2h_sync: NONE:"); - bcm_bprintf(strbuf, " d2h_sync_wait max<%lu> tot<%lu>\n", - dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot); -#endif /* PCIE_D2H_SYNC */ -} - -/* Update local copy of dongle statistics */ -void dhd_prot_dstats(dhd_pub_t *dhd) -{ - return; -} - -int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, - uint reorder_info_len, void **pkt, uint32 *free_buf_count) -{ - return 0; -} -/* post a dummy message to interrupt dongle */ -/* used to process cons commands */ -int -dhd_post_dummy_msg(dhd_pub_t *dhd) -{ - unsigned long flags; - hostevent_hdr_t *hevent = NULL; - uint16 alloced = 0; - - dhd_prot_t *prot = dhd->prot; - - DHD_GENERAL_LOCK(dhd, flags); - hevent = (hostevent_hdr_t *)dhd_alloc_ring_space(dhd, - prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); - - if (hevent == NULL) { - DHD_GENERAL_UNLOCK(dhd, flags); - return -1; - } - - /* CMN msg header */ - hevent->msg.msg_type = MSG_TYPE_HOST_EVNT; - hevent->msg.if_id = 0; - - /* Event payload */ - hevent->evnt_pyld = htol32(HOST_EVENT_CONS_CMD); - - /* Since, we are filling the data directly into the bufptr obtained - * from the msgbuf, we can directly call the write_complete - */ - prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, hevent, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - DHD_GENERAL_UNLOCK(dhd, flags); - - return 0; -} - -static void * BCMFASTPATH -dhd_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced) -{ - void * ret_buf; - uint16 r_index = 0; - - /* Alloc space for nitems in the ring */ - ret_buf = prot_get_ring_space(ring, nitems, alloced); - - if (ret_buf == NULL) { - /* if alloc failed , invalidate cached read ptr */ - if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) { - r_index = dhd_get_dmaed_index(dhd, H2D_DMA_READINDX, ring->idx); - ring->ringstate->r_offset = r_index; - } else - dhd_bus_cmn_readshared(dhd->bus, &(RING_READ_PTR(ring)), - RING_READ_PTR, ring->idx); - - /* Try allocating once more */ - ret_buf = prot_get_ring_space(ring, nitems, alloced); - - if (ret_buf == NULL) { - DHD_INFO(("RING space not available on ring %s for %d items \n", - ring->name, nitems)); - DHD_INFO(("write %d read %d \n\n", RING_WRITE_PTR(ring), - RING_READ_PTR(ring))); - return NULL; - } - } - - /* Return alloced space */ - return ret_buf; -} - -/* Non inline ioct request */ -/* Form a ioctl request first as per ioctptr_reqst_hdr_t header in the circular buffer */ -/* Form a separate request buffer where a 4 byte cmn header is added in the front */ -/* buf contents from parent function is copied to remaining section of this buffer */ -static int -dhd_fillup_ioct_reqst_ptrbased(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx) -{ - dhd_prot_t *prot = dhd->prot; - ioctl_req_msg_t *ioct_rqst; - void * ioct_buf; /* For ioctl payload */ - uint16 rqstlen, resplen; - unsigned long flags; - uint16 alloced = 0; - - rqstlen = len; - resplen = len; - - /* Limit ioct request to MSGBUF_MAX_MSG_SIZE bytes including hdrs */ - /* 8K allocation of dongle buffer fails */ - /* dhd doesnt give separate input & output buf lens */ - /* so making the assumption that input length can never be more than 1.5k */ - rqstlen = MIN(rqstlen, MSGBUF_MAX_MSG_SIZE); - - DHD_GENERAL_LOCK(dhd, flags); - - if (dhd->ioctl_state) { - DHD_ERROR(("%s: pending ioctl %02x\n", __FUNCTION__, dhd->ioctl_state)); - DHD_GENERAL_UNLOCK(dhd, flags); - return BCME_BUSY; - } else { - dhd->ioctl_state = MSGBUF_IOCTL_ACK_PENDING | MSGBUF_IOCTL_RESP_PENDING; - } - - /* Request for cbuf space */ - ioct_rqst = (ioctl_req_msg_t*)dhd_alloc_ring_space(dhd, prot->h2dring_ctrl_subn, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); - if (ioct_rqst == NULL) { - dhd->ioctl_state = 0; - DHD_ERROR(("couldn't allocate space on msgring to send ioctl request\n")); - DHD_GENERAL_UNLOCK(dhd, flags); - return -1; - } - - /* Common msg buf hdr */ - ioct_rqst->cmn_hdr.msg_type = MSG_TYPE_IOCTLPTR_REQ; - ioct_rqst->cmn_hdr.if_id = (uint8)ifidx; - ioct_rqst->cmn_hdr.flags = 0; - ioct_rqst->cmn_hdr.request_id = DHD_IOCTL_REQ_PKTID; - - ioct_rqst->cmd = htol32(cmd); - ioct_rqst->output_buf_len = htol16(resplen); - ioct_rqst->trans_id = prot->ioctl_trans_id ++; - - /* populate ioctl buffer info */ - ioct_rqst->input_buf_len = htol16(rqstlen); - ioct_rqst->host_input_buf_addr.high = htol32(PHYSADDRHI(prot->ioctbuf.pa)); - ioct_rqst->host_input_buf_addr.low = htol32(PHYSADDRLO(prot->ioctbuf.pa)); - /* copy ioct payload */ - ioct_buf = (void *) prot->ioctbuf.va; - - if (buf) - memcpy(ioct_buf, buf, len); - - OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, len); - - if ((ulong)ioct_buf % DMA_ALIGN_LEN) - DHD_ERROR(("host ioct address unaligned !!!!! \n")); - - DHD_CTL(("submitted IOCTL request request_id %d, cmd %d, output_buf_len %d, tx_id %d\n", - ioct_rqst->cmn_hdr.request_id, cmd, ioct_rqst->output_buf_len, - ioct_rqst->trans_id)); - - /* upd wrt ptr and raise interrupt */ - prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, ioct_rqst, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - DHD_GENERAL_UNLOCK(dhd, flags); - - return 0; -} - -/* Packet to PacketID mapper */ -typedef struct { - ulong native; - dmaaddr_t pa; - uint32 pa_len; - uchar dma; -} pktid_t; - -typedef struct { - void *osh; - void *mwbmap_hdl; - pktid_t *pktid_list; - uint32 count; -} pktid_map_t; - - -void *pktid_map_init(void *osh, uint32 count) -{ - pktid_map_t *handle; - - handle = (pktid_map_t *) MALLOC(osh, sizeof(pktid_map_t)); - if (handle == NULL) { - printf("%s:%d: MALLOC failed for size %d\n", - __FUNCTION__, __LINE__, (uint32) sizeof(pktid_map_t)); - return NULL; - } - handle->osh = osh; - handle->count = count; - handle->mwbmap_hdl = bcm_mwbmap_init(osh, count); - if (handle->mwbmap_hdl == NULL) { - printf("%s:%d: bcm_mwbmap_init failed for count %d\n", - __FUNCTION__, __LINE__, count); - MFREE(osh, handle, sizeof(pktid_map_t)); - return NULL; - } - - handle->pktid_list = (pktid_t *) MALLOC(osh, sizeof(pktid_t) * (count+1)); - if (handle->pktid_list == NULL) { - printf("%s:%d: MALLOC failed for count %d / total = %d\n", - __FUNCTION__, __LINE__, count, (uint32) sizeof(pktid_t) * count); - bcm_mwbmap_fini(osh, handle->mwbmap_hdl); - MFREE(osh, handle, sizeof(pktid_map_t)); - return NULL; - } - - return handle; -} - -void -pktid_map_uninit(void *pktid_map_handle) -{ - pktid_map_t *handle = (pktid_map_t *) pktid_map_handle; - uint32 ix; - - if (handle != NULL) { - void *osh = handle->osh; - for (ix = 0; ix < MAX_PKTID_ITEMS; ix++) - { - if (!bcm_mwbmap_isfree(handle->mwbmap_hdl, ix)) { - /* Mark the slot as free */ - bcm_mwbmap_free(handle->mwbmap_hdl, ix); - /* - Here we can do dma unmapping for 32 bit also. - Since this in removal path, it will not affect performance - */ - DMA_UNMAP(osh, handle->pktid_list[ix+1].pa, - (uint) handle->pktid_list[ix+1].pa_len, - handle->pktid_list[ix+1].dma, 0, 0); - PKTFREE(osh, (unsigned long*)handle->pktid_list[ix+1].native, TRUE); - } - } - bcm_mwbmap_fini(osh, handle->mwbmap_hdl); - MFREE(osh, handle->pktid_list, sizeof(pktid_t) * (handle->count+1)); - MFREE(osh, handle, sizeof(pktid_map_t)); - } - return; -} - -uint32 BCMFASTPATH -pktid_map_unique(void *pktid_map_handle, void *pkt, dmaaddr_t physaddr, uint32 physlen, uint32 dma) -{ - uint32 id; - pktid_map_t *handle = (pktid_map_t *) pktid_map_handle; - - if (handle == NULL) { - printf("%s:%d: Error !!! pktid_map_unique called without initing pktid_map\n", - __FUNCTION__, __LINE__); - return 0; - } - id = bcm_mwbmap_alloc(handle->mwbmap_hdl); - if (id == BCM_MWBMAP_INVALID_IDX) { - printf("%s:%d: bcm_mwbmap_alloc failed. Free Count = %d\n", - __FUNCTION__, __LINE__, bcm_mwbmap_free_cnt(handle->mwbmap_hdl)); - return 0; - } - - /* id=0 is invalid as we use this for error checking in the dongle */ - id += 1; - handle->pktid_list[id].native = (ulong) pkt; - handle->pktid_list[id].pa = physaddr; - handle->pktid_list[id].pa_len = (uint32) physlen; - handle->pktid_list[id].dma = (uchar)dma; - - return id; -} - -void * BCMFASTPATH -pktid_get_packet(void *pktid_map_handle, uint32 id, dmaaddr_t *physaddr, uint32 *physlen) -{ - void *native = NULL; - pktid_map_t *handle = (pktid_map_t *) pktid_map_handle; - if (handle == NULL) { - printf("%s:%d: Error !!! pktid_get_packet called without initing pktid_map\n", - __FUNCTION__, __LINE__); - return NULL; - } - - /* Debug check */ - if (bcm_mwbmap_isfree(handle->mwbmap_hdl, (id-1))) { - printf("%s:%d: Error !!!. slot (%d/0x%04x) free but the app is using it.\n", - __FUNCTION__, __LINE__, (id-1), (id-1)); - return NULL; - } - - native = (void *) handle->pktid_list[id].native; - *physaddr = handle->pktid_list[id].pa; - *physlen = (uint32) handle->pktid_list[id].pa_len; - - /* Mark the slot as free */ - bcm_mwbmap_free(handle->mwbmap_hdl, (id-1)); - - return native; -} -static msgbuf_ring_t* -prot_ring_attach(dhd_prot_t * prot, char* name, uint16 max_item, uint16 len_item, uint16 ringid) -{ - uint alloced = 0; - msgbuf_ring_t *ring; - dmaaddr_t physaddr; - uint16 size; - - ASSERT(name); - BCM_REFERENCE(physaddr); - - /* allocate ring info */ - ring = MALLOC(prot->osh, sizeof(msgbuf_ring_t)); - if (ring == NULL) { - ASSERT(0); - return NULL; - } - bzero(ring, sizeof(*ring)); - - /* Init name */ - strncpy(ring->name, name, sizeof(ring->name) - 1); - - /* Ringid in the order given in bcmpcie.h */ - ring->idx = ringid; - - /* init ringmem */ - ring->ringmem = MALLOC(prot->osh, sizeof(ring_mem_t)); - if (ring->ringmem == NULL) - goto fail; - bzero(ring->ringmem, sizeof(*ring->ringmem)); - - ring->ringmem->max_item = max_item; - ring->ringmem->len_items = len_item; - size = max_item * len_item; - - /* Ring Memmory allocation */ - ring->ring_base.va = DMA_ALLOC_CONSISTENT(prot->osh, size, DMA_ALIGN_LEN, - &alloced, &ring->ring_base.pa, &ring->ring_base.dmah); - - if (ring->ring_base.va == NULL) - goto fail; - ring->ringmem->base_addr.high_addr = htol32(PHYSADDRHI(ring->ring_base.pa)); - ring->ringmem->base_addr.low_addr = htol32(PHYSADDRLO(ring->ring_base.pa)); - - ASSERT(MODX((unsigned long)ring->ring_base.va, DMA_ALIGN_LEN) == 0); - bzero(ring->ring_base.va, size); - - OSL_CACHE_FLUSH((void *) ring->ring_base.va, size); - - /* Ring state init */ - ring->ringstate = MALLOC(prot->osh, sizeof(ring_state_t)); - if (ring->ringstate == NULL) - goto fail; - bzero(ring->ringstate, sizeof(*ring->ringstate)); - - DHD_INFO(("RING_ATTACH : %s Max item %d len item %d total size %d " - "ring start %p buf phys addr %x:%x \n", - ring->name, ring->ringmem->max_item, ring->ringmem->len_items, - size, ring->ring_base.va, ring->ringmem->base_addr.high_addr, - ring->ringmem->base_addr.low_addr)); - return ring; -fail: - if (ring->ring_base.va && ring->ringmem) { - PHYSADDRHISET(physaddr, ring->ringmem->base_addr.high_addr); - PHYSADDRLOSET(physaddr, ring->ringmem->base_addr.low_addr); - size = ring->ringmem->max_item * ring->ringmem->len_items; - DMA_FREE_CONSISTENT(prot->osh, ring->ring_base.va, size, ring->ring_base.pa, NULL); - ring->ring_base.va = NULL; - } - if (ring->ringmem) - MFREE(prot->osh, ring->ringmem, sizeof(ring_mem_t)); - MFREE(prot->osh, ring, sizeof(msgbuf_ring_t)); - ASSERT(0); - return NULL; -} -static void -dhd_ring_init(dhd_pub_t *dhd, msgbuf_ring_t *ring) -{ - /* update buffer address of ring */ - dhd_bus_cmn_writeshared(dhd->bus, &ring->ringmem->base_addr, - sizeof(ring->ringmem->base_addr), RING_BUF_ADDR, ring->idx); - - /* Update max items possible in ring */ - dhd_bus_cmn_writeshared(dhd->bus, &ring->ringmem->max_item, - sizeof(ring->ringmem->max_item), RING_MAX_ITEM, ring->idx); - - /* Update length of each item in the ring */ - dhd_bus_cmn_writeshared(dhd->bus, &ring->ringmem->len_items, - sizeof(ring->ringmem->len_items), RING_LEN_ITEMS, ring->idx); - - /* ring inited */ - ring->inited = TRUE; -} -static void -dhd_prot_ring_detach(dhd_pub_t *dhd, msgbuf_ring_t * ring) -{ - dmaaddr_t phyaddr; - uint16 size; - dhd_prot_t *prot = dhd->prot; - - BCM_REFERENCE(phyaddr); - - if (ring == NULL) - return; - - - if (ring->ringmem == NULL) { - DHD_ERROR(("%s: ring->ringmem is NULL\n", __FUNCTION__)); - return; - } - - ring->inited = FALSE; - - PHYSADDRHISET(phyaddr, ring->ringmem->base_addr.high_addr); - PHYSADDRLOSET(phyaddr, ring->ringmem->base_addr.low_addr); - size = ring->ringmem->max_item * ring->ringmem->len_items; - /* Free up ring */ - if (ring->ring_base.va) { - DMA_FREE_CONSISTENT(prot->osh, ring->ring_base.va, size, ring->ring_base.pa, - ring->ring_base.dmah); - ring->ring_base.va = NULL; - } - - /* Free up ring mem space */ - if (ring->ringmem) { - MFREE(prot->osh, ring->ringmem, sizeof(ring_mem_t)); - ring->ringmem = NULL; - } - - /* Free up ring state info */ - if (ring->ringstate) { - MFREE(prot->osh, ring->ringstate, sizeof(ring_state_t)); - ring->ringstate = NULL; - } - - /* free up ring info */ - MFREE(prot->osh, ring, sizeof(msgbuf_ring_t)); -} -/* Assumes only one index is updated ata time */ -static void *BCMFASTPATH -prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced) -{ - void *ret_ptr = NULL; - uint16 ring_avail_cnt; - - ASSERT(nitems <= RING_MAX_ITEM(ring)); - - ring_avail_cnt = CHECK_WRITE_SPACE(RING_READ_PTR(ring), RING_WRITE_PTR(ring), - RING_MAX_ITEM(ring)); - - if (ring_avail_cnt == 0) { - return NULL; - } - *alloced = MIN(nitems, ring_avail_cnt); - - /* Return next available space */ - ret_ptr = (char*)HOST_RING_BASE(ring) + (RING_WRITE_PTR(ring) * RING_LEN_ITEMS(ring)); - - /* Update write pointer */ - if ((RING_WRITE_PTR(ring) + *alloced) == RING_MAX_ITEM(ring)) - RING_WRITE_PTR(ring) = 0; - else if ((RING_WRITE_PTR(ring) + *alloced) < RING_MAX_ITEM(ring)) - RING_WRITE_PTR(ring) += *alloced; - else { - /* Should never hit this */ - ASSERT(0); - return NULL; - } - - return ret_ptr; -} - -static void BCMFASTPATH -prot_ring_write_complete(dhd_pub_t *dhd, msgbuf_ring_t * ring, void* p, uint16 nitems) -{ - dhd_prot_t *prot = dhd->prot; - - /* cache flush */ - OSL_CACHE_FLUSH(p, RING_LEN_ITEMS(ring) * nitems); - - /* update write pointer */ - /* If dma'ing h2d indices are supported - * update the values in the host memory - * o/w update the values in TCM - */ - if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) - dhd_set_dmaed_index(dhd, H2D_DMA_WRITEINDX, - ring->idx, (uint16)RING_WRITE_PTR(ring)); - else - dhd_bus_cmn_writeshared(dhd->bus, &(RING_WRITE_PTR(ring)), - sizeof(uint16), RING_WRITE_PTR, ring->idx); - - /* raise h2d interrupt */ - prot->mb_ring_fn(dhd->bus, RING_WRITE_PTR(ring)); -} - -/* If dma'ing h2d indices are supported - * this function updates the indices in - * the host memory - */ -static void -dhd_set_dmaed_index(dhd_pub_t *dhd, uint8 type, uint16 ringid, uint16 new_index) -{ - dhd_prot_t *prot = dhd->prot; - - uint32 *ptr = NULL; - uint16 offset = 0; - - switch (type) { - case H2D_DMA_WRITEINDX: - ptr = (uint32 *)(prot->h2d_dma_writeindx_buf.va); - - /* Flow-Rings start at Id BCMPCIE_COMMON_MSGRINGS - * but in host memory their indices start - * after H2D Common Rings - */ - if (ringid >= BCMPCIE_COMMON_MSGRINGS) - offset = ringid - BCMPCIE_COMMON_MSGRINGS + - BCMPCIE_H2D_COMMON_MSGRINGS; - else - offset = ringid; - ptr += offset; - - *ptr = htol16(new_index); - - /* cache flush */ - OSL_CACHE_FLUSH((void *)prot->h2d_dma_writeindx_buf.va, - prot->h2d_dma_writeindx_buf_len); - - break; - - case D2H_DMA_READINDX: - ptr = (uint32 *)(prot->d2h_dma_readindx_buf.va); - - /* H2D Common Righs start at Id BCMPCIE_H2D_COMMON_MSGRINGS */ - offset = ringid - BCMPCIE_H2D_COMMON_MSGRINGS; - ptr += offset; - - *ptr = htol16(new_index); - /* cache flush */ - OSL_CACHE_FLUSH((void *)prot->d2h_dma_readindx_buf.va, - prot->d2h_dma_readindx_buf_len); - - break; - - default: - DHD_ERROR(("%s: Invalid option for DMAing read/write index\n", - __FUNCTION__)); - - break; - } - DHD_TRACE(("%s: Data 0x%p, ringId %d, new_index %d\n", - __FUNCTION__, ptr, ringid, new_index)); -} - - -static uint16 -dhd_get_dmaed_index(dhd_pub_t *dhd, uint8 type, uint16 ringid) -{ - uint32 *ptr = NULL; - uint16 data = 0; - uint16 offset = 0; - - switch (type) { - case H2D_DMA_WRITEINDX: - OSL_CACHE_INV((void *)dhd->prot->h2d_dma_writeindx_buf.va, - dhd->prot->h2d_dma_writeindx_buf_len); - ptr = (uint32 *)(dhd->prot->h2d_dma_writeindx_buf.va); - - /* Flow-Rings start at Id BCMPCIE_COMMON_MSGRINGS - * but in host memory their indices start - * after H2D Common Rings - */ - if (ringid >= BCMPCIE_COMMON_MSGRINGS) - offset = ringid - BCMPCIE_COMMON_MSGRINGS + - BCMPCIE_H2D_COMMON_MSGRINGS; - else - offset = ringid; - ptr += offset; - - data = LTOH16((uint16)*ptr); - break; - - case H2D_DMA_READINDX: - OSL_CACHE_INV((void *)dhd->prot->h2d_dma_readindx_buf.va, - dhd->prot->h2d_dma_readindx_buf_len); - ptr = (uint32 *)(dhd->prot->h2d_dma_readindx_buf.va); - - /* Flow-Rings start at Id BCMPCIE_COMMON_MSGRINGS - * but in host memory their indices start - * after H2D Common Rings - */ - if (ringid >= BCMPCIE_COMMON_MSGRINGS) - offset = ringid - BCMPCIE_COMMON_MSGRINGS + - BCMPCIE_H2D_COMMON_MSGRINGS; - else - offset = ringid; - ptr += offset; - - data = LTOH16((uint16)*ptr); - break; - - case D2H_DMA_WRITEINDX: - OSL_CACHE_INV((void *)dhd->prot->d2h_dma_writeindx_buf.va, - dhd->prot->d2h_dma_writeindx_buf_len); - ptr = (uint32 *)(dhd->prot->d2h_dma_writeindx_buf.va); - - /* H2D Common Righs start at Id BCMPCIE_H2D_COMMON_MSGRINGS */ - offset = ringid - BCMPCIE_H2D_COMMON_MSGRINGS; - ptr += offset; - - data = LTOH16((uint16)*ptr); - break; - - case D2H_DMA_READINDX: - OSL_CACHE_INV((void *)dhd->prot->d2h_dma_readindx_buf.va, - dhd->prot->d2h_dma_readindx_buf_len); - ptr = (uint32 *)(dhd->prot->d2h_dma_readindx_buf.va); - - /* H2D Common Righs start at Id BCMPCIE_H2D_COMMON_MSGRINGS */ - offset = ringid - BCMPCIE_H2D_COMMON_MSGRINGS; - ptr += offset; - - data = LTOH16((uint16)*ptr); - break; - - default: - DHD_ERROR(("%s: Invalid option for DMAing read/write index\n", - __FUNCTION__)); - - break; - } - DHD_TRACE(("%s: Data 0x%p, data %d\n", __FUNCTION__, ptr, data)); - return (data); -} - -/* D2H dircetion: get next space to read from */ -static uint8* -prot_get_src_addr(dhd_pub_t *dhd, msgbuf_ring_t * ring, uint16* available_len) -{ - uint16 w_ptr; - uint16 r_ptr; - uint16 depth; - void* ret_addr = NULL; - uint16 d2h_w_index = 0; - - DHD_TRACE(("%s: h2d_dma_readindx_buf %p, d2h_dma_writeindx_buf %p\n", - __FUNCTION__, (uint32 *)(dhd->prot->h2d_dma_readindx_buf.va), - (uint32 *)(dhd->prot->d2h_dma_writeindx_buf.va))); - - /* update write pointer */ - if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) { - /* DMAing write/read indices supported */ - d2h_w_index = dhd_get_dmaed_index(dhd, D2H_DMA_WRITEINDX, ring->idx); - ring->ringstate->w_offset = d2h_w_index; - } else - dhd_bus_cmn_readshared(dhd->bus, - &(RING_WRITE_PTR(ring)), RING_WRITE_PTR, ring->idx); - - w_ptr = ring->ringstate->w_offset; - r_ptr = ring->ringstate->r_offset; - depth = ring->ringmem->max_item; - - /* check for avail space */ - *available_len = READ_AVAIL_SPACE(w_ptr, r_ptr, depth); - if (*available_len == 0) - return NULL; - - if (*available_len > ring->ringmem->max_item) { - DHD_ERROR(("%s: *available_len %d, ring->ringmem->max_item %d\n", - __FUNCTION__, *available_len, ring->ringmem->max_item)); - return NULL; - } - - /* if space available, calculate address to be read */ - ret_addr = (char*)ring->ring_base.va + (r_ptr * ring->ringmem->len_items); - - /* update read pointer */ - if ((ring->ringstate->r_offset + *available_len) >= ring->ringmem->max_item) - ring->ringstate->r_offset = 0; - else - ring->ringstate->r_offset += *available_len; - - ASSERT(ring->ringstate->r_offset < ring->ringmem->max_item); - - /* convert index to bytes */ - *available_len = *available_len * ring->ringmem->len_items; - - /* Cache invalidate */ - OSL_CACHE_INV((void *) ret_addr, *available_len); - - /* return read address */ - return ret_addr; -} -static void -prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) -{ - /* update read index */ - /* If dma'ing h2d indices supported - * update the r -indices in the - * host memory o/w in TCM - */ - if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) - dhd_set_dmaed_index(dhd, D2H_DMA_READINDX, - ring->idx, (uint16)RING_READ_PTR(ring)); - else - dhd_bus_cmn_writeshared(dhd->bus, &(RING_READ_PTR(ring)), - sizeof(uint16), RING_READ_PTR, ring->idx); -} - -static void -prot_store_rxcpln_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) -{ - dhd_prot_t *prot; - - if (!dhd || !dhd->prot) - return; - - prot = dhd->prot; - prot->rx_cpln_early_upd_idx = RING_READ_PTR(ring); -} - -static void -prot_early_upd_rxcpln_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) -{ - dhd_prot_t *prot; - - if (!dhd || !dhd->prot) - return; - - prot = dhd->prot; - - if (prot->rx_cpln_early_upd_idx == RING_READ_PTR(ring)) - return; - - if (++prot->rx_cpln_early_upd_idx >= RING_MAX_ITEM(ring)) - prot->rx_cpln_early_upd_idx = 0; - - if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) - dhd_set_dmaed_index(dhd, D2H_DMA_READINDX, - ring->idx, (uint16)prot->rx_cpln_early_upd_idx); - else - dhd_bus_cmn_writeshared(dhd->bus, &(prot->rx_cpln_early_upd_idx), - sizeof(uint16), RING_READ_PTR, ring->idx); -} - -int -dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) -{ - tx_flowring_create_request_t *flow_create_rqst; - msgbuf_ring_t *msgbuf_flow_info; - dhd_prot_t *prot = dhd->prot; - uint16 hdrlen = sizeof(tx_flowring_create_request_t); - uint16 msglen = hdrlen; - unsigned long flags; - uint16 alloced = 0; - - if (!(msgbuf_flow_info = prot_ring_attach(prot, "h2dflr", - H2DRING_TXPOST_MAX_ITEM, H2DRING_TXPOST_ITEMSIZE, - BCMPCIE_H2D_TXFLOWRINGID + - (flow_ring_node->flowid - BCMPCIE_H2D_COMMON_MSGRINGS)))) { - DHD_ERROR(("%s: kmalloc for H2D TX Flow ring failed\n", __FUNCTION__)); - return BCME_NOMEM; - } - /* Clear write pointer of the ring */ - flow_ring_node->prot_info = (void *)msgbuf_flow_info; - - /* align it to 4 bytes, so that all start addr form cbuf is 4 byte aligned */ - msglen = align(msglen, DMA_ALIGN_LEN); - - - DHD_GENERAL_LOCK(dhd, flags); - /* Request for ring buffer space */ - flow_create_rqst = (tx_flowring_create_request_t *)dhd_alloc_ring_space(dhd, - prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); - - if (flow_create_rqst == NULL) { - DHD_ERROR(("%s: No space in control ring for Flow create req\n", __FUNCTION__)); - DHD_GENERAL_UNLOCK(dhd, flags); - return BCME_NOMEM; - } - msgbuf_flow_info->inited = TRUE; - - /* Common msg buf hdr */ - flow_create_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_CREATE; - flow_create_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; - flow_create_rqst->msg.request_id = htol16(0); /* TBD */ - - /* Update flow create message */ - flow_create_rqst->tid = flow_ring_node->flow_info.tid; - flow_create_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); - memcpy(flow_create_rqst->sa, flow_ring_node->flow_info.sa, sizeof(flow_create_rqst->sa)); - memcpy(flow_create_rqst->da, flow_ring_node->flow_info.da, sizeof(flow_create_rqst->da)); - flow_create_rqst->flow_ring_ptr.low_addr = msgbuf_flow_info->ringmem->base_addr.low_addr; - flow_create_rqst->flow_ring_ptr.high_addr = msgbuf_flow_info->ringmem->base_addr.high_addr; - flow_create_rqst->max_items = htol16(H2DRING_TXPOST_MAX_ITEM); - flow_create_rqst->len_item = htol16(H2DRING_TXPOST_ITEMSIZE); - DHD_ERROR(("%s Send Flow create Req msglen flow ID %d for peer " MACDBG - " prio %d ifindex %d\n", __FUNCTION__, flow_ring_node->flowid, - MAC2STRDBG(flow_ring_node->flow_info.da), flow_ring_node->flow_info.tid, - flow_ring_node->flow_info.ifindex)); - - /* upd wrt ptr and raise interrupt */ - prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, flow_create_rqst, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - - /* If dma'ing indices supported - * update the w-index in host memory o/w in TCM - */ - if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) - dhd_set_dmaed_index(dhd, H2D_DMA_WRITEINDX, - msgbuf_flow_info->idx, (uint16)RING_WRITE_PTR(msgbuf_flow_info)); - else - dhd_bus_cmn_writeshared(dhd->bus, &(RING_WRITE_PTR(msgbuf_flow_info)), - sizeof(uint16), RING_WRITE_PTR, msgbuf_flow_info->idx); - DHD_GENERAL_UNLOCK(dhd, flags); - - return BCME_OK; -} - -static void -dhd_prot_process_flow_ring_create_response(dhd_pub_t *dhd, void* buf, uint16 msglen) -{ - tx_flowring_create_response_t *flow_create_resp = (tx_flowring_create_response_t *)buf; - - DHD_ERROR(("%s Flow create Response status = %d Flow %d\n", __FUNCTION__, - flow_create_resp->cmplt.status, flow_create_resp->cmplt.flow_ring_id)); - - dhd_bus_flow_ring_create_response(dhd->bus, flow_create_resp->cmplt.flow_ring_id, - flow_create_resp->cmplt.status); -} - -void dhd_prot_clean_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info) -{ - msgbuf_ring_t *flow_ring = (msgbuf_ring_t *)msgbuf_flow_info; - dhd_prot_ring_detach(dhd, flow_ring); - DHD_INFO(("%s Cleaning up Flow \n", __FUNCTION__)); -} - -void dhd_prot_print_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info, - struct bcmstrbuf *strbuf) -{ - msgbuf_ring_t *flow_ring = (msgbuf_ring_t *)msgbuf_flow_info; - uint16 rd, wrt; - dhd_bus_cmn_readshared(dhd->bus, &rd, RING_READ_PTR, flow_ring->idx); - dhd_bus_cmn_readshared(dhd->bus, &wrt, RING_WRITE_PTR, flow_ring->idx); - bcm_bprintf(strbuf, "RD %d WR %d\n", rd, wrt); -} - -void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) -{ - bcm_bprintf(strbuf, "CtrlPost: "); - dhd_prot_print_flow_ring(dhd, dhd->prot->h2dring_ctrl_subn, strbuf); - bcm_bprintf(strbuf, "CtrlCpl: "); - dhd_prot_print_flow_ring(dhd, dhd->prot->d2hring_ctrl_cpln, strbuf); - bcm_bprintf(strbuf, "RxPost: "); - bcm_bprintf(strbuf, "RBP %d ", dhd->prot->rxbufpost); - dhd_prot_print_flow_ring(dhd, dhd->prot->h2dring_rxp_subn, strbuf); - bcm_bprintf(strbuf, "RxCpl: "); - dhd_prot_print_flow_ring(dhd, dhd->prot->d2hring_rx_cpln, strbuf); - if (dhd_bus_is_txmode_push(dhd->bus)) { - bcm_bprintf(strbuf, "TxPost: "); - dhd_prot_print_flow_ring(dhd, dhd->prot->h2dring_txp_subn, strbuf); - } - bcm_bprintf(strbuf, "TxCpl: "); - dhd_prot_print_flow_ring(dhd, dhd->prot->d2hring_tx_cpln, strbuf); - bcm_bprintf(strbuf, "active_tx_count %d pktidmap_avail %d\n", - dhd->prot->active_tx_count, - dhd_pktid_map_avail_cnt(dhd->prot->pktid_map_handle)); -} - -int -dhd_prot_flow_ring_delete(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) -{ - tx_flowring_delete_request_t *flow_delete_rqst; - dhd_prot_t *prot = dhd->prot; - uint16 msglen = sizeof(tx_flowring_delete_request_t); - unsigned long flags; - uint16 alloced = 0; - - /* align it to 4 bytes, so that all start addr form cbuf is 4 byte aligned */ - msglen = align(msglen, DMA_ALIGN_LEN); - - /* Request for ring buffer space */ - DHD_GENERAL_LOCK(dhd, flags); - flow_delete_rqst = (tx_flowring_delete_request_t *)dhd_alloc_ring_space(dhd, - prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); - - if (flow_delete_rqst == NULL) { - DHD_GENERAL_UNLOCK(dhd, flags); - DHD_ERROR(("%s Flow Delete req failure no ring mem %d \n", __FUNCTION__, msglen)); - return BCME_NOMEM; - } - - /* Common msg buf hdr */ - flow_delete_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_DELETE; - flow_delete_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; - flow_delete_rqst->msg.request_id = htol16(0); /* TBD */ - - /* Update Delete info */ - flow_delete_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); - flow_delete_rqst->reason = htol16(BCME_OK); - - DHD_ERROR(("%s sending FLOW RING ID %d for peer " MACDBG " prio %d ifindex %d" - " Delete req msglen %d\n", __FUNCTION__, flow_ring_node->flowid, - MAC2STRDBG(flow_ring_node->flow_info.da), flow_ring_node->flow_info.tid, - flow_ring_node->flow_info.ifindex, msglen)); - - /* upd wrt ptr and raise interrupt */ - prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, flow_delete_rqst, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - DHD_GENERAL_UNLOCK(dhd, flags); - - return BCME_OK; -} - -static void -dhd_prot_process_flow_ring_delete_response(dhd_pub_t *dhd, void* buf, uint16 msglen) -{ - tx_flowring_delete_response_t *flow_delete_resp = (tx_flowring_delete_response_t *)buf; - - DHD_INFO(("%s Flow Delete Response status = %d \n", __FUNCTION__, - flow_delete_resp->cmplt.status)); - -#ifdef PCIE_TX_DEFERRAL - if (flow_delete_resp->cmplt.status != BCME_OK) { - DHD_ERROR(("%s Flow Delete Response failure error status = %d \n", - __FUNCTION__, flow_delete_resp->cmplt.status)); - return; - } - set_bit(flow_delete_resp->cmplt.flow_ring_id, dhd->bus->delete_flow_map); - queue_work(dhd->bus->tx_wq, &dhd->bus->delete_flow_work); -#else - dhd_bus_flow_ring_delete_response(dhd->bus, flow_delete_resp->cmplt.flow_ring_id, - flow_delete_resp->cmplt.status); -#endif /* PCIE_TX_DEFERRAL */ -} - -int -dhd_prot_flow_ring_flush(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) -{ - tx_flowring_flush_request_t *flow_flush_rqst; - dhd_prot_t *prot = dhd->prot; - uint16 msglen = sizeof(tx_flowring_flush_request_t); - unsigned long flags; - uint16 alloced = 0; - - /* align it to 4 bytes, so that all start addr form cbuf is 4 byte aligned */ - msglen = align(msglen, DMA_ALIGN_LEN); - - /* Request for ring buffer space */ - DHD_GENERAL_LOCK(dhd, flags); - flow_flush_rqst = (tx_flowring_flush_request_t *)dhd_alloc_ring_space(dhd, - prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); - if (flow_flush_rqst == NULL) { - DHD_GENERAL_UNLOCK(dhd, flags); - DHD_ERROR(("%s Flow Flush req failure no ring mem %d \n", __FUNCTION__, msglen)); - return BCME_NOMEM; - } - - /* Common msg buf hdr */ - flow_flush_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_FLUSH; - flow_flush_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; - flow_flush_rqst->msg.request_id = htol16(0); /* TBD */ - - flow_flush_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); - flow_flush_rqst->reason = htol16(BCME_OK); - - DHD_INFO(("%s sending FLOW RING Flush req msglen %d \n", __FUNCTION__, msglen)); - - /* upd wrt ptr and raise interrupt */ - prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, flow_flush_rqst, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - DHD_GENERAL_UNLOCK(dhd, flags); - - return BCME_OK; -} - -static void -dhd_prot_process_flow_ring_flush_response(dhd_pub_t *dhd, void* buf, uint16 msglen) -{ - tx_flowring_flush_response_t *flow_flush_resp = (tx_flowring_flush_response_t *)buf; - - DHD_INFO(("%s Flow Flush Response status = %d \n", __FUNCTION__, - flow_flush_resp->cmplt.status)); - - dhd_bus_flow_ring_flush_response(dhd->bus, flow_flush_resp->cmplt.flow_ring_id, - flow_flush_resp->cmplt.status); -} - -int -dhd_prot_ringupd_dump(dhd_pub_t *dhd, struct bcmstrbuf *b) -{ - uint32 *ptr; - uint32 value; - uint32 i; - uint8 txpush = 0; - uint32 max_h2d_queues = dhd_bus_max_h2d_queues(dhd->bus, &txpush); - - OSL_CACHE_INV((void *)dhd->prot->d2h_dma_writeindx_buf.va, - dhd->prot->d2h_dma_writeindx_buf_len); - - ptr = (uint32 *)(dhd->prot->d2h_dma_writeindx_buf.va); - - bcm_bprintf(b, "\n max_tx_queues %d, txpush mode %d\n", max_h2d_queues, txpush); - - bcm_bprintf(b, "\nRPTR block H2D common rings, 0x%04x\n", ptr); - value = ltoh32(*ptr); - bcm_bprintf(b, "\tH2D CTRL: value 0x%04x\n", value); - ptr++; - value = ltoh32(*ptr); - bcm_bprintf(b, "\tH2D RXPOST: value 0x%04x\n", value); - - if (txpush) { - ptr++; - value = ltoh32(*ptr); - bcm_bprintf(b, "\tH2D TXPOST value 0x%04x\n", value); - } - else { - ptr++; - bcm_bprintf(b, "RPTR block Flow rings , 0x%04x\n", ptr); - for (i = BCMPCIE_H2D_COMMON_MSGRINGS; i < max_h2d_queues; i++) { - value = ltoh32(*ptr); - bcm_bprintf(b, "\tflowring ID %d: value 0x%04x\n", i, value); - ptr++; - } - } - - OSL_CACHE_INV((void *)dhd->prot->h2d_dma_readindx_buf.va, - dhd->prot->h2d_dma_readindx_buf_len); - - ptr = (uint32 *)(dhd->prot->h2d_dma_readindx_buf.va); - - bcm_bprintf(b, "\nWPTR block D2H common rings, 0x%04x\n", ptr); - value = ltoh32(*ptr); - bcm_bprintf(b, "\tD2H CTRLCPLT: value 0x%04x\n", value); - ptr++; - value = ltoh32(*ptr); - bcm_bprintf(b, "\tD2H TXCPLT: value 0x%04x\n", value); - ptr++; - value = ltoh32(*ptr); - bcm_bprintf(b, "\tD2H RXCPLT: value 0x%04x\n", value); - - return 0; -} - -uint32 -dhd_prot_metadatalen_set(dhd_pub_t *dhd, uint32 val, bool rx) -{ - dhd_prot_t *prot = dhd->prot; - if (rx) - prot->rx_metadata_offset = (uint16)val; - else - prot->tx_metadata_offset = (uint16)val; - return dhd_prot_metadatalen_get(dhd, rx); -} - -uint32 -dhd_prot_metadatalen_get(dhd_pub_t *dhd, bool rx) -{ - dhd_prot_t *prot = dhd->prot; - if (rx) - return prot->rx_metadata_offset; - else - return prot->tx_metadata_offset; -} - -uint32 -dhd_prot_txp_threshold(dhd_pub_t *dhd, bool set, uint32 val) -{ - dhd_prot_t *prot = dhd->prot; - if (set) - prot->txp_threshold = (uint16)val; - val = prot->txp_threshold; - return val; -} - -#ifdef DHD_RX_CHAINING -static INLINE void BCMFASTPATH -dhd_rxchain_reset(rxchain_info_t *rxchain) -{ - rxchain->pkt_count = 0; -} - -static void BCMFASTPATH -dhd_rxchain_frame(dhd_pub_t *dhd, void *pkt, uint ifidx) -{ - uint8 *eh; - uint8 prio; - dhd_prot_t *prot = dhd->prot; - rxchain_info_t *rxchain = &prot->rxchain; - - eh = PKTDATA(dhd->osh, pkt); - prio = IP_TOS46(eh + ETHER_HDR_LEN) >> IPV4_TOS_PREC_SHIFT; - - /* For routers, with HNDCTF, link the packets using PKTSETCLINK, */ - /* so that the chain can be handed off to CTF bridge as is. */ - if (rxchain->pkt_count == 0) { - /* First packet in chain */ - rxchain->pkthead = rxchain->pkttail = pkt; - - /* Keep a copy of ptr to ether_da, ether_sa and prio */ - rxchain->h_da = ((struct ether_header *)eh)->ether_dhost; - rxchain->h_sa = ((struct ether_header *)eh)->ether_shost; - rxchain->h_prio = prio; - rxchain->ifidx = ifidx; - rxchain->pkt_count++; - } else { - if (PKT_CTF_CHAINABLE(dhd, ifidx, eh, prio, rxchain->h_sa, - rxchain->h_da, rxchain->h_prio)) { - /* Same flow - keep chaining */ - PKTSETCLINK(rxchain->pkttail, pkt); - rxchain->pkttail = pkt; - rxchain->pkt_count++; - } else { - /* Different flow - First release the existing chain */ - dhd_rxchain_commit(dhd); - - /* Create a new chain */ - rxchain->pkthead = rxchain->pkttail = pkt; - - /* Keep a copy of ptr to ether_da, ether_sa and prio */ - rxchain->h_da = ((struct ether_header *)eh)->ether_dhost; - rxchain->h_sa = ((struct ether_header *)eh)->ether_shost; - rxchain->h_prio = prio; - rxchain->ifidx = ifidx; - rxchain->pkt_count++; - } - } - - if ((!ETHER_ISMULTI(rxchain->h_da)) && - ((((struct ether_header *)eh)->ether_type == HTON16(ETHER_TYPE_IP)) || - (((struct ether_header *)eh)->ether_type == HTON16(ETHER_TYPE_IPV6)))) { - PKTSETCHAINED(dhd->osh, pkt); - PKTCINCRCNT(rxchain->pkthead); - PKTCADDLEN(rxchain->pkthead, PKTLEN(dhd->osh, pkt)); - } else { - dhd_rxchain_commit(dhd); - return; - } - - /* If we have hit the max chain length, dispatch the chain and reset */ - if (rxchain->pkt_count >= DHD_PKT_CTF_MAX_CHAIN_LEN) { - dhd_rxchain_commit(dhd); - } -} - -static void BCMFASTPATH -dhd_rxchain_commit(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - rxchain_info_t *rxchain = &prot->rxchain; - - if (rxchain->pkt_count == 0) - return; - - /* Release the packets to dhd_linux */ - dhd_bus_rx_frame(dhd->bus, rxchain->pkthead, rxchain->ifidx, rxchain->pkt_count); - - /* Reset the chain */ - dhd_rxchain_reset(rxchain); -} -#endif /* DHD_RX_CHAINING */ - -static void -dhd_prot_ring_clear(msgbuf_ring_t* ring) -{ - uint16 size; - - DHD_TRACE(("%s\n", __FUNCTION__)); - - size = ring->ringmem->max_item * ring->ringmem->len_items; - ASSERT(MODX((unsigned long)ring->ring_base.va, DMA_ALIGN_LEN) == 0); - OSL_CACHE_INV((void *) ring->ring_base.va, size); - bzero(ring->ring_base.va, size); - - OSL_CACHE_FLUSH((void *) ring->ring_base.va, size); - - bzero(ring->ringstate, sizeof(*ring->ringstate)); -} - -void -dhd_prot_clear(dhd_pub_t *dhd) -{ - struct dhd_prot *prot = dhd->prot; - - DHD_TRACE(("%s\n", __FUNCTION__)); - - if (prot == NULL) - return; - - if (prot->h2dring_txp_subn) - dhd_prot_ring_clear(prot->h2dring_txp_subn); - if (prot->h2dring_rxp_subn) - dhd_prot_ring_clear(prot->h2dring_rxp_subn); - if (prot->h2dring_ctrl_subn) - dhd_prot_ring_clear(prot->h2dring_ctrl_subn); - if (prot->d2hring_tx_cpln) - dhd_prot_ring_clear(prot->d2hring_tx_cpln); - if (prot->d2hring_rx_cpln) - dhd_prot_ring_clear(prot->d2hring_rx_cpln); - if (prot->d2hring_ctrl_cpln) - dhd_prot_ring_clear(prot->d2hring_ctrl_cpln); - - if (prot->retbuf.va) { - OSL_CACHE_INV((void *) prot->retbuf.va, IOCT_RETBUF_SIZE); - bzero(prot->retbuf.va, IOCT_RETBUF_SIZE); - OSL_CACHE_FLUSH((void *) prot->retbuf.va, IOCT_RETBUF_SIZE); - } - - if (prot->ioctbuf.va) { - OSL_CACHE_INV((void *) prot->ioctbuf.va, IOCT_RETBUF_SIZE); - bzero(prot->ioctbuf.va, IOCT_RETBUF_SIZE); - OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, IOCT_RETBUF_SIZE); - } - - if (prot->d2h_dma_scratch_buf.va) { - OSL_CACHE_INV((void *)prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); - bzero(prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); - OSL_CACHE_FLUSH((void *)prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); - } - - if (prot->h2d_dma_readindx_buf.va) { - OSL_CACHE_INV((void *)prot->h2d_dma_readindx_buf.va, - prot->h2d_dma_readindx_buf_len); - bzero(prot->h2d_dma_readindx_buf.va, - prot->h2d_dma_readindx_buf_len); - OSL_CACHE_FLUSH((void *)prot->h2d_dma_readindx_buf.va, - prot->h2d_dma_readindx_buf_len); - } - - if (prot->h2d_dma_writeindx_buf.va) { - OSL_CACHE_INV((void *)prot->h2d_dma_writeindx_buf.va, - prot->h2d_dma_writeindx_buf_len); - bzero(prot->h2d_dma_writeindx_buf.va, prot->h2d_dma_writeindx_buf_len); - OSL_CACHE_FLUSH((void *)prot->h2d_dma_writeindx_buf.va, - prot->h2d_dma_writeindx_buf_len); - } - - if (prot->d2h_dma_readindx_buf.va) { - OSL_CACHE_INV((void *)prot->d2h_dma_readindx_buf.va, - prot->d2h_dma_readindx_buf_len); - bzero(prot->d2h_dma_readindx_buf.va, prot->d2h_dma_readindx_buf_len); - OSL_CACHE_FLUSH((void *)prot->d2h_dma_readindx_buf.va, - prot->d2h_dma_readindx_buf_len); - } - - if (prot->d2h_dma_writeindx_buf.va) { - OSL_CACHE_INV((void *)prot->d2h_dma_writeindx_buf.va, - prot->d2h_dma_writeindx_buf_len); - bzero(prot->d2h_dma_writeindx_buf.va, prot->d2h_dma_writeindx_buf_len); - OSL_CACHE_FLUSH((void *)prot->d2h_dma_writeindx_buf.va, - prot->d2h_dma_writeindx_buf_len); - } - - prot->rx_metadata_offset = 0; - prot->tx_metadata_offset = 0; - - prot->rxbufpost = 0; - prot->cur_event_bufs_posted = 0; - prot->cur_ioctlresp_bufs_posted = 0; - - prot->active_tx_count = 0; - prot->data_seq_no = 0; - prot->ioctl_seq_no = 0; - prot->pending = 0; - prot->lastcmd = 0; - - prot->ioctl_trans_id = 1; - - /* dhd_flow_rings_init is located at dhd_bus_start, - * so when stopping bus, flowrings shall be deleted - */ - dhd_flow_rings_deinit(dhd); - NATIVE_TO_PKTID_CLEAR(prot->pktid_map_handle); -} diff --git a/drivers/net/wireless/bcmdhd/dhd_pcie.c b/drivers/net/wireless/bcmdhd/dhd_pcie.c deleted file mode 100644 index c27accd66cda..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_pcie.c +++ /dev/null @@ -1,5253 +0,0 @@ -/* - * DHD Bus Module for PCIE - * - * Copyright (C) 1999-2017, Broadcom Corporation - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_pcie.c 680504 2017-01-20 06:13:53Z $ - */ - - -/* include files */ -#include -#include -#include -#include -#include -#include -#include -#if defined(DHD_DEBUG) -#include -#include -#endif /* defined(DHD_DEBUG) */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef DHDTCPACK_SUPPRESS -#include -#endif /* DHDTCPACK_SUPPRESS */ -#include - -#include - -#ifdef BCMEMBEDIMAGE -#include BCMEMBEDIMAGE -#endif /* BCMEMBEDIMAGE */ - -#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ -#define MAX_NVRAMBUF_SIZE 6144 /* max nvram buf size */ - -#define ARMCR4REG_BANKIDX (0x40/sizeof(uint32)) -#define ARMCR4REG_BANKPDA (0x4C/sizeof(uint32)) -/* Temporary war to fix precommit till sync issue between trunk & precommit branch is resolved */ - -#if defined(SUPPORT_MULTIPLE_BOARD_REV) - extern unsigned int system_rev; -#endif /* SUPPORT_MULTIPLE_BOARD_REV */ - -int dhd_dongle_memsize; -int dhd_dongle_ramsize; -#ifdef DHD_DEBUG -static int dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size); -static int dhdpcie_bus_readconsole(dhd_bus_t *bus); -#endif /* DHD_DEBUG */ - -#if defined(DHD_FW_COREDUMP) -int dhdpcie_mem_dump(dhd_bus_t *bus); -#endif /* DHD_FW_COREDUMP */ - -static int dhdpcie_bus_membytes(dhd_bus_t *bus, bool write, ulong address, uint8 *data, uint size); -static int dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, - const char *name, void *params, - int plen, void *arg, int len, int val_size); -static int dhdpcie_bus_lpback_req(struct dhd_bus *bus, uint32 intval); -static int dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus, - uint32 len, uint32 srcdelay, uint32 destdelay); -static int dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter); -static int _dhdpcie_download_firmware(struct dhd_bus *bus); -static int dhdpcie_download_firmware(dhd_bus_t *bus, osl_t *osh); -static int dhdpcie_bus_write_vars(dhd_bus_t *bus); -static bool dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus); -static bool dhdpci_bus_read_frames(dhd_bus_t *bus); -static int dhdpcie_readshared(dhd_bus_t *bus); -static void dhdpcie_init_shared_addr(dhd_bus_t *bus); -static bool dhdpcie_dongle_attach(dhd_bus_t *bus); -static void dhdpcie_bus_intr_enable(dhd_bus_t *bus); -static void dhdpcie_bus_dongle_setmemsize(dhd_bus_t *bus, int mem_size); -static void dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, - bool dongle_isolation, bool reset_flag); -static void dhdpcie_bus_release_malloc(dhd_bus_t *bus, osl_t *osh); -static int dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len); -static uint8 dhdpcie_bus_rtcm8(dhd_bus_t *bus, ulong offset); -static void dhdpcie_bus_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data); -static void dhdpcie_bus_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data); -static uint16 dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset); -static void dhdpcie_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data); -static uint32 dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset); -#ifdef DHD_SUPPORT_64BIT -static void dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data); -static uint64 dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset); -#endif /* DHD_SUPPORT_64BIT */ -static void dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data); -#ifdef CONFIG_ARCH_MSM8994 -static void dhdpcie_bus_cfg_set_bar1_win(dhd_bus_t *bus, uint32 data); -static ulong dhd_bus_cmn_check_offset(dhd_bus_t *bus, ulong offset); -#endif -static void dhdpcie_bus_reg_unmap(osl_t *osh, ulong addr, int size); -static int dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b); -static void dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data); -static void dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info); -extern void dhd_dpc_kill(dhd_pub_t *dhdp); -static void dhdpcie_handle_mb_data(dhd_bus_t *bus); - -#ifdef BCMEMBEDIMAGE -static int dhdpcie_download_code_array(dhd_bus_t *bus); -#endif /* BCMEMBEDIMAGE */ - - - -#define PCI_VENDOR_ID_BROADCOM 0x14e4 - -/* IOVar table */ -enum { - IOV_INTR = 1, - IOV_MEMBYTES, - IOV_MEMSIZE, - IOV_SET_DOWNLOAD_STATE, - IOV_DEVRESET, - IOV_VARS, - IOV_MSI_SIM, - IOV_PCIE_LPBK, - IOV_CC_NVMSHADOW, - IOV_RAMSIZE, - IOV_RAMSTART, - IOV_SLEEP_ALLOWED, - IOV_PCIE_DMAXFER, - IOV_PCIE_SUSPEND, - IOV_DONGLEISOLATION, - IOV_LTRSLEEPON_UNLOOAD, - IOV_RX_METADATALEN, - IOV_TX_METADATALEN, - IOV_TXP_THRESHOLD, - IOV_BUZZZ_DUMP, - IOV_DUMP_RINGUPD_BLOCK, - IOV_DMA_RINGINDICES, - IOV_DB1_FOR_MB, - IOV_FLOW_PRIO_MAP, -#ifdef DHD_USE_IDLECOUNT - IOV_IDLETIME, -#endif /* DHD_USE_IDLECOUNT */ - IOV_RXBOUND, - IOV_TXBOUND -}; - - -const bcm_iovar_t dhdpcie_iovars[] = { - {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, - {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, - {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 }, - {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, - {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, - {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, - {"pcie_lpbk", IOV_PCIE_LPBK, 0, IOVT_UINT32, 0 }, - {"cc_nvmshadow", IOV_CC_NVMSHADOW, 0, IOVT_BUFFER, 0 }, - {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 }, - {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 }, - {"pcie_dmaxfer", IOV_PCIE_DMAXFER, 0, IOVT_BUFFER, 3 * sizeof(int32) }, - {"pcie_suspend", IOV_PCIE_SUSPEND, 0, IOVT_UINT32, 0 }, - {"sleep_allowed", IOV_SLEEP_ALLOWED, 0, IOVT_BOOL, 0 }, - {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, - {"ltrsleep_on_unload", IOV_LTRSLEEPON_UNLOOAD, 0, IOVT_UINT32, 0 }, - {"dump_ringupdblk", IOV_DUMP_RINGUPD_BLOCK, 0, IOVT_BUFFER, 0 }, - {"dma_ring_indices", IOV_DMA_RINGINDICES, 0, IOVT_UINT32, 0}, - {"rx_metadata_len", IOV_RX_METADATALEN, 0, IOVT_UINT32, 0 }, - {"tx_metadata_len", IOV_TX_METADATALEN, 0, IOVT_UINT32, 0 }, - {"db1_for_mb", IOV_DB1_FOR_MB, 0, IOVT_UINT32, 0 }, - {"txp_thresh", IOV_TXP_THRESHOLD, 0, IOVT_UINT32, 0 }, - {"buzzz_dump", IOV_BUZZZ_DUMP, 0, IOVT_UINT32, 0 }, - {"flow_prio_map", IOV_FLOW_PRIO_MAP, 0, IOVT_UINT32, 0 }, -#ifdef DHD_USE_IDLECOUNT - {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, -#endif /* DHD_USE_IDLECOUNT */ - {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, - {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -#define MAX_READ_TIMEOUT 5 * 1000 * 1000 - -#ifndef DHD_RXBOUND -#define DHD_RXBOUND 64 -#endif -#ifndef DHD_TXBOUND -#define DHD_TXBOUND 64 -#endif -uint dhd_rxbound = DHD_RXBOUND; -uint dhd_txbound = DHD_TXBOUND; - -/* Register/Unregister functions are called by the main DHD entry - * point (e.g. module insertion) to link with the bus driver, in - * order to look for or await the device. - */ - -int -dhd_bus_register(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - return dhdpcie_bus_register(); -} - -void -dhd_bus_unregister(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - dhdpcie_bus_unregister(); - return; -} - - -/** returns a host virtual address */ -uint32 * -dhdpcie_bus_reg_map(osl_t *osh, ulong addr, int size) -{ - return (uint32 *)REG_MAP(addr, size); -} - -void -dhdpcie_bus_reg_unmap(osl_t *osh, ulong addr, int size) -{ - REG_UNMAP((void*)(uintptr)addr); - return; -} - -/** - * 'regs' is the host virtual address that maps to the start of the PCIe BAR0 window. The first 4096 - * bytes in this window are mapped to the backplane address in the PCIEBAR0Window register. The - * precondition is that the PCIEBAR0Window register 'points' at the PCIe core. - * - * 'tcm' is the *host* virtual address at which tcm is mapped. - */ -dhd_bus_t* dhdpcie_bus_attach(osl_t *osh, volatile char* regs, volatile char* tcm, uint32 tcm_size) -{ - dhd_bus_t *bus; - - DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); - - do { - if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { - DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); - break; - } - bzero(bus, sizeof(dhd_bus_t)); - bus->regs = regs; - bus->tcm = tcm; - bus->tcm_size = tcm_size; - bus->osh = osh; - - dll_init(&bus->const_flowring); - mutex_init(&bus->host_clock_lock); - mutex_init(&bus->pm_lock); - - /* Attach pcie shared structure */ - bus->pcie_sh = MALLOC(osh, sizeof(pciedev_shared_t)); - if (!bus->pcie_sh) { - DHD_ERROR(("%s: MALLOC of bus->pcie_sh failed\n", __FUNCTION__)); - break; - } - - /* dhd_common_init(osh); */ - if (dhdpcie_dongle_attach(bus)) { - DHD_ERROR(("%s: dhdpcie_probe_attach failed\n", __FUNCTION__)); - break; - } - - /* software resources */ - if (!(bus->dhd = dhd_attach(osh, bus, PCMSGBUF_HDRLEN))) { - DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); - - break; - } - bus->dhd->busstate = DHD_BUS_DOWN; - bus->db1_for_mb = TRUE; - bus->dhd->hang_report = TRUE; - - bus->d3_ack_war_cnt = 0; - - DHD_TRACE(("%s: EXIT SUCCESS\n", - __FUNCTION__)); - - return bus; - } while (0); - - DHD_TRACE(("%s: EXIT FAILURE\n", __FUNCTION__)); - - if (bus && bus->pcie_sh) - MFREE(osh, bus->pcie_sh, sizeof(pciedev_shared_t)); - - if (bus) - MFREE(osh, bus, sizeof(dhd_bus_t)); - - return NULL; -} - -uint -dhd_bus_chip(struct dhd_bus *bus) -{ - ASSERT(bus->sih != NULL); - return bus->sih->chip; -} - -uint -dhd_bus_chiprev(struct dhd_bus *bus) -{ - ASSERT(bus); - ASSERT(bus->sih != NULL); - return bus->sih->chiprev; -} - -void * -dhd_bus_pub(struct dhd_bus *bus) -{ - return bus->dhd; -} - -void * -dhd_bus_sih(struct dhd_bus *bus) -{ - return (void *)bus->sih; -} - -void * -dhd_bus_txq(struct dhd_bus *bus) -{ - return &bus->txq; -} - -/* Get Chip ID version */ -uint dhd_bus_chip_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - return bus->sih->chip; -} - -/* Get Chip Rev ID version */ -uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - return bus->sih->chiprev; -} - -/* Get Chip Pkg ID version */ -uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - return bus->sih->chippkg; -} - - -/* - -Name: dhdpcie_bus_isr - -Parametrs: - -1: IN int irq -- interrupt vector -2: IN void *arg -- handle to private data structure - -Return value: - -Status (TRUE or FALSE) - -Description: -Interrupt Service routine checks for the status register, -disable interrupt and queue DPC if mail box interrupts are raised. -*/ - - -int32 -dhdpcie_bus_isr(dhd_bus_t *bus) -{ - - do { - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - /* verify argument */ - if (!bus) { - DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); - break; - } - if (bus->dhd->dongle_reset) { - DHD_ERROR(("%s : dongle reset , exit \n", __FUNCTION__)); - break; - } - - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_TRACE(("%s : bus is down. we have nothing to do\n", - __FUNCTION__)); - break; - } - - /* Overall operation: - * - Mask further interrupts - * - Read/ack intstatus - * - Take action based on bits and state - * - Reenable interrupts (as per state) - */ - - /* Count the interrupt call */ - bus->intrcount++; - - if (bus->ipend && bus->intdis) { - if (bus->lastintrs == 0) { - bus->lastintrs = bus->intrcount; - } else if (bus->intrcount > bus->lastintrs + 10) { - DHD_ERROR(("%s : hang recover, lastintrs %d intrcount %d\n", - __FUNCTION__, bus->lastintrs, bus->intrcount)); - bus->lastintrs = 0; - dhd_os_send_hang_message(bus->dhd); - break; - } - } else { - bus->lastintrs = 0; - } - - /* read interrupt status register!! Status bits will be cleared in DPC !! */ - bus->ipend = TRUE; - dhdpcie_bus_intr_disable(bus); /* Disable interrupt!! */ - -#if defined(PCIE_ISR_THREAD) - - DHD_TRACE(("Calling dhd_bus_dpc() from %s\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK(bus->dhd); - while (dhd_bus_dpc(bus)); - DHD_OS_WAKE_UNLOCK(bus->dhd); -#else - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); /* queue DPC now!! */ -#endif /* defined(SDIO_ISR_THREAD) */ - - DHD_TRACE(("%s: Exit Success DPC Queued\n", __FUNCTION__)); - return TRUE; - - } while (0); - - DHD_TRACE(("%s: Exit Failure\n", __FUNCTION__)); - return FALSE; -} - -static bool -dhdpcie_dongle_attach(dhd_bus_t *bus) -{ - - osl_t *osh = bus->osh; - void *regsva = (void*)bus->regs; - uint16 devid = bus->cl_devid; - uint32 val; - sbpcieregs_t *sbpcieregs; - - DHD_TRACE(("%s: ENTER\n", - __FUNCTION__)); - - - bus->alp_only = TRUE; - bus->sih = NULL; - - /* Set bar0 window to si_enum_base */ - dhdpcie_bus_cfg_set_bar0_win(bus, SI_ENUM_BASE); - -#ifdef CONFIG_ARCH_MSM8994 - /* Read bar1 window */ - bus->bar1_win_base = OSL_PCI_READ_CONFIG(bus->osh, PCI_BAR1_WIN, 4); - DHD_ERROR(("%s: PCI_BAR1_WIN = %x\n", __FUNCTION__, bus->bar1_win_base)); -#endif -#ifdef SOMC_1DK_NV_PATH - bus->subsystem_id = (uint16)((OSL_PCI_READ_CONFIG(osh, PCI_CFG_SVID, 4) >> 16) & 0xffff); - DHD_ERROR(("%s: PCI_CFG_SSID = %d\n", __FUNCTION__, bus->subsystem_id)); -#endif /* SOMC_1DK_NV_PATH */ - /* si_attach() will provide an SI handle and scan the backplane */ - if (!(bus->sih = si_attach((uint)devid, osh, regsva, PCI_BUS, bus, - &bus->vars, &bus->varsz))) { - DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); - goto fail; - } - - - si_setcore(bus->sih, PCIE2_CORE_ID, 0); - sbpcieregs = (sbpcieregs_t*)(bus->regs); - - /* WAR where the BAR1 window may not be sized properly */ - W_REG(osh, &sbpcieregs->configaddr, 0x4e0); - val = R_REG(osh, &sbpcieregs->configdata); -#ifdef CONFIG_ARCH_MSM8994 - bus->bar1_win_mask = 0xffffffff - (bus->tcm_size - 1); - DHD_ERROR(("%s: BAR1 window val=%d mask=%x\n", __FUNCTION__, val, bus->bar1_win_mask)); -#endif - W_REG(osh, &sbpcieregs->configdata, val); - - /* Get info on the ARM and SOCRAM cores... */ - /* Should really be qualified by device id */ - if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || - (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || - (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { - bus->armrev = si_corerev(bus->sih); - } else { - DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); - goto fail; - } - - if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { - DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); - goto fail; - } - } else { - /* cr4 has a different way to find the RAM size from TCM's */ - if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { - DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); - goto fail; - } - /* also populate base address */ - switch ((uint16)bus->sih->chip) { - case BCM4339_CHIP_ID: - case BCM4335_CHIP_ID: - bus->dongle_ram_base = CR4_4335_RAM_BASE; - break; - case BCM4358_CHIP_ID: - case BCM4356_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM43567_CHIP_ID: - case BCM43569_CHIP_ID: - case BCM4350_CHIP_ID: - case BCM43570_CHIP_ID: - bus->dongle_ram_base = CR4_4350_RAM_BASE; - break; - case BCM4360_CHIP_ID: - bus->dongle_ram_base = CR4_4360_RAM_BASE; - break; - case BCM4345_CHIP_ID: - bus->dongle_ram_base = CR4_4345_RAM_BASE; - break; - case BCM43602_CHIP_ID: - bus->dongle_ram_base = CR4_43602_RAM_BASE; - break; - case BCM4349_CHIP_GRPID: - bus->dongle_ram_base = CR4_4349_RAM_BASE; - break; - default: - bus->dongle_ram_base = 0; - DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", - __FUNCTION__, bus->dongle_ram_base)); - } - } - bus->ramsize = bus->orig_ramsize; - if (dhd_dongle_memsize) - dhdpcie_bus_dongle_setmemsize(bus, dhd_dongle_memsize); - - DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", - bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); - - bus->srmemsize = si_socram_srmem_size(bus->sih); - - - bus->def_intmask = PCIE_MB_D2H_MB_MASK | PCIE_MB_TOPCIE_FN0_0 | PCIE_MB_TOPCIE_FN0_1; - - /* Set the poll and/or interrupt flags */ - bus->intr = (bool)dhd_intr; - - bus->wait_for_d3_ack = 1; - bus->suspended = FALSE; - bus->force_suspend = 0; - DHD_TRACE(("%s: EXIT: SUCCESS\n", - __FUNCTION__)); - return 0; - -fail: - if (bus->sih != NULL) - si_detach(bus->sih); - DHD_TRACE(("%s: EXIT: FAILURE\n", - __FUNCTION__)); - return -1; -} - -int -dhpcie_bus_unmask_interrupt(dhd_bus_t *bus) -{ - dhdpcie_bus_cfg_write_dword(bus, PCIIntmask, 4, I_MB); - return 0; -} -int -dhpcie_bus_mask_interrupt(dhd_bus_t *bus) -{ - dhdpcie_bus_cfg_write_dword(bus, PCIIntmask, 4, 0x0); - return 0; -} - -void -dhdpcie_bus_intr_enable(dhd_bus_t *bus) -{ - DHD_TRACE(("enable interrupts\n")); - - if (!bus || !bus->sih) - return; - - bus->intdis = FALSE; - if (bus && bus->dev && bus->dev->irq) { - struct irq_desc *desc = irq_to_desc(bus->dev->irq); - if (desc->depth > 0) { - DHD_INTR(("%s enable_irq irq=%d\n", __FUNCTION__, - bus->dev->irq)); - enable_irq(bus->dev->irq); - } - } - if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || - (bus->sih->buscorerev == 4)) { - dhpcie_bus_unmask_interrupt(bus); - } - else if (bus->sih) { - si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, - bus->def_intmask, bus->def_intmask); - } -} - -void -dhdpcie_bus_intr_disable(dhd_bus_t *bus) -{ - - DHD_TRACE(("%s Enter\n", __FUNCTION__)); - - if (!bus || !bus->sih) - return; - - if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || - (bus->sih->buscorerev == 4)) { - dhpcie_bus_mask_interrupt(bus); - } - else if (bus->sih) { - si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, - bus->def_intmask, 0); - } - if (bus && bus->dev && bus->dev->irq) { - struct irq_desc *desc = irq_to_desc(bus->dev->irq); - if (desc->depth == 0) { - DHD_INTR(("%s disable_irq_nosync irq=%d\n", __FUNCTION__, - bus->dev->irq)); - disable_irq_nosync(bus->dev->irq); - } - } - bus->intdis = TRUE; - - DHD_TRACE(("%s Exit\n", __FUNCTION__)); -} - -void -dhdpcie_bus_remove_prep(dhd_bus_t *bus) -{ - DHD_TRACE(("%s Enter\n", __FUNCTION__)); - - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_TRACE(("%s Exit, bus is already down\n", __FUNCTION__)); - return; - } - dhd_os_sdlock(bus->dhd); - - bus->dhd->busstate = DHD_BUS_DOWN; - dhdpcie_bus_intr_disable(bus); - pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *)(bus->regs)); - - dhd_os_sdunlock(bus->dhd); - - DHD_TRACE(("%s Exit\n", __FUNCTION__)); -} - - -/* Detach and free everything */ -void -dhdpcie_bus_release(dhd_bus_t *bus) -{ - bool dongle_isolation = FALSE; - osl_t *osh = NULL; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus) { - - osh = bus->osh; - ASSERT(osh); - - if (bus->dhd) { - dongle_isolation = bus->dhd->dongle_isolation; - if (bus->intr && (bus->dhd->busstate != DHD_BUS_DOWN)) { - dhdpcie_bus_intr_disable(bus); - dhdpcie_free_irq(bus); - } - dhd_detach(bus->dhd); - dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE); - dhd_free(bus->dhd); - bus->dhd = NULL; - } - - /* unmap the regs and tcm here!! */ - if (bus->regs) { - dhdpcie_bus_reg_unmap(osh, (ulong)bus->regs, DONGLE_REG_MAP_SIZE); - bus->regs = NULL; - } - if (bus->tcm) { - dhdpcie_bus_reg_unmap(osh, (ulong)bus->tcm, bus->tcm_size); - bus->tcm = NULL; - } - - dhdpcie_bus_release_malloc(bus, osh); - /* Detach pcie shared structure */ - if (bus->pcie_sh) - MFREE(osh, bus->pcie_sh, sizeof(pciedev_shared_t)); - -#ifdef DHD_DEBUG - - if (bus->console.buf != NULL) - MFREE(osh, bus->console.buf, bus->console.bufsize); -#endif - - - /* Finally free bus info */ - MFREE(osh, bus, sizeof(dhd_bus_t)); - - } - - DHD_TRACE(("%s: Exit\n", __FUNCTION__)); - -} - - -void -dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) -{ - - DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, - bus->dhd, bus->dhd->dongle_reset)); - - if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) { - DHD_TRACE(("%s Exit\n", __FUNCTION__)); - return; - } - - if (bus->sih) { - - if (!dongle_isolation) - pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *)(bus->regs)); - - if (bus->ltrsleep_on_unload) { - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, u.pcie2.ltr_state), ~0, 0); - } - si_detach(bus->sih); - if (bus->vars && bus->varsz) - MFREE(osh, bus->vars, bus->varsz); - bus->vars = NULL; - } - - DHD_TRACE(("%s Exit\n", __FUNCTION__)); -} - -uint32 -dhdpcie_bus_cfg_read_dword(dhd_bus_t *bus, uint32 addr, uint32 size) -{ - uint32 data = OSL_PCI_READ_CONFIG(bus->osh, addr, size); - return data; -} - -/* 32 bit config write */ -void -dhdpcie_bus_cfg_write_dword(dhd_bus_t *bus, uint32 addr, uint32 size, uint32 data) -{ - OSL_PCI_WRITE_CONFIG(bus->osh, addr, size, data); -} - -void -dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data) -{ - OSL_PCI_WRITE_CONFIG(bus->osh, PCI_BAR0_WIN, 4, data); -} - -#ifdef CONFIG_ARCH_MSM8994 -void -dhdpcie_bus_cfg_set_bar1_win(dhd_bus_t *bus, uint32 data) -{ - OSL_PCI_WRITE_CONFIG(bus->osh, PCI_BAR1_WIN, 4, data); -} -#endif - -void -dhdpcie_bus_dongle_setmemsize(struct dhd_bus *bus, int mem_size) -{ - int32 min_size = DONGLE_MIN_MEMSIZE; - /* Restrict the memsize to user specified limit */ - DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", - dhd_dongle_memsize, min_size)); - if ((dhd_dongle_memsize > min_size) && - (dhd_dongle_memsize < (int32)bus->orig_ramsize)) - bus->ramsize = dhd_dongle_memsize; -} - -void -dhdpcie_bus_release_malloc(dhd_bus_t *bus, osl_t *osh) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd && bus->dhd->dongle_reset) - return; - - if (bus->vars && bus->varsz) { - MFREE(osh, bus->vars, bus->varsz); - bus->vars = NULL; - } - - DHD_TRACE(("%s: Exit\n", __FUNCTION__)); - return; - -} - -/* Stop bus module: clear pending frames, disable data flow */ -void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) -{ - uint32 status; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!bus->dhd) - return; - - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: already down by net_dev_reset\n", __FUNCTION__)); - goto done; - } -#ifdef DHD_USE_IDLECOUNT - bus_wake(bus); -#endif /* DHD_USE_IDLECOUNT */ - - bus->dhd->busstate = DHD_BUS_DOWN; - dhdpcie_bus_intr_disable(bus); - status = dhdpcie_bus_cfg_read_dword(bus, PCIIntstatus, 4); - dhdpcie_bus_cfg_write_dword(bus, PCIIntstatus, 4, status); - if (!dhd_download_fw_on_driverload) - dhd_dpc_kill(bus->dhd); - - /* Clear rx control and wake any waiters */ - bus->rxlen = 0; - dhd_os_ioctl_resp_wake(bus->dhd); - -done: - return; -} - -/* Watchdog timer function */ -bool dhd_bus_watchdog(dhd_pub_t *dhd) -{ - dhd_bus_t *bus = dhd->bus; - - if (bus->dhd->hang_was_sent) { - dhd_os_wd_timer(bus->dhd, 0); - return FALSE; - } - -#ifdef DHD_DEBUG - - - /* Poll for console output periodically */ - if (dhd->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { - bus->console.count += dhd_watchdog_ms; - if (bus->console.count >= dhd_console_ms) { - bus->console.count -= dhd_console_ms; - /* Make sure backplane clock is on */ - if (dhdpcie_bus_readconsole(bus) < 0) - dhd_console_ms = 0; /* On error, stop trying */ - } - } -#endif /* DHD_DEBUG */ - -#ifdef DHD_USE_IDLECOUNT - if (bus->suspended == TRUE || bus->host_suspend == TRUE) { - DHD_ERROR(("bus->suspended : %d, bus->host_suspend : %d\n", - bus->suspended, bus->host_suspend)); - return BCME_BUSY; - } - bus->idlecount++; - - if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) { - bus->idlecount = 0; - bus->host_suspend = TRUE; - bus->bus_wake = 0; - - if (!dhd->up) { - DHD_INFO(("%s: DHD is not up\n", __FUNCTION__)); - return FALSE; - } - - atomic_set(&bus->runtime_suspend, 1); - DHD_ERROR(("%s: DHD Idle state!! - idletime :%d, wdtick :%d \n", - __FUNCTION__, bus->idletime, dhd_watchdog_ms)); - - /* if device suspended, wd needs to turn off */ - if (dhdpcie_set_suspend_resume(bus->dev, TRUE)) { - DHD_ERROR(("%s: runtime suspend failed \n", __FUNCTION__)); - atomic_set(&bus->runtime_suspend, 0); - return FALSE; - } - wait_event_interruptible(bus->rpm_queue, bus->bus_wake); - dhdpcie_set_suspend_resume(bus->dev, FALSE); - atomic_set(&bus->runtime_suspend, 0); - smp_wmb(); - wake_up_interruptible(&bus->rpm_queue); - DHD_ERROR(("%s: Runtime resume ended.\n", __FUNCTION__)); - } - -#endif /* DHD_USE_IDLECOUNT */ - - return FALSE; -} - -#if defined(SUPPORT_MULTIPLE_REVISION) -static int concate_revision_bcm4354(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - uint32 chip_id, chip_ver; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[10] = "_4354"; -#else - char chipver_tag[4] = {0, }; -#endif /* SUPPORT_MULTIPLE_CHIPS */ - - chip_id = si_chipid(bus->sih); - chip_ver = bus->sih->chiprev; - if (chip_ver == 0) { - DHD_ERROR(("----- CHIP 4354 A0 -----\n")); - strcat(chipver_tag, "_a0"); - } else if (chip_ver == 1) { - DHD_ERROR(("----- CHIP 4354 A1 -----\n")); - strcat(chipver_tag, "_a1"); - } else { - DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); - } - - strcat(fw_path, chipver_tag); - strcat(nv_path, chipver_tag); - - return 0; -} - -static int concate_revision_bcm4356(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - uint32 chip_id, chip_ver; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[10] = "_4356"; -#else - char chipver_tag[4] = {0, }; -#endif /* SUPPORT_MULTIPLE_CHIPS */ - - chip_id = si_chipid(bus->sih); - chip_ver = bus->sih->chiprev; - if (chip_ver == 2) { - DHD_ERROR(("----- CHIP 4356 A2 -----\n")); - strcat(chipver_tag, "_a2"); - } else { - DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); - } - - strcat(fw_path, chipver_tag); - strcat(nv_path, chipver_tag); - - return 0; -} - -static int concate_revision_bcm4358(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - uint32 chip_id, chip_ver; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[20] = "_4358"; -#else - char chipver_tag[10] = {0, }; -#endif /* SUPPORT_MULTIPLE_CHIPS */ - - chip_id = si_chipid(bus->sih); - chip_ver = bus->sih->chiprev; - if (chip_ver == 0) { - DHD_ERROR(("----- CHIP 4358 A0 -----\n")); - strcat(chipver_tag, "_a0"); - } else if (chip_ver == 1) { - DHD_ERROR(("----- CHIP 4358 A1 -----\n")); -#if defined(SUPPORT_MULTIPLE_CHIPS) - strcat(chipver_tag, "_a1"); -#endif /* SUPPORT_MULTIPLE_CHIPS */ - } else { - DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); - } - - strcat(fw_path, chipver_tag); -#if defined(SUPPORT_MULTIPLE_BOARD_REV) - if (system_rev >= 10) { - DHD_ERROR(("----- Board Rev [%d]-----\n", system_rev)); - strcat(chipver_tag, "_r10"); - } -#endif /* SUPPORT_MULTIPLE_BOARD_REV */ - strcat(nv_path, chipver_tag); - - return 0; -} - - -int -concate_revision(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - int res = 0; - - if (!bus || !bus->sih) { - DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__)); - return -1; - } - - DHD_ERROR(("concate_revision \n")); - - switch (si_chipid(bus->sih)) { - - case BCM4354_CHIP_ID: - res = concate_revision_bcm4354(bus, fw_path, nv_path); - break; - - case BCM4356_CHIP_ID: - res = concate_revision_bcm4356(bus, fw_path, nv_path); - break; - - case BCM43569_CHIP_ID: - case BCM4358_CHIP_ID: - res = concate_revision_bcm4358(bus, fw_path, nv_path); - break; - - default: - DHD_ERROR(("REVISION SPECIFIC feature is not required\n")); - return res; - } - - return res; -} -#endif /* SUPPORT_MULTIPLE_REVISION */ - - -/* Download firmware image and nvram image */ -int -dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, - char *pfw_path, char *pnv_path) -{ - int ret; - - bus->fw_path = pfw_path; - bus->nv_path = pnv_path; - - ret = dhdpcie_download_firmware(bus, osh); - - return ret; -} - -static int -dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) -{ - int ret = 0; -#if defined(BCM_REQUEST_FW) - uint chipid = bus->sih->chip; - uint revid = bus->sih->chiprev; - char fw_path[64] = "/lib/firmware/brcm/bcm"; /* path to firmware image */ - char nv_path[64]; /* path to nvram vars file */ - bus->fw_path = fw_path; - bus->nv_path = nv_path; - switch (chipid) { - case BCM43570_CHIP_ID: - bcmstrncat(fw_path, "43570", 5); - switch (revid) { - case 0: - bcmstrncat(fw_path, "a0", 2); - break; - case 2: - bcmstrncat(fw_path, "a2", 2); - break; - default: - DHD_ERROR(("%s: revid is not found %x\n", __FUNCTION__, - revid)); - break; - } - break; - default: - DHD_ERROR(("%s: unsupported device %x\n", __FUNCTION__, - chipid)); - return 0; - } - /* load board specific nvram file */ - snprintf(bus->nv_path, sizeof(nv_path), "%s.nvm", fw_path); - /* load firmware */ - snprintf(bus->fw_path, sizeof(fw_path), "%s-firmware.bin", fw_path); -#endif /* BCM_REQUEST_FW */ - -#if defined(SUPPORT_MULTIPLE_REVISION) - if (concate_revision(bus, bus->fw_path, bus->nv_path) != 0) { - DHD_ERROR(("%s: fail to concatnate revison \n", - __FUNCTION__)); - return BCME_BADARG; - } -#endif /* SUPPORT_MULTIPLE_REVISION */ -#ifdef SOMC_1DK_NV_PATH -#define SOMC_SUBSYSTEMID_FOR_1DK_CHIP 0xcdab - if (bus->subsystem_id != 0x0000) { - if (bus->subsystem_id == SOMC_SUBSYSTEMID_FOR_1DK_CHIP) - bus->nv_path = SOMC_1DK_NV_PATH; -#ifdef SOMC_LOW_POWER_NV_PATH - else - bus->nv_path = SOMC_LOW_POWER_NV_PATH; -#endif /* SOMC_LOW_POWER_NV_PATH */ - } -#endif /* SOMC_1DK_NV_PATH */ - DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n", - __FUNCTION__, bus->fw_path, bus->nv_path)); - - DHD_OS_WAKE_LOCK(bus->dhd); - - ret = _dhdpcie_download_firmware(bus); - - DHD_OS_WAKE_UNLOCK(bus->dhd); - return ret; -} - -static int -dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) -{ - int bcmerror = -1; - int offset = 0; - int len; - void *image = NULL; - uint8 *memblock = NULL, *memptr; - - DHD_ERROR(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); - - /* Should succeed in opening image if it is actually given through registry - * entry or in module param. - */ - image = dhd_os_open_image(pfw_path); - if (image == NULL) - goto err; - - memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); - goto err; - } - if ((uint32)(uintptr)memblock % DHD_SDALIGN) - memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); - - /* Download image */ - while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { - if (len < 0) { - DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); - bcmerror = BCME_ERROR; - goto err; - } - /* check if CR4 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - /* if address is 0, store the reset instruction to be written in 0 */ - - if (offset == 0) { - bus->resetinstr = *(((uint32*)memptr)); - /* Add start of RAM address to the address given by user */ - offset += bus->dongle_ram_base; - } - } - - bcmerror = dhdpcie_bus_membytes(bus, TRUE, offset, memptr, len); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - -err: - if (memblock) - MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); - - if (image) - dhd_os_close_image(image); - - return bcmerror; -} - - -static int -dhdpcie_download_nvram(struct dhd_bus *bus) -{ - int bcmerror = -1; - uint len; - void * image = NULL; - char * memblock = NULL; - char *bufp; - char *pnv_path; - bool nvram_file_exists; - - pnv_path = bus->nv_path; - - nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); - if (!nvram_file_exists && (bus->nvram_params == NULL)) - return (0); - - if (nvram_file_exists) { - image = dhd_os_open_image(pnv_path); - if (image == NULL) - goto err; - } - - memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, MAX_NVRAMBUF_SIZE)); - goto err; - } - - /* Download variables */ - if (nvram_file_exists) { - len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); - } - else { - - /* nvram is string with null terminated. cannot use strlen */ - len = bus->nvram_params_len; - ASSERT(len <= MAX_NVRAMBUF_SIZE); - memcpy(memblock, bus->nvram_params, len); - } - if (len > 0 && len < MAX_NVRAMBUF_SIZE) { - bufp = (char *)memblock; - bufp[len] = 0; - - if (somc_txpower_calibrate(memblock, len) != BCME_OK) { - DHD_ERROR(("%s: error calibrating tx power\n", __FUNCTION__)); - goto err; - } - - if (nvram_file_exists) - len = process_nvram_vars(bufp, len); - - if (len % 4) { - len += 4 - (len % 4); - } - bufp += len; - *bufp++ = 0; - if (len) - bcmerror = dhdpcie_downloadvars(bus, memblock, len + 1); - if (bcmerror) { - DHD_ERROR(("%s: error downloading vars: %d\n", - __FUNCTION__, bcmerror)); - } - } - else { - DHD_ERROR(("%s: error reading nvram file: %d\n", - __FUNCTION__, len)); - bcmerror = BCME_ERROR; - } - -err: - if (memblock) - MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); - - if (image) - dhd_os_close_image(image); - - return bcmerror; -} - - -#ifdef BCMEMBEDIMAGE -int -dhdpcie_download_code_array(struct dhd_bus *bus) -{ - int bcmerror = -1; - int offset = 0; - unsigned char *p_dlarray = NULL; - unsigned int dlarray_size = 0; - unsigned int downloded_len, remaining_len, len; - char *p_dlimagename, *p_dlimagever, *p_dlimagedate; - uint8 *memblock = NULL, *memptr; - - downloded_len = 0; - remaining_len = 0; - len = 0; - - p_dlarray = dlarray; - dlarray_size = sizeof(dlarray); - p_dlimagename = dlimagename; - p_dlimagever = dlimagever; - p_dlimagedate = dlimagedate; - - if ((p_dlarray == 0) || (dlarray_size == 0) ||(dlarray_size > bus->ramsize) || - (p_dlimagename == 0) || (p_dlimagever == 0) || (p_dlimagedate == 0)) - goto err; - - memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); - goto err; - } - if ((uint32)(uintptr)memblock % DHD_SDALIGN) - memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); - - while (downloded_len < dlarray_size) { - remaining_len = dlarray_size - downloded_len; - if (remaining_len >= MEMBLOCK) - len = MEMBLOCK; - else - len = remaining_len; - - memcpy(memptr, (p_dlarray + downloded_len), len); - /* check if CR4 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - /* if address is 0, store the reset instruction to be written in 0 */ - if (offset == 0) { - bus->resetinstr = *(((uint32*)memptr)); - /* Add start of RAM address to the address given by user */ - offset += bus->dongle_ram_base; - } - } - bcmerror = dhdpcie_bus_membytes(bus, TRUE, offset, (uint8 *)memptr, len); - downloded_len += len; - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - offset += MEMBLOCK; - } - -#ifdef DHD_DEBUG - /* Upload and compare the downloaded code */ - { - unsigned char *ularray = NULL; - unsigned int uploded_len; - uploded_len = 0; - bcmerror = -1; - ularray = MALLOC(bus->dhd->osh, dlarray_size); - if (ularray == NULL) - goto upload_err; - /* Upload image to verify downloaded contents. */ - offset = bus->dongle_ram_base; - memset(ularray, 0xaa, dlarray_size); - while (uploded_len < dlarray_size) { - remaining_len = dlarray_size - uploded_len; - if (remaining_len >= MEMBLOCK) - len = MEMBLOCK; - else - len = remaining_len; - bcmerror = dhdpcie_bus_membytes(bus, FALSE, offset, - (uint8 *)(ularray + uploded_len), len); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto upload_err; - } - - uploded_len += len; - offset += MEMBLOCK; - } - - if (memcmp(p_dlarray, ularray, dlarray_size)) { - DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", - __FUNCTION__, p_dlimagename, p_dlimagever, p_dlimagedate)); - goto upload_err; - - } else - DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", - __FUNCTION__, p_dlimagename, p_dlimagever, p_dlimagedate)); -upload_err: - if (ularray) - MFREE(bus->dhd->osh, ularray, dlarray_size); - } -#endif /* DHD_DEBUG */ -err: - - if (memblock) - MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); - - return bcmerror; -} -#endif /* BCMEMBEDIMAGE */ - - -static int -_dhdpcie_download_firmware(struct dhd_bus *bus) -{ - int bcmerror = -1; - - bool embed = FALSE; /* download embedded firmware */ - bool dlok = FALSE; /* download firmware succeeded */ - - /* Out immediately if no image to download */ - if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { -#ifdef BCMEMBEDIMAGE - embed = TRUE; -#else - DHD_ERROR(("%s: no fimrware file\n", __FUNCTION__)); - return 0; -#endif - } - - /* Keep arm in reset */ - if (dhdpcie_bus_download_state(bus, TRUE)) { - DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); - goto err; - } - - /* External image takes precedence if specified */ - if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { - if (dhdpcie_download_code_file(bus, bus->fw_path)) { - DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); -#ifdef BCMEMBEDIMAGE - embed = TRUE; -#else - goto err; -#endif - } - else { - embed = FALSE; - dlok = TRUE; - } - } - -#ifdef BCMEMBEDIMAGE - if (embed) { - if (dhdpcie_download_code_array(bus)) { - DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); - goto err; - } - else { - dlok = TRUE; - } - } -#else - BCM_REFERENCE(embed); -#endif - if (!dlok) { - DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); - goto err; - } - - /* EXAMPLE: nvram_array */ - /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ - /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ - - - /* External nvram takes precedence if specified */ - if (dhdpcie_download_nvram(bus)) { - DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); - goto err; - } - - /* Take arm out of reset */ - if (dhdpcie_bus_download_state(bus, FALSE)) { - DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); - goto err; - } - - bcmerror = 0; - -err: - return bcmerror; -} - -int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) -{ - int timeleft; - uint rxlen = 0; - bool pending; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) - return -EIO; - -#ifdef DHD_USE_IDLECOUNT - bus_wake(bus); -#endif /* DHD_USE_IDLECOUNT */ - /* Wait until control frame is available */ - timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); - rxlen = bus->rxlen; - bcopy(&bus->ioct_resp, msg, MIN(rxlen, sizeof(ioctl_comp_resp_msg_t))); - bus->rxlen = 0; - - if (rxlen) { - DHD_CTL(("%s: resumed on rxctl frame, got %d\n", __FUNCTION__, rxlen)); - } else if (timeleft == 0) { - DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); -#ifdef DHD_USE_IDLECOUNT - /* must do bus wake again due to ioctl response timeout */ - bus_wake(bus); -#endif /* DHD_USE_IDLECOUNT */ -#if defined(DHD_FW_COREDUMP) && defined(CUSTOMER_HW5) - if (bus->dhd->rxcnt_timeout == 0) { - /* write core dump to file */ - dhdpcie_mem_dump(bus); - } -#endif - bus->ioct_resp.cmn_hdr.request_id = 0; - bus->ioct_resp.compl_hdr.status = 0xffff; - bus->dhd->rxcnt_timeout++; - DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout)); - } else if (pending == TRUE) { - DHD_CTL(("%s: canceled\n", __FUNCTION__)); - return -ERESTARTSYS; - } else { - DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); - } - - if (timeleft != 0) - bus->dhd->rxcnt_timeout = 0; - - if (rxlen) - bus->dhd->rx_ctlpkts++; - else - bus->dhd->rx_ctlerrs++; - - if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) { -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->islinkdown = TRUE; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - return -ETIMEDOUT; - } - - if (bus->dhd->dongle_trap_occured) { -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->islinkdown = TRUE; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - return -EREMOTEIO; - } - - return rxlen ? (int)rxlen : -EIO; - -} - -#define CONSOLE_LINE_MAX 192 - -#ifdef DHD_DEBUG -static int -dhdpcie_bus_readconsole(dhd_bus_t *bus) -{ - dhd_console_t *c = &bus->console; - uint8 line[CONSOLE_LINE_MAX], ch; - uint32 n, idx, addr; - int rv; - - /* Don't do anything until FWREADY updates console address */ - if (bus->console_addr == 0) - return -1; - - /* Read console log struct */ - addr = bus->console_addr + OFFSETOF(hnd_cons_t, log); - - if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) - return rv; - - /* Allocate console buffer (one time only) */ - if (c->buf == NULL) { - c->bufsize = ltoh32(c->log.buf_size); - if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) - return BCME_NOMEM; - } - idx = ltoh32(c->log.idx); - - /* Protect against corrupt value */ - if (idx > c->bufsize) - return BCME_ERROR; - - /* Skip reading the console buffer if the index pointer has not moved */ - if (idx == c->last) - return BCME_OK; - - /* Read the console buffer */ - addr = ltoh32(c->log.buf); - if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 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; - printf("CONSOLE: %s\n", line); - } - } -break2: - - return BCME_OK; -} -#endif /* DHD_DEBUG */ - -static int -dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size) -{ - int bcmerror = 0; - uint msize = 512; - char *mbuffer = NULL; - char *console_buffer = NULL; - uint maxstrlen = 256; - char *str = NULL; - trap_t tr; - pciedev_shared_t *pciedev_shared = bus->pcie_sh; - struct bcmstrbuf strbuf; - uint32 console_ptr, console_size, console_index; - uint8 line[CONSOLE_LINE_MAX], ch; - uint32 n, i, addr; - int rv; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (DHD_NOCHECKDIED_ON()) { - return 0; - } - - if (data == NULL) { - /* - * Called after a rx ctrl timeout. "data" is NULL. - * allocate memory to trace the trap or assert. - */ - size = msize; - mbuffer = data = MALLOC(bus->dhd->osh, msize); - - if (mbuffer == NULL) { - DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); - bcmerror = BCME_NOMEM; - goto done; - } - } - - if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { - DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); - bcmerror = BCME_NOMEM; - goto done; - } - - if ((bcmerror = dhdpcie_readshared(bus)) < 0) { - goto done; - } - - bcm_binit(&strbuf, data, size); - - bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", - pciedev_shared->msgtrace_addr, pciedev_shared->console_addr); - - if ((pciedev_shared->flags & PCIE_SHARED_ASSERT_BUILT) == 0) { - /* NOTE: Misspelled assert is intentional - DO NOT FIX. - * (Avoids conflict with real asserts for programmatic parsing of output.) - */ - bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); - } - - if ((bus->pcie_sh->flags & (PCIE_SHARED_ASSERT|PCIE_SHARED_TRAP)) == 0) { - /* NOTE: Misspelled assert is intentional - DO NOT FIX. - * (Avoids conflict with real asserts for programmatic parsing of output.) - */ - bcm_bprintf(&strbuf, "No trap%s in dongle", - (bus->pcie_sh->flags & PCIE_SHARED_ASSERT_BUILT) - ?"/assrt" :""); - } else { - if (bus->pcie_sh->flags & PCIE_SHARED_ASSERT) { - /* Download assert */ - bcm_bprintf(&strbuf, "Dongle assert"); - if (bus->pcie_sh->assert_exp_addr != 0) { - str[0] = '\0'; - if ((bcmerror = dhdpcie_bus_membytes(bus, FALSE, - bus->pcie_sh->assert_exp_addr, - (uint8 *)str, maxstrlen)) < 0) { - goto done; - } - - str[maxstrlen - 1] = '\0'; - bcm_bprintf(&strbuf, " expr \"%s\"", str); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - " expr \"%s\"", str); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - } - - if (bus->pcie_sh->assert_file_addr != 0) { - str[0] = '\0'; - if ((bcmerror = dhdpcie_bus_membytes(bus, FALSE, - bus->pcie_sh->assert_file_addr, - (uint8 *)str, maxstrlen)) < 0) { - goto done; - } - - str[maxstrlen - 1] = '\0'; - bcm_bprintf(&strbuf, " file \"%s\"", str); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - " file \"%s\"", str); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - } - - bcm_bprintf(&strbuf, " line %d ", bus->pcie_sh->assert_line); - } - - if (bus->pcie_sh->flags & PCIE_SHARED_TRAP) { - bus->dhd->dongle_trap_occured = TRUE; - if ((bcmerror = dhdpcie_bus_membytes(bus, FALSE, - bus->pcie_sh->trap_addr, (uint8*)&tr, sizeof(trap_t))) < 0) { - goto done; - } - - bcm_bprintf(&strbuf, - "\nTRAP type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," - " lp 0x%x, rpc 0x%x" - "\nTrap offset 0x%x, r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " - "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", - ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), - ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), - ltoh32(bus->pcie_sh->trap_addr), - ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), - ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); - -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - "\nTRAP type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," - " lp 0x%x, rpc 0x%x" - "\nTrap offset 0x%x, r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " - "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", - ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), - ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), - ltoh32(bus->pcie_sh->trap_addr), - ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), - ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - addr = bus->pcie_sh->console_addr + OFFSETOF(hnd_cons_t, log); - if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, - (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) { - goto printbuf; - } - - addr = bus->pcie_sh->console_addr + OFFSETOF(hnd_cons_t, log.buf_size); - if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, - (uint8 *)&console_size, sizeof(console_size))) < 0) { - goto printbuf; - } - - addr = bus->pcie_sh->console_addr + OFFSETOF(hnd_cons_t, log.idx); - if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, - (uint8 *)&console_index, sizeof(console_index))) < 0) { - goto printbuf; - } - - console_ptr = ltoh32(console_ptr); - console_size = ltoh32(console_size); - console_index = ltoh32(console_index); - - if (console_size > CONSOLE_BUFFER_MAX || - !(console_buffer = MALLOC(bus->dhd->osh, console_size))) { - goto printbuf; - } - - if ((rv = dhdpcie_bus_membytes(bus, FALSE, console_ptr, - (uint8 *)console_buffer, console_size)) < 0) { - goto printbuf; - } - - for (i = 0, n = 0; i < console_size; i += n + 1) { - for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { - ch = console_buffer[(console_index + i + n) % console_size]; - if (ch == '\n') - break; - line[n] = ch; - } - - - if (n > 0) { - if (line[n - 1] == '\r') - n--; - line[n] = 0; - /* Don't use DHD_ERROR macro since we print - * a lot of information quickly. The macro - * will truncate a lot of the printfs - */ - - printf("CONSOLE: %s\n", line); - } - } - } - } - -printbuf: - if (bus->pcie_sh->flags & (PCIE_SHARED_ASSERT | PCIE_SHARED_TRAP)) { - DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); - -#if defined(DHD_FW_COREDUMP) - /* save core dump or write to a file */ - dhdpcie_mem_dump(bus); - - /* Get backtrace in the kernel log. */ - WARN_ON(1); -#endif /* DHD_FW_COREDUMP */ - - - } - -done: - if (mbuffer) - MFREE(bus->dhd->osh, mbuffer, msize); - if (str) - MFREE(bus->dhd->osh, str, maxstrlen); - - if (console_buffer) - MFREE(bus->dhd->osh, console_buffer, console_size); - - return bcmerror; -} /* dhdpcie_checkdied */ - -#if defined(DHD_FW_COREDUMP) -int -dhdpcie_mem_dump(dhd_bus_t *bus) -{ - int ret = 0; - int size; /* Full mem size */ - int start = bus->dongle_ram_base; /* Start address */ - int read_size = 0; /* Read size of each iteration */ - uint8 *buf = NULL, *databuf = NULL; - -#ifdef DHD_USE_IDLECOUNT - DHD_ERROR(("%s: bus_wake\n", __FUNCTION__)); - if (!bus_wake(bus)) { - DHD_ERROR(("%s: bus_wake failed\n", __FUNCTION__)); - return BCME_ERROR; - } -#endif /* DHD_USE_IDLECOUNT */ - -#ifdef SUPPORT_LINKDOWN_RECOVERY - if (bus->islinkdown) { - DHD_ERROR(("%s: PCIe link is down so skip\n", __FUNCTION__)); - return BCME_ERROR; - } -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - - /* Get full mem size */ - size = bus->ramsize; - buf = dhd_get_fwdump_buf(bus->dhd, size); - if (!buf) { - DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size)); - return BCME_ERROR; - } - - /* Read mem content */ - DHD_TRACE(("Dump dongle memory")); - databuf = buf; - while (size) - { - read_size = MIN(MEMBLOCK, size); - if ((ret = dhdpcie_bus_membytes(bus, FALSE, start, databuf, read_size))) - { - DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret)); - return BCME_ERROR; - } - DHD_TRACE((".")); - - /* Decrement size and increment start address */ - size -= read_size; - start += read_size; - databuf += read_size; - } - - dhd_schedule_memdump(bus->dhd, buf, bus->ramsize); - - /* buf, actually soc_ram free handled in dhd_{free,clear} */ - return ret; -} - -int -dhd_bus_mem_dump(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - return dhdpcie_mem_dump(bus); -} -#endif /* DHD_FW_COREDUMP */ - -/** - * Transfers bytes from host to dongle using pio mode. - * Parameter 'address' is a backplane address. - */ -static int -dhdpcie_bus_membytes(dhd_bus_t *bus, bool write, ulong address, uint8 *data, uint size) -{ - int bcmerror = 0; - uint dsize; - int detect_endian_flag = 0x01; - bool little_endian; -#ifdef CONFIG_ARCH_MSM8994 - bool is_64bit_unaligned; -#endif - - /* Detect endianness. */ - little_endian = *(char *)&detect_endian_flag; - -#ifdef CONFIG_ARCH_MSM8994 - /* Check 64bit aligned or not. */ - is_64bit_unaligned = (address & 0x7); -#endif - /* In remap mode, adjust address beyond socram and redirect - * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize - * is not backplane accessible - */ - - /* Determine initial transfer parameters */ -#ifdef DHD_SUPPORT_64BIT - dsize = sizeof(uint64); -#else /* !DHD_SUPPORT_64BIT */ - dsize = sizeof(uint32); -#endif /* DHD_SUPPORT_64BIT */ - - /* Do the transfer(s) */ - if (write) { - while (size) { -#ifdef DHD_SUPPORT_64BIT - if (size >= sizeof(uint64) && little_endian && !(address % 8)) { -#ifdef CONFIG_ARCH_MSM8994 - if (is_64bit_unaligned) { - DHD_INFO(("%s: write unaligned %lx\n", - __FUNCTION__, address)); - dhdpcie_bus_wtcm32(bus, address, *((uint32 *)data)); - data += 4; - size -= 4; - address += 4; - is_64bit_unaligned = (address & 0x7); - continue; - } - else -#endif - dhdpcie_bus_wtcm64(bus, address, *((uint64 *)data)); - } -#else /* !DHD_SUPPORT_64BIT */ - if (size >= sizeof(uint32) && little_endian && !(address % 4)) { - dhdpcie_bus_wtcm32(bus, address, *((uint32*)data)); - } -#endif /* DHD_SUPPORT_64BIT */ - else { - dsize = sizeof(uint8); - dhdpcie_bus_wtcm8(bus, address, *data); - } - - /* Adjust for next transfer (if any) */ - if ((size -= dsize)) { - data += dsize; - address += dsize; - } - } - } else { - while (size) { -#ifdef DHD_SUPPORT_64BIT - if (size >= sizeof(uint64) && little_endian && !(address % 8)) - { -#ifdef CONFIG_ARCH_MSM8994 - if (is_64bit_unaligned) { - DHD_INFO(("%s: read unaligned %lx\n", - __FUNCTION__, address)); - *(uint32 *)data = dhdpcie_bus_rtcm32(bus, address); - data += 4; - size -= 4; - address += 4; - is_64bit_unaligned = (address & 0x7); - continue; - } - else -#endif - *(uint64 *)data = dhdpcie_bus_rtcm64(bus, address); - } -#else /* !DHD_SUPPORT_64BIT */ - if (size >= sizeof(uint32) && little_endian && !(address % 4)) - { - *(uint32 *)data = dhdpcie_bus_rtcm32(bus, address); - } -#endif /* DHD_SUPPORT_64BIT */ - else { - dsize = sizeof(uint8); - *data = dhdpcie_bus_rtcm8(bus, address); - } - - /* Adjust for next transfer (if any) */ - if ((size -= dsize) > 0) { - data += dsize; - address += dsize; - } - } - } - return bcmerror; -} - -int BCMFASTPATH -dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs) -{ - flow_ring_node_t *flow_ring_node; - int ret = BCME_OK; - - DHD_INFO(("%s: flow_id is %d\n", __FUNCTION__, flow_id)); - /* ASSERT on flow_id */ - if (flow_id >= bus->max_sub_queues) { - DHD_ERROR(("%s: flow_id is invalid %d, max %d\n", __FUNCTION__, - flow_id, bus->max_sub_queues)); - return 0; - } - - flow_ring_node = DHD_FLOW_RING(bus->dhd, flow_id); - - { - unsigned long flags; - void *txp = NULL; - flow_queue_t *queue; - - queue = &flow_ring_node->queue; /* queue associated with flow ring */ - - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - - if (flow_ring_node->status != FLOW_RING_STATUS_OPEN) { - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - return BCME_NOTREADY; - } - - while ((txp = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { - PKTORPHAN(txp); - -#ifdef DHDTCPACK_SUPPRESS - if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_HOLD) { - dhd_tcpack_check_xmit(bus->dhd, txp); - } -#endif /* DHDTCPACK_SUPPRESS */ - /* Attempt to transfer packet over flow ring */ - - ret = dhd_prot_txdata(bus->dhd, txp, flow_ring_node->flow_info.ifindex); - if (ret != BCME_OK) { /* may not have resources in flow ring */ - DHD_INFO(("%s: Reinserrt %d\n", __FUNCTION__, ret)); - dhd_prot_txdata_write_flush(bus->dhd, flow_id, FALSE); - /* reinsert at head */ - dhd_flow_queue_reinsert(bus->dhd, queue, txp); - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - - /* If we are able to requeue back, return success */ - return BCME_OK; - } - } - - dhd_prot_txdata_write_flush(bus->dhd, flow_id, FALSE); - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - } - - return ret; -} - -#ifndef PCIE_TX_DEFERRAL -/* Send a data frame to the dongle. Callee disposes of txp. */ -int BCMFASTPATH -dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx) -{ - unsigned long flags; - int ret = BCME_OK; - void *txp_pend = NULL; - -#ifdef DHD_USE_IDLECOUNT - bus_wake(bus); -#endif /* DHD_USE_IDLECOUNT */ - if (!bus->txmode_push) { - uint16 flowid; - flow_queue_t *queue; - flow_ring_node_t *flow_ring_node; - if (!bus->dhd->flowid_allocator) { - DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); - goto toss; - } - - flowid = DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(txp)); - - flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); - - DHD_TRACE(("%s: pkt flowid %d, status %d active %d\n", - __FUNCTION__, flowid, flow_ring_node->status, - flow_ring_node->active)); - - if ((flowid >= bus->dhd->num_flow_rings) || - (!flow_ring_node->active) || - (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING)) { - DHD_INFO(("%s: Dropping pkt flowid %d, status %d active %d\n", - __FUNCTION__, flowid, flow_ring_node->status, - flow_ring_node->active)); - ret = BCME_ERROR; - goto toss; - } - - queue = &flow_ring_node->queue; /* queue associated with flow ring */ - - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - - if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp)) != BCME_OK) - txp_pend = txp; - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - - if (flow_ring_node->status) { - DHD_INFO(("%s: Enq pkt flowid %d, status %d active %d\n", - __FUNCTION__, flowid, flow_ring_node->status, - flow_ring_node->active)); - if (txp_pend) { - txp = txp_pend; - goto toss; - } - return BCME_OK; - } - ret = dhd_bus_schedule_queue(bus, flowid, FALSE); - - /* If we have anything pending, try to push into q */ - if (txp_pend) { - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - - if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp_pend)) != BCME_OK) { - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - txp = txp_pend; - goto toss; - } - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - } - - return ret; - - } else { /* bus->txmode_push */ - return dhd_prot_txdata(bus->dhd, txp, ifidx); - } - -toss: - DHD_INFO(("%s: Toss %d\n", __FUNCTION__, ret)); - PKTCFREE(bus->dhd->osh, txp, TRUE); - return ret; -} -#else /* PCIE_TX_DEFERRAL */ -int BCMFASTPATH -dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx) -{ - unsigned long flags; - int ret = BCME_OK; - uint16 flowid; - flow_queue_t *queue; - flow_ring_node_t *flow_ring_node; - uint8 *pktdata = (uint8 *)PKTDATA(bus->dhd->osh, txp); - struct ether_header *eh = (struct ether_header *)pktdata; - - if (!bus->dhd->flowid_allocator) { - DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); - goto toss; - } - - flowid = dhd_flowid_find(bus->dhd, ifidx, - bus->dhd->flow_prio_map[(PKTPRIO(txp))], - eh->ether_shost, eh->ether_dhost); - if (flowid == FLOWID_INVALID) { - DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(txp), ifidx); - skb_queue_tail(&bus->orphan_list, txp); - queue_work(bus->tx_wq, &bus->create_flow_work); - return BCME_OK; - } - - DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(txp), flowid); - flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); - queue = &flow_ring_node->queue; /* queue associated with flow ring */ - - DHD_DATA(("%s: pkt flowid %d, status %d active %d\n", - __FUNCTION__, flowid, flow_ring_node->status, - flow_ring_node->active)); - - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - if ((flowid >= bus->dhd->num_flow_rings) || - (!flow_ring_node->active) || - (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING)) { - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - DHD_DATA(("%s: Dropping pkt flowid %d, status %d active %d\n", - __FUNCTION__, flowid, flow_ring_node->status, - flow_ring_node->active)); - ret = BCME_ERROR; - goto toss; - } - - if (flow_ring_node->status == FLOW_RING_STATUS_PENDING) { - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(txp), ifidx); - skb_queue_tail(&bus->orphan_list, txp); - queue_work(bus->tx_wq, &bus->create_flow_work); - return BCME_OK; - } - - if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp)) != BCME_OK) { - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - goto toss; - } - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - - ret = dhd_bus_schedule_queue(bus, flowid, FALSE); - - return ret; - -toss: - DHD_DATA(("%s: Toss %d\n", __FUNCTION__, ret)); - PKTCFREE(bus->dhd->osh, txp, TRUE); - return ret; -} -#endif /* !PCIE_TX_DEFERRAL */ - - -void -dhd_bus_stop_queue(struct dhd_bus *bus) -{ - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); - bus->bus_flowctrl = TRUE; -} - -void -dhd_bus_start_queue(struct dhd_bus *bus) -{ - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); - bus->bus_flowctrl = TRUE; -} - -void -dhd_bus_update_retlen(dhd_bus_t *bus, uint32 retlen, uint32 pkt_id, uint16 status, - uint32 resp_len) -{ - bus->ioct_resp.cmn_hdr.request_id = pkt_id; - bus->ioct_resp.compl_hdr.status = status; - bus->ioct_resp.resp_len = (uint16)resp_len; - - bus->rxlen = retlen; -} - -#if defined(DHD_DEBUG) -/* Device console input function */ -int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen) -{ - dhd_bus_t *bus = dhd->bus; - uint32 addr, val; - int rv; - /* Address could be zero if CONSOLE := 0 in dongle Makefile */ - if (bus->console_addr == 0) - return BCME_UNSUPPORTED; - - /* Don't allow input if dongle is in reset */ - if (bus->dhd->dongle_reset) { - dhd_os_sdunlock(bus->dhd); - return BCME_NOTREADY; - } - -#ifdef DHD_USE_IDLECOUNT - bus_wake(bus); -#endif /* DHD_USE_IDLECOUNT */ - /* Zero cbuf_index */ - addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx); - val = htol32(0); - if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) - goto done; - - /* Write message into cbuf */ - addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf); - if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) - goto done; - - /* Write length into vcons_in */ - addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in); - val = htol32(msglen); - if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) - goto done; - - /* generate an interurpt to dongle to indicate that it needs to process cons command */ - dhdpcie_send_mb_data(bus, H2D_HOST_CONS_INT); -done: - return rv; -} -#endif /* defined(DHD_DEBUG) */ - -/* Process rx frame , Send up the layer to netif */ -void BCMFASTPATH -dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count) -{ -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif - dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, 0); -} - -#ifdef CONFIG_ARCH_MSM8994 -static ulong dhd_bus_cmn_check_offset(dhd_bus_t *bus, ulong offset) -{ - uint new_bar1_wbase = 0; - ulong address = 0; - - new_bar1_wbase = (uint)offset & bus->bar1_win_mask; - if (bus->bar1_win_base != new_bar1_wbase) { - bus->bar1_win_base = new_bar1_wbase; - dhdpcie_bus_cfg_set_bar1_win(bus, bus->bar1_win_base); - DHD_ERROR(("%s: offset=%lx, switch bar1_win_base to %x\n", - __FUNCTION__, offset, bus->bar1_win_base)); - } - - address = offset - bus->bar1_win_base; - - return address; -} -#else -#define dhd_bus_cmn_check_offset(x, y) y -#endif /* CONFIG_ARCH_MSM8994 */ - -/** 'offset' is a backplane address */ -void -dhdpcie_bus_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data) -{ - W_REG(bus->dhd->osh, - (volatile uint8 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)), data); -} - -uint8 -dhdpcie_bus_rtcm8(dhd_bus_t *bus, ulong offset) -{ - volatile uint8 data; - - data = R_REG(bus->dhd->osh, - (volatile uint8 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset))); - - return data; -} - -void -dhdpcie_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data) -{ - W_REG(bus->dhd->osh, - (volatile uint32 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)), data); -} -void -dhdpcie_bus_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data) -{ - W_REG(bus->dhd->osh, - (volatile uint16 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)), data); -} -#ifdef DHD_SUPPORT_64BIT -void -dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data) -{ - W_REG(bus->dhd->osh, - (volatile uint64 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)), data); -} -#endif /* DHD_SUPPORT_64BIT */ - -uint16 -dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset) -{ - volatile uint16 data; - data = R_REG(bus->dhd->osh, - (volatile uint16 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset))); - return data; -} - -uint32 -dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset) -{ - volatile uint32 data; - data = R_REG(bus->dhd->osh, - (volatile uint32 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset))); - return data; -} -#ifdef DHD_SUPPORT_64BIT -uint64 -dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset) -{ - volatile uint64 data; - data = R_REG(bus->dhd->osh, - (volatile uint64 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset))); - return data; -} -#endif /* DHD_SUPPORT_64BIT */ - -void -dhd_bus_cmn_writeshared(dhd_bus_t *bus, void * data, uint32 len, uint8 type, uint16 ringid) -{ - uint64 long_data; - ulong tcm_offset; - pciedev_shared_t *sh; - pciedev_shared_t *shmem = NULL; - - sh = (pciedev_shared_t*)bus->shared_addr; - - DHD_INFO(("%s: writing to msgbuf type %d, len %d\n", __FUNCTION__, type, len)); - - switch (type) { - case DNGL_TO_HOST_DMA_SCRATCH_BUFFER: - long_data = HTOL64(*(uint64 *)data); - tcm_offset = (ulong)&(sh->host_dma_scratch_buffer); - dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); - prhex(__FUNCTION__, data, len); - break; - - case DNGL_TO_HOST_DMA_SCRATCH_BUFFER_LEN : - tcm_offset = (ulong)&(sh->host_dma_scratch_buffer_len); - dhdpcie_bus_wtcm32(bus, tcm_offset, (uint32) HTOL32(*(uint32 *)data)); - prhex(__FUNCTION__, data, len); - break; - - case HOST_TO_DNGL_DMA_WRITEINDX_BUFFER: - /* ring_info_ptr stored in pcie_sh */ - shmem = (pciedev_shared_t *)bus->pcie_sh; - - long_data = HTOL64(*(uint64 *)data); - tcm_offset = (ulong)shmem->rings_info_ptr; - tcm_offset += OFFSETOF(ring_info_t, h2d_w_idx_hostaddr); - dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); - prhex(__FUNCTION__, data, len); - break; - - case HOST_TO_DNGL_DMA_READINDX_BUFFER: - /* ring_info_ptr stored in pcie_sh */ - shmem = (pciedev_shared_t *)bus->pcie_sh; - - long_data = HTOL64(*(uint64 *)data); - tcm_offset = (ulong)shmem->rings_info_ptr; - tcm_offset += OFFSETOF(ring_info_t, h2d_r_idx_hostaddr); - dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); - prhex(__FUNCTION__, data, len); - break; - - case DNGL_TO_HOST_DMA_WRITEINDX_BUFFER: - /* ring_info_ptr stored in pcie_sh */ - shmem = (pciedev_shared_t *)bus->pcie_sh; - - long_data = HTOL64(*(uint64 *)data); - tcm_offset = (ulong)shmem->rings_info_ptr; - tcm_offset += OFFSETOF(ring_info_t, d2h_w_idx_hostaddr); - dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); - prhex(__FUNCTION__, data, len); - break; - - case DNGL_TO_HOST_DMA_READINDX_BUFFER: - /* ring_info_ptr stored in pcie_sh */ - shmem = (pciedev_shared_t *)bus->pcie_sh; - - long_data = HTOL64(*(uint64 *)data); - tcm_offset = (ulong)shmem->rings_info_ptr; - tcm_offset += OFFSETOF(ring_info_t, d2h_r_idx_hostaddr); - dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); - prhex(__FUNCTION__, data, len); - break; - - case RING_LEN_ITEMS : - tcm_offset = bus->ring_sh[ringid].ring_mem_addr; - tcm_offset += OFFSETOF(ring_mem_t, len_items); - dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data)); - break; - - case RING_MAX_ITEM : - tcm_offset = bus->ring_sh[ringid].ring_mem_addr; - tcm_offset += OFFSETOF(ring_mem_t, max_item); - dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data)); - break; - - case RING_BUF_ADDR : - long_data = HTOL64(*(uint64 *)data); - tcm_offset = bus->ring_sh[ringid].ring_mem_addr; - tcm_offset += OFFSETOF(ring_mem_t, base_addr); - dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8 *) &long_data, len); - prhex(__FUNCTION__, data, len); - break; - - case RING_WRITE_PTR : - tcm_offset = bus->ring_sh[ringid].ring_state_w; - dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data)); - break; - case RING_READ_PTR : - tcm_offset = bus->ring_sh[ringid].ring_state_r; - dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data)); - break; - - case DTOH_MB_DATA: - dhdpcie_bus_wtcm32(bus, bus->d2h_mb_data_ptr_addr, - (uint32) HTOL32(*(uint32 *)data)); - break; - - case HTOD_MB_DATA: - dhdpcie_bus_wtcm32(bus, bus->h2d_mb_data_ptr_addr, - (uint32) HTOL32(*(uint32 *)data)); - break; - default: - break; - } -} - - -void -dhd_bus_cmn_readshared(dhd_bus_t *bus, void* data, uint8 type, uint16 ringid) -{ - pciedev_shared_t *sh; - ulong tcm_offset; - - sh = (pciedev_shared_t*)bus->shared_addr; - - switch (type) { - case RING_WRITE_PTR : - tcm_offset = bus->ring_sh[ringid].ring_state_w; - *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset)); - break; - case RING_READ_PTR : - tcm_offset = bus->ring_sh[ringid].ring_state_r; - *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset)); - break; - case TOTAL_LFRAG_PACKET_CNT : - *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, - (ulong) &sh->total_lfrag_pkt_cnt)); - break; - case HTOD_MB_DATA: - *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->h2d_mb_data_ptr_addr)); - break; - case DTOH_MB_DATA: - *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->d2h_mb_data_ptr_addr)); - break; - case MAX_HOST_RXBUFS : - *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, - (ulong) &sh->max_host_rxbufs)); - break; - default : - break; - } -} - -uint32 dhd_bus_get_sharedflags(dhd_bus_t *bus) -{ - return ((pciedev_shared_t*)bus->pcie_sh)->flags; -} - -void -dhd_bus_clearcounts(dhd_pub_t *dhdp) -{ -} - -int -dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - dhd_bus_t *bus = dhdp->bus; - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - uint32 actionid; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - DHD_INFO(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* Look up var locally; if not found pass to host driver */ - if ((vi = bcm_iovar_lookup(dhdpcie_iovars, name)) == NULL) { - goto exit; - } - - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - bcmerror = dhdpcie_bus_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} - -#ifdef BCM_BUZZZ -#include - -int dhd_buzzz_dump_cntrs3(char *p, uint32 *core, uint32 * ovhd, uint32 *log) -{ - int bytes = 0; - uint32 ctr, curr[3], prev[3], delta[3]; - - /* Compute elapsed counter values per counter event type */ - for (ctr = 0U; ctr < 3; ctr++) { - prev[ctr] = core[ctr]; - curr[ctr] = *log++; - core[ctr] = curr[ctr]; /* saved for next log */ - - if (curr[ctr] < prev[ctr]) - delta[ctr] = curr[ctr] + (~0U - prev[ctr]); - else - delta[ctr] = (curr[ctr] - prev[ctr]); - - /* Adjust for instrumentation overhead */ - if (delta[ctr] >= ovhd[ctr]) - delta[ctr] -= ovhd[ctr]; - else - delta[ctr] = 0; - - bytes += sprintf(p + bytes, "%12u ", delta[ctr]); - } - - return bytes; -} - -typedef union cm3_cnts { /* export this in bcm_buzzz.h */ - uint32 u32; - uint8 u8[4]; - struct { - uint8 cpicnt; - uint8 exccnt; - uint8 sleepcnt; - uint8 lsucnt; - }; -} cm3_cnts_t; - -int dhd_buzzz_dump_cntrs6(char *p, uint32 *core, uint32 * ovhd, uint32 *log) -{ - int bytes = 0; - - uint32 cyccnt, instrcnt; - cm3_cnts_t cm3_cnts; - uint8 foldcnt; - - { /* 32bit cyccnt */ - uint32 curr, prev, delta; - prev = core[0]; curr = *log++; core[0] = curr; - if (curr < prev) - delta = curr + (~0U - prev); - else - delta = (curr - prev); - if (delta >= ovhd[0]) - delta -= ovhd[0]; - else - delta = 0; - - bytes += sprintf(p + bytes, "%12u ", delta); - cyccnt = delta; - } - - { /* Extract the 4 cnts: cpi, exc, sleep and lsu */ - int i; - uint8 max8 = ~0; - cm3_cnts_t curr, prev, delta; - prev.u32 = core[1]; curr.u32 = * log++; core[1] = curr.u32; - for (i = 0; i < 4; i++) { - if (curr.u8[i] < prev.u8[i]) - delta.u8[i] = curr.u8[i] + (max8 - prev.u8[i]); - else - delta.u8[i] = (curr.u8[i] - prev.u8[i]); - if (delta.u8[i] >= ovhd[i + 1]) - delta.u8[i] -= ovhd[i + 1]; - else - delta.u8[i] = 0; - bytes += sprintf(p + bytes, "%4u ", delta.u8[i]); - } - cm3_cnts.u32 = delta.u32; - } - - { /* Extract the foldcnt from arg0 */ - uint8 curr, prev, delta, max8 = ~0; - buzzz_arg0_t arg0; arg0.u32 = *log; - prev = core[2]; curr = arg0.klog.cnt; core[2] = curr; - if (curr < prev) - delta = curr + (max8 - prev); - else - delta = (curr - prev); - if (delta >= ovhd[5]) - delta -= ovhd[5]; - else - delta = 0; - bytes += sprintf(p + bytes, "%4u ", delta); - foldcnt = delta; - } - - instrcnt = cyccnt - (cm3_cnts.u8[0] + cm3_cnts.u8[1] + cm3_cnts.u8[2] - + cm3_cnts.u8[3]) + foldcnt; - if (instrcnt > 0xFFFFFF00) - bytes += sprintf(p + bytes, "[%10s] ", "~"); - else - bytes += sprintf(p + bytes, "[%10u] ", instrcnt); - return bytes; -} - -int dhd_buzzz_dump_log(char * p, uint32 * core, uint32 * log, buzzz_t * buzzz) -{ - int bytes = 0; - buzzz_arg0_t arg0; - static uint8 * fmt[] = BUZZZ_FMT_STRINGS; - - if (buzzz->counters == 6) { - bytes += dhd_buzzz_dump_cntrs6(p, core, buzzz->ovhd, log); - log += 2; /* 32bit cyccnt + (4 x 8bit) CM3 */ - } else { - bytes += dhd_buzzz_dump_cntrs3(p, core, buzzz->ovhd, log); - log += 3; /* (3 x 32bit) CR4 */ - } - - /* Dump the logged arguments using the registered formats */ - arg0.u32 = *log++; - - switch (arg0.klog.args) { - case 0: - bytes += sprintf(p + bytes, fmt[arg0.klog.id]); - break; - case 1: - { - uint32 arg1 = *log++; - bytes += sprintf(p + bytes, fmt[arg0.klog.id], arg1); - break; - } - default: - printf("Maximum one argument supported\n"); - break; - } - bytes += sprintf(p + bytes, "\n"); - - return bytes; -} - -void dhd_buzzz_dump(buzzz_t * buzzz_p, void * buffer_p, char * p) -{ - int i; - uint32 total, part1, part2, log_sz, core[BUZZZ_COUNTERS_MAX]; - void * log; - - for (i = 0; i < BUZZZ_COUNTERS_MAX; i++) - core[i] = 0; - - log_sz = buzzz_p->log_sz; - - part1 = ((uint32)buzzz_p->cur - (uint32)buzzz_p->log) / log_sz; - - if (buzzz_p->wrap == TRUE) { - part2 = ((uint32)buzzz_p->end - (uint32)buzzz_p->cur) / log_sz; - total = (buzzz_p->buffer_sz - BUZZZ_LOGENTRY_MAXSZ) / log_sz; - } else { - part2 = 0U; - total = buzzz_p->count; - } - - if (total == 0U) { - printf("buzzz_dump total<%u> done\n", total); - return; - } else { - printf("buzzz_dump total<%u> : part2<%u> + part1<%u>\n", - total, part2, part1); - } - - if (part2) { /* with wrap */ - log = (void*)((size_t)buffer_p + (buzzz_p->cur - buzzz_p->log)); - while (part2--) { /* from cur to end : part2 */ - p[0] = '\0'; - dhd_buzzz_dump_log(p, core, (uint32 *)log, buzzz_p); - printf("%s", p); - log = (void*)((size_t)log + buzzz_p->log_sz); - } - } - - log = (void*)buffer_p; - while (part1--) { - p[0] = '\0'; - dhd_buzzz_dump_log(p, core, (uint32 *)log, buzzz_p); - printf("%s", p); - log = (void*)((size_t)log + buzzz_p->log_sz); - } - - printf("buzzz_dump done.\n"); -} - -int dhd_buzzz_dump_dngl(dhd_bus_t *bus) -{ - buzzz_t * buzzz_p = NULL; - void * buffer_p = NULL; - char * page_p = NULL; - pciedev_shared_t *sh; - int ret = 0; - - if (bus->dhd->busstate != DHD_BUS_DATA) { - return BCME_UNSUPPORTED; - } - if ((page_p = (char *)MALLOC(bus->dhd->osh, 4096)) == NULL) { - printf("Page memory allocation failure\n"); - goto done; - } - if ((buzzz_p = MALLOC(bus->dhd->osh, sizeof(buzzz_t))) == NULL) { - printf("Buzzz memory allocation failure\n"); - goto done; - } - - ret = dhdpcie_readshared(bus); - if (ret < 0) { - DHD_ERROR(("%s :Shared area read failed \n", __FUNCTION__)); - goto done; - } - - sh = bus->pcie_sh; - - DHD_INFO(("%s buzzz:%08x\n", __FUNCTION__, sh->buzzz)); - - if (sh->buzzz != 0U) { /* Fetch and display dongle BUZZZ Trace */ - dhdpcie_bus_membytes(bus, FALSE, (ulong)sh->buzzz, - (uint8 *)buzzz_p, sizeof(buzzz_t)); - if (buzzz_p->count == 0) { - printf("Empty dongle BUZZZ trace\n\n"); - goto done; - } - if (buzzz_p->counters != 3) { /* 3 counters for CR4 */ - printf("Counters<%u> mismatch\n", buzzz_p->counters); - goto done; - } - /* Allocate memory for trace buffer and format strings */ - buffer_p = MALLOC(bus->dhd->osh, buzzz_p->buffer_sz); - if (buffer_p == NULL) { - printf("Buffer memory allocation failure\n"); - goto done; - } - /* Fetch the trace and format strings */ - dhdpcie_bus_membytes(bus, FALSE, (uint32)buzzz_p->log, /* Trace */ - (uint8 *)buffer_p, buzzz_p->buffer_sz); - /* Process and display the trace using formatted output */ - printf("<#cycle> <#instruction> <#ctr3> \n"); - dhd_buzzz_dump(buzzz_p, buffer_p, page_p); - printf("----- End of dongle BUZZZ Trace -----\n\n"); - MFREE(bus->dhd->osh, buffer_p, buzzz_p->buffer_sz); buffer_p = NULL; - } - -done: - - if (page_p) MFREE(bus->dhd->osh, page_p, 4096); - if (buzzz_p) MFREE(bus->dhd->osh, buzzz_p, sizeof(buzzz_t)); - if (buffer_p) MFREE(bus->dhd->osh, buffer_p, buzzz_p->buffer_sz); - - return BCME_OK; -} -#endif /* BCM_BUZZZ */ - -#define PCIE_GEN2(sih) ((BUSTYPE((sih)->bustype) == PCI_BUS) && \ - ((sih)->buscoretype == PCIE2_CORE_ID)) - -int -dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) -{ - dhd_bus_t *bus = dhdp->bus; - int bcmerror = 0; -#ifdef CONFIG_ARCH_MSM - int retry = POWERUP_MAX_RETRY; -#endif /* CONFIG_ARCH_MSM */ - - if (dhd_download_fw_on_driverload) { - bcmerror = dhd_bus_start(dhdp); - } else { - if (flag == TRUE) { /* Turn off WLAN */ - /* Ensure everything is on before accesssing registers. */ -#ifdef DHD_USE_IDLECOUNT - if (!bus_wake(bus)) { - DHD_ERROR(("%s Couldn't wake. Start clock.\n", __FUNCTION__)); - bcmerror = dhdpcie_bus_clock_start(bus); - if (bcmerror) { - DHD_ERROR(("%s: Reenable clock %d\n", - __FUNCTION__, bcmerror)); - } - } -#endif /* DHD_USE_IDLECOUNT */ - /* Removing Power */ - DHD_ERROR(("%s: == Power OFF ==\n", __FUNCTION__)); - mutex_lock(&bus->pm_lock); - bus->dhd->up = FALSE; - if (bus->dhd->busstate != DHD_BUS_DOWN) { - if (bus->intr) { - dhdpcie_free_irq(bus); - } -#ifdef BCMPCIE_OOB_HOST_WAKE - /* Clean up any pending host wake IRQ */ - dhd_bus_oob_intr_set(bus->dhd, FALSE); - dhd_bus_oob_intr_unregister(bus->dhd); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - dhd_os_wd_timer(dhdp, 0); - dhd_bus_stop(bus, TRUE); - dhd_prot_clear(dhdp); - dhd_clear(dhdp); - dhd_bus_release_dongle(bus); - dhdpcie_bus_free_resource(bus); - bcmerror = dhdpcie_bus_disable_device(bus); - if (bcmerror) { - DHD_ERROR(("%s: dhdpcie_bus_disable_device: %d\n", - __FUNCTION__, bcmerror)); - mutex_unlock(&bus->pm_lock); - goto done; - } -#ifdef CONFIG_ARCH_MSM - bcmerror = dhdpcie_bus_clock_stop(bus); - if (bcmerror) { - DHD_ERROR(("%s: host clock stop failed: %d\n", - __FUNCTION__, bcmerror)); - mutex_unlock(&bus->pm_lock); - goto done; - } -#endif /* CONFIG_ARCH_MSM */ - bus->dhd->busstate = DHD_BUS_DOWN; - } else { - if (bus->intr) { - dhdpcie_free_irq(bus); - } -#ifdef BCMPCIE_OOB_HOST_WAKE - /* Clean up any pending host wake IRQ */ - dhd_bus_oob_intr_set(bus->dhd, FALSE); - dhd_bus_oob_intr_unregister(bus->dhd); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - dhd_prot_clear(dhdp); - dhd_clear(dhdp); - dhd_bus_release_dongle(bus); - dhdpcie_bus_free_resource(bus); - bcmerror = dhdpcie_bus_disable_device(bus); - if (bcmerror) { - DHD_ERROR(("%s: dhdpcie_bus_disable_device: %d\n", - __FUNCTION__, bcmerror)); - mutex_unlock(&bus->pm_lock); - goto done; - } - -#ifdef CONFIG_ARCH_MSM - bcmerror = dhdpcie_bus_clock_stop(bus); - if (bcmerror) { - DHD_ERROR(("%s: host clock stop failed: %d\n", - __FUNCTION__, bcmerror)); - mutex_unlock(&bus->pm_lock); - goto done; - } -#endif /* CONFIG_ARCH_MSM */ - } - - bus->dhd->dongle_reset = TRUE; - mutex_unlock(&bus->pm_lock); - DHD_ERROR(("%s: WLAN OFF Done\n", __FUNCTION__)); - - } else { /* Turn on WLAN */ - if (bus->dhd->busstate == DHD_BUS_DOWN) { - /* Powering On */ - DHD_ERROR(("%s: == Power ON ==\n", __FUNCTION__)); -#ifdef CONFIG_ARCH_MSM - while (--retry) { - bcmerror = dhdpcie_bus_clock_start(bus); - if (!bcmerror) { - DHD_ERROR(("%s: dhdpcie_bus_clock_start OK\n", - __FUNCTION__)); - break; - } - else - OSL_SLEEP(10); - } - - if (bcmerror && !retry) { - DHD_ERROR(("%s: host pcie clock enable failed: %d\n", - __FUNCTION__, bcmerror)); - goto done; - } -#endif /* CONFIG_ARCH_MSM */ - bcmerror = dhdpcie_bus_enable_device(bus); - if (bcmerror) { - DHD_ERROR(("%s: host configuration restore failed: %d\n", - __FUNCTION__, bcmerror)); - goto done; - } - - bcmerror = dhdpcie_bus_alloc_resource(bus); - if (bcmerror) { - DHD_ERROR(("%s: dhdpcie_bus_resource_alloc failed: %d\n", - __FUNCTION__, bcmerror)); - goto done; - } - - bcmerror = dhdpcie_bus_dongle_attach(bus); - if (bcmerror) { - DHD_ERROR(("%s: dhdpcie_bus_dongle_attach failed: %d\n", - __FUNCTION__, bcmerror)); - goto done; - } - - bcmerror = dhd_bus_request_irq(bus); - if (bcmerror) { - DHD_ERROR(("%s: dhd_bus_request_irq failed: %d\n", - __FUNCTION__, bcmerror)); - goto done; - } - - bus->dhd->dongle_reset = FALSE; - - bcmerror = dhd_bus_start(dhdp); - if (bcmerror) { - DHD_ERROR(("%s: dhd_bus_start: %d\n", - __FUNCTION__, bcmerror)); - goto done; - } - - bus->dhd->up = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; - bus->idletime = (int32)MAX_IDLE_COUNT; - bus->host_suspend = FALSE; - init_waitqueue_head(&bus->rpm_queue); -#endif /* DHD_USE_IDLECOUNT */ - DHD_ERROR(("%s: WLAN Power On Done\n", __FUNCTION__)); - } else { - DHD_ERROR(("%s: what should we do here\n", __FUNCTION__)); - goto done; - } - } - } -done: - if (bcmerror) - bus->dhd->busstate = DHD_BUS_DOWN; - - return bcmerror; -} - -static int -dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - int32 int_val2 = 0; - int32 int_val3 = 0; - bool bool_val = 0; - - DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", - __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - if (plen >= (int)sizeof(int_val) * 2) - bcopy((void*)((uintptr)params + sizeof(int_val)), &int_val2, sizeof(int_val2)); - - if (plen >= (int)sizeof(int_val) * 3) - bcopy((void*)((uintptr)params + 2 * sizeof(int_val)), &int_val3, sizeof(int_val3)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - - /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ - if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || - actionid == IOV_GVAL(IOV_DEVRESET))) { - bcmerror = BCME_NOTREADY; - goto exit; - } - -#ifdef DHD_USE_IDLECOUNT - bus_wake(bus); -#endif /* DHD_USE_IDLECOUNT */ - switch (actionid) { - - - case IOV_SVAL(IOV_VARS): - bcmerror = dhdpcie_downloadvars(bus, arg, len); - break; - - case IOV_SVAL(IOV_PCIE_LPBK): - bcmerror = dhdpcie_bus_lpback_req(bus, int_val); - break; - - case IOV_SVAL(IOV_PCIE_DMAXFER): - bcmerror = dhdpcie_bus_dmaxfer_req(bus, int_val, int_val2, int_val3); - break; - - case IOV_GVAL(IOV_PCIE_SUSPEND): - int_val = (bus->dhd->busstate == DHD_BUS_SUSPEND) ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PCIE_SUSPEND): - bus->force_suspend = 1; - dhdpcie_bus_suspend(bus, bool_val); - bus->force_suspend = 0; - break; - - case IOV_GVAL(IOV_MEMSIZE): - int_val = (int32)bus->ramsize; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_MEMBYTES): - case IOV_GVAL(IOV_MEMBYTES): - { - uint32 address; /* absolute backplane address */ - uint size, dsize; - uint8 *data; - - bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); - - ASSERT(plen >= 2*sizeof(int)); - - address = (uint32)int_val; - bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); - size = (uint)int_val; - - /* Do some validation */ - dsize = set ? plen - (2 * sizeof(int)) : len; - if (dsize < size) { - DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", - __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); - bcmerror = BCME_BADARG; - break; - } - - DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n dsize %d ", __FUNCTION__, - (set ? "write" : "read"), size, address, dsize)); - - /* check if CR4 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - /* if address is 0, store the reset instruction to be written in 0 */ - if (set && address == bus->dongle_ram_base) { - bus->resetinstr = *(((uint32*)params) + 2); - } - } else { - /* If we know about SOCRAM, check for a fit */ - if ((bus->orig_ramsize) && - ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) - { - uint8 enable, protect, remap; - si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); - if (!enable || protect) { - DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", - __FUNCTION__, bus->orig_ramsize, size, address)); - DHD_ERROR(("%s: socram enable %d, protect %d\n", - __FUNCTION__, enable, protect)); - bcmerror = BCME_BADARG; - break; - } - - if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { - uint32 devramsize = si_socdevram_size(bus->sih); - if ((address < SOCDEVRAM_ARM_ADDR) || - (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { - DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n", - __FUNCTION__, address, size)); - DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n", - __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize)); - bcmerror = BCME_BADARG; - break; - } - /* move it such that address is real now */ - address -= SOCDEVRAM_ARM_ADDR; - address += SOCDEVRAM_BP_ADDR; - DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", - __FUNCTION__, (set ? "write" : "read"), size, address)); - } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { - /* Can not access remap region while devram remap bit is set - * ROM content would be returned in this case - */ - DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n", - __FUNCTION__, address)); - bcmerror = BCME_ERROR; - break; - } - } - } - - /* Generate the actual data pointer */ - data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; - - /* Call to do the transfer */ - bcmerror = dhdpcie_bus_membytes(bus, set, address, data, size); - - break; - } - -#ifdef BCM_BUZZZ - case IOV_GVAL(IOV_BUZZZ_DUMP): - bcmerror = dhd_buzzz_dump_dngl(bus); - break; -#endif /* BCM_BUZZZ */ - - case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): - bcmerror = dhdpcie_bus_download_state(bus, bool_val); - break; - - case IOV_GVAL(IOV_RAMSIZE): - int_val = (int32)bus->ramsize; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_RAMSTART): - int_val = (int32)bus->dongle_ram_base; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_CC_NVMSHADOW): - { - struct bcmstrbuf dump_b; - - bcm_binit(&dump_b, arg, len); - bcmerror = dhdpcie_cc_nvmshadow(bus, &dump_b); - break; - } - - case IOV_GVAL(IOV_SLEEP_ALLOWED): - bool_val = bus->sleep_allowed; - bcopy(&bool_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SLEEP_ALLOWED): - bus->sleep_allowed = bool_val; - break; - - case IOV_GVAL(IOV_DONGLEISOLATION): - int_val = bus->dhd->dongle_isolation; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DONGLEISOLATION): - bus->dhd->dongle_isolation = bool_val; - break; - - case IOV_GVAL(IOV_LTRSLEEPON_UNLOOAD): - int_val = bus->ltrsleep_on_unload; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_LTRSLEEPON_UNLOOAD): - bus->ltrsleep_on_unload = bool_val; - break; - - case IOV_GVAL(IOV_DUMP_RINGUPD_BLOCK): - { - struct bcmstrbuf dump_b; - bcm_binit(&dump_b, arg, len); - bcmerror = dhd_prot_ringupd_dump(bus->dhd, &dump_b); - break; - } - case IOV_GVAL(IOV_DMA_RINGINDICES): - { int h2d_support, d2h_support; - - d2h_support = DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support) ? 1 : 0; - h2d_support = DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support) ? 1 : 0; - int_val = d2h_support | (h2d_support << 1); - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - case IOV_SVAL(IOV_DMA_RINGINDICES): - /* Can change it only during initialization/FW download */ - if (bus->dhd->busstate == DHD_BUS_DOWN) { - if ((int_val > 3) || (int_val < 0)) { - DHD_ERROR(("Bad argument. Possible values: 0, 1, 2 & 3\n")); - bcmerror = BCME_BADARG; - } else { - bus->dhd->dma_d2h_ring_upd_support = (int_val & 1) ? TRUE : FALSE; - bus->dhd->dma_h2d_ring_upd_support = (int_val & 2) ? TRUE : FALSE; - } - } else { - DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", - __FUNCTION__)); - bcmerror = BCME_NOTDOWN; - } - break; - - case IOV_GVAL(IOV_RX_METADATALEN): - int_val = dhd_prot_metadatalen_get(bus->dhd, TRUE); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RX_METADATALEN): - if (int_val > 64) { - bcmerror = BCME_BUFTOOLONG; - break; - } - dhd_prot_metadatalen_set(bus->dhd, int_val, TRUE); - break; - - case IOV_SVAL(IOV_TXP_THRESHOLD): - dhd_prot_txp_threshold(bus->dhd, TRUE, int_val); - break; - - case IOV_GVAL(IOV_TXP_THRESHOLD): - int_val = dhd_prot_txp_threshold(bus->dhd, FALSE, int_val); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DB1_FOR_MB): - if (int_val) - bus->db1_for_mb = TRUE; - else - bus->db1_for_mb = FALSE; - break; - - case IOV_GVAL(IOV_DB1_FOR_MB): - if (bus->db1_for_mb) - int_val = 1; - else - int_val = 0; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_TX_METADATALEN): - int_val = dhd_prot_metadatalen_get(bus->dhd, FALSE); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TX_METADATALEN): - if (int_val > 64) { - bcmerror = BCME_BUFTOOLONG; - break; - } - dhd_prot_metadatalen_set(bus->dhd, int_val, FALSE); - break; - - case IOV_GVAL(IOV_FLOW_PRIO_MAP): - int_val = bus->dhd->flow_prio_map_type; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_FLOW_PRIO_MAP): - int_val = (int32)dhd_update_flow_prio_map(bus->dhd, (uint8)int_val); - bcopy(&int_val, arg, val_size); - break; - -#ifdef DHD_USE_IDLECOUNT - case IOV_GVAL(IOV_IDLETIME): - int_val = bus->idletime; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_IDLETIME): - if (int_val < 0) { - bcmerror = BCME_BADARG; - } else { - bus->idletime = int_val; - } - break; -#endif /* DHD_USE_IDLECOUNT */ - - case IOV_GVAL(IOV_TXBOUND): - int_val = (int32)dhd_txbound; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXBOUND): - dhd_txbound = (uint)int_val; - break; - - case IOV_GVAL(IOV_RXBOUND): - int_val = (int32)dhd_rxbound; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RXBOUND): - dhd_rxbound = (uint)int_val; - break; - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } - -exit: - return bcmerror; -} - -/* Transfers bytes from host to dongle using pio mode */ -static int -dhdpcie_bus_lpback_req(struct dhd_bus *bus, uint32 len) -{ - if (bus->dhd == NULL) { - DHD_ERROR(("bus not inited\n")); - return 0; - } - if (bus->dhd->prot == NULL) { - DHD_ERROR(("prot is not inited\n")); - return 0; - } - if (bus->dhd->busstate != DHD_BUS_DATA) { - DHD_ERROR(("not in a readystate to LPBK is not inited\n")); - return 0; - } - dhdmsgbuf_lpbk_req(bus->dhd, len); - return 0; -} - -void -dhd_bus_set_suspend_resume(dhd_pub_t *dhdp, bool state) -{ - struct dhd_bus *bus = dhdp->bus; - if (bus) { - dhdpcie_bus_suspend(bus, state); - } -} - -int -dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) -{ - - int timeleft; - bool pending; - unsigned long flags; - int rc = 0; - - struct net_device *netdev = NULL; - dhd_pub_t *pub = (dhd_pub_t *)(bus->dhd); - netdev = dhd_idx2net(pub, 0); - - if (bus->dhd == NULL) { - DHD_ERROR(("bus not inited\n")); - return BCME_ERROR; - } - if (bus->dhd->prot == NULL) { - DHD_ERROR(("prot is not inited\n")); - return BCME_ERROR; - } - DHD_GENERAL_LOCK(bus->dhd, flags); - if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) { - DHD_ERROR(("not in a readystate to LPBK is not inited\n")); - DHD_GENERAL_UNLOCK(bus->dhd, flags); - return BCME_ERROR; - } - DHD_GENERAL_UNLOCK(bus->dhd, flags); - if (bus->dhd->dongle_reset) - return -EIO; - - if (bus->suspended == state) /* Set to same state */ - return BCME_OK; - - if (state) { - DHD_GENERAL_LOCK(bus->dhd, flags); - /* Atomically check we can suspend and flag suspend, set busstate */ - if (!bus->force_suspend && dhd_os_check_wakelock_all(bus->dhd)) { - DHD_ERROR(("Suspend failed because of wakelock " - "before sending D3_INFORM\n")); -#ifdef DHD_USE_IDLECOUNT - if (bus->host_suspend == TRUE) { - bus->host_suspend = FALSE; - } -#endif /* DHD_USE_IDLECOUNT */ - DHD_GENERAL_UNLOCK(bus->dhd, flags); - return BCME_ERROR; - } - bus->wait_for_d3_ack = 0; - bus->suspended = TRUE; - bus->dhd->busstate = DHD_BUS_SUSPEND; -#ifndef DHD_USE_IDLECOUNT - netif_stop_queue(netdev); -#endif /* DHD_USE_IDLECOUNT */ - DHD_INFO(("prepare in suspend mode stop net device traffic\n")); - if (bus->dhd->tx_in_progress) { - DHD_ERROR(("Tx Request is not ended\n")); - bus->dhd->busstate = DHD_BUS_DATA; -#ifdef DHD_USE_IDLECOUNT - if (bus->host_suspend == TRUE) { - bus->host_suspend = FALSE; - } -#else - DHD_INFO(("1. fail to suspend, start net device traffic\n")); - netif_start_queue(netdev); -#endif /* DHD_USE_IDLECOUNT */ - - bus->wait_for_d3_ack = 1; - DHD_GENERAL_UNLOCK(bus->dhd, flags); - bus->suspended = FALSE; - return -EBUSY; - } - DHD_GENERAL_UNLOCK(bus->dhd, flags); - DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); - dhd_os_set_ioctl_resp_timeout(D3_ACK_RESP_TIMEOUT); - dhdpcie_send_mb_data(bus, H2D_HOST_D3_INFORM); - timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack, &pending); - dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); - DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); - - /* If wait_for_d3_ack was not updated because D2H MB was not received */ - if (bus->wait_for_d3_ack == 0) { - /* Check the mailbox anyway. */ - dhdpcie_handle_mb_data(bus); - if (bus->wait_for_d3_ack) { - DHD_ERROR(("D3ack without interrupt.\n")); - bus->d3_ack_war_cnt++; - } - } - - if (bus->wait_for_d3_ack) { -#if defined(BCMPCIE_OOB_HOST_WAKE) - dhdpcie_oob_intr_set(bus, TRUE); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - /* Got D3 Ack. Suspend the bus */ - DHD_GENERAL_LOCK(bus->dhd, flags); - if (!bus->force_suspend && dhd_os_check_wakelock_all(bus->dhd)) { - DHD_ERROR(("%s():Suspend failed because of wakelock " - "restoring Dongle to D0\n", __FUNCTION__)); - - /* - * Dongle still thinks that it has to be in D3 state until - * it gets a D0 Inform, but we are backing off from suspend. - * Ensure that Dongle is brought back to D0. - * - * Bringing back Dongle from D3 Ack state to D0 state is a - * 2 step process. Dongle would want to know that D0 Inform - * would be sent as a MB interrupt to bring it out of D3 Ack - * state to D0 state. So we have to send both this message. - */ - DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); - dhdpcie_send_mb_data(bus, - (H2D_HOST_D0_INFORM_IN_USE|H2D_HOST_D0_INFORM)); - DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); - - bus->suspended = FALSE; - bus->dhd->busstate = DHD_BUS_DATA; - rc = BCME_ERROR; -#ifdef DHD_USE_IDLECOUNT - if (bus->host_suspend == TRUE) { - bus->host_suspend = FALSE; - } -#else - DHD_INFO(("2. fail to suspend, start net device traffic\n")); - netif_start_queue(netdev); -#endif /* DHD_USE_IDLECOUNT */ - DHD_GENERAL_UNLOCK(bus->dhd, flags); - } else { - DHD_GENERAL_UNLOCK(bus->dhd, flags); - DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); - dhdpcie_send_mb_data(bus, H2D_HOST_D0_INFORM_IN_USE); - DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); - dhdpcie_bus_intr_disable(bus); - rc = dhdpcie_pci_suspend_resume(bus, state); -#ifdef DHD_USE_IDLECOUNT - if (bus->host_suspend == TRUE) { - dhdpcie_bus_clock_stop(bus); - } -#endif /* DHD_USE_IDLECOUNT */ - } - bus->dhd->d3ackcnt_timeout = 0; - } else if (timeleft == 0) { - bus->dhd->d3ackcnt_timeout++; - DHD_ERROR(("%s: resumed on timeout for D3 ACK d3ackcnt_timeout %d \n", - __FUNCTION__, bus->dhd->d3ackcnt_timeout)); -#if defined(DHD_FW_COREDUMP) - if (bus->dhd->d3ackcnt_timeout == 1) { - /* write core dump to file */ - dhdpcie_mem_dump(bus); - } -#endif /* DHD_FW_COREDUMP */ - bus->suspended = FALSE; - DHD_GENERAL_LOCK(bus->dhd, flags); - bus->dhd->busstate = DHD_BUS_DATA; -#ifdef DHD_USE_IDLECOUNT - if (bus->host_suspend == TRUE) { - bus->host_suspend = FALSE; - } -#else - DHD_INFO(("3. fail to suspend, start net device traffic\n")); - netif_start_queue(netdev); -#endif /* DHD_USE_IDLECOUNT */ - DHD_GENERAL_UNLOCK(bus->dhd, flags); - if (bus->dhd->d3ackcnt_timeout >= MAX_CNTL_D3ACK_TIMEOUT) { - DHD_ERROR(("%s: Event HANG send up " - "due to PCIe linkdown\n", __FUNCTION__)); -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->islinkdown = TRUE; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - dhd_os_check_hang(bus->dhd, 0, -ETIMEDOUT); - } - rc = -ETIMEDOUT; - } - bus->wait_for_d3_ack = 1; - } else { - /* Resume */ -#ifdef BCMPCIE_OOB_HOST_WAKE - DHD_OS_OOB_IRQ_WAKE_UNLOCK(bus->dhd); -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#ifdef DHD_USE_IDLECOUNT - /* wake up host controller if suspend with runtime PM */ - if (bus->host_suspend == TRUE) { - dhdpcie_bus_clock_start(bus); - } -#endif /* DHD_USE_IDLECOUNT */ - rc = dhdpcie_pci_suspend_resume(bus, state); - if (bus->dhd->busstate == DHD_BUS_SUSPEND) { - DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); - dhdpcie_send_mb_data(bus, H2D_HOST_D0_INFORM); - DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); - } - bus->suspended = FALSE; - DHD_GENERAL_LOCK(bus->dhd, flags); - bus->dhd->busstate = DHD_BUS_DATA; - DHD_GENERAL_UNLOCK(bus->dhd, flags); - DHD_INFO(("Resume completed, start net device traffic\n")); - /* resume all interface network queue. */ - dhd_bus_start_queue(bus); - dhdpcie_bus_intr_enable(bus); -#ifdef DHD_USE_IDLECOUNT - /* wake up host controller if suspend with runtime PM */ - if (bus->host_suspend == TRUE) { - bus->host_suspend = FALSE; - } -#endif /* DHD_USE_IDLECOUNT */ - } - return rc; -} - -/* Transfers bytes from host to dongle and to host again using DMA */ -static int -dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus, uint32 len, uint32 srcdelay, uint32 destdelay) -{ - if (bus->dhd == NULL) { - DHD_ERROR(("bus not inited\n")); - return BCME_ERROR; - } - if (bus->dhd->prot == NULL) { - DHD_ERROR(("prot is not inited\n")); - return BCME_ERROR; - } - if (bus->dhd->busstate != DHD_BUS_DATA) { - DHD_ERROR(("not in a readystate to LPBK is not inited\n")); - return BCME_ERROR; - } - - if (len < 5 || len > 4194296) { - DHD_ERROR(("len is too small or too large\n")); - return BCME_ERROR; - } - return dhdmsgbuf_dmaxfer_req(bus->dhd, len, srcdelay, destdelay); -} - - - -static int -dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter) -{ - int bcmerror = 0; - uint32 *cr4_regs; - - if (!bus->sih) - return BCME_ERROR; - /* 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; - - /* some chips (e.g. 43602) have two ARM cores, the CR4 is receives the firmware. */ - cr4_regs = si_setcore(bus->sih, ARMCR4_CORE_ID, 0); - - if (cr4_regs == NULL && !(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - if (cr4_regs == NULL) { /* no CR4 present on chip */ - si_core_disable(bus->sih, 0); - - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - si_core_reset(bus->sih, 0, 0); - - - /* Clear the top bit of memory */ - if (bus->ramsize) { - uint32 zeros = 0; - if (dhdpcie_bus_membytes(bus, TRUE, bus->ramsize - 4, - (uint8*)&zeros, 4) < 0) { - bcmerror = BCME_ERROR; - goto fail; - } - } - } else { - /* For CR4, - * Halt ARM - * Remove ARM reset - * Read RAM base address [0x18_0000] - * [next] Download firmware - * [done at else] Populate the reset vector - * [done at else] Remove ARM halt - */ - /* Halt ARM & remove reset */ - si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); - if (bus->sih->chip == BCM43602_CHIP_ID) { - W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKIDX, 5); - W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKPDA, 0); - W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKIDX, 7); - W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKPDA, 0); - } - /* reset last 4 bytes of RAM address. to be used for shared area */ - dhdpcie_init_shared_addr(bus); - } - } else { - if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - if (!si_iscoreup(bus->sih)) { - DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - - /* Enable remap before ARM reset but after vars. - * No backplane access in remap mode - */ - - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && - !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - } else { - if (bus->sih->chip == BCM43602_CHIP_ID) { - /* Firmware crashes on SOCSRAM access when core is in reset */ - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", - __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - si_core_reset(bus->sih, 0, 0); - si_setcore(bus->sih, ARMCR4_CORE_ID, 0); - } - - /* write vars */ - if ((bcmerror = dhdpcie_bus_write_vars(bus))) { - DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); - goto fail; - } - - - /* switch back to arm core again */ - if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - /* write address 0 with reset instruction */ - bcmerror = dhdpcie_bus_membytes(bus, TRUE, 0, - (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); - - /* now remove reset and halt and continue to run CR4 */ - } - - si_core_reset(bus->sih, 0, 0); - - /* Allow HT Clock now that the ARM is running. */ - bus->alp_only = FALSE; - - bus->dhd->busstate = DHD_BUS_LOAD; - } - -fail: - /* Always return to PCIE core */ - si_setcore(bus->sih, PCIE2_CORE_ID, 0); - - return bcmerror; -} - -static int -dhdpcie_bus_write_vars(dhd_bus_t *bus) -{ - int bcmerror = 0; - uint32 varsize, phys_size; - uint32 varaddr; - uint8 *vbuffer; - uint32 varsizew; -#ifdef DHD_DEBUG - uint8 *nvram_ularray; -#endif /* DHD_DEBUG */ - - /* 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; - - varaddr += bus->dongle_ram_base; - - if (bus->vars) { - - vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); - if (!vbuffer) - return BCME_NOMEM; - - bzero(vbuffer, varsize); - bcopy(bus->vars, vbuffer, bus->varsz); - /* Write the vars list */ - bcmerror = dhdpcie_bus_membytes(bus, TRUE, varaddr, vbuffer, varsize); - - /* Implement read back and verify later */ -#ifdef DHD_DEBUG - /* Verify NVRAM bytes */ - DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); - nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); - if (!nvram_ularray) - return BCME_NOMEM; - - /* Upload image to verify downloaded contents. */ - memset(nvram_ularray, 0xaa, varsize); - - /* Read the vars list to temp buffer for comparison */ - bcmerror = dhdpcie_bus_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", - __FUNCTION__, bcmerror, varsize, varaddr)); - } - - /* Compare the org NVRAM with the one read from RAM */ - if (memcmp(vbuffer, nvram_ularray, varsize)) { - DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); - } else - DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", - __FUNCTION__)); - - MFREE(bus->dhd->osh, nvram_ularray, varsize); -#endif /* DHD_DEBUG */ - - MFREE(bus->dhd->osh, vbuffer, varsize); - } - - phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; - - phys_size += bus->dongle_ram_base; - - /* adjust to the user specified RAM */ - DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", - phys_size, bus->ramsize)); - DHD_INFO(("Vars are at %d, orig varsize is %d\n", - varaddr, varsize)); - varsize = ((phys_size - 4) - varaddr); - - /* - * Determine the length token: - * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. - */ - if (bcmerror) { - varsizew = 0; - bus->nvram_csm = varsizew; - } else { - varsizew = varsize / 4; - varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); - bus->nvram_csm = varsizew; - varsizew = htol32(varsizew); - } - - DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); - - /* Write the length token to the last word */ - bcmerror = dhdpcie_bus_membytes(bus, TRUE, (phys_size - 4), - (uint8*)&varsizew, 4); - - return bcmerror; -} - -int -dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len) -{ - int bcmerror = BCME_OK; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Basic sanity checks */ - if (bus->dhd->up) { - bcmerror = BCME_NOTDOWN; - goto err; - } - if (!len) { - bcmerror = BCME_BUFTOOSHORT; - goto err; - } - - /* Free the old ones and replace with passed variables */ - if (bus->vars) - MFREE(bus->dhd->osh, bus->vars, bus->varsz); - - bus->vars = MALLOC(bus->dhd->osh, len); - bus->varsz = bus->vars ? len : 0; - if (bus->vars == NULL) { - bcmerror = BCME_NOMEM; - goto err; - } - - /* Copy the passed variables, which should include the terminating double-null */ - bcopy(arg, bus->vars, bus->varsz); - - -err: - return bcmerror; -} - -#ifndef BCMPCIE_OOB_HOST_WAKE -/* loop through the capability list and see if the pcie capabilty exists */ -uint8 -dhdpcie_find_pci_capability(osl_t *osh, uint8 req_cap_id) -{ - uint8 cap_id; - uint8 cap_ptr = 0; - uint8 byte_val; - - /* check for Header type 0 */ - byte_val = read_pci_cfg_byte(PCI_CFG_HDR); - if ((byte_val & 0x7f) != PCI_HEADER_NORMAL) { - DHD_ERROR(("%s : PCI config header not normal.\n", __FUNCTION__)); - goto end; - } - - /* check if the capability pointer field exists */ - byte_val = read_pci_cfg_byte(PCI_CFG_STAT); - if (!(byte_val & PCI_CAPPTR_PRESENT)) { - DHD_ERROR(("%s : PCI CAP pointer not present.\n", __FUNCTION__)); - goto end; - } - - cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR); - /* check if the capability pointer is 0x00 */ - if (cap_ptr == 0x00) { - DHD_ERROR(("%s : PCI CAP pointer is 0x00.\n", __FUNCTION__)); - goto end; - } - - /* loop thr'u the capability list and see if the pcie capabilty exists */ - - cap_id = read_pci_cfg_byte(cap_ptr); - - while (cap_id != req_cap_id) { - cap_ptr = read_pci_cfg_byte((cap_ptr + 1)); - if (cap_ptr == 0x00) break; - cap_id = read_pci_cfg_byte(cap_ptr); - } - -end: - return cap_ptr; -} - -void -dhdpcie_pme_active(osl_t *osh, bool enable) -{ - uint8 cap_ptr; - uint32 pme_csr; - - cap_ptr = dhdpcie_find_pci_capability(osh, PCI_CAP_POWERMGMTCAP_ID); - - if (!cap_ptr) { - DHD_ERROR(("%s : Power Management Capability not present\n", __FUNCTION__)); - return; - } - - pme_csr = OSL_PCI_READ_CONFIG(osh, cap_ptr + PME_CSR_OFFSET, sizeof(uint32)); - DHD_ERROR(("%s : pme_sts_ctrl 0x%x suspend(%d)\n", __FUNCTION__, pme_csr, enable)); - - pme_csr |= PME_CSR_PME_STAT; - if (enable) { - pme_csr |= PME_CSR_PME_EN; - } else { - pme_csr &= ~PME_CSR_PME_EN; - } - - OSL_PCI_WRITE_CONFIG(osh, cap_ptr + PME_CSR_OFFSET, sizeof(uint32), pme_csr); -} -#endif /* BCMPCIE_OOB_HOST_WAKE */ - -/* Add bus dump output to a buffer */ -void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - uint16 flowid; - flow_ring_node_t *flow_ring_node; - -#ifdef DHD_USE_IDLECOUNT - bus_wake(dhdp->bus); -#endif /* DHD_USE_IDLECOUNT */ - dhd_prot_print_info(dhdp, strbuf); - for (flowid = 0; flowid < dhdp->num_flow_rings; flowid++) { - flow_ring_node = DHD_FLOW_RING(dhdp, flowid); - if (flow_ring_node->active) { - bcm_bprintf(strbuf, "Flow:%d IF %d Prio %d Qlen %d ", - flow_ring_node->flowid, flow_ring_node->flow_info.ifindex, - flow_ring_node->flow_info.tid, flow_ring_node->queue.len); - dhd_prot_print_flow_ring(dhdp, flow_ring_node->prot_info, strbuf); - } - } - bcm_bprintf(strbuf, "D0 inform cnt %d\n", dhdp->bus->d0_inform_cnt); - bcm_bprintf(strbuf, "D0 inform in use cnt %d\n", dhdp->bus->d0_inform_in_use_cnt); - bcm_bprintf(strbuf, "D3 Ack WAR cnt %d\n", dhdp->bus->d3_ack_war_cnt); -} - -static void -dhd_update_txflowrings(dhd_pub_t *dhd) -{ - dll_t *item, *next; - flow_ring_node_t *flow_ring_node; - struct dhd_bus *bus = dhd->bus; - - for (item = dll_head_p(&bus->const_flowring); - !dll_end(&bus->const_flowring, item); item = next) { - if (dhd->hang_was_sent) { - break; - } - - next = dll_next_p(item); - - flow_ring_node = dhd_constlist_to_flowring(item); - dhd_prot_update_txflowring(dhd, flow_ring_node->flowid, flow_ring_node->prot_info); - } -} - -/* Mailbox ringbell Function */ -static void -dhd_bus_gen_devmb_intr(struct dhd_bus *bus) -{ - if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || - (bus->sih->buscorerev == 4)) { - DHD_ERROR(("mailbox communication not supported\n")); - return; - } - if (bus->db1_for_mb) { - /* this is a pcie core register, not the config regsiter */ - DHD_INFO(("writing a mail box interrupt to the device, through doorbell 1\n")); - si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_DB1, ~0, 0x12345678); - } - else { - DHD_INFO(("writing a mail box interrupt to the device, through config space\n")); - dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0)); - dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0)); - } -} - -/* doorbell ring Function */ -void -dhd_bus_ringbell(struct dhd_bus *bus, uint32 value) -{ - if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || - (bus->sih->buscorerev == 4)) { - si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, PCIE_INTB, PCIE_INTB); - } else { - /* this is a pcie core register, not the config regsiter */ - DHD_INFO(("writing a door bell to the device\n")); - si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_MailBox, ~0, 0x12345678); - } -} - -static void -dhd_bus_ringbell_fast(struct dhd_bus *bus, uint32 value) -{ - if (bus->pcie_mb_intr_addr) { - W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr, value); - } -} - -static void -dhd_bus_ringbell_oldpcie(struct dhd_bus *bus, uint32 value) -{ - uint32 w; - w = (R_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr) & ~PCIE_INTB) | PCIE_INTB; - W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr, w); -} - -dhd_mb_ring_t -dhd_bus_get_mbintr_fn(struct dhd_bus *bus) -{ - if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || - (bus->sih->buscorerev == 4)) { - bus->pcie_mb_intr_addr = si_corereg_addr(bus->sih, bus->sih->buscoreidx, - PCIMailBoxInt); - if (bus->pcie_mb_intr_addr) { - bus->pcie_mb_intr_osh = si_osh(bus->sih); - return dhd_bus_ringbell_oldpcie; - } - } else { - bus->pcie_mb_intr_addr = si_corereg_addr(bus->sih, bus->sih->buscoreidx, - PCIH2D_MailBox); - if (bus->pcie_mb_intr_addr) { - bus->pcie_mb_intr_osh = si_osh(bus->sih); - return dhd_bus_ringbell_fast; - } - } - return dhd_bus_ringbell; -} - -bool BCMFASTPATH -dhd_bus_dpc(struct dhd_bus *bus) -{ - uint32 intstatus = 0; - uint32 newstatus = 0; - bool resched = FALSE; /* Flag indicating resched wanted */ - unsigned long flags; - - DHD_INTR(("%s: Enter\n", __FUNCTION__)); - - DHD_GENERAL_LOCK(bus->dhd, flags); - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); - bus->intstatus = 0; - DHD_GENERAL_UNLOCK(bus->dhd, flags); - return 0; - } - DHD_GENERAL_UNLOCK(bus->dhd, flags); - - bus->ipend = FALSE; - intstatus = bus->intstatus; - - if ((bus->sih->buscorerev == 6) || (bus->sih->buscorerev == 4) || - (bus->sih->buscorerev == 2)) { - newstatus = dhdpcie_bus_cfg_read_dword(bus, PCIIntstatus, 4); - dhdpcie_bus_cfg_write_dword(bus, PCIIntstatus, 4, newstatus); - /* Merge new bits with previous */ - intstatus |= newstatus; - bus->intstatus = 0; - if (intstatus & I_MB) { - resched = dhdpcie_bus_process_mailbox_intr(bus, intstatus); - } - } else { - /* this is a PCIE core register..not a config register... */ - newstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); - intstatus |= (newstatus & bus->def_intmask); - si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, newstatus, newstatus); - if (intstatus & bus->def_intmask) { - resched = dhdpcie_bus_process_mailbox_intr(bus, intstatus); - intstatus &= ~bus->def_intmask; - } - } - - if (!resched) { - bus->intstatus = 0; - DHD_INTR(("%s: enable PCIE interrupts\n", __FUNCTION__)); - dhdpcie_bus_intr_enable(bus); - } - - DHD_INTR(("%s: Exit %d\n", __FUNCTION__, resched)); - return resched; - -} - - -static void -dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data) -{ - uint32 cur_h2d_mb_data = 0; - - DHD_INFO_HW4(("%s: H2D_MB_DATA: 0x%08X\n", __FUNCTION__, h2d_mb_data)); - dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, HTOD_MB_DATA, 0); - - if (cur_h2d_mb_data != 0) { - uint32 i = 0; - DHD_INFO(("GRRRRRRR: MB transaction is already pending 0x%04x\n", cur_h2d_mb_data)); - while ((i++ < 100) && cur_h2d_mb_data) { - OSL_DELAY(10); - dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, HTOD_MB_DATA, 0); - } - if (i >= 100) - DHD_ERROR(("waited 1ms for the dngl to ack the previous mb transaction\n")); - } - - dhd_bus_cmn_writeshared(bus, &h2d_mb_data, sizeof(uint32), HTOD_MB_DATA, 0); - dhd_bus_gen_devmb_intr(bus); - - if (h2d_mb_data == H2D_HOST_D3_INFORM) - DHD_INFO_HW4(("%s: send H2D_HOST_D3_INFORM to dongle\n", __FUNCTION__)); - if (h2d_mb_data == H2D_HOST_D0_INFORM_IN_USE) { - DHD_INFO_HW4(("%s: send H2D_HOST_D0_INFORM_IN_USE to dongle\n", __FUNCTION__)); - bus->d0_inform_in_use_cnt++; - } - if (h2d_mb_data == H2D_HOST_D0_INFORM) { - DHD_INFO_HW4(("%s: send H2D_HOST_D0_INFORM to dongle\n", __FUNCTION__)); - bus->d0_inform_cnt++; - } -} - -static void -dhdpcie_handle_mb_data(dhd_bus_t *bus) -{ - uint32 d2h_mb_data = 0; - uint32 zero = 0; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - - dhd_bus_cmn_readshared(bus, &d2h_mb_data, DTOH_MB_DATA, 0); - if (D2H_DEV_MB_INVALIDATED(d2h_mb_data)) { - DHD_INFO_HW4(("%s: Invalid D2H_MB_DATA: 0x%08x\n", - __FUNCTION__, d2h_mb_data)); - return; - } - - dhd_bus_cmn_writeshared(bus, &zero, sizeof(uint32), DTOH_MB_DATA, 0); - - DHD_INFO_HW4(("D2H_MB_DATA: 0x%08x\n", d2h_mb_data)); - if (d2h_mb_data & D2H_DEV_DS_ENTER_REQ) { - /* what should we do */ - DHD_INFO(("D2H_MB_DATA: DEEP SLEEP REQ\n")); - dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); - DHD_INFO(("D2H_MB_DATA: sent DEEP SLEEP ACK\n")); - } - if (d2h_mb_data & D2H_DEV_DS_EXIT_NOTE) { - /* what should we do */ - DHD_INFO(("D2H_MB_DATA: DEEP SLEEP EXIT\n")); - } - if (d2h_mb_data & D2H_DEV_D3_ACK) { - /* what should we do */ - DHD_INFO_HW4(("%s D2H_MB_DATA: Received D3 ACK\n", __FUNCTION__)); - if (!bus->wait_for_d3_ack) { - bus->wait_for_d3_ack = 1; - dhd_os_d3ack_wake(bus->dhd); - } - } - if (d2h_mb_data & D2H_DEV_FWHALT) { - DHD_INFO(("FW trap has happened\n")); -#ifdef DHD_DEBUG - dhdpcie_checkdied(bus, NULL, 0); -#endif - bus->dhd->busstate = DHD_BUS_DOWN; - } -} - -static bool -dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus) -{ - bool resched = FALSE; - - if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || - (bus->sih->buscorerev == 4)) { - /* Msg stream interrupt */ - if (intstatus & I_BIT1) { - resched = dhdpci_bus_read_frames(bus); - } else if (intstatus & I_BIT0) { - /* do nothing for Now */ - } - } - else { - if (intstatus & (PCIE_MB_TOPCIE_FN0_0 | PCIE_MB_TOPCIE_FN0_1)) - dhdpcie_handle_mb_data(bus); - - if (bus->dhd->busstate == DHD_BUS_SUSPEND) { - goto exit; - } - - if (intstatus & PCIE_MB_D2H_MB_MASK) { - resched = dhdpci_bus_read_frames(bus); - } - } -exit: - return resched; -} - -/* Decode dongle to host message stream */ -static bool -dhdpci_bus_read_frames(dhd_bus_t *bus) -{ - bool more = FALSE; - -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - /* There may be frames in both ctrl buf and data buf; check ctrl buf first */ - DHD_PERIM_LOCK(bus->dhd); /* Take the perimeter lock */ - dhd_prot_process_ctrlbuf(bus->dhd); - /* Unlock to give chance for resp to be handled */ - DHD_PERIM_UNLOCK(bus->dhd); /* Release the perimeter lock */ - - DHD_PERIM_LOCK(bus->dhd); /* Take the perimeter lock */ - /* update the flow ring cpls */ - dhd_update_txflowrings(bus->dhd); - - /* With heavy TX traffic, we could get a lot of TxStatus - * so add bound - */ - more |= dhd_prot_process_msgbuf_txcpl(bus->dhd, dhd_txbound); - - /* With heavy RX traffic, this routine potentially could spend some time - * processing RX frames without RX bound - */ - more |= dhd_prot_process_msgbuf_rxcpl(bus->dhd, dhd_rxbound); - - /* don't talk to the dongle if fw is about to be reloaded */ - if (bus->dhd->hang_was_sent) { - more = FALSE; - } - DHD_PERIM_UNLOCK(bus->dhd); /* Release the perimeter lock */ - - return more; -} - -static int -dhdpcie_readshared(dhd_bus_t *bus) -{ - uint32 addr = 0; - int rv, w_init, r_init; - uint32 shaddr = 0; - pciedev_shared_t *sh = bus->pcie_sh; - dhd_timeout_t tmo; - - shaddr = bus->dongle_ram_base + bus->ramsize - 4; - /* start a timer for 5 seconds */ - dhd_timeout_start(&tmo, MAX_READ_TIMEOUT); - - while (((addr == 0) || (addr == bus->nvram_csm)) && !dhd_timeout_expired(&tmo)) { - /* Read last word in memory to determine address of sdpcm_shared structure */ - addr = LTOH32(dhdpcie_bus_rtcm32(bus, shaddr)); - } - - if ((addr == 0) || (addr == bus->nvram_csm) || (addr < bus->dongle_ram_base) || - (addr > shaddr)) { - DHD_ERROR(("%s: address (0x%08x) of pciedev_shared invalid\n", - __FUNCTION__, addr)); - DHD_ERROR(("Waited %u usec, dongle is not ready\n", tmo.elapsed)); - return BCME_ERROR; - } else { - bus->shared_addr = (ulong)addr; - DHD_ERROR(("PCIe shared addr read took %u usec " - "before dongle is ready\n", tmo.elapsed)); - } - - /* Read hndrte_shared structure */ - if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)sh, - sizeof(pciedev_shared_t))) < 0) { - DHD_ERROR(("Failed to read PCIe shared struct," - "size read %d < %d\n", rv, (int)sizeof(pciedev_shared_t))); - return rv; - } - - /* Endianness */ - sh->flags = ltoh32(sh->flags); - sh->trap_addr = ltoh32(sh->trap_addr); - sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); - sh->assert_file_addr = ltoh32(sh->assert_file_addr); - sh->assert_line = ltoh32(sh->assert_line); - sh->console_addr = ltoh32(sh->console_addr); - sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); - sh->dma_rxoffset = ltoh32(sh->dma_rxoffset); - sh->rings_info_ptr = ltoh32(sh->rings_info_ptr); - /* load bus console address */ - -#ifdef DHD_DEBUG - bus->console_addr = sh->console_addr; -#endif - - /* Read the dma rx offset */ - bus->dma_rxoffset = bus->pcie_sh->dma_rxoffset; - dhd_prot_rx_dataoffset(bus->dhd, bus->dma_rxoffset); - - DHD_ERROR(("DMA RX offset from shared Area %d\n", bus->dma_rxoffset)); - - if ((sh->flags & PCIE_SHARED_VERSION_MASK) > PCIE_SHARED_VERSION) { - DHD_ERROR(("%s: pcie_shared version %d in dhd " - "is older than pciedev_shared version %d in dongle\n", - __FUNCTION__, PCIE_SHARED_VERSION, - sh->flags & PCIE_SHARED_VERSION_MASK)); - return BCME_ERROR; - } - if ((sh->flags & PCIE_SHARED_VERSION_MASK) >= 4) { - if (sh->flags & PCIE_SHARED_TXPUSH_SPRT) { -#ifdef DHDTCPACK_SUPPRESS - /* Do not use tcpack suppress as packets don't stay in queue */ - dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); -#endif - bus->txmode_push = TRUE; - } else - bus->txmode_push = FALSE; - } - DHD_ERROR(("bus->txmode_push is set to %d\n", bus->txmode_push)); - - /* Does the FW support DMA'ing r/w indices */ - if (sh->flags & PCIE_SHARED_DMA_INDEX) { - - DHD_ERROR(("%s: Host support DMAing indices: H2D:%d - D2H:%d. FW supports it\n", - __FUNCTION__, - (DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support) ? 1 : 0), - (DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support) ? 1 : 0))); - - } else if (DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support) || - DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support)) { - -#ifdef BCM_INDX_DMA - DHD_ERROR(("%s: Incompatible FW. FW does not support DMAing indices\n", - __FUNCTION__)); - return BCME_ERROR; -#endif - DHD_ERROR(("%s: Host supports DMAing indices but FW does not\n", - __FUNCTION__)); - bus->dhd->dma_d2h_ring_upd_support = FALSE; - bus->dhd->dma_h2d_ring_upd_support = FALSE; - } - - - /* get ring_info, ring_state and mb data ptrs and store the addresses in bus structure */ - { - ring_info_t ring_info; - - if ((rv = dhdpcie_bus_membytes(bus, FALSE, sh->rings_info_ptr, - (uint8 *)&ring_info, sizeof(ring_info_t))) < 0) - return rv; - - bus->h2d_mb_data_ptr_addr = ltoh32(sh->h2d_mb_data_ptr); - bus->d2h_mb_data_ptr_addr = ltoh32(sh->d2h_mb_data_ptr); - - - bus->max_sub_queues = ltoh16(ring_info.max_sub_queues); - - /* If both FW and Host support DMA'ing indices, allocate memory and notify FW - * The max_sub_queues is read from FW initialized ring_info - */ - if (DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support)) { - w_init = dhd_prot_init_index_dma_block(bus->dhd, - HOST_TO_DNGL_DMA_WRITEINDX_BUFFER, - bus->max_sub_queues); - r_init = dhd_prot_init_index_dma_block(bus->dhd, - DNGL_TO_HOST_DMA_READINDX_BUFFER, - BCMPCIE_D2H_COMMON_MSGRINGS); - - if ((w_init != BCME_OK) || (r_init != BCME_OK)) { - DHD_ERROR(("%s: Failed to allocate memory for dma'ing h2d indices" - "Host will use w/r indices in TCM\n", - __FUNCTION__)); - bus->dhd->dma_h2d_ring_upd_support = FALSE; - } - } - - if (DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support)) { - w_init = dhd_prot_init_index_dma_block(bus->dhd, - DNGL_TO_HOST_DMA_WRITEINDX_BUFFER, - BCMPCIE_D2H_COMMON_MSGRINGS); - r_init = dhd_prot_init_index_dma_block(bus->dhd, - HOST_TO_DNGL_DMA_READINDX_BUFFER, - bus->max_sub_queues); - - if ((w_init != BCME_OK) || (r_init != BCME_OK)) { - DHD_ERROR(("%s: Failed to allocate memory for dma'ing d2h indices" - "Host will use w/r indices in TCM\n", - __FUNCTION__)); - bus->dhd->dma_d2h_ring_upd_support = FALSE; - } - } - - /* read ringmem and ringstate ptrs from shared area and store in host variables */ - dhd_fillup_ring_sharedptr_info(bus, &ring_info); - - bcm_print_bytes("ring_info_raw", (uchar *)&ring_info, sizeof(ring_info_t)); - DHD_INFO(("ring_info\n")); - - DHD_ERROR(("max H2D queues %d\n", ltoh16(ring_info.max_sub_queues))); - - DHD_INFO(("mail box address\n")); - DHD_INFO(("h2d_mb_data_ptr_addr 0x%04x\n", bus->h2d_mb_data_ptr_addr)); - DHD_INFO(("d2h_mb_data_ptr_addr 0x%04x\n", bus->d2h_mb_data_ptr_addr)); - } - - bus->dhd->d2h_sync_mode = sh->flags & PCIE_SHARED_D2H_SYNC_MODE_MASK; - DHD_INFO(("d2h_sync_mode 0x%08x\n", bus->dhd->d2h_sync_mode)); - - return BCME_OK; -} -/* Read ring mem and ring state ptr info from shared are in TCM */ -static void -dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info) -{ - uint16 i = 0; - uint16 j = 0; - uint32 tcm_memloc; - uint32 d2h_w_idx_ptr, d2h_r_idx_ptr, h2d_w_idx_ptr, h2d_r_idx_ptr; - - /* Ring mem ptr info */ - /* Alloated in the order - H2D_MSGRING_CONTROL_SUBMIT 0 - H2D_MSGRING_RXPOST_SUBMIT 1 - D2H_MSGRING_CONTROL_COMPLETE 2 - D2H_MSGRING_TX_COMPLETE 3 - D2H_MSGRING_RX_COMPLETE 4 - TX_FLOW_RING 5 - */ - - { - /* ringmemptr holds start of the mem block address space */ - tcm_memloc = ltoh32(ring_info->ringmem_ptr); - - /* Find out ringmem ptr for each ring common ring */ - for (i = 0; i <= BCMPCIE_COMMON_MSGRING_MAX_ID; i++) { - bus->ring_sh[i].ring_mem_addr = tcm_memloc; - /* Update mem block */ - tcm_memloc = tcm_memloc + sizeof(ring_mem_t); - DHD_INFO(("ring id %d ring mem addr 0x%04x \n", - i, bus->ring_sh[i].ring_mem_addr)); - } - - /* Tx flow Ring */ - if (bus->txmode_push) { - bus->ring_sh[i].ring_mem_addr = tcm_memloc; - DHD_INFO(("TX ring ring id %d ring mem addr 0x%04x \n", - i, bus->ring_sh[i].ring_mem_addr)); - } - } - - /* Ring state mem ptr info */ - { - d2h_w_idx_ptr = ltoh32(ring_info->d2h_w_idx_ptr); - d2h_r_idx_ptr = ltoh32(ring_info->d2h_r_idx_ptr); - h2d_w_idx_ptr = ltoh32(ring_info->h2d_w_idx_ptr); - h2d_r_idx_ptr = ltoh32(ring_info->h2d_r_idx_ptr); - /* Store h2d common ring write/read pointers */ - for (i = 0; i < BCMPCIE_H2D_COMMON_MSGRINGS; i++) { - bus->ring_sh[i].ring_state_w = h2d_w_idx_ptr; - bus->ring_sh[i].ring_state_r = h2d_r_idx_ptr; - - /* update mem block */ - h2d_w_idx_ptr = h2d_w_idx_ptr + sizeof(uint32); - h2d_r_idx_ptr = h2d_r_idx_ptr + sizeof(uint32); - - DHD_INFO(("h2d w/r : idx %d write %x read %x \n", i, - bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); - } - /* Store d2h common ring write/read pointers */ - for (j = 0; j < BCMPCIE_D2H_COMMON_MSGRINGS; j++, i++) { - bus->ring_sh[i].ring_state_w = d2h_w_idx_ptr; - bus->ring_sh[i].ring_state_r = d2h_r_idx_ptr; - - /* update mem block */ - d2h_w_idx_ptr = d2h_w_idx_ptr + sizeof(uint32); - d2h_r_idx_ptr = d2h_r_idx_ptr + sizeof(uint32); - - DHD_INFO(("d2h w/r : idx %d write %x read %x \n", i, - bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); - } - - /* Store txflow ring write/read pointers */ - if (bus->txmode_push) { - bus->ring_sh[i].ring_state_w = h2d_w_idx_ptr; - bus->ring_sh[i].ring_state_r = h2d_r_idx_ptr; - - DHD_INFO(("txflow : idx %d write %x read %x \n", i, - bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); - } else { - for (j = 0; j < (bus->max_sub_queues - BCMPCIE_H2D_COMMON_MSGRINGS); - i++, j++) - { - bus->ring_sh[i].ring_state_w = h2d_w_idx_ptr; - bus->ring_sh[i].ring_state_r = h2d_r_idx_ptr; - - /* update mem block */ - h2d_w_idx_ptr = h2d_w_idx_ptr + sizeof(uint32); - h2d_r_idx_ptr = h2d_r_idx_ptr + sizeof(uint32); - - DHD_INFO(("FLOW Rings h2d w/r : idx %d write %x read %x \n", i, - bus->ring_sh[i].ring_state_w, - bus->ring_sh[i].ring_state_r)); - } - } - } -} - -/* Initialize bus module: prepare for communication w/dongle */ -int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) -{ - dhd_bus_t *bus = dhdp->bus; - int ret = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(bus->dhd); - if (!bus->dhd) - return 0; - - /* Make sure we're talking to the core. */ - bus->reg = si_setcore(bus->sih, PCIE2_CORE_ID, 0); - ASSERT(bus->reg != NULL); - - /* before opening up bus for data transfer, check if shared are is intact */ - ret = dhdpcie_readshared(bus); - if (ret < 0) { - DHD_ERROR(("%s :Shared area read failed \n", __FUNCTION__)); - return ret; - } - - - /* Make sure we're talking to the core. */ - bus->reg = si_setcore(bus->sih, PCIE2_CORE_ID, 0); - ASSERT(bus->reg != NULL); - - /* Set bus state according to enable result */ - dhdp->busstate = DHD_BUS_DATA; - - /* Enable the interrupt after device is up */ - dhdpcie_bus_intr_enable(bus); - - /* bcmsdh_intr_unmask(bus->sdh); */ - -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; - bus->idletime = (int32)MAX_IDLE_COUNT; - bus->host_suspend = FALSE; - atomic_set(&bus->runtime_suspend, 0); - init_waitqueue_head(&bus->rpm_queue); -#endif /* DHD_USE_IDLECOUNT */ - - /* Init counter. */ - bus->d3_ack_war_cnt = 0; - - return ret; - -} - - -static void -dhdpcie_init_shared_addr(dhd_bus_t *bus) -{ - uint32 addr = 0; - uint32 val = 0; - addr = bus->dongle_ram_base + bus->ramsize - 4; -#ifdef DHD_USE_IDLECOUNT - bus_wake(bus); -#endif /* DHD_USE_IDLECOUNT */ - dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val)); -} - - -bool -dhdpcie_chipmatch(uint16 vendor, uint16 device) -{ - if (vendor != PCI_VENDOR_ID_BROADCOM) { - DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, - vendor, device)); - return (-ENODEV); - } - - if ((device == BCM4350_D11AC_ID) || (device == BCM4350_D11AC2G_ID) || - (device == BCM4350_D11AC5G_ID) || BCM4350_CHIP(device)) - return 0; - - if ((device == BCM4354_D11AC_ID) || (device == BCM4354_D11AC2G_ID) || - (device == BCM4354_D11AC5G_ID) || (device == BCM4354_CHIP_ID)) - return 0; - - if ((device == BCM4356_D11AC_ID) || (device == BCM4356_D11AC2G_ID) || - (device == BCM4356_D11AC5G_ID) || (device == BCM4356_CHIP_ID)) - return 0; - - if ((device == BCM4345_D11AC_ID) || (device == BCM4345_D11AC2G_ID) || - (device == BCM4345_D11AC5G_ID) || (device == BCM4345_CHIP_ID)) - return 0; - - if ((device == BCM4335_D11AC_ID) || (device == BCM4335_D11AC2G_ID) || - (device == BCM4335_D11AC5G_ID) || (device == BCM4335_CHIP_ID)) - return 0; - - if ((device == BCM43602_D11AC_ID) || (device == BCM43602_D11AC2G_ID) || - (device == BCM43602_D11AC5G_ID) || (device == BCM43602_CHIP_ID)) - return 0; - - if ((device == BCM43569_D11AC_ID) || (device == BCM43569_D11AC2G_ID) || - (device == BCM43569_D11AC5G_ID) || (device == BCM43569_CHIP_ID)) - return 0; - - if ((device == BCM4358_D11AC_ID) || (device == BCM4358_D11AC2G_ID) || - (device == BCM4358_D11AC5G_ID) || (device == BCM4358_CHIP_ID)) - return 0; - - if ((device == BCM4349_D11AC_ID) || (device == BCM4349_D11AC2G_ID) || - (device == BCM4349_D11AC5G_ID) || (device == BCM4349_CHIP_ID)) - return 0; - if ((device == BCM4355_D11AC_ID) || (device == BCM4355_D11AC2G_ID) || - (device == BCM4355_D11AC5G_ID) || (device == BCM4355_CHIP_ID)) - return 0; - if ((device == BCM4359_D11AC_ID) || (device == BCM4359_D11AC2G_ID) || - (device == BCM4359_D11AC5G_ID) || (device == BCM4359_CHIP_ID)) - return 0; - - - DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, vendor, device)); - return (-ENODEV); -} - - -/* - -Name: dhdpcie_cc_nvmshadow - -Description: -A shadow of OTP/SPROM exists in ChipCommon Region -betw. 0x800 and 0xBFF (Backplane Addr. 0x1800_0800 and 0x1800_0BFF). -Strapping option (SPROM vs. OTP), presence of OTP/SPROM and its size -can also be read from ChipCommon Registers. -*/ - -static int -dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b) -{ - uint16 dump_offset = 0; - uint32 dump_size = 0, otp_size = 0, sprom_size = 0; - - /* Table for 65nm OTP Size (in bits) */ - int otp_size_65nm[8] = {0, 2048, 4096, 8192, 4096, 6144, 512, 1024}; - - volatile uint16 *nvm_shadow; - - uint cur_coreid; - uint chipc_corerev; - chipcregs_t *chipcregs; - - - /* Save the current core */ - cur_coreid = si_coreid(bus->sih); - /* Switch to ChipC */ - chipcregs = (chipcregs_t *)si_setcore(bus->sih, CC_CORE_ID, 0); - chipc_corerev = si_corerev(bus->sih); - - /* Check ChipcommonCore Rev */ - if (chipc_corerev < 44) { - DHD_ERROR(("%s: ChipcommonCore Rev %d < 44\n", __FUNCTION__, chipc_corerev)); - return BCME_UNSUPPORTED; - } - - /* Check ChipID */ - if (((uint16)bus->sih->chip != BCM4350_CHIP_ID) && - ((uint16)bus->sih->chip != BCM4345_CHIP_ID)) { - DHD_ERROR(("%s: cc_nvmdump cmd. supported for 4350/4345 only\n", - __FUNCTION__)); - return BCME_UNSUPPORTED; - } - - /* Check if SRC_PRESENT in SpromCtrl(0x190 in ChipCommon Regs) is set */ - if (chipcregs->sromcontrol & SRC_PRESENT) { - /* SPROM Size: 1Kbits (0x0), 4Kbits (0x1), 16Kbits(0x2) */ - sprom_size = (1 << (2 * ((chipcregs->sromcontrol & SRC_SIZE_MASK) - >> SRC_SIZE_SHIFT))) * 1024; - bcm_bprintf(b, "\nSPROM Present (Size %d bits)\n", sprom_size); - } - - if (chipcregs->sromcontrol & SRC_OTPPRESENT) { - bcm_bprintf(b, "\nOTP Present"); - - if (((chipcregs->otplayout & OTPL_WRAP_TYPE_MASK) >> OTPL_WRAP_TYPE_SHIFT) - == OTPL_WRAP_TYPE_40NM) { - /* 40nm OTP: Size = (OtpSize + 1) * 1024 bits */ - otp_size = (((chipcregs->capabilities & CC_CAP_OTPSIZE) - >> CC_CAP_OTPSIZE_SHIFT) + 1) * 1024; - bcm_bprintf(b, "(Size %d bits)\n", otp_size); - } else { - /* This part is untested since newer chips have 40nm OTP */ - otp_size = otp_size_65nm[(chipcregs->capabilities & CC_CAP_OTPSIZE) - >> CC_CAP_OTPSIZE_SHIFT]; - bcm_bprintf(b, "(Size %d bits)\n", otp_size); - DHD_INFO(("%s: 65nm/130nm OTP Size not tested. \n", - __FUNCTION__)); - } - } - - if (((chipcregs->sromcontrol & SRC_PRESENT) == 0) && - ((chipcregs->capabilities & CC_CAP_OTPSIZE) == 0)) { - DHD_ERROR(("%s: SPROM and OTP could not be found \n", - __FUNCTION__)); - return BCME_NOTFOUND; - } - - /* Check the strapping option in SpromCtrl: Set = OTP otherwise SPROM */ - if ((chipcregs->sromcontrol & SRC_OTPSEL) && - (chipcregs->sromcontrol & SRC_OTPPRESENT)) { - - bcm_bprintf(b, "OTP Strap selected.\n" - "\nOTP Shadow in ChipCommon:\n"); - - dump_size = otp_size / 16 ; /* 16bit words */ - - } else if (((chipcregs->sromcontrol & SRC_OTPSEL) == 0) && - (chipcregs->sromcontrol & SRC_PRESENT)) { - - bcm_bprintf(b, "SPROM Strap selected\n" - "\nSPROM Shadow in ChipCommon:\n"); - - /* If SPROM > 8K only 8Kbits is mapped to ChipCommon (0x800 - 0xBFF) */ - /* dump_size in 16bit words */ - dump_size = sprom_size > 8 ? (8 * 1024) / 16 : sprom_size / 16; - } - else { - DHD_ERROR(("%s: NVM Shadow does not exist in ChipCommon\n", - __FUNCTION__)); - return BCME_NOTFOUND; - } - - if (bus->regs == NULL) { - DHD_ERROR(("ChipCommon Regs. not initialized\n")); - return BCME_NOTREADY; - } else { - bcm_bprintf(b, "\n OffSet:"); - - /* Point to the SPROM/OTP shadow in ChipCommon */ - nvm_shadow = chipcregs->sromotp; - - /* - * Read 16 bits / iteration. - * dump_size & dump_offset in 16-bit words - */ - while (dump_offset < dump_size) { - if (dump_offset % 2 == 0) - /* Print the offset in the shadow space in Bytes */ - bcm_bprintf(b, "\n 0x%04x", dump_offset * 2); - - bcm_bprintf(b, "\t0x%04x", *(nvm_shadow + dump_offset)); - dump_offset += 0x1; - } - } - - /* Switch back to the original core */ - si_setcore(bus->sih, cur_coreid, 0); - - return BCME_OK; -} - - -uint8 BCMFASTPATH -dhd_bus_is_txmode_push(dhd_bus_t *bus) -{ - return bus->txmode_push; -} - -void dhd_bus_clean_flow_ring(dhd_bus_t *bus, void *node) -{ - void *pkt; - flow_queue_t *queue; - flow_ring_node_t *flow_ring_node = (flow_ring_node_t *)node; - unsigned long flags; - - queue = &flow_ring_node->queue; - -#ifdef DHDTCPACK_SUPPRESS - /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, - * when there is a newly coming packet from network stack. - */ - dhd_tcpack_info_tbl_clean(bus->dhd); -#endif /* DHDTCPACK_SUPPRESS */ - - /* clean up BUS level info */ - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - - /* Flush all pending packets in the queue, if any */ - while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { - PKTFREE(bus->dhd->osh, pkt, TRUE); - } - ASSERT(flow_queue_empty(queue)); - - flow_ring_node->status = FLOW_RING_STATUS_CLOSED; - flow_ring_node->active = FALSE; - dll_delete(&flow_ring_node->list); - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - - /* Call Flow ring clean up */ - dhd_prot_clean_flow_ring(bus->dhd, flow_ring_node->prot_info); - dhd_flowid_free(bus->dhd, flow_ring_node->flow_info.ifindex, - flow_ring_node->flowid); - -} - -/* - * Allocate a Flow ring buffer, - * Init Ring buffer, - * Send Msg to device about flow ring creation -*/ -int -dhd_bus_flow_ring_create_request(dhd_bus_t *bus, void *arg) -{ - flow_ring_node_t *flow_ring_node = (flow_ring_node_t *)arg; - - DHD_INFO(("%s :Flow create\n", __FUNCTION__)); - - /* Send Msg to device about flow ring creation */ - if (dhd_prot_flow_ring_create(bus->dhd, flow_ring_node) != BCME_OK) - return BCME_NOMEM; - - return BCME_OK; -} - -void -dhd_bus_flow_ring_create_response(dhd_bus_t *bus, uint16 flowid, int32 status) -{ - flow_ring_node_t *flow_ring_node; - unsigned long flags; - - DHD_INFO(("%s :Flow Response %d \n", __FUNCTION__, flowid)); - - flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); - ASSERT(flow_ring_node->flowid == flowid); - - if (status != BCME_OK) { - DHD_ERROR(("%s Flow create Response failure error status = %d \n", - __FUNCTION__, status)); - /* Call Flow clean up */ - dhd_bus_clean_flow_ring(bus, flow_ring_node); - return; - } - - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - flow_ring_node->status = FLOW_RING_STATUS_OPEN; - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - - dhd_bus_schedule_queue(bus, flowid, FALSE); - - return; -} - -int -dhd_bus_flow_ring_delete_request(dhd_bus_t *bus, void *arg) -{ - void * pkt; - flow_queue_t *queue; - flow_ring_node_t *flow_ring_node; - unsigned long flags; - - DHD_INFO(("%s :Flow Delete\n", __FUNCTION__)); - - flow_ring_node = (flow_ring_node_t *)arg; - - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - if (flow_ring_node->status & FLOW_RING_STATUS_DELETE_PENDING) { - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - DHD_ERROR(("%s :Delete Pending\n", __FUNCTION__)); - return BCME_ERROR; - } - flow_ring_node->status = FLOW_RING_STATUS_DELETE_PENDING; - - queue = &flow_ring_node->queue; /* queue associated with flow ring */ - -#ifdef DHDTCPACK_SUPPRESS - /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, - * when there is a newly coming packet from network stack. - */ - dhd_tcpack_info_tbl_clean(bus->dhd); -#endif /* DHDTCPACK_SUPPRESS */ - /* Flush all pending packets in the queue, if any */ - while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { - PKTFREE(bus->dhd->osh, pkt, TRUE); - } - ASSERT(flow_queue_empty(queue)); - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - - /* Send Msg to device about flow ring deletion */ - dhd_prot_flow_ring_delete(bus->dhd, flow_ring_node); - - return BCME_OK; -} - -void -dhd_bus_flow_ring_delete_response(dhd_bus_t *bus, uint16 flowid, uint32 status) -{ - flow_ring_node_t *flow_ring_node; - - DHD_INFO(("%s :Flow Delete Response %d \n", __FUNCTION__, flowid)); - - flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); - ASSERT(flow_ring_node->flowid == flowid); - - if (status != BCME_OK) { - DHD_ERROR(("%s Flow Delete Response failure error status = %d \n", - __FUNCTION__, status)); - return; - } - /* Call Flow clean up */ - dhd_bus_clean_flow_ring(bus, flow_ring_node); - - return; - -} - -int dhd_bus_flow_ring_flush_request(dhd_bus_t *bus, void *arg) -{ - void *pkt; - flow_queue_t *queue; - flow_ring_node_t *flow_ring_node; - unsigned long flags; - - DHD_INFO(("%s :Flow Delete\n", __FUNCTION__)); - - flow_ring_node = (flow_ring_node_t *)arg; - queue = &flow_ring_node->queue; /* queue associated with flow ring */ - - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - -#ifdef DHDTCPACK_SUPPRESS - /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, - * when there is a newly coming packet from network stack. - */ - dhd_tcpack_info_tbl_clean(bus->dhd); -#endif /* DHDTCPACK_SUPPRESS */ - /* Flush all pending packets in the queue, if any */ - while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { - PKTFREE(bus->dhd->osh, pkt, TRUE); - } - ASSERT(flow_queue_empty(queue)); - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - - /* Send Msg to device about flow ring flush */ - dhd_prot_flow_ring_flush(bus->dhd, flow_ring_node); - - flow_ring_node->status = FLOW_RING_STATUS_FLUSH_PENDING; - return BCME_OK; -} - -void -dhd_bus_flow_ring_flush_response(dhd_bus_t *bus, uint16 flowid, uint32 status) -{ - flow_ring_node_t *flow_ring_node; - - if (status != BCME_OK) { - DHD_ERROR(("%s Flow flush Response failure error status = %d \n", - __FUNCTION__, status)); - return; - } - - flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); - ASSERT(flow_ring_node->flowid == flowid); - - flow_ring_node->status = FLOW_RING_STATUS_OPEN; - return; -} - -uint32 -dhd_bus_max_h2d_queues(struct dhd_bus *bus, uint8 *txpush) -{ - if (bus->txmode_push) - *txpush = 1; - else - *txpush = 0; - return bus->max_sub_queues; -} - -int -dhdpcie_bus_clock_start(struct dhd_bus *bus) -{ - return dhdpcie_start_host_pcieclock(bus); -} - -int -dhdpcie_bus_clock_stop(struct dhd_bus *bus) -{ - return dhdpcie_stop_host_pcieclock(bus); -} - -int -dhdpcie_bus_disable_device(struct dhd_bus *bus) -{ - return dhdpcie_disable_device(bus); -} - -int -dhdpcie_bus_enable_device(struct dhd_bus *bus) -{ - return dhdpcie_enable_device(bus); -} - -int -dhdpcie_bus_alloc_resource(struct dhd_bus *bus) -{ - return dhdpcie_alloc_resource(bus); -} - -void -dhdpcie_bus_free_resource(struct dhd_bus *bus) -{ - dhdpcie_free_resource(bus); -} - -int -dhd_bus_request_irq(struct dhd_bus *bus) -{ - return dhdpcie_bus_request_irq(bus); -} - -bool -dhdpcie_bus_dongle_attach(struct dhd_bus *bus) -{ - return dhdpcie_dongle_attach(bus); -} - -int -dhd_bus_release_dongle(struct dhd_bus *bus) -{ - bool dongle_isolation; - osl_t *osh; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus) { - osh = bus->osh; - ASSERT(osh); - - if (bus->dhd) { - dongle_isolation = bus->dhd->dongle_isolation; - dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE); - } - } - - return 0; -} - -#ifdef DHD_USE_IDLECOUNT -bool dhd_bus_is_resume_done(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - - return (atomic_read(&bus->runtime_suspend) == 0); -} - -bool bus_wake(dhd_bus_t *bus) -{ - int retry = 0; - - DHD_TRACE(("%s Enter\n", __FUNCTION__)); - - if (!bus || !bus->dhd) - return FALSE; - - bus->idlecount = 0; - - if (bus->dhd->up == FALSE) { - return FALSE; - } - - if (bus->suspended && bus->host_suspend) { - bus->bus_wake = 1; - smp_wmb(); - wake_up_interruptible(&bus->rpm_queue); - SMP_RD_BARRIER_DEPENDS(); - while (atomic_read(&bus->runtime_suspend) && retry++ != MAX_RESUME_WAIT) { - SMP_RD_BARRIER_DEPENDS(); - wait_event_interruptible_timeout(bus->rpm_queue, - !atomic_read(&bus->runtime_suspend), - msecs_to_jiffies(1)); - } - DHD_ERROR(("%s wakeup the bus with retry count : %d \n", __FUNCTION__, retry)); - if (atomic_read(&bus->runtime_suspend)) { - DHD_ERROR(("%s wakeup the bus failed with retry count : %d\n", - __FUNCTION__, retry)); - return FALSE; - } - } - - return TRUE; -} - -bool dhd_bus_wake(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - return bus_wake(bus); -} - -bool bus_wakeup(dhd_bus_t *bus) -{ - bus->idlecount = 0; - SMP_RD_BARRIER_DEPENDS(); - if (bus->suspended && bus->host_suspend) { - bus->bus_wake = 1; - smp_wmb(); - wake_up_interruptible(&bus->rpm_queue); - SMP_RD_BARRIER_DEPENDS(); - return TRUE; - } - - return FALSE; -} - -bool dhd_bus_wakeup(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - return bus_wakeup(bus); -} -#endif /* DHD_USE_IDLECOUNT */ - -#ifdef BCMPCIE_OOB_HOST_WAKE -int dhd_bus_oob_intr_register(dhd_pub_t *dhdp) -{ - return dhdpcie_oob_intr_register(dhdp->bus); -} - -void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp) -{ - dhdpcie_oob_intr_unregister(dhdp->bus); -} - -void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable) -{ - dhdpcie_oob_intr_set(dhdp->bus, enable); -} -#endif /* BCMPCIE_OOB_HOST_WAKE */ diff --git a/drivers/net/wireless/bcmdhd/dhd_pcie.h b/drivers/net/wireless/bcmdhd/dhd_pcie.h deleted file mode 100644 index e75d26eb8e32..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_pcie.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Linux DHD Bus Module for PCIE - * - * Copyright (C) 1999-2017, Broadcom Corporation - * Copyright (C) 2015 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_pcie.h 614103 2016-01-21 04:01:39Z $ - */ - - -#ifndef dhd_pcie_h -#define dhd_pcie_h - -#include -#include -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM -#ifdef CONFIG_ARCH_MSM8994 -#include -#else -#include -#endif -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ -#ifdef DHD_USE_IDLECOUNT -#include -#include - -#if !defined(CUSTOM_DHD_WATCHDOG_MS) || (CUSTOM_DHD_WATCHDOG_MS <= 0) -#error "MUST define CUSTOM_DHD_WATCHDOG_MS > 0 when DHD_USE_IDLECOUNT defined." -#endif - -#ifndef MAX_IDLE_COUNT -#define MAX_IDLE_COUNT 16 -#endif /* MAX_IDLE_COUNT */ - -#ifndef MAX_RESUME_WAIT -#define MAX_RESUME_WAIT 100 -#endif /* MAX_RESUME_WAIT */ -#endif /* DHD_USE_IDLECOUNT */ - -/* defines */ - -#define PCMSGBUF_HDRLEN 0 -#define DONGLE_REG_MAP_SIZE (32 * 1024) -#define DONGLE_TCM_MAP_SIZE (4096 * 1024) -#define DONGLE_MIN_MEMSIZE (128 *1024) -#ifdef DHD_DEBUG -#define DHD_PCIE_SUCCESS 0 -#define DHD_PCIE_FAILURE 1 -#endif /* DHD_DEBUG */ -#define REMAP_ENAB(bus) ((bus)->remap) -#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) - -#define MAX_DHD_TX_FLOWS 256 - -/* user defined data structures */ -#ifdef DHD_DEBUG -/* Device console log buffer state */ -#define CONSOLE_LINE_MAX 192 -#define CONSOLE_BUFFER_MAX 2024 - - -typedef struct dhd_console { - uint count; /* Poll interval msec counter */ - uint log_addr; /* Log struct address (fixed) */ - hnd_log_t log; /* Log struct (host copy) */ - uint bufsize; /* Size of log buffer */ - uint8 *buf; /* Log buffer (host copy) */ - uint last; /* Last buffer read index */ -} dhd_console_t; -#endif /* DHD_DEBUG */ -typedef struct ring_sh_info { - uint32 ring_mem_addr; - uint32 ring_state_w; - uint32 ring_state_r; -} ring_sh_info_t; - -typedef struct dhd_bus { - dhd_pub_t *dhd; - struct pci_dev *dev; /* pci device handle */ - dll_t const_flowring; /* constructed list of tx flowring queues */ - - si_t *sih; /* Handle for SI calls */ - char *vars; /* Variables (from CIS and/or other) */ - uint varsz; /* Size of variables buffer */ - uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ - sbpcieregs_t *reg; /* Registers for PCIE core */ - - uint armrev; /* CPU core revision */ - uint ramrev; /* SOCRAM core revision */ - uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ - uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ - uint32 srmemsize; /* Size of SRMEM */ - - uint32 bus; /* gSPI or SDIO bus */ - uint32 intstatus; /* Intstatus bits (events) pending */ - bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ - bool fcstate; /* State of dongle flow-control */ - - uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ - char *fw_path; /* module_param: path to firmware image */ - char *nv_path; /* module_param: path to nvram vars file */ - char *nvram_params; /* user specified nvram params. */ - int nvram_params_len; - - struct pktq txq; /* Queue length used for flow-control */ - - uint rxlen; /* Length of valid data in buffer */ - - - bool intr; /* Use interrupts */ - bool ipend; /* Device interrupt is pending */ - bool intdis; /* Interrupts disabled by isr */ - uint intrcount; /* Count of device interrupt callbacks */ - uint lastintrs; /* Count as of last watchdog timer */ - -#ifdef DHD_DEBUG - dhd_console_t console; /* Console output polling support */ - uint console_addr; /* Console address from shared struct */ -#endif /* DHD_DEBUG */ - - bool alp_only; /* Don't use HT clock (ALP only) */ - - bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram - * Available with socram rev 16 - * Remap region not DMA-able - */ - uint32 resetinstr; - uint32 dongle_ram_base; - - ulong shared_addr; - pciedev_shared_t *pcie_sh; - bool bus_flowctrl; - ioctl_comp_resp_msg_t ioct_resp; - uint32 dma_rxoffset; - volatile char *regs; /* pci device memory va */ - volatile char *tcm; /* pci device memory va */ - uint32 tcm_size; -#ifdef CONFIG_ARCH_MSM8994 - uint32 bar1_win_base; - uint32 bar1_win_mask; -#endif - osl_t *osh; - uint32 nvram_csm; /* Nvram checksum */ - uint16 pollrate; - uint16 polltick; - - uint32 *pcie_mb_intr_addr; - void *pcie_mb_intr_osh; - bool sleep_allowed; - - /* version 3 shared struct related info start */ - ring_sh_info_t ring_sh[BCMPCIE_COMMON_MSGRINGS + MAX_DHD_TX_FLOWS]; - uint8 h2d_ring_count; - uint8 d2h_ring_count; - uint32 ringmem_ptr; - uint32 ring_state_ptr; - - uint32 d2h_dma_scratch_buffer_mem_addr; - - uint32 h2d_mb_data_ptr_addr; - uint32 d2h_mb_data_ptr_addr; - /* version 3 shared struct related info end */ - - uint32 def_intmask; - bool ltrsleep_on_unload; - uint wait_for_d3_ack; - uint8 txmode_push; - uint32 max_sub_queues; - bool db1_for_mb; - bool suspended; -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - struct msm_pcie_register_event pcie_event; - bool islinkdown; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ -#ifdef PCIE_TX_DEFERRAL - struct workqueue_struct *tx_wq; - struct work_struct create_flow_work; - struct work_struct delete_flow_work; - unsigned long *delete_flow_map; - struct sk_buff_head orphan_list; -#endif /* PCIE_TX_DEFERRAL */ -#ifdef DHD_USE_IDLECOUNT - int32 idlecount; /* Activity timeout counter */ - int32 idletime; /* Control for activity timeout */ - int32 bus_wake; /* For wake up the bus */ - atomic_t runtime_suspend; /* For check runtime suspend end */ - bool host_suspend; /* For checking host is suspended */ - wait_queue_head_t rpm_queue; /* wait-queue for bus wake up */ -#endif /* DHD_USE_IDLECOUNT */ - struct mutex pm_lock; /* Synchronize for system PM & runtime PM */ - struct mutex host_clock_lock; /* Synchronize for host clock switching. */ - uint32 d0_inform_cnt; - uint32 d0_inform_in_use_cnt; - uint8 force_suspend; - uint32 d3_ack_war_cnt; -#ifdef SOMC_1DK_NV_PATH - uint16 subsystem_id; -#endif /* SOMC_1DK_NV_PATH */ -} dhd_bus_t; - -/* function declarations */ - -extern uint32* dhdpcie_bus_reg_map(osl_t *osh, ulong addr, int size); -extern int dhdpcie_bus_register(void); -extern void dhdpcie_bus_unregister(void); -extern bool dhdpcie_chipmatch(uint16 vendor, uint16 device); - -extern struct dhd_bus* dhdpcie_bus_attach(osl_t *osh, volatile char* regs, - volatile char* tcm, uint32 tcm_size); -extern uint32 dhdpcie_bus_cfg_read_dword(struct dhd_bus *bus, uint32 addr, uint32 size); -extern void dhdpcie_bus_cfg_write_dword(struct dhd_bus *bus, uint32 addr, uint32 size, uint32 data); -extern void dhdpcie_bus_intr_disable(struct dhd_bus *bus); -extern void dhdpcie_bus_remove_prep(struct dhd_bus *bus); -extern void dhdpcie_bus_release(struct dhd_bus *bus); -extern int32 dhdpcie_bus_isr(struct dhd_bus *bus); -extern void dhdpcie_free_irq(dhd_bus_t *bus); -extern int dhdpcie_bus_suspend(struct dhd_bus *bus, bool state); -extern int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state); -#ifndef BCMPCIE_OOB_HOST_WAKE -extern void dhdpcie_pme_active(osl_t *osh, bool enable); -#endif /* !BCMPCIE_OOB_HOST_WAKE */ -extern int dhdpcie_start_host_pcieclock(dhd_bus_t *bus); -extern int dhdpcie_stop_host_pcieclock(dhd_bus_t *bus); -extern int dhdpcie_disable_device(dhd_bus_t *bus); -extern int dhdpcie_enable_device(dhd_bus_t *bus); -extern int dhdpcie_alloc_resource(dhd_bus_t *bus); -extern void dhdpcie_free_resource(dhd_bus_t *bus); -extern int dhdpcie_bus_request_irq(struct dhd_bus *bus); -#ifdef BCMPCIE_OOB_HOST_WAKE -extern int dhdpcie_oob_intr_register(dhd_bus_t *bus); -extern void dhdpcie_oob_intr_unregister(dhd_bus_t *bus); -extern void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - -extern int dhd_buzzz_dump_dngl(dhd_bus_t *bus); -#endif /* dhd_pcie_h */ diff --git a/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c b/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c deleted file mode 100644 index 357079c30fec..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c +++ /dev/null @@ -1,1392 +0,0 @@ -/* - * Linux DHD Bus Module for PCIE - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_pcie_linux.c 627805 2016-03-28 13:12:47Z $ - */ - - -/* include files */ -#include -#include -#include -#include -#include -#include -#include -#if defined(DHD_DEBUG) -#include -#include -#endif /* defined(DHD_DEBUG) */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_ARCH_MSM -#ifdef CONFIG_ARCH_MSM8994 -#include -#else -#include -#endif -#endif /* CONFIG_ARCH_MSM */ - -#define PCI_CFG_RETRY 10 -#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ -#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ - -#define OSL_PKTTAG_CLEAR(p) \ -do { \ - struct sk_buff *s = (struct sk_buff *)(p); \ - ASSERT(OSL_PKTTAG_SZ == 32); \ - *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ - *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ - *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ - *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ -} while (0) - - -/* user defined data structures */ - -typedef struct dhd_pc_res { - uint32 bar0_size; - void* bar0_addr; - uint32 bar1_size; - void* bar1_addr; -} pci_config_res, *pPci_config_res; - -typedef bool (*dhdpcie_cb_fn_t)(void *); - -typedef struct dhdpcie_info -{ - dhd_bus_t *bus; - osl_t *osh; - struct pci_dev *dev; /* pci device handle */ - volatile char *regs; /* pci device memory va */ - volatile char *tcm; /* pci device memory va */ - uint32 tcm_size; /* pci device memory size */ - struct pcos_info *pcos_info; - uint16 last_intrstatus; /* to cache intrstatus */ - int irq; - char pciname[32]; - struct pci_saved_state* default_state; - struct pci_saved_state* state; -#ifdef BCMPCIE_OOB_HOST_WAKE - void *os_cxt; /* Pointer to per-OS private data */ -#endif /* BCMPCIE_OOB_HOST_WAKE */ -} dhdpcie_info_t; - - -struct pcos_info { - dhdpcie_info_t *pc; - spinlock_t lock; - wait_queue_head_t intr_wait_queue; - struct timer_list tuning_timer; - int tuning_timer_exp; - atomic_t timer_enab; - struct tasklet_struct tuning_tasklet; -}; - -#ifdef BCMPCIE_OOB_HOST_WAKE -typedef struct dhdpcie_os_info { - int oob_irq_num; /* valid when hardware or software oob in use */ - unsigned long oob_irq_flags; /* valid when hardware or software oob in use */ - bool oob_irq_registered; - bool oob_irq_enabled; - bool oob_irq_wake_enabled; - spinlock_t oob_irq_spinlock; - void *dev; /* handle to the underlying device */ -} dhdpcie_os_info_t; -#endif /* BCMPCIE_OOB_HOST_WAKE */ - -/* function declarations */ -static int __devinit -dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -static void __devexit -dhdpcie_pci_remove(struct pci_dev *pdev); -static int dhdpcie_init(struct pci_dev *pdev); -static irqreturn_t dhdpcie_isr(int irq, void *arg); -/* OS Routine functions for PCI suspend/resume */ - -static int dhdpcie_pci_suspend(struct pci_dev *dev, pm_message_t state); -static int dhdpcie_pci_resume(struct pci_dev *dev); -static int dhdpcie_resume_dev(struct pci_dev *dev); -static int dhdpcie_suspend_dev(struct pci_dev *dev); -static struct pci_device_id dhdpcie_pci_devid[] __devinitdata = { - { vendor: 0x14e4, - device: PCI_ANY_ID, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - class: PCI_CLASS_NETWORK_OTHER << 8, - class_mask: 0xffff00, - driver_data: 0, - }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, dhdpcie_pci_devid); - -static struct pci_driver dhdpcie_driver = { - node: {}, - name: "pcieh", - id_table: dhdpcie_pci_devid, - probe: dhdpcie_pci_probe, - remove: dhdpcie_pci_remove, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) - save_state: NULL, -#endif - suspend: dhdpcie_pci_suspend, - resume: dhdpcie_pci_resume, -}; - -int dhdpcie_init_succeeded = FALSE; - -int dhdpcie_set_suspend_resume(struct pci_dev *pdev, bool state) -{ - int ret = 0; - dhdpcie_info_t *pch = pci_get_drvdata(pdev); - dhd_bus_t *bus = NULL; - - if (pch) { - bus = pch->bus; - } - - if (bus && (bus->dhd->busstate == DHD_BUS_DOWN) && - bus->dhd->dongle_reset) { - DHD_ERROR(("%s: Dongle isn't up!\n", __FUNCTION__)); - return ret; - } - - if (bus) - mutex_lock(&bus->pm_lock); - -#ifdef DHD_USE_IDLECOUNT - /* Wake up runtime PM when system PM trigger */ - if (bus && (bus->suspended == TRUE) && (bus->host_suspend == TRUE)) { - if (state == TRUE) { - mutex_unlock(&bus->pm_lock); - if (!bus_wake(bus)) { - DHD_ERROR(("%s: Failed to resume the bus.\n", - __FUNCTION__)); - return -EAGAIN; - } else { - /* Carry on suspending */ - DHD_ERROR(("%s: Woke up from runtime suspend. " - "Carry on legacy suspend.\n", __FUNCTION__)); - mutex_lock(&bus->pm_lock); - } - } else { - ret = dhdpcie_bus_suspend(bus, state); - mutex_unlock(&bus->pm_lock); - return ret; - } - } -#endif /* DHD_USE_IDLECOUNT */ - - /* When firmware is not loaded do the PCI bus */ - /* suspend/resume only */ - if (bus && (bus->dhd->busstate == DHD_BUS_DOWN) && -#ifdef CONFIG_MACH_UNIVERSAL5433 - /* RB:34285 check_rev() : return 1 - new rev., 0 - old rev. */ - (!check_rev() || (check_rev() && !bus->dhd->dongle_reset))) { -#else - !bus->dhd->dongle_reset) { -#endif /* CONFIG_MACH_UNIVERSAL5433 */ - ret = dhdpcie_pci_suspend_resume(bus, state); - mutex_unlock(&bus->pm_lock); - return ret; - } - - if (bus && ((bus->dhd->busstate == DHD_BUS_SUSPEND)|| - (bus->dhd->busstate == DHD_BUS_DATA)) && - (bus->suspended != state)) { -#ifdef DHD_USE_IDLECOUNT - struct net_device *netdev = NULL; - bool runtime_pm = FALSE; - - dhd_pub_t *pub = (dhd_pub_t *)(bus->dhd); - netdev = dhd_idx2net(pub, 0); - - runtime_pm = bus->host_suspend; - - if (!runtime_pm && state) { - netif_stop_queue(netdev); - DHD_ERROR(("prepare in suspend mode stop net device traffic\n")); - } -#endif /* DHD_USE_IDLECOUNT */ - ret = dhdpcie_bus_suspend(bus, state); -#ifdef DHD_USE_IDLECOUNT - if (!runtime_pm) { - if (state) { - if (ret != BCME_OK) { - DHD_ERROR(("fail to suspend, start net device traffic\n")); - netif_start_queue(netdev); - } - } - } -#endif /* DHD_USE_IDLECOUNT */ - } - - if (bus) - mutex_unlock(&bus->pm_lock); - - return ret; -} - -static int dhdpcie_pci_suspend(struct pci_dev * pdev, pm_message_t state) -{ - BCM_REFERENCE(state); - return dhdpcie_set_suspend_resume(pdev, TRUE); -} - -static int dhdpcie_pci_resume(struct pci_dev *pdev) -{ - return dhdpcie_set_suspend_resume(pdev, FALSE); -} - -static int dhdpcie_suspend_dev(struct pci_dev *dev) -{ - int ret; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - dhdpcie_info_t *pch = pci_get_drvdata(dev); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) */ - DHD_TRACE_HW4(("%s: Enter\n", __FUNCTION__)); - pci_save_state(dev); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - pch->state = pci_store_saved_state(dev); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) */ - pci_enable_wake(dev, PCI_D0, TRUE); - if (pci_is_enabled(dev)) { - pci_disable_device(dev); - } - ret = pci_set_power_state(dev, PCI_D3hot); - if (ret) { - DHD_ERROR(("%s: pci_set_power_state error %d\n", - __FUNCTION__, ret)); - } - return ret; -} - -static int dhdpcie_resume_dev(struct pci_dev *dev) -{ - int err = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - dhdpcie_info_t *pch = pci_get_drvdata(dev); - pci_load_and_free_saved_state(dev, &pch->state); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) */ - DHD_TRACE_HW4(("%s: Enter\n", __FUNCTION__)); - pci_restore_state(dev); - err = pci_enable_device(dev); - if (err) { - printf("%s:pci_enable_device error %d \n", __FUNCTION__, err); - return err; - } - pci_set_master(dev); - err = pci_set_power_state(dev, PCI_D0); - if (err) { - printf("%s:pci_set_power_state error %d \n", __FUNCTION__, err); - return err; - } - return err; -} - -int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state) -{ - int rc; - struct pci_dev *dev = bus->dev; - - if (state) { -#ifndef BCMPCIE_OOB_HOST_WAKE - dhdpcie_pme_active(bus->osh, state); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - rc = dhdpcie_suspend_dev(dev); - } else { - rc = dhdpcie_resume_dev(dev); -#ifndef BCMPCIE_OOB_HOST_WAKE - dhdpcie_pme_active(bus->osh, state); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - } - return rc; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -static int dhdpcie_device_scan(struct device *dev, void *data) -{ - struct pci_dev *pcidev; - int *cnt = data; - - pcidev = container_of(dev, struct pci_dev, dev); - if (pcidev->vendor != 0x14e4) - return 0; - - DHD_INFO(("Found Broadcom PCI device 0x%04x\n", pcidev->device)); - *cnt += 1; - if (pcidev->driver && strcmp(pcidev->driver->name, dhdpcie_driver.name)) - DHD_ERROR(("Broadcom PCI Device 0x%04x has allocated with driver %s\n", - pcidev->device, pcidev->driver->name)); - - return 0; -} -#endif /* LINUX_VERSION >= 2.6.0 */ - -int -dhdpcie_bus_register(void) -{ - int error = 0; - - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) - if (!(error = pci_module_init(&dhdpcie_driver))) - return 0; - - DHD_ERROR(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error)); -#else - if (!(error = pci_register_driver(&dhdpcie_driver))) { - bus_for_each_dev(dhdpcie_driver.driver.bus, NULL, &error, dhdpcie_device_scan); - if (!error) { - DHD_ERROR(("No Broadcom PCI device enumerated!\n")); - } else if (!dhdpcie_init_succeeded) { - DHD_ERROR(("%s: dhdpcie initialize failed.\n", __FUNCTION__)); - } else { - return 0; - } - - pci_unregister_driver(&dhdpcie_driver); - error = BCME_ERROR; - } -#endif /* LINUX_VERSION < 2.6.0 */ - - return error; -} - - -void -dhdpcie_bus_unregister(void) -{ - pci_unregister_driver(&dhdpcie_driver); -} - -int __devinit -dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - - if (dhdpcie_chipmatch (pdev->vendor, pdev->device)) { - DHD_ERROR(("%s: chipmatch failed!!\n", __FUNCTION__)); - return -ENODEV; - } - printf("PCI_PROBE: bus %X, slot %X,vendor %X, device %X" - "(good PCI location)\n", pdev->bus->number, - PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device); - -#if defined(CUSTOMER_HW5) && defined(CONFIG_ARCH_MSM) - if (msm_pcie_pm_control(MSM_PCIE_RESUME, pdev->bus->number, pdev, NULL, 0)) { - DHD_ERROR(("%s Failed to resume PCIE link\n", __FUNCTION__)); - return -ENODEV; - } - - if (msm_pcie_recover_config(pdev)) { - DHD_ERROR(("%s Failed to recover PCIE config\n", __FUNCTION__)); - return -ENODEV; - } -#endif /* CUSTOMER_HW5 && CONFIG_ARCH_MSM */ - - if (dhdpcie_init (pdev)) { - DHD_ERROR(("%s: PCIe Enumeration failed\n", __FUNCTION__)); - return -ENODEV; - } - -#ifdef BCMPCIE_DISABLE_ASYNC_SUSPEND - /* disable async suspend */ - device_disable_async_suspend(&pdev->dev); -#endif /* BCMPCIE_DISABLE_ASYNC_SUSPEND */ - - DHD_TRACE(("%s: PCIe Enumeration done!!\n", __FUNCTION__)); - return 0; -} - -int -dhdpcie_detach(dhdpcie_info_t *pch) -{ - if (pch) { - osl_t *osh = pch->osh; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - if (!dhd_download_fw_on_driverload) { - pci_load_and_free_saved_state(pch->dev, &pch->default_state); - } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ - MFREE(osh, pch, sizeof(dhdpcie_info_t)); - } - return 0; -} - - -void __devexit -dhdpcie_pci_remove(struct pci_dev *pdev) -{ - osl_t *osh = NULL; - dhdpcie_info_t *pch = NULL; - dhd_bus_t *bus = NULL; -#ifdef PCIE_TX_DEFERRAL - struct sk_buff *skb; -#endif - - DHD_TRACE(("%s Enter\n", __FUNCTION__)); - pch = pci_get_drvdata(pdev); - bus = pch->bus; - osh = pch->osh; - -#ifdef PCIE_TX_DEFERRAL - if (bus->tx_wq) - destroy_workqueue(bus->tx_wq); - skb = skb_dequeue(&bus->orphan_list); - while (skb) { - PKTCFREE(osh, skb, TRUE); - skb = skb_dequeue(&bus->orphan_list); - } -#endif - -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - if (bus) - msm_pcie_deregister_event(&bus->pcie_event); -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - - dhdpcie_bus_remove_prep(bus); - dhdpcie_bus_release(bus); - if (pci_is_enabled(pdev)) - pci_disable_device(pdev); -#ifdef BCMPCIE_OOB_HOST_WAKE - /* pcie os info detach */ - MFREE(osh, pch->os_cxt, sizeof(dhdpcie_os_info_t)); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - /* pcie info detach */ - dhdpcie_detach(pch); - /* osl detach */ - osl_detach(osh); - - dhdpcie_init_succeeded = FALSE; - - DHD_TRACE(("%s Exit\n", __FUNCTION__)); - - return; -} - -/* Free Linux irq */ -int -dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info) -{ - dhd_bus_t *bus = dhdpcie_info->bus; - struct pci_dev *pdev = dhdpcie_info->bus->dev; - -#ifdef SET_PCIEIRQ_CPU0 - int ret; -#endif - - snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname), - "dhdpcie:%s", pci_name(pdev)); - if (request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED, - dhdpcie_info->pciname, bus) < 0) { - DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__)); - return -1; - } - - DHD_TRACE(("%s %s\n", __FUNCTION__, dhdpcie_info->pciname)); - -#ifdef SET_PCIEIRQ_CPU0 - /* make sure the irq only from cpu core 0 */ - ret = irq_set_affinity(pdev->irq, cpumask_of(0)); - if (ret) { - DHD_ERROR(("%s: irq_set_affinity error(%d)\n", __FUNCTION__, ret)); - } -#endif - - - return 0; /* SUCCESS */ -} - -#ifdef CONFIG_PHYS_ADDR_T_64BIT -#define PRINTF_RESOURCE "0x%016llx" -#else -#define PRINTF_RESOURCE "0x%08x" -#endif - -/* - -Name: osl_pci_get_resource - -Parametrs: - -1: struct pci_dev *pdev -- pci device structure -2: pci_res -- structure containing pci configuration space values - - -Return value: - -int - Status (TRUE or FALSE) - -Description: -Access PCI configuration space, retrieve PCI allocated resources , updates in resource structure. - - */ -int dhdpcie_get_resource(dhdpcie_info_t *dhdpcie_info) -{ - phys_addr_t bar0_addr, bar1_addr; - ulong bar1_size; - struct pci_dev *pdev = NULL; - pdev = dhdpcie_info->dev; - do { - if (pci_enable_device(pdev)) { - printf("%s: Cannot enable PCI device\n", __FUNCTION__); - break; - } - pci_set_master(pdev); - bar0_addr = pci_resource_start(pdev, 0); /* Bar-0 mapped address */ - bar1_addr = pci_resource_start(pdev, 2); /* Bar-1 mapped address */ - - /* read Bar-1 mapped memory range */ - bar1_size = pci_resource_len(pdev, 2); - - if ((bar1_size == 0) || (bar1_addr == 0)) { - printf("%s: BAR1 Not enabled for this device size(%ld)," - " addr(0x"PRINTF_RESOURCE")\n", - __FUNCTION__, bar1_size, bar1_addr); - goto err; - } - - dhdpcie_info->regs = (volatile char *) REG_MAP(bar0_addr, DONGLE_REG_MAP_SIZE); - dhdpcie_info->tcm_size = - (bar1_size < DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE; - dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size); - - if (!dhdpcie_info->regs || !dhdpcie_info->tcm) { - DHD_ERROR(("%s:ioremap() failed\n", __FUNCTION__)); - break; - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - if (!dhd_download_fw_on_driverload) { - /* Backup PCIe configuration so as to use Wi-Fi on/off process - * in case of built in driver - */ - pci_save_state(pdev); - dhdpcie_info->default_state = pci_store_saved_state(pdev); - - if (dhdpcie_info->default_state == NULL) { - DHD_ERROR(("%s pci_store_saved_state returns NULL\n", - __FUNCTION__)); - REG_UNMAP(dhdpcie_info->regs); - REG_UNMAP(dhdpcie_info->tcm); - pci_disable_device(pdev); - break; - } - } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ - - DHD_TRACE(("%s:Phys addr : reg space = %p base addr 0x"PRINTF_RESOURCE" \n", - __FUNCTION__, dhdpcie_info->regs, bar0_addr)); - DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n", - __FUNCTION__, dhdpcie_info->tcm, bar1_addr)); - - return 0; /* SUCCESS */ - } while (0); -err: - return -1; /* FAILURE */ -} - -int dhdpcie_scan_resource(dhdpcie_info_t *dhdpcie_info) -{ - - DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); - - do { - /* define it here only!! */ - if (dhdpcie_get_resource (dhdpcie_info)) { - DHD_ERROR(("%s: Failed to get PCI resources\n", __FUNCTION__)); - break; - } - DHD_TRACE(("%s:Exit - SUCCESS \n", - __FUNCTION__)); - - return 0; /* SUCCESS */ - - } while (0); - - DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__)); - - return -1; /* FAILURE */ - -} - -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM -void dhdpcie_linkdown_cb(struct msm_pcie_notify *noti) -{ - struct pci_dev *pdev = (struct pci_dev *)noti->user; - dhdpcie_info_t *pch = NULL; - - if (pdev) { - pch = pci_get_drvdata(pdev); - if (pch) { - dhd_bus_t *bus = pch->bus; - if (bus) { - dhd_pub_t *dhd = bus->dhd; - if (dhd) { - DHD_ERROR(("%s: Event HANG send up " - "due to PCIe linkdown\n", - __FUNCTION__)); - bus->islinkdown = TRUE; - DHD_OS_WAKE_LOCK(dhd); - dhd_os_check_hang(dhd, 0, -ETIMEDOUT); - } - } - } - } - -} -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - -#ifdef PCIE_TX_DEFERRAL -static void dhd_pcie_create_flow_worker(struct work_struct *worker) -{ - dhd_bus_t *bus; - struct sk_buff *skb; - uint16 ifidx, flowid; - flow_queue_t *queue; - flow_ring_node_t *flow_ring_node; - unsigned long flags; - - bus = container_of(worker, dhd_bus_t, create_flow_work); - skb = skb_dequeue(&bus->orphan_list); - while (skb) { - ifidx = DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(skb)); - if (BCME_OK != dhd_flowid_update(bus->dhd, ifidx, - bus->dhd->flow_prio_map[(PKTPRIO(skb))], skb)) { - PKTCFREE(bus->dhd->osh, skb, TRUE); - skb = skb_dequeue(&bus->orphan_list); - continue; - } - flowid = DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(skb)); - flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); - queue = &flow_ring_node->queue; - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - if ((flowid >= bus->dhd->num_flow_rings) || - (!flow_ring_node->active) || - (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING)) { - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - DHD_ERROR(("%s: Dropping pkt flowid %d, status %d active %d\n", - __FUNCTION__, flowid, flow_ring_node->status, - flow_ring_node->active)); - PKTCFREE(bus->dhd->osh, skb, TRUE); - skb = skb_dequeue(&bus->orphan_list); - continue; - } - if (BCME_OK != dhd_flow_queue_enqueue(bus->dhd, queue, skb)) { - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - PKTCFREE(bus->dhd->osh, skb, TRUE); - skb = skb_dequeue(&bus->orphan_list); - continue; - } - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - - if (flow_ring_node->status == FLOW_RING_STATUS_OPEN) - dhd_bus_schedule_queue(bus, flowid, FALSE); - - skb = skb_dequeue(&bus->orphan_list); - } -} - -static void dhd_pcie_delete_flow_worker(struct work_struct *worker) -{ - dhd_bus_t *bus; - uint16 flowid; - - bus = container_of(worker, dhd_bus_t, delete_flow_work); - for_each_set_bit(flowid, bus->delete_flow_map, bus->dhd->num_flow_rings) { - clear_bit(flowid, bus->delete_flow_map); - dhd_bus_flow_ring_delete_response(bus, flowid, BCME_OK); - } -} - -#endif /* PCIE_TX_DEFERRAL */ - -int dhdpcie_init(struct pci_dev *pdev) -{ - - osl_t *osh = NULL; - dhd_bus_t *bus = NULL; - dhdpcie_info_t *dhdpcie_info = NULL; - wifi_adapter_info_t *adapter = NULL; -#ifdef BCMPCIE_OOB_HOST_WAKE - dhdpcie_os_info_t *dhdpcie_osinfo = NULL; -#endif /* BCMPCIE_OOB_HOST_WAKE */ - - do { - /* osl attach */ - if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { - DHD_ERROR(("%s: osl_attach failed\n", __FUNCTION__)); - break; - } - - /* initialize static buffer */ - adapter = dhd_wifi_platform_get_adapter(PCI_BUS, pdev->bus->number, - PCI_SLOT(pdev->devfn)); - if (adapter != NULL) - DHD_ERROR(("%s: found adapter info '%s'\n", __FUNCTION__, adapter->name)); - else - DHD_ERROR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); - osl_static_mem_init(osh, adapter); - - /* allocate linux spcific pcie structure here */ - if (!(dhdpcie_info = MALLOC(osh, sizeof(dhdpcie_info_t)))) { - DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); - break; - } - bzero(dhdpcie_info, sizeof(dhdpcie_info_t)); - dhdpcie_info->osh = osh; - dhdpcie_info->dev = pdev; - -#ifdef BCMPCIE_OOB_HOST_WAKE - /* allocate OS speicific structure */ - dhdpcie_osinfo = MALLOC(osh, sizeof(dhdpcie_os_info_t)); - if (dhdpcie_osinfo == NULL) { - DHD_ERROR(("%s: MALLOC of dhdpcie_os_info_t failed\n", - __FUNCTION__)); - break; - } - bzero(dhdpcie_osinfo, sizeof(dhdpcie_os_info_t)); - dhdpcie_info->os_cxt = (void *)dhdpcie_osinfo; - - /* Initialize host wake IRQ */ - spin_lock_init(&dhdpcie_osinfo->oob_irq_spinlock); - /* Get customer specific host wake IRQ parametres: IRQ number as IRQ type */ - dhdpcie_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter, - &dhdpcie_osinfo->oob_irq_flags); - if (dhdpcie_osinfo->oob_irq_num < 0) { - DHD_ERROR(("%s: Host OOB irq is not defined\n", __FUNCTION__)); - } -#endif /* BCMPCIE_OOB_HOST_WAKE */ - - /* Find the PCI resources, verify the */ - /* vendor and device ID, map BAR regions and irq, update in structures */ - if (dhdpcie_scan_resource(dhdpcie_info)) { - DHD_ERROR(("%s: dhd_Scan_PCI_Res failed\n", __FUNCTION__)); - - break; - } - - /* Bus initialization */ - bus = dhdpcie_bus_attach(osh, dhdpcie_info->regs, - dhdpcie_info->tcm, dhdpcie_info->tcm_size); - if (!bus) { - DHD_ERROR(("%s:dhdpcie_bus_attach() failed\n", __FUNCTION__)); - break; - } - - dhdpcie_info->bus = bus; - dhdpcie_info->bus->dev = pdev; - -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->pcie_event.events = MSM_PCIE_EVENT_LINKDOWN; - bus->pcie_event.user = pdev; - bus->pcie_event.mode = MSM_PCIE_TRIGGER_CALLBACK; - bus->pcie_event.callback = dhdpcie_linkdown_cb; - bus->pcie_event.options = MSM_PCIE_CONFIG_NO_RECOVERY; - msm_pcie_register_event(&bus->pcie_event); - bus->islinkdown = FALSE; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - - if (bus->intr) { - /* Register interrupt callback, but mask it (not operational yet). */ - DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__)); - dhdpcie_bus_intr_disable(bus); - - if (dhdpcie_request_irq(dhdpcie_info)) { - DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__)); - break; - } - } else { - bus->pollrate = 1; - DHD_INFO(("%s: PCIe interrupt function is NOT registered " - "due to polling mode\n", __FUNCTION__)); - } - -#if defined(BCM_REQUEST_FW) - if (dhd_bus_download_firmware(bus, osh, NULL, NULL) < 0) { - DHD_ERROR(("%s: failed to download firmware\n", __FUNCTION__)); - } - bus->nv_path = NULL; - bus->fw_path = NULL; -#endif /* BCM_REQUEST_FW */ - - if (dhd_download_fw_on_driverload) { - if (dhd_bus_start(bus->dhd)) { - DHD_ERROR(("%s: dhd_bud_start() failed\n", __FUNCTION__)); - break; - } - } - - /* set private data for pci_dev */ - pci_set_drvdata(pdev, dhdpcie_info); - -#ifdef PCIE_TX_DEFERRAL - bus->tx_wq = create_singlethread_workqueue("bcmdhd_tx"); - if (bus->tx_wq == NULL) { - DHD_ERROR(("%s workqueue creation failed\n", __FUNCTION__)); - break; - } - INIT_WORK(&bus->create_flow_work, dhd_pcie_create_flow_worker); - INIT_WORK(&bus->delete_flow_work, dhd_pcie_delete_flow_worker); - skb_queue_head_init(&bus->orphan_list); -#endif /* PCIE_TX_DEFERRAL */ - - /* Attach to the OS network interface */ - DHD_TRACE(("%s(): Calling dhd_register_if() \n", __FUNCTION__)); - if (dhd_register_if(bus->dhd, 0, TRUE)) { - DHD_ERROR(("%s(): ERROR.. dhd_register_if() failed\n", __FUNCTION__)); - break; - } - - dhdpcie_init_succeeded = TRUE; - - DHD_TRACE(("%s:Exit - SUCCESS \n", __FUNCTION__)); - return 0; /* return SUCCESS */ - - } while (0); - /* reverse the initialization in order in case of error */ - - if (bus) - dhdpcie_bus_release(bus); - -#ifdef BCMPCIE_OOB_HOST_WAKE - if (dhdpcie_osinfo) - MFREE(osh, dhdpcie_osinfo, sizeof(dhdpcie_os_info_t)); -#endif /* BCMPCIE_OOB_HOST_WAKE */ - - if (dhdpcie_info) - dhdpcie_detach(dhdpcie_info); - pci_disable_device(pdev); - if (osh) - osl_detach(osh); - - dhdpcie_init_succeeded = FALSE; - - DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__)); - - return -1; /* return FAILURE */ -} - -/* Free Linux irq */ -void -dhdpcie_free_irq(dhd_bus_t *bus) -{ - struct pci_dev *pdev = NULL; - - DHD_TRACE(("%s: freeing up the IRQ\n", __FUNCTION__)); - if (bus) { - pdev = bus->dev; - free_irq(pdev->irq, bus); - } - DHD_TRACE(("%s: Exit\n", __FUNCTION__)); - return; -} - -/* - -Name: dhdpcie_isr - -Parametrs: - -1: IN int irq -- interrupt vector -2: IN void *arg -- handle to private data structure - -Return value: - -Status (TRUE or FALSE) - -Description: -Interrupt Service routine checks for the status register, -disable interrupt and queue DPC if mail box interrupts are raised. -*/ - - -irqreturn_t -dhdpcie_isr(int irq, void *arg) -{ - dhd_bus_t *bus = (dhd_bus_t*)arg; - if (dhdpcie_bus_isr(bus)) - return TRUE; - else - return FALSE; -} - -int -dhdpcie_start_host_pcieclock(dhd_bus_t *bus) -{ - int ret = 0; -#ifdef CONFIG_ARCH_MSM -#ifdef SUPPORT_LINKDOWN_RECOVERY - int options = 0; -#endif /* SUPPORT_LINKDOWN_RECOVERY */ -#endif /* CONFIG_ARCH_MSM */ - DHD_TRACE(("%s Enter:\n", __FUNCTION__)); - - if (bus == NULL) - return BCME_ERROR; - - if (bus->dev == NULL) - return BCME_ERROR; - - mutex_lock(&bus->host_clock_lock); -#ifdef CONFIG_ARCH_MSM -#ifdef SUPPORT_LINKDOWN_RECOVERY - if (bus->islinkdown) { - options = MSM_PCIE_CONFIG_NO_CFG_RESTORE; - } - ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number, - bus->dev, NULL, options); - if (bus->islinkdown && !ret) { - msm_pcie_recover_config(bus->dev); - if (bus->dhd) - DHD_OS_WAKE_UNLOCK(bus->dhd); - bus->islinkdown = FALSE; - } -#else - ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number, - bus->dev, NULL, 0); -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - if (ret) { - DHD_ERROR(("%s Failed to bring up PCIe link\n", __FUNCTION__)); - goto done; - } - -done: -#endif /* CONFIG_ARCH_MSM */ - mutex_unlock(&bus->host_clock_lock); - DHD_TRACE(("%s Exit:\n", __FUNCTION__)); - return ret; -} - -int -dhdpcie_stop_host_pcieclock(dhd_bus_t *bus) -{ - int ret = 0; - -#ifdef CONFIG_ARCH_MSM -#ifdef SUPPORT_LINKDOWN_RECOVERY - int options = 0; -#endif /* SUPPORT_LINKDOWN_RECOVERY */ -#endif /* CONFIG_ARCH_MSM */ - DHD_TRACE(("%s Enter:\n", __FUNCTION__)); - - if (bus == NULL) - return BCME_ERROR; - - if (bus->dev == NULL) - return BCME_ERROR; - - mutex_lock(&bus->host_clock_lock); -#ifdef CONFIG_ARCH_MSM -#ifdef SUPPORT_LINKDOWN_RECOVERY - if (bus->islinkdown) - options = MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN; - - ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number, - bus->dev, NULL, options); -#else - ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number, - bus->dev, NULL, 0); -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - if (ret) { - DHD_ERROR(("Failed to stop PCIe link\n")); - goto done; - } -done: -#endif /* CONFIG_ARCH_MSM */ - mutex_unlock(&bus->host_clock_lock); - DHD_TRACE(("%s Exit:\n", __FUNCTION__)); - return ret; -} - -int -dhdpcie_disable_device(dhd_bus_t *bus) -{ - if (bus == NULL) - return BCME_ERROR; - - if (bus->dev == NULL) - return BCME_ERROR; - - pci_disable_device(bus->dev); - - return 0; -} - -int -dhdpcie_enable_device(dhd_bus_t *bus) -{ - int ret = BCME_ERROR; - dhdpcie_info_t *pch; - - DHD_TRACE(("%s Enter:\n", __FUNCTION__)); - - if (bus == NULL) - return BCME_ERROR; - - if (bus->dev == NULL) - return BCME_ERROR; - - pch = pci_get_drvdata(bus->dev); - if (pch == NULL) - return BCME_ERROR; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - /* Updated with pci_load_and_free_saved_state to compatible - * with kernel 3.14 or higher - */ - if (pci_load_and_free_saved_state(bus->dev, &pch->default_state)) { - pci_disable_device(bus->dev); - } else { -#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))) - if (pci_load_saved_state(bus->dev, pch->default_state)) - pci_disable_device(bus->dev); - else { -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) and - * (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - * (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) - */ - - pci_restore_state(bus->dev); - ret = pci_enable_device(bus->dev); - if (!ret) - pci_set_master(bus->dev); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) and - * (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - * (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) - */ - - if (ret) - pci_disable_device(bus->dev); - - return ret; -} - -int -dhdpcie_alloc_resource(dhd_bus_t *bus) -{ - dhdpcie_info_t *dhdpcie_info; - phys_addr_t bar0_addr, bar1_addr; - ulong bar1_size; - - do { - if (bus == NULL) { - DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); - break; - } - - if (bus->dev == NULL) { - DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); - break; - } - - dhdpcie_info = pci_get_drvdata(bus->dev); - if (dhdpcie_info == NULL) { - DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__)); - break; - } - - bar0_addr = pci_resource_start(bus->dev, 0); /* Bar-0 mapped address */ - bar1_addr = pci_resource_start(bus->dev, 2); /* Bar-1 mapped address */ - - /* read Bar-1 mapped memory range */ - bar1_size = pci_resource_len(bus->dev, 2); - - if ((bar1_size == 0) || (bar1_addr == 0)) { - printf("%s: BAR1 Not enabled for this device size(%ld)," - " addr(0x"PRINTF_RESOURCE")\n", - __FUNCTION__, bar1_size, bar1_addr); - break; - } - - dhdpcie_info->regs = (volatile char *) REG_MAP(bar0_addr, DONGLE_REG_MAP_SIZE); - if (!dhdpcie_info->regs) { - DHD_ERROR(("%s: ioremap() for regs is failed\n", __FUNCTION__)); - break; - } - - bus->regs = dhdpcie_info->regs; - dhdpcie_info->tcm_size = - (bar1_size < DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE; - dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size); - if (!dhdpcie_info->tcm) { - DHD_ERROR(("%s: ioremap() for regs is failed\n", __FUNCTION__)); - REG_UNMAP(dhdpcie_info->regs); - bus->regs = NULL; - break; - } - - bus->tcm = dhdpcie_info->tcm; - bus->tcm_size = dhdpcie_info->tcm_size; - - DHD_TRACE(("%s:Phys addr : reg space = %p base addr 0x"PRINTF_RESOURCE" \n", - __FUNCTION__, dhdpcie_info->regs, bar0_addr)); - DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n", - __FUNCTION__, dhdpcie_info->tcm, bar1_addr)); - - return 0; - } while (0); - - return BCME_ERROR; -} - -void -dhdpcie_free_resource(dhd_bus_t *bus) -{ - dhdpcie_info_t *dhdpcie_info; - - if (bus == NULL) { - DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); - return; - } - - if (bus->dev == NULL) { - DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); - return; - } - - dhdpcie_info = pci_get_drvdata(bus->dev); - if (dhdpcie_info == NULL) { - DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__)); - return; - } - - if (bus->regs) { - REG_UNMAP(dhdpcie_info->regs); - bus->regs = NULL; - } - - if (bus->tcm) { - REG_UNMAP(dhdpcie_info->tcm); - bus->tcm = NULL; - } - - if (bus->pcie_mb_intr_addr) { - bus->pcie_mb_intr_addr = NULL; - } -} - -int -dhdpcie_bus_request_irq(struct dhd_bus *bus) -{ - dhdpcie_info_t *dhdpcie_info; - int ret = 0; - - if (bus == NULL) { - DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); - return BCME_ERROR; - } - - if (bus->dev == NULL) { - DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); - return BCME_ERROR; - } - - dhdpcie_info = pci_get_drvdata(bus->dev); - if (dhdpcie_info == NULL) { - DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__)); - return BCME_ERROR; - } - - if (bus->intr) { - /* Register interrupt callback, but mask it (not operational yet). */ - DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__)); - dhdpcie_bus_intr_disable(bus); - ret = dhdpcie_request_irq(dhdpcie_info); - if (ret) { - DHD_ERROR(("%s: request_irq() failed, ret=%d\n", - __FUNCTION__, ret)); - return ret; - } - } - - return ret; -} - -#ifdef BCMPCIE_OOB_HOST_WAKE -void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable) -{ - unsigned long flags; - dhdpcie_info_t *pch; - dhdpcie_os_info_t *dhdpcie_osinfo; - - if (bus == NULL) { - DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); - return; - } - - if (bus->dev == NULL) { - DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); - return; - } - - pch = pci_get_drvdata(bus->dev); - if (pch == NULL) { - DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__)); - return; - } - - dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt; - spin_lock_irqsave(&dhdpcie_osinfo->oob_irq_spinlock, flags); - if ((dhdpcie_osinfo->oob_irq_enabled != enable) && - (dhdpcie_osinfo->oob_irq_num > 0)) { - if (enable) - enable_irq(dhdpcie_osinfo->oob_irq_num); - else - disable_irq_nosync(dhdpcie_osinfo->oob_irq_num); - dhdpcie_osinfo->oob_irq_enabled = enable; - } - spin_unlock_irqrestore(&dhdpcie_osinfo->oob_irq_spinlock, flags); -} - -static irqreturn_t wlan_oob_irq(int irq, void *data) -{ - dhd_bus_t *bus; - DHD_TRACE(("%s: IRQ Triggered\n", __FUNCTION__)); - bus = (dhd_bus_t *)data; - - dhdpcie_oob_intr_set(bus, FALSE); - -#ifdef DHD_USE_IDLECOUNT - bus_wakeup(bus); -#endif /* DHD_USE_IDLECOUNT */ - if (bus->dhd->up && bus->suspended) { - DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(bus->dhd, OOB_WAKE_LOCK_TIMEOUT); - } - return IRQ_HANDLED; -} - -int dhdpcie_oob_intr_register(dhd_bus_t *bus) -{ - int err = 0; - dhdpcie_info_t *pch; - dhdpcie_os_info_t *dhdpcie_osinfo; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (bus == NULL) { - DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); - return -EINVAL; - } - - if (bus->dev == NULL) { - DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); - return -EINVAL; - } - - pch = pci_get_drvdata(bus->dev); - if (pch == NULL) { - DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__)); - return -EINVAL; - } - - dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt; - if (dhdpcie_osinfo->oob_irq_registered) { - DHD_ERROR(("%s: irq is already registered\n", __FUNCTION__)); - return -EBUSY; - } - - if (dhdpcie_osinfo->oob_irq_num > 0) { - DHD_INFO_HW4(("%s OOB irq=%d flags=%X \n", __FUNCTION__, - (int)dhdpcie_osinfo->oob_irq_num, - (int)dhdpcie_osinfo->oob_irq_flags)); - err = request_irq(dhdpcie_osinfo->oob_irq_num, wlan_oob_irq, - dhdpcie_osinfo->oob_irq_flags, "dhdpcie_host_wake", - bus); - if (err) { - DHD_ERROR(("%s: request_irq failed with %d\n", - __FUNCTION__, err)); - return err; - } - err = enable_irq_wake(dhdpcie_osinfo->oob_irq_num); - if (!err) - dhdpcie_osinfo->oob_irq_wake_enabled = TRUE; - dhdpcie_osinfo->oob_irq_enabled = TRUE; - } - - dhdpcie_osinfo->oob_irq_registered = TRUE; - - return err; -} - -void dhdpcie_oob_intr_unregister(dhd_bus_t *bus) -{ - int err = 0; - dhdpcie_info_t *pch; - dhdpcie_os_info_t *dhdpcie_osinfo; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (bus == NULL) { - DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); - return; - } - - if (bus->dev == NULL) { - DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); - return; - } - - pch = pci_get_drvdata(bus->dev); - if (pch == NULL) { - DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__)); - return; - } - - dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt; - if (!dhdpcie_osinfo->oob_irq_registered) { - DHD_ERROR(("%s: irq is not registered\n", __FUNCTION__)); - return; - } - if (dhdpcie_osinfo->oob_irq_num > 0) { - if (dhdpcie_osinfo->oob_irq_wake_enabled) { - err = disable_irq_wake(dhdpcie_osinfo->oob_irq_num); - if (!err) - dhdpcie_osinfo->oob_irq_wake_enabled = FALSE; - } - if (dhdpcie_osinfo->oob_irq_enabled) { - disable_irq(dhdpcie_osinfo->oob_irq_num); - dhdpcie_osinfo->oob_irq_enabled = FALSE; - } - free_irq(dhdpcie_osinfo->oob_irq_num, bus); - } - dhdpcie_osinfo->oob_irq_registered = FALSE; -} -#endif /* BCMPCIE_OOB_HOST_WAKE */ diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c deleted file mode 100644 index 1fda5f924087..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_pno.c +++ /dev/null @@ -1,3899 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD) - * Prefered Network Offload and Wi-Fi Location Service(WLS) code. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_pno.c 423669 2013-09-18 13:01:55Z yangj$ - */ -#ifdef PNO_SUPPORT -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#ifdef GSCAN_SUPPORT -#include -#endif /* GSCAN_SUPPORT */ -#include - -#ifdef __BIG_ENDIAN -#include -#define htod32(i) (bcmswap32(i)) -#define htod16(i) (bcmswap16(i)) -#define dtoh32(i) (bcmswap32(i)) -#define dtoh16(i) (bcmswap16(i)) -#define htodchanspec(i) htod16(i) -#define dtohchanspec(i) dtoh16(i) -#else -#define htod32(i) (i) -#define htod16(i) (i) -#define dtoh32(i) (i) -#define dtoh16(i) (i) -#define htodchanspec(i) (i) -#define dtohchanspec(i) (i) -#endif /* IL_BIGENDINA */ - -#define NULL_CHECK(p, s, err) \ - do { \ - if (!(p)) { \ - printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ - err = BCME_ERROR; \ - return err; \ - } \ - } while (0) -#define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) -#define PNO_BESTNET_LEN 2048 -#define PNO_ON 1 -#define PNO_OFF 0 -#define CHANNEL_2G_MAX 14 -#define CHANNEL_5G_MAX 165 -#define MAX_NODE_CNT 5 -#define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE) -#define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \ - - (uint32)(timestamp2/1000))) -#define TIME_DIFF_MS(timestamp1, timestamp2) (abs((uint32)(timestamp1) \ - - (uint32)(timestamp2))) -#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ - (ts).tv_nsec / NSEC_PER_USEC) - -#define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") -#define TIME_MIN_DIFF 5 -#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) -#define EVENT_MAX_NETCNT \ - ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_t)) \ - / sizeof(wl_pfn_net_info_t) + 1) - -static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, - dhd_pno_status_info_t *pno_state); -#ifdef GSCAN_SUPPORT -static wl_pfn_gscan_ch_bucket_cfg_t * -dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state, -uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw); -#endif /* GSCAN_SUPPORT */ -static inline bool -is_dfs(uint16 channel) -{ - if (channel >= 52 && channel <= 64) /* class 2 */ - return TRUE; - else if (channel >= 100 && channel <= 140) /* class 4 */ - return TRUE; - else - return FALSE; -} -int -dhd_pno_clean(dhd_pub_t *dhd) -{ - int pfn = 0; - int err; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - /* Disable PNO */ - err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn(error : %d)\n", - __FUNCTION__, err)); - goto exit; - } - _pno_state->pno_status = DHD_PNO_DISABLED; - err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfnclear(error : %d)\n", - __FUNCTION__, err)); - } -exit: - return err; -} - -bool -dhd_is_pno_supported(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - - if (!dhd || !dhd->pno_state) { - DHD_ERROR(("NULL POINTER : %s\n", - __FUNCTION__)); - return FALSE; - } - _pno_state = PNO_GET_PNOSTATE(dhd); - return WLS_SUPPORTED(_pno_state); -} - -bool -dhd_is_legacy_pno_enabled(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - - if (!dhd || !dhd->pno_state) { - DHD_ERROR(("NULL POINTER : %s\n", - __FUNCTION__)); - return FALSE; - } - _pno_state = PNO_GET_PNOSTATE(dhd); - return ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) != 0); -} - -#ifdef GSCAN_SUPPORT -static uint64 -convert_fw_rel_time_to_systime(uint32 fw_ts_ms) -{ - struct timespec ts; - - get_monotonic_boottime(&ts); - return ((uint64)(TIMESPEC_TO_US(ts)) - (uint64)(fw_ts_ms * 1000)); -} - -static void -dhd_pno_idx_to_ssid(struct dhd_pno_gscan_params *gscan_params, - dhd_epno_results_t *res, uint32 idx) -{ - dhd_epno_params_t *iter, *next; - - if (gscan_params->num_epno_ssid > 0) { - list_for_each_entry_safe(iter, next, - &gscan_params->epno_ssid_list, list) { - if (iter->index == idx) { - memcpy(res->ssid, iter->ssid, iter->ssid_len); - res->ssid_len = iter->ssid_len; - return; - } - } - } - /* If we are here then there was no match */ - res->ssid[0] = '\0'; - res->ssid_len = 0; - return; -} - -/* Cleanup all results */ -static void -dhd_gscan_clear_all_batch_results(dhd_pub_t *dhd) -{ - struct dhd_pno_gscan_params *gscan_params; - dhd_pno_status_info_t *_pno_state; - gscan_results_cache_t *iter; - - _pno_state = PNO_GET_PNOSTATE(dhd); - gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; - iter = gscan_params->gscan_batch_cache; - /* Mark everything as consumed */ - while (iter) { - iter->tot_consumed = iter->tot_count; - iter = iter->next; - } - dhd_gscan_batch_cache_cleanup(dhd); - return; -} - -static int -_dhd_pno_gscan_cfg(dhd_pub_t *dhd, wl_pfn_gscan_cfg_t *pfncfg_gscan_param, int size) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - - err = dhd_iovar(dhd, 0, "pfn_gscan_cfg", (char *)pfncfg_gscan_param, size, 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfncfg_gscan_param\n", __FUNCTION__)); - goto exit; - } -exit: - return err; -} - -static bool -is_batch_retrieval_complete(struct dhd_pno_gscan_params *gscan_params) -{ - smp_rmb(); - return (gscan_params->get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE); -} -#endif /* GSCAN_SUPPORT */ - -static int -_dhd_pno_suspend(dhd_pub_t *dhd) -{ - int err; - int suspend = 1; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), 1); - if (err < 0) { - DHD_ERROR(("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err)); - goto exit; - - } - _pno_state->pno_status = DHD_PNO_SUSPEND; -exit: - return err; -} -static int -_dhd_pno_enable(dhd_pub_t *dhd, int enable) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (enable & 0xfffe) { - DHD_ERROR(("%s invalid value\n", __FUNCTION__)); - err = BCME_BADARG; - goto exit; - } - if (!dhd_support_sta_mode(dhd)) { - DHD_ERROR(("PNO is not allowed for non-STA mode")); - err = BCME_BADOPTION; - goto exit; - } - if (enable) { - if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && - dhd_is_associated(dhd, NULL, NULL)) { - DHD_ERROR(("%s Legacy PNO mode cannot be enabled " - "in assoc mode , ignore it\n", __FUNCTION__)); - err = BCME_BADOPTION; - goto exit; - } - } - /* Enable/Disable PNO */ - err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_set - %d\n", __FUNCTION__, err)); - goto exit; - } - _pno_state->pno_status = (enable)? - DHD_PNO_ENABLED : DHD_PNO_DISABLED; - if (!enable) - _pno_state->pno_mode = DHD_PNO_NONE_MODE; - - DHD_PNO(("%s set pno as %s\n", - __FUNCTION__, enable ? "Enable" : "Disable")); -exit: - return err; -} - -static int -_dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode) -{ - int err = BCME_OK; - wl_pfn_param_t pfn_param; - dhd_pno_params_t *_params; - dhd_pno_status_info_t *_pno_state; - bool combined_scan = FALSE; - DHD_PNO(("%s enter\n", __FUNCTION__)); - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - memset(&pfn_param, 0, sizeof(pfn_param)); - - /* set pfn parameters */ - pfn_param.version = htod32(PFN_VERSION); - pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) | - (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT)); - if (mode == DHD_PNO_LEGACY_MODE) { - /* check and set extra pno params */ - if ((pno_params->params_legacy.pno_repeat != 0) || - (pno_params->params_legacy.pno_freq_expo_max != 0)) { - pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); - pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); - pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max); - } - /* set up pno scan fr */ - if (pno_params->params_legacy.scan_fr != 0) - pfn_param.scan_freq = htod32(pno_params->params_legacy.scan_fr); - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - DHD_PNO(("will enable combined scan with BATCHIG SCAN MODE\n")); - mode |= DHD_PNO_BATCH_MODE; - combined_scan = TRUE; - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - DHD_PNO(("will enable combined scan with HOTLIST SCAN MODE\n")); - mode |= DHD_PNO_HOTLIST_MODE; - combined_scan = TRUE; - } -#ifdef GSCAN_SUPPORT - else if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - DHD_PNO(("will enable combined scan with GSCAN SCAN MODE\n")); - mode |= DHD_PNO_GSCAN_MODE; - } -#endif /* GSCAN_SUPPORT */ - } - if (mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { - /* Scan frequency of 30 sec */ - pfn_param.scan_freq = htod32(30); - /* slow adapt scan is off by default */ - pfn_param.slow_freq = htod32(0); - /* RSSI margin of 30 dBm */ - pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); - /* Network timeout 60 sec */ - pfn_param.lost_network_timeout = htod32(60); - /* best n = 2 by default */ - pfn_param.bestn = DEFAULT_BESTN; - /* mscan m=0 by default, so not record best networks by default */ - pfn_param.mscan = DEFAULT_MSCAN; - /* default repeat = 10 */ - pfn_param.repeat = DEFAULT_REPEAT; - /* by default, maximum scan interval = 2^2 - * scan_freq when adaptive scan is turned on - */ - pfn_param.exp = DEFAULT_EXP; - if (mode == DHD_PNO_BATCH_MODE) { - /* In case of BATCH SCAN */ - if (pno_params->params_batch.bestn) - pfn_param.bestn = pno_params->params_batch.bestn; - if (pno_params->params_batch.scan_fr) - pfn_param.scan_freq = htod32(pno_params->params_batch.scan_fr); - if (pno_params->params_batch.mscan) - pfn_param.mscan = pno_params->params_batch.mscan; - /* enable broadcast scan */ - pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); - } else if (mode == DHD_PNO_HOTLIST_MODE) { - /* In case of HOTLIST SCAN */ - if (pno_params->params_hotlist.scan_fr) - pfn_param.scan_freq = htod32(pno_params->params_hotlist.scan_fr); - pfn_param.bestn = 0; - pfn_param.repeat = 0; - /* enable broadcast scan */ - pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); - } - if (combined_scan) { - /* Disable Adaptive Scan */ - pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT)); - pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); - pfn_param.repeat = 0; - pfn_param.exp = 0; - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - /* In case of Legacy PNO + BATCH SCAN */ - _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); - if (_params->params_batch.bestn) - pfn_param.bestn = _params->params_batch.bestn; - if (_params->params_batch.scan_fr) - pfn_param.scan_freq = htod32(_params->params_batch.scan_fr); - if (_params->params_batch.mscan) - pfn_param.mscan = _params->params_batch.mscan; - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - /* In case of Legacy PNO + HOTLIST SCAN */ - _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - if (_params->params_hotlist.scan_fr) - pfn_param.scan_freq = htod32(_params->params_hotlist.scan_fr); - pfn_param.bestn = 0; - pfn_param.repeat = 0; - } - } - } -#ifdef GSCAN_SUPPORT - if (mode & DHD_PNO_GSCAN_MODE) { - uint32 lost_network_timeout; - - pfn_param.scan_freq = htod32(pno_params->params_gscan.scan_fr); - if (pno_params->params_gscan.mscan) { - pfn_param.bestn = pno_params->params_gscan.bestn; - pfn_param.mscan = pno_params->params_gscan.mscan; - pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); - } - /* RSSI margin of 30 dBm */ - pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); - pfn_param.repeat = 0; - pfn_param.exp = 0; - pfn_param.slow_freq = 0; - pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); - - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - dhd_pno_params_t *_params; - - _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - - pfn_param.scan_freq = htod32(gcd(pno_params->params_gscan.scan_fr, - _params->params_legacy.scan_fr)); - - if ((_params->params_legacy.pno_repeat != 0) || - (_params->params_legacy.pno_freq_expo_max != 0)) { - pfn_param.repeat = (uchar) (_params->params_legacy.pno_repeat); - pfn_param.exp = (uchar) (_params->params_legacy.pno_freq_expo_max); - } - } - - lost_network_timeout = (pno_params->params_gscan.max_ch_bucket_freq * - pfn_param.scan_freq * - pno_params->params_gscan.lost_ap_window); - if (lost_network_timeout) { - pfn_param.lost_network_timeout = htod32(MIN(lost_network_timeout, - GSCAN_MIN_BSSID_TIMEOUT)); - } else { - pfn_param.lost_network_timeout = htod32(GSCAN_MIN_BSSID_TIMEOUT); - } - } else -#endif /* GSCAN_SUPPORT */ - { - if (pfn_param.scan_freq < htod32(PNO_SCAN_MIN_FW_SEC) || - pfn_param.scan_freq > htod32(PNO_SCAN_MAX_FW_SEC)) { - DHD_ERROR(("%s pno freq(%d sec) is not valid \n", - __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); - err = BCME_BADARG; - goto exit; - } - } - - err = dhd_set_rand_mac_oui(dhd); - /* Ignore if chip doesnt support the feature */ - if (err < 0 && err != BCME_UNSUPPORTED) { - DHD_ERROR(("%s : failed to set random mac for PNO scan, %d\n", __FUNCTION__, err)); - goto exit; - } - -#ifdef GSCAN_SUPPORT - if (mode == DHD_PNO_BATCH_MODE || - ((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) { -#else - if (mode == DHD_PNO_BATCH_MODE) { -#endif /* GSCAN_SUPPORT */ - int _tmp = pfn_param.bestn; - /* set bestn to calculate the max mscan which firmware supports */ - err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 1); - if (err < 0) { - DHD_ERROR(("%s : failed to set pfnmem\n", __FUNCTION__)); - goto exit; - } - /* get max mscan which the firmware supports */ - err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 0); - if (err < 0) { - DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__)); - goto exit; - } - pfn_param.mscan = MIN(pfn_param.mscan, _tmp); - DHD_PNO((" returned mscan : %d, set bestn : %d mscan %d\n", _tmp, pfn_param.bestn, - pfn_param.mscan)); - } - err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err)); - goto exit; - } - /* need to return mscan if this is for batch scan instead of err */ - err = (mode == DHD_PNO_BATCH_MODE)? pfn_param.mscan : err; -exit: - return err; -} -static int -_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssids_list, int nssid) -{ - int err = BCME_OK; - int i = 0; - wl_pfn_t pfn_element; - - NULL_CHECK(dhd, "dhd is NULL", err); - if (nssid) { - NULL_CHECK(ssids_list, "ssid list is NULL", err); - } - memset(&pfn_element, 0, sizeof(pfn_element)); - { - int j; - for (j = 0; j < nssid; j++) { - DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n", - ssids_list[j].SSID, ssids_list[j].SSID_len, ssids_list[j].hidden, - ssids_list[j].flags, ssids_list[i].rssi_thresh)); - } - } - /* Check for broadcast ssid */ - for (i = 0; i < nssid; i++) { - if (!ssids_list[i].SSID_len) { - DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", i)); - err = BCME_ERROR; - goto exit; - } - } - /* set all pfn ssid */ - for (i = 0; i < nssid; i++) { - pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); - pfn_element.auth = (DOT11_OPEN_SYSTEM); - pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); - pfn_element.wsec = htod32(0); - pfn_element.infra = htod32(1); - if (ssids_list[i].hidden) { - pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); - } else { - pfn_element.flags = 0; - } - pfn_element.flags |= htod32(ssids_list[i].flags); - /* If a single RSSI threshold is defined, use that */ -#ifdef PNO_MIN_RSSI_TRIGGER - pfn_element.flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT); -#else - pfn_element.flags |= ((ssids_list[i].rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT); -#endif /* PNO_MIN_RSSI_TRIGGER */ - memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, - ssids_list[i].SSID_len); - pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; - err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, - sizeof(pfn_element), 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); - goto exit; - } - } -exit: - return err; -} -/* qsort compare function */ -static int -_dhd_pno_cmpfunc(const void *a, const void *b) -{ - return (*(uint16*)a - *(uint16*)b); -} -static int -_dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan, - uint16 *chan_list1, int nchan1, uint16 *chan_list2, int nchan2) -{ - int err = BCME_OK; - int i = 0, j = 0, k = 0; - uint16 tmp; - NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); - NULL_CHECK(nchan, "nchan is NULL", err); - NULL_CHECK(chan_list1, "chan_list1 is NULL", err); - NULL_CHECK(chan_list2, "chan_list2 is NULL", err); - /* chan_list1 and chan_list2 should be sorted at first */ - while (i < nchan1 && j < nchan2) { - tmp = chan_list1[i] < chan_list2[j]? - chan_list1[i++] : chan_list2[j++]; - for (; i < nchan1 && chan_list1[i] == tmp; i++); - for (; j < nchan2 && chan_list2[j] == tmp; j++); - d_chan_list[k++] = tmp; - } - - while (i < nchan1) { - tmp = chan_list1[i++]; - for (; i < nchan1 && chan_list1[i] == tmp; i++); - d_chan_list[k++] = tmp; - } - - while (j < nchan2) { - tmp = chan_list2[j++]; - for (; j < nchan2 && chan_list2[j] == tmp; j++); - d_chan_list[k++] = tmp; - - } - *nchan = k; - return err; -} -static int -_dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list, - int *nchan, uint8 band, bool skip_dfs) -{ - int err = BCME_OK; - int i, j; - uint32 chan_buf[WL_NUMCHANNELS]; - wl_uint32_list_t *list; - NULL_CHECK(dhd, "dhd is NULL", err); - if (*nchan) { - NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); - } - list = (wl_uint32_list_t *) (void *)chan_buf; - list->count = htod32(WL_NUMCHANNELS); - err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); - if (err < 0) { - DHD_ERROR(("failed to get channel list (err: %d)\n", err)); - goto exit; - } - for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) { - if (band == WLC_BAND_2G) { - if (dtoh32(list->element[i]) > CHANNEL_2G_MAX) - continue; - } else if (band == WLC_BAND_5G) { - if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX) - continue; - if (skip_dfs && is_dfs(dtoh32(list->element[i]))) - continue; - - } else if (band == WLC_BAND_AUTO) { - if (skip_dfs || !is_dfs(dtoh32(list->element[i]))) - continue; - - } else { /* All channels */ - if (skip_dfs && is_dfs(dtoh32(list->element[i]))) - continue; - } - if (dtoh32(list->element[i]) <= CHANNEL_5G_MAX) { - d_chan_list[j++] = (uint16) dtoh32(list->element[i]); - } else { - err = BCME_BADCHAN; - goto exit; - } - } - *nchan = j; -exit: - return err; -} -static int -_dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batch, - char *buf, int nbufsize) -{ - int err = BCME_OK; - int bytes_written = 0, nreadsize = 0; - int t_delta = 0; - int nleftsize = nbufsize; - uint8 cnt = 0; - char *bp = buf; - char eabuf[ETHER_ADDR_STR_LEN]; -#ifdef PNO_DEBUG - char *_base_bp; - char msg[150]; -#endif - dhd_pno_bestnet_entry_t *iter, *next; - dhd_pno_scan_results_t *siter, *snext; - dhd_pno_best_header_t *phead, *pprev; - NULL_CHECK(params_batch, "params_batch is NULL", err); - if (nbufsize > 0) - NULL_CHECK(buf, "buf is NULL", err); - /* initialize the buffer */ - memset(buf, 0, nbufsize); - DHD_PNO(("%s enter \n", __FUNCTION__)); - /* # of scans */ - if (!params_batch->get_batch.batch_started) { - bp += nreadsize = sprintf(bp, "scancount=%d\n", - params_batch->get_batch.expired_tot_scan_cnt); - nleftsize -= nreadsize; - params_batch->get_batch.batch_started = TRUE; - } - DHD_PNO(("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt)); - /* preestimate scan count until which scan result this report is going to end */ - list_for_each_entry_safe(siter, snext, - ¶ms_batch->get_batch.expired_scan_results_list, list) { - phead = siter->bestnetheader; - while (phead != NULL) { - /* if left_size is less than bestheader total size , stop this */ - if (nleftsize <= - (phead->tot_size + phead->tot_cnt * ENTRY_OVERHEAD)) - goto exit; - /* increase scan count */ - cnt++; - /* # best of each scan */ - DHD_PNO(("\n\n", cnt - 1, phead->tot_cnt)); - /* attribute of the scan */ - if (phead->reason & PNO_STATUS_ABORT_MASK) { - bp += nreadsize = sprintf(bp, "trunc\n"); - nleftsize -= nreadsize; - } - list_for_each_entry_safe(iter, next, - &phead->entry_list, list) { - t_delta = jiffies_to_msecs(jiffies - iter->recorded_time); -#ifdef PNO_DEBUG - _base_bp = bp; - memset(msg, 0, sizeof(msg)); -#endif - /* BSSID info */ - bp += nreadsize = sprintf(bp, "bssid=%s\n", - bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf)); - nleftsize -= nreadsize; - /* SSID */ - bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID); - nleftsize -= nreadsize; - /* channel */ - bp += nreadsize = sprintf(bp, "freq=%d\n", - wf_channel2mhz(iter->channel, - iter->channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - nleftsize -= nreadsize; - /* RSSI */ - bp += nreadsize = sprintf(bp, "level=%d\n", iter->RSSI); - nleftsize -= nreadsize; - /* add the time consumed in Driver to the timestamp of firmware */ - iter->timestamp += t_delta; - bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp); - nleftsize -= nreadsize; - /* RTT0 */ - bp += nreadsize = sprintf(bp, "dist=%d\n", - (iter->rtt0 == 0)? -1 : iter->rtt0); - nleftsize -= nreadsize; - /* RTT1 */ - bp += nreadsize = sprintf(bp, "distSd=%d\n", - (iter->rtt0 == 0)? -1 : iter->rtt1); - nleftsize -= nreadsize; - bp += nreadsize = sprintf(bp, "%s", AP_END_MARKER); - nleftsize -= nreadsize; - list_del(&iter->list); - MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); -#ifdef PNO_DEBUG - memcpy(msg, _base_bp, bp - _base_bp); - DHD_PNO(("Entry : \n%s", msg)); -#endif - } - bp += nreadsize = sprintf(bp, "%s", SCAN_END_MARKER); - DHD_PNO(("%s", SCAN_END_MARKER)); - nleftsize -= nreadsize; - pprev = phead; - /* reset the header */ - siter->bestnetheader = phead = phead->next; - MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); - - siter->cnt_header--; - } - if (phead == NULL) { - /* we store all entry in this scan , so it is ok to delete */ - list_del(&siter->list); - MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); - } - } -exit: - if (cnt < params_batch->get_batch.expired_tot_scan_cnt) { - DHD_ERROR(("Buffer size is small to save all batch entry," - " cnt : %d (remained_scan_cnt): %d\n", - cnt, params_batch->get_batch.expired_tot_scan_cnt - cnt)); - } - params_batch->get_batch.expired_tot_scan_cnt -= cnt; - /* set FALSE only if the link list is empty after returning the data */ - if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) { - params_batch->get_batch.batch_started = FALSE; - bp += sprintf(bp, "%s", RESULTS_END_MARKER); - DHD_PNO(("%s", RESULTS_END_MARKER)); - DHD_PNO(("%s : Getting the batching data is complete\n", __FUNCTION__)); - } - /* return used memory in buffer */ - bytes_written = (int32)(bp - buf); - return bytes_written; -} -static int -_dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last) -{ - int err = BCME_OK; - int removed_scan_cnt = 0; - dhd_pno_scan_results_t *siter, *snext; - dhd_pno_best_header_t *phead, *pprev; - dhd_pno_bestnet_entry_t *iter, *next; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(head, "head is NULL", err); - NULL_CHECK(head->next, "head->next is NULL", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - list_for_each_entry_safe(siter, snext, - head, list) { - if (only_last) { - /* in case that we need to delete only last one */ - if (!list_is_last(&siter->list, head)) { - /* skip if the one is not last */ - continue; - } - } - /* delete all data belong if the one is last */ - phead = siter->bestnetheader; - while (phead != NULL) { - removed_scan_cnt++; - list_for_each_entry_safe(iter, next, - &phead->entry_list, list) { - list_del(&iter->list); - MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); - } - pprev = phead; - phead = phead->next; - MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); - } - if (phead == NULL) { - /* it is ok to delete top node */ - list_del(&siter->list); - MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); - } - } - return removed_scan_cnt; -} - -static int -_dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) -{ - int err = BCME_OK; - int i = 0; - wl_pfn_cfg_t pfncfg_param; - NULL_CHECK(dhd, "dhd is NULL", err); - if (nchan) { - NULL_CHECK(channel_list, "nchan is NULL", err); - } - if (nchan > WL_NUMCHANNELS) { - return BCME_RANGE; - } - DHD_PNO(("%s enter : nchan : %d\n", __FUNCTION__, nchan)); - memset(&pfncfg_param, 0, sizeof(wl_pfn_cfg_t)); - /* Setup default values */ - pfncfg_param.reporttype = htod32(WL_PFN_REPORT_ALLNET); - pfncfg_param.channel_num = htod32(0); - - for (i = 0; i < nchan; i++) - pfncfg_param.channel_list[i] = channel_list[i]; - - pfncfg_param.channel_num = htod32(nchan); - err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); - goto exit; - } -exit: - return err; -} -static int -_dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL\n", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL\n", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - mutex_lock(&_pno_state->pno_mutex); - switch (mode) { - case DHD_PNO_LEGACY_MODE: { - struct dhd_pno_ssid *iter, *next; - if (params->params_legacy.nssid > 0) { - list_for_each_entry_safe(iter, next, - ¶ms->params_legacy.ssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - params->params_legacy.nssid = 0; - params->params_legacy.scan_fr = 0; - params->params_legacy.pno_freq_expo_max = 0; - params->params_legacy.pno_repeat = 0; - params->params_legacy.nchan = 0; - memset(params->params_legacy.chan_list, 0, - sizeof(params->params_legacy.chan_list)); - break; - } - case DHD_PNO_BATCH_MODE: { - params->params_batch.scan_fr = 0; - params->params_batch.mscan = 0; - params->params_batch.nchan = 0; - params->params_batch.rtt = 0; - params->params_batch.bestn = 0; - params->params_batch.nchan = 0; - params->params_batch.band = WLC_BAND_AUTO; - memset(params->params_batch.chan_list, 0, - sizeof(params->params_batch.chan_list)); - params->params_batch.get_batch.batch_started = FALSE; - params->params_batch.get_batch.buf = NULL; - params->params_batch.get_batch.bufsize = 0; - params->params_batch.get_batch.reason = 0; - _dhd_pno_clear_all_batch_results(dhd, - ¶ms->params_batch.get_batch.scan_results_list, FALSE); - _dhd_pno_clear_all_batch_results(dhd, - ¶ms->params_batch.get_batch.expired_scan_results_list, FALSE); - params->params_batch.get_batch.tot_scan_cnt = 0; - params->params_batch.get_batch.expired_tot_scan_cnt = 0; - params->params_batch.get_batch.top_node_cnt = 0; - INIT_LIST_HEAD(¶ms->params_batch.get_batch.scan_results_list); - INIT_LIST_HEAD(¶ms->params_batch.get_batch.expired_scan_results_list); - break; - } - case DHD_PNO_HOTLIST_MODE: { - struct dhd_pno_bssid *iter, *next; - if (params->params_hotlist.nbssid > 0) { - list_for_each_entry_safe(iter, next, - ¶ms->params_hotlist.bssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - params->params_hotlist.scan_fr = 0; - params->params_hotlist.nbssid = 0; - params->params_hotlist.nchan = 0; - params->params_batch.band = WLC_BAND_AUTO; - memset(params->params_hotlist.chan_list, 0, - sizeof(params->params_hotlist.chan_list)); - break; - } - default: - DHD_ERROR(("%s : unknown mode : %d\n", __FUNCTION__, mode)); - break; - } - mutex_unlock(&_pno_state->pno_mutex); - return err; -} -static int -_dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - if (nbssid) { - NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); - } - err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)p_pfn_bssid, - sizeof(wl_pfn_bssid_t) * nbssid, 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); - goto exit; - } -exit: - return err; -} - -int -dhd_pno_stop_for_ssid(dhd_pub_t *dhd) -{ - int err = BCME_OK; - uint32 mode = 0; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - wl_pfn_bssid_t *p_pfn_bssid = NULL; - NULL_CHECK(dhd, "dev is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { - DHD_ERROR(("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__)); - goto exit; - } - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - struct dhd_pno_gscan_params *gscan_params; - - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - gscan_params = &_params->params_gscan; - if (gscan_params->mscan) { - /* retrieve the batching data from firmware into host */ - err = dhd_wait_batch_results_complete(dhd); - if (err != BCME_OK) - goto exit; - } - /* save current pno_mode before calling dhd_pno_clean */ - mutex_lock(&_pno_state->pno_mutex); - mode = _pno_state->pno_mode; - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - mutex_unlock(&_pno_state->pno_mutex); - goto exit; - } - /* restore previous pno_mode */ - _pno_state->pno_mode = mode; - mutex_unlock(&_pno_state->pno_mutex); - /* Restart gscan */ - err = dhd_pno_initiate_gscan_request(dhd, 1, 0); - goto exit; - } -#endif /* GSCAN_SUPPORT */ - /* restart Batch mode if the batch mode is on */ - if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { - /* retrieve the batching data from firmware into host */ - dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); - /* save current pno_mode before calling dhd_pno_clean */ - mode = _pno_state->pno_mode; - dhd_pno_clean(dhd); - /* restore previous pno_mode */ - _pno_state->pno_mode = mode; - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); - /* restart BATCH SCAN */ - err = dhd_pno_set_for_batch(dhd, &_params->params_batch); - if (err < 0) { - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - /* restart HOTLIST SCAN */ - struct dhd_pno_bssid *iter, *next; - _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * - _params->params_hotlist.nbssid, GFP_KERNEL); - if (p_pfn_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" - " (count: %d)", - __FUNCTION__, _params->params_hotlist.nbssid)); - err = BCME_ERROR; - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - goto exit; - } - /* convert dhd_pno_bssid to wl_pfn_bssid */ - list_for_each_entry_safe(iter, next, - &_params->params_hotlist.bssid_list, list) { - memcpy(&p_pfn_bssid->macaddr, - &iter->macaddr, ETHER_ADDR_LEN); - p_pfn_bssid->flags = iter->flags; - p_pfn_bssid++; - } - err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); - if (err < 0) { - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } - } else { - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } -exit: - if (p_pfn_bssid) - kfree(p_pfn_bssid); - return err; -} - -int -dhd_pno_enable(dhd_pub_t *dhd, int enable) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - return (_dhd_pno_enable(dhd, enable)); -} - -static wlc_ssid_ext_t * -dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state) -{ - int err = BCME_OK; - int i; - struct dhd_pno_ssid *iter, *next; - dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; - wlc_ssid_ext_t *p_ssid_list; - - p_ssid_list = kzalloc(sizeof(wlc_ssid_ext_t) * - _params1->params_legacy.nssid, GFP_KERNEL); - if (p_ssid_list == NULL) { - DHD_ERROR(("%s : failed to allocate wlc_ssid_ext_t array (count: %d)", - __FUNCTION__, _params1->params_legacy.nssid)); - err = BCME_ERROR; - pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; - goto exit; - } - i = 0; - /* convert dhd_pno_ssid to wlc_ssid_ext_t */ - list_for_each_entry_safe(iter, next, &_params1->params_legacy.ssid_list, list) { - p_ssid_list[i].SSID_len = iter->SSID_len; - p_ssid_list[i].hidden = iter->hidden; - p_ssid_list[i].rssi_thresh = iter->rssi_thresh; - memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); - i++; - } -exit: - return p_ssid_list; -} - -#ifdef GSCAN_SUPPORT -static int dhd_epno_set_ssid(dhd_pub_t *dhd, - dhd_pno_status_info_t *pno_state) -{ - int err = BCME_OK; - dhd_epno_params_t *iter, *next; - dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - struct dhd_pno_gscan_params *gscan_params; - wlc_ssid_ext_t ssid_elem; - wl_pfn_ext_list_t *p_ssid_ext_elem = NULL; - uint32 mem_needed = 0, i = 0; - uint16 num_visible_epno_ssid; - uint8 flags; - - gscan_params = &_params1->params_gscan; - num_visible_epno_ssid = gscan_params->num_visible_epno_ssid; - - if (num_visible_epno_ssid) { - mem_needed = sizeof(wl_pfn_ext_list_t) + (sizeof(wl_pfn_ext_t) * - (num_visible_epno_ssid - 1)); - p_ssid_ext_elem = kzalloc(mem_needed, GFP_KERNEL); - if (p_ssid_ext_elem == NULL) { - DHD_ERROR(("%s : failed to allocate memory %u\n", - __FUNCTION__, mem_needed)); - err = BCME_NOMEM; - goto exit; - } - p_ssid_ext_elem->version = PFN_SSID_EXT_VERSION; - p_ssid_ext_elem->count = num_visible_epno_ssid; - } - - DHD_PNO(("Total ssids %d, visible SSIDs %d\n", gscan_params->num_epno_ssid, - num_visible_epno_ssid)); - - /* convert dhd_pno_ssid to wlc_ssid_ext_t */ - list_for_each_entry_safe(iter, next, &gscan_params->epno_ssid_list, list) { - if (iter->flags & DHD_PNO_USE_SSID) { - memset(&ssid_elem, 0, sizeof(ssid_elem)); - ssid_elem.SSID_len = iter->ssid_len; - ssid_elem.hidden = TRUE; - flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? - WL_PFN_SSID_A_BAND_TRIG: 0; - flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? - WL_PFN_SSID_BG_BAND_TRIG: 0; - ssid_elem.flags = flags; - ssid_elem.rssi_thresh = iter->rssi_thresh; - memcpy(ssid_elem.SSID, iter->ssid, iter->ssid_len); - if ((err = _dhd_pno_add_ssid(dhd, &ssid_elem, 1)) < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); - goto exit; - } - } else if (i < num_visible_epno_ssid) { - p_ssid_ext_elem->pfn_ext[i].rssi_thresh = iter->rssi_thresh; - switch (iter->auth) { - case DHD_PNO_AUTH_CODE_OPEN: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = WPA_AUTH_DISABLED; - break; - case DHD_PNO_AUTH_CODE_PSK: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = - (WPA2_AUTH_PSK | WPA_AUTH_PSK); - break; - case DHD_PNO_AUTH_CODE_EAPOL: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = - (uint16)WPA_AUTH_PFN_ANY; - break; - default: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = - (uint16)WPA_AUTH_PFN_ANY; - break; - } - memcpy(p_ssid_ext_elem->pfn_ext[i].ssid, iter->ssid, iter->ssid_len); - p_ssid_ext_elem->pfn_ext[i].ssid_len = iter->ssid_len; - iter->index = gscan_params->ssid_ext_last_used_index++; - flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? - WL_PFN_SSID_A_BAND_TRIG: 0; - flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? - WL_PFN_SSID_BG_BAND_TRIG: 0; - p_ssid_ext_elem->pfn_ext[i].flags = flags; - DHD_PNO(("SSID %s idx %d rssi thresh %d flags %x\n", iter->ssid, - iter->index, iter->rssi_thresh, flags)); - i++; - } - } - if (num_visible_epno_ssid) { - err = dhd_iovar(dhd, 0, "pfn_add_ssid_ext", (char *)p_ssid_ext_elem, - mem_needed, 1); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_add_pno_ext_ssid %d\n", __FUNCTION__, - err)); - } - } -exit: - kfree(p_ssid_ext_elem); - return err; -} -#endif /* GSCAN_SUPPORT */ - -static int -dhd_pno_add_to_ssid_list(dhd_pno_params_t *params, wlc_ssid_ext_t *ssid_list, - int nssid) -{ - int ret = 0; - int i; - struct dhd_pno_ssid *_pno_ssid; - - for (i = 0; i < nssid; i++) { - if (ssid_list[i].SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s : Invalid SSID length %d\n", - __FUNCTION__, ssid_list[i].SSID_len)); - ret = BCME_ERROR; - goto exit; - } - _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); - if (_pno_ssid == NULL) { - DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n", - __FUNCTION__)); - ret = BCME_ERROR; - goto exit; - } - _pno_ssid->SSID_len = ssid_list[i].SSID_len; - _pno_ssid->hidden = ssid_list[i].hidden; - _pno_ssid->rssi_thresh = ssid_list[i].rssi_thresh; - memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); - list_add_tail(&_pno_ssid->list, ¶ms->params_legacy.ssid_list); - params->params_legacy.nssid++; - } - -exit: - return ret; -} - -int -dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, - uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) -{ - dhd_pno_params_t *_params; - dhd_pno_params_t *_params2; - dhd_pno_status_info_t *_pno_state; - uint16 _chan_list[WL_NUMCHANNELS]; - int32 tot_nchan = 0; - int err = BCME_OK; - int i; - int mode = 0; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit_no_clear; - } - DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d," - "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, - scan_fr, pno_repeat, pno_freq_expo_max, nchan)); - - _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - /* If GSCAN is also ON will handle this down below */ -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE && - !(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { -#else - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { -#endif /* GSCAN_SUPPORT */ - DHD_ERROR(("%s : Legacy PNO mode was already started, " - "will disable previous one to start new one\n", __FUNCTION__)); - err = dhd_pno_stop_for_ssid(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to stop legacy PNO (err %d)\n", - __FUNCTION__, err)); - goto exit_no_clear; - } - } - _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; - err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); - if (err < 0) { - DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", - __FUNCTION__, err)); - goto exit_no_clear; - } - memset(_chan_list, 0, sizeof(_chan_list)); - tot_nchan = MIN(nchan, WL_NUMCHANNELS); - if (tot_nchan > 0 && channel_list) { - for (i = 0; i < tot_nchan; i++) - _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i]; - } -#ifdef GSCAN_SUPPORT - else { - tot_nchan = WL_NUMCHANNELS; - err = _dhd_pno_get_channels(dhd, _chan_list, &tot_nchan, - (WLC_BAND_2G | WLC_BAND_5G), FALSE); - if (err < 0) { - tot_nchan = 0; - DHD_PNO(("Could not get channel list for PNO SSID\n")); - } else { - for (i = 0; i < tot_nchan; i++) { - _params->params_legacy.chan_list[i] = _chan_list[i]; - } - } - } -#endif /* GSCAN_SUPPORT */ - - if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { - DHD_PNO(("BATCH SCAN is on progress in firmware\n")); - /* retrieve the batching data from firmware into host */ - dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); - /* store current pno_mode before disabling pno */ - mode = _pno_state->pno_mode; - err = _dhd_pno_enable(dhd, PNO_OFF); - if (err < 0) { - DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - goto exit_no_clear; - } - /* restore the previous mode */ - _pno_state->pno_mode = mode; - /* use superset of channel list between two mode */ - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - _params2 = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); - if (_params2->params_batch.nchan > 0 && tot_nchan > 0) { - err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, - &_params2->params_batch.chan_list[0], - _params2->params_batch.nchan, - &channel_list[0], tot_nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to merge channel list" - " between legacy and batch\n", - __FUNCTION__)); - goto exit_no_clear; - } - } else { - DHD_PNO(("superset channel will use" - " all channels in firmware\n")); - } - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - _params2 = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - if (_params2->params_hotlist.nchan > 0 && tot_nchan > 0) { - err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, - &_params2->params_hotlist.chan_list[0], - _params2->params_hotlist.nchan, - &channel_list[0], tot_nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to merge channel list" - " between legacy and hotlist\n", - __FUNCTION__)); - goto exit_no_clear; - } - } - } - } - _params->params_legacy.scan_fr = scan_fr; - _params->params_legacy.pno_repeat = pno_repeat; - _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max; - _params->params_legacy.nchan = tot_nchan; - _params->params_legacy.nssid = 0; - INIT_LIST_HEAD(&_params->params_legacy.ssid_list); -#ifdef GSCAN_SUPPORT - /* dhd_pno_initiate_gscan_request will handle simultaneous Legacy PNO and GSCAN */ - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { - err = BCME_ERROR; - goto exit; - } - DHD_PNO(("GSCAN mode is ON! Will restart GSCAN+Legacy PNO\n")); - err = dhd_pno_initiate_gscan_request(dhd, 1, 0); - goto exit; - } -#endif /* GSCAN_SUPPORT */ - if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_LEGACY_MODE)) < 0) { - DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); - goto exit; - } - if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { - DHD_ERROR(("failed to add ssid list(err %d), %d in firmware\n", err, nssid)); - goto exit; - } - if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { - err = BCME_ERROR; - goto exit; - } - if (tot_nchan > 0) { - if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { - DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - } - if (_pno_state->pno_status == DHD_PNO_DISABLED) { - if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) - DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); - } -exit: - if (err < 0) { - _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); - } -exit_no_clear: - /* clear mode in case of error */ - if (err < 0) { - int ret = dhd_pno_clean(dhd); - - if (ret < 0) { - DHD_ERROR(("%s : dhd_pno_clean failure (err: %d)\n", - __FUNCTION__, ret)); - } else { - _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; - } - } - return err; -} -int -dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) -{ - int err = BCME_OK; - uint16 _chan_list[WL_NUMCHANNELS]; - int rem_nchan = 0, tot_nchan = 0; - int mode = 0, mscan = 0; - dhd_pno_params_t *_params; - dhd_pno_params_t *_params2; - dhd_pno_status_info_t *_pno_state; - wlc_ssid_ext_t *p_ssid_list = NULL; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - NULL_CHECK(batch_params, "batch_params is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; - if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { - _pno_state->pno_mode |= DHD_PNO_BATCH_MODE; - err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", - __FUNCTION__)); - goto exit; - } - } else { - /* batch mode is already started */ - return -EBUSY; - } - _params->params_batch.scan_fr = batch_params->scan_fr; - _params->params_batch.bestn = batch_params->bestn; - _params->params_batch.mscan = (batch_params->mscan)? - batch_params->mscan : DEFAULT_BATCH_MSCAN; - _params->params_batch.nchan = batch_params->nchan; - memcpy(_params->params_batch.chan_list, batch_params->chan_list, - sizeof(_params->params_batch.chan_list)); - - memset(_chan_list, 0, sizeof(_chan_list)); - - rem_nchan = ARRAYSIZE(batch_params->chan_list) - batch_params->nchan; - if (batch_params->band == WLC_BAND_2G || batch_params->band == WLC_BAND_5G) { - /* get a valid channel list based on band B or A */ - err = _dhd_pno_get_channels(dhd, - &_params->params_batch.chan_list[batch_params->nchan], - &rem_nchan, batch_params->band, FALSE); - if (err < 0) { - DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", - __FUNCTION__, batch_params->band)); - goto exit; - } - /* now we need to update nchan because rem_chan has valid channel count */ - _params->params_batch.nchan += rem_nchan; - /* need to sort channel list */ - sort(_params->params_batch.chan_list, _params->params_batch.nchan, - sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL); - } -#ifdef PNO_DEBUG -{ - DHD_PNO(("Channel list : ")); - for (i = 0; i < _params->params_batch.nchan; i++) { - DHD_PNO(("%d ", _params->params_batch.chan_list[i])); - } - DHD_PNO(("\n")); -} -#endif - if (_params->params_batch.nchan) { - /* copy the channel list into local array */ - memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list)); - tot_nchan = _params->params_batch.nchan; - } - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - DHD_PNO(("PNO SSID is on progress in firmware\n")); - /* store current pno_mode before disabling pno */ - mode = _pno_state->pno_mode; - err = _dhd_pno_enable(dhd, PNO_OFF); - if (err < 0) { - DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - goto exit; - } - /* restore the previous mode */ - _pno_state->pno_mode = mode; - /* Use the superset for channelist between two mode */ - _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - if (_params2->params_legacy.nchan > 0 && _params->params_batch.nchan > 0) { - err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, - &_params2->params_legacy.chan_list[0], - _params2->params_legacy.nchan, - &_params->params_batch.chan_list[0], _params->params_batch.nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to merge channel list" - " between legacy and batch\n", - __FUNCTION__)); - goto exit; - } - } else { - DHD_PNO(("superset channel will use all channels in firmware\n")); - } - p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!p_ssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list, - _params2->params_legacy.nssid)) < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); - goto exit; - } - } - if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_BATCH_MODE)) < 0) { - DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } else { - /* we need to return mscan */ - mscan = err; - } - if (tot_nchan > 0) { - if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { - DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - } - if (_pno_state->pno_status == DHD_PNO_DISABLED) { - if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) - DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); - } -exit: - /* clear mode in case of error */ - if (err < 0) - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - else { - /* return #max scan firmware can do */ - err = mscan; - } - if (p_ssid_list) - kfree(p_ssid_list); - return err; -} - - -#ifdef GSCAN_SUPPORT -static void dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params, - dhd_pno_status_info_t *_pno_state, uint8 flags) -{ - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (flags & GSCAN_FLUSH_SCAN_CFG) { - _params->params_gscan.bestn = 0; - _params->params_gscan.mscan = 0; - _params->params_gscan.buffer_threshold = GSCAN_BATCH_NO_THR_SET; - _params->params_gscan.scan_fr = 0; - _params->params_gscan.send_all_results_flag = 0; - memset(_params->params_gscan.channel_bucket, 0, - _params->params_gscan.nchannel_buckets * - sizeof(struct dhd_pno_gscan_channel_bucket)); - _params->params_gscan.nchannel_buckets = 0; - DHD_PNO(("Flush Scan config\n")); - } - if (flags & GSCAN_FLUSH_HOTLIST_CFG) { - struct dhd_pno_bssid *iter, *next; - if (_params->params_gscan.nbssid_hotlist > 0) { - list_for_each_entry_safe(iter, next, - &_params->params_gscan.hotlist_bssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - _params->params_gscan.nbssid_hotlist = 0; - DHD_PNO(("Flush Hotlist Config\n")); - } - if (flags & GSCAN_FLUSH_EPNO_CFG) { - dhd_epno_params_t *iter, *next; - - if (_params->params_gscan.num_epno_ssid > 0) { - list_for_each_entry_safe(iter, next, - &_params->params_gscan.epno_ssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - _params->params_gscan.num_epno_ssid = 0; - _params->params_gscan.num_visible_epno_ssid = 0; - _params->params_gscan.ssid_ext_last_used_index = 0; - DHD_PNO(("Flushed ePNO Config\n")); - } - - return; -} - -int -dhd_pno_lock_batch_results(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - int err = BCME_OK; - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - mutex_lock(&_pno_state->pno_mutex); - return err; -} - -void -dhd_pno_unlock_batch_results(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - _pno_state = PNO_GET_PNOSTATE(dhd); - mutex_unlock(&_pno_state->pno_mutex); - return; -} - -int -dhd_wait_batch_results_complete(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - int err = BCME_OK; - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - - /* Has the workqueue finished its job already?? */ - if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_IN_PROGRESS) { - DHD_PNO(("%s: Waiting to complete retrieval..\n", __FUNCTION__)); - wait_event_interruptible_timeout(_pno_state->batch_get_wait, - is_batch_retrieval_complete(&_params->params_gscan), - msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); - } else { /* GSCAN_BATCH_RETRIEVAL_COMPLETE */ - gscan_results_cache_t *iter; - uint16 num_results = 0; - - mutex_lock(&_pno_state->pno_mutex); - iter = _params->params_gscan.gscan_batch_cache; - while (iter) { - num_results += iter->tot_count - iter->tot_consumed; - iter = iter->next; - } - mutex_unlock(&_pno_state->pno_mutex); - - /* All results consumed/No results cached?? - * Get fresh results from FW - */ - if ((_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) && !num_results) { - DHD_PNO(("%s: No results cached, getting from FW..\n", __FUNCTION__)); - err = dhd_retreive_batch_scan_results(dhd); - if (err == BCME_OK) { - wait_event_interruptible_timeout(_pno_state->batch_get_wait, - is_batch_retrieval_complete(&_params->params_gscan), - msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); - } - } - } - DHD_PNO(("%s: Wait complete\n", __FUNCTION__)); - return err; -} - -static void * -dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len) -{ - gscan_results_cache_t *iter, *results; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - uint16 num_scan_ids = 0, num_results = 0; - - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - - iter = results = _params->params_gscan.gscan_batch_cache; - while (iter) { - num_results += iter->tot_count - iter->tot_consumed; - num_scan_ids++; - iter = iter->next; - } - - *len = ((num_results << 16) | (num_scan_ids)); - return results; -} - -void * -dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, - void *info, uint32 *len) -{ - void *ret = NULL; - dhd_pno_gscan_capabilities_t *ptr; - dhd_epno_params_t *epno_params; - dhd_pno_params_t *_params; - dhd_pno_status_info_t *_pno_state; - - if (!dhd || !dhd->pno_state) { - DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__)); - return NULL; - } - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - if (!len) { - DHD_ERROR(("%s: len is NULL\n", __FUNCTION__)); - return NULL; - } - - switch (type) { - case DHD_PNO_GET_CAPABILITIES: - ptr = (dhd_pno_gscan_capabilities_t *) - kmalloc(sizeof(dhd_pno_gscan_capabilities_t), GFP_KERNEL); - if (!ptr) - break; - /* Hardcoding these values for now, need to get - * these values from FW, will change in a later check-in - */ - ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE; - ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS; - ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; - ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX; - ptr->max_scan_reporting_threshold = 100; - ptr->max_hotlist_bssids = PFN_HOTLIST_MAX_NUM_APS; - ptr->max_hotlist_ssids = 0; - ptr->max_significant_wifi_change_aps = 0; - ptr->max_bssid_history_entries = 0; - ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; - ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; - ptr->max_white_list_ssid = MAX_WHITELIST_SSID; - ret = (void *)ptr; - *len = sizeof(dhd_pno_gscan_capabilities_t); - break; - - case DHD_PNO_GET_BATCH_RESULTS: - ret = dhd_get_gscan_batch_results(dhd, len); - break; - case DHD_PNO_GET_CHANNEL_LIST: - if (info) { - uint16 ch_list[WL_NUMCHANNELS]; - uint32 *ptr, mem_needed, i; - int32 err, nchan = WL_NUMCHANNELS; - uint32 *gscan_band = (uint32 *) info; - uint8 band = 0; - - /* No band specified?, nothing to do */ - if ((*gscan_band & GSCAN_BAND_MASK) == 0) { - DHD_PNO(("No band specified\n")); - *len = 0; - break; - } - - /* HAL and DHD use different bits for 2.4G and - * 5G in bitmap. Hence translating it here... - */ - if (*gscan_band & GSCAN_BG_BAND_MASK) { - band |= WLC_BAND_2G; - } - if (*gscan_band & GSCAN_A_BAND_MASK) { - band |= WLC_BAND_5G; - } - err = _dhd_pno_get_channels(dhd, ch_list, &nchan, - (band & GSCAN_ABG_BAND_MASK), - !(*gscan_band & GSCAN_DFS_MASK)); - - if (err < 0) { - DHD_ERROR(("%s: failed to get valid channel list\n", - __FUNCTION__)); - *len = 0; - } else { - mem_needed = sizeof(uint32) * nchan; - ptr = (uint32 *) kmalloc(mem_needed, GFP_KERNEL); - if (!ptr) { - DHD_ERROR(("%s: Unable to malloc %d bytes\n", - __FUNCTION__, mem_needed)); - break; - } - for (i = 0; i < nchan; i++) { - ptr[i] = wf_channel2mhz(ch_list[i], - (ch_list[i] <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - } - ret = ptr; - *len = mem_needed; - } - } else { - *len = 0; - DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__)); - } - break; - case DHD_PNO_GET_EPNO_SSID_ELEM: - if (_params->params_gscan.num_epno_ssid >= - (MAX_EPNO_SSID_NUM + MAX_EPNO_HIDDEN_SSID)) { - DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n", - _params->params_gscan.num_epno_ssid)); - return NULL; - } - - if (!_params->params_gscan.num_epno_ssid) - INIT_LIST_HEAD(&_params->params_gscan.epno_ssid_list); - - epno_params = kzalloc(sizeof(dhd_epno_params_t), GFP_KERNEL); - if (!epno_params) { - DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes", - sizeof(dhd_epno_params_t))); - return NULL; - } - _params->params_gscan.num_epno_ssid++; - epno_params->index = DHD_EPNO_DEFAULT_INDEX; - list_add_tail(&epno_params->list, &_params->params_gscan.epno_ssid_list); - ret = epno_params; - default: - DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); - break; - } - - return ret; - -} - -int -dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, - void *buf, uint8 flush) -{ - int err = BCME_OK; - dhd_pno_params_t *_params; - int i; - dhd_pno_status_info_t *_pno_state; - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - mutex_lock(&_pno_state->pno_mutex); - - switch (type) { - case DHD_PNO_BATCH_SCAN_CFG_ID: - { - gscan_batch_params_t *ptr = (gscan_batch_params_t *)buf; - _params->params_gscan.bestn = ptr->bestn; - _params->params_gscan.mscan = ptr->mscan; - _params->params_gscan.buffer_threshold = ptr->buffer_threshold; - } - break; - case DHD_PNO_GEOFENCE_SCAN_CFG_ID: - { - gscan_hotlist_scan_params_t *ptr = (gscan_hotlist_scan_params_t *)buf; - struct dhd_pno_bssid *_pno_bssid; - struct bssid_t *bssid_ptr; - int8 flags; - - if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, - GSCAN_FLUSH_HOTLIST_CFG); - } - - if (!ptr->nbssid) - break; - - if (!_params->params_gscan.nbssid_hotlist) - INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list); - - if ((_params->params_gscan.nbssid_hotlist + - ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { - DHD_ERROR(("Excessive number of hotlist APs programmed %d\n", - (_params->params_gscan.nbssid_hotlist + - ptr->nbssid))); - err = BCME_RANGE; - goto exit; - } - - for (i = 0, bssid_ptr = ptr->bssid; i < ptr->nbssid; i++, bssid_ptr++) { - _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); - - if (!_pno_bssid) { - DHD_ERROR(("_pno_bssid is NULL, cannot kalloc %zd bytes", - sizeof(struct dhd_pno_bssid))); - err = BCME_NOMEM; - goto exit; - } - memcpy(&_pno_bssid->macaddr, &bssid_ptr->macaddr, ETHER_ADDR_LEN); - - flags = (int8) bssid_ptr->rssi_reporting_threshold; - _pno_bssid->flags = flags << WL_PFN_RSSI_SHIFT; - list_add_tail(&_pno_bssid->list, - &_params->params_gscan.hotlist_bssid_list); - } - - _params->params_gscan.nbssid_hotlist += ptr->nbssid; - _params->params_gscan.lost_ap_window = ptr->lost_ap_window; - } - break; - case DHD_PNO_SCAN_CFG_ID: - { - int i, k; - uint16 band; - gscan_scan_params_t *ptr = (gscan_scan_params_t *)buf; - struct dhd_pno_gscan_channel_bucket *ch_bucket; - - if (ptr->nchannel_buckets <= GSCAN_MAX_CH_BUCKETS) { - _params->params_gscan.nchannel_buckets = ptr->nchannel_buckets; - - memcpy(_params->params_gscan.channel_bucket, ptr->channel_bucket, - _params->params_gscan.nchannel_buckets * - sizeof(struct dhd_pno_gscan_channel_bucket)); - ch_bucket = _params->params_gscan.channel_bucket; - - for (i = 0; i < ptr->nchannel_buckets; i++) { - band = ch_bucket[i].band; - for (k = 0; k < ptr->channel_bucket[i].num_channels; k++) { - ch_bucket[i].chan_list[k] = - wf_mhz2channel(ptr->channel_bucket[i].chan_list[k], - 0); - } - ch_bucket[i].band = 0; - /* HAL and DHD use different bits for 2.4G and - * 5G in bitmap. Hence translating it here... - */ - if (band & GSCAN_BG_BAND_MASK) - ch_bucket[i].band |= WLC_BAND_2G; - if (band & GSCAN_A_BAND_MASK) - ch_bucket[i].band |= WLC_BAND_5G; - if (band & GSCAN_DFS_MASK) - ch_bucket[i].band |= GSCAN_DFS_MASK; - - DHD_PNO(("band %d report_flag %d\n", ch_bucket[i].band, - ch_bucket[i].report_flag)); - } - - for (i = 0; i < ptr->nchannel_buckets; i++) { - ch_bucket[i].bucket_freq_multiple = - ch_bucket[i].bucket_freq_multiple/ptr->scan_fr; - ch_bucket[i].bucket_max_multiple = - ch_bucket[i].bucket_max_multiple/ptr->scan_fr; - DHD_PNO(("mult %d max_mult %d\n", - ch_bucket[i].bucket_freq_multiple, - ch_bucket[i].bucket_max_multiple)); - } - _params->params_gscan.scan_fr = ptr->scan_fr; - - DHD_PNO(("num_buckets %d scan_fr %d\n", - ptr->nchannel_buckets, - _params->params_gscan.scan_fr)); - } else { - err = BCME_BADARG; - } - } - break; - case DHD_PNO_EPNO_CFG_ID: - if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, - GSCAN_FLUSH_EPNO_CFG); - } else { - _params->params_gscan.num_visible_epno_ssid += *((uint16 *)buf); - } - break; - default: - err = BCME_BADARG; - DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); - break; - } -exit: - mutex_unlock(&_pno_state->pno_mutex); - return err; - -} - - -static bool -validate_gscan_params(struct dhd_pno_gscan_params *gscan_params) -{ - unsigned int i, k; - - if (!gscan_params->scan_fr || !gscan_params->nchannel_buckets) { - DHD_ERROR(("%s : Scan freq - %d or number of channel buckets - %d is empty\n", - __FUNCTION__, gscan_params->scan_fr, gscan_params->nchannel_buckets)); - return false; - } - - for (i = 0; i < gscan_params->nchannel_buckets; i++) { - if (!gscan_params->channel_bucket[i].band) { - for (k = 0; k < gscan_params->channel_bucket[i].num_channels; k++) { - if (gscan_params->channel_bucket[i].chan_list[k] > CHANNEL_5G_MAX) { - DHD_ERROR(("%s : Unknown channel %d\n", __FUNCTION__, - gscan_params->channel_bucket[i].chan_list[k])); - return false; - } - } - } - } - - return true; -} - -static int -dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) -{ - int err = BCME_OK; - int mode, i = 0, k; - uint16 _chan_list[WL_NUMCHANNELS]; - int tot_nchan = 0; - int num_buckets_to_fw, tot_num_buckets, gscan_param_size; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL; - wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL; - wl_pfn_bssid_t *p_pfn_bssid = NULL; - wlc_ssid_ext_t *pssid_list = NULL; - dhd_pno_params_t *params_legacy; - dhd_pno_params_t *_params; - - params_legacy = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - NULL_CHECK(gscan_params, "gscan_params is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - - if (!validate_gscan_params(gscan_params)) { - DHD_ERROR(("%s : Cannot start gscan - bad params\n", __FUNCTION__)); - err = BCME_BADARG; - goto exit; - } - /* Create channel list based on channel buckets */ - if (!(ch_bucket = dhd_pno_gscan_create_channel_list(dhd, _pno_state, - _chan_list, &tot_num_buckets, &num_buckets_to_fw))) { - goto exit; - } - - mutex_lock(&_pno_state->pno_mutex); - /* Clear any pre-existing results in our cache - * not consumed by framework - */ - dhd_gscan_clear_all_batch_results(dhd); - if (_pno_state->pno_mode & (DHD_PNO_GSCAN_MODE | DHD_PNO_LEGACY_MODE)) { - /* store current pno_mode before disabling pno */ - mode = _pno_state->pno_mode; - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - mutex_unlock(&_pno_state->pno_mutex); - goto exit; - } - /* restore the previous mode */ - _pno_state->pno_mode = mode; - } - _pno_state->pno_mode |= DHD_PNO_GSCAN_MODE; - mutex_unlock(&_pno_state->pno_mutex); - - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - - if (!pssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - - if ((err = _dhd_pno_add_ssid(dhd, pssid_list, - params_legacy->params_legacy.nssid)) < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); - goto exit; - } - } - - if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_GSCAN_MODE)) < 0) { - DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); - goto exit; - } - - gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + - (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); - pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size); - - if (!pfn_gscan_cfg_t) { - DHD_ERROR(("%s: failed to malloc memory of size %d\n", - __FUNCTION__, gscan_param_size)); - err = BCME_NOMEM; - goto exit; - } - - pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION; - if (gscan_params->mscan) { - pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold; - } else { - pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; - } - pfn_gscan_cfg_t->flags = - (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); - pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw; - pfn_gscan_cfg_t->retry_threshold = GSCAN_RETRY_THRESHOLD; - - for (i = 0, k = 0; i < tot_num_buckets; i++) { - if (ch_bucket[i].bucket_end_index != CHANNEL_BUCKET_EMPTY_INDEX) { - pfn_gscan_cfg_t->channel_bucket[k].bucket_end_index = - ch_bucket[i].bucket_end_index; - pfn_gscan_cfg_t->channel_bucket[k].bucket_freq_multiple = - ch_bucket[i].bucket_freq_multiple; - pfn_gscan_cfg_t->channel_bucket[k].max_freq_multiple = - ch_bucket[i].max_freq_multiple; - pfn_gscan_cfg_t->channel_bucket[k].repeat = - ch_bucket[i].repeat; - pfn_gscan_cfg_t->channel_bucket[k].flag = - ch_bucket[i].flag; - k++; - } - } - - tot_nchan = pfn_gscan_cfg_t->channel_bucket[num_buckets_to_fw - 1].bucket_end_index + 1; - DHD_PNO(("Total channel num %d total ch_buckets %d ch_buckets_to_fw %d \n", tot_nchan, - tot_num_buckets, num_buckets_to_fw)); - - if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { - DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - - if ((err = _dhd_pno_gscan_cfg(dhd, pfn_gscan_cfg_t, gscan_param_size)) < 0) { - DHD_ERROR(("%s : failed to set call pno_gscan_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - if (gscan_params->nbssid_hotlist) { - struct dhd_pno_bssid *iter, *next; - wl_pfn_bssid_t *ptr; - p_pfn_bssid = (wl_pfn_bssid_t *)kzalloc(sizeof(wl_pfn_bssid_t) * - gscan_params->nbssid_hotlist, GFP_KERNEL); - if (p_pfn_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" - " (count: %d)", - __FUNCTION__, _params->params_hotlist.nbssid)); - err = BCME_NOMEM; - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - goto exit; - } - ptr = p_pfn_bssid; - /* convert dhd_pno_bssid to wl_pfn_bssid */ - DHD_PNO(("nhotlist %d\n", gscan_params->nbssid_hotlist)); - list_for_each_entry_safe(iter, next, - &gscan_params->hotlist_bssid_list, list) { - memcpy(&ptr->macaddr, - &iter->macaddr, ETHER_ADDR_LEN); - ptr->flags = iter->flags; - ptr++; - } - - err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, gscan_params->nbssid_hotlist); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", - __FUNCTION__, err)); - goto exit; - } - } - - if (gscan_params->num_epno_ssid > 0) { - DHD_PNO(("num_epno_ssid %d\n", gscan_params->num_epno_ssid)); - err = dhd_epno_set_ssid(dhd, _pno_state); - if (err < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); - goto exit; - } - } - - if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) { - DHD_ERROR(("%s : failed to enable PNO err %d\n", __FUNCTION__, err)); - } - -exit: - /* clear mode in case of error */ - if (err < 0) { - int ret = dhd_pno_clean(dhd); - if (ret < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, ret)); - - } else { - _pno_state->pno_mode &= ~DHD_PNO_GSCAN_MODE; - - } - } - kfree(pssid_list); - kfree(p_pfn_bssid); - if (pfn_gscan_cfg_t) { - MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size); - } - if (ch_bucket) { - MFREE(dhd->osh, ch_bucket, - (tot_num_buckets * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); - } - return err; -} - -static wl_pfn_gscan_ch_bucket_cfg_t * -dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, - dhd_pno_status_info_t *_pno_state, - uint16 *chan_list, - uint32 *num_buckets, - uint32 *num_buckets_to_fw) -{ - int i, num_channels, err, nchan = WL_NUMCHANNELS, ch_cnt; - uint16 *ptr = chan_list, max; - wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket; - dhd_pno_params_t *_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - bool is_pno_legacy_running = _pno_state->pno_mode & DHD_PNO_LEGACY_MODE; - dhd_pno_gscan_channel_bucket_t *gscan_buckets = _params->params_gscan.channel_bucket; - - if (is_pno_legacy_running) - *num_buckets = _params->params_gscan.nchannel_buckets + 1; - else - *num_buckets = _params->params_gscan.nchannel_buckets; - - *num_buckets_to_fw = 0; - - ch_bucket = (wl_pfn_gscan_ch_bucket_cfg_t *) MALLOC(dhd->osh, - ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); - - if (!ch_bucket) { - DHD_ERROR(("%s: failed to malloc memory of size %zd\n", - __FUNCTION__, (*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); - *num_buckets_to_fw = *num_buckets = 0; - return NULL; - } - - max = gscan_buckets[0].bucket_freq_multiple; - num_channels = 0; - /* nchan is the remaining space left in chan_list buffer - * So any overflow list of channels is ignored - */ - for (i = 0; i < _params->params_gscan.nchannel_buckets && nchan; i++) { - if (!gscan_buckets[i].band) { - ch_cnt = MIN(gscan_buckets[i].num_channels, (uint8)nchan); - num_channels += ch_cnt; - memcpy(ptr, gscan_buckets[i].chan_list, - ch_cnt * sizeof(uint16)); - ptr = ptr + ch_cnt; - } else { - /* get a valid channel list based on band B or A */ - err = _dhd_pno_get_channels(dhd, ptr, - &nchan, (gscan_buckets[i].band & GSCAN_ABG_BAND_MASK), - !(gscan_buckets[i].band & GSCAN_DFS_MASK)); - - if (err < 0) { - DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", - __FUNCTION__, gscan_buckets[i].band)); - MFREE(dhd->osh, ch_bucket, - ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); - *num_buckets_to_fw = *num_buckets = 0; - return NULL; - } - - num_channels += nchan; - ptr = ptr + nchan; - } - - ch_bucket[i].bucket_end_index = num_channels - 1; - ch_bucket[i].bucket_freq_multiple = gscan_buckets[i].bucket_freq_multiple; - ch_bucket[i].repeat = gscan_buckets[i].repeat; - ch_bucket[i].max_freq_multiple = gscan_buckets[i].bucket_max_multiple; - ch_bucket[i].flag = gscan_buckets[i].report_flag; - /* HAL and FW interpretations are opposite for this bit */ - ch_bucket[i].flag ^= DHD_PNO_REPORT_NO_BATCH; - if (max < gscan_buckets[i].bucket_freq_multiple) - max = gscan_buckets[i].bucket_freq_multiple; - nchan = WL_NUMCHANNELS - num_channels; - *num_buckets_to_fw = *num_buckets_to_fw + 1; - DHD_PNO(("end_idx %d freq_mult - %d\n", - ch_bucket[i].bucket_end_index, ch_bucket[i].bucket_freq_multiple)); - } - - _params->params_gscan.max_ch_bucket_freq = max; - /* Legacy PNO maybe running, which means we need to create a legacy PNO bucket - * Get GCF of Legacy PNO and Gscan scanfreq - */ - if (is_pno_legacy_running) { - dhd_pno_params_t *_params1 = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; - uint16 *legacy_chan_list = _params1->params_legacy.chan_list; - uint16 common_freq; - uint32 legacy_bucket_idx = _params->params_gscan.nchannel_buckets; - /* If no space is left then only the gscan buckets will be sent to FW */ - if (nchan) { - common_freq = gcd(_params->params_gscan.scan_fr, - _params1->params_legacy.scan_fr); - max = gscan_buckets[0].bucket_freq_multiple; - /* GSCAN buckets */ - for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) { - ch_bucket[i].bucket_freq_multiple *= _params->params_gscan.scan_fr; - ch_bucket[i].bucket_freq_multiple /= common_freq; - if (max < gscan_buckets[i].bucket_freq_multiple) - max = gscan_buckets[i].bucket_freq_multiple; - } - /* Legacy PNO bucket */ - ch_bucket[legacy_bucket_idx].bucket_freq_multiple = - _params1->params_legacy.scan_fr; - ch_bucket[legacy_bucket_idx].bucket_freq_multiple /= - common_freq; - _params->params_gscan.max_ch_bucket_freq = MAX(max, - ch_bucket[legacy_bucket_idx].bucket_freq_multiple); - ch_bucket[legacy_bucket_idx].flag = CH_BUCKET_REPORT_REGULAR; - /* Now add channels to the legacy scan bucket */ - for (i = 0; i < _params1->params_legacy.nchan && nchan; i++, nchan--) { - ptr[i] = legacy_chan_list[i]; - num_channels++; - } - ch_bucket[legacy_bucket_idx].bucket_end_index = num_channels - 1; - *num_buckets_to_fw = *num_buckets_to_fw + 1; - DHD_PNO(("end_idx %d freq_mult - %d\n", - ch_bucket[legacy_bucket_idx].bucket_end_index, - ch_bucket[legacy_bucket_idx].bucket_freq_multiple)); - } - } - return ch_bucket; -} - -static int -dhd_pno_stop_for_gscan(dhd_pub_t *dhd) -{ - int err = BCME_OK; - int mode; - dhd_pno_status_info_t *_pno_state; - wlc_ssid_ext_t *pssid_list = NULL; - - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", - __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - - if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { - DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); - goto exit; - } - if (_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.mscan) { - /* retrieve the batching data from firmware into host */ - err = dhd_wait_batch_results_complete(dhd); - if (err != BCME_OK) - goto exit; - } - mutex_lock(&_pno_state->pno_mutex); - mode = _pno_state->pno_mode & ~DHD_PNO_GSCAN_MODE; - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - mutex_unlock(&_pno_state->pno_mutex); - return err; - } - _pno_state->pno_mode = mode; - mutex_unlock(&_pno_state->pno_mutex); - _pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.ssid_ext_last_used_index = 0; - - /* Reprogram Legacy PNO if it was running */ - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - struct dhd_pno_legacy_params *params_legacy; - uint16 chan_list[WL_NUMCHANNELS]; - - params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; - pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!pssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - - DHD_PNO(("Restarting Legacy PNO SSID scan...\n")); - memcpy(chan_list, params_legacy->chan_list, - (params_legacy->nchan * sizeof(uint16))); - err = dhd_pno_set_for_ssid(dhd, pssid_list, params_legacy->nssid, - params_legacy->scan_fr, params_legacy->pno_repeat, - params_legacy->pno_freq_expo_max, chan_list, - params_legacy->nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - - } - -exit: - kfree(pssid_list); - return err; -} - -int -dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush) -{ - int err = BCME_OK; - dhd_pno_params_t *params; - dhd_pno_status_info_t *_pno_state; - struct dhd_pno_gscan_params *gscan_params; - - NULL_CHECK(dhd, "dhd is NULL\n", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - DHD_ERROR(("%s enter - run %d flush %d\n", __FUNCTION__, run, flush)); - - params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - gscan_params = ¶ms->params_gscan; - - if (run) { - err = dhd_pno_set_for_gscan(dhd, gscan_params); - } else { - if (flush) { - mutex_lock(&_pno_state->pno_mutex); - dhd_pno_reset_cfg_gscan(params, _pno_state, GSCAN_FLUSH_ALL_CFG); - mutex_unlock(&_pno_state->pno_mutex); - } - /* Need to stop all gscan */ - err = dhd_pno_stop_for_gscan(dhd); - } - - return err; -} - -int -dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag) -{ - int err = BCME_OK; - dhd_pno_params_t *params; - dhd_pno_status_info_t *_pno_state; - struct dhd_pno_gscan_params *gscan_params; - uint8 old_flag; - - NULL_CHECK(dhd, "dhd is NULL\n", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - - params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - gscan_params = ¶ms->params_gscan; - - mutex_lock(&_pno_state->pno_mutex); - - old_flag = gscan_params->send_all_results_flag; - gscan_params->send_all_results_flag = (uint8) real_time_flag; - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - if (old_flag != gscan_params->send_all_results_flag) { - wl_pfn_gscan_cfg_t gscan_cfg; - gscan_cfg.version = WL_GSCAN_CFG_VERSION; - gscan_cfg.flags = (gscan_params->send_all_results_flag & - GSCAN_SEND_ALL_RESULTS_MASK); - gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK; - - if ((err = _dhd_pno_gscan_cfg(dhd, &gscan_cfg, - sizeof(wl_pfn_gscan_cfg_t))) < 0) { - DHD_ERROR(("%s : pno_gscan_cfg failed (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit_mutex_unlock; - } - } else { - DHD_PNO(("No change in flag - %d\n", old_flag)); - } - } else { - DHD_PNO(("Gscan not started\n")); - } -exit_mutex_unlock: - mutex_unlock(&_pno_state->pno_mutex); -exit: - return err; -} - -/* Cleanup any consumed results - * Return TRUE if all results consumed, else FALSE - */ -int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd) -{ - int ret = 0; - dhd_pno_params_t *params; - struct dhd_pno_gscan_params *gscan_params; - dhd_pno_status_info_t *_pno_state; - gscan_results_cache_t *iter, *tmp; - - _pno_state = PNO_GET_PNOSTATE(dhd); - params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - gscan_params = ¶ms->params_gscan; - iter = gscan_params->gscan_batch_cache; - - while (iter) { - if (iter->tot_consumed == iter->tot_count) { - tmp = iter->next; - kfree(iter); - iter = tmp; - } else - break; - } - gscan_params->gscan_batch_cache = iter; - ret = (iter == NULL); - return ret; -} - -static int -_dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) -{ - int err = BCME_OK; - uint32 timestamp = 0, ts = 0, i, j, timediff; - dhd_pno_params_t *params; - dhd_pno_status_info_t *_pno_state; - wl_pfn_lnet_info_t *plnetinfo; - struct dhd_pno_gscan_params *gscan_params; - wl_pfn_lscanresults_t *plbestnet = NULL; - gscan_results_cache_t *iter, *tail; - wifi_gscan_result_t *result; - uint8 *nAPs_per_scan = NULL; - uint8 num_scans_in_cur_iter; - uint16 count; - - NULL_CHECK(dhd, "dhd is NULL\n", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - - _pno_state = PNO_GET_PNOSTATE(dhd); - params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { - DHD_ERROR(("%s: GSCAN is not enabled\n", __FUNCTION__)); - goto exit; - } - gscan_params = ¶ms->params_gscan; - nAPs_per_scan = (uint8 *) MALLOC(dhd->osh, gscan_params->mscan); - - if (!nAPs_per_scan) { - DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, - gscan_params->mscan)); - err = BCME_NOMEM; - goto exit; - } - - plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); - if (!plbestnet) { - DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, - PNO_BESTNET_LEN)); - err = BCME_NOMEM; - goto exit; - } - - mutex_lock(&_pno_state->pno_mutex); - - dhd_gscan_clear_all_batch_results(dhd); - - if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { - DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); - goto exit_mutex_unlock; - } - - timediff = gscan_params->scan_fr * 1000; - timediff = timediff >> 1; - - /* Ok, now lets start getting results from the FW */ - plbestnet->status = PFN_INCOMPLETE; - tail = gscan_params->gscan_batch_cache; - while (plbestnet->status != PFN_COMPLETE) { - memset(plbestnet, 0, PNO_BESTNET_LEN); - err = dhd_iovar(dhd, 0, "pfnlbest", (char *)plbestnet, PNO_BESTNET_LEN, 0); - if (err < 0) { - DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n", - __FUNCTION__, err)); - goto exit_mutex_unlock; - } - DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, - plbestnet->status, plbestnet->count)); - if (plbestnet->version != PFN_SCANRESULT_VERSION) { - err = BCME_VERSION; - DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", - plbestnet->version, PFN_SCANRESULT_VERSION)); - goto exit_mutex_unlock; - } - if (plbestnet->count == 0) { - DHD_PNO(("No more batch results\n")); - goto exit_mutex_unlock; - } - num_scans_in_cur_iter = 0; - timestamp = plbestnet->netinfo[0].timestamp; - /* find out how many scans' results did we get in this batch of FW results */ - for (i = 0, count = 0; i < plbestnet->count; i++, count++) { - plnetinfo = &plbestnet->netinfo[i]; - /* Unlikely to happen, but just in case the results from - * FW doesnt make sense..... Assume its part of one single scan - */ - if (num_scans_in_cur_iter > gscan_params->mscan) { - num_scans_in_cur_iter = 0; - count = plbestnet->count; - break; - } - if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) { - nAPs_per_scan[num_scans_in_cur_iter] = count; - count = 0; - num_scans_in_cur_iter++; - } - timestamp = plnetinfo->timestamp; - } - nAPs_per_scan[num_scans_in_cur_iter] = count; - num_scans_in_cur_iter++; - - DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter)); - plnetinfo = &plbestnet->netinfo[0]; - - for (i = 0; i < num_scans_in_cur_iter; i++) { - iter = (gscan_results_cache_t *) - kmalloc(((nAPs_per_scan[i] - 1) * sizeof(wifi_gscan_result_t)) + - sizeof(gscan_results_cache_t), GFP_KERNEL); - if (!iter) { - DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", - __FUNCTION__, gscan_params->mscan)); - err = BCME_NOMEM; - goto exit_mutex_unlock; - } - /* Need this check because the new set of results from FW - * maybe a continuation of previous sets' scan results - */ - if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) { - iter->scan_id = ++gscan_params->scan_id; - } else { - iter->scan_id = gscan_params->scan_id; - } - DHD_PNO(("scan_id %d tot_count %d\n", gscan_params->scan_id, - nAPs_per_scan[i])); - iter->tot_count = nAPs_per_scan[i]; - iter->tot_consumed = 0; - iter->flag = 0; - if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { - DHD_PNO(("This scan is aborted\n")); - iter->flag = (ENABLE << PNO_STATUS_ABORT); - } else if (gscan_params->reason) { - iter->flag = (ENABLE << gscan_params->reason); - } - - if (!tail) { - gscan_params->gscan_batch_cache = iter; - } else { - tail->next = iter; - } - tail = iter; - iter->next = NULL; - for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) { - result = &iter->results[j]; - - result->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, - (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - result->rssi = (int32) plnetinfo->RSSI; - /* Info not available & not expected */ - result->beacon_period = 0; - result->capability = 0; - result->ie_length = 0; - result->rtt = (uint64) plnetinfo->rtt0; - result->rtt_sd = (uint64) plnetinfo->rtt1; - result->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); - ts = plnetinfo->timestamp; - if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s: Invalid SSID length %d\n", - __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); - plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; - } - memcpy(result->ssid, plnetinfo->pfnsubnet.SSID, - plnetinfo->pfnsubnet.SSID_len); - result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; - memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID, - ETHER_ADDR_LEN); - - DHD_PNO(("\tSSID : ")); - DHD_PNO(("\n")); - DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", - result->macaddr.octet[0], - result->macaddr.octet[1], - result->macaddr.octet[2], - result->macaddr.octet[3], - result->macaddr.octet[4], - result->macaddr.octet[5])); - DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", - plnetinfo->pfnsubnet.channel, - plnetinfo->RSSI, plnetinfo->timestamp)); - DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", - plnetinfo->rtt0, plnetinfo->rtt1)); - - } - } - } -exit_mutex_unlock: - mutex_unlock(&_pno_state->pno_mutex); -exit: - params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_COMPLETE; - smp_wmb(); - wake_up_interruptible(&_pno_state->batch_get_wait); - if (nAPs_per_scan) { - MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan); - } - if (plbestnet) { - MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); - } - DHD_PNO(("Batch retrieval done!\n")); - return err; -} -#endif /* GSCAN_SUPPORT */ - -static int -_dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) -{ - int err = BCME_OK; - int i, j; - uint32 timestamp = 0; - dhd_pno_params_t *_params = NULL; - dhd_pno_status_info_t *_pno_state = NULL; - wl_pfn_lscanresults_t *plbestnet = NULL; - wl_pfn_lnet_info_t *plnetinfo; - dhd_pno_bestnet_entry_t *pbestnet_entry; - dhd_pno_best_header_t *pbestnetheader = NULL; - dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext; - bool allocate_header = FALSE; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit_no_unlock; - } - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit_no_unlock; - } - - if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { - DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); - goto exit_no_unlock; - } - mutex_lock(&_pno_state->pno_mutex); - _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; - if (buf && bufsize) { - if (!list_empty(&_params->params_batch.get_batch.expired_scan_results_list)) { - /* need to check whether we have cashed data or not */ - DHD_PNO(("%s: have cashed batching data in Driver\n", - __FUNCTION__)); - /* convert to results format */ - goto convert_format; - } else { - /* this is a first try to get batching results */ - if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { - /* move the scan_results_list to expired_scan_results_lists */ - list_for_each_entry_safe(siter, snext, - &_params->params_batch.get_batch.scan_results_list, list) { - list_move_tail(&siter->list, - &_params->params_batch.get_batch.expired_scan_results_list); - } - _params->params_batch.get_batch.top_node_cnt = 0; - _params->params_batch.get_batch.expired_tot_scan_cnt = - _params->params_batch.get_batch.tot_scan_cnt; - _params->params_batch.get_batch.tot_scan_cnt = 0; - goto convert_format; - } - } - } - /* create dhd_pno_scan_results_t whenever we got event WLC_E_PFN_BEST_BATCHING */ - pscan_results = (dhd_pno_scan_results_t *)MALLOC(dhd->osh, SCAN_RESULTS_SIZE); - if (pscan_results == NULL) { - err = BCME_NOMEM; - DHD_ERROR(("failed to allocate dhd_pno_scan_results_t\n")); - goto exit; - } - pscan_results->bestnetheader = NULL; - pscan_results->cnt_header = 0; - /* add the element into list unless total node cnt is less than MAX_NODE_ CNT */ - if (_params->params_batch.get_batch.top_node_cnt < MAX_NODE_CNT) { - list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); - _params->params_batch.get_batch.top_node_cnt++; - } else { - int _removed_scan_cnt; - /* remove oldest one and add new one */ - DHD_PNO(("%s : Remove oldest node and add new one\n", __FUNCTION__)); - _removed_scan_cnt = _dhd_pno_clear_all_batch_results(dhd, - &_params->params_batch.get_batch.scan_results_list, TRUE); - _params->params_batch.get_batch.tot_scan_cnt -= _removed_scan_cnt; - list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); - - } - plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); - NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - memset(plbestnet, 0, PNO_BESTNET_LEN); - while (plbestnet->status != PFN_COMPLETE) { - memset(plbestnet, 0, PNO_BESTNET_LEN); - err = dhd_iovar(dhd, 0, "pfnlbest", (char *)plbestnet, PNO_BESTNET_LEN, 0); - if (err < 0) { - if (err == BCME_EPERM) { - DHD_ERROR(("we cannot get the batching data " - "during scanning in firmware, try again\n,")); - msleep(500); - continue; - } else { - DHD_ERROR(("%s : failed to execute pfnlbest (err :%d)\n", - __FUNCTION__, err)); - goto exit; - } - } - DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, - plbestnet->status, plbestnet->count)); - if (plbestnet->version != PFN_SCANRESULT_VERSION) { - err = BCME_VERSION; - DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", - plbestnet->version, PFN_SCANRESULT_VERSION)); - goto exit; - } - plnetinfo = plbestnet->netinfo; - for (i = 0; i < plbestnet->count; i++) { - pbestnet_entry = (dhd_pno_bestnet_entry_t *) - MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); - if (pbestnet_entry == NULL) { - err = BCME_NOMEM; - DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); - goto exit; - } - memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE); - pbestnet_entry->recorded_time = jiffies; /* record the current time */ - /* create header for the first entry */ - allocate_header = (i == 0)? TRUE : FALSE; - /* check whether the new generation is started or not */ - if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) - > TIME_MIN_DIFF)) - allocate_header = TRUE; - timestamp = plnetinfo->timestamp; - if (allocate_header) { - pbestnetheader = (dhd_pno_best_header_t *) - MALLOC(dhd->osh, BEST_HEADER_SIZE); - if (pbestnetheader == NULL) { - err = BCME_NOMEM; - if (pbestnet_entry) - MFREE(dhd->osh, pbestnet_entry, - BESTNET_ENTRY_SIZE); - DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); - goto exit; - } - /* increase total cnt of bestnet header */ - pscan_results->cnt_header++; - /* need to record the reason to call dhd_pno_get_for_bach */ - if (reason) - pbestnetheader->reason = (ENABLE << reason); - memset(pbestnetheader, 0, BEST_HEADER_SIZE); - /* initialize the head of linked list */ - INIT_LIST_HEAD(&(pbestnetheader->entry_list)); - /* link the pbestnet heaer into existed list */ - if (pscan_results->bestnetheader == NULL) - /* In case of header */ - pscan_results->bestnetheader = pbestnetheader; - else { - dhd_pno_best_header_t *head = pscan_results->bestnetheader; - pscan_results->bestnetheader = pbestnetheader; - pbestnetheader->next = head; - } - } - /* fills the best network info */ - pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; - pbestnet_entry->RSSI = plnetinfo->RSSI; - if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { - /* if RSSI is positive value, we assume that - * this scan is aborted by other scan - */ - DHD_PNO(("This scan is aborted\n")); - pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); - } - pbestnet_entry->rtt0 = plnetinfo->rtt0; - pbestnet_entry->rtt1 = plnetinfo->rtt1; - pbestnet_entry->timestamp = plnetinfo->timestamp; - if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s: Invalid SSID length %d: trimming it to max\n", - __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); - plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; - } - pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; - memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, - pbestnet_entry->SSID_len); - memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); - /* add the element into list */ - list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); - /* increase best entry count */ - pbestnetheader->tot_cnt++; - pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; - DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1)); - DHD_PNO(("\tSSID : ")); - for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) - DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j])); - DHD_PNO(("\n")); - DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", - plnetinfo->pfnsubnet.BSSID.octet[0], - plnetinfo->pfnsubnet.BSSID.octet[1], - plnetinfo->pfnsubnet.BSSID.octet[2], - plnetinfo->pfnsubnet.BSSID.octet[3], - plnetinfo->pfnsubnet.BSSID.octet[4], - plnetinfo->pfnsubnet.BSSID.octet[5])); - DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", - plnetinfo->pfnsubnet.channel, - plnetinfo->RSSI, plnetinfo->timestamp)); - DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1)); - plnetinfo++; - } - } - if (pscan_results->cnt_header == 0) { - /* In case that we didn't get any data from the firmware - * Remove the current scan_result list from get_bach.scan_results_list. - */ - DHD_PNO(("NO BATCH DATA from Firmware, Delete current SCAN RESULT LIST\n")); - list_del(&pscan_results->list); - MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE); - _params->params_batch.get_batch.top_node_cnt--; - } else { - /* increase total scan count using current scan count */ - _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; - } - - if (buf && bufsize) { - /* This is a first try to get batching results */ - if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { - /* move the scan_results_list to expired_scan_results_lists */ - list_for_each_entry_safe(siter, snext, - &_params->params_batch.get_batch.scan_results_list, list) { - list_move_tail(&siter->list, - &_params->params_batch.get_batch.expired_scan_results_list); - } - /* reset gloval values after moving to expired list */ - _params->params_batch.get_batch.top_node_cnt = 0; - _params->params_batch.get_batch.expired_tot_scan_cnt = - _params->params_batch.get_batch.tot_scan_cnt; - _params->params_batch.get_batch.tot_scan_cnt = 0; - } -convert_format: - err = _dhd_pno_convert_format(dhd, &_params->params_batch, buf, bufsize); - if (err < 0) { - DHD_ERROR(("failed to convert the data into upper layer format\n")); - goto exit; - } - } -exit: - if (plbestnet) - MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); - if (_params) { - _params->params_batch.get_batch.buf = NULL; - _params->params_batch.get_batch.bufsize = 0; - _params->params_batch.get_batch.bytes_written = err; - } - mutex_unlock(&_pno_state->pno_mutex); -exit_no_unlock: - if (waitqueue_active(&_pno_state->get_batch_done.wait)) - complete(&_pno_state->get_batch_done); - return err; -} -static void -_dhd_pno_get_batch_handler(struct work_struct *work) -{ - dhd_pno_status_info_t *_pno_state; - dhd_pub_t *dhd; - struct dhd_pno_batch_params *params_batch; - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = container_of(work, struct dhd_pno_status_info, work); - dhd = _pno_state->dhd; - if (dhd == NULL) { - DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); - return; - } -#ifdef GSCAN_SUPPORT - _dhd_pno_get_gscan_batch_from_fw(dhd); -#endif /* GSCAN_SUPPORT */ - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; - - _dhd_pno_get_for_batch(dhd, params_batch->get_batch.buf, - params_batch->get_batch.bufsize, params_batch->get_batch.reason); - } -} - -int -dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) -{ - int err = BCME_OK; - char *pbuf = buf; - dhd_pno_status_info_t *_pno_state; - struct dhd_pno_batch_params *params_batch; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - struct dhd_pno_gscan_params *gscan_params; - gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; - gscan_params->reason = reason; - err = dhd_retreive_batch_scan_results(dhd); - if (err == BCME_OK) { - wait_event_interruptible_timeout(_pno_state->batch_get_wait, - is_batch_retrieval_complete(gscan_params), - msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); - } - } else -#endif - { - if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { - DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); - memset(pbuf, 0, bufsize); - pbuf += sprintf(pbuf, "scancount=%d\n", 0); - sprintf(pbuf, "%s", RESULTS_END_MARKER); - err = strlen(buf); - goto exit; - } - params_batch->get_batch.buf = buf; - params_batch->get_batch.bufsize = bufsize; - params_batch->get_batch.reason = reason; - params_batch->get_batch.bytes_written = 0; - schedule_work(&_pno_state->work); - wait_for_completion(&_pno_state->get_batch_done); - } - -#ifdef GSCAN_SUPPORT - if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) -#endif - err = params_batch->get_batch.bytes_written; -exit: - return err; -} - -int -dhd_pno_stop_for_batch(dhd_pub_t *dhd) -{ - int err = BCME_OK; - int mode = 0; - int i = 0; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - wl_pfn_bssid_t *p_pfn_bssid = NULL; - wlc_ssid_ext_t *p_ssid_list = NULL; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", - __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - DHD_PNO(("Gscan is ongoing, nothing to stop here\n")); - return err; - } -#endif - - if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { - DHD_ERROR(("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__)); - goto exit; - } - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { - mode = _pno_state->pno_mode; - dhd_pno_clean(dhd); - _pno_state->pno_mode = mode; - /* restart Legacy PNO if the Legacy PNO is on */ - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - struct dhd_pno_legacy_params *_params_legacy; - _params_legacy = - &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!p_ssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, - _params_legacy->scan_fr, _params_legacy->pno_repeat, - _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, - _params_legacy->nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - struct dhd_pno_bssid *iter, *next; - _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * - _params->params_hotlist.nbssid, GFP_KERNEL); - if (p_pfn_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" - " (count: %d)", - __FUNCTION__, _params->params_hotlist.nbssid)); - err = BCME_ERROR; - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - goto exit; - } - i = 0; - /* convert dhd_pno_bssid to wl_pfn_bssid */ - list_for_each_entry_safe(iter, next, - &_params->params_hotlist.bssid_list, list) { - memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN); - p_pfn_bssid[i].flags = iter->flags; - i++; - } - err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); - if (err < 0) { - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } - } else { - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } -exit: - _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; - _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); - if (p_ssid_list) - kfree(p_ssid_list); - if (p_pfn_bssid) - kfree(p_pfn_bssid); - return err; -} - -int -dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, - struct dhd_pno_hotlist_params *hotlist_params) -{ - int err = BCME_OK; - int i; - uint16 _chan_list[WL_NUMCHANNELS]; - int rem_nchan = 0; - int tot_nchan = 0; - int mode = 0; - dhd_pno_params_t *_params; - dhd_pno_params_t *_params2; - struct dhd_pno_bssid *_pno_bssid; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - NULL_CHECK(hotlist_params, "hotlist_params is NULL", err); - NULL_CHECK(p_pfn_bssid, "p_pfn_bssid is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - _params = &_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]; - if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { - _pno_state->pno_mode |= DHD_PNO_HOTLIST_MODE; - err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_HOTLIST_MODE); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", - __FUNCTION__)); - goto exit; - } - } - _params->params_batch.nchan = hotlist_params->nchan; - _params->params_batch.scan_fr = hotlist_params->scan_fr; - if (hotlist_params->nchan) - memcpy(_params->params_hotlist.chan_list, hotlist_params->chan_list, - sizeof(_params->params_hotlist.chan_list)); - memset(_chan_list, 0, sizeof(_chan_list)); - - rem_nchan = ARRAYSIZE(hotlist_params->chan_list) - hotlist_params->nchan; - if (hotlist_params->band == WLC_BAND_2G || hotlist_params->band == WLC_BAND_5G) { - /* get a valid channel list based on band B or A */ - err = _dhd_pno_get_channels(dhd, - &_params->params_hotlist.chan_list[hotlist_params->nchan], - &rem_nchan, hotlist_params->band, FALSE); - if (err < 0) { - DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", - __FUNCTION__, hotlist_params->band)); - goto exit; - } - /* now we need to update nchan because rem_chan has valid channel count */ - _params->params_hotlist.nchan += rem_nchan; - /* need to sort channel list */ - sort(_params->params_hotlist.chan_list, _params->params_hotlist.nchan, - sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL); - } -#ifdef PNO_DEBUG -{ - int i; - DHD_PNO(("Channel list : ")); - for (i = 0; i < _params->params_batch.nchan; i++) { - DHD_PNO(("%d ", _params->params_batch.chan_list[i])); - } - DHD_PNO(("\n")); -} -#endif - if (_params->params_hotlist.nchan) { - /* copy the channel list into local array */ - memcpy(_chan_list, _params->params_hotlist.chan_list, - sizeof(_chan_list)); - tot_nchan = _params->params_hotlist.nchan; - } - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - DHD_PNO(("PNO SSID is on progress in firmware\n")); - /* store current pno_mode before disabling pno */ - mode = _pno_state->pno_mode; - err = _dhd_pno_enable(dhd, PNO_OFF); - if (err < 0) { - DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - goto exit; - } - /* restore the previous mode */ - _pno_state->pno_mode = mode; - /* Use the superset for channelist between two mode */ - _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - if (_params2->params_legacy.nchan > 0 && - _params->params_hotlist.nchan > 0) { - err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, - &_params2->params_legacy.chan_list[0], - _params2->params_legacy.nchan, - &_params->params_hotlist.chan_list[0], - _params->params_hotlist.nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to merge channel list" - "between legacy and hotlist\n", - __FUNCTION__)); - goto exit; - } - } - - } - - INIT_LIST_HEAD(&(_params->params_hotlist.bssid_list)); - - err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, hotlist_params->nbssid); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", - __FUNCTION__, err)); - goto exit; - } - if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_HOTLIST_MODE)) < 0) { - DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - if (tot_nchan > 0) { - if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { - DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - } - for (i = 0; i < hotlist_params->nbssid; i++) { - _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); - NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err); - memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN); - _pno_bssid->flags = p_pfn_bssid[i].flags; - list_add_tail(&_pno_bssid->list, &_params->params_hotlist.bssid_list); - } - _params->params_hotlist.nbssid = hotlist_params->nbssid; - if (_pno_state->pno_status == DHD_PNO_DISABLED) { - if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) - DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); - } -exit: - /* clear mode in case of error */ - if (err < 0) - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - return err; -} - -int -dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) -{ - int err = BCME_OK; - uint32 mode = 0; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - wlc_ssid_ext_t *p_ssid_list = NULL; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", - __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - - if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { - DHD_ERROR(("%s : Hotlist MODE is not enabled\n", - __FUNCTION__)); - goto exit; - } - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - - if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_BATCH_MODE)) { - /* retrieve the batching data from firmware into host */ - dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); - /* save current pno_mode before calling dhd_pno_clean */ - mode = _pno_state->pno_mode; - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - /* restore previos pno mode */ - _pno_state->pno_mode = mode; - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - /* restart Legacy PNO Scan */ - struct dhd_pno_legacy_params *_params_legacy; - _params_legacy = - &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!p_ssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, - _params_legacy->scan_fr, _params_legacy->pno_repeat, - _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, - _params_legacy->nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } else if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - /* restart Batching Scan */ - _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); - /* restart BATCH SCAN */ - err = dhd_pno_set_for_batch(dhd, &_params->params_batch); - if (err < 0) { - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } - } else { - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } -exit: - if (p_ssid_list) - kfree(p_ssid_list); - return err; -} - -#ifdef GSCAN_SUPPORT -int -dhd_retreive_batch_scan_results(dhd_pub_t *dhd) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - struct dhd_pno_batch_params *params_batch; - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - - params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; - if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE) { - DHD_PNO(("Retreive batch results\n")); - params_batch->get_batch.buf = NULL; - params_batch->get_batch.bufsize = 0; - params_batch->get_batch.reason = PNO_STATUS_EVENT; - _params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_IN_PROGRESS; - smp_wmb(); - schedule_work(&_pno_state->work); - } else { - DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING retrieval" - "already in progress, will skip\n", __FUNCTION__)); - err = BCME_ERROR; - } - - return err; -} - -void -dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) -{ - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - gscan_results_cache_t *iter, *tmp; - - if (!_pno_state) - return; - - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - - if (type == HOTLIST_FOUND) { - iter = gscan_params->gscan_hotlist_found; - gscan_params->gscan_hotlist_found = NULL; - } else { - iter = gscan_params->gscan_hotlist_lost; - gscan_params->gscan_hotlist_lost = NULL; - } - - while (iter) { - tmp = iter->next; - kfree(iter); - iter = tmp; - } - - return; -} - -void * - -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size) -{ - wl_bss_info_t *bi = NULL; - wl_gscan_result_t *gscan_result; - wifi_gscan_result_t *result = NULL; - u32 bi_length = 0; - uint8 channel; - uint32 mem_needed; - struct timespec ts; - wl_event_gas_t *gas_data; - u32 bi_ie_length = 0; - u32 bi_ie_offset = 0; - - *size = 0; - - gscan_result = (wl_gscan_result_t *)data; - - if (!gscan_result) { - DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); - goto exit; - } -<<<<<<< HEAD - -======= ->>>>>>> 8ee042d1b35b (net: wireless: bcmdhd: Update to 1.71.26) - if ((len < sizeof(*gscan_result)) || - (len < dtoh32(gscan_result->buflen)) || - (dtoh32(gscan_result->buflen) > - (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { - DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__, - dtoh32(gscan_result->buflen))); - goto exit; - } - if (!gscan_result->bss_info) { - DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); - goto exit; - } - bi = &gscan_result->bss_info[0].info; - bi_length = dtoh32(bi->length); - if (bi_length != (dtoh32(gscan_result->buflen) - - WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) { - DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); - goto exit; - } - bi_ie_offset = dtoh32(bi->ie_offset); - bi_ie_length = dtoh32(bi->ie_length); - if ((bi_ie_offset + bi_ie_length) > bi_length) { - DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n", - __FUNCTION__, bi_ie_length, bi_ie_offset)); - goto exit; - } - if (bi->SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s: Invalid SSID length:%u\n", __FUNCTION__, bi->SSID_len)); - goto exit; - } - - mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi_ie_length; - result = kmalloc(mem_needed, GFP_KERNEL); - - if (!result) { - DHD_ERROR(("%s Cannot malloc scan result buffer %d bytes\n", - __FUNCTION__, mem_needed)); - goto exit; - } - - memcpy(result->ssid, bi->SSID, bi->SSID_len); - result->ssid[bi->SSID_len] = '\0'; - channel = wf_chspec_ctlchan(bi->chanspec); - result->channel = wf_channel2mhz(channel, - (channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - result->rssi = (int32) bi->RSSI; - result->rtt = 0; - result->rtt_sd = 0; - get_monotonic_boottime(&ts); - result->ts = (uint64) TIMESPEC_TO_US(ts); - result->beacon_period = dtoh16(bi->beacon_period); - result->capability = dtoh16(bi->capability); - result->ie_length = bi_ie_length; - memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN); - memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length); - *size = mem_needed; -exit: - return result; -} - -void * -dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size) -{ - dhd_epno_results_t *results = NULL; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - uint32 count, mem_needed = 0, i; - uint8 ssid[DOT11_MAX_SSID_LEN + 1]; - struct ether_addr *bssid; - - *size = 0; - if (!_pno_state) - return NULL; - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - - if (event == WLC_E_PFN_SSID_EXT) { - wl_pfn_ssid_ext_result_t *evt_data; - evt_data = (wl_pfn_ssid_ext_result_t *) data; - - if (evt_data->version != PFN_SSID_EXT_VERSION) { - DHD_PNO(("ePNO event: Incorrect version %d %d\n", evt_data->version, - PFN_SSID_EXT_VERSION)); - return NULL; - } - count = evt_data->count; - mem_needed = sizeof(dhd_epno_results_t) * count; - results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); - if (!results) { - DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, - mem_needed)); - return NULL; - } - DHD_ERROR(("Rx'ed WLC_E_PFN_SSID_EXT event: %d results\n", count)); - for (i = 0; i < count; i++) { - results[i].rssi = evt_data->net[i].rssi; - results[i].channel = wf_channel2mhz(evt_data->net[i].channel, - (evt_data->net[i].channel <= CH_MAX_2G_CHANNEL ? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - results[i].flags = evt_data->net[i].flags; - dhd_pno_idx_to_ssid(gscan_params, &results[i], - evt_data->net[i].index); - memcpy(ssid, results[i].ssid, results[i].ssid_len); - bssid = &results[i].bssid; - memcpy(bssid, &evt_data->net[i].bssid, ETHER_ADDR_LEN); - ssid[results[i].ssid_len] = '\0'; - DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " - "idx %d ch %d rssi %d flags %d\n", ssid, - bssid->octet[0], bssid->octet[1], - bssid->octet[2], bssid->octet[3], - bssid->octet[4], bssid->octet[5], - evt_data->net[i].index, results[i].channel, - results[i].rssi, results[i].flags)); - } - } else if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) { - wl_pfn_scanresults_t *pfn_result = (wl_pfn_scanresults_t *)data; - wl_pfn_net_info_t *net; - - if ((pfn_result->count == 0) || - (pfn_result->count > EVENT_MAX_NETCNT)) { - DHD_ERROR(("%s event %d: incorrect results count:%d\n", - __FUNCTION__, event, pfn_result->count)); - return NULL; - } - - if (pfn_result->version != PFN_SCANRESULT_VERSION) { - /* Check if count of pfn results is corrupted */ - if (pfn_result->count > EVENT_MAX_NETCNT) { - DHD_ERROR(("%s event %d: pfn results count %d" - "exceeds the max limit\n", __FUNCTION__, event, pfn_result->count)); - return NULL; - } - DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, - pfn_result->version, PFN_SCANRESULT_VERSION)); - return NULL; - } - count = pfn_result->count; - mem_needed = sizeof(dhd_epno_results_t) * count; - results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); - if (!results) { - DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, - mem_needed)); - return NULL; - } - for (i = 0; i < count; i++) { - net = &pfn_result->netinfo[i]; - results[i].rssi = net->RSSI; - results[i].channel = wf_channel2mhz(net->pfnsubnet.channel, - (net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - results[i].flags = (event == WLC_E_PFN_NET_FOUND) ? - WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST; - results[i].ssid_len = min(net->pfnsubnet.SSID_len, - (uint8)DOT11_MAX_SSID_LEN); - bssid = &results[i].bssid; - memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN); - memcpy(results[i].ssid, net->pfnsubnet.SSID, results[i].ssid_len); - memcpy(ssid, results[i].ssid, results[i].ssid_len); - ssid[results[i].ssid_len] = '\0'; - DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " - "ch %d rssi %d flags %d\n", ssid, - bssid->octet[0], bssid->octet[1], - bssid->octet[2], bssid->octet[3], - bssid->octet[4], bssid->octet[5], - results[i].channel, results[i].rssi, results[i].flags)); - } - } - *size = mem_needed; - return results; -} - - -void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, - hotlist_type_t type) -{ - void *ptr = NULL; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - wl_pfn_scanresults_t *results = (wl_pfn_scanresults_t *)event_data; - wifi_gscan_result_t *hotlist_found_array; - wl_pfn_net_info_t *plnetinfo; - gscan_results_cache_t *gscan_hotlist_cache; - int malloc_size = 0, i, total = 0; - - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - - if ((results->count == 0) || (results->count > EVENT_MAX_NETCNT)) { - DHD_ERROR(("%s: wrong count:%d\n", __FUNCTION__, - results->count)); - *send_evt_bytes = 0; - return ptr; - } - - malloc_size = sizeof(gscan_results_cache_t) + - ((results->count - 1) * sizeof(wifi_gscan_result_t)); - gscan_hotlist_cache = (gscan_results_cache_t *) kmalloc(malloc_size, GFP_KERNEL); - - if (!gscan_hotlist_cache) { - DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size)); - *send_evt_bytes = 0; - return ptr; - } - - if (type == HOTLIST_FOUND) { - gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found; - gscan_params->gscan_hotlist_found = gscan_hotlist_cache; - DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, results->count)); - } else { - gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost; - gscan_params->gscan_hotlist_lost = gscan_hotlist_cache; - DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, results->count)); - } - - gscan_hotlist_cache->tot_count = results->count; - gscan_hotlist_cache->tot_consumed = 0; - plnetinfo = results->netinfo; - - for (i = 0; i < results->count; i++, plnetinfo++) { - hotlist_found_array = &gscan_hotlist_cache->results[i]; - hotlist_found_array->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, - (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - hotlist_found_array->rssi = (int32) plnetinfo->RSSI; - /* Info not available & not expected */ - hotlist_found_array->beacon_period = 0; - hotlist_found_array->capability = 0; - hotlist_found_array->ie_length = 0; - - hotlist_found_array->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); - if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", - plnetinfo->pfnsubnet.SSID_len)); - plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; - } - memcpy(hotlist_found_array->ssid, plnetinfo->pfnsubnet.SSID, - plnetinfo->pfnsubnet.SSID_len); - hotlist_found_array->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; - - memcpy(&hotlist_found_array->macaddr, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); - DHD_PNO(("\t%s %02x:%02x:%02x:%02x:%02x:%02x rssi %d\n", hotlist_found_array->ssid, - hotlist_found_array->macaddr.octet[0], - hotlist_found_array->macaddr.octet[1], - hotlist_found_array->macaddr.octet[2], - hotlist_found_array->macaddr.octet[3], - hotlist_found_array->macaddr.octet[4], - hotlist_found_array->macaddr.octet[5], - hotlist_found_array->rssi)); - } - - - if (results->status == PFN_COMPLETE) { - ptr = (void *) gscan_hotlist_cache; - while (gscan_hotlist_cache) { - total += gscan_hotlist_cache->tot_count; - gscan_hotlist_cache = gscan_hotlist_cache->next; - } - *send_evt_bytes = total * sizeof(wifi_gscan_result_t); - } - - return ptr; -} -#endif /* GSCAN_SUPPORT */ -int -dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) -{ - int err = BCME_OK; - uint status, event_type, flags, datalen; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - event_type = ntoh32(event->event_type); - flags = ntoh16(event->flags); - status = ntoh32(event->status); - datalen = ntoh32(event->datalen); - DHD_PNO(("%s enter : event_type :%d\n", __FUNCTION__, event_type)); - switch (event_type) { - case WLC_E_PFN_BSSID_NET_FOUND: - case WLC_E_PFN_BSSID_NET_LOST: - /* TODO : need to implement event logic using generic netlink */ - break; - case WLC_E_PFN_BEST_BATCHING: -#ifndef GSCAN_SUPPORT - { - struct dhd_pno_batch_params *params_batch; - params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; - if (!waitqueue_active(&_pno_state->get_batch_done.wait)) { - DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); - params_batch->get_batch.buf = NULL; - params_batch->get_batch.bufsize = 0; - params_batch->get_batch.reason = PNO_STATUS_EVENT; - schedule_work(&_pno_state->work); - } else - DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING" - "will skip this event\n", __FUNCTION__)); - break; - } -#else - break; -#endif /* !GSCAN_SUPPORT */ - default: - DHD_ERROR(("unknown event : %d\n", event_type)); - } -exit: - return err; -} - -int dhd_pno_init(dhd_pub_t *dhd) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - UNUSED_PARAMETER(_dhd_pno_suspend); - if (dhd->pno_state) - goto exit; - dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t)); - NULL_CHECK(dhd->pno_state, "failed to create dhd_pno_state", err); - memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t)); - /* need to check whether current firmware support batching and hotlist scan */ - _pno_state = PNO_GET_PNOSTATE(dhd); - _pno_state->wls_supported = TRUE; - _pno_state->dhd = dhd; - mutex_init(&_pno_state->pno_mutex); - INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler); - init_completion(&_pno_state->get_batch_done); -#ifdef GSCAN_SUPPORT - init_waitqueue_head(&_pno_state->batch_get_wait); -#endif /* GSCAN_SUPPORT */ - err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, 0); - if (err == BCME_UNSUPPORTED) { - _pno_state->wls_supported = FALSE; - DHD_INFO(("Current firmware doesn't support" - " Android Location Service\n")); - } -exit: - return err; -} -int dhd_pno_deinit(dhd_pub_t *dhd) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - NULL_CHECK(dhd, "dhd is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - NULL_CHECK(_pno_state, "pno_state is NULL", err); - /* may need to free legacy ssid_list */ - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - _params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; - _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); - } - -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - mutex_lock(&_pno_state->pno_mutex); - dhd_pno_reset_cfg_gscan(_params, _pno_state, GSCAN_FLUSH_ALL_CFG); - mutex_unlock(&_pno_state->pno_mutex); - } -#endif /* GSCAN_SUPPORT */ - - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; - /* clear resource if the BATCH MODE is on */ - _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); - } - cancel_work_sync(&_pno_state->work); - MFREE(dhd->osh, _pno_state, sizeof(dhd_pno_status_info_t)); - dhd->pno_state = NULL; - return err; -} -#endif /* PNO_SUPPORT */ diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h deleted file mode 100644 index dc99441fa47a..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_pno.h +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Header file of Broadcom Dongle Host Driver (DHD) - * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_pno.h 423669 2013-09-18 13:01:55Z $ - */ - -#ifndef __DHD_PNO_H__ -#define __DHD_PNO_H__ - -#if defined(PNO_SUPPORT) -#define PNO_TLV_PREFIX 'S' -#define PNO_TLV_VERSION '1' -#define PNO_TLV_SUBTYPE_LEGACY_PNO '2' -#define PNO_TLV_RESERVED '0' - -#define PNO_BATCHING_SET "SET" -#define PNO_BATCHING_GET "GET" -#define PNO_BATCHING_STOP "STOP" - -#define PNO_PARAMS_DELIMETER " " -#define PNO_PARAM_CHANNEL_DELIMETER "," -#define PNO_PARAM_VALUE_DELLIMETER '=' -#define PNO_PARAM_SCANFREQ "SCANFREQ" -#define PNO_PARAM_BESTN "BESTN" -#define PNO_PARAM_MSCAN "MSCAN" -#define PNO_PARAM_CHANNEL "CHANNEL" -#define PNO_PARAM_RTT "RTT" - -#define PNO_TLV_TYPE_SSID_IE 'S' -#define PNO_TLV_TYPE_TIME 'T' -#define PNO_TLV_FREQ_REPEAT 'R' -#define PNO_TLV_FREQ_EXPO_MAX 'M' - -#define MAXNUM_SSID_PER_ADD 16 -#define MAXNUM_PNO_PARAMS 2 -#define PNO_TLV_COMMON_LENGTH 1 -#define DEFAULT_BATCH_MSCAN 16 - -#define RESULTS_END_MARKER "----\n" -#define SCAN_END_MARKER "####\n" -#define AP_END_MARKER "====\n" -#define PNO_RSSI_MARGIN_DBM 30 - -#ifdef GSCAN_SUPPORT - -#define GSCAN_MAX_CH_BUCKETS 8 -#define GSCAN_MAX_CHANNELS_IN_BUCKET 32 -#define GSCAN_MAX_AP_CACHE_PER_SCAN 32 -#define GSCAN_MAX_AP_CACHE 320 -#define GSCAN_BG_BAND_MASK (1 << 0) -#define GSCAN_A_BAND_MASK (1 << 1) -#define GSCAN_DFS_MASK (1 << 2) -#define GSCAN_ABG_BAND_MASK (GSCAN_A_BAND_MASK | GSCAN_BG_BAND_MASK) -#define GSCAN_BAND_MASK (GSCAN_ABG_BAND_MASK | GSCAN_DFS_MASK) - -#define GSCAN_FLUSH_HOTLIST_CFG (1 << 0) -#define GSCAN_FLUSH_SIGNIFICANT_CFG (1 << 1) -#define GSCAN_FLUSH_SCAN_CFG (1 << 2) -#define GSCAN_FLUSH_EPNO_CFG (1 << 3) -#define GSCAN_FLUSH_ALL_CFG (GSCAN_FLUSH_SCAN_CFG | \ - GSCAN_FLUSH_SIGNIFICANT_CFG | \ - GSCAN_FLUSH_HOTLIST_CFG | \ - GSCAN_FLUSH_EPNO_CFG) -#define DHD_EPNO_HIDDEN_SSID (1 << 0) -#define DHD_EPNO_A_BAND_TRIG (1 << 1) -#define DHD_EPNO_BG_BAND_TRIG (1 << 2) -#define DHD_EPNO_STRICT_MATCH (1 << 3) -#define DHD_PNO_USE_SSID (DHD_EPNO_HIDDEN_SSID | DHD_EPNO_STRICT_MATCH) - -/* Do not change GSCAN_BATCH_RETRIEVAL_COMPLETE */ -#define GSCAN_BATCH_RETRIEVAL_COMPLETE 0 -#define GSCAN_BATCH_RETRIEVAL_IN_PROGRESS 1 -#define GSCAN_BATCH_NO_THR_SET 101 -#define GSCAN_LOST_AP_WINDOW_DEFAULT 4 -#define GSCAN_MIN_BSSID_TIMEOUT 90 -#define GSCAN_BATCH_GET_MAX_WAIT 500 -#define CHANNEL_BUCKET_EMPTY_INDEX 0xFF -#define GSCAN_RETRY_THRESHOLD 3 -#define MAX_EPNO_SSID_NUM 32 - -#endif /* GSCAN_SUPPORT */ - -enum scan_status { - /* SCAN ABORT by other scan */ - PNO_STATUS_ABORT, - /* RTT is presence or not */ - PNO_STATUS_RTT_PRESENCE, - /* Disable PNO by Driver */ - PNO_STATUS_DISABLE, - /* NORMAL BATCHING GET */ - PNO_STATUS_NORMAL, - /* WLC_E_PFN_BEST_BATCHING */ - PNO_STATUS_EVENT, - PNO_STATUS_MAX -}; -#define PNO_STATUS_ABORT_MASK 0x0001 -#define PNO_STATUS_RTT_MASK 0x0002 -#define PNO_STATUS_DISABLE_MASK 0x0004 -#define PNO_STATUS_OOM_MASK 0x0010 - -enum index_mode { - INDEX_OF_LEGACY_PARAMS, - INDEX_OF_BATCH_PARAMS, - INDEX_OF_HOTLIST_PARAMS, - /* GSCAN includes hotlist scan and they do not run - * independent of each other - */ -#ifdef GSCAN_SUPPORT - INDEX_OF_GSCAN_PARAMS = INDEX_OF_HOTLIST_PARAMS, -#endif /* GSCAN_SUPPORT */ - INDEX_MODE_MAX -}; -enum dhd_pno_status { - DHD_PNO_DISABLED, - DHD_PNO_ENABLED, - DHD_PNO_SUSPEND -}; -typedef struct cmd_tlv { - char prefix; - char version; - char subtype; - char reserved; -} cmd_tlv_t; -#ifdef GSCAN_SUPPORT -typedef enum { - WIFI_BAND_UNSPECIFIED, - WIFI_BAND_BG = 1, /* 2.4 GHz */ - WIFI_BAND_A = 2, /* 5 GHz without DFS */ - WIFI_BAND_A_DFS = 4, /* 5 GHz DFS only */ - WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ - WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ - WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ -} gscan_wifi_band_t; - -typedef enum { - HOTLIST_LOST, - HOTLIST_FOUND -} hotlist_type_t; - -typedef enum dhd_pno_gscan_cmd_cfg { - DHD_PNO_BATCH_SCAN_CFG_ID, - DHD_PNO_GEOFENCE_SCAN_CFG_ID, - DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, - DHD_PNO_SCAN_CFG_ID, - DHD_PNO_GET_CAPABILITIES, - DHD_PNO_GET_BATCH_RESULTS, - DHD_PNO_GET_CHANNEL_LIST, - DHD_PNO_GET_EPNO_SSID_ELEM, - DHD_PNO_EPNO_CFG_ID, - DHD_PNO_GET_AUTOJOIN_CAPABILITIES -} dhd_pno_gscan_cmd_cfg_t; - -typedef enum dhd_pno_mode { - /* Wi-Fi Legacy PNO Mode */ - DHD_PNO_NONE_MODE = 0, - DHD_PNO_LEGACY_MODE = (1 << (0)), - /* Wi-Fi Android BATCH SCAN Mode */ - DHD_PNO_BATCH_MODE = (1 << (1)), - /* Wi-Fi Android Hotlist SCAN Mode */ - DHD_PNO_HOTLIST_MODE = (1 << (2)), - /* Wi-Fi Google Android SCAN Mode */ - DHD_PNO_GSCAN_MODE = (1 << (3)) -} dhd_pno_mode_t; -#else -typedef enum dhd_pno_mode { - /* Wi-Fi Legacy PNO Mode */ - DHD_PNO_NONE_MODE = 0, - DHD_PNO_LEGACY_MODE = (1 << (0)), - /* Wi-Fi Android BATCH SCAN Mode */ - DHD_PNO_BATCH_MODE = (1 << (1)), - /* Wi-Fi Android Hotlist SCAN Mode */ - DHD_PNO_HOTLIST_MODE = (1 << (2)) -} dhd_pno_mode_t; -#endif /* GSCAN_SUPPORT */ -struct dhd_pno_ssid { - bool hidden; - int8 rssi_thresh; - uint8 dummy; - uint16 SSID_len; - uchar SSID[DOT11_MAX_SSID_LEN]; - struct list_head list; -}; -struct dhd_pno_bssid { - struct ether_addr macaddr; - /* Bit4: suppress_lost, Bit3: suppress_found */ - uint16 flags; - struct list_head list; -}; -typedef struct dhd_pno_bestnet_entry { - struct ether_addr BSSID; - uint8 SSID_len; - uint8 SSID[DOT11_MAX_SSID_LEN]; - int8 RSSI; - uint8 channel; - uint32 timestamp; - uint16 rtt0; /* distance_cm based on RTT */ - uint16 rtt1; /* distance_cm based on sample standard deviation */ - unsigned long recorded_time; - struct list_head list; -} dhd_pno_bestnet_entry_t; -#define BESTNET_ENTRY_SIZE (sizeof(dhd_pno_bestnet_entry_t)) - -typedef struct dhd_pno_bestnet_header { - struct dhd_pno_bestnet_header *next; - uint8 reason; - uint32 tot_cnt; - uint32 tot_size; - struct list_head entry_list; -} dhd_pno_best_header_t; -#define BEST_HEADER_SIZE (sizeof(dhd_pno_best_header_t)) - -typedef struct dhd_pno_scan_results { - dhd_pno_best_header_t *bestnetheader; - uint8 cnt_header; - struct list_head list; -} dhd_pno_scan_results_t; -#define SCAN_RESULTS_SIZE (sizeof(dhd_pno_scan_results_t)) - -struct dhd_pno_get_batch_info { - /* info related to get batch */ - char *buf; - bool batch_started; - uint32 tot_scan_cnt; - uint32 expired_tot_scan_cnt; - uint32 top_node_cnt; - uint32 bufsize; - uint32 bytes_written; - int reason; - struct list_head scan_results_list; - struct list_head expired_scan_results_list; -}; -struct dhd_pno_legacy_params { - uint16 scan_fr; - uint16 chan_list[WL_NUMCHANNELS]; - uint16 nchan; - int pno_repeat; - int pno_freq_expo_max; - int nssid; - struct list_head ssid_list; -}; -struct dhd_pno_batch_params { - int32 scan_fr; - uint8 bestn; - uint8 mscan; - uint8 band; - uint16 chan_list[WL_NUMCHANNELS]; - uint16 nchan; - uint16 rtt; - struct dhd_pno_get_batch_info get_batch; -}; -struct dhd_pno_hotlist_params { - uint8 band; - int32 scan_fr; - uint16 chan_list[WL_NUMCHANNELS]; - uint16 nchan; - uint16 nbssid; - struct list_head bssid_list; -}; -#ifdef GSCAN_SUPPORT -#define DHD_PNO_REPORT_NO_BATCH (1 << 2) - -typedef struct dhd_pno_gscan_channel_bucket { - uint16 bucket_freq_multiple; - /* band = 1 All bg band channels, - * band = 2 All a band channels, - * band = 0 chan_list channels - */ - uint16 band; - uint8 report_flag; - uint8 num_channels; - uint16 repeat; - uint16 bucket_max_multiple; - uint16 chan_list[GSCAN_MAX_CHANNELS_IN_BUCKET]; -} dhd_pno_gscan_channel_bucket_t; - - -#define DHD_PNO_AUTH_CODE_OPEN 1 /* Open */ -#define DHD_PNO_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ -#define DHD_PNO_AUTH_CODE_EAPOL 4 /* any EAPOL */ - -#define DHD_EPNO_DEFAULT_INDEX 0xFFFFFFFF - -typedef struct dhd_epno_params { - uint8 ssid[DOT11_MAX_SSID_LEN]; - uint8 ssid_len; - int8 rssi_thresh; - uint8 flags; - uint8 auth; - /* index required only for visble ssid */ - uint32 index; - struct list_head list; -} dhd_epno_params_t; - -typedef struct dhd_epno_results { - uint8 ssid[DOT11_MAX_SSID_LEN]; - uint8 ssid_len; - int8 rssi; - uint16 channel; - uint16 flags; - struct ether_addr bssid; -} dhd_epno_results_t; - -struct dhd_pno_swc_evt_param { - uint16 results_rxed_so_far; - wl_pfn_significant_net_t *change_array; -}; - -typedef struct wifi_gscan_result { - uint64 ts; /* Time of discovery */ - char ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated */ - struct ether_addr macaddr; /* BSSID */ - uint32 channel; /* channel frequency in MHz */ - int32 rssi; /* in db */ - uint64 rtt; /* in nanoseconds */ - uint64 rtt_sd; /* standard deviation in rtt */ - uint16 beacon_period; /* units are Kusec */ - uint16 capability; /* Capability information */ - uint32 ie_length; /* byte length of Information Elements */ - char ie_data[1]; /* IE data to follow */ -} wifi_gscan_result_t; - -typedef struct gscan_results_cache { - struct gscan_results_cache *next; - uint8 scan_id; - uint8 flag; - uint8 tot_count; - uint8 tot_consumed; - wifi_gscan_result_t results[1]; -} gscan_results_cache_t; - -typedef struct dhd_pno_gscan_capabilities { - int max_scan_cache_size; - int max_scan_buckets; - int max_ap_cache_per_scan; - int max_rssi_sample_size; - int max_scan_reporting_threshold; - int max_hotlist_bssids; - int max_hotlist_ssids; - int max_significant_wifi_change_aps; - int max_bssid_history_entries; - int max_epno_ssid_crc32; - int max_epno_hidden_ssid; - int max_white_list_ssid; -} dhd_pno_gscan_capabilities_t; - -struct dhd_pno_gscan_params { - int32 scan_fr; - uint8 bestn; - uint8 mscan; - uint8 buffer_threshold; - uint8 swc_nbssid_threshold; - uint8 swc_rssi_window_size; - uint8 lost_ap_window; - uint8 nchannel_buckets; - uint8 reason; - uint8 get_batch_flag; - uint8 send_all_results_flag; - uint16 max_ch_bucket_freq; - gscan_results_cache_t *gscan_batch_cache; - gscan_results_cache_t *gscan_hotlist_found; - gscan_results_cache_t *gscan_hotlist_lost; - uint16 nbssid_significant_change; - uint16 nbssid_hotlist; - uint16 num_epno_ssid; - uint8 num_visible_epno_ssid; - /* To keep track of visble ssid index - * across multiple FW configs i.e. config - * w/o clear in between - */ - uint8 ssid_ext_last_used_index; - struct dhd_pno_swc_evt_param param_significant; - struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; - struct list_head hotlist_bssid_list; - struct list_head significant_bssid_list; - struct list_head epno_ssid_list; - uint32 scan_id; -}; - -typedef struct gscan_scan_params { - int32 scan_fr; - uint16 nchannel_buckets; - struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; -} gscan_scan_params_t; - -typedef struct gscan_batch_params { - uint8 bestn; - uint8 mscan; - uint8 buffer_threshold; -} gscan_batch_params_t; - -struct bssid_t { - struct ether_addr macaddr; - int16 rssi_reporting_threshold; /* 0 -> no reporting threshold */ -}; - -typedef struct gscan_hotlist_scan_params { - uint16 lost_ap_window; /* number of scans to declare LOST */ - uint16 nbssid; /* number of bssids */ - struct bssid_t bssid[1]; /* n bssids to follow */ -} gscan_hotlist_scan_params_t; - -#endif /* GSCAN_SUPPORT */ -typedef union dhd_pno_params { - struct dhd_pno_legacy_params params_legacy; - struct dhd_pno_batch_params params_batch; - struct dhd_pno_hotlist_params params_hotlist; -#ifdef GSCAN_SUPPORT - struct dhd_pno_gscan_params params_gscan; -#endif /* GSCAN_SUPPORT */ -} dhd_pno_params_t; -typedef struct dhd_pno_status_info { - dhd_pub_t *dhd; - struct work_struct work; - struct mutex pno_mutex; -#ifdef GSCAN_SUPPORT - wait_queue_head_t batch_get_wait; -#endif /* GSCAN_SUPPORT */ - struct completion get_batch_done; - bool wls_supported; /* wifi location service supported or not */ - enum dhd_pno_status pno_status; - enum dhd_pno_mode pno_mode; - dhd_pno_params_t pno_params_arr[INDEX_MODE_MAX]; - struct list_head head_list; -} dhd_pno_status_info_t; - -/* wrapper functions */ -extern int -dhd_dev_pno_enable(struct net_device *dev, int enable); - -extern int -dhd_dev_pno_stop_for_ssid(struct net_device *dev); - -extern int -dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, - uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); - -extern int -dhd_dev_pno_set_for_batch(struct net_device *dev, - struct dhd_pno_batch_params *batch_params); - -extern int -dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize); - -extern int -dhd_dev_pno_stop_for_batch(struct net_device *dev); - -extern int -dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, - struct dhd_pno_hotlist_params *hotlist_params); -extern bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev); -#ifdef GSCAN_SUPPORT -extern int -dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, - void *buf, uint8 flush); -extern void * -dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, void *info, - uint32 *len); -int dhd_dev_pno_lock_access_batch_results(struct net_device *dev); -void dhd_dev_pno_unlock_access_batch_results(struct net_device *dev); -extern int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush); -extern int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time); -int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); -extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, - const void *data, int *send_evt_bytes, hotlist_type_t type); -void * dhd_dev_process_full_gscan_result(struct net_device *dev, - const void *data, uint32 len, int *send_evt_bytes); -extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); -extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); -extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); -extern void * dhd_dev_process_epno_result(struct net_device *dev, - const void *data, uint32 event, int *send_evt_bytes); -#endif /* GSCAN_SUPPORT */ -/* dhd pno fuctions */ -extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd); -extern int dhd_pno_enable(dhd_pub_t *dhd, int enable); -extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, - uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); - -extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params); - -extern int dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason); - - -extern int dhd_pno_stop_for_batch(dhd_pub_t *dhd); - -extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, - struct dhd_pno_hotlist_params *hotlist_params); - -extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd); - -extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); -extern int dhd_pno_init(dhd_pub_t *dhd); -extern int dhd_pno_deinit(dhd_pub_t *dhd); -extern bool dhd_is_pno_supported(dhd_pub_t *dhd); -extern int dhd_pno_set_mac_oui(dhd_pub_t *dhd, uint8 *oui); -extern bool dhd_is_legacy_pno_enabled(dhd_pub_t *dhd); -#ifdef GSCAN_SUPPORT -extern int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, - void *buf, uint8 flush); -extern void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *info, - uint32 *len); -extern int dhd_pno_lock_batch_results(dhd_pub_t *dhd); -extern void dhd_pno_unlock_batch_results(dhd_pub_t *dhd); -extern int dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush); -extern int dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag); -extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *buf); -extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); -extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, - int *send_evt_bytes, hotlist_type_t type); -extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, - uint32 len, int *send_evt_bytes); -extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); -extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); -extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); -extern void * dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, - uint32 event, int *size); -#endif /* GSCAN_SUPPORT */ -#endif - -#endif /* __DHD_PNO_H__ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_proto.h b/drivers/net/wireless/bcmdhd/dhd_proto.h deleted file mode 100644 index b7299dee3e47..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_proto.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_proto.h 574949 2015-07-28 13:02:30Z $ - */ - -#ifndef _dhd_proto_h_ -#define _dhd_proto_h_ - -#include -#include -#ifdef BCMPCIE -#include -#endif - -#define DEFAULT_IOCTL_RESP_TIMEOUT 2000 -#ifndef IOCTL_RESP_TIMEOUT -/* In milli second default value for Production FW */ -#define IOCTL_RESP_TIMEOUT DEFAULT_IOCTL_RESP_TIMEOUT -#endif /* IOCTL_RESP_TIMEOUT */ - -#ifndef MFG_IOCTL_RESP_TIMEOUT -#define MFG_IOCTL_RESP_TIMEOUT 20000 /* In milli second default value for MFG FW */ -#endif /* MFG_IOCTL_RESP_TIMEOUT */ - -#define DEFAULT_D3_ACK_RESP_TIMEOUT 4000 -#ifndef D3_ACK_RESP_TIMEOUT -#define D3_ACK_RESP_TIMEOUT DEFAULT_D3_ACK_RESP_TIMEOUT -#endif /* D3_ACK_RESP_TIMEOUT */ - -/* - * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) - */ - -/* Linkage, sets prot link and updates hdrlen in pub */ -extern int dhd_prot_attach(dhd_pub_t *dhdp); - -/* Initilizes the index block for dma'ing indices */ -extern int dhd_prot_init_index_dma_block(dhd_pub_t *dhdp, uint8 type, uint32 length); - -/* Unlink, frees allocated protocol memory (including dhd_prot) */ -extern void dhd_prot_detach(dhd_pub_t *dhdp); - -/* Initialize protocol: sync w/dongle state. - * Sets dongle media info (iswl, drv_version, mac address). - */ -extern int dhd_sync_with_dongle(dhd_pub_t *dhdp); - -/* Protocol initialization needed for IOCTL/IOVAR path */ -extern int dhd_prot_init(dhd_pub_t *dhd); - -/* Stop protocol: sync w/dongle state. */ -extern void dhd_prot_stop(dhd_pub_t *dhdp); - -/* Add any protocol-specific data header. - * Caller must reserve prot_hdrlen prepend space. - */ -extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); -extern uint dhd_prot_hdrlen(dhd_pub_t *, void *txp); - -/* Remove any protocol-specific data header. */ -extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); - -/* Use protocol to issue ioctl to dongle */ -extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); - -/* Handles a protocol control response asynchronously */ -extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); - -/* Check for and handle local prot-specific iovar commands */ -extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Add prot dump output to a buffer */ -extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); - -/* Update local copy of dongle statistics */ -extern void dhd_prot_dstats(dhd_pub_t *dhdp); - -extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); - -extern int dhd_preinit_ioctls(dhd_pub_t *dhd); - -extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, - uint reorder_info_len, void **pkt, uint32 *free_buf_count); - -#ifdef BCMPCIE -extern bool dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound); -extern bool dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound); -extern int dhd_prot_process_ctrlbuf(dhd_pub_t * dhd); -extern bool dhd_prot_dtohsplit(dhd_pub_t * dhd); -extern int dhd_post_dummy_msg(dhd_pub_t *dhd); -extern int dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len); -extern void dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 offset); -extern int dhd_prot_txdata(dhd_pub_t *dhd, void *p, uint8 ifidx); -extern int dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd, uint len, uint srcdelay, uint destdelay); - -extern int dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); -extern void dhd_prot_clean_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info); -extern int dhd_post_tx_ring_item(dhd_pub_t *dhd, void *PKTBUF, uint8 ifindex); -extern int dhd_prot_flow_ring_delete(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); -extern int dhd_prot_flow_ring_flush(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); -extern int dhd_prot_ringupd_dump(dhd_pub_t *dhd, struct bcmstrbuf *b); -extern uint32 dhd_prot_metadatalen_set(dhd_pub_t *dhd, uint32 val, bool rx); -extern uint32 dhd_prot_metadatalen_get(dhd_pub_t *dhd, bool rx); -extern void dhd_prot_print_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info, - struct bcmstrbuf *strbuf); -extern void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf); -extern void dhd_prot_update_txflowring(dhd_pub_t *dhdp, uint16 flow_id, void *msgring_info); -extern void dhd_prot_txdata_write_flush(dhd_pub_t *dhd, uint16 flow_id, bool in_lock); -extern uint32 dhd_prot_txp_threshold(dhd_pub_t *dhd, bool set, uint32 val); -extern void dhd_prot_clear(dhd_pub_t *dhd); - -#endif /* BCMPCIE */ - -/******************************** - * For version-string expansion * - */ -#if defined(BDC) -#define DHD_PROTOCOL "bdc" -#elif defined(CDC) -#define DHD_PROTOCOL "cdc" -#else -#define DHD_PROTOCOL "unknown" -#endif /* proto */ - -#endif /* _dhd_proto_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_rtt.c b/drivers/net/wireless/bcmdhd/dhd_rtt.c deleted file mode 100644 index 23e712aef69e..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_rtt.c +++ /dev/null @@ -1,2015 +0,0 @@ -/* - * Header file of Broadcom Dongle Host Driver (DHD) - * Copyright (C) 1999-2014, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_rtt.c 423669 2014-07-01 13:01:55Z $ - */ -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#define GET_RTTSTATE(dhd) ((rtt_status_info_t *)dhd->rtt_state) -static DEFINE_SPINLOCK(noti_list_lock); -#define NULL_CHECK(p, s, err) \ - do { \ - if (!(p)) { \ - printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ - err = BCME_ERROR; \ - return err; \ - } \ - } while (0) - -#define RTT_IS_ENABLED(rtt_status) (rtt_status->status == RTT_ENABLED) -#define RTT_IS_STOPPED(rtt_status) (rtt_status->status == RTT_STOPPED) -#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ - (ts).tv_nsec / NSEC_PER_USEC) - -#define FTM_IOC_BUFSZ 2048 /* ioc buffsize for our module (> BCM_XTLV_HDR_SIZE) */ -#define FTM_AVAIL_MAX_SLOTS 32 -#define FTM_MAX_CONFIGS 10 -#define FTM_MAX_PARAMS 10 -#define FTM_DEFAULT_SESSION 1 -#define FTM_BURST_TIMEOUT_UNIT 250 /* 250 ns */ -#define FTM_INVALID -1 -#define FTM_DEFAULT_CNT_20M 12 -#define FTM_DEFAULT_CNT_40M 10 -#define FTM_DEFAULT_CNT_80M 5 - -/* convenience macros */ -#define FTM_TU2MICRO(_tu) ((uint64)(_tu) << 10) -#define FTM_MICRO2TU(_tu) ((uint64)(_tu) >> 10) -#define FTM_TU2MILLI(_tu) ((uint32)FTM_TU2MICRO(_tu) / 1000) -#define FTM_MICRO2MILLI(_x) ((uint32)(_x) / 1000) -#define FTM_MICRO2SEC(_x) ((uint32)(_x) / 1000000) -#define FTM_INTVL2NSEC(_intvl) ((uint32)ftm_intvl2nsec(_intvl)) -#define FTM_INTVL2USEC(_intvl) ((uint32)ftm_intvl2usec(_intvl)) -#define FTM_INTVL2MSEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000) -#define FTM_INTVL2SEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000000) -#define FTM_USECIN100MILLI(_usec) ((_usec) / 100000) - -/* broadcom specific set to have more accurate data */ -#define ENABLE_VHT_ACK - -struct rtt_noti_callback { - struct list_head list; - void *ctx; - dhd_rtt_compl_noti_fn noti_fn; -}; - -typedef struct rtt_status_info { - dhd_pub_t *dhd; - int8 status; /* current status for the current entry */ - int8 txchain; /* current device tx chain */ - int8 mpc; /* indicate we change mpc mode */ - int8 cur_idx; /* current entry to do RTT */ - struct capability { - int32 proto :8; - int32 feature :8; - int32 preamble :8; - int32 bw :8; - } rtt_capa; /* rtt capability */ - struct mutex rtt_mutex; - rtt_config_params_t rtt_config; - struct work_struct work; - struct list_head noti_fn_list; - struct list_head rtt_results_cache; /* store results for RTT */ -} rtt_status_info_t; - -/* bitmask indicating which command groups; */ -typedef enum { - FTM_SUBCMD_FLAG_METHOD = 0x01, /* FTM method command */ - FTM_SUBCMD_FLAG_SESSION = 0x02, /* FTM session command */ - FTM_SUBCMD_FLAG_ALL = FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION -} ftm_subcmd_flag_t; - -/* proxd ftm config-category definition */ -typedef enum { - FTM_CONFIG_CAT_GENERAL = 1, /* generial configuration */ - FTM_CONFIG_CAT_OPTIONS = 2, /* 'config options' */ - FTM_CONFIG_CAT_AVAIL = 3, /* 'config avail' */ -} ftm_config_category_t; - - -typedef struct ftm_subcmd_info { - int16 version; /* FTM version (optional) */ - char *name; /* cmd-name string as cmdline input */ - wl_proxd_cmd_t cmdid; /* cmd-id */ - bcm_xtlv_unpack_cbfn_t *handler; /* cmd response handler (optional) */ - ftm_subcmd_flag_t cmdflag; /* CMD flag (optional) */ -} ftm_subcmd_info_t; - - -typedef struct ftm_config_options_info { - uint32 flags; /* wl_proxd_flags_t/wl_proxd_session_flags_t */ - bool enable; -} ftm_config_options_info_t; - -typedef struct ftm_config_param_info { - uint16 tlvid; /* mapping TLV id for the item */ - union { - uint32 chanspec; - struct ether_addr mac_addr; - wl_proxd_intvl_t data_intvl; - uint32 data32; - uint16 data16; - uint8 data8; - }; -} ftm_config_param_info_t; - -/* -* definition for id-string mapping. -* This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string -* for debug-display or cmd-log-display -*/ -typedef struct ftm_strmap_entry { - int32 id; - char *text; -} ftm_strmap_entry_t; - - -typedef struct ftm_status_map_host_entry { - wl_proxd_status_t proxd_status; - rtt_reason_t rtt_reason; -} ftm_status_map_host_entry_t; - -static int -dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len); - -static wifi_rate_t -dhd_rtt_convert_rate_to_host(uint32 ratespec); - -static int -dhd_rtt_start(dhd_pub_t *dhd); - -/* ftm status mapping to host status */ -static const ftm_status_map_host_entry_t ftm_status_map_info[] = { - {WL_PROXD_E_INCOMPLETE, RTT_REASON_FAILURE}, - {WL_PROXD_E_OVERRIDDEN, RTT_REASON_FAILURE}, - {WL_PROXD_E_ASAP_FAILED, RTT_REASON_FAILURE}, - {WL_PROXD_E_NOTSTARTED, RTT_REASON_FAIL_NOT_SCHEDULED_YET}, - {WL_PROXD_E_INVALIDAVB, RTT_REASON_FAIL_INVALID_TS}, - {WL_PROXD_E_INCAPABLE, RTT_REASON_FAIL_NO_CAPABILITY}, - {WL_PROXD_E_MISMATCH, RTT_REASON_FAILURE}, - {WL_PROXD_E_DUP_SESSION, RTT_REASON_FAILURE}, - {WL_PROXD_E_REMOTE_FAIL, RTT_REASON_FAILURE}, - {WL_PROXD_E_REMOTE_INCAPABLE, RTT_REASON_FAILURE}, - {WL_PROXD_E_SCHED_FAIL, RTT_REASON_FAIL_SCHEDULE}, - {WL_PROXD_E_PROTO, RTT_REASON_FAIL_PROTOCOL}, - {WL_PROXD_E_EXPIRED, RTT_REASON_FAILURE}, - {WL_PROXD_E_TIMEOUT, RTT_REASON_FAIL_TM_TIMEOUT}, - {WL_PROXD_E_NOACK, RTT_REASON_FAIL_NO_RSP}, - {WL_PROXD_E_DEFERRED, RTT_REASON_FAILURE}, - {WL_PROXD_E_INVALID_SID, RTT_REASON_FAILURE}, - {WL_PROXD_E_REMOTE_CANCEL, RTT_REASON_FAILURE}, - {WL_PROXD_E_CANCELED, RTT_REASON_ABORTED}, - {WL_PROXD_E_INVALID_SESSION, RTT_REASON_FAILURE}, - {WL_PROXD_E_BAD_STATE, RTT_REASON_FAILURE}, - {WL_PROXD_E_ERROR, RTT_REASON_FAILURE}, - {WL_PROXD_E_OK, RTT_REASON_SUCCESS} -}; - -/* ftm tlv-id mapping */ -static const ftm_strmap_entry_t ftm_tlvid_loginfo[] = { - /* { WL_PROXD_TLV_ID_xxx, "text for WL_PROXD_TLV_ID_xxx" }, */ - { WL_PROXD_TLV_ID_NONE, "none" }, - { WL_PROXD_TLV_ID_METHOD, "method" }, - { WL_PROXD_TLV_ID_FLAGS, "flags" }, - { WL_PROXD_TLV_ID_CHANSPEC, "chanspec" }, - { WL_PROXD_TLV_ID_TX_POWER, "tx power" }, - { WL_PROXD_TLV_ID_RATESPEC, "ratespec" }, - { WL_PROXD_TLV_ID_BURST_DURATION, "burst duration" }, - { WL_PROXD_TLV_ID_BURST_PERIOD, "burst period" }, - { WL_PROXD_TLV_ID_BURST_FTM_SEP, "burst ftm sep" }, - { WL_PROXD_TLV_ID_BURST_NUM_FTM, "burst num ftm" }, - { WL_PROXD_TLV_ID_NUM_BURST, "num burst" }, - { WL_PROXD_TLV_ID_FTM_RETRIES, "ftm retries" }, - { WL_PROXD_TLV_ID_BSS_INDEX, "BSS index" }, - { WL_PROXD_TLV_ID_BSSID, "bssid" }, - { WL_PROXD_TLV_ID_INIT_DELAY, "burst init delay" }, - { WL_PROXD_TLV_ID_BURST_TIMEOUT, "burst timeout" }, - { WL_PROXD_TLV_ID_EVENT_MASK, "event mask" }, - { WL_PROXD_TLV_ID_FLAGS_MASK, "flags mask" }, - { WL_PROXD_TLV_ID_PEER_MAC, "peer addr" }, - { WL_PROXD_TLV_ID_FTM_REQ, "ftm req" }, - { WL_PROXD_TLV_ID_LCI_REQ, "lci req" }, - { WL_PROXD_TLV_ID_LCI, "lci" }, - { WL_PROXD_TLV_ID_CIVIC_REQ, "civic req" }, - { WL_PROXD_TLV_ID_CIVIC, "civic" }, - { WL_PROXD_TLV_ID_AVAIL, "availability" }, - { WL_PROXD_TLV_ID_SESSION_FLAGS, "session flags" }, - { WL_PROXD_TLV_ID_SESSION_FLAGS_MASK, "session flags mask" }, - { WL_PROXD_TLV_ID_RX_MAX_BURST, "rx max bursts" }, - { WL_PROXD_TLV_ID_RANGING_INFO, "ranging info" }, - { WL_PROXD_TLV_ID_RANGING_FLAGS, "ranging flags" }, - { WL_PROXD_TLV_ID_RANGING_FLAGS_MASK, "ranging flags mask" }, - /* output - 512 + x */ - { WL_PROXD_TLV_ID_STATUS, "status" }, - { WL_PROXD_TLV_ID_COUNTERS, "counters" }, - { WL_PROXD_TLV_ID_INFO, "info" }, - { WL_PROXD_TLV_ID_RTT_RESULT, "rtt result" }, - { WL_PROXD_TLV_ID_AOA_RESULT, "aoa result" }, - { WL_PROXD_TLV_ID_SESSION_INFO, "session info" }, - { WL_PROXD_TLV_ID_SESSION_STATUS, "session status" }, - { WL_PROXD_TLV_ID_SESSION_ID_LIST, "session ids" }, - /* debug tlvs can be added starting 1024 */ - { WL_PROXD_TLV_ID_DEBUG_MASK, "debug mask" }, - { WL_PROXD_TLV_ID_COLLECT, "collect" }, - { WL_PROXD_TLV_ID_STRBUF, "result" } -}; - -static const ftm_strmap_entry_t ftm_event_type_loginfo[] = { - /* wl_proxd_event_type_t, text-string */ - { WL_PROXD_EVENT_NONE, "none" }, - { WL_PROXD_EVENT_SESSION_CREATE, "session create" }, - { WL_PROXD_EVENT_SESSION_START, "session start" }, - { WL_PROXD_EVENT_FTM_REQ, "FTM req" }, - { WL_PROXD_EVENT_BURST_START, "burst start" }, - { WL_PROXD_EVENT_BURST_END, "burst end" }, - { WL_PROXD_EVENT_SESSION_END, "session end" }, - { WL_PROXD_EVENT_SESSION_RESTART, "session restart" }, - { WL_PROXD_EVENT_BURST_RESCHED, "burst rescheduled" }, - { WL_PROXD_EVENT_SESSION_DESTROY, "session destroy" }, - { WL_PROXD_EVENT_RANGE_REQ, "range request" }, - { WL_PROXD_EVENT_FTM_FRAME, "FTM frame" }, - { WL_PROXD_EVENT_DELAY, "delay" }, - { WL_PROXD_EVENT_VS_INITIATOR_RPT, "initiator-report " }, /* rx initiator-rpt */ - { WL_PROXD_EVENT_RANGING, "ranging " }, -}; - -/* -* session-state --> text string mapping -*/ -static const ftm_strmap_entry_t ftm_session_state_value_loginfo[] = { - /* wl_proxd_session_state_t, text string */ - { WL_PROXD_SESSION_STATE_CREATED, "created" }, - { WL_PROXD_SESSION_STATE_CONFIGURED, "configured" }, - { WL_PROXD_SESSION_STATE_STARTED, "started" }, - { WL_PROXD_SESSION_STATE_DELAY, "delay" }, - { WL_PROXD_SESSION_STATE_USER_WAIT, "user-wait" }, - { WL_PROXD_SESSION_STATE_SCHED_WAIT, "sched-wait" }, - { WL_PROXD_SESSION_STATE_BURST, "burst" }, - { WL_PROXD_SESSION_STATE_STOPPING, "stopping" }, - { WL_PROXD_SESSION_STATE_ENDED, "ended" }, - { WL_PROXD_SESSION_STATE_DESTROYING, "destroying" }, - { WL_PROXD_SESSION_STATE_NONE, "none" } -}; - -/* -* ranging-state --> text string mapping -*/ -static const ftm_strmap_entry_t ftm_ranging_state_value_loginfo [] = { - /* wl_proxd_ranging_state_t, text string */ - { WL_PROXD_RANGING_STATE_NONE, "none" }, - { WL_PROXD_RANGING_STATE_NOTSTARTED, "nonstarted" }, - { WL_PROXD_RANGING_STATE_INPROGRESS, "inprogress" }, - { WL_PROXD_RANGING_STATE_DONE, "done" }, -}; - -/* -* status --> text string mapping -*/ -static const ftm_strmap_entry_t ftm_status_value_loginfo[] = { - /* wl_proxd_status_t, text-string */ - { WL_PROXD_E_OVERRIDDEN, "overridden" }, - { WL_PROXD_E_ASAP_FAILED, "ASAP failed" }, - { WL_PROXD_E_NOTSTARTED, "not started" }, - { WL_PROXD_E_INVALIDAVB, "invalid AVB" }, - { WL_PROXD_E_INCAPABLE, "incapable" }, - { WL_PROXD_E_MISMATCH, "mismatch"}, - { WL_PROXD_E_DUP_SESSION, "dup session" }, - { WL_PROXD_E_REMOTE_FAIL, "remote fail" }, - { WL_PROXD_E_REMOTE_INCAPABLE, "remote incapable" }, - { WL_PROXD_E_SCHED_FAIL, "sched failure" }, - { WL_PROXD_E_PROTO, "protocol error" }, - { WL_PROXD_E_EXPIRED, "expired" }, - { WL_PROXD_E_TIMEOUT, "timeout" }, - { WL_PROXD_E_NOACK, "no ack" }, - { WL_PROXD_E_DEFERRED, "deferred" }, - { WL_PROXD_E_INVALID_SID, "invalid session id" }, - { WL_PROXD_E_REMOTE_CANCEL, "remote cancel" }, - { WL_PROXD_E_CANCELED, "canceled" }, - { WL_PROXD_E_INVALID_SESSION, "invalid session" }, - { WL_PROXD_E_BAD_STATE, "bad state" }, - { WL_PROXD_E_ERROR, "error" }, - { WL_PROXD_E_OK, "OK" } -}; - -/* -* time interval unit --> text string mapping -*/ -static const ftm_strmap_entry_t ftm_tmu_value_loginfo[] = { - /* wl_proxd_tmu_t, text-string */ - { WL_PROXD_TMU_TU, "TU" }, - { WL_PROXD_TMU_SEC, "sec" }, - { WL_PROXD_TMU_MILLI_SEC, "ms" }, - { WL_PROXD_TMU_MICRO_SEC, "us" }, - { WL_PROXD_TMU_NANO_SEC, "ns" }, - { WL_PROXD_TMU_PICO_SEC, "ps" } -}; - -#define RSPEC_BW(rspec) ((rspec) & WL_RSPEC_BW_MASK) -#define RSPEC_IS20MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_20MHZ) -#define RSPEC_IS40MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_40MHZ) -#define RSPEC_IS80MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_80MHZ) -#define RSPEC_IS160MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_160MHZ) - -#define IS_MCS(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) != WL_RSPEC_ENCODE_RATE) -#define IS_STBC(rspec) (((((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) || \ - (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)) && \ - (((rspec) & WL_RSPEC_STBC) == WL_RSPEC_STBC)) -#define RSPEC_ISSGI(rspec) (((rspec) & WL_RSPEC_SGI) != 0) -#define RSPEC_ISLDPC(rspec) (((rspec) & WL_RSPEC_LDPC) != 0) -#define RSPEC_ISSTBC(rspec) (((rspec) & WL_RSPEC_STBC) != 0) -#define RSPEC_ISTXBF(rspec) (((rspec) & WL_RSPEC_TXBF) != 0) -#define RSPEC_ISVHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) -#define RSPEC_ISHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) -#define RSPEC_ISLEGACY(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) -#define RSPEC2RATE(rspec) (RSPEC_ISLEGACY(rspec) ? \ - ((rspec) & RSPEC_RATE_MASK) : rate_rspec2rate(rspec)) -/* return rate in unit of 500Kbps -- for internal use in wlc_rate_sel.c */ -#define RSPEC2KBPS(rspec) rate_rspec2rate(rspec) - -struct ieee_80211_mcs_rate_info { - uint8 constellation_bits; - uint8 coding_q; - uint8 coding_d; -}; - -static const struct ieee_80211_mcs_rate_info wl_mcs_info[] = { - { 1, 1, 2 }, /* MCS 0: MOD: BPSK, CR 1/2 */ - { 2, 1, 2 }, /* MCS 1: MOD: QPSK, CR 1/2 */ - { 2, 3, 4 }, /* MCS 2: MOD: QPSK, CR 3/4 */ - { 4, 1, 2 }, /* MCS 3: MOD: 16QAM, CR 1/2 */ - { 4, 3, 4 }, /* MCS 4: MOD: 16QAM, CR 3/4 */ - { 6, 2, 3 }, /* MCS 5: MOD: 64QAM, CR 2/3 */ - { 6, 3, 4 }, /* MCS 6: MOD: 64QAM, CR 3/4 */ - { 6, 5, 6 }, /* MCS 7: MOD: 64QAM, CR 5/6 */ - { 8, 3, 4 }, /* MCS 8: MOD: 256QAM, CR 3/4 */ - { 8, 5, 6 } /* MCS 9: MOD: 256QAM, CR 5/6 */ -}; - -/** - * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination. - * 'mcs' : a *single* spatial stream MCS (11n or 11ac) - */ -uint -rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) -{ - const int ksps = 250; /* kilo symbols per sec, 4 us sym */ - const int Nsd_20MHz = 52; - const int Nsd_40MHz = 108; - const int Nsd_80MHz = 234; - const int Nsd_160MHz = 468; - uint rate; - - if (mcs == 32) { - /* just return fixed values for mcs32 instead of trying to parametrize */ - rate = (sgi == 0) ? 6000 : 6778; - } else if (mcs <= 9) { - /* This calculation works for 11n HT and 11ac VHT if the HT mcs values - * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. - * That is, HT MCS 23 is a base MCS = 7, Nss = 3 - */ - - /* find the number of complex numbers per symbol */ - if (RSPEC_IS20MHZ(bw)) { - rate = Nsd_20MHz; - } else if (RSPEC_IS40MHZ(bw)) { - rate = Nsd_40MHz; - } else if (bw == WL_RSPEC_BW_80MHZ) { - rate = Nsd_80MHz; - } else if (bw == WL_RSPEC_BW_160MHZ) { - rate = Nsd_160MHz; - } else { - rate = 0; - } - - /* multiply by bits per number from the constellation in use */ - rate = rate * wl_mcs_info[mcs].constellation_bits; - - /* adjust for the number of spatial streams */ - rate = rate * nss; - - /* adjust for the coding rate given as a quotient and divisor */ - rate = (rate * wl_mcs_info[mcs].coding_q) / wl_mcs_info[mcs].coding_d; - - /* multiply by Kilo symbols per sec to get Kbps */ - rate = rate * ksps; - - /* adjust the symbols per sec for SGI - * symbol duration is 4 us without SGI, and 3.6 us with SGI, - * so ratio is 10 / 9 - */ - if (sgi) { - /* add 4 for rounding of division by 9 */ - rate = ((rate * 10) + 4) / 9; - } - } else { - rate = 0; - } - - return rate; -} /* wlc_rate_mcs2rate */ - -/** take a well formed ratespec_t arg and return phy rate in [Kbps] units */ -int -rate_rspec2rate(uint32 rspec) -{ - int rate = 0; - - if (RSPEC_ISLEGACY(rspec)) { - rate = 500 * (rspec & WL_RSPEC_RATE_MASK); - } else if (RSPEC_ISHT(rspec)) { - uint mcs = (rspec & WL_RSPEC_RATE_MASK); - - if (mcs == 32) { - rate = rate_mcs2rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec)); - } else { - uint nss = 1 + (mcs / 8); - mcs = mcs % 8; - rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); - } - } else if (RSPEC_ISVHT(rspec)) { - uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK); - uint nss = (rspec & WL_RSPEC_VHT_MCS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; - - ASSERT(mcs <= 9); - ASSERT(nss <= 8); - - rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); - } else { - ASSERT(0); - } - - return rate; -} - -char resp_buf[WLC_IOCTL_SMLEN]; - -static uint64 -ftm_intvl2nsec(const wl_proxd_intvl_t *intvl) -{ - uint64 ret; - ret = intvl->intvl; - switch (intvl->tmu) { - case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret) * 1000; break; - case WL_PROXD_TMU_SEC: ret *= 1000000000; break; - case WL_PROXD_TMU_MILLI_SEC: ret *= 1000000; break; - case WL_PROXD_TMU_MICRO_SEC: ret *= 1000; break; - case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000; break; - case WL_PROXD_TMU_NANO_SEC: /* fall through */ - default: break; - } - return ret; -} -uint64 -ftm_intvl2usec(const wl_proxd_intvl_t *intvl) -{ - uint64 ret; - ret = intvl->intvl; - switch (intvl->tmu) { - case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret); break; - case WL_PROXD_TMU_SEC: ret *= 1000000; break; - case WL_PROXD_TMU_NANO_SEC: ret = intvl->intvl / 1000; break; - case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000000; break; - case WL_PROXD_TMU_MILLI_SEC: ret *= 1000; break; - case WL_PROXD_TMU_MICRO_SEC: /* fall through */ - default: break; - } - return ret; -} - -/* -* lookup 'id' (as a key) from a fw status to host map table -* if found, return the corresponding reason code -*/ - -static rtt_reason_t -ftm_get_statusmap_info(wl_proxd_status_t id, const ftm_status_map_host_entry_t *p_table, - uint32 num_entries) -{ - int i; - const ftm_status_map_host_entry_t *p_entry; - /* scan thru the table till end */ - p_entry = p_table; - for (i = 0; i < (int) num_entries; i++) - { - if (p_entry->proxd_status == id) { - return p_entry->rtt_reason; - } - p_entry++; /* next entry */ - } - return RTT_REASON_FAILURE; /* not found */ -} -/* -* lookup 'id' (as a key) from a table -* if found, return the entry pointer, otherwise return NULL -*/ -static const ftm_strmap_entry_t* -ftm_get_strmap_info(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) -{ - int i; - const ftm_strmap_entry_t *p_entry; - - /* scan thru the table till end */ - p_entry = p_table; - for (i = 0; i < (int) num_entries; i++) - { - if (p_entry->id == id) - return p_entry; - p_entry++; /* next entry */ - } - return NULL; /* not found */ -} - -/* -* map enum to a text-string for display, this function is called by the following: -* For debug/trace: -* ftm_[cmdid|tlvid]_to_str() -* For TLV-output log for 'get' commands -* ftm_[method|tmu|caps|status|state]_value_to_logstr() -* Input: -* pTable -- point to a 'enum to string' table. -*/ -static const char * -ftm_map_id_to_str(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) -{ - const ftm_strmap_entry_t*p_entry = ftm_get_strmap_info(id, p_table, num_entries); - if (p_entry) - return (p_entry->text); - - return "invalid"; -} - - -#ifdef RTT_DEBUG - -/* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */ -#define DEF_STRMAP_ENTRY(id) { (id), #id } - -/* ftm cmd-id mapping */ -static const ftm_strmap_entry_t ftm_cmdid_map[] = { - /* {wl_proxd_cmd_t(WL_PROXD_CMD_xxx), "WL_PROXD_CMD_xxx" }, */ - DEF_STRMAP_ENTRY(WL_PROXD_CMD_NONE), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_VERSION), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_ENABLE), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_DISABLE), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_CONFIG), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_SESSION), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_BURST_REQUEST), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_SESSION), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_DELETE_SESSION), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RESULT), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_INFO), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_STATUS), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_SESSIONS), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_COUNTERS), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_CLEAR_COUNTERS), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_COLLECT), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_TUNE), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_DUMP), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_RANGING), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_RANGING), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RANGING_INFO), -}; - -/* -* map a ftm cmd-id to a text-string for display -*/ -static const char * -ftm_cmdid_to_str(uint16 cmdid) -{ - return ftm_map_id_to_str((int32) cmdid, &ftm_cmdid_map[0], ARRAYSIZE(ftm_cmdid_map)); -} -#endif /* RTT_DEBUG */ - - -/* -* convert BCME_xxx error codes into related error strings -* note, bcmerrorstr() defined in bcmutils is for BCMDRIVER only, -* this duplicate copy is for WL access and may need to clean up later -*/ -static const char *ftm_bcmerrorstrtable[] = BCMERRSTRINGTABLE; -static const char * -ftm_status_value_to_logstr(wl_proxd_status_t status) -{ - static char ftm_msgbuf_status_undef[32]; - const ftm_strmap_entry_t *p_loginfo; - int bcmerror; - - /* check if within BCME_xxx error range */ - bcmerror = (int) status; - if (VALID_BCMERROR(bcmerror)) - return ftm_bcmerrorstrtable[-bcmerror]; - - /* otherwise, look for 'proxd ftm status' range */ - p_loginfo = ftm_get_strmap_info((int32) status, - &ftm_status_value_loginfo[0], ARRAYSIZE(ftm_status_value_loginfo)); - if (p_loginfo) - return p_loginfo->text; - - /* report for 'out of range' FTM-status error code */ - memset(ftm_msgbuf_status_undef, 0, sizeof(ftm_msgbuf_status_undef)); - snprintf(ftm_msgbuf_status_undef, sizeof(ftm_msgbuf_status_undef), - "Undefined status %d", status); - return &ftm_msgbuf_status_undef[0]; -} - -static const char * -ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu) -{ - return ftm_map_id_to_str((int32)tmu, - &ftm_tmu_value_loginfo[0], ARRAYSIZE(ftm_tmu_value_loginfo)); -} - -static const ftm_strmap_entry_t* -ftm_get_event_type_loginfo(wl_proxd_event_type_t event_type) -{ - /* look up 'event-type' from a predefined table */ - return ftm_get_strmap_info((int32) event_type, - ftm_event_type_loginfo, ARRAYSIZE(ftm_event_type_loginfo)); -} - -static const char * -ftm_session_state_value_to_logstr(wl_proxd_session_state_t state) -{ - return ftm_map_id_to_str((int32)state, &ftm_session_state_value_loginfo[0], - ARRAYSIZE(ftm_session_state_value_loginfo)); -} - - -/* -* send 'proxd' iovar for all ftm get-related commands -*/ -static int -rtt_do_get_ioctl(dhd_pub_t *dhd, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize, - ftm_subcmd_info_t *p_subcmd_info) -{ - - wl_proxd_iov_t *p_iovresp = (wl_proxd_iov_t *)resp_buf; - int status; - int tlvs_len; - /* send getbuf proxd iovar */ - status = dhd_getiovar(dhd, 0, "proxd", (char *)p_proxd_iov, - proxd_iovsize, (char **)&p_iovresp, WLC_IOCTL_SMLEN); - if (status != BCME_OK) { - DHD_ERROR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n", - __FUNCTION__, p_subcmd_info->cmdid, status)); - return status; - } - if (p_subcmd_info->cmdid == WL_PROXD_CMD_GET_VERSION) { - p_subcmd_info->version = ltoh16(p_iovresp->version); - DHD_RTT(("ftm version: 0x%x\n", ltoh16(p_iovresp->version))); - goto exit; - } - - tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE; - if (tlvs_len < 0) { - DHD_ERROR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n", - __FUNCTION__, ltoh16(p_iovresp->len), (int) WL_PROXD_IOV_HDR_SIZE)); - tlvs_len = 0; - } - - if (tlvs_len > 0 && p_subcmd_info->handler) { - /* unpack TLVs and invokes the cbfn for processing */ - status = bcm_unpack_xtlv_buf(p_proxd_iov, (uint8 *)p_iovresp->tlvs, - tlvs_len, BCM_XTLV_OPTION_ALIGN32, p_subcmd_info->handler); - } -exit: - return status; -} - - -static wl_proxd_iov_t * -rtt_alloc_getset_buf(wl_proxd_method_t method, wl_proxd_session_id_t session_id, - wl_proxd_cmd_t cmdid, uint16 tlvs_bufsize, uint16 *p_out_bufsize) -{ - uint16 proxd_iovsize; - uint16 kflags; - wl_proxd_tlv_t *p_tlv; - wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) NULL; - - *p_out_bufsize = 0; /* init */ - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - /* calculate the whole buffer size, including one reserve-tlv entry in the header */ - proxd_iovsize = sizeof(wl_proxd_iov_t) + tlvs_bufsize; - - p_proxd_iov = kzalloc(proxd_iovsize, kflags); - if (p_proxd_iov == NULL) { - DHD_ERROR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize)); - return NULL; - } - - /* setup proxd-FTM-method iovar header */ - p_proxd_iov->version = htol16(WL_PROXD_API_VERSION); - p_proxd_iov->len = htol16(proxd_iovsize); /* caller may adjust it based on #of TLVs */ - p_proxd_iov->cmd = htol16(cmdid); - p_proxd_iov->method = htol16(method); - p_proxd_iov->sid = htol16(session_id); - - /* initialize the reserved/dummy-TLV in iovar header */ - p_tlv = p_proxd_iov->tlvs; - p_tlv->id = htol16(WL_PROXD_TLV_ID_NONE); - p_tlv->len = htol16(0); - - *p_out_bufsize = proxd_iovsize; /* for caller's reference */ - - return p_proxd_iov; -} - - -static int -dhd_rtt_common_get_handler(dhd_pub_t *dhd, ftm_subcmd_info_t *p_subcmd_info, - wl_proxd_method_t method, wl_proxd_session_id_t session_id) -{ - int status = BCME_OK; - uint16 proxd_iovsize = 0; - wl_proxd_iov_t *p_proxd_iov; -#ifdef RTT_DEBUG - DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", - __FUNCTION__, method, session_id, p_subcmd_info->cmdid, - ftm_cmdid_to_str(p_subcmd_info->cmdid))); -#endif - /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ - p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, - 0, &proxd_iovsize); - - if (p_proxd_iov == NULL) - return BCME_NOMEM; - - status = rtt_do_get_ioctl(dhd, p_proxd_iov, proxd_iovsize, p_subcmd_info); - - if (status != BCME_OK) { - DHD_RTT(("%s failed: status=%d\n", __FUNCTION__, status)); - } - kfree(p_proxd_iov); - return status; -} - -/* -* common handler for set-related proxd method commands which require no TLV as input -* wl proxd ftm [session-id] -* e.g. -* wl proxd ftm enable -- to enable ftm -* wl proxd ftm disable -- to disable ftm -* wl proxd ftm start -- to start a specified session -* wl proxd ftm stop -- to cancel a specified session; -* state is maintained till session is delete. -* wl proxd ftm delete -- to delete a specified session -* wl proxd ftm [] clear-counters -- to clear counters -* wl proxd ftm burst-request -- on initiator: to send burst request; -* on target: send FTM frame -* wl proxd ftm collect -* wl proxd ftm tune (TBD) -*/ -static int -dhd_rtt_common_set_handler(dhd_pub_t *dhd, const ftm_subcmd_info_t *p_subcmd_info, - wl_proxd_method_t method, wl_proxd_session_id_t session_id) -{ - uint16 proxd_iovsize; - wl_proxd_iov_t *p_proxd_iov; - int ret; - -#ifdef RTT_DEBUG - DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", - __FUNCTION__, method, session_id, p_subcmd_info->cmdid, - ftm_cmdid_to_str(p_subcmd_info->cmdid))); -#endif - - /* allocate and initialize a temp buffer for 'set proxd' iovar */ - proxd_iovsize = 0; - p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, - 0, &proxd_iovsize); /* no TLV */ - if (p_proxd_iov == NULL) - return BCME_NOMEM; - - /* no TLV to pack, simply issue a set-proxd iovar */ - ret = dhd_iovar(dhd, 0, "proxd", (void *) p_proxd_iov, proxd_iovsize, 1); -#ifdef RTT_DEBUG - if (ret != BCME_OK) { - DHD_RTT(("error: IOVAR failed, status=%d\n", ret)); - } -#endif - /* clean up */ - kfree(p_proxd_iov); - - return ret; -} - -static int -rtt_unpack_xtlv_cbfn(void *ctx, uint8 *p_data, uint16 tlvid, uint16 len) -{ - int ret = BCME_OK; - wl_proxd_ftm_session_status_t *p_data_info; - switch (tlvid) { - case WL_PROXD_TLV_ID_RTT_RESULT: - ret = dhd_rtt_convert_results_to_host((rtt_report_t *)ctx, - p_data, tlvid, len); - break; - case WL_PROXD_TLV_ID_SESSION_STATUS: - memcpy(ctx, p_data, sizeof(wl_proxd_ftm_session_status_t)); - p_data_info = (wl_proxd_ftm_session_status_t *)ctx; - p_data_info->state = ltoh16_ua(&p_data_info->state); - p_data_info->status = ltoh32_ua(&p_data_info->status); - break; - default: - DHD_ERROR(("> Unsupported TLV ID %d\n", tlvid)); - ret = BCME_ERROR; - break; - } - - return ret; -} -static int -rtt_handle_config_options(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, - uint16 *p_buf_space_left, ftm_config_options_info_t *ftm_configs, int ftm_cfg_cnt) -{ - int ret = BCME_OK; - int cfg_idx = 0; - uint32 flags = WL_PROXD_FLAG_NONE; - uint32 flags_mask = WL_PROXD_FLAG_NONE; - uint32 new_mask; /* cmdline input */ - ftm_config_options_info_t *p_option_info; - uint16 type = (session_id == WL_PROXD_SESSION_ID_GLOBAL) ? - WL_PROXD_TLV_ID_FLAGS_MASK : WL_PROXD_TLV_ID_SESSION_FLAGS_MASK; - for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { - p_option_info = (ftm_configs + cfg_idx); - if (p_option_info != NULL) { - new_mask = p_option_info->flags; - /* update flags mask */ - flags_mask |= new_mask; - if (p_option_info->enable) { - flags |= new_mask; /* set the bit on */ - } else { - flags &= ~new_mask; /* set the bit off */ - } - } - } - flags = htol32(flags); - flags_mask = htol32(flags_mask); - /* setup flags_mask TLV */ - ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, - type, sizeof(uint32), &flags_mask, BCM_XTLV_OPTION_ALIGN32); - if (ret != BCME_OK) { - DHD_ERROR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n", - __FUNCTION__, ret)); - goto exit; - } - - type = (session_id == WL_PROXD_SESSION_ID_GLOBAL)? - WL_PROXD_TLV_ID_FLAGS : WL_PROXD_TLV_ID_SESSION_FLAGS; - /* setup flags TLV */ - ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, - type, sizeof(uint32), &flags, BCM_XTLV_OPTION_ALIGN32); - if (ret != BCME_OK) { -#ifdef RTT_DEBUG - DHD_RTT(("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n", - __FUNCTION__, ret)); -#endif - } -exit: - return ret; -} - -static int -rtt_handle_config_general(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, - uint16 *p_buf_space_left, ftm_config_param_info_t *ftm_configs, int ftm_cfg_cnt) -{ - int ret = BCME_OK; - int cfg_idx = 0; - uint32 chanspec; - ftm_config_param_info_t *p_config_param_info; - void *p_src_data; - uint16 src_data_size; /* size of data pointed by p_src_data as 'source' */ - for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { - p_config_param_info = (ftm_configs + cfg_idx); - if (p_config_param_info != NULL) { - switch (p_config_param_info->tlvid) { - case WL_PROXD_TLV_ID_BSS_INDEX: - p_src_data = &p_config_param_info->data8; - src_data_size = sizeof(uint8); - break; - case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* uint16 */ - case WL_PROXD_TLV_ID_NUM_BURST: - case WL_PROXD_TLV_ID_FTM_RETRIES: - case WL_PROXD_TLV_ID_RX_MAX_BURST: - case WL_PROXD_TLV_ID_FTM_REQ_RETRIES: - p_src_data = &p_config_param_info->data16; - src_data_size = sizeof(uint16); - break; - case WL_PROXD_TLV_ID_TX_POWER: /* uint32 */ - case WL_PROXD_TLV_ID_RATESPEC: - case WL_PROXD_TLV_ID_EVENT_MASK: /* wl_proxd_event_mask_t/uint32 */ - case WL_PROXD_TLV_ID_DEBUG_MASK: - p_src_data = &p_config_param_info->data32; - src_data_size = sizeof(uint32); - break; - case WL_PROXD_TLV_ID_CHANSPEC: /* chanspec_t --> 32bit */ - chanspec = p_config_param_info->chanspec; - p_src_data = (void *) &chanspec; - src_data_size = sizeof(uint32); - break; - case WL_PROXD_TLV_ID_BSSID: /* mac address */ - case WL_PROXD_TLV_ID_PEER_MAC: - p_src_data = &p_config_param_info->mac_addr; - src_data_size = sizeof(struct ether_addr); - break; - case WL_PROXD_TLV_ID_BURST_DURATION: /* wl_proxd_intvl_t */ - case WL_PROXD_TLV_ID_BURST_PERIOD: - case WL_PROXD_TLV_ID_BURST_FTM_SEP: - case WL_PROXD_TLV_ID_BURST_TIMEOUT: - case WL_PROXD_TLV_ID_INIT_DELAY: - p_src_data = &p_config_param_info->data_intvl; - src_data_size = sizeof(wl_proxd_intvl_t); - break; - default: - ret = BCME_BADARG; - break; - } - if (ret != BCME_OK) { - DHD_ERROR(("%s bad TLV ID : %d\n", - __FUNCTION__, p_config_param_info->tlvid)); - break; - } - - ret = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left, - p_config_param_info->tlvid, src_data_size, p_src_data, - BCM_XTLV_OPTION_ALIGN32); - if (ret != BCME_OK) { - DHD_ERROR(("%s: bcm_pack_xltv_entry() failed," - " status=%d\n", __FUNCTION__, ret)); - break; - } - - } - } - return ret; -} - -static int -dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version) -{ - int ret; - ftm_subcmd_info_t subcmd_info; - subcmd_info.name = "ver"; - subcmd_info.cmdid = WL_PROXD_CMD_GET_VERSION; - subcmd_info.handler = NULL; - ret = dhd_rtt_common_get_handler(dhd, &subcmd_info, - WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); - *out_version = (ret == BCME_OK) ? subcmd_info.version : 0; - return ret; -} - -static int -dhd_rtt_ftm_enable(dhd_pub_t *dhd, bool enable) -{ - ftm_subcmd_info_t subcmd_info; - subcmd_info.name = (enable)? "enable" : "disable"; - subcmd_info.cmdid = (enable)? WL_PROXD_CMD_ENABLE: WL_PROXD_CMD_DISABLE; - subcmd_info.handler = NULL; - return dhd_rtt_common_set_handler(dhd, &subcmd_info, - WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); -} - -static int -dhd_rtt_start_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, bool start) -{ - ftm_subcmd_info_t subcmd_info; - subcmd_info.name = (start)? "start session" : "stop session"; - subcmd_info.cmdid = (start)? WL_PROXD_CMD_START_SESSION: WL_PROXD_CMD_STOP_SESSION; - subcmd_info.handler = NULL; - return dhd_rtt_common_set_handler(dhd, &subcmd_info, - WL_PROXD_METHOD_FTM, session_id); -} - -static int -dhd_rtt_delete_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id) -{ - ftm_subcmd_info_t subcmd_info; - subcmd_info.name = "delete session"; - subcmd_info.cmdid = WL_PROXD_CMD_DELETE_SESSION; - subcmd_info.handler = NULL; - return dhd_rtt_common_set_handler(dhd, &subcmd_info, - WL_PROXD_METHOD_FTM, session_id); -} - -static int -dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, - ftm_config_category_t catagory, void *ftm_configs, int ftm_cfg_cnt) -{ - ftm_subcmd_info_t subcmd_info; - wl_proxd_tlv_t *p_tlv; - /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ - wl_proxd_iov_t *p_proxd_iov; - uint16 proxd_iovsize = 0; - uint16 bufsize; - uint16 buf_space_left; - uint16 all_tlvsize; - int ret = BCME_OK; - - subcmd_info.name = "config"; - subcmd_info.cmdid = WL_PROXD_CMD_CONFIG; - - p_proxd_iov = rtt_alloc_getset_buf(WL_PROXD_METHOD_FTM, session_id, subcmd_info.cmdid, - FTM_IOC_BUFSZ, &proxd_iovsize); - - if (p_proxd_iov == NULL) { - DHD_ERROR(("%s : failed to allocate the iovar (size :%d)\n", - __FUNCTION__, FTM_IOC_BUFSZ)); - return BCME_NOMEM; - } - /* setup TLVs */ - bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */ - p_tlv = &p_proxd_iov->tlvs[0]; - /* TLV buffer starts with a full size, will decrement for each packed TLV */ - buf_space_left = bufsize; - if (catagory == FTM_CONFIG_CAT_OPTIONS) { - ret = rtt_handle_config_options(session_id, &p_tlv, &buf_space_left, - (ftm_config_options_info_t *)ftm_configs, ftm_cfg_cnt); - } else if (catagory == FTM_CONFIG_CAT_GENERAL) { - ret = rtt_handle_config_general(session_id, &p_tlv, &buf_space_left, - (ftm_config_param_info_t *)ftm_configs, ftm_cfg_cnt); - } - if (ret == BCME_OK) { - /* update the iov header, set len to include all TLVs + header */ - all_tlvsize = (bufsize - buf_space_left); - p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE); - ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, - all_tlvsize + WL_PROXD_IOV_HDR_SIZE, 1); - if (ret != BCME_OK) { - DHD_ERROR(("%s : failed to set config\n", __FUNCTION__)); - } - } - /* clean up */ - kfree(p_proxd_iov); - return ret; -} - -chanspec_t -dhd_rtt_convert_to_chspec(wifi_channel_info_t channel) -{ - int bw; - chanspec_t chanspec = 0; - uint8 center_chan; - uint8 primary_chan; - /* set witdh to 20MHZ for 2.4G HZ */ - if (channel.center_freq >= 2400 && channel.center_freq <= 2500) { - channel.width = WIFI_CHAN_WIDTH_20; - } - switch (channel.width) { - case WIFI_CHAN_WIDTH_20: - bw = WL_CHANSPEC_BW_20; - primary_chan = wf_mhz2channel(channel.center_freq, 0); - chanspec = wf_channel2chspec(primary_chan, bw); - break; - case WIFI_CHAN_WIDTH_40: - bw = WL_CHANSPEC_BW_40; - primary_chan = wf_mhz2channel(channel.center_freq, 0); - chanspec = wf_channel2chspec(primary_chan, bw); - break; - case WIFI_CHAN_WIDTH_80: - bw = WL_CHANSPEC_BW_80; - primary_chan = wf_mhz2channel(channel.center_freq, 0); - center_chan = wf_mhz2channel(channel.center_freq0, 0); - chanspec = wf_chspec_80(center_chan, primary_chan); - break; - default: - DHD_ERROR(("doesn't support this bandwith : %d", channel.width)); - bw = -1; - break; - } - return chanspec; -} - -int -dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params) -{ - int err = BCME_OK; - int idx; - rtt_status_info_t *rtt_status; - NULL_CHECK(params, "params is NULL", err); - - NULL_CHECK(dhd, "dhd is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - if (!HAS_11MC_CAP(rtt_status->rtt_capa.proto)) { - DHD_ERROR(("doesn't support RTT \n")); - return BCME_ERROR; - } - if (rtt_status->status != RTT_STOPPED) { - DHD_ERROR(("rtt is already started\n")); - return BCME_BUSY; - } - DHD_RTT(("%s enter\n", __FUNCTION__)); - - memset(rtt_status->rtt_config.target_info, 0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); - rtt_status->rtt_config.rtt_target_cnt = params->rtt_target_cnt; - memcpy(rtt_status->rtt_config.target_info, - params->target_info, TARGET_INFO_SIZE(params->rtt_target_cnt)); - rtt_status->status = RTT_STARTED; - /* start to measure RTT from first device */ - /* find next target to trigger RTT */ - for (idx = rtt_status->cur_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { - /* skip the disabled device */ - if (rtt_status->rtt_config.target_info[idx].disable) { - continue; - } else { - /* set the idx to cur_idx */ - rtt_status->cur_idx = idx; - break; - } - } - if (idx < rtt_status->rtt_config.rtt_target_cnt) { - DHD_RTT(("rtt_status->cur_idx : %d\n", rtt_status->cur_idx)); - schedule_work(&rtt_status->work); - } - return err; -} - -int -dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt) -{ - int err = BCME_OK; - int i = 0, j = 0; - rtt_status_info_t *rtt_status; - - NULL_CHECK(dhd, "dhd is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - if (rtt_status->status == RTT_STOPPED) { - DHD_ERROR(("rtt is not started\n")); - return BCME_OK; - } - DHD_RTT(("%s enter\n", __FUNCTION__)); - mutex_lock(&rtt_status->rtt_mutex); - for (i = 0; i < mac_cnt; i++) { - for (j = 0; j < rtt_status->rtt_config.rtt_target_cnt; j++) { - if (!bcmp(&mac_list[i], &rtt_status->rtt_config.target_info[j].addr, - ETHER_ADDR_LEN)) { - rtt_status->rtt_config.target_info[j].disable = TRUE; - } - } - } - mutex_unlock(&rtt_status->rtt_mutex); - return err; -} - -/* custom tune function to have more accuracy */ -static int -dhd_rtt_custom_tune(dhd_pub_t *dhd, bool enable) -{ - int ret = BCME_OK; - uint32 ant_val; - rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd); - - /* Select Antenna */ - if (enable) { - /* read current Antenna value */ - ret = dhd_iovar(dhd, 0, "txchain", (char *)&ant_val, - sizeof(uint32), 0); - if (ret < 0) { - DHD_ERROR(("%s: failed to get txchain, ret=%d\n", - __FUNCTION__, ret)); - goto exit; - } - rtt_status->txchain = ltoh32(ant_val); - /* set 1 for tx chain */ - ant_val = 1; - } else { - /* restore the original value of tx chain */ - ant_val = rtt_status->txchain; - if (ant_val == 0) goto exit; - rtt_status->txchain = 0; - } - ant_val = htol32(ant_val); - ret = dhd_iovar(dhd, 0, "txchain", (char *)&ant_val, - sizeof(uint32), 1); - if (ret < 0) { - DHD_ERROR(("%s: failed to set txchain, ret=%d\n", __FUNCTION__, ret)); - } -#ifdef ENABLE_VHT_ACK - { - int16 vht = 1; - wl_proxd_params_iovar_t proxd_tune; - /* read the current tune params */ - memset(&proxd_tune, 0, sizeof(wl_proxd_params_iovar_t)); - ret = dhd_iovar(dhd, 0, "proxd_tune", (char *)&proxd_tune, - sizeof(wl_proxd_params_iovar_t), 0); - if (ret < 0) { - DHD_ERROR(("%s : failed to get proxd_tune %d\n", __FUNCTION__, ret)); - goto exit; - } - /* set VHT ACK in current tune param */ - proxd_tune.u.tof_tune.force_K = 0; - proxd_tune.u.tof_tune.vhtack = htol16(vht); - proxd_tune.method = htol16(PROXD_TOF_METHOD); - ret = dhd_iovar(dhd, 0, "proxd_tune", (char *)&proxd_tune, - sizeof(wl_proxd_params_iovar_t), 1); - if (ret < 0) { - DHD_ERROR(("%s : failed to set proxd_tune %d\n", __FUNCTION__, ret)); - } - } -#endif /* ENABLE_VHT_ACK */ -exit: - return ret; -} -static int -dhd_rtt_start(dhd_pub_t *dhd) -{ - int err = BCME_OK; - char eabuf[ETHER_ADDR_STR_LEN]; - char chanbuf[CHANSPEC_STR_LEN]; - int mpc = 0; - int ftm_cfg_cnt = 0; - int ftm_param_cnt = 0; - ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS]; - ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS]; - rtt_target_info_t *rtt_target; - rtt_status_info_t *rtt_status; - NULL_CHECK(dhd, "dhd is NULL", err); - - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - - if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) { - err = BCME_RANGE; - DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx)); - goto exit; - } - /* turn off mpc in case of non-associted */ - if (!dhd_is_associated(dhd, NULL, NULL)) { - err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), 1); - if (err) { - DHD_ERROR(("%s : failed to set mpc\n", __FUNCTION__)); - goto exit; - } - rtt_status->mpc = 1; /* Either failure or complete, we need to enable mpc */ - } - - mutex_lock(&rtt_status->rtt_mutex); - /* Get a target information */ - rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; - mutex_unlock(&rtt_status->rtt_mutex); - DHD_RTT(("%s enter\n", __FUNCTION__)); - if (!RTT_IS_ENABLED(rtt_status)) { - /* enable ftm */ - err = dhd_rtt_ftm_enable(dhd, TRUE); - if (err) { - DHD_ERROR(("failed to enable FTM (%d)\n", err)); - goto exit; - } - /* VHT ACK for more accuracy */ - err = dhd_rtt_custom_tune(dhd, TRUE); - if (err < 0) { - DHD_ERROR(("failed to set rtt_custom_set (%d)\n", err)); - goto exit; - } - } - rtt_status->status = RTT_ENABLED; - - /* delete session of index default sesession */ - err = dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION); - if (err < 0 && err != BCME_NOTFOUND) { - DHD_ERROR(("failed to delete session of FTM (%d)\n", err)); - goto exit; - } - memset(ftm_configs, 0, sizeof(ftm_configs)); - memset(ftm_params, 0, sizeof(ftm_params)); - - /* configure the session 1 as initiator */ - ftm_configs[ftm_cfg_cnt].enable = TRUE; - ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_INITIATOR; - dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS, - ftm_configs, ftm_cfg_cnt); - /* target's mac address */ - if (!ETHER_ISNULLADDR(rtt_target->addr.octet)) { - ftm_params[ftm_param_cnt].mac_addr = rtt_target->addr; - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_PEER_MAC; - DHD_RTT((">\t target %s\n", bcm_ether_ntoa(&rtt_target->addr, eabuf))); - } - /* target's chanspec */ - if (rtt_target->chanspec) { - ftm_params[ftm_param_cnt].chanspec = htol32((uint32)rtt_target->chanspec); - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_CHANSPEC; - DHD_RTT((">\t chanspec : %s\n", wf_chspec_ntoa(rtt_target->chanspec, chanbuf))); - } - /* num-burst */ - if (rtt_target->num_burst) { - ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_burst); - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_NUM_BURST; - DHD_RTT((">\t num of burst : %d\n", rtt_target->num_burst)); - } - /* number of frame per burst */ - if (rtt_target->num_frames_per_burst == 0) { - rtt_target->num_frames_per_burst = - CHSPEC_IS20(rtt_target->chanspec) ? FTM_DEFAULT_CNT_20M : - CHSPEC_IS40(rtt_target->chanspec) ? FTM_DEFAULT_CNT_40M : - FTM_DEFAULT_CNT_80M; - } - ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_frames_per_burst); - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_NUM_FTM; - DHD_RTT((">\t number of frame per burst : %d\n", rtt_target->num_frames_per_burst)); - /* FTM retry count */ - if (rtt_target->num_retries_per_ftm) { - ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_retries_per_ftm); - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_RETRIES; - DHD_RTT((">\t retry count of FTM : %d\n", rtt_target->num_retries_per_ftm)); - } - /* FTM Request retry count */ - if (rtt_target->num_retries_per_ftmr) { - ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_retries_per_ftmr); - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_REQ_RETRIES; - DHD_RTT((">\t retry count of FTM Req : %d\n", rtt_target->num_retries_per_ftm)); - } - /* burst-period */ - if (rtt_target->interval) { - ftm_params[ftm_param_cnt].data_intvl.intvl = htol32(rtt_target->interval); /* ms */ - ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC; - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_PERIOD; - DHD_RTT((">\t burst period : %d ms\n", rtt_target->interval)); - } - /* burst-timeout */ - if (rtt_target->burst_timeout) { - ftm_params[ftm_param_cnt].data_intvl.intvl = - htol32(rtt_target->burst_timeout * FTM_BURST_TIMEOUT_UNIT); - ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MICRO_SEC; - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_TIMEOUT; - DHD_RTT((">\t burst timeout : %d us\n", - rtt_target->burst_timeout * WL_PROXD_TMU_MICRO_SEC)); - } - dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_GENERAL, - ftm_params, ftm_param_cnt); - - err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE); - if (err) { - DHD_ERROR(("failed to start session of FTM : error %d\n", err)); - } -exit: - if (err) { - rtt_status->status = RTT_STOPPED; - /* restore default value for custome tune */ - dhd_rtt_custom_tune(dhd, FALSE); - /* disable FTM */ - dhd_rtt_ftm_enable(dhd, FALSE); - if (rtt_status->mpc) { - /* enable mpc again in case of error */ - mpc = 1; - rtt_status->mpc = 0; - err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), 1); - } - } - return err; -} - -int -dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn) -{ - int err = BCME_OK; - struct rtt_noti_callback *cb = NULL, *iter; - rtt_status_info_t *rtt_status; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(noti_fn, "noti_fn is NULL", err); - - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - spin_lock_bh(¬i_list_lock); - list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { - if (iter->noti_fn == noti_fn) { - goto exit; - } - } - cb = kmalloc(sizeof(struct rtt_noti_callback), GFP_ATOMIC); - if (!cb) { - err = -ENOMEM; - goto exit; - } - cb->noti_fn = noti_fn; - cb->ctx = ctx; - list_add(&cb->list, &rtt_status->noti_fn_list); -exit: - spin_unlock_bh(¬i_list_lock); - return err; -} - -int -dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn) -{ - int err = BCME_OK; - struct rtt_noti_callback *cb = NULL, *iter; - rtt_status_info_t *rtt_status; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(noti_fn, "noti_fn is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - spin_lock_bh(¬i_list_lock); - list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { - if (iter->noti_fn == noti_fn) { - cb = iter; - list_del(&cb->list); - break; - } - } - spin_unlock_bh(¬i_list_lock); - if (cb) { - kfree(cb); - } - return err; -} - -static wifi_rate_t -dhd_rtt_convert_rate_to_host(uint32 rspec) -{ - wifi_rate_t host_rate; - uint32 bandwidth; - memset(&host_rate, 0, sizeof(wifi_rate_t)); - if (RSPEC_ISLEGACY(rspec)) { - host_rate.preamble = 0; - } else if (RSPEC_ISHT(rspec)) { - host_rate.preamble = 2; - host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; - } else if (RSPEC_ISVHT(rspec)) { - host_rate.preamble = 3; - host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; - host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; - } - - bandwidth = RSPEC_BW(rspec); - switch (bandwidth) { - case WL_RSPEC_BW_20MHZ: - host_rate.bw = RTT_RATE_20M; - break; - case WL_RSPEC_BW_40MHZ: - host_rate.bw = RTT_RATE_40M; - break; - case WL_RSPEC_BW_80MHZ: - host_rate.bw = RTT_RATE_80M; - break; - case WL_RSPEC_BW_160MHZ: - host_rate.bw = RTT_RATE_160M; - break; - default: - host_rate.bw = RTT_RATE_20M; - break; - } - - host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ - DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); - return host_rate; -} - - -static int -dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len) -{ - int err = BCME_OK; - char eabuf[ETHER_ADDR_STR_LEN]; - wl_proxd_rtt_result_t *p_data_info; - wl_proxd_result_flags_t flags; - wl_proxd_session_state_t session_state; - wl_proxd_status_t proxd_status; - struct timespec ts; - uint32 ratespec; - uint32 avg_dist; - wl_proxd_rtt_sample_t *p_sample; - wl_proxd_intvl_t rtt; - wl_proxd_intvl_t p_time; - - NULL_CHECK(rtt_report, "rtt_report is NULL", err); - NULL_CHECK(p_data, "p_data is NULL", err); - DHD_RTT(("%s enter\n", __FUNCTION__)); - p_data_info = (wl_proxd_rtt_result_t *) p_data; - /* unpack and format 'flags' for display */ - flags = ltoh16_ua(&p_data_info->flags); - - /* session state and status */ - session_state = ltoh16_ua(&p_data_info->state); - proxd_status = ltoh32_ua(&p_data_info->status); - DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n", - bcm_ether_ntoa((&(p_data_info->peer)), eabuf), - session_state, - ftm_session_state_value_to_logstr(session_state), - proxd_status, - ftm_status_value_to_logstr(proxd_status))); - - /* show avg_dist (1/256m units), burst_num */ - avg_dist = ltoh32_ua(&p_data_info->avg_dist); - if (avg_dist == 0xffffffff) { /* report 'failure' case */ - DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n", - ltoh16_ua(&p_data_info->burst_num), - p_data_info->num_valid_rtt)); /* in a session */ - avg_dist = FTM_INVALID; - } - else { - DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n", - avg_dist >> 8, /* 1/256m units */ - ((avg_dist & 0xff) * 625) >> 4, - ltoh16_ua(&p_data_info->burst_num), - p_data_info->num_valid_rtt, - p_data_info->num_ftm)); /* in a session */ - } - /* show 'avg_rtt' sample */ - p_sample = &p_data_info->avg_rtt; - DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d ratespec=0x%08x\n", - (int16) ltoh16_ua(&p_sample->rssi), - ltoh32_ua(&p_sample->rtt.intvl), - ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)), - ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10, - ltoh32_ua(&p_sample->ratespec))); - - /* set peer address */ - rtt_report->addr = p_data_info->peer; - /* burst num */ - rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num); - /* success num */ - rtt_report->success_num = p_data_info->num_valid_rtt; - /* actual number of FTM supported by peer */ - rtt_report->num_per_burst_peer = p_data_info->num_ftm; - /* status */ - rtt_report->status = ftm_get_statusmap_info(proxd_status, - &ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info)); - /* rssi */ - rtt_report->rssi = (int16)ltoh16_ua(&p_data_info->avg_rtt.rssi); - /* rx rate */ - ratespec = ltoh32_ua(&p_data_info->avg_rtt.ratespec); - rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec); - /* rtt_sd */ - rtt.tmu = ltoh16_ua(&p_data_info->avg_rtt.rtt.tmu); - rtt.intvl = ltoh32_ua(&p_data_info->avg_rtt.rtt.intvl); - rtt_report->rtt = FTM_INTVL2NSEC(&rtt) * 10; /* nano -> 0.1 nano */ - rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */ - - /* average distance */ - if (avg_dist != FTM_INVALID) { - rtt_report->distance = (avg_dist >> 8) * 100; /* meter -> cm */ - rtt_report->distance += (avg_dist & 0xff) * 100 / 256; - } else { - rtt_report->distance = FTM_INVALID; - } - /* time stamp */ - /* get the time elapsed from boot time */ - get_monotonic_boottime(&ts); - rtt_report->ts = (uint64)TIMESPEC_TO_US(ts); - - if (proxd_status == WL_PROXD_E_REMOTE_FAIL) { - /* retry time after failure */ - p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); - p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); - rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */ - DHD_RTT((">\tretry_after: %d%s\n", - ltoh32_ua(&p_data_info->u.retry_after.intvl), - ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu)))); - } else { - /* burst duration */ - p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); - p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); - rtt_report->burst_duration = FTM_INTVL2MSEC(&p_time); /* s -> ms */ - DHD_RTT((">\tburst_duration: %d%s\n", - ltoh32_ua(&p_data_info->u.burst_duration.intvl), - ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu)))); - } - return err; -} - -int -dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) -{ - int ret = BCME_OK; - int tlvs_len; - int idx; - uint16 version; - wl_proxd_event_t *p_event; - wl_proxd_event_type_t event_type; - wl_proxd_ftm_session_status_t session_status; - const ftm_strmap_entry_t *p_loginfo; - rtt_status_info_t *rtt_status; - rtt_target_info_t *rtt_target_info; - struct rtt_noti_callback *iter; - rtt_results_header_t *entry = NULL, *next = NULL, *rtt_results_header = NULL; - rtt_result_t *rtt_result, *next2; - gfp_t kflags; - bool is_new = TRUE; - - DHD_RTT(("Enter %s \n", __FUNCTION__)); - NULL_CHECK(dhd, "dhd is NULL", ret); - -#ifdef WL_CFG80211 - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", ret); - - if (RTT_IS_STOPPED(rtt_status)) { - /* Ignore the Proxd event */ - DHD_RTT((" event handler rtt is stopped \n")); - goto exit; - } -#endif /* WL_CFG80211 */ - if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) { - DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__, - ntoh32_ua((void *)&event->datalen))); - ret = -EINVAL; - goto exit; - } - event_type = ntoh32_ua((void *)&event->event_type); - if (event_type != WLC_E_PROXD) { - DHD_ERROR((" failed event \n")); - ret = -EINVAL; - goto exit; - } - - if (!event_data) { - DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); - ret = -EINVAL; - goto exit; - } - p_event = (wl_proxd_event_t *) event_data; - version = ltoh16(p_event->version); - if (version < WL_PROXD_API_VERSION) { - DHD_ERROR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n", - version, WL_PROXD_API_VERSION)); - goto exit; - } - if (!in_atomic()) { - mutex_lock(&rtt_status->rtt_mutex); - } - event_type = (wl_proxd_event_type_t) ltoh16(p_event->type); - - kflags = in_softirq()? GFP_ATOMIC : GFP_KERNEL; - - DHD_RTT(("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x\n", - p_event->type, ntoh16(p_event->type), ltoh16(p_event->type))); - p_loginfo = ftm_get_event_type_loginfo(event_type); - if (p_loginfo == NULL) { - DHD_ERROR(("receive an invalid FTM event %d\n", event_type)); - ret = -EINVAL; - goto exit; /* ignore this event */ - } - /* get TLVs len, skip over event header */ - if (ltoh16(p_event->len) < OFFSETOF(wl_proxd_event_t, tlvs)) { - DHD_ERROR(("invalid FTM event length:%d\n", ltoh16(p_event->len))); - ret = -EINVAL; - goto exit; - } - tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs); - DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n", - p_loginfo->text, - version, - ltoh16(p_event->len), - ltoh16(p_event->method), - ltoh16(p_event->sid), - tlvs_len)); - rtt_target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; - /* find a rtt_report_header for this mac address */ - list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) { - if (!memcmp(&entry->peer_mac, &event->addr, ETHER_ADDR_LEN)) { - /* found a rtt_report_header for peer_mac in the list */ - is_new = FALSE; - rtt_results_header = entry; - break; - } - } - - switch (event_type) { - case WL_PROXD_EVENT_SESSION_CREATE: - DHD_RTT(("WL_PROXD_EVENT_SESSION_CREATE\n")); - break; - case WL_PROXD_EVENT_SESSION_START: - DHD_RTT(("WL_PROXD_EVENT_SESSION_START\n")); - break; - case WL_PROXD_EVENT_BURST_START: - DHD_RTT(("WL_PROXD_EVENT_BURST_START\n")); - break; - case WL_PROXD_EVENT_BURST_END: - DHD_RTT(("WL_PROXD_EVENT_BURST_END\n")); - if (is_new) { - /* allocate new header for rtt_results */ - rtt_results_header = kzalloc(sizeof(rtt_results_header_t), GFP_KERNEL); - if (!rtt_results_header) { - if (!in_atomic()) { - mutex_unlock(&rtt_status->rtt_mutex); - } - ret = -ENOMEM; - goto exit; - } - /* Initialize the head of list for rtt result */ - INIT_LIST_HEAD(&rtt_results_header->result_list); - rtt_results_header->peer_mac = event->addr; - list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache); - } - if (tlvs_len > 0) { - /* allocate rtt_results for new results */ - rtt_result = kzalloc(sizeof(rtt_result_t), kflags); - if (!rtt_result) { - if (!in_atomic()) { - mutex_unlock(&rtt_status->rtt_mutex); - } - ret = -ENOMEM; - goto exit; - } - /* unpack TLVs and invokes the cbfn to print the event content TLVs */ - ret = bcm_unpack_xtlv_buf((void *) &(rtt_result->report), - (uint8 *)&p_event->tlvs[0], tlvs_len, - BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); - if (ret != BCME_OK) { - DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", - __FUNCTION__)); - goto exit; - } - /* fill out the results from the configuration param */ - rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst; - rtt_result->report.type = RTT_TWO_WAY; - DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num)); - rtt_result->report_len = RTT_REPORT_SIZE; - - list_add_tail(&rtt_result->list, &rtt_results_header->result_list); - rtt_results_header->result_cnt++; - rtt_results_header->result_tot_len += rtt_result->report_len; - } - break; - case WL_PROXD_EVENT_SESSION_END: - DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n")); - if (tlvs_len > 0) { - /* unpack TLVs and invokes the cbfn to print the event content TLVs */ - ret = bcm_unpack_xtlv_buf((void *) &session_status, - (uint8 *)&p_event->tlvs[0], tlvs_len, - BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); - if (ret != BCME_OK) { - DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", - __FUNCTION__)); - goto exit; - } - } - /* find next target to trigger RTT */ - for (idx = (rtt_status->cur_idx + 1); - idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { - /* skip the disabled device */ - if (rtt_status->rtt_config.target_info[idx].disable) { - continue; - } else { - /* set the idx to cur_idx */ - rtt_status->cur_idx = idx; - break; - } - } - if (idx < rtt_status->rtt_config.rtt_target_cnt) { - /* restart to measure RTT from next device */ - schedule_work(&rtt_status->work); - } else { - DHD_RTT(("RTT_STOPPED\n")); - rtt_status->status = RTT_STOPPED; - /* to turn on mpc mode */ - schedule_work(&rtt_status->work); - /* notify the completed information to others */ - list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { - iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache); - } - /* remove the rtt results in cache */ - if (!list_empty(&rtt_status->rtt_results_cache)) { - /* Iterate rtt_results_header list */ - list_for_each_entry_safe(entry, next, - &rtt_status->rtt_results_cache, list) { - list_del(&entry->list); - /* Iterate rtt_result list */ - list_for_each_entry_safe(rtt_result, next2, - &entry->result_list, list) { - list_del(&rtt_result->list); - kfree(rtt_result); - } - kfree(entry); - } - } - - /* reinitialize the HEAD */ - INIT_LIST_HEAD(&rtt_status->rtt_results_cache); - /* clear information for rtt_config */ - rtt_status->rtt_config.rtt_target_cnt = 0; - memset(rtt_status->rtt_config.target_info, 0, - TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); - rtt_status->cur_idx = 0; - } - break; - case WL_PROXD_EVENT_SESSION_RESTART: - DHD_RTT(("WL_PROXD_EVENT_SESSION_RESTART\n")); - break; - case WL_PROXD_EVENT_BURST_RESCHED: - DHD_RTT(("WL_PROXD_EVENT_BURST_RESCHED\n")); - break; - case WL_PROXD_EVENT_SESSION_DESTROY: - DHD_RTT(("WL_PROXD_EVENT_SESSION_DESTROY\n")); - break; - case WL_PROXD_EVENT_FTM_FRAME: - DHD_RTT(("WL_PROXD_EVENT_FTM_FRAME\n")); - break; - case WL_PROXD_EVENT_DELAY: - DHD_RTT(("WL_PROXD_EVENT_DELAY\n")); - break; - case WL_PROXD_EVENT_VS_INITIATOR_RPT: - DHD_RTT(("WL_PROXD_EVENT_VS_INITIATOR_RPT\n ")); - break; - case WL_PROXD_EVENT_RANGING: - DHD_RTT(("WL_PROXD_EVENT_RANGING\n")); - break; - - default: - DHD_ERROR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type)); - break; - } - if (!in_atomic()) { - mutex_unlock(&rtt_status->rtt_mutex); - } -exit: - return ret; -} - -static void -dhd_rtt_work(struct work_struct *work) -{ - rtt_status_info_t *rtt_status; - dhd_pub_t *dhd; - rtt_status = container_of(work, rtt_status_info_t, work); - if (rtt_status == NULL) { - DHD_ERROR(("%s : rtt_status is NULL\n", __FUNCTION__)); - return; - } - dhd = rtt_status->dhd; - if (dhd == NULL) { - DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); - return; - } - (void) dhd_rtt_start(dhd); -} - -int -dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa) -{ - rtt_status_info_t *rtt_status; - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - NULL_CHECK(capa, "capa is NULL", err); - bzero(capa, sizeof(rtt_capabilities_t)); - switch (rtt_status->rtt_capa.proto) { - case RTT_CAP_ONE_WAY: - capa->rtt_one_sided_supported = 1; - break; - case RTT_CAP_FTM_WAY: - capa->rtt_ftm_supported = 1; - break; - } - - switch (rtt_status->rtt_capa.feature) { - case RTT_FEATURE_LCI: - capa->lci_support = 1; - break; - case RTT_FEATURE_LCR: - capa->lcr_support = 1; - break; - case RTT_FEATURE_PREAMBLE: - capa->preamble_support = 1; - break; - case RTT_FEATURE_BW: - capa->bw_support = 1; - break; - } - /* bit mask */ - capa->preamble_support = rtt_status->rtt_capa.preamble; - capa->bw_support = rtt_status->rtt_capa.bw; - - return err; -} - -int -dhd_rtt_init(dhd_pub_t *dhd) -{ - int err = BCME_OK, ret; - int32 up = 1; - int32 version; - rtt_status_info_t *rtt_status; - NULL_CHECK(dhd, "dhd is NULL", err); - if (dhd->rtt_state) { - return err; - } - dhd->rtt_state = kzalloc(sizeof(rtt_status_info_t), GFP_KERNEL); - if (dhd->rtt_state == NULL) { - err = BCME_NOMEM; - DHD_ERROR(("%s : failed to create rtt_state\n", __FUNCTION__)); - return err; - } - bzero(dhd->rtt_state, sizeof(rtt_status_info_t)); - rtt_status = GET_RTTSTATE(dhd); - rtt_status->rtt_config.target_info = - kzalloc(TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT), GFP_KERNEL); - if (rtt_status->rtt_config.target_info == NULL) { - DHD_ERROR(("%s failed to allocate the target info for %d\n", - __FUNCTION__, RTT_MAX_TARGET_CNT)); - err = BCME_NOMEM; - goto exit; - } - rtt_status->dhd = dhd; - /* need to do WLC_UP */ - dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(int32), TRUE, 0); - - ret = dhd_rtt_get_version(dhd, &version); - if (ret == BCME_OK && (version == WL_PROXD_API_VERSION)) { - DHD_ERROR(("%s : FTM is supported\n", __FUNCTION__)); - /* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */ - rtt_status->rtt_capa.proto |= RTT_CAP_FTM_WAY; - - /* indicate to set tx rate */ - rtt_status->rtt_capa.feature |= RTT_FEATURE_PREAMBLE; - rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_VHT; - rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_HT; - - /* indicate to set bandwith */ - rtt_status->rtt_capa.feature |= RTT_FEATURE_BW; - rtt_status->rtt_capa.bw |= RTT_BW_20; - rtt_status->rtt_capa.bw |= RTT_BW_40; - rtt_status->rtt_capa.bw |= RTT_BW_80; - } else { - if ((ret != BCME_OK) || (version == 0)) { - DHD_ERROR(("%s : FTM is not supported\n", __FUNCTION__)); - } else { - DHD_ERROR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n", - __FUNCTION__, WL_PROXD_API_VERSION, version)); - } - } - mutex_init(&rtt_status->rtt_mutex); - INIT_LIST_HEAD(&rtt_status->noti_fn_list); - INIT_LIST_HEAD(&rtt_status->rtt_results_cache); - INIT_WORK(&rtt_status->work, dhd_rtt_work); -exit: - if (err < 0) { - kfree(rtt_status->rtt_config.target_info); - kfree(dhd->rtt_state); - } - return err; -} - -int -dhd_rtt_deinit(dhd_pub_t *dhd) -{ - int err = BCME_OK; - rtt_status_info_t *rtt_status; - rtt_results_header_t *rtt_header, *next; - rtt_result_t *rtt_result, *next2; - struct rtt_noti_callback *iter, *iter2; - NULL_CHECK(dhd, "dhd is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - rtt_status->status = RTT_STOPPED; - /* clear evt callback list */ - if (!list_empty(&rtt_status->noti_fn_list)) { - list_for_each_entry_safe(iter, iter2, &rtt_status->noti_fn_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - /* remove the rtt results */ - if (!list_empty(&rtt_status->rtt_results_cache)) { - list_for_each_entry_safe(rtt_header, next, &rtt_status->rtt_results_cache, list) { - list_del(&rtt_header->list); - list_for_each_entry_safe(rtt_result, next2, - &rtt_header->result_list, list) { - list_del(&rtt_result->list); - kfree(rtt_result); - } - kfree(rtt_header); - } - } - kfree(rtt_status->rtt_config.target_info); - kfree(dhd->rtt_state); - dhd->rtt_state = NULL; - return err; -} diff --git a/drivers/net/wireless/bcmdhd/dhd_rtt.h b/drivers/net/wireless/bcmdhd/dhd_rtt.h deleted file mode 100644 index 08216dbc8d08..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_rtt.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Header file of Broadcom Dongle Host Driver (DHD) - * Copyright (C) 1999-2014, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_rtt.h 423669 2014-07-01 13:01:56Z $ - */ -#ifndef __DHD_RTT_H__ -#define __DHD_RTT_H__ - -#include "dngl_stats.h" - -#define RTT_MAX_TARGET_CNT 50 -#define RTT_MAX_FRAME_CNT 25 -#define RTT_MAX_RETRY_CNT 10 -#define DEFAULT_FTM_CNT 6 -#define DEFAULT_RETRY_CNT 6 -#define TARGET_INFO_SIZE(count) (sizeof(rtt_target_info_t) * count) - -#define TARGET_TYPE(target) (target->type) - -#ifndef BIT -#define BIT(x) (1 << (x)) -#endif - -/* DSSS, CCK and 802.11n rates in [500kbps] units */ -#define WL_MAXRATE 108 /* in 500kbps units */ -#define WL_RATE_1M 2 /* in 500kbps units */ -#define WL_RATE_2M 4 /* in 500kbps units */ -#define WL_RATE_5M5 11 /* in 500kbps units */ -#define WL_RATE_11M 22 /* in 500kbps units */ -#define WL_RATE_6M 12 /* in 500kbps units */ -#define WL_RATE_9M 18 /* in 500kbps units */ -#define WL_RATE_12M 24 /* in 500kbps units */ -#define WL_RATE_18M 36 /* in 500kbps units */ -#define WL_RATE_24M 48 /* in 500kbps units */ -#define WL_RATE_36M 72 /* in 500kbps units */ -#define WL_RATE_48M 96 /* in 500kbps units */ -#define WL_RATE_54M 108 /* in 500kbps units */ - - -enum rtt_role { - RTT_INITIATOR = 0, - RTT_TARGET = 1 -}; -enum rtt_status { - RTT_STOPPED = 0, - RTT_STARTED = 1, - RTT_ENABLED = 2 -}; -typedef int64_t wifi_timestamp; /* In microseconds (us) */ -typedef int64_t wifi_timespan; -typedef int32 wifi_rssi; - -typedef enum { - RTT_INVALID, - RTT_ONE_WAY, - RTT_TWO_WAY, - RTT_AUTO -} rtt_type_t; - -typedef enum { - RTT_PEER_STA, - RTT_PEER_AP, - RTT_PEER_P2P, - RTT_PEER_NAN, - RTT_PEER_INVALID -} rtt_peer_type_t; - -typedef enum rtt_reason { - RTT_REASON_SUCCESS, - RTT_REASON_FAILURE, - RTT_REASON_FAIL_NO_RSP, - RTT_REASON_FAIL_INVALID_TS, /* Invalid timestamp */ - RTT_REASON_FAIL_PROTOCOL, /* 11mc protocol failed */ - RTT_REASON_FAIL_REJECTED, - RTT_REASON_FAIL_NOT_SCHEDULED_YET, - RTT_REASON_FAIL_SCHEDULE, /* schedule failed */ - RTT_REASON_FAIL_TM_TIMEOUT, - RTT_REASON_FAIL_AP_ON_DIFF_CHANNEL, - RTT_REASON_FAIL_NO_CAPABILITY, - RTT_REASON_FAIL_BUSY_TRY_LATER, - RTT_REASON_ABORTED -} rtt_reason_t; - -enum { - RTT_CAP_ONE_WAY = BIT(0), - /* IEEE802.11mc */ - RTT_CAP_FTM_WAY = BIT(1) -}; - -enum { - RTT_FEATURE_LCI = BIT(0), - RTT_FEATURE_LCR = BIT(1), - RTT_FEATURE_PREAMBLE = BIT(2), - RTT_FEATURE_BW = BIT(3) -}; - -enum { - RTT_PREAMBLE_LEGACY = BIT(0), - RTT_PREAMBLE_HT = BIT(1), - RTT_PREAMBLE_VHT = BIT(2) -}; - - -enum { - RTT_BW_5 = BIT(0), - RTT_BW_10 = BIT(1), - RTT_BW_20 = BIT(2), - RTT_BW_40 = BIT(3), - RTT_BW_80 = BIT(4), - RTT_BW_160 = BIT(5) -}; - -enum rtt_rate_bw { - RTT_RATE_20M, - RTT_RATE_40M, - RTT_RATE_80M, - RTT_RATE_160M -}; - -#define FTM_MAX_NUM_BURST_EXP 14 -#define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) -#define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) -#define HAS_RTT_CAP(cap) (HAS_ONEWAY_CAP(cap) || HAS_11MC_CAP(cap)) - -typedef struct wifi_channel_info { - wifi_channel_width_t width; - wifi_channel center_freq; /* primary 20 MHz channel */ - wifi_channel center_freq0; /* center freq (MHz) first segment */ - wifi_channel center_freq1; /* center freq (MHz) second segment valid for 80 + 80 */ -} wifi_channel_info_t; - -typedef struct wifi_rate { - uint32 preamble :3; /* 0: OFDM, 1: CCK, 2 : HT, 3: VHT, 4..7 reserved */ - uint32 nss :2; /* 1 : 1x1, 2: 2x2, 3: 3x3, 4: 4x4 */ - uint32 bw :3; /* 0: 20Mhz, 1: 40Mhz, 2: 80Mhz, 3: 160Mhz */ - /* OFDM/CCK rate code would be as per IEEE std in the unit of 0.5 mb - * HT/VHT it would be mcs index - */ - uint32 rateMcsIdx :8; - uint32 reserved :16; /* reserved */ - uint32 bitrate; /* unit of 100 Kbps */ -} wifi_rate_t; - -typedef struct rtt_target_info { - struct ether_addr addr; - rtt_type_t type; /* rtt_type */ - rtt_peer_type_t peer; /* peer type */ - wifi_channel_info_t channel; /* channel information */ - chanspec_t chanspec; /* chanspec for channel */ - bool disable; /* disable for RTT measurement */ - uint32 interval; /* interval of RTT measurement (unit ms) when continuous = true */ - uint16 num_burst; /* total number of RTT bursts when multi_burst = 1 */ - uint32 num_frames_per_burst; - /* num of frames in each RTT burst - * for single side, measurement result num = frame number - * for 2 side RTT, measurement result num = frame number - 1 - */ - uint32 num_retries_per_ftm; /* retry time for RTT measurment frame */ - /* following fields are only valid for 2 side RTT */ - uint32 num_retries_per_ftmr; - uint8 LCI_request; - uint8 LCR_request; - uint32 burst_timeout; - uint8 preamble; /* 0 - Legacy, 1 - HT, 2 - VHT */ - uint8 bw; /* 5, 10, 20, 40, 80, 160 */ -} rtt_target_info_t; - - -typedef struct rtt_report { - struct ether_addr addr; - unsigned int burst_num; /* # of burst inside a multi-burst request */ - unsigned int ftm_num; /* total RTT measurement frames */ - unsigned int success_num; /* total successful RTT measurement frames */ - uint8 num_per_burst_peer; /* max number of FTM number per burst the peer support */ - rtt_reason_t status; /* raging status */ - /* in s, 11mc only, only for RTT_REASON_FAIL_BUSY_TRY_LATER, 1- 31s */ - uint8 retry_after_duration; - rtt_type_t type; /* rtt type */ - wifi_rssi rssi; /* average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB */ - wifi_rssi rssi_spread; /* rssi spread in 0.5 db steps e.g. 5 implies 2.5 spread */ - wifi_rate_t tx_rate; /* tx rate */ - wifi_rate_t rx_rate; /* rx rate */ - wifi_timespan rtt; /* round trip time in 0.1 nanoseconds */ - wifi_timespan rtt_sd; /* rtt standard deviation in 0.1 nanoseconds */ - wifi_timespan rtt_spread; /* difference between max and min rtt times recorded */ - int distance; /* distance in cm (optional) */ - int distance_sd; /* standard deviation in cm (optional) */ - int distance_spread; /* difference between max and min distance recorded (optional) */ - wifi_timestamp ts; /* time of the measurement (in microseconds since boot) */ - int burst_duration; /* in ms, how long the FW time is to fininish one burst measurement */ - bcm_tlv_t *LCI; /* LCI Report */ - bcm_tlv_t *LCR; /* Location Civic Report */ -} rtt_report_t; -#define RTT_REPORT_SIZE (sizeof(rtt_report_t)) - -/* rtt_results_header to maintain rtt result list per mac address */ -typedef struct rtt_results_header { - struct ether_addr peer_mac; - uint32 result_cnt; - uint32 result_tot_len; /* sum of report_len of rtt_result */ - struct list_head list; - struct list_head result_list; -} rtt_results_header_t; - -/* rtt_result to link all of rtt_report */ -typedef struct rtt_result { - struct list_head list; - struct rtt_report report; - int32 report_len; /* total length of rtt_report */ -} rtt_result_t; - -/* RTT Capabilities */ -typedef struct rtt_capabilities { - uint8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */ - uint8 rtt_ftm_supported; /* if ftm rtt data collection is supported */ - uint8 lci_support; /* location configuration information */ - uint8 lcr_support; /* Civic Location */ - uint8 preamble_support; /* bit mask indicate what preamble is supported */ - uint8 bw_support; /* bit mask indicate what BW is supported */ -} rtt_capabilities_t; - -typedef struct rtt_config_params { - int8 rtt_target_cnt; - rtt_target_info_t *target_info; -} rtt_config_params_t; - -typedef void (*dhd_rtt_compl_noti_fn)(void *ctx, void *rtt_data); -/* Linux wrapper to call common dhd_rtt_set_cfg */ -int -dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf); - -int -dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt); - -int -dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, - dhd_rtt_compl_noti_fn noti_fn); - -int -dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn); - -int -dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa); - -/* export to upper layer */ -chanspec_t -dhd_rtt_convert_to_chspec(wifi_channel_info_t channel); - -int -dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params); - -int -dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt); - - -int -dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn); - -int -dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn); - -int -dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); - -int -dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa); - -int -dhd_rtt_init(dhd_pub_t *dhd); - -int -dhd_rtt_deinit(dhd_pub_t *dhd); -#endif /* __DHD_RTT_H__ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c deleted file mode 100644 index 3bc97304da55..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ /dev/null @@ -1,8588 +0,0 @@ -/* - * DHD Bus Module for SDIO - * - * Copyright (C) 1999-2017, Broadcom Corporation - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_sdio.c 559275 2015-05-27 05:20:28Z $ - */ - -#include -#include -#include - -#ifdef BCMEMBEDIMAGE -#include BCMEMBEDIMAGE -#endif /* BCMEMBEDIMAGE */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef PROP_TXSTATUS -#include -#endif -#ifdef DHDTCPACK_SUPPRESS -#include -#endif /* DHDTCPACK_SUPPRESS */ - -bool dhd_mp_halting(dhd_pub_t *dhdp); -extern void bcmsdh_waitfor_iodrain(void *sdh); -extern void bcmsdh_reject_ioreqs(void *sdh, bool reject); -extern bool bcmsdh_fatal_error(void *sdh); - -#ifndef DHDSDIO_MEM_DUMP_FNAME -#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" -#endif - -#define QLEN (1024) /* bulk rx and tx queue lengths */ -#define FCHI (QLEN - 10) -#define FCLOW (FCHI / 2) -#define PRIOMASK 7 - -#define TXRETRIES 2 /* # of retries for tx frames */ -#define READ_FRM_CNT_RETRIES 3 -#ifndef DHD_RXBOUND -#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ -#endif - -#ifndef DHD_TXBOUND -#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ -#endif - -#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ - -#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ -#define MAX_NVRAMBUF_SIZE (6 * 1024) /* max nvram buf size */ -#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */ - -#ifndef DHD_FIRSTREAD -#define DHD_FIRSTREAD 32 -#endif -#if !ISPOWEROF2(DHD_FIRSTREAD) -#error DHD_FIRSTREAD is not a power of 2! -#endif - -/* Total length of frame header for dongle protocol */ -#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) -#define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN) -#define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE - -#ifdef SDTEST -#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) -#else -#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) -#endif - -/* Space for header read, limit for data packets */ -#ifndef MAX_HDR_READ -#define MAX_HDR_READ 32 -#endif -#if !ISPOWEROF2(MAX_HDR_READ) -#error MAX_HDR_READ is not a power of 2! -#endif - -#define MAX_RX_DATASZ 2048 - -/* Maximum milliseconds to wait for F2 to come up */ -#define DHD_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). - */ -#if (PMU_MAX_TRANSITION_DLY <= 1000000) -#undef PMU_MAX_TRANSITION_DLY -#define PMU_MAX_TRANSITION_DLY 1000000 -#endif - -/* hooks for limiting threshold custom tx num in rx processing */ -#define DEFAULT_TXINRX_THRES 0 -#ifndef CUSTOM_TXINRX_THRES -#define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES -#endif - -/* Value for ChipClockCSR during initial setup */ -#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) -#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) - -/* Flags for SDH calls */ -#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) - -/* Packet free applicable unconditionally for sdio and sdspi. Conditional if - * bufpool was present for gspi bus. - */ -#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ - PKTFREE(bus->dhd->osh, pkt, FALSE); -DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); - - -/* Device console log buffer state */ -#define CONSOLE_LINE_MAX 192 -#define CONSOLE_BUFFER_MAX 2024 -typedef struct dhd_console { - uint count; /* Poll interval msec counter */ - uint log_addr; /* Log struct address (fixed) */ - hnd_log_t log; /* Log struct (host copy) */ - uint bufsize; /* Size of log buffer */ - uint8 *buf; /* Log buffer (host copy) */ - uint last; /* Last buffer read index */ -} dhd_console_t; - -#define REMAP_ENAB(bus) ((bus)->remap) -#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) -#define KSO_ENAB(bus) ((bus)->kso) -#define SR_ENAB(bus) ((bus)->_srenab) -#define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto)) -#define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618) -#define MIN_RSRC_SR 0x3 -#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) -#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) -#define RCTL_MACPHY_DISABLE_MASK (1 << 26) -#define RCTL_LOGIC_DISABLE_MASK (1 << 27) - -#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) -#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ -#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ -#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ -#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) -#define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2) -#define OVERFLOW_BLKSZ512_WM 96 -#define OVERFLOW_BLKSZ512_MES 80 - -#define CC_PMUCC3 (0x3) -/* Private data for SDIO bus interaction */ -typedef struct dhd_bus { - dhd_pub_t *dhd; - - bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ - si_t *sih; /* Handle for SI calls */ - char *vars; /* Variables (from CIS and/or other) */ - uint varsz; /* Size of variables buffer */ - uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ - - sdpcmd_regs_t *regs; /* Registers for SDIO core */ - uint sdpcmrev; /* SDIO core revision */ - uint armrev; /* CPU core revision */ - uint ramrev; /* SOCRAM core revision */ - uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ - uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ - uint32 srmemsize; /* Size of SRMEM */ - - uint32 bus; /* gSPI or SDIO bus */ - uint32 bus_num; /* bus number */ - uint32 slot_num; /* slot ID */ - uint32 hostintmask; /* Copy of Host Interrupt Mask */ - uint32 intstatus; /* Intstatus bits (events) pending */ - bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ - bool fcstate; /* State of dongle flow-control */ - - uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ - char *fw_path; /* module_param: path to firmware image */ - char *nv_path; /* module_param: path to nvram vars file */ - const char *nvram_params; /* user specified nvram params. */ - - uint blocksize; /* Block size of SDIO transfers */ - uint roundup; /* Max roundup limit */ - - struct pktq txq; /* Queue length used for flow-control */ - uint8 flowcontrol; /* per prio flow control bitmask */ - uint8 tx_seq; /* Transmit sequence number (next) */ - uint8 tx_max; /* Maximum transmit sequence allowed */ - - uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; - uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ - uint16 nextlen; /* Next Read Len from last header */ - uint8 rx_seq; /* Receive sequence number (expected) */ - bool rxskip; /* Skip receive (awaiting NAK ACK) */ - - void *glomd; /* Packet containing glomming descriptor */ - void *glom; /* Packet chain for glommed superframe */ - uint glomerr; /* Glom packet read errors */ - - uint8 *rxbuf; /* Buffer for receiving control packets */ - uint rxblen; /* Allocated length of rxbuf */ - uint8 *rxctl; /* Aligned pointer into rxbuf */ - uint8 *databuf; /* Buffer for receiving big glom packet */ - uint8 *dataptr; /* Aligned pointer into databuf */ - uint rxlen; /* Length of valid data in buffer */ - - uint8 sdpcm_ver; /* Bus protocol reported by dongle */ - - bool intr; /* Use interrupts */ - bool poll; /* Use polling */ - bool ipend; /* Device interrupt is pending */ - bool intdis; /* Interrupts disabled by isr */ - 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 DHD_DEBUG - dhd_console_t console; /* Console output polling support */ - uint console_addr; /* Console address from shared struct */ -#endif /* DHD_DEBUG */ - - uint regfails; /* Count of R_REG/W_REG failures */ - - uint clkstate; /* State of sd and backplane clock(s) */ - bool activity; /* Activity flag for clock down */ - int32 idletime; /* Control for activity timeout */ - int32 idlecount; /* Activity timeout counter */ - int32 idleclock; /* How to set bus driver when idle */ - int32 sd_divisor; /* Speed control to bus driver */ - int32 sd_mode; /* Mode control to bus driver */ - int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ - bool use_rxchain; /* If dhd should use PKT chains */ - bool sleeping; /* Is SDIO bus sleeping? */ - wait_queue_head_t bus_sleep; - uint rxflow_mode; /* Rx flow control mode */ - bool rxflow; /* Is rx flow control on */ - uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ - 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; - int32 txinrx_thres; /* num of in-queued pkts */ - int32 dotxinrx; /* tx first in dhdsdio_readframes */ -#ifdef SDTEST - /* external loopback */ - bool ext_loop; - uint8 loopid; - - /* pktgen configuration */ - uint pktgen_freq; /* Ticks between bursts */ - uint pktgen_count; /* Packets to send each burst */ - uint pktgen_print; /* Bursts between count displays */ - uint pktgen_total; /* Stop after this many */ - uint pktgen_minlen; /* Minimum packet data len */ - uint pktgen_maxlen; /* Maximum packet data len */ - uint pktgen_mode; /* Configured mode: tx, rx, or echo */ - uint pktgen_stop; /* Number of tx failures causing stop */ - - /* active pktgen fields */ - uint pktgen_tick; /* Tick counter for bursts */ - uint pktgen_ptick; /* Burst counter for printing */ - uint pktgen_sent; /* Number of test packets generated */ - uint pktgen_rcvd; /* Number of test packets received */ - uint pktgen_prev_time; /* Time at which previous stats where printed */ - uint pktgen_prev_sent; /* Number of test packets generated when - * previous stats were printed - */ - uint pktgen_prev_rcvd; /* Number of test packets received when - * previous stats were printed - */ - uint pktgen_fail; /* Number of failed send attempts */ - uint16 pktgen_len; /* Length of next packet to send */ -#define PKTGEN_RCV_IDLE (0) -#define PKTGEN_RCV_ONGOING (1) - uint16 pktgen_rcv_state; /* receive state */ - uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ -#endif /* SDTEST */ - - /* 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 */ -#ifdef DHDENABLE_TAILPAD - uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */ - uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */ -#endif /* DHDENABLE_TAILPAD */ - uint8 *ctrl_frame_buf; - uint32 ctrl_frame_len; - bool ctrl_frame_stat; - uint32 rxint_mode; /* rx interrupt mode */ - bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram - * Available with socram rev 16 - * Remap region not DMA-able - */ - bool kso; - bool _slpauto; - bool _oobwakeup; - bool _srenab; - bool readframes; - bool reqbussleep; - uint32 resetinstr; - uint32 dongle_ram_base; - - void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */ - uint32 txglom_cnt; /* Number of pkts in the glom array */ - uint32 txglom_total_len; /* Total length of pkts in glom array */ - bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled */ - uint32 txglomsize; /* Glom size limitation */ -#ifdef DHDENABLE_TAILPAD - void *pad_pkt; -#endif /* DHDENABLE_TAILPAD */ -} dhd_bus_t; - -/* clkstate */ -#define CLK_NONE 0 -#define CLK_SDONLY 1 -#define CLK_PENDING 2 /* Not used yet */ -#define CLK_AVAIL 3 - -#define DHD_NOPMU(dhd) (FALSE) - -#ifdef DHD_DEBUG -static int qcount[NUMPRIO]; -static int tx_packets[NUMPRIO]; -#endif /* DHD_DEBUG */ - -/* Deferred transmit */ -const uint dhd_deferred_tx = 1; - -extern uint dhd_watchdog_ms; - -extern void dhd_os_wd_timer(void *bus, uint wdtick); - -/* Tx/Rx bounds */ -uint dhd_txbound; -uint dhd_rxbound; -uint dhd_txminmax = DHD_TXMINMAX; - -/* override the RAM size if possible */ -#define DONGLE_MIN_RAMSIZE (128 *1024) -int dhd_dongle_ramsize; - -uint dhd_doflow = TRUE; -uint dhd_dpcpoll = FALSE; - -module_param(dhd_doflow, uint, 0644); -module_param(dhd_dpcpoll, uint, 0644); - -static bool dhd_alignctl; - -static bool sd1idle; - -static bool retrydata; -#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) - -static uint watermark = 8; -static uint mesbusyctrl = 0; -static const uint firstread = DHD_FIRSTREAD; - -/* Retry count for register access failures */ -static const uint retry_limit = 2; - -/* Force even SD lengths (some host controllers mess up on odd bytes) */ -static bool forcealign; - -#define ALIGNMENT 4 - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) -extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); -#endif - -#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) -#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD -#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ -#define PKTALIGN(osh, p, len, align) \ - do { \ - uintptr datalign; \ - datalign = (uintptr)PKTDATA((osh), (p)); \ - datalign = ROUNDUP(datalign, (align)) - datalign; \ - ASSERT(datalign < (align)); \ - ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ - if (datalign) \ - PKTPULL((osh), (p), (uint)datalign); \ - PKTSETLEN((osh), (p), (len)); \ - } while (0) - -/* Limit on rounding up frames */ -static const uint max_roundup = 512; - -/* Try doing readahead */ -static bool dhd_readahead; - -/* To check if there's window offered */ -#define DATAOK(bus) \ - (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ - (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) - -/* To check if there's window offered for ctrl frame */ -#define TXCTLOK(bus) \ - (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ - (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) - -/* Number of pkts available in dongle for data RX */ -#define DATABUFCNT(bus) \ - ((uint8)(bus->tx_max - bus->tx_seq) - 1) - -/* Macros to get register read/write status */ -/* NOTE: these assume a local dhdsdio_bus_t *bus! */ -#define R_SDREG(regvar, regaddr, retryvar) \ -do { \ - retryvar = 0; \ - do { \ - regvar = R_REG(bus->dhd->osh, regaddr); \ - } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ - if (retryvar) { \ - bus->regfails += (retryvar-1); \ - if (retryvar > retry_limit) { \ - DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \ - __FUNCTION__, __LINE__)); \ - regvar = 0; \ - } \ - } \ -} while (0) - -#define W_SDREG(regval, regaddr, retryvar) \ -do { \ - retryvar = 0; \ - do { \ - W_REG(bus->dhd->osh, regaddr, regval); \ - } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ - if (retryvar) { \ - bus->regfails += (retryvar-1); \ - if (retryvar > retry_limit) \ - DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \ - __FUNCTION__, __LINE__)); \ - } \ -} while (0) - -#define BUS_WAKE(bus) \ - do { \ - bus->idlecount = 0; \ - if ((bus)->sleeping) \ - dhdsdio_bussleep((bus), FALSE); \ - } while (0); - -/* - * pktavail interrupts from dongle to host can be managed in 3 different ways - * whenever there is a packet available in dongle to transmit to host. - * - * Mode 0: Dongle writes the software host mailbox and host is interrupted. - * Mode 1: (sdiod core rev >= 4) - * Device sets a new bit in the intstatus whenever there is a packet - * available in fifo. Host can't clear this specific status bit until all the - * packets are read from the FIFO. No need to ack dongle intstatus. - * Mode 2: (sdiod core rev >= 4) - * Device sets a bit in the intstatus, and host acks this by writing - * one to this bit. Dongle won't generate anymore packet interrupts - * until host reads all the packets from the dongle and reads a zero to - * figure that there are no more packets. No need to disable host ints. - * Need to ack the intstatus. - */ - -#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ -#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ -#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ - - -#define FRAME_AVAIL_MASK(bus) \ - ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) - -#define DHD_BUS SDIO_BUS - -#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) - -#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) - -#define GSPI_PR55150_BAILOUT - -#ifdef SDTEST -static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); -static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count); -#endif - -static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); -#ifdef DHD_DEBUG -static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); -#endif /* DHD_DEBUG */ - -#if defined(DHD_FW_COREDUMP) -static int dhdsdio_mem_dump(dhd_bus_t *bus); -#endif /* DHD_FW_COREDUMP */ -static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap); -static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); - -static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); -static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); -static void dhdsdio_disconnect(void *ptr); -static bool dhdsdio_chipmatch(uint16 chipid); -static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, - void * regsva, uint16 devid); -static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); -static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); -static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, - bool reset_flag); - -static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size); -static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); -static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry); -static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt); -static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, - int prev_chain_total_len, bool last_chained_pkt, - int *pad_pkt_len, void **new_pkt); -static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt); - -static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); -static int _dhdsdio_download_firmware(dhd_bus_t *bus); - -static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); -static int dhdsdio_download_nvram(dhd_bus_t *bus); -#ifdef BCMEMBEDIMAGE -static int dhdsdio_download_code_array(dhd_bus_t *bus); -#endif -static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep); -static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok); -static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus); - -#ifdef WLMEDIA_HTSF -#include -extern uint32 dhd_get_htsf(void *dhd, int ifidx); -#endif /* WLMEDIA_HTSF */ - -static void -dhdsdio_tune_fifoparam(struct dhd_bus *bus) -{ - int err; - uint8 devctl, wm, mes; - - if (bus->sih->buscorerev >= 15) { - /* See .ppt in PR for these recommended values */ - if (bus->blocksize == 512) { - wm = OVERFLOW_BLKSZ512_WM; - mes = OVERFLOW_BLKSZ512_MES; - } else { - mes = bus->blocksize/4; - wm = bus->blocksize/4; - } - - watermark = wm; - mesbusyctrl = mes; - } else { - DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n", - bus->sih->buscorerev)); - return; - } - - /* Update watermark */ - if (wm > 0) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err); - - devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl |= SBSDIO_DEVCTL_F2WM_ENAB; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - } - - /* Update MES */ - if (mes > 0) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, - (mes | SBSDIO_MESBUSYCTRL_ENAB), &err); - } - - DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n", - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err), - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err), - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err))); -} - -static void -dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size) -{ - int32 min_size = DONGLE_MIN_RAMSIZE; - /* Restrict the ramsize to user specified limit */ - DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", - dhd_dongle_ramsize, min_size)); - if ((dhd_dongle_ramsize > min_size) && - (dhd_dongle_ramsize < (int32)bus->orig_ramsize)) - bus->ramsize = dhd_dongle_ramsize; -} - -static int -dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) -{ - int err = 0; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, - (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); - if (!err) - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, - (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); - if (!err) - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, - (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); - return err; -} - - -#ifdef USE_OOB_GPIO1 -static int -dhdsdio_oobwakeup_init(dhd_bus_t *bus) -{ - uint32 val, addr, data; - - bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP); - - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - - /* Set device for gpio1 wakeup */ - bcmsdh_reg_write(bus->sdh, addr, 4, 2); - val = bcmsdh_reg_read(bus->sdh, data, 4); - val |= CC_CHIPCTRL2_GPIO1_WAKEUP; - bcmsdh_reg_write(bus->sdh, data, 4, val); - - bus->_oobwakeup = TRUE; - - return 0; -} -#endif /* USE_OOB_GPIO1 */ - -/* - * Query if FW is in SR mode - */ -static bool -dhdsdio_sr_cap(dhd_bus_t *bus) -{ - bool cap = FALSE; - uint32 core_capext, addr, data; - - if (bus->sih->chip == BCM43430_CHIP_ID) { - /* check if fw initialized sr engine */ - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, sr_control1); - if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0) - cap = TRUE; - - return cap; - } - if (bus->sih->chip == BCM4324_CHIP_ID) { - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - bcmsdh_reg_write(bus->sdh, addr, 4, 3); - core_capext = bcmsdh_reg_read(bus->sdh, data, 4); - } else if (bus->sih->chip == BCM4330_CHIP_ID) { - core_capext = FALSE; - } else if ((bus->sih->chip == BCM4335_CHIP_ID) || - (bus->sih->chip == BCM4339_CHIP_ID) || - (bus->sih->chip == BCM43349_CHIP_ID) || - (bus->sih->chip == BCM4345_CHIP_ID) || - (bus->sih->chip == BCM4354_CHIP_ID) || - (bus->sih->chip == BCM4356_CHIP_ID) || - (bus->sih->chip == BCM4358_CHIP_ID) || - (BCM4349_CHIP(bus->sih->chip)) || - (bus->sih->chip == BCM4350_CHIP_ID)) { - core_capext = TRUE; - } else { - core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); - core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK); - } - if (!(core_capext)) - return FALSE; - - if (bus->sih->chip == BCM4324_CHIP_ID) { - /* FIX: Should change to query SR control register instead */ - cap = TRUE; - } else if ((bus->sih->chip == BCM4335_CHIP_ID) || - (bus->sih->chip == BCM4339_CHIP_ID) || - (bus->sih->chip == BCM43349_CHIP_ID) || - (bus->sih->chip == BCM4345_CHIP_ID) || - (bus->sih->chip == BCM4354_CHIP_ID) || - (bus->sih->chip == BCM4356_CHIP_ID) || - (bus->sih->chip == BCM4358_CHIP_ID) || - (bus->sih->chip == BCM4350_CHIP_ID)) { - uint32 enabval = 0; - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); - enabval = bcmsdh_reg_read(bus->sdh, data, 4); - - if ((bus->sih->chip == BCM4350_CHIP_ID) || - (bus->sih->chip == BCM4345_CHIP_ID) || - (bus->sih->chip == BCM4354_CHIP_ID) || - (bus->sih->chip == BCM4356_CHIP_ID) || - (bus->sih->chip == BCM4358_CHIP_ID)) - enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE; - - if (enabval) - cap = TRUE; - } else { - data = bcmsdh_reg_read(bus->sdh, - SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4); - if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) - cap = TRUE; - } - - return cap; -} - -static int -dhdsdio_srwar_init(dhd_bus_t *bus) -{ - bcmsdh_gpio_init(bus->sdh); - -#ifdef USE_OOB_GPIO1 - dhdsdio_oobwakeup_init(bus); -#endif - - - return 0; -} - -static int -dhdsdio_sr_init(dhd_bus_t *bus) -{ - uint8 val; - int err = 0; - - if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) - dhdsdio_srwar_init(bus); - - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); - val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, - 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); - -#ifdef USE_CMD14 - /* Add CMD14 Support */ - dhdsdio_devcap_set(bus, - (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT)); -#endif /* USE_CMD14 */ - - dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err); - - bus->_slpauto = dhd_slpauto ? TRUE : FALSE; - - bus->_srenab = TRUE; - - return 0; -} - -/* - * FIX: Be sure KSO bit is enabled - * Currently, it's defaulting to 0 which should be 1. - */ -static int -dhdsdio_clk_kso_init(dhd_bus_t *bus) -{ - uint8 val; - int err = 0; - - /* set flag */ - bus->kso = TRUE; - - /* - * Enable KeepSdioOn (KSO) bit for normal operation - * Default is 0 (4334A0) so set it. Fixed in B0. - */ - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL); - if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { - val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); - if (err) - DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err)); - } - - return 0; -} - -#define KSO_DBG(x) -#define KSO_WAIT_US 50 -#define KSO_WAIT_MS 1 -#define KSO_SLEEP_RETRY_COUNT 20 -#define ERROR_BCME_NODEVICE_MAX 1 - -#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) -static int -dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) -{ - uint8 wr_val = 0, rd_val, cmp_val, bmask; - int err = 0; - int try_cnt = 0; - - KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); - - wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); - - if (on) { - cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; - bmask = cmp_val; - - OSL_SLEEP(3); - } else { - /* Put device to sleep, turn off KSO */ - cmp_val = 0; - bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; - } - - do { - rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); - if (((rd_val & bmask) == cmp_val) && !err) - break; - - KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); - - if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) { - OSL_SLEEP(KSO_WAIT_MS); - } else - OSL_DELAY(KSO_WAIT_US); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); - } while (try_cnt++ < MAX_KSO_ATTEMPTS); - - - if (try_cnt > 2) - KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", - __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); - - if (try_cnt > MAX_KSO_ATTEMPTS) { - DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", - __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); - } - return err; -} - -static int -dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) -{ - int err = 0; - - if (on == FALSE) { - - BUS_WAKE(bus); - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__, - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err))); - dhdsdio_clk_kso_enab(bus, FALSE); - } else { - DHD_ERROR(("%s: KSO enable\n", __FUNCTION__)); - - /* Make sure we have SD bus access */ - if (bus->clkstate == CLK_NONE) { - DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__)); - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - - dhdsdio_clk_kso_enab(bus, TRUE); - - DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__, - dhdsdio_sleepcsr_get(bus))); - } - - bus->kso = on; - BCM_REFERENCE(err); - - return 0; -} - -static uint8 -dhdsdio_sleepcsr_get(dhd_bus_t *bus) -{ - int err = 0; - uint8 val = 0; - - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); - if (err) - DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err)); - - return val; -} - -uint8 -dhdsdio_devcap_get(dhd_bus_t *bus) -{ - return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL); -} - -static int -dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap) -{ - int err = 0; - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err); - if (err) - DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err)); - - return 0; -} - -static int -dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) -{ - int err = 0, retry; - uint8 val; - - retry = 0; - if (on == TRUE) { - /* Enter Sleep */ - - /* Be sure we request clk before going to sleep - * so we can wake-up with clk request already set - * else device can go back to sleep immediately - */ - if (!SLPAUTO_ENAB(bus)) - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - else { - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if ((val & SBSDIO_CSR_MASK) == 0) { - DHD_ERROR(("%s: No clock before enter sleep:0x%x\n", - __FUNCTION__, val)); - - /* Reset clock request */ - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_ALP_AVAIL_REQ, &err); - DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__, - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err))); - } - } - - DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__, - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err))); -#ifdef USE_CMD14 - err = bcmsdh_sleep(bus->sdh, TRUE); -#else - err = dhdsdio_clk_kso_enab(bus, FALSE); - if (OOB_WAKEUP_ENAB(bus)) - { - err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ - } -#endif /* USE_CMD14 */ - } else { - /* Exit Sleep */ - /* Make sure we have SD bus access */ - if (bus->clkstate == CLK_NONE) { - DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__)); - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - - if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { - SPINWAIT_SLEEP(sdioh_spinwait_sleep, - (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), - GPIO_DEV_SRSTATE_TIMEOUT); - - if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { - DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n")); - } - } -#ifdef USE_CMD14 - err = bcmsdh_sleep(bus->sdh, FALSE); - if (SLPAUTO_ENAB(bus) && (err != 0)) { - OSL_DELAY(10000); - DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__)); - - /* Toggle sleep to resync with host and device */ - err = bcmsdh_sleep(bus->sdh, TRUE); - OSL_DELAY(10000); - err = bcmsdh_sleep(bus->sdh, FALSE); - - if (err) { - OSL_DELAY(10000); - DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__)); - - /* Toggle sleep to resync with host and device */ - err = bcmsdh_sleep(bus->sdh, TRUE); - OSL_DELAY(10000); - err = bcmsdh_sleep(bus->sdh, FALSE); - if (err) { - DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__)); - DHD_ERROR(("%s: FATAL: Device non-response!\n", - __FUNCTION__)); - err = 0; - } - } - } -#else - if (OOB_WAKEUP_ENAB(bus)) - { - err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ - } - do { - err = dhdsdio_clk_kso_enab(bus, TRUE); - if (err) - OSL_SLEEP(10); - } while ((err != 0) && (++retry < 3)); - - if (err != 0) { - DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry)); - err = 0; /* continue anyway */ - } -#endif /* !USE_CMD14 */ - - if (err == 0) { - uint8 csr; - - /* Wait for device ready during transition to wake-up */ - SPINWAIT_SLEEP(sdioh_spinwait_sleep, - (((csr = dhdsdio_sleepcsr_get(bus)) & - SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != - (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); - - DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr)); - - if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) { - DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n", - __FUNCTION__, csr)); - err = BCME_NODEVICE; - } - - SPINWAIT_SLEEP(sdioh_spinwait_sleep, - (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != - (SBSDIO_HT_AVAIL)), (10000)); - - DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr)); - if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) { - DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n", - __FUNCTION__, csr)); - err = BCME_NODEVICE; - } - } - } - - /* Update if successful */ - if (err == 0) - bus->kso = on ? FALSE : TRUE; - else { - DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n", - __FUNCTION__, bus->kso, on, err)); - if (!on && retry > 2) - bus->kso = FALSE; - } - - return err; -} - -/* Turn backplane clock on or off */ -static int -dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) -{ -#define HT_AVAIL_ERROR_MAX 10 - static int ht_avail_error = 0; - int err; - uint8 clkctl, clkreq, devctl; - bcmsdh_info_t *sdh; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - clkctl = 0; - sdh = bus->sdh; - - - if (!KSO_ENAB(bus)) - return BCME_OK; - - if (SLPAUTO_ENAB(bus)) { - bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); - return BCME_OK; - } - - if (on) { - /* Request HT Avail */ - clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; - - - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); - if (err) { - ht_avail_error++; - if (ht_avail_error < HT_AVAIL_ERROR_MAX) { - DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - else if (ht_avail_error == HT_AVAIL_ERROR_MAX) { -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - "%s ht_avail_error = %d\n", __func__, ht_avail_error); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - dhd_os_send_hang_message(bus->dhd); - } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ - return BCME_ERROR; - } else { - ht_avail_error = 0; - } - - - /* Check current status */ - clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (err) { - DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err)); - return BCME_ERROR; - } - -#if !defined(OOB_INTR_ONLY) - /* Go to pending and await interrupt if appropriate */ - if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { - /* Allow only clock-available interrupt */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - if (err) { - DHD_ERROR(("%s: Devctl access error setting CA: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - - devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - DHD_INFO(("CLKCTL: set PENDING\n")); - bus->clkstate = CLK_PENDING; - return BCME_OK; - } else -#endif /* !defined (OOB_INTR_ONLY) */ - { - if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - } - } - - /* Otherwise, wait here (polling) for HT Avail */ - if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - SPINWAIT_SLEEP(sdioh_spinwait_sleep, - ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err)), - !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); - } - if (err) { - DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); - return BCME_ERROR; - } - if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n", - __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl)); - return BCME_ERROR; - } - - /* Mark clock available */ - bus->clkstate = CLK_AVAIL; - DHD_INFO(("CLKCTL: turned ON\n")); - -#if defined(DHD_DEBUG) - if (bus->alp_only == TRUE) { -#if !defined(BCMLXSDMMC) - if (!SBSDIO_ALPONLY(clkctl)) { - DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__)); - } -#endif /* !defined(BCMLXSDMMC) */ - } else { - if (SBSDIO_ALPONLY(clkctl)) { - DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__)); - } - } -#endif /* defined (DHD_DEBUG) */ - - bus->activity = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - } else { - clkreq = 0; - - if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - } - - bus->clkstate = CLK_SDONLY; - if (!SR_ENAB(bus)) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); - DHD_INFO(("CLKCTL: turned OFF\n")); - if (err) { - DHD_ERROR(("%s: Failed access turning clock off: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - } - return BCME_OK; -} - -/* Change idle/active SD state */ -static int -dhdsdio_sdclk(dhd_bus_t *bus, bool on) -{ - int err; - int32 iovalue; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (on) { - if (bus->idleclock == DHD_IDLE_STOP) { - /* Turn on clock and restore mode */ - iovalue = 1; - err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error enabling sd_clock: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - - iovalue = bus->sd_mode; - err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error changing sd_mode: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } else if (bus->idleclock != DHD_IDLE_ACTIVE) { - /* Restore clock speed */ - iovalue = bus->sd_divisor; - err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error restoring sd_divisor: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - bus->clkstate = CLK_SDONLY; - } else { - /* Stop or slow the SD clock itself */ - if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { - DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n", - __FUNCTION__, bus->sd_divisor, bus->sd_mode)); - return BCME_ERROR; - } - if (bus->idleclock == DHD_IDLE_STOP) { - if (sd1idle) { - /* Change to SD1 mode and turn off clock */ - iovalue = 1; - err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error changing sd_clock: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - - iovalue = 0; - err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error disabling sd_clock: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } else if (bus->idleclock != DHD_IDLE_ACTIVE) { - /* Set divisor to idle value */ - iovalue = bus->idleclock; - err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error changing sd_divisor: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - bus->clkstate = CLK_NONE; - } - - return BCME_OK; -} - -/* Transition SD and backplane clock readiness */ -static int -dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) -{ - int ret = BCME_OK; -#ifdef DHD_DEBUG - uint oldstate = bus->clkstate; -#endif /* DHD_DEBUG */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Early exit if we're already there */ - if (bus->clkstate == target) { - if (target == CLK_AVAIL) { - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - bus->activity = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - } - return ret; - } - - switch (target) { - case CLK_AVAIL: - /* Make sure SD clock is available */ - if (bus->clkstate == CLK_NONE) - dhdsdio_sdclk(bus, TRUE); - /* Now request HT Avail on the backplane */ - ret = dhdsdio_htclk(bus, TRUE, pendok); - if (ret == BCME_OK) { - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - bus->activity = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - } - break; - - case CLK_SDONLY: - /* Remove HT request, or bring up SD clock */ - if (bus->clkstate == CLK_NONE) - ret = dhdsdio_sdclk(bus, TRUE); - else if (bus->clkstate == CLK_AVAIL) - ret = dhdsdio_htclk(bus, FALSE, FALSE); - else - DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", - bus->clkstate, target)); - if (ret == BCME_OK) { - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - } - break; - - case CLK_NONE: - /* Make sure to remove HT request */ - if (bus->clkstate == CLK_AVAIL) - ret = dhdsdio_htclk(bus, FALSE, FALSE); - /* Now remove the SD clock */ - ret = dhdsdio_sdclk(bus, FALSE); -#ifdef DHD_DEBUG - if (dhd_console_ms == 0) -#endif /* DHD_DEBUG */ - if (bus->poll == 0) - dhd_os_wd_timer(bus->dhd, 0); - break; - } -#ifdef DHD_DEBUG - DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); -#endif /* DHD_DEBUG */ - - return ret; -} - -static int -dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) -{ - int err = 0; - bcmsdh_info_t *sdh = bus->sdh; - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - - DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", - (sleep ? "SLEEP" : "WAKE"), - (bus->sleeping ? "SLEEP" : "WAKE"))); - - if (bus->dhd->hang_was_sent) - return BCME_ERROR; - - /* Done if we're already in the requested state */ - if (sleep == bus->sleeping) - return BCME_OK; - - /* 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 BCME_BUSY; - - - if (!SLPAUTO_ENAB(bus)) { - /* Disable SDIO interrupts (no longer interested) */ - bcmsdh_intr_disable(bus->sdh); - - /* Make sure the controller has the bus up */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Tell device to start using OOB wakeup */ - W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); - - /* Turn off our contribution to the HT clock request */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); - - /* Isolate the bus */ - if (bus->sih->chip != BCM4329_CHIP_ID && - bus->sih->chip != BCM4319_CHIP_ID) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, - SBSDIO_DEVCTL_PADS_ISO, NULL); - } - } else { - /* Leave interrupts enabled since device can exit sleep and - * interrupt host - */ - err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */); - } - - /* Change state */ - bus->sleeping = TRUE; - wake_up(&bus->bus_sleep); - } else { - /* Waking up: bus power up is ok, set local state */ - - if (!SLPAUTO_ENAB(bus)) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err); - - /* Force pad isolation off if possible (in case power never toggled) */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); - - - /* Make sure the controller has the bus up */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Send misc interrupt to indicate OOB not needed */ - W_SDREG(0, ®s->tosbmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); - - /* Make sure we have SD bus access */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - /* Enable interrupts again */ - if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { - bus->intdis = FALSE; - bcmsdh_intr_enable(bus->sdh); - } - } else { - err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */); - } - - if (err == 0) { - /* Change state */ - bus->sleeping = FALSE; - } - } - - return err; -} - - -#if defined(OOB_INTR_ONLY) -void -dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) -{ -#if defined(HW_OOB) - bcmsdh_enable_hw_oob_intr(bus->sdh, enable); -#else - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (enable == TRUE) { - - /* Tell device to start using OOB wakeup */ - W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); - - } else { - /* Send misc interrupt to indicate OOB not needed */ - W_SDREG(0, ®s->tosbmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - } - - /* Turn off our contribution to the HT clock request */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -#endif /* !defined(HW_OOB) */ -} -#endif - -int -dhd_bus_txdata(struct dhd_bus *bus, void *pkt) -{ - int ret = BCME_ERROR; - osl_t *osh; - uint datalen, prec; -#if defined(DHD_TX_DUMP) - uint8 *dump_data; - uint16 protocol; -#endif /* DHD_TX_DUMP */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - osh = bus->dhd->osh; - datalen = PKTLEN(osh, pkt); - -#ifdef SDTEST - /* Push the test header if doing loopback */ - if (bus->ext_loop) { - uint8* data; - PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); - data = PKTDATA(osh, pkt); - *data++ = SDPCM_TEST_ECHOREQ; - *data++ = (uint8)bus->loopid++; - *data++ = (datalen >> 0); - *data++ = (datalen >> 8); - datalen += SDPCM_TEST_HDRLEN; - } -#else /* SDTEST */ - BCM_REFERENCE(datalen); -#endif /* SDTEST */ - -#if defined(DHD_TX_DUMP) - dump_data = PKTDATA(osh, pkt); - dump_data += 4; /* skip 4 bytes header */ - protocol = (dump_data[12] << 8) | dump_data[13]; - - if (protocol == ETHER_TYPE_802_1X) { - DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n", - dump_data[14], dump_data[15], dump_data[30])); - } -#endif /* DHD_TX_DUMP */ - -#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP) - { - int i; - DHD_ERROR(("TX DUMP\n")); - - for (i = 0; i < (datalen - 4); i++) { - DHD_ERROR(("%02X ", dump_data[i])); - if ((i & 15) == 15) - printk("\n"); - } - DHD_ERROR(("\n")); - } -#endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */ - - prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); - - /* Check for existing queue, current flow-control, pending event, or pending clock */ - if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || - (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || - (bus->clkstate != CLK_AVAIL)) { - bool deq_ret; - int pkq_len; - - DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq))); - bus->fcqueued++; - - /* Priority based enq */ - dhd_os_sdlock_txq(bus->dhd); - deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec); - dhd_os_sdunlock_txq(bus->dhd); - - if (!deq_ret) { -#ifdef PROP_TXSTATUS - if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0) -#endif /* PROP_TXSTATUS */ - { -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - dhd_txcomplete(bus->dhd, pkt, FALSE); - PKTFREE(osh, pkt, TRUE); - } - ret = BCME_NORESOURCE; - } else - ret = BCME_OK; - - dhd_os_sdlock_txq(bus->dhd); - pkq_len = pktq_len(&bus->txq); - dhd_os_sdunlock_txq(bus->dhd); - if (pkq_len >= FCHI) { - bool wlfc_enabled = FALSE; -#ifdef PROP_TXSTATUS - wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) != - WLFC_UNSUPPORTED); -#endif - if (!wlfc_enabled && dhd_doflow) { - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); - } - } - -#ifdef DHD_DEBUG - dhd_os_sdlock_txq(bus->dhd); - if (pktq_plen(&bus->txq, prec) > qcount[prec]) - qcount[prec] = pktq_plen(&bus->txq, prec); - dhd_os_sdunlock_txq(bus->dhd); -#endif - - /* Schedule DPC if needed to send queued packet(s) */ - if (dhd_deferred_tx && !bus->dpc_sched) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - } else { - int chan = SDPCM_DATA_CHANNEL; - -#ifdef SDTEST - chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL); -#endif - /* Lock: we're about to use shared data/code (and SDIO) */ - dhd_os_sdlock(bus->dhd); - - /* Otherwise, send it now */ - BUS_WAKE(bus); - /* Make sure back plane ht clk is on, no pending allowed */ - dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); - - ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE); - - if (ret != BCME_OK) - bus->dhd->tx_errors++; - else - bus->dhd->dstats.tx_bytes += datalen; - - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - } - - return ret; -} - -/* align packet data pointer and packet length to n-byte boundary, process packet headers, - * a new packet may be allocated if there is not enough head and/or tail from for padding. - * the caller is responsible for updating the glom size in the head packet (when glom is - * used) - * - * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter - * is taken in tx glom mode only - * - * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment - * padding, NULL if not needed, the caller is responsible for freeing the new packet - * - * return: positive value - length of the packet, including head and tail padding - * negative value - errors - */ -static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, - int prev_chain_total_len, bool last_chained_pkt, - int *pad_pkt_len, void **new_pkt) -{ - osl_t *osh; - uint8 *frame; - int pkt_len; - int modulo; - int head_padding; - int tail_padding = 0; - uint32 swheader; - uint32 swhdr_offset; - bool alloc_new_pkt = FALSE; - uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; - - *new_pkt = NULL; - osh = bus->dhd->osh; - -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - - /* Add space for the SDPCM hardware/software headers */ - PKTPUSH(osh, pkt, sdpcm_hdrlen); - ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); - - frame = (uint8*)PKTDATA(osh, pkt); - pkt_len = (uint16)PKTLEN(osh, pkt); - -#ifdef WLMEDIA_HTSF - frame = (uint8*)PKTDATA(osh, pkt); - if (PKTLEN(osh, pkt) >= 100) { - htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12); - if (htsf_ts->magic == HTSFMAGIC) { - htsf_ts->c20 = get_cycles(); - htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); - } - } -#endif /* WLMEDIA_HTSF */ -#ifdef DHD_DEBUG - if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) - tx_packets[PKTPRIO(pkt)]++; -#endif /* DHD_DEBUG */ - - /* align the data pointer, allocate a new packet if there is not enough space (new - * packet data pointer will be aligned thus no padding will be needed) - */ - head_padding = (ulong)frame % DHD_SDALIGN; - if (PKTHEADROOM(osh, pkt) < head_padding) { - head_padding = 0; - alloc_new_pkt = TRUE; - } else { - uint cur_chain_total_len; - int chain_tail_padding = 0; - - /* All packets need to be aligned by DHD_SDALIGN */ - modulo = (pkt_len + head_padding) % DHD_SDALIGN; - tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; - - /* Total pkt chain length needs to be aligned by block size, - * unless it is a single pkt chain with total length less than one block size, - * which we prefer sending by byte mode. - * - * Do the chain alignment here if - * 1. This is the last pkt of the chain of multiple pkts or a single pkt. - * 2-1. This chain is of multiple pkts, or - * 2-2. This is a single pkt whose size is longer than one block size. - */ - cur_chain_total_len = prev_chain_total_len + - (head_padding + pkt_len + tail_padding); - if (last_chained_pkt && bus->blocksize != 0 && - (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { - modulo = cur_chain_total_len % bus->blocksize; - chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; - } - -#ifdef DHDENABLE_TAILPAD - if (PKTTAILROOM(osh, pkt) < tail_padding) { - /* We don't have tail room to align by DHD_SDALIGN */ - alloc_new_pkt = TRUE; - bus->tx_tailpad_pktget++; - } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) { - /* We have tail room for tail_padding of this pkt itself, but not for - * total pkt chain alignment by block size. - * Use the padding packet to avoid memory copy if applicable, - * otherwise, just allocate a new pkt. - */ - if (bus->pad_pkt) { - *pad_pkt_len = chain_tail_padding; - bus->tx_tailpad_chain++; - } else { - alloc_new_pkt = TRUE; - bus->tx_tailpad_pktget++; - } - } else - /* This last pkt's tailroom is sufficient to hold both tail_padding - * of the pkt itself and chain_tail_padding of total pkt chain - */ -#endif /* DHDENABLE_TAILPAD */ - tail_padding += chain_tail_padding; - } - - DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n", - __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len)); - - if (alloc_new_pkt) { - void *tmp_pkt; - int newpkt_size; - int cur_total_len; - - ASSERT(*pad_pkt_len == 0); - - DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__)); - - /* head pointer is aligned now, no padding needed */ - head_padding = 0; - - /* update the tail padding as it depends on the head padding, since a new packet is - * allocated, the head padding is non longer needed and packet length is chagned - */ - - cur_total_len = prev_chain_total_len + pkt_len; - if (last_chained_pkt && bus->blocksize != 0 && - (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { - modulo = cur_total_len % bus->blocksize; - tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; - } - else { - modulo = pkt_len % DHD_SDALIGN; - tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; - } - - newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN; - bus->dhd->tx_realloc++; - tmp_pkt = PKTGET(osh, newpkt_size, TRUE); - if (tmp_pkt == NULL) { - DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size)); - return BCME_NOMEM; - } - PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN); - bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt)); - *new_pkt = tmp_pkt; - pkt = tmp_pkt; - } - - if (head_padding) - PKTPUSH(osh, pkt, head_padding); - - frame = (uint8*)PKTDATA(osh, pkt); - bzero(frame, head_padding + sdpcm_hdrlen); - pkt_len = (uint16)PKTLEN(osh, pkt); - - /* the header has the followming format - * 4-byte HW frame tag: length, ~length (for glom this is the total length) - * - * 8-byte HW extesion flags (glom mode only) as the following: - * 2-byte packet length, excluding HW tag and padding - * 2-byte frame channel and frame flags (e.g. next frame following) - * 2-byte header length - * 2-byte tail padding size - * - * 8-byte SW frame tags as the following - * 4-byte flags: host tx seq, channel, data offset - * 4-byte flags: TBD - */ - - swhdr_offset = SDPCM_FRAMETAG_LEN; - - /* hardware frame tag: - * - * in tx-glom mode, dongle only checks the hardware frame tag in the first - * packet and sees it as the total lenght of the glom (including tail padding), - * for each packet in the glom, the packet length needs to be updated, (see - * below PKTSETLEN) - * - * in non tx-glom mode, PKTLEN still need to include tail padding as to be - * referred to in sdioh_request_buffer(). The tail length will be excluded in - * dhdsdio_txpkt_postprocess(). - */ - *(uint16*)frame = (uint16)htol16(pkt_len); - *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len); - pkt_len += tail_padding; - - /* hardware extesion flags */ - if (bus->txglom_enable) { - uint32 hwheader1; - uint32 hwheader2; - - swhdr_offset += SDPCM_HWEXT_LEN; - hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) | - (last_chained_pkt << 24); - hwheader2 = (tail_padding) << 16; - htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); - htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); - } - PKTSETLEN((osh), (pkt), (pkt_len)); - - /* software frame tags */ - swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) - | (txseq % SDPCM_SEQUENCE_WRAP) | - (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); - htol32_ua_store(swheader, frame + swhdr_offset); - htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader)); - - return pkt_len; -} - -static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt) -{ - osl_t *osh; - uint8 *frame; - int data_offset; - int tail_padding; - int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0); - - (void)osh; - osh = bus->dhd->osh; - - /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */ - frame = (uint8*)PKTDATA(osh, pkt); - - DHD_INFO(("%s PKTLEN before postprocess %d", - __FUNCTION__, PKTLEN(osh, pkt))); - - /* PKTLEN still includes tail_padding, so exclude it. - * We shall have head_padding + original pkt_len for PKTLEN afterwards. - */ - if (bus->txglom_enable) { - /* txglom pkts have tail_padding length in HW ext header */ - tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16; - PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding); - DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n", - tail_padding, PKTLEN(osh, pkt))); - } else { - /* non-txglom pkts have head_padding + original pkt length in HW frame tag. - * We cannot refer to this field for txglom pkts as the first pkt of the chain will - * have the field for the total length of the chain. - */ - PKTSETLEN(osh, pkt, *(uint16*)frame); - DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n", - *(uint16*)frame, PKTLEN(osh, pkt))); - } - - data_offset = ltoh32_ua(frame + swhdr_offset); - data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; - /* Get rid of sdpcm header + head_padding */ - PKTPULL(osh, pkt, data_offset); - - DHD_INFO(("%s data_offset %d, PKTLEN %d\n", - __FUNCTION__, data_offset, PKTLEN(osh, pkt))); - - return BCME_OK; -} - -static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt) -{ - int i; - int ret = 0; - osl_t *osh; - bcmsdh_info_t *sdh; - void *pkt = NULL; - void *pkt_chain; - int total_len = 0; - void *head_pkt = NULL; - void *prev_pkt = NULL; - int pad_pkt_len = 0; - int new_pkt_num = 0; - void *new_pkts[MAX_TX_PKTCHAIN_CNT]; - bool wlfc_enabled = FALSE; - - if (bus->dhd->dongle_reset) - return BCME_NOTREADY; - - sdh = bus->sdh; - osh = bus->dhd->osh; - /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */ - new_pkts[0] = NULL; - - for (i = 0; i < num_pkt; i++) { - int pkt_len; - bool last_pkt; - void *new_pkt = NULL; - - pkt = pkts[i]; - ASSERT(pkt); - last_pkt = (i == num_pkt - 1); - pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i, - total_len, last_pkt, &pad_pkt_len, &new_pkt); - if (pkt_len <= 0) - goto done; - if (new_pkt) { - pkt = new_pkt; - new_pkts[new_pkt_num++] = new_pkt; - } - total_len += pkt_len; - - PKTSETNEXT(osh, pkt, NULL); - /* insert the packet into the list */ - head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt); - prev_pkt = pkt; - - } - - /* Update the HW frame tag (total length) in the first pkt of the glom */ - if (bus->txglom_enable) { - uint8 *frame; - - total_len += pad_pkt_len; - frame = (uint8*)PKTDATA(osh, head_pkt); - *(uint16*)frame = (uint16)htol16(total_len); - *(((uint16*)frame) + 1) = (uint16)htol16(~total_len); - - } - -#ifdef DHDENABLE_TAILPAD - /* if a padding packet if needed, insert it to the end of the link list */ - if (pad_pkt_len) { - PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len); - PKTSETNEXT(osh, pkt, bus->pad_pkt); - } -#endif /* DHDENABLE_TAILPAD */ - - /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet - * parameter is not NULL, for non packet chian we pass NULL pkt pointer - * so it will take the aligned length and buffer pointer. - */ - pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL; - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES); - if (ret == BCME_OK) - bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP; - - /* if a padding packet was needed, remove it from the link list as it not a data pkt */ - if (pad_pkt_len && pkt) - PKTSETNEXT(osh, pkt, NULL); - -done: - pkt = head_pkt; - while (pkt) { - void *pkt_next = PKTNEXT(osh, pkt); - PKTSETNEXT(osh, pkt, NULL); - dhdsdio_txpkt_postprocess(bus, pkt); - pkt = pkt_next; - } - - /* new packets might be allocated due to insufficient room for padding, but we - * still have to indicate the original packets to upper layer - */ - for (i = 0; i < num_pkt; i++) { - pkt = pkts[i]; - wlfc_enabled = FALSE; -#ifdef PROP_TXSTATUS - if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) { - wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) != - WLFC_UNSUPPORTED); - } -#endif /* PROP_TXSTATUS */ - if (!wlfc_enabled) { - PKTSETNEXT(osh, pkt, NULL); - dhd_txcomplete(bus->dhd, pkt, ret != 0); - if (free_pkt) - PKTFREE(osh, pkt, TRUE); - } - } - - for (i = 0; i < new_pkt_num; i++) - PKTFREE(osh, new_pkts[i], TRUE); - - return ret; -} - -static uint -dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) -{ - uint cnt = 0; - uint8 tx_prec_map; - uint16 txpktqlen = 0; - uint32 intstatus = 0; - uint retries = 0; - osl_t *osh; - uint datalen = 0; - dhd_pub_t *dhd = bus->dhd; - sdpcmd_regs_t *regs = bus->regs; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return BCME_NODEVICE; - } - - osh = dhd->osh; - tx_prec_map = ~bus->flowcontrol; - for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) { - int i; - int num_pkt = 1; - void *pkts[MAX_TX_PKTCHAIN_CNT]; - int prec_out; - - dhd_os_sdlock_txq(bus->dhd); - if (bus->txglom_enable) { - num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize); - num_pkt = MIN(num_pkt, ARRAYSIZE(pkts)); - } - num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map)); - for (i = 0; i < num_pkt; i++) { - pkts[i] = pktq_mdeq(&bus->txq, ~bus->flowcontrol, &prec_out); - if (!pkts[i]) { - DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n", - __FUNCTION__)); - ASSERT(0); - break; - } - PKTORPHAN(pkts[i]); - datalen += PKTLEN(osh, pkts[i]); - } - dhd_os_sdunlock_txq(bus->dhd); - - if (i == 0) - break; - if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK) - dhd->tx_errors++; - else - dhd->dstats.tx_bytes += datalen; - cnt += i; - - /* In poll mode, need to check for other events */ - if (!bus->intr && cnt) - { - /* Check device status, signal pending interrupt */ - R_SDREG(intstatus, ®s->intstatus, retries); - bus->f2txdata++; - if (bcmsdh_regfail(bus->sdh)) - break; - if (intstatus & bus->hostintmask) - bus->ipend = TRUE; - } - - } - - dhd_os_sdlock_txq(bus->dhd); - txpktqlen = pktq_len(&bus->txq); - dhd_os_sdunlock_txq(bus->dhd); - - /* Do flow-control if needed */ - if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) { - bool wlfc_enabled = FALSE; -#ifdef PROP_TXSTATUS - wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED); -#endif - if (!wlfc_enabled && dhd_doflow && dhd->txoff) { - dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); - } - } - - return cnt; -} - -static void -dhdsdio_sendpendctl(dhd_bus_t *bus) -{ - bcmsdh_info_t *sdh = bus->sdh; - int ret; - uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; - - if (bus->txglom_enable) - frame_seq += SDPCM_HWEXT_LEN; - - if (*frame_seq != bus->tx_seq) { - DHD_INFO(("%s IOCTL frame seq lag detected!" - " frm_seq:%d != bus->tx_seq:%d, corrected\n", - __FUNCTION__, *frame_seq, bus->tx_seq)); - *frame_seq = bus->tx_seq; - } - - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, - NULL, NULL, NULL, 1); - if (ret == BCME_OK) - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - - bus->ctrl_frame_stat = FALSE; - dhd_wait_event_wakeup(bus->dhd); -} - -int -dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) -{ - static int err_nodevice = 0; - uint8 *frame; - uint16 len; - uint32 swheader; - bcmsdh_info_t *sdh = bus->sdh; - uint8 doff = 0; - int ret = -1; - uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) - return -EIO; - - /* 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) */ - if (dhd_alignctl) { - if ((doff = ((uintptr)frame % DHD_SDALIGN))) { - frame -= doff; - len += doff; - msglen += doff; - bzero(frame, doff + sdpcm_hdrlen); - } - ASSERT(doff < DHD_SDALIGN); - } - doff += sdpcm_hdrlen; - - /* Round send length to next SDIO block */ - if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - uint16 pad = bus->blocksize - (len % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize)) - len += pad; - } else if (len % DHD_SDALIGN) { - len += DHD_SDALIGN - (len % DHD_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (forcealign && (len & (ALIGNMENT - 1))) - len = ROUNDUP(len, ALIGNMENT); - - ASSERT(ISALIGNED((uintptr)frame, 2)); - - - /* Need to lock here to protect txseq and SDIO tx calls */ - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - /* Make sure backplane clock is on */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ - *(uint16*)frame = htol16((uint16)msglen); - *(((uint16*)frame) + 1) = htol16(~msglen); - - if (bus->txglom_enable) { - uint32 hwheader1, hwheader2; - /* 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); - htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); - htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN - + SDPCM_HWEXT_LEN + sizeof(swheader)); - - hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24); - hwheader2 = (len - (msglen)) << 16; - htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); - htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); - - *(uint16*)frame = htol16(len); - *(((uint16*)frame) + 1) = htol16(~(len)); - } else { - /* 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); - htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); - htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - } - if (!TXCTLOK(bus)) { - DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", - __FUNCTION__, bus->tx_max, bus->tx_seq)); - bus->ctrl_frame_stat = TRUE; - /* Send from dpc */ - bus->ctrl_frame_buf = frame; - bus->ctrl_frame_len = len; - - if (!bus->dpc_sched) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - if (bus->ctrl_frame_stat) { - dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); - } - - if (bus->ctrl_frame_stat == FALSE) { - DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); - ret = 0; - } else { - bus->dhd->txcnt_timeout++; - if (!bus->dhd->hang_was_sent) { - DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", - __FUNCTION__, bus->dhd->txcnt_timeout)); - } - ret = -1; - bus->ctrl_frame_stat = FALSE; - goto done; - } - } - - bus->dhd->txcnt_timeout = 0; - bus->ctrl_frame_stat = TRUE; - - if (ret == -1) { -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_CTL_ON()) { - prhex("Tx Frame", frame, len); - } else if (DHD_HDRS_ON()) { - prhex("TxHdr", frame, MIN(len, 16)); - } -#endif - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - frame, len, NULL, NULL, NULL, TXRETRIES); - if (ret == BCME_OK) - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - } - bus->ctrl_frame_stat = FALSE; - -done: - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - - if (ret) - bus->dhd->tx_ctlerrs++; - else - bus->dhd->tx_ctlpkts++; - - if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) - return -ETIMEDOUT; - - if (ret == BCME_NODEVICE) - err_nodevice++; - else - err_nodevice = 0; - - return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0; -} - -int -dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) -{ - int timeleft; - uint rxlen = 0; - bool pending; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) - return -EIO; - - /* Wait until control frame is available */ - timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); - - dhd_os_sdlock(bus->dhd); - rxlen = bus->rxlen; - bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); - bus->rxlen = 0; - dhd_os_sdunlock(bus->dhd); - - if (rxlen) { - DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", - __FUNCTION__, rxlen, msglen)); - } else if (timeleft == 0) { -#ifdef DHD_DEBUG - uint32 status, retry = 0; - R_SDREG(status, &bus->regs->intstatus, retry); - DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n", - __FUNCTION__, status)); -#else - DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); -#endif /* DHD_DEBUG */ - dhd_os_sdlock(bus->dhd); - dhdsdio_checkdied(bus, NULL, 0); - dhd_os_sdunlock(bus->dhd); - } else if (pending == TRUE) { - /* signal pending */ - DHD_ERROR(("%s: signal pending\n", __FUNCTION__)); - return -EINTR; - - } else { - DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); - dhd_os_sdlock(bus->dhd); - dhdsdio_checkdied(bus, NULL, 0); - dhd_os_sdunlock(bus->dhd); - } - if (timeleft == 0) { - if (rxlen == 0) - bus->dhd->rxcnt_timeout++; - DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__, - bus->dhd->rxcnt_timeout, rxlen)); - } - else - bus->dhd->rxcnt_timeout = 0; - - if (rxlen) - bus->dhd->rx_ctlpkts++; - else - bus->dhd->rx_ctlerrs++; - - if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) - return -ETIMEDOUT; - - if (bus->dhd->dongle_trap_occured) - return -EREMOTEIO; - - return rxlen ? (int)rxlen : -EIO; -} - -/* IOVar table */ -enum { - IOV_INTR = 1, - IOV_POLLRATE, - IOV_SDREG, - IOV_SBREG, - IOV_SDCIS, - IOV_MEMBYTES, - IOV_RAMSIZE, - IOV_RAMSTART, -#ifdef DHD_DEBUG - IOV_CHECKDIED, - IOV_SERIALCONS, -#endif /* DHD_DEBUG */ - IOV_SET_DOWNLOAD_STATE, - IOV_SOCRAM_STATE, - IOV_FORCEEVEN, - IOV_SDIOD_DRIVE, - IOV_READAHEAD, - IOV_SDRXCHAIN, - IOV_ALIGNCTL, - IOV_SDALIGN, - IOV_DEVRESET, - IOV_CPU, -#if defined(USE_SDIOFIFO_IOVAR) - IOV_WATERMARK, - IOV_MESBUSYCTRL, -#endif /* USE_SDIOFIFO_IOVAR */ -#ifdef SDTEST - IOV_PKTGEN, - IOV_EXTLOOP, -#endif /* SDTEST */ - IOV_SPROM, - IOV_TXBOUND, - IOV_RXBOUND, - IOV_TXMINMAX, - IOV_IDLETIME, - IOV_IDLECLOCK, - IOV_SD1IDLE, - IOV_SLEEP, - IOV_DONGLEISOLATION, - IOV_KSO, - IOV_DEVSLEEP, - IOV_DEVCAP, - IOV_VARS, -#ifdef SOFTAP - IOV_FWPATH, -#endif - IOV_TXGLOMSIZE, - IOV_TXGLOMMODE, - IOV_HANGREPORT, - IOV_TXINRX_THRES -}; - -const bcm_iovar_t dhdsdio_iovars[] = { - {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, - {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 }, - {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 }, - {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, - {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, - {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, - {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, - {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 }, - {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 }, - {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, - {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, - {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, - {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, - {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, - {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 }, - {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, - {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, - {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, -#ifdef DHD_DEBUG - {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, - {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, - {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, - {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, - {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, - {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, -#ifdef DHD_DEBUG - {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, - {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 }, -#endif /* DHD_DEBUG */ -#endif /* DHD_DEBUG */ -#ifdef SDTEST - {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, - {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, -#endif /* SDTEST */ -#if defined(USE_SDIOFIFO_IOVAR) - {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 }, - {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 }, -#endif /* USE_SDIOFIFO_IOVAR */ - {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 }, - {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, - {"kso", IOV_KSO, 0, IOVT_UINT32, 0 }, - {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 }, -#ifdef SOFTAP - {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, -#endif - {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 }, - {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 }, - {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -static void -dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) -{ - uint q1, q2; - - if (!div) { - bcm_bprintf(strbuf, "%s N/A", desc); - } else { - q1 = num / div; - q2 = (100 * (num - (q1 * div))) / div; - bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); - } -} - -void -dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - dhd_bus_t *bus = dhdp->bus; - - bcm_bprintf(strbuf, "Bus SDIO structure:\n"); - bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", - bus->hostintmask, bus->intstatus, bus->sdpcm_ver); - bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n", - bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, - bus->rxlen, bus->rx_seq); - bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n", - bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); - bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n", - bus->pollrate, bus->pollcnt, bus->regfails); - - bcm_bprintf(strbuf, "\nAdditional counters:\n"); -#ifdef DHDENABLE_TAILPAD - bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n", - bus->tx_tailpad_chain, bus->tx_tailpad_pktget); -#endif /* DHDENABLE_TAILPAD */ - bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n", - bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, - bus->rxc_errors); - bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n", - bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); - bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n", - bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); - bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n", - bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); - bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n", - (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, - bus->f2txdata, bus->f1regdata); - { - dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, - (bus->f2rxhdrs + bus->f2rxdata)); - dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); - dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, - (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); - dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); - bcm_bprintf(strbuf, "\n"); - - dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), - bus->dhd->rx_packets); - dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes); - bcm_bprintf(strbuf, "\n"); - - dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata); - dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata); - dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets, - (bus->f2txdata + bus->f1regdata)); - dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount); - bcm_bprintf(strbuf, "\n"); - - dhd_dump_pct(strbuf, "Total: pkts/f2rw", - (bus->dhd->tx_packets + bus->dhd->rx_packets), - (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); - dhd_dump_pct(strbuf, ", pkts/f1sd", - (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata); - dhd_dump_pct(strbuf, ", pkts/sd", - (bus->dhd->tx_packets + bus->dhd->rx_packets), - (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); - dhd_dump_pct(strbuf, ", pkts/int", - (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount); - bcm_bprintf(strbuf, "\n\n"); - } - -#ifdef SDTEST - if (bus->pktgen_count) { - bcm_bprintf(strbuf, "pktgen config and count:\n"); - bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n", - bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, - bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); - bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n", - bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); - } -#endif /* SDTEST */ -#ifdef DHD_DEBUG - bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", - bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); - bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup); -#endif /* DHD_DEBUG */ - bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", - bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); -} - -void -dhd_bus_clearcounts(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; - - bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; - bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; - bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; -#ifdef DHDENABLE_TAILPAD - bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0; -#endif /* DHDENABLE_TAILPAD */ - bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; - bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; - bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; -} - -#ifdef SDTEST -static int -dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg) -{ - dhd_pktgen_t pktgen; - - pktgen.version = DHD_PKTGEN_VERSION; - pktgen.freq = bus->pktgen_freq; - pktgen.count = bus->pktgen_count; - pktgen.print = bus->pktgen_print; - pktgen.total = bus->pktgen_total; - pktgen.minlen = bus->pktgen_minlen; - pktgen.maxlen = bus->pktgen_maxlen; - pktgen.numsent = bus->pktgen_sent; - pktgen.numrcvd = bus->pktgen_rcvd; - pktgen.numfail = bus->pktgen_fail; - pktgen.mode = bus->pktgen_mode; - pktgen.stop = bus->pktgen_stop; - - bcopy(&pktgen, arg, sizeof(pktgen)); - - return 0; -} - -static int -dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) -{ - dhd_pktgen_t pktgen; - uint oldcnt, oldmode; - - bcopy(arg, &pktgen, sizeof(pktgen)); - if (pktgen.version != DHD_PKTGEN_VERSION) - return BCME_BADARG; - - oldcnt = bus->pktgen_count; - oldmode = bus->pktgen_mode; - - bus->pktgen_freq = pktgen.freq; - bus->pktgen_count = pktgen.count; - bus->pktgen_print = pktgen.print; - bus->pktgen_total = pktgen.total; - bus->pktgen_minlen = pktgen.minlen; - bus->pktgen_maxlen = pktgen.maxlen; - bus->pktgen_mode = pktgen.mode; - bus->pktgen_stop = pktgen.stop; - - bus->pktgen_tick = bus->pktgen_ptick = 0; - bus->pktgen_prev_time = jiffies; - bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen); - bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen); - - /* Clear counts for a new pktgen (mode change, or was stopped) */ - if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) { - bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0; - bus->pktgen_prev_rcvd = bus->pktgen_fail = 0; - } - - return 0; -} -#endif /* SDTEST */ - -static void -dhdsdio_devram_remap(dhd_bus_t *bus, bool val) -{ - uint8 enable, protect, remap; - - si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); - remap = val ? TRUE : FALSE; - si_socdevram(bus->sih, TRUE, &enable, &protect, &remap); -} - -static int -dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size) -{ - int bcmerror = 0; - uint32 sdaddr; - uint dsize; - - /* In remap mode, adjust address beyond socram and redirect - * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize - * is not backplane accessible - */ - if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) { - address -= bus->orig_ramsize; - address += SOCDEVRAM_BP_ADDR; - } - - /* 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 */ - if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { - DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); - goto xfer_done; - } - - /* Do the transfer(s) */ - while (size) { - DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n", - __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr, - (address & SBSDIO_SBWINDOW_MASK))); - if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) { - DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__)); - break; - } - - /* Adjust for next transfer (if any) */ - if ((size -= dsize)) { - data += dsize; - address += dsize; - if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { - DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); - break; - } - sdaddr = 0; - dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); - } - - } - -xfer_done: - /* Return the window to backplane enumeration space for core access */ - if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { - DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, - bcmsdh_cur_sbwad(bus->sdh))); - } - - return bcmerror; -} - -static int -dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) -{ - uint32 addr; - int rv, i; - uint32 shaddr = 0; - - if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus)) - bus->srmemsize = 0; - - shaddr = bus->dongle_ram_base + bus->ramsize - 4; - i = 0; - do { - /* Read last word in memory to determine address of sdpcm_shared structure */ - if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) - return rv; - - addr = ltoh32(addr); - - DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); - - /* - * Check if addr is valid. - * NVRAM length at the end of memory should have been overwritten. - */ - if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { - if ((bus->srmemsize > 0) && (i++ == 0)) { - shaddr -= bus->srmemsize; - } else { - DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", - __FUNCTION__, addr)); - return BCME_ERROR; - } - } else - break; - } while (i < 2); - - /* Read hndrte_shared structure */ - if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) - return rv; - - /* Endianness */ - sh->flags = ltoh32(sh->flags); - sh->trap_addr = ltoh32(sh->trap_addr); - sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); - sh->assert_file_addr = ltoh32(sh->assert_file_addr); - sh->assert_line = ltoh32(sh->assert_line); - sh->console_addr = ltoh32(sh->console_addr); - sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); - - if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) - return BCME_OK; - - if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { - DHD_ERROR(("%s: sdpcm_shared version %d in dhd " - "is different than sdpcm_shared version %d in dongle\n", - __FUNCTION__, SDPCM_SHARED_VERSION, - sh->flags & SDPCM_SHARED_VERSION_MASK)); - return BCME_ERROR; - } - - return BCME_OK; -} - -#define CONSOLE_LINE_MAX 192 - -#ifdef DHD_DEBUG -static int -dhdsdio_readconsole(dhd_bus_t *bus) -{ - dhd_console_t *c = &bus->console; - uint8 line[CONSOLE_LINE_MAX], ch; - uint32 n, idx, addr; - int rv; - - /* Don't do anything until FWREADY updates console address */ - if (bus->console_addr == 0) - return 0; - - if (!KSO_ENAB(bus)) - return 0; - - /* Read console log struct */ - addr = bus->console_addr + OFFSETOF(hnd_cons_t, log); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) - return rv; - - /* Allocate console buffer (one time only) */ - if (c->buf == NULL) { - c->bufsize = ltoh32(c->log.buf_size); - if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) - return BCME_NOMEM; - } - - idx = ltoh32(c->log.idx); - - /* Protect against corrupt value */ - if (idx > c->bufsize) - return BCME_ERROR; - - /* Skip reading the console buffer if the index pointer has not moved */ - if (idx == c->last) - return BCME_OK; - - /* Read the console buffer */ - addr = ltoh32(c->log.buf); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 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; - printf("CONSOLE: %s\n", line); -#ifdef LOG_INTO_TCPDUMP - dhd_sendup_log(bus->dhd, line, n); -#endif /* LOG_INTO_TCPDUMP */ - } - } -break2: - - return BCME_OK; -} -#endif /* DHD_DEBUG */ - -static int -dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) -{ - int bcmerror = 0; - uint msize = 512; - char *mbuffer = NULL; - char *console_buffer = NULL; - uint maxstrlen = 256; - char *str = NULL; - trap_t tr; - sdpcm_shared_t sdpcm_shared; - struct bcmstrbuf strbuf; - uint32 console_ptr, console_size, console_index; - uint8 line[CONSOLE_LINE_MAX], ch; - uint32 n, i, addr; - int rv; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (DHD_NOCHECKDIED_ON()) - return 0; - - if (data == NULL) { - /* - * Called after a rx ctrl timeout. "data" is NULL. - * allocate memory to trace the trap or assert. - */ - size = msize; - mbuffer = data = MALLOC(bus->dhd->osh, msize); - if (mbuffer == NULL) { - DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); - bcmerror = BCME_NOMEM; - goto done; - } - } - - if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { - DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); - bcmerror = BCME_NOMEM; - goto done; - } - - if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0) - goto done; - - bcm_binit(&strbuf, data, size); - - bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", - sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); - - if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { - /* NOTE: Misspelled assert is intentional - DO NOT FIX. - * (Avoids conflict with real asserts for programmatic parsing of output.) - */ - bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); - } - - if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) { - /* NOTE: Misspelled assert is intentional - DO NOT FIX. - * (Avoids conflict with real asserts for programmatic parsing of output.) - */ - bcm_bprintf(&strbuf, "No trap%s in dongle", - (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) - ?"/assrt" :""); - } else { - if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { - /* Download assert */ - bcm_bprintf(&strbuf, "Dongle assert"); - if (sdpcm_shared.assert_exp_addr != 0) { - str[0] = '\0'; - if ((bcmerror = dhdsdio_membytes(bus, FALSE, - sdpcm_shared.assert_exp_addr, - (uint8 *)str, maxstrlen)) < 0) - goto done; - - str[maxstrlen - 1] = '\0'; - bcm_bprintf(&strbuf, " expr \"%s\"", str); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - " expr \"%s\"", str); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - } - - if (sdpcm_shared.assert_file_addr != 0) { - str[0] = '\0'; - if ((bcmerror = dhdsdio_membytes(bus, FALSE, - sdpcm_shared.assert_file_addr, - (uint8 *)str, maxstrlen)) < 0) - goto done; - - str[maxstrlen - 1] = '\0'; - bcm_bprintf(&strbuf, " file \"%s\"", str); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - " file \"%s\"", str); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - } - - bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line); - } - - if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { - bus->dhd->dongle_trap_occured = TRUE; - if ((bcmerror = dhdsdio_membytes(bus, FALSE, - sdpcm_shared.trap_addr, - (uint8*)&tr, sizeof(trap_t))) < 0) - goto done; - - bcm_bprintf(&strbuf, - "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," - "lp 0x%x, rpc 0x%x Trap offset 0x%x, " - "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " - "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", - ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), - ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), - ltoh32(sdpcm_shared.trap_addr), - ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), - ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); - -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," - "lp 0x%x, rpc 0x%x Trap offset 0x%x, " - "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " - "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", - ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), - ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), - ltoh32(sdpcm_shared.trap_addr), - ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), - ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, - (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) - goto printbuf; - - addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.buf_size); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, - (uint8 *)&console_size, sizeof(console_size))) < 0) - goto printbuf; - - addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, - (uint8 *)&console_index, sizeof(console_index))) < 0) - goto printbuf; - - console_ptr = ltoh32(console_ptr); - console_size = ltoh32(console_size); - console_index = ltoh32(console_index); - - if (console_size > CONSOLE_BUFFER_MAX || - !(console_buffer = MALLOC(bus->dhd->osh, console_size))) - goto printbuf; - - if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, - (uint8 *)console_buffer, console_size)) < 0) - goto printbuf; - - for (i = 0, n = 0; i < console_size; i += n + 1) { - for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { - ch = console_buffer[(console_index + i + n) % console_size]; - if (ch == '\n') - break; - line[n] = ch; - } - - - if (n > 0) { - if (line[n - 1] == '\r') - n--; - line[n] = 0; - /* Don't use DHD_ERROR macro since we print - * a lot of information quickly. The macro - * will truncate a lot of the printfs - */ - - if (dhd_msg_level & DHD_ERROR_VAL) - printf("CONSOLE: %s\n", line); - } - } - } - } - -printbuf: - if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { - DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); - } - -#if defined(DHD_FW_COREDUMP) - if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { - /* Mem dump to a file on device */ - dhdsdio_mem_dump(bus); - /* In some cases, the host back trace could be relevant too. */ - WARN_ON(1); - } -#endif /* #if defined(DHD_FW_COREDUMP) */ - -done: - if (mbuffer) - MFREE(bus->dhd->osh, mbuffer, msize); - if (str) - MFREE(bus->dhd->osh, str, maxstrlen); - if (console_buffer) - MFREE(bus->dhd->osh, console_buffer, console_size); - - return bcmerror; -} - -#if defined(DHD_FW_COREDUMP) -static int -dhdsdio_mem_dump(dhd_bus_t *bus) -{ - int ret = 0; - int size; /* Full mem size */ - int start = bus->dongle_ram_base; /* Start address */ - int read_size = 0; /* Read size of each iteration */ - uint8 *buf = NULL, *databuf = NULL; - - /* Get full mem size */ - size = bus->ramsize; - buf = dhd_get_fwdump_buf(bus->dhd, size); - if (!buf) { - DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size)); - return -1; - } - - /* Read mem content */ - DHD_ERROR(("Dump dongle memory\n")); - databuf = buf; - while (size) - { - read_size = MIN(MEMBLOCK, size); - if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size))) - { - DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret)); - return -1; - } - /* Decrement size and increment start address */ - size -= read_size; - start += read_size; - databuf += read_size; - } - DHD_ERROR(("Done\n")); - - dhd_schedule_memdump(bus->dhd, buf, bus->ramsize); - /* buf, actually soc_ram free handled in dhd_{free,clear} */ - - - return 0; -} - -int -dhd_bus_mem_dump(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - return dhdsdio_mem_dump(bus); -} -#endif /* DHD_FW_COREDUMP */ - -int -dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) -{ - int bcmerror = BCME_OK; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Basic sanity checks */ - if (bus->dhd->up) { - bcmerror = BCME_NOTDOWN; - goto err; - } - if (!len) { - bcmerror = BCME_BUFTOOSHORT; - goto err; - } - - /* Free the old ones and replace with passed variables */ - if (bus->vars) - MFREE(bus->dhd->osh, bus->vars, bus->varsz); - - bus->vars = MALLOC(bus->dhd->osh, len); - bus->varsz = bus->vars ? len : 0; - if (bus->vars == NULL) { - bcmerror = BCME_NOMEM; - goto err; - } - - /* Copy the passed variables, which should include the terminating double-null */ - bcopy(arg, bus->vars, bus->varsz); -err: - return bcmerror; -} - -#ifdef DHD_DEBUG - -#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) -#define CC_CHIPCTRL_JTAG_SEL (1 << 3) -#define CC_CHIPCTRL_GPIO_SEL (0x3) -#define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28) - -static int -dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) -{ - int int_val; - uint32 addr, data, uart_enab = 0; - uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL; - uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL; - - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - *bcmerror = 0; - - bcmsdh_reg_write(bus->sdh, addr, 4, 1); - if (bcmsdh_regfail(bus->sdh)) { - *bcmerror = BCME_SDIO_ERROR; - return -1; - } - int_val = bcmsdh_reg_read(bus->sdh, data, 4); - if (bcmsdh_regfail(bus->sdh)) { - *bcmerror = BCME_SDIO_ERROR; - return -1; - } - if (bus->sih->chip == BCM4330_CHIP_ID) { - uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; - } - else if (bus->sih->chip == BCM4334_CHIP_ID || - bus->sih->chip == BCM43340_CHIP_ID || - bus->sih->chip == BCM43341_CHIP_ID || - bus->sih->chip == BCM43342_CHIP_ID || - 0) { - if (enable) { - /* Moved to PMU chipcontrol 1 from 4330 */ - int_val &= ~gpio_sel; - int_val |= jtag_sel; - } else { - int_val |= gpio_sel; - int_val &= ~jtag_sel; - } - uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334; - } - - if (!set) - return (int_val & uart_enab); - if (enable) - int_val |= uart_enab; - else - int_val &= ~uart_enab; - bcmsdh_reg_write(bus->sdh, data, 4, int_val); - if (bcmsdh_regfail(bus->sdh)) { - *bcmerror = BCME_SDIO_ERROR; - return -1; - } - if (bus->sih->chip == BCM4330_CHIP_ID) { - uint32 chipcontrol; - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); - chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); - chipcontrol &= ~jtag_sel; - if (enable) { - chipcontrol |= jtag_sel; - chipcontrol &= ~gpio_sel; - } - bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); - } - - return (int_val & uart_enab); -} -#endif - -static int -dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - bool bool_val = 0; - - DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", - __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - - - /* Some ioctls use the bus */ - dhd_os_sdlock(bus->dhd); - - /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ - if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || - actionid == IOV_GVAL(IOV_DEVRESET))) { - bcmerror = BCME_NOTREADY; - goto exit; - } - - /* - * Special handling for keepSdioOn: New SDIO Wake-up Mechanism - */ - if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) { - dhdsdio_clk_kso_iovar(bus, bool_val); - goto exit; - } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { - { - dhdsdio_clk_devsleep_iovar(bus, bool_val); - if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { - DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n", - bus->dpc_sched)); - if (!bus->dpc_sched) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - } - } - goto exit; - } - - /* Handle sleep stuff before any clock mucking */ - if (vi->varid == IOV_SLEEP) { - if (IOV_ISSET(actionid)) { - bcmerror = dhdsdio_bussleep(bus, bool_val); - } else { - int_val = (int32)bus->sleeping; - bcopy(&int_val, arg, val_size); - } - goto exit; - } - - /* Request clock to allow SDIO accesses */ - if (!bus->dhd->dongle_reset) { - BUS_WAKE(bus); - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - } - - switch (actionid) { - case IOV_GVAL(IOV_INTR): - int_val = (int32)bus->intr; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_INTR): - bus->intr = bool_val; - bus->intdis = FALSE; - if (bus->dhd->up) { - if (bus->intr) { - DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); - bcmsdh_intr_enable(bus->sdh); - } else { - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - } - } - break; - - case IOV_GVAL(IOV_POLLRATE): - int_val = (int32)bus->pollrate; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POLLRATE): - bus->pollrate = (uint)int_val; - bus->poll = (bus->pollrate != 0); - break; - - case IOV_GVAL(IOV_IDLETIME): - int_val = bus->idletime; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_IDLETIME): - if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) { - bcmerror = BCME_BADARG; - } else { - bus->idletime = int_val; - } - break; - - case IOV_GVAL(IOV_IDLECLOCK): - int_val = (int32)bus->idleclock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_IDLECLOCK): - bus->idleclock = int_val; - break; - - case IOV_GVAL(IOV_SD1IDLE): - int_val = (int32)sd1idle; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SD1IDLE): - sd1idle = bool_val; - break; - - - case IOV_SVAL(IOV_MEMBYTES): - case IOV_GVAL(IOV_MEMBYTES): - { - uint32 address; - uint size, dsize; - uint8 *data; - - bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); - - ASSERT(plen >= 2*sizeof(int)); - - address = (uint32)int_val; - bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); - size = (uint)int_val; - - /* Do some validation */ - dsize = set ? plen - (2 * sizeof(int)) : len; - if (dsize < size) { - DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", - __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); - bcmerror = BCME_BADARG; - break; - } - - DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, - (set ? "write" : "read"), size, address)); - - /* check if CR4 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - /* - * If address is start of RAM (i.e. a downloaded image), - * store the reset instruction to be written in 0 - */ - if (set && address == bus->dongle_ram_base) { - bus->resetinstr = *(((uint32*)params) + 2); - } - } else { - /* If we know about SOCRAM, check for a fit */ - if ((bus->orig_ramsize) && - ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) - { - uint8 enable, protect, remap; - si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); - if (!enable || protect) { - DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", - __FUNCTION__, bus->orig_ramsize, size, address)); - DHD_ERROR(("%s: socram enable %d, protect %d\n", - __FUNCTION__, enable, protect)); - bcmerror = BCME_BADARG; - break; - } - - if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { - uint32 devramsize = si_socdevram_size(bus->sih); - if ((address < SOCDEVRAM_ARM_ADDR) || - (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { - DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n", - __FUNCTION__, address, size)); - DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n", - __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize)); - bcmerror = BCME_BADARG; - break; - } - /* move it such that address is real now */ - address -= SOCDEVRAM_ARM_ADDR; - address += SOCDEVRAM_BP_ADDR; - DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", - __FUNCTION__, (set ? "write" : "read"), size, address)); - } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { - /* Can not access remap region while devram remap bit is set - * ROM content would be returned in this case - */ - DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n", - __FUNCTION__, address)); - bcmerror = BCME_ERROR; - break; - } - } - } - - /* Generate the actual data pointer */ - data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; - - /* Call to do the transfer */ - bcmerror = dhdsdio_membytes(bus, set, address, data, size); - - break; - } - - case IOV_GVAL(IOV_RAMSIZE): - int_val = (int32)bus->ramsize; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_RAMSTART): - int_val = (int32)bus->dongle_ram_base; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_SDIOD_DRIVE): - int_val = (int32)dhd_sdiod_drive_strength; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDIOD_DRIVE): - dhd_sdiod_drive_strength = int_val; - si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength); - break; - - case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): - bcmerror = dhdsdio_download_state(bus, bool_val); - break; - - case IOV_SVAL(IOV_SOCRAM_STATE): - bcmerror = dhdsdio_download_state(bus, bool_val); - break; - - case IOV_SVAL(IOV_VARS): - bcmerror = dhdsdio_downloadvars(bus, arg, len); - break; - - case IOV_GVAL(IOV_READAHEAD): - int_val = (int32)dhd_readahead; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_READAHEAD): - if (bool_val && !dhd_readahead) - bus->nextlen = 0; - dhd_readahead = bool_val; - break; - - case IOV_GVAL(IOV_SDRXCHAIN): - int_val = (int32)bus->use_rxchain; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDRXCHAIN): - if (bool_val && !bus->sd_rxchain) - bcmerror = BCME_UNSUPPORTED; - else - bus->use_rxchain = bool_val; - break; - case IOV_GVAL(IOV_ALIGNCTL): - int_val = (int32)dhd_alignctl; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_ALIGNCTL): - dhd_alignctl = bool_val; - break; - - case IOV_GVAL(IOV_SDALIGN): - int_val = DHD_SDALIGN; - bcopy(&int_val, arg, val_size); - break; - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_VARS): - if (bus->varsz < (uint)len) - bcopy(bus->vars, arg, bus->varsz); - else - bcmerror = BCME_BUFTOOSHORT; - break; -#endif /* DHD_DEBUG */ - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_SDREG): - { - sdreg_t *sd_ptr; - uint32 addr, size; - - sd_ptr = (sdreg_t *)params; - - addr = (uint32)((ulong)bus->regs + sd_ptr->offset); - size = sd_ptr->func; - int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - bcopy(&int_val, arg, sizeof(int32)); - break; - } - - case IOV_SVAL(IOV_SDREG): - { - sdreg_t *sd_ptr; - uint32 addr, size; - - sd_ptr = (sdreg_t *)params; - - addr = (uint32)((ulong)bus->regs + sd_ptr->offset); - size = sd_ptr->func; - bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - break; - } - - /* Same as above, but offset is not backplane (not SDIO core) */ - case IOV_GVAL(IOV_SBREG): - { - sdreg_t sdreg; - uint32 addr, size; - - bcopy(params, &sdreg, sizeof(sdreg)); - - addr = SI_ENUM_BASE + sdreg.offset; - size = sdreg.func; - int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - bcopy(&int_val, arg, sizeof(int32)); - break; - } - - case IOV_SVAL(IOV_SBREG): - { - sdreg_t sdreg; - uint32 addr, size; - - bcopy(params, &sdreg, sizeof(sdreg)); - - addr = SI_ENUM_BASE + sdreg.offset; - size = sdreg.func; - bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - break; - } - - case IOV_GVAL(IOV_SDCIS): - { - *(char *)arg = 0; - - bcmstrcat(arg, "\nFunc 0\n"); - bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); - bcmstrcat(arg, "\nFunc 1\n"); - bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); - bcmstrcat(arg, "\nFunc 2\n"); - bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); - break; - } - - case IOV_GVAL(IOV_FORCEEVEN): - int_val = (int32)forcealign; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_FORCEEVEN): - forcealign = bool_val; - break; - - case IOV_GVAL(IOV_TXBOUND): - int_val = (int32)dhd_txbound; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXBOUND): - dhd_txbound = (uint)int_val; - break; - - case IOV_GVAL(IOV_RXBOUND): - int_val = (int32)dhd_rxbound; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RXBOUND): - dhd_rxbound = (uint)int_val; - break; - - case IOV_GVAL(IOV_TXMINMAX): - int_val = (int32)dhd_txminmax; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXMINMAX): - dhd_txminmax = (uint)int_val; - break; - - case IOV_GVAL(IOV_SERIALCONS): - int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); - if (bcmerror != 0) - break; - - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SERIALCONS): - dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); - break; - - -#endif /* DHD_DEBUG */ - - -#ifdef SDTEST - case IOV_GVAL(IOV_EXTLOOP): - int_val = (int32)bus->ext_loop; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_EXTLOOP): - bus->ext_loop = bool_val; - break; - - case IOV_GVAL(IOV_PKTGEN): - bcmerror = dhdsdio_pktgen_get(bus, arg); - break; - - case IOV_SVAL(IOV_PKTGEN): - bcmerror = dhdsdio_pktgen_set(bus, arg); - break; -#endif /* SDTEST */ - -#if defined(USE_SDIOFIFO_IOVAR) - case IOV_GVAL(IOV_WATERMARK): - int_val = (int32)watermark; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WATERMARK): - watermark = (uint)int_val; - watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark; - DHD_ERROR(("Setting watermark as 0x%x.\n", watermark)); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL); - break; - - case IOV_GVAL(IOV_MESBUSYCTRL): - int_val = (int32)mesbusyctrl; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MESBUSYCTRL): - mesbusyctrl = (uint)int_val; - mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) - ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; - DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl)); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, - ((uint8)mesbusyctrl | 0x80), NULL); - break; -#endif - - - case IOV_GVAL(IOV_DONGLEISOLATION): - int_val = bus->dhd->dongle_isolation; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DONGLEISOLATION): - bus->dhd->dongle_isolation = bool_val; - break; - - case IOV_SVAL(IOV_DEVRESET): - DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", - __FUNCTION__, bool_val, bus->dhd->dongle_reset, - bus->dhd->busstate)); - - ASSERT(bus->dhd->osh); - /* ASSERT(bus->cl_devid); */ - - dhd_bus_devreset(bus->dhd, (uint8)bool_val); - - break; - /* - * softap firmware is updated through module parameter or android private command - */ - - case IOV_GVAL(IOV_DEVRESET): - DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__)); - - /* Get its status */ - int_val = (bool) bus->dhd->dongle_reset; - bcopy(&int_val, arg, val_size); - - break; - - case IOV_GVAL(IOV_KSO): - int_val = dhdsdio_sleepcsr_get(bus); - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DEVCAP): - int_val = dhdsdio_devcap_get(bus); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DEVCAP): - dhdsdio_devcap_set(bus, (uint8) int_val); - break; - case IOV_GVAL(IOV_TXGLOMSIZE): - int_val = (int32)bus->txglomsize; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXGLOMSIZE): - if (int_val > SDPCM_MAXGLOM_SIZE) { - bcmerror = BCME_ERROR; - } else { - bus->txglomsize = (uint)int_val; - } - break; - case IOV_SVAL(IOV_HANGREPORT): - bus->dhd->hang_report = bool_val; - DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report)); - break; - - case IOV_GVAL(IOV_HANGREPORT): - int_val = (int32)bus->dhd->hang_report; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_TXINRX_THRES): - int_val = bus->txinrx_thres; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_TXINRX_THRES): - if (int_val < 0) { - bcmerror = BCME_BADARG; - } else { - bus->txinrx_thres = int_val; - } - break; - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } - -exit: - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - - return bcmerror; -} - -static int -dhdsdio_write_vars(dhd_bus_t *bus) -{ - int bcmerror = 0; - uint32 varsize, phys_size; - uint32 varaddr; - uint8 *vbuffer; - uint32 varsizew; -#ifdef DHD_DEBUG - uint8 *nvram_ularray; -#endif /* DHD_DEBUG */ - - /* 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; - - varaddr += bus->dongle_ram_base; - - if (bus->vars) { - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { - if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { - DHD_ERROR(("PR85623WAR in place\n")); - varsize += 4; - varaddr -= 4; - } - } - - vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); - if (!vbuffer) - return BCME_NOMEM; - - bzero(vbuffer, varsize); - bcopy(bus->vars, vbuffer, bus->varsz); - - /* Write the vars list */ - bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); -#ifdef DHD_DEBUG - /* Verify NVRAM bytes */ - DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); - nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); - if (!nvram_ularray) - return BCME_NOMEM; - - /* Upload image to verify downloaded contents. */ - memset(nvram_ularray, 0xaa, varsize); - - /* Read the vars list to temp buffer for comparison */ - bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", - __FUNCTION__, bcmerror, varsize, varaddr)); - } - /* Compare the org NVRAM with the one read from RAM */ - if (memcmp(vbuffer, nvram_ularray, varsize)) { - DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); - } else - DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", - __FUNCTION__)); - - MFREE(bus->dhd->osh, nvram_ularray, varsize); -#endif /* DHD_DEBUG */ - - MFREE(bus->dhd->osh, vbuffer, varsize); - } - - phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; - - phys_size += bus->dongle_ram_base; - - /* adjust to the user specified RAM */ - DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", - phys_size, bus->ramsize)); - DHD_INFO(("Vars are at %d, orig varsize is %d\n", - varaddr, varsize)); - varsize = ((phys_size - 4) - varaddr); - - /* - * Determine the length token: - * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. - */ - if (bcmerror) { - varsizew = 0; - } else { - varsizew = varsize / 4; - varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); - varsizew = htol32(varsizew); - } - - DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); - - /* Write the length token to the last word */ - bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4), - (uint8*)&varsizew, 4); - - return bcmerror; -} - -static int -dhdsdio_download_state(dhd_bus_t *bus, bool enter) -{ - uint retries; - int bcmerror = 0; - int foundcr4 = 0; - - if (!bus->sih) - return BCME_ERROR; - /* 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; - - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - foundcr4 = 1; - } else { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - } - - if (!foundcr4) { - si_core_disable(bus->sih, 0); - if (bcmsdh_regfail(bus->sdh)) { - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - si_core_reset(bus->sih, 0, 0); - if (bcmsdh_regfail(bus->sdh)) { - DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", - __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - /* Disable remap for download */ - if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, FALSE); - - if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID) { - /* Disabling Remap for SRAM_3 */ - si_socram_set_bankpda(bus->sih, 0x3, 0x0); - } - - /* Clear the top bit of memory */ - if (bus->ramsize) { - uint32 zeros = 0; - if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, - (uint8*)&zeros, 4) < 0) { - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - } - } else { - /* For CR4, - * Halt ARM - * Remove ARM reset - * Read RAM base address [0x18_0000] - * [next] Download firmware - * [done at else] Populate the reset vector - * [done at else] Remove ARM halt - */ - /* Halt ARM & remove reset */ - si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); - } - } else { - if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - if (!si_iscoreup(bus->sih)) { - DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - if ((bcmerror = dhdsdio_write_vars(bus))) { - DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); - goto fail; - } - - /* Enable remap before ARM reset but after vars. - * No backplane access in remap mode - */ - if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, TRUE); - - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && - !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); - - - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - } else { - /* cr4 has no socram, but tcm's */ - /* write vars */ - if ((bcmerror = dhdsdio_write_vars(bus))) { - DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); - goto fail; - } - - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && - !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); - - /* switch back to arm core again */ - if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - /* write address 0 with reset instruction */ - bcmerror = dhdsdio_membytes(bus, TRUE, 0, - (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); - - /* now remove reset and halt and continue to run CR4 */ - } - - si_core_reset(bus->sih, 0, 0); - if (bcmsdh_regfail(bus->sdh)) { - DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - /* Allow HT Clock now that the ARM is running. */ - bus->alp_only = FALSE; - - bus->dhd->busstate = DHD_BUS_LOAD; - } - -fail: - /* Always return to SDIOD core */ - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) - si_setcore(bus->sih, SDIOD_CORE_ID, 0); - - return bcmerror; -} - -int -dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - dhd_bus_t *bus = dhdp->bus; - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - uint32 actionid; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - /* Look up var locally; if not found pass to host driver */ - if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) { - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - /* Turn on clock in case SD command needs backplane */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set); - - /* Check for bus configuration changes of interest */ - - /* If it was divisor change, read the new one */ - if (set && strcmp(name, "sd_divisor") == 0) { - if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, - &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { - bus->sd_divisor = -1; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); - } else { - DHD_INFO(("%s: noted %s update, value now %d\n", - __FUNCTION__, name, bus->sd_divisor)); - } - } - /* If it was a mode change, read the new one */ - if (set && strcmp(name, "sd_mode") == 0) { - if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, - &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { - bus->sd_mode = -1; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); - } else { - DHD_INFO(("%s: noted %s update, value now %d\n", - __FUNCTION__, name, bus->sd_mode)); - } - } - /* Similar check for blocksize change */ - if (set && strcmp(name, "sd_blocksize") == 0) { - int32 fnum = 2; - if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32), - &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { - bus->blocksize = 0; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); - } else { - DHD_INFO(("%s: noted %s update, value now %d\n", - __FUNCTION__, "sd_blocksize", bus->blocksize)); - - dhdsdio_tune_fifoparam(bus); - } - } - bus->roundup = MIN(max_roundup, bus->blocksize); - - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - goto exit; - } - - DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} - -void -dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) -{ - osl_t *osh; - uint32 local_hostintmask; - uint8 saveclk; - uint retries; - int err; - bool wlfc_enabled = FALSE; - - if (!bus->dhd) - return; - - osh = bus->dhd->osh; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bcmsdh_waitlockfree(bus->sdh); - - if (enforce_mutex) - dhd_os_sdlock(bus->dhd); - - if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { - /* if Firmware already hangs disbale any interrupt */ - bus->dhd->busstate = DHD_BUS_DOWN; - bus->hostintmask = 0; - bcmsdh_intr_disable(bus->sdh); - } else { - - BUS_WAKE(bus); - - /* Change our idea of bus state */ - bus->dhd->busstate = DHD_BUS_DOWN; - - if (KSO_ENAB(bus)) { - - /* Enable clock for device interrupts */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Disable and clear interrupts at the chip level also */ - W_SDREG(0, &bus->regs->hostintmask, retries); - local_hostintmask = bus->hostintmask; - bus->hostintmask = 0; - - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) { - DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", - __FUNCTION__, err)); - } - - /* Turn off the bus (F2), free any pending packets */ - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); - - /* Clear any pending interrupts now that F2 is disabled */ - W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); - } - - /* Turn off the backplane clock (only) */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - -#ifdef PROP_TXSTATUS - wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED); -#endif - if (!wlfc_enabled) { -#ifdef DHDTCPACK_SUPPRESS - /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, - * when there is a newly coming packet from network stack. - */ - dhd_tcpack_info_tbl_clean(bus->dhd); -#endif /* DHDTCPACK_SUPPRESS */ - /* Clear the data packet queues */ - pktq_flush(osh, &bus->txq, TRUE, NULL, 0); - } - - /* Clear any held glomming stuff */ - if (bus->glomd) - PKTFREE(osh, bus->glomd, FALSE); - - if (bus->glom) - PKTFREE(osh, bus->glom, FALSE); - - bus->glom = bus->glomd = NULL; - - /* Clear rx control and wake any waiters */ - bus->rxlen = 0; - dhd_os_ioctl_resp_wake(bus->dhd); - - /* Reset some F2 state stuff */ - bus->rxskip = FALSE; - bus->tx_seq = bus->rx_seq = 0; - - bus->tx_max = 4; - - if (enforce_mutex) - dhd_os_sdunlock(bus->dhd); -} - -#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD) -extern uint sd_txglom; -#endif -void -dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) -{ - /* can't enable host txglom by default, some platforms have no - * (or crappy) ADMA support and txglom will cause kernel assertions (e.g. - * panda board) - */ - dhd_bus_t *bus = dhdp->bus; -#ifdef BCMSDIOH_TXGLOM - char buf[256]; - uint32 rxglom; - int32 ret; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BCMSDIOH_STD - if (enable) - enable = sd_txglom; -#endif /* BCMSDIOH_STD */ - - if (enable) { - rxglom = 1; - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("bus:rxglom", (void *)&rxglom, 4, buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - if (ret >= 0) - bus->txglom_enable = TRUE; - else { -#ifdef BCMSDIOH_STD - sd_txglom = 0; -#endif /* BCMSDIOH_STD */ - bus->txglom_enable = FALSE; - } - } else -#endif /* BCMSDIOH_TXGLOM */ - bus->txglom_enable = FALSE; -} - -int -dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) -{ - dhd_bus_t *bus = dhdp->bus; - dhd_timeout_t tmo; - uint retries = 0; - uint8 ready, enable; - int err, ret = 0; - uint8 saveclk; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(bus->dhd); - if (!bus->dhd) - return 0; - - if (enforce_mutex) - dhd_os_sdlock(bus->dhd); - - /* Make sure backplane clock is on, needed to generate F2 interrupt */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (bus->clkstate != CLK_AVAIL) { - DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate)); - ret = -1; - goto exit; - } - - - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) { - DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); - ret = -1; - goto exit; - } - - /* Enable function 2 (frame transfers) */ - W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT), - &bus->regs->tosbmailboxdata, retries); - enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); - - /* Give the dongle some time to do its thing and set IOR2 */ - dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); - - ready = 0; - while (ready != enable && !dhd_timeout_expired(&tmo)) - ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); - - DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", - __FUNCTION__, enable, ready, tmo.elapsed)); - - - /* If F2 successfully enabled, set core and enable interrupts */ - if (ready == enable) { - /* Make sure we're talking to the core. */ - if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) - bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); - ASSERT(bus->regs != NULL); - - /* Set up the interrupt mask and enable interrupts */ - bus->hostintmask = HOSTINTMASK; - /* corerev 4 could use the newer interrupt logic to detect the frames */ - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && - (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { - bus->hostintmask &= ~I_HMB_FRAME_IND; - bus->hostintmask |= I_XMTDATA_AVAIL; - } - W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); - - if (bus->sih->buscorerev < 15) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, - (uint8)watermark, &err); - } - - /* Set bus state according to enable result */ - dhdp->busstate = DHD_BUS_DATA; - - /* bcmsdh_intr_unmask(bus->sdh); */ - - bus->intdis = FALSE; - if (bus->intr) { - DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); - bcmsdh_intr_enable(bus->sdh); - } else { - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - } - - } - - - else { - /* Disable F2 again */ - enable = SDIO_FUNC_ENABLE_1; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); - } - - if (dhdsdio_sr_cap(bus)) { - dhdsdio_sr_init(bus); - /* Masking the chip active interrupt permanantly */ - bus->hostintmask &= ~I_CHIPACTIVE; - W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); - DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n", - __FUNCTION__, bus->hostintmask)); - } - else - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); - - /* If we didn't come up, turn off backplane clock */ - if (dhdp->busstate != DHD_BUS_DATA) - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - -exit: - if (enforce_mutex) - dhd_os_sdunlock(bus->dhd); - - return ret; -} - -static void -dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) -{ - bcmsdh_info_t *sdh = bus->sdh; - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - uint16 lastrbc; - uint8 hi, lo; - int err; - - DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__, - (abort ? "abort command, " : ""), (rtx ? ", send NAK" : ""))); - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return; - } - - if (abort) { - bcmsdh_abort(sdh, SDIO_FUNC_2); - } - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); - if (err) { - DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__)); - goto fail; - } - bus->f1regdata++; - - /* Wait until the packet has been flushed (device/FIFO stable) */ - for (lastrbc = retries = 0xffff; retries > 0; retries--) { - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err); - if (err) { - DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__)); - goto fail; - } - - bus->f1regdata += 2; - - if ((hi == 0) && (lo == 0)) - break; - - if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { - DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n", - __FUNCTION__, lastrbc, ((hi << 8) + lo))); - } - lastrbc = (hi << 8) + lo; - } - - if (!retries) { - DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc)); - } else { - DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries))); - } - - if (rtx) { - bus->rxrtx++; - W_SDREG(SMB_NAK, ®s->tosbmailbox, retries); - bus->f1regdata++; - if (retries <= retry_limit) { - bus->rxskip = TRUE; - } - } - - /* Clear partial in any case */ - bus->nextlen = 0; - -fail: - /* If we can't reach the device, signal failure */ - if (err || bcmsdh_regfail(sdh)) - bus->dhd->busstate = DHD_BUS_DOWN; -} - -static void -dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) -{ - bcmsdh_info_t *sdh = bus->sdh; - uint rdlen, pad; - - int sdret; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Control data already received in aligned rxctl */ - if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) - goto gotpkt; - - ASSERT(bus->rxbuf); - /* Set rxctl for frame (w/optional alignment) */ - bus->rxctl = bus->rxbuf; - if (dhd_alignctl) { - bus->rxctl += firstread; - if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) - bus->rxctl += (DHD_SDALIGN - pad); - bus->rxctl -= firstread; - } - ASSERT(bus->rxctl >= bus->rxbuf); - - /* Copy the already-read portion over */ - bcopy(hdr, bus->rxctl, firstread); - if (len <= firstread) - goto gotpkt; - - /* Copy the full data pkt in gSPI case and process ioctl. */ - if (bus->bus == SPI_BUS) { - bcopy(hdr, bus->rxctl, len); - goto gotpkt; - } - - /* Raise rdlen to next SDIO block to avoid tail command */ - rdlen = len - 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->dhd->maxctl)) - rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { - rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (forcealign && (rdlen & (ALIGNMENT - 1))) - rdlen = ROUNDUP(rdlen, ALIGNMENT); - - /* Drop if the read is too big or it exceeds our maximum */ - if ((rdlen + firstread) > bus->dhd->maxctl) { - DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n", - __FUNCTION__, rdlen, bus->dhd->maxctl)); - bus->dhd->rx_errors++; - dhdsdio_rxfail(bus, FALSE, FALSE); - goto done; - } - - if ((len - doff) > bus->dhd->maxctl) { - DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", - __FUNCTION__, len, (len - doff), bus->dhd->maxctl)); - bus->dhd->rx_errors++; bus->rx_toolong++; - dhdsdio_rxfail(bus, FALSE, FALSE); - goto done; - } - - - /* Read remainder of frame body into the rxctl buffer */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - /* Control frame failures need retransmission */ - if (sdret < 0) { - DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret)); - bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */ - dhdsdio_rxfail(bus, TRUE, TRUE); - goto done; - } - -gotpkt: - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_CTL_ON()) { - prhex("RxCtrl", bus->rxctl, len); - } -#endif - - /* Point to valid data and indicate its length */ - bus->rxctl += doff; - bus->rxlen = len - doff; - -done: - /* Awake any waiters */ - dhd_os_ioctl_resp_wake(bus->dhd); -} -int -dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, - void **pkt, uint32 *pkt_count); - -static uint8 -dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) -{ - uint16 dlen, totlen; - uint8 *dptr, num = 0; - - uint16 sublen, check; - void *pfirst, *plast, *pnext; - void * list_tail[DHD_MAX_IFS] = { NULL }; - void * list_head[DHD_MAX_IFS] = { NULL }; - uint8 idx; - osl_t *osh = bus->dhd->osh; - - int errcode; - uint8 chan, seq, doff, sfdoff; - uint8 txmax; - uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; - uint reorder_info_len; - - int ifidx = 0; - bool usechain = bus->use_rxchain; - - /* If packets, issue read(s) and send up packet chain */ - /* Return sequence numbers consumed? */ - - DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom)); - - /* If there's a descriptor, generate the packet chain */ - if (bus->glomd) { - dhd_os_sdlock_rxq(bus->dhd); - - pfirst = plast = pnext = NULL; - dlen = (uint16)PKTLEN(osh, bus->glomd); - dptr = PKTDATA(osh, bus->glomd); - if (!dlen || (dlen & 1)) { - DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n", - __FUNCTION__, dlen)); - dlen = 0; - } - - for (totlen = num = 0; dlen; num++) { - /* Get (and move past) next length */ - sublen = ltoh16_ua(dptr); - dlen -= sizeof(uint16); - dptr += sizeof(uint16); - if ((sublen < SDPCM_HDRLEN) || - ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { - DHD_ERROR(("%s: descriptor len %d bad: %d\n", - __FUNCTION__, num, sublen)); - pnext = NULL; - break; - } - if (sublen % DHD_SDALIGN) { - DHD_ERROR(("%s: sublen %d not a multiple of %d\n", - __FUNCTION__, sublen, DHD_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 */ - if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) { - DHD_ERROR(("%s: PKTGET failed, num %d len %d\n", - __FUNCTION__, num, sublen)); - break; - } - ASSERT(!PKTLINK(pnext)); - if (!pfirst) { - ASSERT(!plast); - pfirst = plast = pnext; - } else { - ASSERT(plast); - PKTSETNEXT(osh, plast, pnext); - plast = pnext; - } - - /* Adhere to start alignment requirements */ - PKTALIGN(osh, pnext, sublen, DHD_SDALIGN); - } - - /* If all allocations succeeded, save packet chain in bus structure */ - if (pnext) { - DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n", - __FUNCTION__, totlen, num)); - if (DHD_GLOM_ON() && bus->nextlen) { - if (totlen != bus->nextlen) { - DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d " - "rxseq %d\n", __FUNCTION__, bus->nextlen, - totlen, rxseq)); - } - } - bus->glom = pfirst; - pfirst = pnext = NULL; - } else { - if (pfirst) - PKTFREE(osh, pfirst, FALSE); - bus->glom = NULL; - num = 0; - } - - /* Done with descriptor packet */ - PKTFREE(osh, bus->glomd, FALSE); - bus->glomd = NULL; - bus->nextlen = 0; - - dhd_os_sdunlock_rxq(bus->dhd); - } - - /* Ok -- either we just generated a packet chain, or had one from before */ - if (bus->glom) { - if (DHD_GLOM_ON()) { - DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__)); - for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) { - DHD_GLOM((" %p: %p len 0x%04x (%d)\n", - pnext, (uint8*)PKTDATA(osh, pnext), - PKTLEN(osh, pnext), PKTLEN(osh, pnext))); - } - } - - pfirst = bus->glom; - dlen = (uint16)pkttotlen(osh, 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 = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, (uint8*)PKTDATA(osh, pfirst), - dlen, pfirst, NULL, NULL); - } else if (bus->dataptr) { - errcode = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, bus->dataptr, - dlen, NULL, NULL, NULL); - sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); - if (sublen != dlen) { - DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n", - __FUNCTION__, dlen, sublen)); - errcode = -1; - } - pnext = NULL; - } else { - DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen)); - errcode = -1; - } - bus->f2rxdata++; - ASSERT(errcode != BCME_PENDING); - - /* On failure, kill the superframe, allow a couple retries */ - if (errcode < 0) { - DHD_ERROR(("%s: glom read of %d bytes failed: %d\n", - __FUNCTION__, dlen, errcode)); - bus->dhd->rx_errors++; - - if (bus->glomerr++ < 3) { - dhdsdio_rxfail(bus, TRUE, TRUE); - } else { - bus->glomerr = 0; - dhdsdio_rxfail(bus, TRUE, FALSE); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(osh, bus->glom, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->rxglomfail++; - bus->glom = NULL; - } - return 0; - } - -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - prhex("SUPERFRAME", PKTDATA(osh, pfirst), - MIN(PKTLEN(osh, pfirst), 48)); - } -#endif - - - /* Validate the superframe header */ - dptr = (uint8 *)PKTDATA(osh, pfirst); - sublen = ltoh16_ua(dptr); - check = ltoh16_ua(dptr + sizeof(uint16)); - - 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) { - DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n", - __FUNCTION__, 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 ((uint16)~(sublen^check)) { - DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n", - __FUNCTION__, sublen, check)); - errcode = -1; - } else if (ROUNDUP(sublen, bus->blocksize) != dlen) { - DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", - __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen)); - errcode = -1; - } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) { - DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__, - SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]))); - errcode = -1; - } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { - DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__)); - errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || - (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) { - DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", - __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), - SDPCM_HDRLEN)); - errcode = -1; - } - - /* Check sequence number of superframe SW header */ - if (rxseq != seq) { - DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n", - __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((uint8)(txmax - bus->tx_seq) > 0x70) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", - __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_max; - } - bus->tx_max = txmax; - - /* Remove superframe header, remember offset */ - PKTPULL(osh, pfirst, doff); - sfdoff = doff; - - /* Validate all the subframe headers */ - for (num = 0, pnext = pfirst; pnext && !errcode; - num++, pnext = PKTNEXT(osh, pnext)) { - dptr = (uint8 *)PKTDATA(osh, pnext); - dlen = (uint16)PKTLEN(osh, pnext); - sublen = ltoh16_ua(dptr); - check = ltoh16_ua(dptr + sizeof(uint16)); - chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - prhex("subframe", dptr, 32); - } -#endif - - if ((uint16)~(sublen^check)) { - DHD_ERROR(("%s (subframe %d): HW hdr error: " - "len/check 0x%04x/0x%04x\n", - __FUNCTION__, num, sublen, check)); - errcode = -1; - } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { - DHD_ERROR(("%s (subframe %d): length mismatch: " - "len 0x%04x, expect 0x%04x\n", - __FUNCTION__, num, sublen, dlen)); - errcode = -1; - } else if ((chan != SDPCM_DATA_CHANNEL) && - (chan != SDPCM_EVENT_CHANNEL)) { - DHD_ERROR(("%s (subframe %d): bad channel %d\n", - __FUNCTION__, num, chan)); - errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { - DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n", - __FUNCTION__, 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 */ - PKTPUSH(osh, pfirst, sfdoff); - dhdsdio_rxfail(bus, TRUE, TRUE); - } else { - bus->glomerr = 0; - dhdsdio_rxfail(bus, TRUE, FALSE); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(osh, bus->glom, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->rxglomfail++; - bus->glom = NULL; - } - bus->nextlen = 0; - return 0; - } - - /* Basic SD framing looks ok - process each packet (header) */ - bus->glom = NULL; - plast = NULL; - - dhd_os_sdlock_rxq(bus->dhd); - for (num = 0; pfirst; rxseq++, pfirst = pnext) { - pnext = PKTNEXT(osh, pfirst); - PKTSETNEXT(osh, pfirst, NULL); - - dptr = (uint8 *)PKTDATA(osh, pfirst); - sublen = ltoh16_ua(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]); - - DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", - __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst), - PKTLEN(osh, pfirst), sublen, chan, seq)); - - ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); - - if (rxseq != seq) { - DHD_GLOM(("%s: rx_seq %d, expected %d\n", - __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - prhex("Rx Subframe Data", dptr, dlen); - } -#endif - - PKTSETLEN(osh, pfirst, sublen); - PKTPULL(osh, pfirst, doff); - - reorder_info_len = sizeof(reorder_info_buf); - - if (PKTLEN(osh, pfirst) == 0) { - PKTFREE(bus->dhd->osh, pfirst, FALSE); - continue; - } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, - &reorder_info_len) != 0) { - DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); - bus->dhd->rx_errors++; - PKTFREE(osh, pfirst, FALSE); - continue; - } - if (reorder_info_len) { - uint32 free_buf_count; - void *ppfirst; - - ppfirst = pfirst; - /* Reordering info from the firmware */ - dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, - reorder_info_len, &ppfirst, &free_buf_count); - - if (free_buf_count == 0) { - continue; - } - else { - void *temp; - - /* go to the end of the chain and attach the pnext there */ - temp = ppfirst; - while (PKTNEXT(osh, temp) != NULL) { - temp = PKTNEXT(osh, temp); - } - pfirst = temp; - if (list_tail[ifidx] == NULL) - list_head[ifidx] = ppfirst; - else - PKTSETNEXT(osh, list_tail[ifidx], ppfirst); - list_tail[ifidx] = pfirst; - } - - num += (uint8)free_buf_count; - } - else { - /* this packet will go up, link back into chain and count it */ - - if (list_tail[ifidx] == NULL) { - list_head[ifidx] = list_tail[ifidx] = pfirst; - } - else { - PKTSETNEXT(osh, list_tail[ifidx], pfirst); - list_tail[ifidx] = pfirst; - } - num++; - } -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n", - __FUNCTION__, num, pfirst, - PKTDATA(osh, pfirst), PKTLEN(osh, pfirst), - PKTNEXT(osh, pfirst), PKTLINK(pfirst))); - prhex("", (uint8 *)PKTDATA(osh, pfirst), - MIN(PKTLEN(osh, pfirst), 32)); - } -#endif /* DHD_DEBUG */ - } - dhd_os_sdunlock_rxq(bus->dhd); - - for (idx = 0; idx < DHD_MAX_IFS; idx++) { - if (list_head[idx]) { - void *temp; - uint8 cnt = 0; - temp = list_head[idx]; - do { - temp = PKTNEXT(osh, temp); - cnt++; - } while (temp); - if (cnt) { - dhd_os_sdunlock(bus->dhd); - dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); - dhd_os_sdlock(bus->dhd); - } - } - } - bus->rxglomframes++; - bus->rxglompkts += num; - } - return num; -} - - -/* Return TRUE if there may be more frames to read */ -static uint -dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) -{ - osl_t *osh = bus->dhd->osh; - bcmsdh_info_t *sdh = bus->sdh; - - uint16 len, check; /* Extracted hardware header fields */ - uint8 chan, seq, doff; /* Extracted software header fields */ - uint8 fcbits; /* Extracted fcbits from software header */ - uint8 delta; - - void *pkt; /* Packet for event or data frames */ - uint16 pad; /* Number of pad bytes to read */ - uint16 rdlen; /* Total number of bytes to read */ - uint8 rxseq; /* Next sequence number to expect */ - uint rxleft = 0; /* Remaining number of frames allowed */ - int sdret; /* Return code from bcmsdh calls */ - uint8 txmax; /* Maximum tx sequence offered */ - bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ - uint8 *rxbuf; - int ifidx = 0; - uint rxcount = 0; /* Total frames read */ - uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; - uint reorder_info_len; - uint pkt_count; - -#if defined(DHD_DEBUG) || defined(SDTEST) - bool sdtest = FALSE; /* To limit message spew from test mode */ -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bus->readframes = TRUE; - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: KSO off\n", __FUNCTION__)); - bus->readframes = FALSE; - return 0; - } - - ASSERT(maxframes); - -#ifdef SDTEST - /* Allow pktgen to override maxframes */ - if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { - maxframes = bus->pktgen_count; - sdtest = TRUE; - } -#endif - - /* Not finished unless we encounter no more frames indication */ - *finished = FALSE; - - - for (rxseq = bus->rx_seq, rxleft = maxframes; - !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; - rxseq++, rxleft--) { -#ifdef DHDTCPACK_SUP_DBG - if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) { - if (bus->dotxinrx == FALSE) - DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n", - __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode)); - } -#ifdef DEBUG_COUNTER - else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) { - tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++; - } -#endif /* DEBUG_COUNTER */ -#endif /* DHDTCPACK_SUP_DBG */ - /* tx more to improve rx performance */ - if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { - dhdsdio_sendpendctl(bus); - } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) && - !bus->fcstate && DATAOK(bus) && - (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) { - dhdsdio_sendfromq(bus, dhd_txbound); -#ifdef DHDTCPACK_SUPPRESS - /* In TCPACK_SUP_DELAYTX mode, do txinrx only if - * 1. Any DATA packet to TX - * 2. TCPACK to TCPDATA PSH packets. - * in bus txq. - */ - bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ? - FALSE : TRUE; -#endif - } - - /* Handle glomming separately */ - if (bus->glom || bus->glomd) { - uint8 cnt; - DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n", - __FUNCTION__, bus->glomd, bus->glom)); - cnt = dhdsdio_rxglom(bus, rxseq); - DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt)); - rxseq += cnt - 1; - rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; - continue; - } - - /* Try doing single read if we can */ - if (dhd_readahead && bus->nextlen) { - uint16 nextlen = bus->nextlen; - bus->nextlen = 0; - - if (bus->bus == SPI_BUS) { - rdlen = len = nextlen; - } - else { - rdlen = len = nextlen << 4; - - /* 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 + firstread) < MAX_RX_DATASZ)) - rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { - rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); - } - } - - /* We use bus->rxctl buffer in WinXP for initial control pkt receives. - * Later we use buffer-poll for data as well as control packets. - * This is required because dhd receives full frame in gSPI unlike SDIO. - * After the frame is received we have to distinguish whether it is data - * or non-data frame. - */ - /* Allocate a packet buffer */ - dhd_os_sdlock_rxq(bus->dhd); - if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) { - if (bus->bus == SPI_BUS) { - bus->usebufpool = FALSE; - bus->rxctl = bus->rxbuf; - if (dhd_alignctl) { - bus->rxctl += firstread; - if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) - bus->rxctl += (DHD_SDALIGN - pad); - bus->rxctl -= firstread; - } - ASSERT(bus->rxctl >= bus->rxbuf); - rxbuf = bus->rxctl; - /* Read the entire frame */ - sdret = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(sdh), - SDIO_FUNC_2, - F2SYNC, rxbuf, rdlen, - NULL, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - - /* Control frame failures need retransmission */ - if (sdret < 0) { - DHD_ERROR(("%s: read %d control bytes failed: %d\n", - __FUNCTION__, rdlen, sdret)); - /* dhd.rx_ctlerrs is higher level */ - bus->rxc_errors++; - dhd_os_sdunlock_rxq(bus->dhd); - dhdsdio_rxfail(bus, TRUE, - (bus->bus == SPI_BUS) ? FALSE : TRUE); - continue; - } - } else { - /* Give up on data, request rtx of events */ - DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d " - "expected rxseq %d\n", - __FUNCTION__, len, rdlen, rxseq)); - /* Just go try again w/normal header read */ - dhd_os_sdunlock_rxq(bus->dhd); - continue; - } - } else { - if (bus->bus == SPI_BUS) - bus->usebufpool = TRUE; - - ASSERT(!PKTLINK(pkt)); - PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); - rxbuf = (uint8 *)PKTDATA(osh, pkt); - /* Read the entire frame */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), - SDIO_FUNC_2, - F2SYNC, rxbuf, rdlen, - pkt, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - if (sdret < 0) { - DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n", - __FUNCTION__, rdlen, sdret)); - PKTFREE(bus->dhd->osh, pkt, FALSE); - bus->dhd->rx_errors++; - dhd_os_sdunlock_rxq(bus->dhd); - /* Force retry w/normal header read. Don't attempt NAK for - * gSPI - */ - dhdsdio_rxfail(bus, TRUE, - (bus->bus == SPI_BUS) ? FALSE : TRUE); - continue; - } - } - dhd_os_sdunlock_rxq(bus->dhd); - - /* Now check the header */ - bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN); - - /* Extract hardware header fields */ - len = ltoh16_ua(bus->rxhdr); - check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); - - /* All zeros means readahead info was bad */ - if (!(len|check)) { - DHD_INFO(("%s (nextlen): read zeros in HW header???\n", - __FUNCTION__)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - GSPI_PR55150_BAILOUT; - continue; - } - - /* Validate check bytes */ - if ((uint16)~(len^check)) { - DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check" - " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen, - len, check)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - bus->rx_badhdr++; - dhdsdio_rxfail(bus, FALSE, FALSE); - GSPI_PR55150_BAILOUT; - continue; - } - - /* Validate frame length */ - if (len < SDPCM_HDRLEN) { - DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n", - __FUNCTION__, len)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - GSPI_PR55150_BAILOUT; - continue; - } - - /* 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) */ - DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; " - "expected rxseq %d\n", - __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE); - GSPI_PR55150_BAILOUT; - 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) { - DHD_INFO(("%s (nextlen): got frame w/nextlen too large" - " (%d), seq %d\n", __FUNCTION__, bus->nextlen, - seq)); - bus->nextlen = 0; - } - - bus->dhd->rx_readahead_cnt ++; - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - delta = 0; - if (~bus->flowcontrol & fcbits) { - bus->fc_xoff++; - delta = 1; - } - if (bus->flowcontrol & ~fcbits) { - bus->fc_xon++; - delta = 1; - } - - if (delta) { - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n", - __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((uint8)(txmax - bus->tx_seq) > 0x70) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", - __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_max; - } - bus->tx_max = txmax; - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - prhex("Rx Data", rxbuf, len); - } else if (DHD_HDRS_ON()) { - prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); - } -#endif - - if (chan == SDPCM_CONTROL_CHANNEL) { - if (bus->bus == SPI_BUS) { - dhdsdio_read_control(bus, rxbuf, len, doff); - if (bus->usebufpool) { - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - } - continue; - } else { - DHD_ERROR(("%s (nextlen): readahead on control" - " packet %d?\n", __FUNCTION__, seq)); - /* Force retry w/normal header read */ - bus->nextlen = 0; - dhdsdio_rxfail(bus, FALSE, TRUE); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - continue; - } - } - - if ((bus->bus == SPI_BUS) && !bus->usebufpool) { - DHD_ERROR(("Received %d bytes on %d channel. Running out of " - "rx pktbuf's or not yet malloced.\n", len, chan)); - continue; - } - - /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { - DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n", - __FUNCTION__, doff, len, SDPCM_HDRLEN)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - ASSERT(0); - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - /* All done with this one -- now deliver the packet */ - goto deliver; - } - /* gSPI frames should not be handled in fractions */ - if (bus->bus == SPI_BUS) { - break; - } - - /* Read frame header (hardware and software) */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - bus->rxhdr, firstread, NULL, NULL, NULL); - bus->f2rxhdrs++; - ASSERT(sdret != BCME_PENDING); - - if (sdret < 0) { - DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret)); - bus->rx_hdrfail++; - dhdsdio_rxfail(bus, TRUE, TRUE); - continue; - } - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() || DHD_HDRS_ON()) { - prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); - } -#endif - - /* Extract hardware header fields */ - len = ltoh16_ua(bus->rxhdr); - check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); - - /* All zeros means no more frames */ - if (!(len|check)) { - *finished = TRUE; - break; - } - - /* Validate check bytes */ - if ((uint16)~(len^check)) { - DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n", - __FUNCTION__, len, check)); - bus->rx_badhdr++; - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - /* Validate frame length */ - if (len < SDPCM_HDRLEN) { - DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, 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)) { - DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n", - __FUNCTION__, doff, len, SDPCM_HDRLEN, seq)); - bus->rx_badhdr++; - ASSERT(0); - dhdsdio_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) { - DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n", - __FUNCTION__, bus->nextlen, seq)); - bus->nextlen = 0; - } - - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - delta = 0; - if (~bus->flowcontrol & fcbits) { - bus->fc_xoff++; - delta = 1; - } - if (bus->flowcontrol & ~fcbits) { - bus->fc_xon++; - delta = 1; - } - - if (delta) { - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((uint8)(txmax - bus->tx_seq) > 0x70) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", - __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_max; - } - bus->tx_max = txmax; - - /* Call a separate function for control frames */ - if (chan == SDPCM_CONTROL_CHANNEL) { - dhdsdio_read_control(bus, bus->rxhdr, len, doff); - continue; - } - - ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) || - (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL)); - - /* Length to read */ - rdlen = (len > firstread) ? (len - 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 + firstread) < MAX_RX_DATASZ)) - rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { - rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (forcealign && (rdlen & (ALIGNMENT - 1))) - rdlen = ROUNDUP(rdlen, ALIGNMENT); - - if ((rdlen + firstread) > MAX_RX_DATASZ) { - /* Too long -- skip this frame */ - DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen)); - bus->dhd->rx_errors++; bus->rx_toolong++; - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - dhd_os_sdlock_rxq(bus->dhd); - if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) { - /* Give up on data, request rtx of events */ - DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n", - __FUNCTION__, rdlen, chan)); - bus->dhd->rx_dropped++; - dhd_os_sdunlock_rxq(bus->dhd); - dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan)); - continue; - } - dhd_os_sdunlock_rxq(bus->dhd); - - ASSERT(!PKTLINK(pkt)); - - /* Leave room for what we already read, and align remainder */ - ASSERT(firstread < (PKTLEN(osh, pkt))); - PKTPULL(osh, pkt, firstread); - PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); - - /* Read the remaining frame data */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - if (sdret < 0) { - DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen, - ((chan == SDPCM_EVENT_CHANNEL) ? "event" : - ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->dhd->rx_errors++; - dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan)); - continue; - } - - /* Copy the already-read portion */ - PKTPUSH(osh, pkt, firstread); - bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread); - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - prhex("Rx Data", PKTDATA(osh, pkt), len); - } -#endif - -deliver: - /* Save superframe descriptor and allocate packet frame */ - if (chan == SDPCM_GLOM_CHANNEL) { - if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { - DHD_GLOM(("%s: got glom descriptor, %d bytes:\n", - __FUNCTION__, len)); -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - prhex("Glom Data", PKTDATA(osh, pkt), len); - } -#endif - PKTSETLEN(osh, pkt, len); - ASSERT(doff == SDPCM_HDRLEN); - PKTPULL(osh, pkt, SDPCM_HDRLEN); - bus->glomd = pkt; - } else { - DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__)); - dhdsdio_rxfail(bus, FALSE, FALSE); - } - continue; - } - - /* Fill in packet len and prio, deliver upward */ - PKTSETLEN(osh, pkt, len); - PKTPULL(osh, pkt, doff); - -#ifdef SDTEST - /* Test channel packets are processed separately */ - if (chan == SDPCM_TEST_CHANNEL) { - dhdsdio_testrcv(bus, pkt, seq); - continue; - } -#endif /* SDTEST */ - - if (PKTLEN(osh, pkt) == 0) { - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - continue; - } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf, - &reorder_info_len) != 0) { - DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->dhd->rx_errors++; - continue; - } - if (reorder_info_len) { - /* Reordering info from the firmware */ - dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len, - &pkt, &pkt_count); - if (pkt_count == 0) - continue; - } - else - pkt_count = 1; - - /* Unlock during rx call */ - dhd_os_sdunlock(bus->dhd); - dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); - dhd_os_sdlock(bus->dhd); - } - rxcount = maxframes - rxleft; -#ifdef DHD_DEBUG - /* Message if we hit the limit */ - if (!rxleft && !sdtest) - DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes)); - else -#endif /* DHD_DEBUG */ - DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount)); - /* Back off rxseq if awaiting rtx, update rx_seq */ - if (bus->rxskip) - rxseq--; - bus->rx_seq = rxseq; - - if (bus->reqbussleep) - { - dhdsdio_bussleep(bus, TRUE); - bus->reqbussleep = FALSE; - } - bus->readframes = FALSE; - - return rxcount; -} - -static uint32 -dhdsdio_hostmail(dhd_bus_t *bus) -{ - sdpcmd_regs_t *regs = bus->regs; - uint32 intstatus = 0; - uint32 hmb_data; - uint8 fcbits; - uint retries = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Read mailbox data and ack that we did so */ - R_SDREG(hmb_data, ®s->tohostmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries); - bus->f1regdata += 2; - - /* Dongle recomposed rx frames, accept them again */ - if (hmb_data & HMB_DATA_NAKHANDLED) { - DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq)); - if (!bus->rxskip) { - DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__)); - } - bus->rxskip = FALSE; - intstatus |= FRAME_AVAIL_MASK(bus); - } - - /* - * 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) - DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n", - bus->sdpcm_ver, SDPCM_PROT_VERSION)); - else - DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver)); - /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && - (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { - uint32 val; - - val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); - val &= ~CC_XMTDATAAVAIL_MODE; - val |= CC_XMTDATAAVAIL_CTRL; - W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); - - val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); - } - -#ifdef DHD_DEBUG - /* Retrieve console state address now that firmware should have updated it */ - { - sdpcm_shared_t shared; - if (dhdsdio_readshared(bus, &shared) == 0) - bus->console_addr = shared.console_addr; - } -#endif /* DHD_DEBUG */ - } - - /* - * Flow Control has been moved into the RX headers and this out of band - * method isn't used any more. Leave this here for possibly 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; - } - - /* At least print a message if FW halted */ - if (hmb_data & HMB_DATA_FWHALT) { - DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n")); - dhdsdio_checkdied(bus, NULL, 0); - bus->dhd->busstate = DHD_BUS_DOWN; - } - - /* Shouldn't be any others */ - if (hmb_data & ~(HMB_DATA_DEVREADY | - HMB_DATA_FWHALT | - HMB_DATA_NAKHANDLED | - HMB_DATA_FC | - HMB_DATA_FWREADY | - HMB_DATA_FCDATA_MASK | - HMB_DATA_VERSION_MASK)) { - DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data)); - } - - return intstatus; -} - -static bool -dhdsdio_dpc(dhd_bus_t *bus) -{ - bcmsdh_info_t *sdh = bus->sdh; - sdpcmd_regs_t *regs = bus->regs; - uint32 intstatus, newstatus = 0; - uint retries = 0; - uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */ - uint txlimit = dhd_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 */ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - dhd_os_sdlock(bus->dhd); - - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); - bus->intstatus = 0; - dhd_os_sdunlock(bus->dhd); - return 0; - } - - /* Start with leftover status bits */ - intstatus = bus->intstatus; - - if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - goto exit; - } - - /* If waiting for HTAVAIL, check status */ - if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) { - int err; - uint8 clkctl, devctl = 0; - -#ifdef DHD_DEBUG - /* Check for inconsistent device control */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - if (err) { - DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } else { - ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); - } -#endif /* DHD_DEBUG */ - - /* Read CSR, if clock on switch to AVAIL, else ignore */ - clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (err) { - DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } - - DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl)); - - if (SBSDIO_HTAV(clkctl)) { - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - if (err) { - DHD_ERROR(("%s: error reading DEVCTL: %d\n", - __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - if (err) { - DHD_ERROR(("%s: error writing DEVCTL: %d\n", - __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } - bus->clkstate = CLK_AVAIL; - } else { - goto clkwait; - } - } - - BUS_WAKE(bus); - - /* Make sure backplane clock is on */ - dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); - if (bus->clkstate != CLK_AVAIL) - goto clkwait; - - /* Pending interrupt indicates new device status */ - if (bus->ipend) { - bus->ipend = FALSE; - R_SDREG(newstatus, ®s->intstatus, retries); - bus->f1regdata++; - if (bcmsdh_regfail(bus->sdh)) - newstatus = 0; - newstatus &= bus->hostintmask; - bus->fcstate = !!(newstatus & I_HMB_FC_STATE); - if (newstatus) { - bus->f1regdata++; - if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && - (newstatus == I_XMTDATA_AVAIL)) { - } - else - W_SDREG(newstatus, ®s->intstatus, retries); - } - } - - /* 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_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries); - R_SDREG(newstatus, ®s->intstatus, retries); - bus->f1regdata += 2; - bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); - intstatus |= (newstatus & bus->hostintmask); - } - - /* Just being here means nothing more to do for chipactive */ - if (intstatus & I_CHIPACTIVE) { - /* ASSERT(bus->clkstate == CLK_AVAIL); */ - intstatus &= ~I_CHIPACTIVE; - } - - /* Handle host mailbox indication */ - if (intstatus & I_HMB_HOST_INT) { - intstatus &= ~I_HMB_HOST_INT; - intstatus |= dhdsdio_hostmail(bus); - } - - /* Generally don't ask for these, can get CRC errors... */ - if (intstatus & I_WR_OOSYNC) { - DHD_ERROR(("Dongle reports WR_OOSYNC\n")); - intstatus &= ~I_WR_OOSYNC; - } - - if (intstatus & I_RD_OOSYNC) { - DHD_ERROR(("Dongle reports RD_OOSYNC\n")); - intstatus &= ~I_RD_OOSYNC; - } - - if (intstatus & I_SBINT) { - DHD_ERROR(("Dongle reports SBINT\n")); - intstatus &= ~I_SBINT; - } - - /* Would be active due to wake-wlan in gSPI */ - if (intstatus & I_CHIPACTIVE) { - DHD_INFO(("Dongle reports CHIPACTIVE\n")); - intstatus &= ~I_CHIPACTIVE; - } - - if (intstatus & I_HMB_FC_STATE) { - DHD_INFO(("Dongle reports HMB_FC_STATE\n")); - intstatus &= ~I_HMB_FC_STATE; - } - - /* Ignore frame indications if rxskip is set */ - if (bus->rxskip) { - intstatus &= ~FRAME_AVAIL_MASK(bus); - } - - /* On frame indication, read available frames */ - if (PKT_AVAILABLE(bus, intstatus)) { - framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); - if (rxdone || bus->rxskip) - intstatus &= ~FRAME_AVAIL_MASK(bus); - rxlimit -= MIN(framecnt, rxlimit); - } - - /* Keep still-pending events for next scheduling */ - bus->intstatus = intstatus; - -clkwait: - /* Re-enable interrupts to detect new device events (mailbox, rx frame) - * or clock availability. (Allows tx loop to check ipend if desired.) - * (Unless register access seems hosed, as we may not be able to ACK...) - */ - if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) { - DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", - __FUNCTION__, rxdone, framecnt)); - bus->intdis = FALSE; -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(bus->sdh, TRUE); -#endif /* defined(OOB_INTR_ONLY) */ - bcmsdh_intr_enable(sdh); - } - -#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) - /* In case of SW-OOB(using edge trigger), - * Check interrupt status in the dongle again after enable irq on the host. - * and rechedule dpc if interrupt is pended in the dongle. - * There is a chance to miss OOB interrupt while irq is disabled on the host. - * No need to do this with HW-OOB(level trigger) - */ - R_SDREG(newstatus, ®s->intstatus, retries); - if (bcmsdh_regfail(bus->sdh)) - newstatus = 0; - if (newstatus & bus->hostintmask) { - bus->ipend = TRUE; - resched = TRUE; - } -#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ - -#ifdef PROP_TXSTATUS - dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE); -#endif - - if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) - dhdsdio_sendpendctl(bus); - - /* Send queued frames (limit 1 if rx may still be pending) */ - else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && - pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { - framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax); - framecnt = dhdsdio_sendfromq(bus, framecnt); - txlimit -= framecnt; - } - /* Resched the DPC if ctrl cmd is pending on bus credit */ - if (bus->ctrl_frame_stat) - resched = TRUE; - - /* 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->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { - if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & - SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { - /* Bus failed because of KSO */ - DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__)); - bus->kso = FALSE; - } else { - DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n", - __FUNCTION__)); - bus->dhd->busstate = DHD_BUS_DOWN; - bus->intstatus = 0; - } - } else if (bus->clkstate == CLK_PENDING) { - /* Awaiting I_CHIPACTIVE; don't resched */ - } else if (bus->intstatus || bus->ipend || - (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || - PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ - resched = TRUE; - } - - bus->dpc_sched = resched; - - /* If we're done for now, turn off clock request. */ - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - } - -exit: - - if (!resched && dhd_dpcpoll) { - if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) - resched = TRUE; - } - - dhd_os_sdunlock(bus->dhd); - return resched; -} - -bool -dhd_bus_dpc(struct dhd_bus *bus) -{ - bool resched; - - /* Call the DPC directly. */ - DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); - resched = dhdsdio_dpc(bus); - - return resched; -} - -void -dhdsdio_isr(void *arg) -{ - dhd_bus_t *bus = (dhd_bus_t*)arg; - bcmsdh_info_t *sdh; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!bus) { - DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); - return; - } - sdh = bus->sdh; - - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - return; - } - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Count the interrupt call */ - bus->intrcount++; - bus->ipend = TRUE; - - /* Shouldn't get this interrupt if we're sleeping? */ - if (!SLPAUTO_ENAB(bus)) { - if (bus->sleeping) { - DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n")); - return; - } else if (!KSO_ENAB(bus)) { - DHD_ERROR(("ISR in devsleep 1\n")); - } - } - - /* Disable additional interrupts (is this needed now)? */ - if (bus->intr) { - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - } else { - DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n")); - } - - bcmsdh_intr_disable(sdh); - bus->intdis = TRUE; - -#if defined(SDIO_ISR_THREAD) - DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK(bus->dhd); - dhdsdio_dpc(bus); - DHD_OS_WAKE_UNLOCK(bus->dhd); -#else - - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - -#endif /* defined(SDIO_ISR_THREAD) */ - -} - -#ifdef SDTEST -static void -dhdsdio_pktgen_init(dhd_bus_t *bus) -{ - /* Default to specified length, or full range */ - if (dhd_pktgen_len) { - bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN); - bus->pktgen_minlen = bus->pktgen_maxlen; - } else { - bus->pktgen_maxlen = MAX_PKTGEN_LEN; - bus->pktgen_minlen = 0; - } - bus->pktgen_len = (uint16)bus->pktgen_minlen; - - /* Default to per-watchdog burst with 10s print time */ - bus->pktgen_freq = 1; - bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0; - bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; - - /* Default to echo mode */ - bus->pktgen_mode = DHD_PKTGEN_ECHO; - bus->pktgen_stop = 1; -} - -static void -dhdsdio_pktgen(dhd_bus_t *bus) -{ - void *pkt; - uint8 *data; - uint pktcount; - uint fillbyte; - osl_t *osh = bus->dhd->osh; - uint16 len; - ulong time_lapse; - uint sent_pkts; - uint rcvd_pkts; - - /* Display current count if appropriate */ - if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { - bus->pktgen_ptick = 0; - printf("%s: send attempts %d, rcvd %d, errors %d\n", - __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); - - /* Print throughput stats only for constant length packet runs */ - if (bus->pktgen_minlen == bus->pktgen_maxlen) { - time_lapse = jiffies - bus->pktgen_prev_time; - bus->pktgen_prev_time = jiffies; - sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent; - bus->pktgen_prev_sent = bus->pktgen_sent; - rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd; - bus->pktgen_prev_rcvd = bus->pktgen_rcvd; - - printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n", - __FUNCTION__, - (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8, - (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8); - } - } - - /* For recv mode, just make sure dongle has started sending */ - if (bus->pktgen_mode == DHD_PKTGEN_RECV) { - if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { - bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; - dhdsdio_sdtest_set(bus, bus->pktgen_total); - } - return; - } - - /* Otherwise, generate or request the specified number of packets */ - for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) { - /* Stop if total has been reached */ - if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) { - bus->pktgen_count = 0; - break; - } - - /* Allocate an appropriate-sized packet */ - if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { - len = SDPCM_TEST_PKT_CNT_FLD_LEN; - } else { - len = bus->pktgen_len; - } - if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), - TRUE))) {; - DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); - break; - } - PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); - data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; - - /* Write test header cmd and extra based on mode */ - switch (bus->pktgen_mode) { - case DHD_PKTGEN_ECHO: - *data++ = SDPCM_TEST_ECHOREQ; - *data++ = (uint8)bus->pktgen_sent; - break; - - case DHD_PKTGEN_SEND: - *data++ = SDPCM_TEST_DISCARD; - *data++ = (uint8)bus->pktgen_sent; - break; - - case DHD_PKTGEN_RXBURST: - *data++ = SDPCM_TEST_BURST; - *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */ - break; - - default: - DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode)); - PKTFREE(osh, pkt, TRUE); - bus->pktgen_count = 0; - return; - } - - /* Write test header length field */ - *data++ = (bus->pktgen_len >> 0); - *data++ = (bus->pktgen_len >> 8); - - /* Write frame count in a 4 byte field adjucent to SDPCM test header for - * burst mode - */ - if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { - *data++ = (uint8)(bus->pktgen_count >> 0); - *data++ = (uint8)(bus->pktgen_count >> 8); - *data++ = (uint8)(bus->pktgen_count >> 16); - *data++ = (uint8)(bus->pktgen_count >> 24); - } else { - - /* Then fill in the remainder -- N/A for burst */ - for (fillbyte = 0; fillbyte < len; fillbyte++) - *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); - } - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; - prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN); - } -#endif - - /* Send it */ - if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) { - bus->pktgen_fail++; - if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) - bus->pktgen_count = 0; - } - bus->pktgen_sent++; - - /* Bump length if not fixed, wrap at max */ - if (++bus->pktgen_len > bus->pktgen_maxlen) - bus->pktgen_len = (uint16)bus->pktgen_minlen; - - /* Special case for burst mode: just send one request! */ - if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) - break; - } -} - -static void -dhdsdio_sdtest_set(dhd_bus_t *bus, uint count) -{ - void *pkt; - uint8 *data; - osl_t *osh = bus->dhd->osh; - - /* Allocate the packet */ - if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + - SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) { - DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); - return; - } - PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + - SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN); - data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; - - /* Fill in the test header */ - *data++ = SDPCM_TEST_SEND; - *data++ = (count > 0)?TRUE:FALSE; - *data++ = (bus->pktgen_maxlen >> 0); - *data++ = (bus->pktgen_maxlen >> 8); - *data++ = (uint8)(count >> 0); - *data++ = (uint8)(count >> 8); - *data++ = (uint8)(count >> 16); - *data++ = (uint8)(count >> 24); - - /* Send it */ - if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) - bus->pktgen_fail++; -} - - -static void -dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) -{ - osl_t *osh = bus->dhd->osh; - uint8 *data; - uint pktlen; - - uint8 cmd; - uint8 extra; - uint16 len; - uint16 offset; - - /* Check for min length */ - if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) { - DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen)); - PKTFREE(osh, pkt, FALSE); - return; - } - - /* Extract header fields */ - data = PKTDATA(osh, pkt); - cmd = *data++; - extra = *data++; - len = *data++; len += *data++ << 8; - DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len)); - /* Check length for relevant commands */ - if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { - if (pktlen != len + SDPCM_TEST_HDRLEN) { - DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d" - " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); - PKTFREE(osh, pkt, FALSE); - return; - } - } - - /* Process as per command */ - switch (cmd) { - case SDPCM_TEST_ECHOREQ: - /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ - *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; - if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) { - bus->pktgen_sent++; - } else { - bus->pktgen_fail++; - PKTFREE(osh, pkt, FALSE); - } - bus->pktgen_rcvd++; - break; - - case SDPCM_TEST_ECHORSP: - if (bus->ext_loop) { - PKTFREE(osh, pkt, FALSE); - bus->pktgen_rcvd++; - break; - } - - for (offset = 0; offset < len; offset++, data++) { - if (*data != SDPCM_TEST_FILL(offset, extra)) { - DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: " - "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n", - offset, len, SDPCM_TEST_FILL(offset, extra), *data)); - break; - } - } - PKTFREE(osh, pkt, FALSE); - bus->pktgen_rcvd++; - break; - - case SDPCM_TEST_DISCARD: - { - int i = 0; - uint8 *prn = data; - uint8 testval = extra; - for (i = 0; i < len; i++) { - if (*prn != testval) { - DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", - i, bus->pktgen_rcvd_rcvsession, testval, *prn)); - prn++; testval++; - } - } - } - PKTFREE(osh, pkt, FALSE); - bus->pktgen_rcvd++; - break; - - case SDPCM_TEST_BURST: - case SDPCM_TEST_SEND: - default: - DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d" - " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); - PKTFREE(osh, pkt, FALSE); - break; - } - - /* For recv mode, stop at limit (and tell dongle to stop sending) */ - if (bus->pktgen_mode == DHD_PKTGEN_RECV) { - if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { - bus->pktgen_rcvd_rcvsession++; - - if (bus->pktgen_total && - (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { - bus->pktgen_count = 0; - DHD_ERROR(("Pktgen:rcv test complete!\n")); - bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; - dhdsdio_sdtest_set(bus, FALSE); - bus->pktgen_rcvd_rcvsession = 0; - } - } - } -} -#endif /* SDTEST */ - -int dhd_bus_oob_intr_register(dhd_pub_t *dhdp) -{ - int err = 0; - -#if defined(OOB_INTR_ONLY) - err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus); -#endif - return err; -} - -void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp) -{ -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_unregister(dhdp->bus->sdh); -#endif -} - -void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable) -{ -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(dhdp->bus->sdh, enable); -#endif -} - -void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub) -{ - bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh); -} - -void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub) -{ - bcmsdh_dev_relax(dhdpub->bus->sdh); -} - -bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub) -{ - bool enabled = FALSE; - - enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh); - return enabled; -} - -extern bool -dhd_bus_watchdog(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus; - - DHD_TIMER(("%s: Enter\n", __FUNCTION__)); - - bus = dhdp->bus; - - if (bus->dhd->dongle_reset) - return FALSE; - - if (bus->dhd->hang_was_sent) { - dhd_os_wd_timer(bus->dhd, 0); - return FALSE; - } - - /* Ignore the timer if simulating bus down */ - if (!SLPAUTO_ENAB(bus) && bus->sleeping) - return FALSE; - - if (dhdp->busstate == DHD_BUS_DOWN) - return FALSE; - - dhd_os_sdlock(bus->dhd); - - /* Poll period: check device if appropriate. */ - if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) { - uint32 intstatus = 0; - - /* Reset poll tick */ - bus->polltick = 0; - - /* Check device if no interrupts */ - if (!bus->intr || (bus->intrcount == bus->lastintrs)) { - - if (!bus->dpc_sched) { - uint8 devpend; - devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, - SDIOD_CCCR_INTPEND, 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; - if (bus->intr) { - bcmsdh_intr_disable(bus->sdh); - } - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - } - - /* Update interrupt tracking */ - bus->lastintrs = bus->intrcount; - } - -#ifdef DHD_DEBUG - /* Poll for console output periodically */ - if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { - bus->console.count += dhd_watchdog_ms; - if (bus->console.count >= dhd_console_ms) { - bus->console.count -= dhd_console_ms; - /* Make sure backplane clock is on */ - if (SLPAUTO_ENAB(bus)) - dhdsdio_bussleep(bus, FALSE); - else - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (dhdsdio_readconsole(bus) < 0) - dhd_console_ms = 0; /* On error, stop trying */ - } - } -#endif /* DHD_DEBUG */ - -#ifdef SDTEST - /* Generate packets if configured */ - if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { - /* Make sure backplane clock is on */ - if (SLPAUTO_ENAB(bus)) - dhdsdio_bussleep(bus, FALSE); - else - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - bus->pktgen_tick = 0; - dhdsdio_pktgen(bus); - } -#endif - - /* On idle timeout clear activity flag and/or turn off clock */ -#ifdef DHD_USE_IDLECOUNT - if (bus->activity) - bus->activity = FALSE; - else { - bus->idlecount++; - - if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) { - DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); - if (SLPAUTO_ENAB(bus)) { - if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) - dhd_os_wd_timer(bus->dhd, 0); - } else - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - - bus->idlecount = 0; - } - } -#else - if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { - if (++bus->idlecount >= bus->idletime) { - bus->idlecount = 0; - if (bus->activity) { - bus->activity = FALSE; - if (SLPAUTO_ENAB(bus)) { - if (!bus->readframes) - dhdsdio_bussleep(bus, TRUE); - else - bus->reqbussleep = TRUE; - } - else - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - } - } - } -#endif /* DHD_USE_IDLECOUNT */ - - dhd_os_sdunlock(bus->dhd); - - return bus->ipend; -} - -#ifdef DHD_DEBUG -extern int -dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) -{ - dhd_bus_t *bus = dhdp->bus; - uint32 addr, val; - int rv; - void *pkt; - - /* Address could be zero if CONSOLE := 0 in dongle Makefile */ - if (bus->console_addr == 0) - return BCME_UNSUPPORTED; - - /* Exclusive bus access */ - dhd_os_sdlock(bus->dhd); - - /* Don't allow input if dongle is in reset */ - if (bus->dhd->dongle_reset) { - dhd_os_sdunlock(bus->dhd); - return BCME_NOTREADY; - } - - /* Request clock to allow SDIO accesses */ - BUS_WAKE(bus); - /* No pend allowed since txpkt is called later, ht clk has to be on */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Zero cbuf_index */ - addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx); - val = htol32(0); - if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) - goto done; - - /* Write message into cbuf */ - addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf); - if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) - goto done; - - /* Write length into vcons_in */ - addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in); - val = htol32(msglen); - if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) - goto done; - - /* Bump dongle by sending an empty packet on the event channel. - * sdpcm_sendup (RX) checks for virtual console input. - */ - if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) - rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE); - -done: - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - - return rv; -} -#endif /* DHD_DEBUG */ - -#ifdef DHD_DEBUG -static void -dhd_dump_cis(uint fn, uint8 *cis) -{ - uint byte, tag, tdata; - DHD_INFO(("Function %d CIS:\n", fn)); - - for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { - if ((byte % 16) == 0) - DHD_INFO((" ")); - DHD_INFO(("%02x ", cis[byte])); - if ((byte % 16) == 15) - DHD_INFO(("\n")); - if (!tdata--) { - tag = cis[byte]; - if (tag == 0xff) - break; - else if (!tag) - tdata = 0; - else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) - tdata = cis[byte + 1] + 1; - else - DHD_INFO(("]")); - } - } - if ((byte % 16) != 15) - DHD_INFO(("\n")); -} -#endif /* DHD_DEBUG */ - -static bool -dhdsdio_chipmatch(uint16 chipid) -{ - if (chipid == BCM4325_CHIP_ID) - return TRUE; - if (chipid == BCM4329_CHIP_ID) - return TRUE; - if (chipid == BCM4315_CHIP_ID) - return TRUE; - if (chipid == BCM4319_CHIP_ID) - return TRUE; - if (chipid == BCM4336_CHIP_ID) - return TRUE; - if (chipid == BCM4330_CHIP_ID) - return TRUE; - if (chipid == BCM43237_CHIP_ID) - return TRUE; - if (chipid == BCM43362_CHIP_ID) - return TRUE; - if (chipid == BCM4314_CHIP_ID) - return TRUE; - if (chipid == BCM43242_CHIP_ID) - return TRUE; - if (chipid == BCM43340_CHIP_ID) - return TRUE; - if (chipid == BCM43341_CHIP_ID) - return TRUE; - if (chipid == BCM43143_CHIP_ID) - return TRUE; - if (chipid == BCM43342_CHIP_ID) - return TRUE; - if (chipid == BCM4334_CHIP_ID) - return TRUE; - if (chipid == BCM43239_CHIP_ID) - return TRUE; - if (chipid == BCM4324_CHIP_ID) - return TRUE; - if (chipid == BCM4335_CHIP_ID) - return TRUE; - if (chipid == BCM4339_CHIP_ID) - return TRUE; - if (chipid == BCM43349_CHIP_ID) - return TRUE; - if (chipid == BCM4345_CHIP_ID) - return TRUE; - if (chipid == BCM4350_CHIP_ID) - return TRUE; - if (chipid == BCM4354_CHIP_ID) - return TRUE; - if (chipid == BCM4356_CHIP_ID) - return TRUE; - if (chipid == BCM4358_CHIP_ID) - return TRUE; - if (chipid == BCM43430_CHIP_ID) - return TRUE; - if (BCM4349_CHIP(chipid)) - return TRUE; - return FALSE; -} - -static void * -dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, - uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) -{ - int ret; - dhd_bus_t *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. - */ - dhd_txbound = DHD_TXBOUND; - dhd_rxbound = DHD_RXBOUND; - dhd_alignctl = TRUE; - sd1idle = TRUE; - dhd_readahead = TRUE; - retrydata = FALSE; - dhd_doflow = FALSE; - dhd_dongle_ramsize = 0; - dhd_txminmax = DHD_TXMINMAX; - - forcealign = TRUE; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid)); - - /* We make assumptions about address window mappings */ - ASSERT((uintptr)regsva == SI_ENUM_BASE); - - /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start - * means early parse could fail, so here we should get either an ID - * we recognize OR (-1) indicating we must request power first. - */ - /* Check the Vendor ID */ - switch (venid) { - case 0x0000: - case VENDOR_BROADCOM: - break; - default: - DHD_ERROR(("%s: unknown vendor: 0x%04x\n", - __FUNCTION__, venid)); - goto forcereturn; - } - - /* Check the Device ID and make sure it's one that we support */ - switch (devid) { - case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */ - case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */ - case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */ - DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__)); - break; - case BCM4329_D11N_ID: /* 4329 802.11n dualband device */ - case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */ - case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */ - case 0x4329: - DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__)); - break; - case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */ - case BCM4315_D11G_ID: /* 4315 802.11g id */ - case BCM4315_D11A_ID: /* 4315 802.11a id */ - DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__)); - break; - case BCM4319_D11N_ID: /* 4319 802.11n id */ - case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ - case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ - DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__)); - break; - case 0: - DHD_INFO(("%s: allow device id 0, will check chip internals\n", - __FUNCTION__)); - break; - - default: - DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", - __FUNCTION__, venid, devid)); - goto forcereturn; - } - - if (osh == NULL) { - DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__)); - goto forcereturn; - } - - /* Allocate private bus interface state */ - if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { - DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); - goto fail; - } - bzero(bus, sizeof(dhd_bus_t)); - bus->sdh = sdh; - bus->cl_devid = (uint16)devid; - bus->bus = DHD_BUS; - bus->bus_num = bus_no; - bus->slot_num = slot; - 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 (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { - DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__)); - goto fail; - } - - /* Attach to the dhd/OS/network interface */ - if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) { - DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); - goto fail; - } - - /* Allocate buffers */ - if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { - DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__)); - goto fail; - } - - if (!(dhdsdio_probe_init(bus, osh, sdh))) { - DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__)); - goto fail; - } - - if (bus->intr) { - /* Register interrupt callback, but mask it (not operational yet). */ - DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__)); - bcmsdh_intr_disable(sdh); - if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { - DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n", - __FUNCTION__, ret)); - goto fail; - } - DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__)); - } else { - DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n", - __FUNCTION__)); - } - - DHD_INFO(("%s: completed!!\n", __FUNCTION__)); - - /* if firmware path present try to download and bring up bus */ - bus->dhd->hang_report = TRUE; - if (dhd_download_fw_on_driverload) { - if ((ret = dhd_bus_start(bus->dhd)) != 0) { - DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); - goto fail; - } - } - /* Ok, have the per-port tell the stack we're open for business */ - if (dhd_register_if(bus->dhd, 0, TRUE) != 0) { - DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); - goto fail; - } - - - - init_waitqueue_head(&bus->bus_sleep); - - return bus; - -fail: - dhdsdio_release(bus, osh); - -forcereturn: - - return NULL; -} - -static bool -dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, - uint16 devid) -{ - int err = 0; - uint8 clkctl = 0; - - bus->alp_only = TRUE; - bus->sih = NULL; - - /* Return the window to backplane enumeration space for core access */ - if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) { - DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__)); - } - -#if defined(DHD_DEBUG) - DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n", - bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4))); -#endif - - - /* Force PLL off until si_attach() programs PLL control regs */ - - - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err); - if (!err) - clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - - if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) { - DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", - err, DHD_INIT_CLKCTL1, clkctl)); - goto fail; - } - -#ifdef DHD_DEBUG - if (DHD_INFO_ON()) { - uint fn, numfn; - uint8 *cis[SDIOD_MAX_IOFUNCS]; - int err = 0; - - numfn = bcmsdh_query_iofnum(sdh); - ASSERT(numfn <= SDIOD_MAX_IOFUNCS); - - /* Make sure ALP is available before trying to read CIS */ - SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, NULL)), - !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY); - - /* Now request ALP be put on the bus */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - DHD_INIT_CLKCTL2, &err); - OSL_DELAY(65); - - for (fn = 0; fn <= numfn; fn++) { - if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { - DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn)); - break; - } - bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); - - if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) { - DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err)); - MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); - break; - } - dhd_dump_cis(fn, cis[fn]); - } - - while (fn-- > 0) { - ASSERT(cis[fn]); - MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); - } - - if (err) { - DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n")); - goto fail; - } - } -#endif /* DHD_DEBUG */ - - /* si_attach() will provide an SI handle and scan the backplane */ - if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, - &bus->vars, &bus->varsz))) { - DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); - goto fail; - } - -#ifdef DHD_DEBUG - DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n", - bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg)); -#endif /* DHD_DEBUG */ - - - bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); - - if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { - DHD_ERROR(("%s: unsupported chip: 0x%04x\n", - __FUNCTION__, bus->sih->chip)); - goto fail; - } - - if (bus->sih->buscorerev >= 12) - dhdsdio_clk_kso_init(bus); - else - bus->kso = TRUE; - - if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) { - } - - si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); - - - /* Get info on the ARM and SOCRAM cores... */ - if (!DHD_NOPMU(bus)) { - if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || - (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || - (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { - bus->armrev = si_corerev(bus->sih); - } else { - DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); - goto fail; - } - - if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { - DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); - goto fail; - } - } else { - /* cr4 has a different way to find the RAM size from TCM's */ - if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { - DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); - goto fail; - } - /* also populate base address */ - switch ((uint16)bus->sih->chip) { - case BCM4335_CHIP_ID: - case BCM4339_CHIP_ID: - case BCM43349_CHIP_ID: - bus->dongle_ram_base = CR4_4335_RAM_BASE; - break; - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM4356_CHIP_ID: - case BCM4358_CHIP_ID: - bus->dongle_ram_base = CR4_4350_RAM_BASE; - break; - case BCM4360_CHIP_ID: - bus->dongle_ram_base = CR4_4360_RAM_BASE; - break; - case BCM4345_CHIP_ID: - bus->dongle_ram_base = CR4_4345_RAM_BASE; - break; - case BCM4349_CHIP_GRPID: - bus->dongle_ram_base = CR4_4349_RAM_BASE; - break; - default: - bus->dongle_ram_base = 0; - DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", - __FUNCTION__, bus->dongle_ram_base)); - } - } - bus->ramsize = bus->orig_ramsize; - if (dhd_dongle_ramsize) - dhd_dongle_setramsize(bus, dhd_dongle_ramsize); - - DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", - bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); - - bus->srmemsize = si_socram_srmem_size(bus->sih); - } - - /* ...but normally deal with the SDPCMDEV core */ - if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) && - !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) { - DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__)); - goto fail; - } - bus->sdpcmrev = si_corerev(bus->sih); - - /* Set core control so an SDIO reset does a backplane reset */ - OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); - bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; - - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && - (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) - { - uint32 val; - - val = R_REG(osh, &bus->regs->corecontrol); - val &= ~CC_XMTDATAAVAIL_MODE; - val |= CC_XMTDATAAVAIL_CTRL; - W_REG(osh, &bus->regs->corecontrol, val); - } - - - pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); - - /* Locate an appropriately-aligned portion of hdrbuf */ - bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); - - /* Set the poll and/or interrupt flags */ - bus->intr = (bool)dhd_intr; - if ((bus->poll = (bool)dhd_poll)) - bus->pollrate = 1; - - /* Setting default Glom size */ - bus->txglomsize = SDPCM_DEFGLOM_SIZE; - - return TRUE; - -fail: - if (bus->sih != NULL) { - si_detach(bus->sih); - bus->sih = NULL; - } - return FALSE; -} - -static bool -dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->maxctl) { - bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; - if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) { - DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", - __FUNCTION__, bus->rxblen)); - goto fail; - } - } - /* Allocate buffer to receive glomed packet */ - if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { - DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", - __FUNCTION__, MAX_DATA_BUF)); - /* release rxbuf which was already located as above */ - if (!bus->rxblen) - DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen); - goto fail; - } - - /* Align the buffer */ - if ((uintptr)bus->databuf % DHD_SDALIGN) - bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN)); - else - bus->dataptr = bus->databuf; - - return TRUE; - -fail: - return FALSE; -} - -static bool -dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) -{ - int32 fnum; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bus->_srenab = FALSE; - -#ifdef SDTEST - dhdsdio_pktgen_init(bus); -#endif /* SDTEST */ - - /* Disable F2 to clear any intermediate frame state on the dongle */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); - - bus->dhd->busstate = DHD_BUS_DOWN; - bus->sleeping = FALSE; - bus->rxflow = FALSE; - bus->prev_rxlim_hit = 0; - - /* Done with backplane-dependent accesses, can drop clock... */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); - - /* ...and initialize clock/power states */ - bus->clkstate = CLK_SDONLY; - bus->idletime = (int32)dhd_idletime; - bus->idleclock = DHD_IDLE_ACTIVE; - - /* Query the SD clock speed */ - if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, - &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor")); - bus->sd_divisor = -1; - } else { - DHD_INFO(("%s: Initial value for %s is %d\n", - __FUNCTION__, "sd_divisor", bus->sd_divisor)); - } - - /* Query the SD bus mode */ - if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, - &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode")); - bus->sd_mode = -1; - } else { - DHD_INFO(("%s: Initial value for %s is %d\n", - __FUNCTION__, "sd_mode", bus->sd_mode)); - } - - /* Query the F2 block size, set roundup accordingly */ - fnum = 2; - if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32), - &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { - bus->blocksize = 0; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); - } else { - DHD_INFO(("%s: Initial value for %s is %d\n", - __FUNCTION__, "sd_blocksize", bus->blocksize)); - - dhdsdio_tune_fifoparam(bus); - } - bus->roundup = MIN(max_roundup, bus->blocksize); - -#ifdef DHDENABLE_TAILPAD - if (bus->pad_pkt) - PKTFREE(osh, bus->pad_pkt, FALSE); - bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE); - if (bus->pad_pkt == NULL) - DHD_ERROR(("failed to allocate padding packet\n")); - else { - int alignment_offset = 0; - uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt); - if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN))) - PKTPUSH(osh, bus->pad_pkt, alignment_offset); - PKTSETNEXT(osh, bus->pad_pkt, NULL); - } -#endif /* DHDENABLE_TAILPAD */ - - /* Query if bus module supports packet chaining, default to use if supported */ - if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, - &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) { - bus->sd_rxchain = FALSE; - } else { - DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n", - __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support"))); - } - bus->use_rxchain = (bool)bus->sd_rxchain; - bus->txinrx_thres = CUSTOM_TXINRX_THRES; - /* TX first in dhdsdio_readframes() */ - bus->dotxinrx = TRUE; - - return TRUE; -} - -int -dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, - char *pfw_path, char *pnv_path) -{ - int ret; - - bus->fw_path = pfw_path; - bus->nv_path = pnv_path; - - ret = dhdsdio_download_firmware(bus, osh, bus->sdh); - - - return ret; -} - -static int -dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) -{ - int ret; - -#if defined(SUPPORT_MULTIPLE_REVISION) - if (concate_revision(bus, bus->fw_path, bus->nv_path) != 0) { - DHD_ERROR(("%s: fail to concatnate revison \n", - __FUNCTION__)); - return BCME_BADARG; - } -#endif /* SUPPORT_MULTIPLE_REVISION */ - - DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n", - __FUNCTION__, bus->fw_path, bus->nv_path)); - DHD_OS_WAKE_LOCK(bus->dhd); - - /* Download the firmware */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - ret = _dhdsdio_download_firmware(bus); - - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - DHD_OS_WAKE_UNLOCK(bus->dhd); - return ret; -} - -/* Detach and free everything */ -static void -dhdsdio_release(dhd_bus_t *bus, osl_t *osh) -{ - bool dongle_isolation = FALSE; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus) { - ASSERT(osh); - - if (bus->dhd) { - dongle_isolation = bus->dhd->dongle_isolation; - dhd_detach(bus->dhd); - } - - /* De-register interrupt handler */ - bcmsdh_intr_disable(bus->sdh); - bcmsdh_intr_dereg(bus->sdh); - - if (bus->dhd) { - dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); - dhd_free(bus->dhd); - bus->dhd = NULL; - } - - dhdsdio_release_malloc(bus, osh); - -#ifdef DHD_DEBUG - if (bus->console.buf != NULL) - MFREE(osh, bus->console.buf, bus->console.bufsize); -#endif - -#ifdef DHDENABLE_TAILPAD - if (bus->pad_pkt) - PKTFREE(osh, bus->pad_pkt, FALSE); -#endif /* DHDENABLE_TAILPAD */ - - MFREE(osh, bus, sizeof(dhd_bus_t)); - } - - DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -} - -static void -dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd && bus->dhd->dongle_reset) - return; - - if (bus->rxbuf) { -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(osh, bus->rxbuf, bus->rxblen); -#endif - bus->rxctl = bus->rxbuf = NULL; - bus->rxlen = 0; - } - - if (bus->databuf) { -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(osh, bus->databuf, MAX_DATA_BUF); -#endif - bus->databuf = NULL; - } - - if (bus->vars && bus->varsz) { - MFREE(osh, bus->vars, bus->varsz); - bus->vars = NULL; - } - -} - - -static void -dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) -{ - DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, - bus->dhd, bus->dhd->dongle_reset)); - - if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) - return; - - if (bus->sih) { -#if !defined(BCMLXSDMMC) - if (bus->dhd) { - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - } - if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) - si_watchdog(bus->sih, 4); -#endif /* !defined(BCMLXSDMMC) */ - if (bus->dhd) { - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - } - si_detach(bus->sih); - bus->sih = NULL; - if (bus->vars && bus->varsz) - MFREE(osh, bus->vars, bus->varsz); - bus->vars = NULL; - } - - DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -} - -static void -dhdsdio_disconnect(void *ptr) -{ - dhd_bus_t *bus = (dhd_bus_t *)ptr; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - - - if (bus) { - ASSERT(bus->dhd); - dhdsdio_release(bus, bus->dhd->osh); - } - - - - DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -} - -static int -dhdsdio_suspend(void *context) -{ - int ret = 0; - - dhd_bus_t *bus = (dhd_bus_t*)context; - int wait_time = 0; - if (bus->idletime > 0) { - wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms); - } - - ret = dhd_os_check_wakelock(bus->dhd); - if ((!ret) && (bus->dhd->up)) { - if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) { - if (!bus->sleeping) { - return 1; - } - } - } - return ret; -} - -static int -dhdsdio_resume(void *context) -{ -#if defined(OOB_INTR_ONLY) - dhd_bus_t *bus = (dhd_bus_t*)context; - - if (dhd_os_check_if_up(bus->dhd)) - bcmsdh_oob_intr_set(bus->sdh, TRUE); -#endif - return 0; -} - - -/* Register/Unregister functions are called by the main DHD entry - * point (e.g. module insertion) to link with the bus driver, in - * order to look for or await the device. - */ - -static bcmsdh_driver_t dhd_sdio = { - dhdsdio_probe, - dhdsdio_disconnect, - dhdsdio_suspend, - dhdsdio_resume -}; - -int -dhd_bus_register(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - return bcmsdh_register(&dhd_sdio); -} - -void -dhd_bus_unregister(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bcmsdh_unregister(); -} - -#if defined(BCMLXSDMMC) -/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ -int dhd_bus_reg_sdio_notify(void* semaphore) -{ - return bcmsdh_reg_sdio_notify(semaphore); -} - -void dhd_bus_unreg_sdio_notify(void) -{ - bcmsdh_unreg_sdio_notify(); -} -#endif /* defined(BCMLXSDMMC) */ - -#ifdef BCMEMBEDIMAGE -static int -dhdsdio_download_code_array(struct dhd_bus *bus) -{ - int bcmerror = -1; - int offset = 0; - unsigned char *ularray = NULL; - - DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__)); - - /* Download image */ - while ((offset + MEMBLOCK) < sizeof(dlarray)) { - /* check if CR4 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - /* if address is 0, store the reset instruction to be written in 0 */ - - if (offset == 0) { - bus->resetinstr = *(((uint32*)dlarray)); - /* Add start of RAM address to the address given by user */ - offset += bus->dongle_ram_base; - } - } - - bcmerror = dhdsdio_membytes(bus, TRUE, offset, - (uint8 *) (dlarray + offset), MEMBLOCK); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - - if (offset < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, TRUE, offset, - (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); - goto err; - } - } - -#ifdef DHD_DEBUG - /* Upload and compare the downloaded code */ - { - ularray = MALLOC(bus->dhd->osh, bus->ramsize); - /* Upload image to verify downloaded contents. */ - offset = 0; - memset(ularray, 0xaa, bus->ramsize); - while ((offset + MEMBLOCK) < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - - if (offset < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, FALSE, offset, - ularray + offset, sizeof(dlarray) - offset); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); - goto err; - } - } - - if (memcmp(dlarray, ularray, sizeof(dlarray))) { - DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", - __FUNCTION__, dlimagename, dlimagever, dlimagedate)); - goto err; - } else - DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", - __FUNCTION__, dlimagename, dlimagever, dlimagedate)); - - } -#endif /* DHD_DEBUG */ - -err: - if (ularray) - MFREE(bus->dhd->osh, ularray, bus->ramsize); - return bcmerror; -} -#endif /* BCMEMBEDIMAGE */ - -static int -dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) -{ - int bcmerror = -1; - int offset = 0; - int len; - void *image = NULL; - uint8 *memblock = NULL, *memptr; - - DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); - - image = dhd_os_open_image(pfw_path); - if (image == NULL) - goto err; - - memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); - goto err; - } - if ((uint32)(uintptr)memblock % DHD_SDALIGN) - memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); - - /* Download image */ - while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { - if (len < 0) { - DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); - bcmerror = BCME_ERROR; - goto err; - } - /* check if CR4 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - /* if address is 0, store the reset instruction to be written in 0 */ - - if (offset == 0) { - bus->resetinstr = *(((uint32*)memptr)); - /* Add start of RAM address to the address given by user */ - offset += bus->dongle_ram_base; - } - } - - bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - -err: - if (memblock) - MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); - - if (image) - dhd_os_close_image(image); - - return bcmerror; -} - -/* - EXAMPLE: nvram_array - nvram_arry format: - name=value - Use carriage return at the end of each assignment, and an empty string with - carriage return at the end of array. - - For example: - unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"}; - Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx. - - Search "EXAMPLE: nvram_array" to see how the array is activated. -*/ - -void -dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params) -{ - bus->nvram_params = nvram_params; -} - -static int -dhdsdio_download_nvram(struct dhd_bus *bus) -{ - int bcmerror = -1; - uint len; - void * image = NULL; - char * memblock = NULL; - char *bufp; - char *pnv_path; - bool nvram_file_exists; - - pnv_path = bus->nv_path; - - nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); - if (!nvram_file_exists && (bus->nvram_params == NULL)) - return (0); - - if (nvram_file_exists) { - image = dhd_os_open_image(pnv_path); - if (image == NULL) - goto err; - } - - memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, MAX_NVRAMBUF_SIZE)); - goto err; - } - - /* Download variables */ - if (nvram_file_exists) { - len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); - } - else { - len = strlen(bus->nvram_params); - ASSERT(len <= MAX_NVRAMBUF_SIZE); - memcpy(memblock, bus->nvram_params, len); - } - if (len > 0 && len < MAX_NVRAMBUF_SIZE) { - bufp = (char *)memblock; - bufp[len] = 0; - len = process_nvram_vars(bufp, len); - if (len % 4) { - len += 4 - (len % 4); - } - bufp += len; - *bufp++ = 0; - if (len) - bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1); - if (bcmerror) { - DHD_ERROR(("%s: error downloading vars: %d\n", - __FUNCTION__, bcmerror)); - } - } - else { - DHD_ERROR(("%s: error reading nvram file: %d\n", - __FUNCTION__, len)); - bcmerror = BCME_SDIO_ERROR; - } - -err: - if (memblock) - MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); - - if (image) - dhd_os_close_image(image); - - return bcmerror; -} - -static int -_dhdsdio_download_firmware(struct dhd_bus *bus) -{ - int bcmerror = -1; - - bool embed = FALSE; /* download embedded firmware */ - bool dlok = FALSE; /* download firmware succeeded */ - - /* Out immediately if no image to download */ - if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { -#ifdef BCMEMBEDIMAGE - embed = TRUE; -#else - return 0; -#endif - } - - /* Keep arm in reset */ - if (dhdsdio_download_state(bus, TRUE)) { - DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); - goto err; - } - - /* External image takes precedence if specified */ - if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { - if (dhdsdio_download_code_file(bus, bus->fw_path)) { - DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); -#ifdef BCMEMBEDIMAGE - embed = TRUE; -#else - goto err; -#endif - } - else { - embed = FALSE; - dlok = TRUE; - } - } - -#ifdef BCMEMBEDIMAGE - if (embed) { - if (dhdsdio_download_code_array(bus)) { - DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); - goto err; - } - else { - dlok = TRUE; - } - } -#else - BCM_REFERENCE(embed); -#endif - if (!dlok) { - DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); - goto err; - } - - /* EXAMPLE: nvram_array */ - /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ - /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ - - /* External nvram takes precedence if specified */ - if (dhdsdio_download_nvram(bus)) { - DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); - goto err; - } - - /* Take arm out of reset */ - if (dhdsdio_download_state(bus, FALSE)) { - DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); - goto err; - } - - bcmerror = 0; - -err: - return bcmerror; -} - -static int -dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) -{ - int status; - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return BCME_NODEVICE; - } - - status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle); - - return status; -} - -static int -dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry) -{ - int ret; - int i = 0; - int retries = 0; - bcmsdh_info_t *sdh; - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return BCME_NODEVICE; - } - - sdh = bus->sdh; - do { - ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, - pkt, complete, handle); - - bus->f2txdata++; - ASSERT(ret != BCME_PENDING); - - if (ret == BCME_NODEVICE) { - DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); - } else if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n", - __FUNCTION__, ret)); - bus->tx_sderrs++; - bus->f1regdata++; - bus->dhd->tx_errors++; - bcmsdh_abort(sdh, SDIO_FUNC_2); - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - for (i = 0; i < READ_FRM_CNT_RETRIES; i++) { - uint8 hi, lo; - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI, - NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO, - NULL); - bus->f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - } - } while ((ret < 0) && retrydata && ++retries < max_retry); - - return ret; -} - -uint -dhd_bus_chip(struct dhd_bus *bus) -{ - ASSERT(bus->sih != NULL); - return bus->sih->chip; -} - -uint -dhd_bus_chiprev(struct dhd_bus *bus) -{ - ASSERT(bus); - ASSERT(bus->sih != NULL); - return bus->sih->chiprev; -} - -void * -dhd_bus_pub(struct dhd_bus *bus) -{ - return bus->dhd; -} - -void * -dhd_bus_sih(struct dhd_bus *bus) -{ - return (void *)bus->sih; -} - -void * -dhd_bus_txq(struct dhd_bus *bus) -{ - return &bus->txq; -} - -uint -dhd_bus_hdrlen(struct dhd_bus *bus) -{ - return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; -} - -void -dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val) -{ - bus->dotxinrx = val; -} - -int -dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) -{ - int bcmerror = 0; - dhd_bus_t *bus; - - bus = dhdp->bus; - - if (flag == TRUE) { - if (!bus->dhd->dongle_reset) { - dhd_os_sdlock(dhdp); - dhd_os_wd_timer(dhdp, 0); -#if !defined(IGNORE_ETH0_DOWN) - /* Force flow control as protection when stop come before ifconfig_down */ - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); -#endif /* !defined(IGNORE_ETH0_DOWN) */ - /* Expect app to have torn down any connection before calling */ - /* Stop the bus, disable F2 */ - dhd_bus_stop(bus, FALSE); - -#if defined(OOB_INTR_ONLY) - /* Clean up any pending IRQ */ - dhd_enable_oob_intr(bus, FALSE); - bcmsdh_oob_intr_set(bus->sdh, FALSE); - bcmsdh_oob_intr_unregister(bus->sdh); -#endif - - /* Clean tx/rx buffer pointers, detach from the dongle */ - dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); - - bus->dhd->dongle_reset = TRUE; - bus->dhd->up = FALSE; - dhd_txglom_enable(dhdp, FALSE); - dhd_os_sdunlock(dhdp); - - DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); - /* App can now remove power from device */ - } else - bcmerror = BCME_SDIO_ERROR; - } else { - /* App must have restored power to device before calling */ - - DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) { - /* Turn on WLAN */ - dhd_os_sdlock(dhdp); - /* Reset SD client */ - bcmsdh_reset(bus->sdh); - - /* Attempt to re-attach & download */ - if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh, - (uint32 *)SI_ENUM_BASE, - bus->cl_devid)) { - /* Attempt to download binary to the dongle */ - if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) && - dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) { - - /* Re-init bus, enable F2 transfer */ - bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); - if (bcmerror == BCME_OK) { -#if defined(OOB_INTR_ONLY) - dhd_enable_oob_intr(bus, TRUE); - bcmsdh_oob_intr_register(bus->sdh, - dhdsdio_isr, bus); - bcmsdh_oob_intr_set(bus->sdh, TRUE); -#endif - - bus->dhd->dongle_reset = FALSE; - bus->dhd->up = TRUE; - -#if !defined(IGNORE_ETH0_DOWN) - /* Restore flow control */ - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); -#endif - dhd_os_wd_timer(dhdp, dhd_watchdog_ms); - - DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); - } else { - dhd_bus_stop(bus, FALSE); - dhdsdio_release_dongle(bus, bus->dhd->osh, - TRUE, FALSE); - } - } else - bcmerror = BCME_SDIO_ERROR; - } else - bcmerror = BCME_SDIO_ERROR; - - dhd_os_sdunlock(dhdp); - } else { - bcmerror = BCME_SDIO_ERROR; - DHD_INFO(("%s called when dongle is not in reset\n", - __FUNCTION__)); - DHD_INFO(("Will call dhd_bus_start instead\n")); - dhd_bus_resume(dhdp, 1); - if ((bcmerror = dhd_bus_start(dhdp)) != 0) - DHD_ERROR(("%s: dhd_bus_start fail with %d\n", - __FUNCTION__, bcmerror)); - } - } - return bcmerror; -} - -int dhd_bus_suspend(dhd_pub_t *dhdpub) -{ - return bcmsdh_stop(dhdpub->bus->sdh); -} - -int dhd_bus_resume(dhd_pub_t *dhdpub, int stage) -{ - return bcmsdh_start(dhdpub->bus->sdh, stage); -} - -/* Get Chip ID version */ -uint dhd_bus_chip_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - - return bus->sih->chip; -} - -/* Get Chip Rev ID version */ -uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - - return bus->sih->chiprev; -} - -/* Get Chip Pkg ID version */ -uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - - return bus->sih->chippkg; -} - -int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num) -{ - *bus_type = bus->bus; - *bus_num = bus->bus_num; - *slot_num = bus->slot_num; - return 0; -} - -int -dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) -{ - dhd_bus_t *bus; - - bus = dhdp->bus; - return dhdsdio_membytes(bus, set, address, data, size); -} -#if defined(SUPPORT_MULTIPLE_REVISION) -/* Just print chip revision for BCM4330 */ -static int -concate_revision_bcm4330(dhd_bus_t *bus) -{ - uint chipver; - chipver = bus->sih->chiprev; - - if (chipver == 3) - DHD_ERROR(("---- CHIP bcm4330 B1 ----\n")); - else if (chipver == 4) - DHD_ERROR(("---- CHIP bcm4330 B2 ----\n")); - else - DHD_ERROR(("----- Invalid chip version -----\n")); - return 0; -} - -static int -concate_revision_bcm4334(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ -#define REV_ID_ADDR 0x1E008F90 -#define BCM4334_B1_UNIQUE 0x30312E36 - - uint chipver; - uint32 unique_id; - uint8 data[4]; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[10] = "_4334"; -#else - char chipver_tag[4] = ""; -#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ - - DHD_TRACE(("%s: BCM4334 Multiple Revision Check\n", __FUNCTION__)); - if (bus->sih->chip != BCM4334_CHIP_ID) { - DHD_ERROR(("%s:Chip is not BCM4334\n", __FUNCTION__)); - return -1; - } - chipver = bus->sih->chiprev; - if (chipver == 0x2) { - dhdsdio_membytes(bus, FALSE, REV_ID_ADDR, data, 4); - unique_id = load32_ua(data); - if (unique_id == BCM4334_B1_UNIQUE) - chipver = 0x01; - } - DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); - if (chipver == 1) { - DHD_ERROR(("----- CHIP bcm4334_B0 -----\n")); - strcat(chipver_tag, "_b0"); - } else if (chipver == 2) { - DHD_ERROR(("----- CHIP bcm4334_B1 -----\n")); - strcat(chipver_tag, "_b1"); - } else if (chipver == 3) { - DHD_ERROR(("----- CHIP bcm4334_B2 -----\n")); - strcat(chipver_tag, "_b2"); - } - else { - DHD_ERROR(("----- Invalid chip version -----\n")); - return -1; - } - - strcat(fw_path, chipver_tag); -#if defined(SUPPORT_MULTIPLE_CHIPS) - strcat(nv_path, chipver_tag); -#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ - -#undef REV_ID_ADDR -#undef BCM4334_B1_UNIQUE - return 0; -} - -static int -concate_revision_bcm4335(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - - uint chipver; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[10] = "_4335"; -#else - char chipver_tag[4] = {0, }; -#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ - - DHD_TRACE(("%s: BCM4335 Multiple Revision Check\n", __FUNCTION__)); - if (bus->sih->chip != BCM4335_CHIP_ID) { - DHD_ERROR(("%s:Chip is not BCM4335\n", __FUNCTION__)); - return -1; - } - chipver = bus->sih->chiprev; - DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); - if (chipver == 0x0) { - DHD_ERROR(("----- CHIP bcm4335_A0 -----\n")); - strcat(chipver_tag, "_a0"); - } else if (chipver == 0x1) { - DHD_ERROR(("----- CHIP bcm4335_B0 -----\n")); -#if defined(SUPPORT_MULTIPLE_CHIPS) - strcat(chipver_tag, "_b0"); -#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ - } - - strcat(fw_path, chipver_tag); - strcat(nv_path, chipver_tag); - return 0; -} - -static int -concate_revision_bcm4339(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - - uint chipver; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[10] = "_4339"; -#else - char chipver_tag[4] = {0, }; -#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ - - DHD_TRACE(("%s: BCM4339 Multiple Revision Check\n", __FUNCTION__)); - if (bus->sih->chip != BCM4339_CHIP_ID) { - DHD_ERROR(("%s:Chip is not BCM4339\n", __FUNCTION__)); - return -1; - } - chipver = bus->sih->chiprev; - DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); - if (chipver == 0x1) { - DHD_ERROR(("----- CHIP bcm4339_A0 -----\n")); - strcat(chipver_tag, "_a0"); - } else { - DHD_ERROR(("----- CHIP bcm4339 unknown revision %d -----\n", - chipver)); - } - - strcat(fw_path, chipver_tag); - strcat(nv_path, chipver_tag); - return 0; -} - -static int -concate_revision_bcm43349(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - uint chipver; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[10] = "_43349"; -#else - char chipver_tag[4] = {0, }; -#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ - - DHD_TRACE(("%s: BCM43349 Multiple Revision Check\n", __FUNCTION__)); - if (bus->sih->chip != BCM43349_CHIP_ID) { - DHD_ERROR(("%s:Chip is not BCM43349\n", __FUNCTION__)); - return -1; - } - chipver = bus->sih->chiprev; - DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); - if (chipver == 0x1) { - DHD_ERROR(("----- CHIP bcm43349_A0 -----\n")); - strcat(chipver_tag, "_a0"); - } else { - DHD_ERROR(("----- CHIP bcm43349 unknown revision %d -----\n", chipver)); - } - - strcat(fw_path, chipver_tag); - strcat(nv_path, chipver_tag); - return 0; -} - -static int concate_revision_bcm43241(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - uint32 chip_id, chip_ver; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[10] = "_43241"; -#else - char chipver_tag[4] = {0, }; -#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ - - DHD_TRACE(("%s: BCM43241 Multiple Revision Check\n", __FUNCTION__)); - - chip_id = bus->sih->chip; - chip_ver = bus->sih->chiprev; - - if (chip_ver == 2) { - DHD_ERROR(("----- CHIP bcm43241_B0 -----\n")); - strcat(chipver_tag, "_b0"); - } else if (chip_ver == 5) { - DHD_ERROR(("----- CHIP bcm43241_B4 -----\n")); - strcat(chipver_tag, "_b4"); - } else { - DHD_ERROR(("----- Invalid chip version -----\n")); - return -1; - } - - strcat(fw_path, chipver_tag); - strcat(nv_path, chipver_tag); - return 0; -} - -static int concate_revision_bcm4350(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - uint32 chip_id, chip_ver; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[10] = {0, }; -#else - char chipver_tag[4] = {0, }; -#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ - chip_id = bus->sih->chip; - chip_ver = bus->sih->chiprev; - -#if defined(SUPPORT_MULTIPLE_CHIPS) - if (chip_ver == 3) - strcat(chipver_tag, "_4354"); - else - strcat(chipver_tag, "_4350"); -#endif - - if (chip_ver == 3) { - DHD_ERROR(("----- CHIP 4354 A0 -----\n")); - strcat(chipver_tag, "_a0"); - } else { - DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); - } - - strcat(fw_path, chipver_tag); - strcat(nv_path, chipver_tag); - return 0; -} - -static int concate_revision_bcm4354(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - uint32 chip_id, chip_ver; -#if defined(SUPPORT_MULTIPLE_CHIPS) - char chipver_tag[10] = "_4354"; -#else - char chipver_tag[4] = {0, }; -#endif /* SUPPORT_MULTIPLE_CHIPS */ - - chip_id = bus->sih->chip; - chip_ver = bus->sih->chiprev; - if (chip_ver == 1) { - DHD_ERROR(("----- CHIP 4354 A1 -----\n")); - strcat(chipver_tag, "_a1"); - } else { - DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); - } - - strcat(fw_path, chipver_tag); - strcat(nv_path, chipver_tag); - - return 0; -} - -int -concate_revision(dhd_bus_t *bus, char *fw_path, char *nv_path) -{ - int res = 0; - - if (!bus || !bus->sih) { - DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__)); - return -1; - } - - - switch (bus->sih->chip) { - case BCM4330_CHIP_ID: - res = concate_revision_bcm4330(bus); - break; - case BCM4334_CHIP_ID: - res = concate_revision_bcm4334(bus, fw_path, nv_path); - break; - case BCM4335_CHIP_ID: - res = concate_revision_bcm4335(bus, fw_path, nv_path); - - break; - case BCM4339_CHIP_ID: - res = concate_revision_bcm4339(bus, fw_path, nv_path); - break; - case BCM43349_CHIP_ID: - res = concate_revision_bcm43349(bus, fw_path, nv_path); - break; - case BCM4324_CHIP_ID: - res = concate_revision_bcm43241(bus, fw_path, nv_path); - break; - case BCM4350_CHIP_ID: - res = concate_revision_bcm4350(bus, fw_path, nv_path); - break; - case BCM4354_CHIP_ID: - res = concate_revision_bcm4354(bus, fw_path, nv_path); - break; - - default: - DHD_ERROR(("REVISION SPECIFIC feature is not required\n")); - return res; - } - - if (res == 0) { - } - return res; -} -#endif /* SUPPORT_MULTIPLE_REVISION */ - - -void -dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path) -{ - bus->fw_path = pfw_path; - bus->nv_path = pnv_path; -} - -int -dhd_enableOOB(dhd_pub_t *dhd, bool sleep) -{ - dhd_bus_t *bus = dhd->bus; - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - - if (sleep) { - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - /* Tell device to start using OOB wakeup */ - W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); - if (retries > retry_limit) { - DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); - return BCME_BUSY; - } - /* Turn off our contribution to the HT clock request */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } else { - /* Make sure the controller has the bus up */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Send misc interrupt to indicate OOB not needed */ - W_SDREG(0, ®s->tosbmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); - - /* Make sure we have SD bus access */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - return BCME_OK; -} - -void -dhd_bus_pktq_flush(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - bool wlfc_enabled = FALSE; - -#ifdef PROP_TXSTATUS - wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED); -#endif - if (!wlfc_enabled) { -#ifdef DHDTCPACK_SUPPRESS - /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, - * when there is a newly coming packet from network stack. - */ - dhd_tcpack_info_tbl_clean(bus->dhd); -#endif /* DHDTCPACK_SUPPRESS */ - /* Clear the data packet queues */ - pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0); - } -} - -#ifdef BCMSDIO -int -dhd_sr_config(dhd_pub_t *dhd, bool on) -{ - dhd_bus_t *bus = dhd->bus; - - if (!bus->_srenab) - return -1; - - return dhdsdio_clk_devsleep_iovar(bus, on); -} - -uint16 -dhd_get_chipid(dhd_pub_t *dhd) -{ - dhd_bus_t *bus = dhd->bus; - - if (bus && bus->sih) - return (uint16)bus->sih->chip; - else - return 0; -} -#endif /* BCMSDIO */ - -#ifdef DEBUGGER -uint32 dhd_sdio_reg_read(void *h, uint32 addr) -{ - uint32 rval; - struct dhd_bus *bus = (struct dhd_bus *) h; - - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - rval = bcmsdh_reg_read(bus->sdh, addr, 4); - - dhd_os_sdunlock(bus->dhd); - - return rval; -} - -void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val) -{ - struct dhd_bus *bus = (struct dhd_bus *) h; - - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - bcmsdh_reg_write(bus->sdh, addr, 4, val); - - dhd_os_sdunlock(bus->dhd); -} -#endif /* DEBUGGER */ diff --git a/drivers/net/wireless/bcmdhd/dhd_somc_custom.c b/drivers/net/wireless/bcmdhd/dhd_somc_custom.c deleted file mode 100644 index de106110b05d..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_somc_custom.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Author: Daisuke Niwa daisuke.x.niwa@sonymobile.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include - -/* miscTA items */ -typedef enum somc_nv_item { - SOMC_TA_TXPWR_2_4G = 0, - SOMC_TA_TXPWR_5G_LOW, - SOMC_TA_TXPWR_5G_MID, - SOMC_TA_TXPWR_5G_HIGH, - SOMC_TA_TXPWR_CO1_2_4G, - SOMC_TA_TXPWR_CO1_5G_LOW, - SOMC_TA_TXPWR_CO1_5G_MID, - SOMC_TA_TXPWR_CO1_5G_HIGH, -} somc_nv_item_t; - -/* Paths to miscTA import files */ -static const char *somc_ta_paths[] = { - "/data/etc/wlan_txpower_2_4g", - "/data/etc/wlan_txpower_5g_low", - "/data/etc/wlan_txpower_5g_mid", - "/data/etc/wlan_txpower_5g_high", - "/data/etc/wlan_txpower_co1_2_4g", - "/data/etc/wlan_txpower_co1_5g_low", - "/data/etc/wlan_txpower_co1_5g_mid", - "/data/etc/wlan_txpower_co1_5g_high", -}; - -#define SOMC_NV_IS_5G(i) (i % 4 == 0 ? 0 : 1) -#define SOMC_NV_GET_CHAIN(i) (i < SOMC_TA_TXPWR_CO1_2_4G ? 0 : 1) - -#define SOMC_MAX_TABUF_SIZE 128 -#define SOMC_TXPWR_BUF_SIZE 7 - -/* Keys used in calibration file for tx power */ -#define SOMC_CKEY_TXPWR_2_4G_11B "cckbw202gpo" -#define SOMC_CKEY_TXPWR_2_4G_11A "dot11agofdmhrbw202gpo" -#define SOMC_CKEY_TXPWR_2_4G_11A_2 "ofdmlrbw202gpo" -#define SOMC_CKEY_TXPWR_2_4G_11N "mcsbw202gpo" -#define SOMC_CKEY_TXPWR_5G_LOW_11A "mcsbw205glpo" -#define SOMC_CKEY_TXPWR_5G_LOW_11N "mcsbw405glpo" -#define SOMC_CKEY_TXPWR_5G_LOW_11AC "mcsbw805glpo" -#define SOMC_CKEY_TXPWR_5G_MID_11A "mcsbw205gmpo" -#define SOMC_CKEY_TXPWR_5G_MID_11N "mcsbw405gmpo" -#define SOMC_CKEY_TXPWR_5G_MID_11AC "mcsbw805gmpo" -#define SOMC_CKEY_TXPWR_5G_HIGH_11A "mcsbw205ghpo" -#define SOMC_CKEY_TXPWR_5G_HIGH_11N "mcsbw405ghpo" -#define SOMC_CKEY_TXPWR_5G_HIGH_11AC "mcsbw805ghpo" - -#define SOMC_TXPWR_MAX 127 -#define SOMC_TXPWR_5G 0x20 - -typedef struct { - char *key; /* Key for tx power (see the definitions above) */ - int len; /* Length of a unit of PPR (not incl. "0x") */ - int offset; /* Offset to PPR */ -} somc_ppr_item_t; - -/* List of ppr item handled by somc_txpower_calibrate() */ -static const somc_ppr_item_t somc_ppr_items[] = { - { SOMC_CKEY_TXPWR_2_4G_11B, 4, 0}, - { SOMC_CKEY_TXPWR_2_4G_11A, 4, 0}, - { SOMC_CKEY_TXPWR_2_4G_11A_2, 4, 2}, - { SOMC_CKEY_TXPWR_2_4G_11N, 8, 0}, - { SOMC_CKEY_TXPWR_5G_LOW_11A, 8, 0}, - { SOMC_CKEY_TXPWR_5G_LOW_11N, 8, 0}, - { SOMC_CKEY_TXPWR_5G_LOW_11AC, 8, 0}, - { SOMC_CKEY_TXPWR_5G_MID_11A, 8, 0}, - { SOMC_CKEY_TXPWR_5G_MID_11N, 8, 0}, - { SOMC_CKEY_TXPWR_5G_MID_11AC, 8, 0}, - { SOMC_CKEY_TXPWR_5G_HIGH_11A, 8, 0}, - { SOMC_CKEY_TXPWR_5G_HIGH_11N, 8, 0}, - { SOMC_CKEY_TXPWR_5G_HIGH_11AC, 8, 0}, -}; - -/* {2.4GHz: {chain0, chain1}, 5GHz: {chain0, chain1}} */ -static int somc_txpower_min_deltas[2][2] = {{0, 0},{0, 0}}; - -static int -somc_txpower_get_min_delta(int band5g, int chain) -{ - int min_delta = somc_txpower_min_deltas[band5g][chain]; - return (min_delta == INT_MAX) ? 0 : min_delta; -} - -static void -somc_txpower_update_min_delta(const int *delta, int num, int band5g, int chain) -{ - int *min_delta = &somc_txpower_min_deltas[band5g][chain]; - while (num > 0) { - num--; - if (band5g && (num == 0)) /* ignore 11b delta value for 5GHz */ - continue; - if (!band5g && (num > 2)) /* ignore 11n-40/11ac delta values for 2.4GHz */ - continue; - *min_delta = MIN(*min_delta, delta[num]); - } -} - -static int -somc_read_file(const char *path, unsigned char *buf, int buf_len) -{ - int ret = -1; - int len; - struct file *fp = NULL; - - if (!path || !buf) - goto err; - - fp = filp_open(path, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: file open error: %s\n", __FUNCTION__, path)); - if (PTR_ERR(fp) == -ENOENT) { - DHD_ERROR(("%s: file does not exist: %s\n", __FUNCTION__, path)); - ret = -2; - } - fp = NULL; - goto err; - } - - len = dhd_os_get_image_block(buf, buf_len, (void *)fp); - if (len <= 0 || buf_len <= len) { - DHD_ERROR(("%s: file read error: %s\n", __FUNCTION__, path)); - goto err; - } - buf[len] = '\0'; - - ret = 0; -err: - if (fp) - filp_close(fp, NULL); - return ret; -} - -static int -somc_read_ta(somc_nv_item_t item, unsigned char *buf, int buf_len) -{ - char ta_buf[SOMC_MAX_TABUF_SIZE] = {0}; - int *d, ret; - - ret = somc_read_file(somc_ta_paths[item], ta_buf, sizeof(ta_buf)); - if (ret != 0) - return ret; - - switch (item) { - case SOMC_TA_TXPWR_2_4G: - case SOMC_TA_TXPWR_5G_LOW: - case SOMC_TA_TXPWR_5G_MID: - case SOMC_TA_TXPWR_5G_HIGH: - case SOMC_TA_TXPWR_CO1_2_4G: - case SOMC_TA_TXPWR_CO1_5G_LOW: - case SOMC_TA_TXPWR_CO1_5G_MID: - case SOMC_TA_TXPWR_CO1_5G_HIGH: - if (buf_len < SOMC_TXPWR_BUF_SIZE) - return -1; - d = (int *)buf; - if (sscanf(ta_buf, "%d:%d:%d:%d:%d:%d:%d", - &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6]) != 7) { - DHD_ERROR(("%s: tx power parse error: %s\n", - __FUNCTION__, somc_ta_paths[item])); - return -1; - } - - printk("%s: tx power in miscTA(%s),\n 11b:11a:11n(20MHz):11n(40MHz):" - "11ac(20MHz):11ac(40MHz):11ac(80MHz)=,\n %d:%d:%d:%d:%d:%d:%d\n", - __FUNCTION__, somc_ta_paths[item], - d[0], d[1], d[2], d[3], d[4], d[5], d[6]); - break; - default: - return -1; - } - - return 0; -} - -static int -somc_txpower_apply_delta(const unsigned char *key, int len, int offset, - int delta, unsigned char *nvram, int nvram_len) -{ - unsigned char *end = nvram + nvram_len - 1; - unsigned char *k, *v, *t; - unsigned int power_h, power_l; - int i, j, v_len = len * 2 + 5; /* e.g. "0x5555,0x1111" (= 4 * 2 + 5) */ - const unsigned char *fmt; - - if (!key || !nvram || offset >= len || (len != 4 && len != 8)) - return -1; - - fmt = (len == 4) ? "0x%04x,0x%04x" : "0x%08x,0x%08x"; - - /* look up key in nvram */ - if ((k = strnstr(nvram, key, nvram_len)) == NULL) { - DHD_ERROR(("%s: key not found: %s\n", __FUNCTION__, key)); - return -1; - } - - /* extract value */ - v = k + strlen(key); - if (v > end || *v != '=') { - DHD_ERROR(("%s: value parse error: %s\n", __FUNCTION__, key)); - return -1; - } - v += 1; - - if (v > end || (t = strnchr(v, end - v + 1, '\n')) == NULL || - t - v != v_len) { - DHD_ERROR(("%s: value parse error: %s\n", __FUNCTION__, key)); - return -1; - } - - /* extract each values */ - if (sscanf(v, fmt, &power_l, &power_h) != 2) { - DHD_ERROR(("%s: power offset values parse error: %s\n", __FUNCTION__, key)); - return -1; - } - - /* convert unit since nvram uses 1/2dB step, miscTA uses 1/100dB step */ - if (delta < 0 && delta % 50 != 0) - delta = delta / 50 - 1; - else - delta = delta / 50; - - for (i = 0, j = len - offset; i < j; i++) { - int val, sft = i * 4; - /* combine low and high 4 bits into a value(8bit) */ - val = ((power_l >> sft) & 0xf) | (((power_h >> sft) & 0xf) << 4); - /* apply delta */ - val -= delta; - val = (val > 0xff) ? 0xff : (val < 0x00) ? 0x00 : val; - /* separate power to low and high again */ - power_l &= ~(0xf << sft); - power_l |= (val & 0x0f) << sft; - power_h &= ~(0xf << sft); - power_h |= ((val & 0xf0) >> 4) << sft; - } - - snprintf(v, v_len + 1, fmt, power_l, power_h); - v[v_len] = '\n'; - - return 0; -} - -int somc_txpower_calibrate(char *nvram, int nvram_len) -{ - int v[4][SOMC_TXPWR_BUF_SIZE]; /* tx power offset(s) */ - int i, j, ta_num, delta[sizeof(somc_ppr_items) / sizeof(somc_ppr_items[0])]; - -#ifdef SOMC_MIMO - ta_num = SOMC_TA_TXPWR_CO1_5G_HIGH + 1; -#else - ta_num = SOMC_TA_TXPWR_5G_HIGH + 1; -#endif - /* initialize minimum delta (used for tx power trim) */ - for (i = 0; i < 4; i++) { - for (j = 0; j < SOMC_TXPWR_BUF_SIZE; j++) { - v[i][j] = INT_MAX; - } - } - - /* initialize minimum delta (used for tx power back-off) */ - somc_txpower_min_deltas[0][0 /* chain0 */] = INT_MAX; - somc_txpower_min_deltas[1][0 /* chain0 */] = INT_MAX; - somc_txpower_min_deltas[0][1 /* chain1 */] = INT_MAX; - somc_txpower_min_deltas[1][1 /* chain1 */] = INT_MAX; - - for (i = 0; i < ta_num; i++) { - int ret; - int tv[SOMC_TXPWR_BUF_SIZE] = {0}; - - /* no need to update delta if miscTA doesn't exist(ret == 2) */ - ret = somc_read_ta(i, (char *)tv, sizeof(tv)); - if (ret == 0) { - somc_txpower_update_min_delta(tv, SOMC_TXPWR_BUF_SIZE, - SOMC_NV_IS_5G(i), SOMC_NV_GET_CHAIN(i)); - /* select minimum delta between chain0 and chain1 */ - for (j = 0; j < SOMC_TXPWR_BUF_SIZE; j++) - v[i % 4][j] = MIN(v[i % 4][j], tv[j]); - } else if (ret != -2) - return BCME_OK; - } - - /* construct delta data structure for 2.4GHz - * TA value "v[0]" consists of the following format. - * {11b}:{11a}:{11n-20} - */ - delta[0] = v[0][0]; /* {11b} */ - delta[1] = v[0][1]; /* {11a} */ - delta[2] = v[0][1]; /* {11a} */ - delta[3] = v[0][2]; /* {11n-20} */ - - /* construct delta data structure for 5GHz(low/mid/high) - * TA values "v[1],v[2],v[3]" consist of the following format. - * {11b}:{11a}:{11n-20}:{11n-40}:{11ac-20}:{11ac-40}:{11ac-80} - */ - for (i = 1; i < 4; i++) { - /* minimum delta between {11a}, {11n-20}, {11ac-20} for 20MHz */ - delta[i * 3 + 1] = MIN(MIN(v[i][1], v[i][2]), v[i][4]); - /* minimum delta between {11n-40}, {11ac-40} for 40MHz */ - delta[i * 3 + 2] = MIN(v[i][3], v[i][5]); - /* {11ac-80} for 80MHz */ - delta[i * 3 + 3] = v[i][6]; - } - - /* Apply delta (tx power trim) */ - for (i = 0; i < sizeof(somc_ppr_items) / sizeof(somc_ppr_items[0]); i++) { - if (delta[i] == INT_MAX) - continue; - if (somc_txpower_apply_delta(somc_ppr_items[i].key, somc_ppr_items[i].len, - somc_ppr_items[i].offset, delta[i], nvram, nvram_len) != 0) - return BCME_ERROR; - } - - return BCME_OK; -} - -int somc_update_qtxpower(char *buf, char band, int chain) -{ - int in_qdbm, power; - int delta = somc_txpower_get_min_delta((band & SOMC_TXPWR_5G) != 0, chain); - - in_qdbm = *buf; - - if (in_qdbm < 0 || SOMC_TXPWR_MAX < in_qdbm) - return -1; - - /* convert unit for calculation since 'delta' uses 1/100dB step */ - power = in_qdbm + delta / (100 / 4); - if (power > 0) { - power = (power > SOMC_TXPWR_MAX) ? SOMC_TXPWR_MAX : power; - } else { - power = 0; - } - *buf = (char)power; - - printk("%s: Set max tx power: %d qdBm (delta=%d)\n", - __FUNCTION__, power, delta); - - return 0; -} diff --git a/drivers/net/wireless/bcmdhd/dhd_somc_custom.h b/drivers/net/wireless/bcmdhd/dhd_somc_custom.h deleted file mode 100644 index 4c83517241a2..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_somc_custom.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Author: Daisuke Niwa daisuke.x.niwa@sonymobile.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - */ - -#ifndef __DHD_SOMC_CUSTOM_H__ -#define __DHD_SOMC_CUSTOM_H__ - -extern int somc_txpower_calibrate(char *nvram, int nvram_len); -extern int somc_update_qtxpower(char *buf, char band, int chain); - -#endif /* __DHD_SOMC_CUSTOM_H__ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.c b/drivers/net/wireless/bcmdhd/dhd_wlfc.c deleted file mode 100644 index e4cf02946a56..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_wlfc.c +++ /dev/null @@ -1,4104 +0,0 @@ -/* - * DHD PROP_TXSTATUS Module. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_wlfc.c 507166 2014-10-08 19:50:42Z $ - * - */ - -#include -#include - -#include -#include - -#include -#include - -#include -#include - -#ifdef PROP_TXSTATUS -#include -#include -#endif -#include - - -/* - * wlfc naming and lock rules: - * - * 1. Private functions name like _dhd_wlfc_XXX, declared as static and avoid wlfc lock operation. - * 2. Public functions name like dhd_wlfc_XXX, use wlfc lock if needed. - * 3. Non-Proptxstatus module call public functions only and avoid wlfc lock operation. - * - */ - - -#ifdef PROP_TXSTATUS - -#define DHD_WLFC_QMON_COMPLETE(entry) - -#define LIMIT_BORROW - - -static uint16 -_dhd_wlfc_adjusted_seq(void* p, uint8 current_seq) -{ - uint16 seq; - - if (!p) { - return 0xffff; - } - - seq = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - if (seq < current_seq) { - /* wrap around */ - seq += 256; - } - - return seq; -} - -static void -_dhd_wlfc_prec_enque(struct pktq *pq, int prec, void* p, bool qHead, - uint8 current_seq, bool reOrder) -{ - struct pktq_prec *q; - uint16 seq, seq2; - void *p2, *p2_prev; - - if (!p) - return; - - - ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ - - ASSERT(!pktq_full(pq)); - ASSERT(!pktq_pfull(pq, prec)); - - q = &pq->q[prec]; - - PKTSETLINK(p, NULL); - if (q->head == NULL) { - /* empty queue */ - q->head = p; - q->tail = p; - } else { - if (reOrder && (prec & 1)) { - seq = _dhd_wlfc_adjusted_seq(p, current_seq); - p2 = qHead ? q->head : q->tail; - seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); - - if ((qHead &&((seq+1) > seq2)) || (!qHead && ((seq2+1) > seq))) { - /* need reorder */ - p2 = q->head; - p2_prev = NULL; - seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); - - while (seq > seq2) { - p2_prev = p2; - p2 = PKTLINK(p2); - if (!p2) { - break; - } - seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); - } - - if (p2_prev == NULL) { - /* insert head */ - PKTSETLINK(p, q->head); - q->head = p; - } else if (p2 == NULL) { - /* insert tail */ - PKTSETLINK(p2_prev, p); - q->tail = p; - } else { - /* insert after p2_prev */ - PKTSETLINK(p, PKTLINK(p2_prev)); - PKTSETLINK(p2_prev, p); - } - goto exit; - } - } - - if (qHead) { - PKTSETLINK(p, q->head); - q->head = p; - } else { - PKTSETLINK(q->tail, p); - q->tail = p; - } - } - -exit: - - q->len++; - pq->len++; - - if (pq->hi_prec < prec) - pq->hi_prec = (uint8)prec; -} - -/* Create a place to store all packet pointers submitted to the firmware until - a status comes back, suppress or otherwise. - - hang-er: noun, a contrivance on which things are hung, as a hook. -*/ -static void* -_dhd_wlfc_hanger_create(osl_t *osh, int max_items) -{ - int i; - wlfc_hanger_t* hanger; - - /* allow only up to a specific size for now */ - ASSERT(max_items == WLFC_HANGER_MAXITEMS); - - if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) - return NULL; - - memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); - hanger->max_items = max_items; - - for (i = 0; i < hanger->max_items; i++) { - hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - } - return hanger; -} - -static int -_dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) -{ - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h) { - MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); - return BCME_OK; - } - return BCME_BADARG; -} - -static uint16 -_dhd_wlfc_hanger_get_free_slot(void* hanger) -{ - uint32 i; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h) { - i = h->slot_pos + 1; - if (i == h->max_items) { - i = 0; - } - while (i != h->slot_pos) { - if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { - h->slot_pos = i; - return (uint16)i; - } - i++; - if (i == h->max_items) - i = 0; - } - h->failed_slotfind++; - } - return WLFC_HANGER_MAXITEMS; -} - -static int -_dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - *gen = 0xff; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - - if (h) { - if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || - (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { - *gen = h->items[slot_id].gen; - } - else { - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -_dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { - if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { - h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; - h->items[slot_id].pkt = pkt; - h->items[slot_id].pkt_state = 0; - h->items[slot_id].pkt_txstatus = 0; - h->pushed++; - } - else { - h->failed_to_push++; - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -_dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, bool remove_from_hanger) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - - if (h) { - if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { - *pktout = h->items[slot_id].pkt; - if (remove_from_hanger) { - h->items[slot_id].state = - WLFC_HANGER_ITEM_STATE_FREE; - h->items[slot_id].pkt = NULL; - h->items[slot_id].gen = 0xff; - h->items[slot_id].identifier = 0; - h->popped++; - } - } - else { - h->failed_to_pop++; - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -_dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - if (h) { - h->items[slot_id].gen = gen; - if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { - h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; - } - else - rc = BCME_BADARG; - } - else - rc = BCME_BADARG; - - return rc; -} - -/* remove reference of specific packet in hanger */ -static bool -_dhd_wlfc_hanger_remove_reference(wlfc_hanger_t* h, void* pkt) -{ - int i; - - if (!h || !pkt) { - return FALSE; - } - - for (i = 0; i < h->max_items; i++) { - if (pkt == h->items[i].pkt) { - if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) || - (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - h->items[i].pkt = NULL; - h->items[i].gen = 0xff; - h->items[i].identifier = 0; - } - return TRUE; - } - } - - return FALSE; -} - - -static int -_dhd_wlfc_enque_afq(athost_wl_status_info_t* ctx, void *p) -{ - wlfc_mac_descriptor_t* entry; - uint16 entry_idx = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - uint8 prec = DHD_PKTTAG_FIFO(PKTTAG(p)); - - if (entry_idx < WLFC_MAC_DESC_TABLE_SIZE) - entry = &ctx->destination_entries.nodes[entry_idx]; - else if (entry_idx < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) - entry = &ctx->destination_entries.interfaces[entry_idx - WLFC_MAC_DESC_TABLE_SIZE]; - else - entry = &ctx->destination_entries.other; - - pktq_penq(&entry->afq, prec, p); - - return BCME_OK; -} - -static int -_dhd_wlfc_deque_afq(athost_wl_status_info_t* ctx, uint16 hslot, uint8 hcnt, uint8 prec, - void **pktout) -{ - wlfc_mac_descriptor_t *entry; - struct pktq *pq; - struct pktq_prec *q; - void *p, *b; - - if (!ctx) { - DHD_ERROR(("%s: ctx(%p), pktout(%p)\n", __FUNCTION__, ctx, pktout)); - return BCME_BADARG; - } - - if (pktout) { - *pktout = NULL; - } - - ASSERT(hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM + 1)); - - if (hslot < WLFC_MAC_DESC_TABLE_SIZE) - entry = &ctx->destination_entries.nodes[hslot]; - else if (hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) - entry = &ctx->destination_entries.interfaces[hslot - WLFC_MAC_DESC_TABLE_SIZE]; - else - entry = &ctx->destination_entries.other; - - pq = &entry->afq; - - ASSERT(prec < pq->num_prec); - - q = &pq->q[prec]; - - b = NULL; - p = q->head; - - while (p && (hcnt != WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))))) - { - b = p; - p = PKTLINK(p); - } - - if (p == NULL) { - /* none is matched */ - if (b) { - DHD_ERROR(("%s: can't find matching seq(%d)\n", __FUNCTION__, hcnt)); - } else { - DHD_ERROR(("%s: queue is empty\n", __FUNCTION__)); - } - - return BCME_ERROR; - } - - if (!b) { - /* head packet is matched */ - if ((q->head = PKTLINK(p)) == NULL) { - q->tail = NULL; - } - } else { - /* middle packet is matched */ - DHD_INFO(("%s: out of order, seq(%d), head_seq(%d)\n", __FUNCTION__, hcnt, - WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(q->head))))); - ctx->stats.ooo_pkts[prec]++; - PKTSETLINK(b, PKTLINK(p)); - if (PKTLINK(p) == NULL) { - q->tail = b; - } - } - - q->len--; - pq->len--; - - PKTSETLINK(p, NULL); - - if (pktout) { - *pktout = p; - } - - return BCME_OK; -} - -static int -_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void** packet, bool tim_signal, - uint8 tim_bmp, uint8 mac_handle, uint32 htodtag, uint16 htodseq, bool skip_wlfc_hdr) -{ - uint32 wl_pktinfo = 0; - uint8* wlh; - uint8 dataOffset = 0; - uint8 fillers; - uint8 tim_signal_len = 0; - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - - struct bdc_header *h; - void *p = *packet; - - if (skip_wlfc_hdr) - goto push_bdc_hdr; - - if (tim_signal) { - tim_signal_len = TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; - } - - /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ - dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + TLV_HDR_LEN + tim_signal_len; - if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { - dataOffset += WLFC_CTL_VALUE_LEN_SEQ; - } - - fillers = ROUNDUP(dataOffset, 4) - dataOffset; - dataOffset += fillers; - - PKTPUSH(ctx->osh, p, dataOffset); - wlh = (uint8*) PKTDATA(ctx->osh, p); - - wl_pktinfo = htol32(htodtag); - - wlh[TLV_TAG_OFF] = WLFC_CTL_TYPE_PKTTAG; - wlh[TLV_LEN_OFF] = WLFC_CTL_VALUE_LEN_PKTTAG; - memcpy(&wlh[TLV_HDR_LEN], &wl_pktinfo, sizeof(uint32)); - - if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { - uint16 wl_seqinfo = htol16(htodseq); - wlh[TLV_LEN_OFF] += WLFC_CTL_VALUE_LEN_SEQ; - memcpy(&wlh[TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PKTTAG], &wl_seqinfo, - WLFC_CTL_VALUE_LEN_SEQ); - } - - if (tim_signal_len) { - wlh[dataOffset - fillers - tim_signal_len ] = - WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; - wlh[dataOffset - fillers - tim_signal_len + 1] = - WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; - wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; - wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; - } - if (fillers) - memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); - -push_bdc_hdr: - - PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); - h = (struct bdc_header *)PKTDATA(ctx->osh, p); - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (PKTSUMNEEDED(p)) - h->flags |= BDC_FLAG_SUM_NEEDED; - - - h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); - h->flags2 = 0; - h->dataOffset = dataOffset >> 2; - BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); - *packet = p; - return BCME_OK; -} - -static int -_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) -{ - struct bdc_header *h; - - if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { - DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); - return BCME_ERROR; - } - h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); - - /* pull BDC header */ - PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); - - if (PKTLEN(ctx->osh, pktbuf) < (uint)(h->dataOffset << 2)) { - DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); - return BCME_ERROR; - } - - /* pull wl-header */ - PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); - return BCME_OK; -} - -static wlfc_mac_descriptor_t* -_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) -{ - int i; - wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; - uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); - uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); - wlfc_mac_descriptor_t* entry = DHD_PKTTAG_ENTRY(PKTTAG(p)); - int iftype = ctx->destination_entries.interfaces[ifid].iftype; - - /* saved one exists, return it */ - if (entry) - return entry; - - /* Multicast destination, STA and P2P clients get the interface entry. - * STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations - * have their own entry. - */ - if ((DHD_IF_ROLE_STA(iftype) || ETHER_ISMULTI(dstn)) && - (ctx->destination_entries.interfaces[ifid].occupied)) { - entry = &ctx->destination_entries.interfaces[ifid]; - } - - if (entry && ETHER_ISMULTI(dstn)) { - DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); - return entry; - } - - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (table[i].occupied) { - if (table[i].interface_id == ifid) { - if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) { - entry = &table[i]; - break; - } - } - } - } - - if (entry == NULL) - entry = &ctx->destination_entries.other; - - DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); - - return entry; -} - -static int -_dhd_wlfc_prec_drop(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ) -{ - athost_wl_status_info_t* ctx; - void *pout = NULL; - - ASSERT(dhdp && p); - ASSERT(prec >= 0 && prec <= WLFC_PSQ_PREC_COUNT); - - ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; - - if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { - /* suppressed queue, need pop from hanger */ - _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG - (PKTTAG(p))), &pout, TRUE); - ASSERT(p == pout); - } - - if (!(prec & 1)) { -#ifdef DHDTCPACK_SUPPRESS - /* pkt in delayed q, so fake push BDC header for - * dhd_tcpack_check_xmit() and dhd_txcomplete(). - */ - _dhd_wlfc_pushheader(ctx, &p, FALSE, 0, 0, 0, 0, TRUE); - - /* This packet is about to be freed, so remove it from tcp_ack_info_tbl - * This must be one of... - * 1. A pkt already in delayQ is evicted by another pkt with higher precedence - * in _dhd_wlfc_prec_enq_with_drop() - * 2. A pkt could not be enqueued to delayQ because it is full, - * in _dhd_wlfc_enque_delayq(). - * 3. A pkt could not be enqueued to delayQ because it is full, - * in _dhd_wlfc_rollback_packet_toq(). - */ - if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" - " Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - } - - if (bPktInQ) { - ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; - ctx->pkt_cnt_per_ac[prec>>1]--; - } - - ctx->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(p))][DHD_PKTTAG_FIFO(PKTTAG(p))]--; - ctx->stats.pktout++; - ctx->stats.drop_pkts[prec]++; - - dhd_txcomplete(dhdp, p, FALSE); - PKTFREE(ctx->osh, p, TRUE); - - return 0; -} - -static bool -_dhd_wlfc_prec_enq_with_drop(dhd_pub_t *dhdp, struct pktq *pq, void *pkt, int prec, bool qHead, - uint8 current_seq) -{ - void *p = NULL; - int eprec = -1; /* precedence to evict from */ - athost_wl_status_info_t* ctx; - - ASSERT(dhdp && pq && pkt); - ASSERT(prec >= 0 && prec < pq->num_prec); - - ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; - - /* Fast case, precedence queue is not full and we are also not - * exceeding total queue length - */ - if (!pktq_pfull(pq, prec) && !pktq_full(pq)) { - goto exit; - } - - /* Determine precedence from which to evict packet, if any */ - if (pktq_pfull(pq, prec)) - eprec = prec; - else if (pktq_full(pq)) { - p = pktq_peek_tail(pq, &eprec); - if (!p) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return FALSE; - } - if ((eprec > prec) || (eprec < 0)) { - if (!pktq_pempty(pq, prec)) { - eprec = prec; - } else { - return FALSE; - } - } - } - - /* Evict if needed */ - if (eprec >= 0) { - /* Detect queueing to unconfigured precedence */ - ASSERT(!pktq_pempty(pq, eprec)); - /* Evict all fragmented frames */ - dhd_prec_drop_pkts(dhdp, pq, eprec, _dhd_wlfc_prec_drop); - } - -exit: - /* Enqueue */ - _dhd_wlfc_prec_enque(pq, prec, pkt, qHead, current_seq, - WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)); - ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(pkt))][prec>>1]++; - ctx->pkt_cnt_per_ac[prec>>1]++; - - return TRUE; -} - - -static int -_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, - void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) -{ - /* - put the packet back to the head of queue - - - suppressed packet goes back to suppress sub-queue - - pull out the header, if new or delayed packet - - Note: hslot is used only when header removal is done. - */ - wlfc_mac_descriptor_t* entry; - int rc = BCME_OK; - int prec, fifo_id; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - prec = DHD_PKTTAG_FIFO(PKTTAG(p)); - fifo_id = prec << 1; - if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) - fifo_id += 1; - if (entry != NULL) { - /* - if this packet did not count against FIFO credit, it must have - taken a requested_credit from the firmware (for pspoll etc.) - */ - if ((prec != AC_COUNT) && !DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) - entry->requested_credit++; - - if (pkt_type == eWLFC_PKTTYPE_DELAYED) { - /* decrement sequence count */ - WLFC_DECR_SEQCOUNT(entry, prec); - /* remove header first */ - rc = _dhd_wlfc_pullheader(ctx, p); - if (rc != BCME_OK) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - goto exit; - } - } - - if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, fifo_id, TRUE, - WLFC_SEQCOUNT(entry, fifo_id>>1)) - == FALSE) { - /* enque failed */ - DHD_ERROR(("Error: %s():%d, fifo_id(%d)\n", - __FUNCTION__, __LINE__, fifo_id)); - rc = BCME_ERROR; - } - } else { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } -exit: - if (rc != BCME_OK) { - ctx->stats.rollback_failed++; - _dhd_wlfc_prec_drop(ctx->dhdp, fifo_id, p, FALSE); - } - else - ctx->stats.rollback++; - - return rc; -} - -static bool -_dhd_wlfc_allow_fc(athost_wl_status_info_t* ctx, uint8 ifid) -{ - int prec, ac_traffic = WLFC_NO_TRAFFIC; - - for (prec = 0; prec < AC_COUNT; prec++) { - if (ctx->pkt_cnt_in_drv[ifid][prec] > 0) { - if (ac_traffic == WLFC_NO_TRAFFIC) - ac_traffic = prec + 1; - else if (ac_traffic != (prec + 1)) - ac_traffic = WLFC_MULTI_TRAFFIC; - } - } - - if (ac_traffic >= 1 && ac_traffic <= AC_COUNT) { - /* single AC (BE/BK/VI/VO) in queue */ - if (ctx->allow_fc) { - return TRUE; - } else { - uint32 delta; - uint32 curr_t = OSL_SYSUPTIME(); - - if (ctx->fc_defer_timestamp == 0) { - /* first signle ac scenario */ - ctx->fc_defer_timestamp = curr_t; - return FALSE; - } - - /* single AC duration, this handles wrap around, e.g. 1 - ~0 = 2. */ - delta = curr_t - ctx->fc_defer_timestamp; - if (delta >= WLFC_FC_DEFER_PERIOD_MS) { - ctx->allow_fc = TRUE; - } - } - } else { - /* multiple ACs or BCMC in queue */ - ctx->allow_fc = FALSE; - ctx->fc_defer_timestamp = 0; - } - - return ctx->allow_fc; -} - -static void -_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) -{ - dhd_pub_t *dhdp; - - ASSERT(ctx); - - dhdp = (dhd_pub_t *)ctx->dhdp; - ASSERT(dhdp); - - if (dhdp->skip_fc && dhdp->skip_fc()) - return; - - if ((ctx->hostif_flow_state[if_id] == OFF) && !_dhd_wlfc_allow_fc(ctx, if_id)) - return; - - if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { - /* start traffic */ - ctx->hostif_flow_state[if_id] = OFF; - /* - WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", - pq->len, if_id, __FUNCTION__)); - */ - WLFC_DBGMESG(("F")); - - dhd_txflowcontrol(dhdp, if_id, OFF); - - ctx->toggle_host_if = 0; - } - - if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { - /* stop traffic */ - ctx->hostif_flow_state[if_id] = ON; - /* - WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", - pq->len, if_id, __FUNCTION__)); - */ - WLFC_DBGMESG(("N")); - - dhd_txflowcontrol(dhdp, if_id, ON); - - ctx->host_ifidx = if_id; - ctx->toggle_host_if = 1; - } - - return; -} - -static int -_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - uint8 ta_bmp) -{ - int rc = BCME_OK; - void* p = NULL; - int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 16; - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - - if (dhdp->proptxstatus_txoff) { - rc = BCME_NORESOURCE; - return rc; - } - - /* allocate a dummy packet */ - p = PKTGET(ctx->osh, dummylen, TRUE); - if (p) { - PKTPULL(ctx->osh, p, dummylen); - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); - _dhd_wlfc_pushheader(ctx, &p, TRUE, ta_bmp, entry->mac_handle, 0, 0, FALSE); - DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); - DHD_PKTTAG_WLFCPKT_SET(PKTTAG(p), 1); -#ifdef PROP_TXSTATUS_DEBUG - ctx->stats.signal_only_pkts_sent++; -#endif - -#if defined(BCMPCIE) - rc = dhd_bus_txdata(dhdp->bus, p, ctx->host_ifidx); -#else - rc = dhd_bus_txdata(dhdp->bus, p); -#endif - if (rc != BCME_OK) { - _dhd_wlfc_pullheader(ctx, p); - PKTFREE(ctx->osh, p, TRUE); - } - } - else { - DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", - __FUNCTION__, dummylen)); - rc = BCME_NOMEM; - } - return rc; -} - -/* Return TRUE if traffic availability changed */ -static bool -_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - int prec) -{ - bool rc = FALSE; - - if (entry->state == WLFC_STATE_CLOSE) { - if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && - (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { - - if (entry->traffic_pending_bmp & NBITVAL(prec)) { - rc = TRUE; - entry->traffic_pending_bmp = - entry->traffic_pending_bmp & ~ NBITVAL(prec); - } - } - else { - if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { - rc = TRUE; - entry->traffic_pending_bmp = - entry->traffic_pending_bmp | NBITVAL(prec); - } - } - } - if (rc) { - /* request a TIM update to firmware at the next piggyback opportunity */ - if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { - entry->send_tim_signal = 1; - _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); - entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; - entry->send_tim_signal = 0; - } - else { - rc = FALSE; - } - } - return rc; -} - -static int -_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) -{ - wlfc_mac_descriptor_t* entry; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - if (entry == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_NOTFOUND; - } - /* - - suppressed packets go to sub_queue[2*prec + 1] AND - - delayed packets go to sub_queue[2*prec + 0] to ensure - order of delivery. - */ - if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, ((prec << 1) + 1), FALSE, - WLFC_SEQCOUNT(entry, prec)) - == FALSE) { - ctx->stats.delayq_full_error++; - /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ - WLFC_DBGMESG(("s")); - return BCME_ERROR; - } - - /* A packet has been pushed, update traffic availability bitmap, if applicable */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); - return BCME_OK; -} - -static int -_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, - wlfc_mac_descriptor_t* entry, void** packet, int header_needed, uint32* slot) -{ - int rc = BCME_OK; - int hslot = WLFC_HANGER_MAXITEMS; - bool send_tim_update = FALSE; - uint32 htod = 0; - uint16 htodseq = 0; - uint8 free_ctr, flags = 0; - int gen = 0xff; - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - void * p = *packet; - - *slot = hslot; - - if (entry == NULL) { - entry = _dhd_wlfc_find_table_entry(ctx, p); - } - - if (entry == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_ERROR; - } - - if (entry->send_tim_signal) { - send_tim_update = TRUE; - entry->send_tim_signal = 0; - entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; - } - - if (header_needed) { - if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { - hslot = (uint)(entry - &ctx->destination_entries.nodes[0]); - } else { - hslot = _dhd_wlfc_hanger_get_free_slot(ctx->hanger); - } - gen = entry->generation; - free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); - } else { - if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { - htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(p)); - } - - hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - - if (WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)) { - gen = entry->generation; - } else if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { - gen = WL_TXSTATUS_GET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - } else { - _dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); - } - - free_ctr = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - /* remove old header */ - _dhd_wlfc_pullheader(ctx, p); - } - - if (hslot >= WLFC_HANGER_MAXITEMS) { - DHD_ERROR(("Error: %s():no hanger slot available\n", __FUNCTION__)); - return BCME_ERROR; - } - - flags = WLFC_PKTFLAG_PKTFROMHOST; - if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { - /* - Indicate that this packet is being sent in response to an - explicit request from the firmware side. - */ - flags |= WLFC_PKTFLAG_PKT_REQUESTED; - } - if (pkt_is_dhcp(ctx->osh, p)) { - flags |= WLFC_PKTFLAG_PKT_FORCELOWRATE; - } - - WL_TXSTATUS_SET_FREERUNCTR(htod, free_ctr); - WL_TXSTATUS_SET_HSLOT(htod, hslot); - WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); - WL_TXSTATUS_SET_FLAGS(htod, flags); - WL_TXSTATUS_SET_GENERATION(htod, gen); - DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); - - rc = _dhd_wlfc_pushheader(ctx, &p, send_tim_update, - entry->traffic_lastreported_bmp, entry->mac_handle, htod, htodseq, FALSE); - if (rc == BCME_OK) { - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); - - if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && header_needed) { - /* - a new header was created for this packet. - push to hanger slot and scrub q. Since bus - send succeeded, increment seq number as well. - */ - rc = _dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); - if (rc == BCME_OK) { -#ifdef PROP_TXSTATUS_DEBUG - ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = - OSL_SYSUPTIME(); -#endif - } else { - DHD_ERROR(("%s() hanger_pushpkt() failed, rc: %d\n", - __FUNCTION__, rc)); - } - } - - if ((rc == BCME_OK) && header_needed) { - /* increment free running sequence count */ - WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); - } - } - *slot = hslot; - *packet = p; - return rc; -} - -static int -_dhd_wlfc_is_destination_open(athost_wl_status_info_t* ctx, - wlfc_mac_descriptor_t* entry, int prec) -{ - if (entry->interface_id >= WLFC_MAX_IFNUM) { - ASSERT(&ctx->destination_entries.other == entry); - return 1; - } - if (ctx->destination_entries.interfaces[entry->interface_id].iftype == - WLC_E_IF_ROLE_P2P_GO) { - /* - destination interface is of type p2p GO. - For a p2pGO interface, if the destination is OPEN but the interface is - CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is - destination-specific-credit left send packets. This is because the - firmware storing the destination-specific-requested packet in queue. - */ - if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && - (entry->requested_packet == 0)) { - return 0; - } - } - /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ - if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && - (entry->requested_packet == 0)) || - (!(entry->ac_bitmap & (1 << prec)))) { - return 0; - } - - return 1; -} - -static void* -_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, int prec, - uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out, - bool only_no_credit) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - wlfc_mac_descriptor_t* entry; - int total_entries; - void* p = NULL; - int i; - - *entry_out = NULL; - /* most cases a packet will count against FIFO credit */ - *ac_credit_spent = ((prec == AC_COUNT) && !ctx->bcmc_credit_supported) ? 0 : 1; - - /* search all entries, include nodes as well as interfaces */ - if (only_no_credit) { - total_entries = ctx->requested_entry_count; - } else { - total_entries = ctx->active_entry_count; - } - - for (i = 0; i < total_entries; i++) { - if (only_no_credit) { - entry = ctx->requested_entry[i]; - } else { - entry = ctx->active_entry_head; - /* move head to ensure fair round-robin */ - ctx->active_entry_head = ctx->active_entry_head->next; - } - ASSERT(entry); - - if (entry->occupied && _dhd_wlfc_is_destination_open(ctx, entry, prec) && - (entry->transit_count < WL_TXSTATUS_FREERUNCTR_MASK) && - !(WLFC_GET_REORDERSUPP(dhdp->wlfc_mode) && entry->suppressed)) { - if (entry->state == WLFC_STATE_CLOSE) { - *ac_credit_spent = 0; - } - - /* higher precedence will be picked up first, - * i.e. suppressed packets before delayed ones - */ - p = pktq_pdeq(&entry->psq, PSQ_SUP_IDX(prec)); - *needs_hdr = 0; - if (p == NULL) { - if (entry->suppressed == TRUE) { - /* skip this entry */ - continue; - } - /* De-Q from delay Q */ - p = pktq_pdeq(&entry->psq, PSQ_DLY_IDX(prec)); - *needs_hdr = 1; - } - - if (p != NULL) { - /* did the packet come from suppress sub-queue? */ - if (entry->requested_credit > 0) { - entry->requested_credit--; -#ifdef PROP_TXSTATUS_DEBUG - entry->dstncredit_sent_packets++; -#endif - } else if (entry->requested_packet > 0) { - entry->requested_packet--; - DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); - } - - *entry_out = entry; - ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec]--; - ctx->pkt_cnt_per_ac[prec]--; - _dhd_wlfc_flow_control_check(ctx, &entry->psq, - DHD_PKTTAG_IF(PKTTAG(p))); - /* - A packet has been picked up, update traffic - availability bitmap, if applicable - */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - return p; - } - } - } - return NULL; -} - -static int -_dhd_wlfc_enque_delayq(athost_wl_status_info_t* ctx, void* pktbuf, int prec) -{ - wlfc_mac_descriptor_t* entry; - - if (pktbuf != NULL) { - entry = _dhd_wlfc_find_table_entry(ctx, pktbuf); - if (entry == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_ERROR; - } - - /* - - suppressed packets go to sub_queue[2*prec + 1] AND - - delayed packets go to sub_queue[2*prec + 0] to ensure - order of delivery. - */ - if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, pktbuf, (prec << 1), - FALSE, WLFC_SEQCOUNT(entry, prec)) - == FALSE) { - WLFC_DBGMESG(("D")); - ctx->stats.delayq_full_error++; - return BCME_ERROR; - } - - - /* - A packet has been pushed, update traffic availability bitmap, - if applicable - */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - } - - return BCME_OK; -} - -static bool _dhd_wlfc_ifpkt_fn(void* p, void *p_ifid) -{ - if (!p || !p_ifid) - return FALSE; - - return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (*((uint8 *)p_ifid) == DHD_PKTTAG_IF(PKTTAG(p)))); -} - -static bool _dhd_wlfc_entrypkt_fn(void* p, void *entry) -{ - if (!p || !entry) - return FALSE; - - return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (entry == DHD_PKTTAG_ENTRY(PKTTAG(p)))); -} - -static void -_dhd_wlfc_return_implied_credit(athost_wl_status_info_t* wlfc, void* pkt) -{ - dhd_pub_t *dhdp; - - if (!wlfc || !pkt) { - return; - } - - dhdp = (dhd_pub_t *)(wlfc->dhdp); - if (dhdp && (dhdp->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) && - DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { - int lender, credit_returned = 0; - uint8 fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pkt)); - - /* Note that borrower is fifo_id */ - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; lender >= 0; lender--) { - if (wlfc->credits_borrowed[fifo_id][lender] > 0) { - wlfc->FIFO_credit[lender]++; - wlfc->credits_borrowed[fifo_id][lender]--; - credit_returned = 1; - break; - } - } - - if (!credit_returned) { - wlfc->FIFO_credit[fifo_id]++; - } - } -} - -static void -_dhd_wlfc_hanger_free_pkt(athost_wl_status_info_t* wlfc, uint32 slot_id, uint8 pkt_state, - int pkt_txstatus) -{ - wlfc_hanger_t* hanger; - wlfc_hanger_item_t* item; - - if (!wlfc) - return; - - hanger = (wlfc_hanger_t*)wlfc->hanger; - if (!hanger) - return; - - if (slot_id == WLFC_HANGER_MAXITEMS) - return; - - item = &hanger->items[slot_id]; - item->pkt_state |= pkt_state; - if (pkt_txstatus != -1) { - item->pkt_txstatus = pkt_txstatus; - } - - if (item->pkt) { - if ((item->pkt_state & WLFC_HANGER_PKT_STATE_TXCOMPLETE) && - (item->pkt_state & (WLFC_HANGER_PKT_STATE_TXSTATUS | - WLFC_HANGER_PKT_STATE_CLEANUP))) { - void *p = NULL; - void *pkt = item->pkt; - uint8 old_state = item->state; - int ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, slot_id, &p, TRUE); - BCM_REFERENCE(ret); - BCM_REFERENCE(pkt); - ASSERT((ret == BCME_OK) && p && (pkt == p)); - - /* free packet */ - if (!(item->pkt_state & WLFC_HANGER_PKT_STATE_TXSTATUS)) { - /* cleanup case */ - wlfc_mac_descriptor_t *entry = _dhd_wlfc_find_table_entry(wlfc, p); - - ASSERT(entry); - if (entry->transit_count) - entry->transit_count--; - if (entry->suppr_transit_count) { - entry->suppr_transit_count--; - if (!entry->suppr_transit_count) - entry->suppressed = FALSE; - } - _dhd_wlfc_return_implied_credit(wlfc, p); - wlfc->stats.cleanup_fw_cnt++; - /* slot not freeable yet */ - item->state = old_state; - } - - wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(p))] - [DHD_PKTTAG_FIFO(PKTTAG(p))]--; - wlfc->stats.pktout++; - dhd_txcomplete((dhd_pub_t *)wlfc->dhdp, p, item->pkt_txstatus); - PKTFREE(wlfc->osh, p, TRUE); - } - } else { - if (item->pkt_state & WLFC_HANGER_PKT_STATE_TXSTATUS) { - /* free slot */ - if (item->state == WLFC_HANGER_ITEM_STATE_FREE) - DHD_ERROR(("Error: %s():%d get multi TXSTATUS for one packet???\n", - __FUNCTION__, __LINE__)); - item->state = WLFC_HANGER_ITEM_STATE_FREE; - } - } -} - -static void -_dhd_wlfc_pktq_flush(athost_wl_status_info_t* ctx, struct pktq *pq, - bool dir, f_processpkt_t fn, void *arg, q_type_t q_type) -{ - int prec; - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - - ASSERT(dhdp); - - /* Optimize flush, if pktq len = 0, just return. - * pktq len of 0 means pktq's prec q's are all empty. - */ - if (pq->len == 0) { - return; - } - - - for (prec = 0; prec < pq->num_prec; prec++) { - struct pktq_prec *q; - void *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 = PKTLINK(p); - else - PKTSETLINK(prev, PKTLINK(p)); - if (q_type == Q_TYPE_PSQ) { - if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { - _dhd_wlfc_hanger_remove_reference(ctx->hanger, p); - } - ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; - ctx->pkt_cnt_per_ac[prec>>1]--; - ctx->stats.cleanup_psq_cnt++; - if (!(prec & 1)) { - /* pkt in delayed q, so fake push BDC header for - * dhd_tcpack_check_xmit() and dhd_txcomplete(). - */ - _dhd_wlfc_pushheader(ctx, &p, FALSE, 0, 0, - 0, 0, TRUE); -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" - " Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(dhdp, - TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - } - } else if (q_type == Q_TYPE_AFQ) { - wlfc_mac_descriptor_t* entry = - _dhd_wlfc_find_table_entry(ctx, p); - if (entry->transit_count) - entry->transit_count--; - if (entry->suppr_transit_count) { - entry->suppr_transit_count--; - if (!entry->suppr_transit_count) - entry->suppressed = FALSE; - } - _dhd_wlfc_return_implied_credit(ctx, p); - ctx->stats.cleanup_fw_cnt++; - } - PKTSETLINK(p, NULL); - if (dir) { - ctx->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; - ctx->stats.pktout++; - dhd_txcomplete(dhdp, p, FALSE); - } - PKTFREE(ctx->osh, p, dir); - - q->len--; - pq->len--; - p = (head ? q->head : PKTLINK(prev)); - } else { - prev = p; - p = PKTLINK(p); - } - } - - if (q->head == NULL) { - ASSERT(q->len == 0); - q->tail = NULL; - } - - } - - if (fn == NULL) - ASSERT(pq->len == 0); -} - -static void* -_dhd_wlfc_pktq_pdeq_with_fn(struct pktq *pq, int prec, f_processpkt_t fn, void *arg) -{ - struct pktq_prec *q; - void *p, *prev = NULL; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - p = q->head; - - while (p) { - if (fn == NULL || (*fn)(p, arg)) { - break; - } else { - prev = p; - p = PKTLINK(p); - } - } - if (p == NULL) - return NULL; - - if (prev == NULL) { - if ((q->head = PKTLINK(p)) == NULL) { - q->tail = NULL; - } - } else { - PKTSETLINK(prev, PKTLINK(p)); - if (q->tail == p) { - q->tail = prev; - } - } - - q->len--; - - pq->len--; - - PKTSETLINK(p, NULL); - - return p; -} - -static void -_dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - int prec; - void *pkt = NULL, *head = NULL, *tail = NULL; - struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; - wlfc_mac_descriptor_t* entry; - - dhd_os_sdlock_txq(dhd); - for (prec = 0; prec < txq->num_prec; prec++) { - while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(dhd, pkt) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(dhd, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - if (!head) { - head = pkt; - } - if (tail) { - PKTSETLINK(tail, pkt); - } - tail = pkt; - } - } - dhd_os_sdunlock_txq(dhd); - - - while ((pkt = head)) { - head = PKTLINK(pkt); - PKTSETLINK(pkt, NULL); - entry = _dhd_wlfc_find_table_entry(wlfc, pkt); - - if (!WLFC_GET_AFQ(dhd->wlfc_mode) && - !_dhd_wlfc_hanger_remove_reference(h, pkt)) { - DHD_ERROR(("%s: can't find pkt(%p) in hanger, free it anyway\n", - __FUNCTION__, pkt)); - } - if (entry->transit_count) - entry->transit_count--; - if (entry->suppr_transit_count) { - entry->suppr_transit_count--; - if (!entry->suppr_transit_count) - entry->suppressed = FALSE; - } - _dhd_wlfc_return_implied_credit(wlfc, pkt); - wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pkt))][DHD_PKTTAG_FIFO(PKTTAG(pkt))]--; - wlfc->stats.pktout++; - wlfc->stats.cleanup_txq_cnt++; - dhd_txcomplete(dhd, pkt, FALSE); - PKTFREE(wlfc->osh, pkt, TRUE); - } -} - -void -_dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - int i; - int total_entries; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; - - wlfc->stats.cleanup_txq_cnt = 0; - wlfc->stats.cleanup_psq_cnt = 0; - wlfc->stats.cleanup_fw_cnt = 0; - /* - * flush sequence shoulde be txq -> psq -> hanger/afq, hanger has to be last one - */ - /* flush bus->txq */ - _dhd_wlfc_cleanup_txq(dhd, fn, arg); - - - /* flush psq, search all entries, include nodes as well as interfaces */ - total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); - table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; - - for (i = 0; i < total_entries; i++) { - if (table[i].occupied) { - /* release packets held in PSQ (both delayed and suppressed) */ - if (table[i].psq.len) { - WLFC_DBGMESG(("%s(): PSQ[%d].len = %d\n", - __FUNCTION__, i, table[i].psq.len)); - _dhd_wlfc_pktq_flush(wlfc, &table[i].psq, TRUE, - fn, arg, Q_TYPE_PSQ); - } - - /* free packets held in AFQ */ - if (WLFC_GET_AFQ(dhd->wlfc_mode) && (table[i].afq.len)) { - _dhd_wlfc_pktq_flush(wlfc, &table[i].afq, TRUE, - fn, arg, Q_TYPE_AFQ); - } - - if ((fn == NULL) && (&table[i] != &wlfc->destination_entries.other)) { - table[i].occupied = 0; - if (table[i].transit_count || table[i].suppr_transit_count) { - DHD_ERROR(("%s: table[%d] transit(%d), suppr_tansit(%d)\n", - __FUNCTION__, i, - table[i].transit_count, - table[i].suppr_transit_count)); - } - } - } - } - - /* - . flush remained pkt in hanger queue, not in bus->txq nor psq. - . the remained pkt was successfully downloaded to dongle already. - . hanger slot state cannot be set to free until receive txstatus update. - */ - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - for (i = 0; i < h->max_items; i++) { - if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) || - (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { - if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { - _dhd_wlfc_hanger_free_pkt(wlfc, i, - WLFC_HANGER_PKT_STATE_CLEANUP, FALSE); - } - } - } - } - - return; -} - -static int -_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - uint8 action, uint8 ifid, uint8 iftype, uint8* ea, - f_processpkt_t fn, void *arg) -{ - int rc = BCME_OK; - - - if ((action == eWLFC_MAC_ENTRY_ACTION_ADD) || (action == eWLFC_MAC_ENTRY_ACTION_UPDATE)) { - entry->occupied = 1; - entry->state = WLFC_STATE_OPEN; - entry->requested_credit = 0; - entry->interface_id = ifid; - entry->iftype = iftype; - entry->ac_bitmap = 0xff; /* update this when handling APSD */ - /* for an interface entry we may not care about the MAC address */ - if (ea != NULL) - memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); - - if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { - entry->suppressed = FALSE; - entry->transit_count = 0; - entry->suppr_transit_count = 0; - } - - if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { - dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); - pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); - if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { - pktq_init(&entry->afq, WLFC_AFQ_PREC_COUNT, WLFC_PSQ_LEN); - } - - if (entry->next == NULL) { - /* not linked to anywhere, add to tail */ - if (ctx->active_entry_head) { - entry->prev = ctx->active_entry_head->prev; - ctx->active_entry_head->prev->next = entry; - ctx->active_entry_head->prev = entry; - entry->next = ctx->active_entry_head; - - } else { - ASSERT(ctx->active_entry_count == 0); - entry->prev = entry->next = entry; - ctx->active_entry_head = entry; - } - ctx->active_entry_count++; - } else { - DHD_ERROR(("%s():%d, entry(%d)\n", __FUNCTION__, __LINE__, - (int)(entry - &ctx->destination_entries.nodes[0]))); - } - } - } else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { - /* When the entry is deleted, the packets that are queued in the entry must be - cleanup. The cleanup action should be before the occupied is set as 0. - */ - _dhd_wlfc_cleanup(ctx->dhdp, fn, arg); - _dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid); - - entry->occupied = 0; - entry->state = WLFC_STATE_CLOSE; - memset(&entry->ea[0], 0, ETHER_ADDR_LEN); - - if (entry->next) { - /* not floating, remove from Q */ - if (ctx->active_entry_count <= 1) { - /* last item */ - ctx->active_entry_head = NULL; - ctx->active_entry_count = 0; - } else { - entry->prev->next = entry->next; - entry->next->prev = entry->prev; - if (entry == ctx->active_entry_head) { - ctx->active_entry_head = entry->next; - } - ctx->active_entry_count--; - } - entry->next = entry->prev = NULL; - } else { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - } - } - return rc; -} - -#ifdef LIMIT_BORROW -static int -_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, int highest_lender_ac, int borrower_ac, - bool bBorrowAll) -{ - int lender_ac, borrow_limit = 0; - int rc = -1; - - if (ctx == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return -1; - } - - /* Borrow from lowest priority available AC (including BC/MC credits) */ - for (lender_ac = 0; lender_ac <= highest_lender_ac; lender_ac++) { - if (!bBorrowAll) { - borrow_limit = ctx->Init_FIFO_credit[lender_ac]/WLFC_BORROW_LIMIT_RATIO; - } else { - borrow_limit = 0; - } - - if (ctx->FIFO_credit[lender_ac] > borrow_limit) { - ctx->credits_borrowed[borrower_ac][lender_ac]++; - ctx->FIFO_credit[lender_ac]--; - rc = lender_ac; - break; - } - } - - return rc; -} - -static int _dhd_wlfc_return_credit(athost_wl_status_info_t* ctx, int lender_ac, int borrower_ac) -{ - if ((ctx == NULL) || (lender_ac < 0) || (lender_ac > AC_COUNT) || - (borrower_ac < 0) || (borrower_ac > AC_COUNT)) { - DHD_ERROR(("Error: %s():%d, ctx(%p), lender_ac(%d), borrower_ac(%d)\n", - __FUNCTION__, __LINE__, ctx, lender_ac, borrower_ac)); - - return BCME_BADARG; - } - - ctx->credits_borrowed[borrower_ac][lender_ac]--; - ctx->FIFO_credit[lender_ac]++; - - return BCME_OK; -} -#endif /* LIMIT_BORROW */ - -static int -_dhd_wlfc_interface_entry_update(void* state, - uint8 action, uint8 ifid, uint8 iftype, uint8* ea) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - wlfc_mac_descriptor_t* entry; - - if (ifid >= WLFC_MAX_IFNUM) - return BCME_BADARG; - - entry = &ctx->destination_entries.interfaces[ifid]; - - return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea, - _dhd_wlfc_ifpkt_fn, &ifid); -} - -static int -_dhd_wlfc_BCMCCredit_support_update(void* state) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - - ctx->bcmc_credit_supported = TRUE; - return BCME_OK; -} - -static int -_dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - int i; - - for (i = 0; i <= 4; i++) { - if (ctx->Init_FIFO_credit[i] != ctx->FIFO_credit[i]) { - DHD_ERROR(("%s: credit[i] is not returned, (%d %d)\n", - __FUNCTION__, ctx->Init_FIFO_credit[i], ctx->FIFO_credit[i])); - } - } - - /* update the AC FIFO credit map */ - ctx->FIFO_credit[0] += (credits[0] - ctx->Init_FIFO_credit[0]); - ctx->FIFO_credit[1] += (credits[1] - ctx->Init_FIFO_credit[1]); - ctx->FIFO_credit[2] += (credits[2] - ctx->Init_FIFO_credit[2]); - ctx->FIFO_credit[3] += (credits[3] - ctx->Init_FIFO_credit[3]); - ctx->FIFO_credit[4] += (credits[4] - ctx->Init_FIFO_credit[4]); - - ctx->Init_FIFO_credit[0] = credits[0]; - ctx->Init_FIFO_credit[1] = credits[1]; - ctx->Init_FIFO_credit[2] = credits[2]; - ctx->Init_FIFO_credit[3] = credits[3]; - ctx->Init_FIFO_credit[4] = credits[4]; - - /* credit for ATIM FIFO is not used yet. */ - ctx->Init_FIFO_credit[5] = ctx->FIFO_credit[5] = 0; - - return BCME_OK; -} - -static int -_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, - dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) -{ - uint32 hslot; - int rc; - dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); - - /* - if ac_fifo_credit_spent = 0 - - This packet will not count against the FIFO credit. - To ensure the txstatus corresponding to this packet - does not provide an implied credit (default behavior) - mark the packet accordingly. - - if ac_fifo_credit_spent = 1 - - This is a normal packet and it counts against the FIFO - credit count. - */ - DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); - rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, &commit_info->p, - commit_info->needs_hdr, &hslot); - - if (rc == BCME_OK) { - rc = fcommit(commit_ctx, commit_info->p); - if (rc == BCME_OK) { - uint8 gen = WL_TXSTATUS_GET_GENERATION( - DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))); - ctx->stats.pkt2bus++; - if (commit_info->ac_fifo_credit_spent || (ac == AC_COUNT)) { - ctx->stats.send_pkts[ac]++; - WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); - } - - if (gen != commit_info->mac_entry->generation) { - /* will be suppressed back by design */ - if (!commit_info->mac_entry->suppressed) { - commit_info->mac_entry->suppressed = TRUE; - } - commit_info->mac_entry->suppr_transit_count++; - } - commit_info->mac_entry->transit_count++; - } else if (commit_info->needs_hdr) { - if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { - void *pout = NULL; - /* pop hanger for delayed packet */ - _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT( - DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))), &pout, TRUE); - ASSERT(commit_info->p == pout); - } - } - } else { - ctx->stats.generic_error++; - } - - if (rc != BCME_OK) { - /* - pretx pkt process or bus commit has failed, rollback. - - remove wl-header for a delayed packet - - save wl-header header for suppressed packets - - reset credit check flag - */ - _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, commit_info->pkt_type, hslot); - DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), 0); - } - - return rc; -} - -static uint8 -_dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) -{ - wlfc_mac_descriptor_t* table = - ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; - uint8 table_index; - - if (ea != NULL) { - for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { - if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && - table[table_index].occupied) - return table_index; - } - } - return WLFC_MAC_DESC_ID_INVALID; -} - -static int -_dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, void** p_mac) -{ - uint8 status_flag; - uint32 status; - int ret = BCME_OK; - int remove_from_hanger = 1; - void* pktbuf = NULL; - uint8 fifo_id = 0, gen = 0, count = 0, hcnt; - uint16 hslot; - wlfc_mac_descriptor_t* entry = NULL; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - uint16 seq = 0, seq_fromfw = 0, seq_num = 0; - - memcpy(&status, pkt_info, sizeof(uint32)); - status_flag = WL_TXSTATUS_GET_FLAGS(status); - hcnt = WL_TXSTATUS_GET_FREERUNCTR(status); - hslot = WL_TXSTATUS_GET_HSLOT(status); - fifo_id = WL_TXSTATUS_GET_FIFO(status); - gen = WL_TXSTATUS_GET_GENERATION(status); - - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { - memcpy(&seq, pkt_info + WLFC_CTL_VALUE_LEN_TXSTATUS, WLFC_CTL_VALUE_LEN_SEQ); - seq_fromfw = WL_SEQ_GET_FROMFW(seq); - seq_num = WL_SEQ_GET_NUM(seq); - } - - wlfc->stats.txstatus_in += len; - - if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { - wlfc->stats.pkt_freed += len; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_DISCARD_NOACK) { - wlfc->stats.pkt_freed += len; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { - wlfc->stats.d11_suppress += len; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { - wlfc->stats.wl_suppress += len; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { - wlfc->stats.wlc_tossed_pkts += len; - } - - if (dhd->proptxstatus_txstatus_ignore) { - if (!remove_from_hanger) { - DHD_ERROR(("suppress txstatus: %d\n", status_flag)); - } - return BCME_OK; - } - - while (count < len) { - if (WLFC_GET_AFQ(dhd->wlfc_mode)) { - ret = _dhd_wlfc_deque_afq(wlfc, hslot, hcnt, fifo_id, &pktbuf); - } else { - ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, hslot, &pktbuf, FALSE); - if (!pktbuf) { - _dhd_wlfc_hanger_free_pkt(wlfc, hslot, - WLFC_HANGER_PKT_STATE_TXSTATUS, -1); - goto cont; - } - } - - if ((ret != BCME_OK) || !pktbuf) { - goto cont; - } - - /* set fifo_id to correct value because not all FW does that */ - fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); - - entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); - - if (!remove_from_hanger) { - /* this packet was suppressed */ - if (!entry->suppressed || (entry->generation != gen)) { - if (!entry->suppressed) { - entry->suppr_transit_count = entry->transit_count; - if (p_mac) { - *p_mac = entry; - } - } else { - DHD_ERROR(("gen(%d), entry->generation(%d)\n", - gen, entry->generation)); - } - entry->suppressed = TRUE; - - } - entry->generation = gen; - } - -#ifdef PROP_TXSTATUS_DEBUG - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) - { - uint32 new_t = OSL_SYSUPTIME(); - uint32 old_t; - uint32 delta; - old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[hslot].push_time; - - - wlfc->stats.latency_sample_count++; - if (new_t > old_t) - delta = new_t - old_t; - else - delta = 0xffffffff + new_t - old_t; - wlfc->stats.total_status_latency += delta; - wlfc->stats.latency_most_recent = delta; - - wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; - if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) - wlfc->stats.idx_delta = 0; - } -#endif /* PROP_TXSTATUS_DEBUG */ - - /* pick up the implicit credit from this packet */ - if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { - _dhd_wlfc_return_implied_credit(wlfc, pktbuf); - } else { - /* - if this packet did not count against FIFO credit, it must have - taken a requested_credit from the destination entry (for pspoll etc.) - */ - if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) - entry->requested_credit++; -#ifdef PROP_TXSTATUS_DEBUG - entry->dstncredit_acks++; -#endif - } - - if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || - (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { - /* save generation bit inside packet */ - WL_TXSTATUS_SET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(pktbuf)), gen); - - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { - WL_SEQ_SET_FROMDRV(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_fromfw); - WL_SEQ_SET_NUM(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_num); - } - - ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); - if (ret != BCME_OK) { - /* delay q is full, drop this packet */ - DHD_WLFC_QMON_COMPLETE(entry); - _dhd_wlfc_prec_drop(dhd, (fifo_id << 1) + 1, pktbuf, FALSE); - } else { - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - /* Mark suppressed to avoid a double free - during wlfc cleanup - */ - _dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, hslot, gen); - } - } - } else { - - DHD_WLFC_QMON_COMPLETE(entry); - - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - _dhd_wlfc_hanger_free_pkt(wlfc, hslot, - WLFC_HANGER_PKT_STATE_TXSTATUS, TRUE); - } else { - dhd_txcomplete(dhd, pktbuf, TRUE); - wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pktbuf))] - [DHD_PKTTAG_FIFO(PKTTAG(pktbuf))]--; - wlfc->stats.pktout++; - /* free the packet */ - PKTFREE(wlfc->osh, pktbuf, TRUE); - } - } - /* pkt back from firmware side */ - if (entry->transit_count) - entry->transit_count--; - if (entry->suppr_transit_count) { - entry->suppr_transit_count--; - if (!entry->suppr_transit_count) - entry->suppressed = FALSE; - } - -cont: - hcnt = (hcnt + 1) & WL_TXSTATUS_FREERUNCTR_MASK; - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - hslot = (hslot + 1) & WL_TXSTATUS_HSLOT_MASK; - } - - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode) && seq_fromfw) { - seq_num = (seq_num + 1) & WL_SEQ_NUM_MASK; - } - - count++; - } - return BCME_OK; -} - -static int -_dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) -{ - int i; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { -#ifdef PROP_TXSTATUS_DEBUG - wlfc->stats.fifo_credits_back[i] += credits[i]; -#endif - - /* update FIFO credits */ - if (dhd->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) - { - int lender; /* Note that borrower is i */ - - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { - if (wlfc->credits_borrowed[i][lender] > 0) { - if (credits[i] >= wlfc->credits_borrowed[i][lender]) { - credits[i] -= - (uint8)wlfc->credits_borrowed[i][lender]; - wlfc->FIFO_credit[lender] += - wlfc->credits_borrowed[i][lender]; - wlfc->credits_borrowed[i][lender] = 0; - } - else { - wlfc->credits_borrowed[i][lender] -= credits[i]; - wlfc->FIFO_credit[lender] += credits[i]; - credits[i] = 0; - } - } - } - - /* If we have more credits left over, these must belong to the AC */ - if (credits[i] > 0) { - wlfc->FIFO_credit[i] += credits[i]; - } - - if (wlfc->FIFO_credit[i] > wlfc->Init_FIFO_credit[i]) { - wlfc->FIFO_credit[i] = wlfc->Init_FIFO_credit[i]; - } - } - } - - return BCME_OK; -} - -static void -_dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* entry; - int prec; - void *pkt = NULL, *head = NULL, *tail = NULL; - struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); - uint8 results[WLFC_CTL_VALUE_LEN_TXSTATUS+WLFC_CTL_VALUE_LEN_SEQ]; - uint8 credits[WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK] = {0}; - uint32 htod = 0; - uint16 htodseq = 0; - bool bCreditUpdate = FALSE; - - dhd_os_sdlock_txq(dhd); - for (prec = 0; prec < txq->num_prec; prec++) { - while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { - if (!head) { - head = pkt; - } - if (tail) { - PKTSETLINK(tail, pkt); - } - tail = pkt; - } - } - dhd_os_sdunlock_txq(dhd); - - while ((pkt = head)) { - head = PKTLINK(pkt); - PKTSETLINK(pkt, NULL); - - entry = _dhd_wlfc_find_table_entry(wlfc, pkt); - - /* fake a suppression txstatus */ - htod = DHD_PKTTAG_H2DTAG(PKTTAG(pkt)); - WL_TXSTATUS_SET_FLAGS(htod, WLFC_CTL_PKTFLAG_WLSUPPRESS); - WL_TXSTATUS_SET_GENERATION(htod, entry->generation); - memcpy(results, &htod, WLFC_CTL_VALUE_LEN_TXSTATUS); - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { - htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(pkt)); - if (WL_SEQ_GET_FROMDRV(htodseq)) { - WL_SEQ_SET_FROMFW(htodseq, 1); - WL_SEQ_SET_FROMDRV(htodseq, 0); - } - memcpy(results + WLFC_CTL_VALUE_LEN_TXSTATUS, &htodseq, - WLFC_CTL_VALUE_LEN_SEQ); - } - if (WLFC_GET_AFQ(dhd->wlfc_mode)) { - _dhd_wlfc_enque_afq(wlfc, pkt); - } - _dhd_wlfc_compressed_txstatus_update(dhd, results, 1, NULL); - - /* fake a fifo credit back */ - if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { - credits[DHD_PKTTAG_FIFO(PKTTAG(pkt))]++; - bCreditUpdate = TRUE; - } - } - - if (bCreditUpdate) { - _dhd_wlfc_fifocreditback_indicate(dhd, credits); - } -} - - -static int -_dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) -{ - uint32 timestamp; - - (void)dhd; - - bcopy(&value[2], ×tamp, sizeof(uint32)); - DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp)); - return BCME_OK; -} - -static int -_dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) -{ - (void)dhd; - (void)rssi; - return BCME_OK; -} - -static void -_dhd_wlfc_add_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) -{ - int i; - - if (!wlfc || !entry) { - return; - } - - for (i = 0; i < wlfc->requested_entry_count; i++) { - if (entry == wlfc->requested_entry[i]) { - break; - } - } - - if (i == wlfc->requested_entry_count) { - /* no match entry found */ - ASSERT(wlfc->requested_entry_count <= (WLFC_MAC_DESC_TABLE_SIZE-1)); - wlfc->requested_entry[wlfc->requested_entry_count++] = entry; - } -} - -static void -_dhd_wlfc_remove_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) -{ - int i; - - if (!wlfc || !entry) { - return; - } - - for (i = 0; i < wlfc->requested_entry_count; i++) { - if (entry == wlfc->requested_entry[i]) { - break; - } - } - - if (i < wlfc->requested_entry_count) { - /* found */ - ASSERT(wlfc->requested_entry_count > 0); - wlfc->requested_entry_count--; - if (i != wlfc->requested_entry_count) { - wlfc->requested_entry[i] = - wlfc->requested_entry[wlfc->requested_entry_count]; - } - wlfc->requested_entry[wlfc->requested_entry_count] = NULL; - } -} - -static int -_dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - int rc; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - uint8 existing_index; - uint8 table_index; - uint8 ifid; - uint8* ea; - - WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", - __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], - ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), - WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); - - table = wlfc->destination_entries.nodes; - table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); - ifid = value[1]; - ea = &value[2]; - - _dhd_wlfc_remove_requested_entry(wlfc, &table[table_index]); - if (type == WLFC_CTL_TYPE_MACDESC_ADD) { - existing_index = _dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); - if ((existing_index != WLFC_MAC_DESC_ID_INVALID) && - (existing_index != table_index) && table[existing_index].occupied) { - /* - there is an existing different entry, free the old one - and move it to new index if necessary. - */ - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[existing_index], - eWLFC_MAC_ENTRY_ACTION_DEL, table[existing_index].interface_id, - table[existing_index].iftype, NULL, _dhd_wlfc_entrypkt_fn, - &table[existing_index]); - } - - if (!table[table_index].occupied) { - /* this new MAC entry does not exist, create one */ - table[table_index].mac_handle = value[0]; - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], - eWLFC_MAC_ENTRY_ACTION_ADD, ifid, - wlfc->destination_entries.interfaces[ifid].iftype, - ea, NULL, NULL); - } else { - /* the space should have been empty, but it's not */ - wlfc->stats.mac_update_failed++; - } - } - - if (type == WLFC_CTL_TYPE_MACDESC_DEL) { - if (table[table_index].occupied) { - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], - eWLFC_MAC_ENTRY_ACTION_DEL, ifid, - wlfc->destination_entries.interfaces[ifid].iftype, - ea, _dhd_wlfc_entrypkt_fn, &table[table_index]); - } else { - /* the space should have been occupied, but it's not */ - wlfc->stats.mac_update_failed++; - } - } - BCM_REFERENCE(rc); - return BCME_OK; -} - -static int -_dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - /* Handle PS on/off indication */ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle = value[0]; - int i; - - table = wlfc->destination_entries.nodes; - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - if (type == WLFC_CTL_TYPE_MAC_OPEN) { - desc->state = WLFC_STATE_OPEN; - desc->ac_bitmap = 0xff; - DHD_WLFC_CTRINC_MAC_OPEN(desc); - desc->requested_credit = 0; - desc->requested_packet = 0; - _dhd_wlfc_remove_requested_entry(wlfc, desc); - } - else { - desc->state = WLFC_STATE_CLOSE; - DHD_WLFC_CTRINC_MAC_CLOSE(desc); - /* - Indicate to firmware if there is any traffic pending. - */ - for (i = 0; i < AC_COUNT; i++) { - _dhd_wlfc_traffic_pending_check(wlfc, desc, i); - } - } - } - else { - wlfc->stats.psmode_update_failed++; - } - return BCME_OK; -} - -static int -_dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - /* Handle PS on/off indication */ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - uint8 if_id = value[0]; - - if (if_id < WLFC_MAX_IFNUM) { - table = wlfc->destination_entries.interfaces; - if (table[if_id].occupied) { - if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { - table[if_id].state = WLFC_STATE_OPEN; - /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ - } - else { - table[if_id].state = WLFC_STATE_CLOSE; - /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ - } - return BCME_OK; - } - } - wlfc->stats.interface_update_failed++; - - return BCME_OK; -} - -static int -_dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle; - uint8 credit; - - table = wlfc->destination_entries.nodes; - mac_handle = value[1]; - credit = value[0]; - - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - desc->requested_credit = credit; - - desc->ac_bitmap = value[2] & (~(1<stats.credit_request_failed++; - } - return BCME_OK; -} - -static int -_dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle; - uint8 packet_count; - - table = wlfc->destination_entries.nodes; - mac_handle = value[1]; - packet_count = value[0]; - - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - desc->requested_packet = packet_count; - - desc->ac_bitmap = value[2] & (~(1<stats.packet_request_failed++; - } - return BCME_OK; -} - -static void -_dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) -{ - if (info_len) { - if (info_buf && (len <= WLHOST_REORDERDATA_TOTLEN)) { - bcopy(val, info_buf, len); - *info_len = len; - } - else - *info_len = 0; - } -} - -/* - * public functions - */ - -bool dhd_wlfc_is_supported(dhd_pub_t *dhd) -{ - bool rc = TRUE; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return FALSE; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - rc = FALSE; - } - - dhd_os_wlfc_unblock(dhd); - - return rc; -} - -int dhd_wlfc_enable(dhd_pub_t *dhd) -{ - int i, rc = BCME_OK; - athost_wl_status_info_t* wlfc; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_enabled || dhd->wlfc_state) { - rc = BCME_OK; - goto exit; - } - - /* allocate space to track txstatus propagated from firmware */ - dhd->wlfc_state = DHD_OS_PREALLOC(dhd, DHD_PREALLOC_DHD_WLFC_INFO, - sizeof(athost_wl_status_info_t)); - if (dhd->wlfc_state == NULL) { - rc = BCME_NOMEM; - goto exit; - } - - /* initialize state space */ - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - memset(wlfc, 0, sizeof(athost_wl_status_info_t)); - - /* remember osh & dhdp */ - wlfc->osh = dhd->osh; - wlfc->dhdp = dhd; - - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - wlfc->hanger = _dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); - if (wlfc->hanger == NULL) { - DHD_OS_PREFREE(dhd, dhd->wlfc_state, - sizeof(athost_wl_status_info_t)); - dhd->wlfc_state = NULL; - rc = BCME_NOMEM; - goto exit; - } - } - - dhd->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; - /* default to check rx pkt */ - if (dhd->op_mode & DHD_FLAG_IBSS_MODE) { - dhd->wlfc_rxpkt_chk = FALSE; - } else { - dhd->wlfc_rxpkt_chk = TRUE; - } - - - /* initialize all interfaces to accept traffic */ - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - wlfc->hostif_flow_state[i] = OFF; - } - - _dhd_wlfc_mac_entry_update(wlfc, &wlfc->destination_entries.other, - eWLFC_MAC_ENTRY_ACTION_ADD, 0xff, 0, NULL, NULL, NULL); - - wlfc->allow_credit_borrow = 0; - wlfc->single_ac = 0; - wlfc->single_ac_timestamp = 0; - - -exit: - dhd_os_wlfc_unblock(dhd); - - return rc; -} -#ifdef SUPPORT_P2P_GO_PS -int -dhd_wlfc_suspend(dhd_pub_t *dhd) -{ - - uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ - uint32 tlv = 0; - - DHD_TRACE(("%s: masking wlfc events\n", __FUNCTION__)); - if (!dhd->wlfc_enabled) - return -1; - - bcm_mkiovar("tlv", NULL, 0, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) { - DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); - return -1; - } - tlv = iovbuf[0]; - if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == 0) - return 0; - tlv &= ~(WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); - bcm_mkiovar("tlv", (char *)&tlv, 4, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { - DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", - __FUNCTION__, tlv)); - return -1; - } - - return 0; -} - - int -dhd_wlfc_resume(dhd_pub_t *dhd) -{ - uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ - uint32 tlv = 0; - - DHD_TRACE(("%s: unmasking wlfc events\n", __FUNCTION__)); - if (!dhd->wlfc_enabled) - return -1; - - bcm_mkiovar("tlv", NULL, 0, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) { - DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); - return -1; - } - tlv = iovbuf[0]; - if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == - (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) - return 0; - tlv |= (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); - bcm_mkiovar("tlv", (char *)&tlv, 4, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, (char*)iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { - DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", - __FUNCTION__, tlv)); - return -1; - } - - return 0; -} -#endif /* SUPPORT_P2P_GO_PS */ - -int -dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, - uint *reorder_info_len) -{ - uint8 type, len; - uint8* value; - uint8* tmpbuf; - uint16 remainder = (uint16)tlv_hdr_len; - uint16 processed = 0; - athost_wl_status_info_t* wlfc = NULL; - void* entry; - - if ((dhd == NULL) || (pktbuf == NULL)) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (dhd->proptxstatus_mode != WLFC_ONLY_AMPDU_HOSTREORDER) { - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - } - - tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); - - if (remainder) { - while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { - type = tmpbuf[processed]; - if (type == WLFC_CTL_TYPE_FILLER) { - remainder -= 1; - processed += 1; - continue; - } - - len = tmpbuf[processed + 1]; - value = &tmpbuf[processed + 2]; - - if (remainder < (2 + len)) - break; - - remainder -= 2 + len; - processed += 2 + len; - entry = NULL; - - DHD_INFO(("%s():%d type %d remainder %d processed %d\n", - __FUNCTION__, __LINE__, type, remainder, processed)); - - if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) - _dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, - reorder_info_len); - - if (wlfc == NULL) { - ASSERT(dhd->proptxstatus_mode == WLFC_ONLY_AMPDU_HOSTREORDER); - - if (type != WLFC_CTL_TYPE_HOST_REORDER_RXPKTS && - type != WLFC_CTL_TYPE_TRANS_ID) - DHD_INFO(("%s():%d dhd->wlfc_state is NULL yet!" - " type %d remainder %d processed %d\n", - __FUNCTION__, __LINE__, type, remainder, processed)); - continue; - } - - if (type == WLFC_CTL_TYPE_TXSTATUS) { - _dhd_wlfc_compressed_txstatus_update(dhd, value, 1, &entry); - } - else if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) { - uint8 compcnt_offset = WLFC_CTL_VALUE_LEN_TXSTATUS; - - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { - compcnt_offset += WLFC_CTL_VALUE_LEN_SEQ; - } - _dhd_wlfc_compressed_txstatus_update(dhd, value, - value[compcnt_offset], &entry); - } - else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) - _dhd_wlfc_fifocreditback_indicate(dhd, value); - - else if (type == WLFC_CTL_TYPE_RSSI) - _dhd_wlfc_rssi_indicate(dhd, value); - - else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) - _dhd_wlfc_credit_request(dhd, value); - - else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) - _dhd_wlfc_packet_request(dhd, value); - - else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || - (type == WLFC_CTL_TYPE_MAC_CLOSE)) - _dhd_wlfc_psmode_update(dhd, value, type); - - else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || - (type == WLFC_CTL_TYPE_MACDESC_DEL)) - _dhd_wlfc_mac_table_update(dhd, value, type); - - else if (type == WLFC_CTL_TYPE_TRANS_ID) - _dhd_wlfc_dbg_senum_check(dhd, value); - - else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || - (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { - _dhd_wlfc_interface_update(dhd, value, type); - } - - if (entry && WLFC_GET_REORDERSUPP(dhd->wlfc_mode)) { - /* suppress all packets for this mac entry from bus->txq */ - _dhd_wlfc_suppress_txq(dhd, _dhd_wlfc_entrypkt_fn, entry); - } - } - if (remainder != 0 && wlfc) { - /* trouble..., something is not right */ - wlfc->stats.tlv_parse_failed++; - } - } - - if (wlfc) - wlfc->stats.dhd_hdrpulls++; - - dhd_os_wlfc_unblock(dhd); - return BCME_OK; -} - -int -dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf, - bool need_toggle_host_if) -{ - int ac, single_ac = 0, rc = BCME_OK; - dhd_wlfc_commit_info_t commit_info; - athost_wl_status_info_t* ctx; - int bus_retry_count = 0; - - uint8 tx_map = 0; /* packets (send + in queue), Bitmask for 4 ACs + BC/MC */ - uint8 rx_map = 0; /* received packets, Bitmask for 4 ACs + BC/MC */ - uint8 packets_map = 0; /* packets in queue, Bitmask for 4 ACs + BC/MC */ - bool no_credit = FALSE; - - int lender; - - if ((dhdp == NULL) || (fcommit == NULL)) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - if (pktbuf) { - DHD_PKTTAG_WLFCPKT_SET(PKTTAG(pktbuf), 0); - } - rc = WLFC_UNSUPPORTED; - goto exit2; - } - - ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; - - - if (dhdp->proptxstatus_module_ignore) { - if (pktbuf) { - uint32 htod = 0; - WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); - _dhd_wlfc_pushheader(ctx, &pktbuf, FALSE, 0, 0, htod, 0, FALSE); - if (fcommit(commit_ctx, pktbuf)) - PKTFREE(ctx->osh, pktbuf, TRUE); - rc = BCME_OK; - } - goto exit; - } - - memset(&commit_info, 0, sizeof(commit_info)); - - /* - Commit packets for regular AC traffic. Higher priority first. - First, use up FIFO credits available to each AC. Based on distribution - and credits left, borrow from other ACs as applicable - - -NOTE: - If the bus between the host and firmware is overwhelmed by the - traffic from host, it is possible that higher priority traffic - starves the lower priority queue. If that occurs often, we may - have to employ weighted round-robin or ucode scheme to avoid - low priority packet starvation. - */ - - if (pktbuf) { - DHD_PKTTAG_WLFCPKT_SET(PKTTAG(pktbuf), 1); - ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); - /* en-queue the packets to respective queue. */ - rc = _dhd_wlfc_enque_delayq(ctx, pktbuf, ac); - if (rc) { - _dhd_wlfc_prec_drop(ctx->dhdp, (ac << 1), pktbuf, FALSE); - } else { - ctx->stats.pktin++; - ctx->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pktbuf))][ac]++; - } - } - - for (ac = AC_COUNT; ac >= 0; ac--) { - if (dhdp->wlfc_rxpkt_chk) { - /* check rx packet */ - uint32 curr_t = OSL_SYSUPTIME(), delta; - - delta = curr_t - ctx->rx_timestamp[ac]; - if (delta < WLFC_RX_DETECTION_THRESHOLD_MS) { - rx_map |= (1 << ac); - } - } - - if (ctx->pkt_cnt_per_ac[ac] == 0) { - continue; - } - tx_map |= (1 << ac); - single_ac = ac + 1; - while (FALSE == dhdp->proptxstatus_txoff) { - /* packets from delayQ with less priority are fresh and - * they'd need header and have no MAC entry - */ - no_credit = (ctx->FIFO_credit[ac] < 1); - if (dhdp->proptxstatus_credit_ignore || - ((ac == AC_COUNT) && !ctx->bcmc_credit_supported)) { - no_credit = FALSE; - } - - lender = -1; -#ifdef LIMIT_BORROW - if (no_credit && (ac < AC_COUNT) && (tx_map >= rx_map)) { - /* try borrow from lower priority */ - lender = _dhd_wlfc_borrow_credit(ctx, ac - 1, ac, FALSE); - if (lender != -1) { - no_credit = FALSE; - } - } -#endif - commit_info.needs_hdr = 1; - commit_info.mac_entry = NULL; - commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, - &(commit_info.ac_fifo_credit_spent), - &(commit_info.needs_hdr), - &(commit_info.mac_entry), - no_credit); - commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : - eWLFC_PKTTYPE_SUPPRESSED; - - if (commit_info.p == NULL) { -#ifdef LIMIT_BORROW - if (lender != -1) { - _dhd_wlfc_return_credit(ctx, lender, ac); - } -#endif - break; - } - - if (!dhdp->proptxstatus_credit_ignore && (lender == -1)) { - ASSERT(ctx->FIFO_credit[ac] >= commit_info.ac_fifo_credit_spent); - } - /* here we can ensure have credit or no credit needed */ - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, fcommit, - commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent && (lender == -1)) { - ctx->FIFO_credit[ac]--; - } -#ifdef LIMIT_BORROW - else if (!commit_info.ac_fifo_credit_spent && (lender != -1)) { - _dhd_wlfc_return_credit(ctx, lender, ac); - } -#endif - } else { -#ifdef LIMIT_BORROW - if (lender != -1) { - _dhd_wlfc_return_credit(ctx, lender, ac); - } -#endif - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); - goto exit; - } - } - } - - if (ctx->pkt_cnt_per_ac[ac]) { - packets_map |= (1 << ac); - } - } - - if ((tx_map == 0) || dhdp->proptxstatus_credit_ignore) { - /* nothing send out or remain in queue */ - rc = BCME_OK; - goto exit; - } - - if (((tx_map & (tx_map - 1)) == 0) && (tx_map >= rx_map)) { - /* only one tx ac exist and no higher rx ac */ - if ((single_ac == ctx->single_ac) && ctx->allow_credit_borrow) { - ac = single_ac - 1; - } else { - uint32 delta; - uint32 curr_t = OSL_SYSUPTIME(); - - if (single_ac != ctx->single_ac) { - /* new single ac traffic (first single ac or different single ac) */ - ctx->allow_credit_borrow = 0; - ctx->single_ac_timestamp = curr_t; - ctx->single_ac = (uint8)single_ac; - rc = BCME_OK; - goto exit; - } - /* same ac traffic, check if it lasts enough time */ - delta = curr_t - ctx->single_ac_timestamp; - - if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { - /* wait enough time, can borrow now */ - ctx->allow_credit_borrow = 1; - ac = single_ac - 1; - } else { - rc = BCME_OK; - goto exit; - } - } - } else { - /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ - ctx->allow_credit_borrow = 0; - ctx->single_ac_timestamp = 0; - ctx->single_ac = 0; - rc = BCME_OK; - goto exit; - } - - if (packets_map == 0) { - /* nothing to send, skip borrow */ - rc = BCME_OK; - goto exit; - } - - /* At this point, borrow all credits only for ac */ - while (FALSE == dhdp->proptxstatus_txoff) { -#ifdef LIMIT_BORROW - if ((lender = _dhd_wlfc_borrow_credit(ctx, AC_COUNT, ac, TRUE)) == -1) { - break; - } -#endif - commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, - &(commit_info.ac_fifo_credit_spent), - &(commit_info.needs_hdr), - &(commit_info.mac_entry), - FALSE); - if (commit_info.p == NULL) { - /* before borrow only one ac exists and now this only ac is empty */ -#ifdef LIMIT_BORROW - _dhd_wlfc_return_credit(ctx, lender, ac); -#endif - break; - } - - commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : - eWLFC_PKTTYPE_SUPPRESSED; - - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - - if (commit_info.ac_fifo_credit_spent) { -#ifndef LIMIT_BORROW - ctx->FIFO_credit[ac]--; -#endif - } else { -#ifdef LIMIT_BORROW - _dhd_wlfc_return_credit(ctx, lender, ac); -#endif - } - } else { -#ifdef LIMIT_BORROW - _dhd_wlfc_return_credit(ctx, lender, ac); -#endif - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); - goto exit; - } - } - } - -exit: - if (need_toggle_host_if && ctx->toggle_host_if) { - ctx->toggle_host_if = 0; - } - -exit2: - dhd_os_wlfc_unblock(dhdp); - return rc; -} - -int -dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) -{ - athost_wl_status_info_t* wlfc; - void* pout = NULL; - int rtn = BCME_OK; - if ((dhd == NULL) || (txp == NULL)) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - rtn = WLFC_UNSUPPORTED; - goto EXIT; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { -#ifdef PROP_TXSTATUS_DEBUG - wlfc->stats.signal_only_pkts_freed++; -#endif - /* is this a signal-only packet? */ - _dhd_wlfc_pullheader(wlfc, txp); - PKTFREE(wlfc->osh, txp, TRUE); - goto EXIT; - } - - if (!success || dhd->proptxstatus_txstatus_ignore) { - wlfc_mac_descriptor_t *entry = _dhd_wlfc_find_table_entry(wlfc, txp); - - WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", - __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - _dhd_wlfc_hanger_poppkt(wlfc->hanger, WL_TXSTATUS_GET_HSLOT( - DHD_PKTTAG_H2DTAG(PKTTAG(txp))), &pout, TRUE); - ASSERT(txp == pout); - } - - /* indicate failure and free the packet */ - dhd_txcomplete(dhd, txp, success); - - /* return the credit, if necessary */ - _dhd_wlfc_return_implied_credit(wlfc, txp); - - if (entry->transit_count) - entry->transit_count--; - if (entry->suppr_transit_count) { - entry->suppr_transit_count--; - if (!entry->suppr_transit_count) - entry->suppressed = FALSE; - } - wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(txp))][DHD_PKTTAG_FIFO(PKTTAG(txp))]--; - wlfc->stats.pktout++; - PKTFREE(wlfc->osh, txp, TRUE); - } else { - /* bus confirmed pkt went to firmware side */ - if (WLFC_GET_AFQ(dhd->wlfc_mode)) { - _dhd_wlfc_enque_afq(wlfc, txp); - } else { - int hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(txp))); - _dhd_wlfc_hanger_free_pkt(wlfc, hslot, - WLFC_HANGER_PKT_STATE_TXCOMPLETE, -1); - } - } - -EXIT: - dhd_os_wlfc_unblock(dhd); - return rtn; -} - -int -dhd_wlfc_init(dhd_pub_t *dhd) -{ - char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */ - /* enable all signals & indicate host proptxstatus logic is active */ - uint32 tlv, mode, fw_caps; - int ret = 0; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - if (dhd->wlfc_enabled) { - DHD_ERROR(("%s():%d, Already enabled!\n", __FUNCTION__, __LINE__)); - dhd_os_wlfc_unblock(dhd); - return BCME_OK; - } - dhd->wlfc_enabled = TRUE; - dhd_os_wlfc_unblock(dhd); - - tlv = WLFC_FLAGS_RSSI_SIGNALS | - WLFC_FLAGS_XONXOFF_SIGNALS | - WLFC_FLAGS_CREDIT_STATUS_SIGNALS | - WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | - WLFC_FLAGS_HOST_RXRERODER_ACTIVE; - - - /* - try to enable/disable signaling by sending "tlv" iovar. if that fails, - fallback to no flow control? Print a message for now. - */ - - /* enable proptxtstatus signaling by default */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { - DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); - } - else { - /* - Leaving the message for now, it should be removed after a while; once - the tlv situation is stable. - */ - DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", - dhd->wlfc_enabled?"enabled":"disabled", tlv)); - } - - /* query caps */ - ret = bcm_mkiovar("wlfc_mode", (char *)&mode, 4, iovbuf, sizeof(iovbuf)); - if (ret > 0) { - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); - } - - if (ret >= 0) { - fw_caps = *((uint32 *)iovbuf); - mode = 0; - DHD_ERROR(("%s: query wlfc_mode succeed, fw_caps=0x%x\n", __FUNCTION__, fw_caps)); - - if (WLFC_IS_OLD_DEF(fw_caps)) { - /* enable proptxtstatus v2 by default */ - mode = WLFC_MODE_AFQ; - } else { - WLFC_SET_AFQ(mode, WLFC_GET_AFQ(fw_caps)); - WLFC_SET_REUSESEQ(mode, WLFC_GET_REUSESEQ(fw_caps)); - WLFC_SET_REORDERSUPP(mode, WLFC_GET_REORDERSUPP(fw_caps)); - } - ret = bcm_mkiovar("wlfc_mode", (char *)&mode, 4, iovbuf, sizeof(iovbuf)); - if (ret > 0) { - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - } - } - - dhd_os_wlfc_block(dhd); - - dhd->wlfc_mode = 0; - if (ret >= 0) { - if (WLFC_IS_OLD_DEF(mode)) { - WLFC_SET_AFQ(dhd->wlfc_mode, (mode == WLFC_MODE_AFQ)); - } else { - dhd->wlfc_mode = mode; - } - } - DHD_ERROR(("dhd_wlfc_init(): wlfc_mode=0x%x, ret=%d\n", dhd->wlfc_mode, ret)); - - dhd_os_wlfc_unblock(dhd); - - if (dhd->plat_init) - dhd->plat_init((void *)dhd); - - return BCME_OK; -} - -int -dhd_wlfc_hostreorder_init(dhd_pub_t *dhd) -{ - char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */ - /* enable only ampdu hostreorder here */ - uint32 tlv; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - DHD_TRACE(("%s():%d Enter\n", __FUNCTION__, __LINE__)); - - tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; - - /* enable proptxtstatus signaling by default */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { - DHD_ERROR(("%s(): failed to enable/disable bdcv2 tlv signaling\n", - __FUNCTION__)); - } - else { - /* - Leaving the message for now, it should be removed after a while; once - the tlv situation is stable. - */ - DHD_ERROR(("%s(): successful bdcv2 tlv signaling, %d\n", - __FUNCTION__, tlv)); - } - - dhd_os_wlfc_block(dhd); - dhd->proptxstatus_mode = WLFC_ONLY_AMPDU_HOSTREORDER; - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int -dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - _dhd_wlfc_cleanup_txq(dhd, fn, arg); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -/* release all packet resources */ -int -dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - _dhd_wlfc_cleanup(dhd, fn, arg); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int -dhd_wlfc_deinit(dhd_pub_t *dhd) -{ - char iovbuf[32]; /* Room for "ampdu_hostreorder" or "tlv" + '\0' + parameter */ - /* cleanup all psq related resources */ - athost_wl_status_info_t* wlfc; - uint32 tlv = 0; - uint32 hostreorder = 0; - int ret = BCME_OK; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - if (!dhd->wlfc_enabled) { - DHD_ERROR(("%s():%d, Already disabled!\n", __FUNCTION__, __LINE__)); - dhd_os_wlfc_unblock(dhd); - return BCME_OK; - } - dhd->wlfc_enabled = FALSE; - dhd_os_wlfc_unblock(dhd); - - /* query ampdu hostreorder */ - bcm_mkiovar("ampdu_hostreorder", NULL, 0, iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); - if (ret == BCME_OK) - hostreorder = *((uint32 *)iovbuf); - else { - hostreorder = 0; - DHD_ERROR(("%s():%d, ampdu_hostreorder get failed Err = %d\n", - __FUNCTION__, __LINE__, ret)); - } - - if (hostreorder) { - tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; - DHD_ERROR(("%s():%d, maintain HOST RXRERODER flag in tvl\n", - __FUNCTION__, __LINE__)); - } - - /* Disable proptxtstatus signaling for deinit */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - if (ret == BCME_OK) { - /* - Leaving the message for now, it should be removed after a while; once - the tlv situation is stable. - */ - DHD_ERROR(("%s():%d successfully %s bdcv2 tlv signaling, %d\n", - __FUNCTION__, __LINE__, - dhd->wlfc_enabled?"enabled":"disabled", tlv)); - } else - DHD_ERROR(("%s():%d failed to enable/disable bdcv2 tlv signaling Err = %d\n", - __FUNCTION__, __LINE__, ret)); - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - -#ifdef PROP_TXSTATUS_DEBUG - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) - { - int i; - wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; - for (i = 0; i < h->max_items; i++) { - if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { - WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", - __FUNCTION__, i, h->items[i].pkt, - DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); - } - } - } -#endif - - _dhd_wlfc_cleanup(dhd, NULL, NULL); - - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - /* delete hanger */ - _dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); - } - - - /* free top structure */ - DHD_OS_PREFREE(dhd, dhd->wlfc_state, - sizeof(athost_wl_status_info_t)); - dhd->wlfc_state = NULL; - dhd->proptxstatus_mode = hostreorder ? - WLFC_ONLY_AMPDU_HOSTREORDER : WLFC_FCMODE_NONE; - - dhd_os_wlfc_unblock(dhd); - - if (dhd->plat_deinit) - dhd->plat_deinit((void *)dhd); - return BCME_OK; -} - -int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea) -{ - int rc; - - if (dhdp == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhdp); - return WLFC_UNSUPPORTED; - } - - rc = _dhd_wlfc_interface_entry_update(dhdp->wlfc_state, action, ifid, iftype, ea); - - dhd_os_wlfc_unblock(dhdp); - return rc; -} - -int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data) -{ - int rc; - - if (dhdp == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhdp); - return WLFC_UNSUPPORTED; - } - - rc = _dhd_wlfc_FIFOcreditmap_update(dhdp->wlfc_state, event_data); - - dhd_os_wlfc_unblock(dhdp); - - return rc; -} - -int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp) -{ - int rc; - - if (dhdp == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhdp); - return WLFC_UNSUPPORTED; - } - - rc = _dhd_wlfc_BCMCCredit_support_update(dhdp->wlfc_state); - - dhd_os_wlfc_unblock(dhdp); - return rc; -} - -int -dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - int i; - uint8* ea; - athost_wl_status_info_t* wlfc; - wlfc_hanger_t* h; - wlfc_mac_descriptor_t* mac_table; - wlfc_mac_descriptor_t* interfaces; - char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; - - if (!dhdp || !strbuf) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhdp); - return WLFC_UNSUPPORTED; - } - - wlfc = (athost_wl_status_info_t*)dhdp->wlfc_state; - - h = (wlfc_hanger_t*)wlfc->hanger; - if (h == NULL) { - bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); - } - - mac_table = wlfc->destination_entries.nodes; - interfaces = wlfc->destination_entries.interfaces; - bcm_bprintf(strbuf, "---- wlfc stats ----\n"); - - if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { - h = (wlfc_hanger_t*)wlfc->hanger; - if (h == NULL) { - bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); - } else { - bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," - "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", - h->pushed, - h->popped, - h->failed_to_push, - h->failed_to_pop, - h->failed_slotfind, - (h->pushed - h->popped)); - } - } - - bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " - "(dq_full,rollback_fail) = (%d,%d,%d,%d), (%d,%d)\n", - wlfc->stats.tlv_parse_failed, - wlfc->stats.credit_request_failed, - wlfc->stats.mac_update_failed, - wlfc->stats.psmode_update_failed, - wlfc->stats.delayq_full_error, - wlfc->stats.rollback_failed); - - bcm_bprintf(strbuf, "PKTS (init_credit,credit,sent,drop_d,drop_s,outoforder) " - "(AC0[%d,%d,%d,%d,%d,%d],AC1[%d,%d,%d,%d,%d,%d],AC2[%d,%d,%d,%d,%d,%d]," - "AC3[%d,%d,%d,%d,%d,%d],BC_MC[%d,%d,%d,%d,%d,%d])\n", - wlfc->Init_FIFO_credit[0], wlfc->FIFO_credit[0], wlfc->stats.send_pkts[0], - wlfc->stats.drop_pkts[0], wlfc->stats.drop_pkts[1], wlfc->stats.ooo_pkts[0], - wlfc->Init_FIFO_credit[1], wlfc->FIFO_credit[1], wlfc->stats.send_pkts[1], - wlfc->stats.drop_pkts[2], wlfc->stats.drop_pkts[3], wlfc->stats.ooo_pkts[1], - wlfc->Init_FIFO_credit[2], wlfc->FIFO_credit[2], wlfc->stats.send_pkts[2], - wlfc->stats.drop_pkts[4], wlfc->stats.drop_pkts[5], wlfc->stats.ooo_pkts[2], - wlfc->Init_FIFO_credit[3], wlfc->FIFO_credit[3], wlfc->stats.send_pkts[3], - wlfc->stats.drop_pkts[6], wlfc->stats.drop_pkts[7], wlfc->stats.ooo_pkts[3], - wlfc->Init_FIFO_credit[4], wlfc->FIFO_credit[4], wlfc->stats.send_pkts[4], - wlfc->stats.drop_pkts[8], wlfc->stats.drop_pkts[9], wlfc->stats.ooo_pkts[4]); - - bcm_bprintf(strbuf, "\n"); - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (interfaces[i].occupied) { - char* iftype_desc; - - if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) - iftype_desc = "hostif_flow_state[i] == OFF) - ? " OFF":" ON")); - - bcm_bprintf(strbuf, "INTERFACE[%d].PSQ(len,state,credit),(trans,supp_trans)" - "= (%d,%s,%d),(%d,%d)\n", - i, - interfaces[i].psq.len, - ((interfaces[i].state == - WLFC_STATE_OPEN) ? "OPEN":"CLOSE"), - interfaces[i].requested_credit, - interfaces[i].transit_count, interfaces[i].suppr_transit_count); - - bcm_bprintf(strbuf, "INTERFACE[%d].PSQ" - "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," - "(delay3,sup3,afq3),(delay4,sup4,afq4) = (%d,%d,%d)," - "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", - i, - interfaces[i].psq.q[0].len, - interfaces[i].psq.q[1].len, - interfaces[i].afq.q[0].len, - interfaces[i].psq.q[2].len, - interfaces[i].psq.q[3].len, - interfaces[i].afq.q[1].len, - interfaces[i].psq.q[4].len, - interfaces[i].psq.q[5].len, - interfaces[i].afq.q[2].len, - interfaces[i].psq.q[6].len, - interfaces[i].psq.q[7].len, - interfaces[i].afq.q[3].len, - interfaces[i].psq.q[8].len, - interfaces[i].psq.q[9].len, - interfaces[i].afq.q[4].len); - } - } - - bcm_bprintf(strbuf, "\n"); - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (mac_table[i].occupied) { - ea = mac_table[i].ea; - bcm_bprintf(strbuf, "MAC_table[%d].ea = " - "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], - mac_table[i].interface_id); - - bcm_bprintf(strbuf, "MAC_table[%d].PSQ(len,state,credit),(trans,supp_trans)" - "= (%d,%s,%d),(%d,%d)\n", - i, - mac_table[i].psq.len, - ((mac_table[i].state == - WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), - mac_table[i].requested_credit, - mac_table[i].transit_count, mac_table[i].suppr_transit_count); -#ifdef PROP_TXSTATUS_DEBUG - bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", - i, mac_table[i].opened_ct, mac_table[i].closed_ct); -#endif - bcm_bprintf(strbuf, "MAC_table[%d].PSQ" - "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," - "(delay3,sup3,afq3),(delay4,sup4,afq4) =(%d,%d,%d)," - "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", - i, - mac_table[i].psq.q[0].len, - mac_table[i].psq.q[1].len, - mac_table[i].afq.q[0].len, - mac_table[i].psq.q[2].len, - mac_table[i].psq.q[3].len, - mac_table[i].afq.q[1].len, - mac_table[i].psq.q[4].len, - mac_table[i].psq.q[5].len, - mac_table[i].afq.q[2].len, - mac_table[i].psq.q[6].len, - mac_table[i].psq.q[7].len, - mac_table[i].afq.q[3].len, - mac_table[i].psq.q[8].len, - mac_table[i].psq.q[9].len, - mac_table[i].afq.q[4].len); - - } - } - -#ifdef PROP_TXSTATUS_DEBUG - { - int avg; - int moving_avg = 0; - int moving_samples; - - if (wlfc->stats.latency_sample_count) { - moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); - - for (i = 0; i < moving_samples; i++) - moving_avg += wlfc->stats.deltas[i]; - moving_avg /= moving_samples; - - avg = (100 * wlfc->stats.total_status_latency) / - wlfc->stats.latency_sample_count; - bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " - "(%d.%d, %03d, %03d)\n", - moving_samples, avg/100, (avg - (avg/100)*100), - wlfc->stats.latency_most_recent, - moving_avg); - } - } - - bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " - "back = (%d,%d,%d,%d,%d,%d)\n", - wlfc->stats.fifo_credits_sent[0], - wlfc->stats.fifo_credits_sent[1], - wlfc->stats.fifo_credits_sent[2], - wlfc->stats.fifo_credits_sent[3], - wlfc->stats.fifo_credits_sent[4], - wlfc->stats.fifo_credits_sent[5], - - wlfc->stats.fifo_credits_back[0], - wlfc->stats.fifo_credits_back[1], - wlfc->stats.fifo_credits_back[2], - wlfc->stats.fifo_credits_back[3], - wlfc->stats.fifo_credits_back[4], - wlfc->stats.fifo_credits_back[5]); - { - uint32 fifo_cr_sent = 0; - uint32 fifo_cr_acked = 0; - uint32 request_cr_sent = 0; - uint32 request_cr_ack = 0; - uint32 bc_mc_cr_ack = 0; - - for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { - fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; - } - - for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { - fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; - } - - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (wlfc->destination_entries.nodes[i].occupied) { - request_cr_sent += - wlfc->destination_entries.nodes[i].dstncredit_sent_packets; - } - } - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (wlfc->destination_entries.interfaces[i].occupied) { - request_cr_sent += - wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; - } - } - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (wlfc->destination_entries.nodes[i].occupied) { - request_cr_ack += - wlfc->destination_entries.nodes[i].dstncredit_acks; - } - } - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (wlfc->destination_entries.interfaces[i].occupied) { - request_cr_ack += - wlfc->destination_entries.interfaces[i].dstncredit_acks; - } - } - bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," - "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", - fifo_cr_sent, fifo_cr_acked, - request_cr_sent, request_cr_ack, - wlfc->destination_entries.other.dstncredit_acks, - bc_mc_cr_ack, - wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); - } -#endif /* PROP_TXSTATUS_DEBUG */ - bcm_bprintf(strbuf, "\n"); - bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull,out),(dropped,hdr_only,wlc_tossed)" - "(freed,free_err,rollback)) = " - "((%d,%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", - wlfc->stats.pktin, - wlfc->stats.pkt2bus, - wlfc->stats.txstatus_in, - wlfc->stats.dhd_hdrpulls, - wlfc->stats.pktout, - - wlfc->stats.pktdropped, - wlfc->stats.wlfc_header_only_pkt, - wlfc->stats.wlc_tossed_pkts, - - wlfc->stats.pkt_freed, - wlfc->stats.pkt_free_err, wlfc->stats.rollback); - - bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " - "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", - wlfc->stats.d11_suppress, - wlfc->stats.wl_suppress, - wlfc->stats.bad_suppress, - - wlfc->stats.psq_d11sup_enq, - wlfc->stats.psq_wlsup_enq, - wlfc->stats.psq_hostq_enq, - wlfc->stats.mac_handle_notfound, - - wlfc->stats.psq_d11sup_retx, - wlfc->stats.psq_wlsup_retx, - wlfc->stats.psq_hostq_retx); - - bcm_bprintf(strbuf, "wlfc- cleanup(txq,psq,fw) = (%d,%d,%d)\n", - wlfc->stats.cleanup_txq_cnt, - wlfc->stats.cleanup_psq_cnt, - wlfc->stats.cleanup_fw_cnt); - - bcm_bprintf(strbuf, "wlfc- generic error: %d\n", wlfc->stats.generic_error); - - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - bcm_bprintf(strbuf, "wlfc- if[%d], pkt_cnt_in_q/AC[0-4] = (%d,%d,%d,%d,%d)\n", i, - wlfc->pkt_cnt_in_q[i][0], - wlfc->pkt_cnt_in_q[i][1], - wlfc->pkt_cnt_in_q[i][2], - wlfc->pkt_cnt_in_q[i][3], - wlfc->pkt_cnt_in_q[i][4]); - } - bcm_bprintf(strbuf, "\n"); - - dhd_os_wlfc_unblock(dhdp); - return BCME_OK; -} - -int dhd_wlfc_clear_counts(dhd_pub_t *dhd) -{ - athost_wl_status_info_t* wlfc; - wlfc_hanger_t* hanger; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - - memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); - - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - hanger = (wlfc_hanger_t*)wlfc->hanger; - - hanger->pushed = 0; - hanger->popped = 0; - hanger->failed_slotfind = 0; - hanger->failed_to_pop = 0; - hanger->failed_to_push = 0; - } - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->wlfc_enabled; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->wlfc_state ? dhd->proptxstatus_mode : 0; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val) -{ - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (dhd->wlfc_state) { - dhd->proptxstatus_mode = val & 0xff; - } - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf) -{ - athost_wl_status_info_t* wlfc; - bool rc = FALSE; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return FALSE; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return FALSE; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - - if (PKTLEN(wlfc->osh, pktbuf) == 0) { - wlfc->stats.wlfc_header_only_pkt++; - rc = TRUE; - } - - dhd_os_wlfc_unblock(dhd); - - return rc; -} - -int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock) -{ - if (dhdp == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - if (bAcquireLock) { - dhd_os_wlfc_block(dhdp); - } - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE) || - dhdp->proptxstatus_module_ignore) { - if (bAcquireLock) { - dhd_os_wlfc_unblock(dhdp); - } - return WLFC_UNSUPPORTED; - } - - if (state != dhdp->proptxstatus_txoff) { - dhdp->proptxstatus_txoff = state; - } - - if (bAcquireLock) { - dhd_os_wlfc_unblock(dhdp); - } - - return BCME_OK; -} - -int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio) -{ - athost_wl_status_info_t* wlfc; - int rx_path_ac = -1; - - if ((dhd == NULL) || (prio >= NUMPRIO)) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_rxpkt_chk) { - dhd_os_wlfc_unblock(dhd); - return BCME_OK; - } - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - - rx_path_ac = prio2fifo[prio]; - wlfc->rx_timestamp[rx_path_ac] = OSL_SYSUPTIME(); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->proptxstatus_module_ignore; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val) -{ - char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */ - uint32 tlv = 0; - bool bChanged = FALSE; - - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if ((bool)val != dhd->proptxstatus_module_ignore) { - dhd->proptxstatus_module_ignore = (val != 0); - /* force txstatus_ignore sync with proptxstatus_module_ignore */ - dhd->proptxstatus_txstatus_ignore = dhd->proptxstatus_module_ignore; - if (FALSE == dhd->proptxstatus_module_ignore) { - tlv = WLFC_FLAGS_RSSI_SIGNALS | - WLFC_FLAGS_XONXOFF_SIGNALS | - WLFC_FLAGS_CREDIT_STATUS_SIGNALS | - WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE; - } - /* always enable host reorder */ - tlv |= WLFC_FLAGS_HOST_RXRERODER_ACTIVE; - bChanged = TRUE; - } - - dhd_os_wlfc_unblock(dhd); - - if (bChanged) { - /* select enable proptxtstatus signaling */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { - DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", - __FUNCTION__, tlv)); - } - else { - DHD_ERROR(("%s: successfully set bdcv2 tlv signaling to 0x%x\n", - __FUNCTION__, tlv)); - } - } - return BCME_OK; -} - -int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->proptxstatus_credit_ignore; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val) -{ - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - dhd->proptxstatus_credit_ignore = (val != 0); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->proptxstatus_txstatus_ignore; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val) -{ - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - dhd->proptxstatus_txstatus_ignore = (val != 0); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->wlfc_rxpkt_chk; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val) -{ - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - dhd->wlfc_rxpkt_chk = (val != 0); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} -#endif /* PROP_TXSTATUS */ diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h deleted file mode 100644 index a7658ede2b52..000000000000 --- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h +++ /dev/null @@ -1,517 +0,0 @@ -/* -* Copyright (C) 1999-2017, Broadcom Corporation -* -* Unless you and Broadcom execute a separate written software license -* agreement governing use of this software, this software is licensed to you -* under the terms of the GNU General Public License version 2 (the "GPL"), -* available at http://www.broadcom.com/licenses/GPLv2.php, with the -* following added to such license: -* -* As a special exception, the copyright holders of this software give you -* permission to link this software with independent modules, and to copy and -* distribute the resulting executable under terms of your choice, provided that -* you also meet, for each linked independent module, the terms and conditions of -* the license of that module. An independent module is a module which is not -* derived from this software. The special exception does not apply to any -* modifications of the software. -* -* Notwithstanding the above, under no circumstances may you combine this -* software in any way with any other Broadcom software provided under a license -* other than the GPL, without Broadcom's express prior written consent. -* $Id: dhd_wlfc.h 501046 2014-09-06 01:25:16Z $ -* -*/ -#ifndef __wlfc_host_driver_definitions_h__ -#define __wlfc_host_driver_definitions_h__ - - -/* #define OOO_DEBUG */ - -#define WLFC_UNSUPPORTED -9999 - -#define WLFC_NO_TRAFFIC -1 -#define WLFC_MULTI_TRAFFIC 0 - -#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ - -/* 16 bits will provide an absolute max of 65536 slots */ -#define WLFC_HANGER_MAXITEMS 3072 - -#define WLFC_HANGER_ITEM_STATE_FREE 1 -#define WLFC_HANGER_ITEM_STATE_INUSE 2 -#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 - -#define WLFC_HANGER_PKT_STATE_TXSTATUS 1 -#define WLFC_HANGER_PKT_STATE_TXCOMPLETE 2 -#define WLFC_HANGER_PKT_STATE_CLEANUP 4 - -typedef enum { - Q_TYPE_PSQ, - Q_TYPE_AFQ -} q_type_t; - -typedef enum ewlfc_packet_state { - eWLFC_PKTTYPE_NEW, - eWLFC_PKTTYPE_DELAYED, - eWLFC_PKTTYPE_SUPPRESSED, - eWLFC_PKTTYPE_MAX -} ewlfc_packet_state_t; - -typedef enum ewlfc_mac_entry_action { - eWLFC_MAC_ENTRY_ACTION_ADD, - eWLFC_MAC_ENTRY_ACTION_DEL, - eWLFC_MAC_ENTRY_ACTION_UPDATE, - eWLFC_MAC_ENTRY_ACTION_MAX -} ewlfc_mac_entry_action_t; - -typedef struct wlfc_hanger_item { - uint8 state; - uint8 gen; - uint8 pkt_state; - uint8 pkt_txstatus; - uint32 identifier; - void* pkt; -#ifdef PROP_TXSTATUS_DEBUG - uint32 push_time; -#endif - struct wlfc_hanger_item *next; -} wlfc_hanger_item_t; - -typedef struct wlfc_hanger { - int max_items; - uint32 pushed; - uint32 popped; - uint32 failed_to_push; - uint32 failed_to_pop; - uint32 failed_slotfind; - uint32 slot_pos; - wlfc_hanger_item_t items[1]; -} wlfc_hanger_t; - -#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ - sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) - -#define WLFC_STATE_OPEN 1 -#define WLFC_STATE_CLOSE 2 - -#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ -#define WLFC_AFQ_PREC_COUNT (AC_COUNT + 1) - -#define WLFC_PSQ_LEN 2048 - -#define WLFC_FLOWCONTROL_HIWATER (2048 - 256) -#define WLFC_FLOWCONTROL_LOWATER 256 - -#define WLFC_LOG_BUF_SIZE (1024*1024) - -typedef struct wlfc_mac_descriptor { - uint8 occupied; - uint8 interface_id; - uint8 iftype; - uint8 state; - uint8 ac_bitmap; /* for APSD */ - uint8 requested_credit; - uint8 requested_packet; - uint8 ea[ETHER_ADDR_LEN]; - /* - maintain (MAC,AC) based seq count for - packets going to the device. As well as bc/mc. - */ - uint8 seq[AC_COUNT + 1]; - uint8 generation; - struct pktq psq; - /* packets at firmware */ - struct pktq afq; - /* The AC pending bitmap that was reported to the fw at last change */ - uint8 traffic_lastreported_bmp; - /* The new AC pending bitmap */ - uint8 traffic_pending_bmp; - /* 1= send on next opportunity */ - uint8 send_tim_signal; - uint8 mac_handle; - /* Number of packets at dongle for this entry. */ - int transit_count; - /* Numbe of suppression to wait before evict from delayQ */ - int suppr_transit_count; - /* flag. TRUE when in suppress state */ - uint8 suppressed; - - -#ifdef PROP_TXSTATUS_DEBUG - uint32 dstncredit_sent_packets; - uint32 dstncredit_acks; - uint32 opened_ct; - uint32 closed_ct; -#endif - struct wlfc_mac_descriptor* prev; - struct wlfc_mac_descriptor* next; -} wlfc_mac_descriptor_t; - -typedef struct dhd_wlfc_commit_info { - uint8 needs_hdr; - uint8 ac_fifo_credit_spent; - ewlfc_packet_state_t pkt_type; - wlfc_mac_descriptor_t* mac_entry; - void* p; -} dhd_wlfc_commit_info_t; - -#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ - entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) - -#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ -#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] - -typedef struct athost_wl_stat_counters { - uint32 pktin; - uint32 pktout; - uint32 pkt2bus; - uint32 pktdropped; - uint32 tlv_parse_failed; - uint32 rollback; - uint32 rollback_failed; - uint32 delayq_full_error; - uint32 credit_request_failed; - uint32 packet_request_failed; - uint32 mac_update_failed; - uint32 psmode_update_failed; - uint32 interface_update_failed; - uint32 wlfc_header_only_pkt; - uint32 txstatus_in; - uint32 d11_suppress; - uint32 wl_suppress; - uint32 bad_suppress; - uint32 pkt_freed; - uint32 pkt_free_err; - uint32 psq_wlsup_retx; - uint32 psq_wlsup_enq; - uint32 psq_d11sup_retx; - uint32 psq_d11sup_enq; - uint32 psq_hostq_retx; - uint32 psq_hostq_enq; - uint32 mac_handle_notfound; - uint32 wlc_tossed_pkts; - uint32 dhd_hdrpulls; - uint32 generic_error; - /* an extra one for bc/mc traffic */ - uint32 send_pkts[AC_COUNT + 1]; - uint32 drop_pkts[WLFC_PSQ_PREC_COUNT]; - uint32 ooo_pkts[AC_COUNT + 1]; -#ifdef PROP_TXSTATUS_DEBUG - /* all pkt2bus -> txstatus latency accumulated */ - uint32 latency_sample_count; - uint32 total_status_latency; - uint32 latency_most_recent; - int idx_delta; - uint32 deltas[10]; - uint32 fifo_credits_sent[6]; - uint32 fifo_credits_back[6]; - uint32 dropped_qfull[6]; - uint32 signal_only_pkts_sent; - uint32 signal_only_pkts_freed; -#endif - uint32 cleanup_txq_cnt; - uint32 cleanup_psq_cnt; - uint32 cleanup_fw_cnt; -} athost_wl_stat_counters_t; - -#ifdef PROP_TXSTATUS_DEBUG -#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ - (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) -#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ - (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) -#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ - (ctx)->stats.dropped_qfull[(ac)]++;} while (0) -#else -#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) -#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) -#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) -#endif - -#define WLFC_FCMODE_NONE 0 -#define WLFC_FCMODE_IMPLIED_CREDIT 1 -#define WLFC_FCMODE_EXPLICIT_CREDIT 2 -#define WLFC_ONLY_AMPDU_HOSTREORDER 3 - -/* Reserved credits ratio when borrowed by hihger priority */ -#define WLFC_BORROW_LIMIT_RATIO 4 - -/* How long to defer borrowing in milliseconds */ -#define WLFC_BORROW_DEFER_PERIOD_MS 100 - -/* How long to defer flow control in milliseconds */ -#define WLFC_FC_DEFER_PERIOD_MS 200 - -/* How long to detect occurance per AC in miliseconds */ -#define WLFC_RX_DETECTION_THRESHOLD_MS 100 - -/* Mask to represent available ACs (note: BC/MC is ignored */ -#define WLFC_AC_MASK 0xF - -typedef struct athost_wl_status_info { - uint8 last_seqid_to_wlc; - - /* OSL handle */ - osl_t* osh; - /* dhd pub */ - void* dhdp; - - /* stats */ - athost_wl_stat_counters_t stats; - - int Init_FIFO_credit[AC_COUNT + 2]; - - /* the additional ones are for bc/mc and ATIM FIFO */ - int FIFO_credit[AC_COUNT + 2]; - - /* Credit borrow counts for each FIFO from each of the other FIFOs */ - int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; - - /* packet hanger and MAC->handle lookup table */ - void* hanger; - struct { - /* table for individual nodes */ - wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; - /* table for interfaces */ - wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; - /* OS may send packets to unknown (unassociated) destinations */ - /* A place holder for bc/mc and packets to unknown destinations */ - wlfc_mac_descriptor_t other; - } destination_entries; - - wlfc_mac_descriptor_t *active_entry_head; - int active_entry_count; - - wlfc_mac_descriptor_t* requested_entry[WLFC_MAC_DESC_TABLE_SIZE]; - int requested_entry_count; - - /* pkt counts for each interface and ac */ - int pkt_cnt_in_q[WLFC_MAX_IFNUM][AC_COUNT+1]; - int pkt_cnt_per_ac[AC_COUNT+1]; - int pkt_cnt_in_drv[WLFC_MAX_IFNUM][AC_COUNT+1]; - uint8 allow_fc; - uint32 fc_defer_timestamp; - uint32 rx_timestamp[AC_COUNT+1]; - /* ON/OFF state for flow control to the host network interface */ - uint8 hostif_flow_state[WLFC_MAX_IFNUM]; - uint8 host_ifidx; - /* to flow control an OS interface */ - uint8 toggle_host_if; - - /* To borrow credits */ - uint8 allow_credit_borrow; - - /* ac number for the first single ac traffic */ - uint8 single_ac; - - /* Timestamp for the first single ac traffic */ - uint32 single_ac_timestamp; - - bool bcmc_credit_supported; - -} athost_wl_status_info_t; - -/* Please be mindful that total pkttag space is 32 octets only */ -typedef struct dhd_pkttag { - /* - b[15] - 1 = wlfc packet - b[14:13] - encryption exemption - b[12 ] - 1 = event channel - b[11 ] - 1 = this packet was sent in response to one time packet request, - do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. - b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] - b[9 ] - 1 = packet is host->firmware (transmit direction) - - 0 = packet received from firmware (firmware->host) - b[8 ] - 1 = packet was sent due to credit_request (pspoll), - packet does not count against FIFO credit. - - 0 = normal transaction, packet counts against FIFO credit - b[7 ] - 1 = AP, 0 = STA - b[6:4] - AC FIFO number - b[3:0] - interface index - */ - uint16 if_flags; - /* destination MAC address for this packet so that not every - module needs to open the packet to find this - */ - uint8 dstn_ether[ETHER_ADDR_LEN]; - /* - This 32-bit goes from host to device for every packet. - */ - uint32 htod_tag; - - /* - This 16-bit is original seq number for every suppress packet. - */ - uint16 htod_seq; - - /* - This address is mac entry for every packet. - */ - void* entry; - /* bus specific stuff */ - union { - struct { - void* stuff; - uint32 thing1; - uint32 thing2; - } sd; - struct { - void* bus; - void* urb; - } usb; - } bus_specific; -} dhd_pkttag_t; - -#define DHD_PKTTAG_WLFCPKT_MASK 0x1 -#define DHD_PKTTAG_WLFCPKT_SHIFT 15 -#define DHD_PKTTAG_WLFCPKT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_WLFCPKT_MASK << DHD_PKTTAG_WLFCPKT_SHIFT)) | \ - (((value) & DHD_PKTTAG_WLFCPKT_MASK) << DHD_PKTTAG_WLFCPKT_SHIFT) -#define DHD_PKTTAG_WLFCPKT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_WLFCPKT_SHIFT) & DHD_PKTTAG_WLFCPKT_MASK) - -#define DHD_PKTTAG_EXEMPT_MASK 0x3 -#define DHD_PKTTAG_EXEMPT_SHIFT 13 -#define DHD_PKTTAG_EXEMPT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_EXEMPT_MASK << DHD_PKTTAG_EXEMPT_SHIFT)) | \ - (((value) & DHD_PKTTAG_EXEMPT_MASK) << DHD_PKTTAG_EXEMPT_SHIFT) -#define DHD_PKTTAG_EXEMPT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_EXEMPT_SHIFT) & DHD_PKTTAG_EXEMPT_MASK) - -#define DHD_PKTTAG_EVENT_MASK 0x1 -#define DHD_PKTTAG_EVENT_SHIFT 12 -#define DHD_PKTTAG_SETEVENT(tag, event) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_EVENT_MASK << DHD_PKTTAG_EVENT_SHIFT)) | \ - (((event) & DHD_PKTTAG_EVENT_MASK) << DHD_PKTTAG_EVENT_SHIFT) -#define DHD_PKTTAG_EVENT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_EVENT_SHIFT) & DHD_PKTTAG_EVENT_MASK) - -#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 -#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 -#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ - (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) -#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) - -#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 -#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 -#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ - (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) -#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) - -#define DHD_PKTTAG_PKTDIR_MASK 0x1 -#define DHD_PKTTAG_PKTDIR_SHIFT 9 -#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ - (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) -#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) - -#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 -#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 -#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ - (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) -#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) - -#define DHD_PKTTAG_IFTYPE_MASK 0x1 -#define DHD_PKTTAG_IFTYPE_SHIFT 7 -#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ - (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) -#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) - -#define DHD_PKTTAG_FIFO_MASK 0x7 -#define DHD_PKTTAG_FIFO_SHIFT 4 -#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ - (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) -#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) - -#define DHD_PKTTAG_IF_MASK 0xf -#define DHD_PKTTAG_IF_SHIFT 0 -#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_IF_MASK << DHD_PKTTAG_IF_SHIFT)) | \ - (((if) & DHD_PKTTAG_IF_MASK) << DHD_PKTTAG_IF_SHIFT) -#define DHD_PKTTAG_IF(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_IF_SHIFT) & DHD_PKTTAG_IF_MASK) - -#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ - (dstn_MAC_ea), ETHER_ADDR_LEN) -#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether - -#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) -#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) - -#define DHD_PKTTAG_SET_H2DSEQ(tag, seq) ((dhd_pkttag_t*)(tag))->htod_seq = (seq) -#define DHD_PKTTAG_H2DSEQ(tag) (((dhd_pkttag_t*)(tag))->htod_seq) - -#define DHD_PKTTAG_SET_ENTRY(tag, entry) ((dhd_pkttag_t*)(tag))->entry = (entry) -#define DHD_PKTTAG_ENTRY(tag) (((dhd_pkttag_t*)(tag))->entry) - -#define PSQ_SUP_IDX(x) (x * 2 + 1) -#define PSQ_DLY_IDX(x) (x * 2) - -typedef int (*f_commitpkt_t)(void* ctx, void* p); -typedef bool (*f_processpkt_t)(void* p, void* arg); - -#ifdef PROP_TXSTATUS_DEBUG -#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) -#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) -#else -#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) -#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) -#endif - -/* public functions */ -int dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, - uchar *reorder_info_buf, uint *reorder_info_len); -int dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, - void* commit_ctx, void *pktbuf, bool need_toggle_host_if); -int dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); -int dhd_wlfc_init(dhd_pub_t *dhd); -#ifdef SUPPORT_P2P_GO_PS -int dhd_wlfc_suspend(dhd_pub_t *dhd); -int dhd_wlfc_resume(dhd_pub_t *dhd); -#endif /* SUPPORT_P2P_GO_PS */ -int dhd_wlfc_hostreorder_init(dhd_pub_t *dhd); -int dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg); -int dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void* arg); -int dhd_wlfc_deinit(dhd_pub_t *dhd); -int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea); -int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data); -int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp); -int dhd_wlfc_enable(dhd_pub_t *dhdp); -int dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); -int dhd_wlfc_clear_counts(dhd_pub_t *dhd); -int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val); -int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val); -bool dhd_wlfc_is_supported(dhd_pub_t *dhd); -bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf); -int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock); -int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio); - -int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val); -int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val); -int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val); - -int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val); -#endif /* __wlfc_host_driver_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd/dngl_stats.h b/drivers/net/wireless/bcmdhd/dngl_stats.h deleted file mode 100644 index 496d86fe4de0..000000000000 --- a/drivers/net/wireless/bcmdhd/dngl_stats.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Common stats definitions for clients of dongle - * ports - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dngl_stats.h 596029 2015-10-29 11:23:38Z $ - */ - -#ifndef _dngl_stats_h_ -#define _dngl_stats_h_ - -typedef struct { - 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 */ -} dngl_stats_t; - -#ifdef LINKSTAT_SUPPORT -typedef int wifi_radio; -typedef int wifi_channel; -typedef int wifi_rssi; - -typedef enum wifi_channel_width { - WIFI_CHAN_WIDTH_20 = 0, - WIFI_CHAN_WIDTH_40 = 1, - WIFI_CHAN_WIDTH_80 = 2, - WIFI_CHAN_WIDTH_160 = 3, - WIFI_CHAN_WIDTH_80P80 = 4, - WIFI_CHAN_WIDTH_5 = 5, - WIFI_CHAN_WIDTH_10 = 6, - WIFI_CHAN_WIDTH_INVALID = -1 -} wifi_channel_width_t; - -typedef enum { - WIFI_DISCONNECTED = 0, - WIFI_AUTHENTICATING = 1, - WIFI_ASSOCIATING = 2, - WIFI_ASSOCIATED = 3, - WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ - WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ -} wifi_connection_state; - -typedef enum { - WIFI_ROAMING_IDLE = 0, - WIFI_ROAMING_ACTIVE = 1 -} wifi_roam_state; - -typedef enum { - WIFI_INTERFACE_STA = 0, - WIFI_INTERFACE_SOFTAP = 1, - WIFI_INTERFACE_IBSS = 2, - WIFI_INTERFACE_P2P_CLIENT = 3, - WIFI_INTERFACE_P2P_GO = 4, - WIFI_INTERFACE_NAN = 5, - WIFI_INTERFACE_MESH = 6 -} wifi_interface_mode; - -/* set for QOS association */ -#define WIFI_CAPABILITY_QOS 0x00000001 -/* set for protected association (802.11 beacon frame control protected bit set) */ -#define WIFI_CAPABILITY_PROTECTED 0x00000002 -/* set if 802.11 Extended Capabilities element interworking bit is set */ -#define WIFI_CAPABILITY_INTERWORKING 0x00000004 -/* set for HS20 association */ -#define WIFI_CAPABILITY_HS20 0x00000008 -/* set is 802.11 Extended Capabilities element UTF-8 SSID bit is set */ -#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 -/* set is 802.11 Country Element is present */ -#define WIFI_CAPABILITY_COUNTRY 0x00000020 - -typedef struct { - wifi_interface_mode mode; /* interface mode */ - u8 mac_addr[6]; /* interface mac address (self) */ - wifi_connection_state state; /* connection state (valid for STA, CLI only) */ - wifi_roam_state roaming; /* roaming state */ - u32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ - u8 ssid[33]; /* null terminated SSID */ - u8 bssid[6]; /* bssid */ - u8 ap_country_str[3]; /* country string advertised by AP */ - u8 country_str[3]; /* country string for this association */ -} wifi_interface_info; - -typedef wifi_interface_info *wifi_interface_handle; - -/* channel information */ -typedef struct { - wifi_channel_width_t width; /* channel width (20, 40, 80, 80+80, 160) */ - wifi_channel center_freq; /* primary 20 MHz channel */ - wifi_channel center_freq0; /* center frequency (MHz) first segment */ - wifi_channel center_freq1; /* center frequency (MHz) second segment */ -} wifi_channel_info; - -/* wifi rate */ -typedef struct { - u32 preamble :3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ - u32 nss :2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ - u32 bw :3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ - u32 rateMcsIdx :8; /* OFDM/CCK rate code would be as per - * ieee std in the units of 0.5mbps - */ - /* HT/VHT it would be mcs index */ - u32 reserved :16; /* reserved */ - u32 bitrate; /* units of 100 Kbps */ -} wifi_rate; - -/* channel statistics */ -typedef struct { - wifi_channel_info channel; /* channel */ - u32 on_time; /* msecs the radio is awake - * (32 bits number accruing over time) - */ - u32 cca_busy_time; /* msecs the CCA register is - * busy (32 bits number accruing over time) - */ -} wifi_channel_stat; - -/* radio statistics */ -typedef struct { - wifi_radio radio; /* wifi radio (if multiple radio supported) */ - /* all msecs in 32 bits number accruing over time */ - u32 on_time; /* msecs the radio is awake */ - u32 tx_time; /* msecs the radio is transmitting */ - u32 rx_time; /* msecs the radio is in active receive */ - u32 on_time_scan; /* msecs the radio is awake due to all scan */ - u32 on_time_nbd; /* msecs the radio is awake due to NAN */ - u32 on_time_gscan; /* msecs the radio is awake due to Gscan */ - u32 on_time_roam_scan; /* msecs the radio is awake due to roam scan */ - u32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan */ - u32 on_time_hs20; /* msecs the radio is awake due to - * HS2.0 scans and GAS exchange - */ - u32 num_channels; /* number of channels */ - wifi_channel_stat channels[]; /* channel statistics */ -} wifi_radio_stat; - -/* per rate statistics */ -typedef struct { - wifi_rate rate; /* rate information */ - u32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ - u32 rx_mpdu; /* number of received data pkts */ - u32 mpdu_lost; /* number of data packet losses (no ACK) */ - u32 retries; /* total number of data pkt retries */ - u32 retries_short; /* number of short data pkt retries */ - u32 retries_long; /* number of long data pkt retries */ -} wifi_rate_stat; - -/* access categories */ -typedef enum { - WIFI_AC_VO = 0, - WIFI_AC_VI = 1, - WIFI_AC_BE = 2, - WIFI_AC_BK = 3, - WIFI_AC_MAX = 4 -} wifi_traffic_ac; - -/* wifi peer type */ -typedef enum -{ - WIFI_PEER_STA, - WIFI_PEER_AP, - WIFI_PEER_P2P_GO, - WIFI_PEER_P2P_CLIENT, - WIFI_PEER_NAN, - WIFI_PEER_TDLS, - WIFI_PEER_INVALID -} wifi_peer_type; - -/* per peer statistics */ -typedef struct { - wifi_peer_type type; /* peer type (AP, TDLS, GO etc.) */ - u8 peer_mac_address[6]; /* mac address */ - u32 capabilities; /* peer WIFI_CAPABILITY_XXX */ - u32 num_rate; /* number of rates */ - wifi_rate_stat rate_stats[]; /* per rate statistics, number of entries = num_rate */ -} wifi_peer_info; - -/* per access category statistics */ -typedef struct { - wifi_traffic_ac ac; /* access category (VI, VO, BE, BK) */ - u32 tx_mpdu; /* number of successfully transmitted - * unicast data pkts (ACK rcvd) - */ - u32 rx_mpdu; /* number of received unicast mpdus */ - u32 tx_mcast; /* number of successfully transmitted - * multicast data packets - */ - /* STA case: implies ACK received from AP - * for the unicast packet in which mcast pkt was sent - */ - u32 rx_mcast; /* number of received multicast data packets */ - u32 rx_ampdu; /* number of received unicast a-mpdus */ - u32 tx_ampdu; /* number of transmitted unicast a-mpdus */ - u32 mpdu_lost; /* number of data pkt losses (no ACK) */ - u32 retries; /* total number of data pkt retries */ - u32 retries_short; /* number of short data pkt retries */ - u32 retries_long; /* number of long data pkt retries */ - u32 contention_time_min; /* data pkt min contention time (usecs) */ - u32 contention_time_max; /* data pkt max contention time (usecs) */ - u32 contention_time_avg; /* data pkt avg contention time (usecs) */ - u32 contention_num_samples; /* num of data pkts used for contention statistics */ -} wifi_wmm_ac_stat; - -/* interface statistics */ -typedef struct { - wifi_interface_handle iface; /* wifi interface */ - wifi_interface_info info; /* current state of the interface */ - u32 beacon_rx; /* access point beacon received count - * from connected AP - */ - u64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT) - * The average_tsf_offset field is used so as to calculate - * the typical beacon contention time on the channel as well - * may be used to debug beacon synchronization and related - * power consumption issue - */ - u32 leaky_ap_detected; /* indicate that this AP typically leaks packets beyond - * the driver guard time. - */ - u32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after - * frame with PM bit set was ACK'ed by AP - */ - u32 leaky_ap_guard_time; /* guard time currently in force (when implementing IEEE - * power management based on frame control PM bit), How long - * driver waits before shutting down the radio and after - * receiving an ACK for a data frame with PM bit set) - */ - u32 mgmt_rx; /* access point mgmt frames received count - * from connected AP (including Beacon) - */ - u32 mgmt_action_rx; /* action frames received count */ - u32 mgmt_action_tx; /* action frames transmit count */ - wifi_rssi rssi_mgmt; /* access Point Beacon and - * Management frames RSSI (averaged) - */ - wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) - * from connected AP - */ - wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) - * from connected AP - */ - wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ - u32 num_peers; /* number of peers */ - wifi_peer_info peer_info[]; /* per peer statistics */ -} wifi_iface_stat; -#endif /* LINKSTAT_SUPPORT */ -#endif /* _dngl_stats_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd/dngl_wlhdr.h deleted file mode 100644 index 6050aec62acf..000000000000 --- a/drivers/net/wireless/bcmdhd/dngl_wlhdr.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Dongle WL Header definitions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dngl_wlhdr.h 464743 2014-03-25 21:04:32Z $ - */ - -#ifndef _dngl_wlhdr_h_ -#define _dngl_wlhdr_h_ - -typedef struct wl_header { - uint8 type; /* Header type */ - uint8 version; /* Header version */ - int8 rssi; /* RSSI */ - uint8 pad; /* Unused */ -} wl_header_t; - -#define WL_HEADER_LEN sizeof(wl_header_t) -#define WL_HEADER_TYPE 0 -#define WL_HEADER_VER 1 -#endif /* _dngl_wlhdr_h_ */ diff --git a/drivers/net/wireless/bcmdhd/hnd_pktpool.c b/drivers/net/wireless/bcmdhd/hnd_pktpool.c deleted file mode 100644 index a1b4b16a4cde..000000000000 --- a/drivers/net/wireless/bcmdhd/hnd_pktpool.c +++ /dev/null @@ -1,751 +0,0 @@ -/* - * HND generic packet pool operation primitives - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: $ - */ - -#include -#include -#include -#include - -/* Registry size is one larger than max pools, as slot #0 is reserved */ -#define PKTPOOLREG_RSVD_ID (0U) -#define PKTPOOLREG_RSVD_PTR (POOLPTR(0xdeaddead)) -#define PKTPOOLREG_FREE_PTR (POOLPTR(NULL)) - -#define PKTPOOL_REGISTRY_SET(id, pp) (pktpool_registry_set((id), (pp))) -#define PKTPOOL_REGISTRY_CMP(id, pp) (pktpool_registry_cmp((id), (pp))) - -/* Tag a registry entry as free for use */ -#define PKTPOOL_REGISTRY_CLR(id) \ - PKTPOOL_REGISTRY_SET((id), PKTPOOLREG_FREE_PTR) -#define PKTPOOL_REGISTRY_ISCLR(id) \ - (PKTPOOL_REGISTRY_CMP((id), PKTPOOLREG_FREE_PTR)) - -/* Tag registry entry 0 as reserved */ -#define PKTPOOL_REGISTRY_RSV() \ - PKTPOOL_REGISTRY_SET(PKTPOOLREG_RSVD_ID, PKTPOOLREG_RSVD_PTR) -#define PKTPOOL_REGISTRY_ISRSVD() \ - (PKTPOOL_REGISTRY_CMP(PKTPOOLREG_RSVD_ID, PKTPOOLREG_RSVD_PTR)) - -/* Walk all un-reserved entries in registry */ -#define PKTPOOL_REGISTRY_FOREACH(id) \ - for ((id) = 1U; (id) <= pktpools_max; (id)++) - -uint32 pktpools_max = 0U; /* maximum number of pools that may be initialized */ -pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; /* Pktpool registry */ - -/* Register/Deregister a pktpool with registry during pktpool_init/deinit */ -static int pktpool_register(pktpool_t * poolptr); -static int pktpool_deregister(pktpool_t * poolptr); - -/** accessor functions required when ROMming this file, forced into RAM */ -static void -BCMRAMFN(pktpool_registry_set)(int id, pktpool_t *pp) -{ - pktpools_registry[id] = pp; -} - -static bool -BCMRAMFN(pktpool_registry_cmp)(int id, pktpool_t *pp) -{ - return pktpools_registry[id] == pp; -} - -int /* Construct a pool registry to serve a maximum of total_pools */ -pktpool_attach(osl_t *osh, uint32 total_pools) -{ - uint32 poolid; - - if (pktpools_max != 0U) { - return BCME_ERROR; - } - - ASSERT(total_pools <= PKTPOOL_MAXIMUM_ID); - - /* Initialize registry: reserve slot#0 and tag others as free */ - PKTPOOL_REGISTRY_RSV(); /* reserve slot#0 */ - - PKTPOOL_REGISTRY_FOREACH(poolid) { /* tag all unreserved entries as free */ - PKTPOOL_REGISTRY_CLR(poolid); - } - - pktpools_max = total_pools; - - return (int)pktpools_max; -} - -int /* Destruct the pool registry. Ascertain all pools were first de-inited */ -pktpool_dettach(osl_t *osh) -{ - uint32 poolid; - - if (pktpools_max == 0U) { - return BCME_OK; - } - - /* Ascertain that no pools are still registered */ - ASSERT(PKTPOOL_REGISTRY_ISRSVD()); /* assert reserved slot */ - - PKTPOOL_REGISTRY_FOREACH(poolid) { /* ascertain all others are free */ - ASSERT(PKTPOOL_REGISTRY_ISCLR(poolid)); - } - - pktpools_max = 0U; /* restore boot state */ - - return BCME_OK; -} - -static int /* Register a pool in a free slot; return the registry slot index */ -pktpool_register(pktpool_t * poolptr) -{ - uint32 poolid; - - if (pktpools_max == 0U) { - return PKTPOOL_INVALID_ID; /* registry has not yet been constructed */ - } - - ASSERT(pktpools_max != 0U); - - /* find an empty slot in pktpools_registry */ - PKTPOOL_REGISTRY_FOREACH(poolid) { - if (PKTPOOL_REGISTRY_ISCLR(poolid)) { - PKTPOOL_REGISTRY_SET(poolid, POOLPTR(poolptr)); /* register pool */ - return (int)poolid; /* return pool ID */ - } - } /* FOREACH */ - - return PKTPOOL_INVALID_ID; /* error: registry is full */ -} - -static int /* Deregister a pktpool, given the pool pointer; tag slot as free */ -pktpool_deregister(pktpool_t * poolptr) -{ - uint32 poolid; - - ASSERT(POOLPTR(poolptr) != POOLPTR(NULL)); - - poolid = POOLID(poolptr); - ASSERT(poolid <= pktpools_max); - - /* Asertain that a previously registered poolptr is being de-registered */ - if (PKTPOOL_REGISTRY_CMP(poolid, POOLPTR(poolptr))) { - PKTPOOL_REGISTRY_CLR(poolid); /* mark as free */ - } else { - ASSERT(0); - return BCME_ERROR; /* mismatch in registry */ - } - - return BCME_OK; -} - - -/* - * pktpool_init: - * User provides a pktpool_t sturcture and specifies the number of packets to - * be pre-filled into the pool (pplen). The size of all packets in a pool must - * be the same and is specified by plen. - * pktpool_init first attempts to register the pool and fetch a unique poolid. - * If registration fails, it is considered an BCME_ERR, caused by either the - * registry was not pre-created (pktpool_attach) or the registry is full. - * If registration succeeds, then the requested number of packets will be filled - * into the pool as part of initialization. In the event that there is no - * available memory to service the request, then BCME_NOMEM will be returned - * along with the count of how many packets were successfully allocated. - * In dongle builds, prior to memory reclaimation, one should limit the number - * of packets to be allocated during pktpool_init and fill the pool up after - * reclaim stage. - */ -int -pktpool_init(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx, uint8 type) -{ - int i, err = BCME_OK; - int pktplen; - uint8 pktp_id; - - ASSERT(pktp != NULL); - ASSERT(osh != NULL); - ASSERT(pplen != NULL); - - pktplen = *pplen; - - bzero(pktp, sizeof(pktpool_t)); - - /* assign a unique pktpool id */ - if ((pktp_id = (uint8) pktpool_register(pktp)) == PKTPOOL_INVALID_ID) { - return BCME_ERROR; - } - POOLSETID(pktp, pktp_id); - - pktp->inited = TRUE; - pktp->istx = istx ? TRUE : FALSE; - pktp->plen = (uint16)plen; - pktp->type = type; - - pktp->maxlen = PKTPOOL_LEN_MAX; - pktplen = LIMIT_TO_MAX(pktplen, pktp->maxlen); - - for (i = 0; i < pktplen; i++) { - void *p; - p = PKTGET(osh, plen, TRUE); - - if (p == NULL) { - /* Not able to allocate all requested pkts - * so just return what was actually allocated - * We can add to the pool later - */ - if (pktp->freelist == NULL) /* pktpool free list is empty */ - err = BCME_NOMEM; - - goto exit; - } - - PKTSETPOOL(osh, p, TRUE, pktp); /* Tag packet with pool ID */ - - PKTSETFREELIST(p, pktp->freelist); /* insert p at head of free list */ - pktp->freelist = p; - - pktp->avail++; - -#ifdef BCMDBG_POOL - pktp->dbg_q[pktp->dbg_qlen++].p = p; -#endif - } - -exit: - pktp->len = pktp->avail; - - *pplen = pktp->len; - return err; -} - -/* - * pktpool_deinit: - * Prior to freeing a pktpool, all packets must be first freed into the pktpool. - * Upon pktpool_deinit, all packets in the free pool will be freed to the heap. - * An assert is in place to ensure that there are no packets still lingering - * around. Packets freed to a pool after the deinit will cause a memory - * corruption as the pktpool_t structure no longer exists. - */ -int -pktpool_deinit(osl_t *osh, pktpool_t *pktp) -{ - uint16 freed = 0; - - ASSERT(osh != NULL); - ASSERT(pktp != NULL); - -#ifdef BCMDBG_POOL - { - int i; - for (i = 0; i <= pktp->len; i++) { - pktp->dbg_q[i].p = NULL; - } - } -#endif - - while (pktp->freelist != NULL) { - void * p = pktp->freelist; - - pktp->freelist = PKTFREELIST(p); /* unlink head packet from free list */ - PKTSETFREELIST(p, NULL); - - PKTSETPOOL(osh, p, FALSE, NULL); /* clear pool ID tag in pkt */ - - PKTFREE(osh, p, pktp->istx); /* free the packet */ - - freed++; - ASSERT(freed <= pktp->len); - } - - pktp->avail -= freed; - ASSERT(pktp->avail == 0); - - pktp->len -= freed; - - pktpool_deregister(pktp); /* release previously acquired unique pool id */ - POOLSETID(pktp, PKTPOOL_INVALID_ID); - - pktp->inited = FALSE; - - /* Are there still pending pkts? */ - ASSERT(pktp->len == 0); - - return 0; -} - -int -pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal) -{ - void *p; - int err = 0; - int len, psize, maxlen; - - ASSERT(pktp->plen != 0); - - maxlen = pktp->maxlen; - psize = minimal ? (maxlen >> 2) : maxlen; - for (len = (int)pktp->len; len < psize; len++) { - - p = PKTGET(osh, pktp->len, TRUE); - - if (p == NULL) { - err = BCME_NOMEM; - break; - } - - if (pktpool_add(pktp, p) != BCME_OK) { - PKTFREE(osh, p, FALSE); - err = BCME_ERROR; - break; - } - } - - return err; -} - -static void * -pktpool_deq(pktpool_t *pktp) -{ - void *p; - - if (pktp->avail == 0) - return NULL; - - ASSERT(pktp->freelist != NULL); - - p = pktp->freelist; /* dequeue packet from head of pktpool free list */ - pktp->freelist = PKTFREELIST(p); /* free list points to next packet */ - PKTSETFREELIST(p, NULL); - - pktp->avail--; - - return p; -} - -static void -pktpool_enq(pktpool_t *pktp, void *p) -{ - ASSERT(p != NULL); - - PKTSETFREELIST(p, pktp->freelist); /* insert at head of pktpool free list */ - pktp->freelist = p; /* free list points to newly inserted packet */ - - pktp->avail++; - ASSERT(pktp->avail <= pktp->len); -} - -/* utility for registering host addr fill function called from pciedev */ -int -/* BCMATTACHFN */ -(pktpool_hostaddr_fill_register)(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) -{ - - ASSERT(cb != NULL); - - ASSERT(pktp->cbext.cb == NULL); - pktp->cbext.cb = cb; - pktp->cbext.arg = arg; - return 0; -} - -int -pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) -{ - - ASSERT(cb != NULL); - - ASSERT(pktp->rxcplidfn.cb == NULL); - pktp->rxcplidfn.cb = cb; - pktp->rxcplidfn.arg = arg; - return 0; -} -/* Callback functions for split rx modes */ -/* when evr host posts rxbuffer, invike dma_rxfill from pciedev layer */ -void -pktpool_invoke_dmarxfill(pktpool_t *pktp) -{ - ASSERT(pktp->dmarxfill.cb); - ASSERT(pktp->dmarxfill.arg); - - if (pktp->dmarxfill.cb) - pktp->dmarxfill.cb(pktp, pktp->dmarxfill.arg); -} -int -pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg) -{ - - ASSERT(cb != NULL); - - pktp->dmarxfill.cb = cb; - pktp->dmarxfill.arg = arg; - - return 0; -} -/* No BCMATTACHFN as it is used in xdc_enable_ep which is not an attach function */ -int -pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) -{ - int i; - - ASSERT(cb != NULL); - - i = pktp->cbcnt; - if (i == PKTPOOL_CB_MAX) - return BCME_ERROR; - - ASSERT(pktp->cbs[i].cb == NULL); - pktp->cbs[i].cb = cb; - pktp->cbs[i].arg = arg; - pktp->cbcnt++; - - return 0; -} - -int -pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) -{ - int i; - - ASSERT(cb != NULL); - - i = pktp->ecbcnt; - if (i == PKTPOOL_CB_MAX) - return BCME_ERROR; - - ASSERT(pktp->ecbs[i].cb == NULL); - pktp->ecbs[i].cb = cb; - pktp->ecbs[i].arg = arg; - pktp->ecbcnt++; - - return 0; -} - -static int -pktpool_empty_notify(pktpool_t *pktp) -{ - int i; - - pktp->empty = TRUE; - for (i = 0; i < pktp->ecbcnt; i++) { - ASSERT(pktp->ecbs[i].cb != NULL); - pktp->ecbs[i].cb(pktp, pktp->ecbs[i].arg); - } - pktp->empty = FALSE; - - return 0; -} - -#ifdef BCMDBG_POOL -int -pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) -{ - int i; - - ASSERT(cb); - - i = pktp->dbg_cbcnt; - if (i == PKTPOOL_CB_MAX) - return BCME_ERROR; - - ASSERT(pktp->dbg_cbs[i].cb == NULL); - pktp->dbg_cbs[i].cb = cb; - pktp->dbg_cbs[i].arg = arg; - pktp->dbg_cbcnt++; - - return 0; -} - -int pktpool_dbg_notify(pktpool_t *pktp); - -int -pktpool_dbg_notify(pktpool_t *pktp) -{ - int i; - - for (i = 0; i < pktp->dbg_cbcnt; i++) { - ASSERT(pktp->dbg_cbs[i].cb); - pktp->dbg_cbs[i].cb(pktp, pktp->dbg_cbs[i].arg); - } - - return 0; -} - -int -pktpool_dbg_dump(pktpool_t *pktp) -{ - int i; - - printf("pool len=%d maxlen=%d\n", pktp->dbg_qlen, pktp->maxlen); - for (i = 0; i < pktp->dbg_qlen; i++) { - ASSERT(pktp->dbg_q[i].p); - printf("%d, p: 0x%x dur:%lu us state:%d\n", i, - pktp->dbg_q[i].p, pktp->dbg_q[i].dur/100, PKTPOOLSTATE(pktp->dbg_q[i].p)); - } - - return 0; -} - -int -pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats) -{ - int i; - int state; - - bzero(stats, sizeof(pktpool_stats_t)); - for (i = 0; i < pktp->dbg_qlen; i++) { - ASSERT(pktp->dbg_q[i].p != NULL); - - state = PKTPOOLSTATE(pktp->dbg_q[i].p); - switch (state) { - case POOL_TXENQ: - stats->enq++; break; - case POOL_TXDH: - stats->txdh++; break; - case POOL_TXD11: - stats->txd11++; break; - case POOL_RXDH: - stats->rxdh++; break; - case POOL_RXD11: - stats->rxd11++; break; - case POOL_RXFILL: - stats->rxfill++; break; - case POOL_IDLE: - stats->idle++; break; - } - } - - return 0; -} - -int -pktpool_start_trigger(pktpool_t *pktp, void *p) -{ - uint32 cycles, i; - - if (!PKTPOOL(OSH_NULL, p)) - return 0; - - OSL_GETCYCLES(cycles); - - for (i = 0; i < pktp->dbg_qlen; i++) { - ASSERT(pktp->dbg_q[i].p != NULL); - - if (pktp->dbg_q[i].p == p) { - pktp->dbg_q[i].cycles = cycles; - break; - } - } - - return 0; -} - -int pktpool_stop_trigger(pktpool_t *pktp, void *p); -int -pktpool_stop_trigger(pktpool_t *pktp, void *p) -{ - uint32 cycles, i; - - if (!PKTPOOL(OSH_NULL, p)) - return 0; - - OSL_GETCYCLES(cycles); - - for (i = 0; i < pktp->dbg_qlen; i++) { - ASSERT(pktp->dbg_q[i].p != NULL); - - if (pktp->dbg_q[i].p == p) { - if (pktp->dbg_q[i].cycles == 0) - break; - - if (cycles >= pktp->dbg_q[i].cycles) - pktp->dbg_q[i].dur = cycles - pktp->dbg_q[i].cycles; - else - pktp->dbg_q[i].dur = - (((uint32)-1) - pktp->dbg_q[i].cycles) + cycles + 1; - - pktp->dbg_q[i].cycles = 0; - break; - } - } - - return 0; -} -#endif /* BCMDBG_POOL */ - -int -pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp) -{ - ASSERT(pktp); - pktp->availcb_excl = NULL; - return 0; -} - -int -pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb) -{ - int i; - - ASSERT(pktp); - ASSERT(pktp->availcb_excl == NULL); - for (i = 0; i < pktp->cbcnt; i++) { - if (cb == pktp->cbs[i].cb) { - pktp->availcb_excl = &pktp->cbs[i]; - break; - } - } - - if (pktp->availcb_excl == NULL) - return BCME_ERROR; - else - return 0; -} - -static int -pktpool_avail_notify(pktpool_t *pktp) -{ - int i, k, idx; - int avail; - - ASSERT(pktp); - if (pktp->availcb_excl != NULL) { - pktp->availcb_excl->cb(pktp, pktp->availcb_excl->arg); - return 0; - } - - k = pktp->cbcnt - 1; - for (i = 0; i < pktp->cbcnt; i++) { - avail = pktp->avail; - - if (avail) { - if (pktp->cbtoggle) - idx = i; - else - idx = k--; - - ASSERT(pktp->cbs[idx].cb != NULL); - pktp->cbs[idx].cb(pktp, pktp->cbs[idx].arg); - } - } - - /* Alternate between filling from head or tail - */ - pktp->cbtoggle ^= 1; - - return 0; -} - -void * -pktpool_get(pktpool_t *pktp) -{ - void *p; - - p = pktpool_deq(pktp); - - if (p == NULL) { - /* Notify and try to reclaim tx pkts */ - if (pktp->ecbcnt) - pktpool_empty_notify(pktp); - - p = pktpool_deq(pktp); - if (p == NULL) - return NULL; - } - - return p; -} - -void -pktpool_free(pktpool_t *pktp, void *p) -{ - ASSERT(p != NULL); -#ifdef BCMDBG_POOL - /* pktpool_stop_trigger(pktp, p); */ -#endif - - pktpool_enq(pktp, p); - - if (pktp->emptycb_disable) - return; - - if (pktp->cbcnt) { - if (pktp->empty == FALSE) - pktpool_avail_notify(pktp); - } -} - -int -pktpool_add(pktpool_t *pktp, void *p) -{ - ASSERT(p != NULL); - - if (pktp->len == pktp->maxlen) - return BCME_RANGE; - - /* pkts in pool have same length */ - ASSERT(pktp->plen == PKTLEN(OSH_NULL, p)); - PKTSETPOOL(OSH_NULL, p, TRUE, pktp); - - pktp->len++; - pktpool_enq(pktp, p); - -#ifdef BCMDBG_POOL - pktp->dbg_q[pktp->dbg_qlen++].p = p; -#endif - - return 0; -} - -/* Force pktpool_setmaxlen () into RAM as it uses a constant - * (PKTPOOL_LEN_MAX) that may be changed post tapeout for ROM-based chips. - */ -int -BCMRAMFN(pktpool_setmaxlen)(pktpool_t *pktp, uint16 maxlen) -{ - if (maxlen > PKTPOOL_LEN_MAX) - maxlen = PKTPOOL_LEN_MAX; - - /* if pool is already beyond maxlen, then just cap it - * since we currently do not reduce the pool len - * already allocated - */ - pktp->maxlen = (pktp->len > maxlen) ? pktp->len : maxlen; - - return pktp->maxlen; -} - -void -pktpool_emptycb_disable(pktpool_t *pktp, bool disable) -{ - ASSERT(pktp); - - pktp->emptycb_disable = disable; -} - -bool -pktpool_emptycb_disabled(pktpool_t *pktp) -{ - ASSERT(pktp); - return pktp->emptycb_disable; -} diff --git a/drivers/net/wireless/bcmdhd/hnd_pktq.c b/drivers/net/wireless/bcmdhd/hnd_pktq.c deleted file mode 100644 index e4ce75b1363e..000000000000 --- a/drivers/net/wireless/bcmdhd/hnd_pktq.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * HND generic pktq operation primitives - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: $ - */ - -#include -#include -#include -#include - -/* - * osl multiple-precedence packet queue - * hi_prec is always >= the number of the highest non-empty precedence - */ -void * BCMFASTPATH -pktq_penq(struct pktq *pq, int prec, void *p) -{ - struct pktq_prec *q; - - ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ - - ASSERT(!pktq_full(pq)); - ASSERT(!pktq_pfull(pq, prec)); - - q = &pq->q[prec]; - - if (q->head) - PKTSETLINK(q->tail, p); - else - q->head = p; - - q->tail = p; - q->len++; - - pq->len++; - - if (pq->hi_prec < prec) - pq->hi_prec = (uint8)prec; - - return p; -} - -void * BCMFASTPATH -pktq_penq_head(struct pktq *pq, int prec, void *p) -{ - struct pktq_prec *q; - - ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ - - ASSERT(!pktq_full(pq)); - ASSERT(!pktq_pfull(pq, prec)); - - q = &pq->q[prec]; - - if (q->head == NULL) - q->tail = p; - - PKTSETLINK(p, q->head); - q->head = p; - q->len++; - - pq->len++; - - if (pq->hi_prec < prec) - pq->hi_prec = (uint8)prec; - - return p; -} - -/* - * Append spktq 'list' to the tail of pktq 'pq' - */ -void BCMFASTPATH -pktq_append(struct pktq *pq, int prec, struct spktq *list) -{ - struct pktq_prec *q; - struct pktq_prec *list_q; - - list_q = &list->q[0]; - - /* empty list check */ - if (list_q->head == NULL) - return; - - ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(list_q->tail) == NULL); /* terminated list */ - - ASSERT(!pktq_full(pq)); - ASSERT(!pktq_pfull(pq, prec)); - - q = &pq->q[prec]; - - if (q->head) - PKTSETLINK(q->tail, list_q->head); - else - q->head = list_q->head; - - q->tail = list_q->tail; - q->len += list_q->len; - pq->len += list_q->len; - - if (pq->hi_prec < prec) - pq->hi_prec = (uint8)prec; - - list_q->head = NULL; - list_q->tail = NULL; - list_q->len = 0; - list->len = 0; -} - -/* - * Prepend spktq 'list' to the head of pktq 'pq' - */ -void BCMFASTPATH -pktq_prepend(struct pktq *pq, int prec, struct spktq *list) -{ - struct pktq_prec *q; - struct pktq_prec *list_q; - - list_q = &list->q[0]; - - /* empty list check */ - if (list_q->head == NULL) - return; - - ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(list_q->tail) == NULL); /* terminated list */ - - ASSERT(!pktq_full(pq)); - ASSERT(!pktq_pfull(pq, prec)); - - q = &pq->q[prec]; - - /* set the tail packet of list to point at the former pq head */ - PKTSETLINK(list_q->tail, q->head); - /* the new q head is the head of list */ - q->head = list_q->head; - - /* If the q tail was non-null, then it stays as is. - * If the q tail was null, it is now the tail of list - */ - if (q->tail == NULL) { - q->tail = list_q->tail; - } - - q->len += list_q->len; - pq->len += list_q->len; - - if (pq->hi_prec < prec) - pq->hi_prec = (uint8)prec; - - list_q->head = NULL; - list_q->tail = NULL; - list_q->len = 0; - list->len = 0; -} - -void * BCMFASTPATH -pktq_pdeq(struct pktq *pq, int prec) -{ - struct pktq_prec *q; - void *p; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - if ((q->head = PKTLINK(p)) == NULL) - q->tail = NULL; - - q->len--; - - pq->len--; - - PKTSETLINK(p, NULL); - - return p; -} - -void * BCMFASTPATH -pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) -{ - struct pktq_prec *q; - void *p; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - - if (prev_p == NULL) - return NULL; - - if ((p = PKTLINK(prev_p)) == NULL) - return NULL; - - q->len--; - - pq->len--; - - PKTSETLINK(prev_p, PKTLINK(p)); - PKTSETLINK(p, NULL); - - return p; -} - -void * BCMFASTPATH -pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg) -{ - struct pktq_prec *q; - void *p, *prev = NULL; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - p = q->head; - - while (p) { - if (fn == NULL || (*fn)(p, arg)) { - break; - } else { - prev = p; - p = PKTLINK(p); - } - } - if (p == NULL) - return NULL; - - if (prev == NULL) { - if ((q->head = PKTLINK(p)) == NULL) { - q->tail = NULL; - } - } else { - PKTSETLINK(prev, PKTLINK(p)); - if (q->tail == p) { - q->tail = prev; - } - } - - q->len--; - - pq->len--; - - PKTSETLINK(p, NULL); - - return p; -} - -void * BCMFASTPATH -pktq_pdeq_tail(struct pktq *pq, int prec) -{ - struct pktq_prec *q; - void *p, *prev; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - for (prev = NULL; p != q->tail; p = PKTLINK(p)) - prev = p; - - if (prev) - PKTSETLINK(prev, NULL); - else - q->head = NULL; - - q->tail = prev; - q->len--; - - pq->len--; - - return p; -} - -void -pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) -{ - struct pktq_prec *q; - void *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 = PKTLINK(p); - else - PKTSETLINK(prev, PKTLINK(p)); - PKTSETLINK(p, NULL); - PKTFREE(osh, p, dir); - q->len--; - pq->len--; - p = (head ? q->head : PKTLINK(prev)); - } else { - prev = p; - p = PKTLINK(p); - } - } - - if (q->head == NULL) { - ASSERT(q->len == 0); - q->tail = NULL; - } -} - -bool BCMFASTPATH -pktq_pdel(struct pktq *pq, void *pktbuf, int prec) -{ - struct pktq_prec *q; - void *p; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - /* Should this just assert pktbuf? */ - if (!pktbuf) - return FALSE; - - q = &pq->q[prec]; - - if (q->head == pktbuf) { - if ((q->head = PKTLINK(pktbuf)) == NULL) - q->tail = NULL; - } else { - for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) - ; - if (p == NULL) - return FALSE; - - PKTSETLINK(p, PKTLINK(pktbuf)); - if (q->tail == pktbuf) - q->tail = p; - } - - q->len--; - pq->len--; - PKTSETLINK(pktbuf, NULL); - return TRUE; -} - -void -pktq_init(struct pktq *pq, int num_prec, int max_len) -{ - int prec; - - ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); - - /* pq is variable size; only zero out what's requested */ - bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); - - pq->num_prec = (uint16)num_prec; - - pq->max = (uint16)max_len; - - for (prec = 0; prec < num_prec; prec++) - pq->q[prec].max = pq->max; -} - -void -pktq_set_max_plen(struct pktq *pq, int prec, int max_len) -{ - ASSERT(prec >= 0 && prec < pq->num_prec); - - if (prec < pq->num_prec) - pq->q[prec].max = (uint16)max_len; -} - -void * BCMFASTPATH -pktq_deq(struct pktq *pq, int *prec_out) -{ - struct pktq_prec *q; - void *p; - int prec; - - if (pq->len == 0) - return NULL; - - while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) - pq->hi_prec--; - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - if ((q->head = PKTLINK(p)) == NULL) - q->tail = NULL; - - q->len--; - - pq->len--; - - if (prec_out) - *prec_out = prec; - - PKTSETLINK(p, NULL); - - return p; -} - -void * BCMFASTPATH -pktq_deq_tail(struct pktq *pq, int *prec_out) -{ - struct pktq_prec *q; - void *p, *prev; - int prec; - - if (pq->len == 0) - return NULL; - - for (prec = 0; prec < pq->hi_prec; prec++) - if (pq->q[prec].head) - break; - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - for (prev = NULL; p != q->tail; p = PKTLINK(p)) - prev = p; - - if (prev) - PKTSETLINK(prev, NULL); - else - q->head = NULL; - - q->tail = prev; - q->len--; - - pq->len--; - - if (prec_out) - *prec_out = prec; - - PKTSETLINK(p, NULL); - - return p; -} - -void * -pktq_peek(struct pktq *pq, int *prec_out) -{ - int prec; - - if (pq->len == 0) - return NULL; - - while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) - pq->hi_prec--; - - if (prec_out) - *prec_out = prec; - - return (pq->q[prec].head); -} - -void * -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); -} - -void -pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) -{ - int prec; - - /* Optimize flush, if pktq len = 0, just return. - * pktq len of 0 means pktq's prec q's are all empty. - */ - if (pq->len == 0) { - return; - } - - for (prec = 0; prec < pq->num_prec; prec++) - pktq_pflush(osh, pq, prec, dir, fn, arg); - if (fn == NULL) - ASSERT(pq->len == 0); -} - -/* Return sum of lengths of a specific set of precedences */ -int -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; -} - -/* Priority peek from a specific set of precedences */ -void * BCMFASTPATH -pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) -{ - struct pktq_prec *q; - void *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]; - - if ((p = q->head) == NULL) - return NULL; - - if (prec_out) - *prec_out = prec; - - return p; -} -/* Priority dequeue from a specific set of precedences */ -void * BCMFASTPATH -pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) -{ - struct pktq_prec *q; - void *p; - int prec; - - if (pq->len == 0) - return NULL; - - while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) - pq->hi_prec--; - - while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) - if (prec-- == 0) - return NULL; - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - if ((q->head = PKTLINK(p)) == NULL) - q->tail = NULL; - - q->len--; - - if (prec_out) - *prec_out = prec; - - pq->len--; - - PKTSETLINK(p, NULL); - - return p; -} diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c deleted file mode 100644 index 95656347d148..000000000000 --- a/drivers/net/wireless/bcmdhd/hndpmu.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Misc utility routines for accessing PMU corerev specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hndpmu.c 475037 2014-05-02 23:55:49Z $ - */ - - -/* - * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs. - * However, in the context of this file the baseband ('BB') PLL/FLL is referred to. - * - * Throughout this code, the prefixes 'pmu0_', 'pmu1_' and 'pmu2_' are used. - * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012) - * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports - * fractional frequency generation. pmu2_ does not support fractional frequency generation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PMU_ERROR(args) - -#define PMU_MSG(args) - -/* To check in verbose debugging messages not intended - * to be on except on private builds. - */ -#define PMU_NONE(args) - -/** contains resource bit positions for a specific chip */ -struct rsc_per_chip_s { - uint8 ht_avail; - uint8 macphy_clkavail; - uint8 ht_start; - uint8 otp_pu; -}; - -typedef struct rsc_per_chip_s rsc_per_chip_t; - - -/* SDIO Pad drive strength to select value mappings. - * The last strength value in each table must be 0 (the tri-state value). - */ -typedef struct { - uint8 strength; /* Pad Drive Strength in mA */ - uint8 sel; /* Chip-specific select value */ -} sdiod_drive_str_t; - -/* SDIO Drive Strength to sel value table for PMU Rev 1 */ -static const sdiod_drive_str_t 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 sdiod_drive_str_t 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 sdiod_drive_str_t sdiod_drive_strength_tab3[] = { - {32, 0x7}, - {26, 0x6}, - {22, 0x5}, - {16, 0x4}, - {12, 0x3}, - {8, 0x2}, - {4, 0x1}, - {0, 0x0} }; - -/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { - {32, 0x6}, - {26, 0x7}, - {22, 0x4}, - {16, 0x5}, - {12, 0x2}, - {8, 0x3}, - {4, 0x0}, - {0, 0x1} }; - -/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ - -/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ - -/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { - {6, 0x7}, - {5, 0x6}, - {4, 0x5}, - {3, 0x4}, - {2, 0x2}, - {1, 0x1}, - {0, 0x0} }; - -/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ - -/** SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { - {3, 0x3}, - {2, 0x2}, - {1, 0x1}, - {0, 0x0} }; - - -/** - * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel - * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture - * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has - * been written '1'. - */ -#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 - -static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = { - /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */ - {16, 0x7}, - {12, 0x5}, - {8, 0x3}, - {4, 0x1} }; /* note: 43143 does not support tristate */ - -#else - -static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = { - /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */ - {8, 0x7}, - {6, 0x5}, - {4, 0x3}, - {2, 0x1} }; /* note: 43143 does not support tristate */ - -#endif /* BCM_SDIO_VDDIO */ - -#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) - -/** - * Balance between stable SDIO operation and power consumption is achieved using this function. - * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this - * function should read the VDDIO itself to select the correct table. For now it has been solved - * with the 'BCM_SDIO_VDDIO' preprocessor constant. - * - * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if - * hardware supports this), if no hw support drive strength is not programmed. - */ -void -si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) -{ - sdiod_drive_str_t *str_tab = NULL; - uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */ - uint32 str_shift = 0; - uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */ - uint32 str_ovr_pmuval = 0; /* position of bit within this register */ - - if (!(sih->cccaps & CC_CAP_PMU)) { - return; - } - - switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): - str_tab = (sdiod_drive_str_t *)&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): - case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): - if (sih->pmurev == 8) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; - } - else if (sih->pmurev == 11) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; - } - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; - str_mask = 0x00001800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): -#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 - if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; - } -#else - if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; - } -#endif /* BCM_SDIO_VDDIO */ - str_mask = 0x00000007; - str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; - break; - default: - PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", - bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); - break; - } - - if (str_tab != NULL) { - uint32 cc_data_temp; - int i; - - /* Pick the lowest available drive strength equal or greater than the - * requested strength. Drive strength of 0 requests tri-state. - */ - for (i = 0; drivestrength < str_tab[i].strength; i++) - ; - - if (i > 0 && drivestrength > str_tab[i].strength) - i--; - - W_REG(osh, PMUREG(sih, chipcontrol_addr), PMU_CHIPCTL1); - cc_data_temp = R_REG(osh, PMUREG(sih, chipcontrol_data)); - cc_data_temp &= ~str_mask; - cc_data_temp |= str_tab[i].sel << str_shift; - W_REG(osh, PMUREG(sih, chipcontrol_data), cc_data_temp); - if (str_ovr_pmuval) { /* enables the selected drive strength */ - W_REG(osh, PMUREG(sih, chipcontrol_addr), str_ovr_pmuctl); - OR_REG(osh, PMUREG(sih, chipcontrol_data), str_ovr_pmuval); - } - PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", - drivestrength, str_tab[i].strength)); - } -} /* si_sdiod_drive_strength_init */ diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd/include/Makefile deleted file mode 100644 index 40224e8dc232..000000000000 --- a/drivers/net/wireless/bcmdhd/include/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 1999-2017, Broadcom Corporation -# -# Unless you and Broadcom execute a separate written software license -# agreement governing use of this software, this software is licensed to you -# under the terms of the GNU General Public License version 2 (the "GPL"), -# available at http://www.broadcom.com/licenses/GPLv2.php, with the -# following added to such license: -# -# As a special exception, the copyright holders of this software give you -# permission to link this software with independent modules, and to copy and -# distribute the resulting executable under terms of your choice, provided that -# you also meet, for each linked independent module, the terms and conditions of -# the license of that module. An independent module is a module which is not -# derived from this software. The special exception does not apply to any -# modifications of the software. -# -# Notwithstanding the above, under no circumstances may you combine this -# software in any way with any other Broadcom software provided under a license -# other than the GPL, without Broadcom's express prior written consent. -# -# This script serves following purpose: -# -# 1. It generates native version information by querying -# automerger maintained database to see where src/include -# came from -# 2. For select components, as listed in compvers.sh -# it generates component version files -# -# $Id: Makefile 528443 2015-01-22 09:29:18Z $ -# - -export SRCBASE:=.. - -TARGETS := epivers.h - -ifdef VERBOSE -export VERBOSE -endif - -all release: epivers compvers - -# Generate epivers.h for native branch url -epivers: - bash epivers.sh - -# Generate component versions based on component url -compvers: - @if [ -s "compvers.sh" ]; then \ - echo "Generating component versions, if any"; \ - bash compvers.sh; \ - else \ - echo "Skipping component version generation"; \ - fi - -# Generate epivers.h for native branch version -clean_compvers: - @if [ -s "compvers.sh" ]; then \ - echo "bash compvers.sh clean"; \ - bash compvers.sh clean; \ - else \ - echo "Skipping component version clean"; \ - fi - -clean: - rm -f $(TARGETS) *.prev - -clean_all: clean clean_compvers - -.PHONY: all release clean epivers compvers clean_compvers diff --git a/drivers/net/wireless/bcmdhd/include/aidmp.h b/drivers/net/wireless/bcmdhd/include/aidmp.h deleted file mode 100644 index 8314d110e2e6..000000000000 --- a/drivers/net/wireless/bcmdhd/include/aidmp.h +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Broadcom AMBA Interconnect definitions. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: aidmp.h 511882 2014-10-31 06:08:29Z $ - */ - -#ifndef _AIDMP_H -#define _AIDMP_H - -/* Manufacturer Ids */ -#define MFGID_ARM 0x43b -#define MFGID_BRCM 0x4bf -#define MFGID_MIPS 0x4a7 - -/* Component Classes */ -#define CC_SIM 0 -#define CC_EROM 1 -#define CC_CORESIGHT 9 -#define CC_VERIF 0xb -#define CC_OPTIMO 0xd -#define CC_GEN 0xe -#define CC_PRIMECELL 0xf - -/* 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 -#define ER_SZ_MAX 4096 /* 4KB */ - -/* 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 MasterPortDesc */ -#define MPD_MUI_MASK 0x0000ff00 -#define MPD_MUI_SHIFT 8 -#define MPD_MP_MASK 0x000000f0 -#define MPD_MP_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 - - -#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) - -typedef volatile struct _aidmp { - uint32 oobselina30; /* 0x000 */ - uint32 oobselina74; /* 0x004 */ - uint32 PAD[6]; - uint32 oobselinb30; /* 0x020 */ - uint32 oobselinb74; /* 0x024 */ - uint32 PAD[6]; - uint32 oobselinc30; /* 0x040 */ - uint32 oobselinc74; /* 0x044 */ - uint32 PAD[6]; - uint32 oobselind30; /* 0x060 */ - uint32 oobselind74; /* 0x064 */ - uint32 PAD[38]; - uint32 oobselouta30; /* 0x100 */ - uint32 oobselouta74; /* 0x104 */ - uint32 PAD[6]; - uint32 oobseloutb30; /* 0x120 */ - uint32 oobseloutb74; /* 0x124 */ - uint32 PAD[6]; - uint32 oobseloutc30; /* 0x140 */ - uint32 oobseloutc74; /* 0x144 */ - uint32 PAD[6]; - uint32 oobseloutd30; /* 0x160 */ - uint32 oobseloutd74; /* 0x164 */ - uint32 PAD[38]; - uint32 oobsynca; /* 0x200 */ - uint32 oobseloutaen; /* 0x204 */ - uint32 PAD[6]; - uint32 oobsyncb; /* 0x220 */ - uint32 oobseloutben; /* 0x224 */ - uint32 PAD[6]; - uint32 oobsyncc; /* 0x240 */ - uint32 oobseloutcen; /* 0x244 */ - uint32 PAD[6]; - uint32 oobsyncd; /* 0x260 */ - uint32 oobseloutden; /* 0x264 */ - uint32 PAD[38]; - uint32 oobaextwidth; /* 0x300 */ - uint32 oobainwidth; /* 0x304 */ - uint32 oobaoutwidth; /* 0x308 */ - uint32 PAD[5]; - uint32 oobbextwidth; /* 0x320 */ - uint32 oobbinwidth; /* 0x324 */ - uint32 oobboutwidth; /* 0x328 */ - uint32 PAD[5]; - uint32 oobcextwidth; /* 0x340 */ - uint32 oobcinwidth; /* 0x344 */ - uint32 oobcoutwidth; /* 0x348 */ - uint32 PAD[5]; - uint32 oobdextwidth; /* 0x360 */ - uint32 oobdinwidth; /* 0x364 */ - uint32 oobdoutwidth; /* 0x368 */ - uint32 PAD[37]; - uint32 ioctrlset; /* 0x400 */ - uint32 ioctrlclear; /* 0x404 */ - uint32 ioctrl; /* 0x408 */ - uint32 PAD[61]; - uint32 iostatus; /* 0x500 */ - uint32 PAD[127]; - uint32 ioctrlwidth; /* 0x700 */ - uint32 iostatuswidth; /* 0x704 */ - uint32 PAD[62]; - uint32 resetctrl; /* 0x800 */ - uint32 resetstatus; /* 0x804 */ - uint32 resetreadid; /* 0x808 */ - uint32 resetwriteid; /* 0x80c */ - uint32 PAD[60]; - uint32 errlogctrl; /* 0x900 */ - uint32 errlogdone; /* 0x904 */ - uint32 errlogstatus; /* 0x908 */ - uint32 errlogaddrlo; /* 0x90c */ - uint32 errlogaddrhi; /* 0x910 */ - uint32 errlogid; /* 0x914 */ - uint32 errloguser; /* 0x918 */ - uint32 errlogflags; /* 0x91c */ - uint32 PAD[56]; - uint32 intstatus; /* 0xa00 */ - uint32 PAD[255]; - uint32 config; /* 0xe00 */ - uint32 PAD[63]; - uint32 itcr; /* 0xf00 */ - uint32 PAD[3]; - uint32 itipooba; /* 0xf10 */ - uint32 itipoobb; /* 0xf14 */ - uint32 itipoobc; /* 0xf18 */ - uint32 itipoobd; /* 0xf1c */ - uint32 PAD[4]; - uint32 itipoobaout; /* 0xf30 */ - uint32 itipoobbout; /* 0xf34 */ - uint32 itipoobcout; /* 0xf38 */ - uint32 itipoobdout; /* 0xf3c */ - uint32 PAD[4]; - uint32 itopooba; /* 0xf50 */ - uint32 itopoobb; /* 0xf54 */ - uint32 itopoobc; /* 0xf58 */ - uint32 itopoobd; /* 0xf5c */ - uint32 PAD[4]; - uint32 itopoobain; /* 0xf70 */ - uint32 itopoobbin; /* 0xf74 */ - uint32 itopoobcin; /* 0xf78 */ - uint32 itopoobdin; /* 0xf7c */ - uint32 PAD[4]; - uint32 itopreset; /* 0xf90 */ - uint32 PAD[15]; - uint32 peripherialid4; /* 0xfd0 */ - uint32 peripherialid5; /* 0xfd4 */ - uint32 peripherialid6; /* 0xfd8 */ - uint32 peripherialid7; /* 0xfdc */ - uint32 peripherialid0; /* 0xfe0 */ - uint32 peripherialid1; /* 0xfe4 */ - uint32 peripherialid2; /* 0xfe8 */ - uint32 peripherialid3; /* 0xfec */ - uint32 componentid0; /* 0xff0 */ - uint32 componentid1; /* 0xff4 */ - uint32 componentid2; /* 0xff8 */ - uint32 componentid3; /* 0xffc */ -} aidmp_t; - -#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ - -/* Out-of-band Router registers */ -#define OOB_BUSCONFIG 0x020 -#define OOB_STATUSA 0x100 -#define OOB_STATUSB 0x104 -#define OOB_STATUSC 0x108 -#define OOB_STATUSD 0x10c -#define OOB_ENABLEA0 0x200 -#define OOB_ENABLEA1 0x204 -#define OOB_ENABLEA2 0x208 -#define OOB_ENABLEA3 0x20c -#define OOB_ENABLEB0 0x280 -#define OOB_ENABLEB1 0x284 -#define OOB_ENABLEB2 0x288 -#define OOB_ENABLEB3 0x28c -#define OOB_ENABLEC0 0x300 -#define OOB_ENABLEC1 0x304 -#define OOB_ENABLEC2 0x308 -#define OOB_ENABLEC3 0x30c -#define OOB_ENABLED0 0x380 -#define OOB_ENABLED1 0x384 -#define OOB_ENABLED2 0x388 -#define OOB_ENABLED3 0x38c -#define OOB_ITCR 0xf00 -#define OOB_ITIPOOBA 0xf10 -#define OOB_ITIPOOBB 0xf14 -#define OOB_ITIPOOBC 0xf18 -#define OOB_ITIPOOBD 0xf1c -#define OOB_ITOPOOBA 0xf30 -#define OOB_ITOPOOBB 0xf34 -#define OOB_ITOPOOBC 0xf38 -#define OOB_ITOPOOBD 0xf3c - -/* DMP wrapper registers */ -#define AI_OOBSELINA30 0x000 -#define AI_OOBSELINA74 0x004 -#define AI_OOBSELINB30 0x020 -#define AI_OOBSELINB74 0x024 -#define AI_OOBSELINC30 0x040 -#define AI_OOBSELINC74 0x044 -#define AI_OOBSELIND30 0x060 -#define AI_OOBSELIND74 0x064 -#define AI_OOBSELOUTA30 0x100 -#define AI_OOBSELOUTA74 0x104 -#define AI_OOBSELOUTB30 0x120 -#define AI_OOBSELOUTB74 0x124 -#define AI_OOBSELOUTC30 0x140 -#define AI_OOBSELOUTC74 0x144 -#define AI_OOBSELOUTD30 0x160 -#define AI_OOBSELOUTD74 0x164 -#define AI_OOBSYNCA 0x200 -#define AI_OOBSELOUTAEN 0x204 -#define AI_OOBSYNCB 0x220 -#define AI_OOBSELOUTBEN 0x224 -#define AI_OOBSYNCC 0x240 -#define AI_OOBSELOUTCEN 0x244 -#define AI_OOBSYNCD 0x260 -#define AI_OOBSELOUTDEN 0x264 -#define AI_OOBAEXTWIDTH 0x300 -#define AI_OOBAINWIDTH 0x304 -#define AI_OOBAOUTWIDTH 0x308 -#define AI_OOBBEXTWIDTH 0x320 -#define AI_OOBBINWIDTH 0x324 -#define AI_OOBBOUTWIDTH 0x328 -#define AI_OOBCEXTWIDTH 0x340 -#define AI_OOBCINWIDTH 0x344 -#define AI_OOBCOUTWIDTH 0x348 -#define AI_OOBDEXTWIDTH 0x360 -#define AI_OOBDINWIDTH 0x364 -#define AI_OOBDOUTWIDTH 0x368 - - -#define AI_IOCTRLSET 0x400 -#define AI_IOCTRLCLEAR 0x404 -#define AI_IOCTRL 0x408 -#define AI_IOSTATUS 0x500 -#define AI_RESETCTRL 0x800 -#define AI_RESETSTATUS 0x804 - -#define AI_IOCTRLWIDTH 0x700 -#define AI_IOSTATUSWIDTH 0x704 - -#define AI_RESETREADID 0x808 -#define AI_RESETWRITEID 0x80c -#define AI_ERRLOGCTRL 0xa00 -#define AI_ERRLOGDONE 0xa04 -#define AI_ERRLOGSTATUS 0xa08 -#define AI_ERRLOGADDRLO 0xa0c -#define AI_ERRLOGADDRHI 0xa10 -#define AI_ERRLOGID 0xa14 -#define AI_ERRLOGUSER 0xa18 -#define AI_ERRLOGFLAGS 0xa1c -#define AI_INTSTATUS 0xa00 -#define AI_CONFIG 0xe00 -#define AI_ITCR 0xf00 -#define AI_ITIPOOBA 0xf10 -#define AI_ITIPOOBB 0xf14 -#define AI_ITIPOOBC 0xf18 -#define AI_ITIPOOBD 0xf1c -#define AI_ITIPOOBAOUT 0xf30 -#define AI_ITIPOOBBOUT 0xf34 -#define AI_ITIPOOBCOUT 0xf38 -#define AI_ITIPOOBDOUT 0xf3c -#define AI_ITOPOOBA 0xf50 -#define AI_ITOPOOBB 0xf54 -#define AI_ITOPOOBC 0xf58 -#define AI_ITOPOOBD 0xf5c -#define AI_ITOPOOBAIN 0xf70 -#define AI_ITOPOOBBIN 0xf74 -#define AI_ITOPOOBCIN 0xf78 -#define AI_ITOPOOBDIN 0xf7c -#define AI_ITOPRESET 0xf90 -#define AI_PERIPHERIALID4 0xfd0 -#define AI_PERIPHERIALID5 0xfd4 -#define AI_PERIPHERIALID6 0xfd8 -#define AI_PERIPHERIALID7 0xfdc -#define AI_PERIPHERIALID0 0xfe0 -#define AI_PERIPHERIALID1 0xfe4 -#define AI_PERIPHERIALID2 0xfe8 -#define AI_PERIPHERIALID3 0xfec -#define AI_COMPONENTID0 0xff0 -#define AI_COMPONENTID1 0xff4 -#define AI_COMPONENTID2 0xff8 -#define AI_COMPONENTID3 0xffc - -/* resetctrl */ -#define AIRC_RESET 1 - -/* config */ -#define AICFG_OOB 0x00000020 -#define AICFG_IOS 0x00000010 -#define AICFG_IOC 0x00000008 -#define AICFG_TO 0x00000004 -#define AICFG_ERRL 0x00000002 -#define AICFG_RST 0x00000001 - -/* bit defines for AI_OOBSELOUTB74 reg */ -#define OOB_SEL_OUTEN_B_5 15 -#define OOB_SEL_OUTEN_B_6 23 - -/* AI_OOBSEL for A/B/C/D, 0-7 */ -#define AI_OOBSEL_MASK 0x1F -#define AI_OOBSEL_0_SHIFT 0 -#define AI_OOBSEL_1_SHIFT 8 -#define AI_OOBSEL_2_SHIFT 16 -#define AI_OOBSEL_3_SHIFT 24 -#define AI_OOBSEL_4_SHIFT 0 -#define AI_OOBSEL_5_SHIFT 8 -#define AI_OOBSEL_6_SHIFT 16 -#define AI_OOBSEL_7_SHIFT 24 - -#endif /* _AIDMP_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd/include/bcm_cfg.h deleted file mode 100644 index 7c6e70f449ef..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcm_cfg.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * BCM common config options - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcm_cfg.h 351867 2012-08-21 18:46:16Z $ - */ - -#ifndef _bcm_cfg_h_ -#define _bcm_cfg_h_ -#endif /* _bcm_cfg_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h deleted file mode 100644 index b05ba3704aeb..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Memory pools library, Public interface - * - * API Overview - * - * This package provides a memory allocation subsystem based on pools of - * homogenous objects. - * - * Instrumentation is available for reporting memory utilization both - * on a per-data-structure basis and system wide. - * - * There are two main types defined in this API. - * - * pool manager: A singleton object that acts as a factory for - * pool allocators. It also is used for global - * instrumentation, such as reporting all blocks - * in use across all data structures. The pool manager - * creates and provides individual memory pools - * upon request to application code. - * - * memory pool: An object for allocating homogenous memory blocks. - * - * Global identifiers in this module use the following prefixes: - * bcm_mpm_* Memory pool manager - * bcm_mp_* Memory pool - * - * There are two main types of memory pools: - * - * prealloc: The contiguous memory block of objects can either be supplied - * by the client or malloc'ed by the memory manager. The objects are - * allocated out of a block of memory and freed back to the block. - * - * heap: The memory pool allocator uses the heap (malloc/free) for memory. - * In this case, the pool allocator is just providing statistics - * and instrumentation on top of the heap, without modifying the heap - * allocation implementation. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcm_mpool_pub.h 407097 2013-06-11 18:43:16Z $ - */ - -#ifndef _BCM_MPOOL_PUB_H -#define _BCM_MPOOL_PUB_H 1 - -#include /* needed for uint16 */ - - -/* -************************************************************************** -* -* Type definitions, handles -* -************************************************************************** -*/ - -/* Forward declaration of OSL handle. */ -struct osl_info; - -/* Forward declaration of string buffer. */ -struct bcmstrbuf; - -/* - * Opaque type definition for the pool manager handle. This object is used for global - * memory pool operations such as obtaining a new pool, deleting a pool, iterating and - * instrumentation/debugging. - */ -struct bcm_mpm_mgr; -typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h; - -/* - * Opaque type definition for an instance of a pool. This handle is used for allocating - * and freeing memory through the pool, as well as management/instrumentation on this - * specific pool. - */ -struct bcm_mp_pool; -typedef struct bcm_mp_pool *bcm_mp_pool_h; - - -/* - * To make instrumentation more readable, every memory - * pool must have a readable name. Pool names are up to - * 8 bytes including '\0' termination. (7 printable characters.) - */ -#define BCM_MP_NAMELEN 8 - - -/* - * Type definition for pool statistics. - */ -typedef struct bcm_mp_stats { - char name[BCM_MP_NAMELEN]; /* Name of this pool. */ - unsigned int objsz; /* Object size allocated in this pool */ - uint16 nobj; /* Total number of objects in this pool */ - uint16 num_alloc; /* Number of objects currently allocated */ - uint16 high_water; /* Max number of allocated objects. */ - uint16 failed_alloc; /* Failed allocations. */ -} bcm_mp_stats_t; - - -/* -************************************************************************** -* -* API Routines on the pool manager. -* -************************************************************************** -*/ - -/* - * bcm_mpm_init() - initialize the whole memory pool system. - * - * Parameters: - * osh: INPUT Operating system handle. Needed for heap memory allocation. - * max_pools: INPUT Maximum number of mempools supported. - * mgr: OUTPUT The handle is written with the new pools manager object/handle. - * - * Returns: - * BCME_OK Object initialized successfully. May be used. - * BCME_NOMEM Initialization failed due to no memory. Object must not be used. - */ -int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp); - - -/* - * bcm_mpm_deinit() - de-initialize the whole memory pool system. - * - * Parameters: - * mgr: INPUT Pointer to pool manager handle. - * - * Returns: - * BCME_OK Memory pool manager successfully de-initialized. - * other Indicated error occured during de-initialization. - */ -int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); - -/* - * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The - * pool uses a contiguous block of pre-alloced - * memory. The memory block may either be provided - * by the client or dynamically allocated by the - * pool manager. - * - * Parameters: - * mgr: INPUT The handle to the pool manager - * obj_sz: INPUT Size of objects that will be allocated by the new pool - * Must be >= sizeof(void *). - * nobj: INPUT Maximum number of concurrently existing objects to support - * memstart INPUT Pointer to the memory to use, or NULL to malloc() - * memsize INPUT Number of bytes referenced from memstart (for error checking). - * Must be 0 if 'memstart' is NULL. - * poolname INPUT For instrumentation, the name of the pool - * newp: OUTPUT The handle for the new pool, if creation is successful - * - * Returns: - * BCME_OK Pool created ok. - * other Pool not created due to indicated error. newpoolp set to NULL. - * - * - */ -int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, - unsigned int obj_sz, - int nobj, - void *memstart, - unsigned int memsize, - const char poolname[BCM_MP_NAMELEN], - bcm_mp_pool_h *newp); - - -/* - * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after - * all memory objects have been freed back to the pool. - * - * Parameters: - * mgr: INPUT The handle to the pools manager - * pool: INPUT The handle of the pool to delete - * - * Returns: - * BCME_OK Pool deleted ok. - * other Pool not deleted due to indicated error. - * - */ -int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); - -/* - * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory - * pool allocator uses the heap (malloc/free) for memory. - * In this case, the pool allocator is just providing - * statistics and instrumentation on top of the heap, - * without modifying the heap allocation implementation. - * - * Parameters: - * mgr: INPUT The handle to the pool manager - * obj_sz: INPUT Size of objects that will be allocated by the new pool - * poolname INPUT For instrumentation, the name of the pool - * newp: OUTPUT The handle for the new pool, if creation is successful - * - * Returns: - * BCME_OK Pool created ok. - * other Pool not created due to indicated error. newpoolp set to NULL. - * - * - */ -int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, - const char poolname[BCM_MP_NAMELEN], - bcm_mp_pool_h *newp); - - -/* - * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after - * all memory objects have been freed back to the pool. - * - * Parameters: - * mgr: INPUT The handle to the pools manager - * pool: INPUT The handle of the pool to delete - * - * Returns: - * BCME_OK Pool deleted ok. - * other Pool not deleted due to indicated error. - * - */ -int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); - - -/* - * bcm_mpm_stats() - Return stats for all pools - * - * Parameters: - * mgr: INPUT The handle to the pools manager - * stats: OUTPUT Array of pool statistics. - * nentries: MOD Max elements in 'stats' array on INPUT. Actual number - * of array elements copied to 'stats' on OUTPUT. - * - * Returns: - * BCME_OK Ok - * other Error getting stats. - * - */ -int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries); - - -/* - * bcm_mpm_dump() - Display statistics on all pools - * - * Parameters: - * mgr: INPUT The handle to the pools manager - * b: OUTPUT Output buffer. - * - * Returns: - * BCME_OK Ok - * other Error during dump. - * - */ -int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b); - - -/* - * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to - * compensate for alignment requirements of the objects. - * This function provides the padded object size. If clients - * pre-allocate a memory slab for a memory pool, the - * padded object size should be used by the client to allocate - * the memory slab (in order to provide sufficent space for - * the maximum number of objects). - * - * Parameters: - * mgr: INPUT The handle to the pools manager. - * obj_sz: INPUT Input object size. - * padded_obj_sz: OUTPUT Padded object size. - * - * Returns: - * BCME_OK Ok - * BCME_BADARG Bad arguments. - * - */ -int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz); - - -/* -*************************************************************************** -* -* API Routines on a specific pool. -* -*************************************************************************** -*/ - - -/* - * bcm_mp_alloc() - Allocate a memory pool object. - * - * Parameters: - * pool: INPUT The handle to the pool. - * - * Returns: - * A pointer to the new object. NULL on error. - * - */ -void* bcm_mp_alloc(bcm_mp_pool_h pool); - -/* - * bcm_mp_free() - Free a memory pool object. - * - * Parameters: - * pool: INPUT The handle to the pool. - * objp: INPUT A pointer to the object to free. - * - * Returns: - * BCME_OK Ok - * other Error during free. - * - */ -int bcm_mp_free(bcm_mp_pool_h pool, void *objp); - -/* - * bcm_mp_stats() - Return stats for this pool - * - * Parameters: - * pool: INPUT The handle to the pool - * stats: OUTPUT Pool statistics - * - * Returns: - * BCME_OK Ok - * other Error getting statistics. - * - */ -int bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats); - - -/* - * bcm_mp_dump() - Dump a pool - * - * Parameters: - * pool: INPUT The handle to the pool - * b OUTPUT Output buffer - * - * Returns: - * BCME_OK Ok - * other Error during dump. - * - */ -int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b); - - -#endif /* _BCM_MPOOL_PUB_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/bcmdhd/include/bcmcdc.h deleted file mode 100644 index c93b6f619b20..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmcdc.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * CDC network driver ioctl/indication encoding - * Broadcom 802.11abg Networking Device Driver - * - * Definitions subject to change without notice. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmcdc.h 318308 2012-03-02 02:23:42Z $ - */ -#ifndef _bcmcdc_h_ -#define _bcmcdc_h_ -#include - -typedef struct cdc_ioctl { - uint32 cmd; /* ioctl command value */ - uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */ - uint32 flags; /* flag defns given below */ - uint32 status; /* status code returned from the device */ -} cdc_ioctl_t; - -/* Max valid buffer size that can be sent to the dongle */ -#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN - -/* len field is divided into input and output buffer lengths */ -#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */ - /* excluding IOCTL header */ -#define CDCL_IOC_OUTLEN_SHIFT 0 -#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */ -#define CDCL_IOC_INLEN_SHIFT 16 - -/* CDC flag definitions */ -#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */ -#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */ -#define CDCF_IOC_OVL_IDX_MASK 0x3c /* overlay region index mask */ -#define CDCF_IOC_OVL_RSV 0x40 /* 1=reserve this overlay region */ -#define CDCF_IOC_OVL 0x80 /* 1=this ioctl corresponds to an overlay */ -#define CDCF_IOC_ACTION_MASK 0xfe /* SET/GET, OVL_IDX, OVL_RSV, OVL mask */ -#define CDCF_IOC_ACTION_SHIFT 1 /* SET/GET, OVL_IDX, OVL_RSV, OVL shift */ -#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */ -#define CDCF_IOC_IF_SHIFT 12 -#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */ -#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */ - -#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) -#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) - -#define CDC_GET_IF_IDX(hdr) \ - ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) -#define CDC_SET_IF_IDX(hdr, idx) \ - ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) - -/* - * BDC header - * - * The BDC header is used on data packets to convey priority across USB. - */ - -struct bdc_header { - uint8 flags; /* Flags */ - uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 USB flow control info */ - uint8 flags2; - uint8 dataOffset; /* Offset from end of BDC header to packet data, in - * 4-byte words. Leaves room for optional headers. - */ -}; - -#define BDC_HEADER_LEN 4 - -/* flags field bitmap */ -#define BDC_FLAG_80211_PKT 0x01 /* Packet is in 802.11 format (dongle -> host) */ -#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */ -#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums: host->device */ -#define BDC_FLAG_EVENT_MSG 0x08 /* Payload contains an event msg: device->host */ -#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ -#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ - -/* priority field bitmap */ -#define BDC_PRIORITY_MASK 0x07 -#define BDC_PRIORITY_FC_MASK 0xf0 /* flow control info mask */ -#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */ - -/* flags2 field bitmap */ -#define BDC_FLAG2_IF_MASK 0x0f /* interface index (host <-> dongle) */ -#define BDC_FLAG2_IF_SHIFT 0 -#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */ - /* FLOW CONTROL info only */ - -/* version numbers */ -#define BDC_PROTO_VER_1 1 /* Old Protocol version */ -#define BDC_PROTO_VER 2 /* Protocol version */ - -/* flags2.if field access macros */ -#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))) - -#define BDC_FLAG2_PAD_MASK 0xf0 -#define BDC_FLAG_PAD_MASK 0x03 -#define BDC_FLAG2_PAD_SHIFT 2 -#define BDC_FLAG_PAD_SHIFT 0 -#define BDC_FLAG2_PAD_IDX 0x3c -#define BDC_FLAG_PAD_IDX 0x03 -#define BDC_GET_PAD_LEN(hdr) \ - ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ - ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) -#define BDC_SET_PAD_LEN(hdr, idx) \ - ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ - (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ - ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ - (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) - -#endif /* _bcmcdc_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/bcmdhd/include/bcmdefs.h deleted file mode 100644 index b444cb1c3fc5..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmdefs.h +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Misc system wide definitions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmdefs.h 516456 2014-11-19 21:00:05Z $ - */ - -#ifndef _bcmdefs_h_ -#define _bcmdefs_h_ - -/* - * One doesn't need to include this file explicitly, gets included automatically if - * typedefs.h is included. - */ - -/* Use BCM_REFERENCE to suppress warnings about intentionally-unused function - * arguments or local variables. - */ -#define BCM_REFERENCE(data) ((void)(data)) - -/* Allow for suppressing unused variable warnings. */ -#ifdef __GNUC__ -#define UNUSED_VAR __attribute__ ((unused)) -#else -#define UNUSED_VAR -#endif - -/* Compile-time assert can be used in place of ASSERT if the expression evaluates - * to a constant at compile time. - */ -#define STATIC_ASSERT(expr) { \ - /* Make sure the expression is constant. */ \ - typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \ - /* Make sure the expression is true. */ \ - typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \ -} - -/* Reclaiming text and data : - * The following macros specify special linker sections that can be reclaimed - * after a system is considered 'up'. - * BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN, - * as in most cases, the attach function calls the detach function to clean up on error). - */ - -#define bcmreclaimed 0 -#define _data _data -#define _fn _fn -#define BCMPREATTACHDATA(_data) _data -#define BCMPREATTACHFN(_fn) _fn -#define _data _data -#define _fn _fn -#define _fn _fn -#define BCMNMIATTACHFN(_fn) _fn -#define BCMNMIATTACHDATA(_data) _data -#define CONST const - -#undef BCM47XX_CA9 - -#ifndef BCMFASTPATH -#define BCMFASTPATH -#define BCMFASTPATH_HOST -#endif /* BCMFASTPATH */ - - -/* Use the BCMRAMFN() macro to tag functions in source that must be included in RAM (excluded from - * ROM). This should eliminate the need to manually specify these functions in the ROM config file. - * It should only be used in special cases where the function must be in RAM for *all* ROM-based - * chips. - */ - #define BCMRAMFN(_fn) _fn - -#define STATIC static - -/* Bus types */ -#define SI_BUS 0 /* SOC Interconnect */ -#define PCI_BUS 1 /* PCI target */ -#define PCMCIA_BUS 2 /* PCMCIA target */ -#define SDIO_BUS 3 /* SDIO target */ -#define JTAG_BUS 4 /* JTAG */ -#define USB_BUS 5 /* USB (does not support R/W REG) */ -#define SPI_BUS 6 /* gSPI target */ -#define RPC_BUS 7 /* RPC target */ - -/* Allows size optimization for single-bus image */ -#ifdef BCMBUSTYPE -#define BUSTYPE(bus) (BCMBUSTYPE) -#else -#define BUSTYPE(bus) (bus) -#endif - -/* Allows size optimization for single-backplane image */ -#ifdef BCMCHIPTYPE -#define CHIPTYPE(bus) (BCMCHIPTYPE) -#else -#define CHIPTYPE(bus) (bus) -#endif - - -/* Allows size optimization for SPROM support */ -#if defined(BCMSPROMBUS) -#define SPROMBUS (BCMSPROMBUS) -#elif defined(SI_PCMCIA_SROM) -#define SPROMBUS (PCMCIA_BUS) -#else -#define SPROMBUS (PCI_BUS) -#endif - -/* Allows size optimization for single-chip image */ -#ifdef BCMCHIPID -#define CHIPID(chip) (BCMCHIPID) -#else -#define CHIPID(chip) (chip) -#endif - -#ifdef BCMCHIPREV -#define CHIPREV(rev) (BCMCHIPREV) -#else -#define CHIPREV(rev) (rev) -#endif - -/* Defines for DMA Address Width - Shared between OSL and HNDDMA */ -#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ -#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */ -#define DMADDR_MASK_26 0xFC000000 /* Address maks for 26-bits */ -#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */ - -#define DMADDRWIDTH_26 26 /* 26-bit addressing capability */ -#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */ -#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */ -#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */ -#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */ - -typedef struct { - uint32 loaddr; - uint32 hiaddr; -} dma64addr_t; - -#define PHYSADDR64HI(_pa) ((_pa).hiaddr) -#define PHYSADDR64HISET(_pa, _val) \ - do { \ - (_pa).hiaddr = (_val); \ - } while (0) -#define PHYSADDR64LO(_pa) ((_pa).loaddr) -#define PHYSADDR64LOSET(_pa, _val) \ - do { \ - (_pa).loaddr = (_val); \ - } while (0) - -#define PHYSADDR64ADD(_pa, _hi0, _lo0, _hi1, _lo1) \ - do { \ - uint32 _lo = (uint32)(_lo0); \ - (_pa).loaddr = _lo + (uint32)(_lo1); \ - (_pa).hiaddr = (uint32)(_hi0) + (uint32)(_hi1) + \ - (((_pa).loaddr < _lo)? 1 : 0); \ - } while (0) -#define PHYSADDR64ADD64BITDATA(_pa, _paorg, _hi, _lo) \ - PHYSADDR64ADD((_pa), (_paorg).hiaddr, (_paorg).loaddr, (_hi), (_lo)) -#define PHYSADDR64ADDOFFSET(_pa, _paorg, _offset) \ - PHYSADDR64ADD((_pa), (_paorg).hiaddr, (_paorg).loaddr, 0, (_offset)) -#define PHYSADDR64ROUNDUP(_pa, _paorg, _align) \ - do { \ - PHYSADDR64ADDOFFSET(_pa, _paorg, (uint32)((_align) - 1)); \ - (_pa).loaddr = ((_pa).loaddr / (_align)) * (_align); \ - } while (0) - -#define PHYSADDR64SUB(_pa, _hi0, _lo0, _hi1, _lo1) \ - do { \ - uint32 _lo = (uint32)(_lo0); \ - (_pa).loaddr = _lo - (uint32)(_lo1); \ - (_pa).hiaddr = (uint32)(_hi0) - (uint32)(_hi1) - \ - (((_pa).loaddr > _lo)? 1 : 0); \ - } while (0) -#define PHYSADDR64SUB64BITDATA(_pa, _paorg, _hi, _lo) \ - PHYSADDR64SUB((_pa), (_paorg).hiaddr, (_paorg).loaddr, (_hi), (_lo)) -#define PHYSADDR64SUBOFFSET(_pa, _paorg, _offset) \ - PHYSADDR64SUB((_pa), (_paorg).hiaddr, (_paorg).loaddr, 0, (_offset)) - -#ifdef BCMDMA64OSL -typedef dma64addr_t dmaaddr_t; -#define PHYSADDRHI(_pa) PHYSADDR64HI(_pa) -#define PHYSADDRHISET(_pa, _val) PHYSADDR64HISET(_pa, _val) -#define PHYSADDRLO(_pa) PHYSADDR64LO(_pa) -#define PHYSADDRLOSET(_pa, _val) PHYSADDR64LOSET(_pa, _val) -#define PHYSADDRADD(_pa, _hi0, _lo0, _hi1, _lo1) \ - PHYSADDR64ADD(_pa, _hi0, _lo0, _hi1, _lo1) -#define PHYSADDRADD64BITDATA(_pa, _paorg, _hi, _lo) \ - PHYSADDR64ADD64BITDATA(_pa, _paorg, _hi, _lo) -#define PHYSADDRADDOFFSET(_pa, _paorg, _offset) \ - PHYSADDR64ADDOFFSET(_pa, _paorg, _offset) -#define PHYSADDRROUNDUP(_pa, _paorg, _align) \ - PHYSADDR64ROUNDUP(_pa, _paorg, _align) -#define PHYSADDRSUB(_pa, _hi0, _lo0, _hi1, _lo1) \ - PHYSADDR64SUB(_pa, _hi0, _lo0, _hi1, _lo1) -#define PHYSADDRSUB64BITDATA(_pa, _paorg, _hi, _lo) \ - PHYSADDR64SUB64BITDATA(_pa, _paorg, _hi, _lo) -#define PHYSADDRSUBOFFSET(_pa, _paorg, _offset) \ - PHYSADDR64SUBOFFSET(_pa, _paorg, _offset) -#else -typedef unsigned long dmaaddr_t; -#define PHYSADDRHI(_pa) (0) -#define PHYSADDRHISET(_pa, _val) -#define PHYSADDRLO(_pa) ((_pa)) -#define PHYSADDRLOSET(_pa, _val) \ - do { \ - (_pa) = (_val); \ - } while (0) -#define PHYSADDRADD(_pa, _hi0, _lo0, _hi1, _lo1) \ - do { \ - (_pa) = (uint32)(_lo0) + (uint32)(_lo1); \ - } while (0) -#define PHYSADDRADDOFFSET(_pa, _paorg, _offset) \ - do { \ - (_pa) = (uint32)(_paorg) + (uint32)(_offset); \ - } while (0) -#define PHYSADDRADD64BITDATA(_pa, _paorg, _hi, _lo) \ - do { \ - (_pa) = (uint32)(_paorg) + (uint32)(_lo); \ - } while (0) -#define PHYSADDRROUNDUP(_pa, _paorg, _align) \ - do { \ - (_pa) = (((_paorg) + ((_align) - 1)) / (_align)) * (_align); \ - } while (0) -#define PHYSADDRSUB(_pa, _hi0, _lo0, _hi1, _lo1) \ - do { \ - (_pa) = (uint32)(_lo0) - (uint32)(_lo1); \ - } while (0) -#define PHYSADDRSUB64BITDATA(_pa, _paorg, _hi, _lo) \ - do { \ - (_pa) = (uint32)(_paorg) - (uint32)(_lo); \ - } while (0) -#define PHYSADDRSUBOFFSET(_pa, _paorg, _offset) \ - do { \ - (_pa) = (uint32)(_paorg) - (uint32)(_offset); \ - } while (0) -#endif /* BCMDMA64OSL */ -#define PHYSADDRISZERO(_pa) (PHYSADDRLO(_pa) == 0 && PHYSADDRHI(_pa) == 0) - -/* One physical DMA segment */ -typedef struct { - dmaaddr_t addr; - uint32 length; -} hnddma_seg_t; - -#define MAX_DMA_SEGS 8 - - -typedef struct { - void *oshdmah; /* Opaque handle for OSL to store its information */ - uint origsize; /* Size of the virtual packet */ - uint nsegs; - hnddma_seg_t segs[MAX_DMA_SEGS]; -} hnddma_seg_map_t; - - -/* 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 (hnddma.c). - */ - -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) -/* add 40 bytes to allow for extra RPC header and info */ -#define BCMEXTRAHDROOM 260 -#else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ -#define BCMEXTRAHDROOM 204 -#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ - -/* Packet alignment for most efficient SDIO (can change based on platform) */ -#ifndef SDALIGN -#define SDALIGN 32 -#endif - -/* Headroom required for dongle-to-host communication. Packets allocated - * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should - * leave this much room in front for low-level message headers which may - * be needed to get across the dongle bus to the host. (These messages - * don't go over the network, so room for the full WL header above would - * be a waste.). -*/ -#define BCMDONGLEHDRSZ 12 -#define BCMDONGLEPADSZ 16 - -#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) - - -#if defined(NO_BCMDBG_ASSERT) -# undef BCMDBG_ASSERT -# undef BCMASSERT_LOG -#endif - -#if defined(BCMASSERT_LOG) -#define BCMASSERT_SUPPORT -#endif - -/* 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 BCMSMALL to remove misc features for memory-constrained environments */ -#ifdef BCMSMALL -#undef BCMSPACE -#define bcmspace FALSE /* if (bcmspace) code is discarded */ -#else -#define BCMSPACE -#define bcmspace TRUE /* if (bcmspace) code is retained */ -#endif - -/* Max. nvram variable table size */ -#ifndef MAXSZ_NVRAM_VARS -#define MAXSZ_NVRAM_VARS 4096 -#endif - - - -/* WL_ENAB_RUNTIME_CHECK may be set based upon the #define below (for ROM builds). It may also - * be defined via makefiles (e.g. ROM auto abandon unoptimized compiles). - */ - - -#ifdef BCMLFRAG /* BCMLFRAG support enab macros */ - extern bool _bcmlfrag; - #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) - #define BCMLFRAG_ENAB() (_bcmlfrag) - #elif defined(BCMLFRAG_DISABLED) - #define BCMLFRAG_ENAB() (0) - #else - #define BCMLFRAG_ENAB() (1) - #endif -#else - #define BCMLFRAG_ENAB() (0) -#endif /* BCMLFRAG_ENAB */ -#ifdef BCMSPLITRX /* BCMLFRAG support enab macros */ - extern bool _bcmsplitrx; - #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) - #define BCMSPLITRX_ENAB() (_bcmsplitrx) - #elif defined(BCMSPLITRX_DISABLED) - #define BCMSPLITRX_ENAB() (0) - #else - #define BCMSPLITRX_ENAB() (1) - #endif -#else - #define BCMSPLITRX_ENAB() (0) -#endif /* BCMSPLITRX */ -#ifdef BCM_SPLITBUF - extern bool _bcmsplitbuf; - #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) - #define BCM_SPLITBUF_ENAB() (_bcmsplitbuf) - #elif defined(BCM_SPLITBUF_DISABLED) - #define BCM_SPLITBUF_ENAB() (0) - #else - #define BCM_SPLITBUF_ENAB() (1) - #endif -#else - #define BCM_SPLITBUF_ENAB() (0) -#endif /* BCM_SPLITBUF */ -/* Max size for reclaimable NVRAM array */ -#ifdef DL_NVRAM -#define NVRAM_ARRAY_MAXSIZE DL_NVRAM -#else -#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS -#endif /* DL_NVRAM */ - -extern uint32 gFWID; - - -#endif /* _bcmdefs_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h deleted file mode 100644 index 126086eeba2b..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmdevs.h +++ /dev/null @@ -1,731 +0,0 @@ -/* - * Broadcom device-specific manifest constants. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmdevs.h 484136 2014-06-12 04:36:10Z $ - */ - -#ifndef _BCMDEVS_H -#define _BCMDEVS_H - -/* PCI vendor IDs */ -#define VENDOR_EPIGRAM 0xfeda -#define VENDOR_BROADCOM 0x14e4 -#define VENDOR_3COM 0x10b7 -#define VENDOR_NETGEAR 0x1385 -#define VENDOR_DIAMOND 0x1092 -#define VENDOR_INTEL 0x8086 -#define VENDOR_DELL 0x1028 -#define VENDOR_HP 0x103c -#define VENDOR_HP_COMPAQ 0x0e11 -#define VENDOR_APPLE 0x106b -#define VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */ -#define VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */ -#define VENDOR_TI 0x104c /* Texas Instruments */ -#define VENDOR_RICOH 0x1180 /* Ricoh */ -#define VENDOR_JMICRON 0x197b - - -/* PCMCIA vendor IDs */ -#define VENDOR_BROADCOM_PCMCIA 0x02d0 - -/* SDIO vendor IDs */ -#define VENDOR_BROADCOM_SDIO 0x00BF - -/* DONGLE VID/PIDs */ -#define BCM_DNGL_VID 0x0a5c -#define BCM_DNGL_BL_PID_4328 0xbd12 -#define BCM_DNGL_BL_PID_4322 0xbd13 -#define BCM_DNGL_BL_PID_4319 0xbd16 -#define BCM_DNGL_BL_PID_43236 0xbd17 -#define BCM_DNGL_BL_PID_4332 0xbd18 -#define BCM_DNGL_BL_PID_4330 0xbd19 -#define BCM_DNGL_BL_PID_4334 0xbd1a -#define BCM_DNGL_BL_PID_43239 0xbd1b -#define BCM_DNGL_BL_PID_4324 0xbd1c -#define BCM_DNGL_BL_PID_4360 0xbd1d -#define BCM_DNGL_BL_PID_43143 0xbd1e -#define BCM_DNGL_BL_PID_43242 0xbd1f -#define BCM_DNGL_BL_PID_43342 0xbd21 -#define BCM_DNGL_BL_PID_4335 0xbd20 -#define BCM_DNGL_BL_PID_43341 0xbd22 -#define BCM_DNGL_BL_PID_4350 0xbd23 -#define BCM_DNGL_BL_PID_4345 0xbd24 -#define BCM_DNGL_BL_PID_4349 0xbd25 -#define BCM_DNGL_BL_PID_4354 0xbd26 -#define BCM_DNGL_BL_PID_43569 0xbd27 -#define BCM_DNGL_BL_PID_43909 0xbd28 - -#define BCM_DNGL_BDC_PID 0x0bdc -#define BCM_DNGL_JTAG_PID 0x4a44 - -/* HW USB BLOCK [CPULESS USB] PIDs */ -#define BCM_HWUSB_PID_43239 43239 - -/* PCI Device IDs */ -#define BCM4210_DEVICE_ID 0x1072 /* never used */ -#define BCM4230_DEVICE_ID 0x1086 /* never used */ -#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */ -#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */ -#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */ -#define BCM4211_DEVICE_ID 0x4211 -#define BCM4231_DEVICE_ID 0x4231 -#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */ -#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */ -#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */ -#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */ -#define BCM4328_D11DUAL_ID 0x4314 /* 4328/4312 802.11a/g id */ -#define BCM4328_D11G_ID 0x4315 /* 4328/4312 802.11g id */ -#define BCM4328_D11A_ID 0x4316 /* 4328/4312 802.11a id */ -#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */ -#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */ -#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */ -#define BCM4325_D11DUAL_ID 0x431b /* 4325 802.11a/g id */ -#define BCM4325_D11G_ID 0x431c /* 4325 802.11g id */ -#define BCM4325_D11A_ID 0x431d /* 4325 802.11a id */ -#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */ -#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */ -#define BCM4306_UART_ID 0x4322 /* 4306 uart */ -#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */ -#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */ -#define BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G_ID; INF w/loose binding war */ -#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */ -#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Ghz band id */ -#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */ -#define BCM4322_D11N_ID 0x432b /* 4322 802.11n dualband device */ -#define BCM4322_D11N2G_ID 0x432c /* 4322 802.11n 2.4GHz device */ -#define BCM4322_D11N5G_ID 0x432d /* 4322 802.11n 5GHz device */ -#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */ -#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ -#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ -#define BCM4315_D11DUAL_ID 0x4334 /* 4315 802.11a/g id */ -#define BCM4315_D11G_ID 0x4335 /* 4315 802.11g id */ -#define BCM4315_D11A_ID 0x4336 /* 4315 802.11a id */ -#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 BCM43231_D11N2G_ID 0x4340 /* 43231 802.11n 2.4GHz device */ -#define BCM43221_D11N2G_ID 0x4341 /* 43221 802.11n 2.4GHz device */ -#define BCM43222_D11N_ID 0x4350 /* 43222 802.11n dualband device */ -#define BCM43222_D11N2G_ID 0x4351 /* 43222 802.11n 2.4GHz device */ -#define BCM43222_D11N5G_ID 0x4352 /* 43222 802.11n 5GHz device */ -#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ -#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */ -#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband device */ -#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ -#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ -#define BCM43236_D11N5G_ID 0x4348 /* 43236 802.11n 5GHz device */ -#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ -#define BCM43421_D11N_ID 0xA99D /* 43421 802.11n dualband device */ -#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ -#define BCM4330_D11N_ID 0x4360 /* 4330 802.11n dualband device */ -#define BCM4330_D11N2G_ID 0x4361 /* 4330 802.11n 2.4G device */ -#define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */ -#define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */ -#define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */ -#define BCM6362_D11N2G_ID 0x433f /* 6362 802.11n 2.4Ghz band id */ -#define BCM6362_D11N5G_ID 0x434f /* 6362 802.11n 5Ghz band id */ -#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */ -#define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */ -#define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */ -#define BCM43237_D11N_ID 0x4355 /* 43237 802.11n dualband device */ -#define BCM43237_D11N5G_ID 0x4356 /* 43237 802.11n 5GHz device */ -#define BCM43227_D11N2G_ID 0x4358 /* 43228 802.11n 2.4GHz device */ -#define BCM43228_D11N_ID 0x4359 /* 43228 802.11n DualBand device */ -#define BCM43228_D11N5G_ID 0x435a /* 43228 802.11n 5GHz device */ -#define BCM43362_D11N_ID 0x4363 /* 43362 802.11n 2.4GHz device */ -#define BCM43239_D11N_ID 0x4370 /* 43239 802.11n dualband device */ -#define BCM4324_D11N_ID 0x4374 /* 4324 802.11n dualband device */ -#define BCM43217_D11N2G_ID 0x43a9 /* 43217 802.11n 2.4GHz device */ -#define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */ -#define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */ -#define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */ -#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ -#define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */ -#define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */ -#define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */ -#define BCM43342_D11N_ID 0x4383 /* 43342 802.11n dualband device */ -#define BCM43342_D11N2G_ID 0x4384 /* 43342 802.11n 2.4G device */ -#define BCM43342_D11N5G_ID 0x4385 /* 43342 802.11n 5G device */ -#define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */ -#define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */ -#define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */ -#define BCM4360_D11AC_ID 0x43a0 -#define BCM4360_D11AC2G_ID 0x43a1 -#define BCM4360_D11AC5G_ID 0x43a2 -#define BCM4345_D11AC_ID 0x43ab /* 4345 802.11ac dualband device */ -#define BCM4345_D11AC2G_ID 0x43ac /* 4345 802.11ac 2.4G device */ -#define BCM4345_D11AC5G_ID 0x43ad /* 4345 802.11ac 5G device */ -#define BCM4335_D11AC_ID 0x43ae -#define BCM4335_D11AC2G_ID 0x43af -#define BCM4335_D11AC5G_ID 0x43b0 -#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ -#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ -#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ -#define BCM43602_D11AC_ID 0x43ba /* ac dualband PCI devid SPROM programmed */ -#define BCM43602_D11AC2G_ID 0x43bb /* 43602 802.11ac 2.4G device */ -#define BCM43602_D11AC5G_ID 0x43bc /* 43602 802.11ac 5G device */ -#define BCM4349_D11AC_ID 0x4349 /* 4349 802.11ac dualband device */ -#define BCM4349_D11AC2G_ID 0x43dd /* 4349 802.11ac 2.4G device */ -#define BCM4349_D11AC5G_ID 0x43de /* 4349 802.11ac 5G device */ -#define BCM4355_D11AC_ID 0x43d3 /* 4355 802.11ac dualband device */ -#define BCM4355_D11AC2G_ID 0x43d4 /* 4355 802.11ac 2.4G device */ -#define BCM4355_D11AC5G_ID 0x43d5 /* 4355 802.11ac 5G device */ -#define BCM4359_D11AC_ID 0x43d6 /* 4359 802.11ac dualband device */ -#define BCM4359_D11AC2G_ID 0x43d7 /* 4359 802.11ac 2.4G device */ -#define BCM4359_D11AC5G_ID 0x43d8 /* 4359 802.11ac 5G device */ - -/* PCI Subsystem ID */ -#define BCM943228HMB_SSID_VEN1 0x0607 -#define BCM94313HMGBL_SSID_VEN1 0x0608 -#define BCM94313HMG_SSID_VEN1 0x0609 -#define BCM943142HM_SSID_VEN1 0x0611 - -#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ - -#define BCM43242_D11N_ID 0x4367 /* 43242 802.11n dualband device */ -#define BCM43242_D11N2G_ID 0x4368 /* 43242 802.11n 2.4G device */ -#define BCM43242_D11N5G_ID 0x4369 /* 43242 802.11n 5G device */ - -#define BCM4350_D11AC_ID 0x43a3 -#define BCM4350_D11AC2G_ID 0x43a4 -#define BCM4350_D11AC5G_ID 0x43a5 - -#define BCM43556_D11AC_ID 0x43b7 -#define BCM43556_D11AC2G_ID 0x43b8 -#define BCM43556_D11AC5G_ID 0x43b9 - -#define BCM43558_D11AC_ID 0x43c0 -#define BCM43558_D11AC2G_ID 0x43c1 -#define BCM43558_D11AC5G_ID 0x43c2 - -#define BCM43566_D11AC_ID 0x43d3 -#define BCM43566_D11AC2G_ID 0x43d4 -#define BCM43566_D11AC5G_ID 0x43d5 - -#define BCM43568_D11AC_ID 0x43d6 -#define BCM43568_D11AC2G_ID 0x43d7 -#define BCM43568_D11AC5G_ID 0x43d8 - -#define BCM43569_D11AC_ID 0x43d9 -#define BCM43569_D11AC2G_ID 0x43da -#define BCM43569_D11AC5G_ID 0x43db - -#define BCM43570_D11AC_ID 0x43d9 -#define BCM43570_D11AC2G_ID 0x43da -#define BCM43570_D11AC5G_ID 0x43db - -#define BCM4354_D11AC_ID 0x43df /* 4354 802.11ac dualband device */ -#define BCM4354_D11AC2G_ID 0x43e0 /* 4354 802.11ac 2.4G device */ -#define BCM4354_D11AC5G_ID 0x43e1 /* 4354 802.11ac 5G device */ -#define BCM43430_D11N2G_ID 0x43e2 /* 43430 802.11n 2.4G device */ - - -#define BCM43349_D11N_ID 0x43e6 /* 43349 802.11n dualband id */ -#define BCM43349_D11N2G_ID 0x43e7 /* 43349 802.11n 2.4Ghz band id */ -#define BCM43349_D11N5G_ID 0x43e8 /* 43349 802.11n 5Ghz band id */ - -#define BCM4358_D11AC_ID 0x43e9 /* 4358 802.11ac dualband device */ -#define BCM4358_D11AC2G_ID 0x43ea /* 4358 802.11ac 2.4G device */ -#define BCM4358_D11AC5G_ID 0x43eb /* 4358 802.11ac 5G device */ - -#define BCM4356_D11AC_ID 0x43ec /* 4356 802.11ac dualband device */ -#define BCM4356_D11AC2G_ID 0x43ed /* 4356 802.11ac 2.4G device */ -#define BCM4356_D11AC5G_ID 0x43ee /* 4356 802.11ac 5G device */ - -#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */ -#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */ -#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */ -#define BCM_JTAGM_ID 0x43f1 /* BCM jtagm device id */ -#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */ -#define BCM_SDIOH_ID 0x43f3 /* BCM sdio host id */ -#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */ -#define SPIH_FPGA_ID 0x43f5 /* PCI SPI Host Controller FPGA */ -#define BCM_SPIH_ID 0x43f6 /* Synopsis SPI Host Controller */ -#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */ -#define BCM_JTAGM2_ID 0x43f9 /* BCM alternate jtagm device id */ -#define SDHCI_FPGA_ID 0x43fa /* Standard SDIO Host Controller FPGA */ -#define BCM4402_ENET_ID 0x4402 /* 4402 enet */ -#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */ -#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */ -#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */ -#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */ -#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */ -#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */ -#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */ -#define BCM47XX_AUDIO_ID 0x4711 /* 47xx audio codec */ -#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */ -#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */ -#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */ -#define BCM47XX_GMAC_ID 0x4715 /* 47xx Unimac based GbE */ -#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */ -#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */ -#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */ -#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */ -#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */ -#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */ -#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */ -#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */ -#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */ -#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */ -#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */ -#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */ -#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */ -#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */ -#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */ -#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */ -#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */ -#define JINVANI_SDIOH_ID 0x4743 /* Jinvani SDIO Gold Host */ -#define BCM27XX_SDIOH_ID 0x2702 /* BCM27xx Standard SDIO Host */ -#define PCIXX21_FLASHMEDIA_ID 0x803b /* TI PCI xx21 Standard Host Controller */ -#define PCIXX21_SDIOH_ID 0x803c /* TI PCI xx21 Standard Host Controller */ -#define R5C822_SDIOH_ID 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */ -#define JMICRON_SDIOH_ID 0x2381 /* JMicron Standard SDIO Host Controller */ - -/* Chip IDs */ -#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */ -#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */ -#define BCM43111_CHIP_ID 43111 /* 43111 chipcommon chipid (OTP chipid) */ -#define BCM43112_CHIP_ID 43112 /* 43112 chipcommon chipid (OTP chipid) */ -#define BCM4312_CHIP_ID 0x4312 /* 4312 chipcommon chipid */ -#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ -#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP chipid) */ -#define BCM4315_CHIP_ID 0x4315 /* 4315 chip id */ -#define BCM4318_CHIP_ID 0x4318 /* 4318 chipcommon chipid */ -#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ -#define BCM4320_CHIP_ID 0x4320 /* 4320 chipcommon chipid */ -#define BCM4321_CHIP_ID 0x4321 /* 4321 chipcommon chipid */ -#define BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP chipid) */ -#define BCM4322_CHIP_ID 0x4322 /* 4322 chipcommon chipid */ -#define BCM43221_CHIP_ID 43221 /* 43221 chipcommon chipid (OTP chipid) */ -#define BCM43222_CHIP_ID 43222 /* 43222 chipcommon chipid */ -#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ -#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ -#define BCM43227_CHIP_ID 43227 /* 43227 chipcommon chipid */ -#define BCM43228_CHIP_ID 43228 /* 43228 chipcommon chipid */ -#define BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */ -#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (OTP chipid) */ -#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */ -#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ -#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ -#define BCM43237_CHIP_ID 43237 /* 43237 chipcommon chipid */ -#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ -#define BCM43239_CHIP_ID 43239 /* 43239 chipcommon chipid */ -#define BCM43420_CHIP_ID 43420 /* 43222 chipcommon chipid (OTP, RBBU) */ -#define BCM43421_CHIP_ID 43421 /* 43224 chipcommon chipid (OTP, RBBU) */ -#define BCM43428_CHIP_ID 43428 /* 43228 chipcommon chipid (OTP, RBBU) */ -#define BCM43431_CHIP_ID 43431 /* 4331 chipcommon chipid (OTP, RBBU) */ -#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ -#define BCM4325_CHIP_ID 0x4325 /* 4325 chip id */ -#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */ -#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ -#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ -#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ -#define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */ -#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ -#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ -#define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */ -#define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */ -#define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */ -#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */ -#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */ -#define BCM43243_CHIP_ID 43243 /* 43243 chipcommon chipid */ -#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */ -#define BCM4335_CHIP_ID 0x4335 /* 4335 chipcommon chipid */ -#define BCM4339_CHIP_ID 0x4339 /* 4339 chipcommon chipid */ -#define BCM43349_CHIP_ID 43349 /* 43349(0xA955) chipcommon chipid */ -#define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */ -#define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */ -#define BCM43526_CHIP_ID 0xAA06 -#define BCM43340_CHIP_ID 43340 /* 43340 chipcommon chipid */ -#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */ -#define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */ -#define BCM4350_CHIP_ID 0x4350 /* 4350 chipcommon chipid */ -#define BCM4354_CHIP_ID 0x4354 /* 4354 chipcommon chipid */ -#define BCM4356_CHIP_ID 0x4356 /* 4356 chipcommon chipid */ -#define BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */ -#define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */ -#define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */ -#define BCM43567_CHIP_ID 0xAA2F /* 43567 chipcommon chipid */ -#define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */ -#define BCM43569_CHIP_ID 0xAA31 /* 43569 chipcommon chipid */ -#define BCM43570_CHIP_ID 0xAA32 /* 43570 chipcommon chipid */ -#define BCM4358_CHIP_ID 0x4358 /* 4358 chipcommon chipid */ -#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \ - (CHIPID(chipid) == BCM4354_CHIP_ID) || \ - (CHIPID(chipid) == BCM4356_CHIP_ID) || \ - (CHIPID(chipid) == BCM43556_CHIP_ID) || \ - (CHIPID(chipid) == BCM43558_CHIP_ID) || \ - (CHIPID(chipid) == BCM43566_CHIP_ID) || \ - (CHIPID(chipid) == BCM43567_CHIP_ID) || \ - (CHIPID(chipid) == BCM43568_CHIP_ID) || \ - (CHIPID(chipid) == BCM43569_CHIP_ID) || \ - (CHIPID(chipid) == BCM43570_CHIP_ID) || \ - (CHIPID(chipid) == BCM4358_CHIP_ID)) /* 4350 variations */ -#define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */ -#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */ -#define BCM4349_CHIP_ID 0x4349 /* 4349 chipcommon chipid */ -#define BCM4355_CHIP_ID 0x4355 /* 4355 chipcommon chipid */ -#define BCM4359_CHIP_ID 0x4359 /* 4359 chipcommon chipid */ -#define BCM4349_CHIP(chipid) ((CHIPID(chipid) == BCM4349_CHIP_ID) || \ - (CHIPID(chipid) == BCM4355_CHIP_ID) || \ - (CHIPID(chipid) == BCM4359_CHIP_ID)) -#define BCM4349_CHIP_GRPID BCM4349_CHIP_ID: \ - case BCM4355_CHIP_ID: \ - case BCM4359_CHIP_ID - -#define BCM43602_CHIP_ID 0xaa52 /* 43602 chipcommon chipid */ -#define BCM43462_CHIP_ID 0xa9c6 /* 43462 chipcommon chipid */ - -#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */ -#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */ -#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */ -#define BCM4706_CHIP_ID 0x5300 /* 4706 chipcommon chipid */ -#define BCM4707_CHIP_ID 53010 /* 4707 chipcommon chipid */ -#define BCM53018_CHIP_ID 53018 /* 53018 chipcommon chipid */ -#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || ((chipid) == BCM53018_CHIP_ID)) -#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */ -#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */ -#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) */ -#define BCM4749_CHIP_ID 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */ -#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */ -#define BCM5350_CHIP_ID 0x5350 /* 5350 chipcommon chipid */ -#define BCM5352_CHIP_ID 0x5352 /* 5352 chipcommon chipid */ -#define BCM5354_CHIP_ID 0x5354 /* 5354 chipcommon chipid */ -#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */ -#define BCM5356_CHIP_ID 0x5356 /* 5356 chipcommon chipid */ -#define BCM5357_CHIP_ID 0x5357 /* 5357 chipcommon chipid */ -#define BCM53572_CHIP_ID 53572 /* 53572 chipcommon chipid */ - -/* Package IDs */ -#define BCM4303_PKG_ID 2 /* 4303 package id */ -#define BCM4309_PKG_ID 1 /* 4309 package id */ -#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */ -#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */ -#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */ -#define BCM4328USBD11G_PKG_ID 2 /* 4328 802.11g USB package id */ -#define BCM4328USBDUAL_PKG_ID 3 /* 4328 802.11a/g USB package id */ -#define BCM4328SDIOD11G_PKG_ID 4 /* 4328 802.11g SDIO package id */ -#define BCM4328SDIODUAL_PKG_ID 5 /* 4328 802.11a/g SDIO package id */ -#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */ -#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */ -#define BCM5354E_PKG_ID 1 /* 5354E package id */ -#define BCM4716_PKG_ID 8 /* 4716 package id */ -#define BCM4717_PKG_ID 9 /* 4717 package id */ -#define BCM4718_PKG_ID 10 /* 4718 package id */ -#define BCM5356_PKG_NONMODE 1 /* 5356 package without nmode suppport */ -#define BCM5358U_PKG_ID 8 /* 5358U package id */ -#define BCM5358_PKG_ID 9 /* 5358 package id */ -#define BCM47186_PKG_ID 10 /* 47186 package id */ -#define BCM5357_PKG_ID 11 /* 5357 package id */ -#define BCM5356U_PKG_ID 12 /* 5356U package id */ -#define BCM53572_PKG_ID 8 /* 53572 package id */ -#define BCM5357C0_PKG_ID 8 /* 5357c0 package id (the same as 53572) */ -#define BCM47188_PKG_ID 9 /* 47188 package id */ -#define BCM5358C0_PKG_ID 0xa /* 5358c0 package id */ -#define BCM5356C0_PKG_ID 0xb /* 5356c0 package id */ -#define BCM4331TT_PKG_ID 8 /* 4331 12x12 package id */ -#define BCM4331TN_PKG_ID 9 /* 4331 12x9 package id */ -#define BCM4331TNA0_PKG_ID 0xb /* 4331 12x9 package id */ -#define BCM4706L_PKG_ID 1 /* 4706L package id */ - -#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */ -#define HDLSIM_PKG_ID 14 /* HDL simulator package id */ -#define HWSIM_PKG_ID 15 /* Hardware simulator package id */ -#define BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */ -#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ -#define BCM4336_WLBGA_PKG_ID 0x8 -#define BCM4330_WLBGA_PKG_ID 0x0 -#define BCM4314PCIE_ARM_PKG_ID (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */ -#define BCM4314SDIO_PKG_ID (8 | 1) /* 4314 QFN SDIO package id */ -#define BCM4314PCIE_PKG_ID (8 | 2) /* 4314 QFN PCI (ARM-less) package id */ -#define BCM4314SDIO_ARM_PKG_ID (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */ -#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) /* 4314 FpBGA SDIO package id */ -#define BCM4314DEV_PKG_ID (8 | 6) /* 4314 Developement package id */ - -#define BCM4707_PKG_ID 1 /* 4707 package id */ -#define BCM4708_PKG_ID 2 /* 4708 package id */ -#define BCM4709_PKG_ID 0 /* 4709 package id */ - -#define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */ -#define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */ - -#define BCM4335_WLCSP_PKG_ID (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */ -#define BCM4335_FCBGA_PKG_ID (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */ -#define BCM4335_WLBGA_PKG_ID (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */ -#define BCM4335_FCBGAD_PKG_ID (0x3) /* FCBGA Debug Debug/Dev All if's. */ -#define BCM4335_PKG_MASK (0x3) - -/* boardflags */ -#define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */ -#define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */ -#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */ -#define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio 13 radio disable indication, UNUSED */ -#define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */ -#define BFL_DIS_256QAM 0x00000008 -#define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */ -#define BFL_TSSIAVG 0x00000010 /* TSSI averaging for ACPHY chips */ -#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */ -#define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */ -#define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */ -#define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */ -#define BFL_LTECOEX 0x00000200 /* LTE Coex enabled */ -#define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ -#define BFL_FEM 0x00000800 /* Board supports the Front End Module */ -#define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ -#define BFL_HGPA 0x00002000 /* Board has a high gain PA */ -#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */ -#define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */ -#define BFL_NOPA 0x00010000 /* Board has no PA */ -#define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */ -#define BFL_PAREF 0x00040000 /* Board uses the PARef LDO */ -#define BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */ -#define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */ -#define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */ -#define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */ -#define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */ -#define BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */ -#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */ -#define BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */ -#define BFL_FASTPWR 0x08000000 -#define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */ -#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ -#define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */ -#define BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ -#define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */ -#define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field - * when this flag is set - */ -#define BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */ - -/* boardflags2 */ -#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */ -#define BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ -#define BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */ -#define BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */ -#define BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */ -#define BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */ -#define BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */ -#define BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */ -#define BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace - * BFL2_BTC3WIRE - */ -#define BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */ -#define BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */ -#define BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */ -#define BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */ -#define BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ -#define BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */ -#define BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */ -#define BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */ -#define BFL2_DAC_SPUR_IMPROVEMENT 0x00008000 /* Reducing DAC Spurs */ -#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */ -#define BFL2_REDUCED_PA_TURNONTIME 0x00010000 /* Flag to reduce PA turn on Time */ -#define BFL2_IPALVLSHIFT_3P3 0x00020000 -#define BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */ -#define BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */ - /* Most drivers will turn it off without this flag */ - /* to save power. */ - -#define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */ -#define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */ -#define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */ -#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */ -#define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value - * than programmed. The exact delta is decided by - * driver per chip/boardtype. This can be used - * when tempsense qualification happens after shipment - */ -#define BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */ -#define BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */ -#define BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save */ - /* ucode control of eLNA during Tx */ -#define BFL2_4313_RADIOREG 0x10000000 - /* board rework */ -#define BFL2_DYNAMIC_VMID 0x10000000 /* enable dynamic Vmid in idle TSSI CAL for 4331 */ - -#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ -#define BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */ -#define BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */ -#define BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */ - -/* SROM 11 - 11ac boardflag definitions */ -#define BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */ -#define BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */ -#define BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ -#define BFL_SROM11_EPA_TURNON_TIME 0x00018000 /* 2 bits for different PA turn on times */ -#define BFL_SROM11_EPA_TURNON_TIME_SHIFT 15 -#define BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ -#define BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ -#define BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ -#define BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */ -#define BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */ -#define BFL2_SROM11_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ - -/* boardflags3 */ -#define BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */ -#define BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */ -#define BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */ -#define BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */ -#define BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */ -#define BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */ -#define BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */ -#define BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */ -#define BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */ -#define BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */ -#define BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */ -#define BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */ -#define BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */ -#define BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */ -#define BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */ -#define BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */ -#define BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */ -#define BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */ -#define BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */ -#define BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */ -/* acphy, to use backed off gaintbl for lte-coex */ -#define BFL3_LTECOEX_GAINTBL_EN 0x00060000 -/* acphy, to use backed off gaintbl for lte-coex */ -#define BFL3_LTECOEX_GAINTBL_EN_SHIFT 17 -#define BFL3_5G_SPUR_WAR 0x00080000 /* acphy, enable spur WAR in 5G band */ -#define BFL3_1X1_RSDB_ANT 0x01000000 /* to find if 2-ant RSDB board or 1-ant RSDB board */ -#define BFL3_1X1_RSDB_ANT_SHIFT 24 - -/* acphy: lpmode2g and lpmode_5g related boardflags */ -#define BFL3_ACPHY_LPMODE_2G 0x00300000 /* bits 20:21 for lpmode_2g choice */ -#define BFL3_ACPHY_LPMODE_2G_SHIFT 20 - -#define BFL3_ACPHY_LPMODE_5G 0x00C00000 /* bits 22:23 for lpmode_5g choice */ -#define BFL3_ACPHY_LPMODE_5G_SHIFT 22 - -#define BFL3_EXT_LPO_ISCLOCK 0x02000000 /* External LPO is clock, not x-tal */ -#define BFL3_FORCE_INT_LPO_SEL 0x04000000 /* Force internal lpo */ -#define BFL3_FORCE_EXT_LPO_SEL 0x08000000 /* Force external lpo */ - -#define BFL3_EN_BRCM_IMPBF 0x10000000 /* acphy, Allow BRCM Implicit TxBF */ -#define BFL3_AVVMID_FROM_NVRAM 0x40000000 /* Read Av Vmid from NVRAM */ -#define BFL3_VLIN_EN_FROM_NVRAM 0x80000000 /* Read Vlin En from NVRAM */ - -#define BFL3_AVVMID_FROM_NVRAM_SHIFT 30 /* Read Av Vmid from NVRAM */ -#define BFL3_VLIN_EN_FROM_NVRAM_SHIFT 31 /* Enable Vlin from NVRAM */ - - -/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */ -#define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ -#define BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */ -#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */ -#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */ -#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */ -#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */ -#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */ -#define BOARD_GPIO_12 0x1000 /* gpio 12 */ -#define BOARD_GPIO_13 0x2000 /* gpio 13 */ -#define BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */ -#define BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */ -#define BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */ -#define BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */ -#define BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */ -#define BOARD_GPIO_2_WLAN_PWR 0x04 /* throttle WLAN power on X29C board */ -#define BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */ -#define BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */ - -#define GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */ -#define GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */ -#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */ -#define GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */ -#define GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */ -#define GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */ -#define GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */ - -#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ -#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ -#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal power-up */ -#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL power-down */ - -/* power control defines */ -#define PLL_DELAY 150 /* us pll on delay */ -#define FREF_DELAY 200 /* us fref change delay */ -#define MIN_SLOW_CLK 32 /* us Slow clock period */ -#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ - - -/* 43341 Boards */ -#define BCM943341WLABGS_SSID 0x062d - -/* 43342 Boards */ -#define BCM943342FCAGBI_SSID 0x0641 - -/* 43602 Boards, unclear yet what boards will be created. */ -#define BCM943602RSVD1_SSID 0x06a5 -#define BCM943602RSVD2_SSID 0x06a6 -#define BCM943602X87 0X0133 -#define BCM943602X238 0X0132 - -/* # of GPIO pins */ -#define GPIO_NUMPINS 32 - -/* These values are used by dhd host driver. */ -#define RDL_RAM_BASE_4319 0x60000000 -#define RDL_RAM_BASE_4329 0x60000000 -#define RDL_RAM_SIZE_4319 0x48000 -#define RDL_RAM_SIZE_4329 0x48000 -#define RDL_RAM_SIZE_43236 0x70000 -#define RDL_RAM_BASE_43236 0x60000000 -#define RDL_RAM_SIZE_4328 0x60000 -#define RDL_RAM_BASE_4328 0x80000000 -#define RDL_RAM_SIZE_4322 0x60000 -#define RDL_RAM_BASE_4322 0x60000000 -#define RDL_RAM_SIZE_4360 0xA0000 -#define RDL_RAM_BASE_4360 0x60000000 -#define RDL_RAM_SIZE_43242 0x90000 -#define RDL_RAM_BASE_43242 0x60000000 -#define RDL_RAM_SIZE_43143 0x70000 -#define RDL_RAM_BASE_43143 0x60000000 -#define RDL_RAM_SIZE_4350 0xC0000 -#define RDL_RAM_BASE_4350 0x180800 - -/* generic defs for nvram "muxenab" bits -* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options. -*/ -#define MUXENAB_UART 0x00000001 -#define MUXENAB_GPIO 0x00000002 -#define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */ -#define MUXENAB_JTAG 0x00000008 -#define MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */ -#define MUXENAB_I2S_EN 0x00000020 -#define MUXENAB_I2S_MASTER 0x00000040 -#define MUXENAB_I2S_FULL 0x00000080 -#define MUXENAB_SFLASH 0x00000100 -#define MUXENAB_RFSWCTRL0 0x00000200 -#define MUXENAB_RFSWCTRL1 0x00000400 -#define MUXENAB_RFSWCTRL2 0x00000800 -#define MUXENAB_SECI 0x00001000 -#define MUXENAB_BT_LEGACY 0x00002000 -#define MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */ - -/* Boot flags */ -#define FLASH_KERNEL_NFLASH 0x00000001 -#define FLASH_BOOT_NFLASH 0x00000002 - -#endif /* _BCMDEVS_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmendian.h b/drivers/net/wireless/bcmdhd/include/bcmendian.h deleted file mode 100644 index 970989e38f6b..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmendian.h +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Byte order utilities - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmendian.h 402715 2013-05-16 18:50:09Z $ - * - * This file by default provides proper behavior on little-endian architectures. - * On big-endian architectures, IL_BIGENDIAN should be defined. - */ - -#ifndef _BCMENDIAN_H_ -#define _BCMENDIAN_H_ - -#include - -/* Reverse the bytes in a 16-bit value */ -#define BCMSWAP16(val) \ - ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ - (((uint16)(val) & (uint16)0xff00U) >> 8))) - -/* Reverse the bytes in a 32-bit value */ -#define BCMSWAP32(val) \ - ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ - (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ - (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ - (((uint32)(val) & (uint32)0xff000000U) >> 24))) - -/* Reverse the two 16-bit halves of a 32-bit value */ -#define BCMSWAP32BY16(val) \ - ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ - (((uint32)(val) & (uint32)0xffff0000U) >> 16))) - -/* Reverse the bytes in a 64-bit value */ -#define BCMSWAP64(val) \ - ((uint64)((((uint64)(val) & 0x00000000000000ffULL) << 56) | \ - (((uint64)(val) & 0x000000000000ff00ULL) << 40) | \ - (((uint64)(val) & 0x0000000000ff0000ULL) << 24) | \ - (((uint64)(val) & 0x00000000ff000000ULL) << 8) | \ - (((uint64)(val) & 0x000000ff00000000ULL) >> 8) | \ - (((uint64)(val) & 0x0000ff0000000000ULL) >> 24) | \ - (((uint64)(val) & 0x00ff000000000000ULL) >> 40) | \ - (((uint64)(val) & 0xff00000000000000ULL) >> 56))) - -/* Reverse the two 32-bit halves of a 64-bit value */ -#define BCMSWAP64BY32(val) \ - ((uint64)((((uint64)(val) & 0x00000000ffffffffULL) << 32) | \ - (((uint64)(val) & 0xffffffff00000000ULL) >> 32))) - - -/* Byte swapping macros - * Host <=> Network (Big Endian) for 16- and 32-bit values - * Host <=> Little-Endian for 16- and 32-bit values - */ -#ifndef hton16 -#define HTON16(i) BCMSWAP16(i) -#define hton16(i) bcmswap16(i) -#define HTON32(i) BCMSWAP32(i) -#define hton32(i) bcmswap32(i) -#define NTOH16(i) BCMSWAP16(i) -#define ntoh16(i) bcmswap16(i) -#define NTOH32(i) BCMSWAP32(i) -#define ntoh32(i) bcmswap32(i) -#define LTOH16(i) (i) -#define ltoh16(i) (i) -#define LTOH32(i) (i) -#define ltoh32(i) (i) -#define HTOL16(i) (i) -#define htol16(i) (i) -#define HTOL32(i) (i) -#define htol32(i) (i) -#define HTOL64(i) (i) -#define htol64(i) (i) -#endif /* hton16 */ - -#define ltoh16_buf(buf, i) -#define htol16_buf(buf, i) - -/* Unaligned loads and stores in host byte order */ -#define load32_ua(a) ltoh32_ua(a) -#define store32_ua(a, v) htol32_ua_store(v, a) -#define load16_ua(a) ltoh16_ua(a) -#define store16_ua(a, v) htol16_ua_store(v, a) - -#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) -#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) -#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) -#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) - -#define ltoh_ua(ptr) \ - (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ - sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ - sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ - *(uint8 *)0) - -#define ntoh_ua(ptr) \ - (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ - sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ - sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ - *(uint8 *)0) - -#ifdef __GNUC__ - -/* GNU macro versions avoid referencing the argument multiple times, while also - * avoiding the -fno-inline used in ROM builds. - */ - -#define bcmswap16(val) ({ \ - uint16 _val = (val); \ - BCMSWAP16(_val); \ -}) - -#define bcmswap32(val) ({ \ - uint32 _val = (val); \ - BCMSWAP32(_val); \ -}) - -#define bcmswap64(val) ({ \ - uint64 _val = (val); \ - BCMSWAP64(_val); \ -}) - -#define bcmswap32by16(val) ({ \ - uint32 _val = (val); \ - BCMSWAP32BY16(_val); \ -}) - -#define bcmswap16_buf(buf, len) ({ \ - uint16 *_buf = (uint16 *)(buf); \ - uint _wds = (len) / 2; \ - while (_wds--) { \ - *_buf = bcmswap16(*_buf); \ - _buf++; \ - } \ -}) - -#define htol16_ua_store(val, bytes) ({ \ - uint16 _val = (val); \ - uint8 *_bytes = (uint8 *)(bytes); \ - _bytes[0] = _val & 0xff; \ - _bytes[1] = _val >> 8; \ -}) - -#define htol32_ua_store(val, bytes) ({ \ - uint32 _val = (val); \ - uint8 *_bytes = (uint8 *)(bytes); \ - _bytes[0] = _val & 0xff; \ - _bytes[1] = (_val >> 8) & 0xff; \ - _bytes[2] = (_val >> 16) & 0xff; \ - _bytes[3] = _val >> 24; \ -}) - -#define hton16_ua_store(val, bytes) ({ \ - uint16 _val = (val); \ - uint8 *_bytes = (uint8 *)(bytes); \ - _bytes[0] = _val >> 8; \ - _bytes[1] = _val & 0xff; \ -}) - -#define hton32_ua_store(val, bytes) ({ \ - uint32 _val = (val); \ - uint8 *_bytes = (uint8 *)(bytes); \ - _bytes[0] = _val >> 24; \ - _bytes[1] = (_val >> 16) & 0xff; \ - _bytes[2] = (_val >> 8) & 0xff; \ - _bytes[3] = _val & 0xff; \ -}) - -#define ltoh16_ua(bytes) ({ \ - const uint8 *_bytes = (const uint8 *)(bytes); \ - _LTOH16_UA(_bytes); \ -}) - -#define ltoh32_ua(bytes) ({ \ - const uint8 *_bytes = (const uint8 *)(bytes); \ - _LTOH32_UA(_bytes); \ -}) - -#define ntoh16_ua(bytes) ({ \ - const uint8 *_bytes = (const uint8 *)(bytes); \ - _NTOH16_UA(_bytes); \ -}) - -#define ntoh32_ua(bytes) ({ \ - const uint8 *_bytes = (const uint8 *)(bytes); \ - _NTOH32_UA(_bytes); \ -}) - -#else /* !__GNUC__ */ - -/* Inline versions avoid referencing the argument multiple times */ -static INLINE uint16 -bcmswap16(uint16 val) -{ - return BCMSWAP16(val); -} - -static INLINE uint32 -bcmswap32(uint32 val) -{ - return BCMSWAP32(val); -} - -static INLINE uint64 -bcmswap64(uint64 val) -{ - return BCMSWAP64(val); -} - -static INLINE uint32 -bcmswap32by16(uint32 val) -{ - return BCMSWAP32BY16(val); -} - -/* Reverse pairs of bytes in a buffer (not for high-performance use) */ -/* buf - start of buffer of shorts to swap */ -/* len - byte length of buffer */ -static INLINE void -bcmswap16_buf(uint16 *buf, uint len) -{ - len = len / 2; - - while (len--) { - *buf = bcmswap16(*buf); - buf++; - } -} - -/* - * Store 16-bit value to unaligned little-endian byte array. - */ -static INLINE void -htol16_ua_store(uint16 val, uint8 *bytes) -{ - bytes[0] = val & 0xff; - bytes[1] = val >> 8; -} - -/* - * Store 32-bit value to unaligned little-endian byte array. - */ -static INLINE void -htol32_ua_store(uint32 val, uint8 *bytes) -{ - bytes[0] = val & 0xff; - bytes[1] = (val >> 8) & 0xff; - bytes[2] = (val >> 16) & 0xff; - bytes[3] = val >> 24; -} - -/* - * Store 16-bit value to unaligned network-(big-)endian byte array. - */ -static INLINE void -hton16_ua_store(uint16 val, uint8 *bytes) -{ - bytes[0] = val >> 8; - bytes[1] = val & 0xff; -} - -/* - * Store 32-bit value to unaligned network-(big-)endian byte array. - */ -static INLINE void -hton32_ua_store(uint32 val, uint8 *bytes) -{ - bytes[0] = val >> 24; - bytes[1] = (val >> 16) & 0xff; - bytes[2] = (val >> 8) & 0xff; - bytes[3] = val & 0xff; -} - -/* - * Load 16-bit value from unaligned little-endian byte array. - */ -static INLINE uint16 -ltoh16_ua(const void *bytes) -{ - return _LTOH16_UA((const uint8 *)bytes); -} - -/* - * Load 32-bit value from unaligned little-endian byte array. - */ -static INLINE uint32 -ltoh32_ua(const void *bytes) -{ - return _LTOH32_UA((const uint8 *)bytes); -} - -/* - * Load 16-bit value from unaligned big-(network-)endian byte array. - */ -static INLINE uint16 -ntoh16_ua(const void *bytes) -{ - return _NTOH16_UA((const uint8 *)bytes); -} - -/* - * Load 32-bit value from unaligned big-(network-)endian byte array. - */ -static INLINE uint32 -ntoh32_ua(const void *bytes) -{ - return _NTOH32_UA((const uint8 *)bytes); -} - -#endif /* !__GNUC__ */ -#endif /* !_BCMENDIAN_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h b/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h deleted file mode 100644 index 45ed9a3d846a..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h +++ /dev/null @@ -1,749 +0,0 @@ -/* - * MSGBUF network driver ioctl/indication encoding - * Broadcom 802.11abg Networking Device Driver - * - * Definitions subject to change without notice. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmmsgbuf.h 542258 2015-03-19 07:55:03Z $ - */ -#ifndef _bcmmsgbuf_h_ -#define _bcmmsgbuf_h_ -#include -#include -#include - -#define MSGBUF_MAX_MSG_SIZE ETHER_MAX_LEN - -#define D2H_EPOCH_MODULO 253 /* sequence number wrap */ -#define D2H_EPOCH_INIT_VAL (D2H_EPOCH_MODULO + 1) - -#define H2DRING_TXPOST_ITEMSIZE 48 -#define H2DRING_RXPOST_ITEMSIZE 32 -#define H2DRING_CTRL_SUB_ITEMSIZE 40 -#define D2HRING_TXCMPLT_ITEMSIZE 16 -#define D2HRING_RXCMPLT_ITEMSIZE 32 -#define D2HRING_CTRL_CMPLT_ITEMSIZE 24 - -#define H2DRING_TXPOST_MAX_ITEM 512 -#define H2DRING_RXPOST_MAX_ITEM 256 -#define H2DRING_CTRL_SUB_MAX_ITEM 128 -#define D2HRING_TXCMPLT_MAX_ITEM 1024 -#define D2HRING_RXCMPLT_MAX_ITEM 256 -#define D2HRING_CTRL_CMPLT_MAX_ITEM 128 -enum { - DNGL_TO_HOST_MSGBUF, - HOST_TO_DNGL_MSGBUF -}; - -enum { - HOST_TO_DNGL_TXP_DATA, - HOST_TO_DNGL_RXP_DATA, - HOST_TO_DNGL_CTRL, - DNGL_TO_HOST_DATA, - DNGL_TO_HOST_CTRL -}; - -#define MESSAGE_PAYLOAD(a) (a & MSG_TYPE_INTERNAL_USE_START) ? TRUE : FALSE - -#ifdef PCIE_API_REV1 - -#define BCMMSGBUF_DUMMY_REF(a, b) do {BCM_REFERENCE((a));BCM_REFERENCE((b));} while (0) - -#define BCMMSGBUF_API_IFIDX(a) 0 -#define BCMMSGBUF_API_SEQNUM(a) 0 -#define BCMMSGBUF_IOCTL_XTID(a) 0 -#define BCMMSGBUF_IOCTL_PKTID(a) ((a)->cmd_id) - -#define BCMMSGBUF_SET_API_IFIDX(a, b) BCMMSGBUF_DUMMY_REF(a, b) -#define BCMMSGBUF_SET_API_SEQNUM(a, b) BCMMSGBUF_DUMMY_REF(a, b) -#define BCMMSGBUF_IOCTL_SET_PKTID(a, b) (BCMMSGBUF_IOCTL_PKTID(a) = (b)) -#define BCMMSGBUF_IOCTL_SET_XTID(a, b) BCMMSGBUF_DUMMY_REF(a, b) - -#else /* PCIE_API_REV1 */ - -#define BCMMSGBUF_API_IFIDX(a) ((a)->if_id) -#define BCMMSGBUF_IOCTL_PKTID(a) ((a)->pkt_id) -#define BCMMSGBUF_API_SEQNUM(a) ((a)->u.seq.seq_no) -#define BCMMSGBUF_IOCTL_XTID(a) ((a)->xt_id) - -#define BCMMSGBUF_SET_API_IFIDX(a, b) (BCMMSGBUF_API_IFIDX((a)) = (b)) -#define BCMMSGBUF_SET_API_SEQNUM(a, b) (BCMMSGBUF_API_SEQNUM((a)) = (b)) -#define BCMMSGBUF_IOCTL_SET_PKTID(a, b) (BCMMSGBUF_IOCTL_PKTID((a)) = (b)) -#define BCMMSGBUF_IOCTL_SET_XTID(a, b) (BCMMSGBUF_IOCTL_XTID((a)) = (b)) - -#endif /* PCIE_API_REV1 */ - -/* utility data structures */ -union addr64 { - struct { - uint32 low; - uint32 high; - }; - struct { - uint32 low_addr; - uint32 high_addr; - }; - uint64 u64; -} DECLSPEC_ALIGN(8); - -typedef union addr64 addr64_t; - -/* IOCTL req Hdr */ -/* cmn Msg Hdr */ -typedef struct cmn_msg_hdr { - /* message type */ - uint8 msg_type; - /* interface index this is valid for */ - uint8 if_id; - /* flags */ - uint8 flags; - /* sequence number */ - uint8 epoch; - /* packet Identifier for the associated host buffer */ - uint32 request_id; -} cmn_msg_hdr_t; - -/* message type */ -typedef enum bcmpcie_msgtype { - MSG_TYPE_GEN_STATUS = 0x1, - MSG_TYPE_RING_STATUS = 0x2, - MSG_TYPE_FLOW_RING_CREATE = 0x3, - MSG_TYPE_FLOW_RING_CREATE_CMPLT = 0x4, - MSG_TYPE_FLOW_RING_DELETE = 0x5, - MSG_TYPE_FLOW_RING_DELETE_CMPLT = 0x6, - MSG_TYPE_FLOW_RING_FLUSH = 0x7, - MSG_TYPE_FLOW_RING_FLUSH_CMPLT = 0x8, - MSG_TYPE_IOCTLPTR_REQ = 0x9, - MSG_TYPE_IOCTLPTR_REQ_ACK = 0xA, - MSG_TYPE_IOCTLRESP_BUF_POST = 0xB, - MSG_TYPE_IOCTL_CMPLT = 0xC, - MSG_TYPE_EVENT_BUF_POST = 0xD, - MSG_TYPE_WL_EVENT = 0xE, - MSG_TYPE_TX_POST = 0xF, - MSG_TYPE_TX_STATUS = 0x10, - MSG_TYPE_RXBUF_POST = 0x11, - MSG_TYPE_RX_CMPLT = 0x12, - MSG_TYPE_LPBK_DMAXFER = 0x13, - MSG_TYPE_LPBK_DMAXFER_CMPLT = 0x14, - MSG_TYPE_API_MAX_RSVD = 0x3F -} bcmpcie_msg_type_t; - -typedef enum bcmpcie_msgtype_int { - MSG_TYPE_INTERNAL_USE_START = 0x40, - MSG_TYPE_EVENT_PYLD = 0x41, - MSG_TYPE_IOCT_PYLD = 0x42, - MSG_TYPE_RX_PYLD = 0x43, - MSG_TYPE_HOST_FETCH = 0x44, - MSG_TYPE_LPBK_DMAXFER_PYLD = 0x45, - MSG_TYPE_TXMETADATA_PYLD = 0x46, - MSG_TYPE_HOSTDMA_PTRS = 0x47 -} bcmpcie_msgtype_int_t; - -typedef enum bcmpcie_msgtype_u { - MSG_TYPE_TX_BATCH_POST = 0x80, - MSG_TYPE_IOCTL_REQ = 0x81, - MSG_TYPE_HOST_EVNT = 0x82, - MSG_TYPE_LOOPBACK = 0x83 -} bcmpcie_msgtype_u_t; - - -/* if_id */ -#define BCMPCIE_CMNHDR_IFIDX_PHYINTF_SHFT 5 -#define BCMPCIE_CMNHDR_IFIDX_PHYINTF_MAX 0x7 -#define BCMPCIE_CMNHDR_IFIDX_PHYINTF_MASK \ - (BCMPCIE_CMNHDR_IFIDX_PHYINTF_MAX << BCMPCIE_CMNHDR_IFIDX_PHYINTF_SHFT) -#define BCMPCIE_CMNHDR_IFIDX_VIRTINTF_SHFT 0 -#define BCMPCIE_CMNHDR_IFIDX_VIRTINTF_MAX 0x1F -#define BCMPCIE_CMNHDR_IFIDX_VIRTINTF_MASK \ - (BCMPCIE_CMNHDR_IFIDX_PHYINTF_MAX << BCMPCIE_CMNHDR_IFIDX_PHYINTF_SHFT) - -/* flags */ -#define BCMPCIE_CMNHDR_FLAGS_DMA_R_IDX 0x1 -#define BCMPCIE_CMNHDR_FLAGS_DMA_R_IDX_INTR 0x2 -#define BCMPCIE_CMNHDR_FLAGS_PHASE_BIT 0x80 - - -/* IOCTL request message */ -typedef struct ioctl_req_msg { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - - /* ioctl command type */ - uint32 cmd; - /* ioctl transaction ID, to pair with a ioctl response */ - uint16 trans_id; - /* input arguments buffer len */ - uint16 input_buf_len; - /* expected output len */ - uint16 output_buf_len; - /* to aling the host address on 8 byte boundary */ - uint16 rsvd[3]; - /* always aling on 8 byte boundary */ - addr64_t host_input_buf_addr; - /* rsvd */ - uint32 rsvd1[2]; -} ioctl_req_msg_t; - -/* buffer post messages for device to use to return IOCTL responses, Events */ -typedef struct ioctl_resp_evt_buf_post_msg { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* length of the host buffer supplied */ - uint16 host_buf_len; - /* to aling the host address on 8 byte boundary */ - uint16 reserved[3]; - /* always aling on 8 byte boundary */ - addr64_t host_buf_addr; - uint32 rsvd[4]; -} ioctl_resp_evt_buf_post_msg_t; - - -typedef struct pcie_dma_xfer_params { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - - /* always aling on 8 byte boundary */ - addr64_t host_input_buf_addr; - - /* always aling on 8 byte boundary */ - addr64_t host_ouput_buf_addr; - - /* length of transfer */ - uint32 xfer_len; - /* delay before doing the src txfer */ - uint32 srcdelay; - /* delay before doing the dest txfer */ - uint32 destdelay; - uint32 rsvd; -} pcie_dma_xfer_params_t; - -/* Complete msgbuf hdr for flow ring update from host to dongle */ -typedef struct tx_flowring_create_request { - cmn_msg_hdr_t msg; - uint8 da[ETHER_ADDR_LEN]; - uint8 sa[ETHER_ADDR_LEN]; - uint8 tid; - uint8 if_flags; - uint16 flow_ring_id; - uint8 tc; - uint8 priority; - uint16 int_vector; - uint16 max_items; - uint16 len_item; - addr64_t flow_ring_ptr; -} tx_flowring_create_request_t; - -typedef struct tx_flowring_delete_request { - cmn_msg_hdr_t msg; - uint16 flow_ring_id; - uint16 reason; - uint32 rsvd[7]; -} tx_flowring_delete_request_t; - -typedef struct tx_flowring_flush_request { - cmn_msg_hdr_t msg; - uint16 flow_ring_id; - uint16 reason; - uint32 rsvd[7]; -} tx_flowring_flush_request_t; - -typedef union ctrl_submit_item { - ioctl_req_msg_t ioctl_req; - ioctl_resp_evt_buf_post_msg_t resp_buf_post; - pcie_dma_xfer_params_t dma_xfer; - tx_flowring_create_request_t flow_create; - tx_flowring_delete_request_t flow_delete; - tx_flowring_flush_request_t flow_flush; - unsigned char check[H2DRING_CTRL_SUB_ITEMSIZE]; -} ctrl_submit_item_t; - -/* Control Completion messages (20 bytes) */ -typedef struct compl_msg_hdr { - /* status for the completion */ - int16 status; - /* submisison flow ring id which generated this status */ - uint16 flow_ring_id; -} compl_msg_hdr_t; - -/* XOR checksum or a magic number to audit DMA done */ -typedef uint32 dma_done_t; - -/* completion header status codes */ -#define BCMPCIE_SUCCESS 0 -#define BCMPCIE_NOTFOUND 1 -#define BCMPCIE_NOMEM 2 -#define BCMPCIE_BADOPTION 3 -#define BCMPCIE_RING_IN_USE 4 -#define BCMPCIE_RING_ID_INVALID 5 -#define BCMPCIE_PKT_FLUSH 6 -#define BCMPCIE_NO_EVENT_BUF 7 -#define BCMPCIE_NO_RX_BUF 8 -#define BCMPCIE_NO_IOCTLRESP_BUF 9 -#define BCMPCIE_MAX_IOCTLRESP_BUF 10 -#define BCMPCIE_MAX_EVENT_BUF 11 - -/* IOCTL completion response */ -typedef struct ioctl_compl_resp_msg { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* completion message header */ - compl_msg_hdr_t compl_hdr; - /* response buffer len where a host buffer is involved */ - uint16 resp_len; - /* transaction id to pair with a request */ - uint16 trans_id; - /* cmd id */ - uint32 cmd; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} ioctl_comp_resp_msg_t; - -/* IOCTL request acknowledgement */ -typedef struct ioctl_req_ack_msg { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* completion message header */ - compl_msg_hdr_t compl_hdr; - /* cmd id */ - uint32 cmd; - uint32 rsvd[1]; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} ioctl_req_ack_msg_t; - -/* WL event message: send from device to host */ -typedef struct wlevent_req_msg { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* completion message header */ - compl_msg_hdr_t compl_hdr; - /* event data len valid with the event buffer */ - uint16 event_data_len; - /* sequence number */ - uint16 seqnum; - /* rsvd */ - uint32 rsvd; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} wlevent_req_msg_t; - -/* dma xfer complete message */ -typedef struct pcie_dmaxfer_cmplt { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* completion message header */ - compl_msg_hdr_t compl_hdr; - uint32 rsvd[2]; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} pcie_dmaxfer_cmplt_t; - -/* general status message */ -typedef struct pcie_gen_status { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* completion message header */ - compl_msg_hdr_t compl_hdr; - uint32 rsvd[2]; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} pcie_gen_status_t; - -/* ring status message */ -typedef struct pcie_ring_status { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* completion message header */ - compl_msg_hdr_t compl_hdr; - /* message which firmware couldn't decode */ - uint16 write_idx; - uint16 rsvd[3]; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} pcie_ring_status_t; - -typedef struct tx_flowring_create_response { - cmn_msg_hdr_t msg; - compl_msg_hdr_t cmplt; - uint32 rsvd[2]; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} tx_flowring_create_response_t; -typedef struct tx_flowring_delete_response { - cmn_msg_hdr_t msg; - compl_msg_hdr_t cmplt; - uint32 rsvd[2]; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} tx_flowring_delete_response_t; - -typedef struct tx_flowring_flush_response { - cmn_msg_hdr_t msg; - compl_msg_hdr_t cmplt; - uint32 rsvd[2]; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} tx_flowring_flush_response_t; - -/* Common layout of all d2h control messages */ -typedef struct ctrl_compl_msg { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* completion message header */ - compl_msg_hdr_t compl_hdr; - uint32 rsvd[2]; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} ctrl_compl_msg_t; - -typedef union ctrl_completion_item { - ioctl_comp_resp_msg_t ioctl_resp; - wlevent_req_msg_t event; - ioctl_req_ack_msg_t ioct_ack; - pcie_dmaxfer_cmplt_t pcie_xfer_cmplt; - pcie_gen_status_t pcie_gen_status; - pcie_ring_status_t pcie_ring_status; - tx_flowring_create_response_t txfl_create_resp; - tx_flowring_delete_response_t txfl_delete_resp; - tx_flowring_flush_response_t txfl_flush_resp; - ctrl_compl_msg_t ctrl_compl; - unsigned char check[D2HRING_CTRL_CMPLT_ITEMSIZE]; -} ctrl_completion_item_t; - -/* H2D Rxpost ring work items */ -typedef struct host_rxbuf_post { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* provided meta data buffer len */ - uint16 metadata_buf_len; - /* provided data buffer len to receive data */ - uint16 data_buf_len; - /* alignment to make the host buffers start on 8 byte boundary */ - uint32 rsvd; - /* provided meta data buffer */ - addr64_t metadata_buf_addr; - /* provided data buffer to receive data */ - addr64_t data_buf_addr; -} host_rxbuf_post_t; - -typedef union rxbuf_submit_item { - host_rxbuf_post_t rxpost; - unsigned char check[H2DRING_RXPOST_ITEMSIZE]; -} rxbuf_submit_item_t; - - -/* D2H Rxcompletion ring work items */ -typedef struct host_rxbuf_cmpl { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* completion message header */ - compl_msg_hdr_t compl_hdr; - /* filled up meta data len */ - uint16 metadata_len; - /* filled up buffer len to receive data */ - uint16 data_len; - /* offset in the host rx buffer where the data starts */ - uint16 data_offset; - /* offset in the host rx buffer where the data starts */ - uint16 flags; - /* rx status */ - uint32 rx_status_0; - uint32 rx_status_1; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; -} host_rxbuf_cmpl_t; - -typedef union rxbuf_complete_item { - host_rxbuf_cmpl_t rxcmpl; - unsigned char check[D2HRING_RXCMPLT_ITEMSIZE]; -} rxbuf_complete_item_t; - - -typedef struct host_txbuf_post { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* eth header */ - uint8 txhdr[ETHER_HDR_LEN]; - /* flags */ - uint8 flags; - /* number of segments */ - uint8 seg_cnt; - - /* provided meta data buffer for txstatus */ - addr64_t metadata_buf_addr; - /* provided data buffer to receive data */ - addr64_t data_buf_addr; - /* provided meta data buffer len */ - uint16 metadata_buf_len; - /* provided data buffer len to receive data */ - uint16 data_len; - uint32 flag2; -} host_txbuf_post_t; - -#define BCMPCIE_PKT_FLAGS_FRAME_802_3 0x01 -#define BCMPCIE_PKT_FLAGS_FRAME_802_11 0x02 - -#define BCMPCIE_PKT_FLAGS_FRAME_EXEMPT_MASK 0x03 /* Exempt uses 2 bits */ -#define BCMPCIE_PKT_FLAGS_FRAME_EXEMPT_SHIFT 0x02 /* needs to be shifted past other bits */ - - -#define BCMPCIE_PKT_FLAGS_PRIO_SHIFT 5 -#define BCMPCIE_PKT_FLAGS_PRIO_MASK (7 << BCMPCIE_PKT_FLAGS_PRIO_SHIFT) - -/* These are added to fix up teh compile issues */ -#define BCMPCIE_TXPOST_FLAGS_FRAME_802_3 BCMPCIE_PKT_FLAGS_FRAME_802_3 -#define BCMPCIE_TXPOST_FLAGS_FRAME_802_11 BCMPCIE_PKT_FLAGS_FRAME_802_11 -#define BCMPCIE_TXPOST_FLAGS_PRIO_SHIFT BCMPCIE_PKT_FLAGS_PRIO_SHIFT -#define BCMPCIE_TXPOST_FLAGS_PRIO_MASK BCMPCIE_PKT_FLAGS_PRIO_MASK - -#define BCMPCIE_PKT_FLAGS2_FORCELOWRATE_MASK 0x01 -#define BCMPCIE_PKT_FLAGS2_FORCELOWRATE_SHIFT 0 - -/* H2D Txpost ring work items */ -typedef union txbuf_submit_item { - host_txbuf_post_t txpost; - unsigned char check[H2DRING_TXPOST_ITEMSIZE]; -} txbuf_submit_item_t; - -/* D2H Txcompletion ring work items */ -typedef struct host_txbuf_cmpl { - /* common message header */ - cmn_msg_hdr_t cmn_hdr; - /* completion message header */ - compl_msg_hdr_t compl_hdr; - union { - struct { - /* provided meta data len */ - uint16 metadata_len; - /* WLAN side txstatus */ - uint16 tx_status; - }; - /* XOR checksum or a magic number to audit DMA done */ - dma_done_t marker; - }; -} host_txbuf_cmpl_t; - -typedef union txbuf_complete_item { - host_txbuf_cmpl_t txcmpl; - unsigned char check[D2HRING_TXCMPLT_ITEMSIZE]; -} txbuf_complete_item_t; - -#define BCMPCIE_D2H_METADATA_HDRLEN 4 -#define BCMPCIE_D2H_METADATA_MINLEN (BCMPCIE_D2H_METADATA_HDRLEN + 4) - -/* ret buf struct */ -typedef struct ret_buf_ptr { - uint32 low_addr; - uint32 high_addr; -} ret_buf_t; - -#ifdef PCIE_API_REV1 -/* ioctl specific hdr */ -typedef struct ioctl_hdr { - uint16 cmd; - uint16 retbuf_len; - uint32 cmd_id; -} ioctl_hdr_t; -typedef struct ioctlptr_hdr { - uint16 cmd; - uint16 retbuf_len; - uint16 buflen; - uint16 rsvd; - uint32 cmd_id; -} ioctlptr_hdr_t; -#else /* PCIE_API_REV1 */ -typedef struct ioctl_req_hdr { - uint32 pkt_id; /* Packet ID */ - uint32 cmd; /* IOCTL ID */ - uint16 retbuf_len; - uint16 buflen; - uint16 xt_id; /* transaction ID */ - uint16 rsvd[1]; -} ioctl_req_hdr_t; -#endif /* PCIE_API_REV1 */ - - -/* Complete msgbuf hdr for ioctl from host to dongle */ -typedef struct ioct_reqst_hdr { - cmn_msg_hdr_t msg; -#ifdef PCIE_API_REV1 - ioctl_hdr_t ioct_hdr; -#else - ioctl_req_hdr_t ioct_hdr; -#endif - ret_buf_t ret_buf; -} ioct_reqst_hdr_t; -typedef struct ioctptr_reqst_hdr { - cmn_msg_hdr_t msg; -#ifdef PCIE_API_REV1 - ioctlptr_hdr_t ioct_hdr; -#else - ioctl_req_hdr_t ioct_hdr; -#endif - ret_buf_t ret_buf; - ret_buf_t ioct_buf; -} ioctptr_reqst_hdr_t; - -/* ioctl response header */ -typedef struct ioct_resp_hdr { - cmn_msg_hdr_t msg; -#ifdef PCIE_API_REV1 - uint32 cmd_id; -#else - uint32 pkt_id; -#endif - uint32 status; - uint32 ret_len; - uint32 inline_data; -#ifdef PCIE_API_REV1 -#else - uint16 xt_id; /* transaction ID */ - uint16 rsvd[1]; -#endif -} ioct_resp_hdr_t; - -/* ioct resp header used in dongle */ -/* ret buf hdr will be stripped off inside dongle itself */ -typedef struct msgbuf_ioctl_resp { - ioct_resp_hdr_t ioct_hdr; - ret_buf_t ret_buf; /* ret buf pointers */ -} msgbuf_ioct_resp_t; - -/* WL evet hdr info */ -typedef struct wl_event_hdr { - cmn_msg_hdr_t msg; - uint16 event; - uint8 flags; - uint8 rsvd; - uint16 retbuf_len; - uint16 rsvd1; - uint32 rxbufid; -} wl_event_hdr_t; - -#define TXDESCR_FLOWID_PCIELPBK_1 0xFF -#define TXDESCR_FLOWID_PCIELPBK_2 0xFE - -typedef struct txbatch_lenptr_tup { - uint32 pktid; - uint16 pktlen; - uint16 rsvd; - ret_buf_t ret_buf; /* ret buf pointers */ -} txbatch_lenptr_tup_t; - -typedef struct txbatch_cmn_msghdr { - cmn_msg_hdr_t msg; - uint8 priority; - uint8 hdrlen; - uint8 pktcnt; - uint8 flowid; - uint8 txhdr[ETHER_HDR_LEN]; - uint16 rsvd; -} txbatch_cmn_msghdr_t; - -typedef struct txbatch_msghdr { - txbatch_cmn_msghdr_t txcmn; - txbatch_lenptr_tup_t tx_tup[0]; /* Based on packet count */ -} txbatch_msghdr_t; - -/* TX desc posting header */ -typedef struct tx_lenptr_tup { - uint16 pktlen; - uint16 rsvd; - ret_buf_t ret_buf; /* ret buf pointers */ -} tx_lenptr_tup_t; - -typedef struct txdescr_cmn_msghdr { - cmn_msg_hdr_t msg; - uint8 priority; - uint8 hdrlen; - uint8 descrcnt; - uint8 flowid; - uint32 pktid; -} txdescr_cmn_msghdr_t; - -typedef struct txdescr_msghdr { - txdescr_cmn_msghdr_t txcmn; - uint8 txhdr[ETHER_HDR_LEN]; - uint16 rsvd; - tx_lenptr_tup_t tx_tup[0]; /* Based on descriptor count */ -} txdescr_msghdr_t; - -/* Tx status header info */ -typedef struct txstatus_hdr { - cmn_msg_hdr_t msg; - uint32 pktid; -} txstatus_hdr_t; -/* RX bufid-len-ptr tuple */ -typedef struct rx_lenptr_tup { - uint32 rxbufid; - uint16 len; - uint16 rsvd2; - ret_buf_t ret_buf; /* ret buf pointers */ -} rx_lenptr_tup_t; -/* Rx descr Post hdr info */ -typedef struct rxdesc_msghdr { - cmn_msg_hdr_t msg; - uint16 rsvd0; - uint8 rsvd1; - uint8 descnt; - rx_lenptr_tup_t rx_tup[0]; -} rxdesc_msghdr_t; - -/* RX complete tuples */ -typedef struct rxcmplt_tup { - uint16 retbuf_len; - uint16 data_offset; - uint32 rxstatus0; - uint32 rxstatus1; - uint32 rxbufid; -} rxcmplt_tup_t; -/* RX complete messge hdr */ -typedef struct rxcmplt_hdr { - cmn_msg_hdr_t msg; - uint16 rsvd0; - uint16 rxcmpltcnt; - rxcmplt_tup_t rx_tup[0]; -} rxcmplt_hdr_t; -typedef struct hostevent_hdr { - cmn_msg_hdr_t msg; - uint32 evnt_pyld; -} hostevent_hdr_t; - -typedef struct dma_xfer_params { - uint32 src_physaddr_hi; - uint32 src_physaddr_lo; - uint32 dest_physaddr_hi; - uint32 dest_physaddr_lo; - uint32 len; - uint32 srcdelay; - uint32 destdelay; -} dma_xfer_params_t; - -enum { - HOST_EVENT_CONS_CMD = 1 -}; - -/* defines for flags */ -#define MSGBUF_IOC_ACTION_MASK 0x1 - -#endif /* _bcmmsgbuf_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmnvram.h b/drivers/net/wireless/bcmdhd/include/bcmnvram.h deleted file mode 100644 index 3fbc303bd528..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmnvram.h +++ /dev/null @@ -1,272 +0,0 @@ -/* - * NVRAM variable manipulation - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmnvram.h 428512 2013-10-09 02:12:11Z $ - */ - -#ifndef _bcmnvram_h_ -#define _bcmnvram_h_ - -#ifndef _LANGUAGE_ASSEMBLY - -#include -#include - -struct nvram_header { - uint32 magic; - uint32 len; - uint32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ - uint32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ - uint32 config_ncdl; /* ncdl values for memc */ -}; - -struct nvram_tuple { - char *name; - char *value; - struct nvram_tuple *next; -}; - -/* - * Get default value for an NVRAM variable - */ -extern char *nvram_default_get(const char *name); -/* - * validate/restore all per-interface related variables - */ -extern void nvram_validate_all(char *prefix, bool restore); - -/* - * restore specific per-interface variable - */ -extern void nvram_restore_var(char *prefix, char *name); - -/* - * Initialize NVRAM access. May be unnecessary or undefined on certain - * platforms. - */ -extern int nvram_init(void *sih); -extern int nvram_deinit(void *sih); - - -/* - * Append a chunk of nvram variables to the global list - */ -extern int nvram_append(void *si, char *vars, uint varsz); - -extern void nvram_get_global_vars(char **varlst, uint *varsz); - - -/* - * Check for reset button press for restoring factory defaults. - */ -extern int nvram_reset(void *sih); - -/* - * Disable NVRAM access. May be unnecessary or undefined on certain - * platforms. - */ -extern void nvram_exit(void *sih); - -/* - * Get the value of an NVRAM variable. The pointer returned may be - * invalid after a set. - * @param name name of variable to get - * @return value of variable or NULL if undefined - */ -extern char * nvram_get(const char *name); - -/* - * Read the reset GPIO value from the nvram and set the GPIO - * as input - */ -extern int nvram_resetgpio_init(void *sih); - -/* - * Get the value of an NVRAM variable. - * @param name name of variable to get - * @return value of variable or NUL if undefined - */ -static INLINE char * -nvram_safe_get(const char *name) -{ - char *p = nvram_get(name); - return p ? p : ""; -} - -/* - * Match an NVRAM variable. - * @param name name of variable to match - * @param match value to compare against value of variable - * @return TRUE if variable is defined and its value is string equal - * to match or FALSE otherwise - */ -static INLINE int -nvram_match(const char *name, const char *match) -{ - const char *value = nvram_get(name); - return (value && !strcmp(value, match)); -} - -/* - * Inversely match an NVRAM variable. - * @param name name of variable to match - * @param match value to compare against value of variable - * @return TRUE if variable is defined and its value is not string - * equal to invmatch or FALSE otherwise - */ -static INLINE int -nvram_invmatch(const char *name, const char *invmatch) -{ - const char *value = nvram_get(name); - return (value && strcmp(value, invmatch)); -} - -/* - * Set the value of an NVRAM variable. The name and value strings are - * copied into private storage. Pointers to previously set values - * may become invalid. The new value may be immediately - * retrieved but will not be permanently stored until a commit. - * @param name name of variable to set - * @param value value of variable - * @return 0 on success and errno on failure - */ -extern int nvram_set(const char *name, const char *value); - -/* - * Unset an NVRAM variable. Pointers to previously set values - * remain valid until a set. - * @param name name of variable to unset - * @return 0 on success and errno on failure - * NOTE: use nvram_commit to commit this change to flash. - */ -extern int nvram_unset(const char *name); - -/* - * Commit NVRAM variables to permanent storage. All pointers to values - * may be invalid after a commit. - * NVRAM values are undefined after a commit. - * @param nvram_corrupt true to corrupt nvram, false otherwise. - * @return 0 on success and errno on failure - */ -extern int nvram_commit_internal(bool nvram_corrupt); - -/* - * Commit NVRAM variables to permanent storage. All pointers to values - * may be invalid after a commit. - * NVRAM values are undefined after a commit. - * @return 0 on success and errno on failure - */ -extern int nvram_commit(void); - -/* - * Get all NVRAM variables (format name=value\0 ... \0\0). - * @param buf buffer to store variables - * @param count size of buffer in bytes - * @return 0 on success and errno on failure - */ -extern int nvram_getall(char *nvram_buf, int count); - -/* - * returns the crc value of the nvram - * @param nvh nvram header pointer - */ -uint8 nvram_calc_crc(struct nvram_header * nvh); - -extern int nvram_space; -#endif /* _LANGUAGE_ASSEMBLY */ - -/* The NVRAM version number stored as an NVRAM variable */ -#define NVRAM_SOFTWARE_VERSION "1" - -#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */ -#define NVRAM_CLEAR_MAGIC 0x0 -#define NVRAM_INVALID_MAGIC 0xFFFFFFFF -#define NVRAM_VERSION 1 -#define NVRAM_HEADER_SIZE 20 -/* This definition is for precommit staging, and will be removed */ -#define NVRAM_SPACE 0x8000 -/* For CFE builds this gets passed in thru the makefile */ -#ifndef MAX_NVRAM_SPACE -#define MAX_NVRAM_SPACE 0x10000 -#endif -#define DEF_NVRAM_SPACE 0x8000 -#define ROM_ENVRAM_SPACE 0x1000 -#define NVRAM_LZMA_MAGIC 0x4c5a4d41 /* 'LZMA' */ - -#define NVRAM_MAX_VALUE_LEN 255 -#define NVRAM_MAX_PARAM_LEN 64 - -#define NVRAM_CRC_START_POSITION 9 /* magic, len, crc8 to be skipped */ -#define NVRAM_CRC_VER_MASK 0xffffff00 /* for crc_ver_init */ - -/* Offsets to embedded nvram area */ -#define NVRAM_START_COMPRESSED 0x400 -#define NVRAM_START 0x1000 - -#define BCM_JUMBO_NVRAM_DELIMIT '\n' -#define BCM_JUMBO_START "Broadcom Jumbo Nvram file" - - -#if (defined(FAILSAFE_UPGRADE) || defined(CONFIG_FAILSAFE_UPGRADE) || \ - defined(__CONFIG_FAILSAFE_UPGRADE_SUPPORT__)) -#define IMAGE_SIZE "image_size" -#define BOOTPARTITION "bootpartition" -#define IMAGE_BOOT BOOTPARTITION -#define PARTIALBOOTS "partialboots" -#define MAXPARTIALBOOTS "maxpartialboots" -#define IMAGE_1ST_FLASH_TRX "flash0.trx" -#define IMAGE_1ST_FLASH_OS "flash0.os" -#define IMAGE_2ND_FLASH_TRX "flash0.trx2" -#define IMAGE_2ND_FLASH_OS "flash0.os2" -#define IMAGE_FIRST_OFFSET "image_first_offset" -#define IMAGE_SECOND_OFFSET "image_second_offset" -#define LINUX_FIRST "linux" -#define LINUX_SECOND "linux2" -#endif - -#if (defined(DUAL_IMAGE) || defined(CONFIG_DUAL_IMAGE) || \ - defined(__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__)) -/* Shared by all: CFE, Linux Kernel, and Ap */ -#define IMAGE_BOOT "image_boot" -#define BOOTPARTITION IMAGE_BOOT -/* CFE variables */ -#define IMAGE_1ST_FLASH_TRX "flash0.trx" -#define IMAGE_1ST_FLASH_OS "flash0.os" -#define IMAGE_2ND_FLASH_TRX "flash0.trx2" -#define IMAGE_2ND_FLASH_OS "flash0.os2" -#define IMAGE_SIZE "image_size" - -/* CFE and Linux Kernel shared variables */ -#define IMAGE_FIRST_OFFSET "image_first_offset" -#define IMAGE_SECOND_OFFSET "image_second_offset" - -/* Linux application variables */ -#define LINUX_FIRST "linux" -#define LINUX_SECOND "linux2" -#define POLICY_TOGGLE "toggle" -#define LINUX_PART_TO_FLASH "linux_to_flash" -#define LINUX_FLASH_POLICY "linux_flash_policy" - -#endif /* defined(DUAL_IMAGE||CONFIG_DUAL_IMAGE)||__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__ */ - -#endif /* _bcmnvram_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcie.h b/drivers/net/wireless/bcmdhd/include/bcmpcie.h deleted file mode 100644 index 55a763d6793f..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmpcie.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Broadcom PCIE - * Software-specific definitions shared between device and host side - * Explains the shared area between host and dongle - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmpcie.h 627710 2016-03-28 07:09:41Z $ - */ - -#ifndef _bcmpcie_h_ -#define _bcmpcie_h_ - -#include - -#define ADDR_64(x) (x.addr) -#define HIGH_ADDR_32(x) ((uint32) (((sh_addr_t) x).high_addr)) -#define LOW_ADDR_32(x) ((uint32) (((sh_addr_t) x).low_addr)) - -typedef struct { - uint32 low_addr; - uint32 high_addr; -} sh_addr_t; - - - -#ifdef BCMPCIE_SUPPORT_TX_PUSH_RING -#define BCMPCIE_PUSH_TX_RING 1 -#else -#define BCMPCIE_PUSH_TX_RING 0 -#endif /* BCMPCIE_SUPPORT_TX_PUSH_RING */ - -/* May be overridden by 43xxxxx-roml.mk */ -#if !defined(BCMPCIE_MAX_TX_FLOWS) -#define BCMPCIE_MAX_TX_FLOWS 40 -#endif /* ! BCMPCIE_MAX_TX_FLOWS */ - -#define PCIE_SHARED_VERSION 0x00005 -#define PCIE_SHARED_VERSION_MASK 0x000FF -#define PCIE_SHARED_ASSERT_BUILT 0x00100 -#define PCIE_SHARED_ASSERT 0x00200 -#define PCIE_SHARED_TRAP 0x00400 -#define PCIE_SHARED_IN_BRPT 0x00800 -#define PCIE_SHARED_SET_BRPT 0x01000 -#define PCIE_SHARED_PENDING_BRPT 0x02000 -#define PCIE_SHARED_TXPUSH_SPRT 0x04000 -#define PCIE_SHARED_EVT_SEQNUM 0x08000 -#define PCIE_SHARED_DMA_INDEX 0x10000 - -/* D2H M2M DMA Complete Sync mechanism: Modulo-253-SeqNum or XORCSUM */ -#define PCIE_SHARED_D2H_SYNC_SEQNUM 0x20000 -#define PCIE_SHARED_D2H_SYNC_XORCSUM 0x40000 -#define PCIE_SHARED_D2H_SYNC_MODE_MASK \ - (PCIE_SHARED_D2H_SYNC_SEQNUM | PCIE_SHARED_D2H_SYNC_XORCSUM) - -#define BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT 0 -#define BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT 1 -#define BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE 2 -#define BCMPCIE_D2H_MSGRING_TX_COMPLETE 3 -#define BCMPCIE_D2H_MSGRING_RX_COMPLETE 4 -#define BCMPCIE_COMMON_MSGRING_MAX_ID 4 - -/* Added only for single tx ring */ -#define BCMPCIE_H2D_TXFLOWRINGID 5 - -#define BCMPCIE_H2D_COMMON_MSGRINGS 2 -#define BCMPCIE_D2H_COMMON_MSGRINGS 3 -#define BCMPCIE_COMMON_MSGRINGS 5 - -enum h2dring_idx { - BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT_IDX = 0, - BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT_IDX = 1, - BCMPCIE_H2D_MSGRING_TXFLOW_IDX_START = 2 -}; - -enum d2hring_idx { - BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE_IDX = 0, - BCMPCIE_D2H_MSGRING_TX_COMPLETE_IDX = 1, - BCMPCIE_D2H_MSGRING_RX_COMPLETE_IDX = 2 -}; - -typedef struct ring_mem { - uint16 idx; - uint8 type; - uint8 rsvd; - uint16 max_item; - uint16 len_items; - sh_addr_t base_addr; -} ring_mem_t; - -#define RINGSTATE_INITED 1 - -typedef struct ring_state { - uint8 idx; - uint8 state; - uint16 r_offset; - uint16 w_offset; - uint16 e_offset; -} ring_state_t; - - - -typedef struct ring_info { - /* locations in the TCM where the ringmem is and ringstate are defined */ - uint32 ringmem_ptr; /* ring mem location in TCM */ - uint32 h2d_w_idx_ptr; - - uint32 h2d_r_idx_ptr; - uint32 d2h_w_idx_ptr; - - uint32 d2h_r_idx_ptr; - /* host locations where the DMA of read/write indices are */ - sh_addr_t h2d_w_idx_hostaddr; - sh_addr_t h2d_r_idx_hostaddr; - sh_addr_t d2h_w_idx_hostaddr; - sh_addr_t d2h_r_idx_hostaddr; - uint16 max_sub_queues; - uint16 rsvd; -} ring_info_t; - -typedef struct { - /* shared area version captured at flags 7:0 */ - uint32 flags; - - uint32 trap_addr; - uint32 assert_exp_addr; - uint32 assert_file_addr; - uint32 assert_line; - uint32 console_addr; /* Address of hnd_cons_t */ - - uint32 msgtrace_addr; - - uint32 fwid; - - /* Used for debug/flow control */ - uint16 total_lfrag_pkt_cnt; - uint16 max_host_rxbufs; /* rsvd in spec */ - - uint32 dma_rxoffset; /* rsvd in spec */ - - /* these will be used for sleep request/ack, d3 req/ack */ - uint32 h2d_mb_data_ptr; - uint32 d2h_mb_data_ptr; - - /* information pertinent to host IPC/msgbuf channels */ - /* location in the TCM memory which has the ring_info */ - uint32 rings_info_ptr; - - /* block of host memory for the scratch buffer */ - uint32 host_dma_scratch_buffer_len; - sh_addr_t host_dma_scratch_buffer; - - /* block of host memory for the dongle to push the status into */ - uint32 device_rings_stsblk_len; - sh_addr_t device_rings_stsblk; -#ifdef BCM_BUZZZ - uint32 buzzz; /* BUZZZ state format strings and trace buffer */ -#endif -} pciedev_shared_t; - - -/* H2D mail box Data */ -#define H2D_HOST_D3_INFORM 0x00000001 -#define H2D_HOST_DS_ACK 0x00000002 -#define H2D_HOST_CONS_INT 0x80000000 /* h2d int for console cmds */ - -#define H2D_HOST_D0_INFORM_IN_USE 0x00000008 -#define H2D_HOST_D0_INFORM 0x00000010 - -/* D2H mail box Data */ -#define D2H_DEV_D3_ACK 0x00000001 -#define D2H_DEV_DS_ENTER_REQ 0x00000002 -#define D2H_DEV_DS_EXIT_NOTE 0x00000004 -#define D2H_DEV_FWHALT 0x10000000 -#define D2H_DEV_MB_MASK (D2H_DEV_D3_ACK | D2H_DEV_DS_ENTER_REQ | \ - D2H_DEV_DS_EXIT_NOTE | D2H_DEV_FWHALT) -#define D2H_DEV_MB_INVALIDATED(x) ((!x) || (x & ~D2H_DEV_MB_MASK)) - - -extern pciedev_shared_t pciedev_shared; -#define NEXTTXP(i, d) ((((i)+1) >= (d)) ? 0 : ((i)+1)) -#define NTXPACTIVE(r, w, d) (((r) <= (w)) ? ((w)-(r)) : ((d)-(r)+(w))) -#define NTXPAVAIL(r, w, d) (((d) - NTXPACTIVE((r), (w), (d))) > 1) - -/* Function can be used to notify host of FW halt */ -#define READ_AVAIL_SPACE(w, r, d) \ - ((w >= r) ? (w - r) : (d - r)) - -#define WRT_PEND(x) ((x)->wr_pending) -#define DNGL_RING_WPTR(msgbuf) (*((msgbuf)->tcm_rs_w_ptr)) -#define BCMMSGBUF_RING_SET_W_PTR(msgbuf, a) (DNGL_RING_WPTR(msgbuf) = (a)) - -#define DNGL_RING_RPTR(msgbuf) (*((msgbuf)->tcm_rs_r_ptr)) -#define BCMMSGBUF_RING_SET_R_PTR(msgbuf, a) (DNGL_RING_RPTR(msgbuf) = (a)) - -#define RING_READ_PTR(x) ((x)->ringstate->r_offset) -#define RING_WRITE_PTR(x) ((x)->ringstate->w_offset) -#define RING_START_PTR(x) ((x)->ringmem->base_addr.low_addr) -#define RING_MAX_ITEM(x) ((x)->ringmem->max_item) -#define RING_LEN_ITEMS(x) ((x)->ringmem->len_items) -#define HOST_RING_BASE(x) ((x)->ring_base.va) -#define HOST_RING_END(x) ((uint8 *)HOST_RING_BASE((x)) + \ - ((RING_MAX_ITEM((x))-1)*RING_LEN_ITEMS((x)))) - -#define WRITE_SPACE_AVAIL_CONTINUOUS(r, w, d) ((w >= r) ? (d - w) : (r - w)) -#define WRITE_SPACE_AVAIL(r, w, d) (d - (NTXPACTIVE(r, w, d)) - 1) -#define CHECK_WRITE_SPACE(r, w, d) \ - MIN(WRITE_SPACE_AVAIL(r, w, d), WRITE_SPACE_AVAIL_CONTINUOUS(r, w, d)) - -#endif /* _bcmpcie_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h deleted file mode 100644 index d4781abb982a..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Broadcom PCI-SPI Host Controller Register Definitions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmpcispi.h 241182 2011-02-17 21:50:03Z $ - */ -#ifndef _BCM_PCI_SPI_H -#define _BCM_PCI_SPI_H - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - - -typedef volatile struct { - uint32 spih_ctrl; /* 0x00 SPI Control Register */ - uint32 spih_stat; /* 0x04 SPI Status Register */ - uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ - uint32 spih_ext; /* 0x0C SPI Extension Register */ - uint32 PAD[4]; /* 0x10-0x1F PADDING */ - - uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ - uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ - uint32 PAD[6]; /* 0x28-0x3F PADDING */ - - uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ - uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ - /* 1=Active High) */ - uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ - uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ - uint32 PAD[4]; /* 0x50-0x5F PADDING */ - - uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ - uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ - uint32 PAD[1]; /* 0x68 PADDING */ - uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ - uint32 PAD[4]; /* 0x70-0x7F PADDING */ - uint32 PAD[8]; /* 0x80-0x9F PADDING */ - uint32 PAD[8]; /* 0xA0-0xBF PADDING */ - uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ - uint32 spih_pll_status; /* 0xC4 PLL Status Register */ - uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ - uint32 spih_clk_count; /* 0xCC External Clock Count Register */ - -} spih_regs_t; - -typedef volatile struct { - uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ - uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ - - uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ - uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ - uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ - uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ - uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ - uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ - uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ - uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ - uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ - uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ - uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ - uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ - uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ - uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ - uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ - uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ - uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ - uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ - uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ - uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ - uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ - uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ - uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ - uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ - uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ - uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ - - uint32 PAD[5]; /* 0x16C-0x17F PADDING */ - - uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ - uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ - uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ - uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ - uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ - uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ - uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ - uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ - uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ - uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ - uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ - uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ - uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ - uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ - uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ - uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ - uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ - uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ - uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ - uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ - uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ - uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ - uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ - uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ - uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ - uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ - - uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ - uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ - uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ -} spih_pciregs_t; - -/* - * PCI Core interrupt enable and status bit definitions. - */ - -/* PCI Core ICR Register bit definitions */ -#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ -#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ -#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ -#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ -#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ -#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ - - -/* PCI Core ISR Register bit definitions */ -#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ -#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ -#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ -#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ -#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ - - -/* Registers on the Wishbone bus */ -#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ -#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ -#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ - -/* GPIO Bit definitions */ -#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ -#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ -#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ - -/* SPI Status Register Bit definitions */ -#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ -#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ -#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ -#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ -#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ -#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ - -#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ - -#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ -#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ - -/* Spin bit loop bound check */ -#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ - -#endif /* _BCM_PCI_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmperf.h b/drivers/net/wireless/bcmdhd/include/bcmperf.h deleted file mode 100644 index 84c232f8a059..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmperf.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Performance counters software interface. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmperf.h 241182 2011-02-17 21:50:03Z $ - */ -/* essai */ -#ifndef _BCMPERF_H_ -#define _BCMPERF_H_ -/* get cache hits and misses */ -#define BCMPERF_ENABLE_INSTRCOUNT() -#define BCMPERF_ENABLE_ICACHE_MISS() -#define BCMPERF_ENABLE_ICACHE_HIT() -#define BCMPERF_GETICACHE_MISS(x) ((x) = 0) -#define BCMPERF_GETICACHE_HIT(x) ((x) = 0) -#define BCMPERF_GETINSTRCOUNT(x) ((x) = 0) -#endif /* _BCMPERF_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h deleted file mode 100644 index 4d4634ba6585..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Definitions for API from sdio common code (bcmsdh) to individual - * host controller drivers. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdbus.h 408158 2013-06-17 22:15:35Z $ - */ - -#ifndef _sdio_api_h_ -#define _sdio_api_h_ - - -#define SDIOH_API_RC_SUCCESS (0x00) -#define SDIOH_API_RC_FAIL (0x01) -#define SDIOH_API_SUCCESS(status) (status == 0) - -#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 */ - -#define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */ -#define SDIOH_CMD_TYPE_APPEND 1 /* Append command */ -#define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */ - -#define SDIOH_DATA_PIO 0 /* PIO mode */ -#define SDIOH_DATA_DMA 1 /* DMA mode */ - -/* Max number of glommed pkts */ -#ifdef CUSTOM_MAX_TXGLOM_SIZE -#define SDPCM_MAXGLOM_SIZE CUSTOM_MAX_TXGLOM_SIZE -#else -#define SDPCM_MAXGLOM_SIZE 40 -#endif /* CUSTOM_MAX_TXGLOM_SIZE */ - -#define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ -#define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ - -#ifdef CUSTOM_DEF_TXGLOM_SIZE -#define SDPCM_DEFGLOM_SIZE CUSTOM_DEF_TXGLOM_SIZE -#else -#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE -#endif /* CUSTOM_DEF_TXGLOM_SIZE */ - -#if SDPCM_DEFGLOM_SIZE > SDPCM_MAXGLOM_SIZE -#warning "SDPCM_DEFGLOM_SIZE cannot be higher than SDPCM_MAXGLOM_SIZE!!" -#undef SDPCM_DEFGLOM_SIZE -#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE -#endif - -typedef int SDIOH_API_RC; - -/* SDio Host structure */ -typedef struct sdioh_info sdioh_info_t; - -/* callback function, taking one arg */ -typedef void (*sdioh_cb_fn_t)(void *); - -extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); -extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); - -/* query whether SD interrupt is enabled or not */ -extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff); - -/* enable or disable SD interrupt */ -extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); - -#if defined(DHD_DEBUG) -extern bool sdioh_interrupt_pending(sdioh_info_t *si); -#endif - -/* read or write one byte using cmd52 */ -extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte); - -/* read or write 2/4 bytes using cmd53 */ -extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *si, uint cmd_type, uint rw, uint fnc, - uint addr, uint32 *word, uint nbyte); - -/* read or write any buffer using cmd53 */ -extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc, - uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer, - void *pkt); - -/* get cis data */ -extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); - -extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); -extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); - -/* query number of io functions */ -extern uint sdioh_query_iofnum(sdioh_info_t *si); - -/* handle iovars */ -extern int sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Issue abort to the specified function and clear controller as needed */ -extern int sdioh_abort(sdioh_info_t *si, uint fnc); - -/* Start and Stop SDIO without re-enumerating the SD card. */ -extern int sdioh_start(sdioh_info_t *si, int stage); -extern int sdioh_stop(sdioh_info_t *si); - -/* Wait system lock free */ -extern int sdioh_waitlockfree(sdioh_info_t *si); - -/* Reset and re-initialize the device */ -extern int sdioh_sdio_reset(sdioh_info_t *si); - - - -#if defined(BCMSDIOH_STD) - #define SDIOH_SLEEP_ENABLED -#endif -extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab); - -/* GPIO support */ -extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd); -extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio); -extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio); -extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab); - -#endif /* _sdio_api_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd/include/bcmsdh.h deleted file mode 100644 index 4ff425e350c8..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * SDIO host client driver interface of Broadcom HNBU - * export functions to client drivers - * abstract OS and BUS specific details of SDIO - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh.h 450676 2014-01-22 22:45:13Z $ - */ - -/** - * @file bcmsdh.h - */ - -#ifndef _bcmsdh_h_ -#define _bcmsdh_h_ - -#define BCMSDH_ERROR_VAL 0x0001 /* Error */ -#define BCMSDH_INFO_VAL 0x0002 /* Info */ -extern const uint bcmsdh_msglevel; - -#define BCMSDH_ERROR(x) -#define BCMSDH_INFO(x) - -#if defined(BCMSDIO) && (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || \ - defined(BCMSDIOH_SPI)) -#define BCMSDH_ADAPTER -#endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */ - -/* forward declarations */ -typedef struct bcmsdh_info bcmsdh_info_t; -typedef void (*bcmsdh_cb_fn_t)(void *); - -extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva); -/** - * BCMSDH API context - */ -struct bcmsdh_info -{ - bool init_success; /* underlying driver successfully attached */ - void *sdioh; /* handler for sdioh */ - uint32 vendevid; /* Target Vendor and Device ID on SD bus */ - osl_t *osh; - bool regfail; /* Save status of last reg_read/reg_write call */ - uint32 sbwad; /* Save backplane window address */ - void *os_cxt; /* Pointer to per-OS private data */ -}; - -/* Detach - freeup resources allocated in attach */ -extern int bcmsdh_detach(osl_t *osh, void *sdh); - -/* Query if SD device interrupts are enabled */ -extern bool bcmsdh_intr_query(void *sdh); - -/* Enable/disable SD interrupt */ -extern int bcmsdh_intr_enable(void *sdh); -extern int bcmsdh_intr_disable(void *sdh); - -/* Register/deregister device interrupt handler. */ -extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); -extern int bcmsdh_intr_dereg(void *sdh); -/* Enable/disable SD card interrupt forward */ -extern void bcmsdh_intr_forward(void *sdh, bool pass); - -#if defined(DHD_DEBUG) -/* Query pending interrupt status from the host controller */ -extern bool bcmsdh_intr_pending(void *sdh); -#endif - -/* Register a callback to be called if and when bcmsdh detects - * device removal. No-op in the case of non-removable/hardwired devices. - */ -extern int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); - -/* 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 uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err); -extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err); - -/* Read/Write 4bytes from/to cfg space */ -extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err); -extern void bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err); - -/* Read CIS content for specified function. - * fn: function whose CIS is being requested (0 is common CIS) - * cis: pointer to memory location to place results - * length: number of bytes to read - * Internally, this routine uses the values from the cis base regs (0x9-0xB) - * to form an SDIO-space address to read the data from. - */ -extern int bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length); - -/* 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 uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size); -extern uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data); - -/* set sb address window */ -extern int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set); - -/* Indicate if last reg read/write failed */ -extern bool bcmsdh_regfail(void *sdh); - -/* 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. - */ -typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting); -extern int bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete_fn, void *handle); -extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete_fn, void *handle); - -extern void bcmsdh_glom_post(void *sdh, uint8 *frame, void *pkt, uint len); -extern void bcmsdh_glom_clear(void *sdh); -extern uint bcmsdh_set_mode(void *sdh, uint mode); -extern bool bcmsdh_glom_enabled(void); -/* Flags bits */ -#define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */ -#define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */ -#define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */ -#define SDIO_BYTE_MODE 0x8 /* Byte mode request(non-block mode) */ - -/* Pending (non-error) return code */ -#define BCME_PENDING 1 - -/* 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 bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes); - -/* Issue an abort to the specified function */ -extern int bcmsdh_abort(void *sdh, uint fn); - -/* Start SDIO Host Controller communication */ -extern int bcmsdh_start(void *sdh, int stage); - -/* Stop SDIO Host Controller communication */ -extern int bcmsdh_stop(void *sdh); - -/* Wait system lock free */ -extern int bcmsdh_waitlockfree(void *sdh); - -/* Returns the "Device ID" of target device on the SDIO bus. */ -extern int bcmsdh_query_device(void *sdh); - -/* Returns the number of IO functions reported by the device */ -extern uint bcmsdh_query_iofnum(void *sdh); - -/* Miscellaneous knob tweaker. */ -extern int bcmsdh_iovar_op(void *sdh, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Reset and reinitialize the device */ -extern int bcmsdh_reset(bcmsdh_info_t *sdh); - -/* helper functions */ - -/* callback functions */ -typedef struct { - /* probe the device */ - void *(*probe)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot, - uint16 func, uint bustype, void * regsva, osl_t * osh, - void * param); - /* remove the device */ - void (*remove)(void *context); - /* can we suspend now */ - int (*suspend)(void *context); - /* resume from suspend */ - int (*resume)(void *context); -} bcmsdh_driver_t; - -/* platform specific/high level functions */ -extern int bcmsdh_register(bcmsdh_driver_t *driver); -extern void bcmsdh_unregister(void); -extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device); -extern void bcmsdh_device_remove(void * sdh); - -extern int bcmsdh_reg_sdio_notify(void* semaphore); -extern void bcmsdh_unreg_sdio_notify(void); - -#if defined(OOB_INTR_ONLY) -extern int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, - void* oob_irq_handler_context); -extern void bcmsdh_oob_intr_unregister(bcmsdh_info_t *sdh); -extern void bcmsdh_oob_intr_set(bcmsdh_info_t *sdh, bool enable); -#endif -extern void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *sdh); -extern void bcmsdh_dev_relax(bcmsdh_info_t *sdh); -extern bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *sdh); - -int bcmsdh_suspend(bcmsdh_info_t *bcmsdh); -int bcmsdh_resume(bcmsdh_info_t *bcmsdh); - -/* Function to pass device-status bits to DHD. */ -extern uint32 bcmsdh_get_dstatus(void *sdh); - -/* Function to return current window addr */ -extern uint32 bcmsdh_cur_sbwad(void *sdh); - -/* Function to pass chipid and rev to lower layers for controlling pr's */ -extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); - - -extern int bcmsdh_sleep(void *sdh, bool enab); - -/* GPIO support */ -extern int bcmsdh_gpio_init(void *sd); -extern bool bcmsdh_gpioin(void *sd, uint32 gpio); -extern int bcmsdh_gpioouten(void *sd, uint32 gpio); -extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); - -#endif /* _bcmsdh_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h deleted file mode 100644 index b4578468cbab..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh_sdmmc.h 496576 2014-08-13 15:04:56Z $ - */ - -#ifndef __BCMSDH_SDMMC_H__ -#define __BCMSDH_SDMMC_H__ - -#define sd_err(x) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) - - -#define sd_sync_dma(sd, read, nbytes) -#define sd_init_dma(sd) -#define sd_ack_intr(sd) -#define sd_wakeup(sd); - -#define sd_log(x) - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_4318 64 -#define BLOCK_SIZE_4328 512 - -/* internal return code */ -#define SUCCESS 0 -#define ERROR 1 - -/* private bus modes */ -#define SDIOH_MODE_SD4 2 -#define CLIENT_INTR 0x100 /* Get rid of this! */ -#define SDIOH_SDMMC_MAX_SG_ENTRIES (SDPCM_MAXGLOM_SIZE+2) - -struct sdioh_info { - osl_t *osh; /* osh handler */ - void *bcmsdh; /* upper layer handle */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - uint16 intmask; /* Current active interrupts */ - - int intrcount; /* Client interrupts */ - bool sd_use_dma; /* DMA on CMD53 */ - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - bool use_rxchain; - struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; - struct sdio_func fake_func0; - struct sdio_func *func[SDIOD_MAX_IOFUNCS]; - -}; - -/************************************************************ - * Internal interfaces: per-port references into bcmsdh_sdmmc.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/* OS-independent interrupt handler */ -extern bool check_client_intr(sdioh_info_t *sd); - -/* Core interrupt enable/disable of device interrupts */ -extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); -extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); - - -/************************************************************** - * Internal interfaces: bcmsdh_sdmmc.c references to per-port code - */ - -/* Register mapping routines */ -extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size); -extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size); - -/* Interrupt (de)registration routines */ -extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); -extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd); - -extern sdioh_info_t *sdioh_attach(osl_t *osh, struct sdio_func *func); -extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); -#endif /* __BCMSDH_SDMMC_H__ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h deleted file mode 100644 index 535961916075..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Broadcom SDIO/PCMCIA - * Software-specific definitions shared between device and host side - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdpcm.h 472405 2014-04-23 23:46:55Z $ - */ - -#ifndef _bcmsdpcm_h_ -#define _bcmsdpcm_h_ - -/* - * Software allocation of To SB Mailbox resources - */ - -/* intstatus bits */ -#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */ -#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */ -#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */ -#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */ - -#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) - -/* tosbmailbox bits corresponding to intstatus bits */ -#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ -#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ -#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ -#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ -#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */ - -/* tosbmailboxdata */ -#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */ -#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */ - -/* - * Software allocation of To Host Mailbox resources - */ - -/* intstatus bits */ -#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */ -#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */ -#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */ -#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */ - -#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT) - -/* tohostmailbox bits corresponding to intstatus bits */ -#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */ -#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */ -#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ -#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ -#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */ - -/* tohostmailboxdata */ -#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */ -#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */ -#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */ -#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */ -#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */ - -#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */ -#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ - -#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */ -#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ - -/* - * Software-defined protocol header - */ - -/* Current protocol version */ -#define SDPCM_PROT_VERSION 4 - -/* SW frame header */ -#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ -#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ - -#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ -#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ -#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ - -#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ -#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ -#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ - -/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ -#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ -#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ -#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ -#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) (((uint8 *)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) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) -#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ -#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) -#define SDPCM_VERSION_OFFSET 6 /* Version # */ -#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) -#define SDPCM_UNUSED_OFFSET 7 /* Spare */ -#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) - -#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ - -/* logical channel numbers */ -#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response 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 (superframes) */ -#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ -#define SDPCM_MAX_CHANNEL 15 - -#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ - -#define SDPCM_FLAG_RESVD0 0x01 -#define SDPCM_FLAG_RESVD1 0x02 -#define SDPCM_FLAG_GSPI_TXENAB 0x04 -#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ - -/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ -#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) - -#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80) - -/* For TEST_CHANNEL packets, define another 4-byte header */ -#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2); - * Semantics of Ext byte depend on command. - * Len is current or requested frame length, not - * including test header; sent little-endian. - */ -#define SDPCM_TEST_PKT_CNT_FLD_LEN 4 /* Packet count filed legth */ -#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ -#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ -#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ -#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count - * (Backward compatabilty) Set frame count in a - * 4 byte filed adjacent to the HDR - */ -#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off - * Set frame count in a 4 byte filed adjacent to - * the HDR - */ - -/* Handy macro for filling in datagen packets with a pattern */ -#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) - -/* - * Software counters (first part matches hardware counters) - */ - -typedef volatile struct { - uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ - uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ - uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ - uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ - uint32 abort; /* AbortCount, SDIO: aborts */ - uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ - uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ - uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ - uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ - uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ - uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ - uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ - uint32 rxdescuflo; /* receive descriptor underflows */ - uint32 rxfifooflo; /* receive fifo overflows */ - uint32 txfifouflo; /* transmit fifo underflows */ - uint32 runt; /* runt (too short) frames recv'd from bus */ - uint32 badlen; /* frame's rxh len does not match its hw tag len */ - uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ - uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ - uint32 rxfcrc; /* frame rx header indicates crc error */ - uint32 rxfwoos; /* frame rx header indicates write out of sync */ - uint32 rxfwft; /* frame rx header indicates write frame termination */ - uint32 rxfabort; /* frame rx header indicates frame aborted */ - uint32 woosint; /* write out of sync interrupt */ - uint32 roosint; /* read out of sync interrupt */ - uint32 rftermint; /* read frame terminate interrupt */ - uint32 wftermint; /* write frame terminate interrupt */ -} sdpcmd_cnt_t; - -/* - * Register Access Macros - */ - -#define SDIODREV_IS(var, val) ((var) == (val)) -#define SDIODREV_GE(var, val) ((var) >= (val)) -#define SDIODREV_GT(var, val) ((var) > (val)) -#define SDIODREV_LT(var, val) ((var) < (val)) -#define SDIODREV_LE(var, val) ((var) <= (val)) - -#define SDIODDMAREG32(h, dir, chnl) \ - ((dir) == DMA_TX ? \ - (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ - (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv)) - -#define SDIODDMAREG64(h, dir, chnl) \ - ((dir) == DMA_TX ? \ - (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ - (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv)) - -#define SDIODDMAREG(h, dir, chnl) \ - (SDIODREV_LT((h)->corerev, 1) ? \ - SDIODDMAREG32((h), (dir), (chnl)) : \ - SDIODDMAREG64((h), (dir), (chnl))) - -#define PCMDDMAREG(h, dir, chnl) \ - ((dir) == DMA_TX ? \ - (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \ - (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv)) - -#define SDPCMDMAREG(h, dir, chnl, coreid) \ - ((coreid) == SDIOD_CORE_ID ? \ - SDIODDMAREG(h, dir, chnl) : \ - PCMDDMAREG(h, dir, chnl)) - -#define SDIODFIFOREG(h, corerev) \ - (SDIODREV_LT((corerev), 1) ? \ - ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \ - ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo))) - -#define PCMDFIFOREG(h) \ - ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo)) - -#define SDPCMFIFOREG(h, coreid, corerev) \ - ((coreid) == SDIOD_CORE_ID ? \ - SDIODFIFOREG(h, corerev) : \ - PCMDFIFOREG(h)) - -/* - * Shared structure between dongle and the host. - * The structure contains pointers to trap or assert information. - */ -#define SDPCM_SHARED_VERSION 0x0001 -#define SDPCM_SHARED_VERSION_MASK 0x00FF -#define SDPCM_SHARED_ASSERT_BUILT 0x0100 -#define SDPCM_SHARED_ASSERT 0x0200 -#define SDPCM_SHARED_TRAP 0x0400 -#define SDPCM_SHARED_IN_BRPT 0x0800 -#define SDPCM_SHARED_SET_BRPT 0x1000 -#define SDPCM_SHARED_PENDING_BRPT 0x2000 - -typedef struct { - uint32 flags; - uint32 trap_addr; - uint32 assert_exp_addr; - uint32 assert_file_addr; - uint32 assert_line; - uint32 console_addr; /* Address of hnd_cons_t */ - uint32 msgtrace_addr; - uint32 fwid; -} sdpcm_shared_t; - -extern sdpcm_shared_t sdpcm_shared; - -#endif /* _bcmsdpcm_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h deleted file mode 100644 index 1fc1fd4eef6b..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdspi.h 294363 2011-11-06 23:02:20Z $ - */ -#ifndef _BCM_SD_SPI_H -#define _BCM_SD_SPI_H - -/* global msglevel for debug messages - bitvals come from sdiovar.h */ - -#define sd_err(x) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) - -#define sd_log(x) - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_4318 64 -#define BLOCK_SIZE_4328 512 - -/* internal return code */ -#define SUCCESS 0 -#undef ERROR -#define ERROR 1 - -/* private bus modes */ -#define SDIOH_MODE_SPI 0 - -#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -#define USE_MULTIBLOCK 0x4 - -struct sdioh_info { - uint cfg_bar; /* pci cfg address for bar */ - uint32 caps; /* cached value of capabilities reg */ - uint bar0; /* BAR0 for PCI Device */ - osl_t *osh; /* osh handler */ - void *controller; /* Pointer to SPI Controller's private data struct */ - - uint lockcount; /* nest count of sdspi_lock() calls */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - bool initialized; /* card initialized */ - uint32 target_dev; /* Target device ID */ - uint32 intmask; /* Current active interrupts */ - void *sdos_info; /* Pointer to per-OS private data */ - - uint32 controller_type; /* Host controller type */ - uint8 version; /* Host Controller Spec Compliance Version */ - uint irq; /* Client irq */ - uint32 intrcount; /* Client interrupts */ - uint32 local_intrcount; /* Controller interrupts */ - bool host_init_done; /* Controller initted */ - bool card_init_done; /* Client SDIO interface initted */ - bool polled_mode; /* polling for command completion */ - - bool sd_use_dma; /* DMA on CMD53 */ - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - bool got_hcint; /* Host Controller interrupt. */ - /* polling hack in wl_linux.c:wl_timer() */ - int adapter_slot; /* Maybe dealing with multiple slots/controllers */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ - uint32 data_xfer_count; /* Current register transfer size */ - uint32 cmd53_wr_data; /* Used to pass CMD53 write data */ - uint32 card_response; /* Used to pass back response status byte */ - uint32 card_rsp_data; /* Used to pass back response data word */ - uint16 card_rca; /* Current Address */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - void *dma_buf; - ulong dma_phys; - int r_cnt; /* rx count */ - int t_cnt; /* tx_count */ -}; - -/************************************************************ - * Internal interfaces: per-port references into bcmsdspi.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/************************************************************** - * Internal interfaces: bcmsdspi.c references to per-port code - */ - -/* Register mapping routines */ -extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); -extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); - -/* Interrupt (de)registration routines */ -extern int spi_register_irq(sdioh_info_t *sd, uint irq); -extern void spi_free_irq(uint irq, sdioh_info_t *sd); - -/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -extern void spi_lock(sdioh_info_t *sd); -extern void spi_unlock(sdioh_info_t *sd); - -/* Allocate/init/free per-OS private data */ -extern int spi_osinit(sdioh_info_t *sd); -extern void spi_osfree(sdioh_info_t *sd); - -#endif /* _BCM_SD_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h deleted file mode 100644 index ef55d436b588..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * 'Standard' SDIO HOST CONTROLLER driver - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdstd.h 455390 2014-02-13 22:14:56Z $ - */ -#ifndef _BCM_SD_STD_H -#define _BCM_SD_STD_H - -/* global msglevel for debug messages - bitvals come from sdiovar.h */ -#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) -#define sd_dma(x) - -#define sd_sync_dma(sd, read, nbytes) -#define sd_init_dma(sd) -#define sd_ack_intr(sd) -#define sd_wakeup(sd); -/* Allocate/init/free per-OS private data */ -extern int sdstd_osinit(sdioh_info_t *sd); -extern void sdstd_osfree(sdioh_info_t *sd); - -#define sd_log(x) - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_4318 64 -#define BLOCK_SIZE_4328 512 - -/* internal return code */ -#define SUCCESS 0 -#define ERROR 1 - -/* private bus modes */ -#define SDIOH_MODE_SPI 0 -#define SDIOH_MODE_SD1 1 -#define SDIOH_MODE_SD4 2 - -#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */ -#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */ - -#define SDIOH_TYPE_ARASAN_HDK 1 -#define SDIOH_TYPE_BCM27XX 2 -#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */ -#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */ -#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */ - -/* For linux, allow yielding for dongle */ -#define BCMSDYIELD - -/* Expected card status value for CMD7 */ -#define SDIOH_CMD7_EXP_STATUS 0x00001E00 - -#define RETRIES_LARGE 100000 -#define sdstd_os_yield(sd) do {} while (0) -#define RETRIES_SMALL 100 - - -#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -#define USE_MULTIBLOCK 0x4 - -#define USE_FIFO 0x8 /* Fifo vs non-fifo */ - -#define CLIENT_INTR 0x100 /* Get rid of this! */ - -#define HC_INTR_RETUNING 0x1000 - - -#ifdef BCMSDIOH_TXGLOM -/* Total glom pkt can not exceed 64K - * need one more slot for glom padding packet - */ -#define SDIOH_MAXGLOM_SIZE (40+1) - -typedef struct glom_buf { - uint32 count; /* Total number of pkts queued */ - void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */ - ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */ - uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */ -} glom_buf_t; -#endif - -struct sdioh_info { - uint cfg_bar; /* pci cfg address for bar */ - uint32 caps; /* cached value of capabilities reg */ - uint32 curr_caps; /* max current capabilities reg */ - - osl_t *osh; /* osh handler */ - volatile char *mem_space; /* pci device memory va */ - uint lockcount; /* nest count of sdstd_lock() calls */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - bool initialized; /* card initialized */ - uint target_dev; /* Target device ID */ - uint16 intmask; /* Current active interrupts */ - void *sdos_info; /* Pointer to per-OS private data */ - void *bcmsdh; /* handler to upper layer stack (bcmsdh) */ - - uint32 controller_type; /* Host controller type */ - uint8 version; /* Host Controller Spec Compliance Version */ - uint irq; /* Client irq */ - int intrcount; /* Client interrupts */ - int local_intrcount; /* Controller interrupts */ - bool host_init_done; /* Controller initted */ - bool card_init_done; /* Client SDIO interface initted */ - bool polled_mode; /* polling for command completion */ - - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - /* polling hack in wl_linux.c:wl_timer() */ - int adapter_slot; /* Maybe dealing with multiple slots/controllers */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ - uint32 data_xfer_count; /* Current transfer */ - uint16 card_rca; /* Current Address */ - int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - void *dma_buf; /* DMA Buffer virtual address */ - ulong dma_phys; /* DMA Buffer physical address */ - void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */ - ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */ - - /* adjustments needed to make the dma align properly */ - void *dma_start_buf; - ulong dma_start_phys; - uint alloced_dma_size; - void *adma2_dscr_start_buf; - ulong adma2_dscr_start_phys; - uint alloced_adma2_dscr_size; - - int r_cnt; /* rx count */ - int t_cnt; /* tx_count */ - bool got_hcint; /* local interrupt flag */ - uint16 last_intrstatus; /* to cache intrstatus */ - int host_UHSISupported; /* whether UHSI is supported for HC. */ - int card_UHSI_voltage_Supported; /* whether UHSI is supported for - * Card in terms of Voltage [1.8 or 3.3]. - */ - int global_UHSI_Supp; /* type of UHSI support in both host and card. - * HOST_SDR_UNSUPP: capabilities not supported/matched - * HOST_SDR_12_25: SDR12 and SDR25 supported - * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd - */ - volatile int sd3_dat_state; /* data transfer state used for retuning check */ - volatile int sd3_tun_state; /* tuning state used for retuning check */ - bool sd3_tuning_reqd; /* tuning requirement parameter */ - uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ -#ifdef BCMSDIOH_TXGLOM - glom_buf_t glom_info; /* pkt information used for glomming */ - uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ -#endif -}; - -#define DMA_MODE_NONE 0 -#define DMA_MODE_SDMA 1 -#define DMA_MODE_ADMA1 2 -#define DMA_MODE_ADMA2 3 -#define DMA_MODE_ADMA2_64 4 -#define DMA_MODE_AUTO -1 - -#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) - -/* States for Tuning and corr data */ -#define TUNING_IDLE 0 -#define TUNING_START 1 -#define TUNING_START_AFTER_DAT 2 -#define TUNING_ONGOING 3 - -#define DATA_TRANSFER_IDLE 0 -#define DATA_TRANSFER_ONGOING 1 - -#define CHECK_TUNING_PRE_DATA 1 -#define CHECK_TUNING_POST_DATA 2 - - -#ifdef DHD_DEBUG -#define SD_DHD_DISABLE_PERIODIC_TUNING 0x01 -#define SD_DHD_ENABLE_PERIODIC_TUNING 0x00 -#endif - - -/************************************************************ - * Internal interfaces: per-port references into bcmsdstd.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/* OS-independent interrupt handler */ -extern bool check_client_intr(sdioh_info_t *sd); - -/* Core interrupt enable/disable of device interrupts */ -extern void sdstd_devintr_on(sdioh_info_t *sd); -extern void sdstd_devintr_off(sdioh_info_t *sd); - -/* Enable/disable interrupts for local controller events */ -extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err); -extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err); - -/* Wait for specified interrupt and error bits to be set */ -extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err); - - -/************************************************************** - * Internal interfaces: bcmsdstd.c references to per-port code - */ - -/* Register mapping routines */ -extern uint32 *sdstd_reg_map(osl_t *osh, ulong addr, int size); -extern void sdstd_reg_unmap(osl_t *osh, ulong addr, int size); - -/* Interrupt (de)registration routines */ -extern int sdstd_register_irq(sdioh_info_t *sd, uint irq); -extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); - -/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -extern void sdstd_lock(sdioh_info_t *sd); -extern void sdstd_unlock(sdioh_info_t *sd); -extern void sdstd_waitlockfree(sdioh_info_t *sd); - -/* OS-specific wrappers for safe concurrent register access */ -extern void sdstd_os_lock_irqsave(sdioh_info_t *sd, ulong* flags); -extern void sdstd_os_unlock_irqrestore(sdioh_info_t *sd, ulong* flags); - -/* OS-specific wait-for-interrupt-or-status */ -extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits); - -/* used by bcmsdstd_linux [implemented in sdstd] */ -extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd); -extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); -extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); -extern void sdstd_3_check_and_do_tuning(sdioh_info_t *sd, int tuning_param); -extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); -extern int sdstd_3_get_tune_state(sdioh_info_t *sd); -extern int sdstd_3_get_data_state(sdioh_info_t *sd); -extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); -extern void sdstd_3_set_data_state(sdioh_info_t *sd, int state); -extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); -extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); -extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode); - -/* used by sdstd [implemented in bcmsdstd_linux/ndis] */ -extern void sdstd_3_start_tuning(sdioh_info_t *sd); -extern void sdstd_3_osinit_tuning(sdioh_info_t *sd); -extern void sdstd_3_osclean_tuning(sdioh_info_t *sd); - -extern void sdstd_enable_disable_periodic_timer(sdioh_info_t * sd, uint val); - -extern sdioh_info_t *sdioh_attach(osl_t *osh, void *bar0, uint irq); -extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); -#endif /* _BCM_SD_STD_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmspi.h b/drivers/net/wireless/bcmdhd/include/bcmspi.h deleted file mode 100644 index 193dc8e0c9ca..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmspi.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Broadcom SPI Low-Level Hardware Driver API - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmspi.h 241182 2011-02-17 21:50:03Z $ - */ -#ifndef _BCM_SPI_H -#define _BCM_SPI_H - -extern void spi_devintr_off(sdioh_info_t *sd); -extern void spi_devintr_on(sdioh_info_t *sd); -extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); -extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); -extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); -extern bool spi_hw_attach(sdioh_info_t *sd); -extern bool spi_hw_detach(sdioh_info_t *sd); -extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); -extern void spi_spinbits(sdioh_info_t *sd); -extern void spi_waitbits(sdioh_info_t *sd, bool yield); - -#endif /* _BCM_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h deleted file mode 100644 index c81e6049ae03..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmspibrcm.h 373331 2012-12-07 04:46:22Z $ - */ -#ifndef _BCM_SPI_BRCM_H -#define _BCM_SPI_BRCM_H - -#ifndef SPI_MAX_IOFUNCS -/* Maximum number of I/O funcs */ -#define SPI_MAX_IOFUNCS 4 -#endif -/* global msglevel for debug messages - bitvals come from sdiovar.h */ - -#if defined(DHD_DEBUG) -#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) -#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) -#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) -#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0) -#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) -#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0) -#else -#define sd_err(x) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) -#endif - -#define sd_log(x) - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_F1 64 -#define BLOCK_SIZE_F2 2048 -#define BLOCK_SIZE_F3 2048 - -/* internal return code */ -#define SUCCESS 0 -#undef ERROR -#define ERROR 1 -#define ERROR_UF 2 -#define ERROR_OF 3 - -/* private bus modes */ -#define SDIOH_MODE_SPI 0 - -#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -#define USE_MULTIBLOCK 0x4 - -struct sdioh_info { - uint cfg_bar; /* pci cfg address for bar */ - uint32 caps; /* cached value of capabilities reg */ - void *bar0; /* BAR0 for PCI Device */ - osl_t *osh; /* osh handler */ - void *controller; /* Pointer to SPI Controller's private data struct */ - uint lockcount; /* nest count of spi_lock() calls */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - bool initialized; /* card initialized */ - uint32 target_dev; /* Target device ID */ - uint32 intmask; /* Current active interrupts */ - void *sdos_info; /* Pointer to per-OS private data */ - uint32 controller_type; /* Host controller type */ - uint8 version; /* Host Controller Spec Compliance Version */ - uint irq; /* Client irq */ - uint32 intrcount; /* Client interrupts */ - uint32 local_intrcount; /* Controller interrupts */ - bool host_init_done; /* Controller initted */ - bool card_init_done; /* Client SDIO interface initted */ - bool polled_mode; /* polling for command completion */ - - bool sd_use_dma; /* DMA on CMD53 */ - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - /* polling hack in wl_linux.c:wl_timer() */ - int adapter_slot; /* Maybe dealing with multiple slots/controllers */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SPI_MAX_IOFUNCS]; /* Blocksize */ - uint32 data_xfer_count; /* Current transfer */ - uint16 card_rca; /* Current Address */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 card_dstatus; /* 32bit device status */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SPI_MAX_IOFUNCS]; - void *dma_buf; - ulong dma_phys; - int r_cnt; /* rx count */ - int t_cnt; /* tx_count */ - uint32 wordlen; /* host processor 16/32bits */ - uint32 prev_fun; - uint32 chip; - uint32 chiprev; - bool resp_delay_all; - bool dwordmode; - bool resp_delay_new; - - struct spierrstats_t spierrstats; -}; - -/************************************************************ - * Internal interfaces: per-port references into bcmspibrcm.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/************************************************************** - * Internal interfaces: bcmspibrcm.c references to per-port code - */ - -/* Interrupt (de)registration routines */ -extern int spi_register_irq(sdioh_info_t *sd, uint irq); -extern void spi_free_irq(uint irq, sdioh_info_t *sd); - -/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -extern void spi_lock(sdioh_info_t *sd); -extern void spi_unlock(sdioh_info_t *sd); - -/* Allocate/init/free per-OS private data */ -extern int spi_osinit(sdioh_info_t *sd); -extern void spi_osfree(sdioh_info_t *sd); - -#define SPI_RW_FLAG_M BITFIELD_MASK(1) /* Bit [31] - R/W Command Bit */ -#define SPI_RW_FLAG_S 31 -#define SPI_ACCESS_M BITFIELD_MASK(1) /* Bit [30] - Fixed/Incr Access */ -#define SPI_ACCESS_S 30 -#define SPI_FUNCTION_M BITFIELD_MASK(2) /* Bit [29:28] - Function Number */ -#define SPI_FUNCTION_S 28 -#define SPI_REG_ADDR_M BITFIELD_MASK(17) /* Bit [27:11] - Address */ -#define SPI_REG_ADDR_S 11 -#define SPI_LEN_M BITFIELD_MASK(11) /* Bit [10:0] - Packet length */ -#define SPI_LEN_S 0 - -#endif /* _BCM_SPI_BRCM_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h deleted file mode 100644 index bfb8f1dea0ff..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h +++ /dev/null @@ -1,633 +0,0 @@ -/* - * SROM format definition. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsrom_fmt.h 473704 2014-04-29 15:49:57Z $ - */ - -#ifndef _bcmsrom_fmt_h_ -#define _bcmsrom_fmt_h_ - -#define SROM_MAXREV 11 /* max revisiton supported by driver */ - -/* Maximum srom: 12 Kilobits == 1536 bytes */ -#define SROM_MAX 1536 -#define SROM_MAXW 384 -#define VARS_MAX 4096 - -/* PCI fields */ -#define PCI_F0DEVID 48 - - -#define SROM_WORDS 64 - -#define SROM3_SWRGN_OFF 28 /* s/w region offset in words */ - -#define SROM_SSID 2 -#define SROM_SVID 3 - -#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_ET0 39 -#define SROM_MACMID_ET0 40 -#define SROM_MACLO_ET0 41 -#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 SROM2_ENETPHY 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 accomodate - * MIMO features. It assumes up to two PCIE functions and 440 bytes - * of useable srom i.e. the useable 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_AA2G_MASK 0x00ff -#define SROM4_AA2G_SHIFT 0 -#define SROM4_AA5G_MASK 0xff00 -#define SROM4_AA5G_SHIFT 8 - -#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 - -/* Fields in the ITT_MAXP and 5GLH_MAXP words */ -#define B2G_MAXP_MASK 0xff -#define B2G_ITT_SHIFT 8 -#define B5G_MAXP_MASK 0xff -#define B5G_ITT_SHIFT 8 -#define B5GH_MAXP_MASK 0xff -#define B5GL_MAXP_SHIFT 8 - -/* 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_SIGN 64 - -#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 - -#define SROM8_EXTLNAGAIN 93 - -/* Temperature delta for PHY calibration */ -#define SROM8_PHYCAL_TEMPDELTA 94 - -/* Measured power 1 & 2, 0-13 bits at offset 95, MSB 2 bits are unused for now. */ -#define SROM8_MPWR_1_AND_2 95 - - -/* 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) - -#define SROM8_CRCREV 219 - -/* 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 -#define SROM8_RXGAINERR_2G 205 -#define SROM8_RXGAINERR_5GL 206 -#define SROM8_RXGAINERR_5GM 207 -#define SROM8_RXGAINERR_5GH 208 -#define SROM8_RXGAINERR_5GU 209 -#define SROM8_SUBBAND_PPR 210 -#define SROM8_PCIEINGRESS_WAR 211 -#define SROM9_SAR 212 - -#define SROM8_NOISELVL_2G 213 -#define SROM8_NOISELVL_5GL 214 -#define SROM8_NOISELVL_5GM 215 -#define SROM8_NOISELVL_5GH 216 -#define SROM8_NOISELVL_5GU 217 -#define SROM8_NOISECALOFFSET 218 - -#define SROM9_REV_CRC 219 - -#define SROM10_CCKPWROFFSET 218 -#define SROM10_SIGN 219 -#define SROM10_SWCTRLMAP_2G 220 -#define SROM10_CRCREV 229 - -#define SROM10_WORDS 230 -#define SROM10_SIGNATURE SROM4_SIGNATURE - - -/* SROM REV 11 */ -#define SROM11_BREV 65 - -#define SROM11_BFL0 66 -#define SROM11_BFL1 67 -#define SROM11_BFL2 68 -#define SROM11_BFL3 69 -#define SROM11_BFL4 70 -#define SROM11_BFL5 71 - -#define SROM11_MACHI 72 -#define SROM11_MACMID 73 -#define SROM11_MACLO 74 - -#define SROM11_CCODE 75 -#define SROM11_REGREV 76 - -#define SROM11_LEDBH10 77 -#define SROM11_LEDBH32 78 - -#define SROM11_LEDDC 79 - -#define SROM11_AA 80 - -#define SROM11_AGBG10 81 -#define SROM11_AGBG2A0 82 -#define SROM11_AGA21 83 - -#define SROM11_TXRXC 84 - -#define SROM11_FEM_CFG1 85 -#define SROM11_FEM_CFG2 86 - -/* Masks and offsets for FEM_CFG */ -#define SROM11_FEMCTRL_MASK 0xf800 -#define SROM11_FEMCTRL_SHIFT 11 -#define SROM11_PAPDCAP_MASK 0x0400 -#define SROM11_PAPDCAP_SHIFT 10 -#define SROM11_TWORANGETSSI_MASK 0x0200 -#define SROM11_TWORANGETSSI_SHIFT 9 -#define SROM11_PDGAIN_MASK 0x01f0 -#define SROM11_PDGAIN_SHIFT 4 -#define SROM11_EPAGAIN_MASK 0x000e -#define SROM11_EPAGAIN_SHIFT 1 -#define SROM11_TSSIPOSSLOPE_MASK 0x0001 -#define SROM11_TSSIPOSSLOPE_SHIFT 0 -#define SROM11_GAINCTRLSPH_MASK 0xf800 -#define SROM11_GAINCTRLSPH_SHIFT 11 - -#define SROM11_THERMAL 87 -#define SROM11_MPWR_RAWTS 88 -#define SROM11_TS_SLP_OPT_CORRX 89 -#define SROM11_XTAL_FREQ 90 -#define SROM11_5GB0_4080_W0_A1 91 -#define SROM11_PHYCAL_TEMPDELTA 92 -#define SROM11_MPWR_1_AND_2 93 -#define SROM11_5GB0_4080_W1_A1 94 -#define SROM11_TSSIFLOOR_2G 95 -#define SROM11_TSSIFLOOR_5GL 96 -#define SROM11_TSSIFLOOR_5GM 97 -#define SROM11_TSSIFLOOR_5GH 98 -#define SROM11_TSSIFLOOR_5GU 99 - -/* Masks and offsets for Terrmal parameters */ -#define SROM11_TEMPS_PERIOD_MASK 0xf0 -#define SROM11_TEMPS_PERIOD_SHIFT 4 -#define SROM11_TEMPS_HYSTERESIS_MASK 0x0f -#define SROM11_TEMPS_HYSTERESIS_SHIFT 0 -#define SROM11_TEMPCORRX_MASK 0xfc -#define SROM11_TEMPCORRX_SHIFT 2 -#define SROM11_TEMPSENSE_OPTION_MASK 0x3 -#define SROM11_TEMPSENSE_OPTION_SHIFT 0 - -#define SROM11_PDOFF_2G_40M_A0_MASK 0x000f -#define SROM11_PDOFF_2G_40M_A0_SHIFT 0 -#define SROM11_PDOFF_2G_40M_A1_MASK 0x00f0 -#define SROM11_PDOFF_2G_40M_A1_SHIFT 4 -#define SROM11_PDOFF_2G_40M_A2_MASK 0x0f00 -#define SROM11_PDOFF_2G_40M_A2_SHIFT 8 -#define SROM11_PDOFF_2G_40M_VALID_MASK 0x8000 -#define SROM11_PDOFF_2G_40M_VALID_SHIFT 15 - -#define SROM11_PDOFF_2G_40M 100 -#define SROM11_PDOFF_40M_A0 101 -#define SROM11_PDOFF_40M_A1 102 -#define SROM11_PDOFF_40M_A2 103 -#define SROM11_5GB0_4080_W2_A1 103 -#define SROM11_PDOFF_80M_A0 104 -#define SROM11_PDOFF_80M_A1 105 -#define SROM11_PDOFF_80M_A2 106 -#define SROM11_5GB1_4080_W0_A1 106 - -#define SROM11_SUBBAND5GVER 107 - -/* Per-path fields and offset */ -#define MAX_PATH_SROM_11 3 -#define SROM11_PATH0 108 -#define SROM11_PATH1 128 -#define SROM11_PATH2 148 - -#define SROM11_2G_MAXP 0 -#define SROM11_5GB1_4080_PA 0 -#define SROM11_2G_PA 1 -#define SROM11_5GB2_4080_PA 2 -#define SROM11_RXGAINS1 4 -#define SROM11_RXGAINS 5 -#define SROM11_5GB3_4080_PA 5 -#define SROM11_5GB1B0_MAXP 6 -#define SROM11_5GB3B2_MAXP 7 -#define SROM11_5GB0_PA 8 -#define SROM11_5GB1_PA 11 -#define SROM11_5GB2_PA 14 -#define SROM11_5GB3_PA 17 - -/* Masks and offsets for rxgains */ -#define SROM11_RXGAINS5GTRELNABYPA_MASK 0x8000 -#define SROM11_RXGAINS5GTRELNABYPA_SHIFT 15 -#define SROM11_RXGAINS5GTRISOA_MASK 0x7800 -#define SROM11_RXGAINS5GTRISOA_SHIFT 11 -#define SROM11_RXGAINS5GELNAGAINA_MASK 0x0700 -#define SROM11_RXGAINS5GELNAGAINA_SHIFT 8 -#define SROM11_RXGAINS2GTRELNABYPA_MASK 0x0080 -#define SROM11_RXGAINS2GTRELNABYPA_SHIFT 7 -#define SROM11_RXGAINS2GTRISOA_MASK 0x0078 -#define SROM11_RXGAINS2GTRISOA_SHIFT 3 -#define SROM11_RXGAINS2GELNAGAINA_MASK 0x0007 -#define SROM11_RXGAINS2GELNAGAINA_SHIFT 0 -#define SROM11_RXGAINS5GHTRELNABYPA_MASK 0x8000 -#define SROM11_RXGAINS5GHTRELNABYPA_SHIFT 15 -#define SROM11_RXGAINS5GHTRISOA_MASK 0x7800 -#define SROM11_RXGAINS5GHTRISOA_SHIFT 11 -#define SROM11_RXGAINS5GHELNAGAINA_MASK 0x0700 -#define SROM11_RXGAINS5GHELNAGAINA_SHIFT 8 -#define SROM11_RXGAINS5GMTRELNABYPA_MASK 0x0080 -#define SROM11_RXGAINS5GMTRELNABYPA_SHIFT 7 -#define SROM11_RXGAINS5GMTRISOA_MASK 0x0078 -#define SROM11_RXGAINS5GMTRISOA_SHIFT 3 -#define SROM11_RXGAINS5GMELNAGAINA_MASK 0x0007 -#define SROM11_RXGAINS5GMELNAGAINA_SHIFT 0 - -/* Power per rate */ -#define SROM11_CCKBW202GPO 168 -#define SROM11_CCKBW20UL2GPO 169 -#define SROM11_MCSBW202GPO 170 -#define SROM11_MCSBW202GPO_1 171 -#define SROM11_MCSBW402GPO 172 -#define SROM11_MCSBW402GPO_1 173 -#define SROM11_DOT11AGOFDMHRBW202GPO 174 -#define SROM11_OFDMLRBW202GPO 175 - -#define SROM11_MCSBW205GLPO 176 -#define SROM11_MCSBW205GLPO_1 177 -#define SROM11_MCSBW405GLPO 178 -#define SROM11_MCSBW405GLPO_1 179 -#define SROM11_MCSBW805GLPO 180 -#define SROM11_MCSBW805GLPO_1 181 -#define SROM11_RPCAL_2G 182 -#define SROM11_RPCAL_5GL 183 -#define SROM11_MCSBW205GMPO 184 -#define SROM11_MCSBW205GMPO_1 185 -#define SROM11_MCSBW405GMPO 186 -#define SROM11_MCSBW405GMPO_1 187 -#define SROM11_MCSBW805GMPO 188 -#define SROM11_MCSBW805GMPO_1 189 -#define SROM11_RPCAL_5GM 190 -#define SROM11_RPCAL_5GH 191 -#define SROM11_MCSBW205GHPO 192 -#define SROM11_MCSBW205GHPO_1 193 -#define SROM11_MCSBW405GHPO 194 -#define SROM11_MCSBW405GHPO_1 195 -#define SROM11_MCSBW805GHPO 196 -#define SROM11_MCSBW805GHPO_1 197 -#define SROM11_RPCAL_5GU 198 -#define SROM11_PDOFF_2G_CCK 199 -#define SROM11_MCSLR5GLPO 200 -#define SROM11_MCSLR5GMPO 201 -#define SROM11_MCSLR5GHPO 202 - -#define SROM11_SB20IN40HRPO 203 -#define SROM11_SB20IN80AND160HR5GLPO 204 -#define SROM11_SB40AND80HR5GLPO 205 -#define SROM11_SB20IN80AND160HR5GMPO 206 -#define SROM11_SB40AND80HR5GMPO 207 -#define SROM11_SB20IN80AND160HR5GHPO 208 -#define SROM11_SB40AND80HR5GHPO 209 -#define SROM11_SB20IN40LRPO 210 -#define SROM11_SB20IN80AND160LR5GLPO 211 -#define SROM11_SB40AND80LR5GLPO 212 -#define SROM11_TXIDXCAP2G 212 -#define SROM11_SB20IN80AND160LR5GMPO 213 -#define SROM11_SB40AND80LR5GMPO 214 -#define SROM11_TXIDXCAP5G 214 -#define SROM11_SB20IN80AND160LR5GHPO 215 -#define SROM11_SB40AND80LR5GHPO 216 - -#define SROM11_DOT11AGDUPHRPO 217 -#define SROM11_DOT11AGDUPLRPO 218 - -/* MISC */ -#define SROM11_PCIEINGRESS_WAR 220 -#define SROM11_SAR 221 - -#define SROM11_NOISELVL_2G 222 -#define SROM11_NOISELVL_5GL 223 -#define SROM11_NOISELVL_5GM 224 -#define SROM11_NOISELVL_5GH 225 -#define SROM11_NOISELVL_5GU 226 - -#define SROM11_RXGAINERR_2G 227 -#define SROM11_RXGAINERR_5GL 228 -#define SROM11_RXGAINERR_5GM 229 -#define SROM11_RXGAINERR_5GH 230 -#define SROM11_RXGAINERR_5GU 231 - -#define SROM11_SIGN 64 -#define SROM11_CRCREV 233 - -#define SROM11_WORDS 234 -#define SROM11_SIGNATURE 0x0634 - -typedef struct { - uint8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */ - uint8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */ - uint8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */ - uint8 triso; /* TR switch isolation */ - uint8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */ -} srom_fem_t; - -#endif /* _bcmsrom_fmt_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h deleted file mode 100644 index 4f84428eec0c..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * Table that encodes the srom formats for PCI/PCIe NICs. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsrom_tbl.h 471127 2014-04-17 23:24:23Z $ - */ - -#ifndef _bcmsrom_tbl_h_ -#define _bcmsrom_tbl_h_ - -#include "sbpcmcia.h" -#include "wlioctl.h" -#include - -typedef struct { - const char *name; - uint32 revmask; - uint32 flags; - uint16 off; - uint16 mask; -} sromvar_t; - -#define SRFL_MORE 1 /* value continues as described by the next entry */ -#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 */ -#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */ -#define SRFL_ARRAY 0x100 /* value is in an array. All elements EXCEPT FOR THE LAST - * ONE in the array should have this flag set. - */ - - -#define SROM_DEVID_PCIE 48 - -/* Assumptions: - * - Ethernet address spans across 3 consective 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 sromvar_t pci_sromvars[] = { -#if defined(CABLECPE) - {"devid", 0xffffff00, SRFL_PRHEX, PCI_F0DEVID, 0xffff}, -#elif defined(BCMPCIEDEV) && defined(BCMPCIEDEV_ENABLED) - {"devid", 0xffffff00, SRFL_PRHEX, SROM_DEVID_PCIE, 0xffff}, -#else - {"devid", 0xffffff00, SRFL_PRHEX|SRFL_NOVAR, PCI_F0DEVID, 0xffff}, -#endif - {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK}, - {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, - {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, - {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, - {"boardflags", 0x00000004, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, - {"", 0, 0, SROM_BFL2, 0xffff}, - {"boardflags", 0x00000008, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, - {"", 0, 0, SROM3_BFL2, 0xffff}, - {"boardflags", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL0, 0xffff}, - {"", 0, 0, SROM4_BFL1, 0xffff}, - {"boardflags", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL0, 0xffff}, - {"", 0, 0, SROM5_BFL1, 0xffff}, - {"boardflags", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL0, 0xffff}, - {"", 0, 0, SROM8_BFL1, 0xffff}, - {"boardflags2", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL2, 0xffff}, - {"", 0, 0, SROM4_BFL3, 0xffff}, - {"boardflags2", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL2, 0xffff}, - {"", 0, 0, SROM5_BFL3, 0xffff}, - {"boardflags2", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL2, 0xffff}, - {"", 0, 0, SROM8_BFL3, 0xffff}, - {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, - {"subvid", 0xfffffffc, SRFL_PRHEX, SROM_SVID, 0xffff}, - {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, - {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff}, - {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff}, - {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff}, - {"boardnum", 0x00000700, 0, SROM8_MACLO, 0xffff}, - {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, - {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, - {"regrev", 0x00000010, 0, SROM4_REGREV, 0x00ff}, - {"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff}, - {"regrev", 0x00000700, 0, SROM8_REGREV, 0x00ff}, - {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff}, - {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, - {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff}, - {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, - {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff}, - {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, - {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff}, - {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, - {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff}, - {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, - {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff}, - {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, - {"ledbh0", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, - {"ledbh1", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, - {"ledbh2", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, - {"ledbh3", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, - {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, - {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, - {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, - {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff}, - {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff}, - {"pa0b0", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, - {"pa0b1", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, - {"pa0b2", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, - {"pa0itssit", 0x00000700, 0, SROM8_W0_ITTMAXP, 0xff00}, - {"pa0maxpwr", 0x00000700, 0, SROM8_W0_ITTMAXP, 0x00ff}, - {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff}, - {"opo", 0x00000700, 0, SROM8_2G_OFDMPO, 0x00ff}, - {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, - {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff}, - {"aa2g", 0x00000700, 0, SROM8_AA, 0x00ff}, - {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, - {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, - {"aa5g", 0x00000700, 0, SROM8_AA, 0xff00}, - {"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff}, - {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00}, - {"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff}, - {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00}, - {"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff}, - {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00}, - {"ag0", 0x00000700, 0, SROM8_AG10, 0x00ff}, - {"ag1", 0x00000700, 0, SROM8_AG10, 0xff00}, - {"ag2", 0x00000700, 0, SROM8_AG32, 0x00ff}, - {"ag3", 0x00000700, 0, SROM8_AG32, 0xff00}, - {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, - {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, - {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, - {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, - {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, - {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, - {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, - {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, - {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, - {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00}, - {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, - {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, - {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff}, - {"pa1b0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, - {"pa1b1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, - {"pa1b2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, - {"pa1lob0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, - {"pa1lob1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, - {"pa1lob2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, - {"pa1hib0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, - {"pa1hib1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, - {"pa1hib2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, - {"pa1itssit", 0x00000700, 0, SROM8_W1_ITTMAXP, 0xff00}, - {"pa1maxpwr", 0x00000700, 0, SROM8_W1_ITTMAXP, 0x00ff}, - {"pa1lomaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0xff00}, - {"pa1himaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, - {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, - {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, - {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, - {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, - {"bxa2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x1800}, - {"rssisav2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x0700}, - {"rssismc2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x00f0}, - {"rssismf2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x000f}, - {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, - {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, - {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, - {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, - {"bxa5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x1800}, - {"rssisav5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x0700}, - {"rssismc5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x00f0}, - {"rssismf5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x000f}, - {"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff}, - {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00}, - {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff}, - {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00}, - {"tri2g", 0x00000700, 0, SROM8_TRI52G, 0x00ff}, - {"tri5g", 0x00000700, 0, SROM8_TRI52G, 0xff00}, - {"tri5gl", 0x00000700, 0, SROM8_TRI5GHL, 0x00ff}, - {"tri5gh", 0x00000700, 0, SROM8_TRI5GHL, 0xff00}, - {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, - {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, - {"rxpo2g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, - {"rxpo5g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, - {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK}, - {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK}, - {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK}, - {"txchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, - {"rxchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, - {"antswitch", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, - {"tssipos2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK}, - {"extpagain2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK}, - {"pdetrange2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK}, - {"triso2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, - {"antswctl2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK}, - {"tssipos5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK}, - {"extpagain5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK}, - {"pdetrange5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK}, - {"triso5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, - {"antswctl5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK}, - {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff}, - {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, - {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff}, - {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, - {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff}, - {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, - {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff}, - {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, - {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff}, - {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, - {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff}, - {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, - {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff}, - {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, - {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff}, - {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, - - {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, - {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, - {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, - {"ccode", 0x00000700, SRFL_CCODE, SROM8_CCODE, 0xffff}, - {"macaddr", 0x00000700, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, - {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, - {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, - {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, - {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff}, - {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff}, - {"leddc", 0x00000700, SRFL_NOFFS|SRFL_LEDDC, SROM8_LEDDC, 0xffff}, - {"leddc", 0x000000e0, SRFL_NOFFS|SRFL_LEDDC, SROM5_LEDDC, 0xffff}, - {"leddc", 0x00000010, SRFL_NOFFS|SRFL_LEDDC, SROM4_LEDDC, 0xffff}, - {"leddc", 0x00000008, SRFL_NOFFS|SRFL_LEDDC, SROM3_LEDDC, 0xffff}, - - {"tempthresh", 0x00000700, 0, SROM8_THERMAL, 0xff00}, - {"tempoffset", 0x00000700, 0, SROM8_THERMAL, 0x00ff}, - {"rawtempsense", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff}, - {"measpower", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00}, - {"tempsense_slope", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff}, - {"tempcorrx", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00}, - {"tempsense_option", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300}, - {"freqoffset_corr", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f}, - {"iqcal_swp_dis", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010}, - {"hw_iqcal_en", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020}, - {"elna2g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0x00ff}, - {"elna5g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0xff00}, - {"phycal_tempdelta", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff}, - {"temps_period", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x0f00}, - {"temps_hysteresis", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0xf000}, - {"measpower1", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x007f}, - {"measpower2", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x3f80}, - - {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, - {"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, - {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, - {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, - {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, - {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, - {"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, - {"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, - {"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, - {"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, - {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, - {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, - {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, - {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, - {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, - {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, - {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, - {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, - {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, - {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, - {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, - {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, - {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, - {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, - {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, - {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, - {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, - {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, - {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, - {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, - {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, - {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, - {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, - {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, - {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, - {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, - {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, - {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, - {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, - {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, - {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, - {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, - {"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, - {"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff}, - {"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff}, - {"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff}, - {"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff}, - {"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff}, - {"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff}, - {"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff}, - {"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, - {"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff}, - {"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff}, - {"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff}, - {"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff}, - {"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff}, - {"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff}, - {"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff}, - {"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, - {"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff}, - {"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff}, - {"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff}, - {"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff}, - {"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff}, - {"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff}, - {"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff}, - {"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, - {"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff}, - {"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff}, - {"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff}, - {"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff}, - {"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff}, - {"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff}, - {"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff}, - {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff}, - {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff}, - {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff}, - {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, - {"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff}, - {"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff}, - {"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff}, - {"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, - - /* power per rate from sromrev 9 */ - {"cckbw202gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20, 0xffff}, - {"cckbw20ul2gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, - {"legofdmbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, - {"legofdmbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, - {"legofdmbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, - {"legofdmbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, - {"mcsbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw402gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, - {"mcsbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw405glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, - {"mcsbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw405gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, - {"mcsbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw405ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, - {"mcs32po", 0x00000600, 0, SROM9_PO_MCS32, 0xffff}, - {"legofdm40duppo", 0x00000600, 0, SROM9_PO_LOFDM40DUP, 0xffff}, - {"pcieingress_war", 0x00000700, 0, SROM8_PCIEINGRESS_WAR, 0xf}, - {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f}, - {"rxgainerr2ga1", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x07c0}, - {"rxgainerr2ga2", 0x00000700, 0, SROM8_RXGAINERR_2G, 0xf800}, - {"rxgainerr5gla0", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x003f}, - {"rxgainerr5gla1", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x07c0}, - {"rxgainerr5gla2", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0xf800}, - {"rxgainerr5gma0", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x003f}, - {"rxgainerr5gma1", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x07c0}, - {"rxgainerr5gma2", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0xf800}, - {"rxgainerr5gha0", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x003f}, - {"rxgainerr5gha1", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x07c0}, - {"rxgainerr5gha2", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0xf800}, - {"rxgainerr5gua0", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x003f}, - {"rxgainerr5gua1", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x07c0}, - {"rxgainerr5gua2", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0xf800}, - {"sar2g", 0x00000600, 0, SROM9_SAR, 0x00ff}, - {"sar5g", 0x00000600, 0, SROM9_SAR, 0xff00}, - {"noiselvl2ga0", 0x00000700, 0, SROM8_NOISELVL_2G, 0x001f}, - {"noiselvl2ga1", 0x00000700, 0, SROM8_NOISELVL_2G, 0x03e0}, - {"noiselvl2ga2", 0x00000700, 0, SROM8_NOISELVL_2G, 0x7c00}, - {"noiselvl5gla0", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x001f}, - {"noiselvl5gla1", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x03e0}, - {"noiselvl5gla2", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x7c00}, - {"noiselvl5gma0", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x001f}, - {"noiselvl5gma1", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x03e0}, - {"noiselvl5gma2", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x7c00}, - {"noiselvl5gha0", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x001f}, - {"noiselvl5gha1", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x03e0}, - {"noiselvl5gha2", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x7c00}, - {"noiselvl5gua0", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x001f}, - {"noiselvl5gua1", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x03e0}, - {"noiselvl5gua2", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x7c00}, - {"noisecaloffset", 0x00000300, 0, SROM8_NOISECALOFFSET, 0x00ff}, - {"noisecaloffset5g", 0x00000300, 0, SROM8_NOISECALOFFSET, 0xff00}, - {"subband5gver", 0x00000700, 0, SROM8_SUBBAND_PPR, 0x7}, - - {"cckPwrOffset", 0x00000400, 0, SROM10_CCKPWROFFSET, 0xffff}, - /* swctrlmap_2g array, note that the last element doesn't have SRFL_ARRAY flag set */ - {"swctrlmap_2g", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 1, 0xffff}, - {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 2, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 3, 0xffff}, - {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 4, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 5, 0xffff}, - {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 6, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 7, 0xffff}, - {"", 0x00000400, SRFL_PRHEX, SROM10_SWCTRLMAP_2G + 8, 0xffff}, - - /* sromrev 11 */ - {"boardflags3", 0xfffff800, SRFL_PRHEX|SRFL_MORE, SROM11_BFL4, 0xffff}, - {"", 0, 0, SROM11_BFL5, 0xffff}, - {"boardnum", 0xfffff800, 0, SROM11_MACLO, 0xffff}, - {"macaddr", 0xfffff800, SRFL_ETHADDR, SROM11_MACHI, 0xffff}, - {"ccode", 0xfffff800, SRFL_CCODE, SROM11_CCODE, 0xffff}, - {"regrev", 0xfffff800, 0, SROM11_REGREV, 0x00ff}, - {"ledbh0", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0x00ff}, - {"ledbh1", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0xff00}, - {"ledbh2", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0x00ff}, - {"ledbh3", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0xff00}, - {"leddc", 0xfffff800, SRFL_NOFFS|SRFL_LEDDC, SROM11_LEDDC, 0xffff}, - {"aa2g", 0xfffff800, 0, SROM11_AA, 0x00ff}, - {"aa5g", 0xfffff800, 0, SROM11_AA, 0xff00}, - {"agbg0", 0xfffff800, 0, SROM11_AGBG10, 0xff00}, - {"agbg1", 0xfffff800, 0, SROM11_AGBG10, 0x00ff}, - {"agbg2", 0xfffff800, 0, SROM11_AGBG2A0, 0xff00}, - {"aga0", 0xfffff800, 0, SROM11_AGBG2A0, 0x00ff}, - {"aga1", 0xfffff800, 0, SROM11_AGA21, 0xff00}, - {"aga2", 0xfffff800, 0, SROM11_AGA21, 0x00ff}, - {"txchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_TXCHAIN_MASK}, - {"rxchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_RXCHAIN_MASK}, - {"antswitch", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_SWITCH_MASK}, - - {"tssiposslope2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0001}, - {"epagain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x000e}, - {"pdgain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x01f0}, - {"tworangetssi2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0200}, - {"papdcap2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0400}, - {"femctrl", 0xfffff800, 0, SROM11_FEM_CFG1, 0xf800}, - - {"tssiposslope5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0001}, - {"epagain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x000e}, - {"pdgain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x01f0}, - {"tworangetssi5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0200}, - {"papdcap5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0400}, - {"gainctrlsph", 0xfffff800, 0, SROM11_FEM_CFG2, 0xf800}, - - {"tempthresh", 0xfffff800, 0, SROM11_THERMAL, 0xff00}, - {"tempoffset", 0xfffff800, 0, SROM11_THERMAL, 0x00ff}, - {"rawtempsense", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0x01ff}, - {"measpower", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0xfe00}, - {"tempsense_slope", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x00ff}, - {"tempcorrx", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0xfc00}, - {"tempsense_option", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x0300}, - {"xtalfreq", 0xfffff800, 0, SROM11_XTAL_FREQ, 0xffff}, - /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #1 */ - {"pa5gbw4080a1", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W0_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W1_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W2_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_4080_W0_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_4080_PA + 2, 0xffff}, - {"phycal_tempdelta", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x00ff}, - {"temps_period", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x0f00}, - {"temps_hysteresis", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0xf000}, - {"measpower1", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x007f}, - {"measpower2", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x3f80}, - {"tssifloor2g", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_2G, 0x03ff}, - {"tssifloor5g", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GL, 0x03ff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GM, 0x03ff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GH, 0x03ff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_5GU, 0x03ff}, - {"pdoffset2g40ma0", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x000f}, - {"pdoffset2g40ma1", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x00f0}, - {"pdoffset2g40ma2", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x0f00}, - {"pdoffset2g40mvalid", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x8000}, - {"pdoffset40ma0", 0xfffff800, 0, SROM11_PDOFF_40M_A0, 0xffff}, - {"pdoffset40ma1", 0xfffff800, 0, SROM11_PDOFF_40M_A1, 0xffff}, - {"pdoffset40ma2", 0xfffff800, 0, SROM11_PDOFF_40M_A2, 0xffff}, - {"pdoffset80ma0", 0xfffff800, 0, SROM11_PDOFF_80M_A0, 0xffff}, - {"pdoffset80ma1", 0xfffff800, 0, SROM11_PDOFF_80M_A1, 0xffff}, - {"pdoffset80ma2", 0xfffff800, 0, SROM11_PDOFF_80M_A2, 0xffff}, - - {"subband5gver", 0xfffff800, SRFL_PRHEX, SROM11_SUBBAND5GVER, 0xffff}, - {"paparambwver", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0xf000}, - /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #0 */ - {"pa5gbw4080a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 +SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, - /* Special PA Params for 4335 5G Band, 40 MHz BW */ - {"pa5gbw40a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_5GB3_PA + 2, 0xffff}, - /* Special PA Params for 4335 5G Band, 80 MHz BW */ - {"pa5gbw80a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, - /* Special PA Params for 4335 2G Band, CCK */ - {"pa2gccka0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_2G_PA + 2, 0xffff}, - - /* power per rate */ - {"cckbw202gpo", 0xfffff800, 0, SROM11_CCKBW202GPO, 0xffff}, - {"cckbw20ul2gpo", 0xfffff800, 0, SROM11_CCKBW20UL2GPO, 0xffff}, - {"mcsbw202gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW202GPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW202GPO_1, 0xffff}, - {"mcsbw402gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW402GPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW402GPO_1, 0xffff}, - {"dot11agofdmhrbw202gpo", 0xfffff800, 0, SROM11_DOT11AGOFDMHRBW202GPO, 0xffff}, - {"ofdmlrbw202gpo", 0xfffff800, 0, SROM11_OFDMLRBW202GPO, 0xffff}, - {"mcsbw205glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GLPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW205GLPO_1, 0xffff}, - {"mcsbw405glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GLPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW405GLPO_1, 0xffff}, - {"mcsbw805glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GLPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW805GLPO_1, 0xffff}, - {"mcsbw205gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GMPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW205GMPO_1, 0xffff}, - {"mcsbw405gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GMPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW405GMPO_1, 0xffff}, - {"mcsbw805gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GMPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW805GMPO_1, 0xffff}, - {"mcsbw205ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GHPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW205GHPO_1, 0xffff}, - {"mcsbw405ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GHPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW405GHPO_1, 0xffff}, - {"mcsbw805ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GHPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW805GHPO_1, 0xffff}, - {"mcslr5glpo", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0x0fff}, - {"mcslr5gmpo", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0xffff}, - {"mcslr5ghpo", 0xfffff800, 0, SROM11_MCSLR5GHPO, 0xffff}, - {"sb20in40hrpo", 0xfffff800, 0, SROM11_SB20IN40HRPO, 0xffff}, - {"sb20in80and160hr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GLPO, 0xffff}, - {"sb40and80hr5glpo", 0xfffff800, 0, SROM11_SB40AND80HR5GLPO, 0xffff}, - {"sb20in80and160hr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GMPO, 0xffff}, - {"sb40and80hr5gmpo", 0xfffff800, 0, SROM11_SB40AND80HR5GMPO, 0xffff}, - {"sb20in80and160hr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GHPO, 0xffff}, - {"sb40and80hr5ghpo", 0xfffff800, 0, SROM11_SB40AND80HR5GHPO, 0xffff}, - {"sb20in40lrpo", 0xfffff800, 0, SROM11_SB20IN40LRPO, 0xffff}, - {"sb20in80and160lr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GLPO, 0xffff}, - {"sb40and80lr5glpo", 0xfffff800, 0, SROM11_SB40AND80LR5GLPO, 0xffff}, - {"sb20in80and160lr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GMPO, 0xffff}, - {"sb40and80lr5gmpo", 0xfffff800, 0, SROM11_SB40AND80LR5GMPO, 0xffff}, - {"sb20in80and160lr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GHPO, 0xffff}, - {"sb40and80lr5ghpo", 0xfffff800, 0, SROM11_SB40AND80LR5GHPO, 0xffff}, - {"dot11agduphrpo", 0xfffff800, 0, SROM11_DOT11AGDUPHRPO, 0xffff}, - {"dot11agduplrpo", 0xfffff800, 0, SROM11_DOT11AGDUPLRPO, 0xffff}, - - /* Misc */ - {"sar2g", 0xfffff800, 0, SROM11_SAR, 0x00ff}, - {"sar5g", 0xfffff800, 0, SROM11_SAR, 0xff00}, - - {"noiselvl2ga0", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x001f}, - {"noiselvl2ga1", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x03e0}, - {"noiselvl2ga2", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x7c00}, - {"noiselvl5ga0", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x001f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x001f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x001f}, - {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x001f}, - {"noiselvl5ga1", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x03e0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x03e0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x03e0}, - {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x03e0}, - {"noiselvl5ga2", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x7c00}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x7c00}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x7c00}, - {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x7c00}, - - {"rxgainerr2ga0", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x003f}, - {"rxgainerr2ga1", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x07c0}, - {"rxgainerr2ga2", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0xf800}, - {"rxgainerr5ga0", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x003f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x003f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x003f}, - {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x003f}, - {"rxgainerr5ga1", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x07c0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x07c0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x07c0}, - {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x07c0}, - {"rxgainerr5ga2", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0xf800}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0xf800}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0xf800}, - {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0xf800}, - {"rpcal2g", 0xfffff800, 0, SROM11_RPCAL_2G, 0xffff}, - {"rpcal5gb0", 0xfffff800, 0, SROM11_RPCAL_5GL, 0xffff}, - {"rpcal5gb1", 0xfffff800, 0, SROM11_RPCAL_5GM, 0xffff}, - {"rpcal5gb2", 0xfffff800, 0, SROM11_RPCAL_5GH, 0xffff}, - {"rpcal5gb3", 0xfffff800, 0, SROM11_RPCAL_5GU, 0xffff}, - {"txidxcap2g", 0xfffff800, 0, SROM11_TXIDXCAP2G, 0x0ff0}, - {"txidxcap5g", 0xfffff800, 0, SROM11_TXIDXCAP5G, 0x0ff0}, - {"pdoffsetcckma0", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x000f}, - {"pdoffsetcckma1", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x00f0}, - {"pdoffsetcckma2", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x0f00}, - {NULL, 0, 0, 0, 0} -}; - -static const sromvar_t perpath_pci_sromvars[] = { - {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff}, - {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, - {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, - {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, - {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, - {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, - {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, - {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff}, - {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff}, - {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, - {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, - {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, - {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, - {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, - {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, - {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff}, - {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff}, - {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff}, - {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, - {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff}, - {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff}, - {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff}, - {"maxp2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0x00ff}, - {"itt2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0xff00}, - {"itt5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0xff00}, - {"pa2gw0a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, - {"pa2gw1a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, - {"pa2gw2a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, - {"maxp5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0x00ff}, - {"maxp5gha", 0x00000700, 0, SROM8_5GLH_MAXP, 0x00ff}, - {"maxp5gla", 0x00000700, 0, SROM8_5GLH_MAXP, 0xff00}, - {"pa5gw0a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, - {"pa5gw1a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, - {"pa5gw2a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, - {"pa5glw0a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, - {"pa5glw1a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff}, - {"pa5glw2a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff}, - {"pa5ghw0a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, - {"pa5ghw1a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff}, - {"pa5ghw2a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff}, - - /* sromrev 11 */ - {"maxp2ga", 0xfffff800, 0, SROM11_2G_MAXP, 0x00ff}, - {"pa2ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_2G_PA + 2, 0xffff}, - {"rxgains5gmelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0007}, - {"rxgains5gmtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0078}, - {"rxgains5gmtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0080}, - {"rxgains5ghelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0700}, - {"rxgains5ghtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x7800}, - {"rxgains5ghtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x8000}, - {"rxgains2gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0007}, - {"rxgains2gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x0078}, - {"rxgains2gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x0080}, - {"rxgains5gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0700}, - {"rxgains5gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x7800}, - {"rxgains5gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x8000}, - {"maxp5ga", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0x00ff}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0xff00}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB3B2_MAXP, 0x00ff}, - {"", 0xfffff800, 0, SROM11_5GB3B2_MAXP, 0xff00}, - {"pa5ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_5GB3_PA + 2, 0xffff}, - - {NULL, 0, 0, 0, 0} -}; - -#if !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) -#define PHY_TYPE_HT 7 /* HT-Phy value */ -#define PHY_TYPE_N 4 /* N-Phy value */ -#define PHY_TYPE_LP 5 /* LP-Phy value */ -#endif /* !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) */ -#if !defined(PHY_TYPE_AC) -#define PHY_TYPE_AC 11 /* AC-Phy value */ -#endif /* !defined(PHY_TYPE_AC) */ -#if !defined(PHY_TYPE_NULL) -#define PHY_TYPE_NULL 0xf /* Invalid Phy value */ -#endif /* !defined(PHY_TYPE_NULL) */ - -typedef struct { - uint16 phy_type; - uint16 bandrange; - uint16 chain; - const char *vars; -} pavars_t; - -static const pavars_t pavars[] = { - /* HTPHY */ - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 2, "pa2gw0a2 pa2gw1a2 pa2gw2a2"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 2, "pa5glw0a2 pa5glw1a2 pa5glw2a2"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 2, "pa5gw0a2 pa5gw1a2 pa5gw2a2"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 2, "pa5ghw0a2 pa5ghw1a2 pa5ghw2a2"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 0, "pa5gw0a3 pa5gw1a3 pa5gw2a3"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 1, "pa5glw0a3 pa5glw1a3 pa5glw2a3"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 2, "pa5ghw0a3 pa5ghw1a3 pa5ghw2a3"}, - /* NPHY */ - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, - /* LPPHY */ - {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_2G, 0, "pa0b0 pa0b1 pa0b2"}, - {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GL, 0, "pa1lob0 pa1lob1 pa1lob2"}, - {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GM, 0, "pa1b0 pa1b1 pa1b2"}, - {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GH, 0, "pa1hib0 pa1hib1 pa1hib2"}, - /* ACPHY */ - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5ga2"}, - {PHY_TYPE_NULL, 0, 0, ""} -}; - -/* pavars table when paparambwver is 1 */ -static const pavars_t pavars_bwver_1[] = { - /* ACPHY */ - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gccka0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga2"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5gbw40a0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw80a0"}, - {PHY_TYPE_NULL, 0, 0, ""} -}; - -/* pavars table when paparambwver is 2 */ -static const pavars_t pavars_bwver_2[] = { - /* ACPHY */ - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw4080a0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 3, "pa5gbw4080a1"}, - {PHY_TYPE_NULL, 0, 0, ""} -}; - -typedef struct { - uint16 phy_type; - uint16 bandrange; - const char *vars; -} povars_t; - -static const povars_t povars[] = { - /* NPHY */ - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, "mcs2gpo0 mcs2gpo1 mcs2gpo2 mcs2gpo3 " - "mcs2gpo4 mcs2gpo5 mcs2gpo6 mcs2gpo7"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, "mcs5glpo0 mcs5glpo1 mcs5glpo2 mcs5glpo3 " - "mcs5glpo4 mcs5glpo5 mcs5glpo6 mcs5glpo7"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, "mcs5gpo0 mcs5gpo1 mcs5gpo2 mcs5gpo3 " - "mcs5gpo4 mcs5gpo5 mcs5gpo6 mcs5gpo7"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, "mcs5ghpo0 mcs5ghpo1 mcs5ghpo2 mcs5ghpo3 " - "mcs5ghpo4 mcs5ghpo5 mcs5ghpo6 mcs5ghpo7"}, - {PHY_TYPE_NULL, 0, ""} -}; - -typedef struct { - uint8 tag; /* Broadcom subtag name */ - uint32 revmask; /* Supported cis_sromrev */ - uint8 len; /* Length field of the tuple, note that it includes the - * subtag name (1 byte): 1 + tuple content length - */ - const char *params; -} cis_tuple_t; - -#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */ -#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */ -#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */ -#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */ - -static const cis_tuple_t cis_hnbuvars[] = { - {OTP_RAW1, 0xffffffff, 0, ""}, /* special case */ - {OTP_VERS_1, 0xffffffff, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */ - {OTP_MANFID, 0xffffffff, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */ - /* Unified OTP: tupple to embed USB manfid inside SDIO CIS */ - {HNBU_UMANFID, 0xffffffff, 8, "8usbmanfid"}, - {HNBU_SROMREV, 0xffffffff, 2, "1sromrev"}, - /* NOTE: subdevid is also written to boardtype. - * Need to write HNBU_BOARDTYPE to change it if it is different. - */ - {HNBU_CHIPID, 0xffffffff, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"}, - {HNBU_BOARDREV, 0xffffffff, 3, "2boardrev"}, - {HNBU_PAPARMS, 0xffffffff, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"}, - {HNBU_AA, 0xffffffff, 3, "1aa2g 1aa5g"}, - {HNBU_AA, 0xffffffff, 3, "1aa0 1aa1"}, /* backward compatibility */ - {HNBU_AG, 0xffffffff, 5, "1ag0 1ag1 1ag2 1ag3"}, - {HNBU_BOARDFLAGS, 0xffffffff, 21, "4boardflags 4boardflags2 4boardflags3 " - "4boardflags4 4boardflags5 "}, - {HNBU_LEDS, 0xffffffff, 17, "1ledbh0 1ledbh1 1ledbh2 1ledbh3 1ledbh4 1ledbh5 " - "1ledbh6 1ledbh7 1ledbh8 1ledbh9 1ledbh10 1ledbh11 1ledbh12 1ledbh13 1ledbh14 1ledbh15"}, - {HNBU_CCODE, 0xffffffff, 4, "2ccode 1cctl"}, - {HNBU_CCKPO, 0xffffffff, 3, "2cckpo"}, - {HNBU_OFDMPO, 0xffffffff, 5, "4ofdmpo"}, - {HNBU_PAPARMS5G, 0xffffffff, 23, "2pa1b0 2pa1b1 2pa1b2 2pa1lob0 2pa1lob1 2pa1lob2 " - "2pa1hib0 2pa1hib1 2pa1hib2 1pa1itssit " - "1pa1maxpwr 1pa1lomaxpwr 1pa1himaxpwr"}, - {HNBU_RDLID, 0xffffffff, 3, "2rdlid"}, - {HNBU_RSSISMBXA2G, 0xffffffff, 3, "0rssismf2g 0rssismc2g " - "0rssisav2g 0bxa2g"}, /* special case */ - {HNBU_RSSISMBXA5G, 0xffffffff, 3, "0rssismf5g 0rssismc5g " - "0rssisav5g 0bxa5g"}, /* special case */ - {HNBU_XTALFREQ, 0xffffffff, 5, "4xtalfreq"}, - {HNBU_TRI2G, 0xffffffff, 2, "1tri2g"}, - {HNBU_TRI5G, 0xffffffff, 4, "1tri5gl 1tri5g 1tri5gh"}, - {HNBU_RXPO2G, 0xffffffff, 2, "1rxpo2g"}, - {HNBU_RXPO5G, 0xffffffff, 2, "1rxpo5g"}, - {HNBU_BOARDNUM, 0xffffffff, 3, "2boardnum"}, - {HNBU_MACADDR, 0xffffffff, 7, "6macaddr"}, /* special case */ - {HNBU_RDLSN, 0xffffffff, 3, "2rdlsn"}, - {HNBU_BOARDTYPE, 0xffffffff, 3, "2boardtype"}, - {HNBU_LEDDC, 0xffffffff, 3, "2leddc"}, - {HNBU_RDLRNDIS, 0xffffffff, 2, "1rdlndis"}, - {HNBU_CHAINSWITCH, 0xffffffff, 5, "1txchain 1rxchain 2antswitch"}, - {HNBU_REGREV, 0xffffffff, 2, "1regrev"}, - {HNBU_FEM, 0x000007fe, 5, "0antswctl2g 0triso2g 0pdetrange2g 0extpagain2g " - "0tssipos2g 0antswctl5g 0triso5g 0pdetrange5g 0extpagain5g 0tssipos5g"}, /* special case */ - {HNBU_PAPARMS_C0, 0x000007fe, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 " - "2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 2pa5gw1a0 2pa5gw2a0 " - "2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 2pa5ghw1a0 2pa5ghw2a0"}, - {HNBU_PAPARMS_C1, 0x000007fe, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 " - "2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 2pa5gw1a1 2pa5gw2a1 " - "2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 2pa5ghw1a1 2pa5ghw2a1"}, - {HNBU_PO_CCKOFDM, 0xffffffff, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo " - "4ofdm5ghpo"}, - {HNBU_PO_MCS2G, 0xffffffff, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 " - "2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"}, - {HNBU_PO_MCS5GM, 0xffffffff, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 " - "2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"}, - {HNBU_PO_MCS5GLH, 0xffffffff, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 " - "2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 " - "2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 " - "2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"}, - {HNBU_CCKFILTTYPE, 0xffffffff, 2, "1cckdigfilttype"}, - {HNBU_PO_CDD, 0xffffffff, 3, "2cddpo"}, - {HNBU_PO_STBC, 0xffffffff, 3, "2stbcpo"}, - {HNBU_PO_40M, 0xffffffff, 3, "2bw40po"}, - {HNBU_PO_40MDUP, 0xffffffff, 3, "2bwduppo"}, - {HNBU_RDLRWU, 0xffffffff, 2, "1rdlrwu"}, - {HNBU_WPS, 0xffffffff, 3, "1wpsgpio 1wpsled"}, - {HNBU_USBFS, 0xffffffff, 2, "1usbfs"}, - {HNBU_ELNA2G, 0xffffffff, 2, "1elna2g"}, - {HNBU_ELNA5G, 0xffffffff, 2, "1elna5g"}, - {HNBU_CUSTOM1, 0xffffffff, 5, "4customvar1"}, - {OTP_RAW, 0xffffffff, 0, ""}, /* special case */ - {HNBU_OFDMPO5G, 0xffffffff, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"}, - {HNBU_USBEPNUM, 0xffffffff, 3, "2usbepnum"}, - {HNBU_CCKBW202GPO, 0xffffffff, 7, "2cckbw202gpo 2cckbw20ul2gpo 2cckbw20in802gpo"}, - {HNBU_LEGOFDMBW202GPO, 0xffffffff, 9, "4legofdmbw202gpo 4legofdmbw20ul2gpo"}, - {HNBU_LEGOFDMBW205GPO, 0xffffffff, 25, "4legofdmbw205glpo 4legofdmbw20ul5glpo " - "4legofdmbw205gmpo 4legofdmbw20ul5gmpo 4legofdmbw205ghpo 4legofdmbw20ul5ghpo"}, - {HNBU_MCS2GPO, 0xffffffff, 17, "4mcsbw202gpo 4mcsbw20ul2gpo 4mcsbw402gpo 4mcsbw802gpo"}, - {HNBU_MCS5GLPO, 0xffffffff, 13, "4mcsbw205glpo 4mcsbw20ul5glpo 4mcsbw405glpo"}, - {HNBU_MCS5GMPO, 0xffffffff, 13, "4mcsbw205gmpo 4mcsbw20ul5gmpo 4mcsbw405gmpo"}, - {HNBU_MCS5GHPO, 0xffffffff, 13, "4mcsbw205ghpo 4mcsbw20ul5ghpo 4mcsbw405ghpo"}, - {HNBU_MCS32PO, 0xffffffff, 3, "2mcs32po"}, - {HNBU_LEG40DUPPO, 0xffffffff, 3, "2legofdm40duppo"}, - {HNBU_TEMPTHRESH, 0xffffffff, 7, "1tempthresh 0temps_period 0temps_hysteresis " - "1tempoffset 1tempsense_slope 0tempcorrx 0tempsense_option " - "1phycal_tempdelta"}, /* special case */ - {HNBU_MUXENAB, 0xffffffff, 2, "1muxenab"}, - {HNBU_FEM_CFG, 0xfffff800, 5, "0femctrl 0papdcap2g 0tworangetssi2g 0pdgain2g " - "0epagain2g 0tssiposslope2g 0gainctrlsph 0papdcap5g 0tworangetssi5g 0pdgain5g 0epagain5g " - "0tssiposslope5g"}, /* special case */ - {HNBU_ACPA_C0, 0xfffff800, 39, "2subband5gver 2maxp2ga0 2*3pa2ga0 " - "1*4maxp5ga0 2*12pa5ga0"}, - {HNBU_ACPA_C1, 0xfffff800, 37, "2maxp2ga1 2*3pa2ga1 1*4maxp5ga1 2*12pa5ga1"}, - {HNBU_ACPA_C2, 0xfffff800, 37, "2maxp2ga2 2*3pa2ga2 1*4maxp5ga2 2*12pa5ga2"}, - {HNBU_MEAS_PWR, 0xfffff800, 5, "1measpower 1measpower1 1measpower2 2rawtempsense"}, - {HNBU_PDOFF, 0xfffff800, 13, "2pdoffset40ma0 2pdoffset40ma1 2pdoffset40ma2 " - "2pdoffset80ma0 2pdoffset80ma1 2pdoffset80ma2"}, - {HNBU_ACPPR_2GPO, 0xfffff800, 13, "2dot11agofdmhrbw202gpo 2ofdmlrbw202gpo " - "2sb20in40dot11agofdm2gpo 2sb20in80dot11agofdm2gpo 2sb20in40ofdmlrbw202gpo " - "2sb20in80ofdmlrbw202gpo"}, - {HNBU_ACPPR_5GPO, 0xfffff800, 59, "4mcsbw805glpo 4mcsbw1605glpo 4mcsbw805gmpo " - "4mcsbw1605gmpo 4mcsbw805ghpo 4mcsbw1605ghpo 2mcslr5glpo 2mcslr5gmpo 2mcslr5ghpo " - "4mcsbw80p805glpo 4mcsbw80p805gmpo 4mcsbw80p805ghpo 4mcsbw80p805gx1po 2mcslr5gx1po " - "2mcslr5g80p80po 4mcsbw805gx1po 4mcsbw1605gx1po"}, - {HNBU_MCS5Gx1PO, 0xfffff800, 9, "4mcsbw205gx1po 4mcsbw405gx1po"}, - {HNBU_ACPPR_SBPO, 0xfffff800, 49, "2sb20in40hrpo 2sb20in80and160hr5glpo " - "2sb40and80hr5glpo 2sb20in80and160hr5gmpo 2sb40and80hr5gmpo 2sb20in80and160hr5ghpo " - "2sb40and80hr5ghpo 2sb20in40lrpo 2sb20in80and160lr5glpo 2sb40and80lr5glpo " - "2sb20in80and160lr5gmpo 2sb40and80lr5gmpo 2sb20in80and160lr5ghpo 2sb40and80lr5ghpo " - "4dot11agduphrpo 4dot11agduplrpo 2sb20in40and80hrpo 2sb20in40and80lrpo " - "2sb20in80and160hr5gx1po 2sb20in80and160lr5gx1po 2sb40and80hr5gx1po 2sb40and80lr5gx1po " - }, - {HNBU_ACPPR_SB8080_PO, 0xfffff800, 23, "2sb2040and80in80p80hr5glpo " - "2sb2040and80in80p80lr5glpo 2sb2040and80in80p80hr5gmpo " - "2sb2040and80in80p80lr5gmpo 2sb2040and80in80p80hr5ghpo 2sb2040and80in80p80lr5ghpo " - "2sb2040and80in80p80hr5gx1po 2sb2040and80in80p80lr5gx1po 2sb20in80p80hr5gpo " - "2sb20in80p80lr5gpo 2dot11agduppo"}, - {HNBU_NOISELVL, 0xfffff800, 16, "1noiselvl2ga0 1noiselvl2ga1 1noiselvl2ga2 " - "1*4noiselvl5ga0 1*4noiselvl5ga1 1*4noiselvl5ga2"}, - {HNBU_RXGAIN_ERR, 0xfffff800, 16, "1rxgainerr2ga0 1rxgainerr2ga1 1rxgainerr2ga2 " - "1*4rxgainerr5ga0 1*4rxgainerr5ga1 1*4rxgainerr5ga2"}, - {HNBU_AGBGA, 0xfffff800, 7, "1agbg0 1agbg1 1agbg2 1aga0 1aga1 1aga2"}, - {HNBU_USBDESC_COMPOSITE, 0xffffffff, 3, "2usbdesc_composite"}, - {HNBU_UUID, 0xffffffff, 17, "16uuid"}, - {HNBU_WOWLGPIO, 0xffffffff, 2, "1wowl_gpio"}, - {HNBU_ACRXGAINS_C0, 0xfffff800, 5, "0rxgains5gtrelnabypa0 0rxgains5gtrisoa0 " - "0rxgains5gelnagaina0 0rxgains2gtrelnabypa0 0rxgains2gtrisoa0 0rxgains2gelnagaina0 " - "0rxgains5ghtrelnabypa0 0rxgains5ghtrisoa0 0rxgains5ghelnagaina0 0rxgains5gmtrelnabypa0 " - "0rxgains5gmtrisoa0 0rxgains5gmelnagaina0"}, /* special case */ - {HNBU_ACRXGAINS_C1, 0xfffff800, 5, "0rxgains5gtrelnabypa1 0rxgains5gtrisoa1 " - "0rxgains5gelnagaina1 0rxgains2gtrelnabypa1 0rxgains2gtrisoa1 0rxgains2gelnagaina1 " - "0rxgains5ghtrelnabypa1 0rxgains5ghtrisoa1 0rxgains5ghelnagaina1 0rxgains5gmtrelnabypa1 " - "0rxgains5gmtrisoa1 0rxgains5gmelnagaina1"}, /* special case */ - {HNBU_ACRXGAINS_C2, 0xfffff800, 5, "0rxgains5gtrelnabypa2 0rxgains5gtrisoa2 " - "0rxgains5gelnagaina2 0rxgains2gtrelnabypa2 0rxgains2gtrisoa2 0rxgains2gelnagaina2 " - "0rxgains5ghtrelnabypa2 0rxgains5ghtrisoa2 0rxgains5ghelnagaina2 0rxgains5gmtrelnabypa2 " - "0rxgains5gmtrisoa2 0rxgains5gmelnagaina2"}, /* special case */ - {HNBU_TXDUTY, 0xfffff800, 9, "2tx_duty_cycle_ofdm_40_5g " - "2tx_duty_cycle_thresh_40_5g 2tx_duty_cycle_ofdm_80_5g 2tx_duty_cycle_thresh_80_5g"}, - {HNBU_PDOFF_2G, 0xfffff800, 3, "0pdoffset2g40ma0 0pdoffset2g40ma1 " - "0pdoffset2g40ma2 0pdoffset2g40mvalid"}, - {HNBU_ACPA_CCK, 0xfffff800, 7, "2*3pa2gccka0"}, - {HNBU_ACPA_40, 0xfffff800, 25, "2*12pa5gbw40a0"}, - {HNBU_ACPA_80, 0xfffff800, 25, "2*12pa5gbw80a0"}, - {HNBU_ACPA_4080, 0xfffff800, 49, "2*12pa5gbw4080a0 2*12pa5gbw4080a1"}, - {HNBU_SUBBAND5GVER, 0xfffff800, 3, "2subband5gver"}, - {HNBU_PAPARAMBWVER, 0xfffff800, 2, "1paparambwver"}, - {0xFF, 0xffffffff, 0, ""} -}; - -#endif /* _bcmsrom_tbl_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h deleted file mode 100644 index a3ba46436161..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmutils.h +++ /dev/null @@ -1,1174 +0,0 @@ -/* - * Misc useful os-independent macros and functions. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmutils.h 504037 2014-09-22 19:03:15Z $ - */ - -#ifndef _bcmutils_h_ -#define _bcmutils_h_ - -#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) -#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) -#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) - -#ifdef __cplusplus -extern "C" { -#endif - - -#ifdef PKTQ_LOG -#include -#endif - -/* ctype replacement */ -#define _BCM_U 0x01 /* upper */ -#define _BCM_L 0x02 /* lower */ -#define _BCM_D 0x04 /* digit */ -#define _BCM_C 0x08 /* cntrl */ -#define _BCM_P 0x10 /* punct */ -#define _BCM_S 0x20 /* white space (space/lf/tab) */ -#define _BCM_X 0x40 /* hex digit */ -#define _BCM_SP 0x80 /* hard space (0x20) */ - -extern const unsigned char bcm_ctype[]; -#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) - -#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) -#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) -#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) -#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) -#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) -#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) -#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) -#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) -#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) -#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) -#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) -#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) -#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) - -#define CIRCULAR_ARRAY_FULL(rd_idx, wr_idx, max) ((wr_idx + 1)%max == rd_idx) - -/* Buffer structure for collecting string-formatted data -* using bcm_bprintf() API. -* Use bcm_binit() to initialize before use -*/ - -struct bcmstrbuf { - char *buf; /* pointer to current position in origbuf */ - unsigned int size; /* current (residual) size in bytes */ - char *origbuf; /* unmodified pointer to orignal buffer */ - unsigned int origsize; /* unmodified orignal buffer size in bytes */ -}; - -/* ** driver-only section ** */ -#ifdef BCMDRIVER -#include -#include -#include - -#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */ - -/* - * 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. - */ -#ifndef SPINWAIT_POLL_PERIOD -#define SPINWAIT_POLL_PERIOD 10 -#endif - -#define SPINWAIT(exp, us) { \ - uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1); \ - while ((exp) && (countdown >= SPINWAIT_POLL_PERIOD)) { \ - OSL_DELAY(SPINWAIT_POLL_PERIOD); \ - countdown -= SPINWAIT_POLL_PERIOD; \ - } \ -} - -/* forward definition of ether_addr structure used by some function prototypes */ - -struct ether_addr; - -extern int ether_isbcast(const void *ea); -extern int ether_isnulladdr(const void *ea); - -#define BCM_MAC_RXCPL_IDX_BITS 12 -#define BCM_MAX_RXCPL_IDX_INVALID 0 -#define BCM_MAC_RXCPL_IFIDX_BITS 3 -#define BCM_MAC_RXCPL_DOT11_BITS 1 -#define BCM_MAX_RXCPL_IFIDX ((1 << BCM_MAC_RXCPL_IFIDX_BITS) - 1) -#define BCM_MAC_RXCPL_FLAG_BITS 4 -#define BCM_RXCPL_FLAGS_IN_TRANSIT 0x1 -#define BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST 0x2 -#define BCM_RXCPL_FLAGS_RXCPLVALID 0x4 -#define BCM_RXCPL_FLAGS_RSVD 0x8 - -#define BCM_RXCPL_SET_IN_TRANSIT(a) ((a)->rxcpl_id.flags |= BCM_RXCPL_FLAGS_IN_TRANSIT) -#define BCM_RXCPL_CLR_IN_TRANSIT(a) ((a)->rxcpl_id.flags &= ~BCM_RXCPL_FLAGS_IN_TRANSIT) -#define BCM_RXCPL_IN_TRANSIT(a) ((a)->rxcpl_id.flags & BCM_RXCPL_FLAGS_IN_TRANSIT) - -#define BCM_RXCPL_SET_FRST_IN_FLUSH(a) ((a)->rxcpl_id.flags |= BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST) -#define BCM_RXCPL_CLR_FRST_IN_FLUSH(a) ((a)->rxcpl_id.flags &= ~BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST) -#define BCM_RXCPL_FRST_IN_FLUSH(a) ((a)->rxcpl_id.flags & BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST) - -#define BCM_RXCPL_SET_VALID_INFO(a) ((a)->rxcpl_id.flags |= BCM_RXCPL_FLAGS_RXCPLVALID) -#define BCM_RXCPL_CLR_VALID_INFO(a) ((a)->rxcpl_id.flags &= ~BCM_RXCPL_FLAGS_RXCPLVALID) -#define BCM_RXCPL_VALID_INFO(a) (((a)->rxcpl_id.flags & BCM_RXCPL_FLAGS_RXCPLVALID) ? TRUE : FALSE) - - -struct reorder_rxcpl_id_list { - uint16 head; - uint16 tail; - uint32 cnt; -}; - -typedef struct rxcpl_id { - uint32 idx : BCM_MAC_RXCPL_IDX_BITS; - uint32 next_idx : BCM_MAC_RXCPL_IDX_BITS; - uint32 ifidx : BCM_MAC_RXCPL_IFIDX_BITS; - uint32 dot11 : BCM_MAC_RXCPL_DOT11_BITS; - uint32 flags : BCM_MAC_RXCPL_FLAG_BITS; -} rxcpl_idx_id_t; - -typedef struct rxcpl_data_len { - uint32 metadata_len_w : 6; - uint32 dataoffset: 10; - uint32 datalen : 16; -} rxcpl_data_len_t; - -typedef struct rxcpl_info { - rxcpl_idx_id_t rxcpl_id; - uint32 host_pktref; - union { - rxcpl_data_len_t rxcpl_len; - struct rxcpl_info *free_next; - }; -} rxcpl_info_t; - -/* rx completion list */ -typedef struct bcm_rxcplid_list { - uint32 max; - uint32 avail; - rxcpl_info_t *rxcpl_ptr; - rxcpl_info_t *free_list; -} bcm_rxcplid_list_t; - -extern bool bcm_alloc_rxcplid_list(osl_t *osh, uint32 max); -extern rxcpl_info_t * bcm_alloc_rxcplinfo(void); -extern void bcm_free_rxcplinfo(rxcpl_info_t *ptr); -extern void bcm_chain_rxcplid(uint16 first, uint16 next); -extern rxcpl_info_t *bcm_id2rxcplinfo(uint16 id); -extern uint16 bcm_rxcplinfo2id(rxcpl_info_t *ptr); -extern rxcpl_info_t *bcm_rxcpllist_end(rxcpl_info_t *ptr, uint32 *count); - -/* externs */ -/* packet */ -extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); -extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); -extern uint pkttotlen(osl_t *osh, void *p); -extern void *pktlast(osl_t *osh, void *p); -extern uint pktsegcnt(osl_t *osh, void *p); -extern uint pktsegcnt_war(osl_t *osh, void *p); -extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset); -extern void *pktoffset(osl_t *osh, void *p, uint offset); - -/* Get priority from a packet and pass it back in scb (or equiv) */ -#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */ -#define PKTPRIO_VLAN 0x200 /* VLAN prio found */ -#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ -#define PKTPRIO_DSCP 0x800 /* DSCP prio found */ - -/* DSCP type definitions (RFC4594) */ -/* AF1x: High-Throughput Data (RFC2597) */ -#define DSCP_AF11 0x0A -#define DSCP_AF12 0x0C -#define DSCP_AF13 0x0E -/* AF2x: Low-Latency Data (RFC2597) */ -#define DSCP_AF21 0x12 -#define DSCP_AF22 0x14 -#define DSCP_AF23 0x16 -/* AF3x: Multimedia Streaming (RFC2597) */ -#define DSCP_AF31 0x1A -#define DSCP_AF32 0x1C -#define DSCP_AF33 0x1E -/* EF: Telephony (RFC3246) */ -#define DSCP_EF 0x2E - -extern uint pktsetprio(void *pkt, bool update_vtag); -extern bool pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp); - -/* string */ -extern int bcm_atoi(const char *s); -extern ulong bcm_strtoul(const char *cp, char **endp, uint base); -extern char *bcmstrstr(const char *haystack, const char *needle); -extern char *bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len); -extern char *bcmstrcat(char *dest, const char *src); -extern char *bcmstrncat(char *dest, const char *src, uint size); -extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); -char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); -int bcmstricmp(const char *s1, const char *s2); -int bcmstrnicmp(const char* s1, const char* s2, int cnt); - - -/* ethernet address */ -extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); -extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); - -/* ip address */ -struct ipv4_addr; -extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); -extern char *bcm_ipv6_ntoa(void *ipv6, char *buf); -extern int bcm_atoipv4(const char *p, struct ipv4_addr *ip); - -/* delay */ -extern void bcm_mdelay(uint ms); -/* variable access */ -#define NVRAM_RECLAIM_CHECK(name) - -extern char *getvar(char *vars, const char *name); -extern int getintvar(char *vars, const char *name); -extern int getintvararray(char *vars, const char *name, int index); -extern int getintvararraysize(char *vars, const char *name); -extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); -#define bcm_perf_enable() -#define bcmstats(fmt) -#define bcmlog(fmt, a1, a2) -#define bcmdumplog(buf, size) *buf = '\0' -#define bcmdumplogent(buf, idx) -1 - -#define TSF_TICKS_PER_MS 1000 -#define TS_ENTER 0xdeadbeef /* Timestamp profiling enter */ -#define TS_EXIT 0xbeefcafe /* Timestamp profiling exit */ - -#define bcmtslog(tstamp, fmt, a1, a2) -#define bcmprinttslogs() -#define bcmprinttstamp(us) -#define bcmdumptslog(buf, size) - -extern char *bcm_nvram_vars(uint *length); -extern int bcm_nvram_cache(void *sih); - -/* Support for sharing code across in-driver iovar implementations. - * The intent is that a driver use this structure to map iovar names - * to its (private) iovar identifiers, and the lookup function to - * find the entry. Macros are provided to map ids and get/set actions - * into a single number space for a switch statement. - */ - -/* iovar structure */ -typedef struct bcm_iovar { - const char *name; /* name for lookup and display */ - uint16 varid; /* id for switch */ - uint16 flags; /* driver-specific flag bits */ - uint16 type; /* base type of argument */ - uint16 minlen; /* min length for buffer vars */ -} bcm_iovar_t; - -/* varid definitions are per-driver, may use these get/set bits */ - -/* IOVar action bits for id mapping */ -#define IOV_GET 0 /* Get an iovar */ -#define IOV_SET 1 /* Set an iovar */ - -/* Varid to actionid mapping */ -#define IOV_GVAL(id) ((id) * 2) -#define IOV_SVAL(id) ((id) * 2 + IOV_SET) -#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) -#define IOV_ID(actionid) (actionid >> 1) - -/* flags are per-driver based on driver attributes */ - -extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); -extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); -#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ - defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) -extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); -#endif -#endif /* BCMDRIVER */ - -/* Base type definitions */ -#define IOVT_VOID 0 /* no value (implictly set only) */ -#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */ -#define IOVT_INT8 2 /* integer values are range-checked */ -#define IOVT_UINT8 3 /* unsigned int 8 bits */ -#define IOVT_INT16 4 /* int 16 bits */ -#define IOVT_UINT16 5 /* unsigned int 16 bits */ -#define IOVT_INT32 6 /* int 32 bits */ -#define IOVT_UINT32 7 /* unsigned int 32 bits */ -#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */ -#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) - -/* Initializer for IOV type strings */ -#define BCM_IOV_TYPE_INIT { \ - "void", \ - "bool", \ - "int8", \ - "uint8", \ - "int16", \ - "uint16", \ - "int32", \ - "uint32", \ - "buffer", \ - "" } - -#define BCM_IOVT_IS_INT(type) (\ - (type == IOVT_BOOL) || \ - (type == IOVT_INT8) || \ - (type == IOVT_UINT8) || \ - (type == IOVT_INT16) || \ - (type == IOVT_UINT16) || \ - (type == IOVT_INT32) || \ - (type == IOVT_UINT32)) - -/* ** driver/apps-shared section ** */ - -#define BCME_STRLEN 64 /* Max string length for BCM errors */ -#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) - - -/* - * error codes could be added but the defined ones shouldn't be changed/deleted - * these error codes are exposed to the user code - * when ever a new error code is added to this list - * please update errorstring table with the related error string and - * update osl files with os specific errorcode map -*/ - -#define BCME_OK 0 /* Success */ -#define BCME_ERROR -1 /* Error generic */ -#define BCME_BADARG -2 /* Bad Argument */ -#define BCME_BADOPTION -3 /* Bad option */ -#define BCME_NOTUP -4 /* Not up */ -#define BCME_NOTDOWN -5 /* Not down */ -#define BCME_NOTAP -6 /* Not AP */ -#define BCME_NOTSTA -7 /* Not STA */ -#define BCME_BADKEYIDX -8 /* BAD Key Index */ -#define BCME_RADIOOFF -9 /* Radio Off */ -#define BCME_NOTBANDLOCKED -10 /* Not band locked */ -#define BCME_NOCLK -11 /* No Clock */ -#define BCME_BADRATESET -12 /* BAD Rate valueset */ -#define BCME_BADBAND -13 /* BAD Band */ -#define BCME_BUFTOOSHORT -14 /* Buffer too short */ -#define BCME_BUFTOOLONG -15 /* Buffer too long */ -#define BCME_BUSY -16 /* Busy */ -#define BCME_NOTASSOCIATED -17 /* Not Associated */ -#define BCME_BADSSIDLEN -18 /* Bad SSID len */ -#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ -#define BCME_BADCHAN -20 /* Bad Channel */ -#define BCME_BADADDR -21 /* Bad Address */ -#define BCME_NORESOURCE -22 /* Not Enough Resources */ -#define BCME_UNSUPPORTED -23 /* Unsupported */ -#define BCME_BADLEN -24 /* Bad length */ -#define BCME_NOTREADY -25 /* Not Ready */ -#define BCME_EPERM -26 /* Not Permitted */ -#define BCME_NOMEM -27 /* No Memory */ -#define BCME_ASSOCIATED -28 /* Associated */ -#define BCME_RANGE -29 /* Not In Range */ -#define BCME_NOTFOUND -30 /* Not Found */ -#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ -#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ -#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ -#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ -#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ -#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ -#define BCME_VERSION -37 /* Incorrect version */ -#define BCME_TXFAIL -38 /* TX failure */ -#define BCME_RXFAIL -39 /* RX failure */ -#define BCME_NODEVICE -40 /* Device not present */ -#define BCME_NMODE_DISABLED -41 /* NMODE disabled */ -#define BCME_NONRESIDENT -42 /* access to nonresident overlay */ -#define BCME_SCANREJECT -43 /* reject scan request */ -#define BCME_USAGE_ERROR -44 /* WLCMD usage error */ -#define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */ -#define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */ -#define BCME_DISABLED -47 /* Disabled in this build */ -#define BCME_DECERR -48 /* Decrypt error */ -#define BCME_ENCERR -49 /* Encrypt error */ -#define BCME_MICERR -50 /* Integrity/MIC error */ -#define BCME_REPLAY -51 /* Replay */ -#define BCME_IE_NOTFOUND -52 /* IE not found */ -#define BCME_LAST BCME_IE_NOTFOUND - -#define BCME_NOTENABLED BCME_DISABLED - -/* These are collection of BCME Error strings */ -#define BCMERRSTRINGTABLE { \ - "OK", \ - "Undefined error", \ - "Bad Argument", \ - "Bad Option", \ - "Not up", \ - "Not down", \ - "Not AP", \ - "Not STA", \ - "Bad Key Index", \ - "Radio Off", \ - "Not band locked", \ - "No clock", \ - "Bad Rate valueset", \ - "Bad Band", \ - "Buffer too short", \ - "Buffer too long", \ - "Busy", \ - "Not Associated", \ - "Bad SSID len", \ - "Out of Range Channel", \ - "Bad Channel", \ - "Bad Address", \ - "Not Enough Resources", \ - "Unsupported", \ - "Bad length", \ - "Not Ready", \ - "Not Permitted", \ - "No Memory", \ - "Associated", \ - "Not In Range", \ - "Not Found", \ - "WME Not Enabled", \ - "TSPEC Not Found", \ - "ACM Not Supported", \ - "Not WME Association", \ - "SDIO Bus Error", \ - "Dongle Not Accessible", \ - "Incorrect version", \ - "TX Failure", \ - "RX Failure", \ - "Device Not Present", \ - "NMODE Disabled", \ - "Nonresident overlay access", \ - "Scan Rejected", \ - "WLCMD usage error", \ - "WLCMD ioctl error", \ - "RWL serial port error", \ - "Disabled", \ - "Decrypt error", \ - "Encrypt error", \ - "MIC error", \ - "Replay", \ - "IE not found", \ -} - -#ifndef ABS -#define ABS(a) (((a) < 0) ? -(a) : (a)) -#endif /* ABS */ - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif /* MIN */ - -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif /* MAX */ - -/* limit to [min, max] */ -#ifndef LIMIT_TO_RANGE -#define LIMIT_TO_RANGE(x, min, max) \ - ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) -#endif /* LIMIT_TO_RANGE */ - -/* limit to max */ -#ifndef LIMIT_TO_MAX -#define LIMIT_TO_MAX(x, max) \ - (((x) > (max) ? (max) : (x))) -#endif /* LIMIT_TO_MAX */ - -/* limit to min */ -#ifndef LIMIT_TO_MIN -#define LIMIT_TO_MIN(x, min) \ - (((x) < (min) ? (min) : (x))) -#endif /* LIMIT_TO_MIN */ - -#define DELTA(curr, prev) ((curr) > (prev) ? ((curr) - (prev)) : \ - (0xffffffff - (prev) + (curr) + 1)) -#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) -#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) -#define ROUNDDN(p, align) ((p) & ~((align) - 1)) -#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) -#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ - & ~((boundary) - 1)) -#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ - & ~((boundary) - 1)) -#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) -#define VALID_MASK(mask) !((mask) & ((mask) + 1)) - -#ifndef OFFSETOF -#ifdef __ARMCC_VERSION -/* - * The ARM RVCT compiler complains when using OFFSETOF where a constant - * expression is expected, such as an initializer for a static object. - * offsetof from the runtime library doesn't have that problem. - */ -#include -#define OFFSETOF(type, member) offsetof(type, member) -#else -# if ((__GNUC__ >= 4) && (__GNUC_MINOR__ >= 8)) -/* GCC 4.8+ complains when using our OFFSETOF macro in array length declarations. */ -# define OFFSETOF(type, member) __builtin_offsetof(type, member) -# else -# define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) -# endif /* GCC 4.8 or newer */ -#endif /* __ARMCC_VERSION */ -#endif /* OFFSETOF */ - -#ifndef ARRAYSIZE -#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) -#endif - -#ifndef ARRAYLAST /* returns pointer to last array element */ -#define ARRAYLAST(a) (&a[ARRAYSIZE(a)-1]) -#endif - -/* Reference a function; used to prevent a static function from being optimized out */ -extern void *_bcmutils_dummy_fn; -#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) - -/* bit map related macros */ -#ifndef setbit -#ifndef NBBY /* the BSD family defines NBBY */ -#define NBBY 8 /* 8 bits per byte */ -#endif /* #ifndef NBBY */ -#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS -extern void setbit(void *array, uint bit); -extern void clrbit(void *array, uint bit); -extern bool isset(const void *array, uint bit); -extern bool isclr(const void *array, uint bit); -#else -#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) -#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) -#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) -#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) -#endif -#endif /* setbit */ -extern void set_bitrange(void *array, uint start, uint end, uint maxbit); - -#define isbitset(a, i) (((a) & (1 << (i))) != 0) - -#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) - -extern void bcm_bitprint32(const uint32 u32); - -/* - * ---------------------------------------------------------------------------- - * Multiword map of 2bits, nibbles - * setbit2 setbit4 (void *ptr, uint32 ix, uint32 val) - * getbit2 getbit4 (void *ptr, uint32 ix) - * ---------------------------------------------------------------------------- - */ - -#define DECLARE_MAP_API(NB, RSH, LSH, OFF, MSK) \ -static INLINE void setbit##NB(void *ptr, uint32 ix, uint32 val) \ -{ \ - uint32 *addr = (uint32 *)ptr; \ - uint32 *a = addr + (ix >> RSH); /* (ix / 2^RSH) */ \ - uint32 pos = (ix & OFF) << LSH; /* (ix % 2^RSH) * 2^LSH */ \ - uint32 mask = (MSK << pos); \ - uint32 tmp = *a & ~mask; \ - *a = tmp | (val << pos); \ -} \ -static INLINE uint32 getbit##NB(void *ptr, uint32 ix) \ -{ \ - uint32 *addr = (uint32 *)ptr; \ - uint32 *a = addr + (ix >> RSH); \ - uint32 pos = (ix & OFF) << LSH; \ - return ((*a >> pos) & MSK); \ -} - -DECLARE_MAP_API(2, 4, 1, 15U, 0x0003) /* setbit2() and getbit2() */ -DECLARE_MAP_API(4, 3, 2, 7U, 0x000F) /* setbit4() and getbit4() */ -DECLARE_MAP_API(8, 2, 3, 3U, 0x00FF) /* setbit8() and getbit8() */ - -/* 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 MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 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)) - -/* modulo add/sub - assumes x, y E [0, bound - 1] */ -#define MODADD(x, y, bound) \ - MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) -#define MODSUB(x, y, bound) \ - MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) - -/* module 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)) - -/* crc defines */ -#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */ -#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */ -#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */ -#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */ -#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */ -#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */ - -/* use for direct output of MAC address in printf etc */ -#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" -#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ - ((struct ether_addr *) (ea))->octet[1], \ - ((struct ether_addr *) (ea))->octet[2], \ - ((struct ether_addr *) (ea))->octet[3], \ - ((struct ether_addr *) (ea))->octet[4], \ - ((struct ether_addr *) (ea))->octet[5] - -#define ETHER_TO_MACF(ea) (ea).octet[0], \ - (ea).octet[1], \ - (ea).octet[2], \ - (ea).octet[3], \ - (ea).octet[4], \ - (ea).octet[5] -#if !defined(SIMPLE_MAC_PRINT) -#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] -#else -#define MACDBG "%02x:%02x:%02x" -#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] -#endif /* SIMPLE_MAC_PRINT */ - -/* bcm_format_flags() bit description structure */ -typedef struct bcm_bit_desc { - uint32 bit; - const char* name; -} bcm_bit_desc_t; - -/* bcm_format_field */ -typedef struct bcm_bit_desc_ex { - uint32 mask; - const bcm_bit_desc_t *bitfield; -} bcm_bit_desc_ex_t; - -/* buffer length for ethernet address from bcm_ether_ntoa() */ -#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */ - -static INLINE uint32 /* 32bit word aligned xor-32 */ -bcm_compute_xor32(volatile uint32 *u32, int num_u32) -{ - int i; - uint32 xor32 = 0; - for (i = 0; i < num_u32; i++) - xor32 ^= *(u32 + i); - return xor32; -} - -/* crypto utility function */ -/* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */ -static INLINE void -xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) -{ - if ( -#ifdef __i386__ - 1 || -#endif - (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { - /* ARM CM3 rel time: 1229 (727 if alignment check could be omitted) */ - /* x86 supports unaligned. This version runs 6x-9x faster on x86. */ - ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; - ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; - ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; - ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; - } else { - /* ARM CM3 rel time: 4668 (4191 if alignment check could be omitted) */ - int k; - for (k = 0; k < 16; k++) - dst[k] = src1[k] ^ src2[k]; - } -} - -/* externs */ -/* crc */ -extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); -extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); -extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); - -/* format/print */ -#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ - defined(WLMSG_ASSOC) -/* print out the value a field has: fields may have 1-32 bits and may hold any value */ -extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len); -/* print out which bits in flags are set */ -extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); -#endif - -extern int bcm_format_hex(char *str, const void *bytes, int len); - -extern const char *bcm_crypto_algo_name(uint algo); -extern char *bcm_chipname(uint chipid, char *buf, uint len); -extern char *bcm_brev_str(uint32 brev, char *buf); -extern void printbig(char *buf); -extern void prhex(const char *msg, uchar *buf, uint len); - -/* IE parsing */ - -/* tag_ID/length/value_buffer tuple */ -typedef struct bcm_tlv { - uint8 id; - uint8 len; - uint8 data[1]; -} bcm_tlv_t; - -/* bcm tlv w/ 16 bit id/len */ -typedef struct bcm_xtlv { - uint16 id; - uint16 len; - uint8 data[1]; -} bcm_xtlv_t; - -/* descriptor of xtlv data src or dst */ -typedef struct { - uint16 type; - uint16 len; - void *ptr; /* ptr to memory location */ -} xtlv_desc_t; - -/* set a var from xtlv buffer */ -typedef int -(bcm_set_var_from_tlv_cbfn_t)(void *ctx, void **tlv_buf, uint16 type, uint16 len); - -struct bcm_tlvbuf { - uint16 size; - uint8 *head; /* point to head of buffer */ - uint8 *buf; /* current position of buffer */ - /* followed by the allocated buffer */ -}; - -#define BCM_TLV_MAX_DATA_SIZE (255) -#define BCM_XTLV_MAX_DATA_SIZE (65535) -#define BCM_TLV_HDR_SIZE (OFFSETOF(bcm_tlv_t, data)) - -#define BCM_XTLV_HDR_SIZE (OFFSETOF(bcm_xtlv_t, data)) -#define BCM_XTLV_LEN(elt) ltoh16_ua(&(elt->len)) -#define BCM_XTLV_ID(elt) ltoh16_ua(&(elt->id)) -#define BCM_XTLV_SIZE(elt) (BCM_XTLV_HDR_SIZE + BCM_XTLV_LEN(elt)) - -/* Check that bcm_tlv_t fits into the given buflen */ -#define bcm_valid_tlv(elt, buflen) (\ - ((int)(buflen) >= (int)BCM_TLV_HDR_SIZE) && \ - ((int)(buflen) >= (int)(BCM_TLV_HDR_SIZE + (elt)->len))) - -#define bcm_valid_xtlv(elt, buflen) (\ - ((int)(buflen) >= (int)BCM_XTLV_HDR_SIZE) && \ - ((int)(buflen) >= (int)BCM_XTLV_SIZE(elt))) - -extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); -extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); -extern bcm_tlv_t *bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen); - -extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); - -extern bcm_tlv_t *bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, - int type_len); - -extern uint8 *bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst); -extern uint8 *bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, - int dst_maxlen); - -extern uint8 *bcm_copy_tlv(const void *src, uint8 *dst); -extern uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen); - -/* xtlv */ -extern bcm_xtlv_t *bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen); -extern struct bcm_tlvbuf *bcm_xtlv_buf_alloc(void *osh, uint16 len); -extern void bcm_xtlv_buf_free(void *osh, struct bcm_tlvbuf *tbuf); -extern uint16 bcm_xtlv_buf_len(struct bcm_tlvbuf *tbuf); -extern uint16 bcm_xtlv_buf_rlen(struct bcm_tlvbuf *tbuf); -extern uint8 *bcm_xtlv_buf(struct bcm_tlvbuf *tbuf); -extern uint8 *bcm_xtlv_head(struct bcm_tlvbuf *tbuf); -extern int bcm_xtlv_put_data(struct bcm_tlvbuf *tbuf, uint16 type, const void *data, uint16 dlen); -extern int bcm_xtlv_put_8(struct bcm_tlvbuf *tbuf, uint16 type, const int8 data); -extern int bcm_xtlv_put_16(struct bcm_tlvbuf *tbuf, uint16 type, const int16 data); -extern int bcm_xtlv_put_32(struct bcm_tlvbuf *tbuf, uint16 type, const int32 data); -extern int bcm_unpack_xtlv_entry(void **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst); -extern int bcm_skip_xtlv(void **tlv_buf); -extern int bcm_pack_xtlv_entry(void **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src); -extern int bcm_unpack_xtlv_buf(void *ctx, - void *tlv_buf, uint16 buflen, bcm_set_var_from_tlv_cbfn_t *cbfn); -extern int -bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items); -extern int -bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items); -extern int -bcm_pack_xtlv_entry_from_hex_string(void **tlv_buf, uint16 *buflen, uint16 type, char *hex); - -/* bcmerror */ -extern const char *bcmerrorstr(int bcmerror); - -/* multi-bool data type: set of bools, mbool is true if any is set */ -typedef uint32 mbool; -#define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */ -#define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */ -#define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */ -#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) - -/* generic datastruct to help dump routines */ -struct fielddesc { - const char *nameandfmt; - uint32 offset; - uint32 len; -}; - -extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); -extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); - -extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); -extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); -extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); - -typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); -extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, - char *buf, uint32 bufsize); -extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); - -extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); - -/* power conversion */ -extern uint16 bcm_qdbm_to_mw(uint8 qdbm); -extern uint8 bcm_mw_to_qdbm(uint16 mw); -extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); - -unsigned int process_nvram_vars(char *varbuf, unsigned int len); - -/* calculate a * b + c */ -extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c); -/* calculate a / b */ -extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b); - - -/* Public domain bit twiddling hacks/utilities: Sean Eron Anderson */ - -/* Table driven count set bits. */ -static const uint8 /* Table only for use by bcm_cntsetbits */ -_CSBTBL[256] = -{ -# define B2(n) n, n + 1, n + 1, n + 2 -# define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2) -# define B6(n) B4(n), B4(n + 1), B4(n + 1), B4(n + 2) - B6(0), B6(0 + 1), B6(0 + 1), B6(0 + 2) -}; - -static INLINE uint32 /* Uses table _CSBTBL for fast counting of 1's in a u32 */ -bcm_cntsetbits(const uint32 u32) -{ - /* function local scope declaration of const _CSBTBL[] */ - const uint8 * p = (const uint8 *)&u32; - return (_CSBTBL[p[0]] + _CSBTBL[p[1]] + _CSBTBL[p[2]] + _CSBTBL[p[3]]); -} - - -static INLINE int /* C equivalent count of leading 0's in a u32 */ -C_bcm_count_leading_zeros(uint32 u32) -{ - int shifts = 0; - while (u32) { - shifts++; u32 >>= 1; - } - return (32U - shifts); -} - -#ifdef BCMDRIVER -/* - * Assembly instructions: Count Leading Zeros - * "clz" : MIPS, ARM - * "cntlzw" : PowerPC - * "BSF" : x86 - * "lzcnt" : AMD, SPARC - */ - -#if defined(__arm__) - -#if defined(__ARM_ARCH_7M__) /* Cortex M3 */ -#define __USE_ASM_CLZ__ -#endif /* __ARM_ARCH_7M__ */ - -#if defined(__ARM_ARCH_7R__) /* Cortex R4 */ -#define __USE_ASM_CLZ__ -#endif /* __ARM_ARCH_7R__ */ - -#endif /* __arm__ */ - -static INLINE int -bcm_count_leading_zeros(uint32 u32) -{ -#if defined(__USE_ASM_CLZ__) - int zeros; - __asm__ volatile("clz %0, %1 \n" : "=r" (zeros) : "r" (u32)); - return zeros; -#else /* C equivalent */ - return C_bcm_count_leading_zeros(u32); -#endif /* C equivalent */ -} - -/* INTERFACE: Multiword bitmap based small id allocator. */ -struct bcm_mwbmap; /* forward declaration for use as an opaque mwbmap handle */ - -#define BCM_MWBMAP_INVALID_HDL ((struct bcm_mwbmap *)NULL) -#define BCM_MWBMAP_INVALID_IDX ((uint32)(~0U)) - -/* Incarnate a multiword bitmap based small index allocator */ -extern struct bcm_mwbmap * bcm_mwbmap_init(osl_t * osh, uint32 items_max); - -/* Free up the multiword bitmap index allocator */ -extern void bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl); - -/* Allocate a unique small index using a multiword bitmap index allocator */ -extern uint32 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl); - -/* Force an index at a specified position to be in use */ -extern void bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); - -/* Free a previously allocated index back into the multiword bitmap allocator */ -extern void bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); - -/* Fetch the toal number of free indices in the multiword bitmap allocator */ -extern uint32 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl); - -/* Determine whether an index is inuse or free */ -extern bool bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); - -/* Debug dump a multiword bitmap allocator */ -extern void bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl); - -extern void bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl); -/* End - Multiword bitmap based small Id allocator. */ - - -/* INTERFACE: Simple unique 16bit Id Allocator using a stack implementation. */ - -#define ID16_INVALID ((uint16)(~0)) - -/* - * Construct a 16bit id allocator, managing 16bit ids in the range: - * [start_val16 .. start_val16+total_ids) - * Note: start_val16 is inclusive. - * Returns an opaque handle to the 16bit id allocator. - */ -extern void * id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16); -extern void * id16_map_fini(osl_t *osh, void * id16_map_hndl); -extern void id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16); - -/* Allocate a unique 16bit id */ -extern uint16 id16_map_alloc(void * id16_map_hndl); - -/* Free a 16bit id value into the id16 allocator */ -extern void id16_map_free(void * id16_map_hndl, uint16 val16); - -/* Get the number of failures encountered during id allocation. */ -extern uint32 id16_map_failures(void * id16_map_hndl); - -/* Audit the 16bit id allocator state. */ -extern bool id16_map_audit(void * id16_map_hndl); -/* End - Simple 16bit Id Allocator. */ - -#endif /* BCMDRIVER */ - -extern void bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b); - -void bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset); -void bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset); - -/* calculate checksum for ip header, tcp / udp header / data */ -uint16 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum); - -#ifndef _dll_t_ -#define _dll_t_ -/* - * ----------------------------------------------------------------------------- - * Double Linked List Macros - * ----------------------------------------------------------------------------- - * - * All dll operations must be performed on a pre-initialized node. - * Inserting an uninitialized node into a list effectively initialized it. - * - * When a node is deleted from a list, you may initialize it to avoid corruption - * incurred by double deletion. You may skip initialization if the node is - * immediately inserted into another list. - * - * By placing a dll_t element at the start of a struct, you may cast a dll_t * - * to the struct or vice versa. - * - * Example of declaring an initializing someList and inserting nodeA, nodeB - * - * typedef struct item { - * dll_t node; - * int someData; - * } Item_t; - * Item_t nodeA, nodeB, nodeC; - * nodeA.someData = 11111, nodeB.someData = 22222, nodeC.someData = 33333; - * - * dll_t someList; - * dll_init(&someList); - * - * dll_append(&someList, (dll_t *) &nodeA); - * dll_prepend(&someList, &nodeB.node); - * dll_insert((dll_t *)&nodeC, &nodeA.node); - * - * dll_delete((dll_t *) &nodeB); - * - * Example of a for loop to walk someList of node_p - * - * extern void mydisplay(Item_t * item_p); - * - * dll_t * item_p, * next_p; - * for (item_p = dll_head_p(&someList); ! dll_end(&someList, item_p); - * item_p = next_p) - * { - * next_p = dll_next_p(item_p); - * ... use item_p at will, including removing it from list ... - * mydisplay((PItem_t)item_p); - * } - * - * ----------------------------------------------------------------------------- - */ -typedef struct dll { - struct dll * next_p; - struct dll * prev_p; -} dll_t; - -static INLINE void -dll_init(dll_t *node_p) -{ - node_p->next_p = node_p; - node_p->prev_p = node_p; -} -/* dll macros returing a pointer to dll_t */ - -static INLINE dll_t * -dll_head_p(dll_t *list_p) -{ - return list_p->next_p; -} - - -static INLINE dll_t * -dll_tail_p(dll_t *list_p) -{ - return (list_p)->prev_p; -} - - -static INLINE dll_t * -dll_next_p(dll_t *node_p) -{ - return (node_p)->next_p; -} - - -static INLINE dll_t * -dll_prev_p(dll_t *node_p) -{ - return (node_p)->prev_p; -} - - -static INLINE bool -dll_empty(dll_t *list_p) -{ - return ((list_p)->next_p == (list_p)); -} - - -static INLINE bool -dll_end(dll_t *list_p, dll_t * node_p) -{ - return (list_p == node_p); -} - - -/* inserts the node new_p "after" the node at_p */ -static INLINE void -dll_insert(dll_t *new_p, dll_t * at_p) -{ - new_p->next_p = at_p->next_p; - new_p->prev_p = at_p; - at_p->next_p = new_p; - (new_p->next_p)->prev_p = new_p; -} - -static INLINE void -dll_append(dll_t *list_p, dll_t *node_p) -{ - dll_insert(node_p, dll_tail_p(list_p)); -} - -static INLINE void -dll_prepend(dll_t *list_p, dll_t *node_p) -{ - dll_insert(node_p, list_p); -} - - -/* deletes a node from any list that it "may" be in, if at all. */ -static INLINE void -dll_delete(dll_t *node_p) -{ - node_p->prev_p->next_p = node_p->next_p; - node_p->next_p->prev_p = node_p->prev_p; -} -#endif /* ! defined(_dll_t_) */ - -/* Elements managed in a double linked list */ - -typedef struct dll_pool { - dll_t free_list; - uint16 free_count; - uint16 elems_max; - uint16 elem_size; - dll_t elements[1]; -} dll_pool_t; - -dll_pool_t * dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size); -void * dll_pool_alloc(dll_pool_t * dll_pool_p); -void dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p); -void dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p); -typedef void (* dll_elem_dump)(void * elem_p); -void dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size); - -#ifdef __cplusplus - } -#endif - -/* #define DEBUG_COUNTER */ -#ifdef DEBUG_COUNTER -#define CNTR_TBL_MAX 10 -typedef struct _counter_tbl_t { - char name[16]; /* name of this counter table */ - uint32 prev_log_print; /* Internal use. Timestamp of the previous log print */ - uint log_print_interval; /* Desired interval to print logs in ms */ - uint needed_cnt; /* How many counters need to be used */ - uint32 cnt[CNTR_TBL_MAX]; /* Counting entries to increase at desired places */ - bool enabled; /* Whether to enable printing log */ -} counter_tbl_t; - - -void counter_printlog(counter_tbl_t *ctr_tbl); -#endif /* DEBUG_COUNTER */ - -#endif /* _bcmutils_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h deleted file mode 100644 index d68668bb99e1..000000000000 --- a/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Definitions for nl80211 vendor command/event access to host driver - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: brcm_nl80211.h 595011 2015-10-26 05:41:56Z $ - * - */ - -#ifndef _brcm_nl80211_h_ -#define _brcm_nl80211_h_ - -#define OUI_BRCM 0x001018 - -enum wl_vendor_subcmd { - BRCM_VENDOR_SCMD_UNSPEC, - BRCM_VENDOR_SCMD_PRIV_STR, - BRCM_VENDOR_SCMD_BCM_STR -}; - -struct bcm_nlmsg_hdr { - uint cmd; /* common ioctl definition */ - uint len; /* expected return buffer length */ - uint offset; /* user buffer offset */ - uint set; /* get or set request optional */ - uint magic; /* magic number for verification */ -}; - -enum bcmnl_attrs { - BCM_NLATTR_UNSPEC, - - BCM_NLATTR_LEN, - BCM_NLATTR_DATA, - - __BCM_NLATTR_AFTER_LAST, - BCM_NLATTR_MAX = __BCM_NLATTR_AFTER_LAST - 1 -}; - -struct nl_prv_data { - int err; /* return result */ - void *data; /* ioctl return buffer pointer */ - uint len; /* ioctl return buffer length */ - struct bcm_nlmsg_hdr *nlioc; /* bcm_nlmsg_hdr header pointer */ -}; - -#endif /* _brcm_nl80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/dbus.h b/drivers/net/wireless/bcmdhd/include/dbus.h deleted file mode 100644 index 933e8f0e9d2e..000000000000 --- a/drivers/net/wireless/bcmdhd/include/dbus.h +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Dongle BUS interface Abstraction layer - * target serial buses like USB, SDIO, SPI, etc. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dbus.h 496883 2014-08-14 22:59:09Z $ - */ - -#ifndef __DBUS_H__ -#define __DBUS_H__ - -#include "typedefs.h" - -#define DBUSTRACE(args) -#define DBUSERR(args) -#define DBUSINFO(args) -#define DBUSDBGLOCK(args) - -enum { - DBUS_OK = 0, - DBUS_ERR = -200, - DBUS_ERR_TIMEOUT, - DBUS_ERR_DISCONNECT, - DBUS_ERR_NODEVICE, - DBUS_ERR_UNSUPPORTED, - DBUS_ERR_PENDING, - DBUS_ERR_NOMEM, - DBUS_ERR_TXFAIL, - DBUS_ERR_TXTIMEOUT, - DBUS_ERR_TXDROP, - DBUS_ERR_RXFAIL, - DBUS_ERR_RXDROP, - DBUS_ERR_TXCTLFAIL, - DBUS_ERR_RXCTLFAIL, - DBUS_ERR_REG_PARAM, - DBUS_STATUS_CANCELLED, - DBUS_ERR_NVRAM, - DBUS_JUMBO_NOMATCH, - DBUS_JUMBO_BAD_FORMAT, - DBUS_NVRAM_NONTXT -}; - -#define BCM_OTP_SIZE_43236 84 /* number of 16 bit values */ -#define BCM_OTP_SW_RGN_43236 24 /* start offset of SW config region */ -#define BCM_OTP_ADDR_43236 0x18000800 /* address of otp base */ - -#define ERR_CBMASK_TXFAIL 0x00000001 -#define ERR_CBMASK_RXFAIL 0x00000002 -#define ERR_CBMASK_ALL 0xFFFFFFFF - -#define DBUS_CBCTL_WRITE 0 -#define DBUS_CBCTL_READ 1 -#if defined(INTR_EP_ENABLE) -#define DBUS_CBINTR_POLL 2 -#endif /* defined(INTR_EP_ENABLE) */ - -#define DBUS_TX_RETRY_LIMIT 3 /* retries for failed txirb */ -#define DBUS_TX_TIMEOUT_INTERVAL 250 /* timeout for txirb complete, in ms */ - -#define DBUS_BUFFER_SIZE_TX 32000 -#define DBUS_BUFFER_SIZE_RX 24000 - -#define DBUS_BUFFER_SIZE_TX_NOAGG 2048 -#define DBUS_BUFFER_SIZE_RX_NOAGG 2048 - -/* DBUS types */ -enum { - DBUS_USB, - DBUS_SDIO, - DBUS_SPI, - DBUS_UNKNOWN -}; - -enum dbus_state { - DBUS_STATE_DL_PENDING, - DBUS_STATE_DL_DONE, - DBUS_STATE_UP, - DBUS_STATE_DOWN, - DBUS_STATE_PNP_FWDL, - DBUS_STATE_DISCONNECT, - DBUS_STATE_SLEEP -}; - -enum dbus_pnp_state { - DBUS_PNP_DISCONNECT, - DBUS_PNP_SLEEP, - DBUS_PNP_RESUME -}; - -enum dbus_file { - DBUS_FIRMWARE, - DBUS_NVFILE -}; - -typedef enum _DEVICE_SPEED { - INVALID_SPEED = -1, - LOW_SPEED = 1, /* USB 1.1: 1.5 Mbps */ - FULL_SPEED, /* USB 1.1: 12 Mbps */ - HIGH_SPEED, /* USB 2.0: 480 Mbps */ - SUPER_SPEED, /* USB 3.0: 4.8 Gbps */ -} DEVICE_SPEED; - -typedef struct { - int bustype; - int vid; - int pid; - int devid; - int chiprev; /* chip revsion number */ - int mtu; - int nchan; /* Data Channels */ - int has_2nd_bulk_in_ep; -} dbus_attrib_t; - -/* FIX: Account for errors related to DBUS; - * Let upper layer account for packets/bytes - */ -typedef struct { - uint32 rx_errors; - uint32 tx_errors; - uint32 rx_dropped; - uint32 tx_dropped; -} dbus_stats_t; - -/* - * Configurable BUS parameters - */ -enum { - DBUS_CONFIG_ID_RXCTL_DEFERRES = 1, - DBUS_CONFIG_ID_TXRXQUEUE -}; -typedef struct { - uint32 config_id; - union { - bool rxctl_deferrespok; - struct { - int maxrxq; - int rxbufsize; - int maxtxq; - int txbufsize; - } txrxqueue; - }; -} dbus_config_t; - -/* - * External Download Info - */ -typedef struct dbus_extdl { - uint8 *fw; - int fwlen; - uint8 *vars; - int varslen; -} dbus_extdl_t; - -struct dbus_callbacks; -struct exec_parms; - -typedef void *(*probe_cb_t)(void *arg, const char *desc, uint32 bustype, uint32 hdrlen); -typedef void (*disconnect_cb_t)(void *arg); -typedef void *(*exec_cb_t)(struct exec_parms *args); - -/* Client callbacks registered during dbus_attach() */ -typedef struct dbus_callbacks { - void (*send_complete)(void *cbarg, void *info, int status); - void (*recv_buf)(void *cbarg, uint8 *buf, int len); - void (*recv_pkt)(void *cbarg, void *pkt); - void (*txflowcontrol)(void *cbarg, bool onoff); - void (*errhandler)(void *cbarg, int err); - void (*ctl_complete)(void *cbarg, int type, int status); - void (*state_change)(void *cbarg, int state); - void *(*pktget)(void *cbarg, uint len, bool send); - void (*pktfree)(void *cbarg, void *p, bool send); -} dbus_callbacks_t; - -struct dbus_pub; -struct bcmstrbuf; -struct dbus_irb; -struct dbus_irb_rx; -struct dbus_irb_tx; -struct dbus_intf_callbacks; - -typedef struct { - void* (*attach)(struct dbus_pub *pub, void *cbarg, struct dbus_intf_callbacks *cbs); - void (*detach)(struct dbus_pub *pub, void *bus); - - int (*up)(void *bus); - int (*down)(void *bus); - int (*send_irb)(void *bus, struct dbus_irb_tx *txirb); - int (*recv_irb)(void *bus, struct dbus_irb_rx *rxirb); - int (*cancel_irb)(void *bus, struct dbus_irb_tx *txirb); - int (*send_ctl)(void *bus, uint8 *buf, int len); - int (*recv_ctl)(void *bus, uint8 *buf, int len); - int (*get_stats)(void *bus, dbus_stats_t *stats); - int (*get_attrib)(void *bus, dbus_attrib_t *attrib); - - int (*pnp)(void *bus, int evnt); - int (*remove)(void *bus); - int (*resume)(void *bus); - int (*suspend)(void *bus); - int (*stop)(void *bus); - int (*reset)(void *bus); - - /* Access to bus buffers directly */ - void *(*pktget)(void *bus, int len); - void (*pktfree)(void *bus, void *pkt); - - int (*iovar_op)(void *bus, const char *name, void *params, int plen, void *arg, int len, - bool set); - void (*dump)(void *bus, struct bcmstrbuf *strbuf); - int (*set_config)(void *bus, dbus_config_t *config); - int (*get_config)(void *bus, dbus_config_t *config); - - bool (*device_exists)(void *bus); - bool (*dlneeded)(void *bus); - int (*dlstart)(void *bus, uint8 *fw, int len); - int (*dlrun)(void *bus); - bool (*recv_needed)(void *bus); - - void *(*exec_rxlock)(void *bus, exec_cb_t func, struct exec_parms *args); - void *(*exec_txlock)(void *bus, exec_cb_t func, struct exec_parms *args); - - int (*tx_timer_init)(void *bus); - int (*tx_timer_start)(void *bus, uint timeout); - int (*tx_timer_stop)(void *bus); - - int (*sched_dpc)(void *bus); - int (*lock)(void *bus); - int (*unlock)(void *bus); - int (*sched_probe_cb)(void *bus); - - int (*shutdown)(void *bus); - - int (*recv_stop)(void *bus); - int (*recv_resume)(void *bus); - - int (*recv_irb_from_ep)(void *bus, struct dbus_irb_rx *rxirb, uint ep_idx); - - int (*readreg)(void *bus, uint32 regaddr, int datalen, uint32 *value); - - /* Add from the bottom */ -} dbus_intf_t; - -typedef struct dbus_pub { - struct osl_info *osh; - dbus_stats_t stats; - dbus_attrib_t attrib; - enum dbus_state busstate; - DEVICE_SPEED device_speed; - int ntxq, nrxq, rxsize; - void *bus; - struct shared_info *sh; - void *dev_info; -} dbus_pub_t; - -#define BUS_INFO(bus, type) (((type *) bus)->pub->bus) - -#define ALIGNED_LOCAL_VARIABLE(var, align) \ - uint8 buffer[SDALIGN+64]; \ - uint8 *var = (uint8 *)(((uintptr)&buffer[0]) & ~(align-1)) + align; - -/* - * Public Bus Function Interface - */ - -/* - * FIX: Is there better way to pass OS/Host handles to DBUS but still - * maintain common interface for all OS?? - * Under NDIS, param1 needs to be MiniportHandle - * For NDIS60, param2 is WdfDevice - * Under Linux, param1 and param2 are NULL; - */ -extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, - void *param1, void *param2); -extern int dbus_deregister(void); - -extern dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq, int ntxq, - void *cbarg, dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh); -extern void dbus_detach(dbus_pub_t *pub); - -extern int dbus_up(dbus_pub_t *pub); -extern int dbus_down(dbus_pub_t *pub); -extern int dbus_stop(dbus_pub_t *pub); -extern int dbus_shutdown(dbus_pub_t *pub); -extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on); - -extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); -extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info); -extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); -extern int dbus_send_ctl(dbus_pub_t *pub, uint8 *buf, int len); -extern int dbus_recv_ctl(dbus_pub_t *pub, uint8 *buf, int len); -extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); -extern int dbus_poll_intr(dbus_pub_t *pub); -extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats); -extern int dbus_get_attrib(dbus_pub_t *pub, dbus_attrib_t *attrib); -extern int dbus_get_device_speed(dbus_pub_t *pub); -extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config); -extern int dbus_get_config(dbus_pub_t *pub, dbus_config_t *config); -extern void * dbus_get_devinfo(dbus_pub_t *pub); - -extern void *dbus_pktget(dbus_pub_t *pub, int len); -extern void dbus_pktfree(dbus_pub_t *pub, void* pkt); - -extern int dbus_set_errmask(dbus_pub_t *pub, uint32 mask); -extern int dbus_pnp_sleep(dbus_pub_t *pub); -extern int dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload); -extern int dbus_pnp_disconnect(dbus_pub_t *pub); - -extern int dbus_iovar_op(dbus_pub_t *pub, const char *name, - void *params, int plen, void *arg, int len, bool set); - -extern void *dhd_dbus_txq(const dbus_pub_t *pub); -extern uint dhd_dbus_hdrlen(const dbus_pub_t *pub); - -/* - * Private Common Bus Interface - */ - -/* IO Request Block (IRB) */ -typedef struct dbus_irb { - struct dbus_irb *next; /* it's casted from dbus_irb_tx or dbus_irb_rx struct */ -} dbus_irb_t; - -typedef struct dbus_irb_rx { - struct dbus_irb irb; /* Must be first */ - uint8 *buf; - int buf_len; - int actual_len; - void *pkt; - void *info; - void *arg; -} dbus_irb_rx_t; - -typedef struct dbus_irb_tx { - struct dbus_irb irb; /* Must be first */ - uint8 *buf; - int len; - void *pkt; - int retry_count; - void *info; - void *arg; - void *send_buf; /* linear bufffer for LINUX when aggreagtion is enabled */ -} dbus_irb_tx_t; - -/* DBUS interface callbacks are different from user callbacks - * so, internally, different info can be passed to upper layer - */ -typedef struct dbus_intf_callbacks { - void (*send_irb_timeout)(void *cbarg, dbus_irb_tx_t *txirb); - void (*send_irb_complete)(void *cbarg, dbus_irb_tx_t *txirb, int status); - void (*recv_irb_complete)(void *cbarg, dbus_irb_rx_t *rxirb, int status); - void (*errhandler)(void *cbarg, int err); - void (*ctl_complete)(void *cbarg, int type, int status); - void (*state_change)(void *cbarg, int state); - bool (*isr)(void *cbarg, bool *wantdpc); - bool (*dpc)(void *cbarg, bool bounded); - void (*watchdog)(void *cbarg); - void *(*pktget)(void *cbarg, uint len, bool send); - void (*pktfree)(void *cbarg, void *p, bool send); - struct dbus_irb* (*getirb)(void *cbarg, bool send); - void (*rxerr_indicate)(void *cbarg, bool on); -} dbus_intf_callbacks_t; - -/* - * Porting: To support new bus, port these functions below - */ - -/* - * Bus specific Interface - * Implemented by dbus_usb.c/dbus_sdio.c - */ -extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, - dbus_intf_t **intf, void *param1, void *param2); -extern int dbus_bus_deregister(void); -extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp); - -/* - * Bus-specific and OS-specific Interface - * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c - */ -extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, - void *prarg, dbus_intf_t **intf, void *param1, void *param2); -extern int dbus_bus_osl_deregister(void); - -/* - * Bus-specific, OS-specific, HW-specific Interface - * Mainly for SDIO Host HW controller - */ -extern int dbus_bus_osl_hw_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, - void *prarg, dbus_intf_t **intf); -extern int dbus_bus_osl_hw_deregister(void); - -extern uint usbdev_bulkin_eps(void); -#if defined(BCM_REQUEST_FW) -extern void *dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, - uint16 boardtype, uint16 boardrev); -extern void dbus_release_fw_nvfile(void *firmware); -#endif /* #if defined(BCM_REQUEST_FW) */ - - -#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) - - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) - /* Backward compatibility */ - typedef unsigned int gfp_t; - - #define dma_pool pci_pool - #define dma_pool_create(name, dev, size, align, alloc) \ - pci_pool_create(name, dev, size, align, alloc, GFP_DMA | GFP_ATOMIC) - #define dma_pool_destroy(pool) pci_pool_destroy(pool) - #define dma_pool_alloc(pool, flags, handle) pci_pool_alloc(pool, flags, handle) - #define dma_pool_free(pool, vaddr, addr) pci_pool_free(pool, vaddr, addr) - - #define dma_map_single(dev, addr, size, dir) pci_map_single(dev, addr, size, dir) - #define dma_unmap_single(dev, hnd, size, dir) pci_unmap_single(dev, hnd, size, dir) - #define DMA_FROM_DEVICE PCI_DMA_FROMDEVICE - #define DMA_TO_DEVICE PCI_DMA_TODEVICE -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ - -/* Availability of these functions varies (when present, they have two arguments) */ -#ifndef hc32_to_cpu - #define hc32_to_cpu(x) le32_to_cpu(x) - #define cpu_to_hc32(x) cpu_to_le32(x) - typedef unsigned int __hc32; -#else - #error Two-argument functions needed -#endif - -/* Private USB opcode base */ -#define EHCI_FASTPATH 0x31 -#define EHCI_SET_EP_BYPASS EHCI_FASTPATH -#define EHCI_SET_BYPASS_CB (EHCI_FASTPATH + 1) -#define EHCI_SET_BYPASS_DEV (EHCI_FASTPATH + 2) -#define EHCI_DUMP_STATE (EHCI_FASTPATH + 3) -#define EHCI_SET_BYPASS_POOL (EHCI_FASTPATH + 4) -#define EHCI_CLR_EP_BYPASS (EHCI_FASTPATH + 5) - -/* - * EHCI QTD structure (hardware and extension) - * NOTE that is does not need to (and does not) match its kernel counterpart - */ -#define EHCI_QTD_NBUFFERS 5 -#define EHCI_QTD_ALIGN 32 -#define EHCI_BULK_PACKET_SIZE 512 -#define EHCI_QTD_XACTERR_MAX 32 - -struct ehci_qtd { - /* Hardware map */ - volatile uint32_t qtd_next; - volatile uint32_t qtd_altnext; - volatile uint32_t qtd_status; -#define EHCI_QTD_GET_BYTES(x) (((x)>>16) & 0x7fff) -#define EHCI_QTD_IOC 0x00008000 -#define EHCI_QTD_GET_CERR(x) (((x)>>10) & 0x3) -#define EHCI_QTD_SET_CERR(x) ((x) << 10) -#define EHCI_QTD_GET_PID(x) (((x)>>8) & 0x3) -#define EHCI_QTD_SET_PID(x) ((x) << 8) -#define EHCI_QTD_ACTIVE 0x80 -#define EHCI_QTD_HALTED 0x40 -#define EHCI_QTD_BUFERR 0x20 -#define EHCI_QTD_BABBLE 0x10 -#define EHCI_QTD_XACTERR 0x08 -#define EHCI_QTD_MISSEDMICRO 0x04 - volatile uint32_t qtd_buffer[EHCI_QTD_NBUFFERS]; - volatile uint32_t qtd_buffer_hi[EHCI_QTD_NBUFFERS]; - - /* Implementation extension */ - dma_addr_t qtd_self; /* own hardware address */ - struct ehci_qtd *obj_next; /* software link to the next QTD */ - void *rpc; /* pointer to the rpc buffer */ - size_t length; /* length of the data in the buffer */ - void *buff; /* pointer to the reassembly buffer */ - int xacterrs; /* retry counter for qtd xact error */ -} __attribute__ ((aligned(EHCI_QTD_ALIGN))); - -#define EHCI_NULL __constant_cpu_to_le32(1) /* HW null pointer shall be odd */ - -#define SHORT_READ_Q(token) (EHCI_QTD_GET_BYTES(token) != 0 && EHCI_QTD_GET_PID(token) == 1) - -/* Queue Head */ -/* NOTE This structure is slightly different from the one in the kernel; but needs to stay - * compatible - */ -struct ehci_qh { - /* Hardware map */ - volatile uint32_t qh_link; - volatile uint32_t qh_endp; - volatile uint32_t qh_endphub; - volatile uint32_t qh_curqtd; - - /* QTD overlay */ - volatile uint32_t ow_next; - volatile uint32_t ow_altnext; - volatile uint32_t ow_status; - volatile uint32_t ow_buffer [EHCI_QTD_NBUFFERS]; - volatile uint32_t ow_buffer_hi [EHCI_QTD_NBUFFERS]; - - /* Extension (should match the kernel layout) */ - dma_addr_t unused0; - void *unused1; - struct list_head unused2; - struct ehci_qtd *dummy; - struct ehci_qh *unused3; - - struct ehci_hcd *unused4; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct kref unused5; - unsigned unused6; - - uint8_t unused7; - - /* periodic schedule info */ - uint8_t unused8; - uint8_t unused9; - uint8_t unused10; - uint16_t unused11; - uint16_t unused12; - uint16_t unused13; - struct usb_device *unused14; -#else - unsigned unused5; - - u8 unused6; - - /* periodic schedule info */ - u8 unused7; - u8 unused8; - u8 unused9; - unsigned short unused10; - unsigned short unused11; -#define NO_FRAME ((unsigned short)~0) -#ifdef EHCI_QUIRK_FIX - struct usb_device *unused12; -#endif /* EHCI_QUIRK_FIX */ -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ - struct ehci_qtd *first_qtd; - /* Link to the first QTD; this is an optimized equivalent of the qtd_list field */ - /* NOTE that ehci_qh in ehci.h shall reserve this word */ -} __attribute__ ((aligned(EHCI_QTD_ALIGN))); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -/* The corresponding structure in the kernel is used to get the QH */ -struct hcd_dev { /* usb_device.hcpriv points to this */ - struct list_head unused0; - struct list_head unused1; - - /* array of QH pointers */ - void *ep[32]; -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ - -int optimize_qtd_fill_with_rpc(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *rpc, - int token, int len); -int optimize_qtd_fill_with_data(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *data, - int token, int len); -int optimize_submit_async(struct ehci_qtd *qtd, int epn); -void inline optimize_ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma); -struct ehci_qtd *optimize_ehci_qtd_alloc(gfp_t flags); -void optimize_ehci_qtd_free(struct ehci_qtd *qtd); -void optimize_submit_rx_request(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd_in, void *buf); -#endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ - -void dbus_flowctrl_tx(void *dbi, bool on); -#endif /* __DBUS_H__ */ diff --git a/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h deleted file mode 100644 index 444166042572..000000000000 --- a/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h +++ /dev/null @@ -1,2110 +0,0 @@ -/* - * Custom OID/ioctl definitions for - * Broadcom 802.11abg Networking Device Driver - * - * Definitions subject to change without notice. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wlioctl_defs.h 403826 2013-05-22 16:40:55Z $ - */ - - -#ifndef wlioctl_defs_h -#define wlioctl_defs_h - - - -/* All builds use the new 11ac ratespec/chanspec */ -#undef D11AC_IOTYPES -#define D11AC_IOTYPES - -/* WL_RSPEC defines for rate information */ -#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */ -#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */ -#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */ -#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */ -#define WL_RSPEC_TXEXP_MASK 0x00000300 -#define WL_RSPEC_TXEXP_SHIFT 8 -#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ -#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ -#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ -#define WL_RSPEC_TXBF 0x00200000 /* bit indicates TXBF mode */ -#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ -#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ -#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ -#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */ -#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override both rate & mode */ - -/* WL_RSPEC_ENCODING field defs */ -#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */ -#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */ -#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */ - -/* WL_RSPEC_BW field defs */ -#define WL_RSPEC_BW_UNSPECIFIED 0 -#define WL_RSPEC_BW_20MHZ 0x00010000 -#define WL_RSPEC_BW_40MHZ 0x00020000 -#define WL_RSPEC_BW_80MHZ 0x00030000 -#define WL_RSPEC_BW_160MHZ 0x00040000 - -/* Legacy defines for the nrate iovar */ -#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ -#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ -#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ -#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */ -#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ -#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ -#define OLD_NRATE_SGI 0x00800000 /* sgi mode */ -#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ - -#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */ -#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */ -#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */ -#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */ - -#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ - -#define GET_PRO_PRIETARY_11N_MCS_NSS(mcs) (1 + ((mcs) - 85) / 8) - -#define GET_11N_MCS_NSS(mcs) ((mcs) < 32 ? (1 + ((mcs) / 8)) \ - : ((mcs) == 32 ? 1 : GET_PRO_PRIETARY_11N_MCS_NSS(mcs))) - -#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ -#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ - -#define IBSS_MED 15 /* Mediom in-bss congestion percentage */ -#define IBSS_HI 25 /* Hi in-bss congestion percentage */ -#define OBSS_MED 12 -#define OBSS_HI 25 -#define INTERFER_MED 5 -#define INTERFER_HI 10 - -#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */ -#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */ -#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */ -#define CCA_FLAGS_PREFER_1_6_11 0x10 -#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */ - -#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */ -#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */ -#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */ -#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */ -#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */ - -#define WL_STA_AID(a) ((a) &~ 0xc000) - -/* Flags for sta_info_t indicating properties of STA */ -#define WL_STA_BRCM 0x00000001 /* Running a Broadcom driver */ -#define WL_STA_WME 0x00000002 /* WMM association */ -#define WL_STA_NONERP 0x00000004 /* No ERP */ -#define WL_STA_AUTHE 0x00000008 /* Authenticated */ -#define WL_STA_ASSOC 0x00000010 /* Associated */ -#define WL_STA_AUTHO 0x00000020 /* Authorized */ -#define WL_STA_WDS 0x00000040 /* Wireless Distribution System */ -#define WL_STA_WDS_LINKUP 0x00000080 /* WDS traffic/probes flowing properly */ -#define WL_STA_PS 0x00000100 /* STA is in power save mode from AP's viewpoint */ -#define WL_STA_APSD_BE 0x00000200 /* APSD delv/trigger for AC_BE is default enabled */ -#define WL_STA_APSD_BK 0x00000400 /* APSD delv/trigger for AC_BK is default enabled */ -#define WL_STA_APSD_VI 0x00000800 /* APSD delv/trigger for AC_VI is default enabled */ -#define WL_STA_APSD_VO 0x00001000 /* APSD delv/trigger for AC_VO is default enabled */ -#define WL_STA_N_CAP 0x00002000 /* STA 802.11n capable */ -#define WL_STA_SCBSTATS 0x00004000 /* Per STA debug stats */ -#define WL_STA_AMPDU_CAP 0x00008000 /* STA AMPDU capable */ -#define WL_STA_AMSDU_CAP 0x00010000 /* STA AMSDU capable */ -#define WL_STA_MIMO_PS 0x00020000 /* mimo ps mode is enabled */ -#define WL_STA_MIMO_RTS 0x00040000 /* send rts in mimo ps mode */ -#define WL_STA_RIFS_CAP 0x00080000 /* rifs enabled */ -#define WL_STA_VHT_CAP 0x00100000 /* STA VHT(11ac) capable */ -#define WL_STA_WPS 0x00200000 /* WPS state */ - -#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ - -/* STA HT cap fields */ -#define WL_STA_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ -#define WL_STA_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ -#define WL_STA_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ -#define WL_STA_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ -#define WL_STA_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ -#define WL_STA_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ -#define WL_STA_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ -#define WL_STA_CAP_GF 0x0010 /* Greenfield preamble support */ -#define WL_STA_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ -#define WL_STA_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ -#define WL_STA_CAP_TX_STBC 0x0080 /* Tx STBC support */ -#define WL_STA_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ -#define WL_STA_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ -#define WL_STA_CAP_DELAYED_BA 0x0400 /* delayed BA support */ -#define WL_STA_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ -#define WL_STA_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ -#define WL_STA_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ -#define WL_STA_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ -#define WL_STA_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ - -#define WL_STA_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ -#define WL_STA_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ -#define WL_STA_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ -#define WL_STA_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ - -/* scb vht flags */ -#define WL_STA_VHT_LDPCCAP 0x0001 -#define WL_STA_SGI80 0x0002 -#define WL_STA_SGI160 0x0004 -#define WL_STA_VHT_TX_STBCCAP 0x0008 -#define WL_STA_VHT_RX_STBCCAP 0x0010 -#define WL_STA_SU_BEAMFORMER 0x0020 -#define WL_STA_SU_BEAMFORMEE 0x0040 -#define WL_STA_MU_BEAMFORMER 0x0080 -#define WL_STA_MU_BEAMFORMEE 0x0100 -#define WL_STA_VHT_TXOP_PS 0x0200 -#define WL_STA_HTC_VHT_CAP 0x0400 - -/* Values for TX Filter override mode */ -#define WLC_TXFILTER_OVERRIDE_DISABLED 0 -#define WLC_TXFILTER_OVERRIDE_ENABLED 1 - -#define WL_IOCTL_ACTION_GET 0x0 -#define WL_IOCTL_ACTION_SET 0x1 -#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e -#define WL_IOCTL_ACTION_OVL_RSV 0x20 -#define WL_IOCTL_ACTION_OVL 0x40 -#define WL_IOCTL_ACTION_MASK 0x7e -#define WL_IOCTL_ACTION_OVL_SHIFT 1 - -#define WL_BSSTYPE_INFRA 1 -#define WL_BSSTYPE_INDEP 0 -#define WL_BSSTYPE_ANY 2 - -/* Bitmask for scan_type */ -#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ -#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ -#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ -#define WL_SCANFLAGS_OFFCHAN 0x08 /* allow scanning/reporting off-channel APs */ -#define WL_SCANFLAGS_HOTSPOT 0x10 /* automatic ANQP to hotspot APs */ -#define WL_SCANFLAGS_SWTCHAN 0x20 /* Force channel switch for differerent bandwidth */ - -/* wl_iscan_results status values */ -#define WL_SCAN_RESULTS_SUCCESS 0 -#define WL_SCAN_RESULTS_PARTIAL 1 -#define WL_SCAN_RESULTS_PENDING 2 -#define WL_SCAN_RESULTS_ABORTED 3 -#define WL_SCAN_RESULTS_NO_MEM 4 - -#define SCANOL_ENABLED (1 << 0) -#define SCANOL_BCAST_SSID (1 << 1) -#define SCANOL_NOTIFY_BCAST_SSID (1 << 2) -#define SCANOL_RESULTS_PER_CYCLE (1 << 3) - -/* scan times in milliseconds */ -#define SCANOL_HOME_TIME 45 /* for home channel processing */ -#define SCANOL_ASSOC_TIME 20 /* dwell on a channel while associated */ -#define SCANOL_UNASSOC_TIME 40 /* dwell on a channel while unassociated */ -#define SCANOL_PASSIVE_TIME 110 /* listen on a channelfor passive scan */ -#define SCANOL_AWAY_LIMIT 100 /* max time to be away from home channel */ -#define SCANOL_IDLE_REST_TIME 40 -#define SCANOL_IDLE_REST_MULTIPLIER 0 -#define SCANOL_ACTIVE_REST_TIME 20 -#define SCANOL_ACTIVE_REST_MULTIPLIER 0 -#define SCANOL_CYCLE_IDLE_REST_TIME 300000 /* Idle Rest Time between Scan Cycle (msec) */ -#define SCANOL_CYCLE_IDLE_REST_MULTIPLIER 0 /* Idle Rest Time Multiplier */ -#define SCANOL_CYCLE_ACTIVE_REST_TIME 200 -#define SCANOL_CYCLE_ACTIVE_REST_MULTIPLIER 0 -#define SCANOL_MAX_REST_TIME 3600000 /* max rest time between scan cycle (msec) */ -#define SCANOL_CYCLE_DEFAULT 0 /* default for Max Scan Cycle, 0 = forever */ -#define SCANOL_CYCLE_MAX 864000 /* Max Scan Cycle */ - /* 10 sec/scan cycle => 100 days */ -#define SCANOL_NPROBES 2 /* for Active scan; send n probes on each channel */ -#define SCANOL_NPROBES_MAX 5 /* for Active scan; send n probes on each channel */ -#define SCANOL_SCAN_START_DLY 10 /* delay start of offload scan (sec) */ -#define SCANOL_SCAN_START_DLY_MAX 240 /* delay start of offload scan (sec) */ -#define SCANOL_MULTIPLIER_MAX 10 /* Max Multiplier */ -#define SCANOL_UNASSOC_TIME_MAX 100 /* max dwell on a channel while unassociated */ -#define SCANOL_PASSIVE_TIME_MAX 500 /* max listen on a channel for passive scan */ -#define SCANOL_SSID_MAX 16 /* max supported preferred SSID */ - -/* masks for channel and ssid count */ -#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff -#define WL_SCAN_PARAMS_NSSID_SHIFT 16 - -#define WL_SCAN_ACTION_START 1 -#define WL_SCAN_ACTION_CONTINUE 2 -#define WL_SCAN_ACTION_ABORT 3 - - -#define ANTENNA_NUM_1 1 /* total number of antennas to be used */ -#define ANTENNA_NUM_2 2 -#define ANTENNA_NUM_3 3 -#define ANTENNA_NUM_4 4 - -#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 */ - -/* interference source detection and identification mode */ -#define ITFR_MODE_DISABLE 0 /* disable feature */ -#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */ -#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */ - -/* bit definitions for flags in interference source report */ -#define ITFR_INTERFERENCED 1 /* interference detected */ -#define ITFR_HOME_CHANNEL 2 /* home channel has interference */ -#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */ - -#define WL_NUM_RPI_BINS 8 -#define WL_RM_TYPE_BASIC 1 -#define WL_RM_TYPE_CCA 2 -#define WL_RM_TYPE_RPI 3 -#define WL_RM_TYPE_ABORT -1 /* ABORT any in-progress RM request */ - -#define WL_RM_FLAG_PARALLEL (1<<0) - -#define WL_RM_FLAG_LATE (1<<1) -#define WL_RM_FLAG_INCAPABLE (1<<2) -#define WL_RM_FLAG_REFUSED (1<<3) - -/* flags */ -#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ - -#define WLC_CIS_DEFAULT 0 /* built-in default */ -#define WLC_CIS_SROM 1 /* source is sprom */ -#define WLC_CIS_OTP 2 /* source is otp */ - -/* PCL - Power Control Loop */ -/* current gain setting is replaced by user input */ -#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ -#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ -/* current gain setting is maintained */ -#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ - -#define PLC_CMD_FAILOVER 1 -#define PLC_CMD_MAC_COST 2 -#define PLC_CMD_LINK_COST 3 -#define PLC_CMD_NODE_LIST 4 - -#define NODE_TYPE_UNKNOWN 0 /* Unknown link */ -#define NODE_TYPE_WIFI_ONLY 1 /* Pure Wireless STA node */ -#define NODE_TYPE_PLC_ONLY 2 /* Pure PLC only node */ -#define NODE_TYPE_WIFI_PLC 3 /* WiFi PLC capable node */ - -/* defines used by poweridx iovar - it controls power in a-band */ -/* current gain setting is maintained */ -#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ -#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ -#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ -#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ -/* value >= 0 causes - * - input to be set to that value - * - PCL to be off - */ - -#define BCM_MAC_STATUS_INDICATION (0x40010200L) - -/* Values for TX Filter override mode */ -#define WLC_TXFILTER_OVERRIDE_DISABLED 0 -#define WLC_TXFILTER_OVERRIDE_ENABLED 1 - -/* magic pattern used for mismatch driver and wl */ -#define WL_TXFIFO_SZ_MAGIC 0xa5a5 - -/* check this magic number */ -#define WLC_IOCTL_MAGIC 0x14e46c77 - - -/* bss_info_cap_t flags */ -#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */ -#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */ -#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info received on channel (vs offchannel) */ -#define WL_BSS_FLAGS_HS20 0x08 /* hotspot 2.0 capable */ -#define WL_BSS_FLAGS_RSSI_INVALID 0x10 /* BSS contains invalid RSSI */ -#define WL_BSS_FLAGS_RSSI_INACCURATE 0x20 /* BSS contains inaccurate RSSI */ -#define WL_BSS_FLAGS_SNR_INVALID 0x40 /* BSS contains invalid SNR */ -#define WL_BSS_FLAGS_NF_INVALID 0x80 /* BSS contains invalid noise floor */ - -/* bssinfo flag for nbss_cap */ -#define VHT_BI_SGI_80MHZ 0x00000100 -#define VHT_BI_80MHZ 0x00000200 -#define VHT_BI_160MHZ 0x00000400 -#define VHT_BI_8080MHZ 0x00000800 - -/* reference to wl_ioctl_t struct used by usermode driver */ -#define ioctl_subtype set /* subtype param */ -#define ioctl_pid used /* pid param */ -#define ioctl_status needed /* status param */ - - -/* 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_OCB_MSDU 5 -#define CRYPTO_ALGO_AES_OCB_MPDU 6 -#if !defined(BCMCCX) && !defined(BCMEXTCCX) -#define CRYPTO_ALGO_NALG 7 -#else -#define CRYPTO_ALGO_CKIP 7 -#define CRYPTO_ALGO_CKIP_MMH 8 -#define CRYPTO_ALGO_WEP_MMH 9 -#define CRYPTO_ALGO_NALG 10 -#endif /* !BCMCCX && !BCMEXTCCX */ - -#define CRYPTO_ALGO_SMS4 11 -#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ -#define CRYPTO_ALGO_BIP 13 /* 802.11w BIP (aes cmac) */ - -#define CRYPTO_ALGO_AES_GCM 14 /* 128 bit GCM */ -#define CRYPTO_ALGO_AES_CCM256 15 /* 256 bit CCM */ -#define CRYPTO_ALGO_AES_GCM256 16 /* 256 bit GCM */ -#define CRYPTO_ALGO_BIP_CMAC256 17 /* 256 bit BIP CMAC */ -#define CRYPTO_ALGO_BIP_GMAC 18 /* 128 bit BIP GMAC */ -#define CRYPTO_ALGO_BIP_GMAC256 19 /* 256 bit BIP GMAC */ - -#define CRYPTO_ALGO_NONE CRYPTO_ALGO_OFF - -#define WSEC_GEN_MIC_ERROR 0x0001 -#define WSEC_GEN_REPLAY 0x0002 -#define WSEC_GEN_ICV_ERROR 0x0004 -#define WSEC_GEN_MFP_ACT_ERROR 0x0008 -#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 -#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 - -#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ -#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ -#if defined(BCMCCX) || defined(BCMEXTCCX) -#define WL_CKIP_KP (1 << 4) /* CMIC */ -#define WL_CKIP_MMH (1 << 5) /* CKIP */ -#else -#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ -#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ -#endif /* BCMCCX || BCMEXTCCX */ -#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ - -/* wireless security bitvec */ -#define WEP_ENABLED 0x0001 -#define TKIP_ENABLED 0x0002 -#define AES_ENABLED 0x0004 -#define WSEC_SWFLAG 0x0008 -#ifdef BCMCCX -#define CKIP_KP_ENABLED 0x0010 -#define CKIP_MIC_ENABLED 0x0020 -#endif /* BCMCCX */ -#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */ -#ifdef BCMWAPI_WPI -#define SMS4_ENABLED 0x0100 -#endif /* BCMWAPI_WPI */ - -/* wsec macros for operating on the above definitions */ -#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) -#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) -#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) - -#ifdef BCMCCX -#define WSEC_CKIP_KP_ENABLED(wsec) ((wsec) & CKIP_KP_ENABLED) -#define WSEC_CKIP_MIC_ENABLED(wsec) ((wsec) & CKIP_MIC_ENABLED) -#define WSEC_CKIP_ENABLED(wsec) ((wsec) & (CKIP_KP_ENABLED|CKIP_MIC_ENABLED)) - -#ifdef BCMWAPI_WPI -#define WSEC_ENABLED(wsec) \ - ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | \ - CKIP_MIC_ENABLED | SMS4_ENABLED)) -#else /* BCMWAPI_WPI */ -#define WSEC_ENABLED(wsec) \ - ((wsec) & \ - (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | CKIP_MIC_ENABLED)) -#endif /* BCMWAPI_WPI */ -#else /* defined BCMCCX */ -#ifdef BCMWAPI_WPI -#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) -#else /* BCMWAPI_WPI */ -#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) -#endif /* BCMWAPI_WPI */ -#endif /* BCMCCX */ -#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) -#ifdef BCMWAPI_WAI -#define WSEC_SMS4_ENABLED(wsec) ((wsec) & SMS4_ENABLED) -#endif /* BCMWAPI_WAI */ - -#define MFP_CAPABLE 0x0200 -#define MFP_REQUIRED 0x0400 -#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ - -/* 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 */ -#if defined(BCMCCX) || defined(BCMEXTCCX) -#define WPA_AUTH_CCKM 0x0008 /* CCKM */ -#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ -#endif /* BCMCCX || BCMEXTCCX */ -/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ -#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ -#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ -#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */ -#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */ -#if defined(BCMWAPI_WAI) || defined(BCMWAPI_WPI) -#define WPA_AUTH_WAPI 0x0400 -#define WAPI_AUTH_NONE WPA_AUTH_NONE /* none (IBSS) */ -#define WAPI_AUTH_UNSPECIFIED 0x0400 /* over AS */ -#define WAPI_AUTH_PSK 0x0800 /* Pre-shared key */ -#endif /* BCMWAPI_WAI || BCMWAPI_WPI */ -#define WPA2_AUTH_MFP 0x1000 -#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */ -#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */ -#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ - -/* pmkid */ -#define MAXPMKID 16 - -#ifdef SROM12 -#define WLC_IOCTL_MAXLEN 10000 /* max length ioctl buffer required */ -#else -#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ -#endif /* SROM12 */ - -#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ -#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ -#if defined(LCNCONF) || defined(LCN40CONF) -#define WLC_SAMPLECOLLECT_MAXLEN 1024 /* Max Sample Collect buffer */ -#else -#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ -#endif -#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192 - -/* common ioctl definitions */ -#define WLC_GET_MAGIC 0 -#define WLC_GET_VERSION 1 -#define WLC_UP 2 -#define WLC_DOWN 3 -#define WLC_GET_LOOP 4 -#define WLC_SET_LOOP 5 -#define WLC_DUMP 6 -#define WLC_GET_MSGLEVEL 7 -#define WLC_SET_MSGLEVEL 8 -#define WLC_GET_PROMISC 9 -#define WLC_SET_PROMISC 10 -/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */ -#define WLC_GET_RATE 12 -#define WLC_GET_MAX_RATE 13 -#define WLC_GET_INSTANCE 14 -/* #define WLC_GET_FRAG 15 */ /* no longer supported */ -/* #define WLC_SET_FRAG 16 */ /* no longer supported */ -/* #define WLC_GET_RTS 17 */ /* no longer supported */ -/* #define WLC_SET_RTS 18 */ /* no longer supported */ -#define WLC_GET_INFRA 19 -#define WLC_SET_INFRA 20 -#define WLC_GET_AUTH 21 -#define WLC_SET_AUTH 22 -#define WLC_GET_BSSID 23 -#define WLC_SET_BSSID 24 -#define WLC_GET_SSID 25 -#define WLC_SET_SSID 26 -#define WLC_RESTART 27 -#define WLC_TERMINATED 28 -/* #define WLC_DUMP_SCB 28 */ /* no longer supported */ -#define WLC_GET_CHANNEL 29 -#define WLC_SET_CHANNEL 30 -#define WLC_GET_SRL 31 -#define WLC_SET_SRL 32 -#define WLC_GET_LRL 33 -#define WLC_SET_LRL 34 -#define WLC_GET_PLCPHDR 35 -#define WLC_SET_PLCPHDR 36 -#define WLC_GET_RADIO 37 -#define WLC_SET_RADIO 38 -#define WLC_GET_PHYTYPE 39 -#define WLC_DUMP_RATE 40 -#define WLC_SET_RATE_PARAMS 41 -#define WLC_GET_FIXRATE 42 -#define WLC_SET_FIXRATE 43 -/* #define WLC_GET_WEP 42 */ /* no longer supported */ -/* #define WLC_SET_WEP 43 */ /* no longer supported */ -#define WLC_GET_KEY 44 -#define WLC_SET_KEY 45 -#define WLC_GET_REGULATORY 46 -#define WLC_SET_REGULATORY 47 -#define WLC_GET_PASSIVE_SCAN 48 -#define WLC_SET_PASSIVE_SCAN 49 -#define WLC_SCAN 50 -#define WLC_SCAN_RESULTS 51 -#define WLC_DISASSOC 52 -#define WLC_REASSOC 53 -#define WLC_GET_ROAM_TRIGGER 54 -#define WLC_SET_ROAM_TRIGGER 55 -#define WLC_GET_ROAM_DELTA 56 -#define WLC_SET_ROAM_DELTA 57 -#define WLC_GET_ROAM_SCAN_PERIOD 58 -#define WLC_SET_ROAM_SCAN_PERIOD 59 -#define WLC_EVM 60 /* diag */ -#define WLC_GET_TXANT 61 -#define WLC_SET_TXANT 62 -#define WLC_GET_ANTDIV 63 -#define WLC_SET_ANTDIV 64 -/* #define WLC_GET_TXPWR 65 */ /* no longer supported */ -/* #define WLC_SET_TXPWR 66 */ /* no longer supported */ -#define WLC_GET_CLOSED 67 -#define WLC_SET_CLOSED 68 -#define WLC_GET_MACLIST 69 -#define WLC_SET_MACLIST 70 -#define WLC_GET_RATESET 71 -#define WLC_SET_RATESET 72 -/* #define WLC_GET_LOCALE 73 */ /* no longer supported */ -#define WLC_LONGTRAIN 74 -#define WLC_GET_BCNPRD 75 -#define WLC_SET_BCNPRD 76 -#define WLC_GET_DTIMPRD 77 -#define WLC_SET_DTIMPRD 78 -#define WLC_GET_SROM 79 -#define WLC_SET_SROM 80 -#define WLC_GET_WEP_RESTRICT 81 -#define WLC_SET_WEP_RESTRICT 82 -#define WLC_GET_COUNTRY 83 -#define WLC_SET_COUNTRY 84 -#define WLC_GET_PM 85 -#define WLC_SET_PM 86 -#define WLC_GET_WAKE 87 -#define WLC_SET_WAKE 88 -/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */ -#define WLC_GET_FORCELINK 90 /* ndis only */ -#define WLC_SET_FORCELINK 91 /* ndis only */ -#define WLC_FREQ_ACCURACY 92 /* diag */ -#define WLC_CARRIER_SUPPRESS 93 /* diag */ -#define WLC_GET_PHYREG 94 -#define WLC_SET_PHYREG 95 -#define WLC_GET_RADIOREG 96 -#define WLC_SET_RADIOREG 97 -#define WLC_GET_REVINFO 98 -#define WLC_GET_UCANTDIV 99 -#define WLC_SET_UCANTDIV 100 -#define WLC_R_REG 101 -#define WLC_W_REG 102 -/* #define WLC_DIAG_LOOPBACK 103 old tray diag */ -/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */ -#define WLC_GET_MACMODE 105 -#define WLC_SET_MACMODE 106 -#define WLC_GET_MONITOR 107 -#define WLC_SET_MONITOR 108 -#define WLC_GET_GMODE 109 -#define WLC_SET_GMODE 110 -#define WLC_GET_LEGACY_ERP 111 -#define WLC_SET_LEGACY_ERP 112 -#define WLC_GET_RX_ANT 113 -#define WLC_GET_CURR_RATESET 114 /* current rateset */ -#define WLC_GET_SCANSUPPRESS 115 -#define WLC_SET_SCANSUPPRESS 116 -#define WLC_GET_AP 117 -#define WLC_SET_AP 118 -#define WLC_GET_EAP_RESTRICT 119 -#define WLC_SET_EAP_RESTRICT 120 -#define WLC_SCB_AUTHORIZE 121 -#define WLC_SCB_DEAUTHORIZE 122 -#define WLC_GET_WDSLIST 123 -#define WLC_SET_WDSLIST 124 -#define WLC_GET_ATIM 125 -#define WLC_SET_ATIM 126 -#define WLC_GET_RSSI 127 -#define WLC_GET_PHYANTDIV 128 -#define WLC_SET_PHYANTDIV 129 -#define WLC_AP_RX_ONLY 130 -#define WLC_GET_TX_PATH_PWR 131 -#define WLC_SET_TX_PATH_PWR 132 -#define WLC_GET_WSEC 133 -#define WLC_SET_WSEC 134 -#define WLC_GET_PHY_NOISE 135 -#define WLC_GET_BSS_INFO 136 -#define WLC_GET_PKTCNTS 137 -#define WLC_GET_LAZYWDS 138 -#define WLC_SET_LAZYWDS 139 -#define WLC_GET_BANDLIST 140 - -#define WLC_GET_BAND 141 -#define WLC_SET_BAND 142 -#define WLC_SCB_DEAUTHENTICATE 143 -#define WLC_GET_SHORTSLOT 144 -#define WLC_GET_SHORTSLOT_OVERRIDE 145 -#define WLC_SET_SHORTSLOT_OVERRIDE 146 -#define WLC_GET_SHORTSLOT_RESTRICT 147 -#define WLC_SET_SHORTSLOT_RESTRICT 148 -#define WLC_GET_GMODE_PROTECTION 149 -#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 -#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 -#define WLC_UPGRADE 152 -/* #define WLC_GET_MRATE 153 */ /* no longer supported */ -/* #define WLC_SET_MRATE 154 */ /* no longer supported */ -#define WLC_GET_IGNORE_BCNS 155 -#define WLC_SET_IGNORE_BCNS 156 -#define WLC_GET_SCB_TIMEOUT 157 -#define WLC_SET_SCB_TIMEOUT 158 -#define WLC_GET_ASSOCLIST 159 -#define WLC_GET_CLK 160 -#define WLC_SET_CLK 161 -#define WLC_GET_UP 162 -#define WLC_OUT 163 -#define WLC_GET_WPA_AUTH 164 -#define WLC_SET_WPA_AUTH 165 -#define WLC_GET_UCFLAGS 166 -#define WLC_SET_UCFLAGS 167 -#define WLC_GET_PWRIDX 168 -#define WLC_SET_PWRIDX 169 -#define WLC_GET_TSSI 170 -#define WLC_GET_SUP_RATESET_OVERRIDE 171 -#define WLC_SET_SUP_RATESET_OVERRIDE 172 -/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */ -/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */ -/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */ -/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */ -/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */ -#define WLC_GET_PROTECTION_CONTROL 178 -#define WLC_SET_PROTECTION_CONTROL 179 -#define WLC_GET_PHYLIST 180 -#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */ -#define WLC_DECRYPT_STATUS 182 /* ndis only */ -#define WLC_GET_KEY_SEQ 183 -#define WLC_GET_SCAN_CHANNEL_TIME 184 -#define WLC_SET_SCAN_CHANNEL_TIME 185 -#define WLC_GET_SCAN_UNASSOC_TIME 186 -#define WLC_SET_SCAN_UNASSOC_TIME 187 -#define WLC_GET_SCAN_HOME_TIME 188 -#define WLC_SET_SCAN_HOME_TIME 189 -#define WLC_GET_SCAN_NPROBES 190 -#define WLC_SET_SCAN_NPROBES 191 -#define WLC_GET_PRB_RESP_TIMEOUT 192 -#define WLC_SET_PRB_RESP_TIMEOUT 193 -#define WLC_GET_ATTEN 194 -#define WLC_SET_ATTEN 195 -#define WLC_GET_SHMEM 196 /* diag */ -#define WLC_SET_SHMEM 197 /* diag */ -/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */ -/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */ -#define WLC_SET_WSEC_TEST 200 -#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 -#define WLC_TKIP_COUNTERMEASURES 202 -#define WLC_GET_PIOMODE 203 -#define WLC_SET_PIOMODE 204 -#define WLC_SET_ASSOC_PREFER 205 -#define WLC_GET_ASSOC_PREFER 206 -#define WLC_SET_ROAM_PREFER 207 -#define WLC_GET_ROAM_PREFER 208 -#define WLC_SET_LED 209 -#define WLC_GET_LED 210 -#define WLC_GET_INTERFERENCE_MODE 211 -#define WLC_SET_INTERFERENCE_MODE 212 -#define WLC_GET_CHANNEL_QA 213 -#define WLC_START_CHANNEL_QA 214 -#define WLC_GET_CHANNEL_SEL 215 -#define WLC_START_CHANNEL_SEL 216 -#define WLC_GET_VALID_CHANNELS 217 -#define WLC_GET_FAKEFRAG 218 -#define WLC_SET_FAKEFRAG 219 -#define WLC_GET_PWROUT_PERCENTAGE 220 -#define WLC_SET_PWROUT_PERCENTAGE 221 -#define WLC_SET_BAD_FRAME_PREEMPT 222 -#define WLC_GET_BAD_FRAME_PREEMPT 223 -#define WLC_SET_LEAP_LIST 224 -#define WLC_GET_LEAP_LIST 225 -#define WLC_GET_CWMIN 226 -#define WLC_SET_CWMIN 227 -#define WLC_GET_CWMAX 228 -#define WLC_SET_CWMAX 229 -#define WLC_GET_WET 230 -#define WLC_SET_WET 231 -#define WLC_GET_PUB 232 -/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */ -/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */ -#define WLC_GET_KEY_PRIMARY 235 -#define WLC_SET_KEY_PRIMARY 236 - - -/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */ -#define WLC_GET_ACI_ARGS 238 -#define WLC_SET_ACI_ARGS 239 -#define WLC_UNSET_CALLBACK 240 -#define WLC_SET_CALLBACK 241 -#define WLC_GET_RADAR 242 -#define WLC_SET_RADAR 243 -#define WLC_SET_SPECT_MANAGMENT 244 -#define WLC_GET_SPECT_MANAGMENT 245 -#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ -#define WLC_WDS_GET_WPA_SUP 247 -#define WLC_SET_CS_SCAN_TIMER 248 -#define WLC_GET_CS_SCAN_TIMER 249 -#define WLC_MEASURE_REQUEST 250 -#define WLC_INIT 251 -#define WLC_SEND_QUIET 252 -#define WLC_KEEPALIVE 253 -#define WLC_SEND_PWR_CONSTRAINT 254 -#define WLC_UPGRADE_STATUS 255 -#define WLC_CURRENT_PWR 256 -#define WLC_GET_SCAN_PASSIVE_TIME 257 -#define WLC_SET_SCAN_PASSIVE_TIME 258 -#define WLC_LEGACY_LINK_BEHAVIOR 259 -#define WLC_GET_CHANNELS_IN_COUNTRY 260 -#define WLC_GET_COUNTRY_LIST 261 -#define WLC_GET_VAR 262 /* get value of named variable */ -#define WLC_SET_VAR 263 /* set named variable to value */ -#define WLC_NVRAM_GET 264 /* deprecated */ -#define WLC_NVRAM_SET 265 -#define WLC_NVRAM_DUMP 266 -#define WLC_REBOOT 267 -#define WLC_SET_WSEC_PMK 268 -#define WLC_GET_AUTH_MODE 269 -#define WLC_SET_AUTH_MODE 270 -#define WLC_GET_WAKEENTRY 271 -#define WLC_SET_WAKEENTRY 272 -#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ -#define WLC_NVOTPW 274 -#define WLC_OTPW 275 -#define WLC_IOV_BLOCK_GET 276 -#define WLC_IOV_MODULES_GET 277 -#define WLC_SOFT_RESET 278 -#define WLC_GET_ALLOW_MODE 279 -#define WLC_SET_ALLOW_MODE 280 -#define WLC_GET_DESIRED_BSSID 281 -#define WLC_SET_DESIRED_BSSID 282 -#define WLC_DISASSOC_MYAP 283 -#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */ -#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */ -#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */ -#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */ -#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */ -#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */ -#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */ -#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */ -#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */ -#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */ -#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */ -#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */ -#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */ -#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */ -#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */ -#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */ -#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */ -#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */ -#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */ -#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */ -#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */ -#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */ -#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */ -#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */ -/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */ -#define WLC_GET_CMD 309 -/* #define WLC_LAST 310 */ /* Never used - can be reused */ -#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */ -#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */ -/* #define WLC_GET_WAI_RESTRICT 313 */ /* for WAPI, deprecated use iovar instead */ -/* #define WLC_SET_WAI_RESTRICT 314 */ /* for WAPI, deprecated use iovar instead */ -/* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */ -#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ -#define WLC_GET_NAT_STATE 317 -#define WLC_GET_TXBF_RATESET 318 -#define WLC_SET_TXBF_RATESET 319 -#define WLC_SCAN_CQ 320 -#define WLC_GET_RSSI_QDB 321 /* qdB portion of the RSSI */ -#define WLC_DUMP_RATESET 322 -#define WLC_ECHO 323 -#define WLC_LAST 324 -#ifndef EPICTRL_COOKIE -#define EPICTRL_COOKIE 0xABADCEDE -#endif - -/* vx wlc ioctl's offset */ -#define CMN_IOCTL_OFF 0x180 - -/* - * custom OID support - * - * 0xFF - implementation specific OID - * 0xE4 - first byte of Broadcom PCI vendor ID - * 0x14 - second byte of Broadcom PCI vendor ID - * 0xXX - the custom OID number - */ - -/* begin 0x1f values beyond the start of the ET driver range. */ -#define WL_OID_BASE 0xFFE41420 - -/* NDIS overrides */ -#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) -#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) -#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) -#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) -#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) -#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) -#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) - -/* EXT_STA Dongle suuport */ -#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) -#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) -#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) -#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) -#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) -#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) -#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) -#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) -#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) -#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) -#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) -#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) -#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) -#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) -#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) - -/* NAT filter driver support */ -#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG) -#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE) - -#define WL_DECRYPT_STATUS_SUCCESS 1 -#define WL_DECRYPT_STATUS_FAILURE 2 -#define WL_DECRYPT_STATUS_UNKNOWN 3 - -/* allows user-mode app to poll the status of USB image upgrade */ -#define WLC_UPGRADE_SUCCESS 0 -#define WLC_UPGRADE_PENDING 1 - -/* WLC_GET_AUTH, WLC_SET_AUTH values */ -#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ -#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ -#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ - -/* a large TX Power as an init value to factor out of MIN() calculations, - * keep low enough to fit in an int8, units are .25 dBm - */ -#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ - -/* "diag" iovar argument and error code */ -#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */ -#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */ -#define WL_DIAG_MEMORY 3 /* d11 memory test */ -#define WL_DIAG_LED 4 /* LED test */ -#define WL_DIAG_REG 5 /* d11/phy register test */ -#define WL_DIAG_SROM 6 /* srom read/crc test */ -#define WL_DIAG_DMA 7 /* DMA test */ -#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */ - -#define WL_DIAGERR_SUCCESS 0 -#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */ -#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */ -#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */ -#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */ -#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */ -#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */ -#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */ -#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */ -#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */ -#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */ - -#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */ -#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */ - -/* band types */ -#define WLC_BAND_AUTO 0 /* auto-select */ -#define WLC_BAND_5G 1 /* 5 Ghz */ -#define WLC_BAND_2G 2 /* 2.4 Ghz */ -#define WLC_BAND_ALL 3 /* all bands */ - -/* band range returned by band_range iovar */ -#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 - -#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4 -#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5 -#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6 -#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7 -#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8 - -#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 -#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 -#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 -#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 - -#ifdef SROM12 -#define WL_CHAN_FREQ_RANGE_5G_BAND4 5 -#define WL_CHAN_FREQ_RANGE_2G_40 6 -#define WL_CHAN_FREQ_RANGE_5G_BAND0_40 7 -#define WL_CHAN_FREQ_RANGE_5G_BAND1_40 8 -#define WL_CHAN_FREQ_RANGE_5G_BAND2_40 9 -#define WL_CHAN_FREQ_RANGE_5G_BAND3_40 10 -#define WL_CHAN_FREQ_RANGE_5G_BAND4_40 11 -#define WL_CHAN_FREQ_RANGE_5G_BAND0_80 12 -#define WL_CHAN_FREQ_RANGE_5G_BAND1_80 13 -#define WL_CHAN_FREQ_RANGE_5G_BAND2_80 14 -#define WL_CHAN_FREQ_RANGE_5G_BAND3_80 15 -#define WL_CHAN_FREQ_RANGE_5G_BAND4_80 16 - -#define WL_CHAN_FREQ_RANGE_5G_4BAND 17 -#define WL_CHAN_FREQ_RANGE_5G_5BAND 18 -#define WL_CHAN_FREQ_RANGE_5G_5BAND_40 19 -#define WL_CHAN_FREQ_RANGE_5G_5BAND_80 20 -#else -#define WL_CHAN_FREQ_RANGE_5G_4BAND 5 -#endif /* SROM12 */ -/* MAC list modes */ -#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */ -#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */ -#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */ - -/* - * 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 - -/* values for PLCPHdr_override */ -#define WLC_PLCP_AUTO -1 -#define WLC_PLCP_SHORT 0 -#define WLC_PLCP_LONG 1 - -/* values for g_protection_override and n_protection_override */ -#define WLC_PROTECTION_AUTO -1 -#define WLC_PROTECTION_OFF 0 -#define WLC_PROTECTION_ON 1 -#define WLC_PROTECTION_MMHDR_ONLY 2 -#define WLC_PROTECTION_CTS_ONLY 3 - -/* values for g_protection_control and n_protection_control */ -#define WLC_PROTECTION_CTL_OFF 0 -#define WLC_PROTECTION_CTL_LOCAL 1 -#define WLC_PROTECTION_CTL_OVERLAP 2 - -/* values for n_protection */ -#define WLC_N_PROTECTION_OFF 0 -#define WLC_N_PROTECTION_OPTIONAL 1 -#define WLC_N_PROTECTION_20IN40 2 -#define WLC_N_PROTECTION_MIXEDMODE 3 - -/* values for n_preamble_type */ -#define WLC_N_PREAMBLE_MIXEDMODE 0 -#define WLC_N_PREAMBLE_GF 1 -#define WLC_N_PREAMBLE_GF_BRCM 2 - -/* values for band specific 40MHz capabilities (deprecated) */ -#define WLC_N_BW_20ALL 0 -#define WLC_N_BW_40ALL 1 -#define WLC_N_BW_20IN2G_40IN5G 2 - -#define WLC_BW_20MHZ_BIT (1<<0) -#define WLC_BW_40MHZ_BIT (1<<1) -#define WLC_BW_80MHZ_BIT (1<<2) -#define WLC_BW_160MHZ_BIT (1<<3) - -/* Bandwidth capabilities */ -#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) -#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) -#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) -#define WLC_BW_CAP_160MHZ (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ - WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) -#define WLC_BW_CAP_UNRESTRICTED 0xFF - -#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) -#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) -#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) -#define WL_BW_CAP_160MHZ(bw_cap)(((bw_cap) & WLC_BW_160MHZ_BIT) ? TRUE : FALSE) - -/* values to force tx/rx chain */ -#define WLC_N_TXRX_CHAIN0 0 -#define WLC_N_TXRX_CHAIN1 1 - -/* bitflags for SGI support (sgi_rx iovar) */ -#define WLC_N_SGI_20 0x01 -#define WLC_N_SGI_40 0x02 -#define WLC_VHT_SGI_80 0x04 - -/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ -#define WLC_SGI_ALL 0x02 - -#define LISTEN_INTERVAL 10 -/* interference mitigation options */ -#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ -#define INTERFERE_NONE 0 /* off */ -#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */ -#define WLAN_MANUAL 2 /* ACI: no auto detection */ -#define WLAN_AUTO 3 /* ACI: auto detect */ -#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ -#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ - -/* interfernece mode bit-masks (ACPHY) */ -#define ACPHY_ACI_GLITCHBASED_DESENSE 1 /* bit 0 */ -#define ACPHY_ACI_HWACI_PKTGAINLMT 2 /* bit 1 */ -#define ACPHY_ACI_W2NB_PKTGAINLMT 4 /* bit 2 */ -#define ACPHY_ACI_PREEMPTION 8 /* bit 3 */ -#define ACPHY_HWACI_MITIGATION 16 /* bit 4 */ -#define ACPHY_ACI_MAX_MODE 31 - -/* AP environment */ -#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ -#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ -#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ -#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ - -#define TRIGGER_NOW 0 -#define TRIGGER_CRS 0x01 -#define TRIGGER_CRSDEASSERT 0x02 -#define TRIGGER_GOODFCS 0x04 -#define TRIGGER_BADFCS 0x08 -#define TRIGGER_BADPLCP 0x10 -#define TRIGGER_CRSGLITCH 0x20 - -#define WL_SAMPLEDATA_HEADER_TYPE 1 -#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ -#define WL_SAMPLEDATA_TYPE 2 -#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ -#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ - -/* WL_OTA START */ -#define WL_OTA_ARG_PARSE_BLK_SIZE 1200 -#define WL_OTA_TEST_MAX_NUM_RATE 30 -#define WL_OTA_TEST_MAX_NUM_SEQ 100 - -#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */ - -/* radar iovar SET defines */ -#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */ -#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */ -#define WL_RADAR_SIMULATED 2 /* force radar detector to declare - * detection once - */ -#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */ -#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 */ - -#ifndef WL_RSSI_ANT_MAX -#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ -#elif WL_RSSI_ANT_MAX != 4 -#error "WL_RSSI_ANT_MAX does not match" -#endif - -/* dfs_status iovar-related defines */ - -/* cac - channel availability check, - * ism - in-service monitoring - * csa - channel switching announcement - */ - -/* cac state values */ -#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */ -#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */ -#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */ -#define WL_DFS_CACSTATE_CSA 3 /* csa */ -#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */ -#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */ -#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */ -#define WL_DFS_CACSTATES 7 /* this many states exist */ - -/* Defines used with channel_bandwidth for curpower */ -#define WL_BW_20MHZ 0 -#define WL_BW_40MHZ 1 -#define WL_BW_80MHZ 2 -#define WL_BW_160MHZ 3 -#define WL_BW_8080MHZ 4 - -/* tx_power_t.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 -#define WL_TX_POWER_F_HT 0x10 -#define WL_TX_POWER_F_VHT 0x20 -#define WL_TX_POWER_F_OPENLOOP 0x40 - -/* Message levels */ -#define WL_ERROR_VAL 0x00000001 -#define WL_TRACE_VAL 0x00000002 -#define WL_PRHDRS_VAL 0x00000004 -#define WL_PRPKT_VAL 0x00000008 -#define WL_INFORM_VAL 0x00000010 -#define WL_TMP_VAL 0x00000020 -#define WL_OID_VAL 0x00000040 -#define WL_RATE_VAL 0x00000080 -#define WL_ASSOC_VAL 0x00000100 -#define WL_PRUSR_VAL 0x00000200 -#define WL_PS_VAL 0x00000400 -#define WL_TXPWR_VAL 0x00000800 /* retired in TOT on 6/10/2009 */ -#define WL_MODE_SWITCH_VAL 0x00000800 /* Using retired TXPWR val */ -#define WL_PORT_VAL 0x00001000 -#define WL_DUAL_VAL 0x00002000 -#define WL_WSEC_VAL 0x00004000 -#define WL_WSEC_DUMP_VAL 0x00008000 -#define WL_LOG_VAL 0x00010000 -#define WL_NRSSI_VAL 0x00020000 /* retired in TOT on 6/10/2009 */ -#define WL_LOFT_VAL 0x00040000 /* retired in TOT on 6/10/2009 */ -#define WL_REGULATORY_VAL 0x00080000 -#define WL_TAF_VAL 0x00100000 -#define WL_RADAR_VAL 0x00200000 /* retired in TOT on 6/10/2009 */ -#define WL_MPC_VAL 0x00400000 -#define WL_APSTA_VAL 0x00800000 -#define WL_DFS_VAL 0x01000000 -#define WL_BA_VAL 0x02000000 /* retired in TOT on 6/14/2010 */ -#define WL_ACI_VAL 0x04000000 -#define WL_PRMAC_VAL 0x04000000 -#define WL_MBSS_VAL 0x04000000 -#define WL_CAC_VAL 0x08000000 -#define WL_AMSDU_VAL 0x10000000 -#define WL_AMPDU_VAL 0x20000000 -#define WL_FFPLD_VAL 0x40000000 - -/* wl_msg_level is full. For new bits take the next one and AND with - * wl_msg_level2 in wl_dbg.h - */ -#define WL_DPT_VAL 0x00000001 -#define WL_SCAN_VAL 0x00000002 -#define WL_WOWL_VAL 0x00000004 -#define WL_COEX_VAL 0x00000008 -#define WL_RTDC_VAL 0x00000010 -#define WL_PROTO_VAL 0x00000020 -#define WL_BTA_VAL 0x00000040 -#define WL_CHANINT_VAL 0x00000080 -#define WL_WMF_VAL 0x00000100 -#define WL_P2P_VAL 0x00000200 -#define WL_ITFR_VAL 0x00000400 -#define WL_MCHAN_VAL 0x00000800 -#define WL_TDLS_VAL 0x00001000 -#define WL_MCNX_VAL 0x00002000 -#define WL_PROT_VAL 0x00004000 -#define WL_PSTA_VAL 0x00008000 -#define WL_TSO_VAL 0x00010000 -#define WL_TRF_MGMT_VAL 0x00020000 -#define WL_LPC_VAL 0x00040000 -#define WL_L2FILTER_VAL 0x00080000 -#define WL_TXBF_VAL 0x00100000 -#define WL_P2PO_VAL 0x00200000 -#define WL_TBTT_VAL 0x00400000 -#define WL_MQ_VAL 0x01000000 - -/* This level is currently used in Phoenix2 only */ -#define WL_SRSCAN_VAL 0x02000000 - -#define WL_WNM_VAL 0x04000000 -#define WL_PWRSEL_VAL 0x10000000 -#define WL_NET_DETECT_VAL 0x20000000 -#define WL_PCIE_VAL 0x40000000 - -/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier - * rather than a message-type of its own - */ -#define WL_TIMESTAMP_VAL 0x80000000 - -/* max # of leds supported by GPIO (gpio pin# == led index#) */ -#define WL_LED_NUMGPIO 32 /* gpio 0-31 */ - -/* led per-pin behaviors */ -#define WL_LED_OFF 0 /* always off */ -#define WL_LED_ON 1 /* always on */ -#define WL_LED_ACTIVITY 2 /* activity */ -#define WL_LED_RADIO 3 /* radio enabled */ -#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */ -#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */ -#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */ -#define WL_LED_WI1 7 -#define WL_LED_WI2 8 -#define WL_LED_WI3 9 -#define WL_LED_ASSOC 10 /* associated state indicator */ -#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */ -#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */ -#define WL_LED_WI4 13 -#define WL_LED_WI5 14 -#define WL_LED_BLINKSLOW 15 /* blink slow */ -#define WL_LED_BLINKMED 16 /* blink med */ -#define WL_LED_BLINKFAST 17 /* blink fast */ -#define WL_LED_BLINKCUSTOM 18 /* blink custom */ -#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */ -#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ - /* keep on for 300 sec */ -#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ -#define WL_LED_WI6 22 -#define WL_LED_WI7 23 -#define WL_LED_WI8 24 -#define WL_LED_NUMBEHAVIOR 25 - -/* led behavior numeric value format */ -#define WL_LED_BEH_MASK 0x7f /* behavior mask */ -#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */ - -/* number of bytes needed to define a proper bit mask for MAC event reporting */ -#define BCMIO_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) -#define BCMIO_NBBY 8 -#define WL_EVENTING_MASK_LEN 16 - - -/* join preference types */ -#define WL_JOIN_PREF_RSSI 1 /* by RSSI */ -#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */ -#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */ -#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */ -#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */ - -/* band preference */ -#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */ - -/* any multicast cipher suite */ -#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" - -/* 802.11h measurement types */ -#define WLC_MEASURE_TPC 1 -#define WLC_MEASURE_CHANNEL_BASIC 2 -#define WLC_MEASURE_CHANNEL_CCA 3 -#define WLC_MEASURE_CHANNEL_RPI 4 - -/* regulatory enforcement levels */ -#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */ -#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */ -#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */ -#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */ -/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE - * adoption is done regardless of capability spectrum_management - */ -#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */ - -#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */ -#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */ -#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */ -#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */ -#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */ -#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */ -#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */ - -/* BTC mode used by "btc_mode" iovar */ -#define WL_BTC_DISABLE 0 /* disable BT coexistence */ -#define WL_BTC_FULLTDM 1 /* full TDM COEX */ -#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ -#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ -#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ -#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ -#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ -#define WL_BTC_DEFAULT 8 /* set the default mode for the device */ -#define WL_INF_BTC_DISABLE 0 -#define WL_INF_BTC_ENABLE 1 -#define WL_INF_BTC_AUTO 3 - -/* BTC wire used by "btc_wire" iovar */ -#define WL_BTC_DEFWIRE 0 /* use default wire setting */ -#define WL_BTC_2WIRE 2 /* use 2-wire BTC */ -#define WL_BTC_3WIRE 3 /* use 3-wire BTC */ -#define WL_BTC_4WIRE 4 /* use 4-wire BTC */ - -/* BTC flags: BTC configuration that can be set by host */ -#define WL_BTC_FLAG_PREMPT (1 << 0) -#define WL_BTC_FLAG_BT_DEF (1 << 1) -#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2) -#define WL_BTC_FLAG_SIM_RSP (1 << 3) -#define WL_BTC_FLAG_PS_PROTECT (1 << 4) -#define WL_BTC_FLAG_SIM_TX_LP (1 << 5) -#define WL_BTC_FLAG_ECI (1 << 6) -#define WL_BTC_FLAG_LIGHT (1 << 7) -#define WL_BTC_FLAG_PARALLEL (1 << 8) - -/* maximum channels returned by the get valid channels iovar */ -#define WL_NUMCHANNELS 64 - -/* max number of chanspecs (used by the iovar to calc. buf space) */ -#ifdef WL11AC_80P80 -#define WL_NUMCHANSPECS 206 -#else -#define WL_NUMCHANSPECS 110 -#endif - - -/* WDS link local endpoint WPA role */ -#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */ -#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ -#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ - -/* Base offset values */ -#define WL_PKT_FILTER_BASE_PKT 0 -#define WL_PKT_FILTER_BASE_END 1 -#define WL_PKT_FILTER_BASE_D11_H 2 /* May be removed */ -#define WL_PKT_FILTER_BASE_D11_D 3 /* May be removed */ -#define WL_PKT_FILTER_BASE_ETH_H 4 -#define WL_PKT_FILTER_BASE_ETH_D 5 -#define WL_PKT_FILTER_BASE_ARP_H 6 -#define WL_PKT_FILTER_BASE_ARP_D 7 /* May be removed */ -#define WL_PKT_FILTER_BASE_IP4_H 8 -#define WL_PKT_FILTER_BASE_IP4_D 9 -#define WL_PKT_FILTER_BASE_IP6_H 10 -#define WL_PKT_FILTER_BASE_IP6_D 11 -#define WL_PKT_FILTER_BASE_TCP_H 12 -#define WL_PKT_FILTER_BASE_TCP_D 13 /* May be removed */ -#define WL_PKT_FILTER_BASE_UDP_H 14 -#define WL_PKT_FILTER_BASE_UDP_D 15 -#define WL_PKT_FILTER_BASE_IP6_P 16 -#define WL_PKT_FILTER_BASE_COUNT 17 /* May be removed */ - -/* String mapping for bases that may be used by applications or debug */ -#define WL_PKT_FILTER_BASE_NAMES \ - { "START", WL_PKT_FILTER_BASE_PKT }, \ - { "END", WL_PKT_FILTER_BASE_END }, \ - { "ETH_H", WL_PKT_FILTER_BASE_ETH_H }, \ - { "ETH_D", WL_PKT_FILTER_BASE_ETH_D }, \ - { "D11_H", WL_PKT_FILTER_BASE_D11_H }, \ - { "D11_D", WL_PKT_FILTER_BASE_D11_D }, \ - { "ARP_H", WL_PKT_FILTER_BASE_ARP_H }, \ - { "IP4_H", WL_PKT_FILTER_BASE_IP4_H }, \ - { "IP4_D", WL_PKT_FILTER_BASE_IP4_D }, \ - { "IP6_H", WL_PKT_FILTER_BASE_IP6_H }, \ - { "IP6_D", WL_PKT_FILTER_BASE_IP6_D }, \ - { "IP6_P", WL_PKT_FILTER_BASE_IP6_P }, \ - { "TCP_H", WL_PKT_FILTER_BASE_TCP_H }, \ - { "TCP_D", WL_PKT_FILTER_BASE_TCP_D }, \ - { "UDP_H", WL_PKT_FILTER_BASE_UDP_H }, \ - { "UDP_D", WL_PKT_FILTER_BASE_UDP_D } - -/* Flags for a pattern list element */ -#define WL_PKT_FILTER_MFLAG_NEG 0x0001 - -/* - * Packet engine interface - */ - -#define WL_PKTENG_PER_TX_START 0x01 -#define WL_PKTENG_PER_TX_STOP 0x02 -#define WL_PKTENG_PER_RX_START 0x04 -#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 -#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 -#define WL_PKTENG_PER_RX_STOP 0x08 -#define WL_PKTENG_PER_MASK 0xff - -#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ - -#define WL_PKTENG_MAXPKTSZ 16384 /* max pktsz limit for pkteng */ - -#define NUM_80211b_RATES 4 -#define NUM_80211ag_RATES 8 -#define NUM_80211n_RATES 32 -#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) - -/* - * WOWL capability/override settings - */ -#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */ -#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */ -#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */ -#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */ -#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */ -#define WL_WOWL_TST (1 << 5) /* Wakeup after test */ -#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */ -#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */ -#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */ -#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */ -#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */ -#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */ -#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */ -#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */ -#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */ -#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */ -#define WL_WOWL_SCANOL (1 << 16) /* If the bit is set, scan offload is enabled */ -#define WL_WOWL_TCPKEEP_TIME (1 << 17) /* Wakeup on tcpkeep alive timeout */ -#define WL_WOWL_MDNS_CONFLICT (1 << 18) /* Wakeup on mDNS Conflict Resolution */ -#define WL_WOWL_MDNS_SERVICE (1 << 19) /* Wakeup on mDNS Service Connect */ -#define WL_WOWL_TCPKEEP_DATA (1 << 20) /* tcp keepalive got data */ -#define WL_WOWL_FW_HALT (1 << 21) /* Firmware died in wowl mode */ -#define WL_WOWL_ENAB_HWRADIO (1 << 22) /* Enable detection of radio button changes */ -#define WL_WOWL_MIC_FAIL (1 << 23) /* Offloads detected MIC failure(s) */ -#define WL_WOWL_UNASSOC (1 << 24) /* Wakeup in Unassociated state (Net/Magic Pattern) */ -#define WL_WOWL_SECURE (1 << 25) /* Wakeup if received matched secured pattern */ -#define WL_WOWL_LINKDOWN (1 << 31) /* Link Down indication in WoWL mode */ - -#define WL_WOWL_TCPKEEP (1 << 20) /* temp copy to satisfy automerger */ -#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ - -#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ -#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ - -#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ -#define MAGIC_PKT_NUM_MAC_ADDRS 16 - - -/* Overlap BSS Scan parameters default, minimum, maximum */ -#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */ -#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */ -#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */ -#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */ -#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */ -#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */ -#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 -#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 -#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 -#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */ -#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */ -#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */ -#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */ -#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */ - -#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */ - -#define WL_COEX_INFO_MASK 0x07 -#define WL_COEX_INFO_REQ 0x01 -#define WL_COEX_40MHZ_INTOLERANT 0x02 -#define WL_COEX_WIDTH20 0x04 - -#define WLC_RSSI_INVALID 0 /* invalid RSSI value */ - -#define MAX_RSSI_LEVELS 8 - -/* **** EXTLOG **** */ -#define EXTLOG_CUR_VER 0x0100 - -#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ - -/* log modules (bitmap) */ -#define LOG_MODULE_COMMON 0x0001 -#define LOG_MODULE_ASSOC 0x0002 -#define LOG_MODULE_EVENT 0x0004 -#define LOG_MODULE_MAX 3 /* Update when adding module */ - -/* log levels */ -#define WL_LOG_LEVEL_DISABLE 0 -#define WL_LOG_LEVEL_ERR 1 -#define WL_LOG_LEVEL_WARN 2 -#define WL_LOG_LEVEL_INFO 3 -#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */ - -/* flag */ -#define LOG_FLAG_EVENT 1 - -/* log arg_type */ -#define LOG_ARGTYPE_NULL 0 -#define LOG_ARGTYPE_STR 1 /* %s */ -#define LOG_ARGTYPE_INT 2 /* %d */ -#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */ -#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */ - -/* 802.11 Mgmt Packet flags */ -#define VNDR_IE_BEACON_FLAG 0x1 -#define VNDR_IE_PRBRSP_FLAG 0x2 -#define VNDR_IE_ASSOCRSP_FLAG 0x4 -#define VNDR_IE_AUTHRSP_FLAG 0x8 -#define VNDR_IE_PRBREQ_FLAG 0x10 -#define VNDR_IE_ASSOCREQ_FLAG 0x20 -#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ -#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ - -#if defined(WLP2P) -/* P2P Action Frames flags (spec ordered) */ -#define VNDR_IE_GONREQ_FLAG 0x001000 -#define VNDR_IE_GONRSP_FLAG 0x002000 -#define VNDR_IE_GONCFM_FLAG 0x004000 -#define VNDR_IE_INVREQ_FLAG 0x008000 -#define VNDR_IE_INVRSP_FLAG 0x010000 -#define VNDR_IE_DISREQ_FLAG 0x020000 -#define VNDR_IE_DISRSP_FLAG 0x040000 -#define VNDR_IE_PRDREQ_FLAG 0x080000 -#define VNDR_IE_PRDRSP_FLAG 0x100000 - -#define VNDR_IE_P2PAF_SHIFT 12 -#endif /* WLP2P */ - -/* channel interference measurement (chanim) related defines */ - -/* chanim mode */ -#define CHANIM_DISABLE 0 /* disabled */ -#define CHANIM_DETECT 1 /* detection only */ -#define CHANIM_EXT 2 /* external state machine */ -#define CHANIM_ACT 3 /* full internal state machine, detect + act */ -#define CHANIM_MODE_MAX 4 - -/* define for apcs reason code */ -#define APCS_INIT 0 -#define APCS_IOCTL 1 -#define APCS_CHANIM 2 -#define APCS_CSTIMER 3 -#define APCS_BTA 4 -#define APCS_TXDLY 5 -#define APCS_NONACSD 6 -#define APCS_DFS_REENTRY 7 -#define APCS_TXFAIL 8 -#define APCS_MAX 9 - -/* number of ACS record entries */ -#define CHANIM_ACS_RECORD 10 - -/* CHANIM */ -#define CCASTATS_TXDUR 0 -#define CCASTATS_INBSS 1 -#define CCASTATS_OBSS 2 -#define CCASTATS_NOCTG 3 -#define CCASTATS_NOPKT 4 -#define CCASTATS_DOZE 5 -#define CCASTATS_TXOP 6 -#define CCASTATS_GDTXDUR 7 -#define CCASTATS_BDTXDUR 8 -#define CCASTATS_MAX 9 - -#define WL_CHANIM_COUNT_ALL 0xff -#define WL_CHANIM_COUNT_ONE 0x1 - -/* ap tpc modes */ -#define AP_TPC_OFF 0 -#define AP_TPC_BSS_PWR 1 /* BSS power control */ -#define AP_TPC_AP_PWR 2 /* AP power control */ -#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ -#define AP_TPC_MAX_LINK_MARGIN 127 - -/* ap tpc modes */ -#define AP_TPC_OFF 0 -#define AP_TPC_BSS_PWR 1 /* BSS power control */ -#define AP_TPC_AP_PWR 2 /* AP power control */ -#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ -#define AP_TPC_MAX_LINK_MARGIN 127 - -/* state */ -#define WL_P2P_DISC_ST_SCAN 0 -#define WL_P2P_DISC_ST_LISTEN 1 -#define WL_P2P_DISC_ST_SEARCH 2 - -/* i/f type */ -#define WL_P2P_IF_CLIENT 0 -#define WL_P2P_IF_GO 1 -#define WL_P2P_IF_DYNBCN_GO 2 -#define WL_P2P_IF_DEV 3 - -/* count */ -#define WL_P2P_SCHED_RSVD 0 -#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */ - -#define WL_P2P_SCHED_FIXED_LEN 3 - -/* schedule type */ -#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */ -#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */ - -/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */ -#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */ -#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */ -/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ -#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */ -/* schedule option - WL_P2P_SCHED_TYPE_XXX */ -#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */ - -/* schedule option - WL_P2P_SCHED_TYPE_ABS */ -#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */ -#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */ -/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ -#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with - * start being an offset of the 'current' TSF - */ - -/* feature flags */ -#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */ -#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe - * requests - */ -#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */ - -/* 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 - -/* Proxy STA modes */ -#define PSTA_MODE_DISABLED 0 -#define PSTA_MODE_PROXY 1 -#define PSTA_MODE_REPEATER 2 - -/* op code in nat_cfg */ -#define NAT_OP_ENABLE 1 /* enable NAT on given interface */ -#define NAT_OP_DISABLE 2 /* disable NAT on given interface */ -#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */ - -/* NAT state */ -#define NAT_STATE_ENABLED 1 /* NAT is enabled */ -#define NAT_STATE_DISABLED 2 /* NAT is disabled */ - -#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */ -#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */ -#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */ -#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */ - -/* D0 Coalescing */ -#define IPV4_ARP_FILTER 0x0001 -#define IPV4_NETBT_FILTER 0x0002 -#define IPV4_LLMNR_FILTER 0x0004 -#define IPV4_SSDP_FILTER 0x0008 -#define IPV4_WSD_FILTER 0x0010 -#define IPV6_NETBT_FILTER 0x0200 -#define IPV6_LLMNR_FILTER 0x0400 -#define IPV6_SSDP_FILTER 0x0800 -#define IPV6_WSD_FILTER 0x1000 - -/* Network Offload Engine */ -#define NWOE_OL_ENABLE 0x00000001 - -/* - * Traffic management structures/defines. - */ - -/* Traffic management bandwidth parameters */ -#define TRF_MGMT_MAX_PRIORITIES 3 - -#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ -#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Don't shape traffic */ -#define TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC 0x0008 /* Manage traffic over our local subnet */ -#define TRF_MGMT_FLAG_FILTER_ON_MACADDR 0x0010 /* filter on MAC address */ -#define TRF_MGMT_FLAG_NO_RX 0x0020 /* do not apply fiters to rx packets */ - -#define TRF_FILTER_MAC_ADDR 0x0001 /* L2 filter use dst mac address for filtering */ -#define TRF_FILTER_IP_ADDR 0x0002 /* L3 filter use ip ddress for filtering */ -#define TRF_FILTER_L4 0x0004 /* L4 filter use tcp/udp for filtering */ -#define TRF_FILTER_DWM 0x0008 /* L3 filter use DSCP for filtering */ -#define TRF_FILTER_FAVORED 0x0010 /* Tag the packet FAVORED */ - -/* WNM/NPS subfeatures mask */ -#define WL_WNM_BSSTRANS 0x00000001 -#define WL_WNM_PROXYARP 0x00000002 -#define WL_WNM_MAXIDLE 0x00000004 -#define WL_WNM_TIMBC 0x00000008 -#define WL_WNM_TFS 0x00000010 -#define WL_WNM_SLEEP 0x00000020 -#define WL_WNM_DMS 0x00000040 -#define WL_WNM_FMS 0x00000080 -#define WL_WNM_NOTIF 0x00000100 -#define WL_WNM_MAX 0x00000200 - -#ifndef ETHER_MAX_DATA -#define ETHER_MAX_DATA 1500 -#endif /* ETHER_MAX_DATA */ - -/* Different discovery modes for dpt */ -#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */ -#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */ -#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */ - -/* different path selection values */ -#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */ -#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */ -#define DPT_PATHSEL_APPATH 2 /* always use AP path */ - -/* different ops for deny list */ -#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */ -#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */ - -/* different ops for manual end point */ -#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ -#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ -#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ - -/* flags to indicate DPT status */ -#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */ -#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */ -#define DPT_STATUS_FAILED 0x04 /* DPT link failed */ - -#ifdef WLTDLS -/* different ops for manual end point */ -#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ -#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ -#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ -#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ -#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ -#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ -#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ -#define TDLS_MANUAL_EP_WFD_TPQ 8 /* WiFi-Display Tunneled Probe reQuest */ - -/* modes */ -#define TDLS_WFD_IE_TX 0 -#define TDLS_WFD_IE_RX 1 -#define TDLS_WFD_PROBE_IE_TX 2 -#define TDLS_WFD_PROBE_IE_RX 3 -#endif /* WLTDLS */ - -/* define for flag */ -#define TSPEC_PENDING 0 /* TSPEC pending */ -#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ -#define TSPEC_REJECTED 2 /* TSPEC rejected */ -#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ -#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ - -#ifdef BCMCCX -/* "wlan_reason" iovar interface */ -#define WL_WLAN_ASSOC_REASON_NORMAL_NETWORK 0 /* normal WLAN network setup */ -#define WL_WLAN_ASSOC_REASON_ROAM_FROM_CELLULAR_NETWORK 1 /* roam from Cellular network */ -#define WL_WLAN_ASSOC_REASON_ROAM_FROM_LAN 2 /* roam from LAN */ -#define WL_WLAN_ASSOC_REASON_MAX 2 /* largest value allowed */ -#endif /* BCMCCX */ - -/* Software feature flag defines used by wlfeatureflag */ -#ifdef WLAFTERBURNER -#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ -#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ -#endif /* WLAFTERBURNER */ -#define WL_SWFL_NOHWRADIO 0x0004 -#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ -#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ - -#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ - -#define CSA_BROADCAST_ACTION_FRAME 0 /* csa broadcast action frame */ -#define CSA_UNICAST_ACTION_FRAME 1 /* csa unicast action frame */ - -/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER. - * - * (-100 < value < 0) value is used directly as a roaming trigger in dBm - * (0 <= value) value specifies a logical roaming trigger level from - * the list below - * - * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never - * the logical roam trigger value. - */ -#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */ -#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */ -#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */ -#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */ -#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */ - -#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */ - -/* Preferred Network Offload (PNO, formerly PFN) defines */ -#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ - -#define SORT_CRITERIA_BIT 0 -#define AUTO_NET_SWITCH_BIT 1 -#define ENABLE_BKGRD_SCAN_BIT 2 -#define IMMEDIATE_SCAN_BIT 3 -#define AUTO_CONNECT_BIT 4 -#define ENABLE_BD_SCAN_BIT 5 -#define ENABLE_ADAPTSCAN_BIT 6 -#define IMMEDIATE_EVENT_BIT 8 -#define SUPPRESS_SSID_BIT 9 -#define ENABLE_NET_OFFLOAD_BIT 10 -/* report found/lost events for SSID and BSSID networks seperately */ -#define REPORT_SEPERATELY_BIT 11 -#define BESTN_BSSID_ONLY_BIT 12 - -#define SORT_CRITERIA_MASK 0x0001 -#define AUTO_NET_SWITCH_MASK 0x0002 -#define ENABLE_BKGRD_SCAN_MASK 0x0004 -#define IMMEDIATE_SCAN_MASK 0x0008 -#define AUTO_CONNECT_MASK 0x0010 - -#define ENABLE_BD_SCAN_MASK 0x0020 -#define ENABLE_ADAPTSCAN_MASK 0x00c0 -#define IMMEDIATE_EVENT_MASK 0x0100 -#define SUPPRESS_SSID_MASK 0x0200 -#define ENABLE_NET_OFFLOAD_MASK 0x0400 -/* report found/lost events for SSID and BSSID networks seperately */ -#define REPORT_SEPERATELY_MASK 0x0800 -#define BESTN_BSSID_ONLY_MASK 0x1000 - -#define PFN_VERSION 2 -#define PFN_SCANRESULT_VERSION 1 -#define MAX_PFN_LIST_COUNT 16 - -#define PFN_COMPLETE 1 -#define PFN_INCOMPLETE 0 - -#define DEFAULT_BESTN 2 -#define DEFAULT_MSCAN 0 -#define DEFAULT_REPEAT 10 -#define DEFAULT_EXP 2 - -#define PFN_PARTIAL_SCAN_BIT 0 -#define PFN_PARTIAL_SCAN_MASK 1 - -#define WL_PFN_SUPPRESSFOUND_MASK 0x08 -#define WL_PFN_SUPPRESSLOST_MASK 0x10 -#define WL_PFN_SSID_A_BAND_TRIG 0x20 -#define WL_PFN_SSID_BG_BAND_TRIG 0x40 -#define WL_PFN_RSSI_MASK 0xff00 -#define WL_PFN_RSSI_SHIFT 8 - -#define WL_PFN_REPORT_ALLNET 0 -#define WL_PFN_REPORT_SSIDNET 1 -#define WL_PFN_REPORT_BSSIDNET 2 - -#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ -#define WL_PFN_CFG_FLAGS_HISTORY_OFF 0x00000002 /* Scan history suppressed */ - -#define WL_PFN_HIDDEN_BIT 2 -#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ -#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ -#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ -#define WL_PFN_HIDDEN_MASK 0x4 -#define MAX_SSID_WHITELIST_NUM 4 -#define MAX_BSSID_PREF_LIST_NUM 32 -#define MAX_BSSID_BLACKLIST_NUM 32 - -#ifndef BESTN_MAX -#define BESTN_MAX 8 -#endif - -#ifndef MSCAN_MAX -#define MSCAN_MAX 32 -#endif - -/* TCP Checksum Offload error injection for testing */ -#define TOE_ERRTEST_TX_CSUM 0x00000001 -#define TOE_ERRTEST_RX_CSUM 0x00000002 -#define TOE_ERRTEST_RX_CSUM2 0x00000004 - -/* ARP Offload feature flags for arp_ol iovar */ -#define ARP_OL_AGENT 0x00000001 -#define ARP_OL_SNOOP 0x00000002 -#define ARP_OL_HOST_AUTO_REPLY 0x00000004 -#define ARP_OL_PEER_AUTO_REPLY 0x00000008 - -/* ARP Offload error injection */ -#define ARP_ERRTEST_REPLY_PEER 0x1 -#define ARP_ERRTEST_REPLY_HOST 0x2 - -#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ -#define ND_MULTIHOMING_MAX 10 /* Maximum local host IP addresses */ -#define ND_REQUEST_MAX 5 /* Max set of offload params */ - - -/* AOAC wake event flag */ -#define WAKE_EVENT_NLO_DISCOVERY_BIT 1 -#define WAKE_EVENT_AP_ASSOCIATION_LOST_BIT 2 -#define WAKE_EVENT_GTK_HANDSHAKE_ERROR_BIT 4 -#define WAKE_EVENT_4WAY_HANDSHAKE_REQUEST_BIT 8 - - -#define MAX_NUM_WOL_PATTERN 22 /* LOGO requirements min 22 */ - - -/* Packet filter operation mode */ -/* True: 1; False: 0 */ -#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 -/* Enable and disable pkt_filter as a whole */ -#define PKT_FILTER_MODE_DISABLE 2 -/* Cache first matched rx pkt(be queried by host later) */ -#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 -/* If pkt_filter is enabled and no filter is set, don't forward anything */ -#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 - -#ifdef DONGLEOVERLAYS -#define OVERLAY_IDX_MASK 0x000000ff -#define OVERLAY_IDX_SHIFT 0 -#define OVERLAY_FLAGS_MASK 0xffffff00 -#define OVERLAY_FLAGS_SHIFT 8 -/* overlay written to device memory immediately after loading the base image */ -#define OVERLAY_FLAG_POSTLOAD 0x100 -/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */ -#define OVERLAY_FLAG_DEFER_DL 0x200 -/* overlay downloaded prior to the host going to sleep */ -#define OVERLAY_FLAG_PRESLEEP 0x400 -#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 -#endif /* DONGLEOVERLAYS */ - -/* reuse two number in the sc/rc space */ -#define SMFS_CODE_MALFORMED 0xFFFE -#define SMFS_CODE_IGNORED 0xFFFD - -/* RFAWARE def */ -#define BCM_ACTION_RFAWARE 0x77 -#define BCM_ACTION_RFAWARE_DCS 0x01 - -/* DCS reason code define */ -#define BCM_DCS_IOVAR 0x1 -#define BCM_DCS_UNKNOWN 0xFF - - -#ifdef PROP_TXSTATUS -/* Bit definitions for tlv iovar */ -/* - * enable RSSI signals: - * WLFC_CTL_TYPE_RSSI - */ -#define WLFC_FLAGS_RSSI_SIGNALS 0x0001 - -/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals: - * - * WLFC_CTL_TYPE_MAC_OPEN - * WLFC_CTL_TYPE_MAC_CLOSE - * - * WLFC_CTL_TYPE_INTERFACE_OPEN - * WLFC_CTL_TYPE_INTERFACE_CLOSE - * - * WLFC_CTL_TYPE_MACDESC_ADD - * WLFC_CTL_TYPE_MACDESC_DEL - * - */ -#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002 - -/* enable (status, fifo_credit, mac_credit) signals - * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT - * WLFC_CTL_TYPE_TXSTATUS - * WLFC_CTL_TYPE_FIFO_CREDITBACK - */ -#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 - -#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 -#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 -#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 -#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040 -#define WLFC_FLAGS_PKT_STAMP_SIGNALS 0x0080 - -#endif /* PROP_TXSTATUS */ - -#define WL_TIMBC_STATUS_AP_UNKNOWN 255 /* AP status for internal use only */ - -#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ -#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ -#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ - -/* Definitions for Reliable Multicast */ -#define WL_RELMCAST_MAX_CLIENT 32 -#define WL_RELMCAST_FLAG_INBLACKLIST 1 -#define WL_RELMCAST_FLAG_ACTIVEACKER 2 -#define WL_RELMCAST_FLAG_RELMCAST 4 - -/* structures for proximity detection device role */ -#define WL_PROXD_MODE_DISABLE 0 -#define WL_PROXD_MODE_NEUTRAL 1 -#define WL_PROXD_MODE_INITIATOR 2 -#define WL_PROXD_MODE_TARGET 3 -#define WL_PROXD_RANDOM_WAKEUP 0x8000 - - -#ifdef NET_DETECT -#define NET_DETECT_MAX_WAKE_DATA_SIZE 2048 -#define NET_DETECT_MAX_PROFILES 16 -#define NET_DETECT_MAX_CHANNELS 50 -#endif /* NET_DETECT */ - - -/* 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) -#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */ - -#define WL_SPURAVOID_OFF 0 -#define WL_SPURAVOID_ON1 1 -#define WL_SPURAVOID_ON2 2 - - -#define WL_4335_SPURAVOID_ON1 1 -#define WL_4335_SPURAVOID_ON2 2 -#define WL_4335_SPURAVOID_ON3 3 -#define WL_4335_SPURAVOID_ON4 4 -#define WL_4335_SPURAVOID_ON5 5 -#define WL_4335_SPURAVOID_ON6 6 -#define WL_4335_SPURAVOID_ON7 7 -#define WL_4335_SPURAVOID_ON8 8 -#define WL_4335_SPURAVOID_ON9 9 - -/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ -#define WL_TXPWR_OVERRIDE (1U<<31) -#define WL_TXPWR_NEG (1U<<30) - - -/* 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_LCN40 10 -#define WLC_PHY_TYPE_AC 11 -#define WLC_PHY_TYPE_NULL 0xf - -/* Values for PM */ -#define PM_OFF 0 -#define PM_MAX 1 -#define PM_FAST 2 -#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */ - -#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ - -/* fbt_cap: FBT assoc / reassoc modes. */ -#define WLC_FBT_CAP_DRV_4WAY_AND_REASSOC 1 /* Driver 4-way handshake & reassoc (WLFBT). */ - -/* monitor_promisc_level bits */ -#define WL_MONPROMISC_PROMISC 0x0001 -#define WL_MONPROMISC_CTRL 0x0002 -#define WL_MONPROMISC_FCS 0x0004 - -/* TCP Checksum Offload defines */ -#define TOE_TX_CSUM_OL 0x00000001 -#define TOE_RX_CSUM_OL 0x00000002 - -/* Wi-Fi Display Services (WFDS) */ -#define WL_P2P_SOCIAL_CHANNELS_MAX WL_NUMCHANNELS -#define MAX_WFDS_SEEK_SVC 4 /* Max # of wfds services to seek */ -#define MAX_WFDS_ADVERT_SVC 4 /* Max # of wfds services to advertise */ -#define MAX_WFDS_SVC_NAME_LEN 200 /* maximum service_name length */ -#define MAX_WFDS_ADV_SVC_INFO_LEN 65000 /* maximum adv service_info length */ -#define P2P_WFDS_HASH_LEN 6 /* Length of a WFDS service hash */ -#define MAX_WFDS_SEEK_SVC_INFO_LEN 255 /* maximum seek service_info req length */ -#define MAX_WFDS_SEEK_SVC_NAME_LEN 200 /* maximum service_name length */ - -/* ap_isolate bitmaps */ -#define AP_ISOLATE_DISABLED 0x0 -#define AP_ISOLATE_SENDUP_ALL 0x01 -#define AP_ISOLATE_SENDUP_MCAST 0x02 - -#endif /* wlioctl_defs_h */ diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h deleted file mode 100644 index 766ffbf7fcb7..000000000000 --- a/drivers/net/wireless/bcmdhd/include/dhdioctl.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Definitions for ioctls to access DHD iovars. - * Based on wlioctl.h (for Broadcom 802.11abg driver). - * (Moves towards generic ioctls for BCM drivers/iovars.) - * - * Definitions subject to change without notice. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhdioctl.h 518127 2014-11-28 08:44:47Z $ - */ - -#ifndef _dhdioctl_h_ -#define _dhdioctl_h_ - -#include - - -/* require default structure packing */ -#define BWL_DEFAULT_PACKING -#include - - -/* Linux network driver ioctl encoding */ -typedef struct dhd_ioctl { - uint cmd; /* common ioctl definition */ - void *buf; /* pointer to user buffer */ - uint len; /* length of user buffer */ - bool set; /* get or set request (optional) */ - uint used; /* bytes read or written (optional) */ - uint needed; /* bytes needed (optional) */ - uint driver; /* to identify target driver */ -} dhd_ioctl_t; - -/* Underlying BUS definition */ -enum { - BUS_TYPE_USB = 0, /* for USB dongles */ - BUS_TYPE_SDIO, /* for SDIO dongles */ - BUS_TYPE_PCIE /* for PCIE dongles */ -}; - -/* per-driver magic numbers */ -#define DHD_IOCTL_MAGIC 0x00444944 - -/* bump this number if you change the ioctl interface */ -#define DHD_IOCTL_VERSION 1 - -#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ -#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ - -/* common ioctl definitions */ -#define DHD_GET_MAGIC 0 -#define DHD_GET_VERSION 1 -#define DHD_GET_VAR 2 -#define DHD_SET_VAR 3 - -/* message levels */ -#define DHD_ERROR_VAL 0x0001 -#define DHD_TRACE_VAL 0x0002 -#define DHD_INFO_VAL 0x0004 -#define DHD_DATA_VAL 0x0008 -#define DHD_CTL_VAL 0x0010 -#define DHD_TIMER_VAL 0x0020 -#define DHD_HDRS_VAL 0x0040 -#define DHD_BYTES_VAL 0x0080 -#define DHD_INTR_VAL 0x0100 -#define DHD_LOG_VAL 0x0200 -#define DHD_GLOM_VAL 0x0400 -#define DHD_EVENT_VAL 0x0800 -#define DHD_BTA_VAL 0x1000 -#define DHD_ISCAN_VAL 0x2000 -#define DHD_ARPOE_VAL 0x4000 -#define DHD_REORDER_VAL 0x8000 -#define DHD_WL_VAL 0x10000 -#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */ -#define DHD_WL_VAL2 0x40000 -#define DHD_PNO_VAL 0x80000 -#define DHD_RTT_VAL 0x100000 - -#ifdef SDTEST -/* For pktgen iovar */ -typedef struct dhd_pktgen { - uint version; /* To allow structure change tracking */ - uint freq; /* Max ticks between tx/rx attempts */ - uint count; /* Test packets to send/rcv each attempt */ - uint print; /* Print counts every attempts */ - uint total; /* Total packets (or bursts) */ - uint minlen; /* Minimum length of packets to send */ - uint maxlen; /* Maximum length of packets to send */ - uint numsent; /* Count of test packets sent */ - uint numrcvd; /* Count of test packets received */ - uint numfail; /* Count of test send failures */ - uint mode; /* Test mode (type of test packets) */ - uint stop; /* Stop after this many tx failures */ -} dhd_pktgen_t; - -/* Version in case structure changes */ -#define DHD_PKTGEN_VERSION 2 - -/* Type of test packets to use */ -#define DHD_PKTGEN_ECHO 1 /* Send echo requests */ -#define DHD_PKTGEN_SEND 2 /* Send discard packets */ -#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */ -#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ -#endif /* SDTEST */ - -/* Enter idle immediately (no timeout) */ -#define DHD_IDLE_IMMEDIATE (-1) - -/* Values for idleclock iovar: other values are the sd_divisor to use when idle */ -#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */ -#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */ - - -/* require default structure packing */ -#include - -#endif /* _dhdioctl_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h deleted file mode 100644 index 8624621913d9..000000000000 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 $ - * -*/ - -#ifndef _epivers_h_ -#define _epivers_h_ - -#define EPI_MAJOR_VERSION 1 - -#define EPI_MINOR_VERSION 71 - -#define EPI_RC_NUMBER 26 - -#define EPI_INCREMENTAL_NUMBER 0 - -#define EPI_BUILD_NUMBER 0 - -#define EPI_VERSION 1, 71, 26, 0 - -#define EPI_VERSION_NUM 0x01471a00 - -#define EPI_VERSION_DEV 1.71.26 - -/* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.71.26 (r)" - -#endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/hnd_armtrap.h b/drivers/net/wireless/bcmdhd/include/hnd_armtrap.h deleted file mode 100644 index c6186b156272..000000000000 --- a/drivers/net/wireless/bcmdhd/include/hnd_armtrap.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * HND arm trap handling. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hnd_armtrap.h 470663 2014-04-16 00:24:43Z $ - */ - -#ifndef _hnd_armtrap_h_ -#define _hnd_armtrap_h_ - - -/* ARM trap handling */ - -/* Trap types defined by ARM (see arminc.h) */ - -/* Trap locations in lo memory */ -#define TRAP_STRIDE 4 -#define FIRST_TRAP TR_RST -#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) - -#if defined(__ARM_ARCH_4T__) -#define MAX_TRAP_TYPE (TR_FIQ + 1) -#elif defined(__ARM_ARCH_7M__) -#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) -#endif /* __ARM_ARCH_7M__ */ - -/* The trap structure is defined here as offsets for assembly */ -#define TR_TYPE 0x00 -#define TR_EPC 0x04 -#define TR_CPSR 0x08 -#define TR_SPSR 0x0c -#define TR_REGS 0x10 -#define TR_REG(n) (TR_REGS + (n) * 4) -#define TR_SP TR_REG(13) -#define TR_LR TR_REG(14) -#define TR_PC TR_REG(15) - -#define TRAP_T_SIZE 80 - -#ifndef _LANGUAGE_ASSEMBLY - -#include - -typedef struct _trap_struct { - uint32 type; - uint32 epc; - uint32 cpsr; - uint32 spsr; - uint32 r0; /* a1 */ - uint32 r1; /* a2 */ - uint32 r2; /* a3 */ - uint32 r3; /* a4 */ - uint32 r4; /* v1 */ - uint32 r5; /* v2 */ - uint32 r6; /* v3 */ - uint32 r7; /* v4 */ - uint32 r8; /* v5 */ - uint32 r9; /* sb/v6 */ - uint32 r10; /* sl/v7 */ - uint32 r11; /* fp/v8 */ - uint32 r12; /* ip */ - uint32 r13; /* sp */ - uint32 r14; /* lr */ - uint32 pc; /* r15 */ -} trap_t; - -#endif /* !_LANGUAGE_ASSEMBLY */ - -#endif /* _hnd_armtrap_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/hnd_cons.h b/drivers/net/wireless/bcmdhd/include/hnd_cons.h deleted file mode 100644 index d9c0cb335e64..000000000000 --- a/drivers/net/wireless/bcmdhd/include/hnd_cons.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Console support for RTE - for host use only. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hnd_cons.h 473343 2014-04-29 01:45:22Z $ - */ -#ifndef _hnd_cons_h_ -#define _hnd_cons_h_ - -#include -#include - -#define CBUF_LEN (128) - -#define LOG_BUF_LEN 1024 - -#ifdef BOOTLOADER_CONSOLE_OUTPUT -#undef RWL_MAX_DATA_LEN -#undef CBUF_LEN -#undef LOG_BUF_LEN -#define RWL_MAX_DATA_LEN (4 * 1024 + 8) -#define CBUF_LEN (RWL_MAX_DATA_LEN + 64) -#define LOG_BUF_LEN (16 * 1024) -#endif - -typedef struct { - uint32 buf; /* Can't be pointer on (64-bit) hosts */ - uint buf_size; - uint idx; - uint out_idx; /* output index */ -} hnd_log_t; - -typedef struct { - /* 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. - */ - volatile uint vcons_in; - volatile 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. - */ - hnd_log_t log; - - /* 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]; -} hnd_cons_t; - -#endif /* _hnd_cons_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/hnd_pktpool.h b/drivers/net/wireless/bcmdhd/include/hnd_pktpool.h deleted file mode 100644 index 4100b3eeb4d1..000000000000 --- a/drivers/net/wireless/bcmdhd/include/hnd_pktpool.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * HND generic packet pool operation primitives - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: $ - */ - -#ifndef _hnd_pktpool_h_ -#define _hnd_pktpool_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef BCMPKTPOOL -#define POOL_ENAB(pool) ((pool) && (pool)->inited) -#define SHARED_POOL (pktpool_shared) -#else /* BCMPKTPOOL */ -#define POOL_ENAB(bus) 0 -#define SHARED_POOL ((struct pktpool *)NULL) -#endif /* BCMPKTPOOL */ - -#ifdef BCMFRAGPOOL -#define SHARED_FRAG_POOL (pktpool_shared_lfrag) -#endif -#define SHARED_RXFRAG_POOL (pktpool_shared_rxlfrag) - - -#ifndef PKTPOOL_LEN_MAX -#define PKTPOOL_LEN_MAX 40 -#endif /* PKTPOOL_LEN_MAX */ -#define PKTPOOL_CB_MAX 3 - -/* forward declaration */ -struct pktpool; - -typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); -typedef struct { - pktpool_cb_t cb; - void *arg; -} pktpool_cbinfo_t; -/* call back fn extension to populate host address in pool pkt */ -typedef int (*pktpool_cb_extn_t)(struct pktpool *pool, void *arg1, void* pkt, bool arg2); -typedef struct { - pktpool_cb_extn_t cb; - void *arg; -} pktpool_cbextn_info_t; - - -#ifdef BCMDBG_POOL -/* pkt pool debug states */ -#define POOL_IDLE 0 -#define POOL_RXFILL 1 -#define POOL_RXDH 2 -#define POOL_RXD11 3 -#define POOL_TXDH 4 -#define POOL_TXD11 5 -#define POOL_AMPDU 6 -#define POOL_TXENQ 7 - -typedef struct { - void *p; - uint32 cycles; - uint32 dur; -} pktpool_dbg_t; - -typedef struct { - uint8 txdh; /* tx to host */ - uint8 txd11; /* tx to d11 */ - uint8 enq; /* waiting in q */ - uint8 rxdh; /* rx from host */ - uint8 rxd11; /* rx from d11 */ - uint8 rxfill; /* dma_rxfill */ - uint8 idle; /* avail in pool */ -} pktpool_stats_t; -#endif /* BCMDBG_POOL */ - -typedef struct pktpool { - bool inited; /* pktpool_init was successful */ - uint8 type; /* type of lbuf: basic, frag, etc */ - uint8 id; /* pktpool ID: index in registry */ - bool istx; /* direction: transmit or receive data path */ - - void * freelist; /* free list: see PKTNEXTFREE(), PKTSETNEXTFREE() */ - uint16 avail; /* number of packets in pool's free list */ - uint16 len; /* number of packets managed by pool */ - uint16 maxlen; /* maximum size of pool <= PKTPOOL_LEN_MAX */ - uint16 plen; /* size of pkt buffer, excluding lbuf|lbuf_frag */ - - bool empty; - uint8 cbtoggle; - uint8 cbcnt; - uint8 ecbcnt; - bool emptycb_disable; - pktpool_cbinfo_t *availcb_excl; - pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; - pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; - pktpool_cbextn_info_t cbext; - pktpool_cbextn_info_t rxcplidfn; -#ifdef BCMDBG_POOL - uint8 dbg_cbcnt; - pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; - uint16 dbg_qlen; - pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; -#endif - pktpool_cbinfo_t dmarxfill; -} pktpool_t; - -extern pktpool_t *pktpool_shared; -#ifdef BCMFRAGPOOL -extern pktpool_t *pktpool_shared_lfrag; -#endif -extern pktpool_t *pktpool_shared_rxlfrag; - -/* Incarnate a pktpool registry. On success returns total_pools. */ -extern int pktpool_attach(osl_t *osh, uint32 total_pools); -extern int pktpool_dettach(osl_t *osh); /* Relinquish registry */ - -extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx, uint8 type); -extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); -extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); -extern void* pktpool_get(pktpool_t *pktp); -extern void pktpool_free(pktpool_t *pktp, void *p); -extern int pktpool_add(pktpool_t *pktp, void *p); -extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); -extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); -extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); -extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); -extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); -extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); -extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); -extern bool pktpool_emptycb_disabled(pktpool_t *pktp); -extern int pktpool_hostaddr_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg1); -extern int pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg); -extern void pktpool_invoke_dmarxfill(pktpool_t *pktp); -extern int pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg); - -#define POOLPTR(pp) ((pktpool_t *)(pp)) -#define POOLID(pp) (POOLPTR(pp)->id) - -#define POOLSETID(pp, ppid) (POOLPTR(pp)->id = (ppid)) - -#define pktpool_len(pp) (POOLPTR(pp)->len) -#define pktpool_avail(pp) (POOLPTR(pp)->avail) -#define pktpool_plen(pp) (POOLPTR(pp)->plen) -#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) - - -/* - * ---------------------------------------------------------------------------- - * A pool ID is assigned with a pkt pool during pool initialization. This is - * done by maintaining a registry of all initialized pools, and the registry - * index at which the pool is registered is used as the pool's unique ID. - * ID 0 is reserved and is used to signify an invalid pool ID. - * All packets henceforth allocated from a pool will be tagged with the pool's - * unique ID. Packets allocated from the heap will use the reserved ID = 0. - * Packets with non-zero pool id signify that they were allocated from a pool. - * A maximum of 15 pools are supported, allowing a 4bit pool ID to be used - * in place of a 32bit pool pointer in each packet. - * ---------------------------------------------------------------------------- - */ -#define PKTPOOL_INVALID_ID (0) -#define PKTPOOL_MAXIMUM_ID (15) - -/* Registry of pktpool(s) */ -extern pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; - -/* Pool ID to/from Pool Pointer converters */ -#define PKTPOOL_ID2PTR(id) (pktpools_registry[id]) -#define PKTPOOL_PTR2ID(pp) (POOLID(pp)) - - -#ifdef BCMDBG_POOL -extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); -extern int pktpool_start_trigger(pktpool_t *pktp, void *p); -extern int pktpool_dbg_dump(pktpool_t *pktp); -extern int pktpool_dbg_notify(pktpool_t *pktp); -extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); -#endif /* BCMDBG_POOL */ - -#ifdef __cplusplus - } -#endif - -#endif /* _hnd_pktpool_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/hnd_pktq.h b/drivers/net/wireless/bcmdhd/include/hnd_pktq.h deleted file mode 100644 index 3854843652af..000000000000 --- a/drivers/net/wireless/bcmdhd/include/hnd_pktq.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * HND generic pktq operation primitives - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: $ - */ - -#ifndef _hnd_pktq_h_ -#define _hnd_pktq_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* osl multi-precedence packet queue */ -#define PKTQ_LEN_MAX 0xFFFF /* Max uint16 65535 packets */ -#ifndef PKTQ_LEN_DEFAULT -#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ -#endif -#ifndef PKTQ_MAX_PREC -#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ -#endif - -typedef struct pktq_prec { - void *head; /* first packet to dequeue */ - void *tail; /* last packet to dequeue */ - uint16 len; /* number of queued packets */ - uint16 max; /* maximum number of queued packets */ -} pktq_prec_t; - -#ifdef PKTQ_LOG -typedef struct { - uint32 requested; /* packets requested to be stored */ - uint32 stored; /* packets stored */ - uint32 saved; /* packets saved, - because a lowest priority queue has given away one packet - */ - uint32 selfsaved; /* packets saved, - because an older packet from the same queue has been dropped - */ - uint32 full_dropped; /* packets dropped, - because pktq is full with higher precedence packets - */ - uint32 dropped; /* packets dropped because pktq per that precedence is full */ - uint32 sacrificed; /* packets dropped, - in order to save one from a queue of a highest priority - */ - uint32 busy; /* packets droped because of hardware/transmission error */ - uint32 retry; /* packets re-sent because they were not received */ - uint32 ps_retry; /* packets retried again prior to moving power save mode */ - uint32 suppress; /* packets which were suppressed and not transmitted */ - uint32 retry_drop; /* packets finally dropped after retry limit */ - uint32 max_avail; /* the high-water mark of the queue capacity for packets - - goes to zero as queue fills - */ - uint32 max_used; /* the high-water mark of the queue utilisation for packets - - increases with use ('inverse' of max_avail) - */ - uint32 queue_capacity; /* the maximum capacity of the queue */ - uint32 rtsfail; /* count of rts attempts that failed to receive cts */ - uint32 acked; /* count of packets sent (acked) successfully */ - uint32 txrate_succ; /* running total of phy rate of packets sent successfully */ - uint32 txrate_main; /* running totoal of primary phy rate of all packets */ - uint32 throughput; /* actual data transferred successfully */ - uint32 airtime; /* cumulative total medium access delay in useconds */ - uint32 _logtime; /* timestamp of last counter clear */ -} pktq_counters_t; - -typedef struct { - uint32 _prec_log; - pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */ -} pktq_log_t; -#endif /* PKTQ_LOG */ - - -#define PKTQ_COMMON \ - uint16 num_prec; /* number of precedences in use */ \ - uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ \ - uint16 max; /* total max packets */ \ - uint16 len; /* total number of packets */ - -/* multi-priority pkt queue */ -struct pktq { - PKTQ_COMMON - /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ - struct pktq_prec q[PKTQ_MAX_PREC]; -#ifdef PKTQ_LOG - pktq_log_t* pktqlog; -#endif -}; - -/* simple, non-priority pkt queue */ -struct spktq { - PKTQ_COMMON - /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ - struct pktq_prec q[1]; -}; - -#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) - -/* fn(pkt, arg). return true if pkt belongs to if */ -typedef bool (*ifpkt_cb_t)(void*, int); - -/* operations on a specific precedence in packet queue */ - -#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) -#define pktq_pmax(pq, prec) ((pq)->q[prec].max) -#define pktq_plen(pq, prec) ((pq)->q[prec].len) -#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) -#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) -#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) - -#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) -#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) - -extern void pktq_append(struct pktq *pq, int prec, struct spktq *list); -extern void pktq_prepend(struct pktq *pq, int prec, struct spktq *list); - -extern void *pktq_penq(struct pktq *pq, int prec, void *p); -extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); -extern void *pktq_pdeq(struct pktq *pq, int prec); -extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); -extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg); -extern void *pktq_pdeq_tail(struct pktq *pq, int prec); -/* Empty the queue at particular precedence level */ -extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, - ifpkt_cb_t fn, int arg); -/* Remove a specified packet from its queue */ -extern bool pktq_pdel(struct pktq *pq, void *p, int prec); - -/* operations on a set of precedences in packet queue */ - -extern int pktq_mlen(struct pktq *pq, uint prec_bmp); -extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); -extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); - -/* operations on packet queue as a whole */ - -#define pktq_len(pq) ((int)(pq)->len) -#define pktq_max(pq) ((int)(pq)->max) -#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) -#define pktq_full(pq) ((pq)->len >= (pq)->max) -#define pktq_empty(pq) ((pq)->len == 0) - -/* operations for single precedence queues */ -#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) -#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) -#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) -#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) -#define pktqflush(osh, pq) pktq_flush(osh, ((struct pktq *)(void *)pq), TRUE, NULL, 0) -#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) - -extern void pktq_init(struct pktq *pq, int num_prec, int max_len); -extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); - -/* prec_out may be NULL if caller is not interested in return value */ -extern void *pktq_deq(struct pktq *pq, int *prec_out); -extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); -extern void *pktq_peek(struct pktq *pq, int *prec_out); -extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); -extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); - -#ifdef __cplusplus - } -#endif - -#endif /* _hnd_pktq_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd/include/hndpmu.h deleted file mode 100644 index 763befeffd21..000000000000 --- a/drivers/net/wireless/bcmdhd/include/hndpmu.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * HND SiliconBackplane PMU support. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hndpmu.h 471127 2014-04-17 23:24:23Z $ - */ - -#ifndef _hndpmu_h_ -#define _hndpmu_h_ - -#include -#include -#include - - -extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on, uint32* min_res_mask); -extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength); - -extern void si_pmu_minresmask_htavail_set(si_t *sih, osl_t *osh, bool set_clear); -extern void si_pmu_slow_clk_reinit(si_t *sih, osl_t *osh); - -#endif /* _hndpmu_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/hndsoc.h b/drivers/net/wireless/bcmdhd/include/hndsoc.h deleted file mode 100644 index d6254e62e026..000000000000 --- a/drivers/net/wireless/bcmdhd/include/hndsoc.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Broadcom HND chip & on-chip-interconnect-related definitions. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hndsoc.h 473238 2014-04-28 19:14:56Z $ - */ - -#ifndef _HNDSOC_H -#define _HNDSOC_H - -/* Include the soci specific files */ -#include -#include - -/* - * SOC Interconnect Address Map. - * All regions may not exist on all chips. - */ -#define SI_SDRAM_BASE 0x00000000 /* Physical SDRAM */ -#define SI_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */ -#define SI_PCI_MEM_SZ (64 * 1024 * 1024) -#define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */ -#define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ -#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */ - -#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ - -#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ -#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ - -#ifndef SI_MAXCORES -#define SI_MAXCORES 32 /* NorthStar has more cores */ -#endif /* SI_MAXCORES */ - -#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ -#define SI_FASTRAM_SWAPPED 0x19800000 - -#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */ -#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */ -#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */ -#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */ -#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */ -#define SI_FLASH_WINDOW 0x01000000 /* Flash XIP Window */ - -#define SI_NS_NANDFLASH 0x1c000000 /* NorthStar NAND flash base */ -#define SI_NS_NORFLASH 0x1e000000 /* NorthStar NOR flash base */ -#define SI_NS_ROM 0xfffd0000 /* NorthStar ROM */ -#define SI_NS_FLASH_WINDOW 0x02000000 /* Flash XIP Window */ - -#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */ -#define SI_ARMCR4_ROM 0x000f0000 /* ARM Cortex-R4 ROM */ -#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */ -#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */ -#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */ -#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */ - -#define SI_SFLASH 0x14000000 -#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */ -#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */ -#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ -#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 - * (2 ZettaBytes), low 32 bits - */ -#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 - * (2 ZettaBytes), high 32 bits - */ -/* 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 ACPHY_CORE_ID 0x83b /* Dot11 ACPHY */ -#define PCIE2_CORE_ID 0x83c /* pci express Gen2 core */ -#define USB30D_CORE_ID 0x83d /* usb 3.0 device core */ -#define ARMCR4_CORE_ID 0x83e /* ARM CR4 CPU */ -#define GCI_CORE_ID 0x840 /* GCI Core */ -#define M2MDMA_CORE_ID 0x844 /* memory to memory dma */ -#define APB_BRIDGE_CORE_ID 0x135 /* APB bridge core ID */ -#define AXI_CORE_ID 0x301 /* AXI/GPV core ID */ -#define EROM_CORE_ID 0x366 /* EROM core ID */ -#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 - */ - -#define CC_4706_CORE_ID 0x500 /* chipcommon core */ -#define NS_PCIEG2_CORE_ID 0x501 /* PCIE Gen 2 core */ -#define NS_DMA_CORE_ID 0x502 /* DMA core */ -#define NS_SDIO3_CORE_ID 0x503 /* SDIO3 core */ -#define NS_USB20_CORE_ID 0x504 /* USB2.0 core */ -#define NS_USB30_CORE_ID 0x505 /* USB3.0 core */ -#define NS_A9JTAG_CORE_ID 0x506 /* ARM Cortex A9 JTAG core */ -#define NS_DDR23_CORE_ID 0x507 /* Denali DDR2/DDR3 memory controller */ -#define NS_ROM_CORE_ID 0x508 /* ROM core */ -#define NS_NAND_CORE_ID 0x509 /* NAND flash controller core */ -#define NS_QSPI_CORE_ID 0x50a /* SPI flash controller core */ -#define NS_CCB_CORE_ID 0x50b /* ChipcommonB core */ -#define SOCRAM_4706_CORE_ID 0x50e /* internal memory core */ -#define NS_SOCRAM_CORE_ID SOCRAM_4706_CORE_ID -#define ARMCA9_CORE_ID 0x510 /* ARM Cortex A9 core (ihost) */ -#define NS_IHOST_CORE_ID ARMCA9_CORE_ID /* ARM Cortex A9 core (ihost) */ -#define GMAC_COMMON_4706_CORE_ID 0x5dc /* Gigabit MAC core */ -#define GMAC_4706_CORE_ID 0x52d /* Gigabit MAC core */ -#define AMEMC_CORE_ID 0x52e /* DDR1/2 memory controller core */ -#define ALTA_CORE_ID 0x534 /* I2S core */ -#define DDR23_PHY_CORE_ID 0x5dd - -#define SI_PCI1_MEM 0x40000000 /* Host Mode sb2pcitranslation0 (64 MB) */ -#define SI_PCI1_CFG 0x44000000 /* Host Mode sb2pcitranslation1 (64 MB) */ -#define SI_PCIE1_DMA_H32 0xc0000000 /* PCIE Client Mode sb2pcitranslation2 - * (2 ZettaBytes), high 32 bits - */ -#define CC_4706B0_CORE_REV 0x8000001f /* chipcommon core */ -#define SOCRAM_4706B0_CORE_REV 0x80000005 /* internal memory core */ -#define GMAC_4706B0_CORE_REV 0x80000000 /* Gigabit MAC core */ -#define NS_PCIEG2_CORE_REV_B0 0x7 /* NS-B0 PCIE Gen 2 core rev */ - -/* There are TWO constants on all HND chips: SI_ENUM_BASE above, - * and chipcommon being the first core: - */ -#define SI_CC_IDX 0 -/* SOC Interconnect types (aka chip types) */ -#define SOCI_SB 0 -#define SOCI_AI 1 -#define SOCI_UBUS 2 -#define SOCI_NAI 3 - -/* 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 - -/* Norstar core status flags */ -#define SISF_NS_BOOTDEV_MASK 0x0003 /* ROM core */ -#define SISF_NS_BOOTDEV_NOR 0x0000 /* ROM core */ -#define SISF_NS_BOOTDEV_NAND 0x0001 /* ROM core */ -#define SISF_NS_BOOTDEV_ROM 0x0002 /* ROM core */ -#define SISF_NS_BOOTDEV_OFFLOAD 0x0003 /* ROM core */ -#define SISF_NS_SKUVEC_MASK 0x000c /* ROM core */ - -/* 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 */ -#define SI_PWR_CTL_ST 0x1e8 /* For memory clock gating */ - -/* 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_HQCLKREQ 0x00000040 /* HQ Clock Required */ -#define CCS_USBCLKREQ 0x00000100 /* USB Clock Req */ -#define CCS_SECICLKREQ 0x00000100 /* SECI Clock Req */ -#define CCS_ARMFASTCLOCKREQ 0x00000100 /* ARM CR4 fast clock request */ -#define CCS_AVBCLKREQ 0x00000400 /* AVB Clock enable request */ -#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: Backplane is running on ALP clock */ -#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */ -#define CCS_ARMFASTCLOCKSTATUS 0x01000000 /* Fast CPU clock is running */ -#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ -#define CCS_ERSRC_STS_SHIFT 24 - -#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */ -#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */ - -/* 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 */ - -/* A boot/binary may have an embedded block that describes its size */ -#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */ -#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */ -#define BISZ_MAGIC_IDX 0 /* Word 0: magic */ -#define BISZ_TXTST_IDX 1 /* 1: text start */ -#define BISZ_TXTEND_IDX 2 /* 2: text end */ -#define BISZ_DATAST_IDX 3 /* 3: data start */ -#define BISZ_DATAEND_IDX 4 /* 4: data end */ -#define BISZ_BSSST_IDX 5 /* 5: bss start */ -#define BISZ_BSSEND_IDX 6 /* 6: bss end */ -#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */ - -/* Boot/Kernel related defintion and functions */ -#define SOC_BOOTDEV_ROM 0x00000001 -#define SOC_BOOTDEV_PFLASH 0x00000002 -#define SOC_BOOTDEV_SFLASH 0x00000004 -#define SOC_BOOTDEV_NANDFLASH 0x00000008 - -#define SOC_KNLDEV_NORFLASH 0x00000002 -#define SOC_KNLDEV_NANDFLASH 0x00000004 - -#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) -int soc_boot_dev(void *sih); -int soc_knl_dev(void *sih); -#endif /* !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) */ - -#endif /* _HNDSOC_H */ diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h deleted file mode 100644 index c766d4d20eb7..000000000000 --- a/drivers/net/wireless/bcmdhd/include/linux_osl.h +++ /dev/null @@ -1,986 +0,0 @@ -/* - * Linux OS Independent Layer - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: linux_osl.h 614089 2016-01-21 02:43:09Z $ - */ - -#ifndef _linux_osl_h_ -#define _linux_osl_h_ - -#include -#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) - -/* Linux Kernel: File Operations: start */ -extern void * osl_os_open_image(char * filename); -extern int osl_os_get_image_block(char * buf, int len, void * image); -extern void osl_os_close_image(void * image); -extern int osl_os_image_size(void *image); -/* Linux Kernel: File Operations: end */ - -#ifdef BCMDRIVER - -/* OSL initialization */ -#ifdef SHARED_OSL_CMN -extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag, void **osh_cmn); -#else -extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); -#endif /* SHARED_OSL_CMN */ - -extern void osl_detach(osl_t *osh); -extern int osl_static_mem_init(osl_t *osh, void *adapter); -extern int osl_static_mem_deinit(osl_t *osh, void *adapter); -extern void osl_set_bus_handle(osl_t *osh, void *bus_handle); -extern void* osl_get_bus_handle(osl_t *osh); - -/* Global ASSERT type */ -extern uint32 g_assert_type; - -/* ASSERT */ -#if defined(BCMASSERT_LOG) - #define ASSERT(exp) \ - do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) -extern void osl_assert(const char *exp, const char *file, int line); -#else - #ifdef __GNUC__ - #define GCC_VERSION \ - (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) - #if GCC_VERSION > 30100 - #define ASSERT(exp) do {} while (0) - #else - /* ASSERT could cause segmentation fault on GCC3.1, use empty instead */ - #define ASSERT(exp) - #endif /* GCC_VERSION > 30100 */ - #endif /* __GNUC__ */ -#endif - -/* bcm_prefetch_32B */ -static inline void bcm_prefetch_32B(const uint8 *addr, const int cachelines_32B) -{ -} - -/* microsecond delay */ -#define OSL_DELAY(usec) osl_delay(usec) -extern void osl_delay(uint usec); - -#define OSL_SLEEP(ms) osl_sleep(ms) -extern void osl_sleep(uint ms); - -#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ - osl_pcmcia_read_attr((osh), (offset), (buf), (size)) -#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ - osl_pcmcia_write_attr((osh), (offset), (buf), (size)) -extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); -extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size); - -/* PCI configuration space access macros */ -#define OSL_PCI_READ_CONFIG(osh, offset, size) \ - osl_pci_read_config((osh), (offset), (size)) -#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ - osl_pci_write_config((osh), (offset), (size), (val)) -extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); -extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); - -/* PCI device bus # and slot # */ -#define OSL_PCI_BUS(osh) osl_pci_bus(osh) -#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) -#define OSL_PCIE_DOMAIN(osh) osl_pcie_domain(osh) -#define OSL_PCIE_BUS(osh) osl_pcie_bus(osh) -extern uint osl_pci_bus(osl_t *osh); -extern uint osl_pci_slot(osl_t *osh); -extern uint osl_pcie_domain(osl_t *osh); -extern uint osl_pcie_bus(osl_t *osh); -extern struct pci_dev *osl_pci_device(osl_t *osh); - - -/* Pkttag flag should be part of public information */ -typedef struct { - bool pkttag; - bool mmbus; /* Bus supports memory-mapped register accesses */ - pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ - void *tx_ctx; /* Context to the callback function */ - void *unused[3]; -} osl_pubinfo_t; - -extern void osl_flag_set(osl_t *osh, uint32 mask); -extern bool osl_is_flag_set(osl_t *osh, uint32 mask); - -#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ - do { \ - ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ - ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ - } while (0) - - -/* host/bus architecture-specific byte swap */ -#define BUS_SWAP32(v) (v) - #define MALLOC(osh, size) osl_malloc((osh), (size)) - #define MALLOCZ(osh, size) osl_mallocz((osh), (size)) - #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) - #define MALLOCED(osh) osl_malloced((osh)) - #define MEMORY_LEFTOVER(osh) osl_check_memleak(osh) - extern void *osl_malloc(osl_t *osh, uint size); - extern void *osl_mallocz(osl_t *osh, uint size); - extern void osl_mfree(osl_t *osh, void *addr, uint size); - extern uint osl_malloced(osl_t *osh); - extern uint osl_check_memleak(osl_t *osh); - - -#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) -extern uint osl_malloc_failed(osl_t *osh); - -/* allocate/free shared (dma-able) consistent memory */ -#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() -#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ - osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) -#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ - osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) - -#define DMA_ALLOC_CONSISTENT_FORCE32(osh, size, align, tot, pap, dmah) \ - osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) -#define DMA_FREE_CONSISTENT_FORCE32(osh, va, size, pa, dmah) \ - osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) - -extern uint osl_dma_consistent_align(void); -extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, - uint *tot, dmaaddr_t *pap); -extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa); - -/* map/unmap direction */ -#define DMA_TX 1 /* TX direction for DMA */ -#define DMA_RX 2 /* RX direction for DMA */ - -/* map/unmap shared (dma-able) memory */ -#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ - osl_dma_unmap((osh), (pa), (size), (direction)) -extern dmaaddr_t osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, - hnddma_seg_map_t *txp_dmah); -extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); - -/* API for DMA addressing capability */ -#define OSL_DMADDRWIDTH(osh, addrwidth) ({BCM_REFERENCE(osh); BCM_REFERENCE(addrwidth);}) - -/* API for CPU relax */ -extern void osl_cpu_relax(void); -#define OSL_CPU_RELAX() osl_cpu_relax() - -#if (defined(USE_KMALLOC_FOR_FLOW_RING) && defined(__ARM_ARCH_7A__)) || \ - defined(CONFIG_ARCH_MSM8994) - extern void osl_cache_flush(void *va, uint size); - extern void osl_cache_inv(void *va, uint size); - extern void osl_prefetch(const void *ptr); - #define OSL_CACHE_FLUSH(va, len) osl_cache_flush((void *) va, len) - #define OSL_CACHE_INV(va, len) osl_cache_inv((void *) va, len) - #define OSL_PREFETCH(ptr) osl_prefetch(ptr) -#ifdef __ARM_ARCH_7A__ - extern int osl_arch_is_coherent(void); - #define OSL_ARCH_IS_COHERENT() osl_arch_is_coherent() -#else - #define OSL_ARCH_IS_COHERENT() NULL -#endif /* __ARM_ARCH_7A__ */ -#else - #define OSL_CACHE_FLUSH(va, len) BCM_REFERENCE(va) - #define OSL_CACHE_INV(va, len) BCM_REFERENCE(va) - #define OSL_PREFETCH(ptr) BCM_REFERENCE(ptr) - - #define OSL_ARCH_IS_COHERENT() NULL -#endif - -/* register access macros */ -#if defined(BCMSDIO) - #include - #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(osl_get_bus_handle(osh), \ - (uintptr)(r), sizeof(*(r)), (v))) - #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(osl_get_bus_handle(osh), \ - (uintptr)(r), sizeof(*(r)))) -#endif - - -#if defined(BCMSDIO) - #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ - mmap_op else bus_op - #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ - mmap_op : bus_op -#else - #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) - #define SELECT_BUS_READ(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) -#endif - -#define OSL_ERROR(bcmerror) osl_error(bcmerror) -extern int osl_error(int bcmerror); - -/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ -#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ - -#define OSH_NULL NULL - -/* - * BINOSL selects the slightly slower function-call-based binary compatible osl. - * Macros expand to calls to functions defined in linux_osl.c . - */ -#include /* use current 2.4.x calling conventions */ -#include /* for vsn/printf's */ -#include /* for mem*, str* */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) -#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) -#else -#define OSL_SYSUPTIME() ((uint32)jiffies * msecs_to_jiffies(1)) -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ -#define printf(fmt, args...) printk(fmt , ## args) -#include /* for vsn/printf's */ -#include /* for mem*, str* */ -/* bcopy's: Linux kernel doesn't provide these (anymore) */ -#define bcopy(src, dst, len) memcpy((dst), (src), (len)) -#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) -#define bzero(b, len) memset((b), '\0', (len)) - -/* register access macros */ - -#ifdef CONFIG_64BIT -/* readq is defined only for 64 bit platform */ -#define R_REG(osh, r) (\ - SELECT_BUS_READ(osh, \ - ({ \ - __typeof(*(r)) __osl_v = 0; \ - switch (sizeof(*(r))) { \ - case sizeof(uint8): __osl_v = \ - readb((volatile uint8*)(r)); break; \ - case sizeof(uint16): __osl_v = \ - readw((volatile uint16*)(r)); break; \ - case sizeof(uint32): __osl_v = \ - readl((volatile uint32*)(r)); break; \ - case sizeof(uint64): __osl_v = \ - readq((volatile uint64*)(r)); break; \ - } \ - __osl_v; \ - }), \ - OSL_READ_REG(osh, r)) \ -) -#else /* !CONFIG_64BIT */ -#define R_REG(osh, r) (\ - SELECT_BUS_READ(osh, \ - ({ \ - __typeof(*(r)) __osl_v = 0; \ - switch (sizeof(*(r))) { \ - case sizeof(uint8): __osl_v = \ - readb((volatile uint8*)(r)); break; \ - case sizeof(uint16): __osl_v = \ - readw((volatile uint16*)(r)); break; \ - case sizeof(uint32): __osl_v = \ - readl((volatile uint32*)(r)); break; \ - } \ - __osl_v; \ - }), \ - OSL_READ_REG(osh, r)) \ -) -#endif /* CONFIG_64BIT */ - -#ifdef CONFIG_64BIT -/* writeq is defined only for 64 bit platform */ -#define W_REG(osh, r, v) do { \ - SELECT_BUS_WRITE(osh, \ - switch (sizeof(*(r))) { \ - case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ - case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ - case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ - case sizeof(uint64): writeq((uint64)(v), (volatile uint64*)(r)); break; \ - }, \ - (OSL_WRITE_REG(osh, r, v))); \ - } while (0) -#else /* !CONFIG_64BIT */ -#define W_REG(osh, r, v) do { \ - SELECT_BUS_WRITE(osh, \ - switch (sizeof(*(r))) { \ - case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ - case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ - case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ - }, \ - (OSL_WRITE_REG(osh, r, v))); \ - } while (0) -#endif /* CONFIG_64BIT */ - -#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) - -/* bcopy, bcmp, and bzero functions */ -#define bcopy(src, dst, len) memcpy((dst), (src), (len)) -#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) -#define bzero(b, len) memset((b), '\0', (len)) - -/* uncached/cached virtual address */ -#define OSL_UNCACHED(va) ((void *)va) -#define OSL_CACHED(va) ((void *)va) - -#define OSL_PREF_RANGE_LD(va, sz) BCM_REFERENCE(va) -#define OSL_PREF_RANGE_ST(va, sz) BCM_REFERENCE(va) - -/* get processor cycle count */ -#if defined(__i386__) -#define OSL_GETCYCLES(x) rdtscl((x)) -#else -#define OSL_GETCYCLES(x) ((x) = 0) -#endif - -/* dereference an address that may cause a bus exception */ -#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) - -/* map/unmap physical to virtual I/O */ -#if !defined(CONFIG_MMC_MSM7X00A) -#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) -#else -#define REG_MAP(pa, size) (void *)(0) -#endif /* !defined(CONFIG_MMC_MSM7X00A */ -#define REG_UNMAP(va) iounmap((va)) - -/* shared (dma-able) memory access macros */ -#define R_SM(r) *(r) -#define W_SM(r, v) (*(r) = (v)) -#define BZERO_SM(r, len) memset((r), '\0', (len)) - -/* Because the non BINOSL implemenation of the PKT OSL routines are macros (for - * performance reasons), we need the Linux headers. - */ -#include /* use current 2.4.x calling conventions */ - -/* packet primitives */ -#define PKTGET(osh, len, send) osl_pktget((osh), (len)) -#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) -#define PKTLIST_DUMP(osh, buf) BCM_REFERENCE(osh) -#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) -#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) -#ifdef CONFIG_DHD_USE_STATIC_BUF -#define PREALLOC_FREE_MAGIC 0xFEDC -#define PREALLOC_USED_MAGIC 0xFCDE -#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) -#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) -#else -#define PKTGET_STATIC PKTGET -#define PKTFREE_STATIC PKTFREE -#endif /* CONFIG_DHD_USE_STATIC_BUF */ -#if defined(BCMPCIE) && defined(CONFIG_DHD_USE_STATIC_BUF) && \ - defined(DHD_USE_STATIC_IOCTLBUF) -#define PKTINVALIDATE_STATIC(osh, skb) osl_pktinvalidate_static((osh), (skb)) -#endif /* BCMPCIE && CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTL_BUF */ -#define PKTDATA(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->data);}) -#define PKTLEN(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->len);}) -#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) -#define PKTEXPHEADROOM(osh, skb, b) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_realloc_headroom((struct sk_buff*)(skb), (b)); \ - }) -#define PKTTAILROOM(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_tailroom((struct sk_buff*)(skb)); \ - }) -#define PKTPADTAILROOM(osh, skb, padlen) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_pad((struct sk_buff*)(skb), (padlen)); \ - }) -#define PKTNEXT(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->next);}) -#define PKTSETNEXT(osh, skb, x) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)); \ - }) -#define PKTSETLEN(osh, skb, len) \ - ({ \ - BCM_REFERENCE(osh); \ - __skb_trim((struct sk_buff*)(skb), (len)); \ - }) -#define PKTPUSH(osh, skb, bytes) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_push((struct sk_buff*)(skb), (bytes)); \ - }) -#define PKTPULL(osh, skb, bytes) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_pull((struct sk_buff*)(skb), (bytes)); \ - }) -#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) -#define PKTSETPOOL(osh, skb, x, y) BCM_REFERENCE(osh) -#define PKTPOOL(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) -#define PKTFREELIST(skb) PKTLINK(skb) -#define PKTSETFREELIST(skb, x) PKTSETLINK((skb), (x)) -#define PKTPTR(skb) (skb) -#define PKTID(skb) ({BCM_REFERENCE(skb); 0;}) -#define PKTSETID(skb, id) ({BCM_REFERENCE(skb); BCM_REFERENCE(id);}) -#define PKTSHRINK(osh, m) ({BCM_REFERENCE(osh); m;}) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) -#define PKTORPHAN(skb) skb_orphan(skb) -#else -#define PKTORPHAN(skb) ({BCM_REFERENCE(skb); 0;}) -#endif /* LINUX VERSION >= 3.6 */ - - - -#ifdef CTFPOOL -#define CTFPOOL_REFILL_THRESH 3 -typedef struct ctfpool { - void *head; - spinlock_t lock; - uint max_obj; - uint curr_obj; - uint obj_size; - uint refills; - uint fast_allocs; - uint fast_frees; - uint slow_allocs; -} ctfpool_t; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) -#define FASTBUF (1 << 0) -#define PKTSETFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->pktc_flags) |= FASTBUF); \ - }) -#define PKTCLRFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->pktc_flags) &= (~FASTBUF)); \ - }) -#define PKTISFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->pktc_flags) & FASTBUF); \ - }) -#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->pktc_flags) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -#define FASTBUF (1 << 16) -#define PKTSETFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF); \ - }) -#define PKTCLRFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)); \ - }) -#define PKTISFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->mac_len) & FASTBUF); \ - }) -#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) -#else -#define FASTBUF (1 << 0) -#define PKTSETFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->__unused) |= FASTBUF); \ - }) -#define PKTCLRFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)); \ - }) -#define PKTISFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->__unused) & FASTBUF); \ - }) -#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) -#endif /* 2.6.22 */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) -#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->ctfpool) -#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->ctfpool)->head) -#else -#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) -#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) -#endif - -extern void *osl_ctfpool_add(osl_t *osh); -extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); -extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); -extern void osl_ctfpool_cleanup(osl_t *osh); -extern void osl_ctfpool_stats(osl_t *osh, void *b); -#else /* CTFPOOL */ -#define PKTSETFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTISFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) -#endif /* CTFPOOL */ - -#define PKTSETCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTISCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) - -#ifdef HNDCTF - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) -#define SKIPCT (1 << 2) -#define CHAINED (1 << 3) -#define PKTSETSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags |= SKIPCT); \ - }) -#define PKTCLRSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags &= (~SKIPCT)); \ - }) -#define PKTSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags & SKIPCT); \ - }) -#define PKTSETCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags |= CHAINED); \ - }) -#define PKTCLRCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags &= (~CHAINED)); \ - }) -#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->pktc_flags & CHAINED) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -#define SKIPCT (1 << 18) -#define CHAINED (1 << 19) -#define PKTSETSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len |= SKIPCT); \ - }) -#define PKTCLRSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)); \ - }) -#define PKTSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len & SKIPCT); \ - }) -#define PKTSETCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len |= CHAINED); \ - }) -#define PKTCLRCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len &= (~CHAINED)); \ - }) -#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->mac_len & CHAINED) -#else /* 2.6.22 */ -#define SKIPCT (1 << 2) -#define CHAINED (1 << 3) -#define PKTSETSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused |= SKIPCT); \ - }) -#define PKTCLRSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)); \ - }) -#define PKTSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused & SKIPCT); \ - }) -#define PKTSETCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused |= CHAINED); \ - }) -#define PKTCLRCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused &= (~CHAINED)); \ - }) -#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->__unused & CHAINED) -#endif /* 2.6.22 */ -typedef struct ctf_mark { - uint32 value; -} ctf_mark_t; -#define CTF_MARK(m) (m.value) -#else /* HNDCTF */ -#define PKTSETSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define CTF_MARK(m) ({BCM_REFERENCE(m); 0;}) -#endif /* HNDCTF */ - -#if defined(BCM_GMAC3) - -/** pktalloced accounting in devices using GMAC Bulk Forwarding to DHD */ - -/* Account for packets delivered to downstream forwarder by GMAC interface. */ -extern void osl_pkt_tofwder(osl_t *osh, void *skbs, int skb_cnt); -#define PKTTOFWDER(osh, skbs, skb_cnt) \ - osl_pkt_tofwder(((osl_t *)osh), (void *)(skbs), (skb_cnt)) - -/* Account for packets received from downstream forwarder. */ -extern void osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt); -#define PKTFRMFWDER(osh, skbs, skb_cnt) \ - osl_pkt_frmfwder(((osl_t *)osh), (void *)(skbs), (skb_cnt)) - - -/** GMAC Forwarded packet tagging for reduced cache flush/invalidate. - * In FWDERBUF tagged packet, only FWDER_PKTMAPSZ amount of data would have - * been accessed in the GMAC forwarder. This may be used to limit the number of - * cachelines that need to be flushed or invalidated. - * Packets sent to the DHD from a GMAC forwarder will be tagged w/ FWDERBUF. - * DHD may clear the FWDERBUF tag, if more than FWDER_PKTMAPSZ was accessed. - * Likewise, a debug print of a packet payload in say the ethernet driver needs - * to be accompanied with a clear of the FWDERBUF tag. - */ - -/** Forwarded packets, have a HWRXOFF sized rx header (etc.h) */ -#define FWDER_HWRXOFF (30) - -/** Maximum amount of a pktadat that a downstream forwarder (GMAC) may have - * read into the L1 cache (not dirty). This may be used in reduced cache ops. - * - * Max 56: ET HWRXOFF[30] + BRCMHdr[4] + EtherHdr[14] + VlanHdr[4] + IP[4] - */ -#define FWDER_PKTMAPSZ (FWDER_HWRXOFF + 4 + 14 + 4 + 4) - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - -#define FWDERBUF (1 << 4) -#define PKTSETFWDERBUF(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags |= FWDERBUF); \ - }) -#define PKTCLRFWDERBUF(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags &= (~FWDERBUF)); \ - }) -#define PKTISFWDERBUF(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags & FWDERBUF); \ - }) - -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) - -#define FWDERBUF (1 << 20) -#define PKTSETFWDERBUF(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len |= FWDERBUF); \ - }) -#define PKTCLRFWDERBUF(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len &= (~FWDERBUF)); \ - }) -#define PKTISFWDERBUF(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len & FWDERBUF); \ - }) - -#else /* 2.6.22 */ - -#define FWDERBUF (1 << 4) -#define PKTSETFWDERBUF(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused |= FWDERBUF); \ - }) -#define PKTCLRFWDERBUF(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused &= (~FWDERBUF)); \ - }) -#define PKTISFWDERBUF(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused & FWDERBUF); \ - }) - -#endif /* 2.6.22 */ - -#else /* ! BCM_GMAC3 */ - -#define PKTSETFWDERBUF(osh, skb) ({ BCM_REFERENCE(osh); BCM_REFERENCE(skb); }) -#define PKTCLRFWDERBUF(osh, skb) ({ BCM_REFERENCE(osh); BCM_REFERENCE(skb); }) -#define PKTISFWDERBUF(osh, skb) ({ BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) - -#endif /* ! BCM_GMAC3 */ - - -#ifdef HNDCTF -/* For broadstream iqos */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) -#define TOBR (1 << 5) -#define PKTSETTOBR(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags |= TOBR); \ - }) -#define PKTCLRTOBR(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags &= (~TOBR)); \ - }) -#define PKTISTOBR(skb) (((struct sk_buff*)(skb))->pktc_flags & TOBR) -#define PKTSETCTFIPCTXIF(skb, ifp) (((struct sk_buff*)(skb))->ctf_ipc_txif = ifp) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) -#define PKTSETCTFIPCTXIF(skb, ifp) ({BCM_REFERENCE(skb); BCM_REFERENCE(ifp);}) -#else /* 2.6.22 */ -#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) -#define PKTSETCTFIPCTXIF(skb, ifp) ({BCM_REFERENCE(skb); BCM_REFERENCE(ifp);}) -#endif /* 2.6.22 */ -#else /* HNDCTF */ -#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) -#endif /* HNDCTF */ - - -#ifdef BCMFA -#ifdef BCMFA_HW_HASH -#define PKTSETFAHIDX(skb, idx) (((struct sk_buff*)(skb))->napt_idx = idx) -#else -#define PKTSETFAHIDX(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) -#endif /* BCMFA_SW_HASH */ -#define PKTGETFAHIDX(skb) (((struct sk_buff*)(skb))->napt_idx) -#define PKTSETFADEV(skb, imp) (((struct sk_buff*)(skb))->dev = imp) -#define PKTSETRXDEV(skb) (((struct sk_buff*)(skb))->rxdev = ((struct sk_buff*)(skb))->dev) - -#define AUX_TCP_FIN_RST (1 << 0) -#define AUX_FREED (1 << 1) -#define PKTSETFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_TCP_FIN_RST) -#define PKTCLRFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_TCP_FIN_RST)) -#define PKTISFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_TCP_FIN_RST) -#define PKTSETFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_FREED) -#define PKTCLRFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_FREED)) -#define PKTISFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_FREED) -#define PKTISFABRIDGED(skb) PKTISFAAUX(skb) -#else -#define PKTISFAAUX(skb) ({BCM_REFERENCE(skb); FALSE;}) -#define PKTISFABRIDGED(skb) ({BCM_REFERENCE(skb); FALSE;}) -#define PKTISFAFREED(skb) ({BCM_REFERENCE(skb); FALSE;}) - -#define PKTCLRFAAUX(skb) BCM_REFERENCE(skb) -#define PKTSETFAFREED(skb) BCM_REFERENCE(skb) -#define PKTCLRFAFREED(skb) BCM_REFERENCE(skb) -#endif /* BCMFA */ - -extern void osl_pktfree(osl_t *osh, void *skb, bool send); -extern void *osl_pktget_static(osl_t *osh, uint len); -extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); -extern void osl_pktclone(osl_t *osh, void **pkt); -#if defined(BCMPCIE) && defined(CONFIG_DHD_USE_STATIC_BUF) && \ - defined(DHD_USE_STATIC_IOCTLBUF) -extern void osl_pktinvalidate_static(osl_t *osh, void *p); -#endif /* BCMPCIE && CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTL_BUF */ - -extern void *osl_pkt_frmnative(osl_t *osh, void *skb); -extern void *osl_pktget(osl_t *osh, uint len); -extern void *osl_pktdup(osl_t *osh, void *skb); -extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); -#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), (struct sk_buff*)(skb)) -#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_t *)(osh), (pkt)) - -#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) -#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) -#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) -#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) -#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW) -#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \ - ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) -/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ -#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) - -#ifdef CONFIG_NF_CONNTRACK_MARK -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define PKTMARK(p) (((struct sk_buff *)(p))->mark) -#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->mark = (m) -#else /* !2.6.0 */ -#define PKTMARK(p) (((struct sk_buff *)(p))->nfmark) -#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->nfmark = (m) -#endif /* 2.6.0 */ -#else /* CONFIG_NF_CONNTRACK_MARK */ -#define PKTMARK(p) 0 -#define PKTSETMARK(p, m) -#endif /* CONFIG_NF_CONNTRACK_MARK */ - -#define PKTALLOCED(osh) osl_pktalloced(osh) -extern uint osl_pktalloced(osl_t *osh); - -#define OSL_RAND() osl_rand() -extern uint32 osl_rand(void); - -#define DMA_MAP(osh, va, size, direction, p, dmah) \ - osl_dma_map((osh), (va), (size), (direction), (p), (dmah)) - -#ifdef PKTC -/* Use 8 bytes of skb tstamp field to store below info */ -struct chain_node { - struct sk_buff *link; - unsigned int flags:3, pkts:9, bytes:20; -}; - -#define CHAIN_NODE(skb) ((struct chain_node*)(((struct sk_buff*)skb)->pktc_cb)) - -#define PKTCSETATTR(s, f, p, b) ({CHAIN_NODE(s)->flags = (f); CHAIN_NODE(s)->pkts = (p); \ - CHAIN_NODE(s)->bytes = (b);}) -#define PKTCCLRATTR(s) ({CHAIN_NODE(s)->flags = CHAIN_NODE(s)->pkts = \ - CHAIN_NODE(s)->bytes = 0;}) -#define PKTCGETATTR(s) (CHAIN_NODE(s)->flags << 29 | CHAIN_NODE(s)->pkts << 20 | \ - CHAIN_NODE(s)->bytes) -#define PKTCCNT(skb) (CHAIN_NODE(skb)->pkts) -#define PKTCLEN(skb) (CHAIN_NODE(skb)->bytes) -#define PKTCGETFLAGS(skb) (CHAIN_NODE(skb)->flags) -#define PKTCSETFLAGS(skb, f) (CHAIN_NODE(skb)->flags = (f)) -#define PKTCCLRFLAGS(skb) (CHAIN_NODE(skb)->flags = 0) -#define PKTCFLAGS(skb) (CHAIN_NODE(skb)->flags) -#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c)) -#define PKTCINCRCNT(skb) (CHAIN_NODE(skb)->pkts++) -#define PKTCADDCNT(skb, c) (CHAIN_NODE(skb)->pkts += (c)) -#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l)) -#define PKTCADDLEN(skb, l) (CHAIN_NODE(skb)->bytes += (l)) -#define PKTCSETFLAG(skb, fb) (CHAIN_NODE(skb)->flags |= (fb)) -#define PKTCCLRFLAG(skb, fb) (CHAIN_NODE(skb)->flags &= ~(fb)) -#define PKTCLINK(skb) (CHAIN_NODE(skb)->link) -#define PKTSETCLINK(skb, x) (CHAIN_NODE(skb)->link = (struct sk_buff*)(x)) -#define FOREACH_CHAINED_PKT(skb, nskb) \ - for (; (skb) != NULL; (skb) = (nskb)) \ - if ((nskb) = (PKTISCHAINED(skb) ? PKTCLINK(skb) : NULL), \ - PKTSETCLINK((skb), NULL), 1) -#define PKTCFREE(osh, skb, send) \ -do { \ - void *nskb; \ - ASSERT((skb) != NULL); \ - FOREACH_CHAINED_PKT((skb), nskb) { \ - PKTCLRCHAINED((osh), (skb)); \ - PKTCCLRFLAGS((skb)); \ - PKTFREE((osh), (skb), (send)); \ - } \ -} while (0) -#define PKTCENQTAIL(h, t, p) \ -do { \ - if ((t) == NULL) { \ - (h) = (t) = (p); \ - } else { \ - PKTSETCLINK((t), (p)); \ - (t) = (p); \ - } \ -} while (0) -#endif /* PKTC */ - -#else /* ! BCMDRIVER */ - - -/* ASSERT */ - #define ASSERT(exp) do {} while (0) - -/* MALLOC and MFREE */ -#define MALLOC(o, l) malloc(l) -#define MFREE(o, p, l) free(p) -#include - -/* str* and mem* functions */ -#include - -/* *printf functions */ -#include - -/* bcopy, bcmp, and bzero */ -extern void bcopy(const void *src, void *dst, size_t len); -extern int bcmp(const void *b1, const void *b2, size_t len); -extern void bzero(void *b, size_t len); -#endif /* ! BCMDRIVER */ - -typedef struct sec_cma_info { - struct sec_mem_elem *sec_alloc_list; - struct sec_mem_elem *sec_alloc_list_tail; -} sec_cma_info_t; - -#ifdef BCM_SECURE_DMA - -#define SECURE_DMA_MAP(osh, va, size, direction, p, dmah, pcma, offset) \ - osl_sec_dma_map((osh), (va), (size), (direction), (p), (dmah), (pcma), (offset)) -#define SECURE_DMA_DD_MAP(osh, va, size, direction, p, dmah) \ - osl_sec_dma_dd_map((osh), (va), (size), (direction), (p), (dmah)) -#define SECURE_DMA_MAP_TXMETA(osh, va, size, direction, p, dmah, pcma) \ - osl_sec_dma_map_txmeta((osh), (va), (size), (direction), (p), (dmah), (pcma)) -#define SECURE_DMA_UNMAP(osh, pa, size, direction, p, dmah, pcma, offset) \ - osl_sec_dma_unmap((osh), (pa), (size), (direction), (p), (dmah), (pcma), (offset)) -#define SECURE_DMA_UNMAP_ALL(osh, pcma) \ -osl_sec_dma_unmap_all((osh), (pcma)) - -#if defined(__ARM_ARCH_7A__) -#define ACP_WAR_ENAB() 0 -#define ACP_WIN_LIMIT 0 -#define arch_is_coherent() 0 - -#define CMA_BUFSIZE_4K 4096 -#define CMA_BUFSIZE_2K 2048 -#define CMA_BUFSIZE_512 512 - -#define CMA_BUFNUM 9216 /* packet id num 8192+1024 */ -#define SEC_CMA_COHERENT_BLK 0x8000 /* 32768 */ -#define SEC_CMA_COHERENT_MAX 32 -#define CMA_DMA_DESC_MEMBLOCK (SEC_CMA_COHERENT_BLK * SEC_CMA_COHERENT_MAX) -#define CMA_DMA_DATA_MEMBLOCK (CMA_BUFSIZE_4K*CMA_BUFNUM) -#define CMA_MEMBLOCK (CMA_DMA_DESC_MEMBLOCK + CMA_DMA_DATA_MEMBLOCK) -#define CONT_ARMREGION 0x02 /* Region CMA */ -#else -#define CONT_MIPREGION 0x00 /* To access the MIPs mem, Not yet... */ -#endif /* !defined __ARM_ARCH_7A__ */ - -#define SEC_DMA_ALIGN (1<<16) -typedef struct sec_mem_elem { - size_t size; - int direction; - phys_addr_t pa_cma; /* physical address */ - void *va; /* virtual address of driver pkt */ - dma_addr_t dma_handle; /* bus address assign by linux */ - void *vac; /* virtual address of cma buffer */ - struct sec_mem_elem *next; -} sec_mem_elem_t; - -extern dma_addr_t osl_sec_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, - hnddma_seg_map_t *dmah, void *ptr_cma_info, uint offset); -extern dma_addr_t osl_sec_dma_dd_map(osl_t *osh, void *va, uint size, int direction, void *p, - hnddma_seg_map_t *dmah); -extern dma_addr_t osl_sec_dma_map_txmeta(osl_t *osh, void *va, uint size, - int direction, void *p, hnddma_seg_map_t *dmah, void *ptr_cma_info); -extern void osl_sec_dma_unmap(osl_t *osh, dma_addr_t dma_handle, uint size, int direction, - void *p, hnddma_seg_map_t *map, void *ptr_cma_info, uint offset); -extern void osl_sec_dma_unmap_all(osl_t *osh, void *ptr_cma_info); - -#endif /* BCM_SECURE_DMA */ -#endif /* _linux_osl_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h deleted file mode 100644 index 93934953aff2..000000000000 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ /dev/null @@ -1,748 +0,0 @@ -/* - * Linux-specific abstractions to gain some independence from linux kernel versions. - * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: linuxver.h 431983 2013-10-25 06:53:27Z $ - */ - -#ifndef _linuxver_h_ -#define _linuxver_h_ - -#include -#include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -#include -#else -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) -#include -#else -#include -#endif -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ -#include - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) -#include -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) -/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */ -#ifdef __UNDEF_NO_VERSION__ -#undef __NO_VERSION__ -#else -#define __NO_VERSION__ -#endif -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) -#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i") -#define module_param_string(_name_, _string_, _size_, _perm_) \ - MODULE_PARM(_string_, "c" __MODULE_STRING(_size_)) -#endif - -/* linux/malloc.h is deprecated, use linux/slab.h instead. */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)) -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -#include -#else -#include -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) -#undef IP_TOS -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) */ -#include - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)) -#include -#else -#include -#ifndef work_struct -#define work_struct tq_struct -#endif -#ifndef INIT_WORK -#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data)) -#endif -#ifndef schedule_work -#define schedule_work(_work) schedule_task((_work)) -#endif -#ifndef flush_scheduled_work -#define flush_scheduled_work() flush_scheduled_tasks() -#endif -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -#define DAEMONIZE(a) do { \ - allow_signal(SIGKILL); \ - allow_signal(SIGTERM); \ - } while (0) -#elif ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))) -#define DAEMONIZE(a) daemonize(a); \ - allow_signal(SIGKILL); \ - allow_signal(SIGTERM); -#else /* Linux 2.4 (w/o preemption patch) */ -#define RAISE_RX_SOFTIRQ() \ - cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) -#define DAEMONIZE(a) daemonize(); \ - do { if (a) \ - strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ - } while (0); -#endif /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) -#else -#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) -#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ - (RHEL_MAJOR == 5)) -/* Exclude RHEL 5 */ -typedef void (*work_func_t)(void *work); -#endif -#endif /* >= 2.6.20 */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -/* Some distributions have their own 2.6.x compatibility layers */ -#ifndef IRQ_NONE -typedef void irqreturn_t; -#define IRQ_NONE -#define IRQ_HANDLED -#define IRQ_RETVAL(x) -#endif -#else -typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) -#define IRQF_SHARED SA_SHIRQ -#endif /* < 2.6.18 */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) -#ifdef CONFIG_NET_RADIO -#define CONFIG_WIRELESS_EXT -#endif -#endif /* < 2.6.17 */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) -#include -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) -#include -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -#include -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -#include -#else -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) -#include -#endif -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ - - -#ifndef __exit -#define __exit -#endif -#ifndef __devexit -#define __devexit -#endif -#ifndef __devinit -# if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) -# define __devinit __init -# else -/* All devices are hotpluggable since linux 3.8.0 */ -# define __devinit -# endif -#endif /* !__devinit */ -#ifndef __devinitdata -#define __devinitdata -#endif -#ifndef __devexit_p -#define __devexit_p(x) x -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) - -#define pci_get_drvdata(dev) (dev)->sysdata -#define pci_set_drvdata(dev, value) (dev)->sysdata = (value) - -/* - * New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration - */ - -struct pci_device_id { - unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ - unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ - unsigned long driver_data; /* Data private to the driver */ -}; - -struct pci_driver { - struct list_head node; - char *name; - const struct pci_device_id *id_table; /* NULL if wants all devices */ - int (*probe)(struct pci_dev *dev, - const struct pci_device_id *id); /* New device inserted */ - void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug - * capable driver) - */ - void (*suspend)(struct pci_dev *dev); /* Device suspended */ - void (*resume)(struct pci_dev *dev); /* Device woken up */ -}; - -#define MODULE_DEVICE_TABLE(type, name) -#define PCI_ANY_ID (~0) - -/* compatpci.c */ -#define pci_module_init pci_register_driver -extern int pci_register_driver(struct pci_driver *drv); -extern void pci_unregister_driver(struct pci_driver *drv); - -#endif /* PCI registration */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) -#define pci_module_init pci_register_driver -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) -#ifdef MODULE -#define module_init(x) int init_module(void) { return x(); } -#define module_exit(x) void cleanup_module(void) { x(); } -#else -#define module_init(x) __initcall(x); -#define module_exit(x) __exitcall(x); -#endif -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) -#define WL_USE_NETDEV_OPS -#else -#undef WL_USE_NETDEV_OPS -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL) -#define WL_CONFIG_RFKILL -#else -#undef WL_CONFIG_RFKILL -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13)) -#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) -#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44)) -#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23)) -#define pci_enable_device(dev) do { } while (0) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)) -#define net_device device -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42)) - -/* - * DMA mapping - * - * See linux/Documentation/DMA-mapping.txt - */ - -#ifndef PCI_DMA_TODEVICE -#define PCI_DMA_TODEVICE 1 -#define PCI_DMA_FROMDEVICE 2 -#endif - -typedef u32 dma_addr_t; - -/* Pure 2^n version of get_order */ -static inline int get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - -static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -{ - void *ret; - int gfp = GFP_ATOMIC | GFP_DMA; - - ret = (void *)__get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_bus(ret); - } - return ret; -} -static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} -#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) -#define pci_unmap_single(cookie, address, size, dir) - -#endif /* DMA mapping */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)) - -#define dev_kfree_skb_any(a) dev_kfree_skb(a) -#define netif_down(dev) do { (dev)->start = 0; } while (0) - -/* pcmcia-cs provides its own netdevice compatibility layer */ -#ifndef _COMPAT_NETDEVICE_H - -/* - * SoftNet - * - * For pre-softnet kernels we need to tell the upper layer not to - * re-enter start_xmit() while we are in there. However softnet - * guarantees not to enter while we are in there so there is no need - * to do the netif_stop_queue() dance unless the transmit queue really - * gets stuck. This should also improve performance according to tests - * done by Aman Singla. - */ - -#define dev_kfree_skb_irq(a) dev_kfree_skb(a) -#define netif_wake_queue(dev) \ - do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0) -#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy) - -static inline void netif_start_queue(struct net_device *dev) -{ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; -} - -#define netif_queue_stopped(dev) (dev)->tbusy -#define netif_running(dev) (dev)->start - -#endif /* _COMPAT_NETDEVICE_H */ - -#define netif_device_attach(dev) netif_start_queue(dev) -#define netif_device_detach(dev) netif_stop_queue(dev) - -/* 2.4.x renamed bottom halves to tasklets */ -#define tasklet_struct tq_struct -static inline void tasklet_schedule(struct tasklet_struct *tasklet) -{ - queue_task(tasklet, &tq_immediate); - mark_bh(IMMEDIATE_BH); -} - -static inline void tasklet_init(struct tasklet_struct *tasklet, - void (*func)(unsigned long), - unsigned long data) -{ - tasklet->next = NULL; - tasklet->sync = 0; - tasklet->routine = (void (*)(void *))func; - tasklet->data = (void *)data; -} -#define tasklet_kill(tasklet) { do {} while (0); } - -/* 2.4.x introduced del_timer_sync() */ -#define del_timer_sync(timer) del_timer(timer) - -#else - -#define netif_down(dev) - -#endif /* SoftNet */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)) - -/* - * Emit code to initialise a tq_struct's routine and data pointers - */ -#define PREPARE_TQUEUE(_tq, _routine, _data) \ - do { \ - (_tq)->routine = _routine; \ - (_tq)->data = _data; \ - } while (0) - -/* - * Emit code to initialise all of a tq_struct - */ -#define INIT_TQUEUE(_tq, _routine, _data) \ - do { \ - INIT_LIST_HEAD(&(_tq)->list); \ - (_tq)->sync = 0; \ - PREPARE_TQUEUE((_tq), (_routine), (_data)); \ - } while (0) - -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) */ - -/* Power management related macro & routines */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) -#define PCI_SAVE_STATE(a, b) pci_save_state(a) -#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) -#else -#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) -#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) -static inline int -pci_save_state(struct pci_dev *dev, u32 *buffer) -{ - int i; - if (buffer) { - for (i = 0; i < 16; i++) - pci_read_config_dword(dev, i * 4, &buffer[i]); - } - return 0; -} - -static inline int -pci_restore_state(struct pci_dev *dev, u32 *buffer) -{ - int i; - - if (buffer) { - for (i = 0; i < 16; i++) - pci_write_config_dword(dev, i * 4, buffer[i]); - } - /* - * otherwise, write the context information we know from bootup. - * This works around a problem where warm-booting from Windows - * combined with a D3(hot)->D0 transition causes PCI config - * header data to be forgotten. - */ - else { - for (i = 0; i < 6; i ++) - pci_write_config_dword(dev, - PCI_BASE_ADDRESS_0 + (i * 4), - pci_resource_start(dev, i)); - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } - return 0; -} -#endif /* PCI power management */ - -/* Old cp0 access macros deprecated in 2.4.19 */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19)) -#define read_c0_count() read_32bit_cp0_register(CP0_COUNT) -#endif - -/* Module refcount handled internally in 2.6.x */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) -#ifndef SET_MODULE_OWNER -#define SET_MODULE_OWNER(dev) do {} while (0) -#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -#else -#define OLD_MOD_INC_USE_COUNT do {} while (0) -#define OLD_MOD_DEC_USE_COUNT do {} while (0) -#endif -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ -#ifndef SET_MODULE_OWNER -#define SET_MODULE_OWNER(dev) do {} while (0) -#endif -#ifndef MOD_INC_USE_COUNT -#define MOD_INC_USE_COUNT do {} while (0) -#endif -#ifndef MOD_DEC_USE_COUNT -#define MOD_DEC_USE_COUNT do {} while (0) -#endif -#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ - -#ifndef SET_NETDEV_DEV -#define SET_NETDEV_DEV(net, pdev) do {} while (0) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)) -#ifndef HAVE_FREE_NETDEV -#define free_netdev(dev) kfree(dev) -#endif -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -/* struct packet_type redefined in 2.6.x */ -#define af_packet_priv data -#endif - -/* suspend args */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) -#define DRV_SUSPEND_STATE_TYPE pm_message_t -#else -#define DRV_SUSPEND_STATE_TYPE uint32 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -#define CHECKSUM_HW CHECKSUM_PARTIAL -#endif - -typedef struct { - void *parent; /* some external entity that the thread supposed to work for */ - char *proc_name; - struct task_struct *p_task; - long thr_pid; - int prio; /* priority */ - struct semaphore sema; - int terminated; - struct completion completed; - spinlock_t spinlock; - int up_cnt; -} tsk_ctl_t; - - -/* requires tsk_ctl_t tsk argument, the caller's priv data is passed in owner ptr */ -/* note this macro assumes there may be only one context waiting on thread's completion */ -#ifdef DHD_DEBUG -#define DBG_THR(x) printk x -#else -#define DBG_THR(x) -#endif - -static inline bool binary_sema_down(tsk_ctl_t *tsk) -{ - if (down_interruptible(&tsk->sema) == 0) { - unsigned long flags = 0; - spin_lock_irqsave(&tsk->spinlock, flags); - if (tsk->up_cnt == 1) - tsk->up_cnt--; - else { - DBG_THR(("dhd_dpc_thread: Unexpected up_cnt %d\n", tsk->up_cnt)); - } - spin_unlock_irqrestore(&tsk->spinlock, flags); - return false; - } else - return true; -} - -static inline bool binary_sema_up(tsk_ctl_t *tsk) -{ - bool sem_up = false; - unsigned long flags = 0; - - spin_lock_irqsave(&tsk->spinlock, flags); - if (tsk->up_cnt == 0) { - tsk->up_cnt++; - sem_up = true; - } else if (tsk->up_cnt == 1) { - /* dhd_sched_dpc: dpc is alread up! */ - } else - DBG_THR(("dhd_sched_dpc: unexpected up cnt %d!\n", tsk->up_cnt)); - - spin_unlock_irqrestore(&tsk->spinlock, flags); - - if (sem_up) - up(&tsk->sema); - - return sem_up; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) -#else -#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) -#endif - -#define PROC_START(thread_func, owner, tsk_ctl, flags, name) \ -{ \ - sema_init(&((tsk_ctl)->sema), 0); \ - init_completion(&((tsk_ctl)->completed)); \ - (tsk_ctl)->parent = owner; \ - (tsk_ctl)->proc_name = name; \ - (tsk_ctl)->terminated = FALSE; \ - (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ - (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ - spin_lock_init(&((tsk_ctl)->spinlock)); \ - DBG_THR(("%s(): thread:%s:%lx started\n", __FUNCTION__, \ - (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ -} - -#define PROC_STOP(tsk_ctl) \ -{ \ - (tsk_ctl)->terminated = TRUE; \ - smp_wmb(); \ - up(&((tsk_ctl)->sema)); \ - wait_for_completion(&((tsk_ctl)->completed)); \ - DBG_THR(("%s(): thread:%s:%lx terminated OK\n", __FUNCTION__, \ - (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ - (tsk_ctl)->thr_pid = -1; \ -} - -/* ----------------------- */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -#define KILL_PROC(nr, sig) \ -{ \ -struct task_struct *tsk; \ -struct pid *pid; \ -pid = find_get_pid((pid_t)nr); \ -tsk = pid_task(pid, PIDTYPE_PID); \ -if (tsk) send_sig(sig, tsk, 1); \ -} -#else -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ - KERNEL_VERSION(2, 6, 30)) -#define KILL_PROC(pid, sig) \ -{ \ - struct task_struct *tsk; \ - tsk = find_task_by_vpid(pid); \ - if (tsk) send_sig(sig, tsk, 1); \ -} -#else -#define KILL_PROC(pid, sig) \ -{ \ - kill_proc(pid, sig, 1); \ -} -#endif -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#include -#include -#else -#include - -#define __wait_event_interruptible_timeout(wq, condition, ret) \ -do { \ - wait_queue_t __wait; \ - init_waitqueue_entry(&__wait, current); \ - \ - add_wait_queue(&wq, &__wait); \ - for (;;) { \ - set_current_state(TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if (!signal_pending(current)) { \ - ret = schedule_timeout(ret); \ - if (!ret) \ - break; \ - continue; \ - } \ - ret = -ERESTARTSYS; \ - break; \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&wq, &__wait); \ -} while (0) - -#define wait_event_interruptible_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - if (!(condition)) \ - __wait_event_interruptible_timeout(wq, condition, __ret); \ - __ret; \ -}) - -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ - -/* -For < 2.6.24, wl creates its own netdev but doesn't -align the priv area like the genuine alloc_netdev(). -Since netdev_priv() always gives us the aligned address, it will -not match our unaligned address for < 2.6.24 -*/ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) -#define DEV_PRIV(dev) (dev->priv) -#else -#define DEV_PRIV(dev) netdev_priv(dev) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -#define WL_ISR(i, d, p) wl_isr((i), (d)) -#else -#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) -#endif /* < 2.6.20 */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -#define netdev_priv(dev) dev->priv -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -#define CAN_SLEEP() ((!in_atomic() && !irqs_disabled())) -#else -#define CAN_SLEEP() (FALSE) -#endif - -#define KMALLOC_FLAG (CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC) - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -#define RANDOM32 prandom_u32 -#else -#define RANDOM32 random32 -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -#define SRANDOM32(entropy) prandom_seed(entropy) -#else -#define SRANDOM32(entropy) srandom32(entropy) -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ - -/* - * Overide latest kfifo functions with - * older version to work on older kernels - */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) && !defined(WL_COMPAT_WIRELESS) -#define kfifo_in_spinlocked(a, b, c, d) kfifo_put(a, (u8 *)b, c) -#define kfifo_out_spinlocked(a, b, c, d) kfifo_get(a, (u8 *)b, c) -#define kfifo_esize(a) 1 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)) && !defined(WL_COMPAT_WIRELESS) -#define kfifo_in_spinlocked(a, b, c, d) kfifo_in_locked(a, b, c, d) -#define kfifo_out_spinlocked(a, b, c, d) kfifo_out_locked(a, b, c, d) -#define kfifo_esize(a) 1 -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ - -#endif /* _linuxver_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/miniopt.h b/drivers/net/wireless/bcmdhd/include/miniopt.h deleted file mode 100644 index 3726cbab81b1..000000000000 --- a/drivers/net/wireless/bcmdhd/include/miniopt.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Command line options parser. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: miniopt.h 484281 2014-06-12 22:42:26Z $ - */ - - -#ifndef MINI_OPT_H -#define MINI_OPT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* ---- Include Files ---------------------------------------------------- */ - - -/* ---- Constants and Types ---------------------------------------------- */ - -#define MINIOPT_MAXKEY 128 /* Max options */ -typedef struct miniopt { - - /* These are persistent after miniopt_init() */ - const char* name; /* name for prompt in error strings */ - const char* flags; /* option chars that take no args */ - bool longflags; /* long options may be flags */ - bool opt_end; /* at end of options (passed a "--") */ - - /* These are per-call to miniopt() */ - - int consumed; /* number of argv entries cosumed in - * the most recent call to miniopt() - */ - bool positional; - bool good_int; /* 'val' member is the result of a sucessful - * strtol conversion of the option value - */ - char opt; - char key[MINIOPT_MAXKEY]; - char* valstr; /* positional param, or value for the option, - * or null if the option had - * no accompanying value - */ - uint uval; /* strtol translation of valstr */ - int val; /* strtol translation of valstr */ -} miniopt_t; - -void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); -int miniopt(miniopt_t *t, char **argv); - - -/* ---- Variable Externs ------------------------------------------------- */ -/* ---- Function Prototypes ---------------------------------------------- */ - - -#ifdef __cplusplus - } -#endif - -#endif /* MINI_OPT_H */ diff --git a/drivers/net/wireless/bcmdhd/include/msgtrace.h b/drivers/net/wireless/bcmdhd/include/msgtrace.h deleted file mode 100644 index 3d54bff2f08b..000000000000 --- a/drivers/net/wireless/bcmdhd/include/msgtrace.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Trace messages sent over HBUS - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: msgtrace.h 439681 2013-11-27 15:39:50Z $ - */ - -#ifndef _MSGTRACE_H -#define _MSGTRACE_H - -#ifndef _TYPEDEFS_H_ -#include -#endif - - -/* This marks the start of a packed structure section. */ -#include -/* for osl_t */ -#include -#define MSGTRACE_VERSION 1 - -/* Message trace header */ -typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { - uint8 version; - uint8 trace_type; -#define MSGTRACE_HDR_TYPE_MSG 0 -#define MSGTRACE_HDR_TYPE_LOG 1 - uint16 len; /* Len of the trace */ - uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost - * because of DMA error or a bus reset (ex: SDIO Func2) - */ - /* Msgtrace type only */ - uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */ - uint32 discarded_printf; /* Number of discarded printf because of trace overflow */ -} BWL_POST_PACKED_STRUCT msgtrace_hdr_t; - -#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t) - -/* The hbus driver generates traces when sending a trace message. This causes endless traces. - * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put. - * This prevents endless traces but generates hasardous lost of traces only in bus device code. - * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing - * hbus error traces. hbus error trace should not generates endless traces. - */ -extern bool msgtrace_hbus_trace; - -typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, - uint16 hdrlen, uint8 *buf, uint16 buflen); -extern void msgtrace_start(void); -extern void msgtrace_stop(void); -extern int msgtrace_sent(void); -extern void msgtrace_put(char *buf, int count); -extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send); -extern bool msgtrace_event_enabled(void); - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _MSGTRACE_H */ diff --git a/drivers/net/wireless/bcmdhd/include/osl.h b/drivers/net/wireless/bcmdhd/include/osl.h deleted file mode 100644 index f4bbbcad4841..000000000000 --- a/drivers/net/wireless/bcmdhd/include/osl.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * OS Abstraction Layer - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: osl.h 542258 2015-03-19 07:55:03Z $ - */ - -#ifndef _osl_h_ -#define _osl_h_ - -#include - -#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ - -/* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ -typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); - -/* Drivers use REGOPSSET() to register register read/write funcitons */ -typedef unsigned int (*osl_rreg_fn_t)(void *ctx, volatile void *reg, unsigned int size); -typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, unsigned int size); - - - -#include - -#ifndef PKTDBG_TRACE -#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) -#endif - -#define PKTCTFMAP(osh, p) BCM_REFERENCE(osh) - -/* -------------------------------------------------------------------------- -** Register manipulation macros. -*/ - -#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) - -#ifndef AND_REG -#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -#endif /* !AND_REG */ - -#ifndef OR_REG -#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) -#endif /* !OR_REG */ - -#if !defined(OSL_SYSUPTIME) -#define OSL_SYSUPTIME() (0) -#define OSL_SYSUPTIME_SUPPORT FALSE -#else -#define OSL_SYSUPTIME_SUPPORT TRUE -#endif /* OSL_SYSUPTIME */ - -#if !defined(PKTC) && !defined(PKTC_DONGLE) -#define PKTCGETATTR(skb) (0) -#define PKTCSETATTR(skb, f, p, b) BCM_REFERENCE(skb) -#define PKTCCLRATTR(skb) BCM_REFERENCE(skb) -#define PKTCCNT(skb) (1) -#define PKTCLEN(skb) PKTLEN(NULL, skb) -#define PKTCGETFLAGS(skb) (0) -#define PKTCSETFLAGS(skb, f) BCM_REFERENCE(skb) -#define PKTCCLRFLAGS(skb) BCM_REFERENCE(skb) -#define PKTCFLAGS(skb) (0) -#define PKTCSETCNT(skb, c) BCM_REFERENCE(skb) -#define PKTCINCRCNT(skb) BCM_REFERENCE(skb) -#define PKTCADDCNT(skb, c) BCM_REFERENCE(skb) -#define PKTCSETLEN(skb, l) BCM_REFERENCE(skb) -#define PKTCADDLEN(skb, l) BCM_REFERENCE(skb) -#define PKTCSETFLAG(skb, fb) BCM_REFERENCE(skb) -#define PKTCCLRFLAG(skb, fb) BCM_REFERENCE(skb) -#define PKTCLINK(skb) NULL -#define PKTSETCLINK(skb, x) BCM_REFERENCE(skb) -#define FOREACH_CHAINED_PKT(skb, nskb) \ - for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) -#define PKTCFREE PKTFREE -#define PKTCENQTAIL(h, t, p) \ -do { \ - if ((t) == NULL) { \ - (h) = (t) = (p); \ - } \ -} while (0) -#endif /* !linux || !PKTC */ - -#if !defined(HNDCTF) && !defined(PKTC_TX_DONGLE) -#define PKTSETCHAINED(osh, skb) BCM_REFERENCE(osh) -#define PKTCLRCHAINED(osh, skb) BCM_REFERENCE(osh) -#define PKTISCHAINED(skb) FALSE -#endif - -/* Lbuf with fraglist */ -#define PKTFRAGPKTID(osh, lb) (0) -#define PKTSETFRAGPKTID(osh, lb, id) BCM_REFERENCE(osh) -#define PKTFRAGTOTNUM(osh, lb) (0) -#define PKTSETFRAGTOTNUM(osh, lb, tot) BCM_REFERENCE(osh) -#define PKTFRAGTOTLEN(osh, lb) (0) -#define PKTSETFRAGTOTLEN(osh, lb, len) BCM_REFERENCE(osh) -#define PKTIFINDEX(osh, lb) (0) -#define PKTSETIFINDEX(osh, lb, idx) BCM_REFERENCE(osh) -#define PKTGETLF(osh, len, send, lbuf_type) (0) - -/* in rx path, reuse totlen as used len */ -#define PKTFRAGUSEDLEN(osh, lb) (0) -#define PKTSETFRAGUSEDLEN(osh, lb, len) BCM_REFERENCE(osh) - -#define PKTFRAGLEN(osh, lb, ix) (0) -#define PKTSETFRAGLEN(osh, lb, ix, len) BCM_REFERENCE(osh) -#define PKTFRAGDATA_LO(osh, lb, ix) (0) -#define PKTSETFRAGDATA_LO(osh, lb, ix, addr) BCM_REFERENCE(osh) -#define PKTFRAGDATA_HI(osh, lb, ix) (0) -#define PKTSETFRAGDATA_HI(osh, lb, ix, addr) BCM_REFERENCE(osh) - -/* RX FRAG */ -#define PKTISRXFRAG(osh, lb) (0) -#define PKTSETRXFRAG(osh, lb) BCM_REFERENCE(osh) -#define PKTRESETRXFRAG(osh, lb) BCM_REFERENCE(osh) - -/* TX FRAG */ -#define PKTISTXFRAG(osh, lb) (0) -#define PKTSETTXFRAG(osh, lb) BCM_REFERENCE(osh) - -/* Need Rx completion used for AMPDU reordering */ -#define PKTNEEDRXCPL(osh, lb) (TRUE) -#define PKTSETNORXCPL(osh, lb) BCM_REFERENCE(osh) -#define PKTRESETNORXCPL(osh, lb) BCM_REFERENCE(osh) - -#define PKTISFRAG(osh, lb) (0) -#define PKTFRAGISCHAINED(osh, i) (0) -/* TRIM Tail bytes from lfrag */ -#define PKTFRAG_TRIM_TAILBYTES(osh, p, len) PKTSETLEN(osh, p, PKTLEN(osh, p) - len) - -#endif /* _osl_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/osl_decl.h b/drivers/net/wireless/bcmdhd/include/osl_decl.h deleted file mode 100644 index 04f44a5fea93..000000000000 --- a/drivers/net/wireless/bcmdhd/include/osl_decl.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * osl forward declarations - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id$ - */ - -#ifndef _osl_decl_h_ -#define _osl_decl_h_ - -/* osl handle type forward declaration */ -typedef struct osl_info osl_t; -typedef struct osl_dmainfo osldma_t; -extern unsigned int lmtest; /* low memory test */ -#endif diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/bcmdhd/include/packed_section_end.h deleted file mode 100644 index d4fde86ec6c4..000000000000 --- a/drivers/net/wireless/bcmdhd/include/packed_section_end.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Declare directives for structure packing. No padding will be provided - * between the members of packed structures, and therefore, there is no - * guarantee that structure members will be aligned. - * - * Declaring packed structures is compiler specific. In order to handle all - * cases, packed structures should be delared as: - * - * #include - * - * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { - * some_struct_members; - * } BWL_POST_PACKED_STRUCT foobar_t; - * - * #include - * - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: packed_section_end.h 437241 2013-11-18 07:39:24Z $ - */ - - -/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h - * and undefined in packed_section_end.h. If it is NOT defined at this - * point, then there is a missing include of packed_section_start.h. - */ -#ifdef BWL_PACKED_SECTION - #undef BWL_PACKED_SECTION -#else - #error "BWL_PACKED_SECTION is NOT defined!" -#endif - - - - -/* Compiler-specific directives for structure packing are declared in - * packed_section_start.h. This marks the end of the structure packing section, - * so, undef them here. - */ -#undef BWL_PRE_PACKED_STRUCT -#undef BWL_POST_PACKED_STRUCT diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/bcmdhd/include/packed_section_start.h deleted file mode 100644 index e77fe1477ecf..000000000000 --- a/drivers/net/wireless/bcmdhd/include/packed_section_start.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Declare directives for structure packing. No padding will be provided - * between the members of packed structures, and therefore, there is no - * guarantee that structure members will be aligned. - * - * Declaring packed structures is compiler specific. In order to handle all - * cases, packed structures should be delared as: - * - * #include - * - * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { - * some_struct_members; - * } BWL_POST_PACKED_STRUCT foobar_t; - * - * #include - * - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: packed_section_start.h 437241 2013-11-18 07:39:24Z $ - */ - - -/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h - * and undefined in packed_section_end.h. If it is already defined at this - * point, then there is a missing include of packed_section_end.h. - */ -#ifdef BWL_PACKED_SECTION - #error "BWL_PACKED_SECTION is already defined!" -#else - #define BWL_PACKED_SECTION -#endif - - - - -/* Declare compiler-specific directives for structure packing. */ -#if defined(__GNUC__) || defined(__lint) - #define BWL_PRE_PACKED_STRUCT - #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) -#elif defined(__CC_ARM) - #define BWL_PRE_PACKED_STRUCT __packed - #define BWL_POST_PACKED_STRUCT -#else - #error "Unknown compiler!" -#endif diff --git a/drivers/net/wireless/bcmdhd/include/pcicfg.h b/drivers/net/wireless/bcmdhd/include/pcicfg.h deleted file mode 100644 index 5fae554da755..000000000000 --- a/drivers/net/wireless/bcmdhd/include/pcicfg.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - * pcicfg.h: PCI configuration constants and structures. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: pcicfg.h 506084 2014-10-02 15:34:59Z $ - */ - -#ifndef _h_pcicfg_ -#define _h_pcicfg_ - - -/* pci config status reg has a bit to indicate that capability ptr is present */ - -#define PCI_CAPPTR_PRESENT 0x0010 - -/* A structure for the config registers is nice, but in most - * systems the config space is not memory mapped, so we need - * field offsetts. :-( - */ -#define PCI_CFG_VID 0 -#define PCI_CFG_DID 2 -#define PCI_CFG_CMD 4 -#define PCI_CFG_STAT 6 -#define PCI_CFG_REV 8 -#define PCI_CFG_PROGIF 9 -#define PCI_CFG_SUBCL 0xa -#define PCI_CFG_BASECL 0xb -#define PCI_CFG_CLSZ 0xc -#define PCI_CFG_LATTIM 0xd -#define PCI_CFG_HDR 0xe -#define PCI_CFG_BIST 0xf -#define PCI_CFG_BAR0 0x10 -#define PCI_CFG_BAR1 0x14 -#define PCI_CFG_BAR2 0x18 -#define PCI_CFG_BAR3 0x1c -#define PCI_CFG_BAR4 0x20 -#define PCI_CFG_BAR5 0x24 -#define PCI_CFG_CIS 0x28 -#define PCI_CFG_SVID 0x2c -#define PCI_CFG_SSID 0x2e -#define PCI_CFG_ROMBAR 0x30 -#define PCI_CFG_CAPPTR 0x34 -#define PCI_CFG_INT 0x3c -#define PCI_CFG_PIN 0x3d -#define PCI_CFG_MINGNT 0x3e -#define PCI_CFG_MAXLAT 0x3f -#define PCI_CFG_DEVCTRL 0xd8 - - -/* PCI CAPABILITY DEFINES */ -#define PCI_CAP_POWERMGMTCAP_ID 0x01 -#define PCI_CAP_MSICAP_ID 0x05 -#define PCI_CAP_VENDSPEC_ID 0x09 -#define PCI_CAP_PCIECAP_ID 0x10 - -/* Data structure to define the Message Signalled Interrupt facility - * Valid for PCI and PCIE configurations - */ -typedef struct _pciconfig_cap_msi { - uint8 capID; - uint8 nextptr; - uint16 msgctrl; - uint32 msgaddr; -} pciconfig_cap_msi; -#define MSI_ENABLE 0x1 /* bit 0 of msgctrl */ - -/* Data structure to define the Power managment facility - * Valid for PCI and PCIE configurations - */ -typedef struct _pciconfig_cap_pwrmgmt { - uint8 capID; - uint8 nextptr; - uint16 pme_cap; - uint16 pme_sts_ctrl; - uint8 pme_bridge_ext; - uint8 data; -} pciconfig_cap_pwrmgmt; - -#define PME_CAP_PM_STATES (0x1f << 27) /* Bits 31:27 states that can generate PME */ -#define PME_CSR_OFFSET 0x4 /* 4-bytes offset */ -#define PME_CSR_PME_EN (1 << 8) /* Bit 8 Enable generating of PME */ -#define PME_CSR_PME_STAT (1 << 15) /* Bit 15 PME got asserted */ - -/* Data structure to define the PCIE capability */ -typedef struct _pciconfig_cap_pcie { - uint8 capID; - uint8 nextptr; - uint16 pcie_cap; - uint32 dev_cap; - uint16 dev_ctrl; - uint16 dev_status; - uint32 link_cap; - uint16 link_ctrl; - uint16 link_status; - uint32 slot_cap; - uint16 slot_ctrl; - uint16 slot_status; - uint16 root_ctrl; - uint16 root_cap; - uint32 root_status; -} pciconfig_cap_pcie; - -/* PCIE Enhanced CAPABILITY DEFINES */ -#define PCIE_EXTCFG_OFFSET 0x100 -#define PCIE_ADVERRREP_CAPID 0x0001 -#define PCIE_VC_CAPID 0x0002 -#define PCIE_DEVSNUM_CAPID 0x0003 -#define PCIE_PWRBUDGET_CAPID 0x0004 - -/* PCIE Extended configuration */ -#define PCIE_ADV_CORR_ERR_MASK 0x114 -#define CORR_ERR_RE (1 << 0) /* Receiver */ -#define CORR_ERR_BT (1 << 6) /* Bad TLP */ -#define CORR_ERR_BD (1 << 7) /* Bad DLLP */ -#define CORR_ERR_RR (1 << 8) /* REPLAY_NUM rollover */ -#define CORR_ERR_RT (1 << 12) /* Reply timer timeout */ -#define ALL_CORR_ERRORS (CORR_ERR_RE | CORR_ERR_BT | CORR_ERR_BD | \ - CORR_ERR_RR | CORR_ERR_RT) - -/* PCIE Root Control Register bits (Host mode only) */ -#define PCIE_RC_CORR_SERR_EN 0x0001 -#define PCIE_RC_NONFATAL_SERR_EN 0x0002 -#define PCIE_RC_FATAL_SERR_EN 0x0004 -#define PCIE_RC_PME_INT_EN 0x0008 -#define PCIE_RC_CRS_EN 0x0010 - -/* PCIE Root Capability Register bits (Host mode only) */ -#define PCIE_RC_CRS_VISIBILITY 0x0001 - -/* Header to define the PCIE specific capabilities in the extended config space */ -typedef struct _pcie_enhanced_caphdr { - uint16 capID; - uint16 cap_ver : 4; - uint16 next_ptr : 12; -} pcie_enhanced_caphdr; - - -#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */ -#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */ -#define PCI_SPROM_CONTROL 0x88 /* sprom property control */ -#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */ -#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */ -#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */ -#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */ -#define PCI_BACKPLANE_ADDR 0xa0 /* address an arbitrary location on the system backplane */ -#define PCI_BACKPLANE_DATA 0xa4 /* data at the location specified by above address */ -#define PCI_CLK_CTL_ST 0xa8 /* pci config space clock control/status (>=rev14) */ -#define PCI_BAR0_WIN2 0xac /* backplane addres space accessed by second 4KB of BAR0 */ -#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */ -#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */ -#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */ -#define PCI_LINK_CTRL 0xbc /* PCI link control register */ -#define PCI_DEV_STAT_CTRL2 0xd4 /* PCI device status control 2 register */ -#define PCIE_LTR_MAX_SNOOP 0x1b4 /* PCIE LTRMaxSnoopLatency */ -#define PCI_L1SS_CTRL 0x248 /* The L1 PM Substates Control register */ -#define PCI_L1SS_CTRL2 0x24c /* The L1 PM Substates Control 2 register */ - -/* Private Registers */ -#define PCI_STAT_CTRL 0xa80 -#define PCI_L0_EVENTCNT 0xa84 -#define PCI_L0_STATETMR 0xa88 -#define PCI_L1_EVENTCNT 0xa8c -#define PCI_L1_STATETMR 0xa90 -#define PCI_L1_1_EVENTCNT 0xa94 -#define PCI_L1_1_STATETMR 0xa98 -#define PCI_L1_2_EVENTCNT 0xa9c -#define PCI_L1_2_STATETMR 0xaa0 -#define PCI_L2_EVENTCNT 0xaa4 -#define PCI_L2_STATETMR 0xaa8 - -#define PCI_PMCR_REFUP 0x1814 /* Trefup time */ -#define PCI_PMCR_REFUP_EXT 0x1818 /* Trefup extend Max */ -#define PCI_TPOWER_SCALE_MASK 0x3 -#define PCI_TPOWER_SCALE_SHIFT 3 /* 0:1 is scale and 2 is rsvd */ - - -#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) /* bar0 + 2K accesses sprom shadow (in pci core) */ -#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */ -#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */ -#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) /* pci core SB registers are at the end of the - * 8KB window, so their address is the "regular" - * address plus 4K - */ -/* - * PCIE GEN2 changed some of the above locations for - * Bar0WrapperBase, SecondaryBAR0Window and SecondaryBAR0WrapperBase - * BAR0 maps 32K of register space -*/ -#define PCIE2_BAR0_WIN2 0x70 /* backplane addres space accessed by second 4KB of BAR0 */ -#define PCIE2_BAR0_CORE2_WIN 0x74 /* backplane addres space accessed by second 4KB of BAR0 */ -#define PCIE2_BAR0_CORE2_WIN2 0x78 /* backplane addres space accessed by second 4KB of BAR0 */ - -#define PCI_BAR0_WINSZ (16 * 1024) /* bar0 window size Match with corerev 13 */ -/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ -#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) /* bar0 + 8K accesses pci/pcie core registers */ -#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) /* bar0 + 12K accesses chipc core registers */ -#define PCI_16KBB0_WINSZ (16 * 1024) /* bar0 window size */ - - -/* Header types */ -#define PCI_HEADER_MULTI 0x80 -#define PCI_HEADER_MASK 0x7f -typedef enum { - PCI_HEADER_NORMAL, - PCI_HEADER_BRIDGE, - PCI_HEADER_CARDBUS -} pci_header_types; - -#define PCI_CONFIG_SPACE_SIZE 256 - -#define DWORD_ALIGN(x) (x & ~(0x03)) -#define BYTE_POS(x) (x & 0x3) -#define WORD_POS(x) (x & 0x1) - -#define BYTE_SHIFT(x) (8 * BYTE_POS(x)) -#define WORD_SHIFT(x) (16 * WORD_POS(x)) - -#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF) -#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF) - -#define read_pci_cfg_byte(a) \ - (BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff) - -#define read_pci_cfg_word(a) \ - (WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff) - -#define write_pci_cfg_byte(a, val) do { \ - uint32 tmpval; \ - tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \ - val << BYTE_POS(a); \ - OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \ - } while (0) - -#define write_pci_cfg_word(a, val) do { \ - uint32 tmpval; \ - tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \ - val << WORD_POS(a); \ - OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \ - } while (0) - -#endif /* _h_pcicfg_ */ diff --git a/drivers/net/wireless/bcmdhd/include/pcie_core.h b/drivers/net/wireless/bcmdhd/include/pcie_core.h deleted file mode 100644 index 68ffac32dcae..000000000000 --- a/drivers/net/wireless/bcmdhd/include/pcie_core.h +++ /dev/null @@ -1,642 +0,0 @@ -/* - * BCM43XX PCIE core hardware definitions. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: pcie_core.h 483003 2014-06-05 19:57:46Z $ - */ -#ifndef _PCIE_CORE_H -#define _PCIE_CORE_H - -#include -#include - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif - -/* PCIE Enumeration space offsets */ -#define PCIE_CORE_CONFIG_OFFSET 0x0 -#define PCIE_FUNC0_CONFIG_OFFSET 0x400 -#define PCIE_FUNC1_CONFIG_OFFSET 0x500 -#define PCIE_FUNC2_CONFIG_OFFSET 0x600 -#define PCIE_FUNC3_CONFIG_OFFSET 0x700 -#define PCIE_SPROM_SHADOW_OFFSET 0x800 -#define PCIE_SBCONFIG_OFFSET 0xE00 - - -#define PCIEDEV_MAX_DMAS 4 - -/* PCIE Bar0 Address Mapping. Each function maps 16KB config space */ -#define PCIE_DEV_BAR0_SIZE 0x4000 -#define PCIE_BAR0_WINMAPCORE_OFFSET 0x0 -#define PCIE_BAR0_EXTSPROM_OFFSET 0x1000 -#define PCIE_BAR0_PCIECORE_OFFSET 0x2000 -#define PCIE_BAR0_CCCOREREG_OFFSET 0x3000 - -/* different register spaces to access thr'u pcie indirect access */ -#define PCIE_CONFIGREGS 1 /* Access to config space */ -#define PCIE_PCIEREGS 2 /* Access to pcie registers */ - -/* dma regs to control the flow between host2dev and dev2host */ -typedef struct pcie_devdmaregs { - dma64regs_t tx; - uint32 PAD[2]; - dma64regs_t rx; - uint32 PAD[2]; -} pcie_devdmaregs_t; - -#define PCIE_DB_HOST2DEV_0 0x1 -#define PCIE_DB_HOST2DEV_1 0x2 -#define PCIE_DB_DEV2HOST_0 0x3 -#define PCIE_DB_DEV2HOST_1 0x4 - -/* door bell register sets */ -typedef struct pcie_doorbell { - uint32 host2dev_0; - uint32 host2dev_1; - uint32 dev2host_0; - uint32 dev2host_1; -} pcie_doorbell_t; - -/* SB side: PCIE core and host control registers */ -typedef struct sbpcieregs { - uint32 control; /* host mode only */ - uint32 iocstatus; /* PCIE2: iostatus */ - uint32 PAD[1]; - uint32 biststatus; /* bist Status: 0x00C */ - uint32 gpiosel; /* PCIE gpio sel: 0x010 */ - uint32 gpioouten; /* PCIE gpio outen: 0x14 */ - uint32 PAD[2]; - uint32 intstatus; /* Interrupt status: 0x20 */ - uint32 intmask; /* Interrupt mask: 0x24 */ - uint32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */ - uint32 obffcontrol; /* PCIE2: 0x2C */ - uint32 obffintstatus; /* PCIE2: 0x30 */ - uint32 obffdatastatus; /* PCIE2: 0x34 */ - uint32 PAD[2]; - uint32 errlog; /* PCIE2: 0x40 */ - uint32 errlogaddr; /* PCIE2: 0x44 */ - uint32 mailboxint; /* PCIE2: 0x48 */ - uint32 mailboxintmsk; /* PCIE2: 0x4c */ - uint32 ltrspacing; /* PCIE2: 0x50 */ - uint32 ltrhysteresiscnt; /* PCIE2: 0x54 */ - uint32 PAD[42]; - - uint32 sbtopcie0; /* sb to pcie translation 0: 0x100 */ - uint32 sbtopcie1; /* sb to pcie translation 1: 0x104 */ - uint32 sbtopcie2; /* sb to pcie translation 2: 0x108 */ - uint32 PAD[5]; - - /* pcie core supports in direct access to config space */ - uint32 configaddr; /* pcie config space access: Address field: 0x120 */ - uint32 configdata; /* pcie config space access: Data field: 0x124 */ - union { - struct { - /* mdio access to serdes */ - uint32 mdiocontrol; /* controls the mdio access: 0x128 */ - uint32 mdiodata; /* Data to the mdio access: 0x12c */ - /* pcie protocol phy/dllp/tlp register indirect access mechanism */ - uint32 pcieindaddr; /* indirect access to the internal register: 0x130 */ - uint32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */ - uint32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */ - uint32 PAD[177]; - } pcie1; - struct { - /* mdio access to serdes */ - uint32 mdiocontrol; /* controls the mdio access: 0x128 */ - uint32 mdiowrdata; /* write data to mdio 0x12C */ - uint32 mdiorddata; /* read data to mdio 0x130 */ - uint32 PAD[3]; /* 0x134-0x138-0x13c */ - /* door bell registers available from gen2 rev5 onwards */ - pcie_doorbell_t dbls[PCIEDEV_MAX_DMAS]; /* 0x140 - 0x17F */ - uint32 dataintf; /* 0x180 */ - uint32 PAD[1]; /* 0x184 */ - uint32 d2h_intrlazy_0; /* 0x188 */ - uint32 h2d_intrlazy_0; /* 0x18c */ - uint32 h2d_intstat_0; /* 0x190 */ - uint32 h2d_intmask_0; /* 0x194 */ - uint32 d2h_intstat_0; /* 0x198 */ - uint32 d2h_intmask_0; /* 0x19c */ - uint32 ltr_state; /* 0x1A0 */ - uint32 pwr_int_status; /* 0x1A4 */ - uint32 pwr_int_mask; /* 0x1A8 */ - uint32 PAD[21]; /* 0x1AC - 0x200 */ - pcie_devdmaregs_t h2d0_dmaregs; /* 0x200 - 0x23c */ - pcie_devdmaregs_t d2h0_dmaregs; /* 0x240 - 0x27c */ - pcie_devdmaregs_t h2d1_dmaregs; /* 0x280 - 0x2bc */ - pcie_devdmaregs_t d2h1_dmaregs; /* 0x2c0 - 0x2fc */ - pcie_devdmaregs_t h2d2_dmaregs; /* 0x300 - 0x33c */ - pcie_devdmaregs_t d2h2_dmaregs; /* 0x340 - 0x37c */ - pcie_devdmaregs_t h2d3_dmaregs; /* 0x380 - 0x3bc */ - pcie_devdmaregs_t d2h3_dmaregs; /* 0x3c0 - 0x3fc */ - } pcie2; - } u; - uint32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */ - uint16 sprom[64]; /* SPROM shadow Area */ -} sbpcieregs_t; - -/* PCI control */ -#define PCIE_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */ -#define PCIE_RST 0x02 /* Value driven out to pin */ -#define PCIE_SPERST 0x04 /* SurvivePeRst */ -#define PCIE_DISABLE_L1CLK_GATING 0x10 -#define PCIE_DLYPERST 0x100 /* Delay PeRst to CoE Core */ -#define PCIE_DISSPROMLD 0x200 /* DisableSpromLoadOnPerst */ -#define PCIE_WakeModeL2 0x1000 /* Wake on L2 */ - -#define PCIE_CFGADDR 0x120 /* offsetof(configaddr) */ -#define PCIE_CFGDATA 0x124 /* offsetof(configdata) */ - -/* Interrupt status/mask */ -#define PCIE_INTA 0x01 /* PCIE INTA message is received */ -#define PCIE_INTB 0x02 /* PCIE INTB message is received */ -#define PCIE_INTFATAL 0x04 /* PCIE INTFATAL message is received */ -#define PCIE_INTNFATAL 0x08 /* PCIE INTNONFATAL message is received */ -#define PCIE_INTCORR 0x10 /* PCIE INTCORR message is received */ -#define PCIE_INTPME 0x20 /* PCIE INTPME message is received */ -#define PCIE_PERST 0x40 /* PCIE Reset Interrupt */ - -#define PCIE_INT_MB_FN0_0 0x0100 /* PCIE to SB Mailbox int Fn0.0 is received */ -#define PCIE_INT_MB_FN0_1 0x0200 /* PCIE to SB Mailbox int Fn0.1 is received */ -#define PCIE_INT_MB_FN1_0 0x0400 /* PCIE to SB Mailbox int Fn1.0 is received */ -#define PCIE_INT_MB_FN1_1 0x0800 /* PCIE to SB Mailbox int Fn1.1 is received */ -#define PCIE_INT_MB_FN2_0 0x1000 /* PCIE to SB Mailbox int Fn2.0 is received */ -#define PCIE_INT_MB_FN2_1 0x2000 /* PCIE to SB Mailbox int Fn2.1 is received */ -#define PCIE_INT_MB_FN3_0 0x4000 /* PCIE to SB Mailbox int Fn3.0 is received */ -#define PCIE_INT_MB_FN3_1 0x8000 /* PCIE to SB Mailbox int Fn3.1 is received */ - -/* PCIE MailboxInt/MailboxIntMask register */ -#define PCIE_MB_TOSB_FN0_0 0x0001 /* write to assert PCIEtoSB Mailbox interrupt */ -#define PCIE_MB_TOSB_FN0_1 0x0002 -#define PCIE_MB_TOSB_FN1_0 0x0004 -#define PCIE_MB_TOSB_FN1_1 0x0008 -#define PCIE_MB_TOSB_FN2_0 0x0010 -#define PCIE_MB_TOSB_FN2_1 0x0020 -#define PCIE_MB_TOSB_FN3_0 0x0040 -#define PCIE_MB_TOSB_FN3_1 0x0080 -#define PCIE_MB_TOPCIE_FN0_0 0x0100 /* int status/mask for SBtoPCIE Mailbox interrupts */ -#define PCIE_MB_TOPCIE_FN0_1 0x0200 -#define PCIE_MB_TOPCIE_FN1_0 0x0400 -#define PCIE_MB_TOPCIE_FN1_1 0x0800 -#define PCIE_MB_TOPCIE_FN2_0 0x1000 -#define PCIE_MB_TOPCIE_FN2_1 0x2000 -#define PCIE_MB_TOPCIE_FN3_0 0x4000 -#define PCIE_MB_TOPCIE_FN3_1 0x8000 -#define PCIE_MB_TOPCIE_D2H0_DB0 0x10000 -#define PCIE_MB_TOPCIE_D2H0_DB1 0x20000 -#define PCIE_MB_TOPCIE_D2H1_DB0 0x40000 -#define PCIE_MB_TOPCIE_D2H1_DB1 0x80000 -#define PCIE_MB_TOPCIE_D2H2_DB0 0x100000 -#define PCIE_MB_TOPCIE_D2H2_DB1 0x200000 -#define PCIE_MB_TOPCIE_D2H3_DB0 0x400000 -#define PCIE_MB_TOPCIE_D2H3_DB1 0x800000 - -#define PCIE_MB_D2H_MB_MASK \ - (PCIE_MB_TOPCIE_D2H0_DB0 | PCIE_MB_TOPCIE_D2H0_DB1 | \ - PCIE_MB_TOPCIE_D2H1_DB1 | PCIE_MB_TOPCIE_D2H1_DB1 | \ - PCIE_MB_TOPCIE_D2H2_DB1 | PCIE_MB_TOPCIE_D2H2_DB1 | \ - PCIE_MB_TOPCIE_D2H3_DB1 | PCIE_MB_TOPCIE_D2H3_DB1) - -/* SB to PCIE translation masks */ -#define SBTOPCIE0_MASK 0xfc000000 -#define SBTOPCIE1_MASK 0xfc000000 -#define SBTOPCIE2_MASK 0xc0000000 - -/* Access type bits (0:1) */ -#define SBTOPCIE_MEM 0 -#define SBTOPCIE_IO 1 -#define SBTOPCIE_CFG0 2 -#define SBTOPCIE_CFG1 3 - -/* Prefetch enable bit 2 */ -#define SBTOPCIE_PF 4 - -/* Write Burst enable for memory write bit 3 */ -#define SBTOPCIE_WR_BURST 8 - -/* config access */ -#define CONFIGADDR_FUNC_MASK 0x7000 -#define CONFIGADDR_FUNC_SHF 12 -#define CONFIGADDR_REG_MASK 0x0FFF -#define CONFIGADDR_REG_SHF 0 - -#define PCIE_CONFIG_INDADDR(f, r) ((((f) & CONFIGADDR_FUNC_MASK) << CONFIGADDR_FUNC_SHF) | \ - (((r) & CONFIGADDR_REG_MASK) << CONFIGADDR_REG_SHF)) - -/* PCIE protocol regs Indirect Address */ -#define PCIEADDR_PROT_MASK 0x300 -#define PCIEADDR_PROT_SHF 8 -#define PCIEADDR_PL_TLP 0 -#define PCIEADDR_PL_DLLP 1 -#define PCIEADDR_PL_PLP 2 - -/* PCIE protocol PHY diagnostic registers */ -#define PCIE_PLP_MODEREG 0x200 /* Mode */ -#define PCIE_PLP_STATUSREG 0x204 /* Status */ -#define PCIE_PLP_LTSSMCTRLREG 0x208 /* LTSSM control */ -#define PCIE_PLP_LTLINKNUMREG 0x20c /* Link Training Link number */ -#define PCIE_PLP_LTLANENUMREG 0x210 /* Link Training Lane number */ -#define PCIE_PLP_LTNFTSREG 0x214 /* Link Training N_FTS */ -#define PCIE_PLP_ATTNREG 0x218 /* Attention */ -#define PCIE_PLP_ATTNMASKREG 0x21C /* Attention Mask */ -#define PCIE_PLP_RXERRCTR 0x220 /* Rx Error */ -#define PCIE_PLP_RXFRMERRCTR 0x224 /* Rx Framing Error */ -#define PCIE_PLP_RXERRTHRESHREG 0x228 /* Rx Error threshold */ -#define PCIE_PLP_TESTCTRLREG 0x22C /* Test Control reg */ -#define PCIE_PLP_SERDESCTRLOVRDREG 0x230 /* SERDES Control Override */ -#define PCIE_PLP_TIMINGOVRDREG 0x234 /* Timing param override */ -#define PCIE_PLP_RXTXSMDIAGREG 0x238 /* RXTX State Machine Diag */ -#define PCIE_PLP_LTSSMDIAGREG 0x23C /* LTSSM State Machine Diag */ - -/* PCIE protocol DLLP diagnostic registers */ -#define PCIE_DLLP_LCREG 0x100 /* Link Control */ -#define PCIE_DLLP_LSREG 0x104 /* Link Status */ -#define PCIE_DLLP_LAREG 0x108 /* Link Attention */ -#define PCIE_DLLP_LAMASKREG 0x10C /* Link Attention Mask */ -#define PCIE_DLLP_NEXTTXSEQNUMREG 0x110 /* Next Tx Seq Num */ -#define PCIE_DLLP_ACKEDTXSEQNUMREG 0x114 /* Acked Tx Seq Num */ -#define PCIE_DLLP_PURGEDTXSEQNUMREG 0x118 /* Purged Tx Seq Num */ -#define PCIE_DLLP_RXSEQNUMREG 0x11C /* Rx Sequence Number */ -#define PCIE_DLLP_LRREG 0x120 /* Link Replay */ -#define PCIE_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */ -#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */ -#define PCIE_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */ -#define PCIE_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */ -#define PCIE_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */ -#define PCIE_DLLP_RTRRWREG 0x138 /* Retry buffer Read/Write */ -#define PCIE_DLLP_ECTHRESHREG 0x13C /* Error Count Threshold */ -#define PCIE_DLLP_TLPERRCTRREG 0x140 /* TLP Error Counter */ -#define PCIE_DLLP_ERRCTRREG 0x144 /* Error Counter */ -#define PCIE_DLLP_NAKRXCTRREG 0x148 /* NAK Received Counter */ -#define PCIE_DLLP_TESTREG 0x14C /* Test */ -#define PCIE_DLLP_PKTBIST 0x150 /* Packet BIST */ -#define PCIE_DLLP_PCIE11 0x154 /* DLLP PCIE 1.1 reg */ - -#define PCIE_DLLP_LSREG_LINKUP (1 << 16) - -/* PCIE protocol TLP diagnostic registers */ -#define PCIE_TLP_CONFIGREG 0x000 /* Configuration */ -#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */ -#define PCIE_TLP_WRDMAUPPER 0x010 /* Write DMA Upper Address */ -#define PCIE_TLP_WRDMALOWER 0x014 /* Write DMA Lower Address */ -#define PCIE_TLP_WRDMAREQ_LBEREG 0x018 /* Write DMA Len/ByteEn Req */ -#define PCIE_TLP_RDDMAUPPER 0x01C /* Read DMA Upper Address */ -#define PCIE_TLP_RDDMALOWER 0x020 /* Read DMA Lower Address */ -#define PCIE_TLP_RDDMALENREG 0x024 /* Read DMA Len Req */ -#define PCIE_TLP_MSIDMAUPPER 0x028 /* MSI DMA Upper Address */ -#define PCIE_TLP_MSIDMALOWER 0x02C /* MSI DMA Lower Address */ -#define PCIE_TLP_MSIDMALENREG 0x030 /* MSI DMA Len Req */ -#define PCIE_TLP_SLVREQLENREG 0x034 /* Slave Request Len */ -#define PCIE_TLP_FCINPUTSREQ 0x038 /* Flow Control Inputs */ -#define PCIE_TLP_TXSMGRSREQ 0x03C /* Tx StateMachine and Gated Req */ -#define PCIE_TLP_ADRACKCNTARBLEN 0x040 /* Address Ack XferCnt and ARB Len */ -#define PCIE_TLP_DMACPLHDR0 0x044 /* DMA Completion Hdr 0 */ -#define PCIE_TLP_DMACPLHDR1 0x048 /* DMA Completion Hdr 1 */ -#define PCIE_TLP_DMACPLHDR2 0x04C /* DMA Completion Hdr 2 */ -#define PCIE_TLP_DMACPLMISC0 0x050 /* DMA Completion Misc0 */ -#define PCIE_TLP_DMACPLMISC1 0x054 /* DMA Completion Misc1 */ -#define PCIE_TLP_DMACPLMISC2 0x058 /* DMA Completion Misc2 */ -#define PCIE_TLP_SPTCTRLLEN 0x05C /* Split Controller Req len */ -#define PCIE_TLP_SPTCTRLMSIC0 0x060 /* Split Controller Misc 0 */ -#define PCIE_TLP_SPTCTRLMSIC1 0x064 /* Split Controller Misc 1 */ -#define PCIE_TLP_BUSDEVFUNC 0x068 /* Bus/Device/Func */ -#define PCIE_TLP_RESETCTR 0x06C /* Reset Counter */ -#define PCIE_TLP_RTRYBUF 0x070 /* Retry Buffer value */ -#define PCIE_TLP_TGTDEBUG1 0x074 /* Target Debug Reg1 */ -#define PCIE_TLP_TGTDEBUG2 0x078 /* Target Debug Reg2 */ -#define PCIE_TLP_TGTDEBUG3 0x07C /* Target Debug Reg3 */ -#define PCIE_TLP_TGTDEBUG4 0x080 /* Target Debug Reg4 */ - -/* PCIE2 MDIO register offsets */ -#define PCIE2_MDIO_CONTROL 0x128 -#define PCIE2_MDIO_WR_DATA 0x12C -#define PCIE2_MDIO_RD_DATA 0x130 - - -/* 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 /* Tranaction complete */ - -/* MDIO Data */ -#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */ -#define MDIODATA_TA 0x00020000 /* Turnaround */ -#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift (rev < 10) */ -#define MDIODATA_REGADDR_MASK_OLD 0x003c0000 /* Regaddr Mask (rev < 10) */ -#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift (rev < 10) */ -#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000 /* Physmedia devaddr Mask (rev < 10) */ -#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 */ -#define MDIODATA_WRITE 0x10000000 /* write Transaction */ -#define MDIODATA_READ 0x20000000 /* Read Transaction */ -#define MDIODATA_START 0x40000000 /* start of Transaction */ - -#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */ -#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */ - -/* MDIO control/wrData/rdData register defines for PCIE Gen 2 */ -#define MDIOCTL2_DIVISOR_MASK 0x7f /* clock to be used on MDIO */ -#define MDIOCTL2_DIVISOR_VAL 0x2 -#define MDIOCTL2_REGADDR_SHF 8 /* Regaddr shift */ -#define MDIOCTL2_REGADDR_MASK 0x00FFFF00 /* Regaddr Mask */ -#define MDIOCTL2_DEVADDR_SHF 24 /* Physmedia devaddr shift */ -#define MDIOCTL2_DEVADDR_MASK 0x0f000000 /* Physmedia devaddr Mask */ -#define MDIOCTL2_SLAVE_BYPASS 0x10000000 /* IP slave bypass */ -#define MDIOCTL2_READ 0x20000000 /* IP slave bypass */ - -#define MDIODATA2_DONE 0x80000000 /* rd/wr transaction done */ -#define MDIODATA2_MASK 0x7FFFFFFF /* rd/wr transaction data */ -#define MDIODATA2_DEVADDR_SHF 4 /* Physmedia devaddr shift */ - - -/* MDIO devices (SERDES modules) - * unlike old pcie cores (rev < 10), rev10 pcie serde organizes registers into a few blocks. - * two layers mapping (blockidx, register offset) is required - */ -#define MDIO_DEV_IEEE0 0x000 -#define MDIO_DEV_IEEE1 0x001 -#define MDIO_DEV_BLK0 0x800 -#define MDIO_DEV_BLK1 0x801 -#define MDIO_DEV_BLK2 0x802 -#define MDIO_DEV_BLK3 0x803 -#define MDIO_DEV_BLK4 0x804 -#define MDIO_DEV_TXPLL 0x808 /* TXPLL register block idx */ -#define MDIO_DEV_TXCTRL0 0x820 -#define MDIO_DEV_SERDESID 0x831 -#define MDIO_DEV_RXCTRL0 0x840 - - -/* XgxsBlk1_A Register Offsets */ -#define BLK1_PWR_MGMT0 0x16 -#define BLK1_PWR_MGMT1 0x17 -#define BLK1_PWR_MGMT2 0x18 -#define BLK1_PWR_MGMT3 0x19 -#define BLK1_PWR_MGMT4 0x1A - -/* 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 */ - -/* Power management threshold */ -#define PCIE_L0THRESHOLDTIME_MASK 0xFF00 /* bits 0 - 7 */ -#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 */ - -/* 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_OFFSET_REV8 52 /* word 52 for srom rev 8 */ -#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */ -#define SRSH_BD_OFFSET 6 /* word 6 */ -#define SRSH_AUTOINIT_OFFSET 18 /* auto initialization enable */ - -/* Linkcontrol reg offset in PCIE Cap */ -#define PCIE_CAP_LINKCTRL_OFFSET 16 /* linkctrl 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_LINKSPEED_MASK 0xF0000 /* bits 0 - 3 of high word */ -#define PCIE_LINKSPEED_SHIFT 16 /* PCIE_LINKSPEED_SHIFT */ - -/* Devcontrol reg offset in PCIE Cap */ -#define PCIE_CAP_DEVCTRL_OFFSET 8 /* devctrl offset in pcie cap */ -#define PCIE_CAP_DEVCTRL_MRRS_MASK 0x7000 /* Max read request size mask */ -#define PCIE_CAP_DEVCTRL_MRRS_SHIFT 12 /* Max read request size shift */ -#define PCIE_CAP_DEVCTRL_MRRS_128B 0 /* 128 Byte */ -#define PCIE_CAP_DEVCTRL_MRRS_256B 1 /* 256 Byte */ -#define PCIE_CAP_DEVCTRL_MRRS_512B 2 /* 512 Byte */ -#define PCIE_CAP_DEVCTRL_MRRS_1024B 3 /* 1024 Byte */ -#define PCIE_CAP_DEVCTRL_MPS_MASK 0x00e0 /* Max payload size mask */ -#define PCIE_CAP_DEVCTRL_MPS_SHIFT 5 /* Max payload size shift */ -#define PCIE_CAP_DEVCTRL_MPS_128B 0 /* 128 Byte */ -#define PCIE_CAP_DEVCTRL_MPS_256B 1 /* 256 Byte */ -#define PCIE_CAP_DEVCTRL_MPS_512B 2 /* 512 Byte */ -#define PCIE_CAP_DEVCTRL_MPS_1024B 3 /* 1024 Byte */ - -#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 */ - -#define PCIE_ASPM_L11_ENAB 8 /* ASPM L1.1 in PML1_sub_control2 */ -#define PCIE_ASPM_L12_ENAB 4 /* ASPM L1.2 in PML1_sub_control2 */ - -/* Devcontrol2 reg offset in PCIE Cap */ -#define PCIE_CAP_DEVCTRL2_OFFSET 0x28 /* devctrl2 offset in pcie cap */ -#define PCIE_CAP_DEVCTRL2_LTR_ENAB_MASK 0x400 /* Latency Tolerance Reporting Enable */ -#define PCIE_CAP_DEVCTRL2_OBFF_ENAB_SHIFT 13 /* Enable OBFF mechanism, select signaling method */ -#define PCIE_CAP_DEVCTRL2_OBFF_ENAB_MASK 0x6000 /* Enable OBFF mechanism, select signaling method */ - -/* LTR registers in PCIE Cap */ -#define PCIE_LTR0_REG_OFFSET 0x844 /* ltr0_reg offset in pcie cap */ -#define PCIE_LTR1_REG_OFFSET 0x848 /* ltr1_reg offset in pcie cap */ -#define PCIE_LTR2_REG_OFFSET 0x84c /* ltr2_reg offset in pcie cap */ -#define PCIE_LTR0_REG_DEFAULT_60 0x883c883c /* active latency default to 60usec */ -#define PCIE_LTR0_REG_DEFAULT_150 0x88968896 /* active latency default to 150usec */ -#define PCIE_LTR1_REG_DEFAULT 0x88648864 /* idle latency default to 100usec */ -#define PCIE_LTR2_REG_DEFAULT 0x90039003 /* sleep latency default to 3msec */ - -/* Status reg PCIE_PLP_STATUSREG */ -#define PCIE_PLP_POLARITYINV_STAT 0x10 - - -/* PCIE BRCM Vendor CAP REVID reg bits */ -#define BRCMCAP_PCIEREV_CT_MASK 0xF00 -#define BRCMCAP_PCIEREV_CT_SHIFT 8 -#define BRCMCAP_PCIEREV_REVID_MASK 0xFF -#define BRCMCAP_PCIEREV_REVID_SHIFT 0 - -#define PCIE_REVREG_CT_PCIE1 0 -#define PCIE_REVREG_CT_PCIE2 1 - -/* PCIE GEN2 specific defines */ -/* PCIE BRCM Vendor Cap offsets w.r.t to vendor cap ptr */ -#define PCIE2R0_BRCMCAP_REVID_OFFSET 4 -#define PCIE2R0_BRCMCAP_BAR0_WIN0_WRAP_OFFSET 8 -#define PCIE2R0_BRCMCAP_BAR0_WIN2_OFFSET 12 -#define PCIE2R0_BRCMCAP_BAR0_WIN2_WRAP_OFFSET 16 -#define PCIE2R0_BRCMCAP_BAR0_WIN_OFFSET 20 -#define PCIE2R0_BRCMCAP_BAR1_WIN_OFFSET 24 -#define PCIE2R0_BRCMCAP_SPROM_CTRL_OFFSET 28 -#define PCIE2R0_BRCMCAP_BAR2_WIN_OFFSET 32 -#define PCIE2R0_BRCMCAP_INTSTATUS_OFFSET 36 -#define PCIE2R0_BRCMCAP_INTMASK_OFFSET 40 -#define PCIE2R0_BRCMCAP_PCIE2SB_MB_OFFSET 44 -#define PCIE2R0_BRCMCAP_BPADDR_OFFSET 48 -#define PCIE2R0_BRCMCAP_BPDATA_OFFSET 52 -#define PCIE2R0_BRCMCAP_CLKCTLSTS_OFFSET 56 - -/* definition of configuration space registers of PCIe gen2 - * http://hwnbu-twiki.sj.broadcom.com/twiki/pub/Mwgroup/CurrentPcieGen2ProgramGuide/pcie_ep.htm - */ -#define PCIECFGREG_STATUS_CMD 0x4 -#define PCIECFGREG_PM_CSR 0x4C -#define PCIECFGREG_MSI_CAP 0x58 -#define PCIECFGREG_MSI_ADDR_L 0x5C -#define PCIECFGREG_MSI_ADDR_H 0x60 -#define PCIECFGREG_MSI_DATA 0x64 -#define PCIECFGREG_LINK_STATUS_CTRL 0xBC -#define PCIECFGREG_LINK_STATUS_CTRL2 0xDC -#define PCIECFGREG_RBAR_CTRL 0x228 -#define PCIECFGREG_PML1_SUB_CTRL1 0x248 -#define PCIECFGREG_REG_BAR2_CONFIG 0x4E0 -#define PCIECFGREG_REG_BAR3_CONFIG 0x4F4 -#define PCIECFGREG_PDL_CTRL1 0x1004 -#define PCIECFGREG_PDL_IDDQ 0x1814 -#define PCIECFGREG_REG_PHY_CTL7 0x181c - -/* PCIECFGREG_PML1_SUB_CTRL1 Bit Definition */ -#define PCI_PM_L1_2_ENA_MASK 0x00000001 /* PCI-PM L1.2 Enabled */ -#define PCI_PM_L1_1_ENA_MASK 0x00000002 /* PCI-PM L1.1 Enabled */ -#define ASPM_L1_2_ENA_MASK 0x00000004 /* ASPM L1.2 Enabled */ -#define ASPM_L1_1_ENA_MASK 0x00000008 /* ASPM L1.1 Enabled */ - -/* PCIe gen2 mailbox interrupt masks */ -#define I_MB 0x3 -#define I_BIT0 0x1 -#define I_BIT1 0x2 - -/* PCIE gen2 config regs */ -#define PCIIntstatus 0x090 -#define PCIIntmask 0x094 -#define PCISBMbx 0x98 - -/* enumeration Core regs */ -#define PCIH2D_MailBox 0x140 -#define PCIH2D_DB1 0x144 -#define PCID2H_MailBox 0x148 -#define PCIMailBoxInt 0x48 -#define PCIMailBoxMask 0x4C - -#define I_F0_B0 (0x1 << 8) /* Mail box interrupt Function 0 interrupt, bit 0 */ -#define I_F0_B1 (0x1 << 9) /* Mail box interrupt Function 0 interrupt, bit 1 */ - -#define PCIECFGREG_DEVCONTROL 0xB4 - -/* SROM hardware region */ -#define SROM_OFFSET_BAR1_CTRL 52 - -#define BAR1_ENC_SIZE_MASK 0x000e -#define BAR1_ENC_SIZE_SHIFT 1 - -#define BAR1_ENC_SIZE_1M 0 -#define BAR1_ENC_SIZE_2M 1 -#define BAR1_ENC_SIZE_4M 2 - -#define PCIEGEN2_CAP_DEVSTSCTRL2_OFFSET 0xD4 -#define PCIEGEN2_CAP_DEVSTSCTRL2_LTRENAB 0x400 - -/* - * Latency Tolerance Reporting (LTR) states - * Active has the least tolerant latency requirement - * Sleep is most tolerant - */ -#define LTR_ACTIVE 2 -#define LTR_ACTIVE_IDLE 1 -#define LTR_SLEEP 0 -#define LTR_FINAL_MASK 0x300 -#define LTR_FINAL_SHIFT 8 - -/* pwrinstatus, pwrintmask regs */ -#define PCIEGEN2_PWRINT_D0_STATE_SHIFT 0 -#define PCIEGEN2_PWRINT_D1_STATE_SHIFT 1 -#define PCIEGEN2_PWRINT_D2_STATE_SHIFT 2 -#define PCIEGEN2_PWRINT_D3_STATE_SHIFT 3 -#define PCIEGEN2_PWRINT_L0_LINK_SHIFT 4 -#define PCIEGEN2_PWRINT_L0s_LINK_SHIFT 5 -#define PCIEGEN2_PWRINT_L1_LINK_SHIFT 6 -#define PCIEGEN2_PWRINT_L2_L3_LINK_SHIFT 7 -#define PCIEGEN2_PWRINT_OBFF_CHANGE_SHIFT 8 - -#define PCIEGEN2_PWRINT_D0_STATE_MASK (1 << PCIEGEN2_PWRINT_D0_STATE_SHIFT) -#define PCIEGEN2_PWRINT_D1_STATE_MASK (1 << PCIEGEN2_PWRINT_D1_STATE_SHIFT) -#define PCIEGEN2_PWRINT_D2_STATE_MASK (1 << PCIEGEN2_PWRINT_D2_STATE_SHIFT) -#define PCIEGEN2_PWRINT_D3_STATE_MASK (1 << PCIEGEN2_PWRINT_D3_STATE_SHIFT) -#define PCIEGEN2_PWRINT_L0_LINK_MASK (1 << PCIEGEN2_PWRINT_L0_LINK_SHIFT) -#define PCIEGEN2_PWRINT_L0s_LINK_MASK (1 << PCIEGEN2_PWRINT_L0s_LINK_SHIFT) -#define PCIEGEN2_PWRINT_L1_LINK_MASK (1 << PCIEGEN2_PWRINT_L1_LINK_SHIFT) -#define PCIEGEN2_PWRINT_L2_L3_LINK_MASK (1 << PCIEGEN2_PWRINT_L2_L3_LINK_SHIFT) -#define PCIEGEN2_PWRINT_OBFF_CHANGE_MASK (1 << PCIEGEN2_PWRINT_OBFF_CHANGE_SHIFT) - -/* sbtopcie mail box */ -#define SBTOPCIE_MB_FUNC0_SHIFT 8 -#define SBTOPCIE_MB_FUNC1_SHIFT 10 -#define SBTOPCIE_MB_FUNC2_SHIFT 12 -#define SBTOPCIE_MB_FUNC3_SHIFT 14 - -/* pcieiocstatus */ -#define PCIEGEN2_IOC_D0_STATE_SHIFT 8 -#define PCIEGEN2_IOC_D1_STATE_SHIFT 9 -#define PCIEGEN2_IOC_D2_STATE_SHIFT 10 -#define PCIEGEN2_IOC_D3_STATE_SHIFT 11 -#define PCIEGEN2_IOC_L0_LINK_SHIFT 12 -#define PCIEGEN2_IOC_L1_LINK_SHIFT 13 -#define PCIEGEN2_IOC_L1L2_LINK_SHIFT 14 -#define PCIEGEN2_IOC_L2_L3_LINK_SHIFT 15 - -#define PCIEGEN2_IOC_D0_STATE_MASK (1 << PCIEGEN2_IOC_D0_STATE_SHIFT) -#define PCIEGEN2_IOC_D1_STATE_MASK (1 << PCIEGEN2_IOC_D1_STATE_SHIF) -#define PCIEGEN2_IOC_D2_STATE_MASK (1 << PCIEGEN2_IOC_D2_STATE_SHIF) -#define PCIEGEN2_IOC_D3_STATE_MASK (1 << PCIEGEN2_IOC_D3_STATE_SHIF) -#define PCIEGEN2_IOC_L0_LINK_MASK (1 << PCIEGEN2_IOC_L0_LINK_SHIF) -#define PCIEGEN2_IOC_L1_LINK_MASK (1 << PCIEGEN2_IOC_L1_LINK_SHIF) -#define PCIEGEN2_IOC_L1L2_LINK_MASK (1 << PCIEGEN2_IOC_L1L2_LINK_SHIFT) -#define PCIEGEN2_IOC_L2_L3_LINK_MASK (1 << PCIEGEN2_IOC_L2_L3_LINK_SHIFT) - -/* stat_ctrl */ -#define PCIE_STAT_CTRL_RESET 0x1 -#define PCIE_STAT_CTRL_ENABLE 0x2 -#define PCIE_STAT_CTRL_INTENABLE 0x4 -#define PCIE_STAT_CTRL_INTSTATUS 0x8 - -#ifdef BCMDRIVER -void pcie_watchdog_reset(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs); -#endif /* BCMDRIVER */ - -#endif /* _PCIE_CORE_H */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h deleted file mode 100644 index b446a6dd2617..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11.h +++ /dev/null @@ -1,3853 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental types and constants relating to 802.11 - * - * $Id: 802.11.h 495738 2014-08-08 03:36:17Z $ - */ - -#ifndef _802_11_H_ -#define _802_11_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -#ifndef _NET_ETHERNET_H_ -#include -#endif - -#include - -/* This marks the start of a packed structure section. */ -#include - - -#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */ - -/* Generic 802.11 frame constants */ -#define DOT11_A3_HDR_LEN 24 /* d11 header length with A3 */ -#define DOT11_A4_HDR_LEN 30 /* d11 header length with A4 */ -#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN /* MAC header length */ -#define DOT11_FCS_LEN 4 /* d11 FCS length */ -#define DOT11_ICV_LEN 4 /* d11 ICV length */ -#define DOT11_ICV_AES_LEN 8 /* d11 ICV/AES length */ -#define DOT11_QOS_LEN 2 /* d11 QoS length */ -#define DOT11_HTC_LEN 4 /* d11 HT Control field length */ - -#define DOT11_KEY_INDEX_SHIFT 6 /* d11 key index shift */ -#define DOT11_IV_LEN 4 /* d11 IV length */ -#define DOT11_IV_TKIP_LEN 8 /* d11 IV TKIP length */ -#define DOT11_IV_AES_OCB_LEN 4 /* d11 IV/AES/OCB length */ -#define DOT11_IV_AES_CCM_LEN 8 /* d11 IV/AES/CCM length */ -#define DOT11_IV_MAX_LEN 8 /* maximum iv len for any encryption */ - -/* Includes MIC */ -#define DOT11_MAX_MPDU_BODY_LEN 2304 /* max MPDU body length */ -/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */ -#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ - DOT11_QOS_LEN + \ - DOT11_IV_AES_CCM_LEN + \ - DOT11_MAX_MPDU_BODY_LEN + \ - DOT11_ICV_LEN + \ - DOT11_FCS_LEN) /* d11 max MPDU length */ - -#define DOT11_MAX_SSID_LEN 32 /* d11 max ssid length */ - -/* dot11RTSThreshold */ -#define DOT11_DEFAULT_RTS_LEN 2347 /* d11 default RTS length */ -#define DOT11_MAX_RTS_LEN 2347 /* d11 max RTS length */ - -/* dot11FragmentationThreshold */ -#define DOT11_MIN_FRAG_LEN 256 /* d11 min fragmentation length */ -#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength - * of the attached PHY - */ -#define DOT11_DEFAULT_FRAG_LEN 2346 /* d11 default fragmentation length */ - -/* dot11BeaconPeriod */ -#define DOT11_MIN_BEACON_PERIOD 1 /* d11 min beacon period */ -#define DOT11_MAX_BEACON_PERIOD 0xFFFF /* d11 max beacon period */ - -/* dot11DTIMPeriod */ -#define DOT11_MIN_DTIM_PERIOD 1 /* d11 min DTIM period */ -#define DOT11_MAX_DTIM_PERIOD 0xFF /* d11 max DTIM period */ - -/** 802.2 LLC/SNAP header used by 802.11 per 802.1H */ -#define DOT11_LLC_SNAP_HDR_LEN 8 /* d11 LLC/SNAP header length */ -#define DOT11_OUI_LEN 3 /* d11 OUI length */ -BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { - uint8 dsap; /* always 0xAA */ - uint8 ssap; /* always 0xAA */ - uint8 ctl; /* always 0x03 */ - uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 - * Bridge-Tunnel: 0x00 0x00 0xF8 - */ - uint16 type; /* ethertype */ -} BWL_POST_PACKED_STRUCT; - -/* RFC1042 header used by 802.11 per 802.1H */ -#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) /* RCF1042 header length */ - -/* Generic 802.11 MAC header */ -/** - * N.B.: This struct reflects the full 4 address 802.11 MAC header. - * The fields are defined such that the shorter 1, 2, and 3 - * address headers just use the first k fields. - */ -BWL_PRE_PACKED_STRUCT struct dot11_header { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr a1; /* address 1 */ - struct ether_addr a2; /* address 2 */ - struct ether_addr a3; /* address 3 */ - uint16 seq; /* sequence control */ - struct ether_addr a4; /* address 4 */ -} BWL_POST_PACKED_STRUCT; - -/* Control frames */ - -BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ - struct ether_addr ta; /* transmitter address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_RTS_LEN 16 /* d11 RTS frame length */ - -BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_CTS_LEN 10 /* d11 CTS frame length */ - -BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_ACK_LEN 10 /* d11 ACK frame length */ - -BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { - uint16 fc; /* frame control */ - uint16 durid; /* AID */ - struct ether_addr bssid; /* receiver address, STA in AP */ - struct ether_addr ta; /* transmitter address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_PS_POLL_LEN 16 /* d11 PS poll frame length */ - -BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ - struct ether_addr bssid; /* transmitter address, STA in AP */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */ - -/** - * RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling - * category+OUI+vendor specific content ( this can be variable) - */ -BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { - uint8 category; - uint8 OUI[3]; - uint8 type; - uint8 subtype; - uint8 data[1040]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; - -/** generic vendor specific action frame with variable length */ -BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { - uint8 category; - uint8 OUI[3]; - uint8 type; - uint8 subtype; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; - -#define DOT11_ACTION_VS_HDR_LEN 6 - -#define BCM_ACTION_OUI_BYTE0 0x00 -#define BCM_ACTION_OUI_BYTE1 0x90 -#define BCM_ACTION_OUI_BYTE2 0x4c - -/* BA/BAR Control parameters */ -#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */ -#define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */ -#define DOT11_BA_CTL_POLICY_MASK 0x0001 /* ack policy mask */ - -#define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */ -#define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */ - -#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */ -#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */ - -#define DOT11_BA_CTL_TID_MASK 0xF000 /* tid mask */ -#define DOT11_BA_CTL_TID_SHIFT 12 /* tid shift */ - -/** control frame header (BA/BAR) */ -BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ - struct ether_addr ta; /* transmitter address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */ - -/** BAR frame payload */ -BWL_PRE_PACKED_STRUCT struct dot11_bar { - uint16 bar_control; /* BAR Control */ - uint16 seqnum; /* Starting Sequence control */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_BAR_LEN 4 /* BAR frame payload length */ - -#define DOT11_BA_BITMAP_LEN 128 /* bitmap length */ -#define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */ -/** BA frame payload */ -BWL_PRE_PACKED_STRUCT struct dot11_ba { - uint16 ba_control; /* BA Control */ - uint16 seqnum; /* Starting Sequence control */ - uint8 bitmap[DOT11_BA_BITMAP_LEN]; /* Block Ack Bitmap */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_BA_LEN 4 /* BA frame payload len (wo bitmap) */ - -/** Management frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_management_header { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr da; /* receiver address */ - struct ether_addr sa; /* transmitter address */ - struct ether_addr bssid; /* BSS ID */ - uint16 seq; /* sequence control */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_MGMT_HDR_LEN 24 /* d11 management header length */ - -/* Management frame payloads */ - -BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { - uint32 timestamp[2]; - uint16 beacon_interval; - uint16 capability; -} BWL_POST_PACKED_STRUCT; -#define DOT11_BCN_PRB_LEN 12 /* 802.11 beacon/probe frame fixed length */ -#define DOT11_BCN_PRB_FIXED_LEN 12 /* 802.11 beacon/probe frame fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_auth { - uint16 alg; /* algorithm */ - uint16 seq; /* sequence control */ - uint16 status; /* status code */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge IE */ - -BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { - uint16 capability; /* capability information */ - uint16 listen; /* listen interval */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_ASSOC_REQ_FIXED_LEN 4 /* length of assoc frame without info elts */ - -BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { - uint16 capability; /* capability information */ - uint16 listen; /* listen interval */ - struct ether_addr ap; /* Current AP address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_REASSOC_REQ_FIXED_LEN 10 /* length of assoc frame without info elts */ - -BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { - uint16 capability; /* capability information */ - uint16 status; /* status code */ - uint16 aid; /* association ID */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_ASSOC_RESP_FIXED_LEN 6 /* length of assoc resp frame without info elts */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_measure { - uint8 category; - uint8 action; - uint8 token; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -#define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { - uint8 category; - uint8 action; - uint8 ch_width; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { - uint8 category; - uint8 action; - uint8 control; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { - uint8 category; - uint8 action; - uint16 id; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { - uint8 category; - uint8 action; - uint8 mode; -} BWL_POST_PACKED_STRUCT; - -#define SM_PWRSAVE_ENABLE 1 -#define SM_PWRSAVE_MODE 2 - -/* ************* 802.11h related definitions. ************* */ -BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { - uint8 id; - uint8 len; - uint8 power; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_power_cnst dot11_power_cnst_t; - -BWL_PRE_PACKED_STRUCT struct dot11_power_cap { - int8 min; - int8 max; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_power_cap dot11_power_cap_t; - -BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { - uint8 id; - uint8 len; - uint8 tx_pwr; - uint8 margin; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tpc_rep dot11_tpc_rep_t; -#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */ - -BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { - uint8 id; - uint8 len; - uint8 first_channel; - uint8 num_channels; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_supp_channels dot11_supp_channels_t; - -/** - * Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband - * offset for 40MHz operation. The possible 3 values are: - * 1 = above control channel - * 3 = below control channel - * 0 = no extension channel - */ -BWL_PRE_PACKED_STRUCT struct dot11_extch { - uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ - uint8 len; /* IE length */ - uint8 extch; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_extch dot11_extch_ie_t; - -BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; - uint8 type; /* type indicates what follows */ - uint8 extch; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; - -#define BRCM_EXTCH_IE_LEN 5 -#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ -#define DOT11_EXTCH_IE_LEN 1 -#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ -#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ -#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ -#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { - uint8 category; - uint8 action; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -#define DOT11_ACTION_FRMHDR_LEN 2 - -/** CSA IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { - uint8 id; /* id DOT11_MNG_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - uint8 mode; /* mode 0 or 1 */ - uint8 channel; /* channel switch to */ - uint8 count; /* number of beacons before switching */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_channel_switch dot11_chan_switch_ie_t; - -#define DOT11_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ -/* CSA mode - 802.11h-2003 $7.3.2.20 */ -#define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */ -#define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { - uint8 category; - uint8 action; - dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */ - dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */ -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_csa_body { - uint8 mode; /* mode 0 or 1 */ - uint8 reg; /* regulatory class */ - uint8 channel; /* channel switch to */ - uint8 count; /* number of beacons before switching */ -} BWL_POST_PACKED_STRUCT; - -/** 11n Extended Channel Switch IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { - uint8 id; /* id DOT11_MNG_EXT_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - struct dot11_csa_body b; /* body of the ie */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ext_csa dot11_ext_csa_ie_t; -#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { - uint8 category; - uint8 action; - dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { - uint8 category; - uint8 action; - struct dot11_csa_body b; /* body of the ie */ -} BWL_POST_PACKED_STRUCT; - -/** Wide Bandwidth Channel Switch IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - uint8 channel_width; /* new channel width */ - uint8 center_frequency_segment_0; /* center frequency segment 0 */ - uint8 center_frequency_segment_1; /* center frequency segment 1 */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; - -#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ - -/** Channel Switch Wrapper IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; - -/** VHT Transmit Power Envelope IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - uint8 transmit_power_info; - uint8 local_max_transmit_power_20; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; - -/* vht transmit power envelope IE length depends on channel width */ -#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_40MHZ 1 -#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_80MHZ 2 -#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_160MHZ 3 - -BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { - uint8 id; - uint8 len; - uint8 info; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_obss_coex dot11_obss_coex_t; -#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */ - -#define DOT11_OBSS_COEX_INFO_REQ 0x01 -#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 -#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 - -BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { - uint8 id; - uint8 len; - uint8 regclass; - uint8 chanlist[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; -#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */ - -BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { - uint8 id; - uint8 len; - uint8 cap[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_extcap_ie dot11_extcap_ie_t; - -#define DOT11_EXTCAP_LEN_MAX 8 - -#define DOT11_EXTCAP_LEN_COEX 1 -#define DOT11_EXTCAP_LEN_BT 3 -#define DOT11_EXTCAP_LEN_IW 4 -#define DOT11_EXTCAP_LEN_SI 6 - -#define DOT11_EXTCAP_LEN_TDLS 5 -#define DOT11_11AC_EXTCAP_LEN_TDLS 8 - -#define DOT11_EXTCAP_LEN_FMS 2 -#define DOT11_EXTCAP_LEN_PROXY_ARP 2 -#define DOT11_EXTCAP_LEN_TFS 3 -#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 -#define DOT11_EXTCAP_LEN_TIMBC 3 -#define DOT11_EXTCAP_LEN_BSSTRANS 3 -#define DOT11_EXTCAP_LEN_DMS 4 -#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 -#define DOT11_EXTCAP_LEN_TDLS_WBW 8 -#define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8 - -BWL_PRE_PACKED_STRUCT struct dot11_extcap { - uint8 extcap[DOT11_EXTCAP_LEN_MAX]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_extcap dot11_extcap_t; - -/* TDLS Capabilities */ -#define DOT11_TDLS_CAP_TDLS 37 /* TDLS support */ -#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ -#define DOT11_TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ -#define DOT11_TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ -#define DOT11_TDLS_CAP_PROH 38 /* TDLS prohibited */ -#define DOT11_TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ -#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 /* TDLS Wider Band-Width */ - -#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ - -/* 802.11h/802.11k Measurement Request/Report IEs */ -/* Measurement Type field */ -#define DOT11_MEASURE_TYPE_BASIC 0 /* d11 measurement basic type */ -#define DOT11_MEASURE_TYPE_CCA 1 /* d11 measurement CCA type */ -#define DOT11_MEASURE_TYPE_RPI 2 /* d11 measurement RPI type */ -#define DOT11_MEASURE_TYPE_CHLOAD 3 /* d11 measurement Channel Load type */ -#define DOT11_MEASURE_TYPE_NOISE 4 /* d11 measurement Noise Histogram type */ -#define DOT11_MEASURE_TYPE_BEACON 5 /* d11 measurement Beacon type */ -#define DOT11_MEASURE_TYPE_FRAME 6 /* d11 measurement Frame type */ -#define DOT11_MEASURE_TYPE_STAT 7 /* d11 measurement STA Statistics type */ -#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ -#define DOT11_MEASURE_TYPE_TXSTREAM 9 /* d11 measurement TX Stream type */ -#define DOT11_MEASURE_TYPE_PAUSE 255 /* d11 measurement pause type */ - -/* Measurement Request Modes */ -#define DOT11_MEASURE_MODE_PARALLEL (1<<0) /* d11 measurement parallel */ -#define DOT11_MEASURE_MODE_ENABLE (1<<1) /* d11 measurement enable */ -#define DOT11_MEASURE_MODE_REQUEST (1<<2) /* d11 measurement request */ -#define DOT11_MEASURE_MODE_REPORT (1<<3) /* d11 measurement report */ -#define DOT11_MEASURE_MODE_DUR (1<<4) /* d11 measurement dur mandatory */ -/* Measurement Report Modes */ -#define DOT11_MEASURE_MODE_LATE (1<<0) /* d11 measurement late */ -#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) /* d11 measurement incapable */ -#define DOT11_MEASURE_MODE_REFUSED (1<<2) /* d11 measurement refuse */ -/* Basic Measurement Map bits */ -#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) /* d11 measurement basic map BSS */ -#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) /* d11 measurement map OFDM */ -#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) /* d11 measurement map unknown */ -#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) /* d11 measurement map radar */ -#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) /* d11 measurement map unmeasuremnt */ - -BWL_PRE_PACKED_STRUCT struct dot11_meas_req { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 channel; - uint8 start_time[8]; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_meas_req dot11_meas_req_t; -#define DOT11_MNG_IE_MREQ_LEN 14 /* d11 measurement request IE length */ -/* length of Measure Request IE data not including variable len */ -#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 /* d11 measurement request IE fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - BWL_PRE_PACKED_STRUCT union - { - BWL_PRE_PACKED_STRUCT struct { - uint8 channel; - uint8 start_time[8]; - uint16 duration; - uint8 map; - } BWL_POST_PACKED_STRUCT basic; - uint8 data[1]; - } BWL_POST_PACKED_STRUCT rep; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_meas_rep dot11_meas_rep_t; - -/* length of Measure Report IE data not including variable len */ -#define DOT11_MNG_IE_MREP_FIXED_LEN 3 /* d11 measurement response IE fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { - uint8 channel; - uint8 start_time[8]; - uint16 duration; - uint8 map; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; -#define DOT11_MEASURE_BASIC_REP_LEN 12 /* d11 measurement basic report length */ - -BWL_PRE_PACKED_STRUCT struct dot11_quiet { - uint8 id; - uint8 len; - uint8 count; /* TBTTs until beacon interval in quiet starts */ - uint8 period; /* Beacon intervals between periodic quiet periods ? */ - uint16 duration; /* Length of quiet period, in TU's */ - uint16 offset; /* TU's offset from TBTT in Count field */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_quiet dot11_quiet_t; - -BWL_PRE_PACKED_STRUCT struct chan_map_tuple { - uint8 channel; - uint8 map; -} BWL_POST_PACKED_STRUCT; -typedef struct chan_map_tuple chan_map_tuple_t; - -BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { - uint8 id; - uint8 len; - uint8 eaddr[ETHER_ADDR_LEN]; - uint8 interval; - chan_map_tuple_t map[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; - -/* WME Elements */ -#define WME_OUI "\x00\x50\xf2" /* WME OUI */ -#define WME_OUI_LEN 3 -#define WME_OUI_TYPE 2 /* WME type */ -#define WME_TYPE 2 /* WME type, deprecated */ -#define WME_SUBTYPE_IE 0 /* Information Element */ -#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ -#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ -#define WME_VER 1 /* WME version */ - -/* WME Access Category Indices (ACIs) */ -#define AC_BE 0 /* Best Effort */ -#define AC_BK 1 /* Background */ -#define AC_VI 2 /* Video */ -#define AC_VO 3 /* Voice */ -#define AC_COUNT 4 /* number of ACs */ - -typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */ - -#define AC_BITMAP_NONE 0x0 /* No ACs */ -#define AC_BITMAP_ALL 0xf /* All ACs */ -#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) -#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) -#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) - -/** WME Information Element (IE) */ -BWL_PRE_PACKED_STRUCT struct wme_ie { - uint8 oui[3]; - uint8 type; - uint8 subtype; - uint8 version; - uint8 qosinfo; -} BWL_POST_PACKED_STRUCT; -typedef struct wme_ie wme_ie_t; -#define WME_IE_LEN 7 /* WME IE length */ - -BWL_PRE_PACKED_STRUCT struct edcf_acparam { - uint8 ACI; - uint8 ECW; - uint16 TXOP; /* stored in network order (ls octet first) */ -} BWL_POST_PACKED_STRUCT; -typedef struct edcf_acparam edcf_acparam_t; - -/** WME Parameter Element (PE) */ -BWL_PRE_PACKED_STRUCT struct wme_param_ie { - uint8 oui[3]; - uint8 type; - uint8 subtype; - uint8 version; - uint8 qosinfo; - uint8 rsvd; - edcf_acparam_t acparam[AC_COUNT]; -} BWL_POST_PACKED_STRUCT; -typedef struct wme_param_ie wme_param_ie_t; -#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ - -/* QoS Info field for IE as sent from AP */ -#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ -#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ -#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ -#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ - -/* QoS Info field for IE as sent from STA */ -#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ -#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ -#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ -#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ -#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ -#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ -#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ -#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ -#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ -#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ -#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ -#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ - -/* ACI */ -#define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */ -#define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */ -#define EDCF_AIFSN_MASK 0x0f /* AIFSN mask */ -#define EDCF_ACM_MASK 0x10 /* ACM mask */ -#define EDCF_ACI_MASK 0x60 /* ACI mask */ -#define EDCF_ACI_SHIFT 5 /* ACI shift */ -#define EDCF_AIFSN_SHIFT 12 /* 4 MSB(0xFFF) in ifs_ctl for AC idx */ - -/* ECW */ -#define EDCF_ECW_MIN 0 /* cwmin/cwmax exponent minimum value */ -#define EDCF_ECW_MAX 15 /* cwmin/cwmax exponent maximum value */ -#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) -#define EDCF_ECWMIN_MASK 0x0f /* cwmin exponent form mask */ -#define EDCF_ECWMAX_MASK 0xf0 /* cwmax exponent form mask */ -#define EDCF_ECWMAX_SHIFT 4 /* cwmax exponent form shift */ - -/* TXOP */ -#define EDCF_TXOP_MIN 0 /* TXOP minimum value */ -#define EDCF_TXOP_MAX 65535 /* TXOP maximum value */ -#define EDCF_TXOP2USEC(txop) ((txop) << 5) - -/* Default BE ACI value for non-WME connection STA */ -#define NON_EDCF_AC_BE_ACI_STA 0x02 - -/* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */ -#define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */ -#define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */ -#define EDCF_AC_BE_TXOP_STA 0x0000 /* STA TXOP value for best effort AC */ -#define EDCF_AC_BK_ACI_STA 0x27 /* STA ACI value for background AC */ -#define EDCF_AC_BK_ECW_STA 0xA4 /* STA ECW value for background AC */ -#define EDCF_AC_BK_TXOP_STA 0x0000 /* STA TXOP value for background AC */ -#define EDCF_AC_VI_ACI_STA 0x42 /* STA ACI value for video AC */ -#define EDCF_AC_VI_ECW_STA 0x43 /* STA ECW value for video AC */ -#define EDCF_AC_VI_TXOP_STA 0x005e /* STA TXOP value for video AC */ -#define EDCF_AC_VO_ACI_STA 0x62 /* STA ACI value for audio AC */ -#define EDCF_AC_VO_ECW_STA 0x32 /* STA ECW value for audio AC */ -#define EDCF_AC_VO_TXOP_STA 0x002f /* STA TXOP value for audio AC */ - -/* Default EDCF parameters that AP uses; WMM draft Table 14 */ -#define EDCF_AC_BE_ACI_AP 0x03 /* AP ACI value for best effort AC */ -#define EDCF_AC_BE_ECW_AP 0x64 /* AP ECW value for best effort AC */ -#define EDCF_AC_BE_TXOP_AP 0x0000 /* AP TXOP value for best effort AC */ -#define EDCF_AC_BK_ACI_AP 0x27 /* AP ACI value for background AC */ -#define EDCF_AC_BK_ECW_AP 0xA4 /* AP ECW value for background AC */ -#define EDCF_AC_BK_TXOP_AP 0x0000 /* AP TXOP value for background AC */ -#define EDCF_AC_VI_ACI_AP 0x41 /* AP ACI value for video AC */ -#define EDCF_AC_VI_ECW_AP 0x43 /* AP ECW value for video AC */ -#define EDCF_AC_VI_TXOP_AP 0x005e /* AP TXOP value for video AC */ -#define EDCF_AC_VO_ACI_AP 0x61 /* AP ACI value for audio AC */ -#define EDCF_AC_VO_ECW_AP 0x32 /* AP ECW value for audio AC */ -#define EDCF_AC_VO_TXOP_AP 0x002f /* AP TXOP value for audio AC */ - -/** EDCA Parameter IE */ -BWL_PRE_PACKED_STRUCT struct edca_param_ie { - uint8 qosinfo; - uint8 rsvd; - edcf_acparam_t acparam[AC_COUNT]; -} BWL_POST_PACKED_STRUCT; -typedef struct edca_param_ie edca_param_ie_t; -#define EDCA_PARAM_IE_LEN 18 /* EDCA Parameter IE length */ - -/** QoS Capability IE */ -BWL_PRE_PACKED_STRUCT struct qos_cap_ie { - uint8 qosinfo; -} BWL_POST_PACKED_STRUCT; -typedef struct qos_cap_ie qos_cap_ie_t; - -BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { - uint8 id; /* 11, DOT11_MNG_QBSS_LOAD_ID */ - uint8 length; - uint16 station_count; /* total number of STAs associated */ - uint8 channel_utilization; /* % of time, normalized to 255, QAP sensed medium busy */ - uint16 aac; /* available admission capacity */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; -#define BSS_LOAD_IE_SIZE 7 /* BSS load IE size */ - -#define WLC_QBSS_LOAD_CHAN_FREE_MAX 0xff /* max for channel free score */ - -/* nom_msdu_size */ -#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */ -#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */ - -/* surplus_bandwidth */ -/* Represented as 3 bits of integer, binary point, 13 bits fraction */ -#define INTEGER_SHIFT 13 /* integer shift */ -#define FRACTION_MASK 0x1FFF /* fraction mask */ - -/** Management Notification Frame */ -BWL_PRE_PACKED_STRUCT struct dot11_management_notification { - uint8 category; /* DOT11_ACTION_NOTIFICATION */ - uint8 action; - uint8 token; - uint8 status; - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */ - -/** Timeout Interval IE */ -BWL_PRE_PACKED_STRUCT struct ti_ie { - uint8 ti_type; - uint32 ti_val; -} BWL_POST_PACKED_STRUCT; -typedef struct ti_ie ti_ie_t; -#define TI_TYPE_REASSOC_DEADLINE 1 -#define TI_TYPE_KEY_LIFETIME 2 - -/* WME Action Codes */ -#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ -#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ -#define WME_DELTS_REQUEST 2 /* WME DELTS request */ - -/* WME Setup Response Status Codes */ -#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ -#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ -#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ - -/* Macro to take a pointer to a beacon or probe response - * body and return the char* pointer to the SSID info element - */ -#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) - -/* Authentication frame payload constants */ -#define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */ -#define DOT11_SHARED_KEY 1 /* d11 shared authentication */ -#define DOT11_FAST_BSS 2 /* d11 fast bss authentication */ -#define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */ - -/* Frame control macros */ -#define FC_PVER_MASK 0x3 /* PVER mask */ -#define FC_PVER_SHIFT 0 /* PVER shift */ -#define FC_TYPE_MASK 0xC /* type mask */ -#define FC_TYPE_SHIFT 2 /* type shift */ -#define FC_SUBTYPE_MASK 0xF0 /* subtype mask */ -#define FC_SUBTYPE_SHIFT 4 /* subtype shift */ -#define FC_TODS 0x100 /* to DS */ -#define FC_TODS_SHIFT 8 /* to DS shift */ -#define FC_FROMDS 0x200 /* from DS */ -#define FC_FROMDS_SHIFT 9 /* from DS shift */ -#define FC_MOREFRAG 0x400 /* more frag. */ -#define FC_MOREFRAG_SHIFT 10 /* more frag. shift */ -#define FC_RETRY 0x800 /* retry */ -#define FC_RETRY_SHIFT 11 /* retry shift */ -#define FC_PM 0x1000 /* PM */ -#define FC_PM_SHIFT 12 /* PM shift */ -#define FC_MOREDATA 0x2000 /* more data */ -#define FC_MOREDATA_SHIFT 13 /* more data shift */ -#define FC_WEP 0x4000 /* WEP */ -#define FC_WEP_SHIFT 14 /* WEP shift */ -#define FC_ORDER 0x8000 /* order */ -#define FC_ORDER_SHIFT 15 /* order shift */ - -/* sequence control macros */ -#define SEQNUM_SHIFT 4 /* seq. number shift */ -#define SEQNUM_MAX 0x1000 /* max seqnum + 1 */ -#define FRAGNUM_MASK 0xF /* frag. number mask */ - -/* Frame Control type/subtype defs */ - -/* FC Types */ -#define FC_TYPE_MNG 0 /* management type */ -#define FC_TYPE_CTL 1 /* control type */ -#define FC_TYPE_DATA 2 /* data type */ - -/* Management Subtypes */ -#define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */ -#define FC_SUBTYPE_ASSOC_RESP 1 /* assoc. response */ -#define FC_SUBTYPE_REASSOC_REQ 2 /* reassoc. request */ -#define FC_SUBTYPE_REASSOC_RESP 3 /* reassoc. response */ -#define FC_SUBTYPE_PROBE_REQ 4 /* probe request */ -#define FC_SUBTYPE_PROBE_RESP 5 /* probe response */ -#define FC_SUBTYPE_BEACON 8 /* beacon */ -#define FC_SUBTYPE_ATIM 9 /* ATIM */ -#define FC_SUBTYPE_DISASSOC 10 /* disassoc. */ -#define FC_SUBTYPE_AUTH 11 /* authentication */ -#define FC_SUBTYPE_DEAUTH 12 /* de-authentication */ -#define FC_SUBTYPE_ACTION 13 /* action */ -#define FC_SUBTYPE_ACTION_NOACK 14 /* action no-ack */ - -/* Control Subtypes */ -#define FC_SUBTYPE_CTL_WRAPPER 7 /* Control Wrapper */ -#define FC_SUBTYPE_BLOCKACK_REQ 8 /* Block Ack Req */ -#define FC_SUBTYPE_BLOCKACK 9 /* Block Ack */ -#define FC_SUBTYPE_PS_POLL 10 /* PS poll */ -#define FC_SUBTYPE_RTS 11 /* RTS */ -#define FC_SUBTYPE_CTS 12 /* CTS */ -#define FC_SUBTYPE_ACK 13 /* ACK */ -#define FC_SUBTYPE_CF_END 14 /* CF-END */ -#define FC_SUBTYPE_CF_END_ACK 15 /* CF-END ACK */ - -/* Data Subtypes */ -#define FC_SUBTYPE_DATA 0 /* Data */ -#define FC_SUBTYPE_DATA_CF_ACK 1 /* Data + CF-ACK */ -#define FC_SUBTYPE_DATA_CF_POLL 2 /* Data + CF-Poll */ -#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 /* Data + CF-Ack + CF-Poll */ -#define FC_SUBTYPE_NULL 4 /* Null */ -#define FC_SUBTYPE_CF_ACK 5 /* CF-Ack */ -#define FC_SUBTYPE_CF_POLL 6 /* CF-Poll */ -#define FC_SUBTYPE_CF_ACK_POLL 7 /* CF-Ack + CF-Poll */ -#define FC_SUBTYPE_QOS_DATA 8 /* QoS Data */ -#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 /* QoS Data + CF-Ack */ -#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 /* QoS Data + CF-Poll */ -#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 /* QoS Data + CF-Ack + CF-Poll */ -#define FC_SUBTYPE_QOS_NULL 12 /* QoS Null */ -#define FC_SUBTYPE_QOS_CF_POLL 14 /* QoS CF-Poll */ -#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 /* QoS CF-Ack + CF-Poll */ - -/* Data Subtype Groups */ -#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) -#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) -#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) -#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) -#define FC_SUBTYPE_ANY_PSPOLL(s) (((s) & 10) != 0) - -/* Type/Subtype Combos */ -#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */ - -#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) /* FC kind */ - -#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) /* Subtype from FC */ -#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) /* Type from FC */ - -#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) /* assoc. request */ -#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) /* assoc. response */ -#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) /* reassoc. request */ -#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) /* reassoc. response */ -#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) /* probe request */ -#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) /* probe response */ -#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) /* beacon */ -#define FC_ATIM FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ATIM) /* ATIM */ -#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) /* disassoc */ -#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) /* authentication */ -#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) /* deauthentication */ -#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) /* action */ -#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) /* action no-ack */ - -#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) /* Control Wrapper */ -#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) /* Block Ack Req */ -#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) /* Block Ack */ -#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) /* PS poll */ -#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) /* RTS */ -#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) /* CTS */ -#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) /* ACK */ -#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) /* CF-END */ -#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) /* CF-END ACK */ - -#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) /* data */ -#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) /* null data */ -#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) /* data CF ACK */ -#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) /* QoS data */ -#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) /* QoS null */ - -/* QoS Control Field */ - -/* 802.1D Priority */ -#define QOS_PRIO_SHIFT 0 /* QoS priority shift */ -#define QOS_PRIO_MASK 0x0007 /* QoS priority mask */ -#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) /* QoS priority */ - -/* Traffic Identifier */ -#define QOS_TID_SHIFT 0 /* QoS TID shift */ -#define QOS_TID_MASK 0x000f /* QoS TID mask */ -#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) /* QoS TID */ - -/* End of Service Period (U-APSD) */ -#define QOS_EOSP_SHIFT 4 /* QoS End of Service Period shift */ -#define QOS_EOSP_MASK 0x0010 /* QoS End of Service Period mask */ -#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) /* Qos EOSP */ - -/* Ack Policy */ -#define QOS_ACK_NORMAL_ACK 0 /* Normal Ack */ -#define QOS_ACK_NO_ACK 1 /* No Ack (eg mcast) */ -#define QOS_ACK_NO_EXP_ACK 2 /* No Explicit Ack */ -#define QOS_ACK_BLOCK_ACK 3 /* Block Ack */ -#define QOS_ACK_SHIFT 5 /* QoS ACK shift */ -#define QOS_ACK_MASK 0x0060 /* QoS ACK mask */ -#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) /* QoS ACK */ - -/* A-MSDU flag */ -#define QOS_AMSDU_SHIFT 7 /* AMSDU shift */ -#define QOS_AMSDU_MASK 0x0080 /* AMSDU mask */ - -/* Management Frames */ - -/* Management Frame Constants */ - -/* Fixed fields */ -#define DOT11_MNG_AUTH_ALGO_LEN 2 /* d11 management auth. algo. length */ -#define DOT11_MNG_AUTH_SEQ_LEN 2 /* d11 management auth. seq. length */ -#define DOT11_MNG_BEACON_INT_LEN 2 /* d11 management beacon interval length */ -#define DOT11_MNG_CAP_LEN 2 /* d11 management cap. length */ -#define DOT11_MNG_AP_ADDR_LEN 6 /* d11 management AP address length */ -#define DOT11_MNG_LISTEN_INT_LEN 2 /* d11 management listen interval length */ -#define DOT11_MNG_REASON_LEN 2 /* d11 management reason length */ -#define DOT11_MNG_AID_LEN 2 /* d11 management AID length */ -#define DOT11_MNG_STATUS_LEN 2 /* d11 management status length */ -#define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */ - -/* DUR/ID field in assoc resp is 0xc000 | AID */ -#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ - -/* Reason Codes */ -#define DOT11_RC_RESERVED 0 /* d11 RC reserved */ -#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */ -#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */ -#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station - * is leaving (or has left) IBSS or ESS - */ -#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */ -#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle - * all currently associated stations - */ -#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from - * nonauthenticated station - */ -#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from - * nonassociated station - */ -#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is - * leaving (or has left) BSS - */ -#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is not - * authenticated with responding station - */ -#define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */ -#define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */ -/* 12 is unused */ - -/* 32-39 are QSTA specific reasons added in 11e */ -#define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */ -#define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */ -#define DOT11_RC_EXCESSIVE_FRAMES 34 /* excessive number of frames need ack */ -#define DOT11_RC_TX_OUTSIDE_TXOP 35 /* transmitting outside the limits of txop */ -#define DOT11_RC_LEAVING_QBSS 36 /* QSTA is leaving the QBSS (or restting) */ -#define DOT11_RC_BAD_MECHANISM 37 /* does not want to use the mechanism */ -#define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */ -#define DOT11_RC_TIMEOUT 39 /* timeout */ - -#define DOT11_RC_MAX 23 /* Reason codes > 23 are reserved */ - -#define DOT11_RC_TDLS_PEER_UNREACH 25 -#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 - -/* Status Codes */ -#define DOT11_SC_SUCCESS 0 /* Successful */ -#define DOT11_SC_FAILURE 1 /* Unspecified failure */ -#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but alternative */ - /* schedule provided */ -#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */ -#define DOT11_SC_TDLS_SEC_DISABLED 5 /* TDLS Security disabled */ -#define DOT11_SC_LIFETIME_REJ 6 /* Unacceptable lifetime */ -#define DOT11_SC_NOT_SAME_BSS 7 /* Not in same BSS */ -#define DOT11_SC_CAP_MISMATCH 10 /* Cannot support all requested - * capabilities in the Capability - * Information field - */ -#define DOT11_SC_REASSOC_FAIL 11 /* Reassociation denied due to inability - * to confirm that association exists - */ -#define DOT11_SC_ASSOC_FAIL 12 /* Association denied due to reason - * outside the scope of this standard - */ -#define DOT11_SC_AUTH_MISMATCH 13 /* Responding station does not support - * the specified authentication - * algorithm - */ -#define DOT11_SC_AUTH_SEQ 14 /* Received an Authentication frame - * with authentication transaction - * sequence number out of expected - * sequence - */ -#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of - * challenge failure - */ -#define DOT11_SC_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout - * waiting for next frame in sequence - */ -#define DOT11_SC_ASSOC_BUSY_FAIL 17 /* Association denied because AP is - * unable to handle additional - * associated stations - */ -#define DOT11_SC_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting - * station not supporting all of the - * data rates in the BSSBasicRateSet - * parameter - */ -#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting - * station not supporting the Short - * Preamble option - */ -#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting - * station not supporting the PBCC - * Modulation option - */ -#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting - * station not supporting the Channel - * Agility option - */ -#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum - * Management capability is required. - */ -#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info - * in the Power Cap element is - * unacceptable. - */ -#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info - * in the Supported Channel element is - * unacceptable - */ -#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting - * station not supporting the Short Slot - * Time option - */ -#define DOT11_SC_ASSOC_DSSSOFDM_REQUIRED 26 /* Association denied because requesting station - * does not support the DSSS-OFDM option - */ -#define DOT11_SC_ASSOC_HT_REQUIRED 27 /* Association denied because the requesting - * station does not support HT features - */ -#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 /* Association denied due to AP - * being unable to reach the R0 Key Holder - */ -#define DOT11_SC_ASSOC_TRY_LATER 30 /* Association denied temporarily, try again later - */ -#define DOT11_SC_ASSOC_MFP_VIOLATION 31 /* Association denied due to Robust Management - * frame policy violation - */ - -#define DOT11_SC_DECLINED 37 /* request declined */ -#define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ -#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */ -#define DOT11_SC_INVALID_AKMP 43 /* Association denied due to invalid AKMP */ -#define DOT11_SC_INVALID_RSNIE_CAP 45 /* invalid RSN IE capabilities */ -#define DOT11_SC_DLS_NOT_ALLOWED 48 /* DLS is not allowed in the BSS by policy */ -#define DOT11_SC_INVALID_PMKID 53 /* Association denied due to invalid PMKID */ -#define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */ -#define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */ - -#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 /* ad proto not supported */ -#define DOT11_SC_NO_OUTSTAND_REQ 60 /* no outstanding req */ -#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 /* no response from server */ -#define DOT11_SC_TIMEOUT 62 /* timeout */ -#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 /* query rsp too large */ -#define DOT11_SC_SERVER_UNREACHABLE 65 /* server unreachable */ - -#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ -#define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */ -#define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */ -#define DOT11_SC_ASSOC_VHT_REQUIRED 104 /* Association denied because the requesting - * station does not support VHT features. - */ - -#define DOT11_SC_TRANSMIT_FAILURE 79 /* transmission failure */ - -/* Info Elts, length of INFORMATION portion of Info Elts */ -#define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ -#define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */ - -/* TIM Info element has 3 bytes fixed info in INFORMATION field, - * followed by 1 to 251 bytes of Partial Virtual Bitmap - */ -#define DOT11_MNG_TIM_FIXED_LEN 3 /* d11 management TIM fixed length */ -#define DOT11_MNG_TIM_DTIM_COUNT 0 /* d11 management DTIM count */ -#define DOT11_MNG_TIM_DTIM_PERIOD 1 /* d11 management DTIM period */ -#define DOT11_MNG_TIM_BITMAP_CTL 2 /* d11 management TIM BITMAP control */ -#define DOT11_MNG_TIM_PVB 3 /* d11 management TIM PVB */ - -/* TLV defines */ -#define TLV_TAG_OFF 0 /* tag offset */ -#define TLV_LEN_OFF 1 /* length offset */ -#define TLV_HDR_LEN 2 /* header length */ -#define TLV_BODY_OFF 2 /* body offset */ -#define TLV_BODY_LEN_MAX 255 /* max body length */ - -/* Management Frame Information Element IDs */ -#define DOT11_MNG_SSID_ID 0 /* d11 management SSID id */ -#define DOT11_MNG_RATES_ID 1 /* d11 management rates id */ -#define DOT11_MNG_FH_PARMS_ID 2 /* d11 management FH parameter id */ -#define DOT11_MNG_DS_PARMS_ID 3 /* d11 management DS parameter id */ -#define DOT11_MNG_CF_PARMS_ID 4 /* d11 management CF parameter id */ -#define DOT11_MNG_TIM_ID 5 /* d11 management TIM id */ -#define DOT11_MNG_IBSS_PARMS_ID 6 /* d11 management IBSS parameter id */ -#define DOT11_MNG_COUNTRY_ID 7 /* d11 management country id */ -#define DOT11_MNG_HOPPING_PARMS_ID 8 /* d11 management hopping parameter id */ -#define DOT11_MNG_HOPPING_TABLE_ID 9 /* d11 management hopping table id */ -#define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */ -#define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */ -#define DOT11_MNG_EDCA_PARAM_ID 12 /* 11E EDCA Parameter id */ -#define DOT11_MNG_TSPEC_ID 13 /* d11 management TSPEC id */ -#define DOT11_MNG_TCLAS_ID 14 /* d11 management TCLAS id */ -#define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */ -#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */ -#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */ -#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */ -#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */ -#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */ -#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement */ -#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ -#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */ -#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */ -#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */ -#define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */ -#define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */ -#define DOT11_MNG_TCLAS_PROC_ID 44 /* d11 management TCLAS processing id */ -#define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */ -#define DOT11_MNG_QOS_CAP_ID 46 /* 11E QoS Capability id */ -#define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */ -#define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */ -#define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */ -#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */ -#define DOT11_MNG_NEIGHBOR_REP_ID 52 /* 11k & 11v Neighbor report id */ -#define DOT11_MNG_RCPI_ID 53 /* 11k RCPI */ -#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */ -#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */ -#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */ -#define DOT11_MNG_RDE_ID 57 /* 11r RIC Data Element id */ -#define DOT11_MNG_REGCLASS_ID 59 /* d11 management regulatory class id */ -#define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */ -#define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */ -#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */ -#define DOT11_MNG_BSS_AVR_ACCESS_DELAY_ID 63 /* 11k bss average access delay */ -#define DOT11_MNG_ANTENNA_ID 64 /* 11k antenna id */ -#define DOT11_MNG_RSNI_ID 65 /* 11k RSNI id */ -#define DOT11_MNG_MEASUREMENT_PILOT_TX_ID 66 /* 11k measurement pilot tx info id */ -#define DOT11_MNG_BSS_AVAL_ADMISSION_CAP_ID 67 /* 11k bss aval admission cap id */ -#define DOT11_MNG_BSS_AC_ACCESS_DELAY_ID 68 /* 11k bss AC access delay id */ -#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ -#define DOT11_MNG_TIME_ADVERTISE_ID 69 /* 11p time advertisement */ -#define DOT11_MNG_RRM_CAP_ID 70 /* 11k radio measurement capability */ -#define DOT11_MNG_MULTIPLE_BSSID_ID 71 /* 11k multiple BSSID id */ -#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 /* d11 mgmt OBSS Coexistence INFO */ -#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 /* d11 mgmt OBSS Intolerant Channel list */ -#define DOT11_MNG_HT_OBSS_ID 74 /* d11 mgmt OBSS HT info */ -#define DOT11_MNG_MMIE_ID 76 /* d11 mgmt MIC IE */ -#define DOT11_MNG_FMS_DESCR_ID 86 /* 11v FMS descriptor */ -#define DOT11_MNG_FMS_REQ_ID 87 /* 11v FMS request id */ -#define DOT11_MNG_FMS_RESP_ID 88 /* 11v FMS response id */ -#define DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID 90 /* 11v bss max idle id */ -#define DOT11_MNG_TFS_REQUEST_ID 91 /* 11v tfs request id */ -#define DOT11_MNG_TFS_RESPONSE_ID 92 /* 11v tfs response id */ -#define DOT11_MNG_WNM_SLEEP_MODE_ID 93 /* 11v wnm-sleep mode id */ -#define DOT11_MNG_TIMBC_REQ_ID 94 /* 11v TIM broadcast request id */ -#define DOT11_MNG_TIMBC_RESP_ID 95 /* 11v TIM broadcast response id */ -#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */ -#define DOT11_MNG_TIME_ZONE_ID 98 /* 11v time zone */ -#define DOT11_MNG_DMS_REQUEST_ID 99 /* 11v dms request id */ -#define DOT11_MNG_DMS_RESPONSE_ID 100 /* 11v dms response id */ -#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */ -#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */ -#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */ -#define DOT11_MNG_PTI_CONTROL_ID 105 /* 11z TDLS PTI Control IE */ -#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 /* 11z TDLS PU Buffer Status IE */ -#define DOT11_MNG_INTERWORKING_ID 107 /* 11u interworking */ -#define DOT11_MNG_ADVERTISEMENT_ID 108 /* 11u advertisement protocol */ -#define DOT11_MNG_EXP_BW_REQ_ID 109 /* 11u expedited bandwith request */ -#define DOT11_MNG_QOS_MAP_ID 110 /* 11u QoS map set */ -#define DOT11_MNG_ROAM_CONSORT_ID 111 /* 11u roaming consortium */ -#define DOT11_MNG_EMERGCY_ALERT_ID 112 /* 11u emergency alert identifier */ -#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */ -#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */ -#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */ -#define DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID 194 /* Wide BW Channel Switch IE */ -#define DOT11_MNG_VHT_TRANSMIT_POWER_ENVELOPE_ID 195 /* VHT transmit Power Envelope IE */ -#define DOT11_MNG_CHANNEL_SWITCH_WRAPPER_ID 196 /* Channel Switch Wrapper IE */ -#define DOT11_MNG_AID_ID 197 /* Association ID IE */ -#define DOT11_MNG_OPER_MODE_NOTIF_ID 199 /* d11 mgmt VHT oper mode notif */ - - -#define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */ -#define DOT11_MNG_PROPR_ID 221 -/* should start using this one instead of above two */ -#define DOT11_MNG_VS_ID 221 /* d11 management Vendor Specific IE */ - -/* Rate Defines */ - -/* Valid rates for the Supported Rates and Extended Supported Rates IEs. - * Encoding is the rate in 500kbps units, rouding up for fractional values. - * 802.11-2012, section 6.5.5.2, DATA_RATE parameter enumerates all the values. - * The rate values cover DSSS, HR/DSSS, ERP, and OFDM phy rates. - * The defines below do not cover the rates specific to 10MHz, {3, 4.5, 27}, - * and 5MHz, {1.5, 2.25, 3, 4.5, 13.5}, which are not supported by Broadcom devices. - */ - -#define DOT11_RATE_1M 2 /* 1 Mbps in 500kbps units */ -#define DOT11_RATE_2M 4 /* 2 Mbps in 500kbps units */ -#define DOT11_RATE_5M5 11 /* 5.5 Mbps in 500kbps units */ -#define DOT11_RATE_11M 22 /* 11 Mbps in 500kbps units */ -#define DOT11_RATE_6M 12 /* 6 Mbps in 500kbps units */ -#define DOT11_RATE_9M 18 /* 9 Mbps in 500kbps units */ -#define DOT11_RATE_12M 24 /* 12 Mbps in 500kbps units */ -#define DOT11_RATE_18M 36 /* 18 Mbps in 500kbps units */ -#define DOT11_RATE_24M 48 /* 24 Mbps in 500kbps units */ -#define DOT11_RATE_36M 72 /* 36 Mbps in 500kbps units */ -#define DOT11_RATE_48M 96 /* 48 Mbps in 500kbps units */ -#define DOT11_RATE_54M 108 /* 54 Mbps in 500kbps units */ -#define DOT11_RATE_MAX 108 /* highest rate (54 Mbps) in 500kbps units */ - -/* Supported Rates and Extended Supported Rates IEs - * The supported rates octets are defined a the MSB indicatin a Basic Rate - * and bits 0-6 as the rate value - */ -#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ -#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ - -/* BSS Membership Selector parameters - * 802.11-2012 and 802.11ac_D4.0 sec 8.4.2.3 - * These selector values are advertised in Supported Rates and Extended Supported Rates IEs - * in the supported rates list with the Basic rate bit set. - * Constants below include the basic bit. - */ -#define DOT11_BSS_MEMBERSHIP_HT 0xFF /* Basic 0x80 + 127, HT Required to join */ -#define DOT11_BSS_MEMBERSHIP_VHT 0xFE /* Basic 0x80 + 126, VHT Required to join */ - -/* ERP info element bit values */ -#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ -#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present - *in the BSS - */ -#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for - *ERP-OFDM frames - */ -#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, - * 1 == not allowed - */ -/* TS Delay element offset & size */ -#define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */ -#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ - -/* Capability Information Field */ -#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */ -#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */ -#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */ -#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */ -#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */ -#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */ -#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ -#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ -#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ -#define DOT11_CAP_QOS 0x0200 /* d11 cap. qos */ -#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ -#define DOT11_CAP_APSD 0x0800 /* d11 cap. apsd */ -#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ -#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ -#define DOT11_CAP_DELAY_BA 0x4000 /* d11 cap. delayed block ack */ -#define DOT11_CAP_IMMEDIATE_BA 0x8000 /* d11 cap. immediate block ack */ - -/* Extended capabilities IE bitfields */ -/* 20/40 BSS Coexistence Management support bit position */ -#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 -/* Extended Channel Switching support bit position */ -#define DOT11_EXT_CAP_EXT_CHAN_SWITCHING 2 -/* scheduled PSMP support bit position */ -#define DOT11_EXT_CAP_SPSMP 6 -/* Flexible Multicast Service */ -#define DOT11_EXT_CAP_FMS 11 -/* proxy ARP service support bit position */ -#define DOT11_EXT_CAP_PROXY_ARP 12 -/* Traffic Filter Service */ -#define DOT11_EXT_CAP_TFS 16 -/* WNM-Sleep Mode */ -#define DOT11_EXT_CAP_WNM_SLEEP 17 -/* TIM Broadcast service */ -#define DOT11_EXT_CAP_TIMBC 18 -/* BSS Transition Management support bit position */ -#define DOT11_EXT_CAP_BSSTRANS_MGMT 19 -/* Direct Multicast Service */ -#define DOT11_EXT_CAP_DMS 26 -/* Interworking support bit position */ -#define DOT11_EXT_CAP_IW 31 -/* QoS map support bit position */ -#define DOT11_EXT_CAP_QOS_MAP 32 -/* service Interval granularity bit position and mask */ -#define DOT11_EXT_CAP_SI 41 -#define DOT11_EXT_CAP_SI_MASK 0x0E -/* WNM notification */ -#define DOT11_EXT_CAP_WNM_NOTIF 46 -/* Operating mode notification - VHT (11ac D3.0 - 8.4.2.29) */ -#define DOT11_EXT_CAP_OPER_MODE_NOTIF 62 - -/* VHT Operating mode bit fields - (11ac D3.0 - 8.4.1.50) */ -#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 -#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 -#define DOT11_OPER_MODE_RXNSS_SHIFT 4 -#define DOT11_OPER_MODE_RXNSS_MASK 0x70 -#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 -#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 - -#define DOT11_OPER_MODE(type, nss, chanw) (\ - ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ - DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ - (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ - ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ - DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) - -#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ - (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ - >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) -#define DOT11_OPER_MODE_RXNSS(mode) \ - ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ - >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) -#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ - (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ - >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) - -#define DOT11_OPER_MODE_20MHZ 0 -#define DOT11_OPER_MODE_40MHZ 1 -#define DOT11_OPER_MODE_80MHZ 2 -#define DOT11_OPER_MODE_160MHZ 3 -#define DOT11_OPER_MODE_8080MHZ 3 - -#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ) - -/* Operating mode information element 802.11ac D3.0 - 8.4.2.168 */ -BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { - uint8 mode; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; - -#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 - -/* Extended Capability Information Field */ -#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 /* 20/40 BSS Coexistence Management support */ - -/* - * Action Frame Constants - */ -#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action field */ -#define DOT11_ACTION_CAT_OFF 0 /* category offset */ -#define DOT11_ACTION_ACT_OFF 1 /* action offset */ - -/* Action Category field (sec 8.4.1.11) */ -#define DOT11_ACTION_CAT_ERR_MASK 0x80 /* category error mask */ -#define DOT11_ACTION_CAT_MASK 0x7F /* category mask */ -#define DOT11_ACTION_CAT_SPECT_MNG 0 /* category spectrum management */ -#define DOT11_ACTION_CAT_QOS 1 /* category QoS */ -#define DOT11_ACTION_CAT_DLS 2 /* category DLS */ -#define DOT11_ACTION_CAT_BLOCKACK 3 /* category block ack */ -#define DOT11_ACTION_CAT_PUBLIC 4 /* category public */ -#define DOT11_ACTION_CAT_RRM 5 /* category radio measurements */ -#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */ -#define DOT11_ACTION_CAT_HT 7 /* category for HT */ -#define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */ -#define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */ -#define DOT11_ACTION_CAT_WNM 10 /* category for WNM */ -#define DOT11_ACTION_CAT_UWNM 11 /* category for Unprotected WNM */ -#define DOT11_ACTION_NOTIFICATION 17 -#define DOT11_ACTION_CAT_VHT 21 /* VHT action */ -#define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */ -#define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */ - -/* Spectrum Management Action IDs (sec 7.4.1) */ -#define DOT11_SM_ACTION_M_REQ 0 /* d11 action measurement request */ -#define DOT11_SM_ACTION_M_REP 1 /* d11 action measurement response */ -#define DOT11_SM_ACTION_TPC_REQ 2 /* d11 action TPC request */ -#define DOT11_SM_ACTION_TPC_REP 3 /* d11 action TPC response */ -#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ -#define DOT11_SM_ACTION_EXT_CSA 5 /* d11 extened CSA for 11n */ - -/* QoS action ids */ -#define DOT11_QOS_ACTION_ADDTS_REQ 0 /* d11 action ADDTS request */ -#define DOT11_QOS_ACTION_ADDTS_RESP 1 /* d11 action ADDTS response */ -#define DOT11_QOS_ACTION_DELTS 2 /* d11 action DELTS */ -#define DOT11_QOS_ACTION_SCHEDULE 3 /* d11 action schedule */ -#define DOT11_QOS_ACTION_QOS_MAP 4 /* d11 action QOS map */ - -/* HT action ids */ -#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ -#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ - -/* Public action ids */ -#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 /* 20/40 Coexistence Management action id */ -#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ -#define DOT11_PUB_ACTION_GAS_CB_REQ 12 /* GAS Comeback Request */ - -/* Block Ack action types */ -#define DOT11_BA_ACTION_ADDBA_REQ 0 /* ADDBA Req action frame type */ -#define DOT11_BA_ACTION_ADDBA_RESP 1 /* ADDBA Resp action frame type */ -#define DOT11_BA_ACTION_DELBA 2 /* DELBA action frame type */ - -/* ADDBA action parameters */ -#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 /* AMSDU supported under BA */ -#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 /* policy mask(ack vs delayed) */ -#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 /* policy shift */ -#define DOT11_ADDBA_PARAM_TID_MASK 0x003c /* tid mask */ -#define DOT11_ADDBA_PARAM_TID_SHIFT 2 /* tid shift */ -#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 /* buffer size mask */ -#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 /* buffer size shift */ - -#define DOT11_ADDBA_POLICY_DELAYED 0 /* delayed BA policy */ -#define DOT11_ADDBA_POLICY_IMMEDIATE 1 /* immediate BA policy */ - -/* Fast Transition action types */ -#define DOT11_FT_ACTION_FT_RESERVED 0 -#define DOT11_FT_ACTION_FT_REQ 1 /* FBT request - for over-the-DS FBT */ -#define DOT11_FT_ACTION_FT_RES 2 /* FBT response - for over-the-DS FBT */ -#define DOT11_FT_ACTION_FT_CON 3 /* FBT confirm - for OTDS with RRP */ -#define DOT11_FT_ACTION_FT_ACK 4 /* FBT ack */ - -/* DLS action types */ -#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */ -#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */ -#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */ - -/* Wireless Network Management (WNM) action types */ -#define DOT11_WNM_ACTION_EVENT_REQ 0 -#define DOT11_WNM_ACTION_EVENT_REP 1 -#define DOT11_WNM_ACTION_DIAG_REQ 2 -#define DOT11_WNM_ACTION_DIAG_REP 3 -#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 -#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 -#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6 -#define DOT11_WNM_ACTION_BSSTRANS_REQ 7 -#define DOT11_WNM_ACTION_BSSTRANS_RESP 8 -#define DOT11_WNM_ACTION_FMS_REQ 9 -#define DOT11_WNM_ACTION_FMS_RESP 10 -#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 -#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 -#define DOT11_WNM_ACTION_TFS_REQ 13 -#define DOT11_WNM_ACTION_TFS_RESP 14 -#define DOT11_WNM_ACTION_TFS_NOTIFY_REQ 15 -#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 -#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 -#define DOT11_WNM_ACTION_TIMBC_REQ 18 -#define DOT11_WNM_ACTION_TIMBC_RESP 19 -#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 -#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 -#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 -#define DOT11_WNM_ACTION_DMS_REQ 23 -#define DOT11_WNM_ACTION_DMS_RESP 24 -#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 -#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 -#define DOT11_WNM_ACTION_NOTFCTN_RESP 27 -#define DOT11_WNM_ACTION_TFS_NOTIFY_RESP 28 - -/* Unprotected Wireless Network Management (WNM) action types */ -#define DOT11_UWNM_ACTION_TIM 0 -#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 - -#define DOT11_MNG_COUNTRY_ID_LEN 3 - -/* VHT category action types - 802.11ac D3.0 - 8.5.23.1 */ -#define DOT11_VHT_ACTION_CBF 0 /* Compressed Beamforming */ -#define DOT11_VHT_ACTION_GID_MGMT 1 /* Group ID Management */ -#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 /* Operating mode notif'n */ - -/** DLS Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dls_req { - uint8 category; /* category of action frame (2) */ - uint8 action; /* DLS action: req (0) */ - struct ether_addr da; /* destination address */ - struct ether_addr sa; /* source address */ - uint16 cap; /* capability */ - uint16 timeout; /* timeout value */ - uint8 data[1]; /* IE:support rate, extend support rate, HT cap */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dls_req dot11_dls_req_t; -#define DOT11_DLS_REQ_LEN 18 /* Fixed length */ - -/** DLS response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { - uint8 category; /* category of action frame (2) */ - uint8 action; /* DLS action: req (0) */ - uint16 status; /* status code field */ - struct ether_addr da; /* destination address */ - struct ether_addr sa; /* source address */ - uint8 data[1]; /* optional: capability, rate ... */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dls_resp dot11_dls_resp_t; -#define DOT11_DLS_RESP_LEN 16 /* Fixed length */ - - -/* ************* 802.11v related definitions. ************* */ - -/** BSS Management Transition Query frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_query (6) */ - uint8 token; /* dialog token */ - uint8 reason; /* transition query reason */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bsstrans_query dot11_bsstrans_query_t; -#define DOT11_BSSTRANS_QUERY_LEN 4 /* Fixed length */ - -/** BSS Management Transition Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_req (7) */ - uint8 token; /* dialog token */ - uint8 reqmode; /* transition request mode */ - uint16 disassoc_tmr; /* disassociation timer */ - uint8 validity_intrvl; /* validity interval */ - uint8 data[1]; /* optional: BSS term duration, ... */ - /* ...session info URL, candidate list */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bsstrans_req dot11_bsstrans_req_t; -#define DOT11_BSSTRANS_REQ_LEN 7 /* Fixed length */ - -/* BSS Mgmt Transition Request Mode Field - 802.11v */ -#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01 -#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02 -#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04 -#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08 -#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10 - -/** BSS Management transition response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_resp (8) */ - uint8 token; /* dialog token */ - uint8 status; /* transition status */ - uint8 term_delay; /* validity interval */ - uint8 data[1]; /* optional: BSSID target, candidate list */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t; -#define DOT11_BSSTRANS_RESP_LEN 5 /* Fixed length */ - -/* BSS Mgmt Transition Response Status Field */ -#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0 -#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8 - - -/** BSS Max Idle Period element */ -BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { - uint8 id; /* 90, DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID */ - uint8 len; - uint16 max_idle_period; /* in unit of 1000 TUs */ - uint8 idle_opt; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; -#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 /* bss max idle period IE size */ -#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 /* BSS max idle option */ - -/** TIM Broadcast request element */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { - uint8 id; /* 94, DOT11_MNG_TIMBC_REQ_ID */ - uint8 len; - uint8 interval; /* in unit of beacon interval */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; -#define DOT11_TIMBC_REQ_IE_LEN 1 /* Fixed length */ - -/** TIM Broadcast request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: DOT11_WNM_ACTION_TIMBC_REQ(18) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* TIM broadcast request element */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_req dot11_timbc_req_t; -#define DOT11_TIMBC_REQ_LEN 3 /* Fixed length */ - -/** TIM Broadcast response element */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { - uint8 id; /* 95, DOT11_MNG_TIM_BROADCAST_RESP_ID */ - uint8 len; - uint8 status; /* status of add request */ - uint8 interval; /* in unit of beacon interval */ - int32 offset; /* in unit of ms */ - uint16 high_rate; /* in unit of 0.5 Mb/s */ - uint16 low_rate; /* in unit of 0.5 Mb/s */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; -#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 /* Deny. Fixed length */ -#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 /* Accept. Fixed length */ - -#define DOT11_TIMBC_STATUS_ACCEPT 0 -#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 -#define DOT11_TIMBC_STATUS_DENY 2 -#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 -#define DOT11_TIMBC_STATUS_RESERVED 4 - -/** TIM Broadcast request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* action: DOT11_WNM_ACTION_TIMBC_RESP(19) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* TIM broadcast response element */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_resp dot11_timbc_resp_t; -#define DOT11_TIMBC_RESP_LEN 3 /* Fixed length */ - -/** TIM element */ -BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { - uint8 id; /* 5, DOT11_MNG_TIM_ID */ - uint8 len; /* 4 - 255 */ - uint8 dtim_count; /* DTIM decrementing counter */ - uint8 dtim_period; /* DTIM period */ - uint8 bitmap_control; /* AID 0 + bitmap offset */ - uint8 pvb[1]; /* Partial Virtual Bitmap, variable length */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tim_ie dot11_tim_ie_t; -#define DOT11_TIM_IE_FIXED_LEN 3 /* Fixed length, without id and len */ -#define DOT11_TIM_IE_FIXED_TOTAL_LEN 5 /* Fixed length, with id and len */ - -/** TIM Broadcast frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc { - uint8 category; /* category of action frame (11) */ - uint8 action; /* action: TIM (0) */ - uint8 check_beacon; /* need to check-beacon */ - uint8 tsf[8]; /* Time Synchronization Function */ - dot11_tim_ie_t tim_ie; /* TIM element */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc dot11_timbc_t; -#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) -#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) /* Fixed length */ -#define DOT11_TIMBC_LEN 11 /* Fixed length */ - -/** TCLAS frame classifier type */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { - uint8 type; - uint8 mask; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; -#define DOT11_TCLAS_FC_HDR_LEN 2 /* Fixed length */ - -#define DOT11_TCLAS_MASK_0 0x1 -#define DOT11_TCLAS_MASK_1 0x2 -#define DOT11_TCLAS_MASK_2 0x4 -#define DOT11_TCLAS_MASK_3 0x8 -#define DOT11_TCLAS_MASK_4 0x10 -#define DOT11_TCLAS_MASK_5 0x20 -#define DOT11_TCLAS_MASK_6 0x40 -#define DOT11_TCLAS_MASK_7 0x80 - -#define DOT11_TCLAS_FC_0_ETH 0 -#define DOT11_TCLAS_FC_1_IP 1 -#define DOT11_TCLAS_FC_2_8021Q 2 -#define DOT11_TCLAS_FC_3_OFFSET 3 -#define DOT11_TCLAS_FC_4_IP_HIGHER 4 -#define DOT11_TCLAS_FC_5_8021D 5 - -/** TCLAS frame classifier type 0 parameters for Ethernet */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { - uint8 type; - uint8 mask; - uint8 sa[ETHER_ADDR_LEN]; - uint8 da[ETHER_ADDR_LEN]; - uint16 eth_type; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; -#define DOT11_TCLAS_FC_0_ETH_LEN 16 - -/** TCLAS frame classifier type 1 parameters for IPV4 */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { - uint8 type; - uint8 mask; - uint8 version; - uint32 src_ip; - uint32 dst_ip; - uint16 src_port; - uint16 dst_port; - uint8 dscp; - uint8 protocol; - uint8 reserved; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; -#define DOT11_TCLAS_FC_1_IPV4_LEN 18 - -/** TCLAS frame classifier type 2 parameters for 802.1Q */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { - uint8 type; - uint8 mask; - uint16 tci; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; -#define DOT11_TCLAS_FC_2_8021Q_LEN 4 - -/** TCLAS frame classifier type 3 parameters for filter offset */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { - uint8 type; - uint8 mask; - uint16 offset; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; -#define DOT11_TCLAS_FC_3_FILTER_LEN 4 - -/** TCLAS frame classifier type 4 parameters for IPV4 is the same as TCLAS type 1 */ -typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; -#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN - -/** TCLAS frame classifier type 4 parameters for IPV6 */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { - uint8 type; - uint8 mask; - uint8 version; - uint8 saddr[16]; - uint8 daddr[16]; - uint16 src_port; - uint16 dst_port; - uint8 dscp; - uint8 nexthdr; - uint8 flow_lbl[3]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; -#define DOT11_TCLAS_FC_4_IPV6_LEN 44 - -/** TCLAS frame classifier type 5 parameters for 802.1D */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { - uint8 type; - uint8 mask; - uint8 pcp; - uint8 cfi; - uint16 vid; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; -#define DOT11_TCLAS_FC_5_8021D_LEN 6 - -/** TCLAS frame classifier type parameters */ -BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { - uint8 data[1]; - dot11_tclas_fc_hdr_t hdr; - dot11_tclas_fc_0_eth_t t0_eth; - dot11_tclas_fc_1_ipv4_t t1_ipv4; - dot11_tclas_fc_2_8021q_t t2_8021q; - dot11_tclas_fc_3_filter_t t3_filter; - dot11_tclas_fc_4_ipv4_t t4_ipv4; - dot11_tclas_fc_4_ipv6_t t4_ipv6; - dot11_tclas_fc_5_8021d_t t5_8021d; -} BWL_POST_PACKED_STRUCT; -typedef union dot11_tclas_fc dot11_tclas_fc_t; - -#define DOT11_TCLAS_FC_MIN_LEN 4 /* Classifier Type 2 has the min size */ -#define DOT11_TCLAS_FC_MAX_LEN 254 - -/** TCLAS element */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { - uint8 id; /* 14, DOT11_MNG_TCLAS_ID */ - uint8 len; - uint8 user_priority; - dot11_tclas_fc_t fc; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_ie dot11_tclas_ie_t; -#define DOT11_TCLAS_IE_LEN 3 /* Fixed length, include id and len */ - -/** TCLAS processing element */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { - uint8 id; /* 44, DOT11_MNG_TCLAS_PROC_ID */ - uint8 len; - uint8 process; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; -#define DOT11_TCLAS_PROC_IE_LEN 3 /* Fixed length, include id and len */ - -#define DOT11_TCLAS_PROC_MATCHALL 0 /* All high level element need to match */ -#define DOT11_TCLAS_PROC_MATCHONE 1 /* One high level element need to match */ -#define DOT11_TCLAS_PROC_NONMATCH 2 /* Non match to any high level element */ - - -/* TSPEC element defined in 802.11 std section 8.4.2.32 - Not supported */ -#define DOT11_TSPEC_IE_LEN 57 /* Fixed length */ - -/** TFS request element */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { - uint8 id; /* 91, DOT11_MNG_TFS_REQUEST_ID */ - uint8 len; - uint8 tfs_id; - uint8 actcode; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; -#define DOT11_TFS_REQ_IE_LEN 2 /* Fixed length, without id and len */ - -/** TFS request action codes (bitfield) */ -#define DOT11_TFS_ACTCODE_DELETE 1 -#define DOT11_TFS_ACTCODE_NOTIFY 2 - -/** TFS request subelement IDs */ -#define DOT11_TFS_REQ_TFS_SE_ID 1 -#define DOT11_TFS_REQ_VENDOR_SE_ID 221 - -/** TFS subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { - uint8 sub_id; - uint8 len; - uint8 data[1]; /* TCLAS element(s) + optional TCLAS proc */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_se dot11_tfs_se_t; - - -/** TFS response element */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { - uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ - uint8 len; - uint8 tfs_id; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; -#define DOT11_TFS_RESP_IE_LEN 1 /* Fixed length, without id and len */ - -/** TFS response subelement IDs (same subelments, but different IDs than in TFS request */ -#define DOT11_TFS_RESP_TFS_STATUS_SE_ID 1 -#define DOT11_TFS_RESP_TFS_SE_ID 2 -#define DOT11_TFS_RESP_VENDOR_SE_ID 221 - -/** TFS status subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { - uint8 sub_id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ - uint8 len; - uint8 resp_st; - uint8 data[1]; /* Potential dot11_tfs_se_t included */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; -#define DOT11_TFS_STATUS_SE_LEN 1 /* Fixed length, without id and len */ - -/* Following Definition should be merged to FMS_TFS macro below */ -/* TFS Response status code. Identical to FMS Element status, without N/A */ -#define DOT11_TFS_STATUS_ACCEPT 0 -#define DOT11_TFS_STATUS_DENY_FORMAT 1 -#define DOT11_TFS_STATUS_DENY_RESOURCE 2 -#define DOT11_TFS_STATUS_DENY_POLICY 4 -#define DOT11_TFS_STATUS_DENY_UNSPECIFIED 5 -#define DOT11_TFS_STATUS_ALTPREF_POLICY 7 -#define DOT11_TFS_STATUS_ALTPREF_TCLAS_UNSUPP 14 - -/* FMS Element Status and TFS Response Status Definition */ -#define DOT11_FMS_TFS_STATUS_ACCEPT 0 -#define DOT11_FMS_TFS_STATUS_DENY_FORMAT 1 -#define DOT11_FMS_TFS_STATUS_DENY_RESOURCE 2 -#define DOT11_FMS_TFS_STATUS_DENY_MULTIPLE_DI 3 -#define DOT11_FMS_TFS_STATUS_DENY_POLICY 4 -#define DOT11_FMS_TFS_STATUS_DENY_UNSPECIFIED 5 -#define DOT11_FMS_TFS_STATUS_ALT_DIFF_DI 6 -#define DOT11_FMS_TFS_STATUS_ALT_POLICY 7 -#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_DI 8 -#define DOT11_FMS_TFS_STATUS_ALT_MCRATE 9 -#define DOT11_FMS_TFS_STATUS_TERM_POLICY 10 -#define DOT11_FMS_TFS_STATUS_TERM_RESOURCE 11 -#define DOT11_FMS_TFS_STATUS_TERM_HIGHER_PRIO 12 -#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_MDI 13 -#define DOT11_FMS_TFS_STATUS_ALT_TCLAS_UNSUPP 14 - -/** TFS Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS request (13) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_req dot11_tfs_req_t; -#define DOT11_TFS_REQ_LEN 3 /* Fixed length */ - -/** TFS Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS request (14) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_resp dot11_tfs_resp_t; -#define DOT11_TFS_RESP_LEN 3 /* Fixed length */ - -/** TFS Management Notify frame request header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS notify request (15) */ - uint8 tfs_id_cnt; /* TFS IDs count */ - uint8 tfs_id[1]; /* Array of TFS IDs */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_notify_req dot11_tfs_notify_req_t; -#define DOT11_TFS_NOTIFY_REQ_LEN 3 /* Fixed length */ - -/** TFS Management Notify frame response header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS notify response (28) */ - uint8 tfs_id_cnt; /* TFS IDs count */ - uint8 tfs_id[1]; /* Array of TFS IDs */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_notify_resp dot11_tfs_notify_resp_t; -#define DOT11_TFS_NOTIFY_RESP_LEN 3 /* Fixed length */ - - -/** WNM-Sleep Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: wnm-sleep request (16) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; -#define DOT11_WNM_SLEEP_REQ_LEN 3 /* Fixed length */ - -/** WNM-Sleep Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: wnm-sleep request (17) */ - uint8 token; /* dialog token */ - uint16 key_len; /* key data length */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; -#define DOT11_WNM_SLEEP_RESP_LEN 5 /* Fixed length */ - -#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 -#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 - -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { - uint8 sub_id; - uint8 len; - uint16 key_info; - uint8 key_length; - uint8 rsc[8]; - uint8 key[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; -#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 /* without sub_id, len, and key */ -#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 /* without sub_id and len */ - -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { - uint8 sub_id; - uint8 len; - uint16 key_id; - uint8 pn[6]; - uint8 key[16]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; -#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 /* Fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { - uint8 id; /* 93, DOT11_MNG_WNM_SLEEP_MODE_ID */ - uint8 len; - uint8 act_type; - uint8 resp_status; - uint16 interval; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; -#define DOT11_WNM_SLEEP_IE_LEN 4 /* Fixed length */ - -#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 -#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 - -#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 -#define DOT11_WNM_SLEEP_RESP_UPDATE 1 -#define DOT11_WNM_SLEEP_RESP_DENY 2 -#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 -#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 -#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 -#define DOT11_WNM_SLEEP_RESP_LAST 6 - -/** DMS Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: dms request (23) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_req dot11_dms_req_t; -#define DOT11_DMS_REQ_LEN 3 /* Fixed length */ - -/** DMS Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: dms request (24) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_resp dot11_dms_resp_t; -#define DOT11_DMS_RESP_LEN 3 /* Fixed length */ - -/** DMS request element */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { - uint8 id; /* 99, DOT11_MNG_DMS_REQUEST_ID */ - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; -#define DOT11_DMS_REQ_IE_LEN 2 /* Fixed length */ - -/** DMS response element */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { - uint8 id; /* 100, DOT11_MNG_DMS_RESPONSE_ID */ - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; -#define DOT11_DMS_RESP_IE_LEN 2 /* Fixed length */ - -/** DMS request descriptor */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { - uint8 dms_id; - uint8 len; - uint8 type; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; -#define DOT11_DMS_REQ_DESC_LEN 3 /* Fixed length */ - -#define DOT11_DMS_REQ_TYPE_ADD 0 -#define DOT11_DMS_REQ_TYPE_REMOVE 1 -#define DOT11_DMS_REQ_TYPE_CHANGE 2 - -/** DMS response status */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { - uint8 dms_id; - uint8 len; - uint8 type; - uint16 lsc; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; -#define DOT11_DMS_RESP_STATUS_LEN 5 /* Fixed length */ - -#define DOT11_DMS_RESP_TYPE_ACCEPT 0 -#define DOT11_DMS_RESP_TYPE_DENY 1 -#define DOT11_DMS_RESP_TYPE_TERM 2 - -#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF - -/** FMS Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: fms request (9) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_req dot11_fms_req_t; -#define DOT11_FMS_REQ_LEN 3 /* Fixed length */ - -/** FMS Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: fms request (10) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_resp dot11_fms_resp_t; -#define DOT11_FMS_RESP_LEN 3 /* Fixed length */ - -/** FMS Descriptor element */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_desc { - uint8 id; - uint8 len; - uint8 num_fms_cnt; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_desc dot11_fms_desc_t; -#define DOT11_FMS_DESC_LEN 1 /* Fixed length */ - -#define DOT11_FMS_CNTR_MAX 0x8 -#define DOT11_FMS_CNTR_ID_MASK 0x7 -#define DOT11_FMS_CNTR_ID_SHIFT 0x0 -#define DOT11_FMS_CNTR_COUNT_MASK 0xf1 -#define DOT11_FMS_CNTR_SHIFT 0x3 - -/** FMS request element */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_req_ie { - uint8 id; - uint8 len; - uint8 fms_token; /* token used to identify fms stream set */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_req_ie dot11_fms_req_ie_t; -#define DOT11_FMS_REQ_IE_FIX_LEN 1 /* Fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_rate_id_field { - uint8 mask; - uint8 mcs_idx; - uint16 rate; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rate_id_field dot11_rate_id_field_t; -#define DOT11_RATE_ID_FIELD_MCS_SEL_MASK 0x7 -#define DOT11_RATE_ID_FIELD_MCS_SEL_OFFSET 0 -#define DOT11_RATE_ID_FIELD_RATETYPE_MASK 0x18 -#define DOT11_RATE_ID_FIELD_RATETYPE_OFFSET 3 -#define DOT11_RATE_ID_FIELD_LEN sizeof(dot11_rate_id_field_t) - -/** FMS request subelements */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_se { - uint8 sub_id; - uint8 len; - uint8 interval; - uint8 max_interval; - dot11_rate_id_field_t rate; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_se dot11_fms_se_t; -#define DOT11_FMS_REQ_SE_LEN 6 /* Fixed length */ - -#define DOT11_FMS_REQ_SE_ID_FMS 1 /* FMS subelement */ -#define DOT11_FMS_REQ_SE_ID_VS 221 /* Vendor Specific subelement */ - -/** FMS response element */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_resp_ie { - uint8 id; - uint8 len; - uint8 fms_token; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_resp_ie dot11_fms_resp_ie_t; -#define DOT11_FMS_RESP_IE_FIX_LEN 1 /* Fixed length */ - -/* FMS status subelements */ -#define DOT11_FMS_STATUS_SE_ID_FMS 1 /* FMS Status */ -#define DOT11_FMS_STATUS_SE_ID_TCLAS 2 /* TCLAS Status */ -#define DOT11_FMS_STATUS_SE_ID_VS 221 /* Vendor Specific subelement */ - -/** FMS status subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_status_se { - uint8 sub_id; - uint8 len; - uint8 status; - uint8 interval; - uint8 max_interval; - uint8 fmsid; - uint8 counter; - dot11_rate_id_field_t rate; - uint8 mcast_addr[ETHER_ADDR_LEN]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_status_se dot11_fms_status_se_t; -#define DOT11_FMS_STATUS_SE_LEN 15 /* Fixed length */ - -/** TCLAS status subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_status_se { - uint8 sub_id; - uint8 len; - uint8 fmsid; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_status_se dot11_tclas_status_se_t; -#define DOT11_TCLAS_STATUS_SE_LEN 1 /* Fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_addba_req { - uint8 category; /* category of action frame (3) */ - uint8 action; /* action: addba req */ - uint8 token; /* identifier */ - uint16 addba_param_set; /* parameter set */ - uint16 timeout; /* timeout in seconds */ - uint16 start_seqnum; /* starting sequence number */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_addba_req dot11_addba_req_t; -#define DOT11_ADDBA_REQ_LEN 9 /* length of addba req frame */ - -BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { - uint8 category; /* category of action frame (3) */ - uint8 action; /* action: addba resp */ - uint8 token; /* identifier */ - uint16 status; /* status of add request */ - uint16 addba_param_set; /* negotiated parameter set */ - uint16 timeout; /* negotiated timeout in seconds */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_addba_resp dot11_addba_resp_t; -#define DOT11_ADDBA_RESP_LEN 9 /* length of addba resp frame */ - -/* DELBA action parameters */ -#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 /* initiator mask */ -#define DOT11_DELBA_PARAM_INIT_SHIFT 11 /* initiator shift */ -#define DOT11_DELBA_PARAM_TID_MASK 0xf000 /* tid mask */ -#define DOT11_DELBA_PARAM_TID_SHIFT 12 /* tid shift */ - -BWL_PRE_PACKED_STRUCT struct dot11_delba { - uint8 category; /* category of action frame (3) */ - uint8 action; /* action: addba req */ - uint16 delba_param_set; /* paarmeter set */ - uint16 reason; /* reason for dellba */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_delba dot11_delba_t; -#define DOT11_DELBA_LEN 6 /* length of delba frame */ - -/* SA Query action field value */ -#define SA_QUERY_REQUEST 0 -#define SA_QUERY_RESPONSE 1 - -/* ************* 802.11r related definitions. ************* */ - -/** Over-the-DS Fast Transition Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_ft_req { - uint8 category; /* category of action frame (6) */ - uint8 action; /* action: ft req */ - uint8 sta_addr[ETHER_ADDR_LEN]; - uint8 tgt_ap_addr[ETHER_ADDR_LEN]; - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ft_req dot11_ft_req_t; -#define DOT11_FT_REQ_FIXED_LEN 14 - -/** Over-the-DS Fast Transition Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_ft_res { - uint8 category; /* category of action frame (6) */ - uint8 action; /* action: ft resp */ - uint8 sta_addr[ETHER_ADDR_LEN]; - uint8 tgt_ap_addr[ETHER_ADDR_LEN]; - uint16 status; /* status code */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ft_res dot11_ft_res_t; -#define DOT11_FT_RES_FIXED_LEN 16 - -/** RDE RIC Data Element. */ -BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { - uint8 id; /* 11r, DOT11_MNG_RDE_ID */ - uint8 length; - uint8 rde_id; /* RDE identifier. */ - uint8 rd_count; /* Resource Descriptor Count. */ - uint16 status; /* Status Code. */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rde_ie dot11_rde_ie_t; - -/* 11r - Size of the RDE (RIC Data Element) IE, including TLV header. */ -#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) - - -/* ************* 802.11k related definitions. ************* */ - -/* Radio measurements enabled capability ie */ -#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ -#define RCPI_IE_LEN 1 -#define RSNI_IE_LEN 1 -BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { - uint8 cap[DOT11_RRM_CAP_LEN]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; - -/* Bitmap definitions for cap ie */ -#define DOT11_RRM_CAP_LINK 0 -#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 -#define DOT11_RRM_CAP_PARALLEL 2 -#define DOT11_RRM_CAP_REPEATED 3 -#define DOT11_RRM_CAP_BCN_PASSIVE 4 -#define DOT11_RRM_CAP_BCN_ACTIVE 5 -#define DOT11_RRM_CAP_BCN_TABLE 6 -#define DOT11_RRM_CAP_BCN_REP_COND 7 -#define DOT11_RRM_CAP_FM 8 -#define DOT11_RRM_CAP_CLM 9 -#define DOT11_RRM_CAP_NHM 10 -#define DOT11_RRM_CAP_SM 11 -#define DOT11_RRM_CAP_LCIM 12 -#define DOT11_RRM_CAP_LCIA 13 -#define DOT11_RRM_CAP_TSCM 14 -#define DOT11_RRM_CAP_TTSCM 15 -#define DOT11_RRM_CAP_AP_CHANREP 16 -#define DOT11_RRM_CAP_RMMIB 17 -/* bit18-bit26, not used for RRM_IOVAR */ -#define DOT11_RRM_CAP_MPTI 27 -#define DOT11_RRM_CAP_NBRTSFO 28 -#define DOT11_RRM_CAP_RCPI 29 -#define DOT11_RRM_CAP_RSNI 30 -#define DOT11_RRM_CAP_BSSAAD 31 -#define DOT11_RRM_CAP_BSSAAC 32 -#define DOT11_RRM_CAP_AI 33 - -/* Operating Class (formerly "Regulatory Class") definitions */ -#define DOT11_OP_CLASS_NONE 255 - -BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { - uint8 id; - uint8 len; - uint8 reg; - uint8 chanlist[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct do11_ap_chrep dot11_ap_chrep_t; - -/* Radio Measurements action ids */ -#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ -#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */ -#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */ -#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */ -#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */ -#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */ - -/** Generic radio measurement action frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_rm_action { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rm_action dot11_rm_action_t; -#define DOT11_RM_ACTION_LEN 3 - -BWL_PRE_PACKED_STRUCT struct dot11_rmreq { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - uint16 reps; /* no. of repetitions */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq dot11_rmreq_t; -#define DOT11_RMREQ_LEN 5 - -BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rm_ie dot11_rm_ie_t; -#define DOT11_RM_IE_LEN 5 - -/* Definitions for "mode" bits in rm req */ -#define DOT11_RMREQ_MODE_PARALLEL 1 -#define DOT11_RMREQ_MODE_ENABLE 2 -#define DOT11_RMREQ_MODE_REQUEST 4 -#define DOT11_RMREQ_MODE_REPORT 8 -#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */ - -/* Definitions for "mode" bits in rm rep */ -#define DOT11_RMREP_MODE_LATE 1 -#define DOT11_RMREP_MODE_INCAPABLE 2 -#define DOT11_RMREP_MODE_REFUSED 4 - -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; - uint8 bcn_mode; - struct ether_addr bssid; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; -#define DOT11_RMREQ_BCN_LEN 18 - -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; - uint8 frame_info; - uint8 rcpi; - uint8 rsni; - struct ether_addr bssid; - uint8 antenna_id; - uint32 parent_tsf; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; -#define DOT11_RMREP_BCN_LEN 26 - -/* Beacon request measurement mode */ -#define DOT11_RMREQ_BCN_PASSIVE 0 -#define DOT11_RMREQ_BCN_ACTIVE 1 -#define DOT11_RMREQ_BCN_TABLE 2 - -/* Sub-element IDs for Beacon Request */ -#define DOT11_RMREQ_BCN_SSID_ID 0 -#define DOT11_RMREQ_BCN_REPINFO_ID 1 -#define DOT11_RMREQ_BCN_REPDET_ID 2 -#define DOT11_RMREQ_BCN_REQUEST_ID 10 -#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID - -/* Reporting Detail element definition */ -#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ -#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */ -#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */ - -/* Sub-element IDs for Beacon Report */ -#define DOT11_RMREP_BCN_FRM_BODY 1 - -/* Sub-element IDs for Frame Report */ -#define DOT11_RMREP_FRAME_COUNT_REPORT 1 - -/** Channel load request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; -#define DOT11_RMREQ_CHANLOAD_LEN 11 - -/** Channel load report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; - uint8 channel_load; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; -#define DOT11_RMREP_CHANLOAD_LEN 13 - -/** Noise histogram request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; -#define DOT11_RMREQ_NOISE_LEN 11 - -/** Noise histogram report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; - uint8 antid; - uint8 anpi; - uint8 ipi0_dens; - uint8 ipi1_dens; - uint8 ipi2_dens; - uint8 ipi3_dens; - uint8 ipi4_dens; - uint8 ipi5_dens; - uint8 ipi6_dens; - uint8 ipi7_dens; - uint8 ipi8_dens; - uint8 ipi9_dens; - uint8 ipi10_dens; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; -#define DOT11_RMREP_NOISE_LEN 25 - -/** Frame request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; - uint8 req_type; - struct ether_addr ta; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; -#define DOT11_RMREQ_FRAME_LEN 18 - -/** Frame report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; -#define DOT11_RMREP_FRAME_LEN 12 - -/** Frame report entry */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { - struct ether_addr ta; - struct ether_addr bssid; - uint8 phy_type; - uint8 avg_rcpi; - uint8 last_rsni; - uint8 last_rcpi; - uint8 ant_id; - uint16 frame_cnt; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; -#define DOT11_RMREP_FRMENTRY_LEN 19 - -/** STA statistics request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - struct ether_addr peer; - uint16 interval; - uint16 duration; - uint8 group_id; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; -#define DOT11_RMREQ_STAT_LEN 16 - -/** STA statistics report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { - uint16 duration; - uint8 group_id; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; - -/** Transmit stream/category measurement request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint16 interval; - uint16 duration; - struct ether_addr peer; - uint8 traffic_id; - uint8 bin0_range; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; - -/** Transmit stream/category measurement report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { - uint32 starttime[2]; - uint16 duration; - struct ether_addr peer; - uint8 traffic_id; - uint8 reason; - uint32 txmsdu_cnt; - uint32 msdu_discarded_cnt; - uint32 msdufailed_cnt; - uint32 msduretry_cnt; - uint32 cfpolls_lost_cnt; - uint32 avrqueue_delay; - uint32 avrtx_delay; - uint8 bin0_range; - uint32 bin0; - uint32 bin1; - uint32 bin2; - uint32 bin3; - uint32 bin4; - uint32 bin5; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; - -/** Measurement pause request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint16 pause_time; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; - - -/* Neighbor Report subelements ID (11k & 11v) */ -#define DOT11_NGBR_TSF_INFO_SE_ID 1 -#define DOT11_NGBR_CCS_SE_ID 2 -#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3 -#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4 -#define DOT11_NGBR_BEARING_SE_ID 5 - -/** Neighbor Report, BSS Transition Candidate Preference subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se { - uint8 sub_id; - uint8 len; - uint8 preference; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t; -#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1 - -/** Neighbor Report, BSS Termination Duration subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se { - uint8 sub_id; - uint8 len; - uint8 tsf[8]; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t; -#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10 - -/* Neighbor Report BSSID Information Field */ -#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002 -#define DOT11_NGBR_BI_REACHABILTY 0x0003 -#define DOT11_NGBR_BI_SEC 0x0004 -#define DOT11_NGBR_BI_KEY_SCOPE 0x0008 -#define DOT11_NGBR_BI_CAP 0x03f0 -#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010 -#define DOT11_NGBR_BI_CAP_QOS 0x0020 -#define DOT11_NGBR_BI_CAP_APSD 0x0040 -#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080 -#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100 -#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200 -#define DOT11_NGBR_BI_MOBILITY 0x0400 -#define DOT11_NGBR_BI_HT 0x0800 - -/** Neighbor Report element (11k & 11v) */ -BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie { - uint8 id; - uint8 len; - struct ether_addr bssid; - uint32 bssid_info; - uint8 reg; /* Operating class */ - uint8 channel; - uint8 phytype; - uint8 data[1]; /* Variable size subelements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; -#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13 - - -/* MLME Enumerations */ -#define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ -#define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */ -#define DOT11_BSSTYPE_ANY 2 /* d11 any BSS type */ -#define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */ -#define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */ - -/** Link Measurement */ -BWL_PRE_PACKED_STRUCT struct dot11_lmreq { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - uint8 txpwr; /* Transmit Power Used */ - uint8 maxtxpwr; /* Max Transmit Power */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_lmreq dot11_lmreq_t; -#define DOT11_LMREQ_LEN 5 - -BWL_PRE_PACKED_STRUCT struct dot11_lmrep { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - dot11_tpc_rep_t tpc; /* TPC element */ - uint8 rxant; /* Receive Antenna ID */ - uint8 txant; /* Transmit Antenna ID */ - uint8 rcpi; /* RCPI */ - uint8 rsni; /* RSNI */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_lmrep dot11_lmrep_t; -#define DOT11_LMREP_LEN 11 - -/* 802.11 BRCM "Compromise" Pre N constants */ -#define PREN_PREAMBLE 24 /* green field preamble time */ -#define PREN_MM_EXT 12 /* extra mixed mode preamble time */ -#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ - -/* 802.11N PHY constants */ -#define RIFS_11N_TIME 2 /* NPHY RIFS time */ - -/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3 - * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 - */ -/* HT-SIG1 */ -#define HT_SIG1_MCS_MASK 0x00007F -#define HT_SIG1_CBW 0x000080 -#define HT_SIG1_HT_LENGTH 0xFFFF00 - -/* HT-SIG2 */ -#define HT_SIG2_SMOOTHING 0x000001 -#define HT_SIG2_NOT_SOUNDING 0x000002 -#define HT_SIG2_RESERVED 0x000004 -#define HT_SIG2_AGGREGATION 0x000008 -#define HT_SIG2_STBC_MASK 0x000030 -#define HT_SIG2_STBC_SHIFT 4 -#define HT_SIG2_FEC_CODING 0x000040 -#define HT_SIG2_SHORT_GI 0x000080 -#define HT_SIG2_ESS_MASK 0x000300 -#define HT_SIG2_ESS_SHIFT 8 -#define HT_SIG2_CRC 0x03FC00 -#define HT_SIG2_TAIL 0x1C0000 - -/* HT Timing-related parameters (802.11-2012, sec 20.3.6) */ -#define HT_T_LEG_PREAMBLE 16 -#define HT_T_L_SIG 4 -#define HT_T_SIG 8 -#define HT_T_LTF1 4 -#define HT_T_GF_LTF1 8 -#define HT_T_LTFs 4 -#define HT_T_STF 4 -#define HT_T_GF_STF 8 -#define HT_T_SYML 4 - -#define HT_N_SERVICE 16 /* bits in SERVICE field */ -#define HT_N_TAIL 6 /* tail bits per BCC encoder */ - -/* 802.11 A PHY constants */ -#define APHY_SLOT_TIME 9 /* APHY slot time */ -#define APHY_SIFS_TIME 16 /* APHY SIFS time */ -#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ -#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ -#define APHY_SIGNAL_TIME 4 /* APHY signal time */ -#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ -#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ -#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ -#define APHY_CWMIN 15 /* APHY cwmin */ - -/* 802.11 B PHY constants */ -#define BPHY_SLOT_TIME 20 /* BPHY slot time */ -#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ -#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ -#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ -#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ -#define BPHY_CWMIN 31 /* BPHY cwmin */ - -/* 802.11 G constants */ -#define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */ - -#define PHY_CWMAX 1023 /* PHY cwmax */ - -#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ - -/* 802.11 VHT constants */ - -typedef int vht_group_id_t; - -/* for VHT-A1 */ -/* SIG-A1 reserved bits */ -#define VHT_SIGA1_CONST_MASK 0x800004 - -#define VHT_SIGA1_BW_MASK 0x000003 -#define VHT_SIGA1_20MHZ_VAL 0x000000 -#define VHT_SIGA1_40MHZ_VAL 0x000001 -#define VHT_SIGA1_80MHZ_VAL 0x000002 -#define VHT_SIGA1_160MHZ_VAL 0x000003 - -#define VHT_SIGA1_STBC 0x000008 - -#define VHT_SIGA1_GID_MASK 0x0003f0 -#define VHT_SIGA1_GID_SHIFT 4 -#define VHT_SIGA1_GID_TO_AP 0x00 -#define VHT_SIGA1_GID_NOT_TO_AP 0x3f -#define VHT_SIGA1_GID_MAX_GID 0x3f - -#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 -#define VHT_SIGA1_NSTS_SHIFT 10 - -#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 -#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 - -#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 - -/* for VHT-A2 */ -#define VHT_SIGA2_GI_NONE 0x000000 -#define VHT_SIGA2_GI_SHORT 0x000001 -#define VHT_SIGA2_GI_W_MOD10 0x000002 -#define VHT_SIGA2_CODING_LDPC 0x000004 -#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 -#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 -#define VHT_SIGA2_MCS_SHIFT 4 - -#define VHT_SIGA2_B9_RESERVED 0x000200 -#define VHT_SIGA2_TAIL_MASK 0xfc0000 -#define VHT_SIGA2_TAIL_VALUE 0x000000 - -/* VHT Timing-related parameters (802.11ac D4.0, sec 22.3.6) */ -#define VHT_T_LEG_PREAMBLE 16 -#define VHT_T_L_SIG 4 -#define VHT_T_SIG_A 8 -#define VHT_T_LTF 4 -#define VHT_T_STF 4 -#define VHT_T_SIG_B 4 -#define VHT_T_SYML 4 - -#define VHT_N_SERVICE 16 /* bits in SERVICE field */ -#define VHT_N_TAIL 6 /* tail bits per BCC encoder */ - - -/** dot11Counters Table - 802.11 spec., Annex D */ -typedef struct d11cnt { - uint32 txfrag; /* dot11TransmittedFragmentCount */ - uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ - uint32 txfail; /* dot11FailedCount */ - uint32 txretry; /* dot11RetryCount */ - uint32 txretrie; /* dot11MultipleRetryCount */ - uint32 rxdup; /* dot11FrameduplicateCount */ - uint32 txrts; /* dot11RTSSuccessCount */ - uint32 txnocts; /* dot11RTSFailureCount */ - uint32 txnoack; /* dot11ACKFailureCount */ - uint32 rxfrag; /* dot11ReceivedFragmentCount */ - uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ - uint32 rxcrc; /* dot11FCSErrorCount */ - uint32 txfrmsnt; /* dot11TransmittedFrameCount */ - uint32 rxundec; /* dot11WEPUndecryptableCount */ -} d11cnt_t; - -#define BRCM_PROP_OUI "\x00\x90\x4C" - - -/* Action frame type for RWL */ -#define RWL_WIFI_DEFAULT 0 -#define RWL_WIFI_FIND_MY_PEER 9 /* Used while finding server */ -#define RWL_WIFI_FOUND_PEER 10 /* Server response to the client */ -#define RWL_ACTION_WIFI_FRAG_TYPE 85 /* Fragment indicator for receiver */ - -#define PROXD_AF_TYPE 11 /* Wifi proximity action frame type */ -#define BRCM_RELMACST_AF_TYPE 12 /* RMC action frame type */ - - -/* brcm syscap_ie cap */ -#define BRCM_SYSCAP_WET_TUNNEL 0x0100 /* Device with WET_TUNNEL support */ - -#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ - -/** BRCM info element */ -BWL_PRE_PACKED_STRUCT struct brcm_ie { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; - uint8 ver; /* type/ver of this IE */ - uint8 assoc; /* # of assoc STAs */ - uint8 flags; /* misc flags */ - uint8 flags1; /* misc flags */ - uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ -} BWL_POST_PACKED_STRUCT; -typedef struct brcm_ie brcm_ie_t; -#define BRCM_IE_LEN 11 /* BRCM IE length */ -#define BRCM_IE_VER 2 /* BRCM IE version */ -#define BRCM_IE_LEGACY_AES_VER 1 /* BRCM IE legacy AES version */ - -/* brcm_ie flags */ -#define BRF_ABCAP 0x1 /* afterburner is obsolete, defined for backward compat */ -#define BRF_ABRQRD 0x2 /* afterburner is obsolete, defined for backward compat */ -#define BRF_LZWDS 0x4 /* lazy wds enabled */ -#define BRF_BLOCKACK 0x8 /* BlockACK capable */ -#define BRF_ABCOUNTER_MASK 0xf0 /* afterburner is obsolete, defined for backward compat */ -#define BRF_PROP_11N_MCS 0x10 /* re-use afterburner bit */ - -#define GET_BRF_PROP_11N_MCS(brcm_ie) \ - (!((brcm_ie)->flags & BRF_ABCAP) && ((brcm_ie)->flags & BRF_PROP_11N_MCS)) - -/* brcm_ie flags1 */ -#define BRF1_AMSDU 0x1 /* A-MSDU capable */ -#define BRF1_WMEPS 0x4 /* AP is capable of handling WME + PS w/o APSD */ -#define BRF1_PSOFIX 0x8 /* AP has fixed PS mode out-of-order packets */ -#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ -#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ -#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ -#define BRF1_DWDS 0x80 /* DWDS capable */ - -/** Vendor IE structure */ -BWL_PRE_PACKED_STRUCT struct vndr_ie { - uchar id; - uchar len; - uchar oui [3]; - uchar data [1]; /* Variable size data */ -} BWL_POST_PACKED_STRUCT; -typedef struct vndr_ie vndr_ie_t; - -#define VNDR_IE_HDR_LEN 2 /* id + len field */ -#define VNDR_IE_MIN_LEN 3 /* size of the oui field */ -#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) - -#define VNDR_IE_MAX_LEN 255 /* vendor IE max length, without ID and len */ - -/** BRCM PROP DEVICE PRIMARY MAC ADDRESS IE */ -BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { - uchar id; - uchar len; - uchar oui[3]; - uint8 type; /* type indicates what follows */ - struct ether_addr ea; /* Device Primary MAC Adrress */ -} BWL_POST_PACKED_STRUCT; -typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; - -#define MEMBER_OF_BRCM_PROP_IE_LEN 10 /* IE max length */ -#define MEMBER_OF_BRCM_PROP_IE_HDRLEN (sizeof(member_of_brcm_prop_ie_t)) -#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 - -/** BRCM Reliable Multicast IE */ -BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { - uint8 id; - uint8 len; - uint8 oui[3]; - uint8 type; /* type indicates what follows */ - struct ether_addr ea; /* The ack sender's MAC Adrress */ - struct ether_addr mcast_ea; /* The multicast MAC address */ - uint8 updtmo; /* time interval(second) for client to send null packet to report its rssi */ -} BWL_POST_PACKED_STRUCT; -typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; - -/* IE length */ -/* BRCM_PROP_IE_LEN = sizeof(relmcast_brcm_prop_ie_t)-((sizeof (id) + sizeof (len)))? */ -#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-(2*sizeof(uint8))) - -#define RELMCAST_BRCM_PROP_IE_TYPE 55 - -/* ************* HT definitions. ************* */ -#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ -#define MAX_MCS_NUM (128) /* max mcs number = 128 */ - -BWL_PRE_PACKED_STRUCT struct ht_cap_ie { - uint16 cap; - uint8 params; - uint8 supp_mcs[MCSSET_LEN]; - uint16 ext_htcap; - uint32 txbf_cap; - uint8 as_cap; -} BWL_POST_PACKED_STRUCT; -typedef struct ht_cap_ie ht_cap_ie_t; - -BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { - uint8 id; - uint8 len; - ht_cap_ie_t ht_cap; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; - -/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ -/* the capability IE is primarily used to convey this nodes abilities */ -BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; - uint8 type; /* type indicates what follows */ - ht_cap_ie_t cap_ie; -} BWL_POST_PACKED_STRUCT; -typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; - -#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ -#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */ -#define HT_CAP_IE_TYPE 51 - -#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ -#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ -#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ -#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ -#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ -#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ -#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ -#define HT_CAP_GF 0x0010 /* Greenfield preamble support */ -#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ -#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ -#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */ -#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ -#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ -#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */ -#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ - -#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ -#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ -#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ -#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ - -#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ -#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ -#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ -#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ - - -#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 -#define HT_CAP_TXBF_CAP_NDP_RX 0x8 -#define HT_CAP_TXBF_CAP_NDP_TX 0x10 -#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 -#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 -#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 -#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 -#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 -#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 -#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 -#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 -#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 -#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 -#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 -#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 -#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 - -#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 -#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 - -#define HT_CAP_TXBF_FB_TYPE_NONE 0 -#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 -#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 -#define HT_CAP_TXBF_FB_TYPE_BOTH 3 - -#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400 -#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10 -#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000 -#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15 - -#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ -#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ -/* Max AMSDU len - per spec */ -#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) - -#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */ -#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */ - -#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ -#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ -#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ - -/* HT/AMPDU specific define */ -#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */ -#define AMPDU_DENSITY_NONE 0 /* No density requirement */ -#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */ -#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */ -#define AMPDU_DENSITY_1_US 3 /* 1 us density */ -#define AMPDU_DENSITY_2_US 4 /* 2 us density */ -#define AMPDU_DENSITY_4_US 5 /* 4 us density */ -#define AMPDU_DENSITY_8_US 6 /* 8 us density */ -#define AMPDU_DENSITY_16_US 7 /* 16 us density */ -#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */ -#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */ -#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */ -#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */ - -/* AMPDU RX factors for VHT rates */ -#define AMPDU_RX_FACTOR_128K 4 /* max rcv ampdu len (128kb) */ -#define AMPDU_RX_FACTOR_256K 5 /* max rcv ampdu len (256kb) */ -#define AMPDU_RX_FACTOR_512K 6 /* max rcv ampdu len (512kb) */ -#define AMPDU_RX_FACTOR_1024K 7 /* max rcv ampdu len (1024kb) */ - -#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ -#define AMPDU_RX_FACTOR_BASE_PWR 13 /* ampdu factor base for rx len in power of 2 */ - -#define AMPDU_DELIMITER_LEN 4 /* length of ampdu delimiter */ -#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */ - -#define HT_CAP_EXT_PCO 0x0001 -#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 -#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 -#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 -#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 -#define HT_CAP_EXT_HTC 0x0400 -#define HT_CAP_EXT_RD_RESP 0x0800 - -/** 'ht_add' is called 'HT Operation' information element in the 802.11 standard */ -BWL_PRE_PACKED_STRUCT struct ht_add_ie { - uint8 ctl_ch; /* control channel number */ - uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ - uint16 opmode; /* operation mode */ - uint16 misc_bits; /* misc bits */ - uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ -} BWL_POST_PACKED_STRUCT; -typedef struct ht_add_ie ht_add_ie_t; - -/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ -/* the additional IE is primarily used to convey the current BSS configuration */ -BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; - uint8 type; /* indicates what follows */ - ht_add_ie_t add_ie; -} BWL_POST_PACKED_STRUCT; -typedef struct ht_prop_add_ie ht_prop_add_ie_t; - -#define HT_ADD_IE_LEN 22 -#define HT_ADD_IE_TYPE 52 - -/* byte1 defn's */ -#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ -#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */ - -/* opmode defn's */ -#define HT_OPMODE_MASK 0x0003 /* protection mode mask */ -#define HT_OPMODE_SHIFT 0 /* protection mode shift */ -#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */ -#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ -#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ -#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ -#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ -#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ -#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ - -/* misc_bites defn's */ -#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ -#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ -#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */ -#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ -#define HT_PCO_ACTIVE 0x0400 /* PCO active */ -#define HT_PCO_PHASE 0x0800 /* PCO phase */ -#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */ - -/* Tx Burst Limits */ -#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ -#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ - -/* Macros for opmode */ -#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - >> HT_OPMODE_SHIFT) -#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_MIXED) /* mixed mode present */ -#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_HT20IN40) /* 20MHz HT present */ -#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_OPTIONAL) /* Optional protection present */ -#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ - HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */ -#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ - == HT_OPMODE_NONGF) /* non-GF present */ -#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ - == DOT11N_TXBURST) /* Tx Burst present */ -#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ - == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ - -BWL_PRE_PACKED_STRUCT struct obss_params { - uint16 passive_dwell; - uint16 active_dwell; - uint16 bss_widthscan_interval; - uint16 passive_total; - uint16 active_total; - uint16 chanwidth_transition_dly; - uint16 activity_threshold; -} BWL_POST_PACKED_STRUCT; -typedef struct obss_params obss_params_t; - -BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { - uint8 id; - uint8 len; - obss_params_t obss_params; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_obss_ie dot11_obss_ie_t; -#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */ - -/* HT control field */ -#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */ -#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */ -#define HT_CTRL_LA_MAI_SHIFT 2 -#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */ -#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */ -#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */ -#define HT_CTRL_LA_MFSI_SHIFT 6 -#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */ -#define HT_CTRL_LA_MFB_ASELC_SH 9 -#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */ -#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */ -#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */ -#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */ -#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */ -#define HT_CTRL_CSI_STEER_SHIFT 22 -#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */ -#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */ -#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */ -#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */ -#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */ -#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */ -#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */ - -/* ************* VHT definitions. ************* */ - -/** - * VHT Capabilites IE (sec 8.4.2.160) - */ - -BWL_PRE_PACKED_STRUCT struct vht_cap_ie { - uint32 vht_cap_info; - /* supported MCS set - 64 bit field */ - uint16 rx_mcs_map; - uint16 rx_max_rate; - uint16 tx_mcs_map; - uint16 tx_max_rate; -} BWL_POST_PACKED_STRUCT; -typedef struct vht_cap_ie vht_cap_ie_t; - -/* 4B cap_info + 8B supp_mcs */ -#define VHT_CAP_IE_LEN 12 - -/* VHT Capabilities Info field - 32bit - in VHT Cap IE */ -#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 -#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c -#define VHT_CAP_INFO_LDPC 0x00000010 -#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 -#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 -#define VHT_CAP_INFO_TX_STBC 0x00000080 -#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 -#define VHT_CAP_INFO_RX_STBC_SHIFT 8 -#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 -#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 -#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 -#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 -#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 -#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 -#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 -#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 -#define VHT_CAP_INFO_TXOPPS 0x00200000 -#define VHT_CAP_INFO_HTCVHT 0x00400000 -#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 -#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 -#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 -#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 - -/* VHT Supported MCS Set - 64-bit - in VHT Cap IE */ -#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff -#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 - -#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff -#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 - -#define VHT_CAP_MCS_MAP_0_7 0 -#define VHT_CAP_MCS_MAP_0_8 1 -#define VHT_CAP_MCS_MAP_0_9 2 -#define VHT_CAP_MCS_MAP_NONE 3 -#define VHT_CAP_MCS_MAP_S 2 /* num bits for 1-stream */ -#define VHT_CAP_MCS_MAP_M 0x3 /* mask for 1-stream */ -/* assumes VHT_CAP_MCS_MAP_NONE is 3 and 2 bits are used for encoding */ -#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff -/* mcsmap with MCS0-9 for Nss = 3 */ -#define VHT_CAP_MCS_MAP_0_9_NSS3 \ - ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ - (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ - (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) - -#define VHT_CAP_MCS_MAP_NSS_MAX 8 - -/* get mcsmap with given mcs for given nss streams */ -#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ - do { \ - int i; \ - for (i = 1; i <= nss; i++) { \ - VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ - } \ - } while (0) - -/* Map the mcs code to mcs bit map */ -#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ - ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? 0xff : \ - (mcs_code == VHT_CAP_MCS_MAP_0_8) ? 0x1ff : \ - (mcs_code == VHT_CAP_MCS_MAP_0_9) ? 0x3ff : 0) - -/* Map the mcs bit map to mcs code */ -#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ - ((mcs_map == 0xff) ? VHT_CAP_MCS_MAP_0_7 : \ - (mcs_map == 0x1ff) ? VHT_CAP_MCS_MAP_0_8 : \ - (mcs_map == 0x3ff) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) - -/** VHT Capabilities Supported Channel Width */ -typedef enum vht_cap_chan_width { - VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, - VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, - VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 -} vht_cap_chan_width_t; - -/** VHT Capabilities Supported max MPDU LEN (sec 8.4.2.160.2) */ -typedef enum vht_cap_max_mpdu_len { - VHT_CAP_MPDU_MAX_4K = 0x00, - VHT_CAP_MPDU_MAX_8K = 0x01, - VHT_CAP_MPDU_MAX_11K = 0x02 -} vht_cap_max_mpdu_len_t; - -/* Maximum MPDU Length byte counts for the VHT Capabilities advertised limits */ -#define VHT_MPDU_LIMIT_4K 3895 -#define VHT_MPDU_LIMIT_8K 7991 -#define VHT_MPDU_LIMIT_11K 11454 - - -/** - * VHT Operation IE (sec 8.4.2.161) - */ - -BWL_PRE_PACKED_STRUCT struct vht_op_ie { - uint8 chan_width; - uint8 chan1; - uint8 chan2; - uint16 supp_mcs; /* same def as above in vht cap */ -} BWL_POST_PACKED_STRUCT; -typedef struct vht_op_ie vht_op_ie_t; - -/* 3B VHT Op info + 2B Basic MCS */ -#define VHT_OP_IE_LEN 5 - -typedef enum vht_op_chan_width { - VHT_OP_CHAN_WIDTH_20_40 = 0, - VHT_OP_CHAN_WIDTH_80 = 1, - VHT_OP_CHAN_WIDTH_160 = 2, - VHT_OP_CHAN_WIDTH_80_80 = 3 -} vht_op_chan_width_t; - -/* AID length */ -#define AID_IE_LEN 2 -/** - * BRCM vht features IE header - * The header if the fixed part of the IE - * On the 5GHz band this is the entire IE, - * on 2.4GHz the VHT IEs as defined in the 802.11ac - * specification follows - * - * - * VHT features rates bitmap. - * Bit0: 5G MCS 0-9 BW 160MHz - * Bit1: 5G MCS 0-9 support BW 80MHz - * Bit2: 5G MCS 0-9 support BW 20MHz - * Bit3: 2.4G MCS 0-9 support BW 20MHz - * Bits:4-7 Reserved for future use - * - */ -#define VHT_FEATURES_IE_TYPE 0x4 -BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { - uint8 oui[3]; - uint8 type; /* type of this IE = 4 */ - uint8 rate_mask; /* VHT rate mask */ -} BWL_POST_PACKED_STRUCT; -typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; - -/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ -#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) -#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ - (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) -#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ - do { \ - (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ - (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ - } while (0) -#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ - (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) - - -/* ************* WPA definitions. ************* */ -#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ -#define WPA_OUI_LEN 3 /* WPA OUI length */ -#define WPA_OUI_TYPE 1 -#define WPA_VERSION 1 /* WPA version */ -#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ -#define WPA2_OUI_LEN 3 /* WPA2 OUI length */ -#define WPA2_VERSION 1 /* WPA2 version */ -#define WPA2_VERSION_LEN 2 /* WAP2 version length */ - -/* ************* WPS definitions. ************* */ -#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */ -#define WPS_OUI_LEN 3 /* WPS OUI length */ -#define WPS_OUI_TYPE 4 - -/* ************* WFA definitions. ************* */ - -#ifdef P2P_IE_OVRD -#define WFA_OUI MAC_OUI -#else -#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */ -#endif /* P2P_IE_OVRD */ -#define WFA_OUI_LEN 3 /* WFA OUI length */ -#ifdef P2P_IE_OVRD -#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P -#else -#define WFA_OUI_TYPE_TPC 8 -#define WFA_OUI_TYPE_P2P 9 -#endif - -#define WFA_OUI_TYPE_TPC 8 -#ifdef WLTDLS -#define WFA_OUI_TYPE_TPQ 4 /* WFD Tunneled Probe ReQuest */ -#define WFA_OUI_TYPE_TPS 5 /* WFD Tunneled Probe ReSponse */ -#define WFA_OUI_TYPE_WFD 10 -#endif /* WTDLS */ -#define WFA_OUI_TYPE_HS20 0x10 -#define WFA_OUI_TYPE_OSEN 0x12 -#define WFA_OUI_TYPE_NAN 0x13 - -/* RSN authenticated key managment suite */ -#define RSN_AKM_NONE 0 /* None (IBSS) */ -#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ -#define RSN_AKM_PSK 2 /* Pre-shared Key */ -#define RSN_AKM_FBT_1X 3 /* Fast Bss transition using 802.1X */ -#define RSN_AKM_FBT_PSK 4 /* Fast Bss transition using Pre-shared Key */ -#define RSN_AKM_MFP_1X 5 /* SHA256 key derivation, using 802.1X */ -#define RSN_AKM_MFP_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ -#define RSN_AKM_TPK 7 /* TPK(TDLS Peer Key) handshake */ - -/* OSEN authenticated key managment suite */ -#define OSEN_AKM_UNSPECIFIED RSN_AKM_UNSPECIFIED /* Over 802.1x */ - -/* Key related defines */ -#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */ -#define DOT11_MAX_IGTK_KEYS 2 -#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */ -#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */ -#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */ -#define DOT11_WPA_KEY_RSC_LEN 8 /* WPA RSC key len */ - -#define WEP1_KEY_SIZE 5 /* max size of any WEP key */ -#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */ -#define WEP128_KEY_SIZE 13 /* max size of any WEP key */ -#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */ -#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */ -#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */ -#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */ -#define TKIP_KEY_SIZE 32 /* size of any TKIP key, includs MIC keys */ -#define TKIP_TK_SIZE 16 -#define TKIP_MIC_KEY_SIZE 8 -#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */ -#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */ -#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX /* offset to Supplicant MIC RX key */ -#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX /* offset to Supplicant MIC TX key */ -#define AES_KEY_SIZE 16 /* size of AES key */ -#define AES_MIC_SIZE 8 /* size of AES MIC */ -#define BIP_KEY_SIZE 16 /* size of BIP key */ -#define BIP_MIC_SIZE 8 /* sizeof BIP MIC */ - -#define AES_GCM_MIC_SIZE 16 /* size of MIC for 128-bit GCM - .11adD9 */ - -#define AES256_KEY_SIZE 32 /* size of AES 256 key - .11acD5 */ -#define AES256_MIC_SIZE 16 /* size of MIC for 256 bit keys, incl BIP */ - -/* WCN */ -#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ -#define WCN_TYPE 4 /* WCN type */ - -#ifdef BCMWAPI_WPI -#define SMS4_KEY_LEN 16 -#define SMS4_WPI_CBC_MAC_LEN 16 -#endif - -/* 802.11r protocol definitions */ - -/** Mobility Domain IE */ -BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { - uint8 id; - uint8 len; - uint16 mdid; /* Mobility Domain Id */ - uint8 cap; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_mdid_ie dot11_mdid_ie_t; - -#define FBT_MDID_CAP_OVERDS 0x01 /* Fast Bss transition over the DS support */ -#define FBT_MDID_CAP_RRP 0x02 /* Resource request protocol support */ - -/** Fast Bss Transition IE */ -BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { - uint8 id; - uint8 len; - uint16 mic_control; /* Mic Control */ - uint8 mic[16]; - uint8 anonce[32]; - uint8 snonce[32]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ft_ie dot11_ft_ie_t; - -#define TIE_TYPE_RESERVED 0 -#define TIE_TYPE_REASSOC_DEADLINE 1 -#define TIE_TYPE_KEY_LIEFTIME 2 -#define TIE_TYPE_ASSOC_COMEBACK 3 -BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { - uint8 id; - uint8 len; - uint8 type; /* timeout interval type */ - uint32 value; /* timeout interval value */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timeout_ie dot11_timeout_ie_t; - -/** GTK ie */ -BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { - uint8 id; - uint8 len; - uint16 key_info; - uint8 key_len; - uint8 rsc[8]; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_gtk_ie dot11_gtk_ie_t; - -/** Management MIC ie */ -BWL_PRE_PACKED_STRUCT struct mmic_ie { - uint8 id; /* IE ID: DOT11_MNG_MMIE_ID */ - uint8 len; /* IE length */ - uint16 key_id; /* key id */ - uint8 ipn[6]; /* ipn */ - uint8 mic[16]; /* mic */ -} BWL_POST_PACKED_STRUCT; -typedef struct mmic_ie mmic_ie_t; - -#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" -#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" - -#ifdef BCMWAPI_WAI -#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */ -#define WAPI_VERSION 1 /* WAPI version */ -#define WAPI_VERSION_LEN 2 /* WAPI version length */ -#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */ -#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */ -#endif /* BCMWAPI_WAI */ - -/* ************* WMM Parameter definitions. ************* */ -#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */ -#define WMM_OUI_LEN 3 /* WMM OUI length */ -#define WMM_OUI_TYPE 2 /* WMM OUT type */ -#define WMM_VERSION 1 -#define WMM_VERSION_LEN 1 - -/* WMM OUI subtype */ -#define WMM_OUI_SUBTYPE_PARAMETER 1 -#define WMM_PARAMETER_IE_LEN 24 - -/** Link Identifier Element */ -BWL_PRE_PACKED_STRUCT struct link_id_ie { - uint8 id; - uint8 len; - struct ether_addr bssid; - struct ether_addr tdls_init_mac; - struct ether_addr tdls_resp_mac; -} BWL_POST_PACKED_STRUCT; -typedef struct link_id_ie link_id_ie_t; -#define TDLS_LINK_ID_IE_LEN 18 - -/** Link Wakeup Schedule Element */ -BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { - uint8 id; - uint8 len; - uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */ - uint32 interval; /* in ms bwtween the start of 2 Awake Windows */ - uint32 awake_win_slots; /* in backof slots, duration of Awake Window */ - uint32 max_wake_win; /* in ms, max duration of Awake Window */ - uint16 idle_cnt; /* number of consecutive Awake Windows */ -} BWL_POST_PACKED_STRUCT; -typedef struct wakeup_sch_ie wakeup_sch_ie_t; -#define TDLS_WAKEUP_SCH_IE_LEN 18 - -/** Channel Switch Timing Element */ -BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { - uint8 id; - uint8 len; - uint16 switch_time; /* in ms, time to switch channels */ - uint16 switch_timeout; /* in ms */ -} BWL_POST_PACKED_STRUCT; -typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; -#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 - -/** PTI Control Element */ -BWL_PRE_PACKED_STRUCT struct pti_control_ie { - uint8 id; - uint8 len; - uint8 tid; - uint16 seq_control; -} BWL_POST_PACKED_STRUCT; -typedef struct pti_control_ie pti_control_ie_t; -#define TDLS_PTI_CONTROL_IE_LEN 3 - -/** PU Buffer Status Element */ -BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { - uint8 id; - uint8 len; - uint8 status; -} BWL_POST_PACKED_STRUCT; -typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; -#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 -#define TDLS_PU_BUFFER_STATUS_AC_BK 1 -#define TDLS_PU_BUFFER_STATUS_AC_BE 2 -#define TDLS_PU_BUFFER_STATUS_AC_VI 4 -#define TDLS_PU_BUFFER_STATUS_AC_VO 8 - -/* TDLS Action Field Values */ -#define TDLS_SETUP_REQ 0 -#define TDLS_SETUP_RESP 1 -#define TDLS_SETUP_CONFIRM 2 -#define TDLS_TEARDOWN 3 -#define TDLS_PEER_TRAFFIC_IND 4 -#define TDLS_CHANNEL_SWITCH_REQ 5 -#define TDLS_CHANNEL_SWITCH_RESP 6 -#define TDLS_PEER_PSM_REQ 7 -#define TDLS_PEER_PSM_RESP 8 -#define TDLS_PEER_TRAFFIC_RESP 9 -#define TDLS_DISCOVERY_REQ 10 - -/* 802.11z TDLS Public Action Frame action field */ -#define TDLS_DISCOVERY_RESP 14 - -/* 802.11u GAS action frames */ -#define GAS_REQUEST_ACTION_FRAME 10 -#define GAS_RESPONSE_ACTION_FRAME 11 -#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 -#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 - -/* 802.11u interworking access network options */ -#define IW_ANT_MASK 0x0f -#define IW_INTERNET_MASK 0x10 -#define IW_ASRA_MASK 0x20 -#define IW_ESR_MASK 0x40 -#define IW_UESA_MASK 0x80 - -/* 802.11u interworking access network type */ -#define IW_ANT_PRIVATE_NETWORK 0 -#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 -#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 -#define IW_ANT_FREE_PUBLIC_NETWORK 3 -#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 -#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 -#define IW_ANT_TEST_NETWORK 14 -#define IW_ANT_WILDCARD_NETWORK 15 - -/* 802.11u advertisement protocol */ -#define ADVP_ANQP_PROTOCOL_ID 0 - -/* 802.11u advertisement protocol masks */ -#define ADVP_QRL_MASK 0x7f -#define ADVP_PAME_BI_MASK 0x80 - -/* 802.11u advertisement protocol values */ -#define ADVP_QRL_REQUEST 0x00 -#define ADVP_QRL_RESPONSE 0x7f -#define ADVP_PAME_BI_DEPENDENT 0x00 -#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK - -/* 802.11u ANQP information ID */ -#define ANQP_ID_QUERY_LIST 256 -#define ANQP_ID_CAPABILITY_LIST 257 -#define ANQP_ID_VENUE_NAME_INFO 258 -#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 -#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 -#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 -#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 -#define ANQP_ID_NAI_REALM_LIST 263 -#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 -#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 -#define ANQP_ID_AP_CIVIC_LOCATION 266 -#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 -#define ANQP_ID_DOMAIN_NAME_LIST 268 -#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 -#define ANQP_ID_EMERGENCY_NAI 271 -#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 - -/* 802.11u ANQP OUI */ -#define ANQP_OUI_SUBTYPE 9 - -/* 802.11u venue name */ -#define VENUE_LANGUAGE_CODE_SIZE 3 -#define VENUE_NAME_SIZE 255 - -/* 802.11u venue groups */ -#define VENUE_UNSPECIFIED 0 -#define VENUE_ASSEMBLY 1 -#define VENUE_BUSINESS 2 -#define VENUE_EDUCATIONAL 3 -#define VENUE_FACTORY 4 -#define VENUE_INSTITUTIONAL 5 -#define VENUE_MERCANTILE 6 -#define VENUE_RESIDENTIAL 7 -#define VENUE_STORAGE 8 -#define VENUE_UTILITY 9 -#define VENUE_VEHICULAR 10 -#define VENUE_OUTDOOR 11 - -/* 802.11u network authentication type indicator */ -#define NATI_UNSPECIFIED -1 -#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 -#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 -#define NATI_HTTP_HTTPS_REDIRECTION 2 -#define NATI_DNS_REDIRECTION 3 - -/* 802.11u IP address type availability - IPv6 */ -#define IPA_IPV6_SHIFT 0 -#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) -#define IPA_IPV6_NOT_AVAILABLE 0x00 -#define IPA_IPV6_AVAILABLE 0x01 -#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 - -/* 802.11u IP address type availability - IPv4 */ -#define IPA_IPV4_SHIFT 2 -#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) -#define IPA_IPV4_NOT_AVAILABLE 0x00 -#define IPA_IPV4_PUBLIC 0x01 -#define IPA_IPV4_PORT_RESTRICT 0x02 -#define IPA_IPV4_SINGLE_NAT 0x03 -#define IPA_IPV4_DOUBLE_NAT 0x04 -#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 -#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 -#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 - -/* 802.11u NAI realm encoding */ -#define REALM_ENCODING_RFC4282 0 -#define REALM_ENCODING_UTF8 1 - -/* 802.11u IANA EAP method type numbers */ -#define REALM_EAP_TLS 13 -#define REALM_EAP_LEAP 17 -#define REALM_EAP_SIM 18 -#define REALM_EAP_TTLS 21 -#define REALM_EAP_AKA 23 -#define REALM_EAP_PEAP 25 -#define REALM_EAP_FAST 43 -#define REALM_EAP_PSK 47 -#define REALM_EAP_AKAP 50 -#define REALM_EAP_EXPANDED 254 - -/* 802.11u authentication ID */ -#define REALM_EXPANDED_EAP 1 -#define REALM_NON_EAP_INNER_AUTHENTICATION 2 -#define REALM_INNER_AUTHENTICATION_EAP 3 -#define REALM_EXPANDED_INNER_EAP 4 -#define REALM_CREDENTIAL 5 -#define REALM_TUNNELED_EAP_CREDENTIAL 6 -#define REALM_VENDOR_SPECIFIC_EAP 221 - -/* 802.11u non-EAP inner authentication type */ -#define REALM_RESERVED_AUTH 0 -#define REALM_PAP 1 -#define REALM_CHAP 2 -#define REALM_MSCHAP 3 -#define REALM_MSCHAPV2 4 - -/* 802.11u credential type */ -#define REALM_SIM 1 -#define REALM_USIM 2 -#define REALM_NFC 3 -#define REALM_HARDWARE_TOKEN 4 -#define REALM_SOFTOKEN 5 -#define REALM_CERTIFICATE 6 -#define REALM_USERNAME_PASSWORD 7 -#define REALM_SERVER_SIDE 8 -#define REALM_RESERVED_CRED 9 -#define REALM_VENDOR_SPECIFIC_CRED 10 - -/* 802.11u 3GPP PLMN */ -#define G3PP_GUD_VERSION 0 -#define G3PP_PLMN_LIST_IE 0 - -/** hotspot2.0 indication element (vendor specific) */ -BWL_PRE_PACKED_STRUCT struct hs20_ie { - uint8 oui[3]; - uint8 type; - uint8 config; -} BWL_POST_PACKED_STRUCT; -typedef struct hs20_ie hs20_ie_t; -#define HS20_IE_LEN 5 /* HS20 IE length */ - -/** IEEE 802.11 Annex E */ -typedef enum { - DOT11_2GHZ_20MHZ_CLASS_12 = 81, /* Ch 1-11 */ - DOT11_5GHZ_20MHZ_CLASS_1 = 115, /* Ch 36-48 */ - DOT11_5GHZ_20MHZ_CLASS_2_DFS = 118, /* Ch 52-64 */ - DOT11_5GHZ_20MHZ_CLASS_3 = 124, /* Ch 149-161 */ - DOT11_5GHZ_20MHZ_CLASS_4_DFS = 121, /* Ch 100-140 */ - DOT11_5GHZ_20MHZ_CLASS_5 = 125, /* Ch 149-165 */ - DOT11_5GHZ_40MHZ_CLASS_22 = 116, /* Ch 36-44, lower */ - DOT11_5GHZ_40MHZ_CLASS_23_DFS = 119, /* Ch 52-60, lower */ - DOT11_5GHZ_40MHZ_CLASS_24_DFS = 122, /* Ch 100-132, lower */ - DOT11_5GHZ_40MHZ_CLASS_25 = 126, /* Ch 149-157, lower */ - DOT11_5GHZ_40MHZ_CLASS_27 = 117, /* Ch 40-48, upper */ - DOT11_5GHZ_40MHZ_CLASS_28_DFS = 120, /* Ch 56-64, upper */ - DOT11_5GHZ_40MHZ_CLASS_29_DFS = 123, /* Ch 104-136, upper */ - DOT11_5GHZ_40MHZ_CLASS_30 = 127, /* Ch 153-161, upper */ - DOT11_2GHZ_40MHZ_CLASS_32 = 83, /* Ch 1-7, lower */ - DOT11_2GHZ_40MHZ_CLASS_33 = 84, /* Ch 5-11, upper */ -} dot11_op_class_t; - -/* QoS map */ -#define QOS_MAP_FIXED_LENGTH (8 * 2) /* DSCP ranges fixed with 8 entries */ - -#define BCM_AIBSS_IE_TYPE 56 - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _802_11_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h deleted file mode 100644 index 9de5616ab024..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: 802.11_bta.h 382882 2013-02-04 23:24:31Z $ -*/ - -#ifndef _802_11_BTA_H_ -#define _802_11_BTA_H_ - -#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58" - -/* BT-AMP 802.11 PAL Protocols */ -#define BTA_PROT_L2CAP 1 -#define BTA_PROT_ACTIVITY_REPORT 2 -#define BTA_PROT_SECURITY 3 -#define BTA_PROT_LINK_SUPERVISION_REQUEST 4 -#define BTA_PROT_LINK_SUPERVISION_REPLY 5 - -/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */ -#define BTA_TYPE_ID_MAC_ADDRESS 1 -#define BTA_TYPE_ID_PREFERRED_CHANNELS 2 -#define BTA_TYPE_ID_CONNECTED_CHANNELS 3 -#define BTA_TYPE_ID_CAPABILITIES 4 -#define BTA_TYPE_ID_VERSION 5 -#endif /* _802_11_bta_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h deleted file mode 100644 index ded6b7612415..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 802.11e protocol header file - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: 802.11e.h 382883 2013-02-04 23:26:09Z $ - */ - -#ifndef _802_11e_H_ -#define _802_11e_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - - -/* WME Traffic Specification (TSPEC) element */ -#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ -#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ - -#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ -#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ -#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ -#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ - -BWL_PRE_PACKED_STRUCT struct tsinfo { - uint8 octets[3]; -} BWL_POST_PACKED_STRUCT; - -typedef struct tsinfo tsinfo_t; - -/* 802.11e TSPEC IE */ -typedef BWL_PRE_PACKED_STRUCT struct tspec { - uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ - uint8 type; /* WME_TYPE */ - uint8 subtype; /* WME_SUBTYPE_TSPEC */ - uint8 version; /* WME_VERSION */ - tsinfo_t tsinfo; /* TS Info bit field */ - uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ - uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ - uint32 min_srv_interval; /* Minimum Service Interval (us) */ - uint32 max_srv_interval; /* Maximum Service Interval (us) */ - uint32 inactivity_interval; /* Inactivity Interval (us) */ - uint32 suspension_interval; /* Suspension Interval (us) */ - uint32 srv_start_time; /* Service Start Time (us) */ - uint32 min_data_rate; /* Minimum Data Rate (bps) */ - uint32 mean_data_rate; /* Mean Data Rate (bps) */ - uint32 peak_data_rate; /* Peak Data Rate (bps) */ - uint32 max_burst_size; /* Maximum Burst Size (bytes) */ - uint32 delay_bound; /* Delay Bound (us) */ - uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ - uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ - uint16 medium_time; /* Medium Time (32 us/s periods) */ -} BWL_POST_PACKED_STRUCT tspec_t; - -#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ - -/* ts_info */ -/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ -#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ -#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ -#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ -#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ -#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ -#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ -#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ -#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ -#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ -#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ -#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ -#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ -/* TS info. user priority mask */ -#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) - -/* Macro to get/set bit(s) field in TSINFO */ -#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) -#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ - TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) -#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) -#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ - TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) - -#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ - ((id) << TS_INFO_TID_SHIFT)) -#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ - ((prio) << TS_INFO_USER_PRIO_SHIFT)) - -/* 802.11e QBSS Load IE */ -#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ -#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ - -#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */ - /* DEFVAL dot11ADDTSResponseTimeout = 1s */ - -/* 802.11e ADDTS status code */ -#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ -#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ -#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ -#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ -#ifdef BCMCCX -#define CCX_STATUS_ASSOC_DENIED_UNKNOWN 0xc8 /* unspecified QoS related failure */ -#define CCX_STATUS_ASSOC_DENIED_AP_POLICY 0xc9 /* TSPEC refused due to AP policy */ -#define CCX_STATUS_ASSOC_DENIED_NO_BW 0xca /* Assoc denied due to AP insufficient BW */ -#define CCX_STATUS_ASSOC_DENIED_BAD_PARAM 0xcb /* one or more TSPEC with invalid parameter */ -#endif /* BCMCCX */ - -/* 802.11e DELTS status code */ -#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ -#define DOT11E_STATUS_END_TS 37 /* END TS */ -#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ -#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ - - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _802_11e_CAC_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h deleted file mode 100644 index efb390bfc09e..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental types and constants relating to 802.1D - * - * $Id: 802.1d.h 382882 2013-02-04 23:24:31Z $ - */ - -#ifndef _802_1_D_ -#define _802_1_D_ - -/* 802.1D priority defines */ -#define PRIO_8021D_NONE 2 /* None = - */ -#define PRIO_8021D_BK 1 /* BK - Background */ -#define PRIO_8021D_BE 0 /* BE - Best-effort */ -#define PRIO_8021D_EE 3 /* EE - Excellent-effort */ -#define PRIO_8021D_CL 4 /* CL - Controlled Load */ -#define PRIO_8021D_VI 5 /* Vi - Video */ -#define PRIO_8021D_VO 6 /* Vo - Voice */ -#define PRIO_8021D_NC 7 /* NC - Network Control */ -#define MAXPRIO 7 /* 0-7 */ -#define NUMPRIO (MAXPRIO + 1) - -#define ALLPRIO -1 /* All prioirty */ - -/* Converts prio to precedence since the numerical value of - * PRIO_8021D_BE and PRIO_8021D_NONE are swapped. - */ -#define PRIO2PREC(prio) \ - (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) - -#endif /* _802_1_D__ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.3.h b/drivers/net/wireless/bcmdhd/include/proto/802.3.h deleted file mode 100644 index dc1626aa667a..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/802.3.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental constants relating to 802.3 - * - * $Id: 802.3.h 417943 2013-08-13 07:54:04Z $ - */ - -#ifndef _802_3_h_ -#define _802_3_h_ - -/* This marks the start of a packed structure section. */ -#include - -#define SNAP_HDR_LEN 6 /* 802.3 SNAP header length */ -#define DOT3_OUI_LEN 3 /* 802.3 oui length */ - -BWL_PRE_PACKED_STRUCT struct dot3_mac_llc_snap_header { - uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ - uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ - uint16 length; /* frame length incl header */ - uint8 dsap; /* always 0xAA */ - uint8 ssap; /* always 0xAA */ - uint8 ctl; /* always 0x03 */ - uint8 oui[DOT3_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 - * Bridge-Tunnel: 0x00 0x00 0xF8 - */ - uint16 type; /* ethertype */ -} BWL_POST_PACKED_STRUCT; - -/* This marks the end of a packed structure section. */ -#include - -#endif /* #ifndef _802_3_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h b/drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h deleted file mode 100644 index 1e4bff7d9ed0..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental constants relating to DHCP Protocol - * - * $Id: bcmdhcp.h 528443 2015-01-22 09:29:18Z $ - */ - -#ifndef _bcmdhcp_h_ -#define _bcmdhcp_h_ - -/* DHCP params */ -#define DHCP_TYPE_OFFSET 0 /* DHCP type (request|reply) offset */ -#define DHCP_TID_OFFSET 4 /* DHCP transition id offset */ -#define DHCP_FLAGS_OFFSET 10 /* DHCP flags offset */ -#define DHCP_CIADDR_OFFSET 12 /* DHCP client IP address offset */ -#define DHCP_YIADDR_OFFSET 16 /* DHCP your IP address offset */ -#define DHCP_GIADDR_OFFSET 24 /* DHCP relay agent IP address offset */ -#define DHCP_CHADDR_OFFSET 28 /* DHCP client h/w address offset */ -#define DHCP_OPT_OFFSET 236 /* DHCP options offset */ - -#define DHCP_OPT_MSGTYPE 53 /* DHCP message type */ -#define DHCP_OPT_MSGTYPE_REQ 3 -#define DHCP_OPT_MSGTYPE_ACK 5 /* DHCP message type - ACK */ - -#define DHCP_OPT_CODE_OFFSET 0 /* Option identifier */ -#define DHCP_OPT_LEN_OFFSET 1 /* Option data length */ -#define DHCP_OPT_DATA_OFFSET 2 /* Option data */ - -#define DHCP_OPT_CODE_CLIENTID 61 /* Option identifier */ - -#define DHCP_TYPE_REQUEST 1 /* DHCP request (discover|request) */ -#define DHCP_TYPE_REPLY 2 /* DHCP reply (offset|ack) */ - -#define DHCP_PORT_SERVER 67 /* DHCP server UDP port */ -#define DHCP_PORT_CLIENT 68 /* DHCP client UDP port */ - -#define DHCP_FLAG_BCAST 0x8000 /* DHCP broadcast flag */ - -#define DHCP_FLAGS_LEN 2 /* DHCP flags field length */ - -#define DHCP6_TYPE_SOLICIT 1 /* DHCP6 solicit */ -#define DHCP6_TYPE_ADVERTISE 2 /* DHCP6 advertise */ -#define DHCP6_TYPE_REQUEST 3 /* DHCP6 request */ -#define DHCP6_TYPE_CONFIRM 4 /* DHCP6 confirm */ -#define DHCP6_TYPE_RENEW 5 /* DHCP6 renew */ -#define DHCP6_TYPE_REBIND 6 /* DHCP6 rebind */ -#define DHCP6_TYPE_REPLY 7 /* DHCP6 reply */ -#define DHCP6_TYPE_RELEASE 8 /* DHCP6 release */ -#define DHCP6_TYPE_DECLINE 9 /* DHCP6 decline */ -#define DHCP6_TYPE_RECONFIGURE 10 /* DHCP6 reconfigure */ -#define DHCP6_TYPE_INFOREQ 11 /* DHCP6 information request */ -#define DHCP6_TYPE_RELAYFWD 12 /* DHCP6 relay forward */ -#define DHCP6_TYPE_RELAYREPLY 13 /* DHCP6 relay reply */ - -#define DHCP6_TYPE_OFFSET 0 /* DHCP6 type offset */ - -#define DHCP6_MSG_OPT_OFFSET 4 /* Offset of options in client server messages */ -#define DHCP6_RELAY_OPT_OFFSET 34 /* Offset of options in relay messages */ - -#define DHCP6_OPT_CODE_OFFSET 0 /* Option identifier */ -#define DHCP6_OPT_LEN_OFFSET 2 /* Option data length */ -#define DHCP6_OPT_DATA_OFFSET 4 /* Option data */ - -#define DHCP6_OPT_CODE_CLIENTID 1 /* DHCP6 CLIENTID option */ -#define DHCP6_OPT_CODE_SERVERID 2 /* DHCP6 SERVERID option */ - -#define DHCP6_PORT_SERVER 547 /* DHCP6 server UDP port */ -#define DHCP6_PORT_CLIENT 546 /* DHCP6 client UDP port */ - -#endif /* #ifndef _bcmdhcp_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h deleted file mode 100644 index 90067b207694..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Broadcom Ethernettype protocol definitions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmeth.h 445746 2013-12-30 12:57:26Z $ - */ - -/* - * Broadcom Ethernet protocol defines - */ - -#ifndef _BCMETH_H_ -#define _BCMETH_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - -/* ETHER_TYPE_BRCM is defined in ethernet.h */ - -/* - * Following the 2byte BRCM ether_type is a 16bit BRCM subtype field - * in one of two formats: (only subtypes 32768-65535 are in use now) - * - * subtypes 0-32767: - * 8 bit subtype (0-127) - * 8 bit length in bytes (0-255) - * - * subtypes 32768-65535: - * 16 bit big-endian subtype - * 16 bit big-endian length in bytes (0-65535) - * - * length is the number of additional bytes beyond the 4 or 6 byte header - * - * Reserved values: - * 0 reserved - * 5-15 reserved for iLine protocol assignments - * 17-126 reserved, assignable - * 127 reserved - * 32768 reserved - * 32769-65534 reserved, assignable - * 65535 reserved - */ - -/* - * While adding the subtypes and their specific processing code make sure - * bcmeth_bcm_hdr_t is the first data structure in the user specific data structure definition - */ - -#define BCMILCP_SUBTYPE_RATE 1 -#define BCMILCP_SUBTYPE_LINK 2 -#define BCMILCP_SUBTYPE_CSA 3 -#define BCMILCP_SUBTYPE_LARQ 4 -#define BCMILCP_SUBTYPE_VENDOR 5 -#define BCMILCP_SUBTYPE_FLH 17 - -#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 -#define BCMILCP_SUBTYPE_CERT 32770 -#define BCMILCP_SUBTYPE_SES 32771 - - -#define BCMILCP_BCM_SUBTYPE_RESERVED 0 -#define BCMILCP_BCM_SUBTYPE_EVENT 1 -#define BCMILCP_BCM_SUBTYPE_SES 2 -/* - * The EAPOL type is not used anymore. Instead EAPOL messages are now embedded - * within BCMILCP_BCM_SUBTYPE_EVENT type messages - */ -/* #define BCMILCP_BCM_SUBTYPE_EAPOL 3 */ -#define BCMILCP_BCM_SUBTYPE_DPT 4 - -#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 -#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 -#define BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD 2 - -/* These fields are stored in network order */ -typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr -{ - uint16 subtype; /* Vendor specific..32769 */ - uint16 length; - uint8 version; /* Version is 0 */ - uint8 oui[3]; /* Broadcom OUI */ - /* user specific Data */ - uint16 usr_subtype; -} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; - - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _BCMETH_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h deleted file mode 100644 index e3801f89d053..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Broadcom Event protocol definitions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Dependencies: proto/bcmeth.h - * - * $Id: bcmevent.h 642286 2016-06-08 05:57:20Z $ - * - */ - -/* - * Broadcom Ethernet Events protocol defines - * - */ - -#ifndef _BCMEVENT_H_ -#define _BCMEVENT_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif -/* #include -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */ -#include - -/* This marks the start of a packed structure section. */ -#include - -#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */ -#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */ - -/* flags */ -#define WLC_EVENT_MSG_LINK 0x01 /* link is up */ -#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */ -#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ -#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */ -#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */ - -/* these fields are stored in network order */ - -/* version 1 */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - uint16 version; - uint16 flags; /* see flags below */ - uint32 event_type; /* Message (see below) */ - uint32 status; /* Status code (see below) */ - uint32 reason; /* Reason code (if applicable) */ - uint32 auth_type; /* WLC_E_AUTH */ - uint32 datalen; /* data buf */ - struct ether_addr addr; /* Station address (if applicable) */ - char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ -} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; - -/* the current version */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - uint16 version; - uint16 flags; /* see flags below */ - uint32 event_type; /* Message (see below) */ - uint32 status; /* Status code (see below) */ - uint32 reason; /* Reason code (if applicable) */ - uint32 auth_type; /* WLC_E_AUTH */ - uint32 datalen; /* data buf */ - struct ether_addr addr; /* Station address (if applicable) */ - char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ - uint8 ifidx; /* destination OS i/f index */ - uint8 bsscfgidx; /* source bsscfg index */ -} BWL_POST_PACKED_STRUCT wl_event_msg_t; - -/* used by driver msgs */ -typedef BWL_PRE_PACKED_STRUCT struct bcm_event { - struct ether_header eth; - bcmeth_hdr_t bcm_hdr; - wl_event_msg_t event; - /* data portion follows */ -} BWL_POST_PACKED_STRUCT bcm_event_t; - -#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) - -/* Event messages */ -#define WLC_E_SET_SSID 0 /* indicates status of set SSID */ -#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */ -#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */ -#define WLC_E_AUTH 3 /* 802.11 AUTH request */ -#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */ -#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */ -#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */ -#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */ -#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */ -#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */ -#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */ -#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */ -#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */ -#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */ -#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */ -#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */ -#define WLC_E_LINK 16 /* generic link indication */ -#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */ -#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */ -#define WLC_E_ROAM 19 /* roam attempt occurred: indicate status & reason */ -#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */ -#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */ -#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */ -#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */ -#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */ -#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */ -#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */ -#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */ -#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */ -#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */ -#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */ -#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */ -#define WLC_E_ROAM_PREP 32 /* before attempting to roam */ -#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */ -#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */ -#define WLC_E_RESET_COMPLETE 35 -#define WLC_E_JOIN_START 36 -#define WLC_E_ROAM_START 37 -#define WLC_E_ASSOC_START 38 -#define WLC_E_IBSS_ASSOC 39 -#define WLC_E_RADIO 40 -#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */ -#define WLC_E_PROBREQ_MSG 44 /* probe request received */ -#define WLC_E_SCAN_CONFIRM_IND 45 -#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */ -#define WLC_E_COUNTRY_CODE_CHANGED 47 -#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */ -#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */ -#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */ -#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ -#define WLC_E_TRACE 52 -#define WLC_E_IF 54 /* I/F change (for dongle host notification) */ -#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */ -#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */ -#define WLC_E_PFN_BEST_BATCHING 57 /* PFN best network batching event */ -#define WLC_E_EXTLOG_MSG 58 -#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */ -#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ -#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */ -#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */ -#define WLC_E_CHANNEL_ADOPTED 63 -#define WLC_E_AP_STARTED 64 /* AP started */ -#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */ -#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */ -#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */ -#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */ -#define WLC_E_ESCAN_RESULT 69 /* escan result event */ -#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */ -#define WLC_E_PROBRESP_MSG 71 /* probe response received */ -#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */ -#define WLC_E_DCS_REQUEST 73 -#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */ -#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH - * wl_event_rx_frame_data_t header - */ -#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */ -#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */ -#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */ -#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */ -#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */ -#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */ -#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */ -/* PFN BSSID network found event, conflict/share with WLC_E_PFN_SCAN_NONE */ -#define WLC_E_PFN_BSSID_NET_FOUND 82 -#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */ -/* PFN BSSID network lost event, conflict/share with WLC_E_PFN_SCAN_ALLGONE */ -#define WLC_E_PFN_BSSID_NET_LOST 83 -#define WLC_E_GTK_PLUMBED 84 -#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */ -#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */ -#define WLC_E_ASSOC_REQ_IE 87 -#define WLC_E_ASSOC_RESP_IE 88 -#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ -#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */ -#define WLC_E_AUTH_REQ 91 /* authentication request received */ -#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected/disconnected peer */ -#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */ -#define WLC_E_NATIVE 94 /* port-specific event and payload (e.g. NDIS) */ -#define WLC_E_PKTDELAY_IND 95 /* event for tx pkt delay suddently jump */ -#define WLC_E_PSTA_PRIMARY_INTF_IND 99 /* psta primary interface indication */ -#define WLC_E_NAN 100 /* NAN event */ -#define WLC_E_BEACON_FRAME_RX 101 -#define WLC_E_SERVICE_FOUND 102 /* desired service found */ -#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ -#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ -#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ -#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ -#define WLC_E_WNM_STA_SLEEP 107 /* WNM event to notify STA enter sleep mode */ -#define WLC_E_TXFAIL_THRESH 108 /* Indication of MAC tx failures (exhaustion of - * 802.11 retries) exceeding threshold(s) - */ -#define WLC_E_PROXD 109 /* Proximity Detection event */ -#define WLC_E_IBSS_COALESCE 110 /* IBSS Coalescing */ -#define WLC_E_AIBSS_TXFAIL 110 /* TXFAIL event for AIBSS, re using event 110 */ -#define WLC_E_BSS_LOAD 114 /* Inform host of beacon bss load */ -#define WLC_E_CSA_START_IND 121 -#define WLC_E_CSA_DONE_IND 122 -#define WLC_E_CSA_FAILURE_IND 123 -#define WLC_E_CCA_CHAN_QUAL 124 /* CCA based channel quality report */ -#define WLC_E_BSSID 125 /* to report change in BSSID while roaming */ -#define WLC_E_TX_STAT_ERROR 126 /* tx error indication */ -#define WLC_E_BCMC_CREDIT_SUPPORT 127 /* credit check for BCMC supported */ -#define WLC_E_BT_WIFI_HANDOVER_REQ 130 /* Handover Request Initiated */ -#define WLC_E_SPW_TXINHIBIT 131 /* Southpaw TxInhibit notification */ -#define WLC_E_FBT_AUTH_REQ_IND 132 /* FBT Authentication Request Indication */ -#define WLC_E_RSSI_LQM 133 /* Enhancement addition for WLC_E_RSSI */ -#define WLC_E_PFN_GSCAN_FULL_RESULT 134 /* Full probe/beacon (IEs etc) results */ -/* 135 was legacy entry for WLC_E_PFN_SWC can be reused */ -#define WLC_E_PFN_SCAN_COMPLETE 138 /* PFN completed scan of network list */ -#define WLC_E_RMC_EVENT 139 /* RMC event */ -#define WLC_E_PFN_SSID_EXT 142 /* SSID EXT event */ -#define WLC_E_LAST 143 /* highest val + 1 for range checking */ - -#if (WLC_E_LAST > 143) -#error "WLC_E_LAST: Invalid value for last event; must be <= 140." -#endif /* WLC_E_LAST */ - -/* define an API for getting the string name of an event */ -extern const char *bcmevent_get_name(uint event_type); - -/* validate if the event is proper and if valid copy event header to event */ -extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, - void *out_event); - - - -/* Event status codes */ -#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */ -#define WLC_E_STATUS_FAIL 1 /* operation failed */ -#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */ -#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */ -#define WLC_E_STATUS_ABORT 4 /* operation was aborted */ -#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */ -#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */ -#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */ -#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */ -#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */ -#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */ -#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */ -#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */ -#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */ -#ifdef BCMCCX -#define WLC_E_STATUS_CCXFASTRM 14 /* scan aborted due to CCX fast roam */ -#endif /* BCMCCX */ -#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */ -#define WLC_E_STATUS_ERROR 16 /* request failed due to error */ -#define WLC_E_STATUS_INVALID 0xff /* Invalid status code to init variables. */ - - -/* roam reason codes */ -#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */ -#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */ -#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ -#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ -#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ - -#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ -#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ -#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ -#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ -#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ -#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ -/* retained for precommit auto-merging errors; remove once all branches are synced */ -#define WLC_E_REASON_REQUESTED_ROAM 11 -#define WLC_E_REASON_BSSTRANS_REQ 11 /* roamed due to BSS Transition request by AP */ - -/* prune reason codes */ -#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ -#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ -#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ -#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ -#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ -#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ -#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ -#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ -#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ -#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ -#ifdef BCMCCX -#define WLC_E_PRUNE_CCXFAST_PREVAP 11 /* CCX FAST ROAM: prune previous AP */ -#endif /* def BCMCCX */ -#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ -#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ -#ifdef BCMCCX -#define WLC_E_PRUNE_CCXFAST_DROAM 14 /* CCX FAST ROAM: prune unqualified AP */ -#endif /* def BCMCCX */ -#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ -#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ -#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ -#ifdef BCMCCX -#define WLC_E_PRUNE_AP_BLOCKED 18 /* prune blocked AP */ -#define WLC_E_PRUNE_NO_DIAG_SUPPORT 19 /* prune due to diagnostic mode not supported */ -#endif /* BCMCCX */ - -/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */ -#define WLC_E_SUP_OTHER 0 /* Other reason */ -#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */ -#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */ -#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */ -#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */ -#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */ -#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */ -#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */ -#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */ -#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */ -#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */ -#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */ -#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */ -#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */ -#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */ -#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */ - -/* Event data for events that include frames received over the air */ -/* WLC_E_PROBRESP_MSG - * WLC_E_P2P_PROBREQ_MSG - * WLC_E_ACTION_FRAME_RX - */ -typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { - uint16 version; - uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */ - int32 rssi; - uint32 mactime; - uint32 rate; -} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; - -#define BCM_RX_FRAME_DATA_VERSION 1 - -/* WLC_E_IF event data */ -typedef struct wl_event_data_if { - uint8 ifidx; /* RTE virtual device index (for dongle) */ - uint8 opcode; /* see I/F opcode */ - uint8 reserved; /* bit mask (WLC_E_IF_FLAGS_XXX ) */ - uint8 bssidx; /* bsscfg index */ - uint8 role; /* see I/F role */ -} wl_event_data_if_t; - -/* opcode in WLC_E_IF event */ -#define WLC_E_IF_ADD 1 /* bsscfg add */ -#define WLC_E_IF_DEL 2 /* bsscfg delete */ -#define WLC_E_IF_CHANGE 3 /* bsscfg role change */ - -/* I/F role code in WLC_E_IF event */ -#define WLC_E_IF_ROLE_STA 0 /* Infra STA */ -#define WLC_E_IF_ROLE_AP 1 /* Access Point */ -#define WLC_E_IF_ROLE_WDS 2 /* WDS link */ -#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ -#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ - -/* WLC_E_RSSI event data */ -typedef struct wl_event_data_rssi { - int32 rssi; - int32 snr; - int32 noise; -} wl_event_data_rssi_t; - -/* WLC_E_IF flag */ -#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 /* no host I/F creation needed */ - -/* Reason codes for LINK */ -#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */ -#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */ -#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */ -#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */ - -/* reason codes for WLC_E_OVERLAY_REQ event */ -#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */ -#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */ - -/* reason codes for WLC_E_TDLS_PEER_EVENT event */ -#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */ -#define WLC_E_TDLS_PEER_CONNECTED 1 -#define WLC_E_TDLS_PEER_DISCONNECTED 2 - -/* reason codes for WLC_E_RMC_EVENT event */ -#define WLC_E_REASON_RMC_NONE 0 -#define WLC_E_REASON_RMC_AR_LOST 1 -#define WLC_E_REASON_RMC_AR_NO_ACK 2 - -#ifdef WLTDLS -/* TDLS Action Category code */ -#define TDLS_AF_CATEGORY 12 -/* Wi-Fi Display (WFD) Vendor Specific Category */ -/* used for WFD Tunneled Probe Request and Response */ -#define TDLS_VENDOR_SPECIFIC 127 -/* TDLS Action Field Values */ -#define TDLS_ACTION_SETUP_REQ 0 -#define TDLS_ACTION_SETUP_RESP 1 -#define TDLS_ACTION_SETUP_CONFIRM 2 -#define TDLS_ACTION_TEARDOWN 3 -#define WLAN_TDLS_SET_PROBE_WFD_IE 11 -#define WLAN_TDLS_SET_SETUP_WFD_IE 12 -#endif - - -/* GAS event data */ -typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { - uint16 channel; /* channel of GAS protocol */ - uint8 dialog_token; /* GAS dialog token */ - uint8 fragment_id; /* fragment id */ - uint16 status_code; /* status code on GAS completion */ - uint16 data_len; /* length of data to follow */ - uint8 data[1]; /* variable length specified by data_len */ -} BWL_POST_PACKED_STRUCT wl_event_gas_t; - -/* service discovery TLV */ -typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { - uint16 length; /* length of response_data */ - uint8 protocol; /* service protocol type */ - uint8 transaction_id; /* service transaction id */ - uint8 status_code; /* status code */ - uint8 data[1]; /* response data */ -} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; - -/* service discovery event data */ -typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { - uint16 channel; /* channel */ - uint8 count; /* number of tlvs */ - wl_sd_tlv_t tlv[1]; /* service discovery TLV */ -} BWL_POST_PACKED_STRUCT wl_event_sd_t; - -/* Reason codes for WLC_E_PROXD */ -#define WLC_E_PROXD_FOUND 1 /* Found a proximity device */ -#define WLC_E_PROXD_GONE 2 /* Lost a proximity device */ -#define WLC_E_PROXD_START 3 /* used by: target */ -#define WLC_E_PROXD_STOP 4 /* used by: target */ -#define WLC_E_PROXD_COMPLETED 5 /* used by: initiator completed */ -#define WLC_E_PROXD_ERROR 6 /* used by both initiator and target */ -#define WLC_E_PROXD_COLLECT_START 7 /* used by: target & initiator */ -#define WLC_E_PROXD_COLLECT_STOP 8 /* used by: target */ -#define WLC_E_PROXD_COLLECT_COMPLETED 9 /* used by: initiator completed */ -#define WLC_E_PROXD_COLLECT_ERROR 10 /* used by both initiator and target */ -#define WLC_E_PROXD_NAN_EVENT 11 /* used by both initiator and target */ - -/* proxd_event data */ -typedef struct ftm_sample { - uint32 value; /* RTT in ns */ - int8 rssi; /* RSSI */ -} ftm_sample_t; - -typedef BWL_PRE_PACKED_STRUCT struct proxd_event_data { - uint16 ver; /* version */ - uint16 mode; /* mode: target/initiator */ - uint16 method; /* method: rssi/TOF/AOA */ - uint8 err_code; /* error classification */ - uint8 TOF_type; /* one way or two way TOF */ - uint8 OFDM_frame_type; /* legacy or VHT */ - uint8 bandwidth; /* Bandwidth is 20, 40,80, MHZ */ - struct ether_addr peer_mac; /* (e.g for tgt:initiator's */ - uint32 distance; /* dst to tgt, units meter */ - uint32 meanrtt; /* mean delta */ - uint32 modertt; /* Mode delta */ - uint32 medianrtt; /* median RTT */ - uint32 sdrtt; /* Standard deviation of RTT */ - int gdcalcresult; /* Software or Hardware Kind of redundant, but if */ - /* frame type is VHT, then we should do it by hardware */ - int16 avg_rssi; /* avg rssi accroos the ftm frames */ - int16 validfrmcnt; /* Firmware's valid frame counts */ - char *peer_router_info; /* Peer router information if available in TLV, */ - /* We will add this field later */ - int32 var1; /* average of group delay */ - int32 var2; /* average of threshold crossing */ - int32 var3; /* difference between group delay and threshold crossing */ - /* raw Fine Time Measurements (ftm) data */ - uint16 ftm_unit; /* ftm cnt resolution in picoseconds , 6250ps - default */ - uint16 ftm_cnt; /* num of rtd measurments/length in the ftm buffer */ - ftm_sample_t ftm_buff[1]; /* 1 ... ftm_cnt */ -} BWL_POST_PACKED_STRUCT wl_proxd_event_data_t; - - -/* Video Traffic Interference Monitor Event */ -#define INTFER_EVENT_VERSION 1 -#define INTFER_STREAM_TYPE_NONTCP 1 -#define INTFER_STREAM_TYPE_TCP 2 -#define WLINTFER_STATS_NSMPLS 4 -typedef struct wl_intfer_event { - uint16 version; /* version */ - uint16 status; /* status */ - uint8 txfail_histo[WLINTFER_STATS_NSMPLS]; /* txfail histo */ -} wl_intfer_event_t; - -/* WLC_E_PSTA_PRIMARY_INTF_IND event data */ -typedef struct wl_psta_primary_intf_event { - struct ether_addr prim_ea; /* primary intf ether addr */ -} wl_psta_primary_intf_event_t; - - -/* ********** NAN protocol events/subevents ********** */ -#define NAN_EVENT_BUFFER_SIZE 512 /* max size */ -/* nan application events to the host driver */ -enum nan_app_events { - WL_NAN_EVENT_START = 1, /* NAN cluster started */ - WL_NAN_EVENT_JOIN = 2, /* Joined to a NAN cluster */ - WL_NAN_EVENT_ROLE = 3, /* Role or State changed */ - WL_NAN_EVENT_SCAN_COMPLETE = 4, - WL_NAN_EVENT_DISCOVERY_RESULT = 5, - WL_NAN_EVENT_REPLIED = 6, - WL_NAN_EVENT_TERMINATED = 7, /* the instance ID will be present in the ev data */ - WL_NAN_EVENT_RECEIVE = 8, - WL_NAN_EVENT_STATUS_CHG = 9, /* generated on any change in nan_mac status */ - WL_NAN_EVENT_MERGE = 10, /* Merged to a NAN cluster */ - WL_NAN_EVENT_STOP = 11, /* NAN stopped */ - WL_NAN_EVENT_P2P = 12, /* NAN P2P EVENT */ - WL_NAN_EVENT_INVALID = 13, /* delimiter for max value */ -}; -#define IS_NAN_EVT_ON(var, evt) ((var & (1 << (evt-1))) != 0) -/* ******************* end of NAN section *************** */ - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _BCMEVENT_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h deleted file mode 100644 index 85ce02e580b7..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental constants relating to IP Protocol - * - * $Id: bcmip.h 458522 2014-02-27 02:26:15Z $ - */ - -#ifndef _bcmip_h_ -#define _bcmip_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - - -/* IPV4 and IPV6 common */ -#define IP_VER_OFFSET 0x0 /* offset to version field */ -#define IP_VER_MASK 0xf0 /* version mask */ -#define IP_VER_SHIFT 4 /* version shift */ -#define IP_VER_4 4 /* version number for IPV4 */ -#define IP_VER_6 6 /* version number for IPV6 */ - -#define IP_VER(ip_body) \ - ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) - -#define IP_PROT_ICMP 0x1 /* ICMP protocol */ -#define IP_PROT_IGMP 0x2 /* IGMP protocol */ -#define IP_PROT_TCP 0x6 /* TCP protocol */ -#define IP_PROT_UDP 0x11 /* UDP protocol type */ -#define IP_PROT_ICMP6 0x3a /* ICMPv6 protocol type */ - -/* IPV4 field offsets */ -#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ -#define IPV4_TOS_OFFSET 1 /* type of service offset */ -#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ -#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ -#define IPV4_PROT_OFFSET 9 /* protocol type offset */ -#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ -#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ -#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ -#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ -#define IPV4_MIN_HEADER_LEN 20 /* Minimum size for an IP header (no options) */ - -/* IPV4 field decodes */ -#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ -#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ - -#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ -#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) - -#define IPV4_ADDR_LEN 4 /* IPV4 address length */ - -#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ - ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) - -#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ - ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) - -#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ -#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ - -#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) - -#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ -#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ - -#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ -#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ -#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ - -#define IPV4_TOS_ROUTINE 0 -#define IPV4_TOS_PRIORITY 1 -#define IPV4_TOS_IMMEDIATE 2 -#define IPV4_TOS_FLASH 3 -#define IPV4_TOS_FLASHOVERRIDE 4 -#define IPV4_TOS_CRITICAL 5 -#define IPV4_TOS_INETWORK_CTRL 6 -#define IPV4_TOS_NETWORK_CTRL 7 - -#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) - -#define IPV4_FRAG_RESV 0x8000 /* Reserved */ -#define IPV4_FRAG_DONT 0x4000 /* Don't fragment */ -#define IPV4_FRAG_MORE 0x2000 /* More fragments */ -#define IPV4_FRAG_OFFSET_MASK 0x1fff /* Fragment offset */ - -#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ - -/* IPV4 packet formats */ -BWL_PRE_PACKED_STRUCT struct ipv4_addr { - uint8 addr[IPV4_ADDR_LEN]; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct ipv4_hdr { - uint8 version_ihl; /* Version and Internet Header Length */ - uint8 tos; /* Type Of Service */ - uint16 tot_len; /* Number of bytes in packet (max 65535) */ - uint16 id; - uint16 frag; /* 3 flag bits and fragment offset */ - uint8 ttl; /* Time To Live */ - uint8 prot; /* Protocol */ - uint16 hdr_chksum; /* IP header checksum */ - uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ - uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ -} BWL_POST_PACKED_STRUCT; - -/* IPV6 field offsets */ -#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ -#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ -#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ -#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ -#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ - -/* IPV6 field decodes */ -#define IPV6_TRAFFIC_CLASS(ipv6_body) \ - (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ - ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) - -#define IPV6_FLOW_LABEL(ipv6_body) \ - (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ - (((uint8 *)(ipv6_body))[2] << 8) | \ - (((uint8 *)(ipv6_body))[3])) - -#define IPV6_PAYLOAD_LEN(ipv6_body) \ - ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ - ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) - -#define IPV6_NEXT_HDR(ipv6_body) \ - (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) - -#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) - -#define IPV6_ADDR_LEN 16 /* IPV6 address length */ - -/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ -#define IP_TOS46(ip_body) \ - (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ - IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) - -#define IP_DSCP46(ip_body) (IP_TOS46(ip_body) >> IPV4_TOS_DSCP_SHIFT); - -/* IPV4 or IPV6 Protocol Classifier or 0 */ -#define IP_PROT46(ip_body) \ - (IP_VER(ip_body) == IP_VER_4 ? IPV4_PROT(ip_body) : \ - IP_VER(ip_body) == IP_VER_6 ? IPV6_PROT(ip_body) : 0) - -/* IPV6 extension headers (options) */ -#define IPV6_EXTHDR_HOP 0 -#define IPV6_EXTHDR_ROUTING 43 -#define IPV6_EXTHDR_FRAGMENT 44 -#define IPV6_EXTHDR_AUTH 51 -#define IPV6_EXTHDR_NONE 59 -#define IPV6_EXTHDR_DEST 60 - -#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ - ((prot) == IPV6_EXTHDR_ROUTING) || \ - ((prot) == IPV6_EXTHDR_FRAGMENT) || \ - ((prot) == IPV6_EXTHDR_AUTH) || \ - ((prot) == IPV6_EXTHDR_NONE) || \ - ((prot) == IPV6_EXTHDR_DEST)) - -#define IPV6_MIN_HLEN 40 - -#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) - -BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { - uint8 nexthdr; - uint8 hdrlen; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { - uint8 nexthdr; - uint8 rsvd; - uint16 frag_off; - uint32 ident; -} BWL_POST_PACKED_STRUCT; - -static INLINE int32 -ipv6_exthdr_len(uint8 *h, uint8 *proto) -{ - uint16 len = 0, hlen; - struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; - - while (IPV6_EXTHDR(eh->nexthdr)) { - if (eh->nexthdr == IPV6_EXTHDR_NONE) - return -1; - else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) - hlen = 8; - else if (eh->nexthdr == IPV6_EXTHDR_AUTH) - hlen = (eh->hdrlen + 2) << 2; - else - hlen = IPV6_EXTHDR_LEN(eh); - - len += hlen; - eh = (struct ipv6_exthdr *)(h + len); - } - - *proto = eh->nexthdr; - return len; -} - -#define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000) - -#define IPV4_MCAST_TO_ETHER_MCAST(ipv4, ether) \ -{ \ - ether[0] = 0x01; \ - ether[1] = 0x00; \ - ether[2] = 0x5E; \ - ether[3] = (ipv4 & 0x7f0000) >> 16; \ - ether[4] = (ipv4 & 0xff00) >> 8; \ - ether[5] = (ipv4 & 0xff); \ -} - -/* This marks the end of a packed structure section. */ -#include - -#define IPV4_ADDR_STR "%d.%d.%d.%d" -#define IPV4_ADDR_TO_STR(addr) ((uint32)addr & 0xff000000) >> 24, \ - ((uint32)addr & 0x00ff0000) >> 16, \ - ((uint32)addr & 0x0000ff00) >> 8, \ - ((uint32)addr & 0x000000ff) - -#endif /* _bcmip_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h deleted file mode 100644 index ee65aab4ae2b..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental constants relating to Neighbor Discovery Protocol - * - * $Id: bcmipv6.h 439574 2013-11-27 06:37:37Z $ - */ - -#ifndef _bcmipv6_h_ -#define _bcmipv6_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - -/* Extension headers */ -#define IPV6_EXT_HOP 0 -#define IPV6_EXT_ROUTE 43 -#define IPV6_EXT_FRAG 44 -#define IPV6_EXT_DEST 60 -#define IPV6_EXT_ESEC 50 -#define IPV6_EXT_AUTH 51 - -/* Minimum size (extension header "word" length) */ -#define IPV6_EXT_WORD 8 - -/* Offsets for most extension headers */ -#define IPV6_EXT_NEXTHDR 0 -#define IPV6_EXT_HDRLEN 1 - -/* Constants specific to fragmentation header */ -#define IPV6_FRAG_MORE_MASK 0x0001 -#define IPV6_FRAG_MORE_SHIFT 0 -#define IPV6_FRAG_OFFS_MASK 0xfff8 -#define IPV6_FRAG_OFFS_SHIFT 3 - -/* For icmpv6 */ -#define ICMPV6_HEADER_TYPE 0x3A -#define ICMPV6_PKT_TYPE_RA 134 -#define ICMPV6_PKT_TYPE_NS 135 -#define ICMPV6_PKT_TYPE_NA 136 - -#define ICMPV6_ND_OPT_TYPE_TARGET_MAC 2 -#define ICMPV6_ND_OPT_TYPE_SRC_MAC 1 - -#define ICMPV6_ND_OPT_LEN_LINKADDR 1 - -#define ICMPV6_ND_OPT_LEN_LINKADDR 1 - -#define IPV6_VERSION 6 -#define IPV6_HOP_LIMIT 255 - -#define IPV6_ADDR_NULL(a) ((a[0] | a[1] | a[2] | a[3] | a[4] | \ - a[5] | a[6] | a[7] | a[8] | a[9] | \ - a[10] | a[11] | a[12] | a[13] | \ - a[14] | a[15]) == 0) - -#define IPV6_ADDR_LOCAL(a) (((a[0] == 0xfe) && (a[1] & 0x80))? TRUE: FALSE) - -/* IPV6 address */ -BWL_PRE_PACKED_STRUCT struct ipv6_addr { - uint8 addr[16]; -} BWL_POST_PACKED_STRUCT; - - -/* ICMPV6 Header */ -BWL_PRE_PACKED_STRUCT struct icmp6_hdr { - uint8 icmp6_type; - uint8 icmp6_code; - uint16 icmp6_cksum; - BWL_PRE_PACKED_STRUCT union { - uint32 reserved; - BWL_PRE_PACKED_STRUCT struct nd_advt { - uint32 reserved1:5, - override:1, - solicited:1, - router:1, - reserved2:24; - } BWL_POST_PACKED_STRUCT nd_advt; - } BWL_POST_PACKED_STRUCT opt; -} BWL_POST_PACKED_STRUCT; - -/* Ipv6 Header Format */ -BWL_PRE_PACKED_STRUCT struct ipv6_hdr { - uint8 priority:4, - version:4; - uint8 flow_lbl[3]; - uint16 payload_len; - uint8 nexthdr; - uint8 hop_limit; - struct ipv6_addr saddr; - struct ipv6_addr daddr; -} BWL_POST_PACKED_STRUCT; - -/* Neighbor Advertisement/Solicitation Packet Structure */ -BWL_PRE_PACKED_STRUCT struct nd_msg { - struct icmp6_hdr icmph; - struct ipv6_addr target; -} BWL_POST_PACKED_STRUCT; - - -/* Neighibor Solicitation/Advertisement Optional Structure */ -BWL_PRE_PACKED_STRUCT struct nd_msg_opt { - uint8 type; - uint8 len; - uint8 mac_addr[ETHER_ADDR_LEN]; -} BWL_POST_PACKED_STRUCT; - -/* Ipv6 Fragmentation Header */ -BWL_PRE_PACKED_STRUCT struct ipv6_frag { - uint8 nexthdr; - uint8 reserved; - uint16 frag_offset; - uint32 ident; -} BWL_POST_PACKED_STRUCT; - -/* This marks the end of a packed structure section. */ -#include - -static const struct ipv6_addr all_node_ipv6_maddr = { - { 0xff, 0x2, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 1 - }}; - -#define IPV6_ISMULTI(a) (a[0] == 0xff) - -#define IPV6_MCAST_TO_ETHER_MCAST(ipv6, ether) \ -{ \ - ether[0] = 0x33; \ - ether[1] = 0x33; \ - ether[2] = ipv6[12]; \ - ether[3] = ipv6[13]; \ - ether[4] = ipv6[14]; \ - ether[5] = ipv6[15]; \ -} - -#endif /* !defined(_bcmipv6_h_) */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h deleted file mode 100644 index a024ea8a401f..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Fundamental constants relating to TCP Protocol - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmtcp.h 458522 2014-02-27 02:26:15Z $ - */ - -#ifndef _bcmtcp_h_ -#define _bcmtcp_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - - -#define TCP_SRC_PORT_OFFSET 0 /* TCP source port offset */ -#define TCP_DEST_PORT_OFFSET 2 /* TCP dest port offset */ -#define TCP_SEQ_NUM_OFFSET 4 /* TCP sequence number offset */ -#define TCP_ACK_NUM_OFFSET 8 /* TCP acknowledgement number offset */ -#define TCP_HLEN_OFFSET 12 /* HLEN and reserved bits offset */ -#define TCP_FLAGS_OFFSET 13 /* FLAGS and reserved bits offset */ -#define TCP_CHKSUM_OFFSET 16 /* TCP body checksum offset */ - -#define TCP_PORT_LEN 2 /* TCP port field length */ - -/* 8bit TCP flag field */ -#define TCP_FLAG_URG 0x20 -#define TCP_FLAG_ACK 0x10 -#define TCP_FLAG_PSH 0x08 -#define TCP_FLAG_RST 0x04 -#define TCP_FLAG_SYN 0x02 -#define TCP_FLAG_FIN 0x01 - -#define TCP_HLEN_MASK 0xf000 -#define TCP_HLEN_SHIFT 12 - -/* These fields are stored in network order */ -BWL_PRE_PACKED_STRUCT struct bcmtcp_hdr -{ - uint16 src_port; /* Source Port Address */ - uint16 dst_port; /* Destination Port Address */ - uint32 seq_num; /* TCP Sequence Number */ - uint32 ack_num; /* TCP Sequence Number */ - uint16 hdrlen_rsvd_flags; /* Header length, reserved bits and flags */ - uint16 tcpwin; /* TCP window */ - uint16 chksum; /* Segment checksum with pseudoheader */ - uint16 urg_ptr; /* Points to seq-num of byte following urg data */ -} BWL_POST_PACKED_STRUCT; - -#define TCP_MIN_HEADER_LEN 20 - -#define TCP_HDRLEN_MASK 0xf0 -#define TCP_HDRLEN_SHIFT 4 -#define TCP_HDRLEN(hdrlen) (((hdrlen) & TCP_HDRLEN_MASK) >> TCP_HDRLEN_SHIFT) - -#define TCP_FLAGS_MASK 0x1f -#define TCP_FLAGS(hdrlen) ((hdrlen) & TCP_FLAGS_MASK) - -/* This marks the end of a packed structure section. */ -#include - -/* To address round up by 32bit. */ -#define IS_TCPSEQ_GE(a, b) ((a - b) < NBITVAL(31)) /* a >= b */ -#define IS_TCPSEQ_LE(a, b) ((b - a) < NBITVAL(31)) /* a =< b */ -#define IS_TCPSEQ_GT(a, b) !IS_TCPSEQ_LE(a, b) /* a > b */ -#define IS_TCPSEQ_LT(a, b) !IS_TCPSEQ_GE(a, b) /* a < b */ - -#endif /* #ifndef _bcmtcp_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmudp.h b/drivers/net/wireless/bcmdhd/include/proto/bcmudp.h deleted file mode 100644 index 09b71f2d2cac..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmudp.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental constants relating to UDP Protocol - * - * $Id: bcmudp.h 528443 2015-01-22 09:29:18Z $ - */ - -#ifndef _bcmudp_h_ -#define _bcmudp_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - - -/* UDP header */ -#define UDP_DEST_PORT_OFFSET 2 /* UDP dest port offset */ -#define UDP_LEN_OFFSET 4 /* UDP length offset */ -#define UDP_CHKSUM_OFFSET 6 /* UDP body checksum offset */ - -#define UDP_HDR_LEN 8 /* UDP header length */ -#define UDP_PORT_LEN 2 /* UDP port length */ - -/* These fields are stored in network order */ -BWL_PRE_PACKED_STRUCT struct bcmudp_hdr -{ - uint16 src_port; /* Source Port Address */ - uint16 dst_port; /* Destination Port Address */ - uint16 len; /* Number of bytes in datagram including header */ - uint16 chksum; /* entire datagram checksum with pseudoheader */ -} BWL_POST_PACKED_STRUCT; - -/* This marks the end of a packed structure section. */ -#include - -#endif /* #ifndef _bcmudp_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h deleted file mode 100644 index f1ea2909971c..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bt_amp_hci.h 382882 2013-02-04 23:24:31Z $ -*/ - -#ifndef _bt_amp_hci_h -#define _bt_amp_hci_h - -/* This marks the start of a packed structure section. */ -#include - - -/* AMP HCI CMD packet format */ -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd { - uint16 opcode; - uint8 plen; - uint8 parms[1]; -} BWL_POST_PACKED_STRUCT amp_hci_cmd_t; - -#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms) -#define HCI_CMD_DATA_SIZE 255 - -/* AMP HCI CMD opcode layout */ -#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF)) -#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F)) -#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF) - -/* AMP HCI command opcodes */ -#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001) -#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002) -#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003) -#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009) -#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A) -#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B) -#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035) -#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036) -#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037) -#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038) -#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039) -#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A) -#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B) -#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C) -#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067) -#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069) -#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A) -#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B) -#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003) -#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015) -#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016) -#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036) -#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037) -#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F) -#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061) -#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062) -#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063) -#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064) -#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065) -#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001) -#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002) -#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005) -#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A) - -/* AMP HCI command parameters */ -typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms { - uint8 plh; - uint8 offset[2]; /* length so far */ - uint8 max_remote[2]; -} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms { - uint8 plh; - uint8 offset[2]; - uint8 len[2]; - uint8 frag[1]; -} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms { - uint8 plh; - uint8 key_length; - uint8 key_type; - uint8 key[1]; -} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms { - uint8 plh; - uint8 reason; -} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms { - uint8 plh; - uint8 txflow[16]; - uint8 rxflow[16]; -} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec { - uint8 id; - uint8 service_type; - uint8 max_sdu[2]; - uint8 sdu_ia_time[4]; - uint8 access_latency[4]; - uint8 flush_timeout[4]; -} BWL_POST_PACKED_STRUCT ext_flow_spec_t; - -typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms { - uint8 plh; - uint8 tx_fs_ID; -} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms { - uint8 llh[2]; - uint8 txflow[16]; - uint8 rxflow[16]; -} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct plh_pad { - uint8 plh; - uint8 pad; -} BWL_POST_PACKED_STRUCT plh_pad_t; - -typedef BWL_PRE_PACKED_STRUCT union hci_handle { - uint16 bredr; - plh_pad_t amp; -} BWL_POST_PACKED_STRUCT hci_handle_t; - -typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms { - hci_handle_t handle; - uint8 timeout[2]; -} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms { - uint8 llh[2]; - uint8 befto[4]; -} BWL_POST_PACKED_STRUCT befto_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms { - uint8 plh; - uint8 srm; -} BWL_POST_PACKED_STRUCT srm_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms { - uint8 ld_aware; - uint8 ld[2]; - uint8 ld_opts; - uint8 l_opts; -} BWL_POST_PACKED_STRUCT ld_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms { - uint8 llh[2]; - uint8 packet_type; -} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t; - -/* Generic AMP extended flow spec service types */ -#define EFS_SVCTYPE_NO_TRAFFIC 0 -#define EFS_SVCTYPE_BEST_EFFORT 1 -#define EFS_SVCTYPE_GUARANTEED 2 - -/* AMP HCI event packet format */ -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event { - uint8 ecode; - uint8 plen; - uint8 parms[1]; -} BWL_POST_PACKED_STRUCT amp_hci_event_t; - -#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms) - -/* AMP HCI event codes */ -#define HCI_Command_Complete 0x0E -#define HCI_Command_Status 0x0F -#define HCI_Flush_Occurred 0x11 -#define HCI_Enhanced_Flush_Complete 0x39 -#define HCI_Physical_Link_Complete 0x40 -#define HCI_Channel_Select 0x41 -#define HCI_Disconnect_Physical_Link_Complete 0x42 -#define HCI_Logical_Link_Complete 0x45 -#define HCI_Disconnect_Logical_Link_Complete 0x46 -#define HCI_Flow_Spec_Modify_Complete 0x47 -#define HCI_Number_of_Completed_Data_Blocks 0x48 -#define HCI_Short_Range_Mode_Change_Complete 0x4C -#define HCI_Status_Change_Event 0x4D -#define HCI_Vendor_Specific 0xFF - -/* AMP HCI event mask bit positions */ -#define HCI_Physical_Link_Complete_Event_Mask 0x0001 -#define HCI_Channel_Select_Event_Mask 0x0002 -#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004 -#define HCI_Logical_Link_Complete_Event_Mask 0x0020 -#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040 -#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080 -#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100 -#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000 -#define HCI_Status_Change_Event_Mask 0x2000 -#define HCI_All_Event_Mask 0x31e7 -/* AMP HCI event parameters */ -typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms { - uint8 status; - uint8 cmdpkts; - uint16 opcode; -} BWL_POST_PACKED_STRUCT cmd_status_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms { - uint8 cmdpkts; - uint16 opcode; - uint8 parms[1]; -} BWL_POST_PACKED_STRUCT cmd_complete_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms { - uint16 handle; -} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms { - uint8 status; - uint8 plh; -} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms { - uint8 status; - uint8 plh; - uint16 len; - uint8 frag[1]; -} BWL_POST_PACKED_STRUCT read_local_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms { - uint8 status; - uint8 AMP_status; - uint32 bandwidth; - uint32 gbandwidth; - uint32 latency; - uint32 PDU_size; - uint8 ctrl_type; - uint16 PAL_cap; - uint16 AMP_ASSOC_len; - uint32 max_flush_timeout; - uint32 be_flush_timeout; -} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms { - uint8 status; - uint16 llh; - uint8 plh; - uint8 tx_fs_ID; -} BWL_POST_PACKED_STRUCT log_link_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms { - uint8 status; - uint16 llh; - uint8 reason; -} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms { - uint8 status; - uint8 plh; - uint8 tx_fs_ID; -} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms { - uint8 status; - uint16 llh; -} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms { - uint8 status; - uint8 plh; -} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms { - uint8 status; - uint8 plh; - uint8 reason; -} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms { - uint8 status; - hci_handle_t handle; - uint16 timeout; -} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms { - uint8 status; - uint16 timeout; -} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms { - uint8 status; - uint16 ACL_pkt_len; - uint16 data_block_len; - uint16 data_block_num; -} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct data_blocks { - uint16 handle; - uint16 pkts; - uint16 blocks; -} BWL_POST_PACKED_STRUCT data_blocks_t; - -typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms { - uint16 num_blocks; - uint8 num_handles; - data_blocks_t completed[1]; -} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms { - uint8 status; - uint32 befto; -} BWL_POST_PACKED_STRUCT befto_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms { - uint8 status; - uint8 plh; - uint8 srm; -} BWL_POST_PACKED_STRUCT srm_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms { - uint8 status; - uint8 llh[2]; - uint16 counter; -} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms { - uint8 status; - uint8 llh[2]; -} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms { - uint8 status; - hci_handle_t handle; - uint8 link_quality; -} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms { - uint8 status; - uint8 ld_aware; - uint8 ld[2]; - uint8 ld_opts; - uint8 l_opts; -} BWL_POST_PACKED_STRUCT ld_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms { - uint16 handle; -} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms { - uint8 len; - uint8 parms[1]; -} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms { - uint8 status; - uint8 hci_version; - uint16 hci_revision; - uint8 pal_version; - uint16 mfg_name; - uint16 pal_subversion; -} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t; - -#define MAX_SUPPORTED_CMD_BYTE 64 -typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms { - uint8 status; - uint8 cmd[MAX_SUPPORTED_CMD_BYTE]; -} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms { - uint8 status; - uint8 amp_status; -} BWL_POST_PACKED_STRUCT status_change_evt_parms_t; - -/* AMP HCI error codes */ -#define HCI_SUCCESS 0x00 -#define HCI_ERR_ILLEGAL_COMMAND 0x01 -#define HCI_ERR_NO_CONNECTION 0x02 -#define HCI_ERR_MEMORY_FULL 0x07 -#define HCI_ERR_CONNECTION_TIMEOUT 0x08 -#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 -#define HCI_ERR_CONNECTION_EXISTS 0x0B -#define HCI_ERR_CONNECTION_DISALLOWED 0x0C -#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10 -#define HCI_ERR_UNSUPPORTED_VALUE 0x11 -#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 -#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16 -#define HCI_ERR_UNSPECIFIED 0x1F -#define HCI_ERR_UNIT_KEY_USED 0x26 -#define HCI_ERR_QOS_REJECTED 0x2D -#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 -#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39 -#define HCI_ERR_CHANNEL_MOVE 0xFF - -/* AMP HCI ACL Data packet format */ -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data { - uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */ - uint16 dlen; /* data total length */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t; - -#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data) - -#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14) -#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12) - -#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff) -#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12) - -/* AMP Activity Report packet formats */ -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report { - uint8 ScheduleKnown; - uint8 NumReports; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t; - -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple { - uint32 StartTime; - uint32 Duration; - uint32 Periodicity; -} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t; - -#define HCI_AR_SCHEDULE_KNOWN 0x01 - - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _bt_amp_hci_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/eapol.h b/drivers/net/wireless/bcmdhd/include/proto/eapol.h deleted file mode 100644 index 8fd84ee348e7..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/eapol.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 802.1x EAPOL definitions - * - * See - * IEEE Std 802.1X-2001 - * IEEE 802.1X RADIUS Usage Guidelines - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: eapol.h 528443 2015-01-22 09:29:18Z $ - */ - -#ifndef _eapol_h_ -#define _eapol_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - -#include - -/* EAPOL for 802.3/Ethernet */ -typedef BWL_PRE_PACKED_STRUCT struct { - struct ether_header eth; /* 802.3/Ethernet header */ - unsigned char version; /* EAPOL protocol version */ - unsigned char type; /* EAPOL type */ - unsigned short length; /* Length of body */ - unsigned char body[1]; /* Body (optional) */ -} BWL_POST_PACKED_STRUCT eapol_header_t; - -#define EAPOL_HEADER_LEN 18 - -typedef struct { - unsigned char version; /* EAPOL protocol version */ - unsigned char type; /* EAPOL type */ - unsigned short length; /* Length of body */ -} eapol_hdr_t; - -#define EAPOL_HDR_LEN 4 - -/* EAPOL version */ -#define WPA2_EAPOL_VERSION 2 -#define WPA_EAPOL_VERSION 1 -#define LEAP_EAPOL_VERSION 1 -#define SES_EAPOL_VERSION 1 - -/* EAPOL types */ -#define EAP_PACKET 0 -#define EAPOL_START 1 -#define EAPOL_LOGOFF 2 -#define EAPOL_KEY 3 -#define EAPOL_ASF 4 - -/* EAPOL-Key types */ -#define EAPOL_RC4_KEY 1 -#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ -#define EAPOL_WPA_KEY 254 /* WPA */ - -/* RC4 EAPOL-Key header field sizes */ -#define EAPOL_KEY_REPLAY_LEN 8 -#define EAPOL_KEY_IV_LEN 16 -#define EAPOL_KEY_SIG_LEN 16 - -/* RC4 EAPOL-Key */ -typedef BWL_PRE_PACKED_STRUCT struct { - unsigned char type; /* Key Descriptor Type */ - unsigned short length; /* Key Length (unaligned) */ - unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ - unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ - unsigned char index; /* Key Flags & Index */ - unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ - unsigned char key[1]; /* Key (optional) */ -} BWL_POST_PACKED_STRUCT eapol_key_header_t; - -#define EAPOL_KEY_HEADER_LEN 44 - -/* RC4 EAPOL-Key flags */ -#define EAPOL_KEY_FLAGS_MASK 0x80 -#define EAPOL_KEY_BROADCAST 0 -#define EAPOL_KEY_UNICAST 0x80 - -/* RC4 EAPOL-Key index */ -#define EAPOL_KEY_INDEX_MASK 0x7f - -/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ -#define EAPOL_WPA_KEY_REPLAY_LEN 8 -#define EAPOL_WPA_KEY_NONCE_LEN 32 -#define EAPOL_WPA_KEY_IV_LEN 16 -#define EAPOL_WPA_KEY_RSC_LEN 8 -#define EAPOL_WPA_KEY_ID_LEN 8 -#define EAPOL_WPA_KEY_MIC_LEN 16 -#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) -#define EAPOL_WPA_MAX_KEY_SIZE 32 - -/* WPA EAPOL-Key */ -typedef BWL_PRE_PACKED_STRUCT struct { - unsigned char type; /* Key Descriptor Type */ - unsigned short key_info; /* Key Information (unaligned) */ - unsigned short key_len; /* Key Length (unaligned) */ - unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ - unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ - unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ - unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ - unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ - unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ - unsigned short data_len; /* Key Data Length */ - unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ -} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t; - -#define EAPOL_WPA_KEY_LEN 95 - -/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ -#define WPA_KEY_DESC_OSEN 0x0 -#define WPA_KEY_DESC_V1 0x01 -#define WPA_KEY_DESC_V2 0x02 -#define WPA_KEY_DESC_V3 0x03 -#define WPA_KEY_PAIRWISE 0x08 -#define WPA_KEY_INSTALL 0x40 -#define WPA_KEY_ACK 0x80 -#define WPA_KEY_MIC 0x100 -#define WPA_KEY_SECURE 0x200 -#define WPA_KEY_ERROR 0x400 -#define WPA_KEY_REQ 0x800 - -#define WPA_KEY_DESC_V2_OR_V3 WPA_KEY_DESC_V2 - -/* WPA-only KEY KEY_INFO bits */ -#define WPA_KEY_INDEX_0 0x00 -#define WPA_KEY_INDEX_1 0x10 -#define WPA_KEY_INDEX_2 0x20 -#define WPA_KEY_INDEX_3 0x30 -#define WPA_KEY_INDEX_MASK 0x30 -#define WPA_KEY_INDEX_SHIFT 0x04 - -/* 802.11i/WPA2-only KEY KEY_INFO bits */ -#define WPA_KEY_ENCRYPTED_DATA 0x1000 - -/* Key Data encapsulation */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 type; - uint8 length; - uint8 oui[3]; - uint8 subtype; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; - -#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 - -#define WPA2_KEY_DATA_SUBTYPE_GTK 1 -#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 -#define WPA2_KEY_DATA_SUBTYPE_MAC 3 -#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 -#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 - -/* GTK encapsulation */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 flags; - uint8 reserved; - uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; -} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; - -#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 - -#define WPA2_GTK_INDEX_MASK 0x03 -#define WPA2_GTK_INDEX_SHIFT 0x00 - -#define WPA2_GTK_TRANSMIT 0x04 - -/* IGTK encapsulation */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 key_id; - uint8 ipn[6]; - uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; -} BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; - -#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8 - -/* STAKey encapsulation */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 reserved[2]; - uint8 mac[ETHER_ADDR_LEN]; - uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; -} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t; - -#define WPA2_KEY_DATA_PAD 0xdd - - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _eapol_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h deleted file mode 100644 index 54d363b49608..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: ethernet.h 473238 2014-04-28 19:14:56Z $ - */ - -#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ -#define _NET_ETHERNET_H_ - -#ifndef _TYPEDEFS_H_ -#include "typedefs.h" -#endif - -/* This marks the start of a packed structure section. */ -#include - - -/* - * The number of bytes in an ethernet (MAC) address. - */ -#define ETHER_ADDR_LEN 6 - -/* - * The number of bytes in the type field. - */ -#define ETHER_TYPE_LEN 2 - -/* - * The number of bytes in the trailing CRC field. - */ -#define ETHER_CRC_LEN 4 - -/* - * The length of the combined header. - */ -#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) - -/* - * The minimum packet length. - */ -#define ETHER_MIN_LEN 64 - -/* - * The minimum packet user data length. - */ -#define ETHER_MIN_DATA 46 - -/* - * The maximum packet length. - */ -#define ETHER_MAX_LEN 1518 - -/* - * The maximum packet user data length. - */ -#define ETHER_MAX_DATA 1500 - -/* ether types */ -#define ETHER_TYPE_MIN 0x0600 /* Anything less than MIN is a length */ -#define ETHER_TYPE_IP 0x0800 /* IP */ -#define ETHER_TYPE_ARP 0x0806 /* ARP */ -#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */ -#define ETHER_TYPE_IPV6 0x86dd /* IPv6 */ -#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */ -#define ETHER_TYPE_802_1X 0x888e /* 802.1x */ -#ifdef PLC -#define ETHER_TYPE_88E1 0x88e1 /* GIGLE */ -#define ETHER_TYPE_8912 0x8912 /* GIGLE */ -#define ETHER_TYPE_GIGLED 0xffff /* GIGLE */ -#endif /* PLC */ -#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */ -#define ETHER_TYPE_WAI 0x88b4 /* WAI */ -#define ETHER_TYPE_89_0D 0x890d /* 89-0d frame for TDLS */ - -#define ETHER_TYPE_PPP_SES 0x8864 /* PPPoE Session */ - -#define ETHER_TYPE_IAPP_L2_UPDATE 0x6 /* IAPP L2 update frame */ - -/* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */ -#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */ - -/* ether header */ -#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) /* dest address offset */ -#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) /* src address offset */ -#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) /* ether type offset */ - -/* - * A macro to validate a length with - */ -#define ETHER_IS_VALID_LEN(foo) \ - ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) - -#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ - ((uint8 *)ea)[0] = 0x01; \ - ((uint8 *)ea)[1] = 0x00; \ - ((uint8 *)ea)[2] = 0x5e; \ - ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ - ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ - ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ -} - -#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ -/* - * Structure of a 10Mb/s Ethernet header. - */ -BWL_PRE_PACKED_STRUCT struct ether_header { - uint8 ether_dhost[ETHER_ADDR_LEN]; - uint8 ether_shost[ETHER_ADDR_LEN]; - uint16 ether_type; -} BWL_POST_PACKED_STRUCT; - -/* - * Structure of a 48-bit Ethernet address. - */ -BWL_PRE_PACKED_STRUCT struct ether_addr { - uint8 octet[ETHER_ADDR_LEN]; -} BWL_POST_PACKED_STRUCT; -#endif /* !__INCif_etherh Quick and ugly hack for VxWorks */ - -/* - * Takes a pointer, set, test, clear, toggle locally admininistered - * address bit in the 48-bit Ethernet address. - */ -#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) -#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) -#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) -#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) - -/* Takes a pointer, marks unicast address bit in the MAC address */ -#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) - -/* - * Takes a pointer, returns true if a 48-bit multicast address - * (including broadcast, since it is all ones) - */ -#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) - - -/* compare two ethernet addresses - assumes the pointers can be referenced as shorts */ -#define eacmp(a, b) ((((const uint16 *)(a))[0] ^ ((const uint16 *)(b))[0]) | \ - (((const uint16 *)(a))[1] ^ ((const uint16 *)(b))[1]) | \ - (((const uint16 *)(a))[2] ^ ((const uint16 *)(b))[2])) - -#define ether_cmp(a, b) eacmp(a, b) - -/* copy an ethernet address - assumes the pointers can be referenced as shorts */ -#define eacopy(s, d) \ -do { \ - ((uint16 *)(d))[0] = ((const uint16 *)(s))[0]; \ - ((uint16 *)(d))[1] = ((const uint16 *)(s))[1]; \ - ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \ -} while (0) - -#define ether_copy(s, d) eacopy(s, d) - -/* Copy an ethernet address in reverse order */ -#define ether_rcopy(s, d) \ -do { \ - ((uint16 *)(d))[2] = ((uint16 *)(s))[2]; \ - ((uint16 *)(d))[1] = ((uint16 *)(s))[1]; \ - ((uint16 *)(d))[0] = ((uint16 *)(s))[0]; \ -} while (0) - -/* Copy 14B ethernet header: 32bit aligned source and destination. */ -#define ehcopy32(s, d) \ -do { \ - ((uint32 *)(d))[0] = ((const uint32 *)(s))[0]; \ - ((uint32 *)(d))[1] = ((const uint32 *)(s))[1]; \ - ((uint32 *)(d))[2] = ((const uint32 *)(s))[2]; \ - ((uint16 *)(d))[6] = ((const uint16 *)(s))[6]; \ -} while (0) - - -static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; -static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; -static const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; - -#define ETHER_ISBCAST(ea) ((((const uint8 *)(ea))[0] & \ - ((const uint8 *)(ea))[1] & \ - ((const uint8 *)(ea))[2] & \ - ((const uint8 *)(ea))[3] & \ - ((const uint8 *)(ea))[4] & \ - ((const uint8 *)(ea))[5]) == 0xff) -#define ETHER_ISNULLADDR(ea) ((((const uint8 *)(ea))[0] | \ - ((const uint8 *)(ea))[1] | \ - ((const uint8 *)(ea))[2] | \ - ((const uint8 *)(ea))[3] | \ - ((const uint8 *)(ea))[4] | \ - ((const uint8 *)(ea))[5]) == 0) - -#define ETHER_ISNULLDEST(da) ((((const uint16 *)(da))[0] | \ - ((const uint16 *)(da))[1] | \ - ((const uint16 *)(da))[2]) == 0) -#define ETHER_ISNULLSRC(sa) ETHER_ISNULLDEST(sa) - -#define ETHER_MOVE_HDR(d, s) \ -do { \ - struct ether_header t; \ - t = *(struct ether_header *)(s); \ - *(struct ether_header *)(d) = t; \ -} while (0) - -#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0) - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _NET_ETHERNET_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/nan.h b/drivers/net/wireless/bcmdhd/include/proto/nan.h deleted file mode 100644 index 40b5058320d3..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/nan.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental types and constants relating to WFA NAN - * (Neighbor Awareness Networking) - * - * $Id$ - */ -#ifndef _NAN_H_ -#define _NAN_H_ - -#include -#include - - -/* This marks the start of a packed structure section. */ -#include - -/* WiFi NAN OUI values */ -#define NAN_OUI WFA_OUI /* WiFi OUI */ -/* For oui_type field identifying the type and version of the NAN IE. */ -#define NAN_OUI_TYPE 0x13 /* Type/Version */ -/* IEEE 802.11 vendor specific information element. (Same as P2P_IE_ID.) */ -#define NAN_IE_ID 0xdd - -/* Same as P2P_PUB_AF_CATEGORY and DOT11_ACTION_CAT_PUBLIC */ -#define NAN_PUB_AF_CATEGORY 0x04 -/* IEEE 802.11 Public Action Frame Vendor Specific. (Same as P2P_PUB_AF_ACTION.) */ -#define NAN_PUB_AF_ACTION 0x09 -/* Number of octents in hash of service name. (Same as P2P_WFDS_HASH_LEN.) */ -#define NAN_SVC_HASH_LEN 6 -/* Size of fixed length part of nan_pub_act_frame_t before attributes. */ -#define NAN_PUB_ACT_FRAME_FIXED_LEN 6 -/* Number of octents in master rank value. */ -#define NAN_MASTER_RANK_LEN 8 -/* NAN public action frame header size */ -#define NAN_PUB_ACT_FRAME_HDR_SIZE (OFFSETOF(nan_pub_act_frame_t, data)) -/* NAN network ID */ -#define NAN_NETWORK_ID "\x51\x6F\x9A\x01\x00\x00" -/* Service Control Type length */ -#define NAN_SVC_CONTROL_TYPE_LEN 2 - -/* Attribute TLV header size */ -#define NAN_ATTR_ID_OFF 0 -#define NAN_ATTR_LEN_OFF 1 -#define NAN_ATTR_DATA_OFF 3 - -#define NAN_ATTR_ID_LEN 1 /* ID field length */ -#define NAN_ATTR_LEN_LEN 2 /* Length field length */ -#define NAN_ATTR_HDR_LEN 3 /* ID + 2-byte length field */ - -/* Vendor-specific public action frame for NAN */ -typedef BWL_PRE_PACKED_STRUCT struct nan_pub_act_frame_s { - /* NAN_PUB_AF_CATEGORY 0x04 */ - uint8 category_id; - /* NAN_PUB_AF_ACTION 0x09 */ - uint8 action_field; - /* NAN_OUI 0x50-6F-9A */ - uint8 oui[DOT11_OUI_LEN]; - /* NAN_OUI_TYPE 0x13 */ - uint8 oui_type; - /* One or more NAN Attributes follow */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT nan_pub_act_frame_t; - -/* NAN attributes as defined in the nan spec */ -enum { - NAN_ATTR_MASTER_IND = 0, - NAN_ATTR_CLUSTER = 1, - NAN_ATTR_SVC_ID_LIST = 2, - NAN_ATTR_SVC_DESCRIPTOR = 3, - NAN_ATTR_CONN_CAP = 4, - NAN_ATTR_INFRA = 5, - NAN_ATTR_P2P = 6, - NAN_ATTR_IBSS = 7, - NAN_ATTR_MESH = 8, - NAN_ATTR_FURTHER_NAN_SD = 9, - NAN_ATTR_FURTHER_AVAIL = 10, - NAN_ATTR_COUNTRY_CODE = 11, - NAN_ATTR_RANGING = 12, - NAN_ATTR_VENDOR_SPECIFIC = 221 -}; - -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ie_s { - uint8 id; /* IE ID: NAN_IE_ID 0xDD */ - uint8 len; /* IE length */ - uint8 oui[DOT11_OUI_LEN]; /* NAN_OUI 50:6F:9A */ - uint8 oui_type; /* NAN_OUI_TYPE 0x13 */ - uint8 attr[1]; /* var len attributes */ -} BWL_POST_PACKED_STRUCT wifi_nan_ie_t; - -#define NAN_IE_HDR_SIZE (OFFSETOF(wifi_nan_ie_t, attr)) - -/* master indication record */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_master_ind_attr_s { - uint8 id; - uint16 len; - uint8 master_preference; - uint8 random_factor; -} BWL_POST_PACKED_STRUCT wifi_nan_master_ind_attr_t; - -/* cluster attr record */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_cluster_attr_s { - uint8 id; - uint16 len; - uint8 amr[NAN_MASTER_RANK_LEN]; - uint8 hop_count; - /* Anchor Master Beacon Transmission Time */ - uint32 ambtt; -} BWL_POST_PACKED_STRUCT wifi_nan_cluster_attr_t; - -/* container for service ID records */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_id_attr_s { - uint8 id; - uint16 len; - uint8 svcid[NAN_SVC_HASH_LEN]; /* 6*len of srvc IDs */ -} BWL_POST_PACKED_STRUCT wifi_nan_svc_id_attr_t; - -/* service_control bitmap for wifi_nan_svc_descriptor_attr_t below */ -#define NAN_SC_PUBLISH 0x0 -#define NAN_SC_SUBSCRIBE 0x1 -#define NAN_SC_FOLLOWUP 0x2 -/* Set to 1 if a Matching Filter field is included in descriptors. */ -#define NAN_SC_MATCHING_FILTER_PRESENT 0x8 -/* Set to 1 if a Service Response Filter field is included in descriptors. */ -#define NAN_SC_SR_FILTER_PRESENT 0x10 -/* Set to 1 if a Service Info field is included in descriptors. */ -#define NAN_SC_SVC_INFO_PRESENT 0x20 -/* range is close proximity only */ -#define NAN_SC_RANGE_LIMITED 0x40 - -/* Service descriptor */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_descriptor_attr_s { - /* Attribute ID - 0x03. */ - uint8 id; - /* Length of the following fields in the attribute */ - uint16 len; - /* Hash of the Service Name */ - uint8 svc_hash[NAN_SVC_HASH_LEN]; - /* Publish or subscribe instance id */ - uint8 instance_id; - /* Requestor Instance ID */ - uint8 requestor_id; - /* Service Control Bitmask. Also determines what data follows. */ - uint8 svc_control; - /* Optional fields follow */ -} BWL_POST_PACKED_STRUCT wifi_nan_svc_descriptor_attr_t; - -/* IBSS attribute */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ibss_attr_s { - /* Attribute ID - 0x07. */ - uint8 id; - /* Length of the following fields in the attribute */ - uint16 len; - /* BSSID of the ibss */ - struct ether_addr bssid; - /* - map control:, bits: - [0-3]: Id for associated further avail map attribute - [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved - [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf? - [7] : reserved - */ - uint8 map_ctrl; - /* avail. intervals bitmap, var len */ - uint8 avail_bmp[1]; -} BWL_POST_PACKED_STRUCT wifi_nan_ibss_attr_t; - -/* Further Availability MAP attr */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_favail_attr_s { - /* Attribute ID - 0x0A. */ - uint8 id; - /* Length of the following fields in the attribute */ - uint16 len; - /* MAP id: val [0..15], values[16-255] reserved */ - uint8 map_id; - /* availibility entry, var len */ - uint8 avil_entry[1]; -} BWL_POST_PACKED_STRUCT wifi_nan_favail_attr_t; - -/* Further Availability MAP attr */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_s { - /* - entry control - [0-1]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; - [2:7] reserved - */ - uint8 entry_ctrl; - /* operating class: freq band etc IEEE 802.11 */ - uint8 opclass; - /* channel number */ - uint8 chan; - uint8 map_id; - /* avail bmp, var len */ - uint8 avail_bmp[1]; -} BWL_POST_PACKED_STRUCT wifi_nan_avail_entry_t; - -/* Map control Field */ -#define NAN_MAPCTRL_IDMASK 0x7 -#define NAN_MAPCTRL_DURSHIFT 3 -#define NAN_MAPCTRL_REPEAT 0x40 - -#define NAN_VENDOR_TYPE_RTT 0 -#define NAN_VENDOR_TYPE_P2P 1 - -/* Vendor Specific Attribute */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_vendor_attr_s { - uint8 id; /* 0xDD */ - uint16 len; /* IE length */ - uint8 oui[DOT11_OUI_LEN]; /* 00-90-4C */ - uint8 type; /* attribute type */ - uint8 attr[1]; /* var len attributes */ -} BWL_POST_PACKED_STRUCT wifi_nan_vendor_attr_t; - -#define NAN_VENDOR_HDR_SIZE (OFFSETOF(wifi_nan_vendor_attr_t, attr)) - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _NAN_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/include/proto/p2p.h deleted file mode 100644 index 487603240fb3..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/p2p.h +++ /dev/null @@ -1,710 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) - * - * $Id: p2p.h 457033 2014-02-20 19:39:45Z $ - */ - -#ifndef _P2P_H_ -#define _P2P_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif -#include -#include - -/* This marks the start of a packed structure section. */ -#include - - -/* WiFi P2P OUI values */ -#define P2P_OUI WFA_OUI /* WiFi P2P OUI */ -#define P2P_VER WFA_OUI_TYPE_P2P /* P2P version: 9=WiFi P2P v1.0 */ - -#define P2P_IE_ID 0xdd /* P2P IE element ID */ - -/* WiFi P2P IE */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { - uint8 id; /* IE ID: 0xDD */ - uint8 len; /* IE length */ - uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ - uint8 oui_type; /* Identifies P2P version: P2P_VER */ - uint8 subelts[1]; /* variable length subelements */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_ie wifi_p2p_ie_t; - -#define P2P_IE_FIXED_LEN 6 - -#define P2P_ATTR_ID_OFF 0 -#define P2P_ATTR_LEN_OFF 1 -#define P2P_ATTR_DATA_OFF 3 - -#define P2P_ATTR_ID_LEN 1 /* ID filed length */ -#define P2P_ATTR_LEN_LEN 2 /* length field length */ -#define P2P_ATTR_HDR_LEN 3 /* ID + 2-byte length field spec 1.02 */ - -#define P2P_WFDS_HASH_LEN 6 -#define P2P_WFDS_MAX_SVC_NAME_LEN 32 - -/* P2P IE Subelement IDs from WiFi P2P Technical Spec 1.00 */ -#define P2P_SEID_STATUS 0 /* Status */ -#define P2P_SEID_MINOR_RC 1 /* Minor Reason Code */ -#define P2P_SEID_P2P_INFO 2 /* P2P Capability (capabilities info) */ -#define P2P_SEID_DEV_ID 3 /* P2P Device ID */ -#define P2P_SEID_INTENT 4 /* Group Owner Intent */ -#define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */ -#define P2P_SEID_CHANNEL 6 /* Listen channel */ -#define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */ -#define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */ -#define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */ -#define P2P_SEID_P2P_MGBTY 10 /* P2P Manageability */ -#define P2P_SEID_CHAN_LIST 11 /* Channel List */ -#define P2P_SEID_ABSENCE 12 /* Notice of Absence */ -#define P2P_SEID_DEV_INFO 13 /* Device Info */ -#define P2P_SEID_GROUP_INFO 14 /* Group Info */ -#define P2P_SEID_GROUP_ID 15 /* Group ID */ -#define P2P_SEID_P2P_IF 16 /* P2P Interface */ -#define P2P_SEID_OP_CHANNEL 17 /* Operating Channel */ -#define P2P_SEID_INVITE_FLAGS 18 /* Invitation Flags */ -#define P2P_SEID_SERVICE_HASH 21 /* Service hash */ -#define P2P_SEID_SESSION 22 /* Session information */ -#define P2P_SEID_CONNECT_CAP 23 /* Connection capability */ -#define P2P_SEID_ADVERTISE_ID 24 /* Advertisement ID */ -#define P2P_SEID_ADVERTISE_SERVICE 25 /* Advertised service */ -#define P2P_SEID_SESSION_ID 26 /* Session ID */ -#define P2P_SEID_FEATURE_CAP 27 /* Feature capability */ -#define P2P_SEID_PERSISTENT_GROUP 28 /* Persistent group */ -#define P2P_SEID_SESSION_INFO_RESP 29 /* Session Information Response */ -#define P2P_SEID_VNDR 221 /* Vendor-specific subelement */ - -#define P2P_SE_VS_ID_SERVICES 0x1b - - -/* WiFi P2P IE subelement: P2P Capability (capabilities info) */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { - uint8 eltId; /* SE ID: P2P_SEID_P2P_INFO */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 dev; /* Device Capability Bitmap */ - uint8 group; /* Group Capability Bitmap */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; - -/* P2P Capability subelement's Device Capability Bitmap bit values */ -#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 /* Service Discovery */ -#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 /* Client Discoverability */ -#define P2P_CAPSE_DEV_CONCURRENT 0x4 /* Concurrent Operation */ -#define P2P_CAPSE_DEV_INFRA_MAN 0x8 /* P2P Infrastructure Managed */ -#define P2P_CAPSE_DEV_LIMIT 0x10 /* P2P Device Limit */ -#define P2P_CAPSE_INVITE_PROC 0x20 /* P2P Invitation Procedure */ - -/* P2P Capability subelement's Group Capability Bitmap bit values */ -#define P2P_CAPSE_GRP_OWNER 0x1 /* P2P Group Owner */ -#define P2P_CAPSE_PERSIST_GRP 0x2 /* Persistent P2P Group */ -#define P2P_CAPSE_GRP_LIMIT 0x4 /* P2P Group Limit */ -#define P2P_CAPSE_GRP_INTRA_BSS 0x8 /* Intra-BSS Distribution */ -#define P2P_CAPSE_GRP_X_CONNECT 0x10 /* Cross Connection */ -#define P2P_CAPSE_GRP_PERSISTENT 0x20 /* Persistent Reconnect */ -#define P2P_CAPSE_GRP_FORMATION 0x40 /* Group Formation */ - - -/* WiFi P2P IE subelement: Group Owner Intent */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { - uint8 eltId; /* SE ID: P2P_SEID_INTENT */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 intent; /* Intent Value 0...15 (0=legacy 15=master only) */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; - -/* WiFi P2P IE subelement: Configuration Timeout */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { - uint8 eltId; /* SE ID: P2P_SEID_CFG_TIMEOUT */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 go_tmo; /* GO config timeout in units of 10 ms */ - uint8 client_tmo; /* Client config timeout in units of 10 ms */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; - -/* WiFi P2P IE subelement: Listen Channel */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_listen_channel_se_s { - uint8 eltId; /* SE ID: P2P_SEID_CHANNEL */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 country[3]; /* Country String */ - uint8 op_class; /* Operating Class */ - uint8 channel; /* Channel */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_listen_channel_se_s wifi_p2p_listen_channel_se_t; - -/* WiFi P2P IE subelement: P2P Group BSSID */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_bssid_se_s { - uint8 eltId; /* SE ID: P2P_SEID_GRP_BSSID */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P group bssid */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; - -/* WiFi P2P IE subelement: P2P Group ID */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { - uint8 eltId; /* SE ID: P2P_SEID_GROUP_ID */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P device address */ - uint8 ssid[1]; /* ssid. device id. variable length */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; - -/* WiFi P2P IE subelement: P2P Interface */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { - uint8 eltId; /* SE ID: P2P_SEID_P2P_IF */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P device address */ - uint8 ifaddrs; /* P2P Interface Address count */ - uint8 ifaddr[1][6]; /* P2P Interface Address list */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; - -/* WiFi P2P IE subelement: Status */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { - uint8 eltId; /* SE ID: P2P_SEID_STATUS */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 status; /* Status Code: P2P_STATSE_* */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; - -/* Status subelement Status Code definitions */ -#define P2P_STATSE_SUCCESS 0 - /* Success */ -#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 - /* Failed, information currently unavailable */ -#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL - /* Old name for above in P2P spec 1.08 and older */ -#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 - /* Failed, incompatible parameters */ -#define P2P_STATSE_FAIL_LIMIT_REACHED 3 - /* Failed, limit reached */ -#define P2P_STATSE_FAIL_INVALID_PARAMS 4 - /* Failed, invalid parameters */ -#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 - /* Failed, unable to accomodate request */ -#define P2P_STATSE_FAIL_PROTO_ERROR 6 - /* Failed, previous protocol error or disruptive behaviour */ -#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 - /* Failed, no common channels */ -#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 - /* Failed, unknown P2P Group */ -#define P2P_STATSE_FAIL_INTENT 9 - /* Failed, both peers indicated Intent 15 in GO Negotiation */ -#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 - /* Failed, incompatible provisioning method */ -#define P2P_STATSE_FAIL_USER_REJECT 11 - /* Failed, rejected by user */ -#define P2P_STATSE_SUCCESS_USER_ACCEPT 12 - /* Success, accepted by user */ - -/* WiFi P2P IE attribute: Extended Listen Timing */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { - uint8 eltId; /* ID: P2P_SEID_EXT_TIMING */ - uint8 len[2]; /* length not including eltId, len fields */ - uint8 avail[2]; /* availibility period */ - uint8 interval[2]; /* availibility interval */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; - -#define P2P_EXT_MIN 10 /* minimum 10ms */ - -/* WiFi P2P IE subelement: Intended P2P Interface Address */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { - uint8 eltId; /* SE ID: P2P_SEID_INTINTADDR */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* intended P2P interface MAC address */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; - -/* WiFi P2P IE subelement: Channel */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { - uint8 eltId; /* SE ID: P2P_SEID_STATUS */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 band; /* Regulatory Class (band) */ - uint8 channel; /* Channel */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; - - -/* Channel Entry structure within the Channel List SE */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { - uint8 band; /* Regulatory Class (band) */ - uint8 num_channels; /* # of channels in the channel list */ - uint8 channels[WL_NUMCHANNELS]; /* Channel List */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; -#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 - -/* WiFi P2P IE subelement: Channel List */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { - uint8 eltId; /* SE ID: P2P_SEID_CHAN_LIST */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 country[3]; /* Country String */ - uint8 num_entries; /* # of channel entries */ - wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; - /* Channel Entry List */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; - -/* WiFi Primary Device Type structure */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_pri_devtype_s { - uint16 cat_id; /* Category ID */ - uint8 OUI[3]; /* WFA OUI: 0x0050F2 */ - uint8 oui_type; /* WPS_OUI_TYPE */ - uint16 sub_cat_id; /* Sub Category ID */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_pri_devtype_s wifi_p2p_pri_devtype_t; - -/* WiFi P2P Device Info Sub Element Primary Device Type Sub Category - * maximum values for each category - */ -#define P2P_DISE_SUBCATEGORY_MINVAL 1 -#define P2P_DISE_CATEGORY_COMPUTER 1 -#define P2P_DISE_SUBCATEGORY_COMPUTER_MAXVAL 8 -#define P2P_DISE_CATEGORY_INPUT_DEVICE 2 -#define P2P_DISE_SUBCATEGORY_INPUT_DEVICE_MAXVAL 9 -#define P2P_DISE_CATEGORY_PRINTER 3 -#define P2P_DISE_SUBCATEGORY_PRINTER_MAXVAL 5 -#define P2P_DISE_CATEGORY_CAMERA 4 -#define P2P_DISE_SUBCATEGORY_CAMERA_MAXVAL 4 -#define P2P_DISE_CATEGORY_STORAGE 5 -#define P2P_DISE_SUBCATEGORY_STORAGE_MAXVAL 1 -#define P2P_DISE_CATEGORY_NETWORK_INFRA 6 -#define P2P_DISE_SUBCATEGORY_NETWORK_INFRA_MAXVAL 4 -#define P2P_DISE_CATEGORY_DISPLAY 7 -#define P2P_DISE_SUBCATEGORY_DISPLAY_MAXVAL 4 -#define P2P_DISE_CATEGORY_MULTIMEDIA 8 -#define P2P_DISE_SUBCATEGORY_MULTIMEDIA_MAXVAL 6 -#define P2P_DISE_CATEGORY_GAMING 9 -#define P2P_DISE_SUBCATEGORY_GAMING_MAXVAL 5 -#define P2P_DISE_CATEGORY_TELEPHONE 10 -#define P2P_DISE_SUBCATEGORY_TELEPHONE_MAXVAL 5 -#define P2P_DISE_CATEGORY_AUDIO 11 -#define P2P_DISE_SUBCATEGORY_AUDIO_MAXVAL 6 - -/* WiFi P2P IE's Device Info subelement */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { - uint8 eltId; /* SE ID: P2P_SEID_DEVINFO */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P Device MAC address */ - uint16 wps_cfg_meths; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ - uint8 pri_devtype[8]; /* Primary Device Type */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; - -#define P2P_DEV_TYPE_LEN 8 - -/* WiFi P2P IE's Group Info subelement Client Info Descriptor */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { - uint8 len; - uint8 devaddr[ETHER_ADDR_LEN]; /* P2P Device Address */ - uint8 ifaddr[ETHER_ADDR_LEN]; /* P2P Interface Address */ - uint8 devcap; /* Device Capability */ - uint8 cfg_meths[2]; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ - uint8 pridt[P2P_DEV_TYPE_LEN]; /* Primary Device Type */ - uint8 secdts; /* Number of Secondary Device Types */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; - -/* WiFi P2P IE's Device ID subelement */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { - uint8 eltId; - uint8 len[2]; - struct ether_addr addr; /* P2P Device MAC address */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; - -/* WiFi P2P IE subelement: P2P Manageability */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { - uint8 eltId; /* SE ID: P2P_SEID_P2P_MGBTY */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mg_bitmap; /* manageability bitmap */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; -/* mg_bitmap field bit values */ -#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 /* AP supports Managed P2P Device */ - -/* WiFi P2P IE subelement: Group Info */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { - uint8 eltId; /* SE ID: P2P_SEID_GROUP_INFO */ - uint8 len[2]; /* SE length not including eltId, len fields */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; - -/* WiFi IE subelement: Operating Channel */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_op_channel_se_s { - uint8 eltId; /* SE ID: P2P_SEID_OP_CHANNEL */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 country[3]; /* Country String */ - uint8 op_class; /* Operating Class */ - uint8 channel; /* Channel */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_op_channel_se_s wifi_p2p_op_channel_se_t; - -/* WiFi IE subelement: INVITATION FLAGS */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_invite_flags_se_s { - uint8 eltId; /* SE ID: P2P_SEID_INVITE_FLAGS */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 flags; /* Flags */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_invite_flags_se_s wifi_p2p_invite_flags_se_t; - -/* WiFi P2P IE subelement: Service Hash */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_serv_hash_se_s { - uint8 eltId; /* SE ID: P2P_SEID_SERVICE_HASH */ - uint8 len[2]; /* SE length not including eltId, len fields - * in multiple of 6 Bytes - */ - uint8 hash[1]; /* Variable length - SHA256 hash of - * service names (can be more than one hashes) - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_serv_hash_se_s wifi_p2p_serv_hash_se_t; - -/* WiFi P2P IE subelement: Service Instance Data */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_serv_inst_data_se_s { - uint8 eltId; /* SE ID: P2P_SEID_SESSION */ - uint8 len[2]; /* SE length not including eltId, len */ - uint8 ssn_info[1]; /* Variable length - Session information as specified by - * the service layer, type matches serv. name - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_serv_inst_data_se_s wifi_p2p_serv_inst_data_se_t; - - -/* WiFi P2P IE subelement: Connection capability */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_conn_cap_data_se_s { - uint8 eltId; /* SE ID: P2P_SEID_CONNECT_CAP */ - uint8 len[2]; /* SE length not including eltId, len */ - uint8 conn_cap; /* 1byte capability as specified by the - * service layer, valid bitmask/values - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_conn_cap_data_se_s wifi_p2p_conn_cap_data_se_t; - - -/* WiFi P2P IE subelement: Advertisement ID */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_advt_id_se_s { - uint8 eltId; /* SE ID: P2P_SEID_ADVERTISE_ID */ - uint8 len[2]; /* SE length not including eltId, len fixed 4 Bytes */ - uint8 advt_id[4]; /* 4byte Advertisement ID of the peer device sent in - * PROV Disc in Network byte order - */ - uint8 advt_mac[6]; /* P2P device address of the service advertiser */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_advt_id_se_s wifi_p2p_advt_id_se_t; - - -/* WiFi P2P IE subelement: Advertise Service Hash */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_adv_serv_info_s { - uint8 advt_id[4]; /* SE Advertise ID for the service */ - uint16 nw_cfg_method; /* SE Network Config method for the service */ - uint8 serv_name_len; /* SE length of the service name */ - uint8 serv_name[1]; /* Variable length service name field */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_adv_serv_info_s wifi_p2p_adv_serv_info_t; - - -/* WiFi P2P IE subelement: Advertise Service Hash */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_advt_serv_se_s { - uint8 eltId; /* SE ID: P2P_SEID_ADVERTISE_SERVICE */ - uint8 len[2]; /* SE length not including eltId, len fields mutiple len of - * wifi_p2p_adv_serv_info_t entries - */ - wifi_p2p_adv_serv_info_t p_advt_serv_info[1]; /* Variable length - of multiple instances - of the advertise service info - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_advt_serv_se_s wifi_p2p_advt_serv_se_t; - - -/* WiFi P2P IE subelement: Session ID */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_ssn_id_se_s { - uint8 eltId; /* SE ID: P2P_SEID_SESSION_ID */ - uint8 len[2]; /* SE length not including eltId, len fixed 4 Bytes */ - uint8 ssn_id[4]; /* 4byte Session ID of the peer device sent in - * PROV Disc in Network byte order - */ - uint8 ssn_mac[6]; /* P2P device address of the seeker - session mac */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_ssn_id_se_s wifi_p2p_ssn_id_se_t; - - -#define P2P_ADVT_SERV_SE_FIXED_LEN 3 /* Includes only the element ID and len */ -#define P2P_ADVT_SERV_INFO_FIXED_LEN 7 /* Per ADV Service Instance advt_id + - * nw_config_method + serv_name_len - */ - -/* WiFi P2P Action Frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { - uint8 category; /* P2P_AF_CATEGORY */ - uint8 OUI[3]; /* OUI - P2P_OUI */ - uint8 type; /* OUI Type - P2P_VER */ - uint8 subtype; /* OUI Subtype - P2P_AF_* */ - uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ - uint8 elts[1]; /* Variable length information elements. Max size = - * ACTION_FRAME_SIZE - sizeof(this structure) - 1 - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; -#define P2P_AF_CATEGORY 0x7f - -#define P2P_AF_FIXED_LEN 7 - -/* WiFi P2P Action Frame OUI Subtypes */ -#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ -#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ -#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ -#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ - - -/* WiFi P2P Public Action Frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { - uint8 category; /* P2P_PUB_AF_CATEGORY */ - uint8 action; /* P2P_PUB_AF_ACTION */ - uint8 oui[3]; /* P2P_OUI */ - uint8 oui_type; /* OUI type - P2P_VER */ - uint8 subtype; /* OUI subtype - P2P_TYPE_* */ - uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ - uint8 elts[1]; /* Variable length information elements. Max size = - * ACTION_FRAME_SIZE - sizeof(this structure) - 1 - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; -#define P2P_PUB_AF_FIXED_LEN 8 -#define P2P_PUB_AF_CATEGORY 0x04 -#define P2P_PUB_AF_ACTION 0x09 - -/* WiFi P2P Public Action Frame OUI Subtypes */ -#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ -#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ -#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ -#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ -#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ -#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ -#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ -#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ -#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ -#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ - -/* TODO: Stop using these obsolete aliases for P2P_PAF_GON_* */ -#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ -#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP -#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF - -/* WiFi P2P IE subelement: Notice of Absence */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { - uint8 cnt_type; /* Count/Type */ - uint32 duration; /* Duration */ - uint32 interval; /* Interval */ - uint32 start; /* Start Time */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; - -BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { - uint8 eltId; /* Subelement ID */ - uint8 len[2]; /* Length */ - uint8 index; /* Index */ - uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ - wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; - -#define P2P_NOA_SE_FIXED_LEN 5 - -#define P2P_NOA_SE_MAX_DESC 2 /* max NoA descriptors in presence request */ - -/* cnt_type field values */ -#define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */ -#define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */ -#define P2P_NOA_DESC_TYPE_PREFERRED 1 /* preferred values */ -#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 /* acceptable limits */ - -/* ctw_ops_parms field values */ -#define P2P_NOA_CTW_MASK 0x7f -#define P2P_NOA_OPS_MASK 0x80 -#define P2P_NOA_OPS_SHIFT 7 - -#define P2P_CTW_MIN 10 /* minimum 10TU */ - -/* - * P2P Service Discovery related - */ -#define P2PSD_ACTION_CATEGORY 0x04 - /* Public action frame */ -#define P2PSD_ACTION_ID_GAS_IREQ 0x0a - /* Action value for GAS Initial Request AF */ -#define P2PSD_ACTION_ID_GAS_IRESP 0x0b - /* Action value for GAS Initial Response AF */ -#define P2PSD_ACTION_ID_GAS_CREQ 0x0c - /* Action value for GAS Comback Request AF */ -#define P2PSD_ACTION_ID_GAS_CRESP 0x0d - /* Action value for GAS Comback Response AF */ -#define P2PSD_AD_EID 0x6c - /* Advertisement Protocol IE ID */ -#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 - /* Query Response Length Limit 7 bits plus PAME-BI 1 bit */ -#define P2PSD_ADP_PROTO_ID 0x00 - /* Advertisement Protocol ID. Always 0 for P2P SD */ -#define P2PSD_GAS_OUI P2P_OUI - /* WFA OUI */ -#define P2PSD_GAS_OUI_SUBTYPE P2P_VER - /* OUI Subtype for GAS IE */ -#define P2PSD_GAS_NQP_INFOID 0xDDDD - /* NQP Query Info ID: 56797 */ -#define P2PSD_GAS_COMEBACKDEALY 0x00 - /* Not used in the Native GAS protocol */ - -/* Service Protocol Type */ -typedef enum p2psd_svc_protype { - SVC_RPOTYPE_ALL = 0, - SVC_RPOTYPE_BONJOUR = 1, - SVC_RPOTYPE_UPNP = 2, - SVC_RPOTYPE_WSD = 3, - SVC_RPOTYPE_WFDS = 11, - SVC_RPOTYPE_VENDOR = 255 -} p2psd_svc_protype_t; - -/* Service Discovery response status code */ -typedef enum { - P2PSD_RESP_STATUS_SUCCESS = 0, - P2PSD_RESP_STATUS_PROTYPE_NA = 1, - P2PSD_RESP_STATUS_DATA_NA = 2, - P2PSD_RESP_STATUS_BAD_REQUEST = 3 -} p2psd_resp_status_t; - -/* Advertisement Protocol IE tuple field */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { - uint8 llm_pamebi; /* Query Response Length Limit bit 0-6, set to 0 plus - * Pre-Associated Message Exchange BSSID Independent bit 7, set to 0 - */ - uint8 adp_id; /* Advertisement Protocol ID: 0 for NQP Native Query Protocol */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; - -/* Advertisement Protocol IE */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { - uint8 id; /* IE ID: 0x6c - 108 */ - uint8 len; /* IE length */ - wifi_p2psd_adp_tpl_t adp_tpl; /* Advertisement Protocol Tuple field. Only one - * tuple is defined for P2P Service Discovery - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; - -/* NQP Vendor-specific Content */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { - uint8 oui_subtype; /* OUI Subtype: 0x09 */ - uint16 svc_updi; /* Service Update Indicator */ - uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request, - * wifi_p2psd_qresp_tlv_t type for service response - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; - -/* Service Request TLV */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { - uint16 len; /* Length: 5 plus size of Query Data */ - uint8 svc_prot; /* Service Protocol Type */ - uint8 svc_tscid; /* Service Transaction ID */ - uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; - -/* Query Request Frame, defined in generic format, instead of NQP specific */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { - uint16 info_id; /* Info ID: 0xDDDD */ - uint16 len; /* Length of service request TLV, 5 plus the size of request data */ - uint8 oui[3]; /* WFA OUI: 0x0050F2 */ - uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */ - -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; - -/* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { - wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ - uint16 qreq_len; /* Query Request Length */ - uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; - -/* Service Response TLV */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { - uint16 len; /* Length: 5 plus size of Query Data */ - uint8 svc_prot; /* Service Protocol Type */ - uint8 svc_tscid; /* Service Transaction ID */ - uint8 status; /* Value defined in Table 57 of P2P spec. */ - uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; - -/* Query Response Frame, defined in generic format, instead of NQP specific */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { - uint16 info_id; /* Info ID: 0xDDDD */ - uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */ - uint8 oui[3]; /* WFA OUI: 0x0050F2 */ - uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */ - -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; - -/* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { - uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ - uint16 cb_delay; /* GAS Comeback Delay */ - wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ - uint16 qresp_len; /* Query Response Length */ - uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; - -/* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { - uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ - uint8 fragment_id; /* Fragmentation ID */ - uint16 cb_delay; /* GAS Comeback Delay */ - wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ - uint16 qresp_len; /* Query Response Length */ - uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; - -/* Wi-Fi GAS Public Action Frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { - uint8 category; /* 0x04 Public Action Frame */ - uint8 action; /* 0x6c Advertisement Protocol */ - uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ - uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t - * or wifi_p2psd_gas_iresp_frame_t format - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _P2P_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h deleted file mode 100644 index 35e8180d67dd..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SD-SPI Protocol Standard - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sdspi.h 382882 2013-02-04 23:24:31Z $ - */ -#ifndef _SD_SPI_H -#define _SD_SPI_H - -#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ -#define SPI_START_S 31 -#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ -#define SPI_DIR_S 30 -#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ -#define SPI_CMD_INDEX_S 24 -#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ -#define SPI_RW_S 23 -#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ -#define SPI_FUNC_S 20 -#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ -#define SPI_RAW_S 19 -#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ -#define SPI_STUFF_S 18 -#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ -#define SPI_BLKMODE_S 19 -#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ -#define SPI_OPCODE_S 18 -#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ -#define SPI_ADDR_S 1 -#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ -#define SPI_STUFF0_S 0 - -#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ -#define SPI_RSP_START_S 7 -#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ -#define SPI_RSP_PARAM_ERR_S 6 -#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ -#define SPI_RSP_RFU5_S 5 -#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ -#define SPI_RSP_FUNC_ERR_S 4 -#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ -#define SPI_RSP_CRC_ERR_S 3 -#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ -#define SPI_RSP_ILL_CMD_S 2 -#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ -#define SPI_RSP_RFU1_S 1 -#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ -#define SPI_RSP_IDLE_S 0 - -/* SD-SPI Protocol Definitions */ -#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ -#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ -#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ -#define SDSPI_START_BIT_MASK 0x80 - -#endif /* _SD_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/vlan.h b/drivers/net/wireless/bcmdhd/include/proto/vlan.h deleted file mode 100644 index fc6e13b6cd48..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/vlan.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 802.1Q VLAN protocol definitions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: vlan.h 382883 2013-02-04 23:26:09Z $ - */ - -#ifndef _vlan_h_ -#define _vlan_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - -#ifndef VLAN_VID_MASK -#define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */ -#endif - -#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */ -#define VLAN_PRI_SHIFT 13 /* user priority */ - -#define VLAN_PRI_MASK 7 /* 3 bits of priority */ - -#define VLAN_TPID_OFFSET 12 /* offset of tag protocol id field */ -#define VLAN_TCI_OFFSET 14 /* offset of tag ctrl info field */ - -#define VLAN_TAG_LEN 4 -#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */ - -#define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */ - -struct vlan_header { - uint16 vlan_type; /* 0x8100 */ - uint16 vlan_tag; /* priority, cfi and vid */ -}; - -struct ethervlan_header { - uint8 ether_dhost[ETHER_ADDR_LEN]; - uint8 ether_shost[ETHER_ADDR_LEN]; - uint16 vlan_type; /* 0x8100 */ - uint16 vlan_tag; /* priority, cfi and vid */ - uint16 ether_type; -}; - -struct dot3_mac_llc_snapvlan_header { - uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ - uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ - uint16 length; /* frame length incl header */ - uint8 dsap; /* always 0xAA */ - uint8 ssap; /* always 0xAA */ - uint8 ctl; /* always 0x03 */ - uint8 oui[3]; /* RFC1042: 0x00 0x00 0x00 - * Bridge-Tunnel: 0x00 0x00 0xF8 - */ - uint16 vlan_type; /* 0x8100 */ - uint16 vlan_tag; /* priority, cfi and vid */ - uint16 ether_type; /* ethertype */ -}; - -#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) - - -/* This marks the end of a packed structure section. */ -#include - -#define ETHERVLAN_MOVE_HDR(d, s) \ -do { \ - struct ethervlan_header t; \ - t = *(struct ethervlan_header *)(s); \ - *(struct ethervlan_header *)(d) = t; \ -} while (0) - -#endif /* _vlan_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd/include/proto/wpa.h deleted file mode 100644 index aed733d24f0b..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/wpa.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Fundamental types and constants relating to WPA - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wpa.h 492853 2014-07-23 17:20:34Z $ - */ - -#ifndef _proto_wpa_h_ -#define _proto_wpa_h_ - -#include -#include - - -/* This marks the start of a packed structure section. */ -#include - -/* Reason Codes */ - -/* 13 through 23 taken from IEEE Std 802.11i-2004 */ -#define DOT11_RC_INVALID_WPA_IE 13 /* Invalid info. element */ -#define DOT11_RC_MIC_FAILURE 14 /* Michael failure */ -#define DOT11_RC_4WH_TIMEOUT 15 /* 4-way handshake timeout */ -#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 /* Group key update timeout */ -#define DOT11_RC_WPA_IE_MISMATCH 17 /* WPA IE in 4-way handshake differs from - * (re-)assoc. request/probe response - */ -#define DOT11_RC_INVALID_MC_CIPHER 18 /* Invalid multicast cipher */ -#define DOT11_RC_INVALID_UC_CIPHER 19 /* Invalid unicast cipher */ -#define DOT11_RC_INVALID_AKMP 20 /* Invalid authenticated key management protocol */ -#define DOT11_RC_BAD_WPA_VERSION 21 /* Unsupported WPA version */ -#define DOT11_RC_INVALID_WPA_CAP 22 /* Invalid WPA IE capabilities */ -#define DOT11_RC_8021X_AUTH_FAIL 23 /* 802.1X authentication failure */ - -#define WPA2_PMKID_LEN 16 - -/* WPA IE fixed portion */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - uint8 tag; /* TAG */ - uint8 length; /* TAG length */ - uint8 oui[3]; /* IE OUI */ - uint8 oui_type; /* OUI type */ - BWL_PRE_PACKED_STRUCT struct { - uint8 low; - uint8 high; - } BWL_POST_PACKED_STRUCT version; /* IE version */ -} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; -#define WPA_IE_OUITYPE_LEN 4 -#define WPA_IE_FIXED_LEN 8 -#define WPA_IE_TAG_FIXED_LEN 6 - -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 tag; /* TAG */ - uint8 length; /* TAG length */ - BWL_PRE_PACKED_STRUCT struct { - uint8 low; - uint8 high; - } BWL_POST_PACKED_STRUCT version; /* IE version */ -} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; -#define WPA_RSN_IE_FIXED_LEN 4 -#define WPA_RSN_IE_TAG_FIXED_LEN 2 -typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; - -#define WFA_OSEN_IE_FIXED_LEN 6 - -/* WPA suite/multicast suite */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - uint8 oui[3]; - uint8 type; -} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; -#define WPA_SUITE_LEN 4 - -/* WPA unicast suite list/key management suite list */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - BWL_PRE_PACKED_STRUCT struct { - uint8 low; - uint8 high; - } BWL_POST_PACKED_STRUCT count; - wpa_suite_t list[1]; -} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; -#define WPA_IE_SUITE_COUNT_LEN 2 -typedef BWL_PRE_PACKED_STRUCT struct -{ - BWL_PRE_PACKED_STRUCT struct { - uint8 low; - uint8 high; - } BWL_POST_PACKED_STRUCT count; - wpa_pmkid_t list[1]; -} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; - -/* WPA cipher suites */ -#define WPA_CIPHER_NONE 0 /* None */ -#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */ -#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */ -#define WPA_CIPHER_AES_OCB 3 /* AES (OCB) */ -#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */ -#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */ -#define WPA_CIPHER_BIP 6 /* WEP (104-bit) */ -#define WPA_CIPHER_TPK 7 /* Group addressed traffic not allowed */ -#ifdef BCMCCX -#define WPA_CIPHER_CKIP 8 /* KP with no MIC */ -#define WPA_CIPHER_CKIP_MMH 9 /* KP with MIC ("CKIP/MMH", "CKIP+CMIC") */ -#define WPA_CIPHER_WEP_MMH 10 /* MIC with no KP ("WEP/MMH", "CMIC") */ - -#define IS_CCX_CIPHER(cipher) ((cipher) == WPA_CIPHER_CKIP || \ - (cipher) == WPA_CIPHER_CKIP_MMH || \ - (cipher) == WPA_CIPHER_WEP_MMH) -#endif - -#ifdef BCMWAPI_WAI -#define WAPI_CIPHER_NONE WPA_CIPHER_NONE -#define WAPI_CIPHER_SMS4 11 - -#define WAPI_CSE_WPI_SMS4 1 -#endif /* BCMWAPI_WAI */ - -#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ - (cipher) == WPA_CIPHER_WEP_40 || \ - (cipher) == WPA_CIPHER_WEP_104 || \ - (cipher) == WPA_CIPHER_TKIP || \ - (cipher) == WPA_CIPHER_AES_OCB || \ - (cipher) == WPA_CIPHER_AES_CCM || \ - (cipher) == WPA_CIPHER_TPK) - -#ifdef BCMWAPI_WAI -#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ - (cipher) == WAPI_CSE_WPI_SMS4) - -/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */ -#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ - WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) - -#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ - WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) -#endif /* BCMWAPI_WAI */ - -/* WPA TKIP countermeasures parameters */ -#define WPA_TKIP_CM_DETECT 60 /* multiple MIC failure window (seconds) */ -#define WPA_TKIP_CM_BLOCK 60 /* countermeasures active window (seconds) */ - -/* RSN IE defines */ -#define RSN_CAP_LEN 2 /* Length of RSN capabilities field (2 octets) */ - -/* RSN Capabilities defined in 802.11i */ -#define RSN_CAP_PREAUTH 0x0001 -#define RSN_CAP_NOPAIRWISE 0x0002 -#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C -#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 -#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 -#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 -#define RSN_CAP_1_REPLAY_CNTR 0 -#define RSN_CAP_2_REPLAY_CNTRS 1 -#define RSN_CAP_4_REPLAY_CNTRS 2 -#define RSN_CAP_16_REPLAY_CNTRS 3 -#define RSN_CAP_MFPR 0x0040 -#define RSN_CAP_MFPC 0x0080 -#define RSN_CAP_SPPC 0x0400 -#define RSN_CAP_SPPR 0x0800 - -/* WPA capabilities defined in 802.11i */ -#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS -#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS -#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT -#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK - -/* WPA capabilities defined in 802.11zD9.0 */ -#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) /* bit 9 */ - -/* WPA Specific defines */ -#define WPA_CAP_LEN RSN_CAP_LEN /* Length of RSN capabilities in RSN IE (2 octets) */ -#define WPA_PMKID_CNT_LEN 2 /* Length of RSN PMKID count (2 octests) */ - -#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH - -#define WPA2_PMKID_COUNT_LEN 2 -#define RSN_GROUPMANAGE_CIPHER_LEN 4 - -#ifdef BCMWAPI_WAI -#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH - -/* Other WAI definition */ -#define WAPI_WAI_REQUEST 0x00F1 -#define WAPI_UNICAST_REKEY 0x00F2 -#define WAPI_STA_AGING 0x00F3 -#define WAPI_MUTIL_REKEY 0x00F4 -#define WAPI_STA_STATS 0x00F5 - -#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */ -#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */ -#endif /* BCMWAPI_WAI */ - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _proto_wpa_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/wps.h b/drivers/net/wireless/bcmdhd/include/proto/wps.h deleted file mode 100644 index ce78daeb6b0c..000000000000 --- a/drivers/net/wireless/bcmdhd/include/proto/wps.h +++ /dev/null @@ -1,386 +0,0 @@ -/* - * WPS IE definitions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id$ - */ - -#ifndef _WPS_ -#define _WPS_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Data Element Definitions */ -#define WPS_ID_AP_CHANNEL 0x1001 -#define WPS_ID_ASSOC_STATE 0x1002 -#define WPS_ID_AUTH_TYPE 0x1003 -#define WPS_ID_AUTH_TYPE_FLAGS 0x1004 -#define WPS_ID_AUTHENTICATOR 0x1005 -#define WPS_ID_CONFIG_METHODS 0x1008 -#define WPS_ID_CONFIG_ERROR 0x1009 -#define WPS_ID_CONF_URL4 0x100A -#define WPS_ID_CONF_URL6 0x100B -#define WPS_ID_CONN_TYPE 0x100C -#define WPS_ID_CONN_TYPE_FLAGS 0x100D -#define WPS_ID_CREDENTIAL 0x100E -#define WPS_ID_DEVICE_NAME 0x1011 -#define WPS_ID_DEVICE_PWD_ID 0x1012 -#define WPS_ID_E_HASH1 0x1014 -#define WPS_ID_E_HASH2 0x1015 -#define WPS_ID_E_SNONCE1 0x1016 -#define WPS_ID_E_SNONCE2 0x1017 -#define WPS_ID_ENCR_SETTINGS 0x1018 -#define WPS_ID_ENCR_TYPE 0x100F -#define WPS_ID_ENCR_TYPE_FLAGS 0x1010 -#define WPS_ID_ENROLLEE_NONCE 0x101A -#define WPS_ID_FEATURE_ID 0x101B -#define WPS_ID_IDENTITY 0x101C -#define WPS_ID_IDENTITY_PROOF 0x101D -#define WPS_ID_KEY_WRAP_AUTH 0x101E -#define WPS_ID_KEY_IDENTIFIER 0x101F -#define WPS_ID_MAC_ADDR 0x1020 -#define WPS_ID_MANUFACTURER 0x1021 -#define WPS_ID_MSG_TYPE 0x1022 -#define WPS_ID_MODEL_NAME 0x1023 -#define WPS_ID_MODEL_NUMBER 0x1024 -#define WPS_ID_NW_INDEX 0x1026 -#define WPS_ID_NW_KEY 0x1027 -#define WPS_ID_NW_KEY_INDEX 0x1028 -#define WPS_ID_NEW_DEVICE_NAME 0x1029 -#define WPS_ID_NEW_PWD 0x102A -#define WPS_ID_OOB_DEV_PWD 0x102C -#define WPS_ID_OS_VERSION 0x102D -#define WPS_ID_POWER_LEVEL 0x102F -#define WPS_ID_PSK_CURRENT 0x1030 -#define WPS_ID_PSK_MAX 0x1031 -#define WPS_ID_PUBLIC_KEY 0x1032 -#define WPS_ID_RADIO_ENABLED 0x1033 -#define WPS_ID_REBOOT 0x1034 -#define WPS_ID_REGISTRAR_CURRENT 0x1035 -#define WPS_ID_REGISTRAR_ESTBLSHD 0x1036 -#define WPS_ID_REGISTRAR_LIST 0x1037 -#define WPS_ID_REGISTRAR_MAX 0x1038 -#define WPS_ID_REGISTRAR_NONCE 0x1039 -#define WPS_ID_REQ_TYPE 0x103A -#define WPS_ID_RESP_TYPE 0x103B -#define WPS_ID_RF_BAND 0x103C -#define WPS_ID_R_HASH1 0x103D -#define WPS_ID_R_HASH2 0x103E -#define WPS_ID_R_SNONCE1 0x103F -#define WPS_ID_R_SNONCE2 0x1040 -#define WPS_ID_SEL_REGISTRAR 0x1041 -#define WPS_ID_SERIAL_NUM 0x1042 -#define WPS_ID_SC_STATE 0x1044 -#define WPS_ID_SSID 0x1045 -#define WPS_ID_TOT_NETWORKS 0x1046 -#define WPS_ID_UUID_E 0x1047 -#define WPS_ID_UUID_R 0x1048 -#define WPS_ID_VENDOR_EXT 0x1049 -#define WPS_ID_VERSION 0x104A -#define WPS_ID_X509_CERT_REQ 0x104B -#define WPS_ID_X509_CERT 0x104C -#define WPS_ID_EAP_IDENTITY 0x104D -#define WPS_ID_MSG_COUNTER 0x104E -#define WPS_ID_PUBKEY_HASH 0x104F -#define WPS_ID_REKEY_KEY 0x1050 -#define WPS_ID_KEY_LIFETIME 0x1051 -#define WPS_ID_PERM_CFG_METHODS 0x1052 -#define WPS_ID_SEL_REG_CFG_METHODS 0x1053 -#define WPS_ID_PRIM_DEV_TYPE 0x1054 -#define WPS_ID_SEC_DEV_TYPE_LIST 0x1055 -#define WPS_ID_PORTABLE_DEVICE 0x1056 -#define WPS_ID_AP_SETUP_LOCKED 0x1057 -#define WPS_ID_APP_LIST 0x1058 -#define WPS_ID_EAP_TYPE 0x1059 -#define WPS_ID_INIT_VECTOR 0x1060 -#define WPS_ID_KEY_PROVIDED_AUTO 0x1061 -#define WPS_ID_8021X_ENABLED 0x1062 -#define WPS_ID_WEP_TRANSMIT_KEY 0x1064 -#define WPS_ID_REQ_DEV_TYPE 0x106A - -/* WSC 2.0, WFA Vendor Extension Subelements */ -#define WFA_VENDOR_EXT_ID "\x00\x37\x2A" -#define WPS_WFA_SUBID_VERSION2 0x00 -#define WPS_WFA_SUBID_AUTHORIZED_MACS 0x01 -#define WPS_WFA_SUBID_NW_KEY_SHAREABLE 0x02 -#define WPS_WFA_SUBID_REQ_TO_ENROLL 0x03 -#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME 0x04 -#define WPS_WFA_SUBID_REG_CFG_METHODS 0x05 - - -/* WCN-NET Windows Rally Vertical Pairing Vendor Extensions */ -#define MS_VENDOR_EXT_ID "\x00\x01\x37" -#define WPS_MS_ID_VPI 0x1001 /* Vertical Pairing Identifier TLV */ -#define WPS_MS_ID_TRANSPORT_UUID 0x1002 /* Transport UUID TLV */ - -/* Vertical Pairing Identifier TLV Definitions */ -#define WPS_MS_VPI_TRANSPORT_NONE 0x00 /* None */ -#define WPS_MS_VPI_TRANSPORT_DPWS 0x01 /* Devices Profile for Web Services */ -#define WPS_MS_VPI_TRANSPORT_UPNP 0x02 /* uPnP */ -#define WPS_MS_VPI_TRANSPORT_SDNWS 0x03 /* Secure Devices Profile for Web Services */ -#define WPS_MS_VPI_NO_PROFILE_REQ 0x00 /* Wi-Fi profile not requested. - * Not supported in Windows 7 - */ -#define WPS_MS_VPI_PROFILE_REQ 0x01 /* Wi-Fi profile requested. */ - -/* sizes of the fixed size elements */ -#define WPS_ID_AP_CHANNEL_S 2 -#define WPS_ID_ASSOC_STATE_S 2 -#define WPS_ID_AUTH_TYPE_S 2 -#define WPS_ID_AUTH_TYPE_FLAGS_S 2 -#define WPS_ID_AUTHENTICATOR_S 8 -#define WPS_ID_CONFIG_METHODS_S 2 -#define WPS_ID_CONFIG_ERROR_S 2 -#define WPS_ID_CONN_TYPE_S 1 -#define WPS_ID_CONN_TYPE_FLAGS_S 1 -#define WPS_ID_DEVICE_PWD_ID_S 2 -#define WPS_ID_ENCR_TYPE_S 2 -#define WPS_ID_ENCR_TYPE_FLAGS_S 2 -#define WPS_ID_FEATURE_ID_S 4 -#define WPS_ID_MAC_ADDR_S 6 -#define WPS_ID_MSG_TYPE_S 1 -#define WPS_ID_SC_STATE_S 1 -#define WPS_ID_RF_BAND_S 1 -#define WPS_ID_OS_VERSION_S 4 -#define WPS_ID_VERSION_S 1 -#define WPS_ID_SEL_REGISTRAR_S 1 -#define WPS_ID_SEL_REG_CFG_METHODS_S 2 -#define WPS_ID_REQ_TYPE_S 1 -#define WPS_ID_RESP_TYPE_S 1 -#define WPS_ID_AP_SETUP_LOCKED_S 1 - -/* WSC 2.0, WFA Vendor Extension Subelements */ -#define WPS_WFA_SUBID_VERSION2_S 1 -#define WPS_WFA_SUBID_NW_KEY_SHAREABLE_S 1 -#define WPS_WFA_SUBID_REQ_TO_ENROLL_S 1 -#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME_S 1 -#define WPS_WFA_SUBID_REG_CFG_METHODS_S 2 - -/* Association states */ -#define WPS_ASSOC_NOT_ASSOCIATED 0 -#define WPS_ASSOC_CONN_SUCCESS 1 -#define WPS_ASSOC_CONFIG_FAIL 2 -#define WPS_ASSOC_ASSOC_FAIL 3 -#define WPS_ASSOC_IP_FAIL 4 - -/* Authentication types */ -#define WPS_AUTHTYPE_OPEN 0x0001 -#define WPS_AUTHTYPE_WPAPSK 0x0002 /* Deprecated in WSC 2.0 */ -#define WPS_AUTHTYPE_SHARED 0x0004 /* Deprecated in WSC 2.0 */ -#define WPS_AUTHTYPE_WPA 0x0008 /* Deprecated in WSC 2.0 */ -#define WPS_AUTHTYPE_WPA2 0x0010 -#define WPS_AUTHTYPE_WPA2PSK 0x0020 - -/* Config methods */ -#define WPS_CONFMET_USBA 0x0001 /* Deprecated in WSC 2.0 */ -#define WPS_CONFMET_ETHERNET 0x0002 /* Deprecated in WSC 2.0 */ -#define WPS_CONFMET_LABEL 0x0004 -#define WPS_CONFMET_DISPLAY 0x0008 -#define WPS_CONFMET_EXT_NFC_TOK 0x0010 -#define WPS_CONFMET_INT_NFC_TOK 0x0020 -#define WPS_CONFMET_NFC_INTF 0x0040 -#define WPS_CONFMET_PBC 0x0080 -#define WPS_CONFMET_KEYPAD 0x0100 -/* WSC 2.0 */ -#define WPS_CONFMET_VIRT_PBC 0x0280 -#define WPS_CONFMET_PHY_PBC 0x0480 -#define WPS_CONFMET_VIRT_DISPLAY 0x2008 -#define WPS_CONFMET_PHY_DISPLAY 0x4008 - -/* WPS error messages */ -#define WPS_ERROR_NO_ERROR 0 -#define WPS_ERROR_OOB_INT_READ_ERR 1 -#define WPS_ERROR_DECRYPT_CRC_FAIL 2 -#define WPS_ERROR_CHAN24_NOT_SUPP 3 -#define WPS_ERROR_CHAN50_NOT_SUPP 4 -#define WPS_ERROR_SIGNAL_WEAK 5 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_NW_AUTH_FAIL 6 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_NW_ASSOC_FAIL 7 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_NO_DHCP_RESP 8 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_FAILED_DHCP_CONF 9 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_IP_ADDR_CONFLICT 10 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_FAIL_CONN_REGISTRAR 11 -#define WPS_ERROR_MULTI_PBC_DETECTED 12 -#define WPS_ERROR_ROGUE_SUSPECTED 13 -#define WPS_ERROR_DEVICE_BUSY 14 -#define WPS_ERROR_SETUP_LOCKED 15 -#define WPS_ERROR_MSG_TIMEOUT 16 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_REG_SESSION_TIMEOUT 17 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_DEV_PWD_AUTH_FAIL 18 -#define WPS_ERROR_60GHZ_NOT_SUPPORT 19 -#define WPS_ERROR_PKH_MISMATCH 20 /* Public Key Hash Mismatch */ - -/* Connection types */ -#define WPS_CONNTYPE_ESS 0x01 -#define WPS_CONNTYPE_IBSS 0x02 - -/* Device password ID */ -#define WPS_DEVICEPWDID_DEFAULT 0x0000 -#define WPS_DEVICEPWDID_USER_SPEC 0x0001 -#define WPS_DEVICEPWDID_MACHINE_SPEC 0x0002 -#define WPS_DEVICEPWDID_REKEY 0x0003 -#define WPS_DEVICEPWDID_PUSH_BTN 0x0004 -#define WPS_DEVICEPWDID_REG_SPEC 0x0005 -#define WPS_DEVICEPWDID_IBSS 0x0006 -#define WPS_DEVICEPWDID_NFC_CHO 0x0007 /* NFC-Connection-Handover */ -#define WPS_DEVICEPWDID_WFDS 0x0008 /* Wi-Fi Direct Services Specification */ - -/* Encryption type */ -#define WPS_ENCRTYPE_NONE 0x0001 -#define WPS_ENCRTYPE_WEP 0x0002 /* Deprecated in WSC 2.0 */ -#define WPS_ENCRTYPE_TKIP 0x0004 /* Deprecated in version 2.0. TKIP can only - * be advertised on the AP when Mixed Mode - * is enabled (Encryption Type is 0x000c). - */ -#define WPS_ENCRTYPE_AES 0x0008 - - -/* WPS Message Types */ -#define WPS_ID_BEACON 0x01 -#define WPS_ID_PROBE_REQ 0x02 -#define WPS_ID_PROBE_RESP 0x03 -#define WPS_ID_MESSAGE_M1 0x04 -#define WPS_ID_MESSAGE_M2 0x05 -#define WPS_ID_MESSAGE_M2D 0x06 -#define WPS_ID_MESSAGE_M3 0x07 -#define WPS_ID_MESSAGE_M4 0x08 -#define WPS_ID_MESSAGE_M5 0x09 -#define WPS_ID_MESSAGE_M6 0x0A -#define WPS_ID_MESSAGE_M7 0x0B -#define WPS_ID_MESSAGE_M8 0x0C -#define WPS_ID_MESSAGE_ACK 0x0D -#define WPS_ID_MESSAGE_NACK 0x0E -#define WPS_ID_MESSAGE_DONE 0x0F - -/* WSP private ID for local use */ -#define WPS_PRIVATE_ID_IDENTITY (WPS_ID_MESSAGE_DONE + 1) -#define WPS_PRIVATE_ID_WPS_START (WPS_ID_MESSAGE_DONE + 2) -#define WPS_PRIVATE_ID_FAILURE (WPS_ID_MESSAGE_DONE + 3) -#define WPS_PRIVATE_ID_FRAG (WPS_ID_MESSAGE_DONE + 4) -#define WPS_PRIVATE_ID_FRAG_ACK (WPS_ID_MESSAGE_DONE + 5) -#define WPS_PRIVATE_ID_EAPOL_START (WPS_ID_MESSAGE_DONE + 6) - - -/* Device Type categories for primary and secondary device types */ -#define WPS_DEVICE_TYPE_CAT_COMPUTER 1 -#define WPS_DEVICE_TYPE_CAT_INPUT_DEVICE 2 -#define WPS_DEVICE_TYPE_CAT_PRINTER 3 -#define WPS_DEVICE_TYPE_CAT_CAMERA 4 -#define WPS_DEVICE_TYPE_CAT_STORAGE 5 -#define WPS_DEVICE_TYPE_CAT_NW_INFRA 6 -#define WPS_DEVICE_TYPE_CAT_DISPLAYS 7 -#define WPS_DEVICE_TYPE_CAT_MM_DEVICES 8 -#define WPS_DEVICE_TYPE_CAT_GAME_DEVICES 9 -#define WPS_DEVICE_TYPE_CAT_TELEPHONE 10 -#define WPS_DEVICE_TYPE_CAT_AUDIO_DEVICES 11 /* WSC 2.0 */ - -/* Device Type sub categories for primary and secondary device types */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_PC 1 -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_SERVER 2 -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MEDIA_CTR 3 -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_UM_PC 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NOTEBOOK 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_DESKTOP 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MID 7 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NETBOOK 8 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_Keyboard 1 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_MOUSE 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_JOYSTICK 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_TRACKBALL 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_GAM_CTRL 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_REMOTE 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_TOUCHSCREEN 7 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_BIO_READER 8 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_BAR_READER 9 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_PRINTER 1 -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_SCANNER 2 -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_FAX 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_COPIER 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_ALLINONE 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_DGTL_STILL 1 -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_VIDEO_CAM 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_WEB_CAM 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_SECU_CAM 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_STOR_NAS 1 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_AP 1 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_ROUTER 2 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_SWITCH 3 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_GATEWAY 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_NW_BRIDGE 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_TV 1 -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PIC_FRAME 2 -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PROJECTOR 3 -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_MONITOR 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_MM_DAR 1 -#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVR 2 -#define WPS_DEVICE_TYPE_SUB_CAT_MM_MCX 3 -#define WPS_DEVICE_TYPE_SUB_CAT_MM_STB 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_MM_MS_ME 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVP 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX 1 -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX_360 2 -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PS 3 -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_GC 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PGD 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_WM 1 -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PSM 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PDM 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SSM 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SDM 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_TUNER 1 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_SPEAKERS 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_PMP 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HEADSET 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HPHONE 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_MPHONE 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HTS 7 /* WSC 2.0 */ - - -/* Device request/response type */ -#define WPS_MSGTYPE_ENROLLEE_INFO_ONLY 0x00 -#define WPS_MSGTYPE_ENROLLEE_OPEN_8021X 0x01 -#define WPS_MSGTYPE_REGISTRAR 0x02 -#define WPS_MSGTYPE_AP_WLAN_MGR 0x03 - -/* RF Band */ -#define WPS_RFBAND_24GHZ 0x01 -#define WPS_RFBAND_50GHZ 0x02 - -/* Simple Config state */ -#define WPS_SCSTATE_UNCONFIGURED 0x01 -#define WPS_SCSTATE_CONFIGURED 0x02 -#define WPS_SCSTATE_OFF 11 - -/* WPS Vendor extension key */ -#define WPS_OUI_HEADER_LEN 2 -#define WPS_OUI_HEADER_SIZE 4 -#define WPS_OUI_FIXED_HEADER_OFF 16 -#define WPS_WFA_SUBID_V2_OFF 3 -#define WPS_WFA_V2_OFF 5 - -#ifdef __cplusplus -} -#endif - -#endif /* _WPS_ */ diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h deleted file mode 100644 index 7205468019ab..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sbchipc.h +++ /dev/null @@ -1,3646 +0,0 @@ -/* - * SiliconBackplane Chipcommon core hardware definitions. - * - * The chipcommon core provides chip identification, SB control, - * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, - * GPIO interface, extbus, and support for serial and parallel flashes. - * - * $Id: sbchipc.h 474281 2014-04-30 18:24:55Z $ - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - */ - -#ifndef _SBCHIPC_H -#define _SBCHIPC_H - -#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - -/** - * In chipcommon rev 49 the pmu registers have been moved from chipc to the pmu core if the - * 'AOBPresent' bit of 'CoreCapabilitiesExt' is set. If this field is set, the traditional chipc to - * [pmu|gci|sreng] register interface is deprecated and removed. These register blocks would instead - * be assigned their respective chipc-specific address space and connected to the Always On - * Backplane via the APB interface. - */ -typedef volatile struct { - uint32 PAD[384]; - uint32 pmucontrol; /* 0x600 */ - uint32 pmucapabilities; - uint32 pmustatus; - uint32 res_state; - uint32 res_pending; - uint32 pmutimer; - uint32 min_res_mask; - uint32 max_res_mask; - uint32 res_table_sel; - uint32 res_dep_mask; - uint32 res_updn_timer; - uint32 res_timer; - uint32 clkstretch; - uint32 pmuwatchdog; - uint32 gpiosel; /* 0x638, rev >= 1 */ - uint32 gpioenable; /* 0x63c, rev >= 1 */ - uint32 res_req_timer_sel; - uint32 res_req_timer; - uint32 res_req_mask; - uint32 PAD; - uint32 chipcontrol_addr; /* 0x650 */ - uint32 chipcontrol_data; /* 0x654 */ - uint32 regcontrol_addr; - uint32 regcontrol_data; - uint32 pllcontrol_addr; - uint32 pllcontrol_data; - uint32 pmustrapopt; /* 0x668, corerev >= 28 */ - uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ - uint32 retention_ctl; /* 0x670 */ - uint32 PAD[3]; - uint32 retention_grpidx; /* 0x680 */ - uint32 retention_grpctl; /* 0x684 */ - uint32 PAD[20]; - uint32 pmucontrol_ext; /* 0x6d8 */ - uint32 slowclkperiod; /* 0x6dc */ - uint32 PAD[8]; - uint32 pmuintmask0; /* 0x700 */ - uint32 pmuintmask1; /* 0x704 */ - uint32 PAD[14]; - uint32 pmuintstatus; /* 0x740 */ -} pmuregs_t; - -typedef struct eci_prerev35 { - uint32 eci_output; - uint32 eci_control; - uint32 eci_inputlo; - uint32 eci_inputmi; - uint32 eci_inputhi; - uint32 eci_inputintpolaritylo; - uint32 eci_inputintpolaritymi; - uint32 eci_inputintpolarityhi; - uint32 eci_intmasklo; - uint32 eci_intmaskmi; - uint32 eci_intmaskhi; - uint32 eci_eventlo; - uint32 eci_eventmi; - uint32 eci_eventhi; - uint32 eci_eventmasklo; - uint32 eci_eventmaskmi; - uint32 eci_eventmaskhi; - uint32 PAD[3]; -} eci_prerev35_t; - -typedef struct eci_rev35 { - uint32 eci_outputlo; - uint32 eci_outputhi; - uint32 eci_controllo; - uint32 eci_controlhi; - uint32 eci_inputlo; - uint32 eci_inputhi; - uint32 eci_inputintpolaritylo; - uint32 eci_inputintpolarityhi; - uint32 eci_intmasklo; - uint32 eci_intmaskhi; - uint32 eci_eventlo; - uint32 eci_eventhi; - uint32 eci_eventmasklo; - uint32 eci_eventmaskhi; - uint32 eci_auxtx; - uint32 eci_auxrx; - uint32 eci_datatag; - uint32 eci_uartescvalue; - uint32 eci_autobaudctr; - uint32 eci_uartfifolevel; -} eci_rev35_t; - -typedef struct flash_config { - uint32 PAD[19]; - /* Flash struct configuration registers (0x18c) for BCM4706 (corerev = 31) */ - uint32 flashstrconfig; -} flash_config_t; - -typedef volatile struct { - uint32 chipid; /* 0x0 */ - uint32 capabilities; - uint32 corecontrol; /* corerev >= 1 */ - uint32 bist; - - /* OTP */ - uint32 otpstatus; /* 0x10, corerev >= 10 */ - uint32 otpcontrol; - uint32 otpprog; - uint32 otplayout; /* corerev >= 23 */ - - /* Interrupt control */ - uint32 intstatus; /* 0x20 */ - uint32 intmask; - - /* Chip specific regs */ - uint32 chipcontrol; /* 0x28, rev >= 11 */ - uint32 chipstatus; /* 0x2c, rev >= 11 */ - - /* Jtag Master */ - uint32 jtagcmd; /* 0x30, rev >= 10 */ - uint32 jtagir; - uint32 jtagdr; - uint32 jtagctrl; - - /* serial flash interface registers */ - uint32 flashcontrol; /* 0x40 */ - uint32 flashaddress; - uint32 flashdata; - uint32 otplayoutextension; /* rev >= 35 */ - - /* Silicon backplane configuration broadcast control */ - uint32 broadcastaddress; /* 0x50 */ - uint32 broadcastdata; - - /* gpio - cleared only by power-on-reset */ - uint32 gpiopullup; /* 0x58, corerev >= 20 */ - uint32 gpiopulldown; /* 0x5c, corerev >= 20 */ - uint32 gpioin; /* 0x60 */ - uint32 gpioout; /* 0x64 */ - uint32 gpioouten; /* 0x68 */ - uint32 gpiocontrol; /* 0x6C */ - uint32 gpiointpolarity; /* 0x70 */ - uint32 gpiointmask; /* 0x74 */ - - /* GPIO events corerev >= 11 */ - uint32 gpioevent; - uint32 gpioeventintmask; - - /* Watchdog timer */ - uint32 watchdog; /* 0x80 */ - - /* GPIO events corerev >= 11 */ - uint32 gpioeventintpolarity; - - /* GPIO based LED powersave registers corerev >= 16 */ - uint32 gpiotimerval; /* 0x88 */ - uint32 gpiotimeroutmask; - - /* clock control */ - uint32 clockcontrol_n; /* 0x90 */ - uint32 clockcontrol_sb; /* aka m0 */ - uint32 clockcontrol_pci; /* aka m1 */ - uint32 clockcontrol_m2; /* mii/uart/mipsref */ - uint32 clockcontrol_m3; /* cpu */ - uint32 clkdiv; /* corerev >= 3 */ - uint32 gpiodebugsel; /* corerev >= 28 */ - uint32 capabilities_ext; /* 0xac */ - - /* pll delay registers (corerev >= 4) */ - uint32 pll_on_delay; /* 0xb0 */ - uint32 fref_sel_delay; - uint32 slow_clk_ctl; /* 5 < corerev < 10 */ - uint32 PAD; - - /* Instaclock registers (corerev >= 10) */ - uint32 system_clk_ctl; /* 0xc0 */ - uint32 clkstatestretch; - uint32 PAD[2]; - - /* Indirect backplane access (corerev >= 22) */ - uint32 bp_addrlow; /* 0xd0 */ - uint32 bp_addrhigh; - uint32 bp_data; - uint32 PAD; - uint32 bp_indaccess; - /* SPI registers, corerev >= 37 */ - uint32 gsioctrl; - uint32 gsioaddress; - uint32 gsiodata; - - /* More clock dividers (corerev >= 32) */ - uint32 clkdiv2; - /* FAB ID (corerev >= 40) */ - uint32 otpcontrol1; - uint32 fabid; /* 0xf8 */ - - /* In AI chips, pointer to erom */ - uint32 eromptr; /* 0xfc */ - - /* ExtBus control registers (corerev >= 3) */ - uint32 pcmcia_config; /* 0x100 */ - uint32 pcmcia_memwait; - uint32 pcmcia_attrwait; - uint32 pcmcia_iowait; - uint32 ide_config; - uint32 ide_memwait; - uint32 ide_attrwait; - uint32 ide_iowait; - uint32 prog_config; - uint32 prog_waitcount; - uint32 flash_config; - uint32 flash_waitcount; - uint32 SECI_config; /* 0x130 SECI configuration */ - uint32 SECI_status; - uint32 SECI_statusmask; - uint32 SECI_rxnibchanged; - - uint32 PAD[20]; - - /* SROM interface (corerev >= 32) */ - uint32 sromcontrol; /* 0x190 */ - uint32 sromaddress; - uint32 sromdata; - uint32 PAD[1]; /* 0x19C */ - /* NAND flash registers for BCM4706 (corerev = 31) */ - uint32 nflashctrl; /* 0x1a0 */ - uint32 nflashconf; - uint32 nflashcoladdr; - uint32 nflashrowaddr; - uint32 nflashdata; - uint32 nflashwaitcnt0; /* 0x1b4 */ - uint32 PAD[2]; - - uint32 seci_uart_data; /* 0x1C0 */ - uint32 seci_uart_bauddiv; - uint32 seci_uart_fcr; - uint32 seci_uart_lcr; - uint32 seci_uart_mcr; - uint32 seci_uart_lsr; - uint32 seci_uart_msr; - uint32 seci_uart_baudadj; - /* Clock control and hardware workarounds (corerev >= 20) */ - uint32 clk_ctl_st; /* 0x1e0 */ - uint32 hw_war; - uint32 PAD[70]; - - /* UARTs */ - uint8 uart0data; /* 0x300 */ - uint8 uart0imr; - uint8 uart0fcr; - uint8 uart0lcr; - uint8 uart0mcr; - uint8 uart0lsr; - uint8 uart0msr; - uint8 uart0scratch; - uint8 PAD[248]; /* corerev >= 1 */ - - uint8 uart1data; /* 0x400 */ - uint8 uart1imr; - uint8 uart1fcr; - uint8 uart1lcr; - uint8 uart1mcr; - uint8 uart1lsr; - uint8 uart1msr; - uint8 uart1scratch; /* 0x407 */ - uint32 PAD[62]; - - /* save/restore, corerev >= 48 */ - uint32 sr_capability; /* 0x500 */ - uint32 sr_control0; /* 0x504 */ - uint32 sr_control1; /* 0x508 */ - uint32 gpio_control; /* 0x50C */ - uint32 PAD[60]; - - /* PMU registers (corerev >= 20) */ - /* Note: all timers driven by ILP clock are updated asynchronously to HT/ALP. - * The CPU must read them twice, compare, and retry if different. - */ - uint32 pmucontrol; /* 0x600 */ - uint32 pmucapabilities; - uint32 pmustatus; - uint32 res_state; - uint32 res_pending; - uint32 pmutimer; - uint32 min_res_mask; - uint32 max_res_mask; - uint32 res_table_sel; - uint32 res_dep_mask; - uint32 res_updn_timer; - uint32 res_timer; - uint32 clkstretch; - uint32 pmuwatchdog; - uint32 gpiosel; /* 0x638, rev >= 1 */ - uint32 gpioenable; /* 0x63c, rev >= 1 */ - uint32 res_req_timer_sel; - uint32 res_req_timer; - uint32 res_req_mask; - uint32 PAD; - uint32 chipcontrol_addr; /* 0x650 */ - uint32 chipcontrol_data; /* 0x654 */ - uint32 regcontrol_addr; - uint32 regcontrol_data; - uint32 pllcontrol_addr; - uint32 pllcontrol_data; - uint32 pmustrapopt; /* 0x668, corerev >= 28 */ - uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ - uint32 retention_ctl; /* 0x670 */ - uint32 PAD[3]; - uint32 retention_grpidx; /* 0x680 */ - uint32 retention_grpctl; /* 0x684 */ - uint32 PAD[20]; - uint32 pmucontrol_ext; /* 0x6d8 */ - uint32 slowclkperiod; /* 0x6dc */ - uint32 PAD[8]; - uint32 pmuintmask0; /* 0x700 */ - uint32 pmuintmask1; /* 0x704 */ - uint32 PAD[14]; - uint32 pmuintstatus; /* 0x740 */ - uint32 PAD[47]; - uint16 sromotp[512]; /* 0x800 */ -#ifdef NFLASH_SUPPORT - /* Nand flash MLC controller registers (corerev >= 38) */ - uint32 nand_revision; /* 0xC00 */ - uint32 nand_cmd_start; - uint32 nand_cmd_addr_x; - uint32 nand_cmd_addr; - uint32 nand_cmd_end_addr; - uint32 nand_cs_nand_select; - uint32 nand_cs_nand_xor; - uint32 PAD; - uint32 nand_spare_rd0; - uint32 nand_spare_rd4; - uint32 nand_spare_rd8; - uint32 nand_spare_rd12; - uint32 nand_spare_wr0; - uint32 nand_spare_wr4; - uint32 nand_spare_wr8; - uint32 nand_spare_wr12; - uint32 nand_acc_control; - uint32 PAD; - uint32 nand_config; - uint32 PAD; - uint32 nand_timing_1; - uint32 nand_timing_2; - uint32 nand_semaphore; - uint32 PAD; - uint32 nand_devid; - uint32 nand_devid_x; - uint32 nand_block_lock_status; - uint32 nand_intfc_status; - uint32 nand_ecc_corr_addr_x; - uint32 nand_ecc_corr_addr; - uint32 nand_ecc_unc_addr_x; - uint32 nand_ecc_unc_addr; - uint32 nand_read_error_count; - uint32 nand_corr_stat_threshold; - uint32 PAD[2]; - uint32 nand_read_addr_x; - uint32 nand_read_addr; - uint32 nand_page_program_addr_x; - uint32 nand_page_program_addr; - uint32 nand_copy_back_addr_x; - uint32 nand_copy_back_addr; - uint32 nand_block_erase_addr_x; - uint32 nand_block_erase_addr; - uint32 nand_inv_read_addr_x; - uint32 nand_inv_read_addr; - uint32 PAD[2]; - uint32 nand_blk_wr_protect; - uint32 PAD[3]; - uint32 nand_acc_control_cs1; - uint32 nand_config_cs1; - uint32 nand_timing_1_cs1; - uint32 nand_timing_2_cs1; - uint32 PAD[20]; - uint32 nand_spare_rd16; - uint32 nand_spare_rd20; - uint32 nand_spare_rd24; - uint32 nand_spare_rd28; - uint32 nand_cache_addr; - uint32 nand_cache_data; - uint32 nand_ctrl_config; - uint32 nand_ctrl_status; -#endif /* NFLASH_SUPPORT */ - uint32 gci_corecaps0; /* GCI starting at 0xC00 */ - uint32 gci_corecaps1; - uint32 gci_corecaps2; - uint32 gci_corectrl; - uint32 gci_corestat; /* 0xC10 */ - uint32 gci_intstat; /* 0xC14 */ - uint32 gci_intmask; /* 0xC18 */ - uint32 gci_wakemask; /* 0xC1C */ - uint32 gci_levelintstat; /* 0xC20 */ - uint32 gci_eventintstat; /* 0xC24 */ - uint32 PAD[6]; - uint32 gci_indirect_addr; /* 0xC40 */ - uint32 gci_gpioctl; /* 0xC44 */ - uint32 gci_gpiostatus; - uint32 gci_gpiomask; /* 0xC4C */ - uint32 PAD; - uint32 gci_miscctl; /* 0xC54 */ - uint32 gci_gpiointmask; - uint32 gci_gpiowakemask; - uint32 gci_input[32]; /* C60 */ - uint32 gci_event[32]; /* CE0 */ - uint32 gci_output[4]; /* D60 */ - uint32 gci_control_0; /* 0xD70 */ - uint32 gci_control_1; /* 0xD74 */ - uint32 gci_intpolreg; /* 0xD78 */ - uint32 gci_levelintmask; /* 0xD7C */ - uint32 gci_eventintmask; /* 0xD80 */ - uint32 PAD[3]; - uint32 gci_inbandlevelintmask; /* 0xD90 */ - uint32 gci_inbandeventintmask; /* 0xD94 */ - uint32 PAD[2]; - uint32 gci_seciauxtx; /* 0xDA0 */ - uint32 gci_seciauxrx; /* 0xDA4 */ - uint32 gci_secitx_datatag; /* 0xDA8 */ - uint32 gci_secirx_datatag; /* 0xDAC */ - uint32 gci_secitx_datamask; /* 0xDB0 */ - uint32 gci_seciusef0tx_reg; /* 0xDB4 */ - uint32 gci_secif0tx_offset; /* 0xDB8 */ - uint32 gci_secif0rx_offset; /* 0xDBC */ - uint32 gci_secif1tx_offset; /* 0xDC0 */ - uint32 gci_rxfifo_common_ctrl; /* 0xDC4 */ - uint32 gci_rxfifoctrl; /* 0xDC8 */ - uint32 gci_uartreadid; /* DCC */ - uint32 gci_uartescval; /* DD0 */ - uint32 PAD; - uint32 gci_secififolevel; /* DD8 */ - uint32 gci_seciuartdata; /* DDC */ - uint32 gci_secibauddiv; /* DE0 */ - uint32 gci_secifcr; /* DE4 */ - uint32 gci_secilcr; /* DE8 */ - uint32 gci_secimcr; /* DEC */ - uint32 gci_secilsr; /* DF0 */ - uint32 gci_secimsr; /* DF4 */ - uint32 gci_baudadj; /* DF8 */ - uint32 PAD; - uint32 gci_chipctrl; /* 0xE00 */ - uint32 gci_chipsts; /* 0xE04 */ - uint32 gci_gpioout; /* 0xE08 */ - uint32 gci_gpioout_read; /* 0xE0C */ - uint32 gci_mpwaketx; /* 0xE10 */ - uint32 gci_mpwakedetect; /* 0xE14 */ - uint32 gci_seciin_ctrl; /* 0xE18 */ - uint32 gci_seciout_ctrl; /* 0xE1C */ - uint32 gci_seciin_auxfifo_en; /* 0xE20 */ - uint32 gci_seciout_txen_txbr; /* 0xE24 */ - uint32 gci_seciin_rxbrstatus; /* 0xE28 */ - uint32 gci_seciin_rxerrstatus; /* 0xE2C */ - uint32 gci_seciin_fcstatus; /* 0xE30 */ - uint32 gci_seciout_txstatus; /* 0xE34 */ - uint32 gci_seciout_txbrstatus; /* 0xE38 */ -} chipcregs_t; - -#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ - - -#define CC_CHIPID 0 -#define CC_CAPABILITIES 4 -#define CC_CHIPST 0x2c -#define CC_EROMPTR 0xfc - -#define CC_OTPST 0x10 -#define CC_INTSTATUS 0x20 -#define CC_INTMASK 0x24 -#define CC_JTAGCMD 0x30 -#define CC_JTAGIR 0x34 -#define CC_JTAGDR 0x38 -#define CC_JTAGCTRL 0x3c -#define CC_GPIOPU 0x58 -#define CC_GPIOPD 0x5c -#define CC_GPIOIN 0x60 -#define CC_GPIOOUT 0x64 -#define CC_GPIOOUTEN 0x68 -#define CC_GPIOCTRL 0x6c -#define CC_GPIOPOL 0x70 -#define CC_GPIOINTM 0x74 -#define CC_GPIOEVENT 0x78 -#define CC_GPIOEVENTMASK 0x7c -#define CC_WATCHDOG 0x80 -#define CC_GPIOEVENTPOL 0x84 -#define CC_CLKC_N 0x90 -#define CC_CLKC_M0 0x94 -#define CC_CLKC_M1 0x98 -#define CC_CLKC_M2 0x9c -#define CC_CLKC_M3 0xa0 -#define CC_CLKDIV 0xa4 -#define CC_SYS_CLK_CTL 0xc0 -#define CC_CLK_CTL_ST SI_CLK_CTL_ST -#define PMU_CTL 0x600 -#define PMU_CAP 0x604 -#define PMU_ST 0x608 -#define PMU_RES_STATE 0x60c -#define PMU_RES_PENDING 0x610 -#define PMU_TIMER 0x614 -#define PMU_MIN_RES_MASK 0x618 -#define PMU_MAX_RES_MASK 0x61c -#define CC_CHIPCTL_ADDR 0x650 -#define CC_CHIPCTL_DATA 0x654 -#define PMU_REG_CONTROL_ADDR 0x658 -#define PMU_REG_CONTROL_DATA 0x65C -#define PMU_PLL_CONTROL_ADDR 0x660 -#define PMU_PLL_CONTROL_DATA 0x664 -#define CC_SROM_CTRL 0x190 -#define CC_SROM_OTP 0x800 /* SROM/OTP address space */ -#define CC_GCI_INDIRECT_ADDR_REG 0xC40 -#define CC_GCI_CHIP_CTRL_REG 0xE00 -#define CC_GCI_CC_OFFSET_2 2 -#define CC_GCI_CC_OFFSET_5 5 -#define CC_SWD_CTRL 0x380 -#define CC_SWD_REQACK 0x384 -#define CC_SWD_DATA 0x388 - - -#define CHIPCTRLREG0 0x0 -#define CHIPCTRLREG1 0x1 -#define CHIPCTRLREG2 0x2 -#define CHIPCTRLREG3 0x3 -#define CHIPCTRLREG4 0x4 -#define CHIPCTRLREG5 0x5 -#define CHIPCTRLREG6 0x6 -#define REGCTRLREG4 0x4 -#define REGCTRLREG5 0x5 -#define REGCTRLREG6 0x6 -#define MINRESMASKREG 0x618 -#define MAXRESMASKREG 0x61c -#define CHIPCTRLADDR 0x650 -#define CHIPCTRLDATA 0x654 -#define RSRCTABLEADDR 0x620 -#define PMU_RES_DEP_MASK 0x624 -#define RSRCUPDWNTIME 0x628 -#define PMUREG_RESREQ_MASK 0x68c -#define EXT_LPO_AVAIL 0x100 -#define LPO_SEL (1 << 0) -#define CC_EXT_LPO_PU 0x200000 -#define GC_EXT_LPO_PU 0x2 -#define CC_INT_LPO_PU 0x100000 -#define GC_INT_LPO_PU 0x1 -#define EXT_LPO_SEL 0x8 -#define INT_LPO_SEL 0x4 -#define ENABLE_FINE_CBUCK_CTRL (1 << 30) -#define REGCTRL5_PWM_AUTO_CTRL_MASK 0x007e0000 -#define REGCTRL5_PWM_AUTO_CTRL_SHIFT 17 -#define REGCTRL6_PWM_AUTO_CTRL_MASK 0x3fff0000 -#define REGCTRL6_PWM_AUTO_CTRL_SHIFT 16 - -#ifdef SR_DEBUG -#define SUBCORE_POWER_ON 0x0001 -#define PHY_POWER_ON 0x0010 -#define VDDM_POWER_ON 0x0100 -#define MEMLPLDO_POWER_ON 0x1000 -#define SUBCORE_POWER_ON_CHK 0x00040000 -#define PHY_POWER_ON_CHK 0x00080000 -#define VDDM_POWER_ON_CHK 0x00100000 -#define MEMLPLDO_POWER_ON_CHK 0x00200000 -#endif /* SR_DEBUG */ - -#ifdef NFLASH_SUPPORT -/* NAND flash support */ -#define CC_NAND_REVISION 0xC00 -#define CC_NAND_CMD_START 0xC04 -#define CC_NAND_CMD_ADDR 0xC0C -#define CC_NAND_SPARE_RD_0 0xC20 -#define CC_NAND_SPARE_RD_4 0xC24 -#define CC_NAND_SPARE_RD_8 0xC28 -#define CC_NAND_SPARE_RD_C 0xC2C -#define CC_NAND_CONFIG 0xC48 -#define CC_NAND_DEVID 0xC60 -#define CC_NAND_DEVID_EXT 0xC64 -#define CC_NAND_INTFC_STATUS 0xC6C -#endif /* NFLASH_SUPPORT */ - -/* 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 */ -#define CC_CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */ -#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_ECI 0x20000000 /* ECI Present, rev >= 21 */ -#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */ -#define CC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */ - -#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ -#define CC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */ - -/* capabilities extension */ -#define CC_CAP_EXT_SECI_PRESENT 0x00000001 /* SECI present */ -#define CC_CAP_EXT_GSIO_PRESENT 0x00000002 /* GSIO present */ -#define CC_CAP_EXT_GCI_PRESENT 0x00000004 /* GCI present */ -#define CC_CAP_EXT_AOB_PRESENT 0x00000040 /* AOB present */ - -/* WL Channel Info to BT via GCI - bits 40 - 47 */ -#define GCI_WL_CHN_INFO_MASK (0xFF00) -/* PLL type */ -#define PLL_NONE 0x00000000 -#define PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */ -#define PLL_TYPE2 0x00020000 /* 48MHz, 4 dividers */ -#define PLL_TYPE3 0x00030000 /* 25MHz, 2 dividers */ -#define PLL_TYPE4 0x00008000 /* 48MHz, 4 dividers */ -#define PLL_TYPE5 0x00018000 /* 25MHz, 4 dividers */ -#define PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */ -#define PLL_TYPE7 0x00038000 /* 25MHz, 4 dividers */ - -/* ILP clock */ -#define ILP_CLOCK 32000 - -/* ALP clock on pre-PMU chips */ -#define ALP_CLOCK 20000000 - -#ifdef CFG_SIM -#define NS_ALP_CLOCK 84922 -#define NS_SLOW_ALP_CLOCK 84922 -#define NS_CPU_CLOCK 534500 -#define NS_SLOW_CPU_CLOCK 534500 -#define NS_SI_CLOCK 271750 -#define NS_SLOW_SI_CLOCK 271750 -#define NS_FAST_MEM_CLOCK 271750 -#define NS_MEM_CLOCK 271750 -#define NS_SLOW_MEM_CLOCK 271750 -#else -#define NS_ALP_CLOCK 125000000 -#define NS_SLOW_ALP_CLOCK 100000000 -#define NS_CPU_CLOCK 1000000000 -#define NS_SLOW_CPU_CLOCK 800000000 -#define NS_SI_CLOCK 250000000 -#define NS_SLOW_SI_CLOCK 200000000 -#define NS_FAST_MEM_CLOCK 800000000 -#define NS_MEM_CLOCK 533000000 -#define NS_SLOW_MEM_CLOCK 400000000 -#endif /* CFG_SIM */ - -/* HT clock */ -#define HT_CLOCK 80000000 - -/* corecontrol */ -#define CC_UARTCLKO 0x00000001 /* Drive UART with internal clock */ -#define CC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ -#define CC_ASYNCGPIO 0x00000004 /* 1=generate GPIO interrupt without backplane clock */ -#define CC_UARTCLKEN 0x00000008 /* enable UART Clock (corerev > = 21 */ - -/* 4321 chipcontrol */ -#define CHIPCTRL_4321A0_DEFAULT 0x3a4 -#define CHIPCTRL_4321A1_DEFAULT 0x0a4 -#define CHIPCTRL_4321_PLL_DOWN 0x800000 /* serdes PLL down override */ - -/* Fields in the otpstatus register in rev >= 21 */ -#define OTPS_OL_MASK 0x000000ff -#define OTPS_OL_MFG 0x00000001 /* manuf row is locked */ -#define OTPS_OL_OR1 0x00000002 /* otp redundancy row 1 is locked */ -#define OTPS_OL_OR2 0x00000004 /* otp redundancy row 2 is locked */ -#define OTPS_OL_GU 0x00000008 /* general use region is locked */ -#define OTPS_GUP_MASK 0x00000f00 -#define OTPS_GUP_SHIFT 8 -#define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */ -#define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */ -#define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */ -#define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */ -#define OTPS_READY 0x00001000 -#define OTPS_RV(x) (1 << (16 + (x))) /* redundancy entry valid */ -#define OTPS_RV_MASK 0x0fff0000 -#define OTPS_PROGOK 0x40000000 - -/* Fields in the otpcontrol register in rev >= 21 */ -#define OTPC_PROGSEL 0x00000001 -#define OTPC_PCOUNT_MASK 0x0000000e -#define OTPC_PCOUNT_SHIFT 1 -#define OTPC_VSEL_MASK 0x000000f0 -#define OTPC_VSEL_SHIFT 4 -#define OTPC_TMM_MASK 0x00000700 -#define OTPC_TMM_SHIFT 8 -#define OTPC_ODM 0x00000800 -#define OTPC_PROGEN 0x80000000 - -/* Fields in the 40nm otpcontrol register in rev >= 40 */ -#define OTPC_40NM_PROGSEL_SHIFT 0 -#define OTPC_40NM_PCOUNT_SHIFT 1 -#define OTPC_40NM_PCOUNT_WR 0xA -#define OTPC_40NM_PCOUNT_V1X 0xB -#define OTPC_40NM_REGCSEL_SHIFT 5 -#define OTPC_40NM_REGCSEL_DEF 0x4 -#define OTPC_40NM_PROGIN_SHIFT 8 -#define OTPC_40NM_R2X_SHIFT 10 -#define OTPC_40NM_ODM_SHIFT 11 -#define OTPC_40NM_DF_SHIFT 15 -#define OTPC_40NM_VSEL_SHIFT 16 -#define OTPC_40NM_VSEL_WR 0xA -#define OTPC_40NM_VSEL_V1X 0xA -#define OTPC_40NM_VSEL_R1X 0x5 -#define OTPC_40NM_COFAIL_SHIFT 30 - -#define OTPC1_CPCSEL_SHIFT 0 -#define OTPC1_CPCSEL_DEF 6 -#define OTPC1_TM_SHIFT 8 -#define OTPC1_TM_WR 0x84 -#define OTPC1_TM_V1X 0x84 -#define OTPC1_TM_R1X 0x4 -#define OTPC1_CLK_EN_MASK 0x00020000 -#define OTPC1_CLK_DIV_MASK 0x00FC0000 - -/* Fields in otpprog in rev >= 21 and HND OTP */ -#define OTPP_COL_MASK 0x000000ff -#define OTPP_COL_SHIFT 0 -#define OTPP_ROW_MASK 0x0000ff00 -#define OTPP_ROW_MASK9 0x0001ff00 /* for ccrev >= 49 */ -#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 /* HND OTP */ - -/* Fields in otplayout register */ -#define OTPL_HWRGN_OFF_MASK 0x00000FFF -#define OTPL_HWRGN_OFF_SHIFT 0 -#define OTPL_WRAP_REVID_MASK 0x00F80000 -#define OTPL_WRAP_REVID_SHIFT 19 -#define OTPL_WRAP_TYPE_MASK 0x00070000 -#define OTPL_WRAP_TYPE_SHIFT 16 -#define OTPL_WRAP_TYPE_65NM 0 -#define OTPL_WRAP_TYPE_40NM 1 -#define OTPL_ROW_SIZE_MASK 0x0000F000 -#define OTPL_ROW_SIZE_SHIFT 12 - -/* otplayout reg corerev >= 36 */ -#define OTP_CISFORMAT_NEW 0x80000000 - -/* 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 - -/* Opcodes for OTPP_OC field (40NM) */ -#define OTPPOC_READ_40NM 0 -#define OTPPOC_PROG_ENABLE_40NM 1 -#define OTPPOC_PROG_DISABLE_40NM 2 -#define OTPPOC_VERIFY_40NM 3 -#define OTPPOC_WORD_VERIFY_1_40NM 4 -#define OTPPOC_ROW_LOCK_40NM 5 -#define OTPPOC_STBY_40NM 6 -#define OTPPOC_WAKEUP_40NM 7 -#define OTPPOC_WORD_VERIFY_0_40NM 8 -#define OTPPOC_PRESCN_TEST_40NM 9 -#define OTPPOC_BIT_PROG_40NM 10 -#define OTPPOC_WORDPROG_40NM 11 -#define OTPPOC_BURNIN_40NM 12 -#define OTPPOC_AUTORELOAD_40NM 13 -#define OTPPOC_OVST_READ_40NM 14 -#define OTPPOC_OVST_PROG_40NM 15 - -/* Fields in otplayoutextension */ -#define OTPLAYOUTEXT_FUSE_MASK 0x3FF - - -/* Jtagm characteristics that appeared at a given corerev */ -#define JTAGM_CREV_OLD 10 /* Old command set, 16bit max IR */ -#define JTAGM_CREV_IRP 22 /* Able to do pause-ir */ -#define JTAGM_CREV_RTI 28 /* Able to do return-to-idle */ - -/* jtagcmd */ -#define JCMD_START 0x80000000 -#define JCMD_BUSY 0x80000000 -#define JCMD_STATE_MASK 0x60000000 -#define JCMD_STATE_TLR 0x00000000 /* Test-logic-reset */ -#define JCMD_STATE_PIR 0x20000000 /* Pause IR */ -#define JCMD_STATE_PDR 0x40000000 /* Pause DR */ -#define JCMD_STATE_RTI 0x60000000 /* Run-test-idle */ -#define JCMD0_ACC_MASK 0x0000f000 -#define JCMD0_ACC_IRDR 0x00000000 -#define JCMD0_ACC_DR 0x00001000 -#define JCMD0_ACC_IR 0x00002000 -#define JCMD0_ACC_RESET 0x00003000 -#define JCMD0_ACC_IRPDR 0x00004000 -#define JCMD0_ACC_PDR 0x00005000 -#define JCMD0_IRW_MASK 0x00000f00 -#define JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */ -#define JCMD_ACC_IRDR 0x00000000 -#define JCMD_ACC_DR 0x00010000 -#define JCMD_ACC_IR 0x00020000 -#define JCMD_ACC_RESET 0x00030000 -#define JCMD_ACC_IRPDR 0x00040000 -#define JCMD_ACC_PDR 0x00050000 -#define JCMD_ACC_PIR 0x00060000 -#define JCMD_ACC_IRDR_I 0x00070000 /* rev 28: return to run-test-idle */ -#define JCMD_ACC_DR_I 0x00080000 /* rev 28: return to run-test-idle */ -#define JCMD_IRW_MASK 0x00001f00 -#define JCMD_IRW_SHIFT 8 -#define JCMD_DRW_MASK 0x0000003f - -/* jtagctrl */ -#define JCTRL_FORCE_CLK 4 /* Force clock */ -#define JCTRL_EXT_EN 2 /* Enable external targets */ -#define JCTRL_EN 1 /* Enable Jtag master */ - -#define JCTRL_TAPSEL_BIT 0x00000008 /* JtagMasterCtrl tap_sel bit */ - -/* Fields in clkdiv */ -#define CLKD_SFLASH 0x0f000000 -#define CLKD_SFLASH_SHIFT 24 -#define CLKD_OTP 0x000f0000 -#define CLKD_OTP_SHIFT 16 -#define CLKD_JTAG 0x00000f00 -#define CLKD_JTAG_SHIFT 8 -#define CLKD_UART 0x000000ff - -#define CLKD2_SROM 0x00000003 - -/* intstatus/intmask */ -#define CI_GPIO 0x00000001 /* gpio intr */ -#define CI_EI 0x00000002 /* extif intr (corerev >= 3) */ -#define CI_TEMP 0x00000004 /* temp. ctrl intr (corerev >= 15) */ -#define CI_SIRQ 0x00000008 /* serial IRQ intr (corerev >= 15) */ -#define CI_ECI 0x00000010 /* eci intr (corerev >= 21) */ -#define CI_PMU 0x00000020 /* pmu intr (corerev >= 21) */ -#define CI_UART 0x00000040 /* uart intr (corerev >= 21) */ -#define CI_WDRESET 0x80000000 /* watchdog reset occurred */ - -/* slow_clk_ctl */ -#define SCC_SS_MASK 0x00000007 /* slow clock source mask */ -#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */ -#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */ -#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */ -#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ -#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, - * 0: LPO is enabled - */ -#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, - * 0: power logic control - */ -#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors - * PLL clock disable requests from core - */ -#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't - * disable crystal when appropriate - */ -#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ -#define SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ -#define SCC_CD_SHIFT 16 - -/* system_clk_ctl */ -#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */ -#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */ -#define SYCC_FP 0x00000004 /* ForcePLLOn */ -#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */ -#define SYCC_HR 0x00000010 /* Force HT */ -#define SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ -#define SYCC_CD_SHIFT 16 - -/* Indirect backplane access */ -#define BPIA_BYTEEN 0x0000000f -#define BPIA_SZ1 0x00000001 -#define BPIA_SZ2 0x00000003 -#define BPIA_SZ4 0x00000007 -#define BPIA_SZ8 0x0000000f -#define BPIA_WRITE 0x00000100 -#define BPIA_START 0x00000200 -#define BPIA_BUSY 0x00000200 -#define BPIA_ERROR 0x00000400 - -/* pcmcia/prog/flash_config */ -#define CF_EN 0x00000001 /* enable */ -#define CF_EM_MASK 0x0000000e /* mode */ -#define CF_EM_SHIFT 1 -#define CF_EM_FLASH 0 /* flash/asynchronous mode */ -#define CF_EM_SYNC 2 /* synchronous mode */ -#define CF_EM_PCMCIA 4 /* pcmcia mode */ -#define CF_DS 0x00000010 /* destsize: 0=8bit, 1=16bit */ -#define CF_BS 0x00000020 /* byteswap */ -#define CF_CD_MASK 0x000000c0 /* clock divider */ -#define CF_CD_SHIFT 6 -#define CF_CD_DIV2 0x00000000 /* backplane/2 */ -#define CF_CD_DIV3 0x00000040 /* backplane/3 */ -#define CF_CD_DIV4 0x00000080 /* backplane/4 */ -#define CF_CE 0x00000100 /* clock enable */ -#define CF_SB 0x00000200 /* size/bytestrobe (synch only) */ - -/* pcmcia_memwait */ -#define PM_W0_MASK 0x0000003f /* waitcount0 */ -#define PM_W1_MASK 0x00001f00 /* waitcount1 */ -#define PM_W1_SHIFT 8 -#define PM_W2_MASK 0x001f0000 /* waitcount2 */ -#define PM_W2_SHIFT 16 -#define PM_W3_MASK 0x1f000000 /* waitcount3 */ -#define PM_W3_SHIFT 24 - -/* pcmcia_attrwait */ -#define PA_W0_MASK 0x0000003f /* waitcount0 */ -#define PA_W1_MASK 0x00001f00 /* waitcount1 */ -#define PA_W1_SHIFT 8 -#define PA_W2_MASK 0x001f0000 /* waitcount2 */ -#define PA_W2_SHIFT 16 -#define PA_W3_MASK 0x1f000000 /* waitcount3 */ -#define PA_W3_SHIFT 24 - -/* pcmcia_iowait */ -#define PI_W0_MASK 0x0000003f /* waitcount0 */ -#define PI_W1_MASK 0x00001f00 /* waitcount1 */ -#define PI_W1_SHIFT 8 -#define PI_W2_MASK 0x001f0000 /* waitcount2 */ -#define PI_W2_SHIFT 16 -#define PI_W3_MASK 0x1f000000 /* waitcount3 */ -#define PI_W3_SHIFT 24 - -/* prog_waitcount */ -#define PW_W0_MASK 0x0000001f /* waitcount0 */ -#define PW_W1_MASK 0x00001f00 /* waitcount1 */ -#define PW_W1_SHIFT 8 -#define PW_W2_MASK 0x001f0000 /* waitcount2 */ -#define PW_W2_SHIFT 16 -#define PW_W3_MASK 0x1f000000 /* waitcount3 */ -#define PW_W3_SHIFT 24 - -#define PW_W0 0x0000000c -#define PW_W1 0x00000a00 -#define PW_W2 0x00020000 -#define PW_W3 0x01000000 - -/* flash_waitcount */ -#define FW_W0_MASK 0x0000003f /* waitcount0 */ -#define FW_W1_MASK 0x00001f00 /* waitcount1 */ -#define FW_W1_SHIFT 8 -#define FW_W2_MASK 0x001f0000 /* waitcount2 */ -#define FW_W2_SHIFT 16 -#define FW_W3_MASK 0x1f000000 /* waitcount3 */ -#define FW_W3_SHIFT 24 - -/* 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_OTPPRESENT 0x00000020 -#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 - -/* Fields in pmucontrol */ -#define PCTL_ILP_DIV_MASK 0xffff0000 -#define PCTL_ILP_DIV_SHIFT 16 -#define PCTL_LQ_REQ_EN 0x00008000 -#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 - -/* Retention Control */ -#define PMU_RCTL_CLK_DIV_SHIFT 0 -#define PMU_RCTL_CHAIN_LEN_SHIFT 12 -#define PMU_RCTL_MACPHY_DISABLE_SHIFT 26 -#define PMU_RCTL_MACPHY_DISABLE_MASK (1 << 26) -#define PMU_RCTL_LOGIC_DISABLE_SHIFT 27 -#define PMU_RCTL_LOGIC_DISABLE_MASK (1 << 27) -#define PMU_RCTL_MEMSLP_LOG_SHIFT 28 -#define PMU_RCTL_MEMSLP_LOG_MASK (1 << 28) -#define PMU_RCTL_MEMRETSLP_LOG_SHIFT 29 -#define PMU_RCTL_MEMRETSLP_LOG_MASK (1 << 29) - -/* Retention Group Control */ -#define PMU_RCTLGRP_CHAIN_LEN_SHIFT 0 -#define PMU_RCTLGRP_RMODE_ENABLE_SHIFT 14 -#define PMU_RCTLGRP_RMODE_ENABLE_MASK (1 << 14) -#define PMU_RCTLGRP_DFT_ENABLE_SHIFT 15 -#define PMU_RCTLGRP_DFT_ENABLE_MASK (1 << 15) -#define PMU_RCTLGRP_NSRST_DISABLE_SHIFT 16 -#define PMU_RCTLGRP_NSRST_DISABLE_MASK (1 << 16) -/* Retention Group Control special for 4334 */ -#define PMU4334_RCTLGRP_CHAIN_LEN_GRP0 338 -#define PMU4334_RCTLGRP_CHAIN_LEN_GRP1 315 -/* Retention Group Control special for 43341 */ -#define PMU43341_RCTLGRP_CHAIN_LEN_GRP0 366 -#define PMU43341_RCTLGRP_CHAIN_LEN_GRP1 330 - -/* Fields in clkstretch */ -#define CSTRETCH_HT 0xffff0000 -#define CSTRETCH_ALP 0x0000ffff - -/* gpiotimerval */ -#define GPIO_ONTIME_SHIFT 16 - -/* clockcontrol_n */ -#define CN_N1_MASK 0x3f /* n1 control */ -#define CN_N2_MASK 0x3f00 /* n2 control */ -#define CN_N2_SHIFT 8 -#define CN_PLLC_MASK 0xf0000 /* pll control */ -#define CN_PLLC_SHIFT 16 - -/* clockcontrol_sb/pci/uart */ -#define CC_M1_MASK 0x3f /* m1 control */ -#define CC_M2_MASK 0x3f00 /* m2 control */ -#define CC_M2_SHIFT 8 -#define CC_M3_MASK 0x3f0000 /* m3 control */ -#define CC_M3_SHIFT 16 -#define CC_MC_MASK 0x1f000000 /* mux control */ -#define CC_MC_SHIFT 24 - -/* N3M Clock control magic field values */ -#define CC_F6_2 0x02 /* A factor of 2 in */ -#define CC_F6_3 0x03 /* 6-bit fields like */ -#define CC_F6_4 0x05 /* N1, M1 or M3 */ -#define CC_F6_5 0x09 -#define CC_F6_6 0x11 -#define CC_F6_7 0x21 - -#define CC_F5_BIAS 5 /* 5-bit fields get this added */ - -#define CC_MC_BYPASS 0x08 -#define CC_MC_M1 0x04 -#define CC_MC_M1M2 0x02 -#define CC_MC_M1M2M3 0x01 -#define CC_MC_M1M3 0x11 - -/* Type 2 Clock control magic field values */ -#define CC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ -#define CC_T2M2_BIAS 3 /* m2 bias */ - -#define CC_T2MC_M1BYP 1 -#define CC_T2MC_M2BYP 2 -#define CC_T2MC_M3BYP 4 - -/* Type 6 Clock control magic field values */ -#define CC_T6_MMASK 1 /* bits of interest in m */ -#define CC_T6_M0 120000000 /* sb clock for m = 0 */ -#define CC_T6_M1 100000000 /* sb clock for m = 1 */ -#define SB2MIPS_T6(sb) (2 * (sb)) - -/* Common clock base */ -#define CC_CLOCK_BASE1 24000000 /* Half the clock freq */ -#define CC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLLs */ - -/* Clock control values for 200MHz in 5350 */ -#define CLKC_5350_N 0x0311 -#define CLKC_5350_M 0x04020009 - -/* Flash types in the chipcommon capabilities register */ -#define FLASH_NONE 0x000 /* No flash */ -#define SFLASH_ST 0x100 /* ST serial flash */ -#define SFLASH_AT 0x200 /* Atmel serial flash */ -#define NFLASH 0x300 -#define PFLASH 0x700 /* Parallel flash */ -#define QSPIFLASH_ST 0x800 -#define QSPIFLASH_AT 0x900 - -/* Bits in the ExtBus config registers */ -#define CC_CFG_EN 0x0001 /* Enable */ -#define CC_CFG_EM_MASK 0x000e /* Extif Mode */ -#define CC_CFG_EM_ASYNC 0x0000 /* Async/Parallel flash */ -#define CC_CFG_EM_SYNC 0x0002 /* Synchronous */ -#define CC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */ -#define CC_CFG_EM_IDE 0x0006 /* IDE */ -#define CC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */ -#define CC_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */ -#define CC_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */ -#define CC_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */ -#define CC_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */ - -/* ExtBus address space */ -#define CC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */ -#define CC_EB_PCMCIA_MEM 0x1a000000 /* PCMCIA 0 memory base address */ -#define CC_EB_PCMCIA_IO 0x1a200000 /* PCMCIA 0 I/O base address */ -#define CC_EB_PCMCIA_CFG 0x1a400000 /* PCMCIA 0 config base address */ -#define CC_EB_IDE 0x1a800000 /* IDE memory base */ -#define CC_EB_PCMCIA1_MEM 0x1a800000 /* PCMCIA 1 memory base address */ -#define CC_EB_PCMCIA1_IO 0x1aa00000 /* PCMCIA 1 I/O base address */ -#define CC_EB_PCMCIA1_CFG 0x1ac00000 /* PCMCIA 1 config base address */ -#define CC_EB_PROGIF 0x1b000000 /* ProgIF Async/Sync base address */ - - -/* Start/busy bit in flashcontrol */ -#define SFLASH_OPCODE 0x000000ff -#define SFLASH_ACTION 0x00000700 -#define SFLASH_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */ -#define SFLASH_START 0x80000000 -#define SFLASH_BUSY SFLASH_START - -/* flashcontrol action codes */ -#define SFLASH_ACT_OPONLY 0x0000 /* Issue opcode only */ -#define SFLASH_ACT_OP1D 0x0100 /* opcode + 1 data byte */ -#define SFLASH_ACT_OP3A 0x0200 /* opcode + 3 addr bytes */ -#define SFLASH_ACT_OP3A1D 0x0300 /* opcode + 3 addr & 1 data bytes */ -#define SFLASH_ACT_OP3A4D 0x0400 /* opcode + 3 addr & 4 data bytes */ -#define SFLASH_ACT_OP3A4X4D 0x0500 /* opcode + 3 addr, 4 don't care & 4 data bytes */ -#define SFLASH_ACT_OP3A1X4D 0x0700 /* opcode + 3 addr, 1 don't care & 4 data bytes */ - -/* flashcontrol action+opcodes for ST flashes */ -#define SFLASH_ST_WREN 0x0006 /* Write Enable */ -#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */ -#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */ -#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */ -#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */ -#define SFLASH_ST_PP 0x0302 /* Page Program */ -#define SFLASH_ST_SE 0x02d8 /* Sector Erase */ -#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */ -#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */ -#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */ -#define SFLASH_ST_CSA 0x1000 /* Keep chip select asserted */ -#define SFLASH_ST_SSE 0x0220 /* Sub-sector Erase */ - -#define SFLASH_MXIC_RDID 0x0390 /* Read Manufacture ID */ -#define SFLASH_MXIC_MFID 0xc2 /* MXIC Manufacture ID */ - -/* Status register bits for ST flashes */ -#define SFLASH_ST_WIP 0x01 /* Write In Progress */ -#define SFLASH_ST_WEL 0x02 /* Write Enable Latch */ -#define SFLASH_ST_BP_MASK 0x1c /* Block Protect */ -#define SFLASH_ST_BP_SHIFT 2 -#define SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */ - -/* flashcontrol action+opcodes for Atmel flashes */ -#define SFLASH_AT_READ 0x07e8 -#define SFLASH_AT_PAGE_READ 0x07d2 -#define SFLASH_AT_BUF1_READ -#define SFLASH_AT_BUF2_READ -#define SFLASH_AT_STATUS 0x01d7 -#define SFLASH_AT_BUF1_WRITE 0x0384 -#define SFLASH_AT_BUF2_WRITE 0x0387 -#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 -#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 -#define SFLASH_AT_BUF1_PROGRAM 0x0288 -#define SFLASH_AT_BUF2_PROGRAM 0x0289 -#define SFLASH_AT_PAGE_ERASE 0x0281 -#define SFLASH_AT_BLOCK_ERASE 0x0250 -#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 -#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 -#define SFLASH_AT_BUF1_LOAD 0x0253 -#define SFLASH_AT_BUF2_LOAD 0x0255 -#define SFLASH_AT_BUF1_COMPARE 0x0260 -#define SFLASH_AT_BUF2_COMPARE 0x0261 -#define SFLASH_AT_BUF1_REPROGRAM 0x0258 -#define SFLASH_AT_BUF2_REPROGRAM 0x0259 - -/* Status register bits for Atmel flashes */ -#define SFLASH_AT_READY 0x80 -#define SFLASH_AT_MISMATCH 0x40 -#define SFLASH_AT_ID_MASK 0x38 -#define SFLASH_AT_ID_SHIFT 3 - -/* SPI register bits, corerev >= 37 */ -#define GSIO_START 0x80000000 -#define GSIO_BUSY GSIO_START - -/* - * These are the UART port assignments, expressed as offsets from the base - * register. These assignments should hold for any serial port based on - * a 8250, 16450, or 16550(A). - */ - -#define UART_RX 0 /* In: Receive buffer (DLAB=0) */ -#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ -#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ -#define UART_IER 1 /* In/Out: Interrupt Enable Register (DLAB=0) */ -#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */ -#define UART_IIR 2 /* In: Interrupt Identity Register */ -#define UART_FCR 2 /* Out: FIFO Control Register */ -#define UART_LCR 3 /* Out: Line Control Register */ -#define UART_MCR 4 /* Out: Modem Control Register */ -#define UART_LSR 5 /* In: Line Status Register */ -#define UART_MSR 6 /* In: Modem Status Register */ -#define UART_SCR 7 /* I/O: Scratch Register */ -#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ -#define UART_LCR_WLEN8 0x03 /* Word length: 8 bits */ -#define UART_MCR_OUT2 0x08 /* MCR GPIO out 2 */ -#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ -#define UART_LSR_RX_FIFO 0x80 /* Receive FIFO error */ -#define UART_LSR_TDHR 0x40 /* Data-hold-register empty */ -#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ -#define UART_LSR_BREAK 0x10 /* Break interrupt */ -#define UART_LSR_FRAMING 0x08 /* Framing error */ -#define UART_LSR_PARITY 0x04 /* Parity error */ -#define UART_LSR_OVERRUN 0x02 /* Overrun error */ -#define UART_LSR_RXRDY 0x01 /* Receiver ready */ -#define UART_FCR_FIFO_ENABLE 1 /* FIFO control register bit controlling FIFO enable/disable */ - -/* Interrupt Identity Register (IIR) bits */ -#define UART_IIR_FIFO_MASK 0xc0 /* IIR FIFO disable/enabled mask */ -#define UART_IIR_INT_MASK 0xf /* IIR interrupt ID source */ -#define UART_IIR_MDM_CHG 0x0 /* Modem status changed */ -#define UART_IIR_NOINT 0x1 /* No interrupt pending */ -#define UART_IIR_THRE 0x2 /* THR empty */ -#define UART_IIR_RCVD_DATA 0x4 /* Received data available */ -#define UART_IIR_RCVR_STATUS 0x6 /* Receiver status */ -#define UART_IIR_CHAR_TIME 0xc /* Character time */ - -/* Interrupt Enable Register (IER) bits */ -#define UART_IER_PTIME 128 /* Programmable THRE Interrupt Mode Enable */ -#define UART_IER_EDSSI 8 /* enable modem status interrupt */ -#define UART_IER_ELSI 4 /* enable receiver line status interrupt */ -#define UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */ -#define UART_IER_ERBFI 1 /* enable data available interrupt */ - -/* pmustatus */ -#define PST_SLOW_WR_PENDING 0x0400 -#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 - -/* 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 - -/* PMU Resource Request Timer registers */ -/* This is based on PmuRev0 */ -#define PRRT_TIME_MASK 0x03ff -#define PRRT_INTEN 0x0400 -#define PRRT_REQ_ACTIVE 0x0800 -#define PRRT_ALP_REQ 0x1000 -#define PRRT_HT_REQ 0x2000 -#define PRRT_HQ_REQ 0x4000 - -/* bit 0 of the PMU interrupt vector is asserted if this mask is enabled */ -#define RSRC_INTR_MASK_TIMER_INT_0 1 - -/* PMU resource bit position */ -#define PMURES_BIT(bit) (1 << (bit)) - -/* PMU resource number limit */ -#define PMURES_MAX_RESNUM 30 - -/* PMU chip control0 register */ -#define PMU_CHIPCTL0 0 -#define PMU43143_CC0_SDIO_DRSTR_OVR (1 << 31) /* sdio drive strength override enable */ - -/* clock req types */ -#define PMU_CC1_CLKREQ_TYPE_SHIFT 19 -#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT) - -#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0 -#define CLKREQ_TYPE_CONFIG_PUSHPULL 1 - -/* PMU chip control1 register */ -#define PMU_CHIPCTL1 1 -#define PMU_CC1_RXC_DLL_BYPASS 0x00010000 -#define PMU_CC1_ENABLE_BBPLL_PWR_DOWN 0x00000010 - -#define PMU_CC1_IF_TYPE_MASK 0x00000030 -#define PMU_CC1_IF_TYPE_RMII 0x00000000 -#define PMU_CC1_IF_TYPE_MII 0x00000010 -#define PMU_CC1_IF_TYPE_RGMII 0x00000020 - -#define PMU_CC1_SW_TYPE_MASK 0x000000c0 -#define PMU_CC1_SW_TYPE_EPHY 0x00000000 -#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040 -#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 -#define PMU_CC1_SW_TYPE_RGMII 0x000000c0 - -/* PMU chip control2 register */ -#define PMU_CHIPCTL2 2 -#define PMU_CC2_FORCE_SUBCORE_PWR_SWITCH_ON (1 << 18) -#define PMU_CC2_FORCE_PHY_PWR_SWITCH_ON (1 << 19) -#define PMU_CC2_FORCE_VDDM_PWR_SWITCH_ON (1 << 20) -#define PMU_CC2_FORCE_MEMLPLDO_PWR_SWITCH_ON (1 << 21) - -/* PMU chip control3 register */ -#define PMU_CHIPCTL3 3 -#define PMU_CC3_ENABLE_SDIO_WAKEUP_SHIFT 19 -#define PMU_CC3_ENABLE_RF_SHIFT 22 -#define PMU_CC3_RF_DISABLE_IVALUE_SHIFT 23 - -/* PMU chip control5 register */ -#define PMU_CHIPCTL5 5 - -/* PMU chip control6 register */ -#define PMU_CHIPCTL6 6 -#define PMU_CC6_ENABLE_CLKREQ_WAKEUP (1 << 4) -#define PMU_CC6_ENABLE_PMU_WAKEUP_ALP (1 << 6) - -/* PMU chip control7 register */ -#define PMU_CHIPCTL7 7 -#define PMU_CC7_ENABLE_L2REFCLKPAD_PWRDWN (1 << 25) -#define PMU_CC7_ENABLE_MDIO_RESET_WAR (1 << 27) - - -/* 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 */ -/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */ -#define PMU0_PLL0_PLLCTL0 0 -#define PMU0_PLL0_PC0_PDIV_MASK 1 -#define PMU0_PLL0_PC0_PDIV_FREQ 25000 -#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038 -#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3 -#define PMU0_PLL0_PC0_DIV_ARM_BASE 8 - -/* PC0_DIV_ARM for PLLOUT_ARM */ -#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0 -#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1 -#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2 -#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */ -#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4 -#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5 -#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6 -#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7 - -/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */ -#define PMU0_PLL0_PLLCTL1 1 -#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000 -#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28 -#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00 -#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8 -#define PMU0_PLL0_PC1_STOP_MOD 0x00000040 - -/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */ -#define PMU0_PLL0_PLLCTL2 2 -#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf -#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4 - -/* pllcontrol registers */ -/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ -#define PMU1_PLL0_PLLCTL0 0 -#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 -#define PMU1_PLL0_PC0_P1DIV_SHIFT 20 -#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 -#define PMU1_PLL0_PC0_P2DIV_SHIFT 24 - -/* mdiv */ -#define PMU1_PLL0_PLLCTL1 1 -#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff -#define PMU1_PLL0_PC1_M1DIV_SHIFT 0 -#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 -#define PMU1_PLL0_PC1_M2DIV_SHIFT 8 -#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 -#define PMU1_PLL0_PC1_M3DIV_SHIFT 16 -#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 -#define PMU1_PLL0_PC1_M4DIV_SHIFT 24 -#define PMU1_PLL0_PC1_M4DIV_BY_9 9 -#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12 -#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24 -#define PMU1_PLL0_PC1_M4DIV_BY_60 0x3C - -#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 -#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) -#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) - -/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ -#define PMU1_PLL0_PLLCTL2 2 -#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff -#define PMU1_PLL0_PC2_M5DIV_SHIFT 0 -#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc -#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12 -#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24 -#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 -#define PMU1_PLL0_PC2_M6DIV_SHIFT 8 -#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12 -#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24 -#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 -#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 -#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 -#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */ -#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 -#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 - -/* ndiv_frac */ -#define PMU1_PLL0_PLLCTL3 3 -#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff -#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 - -/* pll_ctrl */ -#define PMU1_PLL0_PLLCTL4 4 - -/* pll_ctrl, vco_rng, clkdrive_ch */ -#define PMU1_PLL0_PLLCTL5 5 -#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 -#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 - -#define PMU1_PLL0_PLLCTL6 6 -#define PMU1_PLL0_PLLCTL7 7 - -#define PMU1_PLL0_PLLCTL8 8 -#define PMU1_PLLCTL8_OPENLOOP_MASK 0x2 - -/* PMU rev 2 control words */ -#define PMU2_PHY_PLL_PLLCTL 4 -#define PMU2_SI_PLL_PLLCTL 10 - -/* PMU rev 2 */ -/* pllcontrol registers */ -/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ -#define PMU2_PLL_PLLCTL0 0 -#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 -#define PMU2_PLL_PC0_P1DIV_SHIFT 20 -#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 -#define PMU2_PLL_PC0_P2DIV_SHIFT 24 - -/* mdiv */ -#define PMU2_PLL_PLLCTL1 1 -#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff -#define PMU2_PLL_PC1_M1DIV_SHIFT 0 -#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 -#define PMU2_PLL_PC1_M2DIV_SHIFT 8 -#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 -#define PMU2_PLL_PC1_M3DIV_SHIFT 16 -#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000 -#define PMU2_PLL_PC1_M4DIV_SHIFT 24 - -/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ -#define PMU2_PLL_PLLCTL2 2 -#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff -#define PMU2_PLL_PC2_M5DIV_SHIFT 0 -#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 -#define PMU2_PLL_PC2_M6DIV_SHIFT 8 -#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 -#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 -#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 -#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20 - -/* ndiv_frac */ -#define PMU2_PLL_PLLCTL3 3 -#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff -#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 - -/* pll_ctrl */ -#define PMU2_PLL_PLLCTL4 4 - -/* pll_ctrl, vco_rng, clkdrive_ch */ -#define PMU2_PLL_PLLCTL5 5 -#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 -#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 -#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 -#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 -#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 -#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 -#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 -#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 -#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 -#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 -#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 -#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 - -/* PMU rev 5 (& 6) */ -#define PMU5_PLL_P1P2_OFF 0 -#define PMU5_PLL_P1_MASK 0x0f000000 -#define PMU5_PLL_P1_SHIFT 24 -#define PMU5_PLL_P2_MASK 0x00f00000 -#define PMU5_PLL_P2_SHIFT 20 -#define PMU5_PLL_M14_OFF 1 -#define PMU5_PLL_MDIV_MASK 0x000000ff -#define PMU5_PLL_MDIV_WIDTH 8 -#define PMU5_PLL_NM5_OFF 2 -#define PMU5_PLL_NDIV_MASK 0xfff00000 -#define PMU5_PLL_NDIV_SHIFT 20 -#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000 -#define PMU5_PLL_NDIV_MODE_SHIFT 17 -#define PMU5_PLL_FMAB_OFF 3 -#define PMU5_PLL_MRAT_MASK 0xf0000000 -#define PMU5_PLL_MRAT_SHIFT 28 -#define PMU5_PLL_ABRAT_MASK 0x08000000 -#define PMU5_PLL_ABRAT_SHIFT 27 -#define PMU5_PLL_FDIV_MASK 0x07ffffff -#define PMU5_PLL_PLLCTL_OFF 4 -#define PMU5_PLL_PCHI_OFF 5 -#define PMU5_PLL_PCHI_MASK 0x0000003f - -/* pmu XtalFreqRatio */ -#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF -#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 -#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 - -/* Divider allocation in 4716/47162/5356/5357 */ -#define PMU5_MAINPLL_CPU 1 -#define PMU5_MAINPLL_MEM 2 -#define PMU5_MAINPLL_SI 3 - -/* 4706 PMU */ -#define PMU4706_MAINPLL_PLL0 0 -#define PMU6_4706_PROCPLL_OFF 4 /* The CPU PLL */ -#define PMU6_4706_PROC_P2DIV_MASK 0x000f0000 -#define PMU6_4706_PROC_P2DIV_SHIFT 16 -#define PMU6_4706_PROC_P1DIV_MASK 0x0000f000 -#define PMU6_4706_PROC_P1DIV_SHIFT 12 -#define PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 -#define PMU6_4706_PROC_NDIV_INT_SHIFT 3 -#define PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 -#define PMU6_4706_PROC_NDIV_MODE_SHIFT 0 - -#define PMU7_PLL_PLLCTL7 7 -#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000 -#define PMU7_PLL_CTL7_M4DIV_SHIFT 24 -#define PMU7_PLL_CTL7_M4DIV_BY_6 6 -#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc -#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18 -#define PMU7_PLL_PLLCTL8 8 -#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff -#define PMU7_PLL_CTL8_M5DIV_SHIFT 0 -#define PMU7_PLL_CTL8_M5DIV_BY_8 8 -#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc -#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18 -#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00 -#define PMU7_PLL_CTL8_M6DIV_SHIFT 8 -#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc -#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18 -#define PMU7_PLL_PLLCTL11 11 -#define PMU7_PLL_PLLCTL11_MASK 0xffffff00 -#define PMU7_PLL_PLLCTL11_VAL 0x22222200 - -/* PMU rev 15 */ -#define PMU15_PLL_PLLCTL0 0 -#define PMU15_PLL_PC0_CLKSEL_MASK 0x00000003 -#define PMU15_PLL_PC0_CLKSEL_SHIFT 0 -#define PMU15_PLL_PC0_FREQTGT_MASK 0x003FFFFC -#define PMU15_PLL_PC0_FREQTGT_SHIFT 2 -#define PMU15_PLL_PC0_PRESCALE_MASK 0x00C00000 -#define PMU15_PLL_PC0_PRESCALE_SHIFT 22 -#define PMU15_PLL_PC0_KPCTRL_MASK 0x07000000 -#define PMU15_PLL_PC0_KPCTRL_SHIFT 24 -#define PMU15_PLL_PC0_FCNTCTRL_MASK 0x38000000 -#define PMU15_PLL_PC0_FCNTCTRL_SHIFT 27 -#define PMU15_PLL_PC0_FDCMODE_MASK 0x40000000 -#define PMU15_PLL_PC0_FDCMODE_SHIFT 30 -#define PMU15_PLL_PC0_CTRLBIAS_MASK 0x80000000 -#define PMU15_PLL_PC0_CTRLBIAS_SHIFT 31 - -#define PMU15_PLL_PLLCTL1 1 -#define PMU15_PLL_PC1_BIAS_CTLM_MASK 0x00000060 -#define PMU15_PLL_PC1_BIAS_CTLM_SHIFT 5 -#define PMU15_PLL_PC1_BIAS_CTLM_RST_MASK 0x00000040 -#define PMU15_PLL_PC1_BIAS_CTLM_RST_SHIFT 6 -#define PMU15_PLL_PC1_BIAS_SS_DIVR_MASK 0x0001FF80 -#define PMU15_PLL_PC1_BIAS_SS_DIVR_SHIFT 7 -#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_MASK 0x03FE0000 -#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_SHIFT 17 -#define PMU15_PLL_PC1_BIAS_INTG_BW_MASK 0x0C000000 -#define PMU15_PLL_PC1_BIAS_INTG_BW_SHIFT 26 -#define PMU15_PLL_PC1_BIAS_INTG_BYP_MASK 0x10000000 -#define PMU15_PLL_PC1_BIAS_INTG_BYP_SHIFT 28 -#define PMU15_PLL_PC1_OPENLP_EN_MASK 0x40000000 -#define PMU15_PLL_PC1_OPENLP_EN_SHIFT 30 - -#define PMU15_PLL_PLLCTL2 2 -#define PMU15_PLL_PC2_CTEN_MASK 0x00000001 -#define PMU15_PLL_PC2_CTEN_SHIFT 0 - -#define PMU15_PLL_PLLCTL3 3 -#define PMU15_PLL_PC3_DITHER_EN_MASK 0x00000001 -#define PMU15_PLL_PC3_DITHER_EN_SHIFT 0 -#define PMU15_PLL_PC3_DCOCTLSP_MASK 0xFE000000 -#define PMU15_PLL_PC3_DCOCTLSP_SHIFT 25 -#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_MASK 0x01 -#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_SHIFT 0 -#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_MASK 0x02 -#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_SHIFT 1 -#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_MASK 0x04 -#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_SHIFT 2 -#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_MASK 0x18 -#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_SHIFT 3 -#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_MASK 0x60 -#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_SHIFT 5 -#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV1 0 -#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV2 1 -#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV3 2 -#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV5 3 - -#define PMU15_PLL_PLLCTL4 4 -#define PMU15_PLL_PC4_FLLCLK1_DIV_MASK 0x00000007 -#define PMU15_PLL_PC4_FLLCLK1_DIV_SHIFT 0 -#define PMU15_PLL_PC4_FLLCLK2_DIV_MASK 0x00000038 -#define PMU15_PLL_PC4_FLLCLK2_DIV_SHIFT 3 -#define PMU15_PLL_PC4_FLLCLK3_DIV_MASK 0x000001C0 -#define PMU15_PLL_PC4_FLLCLK3_DIV_SHIFT 6 -#define PMU15_PLL_PC4_DBGMODE_MASK 0x00000E00 -#define PMU15_PLL_PC4_DBGMODE_SHIFT 9 -#define PMU15_PLL_PC4_FLL480_CTLSP_LK_MASK 0x00001000 -#define PMU15_PLL_PC4_FLL480_CTLSP_LK_SHIFT 12 -#define PMU15_PLL_PC4_FLL480_CTLSP_MASK 0x000FE000 -#define PMU15_PLL_PC4_FLL480_CTLSP_SHIFT 13 -#define PMU15_PLL_PC4_DINPOL_MASK 0x00100000 -#define PMU15_PLL_PC4_DINPOL_SHIFT 20 -#define PMU15_PLL_PC4_CLKOUT_PD_MASK 0x00200000 -#define PMU15_PLL_PC4_CLKOUT_PD_SHIFT 21 -#define PMU15_PLL_PC4_CLKDIV2_PD_MASK 0x00400000 -#define PMU15_PLL_PC4_CLKDIV2_PD_SHIFT 22 -#define PMU15_PLL_PC4_CLKDIV4_PD_MASK 0x00800000 -#define PMU15_PLL_PC4_CLKDIV4_PD_SHIFT 23 -#define PMU15_PLL_PC4_CLKDIV8_PD_MASK 0x01000000 -#define PMU15_PLL_PC4_CLKDIV8_PD_SHIFT 24 -#define PMU15_PLL_PC4_CLKDIV16_PD_MASK 0x02000000 -#define PMU15_PLL_PC4_CLKDIV16_PD_SHIFT 25 -#define PMU15_PLL_PC4_TEST_EN_MASK 0x04000000 -#define PMU15_PLL_PC4_TEST_EN_SHIFT 26 - -#define PMU15_PLL_PLLCTL5 5 -#define PMU15_PLL_PC5_FREQTGT_MASK 0x000FFFFF -#define PMU15_PLL_PC5_FREQTGT_SHIFT 0 -#define PMU15_PLL_PC5_DCOCTLSP_MASK 0x07F00000 -#define PMU15_PLL_PC5_DCOCTLSP_SHIFT 20 -#define PMU15_PLL_PC5_PRESCALE_MASK 0x18000000 -#define PMU15_PLL_PC5_PRESCALE_SHIFT 27 - -#define PMU15_PLL_PLLCTL6 6 -#define PMU15_PLL_PC6_FREQTGT_MASK 0x000FFFFF -#define PMU15_PLL_PC6_FREQTGT_SHIFT 0 -#define PMU15_PLL_PC6_DCOCTLSP_MASK 0x07F00000 -#define PMU15_PLL_PC6_DCOCTLSP_SHIFT 20 -#define PMU15_PLL_PC6_PRESCALE_MASK 0x18000000 -#define PMU15_PLL_PC6_PRESCALE_SHIFT 27 - -#define PMU15_FREQTGT_480_DEFAULT 0x19AB1 -#define PMU15_FREQTGT_492_DEFAULT 0x1A4F5 -#define PMU15_ARM_96MHZ 96000000 /* 96 Mhz */ -#define PMU15_ARM_98MHZ 98400000 /* 98.4 Mhz */ -#define PMU15_ARM_97MHZ 97000000 /* 97 Mhz */ - - -#define PMU17_PLLCTL2_NDIVTYPE_MASK 0x00000070 -#define PMU17_PLLCTL2_NDIVTYPE_SHIFT 4 - -#define PMU17_PLLCTL2_NDIV_MODE_INT 0 -#define PMU17_PLLCTL2_NDIV_MODE_INT1B8 1 -#define PMU17_PLLCTL2_NDIV_MODE_MASH111 2 -#define PMU17_PLLCTL2_NDIV_MODE_MASH111B8 3 - -#define PMU17_PLLCTL0_BBPLL_PWRDWN 0 -#define PMU17_PLLCTL0_BBPLL_DRST 3 -#define PMU17_PLLCTL0_BBPLL_DISBL_CLK 8 - -/* PLL usage in 4716/47162 */ -#define PMU4716_MAINPLL_PLL0 12 - -/* PLL usage in 4335 */ -#define PMU4335_PLL0_PC2_P1DIV_MASK 0x000f0000 -#define PMU4335_PLL0_PC2_P1DIV_SHIFT 16 -#define PMU4335_PLL0_PC2_NDIV_INT_MASK 0xff800000 -#define PMU4335_PLL0_PC2_NDIV_INT_SHIFT 23 -#define PMU4335_PLL0_PC1_MDIV2_MASK 0x0000ff00 -#define PMU4335_PLL0_PC1_MDIV2_SHIFT 8 - - -/* PLL usage in 5356/5357 */ -#define PMU5356_MAINPLL_PLL0 0 -#define PMU5357_MAINPLL_PLL0 0 - -/* 4716/47162 resources */ -#define RES4716_PROC_PLL_ON 0x00000040 -#define RES4716_PROC_HT_AVAIL 0x00000080 - -/* 4716/4717/4718 Chip specific ChipControl register bits */ -#define CCTRL_471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared w/ pflash */ - -/* 5357 Chip specific ChipControl register bits */ -/* 2nd - 32-bit reg */ -#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000 /* I2S pins enable */ -#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000 /* I2C/SPI pins enable */ - -/* 5354 resources */ -#define RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */ -#define RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */ -#define RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */ -#define RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ -#define RES5354_ILP_REQUEST 4 /* 0x00010 */ -#define RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */ -#define RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */ -#define RES5354_ROM_SWITCH 7 /* 0x00080 */ -#define RES5354_PA_REF_LDO 8 /* 0x00100 */ -#define RES5354_RADIO_LDO 9 /* 0x00200 */ -#define RES5354_AFE_LDO 10 /* 0x00400 */ -#define RES5354_PLL_LDO 11 /* 0x00800 */ -#define RES5354_BG_FILTBYP 12 /* 0x01000 */ -#define RES5354_TX_FILTBYP 13 /* 0x02000 */ -#define RES5354_RX_FILTBYP 14 /* 0x04000 */ -#define RES5354_XTAL_PU 15 /* 0x08000 */ -#define RES5354_XTAL_EN 16 /* 0x10000 */ -#define RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */ -#define RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */ -#define RES5354_BB_PLL_PU 19 /* 0x80000 */ - -/* 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 CCTRL5357_NFLASH (1<<16) /* Nandflash in ChipControl 1, bit 16 */ - -/* 43217 Chip specific ChipControl register bits */ -#define CCTRL43217_EXTPA_C0 (1<<13) /* core0 extPA in ChipControl 1, bit 13 */ -#define CCTRL43217_EXTPA_C1 (1<<8) /* core1 extPA in ChipControl 1, bit 8 */ - -/* 43228 Chip specific ChipControl register bits */ -#define CCTRL43228_EXTPA_C0 (1<<14) /* core1 extPA in ChipControl 1, bit 14 */ -#define CCTRL43228_EXTPA_C1 (1<<9) /* core0 extPA in ChipControl 1, bit 1 */ - -/* 4328 resources */ -#define RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */ -#define RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */ -#define RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */ -#define RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ -#define RES4328_ILP_REQUEST 4 /* 0x00010 */ -#define RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */ -#define RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */ -#define RES4328_ROM_SWITCH 7 /* 0x00080 */ -#define RES4328_PA_REF_LDO 8 /* 0x00100 */ -#define RES4328_RADIO_LDO 9 /* 0x00200 */ -#define RES4328_AFE_LDO 10 /* 0x00400 */ -#define RES4328_PLL_LDO 11 /* 0x00800 */ -#define RES4328_BG_FILTBYP 12 /* 0x01000 */ -#define RES4328_TX_FILTBYP 13 /* 0x02000 */ -#define RES4328_RX_FILTBYP 14 /* 0x04000 */ -#define RES4328_XTAL_PU 15 /* 0x08000 */ -#define RES4328_XTAL_EN 16 /* 0x10000 */ -#define RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */ -#define RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */ -#define RES4328_BB_PLL_PU 19 /* 0x80000 */ - -/* 4325 A0/A1 resources */ -#define RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */ -#define RES4325_CBUCK_BURST 1 /* 0x00000002 */ -#define RES4325_CBUCK_PWM 2 /* 0x00000004 */ -#define RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */ -#define RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */ -#define RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */ -#define RES4325_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4325_ABUCK_BURST 7 /* 0x00000080 */ -#define RES4325_ABUCK_PWM 8 /* 0x00000100 */ -#define RES4325_LNLDO1_PU 9 /* 0x00000200 */ -#define RES4325_OTP_PU 10 /* 0x00000400 */ -#define RES4325_LNLDO3_PU 11 /* 0x00000800 */ -#define RES4325_LNLDO4_PU 12 /* 0x00001000 */ -#define RES4325_XTAL_PU 13 /* 0x00002000 */ -#define RES4325_ALP_AVAIL 14 /* 0x00004000 */ -#define RES4325_RX_PWRSW_PU 15 /* 0x00008000 */ -#define RES4325_TX_PWRSW_PU 16 /* 0x00010000 */ -#define RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */ -#define RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */ -#define RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */ -#define RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */ -#define RES4325_HT_AVAIL 21 /* 0x00200000 */ - -/* 4325 B0/C0 resources */ -#define RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */ -#define RES4325B0_CBUCK_BURST 2 /* 0x00000004 */ -#define RES4325B0_CBUCK_PWM 3 /* 0x00000008 */ -#define RES4325B0_CLDO_PU 4 /* 0x00000010 */ - -/* 4325 C1 resources */ -#define RES4325C1_LNLDO2_PU 12 /* 0x00001000 */ - -/* 4325 chip-specific ChipStatus register bits */ -#define CST4325_SPROM_OTP_SEL_MASK 0x00000003 -#define CST4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ -#define CST4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ -#define CST4325_OTP_SEL 2 /* OTP is powered up, no SPROM */ -#define CST4325_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ -#define CST4325_SDIO_USB_MODE_MASK 0x00000004 -#define CST4325_SDIO_USB_MODE_SHIFT 2 -#define CST4325_RCAL_VALID_MASK 0x00000008 -#define CST4325_RCAL_VALID_SHIFT 3 -#define CST4325_RCAL_VALUE_MASK 0x000001f0 -#define CST4325_RCAL_VALUE_SHIFT 4 -#define CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */ -#define CST4325_PMUTOP_2B_SHIFT 9 - -#define RES4329_RESERVED0 0 /* 0x00000001 */ -#define RES4329_CBUCK_LPOM 1 /* 0x00000002 */ -#define RES4329_CBUCK_BURST 2 /* 0x00000004 */ -#define RES4329_CBUCK_PWM 3 /* 0x00000008 */ -#define RES4329_CLDO_PU 4 /* 0x00000010 */ -#define RES4329_PALDO_PU 5 /* 0x00000020 */ -#define RES4329_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4329_RESERVED7 7 /* 0x00000080 */ -#define RES4329_RESERVED8 8 /* 0x00000100 */ -#define RES4329_LNLDO1_PU 9 /* 0x00000200 */ -#define RES4329_OTP_PU 10 /* 0x00000400 */ -#define RES4329_RESERVED11 11 /* 0x00000800 */ -#define RES4329_LNLDO2_PU 12 /* 0x00001000 */ -#define RES4329_XTAL_PU 13 /* 0x00002000 */ -#define RES4329_ALP_AVAIL 14 /* 0x00004000 */ -#define RES4329_RX_PWRSW_PU 15 /* 0x00008000 */ -#define RES4329_TX_PWRSW_PU 16 /* 0x00010000 */ -#define RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */ -#define RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */ -#define RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */ -#define RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */ -#define RES4329_HT_AVAIL 21 /* 0x00200000 */ - -#define CST4329_SPROM_OTP_SEL_MASK 0x00000003 -#define CST4329_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ -#define CST4329_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ -#define CST4329_OTP_SEL 2 /* OTP is powered up, no SPROM */ -#define CST4329_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ -#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 -#define CST4329_SPI_SDIO_MODE_SHIFT 2 - -/* 4312 chip-specific ChipStatus register bits */ -#define CST4312_SPROM_OTP_SEL_MASK 0x00000003 -#define CST4312_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ -#define CST4312_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ -#define CST4312_OTP_SEL 2 /* OTP is powered up, no SPROM */ -#define CST4312_OTP_BAD 3 /* OTP is broken, SPROM is present */ - -/* 4312 resources (all PMU chips with little memory constraint) */ -#define RES4312_SWITCHER_BURST 0 /* 0x00000001 */ -#define RES4312_SWITCHER_PWM 1 /* 0x00000002 */ -#define RES4312_PA_REF_LDO 2 /* 0x00000004 */ -#define RES4312_CORE_LDO_BURST 3 /* 0x00000008 */ -#define RES4312_CORE_LDO_PWM 4 /* 0x00000010 */ -#define RES4312_RADIO_LDO 5 /* 0x00000020 */ -#define RES4312_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4312_BG_FILTBYP 7 /* 0x00000080 */ -#define RES4312_TX_FILTBYP 8 /* 0x00000100 */ -#define RES4312_RX_FILTBYP 9 /* 0x00000200 */ -#define RES4312_XTAL_PU 10 /* 0x00000400 */ -#define RES4312_ALP_AVAIL 11 /* 0x00000800 */ -#define RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */ -#define RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */ -#define RES4312_HT_AVAIL 14 /* 0x00004000 */ - -/* 4322 resources */ -#define RES4322_RF_LDO 0 -#define RES4322_ILP_REQUEST 1 -#define RES4322_XTAL_PU 2 -#define RES4322_ALP_AVAIL 3 -#define RES4322_SI_PLL_ON 4 -#define RES4322_HT_SI_AVAIL 5 -#define RES4322_PHY_PLL_ON 6 -#define RES4322_HT_PHY_AVAIL 7 -#define RES4322_OTP_PU 8 - -/* 4322 chip-specific ChipStatus register bits */ -#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020 -#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0 -#define CST4322_SPROM_OTP_SEL_SHIFT 6 -#define CST4322_NO_SPROM_OTP 0 /* no OTP, no SPROM */ -#define CST4322_SPROM_PRESENT 1 /* SPROM is present */ -#define CST4322_OTP_PRESENT 2 /* OTP is present */ -#define CST4322_PCI_OR_USB 0x00000100 -#define CST4322_BOOT_MASK 0x00000600 -#define CST4322_BOOT_SHIFT 9 -#define CST4322_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ -#define CST4322_BOOT_FROM_ROM 1 /* boot from ROM */ -#define CST4322_BOOT_FROM_FLASH 2 /* boot from FLASH */ -#define CST4322_BOOT_FROM_INVALID 3 -#define CST4322_ILP_DIV_EN 0x00000800 -#define CST4322_FLASH_TYPE_MASK 0x00001000 -#define CST4322_FLASH_TYPE_SHIFT 12 -#define CST4322_FLASH_TYPE_SHIFT_ST 0 /* ST serial FLASH */ -#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1 /* ATMEL flash */ -#define CST4322_ARM_TAP_SEL 0x00002000 -#define CST4322_RES_INIT_MODE_MASK 0x0000c000 -#define CST4322_RES_INIT_MODE_SHIFT 14 -#define CST4322_RES_INIT_MODE_ILPAVAIL 0 /* resinitmode: ILP available */ -#define CST4322_RES_INIT_MODE_ILPREQ 1 /* resinitmode: ILP request */ -#define CST4322_RES_INIT_MODE_ALPAVAIL 2 /* resinitmode: ALP available */ -#define CST4322_RES_INIT_MODE_HTAVAIL 3 /* resinitmode: HT available */ -#define CST4322_PCIPLLCLK_GATING 0x00010000 -#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 -#define CST4322_PCI_CARDBUS_MODE 0x00040000 - -/* 43224 chip-specific ChipControl register bits */ -#define CCTRL43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */ -#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */ -#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */ - -/* 43236 resources */ -#define RES43236_REGULATOR 0 -#define RES43236_ILP_REQUEST 1 -#define RES43236_XTAL_PU 2 -#define RES43236_ALP_AVAIL 3 -#define RES43236_SI_PLL_ON 4 -#define RES43236_HT_SI_AVAIL 5 - -/* 43236 chip-specific ChipControl register bits */ -#define CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */ -#define CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ -#define CCTRL43236_EXT_LNA (1<<2) /* 0 disable */ -#define CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ -#define CCTRL43236_GSIO (1<<4) /* 0 disable */ - -/* 43236 Chip specific ChipStatus register bits */ -#define CST43236_SFLASH_MASK 0x00000040 -#define CST43236_OTP_SEL_MASK 0x00000080 -#define CST43236_OTP_SEL_SHIFT 7 -#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 - -/* 43237 resources */ -#define RES43237_REGULATOR 0 -#define RES43237_ILP_REQUEST 1 -#define RES43237_XTAL_PU 2 -#define RES43237_ALP_AVAIL 3 -#define RES43237_SI_PLL_ON 4 -#define RES43237_HT_SI_AVAIL 5 - -/* 43237 chip-specific ChipControl register bits */ -#define CCTRL43237_BT_COEXIST (1<<0) /* 0 disable */ -#define CCTRL43237_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ -#define CCTRL43237_EXT_LNA (1<<2) /* 0 disable */ -#define CCTRL43237_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ -#define CCTRL43237_GSIO (1<<4) /* 0 disable */ - -/* 43237 Chip specific ChipStatus register bits */ -#define CST43237_SFLASH_MASK 0x00000040 -#define CST43237_OTP_SEL_MASK 0x00000080 -#define CST43237_OTP_SEL_SHIFT 7 -#define CST43237_HSIC_MASK 0x00000100 /* USB/HSIC */ -#define CST43237_BP_CLK 0x00000200 /* 120/96Mbps */ -#define CST43237_BOOT_MASK 0x00001800 -#define CST43237_BOOT_SHIFT 11 -#define CST43237_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ -#define CST43237_BOOT_FROM_ROM 1 /* boot from ROM */ -#define CST43237_BOOT_FROM_FLASH 2 /* boot from FLASH */ -#define CST43237_BOOT_FROM_INVALID 3 - -/* 43239 resources */ -#define RES43239_OTP_PU 9 -#define RES43239_MACPHY_CLKAVAIL 23 -#define RES43239_HT_AVAIL 24 - -/* 43239 Chip specific ChipStatus register bits */ -#define CST43239_SPROM_MASK 0x00000002 -#define CST43239_SFLASH_MASK 0x00000004 -#define CST43239_RES_INIT_MODE_SHIFT 7 -#define CST43239_RES_INIT_MODE_MASK 0x000001f0 -#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) /* SDIO || gSPI */ -#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15)) /* USB || USBDA */ -#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) /* SDIO */ -#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) /* gSPI */ - -/* 4324 resources */ -/* 43242 use same PMU as 4324 */ -#define RES4324_LPLDO_PU 0 -#define RES4324_RESET_PULLDN_DIS 1 -#define RES4324_PMU_BG_PU 2 -#define RES4324_HSIC_LDO_PU 3 -#define RES4324_CBUCK_LPOM_PU 4 -#define RES4324_CBUCK_PFM_PU 5 -#define RES4324_CLDO_PU 6 -#define RES4324_LPLDO2_LVM 7 -#define RES4324_LNLDO1_PU 8 -#define RES4324_LNLDO2_PU 9 -#define RES4324_LDO3P3_PU 10 -#define RES4324_OTP_PU 11 -#define RES4324_XTAL_PU 12 -#define RES4324_BBPLL_PU 13 -#define RES4324_LQ_AVAIL 14 -#define RES4324_WL_CORE_READY 17 -#define RES4324_ILP_REQ 18 -#define RES4324_ALP_AVAIL 19 -#define RES4324_PALDO_PU 20 -#define RES4324_RADIO_PU 21 -#define RES4324_SR_CLK_STABLE 22 -#define RES4324_SR_SAVE_RESTORE 23 -#define RES4324_SR_PHY_PWRSW 24 -#define RES4324_SR_PHY_PIC 25 -#define RES4324_SR_SUBCORE_PWRSW 26 -#define RES4324_SR_SUBCORE_PIC 27 -#define RES4324_SR_MEM_PM0 28 -#define RES4324_HT_AVAIL 29 -#define RES4324_MACPHY_CLKAVAIL 30 - -/* 4324 Chip specific ChipStatus register bits */ -#define CST4324_SPROM_MASK 0x00000080 -#define CST4324_SFLASH_MASK 0x00400000 -#define CST4324_RES_INIT_MODE_SHIFT 10 -#define CST4324_RES_INIT_MODE_MASK 0x00000c00 -#define CST4324_CHIPMODE_MASK 0x7 -#define CST4324_CHIPMODE_SDIOD(cs) ((~(cs)) & (1 << 2)) /* SDIO || gSPI */ -#define CST4324_CHIPMODE_USB20D(cs) (((cs) & CST4324_CHIPMODE_MASK) == 0x6) /* USB || USBDA */ - -/* 43242 Chip specific ChipStatus register bits */ -#define CST43242_SFLASH_MASK 0x00000008 -#define CST43242_SR_HALT (1<<25) -#define CST43242_SR_CHIP_STATUS_2 27 /* bit 27 */ - -/* 4331 resources */ -#define RES4331_REGULATOR 0 -#define RES4331_ILP_REQUEST 1 -#define RES4331_XTAL_PU 2 -#define RES4331_ALP_AVAIL 3 -#define RES4331_SI_PLL_ON 4 -#define RES4331_HT_SI_AVAIL 5 - -/* 4331 chip-specific ChipControl register bits */ -#define CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */ -#define CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ -#define CCTRL4331_EXT_LNA_G (1<<2) /* 0 disable */ -#define CCTRL4331_SPROM_GPIO13_15 (1<<3) /* sprom/gpio13-15 mux */ -#define CCTRL4331_EXTPA_EN (1<<4) /* 0 ext pa disable, 1 ext pa enabled */ -#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) /* set drive out GPIO_CLK on sprom_cs pin */ -#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) /* use sprom_cs pin as PCIE mdio interface */ -#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) /* aband extpa will be at gpio2/5 and sprom_dout */ -#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) /* override core control on pipe_AuxClkEnable */ -#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) /* override core control on pipe_AuxPowerDown */ -#define CCTRL4331_PCIE_AUXCLKEN (1<<10) /* pcie_auxclkenable */ -#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) /* pcie_pipe_pllpowerdown */ -#define CCTRL4331_EXTPA_EN2 (1<<12) /* 0 ext pa disable, 1 ext pa enabled */ -#define CCTRL4331_EXT_LNA_A (1<<13) /* 0 disable */ -#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */ -#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */ -#define CCTRL4331_EXTPA_ANA_EN (1<<24) /* 0 ext pa disable, 1 ext pa enabled */ - -/* 4331 Chip specific ChipStatus register bits */ -#define CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */ -#define CST4331_SPROM_OTP_SEL_MASK 0x00000006 -#define CST4331_SPROM_OTP_SEL_SHIFT 1 -#define CST4331_SPROM_PRESENT 0x00000002 -#define CST4331_OTP_PRESENT 0x00000004 -#define CST4331_LDO_RF 0x00000008 -#define CST4331_LDO_PAR 0x00000010 - -/* 4315 resource */ -#define RES4315_CBUCK_LPOM 1 /* 0x00000002 */ -#define RES4315_CBUCK_BURST 2 /* 0x00000004 */ -#define RES4315_CBUCK_PWM 3 /* 0x00000008 */ -#define RES4315_CLDO_PU 4 /* 0x00000010 */ -#define RES4315_PALDO_PU 5 /* 0x00000020 */ -#define RES4315_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4315_LNLDO1_PU 9 /* 0x00000200 */ -#define RES4315_OTP_PU 10 /* 0x00000400 */ -#define RES4315_LNLDO2_PU 12 /* 0x00001000 */ -#define RES4315_XTAL_PU 13 /* 0x00002000 */ -#define RES4315_ALP_AVAIL 14 /* 0x00004000 */ -#define RES4315_RX_PWRSW_PU 15 /* 0x00008000 */ -#define RES4315_TX_PWRSW_PU 16 /* 0x00010000 */ -#define RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */ -#define RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */ -#define RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */ -#define RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */ -#define RES4315_HT_AVAIL 21 /* 0x00200000 */ - -/* 4315 chip-specific ChipStatus register bits */ -#define CST4315_SPROM_OTP_SEL_MASK 0x00000003 /* gpio [7:6], SDIO CIS selection */ -#define CST4315_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ -#define CST4315_SPROM_SEL 0x00000001 /* use SPROM, OTP is powered up */ -#define CST4315_OTP_SEL 0x00000002 /* use OTP, OTP is powered up */ -#define CST4315_OTP_PWRDN 0x00000003 /* use SPROM, OTP is powered down */ -#define CST4315_SDIO_MODE 0x00000004 /* gpio [8], sdio/usb mode */ -#define CST4315_RCAL_VALID 0x00000008 -#define CST4315_RCAL_VALUE_MASK 0x000001f0 -#define CST4315_RCAL_VALUE_SHIFT 4 -#define CST4315_PALDO_EXTPNP 0x00000200 /* PALDO is configured with external PNP */ -#define CST4315_CBUCK_MODE_MASK 0x00000c00 -#define CST4315_CBUCK_MODE_BURST 0x00000400 -#define CST4315_CBUCK_MODE_LPBURST 0x00000c00 - -/* 4319 resources */ -#define RES4319_CBUCK_LPOM 1 /* 0x00000002 */ -#define RES4319_CBUCK_BURST 2 /* 0x00000004 */ -#define RES4319_CBUCK_PWM 3 /* 0x00000008 */ -#define RES4319_CLDO_PU 4 /* 0x00000010 */ -#define RES4319_PALDO_PU 5 /* 0x00000020 */ -#define RES4319_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4319_LNLDO1_PU 9 /* 0x00000200 */ -#define RES4319_OTP_PU 10 /* 0x00000400 */ -#define RES4319_LNLDO2_PU 12 /* 0x00001000 */ -#define RES4319_XTAL_PU 13 /* 0x00002000 */ -#define RES4319_ALP_AVAIL 14 /* 0x00004000 */ -#define RES4319_RX_PWRSW_PU 15 /* 0x00008000 */ -#define RES4319_TX_PWRSW_PU 16 /* 0x00010000 */ -#define RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */ -#define RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */ -#define RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */ -#define RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */ -#define RES4319_HT_AVAIL 21 /* 0x00200000 */ - -/* 4319 chip-specific ChipStatus register bits */ -#define CST4319_SPI_CPULESSUSB 0x00000001 -#define CST4319_SPI_CLK_POL 0x00000002 -#define CST4319_SPI_CLK_PH 0x00000008 -#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 /* gpio [7:6], SDIO CIS selection */ -#define CST4319_SPROM_OTP_SEL_SHIFT 6 -#define CST4319_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ -#define CST4319_SPROM_SEL 0x00000040 /* use SPROM, OTP is powered up */ -#define CST4319_OTP_SEL 0x00000080 /* use OTP, OTP is powered up */ -#define CST4319_OTP_PWRDN 0x000000c0 /* use SPROM, OTP is powered down */ -#define CST4319_SDIO_USB_MODE 0x00000100 /* gpio [8], sdio/usb mode */ -#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 -#define CST4319_PALDO_EXTPNP 0x00010000 /* PALDO is configured with external PNP */ -#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 - -#define PMU1_PLL0_CHIPCTL0 0 -#define PMU1_PLL0_CHIPCTL1 1 -#define PMU1_PLL0_CHIPCTL2 2 -#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000 -#define CCTL_4319USB_XTAL_SEL_SHIFT 19 -#define CCTL_4319USB_48MHZ_PLL_SEL 1 -#define CCTL_4319USB_24MHZ_PLL_SEL 2 - -/* PMU resources for 4336 */ -#define RES4336_CBUCK_LPOM 0 -#define RES4336_CBUCK_BURST 1 -#define RES4336_CBUCK_LP_PWM 2 -#define RES4336_CBUCK_PWM 3 -#define RES4336_CLDO_PU 4 -#define RES4336_DIS_INT_RESET_PD 5 -#define RES4336_ILP_REQUEST 6 -#define RES4336_LNLDO_PU 7 -#define RES4336_LDO3P3_PU 8 -#define RES4336_OTP_PU 9 -#define RES4336_XTAL_PU 10 -#define RES4336_ALP_AVAIL 11 -#define RES4336_RADIO_PU 12 -#define RES4336_BG_PU 13 -#define RES4336_VREG1p4_PU_PU 14 -#define RES4336_AFE_PWRSW_PU 15 -#define RES4336_RX_PWRSW_PU 16 -#define RES4336_TX_PWRSW_PU 17 -#define RES4336_BB_PWRSW_PU 18 -#define RES4336_SYNTH_PWRSW_PU 19 -#define RES4336_MISC_PWRSW_PU 20 -#define RES4336_LOGEN_PWRSW_PU 21 -#define RES4336_BBPLL_PWRSW_PU 22 -#define RES4336_MACPHY_CLKAVAIL 23 -#define RES4336_HT_AVAIL 24 -#define RES4336_RSVD 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 - -/* 4336 Chip specific PMU ChipControl register bits */ -#define PCTL_4336_SERIAL_ENAB (1 << 24) - -/* 4330 resources */ -#define RES4330_CBUCK_LPOM 0 -#define RES4330_CBUCK_BURST 1 -#define RES4330_CBUCK_LP_PWM 2 -#define RES4330_CBUCK_PWM 3 -#define RES4330_CLDO_PU 4 -#define RES4330_DIS_INT_RESET_PD 5 -#define RES4330_ILP_REQUEST 6 -#define RES4330_LNLDO_PU 7 -#define RES4330_LDO3P3_PU 8 -#define RES4330_OTP_PU 9 -#define RES4330_XTAL_PU 10 -#define RES4330_ALP_AVAIL 11 -#define RES4330_RADIO_PU 12 -#define RES4330_BG_PU 13 -#define RES4330_VREG1p4_PU_PU 14 -#define RES4330_AFE_PWRSW_PU 15 -#define RES4330_RX_PWRSW_PU 16 -#define RES4330_TX_PWRSW_PU 17 -#define RES4330_BB_PWRSW_PU 18 -#define RES4330_SYNTH_PWRSW_PU 19 -#define RES4330_MISC_PWRSW_PU 20 -#define RES4330_LOGEN_PWRSW_PU 21 -#define RES4330_BBPLL_PWRSW_PU 22 -#define RES4330_MACPHY_CLKAVAIL 23 -#define RES4330_HT_AVAIL 24 -#define RES4330_5gRX_PWRSW_PU 25 -#define RES4330_5gTX_PWRSW_PU 26 -#define RES4330_5g_LOGEN_PWRSW_PU 27 - -/* 4330 chip-specific ChipStatus register bits */ -#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */ -#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */ -#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) /* SDIO */ -#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) /* gSPI */ -#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) /* USB packet-oriented */ -#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) /* USB Direct Access */ -#define CST4330_OTP_PRESENT 0x00000010 -#define CST4330_LPO_AUTODET_EN 0x00000020 -#define CST4330_ARMREMAP_0 0x00000040 -#define CST4330_SPROM_PRESENT 0x00000080 /* takes priority over OTP if both set */ -#define CST4330_ILPDIV_EN 0x00000100 -#define CST4330_LPO_SEL 0x00000200 -#define CST4330_RES_INIT_MODE_SHIFT 10 -#define CST4330_RES_INIT_MODE_MASK 0x00000c00 -#define CST4330_CBUCK_MODE_SHIFT 12 -#define CST4330_CBUCK_MODE_MASK 0x00003000 -#define CST4330_CBUCK_POWER_OK 0x00004000 -#define CST4330_BB_PLL_LOCKED 0x00008000 -#define SOCDEVRAM_BP_ADDR 0x1E000000 -#define SOCDEVRAM_ARM_ADDR 0x00800000 - -/* 4330 Chip specific PMU ChipControl register bits */ -#define PCTL_4330_SERIAL_ENAB (1 << 24) - -/* 4330 Chip specific ChipControl register bits */ -#define CCTRL_4330_GPIO_SEL 0x00000001 /* 1=select GPIOs to be muxed out */ -#define CCTRL_4330_ERCX_SEL 0x00000002 /* 1=select ERCX BT coex to be muxed out */ -#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004 /* SDIO: 1=configure GPIO0 for host wake */ -#define CCTRL_4330_JTAG_DISABLE 0x00000008 /* 1=disable JTAG interface on mux'd pins */ - -#define PMU_VREG0_ADDR 0 -#define PMU_VREG0_DISABLE_PULLD_BT_SHIFT 2 -#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 3 - -#define PMU_VREG4_ADDR 4 - -#define PMU_VREG4_CLDO_PWM_SHIFT 4 -#define PMU_VREG4_CLDO_PWM_MASK 0x7 - -#define PMU_VREG4_LPLDO1_SHIFT 15 -#define PMU_VREG4_LPLDO1_MASK 0x7 -#define PMU_VREG4_LPLDO1_1p20V 0 -#define PMU_VREG4_LPLDO1_1p15V 1 -#define PMU_VREG4_LPLDO1_1p10V 2 -#define PMU_VREG4_LPLDO1_1p25V 3 -#define PMU_VREG4_LPLDO1_1p05V 4 -#define PMU_VREG4_LPLDO1_1p00V 5 -#define PMU_VREG4_LPLDO1_0p95V 6 -#define PMU_VREG4_LPLDO1_0p90V 7 - -/* 4350/4345 VREG4 settings */ -#define PMU4350_VREG4_LPLDO1_1p10V 0 -#define PMU4350_VREG4_LPLDO1_1p15V 1 -#define PMU4350_VREG4_LPLDO1_1p21V 2 -#define PMU4350_VREG4_LPLDO1_1p24V 3 -#define PMU4350_VREG4_LPLDO1_0p90V 4 -#define PMU4350_VREG4_LPLDO1_0p96V 5 -#define PMU4350_VREG4_LPLDO1_1p01V 6 -#define PMU4350_VREG4_LPLDO1_1p04V 7 - -#define PMU_VREG4_LPLDO2_LVM_SHIFT 18 -#define PMU_VREG4_LPLDO2_LVM_MASK 0x7 -#define PMU_VREG4_LPLDO2_HVM_SHIFT 21 -#define PMU_VREG4_LPLDO2_HVM_MASK 0x7 -#define PMU_VREG4_LPLDO2_LVM_HVM_MASK 0x3f -#define PMU_VREG4_LPLDO2_1p00V 0 -#define PMU_VREG4_LPLDO2_1p15V 1 -#define PMU_VREG4_LPLDO2_1p20V 2 -#define PMU_VREG4_LPLDO2_1p10V 3 -#define PMU_VREG4_LPLDO2_0p90V 4 /* 4 - 7 is 0.90V */ - -#define PMU_VREG4_HSICLDO_BYPASS_SHIFT 27 -#define PMU_VREG4_HSICLDO_BYPASS_MASK 0x1 - -#define PMU_VREG5_ADDR 5 -#define PMU_VREG5_HSICAVDD_PD_SHIFT 6 -#define PMU_VREG5_HSICAVDD_PD_MASK 0x1 -#define PMU_VREG5_HSICDVDD_PD_SHIFT 11 -#define PMU_VREG5_HSICDVDD_PD_MASK 0x1 - -/* 4334 resources */ -#define RES4334_LPLDO_PU 0 -#define RES4334_RESET_PULLDN_DIS 1 -#define RES4334_PMU_BG_PU 2 -#define RES4334_HSIC_LDO_PU 3 -#define RES4334_CBUCK_LPOM_PU 4 -#define RES4334_CBUCK_PFM_PU 5 -#define RES4334_CLDO_PU 6 -#define RES4334_LPLDO2_LVM 7 -#define RES4334_LNLDO_PU 8 -#define RES4334_LDO3P3_PU 9 -#define RES4334_OTP_PU 10 -#define RES4334_XTAL_PU 11 -#define RES4334_WL_PWRSW_PU 12 -#define RES4334_LQ_AVAIL 13 -#define RES4334_LOGIC_RET 14 -#define RES4334_MEM_SLEEP 15 -#define RES4334_MACPHY_RET 16 -#define RES4334_WL_CORE_READY 17 -#define RES4334_ILP_REQ 18 -#define RES4334_ALP_AVAIL 19 -#define RES4334_MISC_PWRSW_PU 20 -#define RES4334_SYNTH_PWRSW_PU 21 -#define RES4334_RX_PWRSW_PU 22 -#define RES4334_RADIO_PU 23 -#define RES4334_WL_PMU_PU 24 -#define RES4334_VCO_LDO_PU 25 -#define RES4334_AFE_LDO_PU 26 -#define RES4334_RX_LDO_PU 27 -#define RES4334_TX_LDO_PU 28 -#define RES4334_HT_AVAIL 29 -#define RES4334_MACPHY_CLK_AVAIL 30 - -/* 4334 chip-specific ChipStatus register bits */ -#define CST4334_CHIPMODE_MASK 7 -#define CST4334_SDIO_MODE 0x00000000 -#define CST4334_SPI_MODE 0x00000004 -#define CST4334_HSIC_MODE 0x00000006 -#define CST4334_BLUSB_MODE 0x00000007 -#define CST4334_CHIPMODE_HSIC(cs) (((cs) & CST4334_CHIPMODE_MASK) == CST4334_HSIC_MODE) -#define CST4334_OTP_PRESENT 0x00000010 -#define CST4334_LPO_AUTODET_EN 0x00000020 -#define CST4334_ARMREMAP_0 0x00000040 -#define CST4334_SPROM_PRESENT 0x00000080 -#define CST4334_ILPDIV_EN_MASK 0x00000100 -#define CST4334_ILPDIV_EN_SHIFT 8 -#define CST4334_LPO_SEL_MASK 0x00000200 -#define CST4334_LPO_SEL_SHIFT 9 -#define CST4334_RES_INIT_MODE_MASK 0x00000C00 -#define CST4334_RES_INIT_MODE_SHIFT 10 - -/* 4334 Chip specific PMU ChipControl register bits */ -#define PCTL_4334_GPIO3_ENAB (1 << 3) - -/* 4334 Chip control */ -#define CCTRL4334_PMU_WAKEUP_GPIO1 (1 << 0) -#define CCTRL4334_PMU_WAKEUP_HSIC (1 << 1) -#define CCTRL4334_PMU_WAKEUP_AOS (1 << 2) -#define CCTRL4334_HSIC_WAKE_MODE (1 << 3) -#define CCTRL4334_HSIC_INBAND_GPIO1 (1 << 4) -#define CCTRL4334_HSIC_LDO_PU (1 << 23) - -/* 4334 Chip control 3 */ -#define CCTRL4334_BLOCK_EXTRNL_WAKE (1 << 4) -#define CCTRL4334_SAVERESTORE_FIX (1 << 5) - -/* 43341 Chip control 3 */ -#define CCTRL43341_BLOCK_EXTRNL_WAKE (1 << 13) -#define CCTRL43341_SAVERESTORE_FIX (1 << 14) -#define CCTRL43341_BT_ISO_SEL (1 << 16) - -/* 4334 Chip specific ChipControl1 register bits */ -#define CCTRL1_4334_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ -#define CCTRL1_4334_ERCX_SEL (1 << 1) /* 1=select ERCX BT coex to be muxed out */ -#define CCTRL1_4334_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ -#define CCTRL1_4334_JTAG_DISABLE (1 << 3) /* 1=disable JTAG interface on mux'd pins */ -#define CCTRL1_4334_UART_ON_4_5 (1 << 28) /* 1=UART_TX/UART_RX muxed on GPIO_4/5 (4334B0/1) */ - -/* 4324 Chip specific ChipControl1 register bits */ -#define CCTRL1_4324_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ -#define CCTRL1_4324_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ - -/* 43143 chip-specific ChipStatus register bits based on Confluence documentation */ -/* register contains strap values sampled during POR */ -#define CST43143_REMAP_TO_ROM (3 << 0) /* 00=Boot SRAM, 01=Boot ROM, 10=Boot SFLASH */ -#define CST43143_SDIO_EN (1 << 2) /* 0 = USB Enab, SDIO pins are GPIO or I2S */ -#define CST43143_SDIO_ISO (1 << 3) /* 1 = SDIO isolated */ -#define CST43143_USB_CPU_LESS (1 << 4) /* 1 = CPULess mode Enabled */ -#define CST43143_CBUCK_MODE (3 << 6) /* Indicates what controller mode CBUCK is in */ -#define CST43143_POK_CBUCK (1 << 8) /* 1 = 1.2V CBUCK voltage ready */ -#define CST43143_PMU_OVRSPIKE (1 << 9) -#define CST43143_PMU_OVRTEMP (0xF << 10) -#define CST43143_SR_FLL_CAL_DONE (1 << 14) -#define CST43143_USB_PLL_LOCKDET (1 << 15) -#define CST43143_PMU_PLL_LOCKDET (1 << 16) -#define CST43143_CHIPMODE_SDIOD(cs) (((cs) & CST43143_SDIO_EN) != 0) /* SDIO */ - -/* 43143 Chip specific ChipControl register bits */ -/* 00: SECI is disabled (JATG functional), 01: 2 wire, 10: 4 wire */ -#define CCTRL_43143_SECI (1<<0) -#define CCTRL_43143_BT_LEGACY (1<<1) -#define CCTRL_43143_I2S_MODE (1<<2) /* 0: SDIO enabled */ -#define CCTRL_43143_I2S_MASTER (1<<3) /* 0: I2S MCLK input disabled */ -#define CCTRL_43143_I2S_FULL (1<<4) /* 0: I2S SDIN and SPDIF_TX inputs disabled */ -#define CCTRL_43143_GSIO (1<<5) /* 0: sFlash enabled */ -#define CCTRL_43143_RF_SWCTRL_MASK (7<<6) /* 0: disabled */ -#define CCTRL_43143_RF_SWCTRL_0 (1<<6) -#define CCTRL_43143_RF_SWCTRL_1 (2<<6) -#define CCTRL_43143_RF_SWCTRL_2 (4<<6) -#define CCTRL_43143_RF_XSWCTRL (1<<9) /* 0: UART enabled */ -#define CCTRL_43143_HOST_WAKE0 (1<<11) /* 1: SDIO separate interrupt output from GPIO4 */ -#define CCTRL_43143_HOST_WAKE1 (1<<12) /* 1: SDIO separate interrupt output from GPIO16 */ - -/* 43143 resources, based on pmu_params.xls V1.19 */ -#define RES43143_EXT_SWITCHER_PWM 0 /* 0x00001 */ -#define RES43143_XTAL_PU 1 /* 0x00002 */ -#define RES43143_ILP_REQUEST 2 /* 0x00004 */ -#define RES43143_ALP_AVAIL 3 /* 0x00008 */ -#define RES43143_WL_CORE_READY 4 /* 0x00010 */ -#define RES43143_BBPLL_PWRSW_PU 5 /* 0x00020 */ -#define RES43143_HT_AVAIL 6 /* 0x00040 */ -#define RES43143_RADIO_PU 7 /* 0x00080 */ -#define RES43143_MACPHY_CLK_AVAIL 8 /* 0x00100 */ -#define RES43143_OTP_PU 9 /* 0x00200 */ -#define RES43143_LQ_AVAIL 10 /* 0x00400 */ - -#define PMU43143_XTAL_CORE_SIZE_MASK 0x3F - -/* 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 - -/* 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 */ -#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */ - -/* PMU respources for 4314 */ -#define RES4314_LPLDO_PU 0 -#define RES4314_PMU_SLEEP_DIS 1 -#define RES4314_PMU_BG_PU 2 -#define RES4314_CBUCK_LPOM_PU 3 -#define RES4314_CBUCK_PFM_PU 4 -#define RES4314_CLDO_PU 5 -#define RES4314_LPLDO2_LVM 6 -#define RES4314_WL_PMU_PU 7 -#define RES4314_LNLDO_PU 8 -#define RES4314_LDO3P3_PU 9 -#define RES4314_OTP_PU 10 -#define RES4314_XTAL_PU 11 -#define RES4314_WL_PWRSW_PU 12 -#define RES4314_LQ_AVAIL 13 -#define RES4314_LOGIC_RET 14 -#define RES4314_MEM_SLEEP 15 -#define RES4314_MACPHY_RET 16 -#define RES4314_WL_CORE_READY 17 -#define RES4314_ILP_REQ 18 -#define RES4314_ALP_AVAIL 19 -#define RES4314_MISC_PWRSW_PU 20 -#define RES4314_SYNTH_PWRSW_PU 21 -#define RES4314_RX_PWRSW_PU 22 -#define RES4314_RADIO_PU 23 -#define RES4314_VCO_LDO_PU 24 -#define RES4314_AFE_LDO_PU 25 -#define RES4314_RX_LDO_PU 26 -#define RES4314_TX_LDO_PU 27 -#define RES4314_HT_AVAIL 28 -#define RES4314_MACPHY_CLK_AVAIL 29 - -/* 4314 chip-specific ChipStatus register bits */ -#define CST4314_OTP_ENABLED 0x00200000 - -/* 43228 resources */ -#define RES43228_NOT_USED 0 -#define RES43228_ILP_REQUEST 1 -#define RES43228_XTAL_PU 2 -#define RES43228_ALP_AVAIL 3 -#define RES43228_PLL_EN 4 -#define RES43228_HT_PHY_AVAIL 5 - -/* 43228 chipstatus reg bits */ -#define CST43228_ILP_DIV_EN 0x1 -#define CST43228_OTP_PRESENT 0x2 -#define CST43228_SERDES_REFCLK_PADSEL 0x4 -#define CST43228_SDIO_MODE 0x8 -#define CST43228_SDIO_OTP_PRESENT 0x10 -#define CST43228_SDIO_RESET 0x20 - -/* 4706 chipstatus reg bits */ -#define CST4706_PKG_OPTION (1<<0) /* 0: full-featured package 1: low-cost package */ -#define CST4706_SFLASH_PRESENT (1<<1) /* 0: parallel, 1: serial flash is present */ -#define CST4706_SFLASH_TYPE (1<<2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */ -#define CST4706_MIPS_BENDIAN (1<<3) /* 0: little, 1: big endian */ -#define CST4706_PCIE1_DISABLE (1<<5) /* PCIE1 enable strap pin */ - -/* 4706 flashstrconfig reg bits */ -#define FLSTRCF4706_MASK 0x000000ff -#define FLSTRCF4706_SF1 0x00000001 /* 2nd serial flash present */ -#define FLSTRCF4706_PF1 0x00000002 /* 2nd parallel flash present */ -#define FLSTRCF4706_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */ -#define FLSTRCF4706_NF1 0x00000008 /* 2nd NAND flash present */ -#define FLSTRCF4706_1ST_MADDR_SEG_MASK 0x000000f0 /* Valid value mask */ -#define FLSTRCF4706_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */ - -/* 4360 Chip specific ChipControl register bits */ -#define CCTRL4360_I2C_MODE (1 << 0) -#define CCTRL4360_UART_MODE (1 << 1) -#define CCTRL4360_SECI_MODE (1 << 2) -#define CCTRL4360_BTSWCTRL_MODE (1 << 3) -#define CCTRL4360_DISCRETE_FEMCTRL_MODE (1 << 4) -#define CCTRL4360_DIGITAL_PACTRL_MODE (1 << 5) -#define CCTRL4360_BTSWCTRL_AND_DIGPA_PRESENT (1 << 6) -#define CCTRL4360_EXTRA_GPIO_MODE (1 << 7) -#define CCTRL4360_EXTRA_FEMCTRL_MODE (1 << 8) -#define CCTRL4360_BT_LGCY_MODE (1 << 9) -#define CCTRL4360_CORE2FEMCTRL4_ON (1 << 21) -#define CCTRL4360_SECI_ON_GPIO01 (1 << 24) - -/* 4360 Chip specific Regulator Control register bits */ -#define RCTRL4360_RFLDO_PWR_DOWN (1 << 1) - -/* 4360 PMU resources and chip status bits */ -#define RES4360_REGULATOR 0 -#define RES4360_ILP_AVAIL 1 -#define RES4360_ILP_REQ 2 -#define RES4360_XTAL_LDO_PU 3 -#define RES4360_XTAL_PU 4 -#define RES4360_ALP_AVAIL 5 -#define RES4360_BBPLLPWRSW_PU 6 -#define RES4360_HT_AVAIL 7 -#define RES4360_OTP_PU 8 - -#define CST4360_XTAL_40MZ 0x00000001 -#define CST4360_SFLASH 0x00000002 -#define CST4360_SPROM_PRESENT 0x00000004 -#define CST4360_SFLASH_TYPE 0x00000004 -#define CST4360_OTP_ENABLED 0x00000008 -#define CST4360_REMAP_ROM 0x00000010 -#define CST4360_RSRC_INIT_MODE_MASK 0x00000060 -#define CST4360_RSRC_INIT_MODE_SHIFT 5 -#define CST4360_ILP_DIVEN 0x00000080 -#define CST4360_MODE_USB 0x00000100 -#define CST4360_SPROM_SIZE_MASK 0x00000600 -#define CST4360_SPROM_SIZE_SHIFT 9 -#define CST4360_BBPLL_LOCK 0x00000800 -#define CST4360_AVBBPLL_LOCK 0x00001000 -#define CST4360_USBBBPLL_LOCK 0x00002000 -#define CST4360_RSRC_INIT_MODE(cs) ((cs & CST4360_RSRC_INIT_MODE_MASK) >> \ - CST4360_RSRC_INIT_MODE_SHIFT) - -#define CCTRL_4360_UART_SEL 0x2 -#define CST4360_RSRC_INIT_MODE(cs) ((cs & CST4360_RSRC_INIT_MODE_MASK) >> \ - CST4360_RSRC_INIT_MODE_SHIFT) - - -/* 43602 PMU resources based on pmu_params.xls version v0.95 */ -#define RES43602_LPLDO_PU 0 -#define RES43602_REGULATOR 1 -#define RES43602_PMU_SLEEP 2 -#define RES43602_RSVD_3 3 -#define RES43602_XTALLDO_PU 4 -#define RES43602_SERDES_PU 5 -#define RES43602_BBPLL_PWRSW_PU 6 -#define RES43602_SR_CLK_START 7 -#define RES43602_SR_PHY_PWRSW 8 -#define RES43602_SR_SUBCORE_PWRSW 9 -#define RES43602_XTAL_PU 10 -#define RES43602_PERST_OVR 11 -#define RES43602_SR_CLK_STABLE 12 -#define RES43602_SR_SAVE_RESTORE 13 -#define RES43602_SR_SLEEP 14 -#define RES43602_LQ_START 15 -#define RES43602_LQ_AVAIL 16 -#define RES43602_WL_CORE_RDY 17 -#define RES43602_ILP_REQ 18 -#define RES43602_ALP_AVAIL 19 -#define RES43602_RADIO_PU 20 -#define RES43602_RFLDO_PU 21 -#define RES43602_HT_START 22 -#define RES43602_HT_AVAIL 23 -#define RES43602_MACPHY_CLKAVAIL 24 -#define RES43602_PARLDO_PU 25 -#define RES43602_RSVD_26 26 - -/* 43602 chip status bits */ -#define CST43602_SPROM_PRESENT (1<<1) -#define CST43602_SPROM_SIZE (1<<10) /* 0 = 16K, 1 = 4K */ -#define CST43602_BBPLL_LOCK (1<<11) -#define CST43602_RF_LDO_OUT_OK (1<<15) /* RF LDO output OK */ - -#define PMU43602_CC1_GPIO12_OVRD (1<<28) /* GPIO12 override */ - -#define PMU43602_CC2_PCIE_CLKREQ_L_WAKE_EN (1<<1) /* creates gated_pcie_wake, pmu_wakeup logic */ -#define PMU43602_CC2_PCIE_PERST_L_WAKE_EN (1<<2) /* creates gated_pcie_wake, pmu_wakeup logic */ -#define PMU43602_CC2_ENABLE_L2REFCLKPAD_PWRDWN (1<<3) -#define PMU43602_CC2_PMU_WAKE_ALP_AVAIL_EN (1<<5) /* enable pmu_wakeup to request for ALP_AVAIL */ -#define PMU43602_CC2_PERST_L_EXTEND_EN (1<<9) /* extend perst_l until rsc PERST_OVR comes up */ -#define PMU43602_CC2_FORCE_EXT_LPO (1<<19) /* 1=ext LPO clock is the final LPO clock */ -#define PMU43602_CC2_XTAL32_SEL (1<<30) /* 0=ext_clock, 1=xtal */ - -#define CC_SR1_43602_SR_ASM_ADDR (0x0) - -/* PLL CTL register values for open loop, used during S/R operation */ -#define PMU43602_PLL_CTL6_VAL 0x68000528 -#define PMU43602_PLL_CTL7_VAL 0x6 - -#define PMU43602_CC3_ARMCR4_DBG_CLK (1 << 29) - -/* 4349 related */ -#define RES4349_LPLDO_PU 0 -#define RES4349_BG_PU 1 -#define RES4349_PMU_SLEEP 2 -#define RES4349_PALDO3P3_PU 3 -#define RES4349_CBUCK_LPOM_PU 4 -#define RES4349_CBUCK_PFM_PU 5 -#define RES4349_COLD_START_WAIT 6 -#define RES4349_RSVD_7 7 -#define RES4349_LNLDO_PU 8 -#define RES4349_XTALLDO_PU 9 -#define RES4349_LDO3P3_PU 10 -#define RES4349_OTP_PU 11 -#define RES4349_XTAL_PU 12 -#define RES4349_SR_CLK_START 13 -#define RES4349_LQ_AVAIL 14 -#define RES4349_LQ_START 15 -#define RES4349_PERST_OVR 16 -#define RES4349_WL_CORE_RDY 17 -#define RES4349_ILP_REQ 18 -#define RES4349_ALP_AVAIL 19 -#define RES4349_MINI_PMU 20 -#define RES4349_RADIO_PU 21 -#define RES4349_SR_CLK_STABLE 22 -#define RES4349_SR_SAVE_RESTORE 23 -#define RES4349_SR_PHY_PWRSW 24 -#define RES4349_SR_VDDM_PWRSW 25 -#define RES4349_SR_SUBCORE_PWRSW 26 -#define RES4349_SR_SLEEP 27 -#define RES4349_HT_START 28 -#define RES4349_HT_AVAIL 29 -#define RES4349_MACPHY_CLKAVAIL 30 - -#define CR4_4349_RAM_BASE (0x180000) -#define CC4_4349_SR_ASM_ADDR (0x48) - -#define CST4349_CHIPMODE_SDIOD(cs) (((cs) & (1 << 6)) != 0) /* SDIO */ -#define CST4349_CHIPMODE_PCIE(cs) (((cs) & (1 << 7)) != 0) /* PCIE */ - -#define CST4349_SPROM_PRESENT 0x00000010 - - -/* 43430 PMU resources based on pmu_params.xls */ -#define RES43430_LPLDO_PU 0 -#define RES43430_BG_PU 1 -#define RES43430_PMU_SLEEP 2 -#define RES43430_RSVD_3 3 -#define RES43430_CBUCK_LPOM_PU 4 -#define RES43430_CBUCK_PFM_PU 5 -#define RES43430_COLD_START_WAIT 6 -#define RES43430_RSVD_7 7 -#define RES43430_LNLDO_PU 8 -#define RES43430_RSVD_9 9 -#define RES43430_LDO3P3_PU 10 -#define RES43430_OTP_PU 11 -#define RES43430_XTAL_PU 12 -#define RES43430_SR_CLK_START 13 -#define RES43430_LQ_AVAIL 14 -#define RES43430_LQ_START 15 -#define RES43430_RSVD_16 16 -#define RES43430_WL_CORE_RDY 17 -#define RES43430_ILP_REQ 18 -#define RES43430_ALP_AVAIL 19 -#define RES43430_MINI_PMU 20 -#define RES43430_RADIO_PU 21 -#define RES43430_SR_CLK_STABLE 22 -#define RES43430_SR_SAVE_RESTORE 23 -#define RES43430_SR_PHY_PWRSW 24 -#define RES43430_SR_VDDM_PWRSW 25 -#define RES43430_SR_SUBCORE_PWRSW 26 -#define RES43430_SR_SLEEP 27 -#define RES43430_HT_START 28 -#define RES43430_HT_AVAIL 29 -#define RES43430_MACPHY_CLK_AVAIL 30 - -/* 43430 chip status bits */ -#define CST43430_SDIO_MODE 0x00000001 -#define CST43430_GSPI_MODE 0x00000002 -#define CST43430_RSRC_INIT_MODE_0 0x00000080 -#define CST43430_RSRC_INIT_MODE_1 0x00000100 -#define CST43430_SEL0_SDIO 0x00000200 -#define CST43430_SEL1_SDIO 0x00000400 -#define CST43430_SEL2_SDIO 0x00000800 -#define CST43430_BBPLL_LOCKED 0x00001000 -#define CST43430_DBG_INST_DETECT 0x00004000 -#define CST43430_CLB2WL_BT_READY 0x00020000 -#define CST43430_JTAG_MODE 0x00100000 -#define CST43430_HOST_IFACE 0x00400000 -#define CST43430_TRIM_EN 0x00800000 -#define CST43430_DIN_PACKAGE_OPTION 0x10000000 - -/* defines to detect active host interface in use */ -#define CHIP_HOSTIF_PCIEMODE 0x1 -#define CHIP_HOSTIF_USBMODE 0x2 -#define CHIP_HOSTIF_SDIOMODE 0x4 -#define CHIP_HOSTIF_PCIE(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_PCIEMODE) -#define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_USBMODE) -#define CHIP_HOSTIF_SDIO(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_SDIOMODE) - -/* 4335 resources */ -#define RES4335_LPLDO_PO 0 -#define RES4335_PMU_BG_PU 1 -#define RES4335_PMU_SLEEP 2 -#define RES4335_RSVD_3 3 -#define RES4335_CBUCK_LPOM_PU 4 -#define RES4335_CBUCK_PFM_PU 5 -#define RES4335_RSVD_6 6 -#define RES4335_RSVD_7 7 -#define RES4335_LNLDO_PU 8 -#define RES4335_XTALLDO_PU 9 -#define RES4335_LDO3P3_PU 10 -#define RES4335_OTP_PU 11 -#define RES4335_XTAL_PU 12 -#define RES4335_SR_CLK_START 13 -#define RES4335_LQ_AVAIL 14 -#define RES4335_LQ_START 15 -#define RES4335_RSVD_16 16 -#define RES4335_WL_CORE_RDY 17 -#define RES4335_ILP_REQ 18 -#define RES4335_ALP_AVAIL 19 -#define RES4335_MINI_PMU 20 -#define RES4335_RADIO_PU 21 -#define RES4335_SR_CLK_STABLE 22 -#define RES4335_SR_SAVE_RESTORE 23 -#define RES4335_SR_PHY_PWRSW 24 -#define RES4335_SR_VDDM_PWRSW 25 -#define RES4335_SR_SUBCORE_PWRSW 26 -#define RES4335_SR_SLEEP 27 -#define RES4335_HT_START 28 -#define RES4335_HT_AVAIL 29 -#define RES4335_MACPHY_CLKAVAIL 30 - -/* 4335 Chip specific ChipStatus register bits */ -#define CST4335_SPROM_MASK 0x00000020 -#define CST4335_SFLASH_MASK 0x00000040 -#define CST4335_RES_INIT_MODE_SHIFT 7 -#define CST4335_RES_INIT_MODE_MASK 0x00000180 -#define CST4335_CHIPMODE_MASK 0xF -#define CST4335_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ -#define CST4335_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ -#define CST4335_CHIPMODE_USB20D(cs) (((cs) & (1 << 2)) != 0) /* HSIC || USBDA */ -#define CST4335_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ - -/* 4335 Chip specific ChipControl1 register bits */ -#define CCTRL1_4335_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ -#define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ - -/* 4335 Chip specific ChipControl2 register bits */ -#define CCTRL2_4335_AOSBLOCK (1 << 30) -#define CCTRL2_4335_PMUWAKE (1 << 31) -#define PATCHTBL_SIZE (0x800) -#define CR4_4335_RAM_BASE (0x180000) -#define CR4_4345_RAM_BASE (0x1b0000) -#define CR4_4349_RAM_BASE (0x180000) -#define CR4_4350_RAM_BASE (0x180000) -#define CR4_4360_RAM_BASE (0x0) -#define CR4_43602_RAM_BASE (0x180000) - -/* 4335 chip OTP present & OTP select bits. */ -#define SPROM4335_OTP_SELECT 0x00000010 -#define SPROM4335_OTP_PRESENT 0x00000020 - -/* 4335 GCI specific bits. */ -#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) -#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 -#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 - -/* SFLASH clkdev specific bits. */ -#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 -#define CC4335_SFLASH_CLKDIV_SHIFT 25 - -/* 4335 OTP bits for SFLASH. */ -#define CC4335_SROM_OTP_SFLASH 40 -#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 -#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 -#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C -#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 - - -/* 4335 chip OTP present & OTP select bits. */ -#define SPROM4335_OTP_SELECT 0x00000010 -#define SPROM4335_OTP_PRESENT 0x00000020 - -/* 4335 GCI specific bits. */ -#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) -#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 -#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 - -/* SFLASH clkdev specific bits. */ -#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 -#define CC4335_SFLASH_CLKDIV_SHIFT 25 - -/* 4335 OTP bits for SFLASH. */ -#define CC4335_SROM_OTP_SFLASH 40 -#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 -#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 -#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C -#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 - -/* 4335 resources--END */ - -/* 4345 Chip specific ChipStatus register bits */ -#define CST4345_SPROM_MASK 0x00000020 -#define CST4345_SFLASH_MASK 0x00000040 -#define CST4345_RES_INIT_MODE_SHIFT 7 -#define CST4345_RES_INIT_MODE_MASK 0x00000180 -#define CST4345_CHIPMODE_MASK 0x4000F -#define CST4345_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ -#define CST4345_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ -#define CST4345_CHIPMODE_HSIC(cs) (((cs) & (1 << 2)) != 0) /* HSIC */ -#define CST4345_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ -#define CST4345_CHIPMODE_USB20D(cs) (((cs) & (1 << 18)) != 0) /* USBDA */ - -/* 4350 Chipcommon ChipStatus bits */ -#define CST4350_SDIO_MODE 0x00000001 -#define CST4350_HSIC20D_MODE 0x00000002 -#define CST4350_BP_ON_HSIC_CLK 0x00000004 -#define CST4350_PCIE_MODE 0x00000008 -#define CST4350_USB20D_MODE 0x00000010 -#define CST4350_USB30D_MODE 0x00000020 -#define CST4350_SPROM_PRESENT 0x00000040 -#define CST4350_RSRC_INIT_MODE_0 0x00000080 -#define CST4350_RSRC_INIT_MODE_1 0x00000100 -#define CST4350_SEL0_SDIO 0x00000200 -#define CST4350_SEL1_SDIO 0x00000400 -#define CST4350_SDIO_PAD_MODE 0x00000800 -#define CST4350_BBPLL_LOCKED 0x00001000 -#define CST4350_USBPLL_LOCKED 0x00002000 -#define CST4350_LINE_STATE 0x0000C000 -#define CST4350_SERDES_PIPE_PLLLOCK 0x00010000 -#define CST4350_BT_READY 0x00020000 -#define CST4350_SFLASH_PRESENT 0x00040000 -#define CST4350_CPULESS_ENABLE 0x00080000 -#define CST4350_STRAP_HOST_IFC_1 0x00100000 -#define CST4350_STRAP_HOST_IFC_2 0x00200000 -#define CST4350_STRAP_HOST_IFC_3 0x00400000 -#define CST4350_RAW_SPROM_PRESENT 0x00800000 -#define CST4350_APP_CLK_SWITCH_SEL_RDBACK 0x01000000 -#define CST4350_RAW_RSRC_INIT_MODE_0 0x02000000 -#define CST4350_SDIO_PAD_VDDIO 0x04000000 -#define CST4350_GSPI_MODE 0x08000000 -#define CST4350_PACKAGE_OPTION 0xF0000000 -#define CST4350_PACKAGE_SHIFT 28 - -/* package option for 4350 */ -#define CST4350_PACKAGE_WLCSP 0x0 -#define CST4350_PACKAGE_PCIE 0x1 -#define CST4350_PACKAGE_WLBGA 0x2 -#define CST4350_PACKAGE_DBG 0x3 -#define CST4350_PACKAGE_USB 0x4 -#define CST4350_PACKAGE_USB_HSIC 0x4 - -#define CST4350_PKG_MODE(cs) ((cs & CST4350_PACKAGE_OPTION) >> CST4350_PACKAGE_SHIFT) - -#define CST4350_PKG_WLCSP(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLCSP)) -#define CST4350_PKG_PCIE(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_PCIE)) -#define CST4350_PKG_WLBGA(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLBGA)) -#define CST4350_PKG_USB(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB)) -#define CST4350_PKG_USB_HSIC(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB_HSIC)) - -/* 4350C0 USB PACKAGE using raw_sprom_present to indicate 40mHz xtal */ -#define CST4350_PKG_USB_40M(cs) (cs & CST4350_RAW_SPROM_PRESENT) - -#define CST4350_CHIPMODE_SDIOD(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_SDIOD)) -#define CST4350_CHIPMODE_USB20D(cs) ((CST4350_IFC_MODE(cs)) == (CST4350_IFC_MODE_USB20D)) -#define CST4350_CHIPMODE_HSIC20D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC20D)) -#define CST4350_CHIPMODE_HSIC30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC30D)) -#define CST4350_CHIPMODE_USB30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D)) -#define CST4350_CHIPMODE_USB30D_WL(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D_WL)) -#define CST4350_CHIPMODE_PCIE(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_PCIE)) - -/* strap_host_ifc strap value */ -#define CST4350_HOST_IFC_MASK 0x00700000 -#define CST4350_HOST_IFC_SHIFT 20 - -/* host_ifc raw mode */ -#define CST4350_IFC_MODE_SDIOD 0x0 -#define CST4350_IFC_MODE_HSIC20D 0x1 -#define CST4350_IFC_MODE_HSIC30D 0x2 -#define CST4350_IFC_MODE_PCIE 0x3 -#define CST4350_IFC_MODE_USB20D 0x4 -#define CST4350_IFC_MODE_USB30D 0x5 -#define CST4350_IFC_MODE_USB30D_WL 0x6 -#define CST4350_IFC_MODE_USB30D_BT 0x7 - -#define CST4350_IFC_MODE(cs) ((cs & CST4350_HOST_IFC_MASK) >> CST4350_HOST_IFC_SHIFT) - -/* 4350 PMU resources */ -#define RES4350_LPLDO_PU 0 -#define RES4350_PMU_BG_PU 1 -#define RES4350_PMU_SLEEP 2 -#define RES4350_RSVD_3 3 -#define RES4350_CBUCK_LPOM_PU 4 -#define RES4350_CBUCK_PFM_PU 5 -#define RES4350_COLD_START_WAIT 6 -#define RES4350_RSVD_7 7 -#define RES4350_LNLDO_PU 8 -#define RES4350_XTALLDO_PU 9 -#define RES4350_LDO3P3_PU 10 -#define RES4350_OTP_PU 11 -#define RES4350_XTAL_PU 12 -#define RES4350_SR_CLK_START 13 -#define RES4350_LQ_AVAIL 14 -#define RES4350_LQ_START 15 -#define RES4350_PERST_OVR 16 -#define RES4350_WL_CORE_RDY 17 -#define RES4350_ILP_REQ 18 -#define RES4350_ALP_AVAIL 19 -#define RES4350_MINI_PMU 20 -#define RES4350_RADIO_PU 21 -#define RES4350_SR_CLK_STABLE 22 -#define RES4350_SR_SAVE_RESTORE 23 -#define RES4350_SR_PHY_PWRSW 24 -#define RES4350_SR_VDDM_PWRSW 25 -#define RES4350_SR_SUBCORE_PWRSW 26 -#define RES4350_SR_SLEEP 27 -#define RES4350_HT_START 28 -#define RES4350_HT_AVAIL 29 -#define RES4350_MACPHY_CLKAVAIL 30 - -#define MUXENAB4350_UART_MASK (0x0000000f) -#define MUXENAB4350_UART_SHIFT 0 -#define MUXENAB4350_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ -#define MUXENAB4350_HOSTWAKE_SHIFT 4 - - -/* 4350 GCI function sel values */ -#define CC4350_FNSEL_HWDEF (0) -#define CC4350_FNSEL_SAMEASPIN (1) -#define CC4350_FNSEL_UART (2) -#define CC4350_FNSEL_SFLASH (3) -#define CC4350_FNSEL_SPROM (4) -#define CC4350_FNSEL_I2C (5) -#define CC4350_FNSEL_MISC0 (6) -#define CC4350_FNSEL_GCI (7) -#define CC4350_FNSEL_MISC1 (8) -#define CC4350_FNSEL_MISC2 (9) -#define CC4350_FNSEL_PWDOG (10) -#define CC4350_FNSEL_IND (12) -#define CC4350_FNSEL_PDN (13) -#define CC4350_FNSEL_PUP (14) -#define CC4350_FNSEL_TRISTATE (15) -#define CC4350C_FNSEL_UART (3) - - -/* 4350 GPIO */ -#define CC4350_PIN_GPIO_00 (0) -#define CC4350_PIN_GPIO_01 (1) -#define CC4350_PIN_GPIO_02 (2) -#define CC4350_PIN_GPIO_03 (3) -#define CC4350_PIN_GPIO_04 (4) -#define CC4350_PIN_GPIO_05 (5) -#define CC4350_PIN_GPIO_06 (6) -#define CC4350_PIN_GPIO_07 (7) -#define CC4350_PIN_GPIO_08 (8) -#define CC4350_PIN_GPIO_09 (9) -#define CC4350_PIN_GPIO_10 (10) -#define CC4350_PIN_GPIO_11 (11) -#define CC4350_PIN_GPIO_12 (12) -#define CC4350_PIN_GPIO_13 (13) -#define CC4350_PIN_GPIO_14 (14) -#define CC4350_PIN_GPIO_15 (15) - -#define CC4350_RSVD_16_SHIFT 16 - -#define CC2_4350_PHY_PWRSW_UPTIME_MASK (0xf << 0) -#define CC2_4350_PHY_PWRSW_UPTIME_SHIFT (0) -#define CC2_4350_VDDM_PWRSW_UPDELAY_MASK (0xf << 4) -#define CC2_4350_VDDM_PWRSW_UPDELAY_SHIFT (4) -#define CC2_4350_VDDM_PWRSW_UPTIME_MASK (0xf << 8) -#define CC2_4350_VDDM_PWRSW_UPTIME_SHIFT (8) -#define CC2_4350_SBC_PWRSW_DNDELAY_MASK (0x3 << 12) -#define CC2_4350_SBC_PWRSW_DNDELAY_SHIFT (12) -#define CC2_4350_PHY_PWRSW_DNDELAY_MASK (0x3 << 14) -#define CC2_4350_PHY_PWRSW_DNDELAY_SHIFT (14) -#define CC2_4350_VDDM_PWRSW_DNDELAY_MASK (0x3 << 16) -#define CC2_4350_VDDM_PWRSW_DNDELAY_SHIFT (16) -#define CC2_4350_VDDM_PWRSW_EN_MASK (1 << 20) -#define CC2_4350_VDDM_PWRSW_EN_SHIFT (20) -#define CC2_4350_MEMLPLDO_PWRSW_EN_MASK (1 << 21) -#define CC2_4350_MEMLPLDO_PWRSW_EN_SHIFT (21) -#define CC2_4350_SDIO_AOS_WAKEUP_MASK (1 << 24) -#define CC2_4350_SDIO_AOS_WAKEUP_SHIFT (24) - -/* Applies to 4335/4350/4345 */ -#define CC3_SR_CLK_SR_MEM_MASK (1 << 0) -#define CC3_SR_CLK_SR_MEM_SHIFT (0) -#define CC3_SR_BIT1_TBD_MASK (1 << 1) -#define CC3_SR_BIT1_TBD_SHIFT (1) -#define CC3_SR_ENGINE_ENABLE_MASK (1 << 2) -#define CC3_SR_ENGINE_ENABLE_SHIFT (2) -#define CC3_SR_BIT3_TBD_MASK (1 << 3) -#define CC3_SR_BIT3_TBD_SHIFT (3) -#define CC3_SR_MINDIV_FAST_CLK_MASK (0xF << 4) -#define CC3_SR_MINDIV_FAST_CLK_SHIFT (4) -#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_MASK (1 << 8) -#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_SHIFT (8) -#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_MASK (1 << 9) -#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_SHIFT (9) -#define CC3_SR_R23_SR_RISE_EDGE_TRIG_MASK (1 << 10) -#define CC3_SR_R23_SR_RISE_EDGE_TRIG_SHIFT (10) -#define CC3_SR_R23_SR_FALL_EDGE_TRIG_MASK (1 << 11) -#define CC3_SR_R23_SR_FALL_EDGE_TRIG_SHIFT (11) -#define CC3_SR_NUM_CLK_HIGH_MASK (0x7 << 12) -#define CC3_SR_NUM_CLK_HIGH_SHIFT (12) -#define CC3_SR_BIT15_TBD_MASK (1 << 15) -#define CC3_SR_BIT15_TBD_SHIFT (15) -#define CC3_SR_PHY_FUNC_PIC_MASK (1 << 16) -#define CC3_SR_PHY_FUNC_PIC_SHIFT (16) -#define CC3_SR_BIT17_19_TBD_MASK (0x7 << 17) -#define CC3_SR_BIT17_19_TBD_SHIFT (17) -#define CC3_SR_CHIP_TRIGGER_1_MASK (1 << 20) -#define CC3_SR_CHIP_TRIGGER_1_SHIFT (20) -#define CC3_SR_CHIP_TRIGGER_2_MASK (1 << 21) -#define CC3_SR_CHIP_TRIGGER_2_SHIFT (21) -#define CC3_SR_CHIP_TRIGGER_3_MASK (1 << 22) -#define CC3_SR_CHIP_TRIGGER_3_SHIFT (22) -#define CC3_SR_CHIP_TRIGGER_4_MASK (1 << 23) -#define CC3_SR_CHIP_TRIGGER_4_SHIFT (23) -#define CC3_SR_ALLOW_SBC_FUNC_PIC_MASK (1 << 24) -#define CC3_SR_ALLOW_SBC_FUNC_PIC_SHIFT (24) -#define CC3_SR_BIT25_26_TBD_MASK (0x3 << 25) -#define CC3_SR_BIT25_26_TBD_SHIFT (25) -#define CC3_SR_ALLOW_SBC_STBY_MASK (1 << 27) -#define CC3_SR_ALLOW_SBC_STBY_SHIFT (27) -#define CC3_SR_GPIO_MUX_MASK (0xF << 28) -#define CC3_SR_GPIO_MUX_SHIFT (28) - -/* Applies to 4335/4350/4345 */ -#define CC4_SR_INIT_ADDR_MASK (0x3FF0000) -#define CC4_4350_SR_ASM_ADDR (0x30) -#define CC4_4350_C0_SR_ASM_ADDR (0x0) -#define CC4_4335_SR_ASM_ADDR (0x48) -#define CC4_4345_SR_ASM_ADDR (0x48) -#define CC4_SR_INIT_ADDR_SHIFT (16) - -#define CC4_4350_EN_SR_CLK_ALP_MASK (1 << 30) -#define CC4_4350_EN_SR_CLK_ALP_SHIFT (30) -#define CC4_4350_EN_SR_CLK_HT_MASK (1 << 31) -#define CC4_4350_EN_SR_CLK_HT_SHIFT (31) - -#define VREG4_4350_MEMLPDO_PU_MASK (1 << 31) -#define VREG4_4350_MEMLPDO_PU_SHIFT 31 - -#define VREG6_4350_SR_EXT_CLKDIR_MASK (1 << 20) -#define VREG6_4350_SR_EXT_CLKDIR_SHIFT 20 -#define VREG6_4350_SR_EXT_CLKDIV_MASK (0x3 << 21) -#define VREG6_4350_SR_EXT_CLKDIV_SHIFT 21 -#define VREG6_4350_SR_EXT_CLKEN_MASK (1 << 23) -#define VREG6_4350_SR_EXT_CLKEN_SHIFT 23 - -#define CC5_4350_PMU_EN_ASSERT_MASK (1 << 13) -#define CC5_4350_PMU_EN_ASSERT_SHIFT (13) - -#define CC6_4350_PCIE_CLKREQ_WAKEUP_MASK (1 << 4) -#define CC6_4350_PCIE_CLKREQ_WAKEUP_SHIFT (4) -#define CC6_4350_PMU_WAKEUP_ALPAVAIL_MASK (1 << 6) -#define CC6_4350_PMU_WAKEUP_ALPAVAIL_SHIFT (6) -#define CC6_4350_PMU_EN_EXT_PERST_MASK (1 << 17) -#define CC6_4350_PMU_EN_EXT_PERST_SHIFT (17) -#define CC6_4350_PMU_EN_WAKEUP_MASK (1 << 18) -#define CC6_4350_PMU_EN_WAKEUP_SHIFT (18) - -#define CC7_4350_PMU_EN_ASSERT_L2_MASK (1 << 26) -#define CC7_4350_PMU_EN_ASSERT_L2_SHIFT (26) -#define CC7_4350_PMU_EN_MDIO_MASK (1 << 27) -#define CC7_4350_PMU_EN_MDIO_SHIFT (27) - -#define CC6_4345_PMU_EN_PERST_DEASSERT_MASK (1 << 13) -#define CC6_4345_PMU_EN_PERST_DEASSERT_SHIF (13) -#define CC6_4345_PMU_EN_L2_DEASSERT_MASK (1 << 14) -#define CC6_4345_PMU_EN_L2_DEASSERT_SHIF (14) -#define CC6_4345_PMU_EN_ASSERT_L2_MASK (1 << 15) -#define CC6_4345_PMU_EN_ASSERT_L2_SHIFT (15) -#define CC6_4345_PMU_EN_MDIO_MASK (1 << 24) -#define CC6_4345_PMU_EN_MDIO_SHIFT (24) - -/* GCI chipcontrol register indices */ -#define CC_GCI_CHIPCTRL_00 (0) -#define CC_GCI_CHIPCTRL_01 (1) -#define CC_GCI_CHIPCTRL_02 (2) -#define CC_GCI_CHIPCTRL_03 (3) -#define CC_GCI_CHIPCTRL_04 (4) -#define CC_GCI_CHIPCTRL_05 (5) -#define CC_GCI_CHIPCTRL_06 (6) -#define CC_GCI_CHIPCTRL_07 (7) -#define CC_GCI_CHIPCTRL_08 (8) -#define CC_GCI_XTAL_BUFSTRG_NFC (0xff << 12) - -#define CC_GCI_06_JTAG_SEL_SHIFT 4 -#define CC_GCI_06_JTAG_SEL_MASK (1 << 4) - -#define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) - -/* 4345 PMU resources */ -#define RES4345_LPLDO_PU 0 -#define RES4345_PMU_BG_PU 1 -#define RES4345_PMU_SLEEP 2 -#define RES4345_HSICLDO_PU 3 -#define RES4345_CBUCK_LPOM_PU 4 -#define RES4345_CBUCK_PFM_PU 5 -#define RES4345_COLD_START_WAIT 6 -#define RES4345_RSVD_7 7 -#define RES4345_LNLDO_PU 8 -#define RES4345_XTALLDO_PU 9 -#define RES4345_LDO3P3_PU 10 -#define RES4345_OTP_PU 11 -#define RES4345_XTAL_PU 12 -#define RES4345_SR_CLK_START 13 -#define RES4345_LQ_AVAIL 14 -#define RES4345_LQ_START 15 -#define RES4345_PERST_OVR 16 -#define RES4345_WL_CORE_RDY 17 -#define RES4345_ILP_REQ 18 -#define RES4345_ALP_AVAIL 19 -#define RES4345_MINI_PMU 20 -#define RES4345_RADIO_PU 21 -#define RES4345_SR_CLK_STABLE 22 -#define RES4345_SR_SAVE_RESTORE 23 -#define RES4345_SR_PHY_PWRSW 24 -#define RES4345_SR_VDDM_PWRSW 25 -#define RES4345_SR_SUBCORE_PWRSW 26 -#define RES4345_SR_SLEEP 27 -#define RES4345_HT_START 28 -#define RES4345_HT_AVAIL 29 -#define RES4345_MACPHY_CLK_AVAIL 30 - -/* 4335 pins -* note: only the values set as default/used are added here. -*/ -#define CC4335_PIN_GPIO_00 (0) -#define CC4335_PIN_GPIO_01 (1) -#define CC4335_PIN_GPIO_02 (2) -#define CC4335_PIN_GPIO_03 (3) -#define CC4335_PIN_GPIO_04 (4) -#define CC4335_PIN_GPIO_05 (5) -#define CC4335_PIN_GPIO_06 (6) -#define CC4335_PIN_GPIO_07 (7) -#define CC4335_PIN_GPIO_08 (8) -#define CC4335_PIN_GPIO_09 (9) -#define CC4335_PIN_GPIO_10 (10) -#define CC4335_PIN_GPIO_11 (11) -#define CC4335_PIN_GPIO_12 (12) -#define CC4335_PIN_GPIO_13 (13) -#define CC4335_PIN_GPIO_14 (14) -#define CC4335_PIN_GPIO_15 (15) -#define CC4335_PIN_SDIO_CLK (16) -#define CC4335_PIN_SDIO_CMD (17) -#define CC4335_PIN_SDIO_DATA0 (18) -#define CC4335_PIN_SDIO_DATA1 (19) -#define CC4335_PIN_SDIO_DATA2 (20) -#define CC4335_PIN_SDIO_DATA3 (21) -#define CC4335_PIN_RF_SW_CTRL_6 (22) -#define CC4335_PIN_RF_SW_CTRL_7 (23) -#define CC4335_PIN_RF_SW_CTRL_8 (24) -#define CC4335_PIN_RF_SW_CTRL_9 (25) -/* Last GPIO Pad */ -#define CC4335_PIN_GPIO_LAST (31) - -/* 4335 GCI function sel values -*/ -#define CC4335_FNSEL_HWDEF (0) -#define CC4335_FNSEL_SAMEASPIN (1) -#define CC4335_FNSEL_GPIO0 (2) -#define CC4335_FNSEL_GPIO1 (3) -#define CC4335_FNSEL_GCI0 (4) -#define CC4335_FNSEL_GCI1 (5) -#define CC4335_FNSEL_UART (6) -#define CC4335_FNSEL_SFLASH (7) -#define CC4335_FNSEL_SPROM (8) -#define CC4335_FNSEL_MISC0 (9) -#define CC4335_FNSEL_MISC1 (10) -#define CC4335_FNSEL_MISC2 (11) -#define CC4335_FNSEL_IND (12) -#define CC4335_FNSEL_PDN (13) -#define CC4335_FNSEL_PUP (14) -#define CC4335_FNSEL_TRI (15) - -/* GCI Core Control Reg */ -#define GCI_CORECTRL_SR_MASK (1 << 0) /* SECI block Reset */ -#define GCI_CORECTRL_RSL_MASK (1 << 1) /* ResetSECILogic */ -#define GCI_CORECTRL_ES_MASK (1 << 2) /* EnableSECI */ -#define GCI_CORECTRL_FSL_MASK (1 << 3) /* Force SECI Out Low */ -#define GCI_CORECTRL_SOM_MASK (7 << 4) /* SECI Op Mode */ -#define GCI_CORECTRL_US_MASK (1 << 7) /* Update SECI */ -#define GCI_CORECTRL_BOS_MASK (1 << 8) /* Break On Sleep */ - -/* 4345 pins -* note: only the values set as default/used are added here. -*/ -#define CC4345_PIN_GPIO_00 (0) -#define CC4345_PIN_GPIO_01 (1) -#define CC4345_PIN_GPIO_02 (2) -#define CC4345_PIN_GPIO_03 (3) -#define CC4345_PIN_GPIO_04 (4) -#define CC4345_PIN_GPIO_05 (5) -#define CC4345_PIN_GPIO_06 (6) -#define CC4345_PIN_GPIO_07 (7) -#define CC4345_PIN_GPIO_08 (8) -#define CC4345_PIN_GPIO_09 (9) -#define CC4345_PIN_GPIO_10 (10) -#define CC4345_PIN_GPIO_11 (11) -#define CC4345_PIN_GPIO_12 (12) -#define CC4345_PIN_GPIO_13 (13) -#define CC4345_PIN_GPIO_14 (14) -#define CC4345_PIN_GPIO_15 (15) -#define CC4345_PIN_GPIO_16 (16) -#define CC4345_PIN_SDIO_CLK (17) -#define CC4345_PIN_SDIO_CMD (18) -#define CC4345_PIN_SDIO_DATA0 (19) -#define CC4345_PIN_SDIO_DATA1 (20) -#define CC4345_PIN_SDIO_DATA2 (21) -#define CC4345_PIN_SDIO_DATA3 (22) -#define CC4345_PIN_RF_SW_CTRL_0 (23) -#define CC4345_PIN_RF_SW_CTRL_1 (24) -#define CC4345_PIN_RF_SW_CTRL_2 (25) -#define CC4345_PIN_RF_SW_CTRL_3 (26) -#define CC4345_PIN_RF_SW_CTRL_4 (27) -#define CC4345_PIN_RF_SW_CTRL_5 (28) -#define CC4345_PIN_RF_SW_CTRL_6 (29) -#define CC4345_PIN_RF_SW_CTRL_7 (30) -#define CC4345_PIN_RF_SW_CTRL_8 (31) -#define CC4345_PIN_RF_SW_CTRL_9 (32) - -/* 4345 GCI function sel values -*/ -#define CC4345_FNSEL_HWDEF (0) -#define CC4345_FNSEL_SAMEASPIN (1) -#define CC4345_FNSEL_GPIO0 (2) -#define CC4345_FNSEL_GPIO1 (3) -#define CC4345_FNSEL_GCI0 (4) -#define CC4345_FNSEL_GCI1 (5) -#define CC4345_FNSEL_UART (6) -#define CC4345_FNSEL_SFLASH (7) -#define CC4345_FNSEL_SPROM (8) -#define CC4345_FNSEL_MISC0 (9) -#define CC4345_FNSEL_MISC1 (10) -#define CC4345_FNSEL_MISC2 (11) -#define CC4345_FNSEL_IND (12) -#define CC4345_FNSEL_PDN (13) -#define CC4345_FNSEL_PUP (14) -#define CC4345_FNSEL_TRI (15) - -#define MUXENAB4345_UART_MASK (0x0000000f) -#define MUXENAB4345_UART_SHIFT 0 -#define MUXENAB4345_HOSTWAKE_MASK (0x000000f0) -#define MUXENAB4345_HOSTWAKE_SHIFT 4 - -/* 4349 Group (4349, 4355, 4359) GCI AVS function sel values */ -#define CC4349_GRP_GCI_AVS_CTRL_MASK (0xffe00000) -#define CC4349_GRP_GCI_AVS_CTRL_SHIFT (21) -#define CC4349_GRP_GCI_AVS_CTRL_ENAB (1 << 5) - -/* 4345 GCI AVS function sel values */ -#define CC4345_GCI_AVS_CTRL_MASK (0xfc) -#define CC4345_GCI_AVS_CTRL_SHIFT (2) -#define CC4345_GCI_AVS_CTRL_ENAB (1 << 5) - -/* GCI GPIO for function sel GCI-0/GCI-1 */ -#define CC_GCI_GPIO_0 (0) -#define CC_GCI_GPIO_1 (1) -#define CC_GCI_GPIO_2 (2) -#define CC_GCI_GPIO_3 (3) -#define CC_GCI_GPIO_4 (4) -#define CC_GCI_GPIO_5 (5) -#define CC_GCI_GPIO_6 (6) -#define CC_GCI_GPIO_7 (7) -#define CC_GCI_GPIO_8 (8) -#define CC_GCI_GPIO_9 (9) -#define CC_GCI_GPIO_10 (10) -#define CC_GCI_GPIO_11 (11) -#define CC_GCI_GPIO_12 (12) -#define CC_GCI_GPIO_13 (13) -#define CC_GCI_GPIO_14 (14) -#define CC_GCI_GPIO_15 (15) - - -/* indicates Invalid GPIO, e.g. when PAD GPIO doesn't map to GCI GPIO */ -#define CC_GCI_GPIO_INVALID 0xFF - -/* find the 4 bit mask given the bit position */ -#define GCIMASK(pos) (((uint32)0xF) << pos) -/* get the value which can be used to directly OR with chipcontrol reg */ -#define GCIPOSVAL(val, pos) ((((uint32)val) << pos) & GCIMASK(pos)) -/* Extract nibble from a given position */ -#define GCIGETNBL(val, pos) ((val >> pos) & 0xF) - - -/* find the 8 bit mask given the bit position */ -#define GCIMASK_8B(pos) (((uint32)0xFF) << pos) -/* get the value which can be used to directly OR with chipcontrol reg */ -#define GCIPOSVAL_8B(val, pos) ((((uint32)val) << pos) & GCIMASK_8B(pos)) -/* Extract nibble from a given position */ -#define GCIGETNBL_8B(val, pos) ((val >> pos) & 0xFF) - -/* find the 4 bit mask given the bit position */ -#define GCIMASK_4B(pos) (((uint32)0xF) << pos) -/* get the value which can be used to directly OR with chipcontrol reg */ -#define GCIPOSVAL_4B(val, pos) ((((uint32)val) << pos) & GCIMASK_4B(pos)) -/* Extract nibble from a given position */ -#define GCIGETNBL_4B(val, pos) ((val >> pos) & 0xF) - - -/* 4335 GCI Intstatus(Mask)/WakeMask Register bits. */ -#define GCI_INTSTATUS_RBI (1 << 0) /* Rx Break Interrupt */ -#define GCI_INTSTATUS_UB (1 << 1) /* UART Break Interrupt */ -#define GCI_INTSTATUS_SPE (1 << 2) /* SECI Parity Error Interrupt */ -#define GCI_INTSTATUS_SFE (1 << 3) /* SECI Framing Error Interrupt */ -#define GCI_INTSTATUS_SRITI (1 << 9) /* SECI Rx Idle Timer Interrupt */ -#define GCI_INTSTATUS_STFF (1 << 10) /* SECI Tx FIFO Full Interrupt */ -#define GCI_INTSTATUS_STFAE (1 << 11) /* SECI Tx FIFO Almost Empty Intr */ -#define GCI_INTSTATUS_SRFAF (1 << 12) /* SECI Rx FIFO Almost Full */ -#define GCI_INTSTATUS_SRFNE (1 << 14) /* SECI Rx FIFO Not Empty */ -#define GCI_INTSTATUS_SRFOF (1 << 15) /* SECI Rx FIFO Not Empty Timeout */ -#define GCI_INTSTATUS_GPIOINT (1 << 25) /* GCIGpioInt */ -#define GCI_INTSTATUS_GPIOWAKE (1 << 26) /* GCIGpioWake */ - -/* 4335 GCI IntMask Register bits. */ -#define GCI_INTMASK_RBI (1 << 0) /* Rx Break Interrupt */ -#define GCI_INTMASK_UB (1 << 1) /* UART Break Interrupt */ -#define GCI_INTMASK_SPE (1 << 2) /* SECI Parity Error Interrupt */ -#define GCI_INTMASK_SFE (1 << 3) /* SECI Framing Error Interrupt */ -#define GCI_INTMASK_SRITI (1 << 9) /* SECI Rx Idle Timer Interrupt */ -#define GCI_INTMASK_STFF (1 << 10) /* SECI Tx FIFO Full Interrupt */ -#define GCI_INTMASK_STFAE (1 << 11) /* SECI Tx FIFO Almost Empty Intr */ -#define GCI_INTMASK_SRFAF (1 << 12) /* SECI Rx FIFO Almost Full */ -#define GCI_INTMASK_SRFNE (1 << 14) /* SECI Rx FIFO Not Empty */ -#define GCI_INTMASK_SRFOF (1 << 15) /* SECI Rx FIFO Not Empty Timeout */ -#define GCI_INTMASK_GPIOINT (1 << 25) /* GCIGpioInt */ -#define GCI_INTMASK_GPIOWAKE (1 << 26) /* GCIGpioWake */ - -/* 4335 GCI WakeMask Register bits. */ -#define GCI_WAKEMASK_RBI (1 << 0) /* Rx Break Interrupt */ -#define GCI_WAKEMASK_UB (1 << 1) /* UART Break Interrupt */ -#define GCI_WAKEMASK_SPE (1 << 2) /* SECI Parity Error Interrupt */ -#define GCI_WAKEMASK_SFE (1 << 3) /* SECI Framing Error Interrupt */ -#define GCI_WAKE_SRITI (1 << 9) /* SECI Rx Idle Timer Interrupt */ -#define GCI_WAKEMASK_STFF (1 << 10) /* SECI Tx FIFO Full Interrupt */ -#define GCI_WAKEMASK_STFAE (1 << 11) /* SECI Tx FIFO Almost Empty Intr */ -#define GCI_WAKEMASK_SRFAF (1 << 12) /* SECI Rx FIFO Almost Full */ -#define GCI_WAKEMASK_SRFNE (1 << 14) /* SECI Rx FIFO Not Empty */ -#define GCI_WAKEMASK_SRFOF (1 << 15) /* SECI Rx FIFO Not Empty Timeout */ -#define GCI_WAKEMASK_GPIOINT (1 << 25) /* GCIGpioInt */ -#define GCI_WAKEMASK_GPIOWAKE (1 << 26) /* GCIGpioWake */ - -#define GCI_WAKE_ON_GCI_GPIO1 1 -#define GCI_WAKE_ON_GCI_GPIO2 2 -#define GCI_WAKE_ON_GCI_GPIO3 3 -#define GCI_WAKE_ON_GCI_GPIO4 4 -#define GCI_WAKE_ON_GCI_GPIO5 5 -#define GCI_WAKE_ON_GCI_GPIO6 6 -#define GCI_WAKE_ON_GCI_GPIO7 7 -#define GCI_WAKE_ON_GCI_GPIO8 8 -#define GCI_WAKE_ON_GCI_SECI_IN 9 - -/* 4335 MUX options. each nibble belongs to a setting. Non-zero value specifies a logic -* for now only UART for bootloader. -*/ -#define MUXENAB4335_UART_MASK (0x0000000f) - -#define MUXENAB4335_UART_SHIFT 0 -#define MUXENAB4335_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ -#define MUXENAB4335_HOSTWAKE_SHIFT 4 -#define MUXENAB4335_GETIX(val, name) \ - ((((val) & MUXENAB4335_ ## name ## _MASK) >> MUXENAB4335_ ## name ## _SHIFT) - 1) - -/* -* Maximum delay for the PMU state transition in us. -* This is an upper bound intended for spinwaits etc. -*/ -#define PMU_MAX_TRANSITION_DLY 15000 - -/* PMU resource up transition time in ILP cycles */ -#define PMURES_UP_TRANSITION 2 - - -/* SECI configuration */ -#define SECI_MODE_UART 0x0 -#define SECI_MODE_SECI 0x1 -#define SECI_MODE_LEGACY_3WIRE_BT 0x2 -#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3 -#define SECI_MODE_HALF_SECI 0x4 - -#define SECI_RESET (1 << 0) -#define SECI_RESET_BAR_UART (1 << 1) -#define SECI_ENAB_SECI_ECI (1 << 2) -#define SECI_ENAB_SECIOUT_DIS (1 << 3) -#define SECI_MODE_MASK 0x7 -#define SECI_MODE_SHIFT 4 /* (bits 5, 6, 7) */ -#define SECI_UPD_SECI (1 << 7) - -#define SECI_SLIP_ESC_CHAR 0xDB -#define SECI_SIGNOFF_0 SECI_SLIP_ESC_CHAR -#define SECI_SIGNOFF_1 0 -#define SECI_REFRESH_REQ 0xDA - -/* seci clk_ctl_st bits */ -#define CLKCTL_STS_SECI_CLK_REQ (1 << 8) -#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24) - -#define SECI_UART_MSR_CTS_STATE (1 << 0) -#define SECI_UART_MSR_RTS_STATE (1 << 1) -#define SECI_UART_SECI_IN_STATE (1 << 2) -#define SECI_UART_SECI_IN2_STATE (1 << 3) - -/* GCI RX FIFO Control Register */ -#define GCI_RXF_LVL_MASK (0xFF << 0) -#define GCI_RXF_TIMEOUT_MASK (0xFF << 8) - -/* GCI UART Registers' Bit definitions */ -/* Seci Fifo Level Register */ -#define SECI_TXF_LVL_MASK (0x3F << 8) -#define TXF_AE_LVL_DEFAULT 0x4 -#define SECI_RXF_LVL_FC_MASK (0x3F << 16) - -/* SeciUARTFCR Bit definitions */ -#define SECI_UART_FCR_RFR (1 << 0) -#define SECI_UART_FCR_TFR (1 << 1) -#define SECI_UART_FCR_SR (1 << 2) -#define SECI_UART_FCR_THP (1 << 3) -#define SECI_UART_FCR_AB (1 << 4) -#define SECI_UART_FCR_ATOE (1 << 5) -#define SECI_UART_FCR_ARTSOE (1 << 6) -#define SECI_UART_FCR_ABV (1 << 7) -#define SECI_UART_FCR_ALM (1 << 8) - -/* SECI UART LCR register bits */ -#define SECI_UART_LCR_STOP_BITS (1 << 0) /* 0 - 1bit, 1 - 2bits */ -#define SECI_UART_LCR_PARITY_EN (1 << 1) -#define SECI_UART_LCR_PARITY (1 << 2) /* 0 - odd, 1 - even */ -#define SECI_UART_LCR_RX_EN (1 << 3) -#define SECI_UART_LCR_LBRK_CTRL (1 << 4) /* 1 => SECI_OUT held low */ -#define SECI_UART_LCR_TXO_EN (1 << 5) -#define SECI_UART_LCR_RTSO_EN (1 << 6) -#define SECI_UART_LCR_SLIPMODE_EN (1 << 7) -#define SECI_UART_LCR_RXCRC_CHK (1 << 8) -#define SECI_UART_LCR_TXCRC_INV (1 << 9) -#define SECI_UART_LCR_TXCRC_LSBF (1 << 10) -#define SECI_UART_LCR_TXCRC_EN (1 << 11) -#define SECI_UART_LCR_RXSYNC_EN (1 << 12) - -#define SECI_UART_MCR_TX_EN (1 << 0) -#define SECI_UART_MCR_PRTS (1 << 1) -#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2) -#define SECI_UART_MCR_HIGHRATE_EN (1 << 3) -#define SECI_UART_MCR_LOOPBK_EN (1 << 4) -#define SECI_UART_MCR_AUTO_RTS (1 << 5) -#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6) -#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7) -#define SECI_UART_MCR_XONOFF_RPT (1 << 9) - -/* SeciUARTLSR Bit Mask */ -#define SECI_UART_LSR_RXOVR_MASK (1 << 0) -#define SECI_UART_LSR_RFF_MASK (1 << 1) -#define SECI_UART_LSR_TFNE_MASK (1 << 2) -#define SECI_UART_LSR_TI_MASK (1 << 3) -#define SECI_UART_LSR_TPR_MASK (1 << 4) -#define SECI_UART_LSR_TXHALT_MASK (1 << 5) - -/* SeciUARTMSR Bit Mask */ -#define SECI_UART_MSR_CTSS_MASK (1 << 0) -#define SECI_UART_MSR_RTSS_MASK (1 << 1) -#define SECI_UART_MSR_SIS_MASK (1 << 2) -#define SECI_UART_MSR_SIS2_MASK (1 << 3) - -/* SeciUARTData Bits */ -#define SECI_UART_DATA_RF_NOT_EMPTY_BIT (1 << 12) -#define SECI_UART_DATA_RF_FULL_BIT (1 << 13) -#define SECI_UART_DATA_RF_OVRFLOW_BIT (1 << 14) -#define SECI_UART_DATA_FIFO_PTR_MASK 0xFF -#define SECI_UART_DATA_RF_RD_PTR_SHIFT 16 -#define SECI_UART_DATA_RF_WR_PTR_SHIFT 24 - -/* LTECX: ltecxmux */ -#define LTECX_EXTRACT_MUX(val, idx) (getbit4(&(val), (idx))) - -/* LTECX: ltecxmux MODE */ -#define LTECX_MUX_MODE_IDX 0 -#define LTECX_MUX_MODE_WCI2 0x0 -#define LTECX_MUX_MODE_GPIO 0x1 - - -/* LTECX GPIO Information Index */ -#define LTECX_NVRAM_FSYNC_IDX 0 -#define LTECX_NVRAM_LTERX_IDX 1 -#define LTECX_NVRAM_LTETX_IDX 2 -#define LTECX_NVRAM_WLPRIO_IDX 3 - -/* LTECX WCI2 Information Index */ -#define LTECX_NVRAM_WCI2IN_IDX 0 -#define LTECX_NVRAM_WCI2OUT_IDX 1 - -/* LTECX: Macros to get GPIO/FNSEL/GCIGPIO */ -#define LTECX_EXTRACT_PADNUM(val, idx) (getbit8(&(val), (idx))) -#define LTECX_EXTRACT_FNSEL(val, idx) (getbit4(&(val), (idx))) -#define LTECX_EXTRACT_GCIGPIO(val, idx) (getbit4(&(val), (idx))) - -/* WLAN channel numbers - used from wifi.h */ - -/* WLAN BW */ -#define ECI_BW_20 0x0 -#define ECI_BW_25 0x1 -#define ECI_BW_30 0x2 -#define ECI_BW_35 0x3 -#define ECI_BW_40 0x4 -#define ECI_BW_45 0x5 -#define ECI_BW_50 0x6 -#define ECI_BW_ALL 0x7 - -/* WLAN - number of antenna */ -#define WLAN_NUM_ANT1 TXANT_0 -#define WLAN_NUM_ANT2 TXANT_1 - -/* otpctrl1 0xF4 */ -#define OTPC_FORCE_PWR_OFF 0x02000000 -/* chipcommon s/r registers introduced with cc rev >= 48 */ -#define CC_SR_CTL0_ENABLE_MASK 0x1 -#define CC_SR_CTL0_ENABLE_SHIFT 0 -#define CC_SR_CTL0_EN_SR_ENG_CLK_SHIFT 1 /* sr_clk to sr_memory enable */ -#define CC_SR_CTL0_RSRC_TRIGGER_SHIFT 2 /* Rising edge resource trigger 0 to sr_engine */ -#define CC_SR_CTL0_MIN_DIV_SHIFT 6 /* Min division value for fast clk in sr_engine */ -#define CC_SR_CTL0_EN_SBC_STBY_SHIFT 16 /* Allow Subcore mem StandBy? */ -#define CC_SR_CTL0_EN_SR_ALP_CLK_MASK_SHIFT 18 -#define CC_SR_CTL0_EN_SR_HT_CLK_SHIFT 19 -#define CC_SR_CTL0_ALLOW_PIC_SHIFT 20 /* Allow pic to separate power domains */ -#define CC_SR_CTL0_MAX_SR_LQ_CLK_CNT_SHIFT 25 -#define CC_SR_CTL0_EN_MEM_DISABLE_FOR_SLEEP 30 - -#define CC_SR_CTL1_SR_INIT_MASK 0x3FF -#define CC_SR_CTL1_SR_INIT_SHIFT 0 - -#define ECI_INLO_PKTDUR_MASK 0x000000f0 /* [7:4] - 4 bits */ -#define ECI_INLO_PKTDUR_SHIFT 4 - -/* gci chip control bits */ -#define GCI_GPIO_CHIPCTRL_ENAB_IN_BIT 0 -#define GCI_GPIO_CHIPCTRL_ENAB_OP_BIT 1 -#define GCI_GPIO_CHIPCTRL_INVERT_BIT 2 -#define GCI_GPIO_CHIPCTRL_PULLUP_BIT 3 -#define GCI_GPIO_CHIPCTRL_PULLDN_BIT 4 -#define GCI_GPIO_CHIPCTRL_ENAB_BTSIG_BIT 5 -#define GCI_GPIO_CHIPCTRL_ENAB_OD_OP_BIT 6 -#define GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT 7 - -/* gci GPIO input status bits */ -#define GCI_GPIO_STS_VALUE_BIT 0 -#define GCI_GPIO_STS_POS_EDGE_BIT 1 -#define GCI_GPIO_STS_NEG_EDGE_BIT 2 -#define GCI_GPIO_STS_FAST_EDGE_BIT 3 -#define GCI_GPIO_STS_CLEAR 0xF - -#define GCI_GPIO_STS_VALUE (1 << GCI_GPIO_STS_VALUE_BIT) - -#endif /* _SBCHIPC_H */ diff --git a/drivers/net/wireless/bcmdhd/include/sbconfig.h b/drivers/net/wireless/bcmdhd/include/sbconfig.h deleted file mode 100644 index d2e60152abef..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sbconfig.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Broadcom SiliconBackplane hardware register definitions. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbconfig.h 456346 2014-02-18 16:48:52Z $ - */ - -#ifndef _SBCONFIG_H -#define _SBCONFIG_H - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif - -/* enumeration in SB is based on the premise that cores are contiguos in the - * enumeration space. - */ -#define SB_BUS_SIZE 0x10000 /* Each bus gets 64Kbytes for cores */ -#define SB_BUS_BASE(b) (SI_ENUM_BASE + (b) * SB_BUS_SIZE) -#define SB_BUS_MAXCORES (SB_BUS_SIZE / SI_CORE_SIZE) /* Max cores per bus */ - -/* - * Sonics Configuration Space Registers. - */ -#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */ -#define SBCONFIGSIZE 256 /* sizeof (sbconfig_t) */ - -#define SBIPSFLAG 0x08 -#define SBTPSFLAG 0x18 -#define SBTMERRLOGA 0x48 /* sonics >= 2.3 */ -#define SBTMERRLOG 0x50 /* sonics >= 2.3 */ -#define SBADMATCH3 0x60 -#define SBADMATCH2 0x68 -#define SBADMATCH1 0x70 -#define SBIMSTATE 0x90 -#define SBINTVEC 0x94 -#define SBTMSTATELOW 0x98 -#define SBTMSTATEHIGH 0x9c -#define SBBWA0 0xa0 -#define SBIMCONFIGLOW 0xa8 -#define SBIMCONFIGHIGH 0xac -#define SBADMATCH0 0xb0 -#define SBTMCONFIGLOW 0xb8 -#define SBTMCONFIGHIGH 0xbc -#define SBBCONFIG 0xc0 -#define SBBSTATE 0xc8 -#define SBACTCNFG 0xd8 -#define SBFLAGST 0xe8 -#define SBIDLOW 0xf8 -#define SBIDHIGH 0xfc - -/* All the previous registers are above SBCONFIGOFF, but with Sonics 2.3, we have - * a few registers *below* that line. I think it would be very confusing to try - * and change the value of SBCONFIGOFF, so I'm definig them as absolute offsets here, - */ - -#define SBIMERRLOGA 0xea8 -#define SBIMERRLOG 0xeb0 -#define SBTMPORTCONNID0 0xed8 -#define SBTMPORTLOCK0 0xef8 - -#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) - -typedef volatile struct _sbconfig { - uint32 PAD[2]; - uint32 sbipsflag; /* initiator port ocp slave flag */ - uint32 PAD[3]; - uint32 sbtpsflag; /* target port ocp slave flag */ - uint32 PAD[11]; - uint32 sbtmerrloga; /* (sonics >= 2.3) */ - uint32 PAD; - uint32 sbtmerrlog; /* (sonics >= 2.3) */ - uint32 PAD[3]; - uint32 sbadmatch3; /* address match3 */ - uint32 PAD; - uint32 sbadmatch2; /* address match2 */ - uint32 PAD; - uint32 sbadmatch1; /* address match1 */ - uint32 PAD[7]; - uint32 sbimstate; /* initiator agent state */ - uint32 sbintvec; /* interrupt mask */ - uint32 sbtmstatelow; /* target state */ - uint32 sbtmstatehigh; /* target state */ - uint32 sbbwa0; /* bandwidth allocation table0 */ - uint32 PAD; - uint32 sbimconfiglow; /* initiator configuration */ - uint32 sbimconfighigh; /* initiator configuration */ - uint32 sbadmatch0; /* address match0 */ - uint32 PAD; - uint32 sbtmconfiglow; /* target configuration */ - uint32 sbtmconfighigh; /* target configuration */ - uint32 sbbconfig; /* broadcast configuration */ - uint32 PAD; - uint32 sbbstate; /* broadcast state */ - uint32 PAD[3]; - uint32 sbactcnfg; /* activate configuration */ - uint32 PAD[3]; - uint32 sbflagst; /* current sbflags */ - uint32 PAD[3]; - uint32 sbidlow; /* identification */ - uint32 sbidhigh; /* identification */ -} sbconfig_t; - -#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ - -/* sbipsflag */ -#define SBIPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */ -#define SBIPS_INT1_SHIFT 0 -#define SBIPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */ -#define SBIPS_INT2_SHIFT 8 -#define SBIPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */ -#define SBIPS_INT3_SHIFT 16 -#define SBIPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */ -#define SBIPS_INT4_SHIFT 24 - -/* sbtpsflag */ -#define SBTPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */ -#define SBTPS_F0EN0 0x40 /* interrupt is always sent on the backplane */ - -/* sbtmerrlog */ -#define SBTMEL_CM 0x00000007 /* command */ -#define SBTMEL_CI 0x0000ff00 /* connection id */ -#define SBTMEL_EC 0x0f000000 /* error code */ -#define SBTMEL_ME 0x80000000 /* multiple error */ - -/* sbimstate */ -#define SBIM_PC 0xf /* pipecount */ -#define SBIM_AP_MASK 0x30 /* arbitration policy */ -#define SBIM_AP_BOTH 0x00 /* use both timeslaces and token */ -#define SBIM_AP_TS 0x10 /* use timesliaces only */ -#define SBIM_AP_TK 0x20 /* use token only */ -#define SBIM_AP_RSV 0x30 /* reserved */ -#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 */ -#define SBTML_RESET 0x0001 /* reset */ -#define SBTML_REJ_MASK 0x0006 /* reject field */ -#define SBTML_REJ 0x0002 /* reject */ -#define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */ - -#define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */ - -/* sbtmstatehigh */ -#define SBTMH_SERR 0x0001 /* serror */ -#define SBTMH_INT 0x0002 /* interrupt */ -#define SBTMH_BUSY 0x0004 /* busy */ -#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ - -#define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */ - -/* sbbwa0 */ -#define SBBWA_TAB0_MASK 0xffff /* lookup table 0 */ -#define SBBWA_TAB1_MASK 0xffff /* lookup table 1 */ -#define SBBWA_TAB1_SHIFT 16 - -/* sbimconfiglow */ -#define SBIMCL_STO_MASK 0x7 /* service timeout */ -#define SBIMCL_RTO_MASK 0x70 /* request timeout */ -#define SBIMCL_RTO_SHIFT 4 -#define SBIMCL_CID_MASK 0xff0000 /* connection id */ -#define SBIMCL_CID_SHIFT 16 - -/* sbimconfighigh */ -#define SBIMCH_IEM_MASK 0xc /* inband error mode */ -#define SBIMCH_TEM_MASK 0x30 /* timeout error mode */ -#define SBIMCH_TEM_SHIFT 4 -#define SBIMCH_BEM_MASK 0xc0 /* bus error mode */ -#define SBIMCH_BEM_SHIFT 6 - -/* sbadmatch0 */ -#define SBAM_TYPE_MASK 0x3 /* address type */ -#define SBAM_AD64 0x4 /* reserved */ -#define SBAM_ADINT0_MASK 0xf8 /* type0 size */ -#define SBAM_ADINT0_SHIFT 3 -#define SBAM_ADINT1_MASK 0x1f8 /* type1 size */ -#define SBAM_ADINT1_SHIFT 3 -#define SBAM_ADINT2_MASK 0x1f8 /* type2 size */ -#define SBAM_ADINT2_SHIFT 3 -#define SBAM_ADEN 0x400 /* enable */ -#define SBAM_ADNEG 0x800 /* negative decode */ -#define SBAM_BASE0_MASK 0xffffff00 /* type0 base address */ -#define SBAM_BASE0_SHIFT 8 -#define SBAM_BASE1_MASK 0xfffff000 /* type1 base address for the core */ -#define SBAM_BASE1_SHIFT 12 -#define SBAM_BASE2_MASK 0xffff0000 /* type2 base address for the core */ -#define SBAM_BASE2_SHIFT 16 - -/* sbtmconfiglow */ -#define SBTMCL_CD_MASK 0xff /* clock divide */ -#define SBTMCL_CO_MASK 0xf800 /* clock offset */ -#define SBTMCL_CO_SHIFT 11 -#define SBTMCL_IF_MASK 0xfc0000 /* interrupt flags */ -#define SBTMCL_IF_SHIFT 18 -#define SBTMCL_IM_MASK 0x3000000 /* interrupt mode */ -#define SBTMCL_IM_SHIFT 24 - -/* sbtmconfighigh */ -#define SBTMCH_BM_MASK 0x3 /* busy mode */ -#define SBTMCH_RM_MASK 0x3 /* retry mode */ -#define SBTMCH_RM_SHIFT 2 -#define SBTMCH_SM_MASK 0x30 /* stop mode */ -#define SBTMCH_SM_SHIFT 4 -#define SBTMCH_EM_MASK 0x300 /* sb error mode */ -#define SBTMCH_EM_SHIFT 8 -#define SBTMCH_IM_MASK 0xc00 /* int mode */ -#define SBTMCH_IM_SHIFT 10 - -/* sbbconfig */ -#define SBBC_LAT_MASK 0x3 /* sb latency */ -#define SBBC_MAX0_MASK 0xf0000 /* maxccntr0 */ -#define SBBC_MAX0_SHIFT 16 -#define SBBC_MAX1_MASK 0xf00000 /* maxccntr1 */ -#define SBBC_MAX1_SHIFT 20 - -/* sbbstate */ -#define SBBS_SRD 0x1 /* st reg disable */ -#define SBBS_HRD 0x2 /* hold reg disable */ - -/* sbidlow */ -#define SBIDL_CS_MASK 0x3 /* config space */ -#define SBIDL_AR_MASK 0x38 /* # address ranges supported */ -#define SBIDL_AR_SHIFT 3 -#define SBIDL_SYNCH 0x40 /* sync */ -#define SBIDL_INIT 0x80 /* initiator */ -#define SBIDL_MINLAT_MASK 0xf00 /* minimum backplane latency */ -#define SBIDL_MINLAT_SHIFT 8 -#define SBIDL_MAXLAT 0xf000 /* maximum backplane latency */ -#define SBIDL_MAXLAT_SHIFT 12 -#define SBIDL_FIRST 0x10000 /* this initiator is first */ -#define SBIDL_CW_MASK 0xc0000 /* cycle counter width */ -#define SBIDL_CW_SHIFT 18 -#define SBIDL_TP_MASK 0xf00000 /* target ports */ -#define SBIDL_TP_SHIFT 20 -#define SBIDL_IP_MASK 0xf000000 /* initiator ports */ -#define SBIDL_IP_SHIFT 24 -#define SBIDL_RV_MASK 0xf0000000 /* sonics backplane revision code */ -#define SBIDL_RV_SHIFT 28 -#define SBIDL_RV_2_2 0x00000000 /* version 2.2 or earlier */ -#define SBIDL_RV_2_3 0x10000000 /* version 2.3 */ - -/* 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 - -#define SB_COMMIT 0xfd8 /* update buffered registers value */ - -/* vendor codes */ -#define SB_VEND_BCM 0x4243 /* Broadcom's SB vendor code */ - -#endif /* _SBCONFIG_H */ diff --git a/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/bcmdhd/include/sbhnddma.h deleted file mode 100644 index 401fbbbd48dc..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sbhnddma.h +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Generic Broadcom Home Networking Division (HND) DMA engine HW interface - * This supports the following chips: BCM42xx, 44xx, 47xx . - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbhnddma.h 452424 2014-01-30 09:43:39Z $ - */ - -#ifndef _sbhnddma_h_ -#define _sbhnddma_h_ - -/* 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 */ - -/* dma registers per channel(xmt or rcv) */ -typedef volatile struct { - uint32 control; /* enable, et al */ - uint32 addr; /* descriptor ring base address (4K aligned) */ - uint32 ptr; /* last descriptor posted to chip */ - uint32 status; /* current active descriptor, et al */ -} dma32regs_t; - -typedef volatile struct { - dma32regs_t xmt; /* dma tx channel */ - dma32regs_t rcv; /* dma rx channel */ -} dma32regp_t; - -typedef volatile struct { /* diag access */ - uint32 fifoaddr; /* diag address */ - uint32 fifodatalow; /* low 32bits of data */ - uint32 fifodatahigh; /* high 32bits of data */ - uint32 pad; /* reserved */ -} dma32diag_t; - -/* - * DMA Descriptor - * Descriptors are only read by the hardware, never written back. - */ -typedef volatile struct { - uint32 ctrl; /* misc control bits & bufcount */ - uint32 addr; /* data buffer address */ -} dma32dd_t; - -/* - * Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page. - */ -#define D32RINGALIGN_BITS 12 -#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS) -#define D32RINGALIGN (1 << D32RINGALIGN_BITS) - -#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) - -/* transmit channel control */ -#define XC_XE ((uint32)1 << 0) /* transmit enable */ -#define XC_SE ((uint32)1 << 1) /* transmit suspend request */ -#define XC_LE ((uint32)1 << 2) /* loopback enable */ -#define XC_FL ((uint32)1 << 4) /* flush request */ -#define XC_MR_MASK 0x000001C0 /* Multiple outstanding reads */ -#define XC_MR_SHIFT 6 -#define XC_PD ((uint32)1 << 11) /* parity check disable */ -#define XC_AE ((uint32)3 << 16) /* address extension bits */ -#define XC_AE_SHIFT 16 -#define XC_BL_MASK 0x001C0000 /* BurstLen bits */ -#define XC_BL_SHIFT 18 -#define XC_PC_MASK 0x00E00000 /* Prefetch control */ -#define XC_PC_SHIFT 21 -#define XC_PT_MASK 0x03000000 /* Prefetch threshold */ -#define XC_PT_SHIFT 24 - -/* Multiple outstanding reads */ -#define DMA_MR_1 0 -#define DMA_MR_2 1 -#define DMA_MR_4 2 -#define DMA_MR_8 3 -#define DMA_MR_12 4 -#define DMA_MR_16 5 -#define DMA_MR_20 6 -#define DMA_MR_32 7 - -/* DMA Burst Length in bytes */ -#define DMA_BL_16 0 -#define DMA_BL_32 1 -#define DMA_BL_64 2 -#define DMA_BL_128 3 -#define DMA_BL_256 4 -#define DMA_BL_512 5 -#define DMA_BL_1024 6 - -/* Prefetch control */ -#define DMA_PC_0 0 -#define DMA_PC_4 1 -#define DMA_PC_8 2 -#define DMA_PC_16 3 -/* others: reserved */ - -/* Prefetch threshold */ -#define DMA_PT_1 0 -#define DMA_PT_2 1 -#define DMA_PT_4 2 -#define DMA_PT_8 3 - -/* transmit descriptor table pointer */ -#define XP_LD_MASK 0xfff /* last valid descriptor */ - -/* transmit channel status */ -#define XS_CD_MASK 0x0fff /* current descriptor pointer */ -#define XS_XS_MASK 0xf000 /* transmit state */ -#define XS_XS_SHIFT 12 -#define XS_XS_DISABLED 0x0000 /* disabled */ -#define XS_XS_ACTIVE 0x1000 /* active */ -#define XS_XS_IDLE 0x2000 /* idle wait */ -#define XS_XS_STOPPED 0x3000 /* stopped */ -#define XS_XS_SUSP 0x4000 /* suspend pending */ -#define XS_XE_MASK 0xf0000 /* transmit errors */ -#define XS_XE_SHIFT 16 -#define XS_XE_NOERR 0x00000 /* no error */ -#define XS_XE_DPE 0x10000 /* descriptor protocol error */ -#define XS_XE_DFU 0x20000 /* data fifo underrun */ -#define XS_XE_BEBR 0x30000 /* bus error on buffer read */ -#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */ -#define XS_AD_MASK 0xfff00000 /* active descriptor */ -#define XS_AD_SHIFT 20 - -/* receive channel control */ -#define RC_RE ((uint32)1 << 0) /* receive enable */ -#define RC_RO_MASK 0xfe /* receive frame offset */ -#define RC_RO_SHIFT 1 -#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */ -#define RC_SH ((uint32)1 << 9) /* separate rx header descriptor enable */ -#define RC_OC ((uint32)1 << 10) /* overflow continue */ -#define RC_PD ((uint32)1 << 11) /* parity check disable */ -#define RC_AE ((uint32)3 << 16) /* address extension bits */ -#define RC_AE_SHIFT 16 -#define RC_BL_MASK 0x001C0000 /* BurstLen bits */ -#define RC_BL_SHIFT 18 -#define RC_PC_MASK 0x00E00000 /* Prefetch control */ -#define RC_PC_SHIFT 21 -#define RC_PT_MASK 0x03000000 /* Prefetch threshold */ -#define RC_PT_SHIFT 24 - -/* receive descriptor table pointer */ -#define RP_LD_MASK 0xfff /* last valid descriptor */ - -/* receive channel status */ -#define RS_CD_MASK 0x0fff /* current descriptor pointer */ -#define RS_RS_MASK 0xf000 /* receive state */ -#define RS_RS_SHIFT 12 -#define RS_RS_DISABLED 0x0000 /* disabled */ -#define RS_RS_ACTIVE 0x1000 /* active */ -#define RS_RS_IDLE 0x2000 /* idle wait */ -#define RS_RS_STOPPED 0x3000 /* reserved */ -#define RS_RE_MASK 0xf0000 /* receive errors */ -#define RS_RE_SHIFT 16 -#define RS_RE_NOERR 0x00000 /* no error */ -#define RS_RE_DPE 0x10000 /* descriptor protocol error */ -#define RS_RE_DFO 0x20000 /* data fifo overflow */ -#define RS_RE_BEBW 0x30000 /* bus error on buffer write */ -#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */ -#define RS_AD_MASK 0xfff00000 /* active descriptor */ -#define RS_AD_SHIFT 20 - -/* fifoaddr */ -#define FA_OFF_MASK 0xffff /* offset */ -#define FA_SEL_MASK 0xf0000 /* select */ -#define FA_SEL_SHIFT 16 -#define FA_SEL_XDD 0x00000 /* transmit dma data */ -#define FA_SEL_XDP 0x10000 /* transmit dma pointers */ -#define FA_SEL_RDD 0x40000 /* receive dma data */ -#define FA_SEL_RDP 0x50000 /* receive dma pointers */ -#define FA_SEL_XFD 0x80000 /* transmit fifo data */ -#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */ -#define FA_SEL_RFD 0xc0000 /* receive fifo data */ -#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */ -#define FA_SEL_RSD 0xe0000 /* receive frame status data */ -#define FA_SEL_RSP 0xf0000 /* receive frame status pointers */ - -/* descriptor control flags */ -#define CTRL_BC_MASK 0x00001fff /* buffer byte count, real data len must <= 4KB */ -#define CTRL_AE ((uint32)3 << 16) /* address extension bits */ -#define CTRL_AE_SHIFT 16 -#define CTRL_PARITY ((uint32)3 << 18) /* parity bit */ -#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */ -#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */ -#define CTRL_EOF ((uint32)1 << 30) /* end of frame */ -#define CTRL_SOF ((uint32)1 << 31) /* start of frame */ - -/* control flags in the range [27:20] are core-specific and not defined here */ -#define CTRL_CORE_MASK 0x0ff00000 - -/* 64 bits addressing */ - -/* dma registers per channel(xmt or rcv) */ -typedef volatile struct { - uint32 control; /* enable, et al */ - uint32 ptr; /* last descriptor posted to chip */ - uint32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */ - uint32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */ - uint32 status0; /* current descriptor, xmt state */ - uint32 status1; /* active descriptor, xmt error */ -} dma64regs_t; - -typedef volatile struct { - dma64regs_t tx; /* dma64 tx channel */ - dma64regs_t rx; /* dma64 rx channel */ -} dma64regp_t; - -typedef volatile struct { /* diag access */ - uint32 fifoaddr; /* diag address */ - uint32 fifodatalow; /* low 32bits of data */ - uint32 fifodatahigh; /* high 32bits of data */ - uint32 pad; /* reserved */ -} dma64diag_t; - -/* - * DMA Descriptor - * Descriptors are only read by the hardware, never written back. - */ -typedef volatile struct { - uint32 ctrl1; /* misc control bits */ - uint32 ctrl2; /* buffer count and address extension */ - uint32 addrlow; /* memory address of the date buffer, bits 31:0 */ - uint32 addrhigh; /* memory address of the date buffer, bits 63:32 */ -} dma64dd_t; - -/* - * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss. - */ -#define D64RINGALIGN_BITS 13 -#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) -#define D64RINGBOUNDARY (1 << D64RINGALIGN_BITS) - -#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) - -/* for cores with large descriptor ring support, descriptor ring size can be up to 4096 */ -#define D64MAXDD_LARGE ((1 << 16) / sizeof (dma64dd_t)) - -/* for cores with large descriptor ring support (4k descriptors), descriptor ring cannot cross - * 64K boundary - */ -#define D64RINGBOUNDARY_LARGE (1 << 16) - -/* - * Default DMA Burstlen values for USBRev >= 12 and SDIORev >= 11. - * When this field contains the value N, the burst length is 2**(N + 4) bytes. - */ -#define D64_DEF_USBBURSTLEN 2 -#define D64_DEF_SDIOBURSTLEN 1 - - -#ifndef D64_USBBURSTLEN -#define D64_USBBURSTLEN DMA_BL_64 -#endif -#ifndef D64_SDIOBURSTLEN -#define D64_SDIOBURSTLEN DMA_BL_32 -#endif - -/* 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_MR_MASK 0x000001C0 /* Multiple outstanding reads */ -#define D64_XC_MR_SHIFT 6 -#define D64_XC_PD 0x00000800 /* parity check disable */ -#define D64_XC_AE 0x00030000 /* address extension bits */ -#define D64_XC_AE_SHIFT 16 -#define D64_XC_BL_MASK 0x001C0000 /* BurstLen bits */ -#define D64_XC_BL_SHIFT 18 -#define D64_XC_PC_MASK 0x00E00000 /* Prefetch control */ -#define D64_XC_PC_SHIFT 21 -#define D64_XC_PT_MASK 0x03000000 /* Prefetch threshold */ -#define D64_XC_PT_SHIFT 24 - -/* transmit descriptor table pointer */ -#define D64_XP_LD_MASK 0x00001fff /* last valid descriptor */ - -/* transmit channel status */ -#define D64_XS0_CD_MASK (di->d64_xs0_cd_mask) /* 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 (di->d64_xs1_ad_mask) /* 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 */ -#define D64_RC_RE 0x00000001 /* receive enable */ -#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */ -#define D64_RC_RO_SHIFT 1 -#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */ -#define D64_RC_SH 0x00000200 /* separate rx header descriptor enable */ -#define D64_RC_SHIFT 9 /* separate rx header descriptor enable */ -#define D64_RC_OC 0x00000400 /* overflow continue */ -#define D64_RC_PD 0x00000800 /* parity check disable */ -#define D64_RC_GE 0x00004000 /* Glom enable */ -#define D64_RC_AE 0x00030000 /* address extension bits */ -#define D64_RC_AE_SHIFT 16 -#define D64_RC_BL_MASK 0x001C0000 /* BurstLen bits */ -#define D64_RC_BL_SHIFT 18 -#define D64_RC_PC_MASK 0x00E00000 /* Prefetch control */ -#define D64_RC_PC_SHIFT 21 -#define D64_RC_PT_MASK 0x03000000 /* Prefetch threshold */ -#define D64_RC_PT_SHIFT 24 - -/* flags for dma controller */ -#define DMA_CTRL_PEN (1 << 0) /* partity enable */ -#define DMA_CTRL_ROC (1 << 1) /* rx overflow continue */ -#define DMA_CTRL_RXMULTI (1 << 2) /* allow rx scatter to multiple descriptors */ -#define DMA_CTRL_UNFRAMED (1 << 3) /* Unframed Rx/Tx data */ -#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) -#define DMA_CTRL_DMA_AVOIDANCE_WAR (1 << 5) /* DMA avoidance WAR for 4331 */ -#define DMA_CTRL_RXSINGLE (1 << 6) /* always single buffer */ -#define DMA_CTRL_SDIO_RXGLOM (1 << 7) /* DMA Rx glome is enabled */ - -/* receive descriptor table pointer */ -#define D64_RP_LD_MASK 0x00001fff /* last valid descriptor */ - -/* receive channel status */ -#define D64_RS0_CD_MASK (di->d64_rs0_cd_mask) /* 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_NOTPCIE ((uint32)1 << 18) /* buirst size control */ -#define D64_CTRL1_EOT ((uint32)1 << 28) /* end of descriptor table */ -#define D64_CTRL1_IOC ((uint32)1 << 29) /* interrupt on completion */ -#define D64_CTRL1_EOF ((uint32)1 << 30) /* end of frame */ -#define D64_CTRL1_SOF ((uint32)1 << 31) /* start of frame */ - -/* descriptor control flags 2 */ -#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count. real data len must <= 16KB */ -#define D64_CTRL2_AE 0x00030000 /* address extension bits */ -#define D64_CTRL2_AE_SHIFT 16 -#define D64_CTRL2_PARITY 0x00040000 /* parity bit */ - -/* 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, d11corerev >= 22 */ -#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */ - -/* receive frame status */ -typedef volatile struct { - uint16 len; - uint16 flags; -} dma_rxh_t; - -#endif /* _sbhnddma_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h deleted file mode 100644 index b48ef3bd974f..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbpcmcia.h 516206 2014-11-19 05:21:45Z $ - */ - -#ifndef _SBPCMCIA_H -#define _SBPCMCIA_H - -/* All the addresses that are offsets in attribute space are divided - * by two to account for the fact that odd bytes are invalid in - * attribute space and our read/write routines make the space appear - * as if they didn't exist. Still we want to show the original numbers - * as documented in the hnd_pcmcia core manual. - */ - -/* PCMCIA Function Configuration Registers */ -#define PCMCIA_FCR (0x700 / 2) - -#define FCR0_OFF 0 -#define FCR1_OFF (0x40 / 2) -#define FCR2_OFF (0x80 / 2) -#define FCR3_OFF (0xc0 / 2) - -#define PCMCIA_FCR0 (0x700 / 2) -#define PCMCIA_FCR1 (0x740 / 2) -#define PCMCIA_FCR2 (0x780 / 2) -#define PCMCIA_FCR3 (0x7c0 / 2) - -/* Standard PCMCIA FCR registers */ - -#define PCMCIA_COR 0 - -#define COR_RST 0x80 -#define COR_LEV 0x40 -#define COR_IRQEN 0x04 -#define COR_BLREN 0x01 -#define COR_FUNEN 0x01 - - -#define PCICIA_FCSR (2 / 2) -#define PCICIA_PRR (4 / 2) -#define PCICIA_SCR (6 / 2) -#define PCICIA_ESR (8 / 2) - - -#define PCM_MEMOFF 0x0000 -#define F0_MEMOFF 0x1000 -#define F1_MEMOFF 0x2000 -#define F2_MEMOFF 0x3000 -#define F3_MEMOFF 0x4000 - -/* Memory base in the function fcr's */ -#define MEM_ADDR0 (0x728 / 2) -#define MEM_ADDR1 (0x72a / 2) -#define MEM_ADDR2 (0x72c / 2) - -/* PCMCIA base plus Srom access in fcr0: */ -#define PCMCIA_ADDR0 (0x072e / 2) -#define PCMCIA_ADDR1 (0x0730 / 2) -#define PCMCIA_ADDR2 (0x0732 / 2) - -#define MEM_SEG (0x0734 / 2) -#define SROM_CS (0x0736 / 2) -#define SROM_DATAL (0x0738 / 2) -#define SROM_DATAH (0x073a / 2) -#define SROM_ADDRL (0x073c / 2) -#define SROM_ADDRH (0x073e / 2) -#define SROM_INFO2 (0x0772 / 2) /* Corerev >= 2 && <= 5 */ -#define SROM_INFO (0x07be / 2) /* Corerev >= 6 */ - -/* Values for srom_cs: */ -#define SROM_IDLE 0 -#define SROM_WRITE 1 -#define SROM_READ 2 -#define SROM_WEN 4 -#define SROM_WDS 7 -#define SROM_DONE 8 - -/* Fields in srom_info: */ -#define SRI_SZ_MASK 0x03 -#define SRI_BLANK 0x04 -#define SRI_OTP 0x80 - - -/* Standard tuples we know about */ - -#define CISTPL_NULL 0x00 -#define CISTPL_END 0xff /* End of the CIS tuple chain */ - - -#define CISTPL_BRCM_HNBU 0x80 - - -#define HNBU_BOARDREV 0x02 /* One byte board revision */ - - -#define HNBU_BOARDTYPE 0x1b /* 2 bytes; boardtype */ - - -#define HNBU_HNBUCIS 0x1d /* what follows is proprietary HNBU CIS format */ - - -/* sbtmstatelow */ -#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */ -#define SBTML_INT_EN 0x20000 /* enable sb interrupt */ - -/* sbtmstatehigh */ -#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */ - -#endif /* _SBPCMCIA_H */ diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h deleted file mode 100644 index 56e5f14fe34f..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sbsdio.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * SDIO device core hardware definitions. - * sdio is a portion of the pcmcia core in core rev 3 - rev 8 - * - * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbsdio.h 383835 2013-02-07 23:32:39Z $ - */ - -#ifndef _SBSDIO_H -#define _SBSDIO_H - -#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */ - -/* function 1 miscellaneous registers */ -#define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */ -#define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */ -#define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */ -#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */ -#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */ -#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */ -#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */ -#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */ -#define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */ -#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */ - -/* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */ -#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */ -#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */ -#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */ -#define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */ -#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */ -#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */ -#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */ -#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */ -#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */ -#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */ -#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D /* MesBusyCtl at 0x1001D (rev 11) */ - -#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ -#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ - -/* Sdio Core Rev 12 */ -#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E -#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1 -#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0 -#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2 -#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1 -#define SBSDIO_FUNC1_SLEEPCSR 0x1001F -#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1 -#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0 -#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1 -#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2 -#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1 - -/* SBSDIO_SPROM_CS */ -#define SBSDIO_SPROM_IDLE 0 -#define SBSDIO_SPROM_WRITE 1 -#define SBSDIO_SPROM_READ 2 -#define SBSDIO_SPROM_WEN 4 -#define SBSDIO_SPROM_WDS 7 -#define SBSDIO_SPROM_DONE 8 - -/* SBSDIO_SPROM_INFO */ -#define SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */ -#define SROM_BLANK 0x04 /* depreciated in corerev 6 */ -#define SROM_OTP 0x80 /* OTP present */ - -/* SBSDIO_CHIP_CTRL */ -#define SBSDIO_CHIP_CTRL_XTAL 0x01 /* or'd with onchip xtal_pu, - * 1: power on oscillator - * (for 4318 only) - */ -/* SBSDIO_WATERMARK */ -#define SBSDIO_WATERMARK_MASK 0x7f /* number of words - 1 for sd device - * to wait before sending data to host - */ - -/* SBSDIO_MESBUSYCTRL */ -/* When RX FIFO has less entries than this & MBE is set - * => busy signal is asserted between data blocks. -*/ -#define SBSDIO_MESBUSYCTRL_MASK 0x7f -#define SBSDIO_MESBUSYCTRL_ENAB 0x80 /* Enable busy capability for MES access */ - -/* SBSDIO_DEVICE_CTL */ -#define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when - * receiving CMD53 - */ -#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is - * synchronous to the sdio clock - */ -#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host - * except the chipActive (rev 8) - */ -#define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put - * external pads in tri-state; requires - * sdio bus power cycle to clear (rev 9) - */ -#define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ -#define SBSDIO_DEVCTL_F2WM_ENAB 0x10 /* Enable F2 Watermark */ -#define SBSDIO_DEVCTL_NONDAT_PADS_ISO 0x20 /* Isolate sdio clk and cmd (non-data) */ - -/* SBSDIO_FUNC1_CHIPCLKCSR */ -#define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */ -#define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */ -#define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */ -#define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */ -#define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */ -#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */ -#define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */ -#define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */ -/* In rev8, actual avail bits followed original docs */ -#define SBSDIO_Rev8_HT_AVAIL 0x40 -#define SBSDIO_Rev8_ALP_AVAIL 0x80 -#define SBSDIO_CSR_MASK 0x1F - -#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))) - -/* SBSDIO_FUNC1_SDIOPULLUP */ -#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */ -#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */ -#define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */ -#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */ -#define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */ - -/* function 1 OCP space */ -#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */ -#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 -#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */ - -/* some duplication with sbsdpcmdev.h here */ -/* 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 */ -#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ - -/* direct(mapped) cis space */ -#define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ -#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */ -#define SBSDIO_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP CIS */ - -#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */ - -#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple, - * link bytes - */ - -/* indirect cis access (in sprom) */ -#define SBSDIO_SPROM_CIS_OFFSET 0x8 /* 8 control bytes first, CIS starts from - * 8th byte - */ - -#define SBSDIO_BYTEMODE_DATALEN_MAX 64 /* sdio byte mode: maximum length of one - * data comamnd - */ - -#define SBSDIO_CORE_ADDR_MASK 0x1FFFF /* sdio core function one address mask */ - -#endif /* _SBSDIO_H */ diff --git a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h deleted file mode 100644 index f24d0a3c4e76..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific - * device core support - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbsdpcmdev.h 416730 2013-08-06 09:33:19Z $ - */ - -#ifndef _sbsdpcmdev_h_ -#define _sbsdpcmdev_h_ - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - - -typedef volatile struct { - dma64regs_t xmt; /* dma tx */ - uint32 PAD[2]; - dma64regs_t rcv; /* dma rx */ - uint32 PAD[2]; -} dma64p_t; - -/* dma64 sdiod corerev >= 1 */ -typedef volatile struct { - dma64p_t dma64regs[2]; - dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */ - uint32 PAD[92]; -} sdiodma64_t; - -/* dma32 sdiod corerev == 0 */ -typedef volatile struct { - dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ - dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */ - uint32 PAD[108]; -} sdiodma32_t; - -/* dma32 regs for pcmcia core */ -typedef volatile struct { - dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */ - dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */ - uint32 PAD[116]; -} pcmdma32_t; - -/* core registers */ -typedef volatile struct { - uint32 corecontrol; /* CoreControl, 0x000, rev8 */ - uint32 corestatus; /* CoreStatus, 0x004, rev8 */ - uint32 PAD[1]; - uint32 biststatus; /* BistStatus, 0x00c, rev8 */ - - /* PCMCIA access */ - uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */ - uint16 PAD[1]; - uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */ - uint16 PAD[1]; - uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */ - uint16 PAD[1]; - uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */ - uint16 PAD[1]; - - /* interrupt */ - uint32 intstatus; /* IntStatus, 0x020, rev8 */ - uint32 hostintmask; /* IntHostMask, 0x024, rev8 */ - uint32 intmask; /* IntSbMask, 0x028, rev8 */ - uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */ - uint32 sbintmask; /* SBIntMask, 0x030, rev8 */ - uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */ - uint32 PAD[2]; - uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */ - uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */ - uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */ - uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */ - - /* synchronized access to registers in SDIO clock domain */ - uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */ - uint32 PAD[3]; - - /* PCMCIA frame control */ - uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ - uint8 PAD[3]; - uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ - uint8 PAD[155]; - - /* interrupt batching control */ - uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */ - uint32 PAD[3]; - - /* counters */ - uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */ - uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */ - uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */ - uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */ - uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */ - uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */ - uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */ - uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */ - uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */ - uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */ - uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */ - uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */ - uint32 PAD[40]; - uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */ - uint32 PAD[7]; - - /* DMA engines */ - volatile union { - pcmdma32_t pcm32; - sdiodma32_t sdiod32; - sdiodma64_t sdiod64; - } dma; - - /* SDIO/PCMCIA CIS region */ - char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */ - - /* PCMCIA function control registers */ - char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */ - uint16 PAD[55]; - - /* PCMCIA backplane access */ - uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */ - uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */ - uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */ - uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */ - uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */ - uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */ - uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */ - uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */ - uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */ - uint16 PAD[31]; - - /* sprom "size" & "blank" info */ - uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */ - uint32 PAD[464]; - - /* Sonics SiliconBackplane registers */ - sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */ -} sdpcmd_regs_t; - -/* corecontrol */ -#define CC_CISRDY (1 << 0) /* CIS Ready */ -#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ -#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ -#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ -#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */ -#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */ - -/* corestatus */ -#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */ -#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */ -#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */ - -#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */ -#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */ -#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */ -#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */ - -/* 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 transitioned 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) /* DMA Errors */ -#define I_DMA (I_RI | I_XI | I_ERRORS) - -/* sbintstatus */ -#define I_SB_SERR (1 << 8) /* Backplane SError (write) */ -#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */ -#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */ - -/* sdioaccess */ -#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */ -#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */ -#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */ -#define SDA_WRITE 0x01000000 /* Write bit */ -#define SDA_READ 0x00000000 /* Write bit cleared for Read */ -#define SDA_BUSY 0x80000000 /* Busy bit */ - -/* sdioaccess-accessible register address spaces */ -#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */ -#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */ -#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */ -#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */ - -/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */ -#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */ -#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */ -#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */ -#define SDA_DEVICECONTROL 0x009 /* DeviceControl */ -#define SDA_SBADDRLOW 0x00a /* SbAddrLow */ -#define SDA_SBADDRMID 0x00b /* SbAddrMid */ -#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */ -#define SDA_FRAMECTRL 0x00d /* FrameCtrl */ -#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */ -#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */ -#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */ -#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */ -#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */ -#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */ - -/* SDA_F2WATERMARK */ -#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */ - -/* SDA_SBADDRLOW */ -#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */ - -/* SDA_SBADDRMID */ -#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */ - -/* SDA_SBADDRHIGH */ -#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */ - -/* 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) /* HW reports CRC error for write out of sync */ -#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */ - -/* pcmciaframectrl */ -#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */ -#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */ - -/* intrcvlazy */ -#define IRL_TO_MASK 0x00ffffff /* timeout */ -#define IRL_FC_MASK 0xff000000 /* frame count */ -#define IRL_FC_SHIFT 24 /* frame count */ - -/* rx header */ -typedef volatile struct { - uint16 len; - uint16 flags; -} sdpcmd_rxh_t; - -/* rx header flags */ -#define RXF_CRC 0x0001 /* CRC error detected */ -#define RXF_WOOS 0x0002 /* write frame out of sync */ -#define RXF_WF_TERM 0x0004 /* write frame terminated */ -#define RXF_ABORT 0x0008 /* write frame aborted */ -#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */ - -/* HW frame tag */ -#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ - -#define SDPCM_HWEXT_LEN 8 - -#endif /* _sbsdpcmdev_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/sbsocram.h b/drivers/net/wireless/bcmdhd/include/sbsocram.h deleted file mode 100644 index 900c001eea4a..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sbsocram.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * BCM47XX Sonics SiliconBackplane embedded ram core - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbsocram.h 481602 2014-05-29 22:43:34Z $ - */ - -#ifndef _SBSOCRAM_H -#define _SBSOCRAM_H - -#ifndef _LANGUAGE_ASSEMBLY - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - -/* Memcsocram core registers */ -typedef volatile struct sbsocramregs { - uint32 coreinfo; - uint32 bwalloc; - uint32 extracoreinfo; - uint32 biststat; - uint32 bankidx; - uint32 standbyctrl; - - uint32 errlogstatus; /* rev 6 */ - uint32 errlogaddr; /* rev 6 */ - /* used for patching rev 3 & 5 */ - uint32 cambankidx; - uint32 cambankstandbyctrl; - uint32 cambankpatchctrl; - uint32 cambankpatchtblbaseaddr; - uint32 cambankcmdreg; - uint32 cambankdatareg; - uint32 cambankmaskreg; - uint32 PAD[1]; - uint32 bankinfo; /* corev 8 */ - uint32 bankpda; - uint32 PAD[14]; - uint32 extmemconfig; - uint32 extmemparitycsr; - uint32 extmemparityerrdata; - uint32 extmemparityerrcnt; - uint32 extmemwrctrlandsize; - uint32 PAD[84]; - uint32 workaround; - uint32 pwrctl; /* corerev >= 2 */ - uint32 PAD[133]; - uint32 sr_control; /* corerev >= 15 */ - uint32 sr_status; /* corerev >= 15 */ - uint32 sr_address; /* corerev >= 15 */ - uint32 sr_data; /* corerev >= 15 */ -} sbsocramregs_t; - -#endif /* _LANGUAGE_ASSEMBLY */ - -/* Register offsets */ -#define SR_COREINFO 0x00 -#define SR_BWALLOC 0x04 -#define SR_BISTSTAT 0x0c -#define SR_BANKINDEX 0x10 -#define SR_BANKSTBYCTL 0x14 -#define SR_PWRCTL 0x1e8 - -/* Coreinfo register */ -#define SRCI_PT_MASK 0x00070000 /* corerev >= 6; port type[18:16] */ -#define SRCI_PT_SHIFT 16 -/* port types : SRCI_PT__ */ -#define SRCI_PT_OCP_OCP 0 -#define SRCI_PT_AXI_OCP 1 -#define SRCI_PT_ARM7AHB_OCP 2 -#define SRCI_PT_CM3AHB_OCP 3 -#define SRCI_PT_AXI_AXI 4 -#define SRCI_PT_AHB_AXI 5 -/* corerev >= 3 */ -#define SRCI_LSS_MASK 0x00f00000 -#define SRCI_LSS_SHIFT 20 -#define SRCI_LRS_MASK 0x0f000000 -#define SRCI_LRS_SHIFT 24 - -/* In corerev 0, the memory size is 2 to the power of the - * base plus 16 plus to the contents of the memsize field plus 1. - */ -#define SRCI_MS0_MASK 0xf -#define SR_MS0_BASE 16 - -/* - * In corerev 1 the bank size is 2 ^ the bank size field plus 14, - * the memory size is number of banks times bank size. - * The same applies to rom size. - */ -#define SRCI_ROMNB_MASK 0xf000 -#define SRCI_ROMNB_SHIFT 12 -#define SRCI_ROMBSZ_MASK 0xf00 -#define SRCI_ROMBSZ_SHIFT 8 -#define SRCI_SRNB_MASK 0xf0 -#define SRCI_SRNB_SHIFT 4 -#define SRCI_SRBSZ_MASK 0xf -#define SRCI_SRBSZ_SHIFT 0 - -#define SR_BSZ_BASE 14 - -/* Standby control register */ -#define SRSC_SBYOVR_MASK 0x80000000 -#define SRSC_SBYOVR_SHIFT 31 -#define SRSC_SBYOVRVAL_MASK 0x60000000 -#define SRSC_SBYOVRVAL_SHIFT 29 -#define SRSC_SBYEN_MASK 0x01000000 /* rev >= 3 */ -#define SRSC_SBYEN_SHIFT 24 - -/* Power control register */ -#define SRPC_PMU_STBYDIS_MASK 0x00000010 /* rev >= 3 */ -#define SRPC_PMU_STBYDIS_SHIFT 4 -#define SRPC_STBYOVRVAL_MASK 0x00000008 -#define SRPC_STBYOVRVAL_SHIFT 3 -#define SRPC_STBYOVR_MASK 0x00000007 -#define SRPC_STBYOVR_SHIFT 0 - -/* Extra core capability register */ -#define SRECC_NUM_BANKS_MASK 0x000000F0 -#define SRECC_NUM_BANKS_SHIFT 4 -#define SRECC_BANKSIZE_MASK 0x0000000F -#define SRECC_BANKSIZE_SHIFT 0 - -#define SRECC_BANKSIZE(value) (1 << (value)) - -/* CAM bank patch control */ -#define SRCBPC_PATCHENABLE 0x80000000 - -#define SRP_ADDRESS 0x0001FFFC -#define SRP_VALID 0x8000 - -/* CAM bank command reg */ -#define SRCMD_WRITE 0x00020000 -#define SRCMD_READ 0x00010000 -#define SRCMD_DONE 0x80000000 - -#define SRCMD_DONE_DLY 1000 - -/* bankidx and bankinfo reg defines corerev >= 8 */ -#define SOCRAM_BANKINFO_SZMASK 0x7f -#define SOCRAM_BANKIDX_ROM_MASK 0x100 - -#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 -/* socram bankinfo memtype */ -#define SOCRAM_MEMTYPE_RAM 0 -#define SOCRAM_MEMTYPE_R0M 1 -#define SOCRAM_MEMTYPE_DEVRAM 2 - -#define SOCRAM_BANKINFO_REG 0x40 -#define SOCRAM_BANKIDX_REG 0x10 -#define SOCRAM_BANKINFO_STDBY_MASK 0x400 -#define SOCRAM_BANKINFO_STDBY_TIMER 0x800 - -/* bankinfo rev >= 10 */ -#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13 -#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000 -#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14 -#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000 -#define SOCRAM_BANKINFO_SLPSUPP_SHIFT 15 -#define SOCRAM_BANKINFO_SLPSUPP_MASK 0x8000 -#define SOCRAM_BANKINFO_RETNTRAM_SHIFT 16 -#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 -#define SOCRAM_BANKINFO_PDASZ_SHIFT 17 -#define SOCRAM_BANKINFO_PDASZ_MASK 0x003E0000 -#define SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT 24 -#define SOCRAM_BANKINFO_DEVRAMREMAP_MASK 0x01000000 - -/* extracoreinfo register */ -#define SOCRAM_DEVRAMBANK_MASK 0xF000 -#define SOCRAM_DEVRAMBANK_SHIFT 12 - -/* bank info to calculate bank size */ -#define SOCRAM_BANKINFO_SZBASE 8192 -#define SOCRAM_BANKSIZE_SHIFT 13 /* SOCRAM_BANKINFO_SZBASE */ - - -#endif /* _SBSOCRAM_H */ diff --git a/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd/include/sdio.h deleted file mode 100644 index 8bebba9d2981..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sdio.h +++ /dev/null @@ -1,622 +0,0 @@ -/* - * SDIO spec header file - * Protocol and standard (common) device definitions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sdio.h 416730 2013-08-06 09:33:19Z $ - */ - -#ifndef _SDIO_H -#define _SDIO_H - -#ifdef BCMSDIO - -/* CCCR structure for function 0 */ -typedef volatile struct { - uint8 cccr_sdio_rev; /* RO, cccr and sdio revision */ - uint8 sd_rev; /* RO, sd spec revision */ - uint8 io_en; /* I/O enable */ - uint8 io_rdy; /* I/O ready reg */ - uint8 intr_ctl; /* Master and per function interrupt enable control */ - uint8 intr_status; /* RO, interrupt pending status */ - uint8 io_abort; /* read/write abort or reset all functions */ - uint8 bus_inter; /* bus interface control */ - uint8 capability; /* RO, card capability */ - - uint8 cis_base_low; /* 0x9 RO, common CIS base address, LSB */ - uint8 cis_base_mid; - uint8 cis_base_high; /* 0xB RO, common CIS base address, MSB */ - - /* suspend/resume registers */ - uint8 bus_suspend; /* 0xC */ - uint8 func_select; /* 0xD */ - uint8 exec_flag; /* 0xE */ - uint8 ready_flag; /* 0xF */ - - uint8 fn0_blk_size[2]; /* 0x10(LSB), 0x11(MSB) */ - - uint8 power_control; /* 0x12 (SDIO version 1.10) */ - - uint8 speed_control; /* 0x13 */ -} sdio_regs_t; - -/* SDIO Device CCCR offsets */ -#define SDIOD_CCCR_REV 0x00 -#define SDIOD_CCCR_SDREV 0x01 -#define SDIOD_CCCR_IOEN 0x02 -#define SDIOD_CCCR_IORDY 0x03 -#define SDIOD_CCCR_INTEN 0x04 -#define SDIOD_CCCR_INTPEND 0x05 -#define SDIOD_CCCR_IOABORT 0x06 -#define SDIOD_CCCR_BICTRL 0x07 -#define SDIOD_CCCR_CAPABLITIES 0x08 -#define SDIOD_CCCR_CISPTR_0 0x09 -#define SDIOD_CCCR_CISPTR_1 0x0A -#define SDIOD_CCCR_CISPTR_2 0x0B -#define SDIOD_CCCR_BUSSUSP 0x0C -#define SDIOD_CCCR_FUNCSEL 0x0D -#define SDIOD_CCCR_EXECFLAGS 0x0E -#define SDIOD_CCCR_RDYFLAGS 0x0F -#define SDIOD_CCCR_BLKSIZE_0 0x10 -#define SDIOD_CCCR_BLKSIZE_1 0x11 -#define SDIOD_CCCR_POWER_CONTROL 0x12 -#define SDIOD_CCCR_SPEED_CONTROL 0x13 -#define SDIOD_CCCR_UHSI_SUPPORT 0x14 -#define SDIOD_CCCR_DRIVER_STRENGTH 0x15 -#define SDIOD_CCCR_INTR_EXTN 0x16 - -/* Broadcom extensions (corerev >= 1) */ -#define SDIOD_CCCR_BRCM_CARDCAP 0xf0 -#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02 -#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04 -#define SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08 -#define SDIOD_CCCR_BRCM_CARDCTL 0xf1 -#define SDIOD_CCCR_BRCM_SEPINT 0xf2 - -/* cccr_sdio_rev */ -#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */ -#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */ -#define SDIO_SPEC_VERSION_3_0 0x40 /* SDIO spec version 3.0 */ - -/* sd_rev */ -#define SD_REV_PHY_MASK 0x0f /* SD format version number */ - -/* io_en */ -#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */ -#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */ - -/* io_rdys */ -#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */ -#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */ - -/* intr_ctl */ -#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */ -#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */ -#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */ - -/* intr_status */ -#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */ -#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */ - -/* io_abort */ -#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */ -#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */ - -/* bus_inter */ -#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */ -#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */ -#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */ -#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */ -#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */ -#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */ - -/* capability */ -#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */ -#define SDIO_CAP_LSC 0x40 /* low speed card */ -#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */ -#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */ -#define SDIO_CAP_SBS 0x08 /* support suspend/resume */ -#define SDIO_CAP_SRW 0x04 /* support read wait */ -#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */ -#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */ - -/* power_control */ -#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */ -#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */ - -/* speed_control (control device entry into high-speed clocking mode) */ -#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */ -#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */ -#define SDIO_SPEED_UHSI_DDR50 0x08 - -/* for setting bus speed in card: 0x13h */ -#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3) -#define SDIO_BUS_SPEED_UHSISEL_S 1 - -/* for getting bus speed cap in card: 0x14h */ -#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3) -#define SDIO_BUS_SPEED_UHSICAP_S 0 - -/* for getting driver type CAP in card: 0x15h */ -#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3) -#define SDIO_BUS_DRVR_TYPE_CAP_S 0 - -/* for setting driver type selection in card: 0x15h */ -#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2) -#define SDIO_BUS_DRVR_TYPE_SEL_S 4 - -/* for getting async int support in card: 0x16h */ -#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1) -#define SDIO_BUS_ASYNCINT_CAP_S 0 - -/* for setting async int selection in card: 0x16h */ -#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1) -#define SDIO_BUS_ASYNCINT_SEL_S 1 - -/* brcm sepint */ -#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */ -#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */ -#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */ - -/* FBR structure for function 1-7, FBR addresses and register offsets */ -typedef volatile struct { - uint8 devctr; /* device interface, CSA control */ - uint8 ext_dev; /* extended standard I/O device type code */ - uint8 pwr_sel; /* power selection support */ - uint8 PAD[6]; /* reserved */ - - uint8 cis_low; /* CIS LSB */ - uint8 cis_mid; - uint8 cis_high; /* CIS MSB */ - uint8 csa_low; /* code storage area, LSB */ - uint8 csa_mid; - uint8 csa_high; /* code storage area, MSB */ - uint8 csa_dat_win; /* data access window to function */ - - uint8 fnx_blk_size[2]; /* block size, little endian */ -} sdio_fbr_t; - -/* Maximum number of I/O funcs */ -#define SDIOD_MAX_FUNCS 8 -#define SDIOD_MAX_IOFUNCS 7 - -/* SDIO Device FBR Start Address */ -#define SDIOD_FBR_STARTADDR 0x100 - -/* SDIO Device FBR Size */ -#define SDIOD_FBR_SIZE 0x100 - -/* Macro to calculate FBR register base */ -#define SDIOD_FBR_BASE(n) ((n) * 0x100) - -/* Function register offsets */ -#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */ -#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */ -#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */ - -/* SDIO Function CIS ptr offset */ -#define SDIOD_FBR_CISPTR_0 0x09 -#define SDIOD_FBR_CISPTR_1 0x0A -#define SDIOD_FBR_CISPTR_2 0x0B - -/* Code Storage Area pointer */ -#define SDIOD_FBR_CSA_ADDR_0 0x0C -#define SDIOD_FBR_CSA_ADDR_1 0x0D -#define SDIOD_FBR_CSA_ADDR_2 0x0E -#define SDIOD_FBR_CSA_DATA 0x0F - -/* SDIO Function I/O Block Size */ -#define SDIOD_FBR_BLKSIZE_0 0x10 -#define SDIOD_FBR_BLKSIZE_1 0x11 - -/* devctr */ -#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */ -#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */ -#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */ -/* interface codes */ -#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */ -#define SDIOD_DIC_UART 1 -#define SDIOD_DIC_BLUETOOTH_A 2 -#define SDIOD_DIC_BLUETOOTH_B 3 -#define SDIOD_DIC_GPS 4 -#define SDIOD_DIC_CAMERA 5 -#define SDIOD_DIC_PHS 6 -#define SDIOD_DIC_WLAN 7 -#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */ - -/* pwr_sel */ -#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */ -#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */ - -/* misc defines */ -#define SDIO_FUNC_0 0 -#define SDIO_FUNC_1 1 -#define SDIO_FUNC_2 2 -#define SDIO_FUNC_3 3 -#define SDIO_FUNC_4 4 -#define SDIO_FUNC_5 5 -#define SDIO_FUNC_6 6 -#define SDIO_FUNC_7 7 - -#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */ -#define SD_CARD_TYPE_IO 1 /* IO only card */ -#define SD_CARD_TYPE_MEMORY 2 /* memory only card */ -#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */ - -#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */ -#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */ - -/* Card registers: status bit position */ -#define CARDREG_STATUS_BIT_OUTOFRANGE 31 -#define CARDREG_STATUS_BIT_COMCRCERROR 23 -#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22 -#define CARDREG_STATUS_BIT_ERROR 19 -#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12 -#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11 -#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10 -#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9 -#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4 - - - -#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */ -#define SD_CMD_SEND_OPCOND 1 -#define SD_CMD_MMC_SET_RCA 3 -#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */ -#define SD_CMD_SELECT_DESELECT_CARD 7 -#define SD_CMD_SEND_CSD 9 -#define SD_CMD_SEND_CID 10 -#define SD_CMD_STOP_TRANSMISSION 12 -#define SD_CMD_SEND_STATUS 13 -#define SD_CMD_GO_INACTIVE_STATE 15 -#define SD_CMD_SET_BLOCKLEN 16 -#define SD_CMD_READ_SINGLE_BLOCK 17 -#define SD_CMD_READ_MULTIPLE_BLOCK 18 -#define SD_CMD_WRITE_BLOCK 24 -#define SD_CMD_WRITE_MULTIPLE_BLOCK 25 -#define SD_CMD_PROGRAM_CSD 27 -#define SD_CMD_SET_WRITE_PROT 28 -#define SD_CMD_CLR_WRITE_PROT 29 -#define SD_CMD_SEND_WRITE_PROT 30 -#define SD_CMD_ERASE_WR_BLK_START 32 -#define SD_CMD_ERASE_WR_BLK_END 33 -#define SD_CMD_ERASE 38 -#define SD_CMD_LOCK_UNLOCK 42 -#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */ -#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */ -#define SD_CMD_APP_CMD 55 -#define SD_CMD_GEN_CMD 56 -#define SD_CMD_READ_OCR 58 -#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */ -#define SD_ACMD_SD_STATUS 13 -#define SD_ACMD_SEND_NUM_WR_BLOCKS 22 -#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23 -#define SD_ACMD_SD_SEND_OP_COND 41 -#define SD_ACMD_SET_CLR_CARD_DETECT 42 -#define SD_ACMD_SEND_SCR 51 - -/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */ -#define SD_IO_OP_READ 0 /* Read_Write: Read */ -#define SD_IO_OP_WRITE 1 /* Read_Write: Write */ -#define SD_IO_RW_NORMAL 0 /* no RAW */ -#define SD_IO_RW_RAW 1 /* RAW */ -#define SD_IO_BYTE_MODE 0 /* Byte Mode */ -#define SD_IO_BLOCK_MODE 1 /* BlockMode */ -#define SD_IO_FIXED_ADDRESS 0 /* fix Address */ -#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */ - -/* build SD_CMD_IO_RW_DIRECT Argument */ -#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \ - ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \ - (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF)) - -/* build SD_CMD_IO_RW_EXTENDED Argument */ -#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \ - ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \ - (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF)) - -/* SDIO response parameters */ -#define SD_RSP_NO_NONE 0 -#define SD_RSP_NO_1 1 -#define SD_RSP_NO_2 2 -#define SD_RSP_NO_3 3 -#define SD_RSP_NO_4 4 -#define SD_RSP_NO_5 5 -#define SD_RSP_NO_6 6 - - /* Modified R6 response (to CMD3) */ -#define SD_RSP_MR6_COM_CRC_ERROR 0x8000 -#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000 -#define SD_RSP_MR6_ERROR 0x2000 - - /* Modified R1 in R4 Response (to CMD5) */ -#define SD_RSP_MR1_SBIT 0x80 -#define SD_RSP_MR1_PARAMETER_ERROR 0x40 -#define SD_RSP_MR1_RFU5 0x20 -#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10 -#define SD_RSP_MR1_COM_CRC_ERROR 0x08 -#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04 -#define SD_RSP_MR1_RFU1 0x02 -#define SD_RSP_MR1_IDLE_STATE 0x01 - - /* R5 response (to CMD52 and CMD53) */ -#define SD_RSP_R5_COM_CRC_ERROR 0x80 -#define SD_RSP_R5_ILLEGAL_COMMAND 0x40 -#define SD_RSP_R5_IO_CURRENTSTATE1 0x20 -#define SD_RSP_R5_IO_CURRENTSTATE0 0x10 -#define SD_RSP_R5_ERROR 0x08 -#define SD_RSP_R5_RFU 0x04 -#define SD_RSP_R5_FUNC_NUM_ERROR 0x02 -#define SD_RSP_R5_OUT_OF_RANGE 0x01 - -#define SD_RSP_R5_ERRBITS 0xCB - - -/* ------------------------------------------------ - * SDIO Commands and responses - * - * I/O only commands are: - * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53 - * ------------------------------------------------ - */ - -/* SDIO Commands */ -#define SDIOH_CMD_0 0 -#define SDIOH_CMD_3 3 -#define SDIOH_CMD_5 5 -#define SDIOH_CMD_7 7 -#define SDIOH_CMD_11 11 -#define SDIOH_CMD_14 14 -#define SDIOH_CMD_15 15 -#define SDIOH_CMD_19 19 -#define SDIOH_CMD_52 52 -#define SDIOH_CMD_53 53 -#define SDIOH_CMD_59 59 - -/* SDIO Command Responses */ -#define SDIOH_RSP_NONE 0 -#define SDIOH_RSP_R1 1 -#define SDIOH_RSP_R2 2 -#define SDIOH_RSP_R3 3 -#define SDIOH_RSP_R4 4 -#define SDIOH_RSP_R5 5 -#define SDIOH_RSP_R6 6 - -/* - * SDIO Response Error flags - */ -#define SDIOH_RSP5_ERROR_FLAGS 0xCB - -/* ------------------------------------------------ - * SDIO Command structures. I/O only commands are: - * - * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53 - * ------------------------------------------------ - */ - -#define CMD5_OCR_M BITFIELD_MASK(24) -#define CMD5_OCR_S 0 - -#define CMD5_S18R_M BITFIELD_MASK(1) -#define CMD5_S18R_S 24 - -#define CMD7_RCA_M BITFIELD_MASK(16) -#define CMD7_RCA_S 16 - -#define CMD14_RCA_M BITFIELD_MASK(16) -#define CMD14_RCA_S 16 -#define CMD14_SLEEP_M BITFIELD_MASK(1) -#define CMD14_SLEEP_S 15 - -#define CMD_15_RCA_M BITFIELD_MASK(16) -#define CMD_15_RCA_S 16 - -#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52 - */ -#define CMD52_DATA_S 0 -#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ -#define CMD52_REG_ADDR_S 9 -#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */ -#define CMD52_RAW_S 27 -#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ -#define CMD52_FUNCTION_S 28 -#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ -#define CMD52_RW_FLAG_S 31 - - -#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */ -#define CMD53_BYTE_BLK_CNT_S 0 -#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ -#define CMD53_REG_ADDR_S 9 -#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */ -#define CMD53_OP_CODE_S 26 -#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */ -#define CMD53_BLK_MODE_S 27 -#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ -#define CMD53_FUNCTION_S 28 -#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ -#define CMD53_RW_FLAG_S 31 - -/* ------------------------------------------------------ - * SDIO Command Response structures for SD1 and SD4 modes - * ----------------------------------------------------- - */ -#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */ -#define RSP4_IO_OCR_S 0 - -#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */ -#define RSP4_S18A_S 24 - -#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */ -#define RSP4_STUFF_S 24 -#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */ -#define RSP4_MEM_PRESENT_S 27 -#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */ -#define RSP4_NUM_FUNCS_S 28 -#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */ -#define RSP4_CARD_READY_S 31 - -#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0] - */ -#define RSP6_STATUS_S 0 -#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */ -#define RSP6_IO_RCA_S 16 - -#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */ -#define RSP1_AKE_SEQ_ERROR_S 3 -#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ -#define RSP1_APP_CMD_S 5 -#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */ -#define RSP1_READY_FOR_DATA_S 8 -#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card - * when Cmd was received - */ -#define RSP1_CURR_STATE_S 9 -#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */ -#define RSP1_EARSE_RESET_S 13 -#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */ -#define RSP1_CARD_ECC_DISABLE_S 14 -#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */ -#define RSP1_WP_ERASE_SKIP_S 15 -#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits - * of CSD - */ -#define RSP1_CID_CSD_OVERW_S 16 -#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */ -#define RSP1_ERROR_S 19 -#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */ -#define RSP1_CC_ERROR_S 20 -#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed - * to correct data - */ -#define RSP1_CARD_ECC_FAILED_S 21 -#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */ -#define RSP1_ILLEGAL_CMD_S 22 -#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed - */ -#define RSP1_COM_CRC_ERROR_S 23 -#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */ -#define RSP1_LOCK_UNLOCK_FAIL_S 24 -#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */ -#define RSP1_CARD_LOCKED_S 25 -#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program - * write-protected blocks - */ -#define RSP1_WP_VIOLATION_S 26 -#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */ -#define RSP1_ERASE_PARAM_S 27 -#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */ -#define RSP1_ERASE_SEQ_ERR_S 28 -#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */ -#define RSP1_BLK_LEN_ERR_S 29 -#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */ -#define RSP1_ADDR_ERR_S 30 -#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */ -#define RSP1_OUT_OF_RANGE_S 31 - - -#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */ -#define RSP5_DATA_S 0 -#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */ -#define RSP5_FLAGS_S 8 -#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */ -#define RSP5_STUFF_S 16 - -/* ---------------------------------------------- - * SDIO Command Response structures for SPI mode - * ---------------------------------------------- - */ -#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */ -#define SPIRSP4_IO_OCR_S 0 -#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */ -#define SPIRSP4_STUFF_S 16 -#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */ -#define SPIRSP4_MEM_PRESENT_S 19 -#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */ -#define SPIRSP4_NUM_FUNCS_S 20 -#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */ -#define SPIRSP4_CARD_READY_S 23 -#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */ -#define SPIRSP4_IDLE_STATE_S 24 -#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ -#define SPIRSP4_ILLEGAL_CMD_S 26 -#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ -#define SPIRSP4_COM_CRC_ERROR_S 27 -#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error - */ -#define SPIRSP4_FUNC_NUM_ERROR_S 28 -#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ -#define SPIRSP4_PARAM_ERROR_S 30 -#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ -#define SPIRSP4_START_BIT_S 31 - -#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */ -#define SPIRSP5_DATA_S 16 -#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */ -#define SPIRSP5_IDLE_STATE_S 24 -#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ -#define SPIRSP5_ILLEGAL_CMD_S 26 -#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ -#define SPIRSP5_COM_CRC_ERROR_S 27 -#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error - */ -#define SPIRSP5_FUNC_NUM_ERROR_S 28 -#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ -#define SPIRSP5_PARAM_ERROR_S 30 -#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ -#define SPIRSP5_START_BIT_S 31 - -/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */ -#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error - */ -#define RSP6STAT_AKE_SEQ_ERROR_S 3 -#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ -#define RSP6STAT_APP_CMD_S 5 -#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data - * (buff empty) - */ -#define RSP6STAT_READY_FOR_DATA_S 8 -#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at - * Cmd reception - */ -#define RSP6STAT_CURR_STATE_S 9 -#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19 - */ -#define RSP6STAT_ERROR_S 13 -#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for - * card state Bit 22 - */ -#define RSP6STAT_ILLEGAL_CMD_S 14 -#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command - * failed Bit 23 - */ -#define RSP6STAT_COM_CRC_ERROR_S 15 - -#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ -#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE - -/* command issue options */ -#define CMD_OPTION_DEFAULT 0 -#define CMD_OPTION_TUNING 1 - -#endif /* def BCMSDIO */ -#endif /* _SDIO_H */ diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd/include/sdioh.h deleted file mode 100644 index 62a5c4cc3179..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sdioh.h +++ /dev/null @@ -1,445 +0,0 @@ -/* - * SDIO Host Controller Spec header file - * Register map and definitions for the Standard Host Controller - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sdioh.h 345499 2012-07-18 06:59:05Z $ - */ - -#ifndef _SDIOH_H -#define _SDIOH_H - -#define SD_SysAddr 0x000 -#define SD_BlockSize 0x004 -#define SD_BlockCount 0x006 -#define SD_Arg0 0x008 -#define SD_Arg1 0x00A -#define SD_TransferMode 0x00C -#define SD_Command 0x00E -#define SD_Response0 0x010 -#define SD_Response1 0x012 -#define SD_Response2 0x014 -#define SD_Response3 0x016 -#define SD_Response4 0x018 -#define SD_Response5 0x01A -#define SD_Response6 0x01C -#define SD_Response7 0x01E -#define SD_BufferDataPort0 0x020 -#define SD_BufferDataPort1 0x022 -#define SD_PresentState 0x024 -#define SD_HostCntrl 0x028 -#define SD_PwrCntrl 0x029 -#define SD_BlockGapCntrl 0x02A -#define SD_WakeupCntrl 0x02B -#define SD_ClockCntrl 0x02C -#define SD_TimeoutCntrl 0x02E -#define SD_SoftwareReset 0x02F -#define SD_IntrStatus 0x030 -#define SD_ErrorIntrStatus 0x032 -#define SD_IntrStatusEnable 0x034 -#define SD_ErrorIntrStatusEnable 0x036 -#define SD_IntrSignalEnable 0x038 -#define SD_ErrorIntrSignalEnable 0x03A -#define SD_CMD12ErrorStatus 0x03C -#define SD_Capabilities 0x040 -#define SD_Capabilities3 0x044 -#define SD_MaxCurCap 0x048 -#define SD_MaxCurCap_Reserved 0x04C -#define SD_ADMA_ErrStatus 0x054 -#define SD_ADMA_SysAddr 0x58 -#define SD_SlotInterruptStatus 0x0FC -#define SD_HostControllerVersion 0x0FE -#define SD_GPIO_Reg 0x100 -#define SD_GPIO_OE 0x104 -#define SD_GPIO_Enable 0x108 - -/* SD specific registers in PCI config space */ -#define SD_SlotInfo 0x40 - -/* HC 3.0 specific registers and offsets */ -#define SD3_HostCntrl2 0x03E -/* preset regsstart and count */ -#define SD3_PresetValStart 0x060 -#define SD3_PresetValCount 8 -/* preset-indiv regs */ -#define SD3_PresetVal_init 0x060 -#define SD3_PresetVal_default 0x062 -#define SD3_PresetVal_HS 0x064 -#define SD3_PresetVal_SDR12 0x066 -#define SD3_PresetVal_SDR25 0x068 -#define SD3_PresetVal_SDR50 0x06a -#define SD3_PresetVal_SDR104 0x06c -#define SD3_PresetVal_DDR50 0x06e -/* SDIO3.0 Revx specific Registers */ -#define SD3_Tuning_Info_Register 0x0EC -#define SD3_WL_BT_reset_register 0x0F0 - - -/* preset value indices */ -#define SD3_PRESETVAL_INITIAL_IX 0 -#define SD3_PRESETVAL_DESPEED_IX 1 -#define SD3_PRESETVAL_HISPEED_IX 2 -#define SD3_PRESETVAL_SDR12_IX 3 -#define SD3_PRESETVAL_SDR25_IX 4 -#define SD3_PRESETVAL_SDR50_IX 5 -#define SD3_PRESETVAL_SDR104_IX 6 -#define SD3_PRESETVAL_DDR50_IX 7 - -/* SD_Capabilities reg (0x040) */ -#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6) -#define CAP_TO_CLKFREQ_S 0 -#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1) -#define CAP_TO_CLKUNIT_S 7 -/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2 - bits are reserved. going ahead with 8 bits, as it is req for 3.0 -*/ -#define CAP_BASECLK_M BITFIELD_MASK(8) -#define CAP_BASECLK_S 8 -#define CAP_MAXBLOCK_M BITFIELD_MASK(2) -#define CAP_MAXBLOCK_S 16 -#define CAP_ADMA2_M BITFIELD_MASK(1) -#define CAP_ADMA2_S 19 -#define CAP_ADMA1_M BITFIELD_MASK(1) -#define CAP_ADMA1_S 20 -#define CAP_HIGHSPEED_M BITFIELD_MASK(1) -#define CAP_HIGHSPEED_S 21 -#define CAP_DMA_M BITFIELD_MASK(1) -#define CAP_DMA_S 22 -#define CAP_SUSPEND_M BITFIELD_MASK(1) -#define CAP_SUSPEND_S 23 -#define CAP_VOLT_3_3_M BITFIELD_MASK(1) -#define CAP_VOLT_3_3_S 24 -#define CAP_VOLT_3_0_M BITFIELD_MASK(1) -#define CAP_VOLT_3_0_S 25 -#define CAP_VOLT_1_8_M BITFIELD_MASK(1) -#define CAP_VOLT_1_8_S 26 -#define CAP_64BIT_HOST_M BITFIELD_MASK(1) -#define CAP_64BIT_HOST_S 28 - -#define SDIO_OCR_READ_FAIL (2) - - -#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1) -#define CAP_ASYNCINT_SUP_S 29 - -#define CAP_SLOTTYPE_M BITFIELD_MASK(2) -#define CAP_SLOTTYPE_S 30 - -#define CAP3_MSBits_OFFSET (32) -/* note: following are caps MSB32 bits. - So the bits start from 0, instead of 32. that is why - CAP3_MSBits_OFFSET is subtracted. -*/ -#define CAP3_SDR50_SUP_M BITFIELD_MASK(1) -#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET) - -#define CAP3_SDR104_SUP_M BITFIELD_MASK(1) -#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET) - -#define CAP3_DDR50_SUP_M BITFIELD_MASK(1) -#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET) - -/* for knowing the clk caps in a single read */ -#define CAP3_30CLKCAP_M BITFIELD_MASK(3) -#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET) - -#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1) -#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET) - -#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1) -#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET) - -#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1) -#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET) - -#define CAP3_RETUNING_TC_M BITFIELD_MASK(4) -#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET) - -#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1) -#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET) - -#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2) -#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET) - -#define CAP3_CLK_MULT_M BITFIELD_MASK(8) -#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET) - -#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2) -#define PRESET_DRIVR_SELECT_S 14 - -#define PRESET_CLK_DIV_M BITFIELD_MASK(10) -#define PRESET_CLK_DIV_S 0 - -/* SD_MaxCurCap reg (0x048) */ -#define CAP_CURR_3_3_M BITFIELD_MASK(8) -#define CAP_CURR_3_3_S 0 -#define CAP_CURR_3_0_M BITFIELD_MASK(8) -#define CAP_CURR_3_0_S 8 -#define CAP_CURR_1_8_M BITFIELD_MASK(8) -#define CAP_CURR_1_8_S 16 - -/* SD_SysAddr: Offset 0x0000, Size 4 bytes */ - -/* SD_BlockSize: Offset 0x004, Size 2 bytes */ -#define BLKSZ_BLKSZ_M BITFIELD_MASK(12) -#define BLKSZ_BLKSZ_S 0 -#define BLKSZ_BNDRY_M BITFIELD_MASK(3) -#define BLKSZ_BNDRY_S 12 - -/* SD_BlockCount: Offset 0x006, size 2 bytes */ - -/* SD_Arg0: Offset 0x008, size = 4 bytes */ -/* SD_TransferMode Offset 0x00C, size = 2 bytes */ -#define XFER_DMA_ENABLE_M BITFIELD_MASK(1) -#define XFER_DMA_ENABLE_S 0 -#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1) -#define XFER_BLK_COUNT_EN_S 1 -#define XFER_CMD_12_EN_M BITFIELD_MASK(1) -#define XFER_CMD_12_EN_S 2 -#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1) -#define XFER_DATA_DIRECTION_S 4 -#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1) -#define XFER_MULTI_BLOCK_S 5 - -/* SD_Command: Offset 0x00E, size = 2 bytes */ -/* resp_type field */ -#define RESP_TYPE_NONE 0 -#define RESP_TYPE_136 1 -#define RESP_TYPE_48 2 -#define RESP_TYPE_48_BUSY 3 -/* type field */ -#define CMD_TYPE_NORMAL 0 -#define CMD_TYPE_SUSPEND 1 -#define CMD_TYPE_RESUME 2 -#define CMD_TYPE_ABORT 3 - -#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */ -#define CMD_RESP_TYPE_S 0 -#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */ -#define CMD_CRC_EN_S 3 -#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */ -#define CMD_INDEX_EN_S 4 -#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */ -#define CMD_DATA_EN_S 5 -#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc - */ -#define CMD_TYPE_S 6 -#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */ -#define CMD_INDEX_S 8 - -/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */ -/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */ -/* SD_PresentState : Offset 0x024, size = 4 bytes */ -#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */ -#define PRES_CMD_INHIBIT_S 0 -#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */ -#define PRES_DAT_INHIBIT_S 1 -#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */ -#define PRES_DAT_BUSY_S 2 -#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */ -#define PRES_PRESENT_RSVD_S 3 -#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */ -#define PRES_WRITE_ACTIVE_S 8 -#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */ -#define PRES_READ_ACTIVE_S 9 -#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */ -#define PRES_WRITE_DATA_RDY_S 10 -#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */ -#define PRES_READ_DATA_RDY_S 11 -#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */ -#define PRES_CARD_PRESENT_S 16 -#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */ -#define PRES_CARD_STABLE_S 17 -#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */ -#define PRES_CARD_PRESENT_RAW_S 18 -#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */ -#define PRES_WRITE_ENABLED_S 19 -#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */ -#define PRES_DAT_SIGNAL_S 20 -#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */ -#define PRES_CMD_SIGNAL_S 24 - -/* SD_HostCntrl: Offset 0x028, size = 1 bytes */ -#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */ -#define HOST_LED_S 0 -#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */ -#define HOST_DATA_WIDTH_S 1 -#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */ -#define HOST_DMA_SEL_S 3 -#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */ -#define HOST_HI_SPEED_EN_S 2 - -/* Host Control2: */ -#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */ - -#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */ - -#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */ - -#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */ - -#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */ -#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */ - -#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */ - -#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */ -#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */ - -#define HOST_CONTR_VER_2 (1) -#define HOST_CONTR_VER_3 (2) - -/* misc defines */ -#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */ -#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */ - -/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */ -#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */ -#define PWR_BUS_EN_S 0 -#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */ -#define PWR_VOLTS_S 1 - -/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */ -#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */ -#define SW_RESET_ALL_S 0 -#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */ -#define SW_RESET_CMD_S 1 -#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */ -#define SW_RESET_DAT_S 2 - -/* SD_IntrStatus: Offset 0x030, size = 2 bytes */ -/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */ -#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */ -#define INTSTAT_CMD_COMPLETE_S 0 -#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1) -#define INTSTAT_XFER_COMPLETE_S 1 -#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1) -#define INTSTAT_BLOCK_GAP_EVENT_S 2 -#define INTSTAT_DMA_INT_M BITFIELD_MASK(1) -#define INTSTAT_DMA_INT_S 3 -#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1) -#define INTSTAT_BUF_WRITE_READY_S 4 -#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1) -#define INTSTAT_BUF_READ_READY_S 5 -#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1) -#define INTSTAT_CARD_INSERTION_S 6 -#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1) -#define INTSTAT_CARD_REMOVAL_S 7 -#define INTSTAT_CARD_INT_M BITFIELD_MASK(1) -#define INTSTAT_CARD_INT_S 8 -#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */ -#define INTSTAT_RETUNING_INT_S 12 -#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */ -#define INTSTAT_ERROR_INT_S 15 - -/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */ -/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */ -#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1) -#define ERRINT_CMD_TIMEOUT_S 0 -#define ERRINT_CMD_CRC_M BITFIELD_MASK(1) -#define ERRINT_CMD_CRC_S 1 -#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1) -#define ERRINT_CMD_ENDBIT_S 2 -#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1) -#define ERRINT_CMD_INDEX_S 3 -#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1) -#define ERRINT_DATA_TIMEOUT_S 4 -#define ERRINT_DATA_CRC_M BITFIELD_MASK(1) -#define ERRINT_DATA_CRC_S 5 -#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1) -#define ERRINT_DATA_ENDBIT_S 6 -#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1) -#define ERRINT_CURRENT_LIMIT_S 7 -#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1) -#define ERRINT_AUTO_CMD12_S 8 -#define ERRINT_VENDOR_M BITFIELD_MASK(4) -#define ERRINT_VENDOR_S 12 -#define ERRINT_ADMA_M BITFIELD_MASK(1) -#define ERRINT_ADMA_S 9 - -/* Also provide definitions in "normal" form to allow combined masks */ -#define ERRINT_CMD_TIMEOUT_BIT 0x0001 -#define ERRINT_CMD_CRC_BIT 0x0002 -#define ERRINT_CMD_ENDBIT_BIT 0x0004 -#define ERRINT_CMD_INDEX_BIT 0x0008 -#define ERRINT_DATA_TIMEOUT_BIT 0x0010 -#define ERRINT_DATA_CRC_BIT 0x0020 -#define ERRINT_DATA_ENDBIT_BIT 0x0040 -#define ERRINT_CURRENT_LIMIT_BIT 0x0080 -#define ERRINT_AUTO_CMD12_BIT 0x0100 -#define ERRINT_ADMA_BIT 0x0200 - -/* Masks to select CMD vs. DATA errors */ -#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\ - ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT) -#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\ - ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT) -#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS) - -/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */ -/* SD_ClockCntrl : Offset 0x02C , size = bytes */ -/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */ -/* SD_IntrStatus : Offset 0x030 , size = bytes */ -/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */ -/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */ -/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */ -/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */ -/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */ -/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */ -/* SD_Capabilities : Offset 0x040 , size = bytes */ -/* SD_MaxCurCap : Offset 0x048 , size = bytes */ -/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */ -/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */ -/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */ - -/* SDIO Host Control Register DMA Mode Definitions */ -#define SDIOH_SDMA_MODE 0 -#define SDIOH_ADMA1_MODE 1 -#define SDIOH_ADMA2_MODE 2 -#define SDIOH_ADMA2_64_MODE 3 - -#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ -#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ -#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ -#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ -#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ -#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ -#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ -#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ - -/* ADMA2 Descriptor Table Entry for 32-bit Address */ -typedef struct adma2_dscr_32b { - uint32 len_attr; - uint32 phys_addr; -} adma2_dscr_32b_t; - -/* ADMA1 Descriptor Table Entry */ -typedef struct adma1_dscr { - uint32 phys_addr_attr; -} adma1_dscr_t; - -#endif /* _SDIOH_H */ diff --git a/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd/include/sdiovar.h deleted file mode 100644 index 326b32d8dfb0..000000000000 --- a/drivers/net/wireless/bcmdhd/include/sdiovar.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Structure used by apps whose drivers access SDIO drivers. - * Pulled out separately so dhdu and wlu can both use it. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sdiovar.h 241182 2011-02-17 21:50:03Z $ - */ - -#ifndef _sdiovar_h_ -#define _sdiovar_h_ - -#include - -/* require default structure packing */ -#define BWL_DEFAULT_PACKING -#include - -typedef struct sdreg { - int func; - int offset; - int value; -} sdreg_t; - -/* Common msglevel constants */ -#define SDH_ERROR_VAL 0x0001 /* Error */ -#define SDH_TRACE_VAL 0x0002 /* Trace */ -#define SDH_INFO_VAL 0x0004 /* Info */ -#define SDH_DEBUG_VAL 0x0008 /* Debug */ -#define SDH_DATA_VAL 0x0010 /* Data */ -#define SDH_CTRL_VAL 0x0020 /* Control Regs */ -#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ -#define SDH_DMA_VAL 0x0080 /* DMA */ - -#define NUM_PREV_TRANSACTIONS 16 - - -#include - -#endif /* _sdiovar_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h deleted file mode 100644 index 4603169ec1b9..000000000000 --- a/drivers/net/wireless/bcmdhd/include/siutils.h +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Misc utility routines for accessing the SOC Interconnects - * of Broadcom HNBU chips. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: siutils.h 481602 2014-05-29 22:43:34Z $ - */ - -#ifndef _siutils_h_ -#define _siutils_h_ - -#ifdef SR_DEBUG -#include "wlioctl.h" -#endif /* SR_DEBUG */ - - -/* - * Data structure to export all chip specific common variables - * public (read-only) portion of siutils handle returned by si_attach()/si_kattach() - */ -struct si_pub { - uint socitype; /* SOCI_SB, SOCI_AI */ - - uint bustype; /* SI_BUS, PCI_BUS */ - 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 */ - uint32 cccaps; /* chip common capabilities */ - uint32 cccaps_ext; /* chip common capabilities extension */ - int pmurev; /* pmu core rev */ - uint32 pmucaps; /* pmu capabilities */ - uint boardtype; /* board type */ - uint boardrev; /* board rev */ - 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 */ - uint32 chipst; /* chip status */ - bool issim; /* chip is in simulation or emulation */ - uint socirev; /* SOC interconnect rev */ - bool pci_pr32414; - -}; - -/* for HIGH_ONLY driver, the si_t must be writable to allow states sync from BMAC to HIGH driver - * for monolithic driver, it is readonly to prevent accident change - */ -typedef const struct si_pub si_t; - -/* - * 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. - */ -#define SI_OSH NULL /* Use for si_kattach when no osh is available */ - -#define BADIDX (SI_MAXCORES + 1) - -/* 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 /* wireless interface is down */ -#define SI_PCIUP 3 /* wireless interface is up */ - -#ifdef SR_DEBUG -#define PMU_RES 31 -#endif /* SR_DEBUG */ - -#define ISSIM_ENAB(sih) FALSE - -/* PMU clock/power control */ -#if defined(BCMPMUCTL) -#define PMUCTL_ENAB(sih) (BCMPMUCTL) -#else -#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU) -#endif - -#define AOB_ENAB(sih) ((sih)->ccrev >= 35 ? \ - ((sih)->cccaps_ext & CC_CAP_EXT_AOB_PRESENT) : 0) - -/* chipcommon clock/power control (exclusive with PMU's) */ -#if defined(BCMPMUCTL) && BCMPMUCTL -#define CCCTL_ENAB(sih) (0) -#define CCPLL_ENAB(sih) (0) -#else -#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL) -#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK) -#endif - -typedef void (*gpio_handler_t)(uint32 stat, void *arg); -typedef void (*gci_gpio_handler_t)(uint32 stat, void *arg); -/* External BT Coex enable mask */ -#define CC_BTCOEX_EN_MASK 0x01 -/* External PA enable mask */ -#define GPIO_CTRL_EPA_EN_MASK 0x40 -/* WL/BT control enable mask */ -#define GPIO_CTRL_5_6_EN_MASK 0x60 -#define GPIO_CTRL_7_6_EN_MASK 0xC0 -#define GPIO_OUT_7_EN_MASK 0x80 - - -/* CR4 specific defines used by the host driver */ -#define SI_CR4_CAP (0x04) -#define SI_CR4_BANKIDX (0x40) -#define SI_CR4_BANKINFO (0x44) -#define SI_CR4_BANKPDA (0x4C) - -#define ARMCR4_TCBBNB_MASK 0xf0 -#define ARMCR4_TCBBNB_SHIFT 4 -#define ARMCR4_TCBANB_MASK 0xf -#define ARMCR4_TCBANB_SHIFT 0 - -#define SICF_CPUHALT (0x0020) -#define ARMCR4_BSZ_MASK 0x3f -#define ARMCR4_BSZ_MULT 8192 - -#include -/* === exported functions === */ -extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, - void *sdh, char **vars, uint *varsz); -extern si_t *si_kattach(osl_t *osh); -extern void si_detach(si_t *sih); -extern bool si_pci_war16165(si_t *sih); -extern void * -si_d11_switch_addrbase(si_t *sih, uint coreunit); -extern uint si_corelist(si_t *sih, uint coreid[]); -extern uint si_coreid(si_t *sih); -extern uint si_flag(si_t *sih); -extern uint si_flag_alt(si_t *sih); -extern uint si_intflag(si_t *sih); -extern uint si_coreidx(si_t *sih); -extern uint si_coreunit(si_t *sih); -extern uint si_corevendor(si_t *sih); -extern uint si_corerev(si_t *sih); -extern void *si_osh(si_t *sih); -extern void si_setosh(si_t *sih, osl_t *osh); -extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -extern uint si_pmu_corereg(si_t *sih, uint32 idx, uint regoff, uint mask, uint val); -extern uint32 *si_corereg_addr(si_t *sih, uint coreidx, uint regoff); -extern void *si_coreregs(si_t *sih); -extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); -extern uint si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val); -extern void *si_wrapperregs(si_t *sih); -extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); -extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); -extern bool si_iscoreup(si_t *sih); -extern uint si_numcoreunits(si_t *sih, uint coreid); -extern uint si_numd11coreunits(si_t *sih); -extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); -extern void *si_setcoreidx(si_t *sih, uint coreidx); -extern void *si_setcore(si_t *sih, uint coreid, uint coreunit); -extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); -extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); -extern int si_numaddrspaces(si_t *sih); -extern uint32 si_addrspace(si_t *sih, uint asidx); -extern uint32 si_addrspacesize(si_t *sih, uint asidx); -extern void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); -extern int si_corebist(si_t *sih); -extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -extern void si_core_disable(si_t *sih, uint32 bits); -extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); -extern uint si_chip_hostif(si_t *sih); -extern bool si_read_pmu_autopll(si_t *sih); -extern uint32 si_clock(si_t *sih); -extern uint32 si_alp_clock(si_t *sih); /* returns [Hz] units */ -extern uint32 si_ilp_clock(si_t *sih); /* returns [Hz] units */ -extern void si_pci_setup(si_t *sih, uint coremask); -extern void si_pcmcia_init(si_t *sih); -extern void si_setint(si_t *sih, int siflag); -extern bool si_backplane64(si_t *sih); -extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, - void *intrsenabled_fn, void *intr_arg); -extern void si_deregister_intr_callback(si_t *sih); -extern void si_clkctl_init(si_t *sih); -extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); -extern bool si_clkctl_cc(si_t *sih, uint mode); -extern int si_clkctl_xtal(si_t *sih, uint what, bool on); -extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); -extern void si_btcgpiowar(si_t *sih); -extern bool si_deviceremoved(si_t *sih); -extern uint32 si_socram_size(si_t *sih); -extern uint32 si_socdevram_size(si_t *sih); -extern uint32 si_socram_srmem_size(si_t *sih); -extern void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda); -extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect, uint8 *remap); -extern bool si_socdevram_pkg(si_t *sih); -extern bool si_socdevram_remap_isenb(si_t *sih); -extern uint32 si_socdevram_remap_size(si_t *sih); - -extern void si_watchdog(si_t *sih, uint ticks); -extern void si_watchdog_ms(si_t *sih, uint32 ms); -extern uint32 si_watchdog_msticks(void); -extern void *si_gpiosetcore(si_t *sih); -extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpioin(si_t *sih); -extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); -extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); -extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); -extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); -extern uint32 si_gpio_int_enable(si_t *sih, bool enable); -extern void si_gci_uart_init(si_t *sih, osl_t *osh, uint8 seci_mode); -extern void si_gci_enable_gpio(si_t *sih, uint8 gpio, uint32 mask, uint32 value); -extern uint8 si_gci_host_wake_gpio_init(si_t *sih); -extern void si_gci_host_wake_gpio_enable(si_t *sih, uint8 gpio, bool state); - -/* GPIO event handlers */ -extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg); -extern void si_gpio_handler_unregister(si_t *sih, void* gpioh); -extern void si_gpio_handler_process(si_t *sih); - -/* GCI interrupt handlers */ -extern void si_gci_handler_process(si_t *sih); - -/* GCI GPIO event handlers */ -extern void *si_gci_gpioint_handler_register(si_t *sih, uint8 gpio, uint8 sts, - gci_gpio_handler_t cb, void *arg); -extern void si_gci_gpioint_handler_unregister(si_t *sih, void* gci_i); -extern uint8 si_gci_gpio_status(si_t *sih, uint8 gci_gpio, uint8 mask, uint8 value); - -/* Wake-on-wireless-LAN (WOWL) */ -extern bool si_pci_pmecap(si_t *sih); -extern bool si_pci_fastpmecap(struct osl_info *osh); -extern bool si_pci_pmestat(si_t *sih); -extern void si_pci_pmeclr(si_t *sih); -extern void si_pci_pmeen(si_t *sih); -extern void si_pci_pmestatclr(si_t *sih); -extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); -extern uint si_pcie_writereg(void *sih, uint addrtype, uint offset, uint val); - - -#ifdef BCMSDIO -extern void si_sdio_init(si_t *sih); -#endif - -extern uint16 si_d11_devid(si_t *sih); -extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, - uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); - -#define si_eci(sih) 0 -static INLINE void * si_eci_init(si_t *sih) {return NULL;} -#define si_eci_notify_bt(sih, type, val) (0) -#define si_seci(sih) 0 -#define si_seci_upd(sih, a) do {} while (0) -static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} -static INLINE void * si_gci_init(si_t *sih) {return NULL;} -#define si_seci_down(sih) do {} while (0) -#define si_gci(sih) 0 - -/* OTP status */ -extern bool si_is_otp_disabled(si_t *sih); -extern bool si_is_otp_powered(si_t *sih); -extern void si_otp_power(si_t *sih, bool on, uint32* min_res_mask); - -/* SPROM availability */ -extern bool si_is_sprom_available(si_t *sih); -extern bool si_is_sprom_enabled(si_t *sih); -extern void si_sprom_enable(si_t *sih, bool enable); - -/* OTP/SROM CIS stuff */ -extern int si_cis_source(si_t *sih); -#define CIS_DEFAULT 0 -#define CIS_SROM 1 -#define CIS_OTP 2 - -/* Fab-id information */ -#define DEFAULT_FAB 0x0 /* Original/first fab used for this chip */ -#define CSM_FAB7 0x1 /* CSM Fab7 chip */ -#define TSMC_FAB12 0x2 /* TSMC Fab12/Fab14 chip */ -#define SMIC_FAB4 0x3 /* SMIC Fab4 chip */ - -extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw); -extern uint16 si_fabid(si_t *sih); -extern uint16 si_chipid(si_t *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 si_devpath(si_t *sih, char *path, int size); -extern int si_devpath_pcie(si_t *sih, char *path, int size); -/* Read variable with prepending the devpath to the name */ -extern char *si_getdevpathvar(si_t *sih, const char *name); -extern int si_getdevpathintvar(si_t *sih, const char *name); -extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const char *name); - - -extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); -extern uint8 si_pcieltrenable(si_t *sih, uint32 mask, uint32 val); -extern uint8 si_pcieobffenable(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_pcieltr_reg(si_t *sih, uint32 reg, uint32 mask, uint32 val); -extern uint32 si_pcieltrspacing_reg(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_pcieltrhysteresiscnt_reg(si_t *sih, uint32 mask, uint32 val); -extern void si_pcie_set_error_injection(si_t *sih, uint32 mode); -extern void si_pcie_set_L1substate(si_t *sih, uint32 substate); -extern uint32 si_pcie_get_L1substate(si_t *sih); -extern void si_war42780_clkreq(si_t *sih, bool clkreq); -extern void si_pci_down(si_t *sih); -extern void si_pci_up(si_t *sih); -extern void si_pci_sleep(si_t *sih); -extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); -extern void si_pcie_power_save_enable(si_t *sih, bool enable); -extern void si_pcie_extendL1timer(si_t *sih, bool extend); -extern int si_pci_fixcfg(si_t *sih); -extern void si_chippkg_set(si_t *sih, uint); - -extern void si_chipcontrl_btshd0_4331(si_t *sih, bool on); -extern void si_chipcontrl_restore(si_t *sih, uint32 val); -extern uint32 si_chipcontrl_read(si_t *sih); -extern void si_chipcontrl_epa4331(si_t *sih, bool on); -extern void si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl); -extern void si_chipcontrl_srom4360(si_t *sih, bool on); -/* Enable BT-COEX & Ex-PA for 4313 */ -extern void si_epa_4313war(si_t *sih); -extern void si_btc_enable_chipcontrol(si_t *sih); -/* BT/WL selection for 4313 bt combo >= P250 boards */ -extern void si_btcombo_p250_4313_war(si_t *sih); -extern void si_btcombo_43228_war(si_t *sih); -extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); -extern void si_pmu_synth_pwrsw_4313_war(si_t *sih); -extern uint si_pll_reset(si_t *sih); -/* === debug routines === */ - -extern bool si_taclear(si_t *sih, bool details); - - -#if defined(BCMDBG_PHYDUMP) -extern void si_dumpregs(si_t *sih, struct bcmstrbuf *b); -#endif - -extern uint32 si_ccreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); -extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); -#ifdef SR_DEBUG -extern void si_dump_pmu(si_t *sih, void *pmu_var); -extern void si_pmu_keep_on(si_t *sih, int32 int_val); -extern uint32 si_pmu_keep_on_get(si_t *sih); -extern uint32 si_power_island_set(si_t *sih, uint32 int_val); -extern uint32 si_power_island_get(si_t *sih); -#endif /* SR_DEBUG */ -extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); -extern void si_pcie_set_request_size(si_t *sih, uint16 size); -extern uint16 si_pcie_get_request_size(si_t *sih); -extern void si_pcie_set_maxpayload_size(si_t *sih, uint16 size); -extern uint16 si_pcie_get_maxpayload_size(si_t *sih); -extern uint16 si_pcie_get_ssid(si_t *sih); -extern uint32 si_pcie_get_bar0(si_t *sih); -extern int si_pcie_configspace_cache(si_t *sih); -extern int si_pcie_configspace_restore(si_t *sih); -extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); - -char *si_getnvramflvar(si_t *sih, const char *name); - - -extern uint32 si_tcm_size(si_t *sih); -extern bool si_has_flops(si_t *sih); - -extern int si_set_sromctl(si_t *sih, uint32 value); -extern uint32 si_get_sromctl(si_t *sih); - -extern uint32 si_gci_direct(si_t *sih, uint offset, uint32 mask, uint32 val); -extern uint32 si_gci_indirect(si_t *sih, uint regidx, uint offset, uint32 mask, uint32 val); -extern uint32 si_gci_output(si_t *sih, uint reg, uint32 mask, uint32 val); -extern uint32 si_gci_input(si_t *sih, uint reg); -extern uint32 si_gci_int_enable(si_t *sih, bool enable); -extern void si_gci_reset(si_t *sih); -#ifdef BCMLTECOEX -extern void si_gci_seci_init(si_t *sih); -extern void si_ercx_init(si_t *sih, uint32 ltecx_mux, uint32 ltecx_padnum, - uint32 ltecx_fnsel, uint32 ltecx_gcigpio); -extern void si_wci2_init(si_t *sih, uint8 baudrate, uint32 ltecx_mux, uint32 ltecx_padnum, - uint32 ltecx_fnsel, uint32 ltecx_gcigpio); -#endif /* BCMLTECOEX */ -extern void si_gci_set_functionsel(si_t *sih, uint32 pin, uint8 fnsel); -extern uint32 si_gci_get_functionsel(si_t *sih, uint32 pin); -extern void si_gci_clear_functionsel(si_t *sih, uint8 fnsel); -extern uint8 si_gci_get_chipctrlreg_idx(uint32 pin, uint32 *regidx, uint32 *pos); -extern uint32 si_gci_chipcontrol(si_t *sih, uint reg, uint32 mask, uint32 val); -extern uint32 si_gci_chipstatus(si_t *sih, uint reg); -extern uint16 si_cc_get_reg16(uint32 reg_offs); -extern uint32 si_cc_get_reg32(uint32 reg_offs); -extern uint32 si_cc_set_reg32(uint32 reg_offs, uint32 val); -extern uint32 si_gci_preinit_upd_indirect(uint32 regidx, uint32 setval, uint32 mask); -extern uint8 si_enable_device_wake(si_t *sih, uint8 *wake_status, uint8 *cur_status); -extern void si_swdenable(si_t *sih, uint32 swdflag); - -#define CHIPCTRLREG1 0x1 -#define CHIPCTRLREG2 0x2 -#define CHIPCTRLREG3 0x3 -#define CHIPCTRLREG4 0x4 -#define CHIPCTRLREG5 0x5 -#define MINRESMASKREG 0x618 -#define MAXRESMASKREG 0x61c -#define CHIPCTRLADDR 0x650 -#define CHIPCTRLDATA 0x654 -#define RSRCTABLEADDR 0x620 -#define RSRCUPDWNTIME 0x628 -#define PMUREG_RESREQ_MASK 0x68c - -void si_update_masks(si_t *sih); -void si_force_islanding(si_t *sih, bool enable); -extern uint32 si_pmu_res_req_timer_clr(si_t *sih); -extern void si_pmu_rfldo(si_t *sih, bool on); -extern void si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 spert_val); -extern uint32 si_pcie_set_ctrlreg(si_t *sih, uint32 sperst_mask, uint32 spert_val); -extern void si_pcie_ltr_war(si_t *sih); -extern void si_pcie_hw_LTR_war(si_t *sih); -extern void si_pcie_hw_L1SS_war(si_t *sih); -extern void si_pciedev_crwlpciegen2(si_t *sih); -extern void si_pcie_prep_D3(si_t *sih, bool enter_D3); -extern void si_pciedev_reg_pm_clk_period(si_t *sih); - -#ifdef WLRSDB -extern void si_d11rsdb_core_disable(si_t *sih, uint32 bits); -extern void si_d11rsdb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -#endif - - -/* Macro to enable clock gating changes in different cores */ -#define MEM_CLK_GATE_BIT 5 -#define GCI_CLK_GATE_BIT 18 - -#define USBAPP_CLK_BIT 0 -#define PCIE_CLK_BIT 3 -#define ARMCR4_DBG_CLK_BIT 4 -#define SAMPLE_SYNC_CLK_BIT 17 -#define PCIE_TL_CLK_BIT 18 -#define HQ_REQ_BIT 24 -#define PLL_DIV2_BIT_START 9 -#define PLL_DIV2_MASK (0x37 << PLL_DIV2_BIT_START) -#define PLL_DIV2_DIS_OP (0x37 << PLL_DIV2_BIT_START) - -#define PMUREG(si, member) \ - (AOB_ENAB(si) ? \ - si_corereg_addr(si, si_findcoreidx(si, PMU_CORE_ID, 0), \ - OFFSETOF(pmuregs_t, member)): \ - si_corereg_addr(si, SI_CC_IDX, OFFSETOF(chipcregs_t, member))) - -#define pmu_corereg(si, cc_idx, member, mask, val) \ - (AOB_ENAB(si) ? \ - si_pmu_corereg(si, si_findcoreidx(sih, PMU_CORE_ID, 0), \ - OFFSETOF(pmuregs_t, member), mask, val): \ - si_pmu_corereg(si, cc_idx, OFFSETOF(chipcregs_t, member), mask, val)) - -/* GCI Macros */ -#define ALLONES_32 0xFFFFFFFF -#define GCI_CCTL_SECIRST_OFFSET 0 /* SeciReset */ -#define GCI_CCTL_RSTSL_OFFSET 1 /* ResetSeciLogic */ -#define GCI_CCTL_SECIEN_OFFSET 2 /* EnableSeci */ -#define GCI_CCTL_FSL_OFFSET 3 /* ForceSeciOutLow */ -#define GCI_CCTL_SMODE_OFFSET 4 /* SeciOpMode, 6:4 */ -#define GCI_CCTL_US_OFFSET 7 /* UpdateSeci */ -#define GCI_CCTL_BRKONSLP_OFFSET 8 /* BreakOnSleep */ -#define GCI_CCTL_SILOWTOUT_OFFSET 9 /* SeciInLowTimeout, 10:9 */ -#define GCI_CCTL_RSTOCC_OFFSET 11 /* ResetOffChipCoex */ -#define GCI_CCTL_ARESEND_OFFSET 12 /* AutoBTSigResend */ -#define GCI_CCTL_FGCR_OFFSET 16 /* ForceGciClkReq */ -#define GCI_CCTL_FHCRO_OFFSET 17 /* ForceHWClockReqOff */ -#define GCI_CCTL_FREGCLK_OFFSET 18 /* ForceRegClk */ -#define GCI_CCTL_FSECICLK_OFFSET 19 /* ForceSeciClk */ -#define GCI_CCTL_FGCA_OFFSET 20 /* ForceGciClkAvail */ -#define GCI_CCTL_FGCAV_OFFSET 21 /* ForceGciClkAvailValue */ -#define GCI_CCTL_SCS_OFFSET 24 /* SeciClkStretch, 31:24 */ - -#define GCI_MODE_UART 0x0 -#define GCI_MODE_SECI 0x1 -#define GCI_MODE_BTSIG 0x2 -#define GCI_MODE_GPIO 0x3 -#define GCI_MODE_MASK 0x7 - -#define GCI_CCTL_LOWTOUT_DIS 0x0 -#define GCI_CCTL_LOWTOUT_10BIT 0x1 -#define GCI_CCTL_LOWTOUT_20BIT 0x2 -#define GCI_CCTL_LOWTOUT_30BIT 0x3 -#define GCI_CCTL_LOWTOUT_MASK 0x3 - -#define GCI_CCTL_SCS_DEF 0x19 -#define GCI_CCTL_SCS_MASK 0xFF - -#define GCI_SECIIN_MODE_OFFSET 0 -#define GCI_SECIIN_GCIGPIO_OFFSET 4 -#define GCI_SECIIN_RXID2IP_OFFSET 8 - -#define GCI_SECIOUT_MODE_OFFSET 0 -#define GCI_SECIOUT_GCIGPIO_OFFSET 4 -#define GCI_SECIOUT_SECIINRELATED_OFFSET 16 - -#define GCI_SECIAUX_RXENABLE_OFFSET 0 -#define GCI_SECIFIFO_RXENABLE_OFFSET 16 - -#define GCI_SECITX_ENABLE_OFFSET 0 - -#define GCI_GPIOCTL_INEN_OFFSET 0 -#define GCI_GPIOCTL_OUTEN_OFFSET 1 -#define GCI_GPIOCTL_PDN_OFFSET 4 - -#define GCI_GPIOIDX_OFFSET 16 - -#define GCI_LTECX_SECI_ID 0 /* SECI port for LTECX */ - -/* To access per GCI bit registers */ -#define GCI_REG_WIDTH 32 - -/* GCI bit positions */ -/* GCI [127:000] = WLAN [127:0] */ -#define GCI_WLAN_IP_ID 0 -#define GCI_WLAN_BEGIN 0 -#define GCI_WLAN_PRIO_POS (GCI_WLAN_BEGIN + 4) - -/* GCI [639:512] = LTE [127:0] */ -#define GCI_LTE_IP_ID 4 -#define GCI_LTE_BEGIN 512 -#define GCI_LTE_FRAMESYNC_POS (GCI_LTE_BEGIN + 0) -#define GCI_LTE_RX_POS (GCI_LTE_BEGIN + 1) -#define GCI_LTE_TX_POS (GCI_LTE_BEGIN + 2) -#define GCI_LTE_AUXRXDVALID_POS (GCI_LTE_BEGIN + 56) - -/* Reg Index corresponding to ECI bit no x of ECI space */ -#define GCI_REGIDX(x) ((x)/GCI_REG_WIDTH) -/* Bit offset of ECI bit no x in 32-bit words */ -#define GCI_BITOFFSET(x) ((x)%GCI_REG_WIDTH) - -/* End - GCI Macros */ - -#ifdef REROUTE_OOBINT -#define CC_OOB 0x0 -#define M2MDMA_OOB 0x1 -#define PMU_OOB 0x2 -#define D11_OOB 0x3 -#define SDIOD_OOB 0x4 -#define PMU_OOB_BIT (0x10 | PMU_OOB) -#endif /* REROUTE_OOBINT */ - - -#endif /* _siutils_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/spid.h b/drivers/net/wireless/bcmdhd/include/spid.h deleted file mode 100644 index b5d7b675748d..000000000000 --- a/drivers/net/wireless/bcmdhd/include/spid.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SPI device spec header file - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: spid.h 358377 2012-09-23 11:30:22Z $ - */ - -#ifndef _SPI_H -#define _SPI_H - -/* - * Brcm SPI Device Register Map. - * - */ - -typedef volatile struct { - uint8 config; /* 0x00, len, endian, clock, speed, polarity, wakeup */ - uint8 response_delay; /* 0x01, read response delay in bytes (corerev < 3) */ - uint8 status_enable; /* 0x02, status-enable, intr with status, response_delay - * function selection, command/data error check - */ - uint8 reset_bp; /* 0x03, reset on wlan/bt backplane reset (corerev >= 1) */ - uint16 intr_reg; /* 0x04, Intr status register */ - uint16 intr_en_reg; /* 0x06, Intr mask register */ - uint32 status_reg; /* 0x08, RO, Status bits of last spi transfer */ - uint16 f1_info_reg; /* 0x0c, RO, enabled, ready for data transfer, blocksize */ - uint16 f2_info_reg; /* 0x0e, RO, enabled, ready for data transfer, blocksize */ - uint16 f3_info_reg; /* 0x10, RO, enabled, ready for data transfer, blocksize */ - uint32 test_read; /* 0x14, RO 0xfeedbead signature */ - uint32 test_rw; /* 0x18, RW */ - uint8 resp_delay_f0; /* 0x1c, read resp delay bytes for F0 (corerev >= 3) */ - uint8 resp_delay_f1; /* 0x1d, read resp delay bytes for F1 (corerev >= 3) */ - uint8 resp_delay_f2; /* 0x1e, read resp delay bytes for F2 (corerev >= 3) */ - uint8 resp_delay_f3; /* 0x1f, read resp delay bytes for F3 (corerev >= 3) */ -} spi_regs_t; - -/* SPI device register offsets */ -#define SPID_CONFIG 0x00 -#define SPID_RESPONSE_DELAY 0x01 -#define SPID_STATUS_ENABLE 0x02 -#define SPID_RESET_BP 0x03 /* (corerev >= 1) */ -#define SPID_INTR_REG 0x04 /* 16 bits - Interrupt status */ -#define SPID_INTR_EN_REG 0x06 /* 16 bits - Interrupt mask */ -#define SPID_STATUS_REG 0x08 /* 32 bits */ -#define SPID_F1_INFO_REG 0x0C /* 16 bits */ -#define SPID_F2_INFO_REG 0x0E /* 16 bits */ -#define SPID_F3_INFO_REG 0x10 /* 16 bits */ -#define SPID_TEST_READ 0x14 /* 32 bits */ -#define SPID_TEST_RW 0x18 /* 32 bits */ -#define SPID_RESP_DELAY_F0 0x1c /* 8 bits (corerev >= 3) */ -#define SPID_RESP_DELAY_F1 0x1d /* 8 bits (corerev >= 3) */ -#define SPID_RESP_DELAY_F2 0x1e /* 8 bits (corerev >= 3) */ -#define SPID_RESP_DELAY_F3 0x1f /* 8 bits (corerev >= 3) */ - -/* Bit masks for SPID_CONFIG device register */ -#define WORD_LENGTH_32 0x1 /* 0/1 16/32 bit word length */ -#define ENDIAN_BIG 0x2 /* 0/1 Little/Big Endian */ -#define CLOCK_PHASE 0x4 /* 0/1 clock phase delay */ -#define CLOCK_POLARITY 0x8 /* 0/1 Idle state clock polarity is low/high */ -#define HIGH_SPEED_MODE 0x10 /* 1/0 High Speed mode / Normal mode */ -#define INTR_POLARITY 0x20 /* 1/0 Interrupt active polarity is high/low */ -#define WAKE_UP 0x80 /* 0/1 Wake-up command from Host to WLAN */ - -/* Bit mask for SPID_RESPONSE_DELAY device register */ -#define RESPONSE_DELAY_MASK 0xFF /* Configurable rd response delay in multiples of 8 bits */ - -/* Bit mask for SPID_STATUS_ENABLE device register */ -#define STATUS_ENABLE 0x1 /* 1/0 Status sent/not sent to host after read/write */ -#define INTR_WITH_STATUS 0x2 /* 0/1 Do-not / do-interrupt if status is sent */ -#define RESP_DELAY_ALL 0x4 /* Applicability of resp delay to F1 or all func's read */ -#define DWORD_PKT_LEN_EN 0x8 /* Packet len denoted in dwords instead of bytes */ -#define CMD_ERR_CHK_EN 0x20 /* Command error check enable */ -#define DATA_ERR_CHK_EN 0x40 /* Data error check enable */ - -/* Bit mask for SPID_RESET_BP device register */ -#define RESET_ON_WLAN_BP_RESET 0x4 /* enable reset for WLAN backplane */ -#define RESET_ON_BT_BP_RESET 0x8 /* enable reset for BT backplane */ -#define RESET_SPI 0x80 /* reset the above enabled logic */ - -/* Bit mask for SPID_INTR_REG device register */ -#define DATA_UNAVAILABLE 0x0001 /* Requested data not available; Clear by writing a "1" */ -#define F2_F3_FIFO_RD_UNDERFLOW 0x0002 -#define F2_F3_FIFO_WR_OVERFLOW 0x0004 -#define COMMAND_ERROR 0x0008 /* Cleared by writing 1 */ -#define DATA_ERROR 0x0010 /* Cleared by writing 1 */ -#define F2_PACKET_AVAILABLE 0x0020 -#define F3_PACKET_AVAILABLE 0x0040 -#define F1_OVERFLOW 0x0080 /* Due to last write. Bkplane has pending write requests */ -#define MISC_INTR0 0x0100 -#define MISC_INTR1 0x0200 -#define MISC_INTR2 0x0400 -#define MISC_INTR3 0x0800 -#define MISC_INTR4 0x1000 -#define F1_INTR 0x2000 -#define F2_INTR 0x4000 -#define F3_INTR 0x8000 - -/* Bit mask for 32bit SPID_STATUS_REG device register */ -#define STATUS_DATA_NOT_AVAILABLE 0x00000001 -#define STATUS_UNDERFLOW 0x00000002 -#define STATUS_OVERFLOW 0x00000004 -#define STATUS_F2_INTR 0x00000008 -#define STATUS_F3_INTR 0x00000010 -#define STATUS_F2_RX_READY 0x00000020 -#define STATUS_F3_RX_READY 0x00000040 -#define STATUS_HOST_CMD_DATA_ERR 0x00000080 -#define STATUS_F2_PKT_AVAILABLE 0x00000100 -#define STATUS_F2_PKT_LEN_MASK 0x000FFE00 -#define STATUS_F2_PKT_LEN_SHIFT 9 -#define STATUS_F3_PKT_AVAILABLE 0x00100000 -#define STATUS_F3_PKT_LEN_MASK 0xFFE00000 -#define STATUS_F3_PKT_LEN_SHIFT 21 - -/* Bit mask for 16 bits SPID_F1_INFO_REG device register */ -#define F1_ENABLED 0x0001 -#define F1_RDY_FOR_DATA_TRANSFER 0x0002 -#define F1_MAX_PKT_SIZE 0x01FC - -/* Bit mask for 16 bits SPID_F2_INFO_REG device register */ -#define F2_ENABLED 0x0001 -#define F2_RDY_FOR_DATA_TRANSFER 0x0002 -#define F2_MAX_PKT_SIZE 0x3FFC - -/* Bit mask for 16 bits SPID_F3_INFO_REG device register */ -#define F3_ENABLED 0x0001 -#define F3_RDY_FOR_DATA_TRANSFER 0x0002 -#define F3_MAX_PKT_SIZE 0x3FFC - -/* Bit mask for 32 bits SPID_TEST_READ device register read in 16bit LE mode */ -#define TEST_RO_DATA_32BIT_LE 0xFEEDBEAD - -/* Maximum number of I/O funcs */ -#define SPI_MAX_IOFUNCS 4 - -#define SPI_MAX_PKT_LEN (2048*4) - -/* Misc defines */ -#define SPI_FUNC_0 0 -#define SPI_FUNC_1 1 -#define SPI_FUNC_2 2 -#define SPI_FUNC_3 3 - -#define WAIT_F2RXFIFORDY 100 -#define WAIT_F2RXFIFORDY_DELAY 20 - -#endif /* _SPI_H */ diff --git a/drivers/net/wireless/bcmdhd/include/trxhdr.h b/drivers/net/wireless/bcmdhd/include/trxhdr.h deleted file mode 100644 index 5ea40e739e31..000000000000 --- a/drivers/net/wireless/bcmdhd/include/trxhdr.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * TRX image file header format. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: trxhdr.h 349211 2012-08-07 09:45:24Z $ - */ - -#ifndef _TRX_HDR_H -#define _TRX_HDR_H - -#include - -#define TRX_MAGIC 0x30524448 /* "HDR0" */ -#define TRX_MAX_LEN 0x3B0000 /* Max length */ -#define TRX_NO_HEADER 1 /* Do not write TRX header */ -#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ -#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ -#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ -#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ -#define TRX_BOOTLOADER 0x40 /* the image is a bootloader */ - -#define TRX_V1 1 -#define TRX_V1_MAX_OFFSETS 3 /* V1: Max number of individual files */ - -#ifndef BCMTRXV2 -#define TRX_VERSION TRX_V1 /* Version 1 */ -#define TRX_MAX_OFFSET TRX_V1_MAX_OFFSETS -#endif - -/* BMAC Host driver/application like bcmdl need to support both Ver 1 as well as - * Ver 2 of trx header. To make it generic, trx_header is structure is modified - * as below where size of "offsets" field will vary as per the TRX version. - * Currently, BMAC host driver and bcmdl are modified to support TRXV2 as well. - * To make sure, other applications like "dhdl" which are yet to be enhanced to support - * TRXV2 are not broken, new macro and structure defintion take effect only when BCMTRXV2 - * is defined. - */ -struct trx_header { - uint32 magic; /* "HDR0" */ - uint32 len; /* Length of file including header */ - uint32 crc32; /* 32-bit CRC from flag_version to end of file */ - uint32 flag_version; /* 0:15 flags, 16:31 version */ -#ifndef BCMTRXV2 - uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ -#else - uint32 offsets[1]; /* Offsets of partitions from start of header */ -#endif -}; - -#ifdef BCMTRXV2 -#define TRX_VERSION TRX_V2 /* Version 2 */ -#define TRX_MAX_OFFSET TRX_V2_MAX_OFFSETS - -#define TRX_V2 2 -/* V2: Max number of individual files - * To support SDR signature + Config data region - */ -#define TRX_V2_MAX_OFFSETS 5 -#define SIZEOF_TRXHDR_V1 (sizeof(struct trx_header)+(TRX_V1_MAX_OFFSETS-1)*sizeof(uint32)) -#define SIZEOF_TRXHDR_V2 (sizeof(struct trx_header)+(TRX_V2_MAX_OFFSETS-1)*sizeof(uint32)) -#define TRX_VER(trx) (trx->flag_version>>16) -#define ISTRX_V1(trx) (TRX_VER(trx) == TRX_V1) -#define ISTRX_V2(trx) (TRX_VER(trx) == TRX_V2) -/* For V2, return size of V2 size: others, return V1 size */ -#define SIZEOF_TRX(trx) (ISTRX_V2(trx) ? SIZEOF_TRXHDR_V2: SIZEOF_TRXHDR_V1) -#else -#define SIZEOF_TRX(trx) (sizeof(struct trx_header)) -#endif /* BCMTRXV2 */ - -/* Compatibility */ -typedef struct trx_header TRXHDR, *PTRXHDR; - -#endif /* _TRX_HDR_H */ diff --git a/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd/include/typedefs.h deleted file mode 100644 index a0ea58926161..000000000000 --- a/drivers/net/wireless/bcmdhd/include/typedefs.h +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: typedefs.h 484281 2014-06-12 22:42:26Z $ - */ - -#ifndef _TYPEDEFS_H_ -#define _TYPEDEFS_H_ - -#ifdef SITE_TYPEDEFS - -/* - * Define SITE_TYPEDEFS in the compile to include a site-specific - * typedef file "site_typedefs.h". - * - * If SITE_TYPEDEFS is not defined, then the code section below makes - * inferences about the compile environment based on defined symbols and - * possibly compiler pragmas. - * - * Following these two sections is the Default Typedefs section. - * This section is only processed if USE_TYPEDEF_DEFAULTS is - * defined. This section has a default set of typedefs and a few - * preprocessor symbols (TRUE, FALSE, NULL, ...). - */ - -#include "site_typedefs.h" - -#else - -/* - * Infer the compile environment based on preprocessor symbols and pragmas. - * Override type definitions as needed, and include configuration-dependent - * header files to define types. - */ - -#ifdef __cplusplus - -#define TYPEDEF_BOOL -#ifndef FALSE -#define FALSE false -#endif -#ifndef TRUE -#define TRUE true -#endif - -#else /* ! __cplusplus */ - - -#endif /* ! __cplusplus */ - -#if defined(__LP64__) -#define TYPEDEF_UINTPTR -typedef unsigned long long int uintptr; -#endif - - - - - -#if defined(_NEED_SIZE_T_) -typedef long unsigned int size_t; -#endif - - - - - -#if defined(__sparc__) -#define TYPEDEF_ULONG -#endif - -/* - * If this is either a Linux hybrid build or the per-port code of a hybrid build - * then use the Linux header files to get some of the typedefs. Otherwise, define - * them entirely in this file. We can't always define the types because we get - * a duplicate typedef error; there is no way to "undefine" a typedef. - * We know when it's per-port code because each file defines LINUX_PORT at the top. - */ -#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) -#define TYPEDEF_UINT -#ifndef TARGETENV_android -#define TYPEDEF_USHORT -#define TYPEDEF_ULONG -#endif /* TARGETENV_android */ -#ifdef __KERNEL__ -#include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) -#define TYPEDEF_BOOL -#endif /* >= 2.6.19 */ -/* special detection for 2.6.18-128.7.1.0.1.el5 */ -#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) -#include -#ifdef noinline_for_stack -#define TYPEDEF_BOOL -#endif -#endif /* == 2.6.18 */ -#endif /* __KERNEL__ */ -#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ - - -/* Do not support the (u)int64 types with strict ansi for GNU C */ -#if defined(__GNUC__) && defined(__STRICT_ANSI__) -#define TYPEDEF_INT64 -#define TYPEDEF_UINT64 -#endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */ - -/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode - * for signed or unsigned - */ -#if defined(__ICL) - -#define TYPEDEF_INT64 - -#if defined(__STDC__) -#define TYPEDEF_UINT64 -#endif - -#endif /* __ICL */ - -#if !defined(__DJGPP__) - -/* pick up ushort & uint from standard types.h */ -#if defined(__KERNEL__) - -/* See note above */ -#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) -#include /* sys/types.h and linux/types.h are oil and water */ -#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ - -#else - -#include - -#endif /* linux && __KERNEL__ */ - -#endif - - -/* use the default typedefs in the next section of this file */ -#define USE_TYPEDEF_DEFAULTS - -#endif /* SITE_TYPEDEFS */ - - -/* - * Default Typedefs - */ - -#ifdef USE_TYPEDEF_DEFAULTS -#undef USE_TYPEDEF_DEFAULTS - -#ifndef TYPEDEF_BOOL -typedef /* @abstract@ */ unsigned char bool; -#endif /* endif TYPEDEF_BOOL */ - -/* define uchar, ushort, uint, ulong */ - -#ifndef TYPEDEF_UCHAR -typedef unsigned char uchar; -#endif - -#ifndef TYPEDEF_USHORT -typedef unsigned short ushort; -#endif - -#ifndef TYPEDEF_UINT -typedef unsigned int uint; -#endif - -#ifndef TYPEDEF_ULONG -typedef unsigned long ulong; -#endif - -/* define [u]int8/16/32/64, uintptr */ - -#ifndef TYPEDEF_UINT8 -typedef unsigned char uint8; -#endif - -#ifndef TYPEDEF_UINT16 -typedef unsigned short uint16; -#endif - -#ifndef TYPEDEF_UINT32 -typedef unsigned int uint32; -#endif - -#ifndef TYPEDEF_UINT64 -typedef unsigned long long uint64; -#endif - -#ifndef TYPEDEF_UINTPTR -typedef unsigned int uintptr; -#endif - -#ifndef TYPEDEF_INT8 -typedef signed char int8; -#endif - -#ifndef TYPEDEF_INT16 -typedef signed short int16; -#endif - -#ifndef TYPEDEF_INT32 -typedef signed int int32; -#endif - -#ifndef TYPEDEF_INT64 -typedef signed long long int64; -#endif - -/* define float32/64, float_t */ - -#ifndef TYPEDEF_FLOAT32 -typedef float float32; -#endif - -#ifndef TYPEDEF_FLOAT64 -typedef double float64; -#endif - -/* - * abstracted floating point type allows for compile time selection of - * single or double precision arithmetic. Compiling with -DFLOAT32 - * selects single precision; the default is double precision. - */ - -#ifndef TYPEDEF_FLOAT_T - -#if defined(FLOAT32) -typedef float32 float_t; -#else /* default to double precision floating point */ -typedef float64 float_t; -#endif - -#endif /* TYPEDEF_FLOAT_T */ - -/* define macro values */ - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 /* TRUE */ -#endif - -#ifndef NULL -#define NULL 0 -#endif - -#ifndef OFF -#define OFF 0 -#endif - -#ifndef ON -#define ON 1 /* ON = 1 */ -#endif - -#define AUTO (-1) /* Auto = -1 */ - -/* define PTRSZ, INLINE */ - -#ifndef PTRSZ -#define PTRSZ sizeof(char*) -#endif - - -/* Detect compiler type. */ -#if defined(__GNUC__) || defined(__lint) - #define BWL_COMPILER_GNU -#elif defined(__CC_ARM) && __CC_ARM - #define BWL_COMPILER_ARMCC -#else - #error "Unknown compiler!" -#endif - - -#ifndef INLINE - #if defined(BWL_COMPILER_MICROSOFT) - #define INLINE __inline - #elif defined(BWL_COMPILER_GNU) - #define INLINE __inline__ - #elif defined(BWL_COMPILER_ARMCC) - #define INLINE __inline - #else - #define INLINE - #endif -#endif /* INLINE */ - -#undef TYPEDEF_BOOL -#undef TYPEDEF_UCHAR -#undef TYPEDEF_USHORT -#undef TYPEDEF_UINT -#undef TYPEDEF_ULONG -#undef TYPEDEF_UINT8 -#undef TYPEDEF_UINT16 -#undef TYPEDEF_UINT32 -#undef TYPEDEF_UINT64 -#undef TYPEDEF_UINTPTR -#undef TYPEDEF_INT8 -#undef TYPEDEF_INT16 -#undef TYPEDEF_INT32 -#undef TYPEDEF_INT64 -#undef TYPEDEF_FLOAT32 -#undef TYPEDEF_FLOAT64 -#undef TYPEDEF_FLOAT_T - -#endif /* USE_TYPEDEF_DEFAULTS */ - -/* Suppress unused parameter warning */ -#define UNUSED_PARAMETER(x) (void)(x) - -/* Avoid warning for discarded const or volatile qualifier in special cases (-Wcast-qual) */ -#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) - -/* - * Including the bcmdefs.h here, to make sure everyone including typedefs.h - * gets this automatically -*/ -#include -#endif /* _TYPEDEFS_H_ */ diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h deleted file mode 100644 index 2a4b8fa5b17d..000000000000 --- a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h +++ /dev/null @@ -1,301 +0,0 @@ -/* -* Copyright (C) 1999-2017, Broadcom Corporation -* -* Unless you and Broadcom execute a separate written software license -* agreement governing use of this software, this software is licensed to you -* under the terms of the GNU General Public License version 2 (the "GPL"), -* available at http://www.broadcom.com/licenses/GPLv2.php, with the -* following added to such license: -* -* As a special exception, the copyright holders of this software give you -* permission to link this software with independent modules, and to copy and -* distribute the resulting executable under terms of your choice, provided that -* you also meet, for each linked independent module, the terms and conditions of -* the license of that module. An independent module is a module which is not -* derived from this software. The special exception does not apply to any -* modifications of the software. -* -* Notwithstanding the above, under no circumstances may you combine this -* software in any way with any other Broadcom software provided under a license -* other than the GPL, without Broadcom's express prior written consent. -* $Id: wlfc_proto.h 499510 2014-08-28 23:40:47Z $ -* -*/ -#ifndef __wlfc_proto_definitions_h__ -#define __wlfc_proto_definitions_h__ - - /* Use TLV to convey WLFC information. - --------------------------------------------------------------------------- - | Type | Len | value | Description - --------------------------------------------------------------------------- - | 1 | 1 | (handle) | MAC OPEN - --------------------------------------------------------------------------- - | 2 | 1 | (handle) | MAC CLOSE - --------------------------------------------------------------------------- - | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn - --------------------------------------------------------------------------- - | 4 | 4+ | see pkttag comments | TXSTATUS - | | | TX status & timestamps | Present only when pkt timestamp is enabled - --------------------------------------------------------------------------- - | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] - --------------------------------------------------------------------------- - | 6 | 8 | (handle, ifid, MAC) | MAC ADD - --------------------------------------------------------------------------- - | 7 | 8 | (handle, ifid, MAC) | MAC DEL - --------------------------------------------------------------------------- - | 8 | 1 | (rssi) | RSSI - RSSI value for the packet. - --------------------------------------------------------------------------- - | 9 | 1 | (interface ID) | Interface OPEN - --------------------------------------------------------------------------- - | 10 | 1 | (interface ID) | Interface CLOSE - --------------------------------------------------------------------------- - | 11 | 8 | fifo credit returns map | FIFO credits back to the host - | | | | - | | | | -------------------------------------- - | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim | - | | | | -------------------------------------- - | | | | - --------------------------------------------------------------------------- - | 12 | 2 | MAC handle, | Host provides a bitmap of pending - | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn. - | | | | [host->firmware] - --------------------------------------------------------------------------- - | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific - | | | | MAC destination. - --------------------------------------------------------------------------- - | 15 | 12 | (pkttag, timestamps) | Send TX timestamp at reception from host - --------------------------------------------------------------------------- - | 16 | 12 | (pkttag, timestamps) | Send WLAN RX timestamp along with RX frame - --------------------------------------------------------------------------- - | 255 | N/A | N/A | FILLER - This is a special type - | | | | that has no length or value. - | | | | Typically used for padding. - --------------------------------------------------------------------------- - */ - -#define WLFC_CTL_TYPE_MAC_OPEN 1 -#define WLFC_CTL_TYPE_MAC_CLOSE 2 -#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3 -#define WLFC_CTL_TYPE_TXSTATUS 4 -#define WLFC_CTL_TYPE_PKTTAG 5 - -#define WLFC_CTL_TYPE_MACDESC_ADD 6 -#define WLFC_CTL_TYPE_MACDESC_DEL 7 -#define WLFC_CTL_TYPE_RSSI 8 - -#define WLFC_CTL_TYPE_INTERFACE_OPEN 9 -#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 - -#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11 - -#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12 -#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 -#define WLFC_CTL_TYPE_HOST_REORDER_RXPKTS 14 - - -#define WLFC_CTL_TYPE_TX_ENTRY_STAMP 15 -#define WLFC_CTL_TYPE_RX_STAMP 16 - -#define WLFC_CTL_TYPE_TRANS_ID 18 -#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 - -#define WLFC_CTL_TYPE_TID_OPEN 20 -#define WLFC_CTL_TYPE_TID_CLOSE 21 - - -#define WLFC_CTL_TYPE_FILLER 255 - -#define WLFC_CTL_VALUE_LEN_MACDESC 8 /* handle, interface, MAC */ - -#define WLFC_CTL_VALUE_LEN_MAC 1 /* MAC-handle */ -#define WLFC_CTL_VALUE_LEN_RSSI 1 - -#define WLFC_CTL_VALUE_LEN_INTERFACE 1 -#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2 - -#define WLFC_CTL_VALUE_LEN_TXSTATUS 4 -#define WLFC_CTL_VALUE_LEN_PKTTAG 4 - -#define WLFC_CTL_VALUE_LEN_SEQ 2 - -/* enough space to host all 4 ACs, bc/mc and atim fifo credit */ -#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6 - -#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ -#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ - - -#define WLFC_PKTFLAG_PKTFROMHOST 0x01 /* packet originated from hot side */ -#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 /* packet requsted by firmware side */ -#define WLFC_PKTFLAG_PKT_FORCELOWRATE 0x04 /* force low rate for this packet */ - -#define WL_TXSTATUS_STATUS_MASK 0xff /* allow 8 bits */ -#define WL_TXSTATUS_STATUS_SHIFT 24 - -#define WL_TXSTATUS_SET_STATUS(x, status) ((x) = \ - ((x) & ~(WL_TXSTATUS_STATUS_MASK << WL_TXSTATUS_STATUS_SHIFT)) | \ - (((status) & WL_TXSTATUS_STATUS_MASK) << WL_TXSTATUS_STATUS_SHIFT)) -#define WL_TXSTATUS_GET_STATUS(x) (((x) >> WL_TXSTATUS_STATUS_SHIFT) & \ - WL_TXSTATUS_STATUS_MASK) - -#define WL_TXSTATUS_GENERATION_MASK 1 /* allow 1 bit */ -#define WL_TXSTATUS_GENERATION_SHIFT 31 - -#define WL_TXSTATUS_SET_GENERATION(x, gen) ((x) = \ - ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ - (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT)) - -#define WL_TXSTATUS_GET_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ - WL_TXSTATUS_GENERATION_MASK) - -#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ -#define WL_TXSTATUS_FLAGS_SHIFT 27 - -#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ - ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ - (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT)) -#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \ - WL_TXSTATUS_FLAGS_MASK) - -#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ -#define WL_TXSTATUS_FIFO_SHIFT 24 - -#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ - ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ - (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) -#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) - -#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ -#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ - ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) -#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) - -#define WL_TXSTATUS_HSLOT_MASK 0xffff /* allow 16 bits */ -#define WL_TXSTATUS_HSLOT_SHIFT 8 - -#define WL_TXSTATUS_SET_HSLOT(x, hslot) ((x) = \ - ((x) & ~(WL_TXSTATUS_HSLOT_MASK << WL_TXSTATUS_HSLOT_SHIFT)) | \ - (((hslot) & WL_TXSTATUS_HSLOT_MASK) << WL_TXSTATUS_HSLOT_SHIFT)) -#define WL_TXSTATUS_GET_HSLOT(x) (((x) >> WL_TXSTATUS_HSLOT_SHIFT)& \ - WL_TXSTATUS_HSLOT_MASK) - -#define WL_TXSTATUS_FREERUNCTR_MASK 0xff /* allow 8 bits */ - -#define WL_TXSTATUS_SET_FREERUNCTR(x, ctr) ((x) = \ - ((x) & ~(WL_TXSTATUS_FREERUNCTR_MASK)) | \ - ((ctr) & WL_TXSTATUS_FREERUNCTR_MASK)) -#define WL_TXSTATUS_GET_FREERUNCTR(x) ((x)& WL_TXSTATUS_FREERUNCTR_MASK) - -#define WL_SEQ_FROMFW_MASK 0x1 /* allow 1 bit */ -#define WL_SEQ_FROMFW_SHIFT 13 -#define WL_SEQ_SET_FROMFW(x, val) ((x) = \ - ((x) & ~(WL_SEQ_FROMFW_MASK << WL_SEQ_FROMFW_SHIFT)) | \ - (((val) & WL_SEQ_FROMFW_MASK) << WL_SEQ_FROMFW_SHIFT)) -#define WL_SEQ_GET_FROMFW(x) (((x) >> WL_SEQ_FROMFW_SHIFT) & \ - WL_SEQ_FROMFW_MASK) - -#define WL_SEQ_FROMDRV_MASK 0x1 /* allow 1 bit */ -#define WL_SEQ_FROMDRV_SHIFT 12 -#define WL_SEQ_SET_FROMDRV(x, val) ((x) = \ - ((x) & ~(WL_SEQ_FROMDRV_MASK << WL_SEQ_FROMDRV_SHIFT)) | \ - (((val) & WL_SEQ_FROMDRV_MASK) << WL_SEQ_FROMDRV_SHIFT)) -#define WL_SEQ_GET_FROMDRV(x) (((x) >> WL_SEQ_FROMDRV_SHIFT) & \ - WL_SEQ_FROMDRV_MASK) - -#define WL_SEQ_NUM_MASK 0xfff /* allow 12 bit */ -#define WL_SEQ_NUM_SHIFT 0 -#define WL_SEQ_SET_NUM(x, val) ((x) = \ - ((x) & ~(WL_SEQ_NUM_MASK << WL_SEQ_NUM_SHIFT)) | \ - (((val) & WL_SEQ_NUM_MASK) << WL_SEQ_NUM_SHIFT)) -#define WL_SEQ_GET_NUM(x) (((x) >> WL_SEQ_NUM_SHIFT) & \ - WL_SEQ_NUM_MASK) - -/* 32 STA should be enough??, 6 bits; Must be power of 2 */ -#define WLFC_MAC_DESC_TABLE_SIZE 32 -#define WLFC_MAX_IFNUM 16 -#define WLFC_MAC_DESC_ID_INVALID 0xff - -/* b[7:5] -reuse guard, b[4:0] -value */ -#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f) - -#define WLFC_MAX_PENDING_DATALEN 120 - -/* host is free to discard the packet */ -#define WLFC_CTL_PKTFLAG_DISCARD 0 -/* D11 suppressed a packet */ -#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1 -/* WL firmware suppressed a packet because MAC is - already in PSMode (short time window) -*/ -#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2 -/* Firmware tossed this packet */ -#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3 -/* Firmware tossed after retries */ -#define WLFC_CTL_PKTFLAG_DISCARD_NOACK 4 - -#define WLFC_D11_STATUS_INTERPRET(txs) \ - (((txs)->status.suppr_ind != TX_STATUS_SUPR_NONE) ? \ - WLFC_CTL_PKTFLAG_D11SUPPRESS : \ - ((txs)->status.was_acked ? \ - WLFC_CTL_PKTFLAG_DISCARD : WLFC_CTL_PKTFLAG_DISCARD_NOACK)) - -#ifdef PROP_TXSTATUS_DEBUG -#define WLFC_DBGMESG(x) printf x -/* wlfc-breadcrumb */ -#define WLFC_BREADCRUMB(x) do {if ((x) == NULL) \ - {printf("WLFC: %s():%d:caller:%p\n", \ - __FUNCTION__, __LINE__, __builtin_return_address(0));}} while (0) -#define WLFC_PRINTMAC(banner, ea) do {printf("%s MAC: [%02x:%02x:%02x:%02x:%02x:%02x]\n", \ - banner, ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); } while (0) -#define WLFC_WHEREIS(s) printf("WLFC: at %s():%d, %s\n", __FUNCTION__, __LINE__, (s)) -#else -#define WLFC_DBGMESG(x) -#define WLFC_BREADCRUMB(x) -#define WLFC_PRINTMAC(banner, ea) -#define WLFC_WHEREIS(s) -#endif - -/* AMPDU host reorder packet flags */ -#define WLHOST_REORDERDATA_MAXFLOWS 256 -#define WLHOST_REORDERDATA_LEN 10 -#define WLHOST_REORDERDATA_TOTLEN (WLHOST_REORDERDATA_LEN + 1 + 1) /* +tag +len */ - -#define WLHOST_REORDERDATA_FLOWID_OFFSET 0 -#define WLHOST_REORDERDATA_MAXIDX_OFFSET 2 -#define WLHOST_REORDERDATA_FLAGS_OFFSET 4 -#define WLHOST_REORDERDATA_CURIDX_OFFSET 6 -#define WLHOST_REORDERDATA_EXPIDX_OFFSET 8 - -#define WLHOST_REORDERDATA_DEL_FLOW 0x01 -#define WLHOST_REORDERDATA_FLUSH_ALL 0x02 -#define WLHOST_REORDERDATA_CURIDX_VALID 0x04 -#define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 -#define WLHOST_REORDERDATA_NEW_HOLE 0x10 - -/* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ -#define WLFC_CTL_TRANS_ID_LEN 6 -#define WLFC_TYPE_TRANS_ID_LEN 6 - -#define WLFC_MODE_HANGER 1 /* use hanger */ -#define WLFC_MODE_AFQ 2 /* use afq */ -#define WLFC_IS_OLD_DEF(x) ((x & 1) || (x & 2)) - -#define WLFC_MODE_AFQ_SHIFT 2 /* afq bit */ -#define WLFC_SET_AFQ(x, val) ((x) = \ - ((x) & ~(1 << WLFC_MODE_AFQ_SHIFT)) | \ - (((val) & 1) << WLFC_MODE_AFQ_SHIFT)) -#define WLFC_GET_AFQ(x) (((x) >> WLFC_MODE_AFQ_SHIFT) & 1) - -#define WLFC_MODE_REUSESEQ_SHIFT 3 /* seq reuse bit */ -#define WLFC_SET_REUSESEQ(x, val) ((x) = \ - ((x) & ~(1 << WLFC_MODE_REUSESEQ_SHIFT)) | \ - (((val) & 1) << WLFC_MODE_REUSESEQ_SHIFT)) -#define WLFC_GET_REUSESEQ(x) (((x) >> WLFC_MODE_REUSESEQ_SHIFT) & 1) - -#define WLFC_MODE_REORDERSUPP_SHIFT 4 /* host reorder suppress pkt bit */ -#define WLFC_SET_REORDERSUPP(x, val) ((x) = \ - ((x) & ~(1 << WLFC_MODE_REORDERSUPP_SHIFT)) | \ - (((val) & 1) << WLFC_MODE_REORDERSUPP_SHIFT)) -#define WLFC_GET_REORDERSUPP(x) (((x) >> WLFC_MODE_REORDERSUPP_SHIFT) & 1) - -#endif /* __wlfc_proto_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h deleted file mode 100644 index 65469208f67a..000000000000 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ /dev/null @@ -1,6675 +0,0 @@ -/* - * Custom OID/ioctl definitions for - * Broadcom 802.11abg Networking Device Driver - * - * Definitions subject to change without notice. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wlioctl.h 595011 2015-10-26 05:41:56Z $ - */ - -#ifndef _wlioctl_h_ -#define _wlioctl_h_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include - - - - - - -#ifndef INTF_NAME_SIZ -#define INTF_NAME_SIZ 16 -#endif - -/* Used to send ioctls over the transport pipe */ -typedef struct remote_ioctl { - cdc_ioctl_t msg; - uint32 data_len; - char intf_name[INTF_NAME_SIZ]; -} rem_ioctl_t; -#define REMOTE_SIZE sizeof(rem_ioctl_t) - -typedef struct { - uint32 num; - chanspec_t list[1]; -} chanspec_list_t; - -/* DFS Forced param */ -typedef struct wl_dfs_forced_params { - chanspec_t chspec; - uint16 version; - chanspec_list_t chspec_list; -} wl_dfs_forced_t; - -#define DFS_PREFCHANLIST_VER 0x01 -#define WL_CHSPEC_LIST_FIXED_SIZE OFFSETOF(chanspec_list_t, list) -#define WL_DFS_FORCED_PARAMS_FIXED_SIZE \ - (WL_CHSPEC_LIST_FIXED_SIZE + OFFSETOF(wl_dfs_forced_t, chspec_list)) -#define WL_DFS_FORCED_PARAMS_MAX_SIZE \ - WL_DFS_FORCED_PARAMS_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(chanspec_t)) - -/* association decision information */ -typedef struct { - bool assoc_approved; /* (re)association approved */ - uint16 reject_reason; /* reason code for rejecting association */ - struct ether_addr da; - int64 sys_time; /* current system time */ -} assoc_decision_t; - -#define ACTION_FRAME_SIZE 1800 - -typedef struct wl_action_frame { - struct ether_addr da; - uint16 len; - uint32 packetId; - uint8 data[ACTION_FRAME_SIZE]; -} wl_action_frame_t; - -#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) - -typedef struct ssid_info -{ - uint8 ssid_len; /* the length of SSID */ - uint8 ssid[32]; /* SSID string */ -} ssid_info_t; - -typedef struct wl_af_params { - uint32 channel; - int32 dwell_time; - struct ether_addr BSSID; - wl_action_frame_t action_frame; -} wl_af_params_t; - -#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) - -#define MFP_TEST_FLAG_NORMAL 0 -#define MFP_TEST_FLAG_ANY_KEY 1 -typedef struct wl_sa_query { - uint32 flag; - uint8 action; - uint16 id; - struct ether_addr da; -} wl_sa_query_t; - - -/* require default structure packing */ -#define BWL_DEFAULT_PACKING -#include - - -/* Flags for OBSS IOVAR Parameters */ -#define WL_OBSS_DYN_BWSW_FLAG_ACTIVITY_PERIOD (0x01) -#define WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_PERIOD (0x02) -#define WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_INCR_PERIOD (0x04) -#define WL_OBSS_DYN_BWSW_FLAG_PSEUDO_SENSE_PERIOD (0x08) -#define WL_OBSS_DYN_BWSW_FLAG_RX_CRS_PERIOD (0x10) -#define WL_OBSS_DYN_BWSW_FLAG_DUR_THRESHOLD (0x20) -#define WL_OBSS_DYN_BWSW_FLAG_TXOP_PERIOD (0x40) - -/* OBSS IOVAR Version information */ -#define WL_PROT_OBSS_CONFIG_PARAMS_VERSION 1 -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 obss_bwsw_activity_cfm_count_cfg; /* configurable count in - * seconds before we confirm that OBSS is present and - * dynamically activate dynamic bwswitch. - */ - uint8 obss_bwsw_no_activity_cfm_count_cfg; /* configurable count in - * seconds before we confirm that OBSS is GONE and - * dynamically start pseudo upgrade. If in pseudo sense time, we - * will see OBSS, [means that, we false detected that OBSS-is-gone - * in watchdog] this count will be incremented in steps of - * obss_bwsw_no_activity_cfm_count_incr_cfg for confirming OBSS - * detection again. Note that, at present, max 30seconds is - * allowed like this. [OBSS_BWSW_NO_ACTIVITY_MAX_INCR_DEFAULT] - */ - uint8 obss_bwsw_no_activity_cfm_count_incr_cfg; /* see above - */ - uint16 obss_bwsw_pseudo_sense_count_cfg; /* number of msecs/cnt to be in - * pseudo state. This is used to sense/measure the stats from lq. - */ - uint8 obss_bwsw_rx_crs_threshold_cfg; /* RX CRS default threshold */ - uint8 obss_bwsw_dur_thres; /* OBSS dyn bwsw trigger/RX CRS Sec */ - uint8 obss_bwsw_txop_threshold_cfg; /* TXOP default threshold */ -} BWL_POST_PACKED_STRUCT wlc_prot_dynbwsw_config_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 version; /* version field */ - uint32 config_mask; - uint32 reset_mask; - wlc_prot_dynbwsw_config_t config_params; -} BWL_POST_PACKED_STRUCT obss_config_params_t; - - - -/* Legacy structure to help keep backward compatible wl tool and tray app */ - -#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ - -typedef struct wl_bss_info_107 { - uint32 version; /* version field */ - uint32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - struct ether_addr BSSID; - uint16 beacon_period; /* units are Kusec */ - uint16 capability; /* Capability information */ - uint8 SSID_len; - uint8 SSID[32]; - struct { - uint count; /* # rates in this set */ - uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - uint8 channel; /* Channel no. */ - uint16 atim_window; /* units are Kusec */ - uint8 dtim_period; /* DTIM period */ - int16 RSSI; /* receive signal strength (in dBm) */ - int8 phy_noise; /* noise (in dBm) */ - uint32 ie_length; /* byte length of Information Elements */ - /* variable length Information Elements */ -} wl_bss_info_107_t; - -/* - * Per-BSS information structure. - */ - -#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */ - -/* BSS info structure - * Applications MUST CHECK ie_offset field and length field to access IEs and - * next bss_info structure in a vector (in wl_scan_results_t) - */ -typedef struct wl_bss_info_108 { - uint32 version; /* version field */ - uint32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - struct ether_addr BSSID; - uint16 beacon_period; /* units are Kusec */ - uint16 capability; /* Capability information */ - uint8 SSID_len; - uint8 SSID[32]; - struct { - uint count; /* # rates in this set */ - uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - chanspec_t chanspec; /* chanspec for bss */ - uint16 atim_window; /* units are Kusec */ - uint8 dtim_period; /* DTIM period */ - int16 RSSI; /* receive signal strength (in dBm) */ - int8 phy_noise; /* noise (in dBm) */ - - uint8 n_cap; /* BSS is 802.11N Capable */ - uint32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ - uint8 ctl_ch; /* 802.11N BSS control channel number */ - uint32 reserved32[1]; /* Reserved for expansion of BSS properties */ - uint8 flags; /* flags */ - uint8 reserved[3]; /* Reserved for expansion of BSS properties */ - uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ - - uint16 ie_offset; /* offset at which IEs start, from beginning */ - uint32 ie_length; /* byte length of Information Elements */ - /* Add new fields here */ - /* variable length Information Elements */ -} wl_bss_info_108_t; - - -#define WL_BSS_INFO_VERSION 109 /* current version of wl_bss_info struct */ - -/* BSS info structure - * Applications MUST CHECK ie_offset field and length field to access IEs and - * next bss_info structure in a vector (in wl_scan_results_t) - */ -typedef struct wl_bss_info { - uint32 version; /* version field */ - uint32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - struct ether_addr BSSID; - uint16 beacon_period; /* units are Kusec */ - uint16 capability; /* Capability information */ - uint8 SSID_len; - uint8 SSID[32]; - struct { - uint count; /* # rates in this set */ - uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - chanspec_t chanspec; /* chanspec for bss */ - uint16 atim_window; /* units are Kusec */ - uint8 dtim_period; /* DTIM period */ - int16 RSSI; /* receive signal strength (in dBm) */ - int8 phy_noise; /* noise (in dBm) */ - - uint8 n_cap; /* BSS is 802.11N Capable */ - uint32 nbss_cap; /* 802.11N+AC BSS Capabilities */ - uint8 ctl_ch; /* 802.11N BSS control channel number */ - uint8 padding1[3]; /* explicit struct alignment padding */ - uint16 vht_rxmcsmap; /* VHT rx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ - uint16 vht_txmcsmap; /* VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ - uint8 flags; /* flags */ - uint8 vht_cap; /* BSS is vht capable */ - uint8 reserved[2]; /* Reserved for expansion of BSS properties */ - uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ - - uint16 ie_offset; /* offset at which IEs start, from beginning */ - uint32 ie_length; /* byte length of Information Elements */ - int16 SNR; /* average SNR of during frame reception */ - /* Add new fields here */ - /* variable length Information Elements */ -} wl_bss_info_t; - -#define WL_GSCAN_BSS_INFO_VERSION 1 /* current version of wl_gscan_bss_info struct */ -#define WL_GSCAN_INFO_FIXED_FIELD_SIZE (sizeof(wl_gscan_bss_info_t) - sizeof(wl_bss_info_t)) - -typedef struct wl_gscan_bss_info { - uint32 timestamp[2]; - wl_bss_info_t info; - /* variable length Information Elements */ -} wl_gscan_bss_info_t; - - -typedef struct wl_bsscfg { - uint32 bsscfg_idx; - uint32 wsec; - uint32 WPA_auth; - uint32 wsec_index; - uint32 associated; - uint32 BSS; - uint32 phytest_on; - struct ether_addr prev_BSSID; - struct ether_addr BSSID; - uint32 targetbss_wpa2_flags; - uint32 assoc_type; - uint32 assoc_state; -} wl_bsscfg_t; - -typedef struct wl_if_add { - uint32 bsscfg_flags; - uint32 if_flags; - uint32 ap; - struct ether_addr mac_addr; -} wl_if_add_t; - -typedef struct wl_bss_config { - uint32 atim_window; - uint32 beacon_period; - uint32 chanspec; -} wl_bss_config_t; - -#define WL_BSS_USER_RADAR_CHAN_SELECT 0x1 /* User application will randomly select - * radar channel. - */ - -#define DLOAD_HANDLER_VER 1 /* Downloader version */ -#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ -#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ - -#define DL_CRC_NOT_INUSE 0x0001 - -/* generic download types & flags */ -enum { - DL_TYPE_UCODE = 1, - DL_TYPE_CLM = 2 -}; - -/* ucode type values */ -enum { - UCODE_FW, - INIT_VALS, - BS_INIT_VALS -}; - -struct wl_dload_data { - uint16 flag; - uint16 dload_type; - uint32 len; - uint32 crc; - uint8 data[1]; -}; -typedef struct wl_dload_data wl_dload_data_t; - -struct wl_ucode_info { - uint32 ucode_type; - uint32 num_chunks; - uint32 chunk_len; - uint32 chunk_num; - uint8 data_chunk[1]; -}; -typedef struct wl_ucode_info wl_ucode_info_t; - -struct wl_clm_dload_info { - uint32 ds_id; - uint32 clm_total_len; - uint32 num_chunks; - uint32 chunk_len; - uint32 chunk_offset; - uint8 data_chunk[1]; -}; -typedef struct wl_clm_dload_info wl_clm_dload_info_t; - - -typedef struct wlc_ssid { - uint32 SSID_len; - uchar SSID[DOT11_MAX_SSID_LEN]; -} wlc_ssid_t; - -typedef struct wlc_ssid_ext { - bool hidden; - uint16 flags; - uint8 SSID_len; - int8 rssi_thresh; - uchar SSID[DOT11_MAX_SSID_LEN]; -} wlc_ssid_ext_t; - - -#define MAX_PREFERRED_AP_NUM 5 -typedef struct wlc_fastssidinfo { - uint32 SSID_channel[MAX_PREFERRED_AP_NUM]; - wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM]; -} wlc_fastssidinfo_t; - -typedef BWL_PRE_PACKED_STRUCT struct wnm_url { - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT wnm_url_t; - -typedef struct chan_scandata { - uint8 txpower; - uint8 pad; - chanspec_t channel; /* Channel num, bw, ctrl_sb and band */ - uint32 channel_mintime; - uint32 channel_maxtime; -} chan_scandata_t; - -typedef enum wl_scan_type { - EXTDSCAN_FOREGROUND_SCAN, - EXTDSCAN_BACKGROUND_SCAN, - EXTDSCAN_FORCEDBACKGROUND_SCAN -} wl_scan_type_t; - -#define WLC_EXTDSCAN_MAX_SSID 5 - -typedef struct wl_extdscan_params { - int8 nprobes; /* 0, passive, otherwise active */ - int8 split_scan; /* split scan */ - int8 band; /* band */ - int8 pad; - wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /* ssid list */ - uint32 tx_rate; /* in 500ksec units */ - wl_scan_type_t scan_type; /* enum */ - int32 channel_num; - chan_scandata_t channel_list[1]; /* list of chandata structs */ -} wl_extdscan_params_t; - -#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) - -#define WL_SCAN_PARAMS_SSID_MAX 10 - -typedef struct wl_scan_params { - wlc_ssid_t ssid; /* default: {0, ""} */ - struct ether_addr bssid; /* default: bcast */ - int8 bss_type; /* default: any, - * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT - */ - uint8 scan_type; /* flags, 0 use default */ - int32 nprobes; /* -1 use default, number of probes per channel */ - int32 active_time; /* -1 use default, dwell time per channel for - * active scanning - */ - int32 passive_time; /* -1 use default, dwell time per channel - * for passive scanning - */ - int32 home_time; /* -1 use default, dwell time for the home channel - * between channel scans - */ - int32 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 wlc_ssid_t array that - * follows channel_list, aligned for int32 (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 - */ - uint16 channel_list[1]; /* list of chanspecs */ -} wl_scan_params_t; - -/* size of wl_scan_params not including variable length array */ -#define WL_SCAN_PARAMS_FIXED_SIZE 64 -#define WL_MAX_ROAMSCAN_DATSZ (WL_SCAN_PARAMS_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16))) - -#define ISCAN_REQ_VERSION 1 - -/* incremental scan struct */ -typedef struct wl_iscan_params { - uint32 version; - uint16 action; - uint16 scan_duration; - wl_scan_params_t params; -} wl_iscan_params_t; - -/* 3 fields + size of wl_scan_params, not including variable length array */ -#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) - -typedef struct wl_scan_results { - uint32 buflen; - uint32 version; - uint32 count; - wl_bss_info_t bss_info[1]; -} wl_scan_results_t; - -/* size of wl_scan_results not including variable length array */ -#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) - - -#define ESCAN_REQ_VERSION 1 - -typedef struct wl_escan_params { - uint32 version; - uint16 action; - uint16 sync_id; - wl_scan_params_t params; -} wl_escan_params_t; - -#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) - -typedef struct wl_escan_result { - uint32 buflen; - uint32 version; - uint16 sync_id; - uint16 bss_count; - wl_bss_info_t bss_info[1]; -} wl_escan_result_t; - -#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) - -typedef struct wl_gscan_result { - uint32 buflen; - uint32 version; - wl_gscan_bss_info_t bss_info[1]; -} wl_gscan_result_t; - -#define WL_GSCAN_RESULTS_FIXED_SIZE (sizeof(wl_gscan_result_t) - sizeof(wl_gscan_bss_info_t)) - -/* incremental scan results struct */ -typedef struct wl_iscan_results { - uint32 status; - wl_scan_results_t results; -} wl_iscan_results_t; - -/* size of wl_iscan_results not including variable length array */ -#define WL_ISCAN_RESULTS_FIXED_SIZE \ - (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) - -#define SCANOL_PARAMS_VERSION 1 - -typedef struct scanol_params { - uint32 version; - uint32 flags; /* offload scanning flags */ - int32 active_time; /* -1 use default, dwell time per channel for active scanning */ - int32 passive_time; /* -1 use default, dwell time per channel for passive scanning */ - int32 idle_rest_time; /* -1 use default, time idle between scan cycle */ - int32 idle_rest_time_multiplier; - int32 active_rest_time; - int32 active_rest_time_multiplier; - int32 scan_cycle_idle_rest_time; - int32 scan_cycle_idle_rest_multiplier; - int32 scan_cycle_active_rest_time; - int32 scan_cycle_active_rest_multiplier; - int32 max_rest_time; - int32 max_scan_cycles; - int32 nprobes; /* -1 use default, number of probes per channel */ - int32 scan_start_delay; - uint32 nchannels; - uint32 ssid_count; - wlc_ssid_t ssidlist[1]; -} scanol_params_t; - -typedef struct wl_probe_params { - wlc_ssid_t ssid; - struct ether_addr bssid; - struct ether_addr mac; -} wl_probe_params_t; - -#define WL_MAXRATES_IN_SET 16 /* max # of rates in a rateset */ -typedef struct wl_rateset { - uint32 count; /* # rates in this set */ - uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ -} wl_rateset_t; - -typedef struct wl_rateset_args { - uint32 count; /* # rates in this set */ - uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ - uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ - uint16 vht_mcs[VHT_CAP_MCS_MAP_NSS_MAX]; /* supported mcs index bit map per nss */ -} wl_rateset_args_t; - -#define TXBF_RATE_MCS_ALL 4 -#define TXBF_RATE_VHT_ALL 4 -#define TXBF_RATE_OFDM_ALL 8 - -typedef struct wl_txbf_rateset { - uint8 txbf_rate_mcs[TXBF_RATE_MCS_ALL]; /* one for each stream */ - uint8 txbf_rate_mcs_bcm[TXBF_RATE_MCS_ALL]; /* one for each stream */ - uint16 txbf_rate_vht[TXBF_RATE_VHT_ALL]; /* one for each stream */ - uint16 txbf_rate_vht_bcm[TXBF_RATE_VHT_ALL]; /* one for each stream */ - uint8 txbf_rate_ofdm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ - uint8 txbf_rate_ofdm_bcm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ - uint8 txbf_rate_ofdm_cnt; - uint8 txbf_rate_ofdm_cnt_bcm; -} wl_txbf_rateset_t; - -#define OFDM_RATE_MASK 0x0000007f -typedef uint8 ofdm_rates_t; - -typedef struct wl_rates_info { - wl_rateset_t rs_tgt; - uint32 phy_type; - int32 bandtype; - uint8 cck_only; - uint8 rate_mask; - uint8 mcsallow; - uint8 bw; - uint8 txstreams; -} wl_rates_info_t; - -/* uint32 list */ -typedef struct wl_uint32_list { - /* in - # of elements, out - # of entries */ - uint32 count; - /* variable length uint32 list */ - uint32 element[1]; -} wl_uint32_list_t; - -/* used for association with a specific BSSID and chanspec list */ -typedef struct wl_assoc_params { - struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */ - uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, - * otherwise count of chanspecs in chanspec_list - * AND paired bssids following chanspec_list - * also, chanspec_num has to be set to zero - * for bssid list to be used - */ - int32 chanspec_num; /* 0: all available channels, - * otherwise count of chanspecs in chanspec_list - */ - chanspec_t chanspec_list[1]; /* list of chanspecs */ -} wl_assoc_params_t; - -#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) - -/* used for reassociation/roam to a specific BSSID and channel */ -typedef wl_assoc_params_t wl_reassoc_params_t; -#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE - -/* used for association to a specific BSSID and channel */ -typedef wl_assoc_params_t wl_join_assoc_params_t; -#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE - -/* used for join with or without a specific bssid and channel list */ -typedef struct wl_join_params { - wlc_ssid_t ssid; - wl_assoc_params_t params; /* optional field, but it must include the fixed portion - * of the wl_assoc_params_t struct when it does present. - */ -} wl_join_params_t; - -typedef struct wlc_roam_exp_params { - int8 a_band_boost_threshold; - int8 a_band_penalty_threshold; - uint8 a_band_boost_factor; - uint8 a_band_penalty_factor; - uint8 cur_bssid_boost; - int8 alert_roam_trigger_threshold; - uint16 a_band_max_boost; -} wlc_roam_exp_params_t; - -#define ROAM_EXP_CFG_VERSION 1 -#define ROAM_EXP_ENABLE_FLAG (1 << 0) -#define ROAM_EXP_CFG_PRESENT (1 << 1) -typedef struct wl_roam_exp_cfg { - uint8 version; - uint8 flags; - uint16 reserved; - wlc_roam_exp_params_t params; -} wl_roam_exp_cfg_t; - -typedef struct wl_bssid_pref_list { - struct ether_addr bssid; - /* Add this to modify rssi */ - int8 rssi_factor; - int8 flags; -} wl_bssid_pref_list_t; - -#define BSSID_PREF_LIST_VERSION 1 -#define ROAM_EXP_CLEAR_BSSID_PREF (1 << 0) -typedef struct wl_bssid_pref_cfg { - uint8 version; - uint8 flags; - uint16 count; - wl_bssid_pref_list_t bssids[1]; -} wl_bssid_pref_cfg_t; - -#define SSID_WHITELIST_VERSION 1 -#define ROAM_EXP_CLEAR_SSID_WHITELIST (1 << 0) -/* Roam SSID whitelist, ssids in this list are ok to */ -/* be considered as targets to join when considering a roam */ -typedef struct wl_ssid_whitelist { - uint8 version; - uint8 flags; - uint8 ssid_count; - uint8 reserved; - wlc_ssid_t ssids[1]; -} wl_ssid_whitelist_t; - -#define ROAM_EXP_EVENT_VERSION 1 -typedef struct wl_roam_exp_event { - uint8 version; - uint8 flags; - uint16 reserved; - wlc_ssid_t cur_ssid; -} wl_roam_exp_event_t; - -#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \ - WL_ASSOC_PARAMS_FIXED_SIZE) -/* scan params for extended join */ -typedef struct wl_join_scan_params { - uint8 scan_type; /* 0 use default, active or passive scan */ - int32 nprobes; /* -1 use default, number of probes per channel */ - int32 active_time; /* -1 use default, dwell time per channel for - * active scanning - */ - int32 passive_time; /* -1 use default, dwell time per channel - * for passive scanning - */ - int32 home_time; /* -1 use default, dwell time for the home channel - * between channel scans - */ -} wl_join_scan_params_t; - -/* extended join params */ -typedef struct wl_extjoin_params { - wlc_ssid_t ssid; /* {0, ""}: wildcard scan */ - wl_join_scan_params_t scan; - wl_join_assoc_params_t assoc; /* optional field, but it must include the fixed portion - * of the wl_join_assoc_params_t struct when it does - * present. - */ -} wl_extjoin_params_t; -#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \ - WL_JOIN_ASSOC_PARAMS_FIXED_SIZE) - -#define ANT_SELCFG_MAX 4 /* max number of antenna configurations */ -#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ -typedef struct { - uint8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ - uint8 num_antcfg; /* number of available antenna configurations */ -} wlc_antselcfg_t; - -typedef struct { - uint32 duration; /* millisecs spent sampling this channel */ - uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ - /* move if cur bss moves channels) */ - uint32 congest_obss; /* traffic not in our bss */ - uint32 interference; /* millisecs detecting a non 802.11 interferer. */ - uint32 timestamp; /* second timestamp */ -} cca_congest_t; - -typedef struct { - chanspec_t chanspec; /* Which channel? */ - uint8 num_secs; /* How many secs worth of data */ - cca_congest_t secs[1]; /* Data */ -} cca_congest_channel_req_t; - - -/* interference sources */ -enum interference_source { - ITFR_NONE = 0, /* interference */ - ITFR_PHONE, /* wireless phone */ - ITFR_VIDEO_CAMERA, /* wireless video camera */ - ITFR_MICROWAVE_OVEN, /* microwave oven */ - ITFR_BABY_MONITOR, /* wireless baby monitor */ - ITFR_BLUETOOTH, /* bluetooth */ - ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /* wireless camera or baby monitor */ - ITFR_BLUETOOTH_OR_BABY_MONITOR, /* bluetooth or baby monitor */ - ITFR_VIDEO_CAMERA_OR_PHONE, /* video camera or phone */ - ITFR_UNIDENTIFIED /* interference from unidentified source */ -}; - -/* structure for interference source report */ -typedef struct { - uint32 flags; /* flags. bit definitions below */ - uint32 source; /* last detected interference source */ - uint32 timestamp; /* second timestamp on interferenced flag change */ -} interference_source_rep_t; - -#define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ - -typedef struct wl_country { - char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in - * the Country IE - */ - int32 rev; /* revision specifier for ccode - * on set, -1 indicates unspecified. - * on get, rev >= 0 - */ - char ccode[WLC_CNTRY_BUF_SZ]; /* nul-terminated built-in country code. - * variable length, but fixed size in - * struct allows simple allocation for - * expected country strings <= 3 chars. - */ -} wl_country_t; - -typedef struct wl_channels_in_country { - uint32 buflen; - uint32 band; - char country_abbrev[WLC_CNTRY_BUF_SZ]; - uint32 count; - uint32 channel[1]; -} wl_channels_in_country_t; - -typedef struct wl_country_list { - uint32 buflen; - uint32 band_set; - uint32 band; - uint32 count; - char country_abbrev[1]; -} wl_country_list_t; - -typedef struct wl_rm_req_elt { - int8 type; - int8 flags; - chanspec_t chanspec; - uint32 token; /* token for this measurement */ - uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ - uint32 tsf_l; /* TSF low 32-bits */ - uint32 dur; /* TUs */ -} wl_rm_req_elt_t; - -typedef struct wl_rm_req { - uint32 token; /* overall measurement set token */ - uint32 count; /* number of measurement requests */ - void *cb; /* completion callback function: may be NULL */ - void *cb_arg; /* arg to completion callback function */ - wl_rm_req_elt_t req[1]; /* variable length block of requests */ -} wl_rm_req_t; -#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) - -typedef struct wl_rm_rep_elt { - int8 type; - int8 flags; - chanspec_t chanspec; - uint32 token; /* token for this measurement */ - uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ - uint32 tsf_l; /* TSF low 32-bits */ - uint32 dur; /* TUs */ - uint32 len; /* byte length of data block */ - uint8 data[1]; /* variable length data block */ -} wl_rm_rep_elt_t; -#define WL_RM_REP_ELT_FIXED_LEN 24 /* length excluding data block */ - -#define WL_RPI_REP_BIN_NUM 8 -typedef struct wl_rm_rpi_rep { - uint8 rpi[WL_RPI_REP_BIN_NUM]; - int8 rpi_max[WL_RPI_REP_BIN_NUM]; -} wl_rm_rpi_rep_t; - -typedef struct wl_rm_rep { - uint32 token; /* overall measurement set token */ - uint32 len; /* length of measurement report block */ - wl_rm_rep_elt_t rep[1]; /* variable length block of reports */ -} wl_rm_rep_t; -#define WL_RM_REP_FIXED_LEN 8 - -#ifdef BCMCCX - -#define LEAP_USER_MAX 32 -#define LEAP_DOMAIN_MAX 32 -#define LEAP_PASSWORD_MAX 32 - -typedef struct wl_leap_info { - wlc_ssid_t ssid; - uint8 user_len; - uchar user[LEAP_USER_MAX]; - uint8 password_len; - uchar password[LEAP_PASSWORD_MAX]; - uint8 domain_len; - uchar domain[LEAP_DOMAIN_MAX]; -} wl_leap_info_t; - -typedef struct wl_leap_list { - uint32 buflen; - uint32 version; - uint32 count; - wl_leap_info_t leap_info[1]; -} wl_leap_list_t; -#endif /* BCMCCX */ - -typedef enum sup_auth_status { - /* Basic supplicant authentication states */ - WLC_SUP_DISCONNECTED = 0, - WLC_SUP_CONNECTING, - WLC_SUP_IDREQUIRED, - WLC_SUP_AUTHENTICATING, - WLC_SUP_AUTHENTICATED, - WLC_SUP_KEYXCHANGE, - WLC_SUP_KEYED, - WLC_SUP_TIMEOUT, - WLC_SUP_LAST_BASIC_STATE, - - /* Extended supplicant authentication states */ - /* Waiting to receive handshake msg M1 */ - WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, - /* Preparing to send handshake msg M2 */ - WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, - /* Waiting to receive handshake msg M3 */ - WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, - WLC_SUP_KEYXCHANGE_PREP_M4, /* Preparing to send handshake msg M4 */ - WLC_SUP_KEYXCHANGE_WAIT_G1, /* Waiting to receive handshake msg G1 */ - WLC_SUP_KEYXCHANGE_PREP_G2 /* Preparing to send handshake msg G2 */ -} sup_auth_status_t; - -typedef struct wl_wsec_key { - uint32 index; /* key index */ - uint32 len; /* key length */ - uint8 data[DOT11_MAX_KEY_SIZE]; /* key data */ - uint32 pad_1[18]; - uint32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ - uint32 flags; /* misc flags */ - uint32 pad_2[2]; - int pad_3; - int iv_initialized; /* has IV been initialized already? */ - int pad_4; - /* Rx IV */ - struct { - uint32 hi; /* upper 32 bits of IV */ - uint16 lo; /* lower 16 bits of IV */ - } rxiv; - uint32 pad_5[2]; - struct ether_addr ea; /* per station */ -} wl_wsec_key_t; - -#define WSEC_MIN_PSK_LEN 8 -#define WSEC_MAX_PSK_LEN 64 - -/* Flag for key material needing passhash'ing */ -#define WSEC_PASSPHRASE (1<<0) - -/* receptacle for WLC_SET_WSEC_PMK parameter */ -typedef struct { - ushort key_len; /* octets in key material */ - ushort flags; /* key handling qualification */ - uint8 key[WSEC_MAX_PSK_LEN]; /* PMK material */ -} wsec_pmk_t; - -typedef struct _pmkid { - struct ether_addr BSSID; - uint8 PMKID[WPA2_PMKID_LEN]; -} pmkid_t; - -typedef struct _pmkid_list { - uint32 npmkid; - pmkid_t pmkid[1]; -} pmkid_list_t; - -typedef struct _pmkid_cand { - struct ether_addr BSSID; - uint8 preauth; -} pmkid_cand_t; - -typedef struct _pmkid_cand_list { - uint32 npmkid_cand; - pmkid_cand_t pmkid_cand[1]; -} pmkid_cand_list_t; - -#define WL_STA_ANT_MAX 4 /* max possible rx antennas */ - -typedef struct wl_assoc_info { - uint32 req_len; - uint32 resp_len; - uint32 flags; - struct dot11_assoc_req req; - struct ether_addr reassoc_bssid; /* used in reassoc's */ - struct dot11_assoc_resp resp; -} wl_assoc_info_t; - -typedef struct wl_led_info { - uint32 index; /* led index */ - uint32 behavior; - uint8 activehi; -} wl_led_info_t; - - -/* srom read/write struct passed through ioctl */ -typedef struct { - uint byteoff; /* byte offset */ - uint nbytes; /* number of bytes */ - uint16 buf[1]; -} srom_rw_t; - -#define CISH_FLAG_PCIECIS (1 << 15) /* write CIS format bit for PCIe CIS */ -/* similar cis (srom or otp) struct [iovar: may not be aligned] */ -typedef struct { - uint16 source; /* cis source */ - uint16 flags; /* flags */ - uint32 byteoff; /* byte offset */ - uint32 nbytes; /* number of bytes */ - /* data follows here */ -} cis_rw_t; - -/* R_REG and W_REG struct passed through ioctl */ -typedef struct { - uint32 byteoff; /* byte offset of the field in d11regs_t */ - uint32 val; /* read/write value of the field */ - uint32 size; /* sizeof the field */ - uint band; /* band (optional) */ -} rw_reg_t; - -/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */ -/* PCL - Power Control Loop */ -typedef struct { - uint16 auto_ctrl; /* WL_ATTEN_XX */ - uint16 bb; /* Baseband attenuation */ - uint16 radio; /* Radio attenuation */ - uint16 txctl1; /* Radio TX_CTL1 value */ -} atten_t; - -/* Per-AC retry parameters */ -struct wme_tx_params_s { - uint8 short_retry; - uint8 short_fallback; - uint8 long_retry; - uint8 long_fallback; - uint16 max_rate; /* In units of 512 Kbps */ -}; - -typedef struct wme_tx_params_s wme_tx_params_t; - -#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) - -typedef struct wl_plc_nodelist { - uint32 count; /* Number of nodes */ - struct _node { - struct ether_addr ea; /* Node ether address */ - uint32 node_type; /* Node type */ - uint32 cost; /* PLC affinity */ - } node[1]; -} wl_plc_nodelist_t; - -typedef struct wl_plc_params { - uint32 cmd; /* Command */ - uint8 plc_failover; /* PLC failover control/status */ - struct ether_addr node_ea; /* Node ether address */ - uint32 cost; /* Link cost or mac cost */ -} wl_plc_params_t; - -/* Used to get specific link/ac parameters */ -typedef struct { - int32 ac; - uint8 val; - struct ether_addr ea; -} link_val_t; - - -#define WL_PM_MUTE_TX_VER 1 - -typedef struct wl_pm_mute_tx { - uint16 version; /* version */ - uint16 len; /* length */ - uint16 deadline; /* deadline timer (in milliseconds) */ - uint8 enable; /* set to 1 to enable mode; set to 0 to disable it */ -} wl_pm_mute_tx_t; - - -typedef struct { - uint16 ver; /* version of this struct */ - uint16 len; /* length in bytes of this structure */ - uint16 cap; /* sta's advertised capabilities */ - uint32 flags; /* flags defined below */ - uint32 idle; /* time since data pkt rx'd from sta */ - struct ether_addr ea; /* Station address */ - wl_rateset_t rateset; /* rateset in use */ - uint32 in; /* seconds elapsed since associated */ - uint32 listen_interval_inms; /* Min Listen interval in ms for this STA */ - uint32 tx_pkts; /* # of user packets transmitted (unicast) */ - uint32 tx_failures; /* # of user packets failed */ - uint32 rx_ucast_pkts; /* # of unicast packets received */ - uint32 rx_mcast_pkts; /* # of multicast packets received */ - uint32 tx_rate; /* Rate used by last tx frame */ - uint32 rx_rate; /* Rate of last successful rx frame */ - uint32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ - uint32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */ - uint32 tx_tot_pkts; /* # of user tx pkts (ucast + mcast) */ - uint32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */ - uint32 tx_mcast_pkts; /* # of mcast pkts txed */ - uint64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */ - uint64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */ - uint64 tx_ucast_bytes; /* data bytes txed (ucast) */ - uint64 tx_mcast_bytes; /* # data bytes txed (mcast) */ - uint64 rx_ucast_bytes; /* data bytes recvd (ucast) */ - uint64 rx_mcast_bytes; /* data bytes recvd (mcast) */ - int8 rssi[WL_STA_ANT_MAX]; /* average rssi per antenna - * of data frames - */ - int8 nf[WL_STA_ANT_MAX]; /* per antenna noise floor */ - uint16 aid; /* association ID */ - uint16 ht_capabilities; /* advertised ht caps */ - uint16 vht_flags; /* converted vht flags */ - uint32 tx_pkts_retried; /* # of frames where a retry was - * necessary - */ - uint32 tx_pkts_retry_exhausted; /* # of user frames where a retry - * was exhausted - */ - int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /* Per antenna RSSI of last - * received data frame. - */ - /* TX WLAN retry/failure statistics: - * Separated for host requested frames and WLAN locally generated frames. - * Include unicast frame only where the retries/failures can be counted. - */ - uint32 tx_pkts_total; /* # user frames sent successfully */ - uint32 tx_pkts_retries; /* # user frames retries */ - uint32 tx_pkts_fw_total; /* # FW generated sent successfully */ - uint32 tx_pkts_fw_retries; /* # retries for FW generated frames */ - uint32 tx_pkts_fw_retry_exhausted; /* # FW generated where a retry - * was exhausted - */ - uint32 rx_pkts_retried; /* # rx with retry bit set */ - uint32 tx_rate_fallback; /* lowest fallback TX rate */ -} sta_info_t; - -#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts) - -#define WL_STA_VER 4 - -#define WLC_NUMRATES 16 /* max # of rates in a rateset */ - -typedef struct wlc_rateset { - uint32 count; /* number of rates in rates[] */ - uint8 rates[WLC_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */ - uint8 htphy_membership; /* HT PHY Membership */ - uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ - uint16 vht_mcsmap; /* supported vht mcs nss bit map */ -} wlc_rateset_t; - -/* Used to get specific STA parameters */ -typedef struct { - uint32 val; - struct ether_addr ea; -} scb_val_t; - -/* Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */ -typedef struct { - uint32 code; - scb_val_t ioctl_args; -} authops_t; - -/* channel encoding */ -typedef struct channel_info { - int hw_channel; - int target_channel; - int scan_channel; -} channel_info_t; - -/* For ioctls that take a list of MAC addresses */ -typedef struct maclist { - uint count; /* number of MAC addresses */ - struct ether_addr ea[1]; /* variable length array of MAC addresses */ -} maclist_t; - -/* get pkt count struct passed through ioctl */ -typedef struct get_pktcnt { - uint rx_good_pkt; - uint rx_bad_pkt; - uint tx_good_pkt; - uint tx_bad_pkt; - uint rx_ocast_good_pkt; /* unicast packets destined for others */ -} get_pktcnt_t; - -/* NINTENDO2 */ -#define LQ_IDX_MIN 0 -#define LQ_IDX_MAX 1 -#define LQ_IDX_AVG 2 -#define LQ_IDX_SUM 2 -#define LQ_IDX_LAST 3 -#define LQ_STOP_MONITOR 0 -#define LQ_START_MONITOR 1 - -/* Get averages RSSI, Rx PHY rate and SNR values */ -typedef struct { - int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */ - int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */ - int isvalid; /* Flag indicating whether above data is valid */ -} wl_lq_t; /* Link Quality */ - -typedef enum wl_wakeup_reason_type { - LCD_ON = 1, - LCD_OFF, - DRC1_WAKE, - DRC2_WAKE, - REASON_LAST -} wl_wr_type_t; - -typedef struct { -/* Unique filter id */ - uint32 id; - -/* stores the reason for the last wake up */ - uint8 reason; -} wl_wr_t; - -/* Get MAC specific rate histogram command */ -typedef struct { - struct ether_addr ea; /* MAC Address */ - uint8 ac_cat; /* Access Category */ - uint8 num_pkts; /* Number of packet entries to be averaged */ -} wl_mac_ratehisto_cmd_t; /* MAC Specific Rate Histogram command */ - -/* Get MAC rate histogram response */ -typedef struct { - uint32 rate[DOT11_RATE_MAX + 1]; /* Rates */ - uint32 mcs[WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX]; /* MCS counts */ - uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /* VHT counts */ - uint32 tsf_timer[2][2]; /* Start and End time for 8bytes value */ -} wl_mac_ratehisto_res_t; /* MAC Specific Rate Histogram Response */ - -/* Linux network driver ioctl encoding */ -typedef struct wl_ioctl { - uint cmd; /* common ioctl definition */ - void *buf; /* pointer to user buffer */ - uint len; /* length of user buffer */ - uint8 set; /* 1=set IOCTL; 0=query IOCTL */ - uint used; /* bytes read or written (optional) */ - uint needed; /* bytes needed (optional) */ -} wl_ioctl_t; - -#ifdef CONFIG_COMPAT -typedef struct compat_wl_ioctl { - uint cmd; /* common ioctl definition */ - uint32 buf; /* pointer to user buffer */ - uint len; /* length of user buffer */ - uint8 set; /* 1=set IOCTL; 0=query IOCTL */ - uint used; /* bytes read or written (optional) */ - uint needed; /* bytes needed (optional) */ -} compat_wl_ioctl_t; -#endif /* CONFIG_COMPAT */ - -#define WL_NUM_RATES_CCK 4 /* 1, 2, 5.5, 11 Mbps */ -#define WL_NUM_RATES_OFDM 8 /* 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */ -#define WL_NUM_RATES_MCS_1STREAM 8 /* MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */ -#define WL_NUM_RATES_EXTRA_VHT 2 /* Additional VHT 11AC rates */ -#define WL_NUM_RATES_VHT 10 -#define WL_NUM_RATES_MCS32 1 - -/* - * Structure for passing hardware and software - * revision info up from the driver. - */ -typedef struct wlc_rev_info { - uint vendorid; /* PCI vendor id */ - uint deviceid; /* device id of chip */ - uint radiorev; /* radio revision */ - uint chiprev; /* chip revision */ - uint corerev; /* core revision */ - uint boardid; /* board identifier (usu. PCI sub-device id) */ - uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ - uint boardrev; /* board revision */ - uint driverrev; /* driver version */ - uint ucoderev; /* microcode version */ - uint bus; /* bus type */ - uint chipnum; /* chip number */ - uint phytype; /* phy type */ - uint phyrev; /* phy revision */ - uint anarev; /* anacore rev */ - uint chippkg; /* chip package info */ - uint nvramrev; /* nvram revision number */ -} wlc_rev_info_t; - -#define WL_REV_INFO_LEGACY_LENGTH 48 - -#define WL_BRAND_MAX 10 -typedef struct wl_instance_info { - uint instance; - char brand[WL_BRAND_MAX]; -} wl_instance_info_t; - -/* structure to change size of tx fifo */ -typedef struct wl_txfifo_sz { - uint16 magic; - uint16 fifo; - uint16 size; -} wl_txfifo_sz_t; - -/* Transfer info about an IOVar from the driver */ -/* Max supported IOV name size in bytes, + 1 for nul termination */ -#define WLC_IOV_NAME_LEN 30 -typedef struct wlc_iov_trx_s { - uint8 module; - uint8 type; - char name[WLC_IOV_NAME_LEN]; -} wlc_iov_trx_t; - -/* bump this number if you change the ioctl interface */ -#define WLC_IOCTL_VERSION 2 -#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1 - -#ifdef CONFIG_USBRNDIS_RETAIL -/* struct passed in for WLC_NDCONFIG_ITEM */ -typedef struct { - char *name; - void *param; -} ndconfig_item_t; -#endif - - -#define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[0] ... */ - -#define WL_PHY_PAVAR_VER 1 /* pavars version */ -#define WL_PHY_PAVARS2_NUM 3 /* a1, b0, b1 */ -typedef struct wl_pavars2 { - uint16 ver; /* version of this struct */ - uint16 len; /* len of this structure */ - uint16 inuse; /* driver return 1 for a1,b0,b1 in current band range */ - uint16 phy_type; /* phy type */ - uint16 bandrange; - uint16 chain; - uint16 inpa[WL_PHY_PAVARS2_NUM]; /* phy pavars for one band range */ -} wl_pavars2_t; - -typedef struct wl_po { - uint16 phy_type; /* Phy type */ - uint16 band; - uint16 cckpo; - uint32 ofdmpo; - uint16 mcspo[8]; -} wl_po_t; - -#define WL_NUM_RPCALVARS 5 /* number of rpcal vars */ - -typedef struct wl_rpcal { - uint16 value; - uint16 update; -} wl_rpcal_t; - -typedef struct wl_aci_args { - int enter_aci_thresh; /* Trigger level to start detecting ACI */ - int exit_aci_thresh; /* Trigger level to exit ACI mode */ - int usec_spin; /* microsecs to delay between rssi samples */ - int glitch_delay; /* interval between ACI scans when glitch count is consistently high */ - uint16 nphy_adcpwr_enter_thresh; /* ADC power to enter ACI mitigation mode */ - uint16 nphy_adcpwr_exit_thresh; /* ADC power to exit ACI mitigation mode */ - uint16 nphy_repeat_ctr; /* Number of tries per channel to compute power */ - uint16 nphy_num_samples; /* Number of samples to compute power on one channel */ - uint16 nphy_undetect_window_sz; /* num of undetects to exit ACI Mitigation mode */ - uint16 nphy_b_energy_lo_aci; /* low ACI power energy threshold for bphy */ - uint16 nphy_b_energy_md_aci; /* mid ACI power energy threshold for bphy */ - uint16 nphy_b_energy_hi_aci; /* high ACI power energy threshold for bphy */ - uint16 nphy_noise_noassoc_glitch_th_up; /* wl interference 4 */ - uint16 nphy_noise_noassoc_glitch_th_dn; - uint16 nphy_noise_assoc_glitch_th_up; - uint16 nphy_noise_assoc_glitch_th_dn; - uint16 nphy_noise_assoc_aci_glitch_th_up; - uint16 nphy_noise_assoc_aci_glitch_th_dn; - uint16 nphy_noise_assoc_enter_th; - uint16 nphy_noise_noassoc_enter_th; - uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; - uint16 nphy_noise_noassoc_crsidx_incr; - uint16 nphy_noise_assoc_crsidx_incr; - uint16 nphy_noise_crsidx_decr; -} wl_aci_args_t; - -#define WL_ACI_ARGS_LEGACY_LENGTH 16 /* bytes of pre NPHY aci args */ -#define WL_SAMPLECOLLECT_T_VERSION 2 /* version of wl_samplecollect_args_t struct */ -typedef struct wl_samplecollect_args { - /* version 0 fields */ - uint8 coll_us; - int cores; - /* add'l version 1 fields */ - uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */ - uint16 length; /* length of entire structure */ - int8 trigger; - uint16 timeout; - uint16 mode; - uint32 pre_dur; - uint32 post_dur; - uint8 gpio_sel; - uint8 downsamp; - uint8 be_deaf; - uint8 agc; /* loop from init gain and going down */ - uint8 filter; /* override high pass corners to lowest */ - /* add'l version 2 fields */ - uint8 trigger_state; - uint8 module_sel1; - uint8 module_sel2; - uint16 nsamps; - int bitStart; - uint32 gpioCapMask; -} wl_samplecollect_args_t; - -#define WL_SAMPLEDATA_T_VERSION 1 /* version of wl_samplecollect_args_t struct */ -/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */ -#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 - -typedef struct wl_sampledata { - uint16 version; /* structure version */ - uint16 size; /* size of structure */ - uint16 tag; /* Header/Data */ - uint16 length; /* data length */ - uint32 flag; /* bit def */ -} wl_sampledata_t; - - -/* WL_OTA START */ -/* OTA Test Status */ -enum { - WL_OTA_TEST_IDLE = 0, /* Default Idle state */ - WL_OTA_TEST_ACTIVE = 1, /* Test Running */ - WL_OTA_TEST_SUCCESS = 2, /* Successfully Finished Test */ - WL_OTA_TEST_FAIL = 3 /* Test Failed in the Middle */ -}; -/* OTA SYNC Status */ -enum { - WL_OTA_SYNC_IDLE = 0, /* Idle state */ - WL_OTA_SYNC_ACTIVE = 1, /* Waiting for Sync */ - WL_OTA_SYNC_FAIL = 2 /* Sync pkt not recieved */ -}; - -/* Various error states dut can get stuck during test */ -enum { - WL_OTA_SKIP_TEST_CAL_FAIL = 1, /* Phy calibration failed */ - WL_OTA_SKIP_TEST_SYNCH_FAIL = 2, /* Sync Packet not recieved */ - WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL = 3, /* Cmd flow file download failed */ - WL_OTA_SKIP_TEST_NO_TEST_FOUND = 4, /* No test found in Flow file */ - WL_OTA_SKIP_TEST_WL_NOT_UP = 5, /* WL UP failed */ - WL_OTA_SKIP_TEST_UNKNOWN_CALL /* Unintentional scheduling on ota test */ -}; - -/* Differentiator for ota_tx and ota_rx */ -enum { - WL_OTA_TEST_TX = 0, /* ota_tx */ - WL_OTA_TEST_RX = 1, /* ota_rx */ -}; - -/* Catch 3 modes of operation: 20Mhz, 40Mhz, 20 in 40 Mhz */ -enum { - WL_OTA_TEST_BW_20_IN_40MHZ = 0, /* 20 in 40 operation */ - WL_OTA_TEST_BW_20MHZ = 1, /* 20 Mhz operation */ - WL_OTA_TEST_BW_40MHZ = 2 /* full 40Mhz operation */ -}; -typedef struct ota_rate_info { - uint8 rate_cnt; /* Total number of rates */ - uint8 rate_val_mbps[WL_OTA_TEST_MAX_NUM_RATE]; /* array of rates from 1mbps to 130mbps */ - /* for legacy rates : ratein mbps * 2 */ - /* for HT rates : mcs index */ -} ota_rate_info_t; - -typedef struct ota_power_info { - int8 pwr_ctrl_on; /* power control on/off */ - int8 start_pwr; /* starting power/index */ - int8 delta_pwr; /* delta power/index */ - int8 end_pwr; /* end power/index */ -} ota_power_info_t; - -typedef struct ota_packetengine { - uint16 delay; /* Inter-packet delay */ - /* for ota_tx, delay is tx ifs in micro seconds */ - /* for ota_rx, delay is wait time in milliseconds */ - uint16 nframes; /* Number of frames */ - uint16 length; /* Packet length */ -} ota_packetengine_t; - -/* Test info vector */ -typedef struct wl_ota_test_args { - uint8 cur_test; /* test phase */ - uint8 chan; /* channel */ - uint8 bw; /* bandwidth */ - uint8 control_band; /* control band */ - uint8 stf_mode; /* stf mode */ - ota_rate_info_t rt_info; /* Rate info */ - ota_packetengine_t pkteng; /* packeteng info */ - uint8 txant; /* tx antenna */ - uint8 rxant; /* rx antenna */ - ota_power_info_t pwr_info; /* power sweep info */ - uint8 wait_for_sync; /* wait for sync or not */ -} wl_ota_test_args_t; - -typedef struct wl_ota_test_vector { - wl_ota_test_args_t test_arg[WL_OTA_TEST_MAX_NUM_SEQ]; /* Test argument struct */ - uint16 test_cnt; /* Total no of test */ - uint8 file_dwnld_valid; /* File successfully downloaded */ - uint8 sync_timeout; /* sync packet timeout */ - int8 sync_fail_action; /* sync fail action */ - struct ether_addr sync_mac; /* macaddress for sync pkt */ - struct ether_addr tx_mac; /* macaddress for tx */ - struct ether_addr rx_mac; /* macaddress for rx */ - int8 loop_test; /* dbg feature to loop the test */ -} wl_ota_test_vector_t; - - -/* struct copied back form dongle to host to query the status */ -typedef struct wl_ota_test_status { - int16 cur_test_cnt; /* test phase */ - int8 skip_test_reason; /* skip test reasoin */ - wl_ota_test_args_t test_arg; /* cur test arg details */ - uint16 test_cnt; /* total no of test downloaded */ - uint8 file_dwnld_valid; /* file successfully downloaded ? */ - uint8 sync_timeout; /* sync timeout */ - int8 sync_fail_action; /* sync fail action */ - struct ether_addr sync_mac; /* macaddress for sync pkt */ - struct ether_addr tx_mac; /* tx mac address */ - struct ether_addr rx_mac; /* rx mac address */ - uint8 test_stage; /* check the test status */ - int8 loop_test; /* Debug feature to puts test enfine in a loop */ - uint8 sync_status; /* sync status */ -} wl_ota_test_status_t; - -/* WL_OTA END */ - -/* wl_radar_args_t */ -typedef struct { - int npulses; /* required number of pulses at n * t_int */ - int ncontig; /* required number of pulses at t_int */ - int min_pw; /* minimum pulse width (20 MHz clocks) */ - int max_pw; /* maximum pulse width (20 MHz clocks) */ - uint16 thresh0; /* Radar detection, thresh 0 */ - uint16 thresh1; /* Radar detection, thresh 1 */ - uint16 blank; /* Radar detection, blank control */ - uint16 fmdemodcfg; /* Radar detection, fmdemod config */ - int npulses_lp; /* Radar detection, minimum long pulses */ - int min_pw_lp; /* Minimum pulsewidth for long pulses */ - int max_pw_lp; /* Maximum pulsewidth for long pulses */ - int min_fm_lp; /* Minimum fm for long pulses */ - int max_span_lp; /* Maximum deltat for long pulses */ - int min_deltat; /* Minimum spacing between pulses */ - int max_deltat; /* Maximum spacing between pulses */ - uint16 autocorr; /* Radar detection, autocorr on or off */ - uint16 st_level_time; /* Radar detection, start_timing level */ - uint16 t2_min; /* minimum clocks needed to remain in state 2 */ - uint32 version; /* version */ - uint32 fra_pulse_err; /* sample error margin for detecting French radar pulsed */ - int npulses_fra; /* Radar detection, minimum French pulses set */ - int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */ - int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */ - uint16 percal_mask; /* defines which period cal is masked from radar detection */ - int quant; /* quantization resolution to pulse positions */ - uint32 min_burst_intv_lp; /* minimum burst to burst interval for bin3 radar */ - uint32 max_burst_intv_lp; /* maximum burst to burst interval for bin3 radar */ - int nskip_rst_lp; /* number of skipped pulses before resetting lp buffer */ - int max_pw_tol; /* maximum tollerance allowed in detected pulse width for radar detection */ - uint16 feature_mask; /* 16-bit mask to specify enabled features */ -} wl_radar_args_t; - -#define WL_RADAR_ARGS_VERSION 2 - -typedef struct { - uint32 version; /* version */ - uint16 thresh0_20_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */ - uint16 thresh1_20_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */ - uint16 thresh0_40_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */ - uint16 thresh1_40_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */ - uint16 thresh0_80_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */ - uint16 thresh1_80_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */ - uint16 thresh0_20_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */ - uint16 thresh1_20_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */ - uint16 thresh0_40_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */ - uint16 thresh1_40_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */ - uint16 thresh0_80_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */ - uint16 thresh1_80_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */ -#ifdef WL11AC160 - uint16 thresh0_160_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */ - uint16 thresh1_160_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */ - uint16 thresh0_160_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */ - uint16 thresh1_160_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */ -#endif /* WL11AC160 */ -} wl_radar_thr_t; - -#define WL_RADAR_THR_VERSION 2 - -/* RSSI per antenna */ -typedef struct { - uint32 version; /* version field */ - uint32 count; /* number of valid antenna rssi */ - int8 rssi_ant[WL_RSSI_ANT_MAX]; /* rssi per antenna */ -} wl_rssi_ant_t; - -/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */ -typedef struct { - uint state; /* noted by WL_DFS_CACSTATE_XX. */ - uint duration; /* time spent in ms in state. */ - /* as dfs enters ISM state, it removes the operational channel from quiet channel - * list and notes the channel in channel_cleared. set to 0 if no channel is cleared - */ - chanspec_t chanspec_cleared; - /* chanspec cleared used to be a uint, add another to uint16 to maintain size */ - uint16 pad; -} wl_dfs_status_t; - -/* data structure used in 'radar_status' wl interface, which is use to query radar det status */ -typedef struct { - bool detected; - int count; - bool pretended; - uint32 radartype; - uint32 timenow; - uint32 timefromL; - int lp_csect_single; - int detected_pulse_index; - int nconsecq_pulses; - chanspec_t ch; - int pw[10]; - int intv[10]; - int fm[10]; -} wl_radar_status_t; - -#define NUM_PWRCTRL_RATES 12 - -typedef struct { - uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /* User set target */ - uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /* reg and local power limit */ - uint8 txpwr_local_max; /* local max according to the AP */ - uint8 txpwr_local_constraint; /* local constraint according to the AP */ - uint8 txpwr_chan_reg_max; /* Regulatory max for this channel */ - uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /* Latest target for 2.4 and 5 Ghz */ - uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ - uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /* On G phy, OFDM power offset */ - uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /* Max CCK power for this band (SROM) */ - uint8 txpwr_bphy_ofdm_max; /* Max OFDM power for this band (SROM) */ - uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /* Max power for A band (SROM) */ - int8 txpwr_antgain[2]; /* Ant gain for each band - from SROM */ - uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ -} tx_power_legacy_t; - -#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 - -typedef struct { - uint32 flags; - chanspec_t chanspec; /* txpwr report for this channel */ - chanspec_t local_chanspec; /* channel on which we are associated */ - uint8 local_max; /* local max according to the AP */ - uint8 local_constraint; /* local constraint according to the AP */ - int8 antgain[2]; /* Ant gain for each band - from SROM */ - uint8 rf_cores; /* count of RF Cores being reported */ - uint8 est_Pout[4]; /* Latest tx power out estimate per RF - * chain without adjustment - */ - uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ - uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */ - uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */ - uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */ - uint8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */ -} tx_power_legacy2_t; - -/* TX Power index defines */ -#define WLC_NUM_RATES_CCK WL_NUM_RATES_CCK -#define WLC_NUM_RATES_OFDM WL_NUM_RATES_OFDM -#define WLC_NUM_RATES_MCS_1_STREAM WL_NUM_RATES_MCS_1STREAM -#define WLC_NUM_RATES_MCS_2_STREAM WL_NUM_RATES_MCS_1STREAM -#define WLC_NUM_RATES_MCS32 WL_NUM_RATES_MCS32 -#define WL_TX_POWER_CCK_NUM WL_NUM_RATES_CCK -#define WL_TX_POWER_OFDM_NUM WL_NUM_RATES_OFDM -#define WL_TX_POWER_MCS_1_STREAM_NUM WL_NUM_RATES_MCS_1STREAM -#define WL_TX_POWER_MCS_2_STREAM_NUM WL_NUM_RATES_MCS_1STREAM -#define WL_TX_POWER_MCS_32_NUM WL_NUM_RATES_MCS32 - -#define WL_NUM_2x2_ELEMENTS 4 -#define WL_NUM_3x3_ELEMENTS 6 - -typedef struct { - uint16 ver; /* version of this struct */ - uint16 len; /* length in bytes of this structure */ - uint32 flags; - chanspec_t chanspec; /* txpwr report for this channel */ - chanspec_t local_chanspec; /* channel on which we are associated */ - uint32 buflen; /* ppr buffer length */ - uint8 pprbuf[1]; /* Latest target power buffer */ -} wl_txppr_t; - -#define WL_TXPPR_VERSION 1 -#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) -#define TX_POWER_T_VERSION 45 -/* number of ppr serialization buffers, it should be reg, board and target */ -#define WL_TXPPR_SER_BUF_NUM (3) - -typedef struct chanspec_txpwr_max { - chanspec_t chanspec; /* chanspec */ - uint8 txpwr_max; /* max txpwr in all the rates */ - uint8 padding; -} chanspec_txpwr_max_t; - -typedef struct wl_chanspec_txpwr_max { - uint16 ver; /* version of this struct */ - uint16 len; /* length in bytes of this structure */ - uint32 count; /* number of elements of (chanspec, txpwr_max) pair */ - chanspec_txpwr_max_t txpwr[1]; /* array of (chanspec, max_txpwr) pair */ -} wl_chanspec_txpwr_max_t; - -#define WL_CHANSPEC_TXPWR_MAX_VER 1 -#define WL_CHANSPEC_TXPWR_MAX_LEN (sizeof(wl_chanspec_txpwr_max_t)) - -typedef struct tx_inst_power { - uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ - uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ -} tx_inst_power_t; - -#define WL_NUM_TXCHAIN_MAX 4 -typedef struct wl_txchain_pwr_offsets { - int8 offset[WL_NUM_TXCHAIN_MAX]; /* quarter dBm signed offset for each chain */ -} wl_txchain_pwr_offsets_t; -/* maximum channels returned by the get valid channels iovar */ -#define WL_NUMCHANNELS 64 - -/* - * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, - * a one-byte length, and a variable length value. RSSI type tuple must be present - * in the array. - * - * Types are defined in "join preference types" section. - * - * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple - * and must be set to zero. - * - * Values are defined below. - * - * 1. RSSI - 2 octets - * offset 0: reserved - * offset 1: reserved - * - * 2. WPA - 2 + 12 * n octets (n is # tuples defined below) - * offset 0: reserved - * offset 1: # of tuples - * offset 2: tuple 1 - * offset 14: tuple 2 - * ... - * offset 2 + 12 * (n - 1) octets: tuple n - * - * struct wpa_cfg_tuple { - * uint8 akm[DOT11_OUI_LEN+1]; akm suite - * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite - * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite - * }; - * - * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY. - * - * 3. BAND - 2 octets - * offset 0: reserved - * offset 1: see "band preference" and "band types" - * - * 4. BAND RSSI - 2 octets - * offset 0: band types - * offset 1: +ve RSSI boost value in dB - */ - -struct tsinfo_arg { - uint8 octets[3]; -}; - -#define RATE_CCK_1MBPS 0 -#define RATE_CCK_2MBPS 1 -#define RATE_CCK_5_5MBPS 2 -#define RATE_CCK_11MBPS 3 - -#define RATE_LEGACY_OFDM_6MBPS 0 -#define RATE_LEGACY_OFDM_9MBPS 1 -#define RATE_LEGACY_OFDM_12MBPS 2 -#define RATE_LEGACY_OFDM_18MBPS 3 -#define RATE_LEGACY_OFDM_24MBPS 4 -#define RATE_LEGACY_OFDM_36MBPS 5 -#define RATE_LEGACY_OFDM_48MBPS 6 -#define RATE_LEGACY_OFDM_54MBPS 7 - -#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION 1 - -typedef struct wl_bsstrans_rssi { - int8 rssi_2g; /* RSSI in dbm for 2.4 G */ - int8 rssi_5g; /* RSSI in dbm for 5G, unused for cck */ -} wl_bsstrans_rssi_t; - -#define RSSI_RATE_MAP_MAX_STREAMS 4 /* max streams supported */ - -/* RSSI to rate mapping, all 20Mhz, no SGI */ -typedef struct wl_bsstrans_rssi_rate_map { - uint16 ver; - uint16 len; /* length of entire structure */ - wl_bsstrans_rssi_t cck[WL_NUM_RATES_CCK]; /* 2.4G only */ - wl_bsstrans_rssi_t ofdm[WL_NUM_RATES_OFDM]; /* 6 to 54mbps */ - wl_bsstrans_rssi_t phy_n[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_MCS_1STREAM]; /* MCS0-7 */ - wl_bsstrans_rssi_t phy_ac[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_VHT]; /* MCS0-9 */ -} wl_bsstrans_rssi_rate_map_t; - -#define WL_BSSTRANS_ROAMTHROTTLE_VERSION 1 - -/* Configure number of scans allowed per throttle period */ -typedef struct wl_bsstrans_roamthrottle { - uint16 ver; - uint16 period; - uint16 scans_allowed; -} wl_bsstrans_roamthrottle_t; - -#define NFIFO 6 /* # tx/rx fifopairs */ -#define NREINITREASONCOUNT 8 -#define REINITREASONIDX(_x) (((_x) < NREINITREASONCOUNT) ? (_x) : 0) - -#define WL_CNT_T_VERSION 10 /* current version of wl_cnt_t struct */ - -typedef struct { - uint16 version; /* see definition of WL_CNT_T_VERSION */ - uint16 length; /* length of entire structure */ - - /* transmit stat counters */ - uint32 txframe; /* tx data frames */ - uint32 txbyte; /* tx data bytes */ - uint32 txretrans; /* tx mac retransmits */ - uint32 txerror; /* tx data errors (derived: sum of others) */ - uint32 txctl; /* tx management frames */ - uint32 txprshort; /* tx short preamble frames */ - uint32 txserr; /* tx status errors */ - uint32 txnobuf; /* tx out of buffers errors */ - uint32 txnoassoc; /* tx discard because we're not associated */ - uint32 txrunt; /* tx runt frames */ - uint32 txchit; /* tx header cache hit (fastpath) */ - uint32 txcmiss; /* tx header cache miss (slowpath) */ - - /* transmit chip error counters */ - uint32 txuflo; /* tx fifo underflows */ - uint32 txphyerr; /* tx phy errors (indicated in tx status) */ - uint32 txphycrs; - - /* receive stat counters */ - uint32 rxframe; /* rx data frames */ - uint32 rxbyte; /* rx data bytes */ - uint32 rxerror; /* rx data errors (derived: sum of others) */ - uint32 rxctl; /* rx management frames */ - uint32 rxnobuf; /* rx out of buffers errors */ - uint32 rxnondata; /* rx non data frames in the data channel errors */ - uint32 rxbadds; /* rx bad DS errors */ - uint32 rxbadcm; /* rx bad control or management frames */ - uint32 rxfragerr; /* rx fragmentation errors */ - uint32 rxrunt; /* rx runt frames */ - uint32 rxgiant; /* rx giant frames */ - uint32 rxnoscb; /* rx no scb error */ - uint32 rxbadproto; /* rx invalid frames */ - uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ - uint32 rxbadda; /* rx frames tossed for invalid da */ - uint32 rxfilter; /* rx frames filtered out */ - - /* receive chip error counters */ - uint32 rxoflo; /* rx fifo overflow errors */ - uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ - - uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ - uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ - uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ - - /* misc counters */ - uint32 dmade; /* tx/rx dma descriptor errors */ - uint32 dmada; /* tx/rx dma data errors */ - uint32 dmape; /* tx/rx dma descriptor protocol errors */ - uint32 reset; /* reset count */ - uint32 tbtt; /* cnts the TBTT int's */ - uint32 txdmawar; - uint32 pkt_callback_reg_fail; /* callbacks register failure */ - - /* MAC counters: 32-bit version of d11.h's macstat_t */ - uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, - * Control Management (includes retransmissions) - */ - uint32 txrtsfrm; /* number of RTS sent out by the MAC */ - uint32 txctsfrm; /* number of CTS sent out by the MAC */ - uint32 txackfrm; /* number of ACK frames sent out */ - uint32 txdnlfrm; /* Not used */ - uint32 txbcnfrm; /* beacons transmitted */ - uint32 txfunfl[6]; /* per-fifo tx underflows */ - uint32 rxtoolate; /* receive too late */ - uint32 txfbw; /* transmit at fallback bw (dynamic bw) */ - uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS - * or BCN) - */ - uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for - * driver enqueued frames - */ - uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ - uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ - uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not - * data/control/management - */ - uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ - uint32 rxbadplcp; /* parity check of the PLCP header failed */ - uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ - uint32 rxstrt; /* Number of received frames with a good PLCP - * (i.e. passing parity check) - */ - uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ - uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ - uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ - uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ - uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ - uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ - uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ - uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ - uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ - uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ - uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ - uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ - uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ - uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC - * (unlikely to see these) - */ - uint32 rxbeaconmbss; /* beacons received from member of BSS */ - uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from - * other BSS (WDS FRAME) - */ - uint32 rxbeaconobss; /* beacons received from other BSS */ - uint32 rxrsptmout; /* Number of response timeouts for transmitted frames - * expecting a response - */ - uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ - uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ - uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ - uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ - uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ - uint32 pmqovfl; /* Number of PMQ overflows */ - uint32 rxcgprqfrm; /* Number of received Probe requests that made it into - * the PRQ fifo - */ - uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ - uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did - * not get ACK - */ - uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ - uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ - * fifo because a probe response could not be sent out within - * the time limit defined in M_PRS_MAXTIME - */ - uint32 rxnack; /* obsolete */ - uint32 frmscons; /* obsolete */ - uint32 txnack; /* obsolete */ - uint32 rxback; /* blockack rxcnt */ - uint32 txback; /* blockack txcnt */ - - /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ - uint32 txfrag; /* dot11TransmittedFragmentCount */ - uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ - uint32 txfail; /* dot11FailedCount */ - uint32 txretry; /* dot11RetryCount */ - uint32 txretrie; /* dot11MultipleRetryCount */ - uint32 rxdup; /* dot11FrameduplicateCount */ - uint32 txrts; /* dot11RTSSuccessCount */ - uint32 txnocts; /* dot11RTSFailureCount */ - uint32 txnoack; /* dot11ACKFailureCount */ - uint32 rxfrag; /* dot11ReceivedFragmentCount */ - uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ - uint32 rxcrc; /* dot11FCSErrorCount */ - uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ - uint32 rxundec; /* dot11WEPUndecryptableCount */ - - /* WPA2 counters (see rxundec for DecryptFailureCount) */ - uint32 tkipmicfaill; /* TKIPLocalMICFailures */ - uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ - uint32 tkipreplay; /* TKIPReplays */ - uint32 ccmpfmterr; /* CCMPFormatErrors */ - uint32 ccmpreplay; /* CCMPReplays */ - uint32 ccmpundec; /* CCMPDecryptErrors */ - uint32 fourwayfail; /* FourWayHandshakeFailures */ - uint32 wepundec; /* dot11WEPUndecryptableCount */ - uint32 wepicverr; /* dot11WEPICVErrorCount */ - uint32 decsuccess; /* DecryptSuccessCount */ - uint32 tkipicverr; /* TKIPICVErrorCount */ - uint32 wepexcluded; /* dot11WEPExcludedCount */ - - uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ - uint32 psmwds; /* Count PSM watchdogs */ - uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ - - /* MBSS counters, AP only */ - uint32 prq_entries_handled; /* PRQ entries read in */ - uint32 prq_undirected_entries; /* which were bcast bss & ssid */ - uint32 prq_bad_entries; /* which could not be translated to info */ - uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ - uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ - uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ - uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ - - /* per-rate receive stat counters */ - uint32 rx1mbps; /* packets rx at 1Mbps */ - uint32 rx2mbps; /* packets rx at 2Mbps */ - uint32 rx5mbps5; /* packets rx at 5.5Mbps */ - uint32 rx6mbps; /* packets rx at 6Mbps */ - uint32 rx9mbps; /* packets rx at 9Mbps */ - uint32 rx11mbps; /* packets rx at 11Mbps */ - uint32 rx12mbps; /* packets rx at 12Mbps */ - uint32 rx18mbps; /* packets rx at 18Mbps */ - uint32 rx24mbps; /* packets rx at 24Mbps */ - uint32 rx36mbps; /* packets rx at 36Mbps */ - uint32 rx48mbps; /* packets rx at 48Mbps */ - uint32 rx54mbps; /* packets rx at 54Mbps */ - uint32 rx108mbps; /* packets rx at 108mbps */ - uint32 rx162mbps; /* packets rx at 162mbps */ - uint32 rx216mbps; /* packets rx at 216 mbps */ - uint32 rx270mbps; /* packets rx at 270 mbps */ - uint32 rx324mbps; /* packets rx at 324 mbps */ - uint32 rx378mbps; /* packets rx at 378 mbps */ - uint32 rx432mbps; /* packets rx at 432 mbps */ - uint32 rx486mbps; /* packets rx at 486 mbps */ - uint32 rx540mbps; /* packets rx at 540 mbps */ - - /* pkteng rx frame stats */ - uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ - uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ - - uint32 rfdisable; /* count of radio disables */ - uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ - uint32 bphy_badplcp; - - uint32 txexptime; /* Tx frames suppressed due to timer expiration */ - - uint32 txmpdu_sgi; /* count for sgi transmit */ - uint32 rxmpdu_sgi; /* count for sgi received */ - uint32 txmpdu_stbc; /* count for stbc transmit */ - uint32 rxmpdu_stbc; /* count for stbc received */ - - uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ - - /* WPA2 counters (see rxundec for DecryptFailureCount) */ - uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ - uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ - uint32 tkipreplay_mcst; /* TKIPReplays */ - uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ - uint32 ccmpreplay_mcst; /* CCMPReplays */ - uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ - uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ - uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ - uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ - uint32 decsuccess_mcst; /* DecryptSuccessCount */ - uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ - uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ - - uint32 dma_hang; /* count for dma hang */ - uint32 reinit; /* count for reinit */ - - uint32 pstatxucast; /* count of ucast frames xmitted on all psta assoc */ - uint32 pstatxnoassoc; /* count of txnoassoc frames xmitted on all psta assoc */ - uint32 pstarxucast; /* count of ucast frames received on all psta assoc */ - uint32 pstarxbcmc; /* count of bcmc frames received on all psta */ - uint32 pstatxbcmc; /* count of bcmc frames transmitted on all psta */ - - uint32 cso_passthrough; /* hw cso required but passthrough */ - uint32 cso_normal; /* hw cso hdr for normal process */ - uint32 chained; /* number of frames chained */ - uint32 chainedsz1; /* number of chain size 1 frames */ - uint32 unchained; /* number of frames not chained */ - uint32 maxchainsz; /* max chain size so far */ - uint32 currchainsz; /* current chain size */ - uint32 rxdrop20s; /* drop secondary cnt */ - uint32 pciereset; /* Secondary Bus Reset issued by driver */ - uint32 cfgrestore; /* configspace restore by driver */ - uint32 reinitreason[NREINITREASONCOUNT]; /* reinitreason counters; 0: Unknown reason */ - uint32 rxrtry; /* num of received packets with retry bit on */ -} wl_cnt_t; - -typedef struct { - uint16 version; /* see definition of WL_CNT_T_VERSION */ - uint16 length; /* length of entire structure */ - - /* transmit stat counters */ - uint32 txframe; /* tx data frames */ - uint32 txbyte; /* tx data bytes */ - uint32 txretrans; /* tx mac retransmits */ - uint32 txerror; /* tx data errors (derived: sum of others) */ - uint32 txctl; /* tx management frames */ - uint32 txprshort; /* tx short preamble frames */ - uint32 txserr; /* tx status errors */ - uint32 txnobuf; /* tx out of buffers errors */ - uint32 txnoassoc; /* tx discard because we're not associated */ - uint32 txrunt; /* tx runt frames */ - uint32 txchit; /* tx header cache hit (fastpath) */ - uint32 txcmiss; /* tx header cache miss (slowpath) */ - - /* transmit chip error counters */ - uint32 txuflo; /* tx fifo underflows */ - uint32 txphyerr; /* tx phy errors (indicated in tx status) */ - uint32 txphycrs; - - /* receive stat counters */ - uint32 rxframe; /* rx data frames */ - uint32 rxbyte; /* rx data bytes */ - uint32 rxerror; /* rx data errors (derived: sum of others) */ - uint32 rxctl; /* rx management frames */ - uint32 rxnobuf; /* rx out of buffers errors */ - uint32 rxnondata; /* rx non data frames in the data channel errors */ - uint32 rxbadds; /* rx bad DS errors */ - uint32 rxbadcm; /* rx bad control or management frames */ - uint32 rxfragerr; /* rx fragmentation errors */ - uint32 rxrunt; /* rx runt frames */ - uint32 rxgiant; /* rx giant frames */ - uint32 rxnoscb; /* rx no scb error */ - uint32 rxbadproto; /* rx invalid frames */ - uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ - uint32 rxbadda; /* rx frames tossed for invalid da */ - uint32 rxfilter; /* rx frames filtered out */ - - /* receive chip error counters */ - uint32 rxoflo; /* rx fifo overflow errors */ - uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ - - uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ - uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ - uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ - - /* misc counters */ - uint32 dmade; /* tx/rx dma descriptor errors */ - uint32 dmada; /* tx/rx dma data errors */ - uint32 dmape; /* tx/rx dma descriptor protocol errors */ - uint32 reset; /* reset count */ - uint32 tbtt; /* cnts the TBTT int's */ - uint32 txdmawar; - uint32 pkt_callback_reg_fail; /* callbacks register failure */ - - /* MAC counters: 32-bit version of d11.h's macstat_t */ - uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, - * Control Management (includes retransmissions) - */ - uint32 txrtsfrm; /* number of RTS sent out by the MAC */ - uint32 txctsfrm; /* number of CTS sent out by the MAC */ - uint32 txackfrm; /* number of ACK frames sent out */ - uint32 txdnlfrm; /* Not used */ - uint32 txbcnfrm; /* beacons transmitted */ - uint32 txfunfl[6]; /* per-fifo tx underflows */ - uint32 rxtoolate; /* receive too late */ - uint32 txfbw; /* transmit at fallback bw (dynamic bw) */ - uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS - * or BCN) - */ - uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for - * driver enqueued frames - */ - uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ - uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ - uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not - * data/control/management - */ - uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ - uint32 rxbadplcp; /* parity check of the PLCP header failed */ - uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ - uint32 rxstrt; /* Number of received frames with a good PLCP - * (i.e. passing parity check) - */ - uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ - uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ - uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ - uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ - uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ - uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ - uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ - uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ - uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ - uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ - uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ - uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ - uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ - uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC - * (unlikely to see these) - */ - uint32 rxbeaconmbss; /* beacons received from member of BSS */ - uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from - * other BSS (WDS FRAME) - */ - uint32 rxbeaconobss; /* beacons received from other BSS */ - uint32 rxrsptmout; /* Number of response timeouts for transmitted frames - * expecting a response - */ - uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ - uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ - uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ - uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ - uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ - uint32 pmqovfl; /* Number of PMQ overflows */ - uint32 rxcgprqfrm; /* Number of received Probe requests that made it into - * the PRQ fifo - */ - uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ - uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did - * not get ACK - */ - uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ - uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ - * fifo because a probe response could not be sent out within - * the time limit defined in M_PRS_MAXTIME - */ - uint32 rxnack; - uint32 frmscons; - uint32 txnack; /* obsolete */ - uint32 rxback; /* blockack rxcnt */ - uint32 txback; /* blockack txcnt */ - - /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ - uint32 txfrag; /* dot11TransmittedFragmentCount */ - uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ - uint32 txfail; /* dot11FailedCount */ - uint32 txretry; /* dot11RetryCount */ - uint32 txretrie; /* dot11MultipleRetryCount */ - uint32 rxdup; /* dot11FrameduplicateCount */ - uint32 txrts; /* dot11RTSSuccessCount */ - uint32 txnocts; /* dot11RTSFailureCount */ - uint32 txnoack; /* dot11ACKFailureCount */ - uint32 rxfrag; /* dot11ReceivedFragmentCount */ - uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ - uint32 rxcrc; /* dot11FCSErrorCount */ - uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ - uint32 rxundec; /* dot11WEPUndecryptableCount */ - - /* WPA2 counters (see rxundec for DecryptFailureCount) */ - uint32 tkipmicfaill; /* TKIPLocalMICFailures */ - uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ - uint32 tkipreplay; /* TKIPReplays */ - uint32 ccmpfmterr; /* CCMPFormatErrors */ - uint32 ccmpreplay; /* CCMPReplays */ - uint32 ccmpundec; /* CCMPDecryptErrors */ - uint32 fourwayfail; /* FourWayHandshakeFailures */ - uint32 wepundec; /* dot11WEPUndecryptableCount */ - uint32 wepicverr; /* dot11WEPICVErrorCount */ - uint32 decsuccess; /* DecryptSuccessCount */ - uint32 tkipicverr; /* TKIPICVErrorCount */ - uint32 wepexcluded; /* dot11WEPExcludedCount */ - - uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ - - /* WPA2 counters (see rxundec for DecryptFailureCount) */ - uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ - uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ - uint32 tkipreplay_mcst; /* TKIPReplays */ - uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ - uint32 ccmpreplay_mcst; /* CCMPReplays */ - uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ - uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ - uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ - uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ - uint32 decsuccess_mcst; /* DecryptSuccessCount */ - uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ - uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ - - uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ - uint32 txexptime; /* Tx frames suppressed due to timer expiration */ - uint32 psmwds; /* Count PSM watchdogs */ - uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ - - /* MBSS counters, AP only */ - uint32 prq_entries_handled; /* PRQ entries read in */ - uint32 prq_undirected_entries; /* which were bcast bss & ssid */ - uint32 prq_bad_entries; /* which could not be translated to info */ - uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ - uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ - uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ - uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ - - /* per-rate receive stat counters */ - uint32 rx1mbps; /* packets rx at 1Mbps */ - uint32 rx2mbps; /* packets rx at 2Mbps */ - uint32 rx5mbps5; /* packets rx at 5.5Mbps */ - uint32 rx6mbps; /* packets rx at 6Mbps */ - uint32 rx9mbps; /* packets rx at 9Mbps */ - uint32 rx11mbps; /* packets rx at 11Mbps */ - uint32 rx12mbps; /* packets rx at 12Mbps */ - uint32 rx18mbps; /* packets rx at 18Mbps */ - uint32 rx24mbps; /* packets rx at 24Mbps */ - uint32 rx36mbps; /* packets rx at 36Mbps */ - uint32 rx48mbps; /* packets rx at 48Mbps */ - uint32 rx54mbps; /* packets rx at 54Mbps */ - uint32 rx108mbps; /* packets rx at 108mbps */ - uint32 rx162mbps; /* packets rx at 162mbps */ - uint32 rx216mbps; /* packets rx at 216 mbps */ - uint32 rx270mbps; /* packets rx at 270 mbps */ - uint32 rx324mbps; /* packets rx at 324 mbps */ - uint32 rx378mbps; /* packets rx at 378 mbps */ - uint32 rx432mbps; /* packets rx at 432 mbps */ - uint32 rx486mbps; /* packets rx at 486 mbps */ - uint32 rx540mbps; /* packets rx at 540 mbps */ - - /* pkteng rx frame stats */ - uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ - uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ - - uint32 rfdisable; /* count of radio disables */ - uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ - uint32 bphy_badplcp; - - uint32 txmpdu_sgi; /* count for sgi transmit */ - uint32 rxmpdu_sgi; /* count for sgi received */ - uint32 txmpdu_stbc; /* count for stbc transmit */ - uint32 rxmpdu_stbc; /* count for stbc received */ - - uint32 rxdrop20s; /* drop secondary cnt */ - -} wl_cnt_ver_six_t; - -#define WL_DELTA_STATS_T_VERSION 2 /* current version of wl_delta_stats_t struct */ - -typedef struct { - uint16 version; /* see definition of WL_DELTA_STATS_T_VERSION */ - uint16 length; /* length of entire structure */ - - /* transmit stat counters */ - uint32 txframe; /* tx data frames */ - uint32 txbyte; /* tx data bytes */ - uint32 txretrans; /* tx mac retransmits */ - uint32 txfail; /* tx failures */ - - /* receive stat counters */ - uint32 rxframe; /* rx data frames */ - uint32 rxbyte; /* rx data bytes */ - - /* per-rate receive stat counters */ - uint32 rx1mbps; /* packets rx at 1Mbps */ - uint32 rx2mbps; /* packets rx at 2Mbps */ - uint32 rx5mbps5; /* packets rx at 5.5Mbps */ - uint32 rx6mbps; /* packets rx at 6Mbps */ - uint32 rx9mbps; /* packets rx at 9Mbps */ - uint32 rx11mbps; /* packets rx at 11Mbps */ - uint32 rx12mbps; /* packets rx at 12Mbps */ - uint32 rx18mbps; /* packets rx at 18Mbps */ - uint32 rx24mbps; /* packets rx at 24Mbps */ - uint32 rx36mbps; /* packets rx at 36Mbps */ - uint32 rx48mbps; /* packets rx at 48Mbps */ - uint32 rx54mbps; /* packets rx at 54Mbps */ - uint32 rx108mbps; /* packets rx at 108mbps */ - uint32 rx162mbps; /* packets rx at 162mbps */ - uint32 rx216mbps; /* packets rx at 216 mbps */ - uint32 rx270mbps; /* packets rx at 270 mbps */ - uint32 rx324mbps; /* packets rx at 324 mbps */ - uint32 rx378mbps; /* packets rx at 378 mbps */ - uint32 rx432mbps; /* packets rx at 432 mbps */ - uint32 rx486mbps; /* packets rx at 486 mbps */ - uint32 rx540mbps; /* packets rx at 540 mbps */ - - /* phy stats */ - uint32 rxbadplcp; - uint32 rxcrsglitch; - uint32 bphy_rxcrsglitch; - uint32 bphy_badplcp; - -} wl_delta_stats_t; - - -typedef struct { - uint32 packets; - uint32 bytes; -} wl_traffic_stats_t; - -typedef struct { - uint16 version; /* see definition of WL_WME_CNT_VERSION */ - uint16 length; /* length of entire structure */ - - wl_traffic_stats_t tx[AC_COUNT]; /* Packets transmitted */ - wl_traffic_stats_t tx_failed[AC_COUNT]; /* Packets dropped or failed to transmit */ - wl_traffic_stats_t rx[AC_COUNT]; /* Packets received */ - wl_traffic_stats_t rx_failed[AC_COUNT]; /* Packets failed to receive */ - - wl_traffic_stats_t forward[AC_COUNT]; /* Packets forwarded by AP */ - - wl_traffic_stats_t tx_expired[AC_COUNT]; /* packets dropped due to lifetime expiry */ - -} wl_wme_cnt_t; - -struct wl_msglevel2 { - uint32 low; - uint32 high; -}; - -typedef struct wl_mkeep_alive_pkt { - uint16 version; /* Version for mkeep_alive */ - uint16 length; /* length of fixed parameters in the structure */ - uint32 period_msec; - uint16 len_bytes; - uint8 keep_alive_id; /* 0 - 3 for N = 4 */ - uint8 data[1]; -} wl_mkeep_alive_pkt_t; - -#define WL_MKEEP_ALIVE_VERSION 1 -#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) -#define WL_MKEEP_ALIVE_PRECISION 500 - -/* TCP Keep-Alive conn struct */ -typedef struct wl_mtcpkeep_alive_conn_pkt { - struct ether_addr saddr; /* src mac address */ - struct ether_addr daddr; /* dst mac address */ - struct ipv4_addr sipaddr; /* source IP addr */ - struct ipv4_addr dipaddr; /* dest IP addr */ - uint16 sport; /* src port */ - uint16 dport; /* dest port */ - uint32 seq; /* seq number */ - uint32 ack; /* ACK number */ - uint16 tcpwin; /* TCP window */ -} wl_mtcpkeep_alive_conn_pkt_t; - -/* TCP Keep-Alive interval struct */ -typedef struct wl_mtcpkeep_alive_timers_pkt { - uint16 interval; /* interval timer */ - uint16 retry_interval; /* retry_interval timer */ - uint16 retry_count; /* retry_count */ -} wl_mtcpkeep_alive_timers_pkt_t; - -typedef struct wake_info { - uint32 wake_reason; - uint32 wake_info_len; /* size of packet */ - uchar packet[1]; -} wake_info_t; - -typedef struct wake_pkt { - uint32 wake_pkt_len; /* size of packet */ - uchar packet[1]; -} wake_pkt_t; - - -#define WL_MTCPKEEP_ALIVE_VERSION 1 - -#ifdef WLBA - -#define WLC_BA_CNT_VERSION 1 /* current version of wlc_ba_cnt_t */ - -/* block ack related stats */ -typedef struct wlc_ba_cnt { - uint16 version; /* WLC_BA_CNT_VERSION */ - uint16 length; /* length of entire structure */ - - /* transmit stat counters */ - uint32 txpdu; /* pdus sent */ - uint32 txsdu; /* sdus sent */ - uint32 txfc; /* tx side flow controlled packets */ - uint32 txfci; /* tx side flow control initiated */ - uint32 txretrans; /* retransmitted pdus */ - uint32 txbatimer; /* ba resend due to timer */ - uint32 txdrop; /* dropped packets */ - uint32 txaddbareq; /* addba req sent */ - uint32 txaddbaresp; /* addba resp sent */ - uint32 txdelba; /* delba sent */ - uint32 txba; /* ba sent */ - uint32 txbar; /* bar sent */ - uint32 txpad[4]; /* future */ - - /* receive side counters */ - uint32 rxpdu; /* pdus recd */ - uint32 rxqed; /* pdus buffered before sending up */ - uint32 rxdup; /* duplicate pdus */ - uint32 rxnobuf; /* pdus discarded due to no buf */ - uint32 rxaddbareq; /* addba req recd */ - uint32 rxaddbaresp; /* addba resp recd */ - uint32 rxdelba; /* delba recd */ - uint32 rxba; /* ba recd */ - uint32 rxbar; /* bar recd */ - uint32 rxinvba; /* invalid ba recd */ - uint32 rxbaholes; /* ba recd with holes */ - uint32 rxunexp; /* unexpected packets */ - uint32 rxpad[4]; /* future */ -} wlc_ba_cnt_t; -#endif /* WLBA */ - -/* structure for per-tid ampdu control */ -struct ampdu_tid_control { - uint8 tid; /* tid */ - uint8 enable; /* enable/disable */ -}; - -/* struct for ampdu tx/rx aggregation control */ -struct ampdu_aggr { - int8 aggr_override; /* aggr overrided by dongle. Not to be set by host. */ - uint16 conf_TID_bmap; /* bitmap of TIDs to configure */ - uint16 enab_TID_bmap; /* enable/disable per TID */ -}; - -/* structure for identifying ea/tid for sending addba/delba */ -struct ampdu_ea_tid { - struct ether_addr ea; /* Station address */ - uint8 tid; /* tid */ - uint8 initiator; /* 0 is recipient, 1 is originator */ -}; -/* structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */ -struct ampdu_retry_tid { - uint8 tid; /* tid */ - uint8 retry; /* retry value */ -}; - -#define BDD_FNAME_LEN 32 /* Max length of friendly name */ -typedef struct bdd_fname { - uint8 len; /* length of friendly name */ - uchar name[BDD_FNAME_LEN]; /* friendly name */ -} bdd_fname_t; - -/* structure for addts arguments */ -/* For ioctls that take a list of TSPEC */ -struct tslist { - int count; /* number of tspecs */ - struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */ -}; - -#ifdef WLTDLS -/* structure for tdls iovars */ -typedef struct tdls_iovar { - struct ether_addr ea; /* Station address */ - uint8 mode; /* mode: depends on iovar */ - chanspec_t chanspec; - uint32 pad; /* future */ -} tdls_iovar_t; - -#define TDLS_WFD_IE_SIZE 512 -/* structure for tdls wfd ie */ -typedef struct tdls_wfd_ie_iovar { - struct ether_addr ea; /* Station address */ - uint8 mode; - uint16 length; - uint8 data[TDLS_WFD_IE_SIZE]; -} tdls_wfd_ie_iovar_t; -#endif /* WLTDLS */ - -/* structure for addts/delts arguments */ -typedef struct tspec_arg { - uint16 version; /* see definition of TSPEC_ARG_VERSION */ - uint16 length; /* length of entire structure */ - uint flag; /* bit field */ - /* TSPEC Arguments */ - struct tsinfo_arg tsinfo; /* TS Info bit field */ - uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ - uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ - uint min_srv_interval; /* Minimum Service Interval (us) */ - uint max_srv_interval; /* Maximum Service Interval (us) */ - uint inactivity_interval; /* Inactivity Interval (us) */ - uint suspension_interval; /* Suspension Interval (us) */ - uint srv_start_time; /* Service Start Time (us) */ - uint min_data_rate; /* Minimum Data Rate (bps) */ - uint mean_data_rate; /* Mean Data Rate (bps) */ - uint peak_data_rate; /* Peak Data Rate (bps) */ - uint max_burst_size; /* Maximum Burst Size (bytes) */ - uint delay_bound; /* Delay Bound (us) */ - uint min_phy_rate; /* Minimum PHY Rate (bps) */ - uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */ - uint16 medium_time; /* Medium Time (32 us/s periods) */ - uint8 dialog_token; /* dialog token */ -} tspec_arg_t; - -/* tspec arg for desired station */ -typedef struct tspec_per_sta_arg { - struct ether_addr ea; - struct tspec_arg ts; -} tspec_per_sta_arg_t; - -/* structure for max bandwidth for each access category */ -typedef struct wme_max_bandwidth { - uint32 ac[AC_COUNT]; /* max bandwidth for each access category */ -} wme_max_bandwidth_t; - -#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) - -/* current version of wl_tspec_arg_t struct */ -#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */ -#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */ -#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */ -#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */ - - -#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80 -#define WLC_WOWL_MAX_KEEPALIVE 2 - -/* Packet lifetime configuration per ac */ -typedef struct wl_lifetime { - uint32 ac; /* access class */ - uint32 lifetime; /* Packet lifetime value in ms */ -} wl_lifetime_t; - -/* Channel Switch Announcement param */ -typedef struct wl_chan_switch { - uint8 mode; /* value 0 or 1 */ - uint8 count; /* count # of beacons before switching */ - chanspec_t chspec; /* chanspec */ - uint8 reg; /* regulatory class */ - uint8 frame_type; /* csa frame type, unicast or broadcast */ -} wl_chan_switch_t; - -enum { - PFN_LIST_ORDER, - PFN_RSSI -}; - -enum { - DISABLE, - ENABLE -}; - -enum { - OFF_ADAPT, - SMART_ADAPT, - STRICT_ADAPT, - SLOW_ADAPT -}; - -#define SORT_CRITERIA_BIT 0 -#define AUTO_NET_SWITCH_BIT 1 -#define ENABLE_BKGRD_SCAN_BIT 2 -#define IMMEDIATE_SCAN_BIT 3 -#define AUTO_CONNECT_BIT 4 -#define ENABLE_BD_SCAN_BIT 5 -#define ENABLE_ADAPTSCAN_BIT 6 -#define IMMEDIATE_EVENT_BIT 8 -#define SUPPRESS_SSID_BIT 9 -#define ENABLE_NET_OFFLOAD_BIT 10 -/* report found/lost events for SSID and BSSID networks seperately */ -#define REPORT_SEPERATELY_BIT 11 - -#define SORT_CRITERIA_MASK 0x0001 -#define AUTO_NET_SWITCH_MASK 0x0002 -#define ENABLE_BKGRD_SCAN_MASK 0x0004 -#define IMMEDIATE_SCAN_MASK 0x0008 -#define AUTO_CONNECT_MASK 0x0010 - -#define ENABLE_BD_SCAN_MASK 0x0020 -#define ENABLE_ADAPTSCAN_MASK 0x00c0 -#define IMMEDIATE_EVENT_MASK 0x0100 -#define SUPPRESS_SSID_MASK 0x0200 -#define ENABLE_NET_OFFLOAD_MASK 0x0400 -/* report found/lost events for SSID and BSSID networks seperately */ -#define REPORT_SEPERATELY_MASK 0x0800 - -#define PFN_VERSION 2 -#define PFN_SCANRESULT_VERSION 1 -#define MAX_PFN_LIST_COUNT 16 - -#define PFN_COMPLETE 1 -#define PFN_INCOMPLETE 0 - -#define DEFAULT_BESTN 2 -#define DEFAULT_MSCAN 0 -#define DEFAULT_REPEAT 10 -#define DEFAULT_EXP 2 - -#define PFN_PARTIAL_SCAN_BIT 0 -#define PFN_PARTIAL_SCAN_MASK 1 - -#define PFN_SWC_RSSI_WINDOW_MAX 8 -#define PFN_SWC_MAX_NUM_APS 16 -#define PFN_HOTLIST_MAX_NUM_APS 64 - -#define MAX_EPNO_HIDDEN_SSID 8 -#define MAX_WHITELIST_SSID 2 - -/* PFN network info structure */ -typedef struct wl_pfn_subnet_info { - struct ether_addr BSSID; - uint8 channel; /* channel number only */ - uint8 SSID_len; - uint8 SSID[32]; -} wl_pfn_subnet_info_t; - -typedef struct wl_pfn_net_info { - wl_pfn_subnet_info_t pfnsubnet; - int16 RSSI; /* receive signal strength (in dBm) */ - uint16 timestamp; /* age in seconds */ -} wl_pfn_net_info_t; - -typedef struct wl_pfn_lnet_info { - wl_pfn_subnet_info_t pfnsubnet; /* BSSID + channel + SSID len + SSID */ - uint16 flags; /* partial scan, etc */ - int16 RSSI; /* receive signal strength (in dBm) */ - uint32 timestamp; /* age in miliseconds */ - uint16 rtt0; /* estimated distance to this AP in centimeters */ - uint16 rtt1; /* standard deviation of the distance to this AP in centimeters */ -} wl_pfn_lnet_info_t; - -typedef struct wl_pfn_lscanresults { - uint32 version; - uint32 status; - uint32 count; - wl_pfn_lnet_info_t netinfo[1]; -} wl_pfn_lscanresults_t; - -/* this is used to report on 1-* pfn scan results */ -typedef struct wl_pfn_scanresults { - uint32 version; - uint32 status; - uint32 count; - wl_pfn_net_info_t netinfo[1]; -} wl_pfn_scanresults_t; - -typedef struct wl_pfn_significant_net { - uint16 flags; - uint16 channel; - struct ether_addr BSSID; - int8 rssi[PFN_SWC_RSSI_WINDOW_MAX]; -} wl_pfn_significant_net_t; - -typedef struct wl_pfn_swc_results { - uint32 version; - uint32 pkt_count; - uint32 total_count; - wl_pfn_significant_net_t list[1]; -} wl_pfn_swc_results_t; - -/* used to report exactly one scan result */ -/* plus reports detailed scan info in bss_info */ -typedef struct wl_pfn_scanresult { - uint32 version; - uint32 status; - uint32 count; - wl_pfn_net_info_t netinfo; - wl_bss_info_t bss_info; -} wl_pfn_scanresult_t; - -/* PFN data structure */ -typedef struct wl_pfn_param { - int32 version; /* PNO parameters version */ - int32 scan_freq; /* Scan frequency */ - int32 lost_network_timeout; /* Timeout in sec. to declare - * discovered network as lost - */ - int16 flags; /* Bit field to control features - * of PFN such as sort criteria auto - * enable switch and background scan - */ - int16 rssi_margin; /* Margin to avoid jitter for choosing a - * PFN based on RSSI sort criteria - */ - uint8 bestn; /* number of best networks in each scan */ - uint8 mscan; /* number of scans recorded */ - uint8 repeat; /* Minimum number of scan intervals - *before scan frequency changes in adaptive scan - */ - uint8 exp; /* Exponent of 2 for maximum scan interval */ - int32 slow_freq; /* slow scan period */ -} wl_pfn_param_t; - -typedef struct wl_pfn_bssid { - struct ether_addr macaddr; - /* Bit4: suppress_lost, Bit3: suppress_found */ - uint16 flags; -} wl_pfn_bssid_t; - -#define WL_PFN_SUPPRESSFOUND_MASK 0x08 -#define WL_PFN_SUPPRESSLOST_MASK 0x10 -#define WL_PFN_RSSI_MASK 0xff00 -#define WL_PFN_RSSI_SHIFT 8 - -typedef struct wl_pfn_cfg { - uint32 reporttype; - int32 channel_num; - uint16 channel_list[WL_NUMCHANNELS]; - uint32 flags; -} wl_pfn_cfg_t; - -#define CH_BUCKET_REPORT_REGULAR 0 -#define CH_BUCKET_REPORT_FULL_RESULT 2 -#define CH_BUCKET_GSCAN 4 - -typedef struct wl_pfn_gscan_ch_bucket_cfg { - uint8 bucket_end_index; - uint8 bucket_freq_multiple; - uint8 flag; - uint8 reserved; - uint16 repeat; - uint16 max_freq_multiple; -} wl_pfn_gscan_ch_bucket_cfg_t; - -#define GSCAN_SEND_ALL_RESULTS_MASK (1 << 0) -#define GSCAN_CFG_FLAGS_ONLY_MASK (1 << 7) -#define WL_GSCAN_CFG_VERSION 2 -typedef struct wl_pfn_gscan_cfg { - uint16 version; - /* BIT0 1 = send probes/beacons to HOST - * BIT1 Reserved - * BIT2 Reserved - * Add any future flags here - * BIT7 1 = no other useful cfg sent - */ - uint8 flags; - /* Buffer filled threshold in % to generate an event */ - uint8 buffer_threshold; - /* No. of BSSIDs with "change" to generate an evt - * change - crosses rssi threshold/lost - */ - uint8 swc_nbssid_threshold; - /* Max=8 (for now) Size of rssi cache buffer */ - uint8 swc_rssi_window_size; - uint8 count_of_channel_buckets; - uint8 retry_threshold; - uint16 lost_ap_window; - wl_pfn_gscan_ch_bucket_cfg_t channel_bucket[1]; -} wl_pfn_gscan_cfg_t; - -#define WL_PFN_REPORT_ALLNET 0 -#define WL_PFN_REPORT_SSIDNET 1 -#define WL_PFN_REPORT_BSSIDNET 2 - -#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ -#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /* Remaining reserved for future use */ -#define WL_PFN_SSID_A_BAND_TRIG 0x20 -#define WL_PFN_SSID_BG_BAND_TRIG 0x40 -typedef struct wl_pfn { - wlc_ssid_t ssid; /* ssid name and its length */ - int32 flags; /* bit2: hidden */ - int32 infra; /* BSS Vs IBSS */ - int32 auth; /* Open Vs Closed */ - int32 wpa_auth; /* WPA type */ - int32 wsec; /* wsec value */ -} wl_pfn_t; - -typedef struct wl_pfn_list { - uint32 version; - uint32 enabled; - uint32 count; - wl_pfn_t pfn[1]; -} wl_pfn_list_t; - -#define PFN_SSID_EXT_VERSION 2 - -typedef struct wl_pfn_ext { - uint8 flags; - int8 rssi_thresh; /* RSSI threshold, track only if RSSI > threshold */ - uint16 wpa_auth; /* Match the wpa auth type defined in wlioctl_defs.h */ - uint8 ssid[DOT11_MAX_SSID_LEN]; - uint8 ssid_len; - uint8 pad; -} wl_pfn_ext_t; - -typedef struct wl_pfn_ext_list { - uint16 version; - uint16 count; - wl_pfn_ext_t pfn_ext[1]; -} wl_pfn_ext_list_t; - -#define WL_PFN_SSID_EXT_FOUND 0x1 -#define WL_PFN_SSID_EXT_LOST 0x2 -typedef struct wl_pfn_result_ssid { - uint8 flags; - int8 rssi; - /* channel number */ - uint16 channel; - /* Assume idx in order of cfg */ - uint16 index; - struct ether_addr bssid; -} wl_pfn_result_ssid_crc32_t; - -typedef struct wl_pfn_ssid_ext_result { - uint16 version; - uint16 count; - wl_pfn_result_ssid_crc32_t net[1]; -} wl_pfn_ssid_ext_result_t; - -#define PFN_EXT_AUTH_CODE_OPEN 1 /* open */ -#define PFN_EXT_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ -#define PFN_EXT_AUTH_CODE_EAPOL 4 /* any EAPOL */ - -#define WL_PFN_MAC_OUI_ONLY_MASK 1 -#define WL_PFN_SET_MAC_UNASSOC_MASK 2 -/* To configure pfn_macaddr */ -typedef struct wl_pfn_macaddr_cfg { - uint8 version; - uint8 flags; - struct ether_addr macaddr; -} wl_pfn_macaddr_cfg_t; -#define WL_PFN_MACADDR_CFG_VER 1 - -typedef BWL_PRE_PACKED_STRUCT struct pfn_olmsg_params_t { - wlc_ssid_t ssid; - uint32 cipher_type; - uint32 auth_type; - uint8 channels[4]; -} BWL_POST_PACKED_STRUCT pfn_olmsg_params; - -#define WL_PFN_HIDDEN_BIT 2 -#define WL_PFN_HIDDEN_MASK 0x4 - -#ifndef BESTN_MAX -#define BESTN_MAX 3 -#endif - -#ifndef MSCAN_MAX -#define MSCAN_MAX 90 -#endif - - -/* Service discovery */ -typedef struct { - uint8 transaction_id; /* Transaction id */ - uint8 protocol; /* Service protocol type */ - uint16 query_len; /* Length of query */ - uint16 response_len; /* Length of response */ - uint8 qrbuf[1]; -} wl_p2po_qr_t; - -typedef struct { - uint16 period; /* extended listen period */ - uint16 interval; /* extended listen interval */ -} wl_p2po_listen_t; - -/* GAS state machine tunable parameters. Structure field values of 0 means use the default. */ -typedef struct wl_gas_config { - uint16 max_retransmit; /* Max # of firmware/driver retransmits on no Ack - * from peer (on top of the ucode retries). - */ - uint16 response_timeout; /* Max time to wait for a GAS-level response - * after sending a packet. - */ - uint16 max_comeback_delay; /* Max GAS response comeback delay. - * Exceeding this fails the GAS exchange. - */ - uint16 max_retries; /* Max # of GAS state machine retries on failure - * of a GAS frame exchange. - */ -} wl_gas_config_t; - -/* P2P Find Offload parameters */ -typedef BWL_PRE_PACKED_STRUCT struct wl_p2po_find_config { - uint16 version; /* Version of this struct */ - uint16 length; /* sizeof(wl_p2po_find_config_t) */ - int32 search_home_time; /* P2P search state home time when concurrent - * connection exists. -1 for default. - */ - uint8 num_social_channels; - /* Number of social channels up to WL_P2P_SOCIAL_CHANNELS_MAX. - * 0 means use default social channels. - */ - uint8 flags; - uint16 social_channels[1]; /* Variable length array of social channels */ -} BWL_POST_PACKED_STRUCT wl_p2po_find_config_t; -#define WL_P2PO_FIND_CONFIG_VERSION 2 /* value for version field */ - -/* wl_p2po_find_config_t flags */ -#define P2PO_FIND_FLAG_SCAN_ALL_APS 0x01 /* Whether to scan for all APs in the p2po_find - * periodic scans of all channels. - * 0 means scan for only P2P devices. - * 1 means scan for P2P devices plus non-P2P APs. - */ - - -/* For adding a WFDS service to seek */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 seek_hdl; /* unique id chosen by host */ - uint8 addr[6]; /* Seek service from a specific device with this - * MAC address, all 1's for any device. - */ - uint8 service_hash[P2P_WFDS_HASH_LEN]; - uint8 service_name_len; - uint8 service_name[MAX_WFDS_SEEK_SVC_NAME_LEN]; - /* Service name to seek, not null terminated */ - uint8 service_info_req_len; - uint8 service_info_req[1]; /* Service info request, not null terminated. - * Variable length specified by service_info_req_len. - * Maximum length is MAX_WFDS_SEEK_SVC_INFO_LEN. - */ -} BWL_POST_PACKED_STRUCT wl_p2po_wfds_seek_add_t; - -/* For deleting a WFDS service to seek */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 seek_hdl; /* delete service specified by id */ -} BWL_POST_PACKED_STRUCT wl_p2po_wfds_seek_del_t; - - -/* For adding a WFDS service to advertise */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 advertise_hdl; /* unique id chosen by host */ - uint8 service_hash[P2P_WFDS_HASH_LEN]; - uint32 advertisement_id; - uint16 service_config_method; - uint8 service_name_len; - uint8 service_name[MAX_WFDS_SVC_NAME_LEN]; - /* Service name , not null terminated */ - uint8 service_status; - uint16 service_info_len; - uint8 service_info[1]; /* Service info, not null terminated. - * Variable length specified by service_info_len. - * Maximum length is MAX_WFDS_ADV_SVC_INFO_LEN. - */ -} BWL_POST_PACKED_STRUCT wl_p2po_wfds_advertise_add_t; - -/* For deleting a WFDS service to advertise */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 advertise_hdl; /* delete service specified by hdl */ -} BWL_POST_PACKED_STRUCT wl_p2po_wfds_advertise_del_t; - -/* P2P Offload discovery mode for the p2po_state iovar */ -typedef enum { - WL_P2PO_DISC_STOP, - WL_P2PO_DISC_LISTEN, - WL_P2PO_DISC_DISCOVERY -} disc_mode_t; - -/* ANQP offload */ - -#define ANQPO_MAX_QUERY_SIZE 256 -typedef struct { - uint16 max_retransmit; /* ~0 use default, max retransmit on no ACK from peer */ - uint16 response_timeout; /* ~0 use default, msec to wait for resp after tx packet */ - uint16 max_comeback_delay; /* ~0 use default, max comeback delay in resp else fail */ - uint16 max_retries; /* ~0 use default, max retries on failure */ - uint16 query_len; /* length of ANQP query */ - uint8 query_data[1]; /* ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */ -} wl_anqpo_set_t; - -typedef struct { - uint16 channel; /* channel of the peer */ - struct ether_addr addr; /* addr of the peer */ -} wl_anqpo_peer_t; - -#define ANQPO_MAX_PEER_LIST 64 -typedef struct { - uint16 count; /* number of peers in list */ - wl_anqpo_peer_t peer[1]; /* max ANQPO_MAX_PEER_LIST */ -} wl_anqpo_peer_list_t; - -#define ANQPO_MAX_IGNORE_SSID 64 -typedef struct { - bool is_clear; /* set to clear list (not used on GET) */ - uint16 count; /* number of SSID in list */ - wlc_ssid_t ssid[1]; /* max ANQPO_MAX_IGNORE_SSID */ -} wl_anqpo_ignore_ssid_list_t; - -#define ANQPO_MAX_IGNORE_BSSID 64 -typedef struct { - bool is_clear; /* set to clear list (not used on GET) */ - uint16 count; /* number of addr in list */ - struct ether_addr bssid[1]; /* max ANQPO_MAX_IGNORE_BSSID */ -} wl_anqpo_ignore_bssid_list_t; - - -struct toe_ol_stats_t { - /* Num of tx packets that don't need to be checksummed */ - uint32 tx_summed; - - /* Num of tx packets where checksum is filled by offload engine */ - uint32 tx_iph_fill; - uint32 tx_tcp_fill; - uint32 tx_udp_fill; - uint32 tx_icmp_fill; - - /* Num of rx packets where toe finds out if checksum is good or bad */ - uint32 rx_iph_good; - uint32 rx_iph_bad; - uint32 rx_tcp_good; - uint32 rx_tcp_bad; - uint32 rx_udp_good; - uint32 rx_udp_bad; - uint32 rx_icmp_good; - uint32 rx_icmp_bad; - - /* Num of tx packets in which csum error is injected */ - uint32 tx_tcp_errinj; - uint32 tx_udp_errinj; - uint32 tx_icmp_errinj; - - /* Num of rx packets in which csum error is injected */ - uint32 rx_tcp_errinj; - uint32 rx_udp_errinj; - uint32 rx_icmp_errinj; -}; - -/* Arp offload statistic counts */ -struct arp_ol_stats_t { - uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ - uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ - - uint32 arp_table_entries; /* ARP table entries */ - uint32 arp_table_overflow; /* ARP table additions skipped due to overflow */ - - uint32 host_request; /* ARP requests from host */ - uint32 host_reply; /* ARP replies from host */ - uint32 host_service; /* ARP requests from host serviced by ARP Agent */ - - uint32 peer_request; /* ARP requests received from network */ - uint32 peer_request_drop; /* ARP requests from network that were dropped */ - uint32 peer_reply; /* ARP replies received from network */ - uint32 peer_reply_drop; /* ARP replies from network that were dropped */ - uint32 peer_service; /* ARP request from host serviced by ARP Agent */ -}; - -/* NS offload statistic counts */ -struct nd_ol_stats_t { - uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ - uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ - uint32 peer_request; /* NS requests received from network */ - uint32 peer_request_drop; /* NS requests from network that were dropped */ - uint32 peer_reply_drop; /* NA replies from network that were dropped */ - uint32 peer_service; /* NS request from host serviced by firmware */ -}; - -/* - * Keep-alive packet offloading. - */ - -/* NAT keep-alive packets format: specifies the re-transmission period, the packet - * length, and packet contents. - */ -typedef struct wl_keep_alive_pkt { - uint32 period_msec; /* Retransmission period (0 to disable packet re-transmits) */ - uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */ - uint8 data[1]; /* Variable length packet to transmit. Contents should include - * entire ethernet packet (enet header, IP header, UDP header, - * and UDP payload) in network byte order. - */ -} wl_keep_alive_pkt_t; - -#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) - - -/* - * Dongle pattern matching filter. - */ - -/* Packet filter operation mode */ -/* True: 1; False: 0 */ -#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 -/* Enable and disable pkt_filter as a whole */ -#define PKT_FILTER_MODE_DISABLE 2 -/* Cache first matched rx pkt(be queried by host later) */ -#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 -/* If pkt_filter is enabled and no filter is set, don't forward anything */ -#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 - -#define MAX_WAKE_PACKET_CACHE_BYTES 128 /* Maximum cached wake packet */ - -#define MAX_WAKE_PACKET_BYTES (DOT11_A3_HDR_LEN + \ - DOT11_QOS_LEN + \ - sizeof(struct dot11_llc_snap_header) + \ - ETHER_MAX_DATA) - -typedef struct pm_wake_packet { - uint32 status; /* Is the wake reason a packet (if all the other field's valid) */ - uint32 pattern_id; /* Pattern ID that matched */ - uint32 original_packet_size; - uint32 saved_packet_size; - uchar packet[MAX_WAKE_PACKET_CACHE_BYTES]; -} pm_wake_packet_t; - -/* Packet filter types. Currently, only pattern matching is supported. */ -typedef enum wl_pkt_filter_type { - WL_PKT_FILTER_TYPE_PATTERN_MATCH=0, /* Pattern matching filter */ - WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH=1, /* Magic packet match */ - WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH=2, /* A pattern list (match all to match filter) */ - WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH=3, /* SECURE WOWL magic / net pattern match */ -} wl_pkt_filter_type_t; - -#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t - -/* String mapping for types that may be used by applications or debug */ -#define WL_PKT_FILTER_TYPE_NAMES \ - { "PATTERN", WL_PKT_FILTER_TYPE_PATTERN_MATCH }, \ - { "MAGIC", WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH }, \ - { "PATLIST", WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH } - -/* Secured WOWL packet was encrypted, need decrypted before check filter match */ -typedef struct wl_pkt_decrypter { - uint8* (*dec_cb)(void* dec_ctx, const void *sdu, int sending); - void* dec_ctx; -} wl_pkt_decrypter_t; - -/* 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. - */ -typedef struct wl_pkt_filter_pattern { - union { - uint32 offset; /* Offset within received packet to start pattern matching. - * Offset '0' is the first byte of the ethernet header. - */ - wl_pkt_decrypter_t* decrypt_ctx; /* Decrypt context */ - }; - uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ - uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts - * at offset 0. Pattern immediately follows mask. - */ -} wl_pkt_filter_pattern_t; - -/* A pattern list is a numerically specified list of modified pattern structures. */ -typedef struct wl_pkt_filter_pattern_listel { - uint16 rel_offs; /* Offset to begin match (relative to 'base' below) */ - uint16 base_offs; /* Base for offset (defined below) */ - uint16 size_bytes; /* Size of mask/pattern */ - uint16 match_flags; /* Addition flags controlling the match */ - uint8 mask_and_data[1]; /* Variable length mask followed by data, each size_bytes */ -} wl_pkt_filter_pattern_listel_t; - -typedef struct wl_pkt_filter_pattern_list { - uint8 list_cnt; /* Number of elements in the list */ - uint8 PAD1[1]; /* Reserved (possible version: reserved) */ - uint16 totsize; /* Total size of this pattern list (includes this struct) */ - wl_pkt_filter_pattern_listel_t patterns[1]; /* Variable number of list elements */ -} wl_pkt_filter_pattern_list_t; - -/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ -typedef struct wl_pkt_filter { - uint32 id; /* Unique filter id, specified by app. */ - uint32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ - uint32 negate_match; /* Negate the result of filter matches */ - union { /* Filter definitions */ - wl_pkt_filter_pattern_t pattern; /* Pattern matching filter */ - wl_pkt_filter_pattern_list_t patlist; /* List of patterns to match */ - } u; -} wl_pkt_filter_t; - -/* IOVAR "tcp_keep_set" parameter. Used to install tcp keep_alive stuff. */ -typedef struct wl_tcp_keep_set { - uint32 val1; - uint32 val2; -} wl_tcp_keep_set_t; - -#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) -#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) -#define WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_list_t, patterns) -#define WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN \ - OFFSETOF(wl_pkt_filter_pattern_listel_t, mask_and_data) - -/* IOVAR "pkt_filter_enable" parameter. */ -typedef struct wl_pkt_filter_enable { - uint32 id; /* Unique filter id */ - uint32 enable; /* Enable/disable bool */ -} wl_pkt_filter_enable_t; - -/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ -typedef struct wl_pkt_filter_list { - uint32 num; /* Number of installed packet filters */ - wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */ -} wl_pkt_filter_list_t; - -#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) - -/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ -typedef struct wl_pkt_filter_stats { - uint32 num_pkts_matched; /* # filter matches for specified filter id */ - uint32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */ - uint32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ -} wl_pkt_filter_stats_t; - -/* IOVAR "pkt_filter_ports" parameter. Configure TCP/UDP port filters. */ -typedef struct wl_pkt_filter_ports { - uint8 version; /* Be proper */ - uint8 reserved; /* Be really proper */ - uint16 count; /* Number of ports following */ - /* End of fixed data */ - uint16 ports[1]; /* Placeholder for ports[] */ -} wl_pkt_filter_ports_t; - -#define WL_PKT_FILTER_PORTS_FIXED_LEN OFFSETOF(wl_pkt_filter_ports_t, ports) - -#define WL_PKT_FILTER_PORTS_VERSION 0 -#define WL_PKT_FILTER_PORTS_MAX 128 - -#define RSN_KCK_LENGTH 16 -#define RSN_KEK_LENGTH 16 -#define RSN_REPLAY_LEN 8 -typedef struct _gtkrefresh { - uchar KCK[RSN_KCK_LENGTH]; - uchar KEK[RSN_KEK_LENGTH]; - uchar ReplayCounter[RSN_REPLAY_LEN]; -} gtk_keyinfo_t, *pgtk_keyinfo_t; - -/* Sequential Commands ioctl */ -typedef struct wl_seq_cmd_ioctl { - uint32 cmd; /* common ioctl definition */ - uint32 len; /* length of user buffer */ -} wl_seq_cmd_ioctl_t; - -#define WL_SEQ_CMD_ALIGN_BYTES 4 - -/* These are the set of get IOCTLs that should be allowed when using - * IOCTL sequence commands. These are issued implicitly by wl.exe each time - * it is invoked. We never want to buffer these, or else wl.exe will stop working. - */ -#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ - (((cmd) == WLC_GET_MAGIC) || \ - ((cmd) == WLC_GET_VERSION) || \ - ((cmd) == WLC_GET_AP) || \ - ((cmd) == WLC_GET_INSTANCE)) - -typedef struct wl_pkteng { - uint32 flags; - uint32 delay; /* Inter-packet delay */ - uint32 nframes; /* Number of frames */ - uint32 length; /* Packet length */ - uint8 seqno; /* Enable/disable sequence no. */ - struct ether_addr dest; /* Destination address */ - struct ether_addr src; /* Source address */ -} wl_pkteng_t; - -typedef struct wl_pkteng_stats { - uint32 lostfrmcnt; /* RX PER test: no of frames lost (skip seqno) */ - int32 rssi; /* RSSI */ - int32 snr; /* signal to noise ratio */ - uint16 rxpktcnt[NUM_80211_RATES+1]; - uint8 rssi_qdb; /* qdB portion of the computed rssi */ -} wl_pkteng_stats_t; - -typedef struct wl_txcal_params { - wl_pkteng_t pkteng; - uint8 gidx_start; - int8 gidx_step; - uint8 gidx_stop; -} wl_txcal_params_t; - - -typedef enum { - wowl_pattern_type_bitmap = 0, - wowl_pattern_type_arp, - wowl_pattern_type_na -} wowl_pattern_type_t; - -typedef struct wl_wowl_pattern { - uint32 masksize; /* Size of the mask in #of bytes */ - uint32 offset; /* Pattern byte offset in packet */ - uint32 patternoffset; /* Offset of start of pattern in the structure */ - uint32 patternsize; /* Size of the pattern itself in #of bytes */ - uint32 id; /* id */ - uint32 reasonsize; /* Size of the wakeup reason code */ - wowl_pattern_type_t type; /* Type of pattern */ - /* Mask follows the structure above */ - /* Pattern follows the mask is at 'patternoffset' from the start */ -} wl_wowl_pattern_t; - -typedef struct wl_wowl_pattern_list { - uint count; - wl_wowl_pattern_t pattern[1]; -} wl_wowl_pattern_list_t; - -typedef struct wl_wowl_wakeind { - uint8 pci_wakeind; /* Whether PCI PMECSR PMEStatus bit was set */ - uint32 ucode_wakeind; /* What wakeup-event indication was set by ucode */ -} wl_wowl_wakeind_t; - -typedef struct { - uint32 pktlen; /* size of packet */ - void *sdu; -} tcp_keepalive_wake_pkt_infop_t; - -/* per AC rate control related data structure */ -typedef struct wl_txrate_class { - uint8 init_rate; - uint8 min_rate; - uint8 max_rate; -} wl_txrate_class_t; - -/* structure for Overlap BSS scan arguments */ -typedef struct wl_obss_scan_arg { - int16 passive_dwell; - int16 active_dwell; - int16 bss_widthscan_interval; - int16 passive_total; - int16 active_total; - int16 chanwidth_transition_delay; - int16 activity_threshold; -} wl_obss_scan_arg_t; - -#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) - -/* RSSI event notification configuration. */ -typedef struct wl_rssi_event { - uint32 rate_limit_msec; /* # of events posted to application will be limited to - * one per specified period (0 to disable rate limit). - */ - uint8 num_rssi_levels; /* Number of entries in rssi_levels[] below */ - int8 rssi_levels[MAX_RSSI_LEVELS]; /* Variable number of RSSI levels. An event - * will be posted each time the RSSI of received - * beacons/packets crosses a level. - */ -} wl_rssi_event_t; - -#define RSSI_MONITOR_VERSION 1 -#define RSSI_MONITOR_STOP (1 << 0) -typedef struct wl_rssi_monitor_cfg { - uint8 version; - uint8 flags; - int8 max_rssi; - int8 min_rssi; -} wl_rssi_monitor_cfg_t; - -typedef struct wl_rssi_monitor_evt { - uint8 version; - int8 cur_rssi; - uint16 pad; -} wl_rssi_monitor_evt_t; - -typedef struct wl_action_obss_coex_req { - uint8 info; - uint8 num; - uint8 ch_list[1]; -} wl_action_obss_coex_req_t; - - -/* IOVar parameter block for small MAC address array with type indicator */ -#define WL_IOV_MAC_PARAM_LEN 4 - -#define WL_IOV_PKTQ_LOG_PRECS 16 - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 num_addrs; - char addr_type[WL_IOV_MAC_PARAM_LEN]; - struct ether_addr ea[WL_IOV_MAC_PARAM_LEN]; -} BWL_POST_PACKED_STRUCT wl_iov_mac_params_t; - -/* This is extra info that follows wl_iov_mac_params_t */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 addr_info[WL_IOV_MAC_PARAM_LEN]; -} BWL_POST_PACKED_STRUCT wl_iov_mac_extra_params_t; - -/* Combined structure */ -typedef struct { - wl_iov_mac_params_t params; - wl_iov_mac_extra_params_t extra_params; -} wl_iov_mac_full_params_t; - -/* Parameter block for PKTQ_LOG statistics */ -#define PKTQ_LOG_COUNTERS_V4 \ - /* packets requested to be stored */ \ - uint32 requested; \ - /* packets stored */ \ - uint32 stored; \ - /* packets saved, because a lowest priority queue has given away one packet */ \ - uint32 saved; \ - /* packets saved, because an older packet from the same queue has been dropped */ \ - uint32 selfsaved; \ - /* packets dropped, because pktq is full with higher precedence packets */ \ - uint32 full_dropped; \ - /* packets dropped because pktq per that precedence is full */ \ - uint32 dropped; \ - /* packets dropped, in order to save one from a queue of a highest priority */ \ - uint32 sacrificed; \ - /* packets droped because of hardware/transmission error */ \ - uint32 busy; \ - /* packets re-sent because they were not received */ \ - uint32 retry; \ - /* packets retried again (ps pretend) prior to moving power save mode */ \ - uint32 ps_retry; \ - /* suppressed packet count */ \ - uint32 suppress; \ - /* packets finally dropped after retry limit */ \ - uint32 retry_drop; \ - /* the high-water mark of the queue capacity for packets - goes to zero as queue fills */ \ - uint32 max_avail; \ - /* the high-water mark of the queue utilisation for packets - ('inverse' of max_avail) */ \ - uint32 max_used; \ - /* the maximum capacity of the queue */ \ - uint32 queue_capacity; \ - /* count of rts attempts that failed to receive cts */ \ - uint32 rtsfail; \ - /* count of packets sent (acked) successfully */ \ - uint32 acked; \ - /* running total of phy rate of packets sent successfully */ \ - uint32 txrate_succ; \ - /* running total of phy 'main' rate */ \ - uint32 txrate_main; \ - /* actual data transferred successfully */ \ - uint32 throughput; \ - /* time difference since last pktq_stats */ \ - uint32 time_delta; - -typedef struct { - PKTQ_LOG_COUNTERS_V4 -} pktq_log_counters_v04_t; - -/* v5 is the same as V4 with extra parameter */ -typedef struct { - PKTQ_LOG_COUNTERS_V4 - /* cumulative time to transmit */ - uint32 airtime; -} pktq_log_counters_v05_t; - -typedef struct { - uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; - pktq_log_counters_v04_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; - uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; - uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; - char headings[1]; -} pktq_log_format_v04_t; - -typedef struct { - uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; - pktq_log_counters_v05_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; - uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; - uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; - char headings[1]; -} pktq_log_format_v05_t; - - -typedef struct { - uint32 version; - wl_iov_mac_params_t params; - union { - pktq_log_format_v04_t v04; - pktq_log_format_v05_t v05; - } pktq_log; -} wl_iov_pktq_log_t; - -/* PKTQ_LOG_AUTO, PKTQ_LOG_DEF_PREC flags introduced in v05, they are ignored by v04 */ -#define PKTQ_LOG_AUTO (1 << 31) -#define PKTQ_LOG_DEF_PREC (1 << 30) - -/* - * SCB_BS_DATA iovar definitions start. - */ -#define SCB_BS_DATA_STRUCT_VERSION 1 - -/* The actual counters maintained for each station */ -typedef BWL_PRE_PACKED_STRUCT struct { - /* The following counters are a subset of what pktq_stats provides per precedence. */ - uint32 retry; /* packets re-sent because they were not received */ - uint32 retry_drop; /* packets finally dropped after retry limit */ - uint32 rtsfail; /* count of rts attempts that failed to receive cts */ - uint32 acked; /* count of packets sent (acked) successfully */ - uint32 txrate_succ; /* running total of phy rate of packets sent successfully */ - uint32 txrate_main; /* running total of phy 'main' rate */ - uint32 throughput; /* actual data transferred successfully */ - uint32 time_delta; /* time difference since last pktq_stats */ - uint32 airtime; /* cumulative total medium access delay in useconds */ -} BWL_POST_PACKED_STRUCT iov_bs_data_counters_t; - -/* The structure for individual station information. */ -typedef BWL_PRE_PACKED_STRUCT struct { - struct ether_addr station_address; /* The station MAC address */ - uint16 station_flags; /* Bit mask of flags, for future use. */ - iov_bs_data_counters_t station_counters; /* The actual counter values */ -} BWL_POST_PACKED_STRUCT iov_bs_data_record_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 structure_version; /* Structure version number (for wl/wlu matching) */ - uint16 structure_count; /* Number of iov_bs_data_record_t records following */ - iov_bs_data_record_t structure_record[1]; /* 0 - structure_count records */ -} BWL_POST_PACKED_STRUCT iov_bs_data_struct_t; - -/* Bitmask of options that can be passed in to the iovar. */ -enum { - SCB_BS_DATA_FLAG_NO_RESET = (1<<0) /* Do not clear the counters after reading */ -}; -/* - * SCB_BS_DATA iovar definitions end. - */ - -typedef struct wlc_extlog_cfg { - int max_number; - uint16 module; /* bitmap */ - uint8 level; - uint8 flag; - uint16 version; -} wlc_extlog_cfg_t; - -typedef struct log_record { - uint32 time; - uint16 module; - uint16 id; - uint8 level; - uint8 sub_unit; - uint8 seq_num; - int32 arg; - char str[MAX_ARGSTR_LEN]; -} log_record_t; - -typedef struct wlc_extlog_req { - uint32 from_last; - uint32 num; -} wlc_extlog_req_t; - -typedef struct wlc_extlog_results { - uint16 version; - uint16 record_len; - uint32 num; - log_record_t logs[1]; -} wlc_extlog_results_t; - -typedef struct log_idstr { - uint16 id; - uint16 flag; - uint8 arg_type; - const char *fmt_str; -} log_idstr_t; - -#define FMTSTRF_USER 1 - -/* flat ID definitions - * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will - * affect backward compatibility with pre-existing apps - */ -typedef enum { - FMTSTR_DRIVER_UP_ID = 0, - FMTSTR_DRIVER_DOWN_ID = 1, - FMTSTR_SUSPEND_MAC_FAIL_ID = 2, - FMTSTR_NO_PROGRESS_ID = 3, - FMTSTR_RFDISABLE_ID = 4, - FMTSTR_REG_PRINT_ID = 5, - FMTSTR_EXPTIME_ID = 6, - FMTSTR_JOIN_START_ID = 7, - FMTSTR_JOIN_COMPLETE_ID = 8, - FMTSTR_NO_NETWORKS_ID = 9, - FMTSTR_SECURITY_MISMATCH_ID = 10, - FMTSTR_RATE_MISMATCH_ID = 11, - FMTSTR_AP_PRUNED_ID = 12, - FMTSTR_KEY_INSERTED_ID = 13, - FMTSTR_DEAUTH_ID = 14, - FMTSTR_DISASSOC_ID = 15, - FMTSTR_LINK_UP_ID = 16, - FMTSTR_LINK_DOWN_ID = 17, - FMTSTR_RADIO_HW_OFF_ID = 18, - FMTSTR_RADIO_HW_ON_ID = 19, - FMTSTR_EVENT_DESC_ID = 20, - FMTSTR_PNP_SET_POWER_ID = 21, - FMTSTR_RADIO_SW_OFF_ID = 22, - FMTSTR_RADIO_SW_ON_ID = 23, - FMTSTR_PWD_MISMATCH_ID = 24, - FMTSTR_FATAL_ERROR_ID = 25, - FMTSTR_AUTH_FAIL_ID = 26, - FMTSTR_ASSOC_FAIL_ID = 27, - FMTSTR_IBSS_FAIL_ID = 28, - FMTSTR_EXTAP_FAIL_ID = 29, - FMTSTR_MAX_ID -} log_fmtstr_id_t; - -#ifdef DONGLEOVERLAYS -typedef struct { - uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */ - uint32 offset; /* offset into overlay region to write code */ - uint32 len; /* overlay code len */ - /* overlay code follows this struct */ -} wl_ioctl_overlay_t; -#endif /* DONGLEOVERLAYS */ - -/* 11k Neighbor Report element */ -typedef struct nbr_element { - uint8 id; - uint8 len; - struct ether_addr bssid; - uint32 bssid_info; - uint8 reg; - uint8 channel; - uint8 phytype; - uint8 pad; -} nbr_element_t; - - -typedef enum event_msgs_ext_command { - EVENTMSGS_NONE = 0, - EVENTMSGS_SET_BIT = 1, - EVENTMSGS_RESET_BIT = 2, - EVENTMSGS_SET_MASK = 3 -} event_msgs_ext_command_t; - -#define EVENTMSGS_VER 1 -#define EVENTMSGS_EXT_STRUCT_SIZE OFFSETOF(eventmsgs_ext_t, mask[0]) - -/* len- for SET it would be mask size from the application to the firmware */ -/* for GET it would be actual firmware mask size */ -/* maxgetsize - is only used for GET. indicate max mask size that the */ -/* application can read from the firmware */ -typedef struct eventmsgs_ext -{ - uint8 ver; - uint8 command; - uint8 len; - uint8 maxgetsize; - uint8 mask[1]; -} eventmsgs_ext_t; - -typedef BWL_PRE_PACKED_STRUCT struct pcie_bus_tput_params { - /* no of host dma descriptors programmed by the firmware before a commit */ - uint16 max_dma_descriptors; - - uint16 host_buf_len; /* length of host buffer */ - dmaaddr_t host_buf_addr; /* physical address for bus_throughput_buf */ -} BWL_POST_PACKED_STRUCT pcie_bus_tput_params_t; -typedef BWL_PRE_PACKED_STRUCT struct pcie_bus_tput_stats { - uint16 time_taken; /* no of secs the test is run */ - uint16 nbytes_per_descriptor; /* no of bytes of data dma ed per descriptor */ - - /* no of desciptors fo which dma is sucessfully completed within the test time */ - uint32 count; -} BWL_POST_PACKED_STRUCT pcie_bus_tput_stats_t; - -#define MAX_ROAMOFFL_BSSID_NUM 100 - -typedef BWL_PRE_PACKED_STRUCT struct roamoffl_bssid_list { - int cnt; - struct ether_addr bssid[1]; -} BWL_POST_PACKED_STRUCT roamoffl_bssid_list_t; - -/* no default structure packing */ -#include - -typedef struct keepalives_max_idle { - uint16 keepalive_count; /* nmbr of keepalives per bss_max_idle period */ - uint8 mkeepalive_index; /* mkeepalive_index for keepalive frame to be used */ - uint8 PAD; /* to align next field */ - uint16 max_interval; /* seconds */ -} keepalives_max_idle_t; - -#define PM_IGNORE_BCMC_PROXY_ARP (1 << 0) -#define PM_IGNORE_BCMC_ALL_DMS_ACCEPTED (1 << 1) - -/* require strict packing */ -#include - -/* ##### Power Stats section ##### */ - -#define WL_PWRSTATS_VERSION 2 - -/* Input structure for pwrstats IOVAR */ -typedef BWL_PRE_PACKED_STRUCT struct wl_pwrstats_query { - uint16 length; /* Number of entries in type array. */ - uint16 type[1]; /* Types (tags) to retrieve. - * Length 0 (no types) means get all. - */ -} BWL_POST_PACKED_STRUCT wl_pwrstats_query_t; - -/* This structure is for version 2; version 1 will be deprecated in by FW */ -typedef BWL_PRE_PACKED_STRUCT struct wl_pwrstats { - uint16 version; /* Version = 2 is TLV format */ - uint16 length; /* Length of entire structure */ - uint8 data[1]; /* TLV data, a series of structures, - * each starting with type and length. - * - * Padded as necessary so each section - * starts on a 4-byte boundary. - * - * Both type and len are uint16, but the - * upper nibble of length is reserved so - * valid len values are 0-4095. - */ -} BWL_POST_PACKED_STRUCT wl_pwrstats_t; -#define WL_PWR_STATS_HDRLEN OFFSETOF(wl_pwrstats_t, data) - -/* Type values for the data section */ -#define WL_PWRSTATS_TYPE_PHY 0 /* struct wl_pwr_phy_stats */ -#define WL_PWRSTATS_TYPE_SCAN 1 /* struct wl_pwr_scan_stats */ -#define WL_PWRSTATS_TYPE_USB_HSIC 2 /* struct wl_pwr_usb_hsic_stats */ -#define WL_PWRSTATS_TYPE_PM_AWAKE 3 /* struct wl_pwr_pm_awake_stats */ -#define WL_PWRSTATS_TYPE_CONNECTION 4 /* struct wl_pwr_connect_stats; assoc and key-exch time */ -#define WL_PWRSTATS_TYPE_PCIE 6 /* struct wl_pwr_pcie_stats */ - -/* Bits for wake reasons */ -#define WLC_PMD_WAKE_SET 0x1 -#define WLC_PMD_PM_AWAKE_BCN 0x2 -#define WLC_PMD_BTA_ACTIVE 0x4 -#define WLC_PMD_SCAN_IN_PROGRESS 0x8 -#define WLC_PMD_RM_IN_PROGRESS 0x10 -#define WLC_PMD_AS_IN_PROGRESS 0x20 -#define WLC_PMD_PM_PEND 0x40 -#define WLC_PMD_PS_POLL 0x80 -#define WLC_PMD_CHK_UNALIGN_TBTT 0x100 -#define WLC_PMD_APSD_STA_UP 0x200 -#define WLC_PMD_TX_PEND_WAR 0x400 -#define WLC_PMD_GPTIMER_STAY_AWAKE 0x800 -#define WLC_PMD_PM2_RADIO_SOFF_PEND 0x2000 -#define WLC_PMD_NON_PRIM_STA_UP 0x4000 -#define WLC_PMD_AP_UP 0x8000 - -typedef BWL_PRE_PACKED_STRUCT struct wlc_pm_debug { - uint32 timestamp; /* timestamp in millisecond */ - uint32 reason; /* reason(s) for staying awake */ -} BWL_POST_PACKED_STRUCT wlc_pm_debug_t; - -/* Data sent as part of pwrstats IOVAR */ -typedef BWL_PRE_PACKED_STRUCT struct pm_awake_data { - uint32 curr_time; /* ms */ - uint32 hw_macc; /* HW maccontrol */ - uint32 sw_macc; /* SW maccontrol */ - uint32 pm_dur; /* Total sleep time in PM, usecs */ - uint32 mpc_dur; /* Total sleep time in MPC, usecs */ - - /* int32 drifts = remote - local; +ve drift => local-clk slow */ - int32 last_drift; /* Most recent TSF drift from beacon */ - int32 min_drift; /* Min TSF drift from beacon in magnitude */ - int32 max_drift; /* Max TSF drift from beacon in magnitude */ - - uint32 avg_drift; /* Avg TSF drift from beacon */ - - /* Wake history tracking */ - - /* pmstate array (type wlc_pm_debug_t) start offset */ - uint16 pm_state_offset; - /* pmstate number of array entries */ - uint16 pm_state_len; - - /* array (type uint32) start offset */ - uint16 pmd_event_wake_dur_offset; - /* pmd_event_wake_dur number of array entries */ - uint16 pmd_event_wake_dur_len; - - uint32 drift_cnt; /* Count of drift readings over which avg_drift was computed */ - uint8 pmwake_idx; /* for stepping through pm_state */ - uint8 pad[3]; - uint32 frts_time; /* Cumulative ms spent in frts since driver load */ - uint32 frts_end_cnt; /* No of times frts ended since driver load */ -} BWL_POST_PACKED_STRUCT pm_awake_data_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_pm_awake_stats { - uint16 type; /* WL_PWRSTATS_TYPE_PM_AWAKE */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - - pm_awake_data_t awake_data; -} BWL_POST_PACKED_STRUCT wl_pwr_pm_awake_stats_t; - -/* Original bus structure is for HSIC */ -typedef BWL_PRE_PACKED_STRUCT struct bus_metrics { - uint32 suspend_ct; /* suspend count */ - uint32 resume_ct; /* resume count */ - uint32 disconnect_ct; /* disconnect count */ - uint32 reconnect_ct; /* reconnect count */ - uint32 active_dur; /* msecs in bus, usecs for user */ - uint32 suspend_dur; /* msecs in bus, usecs for user */ - uint32 disconnect_dur; /* msecs in bus, usecs for user */ -} BWL_POST_PACKED_STRUCT bus_metrics_t; - -/* Bus interface info for USB/HSIC */ -typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_usb_hsic_stats { - uint16 type; /* WL_PWRSTATS_TYPE_USB_HSIC */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - - bus_metrics_t hsic; /* stats from hsic bus driver */ -} BWL_POST_PACKED_STRUCT wl_pwr_usb_hsic_stats_t; - -typedef BWL_PRE_PACKED_STRUCT struct pcie_bus_metrics { - uint32 d3_suspend_ct; /* suspend count */ - uint32 d0_resume_ct; /* resume count */ - uint32 perst_assrt_ct; /* PERST# assert count */ - uint32 perst_deassrt_ct; /* PERST# de-assert count */ - uint32 active_dur; /* msecs */ - uint32 d3_suspend_dur; /* msecs */ - uint32 perst_dur; /* msecs */ - uint32 l0_cnt; /* L0 entry count */ - uint32 l0_usecs; /* L0 duration in usecs */ - uint32 l1_cnt; /* L1 entry count */ - uint32 l1_usecs; /* L1 duration in usecs */ - uint32 l1_1_cnt; /* L1_1ss entry count */ - uint32 l1_1_usecs; /* L1_1ss duration in usecs */ - uint32 l1_2_cnt; /* L1_2ss entry count */ - uint32 l1_2_usecs; /* L1_2ss duration in usecs */ - uint32 l2_cnt; /* L2 entry count */ - uint32 l2_usecs; /* L2 duration in usecs */ -} BWL_POST_PACKED_STRUCT pcie_bus_metrics_t; - -/* Bus interface info for PCIE */ -typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_pcie_stats { - uint16 type; /* WL_PWRSTATS_TYPE_PCIE */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - pcie_bus_metrics_t pcie; /* stats from pcie bus driver */ -} BWL_POST_PACKED_STRUCT wl_pwr_pcie_stats_t; - -/* Scan information history per category */ -typedef BWL_PRE_PACKED_STRUCT struct scan_data { - uint32 count; /* Number of scans performed */ - uint32 dur; /* Total time (in us) used */ -} BWL_POST_PACKED_STRUCT scan_data_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_scan_stats { - uint16 type; /* WL_PWRSTATS_TYPE_SCAN */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - - /* Scan history */ - scan_data_t user_scans; /* User-requested scans: (i/e/p)scan */ - scan_data_t assoc_scans; /* Scans initiated by association requests */ - scan_data_t roam_scans; /* Scans initiated by the roam engine */ - scan_data_t pno_scans[8]; /* For future PNO bucketing (BSSID, SSID, etc) */ - scan_data_t other_scans; /* Scan engine usage not assigned to the above */ -} BWL_POST_PACKED_STRUCT wl_pwr_scan_stats_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_connect_stats { - uint16 type; /* WL_PWRSTATS_TYPE_SCAN */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - - /* Connection (Association + Key exchange) data */ - uint32 count; /* Number of connections performed */ - uint32 dur; /* Total time (in ms) used */ -} BWL_POST_PACKED_STRUCT wl_pwr_connect_stats_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_phy_stats { - uint16 type; /* WL_PWRSTATS_TYPE_PHY */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - uint32 tx_dur; /* TX Active duration in us */ - uint32 rx_dur; /* RX Active duration in us */ -} BWL_POST_PACKED_STRUCT wl_pwr_phy_stats_t; - - -/* ##### End of Power Stats section ##### */ - -/* IPV4 Arp offloads for ndis context */ -BWL_PRE_PACKED_STRUCT struct hostip_id { - struct ipv4_addr ipa; - uint8 id; -} BWL_POST_PACKED_STRUCT; - - -typedef BWL_PRE_PACKED_STRUCT struct wl_pfn_roam_thresh { - uint32 pfn_alert_thresh; /* time in ms */ - uint32 roam_alert_thresh; /* time in ms */ -} BWL_POST_PACKED_STRUCT wl_pfn_roam_thresh_t; - - -/* Reasons for wl_pmalert_t */ -#define PM_DUR_EXCEEDED (1<<0) -#define MPC_DUR_EXCEEDED (1<<1) -#define ROAM_ALERT_THRESH_EXCEEDED (1<<2) -#define PFN_ALERT_THRESH_EXCEEDED (1<<3) -#define CONST_AWAKE_DUR_ALERT (1<<4) -#define CONST_AWAKE_DUR_RECOVERY (1<<5) - -#define MIN_PM_ALERT_LEN 9 - -/* Data sent in EXCESS_PM_WAKE event */ -#define WL_PM_ALERT_VERSION 3 - -#define MAX_P2P_BSS_DTIM_PRD 4 - -/* This structure is for version 3; version 2 will be deprecated in by FW */ -typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert { - uint16 version; /* Version = 3 is TLV format */ - uint16 length; /* Length of entire structure */ - uint32 reasons; /* reason(s) for pm_alert */ - uint8 data[1]; /* TLV data, a series of structures, - * each starting with type and length. - * - * Padded as necessary so each section - * starts on a 4-byte boundary. - * - * Both type and len are uint16, but the - * upper nibble of length is reserved so - * valid len values are 0-4095. - */ -} BWL_POST_PACKED_STRUCT wl_pmalert_t; - -/* Type values for the data section */ -#define WL_PMALERT_FIXED 0 /* struct wl_pmalert_fixed_t, fixed fields */ -#define WL_PMALERT_PMSTATE 1 /* struct wl_pmalert_pmstate_t, variable */ -#define WL_PMALERT_EVENT_DUR 2 /* struct wl_pmalert_event_dur_t, variable */ -#define WL_PMALERT_UCODE_DBG 3 /* struct wl_pmalert_ucode_dbg_t, variable */ - -typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert_fixed { - uint16 type; /* WL_PMALERT_FIXED */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - uint32 prev_stats_time; /* msecs */ - uint32 curr_time; /* ms */ - uint32 prev_pm_dur; /* usecs */ - uint32 pm_dur; /* Total sleep time in PM, usecs */ - uint32 prev_mpc_dur; /* usecs */ - uint32 mpc_dur; /* Total sleep time in MPC, usecs */ - uint32 hw_macc; /* HW maccontrol */ - uint32 sw_macc; /* SW maccontrol */ - - /* int32 drifts = remote - local; +ve drift -> local-clk slow */ - int32 last_drift; /* Most recent TSF drift from beacon */ - int32 min_drift; /* Min TSF drift from beacon in magnitude */ - int32 max_drift; /* Max TSF drift from beacon in magnitude */ - - uint32 avg_drift; /* Avg TSF drift from beacon */ - uint32 drift_cnt; /* Count of drift readings over which avg_drift was computed */ - uint32 frts_time; /* Cumulative ms spent in frts since driver load */ - uint32 frts_end_cnt; /* No of times frts ended since driver load */ -} BWL_POST_PACKED_STRUCT wl_pmalert_fixed_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert_pmstate { - uint16 type; /* WL_PMALERT_PMSTATE */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - - uint8 pmwake_idx; /* for stepping through pm_state */ - uint8 pad[3]; - /* Array of pmstate; len of array is based on tlv len */ - wlc_pm_debug_t pmstate[1]; -} BWL_POST_PACKED_STRUCT wl_pmalert_pmstate_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert_event_dur { - uint16 type; /* WL_PMALERT_EVENT_DUR */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - - /* Array of event_dur, len of array is based on tlv len */ - uint32 event_dur[1]; -} BWL_POST_PACKED_STRUCT wl_pmalert_event_dur_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert_ucode_dbg { - uint16 type; /* WL_PMALERT_UCODE_DBG */ - uint16 len; /* Up to 4K-1, top 4 bits are reserved */ - uint32 macctrl; - uint16 m_p2p_hps; - uint32 psm_brc; - uint32 ifsstat; - uint16 m_p2p_bss_dtim_prd[MAX_P2P_BSS_DTIM_PRD]; - uint32 psmdebug[20]; - uint32 phydebug[20]; -} BWL_POST_PACKED_STRUCT wl_pmalert_ucode_dbg_t; - - -/* Structures and constants used for "vndr_ie" IOVar interface */ -#define VNDR_IE_CMD_LEN 4 /* length of the set command string: - * "add", "del" (+ NUL) - */ - -#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ - vndr_ie_t vndr_ie_data; /* vendor IE data */ -} BWL_POST_PACKED_STRUCT vndr_ie_info_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - int iecount; /* number of entries in the vndr_ie_list[] array */ - vndr_ie_info_t vndr_ie_list[1]; /* variable size list of vndr_ie_info_t structs */ -} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - char cmd[VNDR_IE_CMD_LEN]; /* vndr_ie IOVar set command : "add", "del" + NUL */ - vndr_ie_buf_t vndr_ie_buffer; /* buffer containing Vendor IE list information */ -} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; - -/* tag_ID/length/value_buffer tuple */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 id; - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT tlv_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ - tlv_t ie_data; /* IE data */ -} BWL_POST_PACKED_STRUCT ie_info_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - int iecount; /* number of entries in the ie_list[] array */ - ie_info_t ie_list[1]; /* variable size list of ie_info_t structs */ -} BWL_POST_PACKED_STRUCT ie_buf_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - char cmd[VNDR_IE_CMD_LEN]; /* ie IOVar set command : "add" + NUL */ - ie_buf_t ie_buffer; /* buffer containing IE list information */ -} BWL_POST_PACKED_STRUCT ie_setbuf_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ - uint8 id; /* IE type */ -} BWL_POST_PACKED_STRUCT ie_getbuf_t; - -/* structures used to define format of wps ie data from probe requests */ -/* passed up to applications via iovar "prbreq_wpsie" */ -typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr { - struct ether_addr staAddr; - uint16 ieLen; -} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t; - -typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { - sta_prbreq_wps_ie_hdr_t hdr; - uint8 ieData[1]; -} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; - -typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { - uint32 totLen; - uint8 ieDataList[1]; -} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; - - -#ifdef WLMEDIA_TXFAILEVENT -typedef BWL_PRE_PACKED_STRUCT struct { - char dest[ETHER_ADDR_LEN]; /* destination MAC */ - uint8 prio; /* Packet Priority */ - uint8 flags; /* Flags */ - uint32 tsf_l; /* TSF timer low */ - uint32 tsf_h; /* TSF timer high */ - uint16 rates; /* Main Rates */ - uint16 txstatus; /* TX Status */ -} BWL_POST_PACKED_STRUCT txfailinfo_t; -#endif /* WLMEDIA_TXFAILEVENT */ - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 flags; - chanspec_t chanspec; /* txpwr report for this channel */ - chanspec_t local_chanspec; /* channel on which we are associated */ - uint8 local_max; /* local max according to the AP */ - uint8 local_constraint; /* local constraint according to the AP */ - int8 antgain[2]; /* Ant gain for each band - from SROM */ - uint8 rf_cores; /* count of RF Cores being reported */ - uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ - uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain w/o adjustment */ - uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ - uint8 tx_power_max[4]; /* Maximum target power among all rates */ - uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ - int8 sar; /* SAR limit for display by wl executable */ - int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ - uint8 version; /* Version of the data format wlu <--> driver */ - uint8 display_core; /* Displayed curpower core */ - int8 target_offsets[4]; /* Target power offsets for current rate per core */ - uint32 last_tx_ratespec; /* Ratespec for last transmition */ - uint user_target; /* user limit */ - uint32 ppr_len; /* length of each ppr serialization buffer */ - int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; - uint8 pprdata[1]; /* ppr serialization buffer */ -} BWL_POST_PACKED_STRUCT tx_pwr_rpt_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - struct ipv4_addr ipv4_addr; - struct ether_addr nexthop; -} BWL_POST_PACKED_STRUCT ibss_route_entry_t; -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 num_entry; - ibss_route_entry_t route_entry[1]; -} BWL_POST_PACKED_STRUCT ibss_route_tbl_t; - -#define MAX_IBSS_ROUTE_TBL_ENTRY 64 - -#define TXPWR_TARGET_VERSION 0 -typedef BWL_PRE_PACKED_STRUCT struct { - int32 version; /* version number */ - chanspec_t chanspec; /* txpwr report for this channel */ - int8 txpwr[WL_STA_ANT_MAX]; /* Max tx target power, in qdb */ - uint8 rf_cores; /* count of RF Cores being reported */ -} BWL_POST_PACKED_STRUCT txpwr_target_max_t; - -#define BSS_PEER_INFO_PARAM_CUR_VER 0 -/* Input structure for IOV_BSS_PEER_INFO */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - struct ether_addr ea; /* peer MAC address */ -} BWL_POST_PACKED_STRUCT bss_peer_info_param_t; - -#define BSS_PEER_INFO_CUR_VER 0 - -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - struct ether_addr ea; - int32 rssi; - uint32 tx_rate; /* current tx rate */ - uint32 rx_rate; /* current rx rate */ - wl_rateset_t rateset; /* rateset in use */ - uint32 age; /* age in seconds */ -} BWL_POST_PACKED_STRUCT bss_peer_info_t; - -#define BSS_PEER_LIST_INFO_CUR_VER 0 - -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - uint16 bss_peer_info_len; /* length of bss_peer_info_t */ - uint32 count; /* number of peer info */ - bss_peer_info_t peer_info[1]; /* peer info */ -} BWL_POST_PACKED_STRUCT bss_peer_list_info_t; - -#define BSS_PEER_LIST_INFO_FIXED_LEN OFFSETOF(bss_peer_list_info_t, peer_info) - -#define AIBSS_BCN_FORCE_CONFIG_VER_0 0 - -/* structure used to configure AIBSS beacon force xmit */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - uint16 len; - uint32 initial_min_bcn_dur; /* dur in ms to check a bcn in bcn_flood period */ - uint32 min_bcn_dur; /* dur in ms to check a bcn after bcn_flood period */ - uint32 bcn_flood_dur; /* Initial bcn xmit period in ms */ -} BWL_POST_PACKED_STRUCT aibss_bcn_force_config_t; - -#define AIBSS_TXFAIL_CONFIG_VER_0 0 - -/* structure used to configure aibss tx fail event */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - uint16 len; - uint32 bcn_timeout; /* dur in seconds to receive 1 bcn */ - uint32 max_tx_retry; /* no of consecutive no acks to send txfail event */ -} BWL_POST_PACKED_STRUCT aibss_txfail_config_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_aibss_if { - uint16 version; - uint16 len; - uint32 flags; - struct ether_addr addr; - chanspec_t chspec; -} BWL_POST_PACKED_STRUCT wl_aibss_if_t; - -typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_entry { - struct ipv4_addr ip_addr; - struct ether_addr nexthop; -} BWL_POST_PACKED_STRUCT wlc_ipfo_route_entry_t; - -typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_tbl { - uint32 num_entry; - wlc_ipfo_route_entry_t route_entry[1]; -} BWL_POST_PACKED_STRUCT wlc_ipfo_route_tbl_t; - -#define WL_IPFO_ROUTE_TBL_FIXED_LEN 4 -#define WL_MAX_IPFO_ROUTE_TBL_ENTRY 64 - -/* no strict structure packing */ -#include - - /* Global ASSERT Logging */ -#define ASSERTLOG_CUR_VER 0x0100 -#define MAX_ASSRTSTR_LEN 64 - - typedef struct assert_record { - uint32 time; - uint8 seq_num; - char str[MAX_ASSRTSTR_LEN]; - } assert_record_t; - - typedef struct assertlog_results { - uint16 version; - uint16 record_len; - uint32 num; - assert_record_t logs[1]; - } assertlog_results_t; - -#define LOGRRC_FIX_LEN 8 -#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) - -#ifdef BCMWAPI_WAI -#define IV_LEN 16 - struct wapi_sta_msg_t - { - uint16 msg_type; - uint16 datalen; - uint8 vap_mac[6]; - uint8 reserve_data1[2]; - uint8 sta_mac[6]; - uint8 reserve_data2[2]; - uint8 gsn[IV_LEN]; - uint8 wie[256]; - }; -#endif /* BCMWAPI_WAI */ - - /* chanim acs record */ - typedef struct { - bool valid; - uint8 trigger; - chanspec_t selected_chspc; - int8 bgnoise; - uint32 glitch_cnt; - uint8 ccastats; - uint timestamp; - } chanim_acs_record_t; - - typedef struct { - chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; - uint8 count; - uint timestamp; - } wl_acs_record_t; - - typedef struct chanim_stats { - uint32 glitchcnt; /* normalized as per second count */ - uint32 badplcp; /* normalized as per second count */ - uint8 ccastats[CCASTATS_MAX]; /* normalized as 0-255 */ - int8 bgnoise; /* background noise level (in dBm) */ - chanspec_t chanspec; - uint32 timestamp; - uint32 bphy_glitchcnt; /* normalized as per second count */ - uint32 bphy_badplcp; /* normalized as per second count */ - uint8 chan_idle; /* normalized as 0~255 */ - } chanim_stats_t; - -#define WL_CHANIM_STATS_VERSION 2 - -typedef struct { - uint32 buflen; - uint32 version; - uint32 count; - chanim_stats_t stats[1]; -} wl_chanim_stats_t; - -#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats) - -/* Noise measurement metrics. */ -#define NOISE_MEASURE_KNOISE 0x1 - -/* scb probe parameter */ -typedef struct { - uint32 scb_timeout; - uint32 scb_activity_time; - uint32 scb_max_probe; -} wl_scb_probe_t; - -/* structure/defines for selective mgmt frame (smf) stats support */ - -#define SMFS_VERSION 1 -/* selected mgmt frame (smf) stats element */ -typedef struct wl_smfs_elem { - uint32 count; - uint16 code; /* SC or RC code */ -} wl_smfs_elem_t; - -typedef struct wl_smf_stats { - uint32 version; - uint16 length; /* reserved for future usage */ - uint8 type; - uint8 codetype; - uint32 ignored_cnt; - uint32 malformed_cnt; - uint32 count_total; /* count included the interested group */ - wl_smfs_elem_t elem[1]; -} wl_smf_stats_t; - -#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); - -enum { - SMFS_CODETYPE_SC, - SMFS_CODETYPE_RC -}; - -typedef enum smfs_type { - SMFS_TYPE_AUTH, - SMFS_TYPE_ASSOC, - SMFS_TYPE_REASSOC, - SMFS_TYPE_DISASSOC_TX, - SMFS_TYPE_DISASSOC_RX, - SMFS_TYPE_DEAUTH_TX, - SMFS_TYPE_DEAUTH_RX, - SMFS_TYPE_MAX -} smfs_type_t; - -#ifdef PHYMON - -#define PHYMON_VERSION 1 - -typedef struct wl_phycal_core_state { - /* Tx IQ/LO calibration coeffs */ - int16 tx_iqlocal_a; - int16 tx_iqlocal_b; - int8 tx_iqlocal_ci; - int8 tx_iqlocal_cq; - int8 tx_iqlocal_di; - int8 tx_iqlocal_dq; - int8 tx_iqlocal_ei; - int8 tx_iqlocal_eq; - int8 tx_iqlocal_fi; - int8 tx_iqlocal_fq; - - /* Rx IQ calibration coeffs */ - int16 rx_iqcal_a; - int16 rx_iqcal_b; - - uint8 tx_iqlocal_pwridx; /* Tx Power Index for Tx IQ/LO calibration */ - uint32 papd_epsilon_table[64]; /* PAPD epsilon table */ - int16 papd_epsilon_offset; /* PAPD epsilon offset */ - uint8 curr_tx_pwrindex; /* Tx power index */ - int8 idle_tssi; /* Idle TSSI */ - int8 est_tx_pwr; /* Estimated Tx Power (dB) */ - int8 est_rx_pwr; /* Estimated Rx Power (dB) from RSSI */ - uint16 rx_gaininfo; /* Rx gain applied on last Rx pkt */ - uint16 init_gaincode; /* initgain required for ACI */ - int8 estirr_tx; - int8 estirr_rx; - -} wl_phycal_core_state_t; - -typedef struct wl_phycal_state { - int version; - int8 num_phy_cores; /* number of cores */ - int8 curr_temperature; /* on-chip temperature sensor reading */ - chanspec_t chspec; /* channspec for this state */ - bool aci_state; /* ACI state: ON/OFF */ - uint16 crsminpower; /* crsminpower required for ACI */ - uint16 crsminpowerl; /* crsminpowerl required for ACI */ - uint16 crsminpoweru; /* crsminpoweru required for ACI */ - wl_phycal_core_state_t phycal_core[1]; -} wl_phycal_state_t; - -#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) -#endif /* PHYMON */ - -/* discovery state */ -typedef struct wl_p2p_disc_st { - uint8 state; /* see state */ - chanspec_t chspec; /* valid in listen state */ - uint16 dwell; /* valid in listen state, in ms */ -} wl_p2p_disc_st_t; - -/* scan request */ -typedef struct wl_p2p_scan { - uint8 type; /* 'S' for WLC_SCAN, 'E' for "escan" */ - uint8 reserved[3]; - /* scan or escan parms... */ -} wl_p2p_scan_t; - -/* i/f request */ -typedef struct wl_p2p_if { - struct ether_addr addr; - uint8 type; /* see i/f type */ - chanspec_t chspec; /* for p2p_ifadd GO */ -} wl_p2p_if_t; - -/* i/f query */ -typedef struct wl_p2p_ifq { - uint bsscfgidx; - char ifname[BCM_MSG_IFNAME_MAX]; -} wl_p2p_ifq_t; - -/* OppPS & CTWindow */ -typedef struct wl_p2p_ops { - uint8 ops; /* 0: disable 1: enable */ - uint8 ctw; /* >= 10 */ -} wl_p2p_ops_t; - -/* absence and presence request */ -typedef struct wl_p2p_sched_desc { - uint32 start; - uint32 interval; - uint32 duration; - uint32 count; /* see count */ -} wl_p2p_sched_desc_t; - -typedef struct wl_p2p_sched { - uint8 type; /* see schedule type */ - uint8 action; /* see schedule action */ - uint8 option; /* see schedule option */ - wl_p2p_sched_desc_t desc[1]; -} wl_p2p_sched_t; - -typedef struct wl_p2p_wfds_hash { - uint32 advt_id; - uint16 nw_cfg_method; - uint8 wfds_hash[6]; - uint8 name_len; - uint8 service_name[MAX_WFDS_SVC_NAME_LEN]; -} wl_p2p_wfds_hash_t; - -typedef struct wl_bcmdcs_data { - uint reason; - chanspec_t chspec; -} wl_bcmdcs_data_t; - - -/* NAT configuration */ -typedef struct { - uint32 ipaddr; /* interface ip address */ - uint32 ipaddr_mask; /* interface ip address mask */ - uint32 ipaddr_gateway; /* gateway ip address */ - uint8 mac_gateway[6]; /* gateway mac address */ - uint32 ipaddr_dns; /* DNS server ip address, valid only for public if */ - uint8 mac_dns[6]; /* DNS server mac address, valid only for public if */ - uint8 GUID[38]; /* interface GUID */ -} nat_if_info_t; - -typedef struct { - uint op; /* operation code */ - bool pub_if; /* set for public if, clear for private if */ - nat_if_info_t if_info; /* interface info */ -} nat_cfg_t; - -typedef struct { - int state; /* NAT state returned */ -} nat_state_t; - - -#define BTA_STATE_LOG_SZ 64 - -/* BTAMP Statemachine states */ -enum { - HCIReset = 1, - HCIReadLocalAMPInfo, - HCIReadLocalAMPASSOC, - HCIWriteRemoteAMPASSOC, - HCICreatePhysicalLink, - HCIAcceptPhysicalLinkRequest, - HCIDisconnectPhysicalLink, - HCICreateLogicalLink, - HCIAcceptLogicalLink, - HCIDisconnectLogicalLink, - HCILogicalLinkCancel, - HCIAmpStateChange, - HCIWriteLogicalLinkAcceptTimeout -}; - -typedef struct flush_txfifo { - uint32 txfifobmp; - uint32 hwtxfifoflush; - struct ether_addr ea; -} flush_txfifo_t; - -enum { - SPATIAL_MODE_2G_IDX = 0, - SPATIAL_MODE_5G_LOW_IDX, - SPATIAL_MODE_5G_MID_IDX, - SPATIAL_MODE_5G_HIGH_IDX, - SPATIAL_MODE_5G_UPPER_IDX, - SPATIAL_MODE_MAX_IDX -}; - -#define WLC_TXCORE_MAX 4 /* max number of txcore supports */ -#define WLC_SUBBAND_MAX 4 /* max number of sub-band supports */ -typedef struct { - uint8 band2g[WLC_TXCORE_MAX]; - uint8 band5g[WLC_SUBBAND_MAX][WLC_TXCORE_MAX]; -} sar_limit_t; - -#define WLC_TXCAL_CORE_MAX 2 /* max number of txcore supports for txcal */ -#define MAX_NUM_TXCAL_MEAS 128 - -typedef struct wl_txcal_meas { - uint8 tssi[WLC_TXCAL_CORE_MAX][MAX_NUM_TXCAL_MEAS]; - int16 pwr[WLC_TXCAL_CORE_MAX][MAX_NUM_TXCAL_MEAS]; - uint8 valid_cnt; -} wl_txcal_meas_t; - -typedef struct wl_txcal_power_tssi { - uint8 set_core; - uint8 channel; - int16 pwr_start[WLC_TXCAL_CORE_MAX]; - uint8 num_entries[WLC_TXCAL_CORE_MAX]; - uint8 tssi[WLC_TXCAL_CORE_MAX][MAX_NUM_TXCAL_MEAS]; - bool gen_tbl; -} wl_txcal_power_tssi_t; - -/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ -typedef struct wl_mempool_stats { - int num; /* Number of memory pools */ - bcm_mp_stats_t s[1]; /* Variable array of memory pool stats. */ -} wl_mempool_stats_t; - -typedef struct { - uint32 ipaddr; - uint32 ipaddr_netmask; - uint32 ipaddr_gateway; -} nwoe_ifconfig_t; - -/* Traffic management priority classes */ -typedef enum trf_mgmt_priority_class { - trf_mgmt_priority_low = 0, /* Maps to 802.1p BK */ - trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ - trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ - trf_mgmt_priority_nochange = 3, /* do not update the priority */ - trf_mgmt_priority_invalid = (trf_mgmt_priority_nochange + 1) -} trf_mgmt_priority_class_t; - -/* Traffic management configuration parameters */ -typedef struct trf_mgmt_config { - uint32 trf_mgmt_enabled; /* 0 - disabled, 1 - enabled */ - uint32 flags; /* See TRF_MGMT_FLAG_xxx defines */ - uint32 host_ip_addr; /* My IP address to determine subnet */ - uint32 host_subnet_mask; /* My subnet mask */ - uint32 downlink_bandwidth; /* In units of kbps */ - uint32 uplink_bandwidth; /* In units of kbps */ - uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed tx bandwidth */ - uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed rx bandwidth */ -} trf_mgmt_config_t; - -/* Traffic management filter */ -typedef struct trf_mgmt_filter { - struct ether_addr dst_ether_addr; /* His L2 address */ - uint32 dst_ip_addr; /* His IP address */ - uint16 dst_port; /* His L4 port */ - uint16 src_port; /* My L4 port */ - uint16 prot; /* L4 protocol (only TCP or UDP) */ - uint16 flags; /* TBD. For now, this must be zero. */ - trf_mgmt_priority_class_t priority; /* Priority for filtered packets */ - uint32 dscp; /* DSCP */ -} trf_mgmt_filter_t; - -/* Traffic management filter list (variable length) */ -typedef struct trf_mgmt_filter_list { - uint32 num_filters; - trf_mgmt_filter_t filter[1]; -} trf_mgmt_filter_list_t; - -/* Traffic management global info used for all queues */ -typedef struct trf_mgmt_global_info { - uint32 maximum_bytes_per_second; - uint32 maximum_bytes_per_sampling_period; - uint32 total_bytes_consumed_per_second; - uint32 total_bytes_consumed_per_sampling_period; - uint32 total_unused_bytes_per_sampling_period; -} trf_mgmt_global_info_t; - -/* Traffic management shaping info per priority queue */ -typedef struct trf_mgmt_shaping_info { - uint32 gauranteed_bandwidth_percentage; - uint32 guaranteed_bytes_per_second; - uint32 guaranteed_bytes_per_sampling_period; - uint32 num_bytes_produced_per_second; - uint32 num_bytes_consumed_per_second; - uint32 num_queued_packets; /* Number of packets in queue */ - uint32 num_queued_bytes; /* Number of bytes in queue */ -} trf_mgmt_shaping_info_t; - -/* Traffic management shaping info array */ -typedef struct trf_mgmt_shaping_info_array { - trf_mgmt_global_info_t tx_global_shaping_info; - trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; - trf_mgmt_global_info_t rx_global_shaping_info; - trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; -} trf_mgmt_shaping_info_array_t; - - -/* Traffic management statistical counters */ -typedef struct trf_mgmt_stats { - uint32 num_processed_packets; /* Number of packets processed */ - uint32 num_processed_bytes; /* Number of bytes processed */ - uint32 num_discarded_packets; /* Number of packets discarded from queue */ -} trf_mgmt_stats_t; - -/* Traffic management statisics array */ -typedef struct trf_mgmt_stats_array { - trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; - trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; -} trf_mgmt_stats_array_t; - -typedef struct powersel_params { - /* LPC Params exposed via IOVAR */ - int32 tp_ratio_thresh; /* Throughput ratio threshold */ - uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ - uint8 pwr_stab_thresh; /* Number of successes before power step down */ - uint8 pwr_sel_exp_time; /* Time lapse for expiry of database */ -} powersel_params_t; - -typedef struct lpc_params { - /* LPC Params exposed via IOVAR */ - uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ - uint8 pwr_stab_thresh; /* Number of successes before power step down */ - uint8 lpc_exp_time; /* Time lapse for expiry of database */ - uint8 pwrup_slow_step; /* Step size for slow step up */ - uint8 pwrup_fast_step; /* Step size for fast step up */ - uint8 pwrdn_slow_step; /* Step size for slow step down */ -} lpc_params_t; - -/* tx pkt delay statistics */ -#define SCB_RETRY_SHORT_DEF 7 /* Default Short retry Limit */ -#define WLPKTDLY_HIST_NBINS 16 /* number of bins used in the Delay histogram */ - -/* structure to store per-AC delay statistics */ -typedef struct scb_delay_stats { - uint32 txmpdu_lost; /* number of MPDUs lost */ - uint32 txmpdu_cnt[SCB_RETRY_SHORT_DEF]; /* retry times histogram */ - uint32 delay_sum[SCB_RETRY_SHORT_DEF]; /* cumulative packet latency */ - uint32 delay_min; /* minimum packet latency observed */ - uint32 delay_max; /* maximum packet latency observed */ - uint32 delay_avg; /* packet latency average */ - uint32 delay_hist[WLPKTDLY_HIST_NBINS]; /* delay histogram */ -} scb_delay_stats_t; - -/* structure for txdelay event */ -typedef struct txdelay_event { - uint8 status; - int rssi; - chanim_stats_t chanim_stats; - scb_delay_stats_t delay_stats[AC_COUNT]; -} txdelay_event_t; - -/* structure for txdelay parameters */ -typedef struct txdelay_params { - uint16 ratio; /* Avg Txdelay Delta */ - uint8 cnt; /* Sample cnt */ - uint8 period; /* Sample period */ - uint8 tune; /* Debug */ -} txdelay_params_t; - -enum { - WNM_SERVICE_DMS = 1, - WNM_SERVICE_FMS = 2, - WNM_SERVICE_TFS = 3 -}; - -/* Definitions for WNM/NPS TCLAS */ -typedef struct wl_tclas { - uint8 user_priority; - uint8 fc_len; - dot11_tclas_fc_t fc; -} wl_tclas_t; - -#define WL_TCLAS_FIXED_SIZE OFFSETOF(wl_tclas_t, fc) - -typedef struct wl_tclas_list { - uint32 num; - wl_tclas_t tclas[1]; -} wl_tclas_list_t; - -/* Definitions for WNM/NPS Traffic Filter Service */ -typedef struct wl_tfs_req { - uint8 tfs_id; - uint8 tfs_actcode; - uint8 tfs_subelem_id; - uint8 send; -} wl_tfs_req_t; - -typedef struct wl_tfs_filter { - uint8 status; /* Status returned by the AP */ - uint8 tclas_proc; /* TCLAS processing value (0:and, 1:or) */ - uint8 tclas_cnt; /* count of all wl_tclas_t in tclas array */ - uint8 tclas[1]; /* VLA of wl_tclas_t */ -} wl_tfs_filter_t; -#define WL_TFS_FILTER_FIXED_SIZE OFFSETOF(wl_tfs_filter_t, tclas) - -typedef struct wl_tfs_fset { - struct ether_addr ea; /* Address of AP/STA involved with this filter set */ - uint8 tfs_id; /* TFS ID field chosen by STA host */ - uint8 status; /* Internal status TFS_STATUS_xxx */ - uint8 actcode; /* Action code DOT11_TFS_ACTCODE_xxx */ - uint8 token; /* Token used in last request frame */ - uint8 notify; /* Notify frame sent/received because of this set */ - uint8 filter_cnt; /* count of all wl_tfs_filter_t in filter array */ - uint8 filter[1]; /* VLA of wl_tfs_filter_t */ -} wl_tfs_fset_t; -#define WL_TFS_FSET_FIXED_SIZE OFFSETOF(wl_tfs_fset_t, filter) - -enum { - TFS_STATUS_DISABLED = 0, /* TFS filter set disabled by user */ - TFS_STATUS_DISABLING = 1, /* Empty request just sent to AP */ - TFS_STATUS_VALIDATED = 2, /* Filter set validated by AP (but maybe not enabled!) */ - TFS_STATUS_VALIDATING = 3, /* Filter set just sent to AP */ - TFS_STATUS_NOT_ASSOC = 4, /* STA not associated */ - TFS_STATUS_NOT_SUPPORT = 5, /* TFS not supported by AP */ - TFS_STATUS_DENIED = 6, /* Filter set refused by AP (=> all sets are disabled!) */ -}; - -typedef struct wl_tfs_status { - uint8 fset_cnt; /* count of all wl_tfs_fset_t in fset array */ - wl_tfs_fset_t fset[1]; /* VLA of wl_tfs_fset_t */ -} wl_tfs_status_t; - -typedef struct wl_tfs_set { - uint8 send; /* Immediatly register registered sets on AP side */ - uint8 tfs_id; /* ID of a specific set (existing or new), or nul for all */ - uint8 actcode; /* Action code for this filter set */ - uint8 tclas_proc; /* TCLAS processing operator for this filter set */ -} wl_tfs_set_t; - -typedef struct wl_tfs_term { - uint8 del; /* Delete internal set once confirmation received */ - uint8 tfs_id; /* ID of a specific set (existing), or nul for all */ -} wl_tfs_term_t; - - -#define DMS_DEP_PROXY_ARP (1 << 0) - -/* Definitions for WNM/NPS Directed Multicast Service */ -enum { - DMS_STATUS_DISABLED = 0, /* DMS desc disabled by user */ - DMS_STATUS_ACCEPTED = 1, /* Request accepted by AP */ - DMS_STATUS_NOT_ASSOC = 2, /* STA not associated */ - DMS_STATUS_NOT_SUPPORT = 3, /* DMS not supported by AP */ - DMS_STATUS_DENIED = 4, /* Request denied by AP */ - DMS_STATUS_TERM = 5, /* Request terminated by AP */ - DMS_STATUS_REMOVING = 6, /* Remove request just sent */ - DMS_STATUS_ADDING = 7, /* Add request just sent */ - DMS_STATUS_ERROR = 8, /* Non compliant AP behvior */ - DMS_STATUS_IN_PROGRESS = 9, /* Request just sent */ - DMS_STATUS_REQ_MISMATCH = 10 /* Conditions for sending DMS req not met */ -}; - -typedef struct wl_dms_desc { - uint8 user_id; - uint8 status; - uint8 token; - uint8 dms_id; - uint8 tclas_proc; - uint8 mac_len; /* length of all ether_addr in data array, 0 if STA */ - uint8 tclas_len; /* length of all wl_tclas_t in data array */ - uint8 data[1]; /* VLA of 'ether_addr' and 'wl_tclas_t' (in this order ) */ -} wl_dms_desc_t; - -#define WL_DMS_DESC_FIXED_SIZE OFFSETOF(wl_dms_desc_t, data) - -typedef struct wl_dms_status { - uint32 cnt; - wl_dms_desc_t desc[1]; -} wl_dms_status_t; - -typedef struct wl_dms_set { - uint8 send; - uint8 user_id; - uint8 tclas_proc; -} wl_dms_set_t; - -typedef struct wl_dms_term { - uint8 del; - uint8 user_id; -} wl_dms_term_t; - -typedef struct wl_service_term { - uint8 service; - union { - wl_dms_term_t dms; - } u; -} wl_service_term_t; - -/* Definitions for WNM/NPS BSS Transistion */ -typedef struct wl_bsstrans_req { - uint16 tbtt; /* time of BSS to end of life, in unit of TBTT */ - uint16 dur; /* time of BSS to keep off, in unit of minute */ - uint8 reqmode; /* request mode of BSS transition request */ - uint8 unicast; /* request by unicast or by broadcast */ -} wl_bsstrans_req_t; - -enum { - BSSTRANS_RESP_AUTO = 0, /* Currently equivalent to ENABLE */ - BSSTRANS_RESP_DISABLE = 1, /* Never answer BSS Trans Req frames */ - BSSTRANS_RESP_ENABLE = 2, /* Always answer Req frames with preset data */ - BSSTRANS_RESP_WAIT = 3, /* Send ind, wait and/or send preset data (NOT IMPL) */ - BSSTRANS_RESP_IMMEDIATE = 4 /* After an ind, set data and send resp (NOT IMPL) */ -}; - -typedef struct wl_bsstrans_resp { - uint8 policy; - uint8 status; - uint8 delay; - struct ether_addr target; -} wl_bsstrans_resp_t; - -/* "wnm_bsstrans_policy" argument programs behavior after BSSTRANS Req reception. - * BSS-Transition feature is used by multiple programs such as NPS-PF, VE-PF, - * Band-steering, Hotspot 2.0 and customer requirements. Each PF and its test plan - * mandates different behavior on receiving BSS-transition request. To accomodate - * such divergent behaviors these policies have been created. - */ -enum { - WL_BSSTRANS_POLICY_ROAM_ALWAYS = 0, /* Roam (or disassociate) in all cases */ - WL_BSSTRANS_POLICY_ROAM_IF_MODE = 1, /* Roam only if requested by Request Mode field */ - WL_BSSTRANS_POLICY_ROAM_IF_PREF = 2, /* Roam only if Preferred BSS provided */ - WL_BSSTRANS_POLICY_WAIT = 3, /* Wait for deauth and send Accepted status */ - WL_BSSTRANS_POLICY_PRODUCT = 4, /* Policy for real product use cases (non-pf) */ -}; - -/* Definitions for WNM/NPS TIM Broadcast */ -typedef struct wl_timbc_offset { - int16 offset; /* offset in us */ - uint16 fix_intv; /* override interval sent from STA */ - uint16 rate_override; /* use rate override to send high rate TIM broadcast frame */ - uint8 tsf_present; /* show timestamp in TIM broadcast frame */ -} wl_timbc_offset_t; - -typedef struct wl_timbc_set { - uint8 interval; /* Interval in DTIM wished or required. */ - uint8 flags; /* Bitfield described below */ - uint16 rate_min; /* Minimum rate required for High/Low TIM frames. Optionnal */ - uint16 rate_max; /* Maximum rate required for High/Low TIM frames. Optionnal */ -} wl_timbc_set_t; - -enum { - WL_TIMBC_SET_TSF_REQUIRED = 1, /* Enable TIMBC only if TSF in TIM frames */ - WL_TIMBC_SET_NO_OVERRIDE = 2, /* ... if AP does not override interval */ - WL_TIMBC_SET_PROXY_ARP = 4, /* ... if AP support Proxy ARP */ - WL_TIMBC_SET_DMS_ACCEPTED = 8 /* ... if all DMS desc have been accepted */ -}; - -typedef struct wl_timbc_status { - uint8 status_sta; /* Status from internal state machine (check below) */ - uint8 status_ap; /* From AP response frame (check 8.4.2.86 from 802.11) */ - uint8 interval; - uint8 pad; - int32 offset; - uint16 rate_high; - uint16 rate_low; -} wl_timbc_status_t; - -enum { - WL_TIMBC_STATUS_DISABLE = 0, /* TIMBC disabled by user */ - WL_TIMBC_STATUS_REQ_MISMATCH = 1, /* AP settings do no match user requirements */ - WL_TIMBC_STATUS_NOT_ASSOC = 2, /* STA not associated */ - WL_TIMBC_STATUS_NOT_SUPPORT = 3, /* TIMBC not supported by AP */ - WL_TIMBC_STATUS_DENIED = 4, /* Req to disable TIMBC sent to AP */ - WL_TIMBC_STATUS_ENABLE = 5 /* TIMBC enabled */ -}; - -/* Definitions for PM2 Dynamic Fast Return To Sleep */ -typedef struct wl_pm2_sleep_ret_ext { - uint8 logic; /* DFRTS logic: see WL_DFRTS_LOGIC_* below */ - uint16 low_ms; /* Low FRTS timeout */ - uint16 high_ms; /* High FRTS timeout */ - uint16 rx_pkts_threshold; /* switching threshold: # rx pkts */ - uint16 tx_pkts_threshold; /* switching threshold: # tx pkts */ - uint16 txrx_pkts_threshold; /* switching threshold: # (tx+rx) pkts */ - uint32 rx_bytes_threshold; /* switching threshold: # rx bytes */ - uint32 tx_bytes_threshold; /* switching threshold: # tx bytes */ - uint32 txrx_bytes_threshold; /* switching threshold: # (tx+rx) bytes */ -} wl_pm2_sleep_ret_ext_t; - -#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ -#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ -#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ - -/* Values for the passive_on_restricted_mode iovar. When set to non-zero, this iovar - * disables automatic conversions of a channel from passively scanned to - * actively scanned. These values only have an effect for country codes such - * as XZ where some 5 GHz channels are defined to be passively scanned. - */ -#define WL_PASSACTCONV_DISABLE_NONE 0 /* Enable permanent and temporary conversions */ -#define WL_PASSACTCONV_DISABLE_ALL 1 /* Disable permanent and temporary conversions */ -#define WL_PASSACTCONV_DISABLE_PERM 2 /* Disable only permanent conversions */ - -/* Definitions for Reliable Multicast */ -#define WL_RMC_CNT_VERSION 1 -#define WL_RMC_TR_VERSION 1 -#define WL_RMC_MAX_CLIENT 32 -#define WL_RMC_FLAG_INBLACKLIST 1 -#define WL_RMC_FLAG_ACTIVEACKER 2 -#define WL_RMC_FLAG_RELMCAST 4 -#define WL_RMC_MAX_TABLE_ENTRY 4 - -#define WL_RMC_VER 1 -#define WL_RMC_INDEX_ACK_ALL 255 -#define WL_RMC_NUM_OF_MC_STREAMS 4 -#define WL_RMC_MAX_TRS_PER_GROUP 1 -#define WL_RMC_MAX_TRS_IN_ACKALL 1 -#define WL_RMC_ACK_MCAST0 0x02 -#define WL_RMC_ACK_MCAST_ALL 0x01 -#define WL_RMC_ACTF_TIME_MIN 300 /* time in ms */ -#define WL_RMC_ACTF_TIME_MAX 20000 /* time in ms */ -#define WL_RMC_MAX_NUM_TRS 32 /* maximun transmitters allowed */ -#define WL_RMC_ARTMO_MIN 350 /* time in ms */ -#define WL_RMC_ARTMO_MAX 40000 /* time in ms */ - -/* RMC events in action frames */ -enum rmc_opcodes { - RELMCAST_ENTRY_OP_DISABLE = 0, /* Disable multi-cast group */ - RELMCAST_ENTRY_OP_DELETE = 1, /* Delete multi-cast group */ - RELMCAST_ENTRY_OP_ENABLE = 2, /* Enable multi-cast group */ - RELMCAST_ENTRY_OP_ACK_ALL = 3 /* Enable ACK ALL bit in AMT */ -}; - -/* RMC operational modes */ -enum rmc_modes { - WL_RMC_MODE_RECEIVER = 0, /* Receiver mode by default */ - WL_RMC_MODE_TRANSMITTER = 1, /* Transmitter mode using wl ackreq */ - WL_RMC_MODE_INITIATOR = 2 /* Initiator mode using wl ackreq */ -}; - -/* Each RMC mcast client info */ -typedef struct wl_relmcast_client { - uint8 flag; /* status of client such as AR, R, or blacklisted */ - int16 rssi; /* rssi value of RMC client */ - struct ether_addr addr; /* mac address of RMC client */ -} wl_relmcast_client_t; - -/* RMC Counters */ -typedef struct wl_rmc_cnts { - uint16 version; /* see definition of WL_CNT_T_VERSION */ - uint16 length; /* length of entire structure */ - uint16 dupcnt; /* counter for duplicate rmc MPDU */ - uint16 ackreq_err; /* counter for wl ackreq error */ - uint16 af_tx_err; /* error count for action frame transmit */ - uint16 null_tx_err; /* error count for rmc null frame transmit */ - uint16 af_unicast_tx_err; /* error count for rmc unicast frame transmit */ - uint16 mc_no_amt_slot; /* No mcast AMT entry available */ - /* Unused. Keep for rom compatibility */ - uint16 mc_no_glb_slot; /* No mcast entry available in global table */ - uint16 mc_not_mirrored; /* mcast group is not mirrored */ - uint16 mc_existing_tr; /* mcast group is already taken by transmitter */ - uint16 mc_exist_in_amt; /* mcast group is already programmed in amt */ - /* Unused. Keep for rom compatibility */ - uint16 mc_not_exist_in_gbl; /* mcast group is not in global table */ - uint16 mc_not_exist_in_amt; /* mcast group is not in AMT table */ - uint16 mc_utilized; /* mcast addressed is already taken */ - uint16 mc_taken_other_tr; /* multi-cast addressed is already taken */ - uint32 rmc_rx_frames_mac; /* no of mc frames received from mac */ - uint32 rmc_tx_frames_mac; /* no of mc frames transmitted to mac */ - uint32 mc_null_ar_cnt; /* no. of times NULL AR is received */ - uint32 mc_ar_role_selected; /* no. of times took AR role */ - uint32 mc_ar_role_deleted; /* no. of times AR role cancelled */ - uint32 mc_noacktimer_expired; /* no. of times noack timer expired */ - uint16 mc_no_wl_clk; /* no wl clk detected when trying to access amt */ - uint16 mc_tr_cnt_exceeded; /* No of transmitters in the network exceeded */ -} wl_rmc_cnts_t; - -/* RMC Status */ -typedef struct wl_relmcast_st { - uint8 ver; /* version of RMC */ - uint8 num; /* number of clients detected by transmitter */ - wl_relmcast_client_t clients[WL_RMC_MAX_CLIENT]; - uint16 err; /* error status (used in infra) */ - uint16 actf_time; /* action frame time period */ -} wl_relmcast_status_t; - -/* Entry for each STA/node */ -typedef struct wl_rmc_entry { - /* operation on multi-cast entry such add, - * delete, ack-all - */ - int8 flag; - struct ether_addr addr; /* multi-cast group mac address */ -} wl_rmc_entry_t; - -/* RMC table */ -typedef struct wl_rmc_entry_table { - uint8 index; /* index to a particular mac entry in table */ - uint8 opcode; /* opcodes or operation on entry */ - wl_rmc_entry_t entry[WL_RMC_MAX_TABLE_ENTRY]; -} wl_rmc_entry_table_t; - -typedef struct wl_rmc_trans_elem { - struct ether_addr tr_mac; /* transmitter mac */ - struct ether_addr ar_mac; /* ar mac */ - uint16 artmo; /* AR timeout */ - uint8 amt_idx; /* amt table entry */ - uint16 flag; /* entry will be acked, not acked, programmed, full etc */ -} wl_rmc_trans_elem_t; - -/* RMC transmitters */ -typedef struct wl_rmc_trans_in_network { - uint8 ver; /* version of RMC */ - uint8 num_tr; /* number of transmitters in the network */ - wl_rmc_trans_elem_t trs[WL_RMC_MAX_NUM_TRS]; -} wl_rmc_trans_in_network_t; - -/* To update vendor specific ie for RMC */ -typedef struct wl_rmc_vsie { - uint8 oui[DOT11_OUI_LEN]; - uint16 payload; /* IE Data Payload */ -} wl_rmc_vsie_t; - - -/* structures & defines for proximity detection */ -enum proxd_method { - PROXD_UNDEFINED_METHOD = 0, - PROXD_RSSI_METHOD = 1, - PROXD_TOF_METHOD = 2 -}; - -/* structures for proximity detection device role */ -#define WL_PROXD_MODE_DISABLE 0 -#define WL_PROXD_MODE_NEUTRAL 1 -#define WL_PROXD_MODE_INITIATOR 2 -#define WL_PROXD_MODE_TARGET 3 - -#define WL_PROXD_ACTION_STOP 0 -#define WL_PROXD_ACTION_START 1 - -#define WL_PROXD_FLAG_TARGET_REPORT 0x1 -#define WL_PROXD_FLAG_REPORT_FAILURE 0x2 -#define WL_PROXD_FLAG_INITIATOR_REPORT 0x4 -#define WL_PROXD_FLAG_NOCHANSWT 0x8 -#define WL_PROXD_FLAG_NETRUAL 0x10 -#define WL_PROXD_FLAG_INITIATOR_RPTRTT 0x20 -#define WL_PROXD_FLAG_ONEWAY 0x40 -#define WL_PROXD_FLAG_SEQ_EN 0x80 - -#define WL_PROXD_RANDOM_WAKEUP 0x8000 - -typedef struct wl_proxd_iovar { - uint16 method; /* Proxmity Detection method */ - uint16 mode; /* Mode (neutral, initiator, target) */ -} wl_proxd_iovar_t; - -/* - * structures for proximity detection parameters - * consists of two parts, common and method specific params - * common params should be placed at the beginning - */ - -/* require strict packing */ -#include - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_common { - chanspec_t chanspec; /* channel spec */ - int16 tx_power; /* tx power of Proximity Detection(PD) frames (in dBm) */ - uint16 tx_rate; /* tx rate of PD rames (in 500kbps units) */ - uint16 timeout; /* timeout value */ - uint16 interval; /* interval between neighbor finding attempts (in TU) */ - uint16 duration; /* duration of neighbor finding attempts (in ms) */ -} BWL_POST_PACKED_STRUCT wl_proxd_params_common_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_rssi_method { - chanspec_t chanspec; /* chanspec for home channel */ - int16 tx_power; /* tx power of Proximity Detection frames (in dBm) */ - uint16 tx_rate; /* tx rate of PD frames, 500kbps units */ - uint16 timeout; /* state machine wait timeout of the frames (in ms) */ - uint16 interval; /* interval between neighbor finding attempts (in TU) */ - uint16 duration; /* duration of neighbor finding attempts (in ms) */ - /* method specific ones go after this line */ - int16 rssi_thresh; /* RSSI threshold (in dBm) */ - uint16 maxconvergtmo; /* max wait converge timeout (in ms) */ -} wl_proxd_params_rssi_method_t; - -#define Q1_NS 25 /* Q1 time units */ - -#define TOF_BW_NUM 3 /* number of bandwidth that the TOF can support */ -#define TOF_BW_SEQ_NUM (TOF_BW_NUM+2) /* number of total index */ -enum tof_bw_index { - TOF_BW_20MHZ_INDEX = 0, - TOF_BW_40MHZ_INDEX = 1, - TOF_BW_80MHZ_INDEX = 2, - TOF_BW_SEQTX_INDEX = 3, - TOF_BW_SEQRX_INDEX = 4 -}; - -#define BANDWIDTH_BASE 20 /* base value of bandwidth */ -#define TOF_BW_20MHZ (BANDWIDTH_BASE << TOF_BW_20MHZ_INDEX) -#define TOF_BW_40MHZ (BANDWIDTH_BASE << TOF_BW_40MHZ_INDEX) -#define TOF_BW_80MHZ (BANDWIDTH_BASE << TOF_BW_80MHZ_INDEX) -#define TOF_BW_10MHZ 10 - -#define NFFT_BASE 64 /* base size of fft */ -#define TOF_NFFT_20MHZ (NFFT_BASE << TOF_BW_20MHZ_INDEX) -#define TOF_NFFT_40MHZ (NFFT_BASE << TOF_BW_40MHZ_INDEX) -#define TOF_NFFT_80MHZ (NFFT_BASE << TOF_BW_80MHZ_INDEX) - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_method { - chanspec_t chanspec; /* chanspec for home channel */ - int16 tx_power; /* tx power of Proximity Detection(PD) frames (in dBm) */ - uint16 tx_rate; /* tx rate of PD rames (in 500kbps units) */ - uint16 timeout; /* state machine wait timeout of the frames (in ms) */ - uint16 interval; /* interval between neighbor finding attempts (in TU) */ - uint16 duration; /* duration of neighbor finding attempts (in ms) */ - /* specific for the method go after this line */ - struct ether_addr tgt_mac; /* target mac addr for TOF method */ - uint16 ftm_cnt; /* number of the frames txed by initiator */ - uint16 retry_cnt; /* number of retransmit attampts for ftm frames */ - int16 vht_rate; /* ht or vht rate */ - /* add more params required for other methods can be added here */ -} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_method_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_tune { - uint32 Ki; /* h/w delay K factor for initiator */ - uint32 Kt; /* h/w delay K factor for target */ - int16 vhtack; /* enable/disable VHT ACK */ - int16 N_log2[TOF_BW_SEQ_NUM]; /* simple threshold crossing */ - int16 w_offset[TOF_BW_NUM]; /* offset of threshold crossing window(per BW) */ - int16 w_len[TOF_BW_NUM]; /* length of threshold crossing window(per BW) */ - int32 maxDT; /* max time difference of T4/T1 or T3/T2 */ - int32 minDT; /* min time difference of T4/T1 or T3/T2 */ - uint8 totalfrmcnt; /* total count of transfered measurement frames */ - uint16 rsv_media; /* reserve media value for TOF */ - uint32 flags; /* flags */ - uint8 core; /* core to use for tx */ - uint8 force_K; /* set to force value of K */ - int16 N_scale[TOF_BW_SEQ_NUM]; /* simple threshold crossing */ - uint8 sw_adj; /* enable sw assisted timestamp adjustment */ - uint8 hw_adj; /* enable hw assisted timestamp adjustment */ - uint8 seq_en; /* enable ranging sequence */ - uint8 ftm_cnt[TOF_BW_SEQ_NUM]; /* number of ftm frames based on bandwidth */ -} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_tune_t; - -typedef struct wl_proxd_params_iovar { - uint16 method; /* Proxmity Detection method */ - union { - /* common params for pdsvc */ - wl_proxd_params_common_t cmn_params; /* common parameters */ - /* method specific */ - wl_proxd_params_rssi_method_t rssi_params; /* RSSI method parameters */ - wl_proxd_params_tof_method_t tof_params; /* TOF meothod parameters */ - /* tune parameters */ - wl_proxd_params_tof_tune_t tof_tune; /* TOF tune parameters */ - } u; /* Method specific optional parameters */ -} wl_proxd_params_iovar_t; - -#define PROXD_COLLECT_GET_STATUS 0 -#define PROXD_COLLECT_SET_STATUS 1 -#define PROXD_COLLECT_QUERY_HEADER 2 -#define PROXD_COLLECT_QUERY_DATA 3 -#define PROXD_COLLECT_QUERY_DEBUG 4 -#define PROXD_COLLECT_REMOTE_REQUEST 5 - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_query { - uint32 method; /* method */ - uint8 request; /* Query request. */ - uint8 status; /* 0 -- disable, 1 -- enable collection, */ - /* 2 -- enable collection & debug */ - uint16 index; /* The current frame index [0 to total_frames - 1]. */ - uint16 mode; /* Initiator or Target */ - bool busy; /* tof sm is busy */ - bool remote; /* Remote collect data */ -} BWL_POST_PACKED_STRUCT wl_proxd_collect_query_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_header { - uint16 total_frames; /* The totral frames for this collect. */ - uint16 nfft; /* nfft value */ - uint16 bandwidth; /* bandwidth */ - uint16 channel; /* channel number */ - uint32 chanspec; /* channel spec */ - uint32 fpfactor; /* avb timer value factor */ - uint16 fpfactor_shift; /* avb timer value shift bits */ - int32 distance; /* distance calculated by fw */ - uint32 meanrtt; /* mean of RTTs */ - uint32 modertt; /* mode of RTTs */ - uint32 medianrtt; /* median of RTTs */ - uint32 sdrtt; /* standard deviation of RTTs */ - uint32 clkdivisor; /* clock divisor */ - uint16 chipnum; /* chip type */ - uint8 chiprev; /* chip revision */ - uint8 phyver; /* phy version */ - struct ether_addr loaclMacAddr; /* local mac address */ - struct ether_addr remoteMacAddr; /* remote mac address */ - wl_proxd_params_tof_tune_t params; -} BWL_POST_PACKED_STRUCT wl_proxd_collect_header_t; - - -/* ********************** NAN wl interface struct types and defs ******************** */ - -#define WL_NAN_IOCTL_VERSION 0x1 -#define WL_P2P_NAN_IOCTL_VERSION 0x1 -#define P2P_NAN_IOC_BUFSZ 512 /* nan p2p ioctl buffer size */ -/* wl_nan_sub_cmd may also be used in dhd */ -typedef struct wl_nan_sub_cmd wl_nan_sub_cmd_t; -typedef int (cmd_handler_t)(void *wl, const wl_nan_sub_cmd_t *cmd, char **argv); -/* nan cmd list entry */ -struct wl_nan_sub_cmd { - char *name; - uint8 version; /* cmd version */ - uint16 id; /* id for the dongle f/w switch/case */ - uint16 type; /* base type of argument */ - cmd_handler_t *handler; /* cmd handler */ -}; -/* p2p nan cfg ioctls */ -enum wl_p2p_nan_cmds { - WL_P2P_NAN_CMD_ENABLE = 1, - WL_P2P_NAN_CMD_CONFIG = 2, - WL_P2P_NAN_CMD_DEL_CONFIG = 3 -}; -/* container for p2p nan iovtls & events */ -typedef BWL_PRE_PACKED_STRUCT struct wl_p2p_nan_ioc { - uint16 version; /* interface command or event version */ - uint16 id; /* p2p nan ioctl cmd ID */ - uint16 len; /* total length of data[] */ - uint8 data [1]; /* var len payload of bcm_xtlv_t type */ -} BWL_POST_PACKED_STRUCT wl_p2p_nan_ioc_t; - -/* container for nan iovtls & events */ -typedef BWL_PRE_PACKED_STRUCT struct wl_nan_ioc { - uint16 version; /* interface command or event version */ - uint16 id; /* nan ioctl cmd ID */ - uint16 len; /* total length of all tlv records in data[] */ - uint16 PAD; /* pad to be 32 bit aligment */ - uint8 data [1]; /* var len payload of bcm_xtlv_t type */ -} BWL_POST_PACKED_STRUCT wl_nan_ioc_t; - -typedef struct wl_nan_status { - uint8 inited; - uint8 joined; - uint8 role; - uint8 hop_count; - uint32 chspec; - uint8 amr[8]; /* Anchor Master Rank */ - uint32 cnt_pend_txfrm; /* pending TX frames */ - uint32 cnt_bcn_tx; /* TX disc/sync beacon count */ - uint32 cnt_bcn_rx; /* RX disc/sync beacon count */ - uint32 cnt_svc_disc_tx; /* TX svc disc frame count */ - uint32 cnt_svc_disc_rx; /* RX svc disc frame count */ - struct ether_addr cid; -} wl_nan_status_t; - -/* various params and ctl swithce for nan_debug instance */ -typedef struct nan_debug_params { - uint8 enabled; /* runtime debuging enabled */ - uint8 collect; /* enables debug svc sdf monitor mode */ - uint16 cmd; /* debug cmd to perform a debug action */ - uint32 msglevel; /* msg level if enabled */ - uint16 status; -} nan_debug_params_t; - - -/* nan passive scan params */ -#define NAN_SCAN_MAX_CHCNT 8 -typedef BWL_PRE_PACKED_STRUCT struct nan_scan_params { - uint16 scan_time; - uint16 home_time; - uint16 ms_intvl; /* interval between merge scan */ - uint16 ms_dur; /* duration of merge scan */ - uint16 chspec_num; - uint8 PAD[2]; /* pad to make 4 byte alignment */ - chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /* act. used 3, 5 rfu */ -} BWL_POST_PACKED_STRUCT nan_scan_params_t; - -enum wl_nan_role { - WL_NAN_ROLE_AUTO = 0, - WL_NAN_ROLE_NON_MASTER_NON_SYNC = 1, - WL_NAN_ROLE_NON_MASTER_SYNC = 2, - WL_NAN_ROLE_MASTER = 3, - WL_NAN_ROLE_ANCHOR_MASTER = 4 -}; -#define NAN_MASTER_RANK_LEN 8 -/* nan cmd IDs */ -enum wl_nan_cmds { - /* nan cfg /disc & dbg ioctls */ - WL_NAN_CMD_ENABLE = 1, - WL_NAN_CMD_ATTR = 2, - WL_NAN_CMD_NAN_JOIN = 3, - WL_NAN_CMD_LEAVE = 4, - WL_NAN_CMD_MERGE = 5, - WL_NAN_CMD_STATUS = 6, - /* discovery engine commands */ - WL_NAN_CMD_PUBLISH = 20, - WL_NAN_CMD_SUBSCRIBE = 21, - WL_NAN_CMD_CANCEL_PUBLISH = 22, - WL_NAN_CMD_CANCEL_SUBSCRIBE = 23, - WL_NAN_CMD_TRANSMIT = 24, - WL_NAN_CMD_CONNECTION = 25, - WL_NAN_CMD_SHOW = 26, - WL_NAN_CMD_STOP = 27, /* stop nan for a given cluster ID */ - /* nan debug iovars & cmds */ - WL_NAN_CMD_SCAN_PARAMS = 46, - WL_NAN_CMD_SCAN = 47, - WL_NAN_CMD_SCAN_RESULTS = 48, - WL_NAN_CMD_EVENT_MASK = 49, - WL_NAN_CMD_EVENT_CHECK = 50, - - WL_NAN_CMD_DEBUG = 60, - WL_NAN_CMD_TEST1 = 61, - WL_NAN_CMD_TEST2 = 62, - WL_NAN_CMD_TEST3 = 63 -}; - -/* - * tlv IDs uniquely identifies cmd parameters - * packed into wl_nan_ioc_t container - */ -enum wl_nan_cmd_xtlv_id { - /* 0x00 ~ 0xFF: standard TLV ID whose data format is the same as NAN attribute TLV */ - WL_NAN_XTLV_ZERO = 0, /* used as tlv buf end marker */ -#ifdef NAN_STD_TLV /* rfu, don't use yet */ - WL_NAN_XTLV_MASTER_IND = 1, /* == NAN_ATTR_MASTER_IND, */ - WL_NAN_XTLV_CLUSTER = 2, /* == NAN_ATTR_CLUSTER, */ - WL_NAN_XTLV_VENDOR = 221, /* == NAN_ATTR_VENDOR, */ -#endif - /* 0x02 ~ 0xFF: reserved. In case to use with the same data format as NAN attribute TLV */ - /* 0x100 ~ : private TLV ID defined just for NAN command */ - /* common types */ - WL_NAN_XTLV_BUFFER = 0x101, /* generic type, function depends on cmd context */ - WL_NAN_XTLV_MAC_ADDR = 0x102, /* used in various cmds */ - WL_NAN_XTLV_REASON = 0x103, - WL_NAN_XTLV_ENABLE = 0x104, - /* explicit types, primarily for discovery engine iovars */ - WL_NAN_XTLV_SVC_PARAMS = 0x120, /* Contains required params: wl_nan_disc_params_t */ - WL_NAN_XTLV_MATCH_RX = 0x121, /* Matching filter to evaluate on receive */ - WL_NAN_XTLV_MATCH_TX = 0x122, /* Matching filter to send */ - WL_NAN_XTLV_SVC_INFO = 0x123, /* Service specific info */ - WL_NAN_XTLV_SVC_NAME = 0x124, /* Optional UTF-8 service name, for debugging. */ - WL_NAN_XTLV_INSTANCE_ID = 0x125, /* Identifies unique publish or subscribe instance */ - WL_NAN_XTLV_PRIORITY = 0x126, /* used in transmit cmd context */ - WL_NAN_XTLV_REQUESTOR_ID = 0x127, /* Requestor instance ID */ - WL_NAN_XTLV_VNDR = 0x128, /* Vendor specific attribute */ - WL_NAN_XTLV_PEER_INSTANCE_ID = 0x131, /* Used to parse remote instance Id */ - /* explicit types, primarily for NAN MAC iovars */ - WL_NAN_XTLV_DW_LEN = 0x140, /* discovery win length */ - WL_NAN_XTLV_BCN_INTERVAL = 0x141, /* beacon interval, both sync and descovery bcns? */ - WL_NAN_XTLV_CLUSTER_ID = 0x142, - WL_NAN_XTLV_IF_ADDR = 0x143, - WL_NAN_XTLV_MC_ADDR = 0x144, - WL_NAN_XTLV_ROLE = 0x145, - WL_NAN_XTLV_START = 0x146, - - WL_NAN_XTLV_MASTER_PREF = 0x147, - WL_NAN_XTLV_DW_INTERVAL = 0x148, - WL_NAN_XTLV_PTBTT_OVERRIDE = 0x149, - /* nan status command xtlvs */ - WL_NAN_XTLV_MAC_INITED = 0x14a, - WL_NAN_XTLV_MAC_ENABLED = 0x14b, - WL_NAN_XTLV_MAC_CHANSPEC = 0x14c, - WL_NAN_XTLV_MAC_AMR = 0x14d, /* anchormaster rank u8 amr[8] */ - WL_NAN_XTLV_MAC_HOPCNT = 0x14e, - WL_NAN_XTLV_MAC_AMBTT = 0x14f, - WL_NAN_XTLV_MAC_TXRATE = 0x150, - WL_NAN_XTLV_MAC_STATUS = 0x151, /* xtlv payload is nan_status_t */ - WL_NAN_XTLV_NAN_SCANPARAMS = 0x152, /* payload is nan_scan_params_t */ - WL_NAN_XTLV_DEBUGPARAMS = 0x153, /* payload is nan_scan_params_t */ - WL_NAN_XTLV_SUBSCR_ID = 0x154, /* subscriber id */ - WL_NAN_XTLV_PUBLR_ID = 0x155, /* publisher id */ - WL_NAN_XTLV_EVENT_MASK = 0x156, - WL_NAN_XTLV_MERGE = 0x157 -}; - -/* Flag bits for Publish and Subscribe (wl_nan_disc_params_t flags) */ -#define WL_NAN_RANGE_LIMITED 0x0040 -/* Bits specific to Publish */ -/* Unsolicited transmissions */ -#define WL_NAN_PUB_UNSOLICIT 0x1000 -/* Solicited transmissions */ -#define WL_NAN_PUB_SOLICIT 0x2000 -#define WL_NAN_PUB_BOTH 0x3000 -/* Set for broadcast solicited transmission - * Do not set for unicast solicited transmission - */ -#define WL_NAN_PUB_BCAST 0x4000 -/* Generate event on each solicited transmission */ -#define WL_NAN_PUB_EVENT 0x8000 -/* Used for one-time solicited Publish functions to indicate transmision occurred */ -#define WL_NAN_PUB_SOLICIT_PENDING 0x10000 -/* Follow-up frames */ -#define WL_NAN_FOLLOWUP 0x20000 -/* Bits specific to Subscribe */ -/* Active subscribe mode (Leave unset for passive) */ -#define WL_NAN_SUB_ACTIVE 0x1000 - -/* Special values for time to live (ttl) parameter */ -#define WL_NAN_TTL_UNTIL_CANCEL 0xFFFFFFFF -/* Publish - runs until first transmission - * Subscribe - runs until first DiscoveryResult event - */ -#define WL_NAN_TTL_FIRST 0 - -/* The service hash (service id) is exactly this many bytes. */ -#define WL_NAN_SVC_HASH_LEN 6 - -/* Instance ID type (unique identifier) */ -typedef uint8 wl_nan_instance_id_t; - -/* Mandatory parameters for publish/subscribe iovars - NAN_TLV_SVC_PARAMS */ -typedef struct wl_nan_disc_params_s { - /* Periodicity of unsolicited/query transmissions, in DWs */ - uint32 period; - /* Time to live in DWs */ - uint32 ttl; - /* Flag bits */ - uint32 flags; - /* Publish or subscribe service id, i.e. hash of the service name */ - uint8 svc_hash[WL_NAN_SVC_HASH_LEN]; - /* pad to make 4 byte alignment, can be used for something else in the future */ - uint8 PAD; - /* Publish or subscribe id */ - wl_nan_instance_id_t instance_id; -} wl_nan_disc_params_t; - -/* -* desovery interface event structures * -*/ - -/* NAN Ranging */ - -/* Bit defines for global flags */ -#define WL_NAN_RANGING_ENABLE 1 /* enable RTT */ -#define WL_NAN_RANGING_RANGED 2 /* Report to host if ranged as target */ -typedef struct nan_ranging_config { - uint32 chanspec; /* Ranging chanspec */ - uint16 timeslot; /* NAN RTT start time slot 1-511 */ - uint16 duration; /* NAN RTT duration in ms */ - struct ether_addr allow_mac; /* peer initiated ranging: the allowed peer mac - * address, a unicast (for one peer) or - * a broadcast for all. Setting it to all zeros - * means responding to none,same as not setting - * the flag bit NAN_RANGING_RESPOND - */ - uint16 flags; -} wl_nan_ranging_config_t; - -/* list of peers for self initiated ranging */ -/* Bit defines for per peer flags */ -#define WL_NAN_RANGING_REPORT (1<<0) /* Enable reporting range to target */ -typedef struct nan_ranging_peer { - uint32 chanspec; /* desired chanspec for this peer */ - uint32 abitmap; /* available bitmap */ - struct ether_addr ea; /* peer MAC address */ - uint8 frmcnt; /* frame count */ - uint8 retrycnt; /* retry count */ - uint16 flags; /* per peer flags, report or not */ -} wl_nan_ranging_peer_t; -typedef struct nan_ranging_list { - uint8 count; /* number of MAC addresses */ - uint8 num_peers_done; /* host set to 0, when read, shows number of peers - * completed, success or fail - */ - uint8 num_dws; /* time period to do the ranging, specified in dws */ - uint8 reserve; /* reserved field */ - wl_nan_ranging_peer_t rp[1]; /* variable length array of peers */ -} wl_nan_ranging_list_t; - -/* ranging results, a list for self initiated ranging and one for peer initiated ranging */ -/* There will be one structure for each peer */ -#define WL_NAN_RANGING_STATUS_SUCCESS 1 -#define WL_NAN_RANGING_STATUS_FAIL 2 -#define WL_NAN_RANGING_STATUS_TIMEOUT 3 -#define WL_NAN_RANGING_STATUS_ABORT 4 /* with partial results if sounding count > 0 */ -typedef struct nan_ranging_result { - uint8 status; /* 1: Success, 2: Fail 3: Timeout 4: Aborted */ - uint8 sounding_count; /* number of measurements completed (0 = failure) */ - struct ether_addr ea; /* initiator MAC address */ - uint32 chanspec; /* Chanspec where the ranging was done */ - uint32 timestamp; /* 32bits of the TSF timestamp ranging was completed at */ - uint32 distance; /* mean distance in meters expressed as Q4 number. - * Only valid when sounding_count > 0. Examples: - * 0x08 = 0.5m - * 0x10 = 1m - * 0x18 = 1.5m - * set to 0xffffffff to indicate invalid number - */ - int32 rtt_var; /* standard deviation in 10th of ns of RTTs measured. - * Only valid when sounding_count > 0 - */ - struct ether_addr tgtea; /* target MAC address */ -} wl_nan_ranging_result_t; -typedef struct nan_ranging_event_data { - uint8 mode; /* 1: Result of host initiated ranging */ - /* 2: Result of peer initiated ranging */ - uint8 reserved; - uint8 success_count; /* number of peers completed successfully */ - uint8 count; /* number of peers in the list */ - wl_nan_ranging_result_t rr[1]; /* variable array of ranging peers */ -} wl_nan_ranging_event_data_t; - -#define WL_P2P_NAN_CONFIG_VERSION 1 - -typedef struct p2p_nan_config { - uint16 version; /* wl_p2p_nan_config_t structure version */ - uint16 len; /* total length */ - uint8 map_ctrl; /* Map control information */ - uint8 dev_role; /* Device role: Table 5-18: dev_role is 1 octet */ - uint16 ie_len; /* variable ie len */ - struct ether_addr mac; /* Mac address based on device role */ - uint32 avail_bmap; /* availability interval bitmap */ - uint8 ie[1]; /* hex ie data */ -} wl_p2p_nan_config_t; - -/* ********************* end of NAN section ******************************** */ - - -#define RSSI_THRESHOLD_SIZE 16 -#define MAX_IMP_RESP_SIZE 256 - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_rssi_bias { - int32 version; /* version */ - int32 threshold[RSSI_THRESHOLD_SIZE]; /* threshold */ - int32 peak_offset; /* peak offset */ - int32 bias; /* rssi bias */ - int32 gd_delta; /* GD - GD_ADJ */ - int32 imp_resp[MAX_IMP_RESP_SIZE]; /* (Hi*Hi)+(Hr*Hr) */ -} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_rssi_bias_avg { - int32 avg_threshold[RSSI_THRESHOLD_SIZE]; /* avg threshold */ - int32 avg_peak_offset; /* avg peak offset */ - int32 avg_rssi; /* avg rssi */ - int32 avg_bias; /* avg bias */ -} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_avg_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_info { - uint16 type; /* type: 0 channel table, 1 channel smoothing table, 2 and 3 seq */ - uint16 index; /* The current frame index, from 1 to total_frames. */ - uint16 tof_cmd; /* M_TOF_CMD */ - uint16 tof_rsp; /* M_TOF_RSP */ - uint16 tof_avb_rxl; /* M_TOF_AVB_RX_L */ - uint16 tof_avb_rxh; /* M_TOF_AVB_RX_H */ - uint16 tof_avb_txl; /* M_TOF_AVB_TX_L */ - uint16 tof_avb_txh; /* M_TOF_AVB_TX_H */ - uint16 tof_id; /* M_TOF_ID */ - uint8 tof_frame_type; - uint8 tof_frame_bw; - int8 tof_rssi; - int32 tof_cfo; - int32 gd_adj_ns; /* gound delay */ - int32 gd_h_adj_ns; /* group delay + threshold crossing */ -#ifdef RSSI_REFINE - wl_proxd_rssi_bias_t rssi_bias; /* RSSI refinement info */ -#endif - int16 nfft; /* number of samples stored in H */ - -} BWL_POST_PACKED_STRUCT wl_proxd_collect_info_t; - -#define k_tof_collect_H_pad 1 -#define k_tof_collect_H_size (256+16+k_tof_collect_H_pad) -#define k_tof_collect_Hraw_size (2*k_tof_collect_H_size) -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_data { - wl_proxd_collect_info_t info; - uint32 H[k_tof_collect_H_size]; /* raw data read from phy used to adjust timestamps */ - -} BWL_POST_PACKED_STRUCT wl_proxd_collect_data_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_debug_data { - uint8 count; /* number of packets */ - uint8 stage; /* state machone stage */ - uint8 received; /* received or txed */ - uint8 paket_type; /* packet type */ - uint8 category; /* category field */ - uint8 action; /* action field */ - uint8 token; /* token number */ - uint8 follow_token; /* following token number */ - uint16 index; /* index of the packet */ - uint16 tof_cmd; /* M_TOF_CMD */ - uint16 tof_rsp; /* M_TOF_RSP */ - uint16 tof_avb_rxl; /* M_TOF_AVB_RX_L */ - uint16 tof_avb_rxh; /* M_TOF_AVB_RX_H */ - uint16 tof_avb_txl; /* M_TOF_AVB_TX_L */ - uint16 tof_avb_txh; /* M_TOF_AVB_TX_H */ - uint16 tof_id; /* M_TOF_ID */ - uint16 tof_status0; /* M_TOF_STATUS_0 */ - uint16 tof_status2; /* M_TOF_STATUS_2 */ - uint16 tof_chsm0; /* M_TOF_CHNSM_0 */ - uint16 tof_phyctl0; /* M_TOF_PHYCTL0 */ - uint16 tof_phyctl1; /* M_TOF_PHYCTL1 */ - uint16 tof_phyctl2; /* M_TOF_PHYCTL2 */ - uint16 tof_lsig; /* M_TOF_LSIG */ - uint16 tof_vhta0; /* M_TOF_VHTA0 */ - uint16 tof_vhta1; /* M_TOF_VHTA1 */ - uint16 tof_vhta2; /* M_TOF_VHTA2 */ - uint16 tof_vhtb0; /* M_TOF_VHTB0 */ - uint16 tof_vhtb1; /* M_TOF_VHTB1 */ - uint16 tof_apmductl; /* M_TOF_AMPDU_CTL */ - uint16 tof_apmdudlim; /* M_TOF_AMPDU_DLIM */ - uint16 tof_apmdulen; /* M_TOF_AMPDU_LEN */ -} BWL_POST_PACKED_STRUCT wl_proxd_debug_data_t; - -/* version of the wl_wsec_info structure */ -#define WL_WSEC_INFO_VERSION 0x01 - -/* start enum value for BSS properties */ -#define WL_WSEC_INFO_BSS_BASE 0x0100 - -/* size of len and type fields of wl_wsec_info_tlv_t struct */ -#define WL_WSEC_INFO_TLV_HDR_LEN OFFSETOF(wl_wsec_info_tlv_t, data) - -/* Allowed wl_wsec_info properties; not all of them may be supported. */ -typedef enum { - WL_WSEC_INFO_NONE = 0, - WL_WSEC_INFO_MAX_KEYS = 1, - WL_WSEC_INFO_NUM_KEYS = 2, - WL_WSEC_INFO_NUM_HW_KEYS = 3, - WL_WSEC_INFO_MAX_KEY_IDX = 4, - WL_WSEC_INFO_NUM_REPLAY_CNTRS = 5, - WL_WSEC_INFO_SUPPORTED_ALGOS = 6, - WL_WSEC_INFO_MAX_KEY_LEN = 7, - WL_WSEC_INFO_FLAGS = 8, - /* add global/per-wlc properties above */ - WL_WSEC_INFO_BSS_FLAGS = (WL_WSEC_INFO_BSS_BASE + 1), - WL_WSEC_INFO_BSS_WSEC = (WL_WSEC_INFO_BSS_BASE + 2), - WL_WSEC_INFO_BSS_TX_KEY_ID = (WL_WSEC_INFO_BSS_BASE + 3), - WL_WSEC_INFO_BSS_ALGO = (WL_WSEC_INFO_BSS_BASE + 4), - WL_WSEC_INFO_BSS_KEY_LEN = (WL_WSEC_INFO_BSS_BASE + 5), - /* add per-BSS properties above */ - WL_WSEC_INFO_MAX = 0xffff -} wl_wsec_info_type_t; - -/* tlv used to return wl_wsec_info properties */ -typedef struct { - uint16 type; - uint16 len; /* data length */ - uint8 data[1]; /* data follows */ -} wl_wsec_info_tlv_t; - -/* input/output data type for wsec_info iovar */ -typedef struct wl_wsec_info { - uint8 version; /* structure version */ - uint8 pad[2]; - uint8 num_tlvs; - wl_wsec_info_tlv_t tlvs[1]; /* tlv data follows */ -} wl_wsec_info_t; - -/* no default structure packing */ -#include - -enum rssi_reason { - RSSI_REASON_UNKNOW = 0, - RSSI_REASON_LOWRSSI = 1, - RSSI_REASON_NSYC = 2, - RSSI_REASON_TIMEOUT = 3 -}; - -enum tof_reason { - TOF_REASON_OK = 0, - TOF_REASON_REQEND = 1, - TOF_REASON_TIMEOUT = 2, - TOF_REASON_NOACK = 3, - TOF_REASON_INVALIDAVB = 4, - TOF_REASON_INITIAL = 5, - TOF_REASON_ABORT = 6 -}; - -enum rssi_state { - RSSI_STATE_POLL = 0, - RSSI_STATE_TPAIRING = 1, - RSSI_STATE_IPAIRING = 2, - RSSI_STATE_THANDSHAKE = 3, - RSSI_STATE_IHANDSHAKE = 4, - RSSI_STATE_CONFIRMED = 5, - RSSI_STATE_PIPELINE = 6, - RSSI_STATE_NEGMODE = 7, - RSSI_STATE_MONITOR = 8, - RSSI_STATE_LAST = 9 -}; - -enum tof_state { - TOF_STATE_IDLE = 0, - TOF_STATE_IWAITM = 1, - TOF_STATE_TWAITM = 2, - TOF_STATE_ILEGACY = 3, - TOF_STATE_IWAITCL = 4, - TOF_STATE_TWAITCL = 5, - TOF_STATE_ICONFIRM = 6, - TOF_STATE_IREPORT = 7 -}; - -enum tof_mode_type { - TOF_LEGACY_UNKNOWN = 0, - TOF_LEGACY_AP = 1, - TOF_NONLEGACY_AP = 2 -}; - -enum tof_way_type { - TOF_TYPE_ONE_WAY = 0, - TOF_TYPE_TWO_WAY = 1, - TOF_TYPE_REPORT = 2 -}; - -enum tof_rate_type { - TOF_FRAME_RATE_VHT = 0, - TOF_FRAME_RATE_LEGACY = 1 -}; - -#define TOF_ADJ_TYPE_NUM 4 /* number of assisted timestamp adjustment */ -enum tof_adj_mode { - TOF_ADJ_SOFTWARE = 0, - TOF_ADJ_HARDWARE = 1, - TOF_ADJ_SEQ = 2, - TOF_ADJ_NONE = 3 -}; - -#define FRAME_TYPE_NUM 4 /* number of frame type */ -enum frame_type { - FRAME_TYPE_CCK = 0, - FRAME_TYPE_OFDM = 1, - FRAME_TYPE_11N = 2, - FRAME_TYPE_11AC = 3 -}; - -typedef struct wl_proxd_status_iovar { - uint16 method; /* method */ - uint8 mode; /* mode */ - uint8 peermode; /* peer mode */ - uint8 state; /* state */ - uint8 reason; /* reason code */ - uint32 distance; /* distance */ - uint32 txcnt; /* tx pkt counter */ - uint32 rxcnt; /* rx pkt counter */ - struct ether_addr peer; /* peer mac address */ - int8 avg_rssi; /* average rssi */ - int8 hi_rssi; /* highest rssi */ - int8 low_rssi; /* lowest rssi */ - uint32 dbgstatus; /* debug status */ - uint16 frame_type_cnt[FRAME_TYPE_NUM]; /* frame types */ - uint8 adj_type_cnt[TOF_ADJ_TYPE_NUM]; /* adj types HW/SW */ -} wl_proxd_status_iovar_t; - -#ifdef NET_DETECT -typedef struct net_detect_adapter_features { - bool wowl_enabled; - bool net_detect_enabled; - bool nlo_enabled; -} net_detect_adapter_features_t; - -typedef enum net_detect_bss_type { - nd_bss_any = 0, - nd_ibss, - nd_ess -} net_detect_bss_type_t; - -typedef struct net_detect_profile { - wlc_ssid_t ssid; - net_detect_bss_type_t bss_type; /* Ignore for now since Phase 1 is only for ESS */ - uint32 cipher_type; /* DOT11_CIPHER_ALGORITHM enumeration values */ - uint32 auth_type; /* DOT11_AUTH_ALGORITHM enumeration values */ -} net_detect_profile_t; - -typedef struct net_detect_profile_list { - uint32 num_nd_profiles; - net_detect_profile_t nd_profile[0]; -} net_detect_profile_list_t; - -typedef struct net_detect_config { - bool nd_enabled; - uint32 scan_interval; - uint32 wait_period; - bool wake_if_connected; - bool wake_if_disconnected; - net_detect_profile_list_t nd_profile_list; -} net_detect_config_t; - -typedef enum net_detect_wake_reason { - nd_reason_unknown, - nd_net_detected, - nd_wowl_event, - nd_ucode_error -} net_detect_wake_reason_t; - -typedef struct net_detect_wake_data { - net_detect_wake_reason_t nd_wake_reason; - uint32 nd_wake_date_length; - uint8 nd_wake_data[0]; /* Wake data (currently unused) */ -} net_detect_wake_data_t; - -#endif /* NET_DETECT */ - -typedef struct bcnreq { - uint8 bcn_mode; - int dur; - int channel; - struct ether_addr da; - uint16 random_int; - wlc_ssid_t ssid; - uint16 reps; -} bcnreq_t; - -typedef struct rrmreq { - struct ether_addr da; - uint8 reg; - uint8 chan; - uint16 random_int; - uint16 dur; - uint16 reps; -} rrmreq_t; - -typedef struct framereq { - struct ether_addr da; - uint8 reg; - uint8 chan; - uint16 random_int; - uint16 dur; - struct ether_addr ta; - uint16 reps; -} framereq_t; - -typedef struct statreq { - struct ether_addr da; - struct ether_addr peer; - uint16 random_int; - uint16 dur; - uint8 group_id; - uint16 reps; -} statreq_t; - -#define WL_RRM_RPT_VER 0 -#define WL_RRM_RPT_MAX_PAYLOAD 64 -#define WL_RRM_RPT_MIN_PAYLOAD 7 -#define WL_RRM_RPT_FALG_ERR 0 -#define WL_RRM_RPT_FALG_OK 1 -typedef struct { - uint16 ver; /* version */ - struct ether_addr addr; /* STA MAC addr */ - uint32 timestamp; /* timestamp of the report */ - uint16 flag; /* flag */ - uint16 len; /* length of payload data */ - unsigned char data[WL_RRM_RPT_MAX_PAYLOAD]; -} statrpt_t; - -typedef struct wlc_l2keepalive_ol_params { - uint8 flags; - uint8 prio; - uint16 period_ms; -} wlc_l2keepalive_ol_params_t; - -typedef struct wlc_dwds_config { - uint32 enable; - uint32 mode; /* STA/AP interface */ - struct ether_addr ea; -} wlc_dwds_config_t; - -typedef struct wl_el_set_params_s { - uint8 set; /* Set number */ - uint32 size; /* Size to make/expand */ -} wl_el_set_params_t; - -typedef struct wl_el_tag_params_s { - uint16 tag; - uint8 set; - uint8 flags; -} wl_el_tag_params_t; - -/* Video Traffic Interference Monitor config */ -#define INTFER_VERSION 1 -typedef struct wl_intfer_params { - uint16 version; /* version */ - uint8 period; /* sample period */ - uint8 cnt; /* sample cnt */ - uint8 txfail_thresh; /* non-TCP txfail threshold */ - uint8 tcptxfail_thresh; /* tcptxfail threshold */ -} wl_intfer_params_t; - -typedef struct wl_staprio_cfg { - struct ether_addr ea; /* mac addr */ - uint8 prio; /* scb priority */ -} wl_staprio_cfg_t; - -typedef enum wl_stamon_cfg_cmd_type { - STAMON_CFG_CMD_DEL = 0, - STAMON_CFG_CMD_ADD = 1 -} wl_stamon_cfg_cmd_type_t; - -typedef struct wlc_stamon_sta_config { - wl_stamon_cfg_cmd_type_t cmd; /* 0 - delete, 1 - add */ - struct ether_addr ea; -} wlc_stamon_sta_config_t; - -#ifdef SR_DEBUG -typedef struct /* pmu_reg */{ - uint32 pmu_control; - uint32 pmu_capabilities; - uint32 pmu_status; - uint32 res_state; - uint32 res_pending; - uint32 pmu_timer1; - uint32 min_res_mask; - uint32 max_res_mask; - uint32 pmu_chipcontrol1[4]; - uint32 pmu_regcontrol[5]; - uint32 pmu_pllcontrol[5]; - uint32 pmu_rsrc_up_down_timer[31]; - uint32 rsrc_dep_mask[31]; -} pmu_reg_t; -#endif /* pmu_reg */ - -typedef struct wl_taf_define { - struct ether_addr ea; /* STA MAC or 0xFF... */ - uint16 version; /* version */ - uint32 sch; /* method index */ - uint32 prio; /* priority */ - uint32 misc; /* used for return value */ - char text[1]; /* used to pass and return ascii text */ -} wl_taf_define_t; - -/* Received Beacons lengths information */ -#define WL_LAST_BCNS_INFO_FIXED_LEN OFFSETOF(wlc_bcn_len_hist_t, bcnlen_ring) -typedef struct wlc_bcn_len_hist { - uint16 ver; /* version field */ - uint16 cur_index; /* current pointed index in ring buffer */ - uint32 max_bcnlen; /* Max beacon length received */ - uint32 min_bcnlen; /* Min beacon length received */ - uint32 ringbuff_len; /* Length of the ring buffer 'bcnlen_ring' */ - uint32 bcnlen_ring[1]; /* ring buffer storing received beacon lengths */ -} wlc_bcn_len_hist_t; - -/* WDS net interface types */ -#define WL_WDSIFTYPE_NONE 0x0 /* The interface type is neither WDS nor DWDS. */ -#define WL_WDSIFTYPE_WDS 0x1 /* The interface is WDS type. */ -#define WL_WDSIFTYPE_DWDS 0x2 /* The interface is DWDS type. */ - -typedef struct wl_bssload_static { - bool is_static; - uint16 sta_count; - uint8 chan_util; - uint16 aac; -} wl_bssload_static_t; - - -/* LTE coex info */ -/* Analogue of HCI Set MWS Signaling cmd */ -typedef struct { - uint16 mws_rx_assert_offset; - uint16 mws_rx_assert_jitter; - uint16 mws_rx_deassert_offset; - uint16 mws_rx_deassert_jitter; - uint16 mws_tx_assert_offset; - uint16 mws_tx_assert_jitter; - uint16 mws_tx_deassert_offset; - uint16 mws_tx_deassert_jitter; - uint16 mws_pattern_assert_offset; - uint16 mws_pattern_assert_jitter; - uint16 mws_inact_dur_assert_offset; - uint16 mws_inact_dur_assert_jitter; - uint16 mws_scan_freq_assert_offset; - uint16 mws_scan_freq_assert_jitter; - uint16 mws_prio_assert_offset_req; -} wci2_config_t; - -/* Analogue of HCI MWS Channel Params */ -typedef struct { - uint16 mws_rx_center_freq; /* MHz */ - uint16 mws_tx_center_freq; - uint16 mws_rx_channel_bw; /* KHz */ - uint16 mws_tx_channel_bw; - uint8 mws_channel_en; - uint8 mws_channel_type; /* Don't care for WLAN? */ -} mws_params_t; - -/* MWS wci2 message */ -typedef struct { - uint8 mws_wci2_data; /* BT-SIG msg */ - uint16 mws_wci2_interval; /* Interval in us */ - uint16 mws_wci2_repeat; /* No of msgs to send */ -} mws_wci2_msg_t; - -typedef struct { - uint32 config; /* MODE: AUTO (-1), Disable (0), Enable (1) */ - uint32 status; /* Current state: Disabled (0), Enabled (1) */ -} wl_config_t; - -#define WLC_RSDB_MODE_AUTO_MASK 0x80 -#define WLC_RSDB_EXTRACT_MODE(val) ((int8)((val) & (~(WLC_RSDB_MODE_AUTO_MASK)))) - -#define WL_IF_STATS_T_VERSION 1 /* current version of wl_if_stats structure */ - -/* per interface counters */ -typedef struct wl_if_stats { - uint16 version; /* version of the structure */ - uint16 length; /* length of the entire structure */ - uint32 PAD; /* padding */ - - /* transmit stat counters */ - uint64 txframe; /* tx data frames */ - uint64 txbyte; /* tx data bytes */ - uint64 txerror; /* tx data errors (derived: sum of others) */ - uint64 txnobuf; /* tx out of buffer errors */ - uint64 txrunt; /* tx runt frames */ - uint64 txfail; /* tx failed frames */ - uint64 txretry; /* tx retry frames */ - uint64 txretrie; /* tx multiple retry frames */ - uint64 txfrmsnt; /* tx sent frames */ - uint64 txmulti; /* tx mulitcast sent frames */ - uint64 txfrag; /* tx fragments sent */ - - /* receive stat counters */ - uint64 rxframe; /* rx data frames */ - uint64 rxbyte; /* rx data bytes */ - uint64 rxerror; /* rx data errors (derived: sum of others) */ - uint64 rxnobuf; /* rx out of buffer errors */ - uint64 rxrunt; /* rx runt frames */ - uint64 rxfragerr; /* rx fragment errors */ - uint64 rxmulti; /* rx multicast frames */ - - uint64 txexptime; /* DATA Tx frames suppressed due to timer expiration */ - uint64 txrts; /* RTS/CTS succeeeded count */ - uint64 txnocts; /* RTS/CTS faled count */ -} -wl_if_stats_t; - -typedef struct wl_band { - uint16 bandtype; /* WL_BAND_2G, WL_BAND_5G */ - uint16 bandunit; /* bandstate[] index */ - uint16 phytype; /* phytype */ - uint16 phyrev; -} -wl_band_t; - -#define WL_WLC_VERSION_T_VERSION 1 /* current version of wlc_version structure */ - -/* wlc interface version */ -typedef struct wl_wlc_version { - uint16 version; /* version of the structure */ - uint16 length; /* length of the entire structure */ - - /* epi version numbers */ - uint16 epi_ver_major; /* epi major version number */ - uint16 epi_ver_minor; /* epi minor version number */ - uint16 epi_rc_num; /* epi RC number */ - uint16 epi_incr_num; /* epi increment number */ - - /* wlc interface version numbers */ - uint16 wlc_ver_major; /* wlc interface major version number */ - uint16 wlc_ver_minor; /* wlc interface minor version number */ -} -wl_wlc_version_t; - -/* Version of WLC interface to be returned as a part of wl_wlc_version structure. - * For the discussion related to versions update policy refer to - * http://hwnbu-twiki.broadcom.com/bin/view/Mwgroup/WlShimAbstractionLayer - * For now the policy is to increment WLC_VERSION_MAJOR each time - * there is a change that involves both WLC layer and per-port layer. - * WLC_VERSION_MINOR is currently not in use. - */ -#define WLC_VERSION_MAJOR 3 -#define WLC_VERSION_MINOR 0 - - -/* require strict packing */ -#include -#define WL_PROXD_API_VERSION 0x0300 /* version 3.0 */ - -/* proximity detection methods */ -enum { - WL_PROXD_METHOD_NONE = 0, - WL_PROXD_METHOD_RSVD1 = 1, /* backward compatibility - RSSI, not supported */ - WL_PROXD_METHOD_TOF = 2, /* 11v+BCM proprietary */ - WL_PROXD_METHOD_RSVD2 = 3, /* 11v only - if needed */ - WL_PROXD_METHOD_FTM = 4, /* IEEE rev mc/2014 */ - WL_PROXD_METHOD_MAX -}; -typedef int16 wl_proxd_method_t; - -/* global and method configuration flags */ -enum { - WL_PROXD_FLAG_NONE = 0x00000000, - WL_PROXD_FLAG_RX_ENABLED = 0x00000001, /* respond to requests */ - WL_PROXD_FLAG_RX_RANGE_REQ = 0x00000002, /* 11mc range requests enabled */ - WL_PROXD_FLAG_TX_LCI = 0x00000004, /* transmit location, if available */ - WL_PROXD_FLAG_TX_CIVIC = 0x00000008, /* tx civic loc, if available */ - WL_PROXD_FLAG_RX_AUTO_BURST = 0x00000010, /* respond to requests w/o host action */ - WL_PROXD_FLAG_TX_AUTO_BURST = 0x00000020, /* continue requests w/o host action */ - WL_PROXD_FLAG_ALL = 0xffffffff -}; -typedef uint32 wl_proxd_flags_t; - -/* session flags */ -enum { - WL_PROXD_SESSION_FLAG_NONE = 0x00000000, /* no flags */ - WL_PROXD_SESSION_FLAG_INITIATOR = 0x00000001, /* local device is initiator */ - WL_PROXD_SESSION_FLAG_TARGET = 0x00000002, /* local device is target */ - WL_PROXD_SESSION_FLAG_ONE_WAY = 0x00000004, /* (initiated) 1-way rtt */ - WL_PROXD_SESSION_FLAG_AUTO_BURST = 0x00000008, /* created w/ rx_auto_burst */ - WL_PROXD_SESSION_FLAG_PERSIST = 0x00000010, /* good until cancelled */ - WL_PROXD_SESSION_FLAG_RTT_DETAIL = 0x00000020, /* rtt detail in results */ - WL_PROXD_SESSION_FLAG_TOF_COMPAT = 0x00000040, /* TOF compatibility - TBD */ - WL_PROXD_SESSION_FLAG_AOA = 0x00000080, /* AOA along w/ RTT */ - WL_PROXD_SESSION_FLAG_RX_AUTO_BURST = 0x00000100, /* Same as proxd flags above */ - WL_PROXD_SESSION_FLAG_TX_AUTO_BURST = 0x00000200, /* Same as proxd flags above */ - WL_PROXD_SESSION_FLAG_NAN_BSS = 0x00000400, /* Use NAN BSS, if applicable */ - WL_PROXD_SESSION_FLAG_TS1 = 0x00000800, /* e.g. FTM1 - cap or rx */ - WL_PROXD_SESSION_FLAG_REPORT_FAILURE = 0x00002000, /* report failure to target */ - WL_PROXD_SESSION_FLAG_INITIATOR_RPT = 0x00004000, /* report distance to target */ - WL_PROXD_SESSION_FLAG_NOCHANSWT = 0x00008000, /* No channel switching */ - WL_PROXD_SESSION_FLAG_NETRUAL = 0x00010000, /* netrual mode */ - WL_PROXD_SESSION_FLAG_SEQ_EN = 0x00020000, /* Toast */ - WL_PROXD_SESSION_FLAG_NO_PARAM_OVRD = 0x00040000, /* no param override from target */ - WL_PROXD_SESSION_FLAG_ASAP = 0x00080000, /* ASAP session */ - WL_PROXD_SESSION_FLAG_REQ_LCI = 0x00100000, /* transmit LCI req */ - WL_PROXD_SESSION_FLAG_REQ_CIV = 0x00200000, /* transmit civic loc req */ - WL_PROXD_SESSION_FLAG_COLLECT = 0x80000000, /* debug - collect */ - WL_PROXD_SESSION_FLAG_ALL = 0xffffffff -}; -typedef uint32 wl_proxd_session_flags_t; - -/* time units - mc supports up to 0.1ns resolution */ -enum { - WL_PROXD_TMU_TU = 0, /* 1024us */ - WL_PROXD_TMU_SEC = 1, - WL_PROXD_TMU_MILLI_SEC = 2, - WL_PROXD_TMU_MICRO_SEC = 3, - WL_PROXD_TMU_NANO_SEC = 4, - WL_PROXD_TMU_PICO_SEC = 5 -}; -typedef int16 wl_proxd_tmu_t; - -/* time interval e.g. 10ns */ -typedef struct wl_proxd_intvl { - uint32 intvl; - wl_proxd_tmu_t tmu; - uint8 pad[2]; -} wl_proxd_intvl_t; - -/* commands that can apply to proxd, method or a session */ -enum { - WL_PROXD_CMD_NONE = 0, - WL_PROXD_CMD_GET_VERSION = 1, - WL_PROXD_CMD_ENABLE = 2, - WL_PROXD_CMD_DISABLE = 3, - WL_PROXD_CMD_CONFIG = 4, - WL_PROXD_CMD_START_SESSION = 5, - WL_PROXD_CMD_BURST_REQUEST = 6, - WL_PROXD_CMD_STOP_SESSION = 7, - WL_PROXD_CMD_DELETE_SESSION = 8, - WL_PROXD_CMD_GET_RESULT = 9, - WL_PROXD_CMD_GET_INFO = 10, - WL_PROXD_CMD_GET_STATUS = 11, - WL_PROXD_CMD_GET_SESSIONS = 12, - WL_PROXD_CMD_GET_COUNTERS = 13, - WL_PROXD_CMD_CLEAR_COUNTERS = 14, - WL_PROXD_CMD_COLLECT = 15, - WL_PROXD_CMD_TUNE = 16, - WL_PROXD_CMD_DUMP = 17, - WL_PROXD_CMD_START_RANGING = 18, - WL_PROXD_CMD_STOP_RANGING = 19, - WL_PROXD_CMD_GET_RANGING_INFO = 20, - WL_PROXD_CMD_MAX -}; -typedef int16 wl_proxd_cmd_t; - -/* session ids: - * id 0 is reserved - * ids 1..0x7fff - allocated by host/app - * 0x8000-0xffff - allocated by firmware, used for auto/rx - */ -enum { - WL_PROXD_SESSION_ID_GLOBAL = 0 -}; - -#define WL_PROXD_SID_HOST_MAX 0x7fff -#define WL_PROXD_SID_HOST_ALLOC(_sid) ((_sid) > 0 && (_sid) <= WL_PROXD_SID_HOST_MAX) - -/* maximum number sessions that can be allocated, may be less if tunable */ -#define WL_PROXD_MAX_SESSIONS 16 - -typedef uint16 wl_proxd_session_id_t; - -/* status - TBD BCME_ vs proxd status - range reserved for BCME_ */ -enum { - WL_PROXD_E_INCOMPLETE = -1044, - WL_PROXD_E_OVERRIDDEN = -1043, - WL_PROXD_E_ASAP_FAILED = -1042, - WL_PROXD_E_NOTSTARTED = -1041, - WL_PROXD_E_INVALIDAVB = -1040, - WL_PROXD_E_INCAPABLE = -1039, - WL_PROXD_E_MISMATCH = -1038, - WL_PROXD_E_DUP_SESSION = -1037, - WL_PROXD_E_REMOTE_FAIL = -1036, - WL_PROXD_E_REMOTE_INCAPABLE = -1035, - WL_PROXD_E_SCHED_FAIL = -1034, - WL_PROXD_E_PROTO = -1033, - WL_PROXD_E_EXPIRED = -1032, - WL_PROXD_E_TIMEOUT = -1031, - WL_PROXD_E_NOACK = -1030, - WL_PROXD_E_DEFERRED = -1029, - WL_PROXD_E_INVALID_SID = -1028, - WL_PROXD_E_REMOTE_CANCEL = -1027, - WL_PROXD_E_CANCELED = -1026, /* local */ - WL_PROXD_E_INVALID_SESSION = -1025, - WL_PROXD_E_BAD_STATE = -1024, - WL_PROXD_E_ERROR = -1, - WL_PROXD_E_OK = 0 -}; -typedef int32 wl_proxd_status_t; - -/* session states */ -enum { - WL_PROXD_SESSION_STATE_NONE = 0, - WL_PROXD_SESSION_STATE_CREATED = 1, - WL_PROXD_SESSION_STATE_CONFIGURED = 2, - WL_PROXD_SESSION_STATE_STARTED = 3, - WL_PROXD_SESSION_STATE_DELAY = 4, - WL_PROXD_SESSION_STATE_USER_WAIT = 5, - WL_PROXD_SESSION_STATE_SCHED_WAIT = 6, - WL_PROXD_SESSION_STATE_BURST = 7, - WL_PROXD_SESSION_STATE_STOPPING = 8, - WL_PROXD_SESSION_STATE_ENDED = 9, - WL_PROXD_SESSION_STATE_DESTROYING = -1 -}; -typedef int16 wl_proxd_session_state_t; - -/* RTT sample flags */ -enum { - WL_PROXD_RTT_SAMPLE_NONE = 0x00, - WL_PROXD_RTT_SAMPLE_DISCARD = 0x01 -}; -typedef uint8 wl_proxd_rtt_sample_flags_t; - -typedef struct wl_proxd_rtt_sample { - uint8 id; /* id for the sample - non-zero */ - wl_proxd_rtt_sample_flags_t flags; - int16 rssi; - wl_proxd_intvl_t rtt; /* round trip time */ - uint32 ratespec; -} wl_proxd_rtt_sample_t; - -/* result flags */ -enum { - WL_PRXOD_RESULT_FLAG_NONE = 0x0000, - WL_PROXD_RESULT_FLAG_NLOS = 0x0001, /* LOS - if available */ - WL_PROXD_RESULT_FLAG_LOS = 0x0002, /* NLOS - if available */ - WL_PROXD_RESULT_FLAG_FATAL = 0x0004, /* Fatal error during burst */ - WL_PROXD_RESULT_FLAG_ALL = 0xffff -}; -typedef int16 wl_proxd_result_flags_t; - -/* rtt measurement result */ -typedef struct wl_proxd_rtt_result { - wl_proxd_session_id_t sid; - wl_proxd_result_flags_t flags; - wl_proxd_status_t status; - struct ether_addr peer; - wl_proxd_session_state_t state; /* current state */ - union { - wl_proxd_intvl_t retry_after; /* hint for errors */ - wl_proxd_intvl_t burst_duration; /* burst duration */ - } u; - wl_proxd_rtt_sample_t avg_rtt; - uint32 avg_dist; /* 1/256m units */ - uint16 sd_rtt; /* RTT standard deviation */ - uint8 num_valid_rtt; /* valid rtt cnt */ - uint8 num_ftm; /* actual num of ftm cnt */ - uint16 burst_num; /* in a session */ - uint16 num_rtt; /* 0 if no detail */ - wl_proxd_rtt_sample_t rtt[1]; /* variable */ -} wl_proxd_rtt_result_t; - -/* aoa measurement result */ -typedef struct wl_proxd_aoa_result { - wl_proxd_session_id_t sid; - wl_proxd_result_flags_t flags; - wl_proxd_status_t status; - struct ether_addr peer; - wl_proxd_session_state_t state; - uint16 burst_num; - uint8 pad[2]; - /* wl_proxd_aoa_sample_t sample_avg; TBD */ -} BWL_POST_PACKED_STRUCT wl_proxd_aoa_result_t; - -/* global stats */ -typedef struct wl_proxd_counters { - uint32 tx; /* tx frame count */ - uint32 rx; /* rx frame count */ - uint32 burst; /* total number of burst */ - uint32 sessions; /* total number of sessions */ - uint32 max_sessions; /* max concurrency */ - uint32 sched_fail; /* scheduling failures */ - uint32 timeouts; /* timeouts */ - uint32 protoerr; /* protocol errors */ - uint32 noack; /* tx w/o ack */ - uint32 txfail; /* any tx falure */ - uint32 lci_req_tx; /* tx LCI requests */ - uint32 lci_req_rx; /* rx LCI requests */ - uint32 lci_rep_tx; /* tx LCI reports */ - uint32 lci_rep_rx; /* rx LCI reports */ - uint32 civic_req_tx; /* tx civic requests */ - uint32 civic_req_rx; /* rx civic requests */ - uint32 civic_rep_tx; /* tx civic reports */ - uint32 civic_rep_rx; /* rx civic reports */ - uint32 rctx; /* ranging contexts created */ - uint32 rctx_done; /* count of ranging done */ -} wl_proxd_counters_t; - -typedef struct wl_proxd_counters wl_proxd_session_counters_t; - -enum { - WL_PROXD_CAP_NONE = 0x0000, - WL_PROXD_CAP_ALL = 0xffff -}; -typedef int16 wl_proxd_caps_t; - -/* method capabilities */ -enum { - WL_PROXD_FTM_CAP_NONE = 0x0000, - WL_PROXD_FTM_CAP_FTM1 = 0x0001 -}; -typedef uint16 wl_proxd_ftm_caps_t; - -typedef struct BWL_PRE_PACKED_STRUCT wl_proxd_tlv_id_list { - uint16 num_ids; - uint16 ids[1]; -} BWL_POST_PACKED_STRUCT wl_proxd_tlv_id_list_t; - -typedef struct wl_proxd_session_id_list { - uint16 num_ids; - wl_proxd_session_id_t ids[1]; -} wl_proxd_session_id_list_t; - -/* tlvs returned for get_info on ftm method - * configuration: - * proxd flags - * event mask - * debug mask - * session defaults (session tlvs) - * status tlv - not supported for ftm method - * info tlv - */ -typedef struct wl_proxd_ftm_info { - wl_proxd_ftm_caps_t caps; - uint16 max_sessions; - uint16 num_sessions; - uint16 rx_max_burst; -} wl_proxd_ftm_info_t; - -/* tlvs returned for get_info on session - * session config (tlvs) - * session info tlv - */ -typedef struct wl_proxd_ftm_session_info { - uint16 sid; - uint8 bss_index; - uint8 pad; - struct ether_addr bssid; - wl_proxd_session_state_t state; - wl_proxd_status_t status; - uint16 burst_num; -} wl_proxd_ftm_session_info_t; - -typedef struct wl_proxd_ftm_session_status { - uint16 sid; - wl_proxd_session_state_t state; - wl_proxd_status_t status; - uint16 burst_num; -} wl_proxd_ftm_session_status_t; - -/* rrm range request */ -typedef struct wl_proxd_range_req { - uint16 num_repeat; - uint16 init_delay_range; /* in TUs */ - uint8 pad; - uint8 num_nbr; /* number of (possible) neighbors */ - nbr_element_t nbr[1]; -} wl_proxd_range_req_t; - -#define WL_PROXD_LCI_LAT_OFF 0 -#define WL_PROXD_LCI_LONG_OFF 5 -#define WL_PROXD_LCI_ALT_OFF 10 - -#define WL_PROXD_LCI_GET_LAT(_lci, _lat, _lat_err) { \ - unsigned _off = WL_PROXD_LCI_LAT_OFF; \ - _lat_err = (_lci)->data[(_off)] & 0x3f; \ - _lat = (_lci)->data[(_off)+1]; \ - _lat |= (_lci)->data[(_off)+2] << 8; \ - _lat |= (_lci)->data[_(_off)+3] << 16; \ - _lat |= (_lci)->data[(_off)+4] << 24; \ - _lat <<= 2; \ - _lat |= (_lci)->data[(_off)] >> 6; \ -} - -#define WL_PROXD_LCI_GET_LONG(_lci, _lcilong, _long_err) { \ - unsigned _off = WL_PROXD_LCI_LONG_OFF; \ - _long_err = (_lci)->data[(_off)] & 0x3f; \ - _lcilong = (_lci)->data[(_off)+1]; \ - _lcilong |= (_lci)->data[(_off)+2] << 8; \ - _lcilong |= (_lci)->data[_(_off)+3] << 16; \ - _lcilong |= (_lci)->data[(_off)+4] << 24; \ - __lcilong <<= 2; \ - _lcilong |= (_lci)->data[(_off)] >> 6; \ -} - -#define WL_PROXD_LCI_GET_ALT(_lci, _alt_type, _alt, _alt_err) { \ - unsigned _off = WL_PROXD_LCI_ALT_OFF; \ - _alt_type = (_lci)->data[_off] & 0x0f; \ - _alt_err = (_lci)->data[(_off)] >> 4; \ - _alt_err |= ((_lci)->data[(_off)+1] & 0x03) << 4; \ - _alt = (_lci)->data[(_off)+2]; \ - _alt |= (_lci)->data[(_off)+3] << 8; \ - _alt |= (_lci)->data[_(_off)+4] << 16; \ - _alt <<= 6; \ - _alt |= (_lci)->data[(_off) + 1] >> 2; \ -} - -#define WL_PROXD_LCI_VERSION(_lci) ((_lci)->data[15] >> 6) - -/* availability. advertising mechanism bss specific */ -/* availablity flags */ -enum { - WL_PROXD_AVAIL_NONE = 0, - WL_PROXD_AVAIL_NAN_PUBLISHED = 0x0001, - WL_PROXD_AVAIL_SCHEDULED = 0x0002 /* scheduled by proxd */ -}; -typedef int16 wl_proxd_avail_flags_t; - -/* time reference */ -enum { - WL_PROXD_TREF_NONE = 0, - WL_PROXD_TREF_DEV_TSF = 1, - WL_PROXD_TREF_NAN_DW = 2, - WL_PROXD_TREF_TBTT = 3, - WL_PROXD_TREF_MAX /* last entry */ -}; -typedef int16 wl_proxd_time_ref_t; - -/* proxd channel-time slot */ -typedef struct { - wl_proxd_intvl_t start; /* from ref */ - wl_proxd_intvl_t duration; /* from start */ - uint32 chanspec; -} wl_proxd_time_slot_t; - -/* availability. advertising mechanism bss specific */ -typedef struct wl_proxd_avail { - wl_proxd_avail_flags_t flags; /* for query only */ - wl_proxd_time_ref_t time_ref; - uint16 max_slots; /* for query only */ - uint16 num_slots; - wl_proxd_time_slot_t slots[1]; -} wl_proxd_avail_t; - -/* collect support TBD */ - -/* debugging */ -enum { - WL_PROXD_DEBUG_NONE = 0x00000000, - WL_PROXD_DEBUG_LOG = 0x00000001, - WL_PROXD_DEBUG_IOV = 0x00000002, - WL_PROXD_DEBUG_EVENT = 0x00000004, - WL_PROXD_DEBUG_SESSION = 0x00000008, - WL_PROXD_DEBUG_PROTO = 0x00000010, - WL_PROXD_DEBUG_SCHED = 0x00000020, - WL_PROXD_DEBUG_RANGING = 0x00000040, - WL_PROXD_DEBUG_ALL = 0xffffffff -}; -typedef uint32 wl_proxd_debug_mask_t; - -/* tlv IDs - data length 4 bytes unless overridden by type, alignment 32 bits */ -enum { - WL_PROXD_TLV_ID_NONE = 0, - WL_PROXD_TLV_ID_METHOD = 1, - WL_PROXD_TLV_ID_FLAGS = 2, - WL_PROXD_TLV_ID_CHANSPEC = 3, /* note: uint32 */ - WL_PROXD_TLV_ID_TX_POWER = 4, - WL_PROXD_TLV_ID_RATESPEC = 5, - WL_PROXD_TLV_ID_BURST_DURATION = 6, /* intvl - length of burst */ - WL_PROXD_TLV_ID_BURST_PERIOD = 7, /* intvl - between bursts */ - WL_PROXD_TLV_ID_BURST_FTM_SEP = 8, /* intvl - between FTMs */ - WL_PROXD_TLV_ID_BURST_NUM_FTM = 9, /* uint16 - per burst */ - WL_PROXD_TLV_ID_NUM_BURST = 10, /* uint16 */ - WL_PROXD_TLV_ID_FTM_RETRIES = 11, /* uint16 at FTM level */ - WL_PROXD_TLV_ID_BSS_INDEX = 12, /* uint8 */ - WL_PROXD_TLV_ID_BSSID = 13, - WL_PROXD_TLV_ID_INIT_DELAY = 14, /* intvl - optional, non-standalone only */ - WL_PROXD_TLV_ID_BURST_TIMEOUT = 15, /* expect response within - intvl */ - WL_PROXD_TLV_ID_EVENT_MASK = 16, /* interested events - in/out */ - WL_PROXD_TLV_ID_FLAGS_MASK = 17, /* interested flags - in only */ - WL_PROXD_TLV_ID_PEER_MAC = 18, /* mac address of peer */ - WL_PROXD_TLV_ID_FTM_REQ = 19, /* dot11_ftm_req */ - WL_PROXD_TLV_ID_LCI_REQ = 20, - WL_PROXD_TLV_ID_LCI = 21, - WL_PROXD_TLV_ID_CIVIC_REQ = 22, - WL_PROXD_TLV_ID_CIVIC = 23, - WL_PROXD_TLV_ID_AVAIL = 24, - WL_PROXD_TLV_ID_SESSION_FLAGS = 25, - WL_PROXD_TLV_ID_SESSION_FLAGS_MASK = 26, /* in only */ - WL_PROXD_TLV_ID_RX_MAX_BURST = 27, /* uint16 - limit bursts per session */ - WL_PROXD_TLV_ID_RANGING_INFO = 28, /* ranging info */ - WL_PROXD_TLV_ID_RANGING_FLAGS = 29, /* uint16 */ - WL_PROXD_TLV_ID_RANGING_FLAGS_MASK = 30, /* uint16, in only */ - /* 31 - 34 reserved for other feature */ - WL_PROXD_TLV_ID_FTM_REQ_RETRIES = 35, /* uint16 FTM request retries */ - - /* output - 512 + x */ - WL_PROXD_TLV_ID_STATUS = 512, - WL_PROXD_TLV_ID_COUNTERS = 513, - WL_PROXD_TLV_ID_INFO = 514, - WL_PROXD_TLV_ID_RTT_RESULT = 515, - WL_PROXD_TLV_ID_AOA_RESULT = 516, - WL_PROXD_TLV_ID_SESSION_INFO = 517, - WL_PROXD_TLV_ID_SESSION_STATUS = 518, - WL_PROXD_TLV_ID_SESSION_ID_LIST = 519, - - /* debug tlvs can be added starting 1024 */ - WL_PROXD_TLV_ID_DEBUG_MASK = 1024, - WL_PROXD_TLV_ID_COLLECT = 1025, /* output only */ - WL_PROXD_TLV_ID_STRBUF = 1026, - - WL_PROXD_TLV_ID_MAX -}; - -typedef struct wl_proxd_tlv { - uint16 id; - uint16 len; - uint8 data[1]; -} wl_proxd_tlv_t; - -/* proxd iovar - applies to proxd, method or session */ -typedef struct wl_proxd_iov { - uint16 version; - uint16 len; - wl_proxd_cmd_t cmd; - wl_proxd_method_t method; - wl_proxd_session_id_t sid; - uint8 pad[2]; - wl_proxd_tlv_t tlvs[1]; /* variable */ -} wl_proxd_iov_t; - -#define WL_PROXD_IOV_HDR_SIZE OFFSETOF(wl_proxd_iov_t, tlvs) - -/* The following event definitions may move to bcmevent.h, but sharing proxd types - * across needs more invasive changes unrelated to proxd - */ -enum { - WL_PROXD_EVENT_NONE = 0, /* not an event, reserved */ - WL_PROXD_EVENT_SESSION_CREATE = 1, - WL_PROXD_EVENT_SESSION_START = 2, - WL_PROXD_EVENT_FTM_REQ = 3, - WL_PROXD_EVENT_BURST_START = 4, - WL_PROXD_EVENT_BURST_END = 5, - WL_PROXD_EVENT_SESSION_END = 6, - WL_PROXD_EVENT_SESSION_RESTART = 7, - WL_PROXD_EVENT_BURST_RESCHED = 8, /* burst rescheduled - e.g. partial TSF */ - WL_PROXD_EVENT_SESSION_DESTROY = 9, - WL_PROXD_EVENT_RANGE_REQ = 10, - WL_PROXD_EVENT_FTM_FRAME = 11, - WL_PROXD_EVENT_DELAY = 12, - WL_PROXD_EVENT_VS_INITIATOR_RPT = 13, /* (target) rx initiator-report */ - WL_PROXD_EVENT_RANGING = 14, - - WL_PROXD_EVENT_MAX -}; -typedef int16 wl_proxd_event_type_t; - -/* proxd event mask - upto 32 events for now */ -typedef uint32 wl_proxd_event_mask_t; - -#define WL_PROXD_EVENT_MASK_ALL 0xfffffffe -#define WL_PROXD_EVENT_MASK_EVENT(_event_type) (1 << (_event_type)) -#define WL_PROXD_EVENT_ENABLED(_mask, _event_type) (\ - ((_mask) & WL_PROXD_EVENT_MASK_EVENT(_event_type)) != 0) - -/* proxd event - applies to proxd, method or session */ -typedef struct wl_proxd_event { - uint16 version; - uint16 len; - wl_proxd_event_type_t type; - wl_proxd_method_t method; - wl_proxd_session_id_t sid; - uint8 pad[2]; - wl_proxd_tlv_t tlvs[1]; /* variable */ -} wl_proxd_event_t; - -enum { - WL_PROXD_RANGING_STATE_NONE = 0, - WL_PROXD_RANGING_STATE_NOTSTARTED = 1, - WL_PROXD_RANGING_STATE_INPROGRESS = 2, - WL_PROXD_RANGING_STATE_DONE = 3 -}; -typedef int16 wl_proxd_ranging_state_t; - -/* proxd ranging flags */ -enum { - WL_PROXD_RANGING_FLAG_NONE = 0x0000, /* no flags */ - WL_PROXD_RANGING_FLAG_DEL_SESSIONS_ON_STOP = 0x0001, - WL_PROXD_RANGING_FLAG_ALL = 0xffff -}; -typedef uint16 wl_proxd_ranging_flags_t; - -struct wl_proxd_ranging_info { - wl_proxd_status_t status; - wl_proxd_ranging_state_t state; - wl_proxd_ranging_flags_t flags; - uint16 num_sids; - uint16 num_done; -}; -typedef struct wl_proxd_ranging_info wl_proxd_ranging_info_t; - -/* end proxd definitions */ -/* Data returned by the bssload_report iovar. - * This is also the WLC_E_BSS_LOAD event data. - */ -typedef BWL_PRE_PACKED_STRUCT struct wl_bssload { - uint16 sta_count; /* station count */ - uint16 aac; /* available admission capacity */ - uint8 chan_util; /* channel utilization */ -} BWL_POST_PACKED_STRUCT wl_bssload_t; - -/* Maximum number of configurable BSS Load levels. The number of BSS Load - * ranges is always 1 more than the number of configured levels. eg. if - * 3 levels of 10, 20, 30 are configured then this defines 4 load ranges: - * 0-10, 11-20, 21-30, 31-255. A WLC_E_BSS_LOAD event is generated each time - * the utilization level crosses into another range, subject to the rate limit. - */ -#define MAX_BSSLOAD_LEVELS 8 -#define MAX_BSSLOAD_RANGES (MAX_BSSLOAD_LEVELS + 1) - -/* BSS Load event notification configuration. */ -typedef struct wl_bssload_cfg { - uint32 rate_limit_msec; /* # of events posted to application will be limited to - * one per specified period (0 to disable rate limit). - */ - uint8 num_util_levels; /* Number of entries in util_levels[] below */ - uint8 util_levels[MAX_BSSLOAD_LEVELS]; - /* Variable number of BSS Load utilization levels in - * low to high order. An event will be posted each time - * a received beacon's BSS Load IE channel utilization - * value crosses a level. - */ -} wl_bssload_cfg_t; - -/* Multiple roaming profile suport */ -#define WL_MAX_ROAM_PROF_BRACKETS 4 - -#define WL_MAX_ROAM_PROF_VER 0 - -#define WL_ROAM_PROF_NONE (0 << 0) -#define WL_ROAM_PROF_LAZY (1 << 0) -#define WL_ROAM_PROF_NO_CI (1 << 1) -#define WL_ROAM_PROF_SUSPEND (1 << 2) -#define WL_ROAM_PROF_SYNC_DTIM (1 << 6) -#define WL_ROAM_PROF_DEFAULT (1 << 7) /* backward compatible single default profile */ - -typedef struct wl_roam_prof { - int8 roam_flags; /* bit flags */ - int8 roam_trigger; /* RSSI trigger level per profile/RSSI bracket */ - int8 rssi_lower; - int8 roam_delta; - int8 rssi_boost_thresh; /* Min RSSI to qualify for RSSI boost */ - int8 rssi_boost_delta; /* RSSI boost for AP in the other band */ - uint16 nfscan; /* nuber of full scan to start with */ - uint16 fullscan_period; - uint16 init_scan_period; - uint16 backoff_multiplier; - uint16 max_scan_period; -} wl_roam_prof_t; - -typedef struct wl_roam_prof_band { - uint32 band; /* Must be just one band */ - uint16 ver; /* version of this struct */ - uint16 len; /* length in bytes of this structure */ - wl_roam_prof_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS]; -} wl_roam_prof_band_t; - -/* Data structures for Interface Create/Remove */ - -#define WL_INTERFACE_CREATE_VER (0) - -/* - * The flags filed of the wl_interface_create is designed to be - * a Bit Mask. As of now only Bit 0 and Bit 1 are used as mentioned below. - * The rest of the bits can be used, incase we have to provide - * more information to the dongle - */ - -/* - * Bit 0 of flags field is used to inform whether the interface requested to - * be created is STA or AP. - * 0 - Create a STA interface - * 1 - Create an AP interface - */ -#define WL_INTERFACE_CREATE_STA (0 << 0) -#define WL_INTERFACE_CREATE_AP (1 << 0) - -/* - * Bit 1 of flags field is used to inform whether MAC is present in the - * data structure or not. - * 0 - Ignore mac_addr field - * 1 - Use the mac_addr field - */ -#define WL_INTERFACE_MAC_DONT_USE (0 << 1) -#define WL_INTERFACE_MAC_USE (1 << 1) - -typedef struct wl_interface_create { - uint16 ver; /* version of this struct */ - uint32 flags; /* flags that defines the operation */ - struct ether_addr mac_addr; /* Optional Mac address */ -} wl_interface_create_t; - -typedef struct wl_interface_info { - uint16 ver; /* version of this struct */ - struct ether_addr mac_addr; /* MAC address of the interface */ - char ifname[BCM_MSG_IFNAME_MAX]; /* name of interface */ - uint8 bsscfgidx; /* source bsscfg index */ -} wl_interface_info_t; - -/* no default structure packing */ -#include - -#endif /* _wlioctl_h_ */ diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c deleted file mode 100644 index 1145a5b10ed8..000000000000 --- a/drivers/net/wireless/bcmdhd/linux_osl.c +++ /dev/null @@ -1,1815 +0,0 @@ -/* - * Linux OS Independent Layer - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: linux_osl.c 614089 2016-01-21 02:43:09Z $ - */ - -#define LINUX_PORT - -#include -#include -#include -#include - - -#include - -#include -#include -#include -#include - - - -#ifdef BCM_SECURE_DMA -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__ARM_ARCH_7A__) -#include -#include -#endif -#include -#endif /* BCM_SECURE_DMA */ - -#include - - -#define PCI_CFG_RETRY 10 - -#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ -#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ -#define DUMPBUFSZ 1024 - -#ifdef CONFIG_DHD_USE_STATIC_BUF -#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) -#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1) -#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2) -#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4) -#else -#define DHD_SKB_HDRSIZE 336 -#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) -#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) -#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) -#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ - -#define STATIC_BUF_MAX_NUM 16 -#define STATIC_BUF_SIZE (PAGE_SIZE*2) -#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) - -typedef struct bcm_static_buf { - spinlock_t static_lock; - unsigned char *buf_ptr; - unsigned char buf_use[STATIC_BUF_MAX_NUM]; -} bcm_static_buf_t; - -static bcm_static_buf_t *bcm_static_buf = 0; - -#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) -#define STATIC_PKT_4PAGE_NUM 0 -#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE -#elif defined(ENHANCED_STATIC_BUF) -#define STATIC_PKT_4PAGE_NUM 1 -#define DHD_SKB_MAX_BUFSIZE DHD_SKB_4PAGE_BUFSIZE -#else -#define STATIC_PKT_4PAGE_NUM 0 -#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE -#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ - -#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) -#define STATIC_PKT_1PAGE_NUM 0 -#define STATIC_PKT_2PAGE_NUM 64 -#else -#define STATIC_PKT_1PAGE_NUM 8 -#define STATIC_PKT_2PAGE_NUM 8 -#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ - -#define STATIC_PKT_1_2PAGE_NUM \ - ((STATIC_PKT_1PAGE_NUM) + (STATIC_PKT_2PAGE_NUM)) -#define STATIC_PKT_MAX_NUM \ - ((STATIC_PKT_1_2PAGE_NUM) + (STATIC_PKT_4PAGE_NUM)) - -typedef struct bcm_static_pkt { -#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) - struct sk_buff *skb_8k[STATIC_PKT_2PAGE_NUM]; - unsigned char pkt_invalid[STATIC_PKT_2PAGE_NUM]; - spinlock_t osl_pkt_lock; - uint32 last_allocated_index; -#else - struct sk_buff *skb_4k[STATIC_PKT_1PAGE_NUM]; - struct sk_buff *skb_8k[STATIC_PKT_2PAGE_NUM]; -#ifdef ENHANCED_STATIC_BUF - struct sk_buff *skb_16k; -#endif /* ENHANCED_STATIC_BUF */ - struct semaphore osl_pkt_sem; -#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ - unsigned char pkt_use[STATIC_PKT_MAX_NUM]; -} bcm_static_pkt_t; - -static bcm_static_pkt_t *bcm_static_skb = 0; - -void* wifi_platform_prealloc(void *adapter, int section, unsigned long size); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - -typedef struct bcm_mem_link { - struct bcm_mem_link *prev; - struct bcm_mem_link *next; - uint size; - int line; - void *osh; - char file[BCM_MEM_FILENAME_LEN]; -} bcm_mem_link_t; - -struct osl_cmn_info { - atomic_t malloced; - atomic_t pktalloced; /* Number of allocated packet buffers */ - spinlock_t dbgmem_lock; - bcm_mem_link_t *dbgmem_list; - spinlock_t pktalloc_lock; - atomic_t refcount; /* Number of references to this shared structure. */ -}; -typedef struct osl_cmn_info osl_cmn_t; - -struct osl_info { - osl_pubinfo_t pub; -#ifdef CTFPOOL - ctfpool_t *ctfpool; -#endif /* CTFPOOL */ - uint magic; - void *pdev; - uint failed; - uint bustype; - osl_cmn_t *cmn; /* Common OSL related data shred between two OSH's */ - - void *bus_handle; - uint32 flags; /* If specific cases to be handled in the OSL */ -}; - -#define OSL_PKTTAG_CLEAR(p) \ -do { \ - struct sk_buff *s = (struct sk_buff *)(p); \ - ASSERT(OSL_PKTTAG_SZ == 32); \ - *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ - *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ - *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ - *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ -} while (0) - -/* PCMCIA attribute space access macros */ - -/* Global ASSERT type flag */ -uint32 g_assert_type = 0; -module_param(g_assert_type, int, 0); - -static int16 linuxbcmerrormap[] = -{ 0, /* 0 */ - -EINVAL, /* BCME_ERROR */ - -EINVAL, /* BCME_BADARG */ - -EINVAL, /* BCME_BADOPTION */ - -EINVAL, /* BCME_NOTUP */ - -EINVAL, /* BCME_NOTDOWN */ - -EINVAL, /* BCME_NOTAP */ - -EINVAL, /* BCME_NOTSTA */ - -EINVAL, /* BCME_BADKEYIDX */ - -EINVAL, /* BCME_RADIOOFF */ - -EINVAL, /* BCME_NOTBANDLOCKED */ - -EINVAL, /* BCME_NOCLK */ - -EINVAL, /* BCME_BADRATESET */ - -EINVAL, /* BCME_BADBAND */ - -E2BIG, /* BCME_BUFTOOSHORT */ - -E2BIG, /* BCME_BUFTOOLONG */ - -EBUSY, /* BCME_BUSY */ - -EINVAL, /* BCME_NOTASSOCIATED */ - -EINVAL, /* BCME_BADSSIDLEN */ - -EINVAL, /* BCME_OUTOFRANGECHAN */ - -EINVAL, /* BCME_BADCHAN */ - -EFAULT, /* BCME_BADADDR */ - -ENOMEM, /* BCME_NORESOURCE */ - -EOPNOTSUPP, /* BCME_UNSUPPORTED */ - -EMSGSIZE, /* BCME_BADLENGTH */ - -EINVAL, /* BCME_NOTREADY */ - -EPERM, /* BCME_EPERM */ - -ENOMEM, /* BCME_NOMEM */ - -EINVAL, /* BCME_ASSOCIATED */ - -ERANGE, /* BCME_RANGE */ - -EINVAL, /* BCME_NOTFOUND */ - -EINVAL, /* BCME_WME_NOT_ENABLED */ - -EINVAL, /* BCME_TSPEC_NOTFOUND */ - -EINVAL, /* BCME_ACM_NOTSUPPORTED */ - -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ - -EIO, /* BCME_SDIO_ERROR */ - -ENODEV, /* BCME_DONGLE_DOWN */ - -EINVAL, /* BCME_VERSION */ - -EIO, /* BCME_TXFAIL */ - -EIO, /* BCME_RXFAIL */ - -ENODEV, /* BCME_NODEVICE */ - -EINVAL, /* BCME_NMODE_DISABLED */ - -ENODATA, /* BCME_NONRESIDENT */ - -EINVAL, /* BCME_SCANREJECT */ - -EINVAL, /* BCME_USAGE_ERROR */ - -EIO, /* BCME_IOCTL_ERROR */ - -EIO, /* BCME_SERIAL_PORT_ERR */ - -EOPNOTSUPP, /* BCME_DISABLED, BCME_NOTENABLED */ - -EIO, /* BCME_DECERR */ - -EIO, /* BCME_ENCERR */ - -EIO, /* BCME_MICERR */ - -ERANGE, /* BCME_REPLAY */ - -EINVAL, /* BCME_IE_NOTFOUND */ - -/* When an new error code is added to bcmutils.h, add os - * specific error translation here as well - */ -/* check if BCME_LAST changed since the last time this function was updated */ -#if BCME_LAST != -52 -#error "You need to add a OS error translation in the linuxbcmerrormap \ - for new error code defined in bcmutils.h" -#endif -}; -uint lmtest = FALSE; - -/* translate bcmerrors into linux errors */ -int -osl_error(int bcmerror) -{ - if (bcmerror > 0) - bcmerror = 0; - else if (bcmerror < BCME_LAST) - bcmerror = BCME_ERROR; - - /* Array bounds covered by ASSERT in osl_attach */ - return linuxbcmerrormap[-bcmerror]; -} -#ifdef SHARED_OSL_CMN -osl_t * -osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn) -{ -#else -osl_t * -osl_attach(void *pdev, uint bustype, bool pkttag) -{ - void **osl_cmn = NULL; -#endif /* SHARED_OSL_CMN */ - osl_t *osh; - gfp_t flags; - - flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; - if (!(osh = kmalloc(sizeof(osl_t), flags))) - return osh; - - ASSERT(osh); - - bzero(osh, sizeof(osl_t)); - - if (osl_cmn == NULL || *osl_cmn == NULL) { - if (!(osh->cmn = kmalloc(sizeof(osl_cmn_t), flags))) { - kfree(osh); - return NULL; - } - bzero(osh->cmn, sizeof(osl_cmn_t)); - if (osl_cmn) - *osl_cmn = osh->cmn; - atomic_set(&osh->cmn->malloced, 0); - osh->cmn->dbgmem_list = NULL; - spin_lock_init(&(osh->cmn->dbgmem_lock)); - - spin_lock_init(&(osh->cmn->pktalloc_lock)); - - } else { - osh->cmn = *osl_cmn; - } - atomic_add(1, &osh->cmn->refcount); - - /* Check that error map has the right number of entries in it */ - ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); - - osh->failed = 0; - osh->pdev = pdev; - osh->pub.pkttag = pkttag; - osh->bustype = bustype; - osh->magic = OS_HANDLE_MAGIC; - - switch (bustype) { - case PCI_BUS: - case SI_BUS: - case PCMCIA_BUS: - osh->pub.mmbus = TRUE; - break; - case JTAG_BUS: - case SDIO_BUS: - case USB_BUS: - case SPI_BUS: - case RPC_BUS: - osh->pub.mmbus = FALSE; - break; - default: - ASSERT(FALSE); - break; - } - - - - return osh; -} - -int osl_static_mem_init(osl_t *osh, void *adapter) -{ -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (!bcm_static_buf && adapter) { - if (!(bcm_static_buf = (bcm_static_buf_t *)wifi_platform_prealloc(adapter, - 3, STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) { - printk("can not alloc static buf!\n"); - bcm_static_skb = NULL; - ASSERT(osh->magic == OS_HANDLE_MAGIC); - return -ENOMEM; - } - else - printk("alloc static buf at %p!\n", bcm_static_buf); - - - spin_lock_init(&bcm_static_buf->static_lock); - - bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; - } - -#if defined(BCMPCIE) && !defined(DHD_USE_STATIC_IOCTLBUF) - return 0; -#else - if (!bcm_static_skb && adapter) { - int i; - void *skb_buff_ptr = 0; - bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); - skb_buff_ptr = wifi_platform_prealloc(adapter, 4, 0); - if (!skb_buff_ptr) { - printk("cannot alloc static buf!\n"); - bcm_static_buf = NULL; - bcm_static_skb = NULL; - ASSERT(osh->magic == OS_HANDLE_MAGIC); - return -ENOMEM; - } - - bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * - (STATIC_PKT_MAX_NUM)); - for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { - bcm_static_skb->pkt_use[i] = 0; -#ifdef BCMPCIE - bcm_static_skb->pkt_invalid[i] = 0; -#endif /* BCMPCIE */ - } - -#ifdef BCMPCIE - spin_lock_init(&bcm_static_skb->osl_pkt_lock); - bcm_static_skb->last_allocated_index = 0; -#else - sema_init(&bcm_static_skb->osl_pkt_sem, 1); -#endif /* BCMPCIE */ - } -#endif /* BCMPCIE && !DHD_USE_STATIC_IOCTLBUF */ -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - - return 0; -} - -void osl_set_bus_handle(osl_t *osh, void *bus_handle) -{ - osh->bus_handle = bus_handle; -} - -void* osl_get_bus_handle(osl_t *osh) -{ - return osh->bus_handle; -} - -void -osl_detach(osl_t *osh) -{ - if (osh == NULL) - return; - - ASSERT(osh->magic == OS_HANDLE_MAGIC); - atomic_sub(1, &osh->cmn->refcount); - if (atomic_read(&osh->cmn->refcount) == 0) { - kfree(osh->cmn); - } - kfree(osh); -} - -int osl_static_mem_deinit(osl_t *osh, void *adapter) -{ -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (bcm_static_buf) { - bcm_static_buf = 0; - } - if (bcm_static_skb) { - bcm_static_skb = 0; - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - return 0; -} - -static struct sk_buff *osl_alloc_skb(osl_t *osh, unsigned int len) -{ - struct sk_buff *skb; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) - gfp_t flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; -#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_ZONE_DMA) - flags |= GFP_ATOMIC; -#endif - skb = __dev_alloc_skb(len, flags); -#else - skb = dev_alloc_skb(len); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) */ - return skb; -} - -#ifdef CTFPOOL - -#ifdef CTFPOOL_SPINLOCK -#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_irqsave(&(ctfpool)->lock, flags) -#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_irqrestore(&(ctfpool)->lock, flags) -#else -#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_bh(&(ctfpool)->lock) -#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_bh(&(ctfpool)->lock) -#endif /* CTFPOOL_SPINLOCK */ -/* - * Allocate and add an object to packet pool. - */ -void * -osl_ctfpool_add(osl_t *osh) -{ - struct sk_buff *skb; -#ifdef CTFPOOL_SPINLOCK - unsigned long flags; -#endif /* CTFPOOL_SPINLOCK */ - - if ((osh == NULL) || (osh->ctfpool == NULL)) - return NULL; - - CTFPOOL_LOCK(osh->ctfpool, flags); - ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj); - - /* No need to allocate more objects */ - if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) { - CTFPOOL_UNLOCK(osh->ctfpool, flags); - return NULL; - } - - /* Allocate a new skb and add it to the ctfpool */ - skb = osl_alloc_skb(osh, osh->ctfpool->obj_size); - if (skb == NULL) { - printf("%s: skb alloc of len %d failed\n", __FUNCTION__, - osh->ctfpool->obj_size); - CTFPOOL_UNLOCK(osh->ctfpool, flags); - return NULL; - } - - /* Add to ctfpool */ - skb->next = (struct sk_buff *)osh->ctfpool->head; - osh->ctfpool->head = skb; - osh->ctfpool->fast_frees++; - osh->ctfpool->curr_obj++; - - /* Hijack a skb member to store ptr to ctfpool */ - CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool; - - /* Use bit flag to indicate skb from fast ctfpool */ - PKTFAST(osh, skb) = FASTBUF; - - CTFPOOL_UNLOCK(osh->ctfpool, flags); - - return skb; -} - -/* - * Add new objects to the pool. - */ -void -osl_ctfpool_replenish(osl_t *osh, uint thresh) -{ - if ((osh == NULL) || (osh->ctfpool == NULL)) - return; - - /* Do nothing if no refills are required */ - while ((osh->ctfpool->refills > 0) && (thresh--)) { - osl_ctfpool_add(osh); - osh->ctfpool->refills--; - } -} - -/* - * Initialize the packet pool with specified number of objects. - */ -int32 -osl_ctfpool_init(osl_t *osh, uint numobj, uint size) -{ - gfp_t flags; - - flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; - osh->ctfpool = kzalloc(sizeof(ctfpool_t), flags); - ASSERT(osh->ctfpool); - - osh->ctfpool->max_obj = numobj; - osh->ctfpool->obj_size = size; - - spin_lock_init(&osh->ctfpool->lock); - - while (numobj--) { - if (!osl_ctfpool_add(osh)) - return -1; - osh->ctfpool->fast_frees--; - } - - return 0; -} - -/* - * Cleanup the packet pool objects. - */ -void -osl_ctfpool_cleanup(osl_t *osh) -{ - struct sk_buff *skb, *nskb; -#ifdef CTFPOOL_SPINLOCK - unsigned long flags; -#endif /* CTFPOOL_SPINLOCK */ - - if ((osh == NULL) || (osh->ctfpool == NULL)) - return; - - CTFPOOL_LOCK(osh->ctfpool, flags); - - skb = osh->ctfpool->head; - - while (skb != NULL) { - nskb = skb->next; - dev_kfree_skb(skb); - skb = nskb; - osh->ctfpool->curr_obj--; - } - - ASSERT(osh->ctfpool->curr_obj == 0); - osh->ctfpool->head = NULL; - CTFPOOL_UNLOCK(osh->ctfpool, flags); - - kfree(osh->ctfpool); - osh->ctfpool = NULL; -} - -void -osl_ctfpool_stats(osl_t *osh, void *b) -{ - struct bcmstrbuf *bb; - - if ((osh == NULL) || (osh->ctfpool == NULL)) - return; - -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (bcm_static_buf) { - bcm_static_buf = 0; - } - if (bcm_static_skb) { - bcm_static_skb = 0; - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - - bb = b; - - ASSERT((osh != NULL) && (bb != NULL)); - - bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n", - osh->ctfpool->max_obj, osh->ctfpool->obj_size, - osh->ctfpool->curr_obj, osh->ctfpool->refills); - bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n", - osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees, - osh->ctfpool->slow_allocs); -} - -static inline struct sk_buff * -osl_pktfastget(osl_t *osh, uint len) -{ - struct sk_buff *skb; -#ifdef CTFPOOL_SPINLOCK - unsigned long flags; -#endif /* CTFPOOL_SPINLOCK */ - - /* Try to do fast allocate. Return null if ctfpool is not in use - * or if there are no items in the ctfpool. - */ - if (osh->ctfpool == NULL) - return NULL; - - CTFPOOL_LOCK(osh->ctfpool, flags); - if (osh->ctfpool->head == NULL) { - ASSERT(osh->ctfpool->curr_obj == 0); - osh->ctfpool->slow_allocs++; - CTFPOOL_UNLOCK(osh->ctfpool, flags); - return NULL; - } - - if (len > osh->ctfpool->obj_size) { - CTFPOOL_UNLOCK(osh->ctfpool, flags); - return NULL; - } - - ASSERT(len <= osh->ctfpool->obj_size); - - /* Get an object from ctfpool */ - skb = (struct sk_buff *)osh->ctfpool->head; - osh->ctfpool->head = (void *)skb->next; - - osh->ctfpool->fast_allocs++; - osh->ctfpool->curr_obj--; - ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head); - CTFPOOL_UNLOCK(osh->ctfpool, flags); - - /* Init skb struct */ - skb->next = skb->prev = NULL; -#if defined(__ARM_ARCH_7A__) - skb->data = skb->head + NET_SKB_PAD; - skb->tail = skb->head + NET_SKB_PAD; -#else - skb->data = skb->head + 16; - skb->tail = skb->head + 16; -#endif /* __ARM_ARCH_7A__ */ - skb->len = 0; - skb->cloned = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) - skb->list = NULL; -#endif - atomic_set(&skb->users, 1); - - PKTSETCLINK(skb, NULL); - PKTCCLRATTR(skb); - PKTFAST(osh, skb) &= ~(CTFBUF | SKIPCT | CHAINED); - - return skb; -} -#endif /* CTFPOOL */ - -#if defined(BCM_GMAC3) -/* Account for a packet delivered to downstream forwarder. - * Decrement a GMAC forwarder interface's pktalloced count. - */ -void BCMFASTPATH -osl_pkt_tofwder(osl_t *osh, void *skbs, int skb_cnt) -{ - - atomic_sub(skb_cnt, &osh->cmn->pktalloced); -} - -/* Account for a downstream forwarder delivered packet to a WL/DHD driver. - * Increment a GMAC forwarder interface's pktalloced count. - */ -void BCMFASTPATH -osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt) -{ - - - atomic_add(skb_cnt, &osh->cmn->pktalloced); -} - -#endif /* BCM_GMAC3 */ - -/* Convert a driver packet to native(OS) packet - * In the process, packettag is zeroed out before sending up - * IP code depends on skb->cb to be setup correctly with various options - * In our case, that means it should be 0 - */ -struct sk_buff * BCMFASTPATH -osl_pkt_tonative(osl_t *osh, void *pkt) -{ - struct sk_buff *nskb; - - if (osh->pub.pkttag) - OSL_PKTTAG_CLEAR(pkt); - - /* Decrement the packet counter */ - for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { - atomic_sub(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced); - - } - return (struct sk_buff *)pkt; -} - -/* Convert a native(OS) packet to driver packet. - * In the process, native packet is destroyed, there is no copying - * Also, a packettag is zeroed out - */ -void * BCMFASTPATH -osl_pkt_frmnative(osl_t *osh, void *pkt) -{ - struct sk_buff *nskb; - - if (osh->pub.pkttag) - OSL_PKTTAG_CLEAR(pkt); - - /* Increment the packet counter */ - for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { - atomic_add(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced); - - } - return (void *)pkt; -} - -/* Return a new packet. zero out pkttag */ -void * BCMFASTPATH -osl_pktget(osl_t *osh, uint len) -{ - struct sk_buff *skb; - uchar num = 0; - if (lmtest != FALSE) { - get_random_bytes(&num, sizeof(uchar)); - if ((num + 1) <= (256 * lmtest / 100)) - return NULL; - } - -#ifdef CTFPOOL - /* Allocate from local pool */ - skb = osl_pktfastget(osh, len); - if ((skb != NULL) || ((skb = osl_alloc_skb(osh, len)) != NULL)) { -#else /* CTFPOOL */ - if ((skb = osl_alloc_skb(osh, len))) { -#endif /* CTFPOOL */ - skb->tail += len; - skb->len += len; - skb->priority = 0; - - atomic_inc(&osh->cmn->pktalloced); - } - - return ((void*) skb); -} - -#ifdef CTFPOOL -static inline void -osl_pktfastfree(osl_t *osh, struct sk_buff *skb) -{ - ctfpool_t *ctfpool; -#ifdef CTFPOOL_SPINLOCK - unsigned long flags; -#endif /* CTFPOOL_SPINLOCK */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) - skb->tstamp.tv.sec = 0; -#else - skb->stamp.tv_sec = 0; -#endif - - /* We only need to init the fields that we change */ - skb->dev = NULL; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) - skb->dst = NULL; -#endif - OSL_PKTTAG_CLEAR(skb); - skb->ip_summed = 0; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - skb_orphan(skb); -#else - skb->destructor = NULL; -#endif - - ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); - ASSERT(ctfpool != NULL); - - /* Add object to the ctfpool */ - CTFPOOL_LOCK(ctfpool, flags); - skb->next = (struct sk_buff *)ctfpool->head; - ctfpool->head = (void *)skb; - - ctfpool->fast_frees++; - ctfpool->curr_obj++; - - ASSERT(ctfpool->curr_obj <= ctfpool->max_obj); - CTFPOOL_UNLOCK(ctfpool, flags); -} -#endif /* CTFPOOL */ - -/* Free the driver packet. Free the tag if present */ -void BCMFASTPATH -osl_pktfree(osl_t *osh, void *p, bool send) -{ - struct sk_buff *skb, *nskb; - if (osh == NULL) - return; - - skb = (struct sk_buff*) p; - - if (send && osh->pub.tx_fn) - osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); - - PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE); - -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (skb && (skb->mac_len == PREALLOC_USED_MAGIC)) { - printk("%s: pkt %p is from static pool\n", - __FUNCTION__, p); - - dump_stack(); - return; - } - - if (skb && (skb->mac_len == PREALLOC_FREE_MAGIC)) { - printk("%s: pkt %p is from static pool and not in used\n", - __FUNCTION__, p); - dump_stack(); - return; - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - - /* perversion: we use skb->next to chain multi-skb packets */ - while (skb) { - nskb = skb->next; - skb->next = NULL; - - - -#ifdef CTFPOOL - if (PKTISFAST(osh, skb)) { - if (atomic_read(&skb->users) == 1) - smp_rmb(); - else if (!atomic_dec_and_test(&skb->users)) - goto next_skb; - osl_pktfastfree(osh, skb); - } else -#endif - { - dev_kfree_skb_any(skb); - } -#ifdef CTFPOOL -next_skb: -#endif - atomic_dec(&osh->cmn->pktalloced); - skb = nskb; - } -} - -#ifdef CONFIG_DHD_USE_STATIC_BUF -void* -osl_pktget_static(osl_t *osh, uint len) -{ - int i = 0; - struct sk_buff *skb; -#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) - unsigned long flags; -#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ - void *p; - - if (!bcm_static_skb) - return osl_pktget(osh, len); - - if (len > DHD_SKB_MAX_BUFSIZE) { - printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len); - p = osl_pktget(osh, len); - return p; - } - -#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) - spin_lock_irqsave(&bcm_static_skb->osl_pkt_lock, flags); - - if (len <= DHD_SKB_2PAGE_BUFSIZE) { - uint32 index; - for (i = 0; i < STATIC_PKT_2PAGE_NUM; i++) { - index = bcm_static_skb->last_allocated_index % STATIC_PKT_2PAGE_NUM; - bcm_static_skb->last_allocated_index++; - if (bcm_static_skb->skb_8k[index] && - bcm_static_skb->pkt_use[index] == 0 && - bcm_static_skb->pkt_invalid[index] == 0) { - break; - } - } - - if ((i != STATIC_PKT_2PAGE_NUM) && - (index >= 0) && (index < STATIC_PKT_2PAGE_NUM)) { - bcm_static_skb->pkt_use[index] = 1; - skb = bcm_static_skb->skb_8k[index]; - skb->data = skb->head + NET_SKB_PAD; - skb->cloned = 0; - skb->priority = 0; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb_set_tail_pointer(skb, len); -#else - skb->tail = skb->data + len; -#endif /* NET_SKBUFF_DATA_USES_OFFSET */ - skb->len = len; - skb->mac_len = PREALLOC_USED_MAGIC; - spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); - return skb; - } - } - - spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); - printk("%s: all static pkt in use!\n", __FUNCTION__); - return NULL; -#else - down(&bcm_static_skb->osl_pkt_sem); - - if (len <= DHD_SKB_1PAGE_BUFSIZE) { - for (i = 0; i < STATIC_PKT_1PAGE_NUM; i++) { - if (bcm_static_skb->skb_4k[i] && - bcm_static_skb->pkt_use[i] == 0) { - break; - } - } - - if (i != STATIC_PKT_1PAGE_NUM) { - bcm_static_skb->pkt_use[i] = 1; - - skb = bcm_static_skb->skb_4k[i]; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb_set_tail_pointer(skb, len); -#else - skb->tail = skb->data + len; -#endif /* NET_SKBUFF_DATA_USES_OFFSET */ - skb->len = len; - - up(&bcm_static_skb->osl_pkt_sem); - return skb; - } - } - - if (len <= DHD_SKB_2PAGE_BUFSIZE) { - for (i = STATIC_PKT_1PAGE_NUM; i < STATIC_PKT_1_2PAGE_NUM; i++) { - if (bcm_static_skb->skb_8k[i - STATIC_PKT_1PAGE_NUM] && - bcm_static_skb->pkt_use[i] == 0) { - break; - } - } - - if ((i >= STATIC_PKT_1PAGE_NUM) && (i < STATIC_PKT_1_2PAGE_NUM)) { - bcm_static_skb->pkt_use[i] = 1; - skb = bcm_static_skb->skb_8k[i - STATIC_PKT_1PAGE_NUM]; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb_set_tail_pointer(skb, len); -#else - skb->tail = skb->data + len; -#endif /* NET_SKBUFF_DATA_USES_OFFSET */ - skb->len = len; - - up(&bcm_static_skb->osl_pkt_sem); - return skb; - } - } - -#if defined(ENHANCED_STATIC_BUF) - if (bcm_static_skb->skb_16k && - bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] == 0) { - bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] = 1; - - skb = bcm_static_skb->skb_16k; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb_set_tail_pointer(skb, len); -#else - skb->tail = skb->data + len; -#endif /* NET_SKBUFF_DATA_USES_OFFSET */ - skb->len = len; - - up(&bcm_static_skb->osl_pkt_sem); - return skb; - } -#endif /* ENHANCED_STATIC_BUF */ - up(&bcm_static_skb->osl_pkt_sem); -#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ - - p = osl_pktget(osh, len); - return p; -} - -void -osl_pktfree_static(osl_t *osh, void *p, bool send) -{ - int i; -#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) - struct sk_buff *skb = p; - unsigned long flags; -#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ - - if (!p) { - return; - } - - if (!bcm_static_skb) { - osl_pktfree(osh, p, send); - return; - } - -#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) - spin_lock_irqsave(&bcm_static_skb->osl_pkt_lock, flags); - - for (i = 0; i < STATIC_PKT_2PAGE_NUM; i++) { - if (p == bcm_static_skb->skb_8k[i]) { - if (bcm_static_skb->pkt_invalid[i] != 0) { - printk("%s: static pkt idx %d(%p) is invalid\n", - __FUNCTION__, i, p); - } else if (bcm_static_skb->pkt_use[i] == 0) { - printk("%s: static pkt idx %d(%p) is double free\n", - __FUNCTION__, i, p); - } else { - bcm_static_skb->pkt_use[i] = 0; - } - - if (skb->mac_len != PREALLOC_USED_MAGIC) { - printk("%s: static pkt idx %d(%p) is not in used\n", - __FUNCTION__, i, p); - } - - skb->mac_len = PREALLOC_FREE_MAGIC; - spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); - return; - } - } - - spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); - printk("%s: packet %p does not exist in the pool\n", __FUNCTION__, p); -#else - down(&bcm_static_skb->osl_pkt_sem); - - for (i = 0; i < STATIC_PKT_1PAGE_NUM; i++) { - if (p == bcm_static_skb->skb_4k[i]) { - if (bcm_static_skb->pkt_use[i] == 0) - printk("[WLAN] %s: double free! %d p %p\n", __FUNCTION__, i, p); - bcm_static_skb->pkt_use[i] = 0; - up(&bcm_static_skb->osl_pkt_sem); - return; - } - } - - for (i = STATIC_PKT_1PAGE_NUM; i < STATIC_PKT_1_2PAGE_NUM; i++) { - if (p == bcm_static_skb->skb_8k[i - STATIC_PKT_1PAGE_NUM]) { - if (bcm_static_skb->pkt_use[i] == 0) - printk("[WLAN] %s: double free! %d p %p\n", __FUNCTION__, i, p); - bcm_static_skb->pkt_use[i] = 0; - up(&bcm_static_skb->osl_pkt_sem); - return; - } - } -#ifdef ENHANCED_STATIC_BUF - if (p == bcm_static_skb->skb_16k) { - bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] = 0; - up(&bcm_static_skb->osl_pkt_sem); - return; - } -#endif /* ENHANCED_STATIC_BUF */ - up(&bcm_static_skb->osl_pkt_sem); - osl_pktfree(osh, p, send); -#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ -} - -#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) -void -osl_pktinvalidate_static(osl_t *osh, void *p) -{ - int i; - unsigned long flags; - - if (!bcm_static_skb) { - return; - } - - spin_lock_irqsave(&bcm_static_skb->osl_pkt_lock, flags); - for (i = 0; i < STATIC_PKT_2PAGE_NUM; i++) { - if (p == bcm_static_skb->skb_8k[i]) { - bcm_static_skb->pkt_invalid[i] = 1; - bcm_static_skb->pkt_use[i] = 1; - break; - } - } - - if (i == STATIC_PKT_2PAGE_NUM) { - printk("%s: pkt=%p isn't static pkt pool\n", __FUNCTION__, p); - } - spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); -} -#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - -uint32 -osl_pci_read_config(osl_t *osh, uint offset, uint size) -{ - uint val = 0; - uint retry = PCI_CFG_RETRY; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - - /* only 4byte access supported */ - ASSERT(size == 4); - - do { - pci_read_config_dword(osh->pdev, offset, &val); - if (val != 0xffffffff) - break; - } while (retry--); - - - return (val); -} - -void -osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) -{ - uint retry = PCI_CFG_RETRY; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - - /* only 4byte access supported */ - ASSERT(size == 4); - - do { - pci_write_config_dword(osh->pdev, offset, val); - if (offset != PCI_BAR0_WIN) - break; - if (osl_pci_read_config(osh, offset, size) == val) - break; - } while (retry--); - -} - -/* return bus # for the pci device pointed by osh->pdev */ -uint -osl_pci_bus(osl_t *osh) -{ - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); - -#if defined(__ARM_ARCH_7A__) && LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35) - return pci_domain_nr(((struct pci_dev *)osh->pdev)->bus); -#else - return ((struct pci_dev *)osh->pdev)->bus->number; -#endif -} - -/* return slot # for the pci device pointed by osh->pdev */ -uint -osl_pci_slot(osl_t *osh) -{ - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); - -#if defined(__ARM_ARCH_7A__) && LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35) - return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn) + 1; -#else - return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); -#endif -} - -/* return domain # for the pci device pointed by osh->pdev */ -uint -osl_pcie_domain(osl_t *osh) -{ - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); - - return pci_domain_nr(((struct pci_dev *)osh->pdev)->bus); -} - -/* return bus # for the pci device pointed by osh->pdev */ -uint -osl_pcie_bus(osl_t *osh) -{ - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); - - return ((struct pci_dev *)osh->pdev)->bus->number; -} - -/* return the pci device pointed by osh->pdev */ -struct pci_dev * -osl_pci_device(osl_t *osh) -{ - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); - - return osh->pdev; -} - -static void -osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) -{ -} - -void -osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size) -{ - osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE); -} - -void -osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) -{ - osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); -} - -void * -osl_malloc(osl_t *osh, uint size) -{ - void *addr; - gfp_t flags; - - /* only ASSERT if osh is defined */ - if (osh) - ASSERT(osh->magic == OS_HANDLE_MAGIC); -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (bcm_static_buf) - { - unsigned long irq_flags; - int i = 0; - if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE)) - { - spin_lock_irqsave(&bcm_static_buf->static_lock, irq_flags); - - for (i = 0; i < STATIC_BUF_MAX_NUM; i++) - { - if (bcm_static_buf->buf_use[i] == 0) - break; - } - - if (i == STATIC_BUF_MAX_NUM) - { - spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); - printk("all static buff in use!\n"); - goto original; - } - - bcm_static_buf->buf_use[i] = 1; - spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); - - bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size); - if (osh) - atomic_add(size, &osh->cmn->malloced); - - return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i)); - } - } -original: -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - - flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; - if ((addr = kmalloc(size, flags)) == NULL) { - if (osh) - osh->failed++; - return (NULL); - } - if (osh && osh->cmn) - atomic_add(size, &osh->cmn->malloced); - - return (addr); -} - -void * -osl_mallocz(osl_t *osh, uint size) -{ - void *ptr; - - ptr = osl_malloc(osh, size); - - if (ptr != NULL) { - bzero(ptr, size); - } - - return ptr; -} - -void -osl_mfree(osl_t *osh, void *addr, uint size) -{ -#ifdef CONFIG_DHD_USE_STATIC_BUF - unsigned long flags; - - if (bcm_static_buf) - { - if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr - <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN))) - { - int buf_idx = 0; - - buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE; - - spin_lock_irqsave(&bcm_static_buf->static_lock, flags); - bcm_static_buf->buf_use[buf_idx] = 0; - spin_unlock_irqrestore(&bcm_static_buf->static_lock, flags); - - if (osh && osh->cmn) { - ASSERT(osh->magic == OS_HANDLE_MAGIC); - atomic_sub(size, &osh->cmn->malloced); - } - return; - } - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - if (osh && osh->cmn) { - ASSERT(osh->magic == OS_HANDLE_MAGIC); - - ASSERT(size <= osl_malloced(osh)); - - atomic_sub(size, &osh->cmn->malloced); - } - kfree(addr); -} - -uint -osl_check_memleak(osl_t *osh) -{ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - if (atomic_read(&osh->cmn->refcount) == 1) - return (atomic_read(&osh->cmn->malloced)); - else - return 0; -} - -uint -osl_malloced(osl_t *osh) -{ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - return (atomic_read(&osh->cmn->malloced)); -} - -uint -osl_malloc_failed(osl_t *osh) -{ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - return (osh->failed); -} - - -uint -osl_dma_consistent_align(void) -{ - return (PAGE_SIZE); -} - -void* -osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, dmaaddr_t *pap) -{ - void *va; - uint16 align = (1 << align_bits); - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - - if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) - size += align; - *alloced = size; - -#if defined(USE_KMALLOC_FOR_FLOW_RING) && defined(__ARM_ARCH_7A__) - va = kmalloc(size, GFP_ATOMIC | __GFP_ZERO); - if (va) - *pap = (ulong)__virt_to_phys((ulong)va); -#else - { - dma_addr_t pap_lin; - struct pci_dev *hwdev = osh->pdev; -#ifdef PCIE_TX_DEFERRAL - va = dma_alloc_coherent(&hwdev->dev, size, &pap_lin, GFP_KERNEL); -#else - va = dma_alloc_coherent(&hwdev->dev, size, &pap_lin, GFP_ATOMIC); -#endif - *pap = (dmaaddr_t)pap_lin; - } -#endif - - return va; -} - -void -osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa) -{ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - -#if defined(USE_KMALLOC_FOR_FLOW_RING) && defined(__ARM_ARCH_7A__) - kfree(va); -#else - pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); -#endif -} - -dmaaddr_t BCMFASTPATH -osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah) -{ - int dir; - dmaaddr_t ret_addr; - dma_addr_t map_addr; - int ret; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; - -#if defined(__ARM_ARCH_7A__) && defined(BCMDMASGLISTOSL) - if (dmah != NULL) { - int32 nsegs, i, totsegs = 0, totlen = 0; - struct scatterlist *sg, _sg[MAX_DMA_SEGS * 2]; - struct sk_buff *skb; - for (skb = (struct sk_buff *)p; skb != NULL; skb = PKTNEXT(osh, skb)) { - sg = &_sg[totsegs]; - if (skb_is_nonlinear(skb)) { - nsegs = skb_to_sgvec(skb, sg, 0, PKTLEN(osh, skb)); - ASSERT((nsegs > 0) && (totsegs + nsegs <= MAX_DMA_SEGS)); - pci_map_sg(osh->pdev, sg, nsegs, dir); - } else { - nsegs = 1; - ASSERT(totsegs + nsegs <= MAX_DMA_SEGS); - sg->page_link = 0; - sg_set_buf(sg, PKTDATA(osh, skb), PKTLEN(osh, skb)); - pci_map_single(osh->pdev, PKTDATA(osh, skb), PKTLEN(osh, skb), dir); - } - totsegs += nsegs; - totlen += PKTLEN(osh, skb); - } - dmah->nsegs = totsegs; - dmah->origsize = totlen; - for (i = 0, sg = _sg; i < totsegs; i++, sg++) { - dmah->segs[i].addr = sg_phys(sg); - dmah->segs[i].length = sg->length; - } - return dmah->segs[0].addr; - } -#endif /* __ARM_ARCH_7A__ && BCMDMASGLISTOSL */ - - - map_addr = pci_map_single(osh->pdev, va, size, dir); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - ret = pci_dma_mapping_error(osh->pdev, map_addr); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 5)) - ret = pci_dma_mapping_error(map_addr); -#else - ret = 0; -#endif - if (ret) { - printk("%s: Failed to map memory\n", __FUNCTION__); - PHYSADDRLOSET(ret_addr, 0); - PHYSADDRHISET(ret_addr, 0); - } else { - PHYSADDRLOSET(ret_addr, map_addr & 0xffffffff); - PHYSADDRHISET(ret_addr, (map_addr >> 32) & 0xffffffff); - } - - return ret_addr; -} - -void BCMFASTPATH -osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) -{ - int dir; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; - pci_unmap_single(osh->pdev, (uint32)pa, size, dir); -} - -/* OSL function for CPU relax */ -inline void BCMFASTPATH -osl_cpu_relax(void) -{ - cpu_relax(); -} - - -#if defined(USE_KMALLOC_FOR_FLOW_RING) && defined(__ARM_ARCH_7A__) || \ - defined(CONFIG_ARCH_MSM8994) - -#include - -/* - * Note that its gauranteed that the Ring is cache line aligned, but - * the messages are not. And we see that __dma_inv_range in - * arch/arm64/mm/cache.S invalidates only if the request size is - * cache line aligned. If not, it will Clean and invalidate. - * So we'll better invalidate the whole ring. - * - * Also, the latest Kernel versions invoke cache maintenance operations - * from arch/arm64/mm/dma-mapping.c, __swiotlb_sync_single_for_device - * Only if is_device_dma_coherent returns 0. Since we don't have BSP - * source, assuming that its the case, since we pass NULL for the dev ptr - */ -inline void BCMFASTPATH -osl_cache_flush(void *va, uint size) -{ - /* - * using long for address arithmatic is OK, in linux - * 32 bit its 4 bytes and 64 bit its 8 bytes - */ - unsigned long end_cache_line_start; - unsigned long end_addr; - unsigned long next_cache_line_start; - - end_addr = (unsigned long)va + size; - - /* Start address beyond the cache line we plan to operate */ - end_cache_line_start = (end_addr & ~(L1_CACHE_BYTES - 1)); - next_cache_line_start = end_cache_line_start + L1_CACHE_BYTES; - - /* Align the start address to cache line boundary */ - va = (void *)((unsigned long)va & ~(L1_CACHE_BYTES - 1)); - - /* Ensure that size is also aligned and extends partial line to full */ - size = next_cache_line_start - (unsigned long)va; - - -#ifdef CONFIG_ARM64 - /* - * virt_to_dma is not present in arm64/include/dma-mapping.h - * So have to convert the va to pa first and then get the dma addr - * of the same. - */ - { - phys_addr_t pa; - dma_addr_t dma_addr; - pa = virt_to_phys(va); - dma_addr = phys_to_dma(NULL, pa); - if (size > 0) - dma_sync_single_for_device(OSH_NULL, dma_addr, size, DMA_TX); - } -#else - if (size > 0) - dma_sync_single_for_device(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_TX); -#endif /* !CONFIG_ARM64 */ -} - -inline void BCMFASTPATH -osl_cache_inv(void *va, uint size) -{ - /* - * using long for address arithmatic is OK, in linux - * 32 bit its 4 bytes and 64 bit its 8 bytes - */ - unsigned long end_cache_line_start; - unsigned long end_addr; - unsigned long next_cache_line_start; - - end_addr = (unsigned long)va + size; - - /* Start address beyond the cache line we plan to operate */ - end_cache_line_start = (end_addr & ~(L1_CACHE_BYTES - 1)); - next_cache_line_start = end_cache_line_start + L1_CACHE_BYTES; - - /* Align the start address to cache line boundary */ - va = (void *)((unsigned long)va & ~(L1_CACHE_BYTES - 1)); - - /* Ensure that size is also aligned and extends partial line to full */ - size = next_cache_line_start - (unsigned long)va; - -#ifdef CONFIG_ARM64 - /* - * virt_to_dma is not present in arm64/include/dma-mapping.h - * So have to convert the va to pa first and then get the dma addr - * of the same. - */ - { - phys_addr_t pa; - dma_addr_t dma_addr; - pa = virt_to_phys(va); - dma_addr = phys_to_dma(NULL, pa); - dma_sync_single_for_cpu(OSH_NULL, dma_addr, size, DMA_RX); - } -#else - dma_sync_single_for_cpu(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_RX); -#endif /* !CONFIG_ARM64 */ - -} - -inline void osl_prefetch(const void *ptr) -{ - /* PLD instruction is not applicable in ARM 64. We don't care for now */ -#ifndef CONFIG_ARM64 - __asm__ __volatile__("pld\t%0" :: "o"(*(char *)ptr) : "cc"); -#endif /* !CONFIG_ARM64 */ -} - -int osl_arch_is_coherent(void) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) - return 0; -#else - return arch_is_coherent(); -#endif -} -#endif - -#if defined(BCMASSERT_LOG) -void -osl_assert(const char *exp, const char *file, int line) -{ - char tempbuf[256]; - const char *basename; - - basename = strrchr(file, '/'); - /* skip the '/' */ - if (basename) - basename++; - - if (!basename) - basename = file; - -#ifdef BCMASSERT_LOG - snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", - exp, basename, line); - printk("%s", tempbuf); -#endif /* BCMASSERT_LOG */ - - -} -#endif - -void -osl_delay(uint usec) -{ - uint d; - - while (usec > 0) { - d = MIN(usec, 1000); - udelay(d); - usec -= d; - } -} - -void -osl_sleep(uint ms) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - if (ms < 20) - usleep_range(ms*1000, ms*1000 + 1000); - else -#endif - msleep(ms); -} - - - -/* Clone a packet. - * The pkttag contents are NOT cloned. - */ -void * -osl_pktdup(osl_t *osh, void *skb) -{ - void * p; - - ASSERT(!PKTISCHAINED(skb)); - - /* clear the CTFBUF flag if set and map the rest of the buffer - * before cloning. - */ - PKTCTFMAP(osh, skb); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - if ((p = pskb_copy((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) -#else - if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) -#endif - return NULL; - -#ifdef CTFPOOL - if (PKTISFAST(osh, skb)) { - ctfpool_t *ctfpool; - - /* if the buffer allocated from ctfpool is cloned then - * we can't be sure when it will be freed. since there - * is a chance that we will be losing a buffer - * from our pool, we increment the refill count for the - * object to be alloced later. - */ - ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); - ASSERT(ctfpool != NULL); - PKTCLRFAST(osh, p); - PKTCLRFAST(osh, skb); - ctfpool->refills++; - } -#endif /* CTFPOOL */ - - /* Clear PKTC context */ - PKTSETCLINK(p, NULL); - PKTCCLRFLAGS(p); - PKTCSETCNT(p, 1); - PKTCSETLEN(p, PKTLEN(osh, skb)); - - /* skb_clone copies skb->cb.. we don't want that */ - if (osh->pub.pkttag) - OSL_PKTTAG_CLEAR(p); - - /* Increment the packet counter */ - atomic_inc(&osh->cmn->pktalloced); - return (p); -} - - - -/* - * OSLREGOPS specifies the use of osl_XXX routines to be used for register access - */ - -/* - * BINOSL selects the slightly slower function-call-based binary compatible osl. - */ - -uint -osl_pktalloced(osl_t *osh) -{ - if (atomic_read(&osh->cmn->refcount) == 1) - return (atomic_read(&osh->cmn->pktalloced)); - else - return 0; -} - -uint32 -osl_rand(void) -{ - uint32 rand; - - get_random_bytes(&rand, sizeof(rand)); - - return rand; -} - -/* Linux Kernel: File Operations: start */ -void * -osl_os_open_image(char *filename) -{ - struct file *fp; - - fp = filp_open(filename, O_RDONLY, 0); - /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? - * Alternative: - * fp = open_namei(AT_FDCWD, filename, O_RD, 0); - * ??? - */ - if (IS_ERR(fp)) - fp = NULL; - - return fp; -} - -int -osl_os_get_image_block(char *buf, int len, void *image) -{ - struct file *fp = (struct file *)image; - int rdlen; - - if (!image) - return 0; - - rdlen = kernel_read(fp, fp->f_pos, buf, len); - if (rdlen > 0) - fp->f_pos += rdlen; - - return rdlen; -} - -void -osl_os_close_image(void *image) -{ - if (image) - filp_close((struct file *)image, NULL); -} - -int -osl_os_image_size(void *image) -{ - int len = 0, curroffset; - - if (image) { - /* store the current offset */ - curroffset = generic_file_llseek(image, 0, 1); - /* goto end of file to get length */ - len = generic_file_llseek(image, 0, 2); - /* restore back the offset */ - generic_file_llseek(image, curroffset, 0); - } - return len; -} - -/* Linux Kernel: File Operations: end */ - - -/* APIs to set/get specific quirks in OSL layer */ -void -osl_flag_set(osl_t *osh, uint32 mask) -{ - osh->flags |= mask; -} - -bool -osl_is_flag_set(osl_t *osh, uint32 mask) -{ - return (osh->flags & mask); -} diff --git a/drivers/net/wireless/bcmdhd/pcie_core.c b/drivers/net/wireless/bcmdhd/pcie_core.c deleted file mode 100644 index b085f161715f..000000000000 --- a/drivers/net/wireless/bcmdhd/pcie_core.c +++ /dev/null @@ -1,88 +0,0 @@ -/** @file pcie_core.c - * - * Contains PCIe related functions that are shared between different driver models (e.g. firmware - * builds, DHD builds, BMAC builds), in order to avoid code duplication. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: pcie_core.c 444841 2013-12-21 04:32:29Z $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pcie_core.h" - -/* local prototypes */ - -/* local variables */ - -/* function definitions */ - -#ifdef BCMDRIVER - -void pcie_watchdog_reset(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs) -{ - uint32 val, i, lsc; - uint16 cfg_offset[] = {PCIECFGREG_STATUS_CMD, PCIECFGREG_PM_CSR, - PCIECFGREG_MSI_CAP, PCIECFGREG_MSI_ADDR_L, - PCIECFGREG_MSI_ADDR_H, PCIECFGREG_MSI_DATA, - PCIECFGREG_LINK_STATUS_CTRL2, PCIECFGREG_RBAR_CTRL, - PCIECFGREG_PML1_SUB_CTRL1, PCIECFGREG_REG_BAR2_CONFIG, - PCIECFGREG_REG_BAR3_CONFIG}; - sbpcieregs_t *pcie = NULL; - uint32 origidx = si_coreidx(sih); - - /* Switch to PCIE2 core */ - pcie = (sbpcieregs_t *)si_setcore(sih, PCIE2_CORE_ID, 0); - BCM_REFERENCE(pcie); - ASSERT(pcie != NULL); - - /* Disable/restore ASPM Control to protect the watchdog reset */ - W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); - lsc = R_REG(osh, &sbpcieregs->configdata); - val = lsc & (~PCIE_ASPM_ENAB); - W_REG(osh, &sbpcieregs->configdata, val); - - si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, 4); - OSL_DELAY(100000); - - W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); - W_REG(osh, &sbpcieregs->configdata, lsc); - - /* Write configuration registers back to the shadow registers - * cause shadow registers are cleared out after watchdog reset. - */ - for (i = 0; i < ARRAYSIZE(cfg_offset); i++) { - W_REG(osh, &sbpcieregs->configaddr, cfg_offset[i]); - val = R_REG(osh, &sbpcieregs->configdata); - W_REG(osh, &sbpcieregs->configdata, val); - } - si_setcoreidx(sih, origidx); -} - -#endif /* BCMDRIVER */ diff --git a/drivers/net/wireless/bcmdhd/sbutils.c b/drivers/net/wireless/bcmdhd/sbutils.c deleted file mode 100644 index 473f8dcc6c92..000000000000 --- a/drivers/net/wireless/bcmdhd/sbutils.c +++ /dev/null @@ -1,1105 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbutils.c 467150 2014-04-02 17:30:43Z $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "siutils_priv.h" - - -/* local prototypes */ -static uint _sb_coreidx(si_info_t *sii, uint32 sba); -static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, - uint ncores); -static uint32 _sb_coresba(si_info_t *sii); -static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); -#define SET_SBREG(sii, r, mask, val) \ - W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) -#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) - -/* sonicsrev */ -#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) -#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT) - -#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr)) -#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v)) -#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v))) -#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v))) - -static uint32 -sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) -{ - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint8 tmp; - uint32 val, intr_val = 0; - - - /* - * compact flash only has 11 bits address, while we needs 12 bits address. - * MEM_SEG will be OR'd with other 11 bits address in hardware, - * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). - * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special - */ - if (PCMCIA(sii)) { - INTR_OFF(sii, intr_val); - tmp = 1; - OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); - sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ - } - - val = R_REG(sii->osh, sbr); - - if (PCMCIA(sii)) { - tmp = 0; - OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); - INTR_RESTORE(sii, intr_val); - } - - return (val); -} - -static void -sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) -{ - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint8 tmp; - volatile uint32 dummy; - uint32 intr_val = 0; - - - /* - * compact flash only has 11 bits address, while we needs 12 bits address. - * MEM_SEG will be OR'd with other 11 bits address in hardware, - * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). - * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special - */ - if (PCMCIA(sii)) { - INTR_OFF(sii, intr_val); - tmp = 1; - OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); - sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ - } - - if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { - dummy = R_REG(sii->osh, sbr); - BCM_REFERENCE(dummy); - W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); - dummy = R_REG(sii->osh, sbr); - BCM_REFERENCE(dummy); - W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); - } else - W_REG(sii->osh, sbr, v); - - if (PCMCIA(sii)) { - tmp = 0; - OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); - INTR_RESTORE(sii, intr_val); - } -} - -uint -sb_coreid(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); -} - -uint -sb_intflag(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - void *corereg; - sbconfig_t *sb; - uint origidx, intflag, intr_val = 0; - - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - corereg = si_setcore(sih, CC_CORE_ID, 0); - ASSERT(corereg != NULL); - sb = REGS2SB(corereg); - intflag = R_SBREG(sii, &sb->sbflagst); - sb_setcoreidx(sih, origidx); - INTR_RESTORE(sii, intr_val); - - return intflag; -} - -uint -sb_flag(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK; -} - -void -sb_setint(si_t *sih, int siflag) -{ - si_info_t *sii; - sbconfig_t *sb; - uint32 vec; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - if (siflag == -1) - vec = 0; - else - vec = 1 << siflag; - W_SBREG(sii, &sb->sbintvec, vec); -} - -/* return core index of the core with address 'sba' */ -static uint -_sb_coreidx(si_info_t *sii, uint32 sba) -{ - uint i; - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - for (i = 0; i < sii->numcores; i ++) - if (sba == cores_info->coresba[i]) - return i; - return BADIDX; -} - -/* return core address of the current core */ -static uint32 -_sb_coresba(si_info_t *sii) -{ - uint32 sbaddr; - - - switch (BUSTYPE(sii->pub.bustype)) { - case SI_BUS: { - sbconfig_t *sb = REGS2SB(sii->curmap); - sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0)); - break; - } - - case PCI_BUS: - sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); - break; - - case PCMCIA_BUS: { - uint8 tmp = 0; - OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); - sbaddr = (uint32)tmp << 12; - OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); - sbaddr |= (uint32)tmp << 16; - OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); - sbaddr |= (uint32)tmp << 24; - break; - } - -#ifdef BCMSDIO - case SPI_BUS: - case SDIO_BUS: - sbaddr = (uint32)(uintptr)sii->curmap; - break; -#endif - - - default: - sbaddr = BADCOREADDR; - break; - } - - return sbaddr; -} - -uint -sb_corevendor(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); -} - -uint -sb_corerev(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - uint sbidh; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - sbidh = R_SBREG(sii, &sb->sbidhigh); - - return (SBCOREREV(sbidh)); -} - -/* set core-specific control flags */ -void -sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii; - sbconfig_t *sb; - uint32 w; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - ASSERT((val & ~mask) == 0); - - /* mask and set */ - w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | - (val << SBTML_SICF_SHIFT); - W_SBREG(sii, &sb->sbtmstatelow, w); -} - -/* set/clear core-specific control flags */ -uint32 -sb_core_cflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii; - sbconfig_t *sb; - uint32 w; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - ASSERT((val & ~mask) == 0); - - /* mask and set */ - if (mask || val) { - w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | - (val << SBTML_SICF_SHIFT); - W_SBREG(sii, &sb->sbtmstatelow, w); - } - - /* return the new value - * for write operation, the following readback ensures the completion of write opration. - */ - return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT); -} - -/* set/clear core-specific status flags */ -uint32 -sb_core_sflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii; - sbconfig_t *sb; - uint32 w; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - ASSERT((val & ~mask) == 0); - ASSERT((mask & ~SISF_CORE_BITS) == 0); - - /* mask and set */ - if (mask || val) { - w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) | - (val << SBTMH_SISF_SHIFT); - W_SBREG(sii, &sb->sbtmstatehigh, w); - } - - /* return the new value */ - return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT); -} - -bool -sb_iscoreup(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - return ((R_SBREG(sii, &sb->sbtmstatelow) & - (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == - (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); -} - -/* - * 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 fidleing with interrupts or core switches are needed. - * - * Also, when using pci/pcie, we can optimize away the core switching for pci registers - * and (on newer pci cores) chipcommon registers. - */ -uint -sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -{ - uint origidx = 0; - uint32 *r = NULL; - uint w; - uint intr_val = 0; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - ASSERT((val & ~mask) == 0); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sii->pub.bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (uint32 *)((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 = si_coreidx(&sii->pub); - - /* switch core */ - r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff); - } - ASSERT(r != NULL); - - /* mask and set */ - if (mask || val) { - if (regoff >= SBCONFIGOFF) { - w = (R_SBREG(sii, r) & ~mask) | val; - W_SBREG(sii, r, w); - } else { - w = (R_REG(sii->osh, r) & ~mask) | val; - W_REG(sii->osh, r, w); - } - } - - /* readback */ - if (regoff >= SBCONFIGOFF) - w = R_SBREG(sii, r); - else { - if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) && - (coreidx == SI_CC_IDX) && - (regoff == OFFSETOF(chipcregs_t, watchdog))) { - w = val; - } else - w = R_REG(sii->osh, r); - } - - if (!fast) { - /* restore core index */ - if (origidx != coreidx) - sb_setcoreidx(&sii->pub, origidx); - - INTR_RESTORE(sii, intr_val); - } - - return (w); -} - -/* - * If there is no need for fiddling with interrupts or core switches (typically silicon - * back plane registers, pci registers and chipcommon registers), this function - * returns the register offset on this core to a mapped address. This address can - * be used for W_REG/R_REG directly. - * - * For accessing registers that would need a core switch, this function will return - * NULL. - */ -uint32 * -sb_corereg_addr(si_t *sih, uint coreidx, uint regoff) -{ - uint32 *r = NULL; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sii->pub.bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (uint32 *)((char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + - regoff); - } - } - - if (!fast) - return 0; - - return (r); -} - -/* Scan the enumeration space to find all cores starting from the given - * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' - * is the default core address at chip POR time and 'regs' is the virtual - * address that the default core is mapped at. 'ncores' is the number of - * cores expected on bus 'sbba'. It returns the total number of cores - * starting from bus 'sbba', inclusive. - */ -#define SB_MAXBUSES 2 -static uint -_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores) -{ - uint next; - uint ncc = 0; - uint i; - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - if (bus >= SB_MAXBUSES) { - SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus)); - return 0; - } - SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores)); - - /* Scan all cores on the bus starting from core 0. - * Core addresses must be contiguous on each bus. - */ - for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { - cores_info->coresba[next] = sbba + (i * SI_CORE_SIZE); - - /* keep and reuse the initial register mapping */ - if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (cores_info->coresba[next] == sba)) { - SI_VMSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next)); - cores_info->regs[next] = regs; - } - - /* change core to 'next' and read its coreid */ - sii->curmap = _sb_setcoreidx(sii, next); - sii->curidx = next; - - cores_info->coreid[next] = sb_coreid(&sii->pub); - - /* core specific processing... */ - /* chipc provides # cores */ - if (cores_info->coreid[next] == CC_CORE_ID) { - chipcregs_t *cc = (chipcregs_t *)sii->curmap; - uint32 ccrev = sb_corerev(&sii->pub); - - /* determine numcores - this is the total # cores in the chip */ - if (((ccrev == 4) || (ccrev >= 6))) { - ASSERT(cc); - numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> - CID_CC_SHIFT; - } else { - /* Older chips */ - uint chip = CHIPID(sii->pub.chip); - - if (chip == BCM4306_CHIP_ID) /* < 4306c0 */ - numcores = 6; - else if (chip == BCM4704_CHIP_ID) - numcores = 9; - else if (chip == BCM5365_CHIP_ID) - numcores = 7; - else { - SI_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", - chip)); - ASSERT(0); - numcores = 1; - } - } - SI_VMSG(("_sb_scan: there are %u cores in the chip %s\n", numcores, - sii->pub.issim ? "QT" : "")); - } - /* scan bridged SB(s) and add results to the end of the list */ - else if (cores_info->coreid[next] == OCP_CORE_ID) { - sbconfig_t *sb = REGS2SB(sii->curmap); - uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); - uint nsbcc; - - sii->numcores = next + 1; - - if ((nsbba & 0xfff00000) != SI_ENUM_BASE) - continue; - nsbba &= 0xfffff000; - if (_sb_coreidx(sii, nsbba) != BADIDX) - continue; - - nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16; - nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc); - if (sbba == SI_ENUM_BASE) - numcores -= nsbcc; - ncc += nsbcc; - } - } - - SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba)); - - sii->numcores = i + ncc; - return sii->numcores; -} - -/* scan the sb enumerated space to identify all cores */ -void -sb_scan(si_t *sih, void *regs, uint devid) -{ - uint32 origsba; - sbconfig_t *sb; - si_info_t *sii = SI_INFO(sih); - - sb = REGS2SB(sii->curmap); - - sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; - - /* Save the current core info and validate it later till we know - * for sure what is good and what is bad. - */ - origsba = _sb_coresba(sii); - - /* scan all SB(s) starting from SI_ENUM_BASE */ - sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1); -} - -/* - * 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 * -sb_setcoreidx(si_t *sih, uint coreidx) -{ - si_info_t *sii = SI_INFO(sih); - - if (coreidx >= sii->numcores) - return (NULL); - - /* - * If the user has provided an interrupt mask enabled function, - * then assert interrupts are disabled before switching the core. - */ - ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); - - sii->curmap = _sb_setcoreidx(sii, coreidx); - sii->curidx = coreidx; - - return (sii->curmap); -} - -/* This function changes the logical "focus" to the indicated core. - * Return the current core's virtual address. - */ -static void * -_sb_setcoreidx(si_info_t *sii, uint coreidx) -{ - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 sbaddr = cores_info->coresba[coreidx]; - void *regs; - - switch (BUSTYPE(sii->pub.bustype)) { - case SI_BUS: - /* map new one */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - regs = cores_info->regs[coreidx]; - break; - - case PCI_BUS: - /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr); - regs = sii->curmap; - break; - - case PCMCIA_BUS: { - uint8 tmp = (sbaddr >> 12) & 0x0f; - OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); - tmp = (sbaddr >> 16) & 0xff; - OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); - tmp = (sbaddr >> 24) & 0xff; - OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); - regs = sii->curmap; - break; - } -#ifdef BCMSDIO - case SPI_BUS: - case SDIO_BUS: - /* map new one */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = (void *)(uintptr)sbaddr; - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - regs = cores_info->regs[coreidx]; - break; -#endif /* BCMSDIO */ - - - default: - ASSERT(0); - regs = NULL; - break; - } - - return regs; -} - -/* Return the address of sbadmatch0/1/2/3 register */ -static volatile uint32 * -sb_admatch(si_info_t *sii, uint asidx) -{ - sbconfig_t *sb; - volatile uint32 *addrm; - - sb = REGS2SB(sii->curmap); - - switch (asidx) { - case 0: - addrm = &sb->sbadmatch0; - break; - - case 1: - addrm = &sb->sbadmatch1; - break; - - case 2: - addrm = &sb->sbadmatch2; - break; - - case 3: - addrm = &sb->sbadmatch3; - break; - - default: - SI_ERROR(("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx)); - return 0; - } - - return (addrm); -} - -/* Return the number of address spaces in current core */ -int -sb_numaddrspaces(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - /* + 1 because of enumeration space */ - return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1; -} - -/* Return the address of the nth address space in the current core */ -uint32 -sb_addrspace(si_t *sih, uint asidx) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - - return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx)))); -} - -/* Return the size of the nth address space in the current core */ -uint32 -sb_addrspacesize(si_t *sih, uint asidx) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - - return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx)))); -} - - -/* do buffered registers update */ -void -sb_commit(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - - origidx = sii->curidx; - ASSERT(GOODIDX(origidx)); - - INTR_OFF(sii, intr_val); - - /* switch over to chipcommon core if there is one, else use pci */ - if (sii->pub.ccrev != NOREV) { - chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - ASSERT(ccregs != NULL); - - /* do the buffer registers update */ - W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT); - W_REG(sii->osh, &ccregs->broadcastdata, 0x0); - } else - ASSERT(0); - - /* restore core index */ - sb_setcoreidx(sih, origidx); - INTR_RESTORE(sii, intr_val); -} - -void -sb_core_disable(si_t *sih, uint32 bits) -{ - si_info_t *sii; - volatile uint32 dummy; - sbconfig_t *sb; - - sii = SI_INFO(sih); - - ASSERT(GOODREGS(sii->curmap)); - sb = REGS2SB(sii->curmap); - - /* if core is already in reset, just return */ - if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET) - return; - - /* if clocks are not enabled, put into reset and return */ - if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0) - goto disable; - - /* set target reject and spin until busy is clear (preserve core-specific bits) */ - OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000); - if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY) - SI_ERROR(("%s: target state still busy\n", __FUNCTION__)); - - if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) { - OR_SBREG(sii, &sb->sbimstate, SBIM_RJ); - dummy = R_SBREG(sii, &sb->sbimstate); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000); - } - - /* set reset and reject while enabling the clocks */ - W_SBREG(sii, &sb->sbtmstatelow, - (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | - SBTML_REJ | SBTML_RESET)); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(10); - - /* don't forget to clear the initiator reject bit */ - if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) - AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ); - -disable: - /* leave reset and reject asserted */ - W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET)); - OSL_DELAY(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 -sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) -{ - si_info_t *sii; - sbconfig_t *sb; - volatile uint32 dummy; - - sii = SI_INFO(sih); - ASSERT(GOODREGS(sii->curmap)); - sb = REGS2SB(sii->curmap); - - /* - * Must do the disable sequence first to work for arbitrary current core state. - */ - sb_core_disable(sih, (bits | resetbits)); - - /* - * Now do the initialization sequence. - */ - - /* set reset while enabling the clock and forcing them on throughout the core */ - W_SBREG(sii, &sb->sbtmstatelow, - (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | - SBTML_RESET)); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - - if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) { - W_SBREG(sii, &sb->sbtmstatehigh, 0); - } - if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) { - AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); - } - - /* clear reset and allow it to propagate throughout the core */ - W_SBREG(sii, &sb->sbtmstatelow, - ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - - /* leave clock enabled */ - W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(1); -} - -/* - * Set the initiator timeout for the "master core". - * The master core is defined to be the core in control - * of the chip and so it issues accesses to non-memory - * locations (Because of dma *any* core can access memeory). - * - * The routine uses the bus to decide who is the master: - * SI_BUS => mips - * JTAG_BUS => chipc - * PCI_BUS => pci or pcie - * PCMCIA_BUS => pcmcia - * SDIO_BUS => pcmcia - * - * This routine exists so callers can disable initiator - * timeouts so accesses to very slow devices like otp - * won't cause an abort. The routine allows arbitrary - * settings of the service and request timeouts, though. - * - * Returns the timeout state before changing it or -1 - * on error. - */ - -#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK) - -uint32 -sb_set_initiator_to(si_t *sih, uint32 to, uint idx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - uint32 tmp, ret = 0xffffffff; - sbconfig_t *sb; - - - if ((to & ~TO_MASK) != 0) - return ret; - - /* Figure out the master core */ - if (idx == BADIDX) { - switch (BUSTYPE(sii->pub.bustype)) { - case PCI_BUS: - idx = sii->pub.buscoreidx; - break; - case JTAG_BUS: - idx = SI_CC_IDX; - break; - case PCMCIA_BUS: -#ifdef BCMSDIO - case SDIO_BUS: -#endif - idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0); - break; - case SI_BUS: - idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0); - break; - default: - ASSERT(0); - } - if (idx == BADIDX) - return ret; - } - - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - sb = REGS2SB(sb_setcoreidx(sih, idx)); - - tmp = R_SBREG(sii, &sb->sbimconfiglow); - ret = tmp & TO_MASK; - W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to); - - sb_commit(sih); - sb_setcoreidx(sih, origidx); - INTR_RESTORE(sii, intr_val); - return ret; -} - -uint32 -sb_base(uint32 admatch) -{ - uint32 base; - uint type; - - type = admatch & SBAM_TYPE_MASK; - ASSERT(type < 3); - - base = 0; - - if (type == 0) { - base = admatch & SBAM_BASE0_MASK; - } else if (type == 1) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - base = admatch & SBAM_BASE1_MASK; - } else if (type == 2) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - base = admatch & SBAM_BASE2_MASK; - } - - return (base); -} - -uint32 -sb_size(uint32 admatch) -{ - uint32 size; - uint type; - - type = admatch & SBAM_TYPE_MASK; - ASSERT(type < 3); - - size = 0; - - if (type == 0) { - size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); - } else if (type == 1) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1); - } else if (type == 2) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1); - } - - return (size); -} - -#if defined(BCMDBG_PHYDUMP) -/* print interesting sbconfig registers */ -void -sb_dumpregs(si_t *sih, struct bcmstrbuf *b) -{ - sbconfig_t *sb; - uint origidx, i, intr_val = 0; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - origidx = sii->curidx; - - INTR_OFF(sii, intr_val); - - for (i = 0; i < sii->numcores; i++) { - sb = REGS2SB(sb_setcoreidx(sih, i)); - - bcm_bprintf(b, "core 0x%x: \n", cores_info->coreid[i]); - - if (sii->pub.socirev > SONICS_2_2) - bcm_bprintf(b, "sbimerrlog 0x%x sbimerrloga 0x%x\n", - sb_corereg(sih, si_coreidx(&sii->pub), SBIMERRLOG, 0, 0), - sb_corereg(sih, si_coreidx(&sii->pub), SBIMERRLOGA, 0, 0)); - - bcm_bprintf(b, "sbtmstatelow 0x%x sbtmstatehigh 0x%x sbidhigh 0x%x " - "sbimstate 0x%x\n sbimconfiglow 0x%x sbimconfighigh 0x%x\n", - R_SBREG(sii, &sb->sbtmstatelow), R_SBREG(sii, &sb->sbtmstatehigh), - R_SBREG(sii, &sb->sbidhigh), R_SBREG(sii, &sb->sbimstate), - R_SBREG(sii, &sb->sbimconfiglow), R_SBREG(sii, &sb->sbimconfighigh)); - } - - sb_setcoreidx(sih, origidx); - INTR_RESTORE(sii, intr_val); -} -#endif diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c deleted file mode 100644 index c2ba1fbd68e6..000000000000 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ /dev/null @@ -1,3048 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: siutils.c 506728 2014-10-07 07:22:45Z $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef BCMSDIO -#include -#include -#include -#include -#include -#include -#endif /* BCMSDIO */ -#include - -#ifdef BCM_SDRBL -#include -#endif /* BCM_SDRBL */ -#ifdef HNDGCI -#include -#endif /* HNDGCI */ - -#include "siutils_priv.h" - -/** - * A set of PMU registers is clocked in the ILP domain, which has an implication on register write - * behavior: if such a register is written, it takes multiple ILP clocks for the PMU block to absorb - * the write. During that time the 'SlowWritePending' bit in the PMUStatus register is set. - */ -#define PMUREGS_ILP_SENSITIVE(regoff) \ - ((regoff) == OFFSETOF(pmuregs_t, pmutimer) || \ - (regoff) == OFFSETOF(pmuregs_t, pmuwatchdog) || \ - (regoff) == OFFSETOF(pmuregs_t, res_req_timer)) - -#define CHIPCREGS_ILP_SENSITIVE(regoff) \ - ((regoff) == OFFSETOF(chipcregs_t, pmutimer) || \ - (regoff) == OFFSETOF(chipcregs_t, pmuwatchdog) || \ - (regoff) == OFFSETOF(chipcregs_t, res_req_timer)) - -/* local prototypes */ -static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, - uint bustype, void *sdh, char **vars, uint *varsz); -static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); -static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, - uint *origidx, void *regs); - - -static bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff); - -#ifdef BCMLTECOEX -static void si_config_gcigpio(si_t *sih, uint32 gci_pos, uint8 gcigpio, - uint8 gpioctl_mask, uint8 gpioctl_val); -#endif /* BCMLTECOEX */ - - - -/* global variable to indicate reservation/release of gpio's */ -static uint32 si_gpioreservation = 0; - -/* global flag to prevent shared resources from being initialized multiple times in si_attach() */ -#ifdef SR_DEBUG -static const uint32 si_power_island_test_array[] = { - 0x0000, 0x0001, 0x0010, 0x0011, - 0x0100, 0x0101, 0x0110, 0x0111, - 0x1000, 0x1001, 0x1010, 0x1011, - 0x1100, 0x1101, 0x1110, 0x1111 -}; -#endif /* SR_DEBUG */ - -int do_4360_pcie2_war = 0; - -/* global kernel resource */ -static si_info_t ksii; -static si_cores_info_t ksii_cores_info; - -/** - * Allocate an si handle. This function may be called multiple times. - * - * devid - pci device id (used to determine chip#) - * osh - opaque OS handle - * regs - virtual address of initial core registers - * bustype - pci/pcmcia/sb/sdio/etc - * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this - * function set 'vars' to NULL, making dereferencing of this parameter undesired. - * varsz - pointer to int to return the size of the vars - */ -si_t * -si_attach(uint devid, osl_t *osh, void *regs, - uint bustype, void *sdh, char **vars, uint *varsz) -{ - si_info_t *sii; - si_cores_info_t *cores_info; - /* alloc si_info_t */ - if ((sii = MALLOCZ(osh, sizeof (si_info_t))) == NULL) { - SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); - return (NULL); - } - - /* alloc si_cores_info_t */ - if ((cores_info = (si_cores_info_t *)MALLOCZ(osh, sizeof (si_cores_info_t))) == NULL) { - SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); - MFREE(osh, sii, sizeof(si_info_t)); - return (NULL); - } - sii->cores_info = cores_info; - - if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { - MFREE(osh, sii, sizeof(si_info_t)); - MFREE(osh, cores_info, sizeof(si_cores_info_t)); - return (NULL); - } - sii->vars = vars ? *vars : NULL; - sii->varsz = varsz ? *varsz : 0; - - return (si_t *)sii; -} - - -static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */ - -/** generic kernel variant of si_attach() */ -si_t * -si_kattach(osl_t *osh) -{ - static bool ksii_attached = FALSE; - si_cores_info_t *cores_info; - - if (!ksii_attached) { - void *regs = NULL; - regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); - cores_info = (si_cores_info_t *)&ksii_cores_info; - ksii.cores_info = cores_info; - - ASSERT(osh); - if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, - SI_BUS, NULL, - osh != SI_OSH ? &(ksii.vars) : NULL, - osh != SI_OSH ? &(ksii.varsz) : NULL) == NULL) { - SI_ERROR(("si_kattach: si_doattach failed\n")); - REG_UNMAP(regs); - return NULL; - } - REG_UNMAP(regs); - - /* save ticks normalized to ms for si_watchdog_ms() */ - if (PMUCTL_ENAB(&ksii.pub)) { - /* based on 32KHz ILP clock */ - wd_msticks = 32; - } else { - wd_msticks = ALP_CLOCK / 1000; - } - - ksii_attached = TRUE; - SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n", - ksii.pub.ccrev, wd_msticks)); - } - - return &ksii.pub; -} - - -static bool -si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) -{ - /* need to set memseg flag for CF card first before any sb registers access */ - if (BUSTYPE(bustype) == PCMCIA_BUS) - sii->memseg = TRUE; - - -#if defined(BCMSDIO) - if (BUSTYPE(bustype) == SDIO_BUS) { - int err; - uint8 clkset; - - /* Try forcing SDIO core to do ALPAvail request only */ - clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); - if (!err) { - uint8 clkval; - - /* If register supported, wait for ALPAvail and then force ALP */ - clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); - if ((clkval & ~SBSDIO_AVBITS) == clkset) { - SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), - PMU_MAX_TRANSITION_DLY); - if (!SBSDIO_ALPAV(clkval)) { - SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", - clkval)); - return FALSE; - } - clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - clkset, &err); - OSL_DELAY(65); - } - } - - /* Also, disable the extra SDIO pull-ups */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); - } - -#endif /* BCMSDIO && BCMDONGLEHOST */ - - return TRUE; -} - -static bool -si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, - uint *origidx, void *regs) -{ - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - bool pci, pcie, pcie_gen2 = FALSE; - uint i; - uint pciidx, pcieidx, pcirev, pcierev; - - cc = si_setcoreidx(&sii->pub, SI_CC_IDX); - ASSERT((uintptr)cc); - - /* get chipcommon rev */ - sii->pub.ccrev = (int)si_corerev(&sii->pub); - - /* get chipcommon chipstatus */ - if (sii->pub.ccrev >= 11) - sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); - - /* get chipcommon capabilites */ - sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); - /* get chipcommon extended capabilities */ - - if (sii->pub.ccrev >= 35) - sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); - - /* get pmu rev and caps */ - if (sii->pub.cccaps & CC_CAP_PMU) { - if (AOB_ENAB(&sii->pub)) { - uint pmucoreidx; - pmuregs_t *pmu; - pmucoreidx = si_findcoreidx(&sii->pub, PMU_CORE_ID, 0); - pmu = si_setcoreidx(&sii->pub, pmucoreidx); - sii->pub.pmucaps = R_REG(sii->osh, &pmu->pmucapabilities); - si_setcoreidx(&sii->pub, SI_CC_IDX); - } else - sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); - - sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; - } - - SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", - sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, - sii->pub.pmucaps)); - - /* figure out bus/orignal core idx */ - sii->pub.buscoretype = NODEV_CORE_ID; - sii->pub.buscorerev = (uint)NOREV; - sii->pub.buscoreidx = BADIDX; - - pci = pcie = FALSE; - pcirev = pcierev = (uint)NOREV; - pciidx = pcieidx = BADIDX; - - for (i = 0; i < sii->numcores; i++) { - uint cid, crev; - - si_setcoreidx(&sii->pub, i); - cid = si_coreid(&sii->pub); - crev = si_corerev(&sii->pub); - - /* Display cores found */ - SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", - i, cid, crev, cores_info->coresba[i], cores_info->regs[i])); - - if (BUSTYPE(bustype) == SI_BUS) { - /* now look at the chipstatus register to figure the pacakge */ - /* for SDIO but downloaded on PCIE dev */ - if (cid == PCIE2_CORE_ID) { - if ((CHIPID(sii->pub.chip) == BCM43602_CHIP_ID) || - ((CHIPID(sii->pub.chip) == BCM4345_CHIP_ID) && - CST4345_CHIPMODE_PCIE(sii->pub.chipst))) { - pcieidx = i; - pcierev = crev; - pcie = TRUE; - pcie_gen2 = TRUE; - } - } - - } - else if (BUSTYPE(bustype) == PCI_BUS) { - if (cid == PCI_CORE_ID) { - pciidx = i; - pcirev = crev; - pci = TRUE; - } else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) { - pcieidx = i; - pcierev = crev; - pcie = TRUE; - if (cid == PCIE2_CORE_ID) - pcie_gen2 = TRUE; - } - } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && - (cid == PCMCIA_CORE_ID)) { - sii->pub.buscorerev = crev; - sii->pub.buscoretype = cid; - sii->pub.buscoreidx = i; - } -#ifdef BCMSDIO - else if (((BUSTYPE(bustype) == SDIO_BUS) || - (BUSTYPE(bustype) == SPI_BUS)) && - ((cid == PCMCIA_CORE_ID) || - (cid == SDIOD_CORE_ID))) { - sii->pub.buscorerev = crev; - sii->pub.buscoretype = cid; - sii->pub.buscoreidx = i; - } -#endif /* BCMSDIO */ - - /* find the core idx before entering this func. */ - if ((savewin && (savewin == cores_info->coresba[i])) || - (regs == cores_info->regs[i])) - *origidx = i; - } - - -#if defined(PCIE_FULL_DONGLE) - if (pcie) { - if (pcie_gen2) - sii->pub.buscoretype = PCIE2_CORE_ID; - else - sii->pub.buscoretype = PCIE_CORE_ID; - sii->pub.buscorerev = pcierev; - sii->pub.buscoreidx = pcieidx; - } - BCM_REFERENCE(pci); - BCM_REFERENCE(pcirev); - BCM_REFERENCE(pciidx); -#else - if (pci) { - sii->pub.buscoretype = PCI_CORE_ID; - sii->pub.buscorerev = pcirev; - sii->pub.buscoreidx = pciidx; - } else if (pcie) { - if (pcie_gen2) - sii->pub.buscoretype = PCIE2_CORE_ID; - else - sii->pub.buscoretype = PCIE_CORE_ID; - sii->pub.buscorerev = pcierev; - sii->pub.buscoreidx = pcieidx; - } -#endif /* defined(PCIE_FULL_DONGLE) */ - - SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, - sii->pub.buscorerev)); - - if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && - (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3)) - OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); - - -#if defined(BCMSDIO) - /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was - * already running. - */ - if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { - if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || - si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) - si_core_disable(&sii->pub, 0); - } -#endif /* BCMSDIO && BCMDONGLEHOST */ - - /* return to the original core */ - si_setcoreidx(&sii->pub, *origidx); - - return TRUE; -} - - - - -uint16 -si_chipid(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - - return (sii->chipnew) ? sii->chipnew : sih->chip; -} - -static void -si_chipid_fixup(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - - ASSERT(sii->chipnew == 0); - switch (sih->chip) { - case BCM43570_CHIP_ID: - case BCM4358_CHIP_ID: - sii->chipnew = sih->chip; /* save it */ - sii->pub.chip = BCM43569_CHIP_ID; /* chip class */ - break; - case BCM4356_CHIP_ID: - sii->chipnew = sih->chip; /* save it */ - sii->pub.chip = BCM4354_CHIP_ID; /* chip class */ - break; - default: - ASSERT(0); - break; - } -} - -/** - * Allocate an si handle. This function may be called multiple times. - * - * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this - * function set 'vars' to NULL. - */ -static si_info_t * -si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, - uint bustype, void *sdh, char **vars, uint *varsz) -{ - struct si_pub *sih = &sii->pub; - uint32 w, savewin; - chipcregs_t *cc; - char *pvars = NULL; - uint origidx; -#if !defined(_CFEZ_) || defined(CFG_WL) -#endif - - ASSERT(GOODREGS(regs)); - - savewin = 0; - - sih->buscoreidx = BADIDX; - - sii->curmap = regs; - sii->sdh = sdh; - sii->osh = osh; - - - /* check to see if we are a si core mimic'ing a pci core */ - if ((bustype == PCI_BUS) && - (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(uint32)) == 0xffffffff)) { - SI_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SI " - "devid:0x%x\n", __FUNCTION__, devid)); - bustype = SI_BUS; - } - - /* find Chipcommon address */ - if (bustype == PCI_BUS) { - savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); - if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) - savewin = SI_ENUM_BASE; - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); - if (!regs) - return NULL; - cc = (chipcregs_t *)regs; -#ifdef BCMSDIO - } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { - cc = (chipcregs_t *)sii->curmap; -#endif - } else { - cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); - } - - sih->bustype = bustype; -#ifdef BCMBUSTYPE - if (bustype != BUSTYPE(bustype)) { - SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", - bustype, BUSTYPE(bustype))); - return NULL; - } -#endif - /* bus/core/clk setup for register access */ - if (!si_buscore_prep(sii, bustype, devid, sdh)) { - SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); - 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. - */ - if (!cc) { - SI_ERROR(("%s: chipcommon register space is null \n", __FUNCTION__)); - return NULL; - } -#ifdef COSTOMER_HW4 -#ifdef CONFIG_MACH_UNIVERSAL5433 - /* old revision check */ - if (!check_rev()) { - /* abnormal link status */ - if (!check_pcie_link_status()) { - printk("%s : PCIE LINK is abnormal status\n", __FUNCTION__); - return NULL; - } - } -#endif /* CONFIG_MACH_UNIVERSAL5433 */ -#endif - w = R_REG(osh, &cc->chipid); - if ((w & 0xfffff) == 148277) w -= 65532; - sih->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; - - if ((sih->chip == BCM4358_CHIP_ID) || - (sih->chip == BCM43570_CHIP_ID) || - (sih->chip == BCM4358_CHIP_ID)) { - si_chipid_fixup(sih); - } - - if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && - (sih->chippkg != BCM4329_289PIN_PKG_ID)) { - sih->chippkg = BCM4329_182PIN_PKG_ID; - } - sih->issim = IS_SIM(sih->chippkg); - - /* scan for cores */ - if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { - SI_MSG(("Found chip type SB (0x%08x)\n", w)); - sb_scan(&sii->pub, regs, devid); - } else if ((CHIPTYPE(sii->pub.socitype) == SOCI_AI) || - (CHIPTYPE(sii->pub.socitype) == SOCI_NAI)) { - if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) - SI_MSG(("Found chip type AI (0x%08x)\n", w)); - else - SI_MSG(("Found chip type NAI (0x%08x)\n", w)); - /* pass chipc address instead of original core base */ - ai_scan(&sii->pub, (void *)(uintptr)cc, devid); - } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { - SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip)); - /* pass chipc address instead of original core base */ - ub_scan(&sii->pub, (void *)(uintptr)cc, devid); - } else { - SI_ERROR(("Found chip of unknown type (0x%08x)\n", w)); - return NULL; - } - /* no cores found, bail out */ - if (sii->numcores == 0) { - SI_ERROR(("si_doattach: could not find any cores\n")); - return NULL; - } - /* bus/core/clk setup */ - origidx = SI_CC_IDX; - if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { - SI_ERROR(("si_doattach: si_buscore_setup failed\n")); - goto exit; - } - -#if !defined(_CFEZ_) || defined(CFG_WL) - if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) - >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | - CST4322_SPROM_PRESENT))) { - SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__)); - return NULL; - } - - /* assume current core is CC */ - if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || - CHIPID(sih->chip) == BCM43235_CHIP_ID || - CHIPID(sih->chip) == BCM43234_CHIP_ID || - CHIPID(sih->chip) == BCM43238_CHIP_ID) && - (CHIPREV(sii->pub.chiprev) <= 2))) { - - if ((cc->chipstatus & CST43236_BP_CLK) != 0) { - uint clkdiv; - clkdiv = R_REG(osh, &cc->clkdiv); - /* otp_clk_div is even number, 120/14 < 9mhz */ - clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); - W_REG(osh, &cc->clkdiv, clkdiv); - SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv)); - } - OSL_DELAY(10); - } - - if (bustype == PCI_BUS) { - - } -#endif -#ifdef BCM_SDRBL - /* 4360 rom bootloader in PCIE case, if the SDR is enabled, But preotection is - * not turned on, then we want to hold arm in reset. - * Bottomline: In sdrenable case, we allow arm to boot only when protection is - * turned on. - */ - if (CHIP_HOSTIF_PCIE(&(sii->pub))) { - uint32 sflags = si_arm_sflags(&(sii->pub)); - - /* If SDR is enabled but protection is not turned on - * then we want to force arm to WFI. - */ - if ((sflags & (SISF_SDRENABLE | SISF_TCMPROT)) == SISF_SDRENABLE) { - disable_arm_irq(); - while (1) { - hnd_cpu_wait(sih); - } - } - } -#endif /* BCM_SDRBL */ - - pvars = NULL; - BCM_REFERENCE(pvars); - - - - if (sii->pub.ccrev >= 20) { - uint32 gpiopullup = 0, gpiopulldown = 0; - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - ASSERT(cc != NULL); - - /* 4314/43142 has pin muxing, don't clear gpio bits */ - if ((CHIPID(sih->chip) == BCM4314_CHIP_ID) || - (CHIPID(sih->chip) == BCM43142_CHIP_ID)) { - gpiopullup |= 0x402e0; - gpiopulldown |= 0x20500; - } - - W_REG(osh, &cc->gpiopullup, gpiopullup); - W_REG(osh, &cc->gpiopulldown, gpiopulldown); - si_setcoreidx(sih, origidx); - } - - - /* clear any previous epidiag-induced target abort */ - ASSERT(!si_taclear(sih, FALSE)); - - -#ifdef BOOTLOADER_CONSOLE_OUTPUT - /* Enable console prints */ - si_muxenab(sii, 3); -#endif - - return (sii); - -exit: - - return NULL; -} - -/** may be called with core in reset */ -void -si_detach(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint idx; - - - if (BUSTYPE(sih->bustype) == SI_BUS) - for (idx = 0; idx < SI_MAXCORES; idx++) - if (cores_info->regs[idx]) { - REG_UNMAP(cores_info->regs[idx]); - cores_info->regs[idx] = NULL; - } - - -#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) - if (cores_info != &ksii_cores_info) -#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ - MFREE(sii->osh, cores_info, sizeof(si_cores_info_t)); - -#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) - if (sii != &ksii) -#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ - MFREE(sii->osh, sii, sizeof(si_info_t)); -} - -void * -si_osh(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - return sii->osh; -} - -void -si_setosh(si_t *sih, osl_t *osh) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - if (sii->osh != NULL) { - SI_ERROR(("osh is already set....\n")); - ASSERT(!sii->osh); - } - sii->osh = osh; -} - -/** register driver interrupt disabling and restoring callback functions */ -void -si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, - void *intrsenabled_fn, void *intr_arg) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - sii->intr_arg = intr_arg; - sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn; - sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn; - sii->intrsenabled_fn = (si_intrsenabled_t)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 = cores_info->coreid[sii->curidx]; -} - -void -si_deregister_intr_callback(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - sii->intrsoff_fn = NULL; - sii->intrsrestore_fn = NULL; - sii->intrsenabled_fn = NULL; -} - -uint -si_intflag(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_intflag(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return R_REG(sii->osh, ((uint32 *)(uintptr) - (sii->oob_router + OOB_STATUSA))); - else { - ASSERT(0); - return 0; - } -} - -uint -si_flag(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_flag(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_flag(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_flag(sih); - else { - ASSERT(0); - return 0; - } -} - -uint -si_flag_alt(si_t *sih) -{ - if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_flag_alt(sih); - else { - ASSERT(0); - return 0; - } -} - -void -si_setint(si_t *sih, int siflag) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - sb_setint(sih, siflag); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_setint(sih, siflag); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - ub_setint(sih, siflag); - else - ASSERT(0); -} - -uint -si_coreid(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - return cores_info->coreid[sii->curidx]; -} - -uint -si_coreidx(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - return sii->curidx; -} - -void * -si_d11_switch_addrbase(si_t *sih, uint coreunit) -{ - return si_setcore(sih, D11_CORE_ID, coreunit); -} - -/** return the core-type instantiation # of the current core */ -uint -si_coreunit(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint idx; - uint coreid; - uint coreunit; - uint i; - - coreunit = 0; - - idx = sii->curidx; - - ASSERT(GOODREGS(sii->curmap)); - coreid = si_coreid(sih); - - /* count the cores of our type */ - for (i = 0; i < idx; i++) - if (cores_info->coreid[i] == coreid) - coreunit++; - - return (coreunit); -} - -uint -si_corevendor(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_corevendor(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_corevendor(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_corevendor(sih); - else { - ASSERT(0); - return 0; - } -} - -bool -si_backplane64(si_t *sih) -{ - return ((sih->cccaps & CC_CAP_BKPLN64) != 0); -} - -uint -si_corerev(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_corerev(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_corerev(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_corerev(sih); - else { - ASSERT(0); - return 0; - } -} - - -/* return index of coreid or BADIDX if not found */ -uint -si_findcoreidx(si_t *sih, uint coreid, uint coreunit) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint found; - uint i; - - - found = 0; - - for (i = 0; i < sii->numcores; i++) - if (cores_info->coreid[i] == coreid) { - if (found == coreunit) - return (i); - found++; - } - - return (BADIDX); -} - -/** return total coreunit of coreid or zero if not found */ -uint -si_numcoreunits(si_t *sih, uint coreid) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint found = 0; - uint i; - - for (i = 0; i < sii->numcores; i++) { - if (cores_info->coreid[i] == coreid) { - found++; - } - } - - return found; -} - -/** return total D11 coreunits */ -uint -BCMRAMFN(si_numd11coreunits)(si_t *sih) -{ - uint found = 0; - - found = si_numcoreunits(sih, D11_CORE_ID); - -#if defined(WLRSDB) && defined(WLRSDB_DISABLED) - /* If RSDB functionality is compiled out, - * then ignore any D11 cores beyond the first - * Used in norsdb dongle build variants for rsdb chip. - */ - found = 1; -#endif /* defined(WLRSDB) && !defined(WLRSDB_DISABLED) */ - - return found; -} - -/** return list of found cores */ -uint -si_corelist(si_t *sih, uint coreid[]) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - bcopy((uchar*)cores_info->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); - return (sii->numcores); -} - -/** return current wrapper mapping */ -void * -si_wrapperregs(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - ASSERT(GOODREGS(sii->curwrap)); - - return (sii->curwrap); -} - -/** return current register mapping */ -void * -si_coreregs(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - ASSERT(GOODREGS(sii->curmap)); - - return (sii->curmap); -} - -/** - * 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 * -si_setcore(si_t *sih, uint coreid, uint coreunit) -{ - uint idx; - - idx = si_findcoreidx(sih, coreid, coreunit); - if (!GOODIDX(idx)) - return (NULL); - - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_setcoreidx(sih, idx); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_setcoreidx(sih, idx); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_setcoreidx(sih, idx); - else { - ASSERT(0); - return NULL; - } -} - -void * -si_setcoreidx(si_t *sih, uint coreidx) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_setcoreidx(sih, coreidx); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_setcoreidx(sih, coreidx); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_setcoreidx(sih, coreidx); - else { - ASSERT(0); - return NULL; - } -} - -/** Turn off interrupt as required by sb_setcore, before switch core */ -void * -si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) -{ - void *cc; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - 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 (void *)CCREGS_FAST(sii); - else if (coreid == sih->buscoretype) - return (void *)PCIEREGS(sii); - } - INTR_OFF(sii, *intr_val); - *origidx = sii->curidx; - cc = si_setcore(sih, coreid, 0); - ASSERT(cc != NULL); - - return cc; -} - -/* restore coreidx and restore interrupt */ -void -si_restore_core(si_t *sih, uint coreid, uint intr_val) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) - return; - - si_setcoreidx(sih, coreid); - INTR_RESTORE(sii, intr_val); -} - -int -si_numaddrspaces(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_numaddrspaces(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_numaddrspaces(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_numaddrspaces(sih); - else { - ASSERT(0); - return 0; - } -} - -uint32 -si_addrspace(si_t *sih, uint asidx) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_addrspace(sih, asidx); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_addrspace(sih, asidx); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_addrspace(sih, asidx); - else { - ASSERT(0); - return 0; - } -} - -uint32 -si_addrspacesize(si_t *sih, uint asidx) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_addrspacesize(sih, asidx); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_addrspacesize(sih, asidx); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_addrspacesize(sih, asidx); - else { - ASSERT(0); - return 0; - } -} - -void -si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) -{ - /* Only supported for SOCI_AI */ - if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_coreaddrspaceX(sih, asidx, addr, size); - else - *size = 0; -} - -uint32 -si_core_cflags(si_t *sih, uint32 mask, uint32 val) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_core_cflags(sih, mask, val); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_core_cflags(sih, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_core_cflags(sih, mask, val); - else { - ASSERT(0); - return 0; - } -} - -void -si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - sb_core_cflags_wo(sih, mask, val); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_core_cflags_wo(sih, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - ub_core_cflags_wo(sih, mask, val); - else - ASSERT(0); -} - -uint32 -si_core_sflags(si_t *sih, uint32 mask, uint32 val) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_core_sflags(sih, mask, val); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_core_sflags(sih, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_core_sflags(sih, mask, val); - else { - ASSERT(0); - return 0; - } -} - -bool -si_iscoreup(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_iscoreup(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_iscoreup(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_iscoreup(sih); - else { - ASSERT(0); - return FALSE; - } -} - -uint -si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) -{ - /* only for AI back plane chips */ - if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return (ai_wrap_reg(sih, offset, mask, val)); - return 0; -} - -uint -si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_corereg(sih, coreidx, regoff, mask, val); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_corereg(sih, coreidx, regoff, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_corereg(sih, coreidx, regoff, mask, val); - else { - ASSERT(0); - return 0; - } -} - -/** ILP sensitive register access needs special treatment to avoid backplane stalls */ -bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff) -{ - if (idx == SI_CC_IDX) { - if (CHIPCREGS_ILP_SENSITIVE(regoff)) - return TRUE; - } else if (PMUREGS_ILP_SENSITIVE(regoff)) { - return TRUE; - } - - return FALSE; -} - -/** 'idx' should refer either to the chipcommon core or the PMU core */ -uint -si_pmu_corereg(si_t *sih, uint32 idx, uint regoff, uint mask, uint val) -{ - int pmustatus_offset; - - /* prevent backplane stall on double write to 'ILP domain' registers in the PMU */ - if (mask != 0 && sih->pmurev >= 22 && - si_pmu_is_ilp_sensitive(idx, regoff)) { - pmustatus_offset = AOB_ENAB(sih) ? OFFSETOF(pmuregs_t, pmustatus) : - OFFSETOF(chipcregs_t, pmustatus); - - while (si_corereg(sih, idx, pmustatus_offset, 0, 0) & PST_SLOW_WR_PENDING) - {}; - } - - return si_corereg(sih, idx, regoff, mask, val); -} - -/* - * If there is no need for fiddling with interrupts or core switches (typically silicon - * back plane registers, pci registers and chipcommon registers), this function - * returns the register offset on this core to a mapped address. This address can - * be used for W_REG/R_REG directly. - * - * For accessing registers that would need a core switch, this function will return - * NULL. - */ -uint32 * -si_corereg_addr(si_t *sih, uint coreidx, uint regoff) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_corereg_addr(sih, coreidx, regoff); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_corereg_addr(sih, coreidx, regoff); - else { - return 0; - } -} - -void -si_core_disable(si_t *sih, uint32 bits) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - sb_core_disable(sih, bits); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_core_disable(sih, bits); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - ub_core_disable(sih, bits); -} - -void -si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - sb_core_reset(sih, bits, resetbits); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_core_reset(sih, bits, resetbits); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - ub_core_reset(sih, bits, resetbits); -} - -/** Run bist on current core. Caller needs to take care of core-specific bist hazards */ -int -si_corebist(si_t *sih) -{ - uint32 cflags; - int result = 0; - - /* Read core control flags */ - cflags = si_core_cflags(sih, 0, 0); - - /* Set bist & fgc */ - si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); - - /* Wait for bist done */ - SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); - - if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) - result = BCME_ERROR; - - /* Reset core control flags */ - si_core_cflags(sih, 0xffff, cflags); - - return result; -} - -static uint32 -factor6(uint32 x) -{ - switch (x) { - case CC_F6_2: return 2; - case CC_F6_3: return 3; - case CC_F6_4: return 4; - case CC_F6_5: return 5; - case CC_F6_6: return 6; - case CC_F6_7: return 7; - default: return 0; - } -} - -/** calculate the speed the SI would run at given a set of clockcontrol values */ -uint32 -si_clock_rate(uint32 pll_type, uint32 n, uint32 m) -{ - uint32 n1, n2, clock, m1, m2, m3, mc; - - n1 = n & CN_N1_MASK; - n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; - - if (pll_type == PLL_TYPE6) { - if (m & CC_T6_MMASK) - return CC_T6_M1; - else - return CC_T6_M0; - } else if ((pll_type == PLL_TYPE1) || - (pll_type == PLL_TYPE3) || - (pll_type == PLL_TYPE4) || - (pll_type == PLL_TYPE7)) { - n1 = factor6(n1); - n2 += CC_F5_BIAS; - } else if (pll_type == PLL_TYPE2) { - n1 += CC_T2_BIAS; - n2 += CC_T2_BIAS; - ASSERT((n1 >= 2) && (n1 <= 7)); - ASSERT((n2 >= 5) && (n2 <= 23)); - } else if (pll_type == PLL_TYPE5) { - return (100000000); - } else - ASSERT(0); - /* PLL types 3 and 7 use BASE2 (25Mhz) */ - if ((pll_type == PLL_TYPE3) || - (pll_type == PLL_TYPE7)) { - clock = CC_CLOCK_BASE2 * n1 * n2; - } else - clock = CC_CLOCK_BASE1 * n1 * n2; - - if (clock == 0) - return 0; - - m1 = m & CC_M1_MASK; - m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; - m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; - mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; - - if ((pll_type == PLL_TYPE1) || - (pll_type == PLL_TYPE3) || - (pll_type == PLL_TYPE4) || - (pll_type == PLL_TYPE7)) { - m1 = factor6(m1); - if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) - m2 += CC_F5_BIAS; - else - m2 = factor6(m2); - m3 = factor6(m3); - - switch (mc) { - case CC_MC_BYPASS: return (clock); - case CC_MC_M1: return (clock / m1); - case CC_MC_M1M2: return (clock / (m1 * m2)); - case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3)); - case CC_MC_M1M3: return (clock / (m1 * m3)); - default: return (0); - } - } else { - ASSERT(pll_type == PLL_TYPE2); - - m1 += CC_T2_BIAS; - m2 += CC_T2M2_BIAS; - m3 += CC_T2_BIAS; - ASSERT((m1 >= 2) && (m1 <= 7)); - ASSERT((m2 >= 3) && (m2 <= 10)); - ASSERT((m3 >= 2) && (m3 <= 7)); - - if ((mc & CC_T2MC_M1BYP) == 0) - clock /= m1; - if ((mc & CC_T2MC_M2BYP) == 0) - clock /= m2; - if ((mc & CC_T2MC_M3BYP) == 0) - clock /= m3; - - return (clock); - } -} - -/** - * Some chips could have multiple host interfaces, however only one will be active. - * For a given chip. Depending pkgopt and cc_chipst return the active host interface. - */ -uint -si_chip_hostif(si_t *sih) -{ - uint hosti = 0; - - switch (CHIPID(sih->chip)) { - - case BCM43602_CHIP_ID: - hosti = CHIP_HOSTIF_PCIEMODE; - break; - - case BCM4360_CHIP_ID: - /* chippkg bit-0 == 0 is PCIE only pkgs - * chippkg bit-0 == 1 has both PCIE and USB cores enabled - */ - if ((sih->chippkg & 0x1) && (sih->chipst & CST4360_MODE_USB)) - hosti = CHIP_HOSTIF_USBMODE; - else - hosti = CHIP_HOSTIF_PCIEMODE; - - break; - - case BCM4335_CHIP_ID: - /* TBD: like in 4360, do we need to check pkg? */ - if (CST4335_CHIPMODE_USB20D(sih->chipst)) - hosti = CHIP_HOSTIF_USBMODE; - else if (CST4335_CHIPMODE_SDIOD(sih->chipst)) - hosti = CHIP_HOSTIF_SDIOMODE; - else - hosti = CHIP_HOSTIF_PCIEMODE; - break; - - case BCM4345_CHIP_ID: - if (CST4345_CHIPMODE_USB20D(sih->chipst) || CST4345_CHIPMODE_HSIC(sih->chipst)) - hosti = CHIP_HOSTIF_USBMODE; - else if (CST4345_CHIPMODE_SDIOD(sih->chipst)) - hosti = CHIP_HOSTIF_SDIOMODE; - else if (CST4345_CHIPMODE_PCIE(sih->chipst)) - hosti = CHIP_HOSTIF_PCIEMODE; - break; - - case BCM4349_CHIP_GRPID: - if (CST4349_CHIPMODE_SDIOD(sih->chipst)) - hosti = CHIP_HOSTIF_SDIOMODE; - else if (CST4349_CHIPMODE_PCIE(sih->chipst)) - hosti = CHIP_HOSTIF_PCIEMODE; - break; - - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM4356_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43569_CHIP_ID: - case BCM43570_CHIP_ID: - case BCM4358_CHIP_ID: - if (CST4350_CHIPMODE_USB20D(sih->chipst) || - CST4350_CHIPMODE_HSIC20D(sih->chipst) || - CST4350_CHIPMODE_USB30D(sih->chipst) || - CST4350_CHIPMODE_USB30D_WL(sih->chipst) || - CST4350_CHIPMODE_HSIC30D(sih->chipst)) - hosti = CHIP_HOSTIF_USBMODE; - else if (CST4350_CHIPMODE_SDIOD(sih->chipst)) - hosti = CHIP_HOSTIF_SDIOMODE; - else if (CST4350_CHIPMODE_PCIE(sih->chipst)) - hosti = CHIP_HOSTIF_PCIEMODE; - break; - - default: - break; - } - - return hosti; -} - - -/** set chip watchdog reset timer to fire in 'ticks' */ -void -si_watchdog(si_t *sih, uint ticks) -{ - uint nb, maxt; - - if (PMUCTL_ENAB(sih)) { - -#if !defined(_CFEZ_) || defined(CFG_WL) - if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && - (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { - si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); - si_setcore(sih, USB20D_CORE_ID, 0); - si_core_disable(sih, 1); - si_setcore(sih, CC_CORE_ID, 0); - } -#endif - - nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); - /* The mips compiler uses the sllv instruction, - * so we specially handle the 32-bit case. - */ - if (nb == 32) - maxt = 0xffffffff; - else - maxt = ((1 << nb) - 1); - - if (ticks == 1) - ticks = 2; - else if (ticks > maxt) - ticks = maxt; - - pmu_corereg(sih, SI_CC_IDX, pmuwatchdog, ~0, ticks); - } else { - maxt = (1 << 28) - 1; - if (ticks > maxt) - ticks = maxt; - - si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); - } -} - -/** trigger watchdog reset after ms milliseconds */ -void -si_watchdog_ms(si_t *sih, uint32 ms) -{ - si_watchdog(sih, wd_msticks * ms); -} - -uint32 si_watchdog_msticks(void) -{ - return wd_msticks; -} - -bool -si_taclear(si_t *sih, bool details) -{ - return FALSE; -} - - - -/** return the slow clock source - LPO, XTAL, or PCI */ -static uint -si_slowclk_src(si_info_t *sii) -{ - chipcregs_t *cc; - - ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); - - if (sii->pub.ccrev < 6) { - if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && - (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) & - PCI_CFG_GPIO_SCS)) - return (SCC_SS_PCI); - else - return (SCC_SS_XTAL); - } else if (sii->pub.ccrev < 10) { - cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); - ASSERT(cc); - return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); - } else /* Insta-clock */ - return (SCC_SS_XTAL); -} - -/** return the ILP (slowclock) min or max frequency */ -static uint -si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) -{ - uint32 slowclk; - uint div; - - ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); - - /* shouldn't be here unless we've established the chip has dynamic clk control */ - ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); - - slowclk = si_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(sii->osh, &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 - ASSERT(0); - } else { - /* Chipc rev 10 is InstaClock */ - div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; - div = 4 * (div + 1); - return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); - } - return (0); -} - -static void -si_clkctl_setdelay(si_info_t *sii, void *chipcregs) -{ - chipcregs_t *cc = (chipcregs_t *)chipcregs; - 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 = si_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 = si_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(sii->osh, &cc->pll_on_delay, pll_on_delay); - W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); -} - -/** initialize power control delay registers */ -void -si_clkctl_init(si_t *sih) -{ - si_info_t *sii; - uint origidx = 0; - chipcregs_t *cc; - bool fast; - - if (!CCCTL_ENAB(sih)) - return; - - sii = SI_INFO(sih); - fast = SI_FAST(sii); - if (!fast) { - origidx = sii->curidx; - if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) - return; - } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) - return; - ASSERT(cc != NULL); - - /* set all Instaclk chip ILP to 1 MHz */ - if (sih->ccrev >= 10) - SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, - (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); - - si_clkctl_setdelay(sii, (void *)(uintptr)cc); - - OSL_DELAY(20000); - - if (!fast) - si_setcoreidx(sih, origidx); -} - - -/** change logical "focus" to the gpio core for optimized access */ -void * -si_gpiosetcore(si_t *sih) -{ - return (si_setcoreidx(sih, SI_CC_IDX)); -} - -/** - * mask & set gpiocontrol bits. - * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin. - * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated - * to some chip-specific purpose. - */ -uint32 -si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - regoff = 0; - - /* gpios could be shared on router platforms - * ignore reservation if it's high priority (e.g., test apps) - */ - if ((priority != GPIO_HI_PRIORITY) && - (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpiocontrol); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/** mask&set gpio output enable bits */ -uint32 -si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - regoff = 0; - - /* gpios could be shared on router platforms - * ignore reservation if it's high priority (e.g., test apps) - */ - if ((priority != GPIO_HI_PRIORITY) && - (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpioouten); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/** mask&set gpio output bits */ -uint32 -si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - regoff = 0; - - /* gpios could be shared on router platforms - * ignore reservation if it's high priority (e.g., test apps) - */ - if ((priority != GPIO_HI_PRIORITY) && - (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpioout); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/** reserve one gpio */ -uint32 -si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) -{ - /* only cores on SI_BUS share GPIO's and only applcation users need to - * reserve/release GPIO - */ - if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { - ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); - return 0xffffffff; - } - /* make sure only one bit is set */ - if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { - ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); - return 0xffffffff; - } - - /* already reserved */ - if (si_gpioreservation & gpio_bitmask) - return 0xffffffff; - /* set reservation */ - si_gpioreservation |= gpio_bitmask; - - return si_gpioreservation; -} - -/** - * release one gpio. - * - * releasing the gpio doesn't change the current value on the GPIO last write value - * persists till someone overwrites it. - */ -uint32 -si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) -{ - /* only cores on SI_BUS share GPIO's and only applcation users need to - * reserve/release GPIO - */ - if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { - ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); - return 0xffffffff; - } - /* make sure only one bit is set */ - if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { - ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); - return 0xffffffff; - } - - /* already released */ - if (!(si_gpioreservation & gpio_bitmask)) - return 0xffffffff; - - /* clear reservation */ - si_gpioreservation &= ~gpio_bitmask; - - return si_gpioreservation; -} - -/* return the current gpioin register value */ -uint32 -si_gpioin(si_t *sih) -{ - uint regoff; - - regoff = OFFSETOF(chipcregs_t, gpioin); - return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0)); -} - -/* mask&set gpio interrupt polarity bits */ -uint32 -si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - /* gpios could be shared on router platforms */ - if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpiointpolarity); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/* mask&set gpio interrupt mask bits */ -uint32 -si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - /* gpios could be shared on router platforms */ - if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpiointmask); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/* assign the gpio to an led */ -uint32 -si_gpioled(si_t *sih, uint32 mask, uint32 val) -{ - if (sih->ccrev < 16) - return 0xffffffff; - - /* gpio led powersave reg */ - return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); -} - -/* mask&set gpio timer val */ -uint32 -si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) -{ - if (sih->ccrev < 16) - return 0xffffffff; - - return (si_corereg(sih, SI_CC_IDX, - OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); -} - -uint32 -si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) -{ - uint offs; - - if (sih->ccrev < 20) - return 0xffffffff; - - offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); - return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); -} - -uint32 -si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) -{ - uint offs; - - if (sih->ccrev < 11) - return 0xffffffff; - - if (regtype == GPIO_REGEVT) - offs = OFFSETOF(chipcregs_t, gpioevent); - else if (regtype == GPIO_REGEVT_INTMSK) - offs = OFFSETOF(chipcregs_t, gpioeventintmask); - else if (regtype == GPIO_REGEVT_INTPOL) - offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); - else - return 0xffffffff; - - return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); -} - -void * -si_gpio_handler_register(si_t *sih, uint32 event, - bool level, gpio_handler_t cb, void *arg) -{ - si_info_t *sii = SI_INFO(sih); - gpioh_item_t *gi; - - ASSERT(event); - ASSERT(cb != NULL); - - if (sih->ccrev < 11) - return NULL; - - if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL) - return NULL; - - bzero(gi, sizeof(gpioh_item_t)); - gi->event = event; - gi->handler = cb; - gi->arg = arg; - gi->level = level; - - gi->next = sii->gpioh_head; - sii->gpioh_head = gi; - - return (void *)(gi); -} - -void -si_gpio_handler_unregister(si_t *sih, void *gpioh) -{ - si_info_t *sii = SI_INFO(sih); - gpioh_item_t *p, *n; - - if (sih->ccrev < 11) - return; - - ASSERT(sii->gpioh_head != NULL); - if ((void*)sii->gpioh_head == gpioh) { - sii->gpioh_head = sii->gpioh_head->next; - MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); - return; - } else { - p = sii->gpioh_head; - n = p->next; - while (n) { - if ((void*)n == gpioh) { - p->next = n->next; - MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); - return; - } - p = n; - n = n->next; - } - } - - ASSERT(0); /* Not found in list */ -} - -void -si_gpio_handler_process(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - gpioh_item_t *h; - uint32 level = si_gpioin(sih); - uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0); - uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); - uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0); - - for (h = sii->gpioh_head; h != NULL; h = h->next) { - if (h->handler) { - uint32 status = (h->level ? level : edge) & h->event; - uint32 polarity = (h->level ? levelp : edgep) & h->event; - - /* polarity bitval is opposite of status bitval */ - if ((h->level && (status ^ polarity)) || (!h->level && status)) - h->handler(status, h->arg); - } - } - - si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ -} - -uint32 -si_gpio_int_enable(si_t *sih, bool enable) -{ - uint offs; - - if (sih->ccrev < 11) - return 0xffffffff; - - offs = OFFSETOF(chipcregs_t, intmask); - return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); -} - - -/** Return the size of the specified SOCRAM bank */ -static uint -socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) -{ - uint banksize, bankinfo; - uint bankidx = idx | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); - - ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); - - W_REG(sii->osh, ®s->bankidx, bankidx); - bankinfo = R_REG(sii->osh, ®s->bankinfo); - banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); - return banksize; -} - -void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - sbsocramregs_t *regs; - bool wasup; - uint corerev; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 16) { - W_REG(sii->osh, ®s->bankidx, bankidx); - W_REG(sii->osh, ®s->bankpda, bankpda); - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); -} - -void -si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect, uint8 *remap) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - sbsocramregs_t *regs; - bool wasup; - uint corerev; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - if (!set) - *enable = *protect = *remap = 0; - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 10) { - uint32 extcinfo; - uint8 nb; - uint8 i; - uint32 bankidx, bankinfo; - - extcinfo = R_REG(sii->osh, ®s->extracoreinfo); - nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); - for (i = 0; i < nb; i++) { - bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); - W_REG(sii->osh, ®s->bankidx, bankidx); - bankinfo = R_REG(sii->osh, ®s->bankinfo); - if (set) { - bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; - bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; - bankinfo &= ~SOCRAM_BANKINFO_DEVRAMREMAP_MASK; - if (*enable) { - bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); - if (*protect) - bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); - if ((corerev >= 16) && *remap) - bankinfo |= - (1 << SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT); - } - W_REG(sii->osh, ®s->bankinfo, bankinfo); - } - else if (i == 0) { - if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { - *enable = 1; - if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) - *protect = 1; - if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) - *remap = 1; - } - } - } - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); -} - -bool -si_socdevram_remap_isenb(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - sbsocramregs_t *regs; - bool wasup, remap = FALSE; - uint corerev; - uint32 extcinfo; - uint8 nb; - uint8 i; - uint32 bankidx, bankinfo; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 16) { - extcinfo = R_REG(sii->osh, ®s->extracoreinfo); - nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); - for (i = 0; i < nb; i++) { - bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); - W_REG(sii->osh, ®s->bankidx, bankidx); - bankinfo = R_REG(sii->osh, ®s->bankinfo); - if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { - remap = TRUE; - break; - } - } - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - return remap; -} - -bool -si_socdevram_pkg(si_t *sih) -{ - if (si_socdevram_size(sih) > 0) - return TRUE; - else - return FALSE; -} - -uint32 -si_socdevram_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - uint32 memsize = 0; - sbsocramregs_t *regs; - bool wasup; - uint corerev; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 10) { - uint32 extcinfo; - uint8 nb; - uint8 i; - - extcinfo = R_REG(sii->osh, ®s->extracoreinfo); - nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); - for (i = 0; i < nb; i++) - memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - -uint32 -si_socdevram_remap_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - uint32 memsize = 0, banksz; - sbsocramregs_t *regs; - bool wasup; - uint corerev; - uint32 extcinfo; - uint8 nb; - uint8 i; - uint32 bankidx, bankinfo; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 16) { - extcinfo = R_REG(sii->osh, ®s->extracoreinfo); - nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); - - /* - * FIX: A0 Issue: Max addressable is 512KB, instead 640KB - * Only four banks are accessible to ARM - */ - if ((corerev == 16) && (nb == 5)) - nb = 4; - - for (i = 0; i < nb; i++) { - bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); - W_REG(sii->osh, ®s->bankidx, bankidx); - bankinfo = R_REG(sii->osh, ®s->bankinfo); - if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { - banksz = socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); - memsize += banksz; - } else { - /* Account only consecutive banks for now */ - break; - } - } - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - -/** Return the RAM size of the SOCRAM core */ -uint32 -si_socram_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - - sbsocramregs_t *regs; - bool wasup; - uint corerev; - uint32 coreinfo; - uint memsize = 0; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - corerev = si_corerev(sih); - coreinfo = R_REG(sii->osh, ®s->coreinfo); - - /* Calculate size from coreinfo based on rev */ - if (corerev == 0) - memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); - else if (corerev < 3) { - memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); - memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - } else if ((corerev <= 7) || (corerev == 12)) { - uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - uint bsz = (coreinfo & SRCI_SRBSZ_MASK); - uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; - if (lss != 0) - nb --; - memsize = nb * (1 << (bsz + SR_BSZ_BASE)); - if (lss != 0) - memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); - } else { - uint8 i; - uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - for (i = 0; i < nb; i++) - memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - - -/** Return the TCM-RAM size of the ARMCR4 core. */ -uint32 -si_tcm_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - uint8 *regs; - bool wasup; - uint32 corecap; - uint memsize = 0; - uint32 nab = 0; - uint32 nbb = 0; - uint32 totb = 0; - uint32 bxinfo = 0; - uint32 idx = 0; - uint32 *arm_cap_reg; - uint32 *arm_bidx; - uint32 *arm_binfo; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to CR4 core */ - if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0))) - goto done; - - /* Get info for determining size. If in reset, come out of reset, - * but remain in halt - */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT); - - arm_cap_reg = (uint32 *)(regs + SI_CR4_CAP); - corecap = R_REG(sii->osh, arm_cap_reg); - - nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; - nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; - totb = nab + nbb; - - arm_bidx = (uint32 *)(regs + SI_CR4_BANKIDX); - arm_binfo = (uint32 *)(regs + SI_CR4_BANKINFO); - for (idx = 0; idx < totb; idx++) { - W_REG(sii->osh, arm_bidx, idx); - - bxinfo = R_REG(sii->osh, arm_binfo); - memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - -bool -si_has_flops(si_t *sih) -{ - uint origidx, cr4_rev; - - /* Find out CR4 core revision */ - origidx = si_coreidx(sih); - if (si_setcore(sih, ARMCR4_CORE_ID, 0)) { - cr4_rev = si_corerev(sih); - si_setcoreidx(sih, origidx); - - if (cr4_rev == 1 || cr4_rev >= 3) - return TRUE; - } - return FALSE; -} - -uint32 -si_socram_srmem_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - - sbsocramregs_t *regs; - bool wasup; - uint corerev; - uint32 coreinfo; - uint memsize = 0; - - if ((CHIPID(sih->chip) == BCM4334_CHIP_ID) && (CHIPREV(sih->chiprev) < 2)) { - return (32 * 1024); - } - - if (CHIPID(sih->chip) == BCM43430_CHIP_ID) { - return (64 * 1024); - } - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - corerev = si_corerev(sih); - coreinfo = R_REG(sii->osh, ®s->coreinfo); - - /* Calculate size from coreinfo based on rev */ - if (corerev >= 16) { - uint8 i; - uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - for (i = 0; i < nb; i++) { - W_REG(sii->osh, ®s->bankidx, i); - if (R_REG(sii->osh, ®s->bankinfo) & SOCRAM_BANKINFO_RETNTRAM_MASK) - memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); - } - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - - -#if !defined(_CFEZ_) || defined(CFG_WL) -void -si_btcgpiowar(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - chipcregs_t *cc; - - /* Make sure that there is ChipCommon core present && - * UART_TX is strapped to 1 - */ - if (!(sih->cccaps & CC_CAP_UARTGPIO)) - return; - - /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */ - INTR_OFF(sii, intr_val); - - origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - ASSERT(cc != NULL); - - W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04); - - /* restore the original index */ - si_setcoreidx(sih, origidx); - - INTR_RESTORE(sii, intr_val); -} - -void -si_chipcontrl_btshd0_4331(si_t *sih, bool on) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - chipcregs_t *cc; - uint origidx; - uint32 val; - uint intr_val = 0; - - INTR_OFF(sii, intr_val); - - origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - val = R_REG(sii->osh, &cc->chipcontrol); - - /* bt_shd0 controls are same for 4331 chiprevs 0 and 1, packages 12x9 and 12x12 */ - if (on) { - /* Enable bt_shd0 on gpio4: */ - val |= (CCTRL4331_BT_SHD0_ON_GPIO4); - W_REG(sii->osh, &cc->chipcontrol, val); - } else { - val &= ~(CCTRL4331_BT_SHD0_ON_GPIO4); - W_REG(sii->osh, &cc->chipcontrol, val); - } - - /* restore the original index */ - si_setcoreidx(sih, origidx); - - INTR_RESTORE(sii, intr_val); -} - -void -si_chipcontrl_restore(si_t *sih, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - W_REG(sii->osh, &cc->chipcontrol, val); - si_setcoreidx(sih, origidx); -} - -uint32 -si_chipcontrl_read(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - uint32 val; - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - val = R_REG(sii->osh, &cc->chipcontrol); - si_setcoreidx(sih, origidx); - return val; -} - -void -si_chipcontrl_epa4331(si_t *sih, bool on) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - uint32 val; - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - val = R_REG(sii->osh, &cc->chipcontrol); - - if (on) { - if (sih->chippkg == 9 || sih->chippkg == 0xb) { - val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); - /* Ext PA Controls for 4331 12x9 Package */ - W_REG(sii->osh, &cc->chipcontrol, val); - } else { - /* Ext PA Controls for 4331 12x12 Package */ - if (sih->chiprev > 0) { - W_REG(sii->osh, &cc->chipcontrol, val | - (CCTRL4331_EXTPA_EN) | (CCTRL4331_EXTPA_EN2)); - } else { - W_REG(sii->osh, &cc->chipcontrol, val | (CCTRL4331_EXTPA_EN)); - } - } - } else { - val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_EN2 | CCTRL4331_EXTPA_ON_GPIO2_5); - W_REG(sii->osh, &cc->chipcontrol, val); - } - - si_setcoreidx(sih, origidx); -} - -/** switch muxed pins, on: SROM, off: FEMCTRL. Called for a family of ac chips, not just 4360. */ -void -si_chipcontrl_srom4360(si_t *sih, bool on) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - uint32 val; - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - val = R_REG(sii->osh, &cc->chipcontrol); - - if (on) { - val &= ~(CCTRL4360_SECI_MODE | - CCTRL4360_BTSWCTRL_MODE | - CCTRL4360_EXTRA_FEMCTRL_MODE | - CCTRL4360_BT_LGCY_MODE | - CCTRL4360_CORE2FEMCTRL4_ON); - - W_REG(sii->osh, &cc->chipcontrol, val); - } else { - } - - si_setcoreidx(sih, origidx); -} - -void -si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl) -{ - si_info_t *sii; - chipcregs_t *cc; - uint origidx; - uint32 val; - bool sel_chip; - - sel_chip = (CHIPID(sih->chip) == BCM4331_CHIP_ID) || - (CHIPID(sih->chip) == BCM43431_CHIP_ID); - sel_chip &= ((sih->chippkg == 9 || sih->chippkg == 0xb)); - - if (!sel_chip) - return; - - sii = SI_INFO(sih); - origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - val = R_REG(sii->osh, &cc->chipcontrol); - - if (enter_wowl) { - val |= CCTRL4331_EXTPA_EN; - W_REG(sii->osh, &cc->chipcontrol, val); - } else { - val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); - W_REG(sii->osh, &cc->chipcontrol, val); - } - si_setcoreidx(sih, origidx); -} -#endif - -uint -si_pll_reset(si_t *sih) -{ - uint err = 0; - - return (err); -} - -/** Enable BT-COEX & Ex-PA for 4313 */ -void -si_epa_4313war(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - /* EPA Fix */ - W_REG(sii->osh, &cc->gpiocontrol, - R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); - - si_setcoreidx(sih, origidx); -} - -void -si_clk_pmu_htavail_set(si_t *sih, bool set_clear) -{ -} - -/** Re-enable synth_pwrsw resource in min_res_mask for 4313 */ -void -si_pmu_synth_pwrsw_4313_war(si_t *sih) -{ -} - -/** WL/BT control for 4313 btcombo boards >= P250 */ -void -si_btcombo_p250_4313_war(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - W_REG(sii->osh, &cc->gpiocontrol, - R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_5_6_EN_MASK); - - W_REG(sii->osh, &cc->gpioouten, - R_REG(sii->osh, &cc->gpioouten) | GPIO_CTRL_5_6_EN_MASK); - - si_setcoreidx(sih, origidx); -} -void -si_btc_enable_chipcontrol(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - /* BT fix */ - W_REG(sii->osh, &cc->chipcontrol, - R_REG(sii->osh, &cc->chipcontrol) | CC_BTCOEX_EN_MASK); - - si_setcoreidx(sih, origidx); -} -void -si_btcombo_43228_war(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - W_REG(sii->osh, &cc->gpioouten, GPIO_CTRL_7_6_EN_MASK); - W_REG(sii->osh, &cc->gpioout, GPIO_OUT_7_EN_MASK); - - si_setcoreidx(sih, origidx); -} - -/** check if the device is removed */ -bool -si_deviceremoved(si_t *sih) -{ - uint32 w; - - switch (BUSTYPE(sih->bustype)) { - case PCI_BUS: - ASSERT(SI_INFO(sih)->osh != NULL); - w = OSL_PCI_READ_CONFIG(SI_INFO(sih)->osh, PCI_CFG_VID, sizeof(uint32)); - if ((w & 0xFFFF) != VENDOR_BROADCOM) - return TRUE; - break; - } - return FALSE; -} - -bool -si_is_sprom_available(si_t *sih) -{ - if (sih->ccrev >= 31) { - si_info_t *sii; - uint origidx; - chipcregs_t *cc; - uint32 sromctrl; - - if ((sih->cccaps & CC_CAP_SROM) == 0) - return FALSE; - - sii = SI_INFO(sih); - origidx = sii->curidx; - cc = si_setcoreidx(sih, SI_CC_IDX); - ASSERT(cc); - sromctrl = R_REG(sii->osh, &cc->sromcontrol); - si_setcoreidx(sih, origidx); - return (sromctrl & SRC_PRESENT); - } - - switch (CHIPID(sih->chip)) { - case BCM4312_CHIP_ID: - return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL); - case BCM4325_CHIP_ID: - return (sih->chipst & CST4325_SPROM_SEL) != 0; - case BCM4322_CHIP_ID: case BCM43221_CHIP_ID: case BCM43231_CHIP_ID: - case BCM43222_CHIP_ID: case BCM43111_CHIP_ID: case BCM43112_CHIP_ID: - case BCM4342_CHIP_ID: { - uint32 spromotp; - spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >> - CST4322_SPROM_OTP_SEL_SHIFT; - return (spromotp & CST4322_SPROM_PRESENT) != 0; - } - case BCM4329_CHIP_ID: - return (sih->chipst & CST4329_SPROM_SEL) != 0; - case BCM4315_CHIP_ID: - return (sih->chipst & CST4315_SPROM_SEL) != 0; - case BCM4319_CHIP_ID: - return (sih->chipst & CST4319_SPROM_SEL) != 0; - case BCM4336_CHIP_ID: - case BCM43362_CHIP_ID: - return (sih->chipst & CST4336_SPROM_PRESENT) != 0; - case BCM4330_CHIP_ID: - return (sih->chipst & CST4330_SPROM_PRESENT) != 0; - case BCM4313_CHIP_ID: - return (sih->chipst & CST4313_SPROM_PRESENT) != 0; - case BCM4331_CHIP_ID: - case BCM43431_CHIP_ID: - return (sih->chipst & CST4331_SPROM_PRESENT) != 0; - case BCM43239_CHIP_ID: - return ((sih->chipst & CST43239_SPROM_MASK) && - !(sih->chipst & CST43239_SFLASH_MASK)); - case BCM4324_CHIP_ID: - case BCM43242_CHIP_ID: - return ((sih->chipst & CST4324_SPROM_MASK) && - !(sih->chipst & CST4324_SFLASH_MASK)); - case BCM4335_CHIP_ID: - case BCM4345_CHIP_ID: - return ((sih->chipst & CST4335_SPROM_MASK) && - !(sih->chipst & CST4335_SFLASH_MASK)); - case BCM4349_CHIP_GRPID: - return (sih->chipst & CST4349_SPROM_PRESENT) != 0; - break; - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM4356_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43569_CHIP_ID: - case BCM43570_CHIP_ID: - case BCM4358_CHIP_ID: - return (sih->chipst & CST4350_SPROM_PRESENT) != 0; - case BCM43602_CHIP_ID: - return (sih->chipst & CST43602_SPROM_PRESENT) != 0; - case BCM43131_CHIP_ID: - case BCM43217_CHIP_ID: - case BCM43227_CHIP_ID: - case BCM43228_CHIP_ID: - case BCM43428_CHIP_ID: - return (sih->chipst & CST43228_OTP_PRESENT) != CST43228_OTP_PRESENT; - default: - return TRUE; - } -} - - -uint32 si_get_sromctl(si_t *sih) -{ - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - uint32 sromctl; - osl_t *osh = si_osh(sih); - - cc = si_setcoreidx(sih, SI_CC_IDX); - ASSERT((uintptr)cc); - - sromctl = R_REG(osh, &cc->sromcontrol); - - /* return to the original core */ - si_setcoreidx(sih, origidx); - return sromctl; -} - -int si_set_sromctl(si_t *sih, uint32 value) -{ - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - osl_t *osh = si_osh(sih); - - cc = si_setcoreidx(sih, SI_CC_IDX); - ASSERT((uintptr)cc); - - /* get chipcommon rev */ - if (si_corerev(sih) < 32) - return BCME_UNSUPPORTED; - - W_REG(osh, &cc->sromcontrol, value); - - /* return to the original core */ - si_setcoreidx(sih, origidx); - return BCME_OK; - -} - -uint -si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val) -{ - uint origidx, intr_val = 0; - uint ret_val; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - origidx = si_coreidx(sih); - - INTR_OFF(sii, intr_val); - si_setcoreidx(sih, coreidx); - - ret_val = si_wrapperreg(sih, offset, mask, val); - - /* return to the original core */ - si_setcoreidx(sih, origidx); - INTR_RESTORE(sii, intr_val); - return ret_val; -} - - -/* cleanup the timer from the host when ARM is been halted - * without a chance for ARM cleanup its resources - * If left not cleanup, Intr from a software timer can still - * request HT clk when ARM is halted. - */ -uint32 -si_pmu_res_req_timer_clr(si_t *sih) -{ - uint32 mask; - - mask = PRRT_REQ_ACTIVE | PRRT_INTEN | PRRT_HT_REQ; - if (CHIPID(sih->chip) != BCM4328_CHIP_ID) - mask <<= 14; - /* clear mask bits */ - pmu_corereg(sih, SI_CC_IDX, res_req_timer, mask, 0); - /* readback to ensure write completes */ - return pmu_corereg(sih, SI_CC_IDX, res_req_timer, 0, 0); -} - -/** turn on/off rfldo */ -void -si_pmu_rfldo(si_t *sih, bool on) -{ -} - - -#ifdef SURVIVE_PERST_ENAB -static uint32 -si_pcie_survive_perst(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - - if (!PCIE(sii)) - return (0); - - return pcie_survive_perst(sii->pch, mask, val); -} - -static void -si_watchdog_reset(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - uint32 i; - - /* issue a watchdog reset */ - pmu_corereg(sih, SI_CC_IDX, pmuwatchdog, 2, 2); - /* do busy wait for 20ms */ - for (i = 0; i < 2000; i++) { - OSL_DELAY(10); - } -} -#endif /* SURVIVE_PERST_ENAB */ - -void -si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 sperst_val) -{ -#ifdef SURVIVE_PERST_ENAB - if (BUSTYPE(sih->bustype) != PCI_BUS) - return; - - if ((CHIPID(sih->chip) != BCM4360_CHIP_ID && CHIPID(sih->chip) != BCM4352_CHIP_ID) || - (CHIPREV(sih->chiprev) >= 4)) - return; - - if (reset) { - si_info_t *sii = SI_INFO(sih); - uint32 bar0win, bar0win_after; - - /* save the bar0win */ - bar0win = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); - - si_watchdog_reset(sih); - - bar0win_after = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); - if (bar0win_after != bar0win) { - SI_ERROR(("%s: bar0win before %08x, bar0win after %08x\n", - __FUNCTION__, bar0win, bar0win_after)); - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32), bar0win); - } - } - if (sperst_mask) { - /* enable survive perst */ - si_pcie_survive_perst(sih, sperst_mask, sperst_val); - } -#endif /* SURVIVE_PERST_ENAB */ -} - -void -si_pcie_ltr_war(si_t *sih) -{ -} - -void -si_pcie_hw_LTR_war(si_t *sih) -{ -} - -void -si_pciedev_reg_pm_clk_period(si_t *sih) -{ -} - -void -si_pciedev_crwlpciegen2(si_t *sih) -{ -} - -void -si_pcie_prep_D3(si_t *sih, bool enter_D3) -{ -} diff --git a/drivers/net/wireless/bcmdhd/siutils_priv.h b/drivers/net/wireless/bcmdhd/siutils_priv.h deleted file mode 100644 index 3941db8895c7..000000000000 --- a/drivers/net/wireless/bcmdhd/siutils_priv.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Include file private to the SOC Interconnect support files. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: siutils_priv.h 474902 2014-05-02 18:31:33Z $ - */ - -#ifndef _siutils_priv_h_ -#define _siutils_priv_h_ - -#define SI_ERROR(args) - -#define SI_MSG(args) - -#ifdef BCMDBG_SI -#define SI_VMSG(args) printf args -#else -#define SI_VMSG(args) -#endif - -#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) - -typedef uint32 (*si_intrsoff_t)(void *intr_arg); -typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg); -typedef bool (*si_intrsenabled_t)(void *intr_arg); - -typedef struct gpioh_item { - void *arg; - bool level; - gpio_handler_t handler; - uint32 event; - struct gpioh_item *next; -} gpioh_item_t; - - -#define SI_GPIO_MAX 16 - -typedef struct gci_gpio_item { - void *arg; - uint8 gci_gpio; - uint8 status; - gci_gpio_handler_t handler; - struct gci_gpio_item *next; -} gci_gpio_item_t; - - -typedef struct si_cores_info { - void *regs[SI_MAXCORES]; /* other regs va */ - - uint coreid[SI_MAXCORES]; /* id of each core */ - uint32 coresba[SI_MAXCORES]; /* backplane address of each core */ - void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */ - uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */ - uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */ - uint32 coresba2_size[SI_MAXCORES]; /* second address space size */ - - void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ - uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ - - uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */ - uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */ -} si_cores_info_t; - -/* misc si info needed by some of the routines */ -typedef struct si_info { - struct si_pub pub; /* back plane public state (must be first field) */ - - void *osh; /* osl os handle */ - void *sdh; /* bcmsdh handle */ - - uint dev_coreid; /* the core provides driver functions */ - void *intr_arg; /* interrupt callback function arg */ - si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ - si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ - si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ - - void *pch; /* PCI/E core handle */ - - gpioh_item_t *gpioh_head; /* GPIO event handlers list */ - - bool memseg; /* flag to toggle MEM_SEG register */ - - char *vars; - uint varsz; - - void *curmap; /* current regs va */ - - uint curidx; /* current core index */ - uint numcores; /* # discovered cores */ - - void *curwrap; /* current wrapper va */ - - uint32 oob_router; /* oob router registers for axi */ - - void *cores_info; - gci_gpio_item_t *gci_gpio_head; /* gci gpio interrupts head */ - uint chipnew; /* new chip number */ -} si_info_t; - - -#define SI_INFO(sih) ((si_info_t *)(uintptr)sih) - -#define GOODCOREADDR(x, b) (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ - ISALIGNED((x), SI_CORE_SIZE)) -#define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE)) -#define BADCOREADDR 0 -#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES) -#define NOREV -1 /* Invalid rev */ - -#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ - ((si)->pub.buscoretype == PCI_CORE_ID)) - -#define PCIE_GEN1(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ - ((si)->pub.buscoretype == PCIE_CORE_ID)) - -#define PCIE_GEN2(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ - ((si)->pub.buscoretype == PCIE2_CORE_ID)) - -#define PCIE(si) (PCIE_GEN1(si) || PCIE_GEN2(si)) - -#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE)) - -/* Newer chips can access PCI/PCIE and CC core without requiring to change - * PCI BAR0 WIN - */ -#define SI_FAST(si) (PCIE(si) || (PCI(si) && ((si)->pub.buscorerev >= 13))) - -#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET)) -#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET)) - -/* - * 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 && (cores_info)->coreid[(si)->curidx] == (si)->dev_coreid) { \ - intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); } -#define INTR_RESTORE(si, intr_val) \ - if ((si)->intrsrestore_fn && (cores_info)->coreid[(si)->curidx] == (si)->dev_coreid) { \ - (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } - -/* 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 */ - -/* Force fast clock for 4360b0 */ -#define PCI_FORCEHT(si) \ - (((PCIE_GEN1(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \ - ((PCI(si) || PCIE_GEN1(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \ - (PCIE_GEN1(si) && (si->pub.chip == BCM4716_CHIP_ID)) || \ - (PCIE_GEN1(si) && (si->pub.chip == BCM4748_CHIP_ID))) - -/* GPIO Based LED powersave defines */ -#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ -#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ - -#ifndef DEFAULT_GPIOTIMERVAL -#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) -#endif - -/* Silicon Backplane externs */ -extern void sb_scan(si_t *sih, void *regs, uint devid); -extern uint sb_coreid(si_t *sih); -extern uint sb_intflag(si_t *sih); -extern uint sb_flag(si_t *sih); -extern void sb_setint(si_t *sih, int siflag); -extern uint sb_corevendor(si_t *sih); -extern uint sb_corerev(si_t *sih); -extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -extern uint32 *sb_corereg_addr(si_t *sih, uint coreidx, uint regoff); -extern bool sb_iscoreup(si_t *sih); -extern void *sb_setcoreidx(si_t *sih, uint coreidx); -extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val); -extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); -extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val); -extern void sb_commit(si_t *sih); -extern uint32 sb_base(uint32 admatch); -extern uint32 sb_size(uint32 admatch); -extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -extern void sb_core_disable(si_t *sih, uint32 bits); -extern uint32 sb_addrspace(si_t *sih, uint asidx); -extern uint32 sb_addrspacesize(si_t *sih, uint asidx); -extern int sb_numaddrspaces(si_t *sih); - -extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); - -extern bool sb_taclear(si_t *sih, bool details); - -#if defined(BCMDBG_PHYDUMP) -extern void sb_dumpregs(si_t *sih, struct bcmstrbuf *b); -#endif - -/* Wake-on-wireless-LAN (WOWL) */ -extern bool sb_pci_pmecap(si_t *sih); -struct osl_info; -extern bool sb_pci_fastpmecap(struct osl_info *osh); -extern bool sb_pci_pmeclr(si_t *sih); -extern void sb_pci_pmeen(si_t *sih); -extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset); - -/* AMBA Interconnect exported externs */ -extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, - void *sdh, char **vars, uint *varsz); -extern si_t *ai_kattach(osl_t *osh); -extern void ai_scan(si_t *sih, void *regs, uint devid); - -extern uint ai_flag(si_t *sih); -extern uint ai_flag_alt(si_t *sih); -extern void ai_setint(si_t *sih, int siflag); -extern uint ai_coreidx(si_t *sih); -extern uint ai_corevendor(si_t *sih); -extern uint ai_corerev(si_t *sih); -extern uint32 *ai_corereg_addr(si_t *sih, uint coreidx, uint regoff); -extern bool ai_iscoreup(si_t *sih); -extern void *ai_setcoreidx(si_t *sih, uint coreidx); -extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val); -extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); -extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val); -extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -extern void ai_d11rsdb_core_reset(si_t *sih, uint32 bits, - uint32 resetbits, void *p, void *s); -extern void ai_core_disable(si_t *sih, uint32 bits); -extern void ai_d11rsdb_core_disable(const si_info_t *sii, uint32 bits, - aidmp_t *pmacai, aidmp_t *smacai); -extern int ai_numaddrspaces(si_t *sih); -extern uint32 ai_addrspace(si_t *sih, uint asidx); -extern uint32 ai_addrspacesize(si_t *sih, uint asidx); -extern void ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); -extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val); - -#if defined(BCMDBG_PHYDUMP) -extern void ai_dumpregs(si_t *sih, struct bcmstrbuf *b); -#endif - - -#define ub_scan(a, b, c) do {} while (0) -#define ub_flag(a) (0) -#define ub_setint(a, b) do {} while (0) -#define ub_coreidx(a) (0) -#define ub_corevendor(a) (0) -#define ub_corerev(a) (0) -#define ub_iscoreup(a) (0) -#define ub_setcoreidx(a, b) (0) -#define ub_core_cflags(a, b, c) (0) -#define ub_core_cflags_wo(a, b, c) do {} while (0) -#define ub_core_sflags(a, b, c) (0) -#define ub_corereg(a, b, c, d, e) (0) -#define ub_core_reset(a, b, c) do {} while (0) -#define ub_core_disable(a, b) do {} while (0) -#define ub_numaddrspaces(a) (0) -#define ub_addrspace(a, b) (0) -#define ub_addrspacesize(a, b) (0) -#define ub_view(a, b) do {} while (0) -#define ub_dumpregs(a, b) do {} while (0) - -#endif /* _siutils_priv_h_ */ diff --git a/drivers/net/wireless/bcmdhd/uamp_api.h b/drivers/net/wireless/bcmdhd/uamp_api.h deleted file mode 100644 index bffadb2ea658..000000000000 --- a/drivers/net/wireless/bcmdhd/uamp_api.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Name: uamp_api.h - * - * Description: Universal AMP API - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: uamp_api.h 467328 2014-04-03 01:23:40Z $ - * - */ - - -#ifndef UAMP_API_H -#define UAMP_API_H - - -#include "typedefs.h" - - -/***************************************************************************** -** Constant and Type Definitions -****************************************************************************** -*/ - -#define BT_API - -/* Types. */ -typedef bool BOOLEAN; -typedef uint8 UINT8; -typedef uint16 UINT16; - - -/* UAMP identifiers */ -#define UAMP_ID_1 1 -#define UAMP_ID_2 2 -typedef UINT8 tUAMP_ID; - -/* UAMP event ids (used by UAMP_CBACK) */ -#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */ -#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */ -#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */ -typedef UINT8 tUAMP_EVT; - - -/* UAMP Channels */ -#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */ -#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */ -#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */ -typedef UINT8 tUAMP_CH; - -/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */ -typedef union { - tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */ -} tUAMP_EVT_DATA; - - -/***************************************************************************** -** -** Function: UAMP_CBACK -** -** Description: Callback for events. Register callback using UAMP_Init. -** -** Parameters amp_id: AMP device identifier that generated the event -** amp_evt: event id -** p_amp_evt_data: pointer to event-specific data -** -****************************************************************************** -*/ -typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data); - -/***************************************************************************** -** external function declarations -****************************************************************************** -*/ -#ifdef __cplusplus -extern "C" -{ -#endif - -/***************************************************************************** -** -** Function: UAMP_Init -** -** Description: Initialize UAMP driver -** -** Parameters p_cback: Callback function for UAMP event notification -** -****************************************************************************** -*/ -BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback); - - -/***************************************************************************** -** -** Function: UAMP_Open -** -** Description: Open connection to local AMP device. -** -** Parameters app_id: Application specific AMP identifer. This value -** will be included in AMP messages sent to the -** BTU task, to identify source of the message -** -****************************************************************************** -*/ -BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id); - -/***************************************************************************** -** -** Function: UAMP_Close -** -** Description: Close connection to local AMP device. -** -** Parameters app_id: Application specific AMP identifer. -** -****************************************************************************** -*/ -BT_API void UAMP_Close(tUAMP_ID amp_id); - - -/***************************************************************************** -** -** Function: UAMP_Write -** -** Description: Send buffer to AMP device. Frees GKI buffer when done. -** -** -** Parameters: app_id: AMP identifer. -** p_buf: pointer to buffer to write -** num_bytes: number of bytes to write -** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD -** -** Returns: number of bytes written -** -****************************************************************************** -*/ -BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel); - -/***************************************************************************** -** -** Function: UAMP_Read -** -** Description: Read incoming data from AMP. Call after receiving a -** UAMP_EVT_RX_READY callback event. -** -** Parameters: app_id: AMP identifer. -** p_buf: pointer to buffer for holding incoming AMP data -** buf_size: size of p_buf -** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT -** -** Returns: number of bytes read -** -****************************************************************************** -*/ -BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel); - -#ifdef __cplusplus -} -#endif - -#endif /* UAMP_API_H */ diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c deleted file mode 100644 index 90d97896ce90..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ /dev/null @@ -1,3226 +0,0 @@ -/* - * Linux cfg80211 driver - Android related functions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * Copyright (C) 2015 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_android.c 675132 2016-12-14 09:13:20Z $ - */ - -#include -#include -#include -#ifdef CONFIG_COMPAT -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef PNO_SUPPORT -#include -#endif -#ifdef BCMSDIO -#include -#endif -#ifdef WL_CFG80211 -#include -#endif - -/* - * Android private command strings, PLEASE define new private commands here - * so they can be updated easily in the future (if needed) - */ - -#define CMD_START "START" -#define CMD_STOP "STOP" -#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" -#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" -#define CMD_RSSI "RSSI" -#define CMD_LINKSPEED "LINKSPEED" -#ifdef PKT_FILTER_SUPPORT -#define CMD_RXFILTER_START "RXFILTER-START" -#define CMD_RXFILTER_STOP "RXFILTER-STOP" -#define CMD_RXFILTER_ADD "RXFILTER-ADD" -#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" -#endif /* PKT_FILTER_SUPPORT */ -#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" -#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" -#define CMD_BTCOEXMODE "BTCOEXMODE" -#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" -#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" -#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" -#define CMD_SETFWPATH "SETFWPATH" -#define CMD_SETBAND "SETBAND" -#define CMD_GETBAND "GETBAND" -#define CMD_COUNTRY "COUNTRY" -#define CMD_P2P_SET_NOA "P2P_SET_NOA" -#if !defined WL_ENABLE_P2P_IF -#define CMD_P2P_GET_NOA "P2P_GET_NOA" -#endif /* WL_ENABLE_P2P_IF */ -#define CMD_P2P_SD_OFFLOAD "P2P_SD_" -#define CMD_P2P_SET_PS "P2P_SET_PS" -#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" -#define CMD_SETROAMMODE "SETROAMMODE" -#define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA" -#define CMD_MIRACAST "MIRACAST" -#define CMD_NAN "NAN_" - -#if defined(WL_SUPPORT_AUTO_CHANNEL) -#define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS" -#endif /* WL_SUPPORT_AUTO_CHANNEL */ - - -#define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */ -#define CMD_CHANSPEC "CHANSPEC" -#define CMD_DATARATE "DATARATE" -#define CMD_ASSOC_CLIENTS "ASSOCLIST" -#define CMD_SET_CSA "SETCSA" - -#define CMD_KEEP_ALIVE "KEEPALIVE" - -#ifdef BCMCCX -/* CCX Private Commands */ -#define CMD_GETCCKM_RN "get cckm_rn" -#define CMD_SETCCKM_KRK "set cckm_krk" -#define CMD_GET_ASSOC_RES_IES "get assoc_res_ies" -#endif - -#ifdef PNO_SUPPORT -#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" -#define CMD_PNOSETUP_SET "PNOSETUP " -#define CMD_PNOENABLE_SET "PNOFORCE" -#define CMD_PNODEBUG_SET "PNODEBUG" -#define CMD_WLS_BATCHING "WLS_BATCHING" -#endif /* PNO_SUPPORT */ - -#define CMD_OKC_SET_PMK "SET_PMK" -#define CMD_OKC_ENABLE "OKC_ENABLE" - -#define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER" - -#ifdef WLFBT -#define CMD_GET_FTKEY "GET_FTKEY" -#endif - -#ifdef WLAIBSS -#define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT" -#define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO" -#define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL" -#define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE" -#define CMD_SETIBSSAMPDU "SETIBSSAMPDU" -#define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE" -#endif /* WLAIBSS */ - -#define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD" -#define CMD_ROAM_OFFLOAD_APLIST "SETROAMOFFLAPLIST" -#define CMD_GET_LINK_STATUS "GETLINKSTATUS" - - -#ifdef SET_RPS_CPUS -#define CMD_RPSMODE "RPSMODE" -#endif /* SET_RPS_CPUS */ - -/* related with CMD_GET_LINK_STATUS */ -#define WL_ANDROID_LINK_VHT 0x01 -#define WL_ANDROID_LINK_MIMO 0x02 -#define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04 -#define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08 - -/* miracast related definition */ -#define MIRACAST_MODE_OFF 0 -#define MIRACAST_MODE_SOURCE 1 -#define MIRACAST_MODE_SINK 2 - -#ifndef MIRACAST_AMPDU_SIZE -#define MIRACAST_AMPDU_SIZE 8 -#endif - -#ifndef MIRACAST_MCHAN_ALGO -#define MIRACAST_MCHAN_ALGO 1 -#endif - -#ifndef MIRACAST_MCHAN_BW -#define MIRACAST_MCHAN_BW 25 -#endif - -#ifdef CHANGE_SCAN_TIME -static int miracast_scan_time[3][2] = { - { WLC_GET_SCAN_CHANNEL_TIME, 20 }, - { WLC_GET_SCAN_UNASSOC_TIME, 20 }, - { WLC_GET_SCAN_PASSIVE_TIME, 40 } - }; -#endif - -#ifdef CONNECTION_STATISTICS -#define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS" - -struct connection_stats { - u32 txframe; - u32 txbyte; - u32 txerror; - u32 rxframe; - u32 rxbyte; - u32 txfail; - u32 txretry; - u32 txretrie; - u32 txrts; - u32 txnocts; - u32 txexptime; - u32 txrate; - u8 chan_idle; -}; -#endif /* CONNECTION_STATISTICS */ - -static LIST_HEAD(miracast_resume_list); -static u8 miracast_cur_mode; - -struct io_cfg { - s8 *iovar; - s32 param; - u32 ioctl; - void *arg; - u32 len; - struct list_head list; -}; - -typedef struct _android_wifi_priv_cmd { - char *buf; - int used_len; - int total_len; -} android_wifi_priv_cmd; - -#ifdef CONFIG_COMPAT -typedef struct _compat_android_wifi_priv_cmd { - compat_caddr_t buf; - int used_len; - int total_len; -} compat_android_wifi_priv_cmd; -#endif /* CONFIG_COMPAT */ - -#if defined(BCMFW_ROAM_ENABLE) -#define CMD_SET_ROAMPREF "SET_ROAMPREF" - -#define MAX_NUM_SUITES 10 -#define WIDTH_AKM_SUITE 8 -#define JOIN_PREF_RSSI_LEN 0x02 -#define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */ -#define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */ -#define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */ -#define JOIN_PREF_MAX_WPA_TUPLES 16 -#define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \ - (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES)) -#endif /* BCMFW_ROAM_ENABLE */ - -#ifdef WL_GENL -static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info); -static int wl_genl_init(void); -static int wl_genl_deinit(void); - -extern struct net init_net; -/* attribute policy: defines which attribute has which type (e.g int, char * etc) - * possible values defined in net/netlink.h - */ -static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = { - [BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING }, - [BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY }, -}; - -#define WL_GENL_VER 1 -/* family definition */ -static struct genl_family wl_genl_family = { - .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */ - .hdrsize = 0, - .name = "bcm-genl", /* Netlink I/F for Android */ - .version = WL_GENL_VER, /* Version Number */ - .maxattr = BCM_GENL_ATTR_MAX, -}; - -/* commands: mapping between the command enumeration and the actual function */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) -struct genl_ops wl_genl_ops[] = { - { - .cmd = BCM_GENL_CMD_MSG, - .flags = 0, - .policy = wl_genl_policy, - .doit = wl_genl_handle_msg, - .dumpit = NULL, - }, -}; -#else -struct genl_ops wl_genl_ops = { - .cmd = BCM_GENL_CMD_MSG, - .flags = 0, - .policy = wl_genl_policy, - .doit = wl_genl_handle_msg, - .dumpit = NULL, - -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) -static struct genl_multicast_group wl_genl_mcast[] = { - { .name = "bcm-genl-mcast", }, -}; -#else -static struct genl_multicast_group wl_genl_mcast = { - .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */ - .name = "bcm-genl-mcast", -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */ -#endif /* WL_GENL */ - -/** - * Extern function declarations (TODO: move them to dhd_linux.h) - */ -int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); -int dhd_dev_init_ioctl(struct net_device *dev); -#ifdef WL_CFG80211 -int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); -int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command); -#else -int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) -{ return 0; } -int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) -{ return 0; } -int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) -{ return 0; } -int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) -{ return 0; } -#endif /* WK_CFG80211 */ - - -#ifdef ENABLE_4335BT_WAR -extern int bcm_bt_lock(int cookie); -extern void bcm_bt_unlock(int cookie); -static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ -#endif /* ENABLE_4335BT_WAR */ - -extern bool ap_fw_loaded; -#if defined(CUSTOMER_HW2) -extern char iface_name[IFNAMSIZ]; -#endif - -/** - * Local (static) functions and variables - */ - -/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first - * time (only) in dhd_open, subsequential wifi on will be handled by - * wl_android_wifi_on - */ -static int g_wifi_on = TRUE; - -/** - * Local (static) function definitions - */ -static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) -{ - int link_speed; - int bytes_written; - int error; - - error = wldev_get_link_speed(net, &link_speed); - if (error) - return -1; - - /* Convert Kbps to Android Mbps */ - link_speed = link_speed / 1000; - bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); - DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); - return bytes_written; -} - -static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) -{ - wlc_ssid_t ssid = {0}; - int bytes_written = 0; - int error = 0; - scb_val_t scbval; - char *delim = NULL; - - - delim = strchr(command, ' '); - /* For Ap mode rssi command would be - * driver rssi - * for STA/GC mode - * driver rssi - */ - if (delim) { - /* Ap/GO mode - * driver rssi - */ - DHD_TRACE(("%s: cmd:%s\n", __FUNCTION__, delim)); - /* skip space from delim after finding char */ - delim++; - if (!(bcm_ether_atoe((delim), &scbval.ea))) { - - DHD_ERROR(("%s:address err\n", __FUNCTION__)); - return -1; - } - scbval.val = htod32(0); - DHD_TRACE(("%s: address:"MACDBG, __FUNCTION__, MAC2STRDBG(scbval.ea.octet))); - } - else { - memset(&scbval, 0, sizeof(scb_val_t)); - } - - error = wldev_get_rssi(net, &scbval); - if (error) - return -1; - - error = wldev_get_ssid(net, &ssid); - if (error) - return -1; - if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { - DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); - } else { - if (total_len > ssid.SSID_len) { - memcpy(command, ssid.SSID, ssid.SSID_len); - bytes_written = ssid.SSID_len; - } else { - return BCME_ERROR; - } - } - - if ((total_len - bytes_written) >= (strlen(" rssi -XXX") + 1)) { - bytes_written += snprintf(&command[bytes_written], total_len - bytes_written, - " rssi %d", scbval.val); - command[bytes_written] = '\0'; - } else { - return BCME_ERROR; - } - - DHD_TRACE(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); - return bytes_written; -} - -static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) -{ - int suspend_flag; - int ret_now; - int ret = 0; - - suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; - - if (suspend_flag != 0) - suspend_flag = 1; - ret_now = net_os_set_suspend_disable(dev, suspend_flag); - - if (ret_now != suspend_flag) { - if (!(ret = net_os_set_suspend(dev, ret_now, 1))) - DHD_INFO(("%s: Suspend Flag %d -> %d\n", - __FUNCTION__, ret_now, suspend_flag)); - else - DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); - } - return ret; -} - -static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) -{ - int ret = 0; - -#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) - int suspend_flag; - - suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; - if (suspend_flag != 0) - suspend_flag = 1; - - if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) - DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag)); - else - DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); -#endif - - return ret; -} - -int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len) -{ - uint8 mode[4]; - int error = 0; - int bytes_written = 0; - - error = wldev_get_mode(dev, mode); - if (error) - return -1; - - DHD_INFO(("%s: mode:%s\n", __FUNCTION__, mode)); - bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode); - DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command)); - return bytes_written; - -} - -extern chanspec_t -wl_chspec_driver_to_host(chanspec_t chanspec); -int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - int bytes_written = 0; - int chsp = {0}; - uint16 band = 0; - uint16 bw = 0; - uint16 channel = 0; - u32 sb = 0; - chanspec_t chanspec; - - /* command is - * driver chanspec - */ - error = wldev_iovar_getint(dev, "chanspec", &chsp); - if (error) - return -1; - - chanspec = wl_chspec_driver_to_host(chsp); - DHD_INFO(("%s:return value of chanspec:%x\n", __FUNCTION__, chanspec)); - - channel = chanspec & WL_CHANSPEC_CHAN_MASK; - band = chanspec & WL_CHANSPEC_BAND_MASK; - bw = chanspec & WL_CHANSPEC_BW_MASK; - - DHD_INFO(("%s:channel:%d band:%d bandwidth:%d\n", __FUNCTION__, channel, band, bw)); - - if (bw == WL_CHANSPEC_BW_80) - bw = WL_CH_BANDWIDTH_80MHZ; - else if (bw == WL_CHANSPEC_BW_40) - bw = WL_CH_BANDWIDTH_40MHZ; - else if (bw == WL_CHANSPEC_BW_20) - bw = WL_CH_BANDWIDTH_20MHZ; - else - bw = WL_CH_BANDWIDTH_20MHZ; - - if (bw == WL_CH_BANDWIDTH_40MHZ) { - if (CHSPEC_SB_UPPER(chanspec)) { - channel += CH_10MHZ_APART; - } else { - channel -= CH_10MHZ_APART; - } - } - else if (bw == WL_CH_BANDWIDTH_80MHZ) { - sb = chanspec & WL_CHANSPEC_CTL_SB_MASK; - if (sb == WL_CHANSPEC_CTL_SB_LL) { - channel -= (CH_10MHZ_APART + CH_20MHZ_APART); - } else if (sb == WL_CHANSPEC_CTL_SB_LU) { - channel -= CH_10MHZ_APART; - } else if (sb == WL_CHANSPEC_CTL_SB_UL) { - channel += CH_10MHZ_APART; - } else { - /* WL_CHANSPEC_CTL_SB_UU */ - channel += (CH_10MHZ_APART + CH_20MHZ_APART); - } - } - bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC, - channel, band == WL_CHANSPEC_BAND_5G ? "5G":"2G", bw); - - DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command)); - return bytes_written; - -} - -/* returns current datarate datarate returned from firmware are in 500kbps */ -int wl_android_get_datarate(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - int datarate = 0; - int bytes_written = 0; - - error = wldev_get_datarate(dev, &datarate); - if (error) - return -1; - - DHD_INFO(("%s:datarate:%d\n", __FUNCTION__, datarate)); - - bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2)); - return bytes_written; -} -int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - int bytes_written = 0; - uint i; - char mac_buf[MAX_NUM_OF_ASSOCLIST * - sizeof(struct ether_addr) + sizeof(uint)] = {0}; - struct maclist *assoc_maclist = (struct maclist *)mac_buf; - - DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); - - assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST); - - error = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), false); - if (error) - return -1; - - assoc_maclist->count = dtoh32(assoc_maclist->count); - bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:", - CMD_ASSOC_CLIENTS, assoc_maclist->count); - - for (i = 0; i < assoc_maclist->count; i++) { - bytes_written += snprintf(command + bytes_written, total_len, " " MACDBG, - MAC2STRDBG(assoc_maclist->ea[i].octet)); - } - return bytes_written; - -} -extern chanspec_t -wl_chspec_host_to_driver(chanspec_t chanspec); -static int wl_android_set_csa(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - char smbuf[WLC_IOCTL_SMLEN]; - wl_chan_switch_t csa_arg; - char buf[32]; - u32 chnsp = 0; - int err = 0; - - DHD_INFO(("%s: command:%s\n", __FUNCTION__, command)); - - command = (command + strlen(CMD_SET_CSA)); - /* Order is mode, count channel */ - if (!*++command) { - DHD_ERROR(("%s:error missing arguments\n", __FUNCTION__)); - return -1; - } - csa_arg.mode = bcm_atoi(command); - if (csa_arg.mode != 0 && csa_arg.mode != 1) { - DHD_ERROR(("Invalid mode\n")); - return -1; - } if (!*++command) { - DHD_ERROR(("%s:error missing count\n", __FUNCTION__)); - return -1; - } - command++; - csa_arg.count = bcm_atoi(command); - if (!*++command) { - DHD_ERROR(("%s:error missing channel\n", __FUNCTION__)); - return -1; - } - csa_arg.reg = 0; - csa_arg.chspec = 0; - command += 2; - if (sizeof(buf) > strlen(command)) - bcm_strncpy_s(buf, sizeof(buf), command, strlen(command)); - else { - DHD_ERROR(("%s:command is not valid\n", __FUNCTION__)); - return -1; - } - chnsp = wf_chspec_aton(buf); - if (chnsp == 0) { - DHD_ERROR(("%s:chsp is not correct\n", __FUNCTION__)); - return -1; - } - chnsp = wl_chspec_host_to_driver(chnsp); - csa_arg.chspec = chnsp; - - if (chnsp & WL_CHANSPEC_BAND_5G) { - u32 chanspec = chnsp; - err = wldev_iovar_getint(dev, "per_chan_info", &chanspec); - if (!err) { - if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) { - DHD_ERROR(("Channel is radar sensitive\n")); - return -1; - } - if (chanspec == 0) { - DHD_ERROR(("Invalid hw channel\n")); - return -1; - } - } else { - DHD_ERROR(("does not support per_chan_info\n")); - return -1; - } - DHD_INFO(("non radar sensitivity\n")); - } - error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg), - smbuf, sizeof(smbuf), NULL); - if (error) { - DHD_ERROR(("%s:set csa failed:%d\n", __FUNCTION__, error)); - return -1; - } - return 0; -} -static int wl_android_get_band(struct net_device *dev, char *command, int total_len) -{ - uint band; - int bytes_written; - int error; - - error = wldev_get_band(dev, &band); - if (error) - return -1; - bytes_written = snprintf(command, total_len, "Band %d", band); - return bytes_written; -} - - -#ifdef PNO_SUPPORT -#define PNO_PARAM_SIZE 50 -#define VALUE_SIZE 50 -#define LIMIT_STR_FMT ("%50s %50s") -static int -wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) -{ - int err = BCME_OK; - uint i, tokens; - char *pos, *pos2, *token, *token2, *delim; - char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1]; - struct dhd_pno_batch_params batch_params; - DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); - if (total_len < strlen(CMD_WLS_BATCHING)) { - DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); - err = BCME_ERROR; - goto exit; - } - pos = command + strlen(CMD_WLS_BATCHING) + 1; - memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params)); - - if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) { - pos += strlen(PNO_BATCHING_SET) + 1; - while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) { - memset(param, 0, sizeof(param)); - memset(value, 0, sizeof(value)); - if (token == NULL || !*token) - break; - if (*token == '\0') - continue; - delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER); - if (delim != NULL) - *delim = ' '; - - tokens = sscanf(token, LIMIT_STR_FMT, param, value); - if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) { - batch_params.scan_fr = simple_strtol(value, NULL, 0); - DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr)); - } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) { - batch_params.bestn = simple_strtol(value, NULL, 0); - DHD_PNO(("bestn : %d\n", batch_params.bestn)); - } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) { - batch_params.mscan = simple_strtol(value, NULL, 0); - DHD_PNO(("mscan : %d\n", batch_params.mscan)); - } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) { - i = 0; - pos2 = value; - tokens = sscanf(value, "<%s>", value); - if (tokens != 1) { - err = BCME_ERROR; - DHD_ERROR(("%s : invalid format for channel" - " <> params\n", __FUNCTION__)); - goto exit; - } - while ((token2 = strsep(&pos2, - PNO_PARAM_CHANNEL_DELIMETER)) != NULL) { - if (token2 == NULL || !*token2) - break; - if (*token2 == '\0') - continue; - if (*token2 == 'A' || *token2 == 'B') { - batch_params.band = (*token2 == 'A')? - WLC_BAND_5G : WLC_BAND_2G; - DHD_PNO(("band : %s\n", - (*token2 == 'A')? "A" : "B")); - } else { - if ((batch_params.nchan >= WL_NUMCHANNELS) || - (i >= WL_NUMCHANNELS)) { - DHD_ERROR(("Too many nchan %d\n", - batch_params.nchan)); - err = BCME_BUFTOOSHORT; - goto exit; - } - batch_params.chan_list[i++] = - simple_strtol(token2, NULL, 0); - batch_params.nchan++; - DHD_PNO(("channel :%d\n", - batch_params.chan_list[i-1])); - } - } - } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) { - batch_params.rtt = simple_strtol(value, NULL, 0); - DHD_PNO(("rtt : %d\n", batch_params.rtt)); - } else { - DHD_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param)); - err = BCME_ERROR; - goto exit; - } - } - err = dhd_dev_pno_set_for_batch(dev, &batch_params); - if (err < 0) { - DHD_ERROR(("failed to configure batch scan\n")); - } else { - memset(command, 0, total_len); - err = sprintf(command, "%d", err); - } - } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) { - err = dhd_dev_pno_get_for_batch(dev, command, total_len); - if (err < 0) { - DHD_ERROR(("failed to getting batching results\n")); - } else { - err = strlen(command); - } - } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) { - err = dhd_dev_pno_stop_for_batch(dev); - if (err < 0) { - DHD_ERROR(("failed to stop batching scan\n")); - } else { - memset(command, 0, total_len); - err = sprintf(command, "OK"); - } - } else { - DHD_ERROR(("%s : unknown command\n", __FUNCTION__)); - err = BCME_ERROR; - goto exit; - } -exit: - return err; -} -#ifndef WL_SCHED_SCAN -static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) -{ - wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; - int res = -1; - int nssid = 0; - cmd_tlv_t *cmd_tlv_temp; - char *str_ptr; - int tlv_size_left; - int pno_time = 0; - int pno_repeat = 0; - int pno_freq_expo_max = 0; - -#ifdef PNO_SET_DEBUG - int i; - char pno_in_example[] = { - 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', - 'S', '1', '2', '0', - 'S', - 0x05, - 'd', 'l', 'i', 'n', 'k', - 'S', - 0x04, - 'G', 'O', 'O', 'G', - 'T', - '0', 'B', - 'R', - '2', - 'M', - '2', - 0x00 - }; -#endif /* PNO_SET_DEBUG */ - DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); - - if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { - DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); - goto exit_proc; - } -#ifdef PNO_SET_DEBUG - memcpy(command, pno_in_example, sizeof(pno_in_example)); - total_len = sizeof(pno_in_example); -#endif - str_ptr = command + strlen(CMD_PNOSETUP_SET); - tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); - - cmd_tlv_temp = (cmd_tlv_t *)str_ptr; - memset(ssids_local, 0, sizeof(ssids_local)); - - if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && - (cmd_tlv_temp->version == PNO_TLV_VERSION) && - (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) { - - str_ptr += sizeof(cmd_tlv_t); - tlv_size_left -= sizeof(cmd_tlv_t); - - if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, - MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { - DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); - goto exit_proc; - } else { - if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { - DHD_ERROR(("%s scan duration corrupted field size %d\n", - __FUNCTION__, tlv_size_left)); - goto exit_proc; - } - str_ptr++; - pno_time = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); - - if (str_ptr[0] != 0) { - if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { - DHD_ERROR(("%s pno repeat : corrupted field\n", - __FUNCTION__)); - goto exit_proc; - } - str_ptr++; - pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); - if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { - DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", - __FUNCTION__)); - goto exit_proc; - } - str_ptr++; - pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_PNO(("%s: pno_freq_expo_max=%d\n", - __FUNCTION__, pno_freq_expo_max)); - } - } - } else { - DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); - goto exit_proc; - } - - res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat, - pno_freq_expo_max, NULL, 0); -exit_proc: - return res; -} -#endif /* !WL_SCHED_SCAN */ -#endif /* PNO_SUPPORT */ - -static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) -{ - int ret; - int bytes_written = 0; - - ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command); - if (ret) - return 0; - bytes_written = sizeof(struct ether_addr); - return bytes_written; -} - -#ifdef BCMCCX -static int wl_android_get_cckm_rn(struct net_device *dev, char *command) -{ - int error, rn; - - WL_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name)); - - error = wldev_iovar_getint(dev, "cckm_rn", &rn); - if (unlikely(error)) { - WL_ERR(("wl_android_get_cckm_rn error (%d)\n", error)); - return -1; - } - memcpy(command, &rn, sizeof(int)); - - return sizeof(int); -} - -static int wl_android_set_cckm_krk(struct net_device *dev, char *command) -{ - int error; - unsigned char key[16]; - static char iovar_buf[WLC_IOCTL_MEDLEN]; - - WL_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name)); - - memset(iovar_buf, 0, sizeof(iovar_buf)); - memcpy(key, command+strlen("set cckm_krk")+1, 16); - - error = wldev_iovar_setbuf(dev, "cckm_krk", key, sizeof(key), - iovar_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(error)) - { - WL_ERR((" cckm_krk set error (%d)\n", error)); - return -1; - } - return 0; -} - -static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command) -{ - int error; - u8 buf[WL_ASSOC_INFO_MAX]; - wl_assoc_info_t assoc_info; - u32 resp_ies_len = 0; - int bytes_written = 0; - - WL_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name)); - - error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf, WL_ASSOC_INFO_MAX, NULL); - if (unlikely(error)) { - WL_ERR(("could not get assoc info (%d)\n", error)); - return -1; - } - - memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t)); - assoc_info.req_len = htod32(assoc_info.req_len); - assoc_info.resp_len = htod32(assoc_info.resp_len); - assoc_info.flags = htod32(assoc_info.flags); - - if (assoc_info.resp_len) { - resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); - } - - /* first 4 bytes are ie len */ - memcpy(command, &resp_ies_len, sizeof(u32)); - bytes_written = sizeof(u32); - - /* get the association resp IE's if there are any */ - if (resp_ies_len) { - error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0, - buf, WL_ASSOC_INFO_MAX, NULL); - if (unlikely(error)) { - WL_ERR(("could not get assoc resp_ies (%d)\n", error)); - return -1; - } - - memcpy(command+sizeof(u32), buf, resp_ies_len); - bytes_written += resp_ies_len; - } - return bytes_written; -} - -#endif /* BCMCCX */ - -int -wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist) -{ - int i, j, match; - int ret = 0; - char mac_buf[MAX_NUM_OF_ASSOCLIST * - sizeof(struct ether_addr) + sizeof(uint)] = {0}; - struct maclist *assoc_maclist = (struct maclist *)mac_buf; - - /* set filtering mode */ - if ((ret = wldev_ioctl(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode), true)) != 0) { - DHD_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret)); - return ret; - } - if (macmode != MACLIST_MODE_DISABLED) { - /* set the MAC filter list */ - if ((ret = wldev_ioctl(dev, WLC_SET_MACLIST, maclist, - sizeof(int) + sizeof(struct ether_addr) * maclist->count, true)) != 0) { - DHD_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret)); - return ret; - } - /* get the current list of associated STAs */ - assoc_maclist->count = MAX_NUM_OF_ASSOCLIST; - if ((ret = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, - sizeof(mac_buf), false)) != 0) { - DHD_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret)); - return ret; - } - /* do we have any STA associated? */ - if (assoc_maclist->count) { - /* iterate each associated STA */ - for (i = 0; i < assoc_maclist->count; i++) { - match = 0; - /* compare with each entry */ - for (j = 0; j < maclist->count; j++) { - DHD_INFO(("%s : associated="MACDBG " list="MACDBG "\n", - __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet), - MAC2STRDBG(maclist->ea[j].octet))); - if (memcmp(assoc_maclist->ea[i].octet, - maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) { - match = 1; - break; - } - } - /* do conditional deauth */ - /* "if not in the allow list" or "if in the deny list" */ - if ((macmode == MACLIST_MODE_ALLOW && !match) || - (macmode == MACLIST_MODE_DENY && match)) { - scb_val_t scbval; - - scbval.val = htod32(1); - memcpy(&scbval.ea, &assoc_maclist->ea[i], - ETHER_ADDR_LEN); - if ((ret = wldev_ioctl(dev, - WLC_SCB_DEAUTHENTICATE_FOR_REASON, - &scbval, sizeof(scb_val_t), true)) != 0) - DHD_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n", - __FUNCTION__, ret)); - } - } - } - } - return ret; -} - -/* - * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2 - * - */ -static int -wl_android_set_mac_address_filter(struct net_device *dev, const char* str) -{ - int i; - int ret = 0; - int macnum = 0; - int macmode = MACLIST_MODE_DISABLED; - struct maclist *list; - char eabuf[ETHER_ADDR_STR_LEN]; - - /* string should look like below (macmode/macnum/maclist) */ - /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */ - - /* get the MAC filter mode */ - macmode = bcm_atoi(strsep((char**)&str, " ")); - - if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) { - DHD_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode)); - return -1; - } - - macnum = bcm_atoi(strsep((char**)&str, " ")); - if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { - DHD_ERROR(("%s : invalid number of MAC address entries %d\n", - __FUNCTION__, macnum)); - return -1; - } - /* allocate memory for the MAC list */ - list = (struct maclist*)kmalloc(sizeof(int) + - sizeof(struct ether_addr) * macnum, GFP_KERNEL); - if (!list) { - DHD_ERROR(("%s : failed to allocate memory\n", __FUNCTION__)); - return -1; - } - /* prepare the MAC list */ - list->count = htod32(macnum); - bzero((char *)eabuf, ETHER_ADDR_STR_LEN); - for (i = 0; i < list->count; i++) { - strncpy(eabuf, strsep((char**)&str, " "), ETHER_ADDR_STR_LEN - 1); - if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) { - DHD_ERROR(("%s : mac parsing err index=%d, addr=%s\n", - __FUNCTION__, i, eabuf)); - list->count--; - break; - } - DHD_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf)); - } - /* set the list */ - if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0) - DHD_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); - - kfree(list); - - return 0; -} - -/** - * Global function definitions (declared in wl_android.h) - */ - -int wl_android_wifi_on(struct net_device *dev) -{ - int ret = 0; -#ifdef CONFIG_MACH_UNIVERSAL5433 - int retry; - /* Do not retry old revision Helsinki Prime */ - if (!check_rev()) { - retry = 1; - } else { - retry = POWERUP_MAX_RETRY; - } -#else - int retry = POWERUP_MAX_RETRY; -#endif /* CONFIG_MACH_UNIVERSAL5433 */ - - DHD_ERROR(("%s in\n", __FUNCTION__)); - if (!dev) { - DHD_ERROR(("%s: dev is null\n", __FUNCTION__)); - return -EINVAL; - } - - dhd_net_if_lock(dev); - if (!g_wifi_on) { - do { - dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY); -#ifdef BCMSDIO - ret = dhd_net_bus_resume(dev, 0); -#endif /* BCMSDIO */ -#ifdef BCMPCIE - ret = dhd_net_bus_devreset(dev, FALSE); -#endif /* BCMPCIE */ - if (ret == 0) - break; - DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n", - retry)); -#ifdef BCMPCIE - dhd_net_bus_devreset(dev, TRUE); -#endif /* BCMPCIE */ - dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); - } while (retry-- > 0); - if (ret != 0) { - DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n")); - goto exit; - } -#ifdef BCMSDIO - ret = dhd_net_bus_devreset(dev, FALSE); - dhd_net_bus_resume(dev, 1); -#endif /* BCMSDIO */ - -#ifndef BCMPCIE - if (!ret) { - if (dhd_dev_init_ioctl(dev) < 0) - ret = -EFAULT; - } -#endif /* !BCMPCIE */ - g_wifi_on = TRUE; - } - -exit: - dhd_net_if_unlock(dev); - - return ret; -} - -int wl_android_wifi_off(struct net_device *dev) -{ - int ret = 0; - - DHD_ERROR(("%s in\n", __FUNCTION__)); - if (!dev) { - DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); - return -EINVAL; - } - - dhd_net_if_lock(dev); - if (g_wifi_on) { -#if defined(BCMSDIO) || defined(BCMPCIE) - ret = dhd_net_bus_devreset(dev, TRUE); -#ifdef BCMSDIO - dhd_net_bus_suspend(dev); -#endif /* BCMSDIO */ -#endif /* BCMSDIO || BCMPCIE */ - dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); - g_wifi_on = FALSE; - } - dhd_net_if_unlock(dev); - - return ret; -} - -static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len) -{ - if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN) - return -1; - return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1); -} - -#ifdef CONNECTION_STATISTICS -static int -wl_chanim_stats(struct net_device *dev, u8 *chan_idle) -{ - int err; - wl_chanim_stats_t *list; - /* Parameter _and_ returned buffer of chanim_stats. */ - wl_chanim_stats_t param; - u8 result[WLC_IOCTL_SMLEN]; - chanim_stats_t *stats; - - memset(¶m, 0, sizeof(param)); - memset(result, 0, sizeof(result)); - - param.buflen = htod32(sizeof(wl_chanim_stats_t)); - param.count = htod32(WL_CHANIM_COUNT_ONE); - - if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)¶m, sizeof(wl_chanim_stats_t), - (char*)result, sizeof(result), 0)) < 0) { - WL_ERR(("Failed to get chanim results %d \n", err)); - return err; - } - - list = (wl_chanim_stats_t*)result; - - list->buflen = dtoh32(list->buflen); - list->version = dtoh32(list->version); - list->count = dtoh32(list->count); - - if (list->buflen == 0) { - list->version = 0; - list->count = 0; - } else if (list->version != WL_CHANIM_STATS_VERSION) { - WL_ERR(("Sorry, firmware has wl_chanim_stats version %d " - "but driver supports only version %d.\n", - list->version, WL_CHANIM_STATS_VERSION)); - list->buflen = 0; - list->count = 0; - } - - stats = list->stats; - stats->glitchcnt = dtoh32(stats->glitchcnt); - stats->badplcp = dtoh32(stats->badplcp); - stats->chanspec = dtoh16(stats->chanspec); - stats->timestamp = dtoh32(stats->timestamp); - stats->chan_idle = dtoh32(stats->chan_idle); - - WL_INFORM(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n", - stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle, - stats->timestamp)); - - *chan_idle = stats->chan_idle; - - return (err); -} - -static int -wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len) -{ - wl_cnt_t* cnt = NULL; -#ifndef DISABLE_IF_COUNTERS - wl_if_stats_t* if_stats = NULL; -#endif /* DISABLE_IF_COUNTERS */ - - int link_speed = 0; - struct connection_stats *output; - unsigned int bufsize = 0; - int bytes_written = -1; - int ret = 0; - - WL_INFORM(("%s: enter Get Connection Stats\n", __FUNCTION__)); - - if (total_len <= 0) { - WL_ERR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len)); - goto error; - } - - bufsize = total_len; - if (bufsize < sizeof(struct connection_stats)) { - WL_ERR(("%s: not enough buffer size, provided=%u, requires=%zu\n", - __FUNCTION__, bufsize, - sizeof(struct connection_stats))); - goto error; - } - - output = (struct connection_stats *)command; - -#ifndef DISABLE_IF_COUNTERS - if ((if_stats = kmalloc(sizeof(*if_stats), GFP_KERNEL)) == NULL) { - WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); - goto error; - } - memset(if_stats, 0, sizeof(*if_stats)); - - ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0, - (char *)if_stats, sizeof(*if_stats), NULL); - if (ret) { - WL_ERR(("%s: if_counters not supported ret=%d\n", - __FUNCTION__, ret)); - - /* In case if_stats IOVAR is not supported, get information from counters. */ -#endif /* DISABLE_IF_COUNTERS */ - if ((cnt = kmalloc(sizeof(*cnt), GFP_KERNEL)) == NULL) { - WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); - goto error; - } - memset(cnt, 0, sizeof(*cnt)); - - ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, - (char *)cnt, sizeof(wl_cnt_t), NULL); - if (ret) { - WL_ERR(("%s: wldev_iovar_getbuf() failed, ret=%d\n", - __FUNCTION__, ret)); - goto error; - } - - if (dtoh16(cnt->version) > WL_CNT_T_VERSION) { - WL_ERR(("%s: incorrect version of wl_cnt_t, expected=%u got=%u\n", - __FUNCTION__, WL_CNT_T_VERSION, cnt->version)); - goto error; - } - - output->txframe = dtoh32(cnt->txframe); - output->txbyte = dtoh32(cnt->txbyte); - output->txerror = dtoh32(cnt->txerror); - output->rxframe = dtoh32(cnt->rxframe); - output->rxbyte = dtoh32(cnt->rxbyte); - output->txfail = dtoh32(cnt->txfail); - output->txretry = dtoh32(cnt->txretry); - output->txretrie = dtoh32(cnt->txretrie); - output->txrts = dtoh32(cnt->txrts); - output->txnocts = dtoh32(cnt->txnocts); - output->txexptime = dtoh32(cnt->txexptime); -#ifndef DISABLE_IF_COUNTERS - } else { - /* Populate from if_stats. */ - if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) { - WL_ERR(("%s: incorrect version of wl_if_stats_t, expected=%u got=%u\n", - __FUNCTION__, WL_IF_STATS_T_VERSION, if_stats->version)); - goto error; - } - - output->txframe = (uint32)dtoh64(if_stats->txframe); - output->txbyte = (uint32)dtoh64(if_stats->txbyte); - output->txerror = (uint32)dtoh64(if_stats->txerror); - output->rxframe = (uint32)dtoh64(if_stats->rxframe); - output->rxbyte = (uint32)dtoh64(if_stats->rxbyte); - output->txfail = (uint32)dtoh64(if_stats->txfail); - output->txretry = (uint32)dtoh64(if_stats->txretry); - output->txretrie = (uint32)dtoh64(if_stats->txretrie); - if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) { - output->txexptime = (uint32)dtoh64(if_stats->txexptime); - output->txrts = (uint32)dtoh64(if_stats->txrts); - output->txnocts = (uint32)dtoh64(if_stats->txnocts); - } else { - output->txexptime = 0; - output->txrts = 0; - output->txnocts = 0; - } - } -#endif /* DISABLE_IF_COUNTERS */ - - /* link_speed is in kbps */ - ret = wldev_get_link_speed(dev, &link_speed); - if (ret || link_speed < 0) { - WL_ERR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n", - __FUNCTION__, ret, link_speed)); - goto error; - } - output->txrate = link_speed; - - /* Channel idle ratio. */ - if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) { - output->chan_idle = 0; - }; - - bytes_written = sizeof(struct connection_stats); - -error: -#ifndef DISABLE_IF_COUNTERS - if (if_stats) { - kfree(if_stats); - } -#endif /* DISABLE_IF_COUNTERS */ - if (cnt) { - kfree(cnt); - } - - return bytes_written; -} -#endif /* CONNECTION_STATISTICS */ - -static int -wl_android_set_pmk(struct net_device *dev, char *command, int total_len) -{ - uchar pmk[33]; - int error = 0; - char smbuf[WLC_IOCTL_SMLEN]; -#ifdef OKC_DEBUG - int i = 0; -#endif - - bzero(pmk, sizeof(pmk)); - memcpy((char *)pmk, command + strlen("SET_PMK "), 32); - error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL); - if (error) { - DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error)); - } -#ifdef OKC_DEBUG - DHD_ERROR(("PMK is ")); - for (i = 0; i < 32; i++) - DHD_ERROR(("%02X ", pmk[i])); - - DHD_ERROR(("\n")); -#endif - return error; -} - -static int -wl_android_okc_enable(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - char okc_enable = 0; - - okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0'; - error = wldev_iovar_setint(dev, "okc_enable", okc_enable); - if (error) { - DHD_ERROR(("Failed to %s OKC, error = %d\n", - okc_enable ? "enable" : "disable", error)); - } - - wldev_iovar_setint(dev, "ccx_enable", 0); - - return error; -} - - - -int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - int mode = 0; - - if (sscanf(command, "%*s %d", &mode) != 1) { - DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); - return -1; - } - - error = wldev_iovar_setint(dev, "roam_off", mode); - if (error) { - DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n", - __FUNCTION__, mode, error)); - return -1; - } - else - DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n", - __FUNCTION__, mode, error)); - return 0; -} - -int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len) -{ - char ie_buf[VNDR_IE_MAX_LEN]; - char *ioctl_buf = NULL; - char hex[] = "XX"; - char *pcmd = NULL; - int ielen = 0, datalen = 0, idx = 0, tot_len = 0; - vndr_ie_setbuf_t *vndr_ie = NULL; - s32 iecount; - uint32 pktflag; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - s32 err = BCME_OK; - - /* Check the VSIE (Vendor Specific IE) which was added. - * If exist then send IOVAR to delete it - */ - if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) { - return -EINVAL; - } - - pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1; - for (idx = 0; idx < DOT11_OUI_LEN; idx++) { - hex[0] = *pcmd++; - hex[1] = *pcmd++; - ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16); - } - pcmd++; - while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) { - hex[0] = *pcmd++; - hex[1] = *pcmd++; - ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16); - datalen++; - } - tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1); - vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags); - if (!vndr_ie) { - WL_ERR(("IE memory alloc failed\n")); - return -ENOMEM; - } - /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ - strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1); - vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - - /* Set the IE count - the buffer contains only 1 IE */ - iecount = htod32(1); - memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32)); - - /* Set packet flag to indicate that BEACON's will contain this IE */ - pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG); - memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, - sizeof(u32)); - /* Set the IE ID */ - vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID; - - memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf, - DOT11_OUI_LEN); - memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, - &ie_buf[DOT11_OUI_LEN], datalen); - - ielen = DOT11_OUI_LEN + datalen; - vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen; - - ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (!ioctl_buf) { - WL_ERR(("ioctl memory alloc failed\n")); - if (vndr_ie) { - kfree(vndr_ie); - } - return -ENOMEM; - } - memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */ - err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - - - if (err != BCME_OK) { - err = -EINVAL; - if (vndr_ie) { - kfree(vndr_ie); - } - } - else { - /* do NOT free 'vndr_ie' for the next process */ - wl_cfg80211_ibss_vsie_set_buffer(vndr_ie, tot_len); - } - - if (ioctl_buf) { - kfree(ioctl_buf); - } - - return err; -} - -#if defined(BCMFW_ROAM_ENABLE) -static int -wl_android_set_roampref(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - char smbuf[WLC_IOCTL_SMLEN]; - uint8 buf[MAX_BUF_SIZE]; - uint8 *pref = buf; - char *pcmd; - uint num_ucipher_suites; - uint num_akm_suites; - wpa_suite_t ucipher_suites[MAX_NUM_SUITES]; - wpa_suite_t akm_suites[MAX_NUM_SUITES]; - int num_tuples = 0; - int total_bytes = 0; - int total_len_left; - int i, j; - char hex[] = "XX"; - - pcmd = command + strlen(CMD_SET_ROAMPREF) + 1; - total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1; - - num_akm_suites = simple_strtoul(pcmd, NULL, 16); - if (num_akm_suites > MAX_NUM_SUITES) { - WL_ERR(("wrong num_akm_suites:%d.\n", num_akm_suites)); - return BCME_ERROR; - } - /* Increment for number of AKM suites field + space */ - pcmd += 3; - total_len_left -= 3; - - /* check to make sure pcmd does not overrun */ - if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE)) - return -1; - - memset(buf, 0, sizeof(buf)); - memset(akm_suites, 0, sizeof(akm_suites)); - memset(ucipher_suites, 0, sizeof(ucipher_suites)); - - /* Save the AKM suites passed in the command */ - for (i = 0; i < num_akm_suites; i++) { - /* Store the MSB first, as required by join_pref */ - for (j = 0; j < 4; j++) { - hex[0] = *pcmd++; - hex[1] = *pcmd++; - buf[j] = (uint8)simple_strtoul(hex, NULL, 16); - } - memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32)); - } - - total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); - num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); - if (num_ucipher_suites > MAX_NUM_SUITES) { - DHD_ERROR(("too many UCIPHER suites = %d\n", num_ucipher_suites)); - return -1; - } - /* Increment for number of cipher suites field + space */ - pcmd += 3; - total_len_left -= 3; - - if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE)) - return -1; - - /* Save the cipher suites passed in the command */ - for (i = 0; i < num_ucipher_suites; i++) { - /* Store the MSB first, as required by join_pref */ - for (j = 0; j < 4; j++) { - hex[0] = *pcmd++; - hex[1] = *pcmd++; - buf[j] = (uint8)simple_strtoul(hex, NULL, 16); - } - memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32)); - } - - /* Join preference for RSSI - * Type : 1 byte (0x01) - * Length : 1 byte (0x02) - * Value : 2 bytes (reserved) - */ - *pref++ = WL_JOIN_PREF_RSSI; - *pref++ = JOIN_PREF_RSSI_LEN; - *pref++ = 0; - *pref++ = 0; - - /* Join preference for WPA - * Type : 1 byte (0x02) - * Length : 1 byte (not used) - * Value : (variable length) - * reserved: 1 byte - * count : 1 byte (no of tuples) - * Tuple1 : 12 bytes - * akm[4] - * ucipher[4] - * mcipher[4] - * Tuple2 : 12 bytes - * Tuplen : 12 bytes - */ - num_tuples = num_akm_suites * num_ucipher_suites; - if (num_tuples != 0) { - if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) { - *pref++ = WL_JOIN_PREF_WPA; - *pref++ = 0; - *pref++ = 0; - *pref++ = (uint8)num_tuples; - total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + - (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples); - } else { - DHD_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__)); - return -1; - } - } else { - /* No WPA config, configure only RSSI preference */ - total_bytes = JOIN_PREF_RSSI_SIZE; - } - - /* akm-ucipher-mcipher tuples in the format required for join_pref */ - for (i = 0; i < num_ucipher_suites; i++) { - for (j = 0; j < num_akm_suites; j++) { - memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN); - pref += WPA_SUITE_LEN; - memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN); - pref += WPA_SUITE_LEN; - /* Set to 0 to match any available multicast cipher */ - memset(pref, 0, WPA_SUITE_LEN); - pref += WPA_SUITE_LEN; - } - } - - prhex("join pref", (uint8 *)buf, total_bytes); - error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL); - if (error) { - DHD_ERROR(("Failed to set join_pref, error = %d\n", error)); - } - return error; -} -#endif /* defined(BCMFW_ROAM_ENABLE */ - -static int -wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config) -{ - struct io_cfg *resume_cfg; - s32 ret; - - resume_cfg = kzalloc(sizeof(struct io_cfg), GFP_KERNEL); - if (!resume_cfg) - return -ENOMEM; - - if (config->iovar) { - ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param); - if (ret) { - DHD_ERROR(("%s: Failed to get current %s value\n", - __FUNCTION__, config->iovar)); - goto error; - } - - ret = wldev_iovar_setint(dev, config->iovar, config->param); - if (ret) { - DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, - config->iovar, config->param)); - goto error; - } - - resume_cfg->iovar = config->iovar; - } else { - resume_cfg->arg = kzalloc(config->len, GFP_KERNEL); - if (!resume_cfg->arg) { - ret = -ENOMEM; - goto error; - } - ret = wldev_ioctl(dev, config->ioctl, resume_cfg->arg, config->len, false); - if (ret) { - DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__, - config->ioctl)); - goto error; - } - ret = wldev_ioctl(dev, config->ioctl + 1, config->arg, config->len, true); - if (ret) { - DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, - config->iovar, config->param)); - goto error; - } - if (config->ioctl + 1 == WLC_SET_PM) - wl_cfg80211_update_power_mode(dev); - resume_cfg->ioctl = config->ioctl; - resume_cfg->len = config->len; - } - - list_add(&resume_cfg->list, head); - - return 0; -error: - kfree(resume_cfg->arg); - kfree(resume_cfg); - return ret; -} - -static void -wl_android_iolist_resume(struct net_device *dev, struct list_head *head) -{ - struct io_cfg *config; - struct list_head *cur, *q; - s32 ret = 0; - - list_for_each_safe(cur, q, head) { - config = list_entry(cur, struct io_cfg, list); - if (config->iovar) { - if (!ret) - ret = wldev_iovar_setint(dev, config->iovar, - config->param); - } else { - if (!ret) - ret = wldev_ioctl(dev, config->ioctl + 1, - config->arg, config->len, true); - if (config->ioctl + 1 == WLC_SET_PM) - wl_cfg80211_update_power_mode(dev); - kfree(config->arg); - } - list_del(cur); - kfree(config); - } -} - -static int -wl_android_set_miracast(struct net_device *dev, char *command, int total_len) -{ - int mode, val; - int ret = 0; - struct io_cfg config; -#ifdef CHANGE_SCAN_TIME - int i; -#endif - - if (sscanf(command, "%*s %d", &mode) != 1) { - DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); - return -1; - } - - DHD_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode)); - - if (miracast_cur_mode == mode) { - return 0; - } - - wl_android_iolist_resume(dev, &miracast_resume_list); - miracast_cur_mode = MIRACAST_MODE_OFF; - - switch (mode) { - case MIRACAST_MODE_SOURCE: - /* setting mchan_algo to platform specific value */ - config.iovar = "mchan_algo"; - - ret = wldev_ioctl(dev, WLC_GET_BCNPRD, &val, sizeof(int), false); - if (!ret && val > 100) { - config.param = 0; - DHD_ERROR(("%s: Connected station's beacon interval: " - "%d and set mchan_algo to %d \n", - __FUNCTION__, val, config.param)); - } else { - config.param = MIRACAST_MCHAN_ALGO; - } - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) { - goto resume; - } - - /* setting mchan_bw to platform specific value */ - config.iovar = "mchan_bw"; - config.param = MIRACAST_MCHAN_BW; - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) { - goto resume; - } - - /* setting apmdu to platform specific value */ - config.iovar = "ampdu_mpdu"; - config.param = MIRACAST_AMPDU_SIZE; - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) { - goto resume; - } - /* FALLTROUGH */ - /* Source mode shares most configurations with sink mode. - * Fall through here to avoid code duplication - */ - case MIRACAST_MODE_SINK: - /* disable internal roaming */ - config.iovar = "roam_off"; - config.param = 1; - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) { - goto resume; - } - - /* tunr off pm */ - ret = wldev_ioctl(dev, WLC_GET_PM, &val, sizeof(val), false); - if (ret) { - goto resume; - } - - if (val != PM_OFF) { - val = PM_OFF; - config.iovar = NULL; - config.ioctl = WLC_GET_PM; - config.arg = &val; - config.len = sizeof(int); - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) { - goto resume; - } - } - -#ifdef CHANGE_SCAN_TIME - for (i = 0; i < sizeof(miracast_scan_time) / sizeof(miracast_scan_time[0]); i++) { - config.iovar = NULL; - config.ioctl = miracast_scan_time[i][0]; - config.arg = &miracast_scan_time[i][1]; - config.len = sizeof(int); - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) { - goto resume; - } - } -#endif - - break; - case MIRACAST_MODE_OFF: - default: - break; - } - miracast_cur_mode = mode; - - return 0; - -resume: - DHD_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret)); - wl_android_iolist_resume(dev, &miracast_resume_list); - return ret; -} - -#define NETLINK_OXYGEN 30 -#define AIBSS_BEACON_TIMEOUT 10 - -static struct sock *nl_sk = NULL; - -static void wl_netlink_recv(struct sk_buff *skb) -{ - WL_ERR(("netlink_recv called\n")); -} - -static int wl_netlink_init(void) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - struct netlink_kernel_cfg cfg = { - .input = wl_netlink_recv, - }; -#endif - - if (nl_sk != NULL) { - WL_ERR(("nl_sk already exist\n")); - return BCME_ERROR; - } - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) - nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, - 0, wl_netlink_recv, NULL, THIS_MODULE); -#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) - nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg); -#else - nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg); -#endif - - if (nl_sk == NULL) { - WL_ERR(("nl_sk is not ready\n")); - return BCME_ERROR; - } - - return BCME_OK; -} - -static void wl_netlink_deinit(void) -{ - if (nl_sk) { - netlink_kernel_release(nl_sk); - nl_sk = NULL; - } -} - -s32 -wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size) -{ - struct sk_buff *skb = NULL; - struct nlmsghdr *nlh = NULL; - int ret = -1; - - if (nl_sk == NULL) { - WL_ERR(("nl_sk was not initialized\n")); - goto nlmsg_failure; - } - - skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC); - if (skb == NULL) { - WL_ERR(("failed to allocate memory\n")); - goto nlmsg_failure; - } - - nlh = nlmsg_put(skb, 0, 0, 0, size, 0); - if (nlh == NULL) { - WL_ERR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n", - skb_tailroom(skb), nlmsg_total_size(size))); - dev_kfree_skb(skb); - goto nlmsg_failure; - } - - memcpy(nlmsg_data(nlh), data, size); - nlh->nlmsg_seq = seq; - nlh->nlmsg_type = type; - - /* netlink_unicast() takes ownership of the skb and frees it itself. */ - ret = netlink_unicast(nl_sk, skb, pid, 0); - WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret)); - -nlmsg_failure: - return ret; -} - -#ifdef WLAIBSS -static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len) -{ - int err = 0; - int retry = 0; - int pid = 0; - aibss_txfail_config_t txfail_config = {0, 0, 0, 0}; - char smbuf[WLC_IOCTL_SMLEN]; - - if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) { - WL_ERR(("Failed to get Parameter from : %s\n", command)); - return -1; - } - - /* set pid, and if the event was happened, let's send a notification through netlink */ - wl_cfg80211_set_txfail_pid(pid); - - /* If retry value is 0, it disables the functionality for TX Fail. */ - if (retry > 0) { - txfail_config.max_tx_retry = retry; - txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */ - } - txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0; - txfail_config.len = sizeof(txfail_config); - - err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config, - sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL); - WL_DBG(("retry=%d, pid=%d, err=%d\n", retry, pid, err)); - - return ((err == 0)?total_len:err); -} - -static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command, - int total_len, bool bAll) -{ - int error; - int bytes_written = 0; - void *buf = NULL; - bss_peer_list_info_t peer_list_info; - bss_peer_info_t *peer_info; - int i; - bool found = false; - struct ether_addr mac_ea; - - WL_DBG(("get ibss peer info(%s)\n", bAll?"true":"false")); - - if (!bAll) { - if (sscanf (command, "GETIBSSPEERINFO %02x:%02x:%02x:%02x:%02x:%02x", - (unsigned int *)&mac_ea.octet[0], (unsigned int *)&mac_ea.octet[1], - (unsigned int *)&mac_ea.octet[2], (unsigned int *)&mac_ea.octet[3], - (unsigned int *)&mac_ea.octet[4], (unsigned int *)&mac_ea.octet[5]) != 6) { - WL_DBG(("invalid MAC address\n")); - return -1; - } - } - - if ((buf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL)) == NULL) { - WL_ERR(("kmalloc failed\n")); - return -1; - } - - error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL); - if (unlikely(error)) { - WL_ERR(("could not get ibss peer info (%d)\n", error)); - kfree(buf); - return -1; - } - - memcpy(&peer_list_info, buf, sizeof(peer_list_info)); - peer_list_info.version = htod16(peer_list_info.version); - peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len); - peer_list_info.count = htod32(peer_list_info.count); - - WL_DBG(("ver:%d, len:%d, count:%d\n", peer_list_info.version, - peer_list_info.bss_peer_info_len, peer_list_info.count)); - - if (peer_list_info.count > 0) { - if (bAll) - bytes_written += sprintf(&command[bytes_written], "%u ", - peer_list_info.count); - - peer_info = (bss_peer_info_t *) ((void *)buf + BSS_PEER_LIST_INFO_FIXED_LEN); - - - for (i = 0; i < peer_list_info.count; i++) { - - WL_DBG(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi, - peer_info->tx_rate, peer_info->rx_rate)); - - if (!bAll && - memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) { - found = true; - } - - if (bAll || found) { - bytes_written += sprintf(&command[bytes_written], MACF, - ETHER_TO_MACF(peer_info->ea)); - bytes_written += sprintf(&command[bytes_written], " %u %d ", - peer_info->tx_rate/1000, peer_info->rssi); - } - - if (found) - break; - - peer_info = (bss_peer_info_t *)((void *)peer_info+sizeof(bss_peer_info_t)); - } - } - else { - WL_ERR(("could not get ibss peer info : no item\n")); - } - bytes_written += sprintf(&command[bytes_written], "%s", "\0"); - - WL_DBG(("command(%u):%s\n", total_len, command)); - WL_DBG(("bytes_written:%d\n", bytes_written)); - - kfree(buf); - return bytes_written; -} - -int wl_android_set_ibss_routetable(struct net_device *dev, char *command, int total_len) -{ - - char *pcmd = command; - char *str = NULL; - - ibss_route_tbl_t *route_tbl = NULL; - char *ioctl_buf = NULL; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - s32 err = BCME_OK; - uint32 route_tbl_len; - uint32 entries; - char *endptr; - uint32 i = 0; - struct ipv4_addr dipaddr; - struct ether_addr ea; - - route_tbl_len = sizeof(ibss_route_tbl_t) + - (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t); - route_tbl = (ibss_route_tbl_t *)kzalloc(route_tbl_len, kflags); - if (!route_tbl) { - WL_ERR(("Route TBL alloc failed\n")); - return -ENOMEM; - } - ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (!ioctl_buf) { - WL_ERR(("ioctl memory alloc failed\n")); - if (route_tbl) { - kfree(route_tbl); - } - return -ENOMEM; - } - memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); - - /* drop command */ - str = bcmstrtok(&pcmd, " ", NULL); - - /* get count */ - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - WL_ERR(("Invalid number parameter %s\n", str)); - err = -EINVAL; - goto exit; - } - entries = bcm_strtoul(str, &endptr, 0); - if (*endptr != '\0') { - WL_ERR(("Invalid number parameter %s\n", str)); - err = -EINVAL; - goto exit; - } - WL_INFORM(("Routing table count:%d\n", entries)); - route_tbl->num_entry = entries; - - for (i = 0; i < entries; i++) { - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_atoipv4(str, &dipaddr)) { - WL_ERR(("Invalid ip string %s\n", str)); - err = -EINVAL; - goto exit; - } - - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_ether_atoe(str, &ea)) { - WL_ERR(("Invalid ethernet string %s\n", str)); - err = -EINVAL; - goto exit; - } - bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN); - bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN); - } - - route_tbl_len = sizeof(ibss_route_tbl_t) + - ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t)); - err = wldev_iovar_setbuf(dev, "ibss_route_tbl", - route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (err != BCME_OK) { - WL_ERR(("Fail to set iovar %d\n", err)); - err = -EINVAL; - } - -exit: - if (route_tbl) - kfree(route_tbl); - if (ioctl_buf) - kfree(ioctl_buf); - return err; - -} - -int -wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len) -{ - char *pcmd = command; - char *str = NULL, *endptr = NULL; - struct ampdu_aggr aggr; - char smbuf[WLC_IOCTL_SMLEN]; - int idx; - int err = 0; - int wme_AC2PRIO[AC_COUNT][2] = { - {PRIO_8021D_VO, PRIO_8021D_NC}, /* AC_VO - 3 */ - {PRIO_8021D_CL, PRIO_8021D_VI}, /* AC_VI - 2 */ - {PRIO_8021D_BK, PRIO_8021D_NONE}, /* AC_BK - 1 */ - {PRIO_8021D_BE, PRIO_8021D_EE}}; /* AC_BE - 0 */ - - WL_DBG(("set ibss ampdu:%s\n", command)); - - memset(&aggr, 0, sizeof(aggr)); - /* Cofigure all priorities */ - aggr.conf_TID_bmap = NBITMASK(NUMPRIO); - - /* acquire parameters */ - /* drop command */ - str = bcmstrtok(&pcmd, " ", NULL); - - for (idx = 0; idx < AC_COUNT; idx++) { - bool on; - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - WL_ERR(("Invalid parameter : %s\n", pcmd)); - return -EINVAL; - } - on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE; - if (*endptr != '\0') { - WL_ERR(("Invalid number format %s\n", str)); - return -EINVAL; - } - if (on) { - setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]); - setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]); - } - } - - err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr, - sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL); - - return ((err == 0) ? total_len : err); -} - -int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len) -{ - char *pcmd = command; - char *str = NULL; - int txchain, rxchain; - int err = 0; - - WL_DBG(("set ibss antenna:%s\n", command)); - - /* acquire parameters */ - /* drop command */ - str = bcmstrtok(&pcmd, " ", NULL); - - /* TX chain */ - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - WL_ERR(("Invalid parameter : %s\n", pcmd)); - return -EINVAL; - } - txchain = bcm_atoi(str); - - /* RX chain */ - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - WL_ERR(("Invalid parameter : %s\n", pcmd)); - return -EINVAL; - } - rxchain = bcm_atoi(str); - - err = wldev_iovar_setint(dev, "txchain", txchain); - if (err != 0) - return err; - err = wldev_iovar_setint(dev, "rxchain", rxchain); - return ((err == 0)?total_len:err); -} -#endif /* WLAIBSS */ - -int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len) -{ - char buf[256]; - const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = -1; - uint period_msec = 0; - - if (extra == NULL) - { - DHD_ERROR(("%s: extra is NULL\n", __FUNCTION__)); - return -1; - } - if (sscanf(extra, "%d", &period_msec) != 1) - { - DHD_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__)); - return -EINVAL; - } - DHD_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec)); - - memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(buf, str, str_len); - buf[ str_len ] = '\0'; - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); - mkeep_alive_pkt.period_msec = period_msec; - buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - - /* Setup keep alive zero for null packet generation */ - mkeep_alive_pkt.keep_alive_id = 0; - mkeep_alive_pkt.len_bytes = 0; - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - if ((res = wldev_ioctl(dev, WLC_SET_VAR, buf, buf_len, TRUE)) < 0) - { - DHD_ERROR(("%s:keep_alive set failed. res[%d]\n", __FUNCTION__, res)); - } - else - { - DHD_ERROR(("%s:keep_alive set ok. res[%d]\n", __FUNCTION__, res)); - } - - return res; -} - - -static const char * -get_string_by_separator(char *result, int result_len, const char *src, char separator) -{ - char *end = result + result_len - 1; - while ((result != end) && (*src != separator) && (*src)) { - *result++ = *src++; - } - *result = 0; - if (*src == separator) - ++src; - return src; -} - -int -wl_android_set_roam_offload_bssid_list(struct net_device *dev, const char *cmd) -{ - char sbuf[32]; - int i, cnt, size, err, ioctl_buf_len; - roamoffl_bssid_list_t *bssid_list; - const char *str = cmd; - char *ioctl_buf; - - str = get_string_by_separator(sbuf, 32, str, ','); - cnt = bcm_atoi(sbuf); - cnt = MIN(cnt, MAX_ROAMOFFL_BSSID_NUM); - size = sizeof(int) + sizeof(struct ether_addr) * cnt; - WL_ERR(("ROAM OFFLOAD BSSID LIST %d BSSIDs, size %d\n", cnt, size)); - bssid_list = kmalloc(size, GFP_KERNEL); - if (bssid_list == NULL) { - WL_ERR(("%s: memory alloc for bssid list(%d) failed\n", - __FUNCTION__, size)); - return -ENOMEM; - } - ioctl_buf_len = size + 64; - ioctl_buf = kmalloc(ioctl_buf_len, GFP_KERNEL); - if (ioctl_buf == NULL) { - WL_ERR(("%s: memory alloc for ioctl_buf(%d) failed\n", - __FUNCTION__, ioctl_buf_len)); - kfree(bssid_list); - return -ENOMEM; - } - - for (i = 0; i < cnt; i++) { - str = get_string_by_separator(sbuf, 32, str, ','); - if (bcm_ether_atoe(sbuf, &bssid_list->bssid[i]) == 0) { - DHD_ERROR(("%s: Invalid station MAC Address!!!\n", __FUNCTION__)); - kfree(bssid_list); - kfree(ioctl_buf); - return -1; - } - } - - bssid_list->cnt = cnt; - err = wldev_iovar_setbuf(dev, "roamoffl_bssid_list", - bssid_list, size, ioctl_buf, ioctl_buf_len, NULL); - kfree(bssid_list); - kfree(ioctl_buf); - - return err; -} - - -static int wl_android_get_link_status(struct net_device *dev, char *command, - int total_len) -{ - int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map; - uint32 rspec; - uint encode, rate, txexp; - struct wl_bss_info *bi; - int datalen = sizeof(uint32) + sizeof(wl_bss_info_t); - char buf[datalen]; - - /* get BSS information */ - *(u32 *) buf = htod32(datalen); - error = wldev_ioctl(dev, WLC_GET_BSS_INFO, (void *)buf, datalen, false); - if (unlikely(error)) { - WL_ERR(("Could not get bss info %d\n", error)); - return -1; - } - - bi = (struct wl_bss_info *) (buf + sizeof(uint32)); - - for (i = 0; i < ETHER_ADDR_LEN; i++) { - if (bi->BSSID.octet[i] > 0) { - break; - } - } - - if (i == ETHER_ADDR_LEN) { - WL_DBG(("No BSSID\n")); - return -1; - } - - /* check VHT capability at beacon */ - if (bi->vht_cap) { - if (CHSPEC_IS5G(bi->chanspec)) { - result |= WL_ANDROID_LINK_AP_VHT_SUPPORT; - } - } - - /* get a rspec (radio spectrum) rate */ - error = wldev_iovar_getint(dev, "nrate", &rspec); - if (unlikely(error) || rspec == 0) { - WL_ERR(("get link status error (%d)\n", error)); - return -1; - } - - encode = (rspec & WL_RSPEC_ENCODING_MASK); - rate = (rspec & WL_RSPEC_RATE_MASK); - txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT; - - switch (encode) { - case WL_RSPEC_ENCODE_HT: - /* check Rx MCS Map for HT */ - for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) { - int8 bitmap = 0xFF; - if (i == MAX_STREAMS_SUPPORTED-1) { - bitmap = 0x7F; - } - if (bi->basic_mcs[i] & bitmap) { - nss++; - } - } - break; - case WL_RSPEC_ENCODE_VHT: - /* check Rx MCS Map for VHT */ - for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) { - mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap)); - if (mcs_map != VHT_CAP_MCS_MAP_NONE) { - nss++; - } - } - break; - } - - /* check MIMO capability with nss in beacon */ - if (nss > 1) { - result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT; - } - - single_stream = (encode == WL_RSPEC_ENCODE_RATE) || - ((encode == WL_RSPEC_ENCODE_HT) && rate < 8) || - ((encode == WL_RSPEC_ENCODE_VHT) && - ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1); - - if (txexp == 0) { - if ((rspec & WL_RSPEC_STBC) && single_stream) { - stf = OLD_NRATE_STF_STBC; - } else { - stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM; - } - } else if (txexp == 1 && single_stream) { - stf = OLD_NRATE_STF_CDD; - } - - /* check 11ac (VHT) */ - if (encode == WL_RSPEC_ENCODE_VHT) { - if (CHSPEC_IS5G(bi->chanspec)) { - result |= WL_ANDROID_LINK_VHT; - } - } - - /* check MIMO */ - if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) { - switch (stf) { - case OLD_NRATE_STF_SISO: - break; - case OLD_NRATE_STF_CDD: - case OLD_NRATE_STF_STBC: - result |= WL_ANDROID_LINK_MIMO; - break; - case OLD_NRATE_STF_SDM: - if (!single_stream) { - result |= WL_ANDROID_LINK_MIMO; - } - break; - } - } - - WL_DBG(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n", - __FUNCTION__, result, stf, single_stream, nss)); - - bytes_written = sprintf(command, "%s %d", CMD_GET_LINK_STATUS, result); - - return bytes_written; -} - -#ifdef SET_RPS_CPUS -static int -wl_android_set_rps_cpus(struct net_device *dev, char *command, int total_len) -{ - int error, enable; - - enable = command[strlen(CMD_RPSMODE) + 1] - '0'; - error = dhd_rps_cpus_enable(dev, enable); - - return error; -} -#endif /* SET_RPS_CPUS */ - -int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) -{ -#define PRIVATE_COMMAND_MAX_LEN 8192 -#define PRIVATE_COMMAND_DEF_LEN 4096 - int ret = 0; - char *command = NULL; - int bytes_written = 0; - android_wifi_priv_cmd priv_cmd; - int buf_size = 0; - - net_os_wake_lock(net); - - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto exit; - } - - if (!ifr->ifr_data) { - ret = -EINVAL; - goto exit; - } - - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto exit; - } - -#ifdef CONFIG_COMPAT - if (is_compat_task()) { - compat_android_wifi_priv_cmd compat_priv_cmd; - if (copy_from_user(&compat_priv_cmd, ifr->ifr_data, - sizeof(compat_android_wifi_priv_cmd))) { - ret = -EFAULT; - goto exit; - - } - priv_cmd.buf = compat_ptr(compat_priv_cmd.buf); - priv_cmd.used_len = compat_priv_cmd.used_len; - priv_cmd.total_len = compat_priv_cmd.total_len; - } else -#endif /* CONFIG_COMPAT */ - { - if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) { - ret = -EFAULT; - goto exit; - } - } - if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) { - DHD_ERROR(("%s: buf length invalid:%d \n", __FUNCTION__, priv_cmd.total_len)); - ret = -EINVAL; - goto exit; - } - - if (priv_cmd.total_len < PRIVATE_COMMAND_DEF_LEN) { - buf_size = PRIVATE_COMMAND_DEF_LEN; - } else { - buf_size = priv_cmd.total_len; - } - - command = kmalloc((buf_size + 1), GFP_KERNEL); - - if (!command) - { - DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__)); - ret = -ENOMEM; - goto exit; - } - if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { - ret = -EFAULT; - goto exit; - } - command[priv_cmd.total_len] = '\0'; - - DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); - - if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { - DHD_INFO(("%s, Received regular START command\n", __FUNCTION__)); - bytes_written = wl_android_wifi_on(net); - } - else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) { - bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len); - } - - if (!g_wifi_on) { - DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n", - __FUNCTION__, command, ifr->ifr_name)); - ret = 0; - goto exit; - } - - if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) { - bytes_written = wl_android_wifi_off(net); - } - else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { - /* TBD: SCAN-ACTIVE */ - } - else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) { - /* TBD: SCAN-PASSIVE */ - } - else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) { - bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { - bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len); - } -#ifdef PKT_FILTER_SUPPORT - else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) { - bytes_written = net_os_enable_packet_filter(net, 1); - } - else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) { - bytes_written = net_os_enable_packet_filter(net, 0); - } - else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) { - int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; - bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num); - } - else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) { - int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; - bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); - } -#endif /* PKT_FILTER_SUPPORT */ - else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { - /* TBD: BTCOEXSCAN-START */ - } - else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) { - /* TBD: BTCOEXSCAN-STOP */ - } - else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { -#ifdef WL_CFG80211 - void *dhdp = wl_cfg80211_get_dhdp(); - bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command); -#else -#ifdef PKT_FILTER_SUPPORT - uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; - - if (mode == 1) - net_os_enable_packet_filter(net, 0); /* DHCP starts */ - else - net_os_enable_packet_filter(net, 1); /* DHCP ends */ -#endif /* PKT_FILTER_SUPPORT */ -#endif /* WL_CFG80211 */ - } - else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { - bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { - bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { - uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; -#ifdef WL_HOST_BAND_MGMT - s32 ret = 0; - if ((ret = wl_cfg80211_set_band(net, band)) < 0) { - if (ret == BCME_UNSUPPORTED) { - /* If roam_var is unsupported, fallback to the original method */ - WL_ERR(("WL_HOST_BAND_MGMT defined, " - "but roam_band iovar unsupported in the firmware\n")); - } else { - bytes_written = -1; - goto exit; - } - } - if ((band == WLC_BAND_AUTO) || (ret == BCME_UNSUPPORTED)) - bytes_written = wldev_set_band(net, band); -#else - bytes_written = wldev_set_band(net, band); -#endif /* WL_HOST_BAND_MGMT */ - } - else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { - bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); - } -#ifdef WL_CFG80211 -#ifndef CUSTOMER_SET_COUNTRY - /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ - else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { - char *country_code = command + strlen(CMD_COUNTRY) + 1; -#ifdef CUSTOMER_HW5 - /* Customer_hw5 want to keep connections */ - bytes_written = wldev_set_country(net, country_code, true, false); -#else - bytes_written = wldev_set_country(net, country_code, true, true); -#endif - } -#endif /* CUSTOMER_SET_COUNTRY */ -#endif /* WL_CFG80211 */ - else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) { - bytes_written = wl_android_set_csa(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) { - bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) { - bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) { - bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) { - bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len); - } - - -#ifdef PNO_SUPPORT - else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { - bytes_written = dhd_dev_pno_stop_for_ssid(net); - } -#ifndef WL_SCHED_SCAN - else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { - bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len); - } -#endif /* !WL_SCHED_SCAN */ - else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { - int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; - bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net); - } - else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) { - bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len); - } -#endif /* PNO_SUPPORT */ - else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { - bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) { - int skip = strlen(CMD_P2P_SET_NOA) + 1; - bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, - priv_cmd.total_len - skip); - } -#if !defined WL_ENABLE_P2P_IF - else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { - bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); - } -#endif /* WL_ENABLE_P2P_IF */ - else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { - int skip = strlen(CMD_P2P_SET_PS) + 1; - bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, - priv_cmd.total_len - skip); - } -#ifdef WL_CFG80211 - else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE, - strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) { - int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3; - bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, - priv_cmd.total_len - skip, *(command + skip - 2) - '0'); - } -#ifdef WLFBT - else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) { - wl_cfg80211_get_fbt_key(command); - bytes_written = FBT_KEYLEN; - } -#endif /* WLFBT */ -#endif /* WL_CFG80211 */ - else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) - bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) - bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); -#ifdef BCMCCX - else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) { - bytes_written = wl_android_get_cckm_rn(net, command); - } - else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) { - bytes_written = wl_android_set_cckm_krk(net, command); - } - else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) { - bytes_written = wl_android_get_assoc_res_ies(net, command); - } -#endif /* BCMCCX */ -#if defined(WL_SUPPORT_AUTO_CHANNEL) - else if (strnicmp(command, CMD_GET_BEST_CHANNELS, - strlen(CMD_GET_BEST_CHANNELS)) == 0) { - bytes_written = wl_cfg80211_get_best_channels(net, command, - priv_cmd.total_len); - } -#endif /* WL_SUPPORT_AUTO_CHANNEL */ - else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) { - int skip = strlen(CMD_HAPD_MAC_FILTER) + 1; - wl_android_set_mac_address_filter(net, (const char*)command+skip); - } - else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0) - bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len); -#if defined(BCMFW_ROAM_ENABLE) - else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) { - bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len); - } -#endif /* BCMFW_ROAM_ENABLE */ - else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) - bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0) - bytes_written = wl_android_set_ibss_beacon_ouidata(net, - command, priv_cmd.total_len); -#ifdef WLAIBSS - else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT, - strlen(CMD_SETIBSSTXFAILEVENT)) == 0) - bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL, - strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0) - bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, - TRUE); - else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO, - strlen(CMD_GET_IBSS_PEER_INFO)) == 0) - bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, - FALSE); - else if (strnicmp(command, CMD_SETIBSSROUTETABLE, - strlen(CMD_SETIBSSROUTETABLE)) == 0) - bytes_written = wl_android_set_ibss_routetable(net, command, - priv_cmd.total_len); - else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0) - bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0) - bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len); -#endif /* WLAIBSS */ - else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) { - int skip = strlen(CMD_KEEP_ALIVE) + 1; - bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip); - } - else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) { - int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0'; - bytes_written = wl_cfg80211_enable_roam_offload(net, enable); - } - else if (strnicmp(command, CMD_ROAM_OFFLOAD_APLIST, strlen(CMD_ROAM_OFFLOAD_APLIST)) == 0) { - bytes_written = wl_android_set_roam_offload_bssid_list(net, - command + strlen(CMD_ROAM_OFFLOAD_APLIST) + 1); - } -#ifdef SET_RPS_CPUS - else if (strnicmp(command, CMD_RPSMODE, strlen(CMD_RPSMODE)) == 0) { - bytes_written = wl_android_set_rps_cpus(net, command, priv_cmd.total_len); - } -#endif /* SET_RPS_CPUS */ - else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) { - bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len); - } -#ifdef CONNECTION_STATISTICS - else if (strnicmp(command, CMD_GET_CONNECTION_STATS, - strlen(CMD_GET_CONNECTION_STATS)) == 0) { - bytes_written = wl_android_get_connection_stats(net, command, - priv_cmd.total_len); - } -#endif - else { - DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); - snprintf(command, 5, "FAIL"); - bytes_written = strlen("FAIL"); - } - - if (bytes_written >= 0) { - if ((bytes_written == 0) && (priv_cmd.total_len > 0)) { - command[0] = '\0'; - } - if (bytes_written >= priv_cmd.total_len) { - DHD_ERROR(("%s: not enough for output. bytes_written:%d >= total_len:%d \n", - __FUNCTION__, bytes_written, priv_cmd.total_len)); - ret = BCME_BUFTOOSHORT; - goto exit; - } else { - bytes_written++; - } - priv_cmd.used_len = bytes_written; - if (copy_to_user(priv_cmd.buf, command, bytes_written)) { - DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); - ret = -EFAULT; - } - } - else { - ret = bytes_written; - } - -exit: - net_os_wake_unlock(net); - if (command) { - kfree(command); - } - - return ret; -} - -int wl_android_init(void) -{ - int ret = 0; - -#ifdef ENABLE_INSMOD_NO_FW_LOAD - dhd_download_fw_on_driverload = FALSE; -#endif /* ENABLE_INSMOD_NO_FW_LOAD */ -#if defined(CUSTOMER_HW2) - if (!iface_name[0]) { - memset(iface_name, 0, IFNAMSIZ); - bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); - } -#endif - -#ifdef WL_GENL - wl_genl_init(); -#endif - wl_netlink_init(); - - return ret; -} - -int wl_android_exit(void) -{ - int ret = 0; - struct io_cfg *cur, *q; - -#ifdef WL_GENL - wl_genl_deinit(); -#endif /* WL_GENL */ - wl_netlink_deinit(); - - list_for_each_entry_safe(cur, q, &miracast_resume_list, list) { - list_del(&cur->list); - kfree(cur); - } - - return ret; -} - -void wl_android_post_init(void) -{ - -#ifdef ENABLE_4335BT_WAR - bcm_bt_unlock(lock_cookie_wifi); - printk("%s: btlock released\n", __FUNCTION__); -#endif /* ENABLE_4335BT_WAR */ - - if (!dhd_download_fw_on_driverload) - g_wifi_on = FALSE; -} - -#ifdef WL_GENL -/* Generic Netlink Initializaiton */ -static int wl_genl_init(void) -{ - int ret; - - WL_DBG(("GEN Netlink Init\n\n")); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) - /* register new family */ - ret = genl_register_family(&wl_genl_family); - if (ret != 0) - goto failure; - - /* register functions (commands) of the new family */ - ret = genl_register_ops(&wl_genl_family, &wl_genl_ops); - if (ret != 0) { - WL_ERR(("register ops failed: %i\n", ret)); - genl_unregister_family(&wl_genl_family); - goto failure; - } - - ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast); -#else - ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast); -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */ - if (ret != 0) { - WL_ERR(("register mc_group failed: %i\n", ret)); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) - genl_unregister_ops(&wl_genl_family, &wl_genl_ops); -#endif - genl_unregister_family(&wl_genl_family); - goto failure; - } - - return 0; - -failure: - WL_ERR(("Registering Netlink failed!!\n")); - return -1; -} - -/* Generic netlink deinit */ -static int wl_genl_deinit(void) -{ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) - if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0) - WL_ERR(("Unregister wl_genl_ops failed\n")); -#endif - if (genl_unregister_family(&wl_genl_family) < 0) - WL_ERR(("Unregister wl_genl_ops failed\n")); - - return 0; -} - -s32 wl_event_to_bcm_event(u16 event_type) -{ - u16 event = -1; - - switch (event_type) { - case WLC_E_SERVICE_FOUND: - event = BCM_E_SVC_FOUND; - break; - case WLC_E_P2PO_ADD_DEVICE: - event = BCM_E_DEV_FOUND; - break; - case WLC_E_P2PO_DEL_DEVICE: - event = BCM_E_DEV_LOST; - break; - /* Above events are supported from BCM Supp ver 47 Onwards */ -#ifdef BT_WIFI_HANDOVER - case WLC_E_BT_WIFI_HANDOVER_REQ: - event = BCM_E_DEV_BT_WIFI_HO_REQ; - break; -#endif /* BT_WIFI_HANDOVER */ - - default: - WL_ERR(("Event not supported\n")); - } - - return event; -} - -s32 -wl_genl_send_msg( - struct net_device *ndev, - u32 event_type, - u8 *buf, - u16 len, - u8 *subhdr, - u16 subhdr_len) -{ - int ret = 0; - struct sk_buff *skb = NULL; - void *msg; - u32 attr_type = 0; - bcm_event_hdr_t *hdr = NULL; - int mcast = 1; /* By default sent as mutlicast type */ - int pid = 0; - u8 *ptr = NULL, *p = NULL; - u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - - WL_DBG(("Enter \n")); - - /* Decide between STRING event and Data event */ - if (event_type == 0) - attr_type = BCM_GENL_ATTR_STRING; - else - attr_type = BCM_GENL_ATTR_MSG; - - skb = genlmsg_new(NLMSG_GOODSIZE, kflags); - if (skb == NULL) { - ret = -ENOMEM; - goto out; - } - - msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG); - if (msg == NULL) { - ret = -ENOMEM; - goto out; - } - - - if (attr_type == BCM_GENL_ATTR_STRING) { - /* Add a BCM_GENL_MSG attribute. Since it is specified as a string. - * make sure it is null terminated - */ - if (subhdr || subhdr_len) { - WL_ERR(("No sub hdr support for the ATTR STRING type \n")); - ret = -EINVAL; - goto out; - } - - ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf); - if (ret != 0) { - WL_ERR(("nla_put_string failed\n")); - goto out; - } - } else { - /* ATTR_MSG */ - - /* Create a single buffer for all */ - p = ptr = kzalloc(tot_len, kflags); - if (!ptr) { - ret = -ENOMEM; - WL_ERR(("ENOMEM!!\n")); - goto out; - } - - /* Include the bcm event header */ - hdr = (bcm_event_hdr_t *)ptr; - hdr->event_type = wl_event_to_bcm_event(event_type); - hdr->len = len + subhdr_len; - ptr += sizeof(bcm_event_hdr_t); - - /* Copy subhdr (if any) */ - if (subhdr && subhdr_len) { - memcpy(ptr, subhdr, subhdr_len); - ptr += subhdr_len; - } - - /* Copy the data */ - if (buf && len) { - memcpy(ptr, buf, len); - } - - ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p); - if (ret != 0) { - WL_ERR(("nla_put_string failed\n")); - goto out; - } - } - - if (mcast) { - int err = 0; - /* finalize the message */ - genlmsg_end(skb, msg); - /* NETLINK_CB(skb).dst_group = 1; */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0) -#else - if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0) -#endif - WL_ERR(("genlmsg_multicast for attr(%d) failed. Error:%d \n", - attr_type, err)); - else - WL_DBG(("Multicast msg sent successfully. attr_type:%d len:%d \n", - attr_type, tot_len)); - } else { - NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */ - - /* finalize the message */ - genlmsg_end(skb, msg); - - /* send the message back */ - if (genlmsg_unicast(&init_net, skb, pid) < 0) - WL_ERR(("genlmsg_unicast failed\n")); - } - -out: - if (p) - kfree(p); - if (ret) - nlmsg_free(skb); - - return ret; -} - -static s32 -wl_genl_handle_msg( - struct sk_buff *skb, - struct genl_info *info) -{ - struct nlattr *na; - u8 *data = NULL; - - WL_DBG(("Enter \n")); - - if (info == NULL) { - return -EINVAL; - } - - na = info->attrs[BCM_GENL_ATTR_MSG]; - if (!na) { - WL_ERR(("nlattribute NULL\n")); - return -EINVAL; - } - - data = (char *)nla_data(na); - if (!data) { - WL_ERR(("Invalid data\n")); - return -EINVAL; - } else { - /* Handle the data */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || defined(WL_COMPAT_WIRELESS) - WL_DBG(("%s: Data received from pid (%d) \n", __func__, - info->snd_pid)); -#else - WL_DBG(("%s: Data received from pid (%d) \n", __func__, - info->snd_portid)); -#endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */ - } - - return 0; -} -#endif /* WL_GENL */ diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h deleted file mode 100644 index cb6ca2403eb9..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_android.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Linux cfg80211 driver - Android related functions - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_android.h 513437 2014-11-06 12:09:29Z $ - */ - -#include -#include -#include - -/* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL - * automatically - */ -#if defined(BT_WIFI_HANDOVER) -#define WL_GENL -#endif - - -#ifdef WL_GENL -#include -#endif - -/** - * Android platform dependent functions, feel free to add Android specific functions here - * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd - * or cfg, define them as static in wl_android.c - */ - -/** - * wl_android_init will be called from module init function (dhd_module_init now), similarly - * wl_android_exit will be called from module exit function (dhd_module_cleanup now) - */ -int wl_android_init(void); -int wl_android_exit(void); -void wl_android_post_init(void); -int wl_android_wifi_on(struct net_device *dev); -int wl_android_wifi_off(struct net_device *dev); -int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); - -#ifdef WL_GENL -typedef struct bcm_event_hdr { - u16 event_type; - u16 len; -} bcm_event_hdr_t; - -/* attributes (variables): the index in this enum is used as a reference for the type, - * userspace application has to indicate the corresponding type - * the policy is used for security considerations - */ -enum { - BCM_GENL_ATTR_UNSPEC, - BCM_GENL_ATTR_STRING, - BCM_GENL_ATTR_MSG, - __BCM_GENL_ATTR_MAX -}; -#define BCM_GENL_ATTR_MAX (__BCM_GENL_ATTR_MAX - 1) - -/* commands: enumeration of all commands (functions), - * used by userspace application to identify command to be ececuted - */ -enum { - BCM_GENL_CMD_UNSPEC, - BCM_GENL_CMD_MSG, - __BCM_GENL_CMD_MAX -}; -#define BCM_GENL_CMD_MAX (__BCM_GENL_CMD_MAX - 1) - -/* Enum values used by the BCM supplicant to identify the events */ -enum { - BCM_E_UNSPEC, - BCM_E_SVC_FOUND, - BCM_E_DEV_FOUND, - BCM_E_DEV_LOST, - BCM_E_DEV_BT_WIFI_HO_REQ, - BCM_E_MAX -}; - -s32 wl_genl_send_msg(struct net_device *ndev, u32 event_type, - u8 *string, u16 len, u8 *hdr, u16 hdrlen); -#endif /* WL_GENL */ -s32 wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size); - -/* hostap mac mode */ -#define MACLIST_MODE_DISABLED 0 -#define MACLIST_MODE_DENY 1 -#define MACLIST_MODE_ALLOW 2 - -/* max number of assoc list */ -#define MAX_NUM_OF_ASSOCLIST 64 -/* Bandwidth */ -#define WL_CH_BANDWIDTH_20MHZ 20 -#define WL_CH_BANDWIDTH_40MHZ 40 -#define WL_CH_BANDWIDTH_80MHZ 80 - -/* max number of mac filter list - * restrict max number to 10 as maximum cmd string size is 255 - */ -#define MAX_NUM_MAC_FILT 10 - -int wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c deleted file mode 100644 index 4d9b84165553..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ /dev/null @@ -1,14416 +0,0 @@ -/* - * Linux cfg80211 driver - * - * Copyright (C) 1999-2017, Broadcom Corporation - * Copyright (C) 2015 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.c 718504 2017-08-31 02:38:08Z $ - */ -/* */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#ifdef PNO_SUPPORT -#include -#endif /* PNO_SUPPORT */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef PROP_TXSTATUS -#include -#endif - -#ifdef WL11U -#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) -#error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \ - according to Kernel version and is supported only in Android-JB -#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ -#endif /* WL11U */ - -#ifdef BCMWAPI_WPI -/* these items should evetually go into wireless.h of the linux system headfile dir */ -#ifndef IW_ENCODE_ALG_SM4 -#define IW_ENCODE_ALG_SM4 0x20 -#endif - -#ifndef IW_AUTH_WAPI_ENABLED -#define IW_AUTH_WAPI_ENABLED 0x20 -#endif - -#ifndef IW_AUTH_WAPI_VERSION_1 -#define IW_AUTH_WAPI_VERSION_1 0x00000008 -#endif - -#ifndef IW_AUTH_CIPHER_SMS4 -#define IW_AUTH_CIPHER_SMS4 0x00000020 -#endif - -#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK -#define IW_AUTH_KEY_MGMT_WAPI_PSK 4 -#endif - -#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT -#define IW_AUTH_KEY_MGMT_WAPI_CERT 8 -#endif -#endif /* BCMWAPI_WPI */ - -#ifdef BCMWAPI_WPI -#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) -#else /* BCMWAPI_WPI */ -#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) -#endif /* BCMWAPI_WPI */ - -static struct device *cfg80211_parent_dev = NULL; -/* g_bcm_cfg should be static. Do not change */ -static struct bcm_cfg80211 *g_bcm_cfg = NULL; -u32 wl_dbg_level = WL_DBG_ERR; - -#ifdef WLAIBSS_MCHAN -#define IBSS_IF_NAME "ibss%d" -#endif /* WLAIBSS_MCHAN */ - -#ifdef VSDB -/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */ -#define DEFAULT_SLEEP_TIME_VSDB 120 -#define OFF_CHAN_TIME_THRESHOLD_MS 200 -#define AF_RETRY_DELAY_TIME 40 - -/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */ -#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \ - do { \ - if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \ - wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \ - OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \ - } \ - } while (0) -#else /* VSDB */ -/* if not VSDB, do nothing */ -#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) -#endif /* VSDB */ - -#ifdef WL_CFG80211_SYNC_GON -#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) \ - (wl_get_drv_status_all(cfg, SENDING_ACT_FRM) || \ - wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) -#else -#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) wl_get_drv_status_all(cfg, SENDING_ACT_FRM) -#endif /* WL_CFG80211_SYNC_GON */ -#define WL_IS_P2P_DEV_EVENT(e) ((e->emsg.ifidx == 0) && \ - (e->emsg.bsscfgidx == P2PAPI_BSSCFG_DEVICE)) - -#define COEX_DHCP - -#define WLAN_EID_SSID 0 -#define CH_MIN_5G_CHANNEL 34 -#define CH_MIN_2G_CHANNEL 1 - -#ifdef WLAIBSS -enum abiss_event_type { - AIBSS_EVENT_TXFAIL -}; -#endif - -enum rmc_event_type { - RMC_EVENT_NONE, - RMC_EVENT_LEADER_CHECK_FAIL -}; - -/* This is to override regulatory domains defined in cfg80211 module (reg.c) - * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN - * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165). - * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels. - * All the chnages in world regulatory domain are to be done here. - */ -static const struct ieee80211_regdomain brcm_regdom = { - .n_reg_rules = 4, - .alpha2 = "99", - .reg_rules = { - /* IEEE 802.11b/g, channels 1..11 */ - REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), - /* If any */ - /* IEEE 802.11 channel 14 - Only JP enables - * this and for 802.11b only - */ - REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), - /* IEEE 802.11a, channel 36..64 */ - REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), - /* IEEE 802.11a, channel 100..165 */ - REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } -}; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) -/* - * Possible interface combinations supported by driver - * - * ADHOC Mode - #ADHOC <= 1 on channels = 1 - * SoftAP Mode - #AP <= 1 on channels = 1 - * STA + P2P Mode - #STA <= 2, #{P2P-GO, P2P-client} <= 1, #P2P-device <= 1 - * on channels = 2 - */ -static const struct ieee80211_iface_limit common_if_limits[] = { - { - .max = 1, - .types = BIT(NL80211_IFTYPE_AP), - }, - { - /* - * During P2P-GO removal, P2P-GO is first changed to STA and later only - * removed. So setting maximum possible number of STA interfaces according - * to kernel version. - * - * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x) - * linux-3.8 and above - max:2 (wlan0 + group removal of p2p-wlan0-x) - */ -#ifdef WL_ENABLE_P2P_IF - .max = 3, -#else - .max = 2, -#endif /* WL_ENABLE_P2P_IF */ - .types = BIT(NL80211_IFTYPE_STATION), - }, - { - .max = 2, - .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), - }, -#if defined(WL_CFG80211_P2P_DEV_IF) - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_DEVICE), - }, -#endif /* WL_CFG80211_P2P_DEV_IF */ - { - .max = 1, - .types = BIT(NL80211_IFTYPE_ADHOC), - }, -}; -#ifdef BCM4330_CHIP -#define NUM_DIFF_CHANNELS 1 -#else -#define NUM_DIFF_CHANNELS 2 -#endif -static const struct ieee80211_iface_combination -common_iface_combinations[] = { - { - .num_different_channels = NUM_DIFF_CHANNELS, - .max_interfaces = 4, - .limits = common_if_limits, - .n_limits = ARRAY_SIZE(common_if_limits), - }, -}; -#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ - -/* Data Element Definitions */ -#define WPS_ID_CONFIG_METHODS 0x1008 -#define WPS_ID_REQ_TYPE 0x103A -#define WPS_ID_DEVICE_NAME 0x1011 -#define WPS_ID_VERSION 0x104A -#define WPS_ID_DEVICE_PWD_ID 0x1012 -#define WPS_ID_REQ_DEV_TYPE 0x106A -#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053 -#define WPS_ID_PRIM_DEV_TYPE 0x1054 - -/* Device Password ID */ -#define DEV_PW_DEFAULT 0x0000 -#define DEV_PW_USER_SPECIFIED 0x0001, -#define DEV_PW_MACHINE_SPECIFIED 0x0002 -#define DEV_PW_REKEY 0x0003 -#define DEV_PW_PUSHBUTTON 0x0004 -#define DEV_PW_REGISTRAR_SPECIFIED 0x0005 - -/* Config Methods */ -#define WPS_CONFIG_USBA 0x0001 -#define WPS_CONFIG_ETHERNET 0x0002 -#define WPS_CONFIG_LABEL 0x0004 -#define WPS_CONFIG_DISPLAY 0x0008 -#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010 -#define WPS_CONFIG_INT_NFC_TOKEN 0x0020 -#define WPS_CONFIG_NFC_INTERFACE 0x0040 -#define WPS_CONFIG_PUSHBUTTON 0x0080 -#define WPS_CONFIG_KEYPAD 0x0100 -#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280 -#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480 -#define WPS_CONFIG_VIRT_DISPLAY 0x2008 -#define WPS_CONFIG_PHY_DISPLAY 0x4008 - -#ifdef BCMCCX -#ifndef WLAN_AKM_SUITE_CCKM -#define WLAN_AKM_SUITE_CCKM 0x00409600 -#endif -#define DOT11_LEAP_AUTH 0x80 /* LEAP auth frame paylod constants */ -#endif /* BCMCCX */ - -#ifdef MFP -#define WL_AKM_SUITE_MFP_1X 0x000FAC05 -#define WL_AKM_SUITE_MFP_PSK 0x000FAC06 -#define WL_MFP_CAPABLE 0x1 -#define WL_MFP_REQUIRED 0x2 -#endif /* MFP */ - -#ifndef IBSS_COALESCE_ALLOWED -#define IBSS_COALESCE_ALLOWED 0 -#endif - -#ifndef IBSS_INITIAL_SCAN_ALLOWED -#define IBSS_INITIAL_SCAN_ALLOWED 0 -#endif - -#define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */ -/* - * cfg80211_ops api/callback list - */ -static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, - const struct ether_addr *sa, const struct ether_addr *bssid, - u8 **pheader, u32 *body_len, u8 *pbody); -static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request, - struct cfg80211_ssid *this_ssid); -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); -#else -static s32 -wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request); -#endif /* WL_CFG80211_P2P_DEV_IF */ -static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); -#ifdef WLAIBSS_MCHAN -static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name); -static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev); -#endif /* WLAIBSS_MCHAN */ -static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params); -static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, - struct net_device *dev); -static s32 wl_cfg80211_get_station(struct wiphy *wiphy, - struct net_device *dev, u8 *mac, - struct station_info *sinfo); -static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, - struct net_device *dev, bool enabled, - s32 timeout); -static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code); -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, s32 mbm); -#else -static s32 -wl_cfg80211_set_tx_power(struct wiphy *wiphy, - enum nl80211_tx_power_setting type, s32 dbm); -#endif /* WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, s32 *dbm); -#else -static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); -#endif /* WL_CFG80211_P2P_DEV_IF */ -static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, - struct net_device *dev, - u8 key_idx, bool unicast, bool multicast); -static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - struct key_params *params); -static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr); -static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - void *cookie, void (*callback) (void *cookie, - struct key_params *params)); -static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *dev, u8 key_idx); -static s32 wl_cfg80211_resume(struct wiphy *wiphy); -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 2, 0)) -static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, - bcm_struct_cfgdev *cfgdev, u64 cookie); -static s32 wl_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *ndev, u8* mac_addr); -static s32 wl_cfg80211_change_station(struct wiphy *wiphy, - struct net_device *dev, u8 *mac, struct station_parameters *params); -#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) -static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); -#else -static s32 wl_cfg80211_suspend(struct wiphy *wiphy); -#endif -static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa); -static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa); -static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, - struct net_device *dev); -static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg); -#if defined(WL_ABORT_SCAN) -static void wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *dev); -#endif /* WL_ABORT_SCAN */ -static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, - struct net_device *ndev, bool aborted, bool fw_abort); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) -#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) -static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, - u32 peer_capability, const u8 *data, size_t len); -#else -static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data, - size_t len); -#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ -static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, enum nl80211_tdls_operation oper); -#endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */ -#ifdef WL_SCHED_SCAN -static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev); -#endif -#if defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) -bcm_struct_cfgdev* -wl_cfg80211_create_iface(struct wiphy *wiphy, enum nl80211_iftype - iface_type, u8 *mac_addr, const char *name); -s32 -wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev); -#endif /* defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) */ -chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec); - -/* - * event & event Q handlers for cfg80211 interfaces - */ -static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg); -static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg); -static s32 wl_event_handler(void *data); -static void wl_init_eq(struct bcm_cfg80211 *cfg); -static void wl_flush_eq(struct bcm_cfg80211 *cfg); -static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg); -static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags); -static void wl_init_eq_lock(struct bcm_cfg80211 *cfg); -static void wl_init_event_handler(struct bcm_cfg80211 *cfg); -static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg); -static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type, - const wl_event_msg_t *msg, void *data); -static void wl_put_event(struct wl_event_q *e); -static void wl_wakeup_event(struct bcm_cfg80211 *cfg); -static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data); -static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data, bool completed); -static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data); -static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -#ifdef BT_WIFI_HANDOVER -static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -#endif /* BT_WIFI_HANDOVER */ -#ifdef WL_SCHED_SCAN -static s32 -wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data); -#endif /* WL_SCHED_SCAN */ -#ifdef PNO_SUPPORT -static s32 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -#endif /* PNO_SUPPORT */ -#ifdef GSCAN_SUPPORT -static s32 wl_notify_gscan_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -#endif /* GSCAN_SUPPORT */ -static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, - enum wl_status state, bool set); - -#ifdef WLTDLS -static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -#endif /* WLTDLS */ -/* - * register/deregister parent device - */ -static void wl_cfg80211_clear_parent_dev(void); - -/* - * ioctl utilites - */ - -/* - * cfg80211 set_wiphy_params utilities - */ -static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); -static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold); -static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); - -/* - * cfg profile utilities - */ -static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data, s32 item); -static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item); -static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev); - -/* - * cfg80211 connect utilites - */ -static s32 wl_set_wpa_version(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_set_auth_type(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_set_set_cipher(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_set_key_mgmt(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_set_set_sharedkey(struct net_device *dev, - struct cfg80211_connect_params *sme); -#ifdef BCMWAPI_WPI -static s32 wl_set_set_wapi_ie(struct net_device *dev, - struct cfg80211_connect_params *sme); -#endif -static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev); -static void wl_ch_to_chanspec(int ch, - struct wl_join_params *join_params, size_t *join_params_size); - -/* - * information element utilities - */ -static void wl_rst_ie(struct bcm_cfg80211 *cfg); -static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v); -static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam); -static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size); -static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size); -static u32 wl_get_ielen(struct bcm_cfg80211 *cfg); -#ifdef MFP -static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa); -#endif - -#ifdef WL11U -bcm_tlv_t * -wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); -static s32 -wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, - uint8 ie_id, uint8 *data, uint8 data_len); -#endif /* WL11U */ - -static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data); -static void wl_free_wdev(struct bcm_cfg80211 *cfg); - -static s32 wl_inform_bss(struct bcm_cfg80211 *cfg); -static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam); -static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam); -static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); -s32 wl_cfg80211_channel_to_freq(u32 channel); - - -static void wl_cfg80211_work_handler(struct work_struct *work); -static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, const u8 *mac_addr, - struct key_params *params); -/* - * key indianess swap utilities - */ -static void swap_key_from_BE(struct wl_wsec_key *key); -static void swap_key_to_BE(struct wl_wsec_key *key); - -/* - * bcm_cfg80211 memory init/deinit utilities - */ -static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg); -static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg); - -static void wl_delay(u32 ms); - -/* - * ibss mode utilities - */ -static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev); -static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg); - -/* - * link up/down , default configuration utilities - */ -static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg); -static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg); -static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); -static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, - struct net_device *ndev); -static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); -static void wl_link_up(struct bcm_cfg80211 *cfg); -static void wl_link_down(struct bcm_cfg80211 *cfg); -static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype); -static void wl_init_conf(struct wl_conf *conf); -static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info, - struct net_device* ndev); - -int wl_cfg80211_get_ioctl_version(void); - -/* - * find most significant bit set - */ -static __used u32 wl_find_msb(u16 bit16); - -/* - * rfkill support - */ -static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup); -static int wl_rfkill_set(void *data, bool blocked); -#ifdef DEBUGFS_CFG80211 -static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg); -static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg); -#endif - -static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel, - int nprobes, int *out_params_size); -static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role); - -#ifdef WL_CFG80211_ACL -/* ACL */ -static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, - const struct cfg80211_acl_data *acl); -#endif /* WL_CFG80211_ACL */ - -/* - * Some external functions, TODO: move them to dhd_linux.h - */ -int dhd_add_monitor(char *name, struct net_device **new_ndev); -int dhd_del_monitor(struct net_device *ndev); -int dhd_monitor_init(void *dhd_pub); -int dhd_monitor_uninit(void); -int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); - - -static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const struct ether_addr *bssid); - -static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ, - WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ }; - -#define RETURN_EIO_IF_NOT_UP(wlpriv) \ -do { \ - struct net_device *checkSysUpNDev = bcmcfg_to_prmry_ndev(wlpriv); \ - if (unlikely(!wl_get_drv_status(wlpriv, READY, checkSysUpNDev))) { \ - WL_INFORM(("device is not ready\n")); \ - return -EIO; \ - } \ -} while (0) - -#ifdef RSSI_OFFSET -static s32 wl_rssi_offset(s32 rssi) -{ - rssi += RSSI_OFFSET; - if (rssi > 0) - rssi = 0; - return rssi; -} -#else -#define wl_rssi_offset(x) x -#endif - -#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ - (akm) == RSN_AKM_UNSPECIFIED || \ - (akm) == RSN_AKM_PSK) - - -extern int dhd_wait_pend8021x(struct net_device *dev); -#ifdef PROP_TXSTATUS_VSDB -extern int disable_proptx; -#endif /* PROP_TXSTATUS_VSDB */ - -extern int passive_channel_skip; - -static s32 -wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, -const wl_event_msg_t *e, void *data); -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \ - 0))) -struct chan_info { - int freq; - int chan_type; -}; -#endif - - -#if (WL_DBG_LEVEL > 0) -#define WL_DBG_ESTR_MAX 50 -static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { - "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND", - "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC", - "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END", - "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM", - "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH", - "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND", - "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", - "PFN_NET_LOST", - "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", - "IBSS_ASSOC", - "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT", - "PROBREQ_MSG", - "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", - "EXCEEDED_MEDIUM_TIME", "ICV_ERROR", - "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE", - "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE", - "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG", - "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND", - "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED", - "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT", - "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE", - "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP", - "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE" -}; -#endif /* WL_DBG_LEVEL */ - -#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(DOT11_RATE_1M, 0), - RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(DOT11_RATE_6M, 0), - RATETAB_ENT(DOT11_RATE_9M, 0), - RATETAB_ENT(DOT11_RATE_12M, 0), - RATETAB_ENT(DOT11_RATE_18M, 0), - RATETAB_ENT(DOT11_RATE_24M, 0), - RATETAB_ENT(DOT11_RATE_36M, 0), - RATETAB_ENT(DOT11_RATE_48M, 0), - RATETAB_ENT(DOT11_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(144, 0), - CHAN5G(149, 0), CHAN5G(153, 0), - CHAN5G(157, 0), CHAN5G(161, 0), - CHAN5G(165, 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 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, -#ifdef BCMWAPI_WPI - WLAN_CIPHER_SUITE_SMS4, -#endif -#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK) - WLAN_CIPHER_SUITE_PMK, -#endif -}; - -#ifdef WL_SUPPORT_ACS -/* - * The firmware code required for this feature to work is currently under - * BCMINTERNAL flag. In future if this is to enabled we need to bring the - * required firmware code out of the BCMINTERNAL flag. - */ -struct wl_dump_survey { - u32 obss; - u32 ibss; - u32 no_ctg; - u32 no_pckt; - u32 tx; - u32 idle; -}; -#endif /* WL_SUPPORT_ACS */ - - -#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) -static int maxrxpktglom = 0; -#endif - -/* IOCtl version read from targeted driver */ -static int ioctl_version; -#ifdef DEBUGFS_CFG80211 -#define S_SUBLOGLEVEL 20 -static const struct { - u32 log_level; - char *sublogname; -} sublogname_map[] = { - {WL_DBG_ERR, "ERR"}, - {WL_DBG_INFO, "INFO"}, - {WL_DBG_DBG, "DBG"}, - {WL_DBG_SCAN, "SCAN"}, - {WL_DBG_TRACE, "TRACE"}, - {WL_DBG_P2P_ACTION, "P2PACTION"} -}; -#endif - - -static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg, bool add_remove, - enum wl_handler_del_type type) -{ - if (cfg == NULL) - return; - - if (cfg->pm_enable_work_on) { - if (add_remove) { - schedule_delayed_work(&cfg->pm_enable_work, - msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); - } else { - cancel_delayed_work_sync(&cfg->pm_enable_work); - switch (type) { - case WL_HANDLER_MAINTAIN: - schedule_delayed_work(&cfg->pm_enable_work, - msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); - break; - case WL_HANDLER_PEND: - schedule_delayed_work(&cfg->pm_enable_work, - msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT*2)); - break; - case WL_HANDLER_DEL: - default: - cfg->pm_enable_work_on = false; - break; - } - } - } -} - -/* Return a new chanspec given a legacy chanspec - * Returns INVCHANSPEC on error - */ -static chanspec_t -wl_chspec_from_legacy(chanspec_t legacy_chspec) -{ - chanspec_t chspec; - - /* get the channel number */ - chspec = LCHSPEC_CHANNEL(legacy_chspec); - - /* convert the band */ - if (LCHSPEC_IS2G(legacy_chspec)) { - chspec |= WL_CHANSPEC_BAND_2G; - } else { - chspec |= WL_CHANSPEC_BAND_5G; - } - - /* convert the bw and sideband */ - if (LCHSPEC_IS20(legacy_chspec)) { - chspec |= WL_CHANSPEC_BW_20; - } else { - chspec |= WL_CHANSPEC_BW_40; - if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { - chspec |= WL_CHANSPEC_CTL_SB_L; - } else { - chspec |= WL_CHANSPEC_CTL_SB_U; - } - } - - if (wf_chspec_malformed(chspec)) { - WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", - chspec)); - return INVCHANSPEC; - } - - return chspec; -} - -/* Return a legacy chanspec given a new chanspec - * Returns INVCHANSPEC on error - */ -static chanspec_t -wl_chspec_to_legacy(chanspec_t chspec) -{ - chanspec_t lchspec; - - if (wf_chspec_malformed(chspec)) { - WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", - chspec)); - return INVCHANSPEC; - } - - /* get the channel number */ - lchspec = CHSPEC_CHANNEL(chspec); - - /* convert the band */ - if (CHSPEC_IS2G(chspec)) { - lchspec |= WL_LCHANSPEC_BAND_2G; - } else { - lchspec |= WL_LCHANSPEC_BAND_5G; - } - - /* convert the bw and sideband */ - if (CHSPEC_IS20(chspec)) { - lchspec |= WL_LCHANSPEC_BW_20; - lchspec |= WL_LCHANSPEC_CTL_SB_NONE; - } else if (CHSPEC_IS40(chspec)) { - lchspec |= WL_LCHANSPEC_BW_40; - if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { - lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; - } else { - lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; - } - } else { - /* cannot express the bandwidth */ - char chanbuf[CHANSPEC_STR_LEN]; - WL_ERR(( - "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " - "to pre-11ac format\n", - wf_chspec_ntoa(chspec, chanbuf), chspec)); - return INVCHANSPEC; - } - - return lchspec; -} - -/* given a chanspec value, do the endian and chanspec version conversion to - * a chanspec_t value - * Returns INVCHANSPEC on error - */ -chanspec_t -wl_chspec_host_to_driver(chanspec_t chanspec) -{ - if (ioctl_version == 1) { - chanspec = wl_chspec_to_legacy(chanspec); - if (chanspec == INVCHANSPEC) { - return chanspec; - } - } - chanspec = htodchanspec(chanspec); - - return chanspec; -} - -/* given a channel value, do the endian and chanspec version conversion to - * a chanspec_t value - * Returns INVCHANSPEC on error - */ -chanspec_t -wl_ch_host_to_driver(u16 channel) -{ - - chanspec_t chanspec; - - chanspec = channel & WL_CHANSPEC_CHAN_MASK; - - if (channel <= 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; - - return wl_chspec_host_to_driver(chanspec); -} - -/* given a chanspec value from the driver, do the endian and chanspec version conversion to - * a chanspec_t value - * Returns INVCHANSPEC on error - */ -chanspec_t -wl_chspec_driver_to_host(chanspec_t chanspec) -{ - chanspec = dtohchanspec(chanspec); - if (ioctl_version == 1) { - chanspec = wl_chspec_from_legacy(chanspec); - } - - return chanspec; -} - -/* - * convert ASCII string to MAC address (colon-delimited format) - * eg: 00:11:22:33:44:55 - */ -int -wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n) -{ - char *c = NULL; - int count = 0; - - memset(n, 0, ETHER_ADDR_LEN); - for (;;) { - n->octet[count++] = (uint8)simple_strtoul(a, &c, 16); - if (!*c++ || count == ETHER_ADDR_LEN) - break; - a = c; - } - return (count == ETHER_ADDR_LEN); -} - -/* convert hex string buffer to binary */ -int -wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str) -{ - int count, slen; - int hvalue; - char tmp[3] = {0}; - char *ptr = str, *endp = NULL; - - if (!data || !str || !dlen) { - WL_DBG((" passed buffer is empty \n")); - return 0; - } - - slen = strlen(str); - if (dlen * 2 < slen) { - WL_DBG((" destination buffer too short \n")); - return 0; - } - - if (slen % 2) { - WL_DBG((" source buffer is of odd length \n")); - return 0; - } - - for (count = 0; count < slen; count += 2) { - memcpy(tmp, ptr, 2); - hvalue = simple_strtol(tmp, &endp, 16); - if (*endp != '\0') { - WL_DBG((" non hexadecimal character encountered \n")); - return 0; - } - *data++ = (unsigned char)hvalue; - ptr += 2; - } - - return (slen / 2); -} - -/* There isn't a lot of sense in it, but you can transmit anything you like */ -static const struct ieee80211_txrx_stypes -wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { - [NL80211_IFTYPE_ADHOC] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) - }, - [NL80211_IFTYPE_STATION] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, - [NL80211_IFTYPE_AP] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | - BIT(IEEE80211_STYPE_DISASSOC >> 4) | - BIT(IEEE80211_STYPE_AUTH >> 4) | - BIT(IEEE80211_STYPE_DEAUTH >> 4) | - BIT(IEEE80211_STYPE_ACTION >> 4) - }, - [NL80211_IFTYPE_AP_VLAN] = { - /* copy AP */ - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | - BIT(IEEE80211_STYPE_DISASSOC >> 4) | - BIT(IEEE80211_STYPE_AUTH >> 4) | - BIT(IEEE80211_STYPE_DEAUTH >> 4) | - BIT(IEEE80211_STYPE_ACTION >> 4) - }, - [NL80211_IFTYPE_P2P_CLIENT] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, - [NL80211_IFTYPE_P2P_GO] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | - BIT(IEEE80211_STYPE_DISASSOC >> 4) | - BIT(IEEE80211_STYPE_AUTH >> 4) | - BIT(IEEE80211_STYPE_DEAUTH >> 4) | - BIT(IEEE80211_STYPE_ACTION >> 4) - }, -#if defined(WL_CFG80211_P2P_DEV_IF) - [NL80211_IFTYPE_P2P_DEVICE] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, -#endif /* WL_CFG80211_P2P_DEV_IF */ -}; - -static void swap_key_from_BE(struct wl_wsec_key *key) -{ - key->index = htod32(key->index); - key->len = htod32(key->len); - key->algo = htod32(key->algo); - key->flags = htod32(key->flags); - key->rxiv.hi = htod32(key->rxiv.hi); - key->rxiv.lo = htod16(key->rxiv.lo); - key->iv_initialized = htod32(key->iv_initialized); -} - -static void swap_key_to_BE(struct wl_wsec_key *key) -{ - key->index = dtoh32(key->index); - key->len = dtoh32(key->len); - key->algo = dtoh32(key->algo); - key->flags = dtoh32(key->flags); - key->rxiv.hi = dtoh32(key->rxiv.hi); - key->rxiv.lo = dtoh16(key->rxiv.lo); - key->iv_initialized = dtoh32(key->iv_initialized); -} - -/* Dump the contents of the encoded wps ie buffer and get pbc value */ -static void -wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) -{ - #define WPS_IE_FIXED_LEN 6 - u16 len; - u8 *subel = NULL; - u16 subelt_id; - u16 subelt_len; - u16 val; - u8 *valptr = (uint8*) &val; - if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) { - WL_ERR(("invalid argument : NULL\n")); - return; - } - len = (u16)wps_ie[TLV_LEN_OFF]; - - if (len > wps_ie_len) { - WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len)); - return; - } - WL_DBG(("wps_ie len=%d\n", len)); - len -= 4; /* for the WPS IE's OUI, oui_type fields */ - subel = wps_ie + WPS_IE_FIXED_LEN; - while (len >= 4) { /* must have attr id, attr len fields */ - valptr[0] = *subel++; - valptr[1] = *subel++; - subelt_id = HTON16(val); - - valptr[0] = *subel++; - valptr[1] = *subel++; - subelt_len = HTON16(val); - - len -= 4; /* for the attr id, attr len fields */ - - if (len < subelt_len) { - WL_ERR(("not enough data, len %d, subelt_len %d\n", len, - subelt_len)); - break; - } - len -= subelt_len; /* for the remaining fields in this attribute */ - - WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n", - subel, subelt_id, subelt_len)); - - if (subelt_id == WPS_ID_VERSION) { - WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel)); - } else if (subelt_id == WPS_ID_REQ_TYPE) { - WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel)); - } else if (subelt_id == WPS_ID_CONFIG_METHODS) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val))); - } else if (subelt_id == WPS_ID_DEVICE_NAME) { - char devname[100]; - int namelen = MIN(subelt_len, (sizeof(devname) - 1)); - - if (namelen) { - memcpy(devname, subel, namelen); - devname[namelen] = '\0'; - /* Printing len as rx'ed in the IE */ - WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n", - devname, subelt_len)); - } - } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val))); - *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false; - } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val))); - valptr[0] = *(subel + 6); - valptr[1] = *(subel + 7); - WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val))); - } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val))); - valptr[0] = *(subel + 6); - valptr[1] = *(subel + 7); - WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val))); - } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS" - ": cat=%u\n", HTON16(val))); - } else { - WL_DBG((" unknown attr 0x%x\n", subelt_id)); - } - - subel += subelt_len; - } -} - -s32 wl_set_tx_power(struct net_device *dev, - enum nl80211_tx_power_setting type, s32 dbm) -{ - s32 err = 0; - s32 disable = 0; - s32 txpwrqdbm; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - /* Make sure radio is off or on as far as software is concerned */ - disable = WL_RADIO_SW_DISABLE << 16; - disable = htod32(disable); - err = wldev_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable), true); - if (unlikely(err)) { - WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); - return err; - } - - if (dbm > 0xffff) - dbm = 0xffff; - txpwrqdbm = dbm * 4; -#ifdef SUPPORT_WL_TXPOWER - if (type == NL80211_TX_POWER_AUTOMATIC) - txpwrqdbm = 127; - else - txpwrqdbm |= WL_TXPWR_OVERRIDE; -#endif /* SUPPORT_WL_TXPOWER */ - err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm, - sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, - &cfg->ioctl_buf_sync); - if (unlikely(err)) - WL_ERR(("qtxpower error (%d)\n", err)); - else - WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm)); - - return err; -} - -s32 wl_get_tx_power(struct net_device *dev, s32 *dbm) -{ - s32 err = 0; - s32 txpwrdbm; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower", - NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - - memcpy(&txpwrdbm, cfg->ioctl_buf, sizeof(txpwrdbm)); - txpwrdbm = dtoh32(txpwrdbm); - *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4; - - WL_INFORM(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm)); - - return err; -} - -static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) -{ - chanspec_t chspec; - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - struct ether_addr bssid; - struct wl_bss_info *bss = NULL; - - if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { - /* STA interface is not associated. So start the new interface on a temp - * channel . Later proper channel will be applied by the above framework - * via set_channel (cfg80211 API). - */ - WL_DBG(("Not associated. Return a temp channel. \n")); - return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); - } - - - *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX); - if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, cfg->extra_buf, - WL_EXTRA_BUF_MAX, false))) { - WL_ERR(("Failed to get associated bss info, use temp channel \n")); - chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); - } - else { - bss = (struct wl_bss_info *) (cfg->extra_buf + 4); - chspec = bss->chanspec; - - WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec)); - } - return chspec; -} - -static bcm_struct_cfgdev * -wl_cfg80211_add_monitor_if(char *name) -{ -#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) - WL_INFORM(("wl_cfg80211_add_monitor_if: No more support monitor interface\n")); - return ERR_PTR(-EOPNOTSUPP); -#else - struct net_device* ndev = NULL; - - dhd_add_monitor(name, &ndev); - WL_INFORM(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); - return ndev_to_cfgdev(ndev); -#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */ -} - -static bcm_struct_cfgdev * -wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, -#if defined(WL_CFG80211_P2P_DEV_IF) - const char *name, -#else - char *name, -#endif /* WL_CFG80211_P2P_DEV_IF */ - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) -{ - s32 err; - s32 timeout = -1; - s32 wlif_type = -1; - s32 mode = 0; - s32 val = 0; - s32 dhd_mode = 0; - chanspec_t chspec; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *primary_ndev; - struct net_device *new_ndev; - struct ether_addr primary_mac; -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - s32 up = 1; - dhd_pub_t *dhd; - bool enabled; -#endif -#endif /* PROP_TXSTATUS_VSDB */ - - if (!cfg) - return ERR_PTR(-EINVAL); - -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - dhd = (dhd_pub_t *)(cfg->pub); -#endif -#endif /* PROP_TXSTATUS_VSDB */ - - /* Use primary I/F for sending cmds down to firmware */ - primary_ndev = bcmcfg_to_prmry_ndev(cfg); - - if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) { - WL_ERR(("device is not ready\n")); - return ERR_PTR(-ENODEV); - } - - WL_DBG(("if name: %s, type: %d\n", name, type)); - switch (type) { - case NL80211_IFTYPE_ADHOC: -#ifdef WLAIBSS_MCHAN - return bcm_cfg80211_add_ibss_if(wiphy, (char *)name); -#endif /* WLAIBSS_MCHAN */ - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MESH_POINT: - WL_ERR(("Unsupported interface type\n")); - mode = WL_MODE_IBSS; - return NULL; - case NL80211_IFTYPE_MONITOR: - return wl_cfg80211_add_monitor_if((char *)name); -#if defined(WL_CFG80211_P2P_DEV_IF) - case NL80211_IFTYPE_P2P_DEVICE: - return wl_cfgp2p_add_p2p_disc_if(cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ - case NL80211_IFTYPE_STATION: -#ifdef DUAL_STA -#ifdef WLAIBSS_MCHAN - if (cfg->ibss_cfgdev) { - WL_ERR(("AIBSS is already operational. " - " AIBSS & DUALSTA can't be used together \n")); - return NULL; - } -#endif /* WLAIBSS_MCHAN */ - if (!name) { - WL_ERR(("Interface name not provided \n")); - return NULL; - } - return wl_cfg80211_create_iface(cfg->wdev->wiphy, - NL80211_IFTYPE_STATION, NULL, name); -#endif /* DUAL_STA */ - case NL80211_IFTYPE_P2P_CLIENT: - wlif_type = WL_P2P_IF_CLIENT; - mode = WL_MODE_BSS; - break; - case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_AP: - wlif_type = WL_P2P_IF_GO; - mode = WL_MODE_AP; - break; - default: - WL_ERR(("Unsupported interface type\n")); - return NULL; - break; - } - - if (!name) { - WL_ERR(("name is NULL\n")); - return NULL; - } - if (cfg->p2p_supported && (wlif_type != -1)) { - ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */ - -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - if (!dhd) - return ERR_PTR(-ENODEV); -#endif -#endif /* PROP_TXSTATUS_VSDB */ - if (!cfg->p2p) - return ERR_PTR(-ENODEV); - - if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { - p2p_on(cfg) = true; - wl_cfgp2p_set_firm_p2p(cfg); - wl_cfgp2p_init_discovery(cfg); - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, - &cfg->p2p->dev_addr, &cfg->p2p->int_addr); - } - - memset(cfg->p2p->vir_ifname, 0, IFNAMSIZ); - strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1); - - wl_cfg80211_scan_abort(cfg); -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - if (!cfg->wlfc_on && !disable_proptx) { - dhd_wlfc_get_enable(dhd, &enabled); - if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) { - dhd_wlfc_init(dhd); - err = wldev_ioctl(primary_ndev, WLC_UP, &up, sizeof(s32), true); - if (err < 0) - WL_ERR(("WLC_UP return err:%d\n", err)); - } - cfg->wlfc_on = true; - } -#endif -#endif /* PROP_TXSTATUS_VSDB */ - - /* In concurrency case, STA may be already associated in a particular channel. - * so retrieve the current channel of primary interface and then start the virtual - * interface on that. - */ - chspec = wl_cfg80211_get_shared_freq(wiphy); - - /* For P2P mode, use P2P-specific driver features to create the - * bss: "cfg p2p_ifadd" - */ - wl_set_p2p_status(cfg, IF_ADDING); - memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); - if (wlif_type == WL_P2P_IF_GO) - wldev_iovar_setint(primary_ndev, "mpc", 0); - err = wl_cfgp2p_ifadd(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec); - if (unlikely(err)) { - wl_clr_p2p_status(cfg, IF_ADDING); - WL_ERR((" virtual iface add failed (%d) \n", err)); - return ERR_PTR(-ENOMEM); - } - - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - (wl_get_p2p_status(cfg, IF_ADDING) == false), - msecs_to_jiffies(MAX_WAIT_TIME)); - - if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) { - struct wireless_dev *vwdev; - int pm_mode = PM_ENABLE; - wl_if_event_info *event = &cfg->if_event_info; - - /* IF_ADD event has come back, we can proceed to to register - * the new interface now, use the interface name provided by caller (thus - * ignore the one from wlc) - */ - strncpy(cfg->if_event_info.name, name, IFNAMSIZ - 1); - new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname, - event->mac, event->bssidx); - if (new_ndev == NULL) - goto fail; - - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = new_ndev; - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = event->bssidx; - vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); - if (unlikely(!vwdev)) { - WL_ERR(("Could not allocate wireless device\n")); - goto fail; - } - vwdev->wiphy = cfg->wdev->wiphy; - WL_INFORM(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname)); - vwdev->iftype = type; - vwdev->netdev = new_ndev; - new_ndev->ieee80211_ptr = vwdev; - SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy)); - wl_set_drv_status(cfg, READY, new_ndev); - cfg->p2p->vif_created = true; - wl_set_mode_by_netdev(cfg, new_ndev, mode); - - if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) { - wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev); - goto fail; - } - wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode); - val = 1; - /* Disable firmware roaming for P2P interface */ - wldev_iovar_setint(new_ndev, "roam_off", val); - - if (mode != WL_MODE_AP) - wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1); - - WL_ERR((" virtual interface(%s) is " - "created net attach done\n", cfg->p2p->vir_ifname)); - if (mode == WL_MODE_AP) - wl_set_drv_status(cfg, CONNECTED, new_ndev); - if (type == NL80211_IFTYPE_P2P_CLIENT) - dhd_mode = DHD_FLAG_P2P_GC_MODE; - else if (type == NL80211_IFTYPE_P2P_GO) - dhd_mode = DHD_FLAG_P2P_GO_MODE; - DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode)); - /* reinitialize completion to clear previous count */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) - INIT_COMPLETION(cfg->iface_disable); -#else - init_completion(&cfg->iface_disable); -#endif - return ndev_to_cfgdev(new_ndev); - } else { - wl_clr_p2p_status(cfg, IF_ADDING); - WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname)); - - WL_ERR(("left timeout : %d\n", timeout)); - WL_ERR(("IF_ADDING status : %d\n", wl_get_p2p_status(cfg, IF_ADDING))); - WL_ERR(("event valid : %d\n", cfg->if_event_info.valid)); - - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - wl_set_p2p_status(cfg, IF_DELETING); - - err = wl_cfgp2p_ifdel(cfg, &cfg->p2p->int_addr); - if (err == BCME_OK) { - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - (wl_get_p2p_status(cfg, IF_DELETING) == false), - msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) && - cfg->if_event_info.valid) { - WL_ERR(("IFDEL operation done\n")); - } else { - WL_ERR(("IFDEL didn't complete properly\n")); - err = BCME_ERROR; - } - } - if (err != BCME_OK) { - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - - WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n", - err, ndev->name)); - #ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(((dhd_pub_t *)(cfg->pub))->crash_reason, - "p2p_ifdel failed, error %d, sent HANG event to %s\n", - err, ndev->name); - #endif /* CONFIG_BCM_WLAN_RAMDUMP */ - net_os_send_hang_message(ndev); - } - - memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ); - cfg->p2p->vif_created = false; -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - dhd_wlfc_get_enable(dhd, &enabled); - if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) { - dhd_wlfc_deinit(dhd); - cfg->wlfc_on = false; - } -#endif -#endif /* PROP_TXSTATUS_VSDB */ - } - } - -fail: - if (wlif_type == WL_P2P_IF_GO) - wldev_iovar_setint(primary_ndev, "mpc", 1); - return ERR_PTR(-ENODEV); -} - -static s32 -wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) -{ - struct net_device *dev = NULL; - struct ether_addr p2p_mac; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 timeout = -1; - s32 ret = 0; - s32 index = -1; -#ifdef CUSTOM_SET_CPUCORE - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif /* CUSTOM_SET_CPUCORE */ - WL_DBG(("Enter\n")); - -#ifdef CUSTOM_SET_CPUCORE - dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE; - if (!(dhd->chan_isvht80)) - dhd_set_cpucore(dhd, FALSE); -#endif /* CUSTOM_SET_CPUCORE */ -#if defined(WL_CFG80211_P2P_DEV_IF) - if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { - return wl_cfgp2p_del_p2p_disc_if(cfgdev, cfg); - } -#endif /* WL_CFG80211_P2P_DEV_IF */ - dev = cfgdev_to_wlc_ndev(cfgdev, cfg); - -#ifdef WLAIBSS_MCHAN - if (cfgdev == cfg->ibss_cfgdev) - return bcm_cfg80211_del_ibss_if(wiphy, cfgdev); -#endif /* WLAIBSS_MCHAN */ - -#ifdef DUAL_STA - if (cfgdev == cfg->bss_cfgdev) - return wl_cfg80211_del_iface(wiphy, cfgdev); -#endif /* DUAL_STA */ - - if (wl_cfgp2p_find_idx(cfg, dev, &index) != BCME_OK) { - WL_ERR(("Find p2p index from ndev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (cfg->p2p_supported) { - memcpy(p2p_mac.octet, cfg->p2p->int_addr.octet, ETHER_ADDR_LEN); - - /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases - */ - WL_DBG(("P2P: GO_NEG_PHASE status cleared ")); - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - if (cfg->p2p->vif_created) { - if (wl_get_drv_status(cfg, SCANNING, dev)) { - wl_notify_escan_complete(cfg, dev, true, true); - } - wldev_iovar_setint(dev, "mpc", 1); - /* Delete pm_enable_work */ - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - - /* for GC */ - if (wl_get_drv_status(cfg, DISCONNECTING, dev) && - (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)) { - WL_ERR(("Wait for Link Down event for GC !\n")); - wait_for_completion_timeout - (&cfg->iface_disable, msecs_to_jiffies(500)); - } - - memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); - wl_set_p2p_status(cfg, IF_DELETING); - DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg)); - - /* for GO */ - if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); - /* disable interface before bsscfg free */ - ret = wl_cfgp2p_ifdisable(cfg, &p2p_mac); - /* if fw doesn't support "ifdis", - do not wait for link down of ap mode - */ - if (ret == 0) { - WL_ERR(("Wait for Link Down event for GO !!!\n")); - wait_for_completion_timeout(&cfg->iface_disable, - msecs_to_jiffies(500)); - } else if (ret != BCME_UNSUPPORTED) { - msleep(300); - } - } - wl_cfgp2p_clear_management_ie(cfg, index); - - if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) - wldev_iovar_setint(dev, "buf_key_b4_m4", 0); - - /* delete interface after link down */ - ret = wl_cfgp2p_ifdel(cfg, &p2p_mac); - - if (ret != BCME_OK) { - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - - WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n", - ret, ndev->name)); - #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID) - #ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(((dhd_pub_t *)(cfg->pub))->crash_reason, - ("p2p_ifdel failed, error %d, sent HANG event to %s\n", - ret, ndev->name); - #endif /* CONFIG_BCM_WLAN_RAMDUMP */ - net_os_send_hang_message(ndev); - #endif - } else { - /* Wait for IF_DEL operation to be finished */ - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - (wl_get_p2p_status(cfg, IF_DELETING) == false), - msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) && - cfg->if_event_info.valid) { - - WL_DBG(("IFDEL operation done\n")); - wl_cfg80211_handle_ifdel(cfg, &cfg->if_event_info, dev); - } else { - WL_ERR(("IFDEL didn't complete properly\n")); - } - } - - ret = dhd_del_monitor(dev); - if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL((dhd_pub_t *)(cfg->pub)); - } - } - } - return ret; -} - -static s32 -wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) -{ - s32 ap = 0; - s32 infra = 0; - s32 ibss = 0; - s32 wlif_type; - s32 mode = 0; - s32 err = BCME_OK; - chanspec_t chspec; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - - WL_DBG(("Enter type %d\n", type)); - switch (type) { - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MESH_POINT: - ap = 1; - WL_ERR(("type (%d) : currently we do not support this type\n", - type)); - break; - case NL80211_IFTYPE_ADHOC: - mode = WL_MODE_IBSS; - ibss = 1; - break; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - mode = WL_MODE_BSS; - infra = 1; - break; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_P2P_GO: - mode = WL_MODE_AP; - ap = 1; - break; - default: - return -EINVAL; - } - if (!dhd) - return -EINVAL; - if (ap) { - wl_set_mode_by_netdev(cfg, ndev, mode); - if (cfg->p2p_supported && cfg->p2p->vif_created) { - WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", cfg->p2p->vif_created, - p2p_on(cfg))); - wldev_iovar_setint(ndev, "mpc", 0); - wl_notify_escan_complete(cfg, ndev, true, true); - - /* In concurrency case, STA may be already associated in a particular - * channel. so retrieve the current channel of primary interface and - * then start the virtual interface on that. - */ - chspec = wl_cfg80211_get_shared_freq(wiphy); - - wlif_type = WL_P2P_IF_GO; - WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", - ndev->name, ap, infra, type)); - wl_set_p2p_status(cfg, IF_CHANGING); - wl_clr_p2p_status(cfg, IF_CHANGED); - wl_cfgp2p_ifchange(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec); - wait_event_interruptible_timeout(cfg->netif_change_event, - (wl_get_p2p_status(cfg, IF_CHANGED) == true), - msecs_to_jiffies(MAX_WAIT_TIME)); - wl_set_mode_by_netdev(cfg, ndev, mode); - dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE; - dhd->op_mode |= DHD_FLAG_P2P_GO_MODE; - wl_clr_p2p_status(cfg, IF_CHANGING); - wl_clr_p2p_status(cfg, IF_CHANGED); - if (mode == WL_MODE_AP) - wl_set_drv_status(cfg, CONNECTED, ndev); - } else if (ndev == bcmcfg_to_prmry_ndev(cfg) && - !wl_get_drv_status(cfg, AP_CREATED, ndev)) { - wl_set_drv_status(cfg, AP_CREATING, ndev); - if (!cfg->ap_info && - !(cfg->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) { - WL_ERR(("struct ap_saved_ie allocation failed\n")); - return -ENOMEM; - } - } else { - WL_ERR(("Cannot change the interface for GO or SOFTAP\n")); - return -EINVAL; - } - } else { - WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA")); - } - - if (ibss) { - infra = 0; - wl_set_mode_by_netdev(cfg, ndev, mode); - err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET Adhoc error %d\n", err)); - return -EINVAL; - } - } - - ndev->ieee80211_ptr->iftype = type; - return 0; -} - -s32 -wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx) -{ - bool ifadd_expected = FALSE; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd") - * redirect the IF_ADD event to ifchange as it is not a real "new" interface - */ - if (wl_get_p2p_status(cfg, IF_CHANGING)) - return wl_cfg80211_notify_ifchange(ifidx, name, mac, bssidx); - - /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */ - if (wl_get_p2p_status(cfg, IF_ADDING)) { - ifadd_expected = TRUE; - wl_clr_p2p_status(cfg, IF_ADDING); - } else if (cfg->bss_pending_op) { - ifadd_expected = TRUE; - cfg->bss_pending_op = FALSE; - } - - if (ifadd_expected) { - wl_if_event_info *if_event_info = &cfg->if_event_info; - - if_event_info->valid = TRUE; - if_event_info->ifidx = ifidx; - if_event_info->bssidx = bssidx; - strncpy(if_event_info->name, name, IFNAMSIZ); - if_event_info->name[IFNAMSIZ] = '\0'; - if (mac) - memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN); - wake_up_interruptible(&cfg->netif_change_event); - return BCME_OK; - } - - return BCME_ERROR; -} - -s32 -wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx) -{ - bool ifdel_expected = FALSE; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - wl_if_event_info *if_event_info = &cfg->if_event_info; - - if (wl_get_p2p_status(cfg, IF_DELETING)) { - ifdel_expected = TRUE; - wl_clr_p2p_status(cfg, IF_DELETING); - } else if (cfg->bss_pending_op) { - ifdel_expected = TRUE; - cfg->bss_pending_op = FALSE; - } - - if (ifdel_expected) { - if_event_info->valid = TRUE; - if_event_info->ifidx = ifidx; - if_event_info->bssidx = bssidx; - wake_up_interruptible(&cfg->netif_change_event); - return BCME_OK; - } - - return BCME_ERROR; -} - -s32 -wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - if (wl_get_p2p_status(cfg, IF_CHANGING)) { - wl_set_p2p_status(cfg, IF_CHANGED); - wake_up_interruptible(&cfg->netif_change_event); - return BCME_OK; - } - - return BCME_ERROR; -} - -static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info, - struct net_device* ndev) -{ - s32 type = -1; - s32 bssidx = -1; -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - bool enabled; -#endif -#endif /* PROP_TXSTATUS_VSDB */ - - bssidx = if_event_info->bssidx; - if (bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION)) { - WL_ERR(("got IF_DEL for if %d, not owned by cfg driver\n", bssidx)); - return BCME_ERROR; - } - - if (p2p_is_on(cfg) && cfg->p2p->vif_created) { - - if (cfg->scan_request && (cfg->escan_info.ndev == ndev)) { - /* Abort any pending scan requests */ - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - WL_DBG(("ESCAN COMPLETED\n")); - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, false); - } - - memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ); - if (wl_cfgp2p_find_type(cfg, bssidx, &type) != BCME_OK) { - WL_ERR(("Find p2p type from bssidx(%d) failed\n", bssidx)); - return BCME_ERROR; - } - wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, type)); - wl_to_p2p_bss_ndev(cfg, type) = NULL; - wl_to_p2p_bss_bssidx(cfg, type) = WL_INVALID; - cfg->p2p->vif_created = false; - -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - dhd_wlfc_get_enable(dhd, &enabled); - if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) { - dhd_wlfc_deinit(dhd); - cfg->wlfc_on = false; - } -#endif -#endif /* PROP_TXSTATUS_VSDB */ - } - - wl_cfg80211_remove_if(cfg, if_event_info->ifidx, ndev); - return BCME_OK; -} - -/* Find listen channel */ -static s32 wl_find_listen_channel(struct bcm_cfg80211 *cfg, - const u8 *ie, u32 ie_len) -{ - wifi_p2p_ie_t *p2p_ie; - u8 *end, *pos; - s32 listen_channel; - - pos = (u8 *)ie; - p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len); - - if (p2p_ie == NULL) - return 0; - - pos = p2p_ie->subelts; - end = p2p_ie->subelts + (p2p_ie->len - 4); - - CFGP2P_DBG((" found p2p ie ! lenth %d \n", - p2p_ie->len)); - - while (pos < end) { - uint16 attr_len; - if (pos + 2 >= end) { - CFGP2P_DBG((" -- Invalid P2P attribute")); - return 0; - } - attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0])); - - if (pos + 3 + attr_len > end) { - CFGP2P_DBG(("P2P: Attribute underflow " - "(len=%u left=%d)", - attr_len, (int) (end - pos - 3))); - return 0; - } - - /* if Listen Channel att id is 6 and the vailue is valid, - * return the listen channel - */ - if (pos[0] == 6) { - /* listen channel subel length format - * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num) - */ - listen_channel = pos[1 + 2 + 3 + 1]; - - if (listen_channel == SOCIAL_CHAN_1 || - listen_channel == SOCIAL_CHAN_2 || - listen_channel == SOCIAL_CHAN_3) { - CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel)); - return listen_channel; - } - } - pos += 3 + attr_len; - } - return 0; -} - -static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) -{ - u32 n_ssids; - u32 n_channels; - u16 channel; - chanspec_t chanspec; - s32 i = 0, j = 0, offset; - char *ptr; - wlc_ssid_t ssid; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); - params->bss_type = DOT11_BSSTYPE_ANY; - params->scan_type = 0; - params->nprobes = -1; - params->active_time = -1; - params->passive_time = -1; - params->home_time = -1; - params->channel_num = 0; - memset(¶ms->ssid, 0, sizeof(wlc_ssid_t)); - - WL_SCAN(("Preparing Scan request\n")); - WL_SCAN(("nprobes=%d\n", params->nprobes)); - WL_SCAN(("active_time=%d\n", params->active_time)); - WL_SCAN(("passive_time=%d\n", params->passive_time)); - WL_SCAN(("home_time=%d\n", params->home_time)); - WL_SCAN(("scan_type=%d\n", params->scan_type)); - - params->nprobes = htod32(params->nprobes); - params->active_time = htod32(params->active_time); - params->passive_time = htod32(params->passive_time); - params->home_time = htod32(params->home_time); - - /* if request is null just exit so it will be all channel broadcast scan */ - if (!request) - return; - - n_ssids = request->n_ssids; - n_channels = request->n_channels; - - /* Copy channel array if applicable */ - WL_SCAN(("### List of channelspecs to scan ###\n")); - if (n_channels > 0) { - for (i = 0; i < n_channels; i++) { - chanspec = 0; - channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); - /* SKIP DFS channels for Secondary interface */ - if ((cfg->escan_info.ndev != bcmcfg_to_prmry_ndev(cfg)) && - (request->channels[i]->flags & -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) - (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) -#else - (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR))) -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */ - continue; - - if (request->channels[i]->band == IEEE80211_BAND_2GHZ) { -#ifdef WL_HOST_BAND_MGMT - if (cfg->curr_band == WLC_BAND_5G) { - WL_DBG(("In 5G only mode, omit 2G channel:%d\n", channel)); - continue; - } -#endif /* WL_HOST_BAND_MGMT */ - chanspec |= WL_CHANSPEC_BAND_2G; - } else { -#ifdef WL_HOST_BAND_MGMT - if (cfg->curr_band == WLC_BAND_2G) { - WL_DBG(("In 2G only mode, omit 5G channel:%d\n", channel)); - continue; - } -#endif /* WL_HOST_BAND_MGMT */ - chanspec |= WL_CHANSPEC_BAND_5G; - } - - chanspec |= WL_CHANSPEC_BW_20; - chanspec |= WL_CHANSPEC_CTL_SB_NONE; - - params->channel_list[j] = channel; - params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK; - params->channel_list[j] |= chanspec; - WL_SCAN(("Chan : %d, Channel spec: %x \n", - channel, params->channel_list[j])); - params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]); - j++; - } - } else { - WL_SCAN(("Scanning all channels\n")); - } - n_channels = j; - /* Copy ssid array if applicable */ - WL_SCAN(("### List of SSIDs to scan ###\n")); - if (n_ssids > 0) { - offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); - offset = roundup(offset, sizeof(u32)); - ptr = (char*)params + offset; - for (i = 0; i < n_ssids; i++) { - memset(&ssid, 0, sizeof(wlc_ssid_t)); - ssid.SSID_len = MIN(request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN); - memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); - if (!ssid.SSID_len) - WL_SCAN(("%d: Broadcast scan\n", i)); - else - WL_SCAN(("%d: scan for %s size =%d\n", i, - ssid.SSID, ssid.SSID_len)); - memcpy(ptr, &ssid, sizeof(wlc_ssid_t)); - ptr += sizeof(wlc_ssid_t); - } - } else { - WL_SCAN(("Broadcast scan\n")); - } - /* Adding mask to channel numbers */ - params->channel_num = - htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | - (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); - - if (n_channels == 1) { - params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); - params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS); - } -} - -static s32 -wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) -{ - wl_uint32_list_t *list; - s32 err = BCME_OK; - if (valid_chan_list == NULL || size <= 0) - return -ENOMEM; - - memset(valid_chan_list, 0, size); - list = (wl_uint32_list_t *)(void *) valid_chan_list; - list->count = htod32(WL_NUMCHANNELS); - err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false); - if (err != 0) { - WL_ERR(("get channels failed with %d\n", err)); - } - - return err; -} - -#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) -#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40 -bool g_first_broadcast_scan = TRUE; -#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ - -static s32 -wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, - struct cfg80211_scan_request *request, uint16 action) -{ - s32 err = BCME_OK; - u32 n_channels; - u32 n_ssids; - s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); - wl_escan_params_t *params = NULL; - u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS)]; - u32 num_chans = 0; - s32 channel; - s32 n_valid_chan; - s32 search_state = WL_P2P_DISC_ST_SCAN; - u32 i, j, n_nodfs = 0; - u16 *default_chan_list = NULL; - wl_uint32_list_t *list; - struct net_device *dev = NULL; -#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) - bool is_first_init_2g_scan = false; -#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ - p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN; - - WL_DBG(("Enter \n")); - - /* scan request can come with empty request : perform all default scan */ - if (!cfg) { - err = -EINVAL; - goto exit; - } - if (!cfg->p2p_supported || !p2p_scan(cfg)) { - /* LEGACY SCAN TRIGGER */ - WL_SCAN((" LEGACY E-SCAN START\n")); - -#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) - if (!request) { - err = -EINVAL; - goto exit; - } - if (ndev == bcmcfg_to_prmry_ndev(cfg) && g_first_broadcast_scan == true) { -#ifdef USE_INITIAL_2G_SCAN - struct ieee80211_channel tmp_channel_list[CH_MAX_2G_CHANNEL]; - /* allow one 5G channel to add previous connected channel in 5G */ - bool allow_one_5g_channel = TRUE; - j = 0; - for (i = 0; i < request->n_channels; i++) { - int tmp_chan = ieee80211_frequency_to_channel - (request->channels[i]->center_freq); - if (tmp_chan > CH_MAX_2G_CHANNEL) { - if (allow_one_5g_channel) - allow_one_5g_channel = FALSE; - else - continue; - } - if (j > CH_MAX_2G_CHANNEL) { - WL_ERR(("Index %d exceeds max 2.4GHz channels %d" - " and previous 5G connected channel\n", - j, CH_MAX_2G_CHANNEL)); - break; - } - bcopy(request->channels[i], &tmp_channel_list[j], - sizeof(struct ieee80211_channel)); - WL_SCAN(("channel of request->channels[%d]=%d\n", i, tmp_chan)); - j++; - } - if ((j > 0) && (j <= CH_MAX_2G_CHANNEL)) { - for (i = 0; i < j; i++) - bcopy(&tmp_channel_list[i], request->channels[i], - sizeof(struct ieee80211_channel)); - - request->n_channels = j; - is_first_init_2g_scan = true; - } - else - WL_ERR(("Invalid number of 2.4GHz channels %d\n", j)); - - WL_SCAN(("request->n_channels=%d\n", request->n_channels)); -#else /* USE_INITIAL_SHORT_DWELL_TIME */ - is_first_init_2g_scan = true; -#endif /* USE_INITIAL_2G_SCAN */ - g_first_broadcast_scan = false; - } -#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ - - /* if scan request is not empty parse scan request paramters */ - if (request != NULL) { - n_channels = request->n_channels; - n_ssids = request->n_ssids; - if (n_channels % 2) - /* If n_channels is odd, add a padd of u16 */ - params_size += sizeof(u16) * (n_channels + 1); - else - params_size += sizeof(u16) * n_channels; - - /* Allocate space for populating ssids in wl_escan_params_t struct */ - params_size += sizeof(struct wlc_ssid) * n_ssids; - } - params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); - if (params == NULL) { - err = -ENOMEM; - goto exit; - } - wl_scan_prep(¶ms->params, request); - -#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) - /* Override active_time to reduce scan time if it's first bradcast scan. */ - if (is_first_init_2g_scan) - params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; -#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ - - params->version = htod32(ESCAN_REQ_VERSION); - params->action = htod16(action); - wl_escan_set_sync_id(params->sync_id, cfg); - wl_escan_set_type(cfg, WL_SCANTYPE_LEGACY); - if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { - WL_ERR(("ioctl buffer length not sufficient\n")); - kfree(params); - err = -ENOMEM; - goto exit; - } - err = wldev_iovar_setbuf(ndev, "escan", params, params_size, - cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(err)) { - if (err == BCME_EPERM) - /* Scan Not permitted at this point of time */ - WL_DBG((" Escan not permitted at this time (%d)\n", err)); - else - WL_ERR((" Escan set error (%d)\n", err)); - } - kfree(params); - } - else if (p2p_is_on(cfg) && p2p_scan(cfg)) { - /* P2P SCAN TRIGGER */ - s32 _freq = 0; - n_nodfs = 0; - if (request && request->n_channels) { - num_chans = request->n_channels; - WL_SCAN((" chann number : %d\n", num_chans)); - default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), - GFP_KERNEL); - if (default_chan_list == NULL) { - WL_ERR(("channel list allocation failed \n")); - err = -ENOMEM; - goto exit; - } - if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { - list = (wl_uint32_list_t *) chan_buf; - n_valid_chan = dtoh32(list->count); - - if (n_valid_chan > WL_NUMCHANNELS) { - WL_ERR(("wrong n_valid_chan:%d\n", - n_valid_chan)); - kfree(default_chan_list); - err = -EINVAL; - goto exit; - } - - for (i = 0; i < num_chans; i++) - { -#ifdef WL_HOST_BAND_MGMT - int channel_band = 0; -#endif /* WL_HOST_BAND_MGMT */ - _freq = request->channels[i]->center_freq; - channel = ieee80211_frequency_to_channel(_freq); -#ifdef WL_HOST_BAND_MGMT - channel_band = (channel > CH_MAX_2G_CHANNEL) ? - WLC_BAND_5G : WLC_BAND_2G; - if ((cfg->curr_band != WLC_BAND_AUTO) && - (cfg->curr_band != channel_band) && - !IS_P2P_SOCIAL_CHANNEL(channel)) - continue; -#endif /* WL_HOST_BAND_MGMT */ - - /* ignore DFS channels */ - if (request->channels[i]->flags & -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - (IEEE80211_CHAN_NO_IR - | IEEE80211_CHAN_RADAR)) -#else - (IEEE80211_CHAN_RADAR -#ifdef CUSTOMER_HW5 - | 0)) -#else - | IEEE80211_CHAN_PASSIVE_SCAN)) -#endif /* CUSTOMER_HW5 */ -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ - continue; - - for (j = 0; j < n_valid_chan; j++) { - /* allows only supported channel on - * current reguatory - */ - if (n_nodfs >= num_chans) - break; - - if (channel == (dtoh32(list->element[j]))) - default_chan_list[n_nodfs++] = - channel; - } - - } - } - if (num_chans == SOCIAL_CHAN_CNT && ( - (default_chan_list[0] == SOCIAL_CHAN_1) && - (default_chan_list[1] == SOCIAL_CHAN_2) && - (default_chan_list[2] == SOCIAL_CHAN_3))) { - /* SOCIAL CHANNELS 1, 6, 11 */ - search_state = WL_P2P_DISC_ST_SEARCH; - p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; - WL_INFORM(("P2P SEARCH PHASE START \n")); - } else if ((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) && - (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) { - /* If you are already a GO, then do SEARCH only */ - WL_INFORM(("Already a GO. Do SEARCH Only")); - search_state = WL_P2P_DISC_ST_SEARCH; - num_chans = n_nodfs; - p2p_scan_purpose = P2P_SCAN_NORMAL; - - } else if (num_chans == 1) { - p2p_scan_purpose = P2P_SCAN_CONNECT_TRY; - } else if (num_chans == SOCIAL_CHAN_CNT + 1) { - /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by - * the supplicant - */ - p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; - } else { - WL_INFORM(("P2P SCAN STATE START \n")); - num_chans = n_nodfs; - p2p_scan_purpose = P2P_SCAN_NORMAL; - } - } else { - err = -EINVAL; - goto exit; - } - err = wl_cfgp2p_escan(cfg, ndev, cfg->active_scan, num_chans, default_chan_list, - search_state, action, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE), NULL, - p2p_scan_purpose); - - if (!err) - cfg->p2p->search_state = search_state; - - kfree(default_chan_list); - } -exit: - if (unlikely(err)) { - /* Don't print Error incase of Scan suppress */ - if ((err == BCME_EPERM) && cfg->scan_suppressed) - WL_DBG(("Escan failed: Scan Suppressed \n")); - else - WL_ERR(("error (%d)\n", err)); - } - return err; -} - - -static s32 -wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request) -{ - s32 err = BCME_OK; - s32 passive_scan; - s32 passive_scan_time; - s32 passive_scan_time_org; - wl_scan_results_t *results; - WL_SCAN(("Enter \n")); - mutex_lock(&cfg->usr_sync); - - results = wl_escan_get_buf(cfg, FALSE); - results->version = 0; - results->count = 0; - results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; - - cfg->escan_info.ndev = ndev; - cfg->escan_info.wiphy = wiphy; - cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING; - passive_scan = cfg->active_scan ? 0 : 1; - err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan), true); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - goto exit; - } - - if (passive_channel_skip) { - - err = wldev_ioctl(ndev, WLC_GET_SCAN_PASSIVE_TIME, - &passive_scan_time_org, sizeof(passive_scan_time_org), false); - if (unlikely(err)) { - WL_ERR(("== error (%d)\n", err)); - goto exit; - } - - WL_SCAN(("PASSIVE SCAN time : %d \n", passive_scan_time_org)); - - passive_scan_time = 0; - err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME, - &passive_scan_time, sizeof(passive_scan_time), true); - if (unlikely(err)) { - WL_ERR(("== error (%d)\n", err)); - goto exit; - } - - WL_SCAN(("PASSIVE SCAN SKIPED!! (passive_channel_skip:%d) \n", - passive_channel_skip)); - } - - err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START); - - if (passive_channel_skip) { - err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME, - &passive_scan_time_org, sizeof(passive_scan_time_org), true); - if (unlikely(err)) { - WL_ERR(("== error (%d)\n", err)); - goto exit; - } - - WL_SCAN(("PASSIVE SCAN RECOVERED!! (passive_scan_time_org:%d) \n", - passive_scan_time_org)); - } - -exit: - mutex_unlock(&cfg->usr_sync); - return err; -} - -static s32 -__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request, - struct cfg80211_ssid *this_ssid) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct cfg80211_ssid *ssids; - struct ether_addr primary_mac; - bool p2p_ssid; -#ifdef WL11U - bcm_tlv_t *interworking_ie; -#endif - s32 err = 0; - s32 bssidx = -1; - s32 i; - - unsigned long flags; - static s32 busy_count = 0; -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - struct net_device *remain_on_channel_ndev = NULL; -#endif - - dhd_pub_t *dhd; - - dhd = (dhd_pub_t *)(cfg->pub); - /* - * Hostapd triggers scan before starting automatic channel selection - * also Dump stats IOVAR scans each channel hence returning from here. - */ - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { -#ifdef WL_SUPPORT_ACS - WL_INFORM(("Scan Command at SoftAP mode\n")); - return 0; -#else - WL_ERR(("Invalid Scan Command at SoftAP mode\n")); - return -EINVAL; -#endif /* WL_SUPPORT_ACS */ - } - - ndev = ndev_to_wlc_ndev(ndev, cfg); - - if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) { - WL_ERR(("Sending Action Frames. Try it again.\n")); - return -EAGAIN; - } - - WL_DBG(("Enter wiphy (%p)\n", wiphy)); - if (wl_get_drv_status_all(cfg, SCANNING)) { - if (cfg->scan_request == NULL) { - wl_clr_drv_status_all(cfg, SCANNING); - WL_DBG(("<<<<<<<<<<>>>>>>>>>>\n")); - } else { - WL_ERR(("Scanning already\n")); - return -EAGAIN; - } - } - if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) { - WL_ERR(("Scanning being aborted\n")); - return -EAGAIN; - } - if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { - WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); - return -EOPNOTSUPP; - } -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg); - if (remain_on_channel_ndev) { - WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n")); - wl_notify_escan_complete(cfg, remain_on_channel_ndev, true, true); - } -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - - - /* Arm scan timeout timer */ - mod_timer(&cfg->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); - if (request) { /* scan bss */ - ssids = request->ssids; - p2p_ssid = false; - for (i = 0; i < request->n_ssids; i++) { - if (ssids[i].ssid_len && - IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { - p2p_ssid = true; - break; - } - } - if (p2p_ssid) { - if (cfg->p2p_supported) { - /* p2p scan trigger */ - if (p2p_on(cfg) == false) { - /* p2p on at the first time */ - p2p_on(cfg) = true; - wl_cfgp2p_set_firm_p2p(cfg); - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, - &cfg->p2p->dev_addr, &cfg->p2p->int_addr); - } - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); - p2p_scan(cfg) = true; - } - } else { - /* legacy scan trigger - * So, we have to disable p2p discovery if p2p discovery is on - */ - if (cfg->p2p_supported) { - p2p_scan(cfg) = false; - /* If Netdevice is not equals to primary and p2p is on - * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. - */ - - if (p2p_scan(cfg) == false) { - if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { - err = wl_cfgp2p_discover_enable_search(cfg, - false); - if (unlikely(err)) { - goto scan_out; - } - - } - } - } - if (!cfg->p2p_supported || !p2p_scan(cfg)) { - - if (wl_cfgp2p_find_idx(cfg, ndev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from ndev(%p) failed\n", - ndev)); - err = BCME_ERROR; - goto scan_out; - } -#ifdef WL11U - if ((interworking_ie = wl_cfg80211_find_interworking_ie( - (u8 *)request->ie, request->ie_len)) != NULL) { - err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, - VNDR_IE_CUSTOM_FLAG, interworking_ie->id, - interworking_ie->data, interworking_ie->len); - - if (unlikely(err)) { - goto scan_out; - } - } else if (cfg->iw_ie_len != 0) { - /* we have to clear IW IE and disable gratuitous APR */ - wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, - VNDR_IE_CUSTOM_FLAG, - DOT11_MNG_INTERWORKING_ID, - 0, 0); - - wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, - bssidx); - cfg->wl11u = FALSE; - /* we don't care about error */ - } -#endif /* WL11U */ - err = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, - VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, - request->ie_len); - - if (unlikely(err)) { - goto scan_out; - } - - } - } - } else { /* scan in ibss */ - ssids = this_ssid; - } - - if (request && !p2p_scan(cfg)) { - WL_TRACE_HW4(("START SCAN\n")); - } - - cfg->scan_request = request; - wl_set_drv_status(cfg, SCANNING, ndev); - - if (cfg->p2p_supported) { - if (p2p_on(cfg) && p2p_scan(cfg)) { - - /* find my listen channel */ - cfg->afx_hdl->my_listen_chan = - wl_find_listen_channel(cfg, request->ie, - request->ie_len); - err = wl_cfgp2p_enable_discovery(cfg, ndev, - request->ie, request->ie_len); - - if (unlikely(err)) { - goto scan_out; - } - } - } - err = wl_do_escan(cfg, wiphy, ndev, request); - if (likely(!err)) - goto scan_success; - else - goto scan_out; - -scan_success: - busy_count = 0; - - return 0; - -scan_out: - if (err == BCME_BUSY || err == BCME_NOTREADY) { - WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY)); - err = -EBUSY; - } - -#define SCAN_EBUSY_RETRY_LIMIT 10 - if (err == -EBUSY) { - if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) { - struct ether_addr bssid; - s32 ret = 0; - busy_count = 0; - WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n", - wl_get_drv_status(cfg, SCANNING, ndev), - wl_get_drv_status(cfg, SCAN_ABORTING, ndev), - wl_get_drv_status(cfg, CONNECTING, ndev), - wl_get_drv_status(cfg, CONNECTED, ndev), - wl_get_drv_status(cfg, DISCONNECTING, ndev), - wl_get_drv_status(cfg, AP_CREATING, ndev), - wl_get_drv_status(cfg, AP_CREATED, ndev), - wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev), - wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev))); - - bzero(&bssid, sizeof(bssid)); - if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID, - &bssid, ETHER_ADDR_LEN, false)) == 0) - WL_ERR(("FW is connected with " MACDBG "/n", - MAC2STRDBG(bssid.octet))); - else - WL_ERR(("GET BSSID failed with %d\n", ret)); - - wl_cfg80211_scan_abort(cfg); - - } - } else { - busy_count = 0; - } - - wl_clr_drv_status(cfg, SCANNING, ndev); - if (timer_pending(&cfg->scan_timeout)) - del_timer_sync(&cfg->scan_timeout); - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - cfg->scan_request = NULL; - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - return err; -} - -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) -#else -static s32 -wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request) -#endif /* WL_CFG80211_P2P_DEV_IF */ -{ - s32 err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); -#if defined(WL_CFG80211_P2P_DEV_IF) - struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ - - WL_DBG(("Enter \n")); - RETURN_EIO_IF_NOT_UP(cfg); - - - err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); - if (unlikely(err)) { - if ((err == BCME_EPERM) && cfg->scan_suppressed) - WL_DBG(("scan not permitted at this time (%d)\n", err)); - else - WL_ERR(("scan error (%d)\n", err)); - return err; - } - - return err; -} - -static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) -{ - s32 err = 0; - - err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold); - if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); - return err; - } - return err; -} - -static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) -{ - s32 err = 0; - - err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0); - if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); - return err; - } - return err; -} - -static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) -{ - s32 err = 0; - u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); - - retry = htod32(retry); - err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true); - if (unlikely(err)) { - WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); - return err; - } - return err; -} - -static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; - - RETURN_EIO_IF_NOT_UP(cfg); - WL_DBG(("Enter\n")); - if (changed & WIPHY_PARAM_RTS_THRESHOLD && - (cfg->conf->rts_threshold != wiphy->rts_threshold)) { - cfg->conf->rts_threshold = wiphy->rts_threshold; - err = wl_set_rts(ndev, cfg->conf->rts_threshold); - if (err != BCME_OK) - return err; - } - if (changed & WIPHY_PARAM_FRAG_THRESHOLD && - (cfg->conf->frag_threshold != wiphy->frag_threshold)) { - cfg->conf->frag_threshold = wiphy->frag_threshold; - err = wl_set_frag(ndev, cfg->conf->frag_threshold); - if (err != BCME_OK) - return err; - } - if (changed & WIPHY_PARAM_RETRY_LONG && - (cfg->conf->retry_long != wiphy->retry_long)) { - cfg->conf->retry_long = wiphy->retry_long; - err = wl_set_retry(ndev, cfg->conf->retry_long, true); - if (err != BCME_OK) - return err; - } - if (changed & WIPHY_PARAM_RETRY_SHORT && - (cfg->conf->retry_short != wiphy->retry_short)) { - cfg->conf->retry_short = wiphy->retry_short; - err = wl_set_retry(ndev, cfg->conf->retry_short, false); - if (err != BCME_OK) { - return err; - } - } - - return err; -} -static chanspec_t -channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - u8 *buf = NULL; - wl_uint32_list_t *list; - int err = BCME_OK; - chanspec_t c = 0, ret_c = 0; - int bw = 0, tmp_bw = 0; - int i; - u32 tmp_c; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; -#define LOCAL_BUF_SIZE 1024 - buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags); - if (!buf) { - WL_ERR(("buf memory alloc failed\n")); - goto exit; - } - list = (wl_uint32_list_t *)(void *)buf; - list->count = htod32(WL_NUMCHANSPECS); - err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, - 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync); - if (err != BCME_OK) { - WL_ERR(("get chanspecs failed with %d\n", err)); - goto exit; - } - for (i = 0; i < dtoh32(list->count); i++) { - c = dtoh32(list->element[i]); - if (channel <= CH_MAX_2G_CHANNEL) { - if (!CHSPEC_IS20(c)) - continue; - if (channel == CHSPEC_CHANNEL(c)) { - ret_c = c; - bw = 20; - goto exit; - } - } - tmp_c = wf_chspec_ctlchan(c); - tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT]; - if (tmp_c != channel) - continue; - - if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) { - bw = tmp_bw; - ret_c = c; - if (bw == bw_cap) - goto exit; - } - } -exit: - if (buf) - kfree(buf); -#undef LOCAL_BUF_SIZE - WL_INFORM(("return chanspec %x %d\n", ret_c, bw)); - return ret_c; -} - -void -wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - if (cfg != NULL && ibss_vsie != NULL) { - if (cfg->ibss_vsie != NULL) { - kfree(cfg->ibss_vsie); - } - cfg->ibss_vsie = ibss_vsie; - cfg->ibss_vsie_len = ibss_vsie_len; - } -} - -static void -wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg) -{ - /* free & initiralize VSIE (Vendor Specific IE) */ - if (cfg->ibss_vsie != NULL) { - kfree(cfg->ibss_vsie); - cfg->ibss_vsie = NULL; - cfg->ibss_vsie_len = 0; - } -} - -s32 -wl_cfg80211_ibss_vsie_delete(struct net_device *dev) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - char *ioctl_buf = NULL; - s32 ret = BCME_OK; - - if (cfg != NULL && cfg->ibss_vsie != NULL) { - ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (!ioctl_buf) { - WL_ERR(("ioctl memory alloc failed\n")); - return -ENOMEM; - } - - /* change the command from "add" to "del" */ - strncpy(cfg->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1); - cfg->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - - ret = wldev_iovar_setbuf(dev, "ie", - cfg->ibss_vsie, cfg->ibss_vsie_len, - ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - WL_ERR(("ret=%d\n", ret)); - - if (ret == BCME_OK) { - /* free & initiralize VSIE */ - kfree(cfg->ibss_vsie); - cfg->ibss_vsie = NULL; - cfg->ibss_vsie_len = 0; - } - - if (ioctl_buf) { - kfree(ioctl_buf); - } - } - - return ret; -} - -#ifdef WLAIBSS_MCHAN -static bcm_struct_cfgdev* -bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct wireless_dev* wdev = NULL; - struct net_device *new_ndev = NULL; - struct net_device *primary_ndev = NULL; - s32 timeout; - wl_aibss_if_t aibss_if; - wl_if_event_info *event = NULL; - - if (cfg->ibss_cfgdev != NULL) { - WL_ERR(("IBSS interface %s already exists\n", name)); - return NULL; - } - - WL_ERR(("Try to create IBSS interface %s\n", name)); - primary_ndev = bcmcfg_to_prmry_ndev(cfg); - /* generate a new MAC address for the IBSS interface */ - get_primary_mac(cfg, &cfg->ibss_if_addr); - cfg->ibss_if_addr.octet[4] ^= 0x40; - memset(&aibss_if, sizeof(aibss_if), 0); - memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr)); - aibss_if.chspec = 0; - aibss_if.len = sizeof(aibss_if); - - cfg->bss_pending_op = TRUE; - memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); - err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if, - sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); - if (err) { - WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err)); - goto fail; - } - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout <= 0 || cfg->bss_pending_op) - goto fail; - - event = &cfg->if_event_info; - strncpy(event->name, name, IFNAMSIZ - 1); - /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control - * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux - * and will be freed by dhd_detach unless it gets unregistered before that. The - * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will - * be freed by wl_dealloc_netinfo - */ - new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name, - event->mac, event->bssidx); - if (new_ndev == NULL) - goto fail; - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (wdev == NULL) - goto fail; - wdev->wiphy = wiphy; - wdev->iftype = NL80211_IFTYPE_ADHOC; - wdev->netdev = new_ndev; - new_ndev->ieee80211_ptr = wdev; - SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy)); - - /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if - * needs to be modified to take one parameter (bool need_rtnl_lock) - */ - ASSERT_RTNL(); - if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) - goto fail; - - wl_alloc_netinfo(cfg, new_ndev, wdev, WL_MODE_IBSS, PM_ENABLE); - cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev); - WL_ERR(("IBSS interface %s created\n", new_ndev->name)); - return cfg->ibss_cfgdev; - -fail: - WL_ERR(("failed to create IBSS interface %s \n", name)); - cfg->bss_pending_op = FALSE; - if (new_ndev) - wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev); - if (wdev) - kfree(wdev); - return NULL; -} - -static s32 -bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *ndev = NULL; - struct net_device *primary_ndev = NULL; - s32 timeout; - - if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet)) - return -EINVAL; - ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev); - primary_ndev = bcmcfg_to_prmry_ndev(cfg); - - cfg->bss_pending_op = TRUE; - memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); - err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr, - sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); - if (err) { - WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err)); - goto fail; - } - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout <= 0 || cfg->bss_pending_op) { - WL_ERR(("timeout in waiting IF_DEL event\n")); - goto fail; - } - - wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev); - cfg->ibss_cfgdev = NULL; - return 0; - -fail: - cfg->bss_pending_op = FALSE; - return -1; -} -#endif /* WLAIBSS_MCHAN */ - -s32 -wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, - struct net_device *ndev, s32 bsscfg_idx, - enum nl80211_iftype iface_type, s32 del, u8 *addr) -{ - wl_interface_create_t iface; - s32 ret; - wl_interface_info_t *info; - - bzero(&iface, sizeof(wl_interface_create_t)); - - iface.ver = WL_INTERFACE_CREATE_VER; - - if (iface_type == NL80211_IFTYPE_AP) - iface.flags = WL_INTERFACE_CREATE_AP; - else - iface.flags = WL_INTERFACE_CREATE_STA; - - if (del) { - ret = wldev_iovar_setbuf(ndev, "interface_remove", - NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - } else { - if (addr) { - memcpy(&iface.mac_addr.octet, addr, ETH_ALEN); - iface.flags |= WL_INTERFACE_MAC_USE; - } - ret = wldev_iovar_getbuf(ndev, "interface_create", - &iface, sizeof(wl_interface_create_t), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (ret == 0) { - /* success */ - info = (wl_interface_info_t *)cfg->ioctl_buf; - WL_DBG(("wl interface create success!! bssidx:%d \n", - info->bsscfgidx)); - ret = info->bsscfgidx; - } - } - - if (ret < 0) - WL_ERR(("Interface %s failed!! ret %d\n", - del ? "remove" : "create", ret)); - - return ret; -} - -#if defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) -s32 -wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg, - struct net_device *ndev, s32 bsscfg_idx, - enum nl80211_iftype iface_type, s32 del, u8 *addr) -{ - s32 ret = BCME_OK; - s32 val = 0; - - struct { - s32 cfg; - s32 val; - struct ether_addr ea; - } bss_setbuf; - - WL_INFORM(("iface_type:%d del:%d \n", iface_type, del)); - - bzero(&bss_setbuf, sizeof(bss_setbuf)); - - /* AP=3, STA=2, up=1, down=0, val=-1 */ - if (del) { - val = -1; - } else if (iface_type == NL80211_IFTYPE_AP) { - /* AP Interface */ - WL_DBG(("Adding AP Interface \n")); - val = 3; - } else if (iface_type == NL80211_IFTYPE_STATION) { - WL_DBG(("Adding STA Interface \n")); - val = 2; - } else { - WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", iface_type)); - return -EINVAL; - } - - bss_setbuf.cfg = htod32(bsscfg_idx); - bss_setbuf.val = htod32(val); - - if (addr) { - memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN); - } - - ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (ret != 0) - WL_ERR(("'bss %d' failed with %d\n", val, ret)); - - return ret; -} - -/* Create a Generic Network Interface and initialize it depending up on - * the interface type - */ -bcm_struct_cfgdev* -wl_cfg80211_create_iface(struct wiphy *wiphy, - enum nl80211_iftype iface_type, - u8 *mac_addr, const char *name) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *new_ndev = NULL; - struct net_device *primary_ndev = NULL; - s32 ret = BCME_OK; - s32 bsscfg_idx = 1; - u32 timeout; - wl_if_event_info *event = NULL; - struct wireless_dev *wdev = NULL; - u8 addr[ETH_ALEN]; - - WL_DBG(("Enter\n")); - - if (!name) { - WL_ERR(("Interface name not provided\n")); - return NULL; - } - - primary_ndev = bcmcfg_to_prmry_ndev(cfg); - - if (likely(!mac_addr)) { - /* Use primary MAC with the locally administered bit for the Secondary STA I/F */ - memcpy(addr, primary_ndev->dev_addr, ETH_ALEN); - addr[0] |= 0x02; - } else { - /* Use the application provided mac address (if any) */ - memcpy(addr, mac_addr, ETH_ALEN); - } - - if ((iface_type != NL80211_IFTYPE_STATION) && (iface_type != NL80211_IFTYPE_AP)) { - WL_ERR(("IFACE type:%d not supported. STA " - "or AP IFACE is only supported\n", iface_type)); - return NULL; - } - - cfg->bss_pending_op = TRUE; - memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); - - /* De-initialize the p2p discovery interface, if operational */ - if (p2p_is_on(cfg)) { - WL_DBG(("Disabling P2P Discovery Interface \n")); -#ifdef WL_CFG80211_P2P_DEV_IF - ret = wl_cfg80211_scan_stop(bcmcfg_to_p2p_wdev(cfg)); -#else - ret = wl_cfg80211_scan_stop(cfg->p2p_net); -#endif - if (unlikely(ret < 0)) { - CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret)); - } - - wl_cfgp2p_disable_discovery(cfg); - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; - p2p_on(cfg) = false; - } - - /* - * Intialize the firmware I/F. - */ - ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx, - NL80211_IFTYPE_STATION, 0, addr); - if (ret == BCME_UNSUPPORTED) { - /* Use bssidx 1 by default */ - if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev, - bsscfg_idx, iface_type, 0, addr)) < 0) { - return NULL; - } - } else if (ret < 0) { - WL_ERR(("Interface create failed!! ret:%d \n", ret)); - goto fail; - } else { - /* Success */ - bsscfg_idx = ret; - } - - /* - * Wait till the firmware send a confirmation event back. - */ - WL_DBG(("Wait for the FW I/F Event\n")); - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout <= 0 || cfg->bss_pending_op) { - WL_ERR(("ADD_IF event, didn't come. Return \n")); - goto fail; - } - - /* - * Since FW operation is successful,we can go ahead with the - * the host interface creation. - */ - event = &cfg->if_event_info; - strncpy(event->name, name, IFNAMSIZ - 1); - new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, - event->name, addr, event->bssidx); - if (!new_ndev) { - WL_ERR(("I/F allocation failed! \n")); - goto fail; - } else - WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n", - event->ifidx, event->bssidx)); - - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (!wdev) { - WL_ERR(("wireless_dev alloc failed! \n")); - goto fail; - } - - wdev->wiphy = wiphy; - wdev->iftype = iface_type; - new_ndev->ieee80211_ptr = wdev; - SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy)); - - /* RTNL lock must have been acquired. */ - ASSERT_RTNL(); - - /* Set the locally administed mac addr, if not applied already */ - if (memcmp(addr, event->mac, ETH_ALEN) != 0) { - ret = wldev_iovar_setbuf_bsscfg(primary_ndev, "cur_etheraddr", addr, ETH_ALEN, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, event->bssidx, &cfg->ioctl_buf_sync); - if (unlikely(ret)) { - WL_ERR(("set cur_etheraddr Error (%d)\n", ret)); - goto fail; - } - memcpy(new_ndev->dev_addr, addr, ETH_ALEN); - } - - if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) { - WL_ERR(("IFACE register failed \n")); - goto fail; - } - - /* Initialize with the station mode params */ - wl_alloc_netinfo(cfg, new_ndev, wdev, - (iface_type == NL80211_IFTYPE_STATION) ? - WL_MODE_BSS : WL_MODE_AP, PM_ENABLE); - cfg->bss_cfgdev = ndev_to_cfgdev(new_ndev); - cfg->cfgdev_bssidx = event->bssidx; - - WL_DBG(("Host Network Interface for Secondary I/F created")); - - return cfg->bss_cfgdev; - -fail: - cfg->bss_pending_op = FALSE; - if (new_ndev) - wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev); - if (wdev) - kfree(wdev); - - return NULL; -} - -s32 -wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *ndev = NULL; - struct net_device *primary_ndev = NULL; - s32 ret = BCME_OK; - s32 bsscfg_idx = 1; - u32 timeout; - u32 ifidx; - enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION; - - WL_DBG(("Enter\n")); - - if (!cfg->bss_cfgdev) - return 0; - - /* If any scan is going on, abort it */ - if (wl_get_drv_status_all(cfg, SCANNING)) { - WL_DBG(("Scan in progress. Aborting the scan!\n")); - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); - } - - ndev = (struct net_device *)cfgdev_to_ndev(cfg->bss_cfgdev); - primary_ndev = bcmcfg_to_prmry_ndev(cfg); - - cfg->bss_pending_op = TRUE; - memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); - - /* Delete the firmware interface */ - ret = wl_cfg80211_interface_ops(cfg, ndev, cfg->cfgdev_bssidx, - NL80211_IFTYPE_STATION, 1, NULL); - if (ret == BCME_UNSUPPORTED) { - if ((ret = wl_cfg80211_add_del_bss(cfg, ndev, - bsscfg_idx, iface_type, true, NULL)) < 0) { - WL_ERR(("DEL bss failed ret:%d \n", ret)); - return ret; - } - } else if (ret < 0) { - WL_ERR(("Interface DEL failed ret:%d \n", ret)); - return ret; - } - - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout <= 0 || cfg->bss_pending_op) { - WL_ERR(("timeout in waiting IF_DEL event\n")); - } - ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev); - wl_cfg80211_remove_if(cfg, ifidx, ndev); - cfg->bss_cfgdev = NULL; - cfg->cfgdev_bssidx = -1; - cfg->bss_pending_op = FALSE; - - WL_DBG(("IF_DEL Done.\n")); - - return ret; -} -#endif /* defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) */ - -static s32 -wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct cfg80211_bss *bss; - struct ieee80211_channel *chan; - struct wl_join_params join_params; - int scan_suppress; - struct cfg80211_ssid ssid; - s32 scan_retry = 0; - s32 err = 0; - size_t join_params_size; - chanspec_t chanspec = 0; - u32 param[2] = {0, 0}; - u32 bw_cap = 0; -#if defined(WLAIBSS) && defined(WLAIBSS_PS) - s32 atim = 10; -#endif /* WLAIBSS & WLAIBSS_PS */ - - WL_TRACE(("In\n")); - RETURN_EIO_IF_NOT_UP(cfg); - WL_INFORM(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid))); - if (!params->ssid || params->ssid_len <= 0 || - params->ssid_len > DOT11_MAX_SSID_LEN) { - WL_ERR(("Invalid parameter\n")); - return -EINVAL; - } -#if defined(WL_CFG80211_P2P_DEV_IF) - chan = params->chandef.chan; -#else - chan = params->channel; -#endif /* WL_CFG80211_P2P_DEV_IF */ - if (chan) - cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); - if (wl_get_drv_status(cfg, CONNECTED, dev)) { - struct wlc_ssid *ssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID); - u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID); - u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN); - if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) && - (memcmp(params->ssid, ssid->SSID, ssid->SSID_len) == 0) && - (*channel == cfg->channel))) { - WL_ERR(("Connection already existed to " MACDBG "\n", - MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID)))); - return -EISCONN; - } - WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n", - ssid->SSID, MAC2STRDBG(bssid))); - } - - /* remove the VSIE */ - wl_cfg80211_ibss_vsie_delete(dev); - - bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); - if (!bss) { - if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) { - memcpy(ssid.ssid, params->ssid, params->ssid_len); - ssid.ssid_len = params->ssid_len; - do { - if (unlikely - (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == - -EBUSY)) { - wl_delay(150); - } else { - break; - } - } while (++scan_retry < WL_SCAN_RETRY_MAX); - - /* rtnl lock code is removed here. don't see why rtnl lock - * needs to be released. - */ - - /* wait 4 secons till scan done.... */ - schedule_timeout_interruptible(msecs_to_jiffies(4000)); - - bss = cfg80211_get_ibss(wiphy, NULL, - params->ssid, params->ssid_len); - } - } - if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) || - ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid && - !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) { - cfg->ibss_starter = false; - WL_DBG(("Found IBSS\n")); - } else { - cfg->ibss_starter = true; - } - if (chan) { - if (chan->band == IEEE80211_BAND_5GHZ) - param[0] = WLC_BAND_5G; - else if (chan->band == IEEE80211_BAND_2GHZ) - param[0] = WLC_BAND_2G; - err = wldev_iovar_getint(dev, "bw_cap", param); - if (unlikely(err)) { - WL_ERR(("Get bw_cap Failed (%d)\n", err)); - return err; - } - bw_cap = param[0]; - chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap); - } - /* - * Join with specific BSSID and cached SSID - * If SSID is zero join based on BSSID only - */ - memset(&join_params, 0, sizeof(join_params)); - memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, - params->ssid_len); - join_params.ssid.SSID_len = htod32(params->ssid_len); - if (params->bssid) { - memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN); - err = wldev_ioctl(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid, - ETHER_ADDR_LEN, true); - if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); - return err; - } - } else - memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); - wldev_iovar_setint(dev, "ibss_coalesce_allowed", IBSS_COALESCE_ALLOWED); - - if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { - scan_suppress = TRUE; - /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */ - err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, - &scan_suppress, sizeof(int), true); - if (unlikely(err)) { - WL_ERR(("Scan Suppress Setting Failed (%d)\n", err)); - return err; - } - } - - join_params.params.chanspec_list[0] = chanspec; - join_params.params.chanspec_num = 1; - wldev_iovar_setint(dev, "chanspec", chanspec); - join_params_size = sizeof(join_params); - - /* Disable Authentication, IBSS will add key if it required */ - wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED); - wldev_iovar_setint(dev, "wsec", 0); - -#ifdef WLAIBSS - /* Enable custom ibss features */ - err = wldev_iovar_setint(dev, "aibss", TRUE); - - if (unlikely(err)) { - WL_ERR(("Enable custom IBSS mode failed (%d)\n", err)); - return err; - } -#ifdef WLAIBSS_PS - err = wldev_ioctl(dev, WLC_SET_ATIM, &atim, sizeof(int), true); - if (unlikely(err)) { - WL_ERR(("Enable custom IBSS ATIM mode failed (%d)\n", err)); - return err; - } -#endif /* WLAIBSS_PS */ -#endif /* WLAIBSS */ - - err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - join_params_size, true); - if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); - return err; - } - - if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { - scan_suppress = FALSE; - /* Reset the SCAN SUPPRESS Flag */ - err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, - &scan_suppress, sizeof(int), true); - if (unlikely(err)) { - WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err)); - return err; - } - } - wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); - wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN); -#ifdef WLAIBSS - cfg->aibss_txfail_seq = 0; /* initialize the sequence */ -#endif /* WLAIBSS */ - cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */ - return err; -} - -static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = 0; - scb_val_t scbval; - u8 *curbssid; - - RETURN_EIO_IF_NOT_UP(cfg); - wl_link_down(cfg); - - WL_ERR(("Leave IBSS\n")); - curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); - wl_set_drv_status(cfg, DISCONNECTING, dev); - scbval.val = 0; - memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - if (unlikely(err)) { - wl_clr_drv_status(cfg, DISCONNECTING, dev); - WL_ERR(("error(%d)\n", err)); - return err; - } - - /* remove the VSIE */ - wl_cfg80211_ibss_vsie_delete(dev); - - return err; -} - -#ifdef MFP -static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa) -{ - u16 suite_count; - wpa_suite_mcast_t *mcast; - wpa_suite_ucast_t *ucast; - u16 len; - wpa_suite_auth_key_mgmt_t *mgmt; - - if (!wpa2ie) - return -1; - - len = wpa2ie->len; - mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; - if ((len -= WPA_SUITE_LEN) <= 0) - return BCME_BADLEN; - ucast = (wpa_suite_ucast_t *)&mcast[1]; - suite_count = ltoh16_ua(&ucast->count); - if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || - (len -= (WPA_IE_SUITE_COUNT_LEN + - (WPA_SUITE_LEN * suite_count))) <= 0) - return BCME_BADLEN; - - mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; - suite_count = ltoh16_ua(&mgmt->count); - - if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || - (len -= (WPA_IE_SUITE_COUNT_LEN + - (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { - capa[0] = *(u8 *)&mgmt->list[suite_count]; - capa[1] = *((u8 *)&mgmt->list[suite_count] + 1); - } else - return BCME_BADLEN; - - return 0; -} -#endif /* MFP */ - -static s32 -wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - s32 val = 0; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) - val = WPA_AUTH_PSK | -#ifdef BCMCCX - WPA_AUTH_CCKM | -#endif - WPA_AUTH_UNSPECIFIED; - else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) - val = WPA2_AUTH_PSK| -#ifdef BCMCCX - WPA2_AUTH_CCKM | -#endif - WPA2_AUTH_UNSPECIFIED; - else - val = WPA_AUTH_DISABLED; - - if (is_wps_conn(sme)) - val = WPA_AUTH_DISABLED; - -#ifdef BCMWAPI_WPI - if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { - WL_DBG((" * wl_set_wpa_version, set wpa_auth" - " to WPA_AUTH_WAPI 0x400")); - val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED; - } -#endif - WL_DBG(("setting wpa_auth to 0x%0x\n", val)); - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); - if (unlikely(err)) { - WL_ERR(("set wpa_auth failed (%d)\n", err)); - return err; - } - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - sec->wpa_versions = sme->crypto.wpa_versions; - return err; -} - -#ifdef BCMWAPI_WPI -static s32 -wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - WL_DBG((" %s \n", __FUNCTION__)); - - if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { - err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", sme->ie, sme->ie_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - if (unlikely(err)) { - WL_ERR(("===> set_wapi_ie Error (%d)\n", err)); - return err; - } - } else - WL_DBG((" * skip \n")); - return err; -} -#endif /* BCMWAPI_WPI */ - -static s32 -wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - s32 val = 0; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - switch (sme->auth_type) { - case NL80211_AUTHTYPE_OPEN_SYSTEM: - val = WL_AUTH_OPEN_SYSTEM; - WL_DBG(("open system\n")); - break; - case NL80211_AUTHTYPE_SHARED_KEY: - val = WL_AUTH_SHARED_KEY; - WL_DBG(("shared key\n")); - break; - case NL80211_AUTHTYPE_AUTOMATIC: - val = WL_AUTH_OPEN_SHARED; - WL_DBG(("automatic\n")); - break; -#ifdef BCMCCX - case NL80211_AUTHTYPE_NETWORK_EAP: - WL_DBG(("network eap\n")); - val = DOT11_LEAP_AUTH; - break; -#endif - default: - val = 2; - WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); - break; - } - - err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); - if (unlikely(err)) { - WL_ERR(("set auth failed (%d)\n", err)); - return err; - } - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - sec->auth_type = sme->auth_type; - return err; -} - -static s32 -wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - s32 pval = 0; - s32 gval = 0; - s32 err = 0; - s32 wsec_val = 0; -#ifdef MFP - s32 mfp = 0; - bcm_tlv_t *wpa2_ie; - u8 rsn_cap[2]; -#endif /* MFP */ - -#ifdef BCMWAPI_WPI - s32 val = 0; -#endif - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - 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: - case WLAN_CIPHER_SUITE_AES_CMAC: - pval = AES_ENABLED; - break; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - val = SMS4_ENABLED; - pval = SMS4_ENABLED; - break; -#endif - 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; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - val = SMS4_ENABLED; - gval = SMS4_ENABLED; - break; -#endif - default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); - return -EINVAL; - } - } - - WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); - - if (is_wps_conn(sme)) { - if (sme->privacy) - err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); - else - /* WPS-2.0 allows no security */ - err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); - } else { -#ifdef BCMWAPI_WPI - if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) { - WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED")); - err = wldev_iovar_setint_bsscfg(dev, "wsec", val, bssidx); - } else { -#endif - WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); - wsec_val = pval | gval; - -#ifdef MFP - if (pval == AES_ENABLED) { - if (((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, - DOT11_MNG_RSN_ID)) != NULL) && - (wl_cfg80211_get_rsn_capa(wpa2_ie, rsn_cap) == 0)) { - - if (rsn_cap[0] & RSN_CAP_MFPC) { - /* MFP Capability advertised by supplicant. Check - * whether MFP is supported in the firmware - */ - if ((err = wldev_iovar_getint_bsscfg(dev, - "mfp", &mfp, bssidx)) < 0) { - WL_ERR(("Get MFP failed! " - "Check MFP support in FW \n")); - return -1; - } - - if ((sme->crypto.n_akm_suites == 1) && - ((sme->crypto.akm_suites[0] == - WL_AKM_SUITE_MFP_PSK) || - (sme->crypto.akm_suites[0] == - WL_AKM_SUITE_MFP_1X))) { - wsec_val |= MFP_SHA256; - } else if (sme->crypto.n_akm_suites > 1) { - WL_ERR(("Multiple AKM Specified \n")); - return -EINVAL; - } - - wsec_val |= MFP_CAPABLE; - if (rsn_cap[0] & RSN_CAP_MFPR) - wsec_val |= MFP_REQUIRED; - - if (rsn_cap[0] & RSN_CAP_MFPR) - mfp = WL_MFP_REQUIRED; - else - mfp = WL_MFP_CAPABLE; - err = wldev_iovar_setint_bsscfg(dev, "mfp", - mfp, bssidx); - } - } - } -#endif /* MFP */ - WL_DBG((" Set WSEC to fW 0x%x \n", wsec_val)); - err = wldev_iovar_setint_bsscfg(dev, "wsec", - wsec_val, bssidx); -#ifdef BCMWAPI_WPI - } -#endif - } - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; - sec->cipher_group = sme->crypto.cipher_group; - - return err; -} - -static s32 -wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - s32 val = 0; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - if (sme->crypto.n_akm_suites) { - err = wldev_iovar_getint(dev, "wpa_auth", &val); - if (unlikely(err)) { - WL_ERR(("could not get wpa_auth (%d)\n", err)); - return err; - } - if (val & (WPA_AUTH_PSK | -#ifdef BCMCCX - WPA_AUTH_CCKM | -#endif - 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; -#ifdef BCMCCX - case WLAN_AKM_SUITE_CCKM: - val = WPA_AUTH_CCKM; - break; -#endif - default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); - return -EINVAL; - } - } else if (val & (WPA2_AUTH_PSK | -#ifdef BCMCCX - WPA2_AUTH_CCKM | -#endif - WPA2_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_8021X: - val = WPA2_AUTH_UNSPECIFIED; - break; -#ifdef MFP - case WL_AKM_SUITE_MFP_1X: - val = WPA2_AUTH_UNSPECIFIED; - break; - case WL_AKM_SUITE_MFP_PSK: - val = WPA2_AUTH_PSK; - break; -#endif - case WLAN_AKM_SUITE_PSK: - val = WPA2_AUTH_PSK; - break; -#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X) - case WLAN_AKM_SUITE_FT_8021X: - val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; - break; -#endif -#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK) - case WLAN_AKM_SUITE_FT_PSK: - val = WPA2_AUTH_PSK | WPA2_AUTH_FT; - break; -#endif -#ifdef BCMCCX - case WLAN_AKM_SUITE_CCKM: - val = WPA2_AUTH_CCKM; - break; -#endif - default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); - return -EINVAL; - } - } -#ifdef BCMWAPI_WPI - else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_WAPI_CERT: - val = WAPI_AUTH_UNSPECIFIED; - break; - case WLAN_AKM_SUITE_WAPI_PSK: - val = WAPI_AUTH_PSK; - break; - default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); - return -EINVAL; - } - } -#endif - WL_DBG(("setting wpa_auth to %d\n", val)); - - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); - if (unlikely(err)) { - WL_ERR(("could not set wpa_auth (%d)\n", err)); - return err; - } - } - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - sec->wpa_auth = sme->crypto.akm_suites[0]; - - return err; -} - -static s32 -wl_set_set_sharedkey(struct net_device *dev, - struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - struct wl_wsec_key key; - s32 val; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - WL_DBG(("key len (%d)\n", sme->key_len)); - if (sme->key_len) { - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", - sec->wpa_versions, sec->cipher_pairwise)); - if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | -#ifdef BCMWAPI_WPI - NL80211_WPA_VERSION_2 | NL80211_WAPI_VERSION_1)) && -#else - NL80211_WPA_VERSION_2)) && -#endif - (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | -#ifdef BCMWAPI_WPI - WLAN_CIPHER_SUITE_WEP104 | WLAN_CIPHER_SUITE_SMS4))) -#else - WLAN_CIPHER_SUITE_WEP104))) -#endif - { - memset(&key, 0, sizeof(key)); - key.len = (u32) sme->key_len; - key.index = (u32) sme->key_idx; - if (unlikely(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 = WL_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; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - key.algo = CRYPTO_ALGO_SMS4; - break; -#endif - default: - WL_ERR(("Invalid algorithm (%d)\n", - sme->crypto.ciphers_pairwise[0])); - return -EINVAL; - } - /* Set the new key/index */ - WL_DBG(("key length (%d) key index (%d) algo (%d)\n", - key.len, key.index, key.algo)); - WL_DBG(("key \"%s\"\n", key.data)); - swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - return err; - } - if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { - WL_DBG(("set auth_type to shared key\n")); - val = WL_AUTH_SHARED_KEY; /* shared key */ - err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); - if (unlikely(err)) { - WL_ERR(("set auth failed (%d)\n", err)); - return err; - } - } - } - } - return err; -} - -#if defined(ESCAN_RESULT_PATCH) -static u8 connect_req_bssid[6]; -static u8 broad_bssid[6]; -#endif /* ESCAN_RESULT_PATCH */ - - - -#if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX) -static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd) -{ - u32 chanspec = 0; - bool isvht80 = 0; - - if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK) - chanspec = wl_chspec_driver_to_host(chanspec); - - isvht80 = chanspec & WL_CHANSPEC_BW_80; - WL_INFO(("%s: chanspec(%x:%d)\n", __FUNCTION__, chanspec, isvht80)); - - return isvht80; -} -#endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */ - -static s32 -wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct ieee80211_channel *chan = sme->channel; - wl_extjoin_params_t *ext_join_params; - struct wl_join_params join_params; - size_t join_params_size; -#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - s32 roam_trigger[2] = {0, 0}; -#endif /* ROAM_AP_ENV_DETECTION */ - s32 err = 0; - wpa_ie_fixed_t *wpa_ie; - bcm_tlv_t *wpa2_ie; - u8* wpaie = 0; - u32 wpaie_len = 0; - u32 chan_cnt = 0; - struct ether_addr bssid; - s32 bssidx; - int ret; - int wait_cnt; - - WL_DBG(("In\n")); - - if (unlikely(!sme->ssid)) { - WL_ERR(("Invalid ssid\n")); - return -EOPNOTSUPP; - } - - if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) { - WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n", - sme->ssid, sme->ssid_len)); - return -EINVAL; - } - - WL_DBG(("SME IE : len=%zu\n", sme->ie_len)); - if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) { - prhex(NULL, sme->ie, sme->ie_len); - } - - RETURN_EIO_IF_NOT_UP(cfg); - - /* - * Cancel ongoing scan to sync up with sme state machine of cfg80211. - */ -#if !defined(ESCAN_RESULT_PATCH) - if (cfg->scan_request) { - wl_notify_escan_complete(cfg, dev, true, true); - } -#endif -#ifdef WL_SCHED_SCAN - if (cfg->sched_scan_req) { - wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg)); - } -#endif -#if defined(ESCAN_RESULT_PATCH) - if (sme->bssid) - memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); - else - bzero(connect_req_bssid, ETHER_ADDR_LEN); - bzero(broad_bssid, ETHER_ADDR_LEN); -#endif -#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) - maxrxpktglom = 0; -#endif - bzero(&bssid, sizeof(bssid)); - if (!wl_get_drv_status(cfg, CONNECTED, dev)&& - (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { - if (!ETHER_ISNULLADDR(&bssid)) { - scb_val_t scbval; - wl_set_drv_status(cfg, DISCONNECTING, dev); - scbval.val = DOT11_RC_DISASSOC_LEAVING; - memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN); - scbval.val = htod32(scbval.val); - - WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n", - MAC2STRDBG(bssid.octet))); - err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - if (unlikely(err)) { - wl_clr_drv_status(cfg, DISCONNECTING, dev); - WL_ERR(("error (%d)\n", err)); - return err; - } - wait_cnt = 500/10; - while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) { - WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", - wait_cnt)); - wait_cnt--; - OSL_SLEEP(10); - } - } else - WL_DBG(("Currently not associated!\n")); - } else { - /* if status is DISCONNECTING, wait for disconnection terminated max 500 ms */ - wait_cnt = 500/10; - while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) { - WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt)); - wait_cnt--; - OSL_SLEEP(10); - } - } - - /* Clean BSSID */ - bzero(&bssid, sizeof(bssid)); - if (!wl_get_drv_status(cfg, DISCONNECTING, dev)) - wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID); - - if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) { - /* we only allow to connect using virtual interface in case of P2P */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); - } else if (dev == bcmcfg_to_prmry_ndev(cfg)) { - /* find the RSN_IE */ - if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, - DOT11_MNG_RSN_ID)) != NULL) { - WL_DBG((" WPA2 IE is found\n")); - } - /* find the WPA_IE */ - if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, - sme->ie_len)) != NULL) { - WL_DBG((" WPA IE is found\n")); - } - if (wpa_ie != NULL || wpa2_ie != NULL) { - wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; - wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; - wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; - err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("wpaie set error (%d)\n", err)); - return err; - } - } else { - err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("wpaie set error (%d)\n", err)); - return err; - } - } - - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len); - if (unlikely(err)) { - return err; - } - } -#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) - if (dhd->roam_env_detection) { - bool is_roamtrig_reset = TRUE; - bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection", - AP_ENV_DETECT_NOT_USED) == BCME_OK); - if (is_roamtrig_reset && is_roam_env_ok) { - roam_trigger[0] = WL_AUTO_ROAM_TRIGGER; - roam_trigger[1] = WLC_BAND_ALL; - err = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, - sizeof(roam_trigger), true); - if (unlikely(err)) { - WL_ERR((" failed to restore roam_trigger for auto env" - " detection\n")); - } - } - } -#endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */ - if (chan) { - cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); - chan_cnt = 1; - WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel, - chan->center_freq, chan_cnt)); - } else - cfg->channel = 0; -#ifdef BCMWAPI_WPI - WL_DBG(("1. enable wapi auth\n")); - if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { - WL_DBG(("2. set wapi ie \n")); - err = wl_set_set_wapi_ie(dev, sme); - if (unlikely(err)) - return err; - } else - WL_DBG(("2. Not wapi ie \n")); -#endif - WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); - WL_DBG(("3. set wapi version \n")); - err = wl_set_wpa_version(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid wpa_version\n")); - return err; - } -#ifdef BCMWAPI_WPI - if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) - WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n")); - else { - WL_DBG(("4. wl_set_auth_type\n")); -#endif - err = wl_set_auth_type(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid auth type\n")); - return err; - } -#ifdef BCMWAPI_WPI - } -#endif - - err = wl_set_set_cipher(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid ciper\n")); - return err; - } - - err = wl_set_key_mgmt(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid key mgmt\n")); - return err; - } - - err = wl_set_set_sharedkey(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid shared key\n")); - return err; - } - - /* - * Join with specific BSSID and cached SSID - * If SSID is zero join based on BSSID only - */ - join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + - chan_cnt * sizeof(chanspec_t); - ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL); - if (ext_join_params == NULL) { - err = -ENOMEM; - wl_clr_drv_status(cfg, CONNECTING, dev); - goto exit; - } - ext_join_params->ssid.SSID_len = MIN(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); - memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); - wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID); - ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); - /* increate dwell time to receive probe response or detect Beacon - * from target AP at a noisy air only during connect command - */ - ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1; - ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1; - /* Set up join scan parameters */ - ext_join_params->scan.scan_type = -1; - ext_join_params->scan.nprobes = chan_cnt ? - (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1; - ext_join_params->scan.home_time = -1; - - if (sme->bssid) - memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN); - else - memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN); - ext_join_params->assoc.chanspec_num = chan_cnt; - if (chan_cnt) { - u16 channel, band, bw, ctl_sb; - chanspec_t chspec; - channel = cfg->channel; - band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G - : WL_CHANSPEC_BAND_5G; - bw = WL_CHANSPEC_BW_20; - ctl_sb = WL_CHANSPEC_CTL_SB_NONE; - chspec = (channel | band | bw | ctl_sb); - ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; - ext_join_params->assoc.chanspec_list[0] |= chspec; - ext_join_params->assoc.chanspec_list[0] = - wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); - } - ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); - if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { - WL_INFORM(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID, - ext_join_params->ssid.SSID_len)); - } - wl_set_drv_status(cfg, CONNECTING, dev); - - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - kfree(ext_join_params); - return BCME_ERROR; - } - err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - WL_ERR(("Connectting with" MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n", - MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), cfg->channel, - ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len)); - - kfree(ext_join_params); - if (err) { - wl_clr_drv_status(cfg, CONNECTING, dev); - if (err == BCME_UNSUPPORTED) { - WL_DBG(("join iovar is not supported\n")); - goto set_ssid; - } else { - WL_ERR(("error (%d)\n", err)); - goto exit; - } - } else - goto exit; - -set_ssid: - memset(&join_params, 0, sizeof(join_params)); - join_params_size = sizeof(join_params.ssid); - - join_params.ssid.SSID_len = MIN(sizeof(join_params.ssid.SSID), sme->ssid_len); - memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); - join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); - wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); - if (sme->bssid) - memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); - else - memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); - - wl_ch_to_chanspec(cfg->channel, &join_params, &join_params_size); - WL_DBG(("join_param_size %zu\n", join_params_size)); - - if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { - WL_INFORM(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, - join_params.ssid.SSID_len)); - } - wl_set_drv_status(cfg, CONNECTING, dev); - err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true); - if (err) { - WL_ERR(("error (%d)\n", err)); - wl_clr_drv_status(cfg, CONNECTING, dev); - } -exit: - return err; -} - -static s32 -wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - scb_val_t scbval; - bool act = false; - s32 err = 0; - u8 *curbssid; -#ifdef CUSTOM_SET_CPUCORE - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif /* CUSTOM_SET_CPUCORE */ - WL_ERR(("Reason %d\n", reason_code)); - RETURN_EIO_IF_NOT_UP(cfg); - act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT); - curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); -#ifdef ESCAN_RESULT_PATCH - if (wl_get_drv_status(cfg, CONNECTING, dev) && curbssid && - (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0)) { - WL_ERR(("Disconnecting from connecting device: " MACDBG "\n", - MAC2STRDBG(curbssid))); - act = true; - } -#endif /* ESCAN_RESULT_PATCH */ - if (act) { - /* - * Cancel ongoing scan to sync up with sme state machine of cfg80211. - */ -#if !defined(ESCAN_RESULT_PATCH) - /* Let scan aborted by F/W */ - if (cfg->scan_request) { - wl_notify_escan_complete(cfg, dev, true, true); - } -#endif /* ESCAN_RESULT_PATCH */ - wl_set_drv_status(cfg, DISCONNECTING, dev); - scbval.val = reason_code; - memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - scbval.val = htod32(scbval.val); - err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - if (unlikely(err)) { - wl_clr_drv_status(cfg, DISCONNECTING, dev); - WL_ERR(("error (%d)\n", err)); - return err; - } - } -#ifdef CUSTOM_SET_CPUCORE - /* set default cpucore */ - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - dhd->chan_isvht80 &= ~DHD_FLAG_STA_MODE; - if (!(dhd->chan_isvht80)) - dhd_set_cpucore(dhd, FALSE); - } -#endif /* CUSTOM_SET_CPUCORE */ - - return err; -} - -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, s32 mbm) -#else -static s32 -wl_cfg80211_set_tx_power(struct wiphy *wiphy, - enum nl80211_tx_power_setting type, s32 dbm) -#endif /* WL_CFG80211_P2P_DEV_IF */ -{ - - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; -#if defined(WL_CFG80211_P2P_DEV_IF) - s32 dbm = MBM_TO_DBM(mbm); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \ - defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES) - dbm = MBM_TO_DBM(dbm); -#endif /* WL_CFG80211_P2P_DEV_IF */ - - RETURN_EIO_IF_NOT_UP(cfg); - switch (type) { - case NL80211_TX_POWER_AUTOMATIC: - break; - case NL80211_TX_POWER_LIMITED: - if (dbm < 0) { - WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n")); - return -EINVAL; - } - break; - case NL80211_TX_POWER_FIXED: - if (dbm < 0) { - WL_ERR(("TX_POWER_FIXED - dbm is negative..\n")); - return -EINVAL; - } - break; - } - - err = wl_set_tx_power(ndev, type, dbm); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - - cfg->conf->tx_power = dbm; - - return err; -} - -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, s32 *dbm) -#else -static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) -#endif /* WL_CFG80211_P2P_DEV_IF */ -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; - - RETURN_EIO_IF_NOT_UP(cfg); - err = wl_get_tx_power(ndev, dbm); - if (unlikely(err)) - WL_ERR(("error (%d)\n", err)); - - return err; -} - -static s32 -wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool unicast, bool multicast) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - u32 index; - s32 wsec; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - WL_DBG(("key index (%d)\n", key_idx)); - RETURN_EIO_IF_NOT_UP(cfg); - err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); - if (unlikely(err)) { - WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); - return err; - } - if (wsec == WEP_ENABLED) { - /* Just select a new current key */ - index = (u32) key_idx; - index = htod32(index); - err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, - sizeof(index), true); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - } - } - return err; -} - -static s32 -wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, const u8 *mac_addr, struct key_params *params) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct wl_wsec_key key; - s32 err = 0; - s32 bssidx; - s32 mode = wl_get_mode_by_netdev(cfg, dev); - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - memset(&key, 0, sizeof(key)); - key.index = (u32) key_idx; - - if (!ETHER_ISMULTI(mac_addr)) - memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); - key.len = (u32) params->key_len; - - /* check for key index change */ - if (key.len == 0) { - /* key delete */ - swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("key delete error (%d)\n", err)); - return err; - } - } else { - if (key.len > sizeof(key.data)) { - WL_ERR(("Invalid key length (%d)\n", key.len)); - return -EINVAL; - } - WL_DBG(("Setting the key index %d\n", key.index)); - memcpy(key.data, params->key, key.len); - - if ((mode == WL_MODE_BSS) && - (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_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); - break; - case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); - break; - case WLAN_CIPHER_SUITE_TKIP: - key.algo = CRYPTO_ALGO_TKIP; - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - key.algo = CRYPTO_ALGO_AES_CCM; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); - break; - case WLAN_CIPHER_SUITE_CCMP: - key.algo = CRYPTO_ALGO_AES_CCM; - WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); - break; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - key.algo = CRYPTO_ALGO_SMS4; - WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); - break; -#endif - default: - WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); - return -EINVAL; - } - swap_key_from_BE(&key); - /* need to guarantee EAPOL 4/4 send out before set key */ - dhd_wait_pend8021x(dev); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - return err; - } - } - return err; -} - -int -wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable) -{ - int err; - wl_eventmsg_buf_t ev_buf; - - if (dev != bcmcfg_to_prmry_ndev(g_bcm_cfg)) { - /* roam offload is only for the primary device */ - return -1; - } - err = wldev_iovar_setint(dev, "roam_offload", enable); - if (err) - return err; - - bzero(&ev_buf, sizeof(wl_eventmsg_buf_t)); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable); - err = wl_cfg80211_apply_eventbuffer(dev, g_bcm_cfg, &ev_buf); - if (!err) { - g_bcm_cfg->roam_offload = enable; - } - return err; -} - -static s32 -wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - struct key_params *params) -{ - struct wl_wsec_key key; - s32 val = 0; - s32 wsec = 0; - s32 err = 0; - u8 keybuf[8]; - s32 bssidx = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 mode = wl_get_mode_by_netdev(cfg, dev); - WL_DBG(("key index (%d)\n", key_idx)); - RETURN_EIO_IF_NOT_UP(cfg); - - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - if (mac_addr && - ((params->cipher != WLAN_CIPHER_SUITE_WEP40) && - (params->cipher != WLAN_CIPHER_SUITE_WEP104))) { - wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); - goto exit; - } - memset(&key, 0, sizeof(key)); - - key.len = (u32) params->key_len; - key.index = (u32) key_idx; - - if (unlikely(key.len > sizeof(key.data))) { - WL_ERR(("Too long key length (%u)\n", key.len)); - return -EINVAL; - } - memcpy(key.data, params->key, key.len); - - key.flags = WL_PRIMARY_KEY; - switch (params->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - key.algo = CRYPTO_ALGO_WEP1; - val = WEP_ENABLED; - WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); - break; - case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; - val = WEP_ENABLED; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); - break; - case WLAN_CIPHER_SUITE_TKIP: - key.algo = CRYPTO_ALGO_TKIP; - val = TKIP_ENABLED; - /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ - if (mode == WL_MODE_BSS) { - bcopy(&key.data[24], keybuf, sizeof(keybuf)); - bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); - bcopy(keybuf, &key.data[16], sizeof(keybuf)); - } - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - key.algo = CRYPTO_ALGO_AES_CCM; - val = AES_ENABLED; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); - break; - case WLAN_CIPHER_SUITE_CCMP: - key.algo = CRYPTO_ALGO_AES_CCM; - val = AES_ENABLED; - WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); - break; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - key.algo = CRYPTO_ALGO_SMS4; - WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); - val = SMS4_ENABLED; - break; -#endif /* BCMWAPI_WPI */ -#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK) - case WLAN_CIPHER_SUITE_PMK: { - int j; - wsec_pmk_t pmk; - char keystring[WSEC_MAX_PSK_LEN + 1]; - char* charptr = keystring; - uint len; - struct wl_security *sec; - - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - if (sec->wpa_auth == WLAN_AKM_SUITE_8021X) { - err = wldev_iovar_setbuf(dev, "okc_info_pmk", params->key, - WSEC_MAX_PSK_LEN / 2, keystring, sizeof(keystring), NULL); - if (err) { - /* could fail in case that 'okc' is not supported */ - WL_INFORM(("Setting 'okc_info_pmk' failed, err=%d\n", err)); - } - } - /* copy the raw hex key to the appropriate format */ - for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { - sprintf(charptr, "%02x", params->key[j]); - charptr += 2; - } - len = strlen(keystring); - pmk.key_len = htod16(len); - bcopy(keystring, pmk.key, len); - pmk.flags = htod16(WSEC_PASSPHRASE); - - err = wldev_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk), true); - if (err) - return err; - } break; -#endif /* WLFBT && WLAN_CIPHER_SUITE_PMK */ - default: - WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); - return -EINVAL; - } - - /* Set the new key/index */ - if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) { - WL_ERR(("IBSS KEY setted\n")); - wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE); - } - swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - return err; - } - -exit: - err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); - if (unlikely(err)) { - WL_ERR(("get wsec error (%d)\n", err)); - return err; - } - - wsec |= val; - err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); - if (unlikely(err)) { - WL_ERR(("set wsec error (%d)\n", err)); - return err; - } - - return err; -} - -static s32 -wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr) -{ - struct wl_wsec_key key; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - WL_DBG(("Enter\n")); - -#ifndef IEEE80211W - if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) - return -EINVAL; -#endif - - RETURN_EIO_IF_NOT_UP(cfg); - memset(&key, 0, sizeof(key)); - - key.flags = WL_PRIMARY_KEY; - key.algo = CRYPTO_ALGO_OFF; - key.index = (u32) key_idx; - - WL_DBG(("key index (%d)\n", key_idx)); - /* Set the new key/index */ - swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - if (err == -EINVAL) { - if (key.index >= DOT11_MAX_DEFAULT_KEYS) { - /* we ignore this key index in this case */ - WL_DBG(("invalid key index (%d)\n", key_idx)); - } - } else { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - } - return err; - } - return err; -} - -static s32 -wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, - void (*callback) (void *cookie, struct key_params * params)) -{ - struct key_params params; - struct wl_wsec_key key; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct wl_security *sec; - s32 wsec; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - WL_DBG(("key index (%d)\n", key_idx)); - RETURN_EIO_IF_NOT_UP(cfg); - memset(&key, 0, sizeof(key)); - key.index = key_idx; - swap_key_to_BE(&key); - memset(¶ms, 0, sizeof(params)); - params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); - memcpy(params.key, key.data, params.key_len); - - err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); - if (unlikely(err)) { - WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); - return err; - } - switch (WSEC_ENABLED(wsec)) { - case WEP_ENABLED: - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { - params.cipher = WLAN_CIPHER_SUITE_WEP40; - WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); - } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { - params.cipher = WLAN_CIPHER_SUITE_WEP104; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); - } - break; - case TKIP_ENABLED: - params.cipher = WLAN_CIPHER_SUITE_TKIP; - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); - break; - case AES_ENABLED: - params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); - break; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - key.algo = CRYPTO_ALGO_SMS4; - WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); - break; -#endif - default: - WL_ERR(("Invalid algo (0x%x)\n", wsec)); - return -EINVAL; - } - - callback(cookie, ¶ms); - return err; -} - -static s32 -wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *dev, u8 key_idx) -{ -#ifdef MFP - return 0; -#else - WL_INFORM(("Not supported\n")); - return -EOPNOTSUPP; -#endif /* MFP */ -} - -static s32 -wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac, struct station_info *sinfo) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - scb_val_t scb_val; - s32 rssi; - s32 rate; - s32 err = 0; - sta_info_t *sta; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS) - s8 eabuf[ETHER_ADDR_STR_LEN]; -#endif - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - RETURN_EIO_IF_NOT_UP(cfg); - if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { - err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, - ETHER_ADDR_LEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); - if (err < 0) { - WL_ERR(("GET STA INFO failed, %d\n", err)); - return err; - } - sinfo->filled = STATION_INFO_INACTIVE_TIME; - sta = (sta_info_t *)cfg->ioctl_buf; - sta->len = dtoh16(sta->len); - sta->cap = dtoh16(sta->cap); - sta->flags = dtoh32(sta->flags); - sta->idle = dtoh32(sta->idle); - sta->in = dtoh32(sta->in); - sinfo->inactive_time = sta->idle * 1000; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS) - if (sta->flags & WL_STA_ASSOC) { - sinfo->filled |= STATION_INFO_CONNECTED_TIME; - sinfo->connected_time = sta->in; - } - WL_INFORM(("STA %s : idle time : %d sec, connected time :%d ms\n", - bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time, - sta->idle * 1000)); -#endif - } else if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS || - wl_get_mode_by_netdev(cfg, dev) == WL_MODE_IBSS) { - get_pktcnt_t pktcnt; - u8 *curmacp; - - if (cfg->roam_offload) { - struct ether_addr bssid; - err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - if (err) { - WL_ERR(("Failed to get current BSSID\n")); - } else { - if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) { - /* roaming is detected */ - err = wl_cfg80211_delayed_roam(cfg, dev, &bssid); - if (err) - WL_ERR(("Failed to handle the delayed roam, " - "err=%d", err)); - mac = (u8 *)bssid.octet; - } - } - } - if (!wl_get_drv_status(cfg, CONNECTED, dev) || - (dhd_is_associated(dhd, NULL, &err) == FALSE)) { - WL_ERR(("NOT assoc\n")); - if (err == -ERESTARTSYS) - return err; - err = -ENODEV; - return err; - } - curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID); - if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { - WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n", - MAC2STRDBG(mac), MAC2STRDBG(curmacp))); - } - - /* Report the current tx rate */ - err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); - if (err) { - WL_ERR(("Could not get rate (%d)\n", err)); - } else { -#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) - int rxpktglom; -#endif - rate = dtoh32(rate); - sinfo->filled |= STATION_INFO_TX_BITRATE; - sinfo->txrate.legacy = rate * 5; - WL_DBG(("Rate %d Mbps\n", (rate / 2))); -#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) - rxpktglom = ((rate/2) > 150) ? 20 : 10; - - if (maxrxpktglom != rxpktglom) { - maxrxpktglom = rxpktglom; - WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2), - maxrxpktglom)); - err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom", - (char*)&maxrxpktglom, 4, cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, NULL); - if (err < 0) { - WL_ERR(("set bus:maxtxpktglom failed, %d\n", err)); - } - } -#endif - } - - memset(&scb_val, 0, sizeof(scb_val)); - scb_val.val = 0; - err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t), false); - if (err) { - WL_ERR(("Could not get rssi (%d)\n", err)); - goto get_station_err; - } - rssi = wl_rssi_offset(dtoh32(scb_val.val)); - sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = rssi; - WL_DBG(("RSSI %d dBm\n", rssi)); - err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt, - sizeof(pktcnt), false); - if (!err) { - sinfo->filled |= (STATION_INFO_RX_PACKETS | - STATION_INFO_RX_DROP_MISC | - STATION_INFO_TX_PACKETS | - STATION_INFO_TX_FAILED); - sinfo->rx_packets = pktcnt.rx_good_pkt; - sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt; - sinfo->tx_packets = pktcnt.tx_good_pkt; - sinfo->tx_failed = pktcnt.tx_bad_pkt; - } -get_station_err: - if (err && (err != -ERESTARTSYS)) { - /* Disconnect due to zero BSSID or error to get RSSI */ - WL_ERR(("force cfg80211_disconnected: %d\n", err)); - wl_clr_drv_status(cfg, CONNECTED, dev); - cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL); - wl_link_down(cfg); - } - } - else { - WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev))); - } - - return err; -} - -static s32 -wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - bool enabled, s32 timeout) -{ - s32 pm; - s32 err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev); - - RETURN_EIO_IF_NOT_UP(cfg); - WL_DBG(("Enter\n")); - if (cfg->p2p_net == dev || _net_info == NULL || cfg->vsdb_mode || - !wl_get_drv_status(cfg, CONNECTED, dev)) { - return err; - } - - /* Delete pm_enable_work */ - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_PEND); - - pm = enabled ? PM_FAST : PM_OFF; - if (_net_info->pm_block) { - WL_ERR(("%s:Do not enable the power save for pm_block %d\n", - dev->name, _net_info->pm_block)); - pm = PM_OFF; - } - pm = htod32(pm); - WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled"))); - err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true); - if (unlikely(err)) { - if (err == -ENODEV) - WL_DBG(("net_device is not ready yet\n")); - else - WL_ERR(("error (%d)\n", err)); - return err; - } - wl_cfg80211_update_power_mode(dev); - return err; -} - -void wl_cfg80211_update_power_mode(struct net_device *dev) -{ - int err, pm = -1; - - err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), true); - if (err) - WL_ERR(("%s:error (%d)\n", __FUNCTION__, err)); - else if (pm != -1 && dev->ieee80211_ptr) - dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true; -} - -static __used u32 wl_find_msb(u16 bit16) -{ - u32 ret = 0; - - if (bit16 & 0xff00) { - ret += 8; - bit16 >>= 8; - } - - if (bit16 & 0xf0) { - ret += 4; - bit16 >>= 4; - } - - if (bit16 & 0xc) { - ret += 2; - bit16 >>= 2; - } - - if (bit16 & 2) - ret += bit16 & 2; - else if (bit16) - ret += bit16; - - return ret; -} - -static s32 wl_cfg80211_resume(struct wiphy *wiphy) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; - - if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) { - WL_INFORM(("device is not ready\n")); - return 0; - } - - return err; -} - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) -static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) -#else -static s32 wl_cfg80211_suspend(struct wiphy *wiphy) -#endif -{ -#ifdef DHD_CLEAR_ON_SUSPEND - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_info *iter, *next; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - unsigned long flags; - if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) { - WL_INFORM(("device is not ready : status (%d)\n", - (int)cfg->status)); - return 0; - } - for_each_ndev(cfg, iter, next) - wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - if (cfg->scan_request) { - cfg80211_scan_done(cfg->scan_request, true); - cfg->scan_request = NULL; - } - for_each_ndev(cfg, iter, next) { - wl_clr_drv_status(cfg, SCANNING, iter->ndev); - wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev); - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - for_each_ndev(cfg, iter, next) { - if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) { - wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false); - } - } -#endif /* DHD_CLEAR_ON_SUSPEND */ - return 0; -} - -static s32 -wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, - s32 err) -{ - int i, j; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); - - if (!pmk_list) { - printk("pmk_list is NULL\n"); - return -EINVAL; - } - /* pmk list is supported only for STA interface i.e. primary interface - * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init - */ - if (primary_dev != dev) { - WL_INFORM(("Not supporting Flushing pmklist on virtual" - " interfaces than primary interface\n")); - return err; - } - - WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid)); - for (i = 0; i < pmk_list->pmkids.npmkid; i++) { - WL_DBG(("PMKID[%d]: %pM =\n", i, - &pmk_list->pmkids.pmkid[i].BSSID)); - for (j = 0; j < WPA2_PMKID_LEN; j++) { - WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j])); - } - } - if (likely(!err)) { - err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, - sizeof(*pmk_list), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - } - - return err; -} - -static s32 -wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = 0; - int i; - - if (pmksa == NULL) { - WL_ERR(("pmksa is null\n")); - return -EINVAL; - } - - RETURN_EIO_IF_NOT_UP(cfg); - for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++) - if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, - ETHER_ADDR_LEN)) - break; - if (i < WL_NUM_PMKIDS_MAX) { - memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, - ETHER_ADDR_LEN); - memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, - WPA2_PMKID_LEN); - if (i == cfg->pmk_list->pmkids.npmkid) - cfg->pmk_list->pmkids.npmkid++; - } else { - err = -EINVAL; - } - WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", - &cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].BSSID)); - for (i = 0; i < WPA2_PMKID_LEN; i++) { - WL_DBG(("%02x\n", - cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1]. - PMKID[i])); - } - - err = wl_update_pmklist(dev, cfg->pmk_list, err); - - return err; -} - -static s32 -wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct _pmkid_list pmkid = {0}; - s32 err = 0; - int i; - - if (pmksa == NULL) { - WL_ERR(("pmksa is null\n")); - return -EINVAL; - } - - RETURN_EIO_IF_NOT_UP(cfg); - memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); - memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); - - WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", - &pmkid.pmkid[0].BSSID)); - for (i = 0; i < WPA2_PMKID_LEN; i++) { - WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i])); - } - - for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++) - if (!memcmp - (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, - ETHER_ADDR_LEN)) - break; - - if ((cfg->pmk_list->pmkids.npmkid > 0) && - (i < cfg->pmk_list->pmkids.npmkid)) { - memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t)); - for (; i < (cfg->pmk_list->pmkids.npmkid - 1); i++) { - memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, - &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID, - ETHER_ADDR_LEN); - memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, - &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID, - WPA2_PMKID_LEN); - } - cfg->pmk_list->pmkids.npmkid--; - } else { - err = -EINVAL; - } - - err = wl_update_pmklist(dev, cfg->pmk_list, err); - - return err; - -} - -static s32 -wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = 0; - RETURN_EIO_IF_NOT_UP(cfg); - memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list)); - err = wl_update_pmklist(dev, cfg->pmk_list, err); - return err; - -} - -static wl_scan_params_t * -wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) -{ - wl_scan_params_t *params; - int params_size; - int num_chans; - - *out_params_size = 0; - - /* Our scan params only need space for 1 channel and 0 ssids */ - params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); - params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); - if (params == NULL) { - WL_ERR(("mem alloc failed (%d bytes)\n", params_size)); - return params; - } - memset(params, 0, params_size); - params->nprobes = nprobes; - - num_chans = (channel == 0) ? 0 : 1; - - memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); - params->bss_type = DOT11_BSSTYPE_ANY; - params->scan_type = DOT11_SCANTYPE_ACTIVE; - params->nprobes = htod32(1); - params->active_time = htod32(-1); - params->passive_time = htod32(-1); - params->home_time = htod32(10); - if (channel == -1) - params->channel_list[0] = htodchanspec(channel); - else - params->channel_list[0] = wl_ch_host_to_driver(channel); - - /* Our scan params have 1 channel and 0 ssids */ - params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | - (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); - - *out_params_size = params_size; /* rtn size to the caller */ - return params; -} - -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - struct ieee80211_channel *channel, unsigned int duration, u64 *cookie) -#else -static s32 -wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - struct ieee80211_channel * channel, - enum nl80211_channel_type channel_type, - unsigned int duration, u64 *cookie) -#endif /* WL_CFG80211_P2P_DEV_IF */ -{ - s32 target_channel; - u32 id; - s32 err = BCME_OK; - struct ether_addr primary_mac; - struct net_device *ndev = NULL; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n", - ieee80211_frequency_to_channel(channel->center_freq), - duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO")); - - if (!cfg->p2p) { - WL_ERR(("cfg->p2p is not initialized\n")); - err = BCME_ERROR; - goto exit; - } - -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - if (wl_get_drv_status_all(cfg, SCANNING)) { - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); - } -#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - - target_channel = ieee80211_frequency_to_channel(channel->center_freq); - memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel)); -#if defined(WL_ENABLE_P2P_IF) - cfg->remain_on_chan_type = channel_type; -#endif /* WL_ENABLE_P2P_IF */ - id = ++cfg->last_roc_id; - if (id == 0) - id = ++cfg->last_roc_id; - *cookie = id; - -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - if (wl_get_drv_status(cfg, SCANNING, ndev)) { - struct timer_list *_timer; - WL_DBG(("scan is running. go to fake listen state\n")); - - wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); - - if (timer_pending(&cfg->p2p->listen_timer)) { - WL_DBG(("cancel current listen timer \n")); - del_timer_sync(&cfg->p2p->listen_timer); - } - - _timer = &cfg->p2p->listen_timer; - wl_clr_p2p_status(cfg, LISTEN_EXPIRED); - - INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0); - - err = BCME_OK; - goto exit; - } -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - -#ifdef WL_CFG80211_SYNC_GON - if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { - /* do not enter listen mode again if we are in listen mode already for next af. - * remain on channel completion will be returned by waiting next af completion. - */ -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); -#else - wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - goto exit; - } -#endif /* WL_CFG80211_SYNC_GON */ - if (cfg->p2p && !cfg->p2p->on) { - /* In case of p2p_listen command, supplicant send remain_on_channel - * without turning on P2P - */ - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr, &cfg->p2p->int_addr); - p2p_on(cfg) = true; - } - - if (p2p_is_on(cfg)) { - err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0); - if (unlikely(err)) { - goto exit; - } -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); -#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - err = wl_cfgp2p_discover_listen(cfg, target_channel, duration); - -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - if (err == BCME_OK) { - wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); - } else { - /* if failed, firmware may be internal scanning state. - * so other scan request shall not abort it - */ - wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); - } -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant - * and expire timer will send a completion to the upper layer - */ - err = BCME_OK; - } - -exit: - if (err == BCME_OK) { - WL_INFORM(("Success\n")); -#if defined(WL_CFG80211_P2P_DEV_IF) - cfg80211_ready_on_channel(cfgdev, *cookie, channel, - duration, GFP_KERNEL); -#else - cfg80211_ready_on_channel(cfgdev, *cookie, channel, - channel_type, duration, GFP_KERNEL); -#endif /* WL_CFG80211_P2P_DEV_IF */ - } else { - WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); - } - return err; -} - -static s32 -wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, - bcm_struct_cfgdev *cfgdev, u64 cookie) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = 0; - - - RETURN_EIO_IF_NOT_UP(cfg); -#if defined(WL_CFG80211_P2P_DEV_IF) - if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { - WL_DBG((" enter ) on P2P dedicated discover interface\n")); - } -#else - WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex)); -#endif /* WL_CFG80211_P2P_DEV_IF */ - - - if (cfg->last_roc_id == cookie) { - wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - } else { - WL_ERR(("%s : ignore, request cookie(%llu) is not matched. (cur : %llu)\n", - __FUNCTION__, cookie, cfg->last_roc_id)); - } - - return err; -} - -static void -wl_cfg80211_afx_handler(struct work_struct *work) -{ - struct afx_hdl *afx_instance; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - s32 ret = BCME_OK; - - afx_instance = container_of(work, struct afx_hdl, work); - if (afx_instance != NULL && cfg->afx_hdl->is_active) { - if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) { - ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan, - (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */ - } else { - ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev, - cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan, - NULL); - } - if (unlikely(ret != BCME_OK)) { - WL_ERR(("ERROR occurred! returned value is (%d)\n", ret)); - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) - complete(&cfg->act_frm_scan); - } - } -} - -static s32 -wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev) -{ - u32 max_retry = WL_CHANNEL_SYNC_RETRY; - - if (dev == NULL) - return -1; - - WL_DBG((" enter ) \n")); - - wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev); - cfg->afx_hdl->is_active = TRUE; - - /* Loop to wait until we find a peer's channel or the - * pending action frame tx is cancelled. - */ - while ((cfg->afx_hdl->retry < max_retry) && - (cfg->afx_hdl->peer_chan == WL_INVALID)) { - cfg->afx_hdl->is_listen = FALSE; - wl_set_drv_status(cfg, SCANNING, dev); - WL_DBG(("Scheduling the action frame for sending.. retry %d\n", - cfg->afx_hdl->retry)); - /* search peer on peer's listen channel */ - schedule_work(&cfg->afx_hdl->work); - wait_for_completion_timeout(&cfg->act_frm_scan, - msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); - - if ((cfg->afx_hdl->peer_chan != WL_INVALID) || - !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) - break; - - if (cfg->afx_hdl->my_listen_chan) { - WL_DBG(("Scheduling Listen peer in my listen channel = %d\n", - cfg->afx_hdl->my_listen_chan)); - /* listen on my listen channel */ - cfg->afx_hdl->is_listen = TRUE; - schedule_work(&cfg->afx_hdl->work); - wait_for_completion_timeout(&cfg->act_frm_scan, - msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); - } - if ((cfg->afx_hdl->peer_chan != WL_INVALID) || - !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) - break; - - cfg->afx_hdl->retry++; - - WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg); - } - - cfg->afx_hdl->is_active = FALSE; - - wl_clr_drv_status(cfg, SCANNING, dev); - wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev); - - return (cfg->afx_hdl->peer_chan); -} - -struct p2p_config_af_params { - s32 max_tx_retry; /* max tx retry count if tx no ack */ - /* To make sure to send successfully action frame, we have to turn off mpc - * 0: off, 1: on, (-1): do nothing - */ - s32 mpc_onoff; -#ifdef WL_CFG80211_SYNC_GON - bool extra_listen; -#endif - bool search_channel; /* 1: search peer's channel to send af */ -}; - -static s32 -wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, - wl_action_frame_t *action_frame, wl_af_params_t *af_params, - struct p2p_config_af_params *config_af_params) -{ - s32 err = BCME_OK; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - wifi_p2p_pub_act_frame_t *act_frm = - (wifi_p2p_pub_act_frame_t *) (action_frame->data); - - /* initialize default value */ -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = true; -#endif - config_af_params->search_channel = false; - config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; - config_af_params->mpc_onoff = -1; - cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; - - switch (act_frm->subtype) { - case P2P_PAF_GON_REQ: { - WL_DBG(("P2P: GO_NEG_PHASE status set \n")); - wl_set_p2p_status(cfg, GO_NEG_PHASE); - - config_af_params->mpc_onoff = 0; - config_af_params->search_channel = true; - cfg->next_af_subtype = act_frm->subtype + 1; - - /* increase dwell time to wait for RESP frame */ - af_params->dwell_time = WL_MED_DWELL_TIME; - - break; - } - case P2P_PAF_GON_RSP: { - cfg->next_af_subtype = act_frm->subtype + 1; - /* increase dwell time to wait for CONF frame */ - af_params->dwell_time = WL_MED_DWELL_TIME + 100; - break; - } - case P2P_PAF_GON_CONF: { - /* If we reached till GO Neg confirmation reset the filter */ - WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - - /* turn on mpc again if go nego is done */ - config_af_params->mpc_onoff = 1; - - /* minimize dwell time */ - af_params->dwell_time = WL_MIN_DWELL_TIME; - -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = false; -#endif /* WL_CFG80211_SYNC_GON */ - break; - } - case P2P_PAF_INVITE_REQ: { - config_af_params->search_channel = true; - cfg->next_af_subtype = act_frm->subtype + 1; - - /* increase dwell time */ - af_params->dwell_time = WL_MED_DWELL_TIME; - break; - } - case P2P_PAF_INVITE_RSP: - /* minimize dwell time */ - af_params->dwell_time = WL_MIN_DWELL_TIME; -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = false; -#endif /* WL_CFG80211_SYNC_GON */ - break; - case P2P_PAF_DEVDIS_REQ: { - if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0], - action_frame->len)) { - config_af_params->search_channel = true; - } - - cfg->next_af_subtype = act_frm->subtype + 1; - /* maximize dwell time to wait for RESP frame */ - af_params->dwell_time = WL_LONG_DWELL_TIME; - break; - } - case P2P_PAF_DEVDIS_RSP: - /* minimize dwell time */ - af_params->dwell_time = WL_MIN_DWELL_TIME; -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = false; -#endif /* WL_CFG80211_SYNC_GON */ - break; - case P2P_PAF_PROVDIS_REQ: { - if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0], - action_frame->len)) { - config_af_params->search_channel = true; - } - - config_af_params->mpc_onoff = 0; - cfg->next_af_subtype = act_frm->subtype + 1; - /* increase dwell time to wait for RESP frame */ - af_params->dwell_time = WL_MED_DWELL_TIME; - break; - } - case P2P_PAF_PROVDIS_RSP: { - cfg->next_af_subtype = P2P_PAF_GON_REQ; - af_params->dwell_time = WL_MIN_DWELL_TIME; -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = false; -#endif /* WL_CFG80211_SYNC_GON */ - break; - } - default: - WL_DBG(("Unknown p2p pub act frame subtype: %d\n", - act_frm->subtype)); - err = BCME_BADARG; - } - return err; -} - -#ifdef WL11U -static bool -wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params, - void *frame, u16 frame_len) -{ - struct wl_scan_results *bss_list; - struct wl_bss_info *bi = NULL; - bool result = false; - s32 i; - chanspec_t chanspec; - - /* If DFS channel is 52~148, check to block it or not */ - if (af_params && - (af_params->channel >= 52 && af_params->channel <= 148)) { - if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) { - bss_list = cfg->bss_list; - bi = next_bss(bss_list, bi); - for_each_bss(bss_list, bi, i) { - chanspec = wl_chspec_driver_to_host(bi->chanspec); - if (CHSPEC_IS5G(chanspec) && - ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec)) - == af_params->channel)) { - result = true; /* do not block the action frame */ - break; - } - } - } - } - else { - result = true; - } - - WL_DBG(("result=%s", result?"true":"false")); - return result; -} -#endif /* WL11U */ - - -static bool -wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, - bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params, - wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) -{ -#ifdef WL11U - struct net_device *ndev = NULL; -#endif /* WL11U */ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - bool ack = false; - u8 category, action; - s32 tx_retry; - struct p2p_config_af_params config_af_params; -#ifdef VSDB - ulong off_chan_started_jiffies = 0; -#endif - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - - - /* Add the default dwell time - * Dwell time to stay off-channel to wait for a response action frame - * after transmitting an GO Negotiation action frame - */ - af_params->dwell_time = WL_DWELL_TIME; - -#ifdef WL11U -#if defined(WL_CFG80211_P2P_DEV_IF) - ndev = dev; -#else - ndev = ndev_to_cfgdev(cfgdev); -#endif /* WL_CFG80211_P2P_DEV_IF */ -#endif /* WL11U */ - - category = action_frame->data[DOT11_ACTION_CAT_OFF]; - action = action_frame->data[DOT11_ACTION_ACT_OFF]; - - /* initialize variables */ - tx_retry = 0; - cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; - config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY; - config_af_params.mpc_onoff = -1; - config_af_params.search_channel = false; -#ifdef WL_CFG80211_SYNC_GON - config_af_params.extra_listen = false; -#endif - - /* config parameters */ - /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */ - if (category == DOT11_ACTION_CAT_PUBLIC) { - if ((action == P2P_PUB_AF_ACTION) && - (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) { - /* p2p public action frame process */ - if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy, - action_frame, af_params, &config_af_params)) { - WL_DBG(("Unknown subtype.\n")); - } - - } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) { - /* service discovery process */ - if (action == P2PSD_ACTION_ID_GAS_IREQ || - action == P2PSD_ACTION_ID_GAS_CREQ) { - /* configure service discovery query frame */ - - config_af_params.search_channel = true; - - /* save next af suptype to cancel remained dwell time */ - cfg->next_af_subtype = action + 1; - - af_params->dwell_time = WL_MED_DWELL_TIME; - } else if (action == P2PSD_ACTION_ID_GAS_IRESP || - action == P2PSD_ACTION_ID_GAS_CRESP) { - /* configure service discovery response frame */ - af_params->dwell_time = WL_MIN_DWELL_TIME; - } else { - WL_DBG(("Unknown action type: %d\n", action)); - } - } else { - WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n", - category, action, action_frame_len)); - } - } else if (category == P2P_AF_CATEGORY) { - /* do not configure anything. it will be sent with a default configuration */ - } else { - WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n", - category, action)); - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev); - return false; - } - } - - /* To make sure to send successfully action frame, we have to turn off mpc */ - if (config_af_params.mpc_onoff == 0) { - wldev_iovar_setint(dev, "mpc", 0); - } - - /* validate channel and p2p ies */ - if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) && - wl_to_p2p_bss_saved_ie(cfg, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { - config_af_params.search_channel = true; - } else { - config_af_params.search_channel = false; - } -#ifdef WL11U - if (ndev == bcmcfg_to_prmry_ndev(cfg)) - config_af_params.search_channel = false; -#endif /* WL11U */ - -#ifdef VSDB - /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ - if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { - OSL_SLEEP(50); - } -#endif - - /* if scan is ongoing, abort current scan. */ - if (wl_get_drv_status_all(cfg, SCANNING)) { - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); - } - - /* Abort P2P listen */ - if (discover_cfgdev(cfgdev, cfg)) { - if (cfg->p2p_supported && cfg->p2p) { - wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - } - } - -#ifdef WL11U - /* handling DFS channel exceptions */ - if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) { - return false; /* the action frame was blocked */ - } -#endif /* WL11U */ - - /* set status and destination address before sending af */ - if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { - /* set this status to cancel the remained dwell time in rx process */ - wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev); - } - wl_set_drv_status(cfg, SENDING_ACT_FRM, dev); - memcpy(cfg->afx_hdl->tx_dst_addr.octet, - af_params->action_frame.da.octet, - sizeof(cfg->afx_hdl->tx_dst_addr.octet)); - - /* save af_params for rx process */ - cfg->afx_hdl->pending_tx_act_frm = af_params; - - if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) { - WL_DBG(("Set GAS action frame config.\n")); - config_af_params.search_channel = false; - config_af_params.max_tx_retry = 1; - } - - /* search peer's channel */ - if (config_af_params.search_channel) { - /* initialize afx_hdl */ - if (wl_cfgp2p_find_idx(cfg, dev, &cfg->afx_hdl->bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - goto exit; - } - cfg->afx_hdl->dev = dev; - cfg->afx_hdl->retry = 0; - cfg->afx_hdl->peer_chan = WL_INVALID; - - if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) { - WL_ERR(("couldn't find peer's channel.\n")); - wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, - af_params->channel); - goto exit; - } - - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - /* - * Abort scan even for VSDB scenarios. Scan gets aborted in firmware - * but after the check of piggyback algorithm. - * To take care of current piggback algo, lets abort the scan here itself. - */ - wl_notify_escan_complete(cfg, dev, true, true); - /* Suspend P2P discovery's search-listen to prevent it from - * starting a scan or changing the channel. - */ - wl_cfgp2p_discover_enable_search(cfg, false); - - /* update channel */ - af_params->channel = cfg->afx_hdl->peer_chan; - } - -#ifdef VSDB - off_chan_started_jiffies = jiffies; -#endif /* VSDB */ - - wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel); - - wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true); - - /* Now send a tx action frame */ - ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true; - - /* if failed, retry it. tx_retry_max value is configure by .... */ - while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) { -#ifdef VSDB - if (af_params->channel) { - if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) > - OFF_CHAN_TIME_THRESHOLD_MS) { - WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg); - off_chan_started_jiffies = jiffies; - } else - OSL_SLEEP(AF_RETRY_DELAY_TIME); - } -#endif /* VSDB */ - ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? - false : true; - } - - if (ack == false) { - WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry)); - } - WL_DBG(("Complete to send action frame\n")); -exit: - /* Clear SENDING_ACT_FRM after all sending af is done */ - wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev); - -#ifdef WL_CFG80211_SYNC_GON - /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. - * if we coundn't get the next action response frame and dongle does not keep - * the dwell time, go to listen state again to get next action response frame. - */ - if (ack && config_af_params.extra_listen && - wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) && - cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) { - s32 extar_listen_time; - - extar_listen_time = af_params->dwell_time - - jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies); - - if (extar_listen_time > 50) { - wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev); - WL_DBG(("Wait more time! actual af time:%d," - "calculated extar listen:%d\n", - af_params->dwell_time, extar_listen_time)); - if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel, - extar_listen_time + 100) == BCME_OK) { - wait_for_completion_timeout(&cfg->wait_next_af, - msecs_to_jiffies(extar_listen_time + 100 + 300)); - } - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev); - } - } -#endif /* WL_CFG80211_SYNC_GON */ - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev); - - if (cfg->afx_hdl->pending_tx_act_frm) - cfg->afx_hdl->pending_tx_act_frm = NULL; - - WL_INFORM(("-- sending Action Frame is %s, listen chan: %d\n", - (ack) ? "Succeeded!!":"Failed!!", cfg->afx_hdl->my_listen_chan)); - - - /* if all done, turn mpc on again */ - if (config_af_params.mpc_onoff == 1) { - wldev_iovar_setint(dev, "mpc", 1); - } - - return ack; -} - -#define MAX_NUM_OF_ASSOCIATED_DEV 64 -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) -static s32 -wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - struct cfg80211_mgmt_tx_params *params, u64 *cookie) -#else -static s32 -wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - struct ieee80211_channel *channel, bool offchan, -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0)) - enum nl80211_channel_type channel_type, - bool channel_type_valid, -#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */ - unsigned int wait, const u8* buf, size_t len, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) - bool no_cck, -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS) - bool dont_wait_for_ack, -#endif - u64 *cookie) -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ -{ - wl_action_frame_t *action_frame; - wl_af_params_t *af_params; - scb_val_t scb_val; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - struct ieee80211_channel *channel = params->chan; - const u8 *buf = params->buf; - size_t len = params->len; -#endif - const struct ieee80211_mgmt *mgmt; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *dev = NULL; - s32 err = BCME_OK; - s32 bssidx = 0; - u32 id; - bool ack = false; - s8 eabuf[ETHER_ADDR_STR_LEN]; - - WL_DBG(("Enter \n")); - - if (len > (ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN)) { - WL_ERR(("bad length:%zu\n", len)); - return BCME_BADARG; - } - dev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if (!dev) { - WL_ERR(("dev is NULL\n")); - return -EINVAL; - } - - /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */ - if (discover_cfgdev(cfgdev, cfg)) { - if (!cfg->p2p_supported || !cfg->p2p) { - WL_ERR(("P2P doesn't setup completed yet\n")); - return -EINVAL; - } - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - } - else { - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - } - - WL_DBG(("TX target bssidx=%d\n", bssidx)); - - if (p2p_is_on(cfg)) { - /* Suspend P2P discovery search-listen to prevent it from changing the - * channel. - */ - if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) { - WL_ERR(("Can not disable discovery mode\n")); - return -EFAULT; - } - } - *cookie = 0; - id = cfg->send_action_id++; - if (id == 0) - id = cfg->send_action_id++; - *cookie = id; - mgmt = (const struct ieee80211_mgmt *)buf; - if (ieee80211_is_mgmt(mgmt->frame_control)) { - if (ieee80211_is_probe_resp(mgmt->frame_control)) { - s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; - s32 ie_len = len - ie_offset; - if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); - cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); - goto exit; - } else if (ieee80211_is_disassoc(mgmt->frame_control) || - ieee80211_is_deauth(mgmt->frame_control)) { - char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * - sizeof(struct ether_addr) + sizeof(uint)] = {0}; - int num_associated = 0; - struct maclist *assoc_maclist = (struct maclist *)mac_buf; - if (!bcmp((const uint8 *)BSSID_BROADCAST, - (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) { - assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; - err = wldev_ioctl(dev, WLC_GET_ASSOCLIST, - assoc_maclist, sizeof(mac_buf), false); - if (err < 0) - WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); - else - num_associated = assoc_maclist->count; - } - memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); - scb_val.val = mgmt->u.disassoc.reason_code; - err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, - sizeof(scb_val_t), true); - if (err < 0) - WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err)); - WL_ERR(("Disconnect STA : %s scb_val.val %d\n", - bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), - scb_val.val)); - - if (num_associated > 0 && ETHER_ISBCAST(mgmt->da)) - wl_delay(400); - - cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); - goto exit; - - } else if (ieee80211_is_action(mgmt->frame_control)) { - /* Abort the dwell time of any previous off-channel - * action frame that may be still in effect. Sending - * off-channel action frames relies on the driver's - * scan engine. If a previous off-channel action frame - * tx is still in progress (including the dwell time), - * then this new action frame will not be sent out. - */ -/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary. - * And previous off-channel action frame must be ended before new af tx. - */ -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_notify_escan_complete(cfg, dev, true, true); -#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - } - - } else { - WL_ERR(("Driver only allows MGMT packet type\n")); - goto exit; - } - - af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); - - if (af_params == NULL) - { - WL_ERR(("unable to allocate frame\n")); - return -ENOMEM; - } - - action_frame = &af_params->action_frame; - - /* Add the packet Id */ - action_frame->packetId = *cookie; - WL_DBG(("action frame %d\n", action_frame->packetId)); - /* Add BSSID */ - memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); - memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN); - - /* Add the length exepted for 802.11 header */ - action_frame->len = len - DOT11_MGMT_HDR_LEN; - WL_DBG(("action_frame->len: %d\n", action_frame->len)); - - /* Add the channel */ - af_params->channel = - ieee80211_frequency_to_channel(channel->center_freq); - /* Save listen_chan for searching common channel */ - cfg->afx_hdl->peer_listen_chan = af_params->channel; - WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan)); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - af_params->dwell_time = params->wait; -#else - af_params->dwell_time = wait; -#endif - - memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); - - ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params, - action_frame, action_frame->len, bssidx); - cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL); - - kfree(af_params); -exit: - return err; -} - - -static void -wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - u16 frame_type, bool reg) -{ - - WL_DBG(("frame_type: %x, reg: %d\n", frame_type, reg)); - - if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) - return; - - return; -} - - -static s32 -wl_cfg80211_change_bss(struct wiphy *wiphy, - struct net_device *dev, - struct bss_parameters *params) -{ - s32 err = 0; - s32 ap_isolate = 0; -#ifdef PCIE_FULL_DONGLE - s32 ifidx = DHD_BAD_IF; -#endif -#if defined(SUPPORT_HOSTAPD_BGN_MODE) - s32 gmode = -1, nmode = -1; - s32 gmode_prev = -1, nmode_prev = -1; -#endif /* SUPPORT_HOSTAPD_BGN_MODE */ -#if defined(PCIE_FULL_DONGLE) || defined(SUPPORT_HOSTAPD_BGN_MODE) - dhd_pub_t *dhd; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd = (dhd_pub_t *)(cfg->pub); -#if defined(WL_ENABLE_P2P_IF) - if (cfg->p2p_net == dev) - dev = bcmcfg_to_prmry_ndev(cfg); -#endif -#endif /* PCIE_FULL_DONGLE || SUPPORT_HOSTAPD_BGN_MODE */ - - if (params->use_cts_prot >= 0) { - } - - if (params->use_short_preamble >= 0) { - } - - if (params->use_short_slot_time >= 0) { - } - - if (params->basic_rates) { -#if defined(SUPPORT_HOSTAPD_BGN_MODE) - switch ((int)(params->basic_rates[params->basic_rates_len -1])) { - case 22: /* B only , rate 11 */ - gmode = 0; - nmode = 0; - break; - case 108: /* G only , rate 54 */ - gmode = 2; - nmode = 0; - break; - default: - gmode = -1; - nmode = -1; - break; - } -#endif /* SUPPORT_HOSTAPD_BGN_MODE */ - } - - if (params->ap_isolate >= 0) { - ap_isolate = params->ap_isolate; -#ifdef PCIE_FULL_DONGLE - ifidx = dhd_net2idx(dhd->info, dev); - - if (ifidx != DHD_BAD_IF) { - err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate); - } else { - WL_ERR(("Failed to set ap_isolate\n")); - } -#else - err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate); - if (unlikely(err)) - { - WL_ERR(("set ap_isolate Error (%d)\n", err)); - } -#endif /* PCIE_FULL_DONGLE */ - } - - if (params->ht_opmode >= 0) { -#if defined(SUPPORT_HOSTAPD_BGN_MODE) - nmode = 1; - gmode = 1; - } else { - nmode = 0; -#endif /* SUPPORT_HOSTAPD_BGN_MODE */ - } - -#if defined(SUPPORT_HOSTAPD_BGN_MODE) - err = wldev_iovar_getint(dev, "nmode", &nmode_prev); - if (unlikely(err)) { - WL_ERR(("error reading nmode (%d)\n", err)); - } - if (nmode == nmode_prev) { - nmode = -1; - } - err = wldev_ioctl(dev, WLC_GET_GMODE, &gmode_prev, sizeof(gmode_prev), 0); - if (unlikely(err)) { - WL_ERR(("error reading gmode (%d)\n", err)); - } - if (gmode == gmode_prev) { - gmode = -1; - } - - if (((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) == DHD_FLAG_HOSTAP_MODE) && - ((gmode > -1) || (nmode > -1))) { - s32 val = 0; - - err = wldev_ioctl(dev, WLC_DOWN, &val, sizeof(s32), true); - if (unlikely(err)) - WL_ERR(("WLC_DOWN command failed:[%d]\n", err)); - - if (nmode > -1) { - err = wldev_iovar_setint(dev, "nmode", nmode); - if (unlikely(err)) - WL_ERR(("nmode command failed:mode[%d]:err[%d]\n", nmode, err)); - } - - if (gmode > -1) { - err = wldev_ioctl(dev, WLC_SET_GMODE, &gmode, sizeof(s32), true); - if (unlikely(err)) - WL_ERR(("WLC_SET_GMODE command failed:mode[%d]:err[%d]\n", - gmode, err)); - } - - val = 0; - err = wldev_ioctl(dev, WLC_UP, &val, sizeof(s32), true); - if (unlikely(err)) - WL_ERR(("WLC_UP command failed:err[%d]\n", err)); - - } -#endif /* SUPPORT_HOSTAPD_BGN_MODE */ - - return err; -} - -static s32 -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS)) -wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_channel *chan, - struct cfg80211_chan_def chandef) -#else -wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */ -{ - s32 _chan; - chanspec_t chspec = 0; - chanspec_t fw_chspec = 0; - u32 bw = WL_CHANSPEC_BW_20; - - s32 err = BCME_OK; - s32 bw_cap = 0; - struct { - u32 band; - u32 bw_cap; - } param = {0, 0}; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); -#ifdef CUSTOM_SET_CPUCORE - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif /* CUSTOM_SET_CPUCORE */ - -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS)) - enum nl80211_channel_type channel_type = NL80211_CHAN_HT20; -#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */ - - dev = ndev_to_wlc_ndev(dev, cfg); - _chan = ieee80211_frequency_to_channel(chan->center_freq); - WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", - dev->ifindex, channel_type, _chan)); - -#if defined(CUSTOMER_HW5) -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_COMPAT_WIRELESS)) - WL_ERR(("chan_width = %d\n", chandef.width)); - switch (chandef.width) { - case NL80211_CHAN_WIDTH_40: - bw = WL_CHANSPEC_BW_40; - break; - case NL80211_CHAN_WIDTH_80: - bw = WL_CHANSPEC_BW_80; - break; - case NL80211_CHAN_WIDTH_80P80: - bw = WL_CHANSPEC_BW_8080; - break; - case NL80211_CHAN_WIDTH_160: - bw = WL_CHANSPEC_BW_160; - break; - default: - bw = WL_CHANSPEC_BW_20; - break; - } - goto set_channel; -#endif /* ((LINUX_VERSION >= VERSION(3, 8, 0) && !WL_COMPAT_WIRELESS) */ -#endif - - if (chan->band == IEEE80211_BAND_5GHZ) { - param.band = WLC_BAND_5G; - err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), - cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); - if (err) { - if (err != BCME_UNSUPPORTED) { - WL_ERR(("bw_cap failed, %d\n", err)); - return err; - } else { - err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); - if (err) { - WL_ERR(("error get mimo_bw_cap (%d)\n", err)); - } - if (bw_cap != WLC_N_BW_20ALL) - bw = WL_CHANSPEC_BW_40; - } - } else { - if (WL_BW_CAP_80MHZ(cfg->ioctl_buf[0])) - bw = WL_CHANSPEC_BW_80; - else if (WL_BW_CAP_40MHZ(cfg->ioctl_buf[0])) - bw = WL_CHANSPEC_BW_40; - else - bw = WL_CHANSPEC_BW_20; - - } - - } else if (chan->band == IEEE80211_BAND_2GHZ) - bw = WL_CHANSPEC_BW_20; -set_channel: - chspec = wf_channel2chspec(_chan, bw); - if (wf_chspec_valid(chspec)) { - fw_chspec = wl_chspec_host_to_driver(chspec); - if (fw_chspec != INVCHANSPEC) { - if ((err = wldev_iovar_setint(dev, "chanspec", - fw_chspec)) == BCME_BADCHAN) { - if (bw == WL_CHANSPEC_BW_80) - goto change_bw; - err = wldev_ioctl(dev, WLC_SET_CHANNEL, - &_chan, sizeof(_chan), true); - if (err < 0) { - WL_ERR(("WLC_SET_CHANNEL error %d" - "chip may not be supporting this channel\n", err)); - } - } else if (err) { - WL_ERR(("failed to set chanspec error %d\n", err)); - } - } else { - WL_ERR(("failed to convert host chanspec to fw chanspec\n")); - err = BCME_ERROR; - } - } else { -change_bw: - if (bw == WL_CHANSPEC_BW_80) - bw = WL_CHANSPEC_BW_40; - else if (bw == WL_CHANSPEC_BW_40) - bw = WL_CHANSPEC_BW_20; - else - bw = 0; - if (bw) - goto set_channel; - WL_ERR(("Invalid chanspec 0x%x\n", chspec)); - err = BCME_ERROR; - } -#ifdef CUSTOM_SET_CPUCORE - if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) { - WL_DBG(("SoftAP mode do not need to set cpucore\n")); - } else if ((dev == wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) && - (chspec & WL_CHANSPEC_BW_80)) { - /* If GO is vht80 */ - dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE; - dhd_set_cpucore(dhd, TRUE); - } -#endif /* CUSTOM_SET_CPUCORE */ - return err; -} - -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -struct net_device * -wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg) -{ - struct net_info *_net_info, *next; - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (_net_info->ndev && - test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state)) - return _net_info->ndev; - } - return NULL; -} -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - -static s32 -wl_validate_opensecurity(struct net_device *dev, s32 bssidx) -{ - s32 err = BCME_OK; - - /* set auth */ - err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx); - if (err < 0) { - WL_ERR(("auth error %d\n", err)); - return BCME_ERROR; - } - /* set wsec */ - err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); - if (err < 0) { - WL_ERR(("wsec error %d\n", err)); - return BCME_ERROR; - } - - /* set upper-layer auth */ - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WPA_AUTH_NONE, bssidx); - if (err < 0) { - WL_ERR(("wpa_auth error %d\n", err)); - return BCME_ERROR; - } - - return 0; -} - -static s32 -wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) -{ - s32 len = 0; - s32 err = BCME_OK; - u16 auth = 0; /* d11 open authentication */ - u32 wsec; - u32 pval = 0; - u32 gval = 0; - u32 wpa_auth = 0; - wpa_suite_mcast_t *mcast; - wpa_suite_ucast_t *ucast; - wpa_suite_auth_key_mgmt_t *mgmt; - wpa_pmkid_list_t *pmkid; - int cnt = 0; -#ifdef MFP - int mfp = 0; - struct bcm_cfg80211 *cfg = g_bcm_cfg; -#endif /* MFP */ - - u16 suite_count; - u8 rsn_cap[2]; - u32 wme_bss_disable; - - if (wpa2ie == NULL) - goto exit; - - WL_DBG(("Enter \n")); - len = wpa2ie->len - WPA2_VERSION_LEN; - /* check the mcast cipher */ - mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; - switch (mcast->type) { - case WPA_CIPHER_NONE: - gval = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - gval = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - gval = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - gval = AES_ENABLED; - break; -#ifdef BCMWAPI_WPI - case WAPI_CIPHER_SMS4: - gval = SMS4_ENABLED; - break; -#endif - default: - WL_ERR(("No Security Info\n")); - break; - } - if ((len -= WPA_SUITE_LEN) <= 0) - return BCME_BADLEN; - - /* check the unicast cipher */ - ucast = (wpa_suite_ucast_t *)&mcast[1]; - suite_count = ltoh16_ua(&ucast->count); - switch (ucast->list[0].type) { - case WPA_CIPHER_NONE: - pval = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - pval = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - pval = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - pval = AES_ENABLED; - break; -#ifdef BCMWAPI_WPI - case WAPI_CIPHER_SMS4: - pval = SMS4_ENABLED; - break; -#endif - default: - WL_ERR(("No Security Info\n")); - } - if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0) - return BCME_BADLEN; - - /* FOR WPS , set SEC_OW_ENABLED */ - wsec = (pval | gval | SES_OW_ENABLED); - /* check the AKM */ - mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; - suite_count = cnt = ltoh16_ua(&mgmt->count); - while (cnt--) { - switch (mgmt->list[cnt].type) { - case RSN_AKM_NONE: - wpa_auth = WPA_AUTH_NONE; - break; - case RSN_AKM_UNSPECIFIED: - wpa_auth = WPA2_AUTH_UNSPECIFIED; - break; - case RSN_AKM_PSK: - wpa_auth = WPA2_AUTH_PSK; - break; -#ifdef MFP - case RSN_AKM_MFP_PSK: - wpa_auth |= WPA2_AUTH_PSK; - wsec |= MFP_SHA256; - break; - case RSN_AKM_MFP_1X: - wpa_auth |= WPA2_AUTH_UNSPECIFIED; - wsec |= MFP_SHA256; - break; -#endif /* MFP */ - default: - WL_ERR(("No Key Mgmt Info\n")); - } - } - - if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { - rsn_cap[0] = *(u8 *)&mgmt->list[suite_count]; - rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1); - - if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) { - wme_bss_disable = 0; - } else { - wme_bss_disable = 1; - } - -#ifdef MFP - if (rsn_cap[0] & RSN_CAP_MFPR) { - WL_DBG(("MFP Required \n")); - mfp = WL_MFP_REQUIRED; - } else if (rsn_cap[0] & RSN_CAP_MFPC) { - WL_DBG(("MFP Capable \n")); - mfp = WL_MFP_CAPABLE; - } -#endif /* MFP */ - - /* set wme_bss_disable to sync RSN Capabilities */ - err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx); - if (err < 0) { - WL_ERR(("wme_bss_disable error %d\n", err)); - return BCME_ERROR; - } - } else { - WL_DBG(("There is no RSN Capabilities. remained len %d\n", len)); - } - - if ((len -= RSN_CAP_LEN) >= WPA2_PMKID_COUNT_LEN) { - pmkid = (wpa_pmkid_list_t *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN); - cnt = ltoh16_ua(&pmkid->count); - if (cnt != 0) { - WL_ERR(("AP has non-zero PMKID count. Wrong!\n")); - return BCME_ERROR; - } - /* since PMKID cnt is known to be 0 for AP, */ - /* so don't bother to send down this info to firmware */ - } - -#ifdef MFP - if ((len -= WPA2_PMKID_COUNT_LEN) >= RSN_GROUPMANAGE_CIPHER_LEN) { - err = wldev_iovar_setbuf_bsscfg(dev, "bip", - (void *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN), - RSN_GROUPMANAGE_CIPHER_LEN, - cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync); - if (err < 0) { - WL_ERR(("bip set error %d\n", err)); - return BCME_ERROR; - } - } -#endif - - /* set auth */ - err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); - if (err < 0) { - WL_ERR(("auth error %d\n", err)); - return BCME_ERROR; - } - /* set wsec */ - err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); - if (err < 0) { - WL_ERR(("wsec error %d\n", err)); - return BCME_ERROR; - } - -#ifdef MFP - if (mfp) { - /* This needs to go after wsec otherwise the wsec command will - * overwrite the values set by MFP - */ - if ((err = wldev_iovar_setint_bsscfg(dev, "mfp", mfp, bssidx)) < 0) { - WL_ERR(("MFP Setting failed. ret = %d \n", err)); - return err; - } - } -#endif /* MFP */ - - /* set upper-layer auth */ - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); - if (err < 0) { - WL_ERR(("wpa_auth error %d\n", err)); - return BCME_ERROR; - } -exit: - return 0; -} - -static s32 -wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) -{ - wpa_suite_mcast_t *mcast; - wpa_suite_ucast_t *ucast; - wpa_suite_auth_key_mgmt_t *mgmt; - u16 auth = 0; /* d11 open authentication */ - u16 count; - s32 err = BCME_OK; - s32 len = 0; - u32 i; - u32 wsec; - u32 pval = 0; - u32 gval = 0; - u32 wpa_auth = 0; - u32 tmp = 0; - - if (wpaie == NULL) - goto exit; - WL_DBG(("Enter \n")); - len = wpaie->length; /* value length */ - len -= WPA_IE_TAG_FIXED_LEN; - /* check for multicast cipher suite */ - if (len < WPA_SUITE_LEN) { - WL_INFORM(("no multicast cipher suite\n")); - goto exit; - } - - /* pick up multicast cipher */ - mcast = (wpa_suite_mcast_t *)&wpaie[1]; - len -= WPA_SUITE_LEN; - if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) { - if (IS_WPA_CIPHER(mcast->type)) { - tmp = 0; - switch (mcast->type) { - case WPA_CIPHER_NONE: - tmp = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - tmp = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - tmp = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - tmp = AES_ENABLED; - break; - default: - WL_ERR(("No Security Info\n")); - } - gval |= tmp; - } - } - /* Check for unicast suite(s) */ - if (len < WPA_IE_SUITE_COUNT_LEN) { - WL_INFORM(("no unicast suite\n")); - goto exit; - } - /* walk thru unicast cipher list and pick up what we recognize */ - ucast = (wpa_suite_ucast_t *)&mcast[1]; - count = ltoh16_ua(&ucast->count); - len -= WPA_IE_SUITE_COUNT_LEN; - for (i = 0; i < count && len >= WPA_SUITE_LEN; - i++, len -= WPA_SUITE_LEN) { - if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { - if (IS_WPA_CIPHER(ucast->list[i].type)) { - tmp = 0; - switch (ucast->list[i].type) { - case WPA_CIPHER_NONE: - tmp = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - tmp = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - tmp = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - tmp = AES_ENABLED; - break; - default: - WL_ERR(("No Security Info\n")); - } - pval |= tmp; - } - } - } - len -= (count - i) * WPA_SUITE_LEN; - /* Check for auth key management suite(s) */ - if (len < WPA_IE_SUITE_COUNT_LEN) { - WL_INFORM((" no auth key mgmt suite\n")); - goto exit; - } - /* walk thru auth management suite list and pick up what we recognize */ - mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count]; - count = ltoh16_ua(&mgmt->count); - len -= WPA_IE_SUITE_COUNT_LEN; - for (i = 0; i < count && len >= WPA_SUITE_LEN; - i++, len -= WPA_SUITE_LEN) { - if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { - if (IS_WPA_AKM(mgmt->list[i].type)) { - tmp = 0; - switch (mgmt->list[i].type) { - case RSN_AKM_NONE: - tmp = WPA_AUTH_NONE; - break; - case RSN_AKM_UNSPECIFIED: - tmp = WPA_AUTH_UNSPECIFIED; - break; - case RSN_AKM_PSK: - tmp = WPA_AUTH_PSK; - break; - default: - WL_ERR(("No Key Mgmt Info\n")); - } - wpa_auth |= tmp; - } - } - - } - /* FOR WPS , set SEC_OW_ENABLED */ - wsec = (pval | gval | SES_OW_ENABLED); - /* set auth */ - err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); - if (err < 0) { - WL_ERR(("auth error %d\n", err)); - return BCME_ERROR; - } - /* set wsec */ - err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); - if (err < 0) { - WL_ERR(("wsec error %d\n", err)); - return BCME_ERROR; - } - /* set upper-layer auth */ - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); - if (err < 0) { - WL_ERR(("wpa_auth error %d\n", err)); - return BCME_ERROR; - } -exit: - return 0; -} - - -static s32 -wl_cfg80211_bcn_validate_sec( - struct net_device *dev, - struct parsed_ies *ies, - u32 dev_role, - s32 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) { - /* For P2P GO, the sec type is WPA2-PSK */ - WL_DBG(("P2P GO: validating wpa2_ie")); - if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0) - return BCME_ERROR; - - } else if (dev_role == NL80211_IFTYPE_AP) { - - WL_DBG(("SoftAP: validating security")); - /* If wpa2_ie or wpa_ie is present validate it */ - - if ((ies->wpa2_ie || ies->wpa_ie) && - ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || - wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) { - cfg->ap_info->security_mode = false; - return BCME_ERROR; - } - - cfg->ap_info->security_mode = true; - if (cfg->ap_info->rsn_ie) { - kfree(cfg->ap_info->rsn_ie); - cfg->ap_info->rsn_ie = NULL; - } - if (cfg->ap_info->wpa_ie) { - kfree(cfg->ap_info->wpa_ie); - cfg->ap_info->wpa_ie = NULL; - } - if (cfg->ap_info->wps_ie) { - kfree(cfg->ap_info->wps_ie); - cfg->ap_info->wps_ie = NULL; - } - if (ies->wpa_ie != NULL) { - /* WPAIE */ - cfg->ap_info->rsn_ie = NULL; - cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, - ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } else if (ies->wpa2_ie != NULL) { - /* RSNIE */ - cfg->ap_info->wpa_ie = NULL; - cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, - ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } - if (!ies->wpa2_ie && !ies->wpa_ie) { - wl_validate_opensecurity(dev, bssidx); - cfg->ap_info->security_mode = false; - } - - if (ies->wps_ie) { - cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); - } - } - - return 0; - -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) -static s32 wl_cfg80211_bcn_set_params( - struct cfg80211_ap_settings *info, - struct net_device *dev, - u32 dev_role, s32 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - s32 err = BCME_OK; - - WL_DBG(("interval (%d) \ndtim_period (%d) \n", - info->beacon_interval, info->dtim_period)); - - if (info->beacon_interval) { - if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, - &info->beacon_interval, sizeof(s32), true)) < 0) { - WL_ERR(("Beacon Interval Set Error, %d\n", err)); - return err; - } - } - - if (info->dtim_period) { - if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, - &info->dtim_period, sizeof(s32), true)) < 0) { - WL_ERR(("DTIM Interval Set Error, %d\n", err)); - return err; - } - } - - if ((info->ssid) && (info->ssid_len > 0) && - (info->ssid_len <= DOT11_MAX_SSID_LEN)) { - WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len)); - if (dev_role == NL80211_IFTYPE_AP) { - /* Store the hostapd SSID */ - memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); - memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len); - cfg->hostapd_ssid.SSID_len = info->ssid_len; - - } else { - /* P2P GO */ - memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); - memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len); - cfg->p2p->ssid.SSID_len = info->ssid_len; - } - } - - if (info->hidden_ssid) { - if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) - WL_ERR(("failed to set hidden : %d\n", err)); - WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid)); - } - - return err; -} -#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */ - -static s32 -wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies) -{ - s32 err = BCME_OK; - - memset(ies, 0, sizeof(struct parsed_ies)); - - /* find the WPSIE */ - if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) { - WL_DBG(("WPSIE in beacon \n")); - ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; - } else { - WL_ERR(("No WPSIE in beacon \n")); - } - - /* find the RSN_IE */ - if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, - DOT11_MNG_RSN_ID)) != NULL) { - WL_DBG((" WPA2 IE found\n")); - ies->wpa2_ie_len = ies->wpa2_ie->len; - } - - /* find the WPA_IE */ - if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) { - WL_DBG((" WPA found\n")); - ies->wpa_ie_len = ies->wpa_ie->length; - } - - return err; - -} - -static s32 -wl_cfg80211_bcn_bringup_ap( - struct net_device *dev, - struct parsed_ies *ies, - u32 dev_role, s32 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_join_params join_params; - bool is_bssup = false; - s32 infra = 1; - s32 join_params_size = 0; - s32 ap = 1; -#ifdef DISABLE_11H_SOFTAP - s32 spect = 0; -#endif /* DISABLE_11H_SOFTAP */ - s32 err = BCME_OK; - - WL_DBG(("Enter dev_role: %d\n", dev_role)); - - /* Common code for SoftAP and P2P GO */ - wldev_iovar_setint(dev, "mpc", 0); - - if (dev_role == NL80211_IFTYPE_P2P_GO) { - is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); - if (!is_bssup && (ies->wpa2_ie != NULL)) { - - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET INFRA error %d\n", err)); - goto exit; - } - - err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid, - sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, - bssidx, &cfg->ioctl_buf_sync); - if (err < 0) { - WL_ERR(("GO SSID setting error %d\n", err)); - goto exit; - } - - /* Do abort scan before creating GO */ - wl_cfg80211_scan_abort(cfg); - - if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) { - WL_ERR(("GO Bring up error %d\n", err)); - goto exit; - } - } else - WL_DBG(("Bss is already up\n")); - } else if ((dev_role == NL80211_IFTYPE_AP) && - (wl_get_drv_status(cfg, AP_CREATING, dev))) { - /* Device role SoftAP */ - err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); - if (err < 0) { - WL_ERR(("WLC_DOWN error %d\n", err)); - goto exit; - } - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET INFRA error %d\n", err)); - goto exit; - } - if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { - WL_ERR(("setting AP mode failed %d \n", err)); - goto exit; - } -#ifdef DISABLE_11H_SOFTAP - err = wldev_ioctl(dev, WLC_SET_SPECT_MANAGMENT, - &spect, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET SPECT_MANAGMENT error %d\n", err)); - goto exit; - } -#endif /* DISABLE_11H_SOFTAP */ - - err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); - if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); - goto exit; - } - - memset(&join_params, 0, sizeof(join_params)); - /* join parameters starts with ssid */ - join_params_size = sizeof(join_params.ssid); - join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len, - DOT11_MAX_SSID_LEN); - memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID, - join_params.ssid.SSID_len); - join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); - - /* create softap */ - if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - join_params_size, true)) == 0) { - WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID)); - wl_clr_drv_status(cfg, AP_CREATING, dev); - wl_set_drv_status(cfg, AP_CREATED, dev); - } - } - - -exit: - return err; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) -s32 -wl_cfg80211_parse_ap_ies( - struct net_device *dev, - struct cfg80211_beacon_data *info, - struct parsed_ies *ies) -{ - struct parsed_ies prb_ies; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - u8 *vndr = NULL; - u32 vndr_ie_len = 0; - s32 err = BCME_OK; - - /* Parse Beacon IEs */ - if (wl_cfg80211_parse_ies((u8 *)info->tail, - info->tail_len, ies) < 0) { - WL_ERR(("Beacon get IEs failed \n")); - err = -EINVAL; - goto fail; - } - - vndr = (u8 *)info->proberesp_ies; - vndr_ie_len = info->proberesp_ies_len; - - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - /* SoftAP mode */ - struct ieee80211_mgmt *mgmt; - mgmt = (struct ieee80211_mgmt *)info->probe_resp; - if (mgmt != NULL) { - vndr = (u8 *)&mgmt->u.probe_resp.variable; - vndr_ie_len = info->probe_resp_len - - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - } - } - - /* Parse Probe Response IEs */ - if (wl_cfg80211_parse_ies(vndr, vndr_ie_len, &prb_ies) < 0) { - WL_ERR(("PROBE RESP get IEs failed \n")); - err = -EINVAL; - } - -fail: - - return err; -} - -s32 -wl_cfg80211_set_ies( - struct net_device *dev, - struct cfg80211_beacon_data *info, - s32 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - u8 *vndr = NULL; - u32 vndr_ie_len = 0; - s32 err = BCME_OK; - - /* Set Beacon IEs to FW */ - if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_BEACON_FLAG, (u8 *)info->tail, - info->tail_len)) < 0) { - WL_ERR(("Set Beacon IE Failed \n")); - } else { - WL_DBG(("Applied Vndr IEs for Beacon \n")); - } - - vndr = (u8 *)info->proberesp_ies; - vndr_ie_len = info->proberesp_ies_len; - - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - /* SoftAP mode */ - struct ieee80211_mgmt *mgmt; - mgmt = (struct ieee80211_mgmt *)info->probe_resp; - if (mgmt != NULL) { - vndr = (u8 *)&mgmt->u.probe_resp.variable; - vndr_ie_len = info->probe_resp_len - - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - } - } - - /* Set Probe Response IEs to FW */ - if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) { - WL_ERR(("Set Probe Resp IE Failed \n")); - } else { - WL_DBG(("Applied Vndr IEs for Probe Resp \n")); - } - - return err; -} -#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */ - -static s32 wl_cfg80211_hostapd_sec( - struct net_device *dev, - struct parsed_ies *ies, - s32 bssidx) -{ - bool update_bss = 0; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - - if (ies->wps_ie) { - if (cfg->ap_info->wps_ie && - memcmp(cfg->ap_info->wps_ie, ies->wps_ie, ies->wps_ie_len)) { - WL_DBG((" WPS IE is changed\n")); - kfree(cfg->ap_info->wps_ie); - cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); - } else if (cfg->ap_info->wps_ie == NULL) { - WL_DBG((" WPS IE is added\n")); - cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); - } - - if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) { - if (!cfg->ap_info->security_mode) { - /* change from open mode to security mode */ - update_bss = true; - if (ies->wpa_ie != NULL) { - cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, - ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } else { - cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, - ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } - } else if (cfg->ap_info->wpa_ie) { - /* change from WPA2 mode to WPA mode */ - if (ies->wpa_ie != NULL) { - update_bss = true; - kfree(cfg->ap_info->rsn_ie); - cfg->ap_info->rsn_ie = NULL; - cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, - ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } else if (memcmp(cfg->ap_info->rsn_ie, - ies->wpa2_ie, ies->wpa2_ie->len - + WPA_RSN_IE_TAG_FIXED_LEN)) { - update_bss = true; - kfree(cfg->ap_info->rsn_ie); - cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, - ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - cfg->ap_info->wpa_ie = NULL; - } - } - if (update_bss) { - cfg->ap_info->security_mode = true; - wl_cfgp2p_bss(cfg, dev, bssidx, 0); - if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || - wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) { - return BCME_ERROR; - } - wl_cfgp2p_bss(cfg, dev, bssidx, 1); - } - } - } else { - WL_ERR(("No WPSIE in beacon \n")); - } - return 0; -} - -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 2, 0)) -static s32 -wl_cfg80211_del_station( - struct wiphy *wiphy, - struct net_device *ndev, - u8* mac_addr) -{ - struct net_device *dev; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - scb_val_t scb_val; - s8 eabuf[ETHER_ADDR_STR_LEN]; - int err; - char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * - sizeof(struct ether_addr) + sizeof(uint)] = {0}; - struct maclist *assoc_maclist = (struct maclist *)mac_buf; - int num_associated = 0; - - WL_DBG(("Entry\n")); - if (mac_addr == NULL) { - WL_DBG(("mac_addr is NULL ignore it\n")); - return 0; - } - - dev = ndev_to_wlc_ndev(ndev, cfg); - - if (p2p_is_on(cfg)) { - /* Suspend P2P discovery search-listen to prevent it from changing the - * channel. - */ - if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) { - WL_ERR(("Can not disable discovery mode\n")); - return -EFAULT; - } - } - - assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; - err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST, - assoc_maclist, sizeof(mac_buf), false); - if (err < 0) - WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); - else - num_associated = assoc_maclist->count; - - memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN); - scb_val.val = DOT11_RC_DEAUTH_LEAVING; - err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, - sizeof(scb_val_t), true); - if (err < 0) - WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err)); - WL_ERR(("Disconnect STA : %s scb_val.val %d\n", - bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf), - scb_val.val)); - - if (num_associated > 0 && ETHER_ISBCAST(mac_addr)) - wl_delay(400); - - return 0; -} - -static s32 -wl_cfg80211_change_station( - struct wiphy *wiphy, - struct net_device *dev, - u8 *mac, - struct station_parameters *params) -{ - int err; - - WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x " - "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac), - params->sta_flags_mask, params->sta_flags_set, dev->name)); - - /* Processing only authorize/de-authorize flag for now */ - if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) { - WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n")); - return -ENOTSUPP; - } - - if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) { - err = wldev_ioctl(dev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN, true); - if (err) - WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err)); - return err; - } - - err = wldev_ioctl(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true); - if (err) - WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err)); - return err; -} -#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) -static s32 -wl_cfg80211_start_ap( - struct wiphy *wiphy, - struct net_device *dev, - struct cfg80211_ap_settings *info) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = BCME_OK; - struct parsed_ies ies; - s32 bssidx = 0; - u32 dev_role = 0; - - WL_DBG(("Enter \n")); - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - WL_DBG(("Start AP req on primary iface: Softap\n")); - dev_role = NL80211_IFTYPE_AP; - } -#if defined(WL_ENABLE_P2P_IF) - else if (dev == cfg->p2p_net) { - /* Group Add request on p2p0 */ - WL_DBG(("Start AP req on P2P iface: GO\n")); - dev = bcmcfg_to_prmry_ndev(cfg); - dev_role = NL80211_IFTYPE_P2P_GO; - } -#endif /* WL_ENABLE_P2P_IF */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (p2p_is_on(cfg) && - (bssidx == wl_to_p2p_bss_bssidx(cfg, - P2PAPI_BSSCFG_CONNECTION))) { - dev_role = NL80211_IFTYPE_P2P_GO; - WL_DBG(("Start AP req on P2P connection iface\n")); - } - - if (!check_dev_role_integrity(cfg, dev_role)) - goto fail; - -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS)) - if ((err = wl_cfg80211_set_channel(wiphy, dev, - dev->ieee80211_ptr->preset_chandef.chan, - dev->ieee80211_ptr->preset_chandef) < 0)) { - WL_ERR(("Set channel failed \n")); - goto fail; - } -#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */ - - if ((err = wl_cfg80211_bcn_set_params(info, dev, - dev_role, bssidx)) < 0) { - WL_ERR(("Beacon params set failed \n")); - goto fail; - } - - /* Parse IEs */ - if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) { - WL_ERR(("Set IEs failed \n")); - goto fail; - } - - if ((wl_cfg80211_bcn_validate_sec(dev, &ies, - dev_role, bssidx)) < 0) - { - WL_ERR(("Beacon set security failed \n")); - goto fail; - } - - if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, - dev_role, bssidx)) < 0) { - WL_ERR(("Beacon bring up AP/GO failed \n")); - goto fail; - } - - WL_DBG(("** AP/GO Created **\n")); - -#ifdef WL_CFG80211_ACL - /* Enfoce Admission Control. */ - if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) { - WL_ERR(("Set ACL failed\n")); - } -#endif /* WL_CFG80211_ACL */ - - /* Set IEs to FW */ - if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0) - WL_ERR(("Set IEs failed \n")); - - /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ - if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) { - bool pbc = 0; - wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); - if (pbc) { - WL_DBG(("set WLC_E_PROBREQ_MSG\n")); - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); - } - } - -fail: - if (err) { - WL_ERR(("ADD/SET beacon failed\n")); - wldev_iovar_setint(dev, "mpc", 1); - } - - return err; -} - -static s32 -wl_cfg80211_stop_ap( - struct wiphy *wiphy, - struct net_device *dev) -{ - int err = 0; - u32 dev_role = 0; - int infra = 0; - int ap = 0; - s32 bssidx = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - WL_DBG(("Enter \n")); - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - dev_role = NL80211_IFTYPE_AP; - } -#if defined(WL_ENABLE_P2P_IF) - else if (dev == cfg->p2p_net) { - /* Group Add request on p2p0 */ - dev = bcmcfg_to_prmry_ndev(cfg); - dev_role = NL80211_IFTYPE_P2P_GO; - } -#endif /* WL_ENABLE_P2P_IF */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (p2p_is_on(cfg) && - (bssidx == wl_to_p2p_bss_bssidx(cfg, - P2PAPI_BSSCFG_CONNECTION))) { - dev_role = NL80211_IFTYPE_P2P_GO; - } - - if (!check_dev_role_integrity(cfg, dev_role)) - goto exit; - - if (dev_role == NL80211_IFTYPE_AP) { - /* SoftAp on primary Interface. - * Shut down AP and turn on MPC - */ - if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { - WL_ERR(("setting AP mode failed %d \n", err)); - err = -ENOTSUPP; - goto exit; - } - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET INFRA error %d\n", err)); - err = -ENOTSUPP; - goto exit; - } - - err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); - if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); - err = -EINVAL; - goto exit; - } - - wl_clr_drv_status(cfg, AP_CREATED, dev); - /* Turn on the MPC */ - wldev_iovar_setint(dev, "mpc", 1); - if (cfg->ap_info) { - kfree(cfg->ap_info->wpa_ie); - kfree(cfg->ap_info->rsn_ie); - kfree(cfg->ap_info->wps_ie); - kfree(cfg->ap_info); - cfg->ap_info = NULL; - } - } else { - WL_DBG(("Stopping P2P GO \n")); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub), - DHD_EVENT_TIMEOUT_MS*3); - DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub)); - } - -exit: - return err; -} - -static s32 -wl_cfg80211_change_beacon( - struct wiphy *wiphy, - struct net_device *dev, - struct cfg80211_beacon_data *info) -{ - s32 err = BCME_OK; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct parsed_ies ies; - u32 dev_role = 0; - s32 bssidx = 0; - bool pbc = 0; - - WL_DBG(("Enter \n")); - - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - dev_role = NL80211_IFTYPE_AP; - } -#if defined(WL_ENABLE_P2P_IF) - else if (dev == cfg->p2p_net) { - /* Group Add request on p2p0 */ - dev = bcmcfg_to_prmry_ndev(cfg); - dev_role = NL80211_IFTYPE_P2P_GO; - } -#endif /* WL_ENABLE_P2P_IF */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (p2p_is_on(cfg) && - (bssidx == wl_to_p2p_bss_bssidx(cfg, - P2PAPI_BSSCFG_CONNECTION))) { - dev_role = NL80211_IFTYPE_P2P_GO; - } - - if (!check_dev_role_integrity(cfg, dev_role)) - goto fail; - - if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) { - WL_ERR(("P2P already down status!\n")); - err = BCME_ERROR; - goto fail; - } - - /* Parse IEs */ - if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) { - WL_ERR(("Parse IEs failed \n")); - goto fail; - } - - /* Set IEs to FW */ - if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) { - WL_ERR(("Set IEs failed \n")); - goto fail; - } - - if (dev_role == NL80211_IFTYPE_AP) { - if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { - WL_ERR(("Hostapd update sec failed \n")); - err = -EINVAL; - goto fail; - } - /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ - if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) { - wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); - WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc)); - if (pbc) - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); - else - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); - } - } - -fail: - return err; -} -#else -static s32 -wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info) -{ - s32 err = BCME_OK; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 ie_offset = 0; - s32 bssidx = 0; - u32 dev_role = NL80211_IFTYPE_AP; - struct parsed_ies ies; - bcm_tlv_t *ssid_ie; - bool pbc = 0; - WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", - info->interval, info->dtim_period, info->head_len, info->tail_len)); - - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - dev_role = NL80211_IFTYPE_AP; - } -#if defined(WL_ENABLE_P2P_IF) - else if (dev == cfg->p2p_net) { - /* Group Add request on p2p0 */ - dev = bcmcfg_to_prmry_ndev(cfg); - dev_role = NL80211_IFTYPE_P2P_GO; - } -#endif /* WL_ENABLE_P2P_IF */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (p2p_is_on(cfg) && - (bssidx == wl_to_p2p_bss_bssidx(cfg, - P2PAPI_BSSCFG_CONNECTION))) { - dev_role = NL80211_IFTYPE_P2P_GO; - } - - if (!check_dev_role_integrity(cfg, dev_role)) - goto fail; - - if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) { - WL_ERR(("P2P already down status!\n")); - err = BCME_ERROR; - goto fail; - } - - ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; - /* find the SSID */ - if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], - info->head_len - ie_offset, - DOT11_MNG_SSID_ID)) != NULL) { - if (dev_role == NL80211_IFTYPE_AP) { - /* Store the hostapd SSID */ - memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); - cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN); - memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data, - cfg->hostapd_ssid.SSID_len); - } else { - /* P2P GO */ - memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); - cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN); - memcpy(cfg->p2p->ssid.SSID, ssid_ie->data, - cfg->p2p->ssid.SSID_len); - } - } - - if (wl_cfg80211_parse_ies((u8 *)info->tail, - info->tail_len, &ies) < 0) { - WL_ERR(("Beacon get IEs failed \n")); - err = -EINVAL; - goto fail; - } - - if (wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_BEACON_FLAG, (u8 *)info->tail, - info->tail_len) < 0) { - WL_ERR(("Beacon set IEs failed \n")); - goto fail; - } else { - WL_DBG(("Applied Vndr IEs for Beacon \n")); - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - if (wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies, - info->proberesp_ies_len) < 0) { - WL_ERR(("ProbeRsp set IEs failed \n")); - goto fail; - } else { - WL_DBG(("Applied Vndr IEs for ProbeRsp \n")); - } -#endif - - if (!wl_cfgp2p_bss_isup(dev, bssidx) && - (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx) < 0)) - { - WL_ERR(("Beacon set security failed \n")); - goto fail; - } - - /* Set BI and DTIM period */ - if (info->interval) { - if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, - &info->interval, sizeof(s32), true)) < 0) { - WL_ERR(("Beacon Interval Set Error, %d\n", err)); - return err; - } - } - if (info->dtim_period) { - if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, - &info->dtim_period, sizeof(s32), true)) < 0) { - WL_ERR(("DTIM Interval Set Error, %d\n", err)); - return err; - } - } - - if (wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx) < 0) { - WL_ERR(("Beacon bring up AP/GO failed \n")); - goto fail; - } - - if (wl_get_drv_status(cfg, AP_CREATED, dev)) { - /* Soft AP already running. Update changed params */ - if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { - WL_ERR(("Hostapd update sec failed \n")); - err = -EINVAL; - goto fail; - } - } - - /* Enable Probe Req filter */ - if (((dev_role == NL80211_IFTYPE_P2P_GO) || - (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) { - wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); - if (pbc) - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); - } - - WL_DBG(("** ADD/SET beacon done **\n")); - -fail: - if (err) { - WL_ERR(("ADD/SET beacon failed\n")); - wldev_iovar_setint(dev, "mpc", 1); - } - return err; - -} -#endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */ - -#ifdef WL_SCHED_SCAN -#define PNO_TIME 30 -#define PNO_REPEAT 4 -#define PNO_FREQ_EXPO_MAX 2 -static bool -is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count) -{ - int i; - - if (!ssid || !ssid_list) - return FALSE; - - for (i = 0; i < count; i++) { - if (ssid->ssid_len == ssid_list[i].ssid_len) { - if (strncmp(ssid->ssid, ssid_list[i].ssid, ssid->ssid_len) == 0) - return TRUE; - } - } - return FALSE; -} - -static int -wl_cfg80211_sched_scan_start(struct wiphy *wiphy, - struct net_device *dev, - struct cfg80211_sched_scan_request *request) -{ - ushort pno_time = PNO_TIME; - int pno_repeat = PNO_REPEAT; - int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; - wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct cfg80211_ssid *ssid = NULL; - struct cfg80211_ssid *hidden_ssid_list = NULL; - int ssid_cnt = 0; - int i; - int ret = 0; - - WL_DBG(("Enter \n")); - WL_ERR((">>> SCHED SCAN START\n")); - WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n", - request->n_match_sets, request->n_ssids)); - WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n", - request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max)); - - - if (!request || !request->n_ssids || !request->n_match_sets) { - WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids)); - return -EINVAL; - } - - memset(&ssids_local, 0, sizeof(ssids_local)); - - if (request->n_ssids > 0) - hidden_ssid_list = request->ssids; - - for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) { - ssid = &request->match_sets[i].ssid; - /* No need to include null ssid */ - if (ssid->ssid_len) { - ssids_local[ssid_cnt].SSID_len = MIN(ssid->ssid_len, - DOT11_MAX_SSID_LEN); - memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid, - ssids_local[ssid_cnt].SSID_len); - if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) { - ssids_local[ssid_cnt].hidden = TRUE; - WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid)); - } else { - ssids_local[ssid_cnt].hidden = FALSE; - WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid->ssid)); - } - if (request->match_sets[i].rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) { - ssids_local[ssid_cnt].rssi_thresh = - (int8)request->match_sets[i].rssi_thold; - } - ssid_cnt++; - } - } - - if (ssid_cnt) { - if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, ssid_cnt, pno_time, - pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) { - WL_ERR(("PNO setup failed!! ret=%d \n", ret)); - return -EINVAL; - } - cfg->sched_scan_req = request; - } else { - return -EINVAL; - } - - return 0; -} - -static int -wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - WL_DBG(("Enter \n")); - WL_PNO((">>> SCHED SCAN STOP\n")); - - if (dhd_dev_pno_stop_for_ssid(dev) < 0) - WL_ERR(("PNO Stop for SSID failed")); - - if (cfg->scan_request && cfg->sched_scan_running) { - WL_PNO((">>> Sched scan running. Aborting it..\n")); - wl_notify_escan_complete(cfg, dev, true, true); - } - - cfg->sched_scan_req = NULL; - cfg->sched_scan_running = FALSE; - - return 0; -} -#endif /* WL_SCHED_SCAN */ - -#ifdef WL_SUPPORT_ACS -/* - * Currently the dump_obss IOVAR is returning string as output so we need to - * parse the output buffer in an unoptimized way. Going forward if we get the - * IOVAR output in binary format this method can be optimized - */ -static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey) -{ - int i; - char *token; - char delim[] = " \n"; - - token = strsep(&buf, delim); - while (token != NULL) { - if (!strcmp(token, "OBSS")) { - for (i = 0; i < OBSS_TOKEN_IDX; i++) - token = strsep(&buf, delim); - survey->obss = simple_strtoul(token, NULL, 10); - } - - if (!strcmp(token, "IBSS")) { - for (i = 0; i < IBSS_TOKEN_IDX; i++) - token = strsep(&buf, delim); - survey->ibss = simple_strtoul(token, NULL, 10); - } - - if (!strcmp(token, "TXDur")) { - for (i = 0; i < TX_TOKEN_IDX; i++) - token = strsep(&buf, delim); - survey->tx = simple_strtoul(token, NULL, 10); - } - - if (!strcmp(token, "Category")) { - for (i = 0; i < CTG_TOKEN_IDX; i++) - token = strsep(&buf, delim); - survey->no_ctg = simple_strtoul(token, NULL, 10); - } - - if (!strcmp(token, "Packet")) { - for (i = 0; i < PKT_TOKEN_IDX; i++) - token = strsep(&buf, delim); - survey->no_pckt = simple_strtoul(token, NULL, 10); - } - - if (!strcmp(token, "Opp(time):")) { - for (i = 0; i < IDLE_TOKEN_IDX; i++) - token = strsep(&buf, delim); - survey->idle = simple_strtoul(token, NULL, 10); - } - - token = strsep(&buf, delim); - } - - return 0; -} - -static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req, - struct wl_dump_survey *survey) -{ - cca_stats_n_flags *results; - char *buf; - int retry, err; - - buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL); - if (unlikely(!buf)) { - WL_ERR(("%s: buf alloc failed\n", __func__)); - return -ENOMEM; - } - - retry = IOCTL_RETRY_COUNT; - while (retry--) { - err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req), - buf, WLC_IOCTL_MAXLEN, NULL); - if (err >= 0) { - break; - } - WL_DBG(("attempt = %d, err = %d, \n", - (IOCTL_RETRY_COUNT - retry), err)); - } - - if (retry <= 0) { - WL_ERR(("failure, dump_obss IOVAR failed\n")); - err = -BCME_ERROR; - goto exit; - } - - results = (cca_stats_n_flags *)(buf); - wl_parse_dump_obss(results->buf, survey); - kfree(buf); - - return 0; -exit: - kfree(buf); - return err; -} - -static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, - int idx, struct survey_info *info) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct wl_dump_survey *survey; - struct ieee80211_supported_band *band; - struct ieee80211_channel*chan; - cca_msrmnt_query req; - int val, err, noise, retry; - - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { - return -ENOENT; - } - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - if (band && idx >= band->n_channels) { - idx -= band->n_channels; - band = NULL; - } - - if (!band || idx >= band->n_channels) { - /* Move to 5G band */ - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - if (idx >= band->n_channels) { - return -ENOENT; - } - } - - chan = &band->channels[idx]; - /* Setting current channel to the requested channel */ - if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan, - NL80211_CHAN_HT20) < 0)) { - WL_ERR(("Set channel failed \n")); - } - - if (!idx) { - /* Disable mpc */ - val = 0; - err = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, - sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, - &cfg->ioctl_buf_sync); - if (err < 0) { - WL_ERR(("set 'mpc' failed, error = %d\n", err)); - } - - /* Set interface up, explicitly. */ - val = 1; - err = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true); - if (err < 0) { - WL_ERR(("set interface up failed, error = %d\n", err)); - } - } - - /* Get noise value */ - retry = IOCTL_RETRY_COUNT; - while (retry--) { - err = wldev_ioctl(ndev, WLC_GET_PHY_NOISE, &noise, - sizeof(noise), false); - if (err >= 0) { - break; - } - WL_DBG(("attempt = %d, err = %d, \n", - (IOCTL_RETRY_COUNT - retry), err)); - } - - if (retry <= 0) { - WL_ERR(("Get Phy Noise failed, error = %d\n", err)); - noise = CHAN_NOISE_DUMMY; - } - - survey = (struct wl_dump_survey *) kzalloc(sizeof(struct wl_dump_survey), - GFP_KERNEL); - if (unlikely(!survey)) { - WL_ERR(("%s: alloc failed\n", __func__)); - return -ENOMEM; - } - - /* Start Measurement for obss stats on current channel */ - req.msrmnt_query = 0; - req.time_req = ACS_MSRMNT_DELAY; - if ((err = wl_dump_obss(ndev, req, survey)) < 0) { - goto exit; - } - - /* - * Wait for the meaurement to complete, adding a buffer value of 10 to take - * into consideration any delay in IOVAR completion - */ - msleep(ACS_MSRMNT_DELAY + 10); - - /* Issue IOVAR to collect measurement results */ - req.msrmnt_query = 1; - if ((err = wl_dump_obss(ndev, req, survey)) < 0) { - goto exit; - } - - info->channel = chan; - info->noise = noise; - info->channel_time = ACS_MSRMNT_DELAY; - info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle; - info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg + - survey->no_pckt; - info->channel_time_tx = survey->tx; - info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX | - SURVEY_INFO_CHANNEL_TIME_TX; - kfree(survey); - - return 0; -exit: - kfree(survey); - return err; -} -#endif /* WL_SUPPORT_ACS */ - -static struct cfg80211_ops wl_cfg80211_ops = { - .add_virtual_intf = wl_cfg80211_add_virtual_iface, - .del_virtual_intf = wl_cfg80211_del_virtual_iface, - .change_virtual_intf = wl_cfg80211_change_virtual_iface, -#if defined(WL_CFG80211_P2P_DEV_IF) - .start_p2p_device = wl_cfgp2p_start_p2p_device, - .stop_p2p_device = wl_cfgp2p_stop_p2p_device, -#endif /* WL_CFG80211_P2P_DEV_IF */ - .scan = wl_cfg80211_scan, - .set_wiphy_params = wl_cfg80211_set_wiphy_params, - .join_ibss = wl_cfg80211_join_ibss, - .leave_ibss = wl_cfg80211_leave_ibss, - .get_station = wl_cfg80211_get_station, - .set_tx_power = wl_cfg80211_set_tx_power, - .get_tx_power = wl_cfg80211_get_tx_power, - .add_key = wl_cfg80211_add_key, - .del_key = wl_cfg80211_del_key, - .get_key = wl_cfg80211_get_key, - .set_default_key = wl_cfg80211_config_default_key, - .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key, - .set_power_mgmt = wl_cfg80211_set_power_mgmt, - .connect = wl_cfg80211_connect, - .disconnect = wl_cfg80211_disconnect, - .suspend = wl_cfg80211_suspend, - .resume = wl_cfg80211_resume, - .set_pmksa = wl_cfg80211_set_pmksa, - .del_pmksa = wl_cfg80211_del_pmksa, - .flush_pmksa = wl_cfg80211_flush_pmksa, - .remain_on_channel = wl_cfg80211_remain_on_channel, - .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel, - .mgmt_tx = wl_cfg80211_mgmt_tx, - .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, - .change_bss = wl_cfg80211_change_bss, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS) - .set_channel = wl_cfg80211_set_channel, -#endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS) - .set_beacon = wl_cfg80211_add_set_beacon, - .add_beacon = wl_cfg80211_add_set_beacon, -#else - .change_beacon = wl_cfg80211_change_beacon, - .start_ap = wl_cfg80211_start_ap, - .stop_ap = wl_cfg80211_stop_ap, -#endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */ -#ifdef WL_SCHED_SCAN - .sched_scan_start = wl_cfg80211_sched_scan_start, - .sched_scan_stop = wl_cfg80211_sched_scan_stop, -#endif /* WL_SCHED_SCAN */ -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 2, 0)) - .del_station = wl_cfg80211_del_station, - .change_station = wl_cfg80211_change_station, - .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, -#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) - .tdls_mgmt = wl_cfg80211_tdls_mgmt, - .tdls_oper = wl_cfg80211_tdls_oper, -#endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */ -#ifdef WL_SUPPORT_ACS - .dump_survey = wl_cfg80211_dump_survey, -#endif /* WL_SUPPORT_ACS */ -#ifdef WL_CFG80211_ACL - .set_mac_acl = wl_cfg80211_set_mac_acl, -#endif /* WL_CFG80211_ACL */ -#if defined(WL_ABORT_SCAN) - .abort_scan = wl_cfg80211_abort_scan, -#endif /* WL_ABORT_SCAN */ - -}; - -s32 wl_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; - case WL_MODE_AP: - return NL80211_IFTYPE_AP; - default: - return NL80211_IFTYPE_UNSPECIFIED; - } - - return err; -} - - -#ifdef CONFIG_PM -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) -static const struct wiphy_wowlan_support brcm_wowlan_support = { - .flags = WIPHY_WOWLAN_ANY, -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ -#endif /* CONFIG_PM */ - -static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context) -{ - s32 err = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS)) - dhd_pub_t *dhd = (dhd_pub_t *)context; - BCM_REFERENCE(dhd); - - if (!dhd) { - WL_ERR(("DHD is NULL!!")); - err = -ENODEV; - return err; - } -#endif - - wdev->wiphy = - wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211)); - if (unlikely(!wdev->wiphy)) { - WL_ERR(("Couldn not allocate wiphy device\n")); - err = -ENOMEM; - return err; - } - set_wiphy_dev(wdev->wiphy, sdiofunc_dev); - wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; - /* Report how many SSIDs Driver can support per Scan request */ - wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; - wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; -#ifdef WL_SCHED_SCAN - wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; - wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; - wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; -#endif /* WL_SCHED_SCAN */ - wdev->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) - | BIT(NL80211_IFTYPE_ADHOC) -#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) - | BIT(NL80211_IFTYPE_MONITOR) -#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF) - | BIT(NL80211_IFTYPE_P2P_CLIENT) - | BIT(NL80211_IFTYPE_P2P_GO) -#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_CFG80211_P2P_DEV_IF) - | BIT(NL80211_IFTYPE_P2P_DEVICE) -#endif /* WL_CFG80211_P2P_DEV_IF */ - | BIT(NL80211_IFTYPE_AP); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) - WL_DBG(("Setting interface combinations for common mode\n")); - wdev->wiphy->iface_combinations = common_iface_combinations; - wdev->wiphy->n_iface_combinations = - ARRAY_SIZE(common_iface_combinations); -#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ - - wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - - 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->max_remain_on_channel_duration = 5000; - wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes; -#ifndef WL_POWERSAVE_DISABLED - wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; -#else - wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; -#endif /* !WL_POWERSAVE_DISABLED */ - wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | - WIPHY_FLAG_4ADDR_AP | -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS) - WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | -#endif - WIPHY_FLAG_4ADDR_STATION; -#if (defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && ((LINUX_VERSION_CODE >= \ - KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)) - /* Please use supplicant ver >= 76 if FW_ROAM is enabled - * If driver advertises FW_ROAM, older supplicant wouldn't - * send the BSSID & Freq in the connect req command. This - * will delay the ASSOC as the FW need to do a full scan - * before attempting to connect. Supplicant >=76 has patch - * to allow bssid & freq to be sent down to driver even if - * FW ROAM is advertised. - */ - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS) - wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_OFFCHAN_TX; -#endif -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 4, 0)) - /* From 3.4 kernel ownards AP_SME flag can be advertised - * to remove the patch from supplicant - */ - wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; - -#ifdef WL_CFG80211_ACL - /* Configure ACL capabilities. */ - wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT; -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS)) - /* Supplicant distinguish between the SoftAP mode and other - * modes (e.g. P2P, WPS, HS2.0) when it builds the probe - * response frame from Supplicant MR1 and Kernel 3.4.0 or - * later version. To add Vendor specific IE into the - * probe response frame in case of SoftAP mode, - * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable. - */ - if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) { - wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - wdev->wiphy->probe_resp_offload = 0; - } -#endif -#endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */ - - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; -#endif - -#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF) - /* - * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the - * disconnection of connected network before suspend. So a dummy wowlan - * filter is configured for kernels linux-3.8 and above. - */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) - wdev->wiphy->wowlan = &brcm_wowlan_support; -#else - wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 10) */ -#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */ - - WL_DBG(("Registering custom regulatory)\n")); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; -#else - wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; -#endif - wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) - WL_DBG(("Registering Vendor80211)\n")); - err = wl_cfgvendor_attach(wdev->wiphy); - if (unlikely(err < 0)) { - WL_ERR(("Couldn not attach vendor commands (%d)\n", err)); - } -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ - - /* Now we can register wiphy with cfg80211 module */ - err = wiphy_register(wdev->wiphy); - if (unlikely(err < 0)) { - WL_ERR(("Couldn not register wiphy device (%d)\n", err)); - wiphy_free(wdev->wiphy); - } - -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \ - KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS) - wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS; -#endif - - return err; -} - -static void wl_free_wdev(struct bcm_cfg80211 *cfg) -{ - struct wireless_dev *wdev = cfg->wdev; - struct wiphy *wiphy; - if (!wdev) { - WL_ERR(("wdev is invalid\n")); - return; - } - wiphy = wdev->wiphy; - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) - wl_cfgvendor_detach(wdev->wiphy); -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ - - wiphy_unregister(wdev->wiphy); - wdev->wiphy->dev.parent = NULL; - - wl_delete_all_netinfo(cfg); - wiphy_free(wiphy); - /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg", - * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! - */ -} - -static s32 wl_inform_bss(struct bcm_cfg80211 *cfg) -{ - struct wl_scan_results *bss_list; - struct wl_bss_info *bi = NULL; /* must be initialized */ - s32 err = 0; - s32 i; - - bss_list = cfg->bss_list; - WL_DBG(("scanned AP count (%d)\n", bss_list->count)); - bi = next_bss(bss_list, bi); - for_each_bss(bss_list, bi, i) { - err = wl_inform_single_bss(cfg, bi, false); - if (unlikely(err)) - break; - } - return err; -} - -static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam) -{ - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - struct ieee80211_mgmt *mgmt; - struct ieee80211_channel *channel; - struct ieee80211_supported_band *band; - struct wl_cfg80211_bss_info *notif_bss_info; - struct wl_scan_req *sr = wl_to_sr(cfg); - struct beacon_proberesp *beacon_proberesp; - struct cfg80211_bss *cbss = NULL; - s32 mgmt_type; - s32 signal; - u32 freq; - s32 err = 0; - gfp_t aflags; - - if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { - WL_DBG(("Beacon is larger than buffer. Discarding\n")); - return err; - } - aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; - notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - - sizeof(u8) + WL_BSS_INFO_MAX, aflags); - if (unlikely(!notif_bss_info)) { - WL_ERR(("notif_bss_info alloc failed\n")); - return -ENOMEM; - } - mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; - notif_bss_info->channel = - wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); - - if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - if (!band) { - WL_ERR(("No valid band")); - kfree(notif_bss_info); - return -EINVAL; - } - notif_bss_info->rssi = wl_rssi_offset(dtoh16(bi->RSSI)); - memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); - mgmt_type = cfg->active_scan ? - IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; - if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type); - } - beacon_proberesp = cfg->active_scan ? - (struct beacon_proberesp *)&mgmt->u.probe_resp : - (struct beacon_proberesp *)&mgmt->u.beacon; - beacon_proberesp->timestamp = 0; - beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); - beacon_proberesp->capab_info = cpu_to_le16(bi->capability); - wl_rst_ie(cfg); - wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, roam); - wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length); - wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX - - offsetof(struct wl_cfg80211_bss_info, frame_buf)); - notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, - u.beacon.variable) + wl_get_ielen(cfg); -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) - freq = ieee80211_channel_to_frequency(notif_bss_info->channel); - (void)band->band; -#else - freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); -#endif - if (freq == 0) { - WL_ERR(("Invalid channel, fail to chcnage channel to freq\n")); - kfree(notif_bss_info); - return -EINVAL; - } - channel = ieee80211_get_channel(wiphy, freq); - if (unlikely(!channel)) { - WL_ERR(("ieee80211_get_channel error\n")); - kfree(notif_bss_info); - return -EINVAL; - } - WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM" - "mgmt_type %d frame_len %d\n", bi->SSID, - notif_bss_info->rssi, notif_bss_info->channel, - mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type, - notif_bss_info->frame_len)); - - signal = notif_bss_info->rssi * 100; - if (!mgmt->u.probe_resp.timestamp) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) - struct timespec ts; - get_monotonic_boottime(&ts); - mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) - + ts.tv_nsec / 1000; -#else - struct timeval tv; - do_gettimeofday(&tv); - mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000) - + tv.tv_usec; -#endif - } - - - cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, - le16_to_cpu(notif_bss_info->frame_len), signal, aflags); - if (unlikely(!cbss)) { - WL_ERR(("cfg80211_inform_bss_frame error\n")); - kfree(notif_bss_info); - return -EINVAL; - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) - cfg80211_put_bss(wiphy, cbss); -#else - cfg80211_put_bss(cbss); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ - kfree(notif_bss_info); - return err; -} - -static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev) -{ - u32 event = ntoh32(e->event_type); - u32 status = ntoh32(e->status); - u16 flags = ntoh16(e->flags); - - WL_DBG(("event %d, status %d flags %x\n", event, status, flags)); - if (event == WLC_E_SET_SSID) { - if (status == WLC_E_STATUS_SUCCESS) { - if (!wl_is_ibssmode(cfg, ndev)) - return true; - } - } else if (event == WLC_E_LINK) { - if (flags & WLC_EVENT_MSG_LINK) - return true; - } - - WL_DBG(("wl_is_linkup false\n")); - return false; -} - -static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e) -{ - u32 event = ntoh32(e->event_type); - u16 flags = ntoh16(e->flags); - - if (event == WLC_E_DEAUTH_IND || - event == WLC_E_DISASSOC_IND || - event == WLC_E_DISASSOC || - event == WLC_E_DEAUTH) { -#if (WL_DBG_LEVEL > 0) - WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); -#endif /* (WL_DBG_LEVEL > 0) */ - return true; - } else if (event == WLC_E_LINK) { - if (!(flags & WLC_EVENT_MSG_LINK)) { -#if (WL_DBG_LEVEL > 0) - WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); -#endif /* (WL_DBG_LEVEL > 0) */ - return true; - } - } - - return false; -} - -static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e) -{ - u32 event = ntoh32(e->event_type); - u32 status = ntoh32(e->status); - - if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) - return true; - if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) - return true; - - return false; -} - -/* The mainline kernel >= 3.2.0 has support for indicating new/del station - * to AP/P2P GO via events. If this change is backported to kernel for which - * this driver is being built, then define WL_CFG80211_STA_EVENT. You - * should use this new/del sta event mechanism for BRCM supplicant >= 22. - */ -static s32 -wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - s32 err = 0; - u32 event = ntoh32(e->event_type); - u32 reason = ntoh32(e->reason); - u32 len = ntoh32(e->datalen); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) \ - && !defined(WL_COMPAT_WIRELESS) - bool isfree = false; - u8 *mgmt_frame; - u8 bsscfgidx = e->bsscfgidx; - s32 freq; - s32 channel; - u8 *body = NULL; - u16 fc = 0; - - struct ieee80211_supported_band *band; - struct ether_addr da; - struct ether_addr bssid; - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - channel_info_t ci; -#else - struct station_info sinfo; -#endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ - - WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason)); - /* if link down, bsscfg is disabled. */ - if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS && - wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) { - wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false); - WL_INFORM(("AP mode link down !! \n")); - complete(&cfg->iface_disable); - return 0; - } - - if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) { - WL_ERR(("event %s(%d) status %d reason %d\n", - bcmevent_get_name(event), event, ntoh32(e->status), reason)); - } - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) \ - && !defined(WL_COMPAT_WIRELESS) - WL_DBG(("Enter \n")); - if (!len && (event == WLC_E_DEAUTH)) { - len = 2; /* reason code field */ - data = &reason; - } - if (len) { - body = kzalloc(len, GFP_KERNEL); - - if (body == NULL) { - WL_ERR(("wl_notify_connect_status: Failed to allocate body\n")); - return WL_INVALID; - } - } - memset(&bssid, 0, ETHER_ADDR_LEN); - WL_DBG(("Enter event %d ndev %p\n", event, ndev)); - if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) { - kfree(body); - return WL_INVALID; - } - if (len) - memcpy(body, data, len); - - wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", - NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); - memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); - err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - switch (event) { - case WLC_E_ASSOC_IND: - fc = FC_ASSOC_REQ; - break; - case WLC_E_REASSOC_IND: - fc = FC_REASSOC_REQ; - break; - case WLC_E_DISASSOC_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH: - fc = FC_DISASSOC; - break; - default: - fc = 0; - goto exit; - } - if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { - kfree(body); - return err; - } - - channel = dtoh32(ci.hw_channel); - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - if (!band) { - WL_ERR(("No valid band")); - if (body) - kfree(body); - return -EINVAL; - } -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) - freq = ieee80211_channel_to_frequency(channel); - (void)band->band; -#else - freq = ieee80211_channel_to_frequency(channel, band->band); -#endif - - err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, - &mgmt_frame, &len, body); - if (err < 0) - goto exit; - isfree = true; - - if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); -#else - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ - } else if (event == WLC_E_DISASSOC_IND) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); -#else - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ - } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); -#else - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ - } - -exit: - if (isfree) - kfree(mgmt_frame); - if (body) - kfree(body); -#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ - sinfo.filled = 0; - if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && - reason == DOT11_SC_SUCCESS) { - sinfo.filled = STATION_INFO_ASSOC_REQ_IES; - if (!data) { - WL_ERR(("No IEs present in ASSOC/REASSOC_IND")); - return -EINVAL; - } - sinfo.assoc_req_ies = data; - sinfo.assoc_req_ies_len = len; - cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); - } else if (event == WLC_E_DISASSOC_IND) { - cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); - } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { - cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); - } -#endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ - return err; -} - -static s32 -wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e) -{ - u32 reason = ntoh32(e->reason); - u32 event = ntoh32(e->event_type); - struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); - WL_DBG(("event type : %d, reason : %d\n", event, reason)); - if (sec) { - switch (event) { - case WLC_E_ASSOC: - case WLC_E_AUTH: - sec->auth_assoc_res_status = reason; - default: - break; - } - } else - WL_ERR(("sec is NULL\n")); - return 0; -} - -static s32 -wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - s32 err = 0; - u32 event = ntoh32(e->event_type); - u16 flags = ntoh16(e->flags); - u32 status = ntoh32(e->status); - bool active; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) - struct ieee80211_channel *channel = NULL; - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - u32 chanspec, chan; - u32 freq, band; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */ - - if (event == WLC_E_JOIN) { - WL_DBG(("joined in IBSS network\n")); - } - if (event == WLC_E_START) { - WL_DBG(("started IBSS network\n")); - } - if (event == WLC_E_JOIN || event == WLC_E_START || - (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) - err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec); - if (unlikely(err)) { - WL_ERR(("Could not get chanspec %d\n", err)); - return err; - } - chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec)); - band = (chan <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - freq = ieee80211_channel_to_frequency(chan, band); - channel = ieee80211_get_channel(wiphy, freq); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */ - if (wl_get_drv_status(cfg, CONNECTED, ndev)) { - /* ROAM or Redundant */ - u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) { - WL_DBG(("IBSS connected event from same BSSID(" - MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid))); - return err; - } - WL_INFORM(("IBSS BSSID is changed from " MACDBG " to " MACDBG "\n", - MAC2STRDBG(cur_bssid), MAC2STRDBG((u8 *)&e->addr))); - wl_get_assoc_ies(cfg, ndev); - wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, false); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) - cfg80211_ibss_joined(ndev, (s8 *)&e->addr, channel, GFP_KERNEL); -#else - cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); -#endif - } - else { - /* New connection */ - WL_INFORM(("IBSS connected to " MACDBG "\n", MAC2STRDBG((u8 *)&e->addr))); - wl_link_up(cfg); - wl_get_assoc_ies(cfg, ndev); - wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, false); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) - cfg80211_ibss_joined(ndev, (s8 *)&e->addr, channel, GFP_KERNEL); -#else - cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); -#endif - wl_set_drv_status(cfg, CONNECTED, ndev); - active = true; - wl_update_prof(cfg, ndev, NULL, (void *)&active, WL_PROF_ACT); - } - } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) || - event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) { - wl_clr_drv_status(cfg, CONNECTED, ndev); - wl_link_down(cfg); - wl_init_prof(cfg, ndev); - } - else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) { - WL_DBG(("no action - join fail (IBSS mode)\n")); - } - else { - WL_DBG(("no action (IBSS mode)\n")); -} - return err; -} - -static s32 -wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - bool act; - struct net_device *ndev = NULL; - s32 err = 0; - u32 event = ntoh32(e->event_type); - -#ifdef DHD_ENABLE_DISC_TIME_LOG - struct timeval tv_now; - do_gettimeofday(&tv_now); -#endif /* DHD_ENABLE_DISC_TIME_LOG */ - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { - err = wl_notify_connect_status_ap(cfg, ndev, e, data); - } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS) { - err = wl_notify_connect_status_ibss(cfg, ndev, e, data); - } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) { - WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", - ntoh32(e->event_type), ntoh32(e->status), ndev)); - if (event == WLC_E_ASSOC || event == WLC_E_AUTH) { - wl_get_auth_assoc_status(cfg, ndev, e); - return 0; - } - if (wl_is_linkup(cfg, e, ndev)) { - wl_link_up(cfg); - act = true; - if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) { - printk("wl_bss_connect_done succeeded with " MACDBG "\n", - MAC2STRDBG((u8*)(&e->addr))); - wl_bss_connect_done(cfg, ndev, e, data, true); - WL_DBG(("joined in BSS network \"%s\"\n", - ((struct wlc_ssid *) - wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID)); - } - wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); - wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - - } else if (wl_is_linkdown(cfg, e)) { - - if (cfg->scan_request) - wl_notify_escan_complete(cfg, ndev, true, true); - if (wl_get_drv_status(cfg, CONNECTED, ndev)) { - scb_val_t scbval; - u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - s32 reason = 0; - if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) - reason = ntoh32(e->reason); - /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ - reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; - -#ifdef DHD_ENABLE_DISC_TIME_LOG - printk("KERN_ERR [Log]%s: current time=%lu\n", __FUNCTION__, - (unsigned long int) tv_now.tv_sec*1000000+tv_now.tv_usec); -#endif /* DHD_ENABLE_DISC_TIME_LOG */ - printk("link down if %s may call cfg80211_disconnected. " - "event : %d, reason=%d from " MACDBG "\n", - ndev->name, event, ntoh32(e->reason), - MAC2STRDBG((u8*)(&e->addr))); - if (!cfg->roam_offload && - memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) { - WL_ERR(("BSSID of event is not the connected BSSID" - "(ignore it) cur: " MACDBG " event: " MACDBG"\n", - MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr)))); - return 0; - } - wl_clr_drv_status(cfg, CONNECTED, ndev); - if (! wl_get_drv_status(cfg, DISCONNECTING, ndev)) { - /* To make sure disconnect, explictly send dissassoc - * for BSSID 00:00:00:00:00:00 issue - */ - scbval.val = WLAN_REASON_DEAUTH_LEAVING; - - memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - scbval.val = htod32(scbval.val); - err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - if (err < 0) { - WL_ERR(("WLC_DISASSOC error %d\n", err)); - err = 0; - } - cfg80211_disconnected(ndev, reason, NULL, 0, GFP_KERNEL); - wl_link_down(cfg); - wl_init_prof(cfg, ndev); - } - } - else if (wl_get_drv_status(cfg, CONNECTING, ndev)) { - printk("link down, during connecting\n"); -#ifdef ESCAN_RESULT_PATCH - if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) || - (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) || - (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0)) - /* In case this event comes while associating another AP */ -#endif /* ESCAN_RESULT_PATCH */ - wl_bss_connect_done(cfg, ndev, e, data, false); - } - wl_clr_drv_status(cfg, DISCONNECTING, ndev); - - /* if link down, bsscfg is diabled */ - if (ndev != bcmcfg_to_prmry_ndev(cfg)) - complete(&cfg->iface_disable); - - } else if (wl_is_nonetwork(cfg, e)) { - printk("connect failed event=%d e->status %d e->reason %d \n", - event, (int)ntoh32(e->status), (int)ntoh32(e->reason)); - /* Clean up any pending scan request */ - if (cfg->scan_request) - wl_notify_escan_complete(cfg, ndev, true, true); - if (wl_get_drv_status(cfg, CONNECTING, ndev)) - wl_bss_connect_done(cfg, ndev, e, data, false); - } else { - WL_DBG(("%s nothing\n", __FUNCTION__)); - } - } - else { - WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev))); - } - return err; -} - -void wl_cfg80211_set_rmc_pid(int pid) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - if (pid > 0) - cfg->rmc_event_pid = pid; - WL_DBG(("set pid for rmc event : pid=%d\n", pid)); -} - -#ifdef WLAIBSS -void wl_cfg80211_set_txfail_pid(int pid) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - if (pid > 0) - cfg->aibss_txfail_pid = pid; - WL_DBG(("set pid for aibss fail event : pid=%d\n", pid)); -} - -static s32 -wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - u32 evt = ntoh32(e->event_type); - int ret = -1; - - if (cfg->aibss_txfail_pid != 0) { - ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL, - cfg->aibss_txfail_seq++, (void *)&e->addr, ETHER_ADDR_LEN); - } - - WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n", - evt, cfg->aibss_txfail_pid, ret, ETHERP_TO_MACF(&e->addr))); - return ret; -} -#endif /* WLAIBSS */ - -static s32 -wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - u32 evt = ntoh32(e->event_type); - u32 reason = ntoh32(e->reason); - int ret = -1; - - switch (reason) { - case WLC_E_REASON_RMC_AR_LOST: - case WLC_E_REASON_RMC_AR_NO_ACK: - if (cfg->rmc_event_pid != 0) { - ret = wl_netlink_send_msg(cfg->rmc_event_pid, - RMC_EVENT_LEADER_CHECK_FAIL, - cfg->rmc_event_seq++, NULL, 0); - } - break; - default: - break; - } - WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret)); - return ret; -} - -static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ -#if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT) - u32 datalen = be32_to_cpu(e->datalen); - struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - - if (datalen) { - wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data; - if (evt_data->version == RSSI_MONITOR_VERSION) { - dhd_rssi_monitor_evt_t monitor_data; - monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION; - monitor_data.cur_rssi = evt_data->cur_rssi; - memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN); - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_RSSI_MONITOR_EVENT, - &monitor_data, sizeof(monitor_data)); - } else { - WL_ERR(("Version mismatch %d, expected %d", evt_data->version, - RSSI_MONITOR_VERSION)); - } - } -#endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */ - return BCME_OK; -} - -static s32 -wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - bool act; - struct net_device *ndev = NULL; - s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); - WL_DBG(("Enter \n")); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) { - wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false); - cfg->disable_roam_event = TRUE; - } - - if ((cfg->disable_roam_event) && (event == WLC_E_ROAM)) - return err; - - if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) { - if (wl_get_drv_status(cfg, CONNECTED, ndev)) - wl_bss_roaming_done(cfg, ndev, e, data); - else - wl_bss_connect_done(cfg, ndev, e, data, true); - act = true; - wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); - wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - } - return err; -} - -static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - wl_assoc_info_t assoc_info; - struct wl_connect_info *conn_info = wl_to_conn(cfg); - s32 err = 0; - - WL_DBG(("Enter \n")); - err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); - if (unlikely(err)) { - WL_ERR(("could not get assoc info (%d)\n", err)); - return err; - } - memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t)); - assoc_info.req_len = htod32(assoc_info.req_len); - assoc_info.resp_len = htod32(assoc_info.resp_len); - assoc_info.flags = htod32(assoc_info.flags); - - if (assoc_info.req_len > - (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + - ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? - ETHER_ADDR_LEN : 0))) { - err = BCME_BADLEN; - goto exit; - } - if ((assoc_info.req_len > 0) && - (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + - ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? - ETHER_ADDR_LEN : 0)))) { - err = BCME_BADLEN; - goto exit; - } - if (assoc_info.resp_len > - (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { - err = BCME_BADLEN; - goto exit; - } - if ((assoc_info.resp_len > 0) && - (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { - err = BCME_BADLEN; - goto exit; - } - - if (conn_info->req_ie_len) { - conn_info->req_ie_len = 0; - bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); - } - if (conn_info->resp_ie_len) { - conn_info->resp_ie_len = 0; - bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); - } - - if (assoc_info.req_len) { - err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, - cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); - if (unlikely(err)) { - WL_ERR(("could not get assoc req (%d)\n", err)); - goto exit; - } - conn_info->req_ie_len = assoc_info.req_len - - sizeof(struct dot11_assoc_req); - if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { - conn_info->req_ie_len -= ETHER_ADDR_LEN; - } - memcpy(conn_info->req_ie, cfg->extra_buf, - conn_info->req_ie_len); - } - - if (assoc_info.resp_len) { - err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, - cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); - if (unlikely(err)) { - WL_ERR(("could not get assoc resp (%d)\n", err)); - goto exit; - } - conn_info->resp_ie_len = - assoc_info.resp_len - sizeof(struct dot11_assoc_resp); - memcpy(conn_info->resp_ie, cfg->extra_buf, - conn_info->resp_ie_len); - } - -exit: - if (err) { - WL_ERR(("err:%d assoc-req:%u,resp:%u conn-req:%u,resp:%u\n", - err, assoc_info.req_len, assoc_info.resp_len, - conn_info->req_ie_len, conn_info->resp_ie_len)); - } - return err; -} - -static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, - size_t *join_params_size) -{ - chanspec_t chanspec = 0; - if (ch != 0) { - join_params->params.chanspec_num = 1; - join_params->params.chanspec_list[0] = ch; - - if (join_params->params.chanspec_list[0] <= 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 += WL_ASSOC_PARAMS_FIXED_SIZE + - join_params->params.chanspec_num * sizeof(chanspec_t); - - join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; - join_params->params.chanspec_list[0] |= chanspec; - join_params->params.chanspec_list[0] = - wl_chspec_host_to_driver(join_params->params.chanspec_list[0]); - - join_params->params.chanspec_num = - htod32(join_params->params.chanspec_num); - WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n", - join_params->params.chanspec_list[0], - join_params->params.chanspec_num)); - } -} - -static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam) -{ - struct cfg80211_bss *bss; - struct wl_bss_info *bi; - struct wlc_ssid *ssid; - struct bcm_tlv *tim; - s32 beacon_interval; - s32 dtim_period; - size_t ie_len; - u8 *ie; - u8 *curbssid; - s32 err = 0; - struct wiphy *wiphy; - u32 channel; - struct ieee80211_channel *cur_channel; - u32 freq, band; - - wiphy = bcmcfg_to_wiphy(cfg); - - ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID); - curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - - mutex_lock(&cfg->usr_sync); - - *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX); - err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, - cfg->extra_buf, WL_EXTRA_BUF_MAX, false); - if (unlikely(err)) { - WL_ERR(("Could not get bss info %d\n", err)); - goto update_bss_info_out; - } - bi = (struct wl_bss_info *)(cfg->extra_buf + 4); - channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); - wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN); -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) - freq = ieee80211_channel_to_frequency(channel); -#else - band = (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - freq = ieee80211_channel_to_frequency(channel, band); -#endif - cur_channel = ieee80211_get_channel(wiphy, freq); - - bss = cfg80211_get_bss(wiphy, cur_channel, curbssid, - ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, - WLAN_CAPABILITY_ESS); - - if (!bss) { - WL_DBG(("Could not find the AP\n")); - if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) { - WL_ERR(("Bssid doesn't match\n")); - err = -EIO; - goto update_bss_info_out; - } - err = wl_inform_single_bss(cfg, bi, roam); - if (unlikely(err)) - goto update_bss_info_out; - - ie = ((u8 *)bi) + bi->ie_offset; - ie_len = bi->ie_length; - beacon_interval = cpu_to_le16(bi->beacon_period); - } else { - WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); -#if defined(WL_CFG80211_P2P_DEV_IF) - ie = (u8 *)bss->ies->data; - ie_len = bss->ies->len; -#else - ie = bss->information_elements; - ie_len = bss->len_information_elements; -#endif /* WL_CFG80211_P2P_DEV_IF */ - beacon_interval = bss->beacon_interval; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) - cfg80211_put_bss(wiphy, bss); -#else - cfg80211_put_bss(bss); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ - } - - tim = bcm_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. - */ - err = wldev_ioctl(ndev, WLC_GET_DTIMPRD, - &dtim_period, sizeof(dtim_period), false); - if (unlikely(err)) { - WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); - goto update_bss_info_out; - } - } - - wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT); - wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); - -update_bss_info_out: - if (unlikely(err)) { - WL_ERR(("Failed with error %d\n", err)); - } - mutex_unlock(&cfg->usr_sync); - return err; -} - -static s32 -wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - struct wl_connect_info *conn_info = wl_to_conn(cfg); - s32 err = 0; - u8 *curbssid; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - struct ieee80211_supported_band *band; - struct ieee80211_channel *notify_channel = NULL; - u32 *channel; - u32 freq; -#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */ - -#ifdef WLFBT - uint32 data_len = 0; - if (data) - data_len = ntoh32(e->datalen); -#endif /* WLFBT */ - - wl_get_assoc_ies(cfg, ndev); - wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); - curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, true); - wl_update_pmklist(ndev, cfg->pmk_list, err); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) - /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */ - channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN); - 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); -#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */ -#ifdef WLFBT - /* back up the given FBT key for the further supplicant request, - * currently not checking the FBT is enabled for current BSS in DHD, - * because the supplicant decides to take it or not. - */ - if (data && (data_len == FBT_KEYLEN)) { - memcpy(cfg->fbt_key, data, FBT_KEYLEN); - } -#endif /* WLFBT */ - printk("wl_bss_roaming_done succeeded to " MACDBG "\n", - MAC2STRDBG((u8*)(&e->addr))); - - cfg80211_roamed(ndev, -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) - notify_channel, -#endif - curbssid, - conn_info->req_ie, conn_info->req_ie_len, - conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); - WL_DBG(("Report roaming result\n")); - - wl_set_drv_status(cfg, CONNECTED, ndev); - - return err; -} - -static s32 -wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data, bool completed) -{ - struct wl_connect_info *conn_info = wl_to_conn(cfg); - struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); -#if (defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)) || \ - defined(CUSTOM_SET_CPUCORE) - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif /* (ROAM_ENABLE && ROAM_AP_ENV_DETECTION) || CUSTOM_SET_CPUCORE */ - s32 err = 0; - u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - if (!sec) { - WL_ERR(("sec is NULL\n")); - return -ENODEV; - } - WL_DBG((" enter\n")); -#ifdef ESCAN_RESULT_PATCH - if (wl_get_drv_status(cfg, CONNECTED, ndev)) { - if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) { - WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n", - ntoh32(e->event_type), ntoh32(e->status))); - return err; - } - } - if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 && - memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) { - WL_DBG(("copy bssid\n")); - memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); - } - -#else - if (cfg->scan_request) { - wl_notify_escan_complete(cfg, ndev, true, true); - } -#endif /* ESCAN_RESULT_PATCH */ - if (wl_get_drv_status(cfg, CONNECTING, ndev)) { - wl_cfg80211_scan_abort(cfg); - wl_clr_drv_status(cfg, CONNECTING, ndev); - if (completed) { - wl_get_assoc_ies(cfg, ndev); - wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); - curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, false); - wl_update_pmklist(ndev, cfg->pmk_list, err); - wl_set_drv_status(cfg, CONNECTED, ndev); -#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) - if (dhd->roam_env_detection) - wldev_iovar_setint(ndev, "roam_env_detection", - AP_ENV_INDETERMINATE); -#endif /* ROAM_AP_ENV_DETECTION */ - if (ndev != bcmcfg_to_prmry_ndev(cfg)) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) - init_completion(&cfg->iface_disable); -#else - /* reinitialize completion to clear previous count */ - INIT_COMPLETION(cfg->iface_disable); -#endif - } -#ifdef CUSTOM_SET_CPUCORE - if (wl_get_chan_isvht80(ndev, dhd)) { - if (ndev == bcmcfg_to_prmry_ndev(cfg)) - dhd->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */ - else if (ndev == wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) - dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */ - dhd_set_cpucore(dhd, TRUE); - } -#endif /* CUSTOM_SET_CPUCORE */ - - } - cfg80211_connect_result(ndev, - curbssid, - conn_info->req_ie, - conn_info->req_ie_len, - conn_info->resp_ie, - conn_info->resp_ie_len, - completed ? WLAN_STATUS_SUCCESS : - (sec->auth_assoc_res_status) ? - sec->auth_assoc_res_status : - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); - if (completed) - WL_INFORM(("Report connect result - connection succeeded\n")); - else - WL_ERR(("Report connect result - connection failed\n")); - } -#ifdef CONFIG_TCPACK_FASTTX - if (wl_get_chan_isvht80(ndev, dhd)) - wldev_iovar_setint(ndev, "tcpack_fast_tx", 0); - else - wldev_iovar_setint(ndev, "tcpack_fast_tx", 1); -#endif /* CONFIG_TCPACK_FASTTX */ - - return err; -} - -static s32 -wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct net_device *ndev = NULL; - u16 flags = ntoh16(e->flags); - enum nl80211_key_type key_type; - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - mutex_lock(&cfg->usr_sync); - if (flags & WLC_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); - mutex_unlock(&cfg->usr_sync); - - return 0; -} - -#ifdef BT_WIFI_HANDOVER -static s32 -wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct net_device *ndev = NULL; - u32 event = ntoh32(e->event_type); - u32 datalen = ntoh32(e->datalen); - s32 err; - - WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen)); - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0); - - return err; -} -#endif /* BT_WIFI_HANDOVER */ - -#ifdef PNO_SUPPORT -static s32 -wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct net_device *ndev = NULL; -#ifdef GSCAN_SUPPORT - void *ptr; - int send_evt_bytes = 0; - u32 event = be32_to_cpu(e->event_type); - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); -#endif /* GSCAN_SUPPORT */ - - if (!data) { - WL_ERR(("Data is NULL!\n")); - return 0; - } - - WL_DBG((">>> PNO Event\n")); - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - -#ifdef GSCAN_SUPPORT - ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes); - if (ptr) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes); - kfree(ptr); - } - if (!dhd_dev_is_legacy_pno_enabled(ndev)) - return 0; -#endif /* GSCAN_SUPPORT */ - -#ifndef WL_SCHED_SCAN - mutex_lock(&cfg->usr_sync); - /* TODO: Use cfg80211_sched_scan_results(wiphy); */ - cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); - mutex_unlock(&cfg->usr_sync); -#else - /* If cfg80211 scheduled scan is supported, report the pno results via sched - * scan results - */ - wl_notify_sched_scan_results(cfg, ndev, e, data); -#endif /* WL_SCHED_SCAN */ - return 0; -} -#endif /* PNO_SUPPORT */ - -#ifdef GSCAN_SUPPORT -static s32 -wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - void *ptr; - int send_evt_bytes = 0; - int batch_event_result_dummy = 0; - struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - u32 len = ntoh32(e->datalen); - - switch (event) { - case WLC_E_PFN_BEST_BATCHING: - err = dhd_dev_retrieve_batch_scan(ndev); - if (err < 0) { - WL_ERR(("Batch retrieval already in progress %d\n", err)); - } else { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_GSCAN_BATCH_SCAN_EVENT, - &batch_event_result_dummy, sizeof(int)); - } - break; - case WLC_E_PFN_SCAN_COMPLETE: - batch_event_result_dummy = WIFI_SCAN_COMPLETE; - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_COMPLETE_EVENT, - &batch_event_result_dummy, sizeof(int)); - break; - case WLC_E_PFN_BSSID_NET_FOUND: - ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes, - HOTLIST_FOUND); - if (ptr) { - wl_cfgvendor_send_hotlist_event(wiphy, ndev, - ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT); - dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_FOUND); - } else { - err = -ENOMEM; - } - break; - case WLC_E_PFN_BSSID_NET_LOST: - /* WLC_E_PFN_BSSID_NET_LOST is conflict shared with WLC_E_PFN_SCAN_ALLGONE - * We currently do not use WLC_E_PFN_SCAN_ALLGONE, so if we get it, ignore - */ - if (len) { - ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes, - HOTLIST_LOST); - if (ptr) { - wl_cfgvendor_send_hotlist_event(wiphy, ndev, - ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT); - dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_LOST); - } else { - err = -ENOMEM; - } - } else { - err = -EINVAL; - } - break; - case WLC_E_PFN_GSCAN_FULL_RESULT: - ptr = dhd_dev_process_full_gscan_result(ndev, data, len, &send_evt_bytes); - if (ptr) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, - send_evt_bytes); - kfree(ptr); - } else { - err = -ENOMEM; - } - break; - case WLC_E_PFN_SSID_EXT: - ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes); - if (ptr) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes); - kfree(ptr); - } else { - err = -ENOMEM; - } - break; - default: - WL_ERR(("Unknown event %d\n", event)); - break; - } - return err; -} -#endif /* GSCAN_SUPPORT */ - -static s32 -wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct channel_info channel_inform; - struct wl_scan_results *bss_list; - struct net_device *ndev = NULL; - u32 len = WL_SCAN_BUF_MAX; - s32 err = 0; - unsigned long flags; - - WL_DBG(("Enter \n")); - if (!wl_get_drv_status(cfg, SCANNING, ndev)) { - WL_ERR(("scan is not ready \n")); - return err; - } - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - mutex_lock(&cfg->usr_sync); - wl_clr_drv_status(cfg, SCANNING, ndev); - err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, - sizeof(channel_inform), false); - if (unlikely(err)) { - WL_ERR(("scan busy (%d)\n", err)); - goto scan_done_out; - } - channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); - if (unlikely(channel_inform.scan_channel)) { - - WL_DBG(("channel_inform.scan_channel (%d)\n", - channel_inform.scan_channel)); - } - cfg->bss_list = cfg->scan_results; - bss_list = cfg->bss_list; - memset(bss_list, 0, len); - bss_list->buflen = htod32(len); - err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false); - if (unlikely(err) && unlikely(!cfg->scan_suppressed)) { - WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); - err = -EINVAL; - goto scan_done_out; - } - bss_list->buflen = dtoh32(bss_list->buflen); - bss_list->version = dtoh32(bss_list->version); - bss_list->count = dtoh32(bss_list->count); - - err = wl_inform_bss(cfg); - -scan_done_out: - del_timer_sync(&cfg->scan_timeout); - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - if (cfg->scan_request) { - cfg80211_scan_done(cfg->scan_request, false); - cfg->scan_request = NULL; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - WL_DBG(("cfg80211_scan_done\n")); - mutex_unlock(&cfg->usr_sync); - return err; -} - -static s32 -wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, - const struct ether_addr *sa, const struct ether_addr *bssid, - u8 **pheader, u32 *body_len, u8 *pbody) -{ - struct dot11_management_header *hdr; - u32 totlen = 0; - s32 err = 0; - u8 *offset; - u32 prebody_len = *body_len; - switch (fc) { - case FC_ASSOC_REQ: - /* capability , listen interval */ - totlen = DOT11_ASSOC_REQ_FIXED_LEN; - *body_len += DOT11_ASSOC_REQ_FIXED_LEN; - break; - - case FC_REASSOC_REQ: - /* capability, listen inteval, ap address */ - totlen = DOT11_REASSOC_REQ_FIXED_LEN; - *body_len += DOT11_REASSOC_REQ_FIXED_LEN; - break; - } - totlen += DOT11_MGMT_HDR_LEN + prebody_len; - *pheader = kzalloc(totlen, GFP_KERNEL); - if (*pheader == NULL) { - WL_ERR(("memory alloc failed \n")); - return -ENOMEM; - } - hdr = (struct dot11_management_header *) (*pheader); - hdr->fc = htol16(fc); - hdr->durid = 0; - hdr->seq = 0; - offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len); - bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN); - bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN); - bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN); - if ((pbody != NULL) && prebody_len) - bcopy((const char*)pbody, offset, prebody_len); - *body_len = totlen; - return err; -} - - -void -wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - if (timer_pending(&cfg->p2p->listen_timer)) { - del_timer_sync(&cfg->p2p->listen_timer); - } - if (cfg->afx_hdl != NULL) { - if (cfg->afx_hdl->dev != NULL) { - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev); - } - cfg->afx_hdl->peer_chan = WL_INVALID; - } - complete(&cfg->act_frm_scan); - WL_DBG(("*** Wake UP ** Working afx searching is cleared\n")); - } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) { - if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) || - wl_get_p2p_status(cfg, ACTION_TX_NOACK))) - wl_set_p2p_status(cfg, ACTION_TX_COMPLETED); - - WL_DBG(("*** Wake UP ** abort actframe iovar\n")); - /* if channel is not zero, "actfame" uses off channel scan. - * So abort scan for off channel completion. - */ - if (cfg->af_sent_channel) - wl_cfg80211_scan_abort(cfg); - } -#ifdef WL_CFG80211_SYNC_GON - else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { - WL_DBG(("*** Wake UP ** abort listen for next af frame\n")); - /* So abort scan to cancel listen */ - wl_cfg80211_scan_abort(cfg); - } -#endif /* WL_CFG80211_SYNC_GON */ -} - - -int wl_cfg80211_get_ioctl_version(void) -{ - return ioctl_version; -} - -static s32 -wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct ieee80211_supported_band *band; - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - struct ether_addr da; - struct ether_addr bssid; - bool isfree = false; - s32 err = 0; - s32 freq; - struct net_device *ndev = NULL; - wifi_p2p_pub_act_frame_t *act_frm = NULL; - wifi_p2p_action_frame_t *p2p_act_frm = NULL; - wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; - wl_event_rx_frame_data_t *rxframe; - u32 event; - u8 *mgmt_frame; - u8 bsscfgidx; - u32 mgmt_frame_len; - u16 channel; - bool retval; - if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) { - WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen))); - return -EINVAL; - } - mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); - event = ntoh32(e->event_type); - bsscfgidx = e->bsscfgidx; - rxframe = (wl_event_rx_frame_data_t *)data; - if (!rxframe) { - WL_ERR(("rxframe: NULL\n")); - return -EINVAL; - } - channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK); - memset(&bssid, 0, ETHER_ADDR_LEN); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - if (!band) { - WL_ERR(("No valid band")); - return -EINVAL; - } -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) - freq = ieee80211_channel_to_frequency(channel); - (void)band->band; -#else - freq = ieee80211_channel_to_frequency(channel, band->band); -#endif - if (event == WLC_E_ACTION_FRAME_RX) { - wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", - NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); - - err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - if (err < 0) - WL_ERR(("WLC_GET_BSSID error %d\n", err)); - memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); - err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, - &mgmt_frame, &mgmt_frame_len, - (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); - if (err < 0) { - WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n", - mgmt_frame_len, channel, freq)); - goto exit; - } - isfree = true; - if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { - act_frm = (wifi_p2p_pub_act_frame_t *) - (&mgmt_frame[DOT11_MGMT_HDR_LEN]); - } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { - p2p_act_frm = (wifi_p2p_action_frame_t *) - (&mgmt_frame[DOT11_MGMT_HDR_LEN]); - (void) p2p_act_frm; - } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { - - sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) - (&mgmt_frame[DOT11_MGMT_HDR_LEN]); - if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) { - if (cfg->next_af_subtype == sd_act_frm->action) { - WL_DBG(("We got a right next frame of SD!(%d)\n", - sd_act_frm->action)); - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); - - /* Stop waiting for next AF. */ - wl_stop_wait_next_action_frame(cfg, ndev); - } - } - (void) sd_act_frm; -#ifdef WLTDLS - } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) { - WL_DBG((" TDLS Action Frame Received type = %d \n", - mgmt_frame[DOT11_MGMT_HDR_LEN + 1])); - - if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) { - cfg->tdls_mgmt_frame = mgmt_frame; - cfg->tdls_mgmt_frame_len = mgmt_frame_len; - cfg->tdls_mgmt_freq = freq; - return 0; - } - - } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_VENDOR_SPECIFIC) { - WL_DBG((" TDLS Vendor Specific Received type \n")); -#endif - } else { - - if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { - u8 action = 0; - if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) { - WL_DBG(("Recived action is not public action frame\n")); - } else if (cfg->next_af_subtype == action) { - WL_DBG(("Recived action is the waiting action(%d)\n", - action)); - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); - - /* Stop waiting for next AF. */ - wl_stop_wait_next_action_frame(cfg, ndev); - } - } - } - - if (act_frm) { - - if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) { - if (cfg->next_af_subtype == act_frm->subtype) { - WL_DBG(("We got a right next frame!(%d)\n", - act_frm->subtype)); - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); - - if (cfg->next_af_subtype == P2P_PAF_GON_CONF) { - OSL_SLEEP(20); - } - - /* Stop waiting for next AF. */ - wl_stop_wait_next_action_frame(cfg, ndev); - } - } - } - - wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel); - /* - * After complete GO Negotiation, roll back to mpc mode - */ - if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || - (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { - wldev_iovar_setint(ndev, "mpc", 1); - } - if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { - WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - } - } else if (event == WLC_E_PROBREQ_MSG) { - - /* Handle probe reqs frame - * WPS-AP certification 4.2.13 - */ - struct parsed_ies prbreq_ies; - u32 prbreq_ie_len = 0; - bool pbc = 0; - - WL_DBG((" Event WLC_E_PROBREQ_MSG received\n")); - mgmt_frame = (u8 *)(data); - mgmt_frame_len = ntoh32(e->datalen); - - if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) { - WL_ERR(("wrong datalen:%d\n", mgmt_frame_len)); - return -EINVAL; - } - prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN; - - /* Parse prob_req IEs */ - if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN], - prbreq_ie_len, &prbreq_ies) < 0) { - WL_ERR(("Prob req get IEs failed\n")); - return 0; - } - if (prbreq_ies.wps_ie != NULL) { - wl_validate_wps_ie((char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc); - WL_DBG((" wps_ie exist pbc = %d\n", pbc)); - /* if pbc method, send prob_req mgmt frame to upper layer */ - if (!pbc) - return 0; - } else - return 0; - } else { - mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); - - /* wpa supplicant use probe request event for restarting another GON Req. - * but it makes GON Req repetition. - * so if src addr of prb req is same as my target device, - * do not send probe request event during sending action frame. - */ - if (event == WLC_E_P2P_PROBREQ_MSG) { - WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ? - "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG")); - - - /* Filter any P2P probe reqs arriving during the - * GO-NEG Phase - */ - if (cfg->p2p && - wl_get_p2p_status(cfg, GO_NEG_PHASE)) { - WL_DBG(("Filtering P2P probe_req while " - "being in GO-Neg state\n")); - return 0; - } - } - } - - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) - retval = cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) - retval = cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); -#else - retval = cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); -#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ - - WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d) retval (%d)\n", - mgmt_frame_len, ntoh32(e->datalen), channel, freq, retval)); -exit: - if (isfree) - kfree(mgmt_frame); - return 0; -} - -#ifdef WL_SCHED_SCAN -/* If target scan is not reliable, set the below define to "1" to do a - * full escan - */ -#define FULL_ESCAN_ON_PFN_NET_FOUND 0 -static s32 -wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - wl_pfn_net_info_t *netinfo, *pnetinfo; - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - int err = 0; - struct cfg80211_scan_request *request = NULL; - struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; - struct ieee80211_channel *channel = NULL; - int channel_req = 0; - int band = 0; - struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; - int n_pfn_results = pfn_result->count; - - WL_DBG(("Enter\n")); - - if ((e->event_type == WLC_E_PFN_NET_LOST) || !data) { - WL_PNO(("Do Nothing %d\n", e->event_type)); - return 0; - } - if (pfn_result->version != PFN_SCANRESULT_VERSION) { - WL_ERR(("Incorrect version %d, expected %d\n", pfn_result->version, - PFN_SCANRESULT_VERSION)); - return 0; - } - WL_PNO((">>> PFN NET FOUND event. count:%d \n", n_pfn_results)); - if (n_pfn_results > 0) { - int i; - - if (n_pfn_results > MAX_PFN_LIST_COUNT) - n_pfn_results = MAX_PFN_LIST_COUNT; - pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) - - sizeof(wl_pfn_net_info_t)); - - memset(&ssid, 0x00, sizeof(ssid)); - - request = kzalloc(sizeof(*request) - + sizeof(*request->channels) * n_pfn_results, - GFP_KERNEL); - channel = (struct ieee80211_channel *)kzalloc( - (sizeof(struct ieee80211_channel) * n_pfn_results), - GFP_KERNEL); - if (!request || !channel) { - WL_ERR(("No memory")); - err = -ENOMEM; - goto out_err; - } - - request->wiphy = wiphy; - - for (i = 0; i < n_pfn_results; i++) { - netinfo = &pnetinfo[i]; - if (!netinfo) { - WL_ERR(("Invalid netinfo ptr. index:%d", i)); - err = -EINVAL; - goto out_err; - } - WL_PNO((">>> SSID:%s Channel:%d \n", - netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel)); - /* PFN result doesn't have all the info which are required by the supplicant - * (For e.g IEs) Do a target Escan so that sched scan results are reported - * via wl_inform_single_bss in the required format. Escan does require the - * scan request in the form of cfg80211_scan_request. For timebeing, create - * cfg80211_scan_request one out of the received PNO event. - */ - ssid[i].ssid_len = MIN(netinfo->pfnsubnet.SSID_len, DOT11_MAX_SSID_LEN); - memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, ssid[i].ssid_len); - request->n_ssids++; - - channel_req = netinfo->pfnsubnet.channel; - band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ - : NL80211_BAND_5GHZ; - channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); - channel[i].band = band; - channel[i].flags |= IEEE80211_CHAN_NO_HT40; - request->channels[i] = &channel[i]; - request->n_channels++; - } - - /* assign parsed ssid array */ - if (request->n_ssids) - request->ssids = &ssid[0]; - - if (wl_get_drv_status_all(cfg, SCANNING)) { - /* Abort any on-going scan */ - wl_notify_escan_complete(cfg, ndev, true, true); - } - - if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { - WL_PNO((">>> P2P discovery was ON. Disabling it\n")); - err = wl_cfgp2p_discover_enable_search(cfg, false); - if (unlikely(err)) { - wl_clr_drv_status(cfg, SCANNING, ndev); - goto out_err; - } - p2p_scan(cfg) = false; - } - - wl_set_drv_status(cfg, SCANNING, ndev); -#if FULL_ESCAN_ON_PFN_NET_FOUND - WL_PNO((">>> Doing Full ESCAN on PNO event\n")); - err = wl_do_escan(cfg, wiphy, ndev, NULL); -#else - WL_PNO((">>> Doing targeted ESCAN on PNO event\n")); - err = wl_do_escan(cfg, wiphy, ndev, request); -#endif - if (err) { - wl_clr_drv_status(cfg, SCANNING, ndev); - goto out_err; - } - cfg->sched_scan_running = TRUE; - } - else { - WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); - } -out_err: - if (request) - kfree(request); - if (channel) - kfree(channel); - return err; -} -#endif /* WL_SCHED_SCAN */ - -static void wl_init_conf(struct wl_conf *conf) -{ - WL_DBG(("Enter \n")); - 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 wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - unsigned long flags; - struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); - - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - memset(profile, 0, sizeof(struct wl_profile)); - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); -} - -static void wl_init_event_handler(struct bcm_cfg80211 *cfg) -{ - memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler)); - - cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; - cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; - cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; - cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; - cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; - cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; - cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; - cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; - cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; - cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_START] = wl_notify_connect_status; -#ifdef PNO_SUPPORT - cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; -#endif /* PNO_SUPPORT */ -#ifdef GSCAN_SUPPORT - cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event; -#endif /* GSCAN_SUPPORT */ - cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event; -#ifdef WLTDLS - cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler; -#endif /* WLTDLS */ - cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status; -#ifdef WLAIBSS - cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail; -#endif /* WLAIBSS */ -#ifdef BT_WIFI_HANDOVER - cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req; -#endif - cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status; - cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind; -} - -#if defined(STATIC_WL_PRIV_STRUCT) -static void -wl_init_escan_result_buf(struct bcm_cfg80211 *cfg) -{ - cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub, - DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE); - bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE); -} - -static void -wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg) -{ - cfg->escan_info.escan_buf = NULL; - -} -#endif /* STATIC_WL_PRIV_STRUCT */ - -static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg) -{ - WL_DBG(("Enter \n")); - cfg->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); - if (unlikely(!cfg->scan_results)) { - WL_ERR(("Scan results alloc failed\n")); - goto init_priv_mem_out; - } - cfg->conf = (void *)kzalloc(sizeof(*cfg->conf), GFP_KERNEL); - if (unlikely(!cfg->conf)) { - WL_ERR(("wl_conf alloc failed\n")); - goto init_priv_mem_out; - } - cfg->scan_req_int = - (void *)kzalloc(sizeof(*cfg->scan_req_int), GFP_KERNEL); - if (unlikely(!cfg->scan_req_int)) { - WL_ERR(("Scan req alloc failed\n")); - goto init_priv_mem_out; - } - cfg->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); - if (unlikely(!cfg->ioctl_buf)) { - WL_ERR(("Ioctl buf alloc failed\n")); - goto init_priv_mem_out; - } - cfg->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); - if (unlikely(!cfg->escan_ioctl_buf)) { - WL_ERR(("Ioctl buf alloc failed\n")); - goto init_priv_mem_out; - } - cfg->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); - if (unlikely(!cfg->extra_buf)) { - WL_ERR(("Extra buf alloc failed\n")); - goto init_priv_mem_out; - } - cfg->pmk_list = (void *)kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL); - if (unlikely(!cfg->pmk_list)) { - WL_ERR(("pmk list alloc failed\n")); - goto init_priv_mem_out; - } - cfg->sta_info = (void *)kzalloc(sizeof(*cfg->sta_info), GFP_KERNEL); - if (unlikely(!cfg->sta_info)) { - WL_ERR(("sta info alloc failed\n")); - goto init_priv_mem_out; - } - -#if defined(STATIC_WL_PRIV_STRUCT) - cfg->conn_info = (void *)kzalloc(sizeof(*cfg->conn_info), GFP_KERNEL); - if (unlikely(!cfg->conn_info)) { - WL_ERR(("cfg->conn_info alloc failed\n")); - goto init_priv_mem_out; - } - cfg->ie = (void *)kzalloc(sizeof(*cfg->ie), GFP_KERNEL); - if (unlikely(!cfg->ie)) { - WL_ERR(("cfg->ie alloc failed\n")); - goto init_priv_mem_out; - } - wl_init_escan_result_buf(cfg); -#endif /* STATIC_WL_PRIV_STRUCT */ - cfg->afx_hdl = (void *)kzalloc(sizeof(*cfg->afx_hdl), GFP_KERNEL); - if (unlikely(!cfg->afx_hdl)) { - WL_ERR(("afx hdl alloc failed\n")); - goto init_priv_mem_out; - } else { - init_completion(&cfg->act_frm_scan); - init_completion(&cfg->wait_next_af); - - INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler); - } - return 0; - -init_priv_mem_out: - wl_deinit_priv_mem(cfg); - - return -ENOMEM; -} - -static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg) -{ - kfree(cfg->scan_results); - cfg->scan_results = NULL; - kfree(cfg->conf); - cfg->conf = NULL; - kfree(cfg->scan_req_int); - cfg->scan_req_int = NULL; - kfree(cfg->ioctl_buf); - cfg->ioctl_buf = NULL; - kfree(cfg->escan_ioctl_buf); - cfg->escan_ioctl_buf = NULL; - kfree(cfg->extra_buf); - cfg->extra_buf = NULL; - kfree(cfg->pmk_list); - cfg->pmk_list = NULL; - kfree(cfg->sta_info); - cfg->sta_info = NULL; -#if defined(STATIC_WL_PRIV_STRUCT) - kfree(cfg->conn_info); - cfg->conn_info = NULL; - kfree(cfg->ie); - cfg->ie = NULL; - wl_deinit_escan_result_buf(cfg); -#endif /* STATIC_WL_PRIV_STRUCT */ - if (cfg->afx_hdl) { - cancel_work_sync(&cfg->afx_hdl->work); - kfree(cfg->afx_hdl); - cfg->afx_hdl = NULL; - } - - if (cfg->ap_info) { - kfree(cfg->ap_info->wpa_ie); - kfree(cfg->ap_info->rsn_ie); - kfree(cfg->ap_info->wps_ie); - kfree(cfg->ap_info); - cfg->ap_info = NULL; - } -#ifdef WLTDLS - if (cfg->tdls_mgmt_frame) { - kfree(cfg->tdls_mgmt_frame); - cfg->tdls_mgmt_frame = NULL; - } -#endif /* WLTDLS */ -} - -static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg) -{ - int ret = 0; - WL_DBG(("Enter \n")); - - /* Do not use DHD in cfg driver */ - cfg->event_tsk.thr_pid = -1; - - PROC_START(wl_event_handler, cfg, &cfg->event_tsk, 0, "wl_event_handler"); - if (cfg->event_tsk.thr_pid < 0) - ret = -ENOMEM; - return ret; -} - -static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg) -{ - if (cfg->event_tsk.thr_pid >= 0) - PROC_STOP(&cfg->event_tsk); -} - -void wl_reinit_event_handler(void) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - if (cfg) { - wl_flush_eq(cfg); - } -} - -static void wl_scan_timeout(unsigned long data) -{ - wl_event_msg_t msg; - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; - - if (!(cfg->scan_request)) { - WL_ERR(("timer expired but no scan request\n")); - return; - } - bzero(&msg, sizeof(wl_event_msg_t)); - WL_ERR(("timer expired\n")); - msg.event_type = hton32(WLC_E_ESCAN_RESULT); - msg.status = hton32(WLC_E_STATUS_TIMEOUT); - msg.reason = 0xFFFFFFFF; - wl_cfg80211_event(bcmcfg_to_prmry_ndev(cfg), &msg, NULL); -} - -static s32 -wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, - unsigned long state, - void *ndev) -{ - struct net_device *dev = ndev; - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - WL_DBG(("Enter \n")); - - if (!wdev || !cfg || dev == bcmcfg_to_prmry_ndev(cfg)) - return NOTIFY_DONE; - - switch (state) { - case NETDEV_DOWN: - { -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) - int max_wait_timeout = 2; - int max_wait_count = 100; - int refcnt = 0; - unsigned long limit = jiffies + max_wait_timeout * HZ; - while (work_pending(&wdev->cleanup_work)) { - if (refcnt%5 == 0) { - WL_ERR(("[NETDEV_DOWN] wait for " - "complete of cleanup_work" - " (%d th)\n", refcnt)); - } - if (!time_before(jiffies, limit)) { - WL_ERR(("[NETDEV_DOWN] cleanup_work" - " of CFG80211 is not" - " completed in %d sec\n", - max_wait_timeout)); - break; - } - if (refcnt >= max_wait_count) { - WL_ERR(("[NETDEV_DOWN] cleanup_work" - " of CFG80211 is not" - " completed in %d loop\n", - max_wait_count)); - break; - } - set_current_state(TASK_INTERRUPTIBLE); - (void)schedule_timeout(HZ); - set_current_state(TASK_RUNNING); - refcnt++; - } -#endif /* LINUX_VERSION < VERSION(3, 14, 0) */ - break; - } - - case NETDEV_UNREGISTER: - /* after calling list_del_rcu(&wdev->list) */ - wl_dealloc_netinfo(cfg, ndev); - break; - case NETDEV_GOING_DOWN: - /* At NETDEV_DOWN state, wdev_cleanup_work work will be called. - * In front of door, the function checks - * whether current scan is working or not. - * If the scanning is still working, wdev_cleanup_work call WARN_ON and - * make the scan done forcibly. - */ - if (wl_get_drv_status(cfg, SCANNING, dev)) - wl_notify_escan_complete(cfg, dev, true, true); - break; - } - return NOTIFY_DONE; -} -static struct notifier_block wl_cfg80211_netdev_notifier = { - .notifier_call = wl_cfg80211_netdev_notifier_call, -}; -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool wl_cfg80211_netdev_notifier_registered = FALSE; - -static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg) -{ - wl_scan_params_t *params = NULL; - s32 params_size = 0; - s32 err = BCME_OK; - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - if (!in_atomic()) { - /* Our scan params only need space for 1 channel and 0 ssids */ - params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); - if (params == NULL) { - WL_ERR(("scan params allocation failed \n")); - err = -ENOMEM; - } else { - /* Do a scan abort to stop the driver's scan engine */ - err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); - if (err < 0) { - WL_ERR(("scan abort failed \n")); - } - kfree(params); - } - } -} - -#if defined(WL_ABORT_SCAN) -static void wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (cfg == NULL) { - WL_ERR(("Parsing parameter failed\n")); - return; - } - wl_cfg80211_scan_abort(cfg); -} -#endif /* WL_ABORT_SCAN */ - -static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, - struct net_device *ndev, - bool aborted, bool fw_abort) -{ - s32 err = BCME_OK; - unsigned long flags; - struct net_device *dev; - - WL_DBG(("Enter \n")); - if (!ndev) { - WL_ERR(("ndev is null\n")); - err = BCME_ERROR; - return err; - } - - if (cfg->escan_info.ndev != ndev) { - WL_ERR(("ndev is different %p %p\n", cfg->escan_info.ndev, ndev)); - err = BCME_ERROR; - return err; - } - - if (cfg->scan_request) { - dev = bcmcfg_to_prmry_ndev(cfg); -#if defined(WL_ENABLE_P2P_IF) - if (cfg->scan_request->dev != cfg->p2p_net) - dev = cfg->scan_request->dev; -#endif /* WL_ENABLE_P2P_IF */ - } - else { - WL_DBG(("cfg->scan_request is NULL may be internal scan." - "doing scan_abort for ndev %p primary %p", - ndev, bcmcfg_to_prmry_ndev(cfg))); - dev = ndev; - } - if (fw_abort && !in_atomic()) - wl_cfg80211_scan_abort(cfg); - if (timer_pending(&cfg->scan_timeout)) - del_timer_sync(&cfg->scan_timeout); -#if defined(ESCAN_RESULT_PATCH) - if (likely(cfg->scan_request)) { - cfg->bss_list = wl_escan_get_buf(cfg, aborted); - wl_inform_bss(cfg); - } -#endif /* ESCAN_RESULT_PATCH */ - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); -#ifdef WL_SCHED_SCAN - if (cfg->sched_scan_req && !cfg->scan_request) { - WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n")); - if (!aborted) - cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy); - cfg->sched_scan_running = FALSE; - cfg->sched_scan_req = NULL; - } -#endif /* WL_SCHED_SCAN */ - if (likely(cfg->scan_request)) { - cfg80211_scan_done(cfg->scan_request, aborted); - cfg->scan_request = NULL; - } - if (p2p_is_on(cfg)) - wl_clr_p2p_status(cfg, SCANNING); - wl_clr_drv_status(cfg, SCANNING, dev); - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - return err; -} - -#ifdef ESCAN_BUF_OVERFLOW_MGMT -static void -wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate) -{ - int idx; - for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) { - int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1; - if (bss->RSSI < candidate[idx].RSSI) { - if (len) - memcpy(&candidate[idx + 1], &candidate[idx], - sizeof(removal_element_t) * len); - candidate[idx].RSSI = bss->RSSI; - candidate[idx].length = bss->length; - memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN); - return; - } - } -} - -static void -wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate, - wl_bss_info_t *bi) -{ - int idx1, idx2; - int total_delete_len = 0; - for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) { - int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; - wl_bss_info_t *bss = NULL; - if (candidate[idx1].RSSI >= bi->RSSI) - continue; - for (idx2 = 0; idx2 < list->count; idx2++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) : - list->bss_info; - if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) && - candidate[idx1].RSSI == bss->RSSI && - candidate[idx1].length == dtoh32(bss->length)) { - u32 delete_len = dtoh32(bss->length); - WL_DBG(("delete scan info of " MACDBG " to add new AP\n", - MAC2STRDBG(bss->BSSID.octet))); - if (idx2 < list->count -1) { - memmove((u8 *)bss, (u8 *)bss + delete_len, - list->buflen - cur_len - delete_len); - } - list->buflen -= delete_len; - list->count--; - total_delete_len += delete_len; - /* if delete_len is greater than or equal to result length */ - if (total_delete_len >= bi->length) { - return; - } - break; - } - cur_len += dtoh32(bss->length); - } - } -} -#endif /* ESCAN_BUF_OVERFLOW_MGMT */ - -static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - s32 err = BCME_OK; - s32 status = ntoh32(e->status); - wl_bss_info_t *bi; - wl_escan_result_t *escan_result; - wl_bss_info_t *bss = NULL; - wl_scan_results_t *list; - wifi_p2p_ie_t * p2p_ie; - struct net_device *ndev = NULL; - u32 bi_length; - u32 i; - u8 *p2p_dev_addr = NULL; - - WL_DBG((" enter event type : %d, status : %d \n", - ntoh32(e->event_type), ntoh32(e->status))); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - mutex_lock(&cfg->usr_sync); - /* P2P SCAN is coming from primary interface */ - if (wl_get_p2p_status(cfg, SCANNING)) { - if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) - ndev = cfg->afx_hdl->dev; - else - ndev = cfg->escan_info.ndev; - - } - if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) { - WL_ERR(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n", - ndev, wl_get_drv_status(cfg, SCANNING, ndev), - ntoh32(e->event_type), ntoh32(e->status))); - goto exit; - } - escan_result = (wl_escan_result_t *)data; - - if (status == WLC_E_STATUS_PARTIAL) { - WL_INFORM(("WLC_E_STATUS_PARTIAL \n")); - if (!escan_result) { - WL_ERR(("Invalid escan result (NULL pointer)\n")); - goto exit; - } - if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) || - (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) { - WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen))); - goto exit; - } - if (dtoh16(escan_result->bss_count) != 1) { - WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); - goto exit; - } - bi = escan_result->bss_info; - if (!bi) { - WL_ERR(("Invalid escan bss info (NULL pointer)\n")); - goto exit; - } - bi_length = dtoh32(bi->length); - if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { - WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); - goto exit; - } - if (wl_escan_check_sync_id(status, escan_result->sync_id, - cfg->escan_info.cur_sync_id) < 0) - goto exit; - - if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { - if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { - WL_DBG(("Ignoring IBSS result\n")); - goto exit; - } - } - - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); - if (p2p_dev_addr && !memcmp(p2p_dev_addr, - cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) { - s32 channel = wf_chspec_ctlchan( - wl_chspec_driver_to_host(bi->chanspec)); - - if ((channel > MAXCHANNEL) || (channel <= 0)) - channel = WL_INVALID; - else - WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found," - " channel : %d\n", - MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet), - channel)); - - wl_clr_p2p_status(cfg, SCANNING); - cfg->afx_hdl->peer_chan = channel; - complete(&cfg->act_frm_scan); - goto exit; - } - - } else { - int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; -#ifdef ESCAN_BUF_OVERFLOW_MGMT - removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT]; - int remove_lower_rssi = FALSE; - - bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT); -#endif /* ESCAN_BUF_OVERFLOW_MGMT */ - - list = wl_escan_get_buf(cfg, FALSE); - if (scan_req_match(cfg)) { -#ifdef WL_HOST_BAND_MGMT - s32 channel = 0; - s32 channel_band = 0; - chanspec_t chspec; -#endif /* WL_HOST_BAND_MGMT */ - /* p2p scan && allow only probe response */ - if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) && - (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) - goto exit; - if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, - bi->ie_length)) == NULL) { - WL_ERR(("Couldn't find P2PIE in probe" - " response/beacon\n")); - goto exit; - } -#ifdef WL_HOST_BAND_MGMT - chspec = wl_chspec_driver_to_host(bi->chanspec); - channel = wf_chspec_ctlchan(chspec); - channel_band = CHSPEC2WLC_BAND(chspec); - - if ((cfg->curr_band == WLC_BAND_5G) && - (channel_band == WLC_BAND_2G)) { - /* Avoid sending the GO results in band conflict */ - if (wl_cfgp2p_retreive_p2pattrib(p2p_ie, - P2P_SEID_GROUP_ID) != NULL) - goto exit; - } -#endif /* WL_HOST_BAND_MGMT */ - } -#ifdef ESCAN_BUF_OVERFLOW_MGMT - if (bi_length > ESCAN_BUF_SIZE - list->buflen) - remove_lower_rssi = TRUE; -#endif /* ESCAN_BUF_OVERFLOW_MGMT */ - - for (i = 0; i < list->count; i++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) - : list->bss_info; -#ifdef ESCAN_BUF_OVERFLOW_MGMT - WL_TRACE(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n", - bss->SSID, MAC2STRDBG(bss->BSSID.octet), - i, bss->RSSI, list->count)); - - if (remove_lower_rssi) - wl_cfg80211_find_removal_candidate(bss, candidate); -#endif /* ESCAN_BUF_OVERFLOW_MGMT */ - - if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && - (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec)) - == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) && - bi->SSID_len == bss->SSID_len && - !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { - - /* do not allow beacon data to update - *the data recd from a probe response - */ - if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) && - (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) - goto exit; - - WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d" - " flags 0x%x, new: RSSI %d flags 0x%x\n", - bss->SSID, MAC2STRDBG(bi->BSSID.octet), i, - bss->RSSI, bss->flags, bi->RSSI, bi->flags)); - - if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == - (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) { - /* preserve max RSSI if the measurements are - * both on-channel or both off-channel - */ - WL_SCAN(("%s("MACDBG"), same onchan" - ", RSSI: prev %d new %d\n", - bss->SSID, MAC2STRDBG(bi->BSSID.octet), - bss->RSSI, bi->RSSI)); - bi->RSSI = MAX(bss->RSSI, bi->RSSI); - } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && - (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { - /* preserve the on-channel rssi measurement - * if the new measurement is off channel - */ - WL_SCAN(("%s("MACDBG"), prev onchan" - ", RSSI: prev %d new %d\n", - bss->SSID, MAC2STRDBG(bi->BSSID.octet), - bss->RSSI, bi->RSSI)); - bi->RSSI = bss->RSSI; - bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; - } - if (dtoh32(bss->length) != bi_length) { - u32 prev_len = dtoh32(bss->length); - - WL_SCAN(("bss info replacement" - " is occured(bcast:%d->probresp%d)\n", - bss->ie_length, bi->ie_length)); - WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n", - bss->SSID, MAC2STRDBG(bi->BSSID.octet), - prev_len, bi_length)); - - if (list->buflen - prev_len + bi_length - > ESCAN_BUF_SIZE) { - WL_ERR(("Buffer is too small: keep the" - " previous result of this AP\n")); - /* Only update RSSI */ - bss->RSSI = bi->RSSI; - bss->flags |= (bi->flags - & WL_BSS_FLAGS_RSSI_ONCHANNEL); - goto exit; - } - - if (i < list->count - 1) { - /* memory copy required by this case only */ - memmove((u8 *)bss + bi_length, - (u8 *)bss + prev_len, - list->buflen - cur_len - prev_len); - } - list->buflen -= prev_len; - list->buflen += bi_length; - } - list->version = dtoh32(bi->version); - memcpy((u8 *)bss, (u8 *)bi, bi_length); - goto exit; - } - cur_len += dtoh32(bss->length); - } - if (bi_length > ESCAN_BUF_SIZE - list->buflen) { -#ifdef ESCAN_BUF_OVERFLOW_MGMT - wl_cfg80211_remove_lowRSSI_info(list, candidate, bi); - if (bi_length > ESCAN_BUF_SIZE - list->buflen) { - WL_DBG(("RSSI(" MACDBG ") is too low(%d) to add Buffer\n", - MAC2STRDBG(bi->BSSID.octet), bi->RSSI)); - goto exit; - } -#else - WL_ERR(("Buffer is too small: ignoring\n")); - goto exit; -#endif /* ESCAN_BUF_OVERFLOW_MGMT */ - } - - memcpy(&(((char *)list)[list->buflen]), bi, bi_length); - list->version = dtoh32(bi->version); - list->buflen += bi_length; - list->count++; - - /* - * !Broadcast && number of ssid = 1 && number of channels =1 - * means specific scan to association - */ - if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) { - WL_ERR(("P2P assoc scan fast aborted.\n")); - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false, true); - goto exit; - } - } - - } - else if (status == WLC_E_STATUS_SUCCESS) { - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id, - escan_result->sync_id); - - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - WL_INFORM(("ACTION FRAME SCAN DONE\n")); - wl_clr_p2p_status(cfg, SCANNING); - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - if (cfg->afx_hdl->peer_chan == WL_INVALID) - complete(&cfg->act_frm_scan); - } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { - WL_INFORM(("ESCAN COMPLETED\n")); - cfg->bss_list = wl_escan_get_buf(cfg, FALSE); - if (!scan_req_match(cfg)) { - WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n", - cfg->bss_list->count)); - } - wl_inform_bss(cfg); - wl_notify_escan_complete(cfg, ndev, false, false); - } - wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); - } - else if (status == WLC_E_STATUS_ABORT) { - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - wl_escan_print_sync_id(status, escan_result->sync_id, - cfg->escan_info.cur_sync_id); - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - WL_INFORM(("ACTION FRAME SCAN DONE\n")); - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - wl_clr_p2p_status(cfg, SCANNING); - if (cfg->afx_hdl->peer_chan == WL_INVALID) - complete(&cfg->act_frm_scan); - } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { - WL_INFORM(("ESCAN ABORTED\n")); - cfg->bss_list = wl_escan_get_buf(cfg, TRUE); - if (!scan_req_match(cfg)) { - WL_TRACE_HW4(("SCAN ABORTED: scanned AP count=%d\n", - cfg->bss_list->count)); - } - wl_inform_bss(cfg); - wl_notify_escan_complete(cfg, ndev, true, false); - } - wl_escan_increment_sync_id(cfg, SCAN_BUF_CNT); - } else if (status == WLC_E_STATUS_NEWSCAN) { - WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, - escan_result->bss_count)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("reason[0x%x]\n", e->reason)); - if (e->reason == 0xFFFFFFFF) { - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); - } - } else { - WL_ERR(("unexpected Escan Event %d : abort\n", status)); - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - wl_escan_print_sync_id(status, escan_result->sync_id, - cfg->escan_info.cur_sync_id); - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - WL_INFORM(("ACTION FRAME SCAN DONE\n")); - wl_clr_p2p_status(cfg, SCANNING); - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - if (cfg->afx_hdl->peer_chan == WL_INVALID) - complete(&cfg->act_frm_scan); - } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { - cfg->bss_list = wl_escan_get_buf(cfg, TRUE); - if (!scan_req_match(cfg)) { - WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): " - "scanned AP count=%d\n", - cfg->bss_list->count)); - } - wl_inform_bss(cfg); - wl_notify_escan_complete(cfg, ndev, true, false); - } - wl_escan_increment_sync_id(cfg, 2); - } -exit: - mutex_unlock(&cfg->usr_sync); - return err; -} - -static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable) -{ - u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED); - struct net_info *iter, *next; - int err; - - if (!cfg->roamoff_on_concurrent) - return; - if (enable && connected_cnt > 1) { - for_each_ndev(cfg, iter, next) { - /* Save the current roam setting */ - if ((err = wldev_iovar_getint(iter->ndev, "roam_off", - (s32 *)&iter->roam_off)) != BCME_OK) { - WL_ERR(("%s:Failed to get current roam setting err %d\n", - iter->ndev->name, err)); - continue; - } - if ((err = wldev_iovar_setint(iter->ndev, "roam_off", 1)) != BCME_OK) { - WL_ERR((" %s:failed to set roam_off : %d\n", - iter->ndev->name, err)); - } - } - } - else if (!enable) { - for_each_ndev(cfg, iter, next) { - if (iter->roam_off != WL_INVALID) { - if ((err = wldev_iovar_setint(iter->ndev, "roam_off", - iter->roam_off)) == BCME_OK) - iter->roam_off = WL_INVALID; - else { - WL_ERR((" %s:failed to set roam_off : %d\n", - iter->ndev->name, err)); - } - } - } - } - return; -} - -static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg) -{ - struct net_info *iter, *next; - u32 ctl_chan = 0; - u32 chanspec = 0; - u32 pre_ctl_chan = 0; - u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED); - cfg->vsdb_mode = false; - - if (connected_cnt <= 1) { - return; - } - for_each_ndev(cfg, iter, next) { - chanspec = 0; - ctl_chan = 0; - if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) { - if (wldev_iovar_getint(iter->ndev, "chanspec", - (s32 *)&chanspec) == BCME_OK) { - chanspec = wl_chspec_driver_to_host(chanspec); - ctl_chan = wf_chspec_ctlchan(chanspec); - wl_update_prof(cfg, iter->ndev, NULL, - &ctl_chan, WL_PROF_CHAN); - } - if (!cfg->vsdb_mode) { - if (!pre_ctl_chan && ctl_chan) - pre_ctl_chan = ctl_chan; - else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) { - cfg->vsdb_mode = true; - } - } - } - } - WL_ERR(("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel")); - return; -} - - -static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, - enum wl_status state, bool set) -{ - s32 pm = PM_FAST; - s32 err = BCME_OK; - u32 mode; - u32 chan = 0; - struct net_info *iter, *next; - struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); - WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n", - state, set, _net_info->pm_restore, _net_info->ndev->name)); - - if (state != WL_STATUS_CONNECTED) - return 0; - mode = wl_get_mode_by_netdev(cfg, _net_info->ndev); - if (set) { - wl_cfg80211_concurrent_roam(cfg, 1); - - if (mode == WL_MODE_AP) { - - if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false)) - WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); - } - wl_cfg80211_determine_vsdb_mode(cfg); - if (cfg->vsdb_mode || _net_info->pm_block) { - /* Delete pm_enable_work */ - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_MAINTAIN); - /* save PM_FAST in _net_info to restore this - * if _net_info->pm_block is false - */ - if (!_net_info->pm_block && (mode == WL_MODE_BSS)) { - _net_info->pm = PM_FAST; - _net_info->pm_restore = true; - } - pm = PM_OFF; - for_each_ndev(cfg, iter, next) { - if (iter->pm_restore) - continue; - /* Save the current power mode */ - err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, - sizeof(iter->pm), false); - WL_DBG(("%s:power save %s\n", iter->ndev->name, - iter->pm ? "enabled" : "disabled")); - if (!err && iter->pm) { - iter->pm_restore = true; - } - - } - for_each_ndev(cfg, iter, next) { - if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev)) - continue; - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, - sizeof(pm), true)) != 0) { - if (err == -ENODEV) - WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); - else - WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); - wl_cfg80211_update_power_mode(iter->ndev); - } - } - } else { - /* add PM Enable timer to go to power save mode - * if supplicant control pm mode, it will be cleared or - * updated by wl_cfg80211_set_power_mgmt() if not - for static IP & HW4 P2P, - * PM will be configured when timer expired - */ - - /* - * before calling pm_enable_timer, we need to set PM -1 for all ndev - */ - pm = PM_OFF; - if (!_net_info->pm_block) { - for_each_ndev(cfg, iter, next) { - if (iter->pm_restore) - continue; - /* Save the current power mode */ - err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, - sizeof(iter->pm), false); - WL_DBG(("%s:power save %s\n", iter->ndev->name, - iter->pm ? "enabled" : "disabled")); - if (!err && iter->pm) { - iter->pm_restore = true; - } - } - } - for_each_ndev(cfg, iter, next) { - if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev)) - continue; - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, - sizeof(pm), true)) != 0) { - if (err == -ENODEV) - WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); - else - WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); - } - } - - if (cfg->pm_enable_work_on) { - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - } - - cfg->pm_enable_work_on = true; - wl_add_remove_pm_enable_work(cfg, TRUE, WL_HANDLER_NOTUSE); - } -#if defined(WLTDLS) -#if defined(DISABLE_TDLS_IN_P2P) - if (cfg->vsdb_mode || p2p_is_on(cfg)) -#else - if (cfg->vsdb_mode) -#endif /* defined(DISABLE_TDLS_IN_P2P) */ - { - - err = wldev_iovar_setint(primary_dev, "tdls_enable", 0); - } -#endif /* defined(WLTDLS) */ - - } - else { /* clear */ - chan = 0; - /* clear chan information when the net device is disconnected */ - wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); - wl_cfg80211_determine_vsdb_mode(cfg); - for_each_ndev(cfg, iter, next) { - if (iter->pm_restore && iter->pm) { - WL_DBG(("%s:restoring power save %s\n", - iter->ndev->name, (iter->pm ? "enabled" : "disabled"))); - err = wldev_ioctl(iter->ndev, - WLC_SET_PM, &iter->pm, sizeof(iter->pm), true); - if (unlikely(err)) { - if (err == -ENODEV) - WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); - else - WL_ERR(("%s:error(%d)\n", iter->ndev->name, err)); - break; - } - iter->pm_restore = 0; - wl_cfg80211_update_power_mode(iter->ndev); - } - } - wl_cfg80211_concurrent_roam(cfg, 0); -#if defined(WLTDLS) - if (!cfg->vsdb_mode) { - err = wldev_iovar_setint(primary_dev, "tdls_enable", 1); - } -#endif /* defined(WLTDLS) */ - - - } - return err; -} -static s32 wl_init_scan(struct bcm_cfg80211 *cfg) -{ - int err = 0; - - cfg->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - wl_escan_init_sync_id(cfg); - - /* Init scan_timeout timer */ - init_timer(&cfg->scan_timeout); - cfg->scan_timeout.data = (unsigned long) cfg; - cfg->scan_timeout.function = wl_scan_timeout; - - return err; -} - -static s32 wl_init_priv(struct bcm_cfg80211 *cfg) -{ - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; - - cfg->scan_request = NULL; - cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); - cfg->roam_on = false; - cfg->active_scan = true; - cfg->rf_blocked = false; - cfg->vsdb_mode = false; -#if defined(BCMSDIO) - cfg->wlfc_on = false; -#endif - cfg->roamoff_on_concurrent = true; - cfg->disable_roam_event = false; - /* register interested state */ - set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state); - spin_lock_init(&cfg->cfgdrv_lock); - mutex_init(&cfg->ioctl_buf_sync); - init_waitqueue_head(&cfg->netif_change_event); - init_completion(&cfg->send_af_done); - init_completion(&cfg->iface_disable); - wl_init_eq(cfg); - err = wl_init_priv_mem(cfg); - if (err) - return err; - if (wl_create_event_handler(cfg)) - return -ENOMEM; - wl_init_event_handler(cfg); - mutex_init(&cfg->usr_sync); - mutex_init(&cfg->event_sync); - err = wl_init_scan(cfg); - if (err) - return err; - wl_init_conf(cfg->conf); - wl_init_prof(cfg, ndev); - wl_link_down(cfg); - DNGL_FUNC(dhd_cfg80211_init, (cfg)); - - return err; -} - -static void wl_deinit_priv(struct bcm_cfg80211 *cfg) -{ - DNGL_FUNC(dhd_cfg80211_deinit, (cfg)); - wl_destroy_event_handler(cfg); - wl_flush_eq(cfg); - wl_link_down(cfg); - del_timer_sync(&cfg->scan_timeout); - wl_deinit_priv_mem(cfg); - if (wl_cfg80211_netdev_notifier_registered) { - wl_cfg80211_netdev_notifier_registered = FALSE; - unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); - } -} - - -#if defined(WL_ENABLE_P2P_IF) -static s32 wl_cfg80211_attach_p2p(void) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - WL_TRACE(("Enter \n")); - - if (wl_cfgp2p_register_ndev(cfg) < 0) { - WL_ERR(("P2P attach failed. \n")); - return -ENODEV; - } - - - return 0; -} -#endif - -#if defined(WL_ENABLE_P2P_IF) -static s32 wl_cfg80211_detach_p2p(void) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wireless_dev *wdev; - - WL_DBG(("Enter \n")); - if (!cfg) { - WL_ERR(("Invalid Ptr\n")); - return -EINVAL; - } else - wdev = cfg->p2p_wdev; - - if (!wdev) { - WL_ERR(("Invalid Ptr\n")); - return -EINVAL; - } - - wl_cfgp2p_unregister_ndev(cfg); - - cfg->p2p_wdev = NULL; - cfg->p2p_net = NULL; - WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev)); - kfree(wdev); - - return 0; -} -#endif - -s32 wl_cfg80211_attach_post(struct net_device *ndev) -{ - struct bcm_cfg80211 * cfg = NULL; - s32 err = 0; - s32 ret = 0; - WL_TRACE(("In\n")); - if (unlikely(!ndev)) { - WL_ERR(("ndev is invaild\n")); - return -ENODEV; - } - cfg = g_bcm_cfg; - if (unlikely(!cfg)) { - WL_ERR(("cfg is invaild\n")); - return -EINVAL; - } - if (!wl_get_drv_status(cfg, READY, ndev)) { - if (cfg->wdev) { - ret = wl_cfgp2p_supported(cfg, ndev); - if (ret > 0) { -#if !defined(WL_ENABLE_P2P_IF) - cfg->wdev->wiphy->interface_modes |= - (BIT(NL80211_IFTYPE_P2P_CLIENT)| - BIT(NL80211_IFTYPE_P2P_GO)); -#endif /* !WL_ENABLE_P2P_IF */ - if ((err = wl_cfgp2p_init_priv(cfg)) != 0) - goto fail; - -#if defined(WL_ENABLE_P2P_IF) - if (cfg->p2p_net) { - /* Update MAC addr for p2p0 interface here. */ - memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); - cfg->p2p_net->dev_addr[0] |= 0x02; - WL_ERR(("%s: p2p_dev_addr="MACDBG "\n", - cfg->p2p_net->name, - MAC2STRDBG(cfg->p2p_net->dev_addr))); - } else { - WL_ERR(("p2p_net not yet populated." - " Couldn't update the MAC Address for p2p0 \n")); - return -ENODEV; - } -#endif /* WL_ENABLE_P2P_IF */ - cfg->p2p_supported = true; - } else if (ret == 0) { - if ((err = wl_cfgp2p_init_priv(cfg)) != 0) - goto fail; - } else { - /* SDIO bus timeout */ - err = -ENODEV; - goto fail; - } - } - } - wl_set_drv_status(cfg, READY, ndev); -fail: - return err; -} - -s32 wl_cfg80211_attach(struct net_device *ndev, void *context) -{ - struct wireless_dev *wdev; - struct bcm_cfg80211 *cfg; - s32 err = 0; - struct device *dev; - - WL_TRACE(("In\n")); - if (!ndev) { - WL_ERR(("ndev is invaild\n")); - return -ENODEV; - } - WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev())); - dev = wl_cfg80211_get_parent_dev(); - - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (unlikely(!wdev)) { - WL_ERR(("Could not allocate wireless device\n")); - return -ENOMEM; - } - err = wl_setup_wiphy(wdev, dev, context); - if (unlikely(err)) { - kfree(wdev); - return -ENOMEM; - } - wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); - cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy); - cfg->wdev = wdev; - cfg->pub = context; - INIT_LIST_HEAD(&cfg->net_list); - ndev->ieee80211_ptr = wdev; - SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); - wdev->netdev = ndev; - cfg->state_notifier = wl_notifier_change_state; - err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE); - if (err) { - WL_ERR(("Failed to alloc net_info (%d)\n", err)); - goto cfg80211_attach_out; - } - err = wl_init_priv(cfg); - if (err) { - WL_ERR(("Failed to init iwm_priv (%d)\n", err)); - goto cfg80211_attach_out; - } - - err = wl_setup_rfkill(cfg, TRUE); - if (err) { - WL_ERR(("Failed to setup rfkill %d\n", err)); - goto cfg80211_attach_out; - } -#ifdef DEBUGFS_CFG80211 - err = wl_setup_debugfs(cfg); - if (err) { - WL_ERR(("Failed to setup debugfs %d\n", err)); - goto cfg80211_attach_out; - } -#endif - if (!wl_cfg80211_netdev_notifier_registered) { - wl_cfg80211_netdev_notifier_registered = TRUE; - err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); - if (err) { - wl_cfg80211_netdev_notifier_registered = FALSE; - WL_ERR(("Failed to register notifierl %d\n", err)); - goto cfg80211_attach_out; - } - } -#if defined(COEX_DHCP) - cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev); - if (!cfg->btcoex_info) - goto cfg80211_attach_out; -#endif - - g_bcm_cfg = cfg; - -#if defined(WL_ENABLE_P2P_IF) - err = wl_cfg80211_attach_p2p(); - if (err) - goto cfg80211_attach_out; -#endif - - return err; - -cfg80211_attach_out: - wl_setup_rfkill(cfg, FALSE); - wl_free_wdev(cfg); - return err; -} - -void wl_cfg80211_detach(void *para) -{ - struct bcm_cfg80211 *cfg; - - (void)para; - cfg = g_bcm_cfg; - - WL_TRACE(("In\n")); - - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - -#if defined(COEX_DHCP) - wl_cfg80211_btcoex_deinit(); - cfg->btcoex_info = NULL; -#endif - - wl_setup_rfkill(cfg, FALSE); -#ifdef DEBUGFS_CFG80211 - wl_free_debugfs(cfg); -#endif - if (cfg->p2p_supported) { - if (timer_pending(&cfg->p2p->listen_timer)) - del_timer_sync(&cfg->p2p->listen_timer); - wl_cfgp2p_deinit_priv(cfg); - } - - if (timer_pending(&cfg->scan_timeout)) - del_timer_sync(&cfg->scan_timeout); - -#if defined(WL_CFG80211_P2P_DEV_IF) - wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_ENABLE_P2P_IF) - wl_cfg80211_detach_p2p(); -#endif - - wl_cfg80211_ibss_vsie_free(cfg); - wl_deinit_priv(cfg); - g_bcm_cfg = NULL; - wl_cfg80211_clear_parent_dev(); - wl_free_wdev(cfg); - /* PLEASE do NOT call any function after wl_free_wdev, the driver's private - * structure "cfg", which is the private part of wiphy, has been freed in - * wl_free_wdev !!!!!!!!!!! - */ -} - -static void wl_wakeup_event(struct bcm_cfg80211 *cfg) -{ - if (cfg->event_tsk.thr_pid >= 0) { - up(&cfg->event_tsk.sema); - } -} - - -static s32 wl_event_handler(void *data) -{ - struct bcm_cfg80211 *cfg = NULL; - struct wl_event_q *e; - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - bcm_struct_cfgdev *cfgdev = NULL; - - cfg = (struct bcm_cfg80211 *)tsk->parent; - - WL_ERR(("tsk Enter, tsk = 0x%p\n", tsk)); - - while (down_interruptible (&tsk->sema) == 0) { - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - while ((e = wl_deq_event(cfg))) { - WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx)); - /* All P2P device address related events comes on primary interface since - * there is no corresponding bsscfg for P2P interface. Map it to p2p0 - * interface. - */ -#if defined(WL_CFG80211_P2P_DEV_IF) - if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_wdev)) { - cfgdev = bcmcfg_to_p2p_wdev(cfg); - } else { - struct net_device *ndev = NULL; - - ndev = dhd_idx2net((struct dhd_pub *)(cfg->pub), e->emsg.ifidx); - if (ndev) - cfgdev = ndev_to_wdev(ndev); - } -#elif defined(WL_ENABLE_P2P_IF) - if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_net)) { - cfgdev = cfg->p2p_net; - } else { - cfgdev = dhd_idx2net((struct dhd_pub *)(cfg->pub), - e->emsg.ifidx); - } -#endif /* WL_CFG80211_P2P_DEV_IF */ - - if (!cfgdev) { -#if defined(WL_CFG80211_P2P_DEV_IF) - cfgdev = bcmcfg_to_prmry_wdev(cfg); -#elif defined(WL_ENABLE_P2P_IF) - cfgdev = bcmcfg_to_prmry_ndev(cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ - } - if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) { - dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub); - if (dhd->busstate == DHD_BUS_DOWN) { - WL_ERR((": BUS is DOWN.\n")); - } else - cfg->evt_handler[e->etype](cfg, cfgdev, &e->emsg, e->edata); - } else { - WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); - } - wl_put_event(e); - DHD_EVENT_WAKE_UNLOCK(cfg->pub); - } - } - WL_ERR(("was terminated\n")); - complete_and_exit(&tsk->completed, 0); - return 0; -} - -void -wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) -{ - u32 event_type = ntoh32(e->event_type); - struct bcm_cfg80211 *cfg = g_bcm_cfg; - -#if (WL_DBG_LEVEL > 0) - s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? - wl_dbg_estr[event_type] : (s8 *) "Unknown"; - WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); -#endif /* (WL_DBG_LEVEL > 0) */ - if (cfg->event_tsk.thr_pid == -1) { - WL_ERR(("Event handler is not created\n")); - return; - } - - if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) { - WL_ERR(("during IF change, ignore event %d\n", event_type)); - return; - } - - if (ndev != bcmcfg_to_prmry_ndev(cfg) && cfg->p2p_supported) { - if ((cfg->bss_cfgdev) && - (ndev == cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg))) { - /* Event is corresponding to the secondary STA interface */ - WL_DBG(("DualSta event (%d), proceed to enqueue it \n", event_type)); - } else if (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) && -#if defined(WL_ENABLE_P2P_IF) - (ndev != (cfg->p2p_net ? cfg->p2p_net : - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE))) && -#else - (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE)) && -#endif /* WL_ENABLE_P2P_IF */ - TRUE) { - WL_ERR(("ignore event %d, not interested\n", event_type)); - return; - } - } - - if (event_type == WLC_E_PFN_NET_FOUND) { - WL_DBG((" PNOEVENT: PNO_NET_FOUND\n")); - } - else if (event_type == WLC_E_PFN_NET_LOST) { - WL_DBG((" PNOEVENT: PNO_NET_LOST\n")); - } - - DHD_EVENT_WAKE_LOCK(cfg->pub); - if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) { - wl_wakeup_event(cfg); - } else { - DHD_EVENT_WAKE_UNLOCK(cfg->pub); - } -} - -static void wl_init_eq(struct bcm_cfg80211 *cfg) -{ - wl_init_eq_lock(cfg); - INIT_LIST_HEAD(&cfg->eq_list); -} - -static void wl_flush_eq(struct bcm_cfg80211 *cfg) -{ - struct wl_event_q *e; - unsigned long flags; - - flags = wl_lock_eq(cfg); - while (!list_empty(&cfg->eq_list)) { - e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list); - list_del(&e->eq_list); - kfree(e); - } - wl_unlock_eq(cfg, flags); -} - -/* -* retrieve first queued event from head -*/ - -static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg) -{ - struct wl_event_q *e = NULL; - unsigned long flags; - - flags = wl_lock_eq(cfg); - if (likely(!list_empty(&cfg->eq_list))) { - e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list); - list_del(&e->eq_list); - } - wl_unlock_eq(cfg, flags); - - return e; -} - -/* - * push event to tail of the queue - */ - -static s32 -wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event, - const wl_event_msg_t *msg, void *data) -{ - struct wl_event_q *e; - s32 err = 0; - uint32 evtq_size; - uint32 data_len; - unsigned long flags; - gfp_t aflags; - - data_len = 0; - if (data) - data_len = ntoh32(msg->datalen); - evtq_size = sizeof(struct wl_event_q) + data_len; - aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; - e = kzalloc(evtq_size, aflags); - if (unlikely(!e)) { - WL_ERR(("event alloc failed\n")); - return -ENOMEM; - } - e->etype = event; - memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); - if (data) - memcpy(e->edata, data, data_len); - flags = wl_lock_eq(cfg); - list_add_tail(&e->eq_list, &cfg->eq_list); - wl_unlock_eq(cfg, flags); - - return err; -} - -static void wl_put_event(struct wl_event_q *e) -{ - kfree(e); -} - -static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype) -{ - s32 infra = 0; - s32 err = 0; - s32 mode = 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: - mode = WL_MODE_IBSS; - break; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - mode = WL_MODE_BSS; - infra = 1; - break; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - mode = WL_MODE_AP; - infra = 1; - break; - default: - err = -EINVAL; - WL_ERR(("invalid type (%d)\n", iftype)); - return err; - } - infra = htod32(infra); - err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true); - if (unlikely(err)) { - WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); - return err; - } - - wl_set_mode_by_netdev(cfg, ndev, mode); - - return 0; -} - -void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set) -{ - if (!ev || (event > WLC_E_LAST)) - return; - - if (ev->num < MAX_EVENT_BUF_NUM) { - ev->event[ev->num].type = event; - ev->event[ev->num].set = set; - ev->num++; - } else { - WL_ERR(("evenbuffer doesn't support > %u events. Update" - " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM)); - ASSERT(0); - } -} - -s32 wl_cfg80211_apply_eventbuffer( - struct net_device *ndev, - struct bcm_cfg80211 *cfg, - wl_eventmsg_buf_t *ev) -{ - char eventmask[WL_EVENTING_MASK_LEN]; - int i, ret = 0; - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - if (!ev || (!ev->num)) - return -EINVAL; - - mutex_lock(&cfg->event_sync); - - /* Read event_msgs mask */ - bcm_mkiovar("event_msgs", NULL, 0, iovbuf, - sizeof(iovbuf)); - ret = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); - if (unlikely(ret)) { - WL_ERR(("Get event_msgs error (%d)\n", ret)); - goto exit; - } - memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); - - /* apply the set bits */ - for (i = 0; i < ev->num; i++) { - if (ev->event[i].set) - setbit(eventmask, ev->event[i].type); - else - clrbit(eventmask, ev->event[i].type); - } - - /* Write updated Event mask */ - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, - sizeof(iovbuf)); - ret = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(ret)) { - WL_ERR(("Set event_msgs error (%d)\n", ret)); - } - -exit: - mutex_unlock(&cfg->event_sync); - return ret; -} - -s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) -{ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - s8 eventmask[WL_EVENTING_MASK_LEN]; - s32 err = 0; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - if (!ndev || !cfg) - return -ENODEV; - - mutex_lock(&cfg->event_sync); - - /* Setup event_msgs */ - bcm_mkiovar("event_msgs", NULL, 0, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); - if (unlikely(err)) { - WL_ERR(("Get event_msgs error (%d)\n", err)); - goto eventmsg_out; - } - memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); - if (add) { - setbit(eventmask, event); - } else { - clrbit(eventmask, event); - } - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("Set event_msgs error (%d)\n", err)); - goto eventmsg_out; - } - -eventmsg_out: - mutex_unlock(&cfg->event_sync); - return err; -} - -static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) -{ - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - struct ieee80211_channel *band_chan_arr = NULL; - wl_uint32_list_t *list; - u32 i, j, index, n_2g, n_5g, band, channel, array_size; - u32 *n_cnt = NULL; - chanspec_t c = 0; - s32 err = BCME_OK; - bool update; - bool ht40_allowed; - u8 *pbuf = NULL; - bool dfs_radar_disabled = FALSE; - -#define LOCAL_BUF_LEN 1024 - pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); - - if (pbuf == NULL) { - WL_ERR(("failed to allocate local buf\n")); - return -ENOMEM; - } - list = (wl_uint32_list_t *)(void *)pbuf; - list->count = htod32(WL_NUMCHANSPECS); - - - err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, - 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync); - if (err != 0) { - WL_ERR(("get chanspecs failed with %d\n", err)); - kfree(pbuf); - return err; - } -#undef LOCAL_BUF_LEN - - list = (wl_uint32_list_t *)(void *)pbuf; - - if ((list) && (dtoh32(list->count) > htod32(WL_NUMCHANSPECS))) { - WL_ERR(("Invalid channel list : %d\n", dtoh32(list->count))); - kfree(pbuf); - return INVCHANSPEC; - } - - band = array_size = n_2g = n_5g = 0; - for (i = 0; i < dtoh32(list->count); i++) { - index = 0; - update = false; - ht40_allowed = false; - c = (chanspec_t)dtoh32(list->element[i]); - c = wl_chspec_driver_to_host(c); - channel = wf_chspec_ctlchan(c); - - if (!CHSPEC_IS40(c) && ! CHSPEC_IS20(c)) { - WL_DBG(("HT80/160/80p80 center channel : %d\n", channel)); - continue; - } - if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) && - (channel <= CH_MAX_2G_CHANNEL)) { - band_chan_arr = __wl_2ghz_channels; - array_size = ARRAYSIZE(__wl_2ghz_channels); - n_cnt = &n_2g; - band = IEEE80211_BAND_2GHZ; - ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; - } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) { - band_chan_arr = __wl_5ghz_a_channels; - array_size = ARRAYSIZE(__wl_5ghz_a_channels); - n_cnt = &n_5g; - band = IEEE80211_BAND_5GHZ; - ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; - } else { - WL_ERR(("Invalid channel Sepc. 0x%x.\n", c)); - continue; - } - if (!ht40_allowed && CHSPEC_IS40(c)) - continue; - for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { - if (band_chan_arr[j].hw_value == channel) { - update = true; - break; - } - } - if (update) - index = j; - else - index = *n_cnt; - if (index < array_size) { -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) - band_chan_arr[index].center_freq = - ieee80211_channel_to_frequency(channel); -#else - band_chan_arr[index].center_freq = - ieee80211_channel_to_frequency(channel, band); -#endif - band_chan_arr[index].hw_value = channel; - band_chan_arr[index].beacon_found = false; - - if (CHSPEC_IS40(c) && ht40_allowed) { - /* assuming the order is HT20, HT40 Upper, - * HT40 lower from chanspecs - */ - u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; - if (CHSPEC_SB_UPPER(c)) { - if (ht40_flag == IEEE80211_CHAN_NO_HT40) - band_chan_arr[index].flags &= - ~IEEE80211_CHAN_NO_HT40; - band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; - } else { - /* It should be one of - * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS - */ - band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; - if (ht40_flag == IEEE80211_CHAN_NO_HT40) - band_chan_arr[index].flags |= - IEEE80211_CHAN_NO_HT40MINUS; - } - } else { - band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; - if (!dfs_radar_disabled) { - if (band == IEEE80211_BAND_2GHZ) - channel |= WL_CHANSPEC_BAND_2G; - else - channel |= WL_CHANSPEC_BAND_5G; - channel |= WL_CHANSPEC_BW_20; - channel = wl_chspec_host_to_driver(channel); - err = wldev_iovar_getint(dev, "per_chan_info", &channel); - if (!err) { - if (channel & WL_CHAN_RADAR) { -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) - band_chan_arr[index].flags |= - (IEEE80211_CHAN_RADAR - | IEEE80211_CHAN_NO_IBSS); -#else - band_chan_arr[index].flags |= - IEEE80211_CHAN_RADAR; -#endif - } - - if (channel & WL_CHAN_PASSIVE) -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) - band_chan_arr[index].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; -#else - band_chan_arr[index].flags |= - IEEE80211_CHAN_NO_IR; -#endif - } else if (err == BCME_UNSUPPORTED) { - dfs_radar_disabled = TRUE; - WL_ERR(("does not support per_chan_info\n")); - } - } - } - if (!update) - (*n_cnt)++; - } - - } - __wl_band_2ghz.n_channels = n_2g; - __wl_band_5ghz_a.n_channels = n_5g; - kfree(pbuf); - return err; -} - -s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) -{ - struct wiphy *wiphy; - struct net_device *dev; - u32 bandlist[3]; - u32 nband = 0; - u32 i = 0; - s32 err = 0; - s32 index = 0; - s32 nmode = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - u32 j = 0; - s32 vhtmode = 0; - s32 txstreams = 0; - s32 rxstreams = 0; - s32 ldpc_cap = 0; - s32 stbc_rx = 0; - s32 stbc_tx = 0; - s32 txbf_bfe_cap = 0; - s32 txbf_bfr_cap = 0; -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - bool rollback_lock = false; - s32 bw_cap = 0; - s32 cur_band = -1; - struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, }; - - if (cfg == NULL) { - cfg = g_bcm_cfg; - mutex_lock(&cfg->usr_sync); - rollback_lock = true; - } - dev = bcmcfg_to_prmry_ndev(cfg); - - memset(bandlist, 0, sizeof(bandlist)); - err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist, - sizeof(bandlist), false); - if (unlikely(err)) { - WL_ERR(("error read bandlist (%d)\n", err)); - goto end_bands; - } - err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band, - sizeof(s32), false); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - goto end_bands; - } - - err = wldev_iovar_getint(dev, "nmode", &nmode); - if (unlikely(err)) { - WL_ERR(("error reading nmode (%d)\n", err)); - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - err = wldev_iovar_getint(dev, "vhtmode", &vhtmode); - if (unlikely(err)) { - WL_ERR(("error reading vhtmode (%d)\n", err)); - } - - if (vhtmode) { - err = wldev_iovar_getint(dev, "txstreams", &txstreams); - if (unlikely(err)) { - WL_ERR(("error reading txstreams (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "rxstreams", &rxstreams); - if (unlikely(err)) { - WL_ERR(("error reading rxstreams (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap); - if (unlikely(err)) { - WL_ERR(("error reading ldpc_cap (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx); - if (unlikely(err)) { - WL_ERR(("error reading stbc_rx (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx); - if (unlikely(err)) { - WL_ERR(("error reading stbc_tx (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap); - if (unlikely(err)) { - WL_ERR(("error reading txbf_bfe_cap (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap); - if (unlikely(err)) { - WL_ERR(("error reading txbf_bfr_cap (%d)\n", err)); - } - } -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - - /* For nmode and vhtmode check bw cap */ - if (nmode || -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - vhtmode || -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - 0) { - err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); - if (unlikely(err)) { - WL_ERR(("error get mimo_bw_cap (%d)\n", err)); - } - } - - err = wl_construct_reginfo(cfg, bw_cap); - if (err) { - WL_ERR(("wl_construct_reginfo() fails err=%d\n", err)); - if (err != BCME_UNSUPPORTED) - goto end_bands; - err = 0; - } - wiphy = bcmcfg_to_wiphy(cfg); - nband = bandlist[0]; - - for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { - index = -1; - if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) { - bands[IEEE80211_BAND_5GHZ] = - &__wl_band_5ghz_a; - index = IEEE80211_BAND_5GHZ; - if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G)) - bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - /* VHT capabilities. */ - if (vhtmode) { - /* Supported */ - bands[index]->vht_cap.vht_supported = TRUE; - - for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) { - /* TX stream rates. */ - if (j <= txstreams) { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, - bands[index]->vht_cap.vht_mcs.tx_mcs_map); - } else { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, - bands[index]->vht_cap.vht_mcs.tx_mcs_map); - } - - /* RX stream rates. */ - if (j <= rxstreams) { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, - bands[index]->vht_cap.vht_mcs.rx_mcs_map); - } else { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, - bands[index]->vht_cap.vht_mcs.rx_mcs_map); - } - } - - - /* Capabilities */ - /* 80 MHz is mandatory */ - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SHORT_GI_80; - - if (WL_BW_CAP_160MHZ(bw_cap)) { - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SHORT_GI_160; - } - - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; - - if (ldpc_cap) - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_RXLDPC; - - if (stbc_tx) - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_TXSTBC; - - if (stbc_rx) - bands[index]->vht_cap.cap |= - (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT); - - if (txbf_bfe_cap) - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; - - if (txbf_bfr_cap) { - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; - } - - if (txbf_bfe_cap || txbf_bfr_cap) { - bands[index]->vht_cap.cap |= - (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT); - bands[index]->vht_cap.cap |= - ((txstreams - 1) << - VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT); - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; - } - - /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */ - bands[index]->vht_cap.cap |= - (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT); - WL_INFORM(("%s band[%d] vht_enab=%d vht_cap=%08x " - "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n", - __FUNCTION__, index, - bands[index]->vht_cap.vht_supported, - bands[index]->vht_cap.cap, - bands[index]->vht_cap.vht_mcs.rx_mcs_map, - bands[index]->vht_cap.vht_mcs.tx_mcs_map)); - } -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - } - else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { - bands[IEEE80211_BAND_2GHZ] = - &__wl_band_2ghz; - index = IEEE80211_BAND_2GHZ; - if (bw_cap == WLC_N_BW_40ALL) - bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; - } - - if ((index >= 0) && nmode) { - bands[index]->ht_cap.cap |= - (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); - bands[index]->ht_cap.ht_supported = TRUE; - bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; - /* An HT shall support all EQM rates for one spatial stream */ - bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; - } - - } - - wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; - wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; - - /* check if any bands populated otherwise makes 2Ghz as default */ - if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL && - wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) { - /* Setup 2Ghz band as default */ - wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - } - - if (notify) - wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); - - end_bands: - if (rollback_lock) - mutex_unlock(&cfg->usr_sync); - return err; -} - -static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) -{ - s32 err = 0; -#ifdef WL_HOST_BAND_MGMT - s32 ret = 0; -#endif /* WL_HOST_BAND_MGMT */ - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - struct wireless_dev *wdev = ndev->ieee80211_ptr; - - WL_DBG(("In\n")); - - err = dhd_config_dongle(cfg); - if (unlikely(err)) - return err; - - err = wl_config_ifmode(cfg, ndev, wdev->iftype); - if (unlikely(err && err != -EINPROGRESS)) { - WL_ERR(("wl_config_ifmode failed\n")); - if (err == -1) { - WL_ERR(("return error %d\n", err)); - return err; - } - } - err = wl_update_wiphybands(cfg, true); - if (unlikely(err)) { - WL_ERR(("wl_update_wiphybands failed\n")); - if (err == -1) { - WL_ERR(("return error %d\n", err)); - return err; - } - } - - err = dhd_monitor_init(cfg->pub); - -#ifdef WL_HOST_BAND_MGMT - /* By default the curr_band is initialized to BAND_AUTO */ - if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) { - if (ret == BCME_UNSUPPORTED) { - /* Don't fail the initialization, lets just - * fall back to the original method - */ - WL_ERR(("WL_HOST_BAND_MGMT defined, " - "but roam_band iovar not supported \n")); - } else { - WL_ERR(("roam_band failed. ret=%d", ret)); - err = -1; - } - } -#endif /* WL_HOST_BAND_MGMT */ - INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler); - wl_set_drv_status(cfg, READY, ndev); - return err; -} - -static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) -{ - s32 err = 0; - unsigned long flags; - struct net_info *iter, *next; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); -#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF) - struct net_device *p2p_net = cfg->p2p_net; -#endif - u32 bssidx = 0; -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif -#endif /* PROP_TXSTATUS_VSDB */ - WL_DBG(("In\n")); - /* Delete pm_enable_work */ - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - - - if (cfg->p2p_supported) { - wl_clr_p2p_status(cfg, GO_NEG_PHASE); -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - if (cfg->p2p->vif_created) { - bool enabled = false; - dhd_wlfc_get_enable(dhd, &enabled); - if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) { - dhd_wlfc_deinit(dhd); - cfg->wlfc_on = false; - } - } -#endif -#endif /* PROP_TXSTATUS_VSDB */ - } - - - /* If primary BSS is operational (for e.g SoftAP), bring it down */ - if (!(wl_cfgp2p_find_idx(cfg, ndev, &bssidx)) && - wl_cfgp2p_bss_isup(ndev, bssidx)) { - if (wl_cfgp2p_bss(cfg, ndev, bssidx, 0) < 0) - WL_ERR(("BSS down failed \n")); - } - - /* Check if cfg80211 interface is already down */ - if (!wl_get_drv_status(cfg, READY, ndev)) - return err; /* it is even not ready */ - for_each_ndev(cfg, iter, next) - wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); - - - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - if (cfg->scan_request) { - cfg80211_scan_done(cfg->scan_request, true); - cfg->scan_request = NULL; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - for_each_ndev(cfg, iter, next) { - wl_clr_drv_status(cfg, READY, iter->ndev); - wl_clr_drv_status(cfg, SCANNING, iter->ndev); - wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev); - wl_clr_drv_status(cfg, CONNECTING, iter->ndev); - wl_clr_drv_status(cfg, CONNECTED, iter->ndev); - wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev); - wl_clr_drv_status(cfg, AP_CREATED, iter->ndev); - wl_clr_drv_status(cfg, AP_CREATING, iter->ndev); - } - bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype = - NL80211_IFTYPE_STATION; -#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF) - if (p2p_net) - dev_close(p2p_net); -#endif - wl_flush_eq(cfg); - wl_link_down(cfg); - if (cfg->p2p_supported) - wl_cfgp2p_down(cfg); - if (cfg->ap_info) { - kfree(cfg->ap_info->wpa_ie); - kfree(cfg->ap_info->rsn_ie); - kfree(cfg->ap_info->wps_ie); - kfree(cfg->ap_info); - cfg->ap_info = NULL; - } - dhd_monitor_uninit(); -#ifdef WLAIBSS_MCHAN - bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev); -#endif /* WLAIBSS_MCHAN */ - -#if defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) - /* Clean up if not removed already */ - if (cfg->bss_cfgdev) - wl_cfg80211_del_iface(cfg->wdev->wiphy, cfg->bss_cfgdev); -#endif /* defined (DUAL_STA) || defined (DUAL_STA_STATIC_IF) */ - - DNGL_FUNC(dhd_cfg80211_down, (cfg)); - - return err; -} - -s32 wl_cfg80211_up(void *para) -{ - struct bcm_cfg80211 *cfg; - s32 err = 0; - int val = 1; - dhd_pub_t *dhd; - - (void)para; - WL_DBG(("In\n")); - cfg = g_bcm_cfg; - - if ((err = wldev_ioctl(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val, - sizeof(int), false) < 0)) { - WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err)); - return err; - } - val = dtoh32(val); - if (val != WLC_IOCTL_VERSION && val != 1) { - WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n", - val, WLC_IOCTL_VERSION)); - return BCME_VERSION; - } - ioctl_version = val; - WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version)); - - mutex_lock(&cfg->usr_sync); - dhd = (dhd_pub_t *)(cfg->pub); - if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { - err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg)); - if (unlikely(err)) - return err; - } - err = __wl_cfg80211_up(cfg); - if (unlikely(err)) - WL_ERR(("__wl_cfg80211_up failed\n")); - mutex_unlock(&cfg->usr_sync); - -#ifdef WLAIBSS_MCHAN - bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME); -#endif /* WLAIBSS_MCHAN */ - -#ifdef DUAL_STA_STATIC_IF -#ifdef DUAL_STA -#error "Both DUAL_STA and DUAL_STA_STATIC_IF can't be enabled together" -#endif - /* Static Interface support is currently supported only for STA only builds (without P2P) */ - wl_cfg80211_create_iface(cfg->wdev->wiphy, NL80211_IFTYPE_STATION, NULL, "wlan%d"); -#endif /* DUAL_STA_STATIC_IF */ - - return err; -} - -/* Private Event to Supplicant with indication that chip hangs */ -int wl_cfg80211_hang(struct net_device *dev, u16 reason) -{ - struct bcm_cfg80211 *cfg; - cfg = g_bcm_cfg; - - WL_ERR(("In : chip crash eventing\n")); - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL); - if (cfg != NULL) { - wl_link_down(cfg); - } - return 0; -} - -s32 wl_cfg80211_down(void *para) -{ - struct bcm_cfg80211 *cfg; - s32 err = 0; - - (void)para; - WL_DBG(("In\n")); - cfg = g_bcm_cfg; - mutex_lock(&cfg->usr_sync); - err = __wl_cfg80211_down(cfg); - mutex_unlock(&cfg->usr_sync); - - return err; -} - -static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item) -{ - unsigned long flags; - void *rptr = NULL; - struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); - - if (!profile) - return NULL; - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - switch (item) { - case WL_PROF_SEC: - rptr = &profile->sec; - break; - case WL_PROF_ACT: - rptr = &profile->active; - break; - case WL_PROF_BSSID: - rptr = profile->bssid; - break; - case WL_PROF_SSID: - rptr = &profile->ssid; - break; - case WL_PROF_CHAN: - rptr = &profile->channel; - break; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - if (!rptr) - WL_ERR(("invalid item (%d)\n", item)); - return rptr; -} - -static s32 -wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data, s32 item) -{ - s32 err = 0; - struct wlc_ssid *ssid; - unsigned long flags; - struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); - - if (!profile) - return WL_INVALID; - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - switch (item) { - case WL_PROF_SSID: - ssid = (wlc_ssid_t *) data; - memset(profile->ssid.SSID, 0, - sizeof(profile->ssid.SSID)); - profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN); - memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len); - break; - case WL_PROF_BSSID: - if (data) - memcpy(profile->bssid, data, ETHER_ADDR_LEN); - else - memset(profile->bssid, 0, ETHER_ADDR_LEN); - break; - case WL_PROF_SEC: - memcpy(&profile->sec, data, sizeof(profile->sec)); - break; - case WL_PROF_ACT: - profile->active = *(bool *)data; - break; - case WL_PROF_BEACONINT: - profile->beacon_interval = *(u16 *)data; - break; - case WL_PROF_DTIMPERIOD: - profile->dtim_period = *(u8 *)data; - break; - case WL_PROF_CHAN: - profile->channel = *(u32*)data; - break; - default: - err = -EOPNOTSUPP; - break; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - if (err == -EOPNOTSUPP) - WL_ERR(("unsupported item (%d)\n", item)); - - return err; -} - -void wl_cfg80211_dbg_level(u32 level) -{ - /* - * prohibit to change debug level - * by insmod parameter. - * eventually debug level will be configured - * in compile time by using CONFIG_XXX - */ - /* wl_dbg_level = level; */ -} - -static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS; -} - -static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg) -{ - return cfg->ibss_starter; -} - -static void wl_rst_ie(struct bcm_cfg80211 *cfg) -{ - struct wl_ie *ie = wl_to_ie(cfg); - - ie->offset = 0; -} - -static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v) -{ - struct wl_ie *ie = wl_to_ie(cfg); - s32 err = 0; - - if (unlikely(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; -} - -static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam) -{ - u8 *ssidie; - int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); - int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len; - ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); - /* ERROR out if - * 1. No ssid IE is FOUND or - * 2. New ssid length is > what was allocated for existing ssid (as - * we do not want to overwrite the rest of the IEs) or - * 3. If in case of erroneous buffer input where ssid length doesnt match the space - * allocated to it. - */ - if (!ssidie) { - return; - } - available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream); - remaining_ie_buf_len = available_buffer_len - (int)ssidie[1]; - unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size); - if (ssidie[1] > available_buffer_len) { - WL_ERR(("%s: skip wl_update_hidden_ap_ie : overflow\n", __FUNCTION__)); - return; - } - - if (ssidie[1] != ssid_len) { - if (ssidie[1]) { - WL_INFORM(("%s: Wrong SSID len: %d != %d\n", - __FUNCTION__, ssidie[1], bi->SSID_len)); - } - if ((roam && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) { - WL_INFORM(("Changing the SSID Info.\n")); - memmove(ssidie + ssid_len + 2, - (ssidie + 2) + ssidie[1], - remaining_ie_buf_len); - memcpy(ssidie + 2, bi->SSID, ssid_len); - *ie_size = *ie_size + ssid_len - ssidie[1]; - ssidie[1] = ssid_len; - } else if (ssid_len < ssidie[1]) { - WL_ERR(("%s: Invalid SSID len: %d < %d\n", - __FUNCTION__, ssidie[1], bi->SSID_len)); - } - return; - } - if (*(ssidie + 2) == '\0') - memcpy(ssidie + 2, bi->SSID, ssid_len); - return; -} - -static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size) -{ - struct wl_ie *ie = wl_to_ie(cfg); - s32 err = 0; - - if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { - WL_ERR(("ei_stream crosses buffer boundary\n")); - return -ENOSPC; - } - memcpy(&ie->buf[ie->offset], ie_stream, ie_size); - ie->offset += ie_size; - - return err; -} - -static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size) -{ - struct wl_ie *ie = wl_to_ie(cfg); - s32 err = 0; - - if (unlikely(ie->offset > dst_size)) { - WL_ERR(("dst_size is not enough\n")); - return -ENOSPC; - } - memcpy(dst, &ie->buf[0], ie->offset); - - return err; -} - -static u32 wl_get_ielen(struct bcm_cfg80211 *cfg) -{ - struct wl_ie *ie = wl_to_ie(cfg); - - return ie->offset; -} - -static void wl_link_up(struct bcm_cfg80211 *cfg) -{ - cfg->link_up = true; -} - -static void wl_link_down(struct bcm_cfg80211 *cfg) -{ - struct wl_connect_info *conn_info = wl_to_conn(cfg); - - WL_DBG(("In\n")); - cfg->link_up = false; - conn_info->req_ie_len = 0; - conn_info->resp_ie_len = 0; -} - -static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg) -{ - unsigned long flags; - - spin_lock_irqsave(&cfg->eq_lock, flags); - return flags; -} - -static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags) -{ - spin_unlock_irqrestore(&cfg->eq_lock, flags); -} - -static void wl_init_eq_lock(struct bcm_cfg80211 *cfg) -{ - spin_lock_init(&cfg->eq_lock); -} - -static void wl_delay(u32 ms) -{ - if (in_atomic() || (ms < jiffies_to_msecs(1))) { - OSL_DELAY(ms*1000); - } else { - OSL_SLEEP(ms); - } -} - -s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct ether_addr p2pif_addr; - struct ether_addr primary_mac; - if (!cfg->p2p) - return -1; - if (!p2p_is_on(cfg)) { - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); - } else { - memcpy(p2pdev_addr->octet, - cfg->p2p->dev_addr.octet, ETHER_ADDR_LEN); - } - - - return 0; -} -s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) -{ - struct bcm_cfg80211 *cfg; - - cfg = g_bcm_cfg; - - return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len); -} - -s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) -{ - struct bcm_cfg80211 *cfg; - cfg = g_bcm_cfg; - - return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len); -} - -s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) -{ - struct bcm_cfg80211 *cfg; - cfg = g_bcm_cfg; - - return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len); -} - -s32 wl_cfg80211_channel_to_freq(u32 channel) -{ - int freq = 0; - -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) - freq = ieee80211_channel_to_frequency(channel); -#else - { - u16 band = 0; - if (channel <= CH_MAX_2G_CHANNEL) - band = IEEE80211_BAND_2GHZ; - else - band = IEEE80211_BAND_5GHZ; - freq = ieee80211_channel_to_frequency(channel, band); - } -#endif - return freq; -} - - -#ifdef WLTDLS -static s32 -wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) { - - struct net_device *ndev = NULL; - u32 reason = ntoh32(e->reason); - s8 *msg = NULL; - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - switch (reason) { - case WLC_E_TDLS_PEER_DISCOVERED : - msg = " TDLS PEER DISCOVERD "; - break; - case WLC_E_TDLS_PEER_CONNECTED : -#ifdef PCIE_FULL_DONGLE - dhd_tdls_update_peer_info(ndev, TRUE, (uint8 *)&e->addr.octet[0]); -#endif /* PCIE_FULL_DONGLE */ - if (cfg->tdls_mgmt_frame) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) - cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0, - cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, - 0, GFP_ATOMIC); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) - cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0, - cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, - GFP_ATOMIC); -#else - cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, - cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, - GFP_ATOMIC); -#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ - } - msg = " TDLS PEER CONNECTED "; - break; - case WLC_E_TDLS_PEER_DISCONNECTED : -#ifdef PCIE_FULL_DONGLE - dhd_tdls_update_peer_info(ndev, FALSE, (uint8 *)&e->addr.octet[0]); -#endif /* PCIE_FULL_DONGLE */ - if (cfg->tdls_mgmt_frame) { - kfree(cfg->tdls_mgmt_frame); - cfg->tdls_mgmt_frame = NULL; - cfg->tdls_mgmt_freq = 0; - } - msg = "TDLS PEER DISCONNECTED "; - break; - } - if (msg) { - WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((u8*)(&e->addr)), - (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary")); - } - return 0; - -} -#endif /* WLTDLS */ - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) -static s32 -#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) -wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, - u32 peer_capability, const u8 *data, size_t len) -#else -wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data, - size_t len) -#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ -{ - s32 ret = 0; -#ifdef WLTDLS - struct bcm_cfg80211 *cfg; - tdls_wfd_ie_iovar_t info; - memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t)); - cfg = g_bcm_cfg; - -#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) - /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10 - * and that cuases build error - */ - BCM_REFERENCE(peer_capability); -#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ - - switch (action_code) { - /* We need to set TDLS Wifi Display IE to firmware - * using tdls_wfd_ie iovar - */ - case WLAN_TDLS_SET_PROBE_WFD_IE: - info.mode = TDLS_WFD_PROBE_IE_TX; - memcpy(&info.data, data, len); - info.length = len; - break; - case WLAN_TDLS_SET_SETUP_WFD_IE: - info.mode = TDLS_WFD_IE_TX; - memcpy(&info.data, data, len); - info.length = len; - break; - default: - WL_ERR(("Unsupported action code : %d\n", action_code)); - goto out; - } - - ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (ret) { - WL_ERR(("tdls_wfd_ie error %d\n", ret)); - } -out: -#endif /* WLTDLS */ - return ret; -} - -static s32 -wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, enum nl80211_tdls_operation oper) -{ - s32 ret = 0; -#ifdef WLTDLS - struct bcm_cfg80211 *cfg; - tdls_iovar_t info; - cfg = g_bcm_cfg; - memset(&info, 0, sizeof(tdls_iovar_t)); - if (peer) { - memcpy(&info.ea, peer, ETHER_ADDR_LEN); - } else { - return -1; - } - switch (oper) { - case NL80211_TDLS_DISCOVERY_REQ: - /* turn on TDLS */ - ret = dhd_tdls_enable(dev, true, false, NULL); - if (ret < 0) - return ret; - /* If the discovery request is broadcast then we need to set - * info.mode to Tunneled Probe Request - */ - if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) { - info.mode = TDLS_MANUAL_EP_WFD_TPQ; - } - else { - info.mode = TDLS_MANUAL_EP_DISCOVERY; - } - break; - case NL80211_TDLS_SETUP: - /* auto mode on */ - ret = dhd_tdls_enable(dev, true, true, (struct ether_addr *)peer); - if (ret < 0) - return ret; - break; - case NL80211_TDLS_TEARDOWN: - info.mode = TDLS_MANUAL_EP_DELETE; - /* auto mode off */ - ret = dhd_tdls_enable(dev, true, false, (struct ether_addr *)peer); - if (ret < 0) - return ret; - break; - default: - WL_ERR(("Unsupported operation : %d\n", oper)); - goto out; - } - if (info.mode) { - ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (ret) { - WL_ERR(("tdls_endpoint error %d\n", ret)); - } - } -out: -#endif /* WLTDLS */ - return ret; -} -#endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */ - -s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, - enum wl_management_type type) -{ - struct bcm_cfg80211 *cfg; - struct net_device *ndev = NULL; - struct ether_addr primary_mac; - s32 ret = 0; - s32 bssidx = 0; - s32 pktflag = 0; - cfg = g_bcm_cfg; - - if (wl_get_drv_status(cfg, AP_CREATING, net)) { - /* Vendor IEs should be set to FW - * after SoftAP interface is brought up - */ - goto exit; - } else if (wl_get_drv_status(cfg, AP_CREATED, net)) { - ndev = net; - bssidx = 0; - } else if (cfg->p2p) { - net = ndev_to_wlc_ndev(net, cfg); - if (!cfg->p2p->on) { - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr, - &cfg->p2p->int_addr); - /* In case of p2p_listen command, supplicant send remain_on_channel - * without turning on P2P - */ - - p2p_on(cfg) = true; - ret = wl_cfgp2p_enable_discovery(cfg, net, NULL, 0); - - if (unlikely(ret)) { - goto exit; - } - } - if (net != bcmcfg_to_prmry_ndev(cfg)) { - if (wl_get_mode_by_netdev(cfg, net) == WL_MODE_AP) { - ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION); - } - } else { - ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - } - } - if (ndev != NULL) { - switch (type) { - case WL_BEACON: - pktflag = VNDR_IE_BEACON_FLAG; - break; - case WL_PROBE_RESP: - pktflag = VNDR_IE_PRBRSP_FLAG; - break; - case WL_ASSOC_RESP: - pktflag = VNDR_IE_ASSOCRSP_FLAG; - break; - } - if (pktflag) - ret = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, pktflag, buf, len); - } -exit: - return ret; -} - -#ifdef WL_SUPPORT_AUTO_CHANNEL -static s32 -wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev) -{ - u32 val = 0; - s32 ret = BCME_ERROR; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - /* Disable mpc, to avoid automatic interface down. */ - val = 0; - - ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, - sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, - &cfg->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("set 'mpc' failed, error = %d\n", ret)); - goto done; - } - - /* Set interface up, explicitly. */ - val = 1; - - ret = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true); - if (ret < 0) { - WL_ERR(("set interface up failed, error = %d\n", ret)); - goto done; - } - - /* Stop all scan explicitly, till auto channel selection complete. */ - wl_set_drv_status(cfg, SCANNING, ndev); - if (cfg->escan_info.ndev == NULL) { - ret = BCME_OK; - goto done; - } - ret = wl_notify_escan_complete(cfg, ndev, true, true); - if (ret < 0) { - WL_ERR(("set scan abort failed, error = %d\n", ret)); - goto done; - } - -done: - return ret; -} - -static bool -wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec) -{ - bool valid = false; - char chanbuf[CHANSPEC_STR_LEN]; - - if (ioctl_version != 1) { - if ((chanspec = wl_chspec_to_legacy(chanspec)) == INVCHANSPEC) { - return valid; - } - } - - /* channel 1 to 14 */ - if ((chanspec >= 0x2b01) && (chanspec <= 0x2b0e)) { - valid = true; - } - /* channel 36 to 48 */ - else if ((chanspec >= 0x1b24) && (chanspec <= 0x1b30)) { - valid = true; - } - /* channel 149 to 161 */ - else if ((chanspec >= 0x1b95) && (chanspec <= 0x1ba1)) { - valid = true; - } - else { - valid = false; - WL_INFORM(("invalid P2P chanspec, chanspec = %s\n", - wf_chspec_ntoa_ex(chanspec, chanbuf))); - } - - return valid; -} - -static s32 -wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen) -{ - s32 ret = BCME_ERROR; - struct bcm_cfg80211 *cfg = NULL; - wl_uint32_list_t *list = NULL; - chanspec_t chanspec = 0; - - memset(buf, 0, buflen); - - cfg = g_bcm_cfg; - list = (wl_uint32_list_t *)buf; - list->count = htod32(WL_NUMCHANSPECS); - - /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */ - chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 | - WL_CHANSPEC_CTL_SB_NONE); - chanspec = wl_chspec_host_to_driver(chanspec); - - ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, - sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); - } - - return ret; -} - -static s32 -wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen) -{ - u32 channel = 0; - s32 ret = BCME_ERROR; - s32 i = 0; - s32 j = 0; - struct bcm_cfg80211 *cfg = NULL; - wl_uint32_list_t *list = NULL; - chanspec_t chanspec = 0; - - memset(buf, 0, buflen); - - cfg = g_bcm_cfg; - list = (wl_uint32_list_t *)buf; - list->count = htod32(WL_NUMCHANSPECS); - - /* Restrict channels to 5GHz, 20MHz BW, no SB. */ - chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 | - WL_CHANSPEC_CTL_SB_NONE); - chanspec = wl_chspec_host_to_driver(chanspec); - - ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, - sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); - goto done; - } - - /* Skip DFS and inavlid P2P channel. */ - for (i = 0, j = 0; i < dtoh32(list->count); i++) { - chanspec = (chanspec_t) dtoh32(list->element[i]); - channel = CHSPEC_CHANNEL(chanspec); - - ret = wldev_iovar_getint(ndev, "per_chan_info", &channel); - if (ret < 0) { - WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret)); - goto done; - } - - if (CHANNEL_IS_RADAR(channel) || - !(wl_cfg80211_valid_chanspec_p2p(chanspec))) { - continue; - } else { - list->element[j] = list->element[i]; - } - - j++; - } - - list->count = j; - -done: - return ret; -} - -static s32 -wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen, - int *channel) -{ - s32 ret = BCME_ERROR; - int chosen = 0; - int retry = 0; - - /* Start auto channel selection scan. */ - ret = wldev_ioctl(ndev, WLC_START_CHANNEL_SEL, buf, buflen, true); - if (ret < 0) { - WL_ERR(("can't start auto channel scan, error = %d\n", ret)); - *channel = 0; - goto done; - } - - /* Wait for auto channel selection, worst case possible delay is 5250ms. */ - retry = CHAN_SEL_RETRY_COUNT; - - while (retry--) { - OSL_SLEEP(CHAN_SEL_IOCTL_DELAY); - - ret = wldev_ioctl(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), - false); - if ((ret == 0) && (dtoh32(chosen) != 0)) { - *channel = (u16)(chosen & 0x00FF); - WL_INFORM(("selected channel = %d\n", *channel)); - break; - } - WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n", - (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen))); - } - - if (retry <= 0) { - WL_ERR(("failure, auto channel selection timed out\n")); - *channel = 0; - ret = BCME_ERROR; - } - -done: - return ret; -} - -static s32 -wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev) -{ - u32 val = 0; - s32 ret = BCME_ERROR; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - /* Clear scan stop driver status. */ - wl_clr_drv_status(cfg, SCANNING, ndev); - - /* Enable mpc back to 1, irrespective of initial state. */ - val = 1; - - ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, - sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, - &cfg->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("set 'mpc' failed, error = %d\n", ret)); - } - - return ret; -} - -s32 -wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len) -{ - int channel = 0; - s32 ret = BCME_ERROR; - u8 *buf = NULL; - char *pos = cmd; - struct bcm_cfg80211 *cfg = NULL; - struct net_device *ndev = NULL; - - memset(cmd, 0, total_len); - - buf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL); - if (buf == NULL) { - WL_ERR(("failed to allocate chanspec buffer\n")); - return -ENOMEM; - } - - /* - * Always use primary interface, irrespective of interface on which - * command came. - */ - cfg = g_bcm_cfg; - ndev = bcmcfg_to_prmry_ndev(cfg); - - /* - * Make sure that FW and driver are in right state to do auto channel - * selection scan. - */ - ret = wl_cfg80211_set_auto_channel_scan_state(ndev); - if (ret < 0) { - WL_ERR(("can't set auto channel scan state, error = %d\n", ret)); - goto done; - } - - /* Best channel selection in 2.4GHz band. */ - ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); - if (ret < 0) { - WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret)); - goto done; - } - - ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, - &channel); - if (ret < 0) { - WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret)); - goto done; - } - - if (CHANNEL_IS_2G(channel)) { - channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); - } else { - WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel)); - channel = 0; - } - - sprintf(pos, "%04d ", channel); - pos += 5; - - /* Best channel selection in 5GHz band. */ - ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); - if (ret < 0) { - WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret)); - goto done; - } - - ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, - &channel); - if (ret < 0) { - WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret)); - goto done; - } - - if (CHANNEL_IS_5G(channel)) { - channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); - } else { - WL_ERR(("invalid 5GHz channel, channel = %d\n", channel)); - channel = 0; - } - - sprintf(pos, "%04d ", channel); - pos += 5; - - /* Set overall best channel same as 5GHz best channel. */ - sprintf(pos, "%04d ", channel); - pos += 5; - -done: - if (NULL != buf) { - kfree(buf); - } - - /* Restore FW and driver back to normal state. */ - ret = wl_cfg80211_restore_auto_channel_scan_state(ndev); - if (ret < 0) { - WL_ERR(("can't restore auto channel scan state, error = %d\n", ret)); - } - - return (pos - cmd); -} -#endif /* WL_SUPPORT_AUTO_CHANNEL */ - -static const struct rfkill_ops wl_rfkill_ops = { - .set_block = wl_rfkill_set -}; - -static int wl_rfkill_set(void *data, bool blocked) -{ - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; - - WL_DBG(("Enter \n")); - WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked")); - - if (!cfg) - return -EINVAL; - - cfg->rf_blocked = blocked; - - return 0; -} - -static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup) -{ - s32 err = 0; - - WL_DBG(("Enter \n")); - if (!cfg) - return -EINVAL; - if (setup) { - cfg->rfkill = rfkill_alloc("brcmfmac-wifi", - wl_cfg80211_get_parent_dev(), - RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg); - - if (!cfg->rfkill) { - err = -ENOMEM; - goto err_out; - } - - err = rfkill_register(cfg->rfkill); - - if (err) - rfkill_destroy(cfg->rfkill); - } else { - if (!cfg->rfkill) { - err = -ENOMEM; - goto err_out; - } - - rfkill_unregister(cfg->rfkill); - rfkill_destroy(cfg->rfkill); - } - -err_out: - return err; -} - -#ifdef DEBUGFS_CFG80211 -/** -* Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level -* to turn on SCAN and DBG log. -* To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level -* To see current setting of debug level, -* cat /sys/kernel/debug/dhd/debug_level -*/ -static ssize_t -wl_debuglevel_write(struct file *file, const char __user *userbuf, - size_t count, loff_t *ppos) -{ - char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL]; - char *params, *token, *colon; - uint i, tokens, log_on = 0; - memset(tbuf, 0, sizeof(tbuf)); - memset(sublog, 0, sizeof(sublog)); - if (copy_from_user(&tbuf, userbuf, min_t(size_t, (sizeof(tbuf) - 1), count))) - return -EFAULT; - - params = &tbuf[0]; - colon = strchr(params, '\n'); - if (colon != NULL) - *colon = '\0'; - while ((token = strsep(¶ms, " ")) != NULL) { - memset(sublog, 0, sizeof(sublog)); - if (token == NULL || !*token) - break; - if (*token == '\0') - continue; - colon = strchr(token, ':'); - if (colon != NULL) { - *colon = ' '; - } - tokens = sscanf(token, "%s %u", sublog, &log_on); - if (colon != NULL) - *colon = ':'; - - if (tokens == 2) { - for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { - if (!strncmp(sublog, sublogname_map[i].sublogname, - strlen(sublogname_map[i].sublogname))) { - if (log_on) - wl_dbg_level |= - (sublogname_map[i].log_level); - else - wl_dbg_level &= - ~(sublogname_map[i].log_level); - } - } - } else - WL_ERR(("%s: can't parse '%s' as a " - "SUBMODULE:LEVEL (%d tokens)\n", - tbuf, token, tokens)); - - - } - return count; -} - -static ssize_t -wl_debuglevel_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - char *param; - char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)]; - uint i; - memset(tbuf, 0, sizeof(tbuf)); - param = &tbuf[0]; - for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { - param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ", - sublogname_map[i].sublogname, - (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0); - } - *param = '\n'; - return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0])); - -} -static const struct file_operations fops_debuglevel = { - .open = NULL, - .write = wl_debuglevel_write, - .read = wl_debuglevel_read, - .owner = THIS_MODULE, - .llseek = NULL, -}; - -static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg) -{ - s32 err = 0; - struct dentry *_dentry; - if (!cfg) - return -EINVAL; - cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!cfg->debugfs || IS_ERR(cfg->debugfs)) { - if (cfg->debugfs == ERR_PTR(-ENODEV)) - WL_ERR(("Debugfs is not enabled on this kernel\n")); - else - WL_ERR(("Can not create debugfs directory\n")); - cfg->debugfs = NULL; - goto exit; - - } - _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR, - cfg->debugfs, cfg, &fops_debuglevel); - if (!_dentry || IS_ERR(_dentry)) { - WL_ERR(("failed to create debug_level debug file\n")); - wl_free_debugfs(cfg); - } -exit: - return err; -} -static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg) -{ - if (!cfg) - return -EINVAL; - if (cfg->debugfs) - debugfs_remove_recursive(cfg->debugfs); - cfg->debugfs = NULL; - return 0; -} -#endif /* DEBUGFS_CFG80211 */ - -struct device *wl_cfg80211_get_parent_dev(void) -{ - return cfg80211_parent_dev; -} - -void wl_cfg80211_set_parent_dev(void *dev) -{ - cfg80211_parent_dev = dev; -} - -static void wl_cfg80211_clear_parent_dev(void) -{ - cfg80211_parent_dev = NULL; -} - -void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac) -{ - wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr", NULL, - 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync); - memcpy(mac->octet, cfg->ioctl_buf, ETHER_ADDR_LEN); -} -static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role) -{ - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - if (((dev_role == NL80211_IFTYPE_AP) && - !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) || - ((dev_role == NL80211_IFTYPE_P2P_GO) && - !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE))) - { - WL_ERR(("device role select failed\n")); - return false; - } - return true; -} - -int wl_cfg80211_do_driver_init(struct net_device *net) -{ - struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net); - - if (!cfg || !cfg->wdev) - return -EINVAL; - - if (dhd_do_driver_init(cfg->wdev->netdev) < 0) - return -1; - - return 0; -} - -void wl_cfg80211_enable_trace(bool set, u32 level) -{ - if (set) - wl_dbg_level = level & WL_DBG_LEVEL; - else - wl_dbg_level |= (WL_DBG_LEVEL & level); -} -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 2, 0)) -static s32 -wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, - bcm_struct_cfgdev *cfgdev, u64 cookie) -{ - /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION - * is passed with CMD_FRAME. This callback is supposed to cancel - * the OFFCHANNEL Wait. Since we are already taking care of that - * with the tx_mgmt logic, do nothing here. - */ - - return 0; -} -#endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */ - -#ifdef WL11U -bcm_tlv_t * -wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) { - return (bcm_tlv_t *)ie; - } - return NULL; -} - - -static s32 -wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, - uint8 ie_id, uint8 *data, uint8 data_len) -{ - s32 err = BCME_OK; - s32 buf_len; - s32 iecount; - ie_setbuf_t *ie_setbuf; - - if (ie_id != DOT11_MNG_INTERWORKING_ID) - return BCME_UNSUPPORTED; - - if (data_len > IW_IES_MAX_BUF_LEN) { - WL_ERR(("wrong data_len:%d\n", data_len)); - return BCME_BADARG; - } - /* Validate the pktflag parameter */ - if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | - VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | - VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| - VNDR_IE_CUSTOM_FLAG))) { - WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag)); - return -1; - } - - /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ - pktflag = htod32(pktflag); - - buf_len = sizeof(ie_setbuf_t) + data_len - 1; - ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); - - if (!ie_setbuf) { - WL_ERR(("Error allocating buffer for IE\n")); - return -ENOMEM; - } - - if (cfg->iw_ie_len == data_len && !memcmp(cfg->iw_ie, data, data_len)) { - WL_ERR(("Previous IW IE is equals to current IE\n")); - err = BCME_OK; - goto exit; - } - - strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); - ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - - /* Buffer contains only 1 IE */ - iecount = htod32(1); - memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); - memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); - - /* Now, add the IE to the buffer */ - ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; - - /* if already set with previous values, delete it first */ - if (cfg->iw_ie_len != 0) { - WL_DBG(("Different IW_IE was already set. clear first\n")); - - ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; - - err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - if (err != BCME_OK) - goto exit; - } - - ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; - memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); - - err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - if (err == BCME_OK) { - memcpy(cfg->iw_ie, data, data_len); - cfg->iw_ie_len = data_len; - cfg->wl11u = TRUE; - - err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); - } - -exit: - if (ie_setbuf) - kfree(ie_setbuf); - return err; -} -#endif /* WL11U */ - -#ifdef WL_HOST_BAND_MGMT -s32 -wl_cfg80211_set_band(struct net_device *ndev, int band) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - int ret = 0; - char ioctl_buf[50]; - - if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) { - WL_ERR(("Invalid band\n")); - return -EINVAL; - } - - if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band, - sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) { - WL_ERR(("seting roam_band failed code=%d\n", ret)); - return ret; - } - - WL_DBG(("Setting band to %d\n", band)); - cfg->curr_band = band; - - return 0; -} -#endif /* WL_HOST_BAND_MGMT */ - - -int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev) -{ - struct bcm_cfg80211 *cfg = NULL; - struct net_device *ndev = NULL; - unsigned long flags; - int clear_flag = 0; - int ret = 0; - - WL_TRACE(("Enter\n")); - - cfg = g_bcm_cfg; - if (!cfg) - return -EINVAL; - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); -#ifdef WL_CFG80211_P2P_DEV_IF - if (cfg->scan_request && cfg->scan_request->wdev == cfgdev) { -#else - if (cfg->scan_request && cfg->scan_request->dev == cfgdev) { -#endif - cfg80211_scan_done(cfg->scan_request, true); - cfg->scan_request = NULL; - clear_flag = 1; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - if (clear_flag) - wl_clr_drv_status(cfg, SCANNING, ndev); - - return ret; -} - -bool wl_cfg80211_is_vsdb_mode(void) -{ - return (g_bcm_cfg && g_bcm_cfg->vsdb_mode); -} - -void* wl_cfg80211_get_dhdp() -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - return cfg->pub; -} - -bool wl_cfg80211_is_p2p_active(void) -{ - return (g_bcm_cfg && g_bcm_cfg->p2p); -} - -static void wl_cfg80211_work_handler(struct work_struct * work) -{ - struct bcm_cfg80211 *cfg = NULL; - struct net_info *iter, *next; - s32 err = BCME_OK; - s32 pm = PM_FAST; - - cfg = container_of(work, struct bcm_cfg80211, pm_enable_work.work); - WL_DBG(("Enter \n")); - if (cfg->pm_enable_work_on) { - cfg->pm_enable_work_on = false; - for_each_ndev(cfg, iter, next) { - if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) || - (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS)) - continue; - if (iter->ndev) { - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, - &pm, sizeof(pm), true)) != 0) { - if (err == -ENODEV) - WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); - else - WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); - } else - wl_cfg80211_update_power_mode(iter->ndev); - } - } - } -} - -u8 -wl_get_action_category(void *frame, u32 frame_len) -{ - u8 category; - u8 *ptr = (u8 *)frame; - if (frame == NULL) - return DOT11_ACTION_CAT_ERR_MASK; - if (frame_len < DOT11_ACTION_HDR_LEN) - return DOT11_ACTION_CAT_ERR_MASK; - category = ptr[DOT11_ACTION_CAT_OFF]; - WL_INFORM(("Action Category: %d\n", category)); - return category; -} - -int -wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action) -{ - u8 *ptr = (u8 *)frame; - if (frame == NULL || ret_action == NULL) - return BCME_ERROR; - if (frame_len < DOT11_ACTION_HDR_LEN) - return BCME_ERROR; - if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len)) - return BCME_ERROR; - *ret_action = ptr[DOT11_ACTION_ACT_OFF]; - WL_INFORM(("Public Action : %d\n", *ret_action)); - return BCME_OK; -} - -#ifdef WLFBT -void -wl_cfg80211_get_fbt_key(uint8 *key) -{ - memcpy(key, g_bcm_cfg->fbt_key, FBT_KEYLEN); -} -#endif /* WLFBT */ - -static int -wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const struct ether_addr *bssid) -{ - s32 err; - wl_event_msg_t e; - - bzero(&e, sizeof(e)); - e.event_type = cpu_to_be32(WLC_E_BSSID); - memcpy(&e.addr, bssid, ETHER_ADDR_LEN); - /* trigger the roam event handler */ - err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL); - - return err; -} - -#ifdef WL_CFG80211_ACL -static int -wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, - const struct cfg80211_acl_data *acl) -{ - int i; - int ret = 0; - int macnum = 0; - int macmode = MACLIST_MODE_DISABLED; - struct maclist *list; - - /* get the MAC filter mode */ - if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) { - macmode = MACLIST_MODE_ALLOW; - } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED && - acl->n_acl_entries) { - macmode = MACLIST_MODE_DENY; - } - - /* if acl == NULL, macmode is still disabled.. */ - if (macmode == MACLIST_MODE_DISABLED) { - if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0) - WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); - - return ret; - } - - macnum = acl->n_acl_entries; - if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { - WL_ERR(("%s : invalid number of MAC address entries %d\n", - __FUNCTION__, macnum)); - return -1; - } - - /* allocate memory for the MAC list */ - list = (struct maclist*)kmalloc(sizeof(int) + - sizeof(struct ether_addr) * macnum, GFP_KERNEL); - if (!list) { - WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__)); - return -1; - } - - /* prepare the MAC list */ - list->count = htod32(macnum); - for (i = 0; i < macnum; i++) { - memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN); - } - /* set the list */ - if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0) - WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); - - kfree(list); - - return ret; -} -#endif /* WL_CFG80211_ACL */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -int wl_chspec_chandef(chanspec_t chanspec, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -struct cfg80211_chan_def *chandef, -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ - \ - 0))) -struct chan_info *chaninfo, -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */ -struct wiphy *wiphy) -{ - uint16 freq = 0; - int chan_type; - int channel = 0; - - if (!chandef) { - return -1; - } - channel = CHSPEC_CHANNEL(chanspec); - - switch (CHSPEC_BW(chanspec)) { - case WL_CHANSPEC_BW_20: - chan_type = NL80211_CHAN_HT20; - break; - case WL_CHANSPEC_BW_40: - { - if (CHSPEC_SB_UPPER(chanspec)) { - channel += CH_10MHZ_APART; - } else { - channel -= CH_10MHZ_APART; - } - } - chan_type = NL80211_CHAN_HT40PLUS; - break; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) - case WL_CHANSPEC_BW_80: - case WL_CHANSPEC_BW_8080: - { - uint16 sb = CHSPEC_CTL_SB(chanspec); - - if (sb == WL_CHANSPEC_CTL_SB_LL) { - channel -= (CH_10MHZ_APART + CH_20MHZ_APART); - } else if (sb == WL_CHANSPEC_CTL_SB_LU) { - channel -= CH_10MHZ_APART; - } else if (sb == WL_CHANSPEC_CTL_SB_UL) { - channel += CH_10MHZ_APART; - } else { - /* WL_CHANSPEC_CTL_SB_UU */ - channel += (CH_10MHZ_APART + CH_20MHZ_APART); - } - } - - chan_type = NL80211_CHAN_WIDTH_80P80; - break; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ - default: - chan_type = NL80211_CHAN_HT20; - break; - - } - - if (CHSPEC_IS5G(chanspec)) - freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ); - else - freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) - cfg80211_chandef_create(chandef, ieee80211_get_channel(wiphy, freq), chan_type); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ - \ - 0))) - chaninfo->freq = freq; - chaninfo->chan_type = chan_type; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ - return 0; -} - -void -wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) - struct cfg80211_chan_def chandef; -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ - \ - 0))) - struct chan_info chaninfo; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ - - if (!wiphy) { - printk("wiphy is null\n"); - return; - } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) - if (wl_chspec_chandef(chanspec, &chandef, wiphy)) { -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ - \ - 0))) - if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) { -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ - - WL_ERR(("%s:chspec_chandef failed\n", __FUNCTION__)); - return; - } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) - cfg80211_ch_switch_notify(dev, &chandef); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ - \ - 0))) - cfg80211_ch_switch_notify(dev, chan_info.freq, chan_info.chan_type); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ - return; -} - -static s32 -wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, -const wl_event_msg_t *e, void *data) -{ - int error = 0; - int chsp = 0; - struct net_device *ndev = NULL; - struct wiphy *wiphy = NULL; - chanspec_t chanspec; - - WL_ERR(("%s\n", __FUNCTION__)); - if (e->status) - return -1; - if (cfgdev) { - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - wiphy = bcmcfg_to_wiphy(cfg); - error = wldev_iovar_getint(ndev, "chanspec", &chsp); - if (error) - return -1; - chanspec = wl_chspec_driver_to_host(chsp); - wl_cfg80211_ch_switch_notify(ndev, chanspec, wiphy); - } else { - WL_ERR(("%s:cfgdev is null\n", __FUNCTION__)); - return -1; - } - - - return 0; -} -#else -static s32 -wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, -const wl_event_msg_t *e, void *data) -{ - WL_ERR(("%s:Not sup for kernel < 3.5\n", __FUNCTION__)); - return 0; -} -#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h deleted file mode 100644 index f1dfe77b95ef..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ /dev/null @@ -1,1040 +0,0 @@ -/* - * Linux cfg80211 driver - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.h 633622 2016-04-24 11:50:51Z $ - */ - -/** - * Older Linux versions support the 'iw' interface, more recent ones the 'cfg80211' interface. - */ - -#ifndef _wl_cfg80211_h_ -#define _wl_cfg80211_h_ - -#include -#include -#include -#include -#include -#include -#include - -#include - -struct wl_conf; -struct wl_iface; -struct bcm_cfg80211; -struct wl_security; -struct wl_ibss; - - -#define htod32(i) (i) -#define htod16(i) (i) -#define dtoh64(i) (i) -#define dtoh32(i) (i) -#define dtoh16(i) (i) -#define htodchanspec(i) (i) -#define dtohchanspec(i) (i) - -#define WL_DBG_NONE 0 -#define WL_DBG_P2P_ACTION (1 << 5) -#define WL_DBG_TRACE (1 << 4) -#define WL_DBG_SCAN (1 << 3) -#define WL_DBG_DBG (1 << 2) -#define WL_DBG_INFO (1 << 1) -#define WL_DBG_ERR (1 << 0) - -/* 0 invalidates all debug messages. default is 1 */ -#define WL_DBG_LEVEL 0xFF - -#define CFG80211_ERROR_TEXT "CFG80211-ERROR) " - -#define MAX_WAIT_TIME 1500 -#define DNGL_FUNC(func, parameters) func parameters; - -#define PM_BLOCK 1 -#define PM_ENABLE 0 - -#if defined(DHD_DEBUG) -#define WL_ERR(args) \ -do { \ - if (wl_dbg_level & WL_DBG_ERR) { \ - printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ - printk args; \ - } \ -} while (0) -#else /* defined(DHD_DEBUG) */ -#define WL_ERR(args) \ -do { \ - if ((wl_dbg_level & WL_DBG_ERR) && net_ratelimit()) { \ - printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ - printk args; \ - } \ -} while (0) -#endif /* defined(DHD_DEBUG) */ - -#ifdef WL_INFORM -#undef WL_INFORM -#endif - -#define WL_INFORM(args) \ -do { \ - if (wl_dbg_level & WL_DBG_INFO) { \ - printk(KERN_INFO "CFG80211-INFO) %s : ", __func__); \ - printk args; \ - } \ -} while (0) - - -#ifdef WL_SCAN -#undef WL_SCAN -#endif -#define WL_SCAN(args) \ -do { \ - if (wl_dbg_level & WL_DBG_SCAN) { \ - printk(KERN_INFO "CFG80211-SCAN) %s :", __func__); \ - printk args; \ - } \ -} while (0) -#ifdef WL_TRACE -#undef WL_TRACE -#endif -#define WL_TRACE(args) \ -do { \ - if (wl_dbg_level & WL_DBG_TRACE) { \ - printk(KERN_INFO "CFG80211-TRACE) %s :", __func__); \ - printk args; \ - } \ -} while (0) -#ifdef WL_TRACE_HW4 -#undef WL_TRACE_HW4 -#endif -#define WL_TRACE_HW4 WL_TRACE -#if (WL_DBG_LEVEL > 0) -#define WL_DBG(args) \ -do { \ - if (wl_dbg_level & WL_DBG_DBG) { \ - printk(KERN_DEBUG "CFG80211-DEBUG) %s :", __func__); \ - printk args; \ - } \ -} while (0) -#else /* !(WL_DBG_LEVEL > 0) */ -#define WL_DBG(args) -#endif /* (WL_DBG_LEVEL > 0) */ -#define WL_PNO(x) -#define WL_SD(x) - - -#define WL_SCAN_RETRY_MAX 3 -#define WL_NUM_PMKIDS_MAX MAXPMKID -#define WL_SCAN_BUF_MAX (1024 * 8) -#define WL_TLV_INFO_MAX 1500 -#define WL_SCAN_IE_LEN_MAX 2048 -#define WL_BSS_INFO_MAX 2048 -#define WL_ASSOC_INFO_MAX 512 -#define WL_IOCTL_LEN_MAX 2048 -#define WL_EXTRA_BUF_MAX 2048 -#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) -#define WL_AP_MAX 256 -#define WL_FILE_NAME_MAX 256 -#define WL_DWELL_TIME 200 -#define WL_MED_DWELL_TIME 400 -#define WL_MIN_DWELL_TIME 100 -#define WL_LONG_DWELL_TIME 1000 -#define IFACE_MAX_CNT 2 -#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 -#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 -#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 -#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 -#define WL_AF_TX_MAX_RETRY 5 - -#define WL_AF_SEARCH_TIME_MAX 450 -#define WL_AF_TX_EXTRA_TIME_MAX 200 - -#define WL_SCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */ -#define WL_CHANNEL_SYNC_RETRY 5 -#define WL_INVALID -1 - -/* Bring down SCB Timeout to 20secs from 60secs default */ -#ifndef WL_SCB_TIMEOUT -#define WL_SCB_TIMEOUT 20 -#endif - -/* SCAN_SUPPRESS timer values in ms */ -#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */ -#define WL_SCAN_SUPPRESS_RETRY 3000 - -#define WL_PM_ENABLE_TIMEOUT 10000 - -#ifdef WLAIBSS -/* Custom AIBSS beacon parameters */ -#define AIBSS_INITIAL_MIN_BCN_DUR 500 -#define AIBSS_MIN_BCN_DUR 5000 -#define AIBSS_BCN_FLOOD_DUR 5000 -#endif /* WLAIBSS */ - -/* driver status */ -enum wl_status { - WL_STATUS_READY = 0, - WL_STATUS_SCANNING, - WL_STATUS_SCAN_ABORTING, - WL_STATUS_CONNECTING, - WL_STATUS_CONNECTED, - WL_STATUS_DISCONNECTING, - WL_STATUS_AP_CREATING, - WL_STATUS_AP_CREATED, - /* whole sending action frame procedure: - * includes a) 'finding common channel' for public action request frame - * and b) 'sending af via 'actframe' iovar' - */ - WL_STATUS_SENDING_ACT_FRM, - /* find a peer to go to a common channel before sending public action req frame */ - WL_STATUS_FINDING_COMMON_CHANNEL, - /* waiting for next af to sync time of supplicant. - * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN - */ - WL_STATUS_WAITING_NEXT_ACT_FRM, -#ifdef WL_CFG80211_SYNC_GON - /* go to listen state to wait for next af after SENDING_ACT_FRM */ - WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN, -#endif /* WL_CFG80211_SYNC_GON */ - /* it will be set when upper layer requests listen and succeed in setting listen mode. - * if set, other scan request can abort current listen state - */ - WL_STATUS_REMAINING_ON_CHANNEL, -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - /* it's fake listen state to keep current scan state. - * it will be set when upper layer requests listen but scan is running. then just run - * a expire timer without actual listen state. - * if set, other scan request does not need to abort scan. - */ - WL_STATUS_FAKE_REMAINING_ON_CHANNEL -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -}; - -/* wi-fi mode */ -enum wl_mode { - WL_MODE_BSS, - WL_MODE_IBSS, - WL_MODE_AP -}; - -/* driver profile list */ -enum wl_prof_list { - WL_PROF_MODE, - WL_PROF_SSID, - WL_PROF_SEC, - WL_PROF_IBSS, - WL_PROF_BAND, - WL_PROF_CHAN, - WL_PROF_BSSID, - WL_PROF_ACT, - WL_PROF_BEACONINT, - WL_PROF_DTIMPERIOD -}; - -/* donlge escan state */ -enum wl_escan_state { - WL_ESCAN_STATE_IDLE, - WL_ESCAN_STATE_SCANING -}; -/* fw downloading status */ -enum wl_fw_status { - WL_FW_LOADING_DONE, - WL_NVRAM_LOADING_DONE -}; - -enum wl_management_type { - WL_BEACON = 0x1, - WL_PROBE_RESP = 0x2, - WL_ASSOC_RESP = 0x4 -}; - -enum wl_handler_del_type { - WL_HANDLER_NOTUSE, - WL_HANDLER_DEL, - WL_HANDLER_MAINTAIN, - WL_HANDLER_PEND -}; - -/* beacon / probe_response */ -struct beacon_proberesp { - __le64 timestamp; - __le16 beacon_int; - __le16 capab_info; - u8 variable[0]; -} __attribute__ ((packed)); - -/* driver configuration */ -struct wl_conf { - u32 frag_threshold; - u32 rts_threshold; - u32 retry_short; - u32 retry_long; - s32 tx_power; - struct ieee80211_channel channel; -}; - -typedef s32(*EVENT_HANDLER) (struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); - -/* bss inform structure for cfg80211 interface */ -struct wl_cfg80211_bss_info { - u16 band; - u16 channel; - s16 rssi; - u16 frame_len; - u8 frame_buf[1]; -}; - -/* basic structure of scan request */ -struct wl_scan_req { - struct wlc_ssid ssid; -}; - -/* basic structure of information element */ -struct wl_ie { - u16 offset; - u8 buf[WL_TLV_INFO_MAX]; -}; - -/* event queue for cfg80211 main event */ -struct wl_event_q { - struct list_head eq_list; - u32 etype; - wl_event_msg_t emsg; - s8 edata[1]; -}; - -/* security information with currently associated ap */ -struct wl_security { - u32 wpa_versions; - u32 auth_type; - u32 cipher_pairwise; - u32 cipher_group; - u32 wpa_auth; - u32 auth_assoc_res_status; -}; - -/* ibss information for currently joined ibss network */ -struct wl_ibss { - u8 beacon_interval; /* in millisecond */ - u8 atim; /* in millisecond */ - s8 join_only; - u8 band; - u8 channel; -}; - -/* cfg driver profile */ -struct wl_profile { - u32 mode; - s32 band; - u32 channel; - struct wlc_ssid ssid; - struct wl_security sec; - struct wl_ibss ibss; - u8 bssid[ETHER_ADDR_LEN]; - u16 beacon_interval; - u8 dtim_period; - bool active; -}; - -struct net_info { - struct net_device *ndev; - struct wireless_dev *wdev; - struct wl_profile profile; - s32 mode; - s32 roam_off; - unsigned long sme_state; - bool pm_restore; - bool pm_block; - s32 pm; - struct list_head list; /* list of all net_info structure */ -}; - -/* association inform */ -#define MAX_REQ_LINE 1024u -struct wl_connect_info { - u8 req_ie[MAX_REQ_LINE]; - u32 req_ie_len; - u8 resp_ie[MAX_REQ_LINE]; - u32 resp_ie_len; -}; - -/* firmware /nvram downloading controller */ -struct wl_fw_ctrl { - const struct firmware *fw_entry; - unsigned long status; - u32 ptr; - s8 fw_name[WL_FILE_NAME_MAX]; - s8 nvram_name[WL_FILE_NAME_MAX]; -}; - -/* assoc ie length */ -struct wl_assoc_ielen { - u32 req_len; - u32 resp_len; -}; - -/* wpa2 pmk list */ -struct wl_pmk_list { - pmkid_list_t pmkids; - pmkid_t foo[MAXPMKID - 1]; -}; - - -#define ESCAN_BUF_SIZE (64 * 1024) - -struct escan_info { - u32 escan_state; -#if defined(STATIC_WL_PRIV_STRUCT) -#ifndef CONFIG_DHD_USE_STATIC_BUF -#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - u8 *escan_buf; -#else - u8 escan_buf[ESCAN_BUF_SIZE]; -#endif /* STATIC_WL_PRIV_STRUCT */ - struct wiphy *wiphy; - struct net_device *ndev; -}; - -#ifdef ESCAN_BUF_OVERFLOW_MGMT -#define BUF_OVERFLOW_MGMT_COUNT 3 -typedef struct { - int RSSI; - int length; - struct ether_addr BSSID; -} removal_element_t; -#endif /* ESCAN_BUF_OVERFLOW_MGMT */ - -struct ap_info { -/* Structure to hold WPS, WPA IEs for a AP */ - u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN]; - u8 beacon_ie[VNDR_IES_MAX_BUF_LEN]; - u8 assoc_res_ie[VNDR_IES_MAX_BUF_LEN]; - u32 probe_res_ie_len; - u32 beacon_ie_len; - u32 assoc_res_ie_len; - u8 *wpa_ie; - u8 *rsn_ie; - u8 *wps_ie; - bool security_mode; -}; - -struct sta_info { - /* Structure to hold WPS IE for a STA */ - u8 probe_req_ie[VNDR_IES_BUF_LEN]; - u8 assoc_req_ie[VNDR_IES_BUF_LEN]; - u32 probe_req_ie_len; - u32 assoc_req_ie_len; -}; - -struct afx_hdl { - wl_af_params_t *pending_tx_act_frm; - struct ether_addr tx_dst_addr; - struct net_device *dev; - struct work_struct work; - u32 bssidx; - u32 retry; - s32 peer_chan; - s32 peer_listen_chan; /* search channel: configured by upper layer */ - s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */ - bool is_listen; - bool ack_recv; - bool is_active; -}; - -struct parsed_ies { - wpa_ie_fixed_t *wps_ie; - u32 wps_ie_len; - wpa_ie_fixed_t *wpa_ie; - u32 wpa_ie_len; - bcm_tlv_t *wpa2_ie; - u32 wpa2_ie_len; -}; - - -#ifdef WL11U -/* Max length of Interworking element */ -#define IW_IES_MAX_BUF_LEN 9 -#endif -#ifdef WLFBT -#define FBT_KEYLEN 32 -#endif -#define MAX_EVENT_BUF_NUM 16 -typedef struct wl_eventmsg_buf { - u16 num; - struct { - u16 type; - bool set; - } event [MAX_EVENT_BUF_NUM]; -} wl_eventmsg_buf_t; - -typedef struct wl_if_event_info { - bool valid; - int ifidx; - int bssidx; - uint8 mac[ETHER_ADDR_LEN]; - char name[IFNAMSIZ+1]; -} wl_if_event_info; - -/* private data of cfg80211 interface */ -struct bcm_cfg80211 { - struct wireless_dev *wdev; /* representing cfg cfg80211 device */ - - struct wireless_dev *p2p_wdev; /* representing cfg cfg80211 device for P2P */ - struct net_device *p2p_net; /* reference to p2p0 interface */ - - struct wl_conf *conf; - struct cfg80211_scan_request *scan_request; /* scan request object */ - EVENT_HANDLER evt_handler[WLC_E_LAST]; - struct list_head eq_list; /* used for event queue */ - struct list_head net_list; /* used for struct net_info */ - spinlock_t eq_lock; /* for event queue synchronization */ - spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ - struct completion act_frm_scan; - struct completion iface_disable; - struct completion wait_next_af; - struct mutex usr_sync; /* maily for up/down synchronization */ - struct wl_scan_results *bss_list; - struct wl_scan_results *scan_results; - - /* scan request object for internal purpose */ - struct wl_scan_req *scan_req_int; - /* information element object for internal purpose */ -#if defined(STATIC_WL_PRIV_STRUCT) - struct wl_ie *ie; -#else - struct wl_ie ie; -#endif - - /* association information container */ -#if defined(STATIC_WL_PRIV_STRUCT) - struct wl_connect_info *conn_info; -#else - struct wl_connect_info conn_info; -#endif -#ifdef DEBUGFS_CFG80211 - struct dentry *debugfs; -#endif /* DEBUGFS_CFG80211 */ - struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ - tsk_ctl_t event_tsk; /* task of main event handler thread */ - void *pub; - u32 iface_cnt; - u32 channel; /* current channel */ - u32 af_sent_channel; /* channel action frame is sent */ - /* next af subtype to cancel the remained dwell time in rx process */ - u8 next_af_subtype; -#ifdef WL_CFG80211_SYNC_GON - ulong af_tx_sent_jiffies; -#endif /* WL_CFG80211_SYNC_GON */ - struct escan_info escan_info; /* escan information */ - bool active_scan; /* current scan mode */ - bool ibss_starter; /* indicates this sta is ibss starter */ - bool link_up; /* link/connection up flag */ - - /* indicate whether chip to support power save mode */ - bool pwr_save; - bool roam_on; /* on/off switch for self-roaming */ - bool scan_tried; /* indicates if first scan attempted */ -#if defined(BCMSDIO) || defined(BCMPCIE) - bool wlfc_on; -#endif - bool vsdb_mode; - bool roamoff_on_concurrent; - u8 *ioctl_buf; /* ioctl buffer */ - struct mutex ioctl_buf_sync; - u8 *escan_ioctl_buf; - u8 *extra_buf; /* maily to grab assoc information */ - struct dentry *debugfsdir; - struct rfkill *rfkill; - bool rf_blocked; - struct ieee80211_channel remain_on_chan; - enum nl80211_channel_type remain_on_chan_type; - u64 send_action_id; - u64 last_roc_id; - wait_queue_head_t netif_change_event; - wl_if_event_info if_event_info; - struct completion send_af_done; - struct afx_hdl *afx_hdl; - struct ap_info *ap_info; - struct sta_info *sta_info; - struct p2p_info *p2p; - bool p2p_supported; - void *btcoex_info; - struct timer_list scan_timeout; /* Timer for catch scan event timeout */ - s32(*state_notifier) (struct bcm_cfg80211 *cfg, - struct net_info *_net_info, enum wl_status state, bool set); - unsigned long interrested_state; - wlc_ssid_t hostapd_ssid; -#ifdef WL11U - bool wl11u; - u8 iw_ie[IW_IES_MAX_BUF_LEN]; - u32 iw_ie_len; -#endif /* WL11U */ - bool sched_scan_running; /* scheduled scan req status */ -#ifdef WL_SCHED_SCAN - struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ -#endif /* WL_SCHED_SCAN */ -#ifdef WL_HOST_BAND_MGMT - u8 curr_band; -#endif /* WL_HOST_BAND_MGMT */ - bool scan_suppressed; - struct timer_list scan_supp_timer; - struct work_struct wlan_work; - struct mutex event_sync; /* maily for up/down synchronization */ - bool disable_roam_event; - bool pm_enable_work_on; - struct delayed_work pm_enable_work; - vndr_ie_setbuf_t *ibss_vsie; /* keep the VSIE for IBSS */ - int ibss_vsie_len; -#ifdef WLAIBSS - u32 aibss_txfail_pid; - u32 aibss_txfail_seq; -#endif /* WLAIBSS */ - u32 rmc_event_pid; - u32 rmc_event_seq; -#ifdef WLAIBSS_MCHAN - struct ether_addr ibss_if_addr; - bcm_struct_cfgdev *ibss_cfgdev; /* For AIBSS */ -#endif /* WLAIBSS_MCHAN */ - bcm_struct_cfgdev *bss_cfgdev; /* For DUAL STA/STA+AP */ - s32 cfgdev_bssidx; - bool bss_pending_op; /* indicate where there is a pending IF operation */ -#ifdef WLFBT - uint8 fbt_key[FBT_KEYLEN]; -#endif - int roam_offload; - bool nan_enable; - bool nan_running; -#ifdef WLTDLS - u8 *tdls_mgmt_frame; - u32 tdls_mgmt_frame_len; - s32 tdls_mgmt_freq; -#endif /* WLTDLS */ - bool need_wait_afrx; -}; - - -static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) -{ - return bss = bss ? - (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; -} -static inline s32 -wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev, - struct wireless_dev * wdev, s32 mode, bool pm_block) -{ - struct net_info *_net_info; - s32 err = 0; - if (cfg->iface_cnt == IFACE_MAX_CNT) - return -ENOMEM; - _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL); - if (!_net_info) - err = -ENOMEM; - else { - _net_info->mode = mode; - _net_info->ndev = ndev; - _net_info->wdev = wdev; - _net_info->pm_restore = 0; - _net_info->pm = 0; - _net_info->pm_block = pm_block; - _net_info->roam_off = WL_INVALID; - cfg->iface_cnt++; - list_add(&_net_info->list, &cfg->net_list); - } - return err; -} -static inline void -wl_dealloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) { - list_del(&_net_info->list); - cfg->iface_cnt--; - kfree(_net_info); - } - } - -} -static inline void -wl_delete_all_netinfo(struct bcm_cfg80211 *cfg) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - list_del(&_net_info->list); - if (_net_info->wdev) - kfree(_net_info->wdev); - kfree(_net_info); - } - cfg->iface_cnt = 0; -} -static inline u32 -wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status) - -{ - struct net_info *_net_info, *next; - u32 cnt = 0; - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (_net_info->ndev && - test_bit(status, &_net_info->sme_state)) - cnt++; - } - return cnt; -} -static inline void -wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op) -{ - struct net_info *_net_info, *next; - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - switch (op) { - case 1: - return; /* set all status is not allowed */ - case 2: - clear_bit(status, &_net_info->sme_state); - if (cfg->state_notifier && - test_bit(status, &(cfg->interrested_state))) - cfg->state_notifier(cfg, _net_info, status, false); - break; - case 4: - return; /* change all status is not allowed */ - default: - return; /* unknown operation */ - } - } -} -static inline void -wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, - struct net_device *ndev, u32 op) -{ - - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) { - switch (op) { - case 1: - set_bit(status, &_net_info->sme_state); - if (cfg->state_notifier && - test_bit(status, &(cfg->interrested_state))) - cfg->state_notifier(cfg, _net_info, status, true); - break; - case 2: - clear_bit(status, &_net_info->sme_state); - if (cfg->state_notifier && - test_bit(status, &(cfg->interrested_state))) - cfg->state_notifier(cfg, _net_info, status, false); - break; - case 4: - change_bit(status, &_net_info->sme_state); - break; - } - } - - } - -} - -static inline u32 -wl_get_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, - struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - return test_bit(status, &_net_info->sme_state); - } - return 0; -} - -static inline s32 -wl_get_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - return _net_info->mode; - } - return -1; -} - - -static inline void -wl_set_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev, - s32 mode) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - _net_info->mode = mode; - } -} -static inline struct wl_profile * -wl_get_profile_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - return &_net_info->profile; - } - return NULL; -} -static inline struct net_info * -wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - return _net_info; - } - return NULL; -} -#define bcmcfg_to_wiphy(cfg) (cfg->wdev->wiphy) -#define bcmcfg_to_prmry_ndev(cfg) (cfg->wdev->netdev) -#define bcmcfg_to_prmry_wdev(cfg) (cfg->wdev) -#define bcmcfg_to_p2p_wdev(cfg) (cfg->p2p_wdev) -#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) -#define ndev_to_wdev(ndev) (ndev->ieee80211_ptr) -#define wdev_to_ndev(wdev) (wdev->netdev) - -#if defined(WL_ENABLE_P2P_IF) -#define ndev_to_wlc_ndev(ndev, cfg) ((ndev == cfg->p2p_net) ? \ - bcmcfg_to_prmry_ndev(cfg) : ndev) -#else -#define ndev_to_wlc_ndev(ndev, cfg) (ndev) -#endif /* WL_ENABLE_P2P_IF */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -#define wdev_to_wlc_ndev(wdev, cfg) \ - ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) ? \ - bcmcfg_to_prmry_ndev(cfg) : wdev_to_ndev(wdev)) -#define cfgdev_to_wlc_ndev(cfgdev, cfg) wdev_to_wlc_ndev(cfgdev, cfg) -#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_wdev(cfg) -#elif defined(WL_ENABLE_P2P_IF) -#define cfgdev_to_wlc_ndev(cfgdev, cfg) ndev_to_wlc_ndev(cfgdev, cfg) -#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_ndev(cfg) -#else -#define cfgdev_to_wlc_ndev(cfgdev, cfg) (cfgdev) -#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) (cfgdev) -#endif /* WL_CFG80211_P2P_DEV_IF */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -#define ndev_to_cfgdev(ndev) ndev_to_wdev(ndev) -#define cfgdev_to_ndev(cfgdev) cfgdev ? (cfgdev->netdev) : NULL -#define discover_cfgdev(cfgdev, cfg) (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) -#else -#define ndev_to_cfgdev(ndev) (ndev) -#define cfgdev_to_ndev(cfgdev) (cfgdev) -#define discover_cfgdev(cfgdev, cfg) (cfgdev == cfg->p2p_net) -#endif /* WL_CFG80211_P2P_DEV_IF */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \ - (cfg->scan_request->wdev == cfg->p2p_wdev)) ? true : false) -#elif defined(WL_ENABLE_P2P_IF) -#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \ - (cfg->scan_request->dev == cfg->p2p_net)) ? true : false) -#else -#define scan_req_match(cfg) (((cfg) && p2p_is_on(cfg) && p2p_scan(cfg)) ? \ - true : false) -#endif /* WL_CFG80211_P2P_DEV_IF */ - -#define wl_to_sr(w) (w->scan_req_int) -#if defined(STATIC_WL_PRIV_STRUCT) -#define wl_to_ie(w) (w->ie) -#define wl_to_conn(w) (w->conn_info) -#else -#define wl_to_ie(w) (&w->ie) -#define wl_to_conn(w) (&w->conn_info) -#endif -#define wiphy_from_scan(w) (w->escan_info.wiphy) -#define wl_get_drv_status_all(cfg, stat) \ - (wl_get_status_all(cfg, WL_STATUS_ ## stat)) -#define wl_get_drv_status(cfg, stat, ndev) \ - (wl_get_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev)) -#define wl_set_drv_status(cfg, stat, ndev) \ - (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 1)) -#define wl_clr_drv_status(cfg, stat, ndev) \ - (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 2)) -#define wl_clr_drv_status_all(cfg, stat) \ - (wl_set_status_all(cfg, WL_STATUS_ ## stat, 2)) -#define wl_chg_drv_status(cfg, stat, ndev) \ - (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 4)) - -#define for_each_bss(list, bss, __i) \ - for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) - -#define for_each_ndev(cfg, iter, next) \ - list_for_each_entry_safe(iter, next, &cfg->net_list, list) - - -/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0. - * In addtion to that, wpa_version is WPA_VERSION_1 - */ -#define is_wps_conn(_sme) \ - ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \ - (!_sme->crypto.n_ciphers_pairwise) && \ - (!_sme->crypto.cipher_group)) -extern s32 wl_cfg80211_attach(struct net_device *ndev, void *context); -extern s32 wl_cfg80211_attach_post(struct net_device *ndev); -extern void wl_cfg80211_detach(void *para); - -extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, - void *data); -void wl_cfg80211_set_parent_dev(void *dev); -struct device *wl_cfg80211_get_parent_dev(void); - -extern s32 wl_cfg80211_up(void *para); -extern s32 wl_cfg80211_down(void *para); -extern s32 wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx); -extern s32 wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx); -extern s32 wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx); -extern struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, - uint8 *mac, uint8 bssidx); -extern int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev); -extern int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev); -extern int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev); -extern bool wl_cfg80211_is_vsdb_mode(void); -extern void* wl_cfg80211_get_dhdp(void); -extern bool wl_cfg80211_is_p2p_active(void); -extern void wl_cfg80211_dbg_level(u32 level); -extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); -extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len); -extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); -extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, - enum wl_management_type type); -extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); - -/* btcoex functions */ -void* wl_cfg80211_btcoex_init(struct net_device *ndev); -void wl_cfg80211_btcoex_deinit(void); - - -#ifdef WL_SUPPORT_AUTO_CHANNEL -#define CHANSPEC_BUF_SIZE 1024 -#define CHAN_SEL_IOCTL_DELAY 300 -#define CHAN_SEL_RETRY_COUNT 15 -#define CHANNEL_IS_RADAR(channel) (((channel & WL_CHAN_RADAR) || \ - (channel & WL_CHAN_PASSIVE)) ? true : false) -#define CHANNEL_IS_2G(channel) (((channel >= 1) && (channel <= 14)) ? \ - true : false) -#define CHANNEL_IS_5G(channel) (((channel >= 36) && (channel <= 165)) ? \ - true : false) -extern s32 wl_cfg80211_get_best_channels(struct net_device *dev, char* command, - int total_len); -#endif /* WL_SUPPORT_AUTO_CHANNEL */ - -extern int wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n); -extern int wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str); -extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); -extern s32 wl_mode_to_nl80211_iftype(s32 mode); -int wl_cfg80211_do_driver_init(struct net_device *net); -void wl_cfg80211_enable_trace(bool set, u32 level); -extern s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify); -extern s32 wl_cfg80211_if_is_group_owner(void); -extern chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec); -extern chanspec_t wl_ch_host_to_driver(u16 channel); -extern s32 wl_set_tx_power(struct net_device *dev, - enum nl80211_tx_power_setting type, s32 dbm); -extern s32 wl_get_tx_power(struct net_device *dev, s32 *dbm); -extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); -extern void wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev); -#ifdef WL_HOST_BAND_MGMT -extern s32 wl_cfg80211_set_band(struct net_device *ndev, int band); -#endif /* WL_HOST_BAND_MGMT */ -extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set); -extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, - struct bcm_cfg80211 *cfg, wl_eventmsg_buf_t *ev); -extern void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac); -extern void wl_cfg80211_update_power_mode(struct net_device *dev); -extern void wl_reinit_event_handler(void); - -#define SCAN_BUF_CNT 2 -#define SCAN_BUF_NEXT 1 -#define WL_SCANTYPE_LEGACY 0x1 -#define WL_SCANTYPE_P2P 0x2 -#define wl_escan_set_sync_id(a, b) ((a) = htod16(0x1234)) -#define wl_escan_set_type(a, b) -#define wl_escan_get_buf(a, b) ((wl_scan_results_t *) (a)->escan_info.escan_buf) -#define wl_escan_check_sync_id(a, b, c) 0 -#define wl_escan_print_sync_id(a, b, c) -#define wl_escan_increment_sync_id(a, b) -#define wl_escan_init_sync_id(a) -extern void wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len); -extern s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev); -#ifdef WLAIBSS -extern void wl_cfg80211_set_txfail_pid(int pid); -#endif /* WLAIBSS */ -extern void wl_cfg80211_set_rmc_pid(int pid); - -#ifdef WLFBT -extern void wl_cfg80211_get_fbt_key(uint8 *key); -#endif - -/* Action frame specific functions */ -extern u8 wl_get_action_category(void *frame, u32 frame_len); -extern int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action); - -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -struct net_device *wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - -#ifdef WL_SUPPORT_ACS -#define ACS_MSRMNT_DELAY 1000 /* dump_obss delay in ms */ -#define IOCTL_RETRY_COUNT 5 -#define CHAN_NOISE_DUMMY -80 -#define OBSS_TOKEN_IDX 15 -#define IBSS_TOKEN_IDX 15 -#define TX_TOKEN_IDX 14 -#define CTG_TOKEN_IDX 13 -#define PKT_TOKEN_IDX 15 -#define IDLE_TOKEN_IDX 12 -#endif /* WL_SUPPORT_ACS */ - -extern int wl_cfg80211_get_ioctl_version(void); -extern int wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable); - - -#ifdef WL_CFG80211_P2P_DEV_IF -extern void wl_cfg80211_del_p2p_wdev(void); -#endif /* WL_CFG80211_P2P_DEV_IF */ - -#define RETURN_EIO_IF_NOT_UP(wlpriv) \ -do { \ - struct net_device *checkSysUpNDev = bcmcfg_to_prmry_ndev(wlpriv); \ - if (unlikely(!wl_get_drv_status(wlpriv, READY, checkSysUpNDev))) { \ - WL_INFORM(("device is not ready\n")); \ - return -EIO; \ - } \ -} while (0) - -#endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c deleted file mode 100644 index 468d3f3ba13e..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg_btcoex.c 637933 2016-05-16 08:21:50Z $ - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef PKT_FILTER_SUPPORT -extern uint dhd_pkt_filter_enable; -extern uint dhd_master_mode; -extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -#endif - -struct btcoex_info { - struct timer_list timer; - u32 timer_ms; - u32 timer_on; - u32 ts_dhcp_start; /* ms ts ecord time stats */ - u32 ts_dhcp_ok; /* ms ts ecord time stats */ - bool dhcp_done; /* flag, indicates that host done with - * dhcp before t1/t2 expiration - */ - s32 bt_state; - struct work_struct work; - struct net_device *dev; -}; - -static struct btcoex_info *btcoex_info_loc = NULL; - -/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ - -/* use New SCO/eSCO smart YG suppression */ -#define BT_DHCP_eSCO_FIX -/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ -#define BT_DHCP_USE_FLAGS -/* T1 start SCO/ESCo priority suppression */ -#define BT_DHCP_OPPR_WIN_TIME 2500 -/* T2 turn off SCO/SCO supperesion is (timeout) */ -#define BT_DHCP_FLAG_FORCE_TIME 5500 - -enum wl_cfg80211_btcoex_status { - BT_DHCP_IDLE, - BT_DHCP_START, - BT_DHCP_OPPR_WIN, - BT_DHCP_FLAG_FORCE_TIMEOUT -}; - -/* - * get named driver variable to uint register value and return error indication - * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) - */ -static int -dev_wlc_intvar_get_reg(struct net_device *dev, char *name, - uint reg, int *retval) -{ - union { - char buf[WLC_IOCTL_SMLEN]; - int val; - } var; - int error; - - bcm_mkiovar(name, (char *)(®), sizeof(reg), - (char *)(&var), sizeof(var.buf)); - error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); - - *retval = dtoh32(var.val); - return (error); -} - -static int -dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) -{ - char ioctlbuf_local[WLC_IOCTL_SMLEN]; - - bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); - - return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); -} -/* -get named driver variable to uint register value and return error indication -calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) -*/ -static int -dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) -{ - char reg_addr[8]; - - memset(reg_addr, 0, sizeof(reg_addr)); - memcpy((char *)®_addr[0], (char *)addr, 4); - memcpy((char *)®_addr[4], (char *)val, 4); - - return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); -} - -static bool btcoex_is_sco_active(struct net_device *dev) -{ - int ioc_res = 0; - bool res = FALSE; - int sco_id_cnt = 0; - int param27; - int i; - - for (i = 0; i < 12; i++) { - - ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); - - WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27)); - - if (ioc_res < 0) { - WL_ERR(("ioc read btc params error\n")); - break; - } - - if ((param27 & 0x6) == 2) { /* count both sco & esco */ - sco_id_cnt++; - } - - if (sco_id_cnt > 2) { - WL_TRACE(("sco/esco detected, pkt id_cnt:%d samples:%d\n", - sco_id_cnt, i)); - res = TRUE; - break; - } - - OSL_SLEEP(5); - } - - return res; -} - -#if defined(BT_DHCP_eSCO_FIX) -/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ -static int set_btc_esco_params(struct net_device *dev, bool trump_sco) -{ - static bool saved_status = FALSE; - - char buf_reg50va_dhcp_on[8] = - { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; - char buf_reg51va_dhcp_on[8] = - { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg64va_dhcp_on[8] = - { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg65va_dhcp_on[8] = - { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg71va_dhcp_on[8] = - { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - uint32 regaddr; - static uint32 saved_reg50; - static uint32 saved_reg51; - static uint32 saved_reg64; - static uint32 saved_reg65; - static uint32 saved_reg71; - - if (trump_sco) { - /* this should reduce eSCO agressive retransmit - * w/o breaking it - */ - - /* 1st save current */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { - saved_status = TRUE; - WL_TRACE(("saved bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - saved_reg50, saved_reg51, - saved_reg64, saved_reg65, saved_reg71)); - } else { - WL_ERR((":%s: save btc_params failed\n", - __FUNCTION__)); - saved_status = FALSE; - return -1; - } - - WL_TRACE(("override with [50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - *(u32 *)(buf_reg50va_dhcp_on+4), - *(u32 *)(buf_reg51va_dhcp_on+4), - *(u32 *)(buf_reg64va_dhcp_on+4), - *(u32 *)(buf_reg65va_dhcp_on+4), - *(u32 *)(buf_reg71va_dhcp_on+4))); - - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg50va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg51va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg64va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg65va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg71va_dhcp_on[0], 8); - - saved_status = TRUE; - } else if (saved_status) { - /* restore previously saved bt params */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - - regaddr = 50; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg50); - regaddr = 51; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg51); - regaddr = 64; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg64); - regaddr = 65; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg65); - regaddr = 71; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg71); - - WL_TRACE(("restore bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - saved_reg50, saved_reg51, saved_reg64, - saved_reg65, saved_reg71)); - - saved_status = FALSE; - } else { - WL_ERR((":%s att to restore not saved BTCOEX params\n", - __FUNCTION__)); - return -1; - } - return 0; -} -#endif /* BT_DHCP_eSCO_FIX */ - -static void -wl_cfg80211_bt_setflag(struct net_device *dev, bool set) -{ -#if defined(BT_DHCP_USE_FLAGS) - char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; -#endif - - -#if defined(BT_DHCP_eSCO_FIX) - /* set = 1, save & turn on 0 - off & restore prev settings */ - set_btc_esco_params(dev, set); -#endif - -#if defined(BT_DHCP_USE_FLAGS) - WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); - if (set == TRUE) - /* Forcing bt_flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_dhcp_on[0], - sizeof(buf_flag7_dhcp_on)); - else - /* Restoring default bt flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], - sizeof(buf_flag7_default)); -#endif -} - -static void wl_cfg80211_bt_timerfunc(ulong data) -{ - struct btcoex_info *bt_local = (struct btcoex_info *)data; - WL_TRACE(("Enter\n")); - bt_local->timer_on = 0; - schedule_work(&bt_local->work); -} - -static void wl_cfg80211_bt_handler(struct work_struct *work) -{ - struct btcoex_info *btcx_inf; - - btcx_inf = container_of(work, struct btcoex_info, work); - - if (btcx_inf->timer_on) { - btcx_inf->timer_on = 0; - del_timer_sync(&btcx_inf->timer); - } - - switch (btcx_inf->bt_state) { - case BT_DHCP_START: - /* DHCP started - * provide OPPORTUNITY window to get DHCP address - */ - WL_TRACE(("bt_dhcp stm: started \n")); - - btcx_inf->bt_state = BT_DHCP_OPPR_WIN; - mod_timer(&btcx_inf->timer, - jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); - btcx_inf->timer_on = 1; - break; - - case BT_DHCP_OPPR_WIN: - if (btcx_inf->dhcp_done) { - WL_TRACE(("DHCP Done before T1 expiration\n")); - goto btc_coex_idle; - } - - /* DHCP is not over yet, start lowering BT priority - * enforce btc_params + flags if necessary - */ - WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); - btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; - mod_timer(&btcx_inf->timer, - jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); - btcx_inf->timer_on = 1; - break; - - case BT_DHCP_FLAG_FORCE_TIMEOUT: - if (btcx_inf->dhcp_done) { - WL_TRACE(("DHCP Done before T2 expiration\n")); - } else { - /* Noo dhcp during T1+T2, restore BT priority */ - WL_TRACE(("DHCP wait interval T2:%d msec expired\n", - BT_DHCP_FLAG_FORCE_TIME)); - } - - /* Restoring default bt priority */ - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); -btc_coex_idle: - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - - default: - WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - } - - net_os_wake_unlock(btcx_inf->dev); -} - -void* wl_cfg80211_btcoex_init(struct net_device *ndev) -{ - struct btcoex_info *btco_inf = NULL; - - btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); - if (!btco_inf) - return NULL; - - btco_inf->bt_state = BT_DHCP_IDLE; - btco_inf->ts_dhcp_start = 0; - btco_inf->ts_dhcp_ok = 0; - /* Set up timer for BT */ - btco_inf->timer_ms = 10; - init_timer(&btco_inf->timer); - btco_inf->timer.data = (ulong)btco_inf; - btco_inf->timer.function = wl_cfg80211_bt_timerfunc; - - btco_inf->dev = ndev; - - INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); - - btcoex_info_loc = btco_inf; - return btco_inf; -} - -void wl_cfg80211_btcoex_deinit() -{ - if (!btcoex_info_loc) - return; - - if (btcoex_info_loc->timer_on) { - btcoex_info_loc->timer_on = 0; - del_timer_sync(&btcoex_info_loc->timer); - } - - cancel_work_sync(&btcoex_info_loc->work); - - kfree(btcoex_info_loc); -} - -int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command) -{ - - struct btcoex_info *btco_inf = btcoex_info_loc; - char powermode_val = 0; - char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; - char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; - char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; - - uint32 regaddr; - static uint32 saved_reg66; - static uint32 saved_reg41; - static uint32 saved_reg68; - static bool saved_status = FALSE; - - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; - - /* Figure out powermode 1 or o command */ - strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); - - if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { - WL_TRACE_HW4(("DHCP session starts\n")); - - -#ifdef PKT_FILTER_SUPPORT - dhd->dhcp_in_progress = 1; - - if (dhd->early_suspended) { - WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n")); - dhd_enable_packet_filter(0, dhd); - } -#endif - - /* Retrieve and saved orig regs value */ - if ((saved_status == FALSE) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { - saved_status = TRUE; - WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); - - /* Disable PM mode during dhpc session */ - - /* Disable PM mode during dhpc session */ - /* Start BT timer only for SCO connection */ - if (btcoex_is_sco_active(dev)) { - /* btc_params 66 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg66va_dhcp_on[0], - sizeof(buf_reg66va_dhcp_on)); - /* btc_params 41 0x33 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg41va_dhcp_on[0], - sizeof(buf_reg41va_dhcp_on)); - /* btc_params 68 0x190 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg68va_dhcp_on[0], - sizeof(buf_reg68va_dhcp_on)); - saved_status = TRUE; - - btco_inf->bt_state = BT_DHCP_START; - btco_inf->timer_on = 1; - mod_timer(&btco_inf->timer, btco_inf->timer.expires); - WL_TRACE(("enable BT DHCP Timer\n")); - } - } - else if (saved_status == TRUE) { - WL_ERR(("was called w/o DHCP OFF. Continue\n")); - } - } - else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { - - - -#ifdef PKT_FILTER_SUPPORT - dhd->dhcp_in_progress = 0; - WL_TRACE_HW4(("DHCP is complete \n")); - - /* Enable packet filtering */ - if (dhd->early_suspended) { - WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); - dhd_enable_packet_filter(1, dhd); - } -#endif /* PKT_FILTER_SUPPORT */ - - /* Restoring PM mode */ - - /* Stop any bt timer because DHCP session is done */ - WL_TRACE(("disable BT DHCP Timer\n")); - if (btco_inf->timer_on) { - btco_inf->timer_on = 0; - del_timer_sync(&btco_inf->timer); - - if (btco_inf->bt_state != BT_DHCP_IDLE) { - /* need to restore original btc flags & extra btc params */ - WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state)); - /* wake up btcoex thread to restore btlags+params */ - schedule_work(&btco_inf->work); - } - } - - /* Restoring btc_flag paramter anyway */ - if (saved_status == TRUE) - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); - - /* Restore original values */ - if (saved_status == TRUE) { - regaddr = 66; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg66); - regaddr = 41; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg41); - regaddr = 68; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg68); - - WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); - } - saved_status = FALSE; - - } - else { - WL_ERR(("Unkwown yet power setting, ignored\n")); - } - - snprintf(command, 3, "OK"); - - return (strlen("OK")); -} diff --git a/drivers/net/wireless/bcmdhd/wl_cfgnan.c b/drivers/net/wireless/bcmdhd/wl_cfgnan.c deleted file mode 100644 index ae2466d8cd74..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_cfgnan.c +++ /dev/null @@ -1,2060 +0,0 @@ -/* - * Neighbor Awareness Networking - * - * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgnan.c 487532 2014-06-26 05:09:36Z $ - */ - -/** - * @file - * @brief - * NAN (Neighbor Awareness Networking) is to provide a low-power mechanism - * that will run in the background to make the devices neighbor aware. NAN - * enables mobile devices to efficiently discover devices and services in - * their proximity. The purpose of NAN is only to discover device and its - * services. Then it is handed over to post NAN discovery and connection - * is established using the actual service data channel (e.g., WLAN - * infrastructure, P2P, IBSS, etc.) - */ - - -#include -#include -#include -#include - -#include -#include -#include - -#ifdef WL_NAN_DEBUG -static u8 g_nan_debug = true; -#else -static u8 g_nan_debug = false; -#endif /* WL_NAN_DEBUG */ - -static nan_cmd_t nan_cmds [] = { - { "NAN_START", wl_cfgnan_start_handler }, - { "NAN_STOP", wl_cfgnan_stop_handler }, - { "NAN_SUPPORT", wl_cfgnan_support_handler }, - { "NAN_STATUS", wl_cfgnan_status_handler }, - { "NAN_PUBLISH", wl_cfgnan_pub_handler }, - { "NAN_SUBSCRIBE", wl_cfgnan_sub_handler }, - { "NAN_CANCEL_PUBLISH", wl_cfgnan_cancel_pub_handler }, - { "NAN_CANCEL_SUBSCRIBE", wl_cfgnan_cancel_sub_handler }, - { "NAN_TRANSMIT", wl_cfgnan_transmit_handler }, - { "NAN_SET_CONFIG", wl_cfgnan_set_config_handler }, - { "NAN_GET_CONFIG", NULL }, - { "NAN_RTT_CONFIG", wl_cfgnan_rtt_config_handler }, - { "NAN_RTT_FIND", wl_cfgnan_rtt_find_handler }, - { "NAN_DEBUG", wl_cfgnan_debug_handler }, -#ifdef NAN_P2P_CONFIG - { "NAN_ADD_CONF", wl_cfgnan_p2p_ie_add_handler }, - { "NAN_ENABLE_CONF", wl_cfgnan_p2p_ie_enable_handler }, - { "NAN_DEL_CONF", wl_cfgnan_p2p_ie_del_handler }, -#endif /* NAN_P2P_CONFIG */ - { NULL, NULL }, -}; - -static nan_config_attr_t nan_config_attrs [] = { - { "ATTR_MASTER", WL_NAN_XTLV_MASTER_PREF }, - { "ATTR_ID", WL_NAN_XTLV_CLUSTER_ID }, - { "ATTR_ADDR", WL_NAN_XTLV_IF_ADDR }, - { "ATTR_ROLE", WL_NAN_XTLV_ROLE }, - { "ATTR_BCN_INT", WL_NAN_XTLV_BCN_INTERVAL }, - { "ATTR_CHAN", WL_NAN_XTLV_MAC_CHANSPEC }, - { "ATTR_TX_RATE", WL_NAN_XTLV_MAC_TXRATE }, - { "ATTR_DW_LEN", WL_NAN_XTLV_DW_LEN }, - { {0}, 0 } -}; - -static char nan_event_str[][NAN_EVENT_STR_MAX_LEN] = { - "NAN-INVALID", - "NAN-STARTED", - "NAN-JOINED", - "NAN-ROLE-CHANGE", - "NAN-SCAN-COMPLETE", - "NAN-SDF-RX", - "NAN-REPLIED", - "NAN-TERMINATED", - "NAN-FOLLOWUP-RX", - "NAN-STATUS-CHANGE", - "NAN-MERGED", - "NAN-STOPPED" - "NAN-INVALID", -#ifdef NAN_P2P_CONFIG - "NAN-P2P-RX", -#endif /* NAN_P2P_CONFIG */ -}; - -static char nan_event_name[][NAN_EVENT_NAME_MAX_LEN] = { - "WL_NAN_EVENT_INVALID", - "WL_NAN_EVENT_START", - "WL_NAN_EVENT_JOIN", - "WL_NAN_EVENT_ROLE", - "WL_NAN_EVENT_SCAN_COMPLETE", - "WL_NAN_EVENT_DISCOVERY_RESULT", - "WL_NAN_EVENT_REPLIED", - "WL_NAN_EVENT_TERMINATED", - "WL_NAN_EVENT_RECEIVE", - "WL_NAN_EVENT_STATUS_CHG", - "WL_NAN_EVENT_MERGE", - "WL_NAN_EVENT_STOP", -#ifdef NAN_P2P_CONFIG - "WL_NAN_EVENT_P2P", -#endif /* NAN_P2P_CONFIG */ - "WL_NAN_EVENT_INVALID" -}; - -int -wl_cfgnan_set_vars_cbfn(void *ctx, void **tlv_buf, uint16 type, uint16 len) -{ - wl_nan_tlv_data_t *ndata = ((wl_nan_tlv_data_t *)(ctx)); - bcm_xtlv_t *ptlv; - struct ether_addr mac; - int ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint8 uv8; - char buf[64]; - - WL_DBG((" enter, xtlv_type: 0x%x \n", type)); - - switch (type) { - case WL_NAN_XTLV_ENABLE: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_ENABLE, - sizeof(uv8), &ndata->enabled); - break; - case WL_NAN_XTLV_MASTER_PREF: - /* - * master role and preference mac has them as two u8's, - * - * masterpref: val & 0x0ff - * rnd_factor: val >> 8 - */ - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MASTER_PREF, - sizeof(uint16), &ndata->master_pref); - break; - case WL_NAN_XTLV_IF_ADDR: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_IF_ADDR, - ETHER_ADDR_LEN, &mac); - memcpy(&ndata->mac_addr, &mac, ETHER_ADDR_LEN); - break; - case WL_NAN_XTLV_CLUSTER_ID: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_CLUSTER_ID, - ETHER_ADDR_LEN, &mac); - memcpy(&ndata->clus_id, &mac, ETHER_ADDR_LEN); - break; - case WL_NAN_XTLV_ROLE: - /* nan device role, master, master-sync nosync etc */ - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_ROLE, 4, - &ndata->dev_role); - break; - case WL_NAN_XTLV_MAC_CHANSPEC: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_CHANSPEC, - sizeof(chanspec_t), &ndata->chanspec); - if (wf_chspec_valid(ndata->chanspec)) { - wf_chspec_ntoa(ndata->chanspec, buf); - WL_DBG((" chanspec: %s 0x%x \n", buf, ndata->chanspec)); - } else { - WL_DBG((" chanspec: 0x%x is not valid \n", ndata->chanspec)); - } - break; - case WL_NAN_XTLV_MAC_AMR: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_AMR, - NAN_MASTER_RANK_LEN, buf); - memcpy(ndata->amr, buf, NAN_MASTER_RANK_LEN); - break; - case WL_NAN_XTLV_MAC_AMBTT: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_AMBTT, - sizeof(uint32), &ndata->ambtt); - break; - case WL_NAN_XTLV_MAC_HOPCNT: - ret = bcm_unpack_xtlv_entry(tlv_buf, - WL_NAN_XTLV_MAC_HOPCNT, sizeof(uint8), &ndata->hop_count); - break; - case WL_NAN_XTLV_INSTANCE_ID: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_INSTANCE_ID, - sizeof(wl_nan_instance_id_t), &ndata->inst_id); - break; - case WL_NAN_XTLV_SVC_NAME: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_SVC_NAME, - WL_NAN_SVC_HASH_LEN, ndata->svc_name); - break; - case WL_NAN_XTLV_SVC_PARAMS: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_SVC_PARAMS, - sizeof(wl_nan_disc_params_t), &ndata->params); - break; - case WL_NAN_XTLV_MAC_STATUS: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_STATUS, - sizeof(wl_nan_status_t), &ndata->nstatus); - break; - case WL_NAN_XTLV_PUBLR_ID: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_PUBLR_ID, - sizeof(uint8), &ndata->pub_id); - break; - case WL_NAN_XTLV_SUBSCR_ID: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_SUBSCR_ID, - sizeof(uint8), &ndata->sub_id); - break; - case WL_NAN_XTLV_MAC_ADDR: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_ADDR, - ETHER_ADDR_LEN, &mac); - memcpy(&ndata->mac_addr, &mac, ETHER_ADDR_LEN); - break; - case WL_NAN_XTLV_VNDR: - ptlv = *tlv_buf; - ndata->vend_info.dlen = BCM_XTLV_LEN(ptlv); - ndata->vend_info.data = kzalloc(ndata->vend_info.dlen, kflags); - if (!ndata->vend_info.data) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - if (ndata->vend_info.data && ndata->vend_info.dlen) { - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_VNDR, - ndata->vend_info.dlen, ndata->vend_info.data); - } - break; - case WL_NAN_XTLV_SVC_INFO: - ptlv = *tlv_buf; - ndata->svc_info.dlen = BCM_XTLV_LEN(ptlv); - ndata->svc_info.data = kzalloc(ndata->svc_info.dlen, kflags); - if (!ndata->svc_info.data) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - if (ndata->svc_info.data && ndata->svc_info.dlen) { - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_SVC_INFO, - ndata->svc_info.dlen, ndata->svc_info.data); - } - break; - case WL_NAN_XTLV_PEER_INSTANCE_ID: - ret = bcm_unpack_xtlv_entry(tlv_buf, - WL_NAN_XTLV_PEER_INSTANCE_ID, sizeof(wl_nan_instance_id_t), - &ndata->peer_inst_id); - break; - case WL_NAN_XTLV_NAN_SCANPARAMS: - ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_NAN_SCANPARAMS, - sizeof(nan_scan_params_t), &ndata->scan_params); - break; - case WL_NAN_XTLV_ZERO: - /* don't parse empty space in the buffer */ - ret = BCME_ERROR; - break; - - default: - /* skip current tlv, if we don't have a handler */ - ret = bcm_skip_xtlv(tlv_buf); - break; - } - -fail: - return ret; -} - -int -wl_cfgnan_enable_events(struct net_device *ndev, struct bcm_cfg80211 *cfg) -{ - wl_nan_ioc_t *nanioc = NULL; - void *pxtlv; - u32 event_mask = 0; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - ret = wl_add_remove_eventmsg(ndev, WLC_E_NAN, true); - if (unlikely(ret)) { - WL_ERR((" nan event enable failed, error = %d \n", ret)); - goto fail; - } - if (g_nan_debug) { - /* enable all nan events */ - event_mask = NAN_EVENT_MASK_ALL; - } else { - /* enable only selected nan events to avoid unnecessary host wake up */ - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_START); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_JOIN); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_DISCOVERY_RESULT); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_RECEIVE); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_TERMINATED); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_STOP); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_CLEAR_BIT); -#ifdef NAN_P2P_CONFIG - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_P2P); -#endif /* NAN_P2P_CONFIG */ - event_mask = htod32(event_mask); - } - - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_EVENT_MASK); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_EVENT_MASK, - sizeof(uint32), &event_mask); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan event selective enable failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan event selective enable successful \n")); - } - - ret = wl_add_remove_eventmsg(ndev, WLC_E_PROXD, true); - if (unlikely(ret)) { - WL_ERR((" proxd event enable failed, error = %d \n", ret)); - goto fail; - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_enable_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - void *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - uint8 val; - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan 1 - * - * wpa_cli: DRIVER NAN_ENABLE - */ - - /* nan enable */ - val = 1; - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_ENABLE); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE, - sizeof(uint8), &val); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan enable failed, error = %d \n", ret)); - goto fail; - } else { - cfg->nan_enable = true; - WL_DBG((" nan enable successful \n")); - } - - /* enable nan events */ - ret = wl_cfgnan_enable_events(ndev, cfg); - if (unlikely(ret)) { - goto fail; - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_start_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - struct ether_addr cluster_id = ether_null; - void *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - uint8 val; - - if (cfg->nan_enable != true) { - ret = wl_cfgnan_enable_handler(ndev, cfg, cmd, cmd_data); - if (unlikely(ret)) { - goto fail; - } - } - - /* - * command to test - * - * wl: wl nan join -start - * - * wpa_cli: DRIVER NAN_START - */ - - /* nan join */ - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - val = 1; - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_NAN_JOIN); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, - ETHER_ADDR_LEN, &cluster_id); - if (unlikely(ret)) { - goto fail; - } - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_START, - sizeof(uint8), &val); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan join failed, error = %d \n", ret)); - goto fail; - } - - WL_DBG((" nan join successful \n")); - cfg->nan_running = true; - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_stop_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - struct ether_addr cluster_id = ether_null; - void *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - uint8 nan_enable = FALSE; - - /* - * command to test - * - * wl: wl nan stop - * wl nan 0 - * - * wpa_cli: DRIVER NAN_STOP - */ - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - if (cfg->nan_running == true) { - /* nan stop */ - - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_STOP); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, - ETHER_ADDR_LEN, &cluster_id); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan stop failed, error = %d \n", ret)); - goto fail; - } else { - cfg->nan_running = false; - WL_DBG((" nan stop successful \n")); - } - } - - /* nan disable */ - if (cfg->nan_enable == true) { - memset(nanioc, 0, nanioc_size); - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_ENABLE); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE, - sizeof(uint8), &nan_enable); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan disable failed, error = %d \n", ret)); - goto fail; - } else { - cfg->nan_enable = false; - WL_DBG((" nan disable successful \n")); - } - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_support_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - void *pxtlv; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan - * - * wpa_cli: DRIVER NAN_SUPPORT - */ - - /* nan support */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_ENABLE); - pxtlv = nanioc->data; - nanioc->len = htod16(BCM_XTLV_HDR_SIZE + 1); - nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); - ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); - if (unlikely(ret)) { - WL_ERR((" nan is not supported, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan is supported \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_status_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - wl_nan_ioc_t *ioc_ret = NULL; - void *pxtlv; - char *ptr = cmd; - wl_nan_tlv_data_t tlv_data; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan status - * - * wpa_cli: DRIVER NAN_STATUS - */ - - /* nan status */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_STATUS); - pxtlv = nanioc->data; - nanioc->len = NAN_IOCTL_BUF_SIZE; - nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); - ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan status failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan status successful \n")); - } - - /* unpack the tlvs */ - memset(&tlv_data, 0, sizeof(tlv_data)); - ioc_ret = (wl_nan_ioc_t *)cfg->ioctl_buf; - if (g_nan_debug) { - prhex(" nanioc->data: ", (uint8 *)ioc_ret->data, ioc_ret->len); - } - bcm_unpack_xtlv_buf(&tlv_data, ioc_ret->data, ioc_ret->len, - wl_cfgnan_set_vars_cbfn); - - ptr += sprintf(ptr, ROLE_PREFIX"%d", tlv_data.dev_role); - ptr += sprintf(ptr, " " AMR_PREFIX); - ptr += bcm_format_hex(ptr, tlv_data.amr, NAN_MASTER_RANK_LEN); - ptr += sprintf(ptr, " " CLUS_ID_PREFIX MACF, ETHER_TO_MACF(tlv_data.clus_id)); - ptr += sprintf(ptr, " " AMBTT_PREFIX"0x%x", tlv_data.ambtt); - ptr += sprintf(ptr, " " HOP_COUNT_PREFIX"%d", tlv_data.hop_count); - - /* nan scan param */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_SCAN_PARAMS); - pxtlv = nanioc->data; - nanioc->len = NAN_IOCTL_BUF_SIZE; - nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); - ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan scan params failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan scan params successful \n")); - } - - /* unpack the tlvs */ - memset(&tlv_data, 0, sizeof(tlv_data)); - ioc_ret = (wl_nan_ioc_t *)cfg->ioctl_buf; - ASSERT(ioc_ret != NULL); - if (g_nan_debug) { - prhex(" nanioc->data: ", (uint8 *)ioc_ret->data, ioc_ret->len); - } - bcm_unpack_xtlv_buf(&tlv_data, ioc_ret->data, ioc_ret->len, - wl_cfgnan_set_vars_cbfn); - - ptr += sprintf(ptr, " " SCAN_PERIOD_PREFIX"%d", - tlv_data.scan_params.ms_dur); - ptr += sprintf(ptr, " " SCAN_INTERVAL_PREFIX"%d", - tlv_data.scan_params.ms_intvl*512); - - WL_DBG((" formatted string for userspace: %s, len: %zu \n", - cmd, strlen(cmd))); - -fail: - if (nanioc) { - kfree(nanioc); - } - if (tlv_data.svc_info.data) { - kfree(tlv_data.svc_info.data); - tlv_data.svc_info.data = NULL; - tlv_data.svc_info.dlen = 0; - } - if (tlv_data.vend_info.data) { - kfree(tlv_data.vend_info.data); - tlv_data.vend_info.data = NULL; - tlv_data.vend_info.dlen = 0; - } - - return ret; -} - - -#ifdef NAN_P2P_CONFIG - -static void -wl_p2p_nan_ioctl_make_header(wl_p2p_nan_ioc_t *p2p_nanioc, uint16 cmd_id, uint16 len) -{ - p2p_nanioc->version = htod16(WL_P2P_NAN_IOCTL_VERSION); - p2p_nanioc->id = cmd_id; - p2p_nanioc->len = htod16(len); -} - -static int -wl_p2p_nan_do_get_ioctl(struct net_device *ndev, struct bcm_cfg80211 *cfg, - wl_p2p_nan_ioc_t *p2p_nanioc, uint16 alloc_size) -{ - wl_p2p_nan_ioc_t *iocresp = NULL; - int res; - uint8 *val; - /* send getbuf p2p nan iovar */ - res = wldev_iovar_getbuf(ndev, "p2p_nan", p2p_nanioc, alloc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - - if (res == BCME_OK) { - iocresp = (wl_p2p_nan_ioc_t *)cfg->ioctl_buf; - if (iocresp == NULL) { - res = BCME_ERROR; - return res; - } - switch (iocresp->id) { - case WL_P2P_NAN_CMD_ENABLE: - val = iocresp->data; - WL_ERR(("wl p2p_nan status is %s\n", - *val == 1? "Enabled":"Disabled")); - break; - case WL_P2P_NAN_CMD_CONFIG: { - wl_p2p_nan_config_t *p_p2p_nan_cfg = - (wl_p2p_nan_config_t *)iocresp->data; - WL_ERR(("wl p2p nan ie len = %u\n", p_p2p_nan_cfg->ie_len)); - prhex("P2P IE", p_p2p_nan_cfg->ie, p_p2p_nan_cfg->ie_len); - } - break; - default: - WL_ERR(("Unknown command %d\n", iocresp->id)); - break; - } - } - return res; -} - - -int wl_cfgnan_p2p_ie_enable_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char* buf, nan_cmd_data_t *cmd_data) { - int res = BCME_OK; - wl_p2p_nan_ioc_t *p2p_nanioc; - uint16 alloc_size = OFFSETOF(wl_p2p_nan_ioc_t, data) + P2P_NAN_IOC_BUFSZ; - void *pdata = NULL; - uint8 val; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - p2p_nanioc = kzalloc(alloc_size, kflags); - if (p2p_nanioc == NULL) { - WL_ERR((" memory allocation failed \n")); - return BCME_NOMEM; - } - - wl_p2p_nan_ioctl_make_header(p2p_nanioc, WL_P2P_NAN_CMD_ENABLE, sizeof(uint8)); - - if (cmd_data->p2p_info.data == NULL) { /* get */ - res = wl_p2p_nan_do_get_ioctl(ndev, cfg, p2p_nanioc, alloc_size); - } else { /* set */ - - val = (uint8) cmd_data->p2p_info.data[0]; - pdata = p2p_nanioc->data; - memcpy(pdata, &val, sizeof(uint8)); - res = wldev_iovar_setbuf(ndev, "p2p_nan", p2p_nanioc, - alloc_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - } - - kfree(p2p_nanioc); - return res; -} -int wl_cfgnan_p2p_ie_add_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) { - int res = BCME_OK; - int ie_len, data_len; - wl_p2p_nan_ioc_t *p2p_nanioc; - uint16 alloc_size = OFFSETOF(wl_p2p_nan_ioc_t, data) + cmd_data->p2p_info.dlen; - wl_p2p_nan_config_t *p_p2p_nan_cfg; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - p2p_nanioc = kzalloc(alloc_size, kflags); - if (p2p_nanioc == NULL) - return BCME_NOMEM; - cmd_data->p2p_info.dlen /= 2; /* Number of hex values will be half of ascii */ - wl_p2p_nan_ioctl_make_header(p2p_nanioc, WL_P2P_NAN_CMD_CONFIG, P2P_NAN_IOC_BUFSZ); - - if (cmd_data->p2p_info.data == NULL) { /* get */ - wl_p2p_nan_do_get_ioctl(ndev, cfg, p2p_nanioc, alloc_size); - } else { - ie_len = cmd_data->p2p_info.dlen; - data_len = OFFSETOF(wl_p2p_nan_config_t, ie) + ie_len; - - p_p2p_nan_cfg = (wl_p2p_nan_config_t *)p2p_nanioc->data; - p_p2p_nan_cfg->version = WL_P2P_NAN_CONFIG_VERSION; - p_p2p_nan_cfg->len = data_len; - p_p2p_nan_cfg->ie_len = ie_len; - - if (!wl_cfg80211_hex_str_to_bin - (p_p2p_nan_cfg->ie, (int)p_p2p_nan_cfg->ie_len, (uchar*)cmd_data->p2p_info.data)) { - res = BCME_BADARG; - goto fail; - } - p2p_nanioc->len = htod16(data_len); - - res = wldev_iovar_setbuf(ndev, "p2p_nan", p2p_nanioc, alloc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - } -fail: - kfree(p2p_nanioc); - return res; -} -int wl_cfgnan_p2p_ie_del_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - int res = BCME_OK; - wl_p2p_nan_ioc_t *p2p_nanioc; - uint16 alloc_size = OFFSETOF(wl_p2p_nan_ioc_t, data); - - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - p2p_nanioc = kzalloc(alloc_size, kflags); - if (p2p_nanioc == NULL) { - WL_ERR((" Memory is not enough\n")); - return BCME_NOMEM; - } - wl_p2p_nan_ioctl_make_header(p2p_nanioc, WL_P2P_NAN_CMD_DEL_CONFIG, 0); - res = wldev_iovar_setbuf(ndev, "p2p_nan", p2p_nanioc, alloc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - return res; -} - -#endif /* NAN_P2P_CONFIG */ - -int -wl_cfgnan_pub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - struct bcm_tlvbuf *tbuf = NULL; - wl_nan_disc_params_t params; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 tbuf_size = BCM_XTLV_HDR_SIZE + sizeof(params); - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - void *pxtlv; - u16 start, end; - - /* - * proceed only if mandatory arguments are present - publisher id, - * service hash - */ - if ((!cmd_data->pub_id) || (!cmd_data->svc_hash.data) || - (!cmd_data->svc_hash.dlen)) { - WL_ERR((" mandatory arguments are not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - tbuf = bcm_xtlv_buf_alloc(NULL, tbuf_size); - if (!tbuf) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - - /* - * command to test - * - * wl: wl nan publish 10 NAN123 -info - * DRIVER NAN_PUBLISH PUB_ID=10 SVC_HASH=NAN123 - * SVC_INFO= PUB_PR=1 PUB_INT=0xffffffff - */ - - /* nan publish */ - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_PUBLISH); - pxtlv = nanioc->data; - - /* disovery parameters */ - if (cmd_data->pub_pr) { - params.period = cmd_data->pub_pr; - } else { - params.period = 1; - } - if (cmd_data->pub_int) { - params.ttl = cmd_data->pub_int; - } else { - params.ttl = WL_NAN_TTL_UNTIL_CANCEL; - } - params.flags = 0; - if (cmd_data->flags & WL_NAN_PUB_UNSOLICIT) { - params.flags |= WL_NAN_PUB_UNSOLICIT; - WL_DBG((" nan publish type - unsolicited\n")); - } - if (cmd_data->flags & WL_NAN_PUB_SOLICIT) { - params.flags |= WL_NAN_PUB_SOLICIT; - WL_DBG((" nan publish type - solicited\n")); - } - if (!params.flags) { - params.flags = WL_NAN_PUB_BOTH; /* default. */ - } - params.instance_id = (wl_nan_instance_id_t)cmd_data->pub_id; - memcpy((char *)params.svc_hash, cmd_data->svc_hash.data, - cmd_data->svc_hash.dlen); - ret = bcm_pack_xtlv_entry(&pxtlv, - &end, WL_NAN_XTLV_SVC_PARAMS, sizeof(wl_nan_disc_params_t), ¶ms); - if (unlikely(ret)) { - goto fail; - } - if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { - WL_DBG((" optional svc_info present, pack it \n")); - ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv, - &end, WL_NAN_XTLV_SVC_INFO, cmd_data->svc_info.data); - if (unlikely(ret)) { - goto fail; - } - } - - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan publish failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan publish successful \n")); - } - -fail: - if (tbuf) { - bcm_xtlv_buf_free(NULL, tbuf); - } - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_sub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - struct bcm_tlvbuf *tbuf = NULL; - wl_nan_disc_params_t params; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - /* - * proceed only if mandatory arguments are present - subscriber id, - * service hash - */ - if ((!cmd_data->sub_id) || (!cmd_data->svc_hash.data) || - (!cmd_data->svc_hash.dlen)) { - WL_ERR((" mandatory arguments are not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - tbuf = bcm_xtlv_buf_alloc(NULL, BCM_XTLV_HDR_SIZE + sizeof(params)); - if (!tbuf) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - - /* - * command to test - * - * wl: wl nan subscribe 10 NAN123 - * - * wpa_cli: DRIVER NAN_SUBSCRIBE SUB_ID=10 SVC_HASH=NAN123 - */ - - /* nan subscribe */ - params.period = 1; - params.ttl = WL_NAN_TTL_UNTIL_CANCEL; - params.flags = 0; - if (cmd_data->flags & WL_NAN_SUB_ACTIVE) { - params.flags = WL_NAN_SUB_ACTIVE; - WL_DBG((" nan subscribe type - Active\n")); - } - params.instance_id = (wl_nan_instance_id_t)cmd_data->sub_id; - memcpy((char *)params.svc_hash, cmd_data->svc_hash.data, - cmd_data->svc_hash.dlen); - bcm_xtlv_put_data(tbuf, WL_NAN_XTLV_SVC_PARAMS, ¶ms, sizeof(params)); - - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_SUBSCRIBE); - nanioc->len = htod16(bcm_xtlv_buf_len(tbuf)); - bcopy(bcm_xtlv_head(tbuf), nanioc->data, bcm_xtlv_buf_len(tbuf)); - nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(tbuf); - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan subscribe failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan subscribe successful \n")); - } - -fail: - if (tbuf) { - bcm_xtlv_buf_free(NULL, tbuf); - } - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_cancel_pub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - struct bcm_tlvbuf *tbuf = NULL; - wl_nan_disc_params_t params; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - /* proceed only if mandatory argument is present - publisher id */ - if (!cmd_data->pub_id) { - WL_ERR((" mandatory argument is not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - tbuf = bcm_xtlv_buf_alloc(NULL, BCM_XTLV_HDR_SIZE + sizeof(params)); - if (!tbuf) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - - /* - * command to test - * - * wl: wl nan cancel_publish 10 - * - * wpa_cli: DRIVER NAN_CANCEL_PUBLISH PUB_ID=10 - */ - - bcm_xtlv_put_data(tbuf, WL_NAN_XTLV_INSTANCE_ID, &cmd_data->pub_id, - sizeof(wl_nan_instance_id_t)); - - /* nan cancel publish */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_CANCEL_PUBLISH); - nanioc->len = htod16(bcm_xtlv_buf_len(tbuf)); - bcopy(bcm_xtlv_head(tbuf), nanioc->data, bcm_xtlv_buf_len(tbuf)); - nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(tbuf); - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan cancel publish failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan cancel publish successful \n")); - } - -fail: - if (tbuf) { - bcm_xtlv_buf_free(NULL, tbuf); - } - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_cancel_sub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - struct bcm_tlvbuf *tbuf = NULL; - wl_nan_disc_params_t params; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - /* proceed only if mandatory argument is present - subscriber id */ - if (!cmd_data->sub_id) { - WL_ERR((" mandatory argument is not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - tbuf = bcm_xtlv_buf_alloc(NULL, BCM_XTLV_HDR_SIZE + sizeof(params)); - if (!tbuf) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - - /* - * command to test - * - * wl: wl nan cancel_subscribe 10 - * - * wpa_cli: DRIVER NAN_CANCEL_SUBSCRIBE PUB_ID=10 - */ - - bcm_xtlv_put_data(tbuf, WL_NAN_XTLV_INSTANCE_ID, &cmd_data->sub_id, - sizeof(wl_nan_instance_id_t)); - - /* nan cancel subscribe */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_CANCEL_SUBSCRIBE); - nanioc->len = htod16(bcm_xtlv_buf_len(tbuf)); - bcopy(bcm_xtlv_head(tbuf), nanioc->data, bcm_xtlv_buf_len(tbuf)); - nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(tbuf); - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan cancel subscribe failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan cancel subscribe successful \n")); - } - -fail: - if (tbuf) { - bcm_xtlv_buf_free(NULL, tbuf); - } - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_transmit_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - void *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - /* - * proceed only if mandatory arguments are present - subscriber id, - * publisher id, mac address - */ - if ((!cmd_data->local_id) || (!cmd_data->remote_id) || - ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) { - WL_ERR((" mandatory arguments are not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan trasnmit -info - * - * wpa_cli: DRIVER NAN_TRANSMIT SUB_ID= PUB_ID= - * MAC_ADDR= SVC_INFO= - */ - - /* nan transmit */ - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_TRANSMIT); - pxtlv = nanioc->data; - - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_INSTANCE_ID, - sizeof(wl_nan_instance_id_t), &cmd_data->local_id); - if (unlikely(ret)) { - goto fail; - } - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_REQUESTOR_ID, - sizeof(wl_nan_instance_id_t), &cmd_data->remote_id); - if (unlikely(ret)) { - goto fail; - } - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_ADDR, - ETHER_ADDR_LEN, &cmd_data->mac_addr.octet); - if (unlikely(ret)) { - goto fail; - } - if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { - WL_DBG((" optional svc_info present, pack it \n")); - ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv, - &end, WL_NAN_XTLV_SVC_INFO, cmd_data->svc_info.data); - if (unlikely(ret)) { - goto fail; - } - } - - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan transmit failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan transmit successful \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_set_config_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - void *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - if (cfg->nan_running == true) { - WL_ERR((" Stop nan (NAN_STOP) before issuing NAN_CONFIG command\n")); - return BCME_ERROR; - } - - if (cfg->nan_enable != true) { - ret = wl_cfgnan_enable_handler(ndev, cfg, cmd, cmd_data); - if (unlikely(ret)) { - goto fail; - } - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan (wl nan role 1) - * - * wpa_cli: DRIVER NAN_CONFIG_SET ATTR= ... - * - * wpa_cli: DRIVER NAN_SET_CONFIG ATTR=ATTR_ROLE ROLE=1 - */ - - /* nan set config */ - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_ATTR); - pxtlv = nanioc->data; - - switch (cmd_data->attr.type) { - case WL_NAN_XTLV_ROLE: - WL_DBG((" set nan ROLE = %#x\n", cmd_data->role)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ROLE, - sizeof(u32), &cmd_data->role); - break; - case WL_NAN_XTLV_MASTER_PREF: - WL_DBG((" set nan MASTER PREF = %#x\n", cmd_data->master_pref)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MASTER_PREF, - sizeof(u16), &cmd_data->master_pref); - break; - case WL_NAN_XTLV_DW_LEN: - WL_DBG((" set nan DW LEN = %#x\n", cmd_data->dw_len)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_DW_LEN, - sizeof(u16), &cmd_data->dw_len); - break; - case WL_NAN_XTLV_CLUSTER_ID: - WL_DBG((" set nan CLUSTER ID ")); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, - sizeof(cmd_data->clus_id), &cmd_data->clus_id); - break; - case WL_NAN_XTLV_IF_ADDR: - WL_DBG((" set nan IFADDR ")); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_IF_ADDR, - sizeof(cmd_data->if_addr), &cmd_data->if_addr); - break; - case WL_NAN_XTLV_MAC_CHANSPEC: - WL_DBG((" set nan CHANSPEC = %#x\n", cmd_data->chanspec)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_CHANSPEC, - sizeof(cmd_data->chanspec), &cmd_data->chanspec); - break; - case WL_NAN_XTLV_BCN_INTERVAL: - WL_DBG((" set nan BCN_INTERVAL = %#x\n", cmd_data->beacon_int)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_BCN_INTERVAL, - sizeof(cmd_data->beacon_int), &cmd_data->beacon_int); - break; - case WL_NAN_XTLV_MAC_TXRATE: - default: - ret = -EINVAL; - break; - } - if (unlikely(ret)) { - WL_ERR((" unsupported attribute, attr = %s (%d) \n", - cmd_data->attr.name, cmd_data->attr.type)); - goto fail; - } - - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan set config failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan set config successful \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_rtt_config_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ranging_config_t rtt_config; - s32 ret = BCME_OK; - - /* proceed only if mandatory argument is present - channel */ - if (!cmd_data->chanspec) { - WL_ERR((" mandatory argument is not present \n")); - return -EINVAL; - } - - /* - * command to test - * - * wl: wl proxd_nancfg 44/80 128 32 ff:ff:ff:ff:ff:ff 1 - * - * wpa_cli: DRIVER NAN_RTT_CONFIG CHAN=44/80 - */ - - memset(&rtt_config, 0, sizeof(wl_nan_ranging_config_t)); - rtt_config.chanspec = cmd_data->chanspec; - rtt_config.timeslot = 128; - rtt_config.duration = 32; - memcpy(&rtt_config.allow_mac, ðer_bcast, ETHER_ADDR_LEN); - rtt_config.flags = 1; - - ret = wldev_iovar_setbuf(ndev, "proxd_nancfg", &rtt_config, - sizeof(wl_nan_ranging_config_t), cfg->ioctl_buf, - WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan rtt config failed, error = %d \n", ret)); - } else { - WL_DBG((" nan rtt config successful \n")); - } - - return ret; -} - -int -wl_cfgnan_rtt_find_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - void *iovbuf; - wl_nan_ranging_list_t *rtt_list; - s32 iovbuf_size = NAN_RTT_IOVAR_BUF_SIZE; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - /* - * proceed only if mandatory arguments are present - channel, bitmap, - * mac address - */ - if ((!cmd_data->chanspec) || (!cmd_data->bmap) || - ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) { - WL_ERR((" mandatory arguments are not present \n")); - return -EINVAL; - } - - iovbuf = kzalloc(iovbuf_size, kflags); - if (!iovbuf) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl proxd_nanfind 1 44/80 0x300 5 6 1 - * - * wpa_cli: DRIVER NAN_RTT_FIND MAC_ADDR= CHAN=44/80 BMAP=0x300 - * - */ - rtt_list = (wl_nan_ranging_list_t *)iovbuf; - rtt_list->count = 1; - rtt_list->num_peers_done = 0; - rtt_list->num_dws = 1; - rtt_list->rp[0].chanspec = cmd_data->chanspec; - memcpy(&rtt_list->rp[0].ea, &cmd_data->mac_addr, - sizeof(struct ether_addr)); - rtt_list->rp[0].abitmap = cmd_data->bmap; - rtt_list->rp[0].frmcnt = 5; - rtt_list->rp[0].retrycnt = 6; - rtt_list->rp[0].flags = 1; - - iovbuf_size = sizeof(wl_nan_ranging_list_t) + - sizeof(wl_nan_ranging_peer_t); - ret = wldev_iovar_setbuf(ndev, "proxd_nanfind", iovbuf, - iovbuf_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan rtt find failed, error = %d \n", ret)); - } else { - WL_DBG((" nan rtt find successful \n")); - } - - if (iovbuf) { - kfree(iovbuf); - } - - return ret; -} - -int -wl_cfgnan_debug_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - /* - * command to test - * - * wpa_cli: DRIVER NAN_DEBUG DEBUG=1 - * - */ - - g_nan_debug = cmd_data->debug_flag; - - /* reconfigure nan events */ - return wl_cfgnan_enable_events(ndev, cfg); -} - -static int wl_cfgnan_config_attr(char *buf, nan_config_attr_t *attr) -{ - s32 ret = BCME_OK; - nan_config_attr_t *nanc = NULL; - - /* only one attribute at a time */ - for (nanc = &nan_config_attrs[0]; strlen(nanc->name) != 0; nanc++) { - if (!strncmp(nanc->name, buf, strlen(nanc->name))) { - strncpy((char *)attr->name, buf, strlen(nanc->name)); - attr->type = nanc->type; - ret = strlen(nanc->name); - break; - } - } - - return ret; -} - -static int wl_cfgnan_parse_args(char *buf, nan_cmd_data_t *cmd_data) -{ - s32 ret = BCME_OK; - char *token = buf; - char delim[] = " "; - - while ((buf != NULL) && (token != NULL)) { - if (!strncmp(buf, PUB_ID_PREFIX, strlen(PUB_ID_PREFIX))) { - buf += strlen(PUB_ID_PREFIX); - token = strsep(&buf, delim); - cmd_data->pub_id = simple_strtoul(token, NULL, 10); - cmd_data->local_id ? (cmd_data->remote_id = cmd_data->pub_id) : - (cmd_data->local_id = cmd_data->pub_id); - if (NAN_INVALID_ID(cmd_data->pub_id)) { - WL_ERR((" invalid publisher id, pub_id = %d \n", - cmd_data->pub_id)); - ret = -EINVAL; - goto fail; - } -#ifdef NAN_P2P_CONFIG - } else if (!strncmp(buf, P2P_IE_PREFIX, strlen(P2P_IE_PREFIX))) { - buf += strlen(P2P_IE_PREFIX); - token = strsep(&buf, delim); - cmd_data->p2p_info.data = token; - cmd_data->p2p_info.dlen = strlen(token); - } else if (!strncmp(buf, IE_EN_PREFIX, strlen(IE_EN_PREFIX))) { - buf += strlen(IE_EN_PREFIX); - token = strsep(&buf, delim); - cmd_data->p2p_info.data = token; - cmd_data->p2p_info.dlen = strlen(token); -#endif /* NAN_P2P_CONFIG */ - } else if (!strncmp(buf, SUB_ID_PREFIX, strlen(SUB_ID_PREFIX))) { - buf += strlen(SUB_ID_PREFIX); - token = strsep(&buf, delim); - cmd_data->sub_id = simple_strtoul(token, NULL, 10); - cmd_data->local_id ? (cmd_data->remote_id = cmd_data->sub_id) : - (cmd_data->local_id = cmd_data->sub_id); - if (NAN_INVALID_ID(cmd_data->sub_id)) { - WL_ERR((" invalid subscriber id, sub_id = %d \n", - cmd_data->sub_id)); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, MAC_ADDR_PREFIX, strlen(MAC_ADDR_PREFIX))) { - buf += strlen(MAC_ADDR_PREFIX); - token = strsep(&buf, delim); - if (!wl_cfg80211_ether_atoe(token, &cmd_data->mac_addr)) { - WL_ERR((" invalid mac address, mac_addr = "MACDBG "\n", - MAC2STRDBG(cmd_data->mac_addr.octet))); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, SVC_HASH_PREFIX, strlen(SVC_HASH_PREFIX))) { - buf += strlen(SVC_HASH_PREFIX); - token = strsep(&buf, delim); - cmd_data->svc_hash.data = token; - cmd_data->svc_hash.dlen = WL_NAN_SVC_HASH_LEN; - } else if (!strncmp(buf, SVC_INFO_PREFIX, strlen(SVC_INFO_PREFIX))) { - buf += strlen(SVC_INFO_PREFIX); - token = strsep(&buf, delim); - cmd_data->svc_info.data = token; - cmd_data->svc_info.dlen = strlen(token); - } else if (!strncmp(buf, CHAN_PREFIX, strlen(CHAN_PREFIX))) { - buf += strlen(CHAN_PREFIX); - token = strsep(&buf, delim); - cmd_data->chanspec = wf_chspec_aton(token); - cmd_data->chanspec = wl_chspec_host_to_driver(cmd_data->chanspec); - if (NAN_INVALID_CHANSPEC(cmd_data->chanspec)) { - WL_ERR((" invalid chanspec, chanspec = 0x%04x \n", - cmd_data->chanspec)); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, BITMAP_PREFIX, strlen(BITMAP_PREFIX))) { - buf += strlen(BITMAP_PREFIX); - token = strsep(&buf, delim); - cmd_data->bmap = simple_strtoul(token, NULL, 16); - } else if (!strncmp(buf, ATTR_PREFIX, strlen(ATTR_PREFIX))) { - buf += strlen(ATTR_PREFIX); - token = strsep(&buf, delim); - if (!wl_cfgnan_config_attr(token, &cmd_data->attr)) { - WL_ERR((" invalid attribute, attr = %s \n", - cmd_data->attr.name)); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, ROLE_PREFIX, strlen(ROLE_PREFIX))) { - buf += strlen(ROLE_PREFIX); - token = strsep(&buf, delim); - cmd_data->role = simple_strtoul(token, NULL, 10); - if (NAN_INVALID_ROLE(cmd_data->role)) { - WL_ERR((" invalid role, role = %d \n", cmd_data->role)); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, MASTER_PREF_PREFIX, - strlen(MASTER_PREF_PREFIX))) { - buf += strlen(MASTER_PREF_PREFIX); - token = strsep(&buf, delim); - cmd_data->master_pref = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, CLUS_ID_PREFIX, strlen(CLUS_ID_PREFIX))) { - buf += strlen(CLUS_ID_PREFIX); - token = strsep(&buf, delim); - if (!wl_cfg80211_ether_atoe(token, &cmd_data->clus_id)) { - WL_ERR((" invalid cluster id, CLUS_ID = "MACDBG "\n", - MAC2STRDBG(cmd_data->clus_id.octet))); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, IF_ADDR_PREFIX, strlen(IF_ADDR_PREFIX))) { - buf += strlen(IF_ADDR_PREFIX); - token = strsep(&buf, delim); - if (!wl_cfg80211_ether_atoe(token, &cmd_data->if_addr)) { - WL_ERR((" invalid cluster id, IF_ADDR = "MACDBG "\n", - MAC2STRDBG(cmd_data->if_addr.octet))); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, BCN_INTERVAL_PREFIX, - strlen(BCN_INTERVAL_PREFIX))) { - buf += strlen(BCN_INTERVAL_PREFIX); - token = strsep(&buf, delim); - cmd_data->beacon_int = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, PUB_PR_PREFIX, strlen(PUB_PR_PREFIX))) { - buf += strlen(PUB_PR_PREFIX); - token = strsep(&buf, delim); - cmd_data->pub_pr = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, PUB_INT_PREFIX, strlen(PUB_INT_PREFIX))) { - buf += strlen(PUB_INT_PREFIX); - token = strsep(&buf, delim); - cmd_data->pub_int = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, DW_LEN_PREFIX, strlen(DW_LEN_PREFIX))) { - buf += strlen(DW_LEN_PREFIX); - token = strsep(&buf, delim); - cmd_data->dw_len = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, DEBUG_PREFIX, strlen(DEBUG_PREFIX))) { - buf += strlen(DEBUG_PREFIX); - token = strsep(&buf, delim); - cmd_data->debug_flag = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, ACTIVE_OPTION, strlen(ACTIVE_OPTION))) { - buf += strlen(ACTIVE_OPTION); - token = strsep(&buf, delim); - cmd_data->flags |= WL_NAN_SUB_ACTIVE; - } else if (!strncmp(buf, SOLICITED_OPTION, strlen(SOLICITED_OPTION))) { - buf += strlen(SOLICITED_OPTION); - token = strsep(&buf, delim); - cmd_data->flags |= WL_NAN_PUB_SOLICIT; - } else if (!strncmp(buf, UNSOLICITED_OPTION, strlen(UNSOLICITED_OPTION))) { - buf += strlen(UNSOLICITED_OPTION); - token = strsep(&buf, delim); - cmd_data->flags |= WL_NAN_PUB_UNSOLICIT; - } else { - WL_ERR((" unknown token, token = %s, buf = %s \n", token, buf)); - ret = -EINVAL; - goto fail; - } - } - -fail: - return ret; -} - -int -wl_cfgnan_cmd_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, - char *cmd, int cmd_len) -{ - nan_cmd_data_t cmd_data; - u8 *buf = cmd; - u8 *cmd_name = NULL; - nan_cmd_t *nanc = NULL; - int buf_len = 0; - int ret = BCME_OK; - - cmd_name = strsep((char **)&buf, " "); - if (buf) { - buf_len = strlen(buf); - } - - WL_DBG((" cmd_name: %s, buf_len: %d, buf: %s \n", cmd_name, buf_len, buf)); - - memset(&cmd_data, 0, sizeof(nan_cmd_data_t)); - ret = wl_cfgnan_parse_args(buf, &cmd_data); - if (unlikely(ret)) { - WL_ERR((" argument parsing failed with error (%d), buf = %s \n", - ret, buf)); - goto fail; - } - - for (nanc = nan_cmds; nanc->name; nanc++) { - if (strncmp(nanc->name, cmd_name, strlen(nanc->name)) == 0) { - ret = (*nanc->func)(ndev, cfg, cmd, &cmd_data); - if (ret < BCME_OK) { - WL_ERR((" command (%s) failed with error (%d) \n", - cmd_name, ret)); - } - } - } - -fail: - return ret; -} - -s32 -wl_cfgnan_notify_proxd_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data) -{ - s32 ret = BCME_OK; - wl_nan_ranging_event_data_t *rdata; - s32 status; - u16 data_len; - s32 event_type; - s32 event_num; - u8 *buf = NULL; - u32 buf_len; - u8 *ptr; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - s32 i; - - if (!event || !data) { - WL_ERR((" event data is NULL \n")); - return -EINVAL; - } - - status = ntoh32(event->reason); - event_type = ntoh32(event->event_type); - event_num = ntoh32(event->reason); - data_len = ntoh32(event->datalen); - - WL_DBG((" proxd event: type: %d num: %d len: %d \n", - event_type, event_num, data_len)); - - if (NAN_INVALID_PROXD_EVENT(event_num)) { - WL_ERR((" unsupported event, num: %d \n", event_num)); - return -EINVAL; - } - - if (g_nan_debug) { - WL_DBG((" event name: WLC_E_PROXD_NAN_EVENT \n")); - WL_DBG((" event data: \n")); - prhex(NULL, data, data_len); - } - - if (data_len < sizeof(wl_nan_ranging_event_data_t)) { - WL_ERR((" wrong data len \n")); - return -EINVAL; - } - - rdata = (wl_nan_ranging_event_data_t *)data; - - WL_DBG((" proxd event: count:%d success_count:%d mode:%d \n", - rdata->count, rdata->success_count, rdata->mode)); - - if (g_nan_debug) { - prhex(" event data: ", data, data_len); - } - - buf_len = NAN_IOCTL_BUF_SIZE; - buf = kzalloc(buf_len, kflags); - if (!buf) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - for (i = 0; i < rdata->count; i++) { - if (&rdata->rr[i] == NULL) { - ret = -EINVAL; - goto fail; - } - - ptr = buf; - WL_DBG((" ranging data for mac:"MACDBG" \n", - MAC2STRDBG(rdata->rr[i].ea.octet))); - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " MAC_ADDR_PREFIX MACF - " "STATUS_PREFIX"%s", EVENT_RTT_STATUS_STR, - ETHER_TO_MACF(rdata->rr[i].ea), (rdata->rr[i].status == 1) ? - "success" : "fail"); - - if (rdata->rr[i].status == 1) { - /* add tsf and distance only if status is success */ - ptr += sprintf(ptr, " "TIMESTAMP_PREFIX"0x%x " - DISTANCE_PREFIX"%d.%04d", rdata->rr[i].timestamp, - rdata->rr[i].distance >> 4, - ((rdata->rr[i].distance & 0x0f) * 625)); - } - -#ifdef WL_GENL - /* send the preformatted string to the upper layer as event */ - WL_DBG((" formatted string for userspace: %s, len: %zu \n", - buf, strlen(buf))); - wl_genl_send_msg(bcmcfg_to_prmry_ndev(cfg), 0, buf, strlen(buf), 0, 0); -#endif /* WL_GENL */ - } - -fail: - if (buf) { - kfree(buf); - } - - return ret; -} - -s32 -wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data) -{ - s32 ret = BCME_OK; - u16 data_len; - u32 event_num; - s32 event_type; - nan_event_hdr_t nan_hdr; - wl_nan_tlv_data_t tlv_data; - u8 *buf = NULL; - u32 buf_len; - u8 *ptr; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - if (!event || !data) { - WL_ERR((" event data is NULL \n")); - return -EINVAL; - } - - event_type = ntoh32(event->event_type); - event_num = ntoh32(event->reason); - data_len = ntoh32(event->datalen); - memset(&nan_hdr, 0, sizeof(nan_event_hdr_t)); - nan_hdr.event_subtype = event_num; - - WL_DBG((" nan event: type: %d num: %d len: %d \n", - event_type, event_num, data_len)); - - if (NAN_INVALID_EVENT(event_num)) { - WL_ERR((" unsupported event, num: %d \n", event_num)); - return -EINVAL; - } - - if (g_nan_debug) { - WL_DBG((" event name: %s \n", nan_event_name[event_num])); - WL_DBG((" event data: \n")); - prhex(NULL, data, data_len); - } - - /* unpack the tlvs */ - memset(&tlv_data, 0, sizeof(wl_nan_tlv_data_t)); - bcm_unpack_xtlv_buf(&tlv_data, data, data_len, - wl_cfgnan_set_vars_cbfn); - - /* - * send as preformatted hex string - * - * EVENT_NAN - */ - - buf_len = NAN_IOCTL_BUF_SIZE; - buf = ptr = kzalloc(buf_len, kflags); - if (!buf) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - - switch (event_num) { - case WL_NAN_EVENT_START: - case WL_NAN_EVENT_JOIN: - case WL_NAN_EVENT_STOP: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, - nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; - case WL_NAN_EVENT_ROLE: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s "ROLE_PREFIX "%d " - CLUS_ID_PREFIX MACF, nan_event_str[event_num], - tlv_data.nstatus.role, ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; - case WL_NAN_EVENT_DISCOVERY_RESULT: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " - SUB_ID_PREFIX"%d " MAC_ADDR_PREFIX MACF, - nan_event_str[event_num], tlv_data.pub_id, tlv_data.sub_id, - ETHER_TO_MACF(tlv_data.mac_addr)); - if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) { - WL_DBG((" service info present \n")); - if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) { - WL_ERR((" service info length = %d\n", - tlv_data.svc_info.dlen)); - WL_ERR((" insufficent buffer to copy service info \n")); - ret = -EOVERFLOW; - goto fail; - } - ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX); - ptr += bcm_format_hex(ptr, tlv_data.svc_info.data, - tlv_data.svc_info.dlen); - } else { - WL_DBG((" service info not present \n")); - } - - if (tlv_data.vend_info.data && tlv_data.vend_info.dlen) { - struct ether_addr *ea; - u8 *temp_data = tlv_data.vend_info.data; - uint32 bitmap; - u16 dlen = tlv_data.vend_info.dlen; - chanspec_t chanspec; - uint8 mapcontrol; - uint8 proto; - - WL_DBG((" vendor info present \n")); - if ((*temp_data != NAN_ATTR_VENDOR_SPECIFIC) || - (dlen < NAN_VENDOR_HDR_SIZE)) { - WL_ERR((" error in vendor info attribute \n")); - ret = -EINVAL; - goto fail; - } else { - WL_DBG((" vendor info not present \n")); - } - - if (*(temp_data + 6) == NAN_VENDOR_TYPE_RTT) { - temp_data += NAN_VENDOR_HDR_SIZE; - ea = (struct ether_addr *)temp_data; - temp_data += ETHER_ADDR_LEN; - mapcontrol = *temp_data++; - proto = *temp_data++; - bitmap = *(uint32 *)temp_data; - temp_data += 4; - chanspec = *(chanspec_t *)temp_data; - ptr += sprintf(ptr, " "BITMAP_PREFIX"0x%x "CHAN_PREFIX"%d/%s", - bitmap, wf_chspec_ctlchan(chanspec), - wf_chspec_to_bw_str(chanspec)); - WL_DBG((" bitmap: 0x%x channel: %d bandwidth: %s \n", bitmap, - wf_chspec_ctlchan(chanspec), - wf_chspec_to_bw_str(chanspec))); - } - } - break; - case WL_NAN_EVENT_REPLIED: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " - MAC_ADDR_PREFIX MACF, nan_event_str[event_num], - tlv_data.pub_id, ETHER_TO_MACF(tlv_data.mac_addr)); - break; - case WL_NAN_EVENT_TERMINATED: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d ", - nan_event_str[event_num], tlv_data.pub_id); - break; - case WL_NAN_EVENT_RECEIVE: - ptr += sprintf(buf, - SUPP_EVENT_PREFIX"%s " INSTANCE_ID_PREFIX"%d " - REMOTE_INSTANCE_ID_PREFIX"%d " MAC_ADDR_PREFIX MACF, - nan_event_str[event_num], tlv_data.inst_id, - tlv_data.peer_inst_id, ETHER_TO_MACF(tlv_data.mac_addr)); - if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) { - WL_DBG((" service info present \n")); - if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) { - WL_ERR((" service info length = %d\n", - tlv_data.svc_info.dlen)); - WL_ERR((" insufficent buffer to copy service info \n")); - ret = -EOVERFLOW; - goto fail; - } - ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX); - ptr += bcm_format_hex(ptr, tlv_data.svc_info.data, - tlv_data.svc_info.dlen); - } else { - WL_DBG((" service info not present \n")); - } - break; - case WL_NAN_EVENT_SCAN_COMPLETE: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, - nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; - case WL_NAN_EVENT_STATUS_CHG: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, - nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; - case WL_NAN_EVENT_MERGE: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, - nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; -#ifdef NAN_P2P_CONFIG - case WL_NAN_EVENT_P2P: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " - MAC_ADDR_PREFIX MACF, nan_event_str[event_num], - ETHER_TO_MACF(tlv_data.mac_addr)); - if (tlv_data.vend_info.data && tlv_data.vend_info.dlen) { - u8 *data = tlv_data.vend_info.data; - u16 dlen = tlv_data.vend_info.dlen; - - WL_DBG((" vendor info present %d dlen = %d\n", - *(data + 6), (dlen - (NAN_VENDOR_HDR_SIZE+1)))); - if ((*data != NAN_ATTR_VENDOR_SPECIFIC) || - (dlen < NAN_VENDOR_HDR_SIZE)) { - WL_ERR((" error in vendor info attribute \n")); - ret = -EINVAL; - goto fail; - } else { - WL_DBG((" vendor info present \n")); - } - - if (*(data + 6) == NAN_VENDOR_TYPE_P2P) { - data += NAN_VENDOR_HDR_SIZE; - ptr += sprintf(ptr, " %s", P2P_IE_PREFIX); - ptr += bcm_format_hex(ptr, data, (dlen - (NAN_VENDOR_HDR_SIZE))); - } - } - break; -#endif /* NAN_P2P_CONFIG */ - default: - WL_ERR((" unknown event \n")); - break; - } - -#ifdef WL_GENL - /* send the preformatted string to the upper layer as event */ - WL_DBG((" formatted string for userspace: %s, len: %zu \n", - buf, strlen(buf))); - wl_genl_send_msg(bcmcfg_to_prmry_ndev(cfg), 0, buf, strlen(buf), 0, 0); -#endif /* WL_GENL */ - -fail: - if (buf) { - kfree(buf); - } - if (tlv_data.svc_info.data) { - kfree(tlv_data.svc_info.data); - tlv_data.svc_info.data = NULL; - tlv_data.svc_info.dlen = 0; - } - if (tlv_data.vend_info.data) { - kfree(tlv_data.vend_info.data); - tlv_data.vend_info.data = NULL; - tlv_data.vend_info.dlen = 0; - } - - return ret; -} diff --git a/drivers/net/wireless/bcmdhd/wl_cfgnan.h b/drivers/net/wireless/bcmdhd/wl_cfgnan.h deleted file mode 100644 index 71de5d68b1ed..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_cfgnan.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Neighbor Awareness Networking - * - * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgnan.h 487532 2014-06-26 05:09:36Z $ - */ - -#ifndef _wl_cfgnan_h_ -#define _wl_cfgnan_h_ - -#define NAN_IOCTL_BUF_SIZE 512 -#define NAN_EVENT_STR_MAX_LEN 30 -#define NAN_EVENT_NAME_MAX_LEN 40 -#define NAN_CONFIG_ATTR_MAX_LEN 24 -#define NAN_RTT_IOVAR_BUF_SIZE 1024 -#define WL_NAN_EVENT_CLEAR_BIT 32 -#define NAN_EVENT_MASK_ALL 0x7fffffff - -#define NAN_INVALID_ID(id) ((id > 255) ? true : false) -#define NAN_INVALID_ROLE(role) ((role > WL_NAN_ROLE_ANCHOR_MASTER) ? true : false) -#define NAN_INVALID_CHANSPEC(chanspec) ((chanspec == INVCHANSPEC) || \ - (chanspec == 0) ? true : false) -#define NAN_INVALID_EVENT(num) (((num < WL_NAN_EVENT_START) || \ - (num >= WL_NAN_EVENT_INVALID)) ? true : false) -#define NAN_INVALID_PROXD_EVENT(num) ((num != WLC_E_PROXD_NAN_EVENT) ? \ - true : false) -#define NAN_EVENT_BIT(event) (1U << (event - WL_NAN_EVENT_START)) - -#define SUPP_EVENT_PREFIX "CTRL-EVENT-" -#define EVENT_RTT_STATUS_STR "NAN-RTT-STATUS" - -#define TIMESTAMP_PREFIX "TSF=" /* timestamp */ -#define AMR_PREFIX "AMR=" /* anchor master rank */ -#define DISTANCE_PREFIX "DIST=" /* distance */ -#define ATTR_PREFIX "ATTR=" /* attribute */ -#define ROLE_PREFIX "ROLE=" /* role */ -#define CHAN_PREFIX "CHAN=" /* channel */ -#define BITMAP_PREFIX "BMAP=" /* bitmap */ -#define DEBUG_PREFIX "DEBUG=" /* debug enable/disable flag */ -#define DW_LEN_PREFIX "DW_LEN=" /* discovery window length */ -#define DW_INT_PREFIX "DW_INT=" /* discovery window interval */ -#define STATUS_PREFIX "STATUS=" /* status */ -#define PUB_ID_PREFIX "PUB_ID=" /* publisher id */ -#define SUB_ID_PREFIX "SUB_ID=" /* subscriber id */ -#define INSTANCE_ID_PREFIX "LOCAL_ID=" /* Instance id */ -#define REMOTE_INSTANCE_ID_PREFIX "PEER_ID=" /* Peer id */ - -#ifdef NAN_P2P_CONFIG -#define P2P_IE_PREFIX "P2P_IE=" /* p2p ie id */ -#define IE_EN_PREFIX "ENBLE_IE=" /* enable p2p ie */ -#endif -#define PUB_PR_PREFIX "PUB_PR=" /* publish period */ -#define PUB_INT_PREFIX "PUB_INT=" /* publish interval (ttl) */ -#define CLUS_ID_PREFIX "CLUS_ID=" /* cluster id */ -#define IF_ADDR_PREFIX "IF_ADDR=" /* IF address */ -#define MAC_ADDR_PREFIX "MAC_ADDR=" /* mac address */ -#define SVC_HASH_PREFIX "SVC_HASH=" /* service hash */ -#define SVC_INFO_PREFIX "SVC_INFO=" /* service information */ -#define HOP_COUNT_PREFIX "HOP_COUNT=" /* hop count */ -#define MASTER_PREF_PREFIX "MASTER_PREF=" /* master preference */ -#define ACTIVE_OPTION "ACTIVE" /* Active Subscribe. */ -#define SOLICITED_OPTION "SOLICITED" /* Solicited Publish. */ -#define UNSOLICITED_OPTION "UNSOLICITED" /* Unsolicited Publish. */ -/* anchor master beacon transmission time */ -#define AMBTT_PREFIX "AMBTT=" -/* passive scan period for cluster merge */ -#define SCAN_PERIOD_PREFIX "SCAN_PERIOD=" -/* passive scan interval for cluster merge */ -#define SCAN_INTERVAL_PREFIX "SCAN_INTERVAL=" -#define BCN_INTERVAL_PREFIX "BCN_INTERVAL=" - -typedef struct nan_str_data { - u8 *data; - u32 dlen; -} nan_str_data_t; - -typedef struct nan_config_attr { - char name[NAN_CONFIG_ATTR_MAX_LEN]; /* attribute name */ - u16 type; /* attribute xtlv type */ -} nan_config_attr_t; - -typedef struct nan_cmd_data { - nan_config_attr_t attr; /* set config attributes */ - nan_str_data_t svc_hash; /* service hash */ - nan_str_data_t svc_info; /* service information */ - nan_str_data_t p2p_info; /* p2p information */ - struct ether_addr mac_addr; /* mac address */ - struct ether_addr clus_id; /* cluster id */ - struct ether_addr if_addr; /* if addr */ - u32 beacon_int; /* beacon interval */ - u32 pub_int; /* publish interval (ttl) */ - u32 pub_pr; /* publish period */ - u32 bmap; /* bitmap */ - u32 role; /* role */ - u16 pub_id; /* publisher id */ - u16 sub_id; /* subscriber id */ - u16 local_id; /* Local id */ - u16 remote_id; /* Remote id */ - uint32 flags; /* Flag bits */ - u16 dw_len; /* discovery window length */ - u16 master_pref; /* master preference */ - chanspec_t chanspec; /* channel */ - u8 debug_flag; /* debug enable/disable flag */ -} nan_cmd_data_t; - -typedef int (nan_func_t)(struct net_device *ndev, struct bcm_cfg80211 *cfg, - char *cmd, nan_cmd_data_t *cmd_data); - -typedef struct nan_cmd { - const char *name; /* command name */ - nan_func_t *func; /* command hadler */ -} nan_cmd_t; - -typedef struct nan_event_hdr { - u16 event_subtype; - u32 flags; /* future use */ -} nan_event_hdr_t; - -typedef struct wl_nan_tlv_data { - wl_nan_status_t nstatus; /* status data */ - wl_nan_disc_params_t params; /* discovery parameters */ - struct ether_addr mac_addr; /* peer mac address */ - struct ether_addr clus_id; /* cluster id */ - nan_str_data_t svc_info; /* service info */ - nan_str_data_t vend_info; /* vendor info */ - /* anchor master beacon transmission time */ - u32 ambtt; - u32 dev_role; /* device role */ - u16 inst_id; /* instance id */ - u16 peer_inst_id; /* Peer instance id */ - u16 pub_id; /* publisher id */ - u16 sub_id; /* subscriber id */ - u16 master_pref; /* master preference */ - chanspec_t chanspec; /* channel */ - u8 amr[NAN_MASTER_RANK_LEN]; /* anchor master role */ - u8 svc_name[WL_NAN_SVC_HASH_LEN]; /* service name */ - u8 hop_count; /* hop count */ - u8 enabled; /* nan status flag */ - nan_scan_params_t scan_params; /* scan_param */ -} wl_nan_tlv_data_t; - -extern int wl_cfgnan_set_vars_cbfn(void *ctx, void **tlv_buf, - uint16 type, uint16 len); -extern int wl_cfgnan_enable_events(struct net_device *ndev, - struct bcm_cfg80211 *cfg); -extern int wl_cfgnan_start_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_stop_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_support_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_status_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_pub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_p2p_ie_add_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_p2p_ie_enable_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_p2p_ie_del_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); - -extern int wl_cfgnan_sub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_cancel_pub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_cancel_sub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_transmit_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_set_config_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_rtt_config_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_rtt_find_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_debug_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_cmd_handler(struct net_device *dev, - struct bcm_cfg80211 *cfg, char *cmd, int cmd_len); -extern s32 wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -extern s32 wl_cfgnan_notify_proxd_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); - -#endif /* _wl_cfgnan_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c deleted file mode 100644 index 6d0efd046d00..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ /dev/null @@ -1,2743 +0,0 @@ -/* - * Linux cfgp2p driver - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgp2p.c 711632 2017-07-19 04:24:04Z $ - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -static s8 scanparambuf[WLC_IOCTL_SMLEN]; -static s8 g_mgmt_ie_buf[2048]; -static bool -wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); - -static u32 -wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag, - s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd); -static s32 wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, - struct wireless_dev *wdev, bool notify); - - -#if defined(WL_ENABLE_P2P_IF) -static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); -static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); -static int wl_cfgp2p_if_open(struct net_device *net); -static int wl_cfgp2p_if_stop(struct net_device *net); - -static const struct net_device_ops wl_cfgp2p_if_ops = { - .ndo_open = wl_cfgp2p_if_open, - .ndo_stop = wl_cfgp2p_if_stop, - .ndo_do_ioctl = wl_cfgp2p_do_ioctl, - .ndo_start_xmit = wl_cfgp2p_start_xmit, -}; -#endif /* WL_ENABLE_P2P_IF */ - - -bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) -{ - wifi_p2p_pub_act_frame_t *pact_frm; - - if (frame == NULL) - return false; - pact_frm = (wifi_p2p_pub_act_frame_t *)frame; - if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1) - return false; - - if (pact_frm->category == P2P_PUB_AF_CATEGORY && - pact_frm->action == P2P_PUB_AF_ACTION && - pact_frm->oui_type == P2P_VER && - memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) { - return true; - } - - return false; -} - -bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) -{ - wifi_p2p_action_frame_t *act_frm; - - if (frame == NULL) - return false; - act_frm = (wifi_p2p_action_frame_t *)frame; - if (frame_len < sizeof(wifi_p2p_action_frame_t) -1) - return false; - - if (act_frm->category == P2P_AF_CATEGORY && - act_frm->type == P2P_VER && - memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) { - return true; - } - - return false; -} - -#define GAS_RESP_LEN 2 -#define DOUBLE_TLV_BODY_OFF 4 -#define GAS_RESP_OFFSET 4 -#define GAS_CRESP_OFFSET 5 - -bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len) -{ - bcm_tlv_t *ie = (bcm_tlv_t *)data; - u8 *frame = NULL; - u16 id, flen; - - /* Skipped first ANQP Element, if frame has anqp elemnt */ - ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID); - - if (ie == NULL) - return false; - - frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN; - id = ((u16) (((frame)[1] << 8) | (frame)[0])); - flen = ((u16) (((frame)[3] << 8) | (frame)[2])); - - /* If the contents match the OUI and the type */ - if (flen >= WFA_OUI_LEN + 1 && - id == P2PSD_GAS_NQP_INFOID && - !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) && - subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) { - return true; - } - - return false; -} - -bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) -{ - - wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; - - if (frame == NULL) - return false; - - sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; - if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)) - return false; - if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) - return false; - - if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) - return true; - else - return false; -} - -bool wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len) -{ - - wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; - - if (frame == NULL) - return false; - - sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; - if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)) - return false; - if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) - return false; - - if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ) - return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, - (u8 *)sd_act_frm->query_data, - frame_len); - else - return false; -} - -void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel) -{ - wifi_p2p_pub_act_frame_t *pact_frm; - wifi_p2p_action_frame_t *act_frm; - wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; - if (!frame || frame_len <= 2) - return; - - if (wl_cfgp2p_is_pub_action(frame, frame_len)) { - pact_frm = (wifi_p2p_pub_act_frame_t *)frame; - switch (pact_frm->subtype) { - case P2P_PAF_GON_REQ: - CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_GON_RSP: - CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_GON_CONF: - CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_INVITE_REQ: - CFGP2P_ACTION(("%s P2P Invitation Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_INVITE_RSP: - CFGP2P_ACTION(("%s P2P Invitation Response Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_DEVDIS_REQ: - CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_DEVDIS_RSP: - CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_PROVDIS_REQ: - CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_PROVDIS_RSP: - CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - default: - CFGP2P_ACTION(("%s Unknown P2P Public Action Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - - } - - } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) { - act_frm = (wifi_p2p_action_frame_t *)frame; - switch (act_frm->subtype) { - case P2P_AF_NOTICE_OF_ABSENCE: - CFGP2P_ACTION(("%s P2P Notice of Absence Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_AF_PRESENCE_REQ: - CFGP2P_ACTION(("%s P2P Presence Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_AF_PRESENCE_RSP: - CFGP2P_ACTION(("%s P2P Presence Response Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_AF_GO_DISC_REQ: - CFGP2P_ACTION(("%s P2P Discoverability Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - default: - CFGP2P_ACTION(("%s Unknown P2P Action Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - } - - } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { - sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; - switch (sd_act_frm->action) { - case P2PSD_ACTION_ID_GAS_IREQ: - CFGP2P_ACTION(("%s P2P GAS Initial Request," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - break; - case P2PSD_ACTION_ID_GAS_IRESP: - CFGP2P_ACTION(("%s P2P GAS Initial Response," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - break; - case P2PSD_ACTION_ID_GAS_CREQ: - CFGP2P_ACTION(("%s P2P GAS Comback Request," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - break; - case P2PSD_ACTION_ID_GAS_CRESP: - CFGP2P_ACTION(("%s P2P GAS Comback Response," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - break; - default: - CFGP2P_ACTION(("%s Unknown P2P GAS Frame," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - } - - - } -} - -/* - * Initialize variables related to P2P - * - */ -s32 -wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg) -{ - if (!(cfg->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) { - CFGP2P_ERR(("struct p2p_info allocation failed\n")); - return -ENOMEM; - } -#define INIT_IE(IE_TYPE, BSS_TYPE) \ - do { \ - memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ - sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ - wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ - } while (0); - - INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE); - INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE); - INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE); - INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE); - INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE); - INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION); - INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION); - INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION); - INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION); - INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION); -#undef INIT_IE - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg); - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0; - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = NULL; - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = 0; - return BCME_OK; - -} -/* - * Deinitialize variables related to P2P - * - */ -void -wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg) -{ - CFGP2P_DBG(("In\n")); - if (cfg->p2p) { - kfree(cfg->p2p); - cfg->p2p = NULL; - } - cfg->p2p_supported = 0; -} -/* - * Set P2P functions into firmware - */ -s32 -wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg) -{ - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } }; - s32 ret = BCME_OK; - s32 val = 0; - /* Do we have to check whether APSTA is enabled or not ? */ - ret = wldev_iovar_getint(ndev, "apsta", &val); - if (ret < 0) { - CFGP2P_ERR(("get apsta error %d\n", ret)); - return ret; - } - if (val == 0) { - val = 1; - ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); - if (ret < 0) { - CFGP2P_ERR(("WLC_DOWN error %d\n", ret)); - return ret; - } - wldev_iovar_setint(ndev, "apsta", val); - ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); - if (ret < 0) { - CFGP2P_ERR(("WLC_UP error %d\n", ret)); - return ret; - } - } - - /* In case of COB type, firmware has default mac address - * After Initializing firmware, we have to set current mac address to - * firmware for P2P device address - */ - ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr, - sizeof(null_eth_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &cfg->ioctl_buf_sync); - if (ret && ret != BCME_UNSUPPORTED) { - CFGP2P_ERR(("failed to update device address ret %d\n", ret)); - } - return ret; -} - -/* Create a new P2P BSS. - * Parameters: - * @mac : MAC address of the BSS to create - * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT - * @chspec : chspec to use if creating a GO BSS. - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, - chanspec_t chspec) -{ - wl_p2p_if_t ifreq; - s32 err; - u32 scb_timeout = WL_SCB_TIMEOUT; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - - ifreq.type = if_type; - ifreq.chspec = chspec; - memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); - - CFGP2P_DBG(("---cfg p2p_ifadd "MACDBG" %s %u\n", - MAC2STRDBG(ifreq.addr.octet), - (if_type == WL_P2P_IF_GO) ? "go" : "client", - (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); - - err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (unlikely(err < 0)) - printk("'cfg p2p_ifadd' error %d\n", err); - else if (if_type == WL_P2P_IF_GO) { - err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); - if (unlikely(err < 0)) - printk("'cfg scb_timeout' error %d\n", err); - } - return err; -} - -/* Disable a P2P BSS. - * Parameters: - * @mac : MAC address of the BSS to disable - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac) -{ - s32 ret; - struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); - - CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdis "MACDBG"\n", - netdev->ifindex, MAC2STRDBG(mac->octet))); - ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(ret < 0)) { - printk("'cfg p2p_ifdis' error %d\n", ret); - } - return ret; -} - -/* Delete a P2P BSS. - * Parameters: - * @mac : MAC address of the BSS to delete - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac) -{ - s32 ret; - struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); - - CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdel "MACDBG"\n", - netdev->ifindex, MAC2STRDBG(mac->octet))); - ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(ret < 0)) { - printk("'cfg p2p_ifdel' error %d\n", ret); - } - return ret; -} - -/* Change a P2P Role. - * Parameters: - * @mac : MAC address of the BSS to change a role - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, - chanspec_t chspec) -{ - wl_p2p_if_t ifreq; - s32 err; - u32 scb_timeout = WL_SCB_TIMEOUT; - - struct net_device *netdev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); - - ifreq.type = if_type; - ifreq.chspec = chspec; - memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); - - CFGP2P_INFO(("---cfg p2p_ifchange "MACDBG" %s %u" - " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet), - (if_type == WL_P2P_IF_GO) ? "go" : "client", - (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT, - ifreq.chspec)); - - err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (unlikely(err < 0)) { - printk("'cfg p2p_ifupd' error %d\n", err); - } else if (if_type == WL_P2P_IF_GO) { - err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); - if (unlikely(err < 0)) - printk("'cfg scb_timeout' error %d\n", err); - } - return err; -} - - -/* Get the index of a created P2P BSS. - * Parameters: - * @mac : MAC address of the created BSS - * @index : output: index of created BSS - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index) -{ - s32 ret; - u8 getbuf[64]; - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - - CFGP2P_INFO(("---cfg p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet))); - - ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, - sizeof(getbuf), wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY), NULL); - - if (ret == 0) { - memcpy(index, getbuf, sizeof(s32)); - CFGP2P_INFO(("---cfg p2p_if ==> %d\n", *index)); - } - - return ret; -} - -static s32 -wl_cfgp2p_set_discovery(struct bcm_cfg80211 *cfg, s32 on) -{ - s32 ret = BCME_OK; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - CFGP2P_DBG(("enter\n")); - - ret = wldev_iovar_setint(ndev, "p2p_disc", on); - - if (unlikely(ret < 0)) { - CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret)); - } - - return ret; -} - -/* Set the WL driver's P2P mode. - * Parameters : - * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}. - * @channel : the channel to listen - * @listen_ms : the time (milli seconds) to wait - * @bssidx : bss index for BSSCFG - * Returns 0 if success - */ - -s32 -wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, u32 channel, u16 listen_ms, int bssidx) -{ - wl_p2p_disc_st_t discovery_mode; - s32 ret; - struct net_device *dev; - CFGP2P_DBG(("enter\n")); - - if (unlikely(bssidx == WL_INVALID)) { - CFGP2P_ERR((" %d index out of range\n", bssidx)); - return -1; - } - - dev = wl_cfgp2p_find_ndev(cfg, bssidx); - if (unlikely(dev == NULL)) { - CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx)); - return BCME_NOTFOUND; - } - - - - /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */ - discovery_mode.state = mode; - discovery_mode.chspec = wl_ch_host_to_driver(channel); - discovery_mode.dwell = listen_ms; - ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode, - sizeof(discovery_mode), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, - bssidx, &cfg->ioctl_buf_sync); - - return ret; -} - -/* Get the index of the P2P Discovery BSS */ -static s32 -wl_cfgp2p_get_disc_idx(struct bcm_cfg80211 *cfg, s32 *index) -{ - s32 ret; - struct net_device *dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); - - ret = wldev_iovar_getint(dev, "p2p_dev", index); - CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret)); - - if (unlikely(ret < 0)) { - CFGP2P_ERR(("'p2p_dev' error %d\n", ret)); - return ret; - } - return ret; -} - -s32 -wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg) -{ - - s32 index = 0; - s32 ret = BCME_OK; - - CFGP2P_DBG(("enter\n")); - - if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0) { - CFGP2P_ERR(("do nothing, already initialized\n")); - return ret; - } - - ret = wl_cfgp2p_set_discovery(cfg, 1); - if (ret < 0) { - CFGP2P_ERR(("set discover error\n")); - return ret; - } - /* Enable P2P Discovery in the WL Driver */ - ret = wl_cfgp2p_get_disc_idx(cfg, &index); - - if (ret < 0) { - return ret; - } - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = index; - - /* Set the initial discovery state to SCAN */ - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - - if (unlikely(ret != 0)) { - CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); - wl_cfgp2p_set_discovery(cfg, 0); - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; - return 0; - } - return ret; -} - -/* Deinitialize P2P Discovery - * Parameters : - * @cfg : wl_private data - * Returns 0 if succes - */ -static s32 -wl_cfgp2p_deinit_discovery(struct bcm_cfg80211 *cfg) -{ - s32 ret = BCME_OK; - CFGP2P_DBG(("enter\n")); - - if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) <= 0) { - CFGP2P_ERR(("do nothing, not initialized\n")); - return -1; - } - /* Set the discovery state to SCAN */ - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */ - ret = wl_cfgp2p_set_discovery(cfg, 0); - - /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver - * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery - * BSS. - */ - - /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we - * have no discovery BSS. - */ - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = WL_INVALID; - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; - - return ret; - -} -/* Enable P2P Discovery - * Parameters: - * @cfg : wl_private data - * @ie : probe request ie (WPS IE + P2P IE) - * @ie_len : probe request ie length - * Returns 0 if success. - */ -s32 -wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, - const u8 *ie, u32 ie_len) -{ - s32 ret = BCME_OK; - s32 bssidx; - - if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { - CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n")); - goto set_ie; - } - - wl_set_p2p_status(cfg, DISCOVERY_ON); - - CFGP2P_DBG(("enter\n")); - - ret = wl_cfgp2p_init_discovery(cfg); - if (unlikely(ret < 0)) { - CFGP2P_ERR((" init discovery error %d\n", ret)); - goto exit; - } - /* Set wsec to any non-zero value in the discovery bsscfg to ensure our - * P2P probe responses have the privacy bit set in the 802.11 WPA IE. - * Some peer devices may not initiate WPS with us if this bit is not set. - */ - ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), - "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - if (unlikely(ret < 0)) { - CFGP2P_ERR((" wsec error %d\n", ret)); - } -set_ie: - if (ie_len) { - if (bcmcfg_to_prmry_ndev(cfg) == dev) { - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - } else if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - ret = wl_cfgp2p_set_management_ie(cfg, dev, - bssidx, - VNDR_IE_PRBREQ_FLAG, ie, ie_len); - - if (unlikely(ret < 0)) { - CFGP2P_ERR(("set probreq ie occurs error %d\n", ret)); - goto exit; - } - } -exit: - return ret; -} - -/* Disable P2P Discovery - * Parameters: - * @cfg : wl_private_data - * Returns 0 if success. - */ -s32 -wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg) -{ - s32 ret = BCME_OK; - CFGP2P_DBG((" enter\n")); - wl_clr_p2p_status(cfg, DISCOVERY_ON); - - if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) == 0) { - CFGP2P_ERR((" do nothing, not initialized\n")); - goto exit; - } - - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - - if (unlikely(ret < 0)) { - - CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); - } - /* Do a scan abort to stop the driver's scan engine in case it is still - * waiting out an action frame tx dwell time. - */ - wl_clr_p2p_status(cfg, DISCOVERY_ON); - ret = wl_cfgp2p_deinit_discovery(cfg); - -exit: - return ret; -} - -s32 -wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, - u32 num_chans, u16 *channels, - s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, - p2p_scan_purpose_t p2p_scan_purpose) -{ - s32 ret = BCME_OK; - s32 memsize; - s32 eparams_size; - u32 i; - s8 *memblk; - wl_p2p_scan_t *p2p_params; - wl_escan_params_t *eparams; - wlc_ssid_t ssid; - /* Scan parameters */ -#define P2PAPI_SCAN_NPROBES 1 -#define P2PAPI_SCAN_DWELL_TIME_MS 80 -#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 -#define P2PAPI_SCAN_HOME_TIME_MS 60 -#define P2PAPI_SCAN_NPROBS_TIME_MS 30 -#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 - - struct net_device *pri_dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); - /* Allocate scan params which need space for 3 channels and 0 ssids */ - eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + - OFFSETOF(wl_escan_params_t, params)) + - num_chans * sizeof(eparams->params.channel_list[0]); - - memsize = sizeof(wl_p2p_scan_t) + eparams_size; - memblk = scanparambuf; - if (memsize > sizeof(scanparambuf)) { - CFGP2P_ERR((" scanpar buf too small (%u > %zu)\n", - memsize, sizeof(scanparambuf))); - return -1; - } - memset(memblk, 0, memsize); - memset(cfg->ioctl_buf, 0, WLC_IOCTL_MAXLEN); - if (search_state == WL_P2P_DISC_ST_SEARCH) { - /* - * If we in SEARCH STATE, we don't need to set SSID explictly - * because dongle use P2P WILDCARD internally by default - */ - wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx); - /* use null ssid */ - ssid.SSID_len = 0; - memset(&ssid.SSID, 0, sizeof(ssid.SSID)); - } else if (search_state == WL_P2P_DISC_ST_SCAN) { - /* SCAN STATE 802.11 SCAN - * WFD Supplicant has p2p_find command with (type=progressive, type= full) - * So if P2P_find command with type=progressive, - * we have to set ssid to P2P WILDCARD because - * we just do broadcast scan unless setting SSID - */ - wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); - /* use wild card ssid */ - ssid.SSID_len = WL_P2P_WILDCARD_SSID_LEN; - memset(&ssid.SSID, 0, sizeof(ssid.SSID)); - memcpy(&ssid.SSID, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN); - } else { - CFGP2P_ERR((" invalid search state %d\n", search_state)); - return -1; - } - - - /* Fill in the P2P scan structure at the start of the iovar param block */ - p2p_params = (wl_p2p_scan_t*) memblk; - p2p_params->type = 'E'; - /* Fill in the Scan structure that follows the P2P scan structure */ - eparams = (wl_escan_params_t*) (p2p_params + 1); - eparams->params.bss_type = DOT11_BSSTYPE_ANY; - if (active) - eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE; - else - eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE; - - if (tx_dst_addr == NULL) - memcpy(&eparams->params.bssid, ðer_bcast, ETHER_ADDR_LEN); - else - memcpy(&eparams->params.bssid, tx_dst_addr, ETHER_ADDR_LEN); - - if (ssid.SSID_len) - memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); - - eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); - - switch (p2p_scan_purpose) { - case P2P_SCAN_SOCIAL_CHANNEL: - eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); - break; - case P2P_SCAN_AFX_PEER_NORMAL: - case P2P_SCAN_AFX_PEER_REDUCED: - eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); - break; - case P2P_SCAN_CONNECT_TRY: - eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); - break; - default : - if (wl_get_drv_status_all(cfg, CONNECTED)) - eparams->params.active_time = -1; - else - eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); - break; - } - - if (p2p_scan_purpose == P2P_SCAN_CONNECT_TRY) - eparams->params.nprobes = htod32(eparams->params.active_time / - WL_SCAN_JOIN_PROBE_INTERVAL_MS); - else - eparams->params.nprobes = htod32((eparams->params.active_time / - P2PAPI_SCAN_NPROBS_TIME_MS)); - - - if (eparams->params.nprobes <= 0) - eparams->params.nprobes = 1; - CFGP2P_DBG(("nprobes # %d, active_time %d\n", - eparams->params.nprobes, eparams->params.active_time)); - eparams->params.passive_time = htod32(-1); - eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | - (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); - - for (i = 0; i < num_chans; i++) { - eparams->params.channel_list[i] = wl_ch_host_to_driver(channels[i]); - } - eparams->version = htod32(ESCAN_REQ_VERSION); - eparams->action = htod16(action); - wl_escan_set_sync_id(eparams->sync_id, cfg); - wl_escan_set_type(cfg, WL_SCANTYPE_P2P); - CFGP2P_INFO(("SCAN CHANNELS : ")); - - for (i = 0; i < num_chans; i++) { - if (i == 0) CFGP2P_INFO(("%d", channels[i])); - else CFGP2P_INFO((",%d", channels[i])); - } - - CFGP2P_INFO(("\n")); - - ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan", - memblk, memsize, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (ret == BCME_OK) - wl_set_p2p_status(cfg, SCANNING); - return ret; -} - -/* search function to reach at common channel to send action frame - * Parameters: - * @cfg : wl_private data - * @ndev : net device for bssidx - * @bssidx : bssidx for BSS - * Returns 0 if success. - */ -s32 -wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, - s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr) -{ - s32 ret = 0; - u32 chan_cnt = 0; - u16 *default_chan_list = NULL; - p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_AFX_PEER_NORMAL; - if (!p2p_is_on(cfg) || ndev == NULL || bssidx == WL_INVALID) - return -BCME_ERROR; - WL_TRACE_HW4((" Enter\n")); - if (bssidx == wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY)) - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - if (channel) - chan_cnt = AF_PEER_SEARCH_CNT; - else - chan_cnt = SOCIAL_CHAN_CNT; - default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL); - if (default_chan_list == NULL) { - CFGP2P_ERR(("channel list allocation failed \n")); - ret = -ENOMEM; - goto exit; - } - if (channel) { - u32 i; - /* insert same channel to the chan_list */ - for (i = 0; i < chan_cnt; i++) { - default_chan_list[i] = channel; - } - } else { - default_chan_list[0] = SOCIAL_CHAN_1; - default_chan_list[1] = SOCIAL_CHAN_2; - default_chan_list[2] = SOCIAL_CHAN_3; - } - ret = wl_cfgp2p_escan(cfg, ndev, true, chan_cnt, - default_chan_list, WL_P2P_DISC_ST_SEARCH, - WL_SCAN_ACTION_START, bssidx, NULL, p2p_scan_purpose); - kfree(default_chan_list); -exit: - return ret; -} - -/* Check whether pointed-to IE looks like WPA. */ -#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) -/* Check whether pointed-to IE looks like WPS. */ -#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) -/* Check whether the given IE looks like WFA P2P IE. */ -#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) -/* Check whether the given IE looks like WFA WFDisplay IE. */ -#ifndef WFA_OUI_TYPE_WFD -#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ -#endif -#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) - -static s32 -wl_cfgp2p_parse_vndr_ies(u8 *parse, u32 len, - struct parsed_vndr_ies *vndr_ies) -{ - s32 err = BCME_OK; - vndr_ie_t *vndrie; - bcm_tlv_t *ie; - struct parsed_vndr_ie_info *parsed_info; - u32 count = 0; - s32 remained_len; - - remained_len = (s32)len; - memset(vndr_ies, 0, sizeof(*vndr_ies)); - - WL_INFORM(("---> len %d\n", len)); - ie = (bcm_tlv_t *) parse; - if (!bcm_valid_tlv(ie, remained_len)) - ie = NULL; - while (ie) { - if (count >= MAX_VNDR_IE_NUMBER) - break; - if (ie->id == DOT11_MNG_VS_ID) { - vndrie = (vndr_ie_t *) ie; - /* len should be bigger than OUI length + one data length at least */ - if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) { - CFGP2P_ERR(("%s: invalid vndr ie. length is too small %d\n", - __FUNCTION__, vndrie->len)); - goto end; - } - /* if wpa or wme ie, do not add ie */ - if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) && - ((vndrie->data[0] == WPA_OUI_TYPE) || - (vndrie->data[0] == WME_OUI_TYPE))) { - CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n")); - goto end; - } - - parsed_info = &vndr_ies->ie_info[count++]; - - /* save vndr ie information */ - parsed_info->ie_ptr = (char *)vndrie; - parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN); - memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t)); - - vndr_ies->count = count; - - CFGP2P_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x \n", - parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1], - parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0])); - } -end: - ie = bcm_next_tlv(ie, &remained_len); - } - return err; -} - - -/* Delete and Set a management vndr ie to firmware - * Parameters: - * @cfg : wl_private data - * @ndev : net device for bssidx - * @bssidx : bssidx for BSS - * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, - * VNDR_IE_ASSOCREQ_FLAG) - * @ie : VNDR IE (such as P2P IE , WPS IE) - * @ie_len : VNDR IE Length - * Returns 0 if success. - */ - -s32 -wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, - s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) -{ - s32 ret = BCME_OK; - u8 *curr_ie_buf = NULL; - u8 *mgmt_ie_buf = NULL; - u32 mgmt_ie_buf_len = 0; - u32 *mgmt_ie_len = 0; - u32 del_add_ie_buf_len = 0; - u32 total_ie_buf_len = 0; - u32 parsed_ie_buf_len = 0; - struct parsed_vndr_ies old_vndr_ies; - struct parsed_vndr_ies new_vndr_ies; - s32 i; - u8 *ptr; - s32 type = -1; - s32 remained_buf_len; -#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie) -#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie_len) - memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf)); - curr_ie_buf = g_mgmt_ie_buf; - CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag)); - -#ifdef DUAL_STA - if ((cfg->p2p != NULL) && ((bssidx == 0) || (bssidx != cfg->cfgdev_bssidx))) { -#else - if (cfg->p2p != NULL) { -#endif - if (wl_cfgp2p_find_type(cfg, bssidx, &type)) { - CFGP2P_ERR(("cannot find type from bssidx : %d\n", bssidx)); - return BCME_ERROR; - } - - switch (pktflag) { - case VNDR_IE_PRBREQ_FLAG : - mgmt_ie_buf = IE_TYPE(probe_req, type); - mgmt_ie_len = &IE_TYPE_LEN(probe_req, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, type)); - break; - case VNDR_IE_PRBRSP_FLAG : - mgmt_ie_buf = IE_TYPE(probe_res, type); - mgmt_ie_len = &IE_TYPE_LEN(probe_res, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, type)); - break; - case VNDR_IE_ASSOCREQ_FLAG : - mgmt_ie_buf = IE_TYPE(assoc_req, type); - mgmt_ie_len = &IE_TYPE_LEN(assoc_req, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, type)); - break; - case VNDR_IE_ASSOCRSP_FLAG : - mgmt_ie_buf = IE_TYPE(assoc_res, type); - mgmt_ie_len = &IE_TYPE_LEN(assoc_res, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, type)); - break; - case VNDR_IE_BEACON_FLAG : - mgmt_ie_buf = IE_TYPE(beacon, type); - mgmt_ie_len = &IE_TYPE_LEN(beacon, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, type)); - break; - default: - mgmt_ie_buf = NULL; - mgmt_ie_len = NULL; - CFGP2P_ERR(("not suitable type\n")); - return BCME_ERROR; - } - } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { - if (cfg->ap_info == NULL) { - CFGP2P_ERR(("hostapd ap_info null ptr refrence while setting IE\n")); - return BCME_ERROR; - - } - switch (pktflag) { - case VNDR_IE_PRBRSP_FLAG : - mgmt_ie_buf = cfg->ap_info->probe_res_ie; - mgmt_ie_len = &cfg->ap_info->probe_res_ie_len; - mgmt_ie_buf_len = sizeof(cfg->ap_info->probe_res_ie); - break; - case VNDR_IE_BEACON_FLAG : - mgmt_ie_buf = cfg->ap_info->beacon_ie; - mgmt_ie_len = &cfg->ap_info->beacon_ie_len; - mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie); - break; - case VNDR_IE_ASSOCRSP_FLAG : - /* WPS-AP WSC2.0 assoc res includes wps_ie */ - mgmt_ie_buf = cfg->ap_info->assoc_res_ie; - mgmt_ie_len = &cfg->ap_info->assoc_res_ie_len; - mgmt_ie_buf_len = sizeof(cfg->ap_info->assoc_res_ie); - break; - default: - mgmt_ie_buf = NULL; - mgmt_ie_len = NULL; - CFGP2P_ERR(("not suitable type\n")); - return BCME_ERROR; - } - bssidx = 0; - } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) { - switch (pktflag) { - case VNDR_IE_PRBREQ_FLAG : - mgmt_ie_buf = cfg->sta_info->probe_req_ie; - mgmt_ie_len = &cfg->sta_info->probe_req_ie_len; - mgmt_ie_buf_len = sizeof(cfg->sta_info->probe_req_ie); - break; - case VNDR_IE_ASSOCREQ_FLAG : - mgmt_ie_buf = cfg->sta_info->assoc_req_ie; - mgmt_ie_len = &cfg->sta_info->assoc_req_ie_len; - mgmt_ie_buf_len = sizeof(cfg->sta_info->assoc_req_ie); - break; - default: - mgmt_ie_buf = NULL; - mgmt_ie_len = NULL; - CFGP2P_ERR(("not suitable type\n")); - return BCME_ERROR; - } - bssidx = 0; - } else { - CFGP2P_ERR(("not suitable type\n")); - return BCME_ERROR; - } - - if (vndr_ie_len > mgmt_ie_buf_len) { - CFGP2P_ERR(("extra IE size too big\n")); - ret = -ENOMEM; - } else { - /* parse and save new vndr_ie in curr_ie_buff before comparing it */ - if (vndr_ie && vndr_ie_len && curr_ie_buf) { - ptr = curr_ie_buf; - - wl_cfgp2p_parse_vndr_ies((u8*)vndr_ie, - vndr_ie_len, &new_vndr_ies); - - for (i = 0; i < new_vndr_ies.count; i++) { - struct parsed_vndr_ie_info *vndrie_info = - &new_vndr_ies.ie_info[i]; - - memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr, - vndrie_info->ie_len); - parsed_ie_buf_len += vndrie_info->ie_len; - } - } - - if (mgmt_ie_buf != NULL) { - if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && - (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { - CFGP2P_INFO(("Previous mgmt IE is equals to current IE")); - goto exit; - } - - /* parse old vndr_ie */ - wl_cfgp2p_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, - &old_vndr_ies); - - /* make a command to delete old ie */ - for (i = 0; i < old_vndr_ies.count; i++) { - struct parsed_vndr_ie_info *vndrie_info = - &old_vndr_ies.ie_info[i]; - - CFGP2P_INFO(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", - vndrie_info->vndrie.id, vndrie_info->vndrie.len, - vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], - vndrie_info->vndrie.oui[2])); - - del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, - pktflag, vndrie_info->vndrie.oui, - vndrie_info->vndrie.id, - vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, - vndrie_info->ie_len - VNDR_IE_FIXED_LEN, - "del"); - - curr_ie_buf += del_add_ie_buf_len; - total_ie_buf_len += del_add_ie_buf_len; - } - } - - *mgmt_ie_len = 0; - /* Add if there is any extra IE */ - if (mgmt_ie_buf && parsed_ie_buf_len) { - ptr = mgmt_ie_buf; - - remained_buf_len = mgmt_ie_buf_len; - - /* make a command to add new ie */ - for (i = 0; i < new_vndr_ies.count; i++) { - struct parsed_vndr_ie_info *vndrie_info = - &new_vndr_ies.ie_info[i]; - - CFGP2P_INFO(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n", - vndrie_info->vndrie.id, vndrie_info->vndrie.len, - vndrie_info->ie_len - 2, - vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], - vndrie_info->vndrie.oui[2])); - - del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, - pktflag, vndrie_info->vndrie.oui, - vndrie_info->vndrie.id, - vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, - vndrie_info->ie_len - VNDR_IE_FIXED_LEN, - "add"); - - /* verify remained buf size before copy data */ - if (remained_buf_len >= vndrie_info->ie_len) { - remained_buf_len -= vndrie_info->ie_len; - } else { - CFGP2P_ERR(("no space in mgmt_ie_buf: pktflag = %d, " - "found vndr ies # = %d(cur %d), remained len %d, " - "cur mgmt_ie_len %d, new ie len = %d\n", - pktflag, new_vndr_ies.count, i, remained_buf_len, - *mgmt_ie_len, vndrie_info->ie_len)); - break; - } - - /* save the parsed IE in cfg struct */ - memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, - vndrie_info->ie_len); - *mgmt_ie_len += vndrie_info->ie_len; - - curr_ie_buf += del_add_ie_buf_len; - total_ie_buf_len += del_add_ie_buf_len; - } - } - if (total_ie_buf_len) { - ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, - total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, - bssidx, &cfg->ioctl_buf_sync); - if (ret) - CFGP2P_ERR(("vndr ie set error : %d\n", ret)); - } - } -#undef IE_TYPE -#undef IE_TYPE_LEN -exit: - return ret; -} - -/* Clear the manament IE buffer of BSSCFG - * Parameters: - * @cfg : wl_private data - * @bssidx : bssidx for BSS - * - * Returns 0 if success. - */ -s32 -wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx) -{ - - s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, - VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG}; - s32 index = -1; - s32 type = -1; - struct net_device *ndev = wl_cfgp2p_find_ndev(cfg, bssidx); -#define INIT_IE(IE_TYPE, BSS_TYPE) \ - do { \ - memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ - sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ - wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ - } while (0); - - if (bssidx < 0 || ndev == NULL) { - CFGP2P_ERR(("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev")); - return BCME_BADARG; - } - - if (wl_cfgp2p_find_type(cfg, bssidx, &type)) { - CFGP2P_ERR(("invalid argument\n")); - return BCME_BADARG; - } - for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) { - /* clean up vndr ies in dongle */ - wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, vndrie_flag[index], NULL, 0); - } - INIT_IE(probe_req, type); - INIT_IE(probe_res, type); - INIT_IE(assoc_req, type); - INIT_IE(assoc_res, type); - INIT_IE(beacon, type); - return BCME_OK; -} - - -/* Is any of the tlvs the expected entry? If - * not update the tlvs buffer pointer/length. - */ -static bool -wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type) -{ - /* If the contents match the OUI and the type */ - if (ie[TLV_LEN_OFF] >= oui_len + 1 && - !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && - type == ie[TLV_BODY_OFF + oui_len]) { - return TRUE; - } - - if (tlvs == NULL) - return FALSE; - /* point to the next ie */ - ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; - /* calculate the length of the rest of the buffer */ - *tlvs_len -= (int)(ie - *tlvs); - /* update the pointer to the start of the buffer */ - *tlvs = ie; - - return FALSE; -} - -wpa_ie_fixed_t * -wl_cfgp2p_find_wpaie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) { - return (wpa_ie_fixed_t *)ie; - } - } - return NULL; -} - -wpa_ie_fixed_t * -wl_cfgp2p_find_wpsie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) { - return (wpa_ie_fixed_t *)ie; - } - } - return NULL; -} - -wifi_p2p_ie_t * -wl_cfgp2p_find_p2pie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) { - return (wifi_p2p_ie_t *)ie; - } - } - return NULL; -} - -wifi_wfd_ie_t * -wl_cfgp2p_find_wfdie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) { - return (wifi_wfd_ie_t *)ie; - } - } - return NULL; -} -static u32 -wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag, - s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd) -{ - vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */ - s32 iecount; - u32 data_offset; - - /* Validate the pktflag parameter */ - if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | - VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | - VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) { - CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag)); - return -1; - } - - /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ - strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1); - hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - - /* Set the IE count - the buffer contains only 1 IE */ - iecount = htod32(1); - memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32)); - - /* Copy packet flags that indicate which packets will contain this IE */ - pktflag = htod32(pktflag); - memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, - sizeof(u32)); - - /* Add the IE ID to the buffer */ - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; - - /* Add the IE length to the buffer */ - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = - (uint8) VNDR_IE_MIN_LEN + datalen; - - /* Add the IE OUI to the buffer */ - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0]; - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1]; - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2]; - - /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */ - memcpy(iebuf, &hdr, sizeof(hdr) - 1); - - /* Copy the IE data to the IE buffer */ - data_offset = - (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] - - (u8*)&hdr; - memcpy(iebuf + data_offset, data, datalen); - return data_offset + datalen; - -} - -/* - * Search the bssidx based on dev argument - * Parameters: - * @cfg : wl_private data - * @ndev : net device to search bssidx - * @bssidx : output arg to store bssidx of the bsscfg of firmware. - * Returns error - */ -s32 -wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *bssidx) -{ - u32 i; - if (ndev == NULL || bssidx == NULL) { - CFGP2P_ERR((" argument is invalid\n")); - return BCME_BADARG; - } - if (!cfg->p2p_supported) { - *bssidx = P2PAPI_BSSCFG_PRIMARY; - return BCME_OK; - } - /* we cannot find the bssidx of DISCOVERY BSS - * because the ndev is same with ndev of PRIMARY BSS. - */ - for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { - if (ndev == wl_to_p2p_bss_ndev(cfg, i)) { - *bssidx = wl_to_p2p_bss_bssidx(cfg, i); - return BCME_OK; - } - } - -#ifdef DUAL_STA - if (cfg->bss_cfgdev && (cfg->bss_cfgdev == ndev_to_cfgdev(ndev))) { - CFGP2P_INFO(("cfgdev is present, return the bssidx")); - *bssidx = cfg->cfgdev_bssidx; - return BCME_OK; - } -#endif - - return BCME_BADARG; - -} -struct net_device * -wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx) -{ - u32 i; - struct net_device *ndev = NULL; - if (bssidx < 0) { - CFGP2P_ERR((" bsscfg idx is invalid\n")); - goto exit; - } - - for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { - if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) { - ndev = wl_to_p2p_bss_ndev(cfg, i); - break; - } - } - -exit: - return ndev; -} -/* - * Search the driver array idx based on bssidx argument - * Parameters: - * @cfg : wl_private data - * @bssidx : bssidx which indicate bsscfg->idx of firmware. - * @type : output arg to store array idx of p2p->bss. - * Returns error - */ - -s32 -wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type) -{ - u32 i; - if (bssidx < 0 || type == NULL) { - CFGP2P_ERR((" argument is invalid\n")); - goto exit; - } - - for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { - if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) { - *type = i; - return BCME_OK; - } - } - -#ifdef DUAL_STA - if (bssidx == cfg->cfgdev_bssidx) { - CFGP2P_DBG(("bssidx matching with the virtual I/F \n")); - *type = 1; - return BCME_OK; - } -#endif - -exit: - return BCME_BADARG; -} - -/* - * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE - */ -s32 -wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - s32 ret = BCME_OK; - struct net_device *ndev = NULL; - - if (!cfg || !cfg->p2p) - return BCME_ERROR; - - CFGP2P_DBG((" Enter\n")); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - - if (wl_get_p2p_status(cfg, LISTEN_EXPIRED) == 0) { - wl_set_p2p_status(cfg, LISTEN_EXPIRED); - if (timer_pending(&cfg->p2p->listen_timer)) { - del_timer_sync(&cfg->p2p->listen_timer); - } - - if (cfg->afx_hdl->is_listen == TRUE && - wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - WL_DBG(("Listen DONE for action frame\n")); - complete(&cfg->act_frm_scan); - } -#ifdef WL_CFG80211_SYNC_GON - else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, ndev); - WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n", - jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies))); - - if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); - - complete(&cfg->wait_next_af); - } -#endif /* WL_CFG80211_SYNC_GON */ - -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL)) { -#else - if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL) || - wl_get_drv_status_all(cfg, FAKE_REMAINING_ON_CHANNEL)) { -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - WL_DBG(("Listen DONE for ramain on channel expired\n")); - wl_clr_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_clr_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - if (ndev && (ndev->ieee80211_ptr != NULL)) { -#if defined(WL_CFG80211_P2P_DEV_IF) - cfg80211_remain_on_channel_expired(bcmcfg_to_p2p_wdev(cfg), - cfg->last_roc_id, &cfg->remain_on_chan, GFP_KERNEL); -#else - cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id, - &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL); -#endif /* WL_CFG80211_P2P_DEV_IF */ - } - } - if (wl_add_remove_eventmsg(bcmcfg_to_prmry_ndev(cfg), - WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) { - CFGP2P_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); - } - } else - wl_clr_p2p_status(cfg, LISTEN_EXPIRED); - - return ret; - -} - -/* - * Timer expire callback function for LISTEN - * We can't report cfg80211_remain_on_channel_expired from Timer ISR context, - * so lets do it from thread context. - */ -void -wl_cfgp2p_listen_expired(unsigned long data) -{ - wl_event_msg_t msg; - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *) data; - CFGP2P_DBG((" Enter\n")); - bzero(&msg, sizeof(wl_event_msg_t)); - msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); -#if defined(WL_ENABLE_P2P_IF) - wl_cfg80211_event(cfg->p2p_net ? cfg->p2p_net : - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, NULL); -#else - wl_cfg80211_event(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, - NULL); -#endif /* WL_ENABLE_P2P_IF */ -} -/* - * Routine for cancelling the P2P LISTEN - */ -static s32 -wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, - struct wireless_dev *wdev, bool notify) -{ - WL_DBG(("Enter \n")); - /* Irrespective of whether timer is running or not, reset - * the LISTEN state. - */ - if (timer_pending(&cfg->p2p->listen_timer)) { - del_timer_sync(&cfg->p2p->listen_timer); - if (notify) { -#if defined(WL_CFG80211_P2P_DEV_IF) - if (wdev) - cfg80211_remain_on_channel_expired(bcmcfg_to_p2p_wdev(cfg), - cfg->last_roc_id, &cfg->remain_on_chan, GFP_KERNEL); -#else - if (ndev && ndev->ieee80211_ptr) - cfg80211_remain_on_channel_expired(ndev, cfg->last_roc_id, - &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL); -#endif /* WL_CFG80211_P2P_DEV_IF */ - } - } - return 0; -} -/* - * Do a P2P Listen on the given channel for the given duration. - * A listen consists of sitting idle and responding to P2P probe requests - * with a P2P probe response. - * - * This fn assumes dongle p2p device discovery is already enabled. - * Parameters : - * @cfg : wl_private data - * @channel : channel to listen - * @duration_ms : the time (milli seconds) to wait - */ -s32 -wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms) -{ -#define EXTRA_DELAY_TIME 100 - s32 ret = BCME_OK; - struct timer_list *_timer; - s32 extra_delay; - struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); - - CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms)); - if (unlikely(wl_get_p2p_status(cfg, DISCOVERY_ON) == 0)) { - - CFGP2P_ERR((" Discovery is not set, so we have noting to do\n")); - - ret = BCME_NOTREADY; - goto exit; - } - if (timer_pending(&cfg->p2p->listen_timer)) { - CFGP2P_DBG(("previous LISTEN is not completed yet\n")); - goto exit; - - } -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - else - wl_clr_p2p_status(cfg, LISTEN_EXPIRED); -#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) { - CFGP2P_ERR((" failed to set WLC_E_P2P_PROPREQ_MSG\n")); - } - - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - _timer = &cfg->p2p->listen_timer; - - /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , - * otherwise we will wait up to duration_ms + 100ms + duration / 10 - */ - if (ret == BCME_OK) { - extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10); - } else { - /* if failed to set listen, it doesn't need to wait whole duration. */ - duration_ms = 100 + duration_ms / 20; - extra_delay = 0; - } - - INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_clr_p2p_status(cfg, LISTEN_EXPIRED); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - -#undef EXTRA_DELAY_TIME -exit: - return ret; -} - - -s32 -wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable) -{ - s32 ret = BCME_OK; - CFGP2P_DBG((" Enter\n")); - if (!wl_get_p2p_status(cfg, DISCOVERY_ON)) { - - CFGP2P_DBG((" do nothing, discovery is off\n")); - return ret; - } - if (wl_get_p2p_status(cfg, SEARCH_ENABLED) == enable) { - CFGP2P_DBG(("already : %d\n", enable)); - return ret; - } - - wl_chg_p2p_status(cfg, SEARCH_ENABLED); - /* When disabling Search, reset the WL driver's p2p discovery state to - * WL_P2P_DISC_ST_SCAN. - */ - if (!enable) { - wl_clr_p2p_status(cfg, SCANNING); - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - } - - return ret; -} - -/* - * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE - */ -s32 -wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - s32 ret = BCME_OK; - u32 event_type = ntoh32(e->event_type); - u32 status = ntoh32(e->status); - struct net_device *ndev = NULL; - CFGP2P_DBG((" Enter\n")); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) { - if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { - - CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); - if (status == WLC_E_STATUS_SUCCESS) { - wl_set_p2p_status(cfg, ACTION_TX_COMPLETED); - CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n")); - if (!cfg->need_wait_afrx && cfg->af_sent_channel) { - CFGP2P_DBG(("no need to wait next AF.\n")); - wl_stop_wait_next_action_frame(cfg, ndev); - } - } - else if (!wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { - wl_set_p2p_status(cfg, ACTION_TX_NOACK); - CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); - wl_stop_wait_next_action_frame(cfg, ndev); - } - } else { - CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," - "status : %d\n", status)); - - if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) - complete(&cfg->send_af_done); - } - } - return ret; -} -/* Send an action frame immediately without doing channel synchronization. - * - * This function does not wait for a completion event before returning. - * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action - * frame is transmitted. - * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an - * 802.11 ack has been received for the sent action frame. - */ -s32 -wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, - wl_af_params_t *af_params, s32 bssidx) -{ - s32 ret = BCME_OK; - s32 evt_ret = BCME_OK; - s32 timeout = 0; - wl_eventmsg_buf_t buf; - - - CFGP2P_INFO(("\n")); - CFGP2P_INFO(("channel : %u , dwell time : %u\n", - af_params->channel, af_params->dwell_time)); - - wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED); - wl_clr_p2p_status(cfg, ACTION_TX_NOACK); - - bzero(&buf, sizeof(wl_eventmsg_buf_t)); - wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true); - wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true); - if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) - return evt_ret; - - cfg->af_sent_channel = af_params->channel; -#ifdef WL_CFG80211_SYNC_GON - cfg->af_tx_sent_jiffies = jiffies; -#endif /* WL_CFG80211_SYNC_GON */ - - ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - if (ret < 0) { - CFGP2P_ERR((" sending action frame is failed\n")); - goto exit; - } - - timeout = wait_for_completion_timeout(&cfg->send_af_done, - msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX)); - - if (timeout >= 0 && wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { - CFGP2P_INFO(("tx action frame operation is completed\n")); - ret = BCME_OK; - } else if (ETHER_ISBCAST(&cfg->afx_hdl->tx_dst_addr)) { - CFGP2P_INFO(("bcast tx action frame operation is completed\n")); - ret = BCME_OK; - } else { - ret = BCME_ERROR; - CFGP2P_INFO(("tx action frame operation is failed\n")); - } - /* clear status bit for action tx */ - wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED); - wl_clr_p2p_status(cfg, ACTION_TX_NOACK); - -exit: - CFGP2P_INFO((" via act frame iovar : status = %d\n", ret)); - - bzero(&buf, sizeof(wl_eventmsg_buf_t)); - wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false); - wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false); - if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) { - WL_ERR(("TX frame events revert back failed \n")); - return evt_ret; - } - - return ret; -} - -/* Generate our P2P Device Address and P2P Interface Address from our primary - * MAC address. - */ -void -wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, - struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr) -{ - memset(out_dev_addr, 0, sizeof(*out_dev_addr)); - memset(out_int_addr, 0, sizeof(*out_int_addr)); - - /* Generate the P2P Device Address. This consists of the device's - * primary MAC address with the locally administered bit set. - */ - memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr)); - out_dev_addr->octet[0] |= 0x02; - - /* Generate the P2P Interface Address. If the discovery and connection - * BSSCFGs need to simultaneously co-exist, then this address must be - * different from the P2P Device Address. - */ - memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr)); - out_int_addr->octet[4] ^= 0x80; - -} - -/* P2P IF Address change to Virtual Interface MAC Address */ -void -wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id) -{ - wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf; - u16 len = ie->len; - u8 *subel; - u8 subelt_id; - u16 subelt_len; - CFGP2P_DBG((" Enter\n")); - - /* Point subel to the P2P IE's subelt field. - * Subtract the preceding fields (id, len, OUI, oui_type) from the length. - */ - subel = ie->subelts; - len -= 4; /* exclude OUI + OUI_TYPE */ - - while (len >= 3) { - /* attribute id */ - subelt_id = *subel; - subel += 1; - len -= 1; - - /* 2-byte little endian */ - subelt_len = *subel++; - subelt_len |= *subel++ << 8; - - len -= 2; - len -= subelt_len; /* for the remaining subelt fields */ - - if (subelt_id == element_id) { - if (subelt_id == P2P_SEID_INTINTADDR) { - memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); - CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n")); - } else if (subelt_id == P2P_SEID_DEV_ID) { - memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); - CFGP2P_INFO(("Device ID ATTR FOUND\n")); - } else if (subelt_id == P2P_SEID_DEV_INFO) { - memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); - CFGP2P_INFO(("Device INFO ATTR FOUND\n")); - } else if (subelt_id == P2P_SEID_GROUP_ID) { - memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); - CFGP2P_INFO(("GROUP ID ATTR FOUND\n")); - } return; - } else { - CFGP2P_DBG(("OTHER id : %d\n", subelt_id)); - } - subel += subelt_len; - } -} -/* - * Check if a BSS is up. - * This is a common implementation called by most OSL implementations of - * p2posl_bss_isup(). DO NOT call this function directly from the - * common code -- call p2posl_bss_isup() instead to allow the OSL to - * override the common implementation if necessary. - */ -bool -wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) -{ - s32 result, val; - bool isup = false; - s8 getbuf[64]; - - /* Check if the BSS is up */ - *(int*)getbuf = -1; - result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, - sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL); - if (result != 0) { - CFGP2P_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result)); - CFGP2P_ERR(("NOTE: this ioctl error is normal " - "when the BSS has not been created yet.\n")); - } else { - val = *(int*)getbuf; - val = dtoh32(val); - CFGP2P_INFO(("---cfg bss -C %d ==> %d\n", bsscfg_idx, val)); - isup = (val ? TRUE : FALSE); - } - return isup; -} - - -/* Bring up or down a BSS */ -s32 -wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up) -{ - s32 ret = BCME_OK; - s32 val = up ? 1 : 0; - - struct { - s32 cfg; - s32 val; - } bss_setbuf; - - bss_setbuf.cfg = htod32(bsscfg_idx); - bss_setbuf.val = htod32(val); - CFGP2P_INFO(("---cfg bss -C %d %s\n", bsscfg_idx, up ? "up" : "down")); - ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (ret != 0) { - CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret)); - } - - return ret; -} - -/* Check if 'p2p' is supported in the driver */ -s32 -wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - s32 ret = BCME_OK; - s32 p2p_supported = 0; - ret = wldev_iovar_getint(ndev, "p2p", - &p2p_supported); - if (ret < 0) { - if (ret == BCME_UNSUPPORTED) { - CFGP2P_INFO(("p2p is unsupported\n")); - return 0; - } else { - CFGP2P_ERR(("cfg p2p error %d\n", ret)); - return ret; - } - } - if (p2p_supported == 1) { - CFGP2P_INFO(("p2p is supported\n")); - } else { - CFGP2P_INFO(("p2p is unsupported\n")); - p2p_supported = 0; - } - return p2p_supported; -} -/* Cleanup P2P resources */ -s32 -wl_cfgp2p_down(struct bcm_cfg80211 *cfg) -{ - struct net_device *ndev = NULL; - struct wireless_dev *wdev = NULL; - s32 i = 0, index = -1; - -#if defined(WL_CFG80211_P2P_DEV_IF) - wdev = bcmcfg_to_p2p_wdev(cfg); - ndev = bcmcfg_to_prmry_ndev(cfg); -#elif defined(WL_ENABLE_P2P_IF) - ndev = cfg->p2p_net ? cfg->p2p_net : bcmcfg_to_prmry_ndev(cfg); - wdev = ndev_to_wdev(ndev); -#endif /* WL_CFG80211_P2P_DEV_IF */ - - wl_cfgp2p_cancel_listen(cfg, ndev, wdev, TRUE); - for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { - index = wl_to_p2p_bss_bssidx(cfg, i); - if (index != WL_INVALID) - wl_cfgp2p_clear_management_ie(cfg, index); - } - wl_cfgp2p_deinit_priv(cfg); - return 0; -} -s32 -wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len) -{ - s32 ret = -1; - int count, start, duration; - wl_p2p_sched_t dongle_noa; - - CFGP2P_DBG((" Enter\n")); - - memset(&dongle_noa, 0, sizeof(dongle_noa)); - - if (cfg->p2p && cfg->p2p->vif_created) { - - cfg->p2p->noa.desc[0].start = 0; - - sscanf(buf, "%10d %10d %10d", &count, &start, &duration); - CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n", - count, start, duration)); - if (count != -1) - cfg->p2p->noa.desc[0].count = count; - - /* supplicant gives interval as start */ - if (start != -1) - cfg->p2p->noa.desc[0].interval = start; - - if (duration != -1) - cfg->p2p->noa.desc[0].duration = duration; - - if (cfg->p2p->noa.desc[0].count != 255 && cfg->p2p->noa.desc[0].count != 0) { - cfg->p2p->noa.desc[0].start = 200; - dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS; - dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF; - dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; - } - else if (cfg->p2p->noa.desc[0].count == 0) { - cfg->p2p->noa.desc[0].start = 0; - dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; - dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; - dongle_noa.action = WL_P2P_SCHED_ACTION_RESET; - } - else { - /* Continuous NoA interval. */ - dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; - dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; - if ((cfg->p2p->noa.desc[0].interval == 102) || - (cfg->p2p->noa.desc[0].interval == 100)) { - cfg->p2p->noa.desc[0].start = 100 - - cfg->p2p->noa.desc[0].duration; - dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT; - } - else { - dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; - } - } - /* Put the noa descriptor in dongle format for dongle */ - dongle_noa.desc[0].count = htod32(cfg->p2p->noa.desc[0].count); - if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) { - dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start); - dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration); - } - else { - dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start*1000); - dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration*1000); - } - dongle_noa.desc[0].interval = htod32(cfg->p2p->noa.desc[0].interval*1000); - - ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION), - "p2p_noa", &dongle_noa, sizeof(dongle_noa), cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (ret < 0) { - CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret)); - } - } - else { - CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n")); - } - return ret; -} -s32 -wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int buf_len) -{ - - wifi_p2p_noa_desc_t *noa_desc; - int len = 0, i; - char _buf[200]; - - CFGP2P_DBG((" Enter\n")); - buf[0] = '\0'; - if (cfg->p2p && cfg->p2p->vif_created) { - if (cfg->p2p->noa.desc[0].count || cfg->p2p->ops.ops) { - _buf[0] = 1; /* noa index */ - _buf[1] = (cfg->p2p->ops.ops ? 0x80: 0) | - (cfg->p2p->ops.ctw & 0x7f); /* ops + ctw */ - len += 2; - if (cfg->p2p->noa.desc[0].count) { - noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len]; - noa_desc->cnt_type = cfg->p2p->noa.desc[0].count; - noa_desc->duration = cfg->p2p->noa.desc[0].duration; - noa_desc->interval = cfg->p2p->noa.desc[0].interval; - noa_desc->start = cfg->p2p->noa.desc[0].start; - len += sizeof(wifi_p2p_noa_desc_t); - } - if (buf_len <= len * 2) { - CFGP2P_ERR(("ERROR: buf_len %d in not enough for" - "returning noa in string format\n", buf_len)); - return -1; - } - /* We have to convert the buffer data into ASCII strings */ - for (i = 0; i < len; i++) { - snprintf(buf, 3, "%02x", _buf[i]); - buf += 2; - } - buf[i*2] = '\0'; - } - } - else { - CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n")); - return -1; - } - return len * 2; -} -s32 -wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len) -{ - int ps, ctw; - int ret = -1; - s32 legacy_ps; - struct net_device *dev; - - CFGP2P_DBG((" Enter\n")); - if (cfg->p2p && cfg->p2p->vif_created) { - sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw); - CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw)); - dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); - if (ctw != -1) { - cfg->p2p->ops.ctw = ctw; - ret = 0; - } - if (ps != -1) { - cfg->p2p->ops.ops = ps; - ret = wldev_iovar_setbuf(dev, - "p2p_ops", &cfg->p2p->ops, sizeof(cfg->p2p->ops), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (ret < 0) { - CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret)); - } - } - - if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) { - ret = wldev_ioctl(dev, - WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true); - if (unlikely(ret)) - CFGP2P_ERR(("error (%d)\n", ret)); - wl_cfg80211_update_power_mode(dev); - } - else - CFGP2P_ERR(("ilegal setting\n")); - } - else { - CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n")); - ret = -1; - } - return ret; -} - -u8 * -wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) -{ - wifi_p2p_ie_t *ie = NULL; - u16 len = 0; - u8 *subel; - u8 subelt_id; - u16 subelt_len; - - if (!buf) { - WL_ERR(("P2P IE not present")); - return 0; - } - - ie = (wifi_p2p_ie_t*) buf; - len = ie->len; - - /* Point subel to the P2P IE's subelt field. - * Subtract the preceding fields (id, len, OUI, oui_type) from the length. - */ - subel = ie->subelts; - len -= 4; /* exclude OUI + OUI_TYPE */ - - while (len >= 3) { - /* attribute id */ - subelt_id = *subel; - subel += 1; - len -= 1; - - /* 2-byte little endian */ - subelt_len = *subel++; - subelt_len |= *subel++ << 8; - - len -= 2; - len -= subelt_len; /* for the remaining subelt fields */ - - if (subelt_id == element_id) { - /* This will point to start of subelement attrib after - * attribute id & len - */ - return subel; - } - - /* Go to next subelement */ - subel += subelt_len; - } - - /* Not Found */ - return NULL; -} - -#define P2P_GROUP_CAPAB_GO_BIT 0x01 - -u8* -wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib) -{ - bcm_tlv_t *ie; - u8* pAttrib; - - CFGP2P_INFO(("Starting parsing parse %p attrib %d remaining len %d ", parse, attrib, len)); - while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len) == TRUE) { - /* Have the P2p ie. Now check for attribute */ - if ((pAttrib = wl_cfgp2p_retreive_p2pattrib(parse, attrib)) != NULL) { - CFGP2P_INFO(("P2P attribute %d was found at parse %p", - attrib, parse)); - return pAttrib; - } - else { - /* move to next IE */ - len -= (u32)((u8 *)ie + TLV_HDR_LEN + ie->len - parse); - parse = (uint8 *)ie + TLV_HDR_LEN + ie->len; - CFGP2P_INFO(("P2P Attribute %d not found Moving parse" - " to %p len to %d", attrib, parse, len)); - } - } - else { - /* It was not p2p IE. parse will get updated automatically to next TLV */ - CFGP2P_INFO(("IT was NOT P2P IE parse %p len %d", parse, len)); - } - } - CFGP2P_ERR(("P2P attribute %d was NOT found", attrib)); - return NULL; -} - -u8 * -wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) -{ - u8 *capability = NULL; - bool p2p_go = 0; - u8 *ptr = NULL; - - if ((capability = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, - bi->ie_length, P2P_SEID_P2P_INFO)) == NULL) { - WL_ERR(("P2P Capability attribute not found")); - return NULL; - } - - /* Check Group capability for Group Owner bit */ - p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT; - if (!p2p_go) { - return bi->BSSID.octet; - } - - /* In probe responses, DEVICE INFO attribute will be present */ - if (!(ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, - bi->ie_length, P2P_SEID_DEV_INFO))) { - /* If DEVICE_INFO is not found, this might be a beacon frame. - * check for DEVICE_ID in the beacon frame. - */ - ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, - bi->ie_length, P2P_SEID_DEV_ID); - } - - if (!ptr) - WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE ")); - - return ptr; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -static void -wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) -{ - snprintf(info->driver, sizeof(info->driver), "p2p"); - snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0)); -} - -struct ethtool_ops cfgp2p_ethtool_ops = { - .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - -#if defined(WL_ENABLE_P2P_IF) -s32 -wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg) -{ - int ret = 0; - struct net_device* net = NULL; - struct wireless_dev *wdev = NULL; - uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; - - if (cfg->p2p_net) { - CFGP2P_ERR(("p2p_net defined already.\n")); - return -EINVAL; - } - - /* Allocate etherdev, including space for private structure */ - if (!(net = alloc_etherdev(sizeof(struct bcm_cfg80211 *)))) { - CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); - return -ENODEV; - } - - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (unlikely(!wdev)) { - WL_ERR(("Could not allocate wireless device\n")); - free_netdev(net); - return -ENOMEM; - } - - strncpy(net->name, "p2p%d", sizeof(net->name) - 1); - net->name[IFNAMSIZ - 1] = '\0'; - - /* Copy the reference to bcm_cfg80211 */ - memcpy((void *)netdev_priv(net), &cfg, sizeof(struct bcm_cfg80211 *)); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - ASSERT(!net->open); - net->do_ioctl = wl_cfgp2p_do_ioctl; - net->hard_start_xmit = wl_cfgp2p_start_xmit; - net->open = wl_cfgp2p_if_open; - net->stop = wl_cfgp2p_if_stop; -#else - ASSERT(!net->netdev_ops); - net->netdev_ops = &wl_cfgp2p_if_ops; -#endif - - /* Register with a dummy MAC addr */ - memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); - - wdev->wiphy = cfg->wdev->wiphy; - - wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); - - net->ieee80211_ptr = wdev; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - net->ethtool_ops = &cfgp2p_ethtool_ops; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - - SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy)); - - /* Associate p2p0 network interface with new wdev */ - wdev->netdev = net; - - ret = register_netdev(net); - if (ret) { - CFGP2P_ERR((" register_netdevice failed (%d)\n", ret)); - free_netdev(net); - kfree(wdev); - return -ENODEV; - } - - /* store p2p net ptr for further reference. Note that iflist won't have this - * entry as there corresponding firmware interface is a "Hidden" interface. - */ - cfg->p2p_wdev = wdev; - cfg->p2p_net = net; - - printk("%s: P2P Interface Registered\n", net->name); - - return ret; -} - -s32 -wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg) -{ - - if (!cfg || !cfg->p2p_net) { - CFGP2P_ERR(("Invalid Ptr\n")); - return -EINVAL; - } - - unregister_netdev(cfg->p2p_net); - free_netdev(cfg->p2p_net); - - return 0; -} - -static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - - if (skb) - { - CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n", - ndev->name)); - dev_kfree_skb_any(skb); - } - - return 0; -} - -static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd) -{ - int ret = 0; - struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - - /* There is no ifidx corresponding to p2p0 in our firmware. So we should - * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs. - * For Android PRIV CMD handling map it to primary I/F - */ - if (cmd == SIOCDEVPRIVATE+1) { - ret = wl_android_priv_cmd(ndev, ifr, cmd); - - } else { - CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n", - __FUNCTION__, cmd)); - return -1; - } - - return ret; -} -#endif - -#if defined(WL_ENABLE_P2P_IF) -static int wl_cfgp2p_if_open(struct net_device *net) -{ - struct wireless_dev *wdev = net->ieee80211_ptr; - - if (!wdev || !wl_cfg80211_is_p2p_active()) - return -EINVAL; - WL_TRACE(("Enter\n")); -#if !defined(WL_IFACE_COMB_NUM_CHANNELS) - /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, - * do it here. This will make sure that in concurrent mode, supplicant - * is not dependent on a particular order of interface initialization. - * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N - * -iwlan0. - */ - wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) - | BIT(NL80211_IFTYPE_P2P_GO)); -#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ - wl_cfg80211_do_driver_init(net); - - return 0; -} - -static int wl_cfgp2p_if_stop(struct net_device *net) -{ - struct wireless_dev *wdev = net->ieee80211_ptr; - if (!wdev) - return -EINVAL; - - wl_cfg80211_scan_stop(net); - -#if !defined(WL_IFACE_COMB_NUM_CHANNELS) - wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) - & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| - BIT(NL80211_IFTYPE_P2P_GO))); -#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ - return 0; -} -#endif - -#if defined(WL_ENABLE_P2P_IF) -bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops) -{ - return (if_ops == &wl_cfgp2p_if_ops); -} -#endif /* WL_ENABLE_P2P_IF */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -struct wireless_dev * -wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg) -{ - struct wireless_dev *wdev = NULL; - struct ether_addr primary_mac; - - if (!cfg || !cfg->p2p_supported) - return ERR_PTR(-EINVAL); - - WL_TRACE(("Enter\n")); - - if (cfg->p2p_wdev) { - CFGP2P_ERR(("p2p_wdev defined already.\n")); -#if defined(CUSTOMER_HW5) - wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); - CFGP2P_ERR(("p2p_wdev deleted.\n")); -#else - return ERR_PTR(-ENFILE); -#endif - } - - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (unlikely(!wdev)) { - WL_ERR(("Could not allocate wireless device\n")); - return ERR_PTR(-ENOMEM); - } - - memset(&primary_mac, 0, sizeof(primary_mac)); - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, - &cfg->p2p->dev_addr, &cfg->p2p->int_addr); - - wdev->wiphy = cfg->wdev->wiphy; - wdev->iftype = NL80211_IFTYPE_P2P_DEVICE; - memcpy(wdev->address, &cfg->p2p->dev_addr, ETHER_ADDR_LEN); - - - /* store p2p wdev ptr for further reference. */ - cfg->p2p_wdev = wdev; - - CFGP2P_ERR(("P2P interface registered\n")); - - return wdev; -} - -int -wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) -{ - int ret = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (!cfg) - return -EINVAL; - - WL_TRACE(("Enter\n")); - - ret = wl_cfgp2p_set_firm_p2p(cfg); - if (unlikely(ret < 0)) { - CFGP2P_ERR(("Set P2P in firmware failed, ret=%d\n", ret)); - goto exit; - } - - ret = wl_cfgp2p_enable_discovery(cfg, bcmcfg_to_prmry_ndev(cfg), NULL, 0); - if (unlikely(ret < 0)) { - CFGP2P_ERR(("P2P enable discovery failed, ret=%d\n", ret)); - goto exit; - } - - p2p_on(cfg) = true; - - CFGP2P_DBG(("P2P interface started\n")); - -exit: - return ret; -} - -void -wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) -{ - int ret = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (!cfg) - return; - - WL_TRACE(("Enter\n")); - - ret = wl_cfg80211_scan_stop(wdev); - if (unlikely(ret < 0)) { - CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret)); - } - - if (!cfg->p2p) - return; - - ret = wl_cfgp2p_disable_discovery(cfg); - if (unlikely(ret < 0)) { - CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret)); - } - - p2p_on(cfg) = false; - - CFGP2P_DBG(("P2P interface stopped\n")); - - return; -} - -int -wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg) -{ - bool rollback_lock = false; - - if (!wdev) - return -EINVAL; - - - WL_TRACE(("Enter\n")); - - if (!rtnl_is_locked()) { - rtnl_lock(); - rollback_lock = true; - } - - cfg80211_unregister_wdev(wdev); - - if (rollback_lock) - rtnl_unlock(); - - kfree(wdev); - - if (cfg) - cfg->p2p_wdev = NULL; - - CFGP2P_ERR(("P2P interface unregistered\n")); - - return 0; -} -#endif /* WL_CFG80211_P2P_DEV_IF */ - -void -wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx) -{ - wifi_p2p_pub_act_frame_t *pact_frm; - int status = 0; - - if (!frame || (frame_len < (sizeof(*pact_frm) + WL_P2P_AF_STATUS_OFFSET - 1))) { - return; - } - - if (wl_cfgp2p_is_pub_action(frame, frame_len)) { - pact_frm = (wifi_p2p_pub_act_frame_t *)frame; - if (pact_frm->subtype == P2P_PAF_GON_RSP && tx) { - CFGP2P_ACTION(("Check TX P2P Group Owner Negotiation Rsp Frame status\n")); - status = pact_frm->elts[WL_P2P_AF_STATUS_OFFSET]; - if (status) { - cfg->need_wait_afrx = false; - return; - } - } - } - - cfg->need_wait_afrx = true; - return; -} - -int -wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request) -{ - if (request && (request->n_ssids == 1) && - (request->n_channels == 1) && - IS_P2P_SSID(request->ssids[0].ssid, WL_P2P_WILDCARD_SSID_LEN) && - (request->ssids[0].ssid_len > WL_P2P_WILDCARD_SSID_LEN)) { - return true; - } - return false; -} diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h deleted file mode 100644 index 327b75f574cd..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Linux cfgp2p driver - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgp2p.h 528497 2015-01-22 10:58:38Z $ - */ -#ifndef _wl_cfgp2p_h_ -#define _wl_cfgp2p_h_ -#include -#include - -struct bcm_cfg80211; -extern u32 wl_dbg_level; - -typedef struct wifi_p2p_ie wifi_wfd_ie_t; -/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not - * confuse this with a bsscfg index. This value is an index into the - * saved_ie[] array of structures which in turn contains a bsscfg index field. - */ -typedef enum { - P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ - P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ - P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ - P2PAPI_BSSCFG_MAX -} p2p_bsscfg_type_t; - -typedef enum { - P2P_SCAN_PURPOSE_MIN, - P2P_SCAN_SOCIAL_CHANNEL, /* scan for social channel */ - P2P_SCAN_AFX_PEER_NORMAL, /* scan for action frame search */ - P2P_SCAN_AFX_PEER_REDUCED, /* scan for action frame search with short time */ - P2P_SCAN_DURING_CONNECTED, /* scan during connected status */ - P2P_SCAN_CONNECT_TRY, /* scan for connecting */ - P2P_SCAN_NORMAL, /* scan during not-connected status */ - P2P_SCAN_PURPOSE_MAX -} p2p_scan_purpose_t; - -/* vendor ies max buffer length for probe response or beacon */ -#define VNDR_IES_MAX_BUF_LEN 1400 -/* normal vendor ies buffer length */ -#define VNDR_IES_BUF_LEN 512 - -/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */ -struct p2p_saved_ie { - u8 p2p_probe_req_ie[VNDR_IES_BUF_LEN]; - u8 p2p_probe_res_ie[VNDR_IES_MAX_BUF_LEN]; - u8 p2p_assoc_req_ie[VNDR_IES_BUF_LEN]; - u8 p2p_assoc_res_ie[VNDR_IES_BUF_LEN]; - u8 p2p_beacon_ie[VNDR_IES_MAX_BUF_LEN]; - u32 p2p_probe_req_ie_len; - u32 p2p_probe_res_ie_len; - u32 p2p_assoc_req_ie_len; - u32 p2p_assoc_res_ie_len; - u32 p2p_beacon_ie_len; -}; - -struct p2p_bss { - s32 bssidx; - struct net_device *dev; - struct p2p_saved_ie saved_ie; - void *private_data; -}; - -struct p2p_info { - bool on; /* p2p on/off switch */ - bool scan; - int16 search_state; - bool vif_created; - s8 vir_ifname[IFNAMSIZ]; - unsigned long status; - struct ether_addr dev_addr; - struct ether_addr int_addr; - struct p2p_bss bss[P2PAPI_BSSCFG_MAX]; - struct timer_list listen_timer; - wl_p2p_sched_t noa; - wl_p2p_ops_t ops; - wlc_ssid_t ssid; -}; - -#define MAX_VNDR_IE_NUMBER 5 - -struct parsed_vndr_ie_info { - char *ie_ptr; - u32 ie_len; /* total length including id & length field */ - vndr_ie_t vndrie; -}; - -struct parsed_vndr_ies { - u32 count; - struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; -}; - -/* dongle status */ -enum wl_cfgp2p_status { - WLP2P_STATUS_DISCOVERY_ON = 0, - WLP2P_STATUS_SEARCH_ENABLED, - WLP2P_STATUS_IF_ADDING, - WLP2P_STATUS_IF_DELETING, - WLP2P_STATUS_IF_CHANGING, - WLP2P_STATUS_IF_CHANGED, - WLP2P_STATUS_LISTEN_EXPIRED, - WLP2P_STATUS_ACTION_TX_COMPLETED, - WLP2P_STATUS_ACTION_TX_NOACK, - WLP2P_STATUS_SCANNING, - WLP2P_STATUS_GO_NEG_PHASE, - WLP2P_STATUS_DISC_IN_PROGRESS -}; - - -#define wl_to_p2p_bss_ndev(cfg, type) ((cfg)->p2p->bss[type].dev) -#define wl_to_p2p_bss_bssidx(cfg, type) ((cfg)->p2p->bss[type].bssidx) -#define wl_to_p2p_bss_saved_ie(cfg, type) ((cfg)->p2p->bss[type].saved_ie) -#define wl_to_p2p_bss_private(cfg, type) ((cfg)->p2p->bss[type].private_data) -#define wl_to_p2p_bss(cfg, type) ((cfg)->p2p->bss[type]) -#define wl_get_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ - test_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) -#define wl_set_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ - set_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) -#define wl_clr_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ - clear_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) -#define wl_chg_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ - change_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) -#define p2p_on(cfg) ((cfg)->p2p->on) -#define p2p_scan(cfg) ((cfg)->p2p->scan) -#define p2p_is_on(cfg) ((cfg)->p2p && (cfg)->p2p->on) - -/* dword align allocation */ -#define WLC_IOCTL_MAXLEN 8192 - -#define CFGP2P_ERROR_TEXT "CFGP2P-ERROR) " - - -#define CFGP2P_ERR(args) \ - do { \ - if (wl_dbg_level & WL_DBG_ERR) { \ - printk(KERN_INFO CFGP2P_ERROR_TEXT "%s : ", __func__); \ - printk args; \ - } \ - } while (0) -#define CFGP2P_INFO(args) \ - do { \ - if (wl_dbg_level & WL_DBG_INFO) { \ - printk(KERN_INFO "CFGP2P-INFO) %s : ", __func__); \ - printk args; \ - } \ - } while (0) -#define CFGP2P_DBG(args) \ - do { \ - if (wl_dbg_level & WL_DBG_DBG) { \ - printk(KERN_DEBUG "CFGP2P-DEBUG) %s :", __func__); \ - printk args; \ - } \ - } while (0) - -#define CFGP2P_ACTION(args) \ - do { \ - if (wl_dbg_level & WL_DBG_P2P_ACTION) { \ - printk(KERN_DEBUG "CFGP2P-ACTION) %s :", __func__); \ - printk args; \ - } \ - } while (0) -#define INIT_TIMER(timer, func, duration, extra_delay) \ - do { \ - init_timer(timer); \ - timer->function = func; \ - timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ - timer->data = (unsigned long) cfg; \ - add_timer(timer); \ - } while (0); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_CFG80211_P2P_DEV_IF) -#define WL_CFG80211_P2P_DEV_IF - -#ifdef WL_ENABLE_P2P_IF -#undef WL_ENABLE_P2P_IF -#endif - -#ifdef WL_SUPPORT_BACKPORTED_KPATCHES -#undef WL_SUPPORT_BACKPORTED_KPATCHES -#endif -#else -#ifdef WLP2P -#ifndef WL_ENABLE_P2P_IF -/* Enable P2P network Interface if P2P support is enabled */ -#define WL_ENABLE_P2P_IF -#endif /* WL_ENABLE_P2P_IF */ -#endif /* WLP2P */ -#endif /* (LINUX_VERSION >= VERSION(3, 8, 0)) */ - -#ifndef WL_CFG80211_P2P_DEV_IF -#endif /* WL_CFG80211_P2P_DEV_IF */ - -#if defined(WL_ENABLE_P2P_IF) && (defined(WL_CFG80211_P2P_DEV_IF) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))) -#error Disable 'WL_ENABLE_P2P_IF', if 'WL_CFG80211_P2P_DEV_IF' is enabled \ - or kernel version is 3.8.0 or above -#endif /* WL_ENABLE_P2P_IF && (WL_CFG80211_P2P_DEV_IF || (LINUX_VERSION >= VERSION(3, 8, 0))) */ - -#if !defined(WLP2P) && (defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)) -#error WLP2P not defined -#endif /* !WLP2P && (WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF) */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -#define bcm_struct_cfgdev struct wireless_dev -#else -#define bcm_struct_cfgdev struct net_device -#endif /* WL_CFG80211_P2P_DEV_IF */ - -extern void -wl_cfgp2p_listen_expired(unsigned long data); -extern bool -wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); -extern bool -wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); -extern bool -wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); -extern bool -wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len); -extern bool -wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len); -extern void -wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel); -extern s32 -wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg); -extern void -wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg); -extern s32 -wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg); -extern s32 -wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, - u32 channel, u16 listen_ms, int bssidx); -extern s32 -wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, - chanspec_t chspec); -extern s32 -wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac); -extern s32 -wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac); -extern s32 -wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, chanspec_t chspec); - -extern s32 -wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index); - -extern s32 -wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg); -extern s32 -wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *ie, - u32 ie_len); -extern s32 -wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg); -extern s32 -wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, u32 num_chans, - u16 *channels, - s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, - p2p_scan_purpose_t p2p_scan_purpose); - -extern s32 -wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, - s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr); - -extern wpa_ie_fixed_t * -wl_cfgp2p_find_wpaie(u8 *parse, u32 len); - -extern wpa_ie_fixed_t * -wl_cfgp2p_find_wpsie(u8 *parse, u32 len); - -extern wifi_p2p_ie_t * -wl_cfgp2p_find_p2pie(u8 *parse, u32 len); - -extern wifi_wfd_ie_t * -wl_cfgp2p_find_wfdie(u8 *parse, u32 len); -extern s32 -wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, - s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len); -extern s32 -wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx); - -extern s32 -wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *index); -extern struct net_device * -wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx); -extern s32 -wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type); - - -extern s32 -wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -extern s32 -wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms); - -extern s32 -wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable); - -extern s32 -wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); - -extern s32 -wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, - wl_af_params_t *af_params, s32 bssidx); - -extern void -wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr, - struct ether_addr *out_int_addr); - -extern void -wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); -extern bool -wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); - -extern s32 -wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up); - - -extern s32 -wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev); - -extern s32 -wl_cfgp2p_down(struct bcm_cfg80211 *cfg); - -extern s32 -wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); - -extern s32 -wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); - -extern s32 -wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); - -extern u8 * -wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id); - -extern u8* -wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib); - -extern u8 * -wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length); - -extern s32 -wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg); - -extern s32 -wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg); - -extern bool -wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops); - -#if defined(WL_CFG80211_P2P_DEV_IF) -extern struct wireless_dev * -wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg); - -extern int -wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); - -extern void -wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); - -extern int -wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ - -extern void -wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx); - -extern int -wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request); - -/* WiFi Direct */ -#define SOCIAL_CHAN_1 1 -#define SOCIAL_CHAN_2 6 -#define SOCIAL_CHAN_3 11 -#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ - (channel == SOCIAL_CHAN_2) || \ - (channel == SOCIAL_CHAN_3)) -#define SOCIAL_CHAN_CNT 3 -#define AF_PEER_SEARCH_CNT 2 -#define WL_P2P_WILDCARD_SSID "DIRECT-" -#define WL_P2P_WILDCARD_SSID_LEN 7 -#define WL_P2P_INTERFACE_PREFIX "p2p" -#define WL_P2P_TEMP_CHAN 11 -#define WL_P2P_AF_STATUS_OFFSET 9 - -/* If the provision discovery is for JOIN operations, - * or the device discoverablity frame is destined to GO - * then we need not do an internal scan to find GO. - */ -#define IS_ACTPUB_WITHOUT_GROUP_ID(p2p_ie, len) \ - (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL) - -#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ - ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ - (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) - -#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \ - ((subtype == P2P_PAF_GON_CONF) || \ - (subtype == P2P_PAF_INVITE_RSP) || \ - (subtype == P2P_PAF_PROVDIS_RSP))) -#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) -#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \ - (len == WL_P2P_WILDCARD_SSID_LEN)) -#endif /* _wl_cfgp2p_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c deleted file mode 100644 index 65bd87c8fb32..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c +++ /dev/null @@ -1,2214 +0,0 @@ -/* - * Linux cfg80211 Vendor Extension Code - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgvendor.c 455257 2014-02-20 08:10:24Z $ -*/ - -/* - * New vendor interface additon to nl80211/cfg80211 to allow vendors - * to implement proprietary features over the cfg80211 stack. -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#ifdef PNO_SUPPORT -#include -#endif /* PNO_SUPPORT */ -#ifdef RTT_SUPPORT -#include -#endif /* RTT_SUPPORT */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#ifdef PROP_TXSTATUS -#include -#endif -#include - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) -/* - * This API is to be used for asynchronous vendor events. This - * shouldn't be used in response to a vendor command from its - * do_it handler context (instead wl_cfgvendor_send_cmd_reply should - * be used). - */ -int wl_cfgvendor_send_async_event(struct wiphy *wiphy, - struct net_device *dev, int event_id, const void *data, int len) -{ - u16 kflags; - struct sk_buff *skb; - - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags); - if (!skb) { - WL_ERR(("skb alloc failed")); - return -ENOMEM; - } - - /* Push the data to the skb */ - nla_put_nohdr(skb, len, data); - - cfg80211_vendor_event(skb, kflags); - - return 0; -} - -static int -wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy, - struct net_device *dev, const void *data, int len) -{ - struct sk_buff *skb; - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); - if (unlikely(!skb)) { - WL_ERR(("skb alloc failed")); - return -ENOMEM; - } - - /* Push the data to the skb */ - nla_put_nohdr(skb, len, data); - - return cfg80211_vendor_cmd_reply(skb); -} - -static int wl_cfgvendor_get_feature_set(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int reply; - - reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg)); - - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - &reply, sizeof(int)); - - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - - return err; -} - -static int wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct sk_buff *skb; - int *reply; - int num, mem_needed, i; - - reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), &num); - - if (!reply) { - WL_ERR(("Could not get feature list matrix\n")); - err = -EINVAL; - return err; - } - - mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * num) + - ATTRIBUTE_U32_LEN; - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); - if (unlikely(!skb)) { - WL_ERR(("skb alloc failed")); - err = -ENOMEM; - goto exit; - } - - nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, num); - for (i = 0; i < num; i++) { - nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply[i]); - } - - err = cfg80211_vendor_cmd_reply(skb); - - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); -exit: - kfree(reply); - return err; -} - -static int -wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type; - uint8 random_mac_oui[DOT11_OUI_LEN]; - - type = nla_type(data); - - if (type == ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI) { - memcpy(random_mac_oui, nla_data(data), DOT11_OUI_LEN); - - err = dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg), random_mac_oui); - - if (unlikely(err)) - WL_ERR(("Bad OUI, could not set:%d \n", err)); - - } else { - err = -1; - } - - return err; -} - -static int wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; -#ifdef CUSTOM_FORCE_NODFS_FLAG - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type; - u32 nodfs; - - type = nla_type(data); - if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) { - nodfs = nla_get_u32(data); - err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs); - } else { - err = -1; - } -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - return err; -} - -#ifdef GSCAN_SUPPORT -int -wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, - struct net_device *dev, void *data, int len, wl_vendor_event_t event) -{ - u16 kflags; - const void *ptr; - struct sk_buff *skb; - int malloc_len, total, iter_cnt_to_send, cnt; - gscan_results_cache_t *cache = (gscan_results_cache_t *)data; - - total = len/sizeof(wifi_gscan_result_t); - while (total > 0) { - malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD; - if (malloc_len > NLMSG_DEFAULT_SIZE) { - malloc_len = NLMSG_DEFAULT_SIZE; - } - iter_cnt_to_send = - (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t); - total = total - iter_cnt_to_send; - - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags); - if (!skb) { - WL_ERR(("skb alloc failed")); - return -ENOMEM; - } - - while (cache && iter_cnt_to_send) { - ptr = (const void *) &cache->results[cache->tot_consumed]; - - if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) { - cnt = iter_cnt_to_send; - } else { - cnt = (cache->tot_count - cache->tot_consumed); - } - - iter_cnt_to_send -= cnt; - cache->tot_consumed += cnt; - /* Push the data to the skb */ - nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr); - if (cache->tot_consumed == cache->tot_count) { - cache = cache->next; - } - - } - - cfg80211_vendor_event(skb, kflags); - } - - return 0; -} - -static int -wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_pno_gscan_capabilities_t *reply = NULL; - uint32 reply_len = 0; - - - reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GET_CAPABILITIES, NULL, &reply_len); - if (!reply) { - WL_ERR(("Could not get capabilities\n")); - err = -EINVAL; - return err; - } - - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - reply, reply_len); - - if (unlikely(err)) { - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - } - - kfree(reply); - return err; -} - -static int -wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0, type, band; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - uint16 *reply = NULL; - uint32 reply_len = 0, num_channels, mem_needed; - struct sk_buff *skb; - - type = nla_type(data); - - if (type == GSCAN_ATTRIBUTE_BAND) { - band = nla_get_u32(data); - } else { - return -EINVAL; - } - - reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len); - - if (!reply) { - WL_ERR(("Could not get channel list\n")); - err = -EINVAL; - return err; - } - num_channels = reply_len/ sizeof(uint32); - mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2); - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); - if (unlikely(!skb)) { - WL_ERR(("skb alloc failed")); - err = -ENOMEM; - goto exit; - } - - nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels); - nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply); - - err = cfg80211_vendor_cmd_reply(skb); - - if (unlikely(err)) { - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - } -exit: - kfree(reply); - return err; -} - -static int -wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_results_cache_t *results, *iter; - uint32 reply_len, complete = 1; - int32 mem_needed, num_results_iter; - wifi_gscan_result_t *ptr; - uint16 num_scan_ids, num_results; - struct sk_buff *skb; - struct nlattr *scan_hdr, *complete_flag; - - err = dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg)); - if (err != BCME_OK) - return -EBUSY; - - err = dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); - if (err != BCME_OK) { - WL_ERR(("Can't obtain lock to access batch results %d\n", err)); - return -EBUSY; - } - results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len); - - if (!results) { - WL_ERR(("No results to send %d\n", err)); - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - results, 0); - - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); - return err; - } - num_scan_ids = reply_len & 0xFFFF; - num_results = (reply_len & 0xFFFF0000) >> 16; - mem_needed = (num_results * sizeof(wifi_gscan_result_t)) + - (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) + - VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN; - - if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) { - mem_needed = (int32)NLMSG_DEFAULT_SIZE; - } - - WL_TRACE(("complete %d mem_needed %d max_mem %d\n", complete, mem_needed, - (int)NLMSG_DEFAULT_SIZE)); - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); - if (unlikely(!skb)) { - WL_ERR(("skb alloc failed")); - dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); - return -ENOMEM; - } - iter = results; - complete_flag = nla_reserve(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, - sizeof(complete)); - mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD); - - while (iter) { - num_results_iter = (mem_needed - (int32)GSCAN_BATCH_RESULT_HDR_LEN); - num_results_iter /= ((int32)sizeof(wifi_gscan_result_t)); - if (num_results_iter <= 0 || - ((iter->tot_count - iter->tot_consumed) > num_results_iter)) { - break; - } - scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS); - /* no more room? we are done then (for now) */ - if (scan_hdr == NULL) { - complete = 0; - break; - } - nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id); - nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag); - num_results_iter = iter->tot_count - iter->tot_consumed; - - nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter); - if (num_results_iter) { - ptr = &iter->results[iter->tot_consumed]; - iter->tot_consumed += num_results_iter; - nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, - num_results_iter * sizeof(wifi_gscan_result_t), ptr); - } - nla_nest_end(skb, scan_hdr); - mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN + - (num_results_iter * sizeof(wifi_gscan_result_t)); - iter = iter->next; - } - /* Returns TRUE if all result consumed */ - complete = dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg)); - memcpy(nla_data(complete_flag), &complete, sizeof(complete)); - dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); - return cfg80211_vendor_cmd_reply(skb); -} - -static int -wl_cfgvendor_initiate_gscan(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type, tmp = len; - int run = 0xFF; - int flush = 0; - const struct nlattr *iter; - - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE) - run = nla_get_u32(iter); - else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE) - flush = nla_get_u32(iter); - } - - if (run != 0xFF) { - err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush); - - if (unlikely(err)) { - WL_ERR(("Could not run gscan:%d \n", err)); - } - return err; - } else { - return -EINVAL; - } - - -} - -static int -wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type; - bool real_time = FALSE; - - type = nla_type(data); - - if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) { - real_time = nla_get_u32(data); - - err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time); - - if (unlikely(err)) { - WL_ERR(("Could not run gscan:%d \n", err)); - } - - } else { - err = -EINVAL; - } - - return err; -} - -static int -wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev, - gscan_scan_params_t *scan_param, int num) -{ - struct dhd_pno_gscan_channel_bucket *ch_bucket; - int k = 0; - int type, err = 0, rem; - const struct nlattr *cur, *next; - - nla_for_each_nested(cur, prev, rem) { - type = nla_type(cur); - ch_bucket = scan_param->channel_bucket; - - switch (type) { - case GSCAN_ATTRIBUTE_BUCKET_ID: - break; - case GSCAN_ATTRIBUTE_BUCKET_PERIOD: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - - ch_bucket[num].bucket_freq_multiple = - nla_get_u32(cur)/1000; - break; - case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].num_channels = - nla_get_u32(cur); - if (ch_bucket[num].num_channels > - GSCAN_MAX_CHANNELS_IN_BUCKET) { - WL_ERR(("channel range:%d,bucket:%d\n", - ch_bucket[num].num_channels, - num)); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_BUCKET_CHANNELS: - nla_for_each_nested(next, cur, rem) { - if (k >= - GSCAN_MAX_CHANNELS_IN_BUCKET) { - break; - } - if (nla_len(next) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].chan_list[k] = - nla_get_u32(next); - k++; - } - break; - case GSCAN_ATTRIBUTE_BUCKETS_BAND: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].band = (uint16) - nla_get_u32(cur); - break; - case GSCAN_ATTRIBUTE_REPORT_EVENTS: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].report_flag = (uint8) - nla_get_u32(cur); - break; - case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].repeat = (uint16) - nla_get_u32(cur); - break; - case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].bucket_max_multiple = - nla_get_u32(cur)/1000; - break; - default: - WL_ERR(("bucket attribute type error %d\n", - type)); - err = -EINVAL; - goto exit; - } - } - -exit: - return err; -} - - -static int -wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_scan_params_t *scan_param; - int j = 0; - int type, tmp; - const struct nlattr *iter; - - scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL); - if (!scan_param) { - WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n")); - err = -EINVAL; - return err; - - } - - scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC; - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - - if (j >= GSCAN_MAX_CH_BUCKETS) { - break; - } - - switch (type) { - case GSCAN_ATTRIBUTE_BASE_PERIOD: - if (nla_len(iter) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - scan_param->scan_fr = nla_get_u32(iter)/1000; - break; - case GSCAN_ATTRIBUTE_NUM_BUCKETS: - if (nla_len(iter) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - scan_param->nchannel_buckets = nla_get_u32(iter); - if (scan_param->nchannel_buckets >= - GSCAN_MAX_CH_BUCKETS) { - WL_ERR(("ncha_buck out of range %d\n", - scan_param->nchannel_buckets)); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_CH_BUCKET_1: - case GSCAN_ATTRIBUTE_CH_BUCKET_2: - case GSCAN_ATTRIBUTE_CH_BUCKET_3: - case GSCAN_ATTRIBUTE_CH_BUCKET_4: - case GSCAN_ATTRIBUTE_CH_BUCKET_5: - case GSCAN_ATTRIBUTE_CH_BUCKET_6: - case GSCAN_ATTRIBUTE_CH_BUCKET_7: - err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j); - if (err < 0) { - WL_ERR(("set_scan_cfg_buck error:%d\n", err)); - goto exit; - } - j++; - break; - default: - WL_ERR(("Unknown type %d\n", type)); - err = -EINVAL; - goto exit; - } - } - - err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_SCAN_CFG_ID, scan_param, 0); - - if (err < 0) { - WL_ERR(("Could not set GSCAN scan cfg\n")); - err = -EINVAL; - } - -exit: - kfree(scan_param); - return err; - -} - -static int -wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_hotlist_scan_params_t *hotlist_params; - int tmp, tmp1, tmp2, type, j = 0, dummy; - const struct nlattr *outer, *inner = NULL, *iter; - uint8 flush = 0; - struct bssid_t *pbssid; - - if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) { - WL_ERR(("buffer length :%d wrong - bail out.\n", len)); - return -EINVAL; - } - hotlist_params = kzalloc(sizeof(*hotlist_params) - + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)), - GFP_KERNEL); - - if (!hotlist_params) { - WL_ERR(("Cannot Malloc memory.\n")); - return -ENOMEM; - } - - hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT; - - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT: - if (nla_len(iter) != sizeof(uint32)) { - WL_DBG(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - hotlist_params->nbssid = (uint16)nla_get_u32(iter); - if ((hotlist_params->nbssid == 0) || - (hotlist_params->nbssid > PFN_SWC_MAX_NUM_APS)) { - WL_ERR(("nbssid:%d exceed limit.\n", - hotlist_params->nbssid)); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS: - if (hotlist_params->nbssid == 0) { - WL_ERR(("nbssid not retrieved.\n")); - err = -EINVAL; - goto exit; - } - pbssid = hotlist_params->bssid; - nla_for_each_nested(outer, iter, tmp) { - nla_for_each_nested(inner, outer, tmp1) { - if (j >= hotlist_params->nbssid) - break; - type = nla_type(inner); - - switch (type) { - case GSCAN_ATTRIBUTE_BSSID: - if (nla_len(inner) != sizeof(pbssid[j].macaddr)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - memcpy(&(pbssid[j].macaddr), - nla_data(inner), - sizeof(pbssid[j].macaddr)); - break; - case GSCAN_ATTRIBUTE_RSSI_LOW: - if (nla_len(inner) != sizeof(uint8)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - pbssid[j].rssi_reporting_threshold = - (int8)nla_get_u8(inner); - break; - case GSCAN_ATTRIBUTE_RSSI_HIGH: - if (nla_len(inner) != sizeof(uint8)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - dummy = (int8)nla_get_u8(inner); - break; - default: - WL_ERR(("ATTR unknown %d\n", type)); - err = -EINVAL; - goto exit; - } - } - j++; - } - if (j != hotlist_params->nbssid) { - WL_ERR(("bssid_cnt:%d != nbssid:%d.\n", j, - hotlist_params->nbssid)); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_HOTLIST_FLUSH: - if (nla_len(iter) != sizeof(uint8)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - flush = nla_get_u8(iter); - break; - case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: - if (nla_len(iter) != sizeof(uint32)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter); - break; - default: - WL_ERR(("Unknown type %d\n", type)); - err = -EINVAL; - goto exit; - } - } - - if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) { - WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err)); - err = -EINVAL; - goto exit; - } -exit: - kfree(hotlist_params); - return err; -} - -static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_epno_params_t *epno_params; - int tmp, tmp1, tmp2, type, num = 0; - const struct nlattr *outer, *inner, *iter; - uint8 flush = 0, i = 0; - uint16 num_visible_ssid = 0; - - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_EPNO_SSID_LIST: - nla_for_each_nested(outer, iter, tmp) { - epno_params = (dhd_epno_params_t *) - dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GET_EPNO_SSID_ELEM, NULL, &num); - if (!epno_params) { - WL_ERR(("Failed to get SSID LIST buffer\n")); - err = -ENOMEM; - goto exit; - } - i++; - nla_for_each_nested(inner, outer, tmp1) { - type = nla_type(inner); - - switch (type) { - case GSCAN_ATTRIBUTE_EPNO_SSID: - memcpy(epno_params->ssid, - nla_data(inner), - DOT11_MAX_SSID_LEN); - break; - case GSCAN_ATTRIBUTE_EPNO_SSID_LEN: - len = nla_get_u8(inner); - if (len < DOT11_MAX_SSID_LEN) { - epno_params->ssid_len = len; - } else { - WL_ERR(("SSID toolong %d\n", - len)); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_EPNO_RSSI: - epno_params->rssi_thresh = - (int8) nla_get_u32(inner); - break; - case GSCAN_ATTRIBUTE_EPNO_FLAGS: - epno_params->flags = - nla_get_u8(inner); - if (!(epno_params->flags & - DHD_PNO_USE_SSID)) - num_visible_ssid++; - break; - case GSCAN_ATTRIBUTE_EPNO_AUTH: - epno_params->auth = - nla_get_u8(inner); - break; - } - } - } - break; - case GSCAN_ATTRIBUTE_EPNO_SSID_NUM: - num = nla_get_u8(iter); - break; - case GSCAN_ATTRIBUTE_EPNO_FLUSH: - flush = nla_get_u8(iter); - dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_EPNO_CFG_ID, NULL, flush); - break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - err = -EINVAL; - goto exit; - } - - } - if (i != num) { - WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__, - num, i)); - err = -EINVAL; - } -exit: - /* Flush all configs if error condition */ - flush = (err < 0) ? TRUE: FALSE; - dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_EPNO_CFG_ID, &num_visible_ssid, flush); - return err; -} - -static int -wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0, tmp, type; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_batch_params_t batch_param; - const struct nlattr *iter; - - batch_param.mscan = batch_param.bestn = 0; - batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET; - - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - - switch (type) { - case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN: - batch_param.bestn = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE: - batch_param.mscan = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_REPORT_THRESHOLD: - batch_param.buffer_threshold = nla_get_u32(iter); - break; - default: - WL_ERR(("Unknown type %d\n", type)); - break; - } - } - - if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_BATCH_SCAN_CFG_ID, - &batch_param, 0) < 0) { - WL_ERR(("Could not set batch cfg\n")); - err = -EINVAL; - return err; - } - - return err; -} - -static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = -EINVAL; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type; - uint32 lazy_roam_enable_flag; - - type = nla_type(data); - - if (type == GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE) { - lazy_roam_enable_flag = nla_get_u32(data); - - err = dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg), - lazy_roam_enable_flag); - - if (unlikely(err)) - WL_ERR(("Could not enable lazy roam:%d \n", err)); - - } - return err; -} - -static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0, tmp, type; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - wlc_roam_exp_params_t roam_param; - const struct nlattr *iter; - - memset(&roam_param, 0, sizeof(roam_param)); - - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - - switch (type) { - case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD: - roam_param.a_band_boost_threshold = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD: - roam_param.a_band_penalty_threshold = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR: - roam_param.a_band_boost_factor = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR: - roam_param.a_band_penalty_factor = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST: - roam_param.a_band_max_boost = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS: - roam_param.cur_bssid_boost = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER: - roam_param.alert_roam_trigger_threshold = nla_get_u32(iter); - break; - } - } - - if (dhd_dev_set_lazy_roam_cfg(bcmcfg_to_prmry_ndev(cfg), &roam_param) < 0) { - WL_ERR(("Could not set batch cfg\n")); - err = -EINVAL; - } - return err; -} - -/* small helper function */ -static wl_bssid_pref_cfg_t * -create_bssid_pref_cfg(uint32 num) -{ - uint32 mem_needed; - wl_bssid_pref_cfg_t *bssid_pref; - - mem_needed = sizeof(wl_bssid_pref_cfg_t); - if (num) - mem_needed += (num - 1) * sizeof(wl_bssid_pref_list_t); - bssid_pref = (wl_bssid_pref_cfg_t *) kmalloc(mem_needed, GFP_KERNEL); - return bssid_pref; -} - -static int -wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - wl_bssid_pref_cfg_t *bssid_pref = NULL; - wl_bssid_pref_list_t *bssids; - int tmp, tmp1, tmp2, type; - const struct nlattr *outer, *inner, *iter; - uint32 flush = 0, i = 0, num = 0; - - /* Assumption: NUM attribute must come first */ - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_NUM_BSSID: - num = nla_get_u32(iter); - if (num > MAX_BSSID_PREF_LIST_NUM) { - WL_ERR(("Too many Preferred BSSIDs!\n")); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH: - flush = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_BSSID_PREF_LIST: - if (!num) - return -EINVAL; - if ((bssid_pref = create_bssid_pref_cfg(num)) == NULL) { - WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__)); - err = -ENOMEM; - goto exit; - } - bssid_pref->count = num; - bssids = bssid_pref->bssids; - nla_for_each_nested(outer, iter, tmp) { - if (i >= num) { - WL_ERR(("CFGs don't seem right!\n")); - err = -EINVAL; - goto exit; - } - nla_for_each_nested(inner, outer, tmp1) { - type = nla_type(inner); - switch (type) { - case GSCAN_ATTRIBUTE_BSSID_PREF: - memcpy(&(bssids[i].bssid), - nla_data(inner), ETHER_ADDR_LEN); - /* not used for now */ - bssids[i].flags = 0; - break; - case GSCAN_ATTRIBUTE_RSSI_MODIFIER: - bssids[i].rssi_factor = - (int8) nla_get_u32(inner); - break; - } - } - i++; - } - break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - break; - } - } - - if (!bssid_pref) { - /* What if only flush is desired? */ - if (flush) { - if ((bssid_pref = create_bssid_pref_cfg(0)) == NULL) { - WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__)); - err = -ENOMEM; - goto exit; - } - bssid_pref->count = 0; - } else { - err = -EINVAL; - goto exit; - } - } - err = dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg), - bssid_pref, flush); -exit: - kfree(bssid_pref); - return err; -} - - -static int -wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - maclist_t *blacklist = NULL; - int err = 0; - int type, tmp; - const struct nlattr *iter; - uint32 mem_needed = 0, flush = 0, i = 0, num = 0; - - /* Assumption: NUM attribute must come first */ - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_NUM_BSSID: - num = nla_get_u32(iter); - if (num > MAX_BSSID_BLACKLIST_NUM) { - WL_ERR(("Too many Blacklist BSSIDs!\n")); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH: - flush = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_BLACKLIST_BSSID: - if (num) { - if (!blacklist) { - mem_needed = sizeof(maclist_t) + - sizeof(struct ether_addr) * (num - 1); - blacklist = (maclist_t *) - kmalloc(mem_needed, GFP_KERNEL); - if (!blacklist) { - WL_ERR(("%s: Can't malloc %d bytes\n", - __FUNCTION__, mem_needed)); - err = -ENOMEM; - goto exit; - } - blacklist->count = num; - } - if (i >= num) { - WL_ERR(("CFGs don't seem right!\n")); - err = -EINVAL; - goto exit; - } - memcpy(&(blacklist->ea[i]), - nla_data(iter), ETHER_ADDR_LEN); - i++; - } - break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - break; - } - } - err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg), - blacklist, mem_needed, flush); -exit: - kfree(blacklist); - return err; -} - -static int -wl_cfgvendor_set_ssid_whitelist(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - wl_ssid_whitelist_t *ssid_whitelist = NULL; - wlc_ssid_t *ssid_elem; - int tmp, tmp2, mem_needed = 0, type; - const struct nlattr *inner, *iter; - uint32 flush = 0, i = 0, num = 0; - - /* Assumption: NUM attribute must come first */ - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_NUM_WL_SSID: - num = nla_get_u32(iter); - if (num > MAX_SSID_WHITELIST_NUM) { - WL_ERR(("Too many WL SSIDs!\n")); - err = -EINVAL; - goto exit; - } - mem_needed = sizeof(wl_ssid_whitelist_t); - if (num) - mem_needed += (num - 1) * sizeof(ssid_info_t); - ssid_whitelist = (wl_ssid_whitelist_t *) - kzalloc(mem_needed, GFP_KERNEL); - if (ssid_whitelist == NULL) { - WL_ERR(("%s: Can't malloc %d bytes\n", - __FUNCTION__, mem_needed)); - err = -ENOMEM; - goto exit; - } - ssid_whitelist->ssid_count = num; - break; - case GSCAN_ATTRIBUTE_WL_SSID_FLUSH: - flush = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM: - if (!num || !ssid_whitelist) { - WL_ERR(("num ssid is not set!\n")); - return -EINVAL; - } - if (i >= num) { - WL_ERR(("CFGs don't seem right!\n")); - err = -EINVAL; - goto exit; - } - ssid_elem = &ssid_whitelist->ssids[i]; - nla_for_each_nested(inner, iter, tmp) { - type = nla_type(inner); - switch (type) { - case GSCAN_ATTRIBUTE_WHITELIST_SSID: - memcpy(ssid_elem->SSID, - nla_data(inner), - DOT11_MAX_SSID_LEN); - break; - case GSCAN_ATTRIBUTE_WL_SSID_LEN: - ssid_elem->SSID_len = (uint8) - nla_get_u32(inner); - break; - } - } - i++; - break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - break; - } - } - - err = dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg), - ssid_whitelist, mem_needed, flush); -exit: - kfree(ssid_whitelist); - return err; -} -#endif /* GSCAN_SUPPORT */ - -static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0, tmp, type, start = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int8 max_rssi = 0, min_rssi = 0; - const struct nlattr *iter; - - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - switch (type) { - case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI: - max_rssi = (int8) nla_get_u32(iter); - break; - case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI: - min_rssi = (int8) nla_get_u32(iter); - break; - case RSSI_MONITOR_ATTRIBUTE_START: - start = nla_get_u32(iter); - } - } - - if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg), - start, max_rssi, min_rssi) < 0) { - WL_ERR(("Could not set rssi monitor cfg\n")); - err = -EINVAL; - } - return err; -} - -#ifdef RTT_SUPPORT -void -wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data) -{ - struct wireless_dev *wdev = (struct wireless_dev *)ctx; - struct wiphy *wiphy; - struct sk_buff *skb; - uint32 complete = 0; - gfp_t kflags; - rtt_result_t *rtt_result; - rtt_results_header_t *rtt_header; - struct list_head *rtt_cache_list; - struct nlattr *rtt_nl_hdr; - wiphy = wdev->wiphy; - - WL_DBG(("In\n")); - /* Push the data to the skb */ - if (!rtt_data) { - WL_ERR(("rtt_data is NULL\n")); - goto exit; - } - rtt_cache_list = (struct list_head *)rtt_data; - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - list_for_each_entry(rtt_header, rtt_cache_list, list) { - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_event_alloc(wiphy, rtt_header->result_tot_len + 100, - GOOGLE_RTT_COMPLETE_EVENT, kflags); - if (!skb) { - WL_ERR(("skb alloc failed")); - goto exit; - } - if (list_is_last(&rtt_header->list, rtt_cache_list)) { - complete = 1; - } - nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, complete); - rtt_nl_hdr = nla_nest_start(skb, RTT_ATTRIBUTE_RESULTS_PER_TARGET); - if (!rtt_nl_hdr) { - WL_ERR(("rtt_nl_hdr is NULL\n")); - break; - } - nla_put(skb, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN, &rtt_header->peer_mac); - nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_CNT, rtt_header->result_cnt); - list_for_each_entry(rtt_result, &rtt_header->result_list, list) { - nla_put(skb, RTT_ATTRIBUTE_RESULT, - rtt_result->report_len, &rtt_result->report); - } - nla_nest_end(skb, rtt_nl_hdr); - cfg80211_vendor_event(skb, kflags); - } -exit: - return; -} - -static int -wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) { - int err = 0, rem, rem1, rem2, type; - int target_cnt; - rtt_config_params_t rtt_param; - rtt_target_info_t* rtt_target = NULL; - const struct nlattr *iter, *iter1, *iter2; - int8 eabuf[ETHER_ADDR_STR_LEN]; - int8 chanbuf[CHANSPEC_STR_LEN]; - int32 feature_set = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - rtt_capabilities_t capability; - feature_set = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg)); - - WL_DBG(("In\n")); - err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt); - if (err < 0) { - WL_ERR(("failed to register rtt_noti_callback\n")); - goto exit; - } - err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability); - if (err < 0) { - WL_ERR(("failed to get the capability\n")); - goto exit; - } - memset(&rtt_param, 0, sizeof(rtt_param)); - if (len <= 0) { - WL_ERR(("Length of the nlattr is not valid len : %d\n", len)); - err = BCME_ERROR; - goto exit; - } - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case RTT_ATTRIBUTE_TARGET_CNT: - target_cnt = nla_get_u8(iter); - if ((target_cnt <= 0) || (target_cnt > RTT_MAX_TARGET_CNT)) { - WL_ERR(("target_cnt is not valid : %d\n", - target_cnt)); - err = BCME_RANGE; - goto exit; - } - rtt_param.rtt_target_cnt = target_cnt; - rtt_param.target_info = kzalloc(TARGET_INFO_SIZE(target_cnt), GFP_KERNEL); - if (rtt_param.target_info == NULL) { - WL_ERR(("failed to allocate target info for (%d)\n", target_cnt)); - err = BCME_NOMEM; - goto exit; - } - break; - case RTT_ATTRIBUTE_TARGET_INFO: - /* Added this variable for safe check to avoid crash - * incase the caller did not respect the order - */ - if (rtt_param.target_info == NULL) { - WL_ERR(("rtt_target_info is NULL\n")); - err = BCME_NOMEM; - goto exit; - } - rtt_target = rtt_param.target_info; - nla_for_each_nested(iter1, iter, rem1) { - nla_for_each_nested(iter2, iter1, rem2) { - type = nla_type(iter2); - switch (type) { - case RTT_ATTRIBUTE_TARGET_MAC: - memcpy(&rtt_target->addr, nla_data(iter2), - ETHER_ADDR_LEN); - break; - case RTT_ATTRIBUTE_TARGET_TYPE: - rtt_target->type = nla_get_u8(iter2); - if (rtt_target->type == RTT_INVALID || - (rtt_target->type == RTT_ONE_WAY && - !capability.rtt_one_sided_supported)) { - WL_ERR(("doesn't support RTT type" - " : %d\n", - rtt_target->type)); - err = -EINVAL; - goto exit; - } - break; - case RTT_ATTRIBUTE_TARGET_PEER: - rtt_target->peer = nla_get_u8(iter2); - break; - case RTT_ATTRIBUTE_TARGET_CHAN: - memcpy(&rtt_target->channel, nla_data(iter2), - sizeof(rtt_target->channel)); - break; - case RTT_ATTRIBUTE_TARGET_INTERVAL: - rtt_target->interval = nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_NUM_BURST: - rtt_target->num_burst = nla_get_u32(iter2); - if (!(rtt_target->num_burst == 1 || - ISPOWEROF2(rtt_target->num_burst))) { - WL_ERR(("%d value must be power of 2" - " or 1\n", - rtt_target->num_burst)); - err = -EINVAL; - goto exit; - } - break; - case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST: - rtt_target->num_frames_per_burst = - nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM: - rtt_target->num_retries_per_ftm = - nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR: - rtt_target->num_retries_per_ftmr = - nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_LCI: - rtt_target->LCI_request = nla_get_u8(iter2); - break; - case RTT_ATTRIBUTE_TARGET_LCR: - rtt_target->LCI_request = nla_get_u8(iter2); - break; - case RTT_ATTRIBUTE_TARGET_BURST_TIMEOUT: - rtt_target->burst_timeout = nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_BW: - rtt_target->bw = nla_get_u8(iter2); - } - } - /* convert to chanspec value */ - rtt_target->chanspec = - dhd_rtt_convert_to_chspec(rtt_target->channel); - if (rtt_target->chanspec == 0) { - WL_ERR(("Channel is not valid \n")); - err = -EINVAL; - goto exit; - } - WL_INFORM(("Target addr %s, Channel : %s for RTT \n", - bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, - eabuf), - wf_chspec_ntoa(rtt_target->chanspec, chanbuf))); - rtt_target++; - } - break; - } - } - WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt)); - if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) { - WL_ERR(("Could not set RTT configuration\n")); - err = -EINVAL; - } -exit: - /* free the target info list */ - if (rtt_param.target_info) { - kfree(rtt_param.target_info); - rtt_param.target_info = NULL; - } - return err; -} - -static int -wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) -{ - int err = 0, rem, type, target_cnt = 0; - int target_cnt_chk = 0; - const struct nlattr *iter; - struct ether_addr *mac_list = NULL, *mac_addr = NULL; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (len <= 0) { - WL_ERR(("Length of nlattr is not valid len : %d\n", len)); - err = -EINVAL; - goto exit; - } - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case RTT_ATTRIBUTE_TARGET_CNT: - if (mac_list != NULL) { - WL_ERR(("mac_list is not NULL\n")); - err = -EINVAL; - goto exit; - } - target_cnt = nla_get_u8(iter); - if ((target_cnt > 0) && (target_cnt < RTT_MAX_TARGET_CNT)) { - mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN, - GFP_KERNEL); - if (mac_list == NULL) { - WL_ERR(("failed to allocate mem for mac list\n")); - err = -EINVAL; - goto exit; - } - mac_addr = &mac_list[0]; - } else { - /* cancel the current whole RTT process */ - goto cancel; - } - break; - case RTT_ATTRIBUTE_TARGET_MAC: - if (mac_addr) { - memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN); - target_cnt_chk++; - if (target_cnt_chk > target_cnt) { - WL_ERR(("over target count\n")); - err = -EINVAL; - goto exit; - } - break; - } else { - WL_ERR(("mac_list is NULL\n")); - err = -EINVAL; - goto exit; - } - } - } -cancel: - if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) { - WL_ERR(("Could not cancel RTT configuration\n")); - err = -EINVAL; - } - -exit: - if (mac_list) { - kfree(mac_list); - } - return err; -} -static int -wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - rtt_capabilities_t capability; - - err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability); - if (unlikely(err)) { - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - goto exit; - } - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - &capability, sizeof(capability)); - - if (unlikely(err)) { - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - } -exit: - return err; -} - -#endif /* RTT_SUPPORT */ - -#if defined(KEEP_ALIVE) -static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) -{ - /* max size of IP packet for keep alive */ - const int MKEEP_ALIVE_IP_PKT_MAX = 256; - - int ret = BCME_OK, rem, type; - u8 mkeep_alive_id = 0; - u8 *ip_pkt = NULL; - u16 ip_pkt_len = 0; - u8 src_mac[ETHER_ADDR_LEN]; - u8 dst_mac[ETHER_ADDR_LEN]; - u32 period_msec = 0; - const struct nlattr *iter; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_pub_t *dhd_pub = cfg->pub; - gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case MKEEP_ALIVE_ATTRIBUTE_ID: - mkeep_alive_id = nla_get_u8(iter); - break; - case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN: - ip_pkt_len = nla_get_u16(iter); - if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) { - ret = BCME_BADARG; - goto exit; - } - break; - case MKEEP_ALIVE_ATTRIBUTE_IP_PKT: - ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags); - if (ip_pkt == NULL) { - ret = BCME_NOMEM; - WL_ERR(("Failed to allocate mem for ip packet\n")); - goto exit; - } - memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len); - break; - case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR: - memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN); - break; - case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR: - memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN); - break; - case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC: - period_msec = nla_get_u32(iter); - break; - default: - WL_ERR(("Unknown type: %d\n", type)); - ret = BCME_BADARG; - goto exit; - } - } - - ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac, - dst_mac, period_msec); - if (ret < 0) { - WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret)); - } - -exit: - if (ip_pkt) { - kfree(ip_pkt); - } - - return ret; -} - -static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) -{ - int ret = BCME_OK, rem, type; - u8 mkeep_alive_id = 0; - const struct nlattr *iter; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_pub_t *dhd_pub = cfg->pub; - - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case MKEEP_ALIVE_ATTRIBUTE_ID: - mkeep_alive_id = nla_get_u8(iter); - break; - default: - WL_ERR(("Unknown type: %d\n", type)); - ret = BCME_BADARG; - break; - } - } - - ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id); - if (ret < 0) { - WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret)); - } - - return ret; -} -#endif /* defined(KEEP_ALIVE) */ - -static int -wl_cfgvendor_priv_string_handler(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int err = 0; - int data_len = 0; - - WL_TRACE(("%s: Enter \n", __func__)); - - bzero(cfg->ioctl_buf, WLC_IOCTL_MAXLEN); - - if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) { - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - data_len = strlen(cfg->ioctl_buf); - } - - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - cfg->ioctl_buf, data_len+1); - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - else - WL_INFORM(("Vendor Command reply sent successfully!\n")); - - return err; -} - -#ifdef LINKSTAT_SUPPORT -#define NUM_RATE 32 -#define NUM_PEER 1 -#define NUM_CHAN 11 -static int -wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - char *iovar_buf = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int err = 0; - wifi_iface_stat *iface; - wifi_radio_stat *radio; - wl_wme_cnt_t *wl_wme_cnt; - wl_cnt_t *wl_cnt; - char *output; - int radstat_buflen = sizeof(wifi_radio_stat) + NUM_CHAN * sizeof(wifi_channel_stat); - int iface_buflen = sizeof(wifi_iface_stat) + NUM_PEER * sizeof(wifi_peer_info); - int ratestat_buflen = NUM_RATE * sizeof(wifi_rate_stat); - scb_val_t scbval; - - WL_TRACE(("%s: Enter \n", __FUNCTION__)); - - RETURN_EIO_IF_NOT_UP(cfg); - - bzero(&scbval, sizeof(scb_val_t)); - - iovar_buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL); - if (unlikely(!iovar_buf)) { - WL_ERR(("%s: link stats buf alloc fails\n", __FUNCTION__)); - return -ENOMEM; - } - - ASSERT((radstat_buflen + iface_buflen + ratestat_buflen) <= - (sizeof(char) * WLC_IOCTL_MAXLEN)); - - output = iovar_buf; - radio = (wifi_radio_stat *)output; - - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("%s: ioctl error(%d) for radiostat - size = %zu\n", - __FUNCTION__, err, sizeof(wifi_radio_stat))); - goto exit; - } - memcpy(output, cfg->ioctl_buf, sizeof(wifi_radio_stat)); - - radio->num_channels = NUM_CHAN; - output += radstat_buflen; - - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "wme_counters", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("%s: ioctl error(%d) for wme_counters\n", __FUNCTION__, err)); - goto exit; - } - wl_wme_cnt = (wl_wme_cnt_t *)cfg->ioctl_buf; - iface = (wifi_iface_stat *)output; - - iface->ac[WIFI_AC_VO].ac = WIFI_AC_VO; - iface->ac[WIFI_AC_VO].tx_mpdu = wl_wme_cnt->tx[AC_VO].packets; - iface->ac[WIFI_AC_VO].rx_mpdu = wl_wme_cnt->rx[AC_VO].packets; - iface->ac[WIFI_AC_VO].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VO].packets; - - iface->ac[WIFI_AC_VI].ac = WIFI_AC_VI; - iface->ac[WIFI_AC_VI].tx_mpdu = wl_wme_cnt->tx[AC_VI].packets; - iface->ac[WIFI_AC_VI].rx_mpdu = wl_wme_cnt->rx[AC_VI].packets; - iface->ac[WIFI_AC_VI].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VI].packets; - - iface->ac[WIFI_AC_BE].ac = WIFI_AC_BE; - iface->ac[WIFI_AC_BE].tx_mpdu = wl_wme_cnt->tx[AC_BE].packets; - iface->ac[WIFI_AC_BE].rx_mpdu = wl_wme_cnt->rx[AC_BE].packets; - iface->ac[WIFI_AC_BE].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BE].packets; - - iface->ac[WIFI_AC_BK].ac = WIFI_AC_BK; - iface->ac[WIFI_AC_BK].tx_mpdu = wl_wme_cnt->tx[AC_BK].packets; - iface->ac[WIFI_AC_BK].rx_mpdu = wl_wme_cnt->rx[AC_BK].packets; - iface->ac[WIFI_AC_BK].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BK].packets; - - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("%s: ioctl error(%d) for counters - size = %zu\n", - __FUNCTION__, err, sizeof(wl_cnt_t))); - goto exit; - } - wl_cnt = (wl_cnt_t *)cfg->ioctl_buf; - iface->ac[WIFI_AC_BE].retries = wl_cnt->txretry; - iface->beacon_rx = wl_cnt->rxbeaconmbss; - - err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval); - if (unlikely(err)) { - WL_ERR(("%s: get_rssi error(%d)\n", __FUNCTION__, err)); - goto exit; - } - iface->rssi_mgmt = scbval.val; - - iface->num_peers = NUM_PEER; - iface->peer_info->num_rate = NUM_RATE; - - output = (char *)iface + iface_buflen; - - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("%s: ioctl error(%d) for ratestat - size = %d\n", - __FUNCTION__, err, ratestat_buflen)); - goto exit; - } - memcpy(output, cfg->ioctl_buf, ratestat_buflen); - - if (unlikely(radio->num_channels != NUM_CHAN)) { - WL_ERR(("%s: error! num_channels corrupted. value=%d \n", - __FUNCTION__, (int)radio->num_channels)); - goto exit; - } - - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - iovar_buf, radstat_buflen + iface_buflen + ratestat_buflen); - if (unlikely(err)) { - WL_ERR(("%s: Vendor Command reply failed ret:%d \n", __FUNCTION__, err)); - } - -exit: - - if (iovar_buf) { - kfree(iovar_buf); - } - return err; -} -#endif /* LINKSTAT_SUPPORT */ - -static int wl_cfgvendor_set_country(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = BCME_ERROR, rem, type; - char country_code[WLC_CNTRY_BUF_SZ] = {0}; - const struct nlattr *iter; - - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case ANDR_WIFI_ATTRIBUTE_COUNTRY: - memcpy(country_code, nla_data(iter), - MIN(nla_len(iter), WLC_CNTRY_BUF_SZ)); - break; - default: - WL_ERR(("Unknown type: %d\n", type)); - return err; - } - } - - err = wldev_set_country(wdev->netdev, country_code, true, true); - if (err < 0) { - WL_ERR(("Set country failed ret:%d\n", err)); - } - - return err; -} - -static const struct wiphy_vendor_command wl_vendor_cmds [] = { - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_PRIV_STR - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_priv_string_handler - }, -#ifdef GSCAN_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_get_capabilities - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_scan_cfg - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_batch_scan_cfg - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_initiate_gscan - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_enable_full_scan_result - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_HOTLIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_hotlist_cfg - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_get_batch_results - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_get_channel_list - }, -#endif /* GSCAN_SUPPORT */ -#ifdef KEEP_ALIVE - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_start_mkeep_alive - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_stop_mkeep_alive - }, -#endif /* KEEP_ALIVE */ -#ifdef RTT_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_SET_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_set_config - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_CANCEL_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_cancel_config - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_GETCAPABILITY - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_get_capability - }, -#endif /* RTT_SUPPORT */ - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_get_feature_set - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_get_feature_set_matrix - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_RANDOM_MAC_OUI - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_rand_mac_oui - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_NODFS_CHANNELS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_nodfs_flag - - }, -#ifdef LINKSTAT_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = LSTATS_SUBCMD_GET_INFO - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_lstats_get_info - }, -#endif /* LINKSTAT_SUPPORT */ - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_SET_COUNTRY - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_country - }, -#ifdef GSCAN_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_epno_cfg - - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_ssid_whitelist - - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_lazy_roam_cfg - - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_enable_lazy_roam - - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_BSSID_PREF - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_bssid_pref - - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_bssid_blacklist - }, -#endif /* GSCAN_SUPPORT */ - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_rssi_monitor - } -}; - -static const struct nl80211_vendor_cmd_info wl_vendor_events [] = { - { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC }, - { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR }, -#ifdef GSCAN_SUPPORT - { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT }, - { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT }, - { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT }, - { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT }, -#endif /* GSCAN_SUPPORT */ - { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT }, -#ifdef GSCAN_SUPPORT - { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT }, - { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT }, - { OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT }, -#endif /* GSCAN_SUPPORT */ - { OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT }, - { OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT }, -#ifdef GSCAN_SUPPORT - { OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT }, -#endif /* GSCAN_SUPPORT */ - { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT }, -#ifdef KEEP_ALIVE - { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT }, -#endif /* KEEP_ALIVE */ -}; - -int wl_cfgvendor_attach(struct wiphy *wiphy) -{ - - WL_INFORM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n", - NL80211_CMD_VENDOR)); - - wiphy->vendor_commands = wl_vendor_cmds; - wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds); - wiphy->vendor_events = wl_vendor_events; - wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events); - - return 0; -} - -int wl_cfgvendor_detach(struct wiphy *wiphy) -{ - WL_INFORM(("Vendor: Unregister BRCM cfg80211 vendor interface \n")); - - wiphy->vendor_commands = NULL; - wiphy->vendor_events = NULL; - wiphy->n_vendor_commands = 0; - wiphy->n_vendor_events = 0; - - return 0; -} -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd/wl_cfgvendor.h deleted file mode 100644 index ae80b74a0326..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.h +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Linux cfg80211 Vendor Extension Code - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgvendor.h 455257 2014-02-20 08:10:24Z $ - */ - - -#ifndef _wl_cfgvendor_h_ -#define _wl_cfgvendor_h_ - -#define OUI_BRCM 0x001018 -#define OUI_GOOGLE 0x001A11 -#define BRCM_VENDOR_SUBCMD_PRIV_STR 1 -#define ATTRIBUTE_U32_LEN (NLA_HDRLEN + 4) -#define VENDOR_ID_OVERHEAD ATTRIBUTE_U32_LEN -#define VENDOR_SUBCMD_OVERHEAD ATTRIBUTE_U32_LEN -#define VENDOR_DATA_OVERHEAD (NLA_HDRLEN) - -#define SCAN_RESULTS_COMPLETE_FLAG_LEN ATTRIBUTE_U32_LEN -#define SCAN_INDEX_HDR_LEN (NLA_HDRLEN) -#define SCAN_ID_HDR_LEN ATTRIBUTE_U32_LEN -#define SCAN_FLAGS_HDR_LEN ATTRIBUTE_U32_LEN -#define GSCAN_NUM_RESULTS_HDR_LEN ATTRIBUTE_U32_LEN -#define GSCAN_RESULTS_HDR_LEN (NLA_HDRLEN) -#define GSCAN_BATCH_RESULT_HDR_LEN (SCAN_INDEX_HDR_LEN + \ - SCAN_ID_HDR_LEN + \ - SCAN_FLAGS_HDR_LEN + \ - GSCAN_NUM_RESULTS_HDR_LEN + \ - GSCAN_RESULTS_HDR_LEN) - -#define VENDOR_REPLY_OVERHEAD (VENDOR_ID_OVERHEAD + \ - VENDOR_SUBCMD_OVERHEAD + \ - VENDOR_DATA_OVERHEAD) -typedef enum { - /* don't use 0 as a valid subcommand */ - VENDOR_NL80211_SUBCMD_UNSPECIFIED, - - /* define all vendor startup commands between 0x0 and 0x0FFF */ - VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001, - VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF, - - /* define all GScan related commands between 0x1000 and 0x10FF */ - ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000, - ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF, - - /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */ - ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100, - ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF, - - /* define all RTT related commands between 0x1100 and 0x11FF */ - ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100, - ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF, - - ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200, - ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF, - - ANDROID_NL80211_SUBCMD_TDLS_RANGE_START = 0x1300, - ANDROID_NL80211_SUBCMD_TDLS_RANGE_END = 0x13FF, - - /* define all wifi calling related commands between 0x1600 and 0x16FF */ - ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600, - ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF, - - /* This is reserved for future usage */ -} ANDROID_VENDOR_SUB_COMMAND; - -enum andr_vendor_subcmd { - GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START, - GSCAN_SUBCMD_SET_CONFIG, - GSCAN_SUBCMD_SET_SCAN_CONFIG, - GSCAN_SUBCMD_ENABLE_GSCAN, - GSCAN_SUBCMD_GET_SCAN_RESULTS, - GSCAN_SUBCMD_SCAN_RESULTS, - GSCAN_SUBCMD_SET_HOTLIST, - GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, - GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, - GSCAN_SUBCMD_GET_CHANNEL_LIST, - /* ANDR_WIFI_XXX although not related to gscan are defined here */ - ANDR_WIFI_SUBCMD_GET_FEATURE_SET, - ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, - ANDR_WIFI_RANDOM_MAC_OUI, - ANDR_WIFI_NODFS_CHANNELS, - ANDR_WIFI_SET_COUNTRY, - GSCAN_SUBCMD_SET_EPNO_SSID, - WIFI_SUBCMD_SET_SSID_WHITELIST, - WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS, - WIFI_SUBCMD_ENABLE_LAZY_ROAM, - WIFI_SUBCMD_SET_BSSID_PREF, - WIFI_SUBCMD_SET_BSSID_BLACKLIST, - GSCAN_SUBCMD_ANQPO_CONFIG, - WIFI_SUBCMD_SET_RSSI_MONITOR, - RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, - RTT_SUBCMD_CANCEL_CONFIG, - RTT_SUBCMD_GETCAPABILITY, - - LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START, - WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START, - WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE, - - /* Add more sub commands here */ - VENDOR_SUBCMD_MAX -}; - - -enum gscan_attributes { - GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, - GSCAN_ATTRIBUTE_BASE_PERIOD, - GSCAN_ATTRIBUTE_BUCKETS_BAND, - GSCAN_ATTRIBUTE_BUCKET_ID, - GSCAN_ATTRIBUTE_BUCKET_PERIOD, - GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, - GSCAN_ATTRIBUTE_BUCKET_CHANNELS, - GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, - GSCAN_ATTRIBUTE_REPORT_THRESHOLD, - GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, - GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND, - - GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, - GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, - GSCAN_ATTRIBUTE_FLUSH_FEATURE, - GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS, - GSCAN_ATTRIBUTE_REPORT_EVENTS, - /* remaining reserved for additional attributes */ - GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, - GSCAN_ATTRIBUTE_FLUSH_RESULTS, - GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ - GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ - GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ - GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ - GSCAN_ATTRIBUTE_NUM_CHANNELS, - GSCAN_ATTRIBUTE_CHANNEL_LIST, - - /* remaining reserved for additional attributes */ - - GSCAN_ATTRIBUTE_SSID = 40, - GSCAN_ATTRIBUTE_BSSID, - GSCAN_ATTRIBUTE_CHANNEL, - GSCAN_ATTRIBUTE_RSSI, - GSCAN_ATTRIBUTE_TIMESTAMP, - GSCAN_ATTRIBUTE_RTT, - GSCAN_ATTRIBUTE_RTTSD, - - /* remaining reserved for additional attributes */ - - GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, - GSCAN_ATTRIBUTE_RSSI_LOW, - GSCAN_ATTRIBUTE_RSSI_HIGH, - GSCAN_ATTRIBUTE_HOSTLIST_BSSID_ELEM, - GSCAN_ATTRIBUTE_HOTLIST_FLUSH, - GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT, - - /* remaining reserved for additional attributes */ - GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, - GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, - GSCAN_ATTRIBUTE_MIN_BREACHING, - GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, - GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, - /* EPNO */ - GSCAN_ATTRIBUTE_EPNO_SSID_LIST = 70, - GSCAN_ATTRIBUTE_EPNO_SSID, - GSCAN_ATTRIBUTE_EPNO_SSID_LEN, - GSCAN_ATTRIBUTE_EPNO_RSSI, - GSCAN_ATTRIBUTE_EPNO_FLAGS, - GSCAN_ATTRIBUTE_EPNO_AUTH, - GSCAN_ATTRIBUTE_EPNO_SSID_NUM, - GSCAN_ATTRIBUTE_EPNO_FLUSH, - - /* Roam SSID Whitelist and BSSID pref */ - GSCAN_ATTRIBUTE_WHITELIST_SSID = 80, - GSCAN_ATTRIBUTE_NUM_WL_SSID, - GSCAN_ATTRIBUTE_WL_SSID_LEN, - GSCAN_ATTRIBUTE_WL_SSID_FLUSH, - GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM, - GSCAN_ATTRIBUTE_NUM_BSSID, - GSCAN_ATTRIBUTE_BSSID_PREF_LIST, - GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH, - GSCAN_ATTRIBUTE_BSSID_PREF, - GSCAN_ATTRIBUTE_RSSI_MODIFIER, - - - /* Roam cfg */ - GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD = 90, - GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD, - GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR, - GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR, - GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST, - GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS, - GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER, - GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE, - - /* BSSID blacklist */ - GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH = 100, - GSCAN_ATTRIBUTE_BLACKLIST_BSSID, - - GSCAN_ATTRIBUTE_ANQPO_HS_LIST = 110, - GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, - GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, - GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, - GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID, - GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, - - /* Adaptive scan attributes */ - GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 120, - GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD, - - GSCAN_ATTRIBUTE_MAX -}; - -enum gscan_bucket_attributes { - GSCAN_ATTRIBUTE_CH_BUCKET_1, - GSCAN_ATTRIBUTE_CH_BUCKET_2, - GSCAN_ATTRIBUTE_CH_BUCKET_3, - GSCAN_ATTRIBUTE_CH_BUCKET_4, - GSCAN_ATTRIBUTE_CH_BUCKET_5, - GSCAN_ATTRIBUTE_CH_BUCKET_6, - GSCAN_ATTRIBUTE_CH_BUCKET_7 -}; - -enum gscan_ch_attributes { - GSCAN_ATTRIBUTE_CH_ID_1, - GSCAN_ATTRIBUTE_CH_ID_2, - GSCAN_ATTRIBUTE_CH_ID_3, - GSCAN_ATTRIBUTE_CH_ID_4, - GSCAN_ATTRIBUTE_CH_ID_5, - GSCAN_ATTRIBUTE_CH_ID_6, - GSCAN_ATTRIBUTE_CH_ID_7 -}; - -enum rtt_attributes { - RTT_ATTRIBUTE_TARGET_CNT, - RTT_ATTRIBUTE_TARGET_INFO, - RTT_ATTRIBUTE_TARGET_MAC, - RTT_ATTRIBUTE_TARGET_TYPE, - RTT_ATTRIBUTE_TARGET_PEER, - RTT_ATTRIBUTE_TARGET_CHAN, - RTT_ATTRIBUTE_TARGET_INTERVAL, - RTT_ATTRIBUTE_TARGET_NUM_BURST, - RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, - RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, - RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, - RTT_ATTRIBUTE_TARGET_LCI, - RTT_ATTRIBUTE_TARGET_LCR, - RTT_ATTRIBUTE_TARGET_BURST_TIMEOUT, - RTT_ATTRIBUTE_TARGET_PREAMBLE, - RTT_ATTRIBUTE_TARGET_BW, - RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, - RTT_ATTRIBUTE_RESULTS_PER_TARGET, - RTT_ATTRIBUTE_RESULT_CNT, - RTT_ATTRIBUTE_RESULT -}; - -enum mkeep_alive_attributes { - MKEEP_ALIVE_ATTRIBUTE_ID, - MKEEP_ALIVE_ATTRIBUTE_IP_PKT, - MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, - MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, - MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, - MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC -}; - -enum wifi_rssi_monitor_attr { - RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, - RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, - RSSI_MONITOR_ATTRIBUTE_START -}; - -typedef enum wl_vendor_event { - BRCM_VENDOR_EVENT_UNSPEC, - BRCM_VENDOR_EVENT_PRIV_STR, - GOOGLE_GSCAN_SIGNIFICANT_EVENT, - GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT, - GOOGLE_GSCAN_BATCH_SCAN_EVENT, - GOOGLE_SCAN_FULL_RESULTS_EVENT, - GOOGLE_RTT_COMPLETE_EVENT, - GOOGLE_SCAN_COMPLETE_EVENT, - GOOGLE_GSCAN_GEOFENCE_LOST_EVENT, - GOOGLE_SCAN_EPNO_EVENT, - GOOGLE_DEBUG_RING_EVENT, - GOOGLE_FW_DUMP_EVENT, - GOOGLE_PNO_HOTSPOT_FOUND_EVENT, - GOOGLE_RSSI_MONITOR_EVENT, - GOOGLE_MKEEP_ALIVE_EVENT -} wl_vendor_event_t; - -enum andr_wifi_attr { - ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, - ANDR_WIFI_ATTRIBUTE_FEATURE_SET, - ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI, - ANDR_WIFI_ATTRIBUTE_NODFS_SET, - ANDR_WIFI_ATTRIBUTE_COUNTRY -}; - -typedef enum wl_vendor_gscan_attribute { - ATTR_START_GSCAN, - ATTR_STOP_GSCAN, - ATTR_SET_SCAN_BATCH_CFG_ID, /* set batch scan params */ - ATTR_SET_SCAN_GEOFENCE_CFG_ID, /* set list of bssids to track */ - ATTR_SET_SCAN_SIGNIFICANT_CFG_ID, /* set list of bssids, rssi threshold etc.. */ - ATTR_SET_SCAN_CFG_ID, /* set common scan config params here */ - ATTR_GET_GSCAN_CAPABILITIES_ID, - - /* Add more sub commands here */ - ATTR_GSCAN_MAX -} wl_vendor_gscan_attribute_t; - -typedef enum gscan_batch_attribute { - ATTR_GSCAN_BATCH_BESTN, - ATTR_GSCAN_BATCH_MSCAN, - ATTR_GSCAN_BATCH_BUFFER_THRESHOLD -} gscan_batch_attribute_t; - -typedef enum gscan_geofence_attribute { - ATTR_GSCAN_NUM_HOTLIST_BSSID, - ATTR_GSCAN_HOTLIST_BSSID -} gscan_geofence_attribute_t; - -typedef enum gscan_complete_event { - WIFI_SCAN_BUFFER_FULL, - WIFI_SCAN_COMPLETE -} gscan_complete_event_t; - -/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */ -#define BRCM_VENDOR_SCMD_CAPA "cap" - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) -extern int wl_cfgvendor_attach(struct wiphy *wiphy); -extern int wl_cfgvendor_detach(struct wiphy *wiphy); -extern int wl_cfgvendor_send_async_event(struct wiphy *wiphy, - struct net_device *dev, int event_id, const void *data, int len); -extern int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, - struct net_device *dev, void *data, int len, wl_vendor_event_t event); -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ - -#endif /* _wl_cfgvendor_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_dbg.h b/drivers/net/wireless/bcmdhd/wl_dbg.h deleted file mode 100644 index 3691db18f4bb..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_dbg.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Minimal debug/trace/assert driver definitions for - * Broadcom 802.11 Networking Adapter. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_dbg.h 472390 2014-04-23 23:32:01Z $ - */ - - -#ifndef _wl_dbg_h_ -#define _wl_dbg_h_ - -/* wl_msg_level is a bit vector with defs in wlioctl.h */ -extern uint32 wl_msg_level; -extern uint32 wl_msg_level2; - -#define WL_TIMESTAMP() - -#define WL_PRINT(args) do { WL_TIMESTAMP(); printf args; } while (0) - -#if defined(EVENT_LOG_COMPILE) && defined(WLMSG_SRSCAN) -#define _WL_SRSCAN(fmt, ...) EVENT_LOG(EVENT_LOG_TAG_SRSCAN, fmt, ##__VA_ARGS__) -#define WL_SRSCAN(args) _WL_SRSCAN args -#else -#define WL_SRSCAN(args) -#endif - -#if defined(BCMCONDITIONAL_LOGGING) - -/* Ideally this should be some include file that vendors can include to conditionalize logging */ - -/* DBGONLY() macro to reduce ifdefs in code for statements that are only needed when - * BCMDBG is defined. - */ -#define DBGONLY(x) - -/* To disable a message completely ... until you need it again */ -#define WL_NONE(args) -#define WL_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args);} while (0) -#define WL_TRACE(args) -#define WL_PRHDRS_MSG(args) -#define WL_PRHDRS(i, p, f, t, r, l) -#define WL_PRPKT(m, b, n) -#define WL_INFORM(args) -#define WL_TMP(args) -#define WL_OID(args) -#define WL_RATE(args) do {if (wl_msg_level & WL_RATE_VAL) WL_PRINT(args);} while (0) -#define WL_ASSOC(args) do {if (wl_msg_level & WL_ASSOC_VAL) WL_PRINT(args);} while (0) -#define WL_PRUSR(m, b, n) -#define WL_PS(args) do {if (wl_msg_level & WL_PS_VAL) WL_PRINT(args);} while (0) - -#define WL_PORT(args) -#define WL_DUAL(args) -#define WL_REGULATORY(args) do {if (wl_msg_level & WL_REGULATORY_VAL) WL_PRINT(args);} while (0) - -#define WL_MPC(args) -#define WL_APSTA(args) -#define WL_APSTA_BCN(args) -#define WL_APSTA_TX(args) -#define WL_APSTA_TSF(args) -#define WL_APSTA_BSSID(args) -#define WL_BA(args) -#define WL_MBSS(args) -#define WL_PROTO(args) - -#define WL_CAC(args) do {if (wl_msg_level & WL_CAC_VAL) WL_PRINT(args);} while (0) -#define WL_AMSDU(args) -#define WL_AMPDU(args) -#define WL_FFPLD(args) -#define WL_MCHAN(args) - -#define WL_DFS(args) -#define WL_WOWL(args) -#define WL_DPT(args) -#define WL_ASSOC_OR_DPT(args) -#define WL_SCAN(args) do {if (wl_msg_level2 & WL_SCAN_VAL) WL_PRINT(args);} while (0) -#define WL_COEX(args) -#define WL_RTDC(w, s, i, j) -#define WL_RTDC2(w, s, i, j) -#define WL_CHANINT(args) -#define WL_BTA(args) -#define WL_P2P(args) -#define WL_ITFR(args) -#define WL_TDLS(args) -#define WL_MCNX(args) -#define WL_PROT(args) -#define WL_PSTA(args) -#define WL_TRF_MGMT(args) -#define WL_L2FILTER(args) -#define WL_MQ(args) -#define WL_TXBF(args) -#define WL_P2PO(args) -#define WL_NET_DETECT(args) -#define WL_ROAM(args) -#define WL_WNM(args) - - -#define WL_AMPDU_UPDN(args) -#define WL_AMPDU_RX(args) -#define WL_AMPDU_ERR(args) -#define WL_AMPDU_TX(args) -#define WL_AMPDU_CTL(args) -#define WL_AMPDU_HW(args) -#define WL_AMPDU_HWTXS(args) -#define WL_AMPDU_HWDBG(args) -#define WL_AMPDU_STAT(args) -#define WL_AMPDU_ERR_ON() 0 -#define WL_AMPDU_HW_ON() 0 -#define WL_AMPDU_HWTXS_ON() 0 - -#define WL_APSTA_UPDN(args) -#define WL_APSTA_RX(args) -#define WL_WSEC(args) -#define WL_WSEC_DUMP(args) -#define WL_PCIE(args) -#define WL_CHANLOG(w, s, i, j) - -#define WL_ERROR_ON() (wl_msg_level & WL_ERROR_VAL) -#define WL_TRACE_ON() 0 -#define WL_PRHDRS_ON() 0 -#define WL_PRPKT_ON() 0 -#define WL_INFORM_ON() 0 -#define WL_TMP_ON() 0 -#define WL_OID_ON() 0 -#define WL_RATE_ON() (wl_msg_level & WL_RATE_VAL) -#define WL_ASSOC_ON() (wl_msg_level & WL_ASSOC_VAL) -#define WL_PRUSR_ON() 0 -#define WL_PS_ON() (wl_msg_level & WL_PS_VAL) -#define WL_PORT_ON() 0 -#define WL_WSEC_ON() 0 -#define WL_WSEC_DUMP_ON() 0 -#define WL_MPC_ON() 0 -#define WL_REGULATORY_ON() (wl_msg_level & WL_REGULATORY_VAL) -#define WL_APSTA_ON() 0 -#define WL_DFS_ON() 0 -#define WL_MBSS_ON() 0 -#define WL_CAC_ON() (wl_msg_level & WL_CAC_VAL) -#define WL_AMPDU_ON() 0 -#define WL_DPT_ON() 0 -#define WL_WOWL_ON() 0 -#define WL_SCAN_ON() (wl_msg_level2 & WL_SCAN_VAL) -#define WL_BTA_ON() 0 -#define WL_P2P_ON() 0 -#define WL_ITFR_ON() 0 -#define WL_MCHAN_ON() 0 -#define WL_TDLS_ON() 0 -#define WL_MCNX_ON() 0 -#define WL_PROT_ON() 0 -#define WL_PSTA_ON() 0 -#define WL_TRF_MGMT_ON() 0 -#define WL_LPC_ON() 0 -#define WL_L2FILTER_ON() 0 -#define WL_TXBF_ON() 0 -#define WL_P2PO_ON() 0 -#define WL_CHANLOG_ON() 0 -#define WL_NET_DETECT_ON() 0 -#define WL_WNM_ON() 0 -#define WL_PCIE_ON() 0 - -#else /* !BCMDBG */ - -/* DBGONLY() macro to reduce ifdefs in code for statements that are only needed when - * BCMDBG is defined. - */ -#define DBGONLY(x) - -/* To disable a message completely ... until you need it again */ -#define WL_NONE(args) - -#define WL_ERROR(args) -#define WL_TRACE(args) -#define WL_APSTA_UPDN(args) -#define WL_APSTA_RX(args) -#ifdef WLMSG_WSEC -#define WL_WSEC(args) WL_PRINT(args) -#define WL_WSEC_DUMP(args) WL_PRINT(args) -#else -#define WL_WSEC(args) -#define WL_WSEC_DUMP(args) -#endif -#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0) -#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL) -#endif - -extern uint32 wl_msg_level; -extern uint32 wl_msg_level2; -#endif /* _wl_dbg_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_linux_mon.c b/drivers/net/wireless/bcmdhd/wl_linux_mon.c deleted file mode 100644 index aa745a913777..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_linux_mon.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Linux monitor network interface - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_linux_mon.c 467328 2014-04-03 01:23:40Z $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -typedef enum monitor_states -{ - MONITOR_STATE_DEINIT = 0x0, - MONITOR_STATE_INIT = 0x1, - MONITOR_STATE_INTERFACE_ADDED = 0x2, - MONITOR_STATE_INTERFACE_DELETED = 0x4 -} monitor_states_t; -int dhd_add_monitor(char *name, struct net_device **new_ndev); -extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); -int dhd_del_monitor(struct net_device *ndev); -int dhd_monitor_init(void *dhd_pub); -int dhd_monitor_uninit(void); - -/** - * Local declarations and defintions (not exposed) - */ -#ifndef DHD_MAX_IFS -#define DHD_MAX_IFS 16 -#endif -#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__) -#define MON_TRACE MON_PRINT - -typedef struct monitor_interface { - int radiotap_enabled; - struct net_device* real_ndev; /* The real interface that the monitor is on */ - struct net_device* mon_ndev; -} monitor_interface; - -typedef struct dhd_linux_monitor { - void *dhd_pub; - monitor_states_t monitor_state; - monitor_interface mon_if[DHD_MAX_IFS]; - struct mutex lock; /* lock to protect mon_if */ -} dhd_linux_monitor_t; - -static dhd_linux_monitor_t g_monitor; - -static struct net_device* lookup_real_netdev(char *name); -static monitor_interface* ndev_to_monif(struct net_device *ndev); -static int dhd_mon_if_open(struct net_device *ndev); -static int dhd_mon_if_stop(struct net_device *ndev); -static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev); -static void dhd_mon_if_set_multicast_list(struct net_device *ndev); -static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr); - -static const struct net_device_ops dhd_mon_if_ops = { - .ndo_open = dhd_mon_if_open, - .ndo_stop = dhd_mon_if_stop, - .ndo_start_xmit = dhd_mon_if_subif_start_xmit, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - .ndo_set_rx_mode = dhd_mon_if_set_multicast_list, -#else - .ndo_set_multicast_list = dhd_mon_if_set_multicast_list, -#endif - .ndo_set_mac_address = dhd_mon_if_change_mac, -}; - -/** - * Local static function defintions - */ - -/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0" - * "p2p-eth0-0" is a match for "mon.p2p-eth0-0") - */ -static struct net_device* lookup_real_netdev(char *name) -{ - struct net_device *ndev_found = NULL; - - int i; - int len = 0; - int last_name_len = 0; - struct net_device *ndev; - - /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0", - * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon - * iface would be mon-p2p0-0. - */ - for (i = 0; i < DHD_MAX_IFS; i++) { - ndev = dhd_idx2net(g_monitor.dhd_pub, i); - - /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it - * it matches, then this netdev is the corresponding real_netdev. - */ - if (ndev && strstr(ndev->name, "p2p-p2p0")) { - len = strlen("p2p"); - } else { - /* if p2p- is not present, then the IFNAMSIZ have reached and name - * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x - */ - len = 0; - } - if (ndev && strstr(name, (ndev->name + len))) { - if (strlen(ndev->name) > last_name_len) { - ndev_found = ndev; - last_name_len = strlen(ndev->name); - } - } - } - - return ndev_found; -} - -static monitor_interface* ndev_to_monif(struct net_device *ndev) -{ - int i; - - for (i = 0; i < DHD_MAX_IFS; i++) { - if (g_monitor.mon_if[i].mon_ndev == ndev) - return &g_monitor.mon_if[i]; - } - - return NULL; -} - -static int dhd_mon_if_open(struct net_device *ndev) -{ - int ret = 0; - - MON_PRINT("enter\n"); - return ret; -} - -static int dhd_mon_if_stop(struct net_device *ndev) -{ - int ret = 0; - - MON_PRINT("enter\n"); - return ret; -} - -static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - int ret = 0; - int rtap_len; - int qos_len = 0; - int dot11_hdr_len = 24; - int snap_len = 6; - unsigned char *pdata; - unsigned short frame_ctl; - unsigned char src_mac_addr[6]; - unsigned char dst_mac_addr[6]; - struct ieee80211_hdr *dot11_hdr; - struct ieee80211_radiotap_header *rtap_hdr; - monitor_interface* mon_if; - - MON_PRINT("enter\n"); - - mon_if = ndev_to_monif(ndev); - if (mon_if == NULL || mon_if->real_ndev == NULL) { - MON_PRINT(" cannot find matched net dev, skip the packet\n"); - goto fail; - } - - if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) - goto fail; - - rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; - if (unlikely(rtap_hdr->it_version)) - goto fail; - - rtap_len = ieee80211_get_radiotap_len(skb->data); - if (unlikely(skb->len < rtap_len)) - goto fail; - - MON_PRINT("radiotap len (should be 14): %d\n", rtap_len); - - /* Skip the ratio tap header */ - skb_pull(skb, rtap_len); - - dot11_hdr = (struct ieee80211_hdr *)skb->data; - frame_ctl = le16_to_cpu(dot11_hdr->frame_control); - /* Check if the QoS bit is set */ - if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { - /* Check if this ia a Wireless Distribution System (WDS) frame - * which has 4 MAC addresses - */ - if (dot11_hdr->frame_control & 0x0080) - qos_len = 2; - if ((dot11_hdr->frame_control & 0x0300) == 0x0300) - dot11_hdr_len += 6; - - memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); - memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); - - /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for - * for two MAC addresses - */ - skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); - pdata = (unsigned char*)skb->data; - memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); - memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); - PKTSETPRIO(skb, 0); - - MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); - - /* Use the real net device to transmit the packet */ - ret = dhd_start_xmit(skb, mon_if->real_ndev); - - return ret; - } -fail: - dev_kfree_skb(skb); - return 0; -} - -static void dhd_mon_if_set_multicast_list(struct net_device *ndev) -{ - monitor_interface* mon_if; - - mon_if = ndev_to_monif(ndev); - if (mon_if == NULL || mon_if->real_ndev == NULL) { - MON_PRINT(" cannot find matched net dev, skip the packet\n"); - } else { - MON_PRINT("enter, if name: %s, matched if name %s\n", - ndev->name, mon_if->real_ndev->name); - } -} - -static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) -{ - int ret = 0; - monitor_interface* mon_if; - - mon_if = ndev_to_monif(ndev); - if (mon_if == NULL || mon_if->real_ndev == NULL) { - MON_PRINT(" cannot find matched net dev, skip the packet\n"); - } else { - MON_PRINT("enter, if name: %s, matched if name %s\n", - ndev->name, mon_if->real_ndev->name); - } - return ret; -} - -/** - * Global function definitions (declared in dhd_linux_mon.h) - */ - -int dhd_add_monitor(char *name, struct net_device **new_ndev) -{ - int i; - int idx = -1; - int ret = 0; - struct net_device* ndev = NULL; - dhd_linux_monitor_t **dhd_mon; - - mutex_lock(&g_monitor.lock); - - MON_TRACE("enter, if name: %s\n", name); - if (!name || !new_ndev) { - MON_PRINT("invalid parameters\n"); - ret = -EINVAL; - goto out; - } - - /* - * Find a vacancy - */ - for (i = 0; i < DHD_MAX_IFS; i++) - if (g_monitor.mon_if[i].mon_ndev == NULL) { - idx = i; - break; - } - if (idx == -1) { - MON_PRINT("exceeds maximum interfaces\n"); - ret = -EFAULT; - goto out; - } - - ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*)); - if (!ndev) { - MON_PRINT("failed to allocate memory\n"); - ret = -ENOMEM; - goto out; - } - - ndev->type = ARPHRD_IEEE80211_RADIOTAP; - strncpy(ndev->name, name, IFNAMSIZ); - ndev->name[IFNAMSIZ - 1] = 0; - ndev->netdev_ops = &dhd_mon_if_ops; - - ret = register_netdevice(ndev); - if (ret) { - MON_PRINT(" register_netdevice failed (%d)\n", ret); - goto out; - } - - *new_ndev = ndev; - g_monitor.mon_if[idx].radiotap_enabled = TRUE; - g_monitor.mon_if[idx].mon_ndev = ndev; - g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name); - dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev); - *dhd_mon = &g_monitor; - g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED; - MON_PRINT("net device returned: 0x%p\n", ndev); - MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name); - -out: - if (ret && ndev) - free_netdev(ndev); - - mutex_unlock(&g_monitor.lock); - return ret; - -} - -int dhd_del_monitor(struct net_device *ndev) -{ - int i; - if (!ndev) - return -EINVAL; - mutex_lock(&g_monitor.lock); - for (i = 0; i < DHD_MAX_IFS; i++) { - if (g_monitor.mon_if[i].mon_ndev == ndev || - g_monitor.mon_if[i].real_ndev == ndev) { - - g_monitor.mon_if[i].real_ndev = NULL; - unregister_netdevice(g_monitor.mon_if[i].mon_ndev); - free_netdev(g_monitor.mon_if[i].mon_ndev); - g_monitor.mon_if[i].mon_ndev = NULL; - g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED; - break; - } - } - - if (g_monitor.monitor_state != MONITOR_STATE_INTERFACE_DELETED) - MON_PRINT("IF not found in monitor array, is this a monitor IF? 0x%p\n", ndev); - mutex_unlock(&g_monitor.lock); - - return 0; -} - -int dhd_monitor_init(void *dhd_pub) -{ - if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) { - g_monitor.dhd_pub = dhd_pub; - mutex_init(&g_monitor.lock); - g_monitor.monitor_state = MONITOR_STATE_INIT; - } - return 0; -} - -int dhd_monitor_uninit(void) -{ - int i; - struct net_device *ndev; - mutex_lock(&g_monitor.lock); - if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) { - for (i = 0; i < DHD_MAX_IFS; i++) { - ndev = g_monitor.mon_if[i].mon_ndev; - if (ndev) { - unregister_netdevice(ndev); - free_netdev(ndev); - g_monitor.mon_if[i].real_ndev = NULL; - g_monitor.mon_if[i].mon_ndev = NULL; - } - } - g_monitor.monitor_state = MONITOR_STATE_DEINIT; - } - mutex_unlock(&g_monitor.lock); - return 0; -} diff --git a/drivers/net/wireless/bcmdhd/wl_roam.c b/drivers/net/wireless/bcmdhd/wl_roam.c deleted file mode 100644 index c937007d84e5..000000000000 --- a/drivers/net/wireless/bcmdhd/wl_roam.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Linux roam cache - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_roam.c 467328 2014-04-03 01:23:40Z $ - */ - - -#include -#include -#include -#include -#include -#ifdef WL_CFG80211 -#include -#endif -#include - -#define MAX_ROAM_CACHE 100 -#define MAX_CHANNEL_LIST 20 -#define MAX_SSID_BUFSIZE 36 - -#define ROAMSCAN_MODE_NORMAL 0 -#define ROAMSCAN_MODE_WES 1 - -typedef struct { - chanspec_t chanspec; - int ssid_len; - char ssid[MAX_SSID_BUFSIZE]; -} roam_channel_cache; - -typedef struct { - int n; - chanspec_t channels[MAX_CHANNEL_LIST]; -} channel_list_t; - -static int n_roam_cache = 0; -static int roam_band = WLC_BAND_AUTO; -static roam_channel_cache roam_cache[MAX_ROAM_CACHE]; -static uint band2G, band5G, band_bw; - -void init_roam(int ioctl_ver) -{ -#ifdef D11AC_IOTYPES - if (ioctl_ver == 1) { - /* legacy chanspec */ - band2G = WL_LCHANSPEC_BAND_2G; - band5G = WL_LCHANSPEC_BAND_5G; - band_bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE; - } else { - band2G = WL_CHANSPEC_BAND_2G; - band5G = WL_CHANSPEC_BAND_5G; - band_bw = WL_CHANSPEC_BW_20; - } -#else - band2G = WL_CHANSPEC_BAND_2G; - band5G = WL_CHANSPEC_BAND_5G; - band_bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; -#endif /* D11AC_IOTYPES */ - - n_roam_cache = 0; - roam_band = WLC_BAND_AUTO; -} - - -void set_roam_band(int band) -{ - roam_band = band; -} - -void reset_roam_cache(void) -{ - - n_roam_cache = 0; -} - -void add_roam_cache(wl_bss_info_t *bi) -{ - int i; - uint8 channel; - char chanbuf[CHANSPEC_STR_LEN]; - - - if (n_roam_cache >= MAX_ROAM_CACHE) - return; - - for (i = 0; i < n_roam_cache; i++) { - if ((roam_cache[i].ssid_len == bi->SSID_len) && - (roam_cache[i].chanspec == bi->chanspec) && - (memcmp(roam_cache[i].ssid, bi->SSID, bi->SSID_len) == 0)) { - /* identical one found, just return */ - return; - } - } - - roam_cache[n_roam_cache].ssid_len = bi->SSID_len; - channel = wf_chspec_ctlchan(bi->chanspec); - WL_DBG(("CHSPEC = %s, CTL %d\n", wf_chspec_ntoa_ex(bi->chanspec, chanbuf), channel)); - roam_cache[n_roam_cache].chanspec = - (channel <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw | channel; - memcpy(roam_cache[n_roam_cache].ssid, bi->SSID, bi->SSID_len); - - n_roam_cache++; -} - -static bool is_duplicated_channel(const chanspec_t *channels, int n_channels, chanspec_t new) -{ - int i; - - for (i = 0; i < n_channels; i++) { - if (channels[i] == new) - return TRUE; - } - - return FALSE; -} - -int get_roam_channel_list(int target_chan, - chanspec_t *channels, const wlc_ssid_t *ssid, int ioctl_ver) -{ - int i, n = 1; - char chanbuf[CHANSPEC_STR_LEN]; - - /* first index is filled with the given target channel */ - channels[0] = (target_chan & WL_CHANSPEC_CHAN_MASK) | - (target_chan <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw; - - WL_DBG((" %s: %03d 0x%04X\n", __FUNCTION__, target_chan, channels[0])); - - - for (i = 0; i < n_roam_cache; i++) { - chanspec_t ch = roam_cache[i].chanspec; - bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch); - bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch); - bool band_match = ((roam_band == WLC_BAND_AUTO) || - ((roam_band == WLC_BAND_2G) && is_2G) || - ((roam_band == WLC_BAND_5G) && is_5G)); - - ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw; - if ((roam_cache[i].ssid_len == ssid->SSID_len) && - band_match && !is_duplicated_channel(channels, n, ch) && - (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) { - /* match found, add it */ - WL_DBG(("%s: Chanspec = %s\n", __FUNCTION__, - wf_chspec_ntoa_ex(ch, chanbuf))); - channels[n++] = ch; - } - } - - return n; -} - - -void print_roam_cache(void) -{ - int i; - - WL_DBG((" %d cache\n", n_roam_cache)); - - for (i = 0; i < n_roam_cache; i++) { - roam_cache[i].ssid[roam_cache[i].ssid_len] = 0; - WL_DBG(("0x%02X %02d %s\n", roam_cache[i].chanspec, - roam_cache[i].ssid_len, roam_cache[i].ssid)); - } -} - -static void add_roamcache_channel(channel_list_t *channels, chanspec_t ch) -{ - int i; - - if (channels->n >= MAX_CHANNEL_LIST) /* buffer full */ - return; - - for (i = 0; i < channels->n; i++) { - if (channels->channels[i] == ch) /* already in the list */ - return; - } - - channels->channels[i] = ch; - channels->n++; - - WL_DBG((" RCC: %02d 0x%04X\n", - ch & WL_CHANSPEC_CHAN_MASK, ch)); -} - -void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver) -{ - int error, i, prev_channels; - channel_list_t channel_list; - char iobuf[WLC_IOCTL_SMLEN]; - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - wlc_ssid_t ssid; - - - if (!wl_get_drv_status(cfg, CONNECTED, dev)) { - WL_DBG(("Not associated\n")); - return; - } - - /* need to read out the current cache list - as the firmware may change dynamically - */ - error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0, - (void *)&channel_list, sizeof(channel_list), NULL); - - WL_DBG(("%d AP, %d cache item(s), err=%d\n", n_roam_cache, channel_list.n, error)); - - error = wldev_get_ssid(dev, &ssid); - if (error) { - WL_ERR(("Failed to get SSID, err=%d\n", error)); - return; - } - - prev_channels = channel_list.n; - for (i = 0; i < n_roam_cache; i++) { - chanspec_t ch = roam_cache[i].chanspec; - bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch); - bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch); - bool band_match = ((roam_band == WLC_BAND_AUTO) || - ((roam_band == WLC_BAND_2G) && is_2G) || - ((roam_band == WLC_BAND_5G) && is_5G)); - - if ((roam_cache[i].ssid_len == ssid.SSID_len) && - band_match && (memcmp(roam_cache[i].ssid, ssid.SSID, ssid.SSID_len) == 0)) { - /* match found, add it */ - ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw; - add_roamcache_channel(&channel_list, ch); - } - } - if (prev_channels != channel_list.n) { - /* channel list updated */ - error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list, - sizeof(channel_list), iobuf, sizeof(iobuf), NULL); - if (error) { - WL_ERR(("Failed to update roamscan channels, error = %d\n", error)); - } - } -} - -void wl_update_roamscan_cache_by_band(struct net_device *dev, int band) -{ - int i, error, ioctl_ver, wes_mode; - channel_list_t chanlist_before, chanlist_after; - char iobuf[WLC_IOCTL_SMLEN]; - - roam_band = band; - if (band == WLC_BAND_AUTO) - return; - - error = wldev_iovar_getint(dev, "roamscan_mode", &wes_mode); - if (error) { - WL_ERR(("Failed to get roamscan mode, error = %d\n", error)); - return; - } - /* in case of WES mode, then skip the update */ - if (wes_mode) - return; - - error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0, - (void *)&chanlist_before, sizeof(channel_list_t), NULL); - if (error) { - WL_ERR(("Failed to get roamscan channels, error = %d\n", error)); - return; - } - ioctl_ver = wl_cfg80211_get_ioctl_version(); - chanlist_after.n = 0; - /* filtering by the given band */ - for (i = 0; i < chanlist_before.n; i++) { - chanspec_t chspec = chanlist_before.channels[i]; - bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(chspec) : CHSPEC_IS2G(chspec); - bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(chspec) : CHSPEC_IS5G(chspec); - bool band_match = ((band == WLC_BAND_2G) && is_2G) || - ((band == WLC_BAND_5G) && is_5G); - if (band_match) { - chanlist_after.channels[chanlist_after.n++] = chspec; - } - } - - if (chanlist_before.n == chanlist_after.n) - return; - - error = wldev_iovar_setbuf(dev, "roamscan_channels", &chanlist_after, - sizeof(channel_list_t), iobuf, sizeof(iobuf), NULL); - if (error) { - WL_ERR(("Failed to update roamscan channels, error = %d\n", error)); - } -} diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c deleted file mode 100644 index a8713802fb0e..000000000000 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Common function shared by Linux WEXT, cfg80211 and p2p drivers - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wldev_common.c 538678 2015-03-04 13:28:49Z $ - */ - -#include -#include -#include -#include - -#include -#include -#include - -#define htod32(i) (i) -#define htod16(i) (i) -#define dtoh32(i) (i) -#define dtoh16(i) (i) -#define htodchanspec(i) (i) -#define dtohchanspec(i) (i) - -#define WLDEV_ERROR(args) \ - do { \ - printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__); \ - printk args; \ - } while (0) - -extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd); - -s32 wldev_ioctl( - struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) -{ - s32 ret = 0; - struct wl_ioctl ioc; - - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; - ioc.set = set; - - ret = dhd_ioctl_entry_local(dev, &ioc, cmd); - - return ret; -} - -/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be - * taken care of in dhd_ioctl_entry. Internal use only, not exposed to - * wl_iw, wl_cfg80211 and wl_cfgp2p - */ -static s32 wldev_mkiovar( - s8 *iovar_name, s8 *param, s32 paramlen, - s8 *iovar_buf, u32 buflen) -{ - s32 iolen = 0; - - iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen); - return iolen; -} - -s32 wldev_iovar_getbuf( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) -{ - s32 ret = 0; - if (buf_sync) { - mutex_lock(buf_sync); - } - wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); - ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); - if (buf_sync) - mutex_unlock(buf_sync); - return ret; -} - - -s32 wldev_iovar_setbuf( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) -{ - s32 ret = 0; - s32 iovar_len; - if (buf_sync) { - mutex_lock(buf_sync); - } - iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); - if (iovar_len > 0) - ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); - else - ret = BCME_BUFTOOSHORT; - - if (buf_sync) - mutex_unlock(buf_sync); - return ret; -} - -s32 wldev_iovar_setint( - struct net_device *dev, s8 *iovar, s32 val) -{ - s8 iovar_buf[WLC_IOCTL_SMLEN]; - - val = htod32(val); - memset(iovar_buf, 0, sizeof(iovar_buf)); - return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf, - sizeof(iovar_buf), NULL); -} - - -s32 wldev_iovar_getint( - struct net_device *dev, s8 *iovar, s32 *pval) -{ - s8 iovar_buf[WLC_IOCTL_SMLEN]; - s32 err; - - memset(iovar_buf, 0, sizeof(iovar_buf)); - err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf, - sizeof(iovar_buf), NULL); - if (err == 0) - { - memcpy(pval, iovar_buf, sizeof(*pval)); - *pval = dtoh32(*pval); - } - return err; -} - -/** Format a bsscfg indexed iovar buffer. The bsscfg index will be - * taken care of in dhd_ioctl_entry. Internal use only, not exposed to - * wl_iw, wl_cfg80211 and wl_cfgp2p - */ -s32 wldev_mkiovar_bsscfg( - const s8 *iovar_name, s8 *param, s32 paramlen, - s8 *iovar_buf, s32 buflen, s32 bssidx) -{ - const s8 *prefix = "bsscfg:"; - s8 *p; - u32 prefixlen; - u32 namelen; - u32 iolen; - - if (bssidx == 0) { - return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen, - (s8 *) iovar_buf, buflen); - } - - prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ - namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */ - iolen = prefixlen + namelen + sizeof(u32) + paramlen; - - if (buflen < 0 || iolen > (u32)buflen) - { - WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__)); - return BCME_BUFTOOSHORT; - } - - p = (s8 *)iovar_buf; - - /* copy prefix, no null */ - memcpy(p, prefix, prefixlen); - p += prefixlen; - - /* copy iovar name including null */ - memcpy(p, iovar_name, namelen); - p += namelen; - - /* bss config index as first param */ - bssidx = htod32(bssidx); - memcpy(p, &bssidx, sizeof(u32)); - p += sizeof(u32); - - /* parameter buffer follows */ - if (paramlen) - memcpy(p, param, paramlen); - - return iolen; - -} - -s32 wldev_iovar_getbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) -{ - s32 ret = 0; - if (buf_sync) { - mutex_lock(buf_sync); - } - - wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); - ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); - if (buf_sync) { - mutex_unlock(buf_sync); - } - return ret; - -} - -s32 wldev_iovar_setbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) -{ - s32 ret = 0; - s32 iovar_len; - if (buf_sync) { - mutex_lock(buf_sync); - } - iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); - if (iovar_len > 0) - ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); - else { - ret = BCME_BUFTOOSHORT; - } - - if (buf_sync) { - mutex_unlock(buf_sync); - } - return ret; -} - -s32 wldev_iovar_setint_bsscfg( - struct net_device *dev, s8 *iovar, s32 val, s32 bssidx) -{ - s8 iovar_buf[WLC_IOCTL_SMLEN]; - - val = htod32(val); - memset(iovar_buf, 0, sizeof(iovar_buf)); - return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, - sizeof(iovar_buf), bssidx, NULL); -} - - -s32 wldev_iovar_getint_bsscfg( - struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx) -{ - s8 iovar_buf[WLC_IOCTL_SMLEN]; - s32 err; - - memset(iovar_buf, 0, sizeof(iovar_buf)); - err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf, - sizeof(iovar_buf), bssidx, NULL); - if (err == 0) - { - memcpy(pval, iovar_buf, sizeof(*pval)); - *pval = dtoh32(*pval); - } - return err; -} - -int wldev_get_link_speed( - struct net_device *dev, int *plink_speed) -{ - int error; - - if (!plink_speed) - return -ENOMEM; - error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0); - if (unlikely(error)) - return error; - - /* Convert internal 500Kbps to Kbps */ - *plink_speed *= 500; - return error; -} - -int wldev_get_rssi( - struct net_device *dev, scb_val_t *scb_val) -{ - int error; - - if (!scb_val) - return -ENOMEM; - - error = wldev_ioctl(dev, WLC_GET_RSSI, scb_val, sizeof(scb_val_t), 0); - if (unlikely(error)) - return error; - - return error; -} - -int wldev_get_ssid( - struct net_device *dev, wlc_ssid_t *pssid) -{ - int error; - - if (!pssid) - return -ENOMEM; - error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0); - if (unlikely(error)) - return error; - pssid->SSID_len = dtoh32(pssid->SSID_len); - return error; -} - -int wldev_get_band( - struct net_device *dev, uint *pband) -{ - int error; - - error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0); - return error; -} - -int wldev_set_band( - struct net_device *dev, uint band) -{ - int error = -1; - - if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { - error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true); - if (!error) - dhd_bus_band_set(dev, band); - } - return error; -} - -int wldev_get_datarate(struct net_device *dev, int *datarate) -{ - int error = 0; - - error = wldev_ioctl(dev, WLC_GET_RATE, datarate, sizeof(int), false); - if (error) { - return -1; - } else { - *datarate = dtoh32(*datarate); - } - - return error; -} - -extern chanspec_t -wl_chspec_driver_to_host(chanspec_t chanspec); -#define WL_EXTRA_BUF_MAX 2048 -int wldev_get_mode( - struct net_device *dev, uint8 *cap) -{ - int error = 0; - int chanspec = 0; - uint16 band = 0; - uint16 bandwidth = 0; - wl_bss_info_t *bss = NULL; - char* buf = NULL; - - buf = kmalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); - if (!buf) { - WLDEV_ERROR(("%s:NOMEM\n", __FUNCTION__)); - return -ENOMEM; - } - - *(u32*) buf = htod32(WL_EXTRA_BUF_MAX); - error = wldev_ioctl(dev, WLC_GET_BSS_INFO, (void*)buf, WL_EXTRA_BUF_MAX, false); - if (error) { - WLDEV_ERROR(("%s:failed:%d\n", __FUNCTION__, error)); - kfree(buf); - buf = NULL; - return error; - } - bss = (struct wl_bss_info *)(buf + 4); - chanspec = wl_chspec_driver_to_host(bss->chanspec); - - band = chanspec & WL_CHANSPEC_BAND_MASK; - bandwidth = chanspec & WL_CHANSPEC_BW_MASK; - - if (band == WL_CHANSPEC_BAND_2G) { - if (bss->n_cap) - strcpy(cap, "n"); - else - strcpy(cap, "bg"); - } else if (band == WL_CHANSPEC_BAND_5G) { - if (bandwidth == WL_CHANSPEC_BW_80) - strcpy(cap, "ac"); - else if ((bandwidth == WL_CHANSPEC_BW_40) || (bandwidth == WL_CHANSPEC_BW_20)) { - if ((bss->nbss_cap & 0xf00) && (bss->n_cap)) - strcpy(cap, "n|ac"); - else if (bss->n_cap) - strcpy(cap, "n"); - else if (bss->vht_cap) - strcpy(cap, "ac"); - else - strcpy(cap, "a"); - } else { - WLDEV_ERROR(("%s:Mode get failed\n", __FUNCTION__)); - error = BCME_ERROR; - } - - } - kfree(buf); - buf = NULL; - return error; -} -int wldev_set_country( - struct net_device *dev, char *country_code, bool notify, bool user_enforced) -{ - int error = -1; - wl_country_t cspec = {{0}, 0, {0}}; - scb_val_t scbval; - char smbuf[WLC_IOCTL_SMLEN]; - struct wireless_dev *wdev = ndev_to_wdev(dev); - struct wiphy *wiphy = wdev->wiphy; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (!country_code) - return error; - - bzero(&scbval, sizeof(scb_val_t)); - error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL); - if (error < 0) { - WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error)); - return error; - } - - if ((error < 0) || - (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { - - if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) { - bzero(&scbval, sizeof(scb_val_t)); - error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); - if (error < 0) { - WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", - __FUNCTION__, error)); - return error; - } - } - - cspec.rev = -1; - memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); - memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); - dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec); - error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), - smbuf, sizeof(smbuf), NULL); - if (error < 0) { - WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - return error; - } - dhd_bus_country_set(dev, &cspec, notify); - WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - } - return 0; -} diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h deleted file mode 100644 index 642d45ea553a..000000000000 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Common function shared by Linux WEXT, cfg80211 and p2p drivers - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wldev_common.h 528551 2015-01-22 14:00:54Z $ - */ -#ifndef __WLDEV_COMMON_H__ -#define __WLDEV_COMMON_H__ - -#include - -/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or - * netdev_ops->ndo_do_ioctl in new kernels) - * @dev: the net_device handle - */ -s32 wldev_ioctl( - struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); - -/** Retrieve named IOVARs, this function calls wl_dev_ioctl with - * WLC_GET_VAR IOCTL code - */ -s32 wldev_iovar_getbuf( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); - -/** Set named IOVARs, this function calls wl_dev_ioctl with - * WLC_SET_VAR IOCTL code - */ -s32 wldev_iovar_setbuf( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); - -s32 wldev_iovar_setint( - struct net_device *dev, s8 *iovar, s32 val); - -s32 wldev_iovar_getint( - struct net_device *dev, s8 *iovar, s32 *pval); - -/** The following function can be implemented if there is a need for bsscfg - * indexed IOVARs - */ - -s32 wldev_mkiovar_bsscfg( - const s8 *iovar_name, s8 *param, s32 paramlen, - s8 *iovar_buf, s32 buflen, s32 bssidx); - -/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with - * WLC_GET_VAR IOCTL code - */ -s32 wldev_iovar_getbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, - void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); - -/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with - * WLC_SET_VAR IOCTL code - */ -s32 wldev_iovar_setbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, - void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); - -s32 wldev_iovar_getint_bsscfg( - struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx); - -s32 wldev_iovar_setint_bsscfg( - struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); - -extern int dhd_net_set_fw_path(struct net_device *dev, char *fw); -extern int dhd_net_bus_suspend(struct net_device *dev); -extern int dhd_net_bus_resume(struct net_device *dev, uint8 stage); -extern int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, - unsigned long delay_msec); -extern void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, - wl_country_t *cspec); -extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify); -extern void dhd_bus_band_set(struct net_device *dev, uint band); -extern int wldev_set_country(struct net_device *dev, char *country_code, bool notify, - bool user_enforced); -extern int net_os_wake_lock(struct net_device *dev); -extern int net_os_wake_unlock(struct net_device *dev); -extern int net_os_wake_lock_timeout(struct net_device *dev); -extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); -extern int net_os_set_dtim_skip(struct net_device *dev, int val); -extern int net_os_set_suspend_disable(struct net_device *dev, int val); -extern int net_os_set_suspend(struct net_device *dev, int val, int force); -extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, - int max, int *bytes_left); - -/* Get the link speed from dongle, speed is in kpbs */ -int wldev_get_link_speed(struct net_device *dev, int *plink_speed); - -int wldev_get_rssi(struct net_device *dev, scb_val_t *prssi); - -int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid); - -int wldev_get_band(struct net_device *dev, uint *pband); - -int wldev_get_mode(struct net_device *dev, uint8 *pband); -int wldev_get_datarate(struct net_device *dev, int *datarate); -int wldev_set_band(struct net_device *dev, uint band); - - -#endif /* __WLDEV_COMMON_H__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt b/drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt deleted file mode 100644 index ddcd4f5c65de..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/ChangeLog/ReleaseNote.txt +++ /dev/null @@ -1,236 +0,0 @@ -DHD 1.141.X Release for BCM4339, 4354, 43455 SDIO Projects. - --------------------------------- -Change History --------------------------------- - -Additional fixes: - - A-37505450 Fix RTT report of providing wrong information - - CVE-2017-0706 A-35195787 Adding boundary check in wl_cfg80211_mgmt_tx - - CVE-2017-0573 A-34469904 Fix buffer overrun in wl_android_set_roampref - - CVE-2016-8464 A-29000183 Fix buffer overrun in private command path - - A-29863589 Add boundary check while getting channel spec - - A-28336924 Check to avoid sending Disassoc in unassociated state - - A-27419732 Fix CONFIG_HZ dependency in wifi driver - - A-24469238 Add a NULL check in dhd_pno_get_gscan_batch_from_fw - - A-24270601 Disable debug trace event WLC_E_TRACE - - A-22666437 Fix for watch dog issue in wifi connect test - - Add ability to pass flags to get_country_code - - -DHD 1.141.67.33 - 2018-03-09 - - CVE-2017-13292 A-70722061 Fix integer overflow in wl_get_assoc_ies - - CVE-2017-13303 A-71359108 Remove obsoleted wl_cfgvendor_priv_string_handler - -DHD 1.141.67.32 - 2017-12-14 - - Fixed buffer overrun issue in wl_parse_ssid_list_tlv() - - Fixed parsing issue on wl_parse_ssid_list_tlv() for PNO setup - - Fixed memory leak in PNO - - Fixed potential buffer overflow - - Fixed missed SSID/MAC filtering in log for security reason - -DHD 1.141.67.30 - 2017.8.31 - - Security fix - - CVE-2017-0786 A-37351060 Added boundary check in wl_escan_handler() - - CVE-2017-0787 A-37722970 Added boundary check in dhd_pno_process_epno_result() - - CVE-2017-0788 A-37722328 Added boundary check in dhd_handle_hotlist_scan_evt() - - CVE-2017-0789 A-37685267 Removed unused SWC feature - - CVE-2017-0790 A-37357704 Added boundary check in dhd_process_full_gscan_result() - - CVE-2017-0791 A-37306719 Added event length check in wl_notify_rx_mgmt_frame() - - CVE-2017-0792 A-37305578 Added event length check in dhd_rtt_event_handler() - - V2017070601 Added P2P IE length check in parsing routine - -DHD 1.141.67.29 - 2017.6.27 - - Security fix - - CVE-2017-0705 A-34973477 Added a boundary check in the handling of gscan attribute for significant change bssids - - CVE-2017-0706 A-35195787 Added a length check of tx mgmt frame - -DHD 1.141.67.28 - 2017.5.26 - - Security fix - - CVE-2017-0633 Enhanced buffer usage in IOCTL path - - CVE-2016-0802 Code enhancement for prevention of overflow - -DHD 1.141.67.27 - 2017.3.24 - - Google security fix - - Fix buffer overrun in wl_cfg80211_add_iw_ie, CVE-2017-0567, A-32125310. - - Fix buffer overrun in wl_run_escan, CVE-2017-0568, A-34197514. - - Fix buffer overrun in dhd_wlfc_reorderinfo_indicate, CVE-2017-0571, A-34203305. - - Fix buffer overrun in dhd_pno_process_anqpo_result, CVE-2017-0572, A-34198931. - - Prevent stack overflow related with AKM suite count, CVE-2017-0573, A-34469904. - -DHD 1.141.67.26 - 2017.2.24 - - Google security fix - Prevent buffer overflow of "default_chan_list" in wl_run_escan(). - - Google security fix - Check a "results->pkt_count" length not to exceed allocated memory length. - - Google security fix - Removing the unused WEXT file, A-32124445 - -DHD 1.141.67.25 - 2017.1.24 - - Google Security Patch - fix possible use-after-free case, A-32838767 - -DHD 1.141.67.24 - 2016.12.30 - - Fix for PMF AP Connectivity issue [CASE# 1097627] - - Fix for p2p disconnection when switching AP [CASE# 1095787] - - Google Security - Elevation of privilege vulnerability in Broadcom Wi-Fi driver - *A-32174590 - *A-32219255 - *A-32219453 - *A-29000183 - *A-32474971 - (A-24739315 / A-32219121 / A-31822524 is not needed for 43455) - -DHD 1.141.67.23 - 2016.09.09 - - Google security fix.(ANDROID-29009982) - -DHD 1.141.67.22 - 2016.07.08 - - Google security enhancement of previous vulnerability fix.(ANDROID-26492805) - -DHD 1.141.67.21 - 2016.05.20 - - Android security fixes.(ANDROID-26425765, ANDROID-26571522) - - Fix a buffer overwrite in dev_wlc_bufvar_set(). [CASE# 1021341] - - Changing copyright of driver files to open copyright. [CASE# 1044970] - -DHD 1.141.67.20 - 2016.03.21 - - Fix extra vulnerabilities reported by google. - -DHD 1.141.67.19 - 2016.02.22 - - Fix vulnerabilities reported by google - validate remaining space in WPS IE. - -DHD 1.141.67.18 - 2016.01.12 - - Avoiding corner case accessing suspended sd host unexpectedly. [CASE# 1003434] - - Fixing P2P group add issue in 5GHz. [CASE# 1005073] - - Ethernet type security vulnerability fix in DHD. - - Fixes potential buffer overflow when parsing WPS_ID_DEVICE_NAME and in sched scan result handler. - -DHD 1.141.67.17 - 2015.12.08 - - Fix host memory corruption problem related with linkstat. [CASE# 999609, 999642], Kitakami R2.1 43455, Loire 43455 - - Porting scan_abort feature from Kernel. [CASE# 998204], Loire 43455 - -DHD 1.141.67.16 - 2015.11.20 - - Enabled Gscan in the Makefile for Shinano R2.2 4354 - - Disable Lossless Roaming for FT over DS and FT over Air for Shinano R2 4339 - - Fix build failure with lower version of kernel - -DHD 1.141.67.15 - 2015.11.10 - - Additional Android M updates for Loire - - 11mc ftm - - ePNO - - RSSI Monitoring - - ANQP offload - -DHD 1.141.67.14 - 2015.11.04 - - Android M updates - - Add mkeep_alive feature - - 5GHz Softap - - Gscan Updates - - LinkStat DHD Updates - -DHD 1.141.67.13 - 2015.08.17 - - Not to forward BRCM event as a network pkt '0x886c' [CASE# 952625], Shinano 2.1, Kitakami R2,43455 - -DHD 1.141.67.12 - 2015.07.15 - - Add srl/lrl value setting in Softap, fix the issue not set properly. [CASE# 912911, 930776], Shinano 2.1, Kitakami R2,43455 - - Fix for P2P TA issue[ CASE#943732], Kitakami R2, 43455 - - Fix for linkstat buffer corruption causing android framework crash [CASE # 940151], Shinano R2.1(4354), Kitakami R2, 43455 - -DHD 1.141.67.11 - 2015.07.08 - - 4-way handshake delayed when roaming due to uplink traffic (Shinano 2.1 BCM4339 CASE#886484) - - Add bcn_to_dly iovar to control link_down event,(Kitakami R2 43455 CASE#912211) - - GSCAN fix only for Kitakami R2 43455 - -DHD 1.141.67.10 - 2015.05.29 - - Add DHD flag to disable 11N proprietary rates. (Kitakami R2 43455 CASE#927300) - - Disable TX Beamforming (tx only). (Kitakami R2 43455 CASE#925270) - -DHD 1.141.67.9 - 2015.04.30 - - TDLS mgmt build error fix CASE#844655 (CASE#911280) - -DHD 1.141.67.8 - 2015.04.14 - - Firmware not responding (when running batch scan while in dhcp negotiation (CASE#907419) - - Question regarding a huge kmalloc barely used (CASE#903335) - - Code questions (CASE#896789) - - WL_VENDOR_EXT_SUPPORT definition (CASE#901912) - - Release wake lock("wlan_wake") when terminating event thread - -DHD 1.141.67.7 - 2015.03.13 - - Use if_counters for connection statistics per interface when available, CSP:892522, Only available in Kitakami R2 43455. - - Fix for ARP stuck issue in multihoming CSP:895926 - -DHD 1.141.67.6 - 2015.02.03 - - Support for 43455. - - Support for 64 bits host system. - - Update some copyright notices. - - Fix for driver fails to load if previous instance of wpa_supplicant did not terminate properly. - - Reduce P2P connection time. - -DHD 1.141.67.5 - 2015.01.09 - - Fill the vht_cap field of ieee80211_supported_band(Wrong Max link rate for VHT), CSP #862670 - - Reset beacon found status whenever regulatory domain settings are changed, CSP #868771 - - Allow to scan for p2p on passive channel, CSP #868771 - - Fix trap in dhd_free(), CSP #874320 - - Creating P2P group in available bandwidths in passive channels on 5GHz region, CSP #830497 - -DHD 1.141.67.4 - 2014.12.5 - - Fix build errors caused by Android L updates - - Fix some warning and potential build error with Kernel 3.8 above. - -DHD 1.141.67.3 - 2014.11.20 (Google L support) - - Including android Google L adaptation code - (Gscan, Linkstat, Private PNO and RTT which can be selectable in Makefie) - - Makefile(Google Android L), Makefile.kk (for Kitkat) - - Enable Dongle memory dump feature. - - Increase max nvram buffer size. - -DHD 1.141.67.2 - 2014.09.05 - - Fix for WFA PMF_AP certification. CSP #824822 - - Netif packet counters are not updated in wlfc flow control - - Adding check routine , wakelock, during softap - - WiFi Direct Certification 5.1.20 change GAS frame handling - - hostapd ap_info null ptr check added - -DHD 1.141.67.1 - 2014.07.28 - - Update Ccode translate table for SOMC - - Don't use wlfc info exchange when a device is asleep on SDIO - - Increase MAX_CNTL_TX_TIMEOUT to 3 from 2 by specifying it in Makefile. CSP # 800769 - -DHD 1.141.67 - 2014.07.09 - - Keep connection while regulatory code change - CSP #803478 - - Including action code for tunneled prob req to set wfd ie. CSP # 809533 - - MAX_KSO_ATTEMPTS changed to 64, same as R1's - - Prevent running wl_event_handler while HANG is occurred - - Fix for hostapd buffer free - -DHD 1.141.65 - 2014.06.05 - - Fix mmc error at re-loading dhd driver CSP#779847 - - Add supports for tdls management frames CSP#778769 - - P2P fails after a driver stop / start in the kernel 3.10 - - Increase assoc_retry_max from 3 to 7 to increase a connection rate in very noisy environmnet. - - Added definition SUPPORT_P2P_GO_PS in checking bus_sleep code - - Fix multi-AC detection logic to look at rx packets as well as tx packets - -DHD 1.141.60 - 2014.05.16 - - CSP 791385, tdls auto enable delete in Makefile - - CSP 796606, SOFTAP WPS tethering issue fixed - - CSP:779847 Fix mmc error at re-loading dhd driver - - CSP:793836 Fix for coverity issue - - CSP:770822 Add driver private command to recover link quality - - CSP: 790918 bcn_timeout value change to 8 when VSDB or roaming are enabled - - Deleting set IRQF_TRIGGER_MASK for preventing clear setting of board configuration - - Use CONFIG_COMAT method to make 32-bit ioctl working with 64-bit kernel - - Protect the cfg->ioctl_buf against the wl_set_tx_power/wl_get_tx_power function - - Add check bus sleep check code in dhdsdio_suspend - - Fixed getting chanspec value when handling DFS channels - - Add KSO_ENAB check code in dhd_bcmsdh_send_buf function - - Dynamic change thread priority, policy by use sysfs. value path is /sys/class/net/wlan0/dpc_prio - - Packet was freed before both proptxstatus and txcomplete finished - - Fix chanspec mismatch - - Fix multicast recive in P2P mode - - Kernel 3.14 support - - Remove the duplicated kfree of ndev->ieee80211_ptr pointer in wl_dealloc_netinfo - - Prevent the RTNL assertion when calling the cfg80211_unregister_wdev function while dhd_module_cleanup - - Remove the kernel version dependency in case of using wl_cfg80211_remove_if in wl_cfg80211_handle_ifdel function. - - Country/Revision is not initialized after Wi-Fi off->on - - Fix the incorrect channel extraction from chanspec when 0 is given as a control channel while scanning - - Supporting WNM Notification for HS20 REL2 - - Applying Interaction with MFP by Spec HS2.0 REL2 - -2014.03.19 - DHD 1.141.48 - - Initial Release for Shinano R2, BCM4339 & BCM4354 diff --git a/drivers/net/wireless/bcmdhd_suzuran/Kconfig b/drivers/net/wireless/bcmdhd_suzuran/Kconfig deleted file mode 100755 index 33e379e9ecb7..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/Kconfig +++ /dev/null @@ -1,57 +0,0 @@ -config BCMDHD_SUZURAN - tristate "Broadcom 43xx wireless cards support" - depends on MMC && CFG80211 - ---help--- - This module adds support for wireless adapters based on - Broadcom 43xx chipset. - This driver uses the kernel's cfg80211 subsystem. - If you choose to build a module, it'll be called dhd. Say M if - unsure. - -config BCM43455 - bool "Broadcom 43455 wireless cards support" - depends on BCMDHD_SUZURAN - ---help--- - This module adds support for wireless adapters based on - Broadcom 43455 chipset. - -config BCMDHD_FW_PATH - depends on BCMDHD_SUZURAN - string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" - ---help--- - Path to the firmware file. - -config BCMDHD_NVRAM_PATH - depends on BCMDHD_SUZURAN - string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" - ---help--- - Path to the calibration file. - -config DHD_USE_STATIC_BUF - bool "Enable memory preallocation" - depends on BCMDHD_SUZURAN - default n - ---help--- - Use memory preallocated in platform - -config BCMDHD_HW_OOB - depends on BCMDHD_SUZURAN - bool "Use H/W OOB to the Host Wakeup" - default y - ---help--- - Use H/W OOB to the Host Wakeup - -config DHD_USE_SCHED_SCAN - bool "Use CFG80211 sched scan" - depends on BCMDHD_SUZURAN && CFG80211 - default n - ---help--- - Use CFG80211 sched scan - -config BROADCOM_WIFI_RESERVED_MEM - bool "BROADCOM Reserved memory for wifi device" - depends on BCMDHD_SUZURAN - ---help--- - This is a configuration for broadcom WLAN driver. diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile b/drivers/net/wireless/bcmdhd_suzuran/Makefile deleted file mode 100755 index c1d46590e9a8..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile +++ /dev/null @@ -1,403 +0,0 @@ -# bcmdhd_suzuran - -##################### -# SDIO Basic feature -##################### -DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ - -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ - -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ - -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ - -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ - -DCONFIG_DTS - -#################### -# Common feature -#################### -DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 -DHDCFLAGS += -DWL_CFG80211 - -# Debug -DHDCFLAGS += -DSIMPLE_MAC_PRINT -DHDCFLAGS += -DDEBUGFS_CFG80211 -# Print out kernel panic point of file and line info when assertion happened -DHDCFLAGS += -DBCMASSERT_LOG - -# Print 8021X -DHDCFLAGS += -DDHD_8021X_DUMP - -# VSDB -DHDCFLAGS += -DVSDB -DHDCFLAGS += -DPROP_TXSTATUS -# Wi-Fi Direct -DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -# For p2p connection issue -DHDCFLAGS += -DWL_SCB_TIMEOUT=10 -# For Kernel ver > 3.6 or Kernel Patch required -DHDCFLAGS += -DWL_SUPPORT_CHAN_BW - -# For TDLS tear down inactive time 10 sec -DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 -# for TDLS RSSI HIGH for establishing TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 -# for TDLS RSSI HIGH for tearing down TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 - -# Roaming -DHDCFLAGS += -DROAM_AP_ENV_DETECTION -DHDCFLAGS += -DROAM_ENABLE -DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - -# Support MAC ACL setting -DHDCFLAGS += -DWL_CFG80211_ACL - -# SoftAP -DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP -DHDCFLAGS += -DDISABLE_11H_SOFTAP -DHDCFLAGS += -DSUPPORT_PM2_ONLY -DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD -DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE - -# For Scan result patch -DHDCFLAGS += -DESCAN_RESULT_PATCH -DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER - -# For Static Buffer -ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) - DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF - DHDCFLAGS += -DENHANCED_STATIC_BUF - DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -endif - -# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) -DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 - -# Ioctl timeout 5000ms -DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 - -# DPC priority -#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 - -# Priority mismatch fix with kernel stack -DHDCFLAGS += -DPKTPRIO_OVERRIDE - -# Prevent rx thread monopolize -DHDCFLAGS += -DWAIT_DEQUEUE - -# Config PM Control -DHDCFLAGS += -DCONFIG_CONTROL_PM - -# Use Android wake lock mechanism -DHDCFLAGS += -DCONFIG_HAS_WAKELOCK - -# idle count -DHDCFLAGS += -DDHD_USE_IDLECOUNT - -# custom specific value define -# For special PNO Event keep wake lock for 10sec -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 -# set keep alive period -ifneq ($(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING),) -DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=$(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING) -else -DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 -endif -# set roam setting values -DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 -DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 - -# Used short dwell time during initial scan -DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME - -# SKB TAILPAD to avoid out of boundary memory access -DHDCFLAGS += -DDHDENABLE_TAILPAD - -# Connection statistics -DHDCFLAGS += -DCONNECTION_STATISTICS - -DHDCFLAGS += -DSUPPORT_P2P_GO_PS - -# Disable TXBF sending -DHDCFLAGS += -DDISABLE_TXBFR - -DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - -# Disable to delay link down event -DHDCFLAGS += -DDISABLE_BCN_DLY - -############################## -# Android Platform Definition -############################## -#ABSOLUTE_BCM_SRC_DIR := $(WLAN_ROOT)/bcmdhd_suzuran -BCM_SRC_DIR := ./ - -########### -# Lollipop -########### -DHDCFLAGS += -DWL_ENABLE_P2P_IF -#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES -# Default definitions for KitKat -DHDCFLAGS += -DWL_CFG80211_STA_EVENT -DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS -# To support p2p private command on kernel 3.8 or above -DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT - -ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD -endif - -ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) -DHDCFLAGS += -DWL_SCHED_SCAN -endif - -ifneq ($(CONFIG_BCM4339),) -# To support GSCAN -#DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o -endif - -ifneq ($(CONFIG_BCM43455),) -# To support RTT -#DHDCFLAGS += -DRTT_SUPPORT -# To support GSCAN -DHDCFLAGS += -DGSCAN_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o -endif - -ifneq ($(CONFIG_BCM4354),) -# To support RTT -DHDCFLAGS += -DRTT_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support GSCAN -#DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o -endif - - -######################### -# Chip dependent feature -######################### -ifneq ($(CONFIG_BCM4354),) - DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DSDIO_CRC_ERROR_FIX - -# tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DREPEAT_READFRAME - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4354),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -# DRIVER_TYPE = y -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM4339),) - DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4339),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # for 4339 only currently - need test for 4354, 43455 - DHDCFLAGS += -DDHD_LOSSLESS_ROAMING - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM43455),) - DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM43455),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -# DHDCFLAGS += -DDISABLE_IF_COUNTERS - DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 - - # Radio_stat v2 - data structure is updated - DHDCFLAGS += -DLINKSTAT_V2 - -# DHDCFLAGS += -DWL_ABORT_SCAN -endif - -# Read custom mac address function -DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE - -# Default Beacon timeout -ifneq ($(CONFIG_SOMC_WLAN_BCN_TIMEOUT),) - DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=$(CONFIG_SOMC_WLAN_BCN_TIMEOUT) -else - DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=3 -endif - -# The number of the maximum devices which phone can associate -DHDCFLAGS += -DSOMC_MAX_ASSOC_NUM=10 - -# Default Listen Interval in Beacons -ifneq ($(CONFIG_SOMC_WLAN_LISTEN_INTERVAL),) - DHDCFLAGS += -DCUSTOM_LISTEN_INTERVAL=$(CONFIG_SOMC_WLAN_LISTEN_INTERVAL) -endif - -# WAPI -DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI - -# Set the number of probe requests per channel -ifneq ($(CONFIG_SOMC_WLAN_SCAN_NPROBES),) - DHDCFLAGS += -DSOMC_WLAN_SCAN_NPROBES=$(CONFIG_SOMC_WLAN_SCAN_NPROBES) -endif - -# Set default nvram path -ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) - DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" -endif - -# Change scan time -ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) - DHDCFLAGS += -DCHANGE_SCAN_TIME -endif - -#EXTRA_LDFLAGS += --strip-debug -EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG -EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" -EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ -KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) - -MODNAME := bcmdhd - -DHDOFILES := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ - dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ - dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o \ - dhd_linux_wq.o aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o \ - hndpmu.o linux_osl.o sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o \ - wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o \ - dhd_somc_custom.o - -DHDOFILES += $(ANDROID_OFILES) - -# Module information used by KBuild framework -obj-$(CONFIG_BCMDHD_SUZURAN) += $(MODNAME).o - -$(MODNAME)-objs := $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile.Nougat b/drivers/net/wireless/bcmdhd_suzuran/Makefile.Nougat deleted file mode 100644 index 7999faaca146..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile.Nougat +++ /dev/null @@ -1,415 +0,0 @@ -# bcmdhd - -##################### -# SDIO Basic feature -##################### -DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ - -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ - -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ - -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ - -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ - -DCONFIG_DTS - -#################### -# Common feature -#################### -DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 -DHDCFLAGS += -DWL_CFG80211 - -# Debug -DHDCFLAGS += -DSIMPLE_MAC_PRINT -DHDCFLAGS += -DDEBUGFS_CFG80211 -# Print out kernel panic point of file and line info when assertion happened -DHDCFLAGS += -DBCMASSERT_LOG - -# Print 8021X -DHDCFLAGS += -DDHD_8021X_DUMP - -# VSDB -DHDCFLAGS += -DVSDB -DHDCFLAGS += -DPROP_TXSTATUS -# Wi-Fi Direct -DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -# For p2p connection issue -DHDCFLAGS += -DWL_SCB_TIMEOUT=10 -# For Kernel ver > 3.6 or Kernel Patch required -DHDCFLAGS += -DWL_SUPPORT_CHAN_BW - -# For TDLS tear down inactive time 10 sec -DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 -# for TDLS RSSI HIGH for establishing TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 -# for TDLS RSSI HIGH for tearing down TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 - -# Roaming -DHDCFLAGS += -DROAM_AP_ENV_DETECTION -DHDCFLAGS += -DROAM_ENABLE -DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - -# Support MAC ACL setting -DHDCFLAGS += -DWL_CFG80211_ACL - -# SoftAP -DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP -DHDCFLAGS += -DDISABLE_11H_SOFTAP -DHDCFLAGS += -DSUPPORT_PM2_ONLY -DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD -DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE - -# For Scan result patch -DHDCFLAGS += -DESCAN_RESULT_PATCH -DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER - -# For Static Buffer -ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) - DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF - DHDCFLAGS += -DENHANCED_STATIC_BUF - DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -endif - -# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) -DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 - -# Ioctl timeout 5000ms -DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 - -# DPC priority -#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 - -# Priority mismatch fix with kernel stack -DHDCFLAGS += -DPKTPRIO_OVERRIDE - -# Prevent rx thread monopolize -DHDCFLAGS += -DWAIT_DEQUEUE - -# Config PM Control -DHDCFLAGS += -DCONFIG_CONTROL_PM - -# Use Android wake lock mechanism -DHDCFLAGS += -DCONFIG_HAS_WAKELOCK - -# idle count -DHDCFLAGS += -DDHD_USE_IDLECOUNT - -# custom specific value define -# For special PNO Event keep wake lock for 10sec -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 -# set keep alive period -ifneq ($(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING),) -DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=$(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING) -else -DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 -endif -# set roam setting values -DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 -DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 - -# Used short dwell time during initial scan -DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME - -# SKB TAILPAD to avoid out of boundary memory access -DHDCFLAGS += -DDHDENABLE_TAILPAD - -# Connection statistics -DHDCFLAGS += -DCONNECTION_STATISTICS - -DHDCFLAGS += -DSUPPORT_P2P_GO_PS - -# Disable TXBF sending -DHDCFLAGS += -DDISABLE_TXBFR - -DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - -# Disable to delay link down event -DHDCFLAGS += -DDISABLE_BCN_DLY - -############################## -# Android Platform Definition -############################## -#ABSOLUTE_BCM_SRC_DIR := $(WLAN_ROOT)/bcmdhd_suzuran -BCM_SRC_DIR := ./ - -############################### -# Android M -############################### -DHDCFLAGS += -DWL_ENABLE_P2P_IF - -# Default definitions for KitKat -DHDCFLAGS += -DWL_CFG80211_STA_EVENT -DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS -# To support p2p private command on kernel 3.8 or above -DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT - -ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD -endif - -ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) -DHDCFLAGS += -DWL_SCHED_SCAN -endif - -ifneq ($(CONFIG_BCM4339),) -# To support GSCAN -#DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o -endif - -ifneq ($(CONFIG_BCM43455),) -# To support RTT -DHDCFLAGS += -DRTT_SUPPORT -# To support GSCAN -DHDCFLAGS += -DGSCAN_SUPPORT -# To support ePNO -DHDCFLAGS += -DEPNO_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support Rssi Monitor -DHDCFLAGS += -DRSSI_MONITOR_SUPPORT -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT -# To support ANQPO - GSCAN must be supported -DHDCFLAGS += -DANQPO_SUPPORT - -# Extra file list for Android M, SOMC -ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o bcmxtlv.o -endif - -ifneq ($(CONFIG_BCM4354),) -# To support RTT -#DHDCFLAGS += -DRTT_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support GSCAN -DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Android M -ANDROID_OFILES := wl_cfgvendor.o -endif - - -######################### -# Chip dependent feature -######################### -ifneq ($(CONFIG_BCM4354),) - DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DSDIO_CRC_ERROR_FIX - -# tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DREPEAT_READFRAME - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4354),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -# DRIVER_TYPE = y -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM4339),) - DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4339),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # for 4339 only currently - need test for 4354, 43455 - DHDCFLAGS += -DDHD_LOSSLESS_ROAMING - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM43455),) - DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM43455),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -# DHDCFLAGS += -DDISABLE_IF_COUNTERS - DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 - - # Radio_stat v2 - data structure is updated - DHDCFLAGS += -DLINKSTAT_V2 - - DHDCFLAGS += -DWL_ABORT_SCAN -endif - -# Read custom mac address function -DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE - -# Default Beacon timeout -ifneq ($(CONFIG_SOMC_WLAN_BCN_TIMEOUT),) - DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=$(CONFIG_SOMC_WLAN_BCN_TIMEOUT) -else - DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=3 -endif - -# The number of the maximum devices which phone can associate -DHDCFLAGS += -DSOMC_MAX_ASSOC_NUM=10 - -# Default Listen Interval in Beacons -ifneq ($(CONFIG_SOMC_WLAN_LISTEN_INTERVAL),) - DHDCFLAGS += -DCUSTOM_LISTEN_INTERVAL=$(CONFIG_SOMC_WLAN_LISTEN_INTERVAL) -endif - -# WAPI -DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI - -# Set the number of probe requests per channel -ifneq ($(CONFIG_SOMC_WLAN_SCAN_NPROBES),) - DHDCFLAGS += -DSOMC_WLAN_SCAN_NPROBES=$(CONFIG_SOMC_WLAN_SCAN_NPROBES) -endif - -# Set default nvram path -ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) - DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" -endif - -# Change scan time -ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) - DHDCFLAGS += -DCHANGE_SCAN_TIME -endif - -# Get country code -#DHDCFLAGS += -DCUSTOM_FORCE_NODFS_FLAG - -# Enable to use Ukraine CODE (UA/999) -DHDCFLAGS += -DENABLE_80211AC_FOR_UA - -#EXTRA_LDFLAGS += --strip-debug -EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG -EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" -EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ -KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) - -MODNAME := wlan - -DHDOFILES := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ - dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ - dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o \ - dhd_linux_wq.o aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o \ - hndpmu.o linux_osl.o sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o \ - wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o \ - dhd_somc_custom.o - -DHDOFILES += $(ANDROID_OFILES) - -# Module information used by KBuild framework -obj-$(CONFIG_BCMDHD_SUZURAN) += $(MODNAME).o - -$(MODNAME)-objs := $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile.kk b/drivers/net/wireless/bcmdhd_suzuran/Makefile.kk deleted file mode 100755 index 1c7ab97d0654..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile.kk +++ /dev/null @@ -1,307 +0,0 @@ -# bcmdhd_suzuran - -##################### -# SDIO Basic feature -##################### -DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ - -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ - -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ - -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ - -DEMBEDDED_PLATFORM -DPNO_SUPPORT - -#################### -# Common feature -#################### -DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 -DHDCFLAGS += -DWL_CFG80211 - -# Debug -DHDCFLAGS += -DSIMPLE_MAC_PRINT -DHDCFLAGS += -DDEBUGFS_CFG80211 -# Print out kernel panic point of file and line info when assertion happened -DHDCFLAGS += -DBCMASSERT_LOG - -# Print 8021X -DHDCFLAGS += -DDHD_8021X_DUMP - -# VSDB -DHDCFLAGS += -DVSDB -DHDCFLAGS += -DPROP_TXSTATUS -# Wi-Fi Direct -DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -# For p2p connection issue -DHDCFLAGS += -DWL_SCB_TIMEOUT=10 - -# For Kernel ver > 3.6 or Kernel Patch required -DHDCFLAGS += -DWL_SUPPORT_CHAN_BW - -# For TDLS tear down inactive time 10 sec -DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 -# for TDLS RSSI HIGH for establishing TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 -# for TDLS RSSI HIGH for tearing down TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 - -# Roaming -DHDCFLAGS += -DROAM_AP_ENV_DETECTION -DHDCFLAGS += -DROAM_ENABLE -DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - -# Support MAC ACL setting -DHDCFLAGS += -DWL_CFG80211_ACL - -# SoftAP -DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP -DHDCFLAGS += -DDISABLE_11H_SOFTAP -DHDCFLAGS += -DSUPPORT_PM2_ONLY -DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD -DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE - -# For Scan result patch -DHDCFLAGS += -DESCAN_RESULT_PATCH -DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER - -# For Static Buffer -ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) - DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF - DHDCFLAGS += -DENHANCED_STATIC_BUF - DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -endif - -# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) -DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 - -# Ioctl timeout 5000ms -DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 - -# DPC priority -#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 - -# Priority mismatch fix with kernel stack -DHDCFLAGS += -DPKTPRIO_OVERRIDE - -# Prevent rx thread monopolize -DHDCFLAGS += -DWAIT_DEQUEUE - -# Config PM Control -DHDCFLAGS += -DCONFIG_CONTROL_PM - -# Use Android wake lock mechanism -DHDCFLAGS += -DCONFIG_HAS_WAKELOCK - -# idle count -DHDCFLAGS += -DDHD_USE_IDLECOUNT - -# custom specific value define -# For special PNO Event keep wake lock for 10sec -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 -# set keep alive period -DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 -# set roam setting values -DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 -DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 - -# Used short dwell time during initial scan -DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME - -# SKB TAILPAD to avoid out of boundary memory access -DHDCFLAGS += -DDHDENABLE_TAILPAD - -# Connection statistics -DHDCFLAGS += -DCONNECTION_STATISTICS - -DHDCFLAGS += -DSUPPORT_P2P_GO_PS - -# Disable TXBF sending -DHDCFLAGS += -DDISABLE_TXBFR - -DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - - -############################## -# Android Platform Definition -############################## - -## Andrioid KitKat ## - -DHDCFLAGS += -DWL_ENABLE_P2P_IF -#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES -# Default definitions for KitKat -DHDCFLAGS += -DWL_CFG80211_STA_EVENT -DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS -# To support p2p private command on kernel 3.8 or above -DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT - - - - -######################### -# Chip dependent feature -######################### -ifneq ($(CONFIG_BCM4354),) - DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DSDIO_CRC_ERROR_FIX - -# tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DREPEAT_READFRAME - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4354),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -# DRIVER_TYPE = y -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM4339),) - DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4339),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # for 4339 only currently - need test for 4354, 43455 - DHDCFLAGS += -DDHD_LOSSLESS_ROAMING - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM43455),) - DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM43455),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -# DHDCFLAGS += -DDISABLE_IF_COUNTERS - DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 - - # Radio_stat v2 - data structure is updated - DHDCFLAGS += -DLINKSTAT_V2 - -# DHDCFLAGS += -DWL_ABORT_SCAN -endif - -#EXTRA_LDFLAGS += --strip-debug -EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG -EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" -EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ -KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) - -DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ - dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ - dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o dhd_linux_wq.o aiutils.o \ - bcmevent.o bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o \ - sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o wl_android.o wl_cfg80211.o \ - wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o - -DHDOFILES += $(ANDROID_OFILES) - -obj-$(CONFIG_BCMDHD_SUZURAN) += bcmdhd.o -bcmdhd-objs += $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile.lp b/drivers/net/wireless/bcmdhd_suzuran/Makefile.lp deleted file mode 100755 index d5d694145526..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile.lp +++ /dev/null @@ -1,351 +0,0 @@ -# bcmdhd_suzuran - -##################### -# SDIO Basic feature -##################### -DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ - -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ - -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ - -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ - -DEMBEDDED_PLATFORM -DPNO_SUPPORT - -#################### -# Common feature -#################### -DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 -DHDCFLAGS += -DWL_CFG80211 - -# Debug -DHDCFLAGS += -DSIMPLE_MAC_PRINT -DHDCFLAGS += -DDEBUGFS_CFG80211 -# Print out kernel panic point of file and line info when assertion happened -DHDCFLAGS += -DBCMASSERT_LOG - -# Print 8021X -DHDCFLAGS += -DDHD_8021X_DUMP - -# VSDB -DHDCFLAGS += -DVSDB -DHDCFLAGS += -DPROP_TXSTATUS -# Wi-Fi Direct -DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -# For p2p connection issue -DHDCFLAGS += -DWL_SCB_TIMEOUT=10 - -# For Kernel ver > 3.6 or Kernel Patch required -DHDCFLAGS += -DWL_SUPPORT_CHAN_BW - -# For TDLS tear down inactive time 10 sec -DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 -# for TDLS RSSI HIGH for establishing TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 -# for TDLS RSSI HIGH for tearing down TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 - -# Roaming -DHDCFLAGS += -DROAM_AP_ENV_DETECTION -DHDCFLAGS += -DROAM_ENABLE -DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - -# Support MAC ACL setting -DHDCFLAGS += -DWL_CFG80211_ACL - -# SoftAP -DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP -DHDCFLAGS += -DDISABLE_11H_SOFTAP -DHDCFLAGS += -DSUPPORT_PM2_ONLY -DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD -DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE - -# For Scan result patch -DHDCFLAGS += -DESCAN_RESULT_PATCH -DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER - -# For Static Buffer -ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) - DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF - DHDCFLAGS += -DENHANCED_STATIC_BUF - DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -endif - -# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) -DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 - -# Ioctl timeout 5000ms -DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 - -# DPC priority -#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 - -# Priority mismatch fix with kernel stack -DHDCFLAGS += -DPKTPRIO_OVERRIDE - -# Prevent rx thread monopolize -DHDCFLAGS += -DWAIT_DEQUEUE - -# Config PM Control -DHDCFLAGS += -DCONFIG_CONTROL_PM - -# Use Android wake lock mechanism -DHDCFLAGS += -DCONFIG_HAS_WAKELOCK - -# idle count -DHDCFLAGS += -DDHD_USE_IDLECOUNT - -# custom specific value define -# For special PNO Event keep wake lock for 10sec -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 -# set keep alive period -DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 -# set roam setting values -DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 -DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 - -# Used short dwell time during initial scan -DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME - -# SKB TAILPAD to avoid out of boundary memory access -DHDCFLAGS += -DDHDENABLE_TAILPAD - -# Connection statistics -DHDCFLAGS += -DCONNECTION_STATISTICS - -DHDCFLAGS += -DSUPPORT_P2P_GO_PS - -# Disable TXBF sending -DHDCFLAGS += -DDISABLE_TXBFR - -DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - - -############################## -# Android Platform Definition -############################## - -########### -# Lollipop -########### -DHDCFLAGS += -DWL_ENABLE_P2P_IF -#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES -# Default definitions for KitKat -DHDCFLAGS += -DWL_CFG80211_STA_EVENT -DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS -# To support p2p private command on kernel 3.8 or above -DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT - -ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) -DHDCFLAGS += -DWL_SCHED_SCAN -endif - -ifneq ($(CONFIG_BCM4339),) -# To support GSCAN -#DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o -endif - -ifneq ($(CONFIG_BCM43455),) -# To support RTT -#DHDCFLAGS += -DRTT_SUPPORT -# To support GSCAN -DHDCFLAGS += -DGSCAN_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o -endif - -ifneq ($(CONFIG_BCM4354),) -# To support RTT -DHDCFLAGS += -DRTT_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support GSCAN -#DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o -endif - - - - -######################### -# Chip dependent feature -######################### -ifneq ($(CONFIG_BCM4354),) - DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DSDIO_CRC_ERROR_FIX - -# tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DREPEAT_READFRAME - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4354),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -# DRIVER_TYPE = y -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM4339),) - DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4339),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # for 4339 only currently - need test for 4354, 43455 - DHDCFLAGS += -DDHD_LOSSLESS_ROAMING - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM43455),) - DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM43455),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -# DHDCFLAGS += -DDISABLE_IF_COUNTERS - DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 - - # Radio_stat v2 - data structure is updated - DHDCFLAGS += -DLINKSTAT_V2 - -# DHDCFLAGS += -DWL_ABORT_SCAN -endif - -#EXTRA_LDFLAGS += --strip-debug -EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG -EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" -EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ -KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) - -DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ - dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ - dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o dhd_linux_wq.o aiutils.o \ - bcmevent.o bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o \ - sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o wl_android.o wl_cfg80211.o \ - wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o - -DHDOFILES += $(ANDROID_OFILES) - -obj-$(CONFIG_BCMDHD_SUZURAN) += bcmdhd.o -bcmdhd-objs += $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile.mm b/drivers/net/wireless/bcmdhd_suzuran/Makefile.mm deleted file mode 100755 index 4d71dc030274..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile.mm +++ /dev/null @@ -1,360 +0,0 @@ -# bcmdhd_suzuran - -##################### -# SDIO Basic feature -##################### -DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ - -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ - -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ - -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ - -DEMBEDDED_PLATFORM -DPNO_SUPPORT - -#################### -# Common feature -#################### -DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 -DHDCFLAGS += -DWL_CFG80211 - -# Debug -DHDCFLAGS += -DSIMPLE_MAC_PRINT -DHDCFLAGS += -DDEBUGFS_CFG80211 -# Print out kernel panic point of file and line info when assertion happened -DHDCFLAGS += -DBCMASSERT_LOG - -# Print 8021X -DHDCFLAGS += -DDHD_8021X_DUMP - -# VSDB -DHDCFLAGS += -DVSDB -DHDCFLAGS += -DPROP_TXSTATUS -# Wi-Fi Direct -DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -# For p2p connection issue -DHDCFLAGS += -DWL_SCB_TIMEOUT=10 - -# For Kernel ver > 3.6 or Kernel Patch required -DHDCFLAGS += -DWL_SUPPORT_CHAN_BW - -# For TDLS tear down inactive time 10 sec -DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 -# for TDLS RSSI HIGH for establishing TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 -# for TDLS RSSI HIGH for tearing down TDLS link -DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 - -# Roaming -DHDCFLAGS += -DROAM_AP_ENV_DETECTION -DHDCFLAGS += -DROAM_ENABLE -DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - -# Support MAC ACL setting -DHDCFLAGS += -DWL_CFG80211_ACL - -# SoftAP -DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP -DHDCFLAGS += -DDISABLE_11H_SOFTAP -DHDCFLAGS += -DSUPPORT_PM2_ONLY -DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD -DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE - -# For Scan result patch -DHDCFLAGS += -DESCAN_RESULT_PATCH -DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER - -# For Static Buffer -ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) - DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF - DHDCFLAGS += -DENHANCED_STATIC_BUF - DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -endif - -# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) -DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 - -# Ioctl timeout 5000ms -DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 - -# DPC priority -#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 - -# Priority mismatch fix with kernel stack -DHDCFLAGS += -DPKTPRIO_OVERRIDE - -# Prevent rx thread monopolize -DHDCFLAGS += -DWAIT_DEQUEUE - -# Config PM Control -DHDCFLAGS += -DCONFIG_CONTROL_PM - -# Use Android wake lock mechanism -DHDCFLAGS += -DCONFIG_HAS_WAKELOCK - -# idle count -DHDCFLAGS += -DDHD_USE_IDLECOUNT - -# custom specific value define -# For special PNO Event keep wake lock for 10sec -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 -# set keep alive period -DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 -# set roam setting values -DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 -DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 - -# Used short dwell time during initial scan -DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME - -# SKB TAILPAD to avoid out of boundary memory access -DHDCFLAGS += -DDHDENABLE_TAILPAD - -# Connection statistics -DHDCFLAGS += -DCONNECTION_STATISTICS - -DHDCFLAGS += -DSUPPORT_P2P_GO_PS - -# Disable TXBF sending -DHDCFLAGS += -DDISABLE_TXBFR - -DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - - -############################## -# Android Platform Definition -############################## - -############################### -# Android M -############################### -DHDCFLAGS += -DWL_ENABLE_P2P_IF - -# Default definitions for KitKat -DHDCFLAGS += -DWL_CFG80211_STA_EVENT -DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS -# To support p2p private command on kernel 3.8 or above -DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT - -ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) -DHDCFLAGS += -DWL_SCHED_SCAN -endif - -ifneq ($(CONFIG_BCM4339),) -# To support GSCAN -#DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Lollipop -ANDROID_OFILES := wl_cfgvendor.o -endif - -ifneq ($(CONFIG_BCM43455),) -# To support RTT -DHDCFLAGS += -DRTT_SUPPORT -# To support GSCAN -DHDCFLAGS += -DGSCAN_SUPPORT -# To support ePNO -DHDCFLAGS += -DEPNO_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support Rssi Monitor -DHDCFLAGS += -DRSSI_MONITOR_SUPPORT -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT -# To support ANQPO - GSCAN must be supported -DHDCFLAGS += -DANQPO_SUPPORT - - - -# Extra file list for Android M, SOMC -ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o bcmxtlv.o -endif - -ifneq ($(CONFIG_BCM4354),) -# To support RTT -#DHDCFLAGS += -DRTT_SUPPORT -# To support Link Statictics -DHDCFLAGS += -DLINKSTAT_SUPPORT -# To support GSCAN -DHDCFLAGS += -DGSCAN_SUPPORT - -# To support WL_VENDOR_EXT_SUPPORT -DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT - -# Extra file list for Android M -ANDROID_OFILES := wl_cfgvendor.o -endif - - - - -######################### -# Chip dependent feature -######################### -ifneq ($(CONFIG_BCM4354),) - DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION - DHDCFLAGS += -DMIMO_ANT_SETTING - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DSDIO_CRC_ERROR_FIX - -# tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DREPEAT_READFRAME - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 - DHDCFLAGS += -DMAX_HDR_READ=128 - DHDCFLAGS += -DDHD_FIRSTREAD=128 - DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 - -# New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4354),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -# DRIVER_TYPE = y -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM4339),) - DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM4339),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP - DHDCFLAGS += -DDISABLE_IF_COUNTERS - - # for 4339 only currently - need test for 4354, 43455 - DHDCFLAGS += -DDHD_LOSSLESS_ROAMING - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 -endif - -ifneq ($(CONFIG_BCM43455),) - DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB - DHDCFLAGS += -DUSE_CID_CHECK - DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP - DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR - - # tput enhancement - DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 - DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 - DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED - DHDCFLAGS += -DDHDTCPACK_SUPPRESS - DHDCFLAGS += -DUSE_WL_TXBF - DHDCFLAGS += -DUSE_WL_FRAMEBURST - DHDCFLAGS += -DRXFRAME_THREAD - DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 - DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 - DHDCFLAGS += -DPROP_TXSTATUS_VSDB -ifeq ($(CONFIG_ARCH_MSM),y) - DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 - DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 -endif - DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 - DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 - - # New Features - DHDCFLAGS += -DWL11U - DHDCFLAGS += -DBCMCCX - DHDCFLAGS += -DWLTDLS - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DSUPPORT_LTECX -# DHDCFLAGS += -DSUPPORT_2G_VHT - DHDCFLAGS += -DSUPPORT_WL_TXPOWER -ifeq ($(CONFIG_BCM43455),y) - DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD - DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC -endif - DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 - DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP -# DHDCFLAGS += -DDISABLE_IF_COUNTERS - DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES - - # For setting custom short & long retry limit - DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 - - # Radio_stat v2 - data structure is updated - DHDCFLAGS += -DLINKSTAT_V2 - -# DHDCFLAGS += -DWL_ABORT_SCAN -endif - -#EXTRA_LDFLAGS += --strip-debug -EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG -EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" -EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ -KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) - -DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ - dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ - dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o dhd_linux_wq.o aiutils.o \ - bcmevent.o bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o \ - sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o wl_android.o wl_cfg80211.o \ - wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o - -DHDOFILES += $(ANDROID_OFILES) - -obj-$(CONFIG_BCMDHD_SUZURAN) += bcmdhd.o -bcmdhd-objs += $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_suzuran/aiutils.c b/drivers/net/wireless/bcmdhd_suzuran/aiutils.c deleted file mode 100755 index e1f833ad28be..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/aiutils.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: aiutils.c 432226 2013-10-26 04:34:36Z $ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "siutils_priv.h" - -#define BCM47162_DMP() (0) -#define BCM5357_DMP() (0) -#define BCM4707_DMP() (0) -#define remap_coreid(sih, coreid) (coreid) -#define remap_corerev(sih, corerev) (corerev) - -/* EROM parsing */ - -static uint32 -get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) -{ - uint32 ent; - uint inv = 0, nom = 0; - - while (TRUE) { - ent = R_REG(si_osh(sih), *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++; - } - - SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); - if (inv + nom) { - SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); - } - return ent; -} - -static uint32 -get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, - uint32 *sizel, uint32 *sizeh) -{ - uint32 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); - - SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", - sp, ad, st, *sizeh, *sizel, *addrh, *addrl)); - - return asd; -} - -static void -ai_hwfixup(si_info_t *sii) -{ -} - - -/* parse the enumeration rom to identify all cores */ -void -ai_scan(si_t *sih, void *regs, uint devid) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - chipcregs_t *cc = (chipcregs_t *)regs; - uint32 erombase, *eromptr, *eromlim; - - erombase = R_REG(sii->osh, &cc->eromptr); - - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); - break; - - case PCI_BUS: - /* Set wrappers address */ - sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); - - /* Now point the window at the erom */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); - eromptr = regs; - break; - - case SPI_BUS: - case SDIO_BUS: - eromptr = (uint32 *)(uintptr)erombase; - break; - - case PCMCIA_BUS: - default: - SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype)); - ASSERT(0); - return; - } - eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); - - SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", - regs, erombase, eromptr, eromlim)); - while (eromptr < eromlim) { - uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; - uint32 mpd, asd, addrl, addrh, sizel, sizeh; - 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)) { - SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); - ai_hwfixup(sii); - return; - } - - cib = get_erom_ent(sih, &eromptr, 0, 0); - - if ((cib & ER_TAG) != ER_CI) { - SI_ERROR(("CIA not followed by CIB\n")); - 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; - -#ifdef BCMDBG_SI - SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " - "nsw = %d, nmp = %d & nsp = %d\n", - mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp)); -#else - BCM_REFERENCE(crev); -#endif - - 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; - } - } - if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID) - continue; - } - - idx = sii->numcores; - - cores_info->cia[idx] = cia; - cores_info->cib[idx] = cib; - cores_info->coreid[idx] = remap_coreid(sih, cid); - - for (i = 0; i < nmp; i++) { - mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); - if ((mpd & ER_TAG) != ER_MP) { - SI_ERROR(("Not enough MP entries for component 0x%x\n", cid)); - goto error; - } - SI_VMSG((" Master port %d, mp: %d id: %d\n", i, - (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, - (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); - } - - /* 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) { - do { - /* 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 (br == TRUE) { - break; - } - else if ((addrh != 0) || (sizeh != 0) || - (sizel != SI_CORE_SIZE)) { - SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 =" - "0x%x\n", addrh, sizeh, sizel)); - SI_ERROR(("First Slave ASD for" - "core 0x%04x malformed " - "(0x%08x)\n", cid, asd)); - goto error; - } - } - } while (1); - } - cores_info->coresba[idx] = addrl; - cores_info->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)) { - cores_info->coresba2[idx] = addrl; - cores_info->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); - - if (asd == 0) - break; - j++; - } while (1); - if (j == 0) { - SI_ERROR((" SP %d has no address descriptors\n", i)); - 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) { - SI_ERROR(("Missing descriptor for MW %d\n", i)); - goto error; - } - if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { - SI_ERROR(("Master wrapper %d is not 4KB\n", i)); - goto error; - } - if (i == 0) - cores_info->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) { - SI_ERROR(("Missing descriptor for SW %d\n", i)); - goto error; - } - if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { - SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); - goto error; - } - if ((nmw == 0) && (i == 0)) - cores_info->wrapba[idx] = addrl; - } - - - /* Don't record bridges */ - if (br) - continue; - - /* Done with core */ - sii->numcores++; - } - - SI_ERROR(("Reached end of erom without finding END")); - -error: - sii->numcores = 0; - return; -} - -/* This function changes the logical "focus" to the indicated core. - * Return the current core's virtual address. - */ -void * -ai_setcoreidx(si_t *sih, uint coreidx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 addr, wrap; - void *regs; - - if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) - return (NULL); - - addr = cores_info->coresba[coreidx]; - wrap = cores_info->wrapba[coreidx]; - - /* - * If the user has provided an interrupt mask enabled function, - * then assert interrupts are disabled before switching the core. - */ - ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); - - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - /* map new one */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - sii->curmap = regs = cores_info->regs[coreidx]; - if (!cores_info->wrappers[coreidx] && (wrap != 0)) { - cores_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->wrappers[coreidx])); - } - sii->curwrap = cores_info->wrappers[coreidx]; - break; - - case PCI_BUS: - /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); - regs = sii->curmap; - /* point bar0 2nd 4KB window to the primary wrapper */ - if (PCIE_GEN2(sii)) - OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap); - else - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); - break; - - case SPI_BUS: - case SDIO_BUS: - sii->curmap = regs = (void *)((uintptr)addr); - sii->curwrap = (void *)((uintptr)wrap); - break; - - case PCMCIA_BUS: - default: - ASSERT(0); - regs = NULL; - break; - } - - sii->curmap = regs; - sii->curidx = coreidx; - - return regs; -} - - -void -ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - chipcregs_t *cc = NULL; - uint32 erombase, *eromptr, *eromlim; - uint i, j, cidx; - uint32 cia, cib, nmp, nsp; - uint32 asd, addrl, addrh, sizel, sizeh; - - for (i = 0; i < sii->numcores; i++) { - if (cores_info->coreid[i] == CC_CORE_ID) { - cc = (chipcregs_t *)cores_info->regs[i]; - break; - } - } - if (cc == NULL) - goto error; - - erombase = R_REG(sii->osh, &cc->eromptr); - eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); - eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); - - cidx = sii->curidx; - cia = cores_info->cia[cidx]; - cib = cores_info->cib[cidx]; - - nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; - nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; - - /* scan for cores */ - while (eromptr < eromlim) { - if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && - (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { - break; - } - } - - /* skip master ports */ - for (i = 0; i < nmp; i++) - get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); - - /* Skip ASDs in port 0 */ - 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); - } - - j = 1; - do { - asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, - &sizel, &sizeh); - 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); - if (asd == 0) - break; - - if (!asidx--) { - *addr = addrl; - *size = sizel; - return; - } - j++; - } while (1); - - if (j == 0) { - SI_ERROR((" SP %d has no address descriptors\n", i)); - break; - } - } - -error: - *size = 0; - return; -} - -/* Return the number of address spaces in current core */ -int -ai_numaddrspaces(si_t *sih) -{ - return 2; -} - -/* Return the address of the nth address space in the current core */ -uint32 -ai_addrspace(si_t *sih, uint asidx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint cidx; - - cidx = sii->curidx; - - if (asidx == 0) - return cores_info->coresba[cidx]; - else if (asidx == 1) - return cores_info->coresba2[cidx]; - else { - SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", - __FUNCTION__, asidx)); - return 0; - } -} - -/* Return the size of the nth address space in the current core */ -uint32 -ai_addrspacesize(si_t *sih, uint asidx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint cidx; - - cidx = sii->curidx; - - if (asidx == 0) - return cores_info->coresba_size[cidx]; - else if (asidx == 1) - return cores_info->coresba2_size[cidx]; - else { - SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", - __FUNCTION__, asidx)); - return 0; - } -} - -uint -ai_flag(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); - return sii->curidx; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); - return sii->curidx; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", - __FUNCTION__)); - return sii->curidx; - } - ai = sii->curwrap; - - return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); -} - -uint -ai_flag_alt(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); - return sii->curidx; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); - return sii->curidx; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", - __FUNCTION__)); - return sii->curidx; - } - ai = sii->curwrap; - - return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK); -} - -void -ai_setint(si_t *sih, int siflag) -{ -} - -uint -ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - uint32 *map = (uint32 *) sii->curwrap; - - if (mask || val) { - uint32 w = R_REG(sii->osh, map+(offset/4)); - w &= ~mask; - w |= val; - W_REG(sii->osh, map+(offset/4), w); - } - - return (R_REG(sii->osh, map+(offset/4))); -} - -uint -ai_corevendor(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 cia; - - cia = cores_info->cia[sii->curidx]; - return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); -} - -uint -ai_corerev(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 cib; - - - cib = cores_info->cib[sii->curidx]; - return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); -} - -bool -ai_iscoreup(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - - ai = sii->curwrap; - - return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && - ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); -} - -/* - * 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(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -{ - uint origidx = 0; - uint32 *r = NULL; - uint w; - uint intr_val = 0; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - ASSERT((val & ~mask) == 0); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sih->bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (uint32 *)((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 = si_coreidx(&sii->pub); - - /* switch core */ - r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); - } - ASSERT(r != NULL); - - /* mask and set */ - if (mask || val) { - w = (R_REG(sii->osh, r) & ~mask) | val; - W_REG(sii->osh, r, w); - } - - /* readback */ - w = R_REG(sii->osh, r); - - if (!fast) { - /* restore core index */ - if (origidx != coreidx) - ai_setcoreidx(&sii->pub, origidx); - - INTR_RESTORE(sii, intr_val); - } - - return (w); -} - -/* - * If there is no need for fiddling with interrupts or core switches (typically silicon - * back plane registers, pci registers and chipcommon registers), this function - * returns the register offset on this core to a mapped address. This address can - * be used for W_REG/R_REG directly. - * - * For accessing registers that would need a core switch, this function will return - * NULL. - */ -uint32 * -ai_corereg_addr(si_t *sih, uint coreidx, uint regoff) -{ - uint32 *r = NULL; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sih->bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (uint32 *)((char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + - regoff); - } - } - - if (!fast) - return 0; - - return (r); -} - -void -ai_core_disable(si_t *sih, uint32 bits) -{ - si_info_t *sii = SI_INFO(sih); - volatile uint32 dummy; - uint32 status; - aidmp_t *ai; - - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - /* if core is already in reset, just return */ - if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) - return; - - /* ensure there are no pending backplane operations */ - SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - /* if pending backplane ops still, try waiting longer */ - if (status != 0) { - /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ - /* during driver load we may need more time */ - SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); - /* if still pending ops, continue on and try disable anyway */ - /* this is in big hammer path, so don't call wl_reinit in this case... */ - } - - W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); - dummy = R_REG(sii->osh, &ai->resetctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - - W_REG(sii->osh, &ai->ioctrl, bits); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(10); -} - -/* 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(si_t *sih, uint32 bits, uint32 resetbits) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - volatile uint32 dummy; - uint loop_counter = 10; - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - - /* put core into reset state */ - W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); - OSL_DELAY(10); - - /* ensure there are no pending backplane operations */ - SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); - - W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN)); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - - /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - - while (R_REG(sii->osh, &ai->resetctrl) != 0 && --loop_counter != 0) { - /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - - /* take core out of reset */ - W_REG(sii->osh, &ai->resetctrl, 0); - - /* ensure there are no pending backplane operations */ - SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); - } - - - W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(1); -} - -void -ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 w; - - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", - __FUNCTION__)); - return; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", - __FUNCTION__)); - return; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", - __FUNCTION__)); - return; - } - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - ASSERT((val & ~mask) == 0); - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); - W_REG(sii->osh, &ai->ioctrl, w); - } -} - -uint32 -ai_core_cflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 w; - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", - __FUNCTION__)); - return 0; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", - __FUNCTION__)); - return 0; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", - __FUNCTION__)); - return 0; - } - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - ASSERT((val & ~mask) == 0); - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); - W_REG(sii->osh, &ai->ioctrl, w); - } - - return R_REG(sii->osh, &ai->ioctrl); -} - -uint32 -ai_core_sflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 w; - - if (BCM47162_DMP()) { - SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", - __FUNCTION__)); - return 0; - } - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", - __FUNCTION__)); - return 0; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", - __FUNCTION__)); - return 0; - } - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - ASSERT((val & ~mask) == 0); - ASSERT((mask & ~SISF_CORE_BITS) == 0); - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); - W_REG(sii->osh, &ai->iostatus, w); - } - - return R_REG(sii->osh, &ai->iostatus); -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmevent.c b/drivers/net/wireless/bcmdhd_suzuran/bcmevent.c deleted file mode 100755 index 3f9f8390424a..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmevent.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * bcmevent read-only data shared by kernel or app layers - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmevent.c 718508 2017-08-31 02:48:38Z $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Use the actual name for event tracing */ -#define BCMEVENT_NAME(_event) {(_event), #_event} - -const bcmevent_name_t bcmevent_names[] = { - BCMEVENT_NAME(WLC_E_SET_SSID), - BCMEVENT_NAME(WLC_E_JOIN), - BCMEVENT_NAME(WLC_E_START), - BCMEVENT_NAME(WLC_E_AUTH), - BCMEVENT_NAME(WLC_E_AUTH_IND), - BCMEVENT_NAME(WLC_E_DEAUTH), - BCMEVENT_NAME(WLC_E_DEAUTH_IND), - BCMEVENT_NAME(WLC_E_ASSOC), - BCMEVENT_NAME(WLC_E_ASSOC_IND), - BCMEVENT_NAME(WLC_E_REASSOC), - BCMEVENT_NAME(WLC_E_REASSOC_IND), - BCMEVENT_NAME(WLC_E_DISASSOC), - BCMEVENT_NAME(WLC_E_DISASSOC_IND), - BCMEVENT_NAME(WLC_E_QUIET_START), - BCMEVENT_NAME(WLC_E_QUIET_END), - BCMEVENT_NAME(WLC_E_BEACON_RX), - BCMEVENT_NAME(WLC_E_LINK), - BCMEVENT_NAME(WLC_E_MIC_ERROR), - BCMEVENT_NAME(WLC_E_NDIS_LINK), - BCMEVENT_NAME(WLC_E_ROAM), - BCMEVENT_NAME(WLC_E_TXFAIL), - BCMEVENT_NAME(WLC_E_PMKID_CACHE), - BCMEVENT_NAME(WLC_E_RETROGRADE_TSF), - BCMEVENT_NAME(WLC_E_PRUNE), - BCMEVENT_NAME(WLC_E_AUTOAUTH), - BCMEVENT_NAME(WLC_E_EAPOL_MSG), - BCMEVENT_NAME(WLC_E_SCAN_COMPLETE), - BCMEVENT_NAME(WLC_E_ADDTS_IND), - BCMEVENT_NAME(WLC_E_DELTS_IND), - BCMEVENT_NAME(WLC_E_BCNSENT_IND), - BCMEVENT_NAME(WLC_E_BCNRX_MSG), - BCMEVENT_NAME(WLC_E_BCNLOST_MSG), - BCMEVENT_NAME(WLC_E_ROAM_PREP), - BCMEVENT_NAME(WLC_E_PFN_NET_FOUND), - BCMEVENT_NAME(WLC_E_PFN_NET_LOST), -#if defined(IBSS_PEER_DISCOVERY_EVENT) - BCMEVENT_NAME(WLC_E_IBSS_ASSOC), -#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */ - BCMEVENT_NAME(WLC_E_RADIO), - BCMEVENT_NAME(WLC_E_PSM_WATCHDOG), - BCMEVENT_NAME(WLC_E_PROBREQ_MSG), - BCMEVENT_NAME(WLC_E_SCAN_CONFIRM_IND), - BCMEVENT_NAME(WLC_E_PSK_SUP), - BCMEVENT_NAME(WLC_E_COUNTRY_CODE_CHANGED), - BCMEVENT_NAME(WLC_E_EXCEEDED_MEDIUM_TIME), - BCMEVENT_NAME(WLC_E_ICV_ERROR), - BCMEVENT_NAME(WLC_E_UNICAST_DECODE_ERROR), - BCMEVENT_NAME(WLC_E_MULTICAST_DECODE_ERROR), - BCMEVENT_NAME(WLC_E_TRACE), - BCMEVENT_NAME(WLC_E_IF), -#ifdef WLP2P - BCMEVENT_NAME(WLC_E_P2P_DISC_LISTEN_COMPLETE), -#endif - BCMEVENT_NAME(WLC_E_RSSI), - BCMEVENT_NAME(WLC_E_PFN_SCAN_COMPLETE), - BCMEVENT_NAME(WLC_E_EXTLOG_MSG), -#ifdef WIFI_ACT_FRAME - BCMEVENT_NAME(WLC_E_ACTION_FRAME), - BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX), - BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE), -#endif -#ifdef BCMWAPI_WAI - BCMEVENT_NAME(WLC_E_WAI_STA_EVENT), - BCMEVENT_NAME(WLC_E_WAI_MSG), -#endif /* BCMWAPI_WAI */ - BCMEVENT_NAME(WLC_E_ESCAN_RESULT), - BCMEVENT_NAME(WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE), -#ifdef WLP2P - BCMEVENT_NAME(WLC_E_PROBRESP_MSG), - BCMEVENT_NAME(WLC_E_P2P_PROBREQ_MSG), -#endif -#ifdef PROP_TXSTATUS - BCMEVENT_NAME(WLC_E_FIFO_CREDIT_MAP), -#endif - BCMEVENT_NAME(WLC_E_WAKE_EVENT), - BCMEVENT_NAME(WLC_E_DCS_REQUEST), - BCMEVENT_NAME(WLC_E_RM_COMPLETE), -#ifdef WLMEDIA_HTSF - BCMEVENT_NAME(WLC_E_HTSFSYNC), -#endif - BCMEVENT_NAME(WLC_E_OVERLAY_REQ), - BCMEVENT_NAME(WLC_E_CSA_COMPLETE_IND), - BCMEVENT_NAME(WLC_E_EXCESS_PM_WAKE_EVENT), - BCMEVENT_NAME(WLC_E_PFN_SCAN_NONE), - BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE), -#ifdef SOFTAP - BCMEVENT_NAME(WLC_E_GTK_PLUMBED), -#endif - BCMEVENT_NAME(WLC_E_ASSOC_REQ_IE), - BCMEVENT_NAME(WLC_E_ASSOC_RESP_IE), - BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX_NDIS), - BCMEVENT_NAME(WLC_E_BEACON_FRAME_RX), -#ifdef WLTDLS - BCMEVENT_NAME(WLC_E_TDLS_PEER_EVENT), -#endif /* WLTDLS */ - BCMEVENT_NAME(WLC_E_NATIVE), -#ifdef WLPKTDLYSTAT - BCMEVENT_NAME(WLC_E_PKTDELAY_IND), -#endif /* WLPKTDLYSTAT */ - BCMEVENT_NAME(WLC_E_SERVICE_FOUND), - BCMEVENT_NAME(WLC_E_GAS_FRAGMENT_RX), - BCMEVENT_NAME(WLC_E_GAS_COMPLETE), - BCMEVENT_NAME(WLC_E_P2PO_ADD_DEVICE), - BCMEVENT_NAME(WLC_E_P2PO_DEL_DEVICE), -#ifdef WLWNM - BCMEVENT_NAME(WLC_E_WNM_STA_SLEEP), -#endif /* WLWNM */ -#if defined(WL_PROXDETECT) - BCMEVENT_NAME(WLC_E_PROXD), -#endif - BCMEVENT_NAME(WLC_E_CCA_CHAN_QUAL), - BCMEVENT_NAME(WLC_E_BSSID), -#ifdef PROP_TXSTATUS - BCMEVENT_NAME(WLC_E_BCMC_CREDIT_SUPPORT), -#endif - BCMEVENT_NAME(WLC_E_TXFAIL_THRESH), -#ifdef GSCAN_SUPPORT - BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT), -#endif /* GSCAN_SUPPORT */ - BCMEVENT_NAME(WLC_E_RMC_EVENT), -#ifdef GSCAN_SUPPORT - BCMEVENT_NAME(WLC_E_PFN_SSID_EXT), -#endif /* GSCAN_SUPPORT */ -}; - -const int bcmevent_names_size = ARRAYSIZE(bcmevent_names); - -/* - * Validate if the event is proper and if valid copy event header to event. - * If proper event pointer is passed, to just validate, pass NULL to event. - * - * Return values are - * BCME_OK - It is a BRCM event or BRCM dongle event - * BCME_NOTFOUND - Not BRCM, not an event, may be okay - * BCME_BADLEN - Bad length, should not process, just drop - */ -int -is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, - bcm_event_msg_u_t *out_event) -{ - uint16 evlen = 0; /* length in bcmeth_hdr */ - uint16 subtype; - uint16 usr_subtype; - bcm_event_t *bcm_event; - uint8 *pktend; - uint8 *evend; - int err = BCME_OK; - uint32 data_len = 0; /* data length in bcm_event */ - - pktend = (uint8 *)pktdata + pktlen; - bcm_event = (bcm_event_t *)pktdata; - - /* only care about 16-bit subtype / length versions */ - if ((uint8 *)&bcm_event->bcm_hdr < pktend) { - uint8 short_subtype = *(uint8 *)&bcm_event->bcm_hdr; - if (!(short_subtype & 0x80)) { - err = BCME_NOTFOUND; - goto done; - } - } - - /* must have both ether_header and bcmeth_hdr */ - if (pktlen < OFFSETOF(bcm_event_t, event)) { - err = BCME_BADLEN; - goto done; - } - - /* check length in bcmeth_hdr */ - - /* temporary - header length not always set properly. When the below - * !BCMDONGLEHOST is in all branches that use trunk DHD, the code - * under BCMDONGLEHOST can be removed. - */ - evlen = (uint16)(pktend - (uint8 *)&bcm_event->bcm_hdr.version); - evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen; - if (evend > pktend) { - err = BCME_BADLEN; - goto done; - } - - /* match on subtype, oui and usr subtype for BRCM events */ - subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.subtype); - if (subtype != BCMILCP_SUBTYPE_VENDOR_LONG) { - err = BCME_NOTFOUND; - goto done; - } - - if (bcmp(BRCM_OUI, &bcm_event->bcm_hdr.oui[0], DOT11_OUI_LEN)) { - err = BCME_NOTFOUND; - goto done; - } - - /* if it is a bcm_event or bcm_dngl_event_t, validate it */ - usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype); - switch (usr_subtype) { - case BCMILCP_BCM_SUBTYPE_EVENT: - /* check that header length and pkt length are sufficient */ - if ((pktlen < sizeof(bcm_event_t)) || - (evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) { - err = BCME_BADLEN; - goto done; - } - - /* ensure data length in event is not beyond the packet. */ - data_len = ntoh32_ua((void *)&bcm_event->event.datalen); - if (data_len > (pktlen - sizeof(bcm_event_t))) { - err = BCME_BADLEN; - goto done; - } - - if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) { - err = BCME_NOTFOUND; - goto done; - } - - if (out_event) { - /* ensure BRCM event pkt aligned */ - memcpy(&out_event->event, &bcm_event->event, sizeof(wl_event_msg_t)); - } - - break; - case BCMILCP_BCM_SUBTYPE_DNGLEVENT: - if ((pktlen < sizeof(bcm_dngl_event_t)) || - (evend < ((uint8 *)bcm_event + sizeof(bcm_dngl_event_t)))) { - err = BCME_BADLEN; - goto done; - } - - /* ensure data length in event is not beyond the packet. */ - data_len = ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata)->dngl_event.datalen); - if (data_len > (pktlen - sizeof(bcm_dngl_event_t))) { - err = BCME_BADLEN; - goto done; - } - - if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) { - err = BCME_NOTFOUND; - goto done; - } - - if (out_event) { - /* ensure BRCM dngl event pkt aligned */ - memcpy(&out_event->dngl_event, &((bcm_dngl_event_t *)pktdata)->dngl_event, - sizeof(bcm_dngl_event_msg_t)); - } - - break; - default: - err = BCME_NOTFOUND; - goto done; - } - - BCM_REFERENCE(data_len); -done: - return err; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c deleted file mode 100755 index ea4edda2c8b3..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c +++ /dev/null @@ -1,705 +0,0 @@ -/* - * BCMSDH interface glue - * implement bcmsdh API for SDIOH driver - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh.c 455573 2014-02-14 17:49:31Z $ - */ - -/** - * @file bcmsdh.c - */ - -/* ****************** BCMSDH Interface Functions *************************** */ - -#include -#include -#include -#include -#include -#include -#include - -#include /* BRCM API for SDIO clients (such as wl, dhd) */ -#include /* common SDIO/controller interface */ -#include /* SDIO device core hardware definitions. */ -#include /* SDIO Device and Protocol Specs */ - -#define SDIOH_API_ACCESS_RETRY_LIMIT 2 -const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; - -/* local copy of bcm sd handler */ -bcmsdh_info_t * l_bcmsdh = NULL; - - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) -extern int -sdioh_enable_hw_oob_intr(void *sdioh, bool enable); - -void -bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) -{ - sdioh_enable_hw_oob_intr(sdh->sdioh, enable); -} -#endif - -/* Attach BCMSDH layer to SDIO Host Controller Driver - * - * @param osh OSL Handle. - * @param cfghdl Configuration Handle. - * @param regsva Virtual address of controller registers. - * @param irq Interrupt number of SDIO controller. - * - * @return bcmsdh_info_t Handle to BCMSDH context. - */ -bcmsdh_info_t * -bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva) -{ - bcmsdh_info_t *bcmsdh; - - if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) { - BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); - return NULL; - } - bzero((char *)bcmsdh, sizeof(bcmsdh_info_t)); - bcmsdh->sdioh = sdioh; - bcmsdh->osh = osh; - bcmsdh->init_success = TRUE; - *regsva = SI_ENUM_BASE; - - /* Report the BAR, to fix if needed */ - bcmsdh->sbwad = SI_ENUM_BASE; - - /* save the handler locally */ - l_bcmsdh = bcmsdh; - - return bcmsdh; -} - -int -bcmsdh_detach(osl_t *osh, void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - if (bcmsdh != NULL) { - MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t)); - } - - l_bcmsdh = NULL; - - return 0; -} - -int -bcmsdh_iovar_op(void *sdh, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set); -} - -bool -bcmsdh_intr_query(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - bool on; - - ASSERT(bcmsdh); - status = sdioh_interrupt_query(bcmsdh->sdioh, &on); - if (SDIOH_API_SUCCESS(status)) - return FALSE; - else - return on; -} - -int -bcmsdh_intr_enable(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - ASSERT(bcmsdh); - - status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE); - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_intr_disable(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - ASSERT(bcmsdh); - - status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE); - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - ASSERT(bcmsdh); - - status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh); - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_intr_dereg(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - ASSERT(bcmsdh); - - status = sdioh_interrupt_deregister(bcmsdh->sdioh); - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -#if defined(DHD_DEBUG) -bool -bcmsdh_intr_pending(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - ASSERT(sdh); - return sdioh_interrupt_pending(bcmsdh->sdioh); -} -#endif - - -int -bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) -{ - ASSERT(sdh); - - /* don't support yet */ - return BCME_UNSUPPORTED; -} - -/** - * Read from SDIO Configuration Space - * @param sdh SDIO Host context. - * @param func_num Function number to read from. - * @param addr Address to read from. - * @param err Error return. - * @return value read from SDIO configuration space. - */ -uint8 -bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - int32 retry = 0; -#endif - uint8 data = 0; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - do { - if (retry) /* wait for 1 ms till bus get settled down */ - OSL_DELAY(1000); -#endif - status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); -#endif - if (err) - *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, - fnc_num, addr, data)); - - return data; -} - -void -bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - int32 retry = 0; -#endif - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - do { - if (retry) /* wait for 1 ms till bus get settled down */ - OSL_DELAY(1000); -#endif - status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); -#endif - if (err) - *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR; - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, - fnc_num, addr, data)); -} - -uint32 -bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - uint32 data = 0; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - - status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num, - addr, &data, 4); - - if (err) - *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, - fnc_num, addr, data)); - - return data; -} - -void -bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - - status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num, - addr, &data, 4); - - if (err) - *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num, - addr, data)); -} - - -int -bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - - uint8 *tmp_buf, *tmp_ptr; - uint8 *ptr; - bool ascii = func & ~0xf; - func &= 0x7; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - ASSERT(cis); - ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT); - - status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length); - - if (ascii) { - /* Move binary bits to tmp and format them into the provided buffer. */ - if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) { - BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__)); - return BCME_NOMEM; - } - bcopy(cis, tmp_buf, length); - for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) { - ptr += snprintf((char*)ptr, (cis + length - ptr - 4), - "%.2x ", *tmp_ptr & 0xff); - if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) - ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n"); - } - MFREE(bcmsdh->osh, tmp_buf, length); - } - - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - - -int -bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set) -{ - int err = 0; - uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK; - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - if (bar0 != bcmsdh->sbwad || force_set) { - bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, - (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); - if (!err) - bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, - (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); - if (!err) - bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, - (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); - - if (!err) - bcmsdh->sbwad = bar0; - else - /* invalidate cached window var */ - bcmsdh->sbwad = 0; - - } - - return err; -} - -uint32 -bcmsdh_reg_read(void *sdh, uint32 addr, uint size) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - uint32 word = 0; - - BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr)); - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - - if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)) - return 0xFFFFFFFF; - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - if (size == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - - status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, - SDIOH_READ, SDIO_FUNC_1, addr, &word, size); - - bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); - - BCMSDH_INFO(("uint32data = 0x%x\n", word)); - - /* if ok, return appropriately masked word */ - if (SDIOH_API_SUCCESS(status)) { - switch (size) { - case sizeof(uint8): - return (word & 0xff); - case sizeof(uint16): - return (word & 0xffff); - case sizeof(uint32): - return word; - default: - bcmsdh->regfail = TRUE; - - } - } - - /* otherwise, bad sdio access or invalid size */ - BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size)); - return 0xFFFFFFFF; -} - -uint32 -bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - int err = 0; - - BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", - __FUNCTION__, addr, size*8, data)); - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - ASSERT(bcmsdh->init_success); - - if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) - return err; - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - if (size == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1, - addr, &data, size); - bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); - - if (SDIOH_API_SUCCESS(status)) - return 0; - - BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n", - __FUNCTION__, data, addr, size)); - return 0xFFFFFFFF; -} - -bool -bcmsdh_regfail(void *sdh) -{ - return ((bcmsdh_info_t *)sdh)->regfail; -} - -int -bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete_fn, void *handle) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - uint incr_fix; - uint width; - int err = 0; - - ASSERT(bcmsdh); - ASSERT(bcmsdh->init_success); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", - __FUNCTION__, fn, addr, nbytes)); - - /* Async not implemented yet */ - ASSERT(!(flags & SDIO_REQ_ASYNC)); - if (flags & SDIO_REQ_ASYNC) - return BCME_UNSUPPORTED; - - if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) - return err; - - 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 = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, - SDIOH_READ, fn, addr, width, nbytes, buf, pkt); - - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); -} - -int -bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete_fn, void *handle) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - uint incr_fix; - uint width; - int err = 0; - - ASSERT(bcmsdh); - ASSERT(bcmsdh->init_success); - - BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", - __FUNCTION__, fn, addr, nbytes)); - - /* Async not implemented yet */ - ASSERT(!(flags & SDIO_REQ_ASYNC)); - if (flags & SDIO_REQ_ASYNC) - return BCME_UNSUPPORTED; - - if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) - return err; - - 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 = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, - SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt); - - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - SDIOH_API_RC status; - - ASSERT(bcmsdh); - ASSERT(bcmsdh->init_success); - ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0); - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - - status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC, - (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, - addr, 4, nbytes, buf, NULL); - - return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -} - -int -bcmsdh_abort(void *sdh, uint fn) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_abort(bcmsdh->sdioh, fn); -} - -int -bcmsdh_start(void *sdh, int stage) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_start(bcmsdh->sdioh, stage); -} - -int -bcmsdh_stop(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_stop(bcmsdh->sdioh); -} - -int -bcmsdh_waitlockfree(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_waitlockfree(bcmsdh->sdioh); -} - - -int -bcmsdh_query_device(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0; - return (bcmsdh->vendevid); -} - -uint -bcmsdh_query_iofnum(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - return (sdioh_query_iofnum(bcmsdh->sdioh)); -} - -int -bcmsdh_reset(bcmsdh_info_t *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - return sdioh_sdio_reset(bcmsdh->sdioh); -} - -void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh) -{ - ASSERT(sdh); - return sdh->sdioh; -} - -/* Function to pass device-status bits to DHD. */ -uint32 -bcmsdh_get_dstatus(void *sdh) -{ - return 0; -} -uint32 -bcmsdh_cur_sbwad(void *sdh) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - - if (!bcmsdh) - bcmsdh = l_bcmsdh; - - return (bcmsdh->sbwad); -} - -void -bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev) -{ - return; -} - - -int -bcmsdh_sleep(void *sdh, bool enab) -{ -#ifdef SDIOH_SLEEP_ENABLED - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_sleep(sd, enab); -#else - return BCME_UNSUPPORTED; -#endif -} - -int -bcmsdh_gpio_init(void *sdh) -{ - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_gpio_init(sd); -} - -bool -bcmsdh_gpioin(void *sdh, uint32 gpio) -{ - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_gpioin(sd, gpio); -} - -int -bcmsdh_gpioouten(void *sdh, uint32 gpio) -{ - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_gpioouten(sd, gpio); -} - -int -bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) -{ - bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; - sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); - - return sdioh_gpioout(sd, gpio, enab); -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c deleted file mode 100755 index 5cab16b98d93..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * SDIO access interface for drivers - linux specific (pci only) - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh_linux.c 461443 2014-03-12 02:40:59Z $ - */ - -/** - * @file bcmsdh_linux.c - */ - -#define __UNDEF_NO_VERSION__ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -extern void dhdsdio_isr(void * args); -#include -#include -#include -#if defined(CONFIG_ARCH_ODIN) -#include -#endif /* defined(CONFIG_ARCH_ODIN) */ - -#include - -/* driver info, initialized when bcmsdh_register is called */ -static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL}; - -typedef enum { - DHD_INTR_INVALID = 0, - DHD_INTR_INBAND, - DHD_INTR_HWOOB, - DHD_INTR_SWOOB -} DHD_HOST_INTR_TYPE; - -/* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g. - * bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather - * than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this - * structure. - */ -typedef struct bcmsdh_os_info { - DHD_HOST_INTR_TYPE intr_type; - int oob_irq_num; /* valid when hardware or software oob in use */ - unsigned long oob_irq_flags; /* valid when hardware or software oob in use */ - bool oob_irq_registered; - bool oob_irq_enabled; - bool oob_irq_wake_enabled; - spinlock_t oob_irq_spinlock; - bcmsdh_cb_fn_t oob_irq_handler; - void *oob_irq_handler_context; - void *context; /* context returned from upper layer */ - void *sdioh; /* handle to lower layer (sdioh) */ - void *dev; /* handle to the underlying device */ - bool dev_wake_enabled; -} bcmsdh_os_info_t; - -/* debugging macros */ -#define SDLX_MSG(x) - -/** - * Checks to see if vendor and device IDs match a supported SDIO Host Controller. - */ -bool -bcmsdh_chipmatch(uint16 vendor, uint16 device) -{ - /* Add other vendors and devices as required */ - -#ifdef BCMSDIOH_STD - /* Check for Arasan host controller */ - if (vendor == VENDOR_SI_IMAGE) { - return (TRUE); - } - /* Check for BRCM 27XX Standard host controller */ - if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) { - return (TRUE); - } - /* Check for BRCM Standard host controller */ - if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) { - return (TRUE); - } - /* Check for TI PCIxx21 Standard host controller */ - if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) { - return (TRUE); - } - if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) { - return (TRUE); - } - /* Ricoh R5C822 Standard SDIO Host */ - if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) { - return (TRUE); - } - /* JMicron Standard SDIO Host */ - if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) { - return (TRUE); - } - -#endif /* BCMSDIOH_STD */ -#ifdef BCMSDIOH_SPI - /* This is the PciSpiHost. */ - if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) { - printf("Found PCI SPI Host Controller\n"); - return (TRUE); - } - -#endif /* BCMSDIOH_SPI */ - - return (FALSE); -} - -void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, - uint bus_num, uint slot_num) -{ - ulong regs; - bcmsdh_info_t *bcmsdh; - uint32 vendevid; - bcmsdh_os_info_t *bcmsdh_osinfo = NULL; - - bcmsdh = bcmsdh_attach(osh, sdioh, ®s); - if (bcmsdh == NULL) { - SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__)); - goto err; - } - bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t)); - if (bcmsdh_osinfo == NULL) { - SDLX_MSG(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__)); - goto err; - } - bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); - bcmsdh->os_cxt = bcmsdh_osinfo; - bcmsdh_osinfo->sdioh = sdioh; - bcmsdh_osinfo->dev = dev; - osl_set_bus_handle(osh, bcmsdh); - -#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - if (dev && device_init_wakeup(dev, true) == 0) - bcmsdh_osinfo->dev_wake_enabled = TRUE; -#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ - -#if defined(OOB_INTR_ONLY) - spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock); - /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */ - bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info, - &bcmsdh_osinfo->oob_irq_flags); - if (bcmsdh_osinfo->oob_irq_num < 0) { - SDLX_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__)); - goto err; - } -#endif /* defined(BCMLXSDMMC) */ - - /* Read the vendor/device ID from the CIS */ - vendevid = bcmsdh_query_device(bcmsdh); - /* try to attach to the target device */ - bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num, - slot_num, 0, bus_type, (void *)regs, osh, bcmsdh); - if (bcmsdh_osinfo->context == NULL) { - SDLX_MSG(("%s: device attach failed\n", __FUNCTION__)); - goto err; - } - - return bcmsdh; - - /* error handling */ -err: - if (bcmsdh != NULL) - bcmsdh_detach(osh, bcmsdh); - if (bcmsdh_osinfo != NULL) - MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); - return NULL; -} - -int bcmsdh_remove(bcmsdh_info_t *bcmsdh) -{ - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - -#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - if (bcmsdh_osinfo->dev) - device_init_wakeup(bcmsdh_osinfo->dev, false); - bcmsdh_osinfo->dev_wake_enabled = FALSE; -#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ - - drvinfo.remove(bcmsdh_osinfo->context); - MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t)); - bcmsdh_detach(bcmsdh->osh, bcmsdh); - - return 0; -} - -int bcmsdh_suspend(bcmsdh_info_t *bcmsdh) -{ - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context)) - return -EBUSY; - return 0; -} - -int bcmsdh_resume(bcmsdh_info_t *bcmsdh) -{ - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - if (drvinfo.resume) - return drvinfo.resume(bcmsdh_osinfo->context); - return 0; -} - -extern int bcmsdh_register_client_driver(void); -extern void bcmsdh_unregister_client_driver(void); -extern int sdio_func_reg_notify(void* semaphore); -extern void sdio_func_unreg_notify(void); - -#if defined(BCMLXSDMMC) -int bcmsdh_reg_sdio_notify(void* semaphore) -{ - return sdio_func_reg_notify(semaphore); -} - -void bcmsdh_unreg_sdio_notify(void) -{ - sdio_func_unreg_notify(); -} -#endif /* defined(BCMLXSDMMC) */ - -int -bcmsdh_register(bcmsdh_driver_t *driver) -{ - int error = 0; - - drvinfo = *driver; - SDLX_MSG(("%s: register client driver\n", __FUNCTION__)); - error = bcmsdh_register_client_driver(); - if (error) - SDLX_MSG(("%s: failed %d\n", __FUNCTION__, error)); - - return error; -} - -void -bcmsdh_unregister(void) -{ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) - if (bcmsdh_pci_driver.node.next == NULL) - return; -#endif - - bcmsdh_unregister_client_driver(); -} - -void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh) -{ -#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - pm_stay_awake(bcmsdh_osinfo->dev); -#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ -} - -void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh) -{ -#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - pm_relax(bcmsdh_osinfo->dev); -#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ -} - -bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh) -{ - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - return bcmsdh_osinfo->dev_wake_enabled; -} - -#if defined(OOB_INTR_ONLY) -void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable) -{ - unsigned long flags; - bcmsdh_os_info_t *bcmsdh_osinfo; - - if (!bcmsdh) - return; - - bcmsdh_osinfo = bcmsdh->os_cxt; - spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags); - if (bcmsdh_osinfo->oob_irq_enabled != enable) { - if (enable) - enable_irq(bcmsdh_osinfo->oob_irq_num); - else - disable_irq_nosync(bcmsdh_osinfo->oob_irq_num); - bcmsdh_osinfo->oob_irq_enabled = enable; - } - spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags); -} - -static irqreturn_t wlan_oob_irq(int irq, void *dev_id) -{ - bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id; - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - bcmsdh_oob_intr_set(bcmsdh, FALSE); - bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context); - - return IRQ_HANDLED; -} - -int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, - void* oob_irq_handler_context) -{ - int err = 0; - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - SDLX_MSG(("%s: Enter\n", __FUNCTION__)); - if (bcmsdh_osinfo->oob_irq_registered) { - SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__)); - return -EBUSY; - } - SDLX_MSG(("%s OOB irq=%d flags=%X \n", __FUNCTION__, - (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags)); - bcmsdh_osinfo->oob_irq_handler = oob_irq_handler; - bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context; -#if defined(CONFIG_ARCH_ODIN) - err = odin_gpio_sms_request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, - bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); -#else - err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, - bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); -#endif /* defined(CONFIG_ARCH_ODIN) */ - if (err) { - SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err)); - return err; - } - - err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num); - if (!err) - bcmsdh_osinfo->oob_irq_wake_enabled = TRUE; - bcmsdh_osinfo->oob_irq_enabled = TRUE; - bcmsdh_osinfo->oob_irq_registered = TRUE; - return err; -} - -void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh) -{ - int err = 0; - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - SDLX_MSG(("%s: Enter\n", __FUNCTION__)); - if (!bcmsdh_osinfo->oob_irq_registered) { - SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__)); - return; - } - if (bcmsdh_osinfo->oob_irq_wake_enabled) { - err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num); - if (!err) - bcmsdh_osinfo->oob_irq_wake_enabled = FALSE; - } - if (bcmsdh_osinfo->oob_irq_enabled) { - disable_irq(bcmsdh_osinfo->oob_irq_num); - bcmsdh_osinfo->oob_irq_enabled = FALSE; - } - free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh); - bcmsdh_osinfo->oob_irq_registered = FALSE; -} -#endif - -/* Module parameters specific to each host-controller driver */ - -extern uint sd_msglevel; /* Debug message level */ -module_param(sd_msglevel, uint, 0); - -extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */ -module_param(sd_power, uint, 0); - -extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */ -module_param(sd_clock, uint, 0); - -extern uint sd_divisor; /* Divisor (-1 means external clock) */ -module_param(sd_divisor, uint, 0); - -extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */ -module_param(sd_sdmode, uint, 0); - -extern uint sd_hiok; /* Ok to use hi-speed mode */ -module_param(sd_hiok, uint, 0); - -extern uint sd_f2_blocksize; -module_param(sd_f2_blocksize, int, 0); - -#ifdef BCMSDIOH_STD -extern int sd_uhsimode; -module_param(sd_uhsimode, int, 0); -extern uint sd_tuning_period; -module_param(sd_tuning_period, uint, 0); -extern int sd_delay_value; -module_param(sd_delay_value, uint, 0); - -/* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */ -extern char dhd_sdiod_uhsi_ds_override[2]; -module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0); - -#endif - -#ifdef BCMSDH_MODULE -EXPORT_SYMBOL(bcmsdh_attach); -EXPORT_SYMBOL(bcmsdh_detach); -EXPORT_SYMBOL(bcmsdh_intr_query); -EXPORT_SYMBOL(bcmsdh_intr_enable); -EXPORT_SYMBOL(bcmsdh_intr_disable); -EXPORT_SYMBOL(bcmsdh_intr_reg); -EXPORT_SYMBOL(bcmsdh_intr_dereg); - -#if defined(DHD_DEBUG) -EXPORT_SYMBOL(bcmsdh_intr_pending); -#endif - -EXPORT_SYMBOL(bcmsdh_devremove_reg); -EXPORT_SYMBOL(bcmsdh_cfg_read); -EXPORT_SYMBOL(bcmsdh_cfg_write); -EXPORT_SYMBOL(bcmsdh_cis_read); -EXPORT_SYMBOL(bcmsdh_reg_read); -EXPORT_SYMBOL(bcmsdh_reg_write); -EXPORT_SYMBOL(bcmsdh_regfail); -EXPORT_SYMBOL(bcmsdh_send_buf); -EXPORT_SYMBOL(bcmsdh_recv_buf); - -EXPORT_SYMBOL(bcmsdh_rwdata); -EXPORT_SYMBOL(bcmsdh_abort); -EXPORT_SYMBOL(bcmsdh_query_device); -EXPORT_SYMBOL(bcmsdh_query_iofnum); -EXPORT_SYMBOL(bcmsdh_iovar_op); -EXPORT_SYMBOL(bcmsdh_register); -EXPORT_SYMBOL(bcmsdh_unregister); -EXPORT_SYMBOL(bcmsdh_chipmatch); -EXPORT_SYMBOL(bcmsdh_reset); -EXPORT_SYMBOL(bcmsdh_waitlockfree); - -EXPORT_SYMBOL(bcmsdh_get_dstatus); -EXPORT_SYMBOL(bcmsdh_cfg_read_word); -EXPORT_SYMBOL(bcmsdh_cfg_write_word); -EXPORT_SYMBOL(bcmsdh_cur_sbwad); -EXPORT_SYMBOL(bcmsdh_chipinfo); - -#endif /* BCMSDH_MODULE */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c deleted file mode 100755 index 87aaeee7c10f..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c +++ /dev/null @@ -1,1386 +0,0 @@ -/* - * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh_sdmmc.c 710227 2017-07-12 08:09:07Z $ - */ -#include - -#include -#include -#include -#include -#include /* SDIO Device and Protocol Specs */ -#include /* Standard SDIO Host Controller Specification */ -#include /* bcmsdh to/from specific controller APIs */ -#include /* ioctl/iovars */ - -#include -#include -#include -#include -#include - -#include -#include - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -#include -extern volatile bool dhd_mmc_suspend; -#endif -#include "bcmsdh_sdmmc.h" - -#ifndef BCMSDH_MODULE -extern int sdio_function_init(void); -extern void sdio_function_cleanup(void); -#endif /* BCMSDH_MODULE */ - -#if !defined(OOB_INTR_ONLY) -static void IRQHandler(struct sdio_func *func); -static void IRQHandlerF2(struct sdio_func *func); -#endif /* !defined(OOB_INTR_ONLY) */ -static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); -extern int sdio_reset_comm(struct mmc_card *card); - -#define DEFAULT_SDIO_F2_BLKSIZE 512 -#ifndef CUSTOM_SDIO_F2_BLKSIZE -#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE -#endif - -#define MAX_IO_RW_EXTENDED_BLK 511 - -uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ -uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; -uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ - -uint sd_power = 1; /* Default to SD Slot powered ON */ -uint sd_clock = 1; /* Default to SD Clock turned ON */ -uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ -uint sd_msglevel = 0x01; -uint sd_use_dma = TRUE; - -#ifndef CUSTOM_RXCHAIN -#define CUSTOM_RXCHAIN 0 -#endif - -DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); -DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); -DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); -DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); - -#define DMA_ALIGN_MASK 0x03 -#define MMC_SDIO_ABORT_RETRY_LIMIT 5 - -int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); - -static int -sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) -{ - int err_ret; - uint32 fbraddr; - uint8 func; - - sd_trace(("%s\n", __FUNCTION__)); - - /* Get the Card's common CIS address */ - sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); - sd->func_cis_ptr[0] = sd->com_cis_ptr; - sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); - - /* Get the Card's function CIS (for each function) */ - for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; - func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { - sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); - sd_info(("%s: Function %d CIS Ptr = 0x%x\n", - __FUNCTION__, func, sd->func_cis_ptr[func])); - } - - sd->func_cis_ptr[0] = sd->com_cis_ptr; - sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); - - /* Enable Function 1 */ - sdio_claim_host(sd->func[1]); - err_ret = sdio_enable_func(sd->func[1]); - sdio_release_host(sd->func[1]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret)); - } - - return FALSE; -} - -/* - * Public entry points & extern's - */ -extern sdioh_info_t * -sdioh_attach(osl_t *osh, struct sdio_func *func) -{ - sdioh_info_t *sd = NULL; - int err_ret; - - sd_trace(("%s\n", __FUNCTION__)); - - if (func == NULL) { - sd_err(("%s: sdio function device is NULL\n", __FUNCTION__)); - return NULL; - } - - if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { - sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); - return NULL; - } - bzero((char *)sd, sizeof(sdioh_info_t)); - sd->osh = osh; - sd->fake_func0.num = 0; - sd->fake_func0.card = func->card; - sd->func[0] = &sd->fake_func0; - sd->func[1] = func->card->sdio_func[0]; - sd->func[2] = func->card->sdio_func[1]; - sd->num_funcs = 2; - sd->sd_blockmode = TRUE; - sd->use_client_ints = TRUE; - sd->client_block_size[0] = 64; - sd->use_rxchain = CUSTOM_RXCHAIN; - if (sd->func[1] == NULL || sd->func[2] == NULL) { - sd_err(("%s: func 1 or 2 is null \n", __FUNCTION__)); - goto fail; - } - sdio_set_drvdata(sd->func[1], sd); - - sdio_claim_host(sd->func[1]); - sd->client_block_size[1] = 64; - err_ret = sdio_set_block_size(sd->func[1], 64); - sdio_release_host(sd->func[1]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize(%d)\n", err_ret)); - goto fail; - } - - sdio_claim_host(sd->func[2]); - sd->client_block_size[2] = sd_f2_blocksize; - err_ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); - sdio_release_host(sd->func[2]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d(%d)\n", - sd_f2_blocksize, err_ret)); - goto fail; - } - - sdioh_sdmmc_card_enablefuncs(sd); - - sd_trace(("%s: Done\n", __FUNCTION__)); - return sd; - -fail: - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return NULL; -} - - -extern SDIOH_API_RC -sdioh_detach(osl_t *osh, sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - - if (sd) { - - /* Disable Function 2 */ - if (sd->func[2]) { - sdio_claim_host(sd->func[2]); - sdio_disable_func(sd->func[2]); - sdio_release_host(sd->func[2]); - } - - /* Disable Function 1 */ - if (sd->func[1]) { - sdio_claim_host(sd->func[1]); - sdio_disable_func(sd->func[1]); - sdio_release_host(sd->func[1]); - } - - sd->func[1] = NULL; - sd->func[2] = NULL; - - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - } - return SDIOH_API_RC_SUCCESS; -} - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) - -extern SDIOH_API_RC -sdioh_enable_func_intr(sdioh_info_t *sd) -{ - uint8 reg; - int err; - - if (sd->func[0] == NULL) { - sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - sdio_claim_host(sd->func[0]); - reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); - if (err) { - sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - sdio_release_host(sd->func[0]); - return SDIOH_API_RC_FAIL; - } - /* Enable F1 and F2 interrupts, clear master enable */ - reg &= ~INTR_CTL_MASTER_EN; - reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); - sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); - sdio_release_host(sd->func[0]); - - if (err) { - sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - return SDIOH_API_RC_FAIL; - } - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_disable_func_intr(sdioh_info_t *sd) -{ - uint8 reg; - int err; - - if (sd->func[0] == NULL) { - sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - sdio_claim_host(sd->func[0]); - reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); - if (err) { - sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - sdio_release_host(sd->func[0]); - return SDIOH_API_RC_FAIL; - } - reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); - /* Disable master interrupt with the last function interrupt */ - if (!(reg & 0xFE)) - reg = 0; - sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); - sdio_release_host(sd->func[0]); - - if (err) { - sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - return SDIOH_API_RC_FAIL; - } - - return SDIOH_API_RC_SUCCESS; -} -#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ - -/* Configure callback to client when we recieve client interrupt */ -extern SDIOH_API_RC -sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - if (fn == NULL) { - sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } -#if !defined(OOB_INTR_ONLY) - sd->intr_handler = fn; - sd->intr_handler_arg = argh; - sd->intr_handler_valid = TRUE; - - /* register and unmask irq */ - if (sd->func[2]) { - sdio_claim_host(sd->func[2]); - sdio_claim_irq(sd->func[2], IRQHandlerF2); - sdio_release_host(sd->func[2]); - } - - if (sd->func[1]) { - sdio_claim_host(sd->func[1]); - sdio_claim_irq(sd->func[1], IRQHandler); - sdio_release_host(sd->func[1]); - } -#elif defined(HW_OOB) - sdioh_enable_func_intr(sd); -#endif /* !defined(OOB_INTR_ONLY) */ - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_deregister(sdioh_info_t *sd) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - -#if !defined(OOB_INTR_ONLY) - if (sd->func[1]) { - /* register and unmask irq */ - sdio_claim_host(sd->func[1]); - sdio_release_irq(sd->func[1]); - sdio_release_host(sd->func[1]); - } - - if (sd->func[2]) { - /* Claim host controller F2 */ - sdio_claim_host(sd->func[2]); - sdio_release_irq(sd->func[2]); - /* Release host controller F2 */ - sdio_release_host(sd->func[2]); - } - - sd->intr_handler_valid = FALSE; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; -#elif defined(HW_OOB) - sdioh_disable_func_intr(sd); -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - *onoff = sd->client_intr_enabled; - return SDIOH_API_RC_SUCCESS; -} - -#if defined(DHD_DEBUG) -extern bool -sdioh_interrupt_pending(sdioh_info_t *sd) -{ - return (0); -} -#endif - -uint -sdioh_query_iofnum(sdioh_info_t *sd) -{ - return sd->num_funcs; -} - -/* IOVar table */ -enum { - IOV_MSGLEVEL = 1, - IOV_BLOCKMODE, - IOV_BLOCKSIZE, - IOV_DMA, - IOV_USEINTS, - IOV_NUMINTS, - IOV_NUMLOCALINTS, - IOV_HOSTREG, - IOV_DEVREG, - IOV_DIVISOR, - IOV_SDMODE, - IOV_HISPEED, - IOV_HCIREGS, - IOV_POWER, - IOV_CLOCK, - IOV_RXCHAIN -}; - -const bcm_iovar_t sdioh_iovars[] = { - {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, - {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, - {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ - {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, - {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, - {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, - {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, - {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, - {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, - {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, - {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, - {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 }, - {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -int -sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - int32 int_val = 0; - bool bool_val; - uint32 actionid; - - ASSERT(name); - ASSERT(len >= 0); - - /* Get must have return space; Set does not take qualifiers */ - ASSERT(set || (arg && len)); - ASSERT(!set || (!params && !plen)); - - sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); - - if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) - goto exit; - - /* Set up params so get and set can share the convenience variables */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - val_size = sizeof(int); - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - BCM_REFERENCE(bool_val); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - switch (actionid) { - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)sd_msglevel; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): - sd_msglevel = int_val; - break; - - case IOV_GVAL(IOV_BLOCKMODE): - int_val = (int32)si->sd_blockmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_BLOCKMODE): - si->sd_blockmode = (bool)int_val; - /* Haven't figured out how to make non-block mode with DMA */ - break; - - case IOV_GVAL(IOV_BLOCKSIZE): - if ((uint32)int_val > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - int_val = (int32)si->client_block_size[int_val]; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_BLOCKSIZE): - { - uint func = ((uint32)int_val >> 16); - uint blksize = (uint16)int_val; - uint maxsize; - - if (func > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - - switch (func) { - case 0: maxsize = 32; break; - case 1: maxsize = BLOCK_SIZE_4318; break; - case 2: maxsize = BLOCK_SIZE_4328; break; - default: maxsize = 0; - } - if (blksize > maxsize) { - bcmerror = BCME_BADARG; - break; - } - if (!blksize) { - blksize = maxsize; - } - - /* Now set it */ - si->client_block_size[func] = blksize; - - break; - } - - case IOV_GVAL(IOV_RXCHAIN): - int_val = (int32)si->use_rxchain; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DMA): - int_val = (int32)si->sd_use_dma; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DMA): - si->sd_use_dma = (bool)int_val; - break; - - case IOV_GVAL(IOV_USEINTS): - int_val = (int32)si->use_client_ints; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_USEINTS): - si->use_client_ints = (bool)int_val; - if (si->use_client_ints) - si->intmask |= CLIENT_INTR; - else - si->intmask &= ~CLIENT_INTR; - - break; - - case IOV_GVAL(IOV_DIVISOR): - int_val = (uint32)sd_divisor; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DIVISOR): - sd_divisor = int_val; - break; - - case IOV_GVAL(IOV_POWER): - int_val = (uint32)sd_power; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POWER): - sd_power = int_val; - break; - - case IOV_GVAL(IOV_CLOCK): - int_val = (uint32)sd_clock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CLOCK): - sd_clock = int_val; - break; - - case IOV_GVAL(IOV_SDMODE): - int_val = (uint32)sd_sdmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDMODE): - sd_sdmode = int_val; - break; - - case IOV_GVAL(IOV_HISPEED): - int_val = (uint32)sd_hiok; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HISPEED): - sd_hiok = int_val; - break; - - case IOV_GVAL(IOV_NUMINTS): - int_val = (int32)si->intrcount; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_NUMLOCALINTS): - int_val = (int32)0; - bcopy(&int_val, arg, val_size); - break; - default: - bcmerror = BCME_UNSUPPORTED; - break; - } -exit: - - return bcmerror; -} - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) - -SDIOH_API_RC -sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) -{ - SDIOH_API_RC status; - uint8 data; - - if (enable) - data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; - else - data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ - - status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); - return status; -} -#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ - -extern SDIOH_API_RC -sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - SDIOH_API_RC status; - /* No lock needed since sdioh_request_byte does locking */ - status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - /* No lock needed since sdioh_request_byte does locking */ - SDIOH_API_RC status; - status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); - return status; -} - -static int -sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) -{ - /* read 24 bits and return valid 17 bit addr */ - int i; - uint32 scratch, regdata; - uint8 *ptr = (uint8 *)&scratch; - for (i = 0; i < 3; i++) { - if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) - sd_err(("%s: Can't read!\n", __FUNCTION__)); - - *ptr++ = (uint8) regdata; - regaddr++; - } - - /* Only the lower 17-bits are valid */ - scratch = ltoh32(scratch); - scratch &= 0x0001FFFF; - return (scratch); -} - -extern SDIOH_API_RC -sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) -{ - uint32 count; - int offset; - uint32 foo; - uint8 *cis = cisd; - - sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); - - if (!sd->func_cis_ptr[func]) { - bzero(cis, length); - sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); - return SDIOH_API_RC_FAIL; - } - - sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); - - for (count = 0; count < length; count++) { - offset = sd->func_cis_ptr[func] + count; - if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { - sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - *cis = (uint8)(foo & 0xff); - cis++; - } - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) -{ - int err_ret = 0; -#if defined(MMC_SDIO_ABORT) - int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; -#endif - - sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); - - DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - if(rw) { /* CMD52 Write */ - if (func == 0) { - /* Can only directly write to some F0 registers. Handle F2 enable - * as a special case. - */ - if (regaddr == SDIOD_CCCR_IOEN) { - if (sd->func[2]) { - sdio_claim_host(sd->func[2]); - if (*byte & SDIO_FUNC_ENABLE_2) { - /* Enable Function 2 */ - err_ret = sdio_enable_func(sd->func[2]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: enable F2 failed:%d", - err_ret)); - } - } else { - /* Disable Function 2 */ - err_ret = sdio_disable_func(sd->func[2]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d", - err_ret)); - } - } - sdio_release_host(sd->func[2]); - } - } -#if defined(MMC_SDIO_ABORT) - /* to allow abort command through F1 */ - else if (regaddr == SDIOD_CCCR_IOABORT) { - while (sdio_abort_retry--) { - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - /* - * this sdio_f0_writeb() can be replaced with - * another api depending upon MMC driver change. - * As of this time, this is temporaray one - */ - sdio_writeb(sd->func[func], - *byte, regaddr, &err_ret); - sdio_release_host(sd->func[func]); - } - if (!err_ret) - break; - } - } -#endif /* MMC_SDIO_ABORT */ - else if (regaddr < 0xF0) { - sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); - } else { - /* Claim host controller, perform F0 write, and release */ - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - sdio_f0_writeb(sd->func[func], - *byte, regaddr, &err_ret); - sdio_release_host(sd->func[func]); - } - } - } else { - /* Claim host controller, perform Fn write, and release */ - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - sdio_writeb(sd->func[func], *byte, regaddr, &err_ret); - sdio_release_host(sd->func[func]); - } - } - } else { /* CMD52 Read */ - /* Claim host controller, perform Fn read, and release */ - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - if (func == 0) { - *byte = sdio_f0_readb(sd->func[func], regaddr, &err_ret); - } else { - *byte = sdio_readb(sd->func[func], regaddr, &err_ret); - } - sdio_release_host(sd->func[func]); - } - } - - if (err_ret) { - if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ))) { - } else { - sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", - rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); - } - } - - return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -extern SDIOH_API_RC -sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, - uint32 *word, uint nbytes) -{ - int err_ret = SDIOH_API_RC_FAIL; -#if defined(MMC_SDIO_ABORT) - int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; -#endif - - if (func == 0) { - sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", - __FUNCTION__, cmd_type, rw, func, addr, nbytes)); - - DHD_PM_RESUME_WAIT(sdioh_request_word_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - /* Claim host controller */ - sdio_claim_host(sd->func[func]); - - if(rw) { /* CMD52 Write */ - if (nbytes == 4) { - sdio_writel(sd->func[func], *word, addr, &err_ret); - } else if (nbytes == 2) { - sdio_writew(sd->func[func], (*word & 0xFFFF), addr, &err_ret); - } else { - sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); - } - } else { /* CMD52 Read */ - if (nbytes == 4) { - *word = sdio_readl(sd->func[func], addr, &err_ret); - } else if (nbytes == 2) { - *word = sdio_readw(sd->func[func], addr, &err_ret) & 0xFFFF; - } else { - sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); - } - } - - /* Release host controller */ - sdio_release_host(sd->func[func]); - - if (err_ret) { -#if defined(MMC_SDIO_ABORT) - /* Any error on CMD53 transaction should abort that function using function 0. */ - while (sdio_abort_retry--) { - if (sd->func[0]) { - sdio_claim_host(sd->func[0]); - /* - * this sdio_f0_writeb() can be replaced with another api - * depending upon MMC driver change. - * As of this time, this is temporaray one - */ - sdio_writeb(sd->func[0], - func, SDIOD_CCCR_IOABORT, &err_ret); - sdio_release_host(sd->func[0]); - } - if (!err_ret) - break; - } - if (err_ret) -#endif /* MMC_SDIO_ABORT */ - { - sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x", - rw ? "Write" : "Read", err_ret)); - } - } - - return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -static SDIOH_API_RC -sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func, - uint addr, void *pkt) -{ - bool fifo = (fix_inc == SDIOH_DATA_FIX); - int err_ret = 0; - void *pnext; - uint ttl_len, pkt_offset; - uint blk_num; - uint blk_size; - uint max_blk_count; - uint max_req_size; - struct mmc_request mmc_req; - struct mmc_command mmc_cmd; - struct mmc_data mmc_dat; - uint32 sg_count; - struct sdio_func *sdio_func = sd->func[func]; - struct mmc_host *host = sdio_func->card->host; - - sd_trace(("%s: Enter\n", __FUNCTION__)); - ASSERT(pkt); - DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - - blk_size = sd->client_block_size[func]; - max_blk_count = min(host->max_blk_count, (uint)MAX_IO_RW_EXTENDED_BLK); - max_req_size = min(max_blk_count * blk_size, host->max_req_size); - - pkt_offset = 0; - pnext = pkt; - - while (pnext != NULL) { - ttl_len = 0; - sg_count = 0; - memset(&mmc_req, 0, sizeof(struct mmc_request)); - memset(&mmc_cmd, 0, sizeof(struct mmc_command)); - memset(&mmc_dat, 0, sizeof(struct mmc_data)); - sg_init_table(sd->sg_list, ARRAYSIZE(sd->sg_list)); - - /* Set up scatter-gather DMA descriptors. this loop is to find out the max - * data we can transfer with one command 53. blocks per command is limited by - * host max_req_size and 9-bit max block number. when the total length of this - * packet chain is bigger than max_req_size, use multiple SD_IO_RW_EXTENDED - * commands (each transfer is still block aligned) - */ - while (pnext != NULL && ttl_len < max_req_size) { - int pkt_len; - int sg_data_size; - uint8 *pdata = (uint8*)PKTDATA(sd->osh, pnext); - - ASSERT(pdata != NULL); - pkt_len = PKTLEN(sd->osh, pnext); - sd_trace(("%s[%d] data=%p, len=%d\n", __FUNCTION__, write, pdata, pkt_len)); - /* sg_count is unlikely larger than the array size, and this is - * NOT something we can handle here, but in case it happens, PLEASE put - * a restriction on max tx/glom count (based on host->max_segs). - */ - if (sg_count >= ARRAYSIZE(sd->sg_list)) { - sd_err(("%s: sg list entries exceed limit\n", __FUNCTION__)); - return (SDIOH_API_RC_FAIL); - } - pdata += pkt_offset; - - sg_data_size = pkt_len - pkt_offset; - if (sg_data_size > max_req_size - ttl_len) - sg_data_size = max_req_size - ttl_len; - /* some platforms put a restriction on the data size of each scatter-gather - * DMA descriptor, use multiple sg buffers when xfer_size is bigger than - * max_seg_size - */ - if (sg_data_size > host->max_seg_size) - sg_data_size = host->max_seg_size; - sg_set_buf(&sd->sg_list[sg_count++], pdata, sg_data_size); - - ttl_len += sg_data_size; - pkt_offset += sg_data_size; - if (pkt_offset == pkt_len) { - pnext = PKTNEXT(sd->osh, pnext); - pkt_offset = 0; - } - } - - if (ttl_len % blk_size != 0) { - sd_err(("%s, data length %d not aligned to block size %d\n", - __FUNCTION__, ttl_len, blk_size)); - return SDIOH_API_RC_FAIL; - } - blk_num = ttl_len / blk_size; - mmc_dat.sg = sd->sg_list; - mmc_dat.sg_len = sg_count; - mmc_dat.blksz = blk_size; - mmc_dat.blocks = blk_num; - mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; - mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ - mmc_cmd.arg = write ? 1<<31 : 0; - mmc_cmd.arg |= (func & 0x7) << 28; - mmc_cmd.arg |= 1<<27; - mmc_cmd.arg |= fifo ? 0 : 1<<26; - mmc_cmd.arg |= (addr & 0x1FFFF) << 9; - mmc_cmd.arg |= blk_num & 0x1FF; - mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; - mmc_req.cmd = &mmc_cmd; - mmc_req.data = &mmc_dat; - if (!fifo) - addr += ttl_len; - - sdio_claim_host(sdio_func); - mmc_set_data_timeout(&mmc_dat, sdio_func->card); - mmc_wait_for_req(host, &mmc_req); - sdio_release_host(sdio_func); - - err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; - if (0 != err_ret) { - sd_err(("%s:CMD53 %s failed with code %d\n", - __FUNCTION__, write ? "write" : "read", err_ret)); - return SDIOH_API_RC_FAIL; - } - } - - sd_trace(("%s: Exit\n", __FUNCTION__)); - return SDIOH_API_RC_SUCCESS; -} - -static SDIOH_API_RC -sdioh_buffer_tofrom_bus(sdioh_info_t *sd, uint fix_inc, uint write, uint func, - uint addr, uint8 *buf, uint len) -{ - bool fifo = (fix_inc == SDIOH_DATA_FIX); - int err_ret = 0; - - sd_trace(("%s: Enter\n", __FUNCTION__)); - ASSERT(buf); - - /* NOTE: - * For all writes, each packet length is aligned to 32 (or 4) - * bytes in dhdsdio_txpkt_preprocess, and for glom the last packet length - * is aligned to block boundary. If you want to align each packet to - * a custom size, please do it in dhdsdio_txpkt_preprocess, NOT here - * - * For reads, the alignment is doen in sdioh_request_buffer. - * - */ - sdio_claim_host(sd->func[func]); - - if ((write) && (!fifo)) - err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); - else if (write) - err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); - else if (fifo) - err_ret = sdio_readsb(sd->func[func], buf, addr, len); - else - err_ret = sdio_memcpy_fromio(sd->func[func], buf, addr, len); - - sdio_release_host(sd->func[func]); - - if (err_ret) - sd_err(("%s: %s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=%d\n", __FUNCTION__, - (write) ? "TX" : "RX", buf, addr, len, err_ret)); - else - sd_trace(("%s: %s xfr'd %p, addr=0x%05x, len=%d\n", __FUNCTION__, - (write) ? "TX" : "RX", buf, addr, len)); - - sd_trace(("%s: Exit\n", __FUNCTION__)); - return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - - -/* - * 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. - * - */ -extern SDIOH_API_RC -sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, - uint addr, uint reg_width, uint buf_len, uint8 *buffer, void *pkt) -{ - SDIOH_API_RC status; - void *tmppkt; - - sd_trace(("%s: Enter\n", __FUNCTION__)); - DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - - if (pkt) { - /* packet chain, only used for tx/rx glom, all packets length - * are aligned, total length is a block multiple - */ - if (PKTNEXT(sd->osh, pkt)) - return sdioh_request_packet_chain(sd, fix_inc, write, func, addr, pkt); - - /* non-glom mode, ignore the buffer parameter and use the packet pointer - * (this shouldn't happen) - */ - buffer = PKTDATA(sd->osh, pkt); - buf_len = PKTLEN(sd->osh, pkt); - } - - ASSERT(buffer); - - /* buffer and length are aligned, use it directly so we can avoid memory copy */ - if (((ulong)buffer & DMA_ALIGN_MASK) == 0 && (buf_len & DMA_ALIGN_MASK) == 0) - return sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, buffer, buf_len); - - sd_err(("%s: [%d] doing memory copy buf=%p, len=%d\n", - __FUNCTION__, write, buffer, buf_len)); - - /* otherwise, a memory copy is needed as the input buffer is not aligned */ - tmppkt = PKTGET_STATIC(sd->osh, buf_len + DEFAULT_SDIO_F2_BLKSIZE, write ? TRUE : FALSE); - if (tmppkt == NULL) { - sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, buf_len)); - return SDIOH_API_RC_FAIL; - } - - if (write) - bcopy(buffer, PKTDATA(sd->osh, tmppkt), buf_len); - - status = sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, - PKTDATA(sd->osh, tmppkt), ROUNDUP(buf_len, (DMA_ALIGN_MASK+1))); - - if (!write) - bcopy(PKTDATA(sd->osh, tmppkt), buffer, buf_len); - - PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE); - - return status; -} - -/* this function performs "abort" for both of host & device */ -extern int -sdioh_abort(sdioh_info_t *sd, uint func) -{ -#if defined(MMC_SDIO_ABORT) - char t_func = (char) func; -#endif /* defined(MMC_SDIO_ABORT) */ - sd_trace(("%s: Enter\n", __FUNCTION__)); - -#if defined(MMC_SDIO_ABORT) - /* issue abort cmd52 command through F1 */ - sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); -#endif /* defined(MMC_SDIO_ABORT) */ - - sd_trace(("%s: Exit\n", __FUNCTION__)); - return SDIOH_API_RC_SUCCESS; -} - -/* Reset and re-initialize the device */ -int sdioh_sdio_reset(sdioh_info_t *si) -{ - sd_trace(("%s: Enter\n", __FUNCTION__)); - sd_trace(("%s: Exit\n", __FUNCTION__)); - return SDIOH_API_RC_SUCCESS; -} - -/* Disable device interrupt */ -void -sdioh_sdmmc_devintr_off(sdioh_info_t *sd) -{ - sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); - sd->intmask &= ~CLIENT_INTR; -} - -/* Enable device interrupt */ -void -sdioh_sdmmc_devintr_on(sdioh_info_t *sd) -{ - sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); - sd->intmask |= CLIENT_INTR; -} - -/* Read client card reg */ -int -sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - - if ((func == 0) || (regsize == 1)) { - uint8 temp = 0; - - sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); - *data = temp; - *data &= 0xff; - sd_data(("%s: byte read data=0x%02x\n", - __FUNCTION__, *data)); - } else { - sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize); - if (regsize == 2) - *data &= 0xffff; - - sd_data(("%s: word read data=0x%08x\n", - __FUNCTION__, *data)); - } - - return SUCCESS; -} - -#if !defined(OOB_INTR_ONLY) -/* bcmsdh_sdmmc interrupt handler */ -static void IRQHandler(struct sdio_func *func) -{ - sdioh_info_t *sd; - - sd = sdio_get_drvdata(func); - - ASSERT(sd != NULL); - sdio_release_host(sd->func[0]); - - if (sd->use_client_ints) { - sd->intrcount++; - ASSERT(sd->intr_handler); - ASSERT(sd->intr_handler_arg); - (sd->intr_handler)(sd->intr_handler_arg); - } else { - sd_err(("bcmsdh_sdmmc: ***IRQHandler\n")); - - sd_err(("%s: Not ready for intr: enabled %d, handler %p\n", - __FUNCTION__, sd->client_intr_enabled, sd->intr_handler)); - } - - sdio_claim_host(sd->func[0]); -} - -/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ -static void IRQHandlerF2(struct sdio_func *func) -{ - sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n")); -} -#endif /* !defined(OOB_INTR_ONLY) */ - -#ifdef NOTUSED -/* Write client card reg */ -static int -sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) -{ - - if ((func == 0) || (regsize == 1)) { - uint8 temp; - - temp = data & 0xff; - sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); - sd_data(("%s: byte write data=0x%02x\n", - __FUNCTION__, data)); - } else { - if (regsize == 2) - data &= 0xffff; - - sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); - - sd_data(("%s: word write data=0x%08x\n", - __FUNCTION__, data)); - } - - return SUCCESS; -} -#endif /* NOTUSED */ - -int -sdioh_start(sdioh_info_t *sd, int stage) -{ - int ret; - - if (!sd) { - sd_err(("%s Failed, sd is NULL\n", __FUNCTION__)); - return (0); - } - - /* Need to do this stages as we can't enable the interrupt till - downloading of the firmware is complete, other wise polling - sdio access will come in way - */ - if (sd->func[0]) { - if (stage == 0) { - /* Since the power to the chip is killed, we will have - re enumerate the device again. Set the block size - and enable the fucntion 1 for in preparation for - downloading the code - */ - /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux - 2.6.27. The implementation prior to that is buggy, and needs broadcom's - patch for it - */ - if ((ret = sdio_reset_comm(sd->func[0]->card))) { - sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); - return ret; - } - else { - sd->num_funcs = 2; - sd->sd_blockmode = TRUE; - sd->use_client_ints = TRUE; - sd->client_block_size[0] = 64; - - if (sd->func[1]) { - /* Claim host controller */ - sdio_claim_host(sd->func[1]); - - sd->client_block_size[1] = 64; - ret = sdio_set_block_size(sd->func[1], 64); - if (ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 " - "blocksize(%d)\n", ret)); - } - - /* Release host controller F1 */ - sdio_release_host(sd->func[1]); - } - - if (sd->func[2]) { - /* Claim host controller F2 */ - sdio_claim_host(sd->func[2]); - - sd->client_block_size[2] = sd_f2_blocksize; - ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); - if (ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F2 " - "blocksize to %d(%d)\n", sd_f2_blocksize, ret)); - } - - /* Release host controller F2 */ - sdio_release_host(sd->func[2]); - } - - sdioh_sdmmc_card_enablefuncs(sd); - } - } else { -#if !defined(OOB_INTR_ONLY) - sdio_claim_host(sd->func[0]); - if (sd->func[2]) - sdio_claim_irq(sd->func[2], IRQHandlerF2); - if (sd->func[1]) - sdio_claim_irq(sd->func[1], IRQHandler); - sdio_release_host(sd->func[0]); -#else /* defined(OOB_INTR_ONLY) */ -#if defined(HW_OOB) - sdioh_enable_func_intr(sd); -#endif - bcmsdh_oob_intr_set(sd->bcmsdh, TRUE); -#endif /* !defined(OOB_INTR_ONLY) */ - } - } - else - sd_err(("%s Failed\n", __FUNCTION__)); - - return (0); -} - -int -sdioh_stop(sdioh_info_t *sd) -{ - /* MSM7201A Android sdio stack has bug with interrupt - So internaly within SDIO stack they are polling - which cause issue when device is turned off. So - unregister interrupt with SDIO stack to stop the - polling - */ - if (sd->func[0]) { -#if !defined(OOB_INTR_ONLY) - sdio_claim_host(sd->func[0]); - if (sd->func[1]) - sdio_release_irq(sd->func[1]); - if (sd->func[2]) - sdio_release_irq(sd->func[2]); - sdio_release_host(sd->func[0]); -#else /* defined(OOB_INTR_ONLY) */ -#if defined(HW_OOB) - sdioh_disable_func_intr(sd); -#endif - bcmsdh_oob_intr_set(sd->bcmsdh, FALSE); -#endif /* !defined(OOB_INTR_ONLY) */ - } - else - sd_err(("%s Failed\n", __FUNCTION__)); - return (0); -} - -int -sdioh_waitlockfree(sdioh_info_t *sd) -{ - return (1); -} - - -SDIOH_API_RC -sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) -{ - return SDIOH_API_RC_FAIL; -} - -SDIOH_API_RC -sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) -{ - return SDIOH_API_RC_FAIL; -} - -bool -sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) -{ - return FALSE; -} - -SDIOH_API_RC -sdioh_gpio_init(sdioh_info_t *sd) -{ - return SDIOH_API_RC_FAIL; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c deleted file mode 100755 index 27a48afb523b..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh_sdmmc_linux.c 611357 2016-01-11 04:26:56Z $ - */ - -#include -#include -#include /* SDIO Device and Protocol Specs */ -#include /* bcmsdh to/from specific controller APIs */ -#include /* to get msglevel bit values */ - -#include /* request_irq() */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(SDIO_VENDOR_ID_BROADCOM) -#define SDIO_VENDOR_ID_BROADCOM 0x02d0 -#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ - -#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 - -#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) -#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4325) -#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4329) -#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) -#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) -#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) -#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4324) -#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) -#define SDIO_DEVICE_ID_BROADCOM_43239 43239 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ - -extern void wl_cfg80211_set_parent_dev(void *dev); -extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); -extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); -extern void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, - uint bus_num, uint slot_num); -extern int bcmsdh_remove(bcmsdh_info_t *bcmsdh); - -int sdio_function_init(void); -void sdio_function_cleanup(void); - -#define DESCRIPTION "bcmsdh_sdmmc Driver" -#define AUTHOR "Broadcom Corporation" - -/* module param defaults */ -static int clockoverride = 0; - -module_param(clockoverride, int, 0644); -MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); - -/* Maximum number of bcmsdh_sdmmc devices supported by driver */ -#define BCMSDH_SDMMC_MAX_DEVICES 1 - -extern volatile bool dhd_mmc_suspend; - -static int sdioh_probe(struct sdio_func *func) -{ - int host_idx = func->card->host->index; - uint32 rca = func->card->rca; - wifi_adapter_info_t *adapter; - osl_t *osh = NULL; - sdioh_info_t *sdioh = NULL; - - sd_err(("bus num (host idx)=%d, slot num (rca)=%d\n", host_idx, rca)); - adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca); - if (adapter != NULL) - sd_err(("found adapter info '%s'\n", adapter->name)); - else - sd_err(("can't find adapter info for this chip\n")); - -#ifdef WL_CFG80211 - wl_cfg80211_set_parent_dev(&func->dev); -#endif - - /* allocate SDIO Host Controller state info */ - osh = osl_attach(&func->dev, SDIO_BUS, TRUE); - if (osh == NULL) { - sd_err(("%s: osl_attach failed\n", __FUNCTION__)); - goto fail; - } - osl_static_mem_init(osh, adapter); - sdioh = sdioh_attach(osh, func); - if (sdioh == NULL) { - sd_err(("%s: sdioh_attach failed\n", __FUNCTION__)); - goto fail; - } - sdioh->bcmsdh = bcmsdh_probe(osh, &func->dev, sdioh, adapter, SDIO_BUS, host_idx, rca); - if (sdioh->bcmsdh == NULL) { - sd_err(("%s: bcmsdh_probe failed\n", __FUNCTION__)); - goto fail; - } - - sdio_set_drvdata(func, sdioh); - return 0; - -fail: - if (sdioh != NULL) - sdioh_detach(osh, sdioh); - if (osh != NULL) - osl_detach(osh); - return -ENOMEM; -} - -static void sdioh_remove(struct sdio_func *func) -{ - sdioh_info_t *sdioh; - osl_t *osh; - - sdioh = sdio_get_drvdata(func); - if (sdioh == NULL) { - sd_err(("%s: error, no sdioh handler found\n", __FUNCTION__)); - return; - } - - osh = sdioh->osh; - bcmsdh_remove(sdioh->bcmsdh); - sdioh_detach(osh, sdioh); - osl_detach(osh); -} - -static int bcmsdh_sdmmc_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - int ret = 0; - - if (func == NULL) - return -EINVAL; - - sd_err(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); - sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); - sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); - sd_info(("sdio_device: 0x%04x\n", func->device)); - sd_info(("Function#: 0x%04x\n", func->num)); - - /* 4318 doesn't have function 2 */ - if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) - ret = sdioh_probe(func); - - return ret; -} - -static void bcmsdh_sdmmc_remove(struct sdio_func *func) -{ - if (func == NULL) { - sd_err(("%s is called with NULL SDIO function pointer\n", __FUNCTION__)); - return; - } - - sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); - sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); - sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); - sd_info(("sdio_device: 0x%04x\n", func->device)); - sd_info(("Function#: 0x%04x\n", func->num)); - - if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) - sdioh_remove(func); -} - -/* devices we support, null terminated */ -static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, - { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, - { /* end: all zeroes */ }, -}; - -MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) -static int bcmsdh_sdmmc_suspend(struct device *pdev) -{ - int err; - sdioh_info_t *sdioh; - struct sdio_func *func = dev_to_sdio_func(pdev); - mmc_pm_flag_t sdio_flags; - - sd_err(("%s Enter\n", __FUNCTION__)); - if (func->num != 2) - return 0; - - dhd_mmc_suspend = TRUE; - sdioh = sdio_get_drvdata(func); - err = bcmsdh_suspend(sdioh->bcmsdh); - if (err) { - dhd_mmc_suspend = FALSE; - return err; - } - sdio_flags = sdio_get_host_pm_caps(func); - if (!(sdio_flags & MMC_PM_KEEP_POWER)) { - sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__)); - dhd_mmc_suspend = FALSE; - return -EINVAL; - } - - /* keep power while host suspended */ - err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); - if (err) { - sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); - dhd_mmc_suspend = FALSE; - return err; - } -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE); -#endif - smp_mb(); - - return 0; -} - -static int bcmsdh_sdmmc_resume(struct device *pdev) -{ - sdioh_info_t *sdioh; - struct sdio_func *func = dev_to_sdio_func(pdev); - - sd_err(("%s Enter\n", __FUNCTION__)); - if (func->num != 2) - return 0; - - sdioh = sdio_get_drvdata(func); - dhd_mmc_suspend = FALSE; -#if defined(OOB_INTR_ONLY) - bcmsdh_resume(sdioh->bcmsdh); -#endif - - smp_mb(); - return 0; -} - -static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { - .suspend = bcmsdh_sdmmc_suspend, - .resume = bcmsdh_sdmmc_resume, -}; -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ - -#if defined(BCMLXSDMMC) -static struct semaphore *notify_semaphore = NULL; - -static int dummy_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - if (func && (func->num != 2)) { - return 0; - } - - if (notify_semaphore) - up(notify_semaphore); - return 0; -} - -static void dummy_remove(struct sdio_func *func) -{ -} - -static struct sdio_driver dummy_sdmmc_driver = { - .probe = dummy_probe, - .remove = dummy_remove, - .name = "dummy_sdmmc", - .id_table = bcmsdh_sdmmc_ids, - }; - -int sdio_func_reg_notify(void* semaphore) -{ - notify_semaphore = semaphore; - return sdio_register_driver(&dummy_sdmmc_driver); -} - -void sdio_func_unreg_notify(void) -{ - OSL_SLEEP(15); - sdio_unregister_driver(&dummy_sdmmc_driver); -} - -#endif /* defined(BCMLXSDMMC) */ - -static struct sdio_driver bcmsdh_sdmmc_driver = { - .probe = bcmsdh_sdmmc_probe, - .remove = bcmsdh_sdmmc_remove, - .name = "bcmsdh_sdmmc", - .id_table = bcmsdh_sdmmc_ids, -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) - .drv = { - .pm = &bcmsdh_sdmmc_pm_ops, - }, -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ - }; - -struct sdos_info { - sdioh_info_t *sd; - spinlock_t lock; -}; - -/* Interrupt enable/disable */ -SDIOH_API_RC -sdioh_interrupt_set(sdioh_info_t *sd, bool enable) -{ - if (!sd) - return BCME_BADARG; - - sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); - return SDIOH_API_RC_SUCCESS; -} - -#ifdef BCMSDH_MODULE -static int __init -bcmsdh_module_init(void) -{ - int error = 0; - error = sdio_function_init(); - return error; -} - -static void __exit -bcmsdh_module_cleanup(void) -{ - sdio_function_cleanup(); -} - -module_init(bcmsdh_module_init); -module_exit(bcmsdh_module_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION(DESCRIPTION); -MODULE_AUTHOR(AUTHOR); - -#endif /* BCMSDH_MODULE */ -/* - * module init -*/ -int bcmsdh_register_client_driver(void) -{ - return sdio_register_driver(&bcmsdh_sdmmc_driver); -} - -/* - * module cleanup -*/ -void bcmsdh_unregister_client_driver(void) -{ - sdio_unregister_driver(&bcmsdh_sdmmc_driver); -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c deleted file mode 100755 index 689115a51b6f..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Broadcom SPI Host Controller Driver - Linux Per-port - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdspi_linux.c 406045 2013-06-05 22:09:52Z $ - */ - -#include -#include - -#include /* bcmsdh to/from specific controller APIs */ -#include /* to get msglevel bit values */ - -#include -#include /* SDIO Device and Protocol Specs */ -#include /* request_irq(), free_irq() */ -#include -#include - -extern uint sd_crc; -module_param(sd_crc, uint, 0); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define KERNEL26 -#endif - -struct sdos_info { - sdioh_info_t *sd; - spinlock_t lock; - wait_queue_head_t intr_wait_queue; -}; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define BLOCKABLE() (!in_atomic()) -#else -#define BLOCKABLE() (!in_interrupt()) -#endif - -/* Interrupt handler */ -static irqreturn_t -sdspi_isr(int irq, void *dev_id -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -, struct pt_regs *ptregs -#endif -) -{ - sdioh_info_t *sd; - struct sdos_info *sdos; - bool ours; - - sd = (sdioh_info_t *)dev_id; - sd->local_intrcount++; - - if (!sd->card_init_done) { - sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq)); - return IRQ_RETVAL(FALSE); - } else { - ours = spi_check_client_intr(sd, NULL); - - /* For local interrupts, wake the waiting process */ - if (ours && sd->got_hcint) { - sdos = (struct sdos_info *)sd->sdos_info; - wake_up_interruptible(&sdos->intr_wait_queue); - } - - return IRQ_RETVAL(ours); - } -} - - -/* Register with Linux for interrupts */ -int -spi_register_irq(sdioh_info_t *sd, uint irq) -{ - sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq)); - if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) { - sd_err(("%s: request_irq() failed\n", __FUNCTION__)); - return ERROR; - } - return SUCCESS; -} - -/* Free Linux irq */ -void -spi_free_irq(uint irq, sdioh_info_t *sd) -{ - free_irq(irq, sd); -} - -/* Map Host controller registers */ -uint32 * -spi_reg_map(osl_t *osh, uintptr addr, int size) -{ - return (uint32 *)REG_MAP(addr, size); -} - -void -spi_reg_unmap(osl_t *osh, uintptr addr, int size) -{ - REG_UNMAP((void*)(uintptr)addr); -} - -int -spi_osinit(sdioh_info_t *sd) -{ - struct sdos_info *sdos; - - sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); - sd->sdos_info = (void*)sdos; - if (sdos == NULL) - return BCME_NOMEM; - - sdos->sd = sd; - spin_lock_init(&sdos->lock); - init_waitqueue_head(&sdos->intr_wait_queue); - return BCME_OK; -} - -void -spi_osfree(sdioh_info_t *sd) -{ - struct sdos_info *sdos; - ASSERT(sd && sd->sdos_info); - - sdos = (struct sdos_info *)sd->sdos_info; - MFREE(sd->osh, sdos, sizeof(struct sdos_info)); -} - -/* Interrupt enable/disable */ -SDIOH_API_RC -sdioh_interrupt_set(sdioh_info_t *sd, bool enable) -{ - ulong flags; - struct sdos_info *sdos; - - sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); - - sdos = (struct sdos_info *)sd->sdos_info; - ASSERT(sdos); - - if (!(sd->host_init_done && sd->card_init_done)) { - sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { - sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - /* Ensure atomicity for enable/disable calls */ - spin_lock_irqsave(&sdos->lock, flags); - - sd->client_intr_enabled = enable; - if (enable && !sd->lockcount) - spi_devintr_on(sd); - else - spi_devintr_off(sd); - - spin_unlock_irqrestore(&sdos->lock, flags); - - return SDIOH_API_RC_SUCCESS; -} - -/* Protect against reentrancy (disable device interrupts while executing) */ -void -spi_lock(sdioh_info_t *sd) -{ - ulong flags; - struct sdos_info *sdos; - - sdos = (struct sdos_info *)sd->sdos_info; - ASSERT(sdos); - - sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount)); - - spin_lock_irqsave(&sdos->lock, flags); - if (sd->lockcount) { - sd_err(("%s: Already locked!\n", __FUNCTION__)); - ASSERT(sd->lockcount == 0); - } - spi_devintr_off(sd); - sd->lockcount++; - spin_unlock_irqrestore(&sdos->lock, flags); -} - -/* Enable client interrupt */ -void -spi_unlock(sdioh_info_t *sd) -{ - ulong flags; - struct sdos_info *sdos; - - sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled)); - ASSERT(sd->lockcount > 0); - - sdos = (struct sdos_info *)sd->sdos_info; - ASSERT(sdos); - - spin_lock_irqsave(&sdos->lock, flags); - if (--sd->lockcount == 0 && sd->client_intr_enabled) { - spi_devintr_on(sd); - } - spin_unlock_irqrestore(&sdos->lock, flags); -} - -void spi_waitbits(sdioh_info_t *sd, bool yield) -{ -#ifndef BCMSDYIELD - ASSERT(!yield); -#endif - sd_trace(("%s: yield %d canblock %d\n", - __FUNCTION__, yield, BLOCKABLE())); - - /* Clear the "interrupt happened" flag and last intrstatus */ - sd->got_hcint = FALSE; - -#ifdef BCMSDYIELD - if (yield && BLOCKABLE()) { - struct sdos_info *sdos; - sdos = (struct sdos_info *)sd->sdos_info; - /* Wait for the indication, the interrupt will be masked when the ISR fires. */ - wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint)); - } else -#endif /* BCMSDYIELD */ - { - spi_spinbits(sd); - } - -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c b/drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c deleted file mode 100755 index da16dccf71aa..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c +++ /dev/null @@ -1,1810 +0,0 @@ -/* - * Broadcom BCMSDH to gSPI Protocol Conversion Layer - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmspibrcm.c 373331 2012-12-07 04:46:22Z $ - */ - -#define HSMODE - -#include - -#include -#include -#include -#include -#include -#include -#include -#include /* SDIO device core hardware definitions. */ -#include - -#include /* bcmsdh to/from specific controller APIs */ -#include /* ioctl/iovars */ -#include /* SDIO Device and Protocol Specs */ - -#include - - -#include -#include - -/* these are for the older cores... for newer cores we have control for each of them */ -#define F0_RESPONSE_DELAY 16 -#define F1_RESPONSE_DELAY 16 -#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY - - -#define GSPI_F0_RESP_DELAY 0 -#define GSPI_F1_RESP_DELAY F1_RESPONSE_DELAY -#define GSPI_F2_RESP_DELAY 0 -#define GSPI_F3_RESP_DELAY 0 - -#define CMDLEN 4 - -#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE) - -/* Globals */ -#if defined(DHD_DEBUG) -uint sd_msglevel = SDH_ERROR_VAL; -#else -uint sd_msglevel = 0; -#endif - -uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ -uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ -uint sd_f2_blocksize = 64; /* Default blocksize */ - - -uint sd_divisor = 2; -uint sd_power = 1; /* Default to SD Slot powered ON */ -uint sd_clock = 1; /* Default to SD Clock turned ON */ -uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ -uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ - -uint8 spi_outbuf[SPI_MAX_PKT_LEN]; -uint8 spi_inbuf[SPI_MAX_PKT_LEN]; - -/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits - * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. - */ -#define BUF2_PKT_LEN 128 -uint8 spi_outbuf2[BUF2_PKT_LEN]; -uint8 spi_inbuf2[BUF2_PKT_LEN]; - -#define SPISWAP_WD4(x) bcmswap32(x); -#define SPISWAP_WD2(x) (bcmswap16(x & 0xffff)) | \ - (bcmswap16((x & 0xffff0000) >> 16) << 16); - -/* Prototypes */ -static bool bcmspi_test_card(sdioh_info_t *sd); -static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); -static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); -static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, - uint32 *data, uint32 datalen); -static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 *data); -static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 data); -static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, - uint8 *data); -static int bcmspi_driver_init(sdioh_info_t *sd); -static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, - uint32 addr, int nbytes, uint32 *data); -static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, - uint32 *data); -static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); -static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); - -/* - * Public entry points & extern's - */ -extern sdioh_info_t * -sdioh_attach(osl_t *osh, void *bar0, uint irq) -{ - sdioh_info_t *sd; - - sd_trace(("%s\n", __FUNCTION__)); - if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { - sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); - return NULL; - } - bzero((char *)sd, sizeof(sdioh_info_t)); - sd->osh = osh; - if (spi_osinit(sd) != 0) { - sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return NULL; - } - - sd->bar0 = bar0; - sd->irq = irq; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; - sd->intr_handler_valid = FALSE; - - /* Set defaults */ - sd->use_client_ints = TRUE; - sd->sd_use_dma = FALSE; /* DMA Not supported */ - - /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit - * mode - */ - sd->wordlen = 2; - - - if (!spi_hw_attach(sd)) { - sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - if (bcmspi_driver_init(sd) != SUCCESS) { - sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - if (spi_register_irq(sd, irq) != SUCCESS) { - sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - sd_trace(("%s: Done\n", __FUNCTION__)); - - return sd; -} - -extern SDIOH_API_RC -sdioh_detach(osl_t *osh, sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - if (sd) { - sd_err(("%s: detaching from hardware\n", __FUNCTION__)); - spi_free_irq(sd->irq, sd); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - } - return SDIOH_API_RC_SUCCESS; -} - -/* Configure callback to client when we recieve client interrupt */ -extern SDIOH_API_RC -sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); -#if !defined(OOB_INTR_ONLY) - sd->intr_handler = fn; - sd->intr_handler_arg = argh; - sd->intr_handler_valid = TRUE; -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_deregister(sdioh_info_t *sd) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); -#if !defined(OOB_INTR_ONLY) - sd->intr_handler_valid = FALSE; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - *onoff = sd->client_intr_enabled; - return SDIOH_API_RC_SUCCESS; -} - -#if defined(DHD_DEBUG) -extern bool -sdioh_interrupt_pending(sdioh_info_t *sd) -{ - return 0; -} -#endif - -extern SDIOH_API_RC -sdioh_query_device(sdioh_info_t *sd) -{ - /* Return a BRCM ID appropriate to the dongle class */ - return (sd->num_funcs > 1) ? BCM4329_D11N_ID : BCM4318_D11G_ID; -} - -/* Provide dstatus bits of spi-transaction for dhd layers. */ -extern uint32 -sdioh_get_dstatus(sdioh_info_t *sd) -{ - return sd->card_dstatus; -} - -extern void -sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) -{ - sd->chip = chip; - sd->chiprev = chiprev; -} - -extern void -sdioh_dwordmode(sdioh_info_t *sd, bool set) -{ - uint8 reg = 0; - int status; - - if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != - SUCCESS) { - sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); - return; - } - - if (set) { - reg |= DWORD_PKT_LEN_EN; - sd->dwordmode = TRUE; - sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ - } else { - reg &= ~DWORD_PKT_LEN_EN; - sd->dwordmode = FALSE; - sd->client_block_size[SPI_FUNC_2] = 2048; - } - - if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != - SUCCESS) { - sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); - return; - } -} - - -uint -sdioh_query_iofnum(sdioh_info_t *sd) -{ - return sd->num_funcs; -} - -/* IOVar table */ -enum { - IOV_MSGLEVEL = 1, - IOV_BLOCKMODE, - IOV_BLOCKSIZE, - IOV_DMA, - IOV_USEINTS, - IOV_NUMINTS, - IOV_NUMLOCALINTS, - IOV_HOSTREG, - IOV_DEVREG, - IOV_DIVISOR, - IOV_SDMODE, - IOV_HISPEED, - IOV_HCIREGS, - IOV_POWER, - IOV_CLOCK, - IOV_SPIERRSTATS, - IOV_RESP_DELAY_ALL -}; - -const bcm_iovar_t sdioh_iovars[] = { - {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, - {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ - {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, - {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, - {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, - {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, - {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, - {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, - {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, - {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, - {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, - {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, - {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -int -sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - int32 int_val = 0; - bool bool_val; - uint32 actionid; -/* - sdioh_regs_t *regs; -*/ - - ASSERT(name); - ASSERT(len >= 0); - - /* Get must have return space; Set does not take qualifiers */ - ASSERT(set || (arg && len)); - ASSERT(!set || (!params && !plen)); - - sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); - - if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) - goto exit; - - /* Set up params so get and set can share the convenience variables */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - val_size = sizeof(int); - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - switch (actionid) { - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)sd_msglevel; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): - sd_msglevel = int_val; - break; - - case IOV_GVAL(IOV_BLOCKSIZE): - if ((uint32)int_val > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - int_val = (int32)si->client_block_size[int_val]; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DMA): - int_val = (int32)si->sd_use_dma; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DMA): - si->sd_use_dma = (bool)int_val; - break; - - case IOV_GVAL(IOV_USEINTS): - int_val = (int32)si->use_client_ints; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_USEINTS): - break; - - case IOV_GVAL(IOV_DIVISOR): - int_val = (uint32)sd_divisor; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DIVISOR): - sd_divisor = int_val; - if (!spi_start_clock(si, (uint16)sd_divisor)) { - sd_err(("%s: set clock failed\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - } - break; - - case IOV_GVAL(IOV_POWER): - int_val = (uint32)sd_power; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POWER): - sd_power = int_val; - break; - - case IOV_GVAL(IOV_CLOCK): - int_val = (uint32)sd_clock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CLOCK): - sd_clock = int_val; - break; - - case IOV_GVAL(IOV_SDMODE): - int_val = (uint32)sd_sdmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDMODE): - sd_sdmode = int_val; - break; - - case IOV_GVAL(IOV_HISPEED): - int_val = (uint32)sd_hiok; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HISPEED): - sd_hiok = int_val; - - if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { - sd_err(("%s: Failed changing highspeed mode to %d.\n", - __FUNCTION__, sd_hiok)); - bcmerror = BCME_ERROR; - return ERROR; - } - break; - - case IOV_GVAL(IOV_NUMINTS): - int_val = (int32)si->intrcount; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_NUMLOCALINTS): - int_val = (int32)si->local_intrcount; - bcopy(&int_val, arg, val_size); - break; - case IOV_GVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data; - - if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - - int_val = (int)data; - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = (uint8)sd_ptr->value; - - if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - } - - - case IOV_GVAL(IOV_SPIERRSTATS): - { - bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); - break; - } - - case IOV_SVAL(IOV_SPIERRSTATS): - { - bzero(&si->spierrstats, sizeof(struct spierrstats_t)); - break; - } - - case IOV_GVAL(IOV_RESP_DELAY_ALL): - int_val = (int32)si->resp_delay_all; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RESP_DELAY_ALL): - si->resp_delay_all = (bool)int_val; - int_val = STATUS_ENABLE|INTR_WITH_STATUS; - if (si->resp_delay_all) - int_val |= RESP_DELAY_ALL; - else { - if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, - F1_RESPONSE_DELAY) != SUCCESS) { - sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - break; - } - } - - if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) - != SUCCESS) { - sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } -exit: - - return bcmerror; -} - -extern SDIOH_API_RC -sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - SDIOH_API_RC status; - /* No lock needed since sdioh_request_byte does locking */ - status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - /* No lock needed since sdioh_request_byte does locking */ - SDIOH_API_RC status; - - if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { - uint8 dummy_data; - status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); - if (status) { - sd_err(("sdioh_cfg_read() failed.\n")); - return status; - } - } - - status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) -{ - uint32 count; - int offset; - uint32 cis_byte; - uint16 *cis = (uint16 *)cisd; - uint bar0 = SI_ENUM_BASE; - int status; - uint8 data; - - sd_trace(("%s: Func %d\n", __FUNCTION__, func)); - - spi_lock(sd); - - /* Set sb window address to 0x18000000 */ - data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); - if (status == SUCCESS) { - data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); - } else { - sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - if (status == SUCCESS) { - data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); - } else { - sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - - offset = CC_SROM_OTP; /* OTP offset in chipcommon. */ - for (count = 0; count < length/2; count++) { - if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { - sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - - *cis = (uint16)cis_byte; - cis++; - offset += 2; - } - - spi_unlock(sd); - - return (BCME_OK); -} - -extern SDIOH_API_RC -sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) -{ - int status; - uint32 cmd_arg; - uint32 dstatus; - uint32 data = (uint32)(*byte); - - spi_lock(sd); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); - - if (rw == SDIOH_READ) { - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr)); - } else { - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, data)); - } - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) { - spi_unlock(sd); - return status; - } - - if (rw == SDIOH_READ) { - *byte = (uint8)data; - sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *byte)); - } - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus=0x%x\n", dstatus)); - - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, - uint32 *word, uint nbytes) -{ - int status; - - spi_lock(sd); - - if (rw == SDIOH_READ) - status = bcmspi_card_regread(sd, func, addr, nbytes, word); - else - status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); - - spi_unlock(sd); - return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -extern SDIOH_API_RC -sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, - uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) -{ - int len; - int buflen = (int)buflen_u; - bool fifo = (fix_inc == SDIOH_DATA_FIX); - - spi_lock(sd); - - ASSERT(reg_width == 4); - ASSERT(buflen_u < (1 << 30)); - ASSERT(sd->client_block_size[func]); - - sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", - __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', - buflen_u, sd->r_cnt, sd->t_cnt, pkt)); - - /* Break buffer down into blocksize chunks. */ - while (buflen > 0) { - len = MIN(sd->client_block_size[func], buflen); - if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { - sd_err(("%s: bcmspi_card_buf %s failed\n", - __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); - spi_unlock(sd); - return SDIOH_API_RC_FAIL; - } - buffer += len; - buflen -= len; - if (!fifo) - addr += len; - } - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. - * Its main aim is to have simpler spi writes rather than recursive writes. - * e.g. When there is a need to program response delay on the fly after detecting the SPI-func - * this call will allow to program the response delay. - */ -static int -bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) -{ - uint32 cmd_arg; - uint32 datalen = 1; - uint32 hostlen; - - cmd_arg = 0; - - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); - - sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); - - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - ASSERT(sd->wordlen == 4 || sd->wordlen == 2); - datalen = ROUNDUP(datalen, sd->wordlen); - - /* Start by copying command in the spi-outbuffer */ - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)spi_outbuf2 = SPISWAP_WD4(cmd_arg); - if (datalen & 0x3) - datalen += (4 - (datalen & 0x3)); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)spi_outbuf2 = SPISWAP_WD2(cmd_arg); - if (datalen & 0x1) - datalen++; - } else { - sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - /* for Write, put the data into the output buffer */ - if (datalen != 0) { - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD4(byte); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD2(byte); - } - } - - /* +4 for cmd, +4 for dstatus */ - hostlen = datalen + 8; - hostlen += (4 - (hostlen & 0x3)); - spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); - - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else { - sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - if (sd->card_dstatus) - sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); - - return (BCME_OK); -} - -/* Program the response delay corresponding to the spi function */ -static int -bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) -{ - if (sd->resp_delay_all == FALSE) - return (BCME_OK); - - if (sd->prev_fun == func) - return (BCME_OK); - - if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) - return (BCME_OK); - - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); - - /* Remember function for which to avoid reprogramming resp-delay in next iteration */ - sd->prev_fun = func; - - return (BCME_OK); - -} - -#define GSPI_RESYNC_PATTERN 0x0 - -/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. - * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is - * synchronised and all queued resuests are cancelled. - */ -static int -bcmspi_resync_f1(sdioh_info_t *sd) -{ - uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; - - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - ASSERT(sd->wordlen == 4 || sd->wordlen == 2); - datalen = ROUNDUP(datalen, sd->wordlen); - - /* Start by copying command in the spi-outbuffer */ - *(uint32 *)spi_outbuf2 = cmd_arg; - - /* for Write, put the data into the output buffer */ - *(uint32 *)&spi_outbuf2[CMDLEN] = data; - - /* +4 for cmd, +4 for dstatus */ - spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); - - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else { - sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - if (sd->card_dstatus) - sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); - - return (BCME_OK); -} - -uint32 dstatus_count = 0; - -static int -bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) -{ - uint32 dstatus = sd->card_dstatus; - struct spierrstats_t *spierrstats = &sd->spierrstats; - int err = SUCCESS; - - sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); - - /* Store dstatus of last few gSPI transactions */ - spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; - spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; - dstatus_count++; - - if (sd->card_init_done == FALSE) - return err; - - if (dstatus & STATUS_DATA_NOT_AVAILABLE) { - spierrstats->dna++; - sd_trace(("Read data not available on F1 addr = 0x%x\n", - GFIELD(cmd_arg, SPI_REG_ADDR))); - /* Clear dna bit */ - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); - } - - if (dstatus & STATUS_UNDERFLOW) { - spierrstats->rdunderflow++; - sd_err(("FIFO underflow happened due to current F2 read command.\n")); - } - - if (dstatus & STATUS_OVERFLOW) { - spierrstats->wroverflow++; - sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); - bcmspi_resync_f1(sd); - sd_err(("Recovering from F1 FIFO overflow.\n")); - } - - if (dstatus & STATUS_F2_INTR) { - spierrstats->f2interrupt++; - sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); - } - - if (dstatus & STATUS_F3_INTR) { - spierrstats->f3interrupt++; - sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); - } - - if (dstatus & STATUS_HOST_CMD_DATA_ERR) { - spierrstats->hostcmddataerr++; - sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); - } - - if (dstatus & STATUS_F2_PKT_AVAILABLE) { - spierrstats->f2pktavailable++; - sd_trace(("Packet is available/ready in F2 TX FIFO\n")); - sd_trace(("Packet length = %d\n", sd->dwordmode ? - ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : - ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); - } - - if (dstatus & STATUS_F3_PKT_AVAILABLE) { - spierrstats->f3pktavailable++; - sd_err(("Packet is available/ready in F3 TX FIFO\n")); - sd_err(("Packet length = %d\n", - (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); - } - - return err; -} - -extern int -sdioh_abort(sdioh_info_t *sd, uint func) -{ - return 0; -} - -int -sdioh_start(sdioh_info_t *sd, int stage) -{ - return SUCCESS; -} - -int -sdioh_stop(sdioh_info_t *sd) -{ - return SUCCESS; -} - -int -sdioh_waitlockfree(sdioh_info_t *sd) -{ - return SUCCESS; -} - - -/* - * Private/Static work routines - */ -static int -bcmspi_host_init(sdioh_info_t *sd) -{ - - /* Default power on mode */ - sd->sd_mode = SDIOH_MODE_SPI; - sd->polled_mode = TRUE; - sd->host_init_done = TRUE; - sd->card_init_done = FALSE; - sd->adapter_slot = 1; - - return (SUCCESS); -} - -static int -get_client_blocksize(sdioh_info_t *sd) -{ - uint32 regdata[2]; - int status; - - /* Find F1/F2/F3 max packet size */ - if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, - 8, regdata)) != SUCCESS) { - return status; - } - - sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", - regdata[0], regdata[1])); - - sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; - sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); - ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); - - sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; - sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); - ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); - - sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; - sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); - ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); - - return 0; -} - -static int -bcmspi_client_init(sdioh_info_t *sd) -{ - uint32 status_en_reg = 0; - sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); - -#ifdef HSMODE - if (!spi_start_clock(sd, (uint16)sd_divisor)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#else - /* Start at ~400KHz clock rate for initialization */ - if (!spi_start_clock(sd, 128)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#endif /* HSMODE */ - - if (!bcmspi_host_device_init_adapt(sd)) { - sd_err(("bcmspi_host_device_init_adapt failed\n")); - return ERROR; - } - - if (!bcmspi_test_card(sd)) { - sd_err(("bcmspi_test_card failed\n")); - return ERROR; - } - - sd->num_funcs = SPI_MAX_IOFUNCS; - - get_client_blocksize(sd); - - /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ - bcmspi_resync_f1(sd); - - sd->dwordmode = FALSE; - - bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); - - sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); - status_en_reg |= INTR_WITH_STATUS; - - if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, - status_en_reg & 0xff) != SUCCESS) { - sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); - return ERROR; - } - -#ifndef HSMODE - /* After configuring for High-Speed mode, set the desired clock rate. */ - if (!spi_start_clock(sd, 4)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#endif /* HSMODE */ - - /* check to see if the response delay needs to be programmed properly */ - { - uint32 f1_respdelay = 0; - bcmspi_card_regread(sd, 0, SPID_RESP_DELAY_F1, 1, &f1_respdelay); - if ((f1_respdelay == 0) || (f1_respdelay == 0xFF)) { - /* older sdiodevice core and has no separte resp delay for each of */ - sd_err(("older corerev < 4 so use the same resp delay for all funcs\n")); - sd->resp_delay_new = FALSE; - } - else { - /* older sdiodevice core and has no separte resp delay for each of */ - int ret_val; - sd->resp_delay_new = TRUE; - sd_err(("new corerev >= 4 so set the resp delay for each of the funcs\n")); - sd_trace(("resp delay for funcs f0(%d), f1(%d), f2(%d), f3(%d)\n", - GSPI_F0_RESP_DELAY, GSPI_F1_RESP_DELAY, - GSPI_F2_RESP_DELAY, GSPI_F3_RESP_DELAY)); - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F0, 1, - GSPI_F0_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F0\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F1, 1, - GSPI_F1_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F1\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F2, 1, - GSPI_F2_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F3, 1, - GSPI_F3_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); - return ERROR; - } - } - } - - - sd->card_init_done = TRUE; - - /* get the device rev to program the prop respdelays */ - - return SUCCESS; -} - -static int -bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) -{ - uint32 regdata; - int status; - - if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, - 4, ®data)) != SUCCESS) - return status; - - sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); - - - if (hsmode == TRUE) { - sd_trace(("Attempting to enable High-Speed mode.\n")); - - if (regdata & HIGH_SPEED_MODE) { - sd_trace(("Device is already in High-Speed mode.\n")); - return status; - } else { - regdata |= HIGH_SPEED_MODE; - sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); - if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, - 4, regdata)) != SUCCESS) { - return status; - } - } - } else { - sd_trace(("Attempting to disable High-Speed mode.\n")); - - if (regdata & HIGH_SPEED_MODE) { - regdata &= ~HIGH_SPEED_MODE; - sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); - if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, - 4, regdata)) != SUCCESS) - return status; - } - else { - sd_trace(("Device is already in Low-Speed mode.\n")); - return status; - } - } - spi_controller_highspeed_mode(sd, hsmode); - - return TRUE; -} - -#define bcmspi_find_curr_mode(sd) { \ - sd->wordlen = 2; \ - status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ - regdata &= 0xff; \ - if ((regdata == 0xad) || (regdata == 0x5b) || \ - (regdata == 0x5d) || (regdata == 0x5a)) \ - break; \ - sd->wordlen = 4; \ - status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ - regdata &= 0xff; \ - if ((regdata == 0xad) || (regdata == 0x5b) || \ - (regdata == 0x5d) || (regdata == 0x5a)) \ - break; \ - sd_trace(("Silicon testability issue: regdata = 0x%x." \ - " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ - OSL_DELAY(100000); \ -} - -#define INIT_ADAPT_LOOP 100 - -/* Adapt clock-phase-speed-bitwidth between host and device */ -static bool -bcmspi_host_device_init_adapt(sdioh_info_t *sd) -{ - uint32 wrregdata, regdata = 0; - int status; - int i; - - /* Due to a silicon testability issue, the first command from the Host - * to the device will get corrupted (first bit will be lost). So the - * Host should poll the device with a safe read request. ie: The Host - * should try to read F0 addr 0x14 using the Fixed address mode - * (This will prevent a unintended write command to be detected by device) - */ - for (i = 0; i < INIT_ADAPT_LOOP; i++) { - /* If device was not power-cycled it will stay in 32bit mode with - * response-delay-all bit set. Alternate the iteration so that - * read either with or without response-delay for F0 to succeed. - */ - bcmspi_find_curr_mode(sd); - sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; - - bcmspi_find_curr_mode(sd); - sd->dwordmode = TRUE; - - bcmspi_find_curr_mode(sd); - sd->dwordmode = FALSE; - } - - /* Bail out, device not detected */ - if (i == INIT_ADAPT_LOOP) - return FALSE; - - /* Softreset the spid logic */ - if ((sd->dwordmode) || (sd->wordlen == 4)) { - bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); - bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); - sd_trace(("reset reg read = 0x%x\n", regdata)); - sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, - sd->wordlen, sd->resp_delay_all)); - /* Restore default state after softreset */ - sd->wordlen = 2; - sd->dwordmode = FALSE; - } - - if (sd->wordlen == 4) { - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != - SUCCESS) - return FALSE; - if (regdata == TEST_RO_DATA_32BIT_LE) { - sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", - regdata)); - sd_trace(("Spid power was left on.\n")); - } else { - sd_err(("Spid power was left on but signature read failed." - " Value read = 0x%x\n", regdata)); - return FALSE; - } - } else { - sd->wordlen = 2; - -#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ - - wrregdata = (CTRL_REG_DEFAULT); - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); - -#ifndef HSMODE - wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); - wrregdata &= ~HIGH_SPEED_MODE; - bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); -#endif /* HSMODE */ - - for (i = 0; i < INIT_ADAPT_LOOP; i++) { - if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { - sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, - ®data)) != SUCCESS) - return FALSE; - } - OSL_DELAY(1000); - } - - /* Change to host controller intr-polarity of active-low */ - wrregdata &= ~INTR_POLARITY; - sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", - wrregdata)); - /* Change to 32bit mode */ - wrregdata |= WORD_LENGTH_32; - bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); - - /* Change command/data packaging in 32bit LE mode */ - sd->wordlen = 4; - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - - if (regdata == TEST_RO_DATA_32BIT_LE) { - sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); - sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); - } else { - sd_err(("Stale spid reg values read as it was kept powered. Value read =" - "0x%x\n", regdata)); - return FALSE; - } - } - - - return TRUE; -} - -static bool -bcmspi_test_card(sdioh_info_t *sd) -{ - uint32 regdata; - int status; - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - - if (regdata == (TEST_RO_DATA_32BIT_LE)) - sd_trace(("32bit LE regdata = 0x%x\n", regdata)); - else { - sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); - return FALSE; - } - - -#define RW_PATTERN1 0xA0A1A2A3 -#define RW_PATTERN2 0x4B5B6B7B - - regdata = RW_PATTERN1; - if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) - return FALSE; - regdata = 0; - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) - return FALSE; - if (regdata != RW_PATTERN1) { - sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", - RW_PATTERN1, regdata)); - return FALSE; - } else - sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); - - regdata = RW_PATTERN2; - if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) - return FALSE; - regdata = 0; - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) - return FALSE; - if (regdata != RW_PATTERN2) { - sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", - RW_PATTERN2, regdata)); - return FALSE; - } else - sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); - - return TRUE; -} - -static int -bcmspi_driver_init(sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - if ((bcmspi_host_init(sd)) != SUCCESS) { - return ERROR; - } - - if (bcmspi_client_init(sd) != SUCCESS) { - return ERROR; - } - - return SUCCESS; -} - -/* Read device reg */ -static int -bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - int status; - uint32 cmd_arg, dstatus; - - ASSERT(regsize); - - if (func == 2) - sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); - - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus =0x%x\n", dstatus)); - - return SUCCESS; -} - -static int -bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - - int status; - uint32 cmd_arg; - uint32 dstatus; - - ASSERT(regsize); - - if (func == 2) - sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); - - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) - return status; - - sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *data)); - - bcmspi_cmd_getdstatus(sd, &dstatus); - sd_trace(("dstatus =0x%x\n", dstatus)); - return SUCCESS; -} - -/* write a device register */ -static int -bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) -{ - int status; - uint32 cmd_arg, dstatus; - - ASSERT(regsize); - - cmd_arg = 0; - - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); - - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize, data)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus=0x%x\n", dstatus)); - - return SUCCESS; -} - -/* write a device register - 1 byte */ -static int -bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) -{ - int status; - uint32 cmd_arg; - uint32 dstatus; - uint32 data = (uint32)(*byte); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); - - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, data)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus =0x%x\n", dstatus)); - - return SUCCESS; -} - -void -bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) -{ - *dstatus_buffer = sd->card_dstatus; -} - -/* 'data' is of type uint32 whereas other buffers are of type uint8 */ -static int -bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, - uint32 *data, uint32 datalen) -{ - uint32 i, j; - uint8 resp_delay = 0; - int err = SUCCESS; - uint32 hostlen; - uint32 spilen = 0; - uint32 dstatus_idx = 0; - uint16 templen, buslen, len, *ptr = NULL; - - sd_trace(("spi cmd = 0x%x\n", cmd_arg)); - - if (DWORDMODE_ON) { - spilen = GFIELD(cmd_arg, SPI_LEN); - if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) || - (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1)) - dstatus_idx = spilen * 3; - - if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && - (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { - spilen = spilen << 2; - dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0; - /* convert len to mod16 size */ - spilen = ROUNDUP(spilen, 16); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); - } - } - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)spi_outbuf = SPISWAP_WD4(cmd_arg); - if (datalen & 0x3) - datalen += (4 - (datalen & 0x3)); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)spi_outbuf = SPISWAP_WD2(cmd_arg); - if (datalen & 0x1) - datalen++; - if (datalen < 4) - datalen = ROUNDUP(datalen, 4); - } else { - sd_err(("Host is %d bit spid, could not create SPI command.\n", - 8 * sd->wordlen)); - return ERROR; - } - - /* for Write, put the data into the output buffer */ - if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { - /* We send len field of hw-header always a mod16 size, both from host and dongle */ - if (DWORDMODE_ON) { - if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) { - ptr = (uint16 *)&data[0]; - templen = *ptr; - /* ASSERT(*ptr == ~*(ptr + 1)); */ - templen = ROUNDUP(templen, 16); - *ptr = templen; - sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1)))); - } - } - - if (datalen != 0) { - for (i = 0; i < datalen/4; i++) { - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = - SPISWAP_WD4(data[i]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = - SPISWAP_WD2(data[i]); - } - } - } - } - - /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ - if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 0)) { - int func = GFIELD(cmd_arg, SPI_FUNCTION); - switch (func) { - case 0: - if (sd->resp_delay_new) - resp_delay = GSPI_F0_RESP_DELAY; - else - resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; - break; - case 1: - if (sd->resp_delay_new) - resp_delay = GSPI_F1_RESP_DELAY; - else - resp_delay = F1_RESPONSE_DELAY; - break; - case 2: - if (sd->resp_delay_new) - resp_delay = GSPI_F2_RESP_DELAY; - else - resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; - break; - default: - ASSERT(0); - break; - } - /* Program response delay */ - if (sd->resp_delay_new == FALSE) - bcmspi_prog_resp_delay(sd, func, resp_delay); - } - - /* +4 for cmd and +4 for dstatus */ - hostlen = datalen + 8 + resp_delay; - hostlen += dstatus_idx; - hostlen += (4 - (hostlen & 0x3)); - spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); - - /* for Read, get the data into the input buffer */ - if (datalen != 0) { - if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ - for (j = 0; j < datalen/4; j++) { - if (sd->wordlen == 4) { /* 32bit spid */ - data[j] = SPISWAP_WD4(*(uint32 *)&spi_inbuf[j * 4 + - CMDLEN + resp_delay]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - data[j] = SPISWAP_WD2(*(uint32 *)&spi_inbuf[j * 4 + - CMDLEN + resp_delay]); - } - } - - if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { - ptr = (uint16 *)&data[0]; - templen = *ptr; - buslen = len = ~(*(ptr + 1)); - buslen = ROUNDUP(buslen, 16); - /* populate actual len in hw-header */ - if (templen == buslen) - *ptr = len; - } - } - } - - /* Restore back the len field of the hw header */ - if (DWORDMODE_ON) { - if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && - (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { - ptr = (uint16 *)&data[0]; - *ptr = (uint16)(~*(ptr+1)); - } - } - - dstatus_idx += (datalen + CMDLEN + resp_delay); - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf[dstatus_idx]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf[dstatus_idx]); - } else { - sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", - 8 * sd->wordlen)); - return ERROR; - } - if (sd->card_dstatus == 0xffffffff) { - sd_err(("looks like not a GSPI device or device is not powered.\n")); - } - - err = bcmspi_update_stats(sd, cmd_arg); - - return err; - -} - -static int -bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, - uint32 addr, int nbytes, uint32 *data) -{ - int status; - uint32 cmd_arg; - bool write = rw == SDIOH_READ ? 0 : 1; - uint retries = 0; - - bool enable; - uint32 spilen; - - cmd_arg = 0; - - ASSERT(nbytes); - ASSERT(nbytes <= sd->client_block_size[func]); - - if (write) sd->t_cnt++; else sd->r_cnt++; - - if (func == 2) { - /* Frame len check limited by gSPI. */ - if ((nbytes > 2000) && write) { - sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); - } - /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ - /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ - if (write) { - uint32 dstatus; - /* check F2 ready with cached one */ - bcmspi_cmd_getdstatus(sd, &dstatus); - if ((dstatus & STATUS_F2_RX_READY) == 0) { - retries = WAIT_F2RXFIFORDY; - enable = 0; - while (retries-- && !enable) { - OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); - bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, - &dstatus); - if (dstatus & STATUS_F2_RX_READY) - enable = TRUE; - } - if (!enable) { - struct spierrstats_t *spierrstats = &sd->spierrstats; - spierrstats->f2rxnotready++; - sd_err(("F2 FIFO is not ready to receive data.\n")); - return ERROR; - } - sd_trace(("No of retries on F2 ready %d\n", - (WAIT_F2RXFIFORDY - retries))); - } - } - } - - /* F2 transfers happen on 0 addr */ - addr = (func == 2) ? 0 : addr; - - /* In pio mode buffer is read using fixed address fifo in func 1 */ - if ((func == 1) && (fifo)) - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); - else - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); - - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); - spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); - if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { - /* convert len to mod4 size */ - spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); - } else - cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); - - if ((func == 2) && (fifo == 1)) { - sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - } - - sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); - sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, nbytes)) != SUCCESS) { - sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, - (write ? "write" : "read"))); - return status; - } - - /* gSPI expects that hw-header-len is equal to spi-command-len */ - if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { - ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); - ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); - } - - if ((nbytes > 2000) && !write) { - sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); - } - - return SUCCESS; -} - -/* Reset and re-initialize the device */ -int -sdioh_sdio_reset(sdioh_info_t *si) -{ - si->card_init_done = FALSE; - return bcmspi_client_init(si); -} - -SDIOH_API_RC -sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) -{ - return SDIOH_API_RC_FAIL; -} - -SDIOH_API_RC -sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) -{ - return SDIOH_API_RC_FAIL; -} - -bool -sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) -{ - return FALSE; -} - -SDIOH_API_RC -sdioh_gpio_init(sdioh_info_t *sd) -{ - return SDIOH_API_RC_FAIL; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmutils.c b/drivers/net/wireless/bcmdhd_suzuran/bcmutils.c deleted file mode 100755 index 0f1631300f95..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmutils.c +++ /dev/null @@ -1,3092 +0,0 @@ -/* - * Driver O/S-independent utility routines - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmutils.c 701450 2017-05-25 02:10:23Z $ - */ - -#include -#include -#include -#include -#ifdef BCMDRIVER - -#include -#include - -#else /* !BCMDRIVER */ - -#include -#include -#include - -#if defined(BCMEXTSUP) -#include -#endif - -#ifndef ASSERT -#define ASSERT(exp) -#endif - -#endif /* !BCMDRIVER */ - -#include -#include -#include -#include -#include -#include -#include - - -void *_bcmutils_dummy_fn = NULL; - - - -#ifdef BCMDRIVER - - - -/* copy a pkt buffer chain into a buffer */ -uint -pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) -{ - uint n, ret = 0; - - if (len < 0) - len = 4096; /* "infinite" */ - - /* skip 'offset' bytes */ - for (; p && offset; p = PKTNEXT(osh, p)) { - if (offset < (uint)PKTLEN(osh, p)) - break; - offset -= PKTLEN(osh, p); - } - - if (!p) - return 0; - - /* copy the data */ - for (; p && len; p = PKTNEXT(osh, p)) { - n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); - bcopy(PKTDATA(osh, p) + offset, buf, n); - buf += n; - len -= n; - ret += n; - offset = 0; - } - - return ret; -} - -/* copy a buffer into a pkt buffer chain */ -uint -pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) -{ - uint n, ret = 0; - - - /* skip 'offset' bytes */ - for (; p && offset; p = PKTNEXT(osh, p)) { - if (offset < (uint)PKTLEN(osh, p)) - break; - offset -= PKTLEN(osh, p); - } - - if (!p) - return 0; - - /* copy the data */ - for (; p && len; p = PKTNEXT(osh, p)) { - n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); - bcopy(buf, PKTDATA(osh, p) + offset, n); - buf += n; - len -= n; - ret += n; - offset = 0; - } - - return ret; -} - - - -/* return total length of buffer chain */ -uint BCMFASTPATH -pkttotlen(osl_t *osh, void *p) -{ - uint total; - int len; - - total = 0; - for (; p; p = PKTNEXT(osh, p)) { - len = PKTLEN(osh, p); - total += len; -#ifdef BCMLFRAG - if (BCMLFRAG_ENAB()) { - if (PKTISFRAG(osh, p)) { - total += PKTFRAGTOTLEN(osh, p); - } - } -#endif - } - - return (total); -} - -/* return the last buffer of chained pkt */ -void * -pktlast(osl_t *osh, void *p) -{ - for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) - ; - - return (p); -} - -/* count segments of a chained packet */ -uint BCMFASTPATH -pktsegcnt(osl_t *osh, void *p) -{ - uint cnt; - - for (cnt = 0; p; p = PKTNEXT(osh, p)) { - cnt++; -#ifdef BCMLFRAG - if (BCMLFRAG_ENAB()) { - if (PKTISFRAG(osh, p)) { - cnt += PKTFRAGTOTNUM(osh, p); - } - } -#endif - } - - return cnt; -} - - -/* count segments of a chained packet */ -uint BCMFASTPATH -pktsegcnt_war(osl_t *osh, void *p) -{ - uint cnt; - uint8 *pktdata; - uint len, remain, align64; - - for (cnt = 0; p; p = PKTNEXT(osh, p)) { - cnt++; - len = PKTLEN(osh, p); - if (len > 128) { - pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ - /* Check for page boundary straddle (2048B) */ - if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) - cnt++; - - align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ - align64 = (64 - align64) & 0x3f; - len -= align64; /* bytes from aligned 64B to end */ - /* if aligned to 128B, check for MOD 128 between 1 to 4B */ - remain = len % 128; - if (remain > 0 && remain <= 4) - cnt++; /* add extra seg */ - } - } - - return cnt; -} - -uint8 * BCMFASTPATH -pktdataoffset(osl_t *osh, void *p, uint offset) -{ - uint total = pkttotlen(osh, p); - uint pkt_off = 0, len = 0; - uint8 *pdata = (uint8 *) PKTDATA(osh, p); - - if (offset > total) - return NULL; - - for (; p; p = PKTNEXT(osh, p)) { - pdata = (uint8 *) PKTDATA(osh, p); - pkt_off = offset - len; - len += PKTLEN(osh, p); - if (len > offset) - break; - } - return (uint8*) (pdata+pkt_off); -} - - -/* given a offset in pdata, find the pkt seg hdr */ -void * -pktoffset(osl_t *osh, void *p, uint offset) -{ - uint total = pkttotlen(osh, p); - uint len = 0; - - if (offset > total) - return NULL; - - for (; p; p = PKTNEXT(osh, p)) { - len += PKTLEN(osh, p); - if (len > offset) - break; - } - return p; -} - -/* - * osl multiple-precedence packet queue - * hi_prec is always >= the number of the highest non-empty precedence - */ -void * BCMFASTPATH -pktq_penq(struct pktq *pq, int prec, void *p) -{ - struct pktq_prec *q; - - ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ - - ASSERT(!pktq_full(pq)); - ASSERT(!pktq_pfull(pq, prec)); - - q = &pq->q[prec]; - - if (q->head) - PKTSETLINK(q->tail, p); - else - q->head = p; - - q->tail = p; - q->len++; - - pq->len++; - - if (pq->hi_prec < prec) - pq->hi_prec = (uint8)prec; - - return p; -} - -void * BCMFASTPATH -pktq_penq_head(struct pktq *pq, int prec, void *p) -{ - struct pktq_prec *q; - - ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ - - ASSERT(!pktq_full(pq)); - ASSERT(!pktq_pfull(pq, prec)); - - q = &pq->q[prec]; - - if (q->head == NULL) - q->tail = p; - - PKTSETLINK(p, q->head); - q->head = p; - q->len++; - - pq->len++; - - if (pq->hi_prec < prec) - pq->hi_prec = (uint8)prec; - - return p; -} - -void * BCMFASTPATH -pktq_pdeq(struct pktq *pq, int prec) -{ - struct pktq_prec *q; - void *p; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - if ((q->head = PKTLINK(p)) == NULL) - q->tail = NULL; - - q->len--; - - pq->len--; - - PKTSETLINK(p, NULL); - - return p; -} - -void * BCMFASTPATH -pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) -{ - struct pktq_prec *q; - void *p; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - - if (prev_p == NULL) - return NULL; - - if ((p = PKTLINK(prev_p)) == NULL) - return NULL; - - q->len--; - - pq->len--; - - PKTSETLINK(prev_p, PKTLINK(p)); - PKTSETLINK(p, NULL); - - return p; -} - -void * BCMFASTPATH -pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg) -{ - struct pktq_prec *q; - void *p, *prev = NULL; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - p = q->head; - - while (p) { - if (fn == NULL || (*fn)(p, arg)) { - break; - } else { - prev = p; - p = PKTLINK(p); - } - } - if (p == NULL) - return NULL; - - if (prev == NULL) { - if ((q->head = PKTLINK(p)) == NULL) { - q->tail = NULL; - } - } else { - PKTSETLINK(prev, PKTLINK(p)); - if (q->tail == p) { - q->tail = prev; - } - } - - q->len--; - - pq->len--; - - PKTSETLINK(p, NULL); - - return p; -} - -void * BCMFASTPATH -pktq_pdeq_tail(struct pktq *pq, int prec) -{ - struct pktq_prec *q; - void *p, *prev; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - for (prev = NULL; p != q->tail; p = PKTLINK(p)) - prev = p; - - if (prev) - PKTSETLINK(prev, NULL); - else - q->head = NULL; - - q->tail = prev; - q->len--; - - pq->len--; - - return p; -} - -void -pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) -{ - struct pktq_prec *q; - void *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 = PKTLINK(p); - else - PKTSETLINK(prev, PKTLINK(p)); - PKTSETLINK(p, NULL); - PKTFREE(osh, p, dir); - q->len--; - pq->len--; - p = (head ? q->head : PKTLINK(prev)); - } else { - prev = p; - p = PKTLINK(p); - } - } - - if (q->head == NULL) { - ASSERT(q->len == 0); - q->tail = NULL; - } -} - -bool BCMFASTPATH -pktq_pdel(struct pktq *pq, void *pktbuf, int prec) -{ - struct pktq_prec *q; - void *p; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - if (!pktbuf) - return FALSE; - - q = &pq->q[prec]; - - if (q->head == pktbuf) { - if ((q->head = PKTLINK(pktbuf)) == NULL) - q->tail = NULL; - } else { - for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) - ; - if (p == NULL) - return FALSE; - - PKTSETLINK(p, PKTLINK(pktbuf)); - if (q->tail == pktbuf) - q->tail = p; - } - - q->len--; - pq->len--; - PKTSETLINK(pktbuf, NULL); - return TRUE; -} - -void -pktq_init(struct pktq *pq, int num_prec, int max_len) -{ - int prec; - - ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); - - /* pq is variable size; only zero out what's requested */ - bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); - - pq->num_prec = (uint16)num_prec; - - pq->max = (uint16)max_len; - - for (prec = 0; prec < num_prec; prec++) - pq->q[prec].max = pq->max; -} - -void -pktq_set_max_plen(struct pktq *pq, int prec, int max_len) -{ - ASSERT(prec >= 0 && prec < pq->num_prec); - - if (prec < pq->num_prec) - pq->q[prec].max = (uint16)max_len; -} - -void * BCMFASTPATH -pktq_deq(struct pktq *pq, int *prec_out) -{ - struct pktq_prec *q; - void *p; - int prec; - - if (pq->len == 0) - return NULL; - - while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) - pq->hi_prec--; - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - if ((q->head = PKTLINK(p)) == NULL) - q->tail = NULL; - - q->len--; - - pq->len--; - - if (prec_out) - *prec_out = prec; - - PKTSETLINK(p, NULL); - - return p; -} - -void * BCMFASTPATH -pktq_deq_tail(struct pktq *pq, int *prec_out) -{ - struct pktq_prec *q; - void *p, *prev; - int prec; - - if (pq->len == 0) - return NULL; - - for (prec = 0; prec < pq->hi_prec; prec++) - if (pq->q[prec].head) - break; - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - for (prev = NULL; p != q->tail; p = PKTLINK(p)) - prev = p; - - if (prev) - PKTSETLINK(prev, NULL); - else - q->head = NULL; - - q->tail = prev; - q->len--; - - pq->len--; - - if (prec_out) - *prec_out = prec; - - PKTSETLINK(p, NULL); - - return p; -} - -void * -pktq_peek(struct pktq *pq, int *prec_out) -{ - int prec; - - if (pq->len == 0) - return NULL; - - while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) - pq->hi_prec--; - - if (prec_out) - *prec_out = prec; - - return (pq->q[prec].head); -} - -void * -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); -} - -void -pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) -{ - int prec; - - /* Optimize flush, if pktq len = 0, just return. - * pktq len of 0 means pktq's prec q's are all empty. - */ - if (pq->len == 0) { - return; - } - - for (prec = 0; prec < pq->num_prec; prec++) - pktq_pflush(osh, pq, prec, dir, fn, arg); - if (fn == NULL) - ASSERT(pq->len == 0); -} - -/* Return sum of lengths of a specific set of precedences */ -int -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; -} - -/* Priority peek from a specific set of precedences */ -void * BCMFASTPATH -pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) -{ - struct pktq_prec *q; - void *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]; - - if ((p = q->head) == NULL) - return NULL; - - if (prec_out) - *prec_out = prec; - - return p; -} -/* Priority dequeue from a specific set of precedences */ -void * BCMFASTPATH -pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) -{ - struct pktq_prec *q; - void *p; - int prec; - - if (pq->len == 0) - return NULL; - - while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) - pq->hi_prec--; - - while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) - if (prec-- == 0) - return NULL; - - q = &pq->q[prec]; - - if ((p = q->head) == NULL) - return NULL; - - if ((q->head = PKTLINK(p)) == NULL) - q->tail = NULL; - - q->len--; - - if (prec_out) - *prec_out = prec; - - pq->len--; - - PKTSETLINK(p, NULL); - - return p; -} - -#endif /* BCMDRIVER */ - -#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) -const unsigned char bcm_ctype[] = { - - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ - _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, - _BCM_C, /* 8-15 */ - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ - _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ - _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ - _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ - _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ - _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, - _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ - _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, - _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ - _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ - _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ - _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ - _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ -}; - -ulong -bcm_strtoul(const char *cp, char **endp, uint base) -{ - ulong result, last_result = 0, value; - bool minus; - - minus = FALSE; - - while (bcm_isspace(*cp)) - cp++; - - if (cp[0] == '+') - cp++; - else if (cp[0] == '-') { - minus = TRUE; - cp++; - } - - if (base == 0) { - if (cp[0] == '0') { - if ((cp[1] == 'x') || (cp[1] == 'X')) { - base = 16; - cp = &cp[2]; - } else { - base = 8; - cp = &cp[1]; - } - } else - base = 10; - } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { - cp = &cp[2]; - } - - result = 0; - - while (bcm_isxdigit(*cp) && - (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { - result = result*base + value; - /* Detected overflow */ - if (result < last_result && !minus) - return (ulong)-1; - last_result = result; - cp++; - } - - if (minus) - result = (ulong)(-(long)result); - - if (endp) - *endp = DISCARD_QUAL(cp, char); - - return (result); -} - -int -bcm_atoi(const char *s) -{ - return (int)bcm_strtoul(s, NULL, 10); -} - -/* return pointer to location of substring 'needle' in 'haystack' */ -char * -bcmstrstr(const char *haystack, const char *needle) -{ - int len, nlen; - int i; - - if ((haystack == NULL) || (needle == NULL)) - return DISCARD_QUAL(haystack, char); - - nlen = strlen(needle); - len = strlen(haystack) - nlen + 1; - - for (i = 0; i < len; i++) - if (memcmp(needle, &haystack[i], nlen) == 0) - return DISCARD_QUAL(&haystack[i], char); - return (NULL); -} - -char * -bcmstrcat(char *dest, const char *src) -{ - char *p; - - p = dest + strlen(dest); - - while ((*p++ = *src++) != '\0') - ; - - return (dest); -} - -char * -bcmstrncat(char *dest, const char *src, uint size) -{ - char *endp; - char *p; - - p = dest + strlen(dest); - endp = p + size; - - while (p != endp && (*p++ = *src++) != '\0') - ; - - return (dest); -} - - -/**************************************************************************** -* Function: bcmstrtok -* -* Purpose: -* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), -* but allows strToken() to be used by different strings or callers at the same -* time. Each call modifies '*string' by substituting a NULL character for the -* first delimiter that is encountered, and updates 'string' to point to the char -* after the delimiter. Leading delimiters are skipped. -* -* Parameters: -* string (mod) Ptr to string ptr, updated by token. -* delimiters (in) Set of delimiter characters. -* tokdelim (out) Character that delimits the returned token. (May -* be set to NULL if token delimiter is not required). -* -* Returns: Pointer to the next token found. NULL when no more tokens are found. -***************************************************************************** -*/ -char * -bcmstrtok(char **string, const char *delimiters, char *tokdelim) -{ - unsigned char *str; - unsigned long map[8]; - int count; - char *nextoken; - - if (tokdelim != NULL) { - /* Prime the token delimiter */ - *tokdelim = '\0'; - } - - /* Clear control map */ - for (count = 0; count < 8; count++) { - map[count] = 0; - } - - /* Set bits in delimiter table */ - do { - map[*delimiters >> 5] |= (1 << (*delimiters & 31)); - } - while (*delimiters++); - - str = (unsigned char*)*string; - - /* Find beginning of token (skip over leading delimiters). Note that - * there is no token iff this loop sets str to point to the terminal - * null (*str == '\0') - */ - while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { - str++; - } - - nextoken = (char*)str; - - /* Find the end of the token. If it is not the end of the string, - * put a null there. - */ - for (; *str; str++) { - if (map[*str >> 5] & (1 << (*str & 31))) { - if (tokdelim != NULL) { - *tokdelim = *str; - } - - *str++ = '\0'; - break; - } - } - - *string = (char*)str; - - /* Determine if a token has been found. */ - if (nextoken == (char *) str) { - return NULL; - } - else { - return nextoken; - } -} - - -#define xToLower(C) \ - ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) - - -/**************************************************************************** -* Function: bcmstricmp -* -* Purpose: Compare to strings case insensitively. -* -* Parameters: s1 (in) First string to compare. -* s2 (in) Second string to compare. -* -* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if -* t1 > t2, when ignoring case sensitivity. -***************************************************************************** -*/ -int -bcmstricmp(const char *s1, const char *s2) -{ - char dc, sc; - - while (*s2 && *s1) { - dc = xToLower(*s1); - sc = xToLower(*s2); - if (dc < sc) return -1; - if (dc > sc) return 1; - s1++; - s2++; - } - - if (*s1 && !*s2) return 1; - if (!*s1 && *s2) return -1; - return 0; -} - - -/**************************************************************************** -* Function: bcmstrnicmp -* -* Purpose: Compare to strings case insensitively, upto a max of 'cnt' -* characters. -* -* Parameters: s1 (in) First string to compare. -* s2 (in) Second string to compare. -* cnt (in) Max characters to compare. -* -* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if -* t1 > t2, when ignoring case sensitivity. -***************************************************************************** -*/ -int -bcmstrnicmp(const char* s1, const char* s2, int cnt) -{ - char dc, sc; - - while (*s2 && *s1 && cnt) { - dc = xToLower(*s1); - sc = xToLower(*s2); - if (dc < sc) return -1; - if (dc > sc) return 1; - s1++; - s2++; - cnt--; - } - - if (!cnt) return 0; - if (*s1 && !*s2) return 1; - if (!*s1 && *s2) return -1; - return 0; -} - -/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ -int -bcm_ether_atoe(const char *p, struct ether_addr *ea) -{ - int i = 0; - char *ep; - - for (;;) { - ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); - p = ep; - if (!*p++ || i == 6) - break; - } - - return (i == 6); -} - -int -bcm_atoipv4(const char *p, struct ipv4_addr *ip) -{ - - int i = 0; - char *c; - for (;;) { - ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0); - if (*c++ != '.' || i == IPV4_ADDR_LEN) - break; - p = c; - } - return (i == IPV4_ADDR_LEN); -} -#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ - - -#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) -/* registry routine buffer preparation utility functions: - * parameter order is like strncpy, but returns count - * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) - */ -ulong -wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) -{ - ulong copyct = 1; - ushort i; - - if (abuflen == 0) - return 0; - - /* wbuflen is in bytes */ - wbuflen /= sizeof(ushort); - - for (i = 0; i < wbuflen; ++i) { - if (--abuflen == 0) - break; - *abuf++ = (char) *wbuf++; - ++copyct; - } - *abuf = '\0'; - - return copyct; -} -#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ - -char * -bcm_ether_ntoa(const struct ether_addr *ea, char *buf) -{ - static const char hex[] = - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - const uint8 *octet = ea->octet; - char *p = buf; - int i; - - for (i = 0; i < 6; i++, octet++) { - *p++ = hex[(*octet >> 4) & 0xf]; - *p++ = hex[*octet & 0xf]; - *p++ = ':'; - } - - *(p-1) = '\0'; - - return (buf); -} - -char * -bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) -{ - snprintf(buf, 16, "%d.%d.%d.%d", - ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); - return (buf); -} - -char * -bcm_ipv6_ntoa(void *ipv6, char *buf) -{ - /* Implementing RFC 5952 Sections 4 + 5 */ - /* Not thoroughly tested */ - uint16 tmp[8]; - uint16 *a = &tmp[0]; - char *p = buf; - int i, i_max = -1, cnt = 0, cnt_max = 1; - uint8 *a4 = NULL; - memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN); - - for (i = 0; i < IPV6_ADDR_LEN/2; i++) { - if (a[i]) { - if (cnt > cnt_max) { - cnt_max = cnt; - i_max = i - cnt; - } - cnt = 0; - } else - cnt++; - } - if (cnt > cnt_max) { - cnt_max = cnt; - i_max = i - cnt; - } - if (i_max == 0 && - /* IPv4-translated: ::ffff:0:a.b.c.d */ - ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || - /* IPv4-mapped: ::ffff:a.b.c.d */ - (cnt_max == 5 && a[5] == 0xffff))) - a4 = (uint8*) (a + 6); - - for (i = 0; i < IPV6_ADDR_LEN/2; i++) { - if ((uint8*) (a + i) == a4) { - snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); - break; - } else if (i == i_max) { - *p++ = ':'; - i += cnt_max - 1; - p[0] = ':'; - p[1] = '\0'; - } else { - if (i) - *p++ = ':'; - p += snprintf(p, 8, "%x", ntoh16(a[i])); - } - } - - return buf; -} -#ifdef BCMDRIVER - -void -bcm_mdelay(uint ms) -{ - uint i; - - for (i = 0; i < ms; i++) { - OSL_DELAY(1000); - } -} - - - - - -#if defined(DHD_DEBUG) -/* pretty hex print a pkt buffer chain */ -void -prpkt(const char *msg, osl_t *osh, void *p0) -{ - void *p; - - if (msg && (msg[0] != '\0')) - printf("%s:\n", msg); - - for (p = p0; p; p = PKTNEXT(osh, p)) - prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); -} -#endif - -/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. - * Also updates the inplace vlan tag if requested. - * For debugging, it returns an indication of what it did. - */ -uint BCMFASTPATH -pktsetprio(void *pkt, bool update_vtag) -{ - struct ether_header *eh; - struct ethervlan_header *evh; - uint8 *pktdata; - int priority = 0; - int rc = 0; - - pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); - ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); - - eh = (struct ether_header *) pktdata; - - if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { - uint16 vlan_tag; - int vlan_prio, dscp_prio = 0; - - evh = (struct ethervlan_header *)eh; - - vlan_tag = ntoh16(evh->vlan_tag); - vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; - - if (evh->ether_type == hton16(ETHER_TYPE_IP)) { - uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); - uint8 tos_tc = IP_TOS46(ip_body); - dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); - } - - /* DSCP priority gets precedence over 802.1P (vlan tag) */ - if (dscp_prio != 0) { - priority = dscp_prio; - rc |= PKTPRIO_VDSCP; - } else { - priority = vlan_prio; - rc |= PKTPRIO_VLAN; - } - /* - * If the DSCP priority is not the same as the VLAN priority, - * then overwrite the priority field in the vlan tag, with the - * DSCP priority value. This is required for Linux APs because - * the VLAN driver on Linux, overwrites the skb->priority field - * with the priority value in the vlan tag - */ - if (update_vtag && (priority != vlan_prio)) { - vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); - vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; - evh->vlan_tag = hton16(vlan_tag); - rc |= PKTPRIO_UPD; - } -#ifdef DHD_LOSSLESS_ROAMING - } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { - priority = PRIO_8021D_NC; - rc = PKTPRIO_DSCP; -#endif /* DHD_LOSSLESS_ROAMING */ - } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) { - uint8 *ip_body = pktdata + sizeof(struct ether_header); - uint8 tos_tc = IP_TOS46(ip_body); - uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; - switch (dscp) { - case DSCP_EF: - priority = PRIO_8021D_VO; - break; - case DSCP_AF31: - case DSCP_AF32: - case DSCP_AF33: - priority = PRIO_8021D_CL; - break; - case DSCP_AF21: - case DSCP_AF22: - case DSCP_AF23: - case DSCP_AF11: - case DSCP_AF12: - case DSCP_AF13: - priority = PRIO_8021D_EE; - break; - default: - priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); - break; - } - - rc |= PKTPRIO_DSCP; - } - - ASSERT(priority >= 0 && priority <= MAXPRIO); - PKTSETPRIO(pkt, priority); - return (rc | priority); -} - - -static char bcm_undeferrstr[32]; -static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; - -/* Convert the error codes into related error strings */ -const char * -bcmerrorstr(int bcmerror) -{ - /* check if someone added a bcmerror code but forgot to add errorstring */ - ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); - - if (bcmerror > 0 || bcmerror < BCME_LAST) { - snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); - return bcm_undeferrstr; - } - - ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); - - return bcmerrorstrtable[-bcmerror]; -} - - - -/* iovar table lookup */ -const bcm_iovar_t* -bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) -{ - const bcm_iovar_t *vi; - const char *lookup_name; - - /* skip any ':' delimited option prefixes */ - lookup_name = strrchr(name, ':'); - if (lookup_name != NULL) - lookup_name++; - else - lookup_name = name; - - ASSERT(table != NULL); - - for (vi = table; vi->name; vi++) { - if (!strcmp(vi->name, lookup_name)) - return vi; - } - /* ran to end of table */ - - return NULL; /* var name not found */ -} - -int -bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) -{ - int bcmerror = 0; - - /* length check on io buf */ - switch (vi->type) { - case IOVT_BOOL: - case IOVT_INT8: - case IOVT_INT16: - case IOVT_INT32: - case IOVT_UINT8: - case IOVT_UINT16: - case IOVT_UINT32: - /* all integers are int32 sized args at the ioctl interface */ - if (len < (int)sizeof(int)) { - bcmerror = BCME_BUFTOOSHORT; - } - break; - - case IOVT_BUFFER: - /* buffer must meet minimum length requirement */ - if (len < vi->minlen) { - bcmerror = BCME_BUFTOOSHORT; - } - break; - - case IOVT_VOID: - if (!set) { - /* Cannot return nil... */ - bcmerror = BCME_UNSUPPORTED; - } else if (len) { - /* Set is an action w/o parameters */ - bcmerror = BCME_BUFTOOLONG; - } - break; - - default: - /* unknown type for length check in iovar info */ - ASSERT(0); - bcmerror = BCME_UNSUPPORTED; - } - - return bcmerror; -} - -#endif /* BCMDRIVER */ - - -uint8 * -bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst) -{ - uint8 *new_dst = dst; - bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst; - - /* dst buffer should always be valid */ - ASSERT(dst); - - /* data len must be within valid range */ - ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)); - - /* source data buffer pointer should be valid, unless datalen is 0 - * meaning no data with this TLV - */ - ASSERT((data != NULL) || (datalen == 0)); - - /* only do work if the inputs are valid - * - must have a dst to write to AND - * - datalen must be within range AND - * - the source data pointer must be non-NULL if datalen is non-zero - * (this last condition detects datalen > 0 with a NULL data pointer) - */ - if ((dst != NULL) && - ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) && - ((data != NULL) || (datalen == 0))) { - - /* write type, len fields */ - dst_tlv->id = (uint8)type; - dst_tlv->len = (uint8)datalen; - - /* if data is present, copy to the output buffer and update - * pointer to output buffer - */ - if (datalen > 0) { - - memcpy(dst_tlv->data, data, datalen); - } - - /* update the output destination poitner to point past - * the TLV written - */ - new_dst = dst + BCM_TLV_HDR_SIZE + datalen; - } - - return (new_dst); -} - -uint8 * -bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen) -{ - uint8 *new_dst = dst; - - if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) { - - /* if len + tlv hdr len is more than destlen, don't do anything - * just return the buffer untouched - */ - if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) { - - new_dst = bcm_write_tlv(type, data, datalen, dst); - } - } - - return (new_dst); -} - -uint8 * -bcm_copy_tlv(const void *src, uint8 *dst) -{ - uint8 *new_dst = dst; - const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; - uint totlen; - - ASSERT(dst && src); - if (dst && src) { - - totlen = BCM_TLV_HDR_SIZE + src_tlv->len; - memcpy(dst, src_tlv, totlen); - new_dst = dst + totlen; - } - - return (new_dst); -} - - -uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen) -{ - uint8 *new_dst = dst; - const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; - - ASSERT(src); - if (src) { - if (bcm_valid_tlv(src_tlv, dst_maxlen)) { - new_dst = bcm_copy_tlv(src, dst); - } - } - - return (new_dst); -} - - -#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) -/******************************************************************************* - * crc8 - * - * Computes a crc8 over the input data using the polynomial: - * - * x^8 + x^7 +x^6 + x^4 + x^2 + 1 - * - * The caller provides the initial value (either CRC8_INIT_VALUE - * or the previous returned value) to allow for processing of - * discontiguous blocks of data. When generating the CRC the - * caller is responsible for complementing the final return value - * and inserting it into the byte stream. When checking, a final - * return value of CRC8_GOOD_VALUE indicates a valid CRC. - * - * Reference: Dallas Semiconductor Application Note 27 - * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", - * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., - * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt - * - * **************************************************************************** - */ - -static const uint8 crc8_table[256] = { - 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, - 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, - 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, - 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, - 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, - 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, - 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, - 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, - 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, - 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, - 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, - 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, - 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, - 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, - 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, - 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, - 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, - 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, - 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, - 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, - 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, - 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, - 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, - 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, - 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, - 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, - 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, - 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, - 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, - 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, - 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, - 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F -}; - -#define CRC_INNER_LOOP(n, c, x) \ - (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] - -uint8 -hndcrc8( - uint8 *pdata, /* pointer to array of data to process */ - uint nbytes, /* number of input data bytes to process */ - uint8 crc /* either CRC8_INIT_VALUE or previous return value */ -) -{ - /* hard code the crc loop instead of using CRC_INNER_LOOP macro - * to avoid the undefined and unnecessary (uint8 >> 8) operation. - */ - while (nbytes-- > 0) - crc = crc8_table[(crc ^ *pdata++) & 0xff]; - - return crc; -} - -/******************************************************************************* - * crc16 - * - * Computes a crc16 over the input data using the polynomial: - * - * x^16 + x^12 +x^5 + 1 - * - * The caller provides the initial value (either CRC16_INIT_VALUE - * or the previous returned value) to allow for processing of - * discontiguous blocks of data. When generating the CRC the - * caller is responsible for complementing the final return value - * and inserting it into the byte stream. When checking, a final - * return value of CRC16_GOOD_VALUE indicates a valid CRC. - * - * Reference: Dallas Semiconductor Application Note 27 - * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", - * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., - * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt - * - * **************************************************************************** - */ - -static const uint16 crc16_table[256] = { - 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, - 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, - 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, - 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, - 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, - 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, - 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, - 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, - 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, - 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, - 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, - 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, - 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, - 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, - 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, - 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, - 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, - 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, - 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, - 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, - 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, - 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, - 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, - 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, - 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, - 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, - 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, - 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, - 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, - 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, - 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, - 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 -}; - -uint16 -hndcrc16( - uint8 *pdata, /* pointer to array of data to process */ - uint nbytes, /* number of input data bytes to process */ - uint16 crc /* either CRC16_INIT_VALUE or previous return value */ -) -{ - while (nbytes-- > 0) - CRC_INNER_LOOP(16, crc, *pdata++); - return crc; -} - -static const uint32 crc32_table[256] = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -}; - -/* - * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if - * accumulating over multiple pieces. - */ -uint32 -hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) -{ - uint8 *pend; - pend = pdata + nbytes; - while (pdata < pend) - CRC_INNER_LOOP(32, crc, *pdata++); - - return crc; -} - -#ifdef notdef -#define CLEN 1499 /* CRC Length */ -#define CBUFSIZ (CLEN+4) -#define CNBUFS 5 /* # of bufs */ - -void -testcrc32(void) -{ - uint j, k, l; - uint8 *buf; - uint len[CNBUFS]; - uint32 crcr; - uint32 crc32tv[CNBUFS] = - {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; - - ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); - - /* step through all possible alignments */ - for (l = 0; l <= 4; l++) { - for (j = 0; j < CNBUFS; j++) { - len[j] = CLEN; - for (k = 0; k < len[j]; k++) - *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; - } - - for (j = 0; j < CNBUFS; j++) { - crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); - ASSERT(crcr == crc32tv[j]); - } - } - - MFREE(buf, CBUFSIZ*CNBUFS); - return; -} -#endif /* notdef */ - -/* - * Advance from the current 1-byte tag/1-byte length/variable-length value - * triple, to the next, returning a pointer to the next. - * If the current or next TLV is invalid (does not fit in given buffer length), - * NULL is returned. - * *buflen is not modified if the TLV elt parameter is invalid, or is decremented - * by the TLV parameter's length if it is valid. - */ -bcm_tlv_t * -bcm_next_tlv(bcm_tlv_t *elt, int *buflen) -{ - int len; - - /* validate current elt */ - if (!bcm_valid_tlv(elt, *buflen)) { - return NULL; - } - - /* advance to next elt */ - len = elt->len; - elt = (bcm_tlv_t*)(elt->data + len); - *buflen -= (TLV_HDR_LEN + len); - - /* validate next elt */ - if (!bcm_valid_tlv(elt, *buflen)) { - return NULL; - } - - return elt; -} - -/* - * 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 - */ -bcm_tlv_t * -bcm_parse_tlvs(void *buf, int buflen, uint key) -{ - bcm_tlv_t *elt; - int totlen; - - elt = (bcm_tlv_t*)buf; - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - int len = elt->len; - - /* validate remaining totlen */ - if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { - - return (elt); - } - - elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - } - - return NULL; -} - -/* - * 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. Stop parsing when we see an element whose ID is greater - * than the target key. - */ -bcm_tlv_t * -bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) -{ - bcm_tlv_t *elt; - int totlen; - - elt = (bcm_tlv_t*)buf; - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - uint id = elt->id; - int len = elt->len; - - /* Punt if we start seeing IDs > than target key */ - if (id > key) { - return (NULL); - } - - /* validate remaining totlen */ - if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { - return (elt); - } - - elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - } - return NULL; -} -#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ - -#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ - defined(DHD_DEBUG) -int -bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len) -{ - int i, slen = 0; - uint32 bit, mask; - const char *name; - mask = bd->mask; - if (len < 2 || !buf) - return 0; - - buf[0] = '\0'; - - for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) { - bit = bd->bitfield[i].bit; - if ((flags & mask) == bit) { - if (len > (int)strlen(name)) { - slen = strlen(name); - strncpy(buf, name, slen+1); - } - break; - } - } - return slen; -} - -int -bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) -{ - int i; - char* p = buf; - char hexstr[16]; - int slen = 0, nlen = 0; - uint32 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, " "); - } - - /* 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 - -/* print bytes formatted as hex to a string. return the resulting string length */ -int -bcm_format_hex(char *str, const void *bytes, int len) -{ - int i; - char *p = str; - const uint8 *src = (const uint8*)bytes; - - for (i = 0; i < len; i++) { - p += snprintf(p, 3, "%02X", *src); - src++; - } - return (int)(p - str); -} - -/* pretty hex print a contiguous buffer */ -void -prhex(const char *msg, uchar *buf, uint nbytes) -{ - char line[128], *p; - int len = sizeof(line); - int nchar; - uint i; - - if (msg && (msg[0] != '\0')) - printf("%s:\n", msg); - - p = line; - for (i = 0; i < nbytes; i++) { - if (i % 16 == 0) { - nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ - p += nchar; - len -= nchar; - } - if (len > 0) { - nchar = snprintf(p, len, "%02x ", buf[i]); - p += nchar; - len -= nchar; - } - - if (i % 16 == 15) { - printf("%s\n", line); /* flush line */ - p = line; - len = sizeof(line); - } - } - - /* flush last partial line */ - if (p != line) - printf("%s\n", line); -} - -static const char *crypto_algo_names[] = { - "NONE", - "WEP1", - "TKIP", - "WEP128", - "AES_CCM", - "AES_OCB_MSDU", - "AES_OCB_MPDU", -#ifdef BCMCCX - "CKIP", - "CKIP_MMH", - "WEP_MMH", - "NALG", -#else - "NALG", - "UNDEF", - "UNDEF", - "UNDEF", -#endif /* BCMCCX */ - "WAPI", - "PMK", - "BIP", - "AES_GCM", - "AES_CCM256", - "AES_GCM256", - "BIP_CMAC256", - "BIP_GMAC", - "BIP_GMAC256", - "UNDEF" -}; - -const char * -bcm_crypto_algo_name(uint algo) -{ - return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; -} - - -char * -bcm_chipname(uint chipid, char *buf, uint len) -{ - const char *fmt; - - fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; - snprintf(buf, len, fmt, chipid); - return buf; -} - -/* Produce a human-readable string for boardrev */ -char * -bcm_brev_str(uint32 brev, char *buf) -{ - if (brev < 0x100) - snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); - else - snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); - - return (buf); -} - -#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ - -/* dump large strings to console */ -void -printbig(char *buf) -{ - uint len, max_len; - char c; - - len = strlen(buf); - - max_len = BUFSIZE_TODUMP_ATONCE; - - while (len > max_len) { - c = buf[max_len]; - buf[max_len] = '\0'; - printf("%s", buf); - buf[max_len] = c; - - buf += max_len; - len -= max_len; - } - /* print the remaining string */ - printf("%s\n", buf); - return; -} - -/* routine to dump fields in a fileddesc structure */ -uint -bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, - char *buf, uint32 bufsize) -{ - uint filled_len; - int len; - struct fielddesc *cur_ptr; - - filled_len = 0; - cur_ptr = fielddesc_array; - - while (bufsize > 1) { - if (cur_ptr->nameandfmt == NULL) - break; - len = snprintf(buf, bufsize, cur_ptr->nameandfmt, - read_rtn(arg0, arg1, cur_ptr->offset)); - /* check for snprintf overflow or error */ - if (len < 0 || (uint32)len >= bufsize) - len = bufsize - 1; - buf += len; - bufsize -= len; - filled_len += len; - cur_ptr++; - } - return filled_len; -} - -uint -bcm_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 */ - if (data && datalen != 0) { - memcpy(&buf[len], data, datalen); - len += datalen; - } - - return len; -} - -/* 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 uint16. - */ - -#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 uint16 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 -}; - -uint16 -bcm_qdbm_to_mw(uint8 qdbm) -{ - uint factor = 1; - int idx = qdbm - QDBM_OFFSET; - - if (idx >= QDBM_TABLE_LEN) { - /* clamp to max uint16 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); -} - -uint8 -bcm_mw_to_qdbm(uint16 mw) -{ - uint8 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 += (uint8)offset; - - return (qdbm); -} - - -uint -bcm_bitcount(uint8 *bitmap, uint length) -{ - uint bitcount = 0, i; - uint8 tmp; - for (i = 0; i < length; i++) { - tmp = bitmap[i]; - while (tmp) { - bitcount++; - tmp &= (tmp - 1); - } - } - return bitcount; -} - -#ifdef BCMDRIVER - -/* Initialization of bcmstrbuf structure */ -void -bcm_binit(struct bcmstrbuf *b, char *buf, uint size) -{ - b->origsize = b->size = size; - b->origbuf = b->buf = buf; -} - -/* Buffer sprintf wrapper to guard against buffer overflow */ -int -bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) -{ - va_list ap; - int r; - - va_start(ap, fmt); - - r = vsnprintf(b->buf, b->size, fmt, ap); - - /* Non Ansi C99 compliant returns -1, - * Ansi compliant return r >= b->size, - * bcmstdlib returns 0, handle all - */ - /* r == 0 is also the case when strlen(fmt) is zero. - * typically the case when "" is passed as argument. - */ - if ((r == -1) || (r >= (int)b->size)) { - b->size = 0; - } else { - b->size -= r; - b->buf += r; - } - - va_end(ap); - - return r; -} - -void -bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len) -{ - int i; - - if (msg != NULL && msg[0] != '\0') - bcm_bprintf(b, "%s", msg); - for (i = 0; i < len; i ++) - bcm_bprintf(b, "%02X", buf[i]); - if (newline) - bcm_bprintf(b, "\n"); -} - -void -bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) -{ - int i; - - for (i = 0; i < num_bytes; i++) { - num[i] += amount; - if (num[i] >= amount) - break; - amount = 1; - } -} - -int -bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) -{ - int i; - - for (i = nbytes - 1; i >= 0; i--) { - if (arg1[i] != arg2[i]) - return (arg1[i] - arg2[i]); - } - return 0; -} - -void -bcm_print_bytes(const char *name, const uchar *data, int len) -{ - int i; - int per_line = 0; - - printf("%s: %d \n", name ? name : "", len); - for (i = 0; i < len; i++) { - printf("%02x ", *data++); - per_line++; - if (per_line == 16) { - per_line = 0; - printf("\n"); - } - } - printf("\n"); -} - -/* Look for vendor-specific IE with specified OUI and optional type */ -bcm_tlv_t * -bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len) -{ - bcm_tlv_t *ie; - uint8 ie_len; - - ie = (bcm_tlv_t*)tlvs; - - /* make sure we are looking at a valid IE */ - if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) { - return NULL; - } - - /* Walk through the IEs looking for an OUI match */ - do { - ie_len = ie->len; - if ((ie->id == DOT11_MNG_PROPR_ID) && - (ie_len >= (DOT11_OUI_LEN + type_len)) && - !bcmp(ie->data, voui, DOT11_OUI_LEN)) - { - /* compare optional type */ - if (type_len == 0 || - !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { - return (ie); /* a match */ - } - } - } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL); - - return NULL; -} - -#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ - defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) -#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) - -int -bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) -{ - uint i, c; - char *p = buf; - char *endp = buf + SSID_FMT_BUF_LEN; - - if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; - - for (i = 0; i < ssid_len; i++) { - c = (uint)ssid[i]; - if (c == '\\') { - *p++ = '\\'; - *p++ = '\\'; - } else if (bcm_isprint((uchar)c)) { - *p++ = (char)c; - } else { - p += snprintf(p, (endp - p), "\\x%02X", c); - } - } - *p = '\0'; - ASSERT(p < endp); - - return (int)(p - buf); -} -#endif - -#endif /* BCMDRIVER */ - -/* - * ProcessVars:Takes a buffer of "=\n" lines read from a file and ending in a NUL. - * also accepts nvram files which are already in the format of =\0\=\0 - * 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. -*/ - -unsigned int -process_nvram_vars(char *varbuf, unsigned int len) -{ - char *dp; - bool findNewline; - int column; - unsigned int buf_len, n; - unsigned int pad = 0; - - dp = varbuf; - - findNewline = FALSE; - column = 0; - - for (n = 0; n < len; n++) { - 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 = (unsigned int)(dp - varbuf); - if (buf_len % 4) { - pad = 4 - buf_len % 4; - if (pad && (buf_len + pad <= len)) { - buf_len += pad; - } - } - - while (dp < varbuf + n) - *dp++ = 0; - - return buf_len; -} - -/* calculate a * b + c */ -void -bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c) -{ -#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;} - uint32 r1, r0; - uint32 a1, a0, b1, b0, t, cc = 0; - - a1 = a >> 16; - a0 = a & 0xffff; - b1 = b >> 16; - b0 = b & 0xffff; - - r0 = a0 * b0; - FORMALIZE(r0); - - t = (a1 * b0) << 16; - FORMALIZE(t); - - r0 += t; - FORMALIZE(r0); - - t = (a0 * b1) << 16; - FORMALIZE(t); - - r0 += t; - FORMALIZE(r0); - - FORMALIZE(c); - - r0 += c; - FORMALIZE(r0); - - r0 |= (cc % 2) ? 0x80000000 : 0; - r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2); - - *r_high = r1; - *r_low = r0; -} - -/* calculate a / b */ -void -bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b) -{ - uint32 a1 = a_high, a0 = a_low, r0 = 0; - - if (b < 2) - return; - - while (a1 != 0) { - r0 += (0xffffffff / b) * a1; - bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0); - } - - r0 += a0 / b; - *r = r0; -} - -#ifndef setbit /* As in the header file */ -#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS -/* Set bit in byte array. */ -void -setbit(void *array, uint bit) -{ - ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY); -} - -/* Clear bit in byte array. */ -void -clrbit(void *array, uint bit) -{ - ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY)); -} - -/* Test if bit is set in byte array. */ -bool -isset(const void *array, uint bit) -{ - return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))); -} - -/* Test if bit is clear in byte array. */ -bool -isclr(const void *array, uint bit) -{ - return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0); -} -#endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */ -#endif /* setbit */ - -void -bcm_bitprint32(const uint32 u32) -{ - int i; - for (i = NBITS(uint32) - 1; i >= 0; i--) { - isbitset(u32, i) ? printf("1") : printf("0"); - if ((i % NBBY) == 0) printf(" "); - } - printf("\n"); -} - -#ifdef BCMDRIVER -/* - * Hierarchical Multiword bitmap based small id allocator. - * - * Multilevel hierarchy bitmap. (maximum 2 levels) - * First hierarchy uses a multiword bitmap to identify 32bit words in the - * second hierarchy that have at least a single bit set. Each bit in a word of - * the second hierarchy represents a unique ID that may be allocated. - * - * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed. - * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word - * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs. - * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non - * non-zero bitmap word carrying at least one free ID. - * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations. - * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID - * - * Design Notes: - * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many - * bits are computed each time on allocation and deallocation, requiring 4 - * array indexed access and 3 arithmetic operations. When not defined, a runtime - * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed. - * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation. - * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may - * be used by defining BCM_MWBMAP_USE_CNTSETBITS. - * - * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array - * size is fixed. No intention to support larger than 4K indice allocation. ID - * allocators for ranges smaller than 4K will have a wastage of only 12Bytes - * with savings in not having to use an indirect access, had it been dynamically - * allocated. - */ -#define BCM_MWBMAP_ITEMS_MAX (4 * 1024) /* May increase to 16K */ - -#define BCM_MWBMAP_BITS_WORD (NBITS(uint32)) -#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD) -#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD) -#define BCM_MWBMAP_SHIFT_OP (5) -#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1)) -#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP) -#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP) - -/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */ -#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl)) -#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr)) - -#if defined(BCM_MWBMAP_DEBUG) -#define BCM_MWBMAP_AUDIT(mwb) \ - do { \ - ASSERT((mwb != NULL) && \ - (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \ - bcm_mwbmap_audit(mwb); \ - } while (0) -#define MWBMAP_ASSERT(exp) ASSERT(exp) -#define MWBMAP_DBG(x) printf x -#else /* !BCM_MWBMAP_DEBUG */ -#define BCM_MWBMAP_AUDIT(mwb) do {} while (0) -#define MWBMAP_ASSERT(exp) do {} while (0) -#define MWBMAP_DBG(x) -#endif /* !BCM_MWBMAP_DEBUG */ - - -typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ - uint16 wmaps; /* Total number of words in free wd bitmap */ - uint16 imaps; /* Total number of words in free id bitmap */ - int16 ifree; /* Count of free indices. Used only in audits */ - uint16 total; /* Total indices managed by multiword bitmap */ - - void * magic; /* Audit handle parameter from user */ - - uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */ -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */ -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - - uint32 id_bitmap[0]; /* Second level bitmap */ -} bcm_mwbmap_t; - -/* Incarnate a hierarchical multiword bitmap based small index allocator. */ -struct bcm_mwbmap * -bcm_mwbmap_init(osl_t *osh, uint32 items_max) -{ - struct bcm_mwbmap * mwbmap_p; - uint32 wordix, size, words, extra; - - /* Implementation Constraint: Uses 32bit word bitmap */ - MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U); - MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U); - MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX)); - MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U); - - ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX); - - /* Determine the number of words needed in the multiword bitmap */ - extra = BCM_MWBMAP_MODOP(items_max); - words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U); - - /* Allocate runtime state of multiword bitmap */ - /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ - size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); - mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); - if (mwbmap_p == (bcm_mwbmap_t *)NULL) { - ASSERT(0); - goto error1; - } - memset(mwbmap_p, 0, size); - - /* Initialize runtime multiword bitmap state */ - mwbmap_p->imaps = (uint16)words; - mwbmap_p->ifree = (int16)items_max; - mwbmap_p->total = (uint16)items_max; - - /* Setup magic, for use in audit of handle */ - mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p); - - /* Setup the second level bitmap of free indices */ - /* Mark all indices as available */ - for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) { - mwbmap_p->id_bitmap[wordix] = (uint32)(~0U); -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD; -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - } - - /* Ensure that extra indices are tagged as un-available */ - if (extra) { /* fixup the free ids in last bitmap and wd_count */ - uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1]; - *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */ -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - } - - /* Setup the first level bitmap hierarchy */ - extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps); - words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U); - - mwbmap_p->wmaps = (uint16)words; - - for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) - mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U); - if (extra) { - uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1]; - *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ - } - - return mwbmap_p; - -error1: - return BCM_MWBMAP_INVALID_HDL; -} - -/* Release resources used by multiword bitmap based small index allocator. */ -void -bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap) - + (sizeof(uint32) * mwbmap_p->imaps)); - return; -} - -/* Allocate a unique small index using a multiword bitmap index allocator. */ -uint32 -bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - /* Start with the first hierarchy */ - for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) { - - bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */ - - if (bitmap != 0U) { - - uint32 count, bitix, *bitmap_p; - - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - - /* clear all except trailing 1 */ - bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); - MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == - bcm_count_leading_zeros(bitmap)); - bitix = (BCM_MWBMAP_BITS_WORD - 1) - - bcm_count_leading_zeros(bitmap); /* use asm clz */ - wordix = BCM_MWBMAP_MULOP(wordix) + bitix; - - /* Clear bit if wd count is 0, without conditional branch */ -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1; -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - mwbmap_p->wd_count[wordix]--; - count = mwbmap_p->wd_count[wordix]; - MWBMAP_ASSERT(count == - (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1)); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - MWBMAP_ASSERT(count >= 0); - - /* clear wd_bitmap bit if id_map count is 0 */ - bitmap = (count == 0) << bitix; - - MWBMAP_DBG(( - "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count)); - - *bitmap_p ^= bitmap; - - /* Use bitix in the second hierarchy */ - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */ - MWBMAP_ASSERT(bitmap != 0U); - - /* clear all except trailing 1 */ - bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); - MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == - bcm_count_leading_zeros(bitmap)); - bitix = BCM_MWBMAP_MULOP(wordix) - + (BCM_MWBMAP_BITS_WORD - 1) - - bcm_count_leading_zeros(bitmap); /* use asm clz */ - - mwbmap_p->ifree--; /* decrement system wide free count */ - MWBMAP_ASSERT(mwbmap_p->ifree >= 0); - - MWBMAP_DBG(( - "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, - mwbmap_p->ifree)); - - *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */ - - return bitix; - } - } - - ASSERT(mwbmap_p->ifree == 0); - - return BCM_MWBMAP_INVALID_IDX; -} - -/* Force an index at a specified position to be in use */ -void -bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 count, wordix, bitmap, *bitmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - /* Start with second hierarchy */ - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - ASSERT((*bitmap_p & bitmap) == bitmap); - - mwbmap_p->ifree--; /* update free count */ - ASSERT(mwbmap_p->ifree >= 0); - - MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, - mwbmap_p->ifree)); - - *bitmap_p ^= bitmap; /* mark as in use */ - - /* Update first hierarchy */ - bitix = wordix; - - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - mwbmap_p->wd_count[bitix]--; - count = mwbmap_p->wd_count[bitix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - MWBMAP_ASSERT(count >= 0); - - bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix); - - MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", - BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, - (*bitmap_p) ^ bitmap, count)); - - *bitmap_p ^= bitmap; /* mark as in use */ - - return; -} - -/* Free a previously allocated index back into the multiword bitmap allocator */ -void -bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap, *bitmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - /* Start with second level hierarchy */ - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */ - - mwbmap_p->ifree++; /* update free count */ - ASSERT(mwbmap_p->ifree <= mwbmap_p->total); - - MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, - mwbmap_p->ifree)); - - *bitmap_p |= bitmap; /* mark as available */ - - /* Now update first level hierarchy */ - - bitix = wordix; - - wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */ - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[bitix]++; -#endif - -#if defined(BCM_MWBMAP_DEBUG) - { - uint32 count; -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[bitix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - - MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD); - - MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count)); - } -#endif /* BCM_MWBMAP_DEBUG */ - - *bitmap_p |= bitmap; - - return; -} - -/* Fetch the toal number of free indices in the multiword bitmap allocator */ -uint32 -bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(mwbmap_p->ifree >= 0); - - return mwbmap_p->ifree; -} - -/* Determine whether an index is inuse or free */ -bool -bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - - return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U); -} - -/* Debug dump a multiword bitmap allocator */ -void -bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl) -{ - uint32 ix, count; - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p, - mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total); - for (ix = 0U; ix < mwbmap_p->wmaps; ix++) { - printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]); - bcm_bitprint32(mwbmap_p->wd_bitmap[ix]); - printf("\n"); - } - for (ix = 0U; ix < mwbmap_p->imaps; ix++) { -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[ix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count); - bcm_bitprint32(mwbmap_p->id_bitmap[ix]); - printf("\n"); - } - - return; -} - -/* Audit a hierarchical multiword bitmap */ -void -bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p; - - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) { - - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - - for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { - if ((*bitmap_p) & (1 << bitix)) { - idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[idmap_ix]; - ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - ASSERT(count != 0U); - free_cnt += count; - } - } - } - - ASSERT(free_cnt == mwbmap_p->ifree); -} -/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ - -#endif /* BCMDRIVER */ - -/* calculate a >> b; and returns only lower 32 bits */ -void -bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b) -{ - uint32 a1 = a_high, a0 = a_low, r0 = 0; - - if (b == 0) { - r0 = a_low; - *r = r0; - return; - } - - if (b < 32) { - a0 = a0 >> b; - a1 = a1 & ((1 << b) - 1); - a1 = a1 << (32 - b); - r0 = a0 | a1; - *r = r0; - return; - } else { - r0 = a1 >> (b - 32); - *r = r0; - return; - } - -} - -/* calculate a + b where a is a 64 bit number and b is a 32 bit number */ -void -bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset) -{ - uint32 r1_lo = *r_lo; - (*r_lo) += offset; - if (*r_lo < r1_lo) - (*r_hi) ++; -} - -/* calculate a - b where a is a 64 bit number and b is a 32 bit number */ -void -bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset) -{ - uint32 r1_lo = *r_lo; - (*r_lo) -= offset; - if (*r_lo > r1_lo) - (*r_hi) --; -} - -#ifdef DEBUG_COUNTER -#if (OSL_SYSUPTIME_SUPPORT == TRUE) -void counter_printlog(counter_tbl_t *ctr_tbl) -{ - uint32 now; - - if (!ctr_tbl->enabled) - return; - - now = OSL_SYSUPTIME(); - - if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) { - uint8 i = 0; - printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print); - - for (i = 0; i < ctr_tbl->needed_cnt; i++) { - printf(" %u", ctr_tbl->cnt[i]); - } - printf("\n"); - - ctr_tbl->prev_log_print = now; - bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint)); - } -} -#else -/* OSL_SYSUPTIME is not supported so no way to get time */ -#define counter_printlog(a) do {} while (0) -#endif /* OSL_SYSUPTIME_SUPPORT == TRUE */ -#endif /* DEBUG_COUNTER */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c deleted file mode 100755 index 33ec4f8db860..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c +++ /dev/null @@ -1,1246 +0,0 @@ -/* - * Misc utility routines used by kernel or app-level. - * Contents are wifi-specific, used by any kernel or app-level - * software that might want wifi things as it grows. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ - */ - -#include -#include -#include - -#ifdef BCMDRIVER -#include -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) -#else -#include -#include -#include -#ifndef ASSERT -#define ASSERT(exp) -#endif -#endif /* BCMDRIVER */ - -#include - -#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) -#include /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ -#endif - -/* Definitions for D11AC capable Chanspec type */ - -/* Chanspec ASCII representation with 802.11ac capability: - * [ 'g'] ['/' []['/'<1st80channel>'-'<2nd80channel>]] - * - * : - * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. - * Default value is 2g if channel <= 14, otherwise 5g. - * : - * channel number of the 5MHz, 10MHz, 20MHz channel, - * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. - * : - * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. - * : - * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. - * - * For 2.4GHz band 40MHz channels, the same primary channel may be the - * upper sideband for one 40MHz channel, and the lower sideband for an - * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel - * is being specified. - * - * For 40MHz in the 5GHz band and all channel bandwidths greater than - * 40MHz, the U/L specificaion is not allowed since the channels are - * non-overlapping and the primary sub-band is derived from its - * position in the wide bandwidth channel. - * - * <1st80Channel>: - * <2nd80Channel>: - * Required for 80+80, otherwise not allowed. - * Specifies the center channel of the first and second 80MHz band. - * - * In its simplest form, it is a 20MHz channel number, with the implied band - * of 2.4GHz if channel number <= 14, and 5GHz otherwise. - * - * To allow for backward compatibility with scripts, the old form for - * 40MHz channels is also allowed: - * - * : - * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz - * : - * "U" for upper, "L" for lower (or lower case "u" "l") - * - * 5 GHz Examples: - * Chanspec BW Center Ch Channel Range Primary Ch - * 5g8 20MHz 8 - - - * 52 20MHz 52 - - - * 52/40 40MHz 54 52-56 52 - * 56/40 40MHz 54 52-56 56 - * 52/80 80MHz 58 52-64 52 - * 56/80 80MHz 58 52-64 56 - * 60/80 80MHz 58 52-64 60 - * 64/80 80MHz 58 52-64 64 - * 52/160 160MHz 50 36-64 52 - * 36/160 160MGz 50 36-64 36 - * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 - * - * 2 GHz Examples: - * Chanspec BW Center Ch Channel Range Primary Ch - * 2g8 20MHz 8 - - - * 8 20MHz 8 - - - * 6 20MHz 6 - - - * 6/40l 40MHz 8 6-10 6 - * 6l 40MHz 8 6-10 6 - * 6/40u 40MHz 4 2-6 6 - * 6u 40MHz 4 2-6 6 - */ - -/* bandwidth ASCII string */ -static const char *wf_chspec_bw_str[] = -{ - "5", - "10", - "20", - "40", - "80", - "160", - "80+80", - "na" -}; - -static const uint8 wf_chspec_bw_mhz[] = -{5, 10, 20, 40, 80, 160, 160}; - -#define WF_NUM_BW \ - (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) - -/* 40MHz channels in 5GHz band */ -static const uint8 wf_5g_40m_chans[] = -{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; -#define WF_NUM_5G_40M_CHANS \ - (sizeof(wf_5g_40m_chans)/sizeof(uint8)) - -/* 80MHz channels in 5GHz band */ -static const uint8 wf_5g_80m_chans[] = -{42, 58, 106, 122, 138, 155}; -#define WF_NUM_5G_80M_CHANS \ - (sizeof(wf_5g_80m_chans)/sizeof(uint8)) - -/* 160MHz channels in 5GHz band */ -static const uint8 wf_5g_160m_chans[] = -{50, 114}; -#define WF_NUM_5G_160M_CHANS \ - (sizeof(wf_5g_160m_chans)/sizeof(uint8)) - - -/* convert bandwidth from chanspec to MHz */ -static uint -bw_chspec_to_mhz(chanspec_t chspec) -{ - uint bw; - - bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; - return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); -} - -/* bw in MHz, return the channel count from the center channel to the - * the channel at the edge of the band - */ -static uint8 -center_chan_to_edge(uint bw) -{ - /* edge channels separated by BW - 10MHz on each side - * delta from cf to edge is half of that, - * MHz to channel num conversion is 5MHz/channel - */ - return (uint8)(((bw - 20) / 2) / 5); -} - -/* return channel number of the low edge of the band - * given the center channel and BW - */ -static uint8 -channel_low_edge(uint center_ch, uint bw) -{ - return (uint8)(center_ch - center_chan_to_edge(bw)); -} - -/* return side band number given center channel and control channel - * return -1 on error - */ -static int -channel_to_sb(uint center_ch, uint ctl_ch, uint bw) -{ - uint lowest = channel_low_edge(center_ch, bw); - uint sb; - - if ((ctl_ch - lowest) % 4) { - /* bad ctl channel, not mult 4 */ - return -1; - } - - sb = ((ctl_ch - lowest) / 4); - - /* sb must be a index to a 20MHz channel in range */ - if (sb >= (bw / 20)) { - /* ctl_ch must have been too high for the center_ch */ - return -1; - } - - return sb; -} - -/* return control channel given center channel and side band */ -static uint8 -channel_to_ctl_chan(uint center_ch, uint bw, uint sb) -{ - return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); -} - -/* return index of 80MHz channel from channel number - * return -1 on error - */ -static int -channel_80mhz_to_id(uint ch) -{ - uint i; - for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { - if (ch == wf_5g_80m_chans[i]) - return i; - } - - return -1; -} - -/* given a chanspec and a string buffer, format the chanspec as a - * string, and return the original pointer a. - * Min buffer length must be CHANSPEC_STR_LEN. - * On error return NULL - */ -char * -wf_chspec_ntoa(chanspec_t chspec, char *buf) -{ - const char *band; - uint ctl_chan; - - if (wf_chspec_malformed(chspec)) - return NULL; - - band = ""; - - /* check for non-default band spec */ - if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || - (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) - band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; - - /* ctl channel */ - ctl_chan = wf_chspec_ctlchan(chspec); - - /* bandwidth and ctl sideband */ - if (CHSPEC_IS20(chspec)) { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); - } else if (!CHSPEC_IS8080(chspec)) { - const char *bw; - const char *sb = ""; - - bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; - -#ifdef CHANSPEC_NEW_40MHZ_FORMAT - /* ctl sideband string if needed for 2g 40MHz */ - if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { - sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; - } - - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); -#else - /* ctl sideband string instead of BW for 40MHz */ - if (CHSPEC_IS40(chspec)) { - sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; - snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); - } else { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); - } -#endif /* CHANSPEC_NEW_40MHZ_FORMAT */ - - } else { - /* 80+80 */ - uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; - uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; - - /* convert to channel number */ - chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; - chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; - - /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ - snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); - } - - return (buf); -} - -static int -read_uint(const char **p, unsigned int *num) -{ - unsigned long val; - char *endp = NULL; - - val = strtoul(*p, &endp, 10); - /* if endp is the initial pointer value, then a number was not read */ - if (endp == *p) - return 0; - - /* advance the buffer pointer to the end of the integer string */ - *p = endp; - /* return the parsed integer */ - *num = (unsigned int)val; - - return 1; -} - -/* given a chanspec string, convert to a chanspec. - * On error return 0 - */ -chanspec_t -wf_chspec_aton(const char *a) -{ - chanspec_t chspec; - uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; - uint num, ctl_ch; - uint ch1, ch2; - char c, sb_ul = '\0'; - int i; - - bw = 20; - chspec_sb = 0; - chspec_ch = ch1 = ch2 = 0; - - /* parse channel num or band */ - if (!read_uint(&a, &num)) - return 0; - - /* if we are looking at a 'g', then the first number was a band */ - c = tolower((int)a[0]); - if (c == 'g') { - a ++; /* consume the char */ - - /* band must be "2" or "5" */ - if (num == 2) - chspec_band = WL_CHANSPEC_BAND_2G; - else if (num == 5) - chspec_band = WL_CHANSPEC_BAND_5G; - else - return 0; - - /* read the channel number */ - if (!read_uint(&a, &ctl_ch)) - return 0; - - c = tolower((int)a[0]); - } - else { - /* first number is channel, use default for band */ - ctl_ch = num; - chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); - } - - if (c == '\0') { - /* default BW of 20MHz */ - chspec_bw = WL_CHANSPEC_BW_20; - goto done_read; - } - - a ++; /* consume the 'u','l', or '/' */ - - /* check 'u'/'l' */ - if (c == 'u' || c == 'l') { - sb_ul = c; - chspec_bw = WL_CHANSPEC_BW_40; - goto done_read; - } - - /* next letter must be '/' */ - if (c != '/') - return 0; - - /* read bandwidth */ - if (!read_uint(&a, &bw)) - return 0; - - /* convert to chspec value */ - if (bw == 20) { - chspec_bw = WL_CHANSPEC_BW_20; - } else if (bw == 40) { - chspec_bw = WL_CHANSPEC_BW_40; - } else if (bw == 80) { - chspec_bw = WL_CHANSPEC_BW_80; - } else if (bw == 160) { - chspec_bw = WL_CHANSPEC_BW_160; - } else { - return 0; - } - - /* So far we have g/ - * Can now be followed by u/l if bw = 40, - * or '+80' if bw = 80, to make '80+80' bw. - */ - - c = tolower((int)a[0]); - - /* if we have a 2g/40 channel, we should have a l/u spec now */ - if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { - if (c == 'u' || c == 'l') { - a ++; /* consume the u/l char */ - sb_ul = c; - goto done_read; - } - } - - /* check for 80+80 */ - if (c == '+') { - /* 80+80 */ - static const char *plus80 = "80/"; - - /* must be looking at '+80/' - * check and consume this string. - */ - chspec_bw = WL_CHANSPEC_BW_8080; - - a ++; /* consume the char '+' */ - - /* consume the '80/' string */ - for (i = 0; i < 3; i++) { - if (*a++ != *plus80++) { - return 0; - } - } - - /* read primary 80MHz channel */ - if (!read_uint(&a, &ch1)) - return 0; - - /* must followed by '-' */ - if (a[0] != '-') - return 0; - a ++; /* consume the char */ - - /* read secondary 80MHz channel */ - if (!read_uint(&a, &ch2)) - return 0; - } - -done_read: - /* skip trailing white space */ - while (a[0] == ' ') { - a ++; - } - - /* must be end of string */ - if (a[0] != '\0') - return 0; - - /* Now have all the chanspec string parts read; - * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. - * chspec_band and chspec_bw are chanspec values. - * Need to convert ctl_ch, sb_ul, and ch1,ch2 into - * a center channel (or two) and sideband. - */ - - /* if a sb u/l string was given, just use that, - * guaranteed to be bw = 40 by sting parse. - */ - if (sb_ul != '\0') { - if (sb_ul == 'l') { - chspec_ch = UPPER_20_SB(ctl_ch); - chspec_sb = WL_CHANSPEC_CTL_SB_LLL; - } else if (sb_ul == 'u') { - chspec_ch = LOWER_20_SB(ctl_ch); - chspec_sb = WL_CHANSPEC_CTL_SB_LLU; - } - } - /* if the bw is 20, center and sideband are trivial */ - else if (chspec_bw == WL_CHANSPEC_BW_20) { - chspec_ch = ctl_ch; - chspec_sb = WL_CHANSPEC_CTL_SB_NONE; - } - /* if the bw is 40/80/160, not 80+80, a single method - * can be used to to find the center and sideband - */ - else if (chspec_bw != WL_CHANSPEC_BW_8080) { - /* figure out ctl sideband based on ctl channel and bandwidth */ - const uint8 *center_ch = NULL; - int num_ch = 0; - int sb = -1; - - if (chspec_bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - } else { - return 0; - } - - for (i = 0; i < num_ch; i ++) { - sb = channel_to_sb(center_ch[i], ctl_ch, bw); - if (sb >= 0) { - chspec_ch = center_ch[i]; - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; - break; - } - } - - /* check for no matching sb/center */ - if (sb < 0) { - return 0; - } - } - /* Otherwise, bw is 80+80. Figure out channel pair and sb */ - else { - int ch1_id = 0, ch2_id = 0; - int sb; - - ch1_id = channel_80mhz_to_id(ch1); - ch2_id = channel_80mhz_to_id(ch2); - - /* validate channels */ - if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0) - return 0; - - /* combined channel in chspec */ - chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | - ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); - - /* figure out ctl sideband */ - - /* does the primary channel fit with the 1st 80MHz channel ? */ - sb = channel_to_sb(ch1, ctl_ch, bw); - if (sb < 0) { - /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ - sb = channel_to_sb(ch2, ctl_ch, bw); - if (sb < 0) { - /* no match for ctl_ch to either 80MHz center channel */ - return 0; - } - /* sb index is 0-3 for the low 80MHz channel, and 4-7 for - * the high 80MHz channel. Add 4 to to shift to high set. - */ - sb += 4; - } - - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; - } - - chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); - - if (wf_chspec_malformed(chspec)) - return 0; - - return chspec; -} - -/* - * 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. - */ -bool -wf_chspec_malformed(chanspec_t chanspec) -{ - uint chspec_bw = CHSPEC_BW(chanspec); - uint chspec_ch = CHSPEC_CHANNEL(chanspec); - - /* must be 2G or 5G band */ - if (CHSPEC_IS2G(chanspec)) { - /* must be valid bandwidth */ - if (chspec_bw != WL_CHANSPEC_BW_20 && - chspec_bw != WL_CHANSPEC_BW_40) { - return TRUE; - } - } else if (CHSPEC_IS5G(chanspec)) { - if (chspec_bw == WL_CHANSPEC_BW_8080) { - uint ch1_id, ch2_id; - - /* channel number in 80+80 must be in range */ - ch1_id = CHSPEC_CHAN1(chanspec); - ch2_id = CHSPEC_CHAN2(chanspec); - if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) - return TRUE; - - /* ch2 must be above ch1 for the chanspec */ - if (ch2_id <= ch1_id) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || - chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { - - if (chspec_ch > MAXCHANNEL) { - return TRUE; - } - } else { - /* invalid bandwidth */ - return TRUE; - } - } else { - /* must be 2G or 5G band */ - return TRUE; - } - - /* side band needs to be consistent with bandwidth */ - if (chspec_bw == WL_CHANSPEC_BW_20) { - if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_40) { - if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) - return TRUE; - } - - return FALSE; -} - -/* - * Verify the chanspec specifies a valid channel according to 802.11. - * RETURNS: TRUE if the chanspec is a valid 802.11 channel - */ -bool -wf_chspec_valid(chanspec_t chanspec) -{ - uint chspec_bw = CHSPEC_BW(chanspec); - uint chspec_ch = CHSPEC_CHANNEL(chanspec); - - if (wf_chspec_malformed(chanspec)) - return FALSE; - - if (CHSPEC_IS2G(chanspec)) { - /* must be valid bandwidth and channel range */ - if (chspec_bw == WL_CHANSPEC_BW_20) { - if (chspec_ch >= 1 && chspec_ch <= 14) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_40) { - if (chspec_ch >= 3 && chspec_ch <= 11) - return TRUE; - } - } else if (CHSPEC_IS5G(chanspec)) { - if (chspec_bw == WL_CHANSPEC_BW_8080) { - uint16 ch1, ch2; - - ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; - ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; - - /* the two channels must be separated by more than 80MHz by VHT req, - * and ch2 above ch1 for the chanspec - */ - if (ch2 > ch1 + CH_80MHZ_APART) - return TRUE; - } else { - const uint8 *center_ch; - uint num_ch, i; - - if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - } else { - /* invalid bandwidth */ - return FALSE; - } - - /* check for a valid center channel */ - if (chspec_bw == WL_CHANSPEC_BW_20) { - /* We don't have an array of legal 20MHz 5G channels, but they are - * each side of the legal 40MHz channels. Check the chanspec - * channel against either side of the 40MHz channels. - */ - for (i = 0; i < num_ch; i ++) { - if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || - chspec_ch == (uint)UPPER_20_SB(center_ch[i])) - break; /* match found */ - } - - if (i == num_ch) { - /* check for channel 165 which is not the side band - * of 40MHz 5G channel - */ - if (chspec_ch == 165) - i = 0; - - /* check for legacy JP channels on failure */ - if (chspec_ch == 34 || chspec_ch == 38 || - chspec_ch == 42 || chspec_ch == 46) - i = 0; - } - } else { - /* check the chanspec channel to each legal channel */ - for (i = 0; i < num_ch; i ++) { - if (chspec_ch == center_ch[i]) - break; /* match found */ - } - } - - if (i < num_ch) { - /* match found */ - return TRUE; - } - } - } - - return FALSE; -} - -/* - * This function returns the channel number that control traffic is being sent on, for 20MHz - * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ - * sideband depending on the chanspec selected - */ -uint8 -wf_chspec_ctlchan(chanspec_t chspec) -{ - uint center_chan; - uint bw_mhz; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - - /* Is there a sideband ? */ - if (CHSPEC_IS20(chspec)) { - return CHSPEC_CHANNEL(chspec); - } else { - sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; - - if (CHSPEC_IS8080(chspec)) { - bw_mhz = 80; - - if (sb < 4) { - center_chan = CHSPEC_CHAN1(chspec); - } - else { - center_chan = CHSPEC_CHAN2(chspec); - sb -= 4; - } - - /* convert from channel index to channel number */ - center_chan = wf_5g_80m_chans[center_chan]; - } - else { - bw_mhz = bw_chspec_to_mhz(chspec); - center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; - } - - return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); - } -} - -/* given a chanspec, return the bandwidth string */ -char * -wf_chspec_to_bw_str(chanspec_t chspec) -{ - return (char *)wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)]; -} - -/* - * This function returns the chanspec of the control channel of a given chanspec - */ -chanspec_t -wf_chspec_ctlchspec(chanspec_t chspec) -{ - chanspec_t ctl_chspec = chspec; - uint8 ctl_chan; - - ASSERT(!wf_chspec_malformed(chspec)); - - /* Is there a sideband ? */ - if (!CHSPEC_IS20(chspec)) { - ctl_chan = wf_chspec_ctlchan(chspec); - ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; - ctl_chspec |= CHSPEC_BAND(chspec); - } - return ctl_chspec; -} - -/* return chanspec given control channel and bandwidth - * return 0 on error - */ -uint16 -wf_channel2chspec(uint ctl_ch, uint bw) -{ - uint16 chspec; - const uint8 *center_ch = NULL; - int num_ch = 0; - int sb = -1; - int i = 0; - - chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); - - chspec |= bw; - - if (bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - bw = 40; - } else if (bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - bw = 80; - } else if (bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - bw = 160; - } else if (bw == WL_CHANSPEC_BW_20) { - chspec |= ctl_ch; - return chspec; - } else { - return 0; - } - - for (i = 0; i < num_ch; i ++) { - sb = channel_to_sb(center_ch[i], ctl_ch, bw); - if (sb >= 0) { - chspec |= center_ch[i]; - chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); - break; - } - } - - /* check for no matching sb/center */ - if (sb < 0) { - return 0; - } - - return chspec; -} - -/* - * This function returns the chanspec for the primary 40MHz of an 80MHz channel. - * The control sideband specifies the same 20MHz channel that the 80MHz channel is using - * as the primary 20MHz channel. - */ -extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) -{ - chanspec_t chspec40 = chspec; - uint center_chan; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - - if (CHSPEC_IS80(chspec)) { - center_chan = CHSPEC_CHANNEL(chspec); - sb = CHSPEC_CTL_SB(chspec); - - if (sb == WL_CHANSPEC_CTL_SB_UL) { - /* Primary 40MHz is on upper side */ - sb = WL_CHANSPEC_CTL_SB_L; - center_chan += CH_20MHZ_APART; - } else if (sb == WL_CHANSPEC_CTL_SB_UU) { - /* Primary 40MHz is on upper side */ - sb = WL_CHANSPEC_CTL_SB_U; - center_chan += CH_20MHZ_APART; - } else { - /* Primary 40MHz is on lower side */ - /* sideband bits are the same for LL/LU and L/U */ - center_chan -= CH_20MHZ_APART; - } - - /* Create primary 40MHz chanspec */ - chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | - sb | center_chan); - } - - return chspec40; -} - -/* - * Return the channel number for a given frequency and base frequency. - * The returned channel number is relative to the given base frequency. - * If the given base frequency is zero, a base frequency of 5 GHz is assumed for - * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. - * - * Frequency is specified in MHz. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for - * 2.4 GHz and 5 GHz bands. - * - * The returned channel will be in the range [1, 14] in the 2.4 GHz band - * and [0, 200] otherwise. - * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the - * frequency is not a 2.4 GHz channel, or if the frequency is not and even - * multiple of 5 MHz from the base frequency to the base plus 1 GHz. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - */ -int -wf_mhz2channel(uint freq, uint start_factor) -{ - int ch = -1; - uint base; - int offset; - - /* take the default channel start frequency */ - if (start_factor == 0) { - if (freq >= 2400 && freq <= 2500) - start_factor = WF_CHAN_FACTOR_2_4_G; - else if (freq >= 5000 && freq <= 6000) - start_factor = WF_CHAN_FACTOR_5_G; - } - - if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) - return 14; - - base = start_factor / 2; - - /* check that the frequency is in 1GHz range of the base */ - if ((freq < base) || (freq > base + 1000)) - return -1; - - offset = freq - base; - ch = offset / 5; - - /* check that frequency is a 5MHz multiple from the base */ - if (offset != (ch * 5)) - return -1; - - /* restricted channel range check for 2.4G */ - if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) - return -1; - - return ch; -} - -/* - * Return the center frequency in MHz of the given channel and base frequency. - * The channel number is interpreted relative to the given base frequency. - * - * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G - * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands. - * The channel range of [1, 14] is only checked for a start_factor of - * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2). - * Odd start_factors produce channels on .5 MHz boundaries, in which case - * the answer is rounded down to an integral MHz. - * -1 is returned for an out of range channel. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - */ -int -wf_channel2mhz(uint ch, uint start_factor) -{ - int freq; - - if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || - (ch > 200)) - freq = -1; - else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) - freq = 2484; - else - freq = ch * 5 + start_factor / 2; - - return freq; -} - -static const uint16 sidebands[] = { - WL_CHANSPEC_CTL_SB_LLL, WL_CHANSPEC_CTL_SB_LLU, - WL_CHANSPEC_CTL_SB_LUL, WL_CHANSPEC_CTL_SB_LUU, - WL_CHANSPEC_CTL_SB_ULL, WL_CHANSPEC_CTL_SB_ULU, - WL_CHANSPEC_CTL_SB_UUL, WL_CHANSPEC_CTL_SB_UUU -}; - -/* - * Returns the chanspec 80Mhz channel corresponding to the following input - * parameters - * - * primary_channel - primary 20Mhz channel - * center_channel - center frequecny of the 80Mhz channel - * - * The center_channel can be one of {42, 58, 106, 122, 138, 155} - * - * returns INVCHANSPEC in case of error - */ -chanspec_t -wf_chspec_80(uint8 center_channel, uint8 primary_channel) -{ - - chanspec_t chanspec = INVCHANSPEC; - chanspec_t chanspec_cur; - uint i; - - for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) { - chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]); - if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) { - chanspec = chanspec_cur; - break; - } - } - /* If the loop ended early, we are good, otherwise we did not - * find a 80MHz chanspec with the given center_channel that had a primary channel - *matching the given primary_channel. - */ - return chanspec; -} - -/* - * Returns the 80+80 chanspec corresponding to the following input parameters - * - * primary_20mhz - Primary 20 Mhz channel - * chan1 - channel number of first 80 Mhz band - * chan2 - channel number of second 80 Mhz band - * - * parameters chan1 and chan2 are channel numbers in {42, 58, 106, 122, 138, 155} - * - * returns INVCHANSPEC in case of error - */ - -chanspec_t -wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan1, uint8 chan2) -{ - int sb = 0; - uint16 chanspec = 0; - int chan1_id = 0, chan2_id = 0; - - /* does the primary channel fit with the 1st 80MHz channel ? */ - sb = channel_to_sb(chan1, primary_20mhz, 80); - if (sb < 0) { - /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ - sb = channel_to_sb(chan2, primary_20mhz, 80); - if (sb < 0) { - /* no match for ctl_ch to either 80MHz center channel */ - return INVCHANSPEC; - } - /* sb index is 0-3 for the low 80MHz channel, and 4-7 for - * the high 80MHz channel. Add 4 to to shift to high set. - */ - sb += 4; - } - chan1_id = channel_80mhz_to_id(chan1); - chan2_id = channel_80mhz_to_id(chan2); - if (chan1_id == -1 || chan2_id == -1) - return INVCHANSPEC; - - chanspec = (chan1_id << WL_CHANSPEC_CHAN1_SHIFT)| - (chan2_id << WL_CHANSPEC_CHAN2_SHIFT)| - (sb << WL_CHANSPEC_CTL_SB_SHIFT)| - (WL_CHANSPEC_BW_8080)| - (WL_CHANSPEC_BAND_5G); - - return chanspec; - -} - -/* - * This function returns the 80Mhz channel for the given id. - */ -static uint8 -wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id) -{ - if (chan_80Mhz_id < WF_NUM_5G_80M_CHANS) - return wf_5g_80m_chans[chan_80Mhz_id]; - - return 0; -} - -/* - * Returns the primary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ - -uint8 -wf_chspec_primary80_channel(chanspec_t chanspec) -{ - uint8 chan1 = 0, chan2 = 0, primary_20mhz = 0, primary80_chan = 0; - int sb = 0; - - primary_20mhz = wf_chspec_ctlchan(chanspec); - - if (CHSPEC_IS80(chanspec)) { - primary80_chan = CHSPEC_CHANNEL(chanspec); - } - else if (CHSPEC_IS8080(chanspec)) { - chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); - chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); - - /* does the primary channel fit with the 1st 80MHz channel ? */ - sb = channel_to_sb(chan1, primary_20mhz, 80); - if (sb < 0) { - /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ - sb = channel_to_sb(chan2, primary_20mhz, 80); - if (!(sb < 0)) { - primary80_chan = chan2; - } - } - else { - primary80_chan = chan1; - } - } - else if (CHSPEC_IS160(chanspec)) { - chan1 = CHSPEC_CHANNEL(chanspec); - sb = channel_to_sb(chan1, primary_20mhz, 160); - if (!(sb < 0)) { - /* based on the sb value primary 80 channel can be retrieved - * if sb is in range 0 to 3 the lower band is the 80Mhz primary band - */ - if (sb < 4) { - primary80_chan = chan1 - CH_40MHZ_APART; - } - /* if sb is in range 4 to 7 the lower band is the 80Mhz primary band */ - else - { - primary80_chan = chan1 + CH_40MHZ_APART; - } - } - } - else { - /* for 20 and 40 Mhz */ - primary80_chan = -1; - } - return primary80_chan; -} - -/* - * Returns the secondary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ -uint8 -wf_chspec_secondary80_channel(chanspec_t chanspec) -{ - uint8 chan1 = 0, chan2 = 0, primary_20mhz = 0, secondary80_chan = 0; - int sb = 0; - - primary_20mhz = wf_chspec_ctlchan(chanspec); - if (CHSPEC_IS80(chanspec)) { - secondary80_chan = -1; - } - else if (CHSPEC_IS8080(chanspec)) { - chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); - chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); - - /* does the primary channel fit with the 1st 80MHz channel ? */ - sb = channel_to_sb(chan1, primary_20mhz, 80); - if (sb < 0) { - /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ - sb = channel_to_sb(chan2, primary_20mhz, 80); - if (!(sb < 0)) { - secondary80_chan = chan1; - } - } - else { - secondary80_chan = chan2; - } - } - else if (CHSPEC_IS160(chanspec)) { - chan1 = CHSPEC_CHANNEL(chanspec); - sb = channel_to_sb(chan1, primary_20mhz, 160); - if (!(sb < 0)) { - /* based on the sb value secondary 80 channel can be retrieved - *if sb is in range 0 to 3 upper band is the secondary 80Mhz band - */ - if (sb < 4) { - secondary80_chan = chan1 + CH_40MHZ_APART; - } - /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */ - else - { - secondary80_chan = chan1 - CH_40MHZ_APART; - } - } - } - else { - /* for 20 and 40 Mhz */ - secondary80_chan = -1; - } - return secondary80_chan; -} - -/* - * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. - * - * chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived - * - * returns INVCHANSPEC in case the provided channel is 20/40 Mhz chanspec - */ -chanspec_t -wf_chspec_primary80_chspec(chanspec_t chspec) -{ - chanspec_t chspec80; - uint center_chan, chan1 = 0, chan2 = 0; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - if (CHSPEC_IS8080(chspec)) { - chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); - chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec)); - - sb = CHSPEC_CTL_SB(chspec); - - if (sb < 4) { - /* Primary 80MHz is on lower side */ - center_chan = chan1; - } - else - { - /* Primary 80MHz is on upper side */ - center_chan = chan2; - sb -= 4; - } - /* Create primary 80MHz chanspec */ - chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 |sb | center_chan); - } - else if (CHSPEC_IS160(chspec)) { - center_chan = CHSPEC_CHANNEL(chspec); - sb = CHSPEC_CTL_SB(chspec); - - if (sb < 4) { - /* Primary 80MHz is on upper side */ - center_chan -= CH_40MHZ_APART; - } - else - { - /* Primary 80MHz is on lower side */ - center_chan += CH_40MHZ_APART; - sb -= 4; - } - /* Create primary 80MHz chanspec */ - chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); - } - else - { - chspec80 = INVCHANSPEC; - } - return chspec80; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h deleted file mode 100755 index 82d59f47ba51..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Misc utility routines for WL and Apps - * This header file housing the define and function prototype use by - * both the wl driver, tools & Apps. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ - */ - -#ifndef _bcmwifi_channels_h_ -#define _bcmwifi_channels_h_ - - -/* A chanspec holds the channel number, band, bandwidth and control sideband */ -typedef uint16 chanspec_t; - -/* channel defines */ -#define CH_UPPER_SB 0x01 -#define CH_LOWER_SB 0x02 -#define CH_EWA_VALID 0x04 -#define CH_80MHZ_APART 16 -#define CH_40MHZ_APART 8 -#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 MAXCHANNEL 224 /* 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 uint8's all over - */ -#define CHSPEC_CTLOVLP(sp1, sp2, sep) (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < \ - (sep)) - -/* All builds use the new 11ac ratespec/chanspec */ -#undef D11AC_IOTYPES -#define D11AC_IOTYPES - -#define WL_CHANSPEC_CHAN_MASK 0x00ff -#define WL_CHANSPEC_CHAN_SHIFT 0 -#define WL_CHANSPEC_CHAN1_MASK 0x000f -#define WL_CHANSPEC_CHAN1_SHIFT 0 -#define WL_CHANSPEC_CHAN2_MASK 0x00f0 -#define WL_CHANSPEC_CHAN2_SHIFT 4 - -#define WL_CHANSPEC_CTL_SB_MASK 0x0700 -#define WL_CHANSPEC_CTL_SB_SHIFT 8 -#define WL_CHANSPEC_CTL_SB_LLL 0x0000 -#define WL_CHANSPEC_CTL_SB_LLU 0x0100 -#define WL_CHANSPEC_CTL_SB_LUL 0x0200 -#define WL_CHANSPEC_CTL_SB_LUU 0x0300 -#define WL_CHANSPEC_CTL_SB_ULL 0x0400 -#define WL_CHANSPEC_CTL_SB_ULU 0x0500 -#define WL_CHANSPEC_CTL_SB_UUL 0x0600 -#define WL_CHANSPEC_CTL_SB_UUU 0x0700 -#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL -#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU -#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL - -#define WL_CHANSPEC_BW_MASK 0x3800 -#define WL_CHANSPEC_BW_SHIFT 11 -#define WL_CHANSPEC_BW_5 0x0000 -#define WL_CHANSPEC_BW_10 0x0800 -#define WL_CHANSPEC_BW_20 0x1000 -#define WL_CHANSPEC_BW_40 0x1800 -#define WL_CHANSPEC_BW_80 0x2000 -#define WL_CHANSPEC_BW_160 0x2800 -#define WL_CHANSPEC_BW_8080 0x3000 - -#define WL_CHANSPEC_BAND_MASK 0xc000 -#define WL_CHANSPEC_BAND_SHIFT 14 -#define WL_CHANSPEC_BAND_2G 0x0000 -#define WL_CHANSPEC_BAND_3G 0x4000 -#define WL_CHANSPEC_BAND_4G 0x8000 -#define WL_CHANSPEC_BAND_5G 0xc000 -#define INVCHANSPEC 255 - -/* channel defines */ -#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ - ((channel) - CH_10MHZ_APART) : 0) -#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ - ((channel) + CH_10MHZ_APART) : 0) - -#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) -#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ - ((channel) + 3 * CH_10MHZ_APART) : 0) -#define LU_20_SB(channel) LOWER_20_SB(channel) -#define UL_20_SB(channel) UPPER_20_SB(channel) - -#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) -#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) -#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) -#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ - (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ - ((channel) + CH_20MHZ_APART) : 0) -#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ - ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ - WL_CHANSPEC_BAND_5G)) -#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | \ - WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) -#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | \ - WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) - -/* simple MACROs to get different fields of chanspec */ -#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) -#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT -#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT -#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) - -#ifdef WL11N_20MHZONLY - -#define CHSPEC_IS10(chspec) 0 -#define CHSPEC_IS20(chspec) 1 -#ifndef CHSPEC_IS40 -#define CHSPEC_IS40(chspec) 0 -#endif -#ifndef CHSPEC_IS80 -#define CHSPEC_IS80(chspec) 0 -#endif -#ifndef CHSPEC_IS160 -#define CHSPEC_IS160(chspec) 0 -#endif -#ifndef CHSPEC_IS8080 -#define CHSPEC_IS8080(chspec) 0 -#endif - -#else /* !WL11N_20MHZONLY */ - -#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 -#ifndef CHSPEC_IS80 -#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) -#endif -#ifndef CHSPEC_IS160 -#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) -#endif -#ifndef CHSPEC_IS8080 -#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) -#endif - -#endif /* !WL11N_20MHZONLY */ - -#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_UPPER(chspec) \ - ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ - (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#define CHSPEC_SB_LOWER(chspec) \ - ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ - (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) - -/** - * Number of chars needed for wf_chspec_ntoa() destination character buffer. - */ -#define CHANSPEC_STR_LEN 20 - - -#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\ - CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080) - -/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made -* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80, -* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080). -* -* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide. -* If both chspec bandwidth and bw is not 160 wide, then the comparison is made. -*/ -#define CHSPEC_BW_GE(chspec, bw) \ - ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ - (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ - (CHSPEC_BW(chspec) >= bw)) - -#define CHSPEC_BW_LE(chspec, bw) \ - ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ - (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ - (CHSPEC_BW(chspec) <= bw)) - -#define CHSPEC_BW_GT(chspec, bw) \ - (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ - (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ - (CHSPEC_BW(chspec) > bw)) - -#define CHSPEC_BW_LT(chspec, bw) \ - (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ - (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ - (CHSPEC_BW(chspec) < bw)) - -/* Legacy Chanspec defines - * These are the defines for the previous format of the chanspec_t - */ -#define WL_LCHANSPEC_CHAN_MASK 0x00ff -#define WL_LCHANSPEC_CHAN_SHIFT 0 - -#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 -#define WL_LCHANSPEC_CTL_SB_SHIFT 8 -#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 -#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 -#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 - -#define WL_LCHANSPEC_BW_MASK 0x0C00 -#define WL_LCHANSPEC_BW_SHIFT 10 -#define WL_LCHANSPEC_BW_10 0x0400 -#define WL_LCHANSPEC_BW_20 0x0800 -#define WL_LCHANSPEC_BW_40 0x0C00 - -#define WL_LCHANSPEC_BAND_MASK 0xf000 -#define WL_LCHANSPEC_BAND_SHIFT 12 -#define WL_LCHANSPEC_BAND_5G 0x1000 -#define WL_LCHANSPEC_BAND_2G 0x2000 - -#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) -#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) -#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) -#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) -#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) -#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) -#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) -#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) -#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) - -#define LCHSPEC_SB_UPPER(chspec) \ - ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \ - (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) -#define LCHSPEC_SB_LOWER(chspec) \ - ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \ - (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) - -#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) - -#define CH20MHZ_LCHSPEC(channel) \ - (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \ - WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G)) - -/* - * WF_CHAN_FACTOR_* constants are used to calculate channel frequency - * given a channel number. - * chan_freq = chan_factor * 500Mhz + chan_number * 5 - */ - -/** - * Channel Factor for the starting frequence of 2.4 GHz channels. - * The value corresponds to 2407 MHz. - */ -#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ - -/** - * Channel Factor for the starting frequence of 5 GHz channels. - * The value corresponds to 5000 MHz. - */ -#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ - -/** - * Channel Factor for the starting frequence of 4.9 GHz channels. - * The value corresponds to 4000 MHz. - */ -#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ - -#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ - -/** - * No of sub-band vlaue of the specified Mhz chanspec - */ -#define WF_NUM_SIDEBANDS_40MHZ 2 -#define WF_NUM_SIDEBANDS_80MHZ 4 -#define WF_NUM_SIDEBANDS_8080MHZ 4 -#define WF_NUM_SIDEBANDS_160MHZ 8 - -/** - * Convert chanspec to ascii string - * - * @param chspec chanspec format - * @param buf ascii string of chanspec - * - * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes - * - * @see CHANSPEC_STR_LEN - */ -extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); - -/** - * Convert ascii string to chanspec - * - * @param a pointer to input string - * - * @return >= 0 if successful or 0 otherwise - */ -extern chanspec_t wf_chspec_aton(const char *a); - -/** - * Verify the chanspec fields are valid. - * - * Verify the chanspec is using a legal set field values, i.e. that the chanspec - * specified a band, bw, ctl_sb and channel and that the combination could be - * legal given some set of circumstances. - * - * @param chanspec input chanspec to verify - * - * @return TRUE if the chanspec is malformed, FALSE if it looks good. - */ -extern bool wf_chspec_malformed(chanspec_t chanspec); - -/** - * Verify the chanspec specifies a valid channel according to 802.11. - * - * @param chanspec input chanspec to verify - * - * @return TRUE if the chanspec is a valid 802.11 channel - */ -extern bool wf_chspec_valid(chanspec_t chanspec); - -/** - * Return the primary (control) channel. - * - * This function returns the channel number of the primary 20MHz channel. For - * 20MHz channels this is just the channel number. For 40MHz or wider channels - * it is the primary 20MHz channel specified by the chanspec. - * - * @param chspec input chanspec - * - * @return Returns the channel number of the primary 20MHz channel - */ -extern uint8 wf_chspec_ctlchan(chanspec_t chspec); - -/** - * Return the bandwidth string. - * - * This function returns the bandwidth string for the passed chanspec. - * - * @param chspec input chanspec - * - * @return Returns the bandwidth string - */ -extern char * wf_chspec_to_bw_str(chanspec_t chspec); - -/** - * Return the primary (control) chanspec. - * - * This function returns the chanspec of the primary 20MHz channel. For 20MHz - * channels this is just the chanspec. For 40MHz or wider channels it is the - * chanspec of the primary 20MHZ channel specified by the chanspec. - * - * @param chspec input chanspec - * - * @return Returns the chanspec of the primary 20MHz channel - */ -extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); - -/** - * Return a channel number corresponding to a frequency. - * - * This function returns the chanspec for the primary 40MHz of an 80MHz channel. - * The control sideband specifies the same 20MHz channel that the 80MHz channel is using - * as the primary 20MHz channel. - */ -extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); - -/* - * Return the channel number for a given frequency and base frequency. - * The returned channel number is relative to the given base frequency. - * If the given base frequency is zero, a base frequency of 5 GHz is assumed for - * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. - * - * Frequency is specified in MHz. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for - * 2.4 GHz and 5 GHz bands. - * - * The returned channel will be in the range [1, 14] in the 2.4 GHz band - * and [0, 200] otherwise. - * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the - * frequency is not a 2.4 GHz channel, or if the frequency is not and even - * multiple of 5 MHz from the base frequency to the base plus 1 GHz. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - * - * @param freq frequency in MHz - * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz - * - * @return Returns a channel number - * - * @see WF_CHAN_FACTOR_2_4_G - * @see WF_CHAN_FACTOR_5_G - */ -extern int wf_mhz2channel(uint freq, uint start_factor); - -/** - * Return the center frequency in MHz of the given channel and base frequency. - * - * Return the center frequency in MHz of the given channel and base frequency. - * The channel number is interpreted relative to the given base frequency. - * - * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for - * 2.4 GHz and 5 GHz bands. - * The channel range of [1, 14] is only checked for a start_factor of - * WF_CHAN_FACTOR_2_4_G (4814). - * Odd start_factors produce channels on .5 MHz boundaries, in which case - * the answer is rounded down to an integral MHz. - * -1 is returned for an out of range channel. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - * - * @param channel input channel number - * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz - * - * @return Returns a frequency in MHz - * - * @see WF_CHAN_FACTOR_2_4_G - * @see WF_CHAN_FACTOR_5_G - */ -extern int wf_channel2mhz(uint channel, uint start_factor); - -/** - * Returns the chanspec 80Mhz channel corresponding to the following input - * parameters - * - * primary_channel - primary 20Mhz channel - * center_channel - center frequecny of the 80Mhz channel - * - * The center_channel can be one of {42, 58, 106, 122, 138, 155} - * - * returns INVCHANSPEC in case of error - */ -extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel); - -/** - * Convert ctl chan and bw to chanspec - * - * @param ctl_ch channel - * @param bw bandwidth - * - * @return > 0 if successful or 0 otherwise - * - */ -extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); - -extern uint wf_channel2freq(uint channel); -extern uint wf_freq2channel(uint freq); - -/* - * Returns the 80+80 chanspec corresponding to the following input parameters - * - * primary_20mhz - Primary 20 Mhz channel - * chan1 - channel number of first 80 Mhz band - * chan2 - channel number of second 80 Mhz band - * - * parameters chan1 and chan2 are channel numbers in {42, 58, 106, 122, 138, 155} - * - * returns INVCHANSPEC in case of error - */ - -extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz, -uint8 chan1_80Mhz, uint8 chan2_80Mhz); - -/* - * Returns the primary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ -extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec); - -/* - * Returns the secondary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ -extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec); - -/* - * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. - */ -extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec); - - -#endif /* _bcmwifi_channels_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h deleted file mode 100755 index 40852cb02b29..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmwifi_rates.h 5187 2012-06-29 06:17:50Z $ - */ - -#ifndef _bcmwifi_rates_h_ -#define _bcmwifi_rates_h_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -#define WL_RATESET_SZ_DSSS 4 -#define WL_RATESET_SZ_OFDM 8 -#define WL_RATESET_SZ_HT_MCS 8 -#define WL_RATESET_SZ_VHT_MCS 10 - -#define WL_TX_CHAINS_MAX 3 - -#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */ - -/* Transmit channel bandwidths */ -typedef enum wl_tx_bw { - WL_TX_BW_20, - WL_TX_BW_40, - WL_TX_BW_80, - WL_TX_BW_160, - WL_TX_BW_20IN40, - WL_TX_BW_20IN80, - WL_TX_BW_40IN80, - WL_TX_BW_20IN160, - WL_TX_BW_40IN160, - WL_TX_BW_80IN160, - WL_TX_BW_ALL -} wl_tx_bw_t; - - -/* - * Transmit modes. - * Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed - */ -typedef enum wl_tx_mode { - WL_TX_MODE_NONE, - WL_TX_MODE_STBC, - WL_TX_MODE_CDD, - WL_TX_MODE_TXBF, - WL_NUM_TX_MODES -} wl_tx_mode_t; - - -/* Number of transmit chains */ -typedef enum wl_tx_chains { - WL_TX_CHAINS_1 = 1, - WL_TX_CHAINS_2, - WL_TX_CHAINS_3 -} wl_tx_chains_t; - - -/* Number of transmit streams */ -typedef enum wl_tx_nss { - WL_TX_NSS_1 = 1, - WL_TX_NSS_2, - WL_TX_NSS_3 -} wl_tx_nss_t; - - -typedef enum clm_rates { - /************ - * 1 chain * - ************ - */ - - /* 1 Stream */ - WL_RATE_1X1_DSSS_1 = 0, - WL_RATE_1X1_DSSS_2 = 1, - WL_RATE_1X1_DSSS_5_5 = 2, - WL_RATE_1X1_DSSS_11 = 3, - - WL_RATE_1X1_OFDM_6 = 4, - WL_RATE_1X1_OFDM_9 = 5, - WL_RATE_1X1_OFDM_12 = 6, - WL_RATE_1X1_OFDM_18 = 7, - WL_RATE_1X1_OFDM_24 = 8, - WL_RATE_1X1_OFDM_36 = 9, - WL_RATE_1X1_OFDM_48 = 10, - WL_RATE_1X1_OFDM_54 = 11, - - WL_RATE_1X1_MCS0 = 12, - WL_RATE_1X1_MCS1 = 13, - WL_RATE_1X1_MCS2 = 14, - WL_RATE_1X1_MCS3 = 15, - WL_RATE_1X1_MCS4 = 16, - WL_RATE_1X1_MCS5 = 17, - WL_RATE_1X1_MCS6 = 18, - WL_RATE_1X1_MCS7 = 19, - - WL_RATE_1X1_VHT0SS1 = 12, - WL_RATE_1X1_VHT1SS1 = 13, - WL_RATE_1X1_VHT2SS1 = 14, - WL_RATE_1X1_VHT3SS1 = 15, - WL_RATE_1X1_VHT4SS1 = 16, - WL_RATE_1X1_VHT5SS1 = 17, - WL_RATE_1X1_VHT6SS1 = 18, - WL_RATE_1X1_VHT7SS1 = 19, - WL_RATE_1X1_VHT8SS1 = 20, - WL_RATE_1X1_VHT9SS1 = 21, - - - /************ - * 2 chains * - ************ - */ - - /* 1 Stream expanded + 1 */ - WL_RATE_1X2_DSSS_1 = 22, - WL_RATE_1X2_DSSS_2 = 23, - WL_RATE_1X2_DSSS_5_5 = 24, - WL_RATE_1X2_DSSS_11 = 25, - - WL_RATE_1X2_CDD_OFDM_6 = 26, - WL_RATE_1X2_CDD_OFDM_9 = 27, - WL_RATE_1X2_CDD_OFDM_12 = 28, - WL_RATE_1X2_CDD_OFDM_18 = 29, - WL_RATE_1X2_CDD_OFDM_24 = 30, - WL_RATE_1X2_CDD_OFDM_36 = 31, - WL_RATE_1X2_CDD_OFDM_48 = 32, - WL_RATE_1X2_CDD_OFDM_54 = 33, - - WL_RATE_1X2_CDD_MCS0 = 34, - WL_RATE_1X2_CDD_MCS1 = 35, - WL_RATE_1X2_CDD_MCS2 = 36, - WL_RATE_1X2_CDD_MCS3 = 37, - WL_RATE_1X2_CDD_MCS4 = 38, - WL_RATE_1X2_CDD_MCS5 = 39, - WL_RATE_1X2_CDD_MCS6 = 40, - WL_RATE_1X2_CDD_MCS7 = 41, - - WL_RATE_1X2_VHT0SS1 = 34, - WL_RATE_1X2_VHT1SS1 = 35, - WL_RATE_1X2_VHT2SS1 = 36, - WL_RATE_1X2_VHT3SS1 = 37, - WL_RATE_1X2_VHT4SS1 = 38, - WL_RATE_1X2_VHT5SS1 = 39, - WL_RATE_1X2_VHT6SS1 = 40, - WL_RATE_1X2_VHT7SS1 = 41, - WL_RATE_1X2_VHT8SS1 = 42, - WL_RATE_1X2_VHT9SS1 = 43, - - /* 2 Streams */ - WL_RATE_2X2_STBC_MCS0 = 44, - WL_RATE_2X2_STBC_MCS1 = 45, - WL_RATE_2X2_STBC_MCS2 = 46, - WL_RATE_2X2_STBC_MCS3 = 47, - WL_RATE_2X2_STBC_MCS4 = 48, - WL_RATE_2X2_STBC_MCS5 = 49, - WL_RATE_2X2_STBC_MCS6 = 50, - WL_RATE_2X2_STBC_MCS7 = 51, - - WL_RATE_2X2_STBC_VHT0SS1 = 44, - WL_RATE_2X2_STBC_VHT1SS1 = 45, - WL_RATE_2X2_STBC_VHT2SS1 = 46, - WL_RATE_2X2_STBC_VHT3SS1 = 47, - WL_RATE_2X2_STBC_VHT4SS1 = 48, - WL_RATE_2X2_STBC_VHT5SS1 = 49, - WL_RATE_2X2_STBC_VHT6SS1 = 50, - WL_RATE_2X2_STBC_VHT7SS1 = 51, - WL_RATE_2X2_STBC_VHT8SS1 = 52, - WL_RATE_2X2_STBC_VHT9SS1 = 53, - - WL_RATE_2X2_SDM_MCS8 = 54, - WL_RATE_2X2_SDM_MCS9 = 55, - WL_RATE_2X2_SDM_MCS10 = 56, - WL_RATE_2X2_SDM_MCS11 = 57, - WL_RATE_2X2_SDM_MCS12 = 58, - WL_RATE_2X2_SDM_MCS13 = 59, - WL_RATE_2X2_SDM_MCS14 = 60, - WL_RATE_2X2_SDM_MCS15 = 61, - - WL_RATE_2X2_VHT0SS2 = 54, - WL_RATE_2X2_VHT1SS2 = 55, - WL_RATE_2X2_VHT2SS2 = 56, - WL_RATE_2X2_VHT3SS2 = 57, - WL_RATE_2X2_VHT4SS2 = 58, - WL_RATE_2X2_VHT5SS2 = 59, - WL_RATE_2X2_VHT6SS2 = 60, - WL_RATE_2X2_VHT7SS2 = 61, - WL_RATE_2X2_VHT8SS2 = 62, - WL_RATE_2X2_VHT9SS2 = 63, - - /************ - * 3 chains * - ************ - */ - - /* 1 Stream expanded + 2 */ - WL_RATE_1X3_DSSS_1 = 64, - WL_RATE_1X3_DSSS_2 = 65, - WL_RATE_1X3_DSSS_5_5 = 66, - WL_RATE_1X3_DSSS_11 = 67, - - WL_RATE_1X3_CDD_OFDM_6 = 68, - WL_RATE_1X3_CDD_OFDM_9 = 69, - WL_RATE_1X3_CDD_OFDM_12 = 70, - WL_RATE_1X3_CDD_OFDM_18 = 71, - WL_RATE_1X3_CDD_OFDM_24 = 72, - WL_RATE_1X3_CDD_OFDM_36 = 73, - WL_RATE_1X3_CDD_OFDM_48 = 74, - WL_RATE_1X3_CDD_OFDM_54 = 75, - - WL_RATE_1X3_CDD_MCS0 = 76, - WL_RATE_1X3_CDD_MCS1 = 77, - WL_RATE_1X3_CDD_MCS2 = 78, - WL_RATE_1X3_CDD_MCS3 = 79, - WL_RATE_1X3_CDD_MCS4 = 80, - WL_RATE_1X3_CDD_MCS5 = 81, - WL_RATE_1X3_CDD_MCS6 = 82, - WL_RATE_1X3_CDD_MCS7 = 83, - - WL_RATE_1X3_VHT0SS1 = 76, - WL_RATE_1X3_VHT1SS1 = 77, - WL_RATE_1X3_VHT2SS1 = 78, - WL_RATE_1X3_VHT3SS1 = 79, - WL_RATE_1X3_VHT4SS1 = 80, - WL_RATE_1X3_VHT5SS1 = 81, - WL_RATE_1X3_VHT6SS1 = 82, - WL_RATE_1X3_VHT7SS1 = 83, - WL_RATE_1X3_VHT8SS1 = 84, - WL_RATE_1X3_VHT9SS1 = 85, - - /* 2 Streams expanded + 1 */ - WL_RATE_2X3_STBC_MCS0 = 86, - WL_RATE_2X3_STBC_MCS1 = 87, - WL_RATE_2X3_STBC_MCS2 = 88, - WL_RATE_2X3_STBC_MCS3 = 89, - WL_RATE_2X3_STBC_MCS4 = 90, - WL_RATE_2X3_STBC_MCS5 = 91, - WL_RATE_2X3_STBC_MCS6 = 92, - WL_RATE_2X3_STBC_MCS7 = 93, - - WL_RATE_2X3_STBC_VHT0SS1 = 86, - WL_RATE_2X3_STBC_VHT1SS1 = 87, - WL_RATE_2X3_STBC_VHT2SS1 = 88, - WL_RATE_2X3_STBC_VHT3SS1 = 89, - WL_RATE_2X3_STBC_VHT4SS1 = 90, - WL_RATE_2X3_STBC_VHT5SS1 = 91, - WL_RATE_2X3_STBC_VHT6SS1 = 92, - WL_RATE_2X3_STBC_VHT7SS1 = 93, - WL_RATE_2X3_STBC_VHT8SS1 = 94, - WL_RATE_2X3_STBC_VHT9SS1 = 95, - - WL_RATE_2X3_SDM_MCS8 = 96, - WL_RATE_2X3_SDM_MCS9 = 97, - WL_RATE_2X3_SDM_MCS10 = 98, - WL_RATE_2X3_SDM_MCS11 = 99, - WL_RATE_2X3_SDM_MCS12 = 100, - WL_RATE_2X3_SDM_MCS13 = 101, - WL_RATE_2X3_SDM_MCS14 = 102, - WL_RATE_2X3_SDM_MCS15 = 103, - - WL_RATE_2X3_VHT0SS2 = 96, - WL_RATE_2X3_VHT1SS2 = 97, - WL_RATE_2X3_VHT2SS2 = 98, - WL_RATE_2X3_VHT3SS2 = 99, - WL_RATE_2X3_VHT4SS2 = 100, - WL_RATE_2X3_VHT5SS2 = 101, - WL_RATE_2X3_VHT6SS2 = 102, - WL_RATE_2X3_VHT7SS2 = 103, - WL_RATE_2X3_VHT8SS2 = 104, - WL_RATE_2X3_VHT9SS2 = 105, - - /* 3 Streams */ - WL_RATE_3X3_SDM_MCS16 = 106, - WL_RATE_3X3_SDM_MCS17 = 107, - WL_RATE_3X3_SDM_MCS18 = 108, - WL_RATE_3X3_SDM_MCS19 = 109, - WL_RATE_3X3_SDM_MCS20 = 110, - WL_RATE_3X3_SDM_MCS21 = 111, - WL_RATE_3X3_SDM_MCS22 = 112, - WL_RATE_3X3_SDM_MCS23 = 113, - - WL_RATE_3X3_VHT0SS3 = 106, - WL_RATE_3X3_VHT1SS3 = 107, - WL_RATE_3X3_VHT2SS3 = 108, - WL_RATE_3X3_VHT3SS3 = 109, - WL_RATE_3X3_VHT4SS3 = 110, - WL_RATE_3X3_VHT5SS3 = 111, - WL_RATE_3X3_VHT6SS3 = 112, - WL_RATE_3X3_VHT7SS3 = 113, - WL_RATE_3X3_VHT8SS3 = 114, - WL_RATE_3X3_VHT9SS3 = 115, - - - /**************************** - * TX Beamforming, 2 chains * - **************************** - */ - - /* 1 Stream expanded + 1 */ - - WL_RATE_1X2_TXBF_OFDM_6 = 116, - WL_RATE_1X2_TXBF_OFDM_9 = 117, - WL_RATE_1X2_TXBF_OFDM_12 = 118, - WL_RATE_1X2_TXBF_OFDM_18 = 119, - WL_RATE_1X2_TXBF_OFDM_24 = 120, - WL_RATE_1X2_TXBF_OFDM_36 = 121, - WL_RATE_1X2_TXBF_OFDM_48 = 122, - WL_RATE_1X2_TXBF_OFDM_54 = 123, - - WL_RATE_1X2_TXBF_MCS0 = 124, - WL_RATE_1X2_TXBF_MCS1 = 125, - WL_RATE_1X2_TXBF_MCS2 = 126, - WL_RATE_1X2_TXBF_MCS3 = 127, - WL_RATE_1X2_TXBF_MCS4 = 128, - WL_RATE_1X2_TXBF_MCS5 = 129, - WL_RATE_1X2_TXBF_MCS6 = 130, - WL_RATE_1X2_TXBF_MCS7 = 131, - - WL_RATE_1X2_TXBF_VHT0SS1 = 124, - WL_RATE_1X2_TXBF_VHT1SS1 = 125, - WL_RATE_1X2_TXBF_VHT2SS1 = 126, - WL_RATE_1X2_TXBF_VHT3SS1 = 127, - WL_RATE_1X2_TXBF_VHT4SS1 = 128, - WL_RATE_1X2_TXBF_VHT5SS1 = 129, - WL_RATE_1X2_TXBF_VHT6SS1 = 130, - WL_RATE_1X2_TXBF_VHT7SS1 = 131, - WL_RATE_1X2_TXBF_VHT8SS1 = 132, - WL_RATE_1X2_TXBF_VHT9SS1 = 133, - - /* 2 Streams */ - - WL_RATE_2X2_TXBF_SDM_MCS8 = 134, - WL_RATE_2X2_TXBF_SDM_MCS9 = 135, - WL_RATE_2X2_TXBF_SDM_MCS10 = 136, - WL_RATE_2X2_TXBF_SDM_MCS11 = 137, - WL_RATE_2X2_TXBF_SDM_MCS12 = 138, - WL_RATE_2X2_TXBF_SDM_MCS13 = 139, - WL_RATE_2X2_TXBF_SDM_MCS14 = 140, - WL_RATE_2X2_TXBF_SDM_MCS15 = 141, - - WL_RATE_2X2_TXBF_VHT0SS2 = 134, - WL_RATE_2X2_TXBF_VHT1SS2 = 135, - WL_RATE_2X2_TXBF_VHT2SS2 = 136, - WL_RATE_2X2_TXBF_VHT3SS2 = 137, - WL_RATE_2X2_TXBF_VHT4SS2 = 138, - WL_RATE_2X2_TXBF_VHT5SS2 = 139, - WL_RATE_2X2_TXBF_VHT6SS2 = 140, - WL_RATE_2X2_TXBF_VHT7SS2 = 141, - - - /**************************** - * TX Beamforming, 3 chains * - **************************** - */ - - /* 1 Stream expanded + 2 */ - - WL_RATE_1X3_TXBF_OFDM_6 = 142, - WL_RATE_1X3_TXBF_OFDM_9 = 143, - WL_RATE_1X3_TXBF_OFDM_12 = 144, - WL_RATE_1X3_TXBF_OFDM_18 = 145, - WL_RATE_1X3_TXBF_OFDM_24 = 146, - WL_RATE_1X3_TXBF_OFDM_36 = 147, - WL_RATE_1X3_TXBF_OFDM_48 = 148, - WL_RATE_1X3_TXBF_OFDM_54 = 149, - - WL_RATE_1X3_TXBF_MCS0 = 150, - WL_RATE_1X3_TXBF_MCS1 = 151, - WL_RATE_1X3_TXBF_MCS2 = 152, - WL_RATE_1X3_TXBF_MCS3 = 153, - WL_RATE_1X3_TXBF_MCS4 = 154, - WL_RATE_1X3_TXBF_MCS5 = 155, - WL_RATE_1X3_TXBF_MCS6 = 156, - WL_RATE_1X3_TXBF_MCS7 = 157, - - WL_RATE_1X3_TXBF_VHT0SS1 = 150, - WL_RATE_1X3_TXBF_VHT1SS1 = 151, - WL_RATE_1X3_TXBF_VHT2SS1 = 152, - WL_RATE_1X3_TXBF_VHT3SS1 = 153, - WL_RATE_1X3_TXBF_VHT4SS1 = 154, - WL_RATE_1X3_TXBF_VHT5SS1 = 155, - WL_RATE_1X3_TXBF_VHT6SS1 = 156, - WL_RATE_1X3_TXBF_VHT7SS1 = 157, - WL_RATE_1X3_TXBF_VHT8SS1 = 158, - WL_RATE_1X3_TXBF_VHT9SS1 = 159, - - /* 2 Streams expanded + 1 */ - - WL_RATE_2X3_TXBF_SDM_MCS8 = 160, - WL_RATE_2X3_TXBF_SDM_MCS9 = 161, - WL_RATE_2X3_TXBF_SDM_MCS10 = 162, - WL_RATE_2X3_TXBF_SDM_MCS11 = 163, - WL_RATE_2X3_TXBF_SDM_MCS12 = 164, - WL_RATE_2X3_TXBF_SDM_MCS13 = 165, - WL_RATE_2X3_TXBF_SDM_MCS14 = 166, - WL_RATE_2X3_TXBF_SDM_MCS15 = 167, - - WL_RATE_2X3_TXBF_VHT0SS2 = 160, - WL_RATE_2X3_TXBF_VHT1SS2 = 161, - WL_RATE_2X3_TXBF_VHT2SS2 = 162, - WL_RATE_2X3_TXBF_VHT3SS2 = 163, - WL_RATE_2X3_TXBF_VHT4SS2 = 164, - WL_RATE_2X3_TXBF_VHT5SS2 = 165, - WL_RATE_2X3_TXBF_VHT6SS2 = 166, - WL_RATE_2X3_TXBF_VHT7SS2 = 167, - WL_RATE_2X3_TXBF_VHT8SS2 = 168, - WL_RATE_2X3_TXBF_VHT9SS2 = 169, - - /* 3 Streams */ - - WL_RATE_3X3_TXBF_SDM_MCS16 = 170, - WL_RATE_3X3_TXBF_SDM_MCS17 = 171, - WL_RATE_3X3_TXBF_SDM_MCS18 = 172, - WL_RATE_3X3_TXBF_SDM_MCS19 = 173, - WL_RATE_3X3_TXBF_SDM_MCS20 = 174, - WL_RATE_3X3_TXBF_SDM_MCS21 = 175, - WL_RATE_3X3_TXBF_SDM_MCS22 = 176, - WL_RATE_3X3_TXBF_SDM_MCS23 = 177, - - WL_RATE_3X3_TXBF_VHT0SS3 = 170, - WL_RATE_3X3_TXBF_VHT1SS3 = 171, - WL_RATE_3X3_TXBF_VHT2SS3 = 172, - WL_RATE_3X3_TXBF_VHT3SS3 = 173, - WL_RATE_3X3_TXBF_VHT4SS3 = 174, - WL_RATE_3X3_TXBF_VHT5SS3 = 175, - WL_RATE_3X3_TXBF_VHT6SS3 = 176, - WL_RATE_3X3_TXBF_VHT7SS3 = 177 -} clm_rates_t; - -/* Number of rate codes */ -#define WL_NUMRATES 178 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* _bcmwifi_rates_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c b/drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c deleted file mode 100755 index 2312c94c4187..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Driver O/S-independent utility routines - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmxtlv.c 487603 2014-06-26 12:33:22Z $ - */ - -#include - -#include -#include - -#include - -#ifdef BCMDRIVER - #include -#else /* !BCMDRIVER */ - #include /* AS!!! */ - #include - #include -#include -#ifndef ASSERT - #define ASSERT(exp) -#endif -inline void* MALLOCZ(void *o, size_t s) { BCM_REFERENCE(o); return calloc(1, s); } -inline void MFREE(void *o, void *p, size_t s) { BCM_REFERENCE(o); BCM_REFERENCE(s); free(p); } -#endif /* !BCMDRIVER */ - -#include -#include - -static INLINE int bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts) -{ - return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + BCM_XTLV_HDR_SIZE, 4) - : (dlen + BCM_XTLV_HDR_SIZE)); -} - -bcm_xtlv_t * -bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts) -{ - int sz; - /* advance to next elt */ - sz = BCM_XTLV_SIZE(elt, opts); - elt = (bcm_xtlv_t*)((uint8 *)elt + sz); - *buflen -= sz; - - /* validate next elt */ - if (!bcm_valid_xtlv(elt, *buflen, opts)) - return NULL; - - return elt; -} - -int -bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, bcm_xtlv_opts_t opts) -{ - if (!tlv_buf || !buf || !len) - return BCME_BADARG; - - tlv_buf->opts = opts; - tlv_buf->size = len; - tlv_buf->head = buf; - tlv_buf->buf = buf; - return BCME_OK; -} - -uint16 -bcm_xtlv_buf_len(bcm_xtlvbuf_t *tbuf) -{ - if (tbuf == NULL) return 0; - return (tbuf->buf - tbuf->head); -} -uint16 -bcm_xtlv_buf_rlen(bcm_xtlvbuf_t *tbuf) -{ - if (tbuf == NULL) return 0; - return tbuf->size - bcm_xtlv_buf_len(tbuf); -} -uint8 * -bcm_xtlv_buf(bcm_xtlvbuf_t *tbuf) -{ - if (tbuf == NULL) return NULL; - return tbuf->buf; -} -uint8 * -bcm_xtlv_head(bcm_xtlvbuf_t *tbuf) -{ - if (tbuf == NULL) return NULL; - return tbuf->head; -} -int -bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const void *data, uint16 dlen) -{ - bcm_xtlv_t *xtlv; - int size; - - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(dlen, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(dlen); - memcpy(xtlv->data, data, dlen); - tbuf->buf += size; - return BCME_OK; -} -int -bcm_xtlv_put_8(bcm_xtlvbuf_t *tbuf, uint16 type, const int8 data) -{ - bcm_xtlv_t *xtlv; - int size; - - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(1, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - xtlv->data[0] = data; - tbuf->buf += size; - return BCME_OK; -} -int -bcm_xtlv_put_16(bcm_xtlvbuf_t *tbuf, uint16 type, const int16 data) -{ - bcm_xtlv_t *xtlv; - int size; - - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(2, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - htol16_ua_store(data, xtlv->data); - tbuf->buf += size; - return BCME_OK; -} -int -bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data) -{ - bcm_xtlv_t *xtlv; - int size; - - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(4, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - htol32_ua_store(data, xtlv->data); - tbuf->buf += size; - return BCME_OK; -} - -/* - * upacks xtlv record from buf checks the type - * copies data to callers buffer - * advances tlv pointer to next record - * caller's resposible for dst space check - */ -int -bcm_unpack_xtlv_entry(uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst, - bcm_xtlv_opts_t opts) -{ - bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; - uint16 len; - uint16 type; - - ASSERT(ptlv); - /* tlv headr is always packed in LE order */ - len = ltoh16(ptlv->len); - type = ltoh16(ptlv->id); - if (len == 0) { - /* z-len tlv headers: allow, but don't process */ - printf("z-len, skip unpack\n"); - } else { - if ((type != xpct_type) || - (len > xpct_len)) { - printf("xtlv_unpack Error: found[type:%d,len:%d] != xpct[type:%d,len:%d]\n", - type, len, xpct_type, xpct_len); - return BCME_BADARG; - } - /* copy tlv record to caller's buffer */ - memcpy(dst, ptlv->data, ptlv->len); - } - *tlv_buf += BCM_XTLV_SIZE(ptlv, opts); - return BCME_OK; -} - -/* - * packs user data into tlv record - * advances tlv pointer to next xtlv slot - * buflen is used for tlv_buf space check - */ -int -bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src, - bcm_xtlv_opts_t opts) -{ - bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; - int size; - - ASSERT(ptlv); - ASSERT(src); - - size = bcm_xtlv_size_for_data(len, opts); - - /* copy data from tlv buffer to dst provided by user */ - if (size > *buflen) { - printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n", - size, *buflen); - return BCME_BADLEN; - } - ptlv->id = htol16(type); - ptlv->len = htol16(len); - - /* copy callers data */ - memcpy(ptlv->data, src, len); - - /* advance callers pointer to tlv buff */ - *tlv_buf += size; - /* decrement the len */ - *buflen -= size; - return BCME_OK; -} - -/* - * unpack all xtlv records from the issue a callback - * to set function one call per found tlv record - */ -int -bcm_unpack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, - bcm_xtlv_unpack_cbfn_t *cbfn) -{ - uint16 len; - uint16 type; - int res = 0; - int size; - bcm_xtlv_t *ptlv; - int sbuflen = buflen; - - ASSERT(!buflen || tlv_buf); - ASSERT(!buflen || cbfn); - - while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) { - ptlv = (bcm_xtlv_t *)tlv_buf; - - /* tlv header is always packed in LE order */ - len = ltoh16(ptlv->len); - type = ltoh16(ptlv->id); - - size = bcm_xtlv_size_for_data(len, opts); - - sbuflen -= size; - /* check for possible buffer overrun */ - if (sbuflen < 0) - break; - - if ((res = cbfn(ctx, ptlv->data, type, len)) != BCME_OK) - break; - tlv_buf += size; - } - return res; -} - -int -bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, - bcm_pack_xtlv_next_info_cbfn_t get_next, bcm_pack_xtlv_pack_next_cbfn_t pack_next, - int *outlen) -{ - int res = BCME_OK; - uint16 tlv_id; - uint16 tlv_len; - uint8 *startp; - uint8 *endp; - uint8 *buf; - bool more; - int size; - - ASSERT(get_next && pack_next); - - buf = (uint8 *)tlv_buf; - startp = buf; - endp = (uint8 *)buf + buflen; - more = TRUE; - while (more && (buf < endp)) { - more = get_next(ctx, &tlv_id, &tlv_len); - size = bcm_xtlv_size_for_data(tlv_len, opts); - if ((buf + size) >= endp) { - res = BCME_BUFTOOSHORT; - goto done; - } - - htol16_ua_store(tlv_id, buf); - htol16_ua_store(tlv_len, buf + sizeof(tlv_id)); - pack_next(ctx, tlv_id, tlv_len, buf + BCM_XTLV_HDR_SIZE); - buf += size; - } - - if (more) - res = BCME_BUFTOOSHORT; - -done: - if (outlen) - *outlen = buf - startp; - return res; -} - -/* - * pack xtlv buffer from memory according to xtlv_desc_t - */ -int -bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items, - bcm_xtlv_opts_t opts) -{ - int res = 0; - uint8 *ptlv = (uint8 *)*tlv_buf; - - while (items->type != 0) { - if ((items->len > 0) && (res = bcm_pack_xtlv_entry(&ptlv, - buflen, items->type, - items->len, items->ptr, opts) != BCME_OK)) { - break; - } - items++; - } - *tlv_buf = ptlv; /* update the external pointer */ - return res; -} - -/* - * unpack xtlv buffer to memory according to xtlv_desc_t - * - */ -int -bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items, bcm_xtlv_opts_t opts) -{ - int res = BCME_OK; - bcm_xtlv_t *elt; - - elt = bcm_valid_xtlv((bcm_xtlv_t *)tlv_buf, *buflen, opts) ? (bcm_xtlv_t *)tlv_buf : NULL; - if (!elt || !items) { - res = BCME_BADARG; - return res; - } - - for (; elt != NULL && res == BCME_OK; elt = bcm_next_xtlv(elt, buflen, opts)) { - /* find matches in desc_t items */ - xtlv_desc_t *dst_desc = items; - uint16 len = ltoh16(elt->len); - - while (dst_desc->type != 0) { - if (ltoh16(elt->id) != dst_desc->type) { - dst_desc++; - continue; - } - if (len != dst_desc->len) - res = BCME_BADLEN; - else - memcpy(dst_desc->ptr, elt->data, len); - break; - } - if (dst_desc->type == 0) - res = BCME_NOTFOUND; - } - - if (*buflen != 0 && res == BCME_OK) - res = BCME_BUFTOOSHORT; - - return res; -} - -int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts) -{ - int size; /* entire size of the XTLV including header, data, and optional padding */ - int len; /* XTLV's value real length wthout padding */ - - len = BCM_XTLV_LEN(elt); - - size = bcm_xtlv_size_for_data(len, opts); - - return size; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd.h b/drivers/net/wireless/bcmdhd_suzuran/dhd.h deleted file mode 100755 index 8156ad66c11c..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd.h +++ /dev/null @@ -1,1020 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * Copyright (C) 2013 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd.h 701450 2017-05-25 02:10:23Z $ - */ - -/**************** - * Common types * - */ - -#ifndef _dhd_h_ -#define _dhd_h_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) -#include -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -/* The kernel threading is sdio-specific */ -struct task_struct; -struct sched_param; -int setScheduler(struct task_struct *p, int policy, struct sched_param *param); -int get_scheduler_policy(struct task_struct *p); - -#define ALL_INTERFACES 0xff - -#include -#include - - -#ifdef CONFIG_BCM_WLAN_RAMDUMP -#include -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - -#if defined(WL11U) && !defined(MFP) -#define MFP /* Applying interaction with MFP by spec HS2.0 REL2 */ -#endif /* WL11U */ - -#if defined(KEEP_ALIVE) -/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ -#define KEEP_ALIVE_PERIOD 55000 -#define NULL_PKT_STR "null_pkt" -#endif /* KEEP_ALIVE */ -/* Forward decls */ -struct dhd_bus; -struct dhd_prot; -struct dhd_info; -struct dhd_ioctl; - -/* The level of bus communication with the dongle */ -enum dhd_bus_state { - DHD_BUS_DOWN, /* Not ready for frame transfers */ - DHD_BUS_LOAD, /* Download access only (CPU reset) */ - DHD_BUS_DATA /* Ready for frame transfers */ -}; - - -enum dhd_op_flags { -/* Firmware requested operation mode */ - DHD_FLAG_STA_MODE = (1 << (0)), /* STA only */ - DHD_FLAG_HOSTAP_MODE = (1 << (1)), /* SOFTAP only */ - DHD_FLAG_P2P_MODE = (1 << (2)), /* P2P Only */ - /* STA + P2P */ - DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), - DHD_FLAG_CONCURR_MULTI_CHAN_MODE = (1 << (4)), /* STA + P2P */ - /* Current P2P mode for P2P connection */ - DHD_FLAG_P2P_GC_MODE = (1 << (5)), - DHD_FLAG_P2P_GO_MODE = (1 << (6)), - DHD_FLAG_MBSS_MODE = (1 << (7)), /* MBSS in future */ - DHD_FLAG_IBSS_MODE = (1 << (8)), - DHD_FLAG_MFG_MODE = (1 << (9)) -}; - -/* Max sequential TX/RX Control timeouts to set HANG event */ -#ifndef MAX_CNTL_TX_TIMEOUT -#define MAX_CNTL_TX_TIMEOUT 2 -#endif /* MAX_CNTL_TX_TIMEOUT */ -#ifndef MAX_CNTL_RX_TIMEOUT -#define MAX_CNTL_RX_TIMEOUT 1 -#endif /* MAX_CNTL_RX_TIMEOUT */ - -#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ -#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ -#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ - -#ifndef POWERUP_MAX_RETRY -#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ -#endif -#ifndef POWERUP_WAIT_MS -#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ -#endif - -enum dhd_bus_wake_state { - WAKE_LOCK_OFF, - WAKE_LOCK_PRIV, - WAKE_LOCK_DPC, - WAKE_LOCK_IOCTL, - WAKE_LOCK_DOWNLOAD, - WAKE_LOCK_TMOUT, - WAKE_LOCK_WATCHDOG, - WAKE_LOCK_LINK_DOWN_TMOUT, - WAKE_LOCK_PNO_FIND_TMOUT, - WAKE_LOCK_SOFTAP_SET, - WAKE_LOCK_SOFTAP_STOP, - WAKE_LOCK_SOFTAP_START, - WAKE_LOCK_SOFTAP_THREAD -}; - -enum dhd_prealloc_index { - DHD_PREALLOC_PROT = 0, - DHD_PREALLOC_RXBUF, - DHD_PREALLOC_DATABUF, - DHD_PREALLOC_OSL_BUF, -#if defined(STATIC_WL_PRIV_STRUCT) - DHD_PREALLOC_WIPHY_ESCAN0 = 5, -#endif /* STATIC_WL_PRIV_STRUCT */ - DHD_PREALLOC_DHD_INFO = 7, - DHD_PREALLOC_DHD_WLFC_INFO = 8, - DHD_PREALLOC_DHD_WLFC_HANGER = 12 -}; - -/* Packet alignment for most efficient SDIO (can change based on platform) */ -#ifndef DHD_SDALIGN -#define DHD_SDALIGN 32 -#endif - -#ifdef DHD_DEBUG -#define DHD_JOIN_MAX_TIME_DEFAULT 10000 /* ms: Max time out for joining AP */ -#define DHD_SCAN_DEF_TIMEOUT 10000 /* ms: Max time out for scan in progress */ -#endif - -/* host reordering packts logic */ -/* followed the structure to hold the reorder buffers (void **p) */ -typedef struct reorder_info { - void **p; - uint8 flow_id; - uint8 cur_idx; - uint8 exp_idx; - uint8 max_idx; - uint8 pend_pkts; -} reorder_info_t; - -#ifdef DHDTCPACK_SUPPRESS -#define TCPACK_SUP_OFF 0 /* TCPACK suppress off */ -/* Replace TCPACK in txq when new coming one has higher ACK number. */ -#define TCPACK_SUP_REPLACE 1 -/* TCPACK_SUP_REPLACE + delayed TCPACK TX unless ACK to PSH DATA. - * This will give benefits to Half-Duplex bus interface(e.g. SDIO) that - * 1. we are able to read TCP DATA packets first from the bus - * 2. TCPACKs that do not need to hurry delivered remains longer in TXQ so can be suppressed. - */ -#define TCPACK_SUP_DELAYTX 2 -#endif /* DHDTCPACK_SUPPRESS */ - -/* Common structure for module and instance linkage */ -typedef struct dhd_pub { - /* Linkage ponters */ - osl_t *osh; /* OSL handle */ - struct dhd_bus *bus; /* Bus module handle */ - struct dhd_prot *prot; /* Protocol module handle */ - struct dhd_info *info; /* Info module handle */ - - /* to NDIS developer, the structure dhd_common is redundant, - * please do NOT merge it back from other branches !!! - */ - - - /* Internal dhd items */ - bool up; /* Driver up/down (to OS) */ - bool txoff; /* Transmit flow-controlled */ - bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ - enum dhd_bus_state busstate; - uint hdrlen; /* Total DHD header length (proto + bus) */ - uint maxctl; /* Max size rxctl request from proto to bus */ - uint rxsz; /* Rx buffer size bus module should use */ - uint8 wme_dp; /* wme discard priority */ - - /* Dongle media info */ - bool iswl; /* Dongle-resident driver is wl */ - ulong drv_version; /* Version of dongle-resident driver */ - struct ether_addr mac; /* MAC address obtained from dongle */ - dngl_stats_t dstats; /* Stats for dongle-based data */ - - /* Additional stats for the bus level */ - ulong tx_packets; /* Data packets sent to dongle */ - ulong tx_multicast; /* Multicast data packets sent to dongle */ - ulong tx_errors; /* Errors in sending data to dongle */ - ulong tx_ctlpkts; /* Control packets sent to dongle */ - ulong tx_ctlerrs; /* Errors sending control frames to dongle */ - ulong rx_packets; /* Packets sent up the network interface */ - ulong rx_multicast; /* Multicast packets sent up the network interface */ - ulong rx_errors; /* Errors processing rx data packets */ - ulong rx_ctlpkts; /* Control frames processed from dongle */ - ulong rx_ctlerrs; /* Errors in processing rx control frames */ - ulong rx_dropped; /* Packets dropped locally (no memory) */ - ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ - ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ - - ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ - ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ - ulong fc_packets; /* Number of flow control pkts recvd */ - - /* Last error return */ - int bcmerror; - uint tickcnt; - - /* Last error from dongle */ - int dongle_error; - - uint8 country_code[WLC_CNTRY_BUF_SZ]; - - /* Suspend disable flag and "in suspend" flag */ - int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ - int in_suspend; /* flag set to 1 when early suspend called */ -#ifdef PNO_SUPPORT - int pno_enable; /* pno status : "1" is pno enable */ - int pno_suspend; /* pno suspend status : "1" is pno suspended */ -#endif /* PNO_SUPPORT */ - /* DTIM skip value, default 0(or 1) means wake each DTIM - * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) - */ - int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ -#ifdef PKT_FILTER_SUPPORT - int early_suspended; /* Early suspend status */ - int dhcp_in_progress; /* DHCP period */ -#endif - - /* Pkt filter defination */ - char * pktfilter[100]; - int pktfilter_count; - - wl_country_t dhd_cspec; /* Current Locale info */ -#ifdef CUSTOM_FORCE_NODFS_FLAG - uint dhd_cflags; -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - bool force_country_change; - char eventmask[WL_EVENTING_MASK_LEN]; - int op_mode; /* STA, HostAPD, WFD, SoftAP */ - -/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. - * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework - * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile - */ -/* #define WL_ENABLE_P2P_IF 1 */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ - struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ -#endif - -#ifdef PROP_TXSTATUS - bool wlfc_enabled; - int wlfc_mode; - void* wlfc_state; - /* - Mode in which the dhd flow control shall operate. Must be set before - traffic starts to the device. - 0 - Do not do any proptxtstatus flow control - 1 - Use implied credit from a packet status - 2 - Use explicit credit - 3 - Only AMPDU hostreorder used. no wlfc. - */ - uint8 proptxstatus_mode; - bool proptxstatus_txoff; - bool proptxstatus_module_ignore; - bool proptxstatus_credit_ignore; - bool proptxstatus_txstatus_ignore; - - bool wlfc_rxpkt_chk; - /* - * implement below functions in each platform if needed. - */ - /* platform specific function whether to skip flow control */ - bool (*skip_fc)(void); - /* platform specific function for wlfc_enable and wlfc_deinit */ - void (*plat_init)(void *dhd); - void (*plat_deinit)(void *dhd); -#endif /* PROP_TXSTATUS */ -#ifdef PNO_SUPPORT - void *pno_state; -#endif -#ifdef RTT_SUPPORT - void *rtt_state; -#endif -#ifdef ROAM_AP_ENV_DETECTION - bool roam_env_detection; -#endif - bool dongle_isolation; - bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ - int hang_was_sent; - int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ - int txcnt_timeout; /* counter txcnt timeout to send HANG */ - bool hang_report; /* enable hang report by default */ -#ifdef WLMEDIA_HTSF - uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ -#endif -#ifdef WLTDLS - bool tdls_enable; -#endif - struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; - char fw_capabilities[WLC_IOCTL_SMLEN]; - #define MAXSKBPEND 1024 - void *skbbuf[MAXSKBPEND]; - uint32 store_idx; - uint32 sent_idx; -#ifdef DHDTCPACK_SUPPRESS - uint8 tcpack_sup_mode; /* TCPACK suppress mode */ - void *tcpack_sup_module; /* TCPACK suppress module */ -#endif /* DHDTCPACK_SUPPRESS */ -#if defined(ARP_OFFLOAD_SUPPORT) - uint32 arp_version; -#endif -#if defined(CUSTOMER_HW5) - bool dhd_bug_on; -#endif -#ifdef CONFIG_BCM_WLAN_RAMDUMP - char crash_reason[BCM_WLAN_CRASH_REASON_LEN]; -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ -#ifdef GSCAN_SUPPORT - bool lazy_roam_enable; -#endif /* GSCAN_SUPPORT */ - uint8 *soc_ram; - uint32 soc_ram_length; -#ifdef DHD_LOSSLESS_ROAMING - uint8 dequeue_prec_map; -#endif /* DHD_LOSSLESS_ROAMING */ - uint8 rand_mac_oui[DOT11_OUI_LEN]; -} dhd_pub_t; -#if defined(CUSTOMER_HW5) -#define MAX_RESCHED_CNT 600 -#endif - - - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) - - #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); - #define _DHD_PM_RESUME_WAIT(a, b) do {\ - int retry = 0; \ - SMP_RD_BARRIER_DEPENDS(); \ - while (dhd_mmc_suspend && retry++ != b) { \ - SMP_RD_BARRIER_DEPENDS(); \ - wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ - } \ - } while (0) - #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) - #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) - #ifdef CUSTOMER_HW4 - #define DHD_PM_RESUME_RETURN_ERROR(a) do { \ - if (dhd_mmc_suspend) { \ - printf("%s[%d]: mmc is still in suspend state!!!\n", \ - __FUNCTION__, __LINE__); \ - return a; \ - } \ - } while (0) - #else - #define DHD_PM_RESUME_RETURN_ERROR(a) do { \ - if (dhd_mmc_suspend) return a; } while (0) - #endif - #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) - - #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); - #define SPINWAIT_SLEEP(a, exp, us) do { \ - uint countdown = (us) + 9999; \ - while ((exp) && (countdown >= 10000)) { \ - wait_event_interruptible_timeout(a, FALSE, 1); \ - countdown -= 10000; \ - } \ - } while (0) - - #else - - #define DHD_PM_RESUME_WAIT_INIT(a) - #define DHD_PM_RESUME_WAIT(a) - #define DHD_PM_RESUME_WAIT_FOREVER(a) - #define DHD_PM_RESUME_RETURN_ERROR(a) - #define DHD_PM_RESUME_RETURN - - #define DHD_SPINWAIT_SLEEP_INIT(a) - #define SPINWAIT_SLEEP(a, exp, us) do { \ - uint countdown = (us) + 9; \ - while ((exp) && (countdown >= 10)) { \ - OSL_DELAY(10); \ - countdown -= 10; \ - } \ - } while (0) - - #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - -#ifdef CONFIG_BCM_WLAN_RAMDUMP -extern char bcm_wlan_ver_info[BCM_WLAN_CRASH_REASON_LEN]; -#define bcm_add_crash_reason(dst, fmt, ...) do { \ - int rest = 0; \ - int pos = strnlen(dst, sizeof(dst)); \ - if (pos == 0) \ - pos += snprintf(&dst[0], sizeof(dst), "%s", bcm_wlan_ver_info); \ - rest = sizeof(dst) - pos; \ - if (rest > 1) { \ - snprintf(&dst[pos], rest, (fmt), ##__VA_ARGS__); \ - } \ - } while (0) -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - -#ifndef OSL_SLEEP -#define OSL_SLEEP(ms) OSL_DELAY(ms*1000) -#endif /* OSL_SLEEP */ - -#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ - -unsigned long dhd_os_spin_lock(dhd_pub_t *pub); -void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); -#ifdef PNO_SUPPORT -int dhd_pno_clean(dhd_pub_t *dhd); -#endif /* PNO_SUPPORT */ -/* - * Wake locks are an Android power management concept. They are used by applications and services - * to request CPU resources. - */ -extern int dhd_os_wake_lock(dhd_pub_t *pub); -extern int dhd_os_wake_unlock(dhd_pub_t *pub); -extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); -extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); -extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); -extern int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub); -extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); -extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); - -inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_init(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_lock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) -#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) -#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) -#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ - dhd_os_wake_lock_rx_timeout_enable(pub, val) -#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ - dhd_os_wake_lock_ctrl_timeout_enable(pub, val) -#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \ - dhd_os_wake_lock_ctrl_timeout_cancel(pub) - -#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub) -#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub) -#define DHD_PACKET_TIMEOUT_MS 500 -#define DHD_EVENT_TIMEOUT_MS 1500 - - -/* interface operations (register, remove) should be atomic, use this lock to prevent race - * condition among wifi on/off and interface operation functions - */ -void dhd_net_if_lock(struct net_device *dev); -void dhd_net_if_unlock(struct net_device *dev); - - -typedef enum dhd_attach_states -{ - DHD_ATTACH_STATE_INIT = 0x0, - DHD_ATTACH_STATE_NET_ALLOC = 0x1, - DHD_ATTACH_STATE_DHD_ALLOC = 0x2, - DHD_ATTACH_STATE_ADD_IF = 0x4, - DHD_ATTACH_STATE_PROT_ATTACH = 0x8, - DHD_ATTACH_STATE_WL_ATTACH = 0x10, - DHD_ATTACH_STATE_THREADS_CREATED = 0x20, - DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, - DHD_ATTACH_STATE_CFG80211 = 0x80, - DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, - DHD_ATTACH_STATE_DONE = 0x200 -} dhd_attach_states_t; - -/* Value -1 means we are unsuccessful in creating the kthread. */ -#define DHD_PID_KT_INVALID -1 -/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ -#define DHD_PID_KT_TL_INVALID -2 - -/* - * Exported from dhd OS modules (dhd_linux/dhd_ndis) - */ - -/* Indication from bus module regarding presence/insertion of dongle. - * Return dhd_pub_t 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 dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); -#if defined(WLP2P) && defined(WL_CFG80211) -/* To allow attach/detach calls corresponding to p2p0 interface */ -extern int dhd_attach_p2p(dhd_pub_t *); -extern int dhd_detach_p2p(dhd_pub_t *); -#endif /* WLP2P && WL_CFG80211 */ -extern int dhd_register_if(dhd_pub_t *dhdp, int idx, bool need_rtnl_lock); - -/* Indication from bus module regarding removal/absence of dongle */ -extern void dhd_detach(dhd_pub_t *dhdp); -extern void dhd_free(dhd_pub_t *dhdp); - -/* Indication from bus module to change flow-control state */ -extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); - -/* Store the status of a connection attempt for later retrieval by an iovar */ -extern void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason); - -extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); - -/* Receive frame for delivery to OS. Callee disposes of rxp. */ -extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); - -/* Return pointer to interface name */ -extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); - -/* Request scheduling of the bus dpc */ -extern void dhd_sched_dpc(dhd_pub_t *dhdp); - -/* Notify tx completion */ -extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); -extern int dhd_dev_get_feature_set(struct net_device *dev); -extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); - -#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */ -#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */ -#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */ -#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */ -#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */ -#define WIFI_FEATURE_GSCAN 0x0020 /* Google-Scan APIs */ -#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness Networking */ -#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */ -#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */ -#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */ -#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */ -#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */ -#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link setup */ -#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off channel */ -#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */ -#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA Concurrency */ -#define WIFI_FEATURE_LINKSTAT 0x10000 /* Support for Linkstats */ -#define WIFI_FEATURE_HAL_EPNO 0x40000 /* WiFi PNO enhanced */ -#define WIFI_FEATURE_RSSI_MONITOR 0x80000 /* RSSI Monitor */ - -#define MAX_FEATURE_SET_CONCURRRENT_GROUPS 3 - -extern int dhd_dev_get_feature_set(struct net_device *dev); -extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); -#ifdef CUSTOM_FORCE_NODFS_FLAG -extern int dhd_dev_set_nodfs(struct net_device *dev, uint nodfs); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -extern int dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui); -extern int dhd_set_rand_mac_oui(dhd_pub_t *dhd); - -#ifdef GSCAN_SUPPORT -extern int dhd_dev_set_lazy_roam_cfg(struct net_device *dev, - wlc_roam_exp_params_t *roam_param); -extern int dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable); -extern int dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, - wl_bssid_pref_cfg_t *bssid_pref, uint32 flush); -extern int dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, - uint32 len, uint32 flush); -extern int dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *whitelist, - uint32 len, uint32 flush); -#endif /* GSCAN_SUPPORT */ - -#ifdef RSSI_MONITOR_SUPPORT -extern int dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, - int8 max_rssi, int8 min_rssi); - -#define DHD_RSSI_MONITOR_EVT_VERSION 1 -typedef struct { - uint8 version; - int8 cur_rssi; - struct ether_addr BSSID; -} dhd_rssi_monitor_evt_t; -#endif /* RSSI_MONITOR_SUPPORT */ - -/* OS independent layer functions */ -extern int dhd_os_proto_block(dhd_pub_t * pub); -extern int dhd_os_proto_unblock(dhd_pub_t * pub); -extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending); -extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); -extern unsigned int dhd_os_get_ioctl_resp_timeout(void); -extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); - -extern int dhd_os_get_image_block(char * buf, int len, void * image); -extern void * dhd_os_open_image(char * filename); -extern void dhd_os_close_image(void * image); -extern void dhd_os_wd_timer(void *bus, uint wdtick); -extern void dhd_os_sdlock(dhd_pub_t * pub); -extern void dhd_os_sdunlock(dhd_pub_t * pub); -extern void dhd_os_sdlock_txq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); -extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); -extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); -#ifdef DHDTCPACK_SUPPRESS -extern void dhd_os_tcpacklock(dhd_pub_t *pub); -extern void dhd_os_tcpackunlock(dhd_pub_t *pub); -#endif /* DHDTCPACK_SUPPRESS */ - -extern int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr); -extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff); -#ifdef GET_CUSTOM_MAC_ENABLE -extern int somc_get_mac_address(unsigned char *buf); -#endif /* GET_CUSTOM_MAC_ENABLE */ -extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf); -#ifdef CUSTOM_FORCE_NODFS_FLAG -extern void get_customized_country_code(void *adapter, char *country_iso_code, - wl_country_t *cspec, u32 flags); -#else -extern void get_customized_country_code(void *adapter, char *country_iso_code, - wl_country_t *cspec); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); -extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); -extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); -extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); -extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); -extern bool dhd_os_check_if_up(dhd_pub_t *pub); -extern int dhd_os_check_wakelock(dhd_pub_t *pub); - - -#if defined(KEEP_ALIVE) -extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); -#endif /* KEEP_ALIVE */ - - -#ifdef PKT_FILTER_SUPPORT -#define DHD_UNICAST_FILTER_NUM 0 -#define DHD_BROADCAST_FILTER_NUM 1 -#define DHD_MULTICAST4_FILTER_NUM 2 -#define DHD_MULTICAST6_FILTER_NUM 3 -#define DHD_MDNS_FILTER_NUM 4 -#define DHD_ARP_FILTER_NUM 5 -extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val); -extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); -extern int net_os_enable_packet_filter(struct net_device *dev, int val); -extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); -#endif /* PKT_FILTER_SUPPORT */ - -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); -extern bool dhd_support_sta_mode(dhd_pub_t *dhd); - -#ifdef DHD_DEBUG -extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); -#endif /* DHD_DEBUG */ - -extern void dhd_os_sdtxlock(dhd_pub_t * pub); -extern void dhd_os_sdtxunlock(dhd_pub_t * pub); - -typedef struct { - uint32 limit; /* Expiration time (usec) */ - uint32 increment; /* Current expiration increment (usec) */ - uint32 elapsed; /* Current elapsed time (usec) */ - uint32 tick; /* O/S tick time (usec) */ -} dhd_timeout_t; - -#if defined(KEEP_ALIVE) -extern int dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, - u16 ip_pkt_len, u8* src_mac_addr, u8* dst_mac_addr, u32 period_msec); -extern int dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id); -#endif /* defined(KEEP_ALIVE) */ - -extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); -extern int dhd_timeout_expired(dhd_timeout_t *tmo); - -extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); -extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); -extern struct net_device * dhd_idx2net(void *pub, int ifidx); -extern int net_os_send_hang_message(struct net_device *dev); -extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, size_t pktlen, - wl_event_msg_t *, void **data_ptr); -extern void wl_event_to_host_order(wl_event_msg_t * evt); -extern int wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu); - -extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); -extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, - int ifindex); -extern void dhd_common_init(osl_t *osh); - -extern int dhd_do_driver_init(struct net_device *net); -extern int dhd_event_ifadd(struct dhd_info *dhd, struct wl_event_data_if *ifevent, - char *name, uint8 *mac); -extern int dhd_event_ifdel(struct dhd_info *dhd, struct wl_event_data_if *ifevent, - char *name, uint8 *mac); -extern struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name, - uint8 *mac, uint8 bssidx, bool need_rtnl_lock); -extern int dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock); -extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); -extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); -extern void dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx); -extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); - -/* Send packet to dongle via data channel */ -extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); - -/* send up locally generated event */ -extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -/* Send event to host */ -extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -#ifdef LOG_INTO_TCPDUMP -extern void dhd_sendup_log(dhd_pub_t *dhdp, void *data, int len); -#endif /* LOG_INTO_TCPDUMP */ -extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); -extern uint dhd_bus_status(dhd_pub_t *dhdp); -extern int dhd_bus_start(dhd_pub_t *dhdp); -extern int dhd_bus_suspend(dhd_pub_t *dhdpub); -extern int dhd_bus_resume(dhd_pub_t *dhdpub, int stage); -extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); -extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); -extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); -extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); -extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); -extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); - -#if defined(KEEP_ALIVE) -extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); -#endif /* KEEP_ALIVE */ - -extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); -int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, - char *res_buf, uint res_len, int set); -extern int dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, - uint cmd_len, char **resptr, uint resp_len); -typedef enum cust_gpio_modes { - WLAN_RESET_ON, - WLAN_RESET_OFF, - WLAN_POWER_ON, - WLAN_POWER_OFF -} cust_gpio_modes_t; - -extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); -extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); -/* - * Insmod parameters for debug/test - */ - -/* Watchdog timer interval */ -extern uint dhd_watchdog_ms; - -#if defined(DHD_DEBUG) -/* Console output poll interval */ -extern uint dhd_console_ms; -extern uint wl_msg_level; -#endif /* defined(DHD_DEBUG) */ - -extern uint dhd_slpauto; - -/* Use interrupts */ -extern uint dhd_intr; - -/* Use polling */ -extern uint dhd_poll; - -/* ARP offload agent mode */ -extern uint dhd_arp_mode; - -/* ARP offload enable */ -extern uint dhd_arp_enable; - -/* Pkt filte enable control */ -extern uint dhd_pkt_filter_enable; - -/* Pkt filter init setup */ -extern uint dhd_pkt_filter_init; - -/* Pkt filter mode control */ -extern uint dhd_master_mode; - -/* Roaming mode control */ -extern uint dhd_roam_disable; - -/* Roaming mode control */ -extern uint dhd_radio_up; - -/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ -extern int dhd_idletime; -#ifdef DHD_USE_IDLECOUNT -#define DHD_IDLETIME_TICKS 5 -#else -#define DHD_IDLETIME_TICKS 1 -#endif /* DHD_USE_IDLECOUNT */ - -/* SDIO Drive Strength */ -extern uint dhd_sdiod_drive_strength; - -/* Override to force tx queueing all the time */ -extern uint dhd_force_tx_queueing; -/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ -#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */ -#ifndef CUSTOM_KEEP_ALIVE_SETTING -#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE -#endif /* DEFAULT_KEEP_ALIVE_VALUE */ - -#define NULL_PKT_STR "null_pkt" - -/* hooks for custom glom setting option via Makefile */ -#define DEFAULT_GLOM_VALUE -1 -#ifndef CUSTOM_GLOM_SETTING -#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE -#endif -#define WL_AUTO_ROAM_TRIGGER -75 -/* hooks for custom Roaming Trigger setting via Makefile */ -#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ -#define DEFAULT_ROAM_TRIGGER_SETTING -1 -#ifndef CUSTOM_ROAM_TRIGGER_SETTING -#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE -#endif - -/* hooks for custom Roaming Romaing setting via Makefile */ -#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ -#define DEFAULT_ROAM_DELTA_SETTING -1 -#ifndef CUSTOM_ROAM_DELTA_SETTING -#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE -#endif - -/* hooks for custom PNO Event wake lock to guarantee enough time - for the Platform to detect Event before system suspended -*/ -#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */ -#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME -#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME -#endif -/* hooks for custom dhd_dpc_prio setting option via Makefile */ -#define DEFAULT_DHP_DPC_PRIO 1 -#ifndef CUSTOM_DPC_PRIO_SETTING -#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO -#endif - -#ifndef CUSTOM_LISTEN_INTERVAL -#define CUSTOM_LISTEN_INTERVAL LISTEN_INTERVAL -#endif /* CUSTOM_LISTEN_INTERVAL */ - -#define DEFAULT_SUSPEND_BCN_LI_DTIM 3 -#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM -#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM -#endif - -#ifndef CUSTOM_RXF_PRIO_SETTING -#define CUSTOM_RXF_PRIO_SETTING MAX((CUSTOM_DPC_PRIO_SETTING - 1), 1) -#endif - -#define DEFAULT_WIFI_TURNOFF_DELAY 0 -#define WIFI_TURNOFF_DELAY DEFAULT_WIFI_TURNOFF_DELAY - -#define DEFAULT_WIFI_TURNON_DELAY 200 -#ifndef WIFI_TURNON_DELAY -#define WIFI_TURNON_DELAY DEFAULT_WIFI_TURNON_DELAY -#endif /* WIFI_TURNON_DELAY */ - -#ifdef WLTDLS -#ifndef CUSTOM_TDLS_IDLE_MODE_SETTING -#define CUSTOM_TDLS_IDLE_MODE_SETTING 60000 /* 60sec to tear down TDLS of not active */ -#endif -#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_HIGH -#define CUSTOM_TDLS_RSSI_THRESHOLD_HIGH -70 /* rssi threshold for establishing TDLS link */ -#endif -#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_LOW -#define CUSTOM_TDLS_RSSI_THRESHOLD_LOW -80 /* rssi threshold for tearing down TDLS link */ -#endif -#endif /* WLTDLS */ - -#ifdef DHD_DEBUG -extern int dhd_start_join_timer(dhd_pub_t *pub); -extern int dhd_del_join_timer(dhd_pub_t *pub); -extern int dhd_set_join_timeout(dhd_pub_t *pub, uint32 timeout); -extern uint32 dhd_get_join_timeout(dhd_pub_t *pub); -extern int dhd_add_scan_timer(dhd_pub_t *dhd_pub); -extern int dhd_del_scan_timer(dhd_pub_t *dhd_pub); -extern int dhd_set_scan_timeout(dhd_pub_t *pub, uint32 timeout); -extern uint32 dhd_get_scan_timeout(dhd_pub_t *pub); -#endif /* DHD_DEBUG */ - -#ifdef SET_RETRY_LIMIT -#define DEFAULT_SHORT_RETRY_LIMIT 13 -#ifndef CUSTOM_SRL_SETTING -#define CUSTOM_SRL_SETTING DEFAULT_SHORT_RETRY_LIMIT -#endif - -#define DEFAULT_LONG_RETRY_LIMIT 13 -#ifndef CUSTOM_LRL_SETTING -#define CUSTOM_LRL_SETTING DEFAULT_LONG_RETRY_LIMIT -#endif -#endif /* SET_RETRY_LIMIT */ - -#define MAX_DTIM_SKIP_BEACON_INTERVAL 100 /* max allowed associated AP beacon for DTIM skip */ -#ifndef MAX_DTIM_ALLOWED_INTERVAL -#define MAX_DTIM_ALLOWED_INTERVAL 600 /* max allowed total beacon interval for DTIM skip */ -#endif -#define NO_DTIM_SKIP 1 -#ifdef SDTEST -/* Echo packet generator (SDIO), pkts/s */ -extern uint dhd_pktgen; - -/* Echo packet len (0 => sawtooth, max 1800) */ -extern uint dhd_pktgen_len; -#define MAX_PKTGEN_LEN 1800 -#endif - - -/* optionally set by a module_param_string() */ -#define MOD_PARAM_PATHLEN 2048 -#define MOD_PARAM_INFOLEN 512 - -#ifdef SOFTAP -extern char fw_path2[MOD_PARAM_PATHLEN]; -#endif - -/* Flag to indicate if we should download firmware on driver load */ -extern uint dhd_download_fw_on_driverload; - - -/* For supporting multiple interfaces */ -#define DHD_MAX_IFS 16 -#define DHD_DEL_IF -0xe -#define DHD_BAD_IF -0xf - -extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); -extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); - -#define IFLOCK_INIT(lock) *lock = 0 -#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ - NdisStallExecution(1); -#define IFUNLOCK(lock) InterlockedExchange((lock), 0) -#define IFLOCK_FREE(lock) -#define FW_SUPPORTED(dhd, capa) ((strstr(dhd->fw_capabilities, #capa) != NULL)) -#ifdef ARP_OFFLOAD_SUPPORT -#define MAX_IPV4_ENTRIES 8 -void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); -void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); - -/* dhd_commn arp offload wrapers */ -void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx); -void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); -int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); -void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef WLTDLS -int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac); -#endif -/* Neighbor Discovery Offload Support */ -int dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable); -int dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipaddr, int idx); -int dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx); -/* ioctl processing for nl80211 */ -int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, struct dhd_ioctl *ioc, void *data_buf); - -void dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path); -void dhd_set_bus_state(void *bus, uint32 state); - -/* Remove proper pkts(either one no-frag pkt or whole fragmented pkts) */ -typedef int (*f_droppkt_t)(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ); -extern bool dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn); - -#ifdef PROP_TXSTATUS -int dhd_os_wlfc_block(dhd_pub_t *pub); -int dhd_os_wlfc_unblock(dhd_pub_t *pub); -extern const uint8 prio2fifo[]; -#endif /* PROP_TXSTATUS */ - -uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail); -void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size); - -#if defined(CONFIG_DHD_USE_STATIC_BUF) -#define DHD_OS_PREALLOC(dhdpub, section, size) dhd_os_prealloc(dhdpub, section, size, FALSE) -#define DHD_OS_PREFREE(dhdpub, addr, size) dhd_os_prefree(dhdpub, addr, size) -#else -#define DHD_OS_PREALLOC(dhdpub, section, size) MALLOC(dhdpub->osh, size) -#define DHD_OS_PREFREE(dhdpub, addr, size) MFREE(dhdpub->osh, addr, size) -#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ - - -void dhd_save_fwdump(dhd_pub_t *dhd_pub, void * buffer, uint32 length); - -#endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c deleted file mode 100755 index e2a891c1e2f8..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * BT-AMP support routines - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_bta.c 701450 2017-05-25 02:10:23Z $ - */ -#error "WLBTAMP is not defined" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -#ifdef SEND_HCI_CMD_VIA_IOCTL -#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE - -/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */ -int -dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) -{ - amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; - int ret; - - if (cmd_len < HCI_CMD_PREAMBLE_SIZE) - return BCME_BADLEN; - - if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) - return BCME_BADLEN; - - ret = dhd_iovar(pub, 0, "HCI_cmd", (char *)cmd, - (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, NULL, 0, TRUE); - - - return ret; -} -#else /* !SEND_HCI_CMD_VIA_IOCTL */ - -static void -dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh) -{ - int prec; - struct pktq *q; - uint count = 0; - - q = dhd_bus_txq(pub->bus); - if (q == NULL) - return; - - DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh)); - - dhd_os_sdlock_txq(pub); - - /* Walk through the txq and toss all HCI ACL data packets */ - PKTQ_PREC_ITER(q, prec) { - void *head_pkt = NULL; - - while (pktq_ppeek(q, prec) != head_pkt) { - void *pkt = pktq_pdeq(q, prec); - int ifidx; - - dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL); - - if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) { - struct ether_header *eh = - (struct ether_header *)PKTDATA(pub->osh, pkt); - - if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { - struct dot11_llc_snap_header *lsh = - (struct dot11_llc_snap_header *)&eh[1]; - - if (bcmp(lsh, BT_SIG_SNAP_MPROT, - DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && - ntoh16(lsh->type) == BTA_PROT_L2CAP) { - amp_hci_ACL_data_t *ACL_data = - (amp_hci_ACL_data_t *)&lsh[1]; - uint16 handle = ltoh16(ACL_data->handle); - - if (HCI_ACL_DATA_HANDLE(handle) == llh) { - PKTFREE(pub->osh, pkt, TRUE); - count ++; - continue; - } - } - } - } - - dhd_prot_hdrpush(pub, ifidx, pkt); - - if (head_pkt == NULL) - head_pkt = pkt; - pktq_penq(q, prec, pkt); - } - } - - dhd_os_sdunlock_txq(pub); - - DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh)); -} - -/* Handle HCI cmd locally. - * Return 0: continue to send the cmd across SDIO - * < 0: stop, fail - * > 0: stop, succuess - */ -static int -_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd) -{ - int status = 0; - - switch (ltoh16_ua((uint8 *)&cmd->opcode)) { - case HCI_Enhanced_Flush: { - eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms; - dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh)); - break; - } - default: - break; - } - - return status; -} - -/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */ -int -dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) -{ - amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; - struct ether_header *eh; - struct dot11_llc_snap_header *lsh; - osl_t *osh = pub->osh; - uint len; - void *p; - int status; - - if (cmd_len < HCI_CMD_PREAMBLE_SIZE) { - DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len)); - return BCME_BADLEN; - } - - if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) { - DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n", - len, cmd_len)); - /* return BCME_BADLEN; */ - } - - p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); - if (p == NULL) { - DHD_ERROR(("dhd_bta_docmd: out of memory\n")); - return BCME_NOMEM; - } - - - /* intercept and handle the HCI cmd locally */ - if ((status = _dhd_bta_docmd(pub, cmd)) > 0) - return 0; - else if (status < 0) - return status; - - /* copy in HCI cmd */ - PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); - bcopy(cmd, PKTDATA(osh, p), len); - - /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ - PKTPUSH(osh, p, RFC1042_HDR_LEN); - eh = (struct ether_header *)PKTDATA(osh, p); - bzero(eh->ether_dhost, ETHER_ADDR_LEN); - ETHER_SET_LOCALADDR(eh->ether_dhost); - bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); - eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); - lsh = (struct dot11_llc_snap_header *)&eh[1]; - bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); - lsh->type = 0; - - return dhd_sendpkt(pub, 0, p); -} -#endif /* !SEND_HCI_CMD_VIA_IOCTL */ - -/* Send HCI ACL data to dongle via data channel */ -int -dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len) -{ - amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf; - struct ether_header *eh; - struct dot11_llc_snap_header *lsh; - osl_t *osh = pub->osh; - uint len; - void *p; - - if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) { - DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len)); - return BCME_BADLEN; - } - - if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) { - DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n", - len, data_len)); - /* return BCME_BADLEN; */ - } - - p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); - if (p == NULL) { - DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n")); - return BCME_NOMEM; - } - - - /* copy in HCI ACL data header and HCI ACL data */ - PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); - bcopy(data, PKTDATA(osh, p), len); - - /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ - PKTPUSH(osh, p, RFC1042_HDR_LEN); - eh = (struct ether_header *)PKTDATA(osh, p); - bzero(eh->ether_dhost, ETHER_ADDR_LEN); - bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); - eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); - lsh = (struct dot11_llc_snap_header *)&eh[1]; - bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); - lsh->type = HTON16(BTA_PROT_L2CAP); - - return dhd_sendpkt(pub, 0, p); -} - -/* txcomplete callback */ -void -dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success) -{ - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp); - amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN); - uint16 handle = ltoh16(ACL_data->handle); - uint16 llh = HCI_ACL_DATA_HANDLE(handle); - - wl_event_msg_t event; - uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)]; - amp_hci_event_t *evt; - num_completed_data_blocks_evt_parms_t *parms; - - uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t); - - /* update the event struct */ - memset(&event, 0, sizeof(event)); - event.version = hton16(BCM_EVENT_MSG_VERSION); - event.event_type = hton32(WLC_E_BTA_HCI_EVENT); - event.status = 0; - event.reason = 0; - event.auth_type = 0; - event.datalen = hton32(len); - event.flags = 0; - - /* generate Number of Completed Blocks event */ - evt = (amp_hci_event_t *)data; - evt->ecode = HCI_Number_of_Completed_Data_Blocks; - evt->plen = sizeof(num_completed_data_blocks_evt_parms_t); - - parms = (num_completed_data_blocks_evt_parms_t *)evt->parms; - htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks); - parms->num_handles = 1; - htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle); - parms->completed[0].pkts = 1; - parms->completed[0].blocks = 1; - - dhd_sendup_event_common(dhdp, &event, data); -} - -/* event callback */ -void -dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) -{ - amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; - - ASSERT(dhdp); - ASSERT(evt); - - switch (evt->ecode) { - case HCI_Command_Complete: { - cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; - switch (ltoh16_ua((uint8 *)&parms->opcode)) { - case HCI_Read_Data_Block_Size: { - read_data_block_size_evt_parms_t *parms2 = - (read_data_block_size_evt_parms_t *)parms->parms; - dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num); - break; - } - } - break; - } - - case HCI_Flush_Occurred: { - flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms; - dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle)); - break; - } - default: - break; - } -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h deleted file mode 100755 index 000d4eee6a51..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * BT-AMP support routines - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_bta.h 291086 2011-10-21 01:17:24Z $ - */ -#ifndef __dhd_bta_h__ -#define __dhd_bta_h__ - -struct dhd_pub; - -extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len); - -extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len); - -extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len); -extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success); - - -#endif /* __dhd_bta_h__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h deleted file mode 100755 index 0887b0ee9bdf..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_bus.h 457888 2014-02-25 03:34:39Z $ - */ - -#ifndef _dhd_bus_h_ -#define _dhd_bus_h_ - -/* - * Exported from dhd bus module (dhd_usb, dhd_sdio) - */ - -/* Indicate (dis)interest in finding dongles. */ -extern int dhd_bus_register(void); -extern void dhd_bus_unregister(void); - -/* Download firmware image and nvram image */ -extern int dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, char *fw_path, char *nv_path); - -/* Stop bus module: clear pending frames, disable data flow */ -extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); - -/* Initialize bus module: prepare for communication w/dongle */ -extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); - -/* Get the Bus Idle Time */ -extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); - -/* Set the Bus Idle Time */ -extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); - -/* Send a data frame to the dongle. Callee disposes of txp. */ -#ifdef BCMPCIE -extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx); -#else -extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); -#endif - - -/* Send/receive a control message to/from the dongle. - * Expects caller to enforce a single outstanding transaction. - */ -extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); -extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); - -/* Watchdog timer function */ -extern bool dhd_bus_watchdog(dhd_pub_t *dhd); - -extern int dhd_bus_oob_intr_register(dhd_pub_t *dhdp); -extern void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp); -extern void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable); -extern void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub); -extern void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub); -extern bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub); - -#if defined(DHD_DEBUG) -/* Device console input function */ -extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); -#endif /* defined(DHD_DEBUG) */ - -/* Deferred processing for the bus, return TRUE requests reschedule */ -extern bool dhd_bus_dpc(struct dhd_bus *bus); -extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); - - -/* Check for and handle local prot-specific iovar commands */ -extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Add bus dump output to a buffer */ -extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); - -/* Clear any bus counters */ -extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); - -/* return the dongle chipid */ -extern uint dhd_bus_chip(struct dhd_bus *bus); - -/* return the dongle chiprev */ -extern uint dhd_bus_chiprev(struct dhd_bus *bus); - -/* Set user-specified nvram parameters. */ -extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); - -extern void *dhd_bus_pub(struct dhd_bus *bus); -extern void *dhd_bus_txq(struct dhd_bus *bus); -extern void *dhd_bus_sih(struct dhd_bus *bus); -extern uint dhd_bus_hdrlen(struct dhd_bus *bus); -extern void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val); - -#define DHD_SET_BUS_STATE_DOWN(_bus) do { \ - (_bus)->dhd->busstate = DHD_BUS_DOWN; \ -} while (0) - -/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ -extern int dhd_bus_reg_sdio_notify(void* semaphore); -extern void dhd_bus_unreg_sdio_notify(void); -extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable); -extern int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, - uint32 *slot_num); - -#ifdef BCMPCIE -enum { - DNGL_TO_HOST_BUF_IOCT, - DNGL_TO_HOST_BUF_ADDR, - HOST_TO_DNGL_BUF_ADDR, - HOST_TO_DNGL_WPTR, - HOST_TO_DNGL_RPTR, - DNGL_TO_HOST_WPTR, - DNGL_TO_HOST_RPTR, - TOTAL_LFRAG_PACKET_CNT, - HOST_TO_DNGL_CTRLBUF_ADDR, - DNGL_TO_HOST_CTRLBUF_ADDR, - HTOD_CTRL_RPTR, - HTOD_CTRL_WPTR, - DTOH_CTRL_RPTR, - DTOH_CTRL_WPTR, - HTOD_MB_DATA, - DTOH_MB_DATA, - MAX_HOST_RXBUFS -}; -typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32); -extern void dhd_bus_cmn_writeshared(struct dhd_bus *bus, void * data, uint32 len, uint8 type); -extern void dhd_bus_ringbell(struct dhd_bus *bus, uint32 value); -extern void dhd_bus_cmn_readshared(struct dhd_bus *bus, void* data, uint8 type); -extern uint32 dhd_bus_get_sharedflags(struct dhd_bus *bus); -extern void dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count); -extern void dhd_bus_start_queue(struct dhd_bus *bus); -extern void dhd_bus_stop_queue(struct dhd_bus *bus); -extern void dhd_bus_update_retlen(struct dhd_bus *bus, uint32 retlen, uint32 cmd_id, uint32 status, - uint32 inline_data); -extern dhd_mb_ring_t dhd_bus_get_mbintr_fn(struct dhd_bus *bus); -#endif /* BCMPCIE */ -#endif /* _dhd_bus_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c deleted file mode 100755 index 153cffbce0b7..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c +++ /dev/null @@ -1,795 +0,0 @@ -/* - * DHD Protocol Module for CDC and BDC. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_cdc.c 701450 2017-05-25 02:10:23Z $ - * - * BDC is like CDC, except it includes a header for data packets to convey - * packet priority over the bus, and flags (e.g. to indicate checksum status - * for dongle offload.) - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - - -#ifdef PROP_TXSTATUS -#include -#include -#endif - - -#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ -#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE - * defined in dhd_sdio.c (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 - */ - -typedef struct dhd_prot { - uint16 reqid; - uint8 pending; - uint32 lastcmd; - uint8 bus_header[BUS_HEADER_LEN]; - cdc_ioctl_t msg; - unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; -} dhd_prot_t; - - -static int -dhdcdc_msg(dhd_pub_t *dhd) -{ - int err = 0; - dhd_prot_t *prot = dhd->prot; - int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - DHD_OS_WAKE_LOCK(dhd); - - /* 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 */ - err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); - - DHD_OS_WAKE_UNLOCK(dhd); - return err; -} - -static int -dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) -{ - int ret; - int cdc_len = len + sizeof(cdc_ioctl_t); - dhd_prot_t *prot = dhd->prot; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#if defined(CUSTOMER_HW5) - DHD_OS_WAKE_LOCK(dhd); -#endif - - do { - ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); - if (ret < 0) - break; - } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); - -#if defined(CUSTOMER_HW5) - DHD_OS_WAKE_UNLOCK(dhd); -#endif - - return ret; -} - -static int -dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - dhd_prot_t *prot = dhd->prot; - cdc_ioctl_t *msg = &prot->msg; - int ret = 0, retries = 0; - uint32 id, flags = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); - - - /* Respond "bcmerror" and "bcmerrorstr" with local cache */ - if (cmd == WLC_GET_VAR && buf) - { - if (!strcmp((char *)buf, "bcmerrorstr")) - { - strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN); - goto done; - } - else if (!strcmp((char *)buf, "bcmerror")) - { - *(int *)buf = dhd->dongle_error; - goto done; - } - } - - memset(msg, 0, sizeof(cdc_ioctl_t)); - - msg->cmd = htol32(cmd); - msg->len = htol32(len); - msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); - CDC_SET_IF_IDX(msg, ifidx); - /* add additional action bits */ - action &= WL_IOCTL_ACTION_MASK; - msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); - msg->flags = htol32(msg->flags); - - if (buf) - memcpy(prot->buf, buf, len); - - if ((ret = dhdcdc_msg(dhd)) < 0) { - if (!dhd->hang_was_sent) - DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret)); - goto done; - } - -retry: - /* wait for interrupt and get first fragment */ - if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) - goto done; - - flags = ltoh32(msg->flags); - id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; - - if ((id < prot->reqid) && (++retries < RETRIES)) - goto retry; - if (id != prot->reqid) { - DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", - dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); - ret = -EINVAL; - goto done; - } - - /* Copy info buffer */ - if (buf) - { - if (ret < (int)len) - len = ret; - memcpy(buf, (void*) prot->buf, len); - } - - /* Check the ERROR flag */ - if (flags & CDCF_IOC_ERROR) - { - ret = ltoh32(msg->status); - /* Cache error from dongle */ - dhd->dongle_error = ret; - } - -done: - return ret; -} - - -static int -dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - dhd_prot_t *prot = dhd->prot; - cdc_ioctl_t *msg = &prot->msg; - int ret = 0; - uint32 flags, id; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - return -EIO; - } - - /* don't talk to the dongle if fw is about to be reloaded */ - if (dhd->hang_was_sent) { - DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", - __FUNCTION__)); - return -EIO; - } - - memset(msg, 0, sizeof(cdc_ioctl_t)); - - msg->cmd = htol32(cmd); - msg->len = htol32(len); - msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); - CDC_SET_IF_IDX(msg, ifidx); - /* add additional action bits */ - action &= WL_IOCTL_ACTION_MASK; - msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; - msg->flags = htol32(msg->flags); - - if (buf) - memcpy(prot->buf, buf, len); - - if ((ret = dhdcdc_msg(dhd)) < 0) { - DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret)); - goto done; - } - - if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) - goto done; - - flags = ltoh32(msg->flags); - id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; - - if (id != prot->reqid) { - DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", - dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); - ret = -EINVAL; - goto done; - } - - /* Check the ERROR flag */ - if (flags & CDCF_IOC_ERROR) - { - ret = ltoh32(msg->status); - /* Cache error from dongle */ - dhd->dongle_error = ret; - } - -done: - return ret; -} - - -int -dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) -{ - dhd_prot_t *prot = dhd->prot; - int ret = -1; - uint8 action; - - if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - goto done; - } - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(len <= WLC_IOCTL_MAXLEN); - - if (len > WLC_IOCTL_MAXLEN) - goto done; - - if (prot->pending == TRUE) { - DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", - ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, - (unsigned long)prot->lastcmd)); - if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { - DHD_TRACE(("iovar cmd=%s\n", (char*)buf)); - } - goto done; - } - - prot->pending = TRUE; - prot->lastcmd = ioc->cmd; - action = ioc->set; - if (action & WL_IOCTL_ACTION_SET) - ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - else { - ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - if (ret > 0) - ioc->used = ret - sizeof(cdc_ioctl_t); - } - - /* Too many programs assume ioctl() returns 0 on success */ - if (ret >= 0) - ret = 0; - else { - cdc_ioctl_t *msg = &prot->msg; - ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ - } - - /* Intercept the wme_dp ioctl here */ - if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { - int slen, val = 0; - - slen = strlen("wme_dp") + 1; - if (len >= (int)(slen + sizeof(int))) - bcopy(((char *)buf + slen), &val, sizeof(int)); - dhd->wme_dp = (uint8) ltoh32(val); - } - - prot->pending = FALSE; - -done: - - return ret; -} - -int -dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - return BCME_UNSUPPORTED; -} - -void -dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); -#ifdef PROP_TXSTATUS - dhd_wlfc_dump(dhdp, strbuf); -#endif -} - -/* The FreeBSD PKTPUSH could change the packet buf pinter - so we need to make it changable -*/ -#define PKTBUF pktbuf -void -dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) -{ -#ifdef BDC - struct bdc_header *h; -#endif /* BDC */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BDC - /* Push BDC header used to convey priority for buses that don't */ - - PKTPUSH(dhd->osh, PKTBUF, BDC_HEADER_LEN); - - h = (struct bdc_header *)PKTDATA(dhd->osh, PKTBUF); - - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (PKTSUMNEEDED(PKTBUF)) - h->flags |= BDC_FLAG_SUM_NEEDED; - - - h->priority = (PKTPRIO(PKTBUF) & BDC_PRIORITY_MASK); - h->flags2 = 0; - h->dataOffset = 0; -#endif /* BDC */ - BDC_SET_IF_IDX(h, ifidx); -} -#undef PKTBUF /* Only defined in the above routine */ - -int -dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, - uint *reorder_info_len) -{ -#ifdef BDC - struct bdc_header *h; -#endif - uint8 data_offset = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BDC - if (reorder_info_len) - *reorder_info_len = 0; - /* Pop BDC header used to convey priority for buses that don't */ - - if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { - DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN)); - return BCME_ERROR; - } - - h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); - - if (!ifidx) { - /* for tx packet, skip the analysis */ - data_offset = h->dataOffset; - PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); - goto exit; - } - - if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { - DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", - __FUNCTION__, *ifidx)); - return BCME_ERROR; - } - - if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { - DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", - dhd_ifname(dhd, *ifidx), h->flags)); - if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) - h->dataOffset = 0; - else - return BCME_ERROR; - } - - if (h->flags & BDC_FLAG_SUM_GOOD) { - DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n", - dhd_ifname(dhd, *ifidx), h->flags)); - PKTSETSUMGOOD(pktbuf, TRUE); - } - - PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); - data_offset = h->dataOffset; - PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); -#endif /* BDC */ - - -#ifdef PROP_TXSTATUS - if (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf))) { - /* - - parse txstatus only for packets that came from the firmware - */ - dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), - reorder_buf_info, reorder_info_len); - - } -#endif /* PROP_TXSTATUS */ - -exit: - PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); - return 0; -} - - -int -dhd_prot_attach(dhd_pub_t *dhd) -{ - dhd_prot_t *cdc; - - if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - memset(cdc, 0, sizeof(dhd_prot_t)); - - /* ensure that the msg buf directly follows the cdc msg struct */ - if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) { - DHD_ERROR(("dhd_prot_t is not correctly defined\n")); - goto fail; - } - - dhd->prot = cdc; -#ifdef BDC - dhd->hdrlen += BDC_HEADER_LEN; -#endif - dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN; - return 0; - -fail: - if (cdc != NULL) - DHD_OS_PREFREE(dhd, cdc, sizeof(dhd_prot_t)); - return BCME_NOMEM; -} - -/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ -void -dhd_prot_detach(dhd_pub_t *dhd) -{ -#ifdef PROP_TXSTATUS - dhd_wlfc_deinit(dhd); -#endif - DHD_OS_PREFREE(dhd, dhd->prot, sizeof(dhd_prot_t)); - dhd->prot = NULL; -} - -void -dhd_prot_dstats(dhd_pub_t *dhd) -{ -/* No stats from dongle added yet, copy bus stats */ - dhd->dstats.tx_packets = dhd->tx_packets; - dhd->dstats.tx_errors = dhd->tx_errors; - dhd->dstats.rx_packets = dhd->rx_packets; - dhd->dstats.rx_errors = dhd->rx_errors; - dhd->dstats.rx_dropped = dhd->rx_dropped; - dhd->dstats.multicast = dhd->rx_multicast; - return; -} - -int -dhd_prot_init(dhd_pub_t *dhd) -{ - int ret = 0; - wlc_rev_info_t revinfo; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - - /* Get the device rev info */ - memset(&revinfo, 0, sizeof(revinfo)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); - if (ret < 0) - goto done; - - - ret = dhd_preinit_ioctls(dhd); - - /* Always assumes wl for now */ - dhd->iswl = TRUE; - -done: - return ret; -} - -void -dhd_prot_stop(dhd_pub_t *dhd) -{ -/* Nothing to do for CDC */ -} - - -static void -dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, - uint32 *pkt_count, void **pplast, uint8 start, uint8 end) -{ - void *plast = NULL, *p; - uint32 pkt_cnt = 0; - - if (ptr->pend_pkts == 0) { - DHD_REORDER(("%s: no packets in reorder queue \n", __FUNCTION__)); - *pplast = NULL; - *pkt_count = 0; - *pkt = NULL; - return; - } - do { - p = (void *)(ptr->p[start]); - ptr->p[start] = NULL; - - if (p != NULL) { - if (plast == NULL) - *pkt = p; - else - PKTSETNEXT(osh, plast, p); - - plast = p; - pkt_cnt++; - } - start++; - if (start > ptr->max_idx) - start = 0; - } while (start != end); - *pplast = plast; - *pkt_count = pkt_cnt; - ptr->pend_pkts -= (uint8)pkt_cnt; -} - -int -dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, - void **pkt, uint32 *pkt_count) -{ - uint8 flow_id, max_idx, cur_idx, exp_idx; - struct reorder_info *ptr; - uint8 flags; - void *cur_pkt, *plast = NULL; - uint32 cnt = 0; - - if (pkt == NULL) { - if (pkt_count != NULL) - *pkt_count = 0; - return 0; - } - - flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; - flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; - - DHD_REORDER(("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags, - reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET], - reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET], - reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET])); - - /* validate flags and flow id */ - if (flags == 0xFF) { - DHD_ERROR(("%s: invalid flags...so ignore this packet\n", __FUNCTION__)); - *pkt_count = 1; - return 0; - } - - cur_pkt = *pkt; - *pkt = NULL; - - ptr = dhd->reorder_bufs[flow_id]; - if (flags & WLHOST_REORDERDATA_DEL_FLOW) { - uint32 buf_size = sizeof(struct reorder_info); - - DHD_REORDER(("%s: Flags indicating to delete a flow id %d\n", - __FUNCTION__, flow_id)); - - if (ptr == NULL) { - DHD_REORDER(("%s: received flags to cleanup, but no flow (%d) yet\n", - __FUNCTION__, flow_id)); - *pkt_count = 1; - *pkt = cur_pkt; - return 0; - } - - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - ptr->exp_idx, ptr->exp_idx); - /* set it to the last packet */ - if (plast) { - PKTSETNEXT(dhd->osh, plast, cur_pkt); - cnt++; - } - else { - if (cnt != 0) { - DHD_ERROR(("%s: del flow: something fishy, pending packets %d\n", - __FUNCTION__, cnt)); - } - *pkt = cur_pkt; - cnt = 1; - } - buf_size += ((ptr->max_idx + 1) * sizeof(void *)); - MFREE(dhd->osh, ptr, buf_size); - dhd->reorder_bufs[flow_id] = NULL; - *pkt_count = cnt; - return 0; - } - /* all the other cases depend on the existance of the reorder struct for that flow id */ - if (ptr == NULL) { - uint32 buf_size_alloc = sizeof(reorder_info_t); - max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; - - buf_size_alloc += ((max_idx + 1) * sizeof(void*)); - /* allocate space to hold the buffers, index etc */ - - DHD_REORDER(("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n", - __FUNCTION__, buf_size_alloc, flow_id, max_idx)); - ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc); - if (ptr == NULL) { - DHD_ERROR(("%s: Malloc failed to alloc buffer\n", __FUNCTION__)); - *pkt_count = 1; - return 0; - } - bzero(ptr, buf_size_alloc); - dhd->reorder_bufs[flow_id] = ptr; - ptr->p = (void *)(ptr+1); - ptr->max_idx = max_idx; - } - if (flags & WLHOST_REORDERDATA_NEW_HOLE) { - DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__)); - if (ptr->pend_pkts) { - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - ptr->exp_idx, ptr->exp_idx); - ptr->pend_pkts = 0; - } - ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; - ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; - ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; - ptr->p[ptr->cur_idx] = cur_pkt; - ptr->pend_pkts++; - *pkt_count = cnt; - } - else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) { - cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; - exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; - - - if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) { - /* still in the current hole */ - /* enqueue the current on the buffer chain */ - if (ptr->p[cur_idx] != NULL) { - DHD_REORDER(("%s: HOLE: ERROR buffer pending..free it\n", - __FUNCTION__)); - PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); - ptr->p[cur_idx] = NULL; - } - ptr->p[cur_idx] = cur_pkt; - ptr->pend_pkts++; - ptr->cur_idx = cur_idx; - DHD_REORDER(("%s: fill up a hole..pending packets is %d\n", - __FUNCTION__, ptr->pend_pkts)); - *pkt_count = 0; - *pkt = NULL; - } - else if (ptr->exp_idx == cur_idx) { - /* got the right one ..flush from cur to exp and update exp */ - DHD_REORDER(("%s: got the right one now, cur_idx is %d\n", - __FUNCTION__, cur_idx)); - if (ptr->p[cur_idx] != NULL) { - DHD_REORDER(("%s: Error buffer pending..free it\n", - __FUNCTION__)); - PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); - ptr->p[cur_idx] = NULL; - } - ptr->p[cur_idx] = cur_pkt; - ptr->pend_pkts++; - - ptr->cur_idx = cur_idx; - ptr->exp_idx = exp_idx; - - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - cur_idx, exp_idx); - *pkt_count = cnt; - DHD_REORDER(("%s: freeing up buffers %d, still pending %d\n", - __FUNCTION__, cnt, ptr->pend_pkts)); - } - else { - uint8 end_idx; - bool flush_current = FALSE; - /* both cur and exp are moved now .. */ - DHD_REORDER(("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n", - __FUNCTION__, flow_id, ptr->cur_idx, cur_idx, - ptr->exp_idx, exp_idx)); - if (flags & WLHOST_REORDERDATA_FLUSH_ALL) - end_idx = ptr->exp_idx; - else - end_idx = exp_idx; - - /* flush pkts first */ - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - ptr->exp_idx, end_idx); - - if (cur_idx == ptr->max_idx) { - if (exp_idx == 0) - flush_current = TRUE; - } else { - if (exp_idx == cur_idx + 1) - flush_current = TRUE; - } - if (flush_current) { - if (plast) - PKTSETNEXT(dhd->osh, plast, cur_pkt); - else - *pkt = cur_pkt; - cnt++; - } - else { - ptr->p[cur_idx] = cur_pkt; - ptr->pend_pkts++; - } - ptr->exp_idx = exp_idx; - ptr->cur_idx = cur_idx; - *pkt_count = cnt; - } - } - else { - uint8 end_idx; - /* no real packet but update to exp_seq...that means explicit window move */ - exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; - - DHD_REORDER(("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n", - __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx)); - if (flags & WLHOST_REORDERDATA_FLUSH_ALL) - end_idx = ptr->exp_idx; - else - end_idx = exp_idx; - - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx); - if (plast) - PKTSETNEXT(dhd->osh, plast, cur_pkt); - else - *pkt = cur_pkt; - cnt++; - *pkt_count = cnt; - /* set the new expected idx */ - ptr->exp_idx = exp_idx; - } - return 0; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c deleted file mode 100755 index bac72e4d560f..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ - */ - -#include -#include - -#include -#include -#include -#include -#include - -#ifdef PKT_FILTER_SUPPORT -#include -#include -#endif -extern struct bcm_cfg80211 *g_bcm_cfg; - -#ifdef PKT_FILTER_SUPPORT -extern uint dhd_pkt_filter_enable; -extern uint dhd_master_mode; -extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -#endif - -static int dhd_dongle_up = FALSE; - -#include -#include -#include -#include -#include - -static s32 wl_dongle_up(struct net_device *ndev, u32 up); - -/** - * Function implementations - */ - -s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg) -{ - dhd_dongle_up = FALSE; - return 0; -} - -s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg) -{ - dhd_dongle_up = FALSE; - return 0; -} - -s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg) -{ - dhd_dongle_up = FALSE; - return 0; -} - -s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val) -{ - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - dhd->op_mode |= val; - WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode)); -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd->arp_version == 1) { - /* IF P2P is enabled, disable arpoe */ - dhd_arp_offload_set(dhd, 0); - dhd_arp_offload_enable(dhd, false); - } -#endif /* ARP_OFFLOAD_SUPPORT */ - - return 0; -} - -s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg) -{ - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); - WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode)); - -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd->arp_version == 1) { - /* IF P2P is disabled, enable arpoe back for STA mode. */ - dhd_arp_offload_set(dhd, dhd_arp_mode); - dhd_arp_offload_enable(dhd, true); - } -#endif /* ARP_OFFLOAD_SUPPORT */ - - return 0; -} - -struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, - uint8 *mac, uint8 bssidx) -{ - return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE); -} - -int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) -{ - return dhd_register_if(cfg->pub, ifidx, FALSE); -} - -int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) -{ - return dhd_remove_if(cfg->pub, ifidx, FALSE); -} - -struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev) -{ - if (ndev) { - if (ndev->ieee80211_ptr) { - kfree(ndev->ieee80211_ptr); - ndev->ieee80211_ptr = NULL; - } - free_netdev(ndev); - return NULL; - } - - return ndev; -} - -void dhd_netdev_free(struct net_device *ndev) -{ -#ifdef WL_CFG80211 - ndev = dhd_cfg80211_netdev_free(ndev); -#endif - if (ndev) - free_netdev(ndev); -} - -static s32 wl_dongle_up(struct net_device *ndev, u32 up) -{ - s32 err = 0; - - err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); - if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); - } - return err; -} - -s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) -{ -#ifndef DHD_SDALIGN -#define DHD_SDALIGN 32 -#endif - struct net_device *ndev; - s32 err = 0; - - WL_TRACE(("In\n")); - if (dhd_dongle_up) { - WL_ERR(("Dongle is already up\n")); - return err; - } - - ndev = bcmcfg_to_prmry_ndev(cfg); - - err = wl_dongle_up(ndev, 0); - if (unlikely(err)) { - WL_ERR(("wl_dongle_up failed\n")); - goto default_conf_out; - } - dhd_dongle_up = true; - -default_conf_out: - - return err; - -} - -#ifdef CONFIG_NL80211_TESTMODE -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) -int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len) -#else -int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ -{ - struct sk_buff *reply; - struct bcm_cfg80211 *cfg; - dhd_pub_t *dhd; - struct bcm_nlmsg_hdr *nlioc = data; - dhd_ioctl_t ioc = { 0 }; - int err = 0; - void *buf = NULL, *cur; - u16 buflen; - u16 maxmsglen = PAGE_SIZE - 0x100; - bool newbuf = false; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) - int8 index = 0; - struct net_device *ndev = NULL; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ - - WL_TRACE(("entry: cmd = %d\n", nlioc->cmd)); - cfg = wiphy_priv(wiphy); - dhd = cfg->pub; - - DHD_OS_WAKE_LOCK(dhd); - - /* send to dongle only if we are not waiting for reload already */ - if (dhd->hang_was_sent) { - WL_ERR(("HANG was sent up earlier\n")); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS); - DHD_OS_WAKE_UNLOCK(dhd); - return OSL_ERROR(BCME_DONGLE_DOWN); - } - - len -= sizeof(struct bcm_nlmsg_hdr); - - if (nlioc->len > 0) { - if (nlioc->len <= len) { - buf = (void *)nlioc + nlioc->offset; - *(char *)(buf + nlioc->len) = '\0'; - } else { - if (nlioc->len > DHD_IOCTL_MAXLEN) - nlioc->len = DHD_IOCTL_MAXLEN; - buf = vzalloc(nlioc->len); - if (!buf) - return -ENOMEM; - newbuf = true; - memcpy(buf, (void *)nlioc + nlioc->offset, len); - *(char *)(buf + len) = '\0'; - } - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) - ndev = wdev_to_wlc_ndev(wdev, cfg); - index = dhd_net2idx(dhd->info, ndev); - if (index == DHD_BAD_IF) { - WL_ERR(("Bad ifidx from wdev:%p\n", wdev)); - return BCME_ERROR; -} -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ - - ioc.cmd = nlioc->cmd; - ioc.len = nlioc->len; - ioc.set = nlioc->set; - ioc.driver = nlioc->magic; - err = dhd_ioctl_process(dhd, 0, &ioc, buf); - if (err) { - WL_TRACE(("dhd_ioctl_process return err %d\n", err)); - err = OSL_ERROR(err); - goto done; - } - - cur = buf; - while (nlioc->len > 0) { - buflen = nlioc->len > maxmsglen ? maxmsglen : nlioc->len; - nlioc->len -= buflen; - reply = cfg80211_testmode_alloc_reply_skb(wiphy, buflen+4); - if (!reply) { - WL_ERR(("Failed to allocate reply msg\n")); - err = -ENOMEM; - break; - } - - if (nla_put(reply, BCM_NLATTR_DATA, buflen, cur) || - nla_put_u16(reply, BCM_NLATTR_LEN, buflen)) { - kfree_skb(reply); - err = -ENOBUFS; - break; - } - - do { - err = cfg80211_testmode_reply(reply); - } while (err == -EAGAIN); - if (err) { - WL_ERR(("testmode reply failed:%d\n", err)); - break; - } - cur += buflen; - } - -done: - if (newbuf) - vfree(buf); - DHD_OS_WAKE_UNLOCK(dhd); - return err; -} -#endif /* CONFIG_NL80211_TESTMODE */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h deleted file mode 100755 index fbc10f211adc..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ - */ - - -#ifndef __DHD_CFG80211__ -#define __DHD_CFG80211__ - -#include -#include - -s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg); -s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg); -s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg); -s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val); -s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg); -s32 dhd_config_dongle(struct bcm_cfg80211 *cfg); - -#ifdef CONFIG_NL80211_TESTMODE -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) -int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len); -#else -int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ -#else -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) -static inline int -dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len) -#else -static inline int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ -{ - return 0; -} -#endif /* CONFIG_NL80211_TESTMODE */ - -#endif /* __DHD_CFG80211__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c deleted file mode 100755 index d89d8220ae11..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c +++ /dev/null @@ -1,2356 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), common DHD core. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_common.c 732203 2017-11-16 05:18:28Z $ - */ -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#ifdef WL_CFG80211 -#include -#endif -#ifdef PNO_SUPPORT -#include -#endif -#ifdef RTT_SUPPORT -#include -#endif -#ifdef SET_RANDOM_MAC_SOFTAP -#include -#include -#endif -#ifdef RTT_SUPPORT -#include -#endif -#define htod32(i) (i) -#define htod16(i) (i) -#define dtoh32(i) (i) -#define dtoh16(i) (i) -#define htodchanspec(i) (i) -#define dtohchanspec(i) (i) - -#ifdef PROP_TXSTATUS -#include -#include -#endif - -#ifdef WLMEDIA_HTSF -extern void htsf_update(struct dhd_info *dhd, void *data); -#endif -int dhd_msg_level = DHD_ERROR_VAL; - - -#if defined(WL_WIRELESS_EXT) -#include -#endif - -#ifdef SOFTAP -char fw_path2[MOD_PARAM_PATHLEN]; -extern bool softap_enabled; -#endif - -/* Last connection success/failure status */ -uint32 dhd_conn_event; -uint32 dhd_conn_status; -uint32 dhd_conn_reason; - -extern int dhd_iscan_request(void * dhdp, uint16 action); -extern void dhd_ind_scan_confirm(void *h, bool status); -extern int dhd_iscan_in_progress(void *h); -void dhd_iscan_lock(void); -void dhd_iscan_unlock(void); -extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); -#if !defined(AP) && defined(WLP2P) -extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); -#endif -bool ap_cfg_running = FALSE; -bool ap_fw_loaded = FALSE; - -/* Version string to report */ -#ifdef DHD_DEBUG -#ifndef SRCBASE -#define SRCBASE "drivers/net/wireless/bcmdhd_suzuran" -#endif -#define DHD_COMPILED "\nCompiled in " SRCBASE -#endif /* DHD_DEBUG */ - -#if defined(DHD_DEBUG) -const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR - DHD_COMPILED " on " __DATE__ " at " __TIME__; -#else -const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nCompiled from "; -#endif - -void dhd_set_timer(void *bus, uint wdtick); - -/* IOVar table */ -enum { - IOV_VERSION = 1, - IOV_MSGLEVEL, - IOV_BCMERRORSTR, - IOV_BCMERROR, - IOV_WDTICK, - IOV_DUMP, - IOV_CLEARCOUNTS, - IOV_LOGDUMP, - IOV_LOGCAL, - IOV_LOGSTAMP, - IOV_GPIOOB, - IOV_IOCTLTIMEOUT, -#if defined(DHD_DEBUG) - IOV_CONS, - IOV_DCONSOLE_POLL, - IOV_DHD_JOIN_TIMEOUT_DBG, - IOV_SCAN_TIMEOUT, -#endif /* defined(DHD_DEBUG) */ -#ifdef PROP_TXSTATUS - IOV_PROPTXSTATUS_ENABLE, - IOV_PROPTXSTATUS_MODE, - IOV_PROPTXSTATUS_OPT, - IOV_PROPTXSTATUS_MODULE_IGNORE, - IOV_PROPTXSTATUS_CREDIT_IGNORE, - IOV_PROPTXSTATUS_TXSTATUS_IGNORE, - IOV_PROPTXSTATUS_RXPKT_CHK, -#endif /* PROP_TXSTATUS */ - IOV_BUS_TYPE, -#ifdef WLMEDIA_HTSF - IOV_WLPKTDLYSTAT_SZ, -#endif - IOV_CHANGEMTU, - IOV_HOSTREORDER_FLOWS, -#ifdef DHDTCPACK_SUPPRESS - IOV_TCPACK_SUPPRESS, -#endif /* DHDTCPACK_SUPPRESS */ - IOV_LAST -}; - -const bcm_iovar_t dhd_iovars[] = { - {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, -#ifdef DHD_DEBUG - {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, -#endif /* DHD_DEBUG */ - {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, - {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, - {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, - {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, -#ifdef DHD_DEBUG - {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, - {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, - {"scan_timeout", IOV_SCAN_TIMEOUT, 0, IOVT_UINT32, 0 }, - {"join_timeout_dbg", IOV_DHD_JOIN_TIMEOUT_DBG, 0, IOVT_UINT32, 0 }, -#endif - {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, - {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, - {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, -#ifdef PROP_TXSTATUS - {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_BOOL, 0 }, - /* - set the proptxtstatus operation mode: - 0 - Do not do any proptxtstatus flow control - 1 - Use implied credit from a packet status - 2 - Use explicit credit - */ - {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, - {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, IOVT_UINT32, 0 }, - {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, IOVT_BOOL, 0 }, - {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, IOVT_BOOL, 0 }, - {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, IOVT_BOOL, 0 }, - {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, IOVT_BOOL, 0 }, -#endif /* PROP_TXSTATUS */ - {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, -#ifdef WLMEDIA_HTSF - {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, -#endif - {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, - {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER, - (WLHOST_REORDERDATA_MAXFLOWS + 1) }, -#ifdef DHDTCPACK_SUPPRESS - {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, IOVT_UINT8, 0 }, -#endif /* DHDTCPACK_SUPPRESS */ - {NULL, 0, 0, 0, 0 } -}; - -#define DHD_IOVAR_BUF_SIZE 128 - - -void dhd_save_fwdump(dhd_pub_t *dhd_pub, void * buffer, uint32 length) -{ - - if (dhd_pub->soc_ram == NULL) { - dhd_pub->soc_ram = (uint8*) MALLOCZ(dhd_pub->osh, length); - if (dhd_pub->soc_ram == NULL) { - DHD_ERROR(("%s: Failed to allocate memory for fw crash snap shot.\n", - __FUNCTION__)); - return; - } - } - dhd_pub->soc_ram_length = length; - memcpy(dhd_pub->soc_ram, buffer, length); -} - -/* to NDIS developer, the structure dhd_common is redundant, - * please do NOT merge it back from other branches !!! - */ - -static int -dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) -{ - char eabuf[ETHER_ADDR_STR_LEN]; - - struct bcmstrbuf b; - struct bcmstrbuf *strbuf = &b; - - bcm_binit(strbuf, buf, buflen); - - /* Base DHD info */ - bcm_bprintf(strbuf, "%s\n", dhd_version); - bcm_bprintf(strbuf, "\n"); - bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", - dhdp->up, dhdp->txoff, dhdp->busstate); - bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n", - dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); - bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", - dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); - bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt); - - bcm_bprintf(strbuf, "dongle stats:\n"); - bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n", - dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, - dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); - bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n", - dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, - dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); - bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast); - - bcm_bprintf(strbuf, "bus stats:\n"); - bcm_bprintf(strbuf, "tx_packets %lu tx_multicast %lu tx_errors %lu\n", - dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors); - bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", - dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); - bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n", - dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); - bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n", - dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); - bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n", - dhdp->rx_readahead_cnt, dhdp->tx_realloc); - bcm_bprintf(strbuf, "\n"); - - /* Add any prot info */ - dhd_prot_dump(dhdp, strbuf); - bcm_bprintf(strbuf, "\n"); - - /* Add any bus info */ - dhd_bus_dump(dhdp, strbuf); - - return (!strbuf->size ? BCME_BUFTOOSHORT : 0); -} - -int -dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex) -{ - wl_ioctl_t ioc; - - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; - ioc.set = set; - - return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); -} - - -int -dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len) -{ - int ret = 0; - - if (dhd_os_proto_block(dhd_pub)) - { - - ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); - if ((ret) && (dhd_pub->up)) - /* Send hang event only if dhd_open() was success */ - dhd_os_check_hang(dhd_pub, ifindex, ret); - - if (ret == -ETIMEDOUT && !dhd_pub->up) { - DHD_ERROR(("%s: 'resumed on timeout' error is " - "occurred before the interface does not" - " bring up\n", __FUNCTION__)); - dhd_pub->busstate = DHD_BUS_DOWN; - } - - dhd_os_proto_unblock(dhd_pub); - - - } - - return ret; -} - -static int -dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - switch (actionid) { - case IOV_GVAL(IOV_VERSION): - /* Need to have checked buffer length */ - bcm_strncpy_s((char*)arg, len, dhd_version, len); - break; - - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)dhd_msg_level; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): -#ifdef WL_CFG80211 - /* Enable DHD and WL logs in oneshot */ - if (int_val & DHD_WL_VAL2) - wl_cfg80211_enable_trace(TRUE, int_val & (~DHD_WL_VAL2)); - else if (int_val & DHD_WL_VAL) - wl_cfg80211_enable_trace(FALSE, WL_DBG_DBG); - if (!(int_val & DHD_WL_VAL2)) -#endif /* WL_CFG80211 */ - dhd_msg_level = int_val; - break; - case IOV_GVAL(IOV_BCMERRORSTR): - bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); - ((char *)arg)[BCME_STRLEN - 1] = 0x00; - break; - - case IOV_GVAL(IOV_BCMERROR): - int_val = (int32)dhd_pub->bcmerror; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_WDTICK): - int_val = (int32)dhd_watchdog_ms; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WDTICK): - if (!dhd_pub->up) { - bcmerror = BCME_NOTUP; - break; - } - dhd_os_wd_timer(dhd_pub, (uint)int_val); - break; - - case IOV_GVAL(IOV_DUMP): - bcmerror = dhd_dump(dhd_pub, arg, len); - break; - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_SCAN_TIMEOUT): - { - uint32 scan_timeout = dhd_get_scan_timeout(dhd_pub); - bcopy(&scan_timeout, arg, sizeof(scan_timeout)); - break; - } - case IOV_SVAL(IOV_SCAN_TIMEOUT): - { - uint32 scan_timeout; - bcopy(((uint8*)params), &scan_timeout, sizeof(scan_timeout)); - dhd_set_scan_timeout(dhd_pub, scan_timeout); - break; - } - case IOV_GVAL(IOV_DHD_JOIN_TIMEOUT_DBG): - { - uint32 join_timeout = dhd_get_join_timeout(dhd_pub); - bcopy(&join_timeout, arg, sizeof(join_timeout)); - break; - } - case IOV_SVAL(IOV_DHD_JOIN_TIMEOUT_DBG): - { - uint32 join_timeout; - bcopy(((uint8*)params), &join_timeout, sizeof(join_timeout)); - dhd_set_join_timeout(dhd_pub, join_timeout); - break; - } -#endif /* DHD_DEBUG */ - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_DCONSOLE_POLL): - int_val = (int32)dhd_console_ms; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DCONSOLE_POLL): - dhd_console_ms = (uint)int_val; - break; - - case IOV_SVAL(IOV_CONS): - if (len > 0) - bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); - break; -#endif /* DHD_DEBUG */ - - case IOV_SVAL(IOV_CLEARCOUNTS): - dhd_pub->tx_packets = dhd_pub->rx_packets = 0; - dhd_pub->tx_errors = dhd_pub->rx_errors = 0; - dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; - dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; - dhd_pub->rx_dropped = 0; - dhd_pub->rx_readahead_cnt = 0; - dhd_pub->tx_realloc = 0; - dhd_pub->wd_dpc_sched = 0; - memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); - dhd_bus_clearcounts(dhd_pub); -#ifdef PROP_TXSTATUS - /* clear proptxstatus related counters */ - dhd_wlfc_clear_counts(dhd_pub); -#endif /* PROP_TXSTATUS */ - break; - - - case IOV_GVAL(IOV_IOCTLTIMEOUT): { - int_val = (int32)dhd_os_get_ioctl_resp_timeout(); - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_IOCTLTIMEOUT): { - if (int_val <= 0) - bcmerror = BCME_BADARG; - else - dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); - break; - } - - -#ifdef PROP_TXSTATUS - case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): { - bool wlfc_enab = FALSE; - bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); - if (bcmerror != BCME_OK) - goto exit; - int_val = wlfc_enab ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): { - bool wlfc_enab = FALSE; - bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); - if (bcmerror != BCME_OK) - goto exit; - - /* wlfc is already set as desired */ - if (wlfc_enab == (int_val == 0 ? FALSE : TRUE)) - goto exit; - - if (int_val == TRUE) - bcmerror = dhd_wlfc_init(dhd_pub); - else - bcmerror = dhd_wlfc_deinit(dhd_pub); - - break; - } - case IOV_GVAL(IOV_PROPTXSTATUS_MODE): - bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_MODE): - dhd_wlfc_set_mode(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): - bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): - dhd_wlfc_set_module_ignore(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): - bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): - dhd_wlfc_set_credit_ignore(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): - bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): - dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK): - bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK): - dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val); - break; - -#endif /* PROP_TXSTATUS */ - - case IOV_GVAL(IOV_BUS_TYPE): - /* The dhd application queries the driver to check if its usb or sdio. */ -#ifdef BCMDHDUSB - int_val = BUS_TYPE_USB; -#endif - int_val = BUS_TYPE_SDIO; -#ifdef PCIE_FULL_DONGLE - int_val = BUS_TYPE_PCIE; -#endif - bcopy(&int_val, arg, val_size); - break; - - -#ifdef WLMEDIA_HTSF - case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): - int_val = dhd_pub->htsfdlystat_sz; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): - dhd_pub->htsfdlystat_sz = int_val & 0xff; - printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); - break; -#endif - case IOV_SVAL(IOV_CHANGEMTU): - int_val &= 0xffff; - bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); - break; - - case IOV_GVAL(IOV_HOSTREORDER_FLOWS): - { - uint i = 0; - uint8 *ptr = (uint8 *)arg; - uint8 count = 0; - - ptr++; - for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { - if (dhd_pub->reorder_bufs[i] != NULL) { - *ptr = dhd_pub->reorder_bufs[i]->flow_id; - ptr++; - count++; - } - } - ptr = (uint8 *)arg; - *ptr = count; - break; - } -#ifdef DHDTCPACK_SUPPRESS - case IOV_GVAL(IOV_TCPACK_SUPPRESS): { - int_val = (uint32)dhd_pub->tcpack_sup_mode; - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_TCPACK_SUPPRESS): { - bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val); - break; - } -#endif /* DHDTCPACK_SUPPRESS */ - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } - -exit: - DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); - return bcmerror; -} - -/* Store the status of a connection attempt for later retrieval by an iovar */ -void -dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) -{ - /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID - * because an encryption/rsn mismatch results in both events, and - * the important information is in the WLC_E_PRUNE. - */ - if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && - dhd_conn_event == WLC_E_PRUNE)) { - dhd_conn_event = event; - dhd_conn_status = status; - dhd_conn_reason = reason; - } -} - -bool -dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) -{ - void *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)) { - 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 = pktq_peek_tail(q, &eprec); - ASSERT(p); - if (eprec > prec || eprec < 0) - return FALSE; - } - - /* Evict if needed */ - if (eprec >= 0) { - /* Detect queueing to unconfigured precedence */ - ASSERT(!pktq_pempty(q, eprec)); - discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); - if (eprec == prec && !discard_oldest) - return FALSE; /* refuse newer (incoming) packet */ - /* Evict packet according to discard policy */ - p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); - ASSERT(p); -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - PKTFREE(dhdp->osh, p, TRUE); - } - - /* Enqueue */ - p = pktq_penq(q, prec, pkt); - ASSERT(p); - - return TRUE; -} - -/* - * Functions to drop proper pkts from queue: - * If one pkt in queue is non-fragmented, drop first non-fragmented pkt only - * If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts - * If can't find pkts matching upper 2 cases, drop first pkt anyway - */ -bool -dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn) -{ - struct pktq_prec *q = NULL; - void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL; - pkt_frag_t frag_info; - - ASSERT(dhdp && pq); - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - p = q->head; - - if (p == NULL) - return FALSE; - - while (p) { - frag_info = pkt_frag_info(dhdp->osh, p); - if (frag_info == DHD_PKT_FRAG_NONE) { - break; - } else if (frag_info == DHD_PKT_FRAG_FIRST) { - if (first) { - /* No last frag pkt, use prev as last */ - last = prev; - break; - } else { - first = p; - prev_first = prev; - } - } else if (frag_info == DHD_PKT_FRAG_LAST) { - if (first) { - last = p; - break; - } - } - - prev = p; - p = PKTLINK(p); - } - - if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) { - /* Not found matching pkts, use oldest */ - prev = NULL; - p = q->head; - frag_info = 0; - } - - if (frag_info == DHD_PKT_FRAG_NONE) { - first = last = p; - prev_first = prev; - } - - p = first; - while (p) { - next = PKTLINK(p); - q->len--; - pq->len--; - - PKTSETLINK(p, NULL); - - if (fn) - fn(dhdp, prec, p, TRUE); - - if (p == last) - break; - - p = next; - } - - if (prev_first == NULL) { - if ((q->head = next) == NULL) - q->tail = NULL; - } else { - PKTSETLINK(prev_first, next); - if (!next) - q->tail = prev_first; - } - - return TRUE; -} - -static int -dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - int bcmerror = 0; - int val_size; - const bcm_iovar_t *vi = NULL; - uint32 actionid; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - - bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} - -int -dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) -{ - int bcmerror = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!buf) { - return BCME_BADARG; - } - - switch (ioc->cmd) { - case DHD_GET_MAGIC: - if (buflen < sizeof(int)) - bcmerror = BCME_BUFTOOSHORT; - else - *(int*)buf = DHD_IOCTL_MAGIC; - break; - - case DHD_GET_VERSION: - if (buflen < sizeof(int)) - bcmerror = BCME_BUFTOOSHORT; - else - *(int*)buf = DHD_IOCTL_VERSION; - break; - - case DHD_GET_VAR: - case DHD_SET_VAR: { - char *arg; - uint arglen; - - /* scan past the name to any arguments */ - for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) - ; - - if (*arg) { - bcmerror = BCME_BUFTOOSHORT; - break; - } - - /* account for the NUL terminator */ - arg++, arglen--; - - /* call with the appropriate arguments */ - if (ioc->cmd == DHD_GET_VAR) - bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, - buf, buflen, IOV_GET); - else - bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); - if (bcmerror != BCME_UNSUPPORTED) - break; - - /* not in generic table, try protocol module */ - if (ioc->cmd == DHD_GET_VAR) - bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, - arglen, buf, buflen, IOV_GET); - else - bcmerror = dhd_prot_iovar_op(dhd_pub, buf, - NULL, 0, arg, arglen, IOV_SET); - if (bcmerror != BCME_UNSUPPORTED) - break; - - /* if still not found, try bus module */ - if (ioc->cmd == DHD_GET_VAR) { - bcmerror = dhd_bus_iovar_op(dhd_pub, buf, - arg, arglen, buf, buflen, IOV_GET); - } else { - bcmerror = dhd_bus_iovar_op(dhd_pub, buf, - NULL, 0, arg, arglen, IOV_SET); - } - - break; - } - - default: - bcmerror = BCME_UNSUPPORTED; - } - - return bcmerror; -} - -#ifdef SHOW_EVENTS -static void -wl_show_host_event(wl_event_msg_t *event, void *event_data) -{ - uint i, status, reason; - bool group = FALSE, flush_txq = FALSE, link = FALSE; - const char *auth_str; - const char *event_name; - uchar *buf; - char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; - uint event_type, flags, auth_type, datalen; - - event_type = ntoh32(event->event_type); - flags = ntoh16(event->flags); - status = ntoh32(event->status); - reason = ntoh32(event->reason); - BCM_REFERENCE(reason); - auth_type = ntoh32(event->auth_type); - datalen = ntoh32(event->datalen); - - /* debug dump of event messages */ - snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", - (uchar)event->addr.octet[0]&0xff, - (uchar)event->addr.octet[1]&0xff, - (uchar)event->addr.octet[2]&0xff, - (uchar)event->addr.octet[3]&0xff, - (uchar)event->addr.octet[4]&0xff, - (uchar)event->addr.octet[5]&0xff); - - event_name = "UNKNOWN"; - for (i = 0; i < (uint)bcmevent_names_size; i++) - if (bcmevent_names[i].event == event_type) - event_name = bcmevent_names[i].name; - - if (flags & WLC_EVENT_MSG_LINK) - link = TRUE; - if (flags & WLC_EVENT_MSG_GROUP) - group = TRUE; - if (flags & WLC_EVENT_MSG_FLUSHTXQ) - flush_txq = TRUE; - - switch (event_type) { - case WLC_E_START: - case WLC_E_DEAUTH: - case WLC_E_DISASSOC: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - - case WLC_E_ASSOC_IND: - case WLC_E_REASSOC_IND: - - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - - case WLC_E_ASSOC: - case WLC_E_REASSOC: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", - event_name, eabuf, (int)reason)); - } else { - DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n", - event_name, eabuf, (int)status)); - } - break; - - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC_IND: - DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); - break; - - case WLC_E_AUTH: - case WLC_E_AUTH_IND: - if (auth_type == DOT11_OPEN_SYSTEM) - auth_str = "Open System"; - else if (auth_type == DOT11_SHARED_KEY) - auth_str = "Shared Key"; - else { - snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); - auth_str = err_msg; - } - if (event_type == WLC_E_AUTH_IND) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", - event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", - event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", - event_name, eabuf, auth_str, (int)reason)); - } - BCM_REFERENCE(auth_str); - - break; - - case WLC_E_JOIN: - case WLC_E_ROAM: - case WLC_E_SET_SSID: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, failed\n", event_name)); - } else if (status == WLC_E_STATUS_NO_NETWORKS) { - DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name)); - } else { - DHD_EVENT(("MACEVENT: %s, unexpected status %d\n", - event_name, (int)status)); - } - break; - - case WLC_E_BEACON_RX: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); - } else { - DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); - } - break; - - case WLC_E_LINK: - DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); - BCM_REFERENCE(link); - break; - - case WLC_E_MIC_ERROR: - DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", - event_name, eabuf, group, flush_txq)); - BCM_REFERENCE(group); - BCM_REFERENCE(flush_txq); - break; - - case WLC_E_ICV_ERROR: - case WLC_E_UNICAST_DECODE_ERROR: - case WLC_E_MULTICAST_DECODE_ERROR: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", - event_name, eabuf)); - break; - - case WLC_E_TXFAIL: - DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf)); - break; - - case WLC_E_SCAN_COMPLETE: - case WLC_E_ASSOC_REQ_IE: - case WLC_E_ASSOC_RESP_IE: - case WLC_E_PMKID_CACHE: - DHD_EVENT(("MACEVENT: %s\n", event_name)); - break; - - case WLC_E_PFN_NET_FOUND: - case WLC_E_PFN_NET_LOST: - case WLC_E_PFN_SCAN_COMPLETE: - case WLC_E_PFN_SCAN_NONE: - case WLC_E_PFN_SCAN_ALLGONE: - DHD_EVENT(("PNOEVENT: %s\n", event_name)); - break; - - case WLC_E_PSK_SUP: - case WLC_E_PRUNE: - DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason)); - break; - -#ifdef WIFI_ACT_FRAME - case WLC_E_ACTION_FRAME: - DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); - break; -#endif /* WIFI_ACT_FRAME */ - - case WLC_E_TRACE: { - static uint32 seqnum_prev = 0; - static uint32 logtrace_seqnum_prev = 0; - msgtrace_hdr_t hdr; - uint32 nblost; - char *s, *p; - - buf = (uchar *) event_data; - memcpy(&hdr, buf, MSGTRACE_HDRLEN); - - if (hdr.version != MSGTRACE_VERSION) { - printf("\nMACEVENT: %s [unsupported version --> " - "dhd version:%d dongle version:%d]\n", - event_name, MSGTRACE_VERSION, hdr.version); - /* Reset datalen to avoid display below */ - datalen = 0; - break; - } - - if (hdr.trace_type == MSGTRACE_HDR_TYPE_MSG) { - /* There are 2 bytes available at the end of data */ - buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; - - if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { - printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" - "discarded_bytes %d discarded_printf %d]\n", - ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); - } - - nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; - if (nblost > 0) { - printf("\nWLC_E_TRACE: [Event lost (msg) --> seqnum %d nblost %d\n", - ntoh32(hdr.seqnum), nblost); - } - seqnum_prev = ntoh32(hdr.seqnum); - - /* Display the trace buffer. Advance from \n to \n to avoid display big - * printf (issue with Linux printk ) - */ - p = (char *)&buf[MSGTRACE_HDRLEN]; - while (*p != '\0' && (s = strstr(p, "\n")) != NULL) { - *s = '\0'; - printf("WLC_E_TRACE: %s\n", p); - p = s+1; - } - if (*p) printf("WLC_E_TRACE: %s", p); - - /* Reset datalen to avoid display below */ - datalen = 0; - - } else if (hdr.trace_type == MSGTRACE_HDR_TYPE_LOG) { - /* Let the standard event printing work for now */ - uint32 timestamp, w; - if (ntoh32(hdr.seqnum) == logtrace_seqnum_prev) { - printf("\nWLC_E_TRACE: [Event duplicate (log) %d", - logtrace_seqnum_prev); - } else { - nblost = ntoh32(hdr.seqnum) - logtrace_seqnum_prev - 1; - if (nblost > 0) { - printf("\nWLC_E_TRACE: [Event lost (log)" - " --> seqnum %d nblost %d\n", - ntoh32(hdr.seqnum), nblost); - } - logtrace_seqnum_prev = ntoh32(hdr.seqnum); - - p = (char *)&buf[MSGTRACE_HDRLEN]; - datalen -= MSGTRACE_HDRLEN; - w = ntoh32((uint32) *p); - p += 4; - datalen -= 4; - timestamp = ntoh32((uint32) *p); - printf("Logtrace %x timestamp %x %x", - logtrace_seqnum_prev, timestamp, w); - - while (datalen > 4) { - p += 4; - datalen -= 4; - /* Print each word. DO NOT ntoh it. */ - printf(" %8.8x", *((uint32 *) p)); - } - printf("\n"); - } - datalen = 0; - } - - break; - } - - - case WLC_E_RSSI: - DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); - break; - - case WLC_E_SERVICE_FOUND: - case WLC_E_P2PO_ADD_DEVICE: - case WLC_E_P2PO_DEL_DEVICE: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - - - case WLC_E_CCA_CHAN_QUAL: - if (datalen) { - buf = (uchar *) event_data; - DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d, " - "channel 0x%02x \n", event_name, event_type, eabuf, (int)status, - (int)reason, (int)auth_type, *(buf + 4))); - } - break; - - - default: - DHD_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 (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen) { - buf = (uchar *) event_data; - DHD_EVENT((" data (%d) : ", datalen)); - for (i = 0; i < datalen; i++) - DHD_EVENT((" 0x%02x ", *buf++)); - DHD_EVENT(("\n")); - } -} -#endif /* SHOW_EVENTS */ - -/* Check whether packet is a BRCM event pkt. If it is, record event data. */ -int -wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu) -{ - int ret; - - ret = is_wlc_event_frame(pktdata, pktlen, 0, evu); - if (ret != BCME_OK && ret != -30) { - DHD_ERROR(("%s: Invalid event frame, err = %d\n", - __FUNCTION__, ret)); - } - - return ret; -} - -int -wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, size_t pktlen, - wl_event_msg_t *event, void **data_ptr) -{ - bcm_event_t *pvt_data = (bcm_event_t *)pktdata; - uint8 *event_data; - uint32 type, status, datalen; - uint16 flags; - uint evlen; - int ret; - uint16 usr_subtype; - bcm_event_msg_u_t evu; - - ret = wl_host_event_get_data(pktdata, pktlen, &evu); - if (ret != BCME_OK) { - return ret; - } - - usr_subtype = ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype); - switch (usr_subtype) { - case BCMILCP_BCM_SUBTYPE_EVENT: - memcpy(event, &evu.event, sizeof(wl_event_msg_t)); - *data_ptr = &pvt_data[1]; - break; - - case BCMILCP_BCM_SUBTYPE_DNGLEVENT: - return BCME_NOTFOUND; - - default: - return BCME_NOTFOUND; - } - - /* start wl_event_msg process */ - event_data = *data_ptr; - type = ntoh32_ua((void *)&event->event_type); - flags = ntoh16_ua((void *)&event->flags); - status = ntoh32_ua((void *)&event->status); - datalen = ntoh32_ua((void *)&event->datalen); - - evlen = datalen + sizeof(bcm_event_t); - - switch (type) { -#ifdef DHD_DEBUG - case WLC_E_JOIN_START: - case WLC_E_ROAM_START: - dhd_start_join_timer(dhd_pub); - break; - case WLC_E_ASSOC: - case WLC_E_REASSOC: - if ((status != WLC_E_STATUS_TIMEOUT) && (status != WLC_E_STATUS_FAIL)) - break; - case WLC_E_SET_SSID: - if (status != WLC_E_STATUS_SUCCESS) - break; - case WLC_E_JOIN: - case WLC_E_ROAM: - dhd_del_join_timer(dhd_pub); - break; - - case WLC_E_SCAN_CONFIRM_IND: - dhd_add_scan_timer(dhd_pub); - break; - - case WLC_E_ESCAN_RESULT: - dhd_del_scan_timer(dhd_pub); - break; -#endif /* DHD_DEBUG */ -#ifdef PROP_TXSTATUS - case WLC_E_FIFO_CREDIT_MAP: - dhd_wlfc_enable(dhd_pub); - dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data); - WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " - "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], - event_data[2], - event_data[3], event_data[4], event_data[5])); - break; - - case WLC_E_BCMC_CREDIT_SUPPORT: - dhd_wlfc_BCMCCredit_support_event(dhd_pub); - break; -#endif - - case WLC_E_IF: { - struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data; - - /* Ignore the event if NOIF is set */ - if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) { - DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n")); - return (BCME_UNSUPPORTED); - } - -#ifdef PROP_TXSTATUS - { - uint8* ea = pvt_data->eth.ether_dhost; - WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " - "[%02x:%02x:%02x:%02x:%02x:%02x]\n", - ifevent->ifidx, - ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD":"DEL"), - ((ifevent->role == 0) ? "STA":"AP "), - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); - (void)ea; - - if (ifevent->opcode == WLC_E_IF_CHANGE) - dhd_wlfc_interface_event(dhd_pub, - eWLFC_MAC_ENTRY_ACTION_UPDATE, - ifevent->ifidx, ifevent->role, ea); - else - dhd_wlfc_interface_event(dhd_pub, - ((ifevent->opcode == WLC_E_IF_ADD) ? - eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), - ifevent->ifidx, ifevent->role, ea); - - /* dhd already has created an interface by default, for 0 */ - if (ifevent->ifidx == 0) - break; - } -#endif /* PROP_TXSTATUS */ - - if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { - if (ifevent->opcode == WLC_E_IF_ADD) { - if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname, - event->addr.octet)) { - - DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d %s\n", - __FUNCTION__, ifevent->ifidx, event->ifname)); - return (BCME_ERROR); - } - } else if (ifevent->opcode == WLC_E_IF_DEL) { - dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname, - event->addr.octet); - } else if (ifevent->opcode == WLC_E_IF_CHANGE) { -#ifdef WL_CFG80211 - wl_cfg80211_notify_ifchange(ifevent->ifidx, - event->ifname, event->addr.octet, ifevent->bssidx); -#endif /* WL_CFG80211 */ - } - } else { -#ifndef PROP_TXSTATUS - DHD_ERROR(("%s: Invalid ifidx %d for %s\n", - __FUNCTION__, ifevent->ifidx, event->ifname)); -#endif /* !PROP_TXSTATUS */ - } - - /* send up the if event: btamp user needs it */ - *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); - /* push up to external supp/auth */ - dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); - break; - } -#ifdef WLMEDIA_HTSF - case WLC_E_HTSFSYNC: - htsf_update(dhd_pub->info, event_data); - break; -#endif /* WLMEDIA_HTSF */ - case WLC_E_NDIS_LINK: { - uint32 temp = hton32(WLC_E_LINK); - - memcpy((void *)(&pvt_data->event.event_type), &temp, - sizeof(pvt_data->event.event_type)); - } - case WLC_E_PFN_NET_FOUND: - case WLC_E_PFN_NET_LOST: - break; -#if defined(PNO_SUPPORT) - case WLC_E_PFN_BSSID_NET_FOUND: - case WLC_E_PFN_BSSID_NET_LOST: - case WLC_E_PFN_BEST_BATCHING: - dhd_pno_event_handler(dhd_pub, event, (void *)event_data); - break; -#endif - /* These are what external supplicant/authenticator wants */ - /* fall through */ -#if defined(RTT_SUPPORT) - case WLC_E_PROXD: - dhd_rtt_event_handler(dhd_pub, event, (void *)event_data); - break; -#endif /* RTT_SUPPORT */ - case WLC_E_LINK: - case WLC_E_DEAUTH: - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC: - case WLC_E_DISASSOC_IND: - DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); - /* fall through */ - default: - *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); - /* push up to external supp/auth */ - dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); - DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); - BCM_REFERENCE(flags); - BCM_REFERENCE(status); - - break; - } - -#ifdef SHOW_EVENTS - wl_show_host_event(event, (void *)event_data); -#endif /* SHOW_EVENTS */ - - return (BCME_OK); -} - -void -wl_event_to_host_order(wl_event_msg_t * evt) -{ - /* Event struct members passed from dongle to host are stored in network - * byte order. Convert all members to host-order. - */ - evt->event_type = ntoh32(evt->event_type); - evt->flags = ntoh16(evt->flags); - evt->status = ntoh32(evt->status); - evt->reason = ntoh32(evt->reason); - evt->auth_type = ntoh32(evt->auth_type); - evt->datalen = ntoh32(evt->datalen); - evt->version = ntoh16(evt->version); -} - -void -dhd_print_buf(void *pbuf, int len, int bytes_per_line) -{ -#ifdef DHD_DEBUG - int i, j = 0; - unsigned char *buf = pbuf; - - if (bytes_per_line == 0) { - bytes_per_line = len; - } - - for (i = 0; i < len; i++) { - printf("%2.2x", *buf++); - j++; - if (j == bytes_per_line) { - printf("\n"); - j = 0; - } else { - printf(":"); - } - } - printf("\n"); -#endif /* DHD_DEBUG */ -} -#ifndef strtoul -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -#endif - -#ifdef PKT_FILTER_SUPPORT -/* Convert user's input in hex pattern to byte-size mask */ -static int -wl_pattern_atoh(char *src, char *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && - strncmp(src, "0X", 2) != 0) { - DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); - return -1; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); - return -1; - } - for (i = 0; *src != '\0'; i++) { - char num[3]; - bcm_strncpy_s(num, sizeof(num), src, 2); - num[2] = '\0'; - dst[i] = (uint8)strtoul(num, NULL, 16); - src += 2; - } - return i; -} - -void -dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) -{ - char *argv[8]; - int i = 0; - const char *str; - int buf_len; - int str_len; - char *arg_save = 0, *arg_org = 0; - int rc; - char buf[128]; - wl_pkt_filter_enable_t enable_parm; - wl_pkt_filter_enable_t * pkt_filterp; - - if (!arg) - return; - - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - arg_org = arg_save; - memcpy(arg_save, arg, strlen(arg) + 1); - - argv[i] = bcmstrtok(&arg_save, " ", 0); - - i = 0; - if (argv[i] == NULL) { - DHD_ERROR(("No args provided\n")); - goto fail; - } - - str = "pkt_filter_enable"; - str_len = strlen(str); - bcm_strncpy_s(buf, sizeof(buf), str, str_len); - buf[str_len] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); - - /* Parse packet filter id. */ - enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); - - /* Parse enable/disable value. */ - enable_parm.enable = htod32(enable); - - buf_len += sizeof(enable_parm); - memcpy((char *)pkt_filterp, - &enable_parm, - sizeof(enable_parm)); - - /* Enable/disable the specified filter. */ - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - rc = rc >= 0 ? 0 : rc; - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); - else - DHD_TRACE(("%s: successfully added pktfilter %s\n", - __FUNCTION__, arg)); - - /* Contorl the master mode */ - rc = dhd_iovar(dhd, 0, "pkt_filter_mode", (char *)&master_mode, - sizeof(master_mode), NULL, 0, TRUE); - - rc = rc >= 0 ? 0 : rc; - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); -fail: - if (arg_org) - MFREE(dhd->osh, arg_org, strlen(arg) + 1); -} - -void -dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) -{ - const char *str; - wl_pkt_filter_t pkt_filter; - wl_pkt_filter_t *pkt_filterp; - int buf_len; - int str_len; - int rc; - uint32 mask_size; - uint32 pattern_size; - char *argv[8], * buf = 0; - int i = 0; - char *arg_save = 0, *arg_org = 0; -#define BUF_SIZE 2048 - - if (!arg) - return; - - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - - arg_org = arg_save; - - if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - - memcpy(arg_save, arg, strlen(arg) + 1); - - if (strlen(arg) > BUF_SIZE) { - DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); - goto fail; - } - - argv[i] = bcmstrtok(&arg_save, " ", 0); - while (argv[i++]) - argv[i] = bcmstrtok(&arg_save, " ", 0); - - i = 0; - if (argv[i] == NULL) { - DHD_ERROR(("No args provided\n")); - goto fail; - } - - str = "pkt_filter_add"; - str_len = strlen(str); - bcm_strncpy_s(buf, BUF_SIZE, str, str_len); - buf[ str_len ] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); - - /* Parse packet filter id. */ - pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Polarity not provided\n")); - goto fail; - } - - /* Parse filter polarity. */ - pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Filter type not provided\n")); - goto fail; - } - - /* Parse filter type. */ - pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Offset not provided\n")); - goto fail; - } - - /* Parse pattern filter offset. */ - pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Bitmask not provided\n")); - goto fail; - } - - /* Parse pattern filter mask. */ - mask_size = - htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Pattern not provided\n")); - goto fail; - } - - /* Parse pattern filter pattern. */ - pattern_size = - htod32(wl_pattern_atoh(argv[i], - (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); - - if (mask_size != pattern_size) { - DHD_ERROR(("Mask and pattern not the same size\n")); - goto fail; - } - - pkt_filter.u.pattern.size_bytes = mask_size; - buf_len += WL_PKT_FILTER_FIXED_LEN; - buf_len += (WL_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, - WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); - - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - rc = rc >= 0 ? 0 : rc; - - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); - else - DHD_TRACE(("%s: successfully added pktfilter %s\n", - __FUNCTION__, arg)); - -fail: - if (arg_org) - MFREE(dhd->osh, arg_org, strlen(arg) + 1); - - if (buf) - MFREE(dhd->osh, buf, BUF_SIZE); -} - -void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id) -{ - int ret; - - ret = dhd_iovar(dhd, 0, "pkt_filter_delete", (char *)&id, sizeof(id), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n", - __FUNCTION__, id, ret)); - } -} -#endif /* PKT_FILTER_SUPPORT */ - -/* ========================== */ -/* ==== ARP OFFLOAD SUPPORT = */ -/* ========================== */ -#ifdef ARP_OFFLOAD_SUPPORT -void -dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) -{ - int ret; - - ret = dhd_iovar(dhd, 0, "arp_ol", (char *)&arp_mode, sizeof(arp_mode), NULL, 0, TRUE); - ret = ret >= 0 ? 0 : ret; - if (ret) - DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, ret = %d\n", - __FUNCTION__, arp_mode, ret)); - else - DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", - __FUNCTION__, arp_mode)); -} - -void -dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) -{ - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int ret; - - ret = dhd_iovar(dhd, 0, "arpoe", (char *)&arp_enable, sizeof(arp_enable), NULL, 0, TRUE); - ret = ret >= 0 ? 0 : ret; - if (ret) - DHD_TRACE(("%s: failed to enabe ARP offload to %d, ret = %d\n", - __FUNCTION__, arp_enable, ret)); - else - DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", - __FUNCTION__, arp_enable)); - - if (arp_enable) { - uint32 version; - ret = dhd_iovar(dhd, 0, "arp_version", NULL, 0, (char *)iovbuf, - sizeof(iovbuf), FALSE); - if (ret) { - DHD_INFO(("%s: fail to get version (maybe version 1:ret = %d\n", - __FUNCTION__, ret)); - dhd->arp_version = 1; - } - else { - memcpy(&version, iovbuf, sizeof(version)); - DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version)); - dhd->arp_version = version; - } - } -} - -void -dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) -{ - int ret = 0; - - if (dhd == NULL) return; - if (dhd->arp_version == 1) - idx = 0; - - ret = dhd_iovar(dhd, idx, "arp_table_clear", NULL, 0, NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -} - -void -dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) -{ - int ret = 0; - - if (dhd == NULL) return; - if (dhd->arp_version == 1) - idx = 0; - - ret = dhd_iovar(dhd, idx, "arp_hostip_clear", NULL, 0, NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -} - -void -dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) -{ - int ret; - - if (dhd == NULL) return; - if (dhd->arp_version == 1) - idx = 0; - - ret = dhd_iovar(dhd, idx, "arp_hostip", (char *)&ipaddr, sizeof(ipaddr), - NULL, 0, TRUE); - if (ret) - DHD_TRACE(("%s: ARP ip addr add failed, ret = %d\n", __FUNCTION__, ret)); - else - DHD_TRACE(("%s: sARP H ipaddr entry added \n", - __FUNCTION__)); -} - -int -dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) -{ - int ret, i; - - uint32 *ptr32 = buf; - bool clr_bottom = FALSE; - - if (!buf) - return -1; - if (dhd == NULL) return -1; - if (dhd->arp_version == 1) - idx = 0; - - ret = dhd_iovar(dhd, idx, "arp_hostip", NULL, 0, (char *)buf, buflen, - FALSE); - if (ret) { - DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", - __FUNCTION__, ret)); - - return -1; - } - - /* clean up the buf, ascii reminder */ - for (i = 0; i < MAX_IPV4_ENTRIES; i++) { - if (!clr_bottom) { - if (*ptr32 == 0) - clr_bottom = TRUE; - } else { - *ptr32 = 0; - } - ptr32++; - } - - return 0; -} -#endif /* ARP_OFFLOAD_SUPPORT */ - -/* - * Neighbor Discovery Offload: enable NDO feature - * Called by ipv6 event handler when interface comes up/goes down - */ -int -dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable) -{ - int ret; - - if (dhd == NULL) - return -1; - - ret = dhd_iovar(dhd, 0, "ndoe", (char *)&ndo_enable, sizeof(ndo_enable), - NULL, 0, TRUE); - if (ret) - DHD_ERROR(("%s: failed to enabe ndo to %d, ret = %d\n", - __FUNCTION__, ndo_enable, ret)); - else - DHD_TRACE(("%s: successfully enabed ndo offload to %d\n", - __FUNCTION__, ndo_enable)); - - return ret; -} - -/* - * Neighbor Discover Offload: enable NDO feature - * Called by ipv6 event handler when interface comes up - */ -int -dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx) -{ - int ret; - - if (dhd == NULL) - return -1; - - ret = dhd_iovar(dhd, idx, "nd_hostip", (char *)ipv6addr, IPV6_ADDR_LEN, - NULL, 0, TRUE); - if (ret) - DHD_ERROR(("%s: ndo ip addr add failed, ret = %d\n", - __FUNCTION__, ret)); - else - DHD_TRACE(("%s: ndo ipaddr entry added \n", - __FUNCTION__)); - - return ret; -} -/* - * Neighbor Discover Offload: enable NDO feature - * Called by ipv6 event handler when interface goes down - */ -int -dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx) -{ - int ret; - - if (dhd == NULL) - return -1; - - ret = dhd_iovar(dhd, idx, "nd_hostip_clear", NULL, 0, - NULL, 0, TRUE); - if (ret) - DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n", - __FUNCTION__, ret)); - else - DHD_TRACE(("%s: ndo ipaddr entry removed \n", - __FUNCTION__)); - - return ret; -} - -/* send up locally generated event */ -void -dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) -{ - switch (ntoh32(event->event_type)) { - default: - break; - } - - /* Call per-port handler. */ - dhd_sendup_event(dhdp, event, data); -} - - -/* - * returns = TRUE if associated, FALSE if not associated - */ -bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) -{ - char bssid[6], zbuf[6]; - int ret = -1; - - bzero(bssid, 6); - bzero(zbuf, 6); - - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0); - DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); - - if (ret == BCME_NOTASSOCIATED) { - DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); - } - - if (retval) - *retval = ret; - - if (ret < 0) - return FALSE; - - if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { - /* STA is assocoated BSSID is non zero */ - - if (bss_buf) { - /* return bss if caller provided buf */ - memcpy(bss_buf, bssid, ETHER_ADDR_LEN); - } - return TRUE; - } else { - DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); - return FALSE; - } -} - - -/* Function to estimate possible DTIM_SKIP value */ -int -dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) -{ - int bcn_li_dtim = 1; /* deafult no dtim skip setting */ - int ret = -1; - int dtim_period = 0; - int ap_beacon = 0; - int allowed_skip_dtim_cnt = 0; - /* Check if associated */ - if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { - DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* read associated AP beacon interval */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, - &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) { - DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* read associated ap's dtim setup */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, - &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) { - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* if not assocated just eixt */ - if (dtim_period == 0) { - goto exit; - } - - /* attemp to use platform defined dtim skip interval */ - bcn_li_dtim = dhd->suspend_bcn_li_dtim; - - /* check if sta listen interval fits into AP dtim */ - if (dtim_period > CUSTOM_LISTEN_INTERVAL) { - /* AP DTIM to big for our Listen Interval : no dtim skiping */ - bcn_li_dtim = NO_DTIM_SKIP; - DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", - __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL)); - goto exit; - } - - if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { - allowed_skip_dtim_cnt = MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon); - bcn_li_dtim = (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; - } - - if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) { - /* Round up dtim_skip to fit into STAs Listen Interval */ - bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period); - DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); - } - - DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", - __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL)); - -exit: - return bcn_li_dtim; -} - -/* Check if the mode supports STA MODE */ -bool dhd_support_sta_mode(dhd_pub_t *dhd) -{ - -#ifdef WL_CFG80211 - if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) - return FALSE; - else -#endif /* WL_CFG80211 */ - return TRUE; -} - -#if defined(KEEP_ALIVE) -int dhd_keep_alive_onoff(dhd_pub_t *dhd) -{ - char buf[256]; - const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0}; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = -1; - - if (!dhd_support_sta_mode(dhd)) - return res; - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(buf, str, str_len); - buf[ str_len ] = '\0'; - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); - mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING; - buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - /* Setup keep alive zero for null packet generation */ - mkeep_alive_pkt.keep_alive_id = 0; - mkeep_alive_pkt.len_bytes = 0; - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); - /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - - return res; -} -#endif /* defined(KEEP_ALIVE) */ -#define CSCAN_TLV_TYPE_SSID_IE 'S' -/* - * SSIDs list parsing from cscan tlv list - */ -int -wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left) -{ - char* str; - int idx = 0; - uint8 len; - - if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return BCME_BADARG; - } - str = *list_str; - while (*bytes_left > 0) { - if (idx >= max) { - DHD_ERROR(("%s number of SSIDs more than %d\n", __FUNCTION__, idx)); - return BCME_BADARG; - } - - if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { - *list_str = str; - DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); - return idx; - } - - /* Get proper CSCAN_TLV_TYPE_SSID_IE */ - *bytes_left -= 1; - if (*bytes_left == 0) { - DHD_ERROR(("%s no length field.\n", __FUNCTION__)); - return BCME_BADARG; - } - str += 1; - ssid[idx].rssi_thresh = 0; - len = str[0]; - if (len == 0) { - /* Broadcast SSID */ - ssid[idx].SSID_len = 0; - memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); - *bytes_left -= 1; - str += 1; - - DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); - } else if (len <= DOT11_MAX_SSID_LEN) { - /* Get proper SSID size */ - ssid[idx].SSID_len = len; - *bytes_left -= 1; - /* Get SSID */ - if (ssid[idx].SSID_len > *bytes_left) { - DHD_ERROR(("%s out of memory range len=%d but left=%d\n", - __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); - return BCME_BADARG; - } - str += 1; - memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); - - *bytes_left -= ssid[idx].SSID_len; - str += ssid[idx].SSID_len; - ssid[idx].hidden = TRUE; - - DHD_TRACE(("%s :size=%d left=%d\n", - (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); - } else { - DHD_ERROR(("### SSID size more than %d\n", str[0])); - return BCME_BADARG; - } - idx++; - } - - *list_str = str; - return idx; -} -#if defined(WL_WIRELESS_EXT) -/* Android ComboSCAN support */ - -/* - * data parsing from ComboScan tlv list -*/ -int -wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, - int input_size, int *bytes_left) -{ - char* str; - uint16 short_temp; - uint32 int_temp; - - if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - str = *list_str; - - /* Clean all dest bytes */ - memset(dst, 0, dst_size); - while (*bytes_left > 0) { - - if (str[0] != token) { - DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", - __FUNCTION__, token, str[0], *bytes_left)); - return -1; - } - - *bytes_left -= 1; - str += 1; - - if (input_size == 1) { - memcpy(dst, str, input_size); - } - else if (input_size == 2) { - memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), - input_size); - } - else if (input_size == 4) { - memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), - input_size); - } - - *bytes_left -= input_size; - str += input_size; - *list_str = str; - return 1; - } - return 1; -} - -/* - * channel list parsing from cscan tlv list -*/ -int -wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, - int channel_num, int *bytes_left) -{ - char* str; - int idx = 0; - - if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - str = *list_str; - - while (*bytes_left > 0) { - - if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { - *list_str = str; - DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); - return idx; - } - /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ - *bytes_left -= 1; - str += 1; - - if (str[0] == 0) { - /* All channels */ - channel_list[idx] = 0x0; - } - else { - channel_list[idx] = (uint16)str[0]; - DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); - } - *bytes_left -= 1; - str += 1; - - if (idx++ > 255) { - DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); - return -1; - } - } - - *list_str = str; - return idx; -} - -/* Parse a comma-separated list from list_str into ssid array, starting - * at index idx. Max specifies size of the ssid array. Parses ssids - * and returns updated idx; if idx >= max not all fit, the excess have - * not been copied. Returns -1 on empty string, or on ssid too long. - */ -int -wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) -{ - char* str, *ptr; - - if ((list_str == NULL) || (*list_str == NULL)) - return -1; - - for (str = *list_str; str != NULL; str = ptr) { - - /* check for next TAG */ - if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { - *list_str = str + strlen(GET_CHANNEL); - return idx; - } - - if ((ptr = strchr(str, ',')) != NULL) { - *ptr++ = '\0'; - } - - if (strlen(str) > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); - return -1; - } - - if (strlen(str) == 0) - ssid[idx].SSID_len = 0; - - if (idx < max) { - bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); - strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); - ssid[idx].SSID_len = strlen(str); - } - idx++; - } - return idx; -} - -/* - * Parse channel list from iwpriv CSCAN - */ -int -wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) -{ - int num; - int val; - char* str; - char* endptr = NULL; - - if ((list_str == NULL)||(*list_str == NULL)) - return -1; - - str = *list_str; - num = 0; - while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { - val = (int)strtoul(str, &endptr, 0); - if (endptr == str) { - printf("could not parse channel number starting at" - " substring \"%s\" in list:\n%s\n", - str, *list_str); - return -1; - } - str = endptr + strspn(endptr, " ,"); - - if (num == channel_num) { - DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", - channel_num, *list_str)); - return -1; - } - - channel_list[num++] = (uint16)val; - } - *list_str = str; - return num; -} - -#endif diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c deleted file mode 100755 index b266c5e7006a..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c +++ /dev/null @@ -1,597 +0,0 @@ -/* -* Customer code to add GPIO control during WLAN start/stop -* Copyright (C) 1999-2018, Broadcom Corporation -* Copyright (C) 2013 Sony Mobile Communications Inc. -* -* Unless you and Broadcom execute a separate written software license -* agreement governing use of this software, this software is licensed to you -* under the terms of the GNU General Public License version 2 (the "GPL"), -* available at http://www.broadcom.com/licenses/GPLv2.php, with the -* following added to such license: -* -* As a special exception, the copyright holders of this software give you -* permission to link this software with independent modules, and to copy and -* distribute the resulting executable under terms of your choice, provided that -* you also meet, for each linked independent module, the terms and conditions of -* the license of that module. An independent module is a module which is not -* derived from this software. The special exception does not apply to any -* modifications of the software. -* -* Notwithstanding the above, under no circumstances may you combine this -* software in any way with any other Broadcom software provided under a license -* other than the GPL, without Broadcom's express prior written consent. -* -* $Id: dhd_custom_gpio.c 684925 2017-02-15 01:55:31Z $ -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#if defined(WL_WIRELESS_EXT) -#include -#endif - -#define WL_ERROR(x) printf x -#define WL_TRACE(x) - -#if defined(CUSTOMER_HW2) - - -#endif - -#ifdef GET_CUSTOM_MAC_ENABLE -#define MACADDR_BUF_LEN 64 -#define MACADDR_PATH "/data/etc/wlan_macaddr0" -#endif /* GET_CUSTOM_MAC_ENABLE */ - -#if defined(OOB_INTR_ONLY) - -#if defined(BCMLXSDMMC) -extern int sdioh_mmc_irq(int irq); -#endif /* (BCMLXSDMMC) */ - -#if defined(CUSTOMER_HW3) -#include -#endif - -/* Customer specific Host GPIO defintion */ -static int dhd_oob_gpio_num = -1; - -module_param(dhd_oob_gpio_num, int, 0644); -MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); - -/* This function will return: - * 1) return : Host gpio interrupt number per customer platform - * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge - * - * NOTE : - * Customer should check his platform definitions - * and his Host Interrupt spec - * to figure out the proper setting for his platform. - * Broadcom provides just reference settings as example. - * - */ -int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr) -{ - int host_oob_irq = 0; - -#if defined(CUSTOMER_HW2) - host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr); - -#else -#if defined(CUSTOM_OOB_GPIO_NUM) - if (dhd_oob_gpio_num < 0) { - dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; - } -#endif /* CUSTOMER_OOB_GPIO_NUM */ - - if (dhd_oob_gpio_num < 0) { - WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", - __FUNCTION__)); - return (dhd_oob_gpio_num); - } - - WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", - __FUNCTION__, dhd_oob_gpio_num)); - -#if defined(CUSTOMER_HW3) - gpio_request(dhd_oob_gpio_num, "oob irq"); - host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); - gpio_direction_input(dhd_oob_gpio_num); -#endif /* defined CUSTOMER_HW3 */ -#endif - - return (host_oob_irq); -} -#endif - -/* Customer function to control hw specific wlan gpios */ -int -dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff) -{ - int err = 0; - - return err; -} - -#ifdef GET_CUSTOM_MAC_ENABLE -int somc_get_mac_address(unsigned char *buf) -{ - int ret = -EINVAL; - int len; - unsigned char macaddr_buf[MACADDR_BUF_LEN]; - void *fp = NULL; - struct ether_addr eth; - - if (!buf) - return -EINVAL; - - fp = dhd_os_open_image(MACADDR_PATH); - if (!fp) { - WL_ERROR(("%s: file open error\n", __FUNCTION__)); - goto err; - } - - len = dhd_os_get_image_block(macaddr_buf, MACADDR_BUF_LEN, fp); - if (len <= 0 || MACADDR_BUF_LEN <= len) { - WL_ERROR(("%s: file read error\n", __FUNCTION__)); - goto err; - } - macaddr_buf[len] = '\0'; - - /* convert mac address */ - ret = !bcm_ether_atoe(macaddr_buf, ð); - if (ret) { - WL_ERROR(("%s: convert mac value fail\n", __FUNCTION__)); - goto err; - } - - memcpy(buf, eth.octet, ETHER_ADDR_LEN); -err: - if (fp) - dhd_os_close_image(fp); - return ret; -} - -/* Function to get custom MAC address */ -int -dhd_custom_get_mac_address(void *adapter, unsigned char *buf) -{ - int ret = 0; - - WL_TRACE(("%s Enter\n", __FUNCTION__)); - if (!buf) - return -EINVAL; - - /* Customer access to MAC address stored outside of DHD driver */ -#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) - ret = wifi_platform_get_mac_addr(adapter, buf); -#endif - -#ifdef EXAMPLE_GET_MAC - /* EXAMPLE code */ - { - struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; - bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); - } -#endif /* EXAMPLE_GET_MAC */ - - return ret; -} -#endif /* GET_CUSTOM_MAC_ENABLE */ - -struct cntry_locales_custom { - char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ - char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ - int32 custom_locale_rev; /* Custom local revisin default -1 */ -}; -/* Customized Locale table : OPTIONAL feature */ -const struct cntry_locales_custom translate_custom_table[] = { -/* Table should be filled out based on custom platform regulatory requirement */ -#ifdef EXAMPLE_TABLE - {"", "XY", 4}, /* Universal if Country code is unknown or empty */ - {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ - {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ - {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ - {"AT", "EU", 5}, - {"BE", "EU", 5}, - {"BG", "EU", 5}, - {"CY", "EU", 5}, - {"CZ", "EU", 5}, - {"DK", "EU", 5}, - {"EE", "EU", 5}, - {"FI", "EU", 5}, - {"FR", "EU", 5}, - {"DE", "EU", 5}, - {"GR", "EU", 5}, - {"HU", "EU", 5}, - {"IE", "EU", 5}, - {"IT", "EU", 5}, - {"LV", "EU", 5}, - {"LI", "EU", 5}, - {"LT", "EU", 5}, - {"LU", "EU", 5}, - {"MT", "EU", 5}, - {"NL", "EU", 5}, - {"PL", "EU", 5}, - {"PT", "EU", 5}, - {"RO", "EU", 5}, - {"SK", "EU", 5}, - {"SI", "EU", 5}, - {"ES", "EU", 5}, - {"SE", "EU", 5}, - {"GB", "EU", 5}, - {"KR", "XY", 3}, - {"AU", "XY", 3}, - {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ - {"TW", "XY", 3}, - {"AR", "XY", 3}, - {"MX", "XY", 3}, - {"IL", "IL", 0}, - {"CH", "CH", 0}, - {"TR", "TR", 0}, - {"NO", "NO", 0}, -#endif /* EXMAPLE_TABLE */ -#if defined(CUSTOMER_HW2) && !defined(CUSTOMER_HW5) -#if defined(BCM4335_CHIP) - {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ -#endif - {"AE", "AE", 1}, - {"AR", "AR", 1}, - {"AT", "AT", 1}, - {"AU", "AU", 2}, - {"BE", "BE", 1}, - {"BG", "BG", 1}, - {"BN", "BN", 1}, - {"CA", "CA", 2}, - {"CH", "CH", 1}, - {"CY", "CY", 1}, - {"CZ", "CZ", 1}, - {"DE", "DE", 3}, - {"DK", "DK", 1}, - {"EE", "EE", 1}, - {"ES", "ES", 1}, - {"FI", "FI", 1}, - {"FR", "FR", 1}, - {"GB", "GB", 1}, - {"GR", "GR", 1}, - {"HR", "HR", 1}, - {"HU", "HU", 1}, - {"IE", "IE", 1}, - {"IS", "IS", 1}, - {"IT", "IT", 1}, - {"ID", "ID", 1}, - {"JP", "JP", 8}, - {"KR", "KR", 24}, - {"KW", "KW", 1}, - {"LI", "LI", 1}, - {"LT", "LT", 1}, - {"LU", "LU", 1}, - {"LV", "LV", 1}, - {"MA", "MA", 1}, - {"MT", "MT", 1}, - {"MX", "MX", 1}, - {"NL", "NL", 1}, - {"NO", "NO", 1}, - {"PL", "PL", 1}, - {"PT", "PT", 1}, - {"PY", "PY", 1}, - {"RO", "RO", 1}, - {"SE", "SE", 1}, - {"SI", "SI", 1}, - {"SK", "SK", 1}, - {"TR", "TR", 7}, - {"TW", "TW", 1}, - {"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ - {"SD", "XZ", 11}, /* Universal if Country code is SUDAN */ - {"SY", "XZ", 11}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ - {"GL", "XZ", 11}, /* Universal if Country code is GREENLAND */ - {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ - {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ - {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ -#ifdef BCM4330_CHIP - {"RU", "RU", 1}, - {"US", "US", 5} -#endif - -#elif defined(CUSTOMER_HW5) - /* default ccode/regrev */ - {"", "XT", 54}, /* Universal if Country code is unknown or empty */ - {"IR", "XT", 54}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ - {"SD", "XT", 54}, /* Universal if Country code is SUDAN */ - {"SY", "XT", 54}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ - {"GL", "E0", 979}, /* Universal if Country code is GREENLAND */ - {"PS", "XT", 54}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ - {"TL", "XT", 54}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ - {"MH", "XT", 54}, /* Universal if Country code is MARSHALL ISLANDS */ - {"CK", "XT", 54}, /* Universal if Country code is Cook Islands */ - {"CU", "XT", 54}, /* Universal if Country code is Cuba */ - {"FO", "XT", 54}, /* Universal if Country code is Faroe Islands */ - {"GI", "XT", 54}, /* Universal if Country code is Gibraltar */ - {"KP", "XT", 54}, /* Universal if Country code is North Korea */ - {"NE", "XT", 54}, /* Universal if Country code is Niger (Republic of the) */ - {"PM", "XT", 54}, /* Universal if Country code is Saint Pierre and Miquelon */ - {"WF", "XT", 54}, /* Universal if Country code is Wallis and Futuna */ - - {"XA", "XX", 4}, /* Default country code for INDONESIA */ - {"XC", "XT", 998}, /* Default country code for RUSSIA */ - {"XD", "XT", 65}, /* Default country code for CHILE */ - {"AD", "AD", 0}, - {"AE", "AE", 212}, - {"AF", "AF", 0}, - {"AG", "XT", 54}, - {"AI", "AI", 2}, - {"AL", "AL", 2}, - {"AM", "AM", 0}, - {"AN", "AN", 3}, - {"AO", "AO", 0}, - {"AR", "AR", 212}, - {"AS", "AS", 15}, - {"AT", "E0", 979}, - {"AU", "AU", 212}, - {"AW", "XT", 54}, - {"AZ", "XT", 54}, - {"BA", "BA", 2}, - {"BB", "BB", 0}, - {"BD", "XT", 54}, - {"BE", "E0", 979}, - {"BF", "XT", 54}, - {"BG", "E0", 979}, - {"BH", "BH", 4}, - {"BI", "BI", 0}, - {"BJ", "BJ", 0}, - {"BM", "BM", 15}, - {"BN", "BN", 4}, - {"BO", "XT", 54}, - {"BR", "BR", 212}, - {"BS", "XT", 54}, - {"BT", "XT", 54}, - {"BW", "BW", 1}, - {"BY", "XT", 54}, - {"BZ", "XT", 54}, - {"CA", "CA", 212}, - {"CD", "CD", 0}, - {"CF", "CF", 0}, - {"CG", "CG", 0}, - {"CH", "E0", 979}, - {"CI", "CI", 0}, - {"CL", "CL", 212}, - {"CM", "CM", 0}, - {"CN", "CN", 212}, - {"CO", "CO", 212}, - {"CR", "CR", 21}, - {"CV", "CV", 0}, - {"CX", "CX", 1}, - {"CY", "E0", 979}, - {"CZ", "E0", 979}, - {"DE", "E0", 979}, - {"DJ", "DJ", 0}, - {"DK", "E0", 979}, - {"DM", "XT", 54}, - {"DO", "XT", 54}, - {"DZ", "DZ", 1}, - {"EC", "EC", 23}, - {"EE", "E0", 979}, - {"EG", "EG", 212}, - {"ER", "ER", 0}, - {"ES", "E0", 979}, - {"ET", "ET", 2}, - {"FI", "E0", 979}, - {"FJ", "XT", 54}, - {"FK", "FK", 0}, - {"FM", "XT", 54}, - {"FR", "E0", 979}, - {"GA", "GA", 0}, - {"GB", "E0", 979}, - {"GD", "XT", 54}, - {"GE", "GE", 0}, - {"GF", "GF", 2}, - {"GH", "GH", 0}, - {"GM", "GM", 0}, - {"GN", "GN", 0}, - {"GP", "GP", 2}, - {"GQ", "GQ", 0}, - {"GR", "E0", 979}, - {"GT", "XT", 54}, - {"GU", "GU", 17}, - {"GW", "GW", 0}, - {"GY", "GY", 0}, - {"HK", "HK", 212}, - {"HN", "HN", 0}, - {"HR", "E0", 979}, - {"HT", "HT", 0}, - {"HU", "E0", 979}, - {"ID", "ID", 212}, - {"IE", "E0", 979}, - {"IL", "IL", 7}, - {"IN", "IN", 212}, - {"IQ", "IQ", 0}, - {"IS", "E0", 979}, - {"IT", "E0", 979}, - {"JM", "JM", 0}, - {"JO", "JO", 3}, - {"JP", "JP", 212}, - {"KE", "KE", 0}, - {"KG", "KG", 0}, - {"KH", "KH", 4}, - {"KI", "KI", 1}, - {"KM", "KM", 0}, - {"KN", "XT", 54}, - {"KR", "KR", 212}, - {"KW", "KW", 5}, - {"KY", "KY", 4}, - {"KZ", "KZ", 212}, - {"LA", "LA", 4}, - {"LB", "LB", 6}, - {"LC", "XT", 54}, - {"LI", "E0", 979}, - {"LK", "XT", 54}, - {"LR", "LR", 2}, - {"LS", "LS", 2}, - {"LT", "E0", 979}, - {"LU", "E0", 979}, - {"LV", "E0", 979}, - {"LY", "LY", 0}, - {"MA", "MA", 2}, - {"MC", "E0", 979}, - {"MD", "MD", 2}, - {"ME", "ME", 2}, - {"MF", "XT", 54}, - {"MG", "MG", 0}, - {"MK", "E0", 979}, - {"ML", "ML", 0}, - {"MM", "MM", 0}, - {"MN", "XT", 54}, - {"MO", "MO", 2}, - {"MP", "XT", 54}, - {"MQ", "MQ", 2}, - {"MR", "MR", 2}, - {"MS", "MS", 0}, - {"MT", "E0", 979}, - {"MU", "MU", 2}, - {"MV", "MV", 3}, - {"MW", "XT", 54}, - {"MX", "MX", 212}, - {"MY", "MY", 998}, - {"MZ", "XT", 54}, - {"NA", "XT", 54}, - {"NC", "NC", 0}, - {"NG", "NG", 0}, - {"NI", "NI", 0}, - {"NL", "E0", 979}, - {"NO", "E0", 979}, - {"NP", "NP", 3}, - {"NR", "NR", 0}, - {"NZ", "NZ", 9}, - {"OM", "OM", 4}, - {"PA", "PA", 17}, - {"PE", "PE", 212}, - {"PF", "PF", 0}, - {"PG", "PG", 2}, - {"PH", "PH", 212}, - {"PK", "PK", 0}, - {"PL", "E0", 979}, - {"PR", "PR", 25}, - {"PT", "E0", 979}, - {"PW", "XT", 54}, - {"PY", "PY", 4}, - {"QA", "QA", 0}, - {"RE", "RE", 2}, - {"RO", "E0", 979}, - {"RS", "RS", 2}, - {"RU", "RU", 212}, - {"RW", "XT", 54}, - {"SA", "SA", 212}, - {"SB", "SB", 0}, - {"SC", "XT", 54}, - {"SE", "E0", 979}, - {"SG", "SG", 212}, - {"SI", "E0", 979}, - {"SK", "E0", 979}, - {"SL", "SL", 0}, - {"SM", "SM", 0}, - {"SN", "SN", 2}, - {"SO", "SO", 0}, - {"SR", "SR", 0}, - {"ST", "ST", 0}, - {"SV", "XT", 54}, - {"SZ", "SZ", 0}, - {"TC", "TC", 0}, - {"TD", "TD", 0}, - {"TF", "TF", 0}, - {"TG", "TG", 0}, - {"TH", "TH", 212}, - {"TJ", "TJ", 0}, - {"TM", "TM", 0}, - {"TN", "TN", 0}, - {"TO", "TO", 0}, - {"TR", "E0", 979}, - {"TT", "TT", 5}, - {"TV", "TV", 0}, - {"TW", "TW", 996}, - {"TZ", "XT", 54}, -#ifdef ENABLE_80211AC_FOR_UA - {"UA", "UA", 999}, -#else - {"UA", "UA", 212}, -#endif - {"UG", "XT", 54}, - {"US", "US", 996}, - {"UY", "UY", 5}, - {"UZ", "XT", 54}, - {"VA", "VA", 2}, - {"VC", "XT", 54}, - {"VE", "VE", 3}, - {"VG", "XT", 54}, - {"VI", "VI", 18}, - {"VN", "XT", 54}, - {"VU", "XT", 54}, - {"WS", "XT", 54}, - {"YE", "XT", 54}, - {"YT", "YT", 2}, - {"ZA", "ZA", 212}, - {"ZM", "ZM", 2}, - {"ZW", "XT", 54}, -#endif /* CUSTOMER_HW2 and CUSTOMER_HW5 */ -}; - - -/* Customized Locale convertor -* input : ISO 3166-1 country abbreviation -* output: customized cspec -*/ -#ifdef CUSTOM_FORCE_NODFS_FLAG -void get_customized_country_code(void *adapter, char *country_iso_code, - wl_country_t *cspec, u32 flags) -#else -void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec) -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -{ -#if 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))) - - struct cntry_locales_custom *cloc_ptr; - - if (!cspec) - return; - -#ifdef CUSTOM_FORCE_NODFS_FLAG - cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code, flags); -#else - cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - if (cloc_ptr) { - strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = cloc_ptr->custom_locale_rev; - } - return; -#else - int size, i; - - size = ARRAYSIZE(translate_custom_table); - - if (cspec == 0) - return; - - if (size == 0) - return; - - for (i = 0; i < size; i++) { - if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { - memcpy(cspec->ccode, - translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[i].custom_locale_rev; - return; - } - } - /* if no country code matched return first universal code from translate_custom_table */ - memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[0].custom_locale_rev; - return; -#endif /* 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))) */ -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h deleted file mode 100755 index 8216dba67297..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Debug/trace/assert driver definitions for Dongle Host Driver. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_dbg.h 516345 2014-11-19 11:58:57Z $ - */ - -#ifndef _dhd_dbg_ -#define _dhd_dbg_ - -#define USE_NET_RATELIMIT 1 - -#if defined(DHD_DEBUG) - -#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && USE_NET_RATELIMIT) \ - printf args;} while (0) -#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) -#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) -#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) -#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0) -#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0) -#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0) -#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0) -#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0) -#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) -#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) -#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0) -#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) -#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) -#define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) -#define DHD_PNO(args) do {if (dhd_msg_level & DHD_PNO_VAL) printf args;} while (0) -#define DHD_RTT(args) do {if (dhd_msg_level & DHD_RTT_VAL) printf args;} while (0) - -#define DHD_TRACE_HW4 DHD_TRACE - -#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) -#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) -#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) -#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL) -#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL) -#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL) -#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL) -#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL) -#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL) -#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) -#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) -#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) -#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) -#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL) -#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL) -#define DHD_NOCHECKDIED_ON() (dhd_msg_level & DHD_NOCHECKDIED_VAL) -#define DHD_PNO_ON() (dhd_msg_level & DHD_PNO_VAL) -#define DHD_RTT_ON() (dhd_msg_level & DHD_RTT_VAL) - -#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ - -#define DHD_ERROR(args) do {if (USE_NET_RATELIMIT) printf args;} while (0) -#define DHD_TRACE(args) -#define DHD_INFO(args) -#define DHD_DATA(args) -#define DHD_CTL(args) -#define DHD_TIMER(args) -#define DHD_HDRS(args) -#define DHD_BYTES(args) -#define DHD_INTR(args) -#define DHD_GLOM(args) -#define DHD_EVENT(args) -#define DHD_BTA(args) -#define DHD_ISCAN(args) -#define DHD_ARPOE(args) -#define DHD_REORDER(args) -#define DHD_PNO(args) - -#define DHD_TRACE_HW4 DHD_TRACE - -#define DHD_ERROR_ON() 0 -#define DHD_TRACE_ON() 0 -#define DHD_INFO_ON() 0 -#define DHD_DATA_ON() 0 -#define DHD_CTL_ON() 0 -#define DHD_TIMER_ON() 0 -#define DHD_HDRS_ON() 0 -#define DHD_BYTES_ON() 0 -#define DHD_INTR_ON() 0 -#define DHD_GLOM_ON() 0 -#define DHD_EVENT_ON() 0 -#define DHD_BTA_ON() 0 -#define DHD_ISCAN_ON() 0 -#define DHD_ARPOE_ON() 0 -#define DHD_REORDER_ON() 0 -#define DHD_NOCHECKDIED_ON() 0 -#define DHD_PNO_ON() 0 -#define DHD_RTT_ON() 0 - -#endif - -#define DHD_LOG(args) - -#define DHD_BLOG(cp, size) - -#define DHD_NONE(args) -extern int dhd_msg_level; - -/* Defines msg bits */ -#include - -#endif /* _dhd_dbg_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c deleted file mode 100755 index 06167ab86cf8..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c +++ /dev/null @@ -1,953 +0,0 @@ -/* - * IP Packet Parser Module. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_ip.c 486237 2014-06-19 09:22:00Z $ - */ -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#ifdef DHDTCPACK_SUPPRESS -#include -#include -#endif /* DHDTCPACK_SUPPRESS */ - -/* special values */ -/* 802.3 llc/snap header */ -static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; - -pkt_frag_t pkt_frag_info(osl_t *osh, void *p) -{ - uint8 *frame; - int length; - uint8 *pt; /* Pointer to type field */ - uint16 ethertype; - struct ipv4_hdr *iph; /* IP frame pointer */ - int ipl; /* IP frame length */ - uint16 iph_frag; - - ASSERT(osh && p); - - frame = PKTDATA(osh, p); - length = PKTLEN(osh, p); - - /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ - if (length < ETHER_HDR_LEN) { - DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length)); - return DHD_PKT_FRAG_NONE; - } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { - /* Frame is Ethernet II */ - pt = frame + ETHER_TYPE_OFFSET; - } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && - !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { - pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; - } else { - DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__)); - return DHD_PKT_FRAG_NONE; - } - - ethertype = ntoh16(*(uint16 *)pt); - - /* Skip VLAN tag, if any */ - if (ethertype == ETHER_TYPE_8021Q) { - pt += VLAN_TAG_LEN; - - if (pt + ETHER_TYPE_LEN > frame + length) { - DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length)); - return DHD_PKT_FRAG_NONE; - } - - ethertype = ntoh16(*(uint16 *)pt); - } - - if (ethertype != ETHER_TYPE_IP) { - DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n", - __FUNCTION__, ethertype, length)); - return DHD_PKT_FRAG_NONE; - } - - iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); - ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame)); - - /* We support IPv4 only */ - if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) { - DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl)); - return DHD_PKT_FRAG_NONE; - } - - iph_frag = ntoh16(iph->frag); - - if (iph_frag & IPV4_FRAG_DONT) { - return DHD_PKT_FRAG_NONE; - } else if ((iph_frag & IPV4_FRAG_MORE) == 0) { - return DHD_PKT_FRAG_LAST; - } else { - return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST; - } -} - -#ifdef DHDTCPACK_SUPPRESS - -typedef struct { - void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */ - void *pkt_ether_hdr; /* Ethernet header pointer of pkt_in_q */ -} tcpack_info_t; - -typedef struct _tdata_psh_info_t { - uint32 end_seq; /* end seq# of a received TCP PSH DATA pkt */ - struct _tdata_psh_info_t *next; /* next pointer of the link chain */ -} tdata_psh_info_t; - -typedef struct { - uint8 src_ip_addr[IPV4_ADDR_LEN]; /* SRC ip addrs of this TCP stream */ - uint8 dst_ip_addr[IPV4_ADDR_LEN]; /* DST ip addrs of this TCP stream */ - uint8 src_tcp_port[TCP_PORT_LEN]; /* SRC tcp ports of this TCP stream */ - uint8 dst_tcp_port[TCP_PORT_LEN]; /* DST tcp ports of this TCP stream */ - tdata_psh_info_t *tdata_psh_info_head; /* Head of received TCP PSH DATA chain */ - tdata_psh_info_t *tdata_psh_info_tail; /* Tail of received TCP PSH DATA chain */ - uint32 last_used_time; /* The last time this tcpdata_info was used(in ms) */ -} tcpdata_info_t; - -/* TCPACK SUPPRESS module */ -typedef struct { - int tcpack_info_cnt; - tcpack_info_t tcpack_info_tbl[TCPACK_INFO_MAXNUM]; /* Info of TCP ACK to send */ - int tcpdata_info_cnt; - tcpdata_info_t tcpdata_info_tbl[TCPDATA_INFO_MAXNUM]; /* Info of received TCP DATA */ - tdata_psh_info_t *tdata_psh_info_pool; /* Pointer to tdata_psh_info elements pool */ - tdata_psh_info_t *tdata_psh_info_free; /* free tdata_psh_info elements chain in pool */ -#ifdef DHDTCPACK_SUP_DBG - int psh_info_enq_num; /* Number of free TCP PSH DATA info elements in pool */ -#endif /* DHDTCPACK_SUP_DBG */ -} tcpack_sup_module_t; - -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) -counter_tbl_t tack_tbl = {"tcpACK", 0, 1000, 10, {0, }, 1}; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - -static void -_tdata_psh_info_pool_enq(tcpack_sup_module_t *tcpack_sup_mod, - tdata_psh_info_t *tdata_psh_info) -{ - if ((tcpack_sup_mod == NULL) || (tdata_psh_info == NULL)) { - DHD_ERROR(("%s %d: ERROR %p %p\n", __FUNCTION__, __LINE__, - tcpack_sup_mod, tdata_psh_info)); - return; - } - - ASSERT(tdata_psh_info->next == NULL); - tdata_psh_info->next = tcpack_sup_mod->tdata_psh_info_free; - tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info; -#ifdef DHDTCPACK_SUP_DBG - tcpack_sup_mod->psh_info_enq_num++; -#endif -} - -static tdata_psh_info_t* -_tdata_psh_info_pool_deq(tcpack_sup_module_t *tcpack_sup_mod) -{ - tdata_psh_info_t *tdata_psh_info = NULL; - - if (tcpack_sup_mod == NULL) { - DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__, __LINE__, - tcpack_sup_mod)); - return NULL; - } - - tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free; - if (tdata_psh_info == NULL) - DHD_ERROR(("%s %d: Out of tdata_disc_grp\n", __FUNCTION__, __LINE__)); - else { - tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; - tdata_psh_info->next = NULL; -#ifdef DHDTCPACK_SUP_DBG - tcpack_sup_mod->psh_info_enq_num--; -#endif /* DHDTCPACK_SUP_DBG */ - } - - return tdata_psh_info; -} - -static int _tdata_psh_info_pool_init(dhd_pub_t *dhdp, - tcpack_sup_module_t *tcpack_sup_mod) -{ - tdata_psh_info_t *tdata_psh_info_pool = NULL; - uint i; - - DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); - - if (tcpack_sup_mod == NULL) - return BCME_ERROR; - - ASSERT(tcpack_sup_mod->tdata_psh_info_pool == NULL); - ASSERT(tcpack_sup_mod->tdata_psh_info_free == NULL); - - tdata_psh_info_pool = - MALLOC(dhdp->osh, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); - - if (tdata_psh_info_pool == NULL) - return BCME_NOMEM; - bzero(tdata_psh_info_pool, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); -#ifdef DHDTCPACK_SUP_DBG - tcpack_sup_mod->psh_info_enq_num = 0; -#endif /* DHDTCPACK_SUP_DBG */ - - /* Enqueue newly allocated tcpdata psh info elements to the pool */ - for (i = 0; i < TCPDATA_PSH_INFO_MAXNUM; i++) - _tdata_psh_info_pool_enq(tcpack_sup_mod, &tdata_psh_info_pool[i]); - - ASSERT(tcpack_sup_mod->tdata_psh_info_free != NULL); - tcpack_sup_mod->tdata_psh_info_pool = tdata_psh_info_pool; - - return BCME_OK; -} - -static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp, - tcpack_sup_module_t *tcpack_sup_mod) -{ - uint i; - tdata_psh_info_t *tdata_psh_info; - - DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); - - if (tcpack_sup_mod == NULL) { - DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n", - __FUNCTION__, __LINE__)); - return; - } - - for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { - tcpdata_info_t *tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; - /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */ - while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { - tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; - tdata_psh_info->next = NULL; - _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); - } - tcpdata_info->tdata_psh_info_tail = NULL; - } -#ifdef DHDTCPACK_SUP_DBG - DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - - i = 0; - /* Be sure we recollected all tdata_psh_info elements */ - while ((tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free)) { - tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; - tdata_psh_info->next = NULL; - i++; - } - ASSERT(i == TCPDATA_PSH_INFO_MAXNUM); - MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool, - sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); - tcpack_sup_mod->tdata_psh_info_pool = NULL; - - return; -} - -int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode) -{ - int ret = BCME_OK; - - dhd_os_tcpacklock(dhdp); - - if (dhdp->tcpack_sup_mode == mode) { - DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode)); - goto exit; - } - - if (mode > TCPACK_SUP_DELAYTX) { - DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__, __LINE__, mode)); - ret = BCME_BADARG; - goto exit; - } - - DHD_TRACE(("%s: %d -> %d\n", - __FUNCTION__, dhdp->tcpack_sup_mode, mode)); - - /* Old tcpack_sup_mode is TCPACK_SUP_DELAYTX */ - if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX) { - tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; - /* We won't need tdata_psh_info pool and tcpddata_info_tbl anymore */ - _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_mod); - tcpack_sup_mod->tcpdata_info_cnt = 0; - bzero(tcpack_sup_mod->tcpdata_info_tbl, - sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM); - /* For half duplex bus interface, tx precedes rx by default */ - if (dhdp->bus) - dhd_bus_set_dotxinrx(dhdp->bus, TRUE); - } - - dhdp->tcpack_sup_mode = mode; - - if (mode == TCPACK_SUP_OFF) { - ASSERT(dhdp->tcpack_sup_module != NULL); - MFREE(dhdp->osh, dhdp->tcpack_sup_module, sizeof(tcpack_sup_module_t)); - dhdp->tcpack_sup_module = NULL; - goto exit; - } - - if (dhdp->tcpack_sup_module == NULL) { - tcpack_sup_module_t *tcpack_sup_mod = - MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t)); - if (tcpack_sup_mod == NULL) { - DHD_ERROR(("%s %d: No MEM\n", __FUNCTION__, __LINE__)); - dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; - ret = BCME_NOMEM; - goto exit; - } - bzero(tcpack_sup_mod, sizeof(tcpack_sup_module_t)); - dhdp->tcpack_sup_module = tcpack_sup_mod; - } - - if (mode == TCPACK_SUP_DELAYTX) { - ret = _tdata_psh_info_pool_init(dhdp, dhdp->tcpack_sup_module); - if (ret != BCME_OK) - DHD_ERROR(("%s %d: pool init fail with %d\n", __FUNCTION__, __LINE__, ret)); - else if (dhdp->bus) - dhd_bus_set_dotxinrx(dhdp->bus, FALSE); - } - -exit: - dhd_os_tcpackunlock(dhdp); - return ret; -} - -void -dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp) -{ - tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) - goto exit; - - dhd_os_tcpacklock(dhdp); - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", - __FUNCTION__, __LINE__)); - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - tcpack_sup_mod->tcpack_info_cnt = 0; - bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM); - dhd_os_tcpackunlock(dhdp); - -exit: - return; -} - -inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt) -{ - uint8 i; - tcpack_sup_module_t *tcpack_sup_mod; - tcpack_info_t *tcpack_info_tbl; - int tbl_cnt; - uint pushed_len; - int ret = BCME_OK; - void *pdata; - uint32 pktlen; - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) - goto exit; - - pdata = PKTDATA(dhdp->osh, pkt); - - /* Length of BDC(+WLFC) headers pushed */ - pushed_len = BDC_HEADER_LEN + (((struct bdc_header *)pdata)->dataOffset * 4); - pktlen = PKTLEN(dhdp->osh, pkt) - pushed_len; - - if (pktlen < TCPACKSZMIN || pktlen > TCPACKSZMAX) { - DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", - __FUNCTION__, __LINE__, pktlen)); - goto exit; - } - - dhd_os_tcpacklock(dhdp); - tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp); - goto exit; - } - tbl_cnt = tcpack_sup_mod->tcpack_info_cnt; - tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; - - ASSERT(tbl_cnt <= TCPACK_INFO_MAXNUM); - - for (i = 0; i < tbl_cnt; i++) { - if (tcpack_info_tbl[i].pkt_in_q == pkt) { - DHD_TRACE(("%s %d: pkt %p sent out. idx %d, tbl_cnt %d\n", - __FUNCTION__, __LINE__, pkt, i, tbl_cnt)); - /* This pkt is being transmitted so remove the tcp_ack_info of it. */ - if (i < tbl_cnt - 1) { - bcopy(&tcpack_info_tbl[tbl_cnt - 1], - &tcpack_info_tbl[i], sizeof(tcpack_info_t)); - } - bzero(&tcpack_info_tbl[tbl_cnt - 1], sizeof(tcpack_info_t)); - if (--tcpack_sup_mod->tcpack_info_cnt < 0) { - DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); - ret = BCME_ERROR; - } - break; - } - } - dhd_os_tcpackunlock(dhdp); - -exit: - return ret; -} - -static INLINE bool dhd_tcpdata_psh_acked(dhd_pub_t *dhdp, uint8 *ip_hdr, - uint8 *tcp_hdr, uint32 tcp_ack_num) -{ - tcpack_sup_module_t *tcpack_sup_mod; - int i; - tcpdata_info_t *tcpdata_info = NULL; - tdata_psh_info_t *tdata_psh_info = NULL; - bool ret = FALSE; - - if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) - goto exit; - - tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - goto exit; - } - - DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d, ack %u\n", __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), - tcp_ack_num)); - - for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { - tcpdata_info_t *tcpdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; - DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, i, - IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->src_ip_addr)), - IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->dst_ip_addr)), - ntoh16_ua(tcpdata_info_tmp->src_tcp_port), - ntoh16_ua(tcpdata_info_tmp->dst_tcp_port))); - - /* If either IP address or TCP port number does not match, skip. */ - if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], - tcpdata_info_tmp->dst_ip_addr, IPV4_ADDR_LEN) == 0 && - memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET], - tcpdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN) == 0 && - memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], - tcpdata_info_tmp->dst_tcp_port, TCP_PORT_LEN) == 0 && - memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET], - tcpdata_info_tmp->src_tcp_port, TCP_PORT_LEN) == 0) { - tcpdata_info = tcpdata_info_tmp; - break; - } - } - - if (tcpdata_info == NULL) { - DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__, __LINE__)); - goto exit; - } - - if (tcpdata_info->tdata_psh_info_head == NULL) { - DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__, __LINE__)); - } - - while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { - if (IS_TCPSEQ_GE(tcp_ack_num, tdata_psh_info->end_seq)) { - DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n", - __FUNCTION__, __LINE__, tcp_ack_num, tdata_psh_info->end_seq)); - tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; - tdata_psh_info->next = NULL; - _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); - ret = TRUE; - } else - break; - } - if (tdata_psh_info == NULL) - tcpdata_info->tdata_psh_info_tail = NULL; - -#ifdef DHDTCPACK_SUP_DBG - DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - -exit: - return ret; -} - -bool -dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt) -{ - uint8 *new_ether_hdr; /* Ethernet header of the new packet */ - uint16 new_ether_type; /* Ethernet type of the new packet */ - uint8 *new_ip_hdr; /* IP header of the new packet */ - uint8 *new_tcp_hdr; /* TCP header of the new packet */ - uint32 new_ip_hdr_len; /* IP header length of the new packet */ - uint32 cur_framelen; - uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ - uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ - uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ - tcpack_sup_module_t *tcpack_sup_mod; - tcpack_info_t *tcpack_info_tbl; - int i; - bool ret = FALSE; - bool set_dotxinrx = TRUE; - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) - goto exit; - - new_ether_hdr = PKTDATA(dhdp->osh, pkt); - cur_framelen = PKTLEN(dhdp->osh, pkt); - - if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { - DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", - __FUNCTION__, __LINE__, cur_framelen)); - goto exit; - } - - new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; - - if (new_ether_type != ETHER_TYPE_IP) { - DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", - __FUNCTION__, __LINE__, new_ether_type)); - goto exit; - } - - DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); - - new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; - cur_framelen -= ETHER_HDR_LEN; - - ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); - - new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); - if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { - DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", - __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); - goto exit; - } - - new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; - cur_framelen -= new_ip_hdr_len; - - ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); - - DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); - - /* is it an ack ? Allow only ACK flag, not to suppress others. */ - if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { - DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", - __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); - goto exit; - } - - new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); - new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); - - /* This packet has TCP data, so just send */ - if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { - DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); - goto exit; - } - - ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); - - new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - DHD_TRACE(("%s %d: TCP ACK with zero DATA length" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", - __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ - dhd_os_tcpacklock(dhdp); -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - counter_printlog(&tack_tbl); - tack_tbl.cnt[0]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - - tcpack_sup_mod = dhdp->tcpack_sup_module; - tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - if (dhd_tcpdata_psh_acked(dhdp, new_ip_hdr, new_tcp_hdr, new_tcp_ack_num)) { - /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */ -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[5]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - } else - set_dotxinrx = FALSE; - - for (i = 0; i < tcpack_sup_mod->tcpack_info_cnt; i++) { - void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ - uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; - uint32 old_ip_hdr_len, old_tcp_hdr_len; - uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ - - if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { - DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); - break; - } - - if (PKTDATA(dhdp->osh, oldpkt) == NULL) { - DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); - break; - } - - old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; - old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; - old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); - old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; - old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); - - DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* If either of IP address or TCP port number does not match, skip. */ - if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], - &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || - memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], - &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) - continue; - - old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - if (IS_TCPSEQ_GT(new_tcp_ack_num, old_tcpack_num)) { - /* New packet has higher TCP ACK number, so it replaces the old packet */ - if (new_ip_hdr_len == old_ip_hdr_len && - new_tcp_hdr_len == old_tcp_hdr_len) { - ASSERT(memcmp(new_ether_hdr, old_ether_hdr, ETHER_HDR_LEN) == 0); - bcopy(new_ip_hdr, old_ip_hdr, new_ip_total_len); - PKTFREE(dhdp->osh, pkt, FALSE); - DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n", - __FUNCTION__, __LINE__, old_tcpack_num, new_tcp_ack_num)); -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[2]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - ret = TRUE; - } else - DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d\n", - __FUNCTION__, __LINE__, new_ip_hdr_len, old_ip_hdr_len, - new_tcp_hdr_len, old_tcp_hdr_len)); - } else if (new_tcp_ack_num == old_tcpack_num) { - set_dotxinrx = TRUE; - /* TCPACK retransmission */ -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[3]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - } else { - DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n", - __FUNCTION__, __LINE__, old_tcpack_num, oldpkt, - new_tcp_ack_num, pkt)); - } - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - if (i == tcpack_sup_mod->tcpack_info_cnt && i < TCPACK_INFO_MAXNUM) { - /* No TCPACK packet with the same IP addr and TCP port is found - * in tcp_ack_info_tbl. So add this packet to the table. - */ - DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", - __FUNCTION__, __LINE__, pkt, new_ether_hdr, - tcpack_sup_mod->tcpack_info_cnt)); - - tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_in_q = pkt; - tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_ether_hdr = new_ether_hdr; - tcpack_sup_mod->tcpack_info_cnt++; -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[1]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - } else { - ASSERT(i == tcpack_sup_mod->tcpack_info_cnt); - DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", - __FUNCTION__, __LINE__)); - } - dhd_os_tcpackunlock(dhdp); - -exit: - /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */ - if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX && set_dotxinrx) - dhd_bus_set_dotxinrx(dhdp->bus, TRUE); - - return ret; -} - -bool -dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt) -{ - uint8 *ether_hdr; /* Ethernet header of the new packet */ - uint16 ether_type; /* Ethernet type of the new packet */ - uint8 *ip_hdr; /* IP header of the new packet */ - uint8 *tcp_hdr; /* TCP header of the new packet */ - uint32 ip_hdr_len; /* IP header length of the new packet */ - uint32 cur_framelen; - uint16 ip_total_len; /* Total length of IP packet for the new packet */ - uint32 tcp_hdr_len; /* TCP header length of the new packet */ - uint32 tcp_seq_num; /* TCP sequence number of the new packet */ - uint16 tcp_data_len; /* TCP DATA length that excludes IP and TCP headers */ - uint32 end_tcp_seq_num; /* TCP seq number of the last byte in the new packet */ - tcpack_sup_module_t *tcpack_sup_mod; - tcpdata_info_t *tcpdata_info = NULL; - tdata_psh_info_t *tdata_psh_info; - - int i; - bool ret = FALSE; - - if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) - goto exit; - - ether_hdr = PKTDATA(dhdp->osh, pkt); - cur_framelen = PKTLEN(dhdp->osh, pkt); - - ether_type = ether_hdr[12] << 8 | ether_hdr[13]; - - if (ether_type != ETHER_TYPE_IP) { - DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", - __FUNCTION__, __LINE__, ether_type)); - goto exit; - } - - DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, ether_type)); - - ip_hdr = ether_hdr + ETHER_HDR_LEN; - cur_framelen -= ETHER_HDR_LEN; - - ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); - - ip_hdr_len = IPV4_HLEN(ip_hdr); - if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { - DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", - __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr))); - goto exit; - } - - tcp_hdr = ip_hdr + ip_hdr_len; - cur_framelen -= ip_hdr_len; - - ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); - - DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); - - ip_total_len = ntoh16_ua(&ip_hdr[IPV4_PKTLEN_OFFSET]); - tcp_hdr_len = 4 * TCP_HDRLEN(tcp_hdr[TCP_HLEN_OFFSET]); - - /* This packet is mere TCP ACK, so do nothing */ - if (ip_total_len == ip_hdr_len + tcp_hdr_len) { - DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__, __LINE__)); - goto exit; - } - - ASSERT(ip_total_len > ip_hdr_len + tcp_hdr_len); - - if ((tcp_hdr[TCP_FLAGS_OFFSET] & TCP_FLAG_PSH) == 0) { - DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__, __LINE__)); - goto exit; - } - - DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d, flag 0x%x\n", - __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), - tcp_hdr[TCP_FLAGS_OFFSET])); - - dhd_os_tcpacklock(dhdp); - tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp); - goto exit; - } - - /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */ - i = 0; - while (i < tcpack_sup_mod->tcpdata_info_cnt) { - tcpdata_info_t *tdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; - uint32 now_in_ms = OSL_SYSUPTIME(); - DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, i, - IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->src_ip_addr)), - IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->dst_ip_addr)), - ntoh16_ua(tdata_info_tmp->src_tcp_port), - ntoh16_ua(tdata_info_tmp->dst_tcp_port))); - - /* If both IP address and TCP port number match, we found it so break. */ - if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], - (void *)tdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN * 2) == 0 && - memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], - (void *)tdata_info_tmp->src_tcp_port, TCP_PORT_LEN * 2) == 0) { - tcpdata_info = tdata_info_tmp; - tcpdata_info->last_used_time = now_in_ms; - break; - } - - if (now_in_ms - tdata_info_tmp->last_used_time > TCPDATA_INFO_TIMEOUT) { - tdata_psh_info_t *tdata_psh_info_tmp; - tcpdata_info_t *last_tdata_info; - - while ((tdata_psh_info_tmp = tdata_info_tmp->tdata_psh_info_head)) { - tdata_info_tmp->tdata_psh_info_head = tdata_psh_info_tmp->next; - tdata_psh_info_tmp->next = NULL; - DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n", - __FUNCTION__, __LINE__, tdata_psh_info_tmp->end_seq)); - _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info_tmp); - } -#ifdef DHDTCPACK_SUP_DBG - DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - tcpack_sup_mod->tcpdata_info_cnt--; - ASSERT(tcpack_sup_mod->tcpdata_info_cnt >= 0); - - last_tdata_info = - &tcpack_sup_mod->tcpdata_info_tbl[tcpack_sup_mod->tcpdata_info_cnt]; - if (i < tcpack_sup_mod->tcpdata_info_cnt) { - ASSERT(last_tdata_info != tdata_info_tmp); - bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t)); - } - bzero(last_tdata_info, sizeof(tcpdata_info_t)); - DHD_ERROR(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt)); - /* Don't increase "i" here, so that the prev last tcpdata_info is checked */ - } else - i++; - } - - tcp_seq_num = ntoh32_ua(&tcp_hdr[TCP_SEQ_NUM_OFFSET]); - tcp_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len; - end_tcp_seq_num = tcp_seq_num + tcp_data_len; - - if (tcpdata_info == NULL) { - ASSERT(i == tcpack_sup_mod->tcpdata_info_cnt); - if (i >= TCPDATA_INFO_MAXNUM) { - DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); - dhd_os_tcpackunlock(dhdp); - goto exit; - } - tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; - - /* No TCP flow with the same IP addr and TCP port is found - * in tcp_data_info_tbl. So add this flow to the table. - */ - DHD_ERROR(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - bcopy(&ip_hdr[IPV4_SRC_IP_OFFSET], (void *)tcpdata_info->src_ip_addr, - IPV4_ADDR_LEN * 2); - bcopy(&tcp_hdr[TCP_SRC_PORT_OFFSET], (void *)tcpdata_info->src_tcp_port, - TCP_PORT_LEN * 2); - - tcpdata_info->last_used_time = OSL_SYSUPTIME(); - tcpack_sup_mod->tcpdata_info_cnt++; - } - - ASSERT(tcpdata_info != NULL); - - tdata_psh_info = _tdata_psh_info_pool_deq(tcpack_sup_mod); -#ifdef DHDTCPACK_SUP_DBG - DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - - if (tdata_psh_info == NULL) { - DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp); - goto exit; - } - tdata_psh_info->end_seq = end_tcp_seq_num; - -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[4]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - - DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n", - __FUNCTION__, __LINE__, tdata_psh_info->end_seq)); - - ASSERT(tdata_psh_info->next == NULL); - - if (tcpdata_info->tdata_psh_info_head == NULL) - tcpdata_info->tdata_psh_info_head = tdata_psh_info; - else { - ASSERT(tcpdata_info->tdata_psh_info_tail); - tcpdata_info->tdata_psh_info_tail->next = tdata_psh_info; - } - tcpdata_info->tdata_psh_info_tail = tdata_psh_info; - - dhd_os_tcpackunlock(dhdp); - -exit: - return ret; -} - -#endif /* DHDTCPACK_SUPPRESS */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h deleted file mode 100755 index 62ce6b5700ff..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Header file describing the common ip parser function. - * - * Provides type definitions and function prototypes used to parse ip packet. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_ip.h 457888 2014-02-25 03:34:39Z $ - */ - -#ifndef _dhd_ip_h_ -#define _dhd_ip_h_ - -#ifdef DHDTCPACK_SUPPRESS -#include -#include -#include -#endif /* DHDTCPACK_SUPPRESS */ - -typedef enum pkt_frag -{ - DHD_PKT_FRAG_NONE = 0, - DHD_PKT_FRAG_FIRST, - DHD_PKT_FRAG_CONT, - DHD_PKT_FRAG_LAST -} pkt_frag_t; - -extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p); - -#ifdef DHDTCPACK_SUPPRESS -#define TCPACKSZMIN (ETHER_HDR_LEN + IPV4_MIN_HEADER_LEN + TCP_MIN_HEADER_LEN) -/* Size of MAX possible TCP ACK packet. Extra bytes for IP/TCP option fields */ -#define TCPACKSZMAX (TCPACKSZMIN + 100) - -/* Max number of TCP streams that have own src/dst IP addrs and TCP ports */ -#define TCPACK_INFO_MAXNUM 4 -#define TCPDATA_INFO_MAXNUM 4 -#define TCPDATA_PSH_INFO_MAXNUM (8 * TCPDATA_INFO_MAXNUM) - -#define TCPDATA_INFO_TIMEOUT 5000 /* Remove tcpdata_info if inactive for this time (in ms) */ - -extern int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 on); -extern void dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp); -extern int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt); -extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt); -extern bool dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt); - -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) -extern counter_tbl_t tack_tbl; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ -#endif /* DHDTCPACK_SUPPRESS */ - -#endif /* _dhd_ip_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c deleted file mode 100755 index ac136f6867f6..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c +++ /dev/null @@ -1,8431 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Linux-specific network interface - * Basically selected code segments from usb-cdc.c and usb-rndis.c - * - * Copyright (C) 1999-2018, Broadcom Corporation - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux.c 718508 2017-08-31 02:48:38Z $ - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_HAS_WAKELOCK -#include -#endif -#ifdef WL_CFG80211 -#include -#endif -#ifdef CUSTOM_COUNTRY_CODE -#include -#endif -#ifdef PNO_SUPPORT -#include -#endif -#ifdef RTT_SUPPORT -#include -#endif - -#ifdef CONFIG_COMPAT -#include -#endif - -#ifdef AMPDU_VO_ENABLE -#include -#endif /* AMPDU_VO_ENABLE */ -#ifdef DHDTCPACK_SUPPRESS -#include -#endif /* DHDTCPACK_SUPPRESS */ - - -#ifdef WLMEDIA_HTSF -#include -#include - -#define HTSF_MINLEN 200 /* min. packet length to timestamp */ -#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ -#define TSMAX 1000 /* max no. of timing record kept */ -#define NUMBIN 34 - -static uint32 tsidx = 0; -static uint32 htsf_seqnum = 0; -uint32 tsfsync; -struct timeval tsync; -static uint32 tsport = 5010; - -typedef struct histo_ { - uint32 bin[NUMBIN]; -} histo_t; - -#if !ISPOWEROF2(DHD_SDALIGN) -#error DHD_SDALIGN is not a power of 2! -#endif - -static histo_t vi_d1, vi_d2, vi_d3, vi_d4; -#endif /* WLMEDIA_HTSF */ - - - -#if defined(SOFTAP) -extern bool ap_cfg_running; -extern bool ap_fw_loaded; -#endif - - -#ifdef ENABLE_ADAPTIVE_SCHED -#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */ -#ifndef CUSTOM_CPUFREQ_THRESH -#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH -#endif /* CUSTOM_CPUFREQ_THRESH */ -#endif /* ENABLE_ADAPTIVE_SCHED */ - -/* enable HOSTIP cache update from the host side when an eth0:N is up */ -#define AOE_IP_ALIAS_SUPPORT 1 - -#ifdef BCM_FD_AGGR -#include -#include -#endif -#ifdef PROP_TXSTATUS -#include -#include -#endif - -#include - -#include - -#ifdef ARP_OFFLOAD_SUPPORT -void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); -static int dhd_inetaddr_notifier_call(struct notifier_block *this, - unsigned long event, void *ptr); -static struct notifier_block dhd_inetaddr_notifier = { - .notifier_call = dhd_inetaddr_notifier_call -}; -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool dhd_inetaddr_notifier_registered = FALSE; -#endif /* ARP_OFFLOAD_SUPPORT */ - -static int dhd_inet6addr_notifier_call(struct notifier_block *this, - unsigned long event, void *ptr); -static struct notifier_block dhd_inet6addr_notifier = { - .notifier_call = dhd_inet6addr_notifier_call -}; -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool dhd_inet6addr_notifier_registered = FALSE; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -#include -volatile bool dhd_mmc_suspend = FALSE; -DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - -#if defined(OOB_INTR_ONLY) -extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -static void dhd_hang_process(void *dhd_info, void *event_data, u8 event); -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -MODULE_LICENSE("GPL v2"); -#endif /* LinuxVer */ - -#include - -#ifdef BCM_FD_AGGR -#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) -#else -#ifndef PROP_TXSTATUS -#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) -#else -#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) -#endif -#endif /* BCM_FD_AGGR */ - -#ifdef PROP_TXSTATUS -extern bool dhd_wlfc_skip_fc(void); -extern void dhd_wlfc_plat_init(void *dhd); -extern void dhd_wlfc_plat_deinit(void *dhd); -#endif /* PROP_TXSTATUS */ - -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) -const char * -print_tainted() -{ - return ""; -} -#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ - -/* Linux wireless extension support */ -#if defined(WL_WIRELESS_EXT) -#include -extern wl_iw_extra_params_t g_wl_iw_params; -#endif /* defined(WL_WIRELESS_EXT) */ - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -#include -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ - -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); - -#ifdef PKT_FILTER_SUPPORT -extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); -extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id); -#endif - - -#ifdef READ_MACADDR -extern int dhd_read_macaddr(struct dhd_info *dhd); -#else -static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; } -#endif -#ifdef WRITE_MACADDR -extern int dhd_write_macaddr(struct ether_addr *mac); -#else -static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; } -#endif - -#ifdef ENABLE_CONTROL_SCHED -#ifndef ENABLE_ADAPTIVE_SCHED -#error ENABLE_ADAPTIVE_SCHED not define. -#endif /* ENABLE_ADAPTIVE_SCHED */ -static int dhd_sysfs_create_node(struct net_device *net); -static void dhd_sysfs_destroy_node(struct net_device *net); -#endif /* ENABLE_CONTROL_SCHED */ - - - - -typedef struct dhd_if_event { - struct list_head list; - wl_event_data_if_t event; - char name[IFNAMSIZ+1]; - uint8 mac[ETHER_ADDR_LEN]; -} dhd_if_event_t; - -/* Interface control information */ -typedef struct dhd_if { - struct dhd_info *info; /* back pointer to dhd_info */ - /* OS/stack specifics */ - struct net_device *net; - struct net_device_stats stats; - int idx; /* iface idx in dongle */ - uint subunit; /* subunit */ - uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ - bool attached; /* Delayed attachment when unset */ - bool txflowcontrol; /* Per interface flow control indicator */ - char name[IFNAMSIZ+1]; /* linux interface name */ - uint8 bssidx; /* bsscfg index for the interface */ - bool set_macaddress; - bool set_multicast; -} dhd_if_t; - -#ifdef WLMEDIA_HTSF -typedef struct { - uint32 low; - uint32 high; -} tsf_t; - -typedef struct { - uint32 last_cycle; - uint32 last_sec; - uint32 last_tsf; - uint32 coef; /* scaling factor */ - uint32 coefdec1; /* first decimal */ - uint32 coefdec2; /* second decimal */ -} htsf_t; - -typedef struct { - uint32 t1; - uint32 t2; - uint32 t3; - uint32 t4; -} tstamp_t; - -static tstamp_t ts[TSMAX]; -static tstamp_t maxdelayts; -static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; - -#endif /* WLMEDIA_HTSF */ - -struct ipv6_work_info_t { - uint8 if_idx; - char ipv6_addr[16]; - unsigned long event; -}; - -#ifdef DHD_DEBUG -typedef struct dhd_dump { - uint8 *buf; - int bufsize; -} dhd_dump_t; -#endif /* DHD_DEBUG */ - -/* Local private structure (extension of pub) */ -typedef struct dhd_info { -#if defined(WL_WIRELESS_EXT) - wl_iw_t iw; /* wireless extensions state (must be first) */ -#endif /* defined(WL_WIRELESS_EXT) */ - - dhd_pub_t pub; - void *adapter; /* adapter information, interrupt, fw path etc. */ - char fw_path[PATH_MAX]; /* path to firmware image */ - char nv_path[PATH_MAX]; /* path to nvram vars file */ - - /* For supporting multiple interfaces */ - dhd_if_t *iflist[DHD_MAX_IFS]; - - struct semaphore proto_sem; -#ifdef PROP_TXSTATUS - spinlock_t wlfc_spinlock; - -#endif /* PROP_TXSTATUS */ -#ifdef WLMEDIA_HTSF - htsf_t htsf; -#endif - wait_queue_head_t ioctl_resp_wait; - uint32 default_wd_interval; - - struct timer_list timer; - bool wd_timer_valid; - struct tasklet_struct tasklet; - spinlock_t sdlock; - spinlock_t txqlock; - spinlock_t dhd_lock; - - struct semaphore sdsem; - tsk_ctl_t thr_dpc_ctl; - tsk_ctl_t thr_wdt_ctl; - - tsk_ctl_t thr_rxf_ctl; - spinlock_t rxf_lock; - bool rxthread_enabled; - - /* Wakelocks */ -#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - struct wake_lock wl_wifi; /* Wifi wakelock */ - struct wake_lock wl_rxwake; /* Wifi rx wakelock */ - struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */ - struct wake_lock wl_wdwake; /* Wifi wd wakelock */ -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - /* net_device interface lock, prevent race conditions among net_dev interface - * calls and wifi_on or wifi_off - */ - struct mutex dhd_net_if_mutex; - struct mutex dhd_suspend_mutex; -#endif - spinlock_t wakelock_spinlock; - uint32 wakelock_counter; - bool waive_wakelock; - uint32 wakelock_before_waive; - int wakelock_wd_counter; - int wakelock_rx_timeout_enable; - int wakelock_ctrl_timeout_enable; - - /* Thread to issue ioctl for multicast */ - wait_queue_head_t ctrl_wait; - atomic_t pend_8021x_cnt; - dhd_attach_states_t dhd_state; - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - struct early_suspend early_suspend; -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -#ifdef ARP_OFFLOAD_SUPPORT - u32 pend_ipaddr; -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef BCM_FD_AGGR - void *rpc_th; - void *rpc_osh; - struct timer_list rpcth_timer; - bool rpcth_timer_active; - bool fdaggr; -#endif -#ifdef DHDTCPACK_SUPPRESS - spinlock_t tcpack_lock; -#endif /* DHDTCPACK_SUPPRESS */ - void *dhd_deferred_wq; -#ifdef DEBUG_CPU_FREQ - struct notifier_block freq_trans; - int __percpu *new_freq; -#endif - unsigned int unit; - struct notifier_block pm_notifier; -#ifdef SAR_SUPPORT - struct notifier_block sar_notifier; -#endif -#ifdef DHD_DEBUG - dhd_dump_t *dump; - struct timer_list join_timer; - u32 join_timeout_val; - bool join_timer_active; - uint scan_time_count; - struct timer_list scan_timer; - bool scan_timer_active; -#endif /* DHD_DEBUG */ -} dhd_info_t; - -/* Flag to indicate if we should download firmware on driver load */ -uint dhd_download_fw_on_driverload = TRUE; - -/* Definitions to provide path to the firmware and nvram - * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" - */ -char firmware_path[MOD_PARAM_PATHLEN]; -char nvram_path[MOD_PARAM_PATHLEN]; - -/* information string to keep firmware, chio, cheip version info visiable from log */ -char info_string[MOD_PARAM_INFOLEN]; -module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); -#ifdef CONFIG_BCM_WLAN_RAMDUMP -char bcm_wlan_ver_info[BCM_WLAN_CRASH_REASON_LEN]; -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ -int op_mode = 0; -int disable_proptx = 0; -module_param(op_mode, int, 0644); -extern int wl_control_wl_start(struct net_device *dev); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC) -struct semaphore dhd_registration_sem; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - -/* deferred handlers */ -static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event); -static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event); -static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event); -static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event); -static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event); - -#ifdef WL_CFG80211 -extern void dhd_netdev_free(struct net_device *ndev); -#endif /* WL_CFG80211 */ - -/* Error bits */ -module_param(dhd_msg_level, int, 0); - -#ifdef ARP_OFFLOAD_SUPPORT -/* ARP offload enable */ -uint dhd_arp_enable = TRUE; -module_param(dhd_arp_enable, uint, 0); - -/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ - -uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; - -module_param(dhd_arp_mode, uint, 0); -#endif /* ARP_OFFLOAD_SUPPORT */ - -/* Disable Prop tx */ -module_param(disable_proptx, int, 0644); -/* load firmware and/or nvram values from the filesystem */ -module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); -module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660); - -/* Disable VHT(11ac) mode */ -#if !defined(DISABLE_11AC) -int somc_disable_vht = 0; -module_param(somc_disable_vht, int, 0660); -#endif /* ! DISABLE_11AC */ - -/* Watchdog interval */ - -/* extend watchdog expiration to 2 seconds when DPC is running */ -#define WATCHDOG_EXTEND_INTERVAL (2000) - -uint dhd_watchdog_ms = 10; -module_param(dhd_watchdog_ms, uint, 0); - -#if defined(DHD_DEBUG) -/* Console poll interval */ -uint dhd_console_ms = 0; -module_param(dhd_console_ms, uint, 0644); -#endif /* defined(DHD_DEBUG) */ - - -uint dhd_slpauto = TRUE; -module_param(dhd_slpauto, uint, 0); - -#ifdef PKT_FILTER_SUPPORT -/* Global Pkt filter enable control */ -uint dhd_pkt_filter_enable = TRUE; -module_param(dhd_pkt_filter_enable, uint, 0); -#endif - -/* Pkt filter init setup */ -uint dhd_pkt_filter_init = 0; -module_param(dhd_pkt_filter_init, uint, 0); - -/* Pkt filter mode control */ -uint dhd_master_mode = TRUE; -module_param(dhd_master_mode, uint, 0); - -int dhd_watchdog_prio = 0; -module_param(dhd_watchdog_prio, int, 0); - -/* DPC thread priority */ -int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; -module_param(dhd_dpc_prio, int, 0); - -/* RX frame thread priority */ -int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; -module_param(dhd_rxf_prio, int, 0); - -#if !defined(BCMDHDUSB) -extern int dhd_dongle_ramsize; -module_param(dhd_dongle_ramsize, int, 0); -#endif /* BCMDHDUSB */ - -/* Keep track of number of instances */ -static int dhd_found = 0; -static int instance_base = 0; /* Starting instance number */ -module_param(instance_base, int, 0644); - -/* Control fw roaming */ -#ifdef BCMCCX -uint dhd_roam_disable = 0; -#else -uint dhd_roam_disable = 0; -#endif /* BCMCCX */ - -/* Control radio state */ -uint dhd_radio_up = 1; - -/* Network inteface name */ -char iface_name[IFNAMSIZ] = {'\0'}; -module_param_string(iface_name, iface_name, IFNAMSIZ, 0); - -/* The following are specific to the SDIO dongle */ - -/* IOCTL response timeout */ -int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; - -/* Idle timeout for backplane clock */ -int dhd_idletime = DHD_IDLETIME_TICKS; -module_param(dhd_idletime, int, 0); - -/* Use polling */ -uint dhd_poll = FALSE; -module_param(dhd_poll, uint, 0); - -/* Use interrupts */ -uint dhd_intr = TRUE; -module_param(dhd_intr, uint, 0); - -/* SDIO Drive Strength (in milliamps) */ -uint dhd_sdiod_drive_strength = 6; -module_param(dhd_sdiod_drive_strength, uint, 0); - -/* Tx/Rx bounds */ -extern uint dhd_txbound; -extern uint dhd_rxbound; -module_param(dhd_txbound, uint, 0); -module_param(dhd_rxbound, uint, 0); - -/* Deferred transmits */ -extern uint dhd_deferred_tx; -module_param(dhd_deferred_tx, uint, 0); - -#ifdef BCMDBGFS -extern void dhd_dbg_init(dhd_pub_t *dhdp); -extern void dhd_dbg_remove(void); -#endif /* BCMDBGFS */ - - - -#ifdef SDTEST -/* Echo packet generator (pkts/s) */ -uint dhd_pktgen = 0; -module_param(dhd_pktgen, uint, 0); - -/* Echo packet len (0 => sawtooth, max 2040) */ -uint dhd_pktgen_len = 0; -module_param(dhd_pktgen_len, uint, 0); -#endif /* SDTEST */ - - -extern char dhd_version[]; - -int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); -static void dhd_net_if_lock_local(dhd_info_t *dhd); -static void dhd_net_if_unlock_local(dhd_info_t *dhd); -static void dhd_suspend_lock(dhd_pub_t *dhdp); -static void dhd_suspend_unlock(dhd_pub_t *dhdp); - -#ifdef WLMEDIA_HTSF -void htsf_update(dhd_info_t *dhd, void *data); -tsf_t prev_tsf, cur_tsf; - -uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); -static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); -static void dhd_dump_latency(void); -static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); -static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); -static void dhd_dump_htsfhisto(histo_t *his, char *s); -#endif /* WLMEDIA_HTSF */ - -/* Monitor interface */ -int dhd_monitor_init(void *dhd_pub); -int dhd_monitor_uninit(void); - - -#if defined(WL_WIRELESS_EXT) -struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); -#endif /* defined(WL_WIRELESS_EXT) */ - -static void dhd_dpc(ulong data); -/* forward decl */ -extern int dhd_wait_pend8021x(struct net_device *dev); -void dhd_os_wd_timer_extend(void *bus, bool extend); - -#ifdef TOE -#ifndef BDC -#error TOE requires BDC -#endif /* !BDC */ -static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); -static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); -#endif /* TOE */ - -static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, - wl_event_msg_t *event_ptr, void **data_ptr); -#if defined(SUPPORT_P2P_GO_PS) -#ifdef PROP_TXSTATUS -static int dhd_wakelock_waive(dhd_info_t *dhdinfo); -static int dhd_wakelock_restore(dhd_info_t *dhdinfo); -#endif -#endif /* defined(SUPPORT_P2P_GO_PS) */ - -#if defined(CONFIG_PM_SLEEP) -static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) -{ - int ret = NOTIFY_DONE; - bool suspend = FALSE; - dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier); - - BCM_REFERENCE(dhdinfo); - switch (action) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - suspend = TRUE; - break; - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - suspend = FALSE; - break; - } - -#if defined(SUPPORT_P2P_GO_PS) -#ifdef PROP_TXSTATUS - if (suspend) { - dhd_wakelock_waive(dhdinfo); - dhd_wlfc_suspend(&dhdinfo->pub); - dhd_wakelock_restore(dhdinfo); - } else { - dhd_wlfc_resume(&dhdinfo->pub); - } - -#endif -#endif /* defined(SUPPORT_P2P_GO_PS) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ - KERNEL_VERSION(2, 6, 39)) - dhd_mmc_suspend = suspend; - smp_mb(); -#endif - return ret; -} - -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool dhd_pm_notifier_registered = FALSE; - -extern int register_pm_notifier(struct notifier_block *nb); -extern int unregister_pm_notifier(struct notifier_block *nb); -#endif /* defined(CONFIG_PM_SLEEP) */ - -#ifdef SAR_SUPPORT -static int dhd_sar_callback(struct notifier_block *nfb, unsigned long action, void *ignored) -{ - dhd_info_t *dhd = (dhd_info_t*)container_of(nfb, struct dhd_info, sar_notifier); - s32 sar_enable; - int ret = 0; - - /* '1' means activate sarlimit and '0' means back to normal state (deactivate - * sarlimit) - */ - sar_enable = action ? 1 : 0; - - ret = dhd_iovar(dhd, 0, "sar_enable", (char *)&sar_enable, sizeof(sar_enable), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s wl sar_enable %d failed %d\n", __FUNCTION__, sar_enable, ret)); - - return NOTIFY_DONE; -} - -static bool dhd_sar_notifier_registered = FALSE; - -extern int register_notifier_by_sar(struct notifier_block *nb); -extern int unregister_notifier_by_sar(struct notifier_block *nb); -#endif /* defined(SAR_SUPPORT) */ - -/* Request scheduling of the bus rx frame */ -static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb); -static void dhd_os_rxflock(dhd_pub_t *pub); -static void dhd_os_rxfunlock(dhd_pub_t *pub); - -static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb) -{ - uint32 store_idx; - uint32 sent_idx; - - if (!skb) { - DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n")); - return BCME_ERROR; - } - - dhd_os_rxflock(dhdp); - store_idx = dhdp->store_idx; - sent_idx = dhdp->sent_idx; - if (dhdp->skbbuf[store_idx] != NULL) { - /* Make sure the previous packets are processed */ - dhd_os_rxfunlock(dhdp); -#ifdef RXF_DEQUEUE_ON_BUSY - DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", - skb, store_idx, sent_idx)); - return BCME_BUSY; -#else /* RXF_DEQUEUE_ON_BUSY */ - DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", - skb, store_idx, sent_idx)); - /* removed msleep here, should use wait_event_timeout if we - * want to give rx frame thread a chance to run - */ -#if defined(WAIT_DEQUEUE) - OSL_SLEEP(1); -#endif - return BCME_ERROR; -#endif /* RXF_DEQUEUE_ON_BUSY */ - } - DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n", - skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1))); - dhdp->skbbuf[store_idx] = skb; - dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1); - dhd_os_rxfunlock(dhdp); - - return BCME_OK; -} - -static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp) -{ - uint32 store_idx; - uint32 sent_idx; - void *skb; - - dhd_os_rxflock(dhdp); - - store_idx = dhdp->store_idx; - sent_idx = dhdp->sent_idx; - skb = dhdp->skbbuf[sent_idx]; - - if (skb == NULL) { - dhd_os_rxfunlock(dhdp); - DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n", - store_idx, sent_idx)); - return NULL; - } - - dhdp->skbbuf[sent_idx] = NULL; - dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1); - - DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n", - skb, sent_idx)); - - dhd_os_rxfunlock(dhdp); - - return skb; -} - -static int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - if (prepost) { /* pre process */ - dhd_read_macaddr(dhd); - } else { /* post process */ - dhd_write_macaddr(&dhd->pub.mac); - } - - return 0; -} - -#if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) -static bool -_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode) -{ - bool _apply = FALSE; - /* In case of IBSS mode, apply arp pkt filter */ - if (op_mode & DHD_FLAG_IBSS_MODE) { - _apply = TRUE; - goto exit; - } - /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */ - if ((dhd->arp_version == 1) && - (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { - _apply = TRUE; - goto exit; - } - -exit: - return _apply; -} -#endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */ - -void dhd_set_packet_filter(dhd_pub_t *dhd) -{ -#ifdef PKT_FILTER_SUPPORT - int i; - - DHD_TRACE(("%s: enter\n", __FUNCTION__)); - if (dhd_pkt_filter_enable) { - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); - } - } -#endif /* PKT_FILTER_SUPPORT */ -} - -void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) -{ -#ifdef PKT_FILTER_SUPPORT - int i; - - DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value)); - /* 1 - Enable packet filter, only allow unicast packet to send up */ - /* 0 - Disable packet filter */ - if (dhd_pkt_filter_enable && (!value || - (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) - { - for (i = 0; i < dhd->pktfilter_count; i++) { -#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER - if (value && (i == DHD_ARP_FILTER_NUM) && - !_turn_on_arp_filter(dhd, dhd->op_mode)) { - DHD_TRACE(("Do not turn on ARP white list pkt filter:" - "val %d, cnt %d, op_mode 0x%x\n", - value, i, dhd->op_mode)); - continue; - } -#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - value, dhd_master_mode); - } - } -#endif /* PKT_FILTER_SUPPORT */ -} - -static int dhd_set_suspend(int value, dhd_pub_t *dhd) -{ -#ifndef SUPPORT_PM2_ONLY - int power_mode = PM_MAX; -#endif /* SUPPORT_PM2_ONLY */ - /* wl_pkt_filter_enable_t enable_parm; */ - int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ -#ifndef ENABLE_FW_ROAM_SUSPEND - uint roamvar = 1; -#endif /* ENABLE_FW_ROAM_SUSPEND */ - uint nd_ra_filter = 0; - int ret = 0; - -#ifdef DYNAMIC_SWOOB_DURATION -#ifndef CUSTOM_INTR_WIDTH -#define CUSTOM_INTR_WIDTH 100 -#endif /* CUSTOM_INTR_WIDTH */ - int intr_width = 0; -#endif /* DYNAMIC_SWOOB_DURATION */ - if (!dhd) - return -ENODEV; - - DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", - __FUNCTION__, value, dhd->in_suspend)); - - dhd_suspend_lock(dhd); - - if (dhd->up) { - if (value && dhd->in_suspend) { -#ifdef PKT_FILTER_SUPPORT - dhd->early_suspended = 1; -#endif - /* Kernel suspended */ - DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); - -#ifndef SUPPORT_PM2_ONLY - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); -#endif /* SUPPORT_PM2_ONLY */ - - /* Enable packet filter, only allow unicast packet to send up */ - dhd_enable_packet_filter(1, dhd); - - - /* If DTIM skip is set up as default, force it to wake - * each third DTIM for better power savings. Note that - * one side effect is a chance to miss BC/MC packet. - */ - bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); - - ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); - -#ifndef ENABLE_FW_ROAM_SUSPEND - /* Disable firmware roaming during suspend */ - dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, - sizeof(roamvar), NULL, 0, TRUE); -#endif /* ENABLE_FW_ROAM_SUSPEND */ - if (FW_SUPPORTED(dhd, ndoe)) { - /* enable IPv6 RA filter in firmware during suspend */ - nd_ra_filter = 1; - ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", - (char *)&nd_ra_filter, sizeof(nd_ra_filter), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("failed to set nd_ra_filter (%d)\n", - ret)); - } -#ifdef DYNAMIC_SWOOB_DURATION - intr_width = CUSTOM_INTR_WIDTH; - ret = dhd_iovar(dhd, 0, "bus:intr_width", (char *)&intr_width, - sizeof(intr_width), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("failed to set intr_width (%d)\n", ret)); - } -#endif /* DYNAMIC_SWOOB_DURATION */ - } else { -#ifdef PKT_FILTER_SUPPORT - dhd->early_suspended = 0; -#endif - /* Kernel resumed */ - DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__)); -#ifdef DYNAMIC_SWOOB_DURATION - intr_width = 0; - ret = dhd_iovar(dhd, 0, "bus:intr_width", (char *)&intr_width, - sizeof(intr_width), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("failed to set intr_width (%d)\n", ret)); - } -#endif /* DYNAMIC_SWOOB_DURATION */ - -#ifndef SUPPORT_PM2_ONLY - power_mode = PM_FAST; - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); -#endif /* SUPPORT_PM2_ONLY */ -#ifdef PKT_FILTER_SUPPORT - /* disable pkt filter */ - dhd_enable_packet_filter(0, dhd); -#endif /* PKT_FILTER_SUPPORT */ - - /* restore pre-suspend setting for dtim_skip */ - dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE); -#ifndef ENABLE_FW_ROAM_SUSPEND - roamvar = dhd_roam_disable; - dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, - sizeof(roamvar), NULL, 0, TRUE); -#endif /* ENABLE_FW_ROAM_SUSPEND */ - if (FW_SUPPORTED(dhd, ndoe)) { - /* disable IPv6 RA filter in firmware during suspend */ - nd_ra_filter = 0; - ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", - (char *)&nd_ra_filter, sizeof(nd_ra_filter), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("failed to set nd_ra_filter (%d)\n", - ret)); - } - } - } - dhd_suspend_unlock(dhd); - - return 0; -} - -static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) -{ - dhd_pub_t *dhdp = &dhd->pub; - int ret = 0; - - DHD_OS_WAKE_LOCK(dhdp); - /* Set flag when early suspend was called */ - dhdp->in_suspend = val; - if ((force || !dhdp->suspend_disable_flag) && - dhd_support_sta_mode(dhdp)) - { - ret = dhd_set_suspend(val, dhdp); - } - - DHD_OS_WAKE_UNLOCK(dhdp); - return ret; -} - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -static void dhd_early_suspend(struct early_suspend *h) -{ - struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); - - if (dhd) - dhd_suspend_resume_helper(dhd, 1, 0); -} - -static void dhd_late_resume(struct early_suspend *h) -{ - struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); - - if (dhd) - dhd_suspend_resume_helper(dhd, 0, 0); -} -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -/* - * Generalized timeout mechanism. Uses spin sleep with exponential back-off until - * the sleep time reaches one jiffy, then switches over to task delay. Usage: - * - * dhd_timeout_start(&tmo, usec); - * while (!dhd_timeout_expired(&tmo)) - * if (poll_something()) - * break; - * if (dhd_timeout_expired(&tmo)) - * fatal(); - */ - -void -dhd_timeout_start(dhd_timeout_t *tmo, uint usec) -{ - tmo->limit = usec; - tmo->increment = 0; - tmo->elapsed = 0; - tmo->tick = jiffies_to_usecs(1); -} - -int -dhd_timeout_expired(dhd_timeout_t *tmo) -{ - /* Does nothing the first call */ - if (tmo->increment == 0) { - tmo->increment = 1; - return 0; - } - - if (tmo->elapsed >= tmo->limit) - return 1; - - /* Add the delay that's about to take place */ - tmo->elapsed += tmo->increment; - - if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) { - OSL_DELAY(tmo->increment); - tmo->increment *= 2; - if (tmo->increment > tmo->tick) - tmo->increment = tmo->tick; - } else { - wait_queue_head_t delay_wait; - DECLARE_WAITQUEUE(wait, current); - init_waitqueue_head(&delay_wait); - add_wait_queue(&delay_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - remove_wait_queue(&delay_wait, &wait); - set_current_state(TASK_RUNNING); - } - - return 0; -} - -int -dhd_net2idx(dhd_info_t *dhd, struct net_device *net) -{ - int i = 0; - - ASSERT(dhd); - while (i < DHD_MAX_IFS) { - if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net)) - return i; - i++; - } - - return DHD_BAD_IF; -} - -struct net_device * dhd_idx2net(void *pub, int ifidx) -{ - struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; - struct dhd_info *dhd_info; - - if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) - return NULL; - dhd_info = dhd_pub->info; - if (dhd_info && dhd_info->iflist[ifidx]) - return dhd_info->iflist[ifidx]->net; - return NULL; -} - -int -dhd_ifname2idx(dhd_info_t *dhd, char *name) -{ - int i = DHD_MAX_IFS; - - ASSERT(dhd); - - if (name == NULL || *name == '\0') - return 0; - - while (--i > 0) - if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ)) - break; - - DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name)); - - return i; /* default - the primary interface */ -} - -char * -dhd_ifname(dhd_pub_t *dhdp, int ifidx) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - ASSERT(dhd); - - if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { - DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); - return ""; - } - - if (dhd->iflist[ifidx] == NULL) { - DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); - return ""; - } - - if (dhd->iflist[ifidx]->net) - return dhd->iflist[ifidx]->net->name; - - return ""; -} - -uint8 * -dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) -{ - int i; - dhd_info_t *dhd = (dhd_info_t *)dhdp; - - ASSERT(dhd); - for (i = 0; i < DHD_MAX_IFS; i++) - if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) - return dhd->iflist[i]->mac_addr; - - return NULL; -} - - -static void -_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) -{ - struct net_device *dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - struct netdev_hw_addr *ha; -#else - struct dev_mc_list *mclist; -#endif - uint32 allmulti, cnt; - - wl_ioctl_t ioc; - char *buf, *bufp; - uint buflen; - int ret; - - ASSERT(dhd && dhd->iflist[ifidx]); - dev = dhd->iflist[ifidx]->net; - if (!dev) - return; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - cnt = netdev_mc_count(dev); -#else - cnt = dev->mc_count; -#endif /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); -#endif - - /* Determine initial value of allmulti flag */ - allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; - - /* Send down the multicast list first. */ - - - buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); - if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { - DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", - dhd_ifname(&dhd->pub, ifidx), cnt)); - return; - } - - strncpy(bufp, "mcast_list", buflen - 1); - bufp[buflen - 1] = '\0'; - bufp += strlen("mcast_list") + 1; - - cnt = htol32(cnt); - memcpy(bufp, &cnt, sizeof(cnt)); - bufp += sizeof(cnt); - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - netdev_for_each_mc_addr(ha, dev) { - if (!cnt) - break; - memcpy(bufp, ha->addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; - cnt--; - } -#else - for (mclist = dev->mc_list; (mclist && (cnt > 0)); - cnt--, mclist = mclist->next) { - memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; - } -#endif /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); -#endif - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = buflen; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", - dhd_ifname(&dhd->pub, ifidx), cnt)); - allmulti = cnt ? TRUE : allmulti; - } - - MFREE(dhd->pub.osh, buf, buflen); - - /* 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... - */ - allmulti = htol32(allmulti); - ret = dhd_iovar(&dhd->pub, ifidx, "allmulti", (char *)&allmulti, - sizeof(allmulti), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: set allmulti %d failed\n", - dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); - } - - /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ - - allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; - - allmulti = htol32(allmulti); - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_PROMISC; - ioc.buf = &allmulti; - ioc.len = sizeof(allmulti); - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set promisc %d failed\n", - dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); - } -} - -int -_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr) -{ - int ret; - ret = dhd_iovar(&dhd->pub, ifidx, "cur_etheraddr", (char *)addr, - ETHER_ADDR_LEN, NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); - } else { - memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); - if (ifidx == 0) - memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); - } - - return ret; -} - -#ifdef SOFTAP -extern struct net_device *ap_net_dev; -extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ -#endif - -static void -dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_if_event_t *if_event = event_info; - struct net_device *ndev; - int ifidx, bssidx; - int ret; - - if (event != DHD_WQ_WORK_IF_ADD) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (!if_event) { - DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - - ifidx = if_event->event.ifidx; - bssidx = if_event->event.bssidx; - DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx)); - - ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name, - if_event->mac, bssidx, TRUE); - if (!ndev) { - DHD_ERROR(("%s: net device alloc failed \n", __FUNCTION__)); - goto done; - } - - ret = dhd_register_if(&dhd->pub, ifidx, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__)); - dhd_remove_if(&dhd->pub, ifidx, TRUE); - } -done: - MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static void -dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - int ifidx; - dhd_if_event_t *if_event = event_info; - - - if (event != DHD_WQ_WORK_IF_DEL) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (!if_event) { - DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - - ifidx = if_event->event.ifidx; - DHD_TRACE(("Removing interface with idx %d\n", ifidx)); - - dhd_remove_if(&dhd->pub, ifidx, TRUE); - - MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static void -dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_if_t *ifp = event_info; - -#ifdef SOFTAP - unsigned long flags; - bool in_ap = FALSE; -#endif - - if (event != DHD_WQ_WORK_SET_MAC) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - -#ifdef SOFTAP - flags = dhd_os_spin_lock(&dhd->pub); - in_ap = (ap_net_dev != NULL); - dhd_os_spin_unlock(&dhd->pub, flags); - - if (in_ap) { - DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n", - ifp->net->name)); - return; - } -#endif - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - - if (ifp == NULL || !dhd->pub.up) { - DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); - goto done; - } - - DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__)); - ifp->set_macaddress = FALSE; - if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0) - DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); - else - DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); - -done: - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static void -dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_if_t *ifp = event_info; - int ifidx; - -#ifdef SOFTAP - bool in_ap = FALSE; - unsigned long flags; -#endif - - if (event != DHD_WQ_WORK_SET_MCAST_LIST) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - -#ifdef SOFTAP - flags = dhd_os_spin_lock(&dhd->pub); - in_ap = (ap_net_dev != NULL); - dhd_os_spin_unlock(&dhd->pub, flags); - - if (in_ap) { - DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n", - ifp->net->name)); - ifp->set_multicast = FALSE; - return; - } -#endif - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - - if (ifp == NULL || !dhd->pub.up) { - DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); - goto done; - } - - ifidx = ifp->idx; - - - _dhd_set_multicast_list(dhd, ifidx); - DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx)); - -done: - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static int -dhd_set_mac_address(struct net_device *dev, void *addr) -{ - int ret = 0; - - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - struct sockaddr *sa = (struct sockaddr *)addr; - int ifidx; - dhd_if_t *dhdif; - - ifidx = dhd_net2idx(dhd, dev); - if (ifidx == DHD_BAD_IF) - return -1; - - dhdif = dhd->iflist[ifidx]; - - dhd_net_if_lock_local(dhd); - memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN); - dhdif->set_macaddress = TRUE; - dhd_net_if_unlock_local(dhd); - dhd_deferred_schedule_work((void *)dhdif, DHD_WQ_WORK_SET_MAC, - dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW); - return ret; -} - -static void -dhd_set_multicast_list(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ifidx; - - ifidx = dhd_net2idx(dhd, dev); - if (ifidx == DHD_BAD_IF) - return; - - dhd->iflist[ifidx]->set_multicast = TRUE; - dhd_deferred_schedule_work((void *)dhd->iflist[ifidx], DHD_WQ_WORK_SET_MCAST_LIST, - dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW); -} - -#ifdef PROP_TXSTATUS -int -dhd_os_wlfc_block(dhd_pub_t *pub) -{ - dhd_info_t *di = (dhd_info_t *)(pub->info); - ASSERT(di != NULL); - spin_lock_bh(&di->wlfc_spinlock); - return 1; -} - -int -dhd_os_wlfc_unblock(dhd_pub_t *pub) -{ - dhd_info_t *di = (dhd_info_t *)(pub->info); - - ASSERT(di != NULL); - spin_unlock_bh(&di->wlfc_spinlock); - return 1; -} - -const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; -const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; -#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] - -#endif /* PROP_TXSTATUS */ -int BCMFASTPATH -dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) -{ - int ret = BCME_OK; - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh = NULL; - - /* Reject if down */ - if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { - /* free the packet here since the caller won't */ - PKTFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - - /* Update multicast statistic */ - if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); - eh = (struct ether_header *)pktdata; - - if (ETHER_ISMULTI(eh->ether_dhost)) - dhdp->tx_multicast++; - if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) - atomic_inc(&dhd->pend_8021x_cnt); - } else { - PKTFREE(dhd->pub.osh, pktbuf, TRUE); - return BCME_ERROR; - } - -#ifdef DHDTCPACK_SUPPRESS - /* If this packet has replaced another packet and got freed, just return */ - if (dhd_tcpack_suppress(dhdp, pktbuf)) - return ret; -#endif /* DHDTCPACK_SUPPRESS */ - - /* Look into the packet and update the packet priority */ -#ifndef PKTPRIO_OVERRIDE - if (PKTPRIO(pktbuf) == 0) -#endif - pktsetprio(pktbuf, FALSE); - -#ifdef PROP_TXSTATUS - if (dhd_wlfc_is_supported(dhdp)) { - /* store the interface ID */ - DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); - - /* store destination MAC in the tag as well */ - DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); - - /* decide which FIFO this packet belongs to */ - if (ETHER_ISMULTI(eh->ether_dhost)) - /* one additional queue index (highest AC + 1) is used for bc/mc queue */ - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); - else - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); - } else -#endif /* PROP_TXSTATUS */ - /* If the protocol uses a data header, apply it */ - dhd_prot_hdrpush(dhdp, ifidx, pktbuf); - - /* Use bus module to send data frame */ -#ifdef WLMEDIA_HTSF - dhd_htsf_addtxts(dhdp, pktbuf); -#endif -#ifdef PROP_TXSTATUS - { - if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata, - dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) { - /* non-proptxstatus way */ - ret = dhd_bus_txdata(dhdp->bus, pktbuf); - } - } -#else -#ifdef BCMPCIE - ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); -#else - ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#endif /* BCMPCIE */ -#endif /* PROP_TXSTATUS */ - - return ret; -} - -int BCMFASTPATH -dhd_start_xmit(struct sk_buff *skb, struct net_device *net) -{ - int ret; - uint datalen; - void *pktbuf; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - dhd_if_t *ifp = NULL; - int ifidx; -#ifdef WLMEDIA_HTSF - uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; -#else - uint8 htsfdlystat_sz = 0; -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - DHD_OS_WAKE_LOCK(&dhd->pub); - - /* Reject if down */ - if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) { - DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", - __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); - netif_stop_queue(net); - /* Send Event when bus down detected during data session */ - if (dhd->pub.up) { - DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(dhd->pub.crash_reason, - "%s: Event HANG sent up\n", __FUNCTION__); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - net_os_send_hang_message(net); - } - DHD_OS_WAKE_UNLOCK(&dhd->pub); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); - netif_stop_queue(net); - DHD_OS_WAKE_UNLOCK(&dhd->pub); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } - - /* re-align socket buffer if "skb->data" is odd adress */ - if (((unsigned long)(skb->data)) & 0x1) { - unsigned char *data = skb->data; - uint32 length = skb->len; - PKTPUSH(dhd->pub.osh, skb, 1); - memmove(skb->data, data, length); - PKTSETLEN(dhd->pub.osh, skb, length); - } - - ifp = dhd->iflist[ifidx]; - datalen = PKTLEN(dhd->pub.osh, skb); - - /* Make sure there's enough room for any header */ - - if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { - struct sk_buff *skb2; - - DHD_INFO(("%s: insufficient headroom\n", - dhd_ifname(&dhd->pub, ifidx))); - dhd->pub.tx_realloc++; - - skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); - - dev_kfree_skb(skb); - if ((skb = skb2) == NULL) { - DHD_ERROR(("%s: skb_realloc_headroom failed\n", - dhd_ifname(&dhd->pub, ifidx))); - ret = -ENOMEM; - goto done; - } - } - - /* Convert to packet */ - if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { - DHD_ERROR(("%s: PKTFRMNATIVE failed\n", - dhd_ifname(&dhd->pub, ifidx))); - dev_kfree_skb_any(skb); - ret = -ENOMEM; - goto done; - } -#ifdef WLMEDIA_HTSF - if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { - uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); - struct ether_header *eh = (struct ether_header *)pktdata; - - if (!ETHER_ISMULTI(eh->ether_dhost) && - (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { - eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); - } - } -#endif - - ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); - -done: - if (ret) { - ifp->stats.tx_dropped++; - } - else { - -#ifdef PROP_TXSTATUS - /* tx_packets counter can counted only when wlfc is disabled */ - if (!dhd_wlfc_is_supported(&dhd->pub)) -#endif - { - dhd->pub.tx_packets++; - ifp->stats.tx_packets++; - ifp->stats.tx_bytes += datalen; - } - } - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - /* Return ok: we always eat the packet */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return 0; -#else - return NETDEV_TX_OK; -#endif -} - -void -dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) -{ - struct net_device *net; - dhd_info_t *dhd = dhdp->info; - int i; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(dhd); - -#ifdef DHD_LOSSLESS_ROAMING - /* block flowcontrol during roaming */ - if ((dhdp->dequeue_prec_map == 1 << PRIO_8021D_NC) && state == ON) { - return; - } -#endif /* DHD_LOSSLESS_ROAMING */ - - if (ifidx == ALL_INTERFACES) { - /* Flow control on all active interfaces */ - dhdp->txoff = state; - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - net = dhd->iflist[i]->net; - if (state == ON) - netif_stop_queue(net); - else - netif_wake_queue(net); - } - } - } - else { - if (dhd->iflist[ifidx]) { - net = dhd->iflist[ifidx]->net; - if (state == ON) - netif_stop_queue(net); - else - netif_wake_queue(net); - } - } -} - -#ifdef DHD_RX_DUMP -typedef struct { - uint16 type; - const char *str; -} PKTTYPE_INFO; - -static const PKTTYPE_INFO packet_type_info[] = -{ - { ETHER_TYPE_IP, "IP" }, - { ETHER_TYPE_ARP, "ARP" }, - { ETHER_TYPE_BRCM, "BRCM" }, - { ETHER_TYPE_802_1X, "802.1X" }, - { ETHER_TYPE_WAI, "WAPI" }, - { 0, ""} -}; - -static const char *_get_packet_type_str(uint16 type) -{ - int i; - int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; - - for (i = 0; i < n; i++) { - if (packet_type_info[i].type == type) - return packet_type_info[i].str; - } - - return packet_type_info[n].str; -} -#endif /* DHD_RX_DUMP */ - - -void -dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - uchar *eth; - uint len; - void *data, *pnext = NULL; - int i; - dhd_if_t *ifp; - wl_event_msg_t event; - int tout_rx = 0; - int tout_ctrl = 0; - void *skbhead = NULL; - void *skbprev = NULL; -#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) - char *dump_data; - uint16 protocol; -#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { - struct ether_header *eh; - - pnext = PKTNEXT(dhdp->osh, pktbuf); - PKTSETNEXT(dhdp->osh, pktbuf, NULL); - - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) { - DHD_ERROR(("%s: ifp is NULL. drop packet\n", - __FUNCTION__)); - PKTFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); - /* Dropping only data packets before registering net device to avoid kernel panic */ -#ifndef PROP_TXSTATUS_VSDB - if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) && - (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { -#else - if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) && - (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { -#endif /* PROP_TXSTATUS_VSDB */ - DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", - __FUNCTION__)); - PKTFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - - -#ifdef PROP_TXSTATUS - if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) { - /* WLFC may send header only packet when - there is an urgent message but no packet to - piggy-back on - */ - PKTFREE(dhdp->osh, pktbuf, FALSE); - continue; - } -#endif -#ifdef DHDTCPACK_SUPPRESS - dhd_tcpdata_info_get(dhdp, pktbuf); -#endif - skb = PKTTONATIVE(dhdp->osh, pktbuf); - - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) - ifp = dhd->iflist[0]; - - ASSERT(ifp); - skb->dev = ifp->net; - - - /* 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; - -#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) - dump_data = skb->data; - protocol = (dump_data[12] << 8) | dump_data[13]; - - if (protocol == ETHER_TYPE_802_1X) { - DHD_ERROR(("ETHER_TYPE_802_1X: " - "ver %d, type %d, replay %d\n", - dump_data[14], dump_data[15], - dump_data[30])); - } -#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */ -#if defined(DHD_RX_DUMP) - DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol))); - if (protocol != ETHER_TYPE_BRCM) { - if (dump_data[0] == 0xFF) { - DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__)); - - if ((dump_data[12] == 8) && - (dump_data[13] == 6)) { - DHD_ERROR(("%s: ARP %d\n", - __FUNCTION__, dump_data[0x15])); - } - } else if (dump_data[0] & 1) { - DHD_ERROR(("%s: MULTICAST: " MACDBG "\n", - __FUNCTION__, MAC2STRDBG(dump_data))); - } -#ifdef DHD_RX_FULL_DUMP - { - int k; - for (k = 0; k < skb->len; k++) { - DHD_ERROR(("%02X ", dump_data[k])); - if ((k & 15) == 15) - DHD_ERROR(("\n")); - } - DHD_ERROR(("\n")); - } -#endif /* DHD_RX_FULL_DUMP */ - } -#endif /* DHD_RX_DUMP */ - - skb->protocol = eth_type_trans(skb, skb->dev); - - if (skb->pkt_type == PACKET_MULTICAST) { - dhd->pub.rx_multicast++; - ifp->stats.multicast++; - } - - skb->data = eth; - skb->len = len; - -#ifdef WLMEDIA_HTSF - dhd_htsf_addrxts(dhdp, pktbuf); -#endif - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* Process special event packets and then discard them */ - memset(&event, 0, sizeof(event)); - if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { - int ret_event; - - ret_event = dhd_wl_host_event(dhd, &ifidx, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) - skb_mac_header(skb), -#else - skb->mac.raw, -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ - len, - &event, - &data); - - if (ret_event != BCME_OK) { - PKTFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - - wl_event_to_host_order(&event); - if (!tout_ctrl) - tout_ctrl = DHD_PACKET_TIMEOUT_MS; - -#if defined(PNO_SUPPORT) - if (event.event_type == WLC_E_PFN_NET_FOUND) { - /* enforce custom wake lock to garantee that Kernel not suspended */ - tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; - } -#endif /* PNO_SUPPORT */ - -#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - PKTFREE(dhdp->osh, pktbuf, FALSE); - continue; -#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ - } else { - tout_rx = DHD_PACKET_TIMEOUT_MS; - -#ifdef PROP_TXSTATUS - dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb)); -#endif /* PROP_TXSTATUS */ - } - - ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); - ifp = dhd->iflist[ifidx]; - - if (ifp->net) - ifp->net->last_rx = jiffies; - - if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { - dhdp->dstats.rx_bytes += skb->len; - dhdp->rx_packets++; /* Local count */ - ifp->stats.rx_bytes += skb->len; - ifp->stats.rx_packets++; - } - - if (in_interrupt()) { - netif_rx(skb); - } else { - if (dhd->rxthread_enabled) { - if (!skbhead) - skbhead = skb; - else - PKTSETNEXT(dhdp->osh, skbprev, skb); - skbprev = 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. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - netif_rx_ni(skb); -#else - ulong flags; - netif_rx(skb); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ - } - } - } - - if (dhd->rxthread_enabled && skbhead) - dhd_sched_rxf(dhdp, skbhead); - - DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); -} - -void -dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx) -{ - /* Linux version has nothing to do */ - return; -} - -void -dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh; - uint16 type; - - dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); - - eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); - type = ntoh16(eh->ether_type); - - if (type == ETHER_TYPE_802_1X) - atomic_dec(&dhd->pend_8021x_cnt); - -#ifdef PROP_TXSTATUS - if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) { - dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))]; - uint datalen = PKTLEN(dhd->pub.osh, txp); - - if (success) { - dhd->pub.tx_packets++; - ifp->stats.tx_packets++; - ifp->stats.tx_bytes += datalen; - } else { - ifp->stats.tx_dropped++; - } - } -#endif -} - -static struct net_device_stats * -dhd_get_stats(struct net_device *net) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - dhd_if_t *ifp; - int ifidx; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); - - memset(&net->stats, 0, sizeof(net->stats)); - return &net->stats; - } - - ifp = dhd->iflist[ifidx]; - ASSERT(dhd && ifp); - - if (dhd->pub.up) { - /* Use the protocol to get dongle stats */ - dhd_prot_dstats(&dhd->pub); - } - return &ifp->stats; -} - -static int -dhd_watchdog_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_watchdog_prio > 0) { - struct sched_param param; - param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? - dhd_watchdog_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - - while (1) - if (down_interruptible (&tsk->sema) == 0) { - unsigned long flags; - unsigned long jiffies_at_start = jiffies; - unsigned long time_lapse; - - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - dhd_os_sdlock(&dhd->pub); - if (dhd->pub.dongle_reset == FALSE) { - DHD_TIMER(("%s:\n", __FUNCTION__)); - - /* Call the bus module watchdog */ - dhd_bus_watchdog(&dhd->pub); - - flags = dhd_os_spin_lock(&dhd->pub); - /* Count the tick for reference */ - dhd->pub.tickcnt++; - time_lapse = jiffies - jiffies_at_start; - - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, - jiffies + - msecs_to_jiffies(dhd_watchdog_ms) - - min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); - dhd_os_spin_unlock(&dhd->pub, flags); - } - dhd_os_sdunlock(&dhd->pub); - } else { - break; - } - - complete_and_exit(&tsk->completed, 0); -} - -static void dhd_watchdog(ulong data) -{ - dhd_info_t *dhd = (dhd_info_t *)data; - unsigned long flags; - - if (dhd->pub.dongle_reset) { - return; - } - - if (dhd->thr_wdt_ctl.thr_pid >= 0) { - up(&dhd->thr_wdt_ctl.sema); - return; - } - - dhd_os_sdlock(&dhd->pub); - /* Call the bus module watchdog */ - dhd_bus_watchdog(&dhd->pub); - - flags = dhd_os_spin_lock(&dhd->pub); - /* Count the tick for reference */ - dhd->pub.tickcnt++; - - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); - dhd_os_spin_unlock(&dhd->pub, flags); - dhd_os_sdunlock(&dhd->pub); -} - -#ifdef ENABLE_ADAPTIVE_SCHED -/* DPC thread policy */ -static int dhd_dpc_poli = SCHED_FIFO; -static void -dhd_sched_policy(int prio) -{ - struct sched_param param; - if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) { - param.sched_priority = 0; - setScheduler(current, SCHED_NORMAL, ¶m); - } else { - if (get_scheduler_policy(current) != SCHED_FIFO) { - param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1); - setScheduler(current, dhd_dpc_poli, ¶m); - } - } -} -#endif /* ENABLE_ADAPTIVE_SCHED */ -#ifdef DEBUG_CPU_FREQ -static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) -{ - dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans); - struct cpufreq_freqs *freq = data; - if (dhd) { - if (!dhd->new_freq) - goto exit; - if (val == CPUFREQ_POSTCHANGE) { - DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n", - freq->new, freq->cpu)); - *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new; - } - } -exit: - return 0; -} -#endif /* DEBUG_CPU_FREQ */ -static int -dhd_dpc_thread(void *data) -{ - - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_dpc_prio > 0) - { - struct sched_param param; - param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - -#ifdef CUSTOM_DPC_CPUCORE - set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE)); -#endif - /* Run until signal received */ - while (1) { - if (!binary_sema_down(tsk)) { -#ifdef ENABLE_ADAPTIVE_SCHED - dhd_sched_policy(dhd_dpc_prio); -#endif /* ENABLE_ADAPTIVE_SCHED */ - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - /* Call bus dpc unless it indicated down (then clean stop) */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { -#if defined(CUSTOMER_HW5) - int resched_cnt = 0; -#endif - dhd_os_wd_timer_extend(&dhd->pub, TRUE); - while (dhd_bus_dpc(dhd->pub.bus)) { - /* process all data */ -#if defined(CUSTOMER_HW5) - resched_cnt++; - if (resched_cnt > MAX_RESCHED_CNT) { - DHD_INFO(("%s Calling msleep to" - "let other processes run. \n", - __FUNCTION__)); - dhd->pub.dhd_bug_on = true; - resched_cnt = 0; - OSL_SLEEP(1); - } -#endif - } - dhd_os_wd_timer_extend(&dhd->pub, FALSE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - } else { - if (dhd->pub.up) - dhd_bus_stop(dhd->pub.bus, TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } - } - else - break; - } - complete_and_exit(&tsk->completed, 0); -} - -static int -dhd_rxf_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - dhd_pub_t *pub = &dhd->pub; -#if defined(WAIT_DEQUEUE) -#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */ - ulong watchdogTime = OSL_SYSUPTIME(); /* msec */ -#endif - - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_rxf_prio > 0) - { - struct sched_param param; - param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - - DAEMONIZE("dhd_rxf"); - /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ - - /* signal: thread has started */ - complete(&tsk->completed); - - /* Run until signal received */ - while (1) { - if (down_interruptible(&tsk->sema) == 0) { - void *skb; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) - ulong flags; -#endif -#ifdef ENABLE_ADAPTIVE_SCHED - dhd_sched_policy(dhd_rxf_prio); -#endif /* ENABLE_ADAPTIVE_SCHED */ - - SMP_RD_BARRIER_DEPENDS(); - - if (tsk->terminated) { - break; - } - skb = dhd_rxf_dequeue(pub); - - if (skb == NULL) { - continue; - } - while (skb) { - void *skbnext = PKTNEXT(pub->osh, skb); - PKTSETNEXT(pub->osh, skb, NULL); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - netif_rx_ni(skb); -#else - netif_rx(skb); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); - -#endif - skb = skbnext; - } -#if defined(WAIT_DEQUEUE) - if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) { - OSL_SLEEP(1); - watchdogTime = OSL_SYSUPTIME(); - } -#endif - - DHD_OS_WAKE_UNLOCK(pub); - } - else - break; - } - - complete_and_exit(&tsk->completed, 0); -} - -static void -dhd_dpc(ulong data) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)data; - - /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] - * down below , wake lock is set, - * the tasklet is initialized in dhd_attach() - */ - /* Call bus dpc unless it indicated down (then clean stop) */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { - if (dhd_bus_dpc(dhd->pub.bus)) - tasklet_schedule(&dhd->tasklet); - else - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } else { - dhd_bus_stop(dhd->pub.bus, TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } -} - -void -dhd_sched_dpc(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - DHD_OS_WAKE_LOCK(dhdp); - if (dhd->thr_dpc_ctl.thr_pid >= 0) { - /* If the semaphore does not get up, - * wake unlock should be done here - */ - if (!binary_sema_up(&dhd->thr_dpc_ctl)) - DHD_OS_WAKE_UNLOCK(dhdp); - return; - } else { - tasklet_schedule(&dhd->tasklet); - } -} - -static void -dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -#ifdef RXF_DEQUEUE_ON_BUSY - int ret = BCME_OK; - int retry = 2; -#endif /* RXF_DEQUEUE_ON_BUSY */ - - DHD_OS_WAKE_LOCK(dhdp); - - DHD_TRACE(("dhd_sched_rxf: Enter\n")); -#ifdef RXF_DEQUEUE_ON_BUSY - do { - ret = dhd_rxf_enqueue(dhdp, skb); - if (ret == BCME_OK || ret == BCME_ERROR) - break; - else - OSL_SLEEP(50); /* waiting for dequeueing */ - } while (retry-- > 0); - - if (retry <= 0 && ret == BCME_BUSY) { - void *skbp = skb; - - while (skbp) { - void *skbnext = PKTNEXT(dhdp->osh, skbp); - PKTSETNEXT(dhdp->osh, skbp, NULL); - netif_rx_ni(skbp); - skbp = skbnext; - } - DHD_ERROR(("send skb to kernel backlog without rxf_thread\n")); - } - else { - if (dhd->thr_rxf_ctl.thr_pid >= 0) { - up(&dhd->thr_rxf_ctl.sema); - } - } -#else /* RXF_DEQUEUE_ON_BUSY */ - do { - if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK) - break; - } while (1); - if (dhd->thr_rxf_ctl.thr_pid >= 0) { - up(&dhd->thr_rxf_ctl.sema); - } - return; -#endif /* RXF_DEQUEUE_ON_BUSY */ -} - -#ifdef TOE -/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ -static int -dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) -{ - char buf[32]; - int ret; - - ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", NULL, 0, (char *)buf, sizeof(buf), FALSE); - if (ret < 0) { - /* Check for older dongle image that doesn't support toe_ol */ - if (ret == -EIO) { - DHD_ERROR(("%s: toe not supported by device\n", dhd_ifname(&dhd->pub, - ifidx))); - return -EOPNOTSUPP; - } - - DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - memcpy(toe_ol, buf, sizeof(uint32)); - return 0; -} - -/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ -static int -dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) -{ - int toe, ret; - - /* Set toe_ol as requested */ - ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", (char *)&toe_ol, sizeof(toe_ol), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", - dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - /* Enable toe globally only if any components are enabled. */ - toe = (toe_ol != 0); - ret = dhd_iovar(&dhd->pub, ifidx, "toe", (char *)&toe, sizeof(toe), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - return 0; -} -#endif /* TOE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -static void -dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - - snprintf(info->driver, sizeof(info->driver), "wl"); - snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); -} - -struct ethtool_ops dhd_ethtool_ops = { - .get_drvinfo = dhd_ethtool_get_drvinfo -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) -static int -dhd_ethtool(dhd_info_t *dhd, void *uaddr) -{ - struct ethtool_drvinfo info; - char drvname[sizeof(info.driver)]; - uint32 cmd; -#ifdef TOE - struct ethtool_value edata; - uint32 toe_cmpnt, csum_dir; - int ret; -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* all ethtool calls start with a cmd word */ - if (copy_from_user(&cmd, uaddr, sizeof (uint32))) - 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 dhd requested, identify ourselves */ - if (strcmp(drvname, "?dhd") == 0) { - snprintf(info.driver, sizeof(info.driver), "dhd"); - strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); - info.version[sizeof(info.version) - 1] = '\0'; - } - - /* otherwise, require dongle to be up */ - else if (!dhd->pub.up) { - DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); - return -ENODEV; - } - - /* finally, report dongle driver type */ - else if (dhd->pub.iswl) - snprintf(info.driver, sizeof(info.driver), "wl"); - else - snprintf(info.driver, sizeof(info.driver), "xx"); - - snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); - if (copy_to_user(uaddr, &info, sizeof(info))) - return -EFAULT; - DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, - (int)sizeof(drvname), drvname, info.driver)); - break; - -#ifdef TOE - /* Get toe offload components from dongle */ - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 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 */ - if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 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; - - if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) - return ret; - - /* If setting TX checksum mode, tell Linux the new mode */ - if (cmd == ETHTOOL_STXCSUM) { - if (edata.data) - dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; - else - dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; - } - - break; -#endif /* TOE */ - - default: - return -EOPNOTSUPP; - } - - return 0; -} -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - -static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) -{ - dhd_info_t *dhd; - - if (!dhdp) { - DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); - return FALSE; - } - - if (!dhdp->up) - return FALSE; - - dhd = (dhd_info_t *)dhdp->info; -#if !defined(BCMPCIE) - if (dhd->thr_dpc_ctl.thr_pid < 0) { - DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); - return FALSE; - } -#endif - - if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || - ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { - DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, - dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(dhdp->crash_reason, - "%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, - dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - net_os_send_hang_message(net); - return TRUE; - } - return FALSE; -} - -int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf) -{ - int bcmerror = BCME_OK; - int buflen = 0; - struct net_device *net; - - net = dhd_idx2net(pub, ifidx); - if (!net) { - bcmerror = BCME_BADARG; - goto done; - } - - if (data_buf) - buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN); - - /* check for local dhd ioctl and handle it */ - if (ioc->driver == DHD_IOCTL_MAGIC) { - bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen); - if (bcmerror) - pub->bcmerror = bcmerror; - goto done; - } - - - /* send to dongle (must be up, and wl). */ - if (pub->busstate != DHD_BUS_DATA) { - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - - if (!pub->iswl) { - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - - /* - * Flush the TX queue if required for proper message serialization: - * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to - * prevent M4 encryption and - * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to - * prevent disassoc frame being sent before WPS-DONE frame. - */ - if (ioc->cmd == WLC_SET_KEY || - (ioc->cmd == WLC_SET_VAR && data_buf != NULL && - strncmp("wsec_key", data_buf, 9) == 0) || - (ioc->cmd == WLC_SET_VAR && data_buf != NULL && - strncmp("bsscfg:wsec_key", data_buf, 15) == 0) || - ioc->cmd == WLC_DISASSOC) - dhd_wait_pend8021x(net); - -#ifdef WLMEDIA_HTSF - if (data_buf) { - /* short cut wl ioctl calls here */ - if (strcmp("htsf", data_buf) == 0) { - dhd_ioctl_htsf_get(dhd, 0); - return BCME_OK; - } - - if (strcmp("htsflate", data_buf) == 0) { - if (ioc->set) { - memset(ts, 0, sizeof(tstamp_t)*TSMAX); - memset(&maxdelayts, 0, sizeof(tstamp_t)); - maxdelay = 0; - tspktcnt = 0; - maxdelaypktno = 0; - memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); - } else { - dhd_dump_latency(); - } - return BCME_OK; - } - if (strcmp("htsfclear", data_buf) == 0) { - memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); - htsf_seqnum = 0; - return BCME_OK; - } - if (strcmp("htsfhis", data_buf) == 0) { - dhd_dump_htsfhisto(&vi_d1, "H to D"); - dhd_dump_htsfhisto(&vi_d2, "D to D"); - dhd_dump_htsfhisto(&vi_d3, "D to H"); - dhd_dump_htsfhisto(&vi_d4, "H to H"); - return BCME_OK; - } - if (strcmp("tsport", data_buf) == 0) { - if (ioc->set) { - memcpy(&tsport, data_buf + 7, 4); - } else { - DHD_ERROR(("current timestamp port: %d \n", tsport)); - } - return BCME_OK; - } - } -#endif /* WLMEDIA_HTSF */ - - if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) && - data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) { -#ifdef BCM_FD_AGGR - bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); -#else - bcmerror = BCME_UNSUPPORTED; -#endif - goto done; - } - - if (ioc->cmd == WLC_SET_VAR && data_buf != NULL && - strncmp("qtxpower", data_buf, 8) == 0) { - if (somc_update_qtxpower((char *)data_buf + 9, *((char *)data_buf + 12), 0) != 0) { - DHD_ERROR(("qtxpower on chain0 failed\n")); - bcmerror = BCME_ERROR; - goto done; - } -#ifdef SOMC_MIMO - if (somc_update_qtxpower((char *)data_buf + 10, *((char *)data_buf + 12), 1) != 0) { - DHD_ERROR(("qtxpower on chain1 failed\n")); - bcmerror = BCME_ERROR; - goto done; - } -#else - /* initialize chain1 value just in case since it's not needed for SISO */ - *((char *)data_buf + 10) = 0; -#endif - } - - bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); - -done: - dhd_check_hang(net, pub, bcmerror); - - return bcmerror; -} - -static int -dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - dhd_ioctl_t ioc; - int bcmerror = 0; - int ifidx; - int ret; - void *local_buf = NULL; - u16 buflen = 0; - - DHD_OS_WAKE_LOCK(&dhd->pub); - - /* send to dongle only if we are not waiting for reload already */ - if (dhd->pub.hang_was_sent) { - DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return OSL_ERROR(BCME_DONGLE_DOWN); - } - - ifidx = dhd_net2idx(dhd, net); - DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); - - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -1; - } - -#if defined(WL_WIRELESS_EXT) - /* linux wireless extensions */ - if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { - /* may recurse, do NOT lock */ - ret = wl_iw_ioctl(net, ifr, cmd); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } -#endif /* defined(WL_WIRELESS_EXT) */ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) - if (cmd == SIOCETHTOOL) { - ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - - if (cmd == SIOCDEVPRIVATE+1) { - ret = wl_android_priv_cmd(net, ifr, cmd); - dhd_check_hang(net, &dhd->pub, ret); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } - - if (cmd != SIOCDEVPRIVATE) { - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -EOPNOTSUPP; - } - - memset(&ioc, 0, sizeof(ioc)); - -#ifdef CONFIG_COMPAT - if (is_compat_task()) { - compat_wl_ioctl_t compat_ioc; - if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) { - bcmerror = BCME_BADADDR; - goto done; - } - ioc.cmd = compat_ioc.cmd; - ioc.buf = compat_ptr(compat_ioc.buf); - ioc.len = compat_ioc.len; - ioc.set = compat_ioc.set; - ioc.used = compat_ioc.used; - ioc.needed = compat_ioc.needed; - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), - sizeof(uint)) != 0)) { - bcmerror = BCME_BADADDR; - goto done; - } - } else -#endif /* CONFIG_COMPAT */ - { - /* Copy the ioc control structure part of ioctl request */ - if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { - bcmerror = BCME_BADADDR; - goto done; - } - - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), - sizeof(uint)) != 0)) { - bcmerror = BCME_BADADDR; - goto done; - } - } - - if (!capable(CAP_NET_ADMIN)) { - bcmerror = BCME_EPERM; - goto done; - } - - if (ioc.len > 0) { - buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); - if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) { - bcmerror = BCME_NOMEM; - goto done; - } - if (copy_from_user(local_buf, ioc.buf, buflen)) { - bcmerror = BCME_BADADDR; - goto done; - } - *(char *)(local_buf + buflen) = '\0'; - } - - bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf); - - if (!bcmerror && buflen && local_buf && ioc.buf) { - if (copy_to_user(ioc.buf, local_buf, buflen)) - bcmerror = -EFAULT; - } - -done: - if (local_buf) - MFREE(dhd->pub.osh, local_buf, buflen+1); - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - return OSL_ERROR(bcmerror); -} - - - - -static int -dhd_stop(struct net_device *net) -{ - int ifidx = 0; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - - - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); - if (dhd->pub.up == 0) { - goto exit; - } - - - ifidx = dhd_net2idx(dhd, net); - BCM_REFERENCE(ifidx); - - /* Set state and stop OS transmissions */ - netif_stop_queue(net); - dhd->pub.up = 0; - -#ifdef ENABLE_CONTROL_SCHED - dhd_sysfs_destroy_node(net); - dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; - dhd_dpc_poli = SCHED_FIFO; -#endif /* ENABLE_CONTROL_SCHED */ - -#ifdef WL_CFG80211 - if (ifidx == 0) { - wl_cfg80211_down(NULL); - - /* - * For CFG80211: Clean up all the left over virtual interfaces - * when the primary Interface is brought down. [ifconfig wlan0 down] - */ - if (!dhd_download_fw_on_driverload) { - if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && - (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { - int i; - - dhd_net_if_lock_local(dhd); - for (i = 1; i < DHD_MAX_IFS; i++) - dhd_remove_if(&dhd->pub, i, FALSE); - dhd_net_if_unlock_local(dhd); - } - } - } -#endif /* WL_CFG80211 */ - -#ifdef PROP_TXSTATUS - dhd_wlfc_cleanup(&dhd->pub, NULL, 0); -#endif - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - - OLD_MOD_DEC_USE_COUNT; -exit: -#if defined(WL_CFG80211) - if (ifidx == 0 && !dhd_download_fw_on_driverload) - wl_android_wifi_off(net); -#endif - dhd->pub.rxcnt_timeout = 0; - dhd->pub.txcnt_timeout = 0; - - dhd->pub.hang_was_sent = 0; - - /* Clear country spec for for built-in type driver */ - if (!dhd_download_fw_on_driverload) { - dhd->pub.dhd_cspec.country_abbrev[0] = 0x00; - dhd->pub.dhd_cspec.rev = 0; - dhd->pub.dhd_cspec.ccode[0] = 0x00; - } - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return 0; -} - -#if defined(WL_CFG80211) && defined(USE_INITIAL_SHORT_DWELL_TIME) -extern bool g_first_broadcast_scan; -#endif - -#ifdef WL11U -static int dhd_interworking_enable(dhd_pub_t *dhd) -{ - uint32 enable = true; - int ret = BCME_OK; - - ret = dhd_iovar(dhd, 0, "interworking", (char *)&enable, sizeof(enable), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret)); - } - - if (ret == BCME_OK) { - /* basic capabilities for HS20 REL2 */ - uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF; - ret = dhd_iovar(dhd, 0, "wnm", (char *)&cap, sizeof(cap), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret)); - } - } - - return ret; -} -#endif /* WL11u */ - -#ifdef ENABLE_CONTROL_SCHED -static ssize_t -read_dpc_prio(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) -{ - DHD_INFO(("%s: read cur_prio(%d), cur_poli(%d)\n", - __FUNCTION__, dhd_dpc_prio, dhd_dpc_poli)); - memset(buf, 0, sizeof(uint32)); - count += snprintf(buf, sizeof(uint32), "%d", dhd_dpc_prio + (dhd_dpc_poli * 100)); - return count; -} - -static ssize_t -write_dpc_prio(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, size_t size) -{ - uint32 new_prio = 0; - uint32 cur_prio = dhd_dpc_prio + (dhd_dpc_poli * 100); - - memcpy(&new_prio, buf, sizeof(uint32)); - new_prio = bcm_atoi((char*)&new_prio); - - if (new_prio < 0 || new_prio > 199) { - DHD_ERROR(("%s: ERROR invalid new_prio(%d)\n", - __FUNCTION__, new_prio)); - return -EINVAL; - } - - if (cur_prio != new_prio) { - dhd_dpc_prio = new_prio % 100; - dhd_dpc_poli = new_prio / 100; - DHD_INFO(("%s: write new_prio(%d), new_policy(%d)\n", - __FUNCTION__, dhd_dpc_prio, dhd_dpc_poli)); - } - - return sizeof(uint32); -} - -static struct bin_attribute dpc_prio_attr = { - .attr = {.name = "dpc_prio", .mode = 0644}, - .size = sizeof(uint32), - .read = read_dpc_prio, - .write = write_dpc_prio, -}; - -static int -dhd_sysfs_create_node(struct net_device *net) -{ - int ret; - - DHD_INFO(("%s Enter\n", __func__)); - ret = sysfs_create_bin_file(&net->dev.kobj, &dpc_prio_attr); - - if (ret) { - DHD_ERROR(("%s: create dpc_prio sysfs fail, ret(%d)\n", __FUNCTION__, ret)); - return ret; - } - return 0; -} - -static void -dhd_sysfs_destroy_node(struct net_device *net) -{ - DHD_INFO(("%s Enter\n", __FUNCTION__)); - sysfs_remove_bin_file(&net->dev.kobj, &dpc_prio_attr); -} -#endif /* ENABLE_CONTROL_SCHED */ - - -static int -dhd_open(struct net_device *net) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); -#ifdef TOE - uint32 toe_ol; -#endif - int ifidx; - int32 ret = 0; - - - - - DHD_OS_WAKE_LOCK(&dhd->pub); - dhd->pub.dongle_trap_occured = 0; - dhd->pub.hang_was_sent = 0; -#ifdef DHD_LOSSLESS_ROAMING - dhd->pub.dequeue_prec_map = ALLPRIO; -#endif /* DHD_LOSSLESS_ROAMING */ - -#ifdef ENABLE_CONTROL_SCHED - ret = dhd_sysfs_create_node(net); - if (ret) { - DHD_ERROR(("%s: Failed to setup dpc_prio ret(%d)\n", __FUNCTION__, ret)); - goto exit; - } -#endif /* ENABLE_CONTROL_SCHED */ - -#if !defined(WL_CFG80211) - /* - * Force start if ifconfig_up gets called before START command - * We keep WEXT's wl_control_wl_start to provide backward compatibility - * This should be removed in the future - */ - ret = wl_control_wl_start(net); - if (ret != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - ret = -1; - goto exit; - } - -#endif - - ifidx = dhd_net2idx(dhd, net); - DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - - if (ifidx < 0) { - DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__)); - ret = -1; - goto exit; - } - - if (!dhd->iflist[ifidx]) { - DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); - ret = -1; - goto exit; - } - - if (ifidx == 0) { - atomic_set(&dhd->pend_8021x_cnt, 0); -#if defined(WL_CFG80211) - if (!dhd_download_fw_on_driverload) { - DHD_ERROR(("\n%s\n", dhd_version)); -#if defined(USE_INITIAL_SHORT_DWELL_TIME) - g_first_broadcast_scan = TRUE; -#endif - ret = wl_android_wifi_on(net); - if (ret != 0) { - DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n", - __FUNCTION__, ret)); - ret = -1; - goto exit; - } - } -#endif - - if (dhd->pub.busstate != DHD_BUS_DATA) { - - /* try to bring up bus */ - if ((ret = dhd_bus_start(&dhd->pub)) != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - ret = -1; - goto exit; - } - - } - - /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */ - memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); - -#ifdef TOE - /* Get current TOE mode from dongle */ - if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) - dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; - else - dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; -#endif /* TOE */ - -#if defined(WL_CFG80211) - if (unlikely(wl_cfg80211_up(NULL))) { - DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); - ret = -1; - goto exit; - } -#endif /* WL_CFG80211 */ - } - - /* Allow transmit calls */ - netif_start_queue(net); - dhd->pub.up = 1; - -#ifdef BCMDBGFS - dhd_dbg_init(&dhd->pub); -#endif - - OLD_MOD_INC_USE_COUNT; -exit: - if (ret) - dhd_stop(net); - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - - return ret; -} - -int dhd_do_driver_init(struct net_device *net) -{ - dhd_info_t *dhd = NULL; - - if (!net) { - DHD_ERROR(("Primary Interface not initialized \n")); - return -EINVAL; - } - - - /* && defined(OEM_ANDROID) && defined(BCMSDIO) */ - dhd = *(dhd_info_t **)netdev_priv(net); - - /* If driver is already initialized, do nothing - */ - if (dhd->pub.busstate == DHD_BUS_DATA) { - DHD_TRACE(("Driver already Inititalized. Nothing to do")); - return 0; - } - - if (dhd_open(net) < 0) { - DHD_ERROR(("Driver Init Failed \n")); - return -1; - } - - return 0; -} - -int -dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) -{ - -#ifdef WL_CFG80211 - if (wl_cfg80211_notify_ifadd(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) - return BCME_OK; -#endif - - /* handle IF event caused by wl commands, SoftAP, WEXT and - * anything else. This has to be done asynchronously otherwise - * DPC will be blocked (and iovars will timeout as DPC has no chance - * to read the response back) - */ - if (ifevent->ifidx > 0) { - dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); - - memcpy(&if_event->event, ifevent, sizeof(if_event->event)); - memcpy(if_event->mac, mac, ETHER_ADDR_LEN); - strncpy(if_event->name, name, IFNAMSIZ); - if_event->name[IFNAMSIZ - 1] = '\0'; - dhd_deferred_schedule_work((void *)if_event, DHD_WQ_WORK_IF_ADD, - dhd_ifadd_event_handler, DHD_WORK_PRIORITY_LOW); - } - - return BCME_OK; -} - -int -dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) -{ - dhd_if_event_t *if_event; - -#ifdef WL_CFG80211 - if (wl_cfg80211_notify_ifdel(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) - return BCME_OK; -#endif /* WL_CFG80211 */ - - /* handle IF event caused by wl commands, SoftAP, WEXT and - * anything else - */ - if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); - memcpy(&if_event->event, ifevent, sizeof(if_event->event)); - memcpy(if_event->mac, mac, ETHER_ADDR_LEN); - strncpy(if_event->name, name, IFNAMSIZ); - if_event->name[IFNAMSIZ - 1] = '\0'; - dhd_deferred_schedule_work((void *)if_event, DHD_WQ_WORK_IF_DEL, - dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW); - - return BCME_OK; -} - -/* unregister and free the existing net_device interface (if any) in iflist and - * allocate a new one. the slot is reused. this function does NOT register the - * new interface to linux kernel. dhd_register_if does the job - */ -struct net_device* -dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name, - uint8 *mac, uint8 bssidx, bool need_rtnl_lock) -{ - dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; - dhd_if_t *ifp; - - ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS)); - ifp = dhdinfo->iflist[ifidx]; - - if (ifp != NULL) { - if (ifp->net != NULL) { - DHD_ERROR(("%s: free existing IF %s\n", __FUNCTION__, ifp->net->name)); - - /* in unregister_netdev case, the interface gets freed by net->destructor - * (which is set to free_netdev) - */ - if (ifp->net->reg_state == NETREG_UNINITIALIZED) { - free_netdev(ifp->net); - } else { - netif_stop_queue(ifp->net); - if (need_rtnl_lock) - unregister_netdev(ifp->net); - else - unregister_netdevice(ifp->net); - } - ifp->net = NULL; - } - } else { - ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t)); - if (ifp == NULL) { - DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t))); - return NULL; - } - } - - memset(ifp, 0, sizeof(dhd_if_t)); - ifp->info = dhdinfo; - ifp->idx = ifidx; - ifp->bssidx = bssidx; - if (mac != NULL) - memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN); - - /* Allocate etherdev, including space for private structure */ - ifp->net = alloc_etherdev(sizeof(dhdinfo)); - if (ifp->net == NULL) { - DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo))); - goto fail; - } - memcpy(netdev_priv(ifp->net), &dhdinfo, sizeof(dhdinfo)); - if (name && name[0]) { - strncpy(ifp->net->name, name, IFNAMSIZ); - ifp->net->name[IFNAMSIZ - 1] = '\0'; - } -#ifdef WL_CFG80211 - if (ifidx == 0) - ifp->net->destructor = free_netdev; - else - ifp->net->destructor = dhd_netdev_free; -#else - ifp->net->destructor = free_netdev; -#endif /* WL_CFG80211 */ - strncpy(ifp->name, ifp->net->name, IFNAMSIZ); - ifp->name[IFNAMSIZ - 1] = '\0'; - dhdinfo->iflist[ifidx] = ifp; - return ifp->net; - -fail: - if (ifp != NULL) { - if (ifp->net != NULL) { - free_netdev(ifp->net); - ifp->net = NULL; - } - MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); - ifp = NULL; - } - dhdinfo->iflist[ifidx] = NULL; - return NULL; -} - -/* unregister and free the the net_device interface associated with the indexed - * slot, also free the slot memory and set the slot pointer to NULL - */ -int -dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) -{ - dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; - dhd_if_t *ifp; - - ifp = dhdinfo->iflist[ifidx]; - if (ifp != NULL) { - if (ifp->net != NULL) { - DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx)); - - /* in unregister_netdev case, the interface gets freed by net->destructor - * (which is set to free_netdev) - */ - if (ifp->net->reg_state == NETREG_UNINITIALIZED) { - free_netdev(ifp->net); - } else { - netif_stop_queue(ifp->net); - - if (need_rtnl_lock) - unregister_netdev(ifp->net); - else - unregister_netdevice(ifp->net); - } - ifp->net = NULL; - } - - dhdinfo->iflist[ifidx] = NULL; - MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); - - } - - return BCME_OK; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -static struct net_device_ops dhd_ops_pri = { - .ndo_open = dhd_open, - .ndo_stop = dhd_stop, - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - .ndo_set_rx_mode = dhd_set_multicast_list, -#else - .ndo_set_multicast_list = dhd_set_multicast_list, -#endif -}; - -static struct net_device_ops dhd_ops_virt = { - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - .ndo_set_rx_mode = dhd_set_multicast_list, -#else - .ndo_set_multicast_list = dhd_set_multicast_list, -#endif -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ - -#ifdef DEBUGGER -extern void debugger_init(void *bus_handle); -#endif - - -dhd_pub_t * -dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) -{ - dhd_info_t *dhd = NULL; - struct net_device *net = NULL; - char if_name[IFNAMSIZ] = {'\0'}; - uint32 bus_type = -1; - uint32 bus_num = -1; - uint32 slot_num = -1; - wifi_adapter_info_t *adapter = NULL; -#ifdef CUSTOM_COUNTRY_CODE - struct cntry_locales_custom *cloc_ptr = NULL; -#endif /* CUSTOM_COUNTRY_CODE */ - - dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* will implement get_ids for DBUS later */ - dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); - adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); - - /* Allocate primary dhd_info */ - dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t)); - if (dhd == NULL) { - dhd = MALLOC(osh, sizeof(dhd_info_t)); - if (dhd == NULL) { - DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); - goto fail; - } - } - memset(dhd, 0, sizeof(dhd_info_t)); - dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; - - dhd->pub.osh = osh; - dhd->adapter = adapter; - -#ifdef GET_CUSTOM_MAC_ENABLE - wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet); -#endif /* GET_CUSTOM_MAC_ENABLE */ -#ifdef CUSTOM_FORCE_NODFS_FLAG - dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; - dhd->pub.force_country_change = TRUE; -#endif -#ifdef CUSTOM_COUNTRY_CODE - cloc_ptr = wifi_platform_get_country_code(dhd->adapter, dhd->pub.dhd_cspec.ccode); - if (cloc_ptr) { - strlcpy(dhd->pub.dhd_cspec.country_abbrev, cloc_ptr->iso_abbrev, WLC_CNTRY_BUF_SZ); - strlcpy(dhd->pub.dhd_cspec.ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); - dhd->pub.dhd_cspec.rev = cloc_ptr->custom_locale_rev; - get_customized_country_code(dhd->adapter, dhd->pub.dhd_cspec.ccode, - &dhd->pub.dhd_cspec); - } -#endif /* CUSTOM_COUNTRY_CODE */ - dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; - dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; - - /* Initialize thread based operation and lock */ - sema_init(&dhd->sdsem, 1); - - /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name. - * This is indeed a hack but we have to make it work properly before we have a better - * solution - */ - dhd_update_fw_nv_path(dhd); - - /* Link to info module */ - dhd->pub.info = dhd; - /* Link to bus module */ - dhd->pub.bus = bus; - dhd->pub.hdrlen = bus_hdrlen; - - /* Set network interface name if it was provided as module parameter */ - if (iface_name[0]) { - int len; - char ch; - strncpy(if_name, iface_name, IFNAMSIZ); - if_name[IFNAMSIZ - 1] = 0; - len = strlen(if_name); - ch = if_name[len - 1]; - if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) - strcat(if_name, "%d"); - } - net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE); - if (net == NULL) - goto fail; - dhd_state |= DHD_ATTACH_STATE_ADD_IF; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - net->open = NULL; -#else - net->netdev_ops = NULL; -#endif - - sema_init(&dhd->proto_sem, 1); - -#ifdef PROP_TXSTATUS - spin_lock_init(&dhd->wlfc_spinlock); - - dhd->pub.skip_fc = dhd_wlfc_skip_fc; - dhd->pub.plat_init = dhd_wlfc_plat_init; - dhd->pub.plat_deinit = dhd_wlfc_plat_deinit; -#endif /* PROP_TXSTATUS */ - - /* Initialize other structure content */ - init_waitqueue_head(&dhd->ioctl_resp_wait); - init_waitqueue_head(&dhd->ctrl_wait); - - /* Initialize the spinlocks */ - spin_lock_init(&dhd->sdlock); - spin_lock_init(&dhd->txqlock); - spin_lock_init(&dhd->dhd_lock); - spin_lock_init(&dhd->rxf_lock); -#if defined(RXFRAME_THREAD) - dhd->rxthread_enabled = TRUE; -#endif /* defined(RXFRAME_THREAD) */ - -#ifdef DHDTCPACK_SUPPRESS - spin_lock_init(&dhd->tcpack_lock); -#endif /* DHDTCPACK_SUPPRESS */ - - /* Initialize Wakelock stuff */ - spin_lock_init(&dhd->wakelock_spinlock); - dhd->wakelock_counter = 0; - dhd->wakelock_wd_counter = 0; - dhd->wakelock_rx_timeout_enable = 0; - dhd->wakelock_ctrl_timeout_enable = 0; - dhd->waive_wakelock = FALSE; -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); - wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); - wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); - wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); -#endif /* CONFIG_HAS_WAKELOCK */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_init(&dhd->dhd_net_if_mutex); - mutex_init(&dhd->dhd_suspend_mutex); -#endif - dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; - - /* Attach and link in the protocol */ - if (dhd_prot_attach(&dhd->pub) != 0) { - DHD_ERROR(("dhd_prot_attach failed\n")); - goto fail; - } - dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; - -#ifdef WL_CFG80211 - /* Attach and link in the cfg80211 */ - if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { - DHD_ERROR(("wl_cfg80211_attach failed\n")); - goto fail; - } - - dhd_monitor_init(&dhd->pub); - dhd_state |= DHD_ATTACH_STATE_CFG80211; -#endif -#if defined(WL_WIRELESS_EXT) - /* Attach and link in the iw */ - if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { - if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { - DHD_ERROR(("wl_iw_attach failed\n")); - goto fail; - } - dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; - } -#endif /* defined(WL_WIRELESS_EXT) */ - - - /* Set up the watchdog timer */ - init_timer(&dhd->timer); - dhd->timer.data = (ulong)dhd; - dhd->timer.function = dhd_watchdog; - dhd->default_wd_interval = dhd_watchdog_ms; - - if (dhd_watchdog_prio >= 0) { - /* Initialize watchdog thread */ - PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); - - } else { - dhd->thr_wdt_ctl.thr_pid = -1; - } - -#ifdef DEBUGGER - debugger_init((void *) bus); -#endif - - /* Set up the bottom half handler */ - if (dhd_dpc_prio >= 0) { - /* Initialize DPC thread */ - PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); - } else { - /* use tasklet for dpc */ - tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); - dhd->thr_dpc_ctl.thr_pid = -1; - } - - if (dhd->rxthread_enabled) { - bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND); - /* Initialize RXF thread */ - PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf"); - } - - dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; - - /* - * Save the dhd_info into the priv - */ - memcpy(netdev_priv(net), &dhd, sizeof(dhd)); - -#if defined(CONFIG_PM_SLEEP) - dhd->pm_notifier.notifier_call = dhd_pm_callback; - dhd->pm_notifier.priority = 10; - if (!dhd_pm_notifier_registered) { - dhd_pm_notifier_registered = TRUE; - register_pm_notifier(&dhd->pm_notifier); - } -#endif /* CONFIG_PM_SLEEP */ - -#ifdef SAR_SUPPORT - dhd->sar_notifier.notifier_call = dhd_sar_callback; - if (!dhd_sar_notifier_registered) { - dhd_sar_notifier_registered = TRUE; - register_notifier_by_sar(&dhd->sar_notifier); - } -#endif - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; - dhd->early_suspend.suspend = dhd_early_suspend; - dhd->early_suspend.resume = dhd_late_resume; - register_early_suspend(&dhd->early_suspend); - dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -#ifdef ARP_OFFLOAD_SUPPORT - dhd->pend_ipaddr = 0; - if (!dhd_inetaddr_notifier_registered) { - dhd_inetaddr_notifier_registered = TRUE; - register_inetaddr_notifier(&dhd_inetaddr_notifier); - } -#endif /* ARP_OFFLOAD_SUPPORT */ - if (!dhd_inet6addr_notifier_registered) { - dhd_inet6addr_notifier_registered = TRUE; - register_inet6addr_notifier(&dhd_inet6addr_notifier); - } - dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd); -#ifdef DEBUG_CPU_FREQ - dhd->new_freq = alloc_percpu(int); - dhd->freq_trans.notifier_call = dhd_cpufreq_notifier; - cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); -#endif -#ifdef DHDTCPACK_SUPPRESS - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DELAYTX); -#endif /* DHDTCPACK_SUPPRESS */ -#ifdef DHD_DEBUG - dhd->join_timeout_val = DHD_JOIN_MAX_TIME_DEFAULT; - dhd->scan_time_count = DHD_SCAN_DEF_TIMEOUT; -#endif - dhd_state |= DHD_ATTACH_STATE_DONE; - dhd->dhd_state = dhd_state; - - dhd->unit = dhd_found + instance_base; - dhd_found++; - return &dhd->pub; - -fail: - if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) { - DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", - __FUNCTION__, dhd_state, &dhd->pub)); - dhd->dhd_state = dhd_state; - dhd_detach(&dhd->pub); - dhd_free(&dhd->pub); - } - - return NULL; -} - -int dhd_get_fw_mode(dhd_info_t *dhdinfo) -{ - if (strstr(dhdinfo->fw_path, "_apsta") != NULL) - return DHD_FLAG_HOSTAP_MODE; - if (strstr(dhdinfo->fw_path, "_p2p") != NULL) - return DHD_FLAG_P2P_MODE; - if (strstr(dhdinfo->fw_path, "_ibss") != NULL) - return DHD_FLAG_IBSS_MODE; - if (strstr(dhdinfo->fw_path, "_mfg") != NULL) - return DHD_FLAG_MFG_MODE; - - return DHD_FLAG_STA_MODE; -} - -bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) -{ - int fw_len; - int nv_len; - const char *fw = NULL; - const char *nv = NULL; - wifi_adapter_info_t *adapter = dhdinfo->adapter; - - - /* Update firmware and nvram path. The path may be from adapter info or module parameter - * The path from adapter info is used for initialization only (as it won't change). - * - * The firmware_path/nvram_path module parameter may be changed by the system at run - * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private - * command may change dhdinfo->fw_path. As such we need to clear the path info in - * module parameter after it is copied. We won't update the path until the module parameter - * is changed again (first character is not '\0') - */ - - /* set default firmware and nvram path for built-in type driver */ - if (!dhd_download_fw_on_driverload) { -#ifdef CONFIG_BCMDHD_FW_PATH - fw = CONFIG_BCMDHD_FW_PATH; -#endif /* CONFIG_BCMDHD_FW_PATH */ -#ifdef CONFIG_BCMDHD_NVRAM_PATH - nv = CONFIG_BCMDHD_NVRAM_PATH; -#endif /* CONFIG_BCMDHD_NVRAM_PATH */ - } - - /* check if we need to initialize the path */ - if (dhdinfo->fw_path[0] == '\0') { - if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0') - fw = adapter->fw_path; - - } - if (dhdinfo->nv_path[0] == '\0') { - if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0') - nv = adapter->nv_path; - } - - /* Use module parameter if it is valid, EVEN IF the path has not been initialized - * - * TODO: need a solution for multi-chip, can't use the same firmware for all chips - */ - if (firmware_path[0] != '\0') - fw = firmware_path; - if (nvram_path[0] != '\0') - nv = nvram_path; - - if (fw && fw[0] != '\0') { - fw_len = strlen(fw); - if (fw_len >= sizeof(dhdinfo->fw_path)) { - DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n")); - return FALSE; - } - strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path)); - if (dhdinfo->fw_path[fw_len-1] == '\n') - dhdinfo->fw_path[fw_len-1] = '\0'; - } - if (nv && nv[0] != '\0') { - nv_len = strlen(nv); - if (nv_len >= sizeof(dhdinfo->nv_path)) { - DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n")); - return FALSE; - } - strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path)); - if (dhdinfo->nv_path[nv_len-1] == '\n') - dhdinfo->nv_path[nv_len-1] = '\0'; - } - - /* clear the path in module parameter */ - firmware_path[0] = '\0'; - nvram_path[0] = '\0'; - - if (dhdinfo->fw_path[0] == '\0') { - DHD_ERROR(("firmware path not found\n")); - return FALSE; - } - if (dhdinfo->nv_path[0] == '\0') { - DHD_ERROR(("nvram path not found\n")); - return FALSE; - } - - return TRUE; -} - - -int -dhd_bus_start(dhd_pub_t *dhdp) -{ - int ret = -1; - dhd_info_t *dhd = (dhd_info_t*)dhdp->info; - unsigned long flags; - - ASSERT(dhd); - - DHD_TRACE(("Enter %s:\n", __FUNCTION__)); - - /* try to download image and nvram to the dongle */ - if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) { - DHD_INFO(("%s download fw %s, nv %s\n", __FUNCTION__, dhd->fw_path, dhd->nv_path)); - ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, - dhd->fw_path, dhd->nv_path); - if (ret < 0) { - DHD_ERROR(("%s: failed to download firmware %s\n", - __FUNCTION__, dhd->fw_path)); - return ret; - } - } - if (dhd->pub.busstate != DHD_BUS_LOAD) { - return -ENETDOWN; - } - - dhd_os_sdlock(dhdp); - - /* Start the watchdog timer */ - dhd->pub.tickcnt = 0; - dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - - /* Bring up the bus */ - if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { - - DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); - dhd_os_sdunlock(dhdp); - return ret; - } -#if defined(OOB_INTR_ONLY) - /* Host registration for OOB interrupt */ - if (dhd_bus_oob_intr_register(dhdp)) { - /* deactivate timer and wait for the handler to finish */ - - flags = dhd_os_spin_lock(&dhd->pub); - dhd->wd_timer_valid = FALSE; - dhd_os_spin_unlock(&dhd->pub, flags); - del_timer_sync(&dhd->timer); - - DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); - dhd_os_sdunlock(dhdp); - DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); - return -ENODEV; - } - - /* Enable oob at firmware */ - dhd_enable_oob_intr(dhd->pub.bus, TRUE); -#endif - - /* If bus is not ready, can't come up */ - if (dhd->pub.busstate != DHD_BUS_DATA) { - flags = dhd_os_spin_lock(&dhd->pub); - dhd->wd_timer_valid = FALSE; - dhd_os_spin_unlock(&dhd->pub, flags); - del_timer_sync(&dhd->timer); - DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); - dhd_os_sdunlock(dhdp); - DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); - return -ENODEV; - } - - dhd_os_sdunlock(dhdp); - - dhd_process_cid_mac(dhdp, TRUE); - - /* Bus is ready, do any protocol initialization */ - if ((ret = dhd_prot_init(&dhd->pub)) < 0) - return ret; - - dhd_process_cid_mac(dhdp, FALSE); - -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd->pend_ipaddr) { -#ifdef AOE_IP_ALIAS_SUPPORT - aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); -#endif /* AOE_IP_ALIAS_SUPPORT */ - dhd->pend_ipaddr = 0; - } -#endif /* ARP_OFFLOAD_SUPPORT */ - - return 0; -} -#ifdef WLTDLS -int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac) -{ - uint32 tdls = tdls_on; - int ret = 0; - uint32 tdls_auto_op = 0; - uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING; - int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH; - int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW; - BCM_REFERENCE(mac); - if (!FW_SUPPORTED(dhd, tdls)) - return BCME_ERROR; - - if (dhd->tdls_enable == tdls_on) - goto auto_mode; - ret = dhd_iovar(dhd, 0, "tdls_enable", (char *)&tdls, sizeof(tdls), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret)); - goto exit; - } - dhd->tdls_enable = tdls_on; -auto_mode: - - tdls_auto_op = auto_on; - ret = dhd_iovar(dhd, 0, "tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), NULL, - 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); - goto exit; - } - - if (tdls_auto_op) { - ret = dhd_iovar(dhd, 0, "tdls_idle_time", (char *)&tdls_idle_time, - sizeof(tdls_idle_time), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); - goto exit; - } - ret = dhd_iovar(dhd, 0, "tdls_rssi_high", (char *)&tdls_rssi_high, - sizeof(tdls_rssi_high), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret)); - goto exit; - } - ret = dhd_iovar(dhd, 0, "tdls_rssi_low", (char *)&tdls_rssi_low, - sizeof(tdls_rssi_low), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret)); - goto exit; - } - } - -exit: - return ret; -} -int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - if (dhd) - ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac); - else - ret = BCME_ERROR; - return ret; -} -#endif - -bool dhd_is_concurrent_mode(dhd_pub_t *dhd) -{ - if (!dhd) - return FALSE; - - if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) - return TRUE; - else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == - DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) - return TRUE; - else - return FALSE; -} -#if !defined(AP) && defined(WLP2P) -/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware - * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA - * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware - * would still be named as fw_bcmdhd_apsta. - */ -uint32 -dhd_get_concurrent_capabilites(dhd_pub_t *dhd) -{ - int32 ret = 0; - char buf[WLC_IOCTL_SMLEN]; - bool mchan_supported = FALSE; - /* if dhd->op_mode is already set for HOSTAP and Manufacturing - * test mode, that means we only will use the mode as it is - */ - if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE)) - return 0; - if (FW_SUPPORTED(dhd, vsdb)) { - mchan_supported = TRUE; - } - if (!FW_SUPPORTED(dhd, p2p)) { - DHD_TRACE(("Chip does not support p2p\n")); - return 0; - } - else { - /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ - memset(buf, 0, sizeof(buf)); - ret = dhd_iovar(dhd, 0, "p2p", NULL, 0, (char *)buf, - sizeof(buf), FALSE); - if (ret < 0) { - DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); - return 0; - } - else { - if (buf[0] == 1) { - /* By default, chip supports single chan concurrency, - * now lets check for mchan - */ - ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; - if (mchan_supported) - ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; -#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) - /* For customer_hw4, although ICS, - * we still support concurrent mode - */ - return ret; -#else - return 0; -#endif - } - } - } - return 0; -} -#endif - - -int -dhd_preinit_ioctls(dhd_pub_t *dhd) -{ - int ret = 0; - char eventmask[WL_EVENTING_MASK_LEN]; - char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - uint32 buf_key_b4_m4 = 1; - uint8 msglen; - eventmsgs_ext_t *eventmask_msg = NULL; - char* iov_buf = NULL; - int ret2 = 0; -#ifdef WLAIBSS - aibss_bcn_force_config_t bcn_config; - uint32 aibss; -#endif -#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ - defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) - uint32 ampdu_ba_wsize = 0; -#endif /* CUSTOM_AMPDU_BA_WSIZE ||(WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ -#if defined(CUSTOM_AMPDU_MPDU) - uint32 ampdu_mpdu = 0; -#endif - -#ifdef PROP_TXSTATUS - int wlfc_enable = TRUE; -#ifndef DISABLE_11N - uint32 hostreorder = 1; -#endif /* DISABLE_11N */ -#endif /* PROP_TXSTATUS */ - -#ifdef DHD_ENABLE_LPC - uint32 lpc = 1; -#endif /* DHD_ENABLE_LPC */ - uint power_mode = PM_FAST; - uint32 dongle_align = DHD_SDALIGN; - uint32 glom = CUSTOM_GLOM_SETTING; -#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) - uint32 credall = 1; -#endif -#ifdef SOMC_WLAN_BCN_TIMEOUT - uint bcn_timeout = SOMC_WLAN_BCN_TIMEOUT; -#else -#if defined(VSDB) || defined(ROAM_ENABLE) - uint bcn_timeout = 8; -#else - uint bcn_timeout = 4; -#endif -#endif /* SOMC_WLAN_BCN_TIMEOUT */ - uint retry_max = 7; -#if defined(ARP_OFFLOAD_SUPPORT) - int arpoe = 1; -#endif - int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; - int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; - int scan_passive_time = DHD_SCAN_PASSIVE_TIME; - char buf[WLC_IOCTL_SMLEN]; - char *ptr; - uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ -#ifdef ROAM_ENABLE - uint roamvar = 0; - int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; - int roam_scan_period[2] = {10, WLC_BAND_ALL}; - int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; -#ifdef ROAM_AP_ENV_DETECTION - int roam_env_mode = AP_ENV_INDETERMINATE; -#endif /* ROAM_AP_ENV_DETECTION */ -#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC - int roam_fullscan_period = 60; -#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ - int roam_fullscan_period = 120; -#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ -#else -#ifdef DISABLE_BUILTIN_ROAM - uint roamvar = 1; -#endif /* DISABLE_BUILTIN_ROAM */ -#endif /* ROAM_ENABLE */ - -#if defined(SOFTAP) - uint dtim = 1; -#endif -#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) - uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ - struct ether_addr p2p_ea; -#endif -#ifdef BCMCCX - uint32 ccx = 1; -#endif - -#ifdef SET_RETRY_LIMIT - uint srl = CUSTOM_SRL_SETTING; - uint lrl = CUSTOM_LRL_SETTING; -#endif /* SET_RETRY_LIMIT */ -#if defined(AP) || defined(WLP2P) - uint32 apsta = 1; /* Enable APSTA mode */ -#endif /* defined(AP) || defined(WLP2P) */ -#ifdef GET_CUSTOM_MAC_ENABLE - struct ether_addr ea_addr; -#endif /* GET_CUSTOM_MAC_ENABLE */ - -#ifdef DISABLE_11N - uint32 nmode = 0; -#endif /* DISABLE_11N */ - - uint32 vhtmode = 0; -#ifdef USE_WL_TXBF - uint32 txbf = 1; -#endif /* USE_WL_TXBF */ -#ifdef DISABLE_TXBFR - uint32 txbf_bfr_cap = 0; -#endif /* DISABLE_TXBFR */ -#ifdef AMPDU_VO_ENABLE - struct ampdu_tid_control tid; -#endif -#ifdef USE_WL_FRAMEBURST - uint32 frameburst = 1; -#endif /* USE_WL_FRAMEBURST */ -#ifdef DHD_SET_FW_HIGHSPEED - uint32 ack_ratio = 250; - uint32 ack_ratio_depth = 64; -#endif /* DHD_SET_FW_HIGHSPEED */ -#ifdef SUPPORT_2G_VHT - uint32 vht_features = 0x3; /* 2G enable | rates all */ -#endif /* SUPPORT_2G_VHT */ -#ifdef DISABLE_11N_PROPRIETARY_RATES - uint32 ht_features = 0; -#endif /* DISABLE_11N_PROPRIETARY_RATES */ -#ifdef CUSTOM_PSPRETEND_THR - uint32 pspretend_thr = CUSTOM_PSPRETEND_THR; -#endif -#ifdef DISABLE_BCN_DLY - uint bcn_to_dly = 0; -#endif - -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = TRUE; -#endif /* PKT_FILTER_SUPPORT */ -#ifdef WLTDLS - dhd->tdls_enable = FALSE; -#endif /* WLTDLS */ - dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; - DHD_TRACE(("Enter %s\n", __FUNCTION__)); - dhd->op_mode = 0; - if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || - (op_mode == DHD_FLAG_MFG_MODE)) { - /* Check and adjust IOCTL response timeout for Manufactring firmware */ - dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT); - DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n", - __FUNCTION__)); - } - else { - dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); - DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__)); - } -#ifdef GET_CUSTOM_MAC_ENABLE - ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet); - if (!ret) { - ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)&ea_addr, ETHER_ADDR_LEN, NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); - return BCME_NOTUP; - } - memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN); - } else { -#endif /* GET_CUSTOM_MAC_ENABLE */ - /* Get the default device MAC address directly from firmware */ - ret = dhd_iovar(dhd, 0, "cur_etheraddr", NULL, 0, (char *)buf, sizeof(buf), FALSE); - if (ret < 0) { - DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); - return BCME_NOTUP; - } - /* Update public MAC address after reading from Firmware */ - memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); - -#ifdef GET_CUSTOM_MAC_ENABLE - } -#endif /* GET_CUSTOM_MAC_ENABLE */ - /* get a capabilities from firmware */ - memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities)); - ret = dhd_iovar(dhd, 0, "cap", NULL, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities), - FALSE); - if (ret < 0) { - DHD_ERROR(("%s: Get Capability failed (error=%d)\n", - __FUNCTION__, ret)); - return 0; - } - if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) || - (op_mode == DHD_FLAG_HOSTAP_MODE)) { -#ifdef SET_RANDOM_MAC_SOFTAP - uint rand_mac; -#endif - dhd->op_mode = DHD_FLAG_HOSTAP_MODE; -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; -#endif -#ifdef SET_RANDOM_MAC_SOFTAP - SRANDOM32((uint)jiffies); - rand_mac = RANDOM32(); - iovbuf[0] = 0x02; /* locally administered bit */ - iovbuf[1] = 0x1A; - iovbuf[2] = 0x11; - iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; - iovbuf[4] = (unsigned char)(rand_mac >> 8); - iovbuf[5] = (unsigned char)(rand_mac >> 16); - - ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)iovbuf, ETHER_ADDR_LEN, NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); - } else - memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); -#endif /* SET_RANDOM_MAC_SOFTAP */ -#if !defined(AP) && defined(WL_CFG80211) - /* Turn off MPC in AP mode */ - ret = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); - } -#endif -#ifdef SET_RETRY_LIMIT - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SRL, (char *)&srl, - sizeof(srl), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set SRL failed %d\n", __FUNCTION__, ret)); - } - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_LRL, (char *)&lrl, - sizeof(lrl), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set LRL failed %d\n", __FUNCTION__, ret)); - } -#endif /* SET_RETRY_LIMIT */ - } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || - (op_mode == DHD_FLAG_MFG_MODE)) { -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; -#endif /* PKT_FILTER_SUPPORT */ - dhd->op_mode = DHD_FLAG_MFG_MODE; - } else { - uint32 concurrent_mode = 0; - if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) || - (op_mode == DHD_FLAG_P2P_MODE)) { -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; -#endif - dhd->op_mode = DHD_FLAG_P2P_MODE; - } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) || - (op_mode == DHD_FLAG_IBSS_MODE)) { - dhd->op_mode = DHD_FLAG_IBSS_MODE; - } else - dhd->op_mode = DHD_FLAG_STA_MODE; -#if !defined(AP) && defined(WLP2P) - if (dhd->op_mode != DHD_FLAG_IBSS_MODE && - (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 1; -#endif - dhd->op_mode |= concurrent_mode; - } - - /* Check if we are enabling p2p */ - if (dhd->op_mode & DHD_FLAG_P2P_MODE) { - ret = dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, - TRUE); - if (ret < 0) - DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret)); - - memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); - ETHER_SET_LOCALADDR(&p2p_ea); - ret = dhd_iovar(dhd, 0, "p2p_da_override", (char *)&p2p_ea, - sizeof(p2p_ea), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); - else - DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); - } -#else - (void)concurrent_mode; -#endif - } - - DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n", - dhd->op_mode, MAC2STRDBG(dhd->mac.octet))); - /* Set Country code */ - if (dhd->dhd_cspec.ccode[0] != 0) { - ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); - } - -#if !defined(DISABLE_11AC) - if (somc_disable_vht) - { -#endif /* ! DISABLE_11AC */ - ret = dhd_iovar(dhd, 0, "vhtmode", (char *)&vhtmode, sizeof(vhtmode), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s wl vhtmode 0 failed %d\n", __FUNCTION__, ret)); - else - DHD_ERROR(("%s VHT(11ac) mode is disabled\n", __FUNCTION__)); -#if !defined(DISABLE_11AC) - } -#endif /* ! DISABLE_11AC */ - - /* Set Listen Interval */ - ret = dhd_iovar(dhd, 0, "assoc_listen", (char *)&listen_interval, sizeof(listen_interval), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); - -#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) - /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ - dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), NULL, 0, TRUE); -#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ -#if defined(ROAM_ENABLE) - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, - sizeof(roam_trigger), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, - sizeof(roam_scan_period), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret)); - if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, - sizeof(roam_delta), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); - ret = dhd_iovar(dhd, 0, "fullroamperiod", (char *)&roam_fullscan_period, - sizeof(roam_fullscan_period), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); -#ifdef ROAM_AP_ENV_DETECTION - if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) { - ret = dhd_iovar(dhd, 0, "roam_env_detection", (char *)&roam_env_mode, - sizeof(roam_env_mode), NULL, 0, TRUE); - if (ret == BCME_OK) - dhd->roam_env_detection = TRUE; - else - dhd->roam_env_detection = FALSE; - } -#endif /* ROAM_AP_ENV_DETECTION */ -#endif /* ROAM_ENABLE */ - -#ifdef BCMCCX - dhd_iovar(dhd, 0, "ccx_enable", (char *)&ccx, sizeof(ccx), NULL, 0, TRUE); -#endif /* BCMCCX */ -#ifdef WLTDLS - /* by default TDLS on and auto mode off */ - _dhd_tdls_enable(dhd, true, false, NULL); -#endif /* WLTDLS */ - -#ifdef DHD_ENABLE_LPC - /* Set lpc 1 */ - ret = dhd_iovar(dhd, 0, "lpc", (char *)&lpc, sizeof(lpc), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); - } -#endif /* DHD_ENABLE_LPC */ - - /* Set PowerSave mode */ - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); - - /* Match Host and Dongle rx alignment */ - dhd_iovar(dhd, 0, "bus:txglomalign", (char *)&dongle_align, sizeof(dongle_align), - NULL, 0, TRUE); -#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) - /* enable credall to reduce the chance of no bus credit happened. */ - dhd_iovar(dhd, 0, "bus:credall", (char *)&credall, sizeof(credall), NULL, 0, TRUE); -#endif - - if (glom != DEFAULT_GLOM_VALUE) { - DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom)); - dhd_iovar(dhd, 0, "bus:txglom", (char *)&glom, sizeof(glom), NULL, 0, TRUE); - } - - /* Setup timeout if Beacons are lost and roam is off to report link down */ - dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, sizeof(bcn_timeout), NULL, 0, TRUE); -#ifdef SOMC_WLAN_SCAN_NPROBES - { - const uint32 scan_nprobes = SOMC_WLAN_SCAN_NPROBES; - if (( ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_NPROBES, (char *)&scan_nprobes, - sizeof(scan_nprobes), TRUE, 0)) < 0) - DHD_ERROR(("%s: set scan_nprobes failed %d\n", __FUNCTION__, ret)); - } -#endif - -#ifdef DISABLE_BCN_DLY - /* Set bcn_to_dly to delay link down until roam complete */ - dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, sizeof(bcn_to_dly), NULL, 0, TRUE); -#endif - /* Setup assoc_retry_max count to reconnect target AP in dongle */ - dhd_iovar(dhd, 0, "assoc_retry_max", (char *)&retry_max, sizeof(retry_max), NULL, 0, TRUE); -#if defined(AP) && !defined(WLP2P) - /* Turn off MPC in AP mode */ - dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); - dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, TRUE); -#endif /* defined(AP) && !defined(WLP2P) */ - - - -#if defined(SOFTAP) - if (ap_fw_loaded == TRUE) { - dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); - } -#endif - -#if defined(KEEP_ALIVE) - { - /* Set Keep Alive : be sure to use FW with -keepalive */ - int res; - -#if defined(SOFTAP) - if (ap_fw_loaded == FALSE) -#endif - if (!(dhd->op_mode & - (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) { - if ((res = dhd_keep_alive_onoff(dhd)) < 0) - DHD_ERROR(("%s set keeplive failed %d\n", - __FUNCTION__, res)); - } - } -#endif /* defined(KEEP_ALIVE) */ -#ifdef USE_WL_TXBF - ret = dhd_iovar(dhd, 0, "txbf", (char *)&txbf, sizeof(txbf), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret)); - } -#endif /* USE_WL_TXBF */ -#ifdef DISABLE_TXBFR - ret = dhd_iovar(dhd, 0, "txbf_bfr_cap", (char *)&txbf_bfr_cap, sizeof(txbf_bfr_cap), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Clear txbf_bfr_cap failed %d\n", __FUNCTION__, ret)); - } -#endif /* DISABLE_TXBFR */ -#ifdef USE_WL_FRAMEBURST -#ifdef DISABLE_WL_FRAMEBURST_SOFTAP - /* Disable Framebursting for SofAP */ - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - frameburst = 0; - } -#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */ - /* Set frameburst to value */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst, - sizeof(frameburst), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set frameburst failed %d\n", __FUNCTION__, ret)); - } -#endif /* USE_WL_FRAMEBURST */ -#ifdef DHD_SET_FW_HIGHSPEED - /* Set ack_ratio */ - ret = dhd_iovar(dhd, 0, "ack_ratio", (char *)&ack_ratio, sizeof(ack_ratio), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s Set ack_ratio failed %d\n", __FUNCTION__, ret)); - - /* Set ack_ratio_depth */ - ret = dhd_iovar(dhd, 0, "ack_ratio_depth", (char *)&ack_ratio_depth, - sizeof(ack_ratio_depth), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s Set ack_ratio_depth failed %d\n", __FUNCTION__, ret)); -#endif /* DHD_SET_FW_HIGHSPEED */ -#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ - defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) - /* Set ampdu ba wsize to 64 or 16 */ -#ifdef CUSTOM_AMPDU_BA_WSIZE - ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE; -#endif -#if defined(WLAIBSS) && defined(CUSTOM_IBSS_AMPDU_BA_WSIZE) - if (dhd->op_mode == DHD_FLAG_IBSS_MODE) - ampdu_ba_wsize = CUSTOM_IBSS_AMPDU_BA_WSIZE; -#endif /* WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE */ - if (ampdu_ba_wsize != 0) { - ret = dhd_iovar(dhd, 0, "ampdu_ba_wsize", (char *)&du_ba_wsize, - sizeof(ampdu_ba_wsize), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n", - __FUNCTION__, ampdu_ba_wsize, ret)); - } - } -#endif /* CUSTOM_AMPDU_BA_WSIZE || (WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ - - iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); - if (iov_buf == NULL) { - DHD_ERROR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN)); - ret = BCME_NOMEM; - goto done; - } -#ifdef WLAIBSS - /* Configure custom IBSS beacon transmission */ - if (dhd->op_mode & DHD_FLAG_IBSS_MODE) - { - aibss = 1; - ret = dhd_iovar(dhd, 0, "aibss", (char *)&aibss, sizeof(aibss), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set aibss to %d failed %d\n", - __FUNCTION__, aibss, ret)); - } - } - memset(&bcn_config, 0, sizeof(bcn_config)); - bcn_config.initial_min_bcn_dur = AIBSS_INITIAL_MIN_BCN_DUR; - bcn_config.min_bcn_dur = AIBSS_MIN_BCN_DUR; - bcn_config.bcn_flood_dur = AIBSS_BCN_FLOOD_DUR; - bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0; - bcn_config.len = sizeof(bcn_config); - - ret = dhd_iovar(dhd, 0, "aibss_bcn_force_config", (char *)&bcn_config, - sizeof(aibss_bcn_force_config_t), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set aibss_bcn_force_config to %d, %d, %d failed %d\n", - __FUNCTION__, AIBSS_INITIAL_MIN_BCN_DUR, AIBSS_MIN_BCN_DUR, - AIBSS_BCN_FLOOD_DUR, ret)); - } -#endif /* WLAIBSS */ - -#if defined(CUSTOM_AMPDU_MPDU) - ampdu_mpdu = CUSTOM_AMPDU_MPDU; - if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) { - ret = dhd_iovar(dhd, 0, "ampdu_mpdu", (char *)&du_mpdu, sizeof(ampdu_mpdu), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n", - __FUNCTION__, CUSTOM_AMPDU_MPDU, ret)); - } - } -#endif /* CUSTOM_AMPDU_MPDU */ - -#ifdef SUPPORT_2G_VHT - ret = dhd_iovar(dhd, 0, "vht_features", (char *)&vht_features, sizeof(vht_features), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret)); - } -#endif /* SUPPORT_2G_VHT */ -#ifdef DISABLE_11N_PROPRIETARY_RATES - ret = dhd_iovar(dhd, 0, "ht_features", (char *)&ht_features, sizeof(ht_features), NULL, 0, - TRUE); - if (ret < 0) - DHD_ERROR(("%s ht_features set failed %d\n", __FUNCTION__, ret)); -#endif /* DISABLE_11N_PROPRIETARY_RATES */ -#ifdef CUSTOM_PSPRETEND_THR - /* Turn off MPC in AP mode */ - ret = dhd_iovar(dhd, 0, "pspretend_threshold", (char *)&pspretend_thr, - sizeof(pspretend_thr), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n", - __FUNCTION__, ret)); -#endif - - ret = dhd_iovar(dhd, 0, "buf_key_b4_m4", (char *)&buf_key_b4_m4, sizeof(buf_key_b4_m4), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret)); - - /* Read event_msgs mask */ - ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, - sizeof(iovbuf), FALSE); - if (ret < 0) { - DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret)); - goto done; - } - bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); - - /* Setup event_msgs */ - setbit(eventmask, WLC_E_SET_SSID); - setbit(eventmask, WLC_E_PRUNE); - setbit(eventmask, WLC_E_AUTH); - setbit(eventmask, WLC_E_ASSOC); - setbit(eventmask, WLC_E_REASSOC); - setbit(eventmask, WLC_E_REASSOC_IND); - setbit(eventmask, WLC_E_DEAUTH); - setbit(eventmask, WLC_E_DEAUTH_IND); - setbit(eventmask, WLC_E_DISASSOC_IND); - setbit(eventmask, WLC_E_DISASSOC); - setbit(eventmask, WLC_E_JOIN); - setbit(eventmask, WLC_E_START); - setbit(eventmask, WLC_E_ASSOC_IND); - setbit(eventmask, WLC_E_PSK_SUP); - setbit(eventmask, WLC_E_LINK); - setbit(eventmask, WLC_E_NDIS_LINK); - setbit(eventmask, WLC_E_MIC_ERROR); - setbit(eventmask, WLC_E_ASSOC_REQ_IE); - setbit(eventmask, WLC_E_ASSOC_RESP_IE); -#ifndef WL_CFG80211 - setbit(eventmask, WLC_E_PMKID_CACHE); - setbit(eventmask, WLC_E_TXFAIL); -#endif - setbit(eventmask, WLC_E_JOIN_START); - setbit(eventmask, WLC_E_SCAN_COMPLETE); -#ifdef DHD_DEBUG - setbit(eventmask, WLC_E_SCAN_CONFIRM_IND); -#endif -#ifdef WLMEDIA_HTSF - setbit(eventmask, WLC_E_HTSFSYNC); -#endif /* WLMEDIA_HTSF */ -#ifdef PNO_SUPPORT - setbit(eventmask, WLC_E_PFN_NET_FOUND); - setbit(eventmask, WLC_E_PFN_BEST_BATCHING); - setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND); - setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST); -#endif /* PNO_SUPPORT */ - /* enable dongle roaming event */ - setbit(eventmask, WLC_E_ROAM); - setbit(eventmask, WLC_E_BSSID); -#ifdef BCMCCX - setbit(eventmask, WLC_E_ADDTS_IND); - setbit(eventmask, WLC_E_DELTS_IND); -#endif /* BCMCCX */ -#ifdef WLTDLS - setbit(eventmask, WLC_E_TDLS_PEER_EVENT); -#endif /* WLTDLS */ -#ifdef RTT_SUPPORT - setbit(eventmask, WLC_E_PROXD); -#endif /* RTT_SUPPORT */ -#ifdef WL_CFG80211 - setbit(eventmask, WLC_E_ESCAN_RESULT); - if (dhd->op_mode & DHD_FLAG_P2P_MODE) { - setbit(eventmask, WLC_E_ACTION_FRAME_RX); - setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); - } -#endif /* WL_CFG80211 */ -#ifdef WLAIBSS - setbit(eventmask, WLC_E_AIBSS_TXFAIL); -#endif /* WLAIBSS */ -#ifdef SHOW_LOGTRACE - setbit(eventmask, WLC_E_TRACE); -#else - clrbit(eventmask, WLC_E_TRACE); -#endif /* SHOW_LOGTRACE */ -#ifdef DHD_LOSSLESS_ROAMING - setbit(eventmask, WLC_E_ROAM_PREP); -#endif /* DHD_LOSSLESS_ROAMING */ - - /* Write updated Event mask */ - ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret)); - goto done; - } - - /* make up event mask ext message iovar for event larger than 128 */ - msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE; - eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL); - if (eventmask_msg == NULL) { - DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen)); - ret = BCME_NOMEM; - goto done; - } - bzero(eventmask_msg, msglen); - eventmask_msg->ver = EVENTMSGS_VER; - eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; - - /* Read event_msgs_ext mask */ - ret2 = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, - WLC_IOCTL_SMLEN, FALSE); - if (ret2 != BCME_UNSUPPORTED) - ret = ret2; - if (ret2 == 0) { /* event_msgs_ext must be supported */ - bcopy(iov_buf, eventmask_msg, msglen); -#ifdef RSSI_MONITOR_SUPPORT - setbit(eventmask_msg->mask, WLC_E_RSSI_LQM); -#endif /* RSSI_MONITOR_SUPPORT */ -#ifdef GSCAN_SUPPORT - setbit(eventmask_msg->mask, WLC_E_PFN_GSCAN_FULL_RESULT); - setbit(eventmask_msg->mask, WLC_E_PFN_SCAN_COMPLETE); - setbit(eventmask_msg->mask, WLC_E_PFN_SSID_EXT); -#endif /* GSCAN_SUPPORT */ - - /* Write updated Event mask */ - eventmask_msg->ver = EVENTMSGS_VER; - eventmask_msg->command = EVENTMSGS_SET_MASK; - eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; - ret = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret)); - goto done; - } - } else if (ret2 < 0) { - DHD_ERROR(("%s read event mask ext unsupported %d\n", __FUNCTION__, ret2)); - } /* unsupported is ok */ - - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, - sizeof(scan_assoc_time), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, - sizeof(scan_unassoc_time), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, - sizeof(scan_passive_time), TRUE, 0); - -#ifdef ARP_OFFLOAD_SUPPORT - /* Set and enable ARP offload feature for STA only */ -#if defined(SOFTAP) - if (arpoe && !ap_fw_loaded) { -#else - if (arpoe) { -#endif - dhd_arp_offload_enable(dhd, TRUE); - dhd_arp_offload_set(dhd, dhd_arp_mode); - } else { - dhd_arp_offload_enable(dhd, FALSE); - dhd_arp_offload_set(dhd, 0); - } - dhd_arp_enable = arpoe; -#endif /* ARP_OFFLOAD_SUPPORT */ - -#ifdef PKT_FILTER_SUPPORT - /* Setup default defintions for pktfilter , enable in suspend */ - dhd->pktfilter_count = 6; - /* Setup filter to allow only unicast */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; - dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; - /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ - dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; - /* apply APP pktfilter */ - dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; - - -#if defined(SOFTAP) - if (ap_fw_loaded) { - dhd_enable_packet_filter(0, dhd); - } -#endif /* defined(SOFTAP) */ - dhd_set_packet_filter(dhd); -#endif /* PKT_FILTER_SUPPORT */ -#ifdef DISABLE_11N - ret = dhd_iovar(dhd, 0, "nmode", (char *)&nmode, sizeof(nmode), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); -#endif /* DISABLE_11N */ - -#ifdef AMPDU_VO_ENABLE - tid.tid = PRIO_8021D_VO; /* Enable TID(6) for voice */ - tid.enable = TRUE; - dhd_iovar(dhd, 0, "ampdu_tid", (char *)&tid, sizeof(tid), NULL, 0, TRUE); - - tid.tid = PRIO_8021D_NC; /* Enable TID(7) for voice */ - tid.enable = TRUE; - dhd_iovar(dhd, 0, "ampdu_tid", (char *)&tid, sizeof(tid), NULL, 0, TRUE); -#endif -#ifdef SOMC_MAX_ASSOC_NUM - { - /* Set the maximum number of stations for P2P / SoftAP */ - const uint32 max = SOMC_MAX_ASSOC_NUM; - dhd_iovar(dhd, 0, "maxassoc", (char *)&max, sizeof(max), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s: maxassoc set failed %d\n", __FUNCTION__, ret)); - } -#endif /* SOMC_MAX_ASSOC_NUM */ - - /* query for 'ver' to get version info from firmware */ - memset(buf, 0, sizeof(buf)); - ptr = buf; - ret = dhd_iovar(dhd, 0, "ver", NULL, 0, (char *)buf, sizeof(buf), FALSE); - if (ret < 0) - DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); - else { - bcmstrtok(&ptr, "\n", 0); - /* Print fw version info */ - DHD_ERROR(("Firmware version = %s\n", buf)); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - snprintf(bcm_wlan_ver_info, sizeof(bcm_wlan_ver_info), - "firmware_version %s\ndhd_version %s\n", - buf, EPI_VERSION_STR); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - dhd_set_version_info(dhd, buf); - } - - dhd_txglom_enable(dhd, TRUE); - -#ifdef PROP_TXSTATUS - if (disable_proptx || -#ifdef PROP_TXSTATUS_VSDB - /* enable WLFC only if the firmware is VSDB when it is in STA mode */ - (dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) || -#endif /* PROP_TXSTATUS_VSDB */ - FALSE) { - wlfc_enable = FALSE; - } - -#ifndef DISABLE_11N - ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, sizeof(hostreorder), - NULL, 0, TRUE); - if (ret2 < 0) { - DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2)); - if (ret2 != BCME_UNSUPPORTED) - ret = ret2; - if (ret2 != BCME_OK) - hostreorder = 0; - } -#endif /* DISABLE_11N */ - if (wlfc_enable) - dhd_wlfc_init(dhd); -#ifndef DISABLE_11N - else if (hostreorder) - dhd_wlfc_hostreorder_init(dhd); -#endif /* DISABLE_11N */ - -#endif /* PROP_TXSTATUS */ -#ifdef PNO_SUPPORT - if (!dhd->pno_state) { - dhd_pno_init(dhd); - } -#endif -#ifdef RTT_SUPPORT - if (!dhd->rtt_state) { - ret = dhd_rtt_init(dhd); - if (ret < 0) { - DHD_ERROR(("%s failed to initialize RTT\n", __FUNCTION__)); - } - } -#endif -#ifdef WL11U - dhd_interworking_enable(dhd); -#endif /* WL11U */ - -done: - - if (eventmask_msg) - kfree(eventmask_msg); - if (iov_buf) - kfree(iov_buf); - - return ret; -} - - -int -dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, char *res_buf, - uint res_len, int set) -{ - char *buf = NULL; - int input_len; - wl_ioctl_t ioc; - int ret; - - if (res_len > WLC_IOCTL_MAXLEN || param_len > WLC_IOCTL_MAXLEN) - return BCME_BADARG; - - input_len = strlen(name) + 1 + param_len; - if (input_len > WLC_IOCTL_MAXLEN) - return BCME_BADARG; - - buf = NULL; - if (set) { - if (res_buf || res_len != 0) { - DHD_ERROR(("%s: SET wrong arguemnet\n", __FUNCTION__)); - ret = BCME_BADARG; - goto exit; - } - buf = kzalloc(input_len, GFP_KERNEL); - if (!buf) { - DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); - ret = BCME_NOMEM; - goto exit; - } - ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); - if (!ret) { - ret = BCME_NOMEM; - goto exit; - } - - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = input_len; - ioc.set = set; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - } else { - if (!res_buf || !res_len) { - DHD_ERROR(("%s: GET failed. resp_buf NULL or length 0.\n", __FUNCTION__)); - ret = BCME_BADARG; - goto exit; - } - - if (res_len < input_len) { - DHD_INFO(("%s: res_len(%d) < input_len(%d)\n", __FUNCTION__, - res_len, input_len)); - buf = kzalloc(input_len, GFP_KERNEL); - if (!buf) { - DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); - ret = BCME_NOMEM; - goto exit; - } - ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); - if (!ret) { - ret = BCME_NOMEM; - goto exit; - } - - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = input_len; - ioc.set = set; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret == BCME_OK) { - memcpy(res_buf, buf, res_len); - } - } else { - memset(res_buf, 0, res_len); - ret = bcm_mkiovar(name, param_buf, param_len, res_buf, res_len); - if (!ret) { - ret = BCME_NOMEM; - goto exit; - } - - ioc.cmd = WLC_GET_VAR; - ioc.buf = res_buf; - ioc.len = res_len; - ioc.set = set; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - } - } - -exit: - kfree(buf); - return ret; -} - -int -dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, - uint cmd_len, char **resptr, uint resp_len) -{ - int len = resp_len; - int ret; - char *buf = *resptr; - wl_ioctl_t ioc; - if (resp_len > WLC_IOCTL_MAXLEN) - return BCME_BADARG; - - memset(buf, 0, resp_len); - - bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = len; - ioc.set = 0; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - - return ret; -} - -int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) -{ - struct dhd_info *dhd = dhdp->info; - struct net_device *dev = NULL; - - ASSERT(dhd && dhd->iflist[ifidx]); - dev = dhd->iflist[ifidx]->net; - ASSERT(dev); - - if (netif_running(dev)) { - DHD_ERROR(("%s: Must be down to change its MTU", dev->name)); - return BCME_NOTDOWN; - } - -#define DHD_MIN_MTU 1500 -#define DHD_MAX_MTU 1752 - - if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { - DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu)); - return BCME_BADARG; - } - - dev->mtu = new_mtu; - return 0; -} - -#ifdef ARP_OFFLOAD_SUPPORT -/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ -void -aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx) -{ - u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ - int i; - int ret; - - bzero(ipv4_buf, sizeof(ipv4_buf)); - - /* display what we've got */ - ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); - DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__)); - if (ret) { - DHD_ERROR(("%s failed\n", __FUNCTION__)); - return; - } -#ifdef AOE_DBG - dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -#endif - /* now we saved hoste_ip table, clr it in the dongle AOE */ - dhd_aoe_hostip_clr(dhd_pub, idx); - - for (i = 0; i < MAX_IPV4_ENTRIES; i++) { - if (add && (ipv4_buf[i] == 0)) { - ipv4_buf[i] = ipa; - add = FALSE; /* added ipa to local table */ - DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n", - __FUNCTION__, i)); - } else if (ipv4_buf[i] == ipa) { - ipv4_buf[i] = 0; - DHD_ARPOE(("%s: removed IP:%x from temp table %d\n", - __FUNCTION__, ipa, i)); - } - - if (ipv4_buf[i] != 0) { - /* add back host_ip entries from our local cache */ - dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx); - DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n", - __FUNCTION__, ipv4_buf[i], i)); - } - } -#ifdef AOE_DBG - /* see the resulting hostip table */ - dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); - DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__)); - dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -#endif -} - -/* - * Notification mechanism from kernel to our driver. This function is called by the Linux kernel - * whenever there is an event related to an IP address. - * ptr : kernel provided pointer to IP address that has changed - */ -static int dhd_inetaddr_notifier_call(struct notifier_block *this, - unsigned long event, - void *ptr) -{ - struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; - - dhd_info_t *dhd; - dhd_pub_t *dhd_pub; - int idx; - - if (!dhd_arp_enable) - return NOTIFY_DONE; - if (!ifa || !(ifa->ifa_dev->dev)) - return NOTIFY_DONE; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) - /* Filter notifications meant for non Broadcom devices */ - if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) && - (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) { -#if defined(WL_ENABLE_P2P_IF) - if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) -#endif /* WL_ENABLE_P2P_IF */ - return NOTIFY_DONE; - } -#endif /* LINUX_VERSION_CODE */ - - dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev); - if (!dhd) - return NOTIFY_DONE; - - dhd_pub = &dhd->pub; - - if (dhd_pub->arp_version == 1) { - idx = 0; - } - else { - for (idx = 0; idx < DHD_MAX_IFS; idx++) { - if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev) - break; - } - if (idx < DHD_MAX_IFS) - DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net, - dhd->iflist[idx]->name, dhd->iflist[idx]->idx)); - else { - DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label)); - idx = 0; - } - } - - switch (event) { - case NETDEV_UP: - DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - - if (dhd->pub.busstate != DHD_BUS_DATA) { - DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); - if (dhd->pend_ipaddr) { - DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", - __FUNCTION__, dhd->pend_ipaddr)); - } - dhd->pend_ipaddr = ifa->ifa_address; - break; - } - -#ifdef AOE_IP_ALIAS_SUPPORT - DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", - __FUNCTION__)); - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx); -#endif /* AOE_IP_ALIAS_SUPPORT */ - break; - - case NETDEV_DOWN: - DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - dhd->pend_ipaddr = 0; -#ifdef AOE_IP_ALIAS_SUPPORT - DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n", - __FUNCTION__)); - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx); -#else - dhd_aoe_hostip_clr(&dhd->pub, idx); - dhd_aoe_arp_clr(&dhd->pub, idx); -#endif /* AOE_IP_ALIAS_SUPPORT */ - break; - - default: - DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n", - __func__, ifa->ifa_label, event)); - break; - } - return NOTIFY_DONE; -} -#endif /* ARP_OFFLOAD_SUPPORT */ - -/* Neighbor Discovery Offload: defered handler */ -static void -dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event) -{ - struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data; - dhd_pub_t *pub = &((dhd_info_t *)dhd_info)->pub; - int ret; - - if (event != DHD_WQ_WORK_IPV6_NDO) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!ndo_work) { - DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__)); - return; - } - - if (!pub) { - DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__)); - return; - } - - if (ndo_work->if_idx) { - DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx)); - return; - } - - switch (ndo_work->event) { - case NETDEV_UP: - DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__)); - ret = dhd_ndo_enable(pub, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret)); - } - - ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx); - if (ret < 0) { - DHD_ERROR(("%s: Adding host ip for NDO failed %d\n", - __FUNCTION__, ret)); - } - break; - case NETDEV_DOWN: - DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__)); - ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx); - if (ret < 0) { - DHD_ERROR(("%s: Removing host ip for NDO failed %d\n", - __FUNCTION__, ret)); - goto done; - } - - ret = dhd_ndo_enable(pub, FALSE); - if (ret < 0) { - DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret)); - goto done; - } - break; - default: - DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__)); - break; - } -done: - /* free ndo_work. alloced while scheduling the work */ - kfree(ndo_work); - - return; -} - -/* - * Neighbor Discovery Offload: Called when an interface - * is assigned with ipv6 address. - * Handles only primary interface - */ -static int dhd_inet6addr_notifier_call(struct notifier_block *this, - unsigned long event, - void *ptr) -{ - dhd_info_t *dhd; - dhd_pub_t *dhd_pub; - struct inet6_ifaddr *inet6_ifa = ptr; - struct in6_addr *ipv6_addr = &inet6_ifa->addr; - struct ipv6_work_info_t *ndo_info; - int idx = 0; /* REVISIT */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) - /* Filter notifications meant for non Broadcom devices */ - if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) { - return NOTIFY_DONE; - } -#endif /* LINUX_VERSION_CODE */ - - dhd = *(dhd_info_t **)netdev_priv(inet6_ifa->idev->dev); - if (!dhd) - return NOTIFY_DONE; - - if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev) - return NOTIFY_DONE; - dhd_pub = &dhd->pub; - if (!FW_SUPPORTED(dhd_pub, ndoe)) - return NOTIFY_DONE; - - ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC); - if (!ndo_info) { - DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__)); - return NOTIFY_DONE; - } - - ndo_info->event = event; - ndo_info->if_idx = idx; - memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN); - - /* defer the work to thread as it may block kernel */ - dhd_deferred_schedule_work((void *)ndo_info, DHD_WQ_WORK_IPV6_NDO, - dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW); - return NOTIFY_DONE; -} - -int -dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct net_device *net = NULL; - int err = 0; - uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; - - DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - - ASSERT(dhd && dhd->iflist[ifidx]); - net = dhd->iflist[ifidx]->net; - ASSERT(net); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - ASSERT(!net->open); - net->get_stats = dhd_get_stats; - net->do_ioctl = dhd_ioctl_entry; - net->hard_start_xmit = dhd_start_xmit; - net->set_mac_address = dhd_set_mac_address; - net->set_multicast_list = dhd_set_multicast_list; - net->open = net->stop = NULL; -#else - ASSERT(!net->netdev_ops); - net->netdev_ops = &dhd_ops_virt; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - - /* Ok, link into the network layer... */ - if (ifidx == 0) { - /* - * device functions for the primary interface only - */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - net->open = dhd_open; - net->stop = dhd_stop; -#else - net->netdev_ops = &dhd_ops_pri; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) - memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); - } else { - /* - * We have to use the primary MAC for virtual interfaces - */ - memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN); - /* - * Android sets the locally administered bit to indicate that this is a - * portable hotspot. This will not work in simultaneous AP/STA mode, - * nor with P2P. Need to set the Donlge's MAC address, and then use that. - */ - if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, - ETHER_ADDR_LEN)) { - DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", - __func__, net->name)); - temp_addr[0] |= 0x02; - } - } - - net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - net->ethtool_ops = &dhd_ethtool_ops; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - -#if defined(WL_WIRELESS_EXT) -#if WIRELESS_EXT < 19 - net->get_wireless_stats = dhd_get_wireless_stats; -#endif /* WIRELESS_EXT < 19 */ -#if WIRELESS_EXT > 12 - net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; -#endif /* WIRELESS_EXT > 12 */ -#endif /* defined(WL_WIRELESS_EXT) */ - - dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); - - memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); - - if (ifidx == 0) - printf("%s\n", dhd_version); - - if (need_rtnl_lock) - err = register_netdev(net); - else - err = register_netdevice(net); - - if (err != 0) { - DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err)); - goto fail; - } - - - printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name, - MAC2STRDBG(net->dev_addr)); - -#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211) - wl_iw_iscan_set_scan_broadcast_prep(net, 1); -#endif - -#if defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - if (ifidx == 0) { -#ifdef BCMLXSDMMC - up(&dhd_registration_sem); -#endif - if (!dhd_download_fw_on_driverload) { - dhd_net_bus_devreset(net, TRUE); - dhd_net_bus_suspend(net); - wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY); - } - } -#endif /* OEM_ANDROID && BCMLXSDMMC && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - return 0; - -fail: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - net->open = NULL; -#else - net->netdev_ops = NULL; -#endif - return err; -} - -void -dhd_bus_detach(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - dhd = (dhd_info_t *)dhdp->info; - if (dhd) { - - /* - * In case of Android cfg80211 driver, the bus is down in dhd_stop, - * calling stop again will cuase SD read/write errors. - */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - - /* Stop the bus module */ - dhd_bus_stop(dhd->pub.bus, TRUE); - } - -#if defined(OOB_INTR_ONLY) - dhd_bus_oob_intr_unregister(dhdp); -#endif - } - } -} - - -void dhd_detach(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - unsigned long flags; - int timer_valid = FALSE; - - if (!dhdp) - return; - - dhd = (dhd_info_t *)dhdp->info; - if (!dhd) - return; - - DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); - - dhd->pub.up = 0; - if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { - /* Give sufficient time for threads to start running in case - * dhd_attach() has failed - */ - OSL_SLEEP(100); - } - - if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { - dhd_bus_detach(dhdp); - - if (dhdp->prot) - dhd_prot_detach(dhdp); - } - -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd_inetaddr_notifier_registered) { - dhd_inetaddr_notifier_registered = FALSE; - unregister_inetaddr_notifier(&dhd_inetaddr_notifier); - } -#endif /* ARP_OFFLOAD_SUPPORT */ - if (dhd_inet6addr_notifier_registered) { - dhd_inet6addr_notifier_registered = FALSE; - unregister_inet6addr_notifier(&dhd_inet6addr_notifier); - } - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { - if (dhd->early_suspend.suspend) - unregister_early_suspend(&dhd->early_suspend); - } -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -#if defined(WL_WIRELESS_EXT) - if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { - /* Detatch and unlink in the iw */ - wl_iw_detach(); - } -#endif /* defined(WL_WIRELESS_EXT) */ - - /* delete all interfaces, start with virtual */ - if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { - int i = 1; - dhd_if_t *ifp; - - /* Cleanup virtual interfaces */ - dhd_net_if_lock_local(dhd); - for (i = 1; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) - dhd_remove_if(&dhd->pub, i, TRUE); - } - dhd_net_if_unlock_local(dhd); - - /* delete primary interface 0 */ - ifp = dhd->iflist[0]; - ASSERT(ifp); - ASSERT(ifp->net); - if (ifp && ifp->net) { - /* in unregister_netdev case, the interface gets freed by net->destructor - * (which is set to free_netdev) - */ - if (ifp->net->reg_state == NETREG_UNINITIALIZED) - free_netdev(ifp->net); - else - unregister_netdev(ifp->net); - ifp->net = NULL; - MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); - dhd->iflist[0] = NULL; - } - } - - /* Clear the watchdog timer */ - flags = dhd_os_spin_lock(&dhd->pub); - timer_valid = dhd->wd_timer_valid; - dhd->wd_timer_valid = FALSE; - dhd_os_spin_unlock(&dhd->pub, flags); - if (timer_valid) - del_timer_sync(&dhd->timer); - - if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { - if (dhd->thr_wdt_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_wdt_ctl); - } - - if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_rxf_ctl); - } - - if (dhd->thr_dpc_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_dpc_ctl); - } else - tasklet_kill(&dhd->tasklet); - } -#ifdef WL_CFG80211 - if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { - wl_cfg80211_detach(NULL); - dhd_monitor_uninit(); - } -#endif - /* free deferred work queue */ - dhd_deferred_work_deinit(dhd->dhd_deferred_wq); - dhd->dhd_deferred_wq = NULL; - -#ifdef PNO_SUPPORT - if (dhdp->pno_state) - dhd_pno_deinit(dhdp); -#endif -#ifdef RTT_SUPPORT - if (dhdp->rtt_state) { - dhd_rtt_deinit(dhdp); - } -#endif -#if defined(CONFIG_PM_SLEEP) - if (dhd_pm_notifier_registered) { - unregister_pm_notifier(&dhd->pm_notifier); - dhd_pm_notifier_registered = FALSE; - } -#endif /* CONFIG_PM_SLEEP */ -#ifdef SAR_SUPPORT - if (dhd_sar_notifier_registered) { - unregister_notifier_by_sar(&dhd->sar_notifier); - dhd_sar_notifier_registered = FALSE; - } -#endif -#ifdef DEBUG_CPU_FREQ - if (dhd->new_freq) - free_percpu(dhd->new_freq); - dhd->new_freq = NULL; - cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); -#endif - if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { - DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); -#ifdef CONFIG_HAS_WAKELOCK - dhd->wakelock_counter = 0; - dhd->wakelock_wd_counter = 0; - dhd->wakelock_rx_timeout_enable = 0; - dhd->wakelock_ctrl_timeout_enable = 0; - wake_lock_destroy(&dhd->wl_wifi); - wake_lock_destroy(&dhd->wl_rxwake); - wake_lock_destroy(&dhd->wl_ctrlwake); - wake_lock_destroy(&dhd->wl_wdwake); -#endif /* CONFIG_HAS_WAKELOCK */ - } - - -#ifdef DHDTCPACK_SUPPRESS - /* This will free all MEM allocated for TCPACK SUPPRESS */ - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); -#endif /* DHDTCPACK_SUPPRESS */ -} - - -void -dhd_free(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - int i; - for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { - if (dhdp->reorder_bufs[i]) { - reorder_info_t *ptr; - uint32 buf_size = sizeof(struct reorder_info); - - ptr = dhdp->reorder_bufs[i]; - - buf_size += ((ptr->max_idx + 1) * sizeof(void*)); - DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", - i, ptr->max_idx, buf_size)); - - MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); - dhdp->reorder_bufs[i] = NULL; - } - } - dhd = (dhd_info_t *)dhdp->info; - if (dhdp->soc_ram) { - MFREE(dhd->pub.osh, dhdp->soc_ram, dhdp->soc_ram_length); - dhdp->soc_ram = NULL; - } - - /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */ - if (dhd && - dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE)) - MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); - dhd = NULL; - } -} - -static void __exit -dhd_module_cleanup(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - dhd_bus_unregister(); - - wl_android_exit(); - - dhd_wifi_platform_unregister_drv(); -} - -#define BCMCONF "/data/misc/wifi/bcm_debug.conf" - -static int __init -dhd_module_init(void) -{ - int err; - void *fp = NULL; - - DHD_ERROR(("%s in\n", __FUNCTION__)); - err = dhd_wifi_platform_register_drv(); - - fp = dhd_os_open_image(BCMCONF); - if (fp) { - unsigned char buf[7]; - long res = 0; - int len = dhd_os_get_image_block(buf, 7, fp); - if (len > 0 && len < 7) { - buf[len] = '\0'; - if (!kstrtol(buf, 16, &res)) - dhd_msg_level = (int)res; - } else { - DHD_ERROR(("Error in dbg level pattern\n")); - } - dhd_os_close_image(fp); - } - - return err; -} - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -#if defined(CONFIG_DEFERRED_INITCALLS) -deferred_module_init(dhd_module_init); -#elif defined(USE_LATE_INITCALL_SYNC) -late_initcall_sync(dhd_module_init); -#else -late_initcall(dhd_module_init); -#endif /* USE_LATE_INITCALL_SYNC */ -#else -module_init(dhd_module_init); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ - -module_exit(dhd_module_cleanup); - -/* - * OS specific functions required to implement DHD driver in OS independent way - */ -int -dhd_os_proto_block(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - down(&dhd->proto_sem); - return 1; - } - - return 0; -} - -int -dhd_os_proto_unblock(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - up(&dhd->proto_sem); - return 1; - } - - return 0; -} - -unsigned int -dhd_os_get_ioctl_resp_timeout(void) -{ - return ((unsigned int)dhd_ioctl_timeout_msec); -} - -void -dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) -{ - dhd_ioctl_timeout_msec = (int)timeout_msec; -} - -int -dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout; - - /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); -#else - timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); -#endif - - timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); - return timeout; -} - -int -dhd_os_ioctl_resp_wake(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - wake_up(&dhd->ioctl_resp_wait); - return 0; -} - -void -dhd_os_wd_timer_extend(void *bus, bool extend) -{ - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - - if (extend) - dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL); - else - dhd_os_wd_timer(bus, dhd->default_wd_interval); -} - - -void -dhd_os_wd_timer(void *bus, uint wdtick) -{ - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - unsigned long flags; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!dhd) { - DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); - return; - } - - flags = dhd_os_spin_lock(pub); - - /* don't start the wd until fw is loaded */ - if (pub->busstate == DHD_BUS_DOWN) { - dhd_os_spin_unlock(pub, flags); - if (!wdtick) - DHD_OS_WD_WAKE_UNLOCK(pub); - return; - } - - /* Totally stop the timer */ - if (!wdtick && dhd->wd_timer_valid == TRUE) { - dhd->wd_timer_valid = FALSE; - dhd_os_spin_unlock(pub, flags); - del_timer_sync(&dhd->timer); - DHD_OS_WD_WAKE_UNLOCK(pub); - return; - } - - if (wdtick) { - DHD_OS_WD_WAKE_LOCK(pub); - dhd_watchdog_ms = (uint)wdtick; - /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); - dhd->wd_timer_valid = TRUE; - } - dhd_os_spin_unlock(pub, flags); -} - -void * -dhd_os_open_image(char *filename) -{ - struct file *fp; - - fp = filp_open(filename, O_RDONLY, 0); - /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? - * Alternative: - * fp = open_namei(AT_FDCWD, filename, O_RD, 0); - * ??? - */ - if (IS_ERR(fp)) - fp = NULL; - - return fp; -} - -int -dhd_os_get_image_block(char *buf, int len, void *image) -{ - struct file *fp = (struct file *)image; - int rdlen; - - if (!image) - return 0; - - rdlen = kernel_read(fp, fp->f_pos, buf, len); - if (rdlen > 0) - fp->f_pos += rdlen; - - return rdlen; -} - -void -dhd_os_close_image(void *image) -{ - if (image) - filp_close((struct file *)image, NULL); -} - -void -dhd_os_sdlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - - if (dhd_dpc_prio >= 0) - down(&dhd->sdsem); - else - spin_lock_bh(&dhd->sdlock); -} - -void -dhd_os_sdunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - - if (dhd_dpc_prio >= 0) - up(&dhd->sdsem); - else - spin_unlock_bh(&dhd->sdlock); -} - -void -dhd_os_sdlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->txqlock); -} - -void -dhd_os_sdunlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->txqlock); -} - -void -dhd_os_sdlock_rxq(dhd_pub_t *pub) -{ -} - -void -dhd_os_sdunlock_rxq(dhd_pub_t *pub) -{ -} - -void -dhd_os_sdtxlock(dhd_pub_t *pub) -{ - dhd_os_sdlock(pub); -} - -void -dhd_os_sdtxunlock(dhd_pub_t *pub) -{ - dhd_os_sdunlock(pub); -} - -static void -dhd_os_rxflock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->rxf_lock); - -} - -static void -dhd_os_rxfunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->rxf_lock); -} - -#ifdef DHDTCPACK_SUPPRESS -void -dhd_os_tcpacklock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->tcpack_lock); - -} - -void -dhd_os_tcpackunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->tcpack_lock); -} -#endif /* DHDTCPACK_SUPPRESS */ - -uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail) -{ - uint8* buf; - gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; - - buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size); - if (buf == NULL) { - DHD_ERROR(("%s: failed to alloc memory, section: %d," - " size: %dbytes", __FUNCTION__, section, size)); - if (kmalloc_if_fail) - buf = kmalloc(size, flags); - } - - return buf; -} - -void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size) -{ -} - -#if defined(WL_WIRELESS_EXT) -struct iw_statistics * -dhd_get_wireless_stats(struct net_device *dev) -{ - int res = 0; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (!dhd->pub.up) { - return NULL; - } - - res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); - - if (res == 0) - return &dhd->iw.wstats; - else - return NULL; -} -#endif /* defined(WL_WIRELESS_EXT) */ - -static int -dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, - wl_event_msg_t *event, void **data) -{ - int bcmerror = 0; - ASSERT(dhd != NULL); - - bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data); - if (bcmerror != BCME_OK) - return (bcmerror); - -#if defined(WL_WIRELESS_EXT) - if (event->bsscfgidx == 0) { - /* - * Wireless ext is on primary interface only - */ - - ASSERT(dhd->iflist[*ifidx] != NULL); - ASSERT(dhd->iflist[*ifidx]->net != NULL); - - if (dhd->iflist[*ifidx]->net) { - wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); - } - } -#endif /* defined(WL_WIRELESS_EXT) */ - -#ifdef WL_CFG80211 - ASSERT(dhd->iflist[*ifidx] != NULL); - ASSERT(dhd->iflist[*ifidx]->net != NULL); - if (dhd->iflist[*ifidx]->net) - wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); -#endif /* defined(WL_CFG80211) */ - - return (bcmerror); -} - -/* send up locally generated event */ -void -dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) -{ - switch (ntoh32(event->event_type)) { - - default: - break; - } -} - -#ifdef LOG_INTO_TCPDUMP -void -dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len) -{ - struct sk_buff *p, *skb; - uint32 pktlen; - int len; - dhd_if_t *ifp; - dhd_info_t *dhd; - uchar *skb_data; - int ifidx = 0; - struct ether_header eth; - - pktlen = sizeof(eth) + data_len; - dhd = dhdp->info; - - if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { - ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); - - bcopy(&dhdp->mac, ð.ether_dhost, ETHER_ADDR_LEN); - bcopy(&dhdp->mac, ð.ether_shost, ETHER_ADDR_LEN); - ETHER_TOGGLE_LOCALADDR(ð.ether_shost); - eth.ether_type = hton16(ETHER_TYPE_BRCM); - - bcopy((void *)ð, PKTDATA(dhdp->osh, p), sizeof(eth)); - bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len); - skb = PKTTONATIVE(dhdp->osh, p); - skb_data = skb->data; - len = skb->len; - - ifidx = dhd_ifname2idx(dhd, "wlan0"); - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) - ifp = dhd->iflist[0]; - - ASSERT(ifp); - skb->dev = ifp->net; - skb->protocol = eth_type_trans(skb, skb->dev); - skb->data = skb_data; - skb->len = len; - - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* Send the packet */ - if (in_interrupt()) { - netif_rx(skb); - } else { - netif_rx_ni(skb); - } - } - else { - /* Could not allocate a sk_buf */ - DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__)); - } -} -#endif /* LOG_INTO_TCPDUMP */ - -void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); -#else - int timeout = IOCTL_RESP_TIMEOUT * msecs_to_jiffies(1); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - - dhd_os_sdunlock(dhd); - wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); - dhd_os_sdlock(dhd); -#endif - return; -} - -void dhd_wait_event_wakeup(dhd_pub_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - if (waitqueue_active(&dhdinfo->ctrl_wait)) - wake_up(&dhdinfo->ctrl_wait); -#endif - return; -} - -int -dhd_net_bus_devreset(struct net_device *dev, uint8 flag) -{ - int ret; - - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (flag == TRUE) { - /* Issue wl down command before resetting the chip */ - if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { - DHD_TRACE(("%s: wl down failed\n", __FUNCTION__)); - } -#ifdef PROP_TXSTATUS - if (dhd->pub.wlfc_enabled) - dhd_wlfc_deinit(&dhd->pub); -#endif /* PROP_TXSTATUS */ -#ifdef PNO_SUPPORT - if (dhd->pub.pno_state) - dhd_pno_deinit(&dhd->pub); -#endif -#ifdef RTT_SUPPORT - if (dhd->pub.rtt_state) { - dhd_rtt_deinit(&dhd->pub); - } -#endif /* RTT_SUPPORT */ - } - - if (!flag) { - dhd_update_fw_nv_path(dhd); - /* update firmware and nvram path to sdio bus */ - dhd_bus_update_fw_nv_path(dhd->pub.bus, - dhd->fw_path, dhd->nv_path); - } - - ret = dhd_bus_devreset(&dhd->pub, flag); - if (ret) { - DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); - return ret; - } - - return ret; -} - -int -dhd_net_bus_suspend(struct net_device *dev) -{ - dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev); - return dhd_bus_suspend(&dhdinfo->pub); -} - -int -dhd_net_bus_resume(struct net_device *dev, uint8 stage) -{ - dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev); - return dhd_bus_resume(&dhdinfo->pub, stage); -} - -int net_os_set_suspend_disable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) { - ret = dhd->pub.suspend_disable_flag; - dhd->pub.suspend_disable_flag = val; - } - return ret; -} - -int net_os_set_suspend(struct net_device *dev, int val, int force) -{ - int ret = 0; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (dhd) { -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - ret = dhd_set_suspend(val, &dhd->pub); -#else - ret = dhd_suspend_resume_helper(dhd, val, force); -#endif -#ifdef WL_CFG80211 - wl_cfg80211_update_power_mode(dev); -#endif - } - return ret; -} - -int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (dhd) - dhd->pub.suspend_bcn_li_dtim = val; - - return 0; -} - -#ifdef PKT_FILTER_SUPPORT -int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - char *filterp = NULL; - int filter_id = 0; - int ret = 0; - - if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || - (num == DHD_MDNS_FILTER_NUM)) - return ret; - if (num >= dhd->pub.pktfilter_count) - return -EINVAL; - switch (num) { - case DHD_BROADCAST_FILTER_NUM: - filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; - filter_id = 101; - break; - case DHD_MULTICAST4_FILTER_NUM: - filterp = "102 0 0 0 0xFFFFFF 0x01005E"; - filter_id = 102; - break; - case DHD_MULTICAST6_FILTER_NUM: - filterp = "103 0 0 0 0xFFFF 0x3333"; - filter_id = 103; - break; - default: - return -EINVAL; - } - - /* Add filter */ - if (add_remove) { - dhd->pub.pktfilter[num] = filterp; - dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); - } else { /* Delete filter */ - if (dhd->pub.pktfilter[num] != NULL) { - dhd_pktfilter_offload_delete(&dhd->pub, filter_id); - dhd->pub.pktfilter[num] = NULL; - } - } - return ret; -} - -int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) - -{ - int ret = 0; - - /* Packet filtering is set only if we still in early-suspend and - * we need either to turn it ON or turn it OFF - * We can always turn it OFF in case of early-suspend, but we turn it - * back ON only if suspend_disable_flag was not set - */ - if (dhdp && dhdp->up) { - if (dhdp->in_suspend) { - if (!val || (val && !dhdp->suspend_disable_flag)) - dhd_enable_packet_filter(val, dhdp); - } - } - return ret; -} - -/* function to enable/disable packet for Network device */ -int net_os_enable_packet_filter(struct net_device *dev, int val) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return dhd_os_enable_packet_filter(&dhd->pub, val); -} -#endif /* PKT_FILTER_SUPPORT */ - -int -dhd_dev_init_ioctl(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret; - - dhd_process_cid_mac(&dhd->pub, TRUE); - - if ((ret = dhd_prot_init(&dhd->pub)) < 0) - goto done; - - dhd_process_cid_mac(&dhd->pub, FALSE); - -done: - return ret; -} - -int -dhd_dev_get_feature_set(struct net_device *dev) -{ - dhd_info_t *ptr = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhd = (&ptr->pub); - int feature_set = 0; - - if (!dhd) - return feature_set; - - if (FW_SUPPORTED(dhd, sta)) - feature_set |= WIFI_FEATURE_INFRA; - if (FW_SUPPORTED(dhd, dualband)) - feature_set |= WIFI_FEATURE_INFRA_5G; - if (FW_SUPPORTED(dhd, p2p)) - feature_set |= WIFI_FEATURE_P2P; - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) - feature_set |= WIFI_FEATURE_SOFT_AP; - if (FW_SUPPORTED(dhd, tdls)) - feature_set |= WIFI_FEATURE_TDLS; - if (FW_SUPPORTED(dhd, vsdb)) - feature_set |= WIFI_FEATURE_TDLS_OFFCHANNEL; - if (FW_SUPPORTED(dhd, nan)) { - feature_set |= WIFI_FEATURE_NAN; - /* NAN is essentail for d2d rtt */ - if (FW_SUPPORTED(dhd, rttd2d)) - feature_set |= WIFI_FEATURE_D2D_RTT; - } -#ifdef RTT_SUPPORT - feature_set |= WIFI_FEATURE_D2AP_RTT; -#endif /* RTT_SUPPORT */ -#ifdef LINKSTAT_SUPPORT - feature_set |= WIFI_FEATURE_LINKSTAT; -#endif /* LINKSTAT_SUPPORT */ - /* Supports STA + STA always */ - feature_set |= WIFI_FEATURE_ADDITIONAL_STA; -#ifdef PNO_SUPPORT - if (dhd_is_pno_supported(dhd)) { - feature_set |= WIFI_FEATURE_PNO; - feature_set |= WIFI_FEATURE_BATCH_SCAN; -#ifdef GSCAN_SUPPORT - feature_set |= WIFI_FEATURE_GSCAN; -#endif /* GSCAN_SUPPORT */ -#ifdef EPNO_SUPPORT - feature_set |= WIFI_FEATURE_HAL_EPNO; -#endif /* EPNO_SUPPORT */ - } -#endif /* PNO_SUPPORT */ -#ifdef RSSI_MONITOR_SUPPORT - if (FW_SUPPORTED(dhd, rssi_mon)) { - feature_set |= WIFI_FEATURE_RSSI_MONITOR; - } -#endif -#ifdef WL11U - feature_set |= WIFI_FEATURE_HOTSPOT; -#endif /* WL11U */ - return feature_set; -} - -int* -dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num) -{ - int feature_set_full, mem_needed; - int *ret; - - *num = 0; - mem_needed = sizeof(int) * MAX_FEATURE_SET_CONCURRRENT_GROUPS; - ret = (int *) kmalloc(mem_needed, GFP_KERNEL); - - if (!ret) { - DHD_ERROR(("%s: failed to allocate %d bytes\n", __FUNCTION__, - mem_needed)); - return ret; - } - - feature_set_full = dhd_dev_get_feature_set(dev); - - ret[0] = (feature_set_full & WIFI_FEATURE_INFRA) | - (feature_set_full & WIFI_FEATURE_INFRA_5G) | - (feature_set_full & WIFI_FEATURE_NAN) | - (feature_set_full & WIFI_FEATURE_D2D_RTT) | - (feature_set_full & WIFI_FEATURE_D2AP_RTT) | - (feature_set_full & WIFI_FEATURE_PNO) | - (feature_set_full & WIFI_FEATURE_HAL_EPNO) | - (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | - (feature_set_full & WIFI_FEATURE_BATCH_SCAN) | - (feature_set_full & WIFI_FEATURE_GSCAN) | - (feature_set_full & WIFI_FEATURE_HOTSPOT) | - (feature_set_full & WIFI_FEATURE_ADDITIONAL_STA) | - (feature_set_full & WIFI_FEATURE_EPR); - - ret[1] = (feature_set_full & WIFI_FEATURE_INFRA) | - (feature_set_full & WIFI_FEATURE_INFRA_5G) | - (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | - /* Not yet verified NAN with P2P */ - /* (feature_set_full & WIFI_FEATURE_NAN) | */ - (feature_set_full & WIFI_FEATURE_P2P) | - (feature_set_full & WIFI_FEATURE_D2AP_RTT) | - (feature_set_full & WIFI_FEATURE_D2D_RTT) | - (feature_set_full & WIFI_FEATURE_EPR); - - ret[2] = (feature_set_full & WIFI_FEATURE_INFRA) | - (feature_set_full & WIFI_FEATURE_INFRA_5G) | - (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | - (feature_set_full & WIFI_FEATURE_NAN) | - (feature_set_full & WIFI_FEATURE_D2D_RTT) | - (feature_set_full & WIFI_FEATURE_D2AP_RTT) | - (feature_set_full & WIFI_FEATURE_TDLS) | - (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL) | - (feature_set_full & WIFI_FEATURE_EPR); - *num = MAX_FEATURE_SET_CONCURRRENT_GROUPS; - - return ret; -} - -#ifdef CUSTOM_FORCE_NODFS_FLAG -int -dhd_dev_set_nodfs(struct net_device *dev, u32 nodfs) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (nodfs) - dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; - else - dhd->pub.dhd_cflags &= ~WLAN_PLAT_NODFS_FLAG; - dhd->pub.force_country_change = TRUE; - return 0; -} -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - -#ifdef PNO_SUPPORT -/* Linux wrapper to call common dhd_pno_stop_for_ssid */ -int -dhd_dev_pno_stop_for_ssid(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_stop_for_ssid(&dhd->pub)); -} -/* Linux wrapper to call common dhd_pno_set_for_ssid */ -int -dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, - uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr, - pno_repeat, pno_freq_expo_max, channel_list, nchan)); -} - -/* Linux wrapper to call common dhd_pno_enable */ -int -dhd_dev_pno_enable(struct net_device *dev, int enable) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_enable(&dhd->pub, enable)); -} - -/* Linux wrapper to call common dhd_pno_set_for_hotlist */ -int -dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, - struct dhd_pno_hotlist_params *hotlist_params) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params)); -} -/* Linux wrapper to call common dhd_dev_pno_stop_for_batch */ -int -dhd_dev_pno_stop_for_batch(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_pno_stop_for_batch(&dhd->pub)); -} -/* Linux wrapper to call common dhd_dev_pno_set_for_batch */ -int -dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_pno_set_for_batch(&dhd->pub, batch_params)); -} -/* Linux wrapper to call common dhd_dev_pno_get_for_batch */ -int -dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL)); -} - -#endif /* PNO_SUPPORT */ - -#ifdef RSSI_MONITOR_SUPPORT -int -dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, - int8 max_rssi, int8 min_rssi) -{ - int err; - wl_rssi_monitor_cfg_t rssi_monitor; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - rssi_monitor.version = RSSI_MONITOR_VERSION; - rssi_monitor.max_rssi = max_rssi; - rssi_monitor.min_rssi = min_rssi; - rssi_monitor.flags = start ? 0: RSSI_MONITOR_STOP; - err = dhd_iovar(&dhd->pub, 0, "rssi_monitor", (char *)&rssi_monitor, sizeof(rssi_monitor), - NULL, 0, TRUE); - if (err < 0 && err != BCME_UNSUPPORTED) { - DHD_ERROR(("%s : Failed to execute rssi_monitor %d\n", __FUNCTION__, err)); - } - return err; -} -#endif /* RSSI_MONITOR_SUPPORT */ - -int -dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhdp = &dhd->pub; - - if (!dhdp || !oui) { - DHD_ERROR(("NULL POINTER : %s\n", - __FUNCTION__)); - return BCME_ERROR; - } - if (ETHER_ISMULTI(oui)) { - DHD_ERROR(("Expected unicast OUI\n")); - return BCME_ERROR; - } else { - uint8 *rand_mac_oui = dhdp->rand_mac_oui; - memcpy(rand_mac_oui, oui, DOT11_OUI_LEN); - DHD_ERROR(("Random MAC OUI to be used - %02x:%02x:%02x\n", rand_mac_oui[0], - rand_mac_oui[1], rand_mac_oui[2])); - } - return BCME_OK; -} - -int -dhd_set_rand_mac_oui(dhd_pub_t *dhd) -{ - int err; - wl_pfn_macaddr_cfg_t cfg; - uint8 *rand_mac_oui = dhd->rand_mac_oui; - - memset(&cfg.macaddr, 0, ETHER_ADDR_LEN); - memcpy(&cfg.macaddr, rand_mac_oui, DOT11_OUI_LEN); - cfg.version = WL_PFN_MACADDR_CFG_VER; - if (ETHER_ISNULLADDR(&cfg.macaddr)) - cfg.flags = 0; - else - cfg.flags = (WL_PFN_MAC_OUI_ONLY_MASK | WL_PFN_SET_MAC_UNASSOC_MASK); - - DHD_ERROR(("Setting rand mac oui to FW - %02x:%02x:%02x\n", rand_mac_oui[0], - rand_mac_oui[1], rand_mac_oui[2])); - - err = dhd_iovar(dhd, 0, "pfn_macaddr", (char *)&cfg, sizeof(cfg), NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_macaddr %d\n", __FUNCTION__, err)); - } - return err; -} - -#ifdef RTT_SUPPORT -/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ -int -dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_set_cfg(&dhd->pub, buf)); -} -int -dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_stop(&dhd->pub, mac_list, mac_cnt)); -} - -int -dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, dhd_rtt_compl_noti_fn noti_fn) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_register_noti_callback(&dhd->pub, ctx, noti_fn)); -} -int -dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_unregister_noti_callback(&dhd->pub, noti_fn)); -} - -int -dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_capability(&dhd->pub, capa)); -} -#endif /* RTT_SUPPORT */ - -#ifdef GSCAN_SUPPORT -/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ -int -dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, - void *buf, uint8 flush) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_set_cfg_gscan(&dhd->pub, type, buf, flush)); -} - -/* Linux wrapper to call common dhd_pno_get_gscan */ -void * -dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, - void *info, uint32 *len) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_get_gscan(&dhd->pub, type, info, len)); -} - -/* Linux wrapper to call common dhd_wait_batch_results_complete */ -int -dhd_dev_wait_batch_results_complete(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_wait_batch_results_complete(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_pno_lock_batch_results */ -int -dhd_dev_pno_lock_access_batch_results(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_lock_batch_results(&dhd->pub)); -} -/* Linux wrapper to call common dhd_pno_unlock_batch_results */ -void -dhd_dev_pno_unlock_access_batch_results(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_unlock_batch_results(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_pno_initiate_gscan_request */ -int -dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_initiate_gscan_request(&dhd->pub, run, flush)); -} - -/* Linux wrapper to call common dhd_pno_enable_full_scan_result */ -int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time_flag) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_enable_full_scan_result(&dhd->pub, real_time_flag)); -} - -/* Linux wrapper to call common dhd_handle_hotlist_scan_evt */ -void * dhd_dev_hotlist_scan_event(struct net_device *dev, - const void *data, int *send_evt_bytes, hotlist_type_t type) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_handle_hotlist_scan_evt(&dhd->pub, data, send_evt_bytes, type)); -} - -/* Linux wrapper to call common dhd_process_full_gscan_result */ -void * dhd_dev_process_full_gscan_result(struct net_device *dev, -const void *data, uint32 len, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_process_full_gscan_result(&dhd->pub, data, len, send_evt_bytes)); -} - -void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - dhd_gscan_hotlist_cache_cleanup(&dhd->pub, type); - - return; -} - -int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_gscan_batch_cache_cleanup(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_retreive_batch_scan_results */ -int dhd_dev_retrieve_batch_scan(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_retreive_batch_scan_results(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_pno_process_epno_result */ -void * dhd_dev_process_epno_result(struct net_device *dev, - const void *data, uint32 event, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_process_epno_result(&dhd->pub, data, event, send_evt_bytes)); -} - -int -dhd_dev_set_lazy_roam_cfg(struct net_device *dev, - wlc_roam_exp_params_t *roam_param) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - wl_roam_exp_cfg_t roam_exp_cfg; - int err; - - if (!roam_param) { - return BCME_BADARG; - } - - DHD_ERROR(("a_band_boost_thr %d a_band_penalty_thr %d\n", - roam_param->a_band_boost_threshold, roam_param->a_band_penalty_threshold)); - DHD_ERROR(("a_band_boost_factor %d a_band_penalty_factor %d cur_bssid_boost %d\n", - roam_param->a_band_boost_factor, roam_param->a_band_penalty_factor, - roam_param->cur_bssid_boost)); - DHD_ERROR(("alert_roam_trigger_thr %d a_band_max_boost %d\n", - roam_param->alert_roam_trigger_threshold, roam_param->a_band_max_boost)); - - memcpy(&roam_exp_cfg.params, roam_param, sizeof(*roam_param)); - roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; - roam_exp_cfg.flags = ROAM_EXP_CFG_PRESENT; - if (dhd->pub.lazy_roam_enable) { - roam_exp_cfg.flags |= ROAM_EXP_ENABLE_FLAG; - } - err = dhd_iovar(&dhd->pub, 0, "roam_exp_params", - (char *)&roam_exp_cfg, sizeof(roam_exp_cfg), NULL, 0, - TRUE); - if (err < 0) { - DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); - } - return err; -} - -int -dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - wl_roam_exp_cfg_t roam_exp_cfg; - - memset(&roam_exp_cfg, 0, sizeof(roam_exp_cfg)); - roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; - if (enable) { - roam_exp_cfg.flags = ROAM_EXP_ENABLE_FLAG; - } - - err = dhd_iovar(&dhd->pub, 0, "roam_exp_params", - (char *)&roam_exp_cfg, sizeof(roam_exp_cfg), NULL, 0, - TRUE); - if (err < 0) { - DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); - } else { - dhd->pub.lazy_roam_enable = (enable != 0); - } - return err; -} -int -dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, - wl_bssid_pref_cfg_t *bssid_pref, uint32 flush) -{ - int err; - int len; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - bssid_pref->version = BSSID_PREF_LIST_VERSION; - /* By default programming bssid pref flushes out old values */ - bssid_pref->flags = (flush && !bssid_pref->count) ? ROAM_EXP_CLEAR_BSSID_PREF: 0; - len = sizeof(wl_bssid_pref_cfg_t); - len += (bssid_pref->count - 1) * sizeof(wl_bssid_pref_list_t); - err = dhd_iovar(&dhd->pub, 0, "roam_exp_bssid_pref", - (char *)bssid_pref, len, NULL, 0, TRUE); - if (err != BCME_OK) { - DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); - } - return err; -} -int -dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, - uint32 len, uint32 flush) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int macmode; - - if (blacklist) { - err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACLIST, (char *)blacklist, - len, TRUE, 0); - if (err != BCME_OK) { - DHD_ERROR(("%s : WLC_SET_MACLIST failed %d\n", __FUNCTION__, err)); - return err; - } - } - /* By default programming blacklist flushes out old values */ - macmode = (flush && !blacklist) ? WLC_MACMODE_DISABLED : WLC_MACMODE_DENY; - err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACMODE, (char *)&macmode, - sizeof(macmode), TRUE, 0); - if (err != BCME_OK) { - DHD_ERROR(("%s : WLC_SET_MACMODE failed %d\n", __FUNCTION__, err)); - } - return err; -} -int -dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid_whitelist, - uint32 len, uint32 flush) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - wl_ssid_whitelist_t whitelist_ssid_flush; - - if (!ssid_whitelist) { - if (flush) { - ssid_whitelist = &whitelist_ssid_flush; - ssid_whitelist->ssid_count = 0; - } else { - DHD_ERROR(("%s : Nothing to do here\n", __FUNCTION__)); - return BCME_BADARG; - } - } - ssid_whitelist->version = SSID_WHITELIST_VERSION; - ssid_whitelist->flags = flush ? ROAM_EXP_CLEAR_SSID_WHITELIST : 0; - err = dhd_iovar(&dhd->pub, 0, "roam_exp_ssid_whitelist", (char *)ssid_whitelist, len, NULL, - 0, TRUE); - if (err != BCME_OK) { - DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); - } - return err; -} -#ifdef ANQPO_SUPPORT -void * dhd_dev_process_anqpo_result(struct net_device *dev, - const void *data, uint32 event, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_process_anqpo_result(&dhd->pub, data, event, send_evt_bytes)); -} -#endif /* ANQPO_SUPPORT */ -#endif /* GSCAN_SUPPORT */ - -bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_is_legacy_pno_enabled(&dhd->pub)); -} - -#if defined(KEEP_ALIVE) -#define TEMP_BUF_SIZE 512 -#define FRAME_SIZE 300 -int -dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, u16 ip_pkt_len, - u8* src_mac, u8* dst_mac, u32 period_msec) -{ - char *pbuf; - const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0}; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = BCME_ERROR; - int len_bytes = 0; - int i; - - /* ether frame to have both max IP pkt (256 bytes) and ether header */ - char *pmac_frame; - - /* - * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, - * dongle shall reject a mkeep_alive request. - */ - if (!dhd_support_sta_mode(dhd_pub)) - return res; - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - if ((pbuf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { - DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE)); - res = BCME_NOMEM; - return res; - } - - if ((pmac_frame = kzalloc(FRAME_SIZE, GFP_KERNEL)) == NULL) { - DHD_ERROR(("failed to allocate mac_frame with size %d\n", FRAME_SIZE)); - res = BCME_NOMEM; - goto exit; - } - - /* - * Get current mkeep-alive status. - */ - res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), - pbuf, TEMP_BUF_SIZE, FALSE); - - if (res < 0) { - DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); - goto exit; - } else { - /* Check available ID whether it is occupied */ - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; - if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { - DHD_ERROR(("%s: Get mkeep_alive failed, ID %u is in use.\n", - __FUNCTION__, mkeep_alive_id)); - - /* Current occupied ID info */ - DHD_ERROR(("%s: mkeep_alive\n", __FUNCTION__)); - DHD_ERROR((" Id : %d\n" - " Period: %d msec\n" - " Length: %d\n" - " Packet: 0x", - mkeep_alive_pktp->keep_alive_id, - dtoh32(mkeep_alive_pktp->period_msec), - dtoh16(mkeep_alive_pktp->len_bytes))); - - for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { - DHD_ERROR(("%02x", mkeep_alive_pktp->data[i])); - } - DHD_ERROR(("\n")); - - res = BCME_NOTFOUND; - goto exit; - } - } - - /* Request the specified ID */ - memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - memset(pbuf, 0, TEMP_BUF_SIZE); - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(pbuf, str, str_len); - pbuf[str_len] = '\0'; - - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1); - mkeep_alive_pkt.period_msec = htod32(period_msec); - buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - - /* ID assigned */ - mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; - - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - - /* - * Build up Ethernet Frame - */ - - /* Mapping dest mac addr */ - memcpy(pmac_frame, dst_mac, ETHER_ADDR_LEN); - pmac_frame += ETHER_ADDR_LEN; - - /* Mapping src mac addr */ - memcpy(pmac_frame, src_mac, ETHER_ADDR_LEN); - pmac_frame += ETHER_ADDR_LEN; - - /* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */ - *(pmac_frame++) = 0x08; - *(pmac_frame++) = 0x00; - - /* Mapping IP pkt */ - memcpy(pmac_frame, ip_pkt, ip_pkt_len); - pmac_frame += ip_pkt_len; - - /* - * Length of ether frame (assume to be all hexa bytes) - * = src mac + dst mac + ether type + ip pkt len - */ - len_bytes = ETHER_ADDR_LEN*2 + ETHER_TYPE_LEN + ip_pkt_len; - /* Get back to the beginning. */ - pmac_frame -= len_bytes; - memcpy(mkeep_alive_pktp->data, pmac_frame, len_bytes); - buf_len += len_bytes; - mkeep_alive_pkt.len_bytes = htod16(len_bytes); - - /* - * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0); -exit: - kfree(pmac_frame); - kfree(pbuf); - return res; -} - -int -dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id) -{ - char *pbuf; - wl_mkeep_alive_pkt_t mkeep_alive_pkt; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int res = BCME_ERROR; - int i; - - /* - * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, - * dongle shall reject a mkeep_alive request. - */ - if (!dhd_support_sta_mode(dhd_pub)) - return res; - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - /* - * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt. - */ - if ((pbuf = kmalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { - DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE)); - return res; - } - - res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, - sizeof(mkeep_alive_id), pbuf, TEMP_BUF_SIZE, FALSE); - - if (res < 0) { - DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); - goto exit; - } else { - /* Check occupied ID */ - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; - DHD_INFO(("%s: mkeep_alive\n", __FUNCTION__)); - DHD_INFO((" Id : %d\n" - " Period: %d msec\n" - " Length: %d\n" - " Packet: 0x", - mkeep_alive_pktp->keep_alive_id, - dtoh32(mkeep_alive_pktp->period_msec), - dtoh16(mkeep_alive_pktp->len_bytes))); - - for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { - DHD_INFO(("%02x", mkeep_alive_pktp->data[i])); - } - DHD_INFO(("\n")); - } - - /* Make it stop if available */ - if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { - DHD_INFO(("stop mkeep_alive on ID %d\n", mkeep_alive_id)); - memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - mkeep_alive_pkt.period_msec = 0; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; - - res = dhd_iovar(dhd_pub, 0, "mkeep_alive", - (char *)&mkeep_alive_pkt, - WL_MKEEP_ALIVE_FIXED_LEN, NULL, 0, TRUE); - } else { - DHD_ERROR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id)); - res = BCME_NOTFOUND; - } -exit: - kfree(pbuf); - return res; -} -#endif /* defined(KEEP_ALIVE) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -static void dhd_hang_process(void *dhd_info, void *event_info, u8 event) -{ - dhd_info_t *dhd; - struct net_device *dev; - - dhd = (dhd_info_t *)dhd_info; - dev = dhd->iflist[0]->net; - - if (dev) { - rtnl_lock(); - dev_close(dev); - rtnl_unlock(); -#if defined(WL_WIRELESS_EXT) - wl_iw_send_priv_event(dev, "HANG"); -#endif -#if defined(WL_CFG80211) - wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -#endif - } -} - -int dhd_os_send_hang_message(dhd_pub_t *dhdp) -{ - int ret = 0; - if (dhdp) { - if (!dhdp->hang_was_sent) { - dhdp->hang_was_sent = 1; - dhd_deferred_schedule_work((void *)dhdp, DHD_WQ_WORK_HANG_MSG, - dhd_hang_process, DHD_WORK_PRIORITY_HIGH); - } - } - return ret; -} - -int net_os_send_hang_message(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) { - /* Report FW problem when enabled */ - if (dhd->pub.hang_report) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - ret = dhd_os_send_hang_message(&dhd->pub); -#else - ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -#endif - } else { - DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n", - __FUNCTION__)); - /* Enforce bus down to stop any future traffic */ - dhd->pub.busstate = DHD_BUS_DOWN; - } - } - return ret; -} -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ - - -int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return wifi_platform_set_power(dhd->adapter, on, delay_msec); -} - -void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, - wl_country_t *cspec) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -#ifdef CUSTOM_FORCE_NODFS_FLAG - get_customized_country_code(dhd->adapter, country_iso_code, cspec, - dhd->pub.dhd_cflags); -#else - get_customized_country_code(dhd->adapter, country_iso_code, cspec); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -} -void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - if (dhd && dhd->pub.up) { - memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); -#ifdef WL_CFG80211 - wl_update_wiphybands(NULL, notify); -#endif - } -} - -void dhd_bus_band_set(struct net_device *dev, uint band) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - if (dhd && dhd->pub.up) { -#ifdef WL_CFG80211 - wl_update_wiphybands(NULL, true); -#endif - } -} - -int dhd_net_set_fw_path(struct net_device *dev, char *fw) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (!fw || fw[0] == '\0') - return -EINVAL; - - strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1); - dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0'; - -#if defined(SOFTAP) - if (strstr(fw, "apsta") != NULL) { - DHD_INFO(("GOT APSTA FIRMWARE\n")); - ap_fw_loaded = TRUE; - } else { - DHD_INFO(("GOT STA FIRMWARE\n")); - ap_fw_loaded = FALSE; - } -#endif - return 0; -} - -void dhd_net_if_lock(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_net_if_lock_local(dhd); -} - -void dhd_net_if_unlock(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_net_if_unlock_local(dhd); -} - -static void dhd_net_if_lock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (dhd) - mutex_lock(&dhd->dhd_net_if_mutex); -#endif -} - -static void dhd_net_if_unlock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (dhd) - mutex_unlock(&dhd->dhd_net_if_mutex); -#endif -} - -static void dhd_suspend_lock(dhd_pub_t *pub) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - if (dhd) - mutex_lock(&dhd->dhd_suspend_mutex); -#endif -} - -static void dhd_suspend_unlock(dhd_pub_t *pub) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - if (dhd) - mutex_unlock(&dhd->dhd_suspend_mutex); -#endif -} - -unsigned long dhd_os_spin_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags = 0; - - if (dhd) - spin_lock_irqsave(&dhd->dhd_lock, flags); - - return flags; -} - -void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) - spin_unlock_irqrestore(&dhd->dhd_lock, flags); -} - -static int -dhd_get_pend_8021x_cnt(dhd_info_t *dhd) -{ - return (atomic_read(&dhd->pend_8021x_cnt)); -} - -#define MAX_WAIT_FOR_8021X_TX 50 - -int -dhd_wait_pend8021x(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int timeout = msecs_to_jiffies(10); - int ntimes = MAX_WAIT_FOR_8021X_TX; - int pend = dhd_get_pend_8021x_cnt(dhd); - - while (ntimes && pend) { - if (pend) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(timeout); - set_current_state(TASK_RUNNING); - ntimes--; - } - pend = dhd_get_pend_8021x_cnt(dhd); - } - if (ntimes == 0) - { - atomic_set(&dhd->pend_8021x_cnt, 0); - DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__)); - } - return pend; -} - -#ifdef DHD_DEBUG -int -write_to_file(dhd_pub_t *dhd, uint8 *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("/data/mem_dump", O_WRONLY|O_CREAT, 0640); - - if (IS_ERR(fp)) { - fp = NULL; - printf("%s: open file error\n", __FUNCTION__); - ret = -1; - goto exit; - } - - /* Write buf to file */ - fp->f_op->write(fp, buf, size, &pos); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) - fp->f_op->fsync(fp, 0, size-1, 1); -#else - fp->f_op->fsync(fp, 1); -#endif /* KERNEL_VERSION(3, 1, 0) */ - -exit: - /* free buf before return */ - if (buf) { - MFREE(dhd->osh, buf, size); - } - /* close file before return */ - if (fp) - filp_close(fp, current->files); - /* restore previous address limit */ - set_fs(old_fs); - - return ret; -} - -static void dhd_join_timeout(ulong data) -{ - dhd_info_t *dhd = (dhd_info_t *)data; - if (dhd->join_timer_active) - DHD_ERROR(("DHD: %s: JOIN TIMEOUT\n", - __FUNCTION__)); -} - -int dhd_start_join_timer(dhd_pub_t *pub) -{ - int ret; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - DHD_INFO(("DHD: Join Timer Started:%s:\n", __FUNCTION__)); - if (!dhd->join_timeout_val) - dhd->join_timeout_val = DHD_JOIN_MAX_TIME_DEFAULT; - init_timer(&dhd->join_timer); - dhd->join_timer.data = (ulong)dhd; - dhd->join_timer.function = dhd_join_timeout; - dhd->join_timer_active = TRUE; - ret = mod_timer(&dhd->join_timer, jiffies + msecs_to_jiffies(dhd->join_timeout_val)); - return ret; -} -int dhd_del_join_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - if (dhd->join_timer_active) { - ret = del_timer(&dhd->join_timer); - DHD_INFO(("DHD: Join Timer Stopped:%s:\n", __FUNCTION__)); - } - return ret; -} -int dhd_set_join_timeout(dhd_pub_t *pub, uint32 timeout) -{ - int ret = BCME_OK; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - if (timeout) { - dhd->join_timeout_val = timeout; - return ret; - } - DHD_ERROR(("DHD: Join Timer Can not be zero:%s:\n", __FUNCTION__)); - return BCME_ERROR; -} -uint32 dhd_get_join_timeout(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)pub->info; - return dhd->join_timeout_val; -} - -static void dhd_scan_timeout(ulong data) -{ - dhd_info_t *dhd = (dhd_info_t *)data; - if (dhd->scan_timer_active) { - DHD_ERROR(("DHD: %s: SCAN TIMEOUT\n", - __FUNCTION__)); - } -} -int dhd_add_scan_timer(dhd_pub_t *pub) -{ - int ret; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - DHD_ERROR(("DHD: Scan Timer Started:%s:\n", __FUNCTION__)); - if (!dhd->scan_time_count) - dhd->scan_time_count = DHD_SCAN_DEF_TIMEOUT; - init_timer(&dhd->scan_timer); - dhd->scan_timer.data = (ulong)dhd; - dhd->scan_timer.function = dhd_scan_timeout; - dhd->scan_timer_active = TRUE; - ret = mod_timer(&dhd->scan_timer, jiffies + msecs_to_jiffies(dhd->scan_time_count)); - return ret; -} -int dhd_del_scan_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - if (dhd->scan_timer_active) { - ret = del_timer(&dhd->scan_timer); - DHD_INFO(("DHD: Scan Timer Stopped:%s:\n", __FUNCTION__)); - } - return ret; -} - -int dhd_set_scan_timeout(dhd_pub_t *pub, uint32 timeout) -{ - int ret = BCME_OK; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - if (timeout) { - dhd->scan_time_count = timeout; - return ret; - } - DHD_ERROR(("DHD: Scan Timer Can not be zero:%s:\n", __FUNCTION__)); - return BCME_ERROR; -} -uint32 dhd_get_scan_timeout(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)pub->info; - return dhd->scan_time_count; -} -#endif /* DHD_DEBUG */ - -int dhd_os_wake_lock_timeout(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? - dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; -#ifdef CONFIG_HAS_WAKELOCK - if (dhd->wakelock_rx_timeout_enable) - wake_lock_timeout(&dhd->wl_rxwake, - msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); - if (dhd->wakelock_ctrl_timeout_enable) - wake_lock_timeout(&dhd->wl_ctrlwake, - msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); -#endif - dhd->wakelock_rx_timeout_enable = 0; - dhd->wakelock_ctrl_timeout_enable = 0; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int net_os_wake_lock_timeout(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_timeout(&dhd->pub); - return ret; -} - -int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_rx_timeout_enable) - dhd->wakelock_rx_timeout_enable = val; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_ctrl_timeout_enable) - dhd->wakelock_ctrl_timeout_enable = val; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - dhd->wakelock_ctrl_timeout_enable = 0; -#ifdef CONFIG_HAS_WAKELOCK - if (wake_lock_active(&dhd->wl_ctrlwake)) - wake_unlock(&dhd->wl_ctrlwake); -#endif - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); - return ret; -} - -int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); - return ret; -} - -int dhd_os_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { -#ifdef CONFIG_HAS_WAKELOCK - wake_lock(&dhd->wl_wifi); -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_stay_awake(pub); -#endif - } - dhd->wakelock_counter++; - ret = dhd->wakelock_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int net_os_wake_lock(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock(&dhd->pub); - return ret; -} - -int dhd_os_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - dhd_os_wake_lock_timeout(pub); - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (dhd->wakelock_counter > 0) { - dhd->wakelock_counter--; - if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_wifi); -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_relax(pub); -#endif - } - ret = dhd->wakelock_counter; - } - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int dhd_os_check_wakelock(dhd_pub_t *pub) -{ -#if defined(CONFIG_HAS_WAKELOCK) || (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_info_t *dhd; - - if (!pub) - return 0; - dhd = (dhd_info_t *)(pub->info); -#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ - -#ifdef CONFIG_HAS_WAKELOCK - /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ - if (dhd && (wake_lock_active(&dhd->wl_wifi) || - (wake_lock_active(&dhd->wl_wdwake)))) - return 1; -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) - return 1; -#endif - return 0; -} -int net_os_wake_unlock(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_unlock(&dhd->pub); - return ret; -} - -int dhd_os_wd_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (dhd->wakelock_wd_counter == 0 && !dhd->waive_wakelock) { -#ifdef CONFIG_HAS_WAKELOCK - /* if wakelock_wd_counter was never used : lock it at once */ - wake_lock(&dhd->wl_wdwake); -#endif - } - dhd->wakelock_wd_counter++; - ret = dhd->wakelock_wd_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int dhd_os_wd_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (dhd->wakelock_wd_counter > 0) { - dhd->wakelock_wd_counter = 0; - if (!dhd->waive_wakelock) { -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_wdwake); -#endif - } - } - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -#ifdef PROP_TXSTATUS -/* waive wakelocks for operations such as IOVARs in suspend function, must be closed - * by a paired function call to dhd_wakelock_restore. returns current wakelock counter - */ -int dhd_wakelock_waive(dhd_info_t *dhdinfo) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&dhdinfo->wakelock_spinlock, flags); - /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ - if (dhdinfo->waive_wakelock) - goto exit; - /* record current lock status */ - dhdinfo->wakelock_before_waive = dhdinfo->wakelock_counter; - dhdinfo->waive_wakelock = TRUE; - -exit: - ret = dhdinfo->wakelock_wd_counter; - spin_unlock_irqrestore(&dhdinfo->wakelock_spinlock, flags); - return ret; -} - -int dhd_wakelock_restore(dhd_info_t *dhdinfo) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&dhdinfo->wakelock_spinlock, flags); - /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ - if (!dhdinfo->waive_wakelock) - goto exit; - - dhdinfo->waive_wakelock = FALSE; - /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore, - * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases - * the lock in between, do the same by calling wake_unlock or pm_relax - */ - if (dhdinfo->wakelock_before_waive == 0 && dhdinfo->wakelock_counter > 0) { -#ifdef CONFIG_HAS_WAKELOCK - wake_lock(&dhdinfo->wl_wifi); -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_stay_awake(&dhdinfo->pub); -#endif - } else if (dhdinfo->wakelock_before_waive > 0 && dhdinfo->wakelock_counter == 0) { -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhdinfo->wl_wifi); -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_relax(&dhdinfo->pub); -#endif - } - dhdinfo->wakelock_before_waive = 0; -exit: - ret = dhdinfo->wakelock_wd_counter; - spin_unlock_irqrestore(&dhdinfo->wakelock_spinlock, flags); - return ret; -} -#endif /* PROP_TXSTATUS */ - -bool dhd_os_check_if_up(dhd_pub_t *pub) -{ - if (!pub) - return FALSE; - return pub->up; -} - -/* function to collect firmware, chip id and chip version info */ -void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) -{ - int i; - - i = snprintf(info_string, sizeof(info_string), - " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); - - if (!dhdp) - return; - - i = snprintf(&info_string[i], sizeof(info_string) - i, - "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), - dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); -} -int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) -{ - int ifidx; - int ret = 0; - dhd_info_t *dhd = NULL; - - if (!net || !netdev_priv(net)) { - DHD_ERROR(("%s invalid parameter\n", __FUNCTION__)); - return -EINVAL; - } - - dhd = *(dhd_info_t **)netdev_priv(net); - if (!dhd) - return -EINVAL; - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - DHD_OS_WAKE_LOCK(&dhd->pub); - ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); - dhd_check_hang(net, &dhd->pub, ret); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - return ret; -} - -bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) -{ - struct net_device *net; - - net = dhd_idx2net(dhdp, ifidx); - if (!net) { - DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx)); - return -EINVAL; - } - - return dhd_check_hang(net, dhdp, ret); -} - - -#ifdef PROP_TXSTATUS - -void dhd_wlfc_plat_init(void *dhd) -{ - return; -} - -void dhd_wlfc_plat_deinit(void *dhd) -{ - return; -} - -bool dhd_wlfc_skip_fc(void) -{ - return FALSE; -} -#endif /* PROP_TXSTATUS */ - -#ifdef BCMDBGFS - -#include - -extern uint32 dhd_readregl(void *bp, uint32 addr); -extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); - -typedef struct dhd_dbgfs { - struct dentry *debugfs_dir; - struct dentry *debugfs_mem; - dhd_pub_t *dhdp; - uint32 size; -} dhd_dbgfs_t; - -dhd_dbgfs_t g_dbgfs; - -static int -dhd_dbg_state_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t -dhd_dbg_state_read(struct file *file, char __user *ubuf, - size_t count, loff_t *ppos) -{ - ssize_t rval; - uint32 tmp; - loff_t pos = *ppos; - size_t ret; - - if (pos < 0) - return -EINVAL; - if (pos >= g_dbgfs.size || !count) - return 0; - if (count > g_dbgfs.size - pos) - count = g_dbgfs.size - pos; - - /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ - tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); - - ret = copy_to_user(ubuf, &tmp, 4); - if (ret == count) - return -EFAULT; - - count -= ret; - *ppos = pos + count; - rval = count; - - return rval; -} - - -static ssize_t -dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) -{ - loff_t pos = *ppos; - size_t ret; - uint32 buf; - - if (pos < 0) - return -EINVAL; - if (pos >= g_dbgfs.size || !count) - return 0; - if (count > g_dbgfs.size - pos) - count = g_dbgfs.size - pos; - - ret = copy_from_user(&buf, ubuf, sizeof(uint32)); - if (ret == count) - return -EFAULT; - - /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ - dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); - - return count; -} - - -loff_t -dhd_debugfs_lseek(struct file *file, loff_t off, int whence) -{ - loff_t pos = -1; - - switch (whence) { - case 0: - pos = off; - break; - case 1: - pos = file->f_pos + off; - break; - case 2: - pos = g_dbgfs.size - off; - } - return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); -} - -static const struct file_operations dhd_dbg_state_ops = { - .read = dhd_dbg_state_read, - .write = dhd_debugfs_write, - .open = dhd_dbg_state_open, - .llseek = dhd_debugfs_lseek -}; - -static void dhd_dbg_create(void) -{ - if (g_dbgfs.debugfs_dir) { - g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, - NULL, &dhd_dbg_state_ops); - } -} - -void dhd_dbg_init(dhd_pub_t *dhdp) -{ - int err; - - g_dbgfs.dhdp = dhdp; - g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ - - g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); - if (IS_ERR(g_dbgfs.debugfs_dir)) { - err = PTR_ERR(g_dbgfs.debugfs_dir); - g_dbgfs.debugfs_dir = NULL; - return; - } - - dhd_dbg_create(); - - return; -} - -void dhd_dbg_remove(void) -{ - debugfs_remove(g_dbgfs.debugfs_mem); - debugfs_remove(g_dbgfs.debugfs_dir); - - bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); - -} -#endif /* ifdef BCMDBGFS */ - -#ifdef WLMEDIA_HTSF - -static -void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct sk_buff *skb; - uint32 htsf = 0; - uint16 dport = 0, oldmagic = 0xACAC; - char *p1; - htsfts_t ts; - - /* timestamp packet */ - - p1 = (char*) PKTDATA(dhdp->osh, pktbuf); - - if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { -/* memcpy(&proto, p1+26, 4); */ - memcpy(&dport, p1+40, 2); -/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ - dport = ntoh16(dport); - } - - /* timestamp only if icmp or udb iperf with port 5555 */ -/* if (proto == 17 && dport == tsport) { */ - if (dport >= tsport && dport <= tsport + 20) { - - skb = (struct sk_buff *) pktbuf; - - htsf = dhd_get_htsf(dhd, 0); - memset(skb->data + 44, 0, 2); /* clear checksum */ - memcpy(skb->data+82, &oldmagic, 2); - memcpy(skb->data+84, &htsf, 4); - - memset(&ts, 0, sizeof(htsfts_t)); - ts.magic = HTSFMAGIC; - ts.prio = PKTPRIO(pktbuf); - ts.seqnum = htsf_seqnum++; - ts.c10 = get_cycles(); - ts.t10 = htsf; - ts.endmagic = HTSFENDMAGIC; - - memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); - } -} - -static void dhd_dump_htsfhisto(histo_t *his, char *s) -{ - int pktcnt = 0, curval = 0, i; - for (i = 0; i < (NUMBIN-2); i++) { - curval += 500; - printf("%d ", his->bin[i]); - pktcnt += his->bin[i]; - } - printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, - his->bin[NUMBIN-1], s); -} - -static -void sorttobin(int value, histo_t *histo) -{ - int i, binval = 0; - - if (value < 0) { - histo->bin[NUMBIN-1]++; - return; - } - if (value > histo->bin[NUMBIN-2]) /* store the max value */ - histo->bin[NUMBIN-2] = value; - - for (i = 0; i < (NUMBIN-2); i++) { - binval += 500; /* 500m s bins */ - if (value <= binval) { - histo->bin[i]++; - return; - } - } - histo->bin[NUMBIN-3]++; -} - -static -void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - char *p1; - uint16 old_magic; - int d1, d2, d3, end2end; - htsfts_t *htsf_ts; - uint32 htsf; - - skb = PKTTONATIVE(dhdp->osh, pktbuf); - p1 = (char*)PKTDATA(dhdp->osh, pktbuf); - - if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { - memcpy(&old_magic, p1+78, 2); - htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); - } - else - return; - - if (htsf_ts->magic == HTSFMAGIC) { - htsf_ts->tE0 = dhd_get_htsf(dhd, 0); - htsf_ts->cE0 = get_cycles(); - } - - if (old_magic == 0xACAC) { - - tspktcnt++; - htsf = dhd_get_htsf(dhd, 0); - memcpy(skb->data+92, &htsf, sizeof(uint32)); - - memcpy(&ts[tsidx].t1, skb->data+80, 16); - - d1 = ts[tsidx].t2 - ts[tsidx].t1; - d2 = ts[tsidx].t3 - ts[tsidx].t2; - d3 = ts[tsidx].t4 - ts[tsidx].t3; - end2end = ts[tsidx].t4 - ts[tsidx].t1; - - sorttobin(d1, &vi_d1); - sorttobin(d2, &vi_d2); - sorttobin(d3, &vi_d3); - sorttobin(end2end, &vi_d4); - - if (end2end > 0 && end2end > maxdelay) { - maxdelay = end2end; - maxdelaypktno = tspktcnt; - memcpy(&maxdelayts, &ts[tsidx], 16); - } - if (++tsidx >= TSMAX) - tsidx = 0; - } -} - -uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) -{ - uint32 htsf = 0, cur_cycle, delta, delta_us; - uint32 factor, baseval, baseval2; - cycles_t t; - - t = get_cycles(); - cur_cycle = t; - - if (cur_cycle > dhd->htsf.last_cycle) - delta = cur_cycle - dhd->htsf.last_cycle; - else { - delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); - } - - delta = delta >> 4; - - if (dhd->htsf.coef) { - /* times ten to get the first digit */ - factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); - baseval = (delta*10)/factor; - baseval2 = (delta*10)/(factor+1); - delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); - htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; - } - else { - DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n")); - } - - return htsf; -} - -static void dhd_dump_latency(void) -{ - int i, max = 0; - int d1, d2, d3, d4, d5; - - printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); - for (i = 0; i < TSMAX; i++) { - d1 = ts[i].t2 - ts[i].t1; - d2 = ts[i].t3 - ts[i].t2; - d3 = ts[i].t4 - ts[i].t3; - d4 = ts[i].t4 - ts[i].t1; - d5 = ts[max].t4-ts[max].t1; - if (d4 > d5 && d4 > 0) { - max = i; - } - printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", - ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, - d1, d2, d3, d4, i); - } - - printf("current idx = %d \n", tsidx); - - printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); - printf("%08X %08X %08X %08X \t%d %d %d %d\n", - maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, - maxdelayts.t2 - maxdelayts.t1, - maxdelayts.t3 - maxdelayts.t2, - maxdelayts.t4 - maxdelayts.t3, - maxdelayts.t4 - maxdelayts.t1); -} - - -static int -dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) -{ - char buf[32]; - int ret; - uint32 s1, s2; - - struct tsf { - uint32 low; - uint32 high; - } tsf_buf; - - memset(&tsf_buf, 0, sizeof(tsf_buf)); - - s1 = dhd_get_htsf(dhd, 0); - ret = dhd_iovar(&dhd->pub, ifidx, "tsf", NULL, 0, buf, sizeof(buf), FALSE); - if (ret < 0) { - if (ret == -EIO) { - DHD_ERROR(("%s: tsf is not supported by device\n", - dhd_ifname(&dhd->pub, ifidx))); - return -EOPNOTSUPP; - } - return ret; - } - s2 = dhd_get_htsf(dhd, 0); - - memcpy(&tsf_buf, buf, sizeof(tsf_buf)); - printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", - tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, - dhd->htsf.coefdec2, s2-tsf_buf.low); - printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); - return 0; -} - -void htsf_update(dhd_info_t *dhd, void *data) -{ - static ulong cur_cycle = 0, prev_cycle = 0; - uint32 htsf, tsf_delta = 0; - uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; - ulong b, a; - cycles_t t; - - /* cycles_t in inlcude/mips/timex.h */ - - t = get_cycles(); - - prev_cycle = cur_cycle; - cur_cycle = t; - - if (cur_cycle > prev_cycle) - cyc_delta = cur_cycle - prev_cycle; - else { - b = cur_cycle; - a = prev_cycle; - cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); - } - - if (data == NULL) - printf(" tsf update ata point er is null \n"); - - memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); - memcpy(&cur_tsf, data, sizeof(tsf_t)); - - if (cur_tsf.low == 0) { - DHD_INFO((" ---- 0 TSF, do not update, return\n")); - return; - } - - if (cur_tsf.low > prev_tsf.low) - tsf_delta = (cur_tsf.low - prev_tsf.low); - else { - DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", - cur_tsf.low, prev_tsf.low)); - if (cur_tsf.high > prev_tsf.high) { - tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); - DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta)); - } - else - return; /* do not update */ - } - - if (tsf_delta) { - hfactor = cyc_delta / tsf_delta; - tmp = (cyc_delta - (hfactor * tsf_delta))*10; - dec1 = tmp/tsf_delta; - dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; - tmp = (tmp - (dec1*tsf_delta))*10; - dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; - - if (dec3 > 4) { - if (dec2 == 9) { - dec2 = 0; - if (dec1 == 9) { - dec1 = 0; - hfactor++; - } - else { - dec1++; - } - } - else - dec2++; - } - } - - if (hfactor) { - htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; - dhd->htsf.coef = hfactor; - dhd->htsf.last_cycle = cur_cycle; - dhd->htsf.last_tsf = cur_tsf.low; - dhd->htsf.coefdec1 = dec1; - dhd->htsf.coefdec2 = dec2; - } - else { - htsf = prev_tsf.low; - } -} - -#endif /* WLMEDIA_HTSF */ - - -#ifdef CUSTOMER_HW5 -bool dhd_is_p2p_connection(struct net_device *ndev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(ndev); - - if (dhd->pub.op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE)) { - return TRUE; - } - return FALSE; -} -#endif /* CUSTOMER_HW5 */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h deleted file mode 100755 index e97929afe083..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * DHD Linux header file (dhd_linux exports for cfg80211 and other components) - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux.h 399301 2013-04-29 21:41:52Z $ - */ - -/* wifi platform functions for power, interrupt and pre-alloc, either - * from Android-like platform device data, or Broadcom wifi platform - * device data. - * - */ -#ifndef __DHD_LINUX_H__ -#define __DHD_LINUX_H__ - -#include -#include -#include -#include - -#if defined(CONFIG_WIFI_CONTROL_FUNC) -#include -#endif -#ifdef CUSTOM_FORCE_NODFS_FLAG -#define WLAN_PLAT_NODFS_FLAG 0x01 -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -#if !defined(CONFIG_WIFI_CONTROL_FUNC) -struct wifi_platform_data { - int (*set_power)(int val); - int (*set_reset)(int val); - int (*set_carddetect)(int val); - void *(*mem_prealloc)(int section, unsigned long size); - int (*get_mac_addr)(unsigned char *buf); -#ifdef CUSTOM_FORCE_NODFS_FLAG - void *(*get_country_code)(char *ccode, u32 flags); -#else - void *(*get_country_code)(char *ccode); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -}; -#endif /* CONFIG_WIFI_CONTROL_FUNC */ - -#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ - -typedef struct wifi_adapter_info { - const char *name; - uint irq_num; - uint intr_flags; - const char *fw_path; - const char *nv_path; - void *wifi_plat_data; /* wifi ctrl func, for backward compatibility */ - uint bus_type; - uint bus_num; - uint slot_num; -} wifi_adapter_info_t; - -typedef struct bcmdhd_wifi_platdata { - uint num_adapters; - wifi_adapter_info_t *adapters; -} bcmdhd_wifi_platdata_t; - -int dhd_wifi_platform_register_drv(void); -void dhd_wifi_platform_unregister_drv(void); -wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, - uint32 slot_num); -int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec); -int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present); -int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr); -int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf); -#ifdef CUSTOM_FORCE_NODFS_FLAG -void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags); -#else -void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size); -void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter); - -int dhd_get_fw_mode(struct dhd_info *dhdinfo); -bool dhd_update_fw_nv_path(struct dhd_info *dhdinfo); - -#endif /* __DHD_LINUX_H__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c deleted file mode 100755 index 3dca697c1f17..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c +++ /dev/null @@ -1,758 +0,0 @@ -/* - * Linux platform device for DHD WLAN adapter - * - * Copyright (C) 1999-2018, Broadcom Corporation - * Copyright (C) 2013 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux_platdev.c 401742 2013-05-13 15:03:21Z $ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_WIFI_CONTROL_FUNC) -#include -#endif -#ifdef CONFIG_DTS -#include -#include -#endif /* CONFIG_DTS */ -#ifdef CONFIG_SOMC_WIFI_CONTROL -#include -#endif /* CONFIG_SOMC_WIFI_CONTROL */ - -#define WIFI_PLAT_NAME "bcmdhd_wlan" -#define WIFI_PLAT_NAME2 "bcm4329_wlan" -#define WIFI_PLAT_EXT "bcmdhd_wifi_platform" - -#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) -struct regulator *wifi_regulator = NULL; -#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ - -bool cfg_multichip = FALSE; -bcmdhd_wifi_platdata_t *dhd_wifi_platdata = NULL; -static int wifi_plat_dev_probe_ret = 0; -static bool is_power_on = FALSE; -#if !defined(CONFIG_DTS) -#if defined(DHD_OF_SUPPORT) -static bool dts_enabled = TRUE; -extern struct resource dhd_wlan_resources; -extern struct wifi_platform_data dhd_wlan_control; -#else -static bool dts_enabled = FALSE; -struct resource dhd_wlan_resources = {0}; -struct wifi_platform_data dhd_wlan_control = {0}; -#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */ -#endif /* !defind(CONFIG_DTS) */ - -static int dhd_wifi_platform_load(void); - -extern void* wl_cfg80211_get_dhdp(void); - -#ifdef ENABLE_4335BT_WAR -extern int bcm_bt_lock(int cookie); -extern void bcm_bt_unlock(int cookie); -static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ -#endif /* ENABLE_4335BT_WAR */ - -wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num) -{ - int i; - - if (dhd_wifi_platdata == NULL) - return NULL; - - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; - if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && - (adapter->bus_num == -1 || adapter->bus_num == bus_num) && - (adapter->slot_num == -1 || adapter->slot_num == slot_num)) { - DHD_TRACE(("found adapter info '%s'\n", adapter->name)); - return adapter; - } - } - return NULL; -} - -void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size) -{ - void *alloc_ptr = NULL; - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return NULL; - plat_data = adapter->wifi_plat_data; - if (plat_data->mem_prealloc) { - alloc_ptr = plat_data->mem_prealloc(section, size); - if (alloc_ptr) { - DHD_INFO(("success alloc section %d\n", section)); - if (size != 0L) - bzero(alloc_ptr, size); - return alloc_ptr; - } - } - - DHD_ERROR(("%s: failed to alloc static mem section %d\n", __FUNCTION__, section)); - return NULL; -} - -void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter) -{ - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return NULL; - plat_data = adapter->wifi_plat_data; - return plat_data->mem_prealloc; -} - -int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr) -{ - if (adapter == NULL) - return -1; - if (irq_flags_ptr) - *irq_flags_ptr = adapter->intr_flags; - return adapter->irq_num; -} - -int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec) -{ - int err = 0; -#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) - if (on) { - err = regulator_enable(wifi_regulator); - is_power_on = TRUE; - } - else { - err = regulator_disable(wifi_regulator); - is_power_on = FALSE; - } - if (err < 0) - DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__)); -#else - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return -EINVAL; - plat_data = adapter->wifi_plat_data; - - DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); - if (plat_data->set_power) { -#ifdef ENABLE_4335BT_WAR - if (on) { - printk("WiFi: trying to acquire BT lock\n"); - if (bcm_bt_lock(lock_cookie_wifi) != 0) - printk("** WiFi: timeout in acquiring bt lock**\n"); - printk("%s: btlock acquired\n", __FUNCTION__); - } - else { - /* For a exceptional case, release btlock */ - bcm_bt_unlock(lock_cookie_wifi); - } -#endif /* ENABLE_4335BT_WAR */ - - err = plat_data->set_power(on); - } - - if (msec && !err) - OSL_SLEEP(msec); - - if (on && !err) - is_power_on = TRUE; - else - is_power_on = FALSE; - -#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ - - return err; -} - -int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present) -{ - int err = 0; - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return -EINVAL; - plat_data = adapter->wifi_plat_data; - - DHD_ERROR(("%s device present %d\n", __FUNCTION__, device_present)); - if (plat_data->set_carddetect) { - err = plat_data->set_carddetect(device_present); - } - return err; - -} - -int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf) -{ - struct wifi_platform_data *plat_data; - - DHD_ERROR(("%s\n", __FUNCTION__)); - if (!buf || !adapter || !adapter->wifi_plat_data) - return -EINVAL; - plat_data = adapter->wifi_plat_data; - if (plat_data->get_mac_addr) { - return plat_data->get_mac_addr(buf); - } -#ifdef GET_CUSTOM_MAC_ENABLE - return somc_get_mac_address(buf); -#else - return -EOPNOTSUPP; -#endif -} - -#ifdef CUSTOM_FORCE_NODFS_FLAG -void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags) -#else -void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -{ - /* get_country_code was added after 2.6.39 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) - struct wifi_platform_data *plat_data; - - if (!ccode || !adapter || !adapter->wifi_plat_data) - return NULL; - plat_data = adapter->wifi_plat_data; - - DHD_TRACE(("%s\n", __FUNCTION__)); - if (plat_data->get_country_code) { -#ifdef CUSTOM_FORCE_NODFS_FLAG /* CUSTOM_COUNTRY_CODE */ - return plat_data->get_country_code(ccode, flags); -#else - return plat_data->get_country_code(ccode); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - } -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ - - return NULL; -} - -static int wifi_plat_dev_drv_probe(struct platform_device *pdev) -{ - struct resource *resource; - wifi_adapter_info_t *adapter; -#ifdef CONFIG_DTS - int irq, gpio; -#endif /* CONFIG_DTS */ - - /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") - * is kept for backward compatibility and supports only 1 adapter - */ - ASSERT(dhd_wifi_platdata != NULL); - ASSERT(dhd_wifi_platdata->num_adapters == 1); - adapter = &dhd_wifi_platdata->adapters[0]; -#ifdef CONFIG_SOMC_WIFI_CONTROL - adapter->wifi_plat_data = (void *)&somc_wifi_control; -#else - adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data); -#endif /* CONFIG_SOMC_WIFI_CONTROL */ - resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); - if (resource == NULL) - resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); - if (resource) { - adapter->irq_num = resource->start; - adapter->intr_flags = resource->flags; - } -#ifdef CONFIG_SOMC_WIFI_CONTROL - somc_wifi_init(pdev); -#endif /* CONFIG_SOMC_WIFI_CONTROL */ -#ifdef CONFIG_DTS -#ifndef CUSTOMER_HW5 - wifi_regulator = regulator_get(&pdev->dev, "wlreg_on"); - if (wifi_regulator == NULL) { - DHD_ERROR(("%s regulator is null\n", __FUNCTION__)); - return -1; - } -#endif /* CUSTOMER_HW5 */ - /* This is to get the irq for the OOB */ -#ifdef CONFIG_SOMC_WIFI_CONTROL - gpio = of_get_gpio(pdev->dev.of_node, 1); -#else - gpio = of_get_gpio(pdev->dev.of_node, 0); -#endif /* CONFIG_SOMC_WIFI_CONTROL */ - if (gpio < 0) { - DHD_ERROR(("%s gpio information is incorrect\n", __FUNCTION__)); - return -1; - } - irq = gpio_to_irq(gpio); - if (irq < 0) { - DHD_ERROR(("%s irq information is incorrect\n", __FUNCTION__)); - return -1; - } - adapter->irq_num = irq; - - /* need to change the flags according to our requirement */ - adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | - IORESOURCE_IRQ_SHAREABLE; -#endif /* CONFIG_DTS */ - - wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); - return wifi_plat_dev_probe_ret; -} - -static int wifi_plat_dev_drv_remove(struct platform_device *pdev) -{ - wifi_adapter_info_t *adapter; - - /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") - * is kept for backward compatibility and supports only 1 adapter - */ - ASSERT(dhd_wifi_platdata != NULL); - ASSERT(dhd_wifi_platdata->num_adapters == 1); - adapter = &dhd_wifi_platdata->adapters[0]; - if (is_power_on) { - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); -#ifndef CUSTOMER_HW5 - wifi_platform_bus_enumerate(adapter, FALSE); -#endif - } -#ifdef CUSTOMER_HW5 - /* Sony mobile uses ENABLE_INSMOD_NO_FW_LOAD for module type driver - * They want to download firmware when primary interface is brought up - * The is_power_on is set to false through wl_android_wifi_off(). - * So move the func to here. - */ - wifi_platform_bus_enumerate(adapter, FALSE); -#endif - -#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) - regulator_put(wifi_regulator); -#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ -#ifdef CONFIG_SOMC_WIFI_CONTROL - somc_wifi_deinit(pdev); -#endif /* CONFIG_SOMC_WIFI_CONTROL */ - return 0; -} - -static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t state) -{ - DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(0); -#endif /* (OOB_INTR_ONLY) */ - return 0; -} - -static int wifi_plat_dev_drv_resume(struct platform_device *pdev) -{ - DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) - if (dhd_os_check_if_up(wl_cfg80211_get_dhdp())) - bcmsdh_oob_intr_set(1); -#endif /* (OOB_INTR_ONLY) */ - return 0; -} - -#ifdef CONFIG_DTS -static const struct of_device_id wifi_device_dt_match[] = { - { .compatible = "android,bcmdhd_wlan", }, - {}, -}; -#endif /* CONFIG_DTS */ -static struct platform_driver wifi_platform_dev_driver = { - .probe = wifi_plat_dev_drv_probe, - .remove = wifi_plat_dev_drv_remove, - .suspend = wifi_plat_dev_drv_suspend, - .resume = wifi_plat_dev_drv_resume, - .driver = { - .name = WIFI_PLAT_NAME, -#ifdef CONFIG_DTS - .of_match_table = wifi_device_dt_match, -#endif /* CONFIG_DTS */ - } -}; - -static struct platform_driver wifi_platform_dev_driver_legacy = { - .probe = wifi_plat_dev_drv_probe, - .remove = wifi_plat_dev_drv_remove, - .suspend = wifi_plat_dev_drv_suspend, - .resume = wifi_plat_dev_drv_resume, - .driver = { - .name = WIFI_PLAT_NAME2, - } -}; - -static int wifi_platdev_match(struct device *dev, void *data) -{ - char *name = (char*)data; - struct platform_device *pdev = to_platform_device(dev); - - if (strcmp(pdev->name, name) == 0) { - DHD_ERROR(("found wifi platform device %s\n", name)); - return TRUE; - } - - return FALSE; -} - -static int wifi_ctrlfunc_register_drv(void) -{ - int err = 0; - struct device *dev1, *dev2; - wifi_adapter_info_t *adapter; - - dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); - dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); - -#if !defined(CONFIG_DTS) - if (!dts_enabled) { - if (dev1 == NULL && dev2 == NULL) { - DHD_ERROR(("no wifi platform data, skip\n")); - return -ENXIO; - } - } -#endif /* !defined(CONFIG_DTS) */ - - /* multi-chip support not enabled, build one adapter information for - * DHD (either SDIO, USB or PCIe) - */ - adapter = kzalloc(sizeof(wifi_adapter_info_t), GFP_KERNEL); - adapter->name = "DHD generic adapter"; - adapter->bus_type = -1; - adapter->bus_num = -1; - adapter->slot_num = -1; - adapter->irq_num = -1; - is_power_on = FALSE; - wifi_plat_dev_probe_ret = 0; - dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL); - dhd_wifi_platdata->num_adapters = 1; - dhd_wifi_platdata->adapters = adapter; - - if (dev1) { - err = platform_driver_register(&wifi_platform_dev_driver); - if (err) { - DHD_ERROR(("%s: failed to register wifi ctrl func driver\n", - __FUNCTION__)); - return err; - } - } - if (dev2) { - err = platform_driver_register(&wifi_platform_dev_driver_legacy); - if (err) { - DHD_ERROR(("%s: failed to register wifi ctrl func legacy driver\n", - __FUNCTION__)); - return err; - } - } - -#if !defined(CONFIG_DTS) - if (dts_enabled) { - struct resource *resource; - adapter->wifi_plat_data = (void *)&dhd_wlan_control; - resource = &dhd_wlan_resources; - adapter->irq_num = resource->start; - adapter->intr_flags = resource->flags; - wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); - } -#endif /* !defined(CONFIG_DTS) */ - - -#ifdef CONFIG_DTS - wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver); -#endif /* CONFIG_DTS */ - - /* return probe function's return value if registeration succeeded */ - return wifi_plat_dev_probe_ret; -} - -void wifi_ctrlfunc_unregister_drv(void) -{ - -#ifdef CONFIG_DTS - DHD_ERROR(("unregister wifi platform drivers\n")); - platform_driver_unregister(&wifi_platform_dev_driver); -#else - struct device *dev1, *dev2; - dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); - dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); - if (!dts_enabled) - if (dev1 == NULL && dev2 == NULL) - return; - - DHD_ERROR(("unregister wifi platform drivers\n")); - if (dev1) - platform_driver_unregister(&wifi_platform_dev_driver); - if (dev2) - platform_driver_unregister(&wifi_platform_dev_driver_legacy); - if (dts_enabled) { - wifi_adapter_info_t *adapter; - adapter = &dhd_wifi_platdata->adapters[0]; - if (is_power_on) { - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } - } -#endif /* !defined(CONFIG_DTS) */ - - kfree(dhd_wifi_platdata->adapters); - dhd_wifi_platdata->adapters = NULL; - dhd_wifi_platdata->num_adapters = 0; - kfree(dhd_wifi_platdata); - dhd_wifi_platdata = NULL; -} - -static int bcmdhd_wifi_plat_dev_drv_probe(struct platform_device *pdev) -{ - dhd_wifi_platdata = (bcmdhd_wifi_platdata_t *)(pdev->dev.platform_data); - - return dhd_wifi_platform_load(); -} - -static int bcmdhd_wifi_plat_dev_drv_remove(struct platform_device *pdev) -{ - int i; - wifi_adapter_info_t *adapter; - ASSERT(dhd_wifi_platdata != NULL); - - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } - return 0; -} - -static struct platform_driver dhd_wifi_platform_dev_driver = { - .probe = bcmdhd_wifi_plat_dev_drv_probe, - .remove = bcmdhd_wifi_plat_dev_drv_remove, - .driver = { - .name = WIFI_PLAT_EXT, - } -}; - -int dhd_wifi_platform_register_drv(void) -{ - int err = 0; - struct device *dev; - - /* register Broadcom wifi platform data driver if multi-chip is enabled, - * otherwise use Android style wifi platform data (aka wifi control function) - * if it exists - * - * to support multi-chip DHD, Broadcom wifi platform data device must - * be added in kernel early boot (e.g. board config file). - */ - if (cfg_multichip) { - dev = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_EXT, wifi_platdev_match); - if (dev == NULL) { - DHD_ERROR(("bcmdhd wifi platform data device not found!!\n")); - return -ENXIO; - } - err = platform_driver_register(&dhd_wifi_platform_dev_driver); - } else { - err = wifi_ctrlfunc_register_drv(); - - /* no wifi ctrl func either, load bus directly and ignore this error */ - if (err) { - if (err == -ENXIO) { - /* wifi ctrl function does not exist */ - err = dhd_wifi_platform_load(); - } else { - /* unregister driver due to initialization failure */ - wifi_ctrlfunc_unregister_drv(); - } - } - } - - return err; -} - -#ifdef BCMPCIE -static int dhd_wifi_platform_load_pcie(void) -{ - int err = 0; - err = dhd_bus_register(); - return err; -} -#else -static int dhd_wifi_platform_load_pcie(void) -{ - return 0; -} -#endif /* BCMPCIE */ - - -void dhd_wifi_platform_unregister_drv(void) -{ - if (cfg_multichip) - platform_driver_unregister(&dhd_wifi_platform_dev_driver); - else - wifi_ctrlfunc_unregister_drv(); -} - -extern int dhd_watchdog_prio; -extern int dhd_dpc_prio; -extern uint dhd_deferred_tx; -#if defined(BCMLXSDMMC) -extern struct semaphore dhd_registration_sem; -#endif - -static int dhd_wifi_platform_load_sdio(void) -{ - int i; - int err = 0; - wifi_adapter_info_t *adapter; - - BCM_REFERENCE(i); - BCM_REFERENCE(adapter); - /* Sanity check on the module parameters - * - Both watchdog and DPC as tasklets are ok - * - If both watchdog and DPC are threads, TX must be deferred - */ - if (!(dhd_watchdog_prio < 0 && dhd_dpc_prio < 0) && - !(dhd_watchdog_prio >= 0 && dhd_dpc_prio >= 0 && dhd_deferred_tx)) - return -EINVAL; - -#if defined(BCMLXSDMMC) - if (dhd_wifi_platdata == NULL) { - DHD_ERROR(("DHD wifi platform data is required for Android build\n")); - return -EINVAL; - } - - sema_init(&dhd_registration_sem, 0); - /* power up all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - bool chip_up = FALSE; - int retry = POWERUP_MAX_RETRY; - struct semaphore dhd_chipup_sem; - - adapter = &dhd_wifi_platdata->adapters[i]; - - DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); - DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", - adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); - DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", - adapter->bus_type, adapter->bus_num, adapter->slot_num)); - - do { - sema_init(&dhd_chipup_sem, 0); - err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); - if (err) { - DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n", - __FUNCTION__, err)); - return err; - } - err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); - if (err) { - /* WL_REG_ON state unknown, Power off forcely */ - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - continue; - } else { - wifi_platform_bus_enumerate(adapter, TRUE); - err = 0; - } - - if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { - dhd_bus_unreg_sdio_notify(); - chip_up = TRUE; - break; - } - - DHD_ERROR(("failed to power up %s, %d retry left\n", adapter->name, retry)); - dhd_bus_unreg_sdio_notify(); - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } while (retry--); - - if (!chip_up) { - DHD_ERROR(("failed to power up %s, max retry reached**\n", adapter->name)); - return -ENODEV; - } - - } - - err = dhd_bus_register(); - - if (err) { - DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); - goto fail; - } - - - /* - * Wait till MMC sdio_register_driver callback called and made driver attach. - * It's needed to make sync up exit from dhd insmod and - * Kernel MMC sdio device callback registration - */ - err = down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); - if (err) { - DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__)); - dhd_bus_unregister(); - goto fail; - } - - return err; - -fail: - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } -#else - - /* x86 bring-up PC needs no power-up operations */ - err = dhd_bus_register(); - -#endif - - return err; -} - -static int dhd_wifi_platform_load_usb(void) -{ - return 0; -} - -static int dhd_wifi_platform_load() -{ - int err = 0; - - wl_android_init(); - - if ((err = dhd_wifi_platform_load_usb())) - goto end; - else if ((err = dhd_wifi_platform_load_sdio())) - goto end; - else - err = dhd_wifi_platform_load_pcie(); - -end: - if (err) - wl_android_exit(); - else - wl_android_post_init(); - - return err; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c deleted file mode 100755 index a24b32124fba..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Expose some of the kernel scheduler routines - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux_sched.c 457596 2014-02-24 02:24:14Z $ - */ -#include -#include -#include -#include -#include - -int setScheduler(struct task_struct *p, int policy, struct sched_param *param) -{ - int rc = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - rc = sched_setscheduler(p, policy, param); -#endif /* LinuxVer */ - return rc; -} - -int get_scheduler_policy(struct task_struct *p) -{ - int rc = SCHED_NORMAL; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - rc = p->policy; -#endif /* LinuxVer */ - return rc; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c deleted file mode 100755 index bd0b7afad022..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Generic work queue framework - * Generic interface to handle dhd deferred work events - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux_wq.c 411851 2013-07-10 20:48:00Z $ - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct dhd_deferred_event_t { - u8 event; /* holds the event */ - void *event_data; /* Holds event specific data */ - event_handler_t event_handler; -}; -#define DEFRD_EVT_SIZE sizeof(struct dhd_deferred_event_t) - -struct dhd_deferred_wq { - struct work_struct deferred_work; /* should be the first member */ - - /* - * work events may occur simultaneously. - * Can hold upto 64 low priority events and 4 high priority events - */ -#define DHD_PRIO_WORK_FIFO_SIZE (4 * sizeof(struct dhd_deferred_event_t)) -#define DHD_WORK_FIFO_SIZE (64 * sizeof(struct dhd_deferred_event_t)) - struct kfifo *prio_fifo; - struct kfifo *work_fifo; - u8 *prio_fifo_buf; - u8 *work_fifo_buf; - spinlock_t work_lock; - void *dhd_info; /* review: does it require */ -}; -struct dhd_deferred_wq *deferred_wq = NULL; - -static inline struct kfifo* -dhd_kfifo_init(u8 *buf, int size, spinlock_t *lock) -{ - struct kfifo *fifo; - gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) - fifo = kfifo_init(buf, size, flags, lock); -#else - fifo = (struct kfifo *)kzalloc(sizeof(struct kfifo), flags); - if (!fifo) { - return NULL; - } - kfifo_init(fifo, buf, size); -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ - return fifo; -} - -static inline void -dhd_kfifo_free(struct kfifo *fifo) -{ - kfifo_free(fifo); -} - -/* deferred work functions */ -static void dhd_deferred_work_handler(struct work_struct *data); - -void* -dhd_deferred_work_init(void *dhd_info) -{ - struct dhd_deferred_wq *work = NULL; - u8* buf; - unsigned long fifo_size = 0; - gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC; - - if (!dhd_info) { - DHD_ERROR(("%s: dhd info not initialized\n", __FUNCTION__)); - goto return_null; - } - - work = (struct dhd_deferred_wq *)kzalloc(sizeof(struct dhd_deferred_wq), - flags); - - if (!work) { - DHD_ERROR(("%s: work queue creation failed \n", __FUNCTION__)); - goto return_null; - } - - INIT_WORK((struct work_struct *)work, dhd_deferred_work_handler); - - /* initialize event fifo */ - spin_lock_init(&work->work_lock); - - /* allocate buffer to hold prio events */ - fifo_size = DHD_PRIO_WORK_FIFO_SIZE; - fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); - buf = (u8*)kzalloc(fifo_size, flags); - if (!buf) { - DHD_ERROR(("%s: prio work fifo allocation failed \n", __FUNCTION__)); - goto return_null; - } - - /* Initialize prio event fifo */ - work->prio_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); - if (!work->prio_fifo) { - kfree(buf); - goto return_null; - } - - /* allocate buffer to hold work events */ - fifo_size = DHD_WORK_FIFO_SIZE; - fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); - buf = (u8*)kzalloc(fifo_size, flags); - if (!buf) { - DHD_ERROR(("%s: work fifo allocation failed \n", __FUNCTION__)); - goto return_null; - } - - /* Initialize event fifo */ - work->work_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); - if (!work->work_fifo) { - kfree(buf); - goto return_null; - } - - work->dhd_info = dhd_info; - deferred_wq = work; - DHD_ERROR(("%s: work queue initialized \n", __FUNCTION__)); - return work; - -return_null: - - if (work) - dhd_deferred_work_deinit(work); - - return NULL; -} - -void -dhd_deferred_work_deinit(void *work) -{ - struct dhd_deferred_wq *deferred_work = work; - - - if (!deferred_work) { - DHD_ERROR(("%s: deferred work has been freed alread \n", __FUNCTION__)); - return; - } - - /* cancel the deferred work handling */ - cancel_work_sync((struct work_struct *)deferred_work); - - /* - * free work event fifo. - * kfifo_free frees locally allocated fifo buffer - */ - if (deferred_work->prio_fifo) - dhd_kfifo_free(deferred_work->prio_fifo); - - if (deferred_work->work_fifo) - dhd_kfifo_free(deferred_work->work_fifo); - - kfree(deferred_work); - - /* deinit internal reference pointer */ - deferred_wq = NULL; -} - -/* - * Prepares event to be queued - * Schedules the event - */ -int -dhd_deferred_schedule_work(void *event_data, u8 event, event_handler_t event_handler, u8 priority) -{ - struct dhd_deferred_event_t deferred_event; - int status; - - if (!deferred_wq) { - DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); - ASSERT(0); - return DHD_WQ_STS_UNINITIALIZED; - } - - if (!event || (event >= DHD_MAX_WQ_EVENTS)) { - DHD_ERROR(("%s: Unknown event \n", __FUNCTION__)); - return DHD_WQ_STS_UNKNOWN_EVENT; - } - - /* - * default element size is 1, which can be changed - * using kfifo_esize(). Older kernel(FC11) doesn't support - * changing element size. For compatibility changing - * element size is not prefered - */ - ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); - ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); - - deferred_event.event = event; - deferred_event.event_data = event_data; - deferred_event.event_handler = event_handler; - - if (priority == DHD_WORK_PRIORITY_HIGH) { - status = kfifo_in_spinlocked(deferred_wq->prio_fifo, &deferred_event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - } else { - status = kfifo_in_spinlocked(deferred_wq->work_fifo, &deferred_event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - } - - if (!status) { - return DHD_WQ_STS_SCHED_FAILED; - } - schedule_work((struct work_struct *)deferred_wq); - return DHD_WQ_STS_OK; -} - -static int -dhd_get_scheduled_work(struct dhd_deferred_event_t *event) -{ - int status = 0; - - if (!deferred_wq) { - DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); - return DHD_WQ_STS_UNINITIALIZED; - } - - /* - * default element size is 1 byte, which can be changed - * using kfifo_esize(). Older kernel(FC11) doesn't support - * changing element size. For compatibility changing - * element size is not prefered - */ - ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); - ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); - - /* first read priorit event fifo */ - status = kfifo_out_spinlocked(deferred_wq->prio_fifo, event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - - if (!status) { - /* priority fifo is empty. Now read low prio work fifo */ - status = kfifo_out_spinlocked(deferred_wq->work_fifo, event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - } - - return status; -} - -/* - * Called when work is scheduled - */ -static void -dhd_deferred_work_handler(struct work_struct *work) -{ - struct dhd_deferred_wq *deferred_work = (struct dhd_deferred_wq *)work; - struct dhd_deferred_event_t work_event; - int status; - - if (!deferred_work) { - DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); - return; - } - - do { - status = dhd_get_scheduled_work(&work_event); - DHD_TRACE(("%s: event to handle %d \n", __FUNCTION__, status)); - if (!status) { - DHD_TRACE(("%s: No event to handle %d \n", __FUNCTION__, status)); - break; - } - - if (work_event.event > DHD_MAX_WQ_EVENTS) { - DHD_TRACE(("%s: Unknown event %d \n", __FUNCTION__, work_event.event)); - break; - } - - if (work_event.event_handler) { - work_event.event_handler(deferred_work->dhd_info, - work_event.event_data, work_event.event); - } else { - DHD_ERROR(("%s: event not defined %d\n", __FUNCTION__, work_event.event)); - } - } while (1); - return; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h deleted file mode 100755 index 66f237fb7002..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Generic work queue framework - * Generic interface to handle dhd deferred work events - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux_wq.h 408802 2013-06-20 19:08:47Z $ - */ -#ifndef _dhd_linux_wq_h_ -#define _dhd_linux_wq_h_ -/* - * Work event definitions - */ -enum _wq_event { - DHD_WQ_WORK_IF_ADD = 1, - DHD_WQ_WORK_IF_DEL, - DHD_WQ_WORK_SET_MAC, - DHD_WQ_WORK_SET_MCAST_LIST, - DHD_WQ_WORK_IPV6_NDO, - DHD_WQ_WORK_HANG_MSG, - - DHD_MAX_WQ_EVENTS -}; - -/* - * Work event priority - */ -#define DHD_WORK_PRIORITY_LOW 0 -#define DHD_WORK_PRIORITY_HIGH 1 - -/* - * Error definitions - */ -#define DHD_WQ_STS_OK 0 -#define DHD_WQ_STS_FAILED -1 /* General failure */ -#define DHD_WQ_STS_UNINITIALIZED -2 -#define DHD_WQ_STS_SCHED_FAILED -3 -#define DHD_WQ_STS_UNKNOWN_EVENT -4 - -typedef void (*event_handler_t)(void *handle, void *event_data, u8 event); - -void *dhd_deferred_work_init(void *dhd); -void dhd_deferred_work_deinit(void *work); -int dhd_deferred_schedule_work(void *event_data, u8 event, - event_handler_t evt_handler, u8 priority); -#endif /* _dhd_linux_wq_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c deleted file mode 100755 index ea97317f040c..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c +++ /dev/null @@ -1,3977 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD) - * Prefered Network Offload and Wi-Fi Location Service(WLS) code. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_pno.c 423669 2013-09-18 13:01:55Z yangj$ - */ - -#if defined(GSCAN_SUPPORT) && !defined(PNO_SUPPORT) -#error "GSCAN needs PNO to be enabled!" -#endif - -#ifdef PNO_SUPPORT -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#ifdef GSCAN_SUPPORT -#include -#endif /* GSCAN_SUPPORT */ -#include - -#ifdef __BIG_ENDIAN -#include -#define htod32(i) (bcmswap32(i)) -#define htod16(i) (bcmswap16(i)) -#define dtoh32(i) (bcmswap32(i)) -#define dtoh16(i) (bcmswap16(i)) -#define htodchanspec(i) htod16(i) -#define dtohchanspec(i) dtoh16(i) -#else -#define htod32(i) (i) -#define htod16(i) (i) -#define dtoh32(i) (i) -#define dtoh16(i) (i) -#define htodchanspec(i) (i) -#define dtohchanspec(i) (i) -#endif /* IL_BIGENDINA */ - -#define NULL_CHECK(p, s, err) \ - do { \ - if (!(p)) { \ - printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ - err = BCME_ERROR; \ - return err; \ - } \ - } while (0) -#define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) -#define PNO_BESTNET_LEN 2048 -#define PNO_ON 1 -#define PNO_OFF 0 -#define CHANNEL_2G_MAX 14 -#define CHANNEL_5G_MAX 165 -#define MAX_NODE_CNT 5 -#define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE) -#define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \ - - (uint32)(timestamp2/1000))) -#define TIME_DIFF_MS(timestamp1, timestamp2) (abs((uint32)(timestamp1) \ - - (uint32)(timestamp2))) -#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ - (ts).tv_nsec / NSEC_PER_USEC) - -#define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") -#define TIME_MIN_DIFF 5 -#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) -#define EVENT_MAX_NETCNT \ - ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_t)) \ - / sizeof(wl_pfn_net_info_t) + 1) - -static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, - dhd_pno_status_info_t *pno_state); -#ifdef GSCAN_SUPPORT -static wl_pfn_gscan_ch_bucket_cfg_t * -dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state, - uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw); -#endif /* GSCAN_SUPPORT */ - -static inline bool -is_dfs(uint16 channel) -{ - if (channel >= 52 && channel <= 64) /* class 2 */ - return TRUE; - else if (channel >= 100 && channel <= 140) /* class 4 */ - return TRUE; - else - return FALSE; -} -int -dhd_pno_clean(dhd_pub_t *dhd) -{ - int pfn = 0; - int err; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - /* Disable PNO */ - err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn(error : %d)\n", - __FUNCTION__, err)); - goto exit; - } - _pno_state->pno_status = DHD_PNO_DISABLED; - err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfnclear(error : %d)\n", - __FUNCTION__, err)); - } -exit: - return err; -} - -bool -dhd_is_pno_supported(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - if (!dhd || !dhd->pno_state) { - DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__)); - return FALSE; - } - _pno_state = PNO_GET_PNOSTATE(dhd); - return WLS_SUPPORTED(_pno_state); -} - -bool -dhd_is_legacy_pno_enabled(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - - if (!dhd || !dhd->pno_state) { - DHD_ERROR(("NULL POINTER : %s\n", - __FUNCTION__)); - return FALSE; - } - _pno_state = PNO_GET_PNOSTATE(dhd); - return ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) != 0); -} - -#ifdef GSCAN_SUPPORT -static uint64 -convert_fw_rel_time_to_systime(uint32 fw_ts_ms) -{ - struct timespec ts; - - get_monotonic_boottime(&ts); - return ((uint64)(TIMESPEC_TO_US(ts)) - (uint64)(fw_ts_ms * 1000)); -} - -static void -dhd_pno_idx_to_ssid(struct dhd_pno_gscan_params *gscan_params, - dhd_epno_results_t *res, uint32 idx) -{ - dhd_epno_params_t *iter, *next; - - if (gscan_params->num_epno_ssid > 0) { - list_for_each_entry_safe(iter, next, - &gscan_params->epno_ssid_list, list) { - if (iter->index == idx) { - memcpy(res->ssid, iter->ssid, iter->ssid_len); - res->ssid_len = iter->ssid_len; - return; - } - } - } - /* If we are here then there was no match */ - res->ssid[0] = '\0'; - res->ssid_len = 0; - return; -} - -/* Cleanup all results */ -static void -dhd_gscan_clear_all_batch_results(dhd_pub_t *dhd) -{ - struct dhd_pno_gscan_params *gscan_params; - dhd_pno_status_info_t *_pno_state; - gscan_results_cache_t *iter; - - _pno_state = PNO_GET_PNOSTATE(dhd); - gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; - iter = gscan_params->gscan_batch_cache; - /* Mark everything as consumed */ - while (iter) { - iter->tot_consumed = iter->tot_count; - iter = iter->next; - } - dhd_gscan_batch_cache_cleanup(dhd); - return; -} - -static int -_dhd_pno_gscan_cfg(dhd_pub_t *dhd, wl_pfn_gscan_cfg_t *pfncfg_gscan_param, int size) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - - err = dhd_iovar(dhd, 0, "pfn_gscan_cfg", (char *)pfncfg_gscan_param, size, NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfncfg_gscan_param\n", __FUNCTION__)); - goto exit; - } -exit: - return err; -} - -static bool -is_batch_retrieval_complete(struct dhd_pno_gscan_params *gscan_params) -{ - smp_rmb(); - return (gscan_params->get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE); -} -#endif /* GSCAN_SUPPORT */ - -static int -_dhd_pno_suspend(dhd_pub_t *dhd) -{ - int err; - int suspend = 1; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err)); - goto exit; - - } - _pno_state->pno_status = DHD_PNO_SUSPEND; -exit: - return err; -} -static int -_dhd_pno_enable(dhd_pub_t *dhd, int enable) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (enable & 0xfffe) { - DHD_ERROR(("%s invalid value\n", __FUNCTION__)); - err = BCME_BADARG; - goto exit; - } - if (!dhd_support_sta_mode(dhd)) { - DHD_ERROR(("PNO is not allowed for non-STA mode")); - err = BCME_BADOPTION; - goto exit; - } - if (enable) { - if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && - dhd_is_associated(dhd, NULL, NULL)) { - DHD_ERROR(("%s Legacy PNO mode cannot be enabled " - "in assoc mode , ignore it\n", __FUNCTION__)); - err = BCME_BADOPTION; - goto exit; - } - } - /* Enable/Disable PNO */ - err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_set - %d\n", __FUNCTION__, err)); - goto exit; - } - _pno_state->pno_status = (enable)? - DHD_PNO_ENABLED : DHD_PNO_DISABLED; - if (!enable) - _pno_state->pno_mode = DHD_PNO_NONE_MODE; - - DHD_PNO(("%s set pno as %s\n", - __FUNCTION__, enable ? "Enable" : "Disable")); -exit: - return err; -} - -static int -_dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode) -{ - int err = BCME_OK; - wl_pfn_param_t pfn_param; - dhd_pno_params_t *_params; - dhd_pno_status_info_t *_pno_state; - bool combined_scan = FALSE; - DHD_PNO(("%s enter\n", __FUNCTION__)); - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - memset(&pfn_param, 0, sizeof(pfn_param)); - - /* set pfn parameters */ - pfn_param.version = htod32(PFN_VERSION); - pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) | - (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT)); - if (mode == DHD_PNO_LEGACY_MODE) { - /* check and set extra pno params */ - if ((pno_params->params_legacy.pno_repeat != 0) || - (pno_params->params_legacy.pno_freq_expo_max != 0)) { - pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); - pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); - pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max); - } - /* set up pno scan fr */ - if (pno_params->params_legacy.scan_fr != 0) - pfn_param.scan_freq = htod32(pno_params->params_legacy.scan_fr); - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - DHD_PNO(("will enable combined scan with BATCHIG SCAN MODE\n")); - mode |= DHD_PNO_BATCH_MODE; - combined_scan = TRUE; - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - DHD_PNO(("will enable combined scan with HOTLIST SCAN MODE\n")); - mode |= DHD_PNO_HOTLIST_MODE; - combined_scan = TRUE; - } -#ifdef GSCAN_SUPPORT - else if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - DHD_PNO(("will enable combined scan with GSCAN SCAN MODE\n")); - mode |= DHD_PNO_GSCAN_MODE; - } -#endif /* GSCAN_SUPPORT */ - } - if (mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { - /* Scan frequency of 30 sec */ - pfn_param.scan_freq = htod32(30); - /* slow adapt scan is off by default */ - pfn_param.slow_freq = htod32(0); - /* RSSI margin of 30 dBm */ - pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); - /* Network timeout 60 sec */ - pfn_param.lost_network_timeout = htod32(60); - /* best n = 2 by default */ - pfn_param.bestn = DEFAULT_BESTN; - /* mscan m=0 by default, so not record best networks by default */ - pfn_param.mscan = DEFAULT_MSCAN; - /* default repeat = 10 */ - pfn_param.repeat = DEFAULT_REPEAT; - /* by default, maximum scan interval = 2^2 - * scan_freq when adaptive scan is turned on - */ - pfn_param.exp = DEFAULT_EXP; - if (mode == DHD_PNO_BATCH_MODE) { - /* In case of BATCH SCAN */ - if (pno_params->params_batch.bestn) - pfn_param.bestn = pno_params->params_batch.bestn; - if (pno_params->params_batch.scan_fr) - pfn_param.scan_freq = htod32(pno_params->params_batch.scan_fr); - if (pno_params->params_batch.mscan) - pfn_param.mscan = pno_params->params_batch.mscan; - /* enable broadcast scan */ - pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); - } else if (mode == DHD_PNO_HOTLIST_MODE) { - /* In case of HOTLIST SCAN */ - if (pno_params->params_hotlist.scan_fr) - pfn_param.scan_freq = htod32(pno_params->params_hotlist.scan_fr); - pfn_param.bestn = 0; - pfn_param.repeat = 0; - /* enable broadcast scan */ - pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); - } - if (combined_scan) { - /* Disable Adaptive Scan */ - pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT)); - pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); - pfn_param.repeat = 0; - pfn_param.exp = 0; - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - /* In case of Legacy PNO + BATCH SCAN */ - _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); - if (_params->params_batch.bestn) - pfn_param.bestn = _params->params_batch.bestn; - if (_params->params_batch.scan_fr) - pfn_param.scan_freq = htod32(_params->params_batch.scan_fr); - if (_params->params_batch.mscan) - pfn_param.mscan = _params->params_batch.mscan; - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - /* In case of Legacy PNO + HOTLIST SCAN */ - _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - if (_params->params_hotlist.scan_fr) - pfn_param.scan_freq = htod32(_params->params_hotlist.scan_fr); - pfn_param.bestn = 0; - pfn_param.repeat = 0; - } - } - } -#ifdef GSCAN_SUPPORT - if (mode & DHD_PNO_GSCAN_MODE) { - uint32 lost_network_timeout; - - pfn_param.scan_freq = htod32(pno_params->params_gscan.scan_fr); - if (pno_params->params_gscan.mscan) { - pfn_param.bestn = pno_params->params_gscan.bestn; - pfn_param.mscan = pno_params->params_gscan.mscan; - pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); - } - /* RSSI margin of 30 dBm */ - pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); - pfn_param.repeat = 0; - pfn_param.exp = 0; - pfn_param.slow_freq = 0; - pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); - - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - dhd_pno_params_t *_params; - - _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - - pfn_param.scan_freq = htod32(gcd(pno_params->params_gscan.scan_fr, - _params->params_legacy.scan_fr)); - - if ((_params->params_legacy.pno_repeat != 0) || - (_params->params_legacy.pno_freq_expo_max != 0)) { - pfn_param.repeat = (uchar) (_params->params_legacy.pno_repeat); - pfn_param.exp = (uchar) (_params->params_legacy.pno_freq_expo_max); - } - } - - lost_network_timeout = (pno_params->params_gscan.max_ch_bucket_freq * - pfn_param.scan_freq * pno_params->params_gscan.lost_ap_window); - if (lost_network_timeout) { - pfn_param.lost_network_timeout = htod32(MIN(lost_network_timeout, - GSCAN_MIN_BSSID_TIMEOUT)); - } else { - pfn_param.lost_network_timeout = htod32(GSCAN_MIN_BSSID_TIMEOUT); - } - } else -#endif /* GSCAN_SUPPORT */ - { - - if (pfn_param.scan_freq < htod32(PNO_SCAN_MIN_FW_SEC) || - pfn_param.scan_freq > htod32(PNO_SCAN_MAX_FW_SEC)) { - DHD_ERROR(("%s pno freq(%d sec) is not valid \n", - __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); - err = BCME_BADARG; - goto exit; - } - - } - - err = dhd_set_rand_mac_oui(dhd); - /* Ignore if chip doesnt support the feature */ - if (err < 0 && err != BCME_UNSUPPORTED) { - DHD_ERROR(("%s : failed to set random mac for PNO scan, %d\n", __FUNCTION__, err)); - goto exit; - } - -#ifdef GSCAN_SUPPORT - if (mode == DHD_PNO_BATCH_MODE || - ((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) { -#else - if (mode == DHD_PNO_BATCH_MODE) { -#endif /* GSCAN_SUPPORT */ - int _tmp = pfn_param.bestn; - /* set bestn to calculate the max mscan which firmware supports */ - err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to set pfnmem\n", __FUNCTION__)); - goto exit; - } - /* get max mscan which the firmware supports */ - err = dhd_iovar(dhd, 0, "pfnmem", NULL, 0, (char *)&_tmp, sizeof(_tmp), FALSE); - if (err < 0) { - DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__)); - goto exit; - } - pfn_param.mscan = MIN(pfn_param.mscan, _tmp); - DHD_PNO((" returned mscan : %d, set bestn : %d mscan %d\n", _tmp, pfn_param.bestn, - pfn_param.mscan)); - } - err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err)); - goto exit; - } - /* need to return mscan if this is for batch scan instead of err */ - err = (mode == DHD_PNO_BATCH_MODE)? pfn_param.mscan : err; -exit: - return err; -} -static int -_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssids_list, int nssid) -{ - int err = BCME_OK; - int i = 0; - wl_pfn_t pfn_element; - - NULL_CHECK(dhd, "dhd is NULL", err); - if (nssid) { - NULL_CHECK(ssids_list, "ssid list is NULL", err); - } - memset(&pfn_element, 0, sizeof(pfn_element)); - { - int j; - for (j = 0; j < nssid; j++) { - DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n", - ssids_list[j].SSID, ssids_list[j].SSID_len, ssids_list[j].hidden, - ssids_list[j].flags, ssids_list[i].rssi_thresh)); - } - } - /* Check for broadcast ssid */ - for (i = 0; i < nssid; i++) { - if (!ssids_list[i].SSID_len) { - DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", i)); - err = BCME_ERROR; - goto exit; - } - } - /* set all pfn ssid */ - for (i = 0; i < nssid; i++) { - pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); - pfn_element.auth = (DOT11_OPEN_SYSTEM); - pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); - pfn_element.wsec = htod32(0); - pfn_element.infra = htod32(1); - if (ssids_list[i].hidden) { - pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); - } else { - pfn_element.flags = 0; - } - pfn_element.flags |= htod32(ssids_list[i].flags); - /* If a single RSSI threshold is defined, use that */ -#ifdef PNO_MIN_RSSI_TRIGGER - pfn_element.flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT); -#else - pfn_element.flags |= ((ssids_list[i].rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT); -#endif /* PNO_MIN_RSSI_TRIGGER */ - memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, - ssids_list[i].SSID_len); - pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; - err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, sizeof(wl_pfn_t), - NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); - goto exit; - } - } -exit: - return err; -} -/* qsort compare function */ -static int -_dhd_pno_cmpfunc(const void *a, const void *b) -{ - return (*(uint16*)a - *(uint16*)b); -} -static int -_dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan, - uint16 *chan_list1, int nchan1, uint16 *chan_list2, int nchan2) -{ - int err = BCME_OK; - int i = 0, j = 0, k = 0; - uint16 tmp; - NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); - NULL_CHECK(nchan, "nchan is NULL", err); - NULL_CHECK(chan_list1, "chan_list1 is NULL", err); - NULL_CHECK(chan_list2, "chan_list2 is NULL", err); - /* chan_list1 and chan_list2 should be sorted at first */ - while (i < nchan1 && j < nchan2) { - tmp = chan_list1[i] < chan_list2[j]? - chan_list1[i++] : chan_list2[j++]; - for (; i < nchan1 && chan_list1[i] == tmp; i++); - for (; j < nchan2 && chan_list2[j] == tmp; j++); - d_chan_list[k++] = tmp; - } - - while (i < nchan1) { - tmp = chan_list1[i++]; - for (; i < nchan1 && chan_list1[i] == tmp; i++); - d_chan_list[k++] = tmp; - } - - while (j < nchan2) { - tmp = chan_list2[j++]; - for (; j < nchan2 && chan_list2[j] == tmp; j++); - d_chan_list[k++] = tmp; - - } - *nchan = k; - return err; -} -static int -_dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list, - int *nchan, uint8 band, bool skip_dfs) -{ - int err = BCME_OK; - int i, j; - uint32 chan_buf[WL_NUMCHANNELS + 1]; - wl_uint32_list_t *list; - NULL_CHECK(dhd, "dhd is NULL", err); - if (*nchan) { - NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); - } - memset(chan_buf, 0, sizeof(chan_buf)); - list = (wl_uint32_list_t *) (void *)chan_buf; - list->count = htod32(WL_NUMCHANNELS); - err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); - if (err < 0) { - DHD_ERROR(("failed to get channel list (err: %d)\n", err)); - goto exit; - } - for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) { - if (band == WLC_BAND_2G) { - if (dtoh32(list->element[i]) > CHANNEL_2G_MAX) - continue; - } else if (band == WLC_BAND_5G) { - if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX) - continue; - if (skip_dfs && is_dfs(dtoh32(list->element[i]))) - continue; - - } else if (band == WLC_BAND_AUTO) { - if (skip_dfs || !is_dfs(dtoh32(list->element[i]))) - continue; - - } else { /* All channels */ - if (skip_dfs && is_dfs(dtoh32(list->element[i]))) - continue; - } - if (dtoh32(list->element[i]) <= CHANNEL_5G_MAX) { - d_chan_list[j++] = (uint16) dtoh32(list->element[i]); - } else { - err = BCME_BADCHAN; - goto exit; - } - } - *nchan = j; -exit: - return err; -} -static int -_dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batch, - char *buf, int nbufsize) -{ - int err = BCME_OK; - int bytes_written = 0, nreadsize = 0; - int t_delta = 0; - int nleftsize = nbufsize; - uint8 cnt = 0; - char *bp = buf; - char eabuf[ETHER_ADDR_STR_LEN]; -#ifdef PNO_DEBUG - char *_base_bp; - char msg[150]; -#endif - dhd_pno_bestnet_entry_t *iter, *next; - dhd_pno_scan_results_t *siter, *snext; - dhd_pno_best_header_t *phead, *pprev; - NULL_CHECK(params_batch, "params_batch is NULL", err); - if (nbufsize > 0) - NULL_CHECK(buf, "buf is NULL", err); - /* initialize the buffer */ - memset(buf, 0, nbufsize); - DHD_PNO(("%s enter \n", __FUNCTION__)); - /* # of scans */ - if (!params_batch->get_batch.batch_started) { - bp += nreadsize = sprintf(bp, "scancount=%d\n", - params_batch->get_batch.expired_tot_scan_cnt); - nleftsize -= nreadsize; - params_batch->get_batch.batch_started = TRUE; - } - DHD_PNO(("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt)); - /* preestimate scan count until which scan result this report is going to end */ - list_for_each_entry_safe(siter, snext, - ¶ms_batch->get_batch.expired_scan_results_list, list) { - phead = siter->bestnetheader; - while (phead != NULL) { - /* if left_size is less than bestheader total size , stop this */ - if (nleftsize <= - (phead->tot_size + phead->tot_cnt * ENTRY_OVERHEAD)) - goto exit; - /* increase scan count */ - cnt++; - /* # best of each scan */ - DHD_PNO(("\n\n", cnt - 1, phead->tot_cnt)); - /* attribute of the scan */ - if (phead->reason & PNO_STATUS_ABORT_MASK) { - bp += nreadsize = sprintf(bp, "trunc\n"); - nleftsize -= nreadsize; - } - list_for_each_entry_safe(iter, next, - &phead->entry_list, list) { - t_delta = jiffies_to_msecs(jiffies - iter->recorded_time); -#ifdef PNO_DEBUG - _base_bp = bp; - memset(msg, 0, sizeof(msg)); -#endif - /* BSSID info */ - bp += nreadsize = sprintf(bp, "bssid=%s\n", - bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf)); - nleftsize -= nreadsize; - /* SSID */ - bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID); - nleftsize -= nreadsize; - /* channel */ - bp += nreadsize = sprintf(bp, "freq=%d\n", - wf_channel2mhz(iter->channel, - iter->channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - nleftsize -= nreadsize; - /* RSSI */ - bp += nreadsize = sprintf(bp, "level=%d\n", iter->RSSI); - nleftsize -= nreadsize; - /* add the time consumed in Driver to the timestamp of firmware */ - iter->timestamp += t_delta; - bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp); - nleftsize -= nreadsize; - /* RTT0 */ - bp += nreadsize = sprintf(bp, "dist=%d\n", - (iter->rtt0 == 0)? -1 : iter->rtt0); - nleftsize -= nreadsize; - /* RTT1 */ - bp += nreadsize = sprintf(bp, "distSd=%d\n", - (iter->rtt0 == 0)? -1 : iter->rtt1); - nleftsize -= nreadsize; - bp += nreadsize = sprintf(bp, "%s", AP_END_MARKER); - nleftsize -= nreadsize; - list_del(&iter->list); - MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); -#ifdef PNO_DEBUG - memcpy(msg, _base_bp, bp - _base_bp); - DHD_PNO(("Entry : \n%s", msg)); -#endif - } - bp += nreadsize = sprintf(bp, "%s", SCAN_END_MARKER); - DHD_PNO(("%s", SCAN_END_MARKER)); - nleftsize -= nreadsize; - pprev = phead; - /* reset the header */ - siter->bestnetheader = phead = phead->next; - MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); - - siter->cnt_header--; - } - if (phead == NULL) { - /* we store all entry in this scan , so it is ok to delete */ - list_del(&siter->list); - MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); - } - } -exit: - if (cnt < params_batch->get_batch.expired_tot_scan_cnt) { - DHD_ERROR(("Buffer size is small to save all batch entry," - " cnt : %d (remained_scan_cnt): %d\n", - cnt, params_batch->get_batch.expired_tot_scan_cnt - cnt)); - } - params_batch->get_batch.expired_tot_scan_cnt -= cnt; - /* set FALSE only if the link list is empty after returning the data */ - if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) { - params_batch->get_batch.batch_started = FALSE; - bp += sprintf(bp, "%s", RESULTS_END_MARKER); - DHD_PNO(("%s", RESULTS_END_MARKER)); - DHD_PNO(("%s : Getting the batching data is complete\n", __FUNCTION__)); - } - /* return used memory in buffer */ - bytes_written = (int32)(bp - buf); - return bytes_written; -} -static int -_dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last) -{ - int err = BCME_OK; - int removed_scan_cnt = 0; - dhd_pno_scan_results_t *siter, *snext; - dhd_pno_best_header_t *phead, *pprev; - dhd_pno_bestnet_entry_t *iter, *next; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(head, "head is NULL", err); - NULL_CHECK(head->next, "head->next is NULL", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - list_for_each_entry_safe(siter, snext, - head, list) { - if (only_last) { - /* in case that we need to delete only last one */ - if (!list_is_last(&siter->list, head)) { - /* skip if the one is not last */ - continue; - } - } - /* delete all data belong if the one is last */ - phead = siter->bestnetheader; - while (phead != NULL) { - removed_scan_cnt++; - list_for_each_entry_safe(iter, next, - &phead->entry_list, list) { - list_del(&iter->list); - MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); - } - pprev = phead; - phead = phead->next; - MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); - } - if (phead == NULL) { - /* it is ok to delete top node */ - list_del(&siter->list); - MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); - } - } - return removed_scan_cnt; -} - -static int -_dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) -{ - int err = BCME_OK; - int i = 0; - wl_pfn_cfg_t pfncfg_param; - NULL_CHECK(dhd, "dhd is NULL", err); - if (nchan) { - NULL_CHECK(channel_list, "nchan is NULL", err); - } - if (nchan > WL_NUMCHANNELS) { - return BCME_RANGE; - } - DHD_PNO(("%s enter : nchan : %d\n", __FUNCTION__, nchan)); - memset(&pfncfg_param, 0, sizeof(wl_pfn_cfg_t)); - /* Setup default values */ - pfncfg_param.reporttype = htod32(WL_PFN_REPORT_ALLNET); - pfncfg_param.channel_num = htod32(0); - - for (i = 0; i < nchan; i++) - pfncfg_param.channel_list[i] = channel_list[i]; - - pfncfg_param.channel_num = htod32(nchan); - err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), NULL, 0, - TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); - goto exit; - } -exit: - return err; -} -static int -_dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL\n", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL\n", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - mutex_lock(&_pno_state->pno_mutex); - switch (mode) { - case DHD_PNO_LEGACY_MODE: { - struct dhd_pno_ssid *iter, *next; - if (params->params_legacy.nssid > 0) { - list_for_each_entry_safe(iter, next, - ¶ms->params_legacy.ssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - params->params_legacy.nssid = 0; - params->params_legacy.scan_fr = 0; - params->params_legacy.pno_freq_expo_max = 0; - params->params_legacy.pno_repeat = 0; - params->params_legacy.nchan = 0; - memset(params->params_legacy.chan_list, 0, - sizeof(params->params_legacy.chan_list)); - break; - } - case DHD_PNO_BATCH_MODE: { - params->params_batch.scan_fr = 0; - params->params_batch.mscan = 0; - params->params_batch.nchan = 0; - params->params_batch.rtt = 0; - params->params_batch.bestn = 0; - params->params_batch.nchan = 0; - params->params_batch.band = WLC_BAND_AUTO; - memset(params->params_batch.chan_list, 0, - sizeof(params->params_batch.chan_list)); - params->params_batch.get_batch.batch_started = FALSE; - params->params_batch.get_batch.buf = NULL; - params->params_batch.get_batch.bufsize = 0; - params->params_batch.get_batch.reason = 0; - _dhd_pno_clear_all_batch_results(dhd, - ¶ms->params_batch.get_batch.scan_results_list, FALSE); - _dhd_pno_clear_all_batch_results(dhd, - ¶ms->params_batch.get_batch.expired_scan_results_list, FALSE); - params->params_batch.get_batch.tot_scan_cnt = 0; - params->params_batch.get_batch.expired_tot_scan_cnt = 0; - params->params_batch.get_batch.top_node_cnt = 0; - INIT_LIST_HEAD(¶ms->params_batch.get_batch.scan_results_list); - INIT_LIST_HEAD(¶ms->params_batch.get_batch.expired_scan_results_list); - break; - } - case DHD_PNO_HOTLIST_MODE: { - struct dhd_pno_bssid *iter, *next; - if (params->params_hotlist.nbssid > 0) { - list_for_each_entry_safe(iter, next, - ¶ms->params_hotlist.bssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - params->params_hotlist.scan_fr = 0; - params->params_hotlist.nbssid = 0; - params->params_hotlist.nchan = 0; - params->params_batch.band = WLC_BAND_AUTO; - memset(params->params_hotlist.chan_list, 0, - sizeof(params->params_hotlist.chan_list)); - break; - } - default: - DHD_ERROR(("%s : unknown mode : %d\n", __FUNCTION__, mode)); - break; - } - mutex_unlock(&_pno_state->pno_mutex); - return err; -} -static int -_dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - if (nbssid) { - NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); - } - err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)p_pfn_bssid, - sizeof(wl_pfn_bssid_t) * nbssid, NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); - goto exit; - } -exit: - return err; -} - -int -dhd_pno_stop_for_ssid(dhd_pub_t *dhd) -{ - int err = BCME_OK; - uint32 mode = 0; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - wl_pfn_bssid_t *p_pfn_bssid = NULL; - NULL_CHECK(dhd, "dev is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { - DHD_ERROR(("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__)); - goto exit; - } - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - struct dhd_pno_gscan_params *gscan_params; - - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - gscan_params = &_params->params_gscan; - if (gscan_params->mscan) { - /* retrieve the batching data from firmware into host */ - err = dhd_wait_batch_results_complete(dhd); - if (err != BCME_OK) - goto exit; - } - /* save current pno_mode before calling dhd_pno_clean */ - mutex_lock(&_pno_state->pno_mutex); - mode = _pno_state->pno_mode; - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - mutex_unlock(&_pno_state->pno_mutex); - goto exit; - } - /* restore previous pno_mode */ - _pno_state->pno_mode = mode; - mutex_unlock(&_pno_state->pno_mutex); - /* Restart gscan */ - err = dhd_pno_initiate_gscan_request(dhd, 1, 0); - - goto exit; - } -#endif /* GSCAN_SUPPORT */ - - - /* restart Batch mode if the batch mode is on */ - if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { - /* retrieve the batching data from firmware into host */ - dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); - /* save current pno_mode before calling dhd_pno_clean */ - mode = _pno_state->pno_mode; - dhd_pno_clean(dhd); - /* restore previous pno_mode */ - _pno_state->pno_mode = mode; - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); - /* restart BATCH SCAN */ - err = dhd_pno_set_for_batch(dhd, &_params->params_batch); - if (err < 0) { - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - /* restart HOTLIST SCAN */ - struct dhd_pno_bssid *iter, *next; - _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * - _params->params_hotlist.nbssid, GFP_KERNEL); - if (p_pfn_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" - " (count: %d)", - __FUNCTION__, _params->params_hotlist.nbssid)); - err = BCME_ERROR; - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - goto exit; - } - /* convert dhd_pno_bssid to wl_pfn_bssid */ - list_for_each_entry_safe(iter, next, - &_params->params_hotlist.bssid_list, list) { - memcpy(&p_pfn_bssid->macaddr, - &iter->macaddr, ETHER_ADDR_LEN); - p_pfn_bssid->flags = iter->flags; - p_pfn_bssid++; - } - err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); - if (err < 0) { - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } - } else { - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } -exit: - if (p_pfn_bssid) - kfree(p_pfn_bssid); - return err; -} - -int -dhd_pno_enable(dhd_pub_t *dhd, int enable) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - return (_dhd_pno_enable(dhd, enable)); -} - -static -wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, - dhd_pno_status_info_t *pno_state) -{ - int err = BCME_OK; - int i; - struct dhd_pno_ssid *iter, *next; - dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; - wlc_ssid_ext_t *p_ssid_list; - - p_ssid_list = kzalloc(sizeof(wlc_ssid_ext_t) * - _params1->params_legacy.nssid, GFP_KERNEL); - if (p_ssid_list == NULL) { - DHD_ERROR(("%s : failed to allocate wlc_ssid_ext_t array (count: %d)", - __FUNCTION__, _params1->params_legacy.nssid)); - err = BCME_ERROR; - pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; - goto exit; - } - i = 0; - /* convert dhd_pno_ssid to wlc_ssid_ext_t */ - list_for_each_entry_safe(iter, next, &_params1->params_legacy.ssid_list, list) { - p_ssid_list[i].SSID_len = iter->SSID_len; - p_ssid_list[i].hidden = iter->hidden; - p_ssid_list[i].rssi_thresh = iter->rssi_thresh; - memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); - i++; - } -exit: - return p_ssid_list; -} - -#ifdef GSCAN_SUPPORT -static int dhd_epno_set_ssid(dhd_pub_t *dhd, - dhd_pno_status_info_t *pno_state) -{ - int err = BCME_OK; - dhd_epno_params_t *iter, *next; - dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - struct dhd_pno_gscan_params *gscan_params; - wlc_ssid_ext_t ssid_elem; - wl_pfn_ext_list_t *p_ssid_ext_elem = NULL; - uint32 mem_needed = 0, i = 0; - uint16 num_visible_epno_ssid; - uint8 flags; - - gscan_params = &_params1->params_gscan; - num_visible_epno_ssid = gscan_params->num_visible_epno_ssid; - - if (num_visible_epno_ssid) { - mem_needed = sizeof(wl_pfn_ext_list_t) + (sizeof(wl_pfn_ext_t) * - (num_visible_epno_ssid - 1)); - p_ssid_ext_elem = kzalloc(mem_needed, GFP_KERNEL); - if (p_ssid_ext_elem == NULL) { - DHD_ERROR(("%s : failed to allocate memory %u\n", - __FUNCTION__, mem_needed)); - err = BCME_NOMEM; - goto exit; - } - p_ssid_ext_elem->version = PFN_SSID_EXT_VERSION; - p_ssid_ext_elem->count = num_visible_epno_ssid; - } - - DHD_PNO(("Total ssids %d, visible SSIDs %d\n", gscan_params->num_epno_ssid, - num_visible_epno_ssid)); - - /* convert dhd_pno_ssid to wlc_ssid_ext_t */ - list_for_each_entry_safe(iter, next, &gscan_params->epno_ssid_list, list) { - if (iter->flags & DHD_PNO_USE_SSID) { - memset(&ssid_elem, 0, sizeof(ssid_elem)); - ssid_elem.SSID_len = iter->ssid_len; - ssid_elem.hidden = TRUE; - flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? - WL_PFN_SSID_A_BAND_TRIG: 0; - flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? - WL_PFN_SSID_BG_BAND_TRIG: 0; - ssid_elem.flags = flags; - ssid_elem.rssi_thresh = iter->rssi_thresh; - memcpy(ssid_elem.SSID, iter->ssid, iter->ssid_len); - if ((err = _dhd_pno_add_ssid(dhd, &ssid_elem, 1)) < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); - goto exit; - } - } else if (i < num_visible_epno_ssid) { - p_ssid_ext_elem->pfn_ext[i].rssi_thresh = iter->rssi_thresh; - switch (iter->auth) { - case DHD_PNO_AUTH_CODE_OPEN: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = WPA_AUTH_DISABLED; - break; - case DHD_PNO_AUTH_CODE_PSK: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = - (WPA2_AUTH_PSK | WPA_AUTH_PSK); - break; - case DHD_PNO_AUTH_CODE_EAPOL: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = - (uint16)WPA_AUTH_PFN_ANY; - break; - default: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = - (uint16)WPA_AUTH_PFN_ANY; - break; - } - memcpy(p_ssid_ext_elem->pfn_ext[i].ssid, iter->ssid, iter->ssid_len); - p_ssid_ext_elem->pfn_ext[i].ssid_len = iter->ssid_len; - iter->index = gscan_params->ssid_ext_last_used_index++; - flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? - WL_PFN_SSID_A_BAND_TRIG: 0; - flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? - WL_PFN_SSID_BG_BAND_TRIG: 0; - p_ssid_ext_elem->pfn_ext[i].flags = flags; - DHD_PNO(("SSID %s idx %d rssi thresh %d flags %x\n", iter->ssid, - iter->index, iter->rssi_thresh, flags)); - i++; - } - } - if (num_visible_epno_ssid) { - err = dhd_iovar(dhd, 0, "pfn_add_ssid_ext", (char *)p_ssid_ext_elem, - mem_needed, NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_add_pno_ext_ssid %d\n", __FUNCTION__, - err)); - } - } -exit: - kfree(p_ssid_ext_elem); - return err; -} -#endif /* GSCAN_SUPPORT */ - -static int -dhd_pno_add_to_ssid_list(dhd_pno_params_t *params, wlc_ssid_ext_t *ssid_list, - int nssid) -{ - int ret = 0; - int i; - struct dhd_pno_ssid *_pno_ssid; - - for (i = 0; i < nssid; i++) { - if (ssid_list[i].SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s : Invalid SSID length %d\n", - __FUNCTION__, ssid_list[i].SSID_len)); - ret = BCME_ERROR; - goto exit; - } - _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); - if (_pno_ssid == NULL) { - DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n", - __FUNCTION__)); - ret = BCME_ERROR; - goto exit; - } - _pno_ssid->SSID_len = ssid_list[i].SSID_len; - _pno_ssid->hidden = ssid_list[i].hidden; - _pno_ssid->rssi_thresh = ssid_list[i].rssi_thresh; - memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); - list_add_tail(&_pno_ssid->list, ¶ms->params_legacy.ssid_list); - params->params_legacy.nssid++; - } - -exit: - return ret; -} - -int -dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, - uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) -{ - dhd_pno_params_t *_params; - dhd_pno_params_t *_params2; - dhd_pno_status_info_t *_pno_state; - uint16 _chan_list[WL_NUMCHANNELS]; - int32 tot_nchan = 0; - int err = BCME_OK; - int i; - int mode = 0; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit_no_clear; - } - DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d," - "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, - scan_fr, pno_repeat, pno_freq_expo_max, nchan)); - - _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - /* If GSCAN is also ON will handle this down below */ -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE && - !(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { -#else - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { -#endif /* GSCAN_SUPPORT */ - DHD_ERROR(("%s : Legacy PNO mode was already started, " - "will disable previous one to start new one\n", __FUNCTION__)); - err = dhd_pno_stop_for_ssid(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to stop legacy PNO (err %d)\n", - __FUNCTION__, err)); - goto exit_no_clear; - } - } - _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; - err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); - if (err < 0) { - DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", - __FUNCTION__, err)); - goto exit_no_clear; - } - memset(_chan_list, 0, sizeof(_chan_list)); - tot_nchan = MIN(nchan, WL_NUMCHANNELS); - if (tot_nchan > 0 && channel_list) { - for (i = 0; i < tot_nchan; i++) - _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i]; - } -#ifdef GSCAN_SUPPORT - else { - tot_nchan = WL_NUMCHANNELS; - err = _dhd_pno_get_channels(dhd, _chan_list, &tot_nchan, - (WLC_BAND_2G | WLC_BAND_5G), FALSE); - if (err < 0) { - tot_nchan = 0; - DHD_PNO(("Could not get channel list for PNO SSID\n")); - } else { - for (i = 0; i < tot_nchan; i++) - _params->params_legacy.chan_list[i] = _chan_list[i]; - } - } -#endif /* GSCAN_SUPPORT */ - - if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { - DHD_PNO(("BATCH SCAN is on progress in firmware\n")); - /* retrieve the batching data from firmware into host */ - dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); - /* store current pno_mode before disabling pno */ - mode = _pno_state->pno_mode; - err = _dhd_pno_enable(dhd, PNO_OFF); - if (err < 0) { - DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - goto exit_no_clear; - } - /* restore the previous mode */ - _pno_state->pno_mode = mode; - /* use superset of channel list between two mode */ - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - _params2 = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); - if (_params2->params_batch.nchan > 0 && tot_nchan > 0) { - err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, - &_params2->params_batch.chan_list[0], - _params2->params_batch.nchan, - &channel_list[0], tot_nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to merge channel list" - " between legacy and batch\n", - __FUNCTION__)); - goto exit_no_clear; - } - } else { - DHD_PNO(("superset channel will use" - " all channels in firmware\n")); - } - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - _params2 = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - if (_params2->params_hotlist.nchan > 0 && tot_nchan > 0) { - err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, - &_params2->params_hotlist.chan_list[0], - _params2->params_hotlist.nchan, - &channel_list[0], tot_nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to merge channel list" - " between legacy and hotlist\n", - __FUNCTION__)); - goto exit_no_clear; - } - } - } - } - _params->params_legacy.scan_fr = scan_fr; - _params->params_legacy.pno_repeat = pno_repeat; - _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max; - _params->params_legacy.nchan = tot_nchan; - _params->params_legacy.nssid = 0; - INIT_LIST_HEAD(&_params->params_legacy.ssid_list); - -#ifdef GSCAN_SUPPORT - /* dhd_pno_initiate_gscan_request will handle simultaneous Legacy PNO and GSCAN */ - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { - err = BCME_ERROR; - goto exit; - } - DHD_PNO(("GSCAN mode is ON! Will restart GSCAN+Legacy PNO\n")); - err = dhd_pno_initiate_gscan_request(dhd, 1, 0); - goto exit; - } -#endif /* GSCAN_SUPPORT */ - if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_LEGACY_MODE)) < 0) { - DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); - goto exit; - } - if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { - DHD_ERROR(("failed to add ssid list(err %d), %d in firmware\n", err, nssid)); - goto exit; - } - if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { - err = BCME_ERROR; - goto exit; - } - if (tot_nchan > 0) { - if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { - DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - } - if (_pno_state->pno_status == DHD_PNO_DISABLED) { - if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) - DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); - } -exit: - if (err < 0) { - _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); - } -exit_no_clear: - /* clear mode in case of error */ - if (err < 0) { - int ret = dhd_pno_clean(dhd); - - if (ret < 0) { - DHD_ERROR(("%s : dhd_pno_clean failure (err: %d)\n", - __FUNCTION__, ret)); - } else { - _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; - } - } - return err; -} -int -dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) -{ - int err = BCME_OK; - uint16 _chan_list[WL_NUMCHANNELS]; - int rem_nchan = 0, tot_nchan = 0; - int mode = 0, mscan = 0; - dhd_pno_params_t *_params; - dhd_pno_params_t *_params2; - dhd_pno_status_info_t *_pno_state; - wlc_ssid_ext_t *p_ssid_list = NULL; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - NULL_CHECK(batch_params, "batch_params is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; - if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { - _pno_state->pno_mode |= DHD_PNO_BATCH_MODE; - err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", - __FUNCTION__)); - goto exit; - } - } else { - /* batch mode is already started */ - return -EBUSY; - } - _params->params_batch.scan_fr = batch_params->scan_fr; - _params->params_batch.bestn = batch_params->bestn; - _params->params_batch.mscan = (batch_params->mscan)? - batch_params->mscan : DEFAULT_BATCH_MSCAN; - _params->params_batch.nchan = batch_params->nchan; - memcpy(_params->params_batch.chan_list, batch_params->chan_list, - sizeof(_params->params_batch.chan_list)); - - memset(_chan_list, 0, sizeof(_chan_list)); - - rem_nchan = ARRAYSIZE(batch_params->chan_list) - batch_params->nchan; - if (batch_params->band == WLC_BAND_2G || batch_params->band == WLC_BAND_5G) { - /* get a valid channel list based on band B or A */ - err = _dhd_pno_get_channels(dhd, - &_params->params_batch.chan_list[batch_params->nchan], - &rem_nchan, batch_params->band, FALSE); - if (err < 0) { - DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", - __FUNCTION__, batch_params->band)); - goto exit; - } - /* now we need to update nchan because rem_chan has valid channel count */ - _params->params_batch.nchan += rem_nchan; - /* need to sort channel list */ - sort(_params->params_batch.chan_list, _params->params_batch.nchan, - sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL); - } -#ifdef PNO_DEBUG -{ - DHD_PNO(("Channel list : ")); - for (i = 0; i < _params->params_batch.nchan; i++) { - DHD_PNO(("%d ", _params->params_batch.chan_list[i])); - } - DHD_PNO(("\n")); -} -#endif - if (_params->params_batch.nchan) { - /* copy the channel list into local array */ - memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list)); - tot_nchan = _params->params_batch.nchan; - } - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - DHD_PNO(("PNO SSID is on progress in firmware\n")); - /* store current pno_mode before disabling pno */ - mode = _pno_state->pno_mode; - err = _dhd_pno_enable(dhd, PNO_OFF); - if (err < 0) { - DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - goto exit; - } - /* restore the previous mode */ - _pno_state->pno_mode = mode; - /* Use the superset for channelist between two mode */ - _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - if (_params2->params_legacy.nchan > 0 && _params->params_batch.nchan > 0) { - err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, - &_params2->params_legacy.chan_list[0], - _params2->params_legacy.nchan, - &_params->params_batch.chan_list[0], _params->params_batch.nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to merge channel list" - " between legacy and batch\n", - __FUNCTION__)); - goto exit; - } - } else { - DHD_PNO(("superset channel will use all channels in firmware\n")); - } - p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!p_ssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list, - _params2->params_legacy.nssid)) < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); - goto exit; - } - } - if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_BATCH_MODE)) < 0) { - DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } else { - /* we need to return mscan */ - mscan = err; - } - if (tot_nchan > 0) { - if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { - DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - } - if (_pno_state->pno_status == DHD_PNO_DISABLED) { - if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) - DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); - } -exit: - /* clear mode in case of error */ - if (err < 0) - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - else { - /* return #max scan firmware can do */ - err = mscan; - } - if (p_ssid_list) - kfree(p_ssid_list); - return err; -} - -#ifdef GSCAN_SUPPORT -static void dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params, - dhd_pno_status_info_t *_pno_state, uint8 flags) -{ - DHD_PNO(("%s enter\n", __FUNCTION__)); - - - if (flags & GSCAN_FLUSH_SCAN_CFG) { - _params->params_gscan.bestn = 0; - _params->params_gscan.mscan = 0; - _params->params_gscan.buffer_threshold = GSCAN_BATCH_NO_THR_SET; - _params->params_gscan.scan_fr = 0; - _params->params_gscan.send_all_results_flag = 0; - memset(_params->params_gscan.channel_bucket, 0, - _params->params_gscan.nchannel_buckets * - sizeof(struct dhd_pno_gscan_channel_bucket)); - _params->params_gscan.nchannel_buckets = 0; - DHD_PNO(("Flush Scan config\n")); - } - if (flags & GSCAN_FLUSH_HOTLIST_CFG) { - struct dhd_pno_bssid *iter, *next; - if (_params->params_gscan.nbssid_hotlist > 0) { - list_for_each_entry_safe(iter, next, - &_params->params_gscan.hotlist_bssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - _params->params_gscan.nbssid_hotlist = 0; - DHD_PNO(("Flush Hotlist Config\n")); - } - if (flags & GSCAN_FLUSH_EPNO_CFG) { - dhd_epno_params_t *iter, *next; - - if (_params->params_gscan.num_epno_ssid > 0) { - list_for_each_entry_safe(iter, next, - &_params->params_gscan.epno_ssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - _params->params_gscan.num_epno_ssid = 0; - _params->params_gscan.num_visible_epno_ssid = 0; - _params->params_gscan.ssid_ext_last_used_index = 0; - DHD_PNO(("Flushed ePNO Config\n")); - } - - return; -} - -int -dhd_pno_lock_batch_results(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - int err = BCME_OK; - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - mutex_lock(&_pno_state->pno_mutex); - return err; -} - -void -dhd_pno_unlock_batch_results(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - _pno_state = PNO_GET_PNOSTATE(dhd); - mutex_unlock(&_pno_state->pno_mutex); - return; -} - -int -dhd_wait_batch_results_complete(dhd_pub_t *dhd) -{ - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - int err = BCME_OK; - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - - /* Has the workqueue finished its job already?? */ - if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_IN_PROGRESS) { - DHD_PNO(("%s: Waiting to complete retrieval..\n", __FUNCTION__)); - wait_event_interruptible_timeout(_pno_state->batch_get_wait, - is_batch_retrieval_complete(&_params->params_gscan), - msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); - } else { /* GSCAN_BATCH_RETRIEVAL_COMPLETE */ - gscan_results_cache_t *iter; - uint16 num_results = 0; - - mutex_lock(&_pno_state->pno_mutex); - iter = _params->params_gscan.gscan_batch_cache; - while (iter) { - num_results += iter->tot_count - iter->tot_consumed; - iter = iter->next; - } - mutex_unlock(&_pno_state->pno_mutex); - - /* All results consumed/No results cached?? - * Get fresh results from FW - */ - if ((_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) && !num_results) { - DHD_PNO(("%s: No results cached, getting from FW..\n", __FUNCTION__)); - err = dhd_retreive_batch_scan_results(dhd); - if (err == BCME_OK) { - wait_event_interruptible_timeout(_pno_state->batch_get_wait, - is_batch_retrieval_complete(&_params->params_gscan), - msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); - } - } - } - DHD_PNO(("%s: Wait complete\n", __FUNCTION__)); - return err; -} - -static void * -dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len) -{ - gscan_results_cache_t *iter, *results; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - uint16 num_scan_ids = 0, num_results = 0; - - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - - iter = results = _params->params_gscan.gscan_batch_cache; - while (iter) { - num_results += iter->tot_count - iter->tot_consumed; - num_scan_ids++; - iter = iter->next; - } - - *len = ((num_results << 16) | (num_scan_ids)); - return results; -} - -void * -dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, - void *info, uint32 *len) -{ - void *ret = NULL; - dhd_pno_gscan_capabilities_t *ptr; - dhd_epno_params_t *epno_params; - dhd_pno_params_t *_params; - dhd_pno_status_info_t *_pno_state; - - if (!dhd || !dhd->pno_state) { - DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__)); - return NULL; - } - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - if (!len) { - DHD_ERROR(("%s: len is NULL\n", __FUNCTION__)); - return NULL; - } - - switch (type) { - case DHD_PNO_GET_CAPABILITIES: - ptr = (dhd_pno_gscan_capabilities_t *) - kmalloc(sizeof(dhd_pno_gscan_capabilities_t), GFP_KERNEL); - if (!ptr) - break; - /* Hardcoding these values for now, need to get - * these values from FW, will change in a later check-in - */ - ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE; - ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS; - ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; - ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX; - ptr->max_scan_reporting_threshold = 100; - ptr->max_hotlist_bssids = PFN_HOTLIST_MAX_NUM_APS; - ptr->max_hotlist_ssids = 0; - ptr->max_significant_wifi_change_aps = 0; - ptr->max_bssid_history_entries = 0; - ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; - ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; - ptr->max_white_list_ssid = MAX_WHITELIST_SSID; - ret = (void *)ptr; - *len = sizeof(dhd_pno_gscan_capabilities_t); - break; - - case DHD_PNO_GET_BATCH_RESULTS: - ret = dhd_get_gscan_batch_results(dhd, len); - break; - case DHD_PNO_GET_CHANNEL_LIST: - if (info) { - uint16 ch_list[WL_NUMCHANNELS]; - uint32 *ptr, mem_needed, i; - int32 err, nchan = WL_NUMCHANNELS; - uint32 *gscan_band = (uint32 *) info; - uint8 band = 0; - - /* No band specified?, nothing to do */ - if ((*gscan_band & GSCAN_BAND_MASK) == 0) { - DHD_PNO(("No band specified\n")); - *len = 0; - break; - } - - /* HAL and DHD use different bits for 2.4G and - * 5G in bitmap. Hence translating it here... - */ - if (*gscan_band & GSCAN_BG_BAND_MASK) { - band |= WLC_BAND_2G; - } - if (*gscan_band & GSCAN_A_BAND_MASK) { - band |= WLC_BAND_5G; - } - - err = _dhd_pno_get_channels(dhd, ch_list, &nchan, - (band & GSCAN_ABG_BAND_MASK), - !(*gscan_band & GSCAN_DFS_MASK)); - - if (err < 0) { - DHD_ERROR(("%s: failed to get valid channel list\n", - __FUNCTION__)); - *len = 0; - } else { - mem_needed = sizeof(uint32) * nchan; - ptr = (uint32 *) kmalloc(mem_needed, GFP_KERNEL); - if (!ptr) { - DHD_ERROR(("%s: Unable to malloc %d bytes\n", - __FUNCTION__, mem_needed)); - break; - } - for (i = 0; i < nchan; i++) { - ptr[i] = wf_channel2mhz(ch_list[i], - (ch_list[i] <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - } - ret = ptr; - *len = mem_needed; - } - } else { - *len = 0; - DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__)); - } - break; - case DHD_PNO_GET_EPNO_SSID_ELEM: - if (_params->params_gscan.num_epno_ssid >= - (MAX_EPNO_SSID_NUM + MAX_EPNO_HIDDEN_SSID)) { - DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n", - _params->params_gscan.num_epno_ssid)); - return NULL; - } - - if (!_params->params_gscan.num_epno_ssid) - INIT_LIST_HEAD(&_params->params_gscan.epno_ssid_list); - - epno_params = kzalloc(sizeof(dhd_epno_params_t), GFP_KERNEL); - if (!epno_params) { - DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes", - sizeof(dhd_epno_params_t))); - return NULL; - } - _params->params_gscan.num_epno_ssid++; - epno_params->index = DHD_EPNO_DEFAULT_INDEX; - list_add_tail(&epno_params->list, &_params->params_gscan.epno_ssid_list); - ret = epno_params; - default: - DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); - break; - } - - return ret; -} - -int -dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, - void *buf, uint8 flush) -{ - int err = BCME_OK; - dhd_pno_params_t *_params; - int i; - dhd_pno_status_info_t *_pno_state; - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - mutex_lock(&_pno_state->pno_mutex); - - switch (type) { - case DHD_PNO_BATCH_SCAN_CFG_ID: - { - gscan_batch_params_t *ptr = (gscan_batch_params_t *)buf; - _params->params_gscan.bestn = ptr->bestn; - _params->params_gscan.mscan = ptr->mscan; - _params->params_gscan.buffer_threshold = ptr->buffer_threshold; - } - break; - case DHD_PNO_GEOFENCE_SCAN_CFG_ID: - { - gscan_hotlist_scan_params_t *ptr = - (gscan_hotlist_scan_params_t *)buf; - struct dhd_pno_bssid *_pno_bssid; - struct bssid_t *bssid_ptr; - int8 flags; - - if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, - GSCAN_FLUSH_HOTLIST_CFG); - } - - if (!ptr->nbssid) - break; - - if (!_params->params_gscan.nbssid_hotlist) - INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list); - - if ((_params->params_gscan.nbssid_hotlist + - ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { - DHD_ERROR(("Excessive number of hotlist APs programmed " - "%d\n", (_params->params_gscan.nbssid_hotlist + - ptr->nbssid))); - err = BCME_RANGE; - goto exit; - } - - for (i = 0, bssid_ptr = ptr->bssid; i < ptr->nbssid; i++, - bssid_ptr++) { - _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), - GFP_KERNEL); - - if (!_pno_bssid) { - DHD_ERROR(("_pno_bssid is NULL, cannot kalloc " - "%zd bytes", - sizeof(struct dhd_pno_bssid))); - err = BCME_NOMEM; - goto exit; - } - memcpy(&_pno_bssid->macaddr, &bssid_ptr->macaddr, - ETHER_ADDR_LEN); - - flags = (int8) bssid_ptr->rssi_reporting_threshold; - _pno_bssid->flags = flags << WL_PFN_RSSI_SHIFT; - list_add_tail(&_pno_bssid->list, - &_params->params_gscan.hotlist_bssid_list); - } - - _params->params_gscan.nbssid_hotlist += ptr->nbssid; - _params->params_gscan.lost_ap_window = ptr->lost_ap_window; - } - break; - case DHD_PNO_SCAN_CFG_ID: - { - int i, k; - uint16 band; - gscan_scan_params_t *ptr = (gscan_scan_params_t *)buf; - struct dhd_pno_gscan_channel_bucket *ch_bucket; - - if (ptr->nchannel_buckets <= GSCAN_MAX_CH_BUCKETS) { - _params->params_gscan.nchannel_buckets = - ptr->nchannel_buckets; - - memcpy(_params->params_gscan.channel_bucket, - ptr->channel_bucket, - _params->params_gscan.nchannel_buckets * - sizeof(struct dhd_pno_gscan_channel_bucket)); - ch_bucket = _params->params_gscan.channel_bucket; - - for (i = 0; i < ptr->nchannel_buckets; i++) { - band = ch_bucket[i].band; - for (k = 0; k < ptr->channel_bucket[i].num_channels; - k++) { - ch_bucket[i].chan_list[k] = - wf_mhz2channel( - ptr->channel_bucket[i].chan_list[k], - 0); - } - ch_bucket[i].band = 0; - /* HAL and DHD use different bits for 2.4G and - * 5G in bitmap. Hence translating it here... - */ - if (band & GSCAN_BG_BAND_MASK) - ch_bucket[i].band |= WLC_BAND_2G; - if (band & GSCAN_A_BAND_MASK) - ch_bucket[i].band |= WLC_BAND_5G; - if (band & GSCAN_DFS_MASK) - ch_bucket[i].band |= GSCAN_DFS_MASK; - - DHD_PNO(("band %d report_flag %d\n", - ch_bucket[i].band, - ch_bucket[i].report_flag)); - } - - for (i = 0; i < ptr->nchannel_buckets; i++) { - ch_bucket[i].bucket_freq_multiple = - ch_bucket[i].bucket_freq_multiple/ptr->scan_fr; - ch_bucket[i].bucket_max_multiple = - ch_bucket[i].bucket_max_multiple/ptr->scan_fr; - DHD_PNO(("mult %d max_mult %d\n", - ch_bucket[i].bucket_freq_multiple, - ch_bucket[i].bucket_max_multiple)); - } - _params->params_gscan.scan_fr = ptr->scan_fr; - - DHD_PNO(("num_buckets %d scan_fr %d\n", - ptr->nchannel_buckets, - _params->params_gscan.scan_fr)); - } else { - err = BCME_BADARG; - } - } - break; - case DHD_PNO_EPNO_CFG_ID: - if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, - GSCAN_FLUSH_EPNO_CFG); - } else { - _params->params_gscan.num_visible_epno_ssid += *((uint16 *)buf); - } - break; - default: - err = BCME_BADARG; - DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); - break; - } -exit: - mutex_unlock(&_pno_state->pno_mutex); - return err; - -} - -static bool -validate_gscan_params(struct dhd_pno_gscan_params *gscan_params) -{ - unsigned int i, k; - - if (!gscan_params->scan_fr || !gscan_params->nchannel_buckets) { - DHD_ERROR(("%s : Scan freq - %d or number of channel buckets - %d is empty\n", - __FUNCTION__, gscan_params->scan_fr, gscan_params->nchannel_buckets)); - return false; - } - - for (i = 0; i < gscan_params->nchannel_buckets; i++) { - if (!gscan_params->channel_bucket[i].band) { - for (k = 0; k < gscan_params->channel_bucket[i].num_channels; k++) { - if (gscan_params->channel_bucket[i].chan_list[k] > CHANNEL_5G_MAX) { - DHD_ERROR(("%s : Unknown channel %d\n", __FUNCTION__, - gscan_params->channel_bucket[i].chan_list[k])); - return false; - } - } - } - } - - return true; -} - -static int -dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) -{ - int err = BCME_OK; - int mode, i = 0, k; - uint16 _chan_list[WL_NUMCHANNELS]; - int tot_nchan = 0; - int num_buckets_to_fw, tot_num_buckets, gscan_param_size; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL; - wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL; - wl_pfn_bssid_t *p_pfn_bssid = NULL; - wlc_ssid_ext_t *pssid_list = NULL; - dhd_pno_params_t *params_legacy; - dhd_pno_params_t *_params; - - params_legacy = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - NULL_CHECK(gscan_params, "gscan_params is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - - if (!validate_gscan_params(gscan_params)) { - DHD_ERROR(("%s : Cannot start gscan - bad params\n", __FUNCTION__)); - err = BCME_BADARG; - goto exit; - } - /* Create channel list based on channel buckets */ - if (!(ch_bucket = dhd_pno_gscan_create_channel_list(dhd, _pno_state, - _chan_list, &tot_num_buckets, &num_buckets_to_fw))) { - goto exit; - } - - mutex_lock(&_pno_state->pno_mutex); - /* Clear any pre-existing results in our cache - * not consumed by framework - */ - dhd_gscan_clear_all_batch_results(dhd); - if (_pno_state->pno_mode & (DHD_PNO_GSCAN_MODE | DHD_PNO_LEGACY_MODE)) { - /* store current pno_mode before disabling pno */ - mode = _pno_state->pno_mode; - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - mutex_unlock(&_pno_state->pno_mutex); - goto exit; - } - /* restore the previous mode */ - _pno_state->pno_mode = mode; - } - _pno_state->pno_mode |= DHD_PNO_GSCAN_MODE; - mutex_unlock(&_pno_state->pno_mutex); - - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - - if (!pssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - - if ((err = _dhd_pno_add_ssid(dhd, pssid_list, - params_legacy->params_legacy.nssid)) < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); - goto exit; - } - } - - if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_GSCAN_MODE)) < 0) { - DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); - goto exit; - } - - gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + - (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); - pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size); - - if (!pfn_gscan_cfg_t) { - DHD_ERROR(("%s: failed to malloc memory of size %d\n", - __FUNCTION__, gscan_param_size)); - err = BCME_NOMEM; - goto exit; - } - - pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION; - if (gscan_params->mscan) { - pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold; - } else { - pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; - } - - pfn_gscan_cfg_t->flags = - (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); - pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw; - pfn_gscan_cfg_t->retry_threshold = GSCAN_RETRY_THRESHOLD; - - for (i = 0, k = 0; i < tot_num_buckets; i++) { - if (ch_bucket[i].bucket_end_index != CHANNEL_BUCKET_EMPTY_INDEX) { - pfn_gscan_cfg_t->channel_bucket[k].bucket_end_index = - ch_bucket[i].bucket_end_index; - pfn_gscan_cfg_t->channel_bucket[k].bucket_freq_multiple = - ch_bucket[i].bucket_freq_multiple; - pfn_gscan_cfg_t->channel_bucket[k].max_freq_multiple = - ch_bucket[i].max_freq_multiple; - pfn_gscan_cfg_t->channel_bucket[k].repeat = - ch_bucket[i].repeat; - pfn_gscan_cfg_t->channel_bucket[k].flag = - ch_bucket[i].flag; - k++; - } - } - - tot_nchan = pfn_gscan_cfg_t->channel_bucket[num_buckets_to_fw - 1].bucket_end_index + 1; - DHD_PNO(("Total channel num %d total ch_buckets %d ch_buckets_to_fw %d \n", tot_nchan, - tot_num_buckets, num_buckets_to_fw)); - - if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { - DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - - if ((err = _dhd_pno_gscan_cfg(dhd, pfn_gscan_cfg_t, gscan_param_size)) < 0) { - DHD_ERROR(("%s : failed to set call pno_gscan_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - - if (gscan_params->nbssid_hotlist) { - struct dhd_pno_bssid *iter, *next; - wl_pfn_bssid_t *ptr; - p_pfn_bssid = (wl_pfn_bssid_t *)kzalloc(sizeof(wl_pfn_bssid_t) * - gscan_params->nbssid_hotlist, GFP_KERNEL); - if (p_pfn_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" - " (count: %d)", - __FUNCTION__, _params->params_hotlist.nbssid)); - err = BCME_NOMEM; - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - goto exit; - } - ptr = p_pfn_bssid; - /* convert dhd_pno_bssid to wl_pfn_bssid */ - DHD_PNO(("nhotlist %d\n", gscan_params->nbssid_hotlist)); - list_for_each_entry_safe(iter, next, - &gscan_params->hotlist_bssid_list, list) { - memcpy(&ptr->macaddr, - &iter->macaddr, ETHER_ADDR_LEN); - ptr->flags = iter->flags; - ptr++; - } - - err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, gscan_params->nbssid_hotlist); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", - __FUNCTION__, err)); - goto exit; - } - } - - if (gscan_params->num_epno_ssid > 0) { - DHD_PNO(("num_epno_ssid %d\n", gscan_params->num_epno_ssid)); - err = dhd_epno_set_ssid(dhd, _pno_state); - if (err < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); - goto exit; - } - } - - if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) { - DHD_ERROR(("%s : failed to enable PNO err %d\n", __FUNCTION__, err)); - } - -exit: - /* clear mode in case of error */ - if (err < 0) { - int ret = dhd_pno_clean(dhd); - - if (ret < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, ret)); - } else { - _pno_state->pno_mode &= ~DHD_PNO_GSCAN_MODE; - } - } - kfree(pssid_list); - kfree(p_pfn_bssid); - if (pfn_gscan_cfg_t) { - MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size); - } - if (ch_bucket) { - MFREE(dhd->osh, ch_bucket, - (tot_num_buckets * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); - } - return err; -} - -static wl_pfn_gscan_ch_bucket_cfg_t * -dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, - dhd_pno_status_info_t *_pno_state, - uint16 *chan_list, - uint32 *num_buckets, - uint32 *num_buckets_to_fw) -{ - int i, num_channels, err, nchan = WL_NUMCHANNELS, ch_cnt; - uint16 *ptr = chan_list, max; - wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket; - dhd_pno_params_t *_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - bool is_pno_legacy_running = _pno_state->pno_mode & DHD_PNO_LEGACY_MODE; - dhd_pno_gscan_channel_bucket_t *gscan_buckets = _params->params_gscan.channel_bucket; - - if (is_pno_legacy_running) - *num_buckets = _params->params_gscan.nchannel_buckets + 1; - else - *num_buckets = _params->params_gscan.nchannel_buckets; - - *num_buckets_to_fw = 0; - - ch_bucket = (wl_pfn_gscan_ch_bucket_cfg_t *) MALLOC(dhd->osh, - ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); - - if (!ch_bucket) { - DHD_ERROR(("%s: failed to malloc memory of size %zd\n", - __FUNCTION__, (*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); - *num_buckets_to_fw = *num_buckets = 0; - return NULL; - } - - max = gscan_buckets[0].bucket_freq_multiple; - num_channels = 0; - /* nchan is the remaining space left in chan_list buffer - * So any overflow list of channels is ignored - */ - for (i = 0; i < _params->params_gscan.nchannel_buckets && nchan; i++) { - if (!gscan_buckets[i].band) { - ch_cnt = MIN(gscan_buckets[i].num_channels, (uint8)nchan); - num_channels += ch_cnt; - memcpy(ptr, gscan_buckets[i].chan_list, - ch_cnt * sizeof(uint16)); - ptr = ptr + ch_cnt; - } else { - /* get a valid channel list based on band B or A */ - err = _dhd_pno_get_channels(dhd, ptr, - &nchan, (gscan_buckets[i].band & GSCAN_ABG_BAND_MASK), - !(gscan_buckets[i].band & GSCAN_DFS_MASK)); - - if (err < 0) { - DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", - __FUNCTION__, gscan_buckets[i].band)); - MFREE(dhd->osh, ch_bucket, - ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); - *num_buckets_to_fw = *num_buckets = 0; - return NULL; - } - - num_channels += nchan; - ptr = ptr + nchan; - } - - ch_bucket[i].bucket_end_index = num_channels - 1; - ch_bucket[i].bucket_freq_multiple = gscan_buckets[i].bucket_freq_multiple; - ch_bucket[i].repeat = gscan_buckets[i].repeat; - ch_bucket[i].max_freq_multiple = gscan_buckets[i].bucket_max_multiple; - ch_bucket[i].flag = gscan_buckets[i].report_flag; - /* HAL and FW interpretations are opposite for this bit */ - ch_bucket[i].flag ^= DHD_PNO_REPORT_NO_BATCH; - if (max < gscan_buckets[i].bucket_freq_multiple) - max = gscan_buckets[i].bucket_freq_multiple; - nchan = WL_NUMCHANNELS - num_channels; - *num_buckets_to_fw = *num_buckets_to_fw + 1; - DHD_PNO(("end_idx %d freq_mult - %d\n", - ch_bucket[i].bucket_end_index, ch_bucket[i].bucket_freq_multiple)); - } - - _params->params_gscan.max_ch_bucket_freq = max; - /* Legacy PNO maybe running, which means we need to create a legacy PNO bucket - * Get GCF of Legacy PNO and Gscan scanfreq - */ - if (is_pno_legacy_running) { - dhd_pno_params_t *_params1 = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; - uint16 *legacy_chan_list = _params1->params_legacy.chan_list; - uint16 common_freq; - uint32 legacy_bucket_idx = _params->params_gscan.nchannel_buckets; - /* If no space is left then only the gscan buckets will be sent to FW */ - if (nchan) { - common_freq = gcd(_params->params_gscan.scan_fr, - _params1->params_legacy.scan_fr); - max = gscan_buckets[0].bucket_freq_multiple; - /* GSCAN buckets */ - for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) { - ch_bucket[i].bucket_freq_multiple *= _params->params_gscan.scan_fr; - ch_bucket[i].bucket_freq_multiple /= common_freq; - if (max < gscan_buckets[i].bucket_freq_multiple) - max = gscan_buckets[i].bucket_freq_multiple; - } - /* Legacy PNO bucket */ - ch_bucket[legacy_bucket_idx].bucket_freq_multiple = - _params1->params_legacy.scan_fr; - ch_bucket[legacy_bucket_idx].bucket_freq_multiple /= - common_freq; - _params->params_gscan.max_ch_bucket_freq = MAX(max, - ch_bucket[legacy_bucket_idx].bucket_freq_multiple); - ch_bucket[legacy_bucket_idx].flag = CH_BUCKET_REPORT_REGULAR; - /* Now add channels to the legacy scan bucket */ - for (i = 0; i < _params1->params_legacy.nchan && nchan; i++, nchan--) { - ptr[i] = legacy_chan_list[i]; - num_channels++; - } - ch_bucket[legacy_bucket_idx].bucket_end_index = num_channels - 1; - *num_buckets_to_fw = *num_buckets_to_fw + 1; - DHD_PNO(("end_idx %d freq_mult - %d\n", - ch_bucket[legacy_bucket_idx].bucket_end_index, - ch_bucket[legacy_bucket_idx].bucket_freq_multiple)); - } - } - return ch_bucket; -} - -static int -dhd_pno_stop_for_gscan(dhd_pub_t *dhd) -{ - int err = BCME_OK; - int mode; - dhd_pno_status_info_t *_pno_state; - wlc_ssid_ext_t *pssid_list = NULL; - - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", - __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - - if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { - DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); - goto exit; - } - if (_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.mscan) { - /* retrieve the batching data from firmware into host */ - err = dhd_wait_batch_results_complete(dhd); - if (err != BCME_OK) - goto exit; - } - mutex_lock(&_pno_state->pno_mutex); - mode = _pno_state->pno_mode & ~DHD_PNO_GSCAN_MODE; - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - mutex_unlock(&_pno_state->pno_mutex); - return err; - } - _pno_state->pno_mode = mode; - mutex_unlock(&_pno_state->pno_mutex); - _pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.ssid_ext_last_used_index = 0; - - /* Reprogram Legacy PNO if it was running */ - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - struct dhd_pno_legacy_params *params_legacy; - uint16 chan_list[WL_NUMCHANNELS]; - - params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; - pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!pssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - - DHD_PNO(("Restarting Legacy PNO SSID scan...\n")); - memcpy(chan_list, params_legacy->chan_list, - (params_legacy->nchan * sizeof(uint16))); - err = dhd_pno_set_for_ssid(dhd, pssid_list, params_legacy->nssid, - params_legacy->scan_fr, params_legacy->pno_repeat, - params_legacy->pno_freq_expo_max, chan_list, - params_legacy->nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - - } - -exit: - kfree(pssid_list); - return err; -} - -int -dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush) -{ - int err = BCME_OK; - dhd_pno_params_t *params; - dhd_pno_status_info_t *_pno_state; - struct dhd_pno_gscan_params *gscan_params; - - NULL_CHECK(dhd, "dhd is NULL\n", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - DHD_ERROR(("%s enter - run %d flush %d\n", __FUNCTION__, run, flush)); - - params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - gscan_params = ¶ms->params_gscan; - - if (run) { - err = dhd_pno_set_for_gscan(dhd, gscan_params); - } else { - if (flush) { - mutex_lock(&_pno_state->pno_mutex); - dhd_pno_reset_cfg_gscan(params, _pno_state, GSCAN_FLUSH_ALL_CFG); - mutex_unlock(&_pno_state->pno_mutex); - } - /* Need to stop all gscan */ - err = dhd_pno_stop_for_gscan(dhd); - } - - return err; -} - -int -dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag) -{ - int err = BCME_OK; - dhd_pno_params_t *params; - dhd_pno_status_info_t *_pno_state; - struct dhd_pno_gscan_params *gscan_params; - uint8 old_flag; - - NULL_CHECK(dhd, "dhd is NULL\n", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - - params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - gscan_params = ¶ms->params_gscan; - - mutex_lock(&_pno_state->pno_mutex); - - old_flag = gscan_params->send_all_results_flag; - gscan_params->send_all_results_flag = (uint8) real_time_flag; - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - if (old_flag != gscan_params->send_all_results_flag) { - wl_pfn_gscan_cfg_t gscan_cfg; - gscan_cfg.version = WL_GSCAN_CFG_VERSION; - gscan_cfg.flags = (gscan_params->send_all_results_flag & - GSCAN_SEND_ALL_RESULTS_MASK); - gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK; - - if ((err = _dhd_pno_gscan_cfg(dhd, &gscan_cfg, - sizeof(wl_pfn_gscan_cfg_t))) < 0) { - DHD_ERROR(("%s : pno_gscan_cfg failed (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit_mutex_unlock; - } - } else { - DHD_PNO(("No change in flag - %d\n", old_flag)); - } - } else { - DHD_PNO(("Gscan not started\n")); - } -exit_mutex_unlock: - mutex_unlock(&_pno_state->pno_mutex); -exit: - return err; -} - -/* Cleanup any consumed results - * Return TRUE if all results consumed, else FALSE - */ -int -dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd) -{ - int ret = 0; - dhd_pno_params_t *params; - struct dhd_pno_gscan_params *gscan_params; - dhd_pno_status_info_t *_pno_state; - gscan_results_cache_t *iter, *tmp; - - _pno_state = PNO_GET_PNOSTATE(dhd); - params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - gscan_params = ¶ms->params_gscan; - iter = gscan_params->gscan_batch_cache; - - while (iter) { - if (iter->tot_consumed == iter->tot_count) { - tmp = iter->next; - kfree(iter); - iter = tmp; - } else - break; - } - gscan_params->gscan_batch_cache = iter; - ret = (iter == NULL); - return ret; -} - -static int -_dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) -{ - int err = BCME_OK; - uint32 timestamp = 0, ts = 0, i, j, timediff; - dhd_pno_params_t *params; - dhd_pno_status_info_t *_pno_state; - wl_pfn_lnet_info_t *plnetinfo; - struct dhd_pno_gscan_params *gscan_params; - wl_pfn_lscanresults_t *plbestnet = NULL; - gscan_results_cache_t *iter, *tail; - wifi_gscan_result_t *result; - uint8 *nAPs_per_scan = NULL; - uint8 num_scans_in_cur_iter; - uint16 count; - - NULL_CHECK(dhd, "dhd is NULL\n", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - - _pno_state = PNO_GET_PNOSTATE(dhd); - params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { - DHD_ERROR(("%s: GSCAN is not enabled\n", __FUNCTION__)); - goto exit; - } - gscan_params = ¶ms->params_gscan; - nAPs_per_scan = (uint8 *) MALLOC(dhd->osh, gscan_params->mscan); - - if (!nAPs_per_scan) { - DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, - gscan_params->mscan)); - err = BCME_NOMEM; - goto exit; - } - - plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); - if (!plbestnet) { - DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, - PNO_BESTNET_LEN)); - err = BCME_NOMEM; - goto exit; - } - - mutex_lock(&_pno_state->pno_mutex); - - dhd_gscan_clear_all_batch_results(dhd); - - if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { - DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); - goto exit_mutex_unlock; - } - - timediff = gscan_params->scan_fr * 1000; - timediff = timediff >> 1; - - /* Ok, now lets start getting results from the FW */ - plbestnet->status = PFN_INCOMPLETE; - tail = gscan_params->gscan_batch_cache; - while (plbestnet->status != PFN_COMPLETE) { - err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN, - FALSE); - if (err < 0) { - DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n", - __FUNCTION__, err)); - goto exit_mutex_unlock; - } - DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, - plbestnet->status, plbestnet->count)); - if (plbestnet->version != PFN_SCANRESULT_VERSION) { - err = BCME_VERSION; - DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", - plbestnet->version, PFN_SCANRESULT_VERSION)); - goto exit_mutex_unlock; - } - if (plbestnet->count == 0) { - DHD_PNO(("No more batch results\n")); - goto exit_mutex_unlock; - } - num_scans_in_cur_iter = 0; - timestamp = plbestnet->netinfo[0].timestamp; - /* find out how many scans' results did we get in this batch of FW results */ - for (i = 0, count = 0; i < plbestnet->count; i++, count++) { - plnetinfo = &plbestnet->netinfo[i]; - /* Unlikely to happen, but just in case the results from - * FW doesnt make sense..... Assume its part of one single scan - */ - if (num_scans_in_cur_iter > gscan_params->mscan) { - num_scans_in_cur_iter = 0; - count = plbestnet->count; - break; - } - if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) { - nAPs_per_scan[num_scans_in_cur_iter] = count; - count = 0; - num_scans_in_cur_iter++; - } - timestamp = plnetinfo->timestamp; - } - nAPs_per_scan[num_scans_in_cur_iter] = count; - num_scans_in_cur_iter++; - - DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter)); - plnetinfo = &plbestnet->netinfo[0]; - - for (i = 0; i < num_scans_in_cur_iter; i++) { - iter = (gscan_results_cache_t *) - kmalloc(((nAPs_per_scan[i] - 1) * sizeof(wifi_gscan_result_t)) + - sizeof(gscan_results_cache_t), GFP_KERNEL); - if (!iter) { - DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", - __FUNCTION__, gscan_params->mscan)); - err = BCME_NOMEM; - goto exit_mutex_unlock; - } - /* Need this check because the new set of results from FW - * maybe a continuation of previous sets' scan results - */ - if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) { - iter->scan_id = ++gscan_params->scan_id; - } else { - iter->scan_id = gscan_params->scan_id; - } - DHD_PNO(("scan_id %d tot_count %d\n", gscan_params->scan_id, - nAPs_per_scan[i])); - iter->tot_count = nAPs_per_scan[i]; - iter->tot_consumed = 0; - iter->flag = 0; - if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { - DHD_PNO(("This scan is aborted\n")); - iter->flag = (ENABLE << PNO_STATUS_ABORT); - } else if (gscan_params->reason) { - iter->flag = (ENABLE << gscan_params->reason); - } - - if (!tail) { - gscan_params->gscan_batch_cache = iter; - } else { - tail->next = iter; - } - tail = iter; - iter->next = NULL; - for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) { - result = &iter->results[j]; - - result->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, - (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - result->rssi = (int32) plnetinfo->RSSI; - /* Info not available & not expected */ - result->beacon_period = 0; - result->capability = 0; - result->ie_length = 0; - result->rtt = (uint64) plnetinfo->rtt0; - result->rtt_sd = (uint64) plnetinfo->rtt1; - result->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); - ts = plnetinfo->timestamp; - if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s: Invalid SSID length %d\n", - __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); - plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; - } - memcpy(result->ssid, plnetinfo->pfnsubnet.SSID, - plnetinfo->pfnsubnet.SSID_len); - result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; - memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID, - ETHER_ADDR_LEN); - - DHD_PNO(("\tSSID : ")); - DHD_PNO(("\n")); - DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", - result->macaddr.octet[0], - result->macaddr.octet[1], - result->macaddr.octet[2], - result->macaddr.octet[3], - result->macaddr.octet[4], - result->macaddr.octet[5])); - DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", - plnetinfo->pfnsubnet.channel, - plnetinfo->RSSI, plnetinfo->timestamp)); - DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", - plnetinfo->rtt0, plnetinfo->rtt1)); - } - } - } -exit_mutex_unlock: - mutex_unlock(&_pno_state->pno_mutex); -exit: - params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_COMPLETE; - smp_wmb(); - wake_up_interruptible(&_pno_state->batch_get_wait); - if (nAPs_per_scan) { - MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan); - } - if (plbestnet) { - MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); - } - DHD_PNO(("Batch retrieval done!\n")); - return err; -} -#endif /* GSCAN_SUPPORT */ - -static int -_dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) -{ - int err = BCME_OK; - int i, j; - uint32 timestamp = 0; - dhd_pno_params_t *_params = NULL; - dhd_pno_status_info_t *_pno_state = NULL; - wl_pfn_lscanresults_t *plbestnet = NULL; - wl_pfn_lnet_info_t *plnetinfo; - dhd_pno_bestnet_entry_t *pbestnet_entry; - dhd_pno_best_header_t *pbestnetheader = NULL; - dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext; - bool allocate_header = FALSE; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit_no_unlock; - } - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit_no_unlock; - } - - if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { - DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); - goto exit_no_unlock; - } - mutex_lock(&_pno_state->pno_mutex); - _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; - if (buf && bufsize) { - if (!list_empty(&_params->params_batch.get_batch.expired_scan_results_list)) { - /* need to check whether we have cashed data or not */ - DHD_PNO(("%s: have cashed batching data in Driver\n", - __FUNCTION__)); - /* convert to results format */ - goto convert_format; - } else { - /* this is a first try to get batching results */ - if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { - /* move the scan_results_list to expired_scan_results_lists */ - list_for_each_entry_safe(siter, snext, - &_params->params_batch.get_batch.scan_results_list, list) { - list_move_tail(&siter->list, - &_params->params_batch.get_batch.expired_scan_results_list); - } - _params->params_batch.get_batch.top_node_cnt = 0; - _params->params_batch.get_batch.expired_tot_scan_cnt = - _params->params_batch.get_batch.tot_scan_cnt; - _params->params_batch.get_batch.tot_scan_cnt = 0; - goto convert_format; - } - } - } - /* create dhd_pno_scan_results_t whenever we got event WLC_E_PFN_BEST_BATCHING */ - pscan_results = (dhd_pno_scan_results_t *)MALLOC(dhd->osh, SCAN_RESULTS_SIZE); - if (pscan_results == NULL) { - err = BCME_NOMEM; - DHD_ERROR(("failed to allocate dhd_pno_scan_results_t\n")); - goto exit; - } - pscan_results->bestnetheader = NULL; - pscan_results->cnt_header = 0; - /* add the element into list unless total node cnt is less than MAX_NODE_ CNT */ - if (_params->params_batch.get_batch.top_node_cnt < MAX_NODE_CNT) { - list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); - _params->params_batch.get_batch.top_node_cnt++; - } else { - int _removed_scan_cnt; - /* remove oldest one and add new one */ - DHD_PNO(("%s : Remove oldest node and add new one\n", __FUNCTION__)); - _removed_scan_cnt = _dhd_pno_clear_all_batch_results(dhd, - &_params->params_batch.get_batch.scan_results_list, TRUE); - _params->params_batch.get_batch.tot_scan_cnt -= _removed_scan_cnt; - list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); - - } - plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); - NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - memset(plbestnet, 0, PNO_BESTNET_LEN); - while (plbestnet->status != PFN_COMPLETE) { - err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN, - FALSE); - if (err < 0) { - if (err == BCME_EPERM) { - DHD_ERROR(("we cannot get the batching data " - "during scanning in firmware, try again\n,")); - msleep(500); - continue; - } else { - DHD_ERROR(("%s : failed to execute pfnlbest (err :%d)\n", - __FUNCTION__, err)); - goto exit; - } - } - DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, - plbestnet->status, plbestnet->count)); - if (plbestnet->version != PFN_SCANRESULT_VERSION) { - err = BCME_VERSION; - DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", - plbestnet->version, PFN_SCANRESULT_VERSION)); - goto exit; - } - plnetinfo = plbestnet->netinfo; - for (i = 0; i < plbestnet->count; i++) { - pbestnet_entry = (dhd_pno_bestnet_entry_t *) - MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); - if (pbestnet_entry == NULL) { - err = BCME_NOMEM; - DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); - goto exit; - } - memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE); - pbestnet_entry->recorded_time = jiffies; /* record the current time */ - /* create header for the first entry */ - allocate_header = (i == 0)? TRUE : FALSE; - /* check whether the new generation is started or not */ - if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) - > TIME_MIN_DIFF)) - allocate_header = TRUE; - timestamp = plnetinfo->timestamp; - if (allocate_header) { - pbestnetheader = (dhd_pno_best_header_t *) - MALLOC(dhd->osh, BEST_HEADER_SIZE); - if (pbestnetheader == NULL) { - err = BCME_NOMEM; - if (pbestnet_entry) - MFREE(dhd->osh, pbestnet_entry, - BESTNET_ENTRY_SIZE); - DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); - goto exit; - } - /* increase total cnt of bestnet header */ - pscan_results->cnt_header++; - /* need to record the reason to call dhd_pno_get_for_bach */ - if (reason) - pbestnetheader->reason = (ENABLE << reason); - memset(pbestnetheader, 0, BEST_HEADER_SIZE); - /* initialize the head of linked list */ - INIT_LIST_HEAD(&(pbestnetheader->entry_list)); - /* link the pbestnet heaer into existed list */ - if (pscan_results->bestnetheader == NULL) - /* In case of header */ - pscan_results->bestnetheader = pbestnetheader; - else { - dhd_pno_best_header_t *head = pscan_results->bestnetheader; - pscan_results->bestnetheader = pbestnetheader; - pbestnetheader->next = head; - } - } - /* fills the best network info */ - pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; - pbestnet_entry->RSSI = plnetinfo->RSSI; - if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { - /* if RSSI is positive value, we assume that - * this scan is aborted by other scan - */ - DHD_PNO(("This scan is aborted\n")); - pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); - } - pbestnet_entry->rtt0 = plnetinfo->rtt0; - pbestnet_entry->rtt1 = plnetinfo->rtt1; - pbestnet_entry->timestamp = plnetinfo->timestamp; - if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s: Invalid SSID length %d: trimming it to max\n", - __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); - plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; - } - pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; - memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, - pbestnet_entry->SSID_len); - memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); - /* add the element into list */ - list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); - /* increase best entry count */ - pbestnetheader->tot_cnt++; - pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; - DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1)); - DHD_PNO(("\tSSID : ")); - for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) - DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j])); - DHD_PNO(("\n")); - DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", - plnetinfo->pfnsubnet.BSSID.octet[0], - plnetinfo->pfnsubnet.BSSID.octet[1], - plnetinfo->pfnsubnet.BSSID.octet[2], - plnetinfo->pfnsubnet.BSSID.octet[3], - plnetinfo->pfnsubnet.BSSID.octet[4], - plnetinfo->pfnsubnet.BSSID.octet[5])); - DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", - plnetinfo->pfnsubnet.channel, - plnetinfo->RSSI, plnetinfo->timestamp)); - DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1)); - plnetinfo++; - } - } - if (pscan_results->cnt_header == 0) { - /* In case that we didn't get any data from the firmware - * Remove the current scan_result list from get_bach.scan_results_list. - */ - DHD_PNO(("NO BATCH DATA from Firmware, Delete current SCAN RESULT LIST\n")); - list_del(&pscan_results->list); - MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE); - _params->params_batch.get_batch.top_node_cnt--; - } else { - /* increase total scan count using current scan count */ - _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; - } - - if (buf && bufsize) { - /* This is a first try to get batching results */ - if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { - /* move the scan_results_list to expired_scan_results_lists */ - list_for_each_entry_safe(siter, snext, - &_params->params_batch.get_batch.scan_results_list, list) { - list_move_tail(&siter->list, - &_params->params_batch.get_batch.expired_scan_results_list); - } - /* reset gloval values after moving to expired list */ - _params->params_batch.get_batch.top_node_cnt = 0; - _params->params_batch.get_batch.expired_tot_scan_cnt = - _params->params_batch.get_batch.tot_scan_cnt; - _params->params_batch.get_batch.tot_scan_cnt = 0; - } -convert_format: - err = _dhd_pno_convert_format(dhd, &_params->params_batch, buf, bufsize); - if (err < 0) { - DHD_ERROR(("failed to convert the data into upper layer format\n")); - goto exit; - } - } -exit: - if (plbestnet) - MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); - if (_params) { - _params->params_batch.get_batch.buf = NULL; - _params->params_batch.get_batch.bufsize = 0; - _params->params_batch.get_batch.bytes_written = err; - } - mutex_unlock(&_pno_state->pno_mutex); -exit_no_unlock: - if (waitqueue_active(&_pno_state->get_batch_done.wait)) - complete(&_pno_state->get_batch_done); - return err; -} -static void -_dhd_pno_get_batch_handler(struct work_struct *work) -{ - dhd_pno_status_info_t *_pno_state; - dhd_pub_t *dhd; - struct dhd_pno_batch_params *params_batch; - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = container_of(work, struct dhd_pno_status_info, work); - dhd = _pno_state->dhd; - if (dhd == NULL) { - DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); - return; - } -#ifdef GSCAN_SUPPORT - _dhd_pno_get_gscan_batch_from_fw(dhd); -#endif /* GSCAN_SUPPORT */ - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; - - _dhd_pno_get_for_batch(dhd, params_batch->get_batch.buf, - params_batch->get_batch.bufsize, params_batch->get_batch.reason); - } -} - -int -dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) -{ - int err = BCME_OK; - char *pbuf = buf; - dhd_pno_status_info_t *_pno_state; - struct dhd_pno_batch_params *params_batch; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - struct dhd_pno_gscan_params *gscan_params; - gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; - gscan_params->reason = reason; - err = dhd_retreive_batch_scan_results(dhd); - if (err == BCME_OK) { - wait_event_interruptible_timeout(_pno_state->batch_get_wait, - is_batch_retrieval_complete(gscan_params), - msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); - } - } else -#endif - { - if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { - DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); - memset(pbuf, 0, bufsize); - pbuf += sprintf(pbuf, "scancount=%d\n", 0); - sprintf(pbuf, "%s", RESULTS_END_MARKER); - err = strlen(buf); - goto exit; - } - params_batch->get_batch.buf = buf; - params_batch->get_batch.bufsize = bufsize; - params_batch->get_batch.reason = reason; - params_batch->get_batch.bytes_written = 0; - schedule_work(&_pno_state->work); - wait_for_completion(&_pno_state->get_batch_done); - } - -#ifdef GSCAN_SUPPORT - if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) -#endif - err = params_batch->get_batch.bytes_written; -exit: - return err; -} - -int -dhd_pno_stop_for_batch(dhd_pub_t *dhd) -{ - int err = BCME_OK; - int mode = 0; - int i = 0; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - wl_pfn_bssid_t *p_pfn_bssid = NULL; - wlc_ssid_ext_t *p_ssid_list = NULL; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", - __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - DHD_PNO(("Gscan is ongoing, nothing to stop here\n")); - return err; - } -#endif - - if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { - DHD_ERROR(("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__)); - goto exit; - } - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { - mode = _pno_state->pno_mode; - dhd_pno_clean(dhd); - _pno_state->pno_mode = mode; - /* restart Legacy PNO if the Legacy PNO is on */ - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - struct dhd_pno_legacy_params *_params_legacy; - _params_legacy = - &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!p_ssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, - _params_legacy->scan_fr, _params_legacy->pno_repeat, - _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, - _params_legacy->nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { - struct dhd_pno_bssid *iter, *next; - _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * - _params->params_hotlist.nbssid, GFP_KERNEL); - if (p_pfn_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" - " (count: %d)", - __FUNCTION__, _params->params_hotlist.nbssid)); - err = BCME_ERROR; - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - goto exit; - } - i = 0; - /* convert dhd_pno_bssid to wl_pfn_bssid */ - list_for_each_entry_safe(iter, next, - &_params->params_hotlist.bssid_list, list) { - memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN); - p_pfn_bssid[i].flags = iter->flags; - i++; - } - err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); - if (err < 0) { - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } - } else { - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } -exit: - _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; - _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); - if (p_ssid_list) - kfree(p_ssid_list); - if (p_pfn_bssid) - kfree(p_pfn_bssid); - return err; -} - -int -dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, - struct dhd_pno_hotlist_params *hotlist_params) -{ - int err = BCME_OK; - int i; - uint16 _chan_list[WL_NUMCHANNELS]; - int rem_nchan = 0; - int tot_nchan = 0; - int mode = 0; - dhd_pno_params_t *_params; - dhd_pno_params_t *_params2; - struct dhd_pno_bssid *_pno_bssid; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - NULL_CHECK(hotlist_params, "hotlist_params is NULL", err); - NULL_CHECK(p_pfn_bssid, "p_pfn_bssid is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - DHD_PNO(("%s enter\n", __FUNCTION__)); - - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit; - } - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - _params = &_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]; - if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { - _pno_state->pno_mode |= DHD_PNO_HOTLIST_MODE; - err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_HOTLIST_MODE); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", - __FUNCTION__)); - goto exit; - } - } - _params->params_batch.nchan = hotlist_params->nchan; - _params->params_batch.scan_fr = hotlist_params->scan_fr; - if (hotlist_params->nchan) - memcpy(_params->params_hotlist.chan_list, hotlist_params->chan_list, - sizeof(_params->params_hotlist.chan_list)); - memset(_chan_list, 0, sizeof(_chan_list)); - - rem_nchan = ARRAYSIZE(hotlist_params->chan_list) - hotlist_params->nchan; - if (hotlist_params->band == WLC_BAND_2G || hotlist_params->band == WLC_BAND_5G) { - /* get a valid channel list based on band B or A */ - err = _dhd_pno_get_channels(dhd, - &_params->params_hotlist.chan_list[hotlist_params->nchan], - &rem_nchan, hotlist_params->band, FALSE); - if (err < 0) { - DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", - __FUNCTION__, hotlist_params->band)); - goto exit; - } - /* now we need to update nchan because rem_chan has valid channel count */ - _params->params_hotlist.nchan += rem_nchan; - /* need to sort channel list */ - sort(_params->params_hotlist.chan_list, _params->params_hotlist.nchan, - sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL); - } -#ifdef PNO_DEBUG -{ - int i; - DHD_PNO(("Channel list : ")); - for (i = 0; i < _params->params_batch.nchan; i++) { - DHD_PNO(("%d ", _params->params_batch.chan_list[i])); - } - DHD_PNO(("\n")); -} -#endif - if (_params->params_hotlist.nchan) { - /* copy the channel list into local array */ - memcpy(_chan_list, _params->params_hotlist.chan_list, - sizeof(_chan_list)); - tot_nchan = _params->params_hotlist.nchan; - } - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - DHD_PNO(("PNO SSID is on progress in firmware\n")); - /* store current pno_mode before disabling pno */ - mode = _pno_state->pno_mode; - err = _dhd_pno_enable(dhd, PNO_OFF); - if (err < 0) { - DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - goto exit; - } - /* restore the previous mode */ - _pno_state->pno_mode = mode; - /* Use the superset for channelist between two mode */ - _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - if (_params2->params_legacy.nchan > 0 && - _params->params_hotlist.nchan > 0) { - err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, - &_params2->params_legacy.chan_list[0], - _params2->params_legacy.nchan, - &_params->params_hotlist.chan_list[0], - _params->params_hotlist.nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to merge channel list" - "between legacy and hotlist\n", - __FUNCTION__)); - goto exit; - } - } - - } - - INIT_LIST_HEAD(&(_params->params_hotlist.bssid_list)); - - err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, hotlist_params->nbssid); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", - __FUNCTION__, err)); - goto exit; - } - if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_HOTLIST_MODE)) < 0) { - DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - if (tot_nchan > 0) { - if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { - DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", - __FUNCTION__, err)); - goto exit; - } - } - for (i = 0; i < hotlist_params->nbssid; i++) { - _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); - NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err); - memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN); - _pno_bssid->flags = p_pfn_bssid[i].flags; - list_add_tail(&_pno_bssid->list, &_params->params_hotlist.bssid_list); - } - _params->params_hotlist.nbssid = hotlist_params->nbssid; - if (_pno_state->pno_status == DHD_PNO_DISABLED) { - if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) - DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); - } -exit: - /* clear mode in case of error */ - if (err < 0) - _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; - return err; -} - -int -dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) -{ - int err = BCME_OK; - uint32 mode = 0; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - wlc_ssid_ext_t *p_ssid_list = NULL; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", - __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - - if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { - DHD_ERROR(("%s : Hotlist MODE is not enabled\n", - __FUNCTION__)); - goto exit; - } - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - - if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_BATCH_MODE)) { - /* retrieve the batching data from firmware into host */ - dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); - /* save current pno_mode before calling dhd_pno_clean */ - mode = _pno_state->pno_mode; - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - /* restore previos pno mode */ - _pno_state->pno_mode = mode; - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - /* restart Legacy PNO Scan */ - struct dhd_pno_legacy_params *_params_legacy; - _params_legacy = - &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!p_ssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, - _params_legacy->scan_fr, _params_legacy->pno_repeat, - _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, - _params_legacy->nchan); - if (err < 0) { - DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } else if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - /* restart Batching Scan */ - _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); - /* restart BATCH SCAN */ - err = dhd_pno_set_for_batch(dhd, &_params->params_batch); - if (err < 0) { - _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; - DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } - } else { - err = dhd_pno_clean(dhd); - if (err < 0) { - DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", - __FUNCTION__, err)); - goto exit; - } - } -exit: - if (p_ssid_list) - kfree(p_ssid_list); - return err; -} - -#ifdef GSCAN_SUPPORT -int -dhd_retreive_batch_scan_results(dhd_pub_t *dhd) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - struct dhd_pno_batch_params *params_batch; - - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - - params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; - if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE) { - DHD_PNO(("Retreive batch results\n")); - params_batch->get_batch.buf = NULL; - params_batch->get_batch.bufsize = 0; - params_batch->get_batch.reason = PNO_STATUS_EVENT; - _params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_IN_PROGRESS; - smp_wmb(); - schedule_work(&_pno_state->work); - } else { - DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING retrieval" - "already in progress, will skip\n", __FUNCTION__)); - err = BCME_ERROR; - } - - return err; -} - -void -dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) -{ - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - gscan_results_cache_t *iter, *tmp; - - if (!_pno_state) - return; - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - - if (type == HOTLIST_FOUND) { - iter = gscan_params->gscan_hotlist_found; - gscan_params->gscan_hotlist_found = NULL; - } else { - iter = gscan_params->gscan_hotlist_lost; - gscan_params->gscan_hotlist_lost = NULL; - } - - while (iter) { - tmp = iter->next; - kfree(iter); - iter = tmp; - } - - return; -} - -void * -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size) -{ - wl_bss_info_t *bi = NULL; - wl_gscan_result_t *gscan_result; - wifi_gscan_result_t *result = NULL; - u32 bi_length = 0; - uint8 channel; - uint32 mem_needed; - struct timespec ts; - u32 bi_ie_length = 0; - u32 bi_ie_offset = 0; - - *size = 0; - - gscan_result = (wl_gscan_result_t *)data; - - if (!gscan_result) { - DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); - goto exit; - } - if ((len < sizeof(*gscan_result)) || - (len < dtoh32(gscan_result->buflen)) || - (dtoh32(gscan_result->buflen) > - (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { - DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__, - dtoh32(gscan_result->buflen))); - goto exit; - } - if (!gscan_result->bss_info) { - DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); - goto exit; - } - bi = &gscan_result->bss_info[0].info; - bi_length = dtoh32(bi->length); - if (bi_length != (dtoh32(gscan_result->buflen) - - WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) { - DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); - goto exit; - } - bi_ie_offset = dtoh32(bi->ie_offset); - bi_ie_length = dtoh32(bi->ie_length); - if ((bi_ie_offset + bi_ie_length) > bi_length) { - DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n", - __FUNCTION__, bi_ie_length, bi_ie_offset)); - goto exit; - } - if (bi->SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s: Invalid SSID length:%u\n", __FUNCTION__, bi->SSID_len)); - goto exit; - } - - mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi_ie_length; - result = kmalloc(mem_needed, GFP_KERNEL); - - if (!result) { - DHD_ERROR(("%s Cannot malloc scan result buffer %d bytes\n", - __FUNCTION__, mem_needed)); - goto exit; - } - - memcpy(result->ssid, bi->SSID, bi->SSID_len); - result->ssid[bi->SSID_len] = '\0'; - channel = wf_chspec_ctlchan(bi->chanspec); - result->channel = wf_channel2mhz(channel, - (channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - result->rssi = (int32) bi->RSSI; - result->rtt = 0; - result->rtt_sd = 0; - get_monotonic_boottime(&ts); - result->ts = (uint64) TIMESPEC_TO_US(ts); - result->beacon_period = dtoh16(bi->beacon_period); - result->capability = dtoh16(bi->capability); - result->ie_length = bi_ie_length; - memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN); - memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length); - *size = mem_needed; -exit: - return result; -} - -void * -dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size) -{ - dhd_epno_results_t *results = NULL; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - uint32 count, mem_needed = 0, i; - uint8 ssid[DOT11_MAX_SSID_LEN + 1]; - struct ether_addr *bssid; - - *size = 0; - if (!_pno_state) - return NULL; - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - - if (event == WLC_E_PFN_SSID_EXT) { - wl_pfn_ssid_ext_result_t *evt_data; - evt_data = (wl_pfn_ssid_ext_result_t *) data; - - if (evt_data->version != PFN_SSID_EXT_VERSION) { - DHD_PNO(("ePNO event: Incorrect version %d %d\n", evt_data->version, - PFN_SSID_EXT_VERSION)); - return NULL; - } - count = evt_data->count; - mem_needed = sizeof(dhd_epno_results_t) * count; - results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); - if (!results) { - DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, - mem_needed)); - return NULL; - } - DHD_ERROR(("Rx'ed WLC_E_PFN_SSID_EXT event: %d results\n", count)); - for (i = 0; i < count; i++) { - results[i].rssi = evt_data->net[i].rssi; - results[i].channel = wf_channel2mhz(evt_data->net[i].channel, - (evt_data->net[i].channel <= CH_MAX_2G_CHANNEL ? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - results[i].flags = evt_data->net[i].flags; - dhd_pno_idx_to_ssid(gscan_params, &results[i], - evt_data->net[i].index); - memcpy(ssid, results[i].ssid, results[i].ssid_len); - bssid = &results[i].bssid; - memcpy(bssid, &evt_data->net[i].bssid, ETHER_ADDR_LEN); - ssid[results[i].ssid_len] = '\0'; - DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " - "idx %d ch %d rssi %d flags %d\n", ssid, - bssid->octet[0], bssid->octet[1], - bssid->octet[2], bssid->octet[3], - bssid->octet[4], bssid->octet[5], - evt_data->net[i].index, results[i].channel, - results[i].rssi, results[i].flags)); - } - } else if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) { - wl_pfn_scanresults_t *pfn_result = (wl_pfn_scanresults_t *)data; - wl_pfn_net_info_t *net; - - if (pfn_result->version != PFN_SCANRESULT_VERSION) { - /* Check if count of pfn results is corrupted */ - if (pfn_result->count > EVENT_MAX_NETCNT) { - DHD_ERROR(("%s event %d: pfn results count %d" - "exceeds the max limit\n", __FUNCTION__, event, pfn_result->count)); - return NULL; - } - DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, - pfn_result->version, PFN_SCANRESULT_VERSION)); - return NULL; - } - count = pfn_result->count; - mem_needed = sizeof(dhd_epno_results_t) * count; - results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); - if (!results) { - DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, - mem_needed)); - return NULL; - } - for (i = 0; i < count; i++) { - net = &pfn_result->netinfo[i]; - results[i].rssi = net->RSSI; - results[i].channel = wf_channel2mhz(net->pfnsubnet.channel, - (net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - results[i].flags = (event == WLC_E_PFN_NET_FOUND) ? - WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST; - results[i].ssid_len = min(net->pfnsubnet.SSID_len, - (uint8)DOT11_MAX_SSID_LEN); - bssid = &results[i].bssid; - memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN); - memcpy(results[i].ssid, net->pfnsubnet.SSID, results[i].ssid_len); - memcpy(ssid, results[i].ssid, results[i].ssid_len); - ssid[results[i].ssid_len] = '\0'; - DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " - "ch %d rssi %d flags %d\n", ssid, - bssid->octet[0], bssid->octet[1], - bssid->octet[2], bssid->octet[3], - bssid->octet[4], bssid->octet[5], - results[i].channel, results[i].rssi, results[i].flags)); - } - } - *size = mem_needed; - return results; -} - -#ifdef ANQPO_SUPPORT -void * -dhd_pno_process_anqpo_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size) -{ - wl_bss_info_t *bi = (wl_bss_info_t *)data; - wifi_gscan_result_t *result = NULL; - wl_event_gas_t *gas_data; - uint8 channel; - uint32 mem_needed; - struct timespec ts; - - if ((bi->SSID_len > DOT11_MAX_SSID_LEN) || - (bi->ie_length > (*size - sizeof(wl_bss_info_t))) || - (bi->ie_offset < sizeof(wl_bss_info_t)) || - (bi->ie_offset > (sizeof(wl_bss_info_t) + bi->ie_length))) { - DHD_ERROR(("%s: tot:%d,SSID:%d,ie_len:%d,ie_off:%d\n", - __FUNCTION__, *size, bi->SSID_len, - bi->ie_length, bi->ie_offset)); - return NULL; - } - - gas_data = (wl_event_gas_t *)((uint8 *)data + bi->ie_offset + bi->ie_length); - if (gas_data->data_len > (*size - (bi->ie_offset + bi->ie_length))) { - DHD_ERROR(("%s: wrong gas_data_len:%d\n", - __FUNCTION__, gas_data->data_len)); - return NULL; - } - - if (event == WLC_E_PFN_NET_FOUND) { - mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi->ie_length + - OFFSETOF(wl_event_gas_t, data) + gas_data->data_len + - sizeof(int); - result = (wifi_gscan_result_t *) kmalloc(mem_needed, GFP_KERNEL); - if (result == NULL) { - DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, mem_needed)); - return NULL; - } - - memcpy(result->ssid, bi->SSID, bi->SSID_len); - result->ssid[bi->SSID_len] = '\0'; - channel = wf_chspec_ctlchan(bi->chanspec); - result->channel = wf_channel2mhz(channel, (channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - result->rssi = (int32) bi->RSSI; - result->rtt = 0; - result->rtt_sd = 0; - get_monotonic_boottime(&ts); - result->ts = (uint64) TIMESPEC_TO_US(ts); - result->beacon_period = dtoh16(bi->beacon_period); - result->capability = dtoh16(bi->capability); - result->ie_length = dtoh32(bi->ie_length); - memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN); - memcpy(result->ie_data, ((uint8 *)bi + bi->ie_offset), bi->ie_length); - /* append ANQP data to end of scan result */ - memcpy((uint8 *)result+OFFSETOF(wifi_gscan_result_t, ie_data)+bi->ie_length, - gas_data, OFFSETOF(wl_event_gas_t, data)+gas_data->data_len); - /* append network id to end of result */ - memcpy((uint8 *)result+mem_needed-sizeof(int), - (uint8 *)data+(*size)-sizeof(int), sizeof(int)); - *size = mem_needed; - } else { - DHD_ERROR(("%s unknown event: %d!!\n", __FUNCTION__, event)); - } - - return result; -} -#endif /* ANQPO_SUPPORT */ - -void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, - hotlist_type_t type) -{ - void *ptr = NULL; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - wl_pfn_scanresults_t *results = (wl_pfn_scanresults_t *)event_data; - wifi_gscan_result_t *hotlist_found_array; - wl_pfn_net_info_t *plnetinfo; - gscan_results_cache_t *gscan_hotlist_cache; - int malloc_size = 0, i, total = 0; - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - - if (!results->count || (results->count > EVENT_MAX_NETCNT)) { - DHD_ERROR(("%s: wrong result count:%d\n", __FUNCTION__, results->count)); - *send_evt_bytes = 0; - return ptr; - } - - malloc_size = sizeof(gscan_results_cache_t) + - ((results->count - 1) * sizeof(wifi_gscan_result_t)); - gscan_hotlist_cache = (gscan_results_cache_t *) kmalloc(malloc_size, GFP_KERNEL); - - if (!gscan_hotlist_cache) { - DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size)); - *send_evt_bytes = 0; - return ptr; - } - - if (type == HOTLIST_FOUND) { - gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found; - gscan_params->gscan_hotlist_found = gscan_hotlist_cache; - DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, results->count)); - } else { - gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost; - gscan_params->gscan_hotlist_lost = gscan_hotlist_cache; - DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, results->count)); - } - - gscan_hotlist_cache->tot_count = results->count; - gscan_hotlist_cache->tot_consumed = 0; - plnetinfo = results->netinfo; - - for (i = 0; i < results->count; i++, plnetinfo++) { - hotlist_found_array = &gscan_hotlist_cache->results[i]; - hotlist_found_array->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, - (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - hotlist_found_array->rssi = (int32) plnetinfo->RSSI; - /* Info not available & not expected */ - hotlist_found_array->beacon_period = 0; - hotlist_found_array->capability = 0; - hotlist_found_array->ie_length = 0; - - hotlist_found_array->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); - if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", - plnetinfo->pfnsubnet.SSID_len)); - plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; - } - memcpy(hotlist_found_array->ssid, plnetinfo->pfnsubnet.SSID, - plnetinfo->pfnsubnet.SSID_len); - hotlist_found_array->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; - - memcpy(&hotlist_found_array->macaddr, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); - DHD_PNO(("\t%s %02x:%02x:%02x:%02x:%02x:%02x rssi %d\n", hotlist_found_array->ssid, - hotlist_found_array->macaddr.octet[0], - hotlist_found_array->macaddr.octet[1], - hotlist_found_array->macaddr.octet[2], - hotlist_found_array->macaddr.octet[3], - hotlist_found_array->macaddr.octet[4], - hotlist_found_array->macaddr.octet[5], - hotlist_found_array->rssi)); - } - - if (results->status == PFN_COMPLETE) { - ptr = (void *) gscan_hotlist_cache; - while (gscan_hotlist_cache) { - total += gscan_hotlist_cache->tot_count; - gscan_hotlist_cache = gscan_hotlist_cache->next; - } - *send_evt_bytes = total * sizeof(wifi_gscan_result_t); - } - - return ptr; -} -#endif /* GSCAN_SUPPORT */ - -int -dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) -{ - int err = BCME_OK; - uint status, event_type, flags, datalen; - dhd_pno_status_info_t *_pno_state; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); - if (!WLS_SUPPORTED(_pno_state)) { - DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); - err = BCME_UNSUPPORTED; - goto exit; - } - event_type = ntoh32(event->event_type); - flags = ntoh16(event->flags); - status = ntoh32(event->status); - datalen = ntoh32(event->datalen); - DHD_PNO(("%s enter : event_type :%d\n", __FUNCTION__, event_type)); - switch (event_type) { - case WLC_E_PFN_BSSID_NET_FOUND: - case WLC_E_PFN_BSSID_NET_LOST: - /* TODO : need to implement event logic using generic netlink */ - break; - case WLC_E_PFN_BEST_BATCHING: -#ifndef GSCAN_SUPPORT - { - struct dhd_pno_batch_params *params_batch; - params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; - if (!waitqueue_active(&_pno_state->get_batch_done.wait)) { - DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); - params_batch->get_batch.buf = NULL; - params_batch->get_batch.bufsize = 0; - params_batch->get_batch.reason = PNO_STATUS_EVENT; - schedule_work(&_pno_state->work); - } else - DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING" - "will skip this event\n", __FUNCTION__)); - break; - } -#else - break; -#endif /* !GSCAN_SUPPORT */ - default: - DHD_ERROR(("unknown event : %d\n", event_type)); - } -exit: - return err; -} - -int dhd_pno_init(dhd_pub_t *dhd) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - char *buf = NULL; - NULL_CHECK(dhd, "dhd is NULL", err); - DHD_PNO(("%s enter\n", __FUNCTION__)); - UNUSED_PARAMETER(_dhd_pno_suspend); - if (dhd->pno_state) - goto exit; - dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t)); - NULL_CHECK(dhd->pno_state, "failed to create dhd_pno_state", err); - memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t)); - /* need to check whether current firmware support batching and hotlist scan */ - _pno_state = PNO_GET_PNOSTATE(dhd); - _pno_state->wls_supported = TRUE; - _pno_state->dhd = dhd; - mutex_init(&_pno_state->pno_mutex); - INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler); - init_completion(&_pno_state->get_batch_done); - -#ifdef GSCAN_SUPPORT - init_waitqueue_head(&_pno_state->batch_get_wait); -#endif /* GSCAN_SUPPORT */ - buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); - if (!buf) { - DHD_ERROR((":%s buf alloc err.\n", __FUNCTION__)); - return BCME_NOMEM; - } - err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, buf, WLC_IOCTL_SMLEN, - FALSE); - if (err == BCME_UNSUPPORTED) { - _pno_state->wls_supported = FALSE; - DHD_INFO(("Current firmware doesn't support" - " Android Location Service\n")); - } -exit: - kfree(buf); - return err; -} -int dhd_pno_deinit(dhd_pub_t *dhd) -{ - int err = BCME_OK; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - NULL_CHECK(dhd, "dhd is NULL", err); - - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); - NULL_CHECK(_pno_state, "pno_state is NULL", err); - /* may need to free legacy ssid_list */ - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - _params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; - _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); - } - -#ifdef GSCAN_SUPPORT - if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - mutex_lock(&_pno_state->pno_mutex); - dhd_pno_reset_cfg_gscan(_params, _pno_state, GSCAN_FLUSH_ALL_CFG); - mutex_unlock(&_pno_state->pno_mutex); - } -#endif /* GSCAN_SUPPORT */ - - if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { - _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; - /* clear resource if the BATCH MODE is on */ - _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); - } - cancel_work_sync(&_pno_state->work); - MFREE(dhd->osh, _pno_state, sizeof(dhd_pno_status_info_t)); - dhd->pno_state = NULL; - return err; -} -#endif /* PNO_SUPPORT */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h deleted file mode 100755 index 62425da6c1e6..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Header file of Broadcom Dongle Host Driver (DHD) - * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_pno.h 423669 2013-09-18 13:01:55Z $ - */ - -#ifndef __DHD_PNO_H__ -#define __DHD_PNO_H__ - -#if defined(PNO_SUPPORT) -#define PNO_TLV_PREFIX 'S' -#define PNO_TLV_VERSION '1' -#define PNO_TLV_SUBTYPE_LEGACY_PNO '2' -#define PNO_TLV_RESERVED '0' - -#define PNO_BATCHING_SET "SET" -#define PNO_BATCHING_GET "GET" -#define PNO_BATCHING_STOP "STOP" - -#define PNO_PARAMS_DELIMETER " " -#define PNO_PARAM_CHANNEL_DELIMETER "," -#define PNO_PARAM_VALUE_DELLIMETER '=' -#define PNO_PARAM_SCANFREQ "SCANFREQ" -#define PNO_PARAM_BESTN "BESTN" -#define PNO_PARAM_MSCAN "MSCAN" -#define PNO_PARAM_CHANNEL "CHANNEL" -#define PNO_PARAM_RTT "RTT" - -#define PNO_TLV_TYPE_SSID_IE 'S' -#define PNO_TLV_TYPE_TIME 'T' -#define PNO_TLV_FREQ_REPEAT 'R' -#define PNO_TLV_FREQ_EXPO_MAX 'M' - -#define MAXNUM_SSID_PER_ADD 16 -#define MAXNUM_PNO_PARAMS 2 -#define PNO_TLV_COMMON_LENGTH 1 -#define DEFAULT_BATCH_MSCAN 16 - -#define RESULTS_END_MARKER "----\n" -#define SCAN_END_MARKER "####\n" -#define AP_END_MARKER "====\n" - -#define PNO_RSSI_MARGIN_DBM 30 - -#ifdef GSCAN_SUPPORT - -#define GSCAN_MAX_CH_BUCKETS 8 -#define GSCAN_MAX_CHANNELS_IN_BUCKET 32 -#define GSCAN_MAX_AP_CACHE_PER_SCAN 32 -#define GSCAN_MAX_AP_CACHE 320 -#define GSCAN_BG_BAND_MASK (1 << 0) -#define GSCAN_A_BAND_MASK (1 << 1) -#define GSCAN_DFS_MASK (1 << 2) -#define GSCAN_ABG_BAND_MASK (GSCAN_A_BAND_MASK | GSCAN_BG_BAND_MASK) -#define GSCAN_BAND_MASK (GSCAN_ABG_BAND_MASK | GSCAN_DFS_MASK) - -#define GSCAN_FLUSH_HOTLIST_CFG (1 << 0) -#define GSCAN_FLUSH_SIGNIFICANT_CFG (1 << 1) -#define GSCAN_FLUSH_SCAN_CFG (1 << 2) -#define GSCAN_FLUSH_EPNO_CFG (1 << 3) -#define GSCAN_FLUSH_ALL_CFG (GSCAN_FLUSH_SCAN_CFG | \ - GSCAN_FLUSH_SIGNIFICANT_CFG | \ - GSCAN_FLUSH_HOTLIST_CFG | \ - GSCAN_FLUSH_EPNO_CFG) -#define DHD_EPNO_HIDDEN_SSID (1 << 0) -#define DHD_EPNO_A_BAND_TRIG (1 << 1) -#define DHD_EPNO_BG_BAND_TRIG (1 << 2) -#define DHD_EPNO_STRICT_MATCH (1 << 3) -#define DHD_PNO_USE_SSID (DHD_EPNO_HIDDEN_SSID | DHD_EPNO_STRICT_MATCH) - -/* Do not change GSCAN_BATCH_RETRIEVAL_COMPLETE */ -#define GSCAN_BATCH_RETRIEVAL_COMPLETE 0 -#define GSCAN_BATCH_RETRIEVAL_IN_PROGRESS 1 -#define GSCAN_BATCH_NO_THR_SET 101 -#define GSCAN_LOST_AP_WINDOW_DEFAULT 4 -#define GSCAN_MIN_BSSID_TIMEOUT 90 -#define GSCAN_BATCH_GET_MAX_WAIT 500 - -#define CHANNEL_BUCKET_EMPTY_INDEX 0xFF -#define GSCAN_RETRY_THRESHOLD 3 -#define MAX_EPNO_SSID_NUM 32 -#define GSCAN_ANQPO_MAX_HS_LIST_SIZE 16 -#define ANQPO_MAX_HS_NAI_REALM_SIZE 256 -#endif /* GSCAN_SUPPORT */ - -enum scan_status { - /* SCAN ABORT by other scan */ - PNO_STATUS_ABORT, - /* RTT is presence or not */ - PNO_STATUS_RTT_PRESENCE, - /* Disable PNO by Driver */ - PNO_STATUS_DISABLE, - /* NORMAL BATCHING GET */ - PNO_STATUS_NORMAL, - /* WLC_E_PFN_BEST_BATCHING */ - PNO_STATUS_EVENT, - PNO_STATUS_MAX -}; -#define PNO_STATUS_ABORT_MASK 0x0001 -#define PNO_STATUS_RTT_MASK 0x0002 -#define PNO_STATUS_DISABLE_MASK 0x0004 -#define PNO_STATUS_OOM_MASK 0x0010 - -enum index_mode { - INDEX_OF_LEGACY_PARAMS, - INDEX_OF_BATCH_PARAMS, - INDEX_OF_HOTLIST_PARAMS, - /* GSCAN includes hotlist scan and they do not run - * independent of each other - */ -#ifdef GSCAN_SUPPORT - INDEX_OF_GSCAN_PARAMS = INDEX_OF_HOTLIST_PARAMS, -#endif /* GSCAN_SUPPORT */ - INDEX_MODE_MAX -}; -enum dhd_pno_status { - DHD_PNO_DISABLED, - DHD_PNO_ENABLED, - DHD_PNO_SUSPEND -}; -typedef struct cmd_tlv { - char prefix; - char version; - char subtype; - char reserved; -} cmd_tlv_t; - -#ifdef GSCAN_SUPPORT -typedef enum { - WIFI_BAND_UNSPECIFIED, - WIFI_BAND_BG = 1, /* 2.4 GHz */ - WIFI_BAND_A = 2, /* 5 GHz without DFS */ - WIFI_BAND_A_DFS = 4, /* 5 GHz DFS only */ - WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ - WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ - WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ -} gscan_wifi_band_t; - -typedef enum { - HOTLIST_LOST, - HOTLIST_FOUND -} hotlist_type_t; - -typedef enum dhd_pno_gscan_cmd_cfg { - DHD_PNO_BATCH_SCAN_CFG_ID, - DHD_PNO_GEOFENCE_SCAN_CFG_ID, - DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, - DHD_PNO_SCAN_CFG_ID, - DHD_PNO_GET_CAPABILITIES, - DHD_PNO_GET_BATCH_RESULTS, - DHD_PNO_GET_CHANNEL_LIST, - DHD_PNO_GET_EPNO_SSID_ELEM, - DHD_PNO_EPNO_CFG_ID, - DHD_PNO_GET_AUTOJOIN_CAPABILITIES -} dhd_pno_gscan_cmd_cfg_t; - -typedef enum dhd_pno_mode { - /* Wi-Fi Legacy PNO Mode */ - DHD_PNO_NONE_MODE = 0, - DHD_PNO_LEGACY_MODE = (1 << (0)), - /* Wi-Fi Android BATCH SCAN Mode */ - DHD_PNO_BATCH_MODE = (1 << (1)), - /* Wi-Fi Android Hotlist SCAN Mode */ - DHD_PNO_HOTLIST_MODE = (1 << (2)), - /* Wi-Fi Google Android SCAN Mode */ - DHD_PNO_GSCAN_MODE = (1 << (3)) -} dhd_pno_mode_t; -#else -typedef enum dhd_pno_mode { - /* Wi-Fi Legacy PNO Mode */ - DHD_PNO_NONE_MODE = 0, - DHD_PNO_LEGACY_MODE = (1 << (0)), - /* Wi-Fi Android BATCH SCAN Mode */ - DHD_PNO_BATCH_MODE = (1 << (1)), - /* Wi-Fi Android Hotlist SCAN Mode */ - DHD_PNO_HOTLIST_MODE = (1 << (2)) -} dhd_pno_mode_t; -#endif /* GSCAN_SUPPORT */ -struct dhd_pno_ssid { - bool hidden; - int8 rssi_thresh; - uint8 dummy; - uint16 SSID_len; - uchar SSID[DOT11_MAX_SSID_LEN]; - struct list_head list; -}; -struct dhd_pno_bssid { - struct ether_addr macaddr; - /* Bit4: suppress_lost, Bit3: suppress_found */ - uint16 flags; - struct list_head list; -}; -typedef struct dhd_pno_bestnet_entry { - struct ether_addr BSSID; - uint8 SSID_len; - uint8 SSID[DOT11_MAX_SSID_LEN]; - int8 RSSI; - uint8 channel; - uint32 timestamp; - uint16 rtt0; /* distance_cm based on RTT */ - uint16 rtt1; /* distance_cm based on sample standard deviation */ - unsigned long recorded_time; - struct list_head list; -} dhd_pno_bestnet_entry_t; -#define BESTNET_ENTRY_SIZE (sizeof(dhd_pno_bestnet_entry_t)) - -typedef struct dhd_pno_bestnet_header { - struct dhd_pno_bestnet_header *next; - uint8 reason; - uint32 tot_cnt; - uint32 tot_size; - struct list_head entry_list; -} dhd_pno_best_header_t; -#define BEST_HEADER_SIZE (sizeof(dhd_pno_best_header_t)) - -typedef struct dhd_pno_scan_results { - dhd_pno_best_header_t *bestnetheader; - uint8 cnt_header; - struct list_head list; -} dhd_pno_scan_results_t; -#define SCAN_RESULTS_SIZE (sizeof(dhd_pno_scan_results_t)) - -struct dhd_pno_get_batch_info { - /* info related to get batch */ - char *buf; - bool batch_started; - uint32 tot_scan_cnt; - uint32 expired_tot_scan_cnt; - uint32 top_node_cnt; - uint32 bufsize; - uint32 bytes_written; - int reason; - struct list_head scan_results_list; - struct list_head expired_scan_results_list; -}; -struct dhd_pno_legacy_params { - uint16 scan_fr; - uint16 chan_list[WL_NUMCHANNELS]; - uint16 nchan; - int pno_repeat; - int pno_freq_expo_max; - int nssid; - struct list_head ssid_list; -}; -struct dhd_pno_batch_params { - int32 scan_fr; - uint8 bestn; - uint8 mscan; - uint8 band; - uint16 chan_list[WL_NUMCHANNELS]; - uint16 nchan; - uint16 rtt; - struct dhd_pno_get_batch_info get_batch; -}; -struct dhd_pno_hotlist_params { - uint8 band; - int32 scan_fr; - uint16 chan_list[WL_NUMCHANNELS]; - uint16 nchan; - uint16 nbssid; - struct list_head bssid_list; -}; - -#ifdef GSCAN_SUPPORT -#define DHD_PNO_REPORT_NO_BATCH (1 << 2) - -typedef struct dhd_pno_gscan_channel_bucket { - uint16 bucket_freq_multiple; - /* band = 1 All bg band channels, - * band = 2 All a band channels, - * band = 0 chan_list channels - */ - uint16 band; - uint8 report_flag; - uint8 num_channels; - uint16 repeat; - uint16 bucket_max_multiple; - uint16 chan_list[GSCAN_MAX_CHANNELS_IN_BUCKET]; -} dhd_pno_gscan_channel_bucket_t; - - -#define DHD_PNO_AUTH_CODE_OPEN 1 /* Open */ -#define DHD_PNO_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ -#define DHD_PNO_AUTH_CODE_EAPOL 4 /* any EAPOL */ - -#define DHD_EPNO_DEFAULT_INDEX 0xFFFFFFFF - -typedef struct dhd_epno_params { - uint8 ssid[DOT11_MAX_SSID_LEN]; - uint8 ssid_len; - int8 rssi_thresh; - uint8 flags; - uint8 auth; - /* index required only for visble ssid */ - uint32 index; - struct list_head list; -} dhd_epno_params_t; - -typedef struct dhd_epno_results { - uint8 ssid[DOT11_MAX_SSID_LEN]; - uint8 ssid_len; - int8 rssi; - uint16 channel; - uint16 flags; - struct ether_addr bssid; -} dhd_epno_results_t; - -struct dhd_pno_swc_evt_param { - uint16 results_rxed_so_far; - wl_pfn_significant_net_t *change_array; -}; - -typedef struct wifi_gscan_result { - uint64 ts; /* Time of discovery */ - char ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated */ - struct ether_addr macaddr; /* BSSID */ - uint32 channel; /* channel frequency in MHz */ - int32 rssi; /* in db */ - uint64 rtt; /* in nanoseconds */ - uint64 rtt_sd; /* standard deviation in rtt */ - uint16 beacon_period; /* units are Kusec */ - uint16 capability; /* Capability information */ - uint32 ie_length; /* byte length of Information Elements */ - char ie_data[1]; /* IE data to follow */ -} wifi_gscan_result_t; - -typedef struct gscan_results_cache { - struct gscan_results_cache *next; - uint8 scan_id; - uint8 flag; - uint8 tot_count; - uint8 tot_consumed; - wifi_gscan_result_t results[1]; -} gscan_results_cache_t; - -#ifdef ANQPO_SUPPORT -typedef struct { - int id; - char realm[ANQPO_MAX_HS_NAI_REALM_SIZE]; - int64_t roamingConsortiumIds[ANQPO_MAX_PFN_HS]; - uint8 plmn[ANQPO_MCC_LENGTH]; -} wifi_passpoint_network; -#endif /* ANQPO_SUPPORT */ - -typedef struct dhd_pno_gscan_capabilities { - int max_scan_cache_size; - int max_scan_buckets; - int max_ap_cache_per_scan; - int max_rssi_sample_size; - int max_scan_reporting_threshold; - int max_hotlist_bssids; - int max_hotlist_ssids; - int max_significant_wifi_change_aps; - int max_bssid_history_entries; - int max_epno_ssid_crc32; - int max_epno_hidden_ssid; - int max_white_list_ssid; -} dhd_pno_gscan_capabilities_t; - -struct dhd_pno_gscan_params { - int32 scan_fr; - uint8 bestn; - uint8 mscan; - uint8 buffer_threshold; - uint8 swc_nbssid_threshold; - uint8 swc_rssi_window_size; - uint8 lost_ap_window; - uint8 nchannel_buckets; - uint8 reason; - uint8 get_batch_flag; - uint8 send_all_results_flag; - uint16 max_ch_bucket_freq; - gscan_results_cache_t *gscan_batch_cache; - gscan_results_cache_t *gscan_hotlist_found; - gscan_results_cache_t *gscan_hotlist_lost; - uint16 nbssid_significant_change; - uint16 nbssid_hotlist; - uint16 num_epno_ssid; - uint8 num_visible_epno_ssid; - /* To keep track of visble ssid index - * across multiple FW configs i.e. config - * w/o clear in between - */ - uint8 ssid_ext_last_used_index; - struct dhd_pno_swc_evt_param param_significant; - struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; - struct list_head hotlist_bssid_list; - struct list_head significant_bssid_list; - struct list_head epno_ssid_list; - uint32 scan_id; -}; - -typedef struct gscan_scan_params { - int32 scan_fr; - uint16 nchannel_buckets; - struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; -} gscan_scan_params_t; - -typedef struct gscan_batch_params { - uint8 bestn; - uint8 mscan; - uint8 buffer_threshold; -} gscan_batch_params_t; - -struct bssid_t { - struct ether_addr macaddr; - int16 rssi_reporting_threshold; /* 0 -> no reporting threshold */ -}; - -typedef struct gscan_hotlist_scan_params { - uint16 lost_ap_window; /* number of scans to declare LOST */ - uint16 nbssid; /* number of bssids */ - struct bssid_t bssid[1]; /* n bssids to follow */ -} gscan_hotlist_scan_params_t; - -#endif /* GSCAN_SUPPORT */ -typedef union dhd_pno_params { - struct dhd_pno_legacy_params params_legacy; - struct dhd_pno_batch_params params_batch; - struct dhd_pno_hotlist_params params_hotlist; -#ifdef GSCAN_SUPPORT - struct dhd_pno_gscan_params params_gscan; -#endif /* GSCAN_SUPPORT */ -} dhd_pno_params_t; -typedef struct dhd_pno_status_info { - dhd_pub_t *dhd; - struct work_struct work; - struct mutex pno_mutex; -#ifdef GSCAN_SUPPORT - wait_queue_head_t batch_get_wait; -#endif /* GSCAN_SUPPORT */ - struct completion get_batch_done; - bool wls_supported; /* wifi location service supported or not */ - enum dhd_pno_status pno_status; - enum dhd_pno_mode pno_mode; - dhd_pno_params_t pno_params_arr[INDEX_MODE_MAX]; - struct list_head head_list; -} dhd_pno_status_info_t; - -/* wrapper functions */ -extern int -dhd_dev_pno_enable(struct net_device *dev, int enable); - -extern int -dhd_dev_pno_stop_for_ssid(struct net_device *dev); - -extern int -dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, - uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); - -extern int -dhd_dev_pno_set_for_batch(struct net_device *dev, - struct dhd_pno_batch_params *batch_params); - -extern int -dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize); - -extern int -dhd_dev_pno_stop_for_batch(struct net_device *dev); - -extern int -dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, - struct dhd_pno_hotlist_params *hotlist_params); -extern bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev); -#ifdef GSCAN_SUPPORT -extern int -dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, - void *buf, uint8 flush); -extern void * -dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, void *info, - uint32 *len); -int dhd_dev_pno_lock_access_batch_results(struct net_device *dev); -void dhd_dev_pno_unlock_access_batch_results(struct net_device *dev); -extern int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush); -extern int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time); -int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); -extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, - const void *data, int *send_evt_bytes, hotlist_type_t type); -void * dhd_dev_process_full_gscan_result(struct net_device *dev, - const void *data, uint32 len, int *send_evt_bytes); -extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); -extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); -extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); -extern void * dhd_dev_process_epno_result(struct net_device *dev, - const void *data, uint32 event, int *send_evt_bytes); -#ifdef ANQPO_SUPPORT -extern void * dhd_dev_process_anqpo_result(struct net_device *dev, - const void *data, uint32 event, int *send_evt_bytes); -#endif /* ANQPO_SUPPORT */ -#endif /* GSCAN_SUPPORT */ -/* dhd pno fuctions */ -extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd); -extern int dhd_pno_enable(dhd_pub_t *dhd, int enable); -extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, - uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); - -extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params); - -extern int dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason); - - -extern int dhd_pno_stop_for_batch(dhd_pub_t *dhd); - -extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, - struct dhd_pno_hotlist_params *hotlist_params); - -extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd); - -extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); -extern int dhd_pno_init(dhd_pub_t *dhd); -extern int dhd_pno_deinit(dhd_pub_t *dhd); -extern bool dhd_is_pno_supported(dhd_pub_t *dhd); -extern int dhd_pno_set_mac_oui(dhd_pub_t *dhd, uint8 *oui); -extern bool dhd_is_legacy_pno_enabled(dhd_pub_t *dhd); -#ifdef GSCAN_SUPPORT -extern int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, - void *buf, uint8 flush); -extern void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *info, - uint32 *len); -extern int dhd_pno_lock_batch_results(dhd_pub_t *dhd); -extern void dhd_pno_unlock_batch_results(dhd_pub_t *dhd); -extern int dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush); -extern int dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag); -extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *buf); -extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); -extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, - int *send_evt_bytes, hotlist_type_t type); -extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, - uint32 len, int *send_evt_bytes); -extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); -extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); -extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); -extern void * dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, - uint32 event, int *size); -#ifdef ANQPO_SUPPORT -extern void * dhd_pno_process_anqpo_result(dhd_pub_t *dhd, - const void *data, uint32 event, int *size); -#endif /* ANQPO_SUPPORT */ -#endif /* GSCAN_SUPPORT */ -#endif - -#endif /* __DHD_PNO_H__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h deleted file mode 100755 index 61b95d13a747..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_proto.h 455951 2014-02-17 10:52:22Z $ - */ - -#ifndef _dhd_proto_h_ -#define _dhd_proto_h_ - -#include -#include - -#ifndef IOCTL_RESP_TIMEOUT -#define IOCTL_RESP_TIMEOUT 2000 /* In milli second default value for Production FW */ -#endif /* IOCTL_RESP_TIMEOUT */ - -#ifndef MFG_IOCTL_RESP_TIMEOUT -#define MFG_IOCTL_RESP_TIMEOUT 20000 /* In milli second default value for MFG FW */ -#endif /* MFG_IOCTL_RESP_TIMEOUT */ - -/* - * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) - */ - -/* Linkage, sets prot link and updates hdrlen in pub */ -extern int dhd_prot_attach(dhd_pub_t *dhdp); - -/* Unlink, frees allocated protocol memory (including dhd_prot) */ -extern void dhd_prot_detach(dhd_pub_t *dhdp); - -/* Initialize protocol: sync w/dongle state. - * Sets dongle media info (iswl, drv_version, mac address). - */ -extern int dhd_prot_init(dhd_pub_t *dhdp); - -/* Stop protocol: sync w/dongle state. */ -extern void dhd_prot_stop(dhd_pub_t *dhdp); - -/* Add any protocol-specific data header. - * Caller must reserve prot_hdrlen prepend space. - */ -extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); - -/* Remove any protocol-specific data header. */ -extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); - -/* Use protocol to issue ioctl to dongle */ -extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); - -/* Handles a protocol control response asynchronously */ -extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); - -/* Check for and handle local prot-specific iovar commands */ -extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Add prot dump output to a buffer */ -extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); - -/* Update local copy of dongle statistics */ -extern void dhd_prot_dstats(dhd_pub_t *dhdp); - -extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); - -extern int dhd_preinit_ioctls(dhd_pub_t *dhd); - -extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, - uint reorder_info_len, void **pkt, uint32 *free_buf_count); - -#ifdef BCMPCIE -extern int dhd_prot_process_msgbuf(dhd_pub_t *dhd); -extern int dhd_prot_process_ctrlbuf(dhd_pub_t * dhd); -extern bool dhd_prot_dtohsplit(dhd_pub_t * dhd); -extern int dhd_post_dummy_msg(dhd_pub_t *dhd); -extern int dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len); -extern void dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 offset); -extern int dhd_prot_txdata(dhd_pub_t *dhd, void *p, uint8 ifidx); -extern int dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd, uint len, uint srcdelay, uint destdelay); -#endif - -/******************************** - * For version-string expansion * - */ -#if defined(BDC) -#define DHD_PROTOCOL "bdc" -#elif defined(CDC) -#define DHD_PROTOCOL "cdc" -#else -#define DHD_PROTOCOL "unknown" -#endif /* proto */ - -#endif /* _dhd_proto_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c deleted file mode 100755 index b80fffe86ae1..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c +++ /dev/null @@ -1,1951 +0,0 @@ -/* - * Header file of Broadcom Dongle Host Driver (DHD) - * Copyright (C) 1999-2014, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_rtt.c 423669 2014-07-01 13:01:55Z $ - */ -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#define GET_RTTSTATE(dhd) ((rtt_status_info_t *)dhd->rtt_state) -static DEFINE_SPINLOCK(noti_list_lock); -#define NULL_CHECK(p, s, err) \ - do { \ - if (!(p)) { \ - printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ - err = BCME_ERROR; \ - return err; \ - } \ - } while (0) - -#define RTT_IS_ENABLED(rtt_status) (rtt_status->status == RTT_ENABLED) -#define RTT_IS_STOPPED(rtt_status) (rtt_status->status == RTT_STOPPED) -#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ - (ts).tv_nsec / NSEC_PER_USEC) - -#define FTM_IOC_BUFSZ 2048 /* ioc buffsize for our module (> BCM_XTLV_HDR_SIZE) */ -#define FTM_AVAIL_MAX_SLOTS 32 -#define FTM_MAX_CONFIGS 10 -#define FTM_MAX_PARAMS 10 -#define FTM_DEFAULT_SESSION 1 -#define FTM_BURST_TIMEOUT_UNIT 250 /* 250 ns */ -#define FTM_INVALID -1 -#define FTM_DEFAULT_CNT_20M 12 -#define FTM_DEFAULT_CNT_40M 10 -#define FTM_DEFAULT_CNT_80M 5 - -/* convenience macros */ -#define FTM_TU2MICRO(_tu) ((uint64)(_tu) << 10) -#define FTM_MICRO2TU(_tu) ((uint64)(_tu) >> 10) -#define FTM_TU2MILLI(_tu) ((uint32)FTM_TU2MICRO(_tu) / 1000) -#define FTM_MICRO2MILLI(_x) ((uint32)(_x) / 1000) -#define FTM_MICRO2SEC(_x) ((uint32)(_x) / 1000000) -#define FTM_INTVL2NSEC(_intvl) ((uint32)ftm_intvl2nsec(_intvl)) -#define FTM_INTVL2USEC(_intvl) ((uint32)ftm_intvl2usec(_intvl)) -#define FTM_INTVL2MSEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000) -#define FTM_INTVL2SEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000000) -#define FTM_USECIN100MILLI(_usec) ((_usec) / 100000) - -/* broadcom specific set to have more accurate data */ -#define ENABLE_VHT_ACK - -struct rtt_noti_callback { - struct list_head list; - void *ctx; - dhd_rtt_compl_noti_fn noti_fn; -}; - -typedef struct rtt_status_info { - dhd_pub_t *dhd; - int8 status; /* current status for the current entry */ - int8 txchain; /* current device tx chain */ - int8 mpc; /* indicate we change mpc mode */ - int8 cur_idx; /* current entry to do RTT */ - struct capability { - int32 proto :8; - int32 feature :8; - int32 preamble :8; - int32 bw :8; - } rtt_capa; /* rtt capability */ - struct mutex rtt_mutex; - rtt_config_params_t rtt_config; - struct work_struct work; - struct list_head noti_fn_list; - struct list_head rtt_results_cache; /* store results for RTT */ -} rtt_status_info_t; - -/* bitmask indicating which command groups; */ -typedef enum { - FTM_SUBCMD_FLAG_METHOD = 0x01, /* FTM method command */ - FTM_SUBCMD_FLAG_SESSION = 0x02, /* FTM session command */ - FTM_SUBCMD_FLAG_ALL = FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION -} ftm_subcmd_flag_t; - -/* proxd ftm config-category definition */ -typedef enum { - FTM_CONFIG_CAT_GENERAL = 1, /* generial configuration */ - FTM_CONFIG_CAT_OPTIONS = 2, /* 'config options' */ - FTM_CONFIG_CAT_AVAIL = 3, /* 'config avail' */ -} ftm_config_category_t; - - -typedef struct ftm_subcmd_info { - int16 version; /* FTM version (optional) */ - char *name; /* cmd-name string as cmdline input */ - wl_proxd_cmd_t cmdid; /* cmd-id */ - bcm_xtlv_unpack_cbfn_t *handler; /* cmd response handler (optional) */ - ftm_subcmd_flag_t cmdflag; /* CMD flag (optional) */ -} ftm_subcmd_info_t; - - -typedef struct ftm_config_options_info { - uint32 flags; /* wl_proxd_flags_t/wl_proxd_session_flags_t */ - bool enable; -} ftm_config_options_info_t; - -typedef struct ftm_config_param_info { - uint16 tlvid; /* mapping TLV id for the item */ - union { - uint32 chanspec; - struct ether_addr mac_addr; - wl_proxd_intvl_t data_intvl; - uint32 data32; - uint16 data16; - uint8 data8; - }; -} ftm_config_param_info_t; - -/* -* definition for id-string mapping. -* This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string -* for debug-display or cmd-log-display -*/ -typedef struct ftm_strmap_entry { - int32 id; - char *text; -} ftm_strmap_entry_t; - - -typedef struct ftm_status_map_host_entry { - wl_proxd_status_t proxd_status; - rtt_reason_t rtt_reason; -} ftm_status_map_host_entry_t; - -static int -dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len); - -static wifi_rate_t -dhd_rtt_convert_rate_to_host(uint32 ratespec); - -static int -dhd_rtt_start(dhd_pub_t *dhd); - -/* ftm status mapping to host status */ -static const ftm_status_map_host_entry_t ftm_status_map_info[] = { - {WL_PROXD_E_INCOMPLETE, RTT_REASON_FAILURE}, - {WL_PROXD_E_OVERRIDDEN, RTT_REASON_FAILURE}, - {WL_PROXD_E_ASAP_FAILED, RTT_REASON_FAILURE}, - {WL_PROXD_E_NOTSTARTED, RTT_REASON_FAIL_NOT_SCHEDULED_YET}, - {WL_PROXD_E_INVALIDAVB, RTT_REASON_FAIL_INVALID_TS}, - {WL_PROXD_E_INCAPABLE, RTT_REASON_FAIL_NO_CAPABILITY}, - {WL_PROXD_E_MISMATCH, RTT_REASON_FAILURE}, - {WL_PROXD_E_DUP_SESSION, RTT_REASON_FAILURE}, - {WL_PROXD_E_REMOTE_FAIL, RTT_REASON_FAILURE}, - {WL_PROXD_E_REMOTE_INCAPABLE, RTT_REASON_FAILURE}, - {WL_PROXD_E_SCHED_FAIL, RTT_REASON_FAIL_SCHEDULE}, - {WL_PROXD_E_PROTO, RTT_REASON_FAIL_PROTOCOL}, - {WL_PROXD_E_EXPIRED, RTT_REASON_FAILURE}, - {WL_PROXD_E_TIMEOUT, RTT_REASON_FAIL_TM_TIMEOUT}, - {WL_PROXD_E_NOACK, RTT_REASON_FAIL_NO_RSP}, - {WL_PROXD_E_DEFERRED, RTT_REASON_FAILURE}, - {WL_PROXD_E_INVALID_SID, RTT_REASON_FAILURE}, - {WL_PROXD_E_REMOTE_CANCEL, RTT_REASON_FAILURE}, - {WL_PROXD_E_CANCELED, RTT_REASON_ABORTED}, - {WL_PROXD_E_INVALID_SESSION, RTT_REASON_FAILURE}, - {WL_PROXD_E_BAD_STATE, RTT_REASON_FAILURE}, - {WL_PROXD_E_ERROR, RTT_REASON_FAILURE}, - {WL_PROXD_E_OK, RTT_REASON_SUCCESS} -}; - -/* ftm tlv-id mapping */ -static const ftm_strmap_entry_t ftm_tlvid_loginfo[] = { - /* { WL_PROXD_TLV_ID_xxx, "text for WL_PROXD_TLV_ID_xxx" }, */ - { WL_PROXD_TLV_ID_NONE, "none" }, - { WL_PROXD_TLV_ID_METHOD, "method" }, - { WL_PROXD_TLV_ID_FLAGS, "flags" }, - { WL_PROXD_TLV_ID_CHANSPEC, "chanspec" }, - { WL_PROXD_TLV_ID_TX_POWER, "tx power" }, - { WL_PROXD_TLV_ID_RATESPEC, "ratespec" }, - { WL_PROXD_TLV_ID_BURST_DURATION, "burst duration" }, - { WL_PROXD_TLV_ID_BURST_PERIOD, "burst period" }, - { WL_PROXD_TLV_ID_BURST_FTM_SEP, "burst ftm sep" }, - { WL_PROXD_TLV_ID_BURST_NUM_FTM, "burst num ftm" }, - { WL_PROXD_TLV_ID_NUM_BURST, "num burst" }, - { WL_PROXD_TLV_ID_FTM_RETRIES, "ftm retries" }, - { WL_PROXD_TLV_ID_BSS_INDEX, "BSS index" }, - { WL_PROXD_TLV_ID_BSSID, "bssid" }, - { WL_PROXD_TLV_ID_INIT_DELAY, "burst init delay" }, - { WL_PROXD_TLV_ID_BURST_TIMEOUT, "burst timeout" }, - { WL_PROXD_TLV_ID_EVENT_MASK, "event mask" }, - { WL_PROXD_TLV_ID_FLAGS_MASK, "flags mask" }, - { WL_PROXD_TLV_ID_PEER_MAC, "peer addr" }, - { WL_PROXD_TLV_ID_FTM_REQ, "ftm req" }, - { WL_PROXD_TLV_ID_LCI_REQ, "lci req" }, - { WL_PROXD_TLV_ID_LCI, "lci" }, - { WL_PROXD_TLV_ID_CIVIC_REQ, "civic req" }, - { WL_PROXD_TLV_ID_CIVIC, "civic" }, - { WL_PROXD_TLV_ID_AVAIL, "availability" }, - { WL_PROXD_TLV_ID_SESSION_FLAGS, "session flags" }, - { WL_PROXD_TLV_ID_SESSION_FLAGS_MASK, "session flags mask" }, - { WL_PROXD_TLV_ID_RX_MAX_BURST, "rx max bursts" }, - { WL_PROXD_TLV_ID_RANGING_INFO, "ranging info" }, - { WL_PROXD_TLV_ID_RANGING_FLAGS, "ranging flags" }, - { WL_PROXD_TLV_ID_RANGING_FLAGS_MASK, "ranging flags mask" }, - /* output - 512 + x */ - { WL_PROXD_TLV_ID_STATUS, "status" }, - { WL_PROXD_TLV_ID_COUNTERS, "counters" }, - { WL_PROXD_TLV_ID_INFO, "info" }, - { WL_PROXD_TLV_ID_RTT_RESULT, "rtt result" }, - { WL_PROXD_TLV_ID_AOA_RESULT, "aoa result" }, - { WL_PROXD_TLV_ID_SESSION_INFO, "session info" }, - { WL_PROXD_TLV_ID_SESSION_STATUS, "session status" }, - { WL_PROXD_TLV_ID_SESSION_ID_LIST, "session ids" }, - /* debug tlvs can be added starting 1024 */ - { WL_PROXD_TLV_ID_DEBUG_MASK, "debug mask" }, - { WL_PROXD_TLV_ID_COLLECT, "collect" }, - { WL_PROXD_TLV_ID_STRBUF, "result" } -}; - -static const ftm_strmap_entry_t ftm_event_type_loginfo[] = { - /* wl_proxd_event_type_t, text-string */ - { WL_PROXD_EVENT_NONE, "none" }, - { WL_PROXD_EVENT_SESSION_CREATE, "session create" }, - { WL_PROXD_EVENT_SESSION_START, "session start" }, - { WL_PROXD_EVENT_FTM_REQ, "FTM req" }, - { WL_PROXD_EVENT_BURST_START, "burst start" }, - { WL_PROXD_EVENT_BURST_END, "burst end" }, - { WL_PROXD_EVENT_SESSION_END, "session end" }, - { WL_PROXD_EVENT_SESSION_RESTART, "session restart" }, - { WL_PROXD_EVENT_BURST_RESCHED, "burst rescheduled" }, - { WL_PROXD_EVENT_SESSION_DESTROY, "session destroy" }, - { WL_PROXD_EVENT_RANGE_REQ, "range request" }, - { WL_PROXD_EVENT_FTM_FRAME, "FTM frame" }, - { WL_PROXD_EVENT_DELAY, "delay" }, - { WL_PROXD_EVENT_VS_INITIATOR_RPT, "initiator-report " }, /* rx initiator-rpt */ - { WL_PROXD_EVENT_RANGING, "ranging " }, -}; - -/* -* session-state --> text string mapping -*/ -static const ftm_strmap_entry_t ftm_session_state_value_loginfo[] = { - /* wl_proxd_session_state_t, text string */ - { WL_PROXD_SESSION_STATE_CREATED, "created" }, - { WL_PROXD_SESSION_STATE_CONFIGURED, "configured" }, - { WL_PROXD_SESSION_STATE_STARTED, "started" }, - { WL_PROXD_SESSION_STATE_DELAY, "delay" }, - { WL_PROXD_SESSION_STATE_USER_WAIT, "user-wait" }, - { WL_PROXD_SESSION_STATE_SCHED_WAIT, "sched-wait" }, - { WL_PROXD_SESSION_STATE_BURST, "burst" }, - { WL_PROXD_SESSION_STATE_STOPPING, "stopping" }, - { WL_PROXD_SESSION_STATE_ENDED, "ended" }, - { WL_PROXD_SESSION_STATE_DESTROYING, "destroying" }, - { WL_PROXD_SESSION_STATE_NONE, "none" } -}; - -/* -* ranging-state --> text string mapping -*/ -static const ftm_strmap_entry_t ftm_ranging_state_value_loginfo [] = { - /* wl_proxd_ranging_state_t, text string */ - { WL_PROXD_RANGING_STATE_NONE, "none" }, - { WL_PROXD_RANGING_STATE_NOTSTARTED, "nonstarted" }, - { WL_PROXD_RANGING_STATE_INPROGRESS, "inprogress" }, - { WL_PROXD_RANGING_STATE_DONE, "done" }, -}; - -/* -* status --> text string mapping -*/ -static const ftm_strmap_entry_t ftm_status_value_loginfo[] = { - /* wl_proxd_status_t, text-string */ - { WL_PROXD_E_OVERRIDDEN, "overridden" }, - { WL_PROXD_E_ASAP_FAILED, "ASAP failed" }, - { WL_PROXD_E_NOTSTARTED, "not started" }, - { WL_PROXD_E_INVALIDAVB, "invalid AVB" }, - { WL_PROXD_E_INCAPABLE, "incapable" }, - { WL_PROXD_E_MISMATCH, "mismatch"}, - { WL_PROXD_E_DUP_SESSION, "dup session" }, - { WL_PROXD_E_REMOTE_FAIL, "remote fail" }, - { WL_PROXD_E_REMOTE_INCAPABLE, "remote incapable" }, - { WL_PROXD_E_SCHED_FAIL, "sched failure" }, - { WL_PROXD_E_PROTO, "protocol error" }, - { WL_PROXD_E_EXPIRED, "expired" }, - { WL_PROXD_E_TIMEOUT, "timeout" }, - { WL_PROXD_E_NOACK, "no ack" }, - { WL_PROXD_E_DEFERRED, "deferred" }, - { WL_PROXD_E_INVALID_SID, "invalid session id" }, - { WL_PROXD_E_REMOTE_CANCEL, "remote cancel" }, - { WL_PROXD_E_CANCELED, "canceled" }, - { WL_PROXD_E_INVALID_SESSION, "invalid session" }, - { WL_PROXD_E_BAD_STATE, "bad state" }, - { WL_PROXD_E_ERROR, "error" }, - { WL_PROXD_E_OK, "OK" } -}; - -/* -* time interval unit --> text string mapping -*/ -static const ftm_strmap_entry_t ftm_tmu_value_loginfo[] = { - /* wl_proxd_tmu_t, text-string */ - { WL_PROXD_TMU_TU, "TU" }, - { WL_PROXD_TMU_SEC, "sec" }, - { WL_PROXD_TMU_MILLI_SEC, "ms" }, - { WL_PROXD_TMU_MICRO_SEC, "us" }, - { WL_PROXD_TMU_NANO_SEC, "ns" }, - { WL_PROXD_TMU_PICO_SEC, "ps" } -}; - -#define RSPEC_BW(rspec) ((rspec) & WL_RSPEC_BW_MASK) -#define RSPEC_IS20MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_20MHZ) -#define RSPEC_IS40MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_40MHZ) -#define RSPEC_IS80MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_80MHZ) -#define RSPEC_IS160MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_160MHZ) - -#define IS_MCS(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) != WL_RSPEC_ENCODE_RATE) -#define IS_STBC(rspec) (((((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) || \ - (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)) && \ - (((rspec) & WL_RSPEC_STBC) == WL_RSPEC_STBC)) -#define RSPEC_ISSGI(rspec) (((rspec) & WL_RSPEC_SGI) != 0) -#define RSPEC_ISLDPC(rspec) (((rspec) & WL_RSPEC_LDPC) != 0) -#define RSPEC_ISSTBC(rspec) (((rspec) & WL_RSPEC_STBC) != 0) -#define RSPEC_ISTXBF(rspec) (((rspec) & WL_RSPEC_TXBF) != 0) -#define RSPEC_ISVHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) -#define RSPEC_ISHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) -#define RSPEC_ISLEGACY(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) -#define RSPEC2RATE(rspec) (RSPEC_ISLEGACY(rspec) ? \ - ((rspec) & RSPEC_RATE_MASK) : rate_rspec2rate(rspec)) -/* return rate in unit of 500Kbps -- for internal use in wlc_rate_sel.c */ -#define RSPEC2KBPS(rspec) rate_rspec2rate(rspec) - -struct ieee_80211_mcs_rate_info { - uint8 constellation_bits; - uint8 coding_q; - uint8 coding_d; -}; - -static const struct ieee_80211_mcs_rate_info wl_mcs_info[] = { - { 1, 1, 2 }, /* MCS 0: MOD: BPSK, CR 1/2 */ - { 2, 1, 2 }, /* MCS 1: MOD: QPSK, CR 1/2 */ - { 2, 3, 4 }, /* MCS 2: MOD: QPSK, CR 3/4 */ - { 4, 1, 2 }, /* MCS 3: MOD: 16QAM, CR 1/2 */ - { 4, 3, 4 }, /* MCS 4: MOD: 16QAM, CR 3/4 */ - { 6, 2, 3 }, /* MCS 5: MOD: 64QAM, CR 2/3 */ - { 6, 3, 4 }, /* MCS 6: MOD: 64QAM, CR 3/4 */ - { 6, 5, 6 }, /* MCS 7: MOD: 64QAM, CR 5/6 */ - { 8, 3, 4 }, /* MCS 8: MOD: 256QAM, CR 3/4 */ - { 8, 5, 6 } /* MCS 9: MOD: 256QAM, CR 5/6 */ -}; - -/** - * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination. - * 'mcs' : a *single* spatial stream MCS (11n or 11ac) - */ -uint -rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) -{ - const int ksps = 250; /* kilo symbols per sec, 4 us sym */ - const int Nsd_20MHz = 52; - const int Nsd_40MHz = 108; - const int Nsd_80MHz = 234; - const int Nsd_160MHz = 468; - uint rate; - - if (mcs == 32) { - /* just return fixed values for mcs32 instead of trying to parametrize */ - rate = (sgi == 0) ? 6000 : 6778; - } else if (mcs <= 9) { - /* This calculation works for 11n HT and 11ac VHT if the HT mcs values - * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. - * That is, HT MCS 23 is a base MCS = 7, Nss = 3 - */ - - /* find the number of complex numbers per symbol */ - if (RSPEC_IS20MHZ(bw)) { - rate = Nsd_20MHz; - } else if (RSPEC_IS40MHZ(bw)) { - rate = Nsd_40MHz; - } else if (bw == WL_RSPEC_BW_80MHZ) { - rate = Nsd_80MHz; - } else if (bw == WL_RSPEC_BW_160MHZ) { - rate = Nsd_160MHz; - } else { - rate = 0; - } - - /* multiply by bits per number from the constellation in use */ - rate = rate * wl_mcs_info[mcs].constellation_bits; - - /* adjust for the number of spatial streams */ - rate = rate * nss; - - /* adjust for the coding rate given as a quotient and divisor */ - rate = (rate * wl_mcs_info[mcs].coding_q) / wl_mcs_info[mcs].coding_d; - - /* multiply by Kilo symbols per sec to get Kbps */ - rate = rate * ksps; - - /* adjust the symbols per sec for SGI - * symbol duration is 4 us without SGI, and 3.6 us with SGI, - * so ratio is 10 / 9 - */ - if (sgi) { - /* add 4 for rounding of division by 9 */ - rate = ((rate * 10) + 4) / 9; - } - } else { - rate = 0; - } - - return rate; -} /* wlc_rate_mcs2rate */ - -/** take a well formed ratespec_t arg and return phy rate in [Kbps] units */ -int -rate_rspec2rate(uint32 rspec) -{ - int rate = 0; - - if (RSPEC_ISLEGACY(rspec)) { - rate = 500 * (rspec & WL_RSPEC_RATE_MASK); - } else if (RSPEC_ISHT(rspec)) { - uint mcs = (rspec & WL_RSPEC_RATE_MASK); - - if (mcs == 32) { - rate = rate_mcs2rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec)); - } else { - uint nss = 1 + (mcs / 8); - mcs = mcs % 8; - rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); - } - } else if (RSPEC_ISVHT(rspec)) { - uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK); - uint nss = (rspec & WL_RSPEC_VHT_MCS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; - - ASSERT(mcs <= 9); - ASSERT(nss <= 8); - - rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); - } else { - ASSERT(0); - } - - return rate; -} - -char resp_buf[WLC_IOCTL_SMLEN]; - -static uint64 -ftm_intvl2nsec(const wl_proxd_intvl_t *intvl) -{ - uint64 ret; - ret = intvl->intvl; - switch (intvl->tmu) { - case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret) * 1000; break; - case WL_PROXD_TMU_SEC: ret *= 1000000000; break; - case WL_PROXD_TMU_MILLI_SEC: ret *= 1000000; break; - case WL_PROXD_TMU_MICRO_SEC: ret *= 1000; break; - case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000; break; - case WL_PROXD_TMU_NANO_SEC: /* fall through */ - default: break; - } - return ret; -} -uint64 -ftm_intvl2usec(const wl_proxd_intvl_t *intvl) -{ - uint64 ret; - ret = intvl->intvl; - switch (intvl->tmu) { - case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret); break; - case WL_PROXD_TMU_SEC: ret *= 1000000; break; - case WL_PROXD_TMU_NANO_SEC: ret = intvl->intvl / 1000; break; - case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000000; break; - case WL_PROXD_TMU_MILLI_SEC: ret *= 1000; break; - case WL_PROXD_TMU_MICRO_SEC: /* fall through */ - default: break; - } - return ret; -} - -/* -* lookup 'id' (as a key) from a fw status to host map table -* if found, return the corresponding reason code -*/ - -static rtt_reason_t -ftm_get_statusmap_info(wl_proxd_status_t id, const ftm_status_map_host_entry_t *p_table, - uint32 num_entries) -{ - int i; - const ftm_status_map_host_entry_t *p_entry; - /* scan thru the table till end */ - p_entry = p_table; - for (i = 0; i < (int) num_entries; i++) - { - if (p_entry->proxd_status == id) { - return p_entry->rtt_reason; - } - p_entry++; /* next entry */ - } - return RTT_REASON_FAILURE; /* not found */ -} -/* -* lookup 'id' (as a key) from a table -* if found, return the entry pointer, otherwise return NULL -*/ -static const ftm_strmap_entry_t* -ftm_get_strmap_info(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) -{ - int i; - const ftm_strmap_entry_t *p_entry; - - /* scan thru the table till end */ - p_entry = p_table; - for (i = 0; i < (int) num_entries; i++) - { - if (p_entry->id == id) - return p_entry; - p_entry++; /* next entry */ - } - return NULL; /* not found */ -} - -/* -* map enum to a text-string for display, this function is called by the following: -* For debug/trace: -* ftm_[cmdid|tlvid]_to_str() -* For TLV-output log for 'get' commands -* ftm_[method|tmu|caps|status|state]_value_to_logstr() -* Input: -* pTable -- point to a 'enum to string' table. -*/ -static const char * -ftm_map_id_to_str(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) -{ - const ftm_strmap_entry_t*p_entry = ftm_get_strmap_info(id, p_table, num_entries); - if (p_entry) - return (p_entry->text); - - return "invalid"; -} - - -#ifdef RTT_DEBUG - -/* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */ -#define DEF_STRMAP_ENTRY(id) { (id), #id } - -/* ftm cmd-id mapping */ -static const ftm_strmap_entry_t ftm_cmdid_map[] = { - /* {wl_proxd_cmd_t(WL_PROXD_CMD_xxx), "WL_PROXD_CMD_xxx" }, */ - DEF_STRMAP_ENTRY(WL_PROXD_CMD_NONE), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_VERSION), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_ENABLE), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_DISABLE), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_CONFIG), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_SESSION), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_BURST_REQUEST), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_SESSION), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_DELETE_SESSION), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RESULT), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_INFO), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_STATUS), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_SESSIONS), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_COUNTERS), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_CLEAR_COUNTERS), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_COLLECT), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_TUNE), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_DUMP), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_RANGING), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_RANGING), - DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RANGING_INFO), -}; - -/* -* map a ftm cmd-id to a text-string for display -*/ -static const char * -ftm_cmdid_to_str(uint16 cmdid) -{ - return ftm_map_id_to_str((int32) cmdid, &ftm_cmdid_map[0], ARRAYSIZE(ftm_cmdid_map)); -} -#endif /* RTT_DEBUG */ - - -/* -* convert BCME_xxx error codes into related error strings -* note, bcmerrorstr() defined in bcmutils is for BCMDRIVER only, -* this duplicate copy is for WL access and may need to clean up later -*/ -static const char *ftm_bcmerrorstrtable[] = BCMERRSTRINGTABLE; -static const char * -ftm_status_value_to_logstr(wl_proxd_status_t status) -{ - static char ftm_msgbuf_status_undef[32]; - const ftm_strmap_entry_t *p_loginfo; - int bcmerror; - - /* check if within BCME_xxx error range */ - bcmerror = (int) status; - if (VALID_BCMERROR(bcmerror)) - return ftm_bcmerrorstrtable[-bcmerror]; - - /* otherwise, look for 'proxd ftm status' range */ - p_loginfo = ftm_get_strmap_info((int32) status, - &ftm_status_value_loginfo[0], ARRAYSIZE(ftm_status_value_loginfo)); - if (p_loginfo) - return p_loginfo->text; - - /* report for 'out of range' FTM-status error code */ - memset(ftm_msgbuf_status_undef, 0, sizeof(ftm_msgbuf_status_undef)); - snprintf(ftm_msgbuf_status_undef, sizeof(ftm_msgbuf_status_undef), - "Undefined status %d", status); - return &ftm_msgbuf_status_undef[0]; -} - -static const char * -ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu) -{ - return ftm_map_id_to_str((int32)tmu, - &ftm_tmu_value_loginfo[0], ARRAYSIZE(ftm_tmu_value_loginfo)); -} - -static const ftm_strmap_entry_t* -ftm_get_event_type_loginfo(wl_proxd_event_type_t event_type) -{ - /* look up 'event-type' from a predefined table */ - return ftm_get_strmap_info((int32) event_type, - ftm_event_type_loginfo, ARRAYSIZE(ftm_event_type_loginfo)); -} - -static const char * -ftm_session_state_value_to_logstr(wl_proxd_session_state_t state) -{ - return ftm_map_id_to_str((int32)state, &ftm_session_state_value_loginfo[0], - ARRAYSIZE(ftm_session_state_value_loginfo)); -} - - -/* -* send 'proxd' iovar for all ftm get-related commands -*/ -static int -rtt_do_get_ioctl(dhd_pub_t *dhd, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize, - ftm_subcmd_info_t *p_subcmd_info) -{ - - wl_proxd_iov_t *p_iovresp = (wl_proxd_iov_t *)resp_buf; - int status; - int tlvs_len; - /* send getbuf proxd iovar */ - status = dhd_getiovar(dhd, 0, "proxd", (char *)p_proxd_iov, - proxd_iovsize, (char **)&p_iovresp, WLC_IOCTL_SMLEN); - if (status != BCME_OK) { - DHD_ERROR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n", - __FUNCTION__, p_subcmd_info->cmdid, status)); - return status; - } - if (p_subcmd_info->cmdid == WL_PROXD_CMD_GET_VERSION) { - p_subcmd_info->version = ltoh16(p_iovresp->version); - DHD_RTT(("ftm version: 0x%x\n", ltoh16(p_iovresp->version))); - goto exit; - } - - tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE; - if (tlvs_len < 0) { - DHD_ERROR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n", - __FUNCTION__, ltoh16(p_iovresp->len), (int) WL_PROXD_IOV_HDR_SIZE)); - tlvs_len = 0; - } - - if (tlvs_len > 0 && p_subcmd_info->handler) { - /* unpack TLVs and invokes the cbfn for processing */ - status = bcm_unpack_xtlv_buf(p_proxd_iov, (uint8 *)p_iovresp->tlvs, - tlvs_len, BCM_XTLV_OPTION_ALIGN32, p_subcmd_info->handler); - } -exit: - return status; -} - - -static wl_proxd_iov_t * -rtt_alloc_getset_buf(wl_proxd_method_t method, wl_proxd_session_id_t session_id, - wl_proxd_cmd_t cmdid, uint16 tlvs_bufsize, uint16 *p_out_bufsize) -{ - uint16 proxd_iovsize; - uint16 kflags; - wl_proxd_tlv_t *p_tlv; - wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) NULL; - - *p_out_bufsize = 0; /* init */ - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - /* calculate the whole buffer size, including one reserve-tlv entry in the header */ - proxd_iovsize = sizeof(wl_proxd_iov_t) + tlvs_bufsize; - - p_proxd_iov = kzalloc(proxd_iovsize, kflags); - if (p_proxd_iov == NULL) { - DHD_ERROR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize)); - return NULL; - } - - /* setup proxd-FTM-method iovar header */ - p_proxd_iov->version = htol16(WL_PROXD_API_VERSION); - p_proxd_iov->len = htol16(proxd_iovsize); /* caller may adjust it based on #of TLVs */ - p_proxd_iov->cmd = htol16(cmdid); - p_proxd_iov->method = htol16(method); - p_proxd_iov->sid = htol16(session_id); - - /* initialize the reserved/dummy-TLV in iovar header */ - p_tlv = p_proxd_iov->tlvs; - p_tlv->id = htol16(WL_PROXD_TLV_ID_NONE); - p_tlv->len = htol16(0); - - *p_out_bufsize = proxd_iovsize; /* for caller's reference */ - - return p_proxd_iov; -} - - -static int -dhd_rtt_common_get_handler(dhd_pub_t *dhd, ftm_subcmd_info_t *p_subcmd_info, - wl_proxd_method_t method, - wl_proxd_session_id_t session_id) -{ - int status = BCME_OK; - uint16 proxd_iovsize = 0; - wl_proxd_iov_t *p_proxd_iov; -#ifdef RTT_DEBUG - DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", - __FUNCTION__, method, session_id, p_subcmd_info->cmdid, - ftm_cmdid_to_str(p_subcmd_info->cmdid))); -#endif - /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ - p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, - 0, &proxd_iovsize); - - if (p_proxd_iov == NULL) - return BCME_NOMEM; - - status = rtt_do_get_ioctl(dhd, p_proxd_iov, proxd_iovsize, p_subcmd_info); - - if (status != BCME_OK) { - DHD_RTT(("%s failed: status=%d\n", __FUNCTION__, status)); - } - kfree(p_proxd_iov); - return status; -} - -/* -* common handler for set-related proxd method commands which require no TLV as input -* wl proxd ftm [session-id] -* e.g. -* wl proxd ftm enable -- to enable ftm -* wl proxd ftm disable -- to disable ftm -* wl proxd ftm start -- to start a specified session -* wl proxd ftm stop -- to cancel a specified session; -* state is maintained till session is delete. -* wl proxd ftm delete -- to delete a specified session -* wl proxd ftm [] clear-counters -- to clear counters -* wl proxd ftm burst-request -- on initiator: to send burst request; -* on target: send FTM frame -* wl proxd ftm collect -* wl proxd ftm tune (TBD) -*/ -static int -dhd_rtt_common_set_handler(dhd_pub_t *dhd, const ftm_subcmd_info_t *p_subcmd_info, - wl_proxd_method_t method, wl_proxd_session_id_t session_id) -{ - uint16 proxd_iovsize; - wl_proxd_iov_t *p_proxd_iov; - int ret; - -#ifdef RTT_DEBUG - DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", - __FUNCTION__, method, session_id, p_subcmd_info->cmdid, - ftm_cmdid_to_str(p_subcmd_info->cmdid))); -#endif - - /* allocate and initialize a temp buffer for 'set proxd' iovar */ - proxd_iovsize = 0; - p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, - 0, &proxd_iovsize); /* no TLV */ - if (p_proxd_iov == NULL) - return BCME_NOMEM; - - /* no TLV to pack, simply issue a set-proxd iovar */ - ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, proxd_iovsize, NULL, 0, TRUE); -#ifdef RTT_DEBUG - if (ret != BCME_OK) { - DHD_RTT(("error: IOVAR failed, status=%d\n", ret)); - } -#endif - /* clean up */ - kfree(p_proxd_iov); - - return ret; -} - -static int -rtt_unpack_xtlv_cbfn(void *ctx, uint8 *p_data, uint16 tlvid, uint16 len) -{ - int ret = BCME_OK; - wl_proxd_ftm_session_status_t *p_data_info; - switch (tlvid) { - case WL_PROXD_TLV_ID_RTT_RESULT: - ret = dhd_rtt_convert_results_to_host((rtt_report_t *)ctx, - p_data, tlvid, len); - break; - case WL_PROXD_TLV_ID_SESSION_STATUS: - memcpy(ctx, p_data, sizeof(wl_proxd_ftm_session_status_t)); - p_data_info = (wl_proxd_ftm_session_status_t *)ctx; - p_data_info->state = ltoh16_ua(&p_data_info->state); - p_data_info->status = ltoh32_ua(&p_data_info->status); - break; - default: - DHD_ERROR(("> Unsupported TLV ID %d\n", tlvid)); - ret = BCME_ERROR; - break; - } - - return ret; -} -static int -rtt_handle_config_options(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, - uint16 *p_buf_space_left, ftm_config_options_info_t *ftm_configs, int ftm_cfg_cnt) -{ - int ret = BCME_OK; - int cfg_idx = 0; - uint32 flags = WL_PROXD_FLAG_NONE; - uint32 flags_mask = WL_PROXD_FLAG_NONE; - uint32 new_mask; /* cmdline input */ - ftm_config_options_info_t *p_option_info; - uint16 type = (session_id == WL_PROXD_SESSION_ID_GLOBAL) ? - WL_PROXD_TLV_ID_FLAGS_MASK : WL_PROXD_TLV_ID_SESSION_FLAGS_MASK; - for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { - p_option_info = (ftm_configs + cfg_idx); - if (p_option_info != NULL) { - new_mask = p_option_info->flags; - /* update flags mask */ - flags_mask |= new_mask; - if (p_option_info->enable) { - flags |= new_mask; /* set the bit on */ - } else { - flags &= ~new_mask; /* set the bit off */ - } - } - } - flags = htol32(flags); - flags_mask = htol32(flags_mask); - /* setup flags_mask TLV */ - ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, - type, sizeof(uint32), &flags_mask, BCM_XTLV_OPTION_ALIGN32); - if (ret != BCME_OK) { - DHD_ERROR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n", - __FUNCTION__, ret)); - goto exit; - } - - type = (session_id == WL_PROXD_SESSION_ID_GLOBAL)? - WL_PROXD_TLV_ID_FLAGS : WL_PROXD_TLV_ID_SESSION_FLAGS; - /* setup flags TLV */ - ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, - type, sizeof(uint32), &flags, BCM_XTLV_OPTION_ALIGN32); - if (ret != BCME_OK) { -#ifdef RTT_DEBUG - DHD_RTT(("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n", - __FUNCTION__, ret)); -#endif - } -exit: - return ret; -} - -static int -rtt_handle_config_general(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, - uint16 *p_buf_space_left, ftm_config_param_info_t *ftm_configs, int ftm_cfg_cnt) -{ - int ret = BCME_OK; - int cfg_idx = 0; - uint32 chanspec; - ftm_config_param_info_t *p_config_param_info; - void *p_src_data; - uint16 src_data_size; /* size of data pointed by p_src_data as 'source' */ - for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { - p_config_param_info = (ftm_configs + cfg_idx); - if (p_config_param_info != NULL) { - switch (p_config_param_info->tlvid) { - case WL_PROXD_TLV_ID_BSS_INDEX: - case WL_PROXD_TLV_ID_FTM_RETRIES: - case WL_PROXD_TLV_ID_FTM_REQ_RETRIES: - p_src_data = &p_config_param_info->data8; - src_data_size = sizeof(uint8); - break; - case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* uint16 */ - case WL_PROXD_TLV_ID_NUM_BURST: - case WL_PROXD_TLV_ID_RX_MAX_BURST: - p_src_data = &p_config_param_info->data16; - src_data_size = sizeof(uint16); - break; - case WL_PROXD_TLV_ID_TX_POWER: /* uint32 */ - case WL_PROXD_TLV_ID_RATESPEC: - case WL_PROXD_TLV_ID_EVENT_MASK: /* wl_proxd_event_mask_t/uint32 */ - case WL_PROXD_TLV_ID_DEBUG_MASK: - p_src_data = &p_config_param_info->data32; - src_data_size = sizeof(uint32); - break; - case WL_PROXD_TLV_ID_CHANSPEC: /* chanspec_t --> 32bit */ - chanspec = p_config_param_info->chanspec; - p_src_data = (void *) &chanspec; - src_data_size = sizeof(uint32); - break; - case WL_PROXD_TLV_ID_BSSID: /* mac address */ - case WL_PROXD_TLV_ID_PEER_MAC: - p_src_data = &p_config_param_info->mac_addr; - src_data_size = sizeof(struct ether_addr); - break; - case WL_PROXD_TLV_ID_BURST_DURATION: /* wl_proxd_intvl_t */ - case WL_PROXD_TLV_ID_BURST_PERIOD: - case WL_PROXD_TLV_ID_BURST_FTM_SEP: - case WL_PROXD_TLV_ID_BURST_TIMEOUT: - case WL_PROXD_TLV_ID_INIT_DELAY: - p_src_data = &p_config_param_info->data_intvl; - src_data_size = sizeof(wl_proxd_intvl_t); - break; - default: - ret = BCME_BADARG; - break; - } - if (ret != BCME_OK) { - DHD_ERROR(("%s bad TLV ID : %d\n", - __FUNCTION__, p_config_param_info->tlvid)); - break; - } - - ret = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left, - p_config_param_info->tlvid, src_data_size, p_src_data, - BCM_XTLV_OPTION_ALIGN32); - if (ret != BCME_OK) { - DHD_ERROR(("%s: bcm_pack_xltv_entry() failed," - " status=%d\n", __FUNCTION__, ret)); - break; - } - - } - } - return ret; -} - -static int -dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version) -{ - int ret; - ftm_subcmd_info_t subcmd_info; - subcmd_info.name = "ver"; - subcmd_info.cmdid = WL_PROXD_CMD_GET_VERSION; - subcmd_info.handler = NULL; - ret = dhd_rtt_common_get_handler(dhd, &subcmd_info, - WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); - *out_version = (ret == BCME_OK) ? subcmd_info.version : 0; - return ret; -} - -static int -dhd_rtt_ftm_enable(dhd_pub_t *dhd, bool enable) -{ - ftm_subcmd_info_t subcmd_info; - subcmd_info.name = (enable)? "enable" : "disable"; - subcmd_info.cmdid = (enable)? WL_PROXD_CMD_ENABLE: WL_PROXD_CMD_DISABLE; - subcmd_info.handler = NULL; - return dhd_rtt_common_set_handler(dhd, &subcmd_info, - WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); -} - -static int -dhd_rtt_start_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, bool start) -{ - ftm_subcmd_info_t subcmd_info; - subcmd_info.name = (start)? "start session" : "stop session"; - subcmd_info.cmdid = (start)? WL_PROXD_CMD_START_SESSION: WL_PROXD_CMD_STOP_SESSION; - subcmd_info.handler = NULL; - return dhd_rtt_common_set_handler(dhd, &subcmd_info, - WL_PROXD_METHOD_FTM, session_id); -} - -static int -dhd_rtt_delete_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id) -{ - ftm_subcmd_info_t subcmd_info; - subcmd_info.name = "delete session"; - subcmd_info.cmdid = WL_PROXD_CMD_DELETE_SESSION; - subcmd_info.handler = NULL; - return dhd_rtt_common_set_handler(dhd, &subcmd_info, - WL_PROXD_METHOD_FTM, session_id); -} - -static int -dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, - ftm_config_category_t catagory, void *ftm_configs, int ftm_cfg_cnt) -{ - ftm_subcmd_info_t subcmd_info; - wl_proxd_tlv_t *p_tlv; - /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ - wl_proxd_iov_t *p_proxd_iov; - uint16 proxd_iovsize = 0; - uint16 bufsize; - uint16 buf_space_left; - uint16 all_tlvsize; - int ret = BCME_OK; - - subcmd_info.name = "config"; - subcmd_info.cmdid = WL_PROXD_CMD_CONFIG; - - p_proxd_iov = rtt_alloc_getset_buf(WL_PROXD_METHOD_FTM, session_id, subcmd_info.cmdid, - FTM_IOC_BUFSZ, &proxd_iovsize); - - if (p_proxd_iov == NULL) { - DHD_ERROR(("%s : failed to allocate the iovar (size :%d)\n", - __FUNCTION__, FTM_IOC_BUFSZ)); - return BCME_NOMEM; - } - /* setup TLVs */ - bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */ - p_tlv = &p_proxd_iov->tlvs[0]; - /* TLV buffer starts with a full size, will decrement for each packed TLV */ - buf_space_left = bufsize; - if (catagory == FTM_CONFIG_CAT_OPTIONS) { - ret = rtt_handle_config_options(session_id, &p_tlv, &buf_space_left, - (ftm_config_options_info_t *)ftm_configs, ftm_cfg_cnt); - } else if (catagory == FTM_CONFIG_CAT_GENERAL) { - ret = rtt_handle_config_general(session_id, &p_tlv, &buf_space_left, - (ftm_config_param_info_t *)ftm_configs, ftm_cfg_cnt); - } - if (ret == BCME_OK) { - /* update the iov header, set len to include all TLVs + header */ - all_tlvsize = (bufsize - buf_space_left); - p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE); - ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, - all_tlvsize + WL_PROXD_IOV_HDR_SIZE, NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("%s : failed to set config\n", __FUNCTION__)); - } - } - /* clean up */ - kfree(p_proxd_iov); - return ret; -} - -chanspec_t -dhd_rtt_convert_to_chspec(wifi_channel_info_t channel) -{ - int bw; - chanspec_t chanspec = 0; - uint8 center_chan; - uint8 primary_chan; - /* set witdh to 20MHZ for 2.4G HZ */ - if (channel.center_freq >= 2400 && channel.center_freq <= 2500) { - channel.width = WIFI_CHAN_WIDTH_20; - } - switch (channel.width) { - case WIFI_CHAN_WIDTH_20: - bw = WL_CHANSPEC_BW_20; - primary_chan = wf_mhz2channel(channel.center_freq, 0); - chanspec = wf_channel2chspec(primary_chan, bw); - break; - case WIFI_CHAN_WIDTH_40: - bw = WL_CHANSPEC_BW_40; - primary_chan = wf_mhz2channel(channel.center_freq, 0); - chanspec = wf_channel2chspec(primary_chan, bw); - break; - case WIFI_CHAN_WIDTH_80: - bw = WL_CHANSPEC_BW_80; - primary_chan = wf_mhz2channel(channel.center_freq, 0); - center_chan = wf_mhz2channel(channel.center_freq0, 0); - chanspec = wf_chspec_80(center_chan, primary_chan); - break; - default: - DHD_ERROR(("doesn't support this bandwith : %d", channel.width)); - bw = -1; - break; - } - return chanspec; -} - -int -dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params) -{ - int err = BCME_OK; - int idx; - rtt_status_info_t *rtt_status; - NULL_CHECK(params, "params is NULL", err); - - NULL_CHECK(dhd, "dhd is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - if (!HAS_11MC_CAP(rtt_status->rtt_capa.proto)) { - DHD_ERROR(("doesn't support RTT \n")); - return BCME_ERROR; - } - if (rtt_status->status != RTT_STOPPED) { - DHD_ERROR(("rtt is already started\n")); - return BCME_BUSY; - } - DHD_RTT(("%s enter\n", __FUNCTION__)); - - memset(rtt_status->rtt_config.target_info, 0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); - rtt_status->rtt_config.rtt_target_cnt = params->rtt_target_cnt; - memcpy(rtt_status->rtt_config.target_info, - params->target_info, TARGET_INFO_SIZE(params->rtt_target_cnt)); - rtt_status->status = RTT_STARTED; - /* start to measure RTT from first device */ - /* find next target to trigger RTT */ - for (idx = rtt_status->cur_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { - /* skip the disabled device */ - if (rtt_status->rtt_config.target_info[idx].disable) { - continue; - } else { - /* set the idx to cur_idx */ - rtt_status->cur_idx = idx; - break; - } - } - if (idx < rtt_status->rtt_config.rtt_target_cnt) { - DHD_RTT(("rtt_status->cur_idx : %d\n", rtt_status->cur_idx)); - schedule_work(&rtt_status->work); - } - return err; -} - -int -dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt) -{ - int err = BCME_OK; - int i = 0, j = 0; - rtt_status_info_t *rtt_status; - - NULL_CHECK(dhd, "dhd is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - if (rtt_status->status == RTT_STOPPED) { - DHD_ERROR(("rtt is not started\n")); - return BCME_OK; - } - DHD_RTT(("%s enter\n", __FUNCTION__)); - mutex_lock(&rtt_status->rtt_mutex); - for (i = 0; i < mac_cnt; i++) { - for (j = 0; j < rtt_status->rtt_config.rtt_target_cnt; j++) { - if (!bcmp(&mac_list[i], &rtt_status->rtt_config.target_info[j].addr, - ETHER_ADDR_LEN)) { - rtt_status->rtt_config.target_info[j].disable = TRUE; - } - } - } - mutex_unlock(&rtt_status->rtt_mutex); - return err; -} - -static int -dhd_rtt_start(dhd_pub_t *dhd) -{ - int err = BCME_OK; - char eabuf[ETHER_ADDR_STR_LEN]; - char chanbuf[CHANSPEC_STR_LEN]; - int mpc = 0; - int ftm_cfg_cnt = 0; - int ftm_param_cnt = 0; - ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS]; - ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS]; - rtt_target_info_t *rtt_target; - rtt_status_info_t *rtt_status; - NULL_CHECK(dhd, "dhd is NULL", err); - - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - - if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) { - err = BCME_RANGE; - DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx)); - goto exit; - } - /* turn off mpc in case of non-associted */ - if (!dhd_is_associated(dhd, NULL, NULL)) { - err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); - if (err) { - DHD_ERROR(("%s : failed to set mpc\n", __FUNCTION__)); - goto exit; - } - rtt_status->mpc = 1; /* Either failure or complete, we need to enable mpc */ - } - - mutex_lock(&rtt_status->rtt_mutex); - /* Get a target information */ - rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; - mutex_unlock(&rtt_status->rtt_mutex); - DHD_RTT(("%s enter\n", __FUNCTION__)); - if (!RTT_IS_ENABLED(rtt_status)) { - /* enable ftm */ - err = dhd_rtt_ftm_enable(dhd, TRUE); - if (err) { - DHD_ERROR(("failed to enable FTM (%d)\n", err)); - goto exit; - } - } - rtt_status->status = RTT_ENABLED; - - /* delete session of index default sesession */ - err = dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION); - if (err < 0 && err != BCME_NOTFOUND) { - DHD_ERROR(("failed to delete session of FTM (%d)\n", err)); - goto exit; - } - memset(ftm_configs, 0, sizeof(ftm_configs)); - memset(ftm_params, 0, sizeof(ftm_params)); - - /* configure the session 1 as initiator */ - ftm_configs[ftm_cfg_cnt].enable = TRUE; - ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_INITIATOR; - dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS, - ftm_configs, ftm_cfg_cnt); - /* target's mac address */ - if (!ETHER_ISNULLADDR(rtt_target->addr.octet)) { - ftm_params[ftm_param_cnt].mac_addr = rtt_target->addr; - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_PEER_MAC; - DHD_RTT((">\t target %s\n", bcm_ether_ntoa(&rtt_target->addr, eabuf))); - } - /* target's chanspec */ - if (rtt_target->chanspec) { - ftm_params[ftm_param_cnt].chanspec = htol32((uint32)rtt_target->chanspec); - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_CHANSPEC; - DHD_RTT((">\t chanspec : %s\n", wf_chspec_ntoa(rtt_target->chanspec, chanbuf))); - } - /* num-burst */ - if (rtt_target->num_burst) { - ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_burst); - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_NUM_BURST; - DHD_RTT((">\t num of burst : %d\n", rtt_target->num_burst)); - } - /* number of frame per burst */ - if (rtt_target->num_frames_per_burst == 0) { - rtt_target->num_frames_per_burst = - CHSPEC_IS20(rtt_target->chanspec) ? FTM_DEFAULT_CNT_20M : - CHSPEC_IS40(rtt_target->chanspec) ? FTM_DEFAULT_CNT_40M : - FTM_DEFAULT_CNT_80M; - } - ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_frames_per_burst); - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_NUM_FTM; - DHD_RTT((">\t number of frame per burst : %d\n", rtt_target->num_frames_per_burst)); - /* FTM retry count */ - if (rtt_target->num_retries_per_ftm) { - ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftm; - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_RETRIES; - DHD_RTT((">\t retry count of FTM : %d\n", rtt_target->num_retries_per_ftm)); - } - /* FTM Request retry count */ - if (rtt_target->num_retries_per_ftmr) { - ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftmr; - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_REQ_RETRIES; - DHD_RTT((">\t retry count of FTM Req : %d\n", rtt_target->num_retries_per_ftm)); - } - /* burst-period */ - if (rtt_target->interval) { - ftm_params[ftm_param_cnt].data_intvl.intvl = htol32(rtt_target->interval); /* ms */ - ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC; - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_PERIOD; - DHD_RTT((">\t burst period : %d ms\n", rtt_target->interval)); - } - /* burst-timeout */ - if (rtt_target->burst_timeout) { - ftm_params[ftm_param_cnt].data_intvl.intvl = - htol32(rtt_target->burst_timeout * FTM_BURST_TIMEOUT_UNIT); - ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MICRO_SEC; - ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_TIMEOUT; - DHD_RTT((">\t burst timeout : %d us\n", - rtt_target->burst_timeout * WL_PROXD_TMU_MICRO_SEC)); - } - dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_GENERAL, - ftm_params, ftm_param_cnt); - - err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE); - if (err) { - DHD_ERROR(("failed to start session of FTM : error %d\n", err)); - } -exit: - if (err) { - rtt_status->status = RTT_STOPPED; - /* disable FTM */ - dhd_rtt_ftm_enable(dhd, FALSE); - if (rtt_status->mpc) { - /* enable mpc again in case of error */ - mpc = 1; - rtt_status->mpc = 0; - err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); - } - } - return err; -} - -int -dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn) -{ - int err = BCME_OK; - struct rtt_noti_callback *cb = NULL, *iter; - rtt_status_info_t *rtt_status; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(noti_fn, "noti_fn is NULL", err); - - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - spin_lock_bh(¬i_list_lock); - list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { - if (iter->noti_fn == noti_fn) { - goto exit; - } - } - cb = kmalloc(sizeof(struct rtt_noti_callback), GFP_ATOMIC); - if (!cb) { - err = -ENOMEM; - goto exit; - } - cb->noti_fn = noti_fn; - cb->ctx = ctx; - list_add(&cb->list, &rtt_status->noti_fn_list); -exit: - spin_unlock_bh(¬i_list_lock); - return err; -} - -int -dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn) -{ - int err = BCME_OK; - struct rtt_noti_callback *cb = NULL, *iter; - rtt_status_info_t *rtt_status; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(noti_fn, "noti_fn is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - spin_lock_bh(¬i_list_lock); - list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { - if (iter->noti_fn == noti_fn) { - cb = iter; - list_del(&cb->list); - break; - } - } - spin_unlock_bh(¬i_list_lock); - if (cb) { - kfree(cb); - } - return err; -} - -static wifi_rate_t -dhd_rtt_convert_rate_to_host(uint32 rspec) -{ - wifi_rate_t host_rate; - uint32 bandwidth; - memset(&host_rate, 0, sizeof(wifi_rate_t)); - if (RSPEC_ISLEGACY(rspec)) { - host_rate.preamble = 0; - } else if (RSPEC_ISHT(rspec)) { - host_rate.preamble = 2; - host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; - } else if (RSPEC_ISVHT(rspec)) { - host_rate.preamble = 3; - host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; - host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; - } - - bandwidth = RSPEC_BW(rspec); - switch (bandwidth) { - case WL_RSPEC_BW_20MHZ: - host_rate.bw = RTT_RATE_20M; - break; - case WL_RSPEC_BW_40MHZ: - host_rate.bw = RTT_RATE_40M; - break; - case WL_RSPEC_BW_80MHZ: - host_rate.bw = RTT_RATE_80M; - break; - case WL_RSPEC_BW_160MHZ: - host_rate.bw = RTT_RATE_160M; - break; - default: - host_rate.bw = RTT_RATE_20M; - break; - } - - host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ - DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); - return host_rate; -} - - -static int -dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len) -{ - int err = BCME_OK; - char eabuf[ETHER_ADDR_STR_LEN]; - wl_proxd_rtt_result_t *p_data_info; - wl_proxd_result_flags_t flags; - wl_proxd_session_state_t session_state; - wl_proxd_status_t proxd_status; - struct timespec ts; - uint32 ratespec; - uint32 avg_dist; - wl_proxd_rtt_sample_t *p_sample; - wl_proxd_intvl_t rtt; - wl_proxd_intvl_t p_time; - - NULL_CHECK(rtt_report, "rtt_report is NULL", err); - NULL_CHECK(p_data, "p_data is NULL", err); - DHD_RTT(("%s enter\n", __FUNCTION__)); - p_data_info = (wl_proxd_rtt_result_t *) p_data; - /* unpack and format 'flags' for display */ - flags = ltoh16_ua(&p_data_info->flags); - - /* session state and status */ - session_state = ltoh16_ua(&p_data_info->state); - proxd_status = ltoh32_ua(&p_data_info->status); - DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n", - bcm_ether_ntoa((&(p_data_info->peer)), eabuf), - session_state, - ftm_session_state_value_to_logstr(session_state), - proxd_status, - ftm_status_value_to_logstr(proxd_status))); - - /* show avg_dist (1/256m units), burst_num */ - avg_dist = ltoh32_ua(&p_data_info->avg_dist); - if (avg_dist == 0xffffffff) { /* report 'failure' case */ - DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n", - ltoh16_ua(&p_data_info->burst_num), - p_data_info->num_valid_rtt)); /* in a session */ - avg_dist = FTM_INVALID; - } - else { - DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n", - avg_dist >> 8, /* 1/256m units */ - ((avg_dist & 0xff) * 625) >> 4, - ltoh16_ua(&p_data_info->burst_num), - p_data_info->num_valid_rtt, - p_data_info->num_ftm)); /* in a session */ - } - /* show 'avg_rtt' sample */ - p_sample = &p_data_info->avg_rtt; - DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d ratespec=0x%08x\n", - (int16) ltoh16_ua(&p_sample->rssi), - ltoh32_ua(&p_sample->rtt.intvl), - ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)), - ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10, - ltoh32_ua(&p_sample->ratespec))); - - /* set peer address */ - rtt_report->addr = p_data_info->peer; - /* burst num */ - rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num); - /* success num */ - rtt_report->success_num = p_data_info->num_valid_rtt; - /* actual number of FTM supported by peer */ - rtt_report->num_per_burst_peer = p_data_info->num_ftm; - /* status */ - rtt_report->status = ftm_get_statusmap_info(proxd_status, - &ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info)); - /* rssi (0.5db) */ - rtt_report->rssi = (int16)ltoh16_ua(&p_data_info->avg_rtt.rssi) * 2; - /* rx rate */ - ratespec = ltoh32_ua(&p_data_info->avg_rtt.ratespec); - rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec); - /* rtt_sd */ - rtt.tmu = ltoh16_ua(&p_data_info->avg_rtt.rtt.tmu); - rtt.intvl = ltoh32_ua(&p_data_info->avg_rtt.rtt.intvl); - rtt_report->rtt = FTM_INTVL2NSEC(&rtt) * 10; /* nano -> 0.1 nano */ - rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */ - DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt)); - DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi)); - - /* average distance */ - if (avg_dist != FTM_INVALID) { - rtt_report->distance = (avg_dist >> 8) * 100; /* meter -> cm */ - rtt_report->distance += (avg_dist & 0xff) * 100 / 256; - } else { - rtt_report->distance = FTM_INVALID; - } - /* time stamp */ - /* get the time elapsed from boot time */ - get_monotonic_boottime(&ts); - rtt_report->ts = (uint64)TIMESPEC_TO_US(ts); - - if (proxd_status == WL_PROXD_E_REMOTE_FAIL) { - /* retry time after failure */ - p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); - p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); - rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */ - DHD_RTT((">\tretry_after: %d%s\n", - ltoh32_ua(&p_data_info->u.retry_after.intvl), - ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu)))); - } else { - /* burst duration */ - p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); - p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); - rtt_report->burst_duration = FTM_INTVL2MSEC(&p_time); /* s -> ms */ - DHD_RTT((">\tburst_duration: %d%s\n", - ltoh32_ua(&p_data_info->u.burst_duration.intvl), - ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu)))); - } - return err; -} - -int -dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) -{ - int ret = BCME_OK; - int tlvs_len; - int idx; - uint16 version; - wl_proxd_event_t *p_event; - wl_proxd_event_type_t event_type; - wl_proxd_ftm_session_status_t session_status; - const ftm_strmap_entry_t *p_loginfo; - rtt_status_info_t *rtt_status; - rtt_target_info_t *rtt_target_info; - struct rtt_noti_callback *iter; - rtt_results_header_t *entry = NULL, *next = NULL, *rtt_results_header = NULL; - rtt_result_t *rtt_result, *next2; - gfp_t kflags; - bool is_new = TRUE; - - DHD_RTT(("Enter %s \n", __FUNCTION__)); - NULL_CHECK(dhd, "dhd is NULL", ret); - -#ifdef WL_CFG80211 - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", ret); - - if (RTT_IS_STOPPED(rtt_status)) { - /* Ignore the Proxd event */ - DHD_RTT((" event handler rtt is stopped \n")); - goto exit; - } -#endif /* WL_CFG80211 */ - if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) { - DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__, - ntoh32_ua((void *)&event->datalen))); - ret = -EINVAL; - goto exit; - } - event_type = ntoh32_ua((void *)&event->event_type); - if (event_type != WLC_E_PROXD) { - DHD_ERROR((" failed event \n")); - ret = -EINVAL; - goto exit; - } - - if (!event_data) { - DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); - ret = -EINVAL; - goto exit; - } - p_event = (wl_proxd_event_t *) event_data; - version = ltoh16(p_event->version); - if (version < WL_PROXD_API_VERSION) { - DHD_ERROR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n", - version, WL_PROXD_API_VERSION)); - goto exit; - } - if (!in_atomic()) { - mutex_lock(&rtt_status->rtt_mutex); - } - event_type = (wl_proxd_event_type_t) ltoh16(p_event->type); - - kflags = in_softirq()? GFP_ATOMIC : GFP_KERNEL; - - DHD_RTT(("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x\n", - p_event->type, ntoh16(p_event->type), ltoh16(p_event->type))); - p_loginfo = ftm_get_event_type_loginfo(event_type); - if (p_loginfo == NULL) { - DHD_ERROR(("receive an invalid FTM event %d\n", event_type)); - ret = -EINVAL; - goto exit; /* ignore this event */ - } - /* get TLVs len, skip over event header */ - if (ltoh16(p_event->len) < OFFSETOF(wl_proxd_event_t, tlvs)) { - DHD_ERROR(("invalid FTM event length:%d\n", ltoh16(p_event->len))); - ret = -EINVAL; - goto exit; - } - tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs); - DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n", - p_loginfo->text, - version, - ltoh16(p_event->len), - ltoh16(p_event->method), - ltoh16(p_event->sid), - tlvs_len)); - rtt_target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; - /* find a rtt_report_header for this mac address */ - list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) { - if (!memcmp(&entry->peer_mac, &event->addr, ETHER_ADDR_LEN)) { - /* found a rtt_report_header for peer_mac in the list */ - is_new = FALSE; - rtt_results_header = entry; - break; - } - } - - switch (event_type) { - case WL_PROXD_EVENT_SESSION_CREATE: - DHD_RTT(("WL_PROXD_EVENT_SESSION_CREATE\n")); - break; - case WL_PROXD_EVENT_SESSION_START: - DHD_RTT(("WL_PROXD_EVENT_SESSION_START\n")); - break; - case WL_PROXD_EVENT_BURST_START: - DHD_RTT(("WL_PROXD_EVENT_BURST_START\n")); - break; - case WL_PROXD_EVENT_BURST_END: - DHD_RTT(("WL_PROXD_EVENT_BURST_END\n")); - if (is_new) { - /* allocate new header for rtt_results */ - rtt_results_header = kzalloc(sizeof(rtt_results_header_t), GFP_KERNEL); - if (!rtt_results_header) { - if (!in_atomic()) { - mutex_unlock(&rtt_status->rtt_mutex); - } - ret = -ENOMEM; - goto exit; - } - /* Initialize the head of list for rtt result */ - INIT_LIST_HEAD(&rtt_results_header->result_list); - rtt_results_header->peer_mac = event->addr; - list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache); - } - if (tlvs_len > 0) { - /* allocate rtt_results for new results */ - rtt_result = kzalloc(sizeof(rtt_result_t), kflags); - if (!rtt_result) { - if (!in_atomic()) { - mutex_unlock(&rtt_status->rtt_mutex); - } - ret = -ENOMEM; - goto exit; - } - /* unpack TLVs and invokes the cbfn to print the event content TLVs */ - ret = bcm_unpack_xtlv_buf((void *) &(rtt_result->report), - (uint8 *)&p_event->tlvs[0], tlvs_len, - BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); - if (ret != BCME_OK) { - DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", - __FUNCTION__)); - goto exit; - } - /* fill out the results from the configuration param */ - rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst; - rtt_result->report.type = RTT_TWO_WAY; - DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num)); - rtt_result->report_len = RTT_REPORT_SIZE; - - list_add_tail(&rtt_result->list, &rtt_results_header->result_list); - rtt_results_header->result_cnt++; - rtt_results_header->result_tot_len += rtt_result->report_len; - } - break; - case WL_PROXD_EVENT_SESSION_END: - DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n")); - if (tlvs_len > 0) { - /* unpack TLVs and invokes the cbfn to print the event content TLVs */ - ret = bcm_unpack_xtlv_buf((void *) &session_status, - (uint8 *)&p_event->tlvs[0], tlvs_len, - BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); - if (ret != BCME_OK) { - DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", - __FUNCTION__)); - goto exit; - } - } - /* find next target to trigger RTT */ - for (idx = (rtt_status->cur_idx + 1); - idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { - /* skip the disabled device */ - if (rtt_status->rtt_config.target_info[idx].disable) { - continue; - } else { - /* set the idx to cur_idx */ - rtt_status->cur_idx = idx; - break; - } - } - if (idx < rtt_status->rtt_config.rtt_target_cnt) { - /* restart to measure RTT from next device */ - schedule_work(&rtt_status->work); - } else { - DHD_RTT(("RTT_STOPPED\n")); - rtt_status->status = RTT_STOPPED; - /* to turn on mpc mode */ - schedule_work(&rtt_status->work); - /* notify the completed information to others */ - list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { - iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache); - } - /* remove the rtt results in cache */ - if (!list_empty(&rtt_status->rtt_results_cache)) { - /* Iterate rtt_results_header list */ - list_for_each_entry_safe(entry, next, - &rtt_status->rtt_results_cache, list) { - list_del(&entry->list); - /* Iterate rtt_result list */ - list_for_each_entry_safe(rtt_result, next2, - &entry->result_list, list) { - list_del(&rtt_result->list); - kfree(rtt_result); - } - kfree(entry); - } - } - - /* reinitialize the HEAD */ - INIT_LIST_HEAD(&rtt_status->rtt_results_cache); - /* clear information for rtt_config */ - rtt_status->rtt_config.rtt_target_cnt = 0; - memset(rtt_status->rtt_config.target_info, 0, - TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); - rtt_status->cur_idx = 0; - } - break; - case WL_PROXD_EVENT_SESSION_RESTART: - DHD_RTT(("WL_PROXD_EVENT_SESSION_RESTART\n")); - break; - case WL_PROXD_EVENT_BURST_RESCHED: - DHD_RTT(("WL_PROXD_EVENT_BURST_RESCHED\n")); - break; - case WL_PROXD_EVENT_SESSION_DESTROY: - DHD_RTT(("WL_PROXD_EVENT_SESSION_DESTROY\n")); - break; - case WL_PROXD_EVENT_FTM_FRAME: - DHD_RTT(("WL_PROXD_EVENT_FTM_FRAME\n")); - break; - case WL_PROXD_EVENT_DELAY: - DHD_RTT(("WL_PROXD_EVENT_DELAY\n")); - break; - case WL_PROXD_EVENT_VS_INITIATOR_RPT: - DHD_RTT(("WL_PROXD_EVENT_VS_INITIATOR_RPT\n ")); - break; - case WL_PROXD_EVENT_RANGING: - DHD_RTT(("WL_PROXD_EVENT_RANGING\n")); - break; - - default: - DHD_ERROR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type)); - break; - } - if (!in_atomic()) { - mutex_unlock(&rtt_status->rtt_mutex); - } -exit: - return ret; -} - -static void -dhd_rtt_work(struct work_struct *work) -{ - rtt_status_info_t *rtt_status; - dhd_pub_t *dhd; - rtt_status = container_of(work, rtt_status_info_t, work); - if (rtt_status == NULL) { - DHD_ERROR(("%s : rtt_status is NULL\n", __FUNCTION__)); - return; - } - dhd = rtt_status->dhd; - if (dhd == NULL) { - DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); - return; - } - (void) dhd_rtt_start(dhd); -} - -int -dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa) -{ - rtt_status_info_t *rtt_status; - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - NULL_CHECK(capa, "capa is NULL", err); - bzero(capa, sizeof(rtt_capabilities_t)); - switch (rtt_status->rtt_capa.proto) { - case RTT_CAP_ONE_WAY: - capa->rtt_one_sided_supported = 1; - break; - case RTT_CAP_FTM_WAY: - capa->rtt_ftm_supported = 1; - break; - } - - switch (rtt_status->rtt_capa.feature) { - case RTT_FEATURE_LCI: - capa->lci_support = 1; - break; - case RTT_FEATURE_LCR: - capa->lcr_support = 1; - break; - case RTT_FEATURE_PREAMBLE: - capa->preamble_support = 1; - break; - case RTT_FEATURE_BW: - capa->bw_support = 1; - break; - } - /* bit mask */ - capa->preamble_support = rtt_status->rtt_capa.preamble; - capa->bw_support = rtt_status->rtt_capa.bw; - - return err; -} - -int -dhd_rtt_init(dhd_pub_t *dhd) -{ - int err = BCME_OK, ret; - int32 up = 1; - int32 version; - rtt_status_info_t *rtt_status; - NULL_CHECK(dhd, "dhd is NULL", err); - if (dhd->rtt_state) { - return err; - } - dhd->rtt_state = kzalloc(sizeof(rtt_status_info_t), GFP_KERNEL); - if (dhd->rtt_state == NULL) { - err = BCME_NOMEM; - DHD_ERROR(("%s : failed to create rtt_state\n", __FUNCTION__)); - return err; - } - bzero(dhd->rtt_state, sizeof(rtt_status_info_t)); - rtt_status = GET_RTTSTATE(dhd); - rtt_status->rtt_config.target_info = - kzalloc(TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT), GFP_KERNEL); - if (rtt_status->rtt_config.target_info == NULL) { - DHD_ERROR(("%s failed to allocate the target info for %d\n", - __FUNCTION__, RTT_MAX_TARGET_CNT)); - err = BCME_NOMEM; - goto exit; - } - rtt_status->dhd = dhd; - /* need to do WLC_UP */ - dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(int32), TRUE, 0); - - ret = dhd_rtt_get_version(dhd, &version); - if (ret == BCME_OK && (version == WL_PROXD_API_VERSION)) { - DHD_ERROR(("%s : FTM is supported\n", __FUNCTION__)); - /* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */ - rtt_status->rtt_capa.proto |= RTT_CAP_FTM_WAY; - - /* indicate to set tx rate */ - rtt_status->rtt_capa.feature |= RTT_FEATURE_PREAMBLE; - rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_VHT; - rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_HT; - - /* indicate to set bandwith */ - rtt_status->rtt_capa.feature |= RTT_FEATURE_BW; - rtt_status->rtt_capa.bw |= RTT_BW_20; - rtt_status->rtt_capa.bw |= RTT_BW_40; - rtt_status->rtt_capa.bw |= RTT_BW_80; - } else { - if ((ret != BCME_OK) || (version == 0)) { - DHD_ERROR(("%s : FTM is not supported\n", __FUNCTION__)); - } else { - DHD_ERROR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n", - __FUNCTION__, WL_PROXD_API_VERSION, version)); - } - } - mutex_init(&rtt_status->rtt_mutex); - INIT_LIST_HEAD(&rtt_status->noti_fn_list); - INIT_LIST_HEAD(&rtt_status->rtt_results_cache); - INIT_WORK(&rtt_status->work, dhd_rtt_work); -exit: - if (err < 0) { - kfree(rtt_status->rtt_config.target_info); - kfree(dhd->rtt_state); - } - return err; -} - -int -dhd_rtt_deinit(dhd_pub_t *dhd) -{ - int err = BCME_OK; - rtt_status_info_t *rtt_status; - rtt_results_header_t *rtt_header, *next; - rtt_result_t *rtt_result, *next2; - struct rtt_noti_callback *iter, *iter2; - NULL_CHECK(dhd, "dhd is NULL", err); - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - rtt_status->status = RTT_STOPPED; - /* clear evt callback list */ - if (!list_empty(&rtt_status->noti_fn_list)) { - list_for_each_entry_safe(iter, iter2, &rtt_status->noti_fn_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - /* remove the rtt results */ - if (!list_empty(&rtt_status->rtt_results_cache)) { - list_for_each_entry_safe(rtt_header, next, &rtt_status->rtt_results_cache, list) { - list_del(&rtt_header->list); - list_for_each_entry_safe(rtt_result, next2, - &rtt_header->result_list, list) { - list_del(&rtt_result->list); - kfree(rtt_result); - } - kfree(rtt_header); - } - } - kfree(rtt_status->rtt_config.target_info); - kfree(dhd->rtt_state); - dhd->rtt_state = NULL; - return err; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h deleted file mode 100755 index 08216dbc8d08..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Header file of Broadcom Dongle Host Driver (DHD) - * Copyright (C) 1999-2014, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_rtt.h 423669 2014-07-01 13:01:56Z $ - */ -#ifndef __DHD_RTT_H__ -#define __DHD_RTT_H__ - -#include "dngl_stats.h" - -#define RTT_MAX_TARGET_CNT 50 -#define RTT_MAX_FRAME_CNT 25 -#define RTT_MAX_RETRY_CNT 10 -#define DEFAULT_FTM_CNT 6 -#define DEFAULT_RETRY_CNT 6 -#define TARGET_INFO_SIZE(count) (sizeof(rtt_target_info_t) * count) - -#define TARGET_TYPE(target) (target->type) - -#ifndef BIT -#define BIT(x) (1 << (x)) -#endif - -/* DSSS, CCK and 802.11n rates in [500kbps] units */ -#define WL_MAXRATE 108 /* in 500kbps units */ -#define WL_RATE_1M 2 /* in 500kbps units */ -#define WL_RATE_2M 4 /* in 500kbps units */ -#define WL_RATE_5M5 11 /* in 500kbps units */ -#define WL_RATE_11M 22 /* in 500kbps units */ -#define WL_RATE_6M 12 /* in 500kbps units */ -#define WL_RATE_9M 18 /* in 500kbps units */ -#define WL_RATE_12M 24 /* in 500kbps units */ -#define WL_RATE_18M 36 /* in 500kbps units */ -#define WL_RATE_24M 48 /* in 500kbps units */ -#define WL_RATE_36M 72 /* in 500kbps units */ -#define WL_RATE_48M 96 /* in 500kbps units */ -#define WL_RATE_54M 108 /* in 500kbps units */ - - -enum rtt_role { - RTT_INITIATOR = 0, - RTT_TARGET = 1 -}; -enum rtt_status { - RTT_STOPPED = 0, - RTT_STARTED = 1, - RTT_ENABLED = 2 -}; -typedef int64_t wifi_timestamp; /* In microseconds (us) */ -typedef int64_t wifi_timespan; -typedef int32 wifi_rssi; - -typedef enum { - RTT_INVALID, - RTT_ONE_WAY, - RTT_TWO_WAY, - RTT_AUTO -} rtt_type_t; - -typedef enum { - RTT_PEER_STA, - RTT_PEER_AP, - RTT_PEER_P2P, - RTT_PEER_NAN, - RTT_PEER_INVALID -} rtt_peer_type_t; - -typedef enum rtt_reason { - RTT_REASON_SUCCESS, - RTT_REASON_FAILURE, - RTT_REASON_FAIL_NO_RSP, - RTT_REASON_FAIL_INVALID_TS, /* Invalid timestamp */ - RTT_REASON_FAIL_PROTOCOL, /* 11mc protocol failed */ - RTT_REASON_FAIL_REJECTED, - RTT_REASON_FAIL_NOT_SCHEDULED_YET, - RTT_REASON_FAIL_SCHEDULE, /* schedule failed */ - RTT_REASON_FAIL_TM_TIMEOUT, - RTT_REASON_FAIL_AP_ON_DIFF_CHANNEL, - RTT_REASON_FAIL_NO_CAPABILITY, - RTT_REASON_FAIL_BUSY_TRY_LATER, - RTT_REASON_ABORTED -} rtt_reason_t; - -enum { - RTT_CAP_ONE_WAY = BIT(0), - /* IEEE802.11mc */ - RTT_CAP_FTM_WAY = BIT(1) -}; - -enum { - RTT_FEATURE_LCI = BIT(0), - RTT_FEATURE_LCR = BIT(1), - RTT_FEATURE_PREAMBLE = BIT(2), - RTT_FEATURE_BW = BIT(3) -}; - -enum { - RTT_PREAMBLE_LEGACY = BIT(0), - RTT_PREAMBLE_HT = BIT(1), - RTT_PREAMBLE_VHT = BIT(2) -}; - - -enum { - RTT_BW_5 = BIT(0), - RTT_BW_10 = BIT(1), - RTT_BW_20 = BIT(2), - RTT_BW_40 = BIT(3), - RTT_BW_80 = BIT(4), - RTT_BW_160 = BIT(5) -}; - -enum rtt_rate_bw { - RTT_RATE_20M, - RTT_RATE_40M, - RTT_RATE_80M, - RTT_RATE_160M -}; - -#define FTM_MAX_NUM_BURST_EXP 14 -#define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) -#define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) -#define HAS_RTT_CAP(cap) (HAS_ONEWAY_CAP(cap) || HAS_11MC_CAP(cap)) - -typedef struct wifi_channel_info { - wifi_channel_width_t width; - wifi_channel center_freq; /* primary 20 MHz channel */ - wifi_channel center_freq0; /* center freq (MHz) first segment */ - wifi_channel center_freq1; /* center freq (MHz) second segment valid for 80 + 80 */ -} wifi_channel_info_t; - -typedef struct wifi_rate { - uint32 preamble :3; /* 0: OFDM, 1: CCK, 2 : HT, 3: VHT, 4..7 reserved */ - uint32 nss :2; /* 1 : 1x1, 2: 2x2, 3: 3x3, 4: 4x4 */ - uint32 bw :3; /* 0: 20Mhz, 1: 40Mhz, 2: 80Mhz, 3: 160Mhz */ - /* OFDM/CCK rate code would be as per IEEE std in the unit of 0.5 mb - * HT/VHT it would be mcs index - */ - uint32 rateMcsIdx :8; - uint32 reserved :16; /* reserved */ - uint32 bitrate; /* unit of 100 Kbps */ -} wifi_rate_t; - -typedef struct rtt_target_info { - struct ether_addr addr; - rtt_type_t type; /* rtt_type */ - rtt_peer_type_t peer; /* peer type */ - wifi_channel_info_t channel; /* channel information */ - chanspec_t chanspec; /* chanspec for channel */ - bool disable; /* disable for RTT measurement */ - uint32 interval; /* interval of RTT measurement (unit ms) when continuous = true */ - uint16 num_burst; /* total number of RTT bursts when multi_burst = 1 */ - uint32 num_frames_per_burst; - /* num of frames in each RTT burst - * for single side, measurement result num = frame number - * for 2 side RTT, measurement result num = frame number - 1 - */ - uint32 num_retries_per_ftm; /* retry time for RTT measurment frame */ - /* following fields are only valid for 2 side RTT */ - uint32 num_retries_per_ftmr; - uint8 LCI_request; - uint8 LCR_request; - uint32 burst_timeout; - uint8 preamble; /* 0 - Legacy, 1 - HT, 2 - VHT */ - uint8 bw; /* 5, 10, 20, 40, 80, 160 */ -} rtt_target_info_t; - - -typedef struct rtt_report { - struct ether_addr addr; - unsigned int burst_num; /* # of burst inside a multi-burst request */ - unsigned int ftm_num; /* total RTT measurement frames */ - unsigned int success_num; /* total successful RTT measurement frames */ - uint8 num_per_burst_peer; /* max number of FTM number per burst the peer support */ - rtt_reason_t status; /* raging status */ - /* in s, 11mc only, only for RTT_REASON_FAIL_BUSY_TRY_LATER, 1- 31s */ - uint8 retry_after_duration; - rtt_type_t type; /* rtt type */ - wifi_rssi rssi; /* average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB */ - wifi_rssi rssi_spread; /* rssi spread in 0.5 db steps e.g. 5 implies 2.5 spread */ - wifi_rate_t tx_rate; /* tx rate */ - wifi_rate_t rx_rate; /* rx rate */ - wifi_timespan rtt; /* round trip time in 0.1 nanoseconds */ - wifi_timespan rtt_sd; /* rtt standard deviation in 0.1 nanoseconds */ - wifi_timespan rtt_spread; /* difference between max and min rtt times recorded */ - int distance; /* distance in cm (optional) */ - int distance_sd; /* standard deviation in cm (optional) */ - int distance_spread; /* difference between max and min distance recorded (optional) */ - wifi_timestamp ts; /* time of the measurement (in microseconds since boot) */ - int burst_duration; /* in ms, how long the FW time is to fininish one burst measurement */ - bcm_tlv_t *LCI; /* LCI Report */ - bcm_tlv_t *LCR; /* Location Civic Report */ -} rtt_report_t; -#define RTT_REPORT_SIZE (sizeof(rtt_report_t)) - -/* rtt_results_header to maintain rtt result list per mac address */ -typedef struct rtt_results_header { - struct ether_addr peer_mac; - uint32 result_cnt; - uint32 result_tot_len; /* sum of report_len of rtt_result */ - struct list_head list; - struct list_head result_list; -} rtt_results_header_t; - -/* rtt_result to link all of rtt_report */ -typedef struct rtt_result { - struct list_head list; - struct rtt_report report; - int32 report_len; /* total length of rtt_report */ -} rtt_result_t; - -/* RTT Capabilities */ -typedef struct rtt_capabilities { - uint8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */ - uint8 rtt_ftm_supported; /* if ftm rtt data collection is supported */ - uint8 lci_support; /* location configuration information */ - uint8 lcr_support; /* Civic Location */ - uint8 preamble_support; /* bit mask indicate what preamble is supported */ - uint8 bw_support; /* bit mask indicate what BW is supported */ -} rtt_capabilities_t; - -typedef struct rtt_config_params { - int8 rtt_target_cnt; - rtt_target_info_t *target_info; -} rtt_config_params_t; - -typedef void (*dhd_rtt_compl_noti_fn)(void *ctx, void *rtt_data); -/* Linux wrapper to call common dhd_rtt_set_cfg */ -int -dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf); - -int -dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt); - -int -dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, - dhd_rtt_compl_noti_fn noti_fn); - -int -dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn); - -int -dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa); - -/* export to upper layer */ -chanspec_t -dhd_rtt_convert_to_chspec(wifi_channel_info_t channel); - -int -dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params); - -int -dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt); - - -int -dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn); - -int -dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn); - -int -dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); - -int -dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa); - -int -dhd_rtt_init(dhd_pub_t *dhd); - -int -dhd_rtt_deinit(dhd_pub_t *dhd); -#endif /* __DHD_RTT_H__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c deleted file mode 100755 index f04512680089..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c +++ /dev/null @@ -1,8334 +0,0 @@ -/* - * DHD Bus Module for SDIO - * - * Copyright (C) 1999-2018, Broadcom Corporation - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_sdio.c 701450 2017-05-25 02:10:23Z $ - */ - -#include -#include -#include - -#ifdef BCMEMBEDIMAGE -#include BCMEMBEDIMAGE -#endif /* BCMEMBEDIMAGE */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#if defined(DHD_DEBUG) -#include -#include -#endif /* defined(DHD_DEBUG) */ -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef PROP_TXSTATUS -#include -#endif - -#ifdef DHDTCPACK_SUPPRESS -#include -#endif - -#include - -bool dhd_mp_halting(dhd_pub_t *dhdp); -extern void bcmsdh_waitfor_iodrain(void *sdh); -extern void bcmsdh_reject_ioreqs(void *sdh, bool reject); -extern bool bcmsdh_fatal_error(void *sdh); - -#ifndef DHDSDIO_MEM_DUMP_FNAME -#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" -#endif - -#define QLEN (1024) /* bulk rx and tx queue lengths */ -#define FCHI (QLEN - 10) -#define FCLOW (FCHI / 2) -#define PRIOMASK 7 - -#define TXRETRIES 2 /* # of retries for tx frames */ -#define READ_FRM_CNT_RETRIES 3 -#ifndef DHD_RXBOUND -#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ -#endif - -#ifndef DHD_TXBOUND -#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ -#endif - -#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ - -#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ -#define MAX_NVRAMBUF_SIZE (6 * 1024) /* max nvram buf size */ -#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */ - -#ifndef DHD_FIRSTREAD -#define DHD_FIRSTREAD 32 -#endif -#if !ISPOWEROF2(DHD_FIRSTREAD) -#error DHD_FIRSTREAD is not a power of 2! -#endif - -/* Total length of frame header for dongle protocol */ -#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) -#define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN) -#define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE - -#ifdef SDTEST -#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) -#else -#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) -#endif - -/* Space for header read, limit for data packets */ -#ifndef MAX_HDR_READ -#define MAX_HDR_READ 32 -#endif -#if !ISPOWEROF2(MAX_HDR_READ) -#error MAX_HDR_READ is not a power of 2! -#endif - -#define MAX_RX_DATASZ 2048 - -/* Maximum milliseconds to wait for F2 to come up */ -#define DHD_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). - */ -#if (PMU_MAX_TRANSITION_DLY <= 1000000) -#undef PMU_MAX_TRANSITION_DLY -#define PMU_MAX_TRANSITION_DLY 1000000 -#endif - -/* hooks for limiting threshold custom tx num in rx processing */ -#define DEFAULT_TXINRX_THRES 0 -#ifndef CUSTOM_TXINRX_THRES -#define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES -#endif - -/* Value for ChipClockCSR during initial setup */ -#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) -#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) - -/* Flags for SDH calls */ -#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) - -/* Packet free applicable unconditionally for sdio and sdspi. Conditional if - * bufpool was present for gspi bus. - */ -#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ - PKTFREE(bus->dhd->osh, pkt, FALSE); -DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); - - -#ifdef DHD_DEBUG -/* Device console log buffer state */ -#define CONSOLE_LINE_MAX 192 -#define CONSOLE_BUFFER_MAX 2024 -typedef struct dhd_console { - uint count; /* Poll interval msec counter */ - uint log_addr; /* Log struct address (fixed) */ - hndrte_log_t log; /* Log struct (host copy) */ - uint bufsize; /* Size of log buffer */ - uint8 *buf; /* Log buffer (host copy) */ - uint last; /* Last buffer read index */ -} dhd_console_t; -#endif /* DHD_DEBUG */ - -#define REMAP_ENAB(bus) ((bus)->remap) -#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) -#define KSO_ENAB(bus) ((bus)->kso) -#define SR_ENAB(bus) ((bus)->_srenab) -#define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto)) -#define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618) -#define MIN_RSRC_SR 0x3 -#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) -#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) -#define RCTL_MACPHY_DISABLE_MASK (1 << 26) -#define RCTL_LOGIC_DISABLE_MASK (1 << 27) - -#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) -#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ -#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ -#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ -#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) -#define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2) -#define OVERFLOW_BLKSZ512_WM 96 -#define OVERFLOW_BLKSZ512_MES 80 - -#define CC_PMUCC3 (0x3) -#if defined(CUSTOMER_HW5) -#define DHD_DPC_LOG_SZ (256) -#endif /* CUSTOMER_HW5 */ -/* Private data for SDIO bus interaction */ -typedef struct dhd_bus { - dhd_pub_t *dhd; - - bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ - si_t *sih; /* Handle for SI calls */ - char *vars; /* Variables (from CIS and/or other) */ - uint varsz; /* Size of variables buffer */ - uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ - - sdpcmd_regs_t *regs; /* Registers for SDIO core */ - uint sdpcmrev; /* SDIO core revision */ - uint armrev; /* CPU core revision */ - uint ramrev; /* SOCRAM core revision */ - uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ - uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ - uint32 srmemsize; /* Size of SRMEM */ - - uint32 bus; /* gSPI or SDIO bus */ - uint32 bus_num; /* bus number */ - uint32 slot_num; /* slot ID */ - uint32 hostintmask; /* Copy of Host Interrupt Mask */ - uint32 intstatus; /* Intstatus bits (events) pending */ - bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ - bool fcstate; /* State of dongle flow-control */ - - uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ - char *fw_path; /* module_param: path to firmware image */ - char *nv_path; /* module_param: path to nvram vars file */ - const char *nvram_params; /* user specified nvram params. */ - - uint blocksize; /* Block size of SDIO transfers */ - uint roundup; /* Max roundup limit */ - - struct pktq txq; /* Queue length used for flow-control */ - uint8 flowcontrol; /* per prio flow control bitmask */ - uint8 tx_seq; /* Transmit sequence number (next) */ - uint8 tx_max; /* Maximum transmit sequence allowed */ - - uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; - uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ - uint16 nextlen; /* Next Read Len from last header */ - uint8 rx_seq; /* Receive sequence number (expected) */ - bool rxskip; /* Skip receive (awaiting NAK ACK) */ - - void *glomd; /* Packet containing glomming descriptor */ - void *glom; /* Packet chain for glommed superframe */ - uint glomerr; /* Glom packet read errors */ - - uint8 *rxbuf; /* Buffer for receiving control packets */ - uint rxblen; /* Allocated length of rxbuf */ - uint8 *rxctl; /* Aligned pointer into rxbuf */ - uint8 *databuf; /* Buffer for receiving big glom packet */ - uint8 *dataptr; /* Aligned pointer into databuf */ - uint rxlen; /* Length of valid data in buffer */ - - uint8 sdpcm_ver; /* Bus protocol reported by dongle */ - - bool intr; /* Use interrupts */ - bool poll; /* Use polling */ - bool ipend; /* Device interrupt is pending */ - bool intdis; /* Interrupts disabled by isr */ - 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 DHD_DEBUG - dhd_console_t console; /* Console output polling support */ - uint console_addr; /* Console address from shared struct */ -#endif /* DHD_DEBUG */ - - uint regfails; /* Count of R_REG/W_REG failures */ - - uint clkstate; /* State of sd and backplane clock(s) */ - bool activity; /* Activity flag for clock down */ - int32 idletime; /* Control for activity timeout */ - int32 idlecount; /* Activity timeout counter */ - int32 idleclock; /* How to set bus driver when idle */ - int32 sd_divisor; /* Speed control to bus driver */ - int32 sd_mode; /* Mode control to bus driver */ - int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ - bool use_rxchain; /* If dhd should use PKT chains */ - bool sleeping; /* Is SDIO bus sleeping? */ -#if defined(SUPPORT_P2P_GO_PS) - wait_queue_head_t bus_sleep; -#endif /* LINUX && SUPPORT_P2P_GO_PS */ - uint rxflow_mode; /* Rx flow control mode */ - bool rxflow; /* Is rx flow control on */ - uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ - 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; - int32 txinrx_thres; /* num of in-queued pkts */ - int32 dotxinrx; /* tx first in dhdsdio_readframes */ -#ifdef SDTEST - /* external loopback */ - bool ext_loop; - uint8 loopid; - - /* pktgen configuration */ - uint pktgen_freq; /* Ticks between bursts */ - uint pktgen_count; /* Packets to send each burst */ - uint pktgen_print; /* Bursts between count displays */ - uint pktgen_total; /* Stop after this many */ - uint pktgen_minlen; /* Minimum packet data len */ - uint pktgen_maxlen; /* Maximum packet data len */ - uint pktgen_mode; /* Configured mode: tx, rx, or echo */ - uint pktgen_stop; /* Number of tx failures causing stop */ - - /* active pktgen fields */ - uint pktgen_tick; /* Tick counter for bursts */ - uint pktgen_ptick; /* Burst counter for printing */ - uint pktgen_sent; /* Number of test packets generated */ - uint pktgen_rcvd; /* Number of test packets received */ - uint pktgen_prev_time; /* Time at which previous stats where printed */ - uint pktgen_prev_sent; /* Number of test packets generated when - * previous stats were printed - */ - uint pktgen_prev_rcvd; /* Number of test packets received when - * previous stats were printed - */ - uint pktgen_fail; /* Number of failed send attempts */ - uint16 pktgen_len; /* Length of next packet to send */ -#define PKTGEN_RCV_IDLE (0) -#define PKTGEN_RCV_ONGOING (1) - uint16 pktgen_rcv_state; /* receive state */ - uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ -#endif /* SDTEST */ - - /* 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 */ -#ifdef DHDENABLE_TAILPAD - uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */ - uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */ -#endif - uint8 *ctrl_frame_buf; - uint32 ctrl_frame_len; - bool ctrl_frame_stat; - uint32 rxint_mode; /* rx interrupt mode */ - bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram - * Available with socram rev 16 - * Remap region not DMA-able - */ - bool kso; - bool _slpauto; - bool _oobwakeup; - bool _srenab; - bool readframes; - bool reqbussleep; - uint32 resetinstr; - uint32 dongle_ram_base; - - void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */ - uint32 txglom_cnt; /* Number of pkts in the glom array */ - uint32 txglom_total_len; /* Total length of pkts in glom array */ - bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled */ - uint32 txglomsize; /* Glom size limitation */ - void *pad_pkt; -#if defined(CUSTOMER_HW5) - char dpc_log_previous[DHD_DPC_LOG_SZ]; - char dpc_log_current[DHD_DPC_LOG_SZ]; - int dpc_log_loops; -#endif /* CUSTOMER_HW5 */ -} dhd_bus_t; - -/* clkstate */ -#define CLK_NONE 0 -#define CLK_SDONLY 1 -#define CLK_PENDING 2 /* Not used yet */ -#define CLK_AVAIL 3 - -#define DHD_NOPMU(dhd) (FALSE) - -#ifdef DHD_DEBUG -static int qcount[NUMPRIO]; -static int tx_packets[NUMPRIO]; -#endif /* DHD_DEBUG */ - -/* Deferred transmit */ -const uint dhd_deferred_tx = 1; - -extern uint dhd_watchdog_ms; - -extern void dhd_os_wd_timer(void *bus, uint wdtick); - -/* Tx/Rx bounds */ -uint dhd_txbound; -uint dhd_rxbound; -uint dhd_txminmax = DHD_TXMINMAX; - -/* override the RAM size if possible */ -#define DONGLE_MIN_RAMSIZE (128 *1024) -int dhd_dongle_ramsize; - -uint dhd_doflow = TRUE; -uint dhd_dpcpoll = FALSE; - -module_param(dhd_doflow, uint, 0644); -module_param(dhd_dpcpoll, uint, 0644); - -static bool dhd_alignctl; - -static bool sd1idle; - -static bool retrydata; -#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) - -static uint watermark = 8; -static uint mesbusyctrl = 0; -static const uint firstread = DHD_FIRSTREAD; - -/* Retry count for register access failures */ -static const uint retry_limit = 2; - -/* Force even SD lengths (some host controllers mess up on odd bytes) */ -static bool forcealign; - -#define ALIGNMENT 4 - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) -extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); -#endif - -#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) -#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD -#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ -#define PKTALIGN(osh, p, len, align) \ - do { \ - uintptr datalign; \ - datalign = (uintptr)PKTDATA((osh), (p)); \ - datalign = ROUNDUP(datalign, (align)) - datalign; \ - ASSERT(datalign < (align)); \ - ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ - if (datalign) \ - PKTPULL((osh), (p), (uint)datalign); \ - PKTSETLEN((osh), (p), (len)); \ - } while (0) - -/* Limit on rounding up frames */ -static const uint max_roundup = 512; - -/* Try doing readahead */ -static bool dhd_readahead; - -/* To check if there's window offered */ -#define DATAOK(bus) \ - (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ - (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) - -/* To check if there's window offered for ctrl frame */ -#define TXCTLOK(bus) \ - (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ - (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) - -/* Number of pkts available in dongle for data RX */ -#define DATABUFCNT(bus) \ - ((uint8)(bus->tx_max - bus->tx_seq) - 1) - -/* Macros to get register read/write status */ -/* NOTE: these assume a local dhdsdio_bus_t *bus! */ -#define R_SDREG(regvar, regaddr, retryvar) \ -do { \ - retryvar = 0; \ - do { \ - regvar = R_REG(bus->dhd->osh, regaddr); \ - } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ - if (retryvar) { \ - bus->regfails += (retryvar-1); \ - if (retryvar > retry_limit) { \ - DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \ - __FUNCTION__, __LINE__)); \ - regvar = 0; \ - } \ - } \ -} while (0) - -#define W_SDREG(regval, regaddr, retryvar) \ -do { \ - retryvar = 0; \ - do { \ - W_REG(bus->dhd->osh, regaddr, regval); \ - } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ - if (retryvar) { \ - bus->regfails += (retryvar-1); \ - if (retryvar > retry_limit) \ - DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \ - __FUNCTION__, __LINE__)); \ - } \ -} while (0) - -#define BUS_WAKE(bus) \ - do { \ - bus->idlecount = 0; \ - if ((bus)->sleeping) \ - dhdsdio_bussleep((bus), FALSE); \ - } while (0); - -/* - * pktavail interrupts from dongle to host can be managed in 3 different ways - * whenever there is a packet available in dongle to transmit to host. - * - * Mode 0: Dongle writes the software host mailbox and host is interrupted. - * Mode 1: (sdiod core rev >= 4) - * Device sets a new bit in the intstatus whenever there is a packet - * available in fifo. Host can't clear this specific status bit until all the - * packets are read from the FIFO. No need to ack dongle intstatus. - * Mode 2: (sdiod core rev >= 4) - * Device sets a bit in the intstatus, and host acks this by writing - * one to this bit. Dongle won't generate anymore packet interrupts - * until host reads all the packets from the dongle and reads a zero to - * figure that there are no more packets. No need to disable host ints. - * Need to ack the intstatus. - */ - -#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ -#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ -#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ - - -#define FRAME_AVAIL_MASK(bus) \ - ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) - -#define DHD_BUS SDIO_BUS - -#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) - -#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) - -#define GSPI_PR55150_BAILOUT - -#ifdef SDTEST -static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); -static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count); -#endif - -#ifdef DHD_DEBUG -static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); -static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); -static int dhdsdio_mem_dump(dhd_bus_t *bus); -#endif /* DHD_DEBUG */ - -static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap); -static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); - -static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); -static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); -static void dhdsdio_disconnect(void *ptr); -static bool dhdsdio_chipmatch(uint16 chipid); -static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, - void * regsva, uint16 devid); -static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); -static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); -static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, - bool reset_flag); - -static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size); -static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); -static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry); -static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt); -static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, - int prev_chain_total_len, bool last_chained_pkt, - int *pad_pkt_len, void **new_pkt); -static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt); - -static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); -static int _dhdsdio_download_firmware(dhd_bus_t *bus); - -static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); -static int dhdsdio_download_nvram(dhd_bus_t *bus); -#ifdef BCMEMBEDIMAGE -static int dhdsdio_download_code_array(dhd_bus_t *bus); -#endif -static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep); -static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok); -static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus); - -#ifdef WLMEDIA_HTSF -#include -extern uint32 dhd_get_htsf(void *dhd, int ifidx); -#endif /* WLMEDIA_HTSF */ - -static void -dhdsdio_tune_fifoparam(struct dhd_bus *bus) -{ - int err; - uint8 devctl, wm, mes; - - if (bus->sih->buscorerev >= 15) { - /* See .ppt in PR for these recommended values */ - if (bus->blocksize == 512) { - wm = OVERFLOW_BLKSZ512_WM; - mes = OVERFLOW_BLKSZ512_MES; - } else { - mes = bus->blocksize/4; - wm = bus->blocksize/4; - } - - watermark = wm; - mesbusyctrl = mes; - } else { - DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n", - bus->sih->buscorerev)); - return; - } - - /* Update watermark */ - if (wm > 0) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err); - - devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl |= SBSDIO_DEVCTL_F2WM_ENAB; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - } - - /* Update MES */ - if (mes > 0) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, - (mes | SBSDIO_MESBUSYCTRL_ENAB), &err); - } - - DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n", - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err), - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err), - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err))); -} - -static void -dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size) -{ - int32 min_size = DONGLE_MIN_RAMSIZE; - /* Restrict the ramsize to user specified limit */ - DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", - dhd_dongle_ramsize, min_size)); - if ((dhd_dongle_ramsize > min_size) && - (dhd_dongle_ramsize < (int32)bus->orig_ramsize)) - bus->ramsize = dhd_dongle_ramsize; -} - -static int -dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) -{ - int err = 0; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, - (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); - if (!err) - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, - (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); - if (!err) - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, - (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); - return err; -} - - -#ifdef USE_OOB_GPIO1 -static int -dhdsdio_oobwakeup_init(dhd_bus_t *bus) -{ - uint32 val, addr, data; - - bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP); - - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - - /* Set device for gpio1 wakeup */ - bcmsdh_reg_write(bus->sdh, addr, 4, 2); - val = bcmsdh_reg_read(bus->sdh, data, 4); - val |= CC_CHIPCTRL2_GPIO1_WAKEUP; - bcmsdh_reg_write(bus->sdh, data, 4, val); - - bus->_oobwakeup = TRUE; - - return 0; -} -#endif /* USE_OOB_GPIO1 */ - -/* - * Query if FW is in SR mode - */ -static bool -dhdsdio_sr_cap(dhd_bus_t *bus) -{ - bool cap = FALSE; - uint32 core_capext, addr, data; - - - if (bus->sih->chip == BCM43430_CHIP_ID) { - /* check if fw initialized sr engine */ - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, sr_control1); - if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0) - cap = TRUE; - - return cap; - } - - if (bus->sih->chip == BCM4324_CHIP_ID) { - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - bcmsdh_reg_write(bus->sdh, addr, 4, 3); - core_capext = bcmsdh_reg_read(bus->sdh, data, 4); - } else if (bus->sih->chip == BCM4330_CHIP_ID) { - core_capext = FALSE; - } else if ((bus->sih->chip == BCM4335_CHIP_ID) || - (bus->sih->chip == BCM4339_CHIP_ID) || - (bus->sih->chip == BCM43349_CHIP_ID) || - (bus->sih->chip == BCM4345_CHIP_ID) || - (bus->sih->chip == BCM43454_CHIP_ID) || - (bus->sih->chip == BCM4354_CHIP_ID) || - (bus->sih->chip == BCM4356_CHIP_ID) || - (bus->sih->chip == BCM4350_CHIP_ID)) { - core_capext = TRUE; - } else { - core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); - core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK); - } - if (!(core_capext)) - return FALSE; - - if (bus->sih->chip == BCM4324_CHIP_ID) { - /* FIX: Should change to query SR control register instead */ - cap = TRUE; - } else if ((bus->sih->chip == BCM4335_CHIP_ID) || - (bus->sih->chip == BCM4339_CHIP_ID) || - (bus->sih->chip == BCM43349_CHIP_ID) || - (bus->sih->chip == BCM4345_CHIP_ID) || - (bus->sih->chip == BCM43454_CHIP_ID) || - (bus->sih->chip == BCM4354_CHIP_ID) || - (bus->sih->chip == BCM4356_CHIP_ID) || - (bus->sih->chip == BCM4350_CHIP_ID)) { - uint32 enabval = 0; - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); - enabval = bcmsdh_reg_read(bus->sdh, data, 4); - - if ((bus->sih->chip == BCM4350_CHIP_ID) || - (bus->sih->chip == BCM4345_CHIP_ID) || - (bus->sih->chip == BCM43454_CHIP_ID) || - (bus->sih->chip == BCM4356_CHIP_ID) || - (bus->sih->chip == BCM4354_CHIP_ID)) - enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE; - - if (enabval) - cap = TRUE; - } else { - data = bcmsdh_reg_read(bus->sdh, - SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4); - if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) - cap = TRUE; - } - - return cap; -} - -static int -dhdsdio_srwar_init(dhd_bus_t *bus) -{ - bcmsdh_gpio_init(bus->sdh); - -#ifdef USE_OOB_GPIO1 - dhdsdio_oobwakeup_init(bus); -#endif - - - return 0; -} - -static int -dhdsdio_sr_init(dhd_bus_t *bus) -{ - uint8 val; - int err = 0; - - if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) - dhdsdio_srwar_init(bus); - - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); - val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, - 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); - - /* Add CMD14 Support */ - dhdsdio_devcap_set(bus, - (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT)); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err); - - bus->_slpauto = dhd_slpauto ? TRUE : FALSE; - - bus->_srenab = TRUE; - - return 0; -} - -/* - * FIX: Be sure KSO bit is enabled - * Currently, it's defaulting to 0 which should be 1. - */ -static int -dhdsdio_clk_kso_init(dhd_bus_t *bus) -{ - uint8 val; - int err = 0; - - /* set flag */ - bus->kso = TRUE; - - /* - * Enable KeepSdioOn (KSO) bit for normal operation - * Default is 0 (4334A0) so set it. Fixed in B0. - */ - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL); - if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { - val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); - if (err) - DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err)); - } - - return 0; -} - -#define KSO_DBG(x) -#define KSO_WAIT_US 50 -#define KSO_WAIT_MS 1 -#define KSO_SLEEP_RETRY_COUNT 20 -#define ERROR_BCME_NODEVICE_MAX 1 - -#if defined(CUSTOMER_HW5) -#define MAX_KSO_ATTEMPTS 64 -#else -#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) -#endif -static int -dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) -{ - uint8 wr_val = 0, rd_val, cmp_val, bmask; - int err = 0; - int try_cnt = 0; - - KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); - - wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); - - if (on) { - cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; - bmask = cmp_val; - - OSL_SLEEP(3); - } else { - /* Put device to sleep, turn off KSO */ - cmp_val = 0; - bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; - } - - do { - rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); - if (((rd_val & bmask) == cmp_val) && !err) - break; - - KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); - - if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) { - OSL_SLEEP(KSO_WAIT_MS); - } else - OSL_DELAY(KSO_WAIT_US); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); - } while (try_cnt++ < MAX_KSO_ATTEMPTS); - - - if (try_cnt > 2) - KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", - __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); - - if (try_cnt > MAX_KSO_ATTEMPTS) { - DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", - __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); - } - return err; -} - -static int -dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) -{ - int err = 0; - - if (on == FALSE) { - - BUS_WAKE(bus); - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__, - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err))); - dhdsdio_clk_kso_enab(bus, FALSE); - } else { - DHD_ERROR(("%s: KSO enable\n", __FUNCTION__)); - - /* Make sure we have SD bus access */ - if (bus->clkstate == CLK_NONE) { - DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__)); - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - - dhdsdio_clk_kso_enab(bus, TRUE); - - DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__, - dhdsdio_sleepcsr_get(bus))); - } - - bus->kso = on; - BCM_REFERENCE(err); - - return 0; -} - -static uint8 -dhdsdio_sleepcsr_get(dhd_bus_t *bus) -{ - int err = 0; - uint8 val = 0; - - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); - if (err) - DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err)); - - return val; -} - -uint8 -dhdsdio_devcap_get(dhd_bus_t *bus) -{ - return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL); -} - -static int -dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap) -{ - int err = 0; - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err); - if (err) - DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err)); - - return 0; -} - -static int -dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) -{ - int err = 0, retry; - uint8 val; - - retry = 0; - if (on == TRUE) { - /* Enter Sleep */ - - /* Be sure we request clk before going to sleep - * so we can wake-up with clk request already set - * else device can go back to sleep immediately - */ - if (!SLPAUTO_ENAB(bus)) - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - else { - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if ((val & SBSDIO_CSR_MASK) == 0) { - DHD_ERROR(("%s: No clock before enter sleep:0x%x\n", - __FUNCTION__, val)); - - /* Reset clock request */ - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_ALP_AVAIL_REQ, &err); - DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__, - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err))); - } - } - - DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__, - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err))); -#ifdef USE_CMD14 - err = bcmsdh_sleep(bus->sdh, TRUE); -#else - err = dhdsdio_clk_kso_enab(bus, FALSE); - if (OOB_WAKEUP_ENAB(bus)) - { - err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ - } -#endif /* USE_CMD14 */ - } else { - /* Exit Sleep */ - /* Make sure we have SD bus access */ - if (bus->clkstate == CLK_NONE) { - DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__)); - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - - if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { - SPINWAIT_SLEEP(sdioh_spinwait_sleep, - (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), - GPIO_DEV_SRSTATE_TIMEOUT); - - if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { - DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n")); - } - } -#ifdef USE_CMD14 - err = bcmsdh_sleep(bus->sdh, FALSE); - if (SLPAUTO_ENAB(bus) && (err != 0)) { - OSL_DELAY(10000); - DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__)); - - /* Toggle sleep to resync with host and device */ - err = bcmsdh_sleep(bus->sdh, TRUE); - OSL_DELAY(10000); - err = bcmsdh_sleep(bus->sdh, FALSE); - - if (err) { - OSL_DELAY(10000); - DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__)); - - /* Toggle sleep to resync with host and device */ - err = bcmsdh_sleep(bus->sdh, TRUE); - OSL_DELAY(10000); - err = bcmsdh_sleep(bus->sdh, FALSE); - if (err) { - DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__)); - DHD_ERROR(("%s: FATAL: Device non-response!\n", - __FUNCTION__)); - err = 0; - } - } - } -#else - if (OOB_WAKEUP_ENAB(bus)) - { - err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ - } - do { - err = dhdsdio_clk_kso_enab(bus, TRUE); - if (err) - OSL_SLEEP(10); - } while ((err != 0) && (++retry < 3)); - - if (err != 0) { - DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry)); - err = 0; /* continue anyway */ - } -#endif /* !USE_CMD14 */ - - if (err == 0) { - uint8 csr; - - /* Wait for device ready during transition to wake-up */ - SPINWAIT_SLEEP(sdioh_spinwait_sleep, - (((csr = dhdsdio_sleepcsr_get(bus)) & - SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != - (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); - - DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr)); - - if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) { - DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n", - __FUNCTION__, csr)); - err = BCME_NODEVICE; - } - - SPINWAIT_SLEEP(sdioh_spinwait_sleep, - (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != - (SBSDIO_HT_AVAIL)), (10000)); - - DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr)); - if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) { - DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n", - __FUNCTION__, csr)); - err = BCME_NODEVICE; - } - } - } - - /* Update if successful */ - if (err == 0) - bus->kso = on ? FALSE : TRUE; - else { - DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n", - __FUNCTION__, bus->kso, on, err)); - if (!on && retry > 2) - bus->kso = FALSE; - } - - return err; -} - -/* Turn backplane clock on or off */ -static int -dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) -{ -#define HT_AVAIL_ERROR_MAX 10 - static int ht_avail_error = 0; - int err; - uint8 clkctl, clkreq, devctl; - bcmsdh_info_t *sdh; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - clkctl = 0; - sdh = bus->sdh; - - - if (!KSO_ENAB(bus)) - return BCME_OK; - - if (SLPAUTO_ENAB(bus)) { - bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); - return BCME_OK; - } - - if (on) { - /* Request HT Avail */ - clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; - - - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); - if (err) { - ht_avail_error++; - if (ht_avail_error < HT_AVAIL_ERROR_MAX) { - DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - else if (ht_avail_error == HT_AVAIL_ERROR_MAX) { -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - "%s ht_avail_error = %d\n", __func__, ht_avail_error); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - dhd_os_send_hang_message(bus->dhd); - } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ - return BCME_ERROR; - } else { - ht_avail_error = 0; - } - - - /* Check current status */ - clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (err) { - DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err)); - return BCME_ERROR; - } - -#if !defined(OOB_INTR_ONLY) - /* Go to pending and await interrupt if appropriate */ - if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { - /* Allow only clock-available interrupt */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - if (err) { - DHD_ERROR(("%s: Devctl access error setting CA: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - - devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - DHD_INFO(("CLKCTL: set PENDING\n")); - bus->clkstate = CLK_PENDING; - return BCME_OK; - } else -#endif /* !defined (OOB_INTR_ONLY) */ - { - if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - } - } - - /* Otherwise, wait here (polling) for HT Avail */ - if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - SPINWAIT_SLEEP(sdioh_spinwait_sleep, - ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err)), - !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); - } - if (err) { - DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); - return BCME_ERROR; - } - if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n", - __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl)); - return BCME_ERROR; - } - - /* Mark clock available */ - bus->clkstate = CLK_AVAIL; - DHD_INFO(("CLKCTL: turned ON\n")); - -#if defined(DHD_DEBUG) - if (bus->alp_only == TRUE) { -#if !defined(BCMLXSDMMC) - if (!SBSDIO_ALPONLY(clkctl)) { - DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__)); - } -#endif /* !defined(BCMLXSDMMC) */ - } else { - if (SBSDIO_ALPONLY(clkctl)) { - DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__)); - } - } -#endif /* defined (DHD_DEBUG) */ - - bus->activity = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - } else { - clkreq = 0; - - if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - } - - bus->clkstate = CLK_SDONLY; - if (!SR_ENAB(bus)) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); - DHD_INFO(("CLKCTL: turned OFF\n")); - if (err) { - DHD_ERROR(("%s: Failed access turning clock off: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - } - return BCME_OK; -} - -/* Change idle/active SD state */ -static int -dhdsdio_sdclk(dhd_bus_t *bus, bool on) -{ - int err; - int32 iovalue; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (on) { - if (bus->idleclock == DHD_IDLE_STOP) { - /* Turn on clock and restore mode */ - iovalue = 1; - err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error enabling sd_clock: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - - iovalue = bus->sd_mode; - err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error changing sd_mode: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } else if (bus->idleclock != DHD_IDLE_ACTIVE) { - /* Restore clock speed */ - iovalue = bus->sd_divisor; - err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error restoring sd_divisor: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - bus->clkstate = CLK_SDONLY; - } else { - /* Stop or slow the SD clock itself */ - if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { - DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n", - __FUNCTION__, bus->sd_divisor, bus->sd_mode)); - return BCME_ERROR; - } - if (bus->idleclock == DHD_IDLE_STOP) { - if (sd1idle) { - /* Change to SD1 mode and turn off clock */ - iovalue = 1; - err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error changing sd_clock: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - - iovalue = 0; - err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error disabling sd_clock: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } else if (bus->idleclock != DHD_IDLE_ACTIVE) { - /* Set divisor to idle value */ - iovalue = bus->idleclock; - err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error changing sd_divisor: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - bus->clkstate = CLK_NONE; - } - - return BCME_OK; -} - -/* Transition SD and backplane clock readiness */ -static int -dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) -{ - int ret = BCME_OK; -#ifdef DHD_DEBUG - uint oldstate = bus->clkstate; -#endif /* DHD_DEBUG */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Early exit if we're already there */ - if (bus->clkstate == target) { - if (target == CLK_AVAIL) { - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - bus->activity = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - } - return ret; - } - - switch (target) { - case CLK_AVAIL: - /* Make sure SD clock is available */ - if (bus->clkstate == CLK_NONE) - dhdsdio_sdclk(bus, TRUE); - /* Now request HT Avail on the backplane */ - ret = dhdsdio_htclk(bus, TRUE, pendok); - if (ret == BCME_OK) { - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - bus->activity = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - } - break; - - case CLK_SDONLY: - /* Remove HT request, or bring up SD clock */ - if (bus->clkstate == CLK_NONE) - ret = dhdsdio_sdclk(bus, TRUE); - else if (bus->clkstate == CLK_AVAIL) - ret = dhdsdio_htclk(bus, FALSE, FALSE); - else - DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", - bus->clkstate, target)); - if (ret == BCME_OK) { - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - } - break; - - case CLK_NONE: - /* Make sure to remove HT request */ - if (bus->clkstate == CLK_AVAIL) - ret = dhdsdio_htclk(bus, FALSE, FALSE); - /* Now remove the SD clock */ - ret = dhdsdio_sdclk(bus, FALSE); -#ifdef DHD_DEBUG - if (dhd_console_ms == 0) -#endif /* DHD_DEBUG */ - if (bus->poll == 0) - dhd_os_wd_timer(bus->dhd, 0); - break; - } -#ifdef DHD_DEBUG - DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); -#endif /* DHD_DEBUG */ - - return ret; -} - -static int -dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) -{ - int err = 0; - bcmsdh_info_t *sdh = bus->sdh; - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - - DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", - (sleep ? "SLEEP" : "WAKE"), - (bus->sleeping ? "SLEEP" : "WAKE"))); - - if (bus->dhd->hang_was_sent) - return BCME_ERROR; - - /* Done if we're already in the requested state */ - if (sleep == bus->sleeping) - return BCME_OK; - - /* Going to sleep: set the alarm and turn off the lights... */ - if (sleep) { - /* Don't sleep if something is pending */ -#if defined(CUSTOMER_HW5) - if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes || - bus->ctrl_frame_stat) -#else - if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) -#endif - return BCME_BUSY; - - - if (!SLPAUTO_ENAB(bus)) { - /* Disable SDIO interrupts (no longer interested) */ - bcmsdh_intr_disable(bus->sdh); - - /* Make sure the controller has the bus up */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Tell device to start using OOB wakeup */ - W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); - - /* Turn off our contribution to the HT clock request */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); - - /* Isolate the bus */ - if (bus->sih->chip != BCM4329_CHIP_ID && - bus->sih->chip != BCM4319_CHIP_ID) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, - SBSDIO_DEVCTL_PADS_ISO, NULL); - } - } else { - /* Leave interrupts enabled since device can exit sleep and - * interrupt host - */ - err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */); - } - - /* Change state */ - bus->sleeping = TRUE; -#if defined(SUPPORT_P2P_GO_PS) - wake_up(&bus->bus_sleep); -#endif /* LINUX && SUPPORT_P2P_GO_PS */ - } else { - /* Waking up: bus power up is ok, set local state */ - - if (!SLPAUTO_ENAB(bus)) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err); - - /* Force pad isolation off if possible (in case power never toggled) */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); - - - /* Make sure the controller has the bus up */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Send misc interrupt to indicate OOB not needed */ - W_SDREG(0, ®s->tosbmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); - - /* Make sure we have SD bus access */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - /* Enable interrupts again */ - if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { - bus->intdis = FALSE; - bcmsdh_intr_enable(bus->sdh); - } - } else { - err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */); - } - - if (err == 0) { - /* Change state */ - bus->sleeping = FALSE; - } - } - - return err; -} - - -#if defined(OOB_INTR_ONLY) -void -dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) -{ -#if defined(HW_OOB) - bcmsdh_enable_hw_oob_intr(bus->sdh, enable); -#else - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (enable == TRUE) { - - /* Tell device to start using OOB wakeup */ - W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); - - } else { - /* Send misc interrupt to indicate OOB not needed */ - W_SDREG(0, ®s->tosbmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - } - - /* Turn off our contribution to the HT clock request */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -#endif /* !defined(HW_OOB) */ -} -#endif - -int -dhd_bus_txdata(struct dhd_bus *bus, void *pkt) -{ - int ret = BCME_ERROR; - osl_t *osh; - uint datalen, prec; -#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP) - uint8 *dump_data; - uint16 protocol; -#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - osh = bus->dhd->osh; - datalen = PKTLEN(osh, pkt); - -#ifdef SDTEST - /* Push the test header if doing loopback */ - if (bus->ext_loop) { - uint8* data; - PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); - data = PKTDATA(osh, pkt); - *data++ = SDPCM_TEST_ECHOREQ; - *data++ = (uint8)bus->loopid++; - *data++ = (datalen >> 0); - *data++ = (datalen >> 8); - datalen += SDPCM_TEST_HDRLEN; - } -#else /* SDTEST */ - BCM_REFERENCE(datalen); -#endif /* SDTEST */ - -#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP) - dump_data = PKTDATA(osh, pkt); - dump_data += 4; /* skip 4 bytes header */ - protocol = (dump_data[12] << 8) | dump_data[13]; - - if (protocol == ETHER_TYPE_802_1X) { - DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n", - dump_data[14], dump_data[15], dump_data[30])); - } -#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */ - -#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP) - { - int i; - DHD_ERROR(("TX DUMP\n")); - - for (i = 0; i < (datalen - 4); i++) { - DHD_ERROR(("%02X ", dump_data[i])); - if ((i & 15) == 15) - printk("\n"); - } - DHD_ERROR(("\n")); - } -#endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */ - - prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); - - /* Check for existing queue, current flow-control, pending event, or pending clock */ - if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || - (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || - (bus->clkstate != CLK_AVAIL)) { - bool deq_ret; - int pkq_len; - - DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq))); - bus->fcqueued++; - - /* Priority based enq */ - dhd_os_sdlock_txq(bus->dhd); - deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec); - dhd_os_sdunlock_txq(bus->dhd); - - if (!deq_ret) { -#ifdef PROP_TXSTATUS - if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0) -#endif /* PROP_TXSTATUS */ - { -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - dhd_txcomplete(bus->dhd, pkt, FALSE); - PKTFREE(osh, pkt, TRUE); - } - ret = BCME_NORESOURCE; - } else - ret = BCME_OK; - - dhd_os_sdlock_txq(bus->dhd); - pkq_len = pktq_len(&bus->txq); - dhd_os_sdunlock_txq(bus->dhd); - if (pkq_len >= FCHI) { - bool wlfc_enabled = FALSE; -#ifdef PROP_TXSTATUS - wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) != - WLFC_UNSUPPORTED); -#endif - if (!wlfc_enabled && dhd_doflow) { - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); - } - } - -#ifdef DHD_DEBUG - dhd_os_sdlock_txq(bus->dhd); - if (pktq_plen(&bus->txq, prec) > qcount[prec]) - qcount[prec] = pktq_plen(&bus->txq, prec); - dhd_os_sdunlock_txq(bus->dhd); -#endif - - /* Schedule DPC if needed to send queued packet(s) */ - if (dhd_deferred_tx && !bus->dpc_sched) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - } else { - int chan = SDPCM_DATA_CHANNEL; - -#ifdef SDTEST - chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL); -#endif - /* Lock: we're about to use shared data/code (and SDIO) */ - dhd_os_sdlock(bus->dhd); - - /* Otherwise, send it now */ - BUS_WAKE(bus); - /* Make sure back plane ht clk is on, no pending allowed */ - dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); - - ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE); - - if (ret != BCME_OK) - bus->dhd->tx_errors++; - else - bus->dhd->dstats.tx_bytes += datalen; - - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - } - - return ret; -} - -/* align packet data pointer and packet length to n-byte boundary, process packet headers, - * a new packet may be allocated if there is not enough head and/or tail from for padding. - * the caller is responsible for updating the glom size in the head packet (when glom is - * used) - * - * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter - * is taken in tx glom mode only - * - * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment - * padding, NULL if not needed, the caller is responsible for freeing the new packet - * - * return: positive value - length of the packet, including head and tail padding - * negative value - errors - */ -static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, - int prev_chain_total_len, bool last_chained_pkt, - int *pad_pkt_len, void **new_pkt) -{ - osl_t *osh; - uint8 *frame; - int pkt_len; - int modulo; - int head_padding; - int tail_padding = 0; - uint32 swheader; - uint32 swhdr_offset; - bool alloc_new_pkt = FALSE; - uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; - - *new_pkt = NULL; - osh = bus->dhd->osh; - -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - - /* Add space for the SDPCM hardware/software headers */ - PKTPUSH(osh, pkt, sdpcm_hdrlen); - ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); - - frame = (uint8*)PKTDATA(osh, pkt); - pkt_len = (uint16)PKTLEN(osh, pkt); - -#ifdef WLMEDIA_HTSF - frame = (uint8*)PKTDATA(osh, pkt); - if (PKTLEN(osh, pkt) >= 100) { - htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12); - if (htsf_ts->magic == HTSFMAGIC) { - htsf_ts->c20 = get_cycles(); - htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); - } - } -#endif /* WLMEDIA_HTSF */ -#ifdef DHD_DEBUG - if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) - tx_packets[PKTPRIO(pkt)]++; -#endif /* DHD_DEBUG */ - - /* align the data pointer, allocate a new packet if there is not enough space (new - * packet data pointer will be aligned thus no padding will be needed) - */ - head_padding = (ulong)frame % DHD_SDALIGN; - if (PKTHEADROOM(osh, pkt) < head_padding) { - head_padding = 0; - alloc_new_pkt = TRUE; - } else { - uint cur_chain_total_len; - int chain_tail_padding = 0; - - /* All packets need to be aligned by DHD_SDALIGN */ - modulo = (pkt_len + head_padding) % DHD_SDALIGN; - tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; - - /* Total pkt chain length needs to be aligned by block size, - * unless it is a single pkt chain with total length less than one block size, - * which we prefer sending by byte mode. - * - * Do the chain alignment here if - * 1. This is the last pkt of the chain of multiple pkts or a single pkt. - * 2-1. This chain is of multiple pkts, or - * 2-2. This is a single pkt whose size is longer than one block size. - */ - cur_chain_total_len = prev_chain_total_len + - (head_padding + pkt_len + tail_padding); - if (last_chained_pkt && bus->blocksize != 0 && - (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { - modulo = cur_chain_total_len % bus->blocksize; - chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; - } - -#ifdef DHDENABLE_TAILPAD - if (PKTTAILROOM(osh, pkt) < tail_padding) { - /* We don't have tail room to align by DHD_SDALIGN */ - alloc_new_pkt = TRUE; - bus->tx_tailpad_pktget++; - } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) { - /* We have tail room for tail_padding of this pkt itself, but not for - * total pkt chain alignment by block size. - * Use the padding packet to avoid memory copy if applicable, - * otherwise, just allocate a new pkt. - */ - if (bus->pad_pkt) { - *pad_pkt_len = chain_tail_padding; - bus->tx_tailpad_chain++; - } else { - alloc_new_pkt = TRUE; - bus->tx_tailpad_pktget++; - } - } else - /* This last pkt's tailroom is sufficient to hold both tail_padding - * of the pkt itself and chain_tail_padding of total pkt chain - */ -#endif /* DHDENABLE_TAILPAD */ - tail_padding += chain_tail_padding; - } - - DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n", - __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len)); - - if (alloc_new_pkt) { - void *tmp_pkt; - int newpkt_size; - int cur_total_len; - - ASSERT(*pad_pkt_len == 0); - - DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__)); - - /* head pointer is aligned now, no padding needed */ - head_padding = 0; - - /* update the tail padding as it depends on the head padding, since a new packet is - * allocated, the head padding is non longer needed and packet length is chagned - */ - - cur_total_len = prev_chain_total_len + pkt_len; - if (last_chained_pkt && bus->blocksize != 0 && - (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { - modulo = cur_total_len % bus->blocksize; - tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; - } - else { - modulo = pkt_len % DHD_SDALIGN; - tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; - } - - newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN; - bus->dhd->tx_realloc++; - tmp_pkt = PKTGET(osh, newpkt_size, TRUE); - if (tmp_pkt == NULL) { - DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size)); - return BCME_NOMEM; - } - PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN); - bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt)); - *new_pkt = tmp_pkt; - pkt = tmp_pkt; - } - - if (head_padding) - PKTPUSH(osh, pkt, head_padding); - - frame = (uint8*)PKTDATA(osh, pkt); - bzero(frame, head_padding + sdpcm_hdrlen); - pkt_len = (uint16)PKTLEN(osh, pkt); - - /* the header has the followming format - * 4-byte HW frame tag: length, ~length (for glom this is the total length) - * - * 8-byte HW extesion flags (glom mode only) as the following: - * 2-byte packet length, excluding HW tag and padding - * 2-byte frame channel and frame flags (e.g. next frame following) - * 2-byte header length - * 2-byte tail padding size - * - * 8-byte SW frame tags as the following - * 4-byte flags: host tx seq, channel, data offset - * 4-byte flags: TBD - */ - - swhdr_offset = SDPCM_FRAMETAG_LEN; - - /* hardware frame tag: - * - * in tx-glom mode, dongle only checks the hardware frame tag in the first - * packet and sees it as the total lenght of the glom (including tail padding), - * for each packet in the glom, the packet length needs to be updated, (see - * below PKTSETLEN) - * - * in non tx-glom mode, PKTLEN still need to include tail padding as to be - * referred to in sdioh_request_buffer(). The tail length will be excluded in - * dhdsdio_txpkt_postprocess(). - */ - *(uint16*)frame = (uint16)htol16(pkt_len); - *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len); - pkt_len += tail_padding; - - /* hardware extesion flags */ - if (bus->txglom_enable) { - uint32 hwheader1; - uint32 hwheader2; - - swhdr_offset += SDPCM_HWEXT_LEN; - hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) | - (last_chained_pkt << 24); - hwheader2 = (tail_padding) << 16; - htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); - htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); - } - PKTSETLEN((osh), (pkt), (pkt_len)); - - /* software frame tags */ - swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) - | (txseq % SDPCM_SEQUENCE_WRAP) | - (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); - htol32_ua_store(swheader, frame + swhdr_offset); - htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader)); - - return pkt_len; -} - -static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt) -{ - osl_t *osh; - uint8 *frame; - int data_offset; - int tail_padding; - int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0); - - (void)osh; - osh = bus->dhd->osh; - - /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */ - frame = (uint8*)PKTDATA(osh, pkt); - - DHD_INFO(("%s PKTLEN before postprocess %d", - __FUNCTION__, PKTLEN(osh, pkt))); - - /* PKTLEN still includes tail_padding, so exclude it. - * We shall have head_padding + original pkt_len for PKTLEN afterwards. - */ - if (bus->txglom_enable) { - /* txglom pkts have tail_padding length in HW ext header */ - tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16; - PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding); - DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n", - tail_padding, PKTLEN(osh, pkt))); - } else { - /* non-txglom pkts have head_padding + original pkt length in HW frame tag. - * We cannot refer to this field for txglom pkts as the first pkt of the chain will - * have the field for the total length of the chain. - */ - PKTSETLEN(osh, pkt, *(uint16*)frame); - DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n", - *(uint16*)frame, PKTLEN(osh, pkt))); - } - - data_offset = ltoh32_ua(frame + swhdr_offset); - data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; - /* Get rid of sdpcm header + head_padding */ - PKTPULL(osh, pkt, data_offset); - - DHD_INFO(("%s data_offset %d, PKTLEN %d\n", - __FUNCTION__, data_offset, PKTLEN(osh, pkt))); - - return BCME_OK; -} - -static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt) -{ - int i; - int ret = 0; - osl_t *osh; - bcmsdh_info_t *sdh; - void *pkt = NULL; - void *pkt_chain; - int total_len = 0; - void *head_pkt = NULL; - void *prev_pkt = NULL; - int pad_pkt_len = 0; - int new_pkt_num = 0; - void *new_pkts[MAX_TX_PKTCHAIN_CNT]; - bool wlfc_enabled = FALSE; - - if (bus->dhd->dongle_reset) - return BCME_NOTREADY; - - sdh = bus->sdh; - osh = bus->dhd->osh; - /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */ - new_pkts[0] = NULL; - - for (i = 0; i < num_pkt; i++) { - int pkt_len; - bool last_pkt; - void *new_pkt = NULL; - - pkt = pkts[i]; - ASSERT(pkt); - last_pkt = (i == num_pkt - 1); - pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i, - total_len, last_pkt, &pad_pkt_len, &new_pkt); - if (pkt_len <= 0) - goto done; - if (new_pkt) { - pkt = new_pkt; - new_pkts[new_pkt_num++] = new_pkt; - } - total_len += pkt_len; - - PKTSETNEXT(osh, pkt, NULL); - /* insert the packet into the list */ - head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt); - prev_pkt = pkt; - - } - - /* Update the HW frame tag (total length) in the first pkt of the glom */ - if (bus->txglom_enable) { - uint8 *frame; - - total_len += pad_pkt_len; - frame = (uint8*)PKTDATA(osh, head_pkt); - *(uint16*)frame = (uint16)htol16(total_len); - *(((uint16*)frame) + 1) = (uint16)htol16(~total_len); - - } - - /* if a padding packet if needed, insert it to the end of the link list */ - if (pad_pkt_len) { - PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len); - PKTSETNEXT(osh, pkt, bus->pad_pkt); - } - - /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet - * parameter is not NULL, for non packet chian we pass NULL pkt pointer - * so it will take the aligned length and buffer pointer. - */ - pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL; - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES); - if (ret == BCME_OK) - bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP; - - /* if a padding packet was needed, remove it from the link list as it not a data pkt */ - if (pad_pkt_len && pkt) - PKTSETNEXT(osh, pkt, NULL); - -done: - pkt = head_pkt; - while (pkt) { - void *pkt_next = PKTNEXT(osh, pkt); - PKTSETNEXT(osh, pkt, NULL); - dhdsdio_txpkt_postprocess(bus, pkt); - pkt = pkt_next; - } - - /* new packets might be allocated due to insufficient room for padding, but we - * still have to indicate the original packets to upper layer - */ - for (i = 0; i < num_pkt; i++) { - pkt = pkts[i]; - wlfc_enabled = FALSE; -#ifdef PROP_TXSTATUS - if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) { - wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) != - WLFC_UNSUPPORTED); - } -#endif /* PROP_TXSTATUS */ - if (!wlfc_enabled) { - PKTSETNEXT(osh, pkt, NULL); - dhd_txcomplete(bus->dhd, pkt, ret != 0); - if (free_pkt) - PKTFREE(osh, pkt, TRUE); - } - } - - for (i = 0; i < new_pkt_num; i++) - PKTFREE(osh, new_pkts[i], TRUE); - - return ret; -} - -static uint -dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) -{ - uint cnt = 0; - uint8 tx_prec_map; - uint16 txpktqlen = 0; - uint32 intstatus = 0; - uint retries = 0; - osl_t *osh; - uint datalen = 0; - dhd_pub_t *dhd = bus->dhd; - sdpcmd_regs_t *regs = bus->regs; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return BCME_NODEVICE; - } - - osh = dhd->osh; - tx_prec_map = ~bus->flowcontrol; -#ifdef DHD_LOSSLESS_ROAMING - tx_prec_map &= dhd->dequeue_prec_map; -#endif /* DHD_LOSSLESS_ROAMING */ - for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) { - int i; - int num_pkt = 1; - void *pkts[MAX_TX_PKTCHAIN_CNT]; - int prec_out; - - dhd_os_sdlock_txq(bus->dhd); - if (bus->txglom_enable) { - num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize); - num_pkt = MIN(num_pkt, ARRAYSIZE(pkts)); - } - num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map)); - for (i = 0; i < num_pkt; i++) { - pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); - datalen += PKTLEN(osh, pkts[i]); - } - dhd_os_sdunlock_txq(bus->dhd); - - if (i == 0) - break; - if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK) - dhd->tx_errors++; - else - dhd->dstats.tx_bytes += datalen; - cnt += i; - - /* In poll mode, need to check for other events */ - if (!bus->intr && cnt) - { - /* Check device status, signal pending interrupt */ - R_SDREG(intstatus, ®s->intstatus, retries); - bus->f2txdata++; - if (bcmsdh_regfail(bus->sdh)) - break; - if (intstatus & bus->hostintmask) - bus->ipend = TRUE; - } - - } - - dhd_os_sdlock_txq(bus->dhd); - txpktqlen = pktq_len(&bus->txq); - dhd_os_sdunlock_txq(bus->dhd); - - /* Do flow-control if needed */ - if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) { - bool wlfc_enabled = FALSE; -#ifdef PROP_TXSTATUS - wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED); -#endif - if (!wlfc_enabled && dhd_doflow && dhd->txoff) { - dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); - } - } - - return cnt; -} - -static void -dhdsdio_sendpendctl(dhd_bus_t *bus) -{ - bcmsdh_info_t *sdh = bus->sdh; - int ret; - uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; - - if (bus->txglom_enable) - frame_seq += SDPCM_HWEXT_LEN; - - if (*frame_seq != bus->tx_seq) { - DHD_INFO(("%s IOCTL frame seq lag detected!" - " frm_seq:%d != bus->tx_seq:%d, corrected\n", - __FUNCTION__, *frame_seq, bus->tx_seq)); - *frame_seq = bus->tx_seq; - } - - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, - NULL, NULL, NULL, 1); - if (ret == BCME_OK) - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - - bus->ctrl_frame_stat = FALSE; - dhd_wait_event_wakeup(bus->dhd); -} - -int -dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) -{ - static int err_nodevice = 0; - uint8 *frame; - uint16 len; - uint32 swheader; - bcmsdh_info_t *sdh = bus->sdh; - uint8 doff = 0; - int ret = -1; - uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) - return -EIO; - - /* 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) */ - if (dhd_alignctl) { - if ((doff = ((uintptr)frame % DHD_SDALIGN))) { - frame -= doff; - len += doff; - msglen += doff; - bzero(frame, doff + sdpcm_hdrlen); - } - ASSERT(doff < DHD_SDALIGN); - } - doff += sdpcm_hdrlen; - - /* Round send length to next SDIO block */ - if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - uint16 pad = bus->blocksize - (len % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize)) - len += pad; - } else if (len % DHD_SDALIGN) { - len += DHD_SDALIGN - (len % DHD_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (forcealign && (len & (ALIGNMENT - 1))) - len = ROUNDUP(len, ALIGNMENT); - - ASSERT(ISALIGNED((uintptr)frame, 2)); - - - /* Need to lock here to protect txseq and SDIO tx calls */ - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - /* Make sure backplane clock is on */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ - *(uint16*)frame = htol16((uint16)msglen); - *(((uint16*)frame) + 1) = htol16(~msglen); - - if (bus->txglom_enable) { - uint32 hwheader1, hwheader2; - /* 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); - htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); - htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN - + SDPCM_HWEXT_LEN + sizeof(swheader)); - - hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24); - hwheader2 = (len - (msglen)) << 16; - htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); - htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); - - *(uint16*)frame = htol16(len); - *(((uint16*)frame) + 1) = htol16(~(len)); - } else { - /* 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); - htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); - htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - } - if (!TXCTLOK(bus)) { - DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", - __FUNCTION__, bus->tx_max, bus->tx_seq)); - bus->ctrl_frame_stat = TRUE; - /* Send from dpc */ - bus->ctrl_frame_buf = frame; - bus->ctrl_frame_len = len; - - if (!bus->dpc_sched) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - if (bus->ctrl_frame_stat) { - dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); - } - - if (bus->ctrl_frame_stat == FALSE) { - DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); - ret = 0; - } else { - bus->dhd->txcnt_timeout++; - if (!bus->dhd->hang_was_sent) { - DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", - __FUNCTION__, bus->dhd->txcnt_timeout)); - } - ret = -1; - bus->ctrl_frame_stat = FALSE; - goto done; - } - } - - bus->dhd->txcnt_timeout = 0; - bus->ctrl_frame_stat = TRUE; - - if (ret == -1) { -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_CTL_ON()) { - prhex("Tx Frame", frame, len); - } else if (DHD_HDRS_ON()) { - prhex("TxHdr", frame, MIN(len, 16)); - } -#endif - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - frame, len, NULL, NULL, NULL, TXRETRIES); - if (ret == BCME_OK) - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - } - bus->ctrl_frame_stat = FALSE; - -done: - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - - if (ret) - bus->dhd->tx_ctlerrs++; - else - bus->dhd->tx_ctlpkts++; - - if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) - return -ETIMEDOUT; - - if (ret == BCME_NODEVICE) - err_nodevice++; - else - err_nodevice = 0; - - return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0; -} - -int -dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) -{ - int timeleft; - uint rxlen = 0; - bool pending; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) - return -EIO; - - /* Wait until control frame is available */ - timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); - - dhd_os_sdlock(bus->dhd); - rxlen = bus->rxlen; - bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); - bus->rxlen = 0; - dhd_os_sdunlock(bus->dhd); - - if (rxlen) { - DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", - __FUNCTION__, rxlen, msglen)); - } else if (timeleft == 0) { -#ifdef DHD_DEBUG - uint32 status, retry = 0; - R_SDREG(status, &bus->regs->intstatus, retry); - DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n", - __FUNCTION__, status)); -#else - DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); -#endif /* DHD_DEBUG */ -#ifdef DHD_DEBUG - dhd_os_sdlock(bus->dhd); - dhdsdio_checkdied(bus, NULL, 0); - dhd_os_sdunlock(bus->dhd); -#endif /* DHD_DEBUG */ - } else if (pending == TRUE) { - /* signal pending */ - DHD_ERROR(("%s: signal pending\n", __FUNCTION__)); - return -EINTR; - - } else { - DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); -#ifdef DHD_DEBUG - dhd_os_sdlock(bus->dhd); - dhdsdio_checkdied(bus, NULL, 0); - dhd_os_sdunlock(bus->dhd); -#endif /* DHD_DEBUG */ - } - if (timeleft == 0) { - if (rxlen == 0) - bus->dhd->rxcnt_timeout++; - DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__, - bus->dhd->rxcnt_timeout, rxlen)); - } - else - bus->dhd->rxcnt_timeout = 0; - - if (rxlen) - bus->dhd->rx_ctlpkts++; - else - bus->dhd->rx_ctlerrs++; - - if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) - return -ETIMEDOUT; - - if (bus->dhd->dongle_trap_occured) - return -EREMOTEIO; - - return rxlen ? (int)rxlen : -EIO; -} - -/* IOVar table */ -enum { - IOV_INTR = 1, - IOV_POLLRATE, - IOV_SDREG, - IOV_SBREG, - IOV_SDCIS, - IOV_MEMBYTES, - IOV_RAMSIZE, - IOV_RAMSTART, -#ifdef DHD_DEBUG - IOV_CHECKDIED, - IOV_SERIALCONS, -#endif /* DHD_DEBUG */ - IOV_SET_DOWNLOAD_STATE, - IOV_SOCRAM_STATE, - IOV_FORCEEVEN, - IOV_SDIOD_DRIVE, - IOV_READAHEAD, - IOV_SDRXCHAIN, - IOV_ALIGNCTL, - IOV_SDALIGN, - IOV_DEVRESET, - IOV_CPU, -#if defined(USE_SDIOFIFO_IOVAR) - IOV_WATERMARK, - IOV_MESBUSYCTRL, -#endif /* USE_SDIOFIFO_IOVAR */ -#ifdef SDTEST - IOV_PKTGEN, - IOV_EXTLOOP, -#endif /* SDTEST */ - IOV_SPROM, - IOV_TXBOUND, - IOV_RXBOUND, - IOV_TXMINMAX, - IOV_IDLETIME, - IOV_IDLECLOCK, - IOV_SD1IDLE, - IOV_SLEEP, - IOV_DONGLEISOLATION, - IOV_KSO, - IOV_DEVSLEEP, - IOV_DEVCAP, - IOV_VARS, -#ifdef SOFTAP - IOV_FWPATH, -#endif - IOV_TXGLOMSIZE, - IOV_TXGLOMMODE, - IOV_HANGREPORT, - IOV_TXINRX_THRES -}; - -const bcm_iovar_t dhdsdio_iovars[] = { - {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, - {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 }, - {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 }, - {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, - {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, - {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, - {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, - {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 }, - {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 }, - {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, - {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, - {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, - {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, - {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, - {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 }, - {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, - {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, - {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, -#ifdef DHD_DEBUG - {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, - {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, - {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, - {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, - {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, - {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, -#ifdef DHD_DEBUG - {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, - {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 }, -#endif /* DHD_DEBUG */ -#endif /* DHD_DEBUG */ -#ifdef SDTEST - {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, - {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, -#endif /* SDTEST */ -#if defined(USE_SDIOFIFO_IOVAR) - {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 }, - {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 }, -#endif /* USE_SDIOFIFO_IOVAR */ - {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 }, - {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, - {"kso", IOV_KSO, 0, IOVT_UINT32, 0 }, - {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 }, -#ifdef SOFTAP - {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, -#endif - {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 }, - {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 }, - {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -static void -dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) -{ - uint q1, q2; - - if (!div) { - bcm_bprintf(strbuf, "%s N/A", desc); - } else { - q1 = num / div; - q2 = (100 * (num - (q1 * div))) / div; - bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); - } -} - -void -dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - dhd_bus_t *bus = dhdp->bus; - - bcm_bprintf(strbuf, "Bus SDIO structure:\n"); - bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", - bus->hostintmask, bus->intstatus, bus->sdpcm_ver); - bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n", - bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, - bus->rxlen, bus->rx_seq); - bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n", - bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); - bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n", - bus->pollrate, bus->pollcnt, bus->regfails); - - bcm_bprintf(strbuf, "\nAdditional counters:\n"); -#ifdef DHDENABLE_TAILPAD - bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n", - bus->tx_tailpad_chain, bus->tx_tailpad_pktget); -#endif - bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n", - bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, - bus->rxc_errors); - bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n", - bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); - bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n", - bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); - bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n", - bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); - bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n", - (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, - bus->f2txdata, bus->f1regdata); - { - dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, - (bus->f2rxhdrs + bus->f2rxdata)); - dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); - dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, - (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); - dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); - bcm_bprintf(strbuf, "\n"); - - dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), - bus->dhd->rx_packets); - dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes); - bcm_bprintf(strbuf, "\n"); - - dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata); - dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata); - dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets, - (bus->f2txdata + bus->f1regdata)); - dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount); - bcm_bprintf(strbuf, "\n"); - - dhd_dump_pct(strbuf, "Total: pkts/f2rw", - (bus->dhd->tx_packets + bus->dhd->rx_packets), - (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); - dhd_dump_pct(strbuf, ", pkts/f1sd", - (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata); - dhd_dump_pct(strbuf, ", pkts/sd", - (bus->dhd->tx_packets + bus->dhd->rx_packets), - (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); - dhd_dump_pct(strbuf, ", pkts/int", - (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount); - bcm_bprintf(strbuf, "\n\n"); - } - -#ifdef SDTEST - if (bus->pktgen_count) { - bcm_bprintf(strbuf, "pktgen config and count:\n"); - bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n", - bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, - bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); - bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n", - bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); - } -#endif /* SDTEST */ -#ifdef DHD_DEBUG - bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", - bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); - bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup); -#endif /* DHD_DEBUG */ - bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", - bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); -} - -void -dhd_bus_clearcounts(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; - - bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; - bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; - bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; -#ifdef DHDENABLE_TAILPAD - bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0; -#endif - bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; - bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; - bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; -} - -#ifdef SDTEST -static int -dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg) -{ - dhd_pktgen_t pktgen; - - pktgen.version = DHD_PKTGEN_VERSION; - pktgen.freq = bus->pktgen_freq; - pktgen.count = bus->pktgen_count; - pktgen.print = bus->pktgen_print; - pktgen.total = bus->pktgen_total; - pktgen.minlen = bus->pktgen_minlen; - pktgen.maxlen = bus->pktgen_maxlen; - pktgen.numsent = bus->pktgen_sent; - pktgen.numrcvd = bus->pktgen_rcvd; - pktgen.numfail = bus->pktgen_fail; - pktgen.mode = bus->pktgen_mode; - pktgen.stop = bus->pktgen_stop; - - bcopy(&pktgen, arg, sizeof(pktgen)); - - return 0; -} - -static int -dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) -{ - dhd_pktgen_t pktgen; - uint oldcnt, oldmode; - - bcopy(arg, &pktgen, sizeof(pktgen)); - if (pktgen.version != DHD_PKTGEN_VERSION) - return BCME_BADARG; - - oldcnt = bus->pktgen_count; - oldmode = bus->pktgen_mode; - - bus->pktgen_freq = pktgen.freq; - bus->pktgen_count = pktgen.count; - bus->pktgen_print = pktgen.print; - bus->pktgen_total = pktgen.total; - bus->pktgen_minlen = pktgen.minlen; - bus->pktgen_maxlen = pktgen.maxlen; - bus->pktgen_mode = pktgen.mode; - bus->pktgen_stop = pktgen.stop; - - bus->pktgen_tick = bus->pktgen_ptick = 0; - bus->pktgen_prev_time = jiffies; - bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen); - bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen); - - /* Clear counts for a new pktgen (mode change, or was stopped) */ - if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) { - bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0; - bus->pktgen_prev_rcvd = bus->pktgen_fail = 0; - } - - return 0; -} -#endif /* SDTEST */ - -static void -dhdsdio_devram_remap(dhd_bus_t *bus, bool val) -{ - uint8 enable, protect, remap; - - si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); - remap = val ? TRUE : FALSE; - si_socdevram(bus->sih, TRUE, &enable, &protect, &remap); -} - -static int -dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size) -{ - int bcmerror = 0; - uint32 sdaddr; - uint dsize; - - /* In remap mode, adjust address beyond socram and redirect - * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize - * is not backplane accessible - */ - if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) { - address -= bus->orig_ramsize; - address += SOCDEVRAM_BP_ADDR; - } - - /* 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 */ - if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { - DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); - goto xfer_done; - } - - /* Do the transfer(s) */ - while (size) { - DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n", - __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr, - (address & SBSDIO_SBWINDOW_MASK))); - if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) { - DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__)); - break; - } - - /* Adjust for next transfer (if any) */ - if ((size -= dsize)) { - data += dsize; - address += dsize; - if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { - DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); - break; - } - sdaddr = 0; - dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); - } - - } - -xfer_done: - /* Return the window to backplane enumeration space for core access */ - if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { - DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, - bcmsdh_cur_sbwad(bus->sdh))); - } - - return bcmerror; -} - -#ifdef DHD_DEBUG -static int -dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) -{ - uint32 addr; - int rv, i; - uint32 shaddr = 0; - - if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus)) - bus->srmemsize = 0; - - shaddr = bus->dongle_ram_base + bus->ramsize - 4; - i = 0; - do { - /* Read last word in memory to determine address of sdpcm_shared structure */ - if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) - return rv; - - addr = ltoh32(addr); - - DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); - - /* - * Check if addr is valid. - * NVRAM length at the end of memory should have been overwritten. - */ - if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { - if ((bus->srmemsize > 0) && (i++ == 0)) { - shaddr -= bus->srmemsize; - } else { - DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", - __FUNCTION__, addr)); - return BCME_ERROR; - } - } else - break; - } while (i < 2); - - /* Read hndrte_shared structure */ - if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) - return rv; - - /* Endianness */ - sh->flags = ltoh32(sh->flags); - sh->trap_addr = ltoh32(sh->trap_addr); - sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); - sh->assert_file_addr = ltoh32(sh->assert_file_addr); - sh->assert_line = ltoh32(sh->assert_line); - sh->console_addr = ltoh32(sh->console_addr); - sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); - - if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) - return BCME_OK; - - if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { - DHD_ERROR(("%s: sdpcm_shared version %d in dhd " - "is different than sdpcm_shared version %d in dongle\n", - __FUNCTION__, SDPCM_SHARED_VERSION, - sh->flags & SDPCM_SHARED_VERSION_MASK)); - return BCME_ERROR; - } - - return BCME_OK; -} - -#define CONSOLE_LINE_MAX 192 - -static int -dhdsdio_readconsole(dhd_bus_t *bus) -{ - dhd_console_t *c = &bus->console; - uint8 line[CONSOLE_LINE_MAX], ch; - uint32 n, idx, addr; - int rv; - - /* Don't do anything until FWREADY updates console address */ - if (bus->console_addr == 0) - return 0; - - if (!KSO_ENAB(bus)) - return 0; - - /* Read console log struct */ - addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) - return rv; - - /* Allocate console buffer (one time only) */ - if (c->buf == NULL) { - c->bufsize = ltoh32(c->log.buf_size); - if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) - return BCME_NOMEM; - } - - idx = ltoh32(c->log.idx); - - /* Protect against corrupt value */ - if (idx > c->bufsize) - return BCME_ERROR; - - /* Skip reading the console buffer if the index pointer has not moved */ - if (idx == c->last) - return BCME_OK; - - /* Read the console buffer */ - addr = ltoh32(c->log.buf); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 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; - printf("CONSOLE: %s\n", line); -#ifdef LOG_INTO_TCPDUMP - dhd_sendup_log(bus->dhd, line, n); -#endif /* LOG_INTO_TCPDUMP */ - } - } -break2: - - return BCME_OK; -} - -static int -dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) -{ - int bcmerror = 0; - uint msize = 512; - char *mbuffer = NULL; - char *console_buffer = NULL; - uint maxstrlen = 256; - char *str = NULL; - trap_t tr; - sdpcm_shared_t sdpcm_shared; - struct bcmstrbuf strbuf; - uint32 console_ptr, console_size, console_index; - uint8 line[CONSOLE_LINE_MAX], ch; - uint32 n, i, addr; - int rv; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (DHD_NOCHECKDIED_ON()) - return 0; - - if (data == NULL) { - /* - * Called after a rx ctrl timeout. "data" is NULL. - * allocate memory to trace the trap or assert. - */ - size = msize; - mbuffer = data = MALLOC(bus->dhd->osh, msize); - if (mbuffer == NULL) { - DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); - bcmerror = BCME_NOMEM; - goto done; - } - } - - if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { - DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); - bcmerror = BCME_NOMEM; - goto done; - } - - if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0) - goto done; - - bcm_binit(&strbuf, data, size); - - bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", - sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); - - if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { - /* NOTE: Misspelled assert is intentional - DO NOT FIX. - * (Avoids conflict with real asserts for programmatic parsing of output.) - */ - bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); - } - - if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) { - /* NOTE: Misspelled assert is intentional - DO NOT FIX. - * (Avoids conflict with real asserts for programmatic parsing of output.) - */ - bcm_bprintf(&strbuf, "No trap%s in dongle", - (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) - ?"/assrt" :""); - } else { - if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { - /* Download assert */ - bcm_bprintf(&strbuf, "Dongle assert"); - if (sdpcm_shared.assert_exp_addr != 0) { - str[0] = '\0'; - if ((bcmerror = dhdsdio_membytes(bus, FALSE, - sdpcm_shared.assert_exp_addr, - (uint8 *)str, maxstrlen)) < 0) - goto done; - - str[maxstrlen - 1] = '\0'; - bcm_bprintf(&strbuf, " expr \"%s\"", str); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - " expr \"%s\"", str); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - } - - if (sdpcm_shared.assert_file_addr != 0) { - str[0] = '\0'; - if ((bcmerror = dhdsdio_membytes(bus, FALSE, - sdpcm_shared.assert_file_addr, - (uint8 *)str, maxstrlen)) < 0) - goto done; - - str[maxstrlen - 1] = '\0'; - bcm_bprintf(&strbuf, " file \"%s\"", str); -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - " file \"%s\"", str); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - } - - bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line); - } - - if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { - bus->dhd->dongle_trap_occured = TRUE; - if ((bcmerror = dhdsdio_membytes(bus, FALSE, - sdpcm_shared.trap_addr, - (uint8*)&tr, sizeof(trap_t))) < 0) - goto done; - - bcm_bprintf(&strbuf, - "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," - "lp 0x%x, rpc 0x%x Trap offset 0x%x, " - "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " - "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", - ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), - ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), - ltoh32(sdpcm_shared.trap_addr), - ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), - ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); - -#ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(bus->dhd->crash_reason, - "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," - "lp 0x%x, rpc 0x%x Trap offset 0x%x, " - "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " - "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", - ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), - ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), - ltoh32(sdpcm_shared.trap_addr), - ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), - ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, - (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) - goto printbuf; - - addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, - (uint8 *)&console_size, sizeof(console_size))) < 0) - goto printbuf; - - addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, - (uint8 *)&console_index, sizeof(console_index))) < 0) - goto printbuf; - - console_ptr = ltoh32(console_ptr); - console_size = ltoh32(console_size); - console_index = ltoh32(console_index); - - if (console_size > CONSOLE_BUFFER_MAX || - !(console_buffer = MALLOC(bus->dhd->osh, console_size))) - goto printbuf; - - if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, - (uint8 *)console_buffer, console_size)) < 0) - goto printbuf; - - for (i = 0, n = 0; i < console_size; i += n + 1) { - for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { - ch = console_buffer[(console_index + i + n) % console_size]; - if (ch == '\n') - break; - line[n] = ch; - } - - - if (n > 0) { - if (line[n - 1] == '\r') - n--; - line[n] = 0; - /* Don't use DHD_ERROR macro since we print - * a lot of information quickly. The macro - * will truncate a lot of the printfs - */ - - if (dhd_msg_level & DHD_ERROR_VAL) - printf("CONSOLE: %s\n", line); - } - } - } - } - -printbuf: - if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { - DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); - } - -#ifdef DHD_DEBUG - if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { - /* Mem dump to a file on device */ - dhdsdio_mem_dump(bus); - /* In some cases, the host back trace could be relevant too. */ - WARN_ON(1); - } -#endif /* DHD_DEBUG */ - -done: - if (mbuffer) - MFREE(bus->dhd->osh, mbuffer, msize); - if (str) - MFREE(bus->dhd->osh, str, maxstrlen); - if (console_buffer) - MFREE(bus->dhd->osh, console_buffer, console_size); - - return bcmerror; -} - -static int -dhdsdio_mem_dump(dhd_bus_t *bus) -{ - int ret = 0; - int size; /* Full mem size */ - int start = bus->dongle_ram_base; /* Start address */ - int read_size = 0; /* Read size of each iteration */ - uint8 *buf = NULL, *databuf = NULL; - - /* Get full mem size */ - size = bus->ramsize; - buf = MALLOC(bus->dhd->osh, size); - if (!buf) { - printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size); - return -1; - } - - /* Read mem content */ - DHD_ERROR(("Dump dongle memory")); - databuf = buf; - while (size) - { - read_size = MIN(MEMBLOCK, size); - if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size))) - { - DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret)); - if (buf) { - MFREE(bus->dhd->osh, buf, size); - } - return -1; - } - /* Decrement size and increment start address */ - size -= read_size; - start += read_size; - databuf += read_size; - } - DHD_ERROR(("Done\n")); - - dhd_save_fwdump(bus->dhd, buf, bus->ramsize); -#ifndef CONFIG_BCM_WLAN_RAMDUMP - /* free buf before return !!! */ - if (write_to_file(bus->dhd, buf, bus->ramsize)) - { - printf("%s: Error writing to files\n", __FUNCTION__); - return -1; - } - - /* buf free handled in write_to_file, not here */ -#else - bcm_wlan_crash_reason(bus->dhd->crash_reason); - bcm_wlan_ramdump(buf, bus->ramsize); - memset(bus->dhd->crash_reason, 0 , sizeof(bus->dhd->crash_reason)); - MFREE(bus->dhd->osh, buf, bus->ramsize); -#endif /* CONFIG_BCM_WLAN_RAMDUMP */ - return 0; -} -#endif /* DHD_DEBUG */ - -int -dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) -{ - int bcmerror = BCME_OK; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Basic sanity checks */ - if (bus->dhd->up) { - bcmerror = BCME_NOTDOWN; - goto err; - } - if (!len) { - bcmerror = BCME_BUFTOOSHORT; - goto err; - } - - /* Free the old ones and replace with passed variables */ - if (bus->vars) - MFREE(bus->dhd->osh, bus->vars, bus->varsz); - - bus->vars = MALLOC(bus->dhd->osh, len); - bus->varsz = bus->vars ? len : 0; - if (bus->vars == NULL) { - bcmerror = BCME_NOMEM; - goto err; - } - - /* Copy the passed variables, which should include the terminating double-null */ - bcopy(arg, bus->vars, bus->varsz); -err: - return bcmerror; -} - -#ifdef DHD_DEBUG - -#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) -#define CC_CHIPCTRL_JTAG_SEL (1 << 3) -#define CC_CHIPCTRL_GPIO_SEL (0x3) -#define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28) - -static int -dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) -{ - int int_val; - uint32 addr, data, uart_enab = 0; - uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL; - uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL; - - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - *bcmerror = 0; - - bcmsdh_reg_write(bus->sdh, addr, 4, 1); - if (bcmsdh_regfail(bus->sdh)) { - *bcmerror = BCME_SDIO_ERROR; - return -1; - } - int_val = bcmsdh_reg_read(bus->sdh, data, 4); - if (bcmsdh_regfail(bus->sdh)) { - *bcmerror = BCME_SDIO_ERROR; - return -1; - } - if (bus->sih->chip == BCM4330_CHIP_ID) { - uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; - } - else if (bus->sih->chip == BCM4334_CHIP_ID || - bus->sih->chip == BCM43340_CHIP_ID || - bus->sih->chip == BCM43341_CHIP_ID || - bus->sih->chip == BCM43342_CHIP_ID || - 0) { - if (enable) { - /* Moved to PMU chipcontrol 1 from 4330 */ - int_val &= ~gpio_sel; - int_val |= jtag_sel; - } else { - int_val |= gpio_sel; - int_val &= ~jtag_sel; - } - uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334; - } - - if (!set) - return (int_val & uart_enab); - if (enable) - int_val |= uart_enab; - else - int_val &= ~uart_enab; - bcmsdh_reg_write(bus->sdh, data, 4, int_val); - if (bcmsdh_regfail(bus->sdh)) { - *bcmerror = BCME_SDIO_ERROR; - return -1; - } - if (bus->sih->chip == BCM4330_CHIP_ID) { - uint32 chipcontrol; - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); - chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); - chipcontrol &= ~jtag_sel; - if (enable) { - chipcontrol |= jtag_sel; - chipcontrol &= ~gpio_sel; - } - bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); - } - - return (int_val & uart_enab); -} -#endif - -static int -dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - bool bool_val = 0; - - DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", - __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - - - /* Some ioctls use the bus */ - dhd_os_sdlock(bus->dhd); - - /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ - if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || - actionid == IOV_GVAL(IOV_DEVRESET))) { - bcmerror = BCME_NOTREADY; - goto exit; - } - - /* - * Special handling for keepSdioOn: New SDIO Wake-up Mechanism - */ - if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) { - dhdsdio_clk_kso_iovar(bus, bool_val); - goto exit; - } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { - { - dhdsdio_clk_devsleep_iovar(bus, bool_val); - if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { - DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n", - bus->dpc_sched)); - if (!bus->dpc_sched) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - } - } - goto exit; - } - - /* Handle sleep stuff before any clock mucking */ - if (vi->varid == IOV_SLEEP) { - if (IOV_ISSET(actionid)) { - bcmerror = dhdsdio_bussleep(bus, bool_val); - } else { - int_val = (int32)bus->sleeping; - bcopy(&int_val, arg, val_size); - } - goto exit; - } - - /* Request clock to allow SDIO accesses */ - if (!bus->dhd->dongle_reset) { - BUS_WAKE(bus); - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - } - - switch (actionid) { - case IOV_GVAL(IOV_INTR): - int_val = (int32)bus->intr; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_INTR): - bus->intr = bool_val; - bus->intdis = FALSE; - if (bus->dhd->up) { - if (bus->intr) { - DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); - bcmsdh_intr_enable(bus->sdh); - } else { - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - } - } - break; - - case IOV_GVAL(IOV_POLLRATE): - int_val = (int32)bus->pollrate; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POLLRATE): - bus->pollrate = (uint)int_val; - bus->poll = (bus->pollrate != 0); - break; - - case IOV_GVAL(IOV_IDLETIME): - int_val = bus->idletime; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_IDLETIME): - if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) { - bcmerror = BCME_BADARG; - } else { - bus->idletime = int_val; - } - break; - - case IOV_GVAL(IOV_IDLECLOCK): - int_val = (int32)bus->idleclock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_IDLECLOCK): - bus->idleclock = int_val; - break; - - case IOV_GVAL(IOV_SD1IDLE): - int_val = (int32)sd1idle; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SD1IDLE): - sd1idle = bool_val; - break; - - - case IOV_SVAL(IOV_MEMBYTES): - case IOV_GVAL(IOV_MEMBYTES): - { - uint32 address; - uint size, dsize; - uint8 *data; - - bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); - - ASSERT(plen >= 2*sizeof(int)); - - address = (uint32)int_val; - bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); - size = (uint)int_val; - - /* Do some validation */ - dsize = set ? plen - (2 * sizeof(int)) : len; - if (dsize < size) { - DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", - __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); - bcmerror = BCME_BADARG; - break; - } - - DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, - (set ? "write" : "read"), size, address)); - - /* check if CR4 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - /* - * If address is start of RAM (i.e. a downloaded image), - * store the reset instruction to be written in 0 - */ - if (set && address == bus->dongle_ram_base) { - bus->resetinstr = *(((uint32*)params) + 2); - } - } else { - /* If we know about SOCRAM, check for a fit */ - if ((bus->orig_ramsize) && - ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) - { - uint8 enable, protect, remap; - si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); - if (!enable || protect) { - DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", - __FUNCTION__, bus->orig_ramsize, size, address)); - DHD_ERROR(("%s: socram enable %d, protect %d\n", - __FUNCTION__, enable, protect)); - bcmerror = BCME_BADARG; - break; - } - - if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { - uint32 devramsize = si_socdevram_size(bus->sih); - if ((address < SOCDEVRAM_ARM_ADDR) || - (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { - DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n", - __FUNCTION__, address, size)); - DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n", - __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize)); - bcmerror = BCME_BADARG; - break; - } - /* move it such that address is real now */ - address -= SOCDEVRAM_ARM_ADDR; - address += SOCDEVRAM_BP_ADDR; - DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", - __FUNCTION__, (set ? "write" : "read"), size, address)); - } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { - /* Can not access remap region while devram remap bit is set - * ROM content would be returned in this case - */ - DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n", - __FUNCTION__, address)); - bcmerror = BCME_ERROR; - break; - } - } - } - - /* Generate the actual data pointer */ - data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; - - /* Call to do the transfer */ - bcmerror = dhdsdio_membytes(bus, set, address, data, size); - - break; - } - - case IOV_GVAL(IOV_RAMSIZE): - int_val = (int32)bus->ramsize; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_RAMSTART): - int_val = (int32)bus->dongle_ram_base; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_SDIOD_DRIVE): - int_val = (int32)dhd_sdiod_drive_strength; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDIOD_DRIVE): - dhd_sdiod_drive_strength = int_val; - si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength); - break; - - case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): - bcmerror = dhdsdio_download_state(bus, bool_val); - break; - - case IOV_SVAL(IOV_SOCRAM_STATE): - bcmerror = dhdsdio_download_state(bus, bool_val); - break; - - case IOV_SVAL(IOV_VARS): - bcmerror = dhdsdio_downloadvars(bus, arg, len); - break; - - case IOV_GVAL(IOV_READAHEAD): - int_val = (int32)dhd_readahead; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_READAHEAD): - if (bool_val && !dhd_readahead) - bus->nextlen = 0; - dhd_readahead = bool_val; - break; - - case IOV_GVAL(IOV_SDRXCHAIN): - int_val = (int32)bus->use_rxchain; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDRXCHAIN): - if (bool_val && !bus->sd_rxchain) - bcmerror = BCME_UNSUPPORTED; - else - bus->use_rxchain = bool_val; - break; - case IOV_GVAL(IOV_ALIGNCTL): - int_val = (int32)dhd_alignctl; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_ALIGNCTL): - dhd_alignctl = bool_val; - break; - - case IOV_GVAL(IOV_SDALIGN): - int_val = DHD_SDALIGN; - bcopy(&int_val, arg, val_size); - break; - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_VARS): - if (bus->varsz < (uint)len) - bcopy(bus->vars, arg, bus->varsz); - else - bcmerror = BCME_BUFTOOSHORT; - break; -#endif /* DHD_DEBUG */ - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_SDREG): - { - sdreg_t *sd_ptr; - uint32 addr, size; - - sd_ptr = (sdreg_t *)params; - - addr = (uint32)((ulong)bus->regs + sd_ptr->offset); - size = sd_ptr->func; - int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - bcopy(&int_val, arg, sizeof(int32)); - break; - } - - case IOV_SVAL(IOV_SDREG): - { - sdreg_t *sd_ptr; - uint32 addr, size; - - sd_ptr = (sdreg_t *)params; - - addr = (uint32)((ulong)bus->regs + sd_ptr->offset); - size = sd_ptr->func; - bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - break; - } - - /* Same as above, but offset is not backplane (not SDIO core) */ - case IOV_GVAL(IOV_SBREG): - { - sdreg_t sdreg; - uint32 addr, size; - - bcopy(params, &sdreg, sizeof(sdreg)); - - addr = SI_ENUM_BASE + sdreg.offset; - size = sdreg.func; - int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - bcopy(&int_val, arg, sizeof(int32)); - break; - } - - case IOV_SVAL(IOV_SBREG): - { - sdreg_t sdreg; - uint32 addr, size; - - bcopy(params, &sdreg, sizeof(sdreg)); - - addr = SI_ENUM_BASE + sdreg.offset; - size = sdreg.func; - bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - break; - } - - case IOV_GVAL(IOV_SDCIS): - { - *(char *)arg = 0; - - bcmstrcat(arg, "\nFunc 0\n"); - bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); - bcmstrcat(arg, "\nFunc 1\n"); - bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); - bcmstrcat(arg, "\nFunc 2\n"); - bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); - break; - } - - case IOV_GVAL(IOV_FORCEEVEN): - int_val = (int32)forcealign; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_FORCEEVEN): - forcealign = bool_val; - break; - - case IOV_GVAL(IOV_TXBOUND): - int_val = (int32)dhd_txbound; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXBOUND): - dhd_txbound = (uint)int_val; - break; - - case IOV_GVAL(IOV_RXBOUND): - int_val = (int32)dhd_rxbound; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RXBOUND): - dhd_rxbound = (uint)int_val; - break; - - case IOV_GVAL(IOV_TXMINMAX): - int_val = (int32)dhd_txminmax; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXMINMAX): - dhd_txminmax = (uint)int_val; - break; - - case IOV_GVAL(IOV_SERIALCONS): - int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); - if (bcmerror != 0) - break; - - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SERIALCONS): - dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); - break; - - -#endif /* DHD_DEBUG */ - - -#ifdef SDTEST - case IOV_GVAL(IOV_EXTLOOP): - int_val = (int32)bus->ext_loop; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_EXTLOOP): - bus->ext_loop = bool_val; - break; - - case IOV_GVAL(IOV_PKTGEN): - bcmerror = dhdsdio_pktgen_get(bus, arg); - break; - - case IOV_SVAL(IOV_PKTGEN): - bcmerror = dhdsdio_pktgen_set(bus, arg); - break; -#endif /* SDTEST */ - -#if defined(USE_SDIOFIFO_IOVAR) - case IOV_GVAL(IOV_WATERMARK): - int_val = (int32)watermark; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WATERMARK): - watermark = (uint)int_val; - watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark; - DHD_ERROR(("Setting watermark as 0x%x.\n", watermark)); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL); - break; - - case IOV_GVAL(IOV_MESBUSYCTRL): - int_val = (int32)mesbusyctrl; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MESBUSYCTRL): - mesbusyctrl = (uint)int_val; - mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) - ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; - DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl)); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, - ((uint8)mesbusyctrl | 0x80), NULL); - break; -#endif - - - case IOV_GVAL(IOV_DONGLEISOLATION): - int_val = bus->dhd->dongle_isolation; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DONGLEISOLATION): - bus->dhd->dongle_isolation = bool_val; - break; - - case IOV_SVAL(IOV_DEVRESET): - DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", - __FUNCTION__, bool_val, bus->dhd->dongle_reset, - bus->dhd->busstate)); - - ASSERT(bus->dhd->osh); - /* ASSERT(bus->cl_devid); */ - - dhd_bus_devreset(bus->dhd, (uint8)bool_val); - - break; - /* - * softap firmware is updated through module parameter or android private command - */ - - case IOV_GVAL(IOV_DEVRESET): - DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__)); - - /* Get its status */ - int_val = (bool) bus->dhd->dongle_reset; - bcopy(&int_val, arg, val_size); - - break; - - case IOV_GVAL(IOV_KSO): - int_val = dhdsdio_sleepcsr_get(bus); - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DEVCAP): - int_val = dhdsdio_devcap_get(bus); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DEVCAP): - dhdsdio_devcap_set(bus, (uint8) int_val); - break; - case IOV_GVAL(IOV_TXGLOMSIZE): - int_val = (int32)bus->txglomsize; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXGLOMSIZE): - if (int_val > SDPCM_MAXGLOM_SIZE) { - bcmerror = BCME_ERROR; - } else { - bus->txglomsize = (uint)int_val; - } - break; - case IOV_SVAL(IOV_HANGREPORT): - bus->dhd->hang_report = bool_val; - DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report)); - break; - - case IOV_GVAL(IOV_HANGREPORT): - int_val = (int32)bus->dhd->hang_report; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_TXINRX_THRES): - int_val = bus->txinrx_thres; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_TXINRX_THRES): - if (int_val < 0) { - bcmerror = BCME_BADARG; - } else { - bus->txinrx_thres = int_val; - } - break; - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } - -exit: - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - - return bcmerror; -} - -static int -dhdsdio_write_vars(dhd_bus_t *bus) -{ - int bcmerror = 0; - uint32 varsize, phys_size; - uint32 varaddr; - uint8 *vbuffer; - uint32 varsizew; -#ifdef DHD_DEBUG - uint8 *nvram_ularray; -#endif /* DHD_DEBUG */ - - /* 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; - - varaddr += bus->dongle_ram_base; - - if (bus->vars) { - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { - if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { - DHD_ERROR(("PR85623WAR in place\n")); - varsize += 4; - varaddr -= 4; - } - } - - vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); - if (!vbuffer) - return BCME_NOMEM; - - bzero(vbuffer, varsize); - bcopy(bus->vars, vbuffer, bus->varsz); - - /* Write the vars list */ - bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); -#ifdef DHD_DEBUG - /* Verify NVRAM bytes */ - DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); - nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); - if (!nvram_ularray) { - MFREE(bus->dhd->osh, vbuffer, varsize); - return BCME_NOMEM; - } - - /* Upload image to verify downloaded contents. */ - memset(nvram_ularray, 0xaa, varsize); - - /* Read the vars list to temp buffer for comparison */ - bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", - __FUNCTION__, bcmerror, varsize, varaddr)); - } - /* Compare the org NVRAM with the one read from RAM */ - if (memcmp(vbuffer, nvram_ularray, varsize)) { - DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); - } else - DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", - __FUNCTION__)); - - MFREE(bus->dhd->osh, nvram_ularray, varsize); -#endif /* DHD_DEBUG */ - - MFREE(bus->dhd->osh, vbuffer, varsize); - } - - phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; - - phys_size += bus->dongle_ram_base; - - /* adjust to the user specified RAM */ - DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", - phys_size, bus->ramsize)); - DHD_INFO(("Vars are at %d, orig varsize is %d\n", - varaddr, varsize)); - varsize = ((phys_size - 4) - varaddr); - - /* - * Determine the length token: - * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. - */ - if (bcmerror) { - varsizew = 0; - } else { - varsizew = varsize / 4; - varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); - varsizew = htol32(varsizew); - } - - DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); - - /* Write the length token to the last word */ - bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4), - (uint8*)&varsizew, 4); - - return bcmerror; -} - -static int -dhdsdio_download_state(dhd_bus_t *bus, bool enter) -{ - uint retries; - int bcmerror = 0; - int foundcr4 = 0; - - if (!bus->sih) - return BCME_ERROR; - /* 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; - - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - foundcr4 = 1; - } else { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - } - - if (!foundcr4) { - si_core_disable(bus->sih, 0); - if (bcmsdh_regfail(bus->sdh)) { - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - si_core_reset(bus->sih, 0, 0); - if (bcmsdh_regfail(bus->sdh)) { - DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", - __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - /* Disable remap for download */ - if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, FALSE); - - if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID) { - /* Disabling Remap for SRAM_3 */ - si_socram_set_bankpda(bus->sih, 0x3, 0x0); - } - - /* Clear the top bit of memory */ - if (bus->ramsize) { - uint32 zeros = 0; - if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, - (uint8*)&zeros, 4) < 0) { - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - } - } else { - /* For CR4, - * Halt ARM - * Remove ARM reset - * Read RAM base address [0x18_0000] - * [next] Download firmware - * [done at else] Populate the reset vector - * [done at else] Remove ARM halt - */ - /* Halt ARM & remove reset */ - si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); - } - } else { - if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - if (!si_iscoreup(bus->sih)) { - DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - if ((bcmerror = dhdsdio_write_vars(bus))) { - DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); - goto fail; - } - - /* Enable remap before ARM reset but after vars. - * No backplane access in remap mode - */ - if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, TRUE); - - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && - !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); - - - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - } else { - /* cr4 has no socram, but tcm's */ - /* write vars */ - if ((bcmerror = dhdsdio_write_vars(bus))) { - DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); - goto fail; - } - - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && - !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); - - /* switch back to arm core again */ - if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - /* write address 0 with reset instruction */ - bcmerror = dhdsdio_membytes(bus, TRUE, 0, - (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); - - /* now remove reset and halt and continue to run CR4 */ - } - - si_core_reset(bus->sih, 0, 0); - if (bcmsdh_regfail(bus->sdh)) { - DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - /* Allow HT Clock now that the ARM is running. */ - bus->alp_only = FALSE; - - bus->dhd->busstate = DHD_BUS_LOAD; - } - -fail: - /* Always return to SDIOD core */ - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) - si_setcore(bus->sih, SDIOD_CORE_ID, 0); - - return bcmerror; -} - -int -dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - dhd_bus_t *bus = dhdp->bus; - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - uint32 actionid; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - /* Look up var locally; if not found pass to host driver */ - if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) { - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - /* Turn on clock in case SD command needs backplane */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set); - - /* Check for bus configuration changes of interest */ - - /* If it was divisor change, read the new one */ - if (set && strcmp(name, "sd_divisor") == 0) { - if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, - &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { - bus->sd_divisor = -1; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); - } else { - DHD_INFO(("%s: noted %s update, value now %d\n", - __FUNCTION__, name, bus->sd_divisor)); - } - } - /* If it was a mode change, read the new one */ - if (set && strcmp(name, "sd_mode") == 0) { - if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, - &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { - bus->sd_mode = -1; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); - } else { - DHD_INFO(("%s: noted %s update, value now %d\n", - __FUNCTION__, name, bus->sd_mode)); - } - } - /* Similar check for blocksize change */ - if (set && strcmp(name, "sd_blocksize") == 0) { - int32 fnum = 2; - if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32), - &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { - bus->blocksize = 0; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); - } else { - DHD_INFO(("%s: noted %s update, value now %d\n", - __FUNCTION__, "sd_blocksize", bus->blocksize)); - - dhdsdio_tune_fifoparam(bus); - } - } - bus->roundup = MIN(max_roundup, bus->blocksize); - - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - goto exit; - } - - DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} - -void -dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) -{ - osl_t *osh; - uint32 local_hostintmask; - uint8 saveclk; - uint retries; - int err; - bool wlfc_enabled = FALSE; - - if (!bus->dhd) - return; - - osh = bus->dhd->osh; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bcmsdh_waitlockfree(bus->sdh); - - if (enforce_mutex) - dhd_os_sdlock(bus->dhd); - - if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { - /* if Firmware already hangs disbale any interrupt */ - bus->dhd->busstate = DHD_BUS_DOWN; - bus->hostintmask = 0; - bcmsdh_intr_disable(bus->sdh); - } else { - - BUS_WAKE(bus); - - /* Change our idea of bus state */ - bus->dhd->busstate = DHD_BUS_DOWN; - - if (KSO_ENAB(bus)) { - - /* Enable clock for device interrupts */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Disable and clear interrupts at the chip level also */ - W_SDREG(0, &bus->regs->hostintmask, retries); - local_hostintmask = bus->hostintmask; - bus->hostintmask = 0; - - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) { - DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", - __FUNCTION__, err)); - } - - /* Turn off the bus (F2), free any pending packets */ - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); - - /* Clear any pending interrupts now that F2 is disabled */ - W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); - } - - /* Turn off the backplane clock (only) */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - -#ifdef PROP_TXSTATUS - wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED); -#endif - if (!wlfc_enabled) { -#ifdef DHDTCPACK_SUPPRESS - /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, - * when there is a newly coming packet from network stack. - */ - dhd_tcpack_info_tbl_clean(bus->dhd); -#endif /* DHDTCPACK_SUPPRESS */ - /* Clear the data packet queues */ - pktq_flush(osh, &bus->txq, TRUE, NULL, 0); - } - - /* Clear any held glomming stuff */ - if (bus->glomd) - PKTFREE(osh, bus->glomd, FALSE); - - if (bus->glom) - PKTFREE(osh, bus->glom, FALSE); - - bus->glom = bus->glomd = NULL; - - /* Clear rx control and wake any waiters */ - bus->rxlen = 0; - dhd_os_ioctl_resp_wake(bus->dhd); - - /* Reset some F2 state stuff */ - bus->rxskip = FALSE; - bus->tx_seq = bus->rx_seq = 0; - - bus->tx_max = 4; - - if (enforce_mutex) - dhd_os_sdunlock(bus->dhd); -} - -#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD) -extern uint sd_txglom; -#endif -void -dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) -{ - /* can't enable host txglom by default, some platforms have no - * (or crappy) ADMA support and txglom will cause kernel assertions (e.g. - * panda board) - */ - dhd_bus_t *bus = dhdp->bus; -#ifdef BCMSDIOH_TXGLOM - uint32 rxglom; - int32 ret; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BCMSDIOH_STD - if (enable) - enable = sd_txglom; -#endif /* BCMSDIOH_STD */ - - if (enable) { - rxglom = 1; - ret = dhd_iovar(dhdp, 0, "bus:rxglom", (char *)&rxglom, sizeof(rxglom), NULL, 0, - TRUE); - if (ret >= 0) - bus->txglom_enable = TRUE; - else { -#ifdef BCMSDIOH_STD - sd_txglom = 0; -#endif /* BCMSDIOH_STD */ - bus->txglom_enable = FALSE; - } - } else -#endif /* BCMSDIOH_TXGLOM */ - bus->txglom_enable = FALSE; -} - -int -dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) -{ - dhd_bus_t *bus = dhdp->bus; - dhd_timeout_t tmo; - uint retries = 0; - uint8 ready, enable; - int err, ret = 0; - uint8 saveclk; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(bus->dhd); - if (!bus->dhd) - return 0; - - if (enforce_mutex) - dhd_os_sdlock(bus->dhd); - - /* Make sure backplane clock is on, needed to generate F2 interrupt */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (bus->clkstate != CLK_AVAIL) { - DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate)); - ret = -1; - goto exit; - } - - - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) { - DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); - ret = -1; - goto exit; - } - - /* Enable function 2 (frame transfers) */ - W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT), - &bus->regs->tosbmailboxdata, retries); - enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); - - /* Give the dongle some time to do its thing and set IOR2 */ - dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); - - ready = 0; - while (ready != enable && !dhd_timeout_expired(&tmo)) - ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); - - DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", - __FUNCTION__, enable, ready, tmo.elapsed)); - - - /* If F2 successfully enabled, set core and enable interrupts */ - if (ready == enable) { - /* Make sure we're talking to the core. */ - if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) - bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); - ASSERT(bus->regs != NULL); - - /* Set up the interrupt mask and enable interrupts */ - bus->hostintmask = HOSTINTMASK; - /* corerev 4 could use the newer interrupt logic to detect the frames */ - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && - (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { - bus->hostintmask &= ~I_HMB_FRAME_IND; - bus->hostintmask |= I_XMTDATA_AVAIL; - } - W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); - - if (bus->sih->buscorerev < 15) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, - (uint8)watermark, &err); - } - - /* Set bus state according to enable result */ - dhdp->busstate = DHD_BUS_DATA; - - /* bcmsdh_intr_unmask(bus->sdh); */ - - bus->intdis = FALSE; - if (bus->intr) { - DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); - bcmsdh_intr_enable(bus->sdh); - } else { - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - } - - } - - - else { - /* Disable F2 again */ - enable = SDIO_FUNC_ENABLE_1; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); - } - - if (dhdsdio_sr_cap(bus)) { - dhdsdio_sr_init(bus); - /* Masking the chip active interrupt permanantly */ - bus->hostintmask &= ~I_CHIPACTIVE; - W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); - DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n", - __FUNCTION__, bus->hostintmask)); - } - else - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); - - /* If we didn't come up, turn off backplane clock */ - if (dhdp->busstate != DHD_BUS_DATA) - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - - -exit: - if (enforce_mutex) - dhd_os_sdunlock(bus->dhd); - - return ret; -} - -static void -dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) -{ - bcmsdh_info_t *sdh = bus->sdh; - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - uint16 lastrbc; - uint8 hi, lo; - int err; - - DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__, - (abort ? "abort command, " : ""), (rtx ? ", send NAK" : ""))); - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return; - } - - if (abort) { - bcmsdh_abort(sdh, SDIO_FUNC_2); - } - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); - if (err) { - DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__)); - goto fail; - } - bus->f1regdata++; - - /* Wait until the packet has been flushed (device/FIFO stable) */ - for (lastrbc = retries = 0xffff; retries > 0; retries--) { - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err); - if (err) { - DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__)); - goto fail; - } - - bus->f1regdata += 2; - - if ((hi == 0) && (lo == 0)) - break; - - if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { - DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n", - __FUNCTION__, lastrbc, ((hi << 8) + lo))); - } - lastrbc = (hi << 8) + lo; - } - - if (!retries) { - DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc)); - } else { - DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries))); - } - - if (rtx) { - bus->rxrtx++; - W_SDREG(SMB_NAK, ®s->tosbmailbox, retries); - bus->f1regdata++; - if (retries <= retry_limit) { - bus->rxskip = TRUE; - } - } - - /* Clear partial in any case */ - bus->nextlen = 0; - -fail: - /* If we can't reach the device, signal failure */ - if (err || bcmsdh_regfail(sdh)) - bus->dhd->busstate = DHD_BUS_DOWN; -} - -static void -dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) -{ - bcmsdh_info_t *sdh = bus->sdh; - uint rdlen, pad; - - int sdret; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Control data already received in aligned rxctl */ - if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) - goto gotpkt; - - ASSERT(bus->rxbuf); - /* Set rxctl for frame (w/optional alignment) */ - bus->rxctl = bus->rxbuf; - if (dhd_alignctl) { - bus->rxctl += firstread; - if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) - bus->rxctl += (DHD_SDALIGN - pad); - bus->rxctl -= firstread; - } - ASSERT(bus->rxctl >= bus->rxbuf); - - /* Copy the already-read portion over */ - bcopy(hdr, bus->rxctl, firstread); - if (len <= firstread) - goto gotpkt; - - /* Copy the full data pkt in gSPI case and process ioctl. */ - if (bus->bus == SPI_BUS) { - bcopy(hdr, bus->rxctl, len); - goto gotpkt; - } - - /* Raise rdlen to next SDIO block to avoid tail command */ - rdlen = len - 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->dhd->maxctl)) - rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { - rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (forcealign && (rdlen & (ALIGNMENT - 1))) - rdlen = ROUNDUP(rdlen, ALIGNMENT); - - /* Drop if the read is too big or it exceeds our maximum */ - if ((rdlen + firstread) > bus->dhd->maxctl) { - DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n", - __FUNCTION__, rdlen, bus->dhd->maxctl)); - bus->dhd->rx_errors++; - dhdsdio_rxfail(bus, FALSE, FALSE); - goto done; - } - - if ((len - doff) > bus->dhd->maxctl) { - DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", - __FUNCTION__, len, (len - doff), bus->dhd->maxctl)); - bus->dhd->rx_errors++; bus->rx_toolong++; - dhdsdio_rxfail(bus, FALSE, FALSE); - goto done; - } - - - /* Read remainder of frame body into the rxctl buffer */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - /* Control frame failures need retransmission */ - if (sdret < 0) { - DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret)); - bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */ - dhdsdio_rxfail(bus, TRUE, TRUE); - goto done; - } - -gotpkt: - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_CTL_ON()) { - prhex("RxCtrl", bus->rxctl, len); - } -#endif - - /* Point to valid data and indicate its length */ - bus->rxctl += doff; - bus->rxlen = len - doff; - -done: - /* Awake any waiters */ - dhd_os_ioctl_resp_wake(bus->dhd); -} -int -dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, - void **pkt, uint32 *pkt_count); - -static uint8 -dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) -{ - uint16 dlen, totlen; - uint8 *dptr, num = 0; - - uint16 sublen, check; - void *pfirst, *plast, *pnext; - void * list_tail[DHD_MAX_IFS] = { NULL }; - void * list_head[DHD_MAX_IFS] = { NULL }; - uint8 idx; - osl_t *osh = bus->dhd->osh; - - int errcode; - uint8 chan, seq, doff, sfdoff; - uint8 txmax; - uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; - uint reorder_info_len; - - int ifidx = 0; - bool usechain = bus->use_rxchain; - - /* If packets, issue read(s) and send up packet chain */ - /* Return sequence numbers consumed? */ - - DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom)); - - /* If there's a descriptor, generate the packet chain */ - if (bus->glomd) { - dhd_os_sdlock_rxq(bus->dhd); - - pfirst = plast = pnext = NULL; - dlen = (uint16)PKTLEN(osh, bus->glomd); - dptr = PKTDATA(osh, bus->glomd); - if (!dlen || (dlen & 1)) { - DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n", - __FUNCTION__, dlen)); - dlen = 0; - } - - for (totlen = num = 0; dlen; num++) { - /* Get (and move past) next length */ - sublen = ltoh16_ua(dptr); - dlen -= sizeof(uint16); - dptr += sizeof(uint16); - if ((sublen < SDPCM_HDRLEN) || - ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { - DHD_ERROR(("%s: descriptor len %d bad: %d\n", - __FUNCTION__, num, sublen)); - pnext = NULL; - break; - } - if (sublen % DHD_SDALIGN) { - DHD_ERROR(("%s: sublen %d not a multiple of %d\n", - __FUNCTION__, sublen, DHD_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 */ - if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) { - DHD_ERROR(("%s: PKTGET failed, num %d len %d\n", - __FUNCTION__, num, sublen)); - break; - } - ASSERT(!PKTLINK(pnext)); - if (!pfirst) { - ASSERT(!plast); - pfirst = plast = pnext; - } else { - ASSERT(plast); - PKTSETNEXT(osh, plast, pnext); - plast = pnext; - } - - /* Adhere to start alignment requirements */ - PKTALIGN(osh, pnext, sublen, DHD_SDALIGN); - } - - /* If all allocations succeeded, save packet chain in bus structure */ - if (pnext) { - DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n", - __FUNCTION__, totlen, num)); - if (DHD_GLOM_ON() && bus->nextlen) { - if (totlen != bus->nextlen) { - DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d " - "rxseq %d\n", __FUNCTION__, bus->nextlen, - totlen, rxseq)); - } - } - bus->glom = pfirst; - pfirst = pnext = NULL; - } else { - if (pfirst) - PKTFREE(osh, pfirst, FALSE); - bus->glom = NULL; - num = 0; - } - - /* Done with descriptor packet */ - PKTFREE(osh, bus->glomd, FALSE); - bus->glomd = NULL; - bus->nextlen = 0; - - dhd_os_sdunlock_rxq(bus->dhd); - } - - /* Ok -- either we just generated a packet chain, or had one from before */ - if (bus->glom) { - if (DHD_GLOM_ON()) { - DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__)); - for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) { - DHD_GLOM((" %p: %p len 0x%04x (%d)\n", - pnext, (uint8*)PKTDATA(osh, pnext), - PKTLEN(osh, pnext), PKTLEN(osh, pnext))); - } - } - - pfirst = bus->glom; - dlen = (uint16)pkttotlen(osh, 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 = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, (uint8*)PKTDATA(osh, pfirst), - dlen, pfirst, NULL, NULL); - } else if (bus->dataptr) { - errcode = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, bus->dataptr, - dlen, NULL, NULL, NULL); - sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); - if (sublen != dlen) { - DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n", - __FUNCTION__, dlen, sublen)); - errcode = -1; - } - pnext = NULL; - } else { - DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen)); - errcode = -1; - } - bus->f2rxdata++; - ASSERT(errcode != BCME_PENDING); - - /* On failure, kill the superframe, allow a couple retries */ - if (errcode < 0) { - DHD_ERROR(("%s: glom read of %d bytes failed: %d\n", - __FUNCTION__, dlen, errcode)); - bus->dhd->rx_errors++; - - if (bus->glomerr++ < 3) { - dhdsdio_rxfail(bus, TRUE, TRUE); - } else { - bus->glomerr = 0; - dhdsdio_rxfail(bus, TRUE, FALSE); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(osh, bus->glom, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->rxglomfail++; - bus->glom = NULL; - } - return 0; - } - -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - prhex("SUPERFRAME", PKTDATA(osh, pfirst), - MIN(PKTLEN(osh, pfirst), 48)); - } -#endif - - - /* Validate the superframe header */ - dptr = (uint8 *)PKTDATA(osh, pfirst); - sublen = ltoh16_ua(dptr); - check = ltoh16_ua(dptr + sizeof(uint16)); - - 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) { - DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n", - __FUNCTION__, 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 ((uint16)~(sublen^check)) { - DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n", - __FUNCTION__, sublen, check)); - errcode = -1; - } else if (ROUNDUP(sublen, bus->blocksize) != dlen) { - DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", - __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen)); - errcode = -1; - } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) { - DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__, - SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]))); - errcode = -1; - } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { - DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__)); - errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || - (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) { - DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", - __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), - SDPCM_HDRLEN)); - errcode = -1; - } - - /* Check sequence number of superframe SW header */ - if (rxseq != seq) { - DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n", - __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((uint8)(txmax - bus->tx_seq) > 0x70) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", - __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_max; - } - bus->tx_max = txmax; - - /* Remove superframe header, remember offset */ - PKTPULL(osh, pfirst, doff); - sfdoff = doff; - - /* Validate all the subframe headers */ - for (num = 0, pnext = pfirst; pnext && !errcode; - num++, pnext = PKTNEXT(osh, pnext)) { - dptr = (uint8 *)PKTDATA(osh, pnext); - dlen = (uint16)PKTLEN(osh, pnext); - sublen = ltoh16_ua(dptr); - check = ltoh16_ua(dptr + sizeof(uint16)); - chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - prhex("subframe", dptr, 32); - } -#endif - - if ((uint16)~(sublen^check)) { - DHD_ERROR(("%s (subframe %d): HW hdr error: " - "len/check 0x%04x/0x%04x\n", - __FUNCTION__, num, sublen, check)); - errcode = -1; - } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { - DHD_ERROR(("%s (subframe %d): length mismatch: " - "len 0x%04x, expect 0x%04x\n", - __FUNCTION__, num, sublen, dlen)); - errcode = -1; - } else if ((chan != SDPCM_DATA_CHANNEL) && - (chan != SDPCM_EVENT_CHANNEL)) { - DHD_ERROR(("%s (subframe %d): bad channel %d\n", - __FUNCTION__, num, chan)); - errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { - DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n", - __FUNCTION__, 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 */ - PKTPUSH(osh, pfirst, sfdoff); - dhdsdio_rxfail(bus, TRUE, TRUE); - } else { - bus->glomerr = 0; - dhdsdio_rxfail(bus, TRUE, FALSE); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(osh, bus->glom, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->rxglomfail++; - bus->glom = NULL; - } - bus->nextlen = 0; - return 0; - } - - /* Basic SD framing looks ok - process each packet (header) */ - bus->glom = NULL; - plast = NULL; - - dhd_os_sdlock_rxq(bus->dhd); - for (num = 0; pfirst; rxseq++, pfirst = pnext) { - pnext = PKTNEXT(osh, pfirst); - PKTSETNEXT(osh, pfirst, NULL); - - dptr = (uint8 *)PKTDATA(osh, pfirst); - sublen = ltoh16_ua(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]); - - DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", - __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst), - PKTLEN(osh, pfirst), sublen, chan, seq)); - - ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); - - if (rxseq != seq) { - DHD_GLOM(("%s: rx_seq %d, expected %d\n", - __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - prhex("Rx Subframe Data", dptr, dlen); - } -#endif - - PKTSETLEN(osh, pfirst, sublen); - PKTPULL(osh, pfirst, doff); - - reorder_info_len = sizeof(reorder_info_buf); - - if (PKTLEN(osh, pfirst) == 0) { - PKTFREE(bus->dhd->osh, pfirst, FALSE); - continue; - } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, - &reorder_info_len) != 0) { - DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); - bus->dhd->rx_errors++; - PKTFREE(osh, pfirst, FALSE); - continue; - } - if (reorder_info_len) { - uint32 free_buf_count; - void *ppfirst; - - ppfirst = pfirst; - /* Reordering info from the firmware */ - dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, - reorder_info_len, &ppfirst, &free_buf_count); - - if (free_buf_count == 0) { - continue; - } - else { - void *temp; - - /* go to the end of the chain and attach the pnext there */ - temp = ppfirst; - while (PKTNEXT(osh, temp) != NULL) { - temp = PKTNEXT(osh, temp); - } - pfirst = temp; - if (list_tail[ifidx] == NULL) - list_head[ifidx] = ppfirst; - else - PKTSETNEXT(osh, list_tail[ifidx], ppfirst); - list_tail[ifidx] = pfirst; - } - - num += (uint8)free_buf_count; - } - else { - /* this packet will go up, link back into chain and count it */ - - if (list_tail[ifidx] == NULL) { - list_head[ifidx] = list_tail[ifidx] = pfirst; - } - else { - PKTSETNEXT(osh, list_tail[ifidx], pfirst); - list_tail[ifidx] = pfirst; - } - num++; - } -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n", - __FUNCTION__, num, pfirst, - PKTDATA(osh, pfirst), PKTLEN(osh, pfirst), - PKTNEXT(osh, pfirst), PKTLINK(pfirst))); - prhex("", (uint8 *)PKTDATA(osh, pfirst), - MIN(PKTLEN(osh, pfirst), 32)); - } -#endif /* DHD_DEBUG */ - } - dhd_os_sdunlock_rxq(bus->dhd); - - for (idx = 0; idx < DHD_MAX_IFS; idx++) { - if (list_head[idx]) { - void *temp; - uint8 cnt = 0; - temp = list_head[idx]; - do { - temp = PKTNEXT(osh, temp); - cnt++; - } while (temp); - if (cnt) { - dhd_os_sdunlock(bus->dhd); - dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); - dhd_os_sdlock(bus->dhd); - } - } - } - bus->rxglomframes++; - bus->rxglompkts += num; - } - return num; -} - - -/* Return TRUE if there may be more frames to read */ -static uint -dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) -{ - osl_t *osh = bus->dhd->osh; - bcmsdh_info_t *sdh = bus->sdh; - - uint16 len, check; /* Extracted hardware header fields */ - uint8 chan, seq, doff; /* Extracted software header fields */ - uint8 fcbits; /* Extracted fcbits from software header */ - uint8 delta; - - void *pkt; /* Packet for event or data frames */ - uint16 pad; /* Number of pad bytes to read */ - uint16 rdlen; /* Total number of bytes to read */ - uint8 rxseq; /* Next sequence number to expect */ - uint rxleft = 0; /* Remaining number of frames allowed */ - int sdret; /* Return code from bcmsdh calls */ - uint8 txmax; /* Maximum tx sequence offered */ - bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ - uint8 *rxbuf; - int ifidx = 0; - uint rxcount = 0; /* Total frames read */ - uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; - uint reorder_info_len; - uint pkt_count; - -#if defined(DHD_DEBUG) || defined(SDTEST) - bool sdtest = FALSE; /* To limit message spew from test mode */ -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bus->readframes = TRUE; - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: KSO off\n", __FUNCTION__)); - bus->readframes = FALSE; - return 0; - } - - ASSERT(maxframes); - -#ifdef SDTEST - /* Allow pktgen to override maxframes */ - if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { - maxframes = bus->pktgen_count; - sdtest = TRUE; - } -#endif - - /* Not finished unless we encounter no more frames indication */ - *finished = FALSE; - - - for (rxseq = bus->rx_seq, rxleft = maxframes; - !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; - rxseq++, rxleft--) { -#ifdef DHDTCPACK_SUP_DBG - if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) { - if (bus->dotxinrx == FALSE) - DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n", - __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode)); - } -#ifdef DEBUG_COUNTER - else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) { - tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++; - } -#endif /* DEBUG_COUNTER */ -#endif /* DHDTCPACK_SUP_DBG */ - /* tx more to improve rx performance */ - if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { - dhdsdio_sendpendctl(bus); - } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) && - !bus->fcstate && DATAOK(bus) && - (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) { - dhdsdio_sendfromq(bus, dhd_txbound); -#ifdef DHDTCPACK_SUPPRESS - /* In TCPACK_SUP_DELAYTX mode, do txinrx only if - * 1. Any DATA packet to TX - * 2. TCPACK to TCPDATA PSH packets. - * in bus txq. - */ - bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ? - FALSE : TRUE; -#endif - } - - /* Handle glomming separately */ - if (bus->glom || bus->glomd) { - uint8 cnt; - DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n", - __FUNCTION__, bus->glomd, bus->glom)); - cnt = dhdsdio_rxglom(bus, rxseq); - DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt)); - rxseq += cnt - 1; - rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; - continue; - } - - /* Try doing single read if we can */ - if (dhd_readahead && bus->nextlen) { - uint16 nextlen = bus->nextlen; - bus->nextlen = 0; - - if (bus->bus == SPI_BUS) { - rdlen = len = nextlen; - } - else { - rdlen = len = nextlen << 4; - - /* 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 + firstread) < MAX_RX_DATASZ)) - rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { - rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); - } - } - - /* We use bus->rxctl buffer in WinXP for initial control pkt receives. - * Later we use buffer-poll for data as well as control packets. - * This is required because dhd receives full frame in gSPI unlike SDIO. - * After the frame is received we have to distinguish whether it is data - * or non-data frame. - */ - /* Allocate a packet buffer */ - dhd_os_sdlock_rxq(bus->dhd); - if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) { - if (bus->bus == SPI_BUS) { - bus->usebufpool = FALSE; - bus->rxctl = bus->rxbuf; - if (dhd_alignctl) { - bus->rxctl += firstread; - if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) - bus->rxctl += (DHD_SDALIGN - pad); - bus->rxctl -= firstread; - } - ASSERT(bus->rxctl >= bus->rxbuf); - rxbuf = bus->rxctl; - /* Read the entire frame */ - sdret = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(sdh), - SDIO_FUNC_2, - F2SYNC, rxbuf, rdlen, - NULL, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - - /* Control frame failures need retransmission */ - if (sdret < 0) { - DHD_ERROR(("%s: read %d control bytes failed: %d\n", - __FUNCTION__, rdlen, sdret)); - /* dhd.rx_ctlerrs is higher level */ - bus->rxc_errors++; - dhd_os_sdunlock_rxq(bus->dhd); - dhdsdio_rxfail(bus, TRUE, - (bus->bus == SPI_BUS) ? FALSE : TRUE); - continue; - } - } else { - /* Give up on data, request rtx of events */ - DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d " - "expected rxseq %d\n", - __FUNCTION__, len, rdlen, rxseq)); - /* Just go try again w/normal header read */ - dhd_os_sdunlock_rxq(bus->dhd); - continue; - } - } else { - if (bus->bus == SPI_BUS) - bus->usebufpool = TRUE; - - ASSERT(!PKTLINK(pkt)); - PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); - rxbuf = (uint8 *)PKTDATA(osh, pkt); - /* Read the entire frame */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), - SDIO_FUNC_2, - F2SYNC, rxbuf, rdlen, - pkt, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - if (sdret < 0) { - DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n", - __FUNCTION__, rdlen, sdret)); - PKTFREE(bus->dhd->osh, pkt, FALSE); - bus->dhd->rx_errors++; - dhd_os_sdunlock_rxq(bus->dhd); - /* Force retry w/normal header read. Don't attempt NAK for - * gSPI - */ - dhdsdio_rxfail(bus, TRUE, - (bus->bus == SPI_BUS) ? FALSE : TRUE); - continue; - } - } - dhd_os_sdunlock_rxq(bus->dhd); - - /* Now check the header */ - bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN); - - /* Extract hardware header fields */ - len = ltoh16_ua(bus->rxhdr); - check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); - - /* All zeros means readahead info was bad */ - if (!(len|check)) { - DHD_INFO(("%s (nextlen): read zeros in HW header???\n", - __FUNCTION__)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - GSPI_PR55150_BAILOUT; - continue; - } - - /* Validate check bytes */ - if ((uint16)~(len^check)) { - DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check" - " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen, - len, check)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - bus->rx_badhdr++; - dhdsdio_rxfail(bus, FALSE, FALSE); - GSPI_PR55150_BAILOUT; - continue; - } - - /* Validate frame length */ - if (len < SDPCM_HDRLEN) { - DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n", - __FUNCTION__, len)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - GSPI_PR55150_BAILOUT; - continue; - } - - /* 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) */ - DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; " - "expected rxseq %d\n", - __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE); - GSPI_PR55150_BAILOUT; - 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) { - DHD_INFO(("%s (nextlen): got frame w/nextlen too large" - " (%d), seq %d\n", __FUNCTION__, bus->nextlen, - seq)); - bus->nextlen = 0; - } - - bus->dhd->rx_readahead_cnt ++; - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - delta = 0; - if (~bus->flowcontrol & fcbits) { - bus->fc_xoff++; - delta = 1; - } - if (bus->flowcontrol & ~fcbits) { - bus->fc_xon++; - delta = 1; - } - - if (delta) { - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n", - __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((uint8)(txmax - bus->tx_seq) > 0x70) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", - __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_max; - } - bus->tx_max = txmax; - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - prhex("Rx Data", rxbuf, len); - } else if (DHD_HDRS_ON()) { - prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); - } -#endif - - if (chan == SDPCM_CONTROL_CHANNEL) { - if (bus->bus == SPI_BUS) { - dhdsdio_read_control(bus, rxbuf, len, doff); - if (bus->usebufpool) { - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - } - continue; - } else { - DHD_ERROR(("%s (nextlen): readahead on control" - " packet %d?\n", __FUNCTION__, seq)); - /* Force retry w/normal header read */ - bus->nextlen = 0; - dhdsdio_rxfail(bus, FALSE, TRUE); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - continue; - } - } - - if ((bus->bus == SPI_BUS) && !bus->usebufpool) { - DHD_ERROR(("Received %d bytes on %d channel. Running out of " - "rx pktbuf's or not yet malloced.\n", len, chan)); - continue; - } - - /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { - DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n", - __FUNCTION__, doff, len, SDPCM_HDRLEN)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - ASSERT(0); - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - /* All done with this one -- now deliver the packet */ - goto deliver; - } - /* gSPI frames should not be handled in fractions */ - if (bus->bus == SPI_BUS) { - break; - } - - /* Read frame header (hardware and software) */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - bus->rxhdr, firstread, NULL, NULL, NULL); - bus->f2rxhdrs++; - ASSERT(sdret != BCME_PENDING); - - if (sdret < 0) { - DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret)); - bus->rx_hdrfail++; - dhdsdio_rxfail(bus, TRUE, TRUE); - continue; - } - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() || DHD_HDRS_ON()) { - prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); - } -#endif - - /* Extract hardware header fields */ - len = ltoh16_ua(bus->rxhdr); - check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); - - /* All zeros means no more frames */ - if (!(len|check)) { - *finished = TRUE; - break; - } - - /* Validate check bytes */ - if ((uint16)~(len^check)) { - DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n", - __FUNCTION__, len, check)); - bus->rx_badhdr++; - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - /* Validate frame length */ - if (len < SDPCM_HDRLEN) { - DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, 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)) { - DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n", - __FUNCTION__, doff, len, SDPCM_HDRLEN, seq)); - bus->rx_badhdr++; - ASSERT(0); - dhdsdio_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) { - DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n", - __FUNCTION__, bus->nextlen, seq)); - bus->nextlen = 0; - } - - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - delta = 0; - if (~bus->flowcontrol & fcbits) { - bus->fc_xoff++; - delta = 1; - } - if (bus->flowcontrol & ~fcbits) { - bus->fc_xon++; - delta = 1; - } - - if (delta) { - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((uint8)(txmax - bus->tx_seq) > 0x70) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", - __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_max; - } - bus->tx_max = txmax; - - /* Call a separate function for control frames */ - if (chan == SDPCM_CONTROL_CHANNEL) { - dhdsdio_read_control(bus, bus->rxhdr, len, doff); - continue; - } - - ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) || - (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL)); - - /* Length to read */ - rdlen = (len > firstread) ? (len - 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 + firstread) < MAX_RX_DATASZ)) - rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { - rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (forcealign && (rdlen & (ALIGNMENT - 1))) - rdlen = ROUNDUP(rdlen, ALIGNMENT); - - if ((rdlen + firstread) > MAX_RX_DATASZ) { - /* Too long -- skip this frame */ - DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen)); - bus->dhd->rx_errors++; bus->rx_toolong++; - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - dhd_os_sdlock_rxq(bus->dhd); - if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) { - /* Give up on data, request rtx of events */ - DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n", - __FUNCTION__, rdlen, chan)); - bus->dhd->rx_dropped++; - dhd_os_sdunlock_rxq(bus->dhd); - dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan)); - continue; - } - dhd_os_sdunlock_rxq(bus->dhd); - - ASSERT(!PKTLINK(pkt)); - - /* Leave room for what we already read, and align remainder */ - ASSERT(firstread < (PKTLEN(osh, pkt))); - PKTPULL(osh, pkt, firstread); - PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); - - /* Read the remaining frame data */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - if (sdret < 0) { - DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen, - ((chan == SDPCM_EVENT_CHANNEL) ? "event" : - ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->dhd->rx_errors++; - dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan)); - continue; - } - - /* Copy the already-read portion */ - PKTPUSH(osh, pkt, firstread); - bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread); - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - prhex("Rx Data", PKTDATA(osh, pkt), len); - } -#endif - -deliver: - /* Save superframe descriptor and allocate packet frame */ - if (chan == SDPCM_GLOM_CHANNEL) { - if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { - DHD_GLOM(("%s: got glom descriptor, %d bytes:\n", - __FUNCTION__, len)); -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - prhex("Glom Data", PKTDATA(osh, pkt), len); - } -#endif - PKTSETLEN(osh, pkt, len); - ASSERT(doff == SDPCM_HDRLEN); - PKTPULL(osh, pkt, SDPCM_HDRLEN); - bus->glomd = pkt; - } else { - DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__)); - dhdsdio_rxfail(bus, FALSE, FALSE); - } - continue; - } - - /* Fill in packet len and prio, deliver upward */ - PKTSETLEN(osh, pkt, len); - PKTPULL(osh, pkt, doff); - -#ifdef SDTEST - /* Test channel packets are processed separately */ - if (chan == SDPCM_TEST_CHANNEL) { - dhdsdio_testrcv(bus, pkt, seq); - continue; - } -#endif /* SDTEST */ - - if (PKTLEN(osh, pkt) == 0) { - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - continue; - } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf, - &reorder_info_len) != 0) { - DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->dhd->rx_errors++; - continue; - } - if (reorder_info_len) { - /* Reordering info from the firmware */ - dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len, - &pkt, &pkt_count); - if (pkt_count == 0) - continue; - } - else - pkt_count = 1; - - /* Unlock during rx call */ - dhd_os_sdunlock(bus->dhd); - dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); - dhd_os_sdlock(bus->dhd); - } - rxcount = maxframes - rxleft; -#ifdef DHD_DEBUG - /* Message if we hit the limit */ - if (!rxleft && !sdtest) - DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes)); - else -#endif /* DHD_DEBUG */ - DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount)); - /* Back off rxseq if awaiting rtx, update rx_seq */ - if (bus->rxskip) - rxseq--; - bus->rx_seq = rxseq; - - if (bus->reqbussleep) - { - dhdsdio_bussleep(bus, TRUE); - bus->reqbussleep = FALSE; - } - bus->readframes = FALSE; - - return rxcount; -} - -static uint32 -dhdsdio_hostmail(dhd_bus_t *bus) -{ - sdpcmd_regs_t *regs = bus->regs; - uint32 intstatus = 0; - uint32 hmb_data; - uint8 fcbits; - uint retries = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Read mailbox data and ack that we did so */ - R_SDREG(hmb_data, ®s->tohostmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries); - bus->f1regdata += 2; - - /* Dongle recomposed rx frames, accept them again */ - if (hmb_data & HMB_DATA_NAKHANDLED) { - DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq)); - if (!bus->rxskip) { - DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__)); - } - bus->rxskip = FALSE; - intstatus |= FRAME_AVAIL_MASK(bus); - } - - /* - * 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) - DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n", - bus->sdpcm_ver, SDPCM_PROT_VERSION)); - else - DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver)); - /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && - (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { - uint32 val; - - val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); - val &= ~CC_XMTDATAAVAIL_MODE; - val |= CC_XMTDATAAVAIL_CTRL; - W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); - - val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); - } - -#ifdef DHD_DEBUG - /* Retrieve console state address now that firmware should have updated it */ - { - sdpcm_shared_t shared; - if (dhdsdio_readshared(bus, &shared) == 0) - bus->console_addr = shared.console_addr; - } -#endif /* DHD_DEBUG */ - } - - /* - * Flow Control has been moved into the RX headers and this out of band - * method isn't used any more. Leave this here for possibly 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; - } - -#ifdef DHD_DEBUG - /* At least print a message if FW halted */ - if (hmb_data & HMB_DATA_FWHALT) { - DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n")); - dhdsdio_checkdied(bus, NULL, 0); - bus->dhd->busstate = DHD_BUS_DOWN; - } -#endif /* DHD_DEBUG */ - - /* Shouldn't be any others */ - if (hmb_data & ~(HMB_DATA_DEVREADY | - HMB_DATA_FWHALT | - HMB_DATA_NAKHANDLED | - HMB_DATA_FC | - HMB_DATA_FWREADY | - HMB_DATA_FCDATA_MASK | - HMB_DATA_VERSION_MASK)) { - DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data)); - } - - return intstatus; -} - -static bool -dhdsdio_dpc(dhd_bus_t *bus) -{ - bcmsdh_info_t *sdh = bus->sdh; - sdpcmd_regs_t *regs = bus->regs; - uint32 intstatus, newstatus = 0; - uint retries = 0; - uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */ - uint txlimit = dhd_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 */ -#if defined(CUSTOMER_HW5) - bool is_resched_by_readframe = FALSE; -#endif - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - dhd_os_sdlock(bus->dhd); - - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); - bus->intstatus = 0; - dhd_os_sdunlock(bus->dhd); - return 0; - } - - /* Start with leftover status bits */ - intstatus = bus->intstatus; - - if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - goto exit; - } - - /* If waiting for HTAVAIL, check status */ - if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) { - int err; - uint8 clkctl, devctl = 0; - -#ifdef DHD_DEBUG - /* Check for inconsistent device control */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - if (err) { - DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } else { - ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); - } -#endif /* DHD_DEBUG */ - - /* Read CSR, if clock on switch to AVAIL, else ignore */ - clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (err) { - DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } - - DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl)); - - if (SBSDIO_HTAV(clkctl)) { - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - if (err) { - DHD_ERROR(("%s: error reading DEVCTL: %d\n", - __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - if (err) { - DHD_ERROR(("%s: error writing DEVCTL: %d\n", - __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } - bus->clkstate = CLK_AVAIL; - } else { - goto clkwait; - } - } - - BUS_WAKE(bus); - - /* Make sure backplane clock is on */ - dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); - if (bus->clkstate != CLK_AVAIL) - goto clkwait; - - /* Pending interrupt indicates new device status */ - if (bus->ipend) { - bus->ipend = FALSE; - R_SDREG(newstatus, ®s->intstatus, retries); - bus->f1regdata++; - if (bcmsdh_regfail(bus->sdh)) - newstatus = 0; - newstatus &= bus->hostintmask; - bus->fcstate = !!(newstatus & I_HMB_FC_STATE); - if (newstatus) { - bus->f1regdata++; - if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && - (newstatus == I_XMTDATA_AVAIL)) { - } - else - W_SDREG(newstatus, ®s->intstatus, retries); - } - } - - /* 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_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries); - R_SDREG(newstatus, ®s->intstatus, retries); - bus->f1regdata += 2; - bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); - intstatus |= (newstatus & bus->hostintmask); - } - - /* Just being here means nothing more to do for chipactive */ - if (intstatus & I_CHIPACTIVE) { - /* ASSERT(bus->clkstate == CLK_AVAIL); */ - intstatus &= ~I_CHIPACTIVE; - } - - /* Handle host mailbox indication */ - if (intstatus & I_HMB_HOST_INT) { - intstatus &= ~I_HMB_HOST_INT; - intstatus |= dhdsdio_hostmail(bus); - } - - /* Generally don't ask for these, can get CRC errors... */ - if (intstatus & I_WR_OOSYNC) { - DHD_ERROR(("Dongle reports WR_OOSYNC\n")); - intstatus &= ~I_WR_OOSYNC; - } - - if (intstatus & I_RD_OOSYNC) { - DHD_ERROR(("Dongle reports RD_OOSYNC\n")); - intstatus &= ~I_RD_OOSYNC; - } - - if (intstatus & I_SBINT) { - DHD_ERROR(("Dongle reports SBINT\n")); - intstatus &= ~I_SBINT; - } - - /* Would be active due to wake-wlan in gSPI */ - if (intstatus & I_CHIPACTIVE) { - DHD_INFO(("Dongle reports CHIPACTIVE\n")); - intstatus &= ~I_CHIPACTIVE; - } - - if (intstatus & I_HMB_FC_STATE) { - DHD_INFO(("Dongle reports HMB_FC_STATE\n")); - intstatus &= ~I_HMB_FC_STATE; - } - - /* Ignore frame indications if rxskip is set */ - if (bus->rxskip) { - intstatus &= ~FRAME_AVAIL_MASK(bus); - } - - /* On frame indication, read available frames */ - if (PKT_AVAILABLE(bus, intstatus)) { - framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); - if (rxdone || bus->rxskip) - intstatus &= ~FRAME_AVAIL_MASK(bus); - rxlimit -= MIN(framecnt, rxlimit); - } - - /* Keep still-pending events for next scheduling */ - bus->intstatus = intstatus; - -clkwait: - /* Re-enable interrupts to detect new device events (mailbox, rx frame) - * or clock availability. (Allows tx loop to check ipend if desired.) - * (Unless register access seems hosed, as we may not be able to ACK...) - */ - if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) { - DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", - __FUNCTION__, rxdone, framecnt)); - bus->intdis = FALSE; -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(bus->sdh, TRUE); -#endif /* defined(OOB_INTR_ONLY) */ - bcmsdh_intr_enable(sdh); - } - -#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) - /* In case of SW-OOB(using edge trigger), - * Check interrupt status in the dongle again after enable irq on the host. - * and rechedule dpc if interrupt is pended in the dongle. - * There is a chance to miss OOB interrupt while irq is disabled on the host. - * No need to do this with HW-OOB(level trigger) - */ - R_SDREG(newstatus, ®s->intstatus, retries); - if (bcmsdh_regfail(bus->sdh)) - newstatus = 0; - if (newstatus & bus->hostintmask) { - bus->ipend = TRUE; - resched = TRUE; - } -#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ - -#ifdef PROP_TXSTATUS - dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE); -#endif - - if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) - dhdsdio_sendpendctl(bus); - - /* Send queued frames (limit 1 if rx may still be pending) */ - else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && - pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { - framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax); - framecnt = dhdsdio_sendfromq(bus, framecnt); - txlimit -= framecnt; - } - /* Resched the DPC if ctrl cmd is pending on bus credit */ - if (bus->ctrl_frame_stat) - resched = TRUE; - - /* 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->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { - if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & - SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { - /* Bus failed because of KSO */ - DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__)); - bus->kso = FALSE; - } else { - DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n", - __FUNCTION__)); - bus->dhd->busstate = DHD_BUS_DOWN; - bus->intstatus = 0; - } - } else if (bus->clkstate == CLK_PENDING) { - /* Awaiting I_CHIPACTIVE; don't resched */ - } else if (bus->intstatus || bus->ipend || - (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || - PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ - resched = TRUE; - } - - bus->dpc_sched = resched; - - /* If we're done for now, turn off clock request. */ - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - } - -exit: - - if (!resched && dhd_dpcpoll) { - if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) { - resched = TRUE; -#if defined(CUSTOMER_HW5) - is_resched_by_readframe = TRUE; -#endif - } - } - - dhd_os_sdunlock(bus->dhd); -#if defined(CUSTOMER_HW5) - if (bus->dhd->dhd_bug_on) { - sprintf(bus->dpc_log_current, "%s: resched = %d ctrl_frame_stat = %d " - "intstatus 0x%08x ipend = %d pktq_mlen = %d " - "is_resched_by_readframe = %d TXCTLOK = %d, clkstate = %d\n", - __FUNCTION__, resched, bus->ctrl_frame_stat, - bus->intstatus, bus->ipend, - pktq_mlen(&bus->txq, ~bus->flowcontrol), is_resched_by_readframe, - TXCTLOK(bus), bus->clkstate); - if (strcmp(bus->dpc_log_previous, bus->dpc_log_current) == 0) { - /* Same log */ - bus->dpc_log_loops++; - } else { - if (bus->dpc_log_loops) { - DHD_ERROR(("(%d) %s\n", bus->dpc_log_loops, bus->dpc_log_previous)); - } - DHD_ERROR(("%s\n", bus->dpc_log_current)); - strcpy(bus->dpc_log_previous, bus->dpc_log_current); - bus->dpc_log_loops = 0; - } - bus->dhd->dhd_bug_on = FALSE; - } -#endif /* CUSTOMER_HW5 */ - return resched; -} - -bool -dhd_bus_dpc(struct dhd_bus *bus) -{ - bool resched; - - /* Call the DPC directly. */ - DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); - resched = dhdsdio_dpc(bus); - - return resched; -} - -void -dhdsdio_isr(void *arg) -{ - dhd_bus_t *bus = (dhd_bus_t*)arg; - bcmsdh_info_t *sdh; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!bus) { - DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); - return; - } - sdh = bus->sdh; - - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - return; - } - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Count the interrupt call */ - bus->intrcount++; - bus->ipend = TRUE; - - /* Shouldn't get this interrupt if we're sleeping? */ - if (!SLPAUTO_ENAB(bus)) { - if (bus->sleeping) { - DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n")); - return; - } else if (!KSO_ENAB(bus)) { - DHD_ERROR(("ISR in devsleep 1\n")); - } - } - - /* Disable additional interrupts (is this needed now)? */ - if (bus->intr) { - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - } else { - DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n")); - } - - bcmsdh_intr_disable(sdh); - bus->intdis = TRUE; - -#if defined(SDIO_ISR_THREAD) - DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK(bus->dhd); - dhdsdio_dpc(bus); - DHD_OS_WAKE_UNLOCK(bus->dhd); -#else - - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - -#endif /* defined(SDIO_ISR_THREAD) */ - -} - -#ifdef SDTEST -static void -dhdsdio_pktgen_init(dhd_bus_t *bus) -{ - /* Default to specified length, or full range */ - if (dhd_pktgen_len) { - bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN); - bus->pktgen_minlen = bus->pktgen_maxlen; - } else { - bus->pktgen_maxlen = MAX_PKTGEN_LEN; - bus->pktgen_minlen = 0; - } - bus->pktgen_len = (uint16)bus->pktgen_minlen; - - /* Default to per-watchdog burst with 10s print time */ - bus->pktgen_freq = 1; - bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0; - bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; - - /* Default to echo mode */ - bus->pktgen_mode = DHD_PKTGEN_ECHO; - bus->pktgen_stop = 1; -} - -static void -dhdsdio_pktgen(dhd_bus_t *bus) -{ - void *pkt; - uint8 *data; - uint pktcount; - uint fillbyte; - osl_t *osh = bus->dhd->osh; - uint16 len; - ulong time_lapse; - uint sent_pkts; - uint rcvd_pkts; - - /* Display current count if appropriate */ - if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { - bus->pktgen_ptick = 0; - printf("%s: send attempts %d, rcvd %d, errors %d\n", - __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); - - /* Print throughput stats only for constant length packet runs */ - if (bus->pktgen_minlen == bus->pktgen_maxlen) { - time_lapse = jiffies - bus->pktgen_prev_time; - bus->pktgen_prev_time = jiffies; - sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent; - bus->pktgen_prev_sent = bus->pktgen_sent; - rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd; - bus->pktgen_prev_rcvd = bus->pktgen_rcvd; - - printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n", - __FUNCTION__, - (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8, - (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8); - } - } - - /* For recv mode, just make sure dongle has started sending */ - if (bus->pktgen_mode == DHD_PKTGEN_RECV) { - if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { - bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; - dhdsdio_sdtest_set(bus, bus->pktgen_total); - } - return; - } - - /* Otherwise, generate or request the specified number of packets */ - for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) { - /* Stop if total has been reached */ - if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) { - bus->pktgen_count = 0; - break; - } - - /* Allocate an appropriate-sized packet */ - if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { - len = SDPCM_TEST_PKT_CNT_FLD_LEN; - } else { - len = bus->pktgen_len; - } - if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), - TRUE))) {; - DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); - break; - } - PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); - data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; - - /* Write test header cmd and extra based on mode */ - switch (bus->pktgen_mode) { - case DHD_PKTGEN_ECHO: - *data++ = SDPCM_TEST_ECHOREQ; - *data++ = (uint8)bus->pktgen_sent; - break; - - case DHD_PKTGEN_SEND: - *data++ = SDPCM_TEST_DISCARD; - *data++ = (uint8)bus->pktgen_sent; - break; - - case DHD_PKTGEN_RXBURST: - *data++ = SDPCM_TEST_BURST; - *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */ - break; - - default: - DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode)); - PKTFREE(osh, pkt, TRUE); - bus->pktgen_count = 0; - return; - } - - /* Write test header length field */ - *data++ = (bus->pktgen_len >> 0); - *data++ = (bus->pktgen_len >> 8); - - /* Write frame count in a 4 byte field adjucent to SDPCM test header for - * burst mode - */ - if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { - *data++ = (uint8)(bus->pktgen_count >> 0); - *data++ = (uint8)(bus->pktgen_count >> 8); - *data++ = (uint8)(bus->pktgen_count >> 16); - *data++ = (uint8)(bus->pktgen_count >> 24); - } else { - - /* Then fill in the remainder -- N/A for burst */ - for (fillbyte = 0; fillbyte < len; fillbyte++) - *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); - } - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; - prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN); - } -#endif - - /* Send it */ - if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) { - bus->pktgen_fail++; - if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) - bus->pktgen_count = 0; - } - bus->pktgen_sent++; - - /* Bump length if not fixed, wrap at max */ - if (++bus->pktgen_len > bus->pktgen_maxlen) - bus->pktgen_len = (uint16)bus->pktgen_minlen; - - /* Special case for burst mode: just send one request! */ - if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) - break; - } -} - -static void -dhdsdio_sdtest_set(dhd_bus_t *bus, uint count) -{ - void *pkt; - uint8 *data; - osl_t *osh = bus->dhd->osh; - - /* Allocate the packet */ - if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + - SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) { - DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); - return; - } - PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + - SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN); - data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; - - /* Fill in the test header */ - *data++ = SDPCM_TEST_SEND; - *data++ = (count > 0)?TRUE:FALSE; - *data++ = (bus->pktgen_maxlen >> 0); - *data++ = (bus->pktgen_maxlen >> 8); - *data++ = (uint8)(count >> 0); - *data++ = (uint8)(count >> 8); - *data++ = (uint8)(count >> 16); - *data++ = (uint8)(count >> 24); - - /* Send it */ - if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) - bus->pktgen_fail++; -} - - -static void -dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) -{ - osl_t *osh = bus->dhd->osh; - uint8 *data; - uint pktlen; - - uint8 cmd; - uint8 extra; - uint16 len; - uint16 offset; - - /* Check for min length */ - if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) { - DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen)); - PKTFREE(osh, pkt, FALSE); - return; - } - - /* Extract header fields */ - data = PKTDATA(osh, pkt); - cmd = *data++; - extra = *data++; - len = *data++; len += *data++ << 8; - DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len)); - /* Check length for relevant commands */ - if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { - if (pktlen != len + SDPCM_TEST_HDRLEN) { - DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d" - " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); - PKTFREE(osh, pkt, FALSE); - return; - } - } - - /* Process as per command */ - switch (cmd) { - case SDPCM_TEST_ECHOREQ: - /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ - *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; - if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) { - bus->pktgen_sent++; - } else { - bus->pktgen_fail++; - PKTFREE(osh, pkt, FALSE); - } - bus->pktgen_rcvd++; - break; - - case SDPCM_TEST_ECHORSP: - if (bus->ext_loop) { - PKTFREE(osh, pkt, FALSE); - bus->pktgen_rcvd++; - break; - } - - for (offset = 0; offset < len; offset++, data++) { - if (*data != SDPCM_TEST_FILL(offset, extra)) { - DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: " - "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n", - offset, len, SDPCM_TEST_FILL(offset, extra), *data)); - break; - } - } - PKTFREE(osh, pkt, FALSE); - bus->pktgen_rcvd++; - break; - - case SDPCM_TEST_DISCARD: - { - int i = 0; - uint8 *prn = data; - uint8 testval = extra; - for (i = 0; i < len; i++) { - if (*prn != testval) { - DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", - i, bus->pktgen_rcvd_rcvsession, testval, *prn)); - prn++; testval++; - } - } - } - PKTFREE(osh, pkt, FALSE); - bus->pktgen_rcvd++; - break; - - case SDPCM_TEST_BURST: - case SDPCM_TEST_SEND: - default: - DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d" - " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); - PKTFREE(osh, pkt, FALSE); - break; - } - - /* For recv mode, stop at limit (and tell dongle to stop sending) */ - if (bus->pktgen_mode == DHD_PKTGEN_RECV) { - if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { - bus->pktgen_rcvd_rcvsession++; - - if (bus->pktgen_total && - (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { - bus->pktgen_count = 0; - DHD_ERROR(("Pktgen:rcv test complete!\n")); - bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; - dhdsdio_sdtest_set(bus, FALSE); - bus->pktgen_rcvd_rcvsession = 0; - } - } - } -} -#endif /* SDTEST */ - -int dhd_bus_oob_intr_register(dhd_pub_t *dhdp) -{ - int err = 0; - -#if defined(OOB_INTR_ONLY) - err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus); -#endif - return err; -} - -void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp) -{ -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_unregister(dhdp->bus->sdh); -#endif -} - -void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable) -{ -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(dhdp->bus->sdh, enable); -#endif -} - -void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub) -{ - bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh); -} - -void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub) -{ - bcmsdh_dev_relax(dhdpub->bus->sdh); -} - -bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub) -{ - bool enabled = FALSE; - - enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh); - return enabled; -} - -extern bool -dhd_bus_watchdog(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus; - - DHD_TIMER(("%s: Enter\n", __FUNCTION__)); - - bus = dhdp->bus; - - if (bus->dhd->dongle_reset) - return FALSE; - - if (bus->dhd->hang_was_sent) { - dhd_os_wd_timer(bus->dhd, 0); - return FALSE; - } - - /* Ignore the timer if simulating bus down */ - if (!SLPAUTO_ENAB(bus) && bus->sleeping) - return FALSE; - - if (dhdp->busstate == DHD_BUS_DOWN) - return FALSE; - - /* Poll period: check device if appropriate. */ - if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) { - uint32 intstatus = 0; - - /* Reset poll tick */ - bus->polltick = 0; - - /* Check device if no interrupts */ - if (!bus->intr || (bus->intrcount == bus->lastintrs)) { - - if (!bus->dpc_sched) { - uint8 devpend; - devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, - SDIOD_CCCR_INTPEND, 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; - if (bus->intr) { - bcmsdh_intr_disable(bus->sdh); - } - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - } - - /* Update interrupt tracking */ - bus->lastintrs = bus->intrcount; - } - -#ifdef DHD_DEBUG - /* Poll for console output periodically */ - if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { - bus->console.count += dhd_watchdog_ms; - if (bus->console.count >= dhd_console_ms) { - bus->console.count -= dhd_console_ms; - /* Make sure backplane clock is on */ - if (SLPAUTO_ENAB(bus)) - dhdsdio_bussleep(bus, FALSE); - else - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (dhdsdio_readconsole(bus) < 0) - dhd_console_ms = 0; /* On error, stop trying */ - } - } -#endif /* DHD_DEBUG */ - -#ifdef SDTEST - /* Generate packets if configured */ - if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { - /* Make sure backplane clock is on */ - if (SLPAUTO_ENAB(bus)) - dhdsdio_bussleep(bus, FALSE); - else - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - bus->pktgen_tick = 0; - dhdsdio_pktgen(bus); - } -#endif - - /* On idle timeout clear activity flag and/or turn off clock */ -#ifdef DHD_USE_IDLECOUNT - if (bus->activity) - bus->activity = FALSE; - else { - bus->idlecount++; - - if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) { - DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); - if (SLPAUTO_ENAB(bus)) { - if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) - dhd_os_wd_timer(bus->dhd, 0); - } else - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - - bus->idlecount = 0; - } - } -#else - if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { - if (++bus->idlecount >= bus->idletime) { - bus->idlecount = 0; - if (bus->activity) { - bus->activity = FALSE; - if (SLPAUTO_ENAB(bus)) { - if (!bus->readframes) - dhdsdio_bussleep(bus, TRUE); - else - bus->reqbussleep = TRUE; - } - else - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - } - } - } -#endif /* DHD_USE_IDLECOUNT */ - - return bus->ipend; -} - -#ifdef DHD_DEBUG -extern int -dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) -{ - dhd_bus_t *bus = dhdp->bus; - uint32 addr, val; - int rv; - void *pkt; - - /* Address could be zero if CONSOLE := 0 in dongle Makefile */ - if (bus->console_addr == 0) - return BCME_UNSUPPORTED; - - /* Exclusive bus access */ - dhd_os_sdlock(bus->dhd); - - /* Don't allow input if dongle is in reset */ - if (bus->dhd->dongle_reset) { - dhd_os_sdunlock(bus->dhd); - return BCME_NOTREADY; - } - - /* Request clock to allow SDIO accesses */ - BUS_WAKE(bus); - /* No pend allowed since txpkt is called later, ht clk has to be on */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Zero cbuf_index */ - addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx); - val = htol32(0); - if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) - goto done; - - /* Write message into cbuf */ - addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf); - if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) - goto done; - - /* Write length into vcons_in */ - addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in); - val = htol32(msglen); - if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) - goto done; - - /* Bump dongle by sending an empty packet on the event channel. - * sdpcm_sendup (RX) checks for virtual console input. - */ - if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) - rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE); - -done: - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - - return rv; -} -#endif /* DHD_DEBUG */ - -#ifdef DHD_DEBUG -static void -dhd_dump_cis(uint fn, uint8 *cis) -{ - uint byte, tag, tdata; - DHD_INFO(("Function %d CIS:\n", fn)); - - for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { - if ((byte % 16) == 0) - DHD_INFO((" ")); - DHD_INFO(("%02x ", cis[byte])); - if ((byte % 16) == 15) - DHD_INFO(("\n")); - if (!tdata--) { - tag = cis[byte]; - if (tag == 0xff) - break; - else if (!tag) - tdata = 0; - else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) - tdata = cis[byte + 1] + 1; - else - DHD_INFO(("]")); - } - } - if ((byte % 16) != 15) - DHD_INFO(("\n")); -} -#endif /* DHD_DEBUG */ - -static bool -dhdsdio_chipmatch(uint16 chipid) -{ - if (chipid == BCM4325_CHIP_ID) - return TRUE; - if (chipid == BCM4329_CHIP_ID) - return TRUE; - if (chipid == BCM4315_CHIP_ID) - return TRUE; - if (chipid == BCM4319_CHIP_ID) - return TRUE; - if (chipid == BCM4336_CHIP_ID) - return TRUE; - if (chipid == BCM4330_CHIP_ID) - return TRUE; - if (chipid == BCM43237_CHIP_ID) - return TRUE; - if (chipid == BCM43362_CHIP_ID) - return TRUE; - if (chipid == BCM4314_CHIP_ID) - return TRUE; - if (chipid == BCM43242_CHIP_ID) - return TRUE; - if (chipid == BCM43340_CHIP_ID) - return TRUE; - if (chipid == BCM43341_CHIP_ID) - return TRUE; - if (chipid == BCM43143_CHIP_ID) - return TRUE; - if (chipid == BCM43342_CHIP_ID) - return TRUE; - if (chipid == BCM4334_CHIP_ID) - return TRUE; - if (chipid == BCM43239_CHIP_ID) - return TRUE; - if (chipid == BCM4324_CHIP_ID) - return TRUE; - if (chipid == BCM4335_CHIP_ID) - return TRUE; - if (chipid == BCM4339_CHIP_ID) - return TRUE; - if (chipid == BCM43349_CHIP_ID) - return TRUE; - if (chipid == BCM4345_CHIP_ID || chipid == BCM43454_CHIP_ID) - return TRUE; - if (chipid == BCM4350_CHIP_ID) - return TRUE; - if (chipid == BCM4354_CHIP_ID) - return TRUE; - if (chipid == BCM4356_CHIP_ID) - return TRUE; - if (chipid == BCM43430_CHIP_ID) - return TRUE; - return FALSE; -} - -static void * -dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, - uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) -{ - int ret; - dhd_bus_t *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. - */ - dhd_txbound = DHD_TXBOUND; - dhd_rxbound = DHD_RXBOUND; - dhd_alignctl = TRUE; - sd1idle = TRUE; - dhd_readahead = TRUE; - retrydata = FALSE; - - dhd_doflow = FALSE; - dhd_dongle_ramsize = 0; - dhd_txminmax = DHD_TXMINMAX; - - forcealign = TRUE; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid)); - - /* We make assumptions about address window mappings */ - ASSERT((uintptr)regsva == SI_ENUM_BASE); - - /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start - * means early parse could fail, so here we should get either an ID - * we recognize OR (-1) indicating we must request power first. - */ - /* Check the Vendor ID */ - switch (venid) { - case 0x0000: - case VENDOR_BROADCOM: - break; - default: - DHD_ERROR(("%s: unknown vendor: 0x%04x\n", - __FUNCTION__, venid)); - goto forcereturn; - } - - /* Check the Device ID and make sure it's one that we support */ - switch (devid) { - case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */ - case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */ - case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */ - DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__)); - break; - case BCM4329_D11N_ID: /* 4329 802.11n dualband device */ - case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */ - case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */ - case 0x4329: - DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__)); - break; - case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */ - case BCM4315_D11G_ID: /* 4315 802.11g id */ - case BCM4315_D11A_ID: /* 4315 802.11a id */ - DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__)); - break; - case BCM4319_D11N_ID: /* 4319 802.11n id */ - case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ - case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ - DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__)); - break; - case 0: - DHD_INFO(("%s: allow device id 0, will check chip internals\n", - __FUNCTION__)); - break; - - default: - DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", - __FUNCTION__, venid, devid)); - goto forcereturn; - } - - if (osh == NULL) { - DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__)); - goto forcereturn; - } - - /* Allocate private bus interface state */ - if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { - DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); - goto fail; - } - bzero(bus, sizeof(dhd_bus_t)); - bus->sdh = sdh; - bus->cl_devid = (uint16)devid; - bus->bus = DHD_BUS; - bus->bus_num = bus_no; - bus->slot_num = slot; - bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; - bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */ - -#if defined(SUPPORT_P2P_GO_PS) - init_waitqueue_head(&bus->bus_sleep); -#endif /* LINUX && SUPPORT_P2P_GO_PS */ - - /* attempt to attach to the dongle */ - if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { - DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__)); - goto fail; - } - - /* Attach to the dhd/OS/network interface */ - if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) { - DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); - goto fail; - } - - /* Allocate buffers */ - if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { - DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__)); - goto fail; - } - - if (!(dhdsdio_probe_init(bus, osh, sdh))) { - DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__)); - goto fail; - } - - if (bus->intr) { - /* Register interrupt callback, but mask it (not operational yet). */ - DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__)); - bcmsdh_intr_disable(sdh); - if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { - DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n", - __FUNCTION__, ret)); - goto fail; - } - DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__)); - } else { - DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n", - __FUNCTION__)); - } - - DHD_INFO(("%s: completed!!\n", __FUNCTION__)); - - /* if firmware path present try to download and bring up bus */ - bus->dhd->hang_report = TRUE; - if (dhd_download_fw_on_driverload) { - if ((ret = dhd_bus_start(bus->dhd)) != 0) { - DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); - goto fail; - } - } - /* Ok, have the per-port tell the stack we're open for business */ - if (dhd_register_if(bus->dhd, 0, TRUE) != 0) { - DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); - goto fail; - } - - - return bus; - -fail: - dhdsdio_release(bus, osh); - -forcereturn: - - return NULL; -} - -static bool -dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, - uint16 devid) -{ - int err = 0; - uint8 clkctl = 0; - - bus->alp_only = TRUE; - bus->sih = NULL; - - /* Return the window to backplane enumeration space for core access */ - if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) { - DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__)); - } - - - /* Force PLL off until si_attach() programs PLL control regs */ - - - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err); - if (!err) - clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - - if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) { - DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", - err, DHD_INIT_CLKCTL1, clkctl)); - goto fail; - } - -#ifdef DHD_DEBUG - if (DHD_INFO_ON()) { - uint fn, numfn; - uint8 *cis[SDIOD_MAX_IOFUNCS]; - int err = 0; - - numfn = bcmsdh_query_iofnum(sdh); - ASSERT(numfn <= SDIOD_MAX_IOFUNCS); - - /* Make sure ALP is available before trying to read CIS */ - SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, NULL)), - !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY); - - /* Now request ALP be put on the bus */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - DHD_INIT_CLKCTL2, &err); - OSL_DELAY(65); - - for (fn = 0; fn <= numfn; fn++) { - if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { - DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn)); - break; - } - bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); - - if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) { - DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err)); - MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); - break; - } - dhd_dump_cis(fn, cis[fn]); - } - - while (fn-- > 0) { - ASSERT(cis[fn]); - MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); - } - - if (err) { - DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n")); - goto fail; - } - } -#endif /* DHD_DEBUG */ - - /* si_attach() will provide an SI handle and scan the backplane */ - if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, - &bus->vars, &bus->varsz))) { - DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); - goto fail; - } - -#ifdef DHD_DEBUG - DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n", - bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg)); -#endif /* DHD_DEBUG */ - - - bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); - - if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { - DHD_ERROR(("%s: unsupported chip: 0x%04x\n", - __FUNCTION__, bus->sih->chip)); - goto fail; - } - - if (bus->sih->buscorerev >= 12) - dhdsdio_clk_kso_init(bus); - else - bus->kso = TRUE; - - if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) { - } - - si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); - - - /* Get info on the ARM and SOCRAM cores... */ - if (!DHD_NOPMU(bus)) { - if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || - (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || - (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { - bus->armrev = si_corerev(bus->sih); - } else { - DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); - goto fail; - } - - if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { - DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); - goto fail; - } - } else { - /* cr4 has a different way to find the RAM size from TCM's */ - if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { - DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); - goto fail; - } - /* also populate base address */ - switch ((uint16)bus->sih->chip) { - case BCM4335_CHIP_ID: - case BCM4339_CHIP_ID: - case BCM43349_CHIP_ID: - bus->dongle_ram_base = CR4_4335_RAM_BASE; - break; - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM4356_CHIP_ID: - bus->dongle_ram_base = CR4_4350_RAM_BASE; - break; - case BCM4360_CHIP_ID: - bus->dongle_ram_base = CR4_4360_RAM_BASE; - break; - case BCM4345_CHIP_ID: - case BCM43454_CHIP_ID: - bus->dongle_ram_base = (bus->sih->chiprev < 6) /* from 4345C0 */ - ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE; - break; - default: - bus->dongle_ram_base = 0; - DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", - __FUNCTION__, bus->dongle_ram_base)); - } - } - bus->ramsize = bus->orig_ramsize; - if (dhd_dongle_ramsize) - dhd_dongle_setramsize(bus, dhd_dongle_ramsize); - - DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", - bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); - - bus->srmemsize = si_socram_srmem_size(bus->sih); - } - - /* ...but normally deal with the SDPCMDEV core */ - if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) && - !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) { - DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__)); - goto fail; - } - bus->sdpcmrev = si_corerev(bus->sih); - - /* Set core control so an SDIO reset does a backplane reset */ - OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); - bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; - - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && - (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) - { - uint32 val; - - val = R_REG(osh, &bus->regs->corecontrol); - val &= ~CC_XMTDATAAVAIL_MODE; - val |= CC_XMTDATAAVAIL_CTRL; - W_REG(osh, &bus->regs->corecontrol, val); - } - - - pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); - - /* Locate an appropriately-aligned portion of hdrbuf */ - bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); - - /* Set the poll and/or interrupt flags */ - bus->intr = (bool)dhd_intr; - if ((bus->poll = (bool)dhd_poll)) - bus->pollrate = 1; - - /* Setting default Glom size */ - bus->txglomsize = SDPCM_DEFGLOM_SIZE; - - return TRUE; - -fail: - if (bus->sih != NULL) { - si_detach(bus->sih); - bus->sih = NULL; - } - return FALSE; -} - -static bool -dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->maxctl) { - bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; - if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) { - DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", - __FUNCTION__, bus->rxblen)); - goto fail; - } - } - /* Allocate buffer to receive glomed packet */ - if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { - DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", - __FUNCTION__, MAX_DATA_BUF)); - /* release rxbuf which was already located as above */ - if (!bus->rxblen) - DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen); - goto fail; - } - - /* Align the buffer */ - if ((uintptr)bus->databuf % DHD_SDALIGN) - bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN)); - else - bus->dataptr = bus->databuf; - - return TRUE; - -fail: - return FALSE; -} - -static bool -dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) -{ - int32 fnum; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bus->_srenab = FALSE; - -#ifdef SDTEST - dhdsdio_pktgen_init(bus); -#endif /* SDTEST */ - - /* Disable F2 to clear any intermediate frame state on the dongle */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); - - bus->dhd->busstate = DHD_BUS_DOWN; - bus->sleeping = FALSE; - bus->rxflow = FALSE; - bus->prev_rxlim_hit = 0; - - /* Done with backplane-dependent accesses, can drop clock... */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); - - /* ...and initialize clock/power states */ - bus->clkstate = CLK_SDONLY; - bus->idletime = (int32)dhd_idletime; - bus->idleclock = DHD_IDLE_ACTIVE; - - /* Query the SD clock speed */ - if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, - &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor")); - bus->sd_divisor = -1; - } else { - DHD_INFO(("%s: Initial value for %s is %d\n", - __FUNCTION__, "sd_divisor", bus->sd_divisor)); - } - - /* Query the SD bus mode */ - if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, - &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode")); - bus->sd_mode = -1; - } else { - DHD_INFO(("%s: Initial value for %s is %d\n", - __FUNCTION__, "sd_mode", bus->sd_mode)); - } - - /* Query the F2 block size, set roundup accordingly */ - fnum = 2; - if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32), - &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { - bus->blocksize = 0; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); - } else { - DHD_INFO(("%s: Initial value for %s is %d\n", - __FUNCTION__, "sd_blocksize", bus->blocksize)); - - dhdsdio_tune_fifoparam(bus); - } - bus->roundup = MIN(max_roundup, bus->blocksize); - - if (bus->pad_pkt) - PKTFREE(osh, bus->pad_pkt, FALSE); - bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE); - if (bus->pad_pkt == NULL) - DHD_ERROR(("failed to allocate padding packet\n")); - else { - int alignment_offset = 0; - uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt); - if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN))) - PKTPUSH(osh, bus->pad_pkt, alignment_offset); - PKTSETNEXT(osh, bus->pad_pkt, NULL); - } - - /* Query if bus module supports packet chaining, default to use if supported */ - if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, - &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) { - bus->sd_rxchain = FALSE; - } else { - DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n", - __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support"))); - } - bus->use_rxchain = (bool)bus->sd_rxchain; - bus->txinrx_thres = CUSTOM_TXINRX_THRES; - /* TX first in dhdsdio_readframes() */ - bus->dotxinrx = TRUE; -#if defined(CUSTOMER_HW5) - memset(bus->dpc_log_previous, 0, sizeof(bus->dpc_log_previous)); - memset(bus->dpc_log_current, 0, sizeof(bus->dpc_log_current)); - bus->dpc_log_loops = 0; -#endif /* CUSTOMER_HW5 */ - - return TRUE; -} - -int -dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, - char *pfw_path, char *pnv_path) -{ - int ret; - - bus->fw_path = pfw_path; - bus->nv_path = pnv_path; - - ret = dhdsdio_download_firmware(bus, osh, bus->sdh); - - - return ret; -} - -static int -dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) -{ - int ret; - - - DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n", - __FUNCTION__, bus->fw_path, bus->nv_path)); - DHD_OS_WAKE_LOCK(bus->dhd); - - /* Download the firmware */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - ret = _dhdsdio_download_firmware(bus); - - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - DHD_OS_WAKE_UNLOCK(bus->dhd); - return ret; -} - -/* Detach and free everything */ -static void -dhdsdio_release(dhd_bus_t *bus, osl_t *osh) -{ - bool dongle_isolation = FALSE; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus) { - ASSERT(osh); - - if (bus->dhd) { - dongle_isolation = bus->dhd->dongle_isolation; - dhd_detach(bus->dhd); - } - - /* De-register interrupt handler */ - bcmsdh_intr_disable(bus->sdh); - bcmsdh_intr_dereg(bus->sdh); - - if (bus->dhd) { - dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); - dhd_free(bus->dhd); - bus->dhd = NULL; - } - - dhdsdio_release_malloc(bus, osh); - -#ifdef DHD_DEBUG - if (bus->console.buf != NULL) - MFREE(osh, bus->console.buf, bus->console.bufsize); -#endif - - if (bus->pad_pkt) - PKTFREE(osh, bus->pad_pkt, FALSE); - - MFREE(osh, bus, sizeof(dhd_bus_t)); - } - - DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -} - -static void -dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd && bus->dhd->dongle_reset) - return; - - if (bus->rxbuf) { -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(osh, bus->rxbuf, bus->rxblen); -#endif - bus->rxctl = bus->rxbuf = NULL; - bus->rxlen = 0; - } - - if (bus->databuf) { -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(osh, bus->databuf, MAX_DATA_BUF); -#endif - bus->databuf = NULL; - } - - if (bus->vars && bus->varsz) { - MFREE(osh, bus->vars, bus->varsz); - bus->vars = NULL; - } - -} - - -static void -dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) -{ - DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, - bus->dhd, bus->dhd->dongle_reset)); - - if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) - return; - - if (bus->sih) { -#if !defined(BCMLXSDMMC) - if (bus->dhd) { - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - } - if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) - si_watchdog(bus->sih, 4); -#endif /* !defined(BCMLXSDMMC) */ - if (bus->dhd) { - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - } - si_detach(bus->sih); - bus->sih = NULL; - if (bus->vars && bus->varsz) - MFREE(osh, bus->vars, bus->varsz); - bus->vars = NULL; - } - - DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -} - -static void -dhdsdio_disconnect(void *ptr) -{ - dhd_bus_t *bus = (dhd_bus_t *)ptr; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - - - if (bus) { - ASSERT(bus->dhd); - dhdsdio_release(bus, bus->dhd->osh); - } - - - - DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -} - -static int -dhdsdio_suspend(void *context) -{ - int ret = 0; - - dhd_bus_t *bus = (dhd_bus_t*)context; -#ifdef SUPPORT_P2P_GO_PS - int wait_time = 0; - - if (bus->idletime > 0) { - wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms); - } -#endif /* SUPPORT_P2P_GO_PS */ - ret = dhd_os_check_wakelock(bus->dhd); -#ifdef SUPPORT_P2P_GO_PS - if ((!ret) && (bus->dhd->up) && (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) { - if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) { - if (!bus->sleeping) { - return 1; - } - } - } -#endif /* SUPPORT_P2P_GO_PS */ - return ret; -} - -static int -dhdsdio_resume(void *context) -{ -#if defined(OOB_INTR_ONLY) - dhd_bus_t *bus = (dhd_bus_t*)context; - - if (dhd_os_check_if_up(bus->dhd)) - bcmsdh_oob_intr_set(bus->sdh, TRUE); -#endif - return 0; -} - - -/* Register/Unregister functions are called by the main DHD entry - * point (e.g. module insertion) to link with the bus driver, in - * order to look for or await the device. - */ - -static bcmsdh_driver_t dhd_sdio = { - dhdsdio_probe, - dhdsdio_disconnect, - dhdsdio_suspend, - dhdsdio_resume -}; - -int -dhd_bus_register(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - return bcmsdh_register(&dhd_sdio); -} - -void -dhd_bus_unregister(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bcmsdh_unregister(); -} - -#if defined(BCMLXSDMMC) -/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ -int dhd_bus_reg_sdio_notify(void* semaphore) -{ - return bcmsdh_reg_sdio_notify(semaphore); -} - -void dhd_bus_unreg_sdio_notify(void) -{ - bcmsdh_unreg_sdio_notify(); -} -#endif /* defined(BCMLXSDMMC) */ - -#ifdef BCMEMBEDIMAGE -static int -dhdsdio_download_code_array(struct dhd_bus *bus) -{ - int bcmerror = -1; - int offset = 0; - unsigned char *ularray = NULL; - - DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__)); - - /* Download image */ - while ((offset + MEMBLOCK) < sizeof(dlarray)) { - /* check if CR4 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - /* if address is 0, store the reset instruction to be written in 0 */ - - if (offset == 0) { - bus->resetinstr = *(((uint32*)dlarray)); - /* Add start of RAM address to the address given by user */ - offset += bus->dongle_ram_base; - } - } - - bcmerror = dhdsdio_membytes(bus, TRUE, offset, - (uint8 *) (dlarray + offset), MEMBLOCK); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - - if (offset < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, TRUE, offset, - (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); - goto err; - } - } - -#ifdef DHD_DEBUG - /* Upload and compare the downloaded code */ - { - ularray = MALLOC(bus->dhd->osh, bus->ramsize); - /* Upload image to verify downloaded contents. */ - offset = 0; - memset(ularray, 0xaa, bus->ramsize); - while ((offset + MEMBLOCK) < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - - if (offset < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, FALSE, offset, - ularray + offset, sizeof(dlarray) - offset); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); - goto err; - } - } - - if (memcmp(dlarray, ularray, sizeof(dlarray))) { - DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", - __FUNCTION__, dlimagename, dlimagever, dlimagedate)); - goto err; - } else - DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", - __FUNCTION__, dlimagename, dlimagever, dlimagedate)); - - } -#endif /* DHD_DEBUG */ - -err: - if (ularray) - MFREE(bus->dhd->osh, ularray, bus->ramsize); - return bcmerror; -} -#endif /* BCMEMBEDIMAGE */ - -static int -dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) -{ - int bcmerror = -1; - int offset = 0; - int len; - void *image = NULL; - uint8 *memblock = NULL, *memptr; - - DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); - - image = dhd_os_open_image(pfw_path); - if (image == NULL) - goto err; - - memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); - goto err; - } - if ((uint32)(uintptr)memblock % DHD_SDALIGN) - memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); - - /* Download image */ - while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { - if (len < 0) { - DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); - bcmerror = BCME_ERROR; - goto err; - } - /* check if CR4 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - /* if address is 0, store the reset instruction to be written in 0 */ - - if (offset == 0) { - bus->resetinstr = *(((uint32*)memptr)); - /* Add start of RAM address to the address given by user */ - offset += bus->dongle_ram_base; - } - } - - bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - -err: - if (memblock) - MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); - - if (image) - dhd_os_close_image(image); - - return bcmerror; -} - -/* - EXAMPLE: nvram_array - nvram_arry format: - name=value - Use carriage return at the end of each assignment, and an empty string with - carriage return at the end of array. - - For example: - unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"}; - Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx. - - Search "EXAMPLE: nvram_array" to see how the array is activated. -*/ - -void -dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params) -{ - bus->nvram_params = nvram_params; -} - -static int -dhdsdio_download_nvram(struct dhd_bus *bus) -{ - int bcmerror = -1; - uint len; - void * image = NULL; - char * memblock = NULL; - char *bufp; - char *pnv_path; - bool nvram_file_exists; - - pnv_path = bus->nv_path; - - nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); - if (!nvram_file_exists && (bus->nvram_params == NULL)) - return (0); - - if (nvram_file_exists) { - image = dhd_os_open_image(pnv_path); - if (image == NULL) - goto err; - } - - memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, MAX_NVRAMBUF_SIZE)); - goto err; - } - - /* Download variables */ - if (nvram_file_exists) { - len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); - } - else { - len = strlen(bus->nvram_params); - ASSERT(len <= MAX_NVRAMBUF_SIZE); - memcpy(memblock, bus->nvram_params, len); - } - if (len > 0 && len < MAX_NVRAMBUF_SIZE) { - bufp = (char *)memblock; - bufp[len] = 0; - - if (somc_txpower_calibrate(memblock, len) != BCME_OK) { - DHD_ERROR(("%s: error calibrating tx power\n", __FUNCTION__)); - goto err; - } - - len = process_nvram_vars(bufp, len); - if (len % 4) { - len += 4 - (len % 4); - } - bufp += len; - *bufp++ = 0; - if (len) - bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1); - if (bcmerror) { - DHD_ERROR(("%s: error downloading vars: %d\n", - __FUNCTION__, bcmerror)); - } - } - else { - DHD_ERROR(("%s: error reading nvram file: %d\n", - __FUNCTION__, len)); - bcmerror = BCME_SDIO_ERROR; - } - -err: - if (memblock) - MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); - - if (image) - dhd_os_close_image(image); - - return bcmerror; -} - -static int -_dhdsdio_download_firmware(struct dhd_bus *bus) -{ - int bcmerror = -1; - - bool embed = FALSE; /* download embedded firmware */ - bool dlok = FALSE; /* download firmware succeeded */ - - /* Out immediately if no image to download */ - if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { -#ifdef BCMEMBEDIMAGE - embed = TRUE; -#else - return 0; -#endif - } - - /* Keep arm in reset */ - if (dhdsdio_download_state(bus, TRUE)) { - DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); - goto err; - } - - /* External image takes precedence if specified */ - if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { - if (dhdsdio_download_code_file(bus, bus->fw_path)) { - DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); -#ifdef BCMEMBEDIMAGE - embed = TRUE; -#else - goto err; -#endif - } - else { - embed = FALSE; - dlok = TRUE; - } - } - -#ifdef BCMEMBEDIMAGE - if (embed) { - if (dhdsdio_download_code_array(bus)) { - DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); - goto err; - } - else { - dlok = TRUE; - } - } -#else - BCM_REFERENCE(embed); -#endif - if (!dlok) { - DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); - goto err; - } - - /* EXAMPLE: nvram_array */ - /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ - /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ - - /* External nvram takes precedence if specified */ - if (dhdsdio_download_nvram(bus)) { - DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); - goto err; - } - - /* Take arm out of reset */ - if (dhdsdio_download_state(bus, FALSE)) { - DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); - goto err; - } - - bcmerror = 0; - -err: - return bcmerror; -} - -static int -dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) -{ - int status; - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return BCME_NODEVICE; - } - - status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle); - - return status; -} - -static int -dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry) -{ - int ret; - int i = 0; - int retries = 0; - bcmsdh_info_t *sdh; - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return BCME_NODEVICE; - } - - sdh = bus->sdh; - do { - ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, - pkt, complete, handle); - - bus->f2txdata++; - ASSERT(ret != BCME_PENDING); - - if (ret == BCME_NODEVICE) { - DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); - } else if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n", - __FUNCTION__, ret)); - bus->tx_sderrs++; - bus->f1regdata++; - bus->dhd->tx_errors++; - bcmsdh_abort(sdh, SDIO_FUNC_2); - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - for (i = 0; i < READ_FRM_CNT_RETRIES; i++) { - uint8 hi, lo; - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI, - NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO, - NULL); - bus->f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - } - } while ((ret < 0) && retrydata && ++retries < max_retry); - - return ret; -} - -uint -dhd_bus_chip(struct dhd_bus *bus) -{ - ASSERT(bus->sih != NULL); - return bus->sih->chip; -} - -uint -dhd_bus_chiprev(struct dhd_bus *bus) -{ - ASSERT(bus); - ASSERT(bus->sih != NULL); - return bus->sih->chiprev; -} - -void * -dhd_bus_pub(struct dhd_bus *bus) -{ - return bus->dhd; -} - -void * -dhd_bus_sih(struct dhd_bus *bus) -{ - return (void *)bus->sih; -} - -void * -dhd_bus_txq(struct dhd_bus *bus) -{ - return &bus->txq; -} - -void -dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val) -{ - bus->dotxinrx = val; -} - -int -dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) -{ - int bcmerror = 0; - dhd_bus_t *bus; - - bus = dhdp->bus; - - if (flag == TRUE) { - if (!bus->dhd->dongle_reset) { - dhd_os_sdlock(dhdp); - dhd_os_wd_timer(dhdp, 0); -#if !defined(IGNORE_ETH0_DOWN) - /* Force flow control as protection when stop come before ifconfig_down */ - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); -#endif /* !defined(IGNORE_ETH0_DOWN) */ - /* Expect app to have torn down any connection before calling */ - /* Stop the bus, disable F2 */ - dhd_bus_stop(bus, FALSE); - -#if defined(OOB_INTR_ONLY) - /* Clean up any pending IRQ */ - dhd_enable_oob_intr(bus, FALSE); - bcmsdh_oob_intr_set(bus->sdh, FALSE); - bcmsdh_oob_intr_unregister(bus->sdh); -#endif - - /* Clean tx/rx buffer pointers, detach from the dongle */ - dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); - - bus->dhd->dongle_reset = TRUE; - bus->dhd->up = FALSE; - dhd_txglom_enable(dhdp, FALSE); - dhd_os_sdunlock(dhdp); - - DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); - /* App can now remove power from device */ - } else - bcmerror = BCME_SDIO_ERROR; - } else { - /* App must have restored power to device before calling */ - - DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) { - /* Turn on WLAN */ - dhd_os_sdlock(dhdp); - /* Reset SD client */ - bcmsdh_reset(bus->sdh); - - /* Attempt to re-attach & download */ - if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh, - (uint32 *)SI_ENUM_BASE, - bus->cl_devid)) { - /* Attempt to download binary to the dongle */ - if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) && - dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) { - - /* Re-init bus, enable F2 transfer */ - bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); - if (bcmerror == BCME_OK) { -#if defined(OOB_INTR_ONLY) - dhd_enable_oob_intr(bus, TRUE); - bcmsdh_oob_intr_register(bus->sdh, - dhdsdio_isr, bus); - bcmsdh_oob_intr_set(bus->sdh, TRUE); -#endif - - bus->dhd->dongle_reset = FALSE; - bus->dhd->up = TRUE; - -#if !defined(IGNORE_ETH0_DOWN) - /* Restore flow control */ - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); -#endif - dhd_os_wd_timer(dhdp, dhd_watchdog_ms); - - DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); - } else { - dhd_bus_stop(bus, FALSE); - dhdsdio_release_dongle(bus, bus->dhd->osh, - TRUE, FALSE); - } - } else - bcmerror = BCME_SDIO_ERROR; - } else - bcmerror = BCME_SDIO_ERROR; - - dhd_os_sdunlock(dhdp); - } else { - bcmerror = BCME_SDIO_ERROR; - DHD_INFO(("%s called when dongle is not in reset\n", - __FUNCTION__)); - DHD_INFO(("Will call dhd_bus_start instead\n")); - dhd_bus_resume(dhdp, 1); - if ((bcmerror = dhd_bus_start(dhdp)) != 0) - DHD_ERROR(("%s: dhd_bus_start fail with %d\n", - __FUNCTION__, bcmerror)); - } - } - return bcmerror; -} - -int dhd_bus_suspend(dhd_pub_t *dhdpub) -{ - return bcmsdh_stop(dhdpub->bus->sdh); -} - -int dhd_bus_resume(dhd_pub_t *dhdpub, int stage) -{ - return bcmsdh_start(dhdpub->bus->sdh, stage); -} - -/* Get Chip ID version */ -uint dhd_bus_chip_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - - return bus->sih->chip; -} - -/* Get Chip Rev ID version */ -uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - - return bus->sih->chiprev; -} - -/* Get Chip Pkg ID version */ -uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - - return bus->sih->chippkg; -} - -int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num) -{ - *bus_type = bus->bus; - *bus_num = bus->bus_num; - *slot_num = bus->slot_num; - return 0; -} - -int -dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) -{ - dhd_bus_t *bus; - - bus = dhdp->bus; - return dhdsdio_membytes(bus, set, address, data, size); -} - - -void -dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path) -{ - bus->fw_path = pfw_path; - bus->nv_path = pnv_path; -} - -int -dhd_enableOOB(dhd_pub_t *dhd, bool sleep) -{ - dhd_bus_t *bus = dhd->bus; - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - - if (sleep) { - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - /* Tell device to start using OOB wakeup */ - W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); - if (retries > retry_limit) { - DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); - return BCME_BUSY; - } - /* Turn off our contribution to the HT clock request */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } else { - /* Make sure the controller has the bus up */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Send misc interrupt to indicate OOB not needed */ - W_SDREG(0, ®s->tosbmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); - - /* Make sure we have SD bus access */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - return BCME_OK; -} - -void -dhd_bus_pktq_flush(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - bool wlfc_enabled = FALSE; - -#ifdef PROP_TXSTATUS - wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED); -#endif - if (!wlfc_enabled) { -#ifdef DHDTCPACK_SUPPRESS - /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, - * when there is a newly coming packet from network stack. - */ - dhd_tcpack_info_tbl_clean(bus->dhd); -#endif /* DHDTCPACK_SUPPRESS */ - /* Clear the data packet queues */ - pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0); - } -} - -int -dhd_sr_config(dhd_pub_t *dhd, bool on) -{ - dhd_bus_t *bus = dhd->bus; - - if (!bus->_srenab) - return -1; - - return dhdsdio_clk_devsleep_iovar(bus, on); -} - -uint16 -dhd_get_chipid(dhd_pub_t *dhd) -{ - dhd_bus_t *bus = dhd->bus; - - if (bus && bus->sih) - return (uint16)bus->sih->chip; - else - return 0; -} - -#ifdef DEBUGGER -uint32 dhd_sdio_reg_read(void *h, uint32 addr) -{ - uint32 rval; - struct dhd_bus *bus = (struct dhd_bus *) h; - - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - rval = bcmsdh_reg_read(bus->sdh, addr, 4); - - dhd_os_sdunlock(bus->dhd); - - return rval; -} - -void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val) -{ - struct dhd_bus *bus = (struct dhd_bus *) h; - - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - bcmsdh_reg_write(bus->sdh, addr, 4, val); - - dhd_os_sdunlock(bus->dhd); -} -#endif /* DEBUGGER */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.c deleted file mode 100755 index de106110b05d..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Author: Daisuke Niwa daisuke.x.niwa@sonymobile.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include - -/* miscTA items */ -typedef enum somc_nv_item { - SOMC_TA_TXPWR_2_4G = 0, - SOMC_TA_TXPWR_5G_LOW, - SOMC_TA_TXPWR_5G_MID, - SOMC_TA_TXPWR_5G_HIGH, - SOMC_TA_TXPWR_CO1_2_4G, - SOMC_TA_TXPWR_CO1_5G_LOW, - SOMC_TA_TXPWR_CO1_5G_MID, - SOMC_TA_TXPWR_CO1_5G_HIGH, -} somc_nv_item_t; - -/* Paths to miscTA import files */ -static const char *somc_ta_paths[] = { - "/data/etc/wlan_txpower_2_4g", - "/data/etc/wlan_txpower_5g_low", - "/data/etc/wlan_txpower_5g_mid", - "/data/etc/wlan_txpower_5g_high", - "/data/etc/wlan_txpower_co1_2_4g", - "/data/etc/wlan_txpower_co1_5g_low", - "/data/etc/wlan_txpower_co1_5g_mid", - "/data/etc/wlan_txpower_co1_5g_high", -}; - -#define SOMC_NV_IS_5G(i) (i % 4 == 0 ? 0 : 1) -#define SOMC_NV_GET_CHAIN(i) (i < SOMC_TA_TXPWR_CO1_2_4G ? 0 : 1) - -#define SOMC_MAX_TABUF_SIZE 128 -#define SOMC_TXPWR_BUF_SIZE 7 - -/* Keys used in calibration file for tx power */ -#define SOMC_CKEY_TXPWR_2_4G_11B "cckbw202gpo" -#define SOMC_CKEY_TXPWR_2_4G_11A "dot11agofdmhrbw202gpo" -#define SOMC_CKEY_TXPWR_2_4G_11A_2 "ofdmlrbw202gpo" -#define SOMC_CKEY_TXPWR_2_4G_11N "mcsbw202gpo" -#define SOMC_CKEY_TXPWR_5G_LOW_11A "mcsbw205glpo" -#define SOMC_CKEY_TXPWR_5G_LOW_11N "mcsbw405glpo" -#define SOMC_CKEY_TXPWR_5G_LOW_11AC "mcsbw805glpo" -#define SOMC_CKEY_TXPWR_5G_MID_11A "mcsbw205gmpo" -#define SOMC_CKEY_TXPWR_5G_MID_11N "mcsbw405gmpo" -#define SOMC_CKEY_TXPWR_5G_MID_11AC "mcsbw805gmpo" -#define SOMC_CKEY_TXPWR_5G_HIGH_11A "mcsbw205ghpo" -#define SOMC_CKEY_TXPWR_5G_HIGH_11N "mcsbw405ghpo" -#define SOMC_CKEY_TXPWR_5G_HIGH_11AC "mcsbw805ghpo" - -#define SOMC_TXPWR_MAX 127 -#define SOMC_TXPWR_5G 0x20 - -typedef struct { - char *key; /* Key for tx power (see the definitions above) */ - int len; /* Length of a unit of PPR (not incl. "0x") */ - int offset; /* Offset to PPR */ -} somc_ppr_item_t; - -/* List of ppr item handled by somc_txpower_calibrate() */ -static const somc_ppr_item_t somc_ppr_items[] = { - { SOMC_CKEY_TXPWR_2_4G_11B, 4, 0}, - { SOMC_CKEY_TXPWR_2_4G_11A, 4, 0}, - { SOMC_CKEY_TXPWR_2_4G_11A_2, 4, 2}, - { SOMC_CKEY_TXPWR_2_4G_11N, 8, 0}, - { SOMC_CKEY_TXPWR_5G_LOW_11A, 8, 0}, - { SOMC_CKEY_TXPWR_5G_LOW_11N, 8, 0}, - { SOMC_CKEY_TXPWR_5G_LOW_11AC, 8, 0}, - { SOMC_CKEY_TXPWR_5G_MID_11A, 8, 0}, - { SOMC_CKEY_TXPWR_5G_MID_11N, 8, 0}, - { SOMC_CKEY_TXPWR_5G_MID_11AC, 8, 0}, - { SOMC_CKEY_TXPWR_5G_HIGH_11A, 8, 0}, - { SOMC_CKEY_TXPWR_5G_HIGH_11N, 8, 0}, - { SOMC_CKEY_TXPWR_5G_HIGH_11AC, 8, 0}, -}; - -/* {2.4GHz: {chain0, chain1}, 5GHz: {chain0, chain1}} */ -static int somc_txpower_min_deltas[2][2] = {{0, 0},{0, 0}}; - -static int -somc_txpower_get_min_delta(int band5g, int chain) -{ - int min_delta = somc_txpower_min_deltas[band5g][chain]; - return (min_delta == INT_MAX) ? 0 : min_delta; -} - -static void -somc_txpower_update_min_delta(const int *delta, int num, int band5g, int chain) -{ - int *min_delta = &somc_txpower_min_deltas[band5g][chain]; - while (num > 0) { - num--; - if (band5g && (num == 0)) /* ignore 11b delta value for 5GHz */ - continue; - if (!band5g && (num > 2)) /* ignore 11n-40/11ac delta values for 2.4GHz */ - continue; - *min_delta = MIN(*min_delta, delta[num]); - } -} - -static int -somc_read_file(const char *path, unsigned char *buf, int buf_len) -{ - int ret = -1; - int len; - struct file *fp = NULL; - - if (!path || !buf) - goto err; - - fp = filp_open(path, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: file open error: %s\n", __FUNCTION__, path)); - if (PTR_ERR(fp) == -ENOENT) { - DHD_ERROR(("%s: file does not exist: %s\n", __FUNCTION__, path)); - ret = -2; - } - fp = NULL; - goto err; - } - - len = dhd_os_get_image_block(buf, buf_len, (void *)fp); - if (len <= 0 || buf_len <= len) { - DHD_ERROR(("%s: file read error: %s\n", __FUNCTION__, path)); - goto err; - } - buf[len] = '\0'; - - ret = 0; -err: - if (fp) - filp_close(fp, NULL); - return ret; -} - -static int -somc_read_ta(somc_nv_item_t item, unsigned char *buf, int buf_len) -{ - char ta_buf[SOMC_MAX_TABUF_SIZE] = {0}; - int *d, ret; - - ret = somc_read_file(somc_ta_paths[item], ta_buf, sizeof(ta_buf)); - if (ret != 0) - return ret; - - switch (item) { - case SOMC_TA_TXPWR_2_4G: - case SOMC_TA_TXPWR_5G_LOW: - case SOMC_TA_TXPWR_5G_MID: - case SOMC_TA_TXPWR_5G_HIGH: - case SOMC_TA_TXPWR_CO1_2_4G: - case SOMC_TA_TXPWR_CO1_5G_LOW: - case SOMC_TA_TXPWR_CO1_5G_MID: - case SOMC_TA_TXPWR_CO1_5G_HIGH: - if (buf_len < SOMC_TXPWR_BUF_SIZE) - return -1; - d = (int *)buf; - if (sscanf(ta_buf, "%d:%d:%d:%d:%d:%d:%d", - &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6]) != 7) { - DHD_ERROR(("%s: tx power parse error: %s\n", - __FUNCTION__, somc_ta_paths[item])); - return -1; - } - - printk("%s: tx power in miscTA(%s),\n 11b:11a:11n(20MHz):11n(40MHz):" - "11ac(20MHz):11ac(40MHz):11ac(80MHz)=,\n %d:%d:%d:%d:%d:%d:%d\n", - __FUNCTION__, somc_ta_paths[item], - d[0], d[1], d[2], d[3], d[4], d[5], d[6]); - break; - default: - return -1; - } - - return 0; -} - -static int -somc_txpower_apply_delta(const unsigned char *key, int len, int offset, - int delta, unsigned char *nvram, int nvram_len) -{ - unsigned char *end = nvram + nvram_len - 1; - unsigned char *k, *v, *t; - unsigned int power_h, power_l; - int i, j, v_len = len * 2 + 5; /* e.g. "0x5555,0x1111" (= 4 * 2 + 5) */ - const unsigned char *fmt; - - if (!key || !nvram || offset >= len || (len != 4 && len != 8)) - return -1; - - fmt = (len == 4) ? "0x%04x,0x%04x" : "0x%08x,0x%08x"; - - /* look up key in nvram */ - if ((k = strnstr(nvram, key, nvram_len)) == NULL) { - DHD_ERROR(("%s: key not found: %s\n", __FUNCTION__, key)); - return -1; - } - - /* extract value */ - v = k + strlen(key); - if (v > end || *v != '=') { - DHD_ERROR(("%s: value parse error: %s\n", __FUNCTION__, key)); - return -1; - } - v += 1; - - if (v > end || (t = strnchr(v, end - v + 1, '\n')) == NULL || - t - v != v_len) { - DHD_ERROR(("%s: value parse error: %s\n", __FUNCTION__, key)); - return -1; - } - - /* extract each values */ - if (sscanf(v, fmt, &power_l, &power_h) != 2) { - DHD_ERROR(("%s: power offset values parse error: %s\n", __FUNCTION__, key)); - return -1; - } - - /* convert unit since nvram uses 1/2dB step, miscTA uses 1/100dB step */ - if (delta < 0 && delta % 50 != 0) - delta = delta / 50 - 1; - else - delta = delta / 50; - - for (i = 0, j = len - offset; i < j; i++) { - int val, sft = i * 4; - /* combine low and high 4 bits into a value(8bit) */ - val = ((power_l >> sft) & 0xf) | (((power_h >> sft) & 0xf) << 4); - /* apply delta */ - val -= delta; - val = (val > 0xff) ? 0xff : (val < 0x00) ? 0x00 : val; - /* separate power to low and high again */ - power_l &= ~(0xf << sft); - power_l |= (val & 0x0f) << sft; - power_h &= ~(0xf << sft); - power_h |= ((val & 0xf0) >> 4) << sft; - } - - snprintf(v, v_len + 1, fmt, power_l, power_h); - v[v_len] = '\n'; - - return 0; -} - -int somc_txpower_calibrate(char *nvram, int nvram_len) -{ - int v[4][SOMC_TXPWR_BUF_SIZE]; /* tx power offset(s) */ - int i, j, ta_num, delta[sizeof(somc_ppr_items) / sizeof(somc_ppr_items[0])]; - -#ifdef SOMC_MIMO - ta_num = SOMC_TA_TXPWR_CO1_5G_HIGH + 1; -#else - ta_num = SOMC_TA_TXPWR_5G_HIGH + 1; -#endif - /* initialize minimum delta (used for tx power trim) */ - for (i = 0; i < 4; i++) { - for (j = 0; j < SOMC_TXPWR_BUF_SIZE; j++) { - v[i][j] = INT_MAX; - } - } - - /* initialize minimum delta (used for tx power back-off) */ - somc_txpower_min_deltas[0][0 /* chain0 */] = INT_MAX; - somc_txpower_min_deltas[1][0 /* chain0 */] = INT_MAX; - somc_txpower_min_deltas[0][1 /* chain1 */] = INT_MAX; - somc_txpower_min_deltas[1][1 /* chain1 */] = INT_MAX; - - for (i = 0; i < ta_num; i++) { - int ret; - int tv[SOMC_TXPWR_BUF_SIZE] = {0}; - - /* no need to update delta if miscTA doesn't exist(ret == 2) */ - ret = somc_read_ta(i, (char *)tv, sizeof(tv)); - if (ret == 0) { - somc_txpower_update_min_delta(tv, SOMC_TXPWR_BUF_SIZE, - SOMC_NV_IS_5G(i), SOMC_NV_GET_CHAIN(i)); - /* select minimum delta between chain0 and chain1 */ - for (j = 0; j < SOMC_TXPWR_BUF_SIZE; j++) - v[i % 4][j] = MIN(v[i % 4][j], tv[j]); - } else if (ret != -2) - return BCME_OK; - } - - /* construct delta data structure for 2.4GHz - * TA value "v[0]" consists of the following format. - * {11b}:{11a}:{11n-20} - */ - delta[0] = v[0][0]; /* {11b} */ - delta[1] = v[0][1]; /* {11a} */ - delta[2] = v[0][1]; /* {11a} */ - delta[3] = v[0][2]; /* {11n-20} */ - - /* construct delta data structure for 5GHz(low/mid/high) - * TA values "v[1],v[2],v[3]" consist of the following format. - * {11b}:{11a}:{11n-20}:{11n-40}:{11ac-20}:{11ac-40}:{11ac-80} - */ - for (i = 1; i < 4; i++) { - /* minimum delta between {11a}, {11n-20}, {11ac-20} for 20MHz */ - delta[i * 3 + 1] = MIN(MIN(v[i][1], v[i][2]), v[i][4]); - /* minimum delta between {11n-40}, {11ac-40} for 40MHz */ - delta[i * 3 + 2] = MIN(v[i][3], v[i][5]); - /* {11ac-80} for 80MHz */ - delta[i * 3 + 3] = v[i][6]; - } - - /* Apply delta (tx power trim) */ - for (i = 0; i < sizeof(somc_ppr_items) / sizeof(somc_ppr_items[0]); i++) { - if (delta[i] == INT_MAX) - continue; - if (somc_txpower_apply_delta(somc_ppr_items[i].key, somc_ppr_items[i].len, - somc_ppr_items[i].offset, delta[i], nvram, nvram_len) != 0) - return BCME_ERROR; - } - - return BCME_OK; -} - -int somc_update_qtxpower(char *buf, char band, int chain) -{ - int in_qdbm, power; - int delta = somc_txpower_get_min_delta((band & SOMC_TXPWR_5G) != 0, chain); - - in_qdbm = *buf; - - if (in_qdbm < 0 || SOMC_TXPWR_MAX < in_qdbm) - return -1; - - /* convert unit for calculation since 'delta' uses 1/100dB step */ - power = in_qdbm + delta / (100 / 4); - if (power > 0) { - power = (power > SOMC_TXPWR_MAX) ? SOMC_TXPWR_MAX : power; - } else { - power = 0; - } - *buf = (char)power; - - printk("%s: Set max tx power: %d qdBm (delta=%d)\n", - __FUNCTION__, power, delta); - - return 0; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.h deleted file mode 100755 index 4c83517241a2..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2014 Sony Mobile Communications Inc. - * - * Author: Daisuke Niwa daisuke.x.niwa@sonymobile.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - */ - -#ifndef __DHD_SOMC_CUSTOM_H__ -#define __DHD_SOMC_CUSTOM_H__ - -extern int somc_txpower_calibrate(char *nvram, int nvram_len); -extern int somc_update_qtxpower(char *buf, char band, int chain); - -#endif /* __DHD_SOMC_CUSTOM_H__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c b/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c deleted file mode 100755 index 1152ce9dfd23..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c +++ /dev/null @@ -1,4046 +0,0 @@ -/* - * DHD PROP_TXSTATUS Module. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_wlfc.c 701450 2017-05-25 02:10:23Z $ - * - */ - -#include -#include - -#include -#include - -#include -#include - -#include -#include - -#ifdef PROP_TXSTATUS -#include -#include -#endif -#ifdef DHDTCPACK_SUPPRESS -#include -#endif /* DHDTCPACK_SUPPRESS */ - - -/* - * wlfc naming and lock rules: - * - * 1. Private functions name like _dhd_wlfc_XXX, declared as static and avoid wlfc lock operation. - * 2. Public functions name like dhd_wlfc_XXX, use wlfc lock if needed. - * 3. Non-Proptxstatus module call public functions only and avoid wlfc lock operation. - * - */ - - -#ifdef PROP_TXSTATUS - -#define DHD_WLFC_QMON_COMPLETE(entry) - -#define LIMIT_BORROW - - -static uint16 -_dhd_wlfc_adjusted_seq(void* p, uint8 current_seq) -{ - uint16 seq; - - if (!p) { - return 0xffff; - } - - seq = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - if (seq < current_seq) { - /* wrap around */ - seq += 256; - } - - return seq; -} - -static void -_dhd_wlfc_prec_enque(struct pktq *pq, int prec, void* p, bool qHead, - uint8 current_seq, bool reOrder) -{ - struct pktq_prec *q; - uint16 seq, seq2; - void *p2, *p2_prev; - - if (!p) - return; - - - ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ - - ASSERT(!pktq_full(pq)); - ASSERT(!pktq_pfull(pq, prec)); - - q = &pq->q[prec]; - - PKTSETLINK(p, NULL); - if (q->head == NULL) { - /* empty queue */ - q->head = p; - q->tail = p; - } else { - if (reOrder && (prec & 1)) { - seq = _dhd_wlfc_adjusted_seq(p, current_seq); - p2 = qHead ? q->head : q->tail; - seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); - - if ((qHead &&((seq+1) > seq2)) || (!qHead && ((seq2+1) > seq))) { - /* need reorder */ - p2 = q->head; - p2_prev = NULL; - seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); - - while (seq > seq2) { - p2_prev = p2; - p2 = PKTLINK(p2); - if (!p2) { - break; - } - seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); - } - - if (p2_prev == NULL) { - /* insert head */ - PKTSETLINK(p, q->head); - q->head = p; - } else if (p2 == NULL) { - /* insert tail */ - PKTSETLINK(p2_prev, p); - q->tail = p; - } else { - /* insert after p2_prev */ - PKTSETLINK(p, PKTLINK(p2_prev)); - PKTSETLINK(p2_prev, p); - } - goto exit; - } - } - - if (qHead) { - PKTSETLINK(p, q->head); - q->head = p; - } else { - PKTSETLINK(q->tail, p); - q->tail = p; - } - } - -exit: - - q->len++; - pq->len++; - - if (pq->hi_prec < prec) - pq->hi_prec = (uint8)prec; -} - -/* Create a place to store all packet pointers submitted to the firmware until - a status comes back, suppress or otherwise. - - hang-er: noun, a contrivance on which things are hung, as a hook. -*/ -static void* -_dhd_wlfc_hanger_create(dhd_pub_t *dhd, int max_items) -{ - int i; - wlfc_hanger_t* hanger; - - /* allow only up to a specific size for now */ - ASSERT(max_items == WLFC_HANGER_MAXITEMS); - - if ((hanger = (wlfc_hanger_t*)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_DHD_WLFC_HANGER, - WLFC_HANGER_SIZE(max_items))) == NULL) { - return NULL; - } - memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); - hanger->max_items = max_items; - - for (i = 0; i < hanger->max_items; i++) { - hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - } - return hanger; -} - -static int -_dhd_wlfc_hanger_delete(dhd_pub_t *dhd, void* hanger) -{ - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h) { - DHD_OS_PREFREE(dhd, h, WLFC_HANGER_SIZE(h->max_items)); - return BCME_OK; - } - return BCME_BADARG; -} - -static uint16 -_dhd_wlfc_hanger_get_free_slot(void* hanger) -{ - uint32 i; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h) { - i = h->slot_pos + 1; - if (i == h->max_items) { - i = 0; - } - while (i != h->slot_pos) { - if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { - h->slot_pos = i; - return (uint16)i; - } - i++; - if (i == h->max_items) - i = 0; - } - h->failed_slotfind++; - } - return WLFC_HANGER_MAXITEMS; -} - -static int -_dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - *gen = 0xff; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - - if (h) { - if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || - (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { - *gen = h->items[slot_id].gen; - } - else { - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -_dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { - if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { - h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; - h->items[slot_id].pkt = pkt; - h->pushed++; - } - else { - h->failed_to_push++; - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -_dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - - if (h) { - if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { - *pktout = h->items[slot_id].pkt; - if (remove_from_hanger) { - h->items[slot_id].state = - WLFC_HANGER_ITEM_STATE_FREE; - h->items[slot_id].pkt = NULL; - h->items[slot_id].gen = 0xff; - h->items[slot_id].identifier = 0; - h->popped++; - } - } - else { - h->failed_to_pop++; - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -_dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - if (h) { - h->items[slot_id].gen = gen; - if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { - h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; - } - else - rc = BCME_BADARG; - } - else - rc = BCME_BADARG; - - return rc; -} - -static void -_dhd_wlfc_hanger_waitevent_set(void* hanger, uint32 hslot, uint8 waitevent) -{ - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - ASSERT(h && (hslot < (uint32) h->max_items)); - - h->items[hslot].waitevent = waitevent; -} - -static uint8 -_dhd_wlfc_hanger_waitevent_decreturn(void* hanger, uint32 hslot) -{ - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - ASSERT(h && (hslot < (uint32) h->max_items)); - - h->items[hslot].waitevent--; - return h->items[hslot].waitevent; -} - -/* return true if the slot is only waiting for clean */ -static bool -_dhd_wlfc_hanger_wait_clean(void* hanger, uint32 hslot) -{ - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if ((hslot < (uint32) h->max_items) && - (h->items[hslot].state == WLFC_HANGER_ITEM_STATE_WAIT_CLEAN)) { - /* the packet should be already freed by _dhd_wlfc_cleanup */ - h->items[hslot].state = WLFC_HANGER_ITEM_STATE_FREE; - h->items[hslot].pkt = NULL; - h->items[hslot].gen = 0xff; - h->items[hslot].identifier = 0; - return TRUE; - } - - return FALSE; -} - -/* remove reference of specific packet in hanger */ -static bool -_dhd_wlfc_hanger_remove_reference(wlfc_hanger_t* h, void* pkt) -{ - int i; - - if (!h || !pkt) { - return FALSE; - } - - for (i = 0; i < h->max_items; i++) { - if (pkt == h->items[i].pkt) { - if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) || - (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - h->items[i].pkt = NULL; - h->items[i].gen = 0xff; - h->items[i].identifier = 0; - } - return TRUE; - } - } - - return FALSE; -} - - -static int -_dhd_wlfc_enque_afq(athost_wl_status_info_t* ctx, void *p) -{ - wlfc_mac_descriptor_t* entry; - uint16 entry_idx = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - uint8 prec = DHD_PKTTAG_FIFO(PKTTAG(p)); - - if (entry_idx < WLFC_MAC_DESC_TABLE_SIZE) - entry = &ctx->destination_entries.nodes[entry_idx]; - else if (entry_idx < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) - entry = &ctx->destination_entries.interfaces[entry_idx - WLFC_MAC_DESC_TABLE_SIZE]; - else - entry = &ctx->destination_entries.other; - - pktq_penq(&entry->afq, prec, p); - - return BCME_OK; -} - -static int -_dhd_wlfc_deque_afq(athost_wl_status_info_t* ctx, uint16 hslot, uint8 hcnt, uint8 prec, - void **pktout) -{ - wlfc_mac_descriptor_t *entry; - struct pktq *pq; - struct pktq_prec *q; - void *p, *b; - - if (!ctx) { - DHD_ERROR(("%s: ctx(%p), pktout(%p)\n", __FUNCTION__, ctx, pktout)); - return BCME_BADARG; - } - - if (pktout) { - *pktout = NULL; - } - - ASSERT(hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM + 1)); - - if (hslot < WLFC_MAC_DESC_TABLE_SIZE) - entry = &ctx->destination_entries.nodes[hslot]; - else if (hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) - entry = &ctx->destination_entries.interfaces[hslot - WLFC_MAC_DESC_TABLE_SIZE]; - else - entry = &ctx->destination_entries.other; - - pq = &entry->afq; - - ASSERT(prec < pq->num_prec); - - q = &pq->q[prec]; - - b = NULL; - p = q->head; - - while (p && (hcnt != WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))))) - { - b = p; - p = PKTLINK(p); - } - - if (p == NULL) { - /* none is matched */ - if (b) { - DHD_ERROR(("%s: can't find matching seq(%d)\n", __FUNCTION__, hcnt)); - } else { - DHD_ERROR(("%s: queue is empty\n", __FUNCTION__)); - } - - return BCME_ERROR; - } - - if (!b) { - /* head packet is matched */ - if ((q->head = PKTLINK(p)) == NULL) { - q->tail = NULL; - } - } else { - /* middle packet is matched */ - DHD_INFO(("%s: out of order, seq(%d), head_seq(%d)\n", __FUNCTION__, hcnt, - WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(q->head))))); - ctx->stats.ooo_pkts[prec]++; - PKTSETLINK(b, PKTLINK(p)); - if (PKTLINK(p) == NULL) { - q->tail = b; - } - } - - q->len--; - pq->len--; - - PKTSETLINK(p, NULL); - - if (pktout) { - *pktout = p; - } - - return BCME_OK; -} - -static int -_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, - uint8 tim_bmp, uint8 mac_handle, uint32 htodtag, uint16 htodseq, bool skip_wlfc_hdr) -{ - uint32 wl_pktinfo = 0; - uint8* wlh; - uint8 dataOffset = 0; - uint8 fillers; - uint8 tim_signal_len = 0; - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - - struct bdc_header *h; - - if (skip_wlfc_hdr) - goto push_bdc_hdr; - - if (tim_signal) { - tim_signal_len = TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; - } - - /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ - dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + TLV_HDR_LEN + tim_signal_len; - if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { - dataOffset += WLFC_CTL_VALUE_LEN_SEQ; - } - - fillers = ROUNDUP(dataOffset, 4) - dataOffset; - dataOffset += fillers; - - PKTPUSH(ctx->osh, p, dataOffset); - wlh = (uint8*) PKTDATA(ctx->osh, p); - - wl_pktinfo = htol32(htodtag); - - wlh[TLV_TAG_OFF] = WLFC_CTL_TYPE_PKTTAG; - wlh[TLV_LEN_OFF] = WLFC_CTL_VALUE_LEN_PKTTAG; - memcpy(&wlh[TLV_HDR_LEN], &wl_pktinfo, sizeof(uint32)); - - if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { - uint16 wl_seqinfo = htol16(htodseq); - wlh[TLV_LEN_OFF] += WLFC_CTL_VALUE_LEN_SEQ; - memcpy(&wlh[TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PKTTAG], &wl_seqinfo, - WLFC_CTL_VALUE_LEN_SEQ); - } - - if (tim_signal_len) { - wlh[dataOffset - fillers - tim_signal_len ] = - WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; - wlh[dataOffset - fillers - tim_signal_len + 1] = - WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; - wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; - wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; - } - if (fillers) - memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); - -push_bdc_hdr: - - PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); - h = (struct bdc_header *)PKTDATA(ctx->osh, p); - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (PKTSUMNEEDED(p)) - h->flags |= BDC_FLAG_SUM_NEEDED; - - - h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); - h->flags2 = 0; - h->dataOffset = dataOffset >> 2; - BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); - return BCME_OK; -} - -static int -_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) -{ - struct bdc_header *h; - - if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { - DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); - return BCME_ERROR; - } - h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); - - /* pull BDC header */ - PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); - - if (PKTLEN(ctx->osh, pktbuf) < (uint)(h->dataOffset << 2)) { - DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); - return BCME_ERROR; - } - - /* pull wl-header */ - PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); - return BCME_OK; -} - -static wlfc_mac_descriptor_t* -_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) -{ - int i; - wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; - uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); - uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); - wlfc_mac_descriptor_t* entry = DHD_PKTTAG_ENTRY(PKTTAG(p)); - int iftype = ctx->destination_entries.interfaces[ifid].iftype; - - /* saved one exists, return it */ - if (entry) - return entry; - - /* Multicast destination, STA and P2P clients get the interface entry. - * STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations - * have their own entry. - */ - if ((iftype == WLC_E_IF_ROLE_STA || ETHER_ISMULTI(dstn) || - iftype == WLC_E_IF_ROLE_P2P_CLIENT) && - (ctx->destination_entries.interfaces[ifid].occupied)) { - entry = &ctx->destination_entries.interfaces[ifid]; - } - - if (entry && ETHER_ISMULTI(dstn)) { - DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); - return entry; - } - - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (table[i].occupied) { - if (table[i].interface_id == ifid) { - if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) { - entry = &table[i]; - break; - } - } - } - } - - if (entry == NULL) - entry = &ctx->destination_entries.other; - - DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); - - return entry; -} - -static int -_dhd_wlfc_prec_drop(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ) -{ - athost_wl_status_info_t* ctx; - void *pout = NULL; - - ASSERT(dhdp && p); - ASSERT(prec >= 0 && prec <= WLFC_PSQ_PREC_COUNT); - - ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; - - if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { - /* suppressed queue, need pop from hanger */ - _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG - (PKTTAG(p))), &pout, 1); - ASSERT(p == pout); - } - - if (!(prec & 1)) { -#ifdef DHDTCPACK_SUPPRESS - /* pkt in delayed q, so fake push BDC header for - * dhd_tcpack_check_xmit() and dhd_txcomplete(). - */ - _dhd_wlfc_pushheader(ctx, p, FALSE, 0, 0, 0, 0, TRUE); - - /* This packet is about to be freed, so remove it from tcp_ack_info_tbl - * This must be one of... - * 1. A pkt already in delayQ is evicted by another pkt with higher precedence - * in _dhd_wlfc_prec_enq_with_drop() - * 2. A pkt could not be enqueued to delayQ because it is full, - * in _dhd_wlfc_enque_delayq(). - * 3. A pkt could not be enqueued to delayQ because it is full, - * in _dhd_wlfc_rollback_packet_toq(). - */ - if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" - " Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - } - - if (bPktInQ) { - ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; - ctx->pkt_cnt_per_ac[prec>>1]--; - } - - dhd_txcomplete(dhdp, p, FALSE); - PKTFREE(ctx->osh, p, TRUE); - ctx->stats.pktout++; - ctx->stats.drop_pkts[prec]++; - - return 0; -} - -static bool -_dhd_wlfc_prec_enq_with_drop(dhd_pub_t *dhdp, struct pktq *pq, void *pkt, int prec, bool qHead, - uint8 current_seq) -{ - void *p = NULL; - int eprec = -1; /* precedence to evict from */ - athost_wl_status_info_t* ctx; - - ASSERT(dhdp && pq && pkt); - ASSERT(prec >= 0 && prec < pq->num_prec); - - ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; - - /* Fast case, precedence queue is not full and we are also not - * exceeding total queue length - */ - if (!pktq_pfull(pq, prec) && !pktq_full(pq)) { - goto exit; - } - - /* Determine precedence from which to evict packet, if any */ - if (pktq_pfull(pq, prec)) - eprec = prec; - else if (pktq_full(pq)) { - p = pktq_peek_tail(pq, &eprec); - if (!p) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return FALSE; - } - if ((eprec > prec) || (eprec < 0)) { - if (!pktq_pempty(pq, prec)) { - eprec = prec; - } else { - return FALSE; - } - } - } - - /* Evict if needed */ - if (eprec >= 0) { - /* Detect queueing to unconfigured precedence */ - ASSERT(!pktq_pempty(pq, eprec)); - /* Evict all fragmented frames */ - dhd_prec_drop_pkts(dhdp, pq, eprec, _dhd_wlfc_prec_drop); - } - -exit: - /* Enqueue */ - _dhd_wlfc_prec_enque(pq, prec, pkt, qHead, current_seq, - WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)); - ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(pkt))][prec>>1]++; - ctx->pkt_cnt_per_ac[prec>>1]++; - - return TRUE; -} - - -static int -_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, - void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) -{ - /* - put the packet back to the head of queue - - - suppressed packet goes back to suppress sub-queue - - pull out the header, if new or delayed packet - - Note: hslot is used only when header removal is done. - */ - wlfc_mac_descriptor_t* entry; - int rc = BCME_OK; - int prec, fifo_id; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - prec = DHD_PKTTAG_FIFO(PKTTAG(p)); - fifo_id = prec << 1; - if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) - fifo_id += 1; - if (entry != NULL) { - /* - if this packet did not count against FIFO credit, it must have - taken a requested_credit from the firmware (for pspoll etc.) - */ - if ((prec != AC_COUNT) && !DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) - entry->requested_credit++; - - if (pkt_type == eWLFC_PKTTYPE_DELAYED) { - /* decrement sequence count */ - WLFC_DECR_SEQCOUNT(entry, prec); - /* remove header first */ - rc = _dhd_wlfc_pullheader(ctx, p); - if (rc != BCME_OK) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - goto exit; - } - } - - if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, fifo_id, TRUE, - WLFC_SEQCOUNT(entry, fifo_id>>1)) - == FALSE) { - /* enque failed */ - DHD_ERROR(("Error: %s():%d, fifo_id(%d)\n", - __FUNCTION__, __LINE__, fifo_id)); - rc = BCME_ERROR; - } - } else { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } -exit: - if (rc != BCME_OK) { - ctx->stats.rollback_failed++; - _dhd_wlfc_prec_drop(ctx->dhdp, fifo_id, p, FALSE); - } - else - ctx->stats.rollback++; - - return rc; -} - -static bool -_dhd_wlfc_allow_fc(athost_wl_status_info_t* ctx, uint8 ifid) -{ - int prec, ac_traffic = WLFC_NO_TRAFFIC; - - for (prec = 0; prec < AC_COUNT; prec++) { - if (ctx->pkt_cnt_in_q[ifid][prec] > 0) { - if (ac_traffic == WLFC_NO_TRAFFIC) - ac_traffic = prec + 1; - else if (ac_traffic != (prec + 1)) - ac_traffic = WLFC_MULTI_TRAFFIC; - } - } - - if (ac_traffic >= 1 && ac_traffic <= AC_COUNT) { - /* single AC (BE/BK/VI/VO) in queue */ - if (ctx->allow_fc) { - return TRUE; - } else { - uint32 delta; - uint32 curr_t = OSL_SYSUPTIME(); - - if (ctx->fc_defer_timestamp == 0) { - /* first signle ac scenario */ - ctx->fc_defer_timestamp = curr_t; - return FALSE; - } - - /* single AC duration, this handles wrap around, e.g. 1 - ~0 = 2. */ - delta = curr_t - ctx->fc_defer_timestamp; - if (delta >= WLFC_FC_DEFER_PERIOD_MS) { - ctx->allow_fc = TRUE; - } - } - } else { - /* multiple ACs or BCMC in queue */ - ctx->allow_fc = FALSE; - ctx->fc_defer_timestamp = 0; - } - - return ctx->allow_fc; -} - -static void -_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) -{ - dhd_pub_t *dhdp; - - ASSERT(ctx); - - dhdp = (dhd_pub_t *)ctx->dhdp; - ASSERT(dhdp); - - if (dhdp->skip_fc && dhdp->skip_fc()) - return; - - if ((ctx->hostif_flow_state[if_id] == OFF) && !_dhd_wlfc_allow_fc(ctx, if_id)) - return; - - if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { - /* start traffic */ - ctx->hostif_flow_state[if_id] = OFF; - /* - WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", - pq->len, if_id, __FUNCTION__)); - */ - WLFC_DBGMESG(("F")); - - dhd_txflowcontrol(dhdp, if_id, OFF); - - ctx->toggle_host_if = 0; - } - - if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { - /* stop traffic */ - ctx->hostif_flow_state[if_id] = ON; - /* - WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", - pq->len, if_id, __FUNCTION__)); - */ - WLFC_DBGMESG(("N")); - - dhd_txflowcontrol(dhdp, if_id, ON); - - ctx->host_ifidx = if_id; - ctx->toggle_host_if = 1; - } - - return; -} - -static int -_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - uint8 ta_bmp) -{ - int rc = BCME_OK; - void* p = NULL; - int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 16; - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - - if (dhdp->proptxstatus_txoff) { - rc = BCME_NORESOURCE; - return rc; - } - - /* allocate a dummy packet */ - p = PKTGET(ctx->osh, dummylen, TRUE); - if (p) { - PKTPULL(ctx->osh, p, dummylen); - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); - _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0, 0, FALSE); - DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); - DHD_PKTTAG_WLFCPKT_SET(PKTTAG(p), 1); -#ifdef PROP_TXSTATUS_DEBUG - ctx->stats.signal_only_pkts_sent++; -#endif - -#if defined(BCMPCIE) - rc = dhd_bus_txdata(dhdp->bus, p, ctx->host_ifidx); -#else - rc = dhd_bus_txdata(dhdp->bus, p); -#endif - if (rc != BCME_OK) { - _dhd_wlfc_pullheader(ctx, p); - PKTFREE(ctx->osh, p, TRUE); - } - } - else { - DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", - __FUNCTION__, dummylen)); - rc = BCME_NOMEM; - } - return rc; -} - -/* Return TRUE if traffic availability changed */ -static bool -_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - int prec) -{ - bool rc = FALSE; - - if (entry->state == WLFC_STATE_CLOSE) { - if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && - (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { - - if (entry->traffic_pending_bmp & NBITVAL(prec)) { - rc = TRUE; - entry->traffic_pending_bmp = - entry->traffic_pending_bmp & ~ NBITVAL(prec); - } - } - else { - if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { - rc = TRUE; - entry->traffic_pending_bmp = - entry->traffic_pending_bmp | NBITVAL(prec); - } - } - } - if (rc) { - /* request a TIM update to firmware at the next piggyback opportunity */ - if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { - entry->send_tim_signal = 1; - _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); - entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; - entry->send_tim_signal = 0; - } - else { - rc = FALSE; - } - } - return rc; -} - -static int -_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) -{ - wlfc_mac_descriptor_t* entry; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - if (entry == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_NOTFOUND; - } - /* - - suppressed packets go to sub_queue[2*prec + 1] AND - - delayed packets go to sub_queue[2*prec + 0] to ensure - order of delivery. - */ - if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, ((prec << 1) + 1), FALSE, - WLFC_SEQCOUNT(entry, prec)) - == FALSE) { - ctx->stats.delayq_full_error++; - /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ - WLFC_DBGMESG(("s")); - return BCME_ERROR; - } - - /* A packet has been pushed, update traffic availability bitmap, if applicable */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); - return BCME_OK; -} - -static int -_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, - wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) -{ - int rc = BCME_OK; - int hslot = WLFC_HANGER_MAXITEMS; - bool send_tim_update = FALSE; - uint32 htod = 0; - uint16 htodseq = 0; - uint8 free_ctr; - int gen = 0xff; - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - - *slot = hslot; - - if (entry == NULL) { - entry = _dhd_wlfc_find_table_entry(ctx, p); - } - - if (entry == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_ERROR; - } - - if (entry->send_tim_signal) { - send_tim_update = TRUE; - entry->send_tim_signal = 0; - entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; - } - - if (header_needed) { - if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { - hslot = (uint)(entry - &ctx->destination_entries.nodes[0]); - } else { - hslot = _dhd_wlfc_hanger_get_free_slot(ctx->hanger); - } - gen = entry->generation; - free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); - } else { - if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { - htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(p)); - } - - hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - - if (WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)) { - gen = entry->generation; - } else if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { - gen = WL_TXSTATUS_GET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - } else { - _dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); - } - - free_ctr = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - /* remove old header */ - _dhd_wlfc_pullheader(ctx, p); - } - - if (hslot >= WLFC_HANGER_MAXITEMS) { - DHD_ERROR(("Error: %s():no hanger slot available\n", __FUNCTION__)); - return BCME_ERROR; - } - - WL_TXSTATUS_SET_FREERUNCTR(htod, free_ctr); - WL_TXSTATUS_SET_HSLOT(htod, hslot); - WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); - WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); - WL_TXSTATUS_SET_GENERATION(htod, gen); - DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); - - if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { - /* - Indicate that this packet is being sent in response to an - explicit request from the firmware side. - */ - WLFC_PKTFLAG_SET_PKTREQUESTED(htod); - } else { - WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); - } - - rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, - entry->traffic_lastreported_bmp, entry->mac_handle, htod, htodseq, FALSE); - if (rc == BCME_OK) { - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); - - if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && header_needed) { - /* - a new header was created for this packet. - push to hanger slot and scrub q. Since bus - send succeeded, increment seq number as well. - */ - rc = _dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); - if (rc == BCME_OK) { -#ifdef PROP_TXSTATUS_DEBUG - ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = - OSL_SYSUPTIME(); -#endif - } else { - DHD_ERROR(("%s() hanger_pushpkt() failed, rc: %d\n", - __FUNCTION__, rc)); - } - } - - if ((rc == BCME_OK) && header_needed) { - /* increment free running sequence count */ - WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); - } - } - *slot = hslot; - return rc; -} - -static int -_dhd_wlfc_is_destination_open(athost_wl_status_info_t* ctx, - wlfc_mac_descriptor_t* entry, int prec) -{ - if (entry->interface_id >= WLFC_MAX_IFNUM) { - ASSERT(&ctx->destination_entries.other == entry); - return 1; - } - if (ctx->destination_entries.interfaces[entry->interface_id].iftype == - WLC_E_IF_ROLE_P2P_GO) { - /* - destination interface is of type p2p GO. - For a p2pGO interface, if the destination is OPEN but the interface is - CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is - destination-specific-credit left send packets. This is because the - firmware storing the destination-specific-requested packet in queue. - */ - if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && - (entry->requested_packet == 0)) { - return 0; - } - } - /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ - if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && - (entry->requested_packet == 0)) || - (!(entry->ac_bitmap & (1 << prec)))) { - return 0; - } - - return 1; -} - -static void* -_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, int prec, - uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out, - bool only_no_credit) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - wlfc_mac_descriptor_t* entry; - int total_entries; - void* p = NULL; - int i; - - *entry_out = NULL; - /* most cases a packet will count against FIFO credit */ - *ac_credit_spent = ((prec == AC_COUNT) && !ctx->bcmc_credit_supported) ? 0 : 1; - - /* search all entries, include nodes as well as interfaces */ - if (only_no_credit) { - total_entries = ctx->requested_entry_count; - } else { - total_entries = ctx->active_entry_count; - } - - for (i = 0; i < total_entries; i++) { - if (only_no_credit) { - entry = ctx->requested_entry[i]; - } else { - entry = ctx->active_entry_head; - /* move head to ensure fair round-robin */ - ctx->active_entry_head = ctx->active_entry_head->next; - } - ASSERT(entry); - - if (entry->occupied && _dhd_wlfc_is_destination_open(ctx, entry, prec) && - (entry->transit_count < WL_TXSTATUS_FREERUNCTR_MASK) && - !(WLFC_GET_REORDERSUPP(dhdp->wlfc_mode) && entry->suppressed)) { - if (entry->state == WLFC_STATE_CLOSE) { - *ac_credit_spent = 0; - } - - /* higher precedence will be picked up first, - * i.e. suppressed packets before delayed ones - */ - p = pktq_pdeq(&entry->psq, PSQ_SUP_IDX(prec)); - *needs_hdr = 0; - if (p == NULL) { - if (entry->suppressed == TRUE) { - /* skip this entry */ - continue; - } - /* De-Q from delay Q */ - p = pktq_pdeq(&entry->psq, PSQ_DLY_IDX(prec)); - *needs_hdr = 1; - } - - if (p != NULL) { - /* did the packet come from suppress sub-queue? */ - if (entry->requested_credit > 0) { - entry->requested_credit--; -#ifdef PROP_TXSTATUS_DEBUG - entry->dstncredit_sent_packets++; -#endif - } else if (entry->requested_packet > 0) { - entry->requested_packet--; - DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); - } - - *entry_out = entry; - ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec]--; - ctx->pkt_cnt_per_ac[prec]--; - _dhd_wlfc_flow_control_check(ctx, &entry->psq, - DHD_PKTTAG_IF(PKTTAG(p))); - /* - A packet has been picked up, update traffic - availability bitmap, if applicable - */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - return p; - } - } - } - return NULL; -} - -static int -_dhd_wlfc_enque_delayq(athost_wl_status_info_t* ctx, void* pktbuf, int prec) -{ - wlfc_mac_descriptor_t* entry; - - if (pktbuf != NULL) { - entry = _dhd_wlfc_find_table_entry(ctx, pktbuf); - if (entry == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_ERROR; - } - - /* - - suppressed packets go to sub_queue[2*prec + 1] AND - - delayed packets go to sub_queue[2*prec + 0] to ensure - order of delivery. - */ - if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, pktbuf, (prec << 1), - FALSE, WLFC_SEQCOUNT(entry, prec)) - == FALSE) { - WLFC_DBGMESG(("D")); - ctx->stats.delayq_full_error++; - return BCME_ERROR; - } - - - /* - A packet has been pushed, update traffic availability bitmap, - if applicable - */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - } - - return BCME_OK; -} - -static bool _dhd_wlfc_ifpkt_fn(void* p, void *p_ifid) -{ - if (!p || !p_ifid) - return FALSE; - - return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (*((uint8 *)p_ifid) == DHD_PKTTAG_IF(PKTTAG(p)))); -} - -static bool _dhd_wlfc_entrypkt_fn(void* p, void *entry) -{ - if (!p || !entry) - return FALSE; - - return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (entry == DHD_PKTTAG_ENTRY(PKTTAG(p)))); -} - -static void -_dhd_wlfc_return_implied_credit(athost_wl_status_info_t* wlfc, void* pkt) -{ - dhd_pub_t *dhdp; - - if (!wlfc || !pkt) { - return; - } - - dhdp = (dhd_pub_t *)(wlfc->dhdp); - if (dhdp && (dhdp->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) && - DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { - int lender, credit_returned = 0; - uint8 fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pkt)); - - /* Note that borrower is fifo_id */ - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; lender >= 0; lender--) { - if (wlfc->credits_borrowed[fifo_id][lender] > 0) { - wlfc->FIFO_credit[lender]++; - wlfc->credits_borrowed[fifo_id][lender]--; - credit_returned = 1; - break; - } - } - - if (!credit_returned) { - wlfc->FIFO_credit[fifo_id]++; - } - } -} - -static void -_dhd_wlfc_pktq_flush(athost_wl_status_info_t* ctx, struct pktq *pq, - bool dir, f_processpkt_t fn, void *arg, q_type_t q_type) -{ - int prec; - dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; - - ASSERT(dhdp); - - /* Optimize flush, if pktq len = 0, just return. - * pktq len of 0 means pktq's prec q's are all empty. - */ - if (pq->len == 0) { - return; - } - - - for (prec = 0; prec < pq->num_prec; prec++) { - struct pktq_prec *q; - void *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 = PKTLINK(p); - else - PKTSETLINK(prev, PKTLINK(p)); - if (q_type == Q_TYPE_PSQ) { - if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { - _dhd_wlfc_hanger_remove_reference(ctx->hanger, p); - } - ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; - ctx->pkt_cnt_per_ac[prec>>1]--; - ctx->stats.cleanup_psq_cnt++; - if (!(prec & 1)) { - /* pkt in delayed q, so fake push BDC header for - * dhd_tcpack_check_xmit() and dhd_txcomplete(). - */ - _dhd_wlfc_pushheader(ctx, p, FALSE, 0, 0, - 0, 0, TRUE); -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" - " Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(dhdp, - TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - } - } else if (q_type == Q_TYPE_AFQ) { - wlfc_mac_descriptor_t* entry = - _dhd_wlfc_find_table_entry(ctx, p); - entry->transit_count--; - if (entry->suppressed && - (--entry->suppr_transit_count == 0)) { - entry->suppressed = FALSE; - } - _dhd_wlfc_return_implied_credit(ctx, p); - ctx->stats.cleanup_fw_cnt++; - } - PKTSETLINK(p, NULL); - dhd_txcomplete(dhdp, p, FALSE); - PKTFREE(ctx->osh, p, dir); - if (dir) { - ctx->stats.pktout++; - } - q->len--; - pq->len--; - p = (head ? q->head : PKTLINK(prev)); - } else { - prev = p; - p = PKTLINK(p); - } - } - - if (q->head == NULL) { - ASSERT(q->len == 0); - q->tail = NULL; - } - - } - - if (fn == NULL) - ASSERT(pq->len == 0); -} - -static void* -_dhd_wlfc_pktq_pdeq_with_fn(struct pktq *pq, int prec, f_processpkt_t fn, void *arg) -{ - struct pktq_prec *q; - void *p, *prev = NULL; - - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - p = q->head; - - while (p) { - if (fn == NULL || (*fn)(p, arg)) { - break; - } else { - prev = p; - p = PKTLINK(p); - } - } - if (p == NULL) - return NULL; - - if (prev == NULL) { - if ((q->head = PKTLINK(p)) == NULL) { - q->tail = NULL; - } - } else { - PKTSETLINK(prev, PKTLINK(p)); - if (q->tail == p) { - q->tail = prev; - } - } - - q->len--; - - pq->len--; - - PKTSETLINK(p, NULL); - - return p; -} - -static void -_dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - int prec; - void *pkt = NULL, *head = NULL, *tail = NULL; - struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; - wlfc_mac_descriptor_t* entry; - - dhd_os_sdlock_txq(dhd); - for (prec = 0; prec < txq->num_prec; prec++) { - while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(dhd, pkt) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(dhd, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - if (!head) { - head = pkt; - } - if (tail) { - PKTSETLINK(tail, pkt); - } - tail = pkt; - } - } - dhd_os_sdunlock_txq(dhd); - - - while ((pkt = head)) { - head = PKTLINK(pkt); - PKTSETLINK(pkt, NULL); - entry = _dhd_wlfc_find_table_entry(wlfc, pkt); - - if (!WLFC_GET_AFQ(dhd->wlfc_mode) && - !_dhd_wlfc_hanger_remove_reference(h, pkt)) { - DHD_ERROR(("%s: can't find pkt(%p) in hanger, free it anyway\n", - __FUNCTION__, pkt)); - } - entry->transit_count--; - if (entry->suppressed && - (--entry->suppr_transit_count == 0)) { - entry->suppressed = FALSE; - } - _dhd_wlfc_return_implied_credit(wlfc, pkt); - dhd_txcomplete(dhd, pkt, FALSE); - PKTFREE(wlfc->osh, pkt, TRUE); - wlfc->stats.pktout++; - wlfc->stats.cleanup_txq_cnt++; - - } -} - -void -_dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - int i; - int total_entries; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; - - wlfc->stats.cleanup_txq_cnt = 0; - wlfc->stats.cleanup_psq_cnt = 0; - wlfc->stats.cleanup_fw_cnt = 0; - /* - * flush sequence shoulde be txq -> psq -> hanger/afq, hanger has to be last one - */ - /* flush bus->txq */ - _dhd_wlfc_cleanup_txq(dhd, fn, arg); - - - /* flush psq, search all entries, include nodes as well as interfaces */ - total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); - table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; - - for (i = 0; i < total_entries; i++) { - if (table[i].occupied) { - /* release packets held in PSQ (both delayed and suppressed) */ - if (table[i].psq.len) { - WLFC_DBGMESG(("%s(): PSQ[%d].len = %d\n", - __FUNCTION__, i, table[i].psq.len)); - _dhd_wlfc_pktq_flush(wlfc, &table[i].psq, TRUE, - fn, arg, Q_TYPE_PSQ); - } - - /* free packets held in AFQ */ - if (WLFC_GET_AFQ(dhd->wlfc_mode) && (table[i].afq.len)) { - _dhd_wlfc_pktq_flush(wlfc, &table[i].afq, TRUE, - fn, arg, Q_TYPE_AFQ); - } - - if ((fn == NULL) && (&table[i] != &wlfc->destination_entries.other)) { - table[i].occupied = 0; - if (table[i].transit_count || table[i].suppr_transit_count) { - DHD_ERROR(("%s: table[%d] transit(%d), suppr_tansit(%d)\n", - __FUNCTION__, i, - table[i].transit_count, - table[i].suppr_transit_count)); - } - } - } - } - - /* - . flush remained pkt in hanger queue, not in bus->txq nor psq. - . the remained pkt was successfully downloaded to dongle already. - . hanger slot state cannot be set to free until receive txstatus update. - */ - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - for (i = 0; i < h->max_items; i++) { - if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) || - (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { - if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { - table = _dhd_wlfc_find_table_entry(wlfc, h->items[i].pkt); - table->transit_count--; - if (table->suppressed && - (--table->suppr_transit_count == 0)) { - table->suppressed = FALSE; - } - _dhd_wlfc_return_implied_credit(wlfc, h->items[i].pkt); - dhd_txcomplete(dhd, h->items[i].pkt, FALSE); - PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); - wlfc->stats.pktout++; - wlfc->stats.cleanup_fw_cnt++; - h->items[i].state = WLFC_HANGER_ITEM_STATE_WAIT_CLEAN; - } - } - } - } - - return; -} - -static int -_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - uint8 action, uint8 ifid, uint8 iftype, uint8* ea, - f_processpkt_t fn, void *arg) -{ - int rc = BCME_OK; - - - if ((action == eWLFC_MAC_ENTRY_ACTION_ADD) || (action == eWLFC_MAC_ENTRY_ACTION_UPDATE)) { - entry->occupied = 1; - entry->state = WLFC_STATE_OPEN; - entry->requested_credit = 0; - entry->interface_id = ifid; - entry->iftype = iftype; - entry->ac_bitmap = 0xff; /* update this when handling APSD */ - /* for an interface entry we may not care about the MAC address */ - if (ea != NULL) - memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); - - if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { - dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); - pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); - if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { - pktq_init(&entry->afq, WLFC_AFQ_PREC_COUNT, WLFC_PSQ_LEN); - } - - if (entry->next == NULL) { - /* not linked to anywhere, add to tail */ - if (ctx->active_entry_head) { - entry->prev = ctx->active_entry_head->prev; - ctx->active_entry_head->prev->next = entry; - ctx->active_entry_head->prev = entry; - entry->next = ctx->active_entry_head; - - } else { - ASSERT(ctx->active_entry_count == 0); - entry->prev = entry->next = entry; - ctx->active_entry_head = entry; - } - ctx->active_entry_count++; - } else { - DHD_ERROR(("%s():%d, entry(%d)\n", __FUNCTION__, __LINE__, - (int)(entry - &ctx->destination_entries.nodes[0]))); - } - } - } else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { - /* When the entry is deleted, the packets that are queued in the entry must be - cleanup. The cleanup action should be before the occupied is set as 0. - */ - _dhd_wlfc_cleanup(ctx->dhdp, fn, arg); - _dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid); - - entry->occupied = 0; - entry->suppressed = 0; - entry->state = WLFC_STATE_CLOSE; - entry->requested_credit = 0; - entry->transit_count = 0; - entry->suppr_transit_count = 0; - memset(&entry->ea[0], 0, ETHER_ADDR_LEN); - - if (entry->next) { - /* not floating, remove from Q */ - if (ctx->active_entry_count <= 1) { - /* last item */ - ctx->active_entry_head = NULL; - ctx->active_entry_count = 0; - } else { - entry->prev->next = entry->next; - entry->next->prev = entry->prev; - if (entry == ctx->active_entry_head) { - ctx->active_entry_head = entry->next; - } - ctx->active_entry_count--; - } - entry->next = entry->prev = NULL; - } else { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - } - } - return rc; -} - -#ifdef LIMIT_BORROW -static int -_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, int highest_lender_ac, int borrower_ac) -{ - int lender_ac; - int rc = -1; - - if (ctx == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return -1; - } - - /* Borrow from lowest priority available AC (including BC/MC credits) */ - for (lender_ac = 0; lender_ac <= highest_lender_ac; lender_ac++) { - if (ctx->FIFO_credit[lender_ac] > 0) { - ctx->credits_borrowed[borrower_ac][lender_ac]++; - ctx->FIFO_credit[lender_ac]--; - rc = lender_ac; - break; - } - } - - return rc; -} - -static int _dhd_wlfc_return_credit(athost_wl_status_info_t* ctx, int lender_ac, int borrower_ac) -{ - if ((ctx == NULL) || (lender_ac < 0) || (lender_ac > AC_COUNT) || - (borrower_ac < 0) || (borrower_ac > AC_COUNT)) { - DHD_ERROR(("Error: %s():%d, ctx(%p), lender_ac(%d), borrower_ac(%d)\n", - __FUNCTION__, __LINE__, ctx, lender_ac, borrower_ac)); - - return BCME_BADARG; - } - - ctx->credits_borrowed[borrower_ac][lender_ac]--; - ctx->FIFO_credit[lender_ac]++; - - return BCME_OK; -} -#endif /* LIMIT_BORROW */ - -static int -_dhd_wlfc_interface_entry_update(void* state, - uint8 action, uint8 ifid, uint8 iftype, uint8* ea) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - wlfc_mac_descriptor_t* entry; - - if (ifid >= WLFC_MAX_IFNUM) - return BCME_BADARG; - - entry = &ctx->destination_entries.interfaces[ifid]; - - return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea, - _dhd_wlfc_ifpkt_fn, &ifid); -} - -static int -_dhd_wlfc_BCMCCredit_support_update(void* state) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - - ctx->bcmc_credit_supported = TRUE; - return BCME_OK; -} - -static int -_dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - int i; - - for (i = 0; i <= 4; i++) { - if (ctx->Init_FIFO_credit[i] != ctx->FIFO_credit[i]) { - DHD_ERROR(("%s: credit[i] is not returned, (%d %d)\n", - __FUNCTION__, ctx->Init_FIFO_credit[i], ctx->FIFO_credit[i])); - } - } - - /* update the AC FIFO credit map */ - ctx->FIFO_credit[0] += (credits[0] - ctx->Init_FIFO_credit[0]); - ctx->FIFO_credit[1] += (credits[1] - ctx->Init_FIFO_credit[1]); - ctx->FIFO_credit[2] += (credits[2] - ctx->Init_FIFO_credit[2]); - ctx->FIFO_credit[3] += (credits[3] - ctx->Init_FIFO_credit[3]); - ctx->FIFO_credit[4] += (credits[4] - ctx->Init_FIFO_credit[4]); - - ctx->Init_FIFO_credit[0] = credits[0]; - ctx->Init_FIFO_credit[1] = credits[1]; - ctx->Init_FIFO_credit[2] = credits[2]; - ctx->Init_FIFO_credit[3] = credits[3]; - ctx->Init_FIFO_credit[4] = credits[4]; - - /* credit for ATIM FIFO is not used yet. */ - ctx->Init_FIFO_credit[5] = ctx->FIFO_credit[5] = 0; - - return BCME_OK; -} - -static int -_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, - dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) -{ - uint32 hslot; - int rc; - dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); - - /* - if ac_fifo_credit_spent = 0 - - This packet will not count against the FIFO credit. - To ensure the txstatus corresponding to this packet - does not provide an implied credit (default behavior) - mark the packet accordingly. - - if ac_fifo_credit_spent = 1 - - This is a normal packet and it counts against the FIFO - credit count. - */ - DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); - rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, - commit_info->needs_hdr, &hslot); - - if (rc == BCME_OK) { - DHD_PKTTAG_WLFCPKT_SET(PKTTAG(commit_info->p), 1); - rc = fcommit(commit_ctx, commit_info->p); - if (rc == BCME_OK) { - uint8 gen = WL_TXSTATUS_GET_GENERATION( - DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))); - if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { - _dhd_wlfc_hanger_waitevent_set(ctx->hanger, hslot, - WLFC_HANGER_ITEM_WAIT_EVENT_COUNT); - } - ctx->stats.pkt2bus++; - if (commit_info->ac_fifo_credit_spent || (ac == AC_COUNT)) { - ctx->stats.send_pkts[ac]++; - WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); - } - - if (gen != commit_info->mac_entry->generation) { - /* will be suppressed back by design */ - if (!commit_info->mac_entry->suppressed) { - commit_info->mac_entry->suppressed = TRUE; - } - commit_info->mac_entry->suppr_transit_count++; - } - commit_info->mac_entry->transit_count++; - } else if (commit_info->needs_hdr) { - if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { - void *pout = NULL; - /* pop hanger for delayed packet */ - _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT( - DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))), &pout, 1); - ASSERT(commit_info->p == pout); - } - } - } else { - ctx->stats.generic_error++; - } - - if (rc != BCME_OK) { - /* - pretx pkt process or bus commit has failed, rollback. - - remove wl-header for a delayed packet - - save wl-header header for suppressed packets - - reset credit check flag - */ - _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, commit_info->pkt_type, hslot); - DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), 0); - } - - return rc; -} - -static uint8 -_dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) -{ - wlfc_mac_descriptor_t* table = - ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; - uint8 table_index; - - if (ea != NULL) { - for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { - if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && - table[table_index].occupied) - return table_index; - } - } - return WLFC_MAC_DESC_ID_INVALID; -} - -static int -_dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, void** p_mac) -{ - uint8 status_flag; - uint32 status; - int ret = BCME_OK; - int remove_from_hanger = 1; - void* pktbuf = NULL; - uint8 fifo_id = 0, gen = 0, count = 0, hcnt; - uint16 hslot; - wlfc_mac_descriptor_t* entry = NULL; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - uint16 seq = 0, seq_fromfw = 0, seq_num = 0; - - memcpy(&status, pkt_info, sizeof(uint32)); - status_flag = WL_TXSTATUS_GET_FLAGS(status); - hcnt = WL_TXSTATUS_GET_FREERUNCTR(status); - hslot = WL_TXSTATUS_GET_HSLOT(status); - fifo_id = WL_TXSTATUS_GET_FIFO(status); - gen = WL_TXSTATUS_GET_GENERATION(status); - - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { - memcpy(&seq, pkt_info + WLFC_CTL_VALUE_LEN_TXSTATUS, WLFC_CTL_VALUE_LEN_SEQ); - seq_fromfw = WL_SEQ_GET_FROMFW(seq); - seq_num = WL_SEQ_GET_NUM(seq); - } - - wlfc->stats.txstatus_in += len; - - if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { - wlfc->stats.pkt_freed += len; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_DISCARD_NOACK) { - wlfc->stats.pkt_freed += len; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { - wlfc->stats.d11_suppress += len; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { - wlfc->stats.wl_suppress += len; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { - wlfc->stats.wlc_tossed_pkts += len; - } - - if (dhd->proptxstatus_txstatus_ignore) { - if (!remove_from_hanger) { - DHD_ERROR(("suppress txstatus: %d\n", status_flag)); - } - return BCME_OK; - } - - while (count < len) { - if (WLFC_GET_AFQ(dhd->wlfc_mode)) { - ret = _dhd_wlfc_deque_afq(wlfc, hslot, hcnt, fifo_id, &pktbuf); - } else { - if (_dhd_wlfc_hanger_wait_clean(wlfc->hanger, hslot)) { - goto cont; - } - - ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, hslot, &pktbuf, 0); - } - - if ((ret != BCME_OK) || !pktbuf) { - goto cont; - } - - /* set fifo_id to correct value because not all FW does that */ - fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); - - entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); - - if (!remove_from_hanger) { - /* this packet was suppressed */ - if (!entry->suppressed || (entry->generation != gen)) { - if (!entry->suppressed) { - entry->suppr_transit_count = entry->transit_count; - if (p_mac) { - *p_mac = entry; - } - } else { - DHD_ERROR(("gen(%d), entry->generation(%d)\n", - gen, entry->generation)); - } - entry->suppressed = TRUE; - - } - entry->generation = gen; - } - -#ifdef PROP_TXSTATUS_DEBUG - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) - { - uint32 new_t = OSL_SYSUPTIME(); - uint32 old_t; - uint32 delta; - old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[hslot].push_time; - - - wlfc->stats.latency_sample_count++; - if (new_t > old_t) - delta = new_t - old_t; - else - delta = 0xffffffff + new_t - old_t; - wlfc->stats.total_status_latency += delta; - wlfc->stats.latency_most_recent = delta; - - wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; - if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) - wlfc->stats.idx_delta = 0; - } -#endif /* PROP_TXSTATUS_DEBUG */ - - /* pick up the implicit credit from this packet */ - if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { - _dhd_wlfc_return_implied_credit(wlfc, pktbuf); - } else { - /* - if this packet did not count against FIFO credit, it must have - taken a requested_credit from the destination entry (for pspoll etc.) - */ - if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) - entry->requested_credit++; -#ifdef PROP_TXSTATUS_DEBUG - entry->dstncredit_acks++; -#endif - } - - if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || - (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { - /* save generation bit inside packet */ - WL_TXSTATUS_SET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(pktbuf)), gen); - - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { - WL_SEQ_SET_FROMDRV(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_fromfw); - WL_SEQ_SET_NUM(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_num); - } - - ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); - if (ret != BCME_OK) { - /* delay q is full, drop this packet */ - DHD_WLFC_QMON_COMPLETE(entry); - _dhd_wlfc_prec_drop(dhd, (fifo_id << 1) + 1, pktbuf, FALSE); - } else { - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - /* Mark suppressed to avoid a double free - during wlfc cleanup - */ - _dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, hslot, gen); - } - } - } else { - uint8 waitevent = 0; - void *pktbuf_tmp = NULL; - dhd_txcomplete(dhd, pktbuf, TRUE); - - DHD_WLFC_QMON_COMPLETE(entry); - wlfc->stats.pktout++; - - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - waitevent = _dhd_wlfc_hanger_waitevent_decreturn(wlfc->hanger, - hslot); - if (!waitevent) { - ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, - hslot, &pktbuf_tmp, 1); - ASSERT((ret == BCME_OK) && (pktbuf == pktbuf_tmp)); - } - } - if (!waitevent) { - /* free the packet */ - PKTFREE(wlfc->osh, pktbuf, TRUE); - } - } - /* pkt back from firmware side */ - entry->transit_count--; - if (entry->suppressed && (--entry->suppr_transit_count == 0)) { - entry->suppressed = FALSE; - } - -cont: - hcnt = (hcnt + 1) & WL_TXSTATUS_FREERUNCTR_MASK; - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - hslot = (hslot + 1) & WL_TXSTATUS_HSLOT_MASK; - } - - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode) && seq_fromfw) { - seq_num = (seq_num + 1) & WL_SEQ_NUM_MASK; - } - - count++; - } - return BCME_OK; -} - -static int -_dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) -{ - int i; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { -#ifdef PROP_TXSTATUS_DEBUG - wlfc->stats.fifo_credits_back[i] += credits[i]; -#endif - - /* update FIFO credits */ - if (dhd->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) - { - int lender; /* Note that borrower is i */ - - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { - if (wlfc->credits_borrowed[i][lender] > 0) { - if (credits[i] >= wlfc->credits_borrowed[i][lender]) { - credits[i] -= - (uint8)wlfc->credits_borrowed[i][lender]; - wlfc->FIFO_credit[lender] += - wlfc->credits_borrowed[i][lender]; - wlfc->credits_borrowed[i][lender] = 0; - } - else { - wlfc->credits_borrowed[i][lender] -= credits[i]; - wlfc->FIFO_credit[lender] += credits[i]; - credits[i] = 0; - } - } - } - - /* If we have more credits left over, these must belong to the AC */ - if (credits[i] > 0) { - wlfc->FIFO_credit[i] += credits[i]; - } - - if (wlfc->FIFO_credit[i] > wlfc->Init_FIFO_credit[i]) { - wlfc->FIFO_credit[i] = wlfc->Init_FIFO_credit[i]; - } - } - } - - return BCME_OK; -} - -static void -_dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* entry; - int prec; - void *pkt = NULL, *head = NULL, *tail = NULL; - struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); - uint8 results[WLFC_CTL_VALUE_LEN_TXSTATUS+WLFC_CTL_VALUE_LEN_SEQ]; - uint8 credits[WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK] = {0}; - uint32 htod = 0; - uint16 htodseq = 0; - bool bCreditUpdate = FALSE; - - dhd_os_sdlock_txq(dhd); - for (prec = 0; prec < txq->num_prec; prec++) { - while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { - if (!head) { - head = pkt; - } - if (tail) { - PKTSETLINK(tail, pkt); - } - tail = pkt; - } - } - dhd_os_sdunlock_txq(dhd); - - while ((pkt = head)) { - head = PKTLINK(pkt); - PKTSETLINK(pkt, NULL); - - entry = _dhd_wlfc_find_table_entry(wlfc, pkt); - - /* fake a suppression txstatus */ - htod = DHD_PKTTAG_H2DTAG(PKTTAG(pkt)); - WL_TXSTATUS_SET_FLAGS(htod, WLFC_CTL_PKTFLAG_WLSUPPRESS); - WL_TXSTATUS_SET_GENERATION(htod, entry->generation); - memcpy(results, &htod, WLFC_CTL_VALUE_LEN_TXSTATUS); - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { - htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(pkt)); - if (WL_SEQ_GET_FROMDRV(htodseq)) { - WL_SEQ_SET_FROMFW(htodseq, 1); - WL_SEQ_SET_FROMDRV(htodseq, 0); - } - memcpy(results + WLFC_CTL_VALUE_LEN_TXSTATUS, &htodseq, - WLFC_CTL_VALUE_LEN_SEQ); - } - if (WLFC_GET_AFQ(dhd->wlfc_mode)) { - _dhd_wlfc_enque_afq(wlfc, pkt); - } - _dhd_wlfc_compressed_txstatus_update(dhd, results, 1, NULL); - - /* fake a fifo credit back */ - if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { - credits[DHD_PKTTAG_FIFO(PKTTAG(pkt))]++; - bCreditUpdate = TRUE; - } - } - - if (bCreditUpdate) { - _dhd_wlfc_fifocreditback_indicate(dhd, credits); - } -} - - -static int -_dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) -{ - uint32 timestamp; - - (void)dhd; - - bcopy(&value[2], ×tamp, sizeof(uint32)); - DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp)); - return BCME_OK; -} - -static int -_dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) -{ - (void)dhd; - (void)rssi; - return BCME_OK; -} - -static void -_dhd_wlfc_add_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) -{ - int i; - - if (!wlfc || !entry) { - return; - } - - for (i = 0; i < wlfc->requested_entry_count; i++) { - if (entry == wlfc->requested_entry[i]) { - break; - } - } - - if (i == wlfc->requested_entry_count) { - /* no match entry found */ - ASSERT(wlfc->requested_entry_count <= (WLFC_MAC_DESC_TABLE_SIZE-1)); - wlfc->requested_entry[wlfc->requested_entry_count++] = entry; - } -} - -static void -_dhd_wlfc_remove_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) -{ - int i; - - if (!wlfc || !entry) { - return; - } - - for (i = 0; i < wlfc->requested_entry_count; i++) { - if (entry == wlfc->requested_entry[i]) { - break; - } - } - - if (i < wlfc->requested_entry_count) { - /* found */ - ASSERT(wlfc->requested_entry_count > 0); - wlfc->requested_entry_count--; - if (i != wlfc->requested_entry_count) { - wlfc->requested_entry[i] = - wlfc->requested_entry[wlfc->requested_entry_count]; - } - wlfc->requested_entry[wlfc->requested_entry_count] = NULL; - } -} - -static int -_dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - int rc; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - uint8 existing_index; - uint8 table_index; - uint8 ifid; - uint8* ea; - - WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", - __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], - ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), - WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); - - table = wlfc->destination_entries.nodes; - table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); - ifid = value[1]; - ea = &value[2]; - - _dhd_wlfc_remove_requested_entry(wlfc, &table[table_index]); - if (type == WLFC_CTL_TYPE_MACDESC_ADD) { - existing_index = _dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); - if ((existing_index != WLFC_MAC_DESC_ID_INVALID) && - (existing_index != table_index) && table[existing_index].occupied) { - /* - there is an existing different entry, free the old one - and move it to new index if necessary. - */ - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[existing_index], - eWLFC_MAC_ENTRY_ACTION_DEL, table[existing_index].interface_id, - table[existing_index].iftype, NULL, _dhd_wlfc_entrypkt_fn, - &table[existing_index]); - } - - if (!table[table_index].occupied) { - /* this new MAC entry does not exist, create one */ - table[table_index].mac_handle = value[0]; - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], - eWLFC_MAC_ENTRY_ACTION_ADD, ifid, - wlfc->destination_entries.interfaces[ifid].iftype, - ea, NULL, NULL); - } else { - /* the space should have been empty, but it's not */ - wlfc->stats.mac_update_failed++; - } - } - - if (type == WLFC_CTL_TYPE_MACDESC_DEL) { - if (table[table_index].occupied) { - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], - eWLFC_MAC_ENTRY_ACTION_DEL, ifid, - wlfc->destination_entries.interfaces[ifid].iftype, - ea, _dhd_wlfc_entrypkt_fn, &table[table_index]); - } else { - /* the space should have been occupied, but it's not */ - wlfc->stats.mac_update_failed++; - } - } - BCM_REFERENCE(rc); - return BCME_OK; -} - -static int -_dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - /* Handle PS on/off indication */ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle = value[0]; - int i; - - table = wlfc->destination_entries.nodes; - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - /* a fresh PS mode should wipe old ps credits? */ - desc->requested_credit = 0; - if (type == WLFC_CTL_TYPE_MAC_OPEN) { - desc->state = WLFC_STATE_OPEN; - desc->ac_bitmap = 0xff; - DHD_WLFC_CTRINC_MAC_OPEN(desc); - _dhd_wlfc_remove_requested_entry(wlfc, desc); - } - else { - desc->state = WLFC_STATE_CLOSE; - DHD_WLFC_CTRINC_MAC_CLOSE(desc); - /* - Indicate to firmware if there is any traffic pending. - */ - for (i = 0; i < AC_COUNT; i++) { - _dhd_wlfc_traffic_pending_check(wlfc, desc, i); - } - } - } - else { - wlfc->stats.psmode_update_failed++; - } - return BCME_OK; -} - -static int -_dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - /* Handle PS on/off indication */ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - uint8 if_id = value[0]; - - if (if_id < WLFC_MAX_IFNUM) { - table = wlfc->destination_entries.interfaces; - if (table[if_id].occupied) { - if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { - table[if_id].state = WLFC_STATE_OPEN; - /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ - } - else { - table[if_id].state = WLFC_STATE_CLOSE; - /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ - } - return BCME_OK; - } - } - wlfc->stats.interface_update_failed++; - - return BCME_OK; -} - -static int -_dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle; - uint8 credit; - - table = wlfc->destination_entries.nodes; - mac_handle = value[1]; - credit = value[0]; - - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - desc->requested_credit = credit; - - desc->ac_bitmap = value[2] & (~(1<stats.credit_request_failed++; - } - return BCME_OK; -} - -static int -_dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle; - uint8 packet_count; - - table = wlfc->destination_entries.nodes; - mac_handle = value[1]; - packet_count = value[0]; - - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - desc->requested_packet = packet_count; - - desc->ac_bitmap = value[2] & (~(1<stats.packet_request_failed++; - } - return BCME_OK; -} - -static void -_dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) -{ - if (info_len) { - /* Check copy length to avoid buffer overrun. In case of length exceeding - * WLHOST_REORDERDATA_TOTLEN, return failure instead sending incomplete result - * of length WLHOST_REORDERDATA_TOTLEN - */ - if ((info_buf) && (len <= WLHOST_REORDERDATA_TOTLEN)) { - bcopy(val, info_buf, len); - *info_len = len; - } - else - *info_len = 0; - } -} - -/* - * public functions - */ - -bool dhd_wlfc_is_supported(dhd_pub_t *dhd) -{ - bool rc = TRUE; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return FALSE; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - rc = FALSE; - } - - dhd_os_wlfc_unblock(dhd); - - return rc; -} - -int dhd_wlfc_enable(dhd_pub_t *dhd) -{ - int i, rc = BCME_OK; - athost_wl_status_info_t* wlfc; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_enabled || dhd->wlfc_state) { - rc = BCME_OK; - goto exit; - } - - /* allocate space to track txstatus propagated from firmware */ - dhd->wlfc_state = DHD_OS_PREALLOC(dhd, DHD_PREALLOC_DHD_WLFC_INFO, - sizeof(athost_wl_status_info_t)); - if (dhd->wlfc_state == NULL) { - rc = BCME_NOMEM; - goto exit; - } - - /* initialize state space */ - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - memset(wlfc, 0, sizeof(athost_wl_status_info_t)); - - /* remember osh & dhdp */ - wlfc->osh = dhd->osh; - wlfc->dhdp = dhd; - - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - wlfc->hanger = _dhd_wlfc_hanger_create(dhd, WLFC_HANGER_MAXITEMS); - if (wlfc->hanger == NULL) { - DHD_OS_PREFREE(dhd, dhd->wlfc_state, - sizeof(athost_wl_status_info_t)); - dhd->wlfc_state = NULL; - rc = BCME_NOMEM; - goto exit; - } - } - - dhd->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; - /* default to check rx pkt */ - if (dhd->op_mode & DHD_FLAG_IBSS_MODE) { - dhd->wlfc_rxpkt_chk = FALSE; - } else { - dhd->wlfc_rxpkt_chk = TRUE; - } - - - /* initialize all interfaces to accept traffic */ - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - wlfc->hostif_flow_state[i] = OFF; - } - - _dhd_wlfc_mac_entry_update(wlfc, &wlfc->destination_entries.other, - eWLFC_MAC_ENTRY_ACTION_ADD, 0xff, 0, NULL, NULL, NULL); - - wlfc->allow_credit_borrow = 0; - wlfc->single_ac = 0; - wlfc->single_ac_timestamp = 0; - - -exit: - dhd_os_wlfc_unblock(dhd); - - return rc; -} - -int -dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, - uint *reorder_info_len) -{ - uint8 type, len; - uint8* value; - uint8* tmpbuf; - uint16 remainder = (uint16)tlv_hdr_len; - uint16 processed = 0; - athost_wl_status_info_t* wlfc = NULL; - void* entry; - - if ((dhd == NULL) || (pktbuf == NULL)) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (dhd->proptxstatus_mode != WLFC_ONLY_AMPDU_HOSTREORDER) { - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - } - - tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); - - if (remainder) { - while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { - type = tmpbuf[processed]; - if (type == WLFC_CTL_TYPE_FILLER) { - remainder -= 1; - processed += 1; - continue; - } - - len = tmpbuf[processed + 1]; - value = &tmpbuf[processed + 2]; - - if (remainder < (2 + len)) - break; - - remainder -= 2 + len; - processed += 2 + len; - entry = NULL; - - DHD_INFO(("%s():%d type %d remainder %d processed %d\n", - __FUNCTION__, __LINE__, type, remainder, processed)); - - if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) - _dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, - reorder_info_len); - - if (wlfc == NULL) { - ASSERT(dhd->proptxstatus_mode == WLFC_ONLY_AMPDU_HOSTREORDER); - - if (type != WLFC_CTL_TYPE_HOST_REORDER_RXPKTS && - type != WLFC_CTL_TYPE_TRANS_ID) - DHD_INFO(("%s():%d dhd->wlfc_state is NULL yet!" - " type %d remainder %d processed %d\n", - __FUNCTION__, __LINE__, type, remainder, processed)); - continue; - } - - if (type == WLFC_CTL_TYPE_TXSTATUS) { - _dhd_wlfc_compressed_txstatus_update(dhd, value, 1, &entry); - } - else if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) { - uint8 compcnt_offset = WLFC_CTL_VALUE_LEN_TXSTATUS; - - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { - compcnt_offset += WLFC_CTL_VALUE_LEN_SEQ; - } - _dhd_wlfc_compressed_txstatus_update(dhd, value, - value[compcnt_offset], &entry); - } - else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) - _dhd_wlfc_fifocreditback_indicate(dhd, value); - - else if (type == WLFC_CTL_TYPE_RSSI) - _dhd_wlfc_rssi_indicate(dhd, value); - - else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) - _dhd_wlfc_credit_request(dhd, value); - - else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) - _dhd_wlfc_packet_request(dhd, value); - - else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || - (type == WLFC_CTL_TYPE_MAC_CLOSE)) - _dhd_wlfc_psmode_update(dhd, value, type); - - else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || - (type == WLFC_CTL_TYPE_MACDESC_DEL)) - _dhd_wlfc_mac_table_update(dhd, value, type); - - else if (type == WLFC_CTL_TYPE_TRANS_ID) - _dhd_wlfc_dbg_senum_check(dhd, value); - - else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || - (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { - _dhd_wlfc_interface_update(dhd, value, type); - } - - if (entry && WLFC_GET_REORDERSUPP(dhd->wlfc_mode)) { - /* suppress all packets for this mac entry from bus->txq */ - _dhd_wlfc_suppress_txq(dhd, _dhd_wlfc_entrypkt_fn, entry); - } - } - if (remainder != 0 && wlfc) { - /* trouble..., something is not right */ - wlfc->stats.tlv_parse_failed++; - } - } - - if (wlfc) - wlfc->stats.dhd_hdrpulls++; - - dhd_os_wlfc_unblock(dhd); - return BCME_OK; -} - -int -dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf, - bool need_toggle_host_if) -{ - int ac, single_ac = 0, rc = BCME_OK; - dhd_wlfc_commit_info_t commit_info; - athost_wl_status_info_t* ctx; - int bus_retry_count = 0; - - uint8 tx_map = 0; /* packets (send + in queue), Bitmask for 4 ACs + BC/MC */ - uint8 rx_map = 0; /* received packets, Bitmask for 4 ACs + BC/MC */ - uint8 packets_map = 0; /* packets in queue, Bitmask for 4 ACs + BC/MC */ - bool no_credit = FALSE; - -#ifdef LIMIT_BORROW - int lender; -#endif - - if ((dhdp == NULL) || (fcommit == NULL)) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - if (pktbuf) { - DHD_PKTTAG_WLFCPKT_SET(PKTTAG(pktbuf), 0); - } - rc = WLFC_UNSUPPORTED; - goto exit2; - } - - ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; - - - if (dhdp->proptxstatus_module_ignore) { - if (pktbuf) { - uint32 htod = 0; - WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); - _dhd_wlfc_pushheader(ctx, pktbuf, FALSE, 0, 0, htod, 0, FALSE); - if (fcommit(commit_ctx, pktbuf)) - PKTFREE(ctx->osh, pktbuf, TRUE); - rc = BCME_OK; - } - goto exit; - } - - memset(&commit_info, 0, sizeof(commit_info)); - - /* - Commit packets for regular AC traffic. Higher priority first. - First, use up FIFO credits available to each AC. Based on distribution - and credits left, borrow from other ACs as applicable - - -NOTE: - If the bus between the host and firmware is overwhelmed by the - traffic from host, it is possible that higher priority traffic - starves the lower priority queue. If that occurs often, we may - have to employ weighted round-robin or ucode scheme to avoid - low priority packet starvation. - */ - - if (pktbuf) { - ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); - /* en-queue the packets to respective queue. */ - rc = _dhd_wlfc_enque_delayq(ctx, pktbuf, ac); - if (rc) - _dhd_wlfc_prec_drop(ctx->dhdp, (ac << 1), pktbuf, FALSE); - else - ctx->stats.pktin++; - } - - for (ac = AC_COUNT; ac >= 0; ac--) { - if (dhdp->wlfc_rxpkt_chk) { - /* check rx packet */ - uint32 curr_t = OSL_SYSUPTIME(), delta; - - delta = curr_t - ctx->rx_timestamp[ac]; - if (delta < WLFC_RX_DETECTION_THRESHOLD_MS) { - rx_map |= (1 << ac); - } - } - - if (ctx->pkt_cnt_per_ac[ac] == 0) { - continue; - } - tx_map |= (1 << ac); - single_ac = ac + 1; - while (FALSE == dhdp->proptxstatus_txoff) { - /* packets from delayQ with less priority are fresh and - * they'd need header and have no MAC entry - */ - no_credit = (ctx->FIFO_credit[ac] < 1); - if (dhdp->proptxstatus_credit_ignore || - ((ac == AC_COUNT) && !ctx->bcmc_credit_supported)) { - no_credit = FALSE; - } - commit_info.needs_hdr = 1; - commit_info.mac_entry = NULL; - commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, - &(commit_info.ac_fifo_credit_spent), - &(commit_info.needs_hdr), - &(commit_info.mac_entry), - no_credit); - commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : - eWLFC_PKTTYPE_SUPPRESSED; - - if (commit_info.p == NULL) { - break; - } - - if (!dhdp->proptxstatus_credit_ignore) { - ASSERT(ctx->FIFO_credit[ac] >= commit_info.ac_fifo_credit_spent); - } - /* here we can ensure have credit or no credit needed */ - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, fcommit, - commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent) - ctx->FIFO_credit[ac]--; - } else { - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); - goto exit; - } - } - } - - if (ctx->pkt_cnt_per_ac[ac]) { - packets_map |= (1 << ac); - } - } - - if ((tx_map == 0) || dhdp->proptxstatus_credit_ignore) { - /* nothing send out or remain in queue */ - rc = BCME_OK; - goto exit; - } - - if (((tx_map & (tx_map - 1)) == 0) && (tx_map >= rx_map)) { - /* only one tx ac exist and no higher rx ac */ - if ((single_ac == ctx->single_ac) && ctx->allow_credit_borrow) { - ac = single_ac - 1; - } else { - uint32 delta; - uint32 curr_t = OSL_SYSUPTIME(); - - if (single_ac != ctx->single_ac) { - /* new single ac traffic (first single ac or different single ac) */ - ctx->allow_credit_borrow = 0; - ctx->single_ac_timestamp = curr_t; - ctx->single_ac = (uint8)single_ac; - rc = BCME_OK; - goto exit; - } - /* same ac traffic, check if it lasts enough time */ - delta = curr_t - ctx->single_ac_timestamp; - - if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { - /* wait enough time, can borrow now */ - ctx->allow_credit_borrow = 1; - ac = single_ac - 1; - } else { - rc = BCME_OK; - goto exit; - } - } - } else { - /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ - ctx->allow_credit_borrow = 0; - ctx->single_ac_timestamp = 0; - ctx->single_ac = 0; - rc = BCME_OK; - goto exit; - } - - if (packets_map == 0) { - /* nothing to send, skip borrow */ - rc = BCME_OK; - goto exit; - } - - /* At this point, borrow all credits only for ac */ - while (FALSE == dhdp->proptxstatus_txoff) { -#ifdef LIMIT_BORROW - if ((lender = _dhd_wlfc_borrow_credit(ctx, AC_COUNT, ac)) == -1) { - break; - } -#endif - commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, - &(commit_info.ac_fifo_credit_spent), - &(commit_info.needs_hdr), - &(commit_info.mac_entry), - FALSE); - if (commit_info.p == NULL) { - /* before borrow only one ac exists and now this only ac is empty */ -#ifdef LIMIT_BORROW - _dhd_wlfc_return_credit(ctx, lender, ac); -#endif - break; - } - - commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : - eWLFC_PKTTYPE_SUPPRESSED; - - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - - if (commit_info.ac_fifo_credit_spent) { -#ifndef LIMIT_BORROW - ctx->FIFO_credit[ac]--; -#endif - } else { -#ifdef LIMIT_BORROW - _dhd_wlfc_return_credit(ctx, lender, ac); -#endif - } - } else { -#ifdef LIMIT_BORROW - _dhd_wlfc_return_credit(ctx, lender, ac); -#endif - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); - goto exit; - } - } - } - -exit: - if (need_toggle_host_if && ctx->toggle_host_if) { - ctx->toggle_host_if = 0; - } - -exit2: - dhd_os_wlfc_unblock(dhdp); - return rc; -} - -int -dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) -{ - athost_wl_status_info_t* wlfc; - void* pout = NULL; - int rtn = BCME_OK; - if ((dhd == NULL) || (txp == NULL)) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - rtn = WLFC_UNSUPPORTED; - goto EXIT; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { -#ifdef PROP_TXSTATUS_DEBUG - wlfc->stats.signal_only_pkts_freed++; -#endif - /* is this a signal-only packet? */ - _dhd_wlfc_pullheader(wlfc, txp); - PKTFREE(wlfc->osh, txp, TRUE); - goto EXIT; - } - - if (!success || dhd->proptxstatus_txstatus_ignore) { - wlfc_mac_descriptor_t *entry = _dhd_wlfc_find_table_entry(wlfc, txp); - - WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", - __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - _dhd_wlfc_hanger_poppkt(wlfc->hanger, WL_TXSTATUS_GET_HSLOT( - DHD_PKTTAG_H2DTAG(PKTTAG(txp))), &pout, 1); - ASSERT(txp == pout); - } - - /* indicate failure and free the packet */ - dhd_txcomplete(dhd, txp, success); - - /* return the credit, if necessary */ - _dhd_wlfc_return_implied_credit(wlfc, txp); - - entry->transit_count--; - if (entry->suppressed && (--entry->suppr_transit_count == 0)) { - entry->suppressed = FALSE; - } - - PKTFREE(wlfc->osh, txp, TRUE); - wlfc->stats.pktout++; - } else { - /* bus confirmed pkt went to firmware side */ - if (WLFC_GET_AFQ(dhd->wlfc_mode)) { - _dhd_wlfc_enque_afq(wlfc, txp); - } else { - int ret; - void *pktbuf_tmp = NULL; - int hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(txp))); - if (_dhd_wlfc_hanger_waitevent_decreturn(wlfc->hanger, hslot) == 0) { - ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, hslot, &pktbuf_tmp, 1); - BCM_REFERENCE(ret); - ASSERT((ret == BCME_OK) && pktbuf_tmp && (txp == pktbuf_tmp)); - - /* free the packet */ - PKTFREE(wlfc->osh, txp, TRUE); - } - } - } - -EXIT: - dhd_os_wlfc_unblock(dhd); - return rtn; -} - -int -dhd_wlfc_init(dhd_pub_t *dhd) -{ - char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */ - /* enable all signals & indicate host proptxstatus logic is active */ - uint32 tlv, mode, fw_caps; - int ret = 0; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - if (dhd->wlfc_enabled) { - DHD_ERROR(("%s():%d, Already enabled!\n", __FUNCTION__, __LINE__)); - dhd_os_wlfc_unblock(dhd); - return BCME_OK; - } - dhd->wlfc_enabled = TRUE; - dhd_os_wlfc_unblock(dhd); - - tlv = WLFC_FLAGS_RSSI_SIGNALS | - WLFC_FLAGS_XONXOFF_SIGNALS | - WLFC_FLAGS_CREDIT_STATUS_SIGNALS | - WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | - WLFC_FLAGS_HOST_RXRERODER_ACTIVE; - - - /* - try to enable/disable signaling by sending "tlv" iovar. if that fails, - fallback to no flow control? Print a message for now. - */ - - /* enable proptxtstatus signaling by default */ - ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); - } - else { - /* - Leaving the message for now, it should be removed after a while; once - the tlv situation is stable. - */ - DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", - dhd->wlfc_enabled?"enabled":"disabled", tlv)); - } - - /* query caps */ - ret = dhd_iovar(dhd, 0, "wlfc_mode", (char *)&mode, sizeof(mode), - iovbuf, sizeof(iovbuf), FALSE); - if (ret >= 0) { - fw_caps = *((uint32 *)iovbuf); - mode = 0; - DHD_ERROR(("%s: query wlfc_mode succeed, fw_caps=0x%x\n", __FUNCTION__, fw_caps)); - - if (WLFC_IS_OLD_DEF(fw_caps)) { - /* enable proptxtstatus v2 by default */ - mode = WLFC_MODE_AFQ; - } else { - WLFC_SET_AFQ(mode, WLFC_GET_AFQ(fw_caps)); - WLFC_SET_REUSESEQ(mode, WLFC_GET_REUSESEQ(fw_caps)); - WLFC_SET_REORDERSUPP(mode, WLFC_GET_REORDERSUPP(fw_caps)); - } - dhd_iovar(dhd, 0, "wlfc_mode", (char *)&mode, sizeof(mode), NULL, 0, TRUE); - } - - dhd_os_wlfc_block(dhd); - - dhd->wlfc_mode = 0; - if (ret >= 0) { - if (WLFC_IS_OLD_DEF(mode)) { - WLFC_SET_AFQ(dhd->wlfc_mode, (mode == WLFC_MODE_AFQ)); - } else { - dhd->wlfc_mode = mode; - } - } - DHD_ERROR(("dhd_wlfc_init(): wlfc_mode=0x%x, ret=%d\n", dhd->wlfc_mode, ret)); - - dhd_os_wlfc_unblock(dhd); - - if (dhd->plat_init) - dhd->plat_init((void *)dhd); - - return BCME_OK; -} - -int -dhd_wlfc_hostreorder_init(dhd_pub_t *dhd) -{ - /* enable only ampdu hostreorder here */ - uint32 tlv; - int ret; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - DHD_TRACE(("%s():%d Enter\n", __FUNCTION__, __LINE__)); - - tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; - - /* enable proptxtstatus signaling by default */ - ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s(): failed to enable/disable bdcv2 tlv signaling\n", - __FUNCTION__)); - } - else { - /* - Leaving the message for now, it should be removed after a while; once - the tlv situation is stable. - */ - DHD_ERROR(("%s(): successful bdcv2 tlv signaling, %d\n", - __FUNCTION__, tlv)); - } - - dhd_os_wlfc_block(dhd); - dhd->proptxstatus_mode = WLFC_ONLY_AMPDU_HOSTREORDER; - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -#ifdef SUPPORT_P2P_GO_PS -int -dhd_wlfc_suspend(dhd_pub_t *dhd) -{ - - uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ - uint32 tlv = 0; - int ret; - - DHD_TRACE(("%s: masking wlfc events\n", __FUNCTION__)); - if (!dhd->wlfc_enabled) - return -1; - - ret = dhd_iovar(dhd, 0, "tlv", NULL, 0, - (char *)iovbuf, sizeof(iovbuf), FALSE); - if (ret < 0) { - DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); - return -1; - } - tlv = iovbuf[0]; - if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == 0) - return 0; - tlv &= ~(WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); - - ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", - __FUNCTION__, tlv)); - return -1; - } - - return 0; -} - - int -dhd_wlfc_resume(dhd_pub_t *dhd) -{ - uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ - uint32 tlv = 0; - int ret; - - DHD_TRACE(("%s: unmasking wlfc events\n", __FUNCTION__)); - if (!dhd->wlfc_enabled) - return -1; - - ret = dhd_iovar(dhd, 0, "tlv", NULL, 0, - (char *)iovbuf, sizeof(iovbuf), FALSE); - if (ret < 0) { - DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); - return -1; - } - tlv = iovbuf[0]; - if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == - (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) - return 0; - tlv |= (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); - ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", - __FUNCTION__, tlv)); - return -1; - } - - return 0; -} -#endif /* SUPPORT_P2P_GO_PS */ - -int -dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - _dhd_wlfc_cleanup_txq(dhd, fn, arg); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -/* release all packet resources */ -int -dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) -{ - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - _dhd_wlfc_cleanup(dhd, fn, arg); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int -dhd_wlfc_deinit(dhd_pub_t *dhd) -{ - char iovbuf[32]; /* Room for "ampdu_hostreorder" or "tlv" + '\0' + parameter */ - /* cleanup all psq related resources */ - athost_wl_status_info_t* wlfc; - uint32 tlv = 0; - uint32 hostreorder = 0; - int ret = BCME_OK; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - if (!dhd->wlfc_enabled) { - DHD_ERROR(("%s():%d, Already disabled!\n", __FUNCTION__, __LINE__)); - dhd_os_wlfc_unblock(dhd); - return BCME_OK; - } - dhd->wlfc_enabled = FALSE; - dhd_os_wlfc_unblock(dhd); - - /* query ampdu hostreorder */ - ret = dhd_iovar(dhd, 0, "ampdu_hostreorder", NULL, 0, - (char *)iovbuf, sizeof(iovbuf), FALSE); - if (ret == BCME_OK) - hostreorder = *((uint32 *)iovbuf); - else { - hostreorder = 0; - DHD_ERROR(("%s():%d, ampdu_hostreorder get failed Err = %d\n", - __FUNCTION__, __LINE__, ret)); - } - - if (hostreorder) { - tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; - DHD_ERROR(("%s():%d, maintain HOST RXRERODER flag in tvl\n", - __FUNCTION__, __LINE__)); - } - - /* Disable proptxtstatus signaling for deinit */ - ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); - if (ret == BCME_OK) { - /* - Leaving the message for now, it should be removed after a while; once - the tlv situation is stable. - */ - DHD_ERROR(("%s():%d successfully %s bdcv2 tlv signaling, %d\n", - __FUNCTION__, __LINE__, - dhd->wlfc_enabled?"enabled":"disabled", tlv)); - } else - DHD_ERROR(("%s():%d failed to enable/disable bdcv2 tlv signaling Err = %d\n", - __FUNCTION__, __LINE__, ret)); - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - -#ifdef PROP_TXSTATUS_DEBUG - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) - { - int i; - wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; - for (i = 0; i < h->max_items; i++) { - if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { - WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", - __FUNCTION__, i, h->items[i].pkt, - DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); - } - } - } -#endif - - _dhd_wlfc_cleanup(dhd, NULL, NULL); - - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - /* delete hanger */ - _dhd_wlfc_hanger_delete(dhd, wlfc->hanger); - } - - - /* free top structure */ - DHD_OS_PREFREE(dhd, dhd->wlfc_state, - sizeof(athost_wl_status_info_t)); - dhd->wlfc_state = NULL; - dhd->proptxstatus_mode = hostreorder ? - WLFC_ONLY_AMPDU_HOSTREORDER : WLFC_FCMODE_NONE; - - dhd_os_wlfc_unblock(dhd); - - if (dhd->plat_deinit) - dhd->plat_deinit((void *)dhd); - return BCME_OK; -} - -int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea) -{ - int rc; - - if (dhdp == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhdp); - return WLFC_UNSUPPORTED; - } - - rc = _dhd_wlfc_interface_entry_update(dhdp->wlfc_state, action, ifid, iftype, ea); - - dhd_os_wlfc_unblock(dhdp); - return rc; -} - -int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data) -{ - int rc; - - if (dhdp == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhdp); - return WLFC_UNSUPPORTED; - } - - rc = _dhd_wlfc_FIFOcreditmap_update(dhdp->wlfc_state, event_data); - - dhd_os_wlfc_unblock(dhdp); - - return rc; -} - -int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp) -{ - int rc; - - if (dhdp == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhdp); - return WLFC_UNSUPPORTED; - } - - rc = _dhd_wlfc_BCMCCredit_support_update(dhdp->wlfc_state); - - dhd_os_wlfc_unblock(dhdp); - return rc; -} - -int -dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - int i; - uint8* ea; - athost_wl_status_info_t* wlfc; - wlfc_hanger_t* h; - wlfc_mac_descriptor_t* mac_table; - wlfc_mac_descriptor_t* interfaces; - char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; - - if (!dhdp || !strbuf) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhdp); - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhdp); - return WLFC_UNSUPPORTED; - } - - wlfc = (athost_wl_status_info_t*)dhdp->wlfc_state; - - h = (wlfc_hanger_t*)wlfc->hanger; - if (h == NULL) { - bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); - } - - mac_table = wlfc->destination_entries.nodes; - interfaces = wlfc->destination_entries.interfaces; - bcm_bprintf(strbuf, "---- wlfc stats ----\n"); - - if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { - h = (wlfc_hanger_t*)wlfc->hanger; - if (h == NULL) { - bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); - } else { - bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," - "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", - h->pushed, - h->popped, - h->failed_to_push, - h->failed_to_pop, - h->failed_slotfind, - (h->pushed - h->popped)); - } - } - - bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " - "(dq_full,rollback_fail) = (%d,%d,%d,%d), (%d,%d)\n", - wlfc->stats.tlv_parse_failed, - wlfc->stats.credit_request_failed, - wlfc->stats.mac_update_failed, - wlfc->stats.psmode_update_failed, - wlfc->stats.delayq_full_error, - wlfc->stats.rollback_failed); - - bcm_bprintf(strbuf, "PKTS (init_credit,credit,sent,drop_d,drop_s,outoforder) " - "(AC0[%d,%d,%d,%d,%d,%d],AC1[%d,%d,%d,%d,%d,%d],AC2[%d,%d,%d,%d,%d,%d]," - "AC3[%d,%d,%d,%d,%d,%d],BC_MC[%d,%d,%d,%d,%d,%d])\n", - wlfc->Init_FIFO_credit[0], wlfc->FIFO_credit[0], wlfc->stats.send_pkts[0], - wlfc->stats.drop_pkts[0], wlfc->stats.drop_pkts[1], wlfc->stats.ooo_pkts[0], - wlfc->Init_FIFO_credit[1], wlfc->FIFO_credit[1], wlfc->stats.send_pkts[1], - wlfc->stats.drop_pkts[2], wlfc->stats.drop_pkts[3], wlfc->stats.ooo_pkts[1], - wlfc->Init_FIFO_credit[2], wlfc->FIFO_credit[2], wlfc->stats.send_pkts[2], - wlfc->stats.drop_pkts[4], wlfc->stats.drop_pkts[5], wlfc->stats.ooo_pkts[2], - wlfc->Init_FIFO_credit[3], wlfc->FIFO_credit[3], wlfc->stats.send_pkts[3], - wlfc->stats.drop_pkts[6], wlfc->stats.drop_pkts[7], wlfc->stats.ooo_pkts[3], - wlfc->Init_FIFO_credit[4], wlfc->FIFO_credit[4], wlfc->stats.send_pkts[4], - wlfc->stats.drop_pkts[8], wlfc->stats.drop_pkts[9], wlfc->stats.ooo_pkts[4]); - - bcm_bprintf(strbuf, "\n"); - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (interfaces[i].occupied) { - char* iftype_desc; - - if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) - iftype_desc = "hostif_flow_state[i] == OFF) - ? " OFF":" ON")); - - bcm_bprintf(strbuf, "INTERFACE[%d].PSQ(len,state,credit),(trans,supp_trans)" - "= (%d,%s,%d),(%d,%d)\n", - i, - interfaces[i].psq.len, - ((interfaces[i].state == - WLFC_STATE_OPEN) ? "OPEN":"CLOSE"), - interfaces[i].requested_credit, - interfaces[i].transit_count, interfaces[i].suppr_transit_count); - - bcm_bprintf(strbuf, "INTERFACE[%d].PSQ" - "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," - "(delay3,sup3,afq3),(delay4,sup4,afq4) = (%d,%d,%d)," - "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", - i, - interfaces[i].psq.q[0].len, - interfaces[i].psq.q[1].len, - interfaces[i].afq.q[0].len, - interfaces[i].psq.q[2].len, - interfaces[i].psq.q[3].len, - interfaces[i].afq.q[1].len, - interfaces[i].psq.q[4].len, - interfaces[i].psq.q[5].len, - interfaces[i].afq.q[2].len, - interfaces[i].psq.q[6].len, - interfaces[i].psq.q[7].len, - interfaces[i].afq.q[3].len, - interfaces[i].psq.q[8].len, - interfaces[i].psq.q[9].len, - interfaces[i].afq.q[4].len); - } - } - - bcm_bprintf(strbuf, "\n"); - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (mac_table[i].occupied) { - ea = mac_table[i].ea; - bcm_bprintf(strbuf, "MAC_table[%d].ea = " - "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], - mac_table[i].interface_id); - - bcm_bprintf(strbuf, "MAC_table[%d].PSQ(len,state,credit),(trans,supp_trans)" - "= (%d,%s,%d),(%d,%d)\n", - i, - mac_table[i].psq.len, - ((mac_table[i].state == - WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), - mac_table[i].requested_credit, - mac_table[i].transit_count, mac_table[i].suppr_transit_count); -#ifdef PROP_TXSTATUS_DEBUG - bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", - i, mac_table[i].opened_ct, mac_table[i].closed_ct); -#endif - bcm_bprintf(strbuf, "MAC_table[%d].PSQ" - "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," - "(delay3,sup3,afq3),(delay4,sup4,afq4) =(%d,%d,%d)," - "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", - i, - mac_table[i].psq.q[0].len, - mac_table[i].psq.q[1].len, - mac_table[i].afq.q[0].len, - mac_table[i].psq.q[2].len, - mac_table[i].psq.q[3].len, - mac_table[i].afq.q[1].len, - mac_table[i].psq.q[4].len, - mac_table[i].psq.q[5].len, - mac_table[i].afq.q[2].len, - mac_table[i].psq.q[6].len, - mac_table[i].psq.q[7].len, - mac_table[i].afq.q[3].len, - mac_table[i].psq.q[8].len, - mac_table[i].psq.q[9].len, - mac_table[i].afq.q[4].len); - - } - } - -#ifdef PROP_TXSTATUS_DEBUG - { - int avg; - int moving_avg = 0; - int moving_samples; - - if (wlfc->stats.latency_sample_count) { - moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); - - for (i = 0; i < moving_samples; i++) - moving_avg += wlfc->stats.deltas[i]; - moving_avg /= moving_samples; - - avg = (100 * wlfc->stats.total_status_latency) / - wlfc->stats.latency_sample_count; - bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " - "(%d.%d, %03d, %03d)\n", - moving_samples, avg/100, (avg - (avg/100)*100), - wlfc->stats.latency_most_recent, - moving_avg); - } - } - - bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " - "back = (%d,%d,%d,%d,%d,%d)\n", - wlfc->stats.fifo_credits_sent[0], - wlfc->stats.fifo_credits_sent[1], - wlfc->stats.fifo_credits_sent[2], - wlfc->stats.fifo_credits_sent[3], - wlfc->stats.fifo_credits_sent[4], - wlfc->stats.fifo_credits_sent[5], - - wlfc->stats.fifo_credits_back[0], - wlfc->stats.fifo_credits_back[1], - wlfc->stats.fifo_credits_back[2], - wlfc->stats.fifo_credits_back[3], - wlfc->stats.fifo_credits_back[4], - wlfc->stats.fifo_credits_back[5]); - { - uint32 fifo_cr_sent = 0; - uint32 fifo_cr_acked = 0; - uint32 request_cr_sent = 0; - uint32 request_cr_ack = 0; - uint32 bc_mc_cr_ack = 0; - - for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { - fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; - } - - for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { - fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; - } - - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (wlfc->destination_entries.nodes[i].occupied) { - request_cr_sent += - wlfc->destination_entries.nodes[i].dstncredit_sent_packets; - } - } - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (wlfc->destination_entries.interfaces[i].occupied) { - request_cr_sent += - wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; - } - } - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (wlfc->destination_entries.nodes[i].occupied) { - request_cr_ack += - wlfc->destination_entries.nodes[i].dstncredit_acks; - } - } - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (wlfc->destination_entries.interfaces[i].occupied) { - request_cr_ack += - wlfc->destination_entries.interfaces[i].dstncredit_acks; - } - } - bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," - "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", - fifo_cr_sent, fifo_cr_acked, - request_cr_sent, request_cr_ack, - wlfc->destination_entries.other.dstncredit_acks, - bc_mc_cr_ack, - wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); - } -#endif /* PROP_TXSTATUS_DEBUG */ - bcm_bprintf(strbuf, "\n"); - bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull,out),(dropped,hdr_only,wlc_tossed)" - "(freed,free_err,rollback)) = " - "((%d,%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", - wlfc->stats.pktin, - wlfc->stats.pkt2bus, - wlfc->stats.txstatus_in, - wlfc->stats.dhd_hdrpulls, - wlfc->stats.pktout, - - wlfc->stats.pktdropped, - wlfc->stats.wlfc_header_only_pkt, - wlfc->stats.wlc_tossed_pkts, - - wlfc->stats.pkt_freed, - wlfc->stats.pkt_free_err, wlfc->stats.rollback); - - bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " - "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", - wlfc->stats.d11_suppress, - wlfc->stats.wl_suppress, - wlfc->stats.bad_suppress, - - wlfc->stats.psq_d11sup_enq, - wlfc->stats.psq_wlsup_enq, - wlfc->stats.psq_hostq_enq, - wlfc->stats.mac_handle_notfound, - - wlfc->stats.psq_d11sup_retx, - wlfc->stats.psq_wlsup_retx, - wlfc->stats.psq_hostq_retx); - - bcm_bprintf(strbuf, "wlfc- cleanup(txq,psq,fw) = (%d,%d,%d)\n", - wlfc->stats.cleanup_txq_cnt, - wlfc->stats.cleanup_psq_cnt, - wlfc->stats.cleanup_fw_cnt); - - bcm_bprintf(strbuf, "wlfc- generic error: %d\n", wlfc->stats.generic_error); - - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - bcm_bprintf(strbuf, "wlfc- if[%d], pkt_cnt_in_q/AC[0-4] = (%d,%d,%d,%d,%d)\n", i, - wlfc->pkt_cnt_in_q[i][0], - wlfc->pkt_cnt_in_q[i][1], - wlfc->pkt_cnt_in_q[i][2], - wlfc->pkt_cnt_in_q[i][3], - wlfc->pkt_cnt_in_q[i][4]); - } - bcm_bprintf(strbuf, "\n"); - - dhd_os_wlfc_unblock(dhdp); - return BCME_OK; -} - -int dhd_wlfc_clear_counts(dhd_pub_t *dhd) -{ - athost_wl_status_info_t* wlfc; - wlfc_hanger_t* hanger; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - - memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); - - if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { - hanger = (wlfc_hanger_t*)wlfc->hanger; - - hanger->pushed = 0; - hanger->popped = 0; - hanger->failed_slotfind = 0; - hanger->failed_to_pop = 0; - hanger->failed_to_push = 0; - } - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->wlfc_enabled; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->wlfc_state ? dhd->proptxstatus_mode : 0; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val) -{ - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (dhd->wlfc_state) { - dhd->proptxstatus_mode = val & 0xff; - } - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf) -{ - athost_wl_status_info_t* wlfc; - bool rc = FALSE; - - if (dhd == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return FALSE; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return FALSE; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - - if (PKTLEN(wlfc->osh, pktbuf) == 0) { - wlfc->stats.wlfc_header_only_pkt++; - rc = TRUE; - } - - dhd_os_wlfc_unblock(dhd); - - return rc; -} - -int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock) -{ - if (dhdp == NULL) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - if (bAcquireLock) { - dhd_os_wlfc_block(dhdp); - } - - if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE) || - dhdp->proptxstatus_module_ignore) { - if (bAcquireLock) { - dhd_os_wlfc_unblock(dhdp); - } - return WLFC_UNSUPPORTED; - } - - if (state != dhdp->proptxstatus_txoff) { - dhdp->proptxstatus_txoff = state; - } - - if (bAcquireLock) { - dhd_os_wlfc_unblock(dhdp); - } - - return BCME_OK; -} - -int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio) -{ - athost_wl_status_info_t* wlfc; - int rx_path_ac = -1; - - if ((dhd == NULL) || (prio >= NUMPRIO)) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if (!dhd->wlfc_rxpkt_chk) { - dhd_os_wlfc_unblock(dhd); - return BCME_OK; - } - - if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { - dhd_os_wlfc_unblock(dhd); - return WLFC_UNSUPPORTED; - } - - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - - rx_path_ac = prio2fifo[prio]; - wlfc->rx_timestamp[rx_path_ac] = OSL_SYSUPTIME(); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->proptxstatus_module_ignore; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val) -{ - uint32 tlv = 0; - bool bChanged = FALSE; - int ret; - - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - if ((bool)val != dhd->proptxstatus_module_ignore) { - dhd->proptxstatus_module_ignore = (val != 0); - /* force txstatus_ignore sync with proptxstatus_module_ignore */ - dhd->proptxstatus_txstatus_ignore = dhd->proptxstatus_module_ignore; - if (FALSE == dhd->proptxstatus_module_ignore) { - tlv = WLFC_FLAGS_RSSI_SIGNALS | - WLFC_FLAGS_XONXOFF_SIGNALS | - WLFC_FLAGS_CREDIT_STATUS_SIGNALS | - WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE; - } - /* always enable host reorder */ - tlv |= WLFC_FLAGS_HOST_RXRERODER_ACTIVE; - bChanged = TRUE; - } - - dhd_os_wlfc_unblock(dhd); - - if (bChanged) { - /* select enable proptxtstatus signaling */ - ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", - __FUNCTION__, tlv)); - } - else { - DHD_ERROR(("%s: successfully set bdcv2 tlv signaling to 0x%x\n", - __FUNCTION__, tlv)); - } - } - return BCME_OK; -} - -int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->proptxstatus_credit_ignore; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val) -{ - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - dhd->proptxstatus_credit_ignore = (val != 0); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->proptxstatus_txstatus_ignore; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val) -{ - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - dhd->proptxstatus_txstatus_ignore = (val != 0); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val) -{ - if (!dhd || !val) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - *val = dhd->wlfc_rxpkt_chk; - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} - -int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val) -{ - if (!dhd) { - DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - dhd_os_wlfc_block(dhd); - - dhd->wlfc_rxpkt_chk = (val != 0); - - dhd_os_wlfc_unblock(dhd); - - return BCME_OK; -} -#endif /* PROP_TXSTATUS */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h b/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h deleted file mode 100755 index 347c1bcbea46..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h +++ /dev/null @@ -1,513 +0,0 @@ -/* -* Copyright (C) 1999-2018, Broadcom Corporation -* -* Unless you and Broadcom execute a separate written software license -* agreement governing use of this software, this software is licensed to you -* under the terms of the GNU General Public License version 2 (the "GPL"), -* available at http://www.broadcom.com/licenses/GPLv2.php, with the -* following added to such license: -* -* As a special exception, the copyright holders of this software give you -* permission to link this software with independent modules, and to copy and -* distribute the resulting executable under terms of your choice, provided that -* you also meet, for each linked independent module, the terms and conditions of -* the license of that module. An independent module is a module which is not -* derived from this software. The special exception does not apply to any -* modifications of the software. -* -* Notwithstanding the above, under no circumstances may you combine this -* software in any way with any other Broadcom software provided under a license -* other than the GPL, without Broadcom's express prior written consent. -* $Id: dhd_wlfc.h 485659 2014-06-16 21:33:12Z $ -* -*/ -#ifndef __wlfc_host_driver_definitions_h__ -#define __wlfc_host_driver_definitions_h__ - - -/* #define OOO_DEBUG */ - -#define WLFC_UNSUPPORTED -9999 - -#define WLFC_NO_TRAFFIC -1 -#define WLFC_MULTI_TRAFFIC 0 - -#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ - -/* 16 bits will provide an absolute max of 65536 slots */ -#define WLFC_HANGER_MAXITEMS 3072 - -#define WLFC_HANGER_ITEM_STATE_FREE 1 -#define WLFC_HANGER_ITEM_STATE_INUSE 2 -#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 -#define WLFC_HANGER_ITEM_STATE_WAIT_CLEAN 4 - -#define WLFC_HANGER_ITEM_WAIT_EVENT_COUNT 2 -#define WLFC_HANGER_ITEM_WAIT_EVENT_INVALID 255 - -typedef enum { - Q_TYPE_PSQ, - Q_TYPE_AFQ -} q_type_t; - -typedef enum ewlfc_packet_state { - eWLFC_PKTTYPE_NEW, - eWLFC_PKTTYPE_DELAYED, - eWLFC_PKTTYPE_SUPPRESSED, - eWLFC_PKTTYPE_MAX -} ewlfc_packet_state_t; - -typedef enum ewlfc_mac_entry_action { - eWLFC_MAC_ENTRY_ACTION_ADD, - eWLFC_MAC_ENTRY_ACTION_DEL, - eWLFC_MAC_ENTRY_ACTION_UPDATE, - eWLFC_MAC_ENTRY_ACTION_MAX -} ewlfc_mac_entry_action_t; - -typedef struct wlfc_hanger_item { - uint8 state; - uint8 gen; - uint8 waitevent; /* wait txstatus_update and txcomplete before free a packet */ - uint8 pad; - uint32 identifier; - void* pkt; -#ifdef PROP_TXSTATUS_DEBUG - uint32 push_time; -#endif - struct wlfc_hanger_item *next; -} wlfc_hanger_item_t; - -typedef struct wlfc_hanger { - int max_items; - uint32 pushed; - uint32 popped; - uint32 failed_to_push; - uint32 failed_to_pop; - uint32 failed_slotfind; - uint32 slot_pos; - wlfc_hanger_item_t items[1]; -} wlfc_hanger_t; - -#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ - sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) - -#define WLFC_STATE_OPEN 1 -#define WLFC_STATE_CLOSE 2 - -#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ -#define WLFC_AFQ_PREC_COUNT (AC_COUNT + 1) - -#define WLFC_PSQ_LEN 2048 - -#define WLFC_FLOWCONTROL_HIWATER (2048 - 256) -#define WLFC_FLOWCONTROL_LOWATER 256 - -#define WLFC_LOG_BUF_SIZE (1024*1024) - -typedef struct wlfc_mac_descriptor { - uint8 occupied; - uint8 interface_id; - uint8 iftype; - uint8 state; - uint8 ac_bitmap; /* for APSD */ - uint8 requested_credit; - uint8 requested_packet; - uint8 ea[ETHER_ADDR_LEN]; - /* - maintain (MAC,AC) based seq count for - packets going to the device. As well as bc/mc. - */ - uint8 seq[AC_COUNT + 1]; - uint8 generation; - struct pktq psq; - /* packets at firmware */ - struct pktq afq; - /* The AC pending bitmap that was reported to the fw at last change */ - uint8 traffic_lastreported_bmp; - /* The new AC pending bitmap */ - uint8 traffic_pending_bmp; - /* 1= send on next opportunity */ - uint8 send_tim_signal; - uint8 mac_handle; - /* Number of packets at dongle for this entry. */ - uint transit_count; - /* Numbe of suppression to wait before evict from delayQ */ - uint suppr_transit_count; - /* flag. TRUE when in suppress state */ - uint8 suppressed; - - -#ifdef PROP_TXSTATUS_DEBUG - uint32 dstncredit_sent_packets; - uint32 dstncredit_acks; - uint32 opened_ct; - uint32 closed_ct; -#endif - struct wlfc_mac_descriptor* prev; - struct wlfc_mac_descriptor* next; -} wlfc_mac_descriptor_t; - -typedef struct dhd_wlfc_commit_info { - uint8 needs_hdr; - uint8 ac_fifo_credit_spent; - ewlfc_packet_state_t pkt_type; - wlfc_mac_descriptor_t* mac_entry; - void* p; -} dhd_wlfc_commit_info_t; - -#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ - entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) - -#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ -#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] - -typedef struct athost_wl_stat_counters { - uint32 pktin; - uint32 pktout; - uint32 pkt2bus; - uint32 pktdropped; - uint32 tlv_parse_failed; - uint32 rollback; - uint32 rollback_failed; - uint32 delayq_full_error; - uint32 credit_request_failed; - uint32 packet_request_failed; - uint32 mac_update_failed; - uint32 psmode_update_failed; - uint32 interface_update_failed; - uint32 wlfc_header_only_pkt; - uint32 txstatus_in; - uint32 d11_suppress; - uint32 wl_suppress; - uint32 bad_suppress; - uint32 pkt_freed; - uint32 pkt_free_err; - uint32 psq_wlsup_retx; - uint32 psq_wlsup_enq; - uint32 psq_d11sup_retx; - uint32 psq_d11sup_enq; - uint32 psq_hostq_retx; - uint32 psq_hostq_enq; - uint32 mac_handle_notfound; - uint32 wlc_tossed_pkts; - uint32 dhd_hdrpulls; - uint32 generic_error; - /* an extra one for bc/mc traffic */ - uint32 send_pkts[AC_COUNT + 1]; - uint32 drop_pkts[WLFC_PSQ_PREC_COUNT]; - uint32 ooo_pkts[AC_COUNT + 1]; -#ifdef PROP_TXSTATUS_DEBUG - /* all pkt2bus -> txstatus latency accumulated */ - uint32 latency_sample_count; - uint32 total_status_latency; - uint32 latency_most_recent; - int idx_delta; - uint32 deltas[10]; - uint32 fifo_credits_sent[6]; - uint32 fifo_credits_back[6]; - uint32 dropped_qfull[6]; - uint32 signal_only_pkts_sent; - uint32 signal_only_pkts_freed; -#endif - uint32 cleanup_txq_cnt; - uint32 cleanup_psq_cnt; - uint32 cleanup_fw_cnt; -} athost_wl_stat_counters_t; - -#ifdef PROP_TXSTATUS_DEBUG -#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ - (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) -#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ - (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) -#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ - (ctx)->stats.dropped_qfull[(ac)]++;} while (0) -#else -#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) -#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) -#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) -#endif - -#define WLFC_FCMODE_NONE 0 -#define WLFC_FCMODE_IMPLIED_CREDIT 1 -#define WLFC_FCMODE_EXPLICIT_CREDIT 2 -#define WLFC_ONLY_AMPDU_HOSTREORDER 3 - -/* How long to defer borrowing in milliseconds */ -#define WLFC_BORROW_DEFER_PERIOD_MS 100 - -/* How long to defer flow control in milliseconds */ -#define WLFC_FC_DEFER_PERIOD_MS 200 - -/* How long to detect occurance per AC in miliseconds */ -#define WLFC_RX_DETECTION_THRESHOLD_MS 100 - -/* Mask to represent available ACs (note: BC/MC is ignored */ -#define WLFC_AC_MASK 0xF - -typedef struct athost_wl_status_info { - uint8 last_seqid_to_wlc; - - /* OSL handle */ - osl_t* osh; - /* dhd pub */ - void* dhdp; - - /* stats */ - athost_wl_stat_counters_t stats; - - int Init_FIFO_credit[AC_COUNT + 2]; - - /* the additional ones are for bc/mc and ATIM FIFO */ - int FIFO_credit[AC_COUNT + 2]; - - /* Credit borrow counts for each FIFO from each of the other FIFOs */ - int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; - - /* packet hanger and MAC->handle lookup table */ - void* hanger; - struct { - /* table for individual nodes */ - wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; - /* table for interfaces */ - wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; - /* OS may send packets to unknown (unassociated) destinations */ - /* A place holder for bc/mc and packets to unknown destinations */ - wlfc_mac_descriptor_t other; - } destination_entries; - - wlfc_mac_descriptor_t *active_entry_head; - int active_entry_count; - - wlfc_mac_descriptor_t* requested_entry[WLFC_MAC_DESC_TABLE_SIZE]; - int requested_entry_count; - - /* pkt counts for each interface and ac */ - int pkt_cnt_in_q[WLFC_MAX_IFNUM][AC_COUNT+1]; - int pkt_cnt_per_ac[AC_COUNT+1]; - uint8 allow_fc; - uint32 fc_defer_timestamp; - uint32 rx_timestamp[AC_COUNT+1]; - /* ON/OFF state for flow control to the host network interface */ - uint8 hostif_flow_state[WLFC_MAX_IFNUM]; - uint8 host_ifidx; - /* to flow control an OS interface */ - uint8 toggle_host_if; - - /* To borrow credits */ - uint8 allow_credit_borrow; - - /* ac number for the first single ac traffic */ - uint8 single_ac; - - /* Timestamp for the first single ac traffic */ - uint32 single_ac_timestamp; - - bool bcmc_credit_supported; - -} athost_wl_status_info_t; - -/* Please be mindful that total pkttag space is 32 octets only */ -typedef struct dhd_pkttag { - /* - b[15] - 1 = wlfc packet - b[14:13] - encryption exemption - b[12 ] - 1 = event channel - b[11 ] - 1 = this packet was sent in response to one time packet request, - do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. - b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] - b[9 ] - 1 = packet is host->firmware (transmit direction) - - 0 = packet received from firmware (firmware->host) - b[8 ] - 1 = packet was sent due to credit_request (pspoll), - packet does not count against FIFO credit. - - 0 = normal transaction, packet counts against FIFO credit - b[7 ] - 1 = AP, 0 = STA - b[6:4] - AC FIFO number - b[3:0] - interface index - */ - uint16 if_flags; - /* destination MAC address for this packet so that not every - module needs to open the packet to find this - */ - uint8 dstn_ether[ETHER_ADDR_LEN]; - /* - This 32-bit goes from host to device for every packet. - */ - uint32 htod_tag; - - /* - This 16-bit is original seq number for every suppress packet. - */ - uint16 htod_seq; - - /* - This address is mac entry for every packet. - */ - void* entry; - /* bus specific stuff */ - union { - struct { - void* stuff; - uint32 thing1; - uint32 thing2; - } sd; - struct { - void* bus; - void* urb; - } usb; - } bus_specific; -} dhd_pkttag_t; - -#define DHD_PKTTAG_WLFCPKT_MASK 0x1 -#define DHD_PKTTAG_WLFCPKT_SHIFT 15 -#define DHD_PKTTAG_WLFCPKT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_WLFCPKT_MASK << DHD_PKTTAG_WLFCPKT_SHIFT)) | \ - (((value) & DHD_PKTTAG_WLFCPKT_MASK) << DHD_PKTTAG_WLFCPKT_SHIFT) -#define DHD_PKTTAG_WLFCPKT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_WLFCPKT_SHIFT) & DHD_PKTTAG_WLFCPKT_MASK) - -#define DHD_PKTTAG_EXEMPT_MASK 0x3 -#define DHD_PKTTAG_EXEMPT_SHIFT 13 -#define DHD_PKTTAG_EXEMPT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_EXEMPT_MASK << DHD_PKTTAG_EXEMPT_SHIFT)) | \ - (((value) & DHD_PKTTAG_EXEMPT_MASK) << DHD_PKTTAG_EXEMPT_SHIFT) -#define DHD_PKTTAG_EXEMPT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_EXEMPT_SHIFT) & DHD_PKTTAG_EXEMPT_MASK) - -#define DHD_PKTTAG_EVENT_MASK 0x1 -#define DHD_PKTTAG_EVENT_SHIFT 12 -#define DHD_PKTTAG_SETEVENT(tag, event) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_EVENT_MASK << DHD_PKTTAG_EVENT_SHIFT)) | \ - (((event) & DHD_PKTTAG_EVENT_MASK) << DHD_PKTTAG_EVENT_SHIFT) -#define DHD_PKTTAG_EVENT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_EVENT_SHIFT) & DHD_PKTTAG_EVENT_MASK) - -#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 -#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 -#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ - (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) -#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) - -#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 -#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 -#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ - (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) -#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) - -#define DHD_PKTTAG_PKTDIR_MASK 0x1 -#define DHD_PKTTAG_PKTDIR_SHIFT 9 -#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ - (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) -#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) - -#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 -#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 -#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ - (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) -#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) - -#define DHD_PKTTAG_IFTYPE_MASK 0x1 -#define DHD_PKTTAG_IFTYPE_SHIFT 7 -#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ - (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) -#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) - -#define DHD_PKTTAG_FIFO_MASK 0x7 -#define DHD_PKTTAG_FIFO_SHIFT 4 -#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ - (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) -#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) - -#define DHD_PKTTAG_IF_MASK 0xf -#define DHD_PKTTAG_IF_SHIFT 0 -#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_IF_MASK << DHD_PKTTAG_IF_SHIFT)) | \ - (((if) & DHD_PKTTAG_IF_MASK) << DHD_PKTTAG_IF_SHIFT) -#define DHD_PKTTAG_IF(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_IF_SHIFT) & DHD_PKTTAG_IF_MASK) - -#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ - (dstn_MAC_ea), ETHER_ADDR_LEN) -#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether - -#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) -#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) - -#define DHD_PKTTAG_SET_H2DSEQ(tag, seq) ((dhd_pkttag_t*)(tag))->htod_seq = (seq) -#define DHD_PKTTAG_H2DSEQ(tag) (((dhd_pkttag_t*)(tag))->htod_seq) - -#define DHD_PKTTAG_SET_ENTRY(tag, entry) ((dhd_pkttag_t*)(tag))->entry = (entry) -#define DHD_PKTTAG_ENTRY(tag) (((dhd_pkttag_t*)(tag))->entry) - -#define PSQ_SUP_IDX(x) (x * 2 + 1) -#define PSQ_DLY_IDX(x) (x * 2) - -typedef int (*f_commitpkt_t)(void* ctx, void* p); -typedef bool (*f_processpkt_t)(void* p, void* arg); - -#ifdef PROP_TXSTATUS_DEBUG -#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) -#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) -#else -#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) -#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) -#endif - -/* public functions */ -int dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, - uchar *reorder_info_buf, uint *reorder_info_len); -int dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, - void* commit_ctx, void *pktbuf, bool need_toggle_host_if); -int dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); -int dhd_wlfc_init(dhd_pub_t *dhd); -int dhd_wlfc_hostreorder_init(dhd_pub_t *dhd); -#ifdef SUPPORT_P2P_GO_PS -int dhd_wlfc_suspend(dhd_pub_t *dhd); -int dhd_wlfc_resume(dhd_pub_t *dhd); -#endif /* SUPPORT_P2P_GO_PS */ -int dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg); -int dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void* arg); -int dhd_wlfc_deinit(dhd_pub_t *dhd); -int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea); -int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data); -int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp); -int dhd_wlfc_enable(dhd_pub_t *dhdp); -int dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); -int dhd_wlfc_clear_counts(dhd_pub_t *dhd); -int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val); -int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val); -bool dhd_wlfc_is_supported(dhd_pub_t *dhd); -bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf); -int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock); -int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio); - -int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val); -int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val); -int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val); - -int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val); -int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val); -#endif /* __wlfc_host_driver_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h b/drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h deleted file mode 100755 index cd499133dcc7..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Common stats definitions for clients of dongle - * ports - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dngl_stats.h 604675 2015-12-08 06:42:14Z $ - */ - -#ifndef _dngl_stats_h_ -#define _dngl_stats_h_ - -typedef struct { - 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 */ -} dngl_stats_t; - -#ifdef LINKSTAT_SUPPORT -typedef int wifi_radio; -typedef int wifi_channel; -typedef int wifi_rssi; - -typedef enum wifi_channel_width { - WIFI_CHAN_WIDTH_20 = 0, - WIFI_CHAN_WIDTH_40 = 1, - WIFI_CHAN_WIDTH_80 = 2, - WIFI_CHAN_WIDTH_160 = 3, - WIFI_CHAN_WIDTH_80P80 = 4, - WIFI_CHAN_WIDTH_5 = 5, - WIFI_CHAN_WIDTH_10 = 6, - WIFI_CHAN_WIDTH_INVALID = -1 -} wifi_channel_width_t; - -typedef enum { - WIFI_DISCONNECTED = 0, - WIFI_AUTHENTICATING = 1, - WIFI_ASSOCIATING = 2, - WIFI_ASSOCIATED = 3, - WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ - WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ -} wifi_connection_state; - -typedef enum { - WIFI_ROAMING_IDLE = 0, - WIFI_ROAMING_ACTIVE = 1 -} wifi_roam_state; - -typedef enum { - WIFI_INTERFACE_STA = 0, - WIFI_INTERFACE_SOFTAP = 1, - WIFI_INTERFACE_IBSS = 2, - WIFI_INTERFACE_P2P_CLIENT = 3, - WIFI_INTERFACE_P2P_GO = 4, - WIFI_INTERFACE_NAN = 5, - WIFI_INTERFACE_MESH = 6 -} wifi_interface_mode; - -/* set for QOS association */ -#define WIFI_CAPABILITY_QOS 0x00000001 -/* set for protected association (802.11 beacon frame control protected bit set) */ -#define WIFI_CAPABILITY_PROTECTED 0x00000002 -/* set if 802.11 Extended Capabilities element interworking bit is set */ -#define WIFI_CAPABILITY_INTERWORKING 0x00000004 -/* set for HS20 association */ -#define WIFI_CAPABILITY_HS20 0x00000008 -/* set is 802.11 Extended Capabilities element UTF-8 SSID bit is set */ -#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 -/* set is 802.11 Country Element is present */ -#define WIFI_CAPABILITY_COUNTRY 0x00000020 - -typedef struct { - wifi_interface_mode mode; /* interface mode */ - uint8 mac_addr[6]; /* interface mac address (self) */ - wifi_connection_state state; /* connection state (valid for STA, CLI only) */ - wifi_roam_state roaming; /* roaming state */ - uint32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ - uint8 ssid[33]; /* null terminated SSID */ - uint8 bssid[6]; /* bssid */ - uint8 ap_country_str[3]; /* country string advertised by AP */ - uint8 country_str[3]; /* country string for this association */ -} wifi_interface_info; - -typedef wifi_interface_info *wifi_interface_handle; - -/* channel information */ -typedef struct { - wifi_channel_width_t width; /* channel width (20, 40, 80, 80+80, 160) */ - wifi_channel center_freq; /* primary 20 MHz channel */ - wifi_channel center_freq0; /* center frequency (MHz) first segment */ - wifi_channel center_freq1; /* center frequency (MHz) second segment */ -} wifi_channel_info; - -/* wifi rate */ -typedef struct { - uint32 preamble :3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ - uint32 nss :2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ - uint32 bw :3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ - uint32 rateMcsIdx :8; /* OFDM/CCK rate code would be as per - * ieee std in the units of 0.5mbps - */ - /* HT/VHT it would be mcs index */ - uint32 reserved :16; /* reserved */ - uint32 bitrate; /* units of 100 Kbps */ -} wifi_rate; - -typedef struct { - uint32 preamble; - uint32 nss; - uint32 bw; - uint32 rateMcsIdx; - uint32 reserved; - uint32 bitrate; -} wifi_rate_v2; - -/* channel statistics */ -typedef struct { - wifi_channel_info channel; /* channel */ - uint32 on_time; /* msecs the radio is awake - * (32 bits number accruing over time) - */ - uint32 cca_busy_time; /* msecs the CCA register is - * busy (32 bits number accruing over time) - */ -} wifi_channel_stat; - -/* radio statistics */ -typedef struct { - wifi_radio radio; /* wifi radio (if multiple radio supported) */ - /* all msecs in 32 bits number accruing over time */ - uint32 on_time; /* msecs the radio is awake */ - uint32 tx_time; /* msecs the radio is transmitting */ - uint32 rx_time; /* msecs the radio is in active receive */ - uint32 on_time_scan; /* msecs the radio is awake due to all scan */ - uint32 on_time_nbd; /* msecs the radio is awake due to NAN */ - uint32 on_time_gscan; /* msecs the radio is awake due to Gscan */ - uint32 on_time_roam_scan; /* msecs the radio is awake due to roam scan */ - uint32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan */ - uint32 on_time_hs20; /* msecs the radio is awake due to - * HS2.0 scans and GAS exchange - */ - uint32 num_channels; /* number of channels */ - wifi_channel_stat channels[]; /* channel statistics */ -} wifi_radio_stat; - -typedef struct { - uint16 version; - uint16 length; - wifi_radio radio; - uint32 on_time; - uint32 tx_time; - uint32 rx_time; - uint32 on_time_scan; - uint32 on_time_nbd; - uint32 on_time_gscan; - uint32 on_time_roam_scan; - uint32 on_time_pno_scan; - uint32 on_time_hs20; - uint32 num_channels; - uint8 channels[1]; -} wifi_radio_stat_v2; - -/* per rate statistics */ -typedef struct { - wifi_rate rate; /* rate information */ - uint32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ - uint32 rx_mpdu; /* number of received data pkts */ - uint32 mpdu_lost; /* number of data packet losses (no ACK) */ - uint32 retries; /* total number of data pkt retries */ - uint32 retries_short; /* number of short data pkt retries */ - uint32 retries_long; /* number of long data pkt retries */ -} wifi_rate_stat; - -typedef struct { - uint16 version; - uint16 length; - uint32 tx_mpdu; - uint32 rx_mpdu; - uint32 mpdu_lost; - uint32 retries; - uint32 retries_short; - uint32 retries_long; - wifi_rate_v2 rate; -} wifi_rate_stat_v2; - -/* access categories */ -typedef enum { - WIFI_AC_VO = 0, - WIFI_AC_VI = 1, - WIFI_AC_BE = 2, - WIFI_AC_BK = 3, - WIFI_AC_MAX = 4 -} wifi_traffic_ac; - -/* wifi peer type */ -typedef enum -{ - WIFI_PEER_STA, - WIFI_PEER_AP, - WIFI_PEER_P2P_GO, - WIFI_PEER_P2P_CLIENT, - WIFI_PEER_NAN, - WIFI_PEER_TDLS, - WIFI_PEER_INVALID -} wifi_peer_type; - -/* per peer statistics */ -typedef struct { - wifi_peer_type type; /* peer type (AP, TDLS, GO etc.) */ - uint8 peer_mac_address[6]; /* mac address */ - uint32 capabilities; /* peer WIFI_CAPABILITY_XXX */ - uint32 num_rate; /* number of rates */ - wifi_rate_stat rate_stats[]; /* per rate statistics, number of entries = num_rate */ -} wifi_peer_info; - -/* per access category statistics */ -typedef struct { - wifi_traffic_ac ac; /* access category (VI, VO, BE, BK) */ - uint32 tx_mpdu; /* number of successfully transmitted - * unicast data pkts (ACK rcvd) - */ - uint32 rx_mpdu; /* number of received unicast mpdus */ - uint32 tx_mcast; /* number of successfully transmitted - * multicast data packets - */ - /* STA case: implies ACK received from AP - * for the unicast packet in which mcast pkt was sent - */ - uint32 rx_mcast; /* number of received multicast data packets */ - uint32 rx_ampdu; /* number of received unicast a-mpdus */ - uint32 tx_ampdu; /* number of transmitted unicast a-mpdus */ - uint32 mpdu_lost; /* number of data pkt losses (no ACK) */ - uint32 retries; /* total number of data pkt retries */ - uint32 retries_short; /* number of short data pkt retries */ - uint32 retries_long; /* number of long data pkt retries */ - uint32 contention_time_min; /* data pkt min contention time (usecs) */ - uint32 contention_time_max; /* data pkt max contention time (usecs) */ - uint32 contention_time_avg; /* data pkt avg contention time (usecs) */ - uint32 contention_num_samples; /* num of data pkts used for contention statistics */ -} wifi_wmm_ac_stat; - -/* interface statistics */ -typedef struct { - wifi_interface_handle iface; /* wifi interface */ - wifi_interface_info info; /* current state of the interface */ - uint32 beacon_rx; /* access point beacon received count - * from connected AP - */ - uint64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT) - * The average_tsf_offset field is used so as to calculate - * the typical beacon contention time on the channel as well - * may be used to debug beacon synchronization and related - * power consumption issue - */ - uint32 leaky_ap_detected; /* indicate that this AP typically leaks packets beyond - * the driver guard time. - */ - uint32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after - * frame with PM bit set was ACK'ed by AP - */ - uint32 leaky_ap_guard_time; /* guard time currently in force (when implementing IEEE - * power management based on frame control PM bit), How long - * driver waits before shutting down the radio and after - * receiving an ACK for a data frame with PM bit set) - */ - uint32 mgmt_rx; /* access point mgmt frames received count - * from connected AP (including Beacon) - */ - uint32 mgmt_action_rx; /* action frames received count */ - uint32 mgmt_action_tx; /* action frames transmit count */ - wifi_rssi rssi_mgmt; /* access Point Beacon and - * Management frames RSSI (averaged) - */ - wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) - * from connected AP - */ - wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) - * from connected AP - */ - wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ - uint32 num_peers; /* number of peers */ - wifi_peer_info peer_info[]; /* per peer statistics */ -} wifi_iface_stat; -#endif /* LINKSTAT_SUPPORT */ -#endif /* _dngl_stats_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h deleted file mode 100755 index 74047430fff4..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Dongle WL Header definitions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dngl_wlhdr.h 241182 2011-02-17 21:50:03Z $ - */ - -#ifndef _dngl_wlhdr_h_ -#define _dngl_wlhdr_h_ - -typedef struct wl_header { - uint8 type; /* Header type */ - uint8 version; /* Header version */ - int8 rssi; /* RSSI */ - uint8 pad; /* Unused */ -} wl_header_t; - -#define WL_HEADER_LEN sizeof(wl_header_t) -#define WL_HEADER_TYPE 0 -#define WL_HEADER_VER 1 -#endif /* _dngl_wlhdr_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/hndpmu.c b/drivers/net/wireless/bcmdhd_suzuran/hndpmu.c deleted file mode 100755 index cfbbea8a854c..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/hndpmu.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Misc utility routines for accessing PMU corerev specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hndpmu.c 433378 2013-10-31 17:19:39Z $ - */ - - -/* - * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs. - * However, in the context of this file the baseband ('BB') PLL/FLL is referred to. - * - * Throughout this code, the prefixes 'pmu0_', 'pmu1_' and 'pmu2_' are used. - * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012) - * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports - * fractional frequency generation. pmu2_ does not support fractional frequency generation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PMU_ERROR(args) - -#define PMU_MSG(args) - -/* To check in verbose debugging messages not intended - * to be on except on private builds. - */ -#define PMU_NONE(args) - -/** contains resource bit positions for a specific chip */ -struct rsc_per_chip_s { - uint8 ht_avail; - uint8 macphy_clkavail; - uint8 ht_start; - uint8 otp_pu; -}; - -typedef struct rsc_per_chip_s rsc_per_chip_t; - - -/* SDIO Pad drive strength to select value mappings. - * The last strength value in each table must be 0 (the tri-state value). - */ -typedef struct { - uint8 strength; /* Pad Drive Strength in mA */ - uint8 sel; /* Chip-specific select value */ -} sdiod_drive_str_t; - -/* SDIO Drive Strength to sel value table for PMU Rev 1 */ -static const sdiod_drive_str_t 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 sdiod_drive_str_t 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 sdiod_drive_str_t sdiod_drive_strength_tab3[] = { - {32, 0x7}, - {26, 0x6}, - {22, 0x5}, - {16, 0x4}, - {12, 0x3}, - {8, 0x2}, - {4, 0x1}, - {0, 0x0} }; - -/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { - {32, 0x6}, - {26, 0x7}, - {22, 0x4}, - {16, 0x5}, - {12, 0x2}, - {8, 0x3}, - {4, 0x0}, - {0, 0x1} }; - -/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ - -/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ - -/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { - {6, 0x7}, - {5, 0x6}, - {4, 0x5}, - {3, 0x4}, - {2, 0x2}, - {1, 0x1}, - {0, 0x0} }; - -/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ - -/** SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { - {3, 0x3}, - {2, 0x2}, - {1, 0x1}, - {0, 0x0} }; - - -/** - * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel - * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture - * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has - * been written '1'. - */ -#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 - -static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = { - /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */ - {16, 0x7}, - {12, 0x5}, - {8, 0x3}, - {4, 0x1} }; /* note: 43143 does not support tristate */ - -#else - -static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = { - /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */ - {8, 0x7}, - {6, 0x5}, - {4, 0x3}, - {2, 0x1} }; /* note: 43143 does not support tristate */ - -#endif /* BCM_SDIO_VDDIO */ - -#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) - -/** - * Balance between stable SDIO operation and power consumption is achieved using this function. - * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this - * function should read the VDDIO itself to select the correct table. For now it has been solved - * with the 'BCM_SDIO_VDDIO' preprocessor constant. - * - * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if - * hardware supports this), if no hw support drive strength is not programmed. - */ -void -si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) -{ - chipcregs_t *cc; - uint origidx, intr_val = 0; - sdiod_drive_str_t *str_tab = NULL; - uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */ - uint32 str_shift = 0; - uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */ - uint32 str_ovr_pmuval = 0; /* position of bit within this register */ - - if (!(sih->cccaps & CC_CAP_PMU)) { - return; - } - - /* Remember original core before switch to chipc */ - cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); - - switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): - str_tab = (sdiod_drive_str_t *)&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): - case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): - if (sih->pmurev == 8) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; - } - else if (sih->pmurev == 11) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; - } - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; - str_mask = 0x00001800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): -#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 - if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; - } -#else - if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; - } -#endif /* BCM_SDIO_VDDIO */ - str_mask = 0x00000007; - str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; - break; - default: - PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", - bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); - break; - } - - if (str_tab != NULL && cc != NULL) { - uint32 cc_data_temp; - int i; - - /* Pick the lowest available drive strength equal or greater than the - * requested strength. Drive strength of 0 requests tri-state. - */ - for (i = 0; drivestrength < str_tab[i].strength; i++) - ; - - if (i > 0 && drivestrength > str_tab[i].strength) - i--; - - W_REG(osh, &cc->chipcontrol_addr, PMU_CHIPCTL1); - cc_data_temp = R_REG(osh, &cc->chipcontrol_data); - cc_data_temp &= ~str_mask; - cc_data_temp |= str_tab[i].sel << str_shift; - W_REG(osh, &cc->chipcontrol_data, cc_data_temp); - if (str_ovr_pmuval) { /* enables the selected drive strength */ - W_REG(osh, &cc->chipcontrol_addr, str_ovr_pmuctl); - OR_REG(osh, &cc->chipcontrol_data, str_ovr_pmuval); - } - PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", - drivestrength, str_tab[i].strength)); - } - - /* Return to original core */ - si_restore_core(sih, origidx, intr_val); -} /* si_sdiod_drive_strength_init */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/Makefile b/drivers/net/wireless/bcmdhd_suzuran/include/Makefile deleted file mode 100755 index 3b8291471203..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 1999-2018, Broadcom Corporation -# -# Unless you and Broadcom execute a separate written software license -# agreement governing use of this software, this software is licensed to you -# under the terms of the GNU General Public License version 2 (the "GPL"), -# available at http://www.broadcom.com/licenses/GPLv2.php, with the -# following added to such license: -# -# As a special exception, the copyright holders of this software give you -# permission to link this software with independent modules, and to copy and -# distribute the resulting executable under terms of your choice, provided that -# you also meet, for each linked independent module, the terms and conditions of -# the license of that module. An independent module is a module which is not -# derived from this software. The special exception does not apply to any -# modifications of the software. -# -# Notwithstanding the above, under no circumstances may you combine this -# software in any way with any other Broadcom software provided under a license -# other than the GPL, without Broadcom's express prior written consent. -# -# This script serves following purpose: -# -# 1. It generates native version information by querying -# automerger maintained database to see where src/include -# came from -# 2. For select components, as listed in compvers.sh -# it generates component version files -# -# $Id: Makefile 528449 2015-01-22 09:38:18Z $ -# - -export SRCBASE:=.. - -TARGETS := epivers.h - -ifdef VERBOSE -export VERBOSE -endif - -all release: epivers compvers - -# Generate epivers.h for native branch url -epivers: - bash epivers.sh - -# Generate component versions based on component url -compvers: - @if [ -s "compvers.sh" ]; then \ - echo "Generating component versions, if any"; \ - bash compvers.sh; \ - else \ - echo "Skipping component version generation"; \ - fi - -# Generate epivers.h for native branch version -clean_compvers: - @if [ -s "compvers.sh" ]; then \ - echo "bash compvers.sh clean"; \ - bash compvers.sh clean; \ - else \ - echo "Skipping component version clean"; \ - fi - -clean: - rm -f $(TARGETS) *.prev - -clean_all: clean clean_compvers - -.PHONY: all release clean epivers compvers clean_compvers diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h b/drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h deleted file mode 100755 index cc4fe830c965..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Broadcom AMBA Interconnect definitions. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: aidmp.h 404499 2013-05-28 01:06:37Z $ - */ - -#ifndef _AIDMP_H -#define _AIDMP_H - -/* Manufacturer Ids */ -#define MFGID_ARM 0x43b -#define MFGID_BRCM 0x4bf -#define MFGID_MIPS 0x4a7 - -/* Component Classes */ -#define CC_SIM 0 -#define CC_EROM 1 -#define CC_CORESIGHT 9 -#define CC_VERIF 0xb -#define CC_OPTIMO 0xd -#define CC_GEN 0xe -#define CC_PRIMECELL 0xf - -/* 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 MasterPortDesc */ -#define MPD_MUI_MASK 0x0000ff00 -#define MPD_MUI_SHIFT 8 -#define MPD_MP_MASK 0x000000f0 -#define MPD_MP_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 - - -#ifndef _LANGUAGE_ASSEMBLY - -typedef volatile struct _aidmp { - uint32 oobselina30; /* 0x000 */ - uint32 oobselina74; /* 0x004 */ - uint32 PAD[6]; - uint32 oobselinb30; /* 0x020 */ - uint32 oobselinb74; /* 0x024 */ - uint32 PAD[6]; - uint32 oobselinc30; /* 0x040 */ - uint32 oobselinc74; /* 0x044 */ - uint32 PAD[6]; - uint32 oobselind30; /* 0x060 */ - uint32 oobselind74; /* 0x064 */ - uint32 PAD[38]; - uint32 oobselouta30; /* 0x100 */ - uint32 oobselouta74; /* 0x104 */ - uint32 PAD[6]; - uint32 oobseloutb30; /* 0x120 */ - uint32 oobseloutb74; /* 0x124 */ - uint32 PAD[6]; - uint32 oobseloutc30; /* 0x140 */ - uint32 oobseloutc74; /* 0x144 */ - uint32 PAD[6]; - uint32 oobseloutd30; /* 0x160 */ - uint32 oobseloutd74; /* 0x164 */ - uint32 PAD[38]; - uint32 oobsynca; /* 0x200 */ - uint32 oobseloutaen; /* 0x204 */ - uint32 PAD[6]; - uint32 oobsyncb; /* 0x220 */ - uint32 oobseloutben; /* 0x224 */ - uint32 PAD[6]; - uint32 oobsyncc; /* 0x240 */ - uint32 oobseloutcen; /* 0x244 */ - uint32 PAD[6]; - uint32 oobsyncd; /* 0x260 */ - uint32 oobseloutden; /* 0x264 */ - uint32 PAD[38]; - uint32 oobaextwidth; /* 0x300 */ - uint32 oobainwidth; /* 0x304 */ - uint32 oobaoutwidth; /* 0x308 */ - uint32 PAD[5]; - uint32 oobbextwidth; /* 0x320 */ - uint32 oobbinwidth; /* 0x324 */ - uint32 oobboutwidth; /* 0x328 */ - uint32 PAD[5]; - uint32 oobcextwidth; /* 0x340 */ - uint32 oobcinwidth; /* 0x344 */ - uint32 oobcoutwidth; /* 0x348 */ - uint32 PAD[5]; - uint32 oobdextwidth; /* 0x360 */ - uint32 oobdinwidth; /* 0x364 */ - uint32 oobdoutwidth; /* 0x368 */ - uint32 PAD[37]; - uint32 ioctrlset; /* 0x400 */ - uint32 ioctrlclear; /* 0x404 */ - uint32 ioctrl; /* 0x408 */ - uint32 PAD[61]; - uint32 iostatus; /* 0x500 */ - uint32 PAD[127]; - uint32 ioctrlwidth; /* 0x700 */ - uint32 iostatuswidth; /* 0x704 */ - uint32 PAD[62]; - uint32 resetctrl; /* 0x800 */ - uint32 resetstatus; /* 0x804 */ - uint32 resetreadid; /* 0x808 */ - uint32 resetwriteid; /* 0x80c */ - uint32 PAD[60]; - uint32 errlogctrl; /* 0x900 */ - uint32 errlogdone; /* 0x904 */ - uint32 errlogstatus; /* 0x908 */ - uint32 errlogaddrlo; /* 0x90c */ - uint32 errlogaddrhi; /* 0x910 */ - uint32 errlogid; /* 0x914 */ - uint32 errloguser; /* 0x918 */ - uint32 errlogflags; /* 0x91c */ - uint32 PAD[56]; - uint32 intstatus; /* 0xa00 */ - uint32 PAD[255]; - uint32 config; /* 0xe00 */ - uint32 PAD[63]; - uint32 itcr; /* 0xf00 */ - uint32 PAD[3]; - uint32 itipooba; /* 0xf10 */ - uint32 itipoobb; /* 0xf14 */ - uint32 itipoobc; /* 0xf18 */ - uint32 itipoobd; /* 0xf1c */ - uint32 PAD[4]; - uint32 itipoobaout; /* 0xf30 */ - uint32 itipoobbout; /* 0xf34 */ - uint32 itipoobcout; /* 0xf38 */ - uint32 itipoobdout; /* 0xf3c */ - uint32 PAD[4]; - uint32 itopooba; /* 0xf50 */ - uint32 itopoobb; /* 0xf54 */ - uint32 itopoobc; /* 0xf58 */ - uint32 itopoobd; /* 0xf5c */ - uint32 PAD[4]; - uint32 itopoobain; /* 0xf70 */ - uint32 itopoobbin; /* 0xf74 */ - uint32 itopoobcin; /* 0xf78 */ - uint32 itopoobdin; /* 0xf7c */ - uint32 PAD[4]; - uint32 itopreset; /* 0xf90 */ - uint32 PAD[15]; - uint32 peripherialid4; /* 0xfd0 */ - uint32 peripherialid5; /* 0xfd4 */ - uint32 peripherialid6; /* 0xfd8 */ - uint32 peripherialid7; /* 0xfdc */ - uint32 peripherialid0; /* 0xfe0 */ - uint32 peripherialid1; /* 0xfe4 */ - uint32 peripherialid2; /* 0xfe8 */ - uint32 peripherialid3; /* 0xfec */ - uint32 componentid0; /* 0xff0 */ - uint32 componentid1; /* 0xff4 */ - uint32 componentid2; /* 0xff8 */ - uint32 componentid3; /* 0xffc */ -} aidmp_t; - -#endif /* _LANGUAGE_ASSEMBLY */ - -/* Out-of-band Router registers */ -#define OOB_BUSCONFIG 0x020 -#define OOB_STATUSA 0x100 -#define OOB_STATUSB 0x104 -#define OOB_STATUSC 0x108 -#define OOB_STATUSD 0x10c -#define OOB_ENABLEA0 0x200 -#define OOB_ENABLEA1 0x204 -#define OOB_ENABLEA2 0x208 -#define OOB_ENABLEA3 0x20c -#define OOB_ENABLEB0 0x280 -#define OOB_ENABLEB1 0x284 -#define OOB_ENABLEB2 0x288 -#define OOB_ENABLEB3 0x28c -#define OOB_ENABLEC0 0x300 -#define OOB_ENABLEC1 0x304 -#define OOB_ENABLEC2 0x308 -#define OOB_ENABLEC3 0x30c -#define OOB_ENABLED0 0x380 -#define OOB_ENABLED1 0x384 -#define OOB_ENABLED2 0x388 -#define OOB_ENABLED3 0x38c -#define OOB_ITCR 0xf00 -#define OOB_ITIPOOBA 0xf10 -#define OOB_ITIPOOBB 0xf14 -#define OOB_ITIPOOBC 0xf18 -#define OOB_ITIPOOBD 0xf1c -#define OOB_ITOPOOBA 0xf30 -#define OOB_ITOPOOBB 0xf34 -#define OOB_ITOPOOBC 0xf38 -#define OOB_ITOPOOBD 0xf3c - -/* DMP wrapper registers */ -#define AI_OOBSELINA30 0x000 -#define AI_OOBSELINA74 0x004 -#define AI_OOBSELINB30 0x020 -#define AI_OOBSELINB74 0x024 -#define AI_OOBSELINC30 0x040 -#define AI_OOBSELINC74 0x044 -#define AI_OOBSELIND30 0x060 -#define AI_OOBSELIND74 0x064 -#define AI_OOBSELOUTA30 0x100 -#define AI_OOBSELOUTA74 0x104 -#define AI_OOBSELOUTB30 0x120 -#define AI_OOBSELOUTB74 0x124 -#define AI_OOBSELOUTC30 0x140 -#define AI_OOBSELOUTC74 0x144 -#define AI_OOBSELOUTD30 0x160 -#define AI_OOBSELOUTD74 0x164 -#define AI_OOBSYNCA 0x200 -#define AI_OOBSELOUTAEN 0x204 -#define AI_OOBSYNCB 0x220 -#define AI_OOBSELOUTBEN 0x224 -#define AI_OOBSYNCC 0x240 -#define AI_OOBSELOUTCEN 0x244 -#define AI_OOBSYNCD 0x260 -#define AI_OOBSELOUTDEN 0x264 -#define AI_OOBAEXTWIDTH 0x300 -#define AI_OOBAINWIDTH 0x304 -#define AI_OOBAOUTWIDTH 0x308 -#define AI_OOBBEXTWIDTH 0x320 -#define AI_OOBBINWIDTH 0x324 -#define AI_OOBBOUTWIDTH 0x328 -#define AI_OOBCEXTWIDTH 0x340 -#define AI_OOBCINWIDTH 0x344 -#define AI_OOBCOUTWIDTH 0x348 -#define AI_OOBDEXTWIDTH 0x360 -#define AI_OOBDINWIDTH 0x364 -#define AI_OOBDOUTWIDTH 0x368 - - -#define AI_IOCTRLSET 0x400 -#define AI_IOCTRLCLEAR 0x404 -#define AI_IOCTRL 0x408 -#define AI_IOSTATUS 0x500 -#define AI_RESETCTRL 0x800 -#define AI_RESETSTATUS 0x804 - -#define AI_IOCTRLWIDTH 0x700 -#define AI_IOSTATUSWIDTH 0x704 - -#define AI_RESETREADID 0x808 -#define AI_RESETWRITEID 0x80c -#define AI_ERRLOGCTRL 0xa00 -#define AI_ERRLOGDONE 0xa04 -#define AI_ERRLOGSTATUS 0xa08 -#define AI_ERRLOGADDRLO 0xa0c -#define AI_ERRLOGADDRHI 0xa10 -#define AI_ERRLOGID 0xa14 -#define AI_ERRLOGUSER 0xa18 -#define AI_ERRLOGFLAGS 0xa1c -#define AI_INTSTATUS 0xa00 -#define AI_CONFIG 0xe00 -#define AI_ITCR 0xf00 -#define AI_ITIPOOBA 0xf10 -#define AI_ITIPOOBB 0xf14 -#define AI_ITIPOOBC 0xf18 -#define AI_ITIPOOBD 0xf1c -#define AI_ITIPOOBAOUT 0xf30 -#define AI_ITIPOOBBOUT 0xf34 -#define AI_ITIPOOBCOUT 0xf38 -#define AI_ITIPOOBDOUT 0xf3c -#define AI_ITOPOOBA 0xf50 -#define AI_ITOPOOBB 0xf54 -#define AI_ITOPOOBC 0xf58 -#define AI_ITOPOOBD 0xf5c -#define AI_ITOPOOBAIN 0xf70 -#define AI_ITOPOOBBIN 0xf74 -#define AI_ITOPOOBCIN 0xf78 -#define AI_ITOPOOBDIN 0xf7c -#define AI_ITOPRESET 0xf90 -#define AI_PERIPHERIALID4 0xfd0 -#define AI_PERIPHERIALID5 0xfd4 -#define AI_PERIPHERIALID6 0xfd8 -#define AI_PERIPHERIALID7 0xfdc -#define AI_PERIPHERIALID0 0xfe0 -#define AI_PERIPHERIALID1 0xfe4 -#define AI_PERIPHERIALID2 0xfe8 -#define AI_PERIPHERIALID3 0xfec -#define AI_COMPONENTID0 0xff0 -#define AI_COMPONENTID1 0xff4 -#define AI_COMPONENTID2 0xff8 -#define AI_COMPONENTID3 0xffc - -/* resetctrl */ -#define AIRC_RESET 1 - -/* config */ -#define AICFG_OOB 0x00000020 -#define AICFG_IOS 0x00000010 -#define AICFG_IOC 0x00000008 -#define AICFG_TO 0x00000004 -#define AICFG_ERRL 0x00000002 -#define AICFG_RST 0x00000001 - -/* bit defines for AI_OOBSELOUTB74 reg */ -#define OOB_SEL_OUTEN_B_5 15 -#define OOB_SEL_OUTEN_B_6 23 - -/* AI_OOBSEL for A/B/C/D, 0-7 */ -#define AI_OOBSEL_MASK 0x1F -#define AI_OOBSEL_0_SHIFT 0 -#define AI_OOBSEL_1_SHIFT 8 -#define AI_OOBSEL_2_SHIFT 16 -#define AI_OOBSEL_3_SHIFT 24 -#define AI_OOBSEL_4_SHIFT 0 -#define AI_OOBSEL_5_SHIFT 8 -#define AI_OOBSEL_6_SHIFT 16 -#define AI_OOBSEL_7_SHIFT 24 - -#endif /* _AIDMP_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h deleted file mode 100755 index fe1622268957..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * BCM common config options - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcm_cfg.h 351867 2012-08-21 18:46:16Z $ - */ - -#ifndef _bcm_cfg_h_ -#define _bcm_cfg_h_ -#endif /* _bcm_cfg_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h deleted file mode 100755 index bbb4e6699b73..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Memory pools library, Public interface - * - * API Overview - * - * This package provides a memory allocation subsystem based on pools of - * homogenous objects. - * - * Instrumentation is available for reporting memory utilization both - * on a per-data-structure basis and system wide. - * - * There are two main types defined in this API. - * - * pool manager: A singleton object that acts as a factory for - * pool allocators. It also is used for global - * instrumentation, such as reporting all blocks - * in use across all data structures. The pool manager - * creates and provides individual memory pools - * upon request to application code. - * - * memory pool: An object for allocating homogenous memory blocks. - * - * Global identifiers in this module use the following prefixes: - * bcm_mpm_* Memory pool manager - * bcm_mp_* Memory pool - * - * There are two main types of memory pools: - * - * prealloc: The contiguous memory block of objects can either be supplied - * by the client or malloc'ed by the memory manager. The objects are - * allocated out of a block of memory and freed back to the block. - * - * heap: The memory pool allocator uses the heap (malloc/free) for memory. - * In this case, the pool allocator is just providing statistics - * and instrumentation on top of the heap, without modifying the heap - * allocation implementation. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcm_mpool_pub.h 407097 2013-06-11 18:43:16Z $ - */ - -#ifndef _BCM_MPOOL_PUB_H -#define _BCM_MPOOL_PUB_H 1 - -#include /* needed for uint16 */ - - -/* -************************************************************************** -* -* Type definitions, handles -* -************************************************************************** -*/ - -/* Forward declaration of OSL handle. */ -struct osl_info; - -/* Forward declaration of string buffer. */ -struct bcmstrbuf; - -/* - * Opaque type definition for the pool manager handle. This object is used for global - * memory pool operations such as obtaining a new pool, deleting a pool, iterating and - * instrumentation/debugging. - */ -struct bcm_mpm_mgr; -typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h; - -/* - * Opaque type definition for an instance of a pool. This handle is used for allocating - * and freeing memory through the pool, as well as management/instrumentation on this - * specific pool. - */ -struct bcm_mp_pool; -typedef struct bcm_mp_pool *bcm_mp_pool_h; - - -/* - * To make instrumentation more readable, every memory - * pool must have a readable name. Pool names are up to - * 8 bytes including '\0' termination. (7 printable characters.) - */ -#define BCM_MP_NAMELEN 8 - - -/* - * Type definition for pool statistics. - */ -typedef struct bcm_mp_stats { - char name[BCM_MP_NAMELEN]; /* Name of this pool. */ - unsigned int objsz; /* Object size allocated in this pool */ - uint16 nobj; /* Total number of objects in this pool */ - uint16 num_alloc; /* Number of objects currently allocated */ - uint16 high_water; /* Max number of allocated objects. */ - uint16 failed_alloc; /* Failed allocations. */ -} bcm_mp_stats_t; - - -/* -************************************************************************** -* -* API Routines on the pool manager. -* -************************************************************************** -*/ - -/* - * bcm_mpm_init() - initialize the whole memory pool system. - * - * Parameters: - * osh: INPUT Operating system handle. Needed for heap memory allocation. - * max_pools: INPUT Maximum number of mempools supported. - * mgr: OUTPUT The handle is written with the new pools manager object/handle. - * - * Returns: - * BCME_OK Object initialized successfully. May be used. - * BCME_NOMEM Initialization failed due to no memory. Object must not be used. - */ -int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp); - - -/* - * bcm_mpm_deinit() - de-initialize the whole memory pool system. - * - * Parameters: - * mgr: INPUT Pointer to pool manager handle. - * - * Returns: - * BCME_OK Memory pool manager successfully de-initialized. - * other Indicated error occured during de-initialization. - */ -int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); - -/* - * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The - * pool uses a contiguous block of pre-alloced - * memory. The memory block may either be provided - * by the client or dynamically allocated by the - * pool manager. - * - * Parameters: - * mgr: INPUT The handle to the pool manager - * obj_sz: INPUT Size of objects that will be allocated by the new pool - * Must be >= sizeof(void *). - * nobj: INPUT Maximum number of concurrently existing objects to support - * memstart INPUT Pointer to the memory to use, or NULL to malloc() - * memsize INPUT Number of bytes referenced from memstart (for error checking). - * Must be 0 if 'memstart' is NULL. - * poolname INPUT For instrumentation, the name of the pool - * newp: OUTPUT The handle for the new pool, if creation is successful - * - * Returns: - * BCME_OK Pool created ok. - * other Pool not created due to indicated error. newpoolp set to NULL. - * - * - */ -int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, - unsigned int obj_sz, - int nobj, - void *memstart, - unsigned int memsize, - const char poolname[BCM_MP_NAMELEN], - bcm_mp_pool_h *newp); - - -/* - * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after - * all memory objects have been freed back to the pool. - * - * Parameters: - * mgr: INPUT The handle to the pools manager - * pool: INPUT The handle of the pool to delete - * - * Returns: - * BCME_OK Pool deleted ok. - * other Pool not deleted due to indicated error. - * - */ -int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); - -/* - * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory - * pool allocator uses the heap (malloc/free) for memory. - * In this case, the pool allocator is just providing - * statistics and instrumentation on top of the heap, - * without modifying the heap allocation implementation. - * - * Parameters: - * mgr: INPUT The handle to the pool manager - * obj_sz: INPUT Size of objects that will be allocated by the new pool - * poolname INPUT For instrumentation, the name of the pool - * newp: OUTPUT The handle for the new pool, if creation is successful - * - * Returns: - * BCME_OK Pool created ok. - * other Pool not created due to indicated error. newpoolp set to NULL. - * - * - */ -int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, - const char poolname[BCM_MP_NAMELEN], - bcm_mp_pool_h *newp); - - -/* - * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after - * all memory objects have been freed back to the pool. - * - * Parameters: - * mgr: INPUT The handle to the pools manager - * pool: INPUT The handle of the pool to delete - * - * Returns: - * BCME_OK Pool deleted ok. - * other Pool not deleted due to indicated error. - * - */ -int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); - - -/* - * bcm_mpm_stats() - Return stats for all pools - * - * Parameters: - * mgr: INPUT The handle to the pools manager - * stats: OUTPUT Array of pool statistics. - * nentries: MOD Max elements in 'stats' array on INPUT. Actual number - * of array elements copied to 'stats' on OUTPUT. - * - * Returns: - * BCME_OK Ok - * other Error getting stats. - * - */ -int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries); - - -/* - * bcm_mpm_dump() - Display statistics on all pools - * - * Parameters: - * mgr: INPUT The handle to the pools manager - * b: OUTPUT Output buffer. - * - * Returns: - * BCME_OK Ok - * other Error during dump. - * - */ -int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b); - - -/* - * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to - * compensate for alignment requirements of the objects. - * This function provides the padded object size. If clients - * pre-allocate a memory slab for a memory pool, the - * padded object size should be used by the client to allocate - * the memory slab (in order to provide sufficent space for - * the maximum number of objects). - * - * Parameters: - * mgr: INPUT The handle to the pools manager. - * obj_sz: INPUT Input object size. - * padded_obj_sz: OUTPUT Padded object size. - * - * Returns: - * BCME_OK Ok - * BCME_BADARG Bad arguments. - * - */ -int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz); - - -/* -*************************************************************************** -* -* API Routines on a specific pool. -* -*************************************************************************** -*/ - - -/* - * bcm_mp_alloc() - Allocate a memory pool object. - * - * Parameters: - * pool: INPUT The handle to the pool. - * - * Returns: - * A pointer to the new object. NULL on error. - * - */ -void* bcm_mp_alloc(bcm_mp_pool_h pool); - -/* - * bcm_mp_free() - Free a memory pool object. - * - * Parameters: - * pool: INPUT The handle to the pool. - * objp: INPUT A pointer to the object to free. - * - * Returns: - * BCME_OK Ok - * other Error during free. - * - */ -int bcm_mp_free(bcm_mp_pool_h pool, void *objp); - -/* - * bcm_mp_stats() - Return stats for this pool - * - * Parameters: - * pool: INPUT The handle to the pool - * stats: OUTPUT Pool statistics - * - * Returns: - * BCME_OK Ok - * other Error getting statistics. - * - */ -int bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats); - - -/* - * bcm_mp_dump() - Dump a pool - * - * Parameters: - * pool: INPUT The handle to the pool - * b OUTPUT Output buffer - * - * Returns: - * BCME_OK Ok - * other Error during dump. - * - */ -int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b); - - -#endif /* _BCM_MPOOL_PUB_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h deleted file mode 100755 index 3759e362f1be..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * CDC network driver ioctl/indication encoding - * Broadcom 802.11abg Networking Device Driver - * - * Definitions subject to change without notice. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmcdc.h 318308 2012-03-02 02:23:42Z $ - */ -#ifndef _bcmcdc_h_ -#define _bcmcdc_h_ -#include - -typedef struct cdc_ioctl { - uint32 cmd; /* ioctl command value */ - uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */ - uint32 flags; /* flag defns given below */ - uint32 status; /* status code returned from the device */ -} cdc_ioctl_t; - -/* Max valid buffer size that can be sent to the dongle */ -#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN - -/* len field is divided into input and output buffer lengths */ -#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */ - /* excluding IOCTL header */ -#define CDCL_IOC_OUTLEN_SHIFT 0 -#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */ -#define CDCL_IOC_INLEN_SHIFT 16 - -/* CDC flag definitions */ -#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */ -#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */ -#define CDCF_IOC_OVL_IDX_MASK 0x3c /* overlay region index mask */ -#define CDCF_IOC_OVL_RSV 0x40 /* 1=reserve this overlay region */ -#define CDCF_IOC_OVL 0x80 /* 1=this ioctl corresponds to an overlay */ -#define CDCF_IOC_ACTION_MASK 0xfe /* SET/GET, OVL_IDX, OVL_RSV, OVL mask */ -#define CDCF_IOC_ACTION_SHIFT 1 /* SET/GET, OVL_IDX, OVL_RSV, OVL shift */ -#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */ -#define CDCF_IOC_IF_SHIFT 12 -#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */ -#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */ - -#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) -#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) - -#define CDC_GET_IF_IDX(hdr) \ - ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) -#define CDC_SET_IF_IDX(hdr, idx) \ - ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) - -/* - * BDC header - * - * The BDC header is used on data packets to convey priority across USB. - */ - -struct bdc_header { - uint8 flags; /* Flags */ - uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 USB flow control info */ - uint8 flags2; - uint8 dataOffset; /* Offset from end of BDC header to packet data, in - * 4-byte words. Leaves room for optional headers. - */ -}; - -#define BDC_HEADER_LEN 4 - -/* flags field bitmap */ -#define BDC_FLAG_80211_PKT 0x01 /* Packet is in 802.11 format (dongle -> host) */ -#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */ -#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums: host->device */ -#define BDC_FLAG_EVENT_MSG 0x08 /* Payload contains an event msg: device->host */ -#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ -#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ - -/* priority field bitmap */ -#define BDC_PRIORITY_MASK 0x07 -#define BDC_PRIORITY_FC_MASK 0xf0 /* flow control info mask */ -#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */ - -/* flags2 field bitmap */ -#define BDC_FLAG2_IF_MASK 0x0f /* interface index (host <-> dongle) */ -#define BDC_FLAG2_IF_SHIFT 0 -#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */ - /* FLOW CONTROL info only */ - -/* version numbers */ -#define BDC_PROTO_VER_1 1 /* Old Protocol version */ -#define BDC_PROTO_VER 2 /* Protocol version */ - -/* flags2.if field access macros */ -#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))) - -#define BDC_FLAG2_PAD_MASK 0xf0 -#define BDC_FLAG_PAD_MASK 0x03 -#define BDC_FLAG2_PAD_SHIFT 2 -#define BDC_FLAG_PAD_SHIFT 0 -#define BDC_FLAG2_PAD_IDX 0x3c -#define BDC_FLAG_PAD_IDX 0x03 -#define BDC_GET_PAD_LEN(hdr) \ - ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ - ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) -#define BDC_SET_PAD_LEN(hdr, idx) \ - ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ - (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ - ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ - (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) - -#endif /* _bcmcdc_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h deleted file mode 100755 index d7a14c094aa5..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Misc system wide definitions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmdefs.h 433011 2013-10-30 09:19:54Z $ - */ - -#ifndef _bcmdefs_h_ -#define _bcmdefs_h_ - -/* - * One doesn't need to include this file explicitly, gets included automatically if - * typedefs.h is included. - */ - -/* Use BCM_REFERENCE to suppress warnings about intentionally-unused function - * arguments or local variables. - */ -#define BCM_REFERENCE(data) ((void)(data)) - -/* Allow for suppressing unused variable warnings. */ -#ifdef __GNUC__ -#define UNUSED_VAR __attribute__ ((unused)) -#else -#define UNUSED_VAR -#endif - -/* Compile-time assert can be used in place of ASSERT if the expression evaluates - * to a constant at compile time. - */ -#define STATIC_ASSERT(expr) { \ - /* Make sure the expression is constant. */ \ - typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \ - /* Make sure the expression is true. */ \ - typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \ -} - -/* Reclaiming text and data : - * The following macros specify special linker sections that can be reclaimed - * after a system is considered 'up'. - * BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN, - * as in most cases, the attach function calls the detach function to clean up on error). - */ - -#define bcmreclaimed 0 -#define _data _data -#define _fn _fn -#define BCMPREATTACHDATA(_data) _data -#define BCMPREATTACHFN(_fn) _fn -#define _data _data -#define _fn _fn -#define _fn _fn -#define BCMNMIATTACHFN(_fn) _fn -#define BCMNMIATTACHDATA(_data) _data -#define CONST const - -#undef BCM47XX_CA9 - -#ifndef BCMFASTPATH -#if defined(BCM47XX_CA9) -#define BCMFASTPATH __attribute__ ((__section__ (".text.fastpath"))) -#define BCMFASTPATH_HOST __attribute__ ((__section__ (".text.fastpath_host"))) -#else -#define BCMFASTPATH -#define BCMFASTPATH_HOST -#endif -#endif /* BCMFASTPATH */ - - -/* Use the BCMRAMFN() macro to tag functions in source that must be included in RAM (excluded from - * ROM). This should eliminate the need to manually specify these functions in the ROM config file. - * It should only be used in special cases where the function must be in RAM for *all* ROM-based - * chips. - */ - #define BCMRAMFN(_fn) _fn - - - -/* Put some library data/code into ROM to reduce RAM requirements */ -#define _data _data -#define BCMROMDAT_NAME(_data) _data -#define _fn _fn -#define _fn _fn -#define STATIC static -#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data) -#define BCMROMDAT_SIZEOF(data) sizeof(data) -#define BCMROMDAT_APATCH(data) -#define BCMROMDAT_SPATCH(data) - -/* Bus types */ -#define SI_BUS 0 /* SOC Interconnect */ -#define PCI_BUS 1 /* PCI target */ -#define PCMCIA_BUS 2 /* PCMCIA target */ -#define SDIO_BUS 3 /* SDIO target */ -#define JTAG_BUS 4 /* JTAG */ -#define USB_BUS 5 /* USB (does not support R/W REG) */ -#define SPI_BUS 6 /* gSPI target */ -#define RPC_BUS 7 /* RPC target */ - -/* Allows size optimization for single-bus image */ -#ifdef BCMBUSTYPE -#define BUSTYPE(bus) (BCMBUSTYPE) -#else -#define BUSTYPE(bus) (bus) -#endif - -/* Allows size optimization for single-backplane image */ -#ifdef BCMCHIPTYPE -#define CHIPTYPE(bus) (BCMCHIPTYPE) -#else -#define CHIPTYPE(bus) (bus) -#endif - - -/* Allows size optimization for SPROM support */ -#if defined(BCMSPROMBUS) -#define SPROMBUS (BCMSPROMBUS) -#elif defined(SI_PCMCIA_SROM) -#define SPROMBUS (PCMCIA_BUS) -#else -#define SPROMBUS (PCI_BUS) -#endif - -/* Allows size optimization for single-chip image */ -#ifdef BCMCHIPID -#define CHIPID(chip) (BCMCHIPID) -#else -#define CHIPID(chip) (chip) -#endif - -#ifdef BCMCHIPREV -#define CHIPREV(rev) (BCMCHIPREV) -#else -#define CHIPREV(rev) (rev) -#endif - -/* Defines for DMA Address Width - Shared between OSL and HNDDMA */ -#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ -#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */ -#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */ - -#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */ -#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */ -#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */ -#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */ - -typedef struct { - uint32 loaddr; - uint32 hiaddr; -} dma64addr_t; - -#define PHYSADDR64HI(_pa) ((_pa).hiaddr) -#define PHYSADDR64HISET(_pa, _val) \ - do { \ - (_pa).hiaddr = (_val); \ - } while (0) -#define PHYSADDR64LO(_pa) ((_pa).loaddr) -#define PHYSADDR64LOSET(_pa, _val) \ - do { \ - (_pa).loaddr = (_val); \ - } while (0) - -#ifdef BCMDMA64OSL -typedef dma64addr_t dmaaddr_t; -#define PHYSADDRHI(_pa) PHYSADDR64HI(_pa) -#define PHYSADDRHISET(_pa, _val) PHYSADDR64HISET(_pa, _val) -#define PHYSADDRLO(_pa) PHYSADDR64LO(_pa) -#define PHYSADDRLOSET(_pa, _val) PHYSADDR64LOSET(_pa, _val) - -#else -typedef unsigned long dmaaddr_t; -#define PHYSADDRHI(_pa) (0) -#define PHYSADDRHISET(_pa, _val) -#define PHYSADDRLO(_pa) ((_pa)) -#define PHYSADDRLOSET(_pa, _val) \ - do { \ - (_pa) = (_val); \ - } while (0) -#endif /* BCMDMA64OSL */ - -/* One physical DMA segment */ -typedef struct { - dmaaddr_t addr; - uint32 length; -} hnddma_seg_t; - -#define MAX_DMA_SEGS 8 - - -typedef struct { - void *oshdmah; /* Opaque handle for OSL to store its information */ - uint origsize; /* Size of the virtual packet */ - uint nsegs; - hnddma_seg_t segs[MAX_DMA_SEGS]; -} hnddma_seg_map_t; - - -/* 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 (hnddma.c). - */ - -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) -/* add 40 bytes to allow for extra RPC header and info */ -#define BCMEXTRAHDROOM 260 -#else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ -#if defined(BCM47XX_CA9) -#define BCMEXTRAHDROOM 224 -#else -#define BCMEXTRAHDROOM 204 -#endif /* linux && BCM47XX_CA9 */ -#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ - -/* Packet alignment for most efficient SDIO (can change based on platform) */ -#ifndef SDALIGN -#define SDALIGN 32 -#endif - -/* Headroom required for dongle-to-host communication. Packets allocated - * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should - * leave this much room in front for low-level message headers which may - * be needed to get across the dongle bus to the host. (These messages - * don't go over the network, so room for the full WL header above would - * be a waste.). -*/ -#define BCMDONGLEHDRSZ 12 -#define BCMDONGLEPADSZ 16 - -#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) - - -#if defined(NO_BCMDBG_ASSERT) -# undef BCMDBG_ASSERT -# undef BCMASSERT_LOG -#endif - -#if defined(BCMASSERT_LOG) -#define BCMASSERT_SUPPORT -#endif - -/* 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 BCMSMALL to remove misc features for memory-constrained environments */ -#ifdef BCMSMALL -#undef BCMSPACE -#define bcmspace FALSE /* if (bcmspace) code is discarded */ -#else -#define BCMSPACE -#define bcmspace TRUE /* if (bcmspace) code is retained */ -#endif - -/* Max. nvram variable table size */ -#ifndef MAXSZ_NVRAM_VARS -#define MAXSZ_NVRAM_VARS 4096 -#endif - - - -/* WL_ENAB_RUNTIME_CHECK may be set based upon the #define below (for ROM builds). It may also - * be defined via makefiles (e.g. ROM auto abandon unoptimized compiles). - */ - - -#ifdef BCMLFRAG /* BCMLFRAG support enab macros */ - extern bool _bcmlfrag; - #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) - #define BCMLFRAG_ENAB() (_bcmlfrag) - #elif defined(BCMLFRAG_DISABLED) - #define BCMLFRAG_ENAB() (0) - #else - #define BCMLFRAG_ENAB() (1) - #endif -#else - #define BCMLFRAG_ENAB() (0) -#endif /* BCMLFRAG_ENAB */ -#ifdef BCMSPLITRX /* BCMLFRAG support enab macros */ - extern bool _bcmsplitrx; - #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) - #define BCMSPLITRX_ENAB() (_bcmsplitrx) - #elif defined(BCMSPLITRX_DISABLED) - #define BCMSPLITRX_ENAB() (0) - #else - #define BCMSPLITRX_ENAB() (1) - #endif -#else - #define BCMSPLITRX_ENAB() (0) -#endif /* BCMSPLITRX */ -#ifdef BCM_SPLITBUF - extern bool _bcmsplitbuf; - #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) - #define BCM_SPLITBUF_ENAB() (_bcmsplitbuf) - #elif defined(BCM_SPLITBUF_DISABLED) - #define BCM_SPLITBUF_ENAB() (0) - #else - #define BCM_SPLITBUF_ENAB() (1) - #endif -#else - #define BCM_SPLITBUF_ENAB() (0) -#endif /* BCM_SPLITBUF */ -/* Max size for reclaimable NVRAM array */ -#ifdef DL_NVRAM -#define NVRAM_ARRAY_MAXSIZE DL_NVRAM -#else -#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS -#endif /* DL_NVRAM */ - -#ifdef BCMUSBDEV_ENABLED -extern uint32 gFWID; -#endif - - -#endif /* _bcmdefs_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h deleted file mode 100755 index d950bc71355e..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h +++ /dev/null @@ -1,689 +0,0 @@ -/* - * Broadcom device-specific manifest constants. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmdevs.h 527126 2015-01-16 03:33:51Z $ - */ - -#ifndef _BCMDEVS_H -#define _BCMDEVS_H - -/* PCI vendor IDs */ -#define VENDOR_EPIGRAM 0xfeda -#define VENDOR_BROADCOM 0x14e4 -#define VENDOR_3COM 0x10b7 -#define VENDOR_NETGEAR 0x1385 -#define VENDOR_DIAMOND 0x1092 -#define VENDOR_INTEL 0x8086 -#define VENDOR_DELL 0x1028 -#define VENDOR_HP 0x103c -#define VENDOR_HP_COMPAQ 0x0e11 -#define VENDOR_APPLE 0x106b -#define VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */ -#define VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */ -#define VENDOR_TI 0x104c /* Texas Instruments */ -#define VENDOR_RICOH 0x1180 /* Ricoh */ -#define VENDOR_JMICRON 0x197b - - -/* PCMCIA vendor IDs */ -#define VENDOR_BROADCOM_PCMCIA 0x02d0 - -/* SDIO vendor IDs */ -#define VENDOR_BROADCOM_SDIO 0x00BF - -/* DONGLE VID/PIDs */ -#define BCM_DNGL_VID 0x0a5c -#define BCM_DNGL_BL_PID_4328 0xbd12 -#define BCM_DNGL_BL_PID_4322 0xbd13 -#define BCM_DNGL_BL_PID_4319 0xbd16 -#define BCM_DNGL_BL_PID_43236 0xbd17 -#define BCM_DNGL_BL_PID_4332 0xbd18 -#define BCM_DNGL_BL_PID_4330 0xbd19 -#define BCM_DNGL_BL_PID_4334 0xbd1a -#define BCM_DNGL_BL_PID_43239 0xbd1b -#define BCM_DNGL_BL_PID_4324 0xbd1c -#define BCM_DNGL_BL_PID_4360 0xbd1d -#define BCM_DNGL_BL_PID_43143 0xbd1e -#define BCM_DNGL_BL_PID_43242 0xbd1f -#define BCM_DNGL_BL_PID_43342 0xbd21 -#define BCM_DNGL_BL_PID_4335 0xbd20 -#define BCM_DNGL_BL_PID_43341 0xbd22 -#define BCM_DNGL_BL_PID_4350 0xbd23 -#define BCM_DNGL_BL_PID_4345 0xbd24 -#define BCM_DNGL_BL_PID_4349 0xbd25 -#define BCM_DNGL_BL_PID_4354 0xbd26 - -#define BCM_DNGL_BDC_PID 0x0bdc -#define BCM_DNGL_JTAG_PID 0x4a44 - -/* HW USB BLOCK [CPULESS USB] PIDs */ -#define BCM_HWUSB_PID_43239 43239 - -/* PCI Device IDs */ -#define BCM4210_DEVICE_ID 0x1072 /* never used */ -#define BCM4230_DEVICE_ID 0x1086 /* never used */ -#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */ -#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */ -#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */ -#define BCM4211_DEVICE_ID 0x4211 -#define BCM4231_DEVICE_ID 0x4231 -#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */ -#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */ -#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */ -#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */ -#define BCM4328_D11DUAL_ID 0x4314 /* 4328/4312 802.11a/g id */ -#define BCM4328_D11G_ID 0x4315 /* 4328/4312 802.11g id */ -#define BCM4328_D11A_ID 0x4316 /* 4328/4312 802.11a id */ -#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */ -#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */ -#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */ -#define BCM4325_D11DUAL_ID 0x431b /* 4325 802.11a/g id */ -#define BCM4325_D11G_ID 0x431c /* 4325 802.11g id */ -#define BCM4325_D11A_ID 0x431d /* 4325 802.11a id */ -#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */ -#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */ -#define BCM4306_UART_ID 0x4322 /* 4306 uart */ -#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */ -#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */ -#define BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G_ID; INF w/loose binding war */ -#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */ -#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Ghz band id */ -#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */ -#define BCM4322_D11N_ID 0x432b /* 4322 802.11n dualband device */ -#define BCM4322_D11N2G_ID 0x432c /* 4322 802.11n 2.4GHz device */ -#define BCM4322_D11N5G_ID 0x432d /* 4322 802.11n 5GHz device */ -#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */ -#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ -#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ -#define BCM4315_D11DUAL_ID 0x4334 /* 4315 802.11a/g id */ -#define BCM4315_D11G_ID 0x4335 /* 4315 802.11g id */ -#define BCM4315_D11A_ID 0x4336 /* 4315 802.11a id */ -#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 BCM43231_D11N2G_ID 0x4340 /* 43231 802.11n 2.4GHz device */ -#define BCM43221_D11N2G_ID 0x4341 /* 43221 802.11n 2.4GHz device */ -#define BCM43222_D11N_ID 0x4350 /* 43222 802.11n dualband device */ -#define BCM43222_D11N2G_ID 0x4351 /* 43222 802.11n 2.4GHz device */ -#define BCM43222_D11N5G_ID 0x4352 /* 43222 802.11n 5GHz device */ -#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ -#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */ -#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband device */ -#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ -#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ -#define BCM43236_D11N5G_ID 0x4348 /* 43236 802.11n 5GHz device */ -#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ -#define BCM43421_D11N_ID 0xA99D /* 43421 802.11n dualband device */ -#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ -#define BCM4330_D11N_ID 0x4360 /* 4330 802.11n dualband device */ -#define BCM4330_D11N2G_ID 0x4361 /* 4330 802.11n 2.4G device */ -#define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */ -#define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */ -#define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */ -#define BCM6362_D11N2G_ID 0x433f /* 6362 802.11n 2.4Ghz band id */ -#define BCM6362_D11N5G_ID 0x434f /* 6362 802.11n 5Ghz band id */ -#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */ -#define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */ -#define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */ -#define BCM43237_D11N_ID 0x4355 /* 43237 802.11n dualband device */ -#define BCM43237_D11N5G_ID 0x4356 /* 43237 802.11n 5GHz device */ -#define BCM43227_D11N2G_ID 0x4358 /* 43228 802.11n 2.4GHz device */ -#define BCM43228_D11N_ID 0x4359 /* 43228 802.11n DualBand device */ -#define BCM43228_D11N5G_ID 0x435a /* 43228 802.11n 5GHz device */ -#define BCM43362_D11N_ID 0x4363 /* 43362 802.11n 2.4GHz device */ -#define BCM43239_D11N_ID 0x4370 /* 43239 802.11n dualband device */ -#define BCM4324_D11N_ID 0x4374 /* 4324 802.11n dualband device */ -#define BCM43217_D11N2G_ID 0x43a9 /* 43217 802.11n 2.4GHz device */ -#define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */ -#define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */ -#define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */ -#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ -#define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */ -#define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */ -#define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */ -#define BCM43342_D11N_ID 0x4383 /* 43342 802.11n dualband device */ -#define BCM43342_D11N2G_ID 0x4384 /* 43342 802.11n 2.4G device */ -#define BCM43342_D11N5G_ID 0x4385 /* 43342 802.11n 5G device */ -#define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */ -#define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */ -#define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */ -#define BCM4360_D11AC_ID 0x43a0 -#define BCM4360_D11AC2G_ID 0x43a1 -#define BCM4360_D11AC5G_ID 0x43a2 -#define BCM4345_D11AC_ID 0x43ab /* 4345 802.11ac dualband device */ -#define BCM4345_D11AC2G_ID 0x43ac /* 4345 802.11ac 2.4G device */ -#define BCM4345_D11AC5G_ID 0x43ad /* 4345 802.11ac 5G device */ -#define BCM4335_D11AC_ID 0x43ae -#define BCM4335_D11AC2G_ID 0x43af -#define BCM4335_D11AC5G_ID 0x43b0 -#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ -#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ -#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ -#define BCM43602_D11AC_ID 0x43ba /* ac dualband PCI devid SPROM programmed */ -#define BCM43602_D11AC2G_ID 0x43bb /* 43602 802.11ac 2.4G device */ -#define BCM43602_D11AC5G_ID 0x43bc /* 43602 802.11ac 5G device */ - -/* PCI Subsystem ID */ -#define BCM943228HMB_SSID_VEN1 0x0607 -#define BCM94313HMGBL_SSID_VEN1 0x0608 -#define BCM94313HMG_SSID_VEN1 0x0609 -#define BCM943142HM_SSID_VEN1 0x0611 - -#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ - -#define BCM43242_D11N_ID 0x4367 /* 43242 802.11n dualband device */ -#define BCM43242_D11N2G_ID 0x4368 /* 43242 802.11n 2.4G device */ -#define BCM43242_D11N5G_ID 0x4369 /* 43242 802.11n 5G device */ - -#define BCM4350_D11AC_ID 0x43a3 -#define BCM4350_D11AC2G_ID 0x43a4 -#define BCM4350_D11AC5G_ID 0x43a5 - -#define BCM43556_D11AC_ID 0x43b7 -#define BCM43556_D11AC2G_ID 0x43b8 -#define BCM43556_D11AC5G_ID 0x43b9 - -#define BCM43558_D11AC_ID 0x43c0 -#define BCM43558_D11AC2G_ID 0x43c1 -#define BCM43558_D11AC5G_ID 0x43c2 - -#define BCM43566_D11AC_ID 0x43d3 -#define BCM43566_D11AC2G_ID 0x43d4 -#define BCM43566_D11AC5G_ID 0x43d5 - -#define BCM43568_D11AC_ID 0x43d6 -#define BCM43568_D11AC2G_ID 0x43d7 -#define BCM43568_D11AC5G_ID 0x43d8 - -#define BCM43569_D11AC_ID 0x43d9 -#define BCM43569_D11AC2G_ID 0x43da -#define BCM43569_D11AC5G_ID 0x43db - -#define BCM4354_D11AC_ID 0x43df /* 4354 802.11ac dualband device */ -#define BCM4354_D11AC2G_ID 0x43e0 /* 4354 802.11ac 2.4G device */ -#define BCM4354_D11AC5G_ID 0x43e1 /* 4354 802.11ac 5G device */ -#define BCM43430_D11N2G_ID 0x43e2 /* 43430 802.11n 2.4G device */ - - -#define BCM43349_D11N_ID 0x43e6 /* 43349 802.11n dualband id */ -#define BCM43349_D11N2G_ID 0x43e7 /* 43349 802.11n 2.4Ghz band id */ -#define BCM43349_D11N5G_ID 0x43e8 /* 43349 802.11n 5Ghz band id */ - -#define BCM4356_D11AC_ID 0x43ec /* 4356 802.11ac dualband device */ -#define BCM4356_D11AC2G_ID 0x43ed /* 4356 802.11ac 2.4G device */ -#define BCM4356_D11AC5G_ID 0x43ee /* 4356 802.11ac 5G device */ - -#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */ -#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */ -#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */ -#define BCM_JTAGM_ID 0x43f1 /* BCM jtagm device id */ -#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */ -#define BCM_SDIOH_ID 0x43f3 /* BCM sdio host id */ -#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */ -#define SPIH_FPGA_ID 0x43f5 /* PCI SPI Host Controller FPGA */ -#define BCM_SPIH_ID 0x43f6 /* Synopsis SPI Host Controller */ -#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */ -#define BCM_JTAGM2_ID 0x43f9 /* BCM alternate jtagm device id */ -#define SDHCI_FPGA_ID 0x43fa /* Standard SDIO Host Controller FPGA */ -#define BCM4402_ENET_ID 0x4402 /* 4402 enet */ -#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */ -#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */ -#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */ -#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */ -#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */ -#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */ -#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */ -#define BCM47XX_AUDIO_ID 0x4711 /* 47xx audio codec */ -#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */ -#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */ -#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */ -#define BCM47XX_GMAC_ID 0x4715 /* 47xx Unimac based GbE */ -#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */ -#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */ -#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */ -#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */ -#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */ -#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */ -#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */ -#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */ -#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */ -#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */ -#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */ -#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */ -#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */ -#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */ -#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */ -#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */ -#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */ -#define JINVANI_SDIOH_ID 0x4743 /* Jinvani SDIO Gold Host */ -#define BCM27XX_SDIOH_ID 0x2702 /* BCM27xx Standard SDIO Host */ -#define PCIXX21_FLASHMEDIA_ID 0x803b /* TI PCI xx21 Standard Host Controller */ -#define PCIXX21_SDIOH_ID 0x803c /* TI PCI xx21 Standard Host Controller */ -#define R5C822_SDIOH_ID 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */ -#define JMICRON_SDIOH_ID 0x2381 /* JMicron Standard SDIO Host Controller */ - -/* Chip IDs */ -#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */ -#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */ -#define BCM43111_CHIP_ID 43111 /* 43111 chipcommon chipid (OTP chipid) */ -#define BCM43112_CHIP_ID 43112 /* 43112 chipcommon chipid (OTP chipid) */ -#define BCM4312_CHIP_ID 0x4312 /* 4312 chipcommon chipid */ -#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ -#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP chipid) */ -#define BCM4315_CHIP_ID 0x4315 /* 4315 chip id */ -#define BCM4318_CHIP_ID 0x4318 /* 4318 chipcommon chipid */ -#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ -#define BCM4320_CHIP_ID 0x4320 /* 4320 chipcommon chipid */ -#define BCM4321_CHIP_ID 0x4321 /* 4321 chipcommon chipid */ -#define BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP chipid) */ -#define BCM4322_CHIP_ID 0x4322 /* 4322 chipcommon chipid */ -#define BCM43221_CHIP_ID 43221 /* 43221 chipcommon chipid (OTP chipid) */ -#define BCM43222_CHIP_ID 43222 /* 43222 chipcommon chipid */ -#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ -#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ -#define BCM43227_CHIP_ID 43227 /* 43227 chipcommon chipid */ -#define BCM43228_CHIP_ID 43228 /* 43228 chipcommon chipid */ -#define BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */ -#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (OTP chipid) */ -#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */ -#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ -#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ -#define BCM43237_CHIP_ID 43237 /* 43237 chipcommon chipid */ -#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ -#define BCM43239_CHIP_ID 43239 /* 43239 chipcommon chipid */ -#define BCM43420_CHIP_ID 43420 /* 43222 chipcommon chipid (OTP, RBBU) */ -#define BCM43421_CHIP_ID 43421 /* 43224 chipcommon chipid (OTP, RBBU) */ -#define BCM43428_CHIP_ID 43428 /* 43228 chipcommon chipid (OTP, RBBU) */ -#define BCM43431_CHIP_ID 43431 /* 4331 chipcommon chipid (OTP, RBBU) */ -#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ -#define BCM4325_CHIP_ID 0x4325 /* 4325 chip id */ -#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */ -#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ -#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ -#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ -#define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */ -#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ -#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ -#define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */ -#define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */ -#define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */ -#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */ -#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */ -#define BCM43243_CHIP_ID 43243 /* 43243 chipcommon chipid */ -#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */ -#define BCM4335_CHIP_ID 0x4335 /* 4335 chipcommon chipid */ -#define BCM4339_CHIP_ID 0x4339 /* 4339 chipcommon chipid */ -#define BCM43349_CHIP_ID 43349 /* 43349(0xA955) chipcommon chipid */ -#define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */ -#define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */ -#define BCM43526_CHIP_ID 0xAA06 -#define BCM43340_CHIP_ID 43340 /* 43340 chipcommon chipid */ -#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */ -#define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */ -#define BCM4350_CHIP_ID 0x4350 /* 4350 chipcommon chipid */ -#define BCM4354_CHIP_ID 0x4354 /* 4354 chipcommon chipid */ -#define BCM4356_CHIP_ID 0x4356 /* 4356 chipcommon chipid */ -#define BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */ -#define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */ -#define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */ -#define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */ -#define BCM43569_CHIP_ID 0xAA31 /* 43569 chipcommon chipid */ -#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \ - (CHIPID(chipid) == BCM4354_CHIP_ID) || \ - (CHIPID(chipid) == BCM4356_CHIP_ID) || \ - (CHIPID(chipid) == BCM43556_CHIP_ID) || \ - (CHIPID(chipid) == BCM43558_CHIP_ID) || \ - (CHIPID(chipid) == BCM43566_CHIP_ID) || \ - (CHIPID(chipid) == BCM43568_CHIP_ID) || \ - (CHIPID(chipid) == BCM43569_CHIP_ID)) /* 4350 variations */ -#define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */ -#define BCM43454_CHIP_ID 43454 /* 43454 chipcommon chipid */ -#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */ - -#define BCM43602_CHIP_ID 0xaa52 /* 43602 chipcommon chipid */ - -#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */ -#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */ -#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */ -#define BCM4706_CHIP_ID 0x5300 /* 4706 chipcommon chipid */ -#define BCM4707_CHIP_ID 53010 /* 4707 chipcommon chipid */ -#define BCM53018_CHIP_ID 53018 /* 53018 chipcommon chipid */ -#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || ((chipid) == BCM53018_CHIP_ID)) -#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */ -#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */ -#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) */ -#define BCM4749_CHIP_ID 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */ -#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */ -#define BCM5350_CHIP_ID 0x5350 /* 5350 chipcommon chipid */ -#define BCM5352_CHIP_ID 0x5352 /* 5352 chipcommon chipid */ -#define BCM5354_CHIP_ID 0x5354 /* 5354 chipcommon chipid */ -#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */ -#define BCM5356_CHIP_ID 0x5356 /* 5356 chipcommon chipid */ -#define BCM5357_CHIP_ID 0x5357 /* 5357 chipcommon chipid */ -#define BCM53572_CHIP_ID 53572 /* 53572 chipcommon chipid */ - -/* Package IDs */ -#define BCM4303_PKG_ID 2 /* 4303 package id */ -#define BCM4309_PKG_ID 1 /* 4309 package id */ -#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */ -#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */ -#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */ -#define BCM4328USBD11G_PKG_ID 2 /* 4328 802.11g USB package id */ -#define BCM4328USBDUAL_PKG_ID 3 /* 4328 802.11a/g USB package id */ -#define BCM4328SDIOD11G_PKG_ID 4 /* 4328 802.11g SDIO package id */ -#define BCM4328SDIODUAL_PKG_ID 5 /* 4328 802.11a/g SDIO package id */ -#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */ -#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */ -#define BCM5354E_PKG_ID 1 /* 5354E package id */ -#define BCM4716_PKG_ID 8 /* 4716 package id */ -#define BCM4717_PKG_ID 9 /* 4717 package id */ -#define BCM4718_PKG_ID 10 /* 4718 package id */ -#define BCM5356_PKG_NONMODE 1 /* 5356 package without nmode suppport */ -#define BCM5358U_PKG_ID 8 /* 5358U package id */ -#define BCM5358_PKG_ID 9 /* 5358 package id */ -#define BCM47186_PKG_ID 10 /* 47186 package id */ -#define BCM5357_PKG_ID 11 /* 5357 package id */ -#define BCM5356U_PKG_ID 12 /* 5356U package id */ -#define BCM53572_PKG_ID 8 /* 53572 package id */ -#define BCM5357C0_PKG_ID 8 /* 5357c0 package id (the same as 53572) */ -#define BCM47188_PKG_ID 9 /* 47188 package id */ -#define BCM5358C0_PKG_ID 0xa /* 5358c0 package id */ -#define BCM5356C0_PKG_ID 0xb /* 5356c0 package id */ -#define BCM4331TT_PKG_ID 8 /* 4331 12x12 package id */ -#define BCM4331TN_PKG_ID 9 /* 4331 12x9 package id */ -#define BCM4331TNA0_PKG_ID 0xb /* 4331 12x9 package id */ -#define BCM4706L_PKG_ID 1 /* 4706L package id */ - -#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */ -#define HDLSIM_PKG_ID 14 /* HDL simulator package id */ -#define HWSIM_PKG_ID 15 /* Hardware simulator package id */ -#define BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */ -#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ -#define BCM4336_WLBGA_PKG_ID 0x8 -#define BCM4330_WLBGA_PKG_ID 0x0 -#define BCM4314PCIE_ARM_PKG_ID (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */ -#define BCM4314SDIO_PKG_ID (8 | 1) /* 4314 QFN SDIO package id */ -#define BCM4314PCIE_PKG_ID (8 | 2) /* 4314 QFN PCI (ARM-less) package id */ -#define BCM4314SDIO_ARM_PKG_ID (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */ -#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) /* 4314 FpBGA SDIO package id */ -#define BCM4314DEV_PKG_ID (8 | 6) /* 4314 Developement package id */ - -#define BCM4707_PKG_ID 1 /* 4707 package id */ -#define BCM4708_PKG_ID 2 /* 4708 package id */ -#define BCM4709_PKG_ID 0 /* 4709 package id */ - -#define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */ -#define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */ - -#define BCM4335_WLCSP_PKG_ID (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */ -#define BCM4335_FCBGA_PKG_ID (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */ -#define BCM4335_WLBGA_PKG_ID (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */ -#define BCM4335_FCBGAD_PKG_ID (0x3) /* FCBGA Debug Debug/Dev All if's. */ -#define BCM4335_PKG_MASK (0x3) - -/* boardflags */ -#define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */ -#define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */ -#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */ -#define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio 13 radio disable indication, UNUSED */ -#define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */ -#define BFL_DIS_256QAM 0x00000008 -#define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */ -#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */ -#define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */ -#define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */ -#define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */ -#define BFL_UNUSED 0x00000200 -#define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ -#define BFL_FEM 0x00000800 /* Board supports the Front End Module */ -#define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ -#define BFL_HGPA 0x00002000 /* Board has a high gain PA */ -#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */ -#define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */ -#define BFL_NOPA 0x00010000 /* Board has no PA */ -#define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */ -#define BFL_PAREF 0x00040000 /* Board uses the PARef LDO */ -#define BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */ -#define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */ -#define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */ -#define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */ -#define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */ -#define BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */ -#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */ -#define BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */ -#define BFL_FASTPWR 0x08000000 -#define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */ -#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ -#define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */ -#define BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ -#define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */ -#define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field - * when this flag is set - */ -#define BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */ - -/* boardflags2 */ -#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */ -#define BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ -#define BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */ -#define BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */ -#define BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */ -#define BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */ -#define BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */ -#define BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */ -#define BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace - * BFL2_BTC3WIRE - */ -#define BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */ -#define BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */ -#define BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */ -#define BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */ -#define BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ -#define BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */ -#define BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */ -#define BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */ -#define BFL2_DAC_SPUR_IMPROVEMENT 0x00008000 /* Reducing DAC Spurs */ -#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */ -#define BFL2_IPALVLSHIFT_3P3 0x00020000 -#define BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */ -#define BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */ - /* Most drivers will turn it off without this flag */ - /* to save power. */ - -#define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */ -#define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */ -#define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */ -#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */ -#define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value - * than programmed. The exact delta is decided by - * driver per chip/boardtype. This can be used - * when tempsense qualification happens after shipment - */ -#define BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */ -#define BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */ -#define BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save */ - /* ucode control of eLNA during Tx */ -#define BFL2_4313_RADIOREG 0x10000000 - /* board rework */ -#define BFL2_DYNAMIC_VMID 0x10000000 /* enable dynamic Vmid in idle TSSI CAL for 4331 */ - -#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ -#define BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */ -#define BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */ -#define BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */ - -/* SROM 11 - 11ac boardflag definitions */ -#define BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */ -#define BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */ -#define BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ -#define BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ -#define BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ -#define BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ -#define BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */ -#define BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */ -#define BFL2_SROM11_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ - -/* boardflags3 */ -#define BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */ -#define BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */ -#define BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */ -#define BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */ -#define BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */ -#define BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */ -#define BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */ -#define BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */ -#define BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */ -#define BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */ -#define BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */ -#define BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */ -#define BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */ -#define BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */ -#define BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */ -#define BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */ -#define BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */ -#define BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */ -#define BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */ -#define BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */ -/* acphy, to use backed off gaintbl for lte-coex */ -#define BFL3_LTECOEX_GAINTBL_EN 0x00060000 -/* acphy, to use backed off gaintbl for lte-coex */ -#define BFL3_LTECOEX_GAINTBL_EN_SHIFT 17 -#define BFL3_5G_SPUR_WAR 0x00080000 /* acphy, enable spur WAR in 5G band */ - -/* acphy: lpmode2g and lpmode_5g related boardflags */ -#define BFL3_ACPHY_LPMODE_2G 0x00300000 /* bits 20:21 for lpmode_2g choice */ -#define BFL3_ACPHY_LPMODE_2G_SHIFT 20 - -#define BFL3_ACPHY_LPMODE_5G 0x00C00000 /* bits 22:23 for lpmode_5g choice */ -#define BFL3_ACPHY_LPMODE_5G_SHIFT 22 - -#define BFL3_EXT_LPO_ISCLOCK 0x02000000 /* External LPO is clock, not x-tal */ -#define BFL3_FORCE_INT_LPO_SEL 0x04000000 /* Force internal lpo */ -#define BFL3_FORCE_EXT_LPO_SEL 0x08000000 /* Force external lpo */ - -#define BFL3_EN_BRCM_IMPBF 0x10000000 /* acphy, Allow BRCM Implicit TxBF */ -#define BFL3_AVVMID_FROM_NVRAM 0x40000000 /* Read Av Vmid from NVRAM */ -#define BFL3_VLIN_EN_FROM_NVRAM 0x80000000 /* Read Vlin En from NVRAM */ - -#define BFL3_AVVMID_FROM_NVRAM_SHIFT 30 /* Read Av Vmid from NVRAM */ -#define BFL3_VLIN_EN_FROM_NVRAM_SHIFT 31 /* Enable Vlin from NVRAM */ - - -/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */ -#define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ -#define BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */ -#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */ -#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */ -#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */ -#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */ -#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */ -#define BOARD_GPIO_12 0x1000 /* gpio 12 */ -#define BOARD_GPIO_13 0x2000 /* gpio 13 */ -#define BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */ -#define BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */ -#define BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */ -#define BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */ -#define BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */ -#define BOARD_GPIO_2_WLAN_PWR 0x04 /* throttle WLAN power on X29C board */ -#define BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */ -#define BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */ - -#define GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */ -#define GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */ -#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */ -#define GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */ -#define GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */ -#define GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */ -#define GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */ - -#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ -#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ -#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal power-up */ -#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL power-down */ - -/* power control defines */ -#define PLL_DELAY 150 /* us pll on delay */ -#define FREF_DELAY 200 /* us fref change delay */ -#define MIN_SLOW_CLK 32 /* us Slow clock period */ -#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ - - -/* 43341 Boards */ -#define BCM943341WLABGS_SSID 0x062d - -/* 43342 Boards */ -#define BCM943342FCAGBI_SSID 0x0641 - -/* 43602 Boards, unclear yet what boards will be created. */ -#define BCM943602RSVD1_SSID 0x06a5 -#define BCM943602RSVD2_SSID 0x06a6 - -/* # of GPIO pins */ -#define GPIO_NUMPINS 32 - -/* These values are used by dhd host driver. */ -#define RDL_RAM_BASE_4319 0x60000000 -#define RDL_RAM_BASE_4329 0x60000000 -#define RDL_RAM_SIZE_4319 0x48000 -#define RDL_RAM_SIZE_4329 0x48000 -#define RDL_RAM_SIZE_43236 0x70000 -#define RDL_RAM_BASE_43236 0x60000000 -#define RDL_RAM_SIZE_4328 0x60000 -#define RDL_RAM_BASE_4328 0x80000000 -#define RDL_RAM_SIZE_4322 0x60000 -#define RDL_RAM_BASE_4322 0x60000000 -#define RDL_RAM_SIZE_4360 0xA0000 -#define RDL_RAM_BASE_4360 0x60000000 -#define RDL_RAM_SIZE_43242 0x90000 -#define RDL_RAM_BASE_43242 0x60000000 -#define RDL_RAM_SIZE_43143 0x70000 -#define RDL_RAM_BASE_43143 0x60000000 -#define RDL_RAM_SIZE_4350 0xC0000 -#define RDL_RAM_BASE_4350 0x180800 - -/* generic defs for nvram "muxenab" bits -* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options. -*/ -#define MUXENAB_UART 0x00000001 -#define MUXENAB_GPIO 0x00000002 -#define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */ -#define MUXENAB_JTAG 0x00000008 -#define MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */ -#define MUXENAB_I2S_EN 0x00000020 -#define MUXENAB_I2S_MASTER 0x00000040 -#define MUXENAB_I2S_FULL 0x00000080 -#define MUXENAB_SFLASH 0x00000100 -#define MUXENAB_RFSWCTRL0 0x00000200 -#define MUXENAB_RFSWCTRL1 0x00000400 -#define MUXENAB_RFSWCTRL2 0x00000800 -#define MUXENAB_SECI 0x00001000 -#define MUXENAB_BT_LEGACY 0x00002000 -#define MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */ - -/* Boot flags */ -#define FLASH_KERNEL_NFLASH 0x00000001 -#define FLASH_BOOT_NFLASH 0x00000002 - -#endif /* _BCMDEVS_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h deleted file mode 100755 index 3e783eae32be..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Byte order utilities - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmendian.h 402715 2013-05-16 18:50:09Z $ - * - * This file by default provides proper behavior on little-endian architectures. - * On big-endian architectures, IL_BIGENDIAN should be defined. - */ - -#ifndef _BCMENDIAN_H_ -#define _BCMENDIAN_H_ - -#include - -/* Reverse the bytes in a 16-bit value */ -#define BCMSWAP16(val) \ - ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ - (((uint16)(val) & (uint16)0xff00U) >> 8))) - -/* Reverse the bytes in a 32-bit value */ -#define BCMSWAP32(val) \ - ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ - (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ - (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ - (((uint32)(val) & (uint32)0xff000000U) >> 24))) - -/* Reverse the two 16-bit halves of a 32-bit value */ -#define BCMSWAP32BY16(val) \ - ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ - (((uint32)(val) & (uint32)0xffff0000U) >> 16))) - -/* Reverse the bytes in a 64-bit value */ -#define BCMSWAP64(val) \ - ((uint64)((((uint64)(val) & 0x00000000000000ffULL) << 56) | \ - (((uint64)(val) & 0x000000000000ff00ULL) << 40) | \ - (((uint64)(val) & 0x0000000000ff0000ULL) << 24) | \ - (((uint64)(val) & 0x00000000ff000000ULL) << 8) | \ - (((uint64)(val) & 0x000000ff00000000ULL) >> 8) | \ - (((uint64)(val) & 0x0000ff0000000000ULL) >> 24) | \ - (((uint64)(val) & 0x00ff000000000000ULL) >> 40) | \ - (((uint64)(val) & 0xff00000000000000ULL) >> 56))) - -/* Reverse the two 32-bit halves of a 64-bit value */ -#define BCMSWAP64BY32(val) \ - ((uint64)((((uint64)(val) & 0x00000000ffffffffULL) << 32) | \ - (((uint64)(val) & 0xffffffff00000000ULL) >> 32))) - - -/* Byte swapping macros - * Host <=> Network (Big Endian) for 16- and 32-bit values - * Host <=> Little-Endian for 16- and 32-bit values - */ -#ifndef hton16 -#define HTON16(i) BCMSWAP16(i) -#define hton16(i) bcmswap16(i) -#define HTON32(i) BCMSWAP32(i) -#define hton32(i) bcmswap32(i) -#define NTOH16(i) BCMSWAP16(i) -#define ntoh16(i) bcmswap16(i) -#define NTOH32(i) BCMSWAP32(i) -#define ntoh32(i) bcmswap32(i) -#define LTOH16(i) (i) -#define ltoh16(i) (i) -#define LTOH32(i) (i) -#define ltoh32(i) (i) -#define HTOL16(i) (i) -#define htol16(i) (i) -#define HTOL32(i) (i) -#define htol32(i) (i) -#define HTOL64(i) (i) -#define htol64(i) (i) -#endif /* hton16 */ - -#define ltoh16_buf(buf, i) -#define htol16_buf(buf, i) - -/* Unaligned loads and stores in host byte order */ -#define load32_ua(a) ltoh32_ua(a) -#define store32_ua(a, v) htol32_ua_store(v, a) -#define load16_ua(a) ltoh16_ua(a) -#define store16_ua(a, v) htol16_ua_store(v, a) - -#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) -#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) -#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) -#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) - -#define ltoh_ua(ptr) \ - (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ - sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ - sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ - *(uint8 *)0) - -#define ntoh_ua(ptr) \ - (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ - sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ - sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ - *(uint8 *)0) - -#ifdef __GNUC__ - -/* GNU macro versions avoid referencing the argument multiple times, while also - * avoiding the -fno-inline used in ROM builds. - */ - -#define bcmswap16(val) ({ \ - uint16 _val = (val); \ - BCMSWAP16(_val); \ -}) - -#define bcmswap32(val) ({ \ - uint32 _val = (val); \ - BCMSWAP32(_val); \ -}) - -#define bcmswap64(val) ({ \ - uint64 _val = (val); \ - BCMSWAP64(_val); \ -}) - -#define bcmswap32by16(val) ({ \ - uint32 _val = (val); \ - BCMSWAP32BY16(_val); \ -}) - -#define bcmswap16_buf(buf, len) ({ \ - uint16 *_buf = (uint16 *)(buf); \ - uint _wds = (len) / 2; \ - while (_wds--) { \ - *_buf = bcmswap16(*_buf); \ - _buf++; \ - } \ -}) - -#define htol16_ua_store(val, bytes) ({ \ - uint16 _val = (val); \ - uint8 *_bytes = (uint8 *)(bytes); \ - _bytes[0] = _val & 0xff; \ - _bytes[1] = _val >> 8; \ -}) - -#define htol32_ua_store(val, bytes) ({ \ - uint32 _val = (val); \ - uint8 *_bytes = (uint8 *)(bytes); \ - _bytes[0] = _val & 0xff; \ - _bytes[1] = (_val >> 8) & 0xff; \ - _bytes[2] = (_val >> 16) & 0xff; \ - _bytes[3] = _val >> 24; \ -}) - -#define hton16_ua_store(val, bytes) ({ \ - uint16 _val = (val); \ - uint8 *_bytes = (uint8 *)(bytes); \ - _bytes[0] = _val >> 8; \ - _bytes[1] = _val & 0xff; \ -}) - -#define hton32_ua_store(val, bytes) ({ \ - uint32 _val = (val); \ - uint8 *_bytes = (uint8 *)(bytes); \ - _bytes[0] = _val >> 24; \ - _bytes[1] = (_val >> 16) & 0xff; \ - _bytes[2] = (_val >> 8) & 0xff; \ - _bytes[3] = _val & 0xff; \ -}) - -#define ltoh16_ua(bytes) ({ \ - const uint8 *_bytes = (const uint8 *)(bytes); \ - _LTOH16_UA(_bytes); \ -}) - -#define ltoh32_ua(bytes) ({ \ - const uint8 *_bytes = (const uint8 *)(bytes); \ - _LTOH32_UA(_bytes); \ -}) - -#define ntoh16_ua(bytes) ({ \ - const uint8 *_bytes = (const uint8 *)(bytes); \ - _NTOH16_UA(_bytes); \ -}) - -#define ntoh32_ua(bytes) ({ \ - const uint8 *_bytes = (const uint8 *)(bytes); \ - _NTOH32_UA(_bytes); \ -}) - -#else /* !__GNUC__ */ - -/* Inline versions avoid referencing the argument multiple times */ -static INLINE uint16 -bcmswap16(uint16 val) -{ - return BCMSWAP16(val); -} - -static INLINE uint32 -bcmswap32(uint32 val) -{ - return BCMSWAP32(val); -} - -static INLINE uint64 -bcmswap64(uint64 val) -{ - return BCMSWAP64(val); -} - -static INLINE uint32 -bcmswap32by16(uint32 val) -{ - return BCMSWAP32BY16(val); -} - -/* Reverse pairs of bytes in a buffer (not for high-performance use) */ -/* buf - start of buffer of shorts to swap */ -/* len - byte length of buffer */ -static INLINE void -bcmswap16_buf(uint16 *buf, uint len) -{ - len = len / 2; - - while (len--) { - *buf = bcmswap16(*buf); - buf++; - } -} - -/* - * Store 16-bit value to unaligned little-endian byte array. - */ -static INLINE void -htol16_ua_store(uint16 val, uint8 *bytes) -{ - bytes[0] = val & 0xff; - bytes[1] = val >> 8; -} - -/* - * Store 32-bit value to unaligned little-endian byte array. - */ -static INLINE void -htol32_ua_store(uint32 val, uint8 *bytes) -{ - bytes[0] = val & 0xff; - bytes[1] = (val >> 8) & 0xff; - bytes[2] = (val >> 16) & 0xff; - bytes[3] = val >> 24; -} - -/* - * Store 16-bit value to unaligned network-(big-)endian byte array. - */ -static INLINE void -hton16_ua_store(uint16 val, uint8 *bytes) -{ - bytes[0] = val >> 8; - bytes[1] = val & 0xff; -} - -/* - * Store 32-bit value to unaligned network-(big-)endian byte array. - */ -static INLINE void -hton32_ua_store(uint32 val, uint8 *bytes) -{ - bytes[0] = val >> 24; - bytes[1] = (val >> 16) & 0xff; - bytes[2] = (val >> 8) & 0xff; - bytes[3] = val & 0xff; -} - -/* - * Load 16-bit value from unaligned little-endian byte array. - */ -static INLINE uint16 -ltoh16_ua(const void *bytes) -{ - return _LTOH16_UA((const uint8 *)bytes); -} - -/* - * Load 32-bit value from unaligned little-endian byte array. - */ -static INLINE uint32 -ltoh32_ua(const void *bytes) -{ - return _LTOH32_UA((const uint8 *)bytes); -} - -/* - * Load 16-bit value from unaligned big-(network-)endian byte array. - */ -static INLINE uint16 -ntoh16_ua(const void *bytes) -{ - return _NTOH16_UA((const uint8 *)bytes); -} - -/* - * Load 32-bit value from unaligned big-(network-)endian byte array. - */ -static INLINE uint32 -ntoh32_ua(const void *bytes) -{ - return _NTOH32_UA((const uint8 *)bytes); -} - -#endif /* !__GNUC__ */ -#endif /* !_BCMENDIAN_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h deleted file mode 100755 index e4b785c84f4c..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h +++ /dev/null @@ -1,272 +0,0 @@ -/* - * NVRAM variable manipulation - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmnvram.h 428512 2013-10-09 02:12:11Z $ - */ - -#ifndef _bcmnvram_h_ -#define _bcmnvram_h_ - -#ifndef _LANGUAGE_ASSEMBLY - -#include -#include - -struct nvram_header { - uint32 magic; - uint32 len; - uint32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ - uint32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ - uint32 config_ncdl; /* ncdl values for memc */ -}; - -struct nvram_tuple { - char *name; - char *value; - struct nvram_tuple *next; -}; - -/* - * Get default value for an NVRAM variable - */ -extern char *nvram_default_get(const char *name); -/* - * validate/restore all per-interface related variables - */ -extern void nvram_validate_all(char *prefix, bool restore); - -/* - * restore specific per-interface variable - */ -extern void nvram_restore_var(char *prefix, char *name); - -/* - * Initialize NVRAM access. May be unnecessary or undefined on certain - * platforms. - */ -extern int nvram_init(void *sih); -extern int nvram_deinit(void *sih); - - -/* - * Append a chunk of nvram variables to the global list - */ -extern int nvram_append(void *si, char *vars, uint varsz); - -extern void nvram_get_global_vars(char **varlst, uint *varsz); - - -/* - * Check for reset button press for restoring factory defaults. - */ -extern int nvram_reset(void *sih); - -/* - * Disable NVRAM access. May be unnecessary or undefined on certain - * platforms. - */ -extern void nvram_exit(void *sih); - -/* - * Get the value of an NVRAM variable. The pointer returned may be - * invalid after a set. - * @param name name of variable to get - * @return value of variable or NULL if undefined - */ -extern char * nvram_get(const char *name); - -/* - * Read the reset GPIO value from the nvram and set the GPIO - * as input - */ -extern int nvram_resetgpio_init(void *sih); - -/* - * Get the value of an NVRAM variable. - * @param name name of variable to get - * @return value of variable or NUL if undefined - */ -static INLINE char * -nvram_safe_get(const char *name) -{ - char *p = nvram_get(name); - return p ? p : ""; -} - -/* - * Match an NVRAM variable. - * @param name name of variable to match - * @param match value to compare against value of variable - * @return TRUE if variable is defined and its value is string equal - * to match or FALSE otherwise - */ -static INLINE int -nvram_match(const char *name, const char *match) -{ - const char *value = nvram_get(name); - return (value && !strcmp(value, match)); -} - -/* - * Inversely match an NVRAM variable. - * @param name name of variable to match - * @param match value to compare against value of variable - * @return TRUE if variable is defined and its value is not string - * equal to invmatch or FALSE otherwise - */ -static INLINE int -nvram_invmatch(const char *name, const char *invmatch) -{ - const char *value = nvram_get(name); - return (value && strcmp(value, invmatch)); -} - -/* - * Set the value of an NVRAM variable. The name and value strings are - * copied into private storage. Pointers to previously set values - * may become invalid. The new value may be immediately - * retrieved but will not be permanently stored until a commit. - * @param name name of variable to set - * @param value value of variable - * @return 0 on success and errno on failure - */ -extern int nvram_set(const char *name, const char *value); - -/* - * Unset an NVRAM variable. Pointers to previously set values - * remain valid until a set. - * @param name name of variable to unset - * @return 0 on success and errno on failure - * NOTE: use nvram_commit to commit this change to flash. - */ -extern int nvram_unset(const char *name); - -/* - * Commit NVRAM variables to permanent storage. All pointers to values - * may be invalid after a commit. - * NVRAM values are undefined after a commit. - * @param nvram_corrupt true to corrupt nvram, false otherwise. - * @return 0 on success and errno on failure - */ -extern int nvram_commit_internal(bool nvram_corrupt); - -/* - * Commit NVRAM variables to permanent storage. All pointers to values - * may be invalid after a commit. - * NVRAM values are undefined after a commit. - * @return 0 on success and errno on failure - */ -extern int nvram_commit(void); - -/* - * Get all NVRAM variables (format name=value\0 ... \0\0). - * @param buf buffer to store variables - * @param count size of buffer in bytes - * @return 0 on success and errno on failure - */ -extern int nvram_getall(char *nvram_buf, int count); - -/* - * returns the crc value of the nvram - * @param nvh nvram header pointer - */ -uint8 nvram_calc_crc(struct nvram_header * nvh); - -extern int nvram_space; -#endif /* _LANGUAGE_ASSEMBLY */ - -/* The NVRAM version number stored as an NVRAM variable */ -#define NVRAM_SOFTWARE_VERSION "1" - -#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */ -#define NVRAM_CLEAR_MAGIC 0x0 -#define NVRAM_INVALID_MAGIC 0xFFFFFFFF -#define NVRAM_VERSION 1 -#define NVRAM_HEADER_SIZE 20 -/* This definition is for precommit staging, and will be removed */ -#define NVRAM_SPACE 0x8000 -/* For CFE builds this gets passed in thru the makefile */ -#ifndef MAX_NVRAM_SPACE -#define MAX_NVRAM_SPACE 0x10000 -#endif -#define DEF_NVRAM_SPACE 0x8000 -#define ROM_ENVRAM_SPACE 0x1000 -#define NVRAM_LZMA_MAGIC 0x4c5a4d41 /* 'LZMA' */ - -#define NVRAM_MAX_VALUE_LEN 255 -#define NVRAM_MAX_PARAM_LEN 64 - -#define NVRAM_CRC_START_POSITION 9 /* magic, len, crc8 to be skipped */ -#define NVRAM_CRC_VER_MASK 0xffffff00 /* for crc_ver_init */ - -/* Offsets to embedded nvram area */ -#define NVRAM_START_COMPRESSED 0x400 -#define NVRAM_START 0x1000 - -#define BCM_JUMBO_NVRAM_DELIMIT '\n' -#define BCM_JUMBO_START "Broadcom Jumbo Nvram file" - - -#if (defined(FAILSAFE_UPGRADE) || defined(CONFIG_FAILSAFE_UPGRADE) || \ - defined(__CONFIG_FAILSAFE_UPGRADE_SUPPORT__)) -#define IMAGE_SIZE "image_size" -#define BOOTPARTITION "bootpartition" -#define IMAGE_BOOT BOOTPARTITION -#define PARTIALBOOTS "partialboots" -#define MAXPARTIALBOOTS "maxpartialboots" -#define IMAGE_1ST_FLASH_TRX "flash0.trx" -#define IMAGE_1ST_FLASH_OS "flash0.os" -#define IMAGE_2ND_FLASH_TRX "flash0.trx2" -#define IMAGE_2ND_FLASH_OS "flash0.os2" -#define IMAGE_FIRST_OFFSET "image_first_offset" -#define IMAGE_SECOND_OFFSET "image_second_offset" -#define LINUX_FIRST "linux" -#define LINUX_SECOND "linux2" -#endif - -#if (defined(DUAL_IMAGE) || defined(CONFIG_DUAL_IMAGE) || \ - defined(__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__)) -/* Shared by all: CFE, Linux Kernel, and Ap */ -#define IMAGE_BOOT "image_boot" -#define BOOTPARTITION IMAGE_BOOT -/* CFE variables */ -#define IMAGE_1ST_FLASH_TRX "flash0.trx" -#define IMAGE_1ST_FLASH_OS "flash0.os" -#define IMAGE_2ND_FLASH_TRX "flash0.trx2" -#define IMAGE_2ND_FLASH_OS "flash0.os2" -#define IMAGE_SIZE "image_size" - -/* CFE and Linux Kernel shared variables */ -#define IMAGE_FIRST_OFFSET "image_first_offset" -#define IMAGE_SECOND_OFFSET "image_second_offset" - -/* Linux application variables */ -#define LINUX_FIRST "linux" -#define LINUX_SECOND "linux2" -#define POLICY_TOGGLE "toggle" -#define LINUX_PART_TO_FLASH "linux_to_flash" -#define LINUX_FLASH_POLICY "linux_flash_policy" - -#endif /* defined(DUAL_IMAGE||CONFIG_DUAL_IMAGE)||__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__ */ - -#endif /* _bcmnvram_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h deleted file mode 100755 index 49790c24ae22..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Broadcom PCI-SPI Host Controller Register Definitions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmpcispi.h 241182 2011-02-17 21:50:03Z $ - */ -#ifndef _BCM_PCI_SPI_H -#define _BCM_PCI_SPI_H - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - - -typedef volatile struct { - uint32 spih_ctrl; /* 0x00 SPI Control Register */ - uint32 spih_stat; /* 0x04 SPI Status Register */ - uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ - uint32 spih_ext; /* 0x0C SPI Extension Register */ - uint32 PAD[4]; /* 0x10-0x1F PADDING */ - - uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ - uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ - uint32 PAD[6]; /* 0x28-0x3F PADDING */ - - uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ - uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ - /* 1=Active High) */ - uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ - uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ - uint32 PAD[4]; /* 0x50-0x5F PADDING */ - - uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ - uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ - uint32 PAD[1]; /* 0x68 PADDING */ - uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ - uint32 PAD[4]; /* 0x70-0x7F PADDING */ - uint32 PAD[8]; /* 0x80-0x9F PADDING */ - uint32 PAD[8]; /* 0xA0-0xBF PADDING */ - uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ - uint32 spih_pll_status; /* 0xC4 PLL Status Register */ - uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ - uint32 spih_clk_count; /* 0xCC External Clock Count Register */ - -} spih_regs_t; - -typedef volatile struct { - uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ - uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ - - uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ - uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ - uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ - uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ - uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ - uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ - uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ - uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ - uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ - uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ - uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ - uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ - uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ - uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ - uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ - uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ - uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ - uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ - uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ - uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ - uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ - uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ - uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ - uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ - uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ - uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ - - uint32 PAD[5]; /* 0x16C-0x17F PADDING */ - - uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ - uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ - uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ - uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ - uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ - uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ - uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ - uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ - uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ - uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ - uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ - uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ - uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ - uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ - uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ - uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ - uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ - uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ - uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ - uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ - uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ - uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ - uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ - uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ - uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ - uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ - - uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ - uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ - uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ -} spih_pciregs_t; - -/* - * PCI Core interrupt enable and status bit definitions. - */ - -/* PCI Core ICR Register bit definitions */ -#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ -#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ -#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ -#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ -#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ -#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ - - -/* PCI Core ISR Register bit definitions */ -#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ -#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ -#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ -#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ -#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ - - -/* Registers on the Wishbone bus */ -#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ -#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ -#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ - -/* GPIO Bit definitions */ -#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ -#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ -#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ - -/* SPI Status Register Bit definitions */ -#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ -#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ -#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ -#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ -#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ -#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ - -#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ - -#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ -#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ - -/* Spin bit loop bound check */ -#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ - -#endif /* _BCM_PCI_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h deleted file mode 100755 index 9cc62882fe40..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Performance counters software interface. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmperf.h 241182 2011-02-17 21:50:03Z $ - */ -/* essai */ -#ifndef _BCMPERF_H_ -#define _BCMPERF_H_ -/* get cache hits and misses */ -#define BCMPERF_ENABLE_INSTRCOUNT() -#define BCMPERF_ENABLE_ICACHE_MISS() -#define BCMPERF_ENABLE_ICACHE_HIT() -#define BCMPERF_GETICACHE_MISS(x) ((x) = 0) -#define BCMPERF_GETICACHE_HIT(x) ((x) = 0) -#define BCMPERF_GETINSTRCOUNT(x) ((x) = 0) -#endif /* _BCMPERF_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h deleted file mode 100755 index 267c974cb33d..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Definitions for API from sdio common code (bcmsdh) to individual - * host controller drivers. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdbus.h 408158 2013-06-17 22:15:35Z $ - */ - -#ifndef _sdio_api_h_ -#define _sdio_api_h_ - - -#define SDIOH_API_RC_SUCCESS (0x00) -#define SDIOH_API_RC_FAIL (0x01) -#define SDIOH_API_SUCCESS(status) (status == 0) - -#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 */ - -#define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */ -#define SDIOH_CMD_TYPE_APPEND 1 /* Append command */ -#define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */ - -#define SDIOH_DATA_PIO 0 /* PIO mode */ -#define SDIOH_DATA_DMA 1 /* DMA mode */ - -/* Max number of glommed pkts */ -#ifdef CUSTOM_MAX_TXGLOM_SIZE -#define SDPCM_MAXGLOM_SIZE CUSTOM_MAX_TXGLOM_SIZE -#else -#define SDPCM_MAXGLOM_SIZE 40 -#endif /* CUSTOM_MAX_TXGLOM_SIZE */ - -#define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ -#define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ - -#ifdef CUSTOM_DEF_TXGLOM_SIZE -#define SDPCM_DEFGLOM_SIZE CUSTOM_DEF_TXGLOM_SIZE -#else -#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE -#endif /* CUSTOM_DEF_TXGLOM_SIZE */ - -#if SDPCM_DEFGLOM_SIZE > SDPCM_MAXGLOM_SIZE -#warning "SDPCM_DEFGLOM_SIZE cannot be higher than SDPCM_MAXGLOM_SIZE!!" -#undef SDPCM_DEFGLOM_SIZE -#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE -#endif - -typedef int SDIOH_API_RC; - -/* SDio Host structure */ -typedef struct sdioh_info sdioh_info_t; - -/* callback function, taking one arg */ -typedef void (*sdioh_cb_fn_t)(void *); - -extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); -extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); - -/* query whether SD interrupt is enabled or not */ -extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff); - -/* enable or disable SD interrupt */ -extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); - -#if defined(DHD_DEBUG) -extern bool sdioh_interrupt_pending(sdioh_info_t *si); -#endif - -/* read or write one byte using cmd52 */ -extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte); - -/* read or write 2/4 bytes using cmd53 */ -extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *si, uint cmd_type, uint rw, uint fnc, - uint addr, uint32 *word, uint nbyte); - -/* read or write any buffer using cmd53 */ -extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc, - uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer, - void *pkt); - -/* get cis data */ -extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); - -extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); -extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); - -/* query number of io functions */ -extern uint sdioh_query_iofnum(sdioh_info_t *si); - -/* handle iovars */ -extern int sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Issue abort to the specified function and clear controller as needed */ -extern int sdioh_abort(sdioh_info_t *si, uint fnc); - -/* Start and Stop SDIO without re-enumerating the SD card. */ -extern int sdioh_start(sdioh_info_t *si, int stage); -extern int sdioh_stop(sdioh_info_t *si); - -/* Wait system lock free */ -extern int sdioh_waitlockfree(sdioh_info_t *si); - -/* Reset and re-initialize the device */ -extern int sdioh_sdio_reset(sdioh_info_t *si); - - - -#if defined(BCMSDIOH_STD) - #define SDIOH_SLEEP_ENABLED -#endif -extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab); - -/* GPIO support */ -extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd); -extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio); -extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio); -extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab); - -#endif /* _sdio_api_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h deleted file mode 100755 index 9946acfb7ea2..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * SDIO host client driver interface of Broadcom HNBU - * export functions to client drivers - * abstract OS and BUS specific details of SDIO - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh.h 455573 2014-02-14 17:49:31Z $ - */ - -/** - * @file bcmsdh.h - */ - -#ifndef _bcmsdh_h_ -#define _bcmsdh_h_ - -#define BCMSDH_ERROR_VAL 0x0001 /* Error */ -#define BCMSDH_INFO_VAL 0x0002 /* Info */ -extern const uint bcmsdh_msglevel; - -#define BCMSDH_ERROR(x) -#define BCMSDH_INFO(x) - -#if (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || defined(BCMSDIOH_SPI)) -#define BCMSDH_ADAPTER -#endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */ - -/* forward declarations */ -typedef struct bcmsdh_info bcmsdh_info_t; -typedef void (*bcmsdh_cb_fn_t)(void *); - -extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva); -/** - * BCMSDH API context - */ -struct bcmsdh_info -{ - bool init_success; /* underlying driver successfully attached */ - void *sdioh; /* handler for sdioh */ - uint32 vendevid; /* Target Vendor and Device ID on SD bus */ - osl_t *osh; - bool regfail; /* Save status of last reg_read/reg_write call */ - uint32 sbwad; /* Save backplane window address */ - void *os_cxt; /* Pointer to per-OS private data */ -}; - -/* Detach - freeup resources allocated in attach */ -extern int bcmsdh_detach(osl_t *osh, void *sdh); - -/* Query if SD device interrupts are enabled */ -extern bool bcmsdh_intr_query(void *sdh); - -/* Enable/disable SD interrupt */ -extern int bcmsdh_intr_enable(void *sdh); -extern int bcmsdh_intr_disable(void *sdh); - -/* Register/deregister device interrupt handler. */ -extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); -extern int bcmsdh_intr_dereg(void *sdh); -/* Enable/disable SD card interrupt forward */ -extern void bcmsdh_intr_forward(void *sdh, bool pass); - -#if defined(DHD_DEBUG) -/* Query pending interrupt status from the host controller */ -extern bool bcmsdh_intr_pending(void *sdh); -#endif - -/* Register a callback to be called if and when bcmsdh detects - * device removal. No-op in the case of non-removable/hardwired devices. - */ -extern int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); - -/* 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 uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err); -extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err); - -/* Read/Write 4bytes from/to cfg space */ -extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err); -extern void bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err); - -/* Read CIS content for specified function. - * fn: function whose CIS is being requested (0 is common CIS) - * cis: pointer to memory location to place results - * length: number of bytes to read - * Internally, this routine uses the values from the cis base regs (0x9-0xB) - * to form an SDIO-space address to read the data from. - */ -extern int bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length); - -/* 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 uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size); -extern uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data); - -/* set sb address window */ -extern int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set); - -/* Indicate if last reg read/write failed */ -extern bool bcmsdh_regfail(void *sdh); - -/* 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. - */ -typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting); -extern int bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete_fn, void *handle); -extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete_fn, void *handle); - -extern void bcmsdh_glom_post(void *sdh, uint8 *frame, void *pkt, uint len); -extern void bcmsdh_glom_clear(void *sdh); -extern uint bcmsdh_set_mode(void *sdh, uint mode); -extern bool bcmsdh_glom_enabled(void); -/* Flags bits */ -#define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */ -#define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */ -#define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */ -#define SDIO_BYTE_MODE 0x8 /* Byte mode request(non-block mode) */ - -/* Pending (non-error) return code */ -#define BCME_PENDING 1 - -/* 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 bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes); - -/* Issue an abort to the specified function */ -extern int bcmsdh_abort(void *sdh, uint fn); - -/* Start SDIO Host Controller communication */ -extern int bcmsdh_start(void *sdh, int stage); - -/* Stop SDIO Host Controller communication */ -extern int bcmsdh_stop(void *sdh); - -/* Wait system lock free */ -extern int bcmsdh_waitlockfree(void *sdh); - -/* Returns the "Device ID" of target device on the SDIO bus. */ -extern int bcmsdh_query_device(void *sdh); - -/* Returns the number of IO functions reported by the device */ -extern uint bcmsdh_query_iofnum(void *sdh); - -/* Miscellaneous knob tweaker. */ -extern int bcmsdh_iovar_op(void *sdh, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Reset and reinitialize the device */ -extern int bcmsdh_reset(bcmsdh_info_t *sdh); - -/* helper functions */ - -/* callback functions */ -typedef struct { - /* probe the device */ - void *(*probe)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot, - uint16 func, uint bustype, void * regsva, osl_t * osh, - void * param); - /* remove the device */ - void (*remove)(void *context); - /* can we suspend now */ - int (*suspend)(void *context); - /* resume from suspend */ - int (*resume)(void *context); -} bcmsdh_driver_t; - -/* platform specific/high level functions */ -extern int bcmsdh_register(bcmsdh_driver_t *driver); -extern void bcmsdh_unregister(void); -extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device); -extern void bcmsdh_device_remove(void * sdh); - -extern int bcmsdh_reg_sdio_notify(void* semaphore); -extern void bcmsdh_unreg_sdio_notify(void); - -#if defined(OOB_INTR_ONLY) -extern int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, - void* oob_irq_handler_context); -extern void bcmsdh_oob_intr_unregister(bcmsdh_info_t *sdh); -extern void bcmsdh_oob_intr_set(bcmsdh_info_t *sdh, bool enable); -#endif -extern void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *sdh); -extern void bcmsdh_dev_relax(bcmsdh_info_t *sdh); -extern bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *sdh); - -int bcmsdh_suspend(bcmsdh_info_t *bcmsdh); -int bcmsdh_resume(bcmsdh_info_t *bcmsdh); - -/* Function to pass device-status bits to DHD. */ -extern uint32 bcmsdh_get_dstatus(void *sdh); - -/* Function to return current window addr */ -extern uint32 bcmsdh_cur_sbwad(void *sdh); - -/* Function to pass chipid and rev to lower layers for controlling pr's */ -extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); - - -extern int bcmsdh_sleep(void *sdh, bool enab); - -/* GPIO support */ -extern int bcmsdh_gpio_init(void *sd); -extern bool bcmsdh_gpioin(void *sd, uint32 gpio); -extern int bcmsdh_gpioouten(void *sd, uint32 gpio); -extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); - -#endif /* _bcmsdh_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h deleted file mode 100755 index c98171fd3015..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdh_sdmmc.h 444019 2013-12-18 08:36:54Z $ - */ - -#ifndef __BCMSDH_SDMMC_H__ -#define __BCMSDH_SDMMC_H__ - -#define sd_err(x) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) - - -#define sd_sync_dma(sd, read, nbytes) -#define sd_init_dma(sd) -#define sd_ack_intr(sd) -#define sd_wakeup(sd); - -#define sd_log(x) - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_4318 64 -#define BLOCK_SIZE_4328 512 - -/* internal return code */ -#define SUCCESS 0 -#define ERROR 1 - -/* private bus modes */ -#define SDIOH_MODE_SD4 2 -#define CLIENT_INTR 0x100 /* Get rid of this! */ -#define SDIOH_SDMMC_MAX_SG_ENTRIES (SDPCM_MAXGLOM_SIZE+2) - -struct sdioh_info { - osl_t *osh; /* osh handler */ - void *bcmsdh; /* upper layer handle */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - uint16 intmask; /* Current active interrupts */ - - int intrcount; /* Client interrupts */ - bool sd_use_dma; /* DMA on CMD53 */ - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - bool use_rxchain; - struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; - struct sdio_func fake_func0; - struct sdio_func *func[SDIOD_MAX_IOFUNCS]; - -}; - -/************************************************************ - * Internal interfaces: per-port references into bcmsdh_sdmmc.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/* OS-independent interrupt handler */ -extern bool check_client_intr(sdioh_info_t *sd); - -/* Core interrupt enable/disable of device interrupts */ -extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); -extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); - - -/************************************************************** - * Internal interfaces: bcmsdh_sdmmc.c references to per-port code - */ - -/* Register mapping routines */ -extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size); -extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size); - -/* Interrupt (de)registration routines */ -extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); -extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd); - -extern sdioh_info_t *sdioh_attach(osl_t *osh, struct sdio_func *func); -extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); -#endif /* __BCMSDH_SDMMC_H__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h deleted file mode 100755 index 9c9c32e1ed24..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Broadcom SDIO/PCMCIA - * Software-specific definitions shared between device and host side - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdpcm.h 414378 2013-07-24 15:58:50Z $ - */ - -#ifndef _bcmsdpcm_h_ -#define _bcmsdpcm_h_ - -/* - * Software allocation of To SB Mailbox resources - */ - -/* intstatus bits */ -#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */ -#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */ -#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */ -#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */ - -#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) - -/* tosbmailbox bits corresponding to intstatus bits */ -#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ -#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ -#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ -#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ -#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */ - -/* tosbmailboxdata */ -#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */ -#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */ - -/* - * Software allocation of To Host Mailbox resources - */ - -/* intstatus bits */ -#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */ -#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */ -#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */ -#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */ - -#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT) - -/* tohostmailbox bits corresponding to intstatus bits */ -#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */ -#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */ -#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ -#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ -#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */ - -/* tohostmailboxdata */ -#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */ -#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */ -#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */ -#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */ -#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */ - -#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */ -#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ - -#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */ -#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ - -/* - * Software-defined protocol header - */ - -/* Current protocol version */ -#define SDPCM_PROT_VERSION 4 - -/* SW frame header */ -#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ -#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ - -#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ -#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ -#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ - -#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ -#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ -#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ - -/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ -#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ -#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ -#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ -#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) (((uint8 *)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) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) -#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ -#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) -#define SDPCM_VERSION_OFFSET 6 /* Version # */ -#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) -#define SDPCM_UNUSED_OFFSET 7 /* Spare */ -#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) - -#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ - -/* logical channel numbers */ -#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response 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 (superframes) */ -#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ -#define SDPCM_MAX_CHANNEL 15 - -#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ - -#define SDPCM_FLAG_RESVD0 0x01 -#define SDPCM_FLAG_RESVD1 0x02 -#define SDPCM_FLAG_GSPI_TXENAB 0x04 -#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ - -/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ -#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) - -#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80) - -/* For TEST_CHANNEL packets, define another 4-byte header */ -#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2); - * Semantics of Ext byte depend on command. - * Len is current or requested frame length, not - * including test header; sent little-endian. - */ -#define SDPCM_TEST_PKT_CNT_FLD_LEN 4 /* Packet count filed legth */ -#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ -#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ -#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ -#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count - * (Backward compatabilty) Set frame count in a - * 4 byte filed adjacent to the HDR - */ -#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off - * Set frame count in a 4 byte filed adjacent to - * the HDR - */ - -/* Handy macro for filling in datagen packets with a pattern */ -#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) - -/* - * Software counters (first part matches hardware counters) - */ - -typedef volatile struct { - uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ - uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ - uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ - uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ - uint32 abort; /* AbortCount, SDIO: aborts */ - uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ - uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ - uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ - uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ - uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ - uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ - uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ - uint32 rxdescuflo; /* receive descriptor underflows */ - uint32 rxfifooflo; /* receive fifo overflows */ - uint32 txfifouflo; /* transmit fifo underflows */ - uint32 runt; /* runt (too short) frames recv'd from bus */ - uint32 badlen; /* frame's rxh len does not match its hw tag len */ - uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ - uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ - uint32 rxfcrc; /* frame rx header indicates crc error */ - uint32 rxfwoos; /* frame rx header indicates write out of sync */ - uint32 rxfwft; /* frame rx header indicates write frame termination */ - uint32 rxfabort; /* frame rx header indicates frame aborted */ - uint32 woosint; /* write out of sync interrupt */ - uint32 roosint; /* read out of sync interrupt */ - uint32 rftermint; /* read frame terminate interrupt */ - uint32 wftermint; /* write frame terminate interrupt */ -} sdpcmd_cnt_t; - -/* - * Register Access Macros - */ - -#define SDIODREV_IS(var, val) ((var) == (val)) -#define SDIODREV_GE(var, val) ((var) >= (val)) -#define SDIODREV_GT(var, val) ((var) > (val)) -#define SDIODREV_LT(var, val) ((var) < (val)) -#define SDIODREV_LE(var, val) ((var) <= (val)) - -#define SDIODDMAREG32(h, dir, chnl) \ - ((dir) == DMA_TX ? \ - (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ - (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv)) - -#define SDIODDMAREG64(h, dir, chnl) \ - ((dir) == DMA_TX ? \ - (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ - (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv)) - -#define SDIODDMAREG(h, dir, chnl) \ - (SDIODREV_LT((h)->corerev, 1) ? \ - SDIODDMAREG32((h), (dir), (chnl)) : \ - SDIODDMAREG64((h), (dir), (chnl))) - -#define PCMDDMAREG(h, dir, chnl) \ - ((dir) == DMA_TX ? \ - (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \ - (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv)) - -#define SDPCMDMAREG(h, dir, chnl, coreid) \ - ((coreid) == SDIOD_CORE_ID ? \ - SDIODDMAREG(h, dir, chnl) : \ - PCMDDMAREG(h, dir, chnl)) - -#define SDIODFIFOREG(h, corerev) \ - (SDIODREV_LT((corerev), 1) ? \ - ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \ - ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo))) - -#define PCMDFIFOREG(h) \ - ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo)) - -#define SDPCMFIFOREG(h, coreid, corerev) \ - ((coreid) == SDIOD_CORE_ID ? \ - SDIODFIFOREG(h, corerev) : \ - PCMDFIFOREG(h)) - -/* - * Shared structure between dongle and the host. - * The structure contains pointers to trap or assert information. - */ -#define SDPCM_SHARED_VERSION 0x0001 -#define SDPCM_SHARED_VERSION_MASK 0x00FF -#define SDPCM_SHARED_ASSERT_BUILT 0x0100 -#define SDPCM_SHARED_ASSERT 0x0200 -#define SDPCM_SHARED_TRAP 0x0400 -#define SDPCM_SHARED_IN_BRPT 0x0800 -#define SDPCM_SHARED_SET_BRPT 0x1000 -#define SDPCM_SHARED_PENDING_BRPT 0x2000 - -typedef struct { - uint32 flags; - uint32 trap_addr; - uint32 assert_exp_addr; - uint32 assert_file_addr; - uint32 assert_line; - uint32 console_addr; /* Address of hndrte_cons_t */ - uint32 msgtrace_addr; - uint32 fwid; -} sdpcm_shared_t; - -extern sdpcm_shared_t sdpcm_shared; - -/* Function can be used to notify host of FW halt */ -extern void sdpcmd_fwhalt(void); - -#endif /* _bcmsdpcm_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h deleted file mode 100755 index 559a7c2bb630..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdspi.h 294363 2011-11-06 23:02:20Z $ - */ -#ifndef _BCM_SD_SPI_H -#define _BCM_SD_SPI_H - -/* global msglevel for debug messages - bitvals come from sdiovar.h */ - -#define sd_err(x) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) - -#define sd_log(x) - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_4318 64 -#define BLOCK_SIZE_4328 512 - -/* internal return code */ -#define SUCCESS 0 -#undef ERROR -#define ERROR 1 - -/* private bus modes */ -#define SDIOH_MODE_SPI 0 - -#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -#define USE_MULTIBLOCK 0x4 - -struct sdioh_info { - uint cfg_bar; /* pci cfg address for bar */ - uint32 caps; /* cached value of capabilities reg */ - uint bar0; /* BAR0 for PCI Device */ - osl_t *osh; /* osh handler */ - void *controller; /* Pointer to SPI Controller's private data struct */ - - uint lockcount; /* nest count of sdspi_lock() calls */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - bool initialized; /* card initialized */ - uint32 target_dev; /* Target device ID */ - uint32 intmask; /* Current active interrupts */ - void *sdos_info; /* Pointer to per-OS private data */ - - uint32 controller_type; /* Host controller type */ - uint8 version; /* Host Controller Spec Compliance Version */ - uint irq; /* Client irq */ - uint32 intrcount; /* Client interrupts */ - uint32 local_intrcount; /* Controller interrupts */ - bool host_init_done; /* Controller initted */ - bool card_init_done; /* Client SDIO interface initted */ - bool polled_mode; /* polling for command completion */ - - bool sd_use_dma; /* DMA on CMD53 */ - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - bool got_hcint; /* Host Controller interrupt. */ - /* polling hack in wl_linux.c:wl_timer() */ - int adapter_slot; /* Maybe dealing with multiple slots/controllers */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ - uint32 data_xfer_count; /* Current register transfer size */ - uint32 cmd53_wr_data; /* Used to pass CMD53 write data */ - uint32 card_response; /* Used to pass back response status byte */ - uint32 card_rsp_data; /* Used to pass back response data word */ - uint16 card_rca; /* Current Address */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - void *dma_buf; - ulong dma_phys; - int r_cnt; /* rx count */ - int t_cnt; /* tx_count */ -}; - -/************************************************************ - * Internal interfaces: per-port references into bcmsdspi.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/************************************************************** - * Internal interfaces: bcmsdspi.c references to per-port code - */ - -/* Register mapping routines */ -extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); -extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); - -/* Interrupt (de)registration routines */ -extern int spi_register_irq(sdioh_info_t *sd, uint irq); -extern void spi_free_irq(uint irq, sdioh_info_t *sd); - -/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -extern void spi_lock(sdioh_info_t *sd); -extern void spi_unlock(sdioh_info_t *sd); - -/* Allocate/init/free per-OS private data */ -extern int spi_osinit(sdioh_info_t *sd); -extern void spi_osfree(sdioh_info_t *sd); - -#endif /* _BCM_SD_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h deleted file mode 100755 index 318a6a8fc85d..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * 'Standard' SDIO HOST CONTROLLER driver - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsdstd.h 528504 2015-01-22 11:15:31Z $ - */ -#ifndef _BCM_SD_STD_H -#define _BCM_SD_STD_H - -/* global msglevel for debug messages - bitvals come from sdiovar.h */ -#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) -#define sd_dma(x) - -#define sd_sync_dma(sd, read, nbytes) -#define sd_init_dma(sd) -#define sd_ack_intr(sd) -#define sd_wakeup(sd); -/* Allocate/init/free per-OS private data */ -extern int sdstd_osinit(sdioh_info_t *sd); -extern void sdstd_osfree(sdioh_info_t *sd); - -#define sd_log(x) - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_4318 64 -#define BLOCK_SIZE_4328 512 - -/* internal return code */ -#define SUCCESS 0 -#define ERROR 1 - -/* private bus modes */ -#define SDIOH_MODE_SPI 0 -#define SDIOH_MODE_SD1 1 -#define SDIOH_MODE_SD4 2 - -#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */ -#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */ - -#define SDIOH_TYPE_ARASAN_HDK 1 -#define SDIOH_TYPE_BCM27XX 2 -#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */ -#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */ -#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */ - -/* For linux, allow yielding for dongle */ -#define BCMSDYIELD - -/* Expected card status value for CMD7 */ -#define SDIOH_CMD7_EXP_STATUS 0x00001E00 - -#define RETRIES_LARGE 100000 -#define sdstd_os_yield(sd) do {} while (0) -#define RETRIES_SMALL 100 - - -#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -#define USE_MULTIBLOCK 0x4 - -#define USE_FIFO 0x8 /* Fifo vs non-fifo */ - -#define CLIENT_INTR 0x100 /* Get rid of this! */ - -#define HC_INTR_RETUNING 0x1000 - - -#ifdef BCMSDIOH_TXGLOM -/* Total glom pkt can not exceed 64K - * need one more slot for glom padding packet - */ -#define SDIOH_MAXGLOM_SIZE (40+1) - -typedef struct glom_buf { - uint32 count; /* Total number of pkts queued */ - void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */ - ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */ - uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */ -} glom_buf_t; -#endif - -struct sdioh_info { - uint cfg_bar; /* pci cfg address for bar */ - uint32 caps; /* cached value of capabilities reg */ - uint32 curr_caps; /* max current capabilities reg */ - - osl_t *osh; /* osh handler */ - volatile char *mem_space; /* pci device memory va */ - uint lockcount; /* nest count of sdstd_lock() calls */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - bool initialized; /* card initialized */ - uint target_dev; /* Target device ID */ - uint16 intmask; /* Current active interrupts */ - void *sdos_info; /* Pointer to per-OS private data */ - void *bcmsdh; /* handler to upper layer stack (bcmsdh) */ - - uint32 controller_type; /* Host controller type */ - uint8 version; /* Host Controller Spec Compliance Version */ - uint irq; /* Client irq */ - int intrcount; /* Client interrupts */ - int local_intrcount; /* Controller interrupts */ - bool host_init_done; /* Controller initted */ - bool card_init_done; /* Client SDIO interface initted */ - bool polled_mode; /* polling for command completion */ - - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - /* polling hack in wl_linux.c:wl_timer() */ - int adapter_slot; /* Maybe dealing with multiple slots/controllers */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ - uint32 data_xfer_count; /* Current transfer */ - uint16 card_rca; /* Current Address */ - int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - void *dma_buf; /* DMA Buffer virtual address */ - ulong dma_phys; /* DMA Buffer physical address */ - void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */ - ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */ - - /* adjustments needed to make the dma align properly */ - void *dma_start_buf; - ulong dma_start_phys; - uint alloced_dma_size; - void *adma2_dscr_start_buf; - ulong adma2_dscr_start_phys; - uint alloced_adma2_dscr_size; - - int r_cnt; /* rx count */ - int t_cnt; /* tx_count */ - bool got_hcint; /* local interrupt flag */ - uint16 last_intrstatus; /* to cache intrstatus */ - int host_UHSISupported; /* whether UHSI is supported for HC. */ - int card_UHSI_voltage_Supported; /* whether UHSI is supported for - * Card in terms of Voltage [1.8 or 3.3]. - */ - int global_UHSI_Supp; /* type of UHSI support in both host and card. - * HOST_SDR_UNSUPP: capabilities not supported/matched - * HOST_SDR_12_25: SDR12 and SDR25 supported - * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd - */ - volatile int sd3_dat_state; /* data transfer state used for retuning check */ - volatile int sd3_tun_state; /* tuning state used for retuning check */ - bool sd3_tuning_reqd; /* tuning requirement parameter */ - uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ -#ifdef BCMSDIOH_TXGLOM - glom_buf_t glom_info; /* pkt information used for glomming */ - uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ -#endif -}; - -#define DMA_MODE_NONE 0 -#define DMA_MODE_SDMA 1 -#define DMA_MODE_ADMA1 2 -#define DMA_MODE_ADMA2 3 -#define DMA_MODE_ADMA2_64 4 -#define DMA_MODE_AUTO -1 - -#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) - -/* States for Tuning and corr data */ -#define TUNING_IDLE 0 -#define TUNING_START 1 -#define TUNING_START_AFTER_DAT 2 -#define TUNING_ONGOING 3 - -#define DATA_TRANSFER_IDLE 0 -#define DATA_TRANSFER_ONGOING 1 - -#define CHECK_TUNING_PRE_DATA 1 -#define CHECK_TUNING_POST_DATA 2 - - -#ifdef DHD_DEBUG -#define SD_DHD_DISABLE_PERIODIC_TUNING 0x01 -#define SD_DHD_ENABLE_PERIODIC_TUNING 0x00 -#endif - - -/************************************************************ - * Internal interfaces: per-port references into bcmsdstd.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/* OS-independent interrupt handler */ -extern bool check_client_intr(sdioh_info_t *sd); - -/* Core interrupt enable/disable of device interrupts */ -extern void sdstd_devintr_on(sdioh_info_t *sd); -extern void sdstd_devintr_off(sdioh_info_t *sd); - -/* Enable/disable interrupts for local controller events */ -extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err); -extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err); - -/* Wait for specified interrupt and error bits to be set */ -extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err); - - -/************************************************************** - * Internal interfaces: bcmsdstd.c references to per-port code - */ - -/* Register mapping routines */ -extern uint32 *sdstd_reg_map(osl_t *osh, ulong addr, int size); -extern void sdstd_reg_unmap(osl_t *osh, ulong addr, int size); - -/* Interrupt (de)registration routines */ -extern int sdstd_register_irq(sdioh_info_t *sd, uint irq); -extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); - -/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -extern void sdstd_lock(sdioh_info_t *sd); -extern void sdstd_unlock(sdioh_info_t *sd); -extern void sdstd_waitlockfree(sdioh_info_t *sd); - -/* OS-specific wrappers for safe concurrent register access */ -extern void sdstd_os_lock_irqsave(sdioh_info_t *sd, ulong* flags); -extern void sdstd_os_unlock_irqrestore(sdioh_info_t *sd, ulong* flags); - -/* OS-specific wait-for-interrupt-or-status */ -extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits); - -/* used by bcmsdstd_linux [implemented in sdstd] */ -extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd); -extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); -extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); -extern void sdstd_3_check_and_do_tuning(sdioh_info_t *sd, int tuning_param); -extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); -extern int sdstd_3_get_tune_state(sdioh_info_t *sd); -extern int sdstd_3_get_data_state(sdioh_info_t *sd); -extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); -extern void sdstd_3_set_data_state(sdioh_info_t *sd, int state); -extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); -extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); -extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode); - -/* used by sdstd [implemented in bcmsdstd_linux/ndis] */ -extern void sdstd_3_start_tuning(sdioh_info_t *sd); -extern void sdstd_3_osinit_tuning(sdioh_info_t *sd); -extern void sdstd_3_osclean_tuning(sdioh_info_t *sd); - -extern void sdstd_enable_disable_periodic_timer(sdioh_info_t * sd, uint val); - -extern sdioh_info_t *sdioh_attach(osl_t *osh, void *bar0, uint irq); -extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); -#endif /* _BCM_SD_STD_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h deleted file mode 100755 index 0b4d7bdb6d6d..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Broadcom SPI Low-Level Hardware Driver API - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmspi.h 241182 2011-02-17 21:50:03Z $ - */ -#ifndef _BCM_SPI_H -#define _BCM_SPI_H - -extern void spi_devintr_off(sdioh_info_t *sd); -extern void spi_devintr_on(sdioh_info_t *sd); -extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); -extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); -extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); -extern bool spi_hw_attach(sdioh_info_t *sd); -extern bool spi_hw_detach(sdioh_info_t *sd); -extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); -extern void spi_spinbits(sdioh_info_t *sd); -extern void spi_waitbits(sdioh_info_t *sd, bool yield); - -#endif /* _BCM_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h deleted file mode 100755 index 833fd261705d..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmspibrcm.h 373331 2012-12-07 04:46:22Z $ - */ -#ifndef _BCM_SPI_BRCM_H -#define _BCM_SPI_BRCM_H - -#ifndef SPI_MAX_IOFUNCS -/* Maximum number of I/O funcs */ -#define SPI_MAX_IOFUNCS 4 -#endif -/* global msglevel for debug messages - bitvals come from sdiovar.h */ - -#if defined(DHD_DEBUG) -#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) -#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) -#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) -#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0) -#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) -#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0) -#else -#define sd_err(x) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) -#endif - -#define sd_log(x) - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_F1 64 -#define BLOCK_SIZE_F2 2048 -#define BLOCK_SIZE_F3 2048 - -/* internal return code */ -#define SUCCESS 0 -#undef ERROR -#define ERROR 1 -#define ERROR_UF 2 -#define ERROR_OF 3 - -/* private bus modes */ -#define SDIOH_MODE_SPI 0 - -#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -#define USE_MULTIBLOCK 0x4 - -struct sdioh_info { - uint cfg_bar; /* pci cfg address for bar */ - uint32 caps; /* cached value of capabilities reg */ - void *bar0; /* BAR0 for PCI Device */ - osl_t *osh; /* osh handler */ - void *controller; /* Pointer to SPI Controller's private data struct */ - uint lockcount; /* nest count of spi_lock() calls */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - bool initialized; /* card initialized */ - uint32 target_dev; /* Target device ID */ - uint32 intmask; /* Current active interrupts */ - void *sdos_info; /* Pointer to per-OS private data */ - uint32 controller_type; /* Host controller type */ - uint8 version; /* Host Controller Spec Compliance Version */ - uint irq; /* Client irq */ - uint32 intrcount; /* Client interrupts */ - uint32 local_intrcount; /* Controller interrupts */ - bool host_init_done; /* Controller initted */ - bool card_init_done; /* Client SDIO interface initted */ - bool polled_mode; /* polling for command completion */ - - bool sd_use_dma; /* DMA on CMD53 */ - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - /* polling hack in wl_linux.c:wl_timer() */ - int adapter_slot; /* Maybe dealing with multiple slots/controllers */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SPI_MAX_IOFUNCS]; /* Blocksize */ - uint32 data_xfer_count; /* Current transfer */ - uint16 card_rca; /* Current Address */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 card_dstatus; /* 32bit device status */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SPI_MAX_IOFUNCS]; - void *dma_buf; - ulong dma_phys; - int r_cnt; /* rx count */ - int t_cnt; /* tx_count */ - uint32 wordlen; /* host processor 16/32bits */ - uint32 prev_fun; - uint32 chip; - uint32 chiprev; - bool resp_delay_all; - bool dwordmode; - bool resp_delay_new; - - struct spierrstats_t spierrstats; -}; - -/************************************************************ - * Internal interfaces: per-port references into bcmspibrcm.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/************************************************************** - * Internal interfaces: bcmspibrcm.c references to per-port code - */ - -/* Interrupt (de)registration routines */ -extern int spi_register_irq(sdioh_info_t *sd, uint irq); -extern void spi_free_irq(uint irq, sdioh_info_t *sd); - -/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -extern void spi_lock(sdioh_info_t *sd); -extern void spi_unlock(sdioh_info_t *sd); - -/* Allocate/init/free per-OS private data */ -extern int spi_osinit(sdioh_info_t *sd); -extern void spi_osfree(sdioh_info_t *sd); - -#define SPI_RW_FLAG_M BITFIELD_MASK(1) /* Bit [31] - R/W Command Bit */ -#define SPI_RW_FLAG_S 31 -#define SPI_ACCESS_M BITFIELD_MASK(1) /* Bit [30] - Fixed/Incr Access */ -#define SPI_ACCESS_S 30 -#define SPI_FUNCTION_M BITFIELD_MASK(2) /* Bit [29:28] - Function Number */ -#define SPI_FUNCTION_S 28 -#define SPI_REG_ADDR_M BITFIELD_MASK(17) /* Bit [27:11] - Address */ -#define SPI_REG_ADDR_S 11 -#define SPI_LEN_M BITFIELD_MASK(11) /* Bit [10:0] - Packet length */ -#define SPI_LEN_S 0 - -#endif /* _BCM_SPI_BRCM_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h deleted file mode 100755 index 3e485d519581..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h +++ /dev/null @@ -1,633 +0,0 @@ -/* - * SROM format definition. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsrom_fmt.h 427005 2013-10-02 00:15:10Z $ - */ - -#ifndef _bcmsrom_fmt_h_ -#define _bcmsrom_fmt_h_ - -#define SROM_MAXREV 11 /* max revisiton supported by driver */ - -/* Maximum srom: 6 Kilobits == 768 bytes */ -#define SROM_MAX 768 -#define SROM_MAXW 384 -#define VARS_MAX 4096 - -/* PCI fields */ -#define PCI_F0DEVID 48 - - -#define SROM_WORDS 64 - -#define SROM3_SWRGN_OFF 28 /* s/w region offset in words */ - -#define SROM_SSID 2 -#define SROM_SVID 3 - -#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_ET0 39 -#define SROM_MACMID_ET0 40 -#define SROM_MACLO_ET0 41 -#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 SROM2_ENETPHY 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 accomodate - * MIMO features. It assumes up to two PCIE functions and 440 bytes - * of useable srom i.e. the useable 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_AA2G_MASK 0x00ff -#define SROM4_AA2G_SHIFT 0 -#define SROM4_AA5G_MASK 0xff00 -#define SROM4_AA5G_SHIFT 8 - -#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 - -/* Fields in the ITT_MAXP and 5GLH_MAXP words */ -#define B2G_MAXP_MASK 0xff -#define B2G_ITT_SHIFT 8 -#define B5G_MAXP_MASK 0xff -#define B5G_ITT_SHIFT 8 -#define B5GH_MAXP_MASK 0xff -#define B5GL_MAXP_SHIFT 8 - -/* 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_SIGN 64 - -#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 - -#define SROM8_EXTLNAGAIN 93 - -/* Temperature delta for PHY calibration */ -#define SROM8_PHYCAL_TEMPDELTA 94 - -/* Measured power 1 & 2, 0-13 bits at offset 95, MSB 2 bits are unused for now. */ -#define SROM8_MPWR_1_AND_2 95 - - -/* 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) - -#define SROM8_CRCREV 219 - -/* 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 -#define SROM8_RXGAINERR_2G 205 -#define SROM8_RXGAINERR_5GL 206 -#define SROM8_RXGAINERR_5GM 207 -#define SROM8_RXGAINERR_5GH 208 -#define SROM8_RXGAINERR_5GU 209 -#define SROM8_SUBBAND_PPR 210 -#define SROM8_PCIEINGRESS_WAR 211 -#define SROM9_SAR 212 - -#define SROM8_NOISELVL_2G 213 -#define SROM8_NOISELVL_5GL 214 -#define SROM8_NOISELVL_5GM 215 -#define SROM8_NOISELVL_5GH 216 -#define SROM8_NOISELVL_5GU 217 -#define SROM8_NOISECALOFFSET 218 - -#define SROM9_REV_CRC 219 - -#define SROM10_CCKPWROFFSET 218 -#define SROM10_SIGN 219 -#define SROM10_SWCTRLMAP_2G 220 -#define SROM10_CRCREV 229 - -#define SROM10_WORDS 230 -#define SROM10_SIGNATURE SROM4_SIGNATURE - - -/* SROM REV 11 */ -#define SROM11_BREV 65 - -#define SROM11_BFL0 66 -#define SROM11_BFL1 67 -#define SROM11_BFL2 68 -#define SROM11_BFL3 69 -#define SROM11_BFL4 70 -#define SROM11_BFL5 71 - -#define SROM11_MACHI 72 -#define SROM11_MACMID 73 -#define SROM11_MACLO 74 - -#define SROM11_CCODE 75 -#define SROM11_REGREV 76 - -#define SROM11_LEDBH10 77 -#define SROM11_LEDBH32 78 - -#define SROM11_LEDDC 79 - -#define SROM11_AA 80 - -#define SROM11_AGBG10 81 -#define SROM11_AGBG2A0 82 -#define SROM11_AGA21 83 - -#define SROM11_TXRXC 84 - -#define SROM11_FEM_CFG1 85 -#define SROM11_FEM_CFG2 86 - -/* Masks and offsets for FEM_CFG */ -#define SROM11_FEMCTRL_MASK 0xf800 -#define SROM11_FEMCTRL_SHIFT 11 -#define SROM11_PAPDCAP_MASK 0x0400 -#define SROM11_PAPDCAP_SHIFT 10 -#define SROM11_TWORANGETSSI_MASK 0x0200 -#define SROM11_TWORANGETSSI_SHIFT 9 -#define SROM11_PDGAIN_MASK 0x01f0 -#define SROM11_PDGAIN_SHIFT 4 -#define SROM11_EPAGAIN_MASK 0x000e -#define SROM11_EPAGAIN_SHIFT 1 -#define SROM11_TSSIPOSSLOPE_MASK 0x0001 -#define SROM11_TSSIPOSSLOPE_SHIFT 0 -#define SROM11_GAINCTRLSPH_MASK 0xf800 -#define SROM11_GAINCTRLSPH_SHIFT 11 - -#define SROM11_THERMAL 87 -#define SROM11_MPWR_RAWTS 88 -#define SROM11_TS_SLP_OPT_CORRX 89 -#define SROM11_XTAL_FREQ 90 -#define SROM11_5GB0_4080_W0_A1 91 -#define SROM11_PHYCAL_TEMPDELTA 92 -#define SROM11_MPWR_1_AND_2 93 -#define SROM11_5GB0_4080_W1_A1 94 -#define SROM11_TSSIFLOOR_2G 95 -#define SROM11_TSSIFLOOR_5GL 96 -#define SROM11_TSSIFLOOR_5GM 97 -#define SROM11_TSSIFLOOR_5GH 98 -#define SROM11_TSSIFLOOR_5GU 99 - -/* Masks and offsets for Terrmal parameters */ -#define SROM11_TEMPS_PERIOD_MASK 0xf0 -#define SROM11_TEMPS_PERIOD_SHIFT 4 -#define SROM11_TEMPS_HYSTERESIS_MASK 0x0f -#define SROM11_TEMPS_HYSTERESIS_SHIFT 0 -#define SROM11_TEMPCORRX_MASK 0xfc -#define SROM11_TEMPCORRX_SHIFT 2 -#define SROM11_TEMPSENSE_OPTION_MASK 0x3 -#define SROM11_TEMPSENSE_OPTION_SHIFT 0 - -#define SROM11_PDOFF_2G_40M_A0_MASK 0x000f -#define SROM11_PDOFF_2G_40M_A0_SHIFT 0 -#define SROM11_PDOFF_2G_40M_A1_MASK 0x00f0 -#define SROM11_PDOFF_2G_40M_A1_SHIFT 4 -#define SROM11_PDOFF_2G_40M_A2_MASK 0x0f00 -#define SROM11_PDOFF_2G_40M_A2_SHIFT 8 -#define SROM11_PDOFF_2G_40M_VALID_MASK 0x8000 -#define SROM11_PDOFF_2G_40M_VALID_SHIFT 15 - -#define SROM11_PDOFF_2G_40M 100 -#define SROM11_PDOFF_40M_A0 101 -#define SROM11_PDOFF_40M_A1 102 -#define SROM11_PDOFF_40M_A2 103 -#define SROM11_5GB0_4080_W2_A1 103 -#define SROM11_PDOFF_80M_A0 104 -#define SROM11_PDOFF_80M_A1 105 -#define SROM11_PDOFF_80M_A2 106 -#define SROM11_5GB1_4080_W0_A1 106 - -#define SROM11_SUBBAND5GVER 107 - -/* Per-path fields and offset */ -#define MAX_PATH_SROM_11 3 -#define SROM11_PATH0 108 -#define SROM11_PATH1 128 -#define SROM11_PATH2 148 - -#define SROM11_2G_MAXP 0 -#define SROM11_5GB1_4080_PA 0 -#define SROM11_2G_PA 1 -#define SROM11_5GB2_4080_PA 2 -#define SROM11_RXGAINS1 4 -#define SROM11_RXGAINS 5 -#define SROM11_5GB3_4080_PA 5 -#define SROM11_5GB1B0_MAXP 6 -#define SROM11_5GB3B2_MAXP 7 -#define SROM11_5GB0_PA 8 -#define SROM11_5GB1_PA 11 -#define SROM11_5GB2_PA 14 -#define SROM11_5GB3_PA 17 - -/* Masks and offsets for rxgains */ -#define SROM11_RXGAINS5GTRELNABYPA_MASK 0x8000 -#define SROM11_RXGAINS5GTRELNABYPA_SHIFT 15 -#define SROM11_RXGAINS5GTRISOA_MASK 0x7800 -#define SROM11_RXGAINS5GTRISOA_SHIFT 11 -#define SROM11_RXGAINS5GELNAGAINA_MASK 0x0700 -#define SROM11_RXGAINS5GELNAGAINA_SHIFT 8 -#define SROM11_RXGAINS2GTRELNABYPA_MASK 0x0080 -#define SROM11_RXGAINS2GTRELNABYPA_SHIFT 7 -#define SROM11_RXGAINS2GTRISOA_MASK 0x0078 -#define SROM11_RXGAINS2GTRISOA_SHIFT 3 -#define SROM11_RXGAINS2GELNAGAINA_MASK 0x0007 -#define SROM11_RXGAINS2GELNAGAINA_SHIFT 0 -#define SROM11_RXGAINS5GHTRELNABYPA_MASK 0x8000 -#define SROM11_RXGAINS5GHTRELNABYPA_SHIFT 15 -#define SROM11_RXGAINS5GHTRISOA_MASK 0x7800 -#define SROM11_RXGAINS5GHTRISOA_SHIFT 11 -#define SROM11_RXGAINS5GHELNAGAINA_MASK 0x0700 -#define SROM11_RXGAINS5GHELNAGAINA_SHIFT 8 -#define SROM11_RXGAINS5GMTRELNABYPA_MASK 0x0080 -#define SROM11_RXGAINS5GMTRELNABYPA_SHIFT 7 -#define SROM11_RXGAINS5GMTRISOA_MASK 0x0078 -#define SROM11_RXGAINS5GMTRISOA_SHIFT 3 -#define SROM11_RXGAINS5GMELNAGAINA_MASK 0x0007 -#define SROM11_RXGAINS5GMELNAGAINA_SHIFT 0 - -/* Power per rate */ -#define SROM11_CCKBW202GPO 168 -#define SROM11_CCKBW20UL2GPO 169 -#define SROM11_MCSBW202GPO 170 -#define SROM11_MCSBW202GPO_1 171 -#define SROM11_MCSBW402GPO 172 -#define SROM11_MCSBW402GPO_1 173 -#define SROM11_DOT11AGOFDMHRBW202GPO 174 -#define SROM11_OFDMLRBW202GPO 175 - -#define SROM11_MCSBW205GLPO 176 -#define SROM11_MCSBW205GLPO_1 177 -#define SROM11_MCSBW405GLPO 178 -#define SROM11_MCSBW405GLPO_1 179 -#define SROM11_MCSBW805GLPO 180 -#define SROM11_MCSBW805GLPO_1 181 -#define SROM11_RPCAL_2G 182 -#define SROM11_RPCAL_5GL 183 -#define SROM11_MCSBW205GMPO 184 -#define SROM11_MCSBW205GMPO_1 185 -#define SROM11_MCSBW405GMPO 186 -#define SROM11_MCSBW405GMPO_1 187 -#define SROM11_MCSBW805GMPO 188 -#define SROM11_MCSBW805GMPO_1 189 -#define SROM11_RPCAL_5GM 190 -#define SROM11_RPCAL_5GH 191 -#define SROM11_MCSBW205GHPO 192 -#define SROM11_MCSBW205GHPO_1 193 -#define SROM11_MCSBW405GHPO 194 -#define SROM11_MCSBW405GHPO_1 195 -#define SROM11_MCSBW805GHPO 196 -#define SROM11_MCSBW805GHPO_1 197 -#define SROM11_RPCAL_5GU 198 -#define SROM11_PDOFF_2G_CCK 199 -#define SROM11_MCSLR5GLPO 200 -#define SROM11_MCSLR5GMPO 201 -#define SROM11_MCSLR5GHPO 202 - -#define SROM11_SB20IN40HRPO 203 -#define SROM11_SB20IN80AND160HR5GLPO 204 -#define SROM11_SB40AND80HR5GLPO 205 -#define SROM11_SB20IN80AND160HR5GMPO 206 -#define SROM11_SB40AND80HR5GMPO 207 -#define SROM11_SB20IN80AND160HR5GHPO 208 -#define SROM11_SB40AND80HR5GHPO 209 -#define SROM11_SB20IN40LRPO 210 -#define SROM11_SB20IN80AND160LR5GLPO 211 -#define SROM11_SB40AND80LR5GLPO 212 -#define SROM11_TXIDXCAP2G 212 -#define SROM11_SB20IN80AND160LR5GMPO 213 -#define SROM11_SB40AND80LR5GMPO 214 -#define SROM11_TXIDXCAP5G 214 -#define SROM11_SB20IN80AND160LR5GHPO 215 -#define SROM11_SB40AND80LR5GHPO 216 - -#define SROM11_DOT11AGDUPHRPO 217 -#define SROM11_DOT11AGDUPLRPO 218 - -/* MISC */ -#define SROM11_PCIEINGRESS_WAR 220 -#define SROM11_SAR 221 - -#define SROM11_NOISELVL_2G 222 -#define SROM11_NOISELVL_5GL 223 -#define SROM11_NOISELVL_5GM 224 -#define SROM11_NOISELVL_5GH 225 -#define SROM11_NOISELVL_5GU 226 - -#define SROM11_RXGAINERR_2G 227 -#define SROM11_RXGAINERR_5GL 228 -#define SROM11_RXGAINERR_5GM 229 -#define SROM11_RXGAINERR_5GH 230 -#define SROM11_RXGAINERR_5GU 231 - -#define SROM11_SIGN 64 -#define SROM11_CRCREV 233 - -#define SROM11_WORDS 234 -#define SROM11_SIGNATURE 0x0634 - -typedef struct { - uint8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */ - uint8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */ - uint8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */ - uint8 triso; /* TR switch isolation */ - uint8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */ -} srom_fem_t; - -#endif /* _bcmsrom_fmt_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h deleted file mode 100755 index be43a7c5ef18..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h +++ /dev/null @@ -1,1014 +0,0 @@ -/* - * Table that encodes the srom formats for PCI/PCIe NICs. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmsrom_tbl.h 427005 2013-10-02 00:15:10Z $ - */ - -#ifndef _bcmsrom_tbl_h_ -#define _bcmsrom_tbl_h_ - -#include "sbpcmcia.h" -#include "wlioctl.h" - -typedef struct { - const char *name; - uint32 revmask; - uint32 flags; - uint16 off; - uint16 mask; -} sromvar_t; - -#define SRFL_MORE 1 /* value continues as described by the next entry */ -#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 */ -#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */ -#define SRFL_ARRAY 0x100 /* value is in an array. All elements EXCEPT FOR THE LAST - * ONE in the array should have this flag set. - */ - - -#define SROM_DEVID_PCIE 48 - -/* Assumptions: - * - Ethernet address spans across 3 consective 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 sromvar_t pci_sromvars[] = { -#if defined(CABLECPE) - {"devid", 0xffffff00, SRFL_PRHEX, PCI_F0DEVID, 0xffff}, -#elif defined(BCMPCIEDEV) && defined(BCMPCIEDEV_ENABLED) - {"devid", 0xffffff00, SRFL_PRHEX, SROM_DEVID_PCIE, 0xffff}, -#else - {"devid", 0xffffff00, SRFL_PRHEX|SRFL_NOVAR, PCI_F0DEVID, 0xffff}, -#endif - {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK}, - {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, - {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, - {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, - {"boardflags", 0x00000004, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, - {"", 0, 0, SROM_BFL2, 0xffff}, - {"boardflags", 0x00000008, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, - {"", 0, 0, SROM3_BFL2, 0xffff}, - {"boardflags", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL0, 0xffff}, - {"", 0, 0, SROM4_BFL1, 0xffff}, - {"boardflags", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL0, 0xffff}, - {"", 0, 0, SROM5_BFL1, 0xffff}, - {"boardflags", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL0, 0xffff}, - {"", 0, 0, SROM8_BFL1, 0xffff}, - {"boardflags2", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL2, 0xffff}, - {"", 0, 0, SROM4_BFL3, 0xffff}, - {"boardflags2", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL2, 0xffff}, - {"", 0, 0, SROM5_BFL3, 0xffff}, - {"boardflags2", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL2, 0xffff}, - {"", 0, 0, SROM8_BFL3, 0xffff}, - {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, - {"subvid", 0xfffffffc, SRFL_PRHEX, SROM_SVID, 0xffff}, - {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, - {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff}, - {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff}, - {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff}, - {"boardnum", 0x00000700, 0, SROM8_MACLO, 0xffff}, - {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, - {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, - {"regrev", 0x00000010, 0, SROM4_REGREV, 0x00ff}, - {"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff}, - {"regrev", 0x00000700, 0, SROM8_REGREV, 0x00ff}, - {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff}, - {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, - {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff}, - {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, - {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff}, - {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, - {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff}, - {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, - {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff}, - {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, - {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff}, - {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, - {"ledbh0", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, - {"ledbh1", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, - {"ledbh2", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, - {"ledbh3", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, - {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, - {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, - {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, - {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff}, - {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff}, - {"pa0b0", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, - {"pa0b1", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, - {"pa0b2", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, - {"pa0itssit", 0x00000700, 0, SROM8_W0_ITTMAXP, 0xff00}, - {"pa0maxpwr", 0x00000700, 0, SROM8_W0_ITTMAXP, 0x00ff}, - {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff}, - {"opo", 0x00000700, 0, SROM8_2G_OFDMPO, 0x00ff}, - {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, - {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff}, - {"aa2g", 0x00000700, 0, SROM8_AA, 0x00ff}, - {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, - {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, - {"aa5g", 0x00000700, 0, SROM8_AA, 0xff00}, - {"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff}, - {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00}, - {"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff}, - {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00}, - {"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff}, - {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00}, - {"ag0", 0x00000700, 0, SROM8_AG10, 0x00ff}, - {"ag1", 0x00000700, 0, SROM8_AG10, 0xff00}, - {"ag2", 0x00000700, 0, SROM8_AG32, 0x00ff}, - {"ag3", 0x00000700, 0, SROM8_AG32, 0xff00}, - {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, - {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, - {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, - {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, - {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, - {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, - {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, - {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, - {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, - {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00}, - {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, - {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, - {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff}, - {"pa1b0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, - {"pa1b1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, - {"pa1b2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, - {"pa1lob0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, - {"pa1lob1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, - {"pa1lob2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, - {"pa1hib0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, - {"pa1hib1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, - {"pa1hib2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, - {"pa1itssit", 0x00000700, 0, SROM8_W1_ITTMAXP, 0xff00}, - {"pa1maxpwr", 0x00000700, 0, SROM8_W1_ITTMAXP, 0x00ff}, - {"pa1lomaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0xff00}, - {"pa1himaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, - {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, - {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, - {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, - {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, - {"bxa2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x1800}, - {"rssisav2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x0700}, - {"rssismc2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x00f0}, - {"rssismf2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x000f}, - {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, - {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, - {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, - {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, - {"bxa5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x1800}, - {"rssisav5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x0700}, - {"rssismc5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x00f0}, - {"rssismf5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x000f}, - {"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff}, - {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00}, - {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff}, - {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00}, - {"tri2g", 0x00000700, 0, SROM8_TRI52G, 0x00ff}, - {"tri5g", 0x00000700, 0, SROM8_TRI52G, 0xff00}, - {"tri5gl", 0x00000700, 0, SROM8_TRI5GHL, 0x00ff}, - {"tri5gh", 0x00000700, 0, SROM8_TRI5GHL, 0xff00}, - {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, - {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, - {"rxpo2g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, - {"rxpo5g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, - {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK}, - {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK}, - {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK}, - {"txchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, - {"rxchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, - {"antswitch", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, - {"tssipos2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK}, - {"extpagain2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK}, - {"pdetrange2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK}, - {"triso2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, - {"antswctl2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK}, - {"tssipos5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK}, - {"extpagain5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK}, - {"pdetrange5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK}, - {"triso5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, - {"antswctl5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK}, - {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff}, - {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, - {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff}, - {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, - {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff}, - {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, - {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff}, - {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, - {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff}, - {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, - {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff}, - {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, - {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff}, - {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, - {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff}, - {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, - - {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, - {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, - {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, - {"ccode", 0x00000700, SRFL_CCODE, SROM8_CCODE, 0xffff}, - {"macaddr", 0x00000700, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, - {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, - {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, - {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, - {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff}, - {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff}, - {"leddc", 0x00000700, SRFL_NOFFS|SRFL_LEDDC, SROM8_LEDDC, 0xffff}, - {"leddc", 0x000000e0, SRFL_NOFFS|SRFL_LEDDC, SROM5_LEDDC, 0xffff}, - {"leddc", 0x00000010, SRFL_NOFFS|SRFL_LEDDC, SROM4_LEDDC, 0xffff}, - {"leddc", 0x00000008, SRFL_NOFFS|SRFL_LEDDC, SROM3_LEDDC, 0xffff}, - - {"tempthresh", 0x00000700, 0, SROM8_THERMAL, 0xff00}, - {"tempoffset", 0x00000700, 0, SROM8_THERMAL, 0x00ff}, - {"rawtempsense", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff}, - {"measpower", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00}, - {"tempsense_slope", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff}, - {"tempcorrx", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00}, - {"tempsense_option", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300}, - {"freqoffset_corr", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f}, - {"iqcal_swp_dis", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010}, - {"hw_iqcal_en", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020}, - {"elna2g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0x00ff}, - {"elna5g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0xff00}, - {"phycal_tempdelta", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff}, - {"temps_period", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x0f00}, - {"temps_hysteresis", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0xf000}, - {"measpower1", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x007f}, - {"measpower2", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x3f80}, - - {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, - {"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, - {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, - {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, - {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, - {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, - {"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, - {"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, - {"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, - {"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, - {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, - {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, - {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, - {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, - {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, - {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, - {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, - {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, - {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, - {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, - {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, - {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, - {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, - {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, - {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, - {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, - {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, - {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, - {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, - {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, - {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, - {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, - {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, - {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, - {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, - {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, - {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, - {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, - {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, - {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, - {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, - {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, - {"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, - {"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff}, - {"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff}, - {"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff}, - {"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff}, - {"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff}, - {"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff}, - {"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff}, - {"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, - {"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff}, - {"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff}, - {"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff}, - {"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff}, - {"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff}, - {"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff}, - {"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff}, - {"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, - {"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff}, - {"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff}, - {"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff}, - {"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff}, - {"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff}, - {"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff}, - {"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff}, - {"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, - {"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff}, - {"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff}, - {"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff}, - {"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff}, - {"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff}, - {"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff}, - {"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff}, - {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff}, - {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff}, - {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff}, - {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, - {"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff}, - {"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff}, - {"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff}, - {"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, - - /* power per rate from sromrev 9 */ - {"cckbw202gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20, 0xffff}, - {"cckbw20ul2gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, - {"legofdmbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, - {"legofdmbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, - {"legofdmbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, - {"legofdmbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, - {"mcsbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw402gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, - {"mcsbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw405glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, - {"mcsbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw405gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, - {"mcsbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw405ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, - {"mcs32po", 0x00000600, 0, SROM9_PO_MCS32, 0xffff}, - {"legofdm40duppo", 0x00000600, 0, SROM9_PO_LOFDM40DUP, 0xffff}, - {"pcieingress_war", 0x00000700, 0, SROM8_PCIEINGRESS_WAR, 0xf}, - {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f}, - {"rxgainerr2ga1", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x07c0}, - {"rxgainerr2ga2", 0x00000700, 0, SROM8_RXGAINERR_2G, 0xf800}, - {"rxgainerr5gla0", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x003f}, - {"rxgainerr5gla1", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x07c0}, - {"rxgainerr5gla2", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0xf800}, - {"rxgainerr5gma0", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x003f}, - {"rxgainerr5gma1", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x07c0}, - {"rxgainerr5gma2", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0xf800}, - {"rxgainerr5gha0", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x003f}, - {"rxgainerr5gha1", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x07c0}, - {"rxgainerr5gha2", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0xf800}, - {"rxgainerr5gua0", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x003f}, - {"rxgainerr5gua1", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x07c0}, - {"rxgainerr5gua2", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0xf800}, - {"sar2g", 0x00000600, 0, SROM9_SAR, 0x00ff}, - {"sar5g", 0x00000600, 0, SROM9_SAR, 0xff00}, - {"noiselvl2ga0", 0x00000700, 0, SROM8_NOISELVL_2G, 0x001f}, - {"noiselvl2ga1", 0x00000700, 0, SROM8_NOISELVL_2G, 0x03e0}, - {"noiselvl2ga2", 0x00000700, 0, SROM8_NOISELVL_2G, 0x7c00}, - {"noiselvl5gla0", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x001f}, - {"noiselvl5gla1", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x03e0}, - {"noiselvl5gla2", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x7c00}, - {"noiselvl5gma0", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x001f}, - {"noiselvl5gma1", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x03e0}, - {"noiselvl5gma2", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x7c00}, - {"noiselvl5gha0", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x001f}, - {"noiselvl5gha1", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x03e0}, - {"noiselvl5gha2", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x7c00}, - {"noiselvl5gua0", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x001f}, - {"noiselvl5gua1", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x03e0}, - {"noiselvl5gua2", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x7c00}, - {"noisecaloffset", 0x00000300, 0, SROM8_NOISECALOFFSET, 0x00ff}, - {"noisecaloffset5g", 0x00000300, 0, SROM8_NOISECALOFFSET, 0xff00}, - {"subband5gver", 0x00000700, 0, SROM8_SUBBAND_PPR, 0x7}, - - {"cckPwrOffset", 0x00000400, 0, SROM10_CCKPWROFFSET, 0xffff}, - /* swctrlmap_2g array, note that the last element doesn't have SRFL_ARRAY flag set */ - {"swctrlmap_2g", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 1, 0xffff}, - {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 2, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 3, 0xffff}, - {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 4, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 5, 0xffff}, - {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 6, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 7, 0xffff}, - {"", 0x00000400, SRFL_PRHEX, SROM10_SWCTRLMAP_2G + 8, 0xffff}, - - /* sromrev 11 */ - {"boardflags3", 0xfffff800, SRFL_PRHEX|SRFL_MORE, SROM11_BFL4, 0xffff}, - {"", 0, 0, SROM11_BFL5, 0xffff}, - {"boardnum", 0xfffff800, 0, SROM11_MACLO, 0xffff}, - {"macaddr", 0xfffff800, SRFL_ETHADDR, SROM11_MACHI, 0xffff}, - {"ccode", 0xfffff800, SRFL_CCODE, SROM11_CCODE, 0xffff}, - {"regrev", 0xfffff800, 0, SROM11_REGREV, 0x00ff}, - {"ledbh0", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0x00ff}, - {"ledbh1", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0xff00}, - {"ledbh2", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0x00ff}, - {"ledbh3", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0xff00}, - {"leddc", 0xfffff800, SRFL_NOFFS|SRFL_LEDDC, SROM11_LEDDC, 0xffff}, - {"aa2g", 0xfffff800, 0, SROM11_AA, 0x00ff}, - {"aa5g", 0xfffff800, 0, SROM11_AA, 0xff00}, - {"agbg0", 0xfffff800, 0, SROM11_AGBG10, 0xff00}, - {"agbg1", 0xfffff800, 0, SROM11_AGBG10, 0x00ff}, - {"agbg2", 0xfffff800, 0, SROM11_AGBG2A0, 0xff00}, - {"aga0", 0xfffff800, 0, SROM11_AGBG2A0, 0x00ff}, - {"aga1", 0xfffff800, 0, SROM11_AGA21, 0xff00}, - {"aga2", 0xfffff800, 0, SROM11_AGA21, 0x00ff}, - {"txchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_TXCHAIN_MASK}, - {"rxchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_RXCHAIN_MASK}, - {"antswitch", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_SWITCH_MASK}, - - {"tssiposslope2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0001}, - {"epagain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x000e}, - {"pdgain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x01f0}, - {"tworangetssi2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0200}, - {"papdcap2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0400}, - {"femctrl", 0xfffff800, 0, SROM11_FEM_CFG1, 0xf800}, - - {"tssiposslope5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0001}, - {"epagain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x000e}, - {"pdgain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x01f0}, - {"tworangetssi5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0200}, - {"papdcap5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0400}, - {"gainctrlsph", 0xfffff800, 0, SROM11_FEM_CFG2, 0xf800}, - - {"tempthresh", 0xfffff800, 0, SROM11_THERMAL, 0xff00}, - {"tempoffset", 0xfffff800, 0, SROM11_THERMAL, 0x00ff}, - {"rawtempsense", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0x01ff}, - {"measpower", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0xfe00}, - {"tempsense_slope", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x00ff}, - {"tempcorrx", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0xfc00}, - {"tempsense_option", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x0300}, - {"xtalfreq", 0xfffff800, 0, SROM11_XTAL_FREQ, 0xffff}, - /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #1 */ - {"pa5gbw4080a1", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W0_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W1_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W2_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_4080_W0_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_4080_PA + 2, 0xffff}, - {"phycal_tempdelta", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x00ff}, - {"temps_period", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x0f00}, - {"temps_hysteresis", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0xf000}, - {"measpower1", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x007f}, - {"measpower2", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x3f80}, - {"tssifloor2g", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_2G, 0x03ff}, - {"tssifloor5g", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GL, 0x03ff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GM, 0x03ff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GH, 0x03ff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_5GU, 0x03ff}, - {"pdoffset2g40ma0", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x000f}, - {"pdoffset2g40ma1", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x00f0}, - {"pdoffset2g40ma2", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x0f00}, - {"pdoffset2g40mvalid", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x8000}, - {"pdoffset40ma0", 0xfffff800, 0, SROM11_PDOFF_40M_A0, 0xffff}, - {"pdoffset40ma1", 0xfffff800, 0, SROM11_PDOFF_40M_A1, 0xffff}, - {"pdoffset40ma2", 0xfffff800, 0, SROM11_PDOFF_40M_A2, 0xffff}, - {"pdoffset80ma0", 0xfffff800, 0, SROM11_PDOFF_80M_A0, 0xffff}, - {"pdoffset80ma1", 0xfffff800, 0, SROM11_PDOFF_80M_A1, 0xffff}, - {"pdoffset80ma2", 0xfffff800, 0, SROM11_PDOFF_80M_A2, 0xffff}, - - {"subband5gver", 0xfffff800, SRFL_PRHEX, SROM11_SUBBAND5GVER, 0xffff}, - {"paparambwver", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0xf000}, - /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #0 */ - {"pa5gbw4080a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 +SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, - /* Special PA Params for 4335 5G Band, 40 MHz BW */ - {"pa5gbw40a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_5GB3_PA + 2, 0xffff}, - /* Special PA Params for 4335 5G Band, 80 MHz BW */ - {"pa5gbw80a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, - /* Special PA Params for 4335 2G Band, CCK */ - {"pa2gccka0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_2G_PA + 2, 0xffff}, - - /* power per rate */ - {"cckbw202gpo", 0xfffff800, 0, SROM11_CCKBW202GPO, 0xffff}, - {"cckbw20ul2gpo", 0xfffff800, 0, SROM11_CCKBW20UL2GPO, 0xffff}, - {"mcsbw202gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW202GPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW202GPO_1, 0xffff}, - {"mcsbw402gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW402GPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW402GPO_1, 0xffff}, - {"dot11agofdmhrbw202gpo", 0xfffff800, 0, SROM11_DOT11AGOFDMHRBW202GPO, 0xffff}, - {"ofdmlrbw202gpo", 0xfffff800, 0, SROM11_OFDMLRBW202GPO, 0xffff}, - {"mcsbw205glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GLPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW205GLPO_1, 0xffff}, - {"mcsbw405glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GLPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW405GLPO_1, 0xffff}, - {"mcsbw805glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GLPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW805GLPO_1, 0xffff}, - {"mcsbw205gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GMPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW205GMPO_1, 0xffff}, - {"mcsbw405gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GMPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW405GMPO_1, 0xffff}, - {"mcsbw805gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GMPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW805GMPO_1, 0xffff}, - {"mcsbw205ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GHPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW205GHPO_1, 0xffff}, - {"mcsbw405ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GHPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW405GHPO_1, 0xffff}, - {"mcsbw805ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GHPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW805GHPO_1, 0xffff}, - {"mcslr5glpo", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0x0fff}, - {"mcslr5gmpo", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0xffff}, - {"mcslr5ghpo", 0xfffff800, 0, SROM11_MCSLR5GHPO, 0xffff}, - {"sb20in40hrpo", 0xfffff800, 0, SROM11_SB20IN40HRPO, 0xffff}, - {"sb20in80and160hr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GLPO, 0xffff}, - {"sb40and80hr5glpo", 0xfffff800, 0, SROM11_SB40AND80HR5GLPO, 0xffff}, - {"sb20in80and160hr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GMPO, 0xffff}, - {"sb40and80hr5gmpo", 0xfffff800, 0, SROM11_SB40AND80HR5GMPO, 0xffff}, - {"sb20in80and160hr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GHPO, 0xffff}, - {"sb40and80hr5ghpo", 0xfffff800, 0, SROM11_SB40AND80HR5GHPO, 0xffff}, - {"sb20in40lrpo", 0xfffff800, 0, SROM11_SB20IN40LRPO, 0xffff}, - {"sb20in80and160lr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GLPO, 0xffff}, - {"sb40and80lr5glpo", 0xfffff800, 0, SROM11_SB40AND80LR5GLPO, 0xffff}, - {"sb20in80and160lr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GMPO, 0xffff}, - {"sb40and80lr5gmpo", 0xfffff800, 0, SROM11_SB40AND80LR5GMPO, 0xffff}, - {"sb20in80and160lr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GHPO, 0xffff}, - {"sb40and80lr5ghpo", 0xfffff800, 0, SROM11_SB40AND80LR5GHPO, 0xffff}, - {"dot11agduphrpo", 0xfffff800, 0, SROM11_DOT11AGDUPHRPO, 0xffff}, - {"dot11agduplrpo", 0xfffff800, 0, SROM11_DOT11AGDUPLRPO, 0xffff}, - - /* Misc */ - {"sar2g", 0xfffff800, 0, SROM11_SAR, 0x00ff}, - {"sar5g", 0xfffff800, 0, SROM11_SAR, 0xff00}, - - {"noiselvl2ga0", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x001f}, - {"noiselvl2ga1", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x03e0}, - {"noiselvl2ga2", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x7c00}, - {"noiselvl5ga0", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x001f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x001f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x001f}, - {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x001f}, - {"noiselvl5ga1", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x03e0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x03e0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x03e0}, - {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x03e0}, - {"noiselvl5ga2", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x7c00}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x7c00}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x7c00}, - {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x7c00}, - - {"rxgainerr2ga0", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x003f}, - {"rxgainerr2ga1", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x07c0}, - {"rxgainerr2ga2", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0xf800}, - {"rxgainerr5ga0", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x003f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x003f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x003f}, - {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x003f}, - {"rxgainerr5ga1", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x07c0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x07c0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x07c0}, - {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x07c0}, - {"rxgainerr5ga2", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0xf800}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0xf800}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0xf800}, - {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0xf800}, - {"rpcal2g", 0xfffff800, 0, SROM11_RPCAL_2G, 0xffff}, - {"rpcal5gb0", 0xfffff800, 0, SROM11_RPCAL_5GL, 0xffff}, - {"rpcal5gb1", 0xfffff800, 0, SROM11_RPCAL_5GM, 0xffff}, - {"rpcal5gb2", 0xfffff800, 0, SROM11_RPCAL_5GH, 0xffff}, - {"rpcal5gb3", 0xfffff800, 0, SROM11_RPCAL_5GU, 0xffff}, - {"txidxcap2g", 0xfffff800, 0, SROM11_TXIDXCAP2G, 0x0ff0}, - {"txidxcap5g", 0xfffff800, 0, SROM11_TXIDXCAP5G, 0x0ff0}, - {"pdoffsetcckma0", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x000f}, - {"pdoffsetcckma1", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x00f0}, - {"pdoffsetcckma2", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x0f00}, - {NULL, 0, 0, 0, 0} -}; - -static const sromvar_t perpath_pci_sromvars[] = { - {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff}, - {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, - {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, - {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, - {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, - {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, - {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, - {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff}, - {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff}, - {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, - {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, - {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, - {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, - {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, - {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, - {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff}, - {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff}, - {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff}, - {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, - {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff}, - {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff}, - {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff}, - {"maxp2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0x00ff}, - {"itt2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0xff00}, - {"itt5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0xff00}, - {"pa2gw0a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, - {"pa2gw1a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, - {"pa2gw2a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, - {"maxp5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0x00ff}, - {"maxp5gha", 0x00000700, 0, SROM8_5GLH_MAXP, 0x00ff}, - {"maxp5gla", 0x00000700, 0, SROM8_5GLH_MAXP, 0xff00}, - {"pa5gw0a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, - {"pa5gw1a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, - {"pa5gw2a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, - {"pa5glw0a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, - {"pa5glw1a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff}, - {"pa5glw2a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff}, - {"pa5ghw0a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, - {"pa5ghw1a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff}, - {"pa5ghw2a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff}, - - /* sromrev 11 */ - {"maxp2ga", 0xfffff800, 0, SROM11_2G_MAXP, 0x00ff}, - {"pa2ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_2G_PA + 2, 0xffff}, - {"rxgains5gmelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0007}, - {"rxgains5gmtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0078}, - {"rxgains5gmtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0080}, - {"rxgains5ghelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0700}, - {"rxgains5ghtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x7800}, - {"rxgains5ghtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x8000}, - {"rxgains2gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0007}, - {"rxgains2gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x0078}, - {"rxgains2gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x0080}, - {"rxgains5gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0700}, - {"rxgains5gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x7800}, - {"rxgains5gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x8000}, - {"maxp5ga", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0x00ff}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0xff00}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB3B2_MAXP, 0x00ff}, - {"", 0xfffff800, 0, SROM11_5GB3B2_MAXP, 0xff00}, - {"pa5ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_5GB3_PA + 2, 0xffff}, - - {NULL, 0, 0, 0, 0} -}; - -#if !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) -#define PHY_TYPE_HT 7 /* HT-Phy value */ -#define PHY_TYPE_N 4 /* N-Phy value */ -#define PHY_TYPE_LP 5 /* LP-Phy value */ -#endif /* !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) */ -#if !defined(PHY_TYPE_AC) -#define PHY_TYPE_AC 11 /* AC-Phy value */ -#endif /* !defined(PHY_TYPE_AC) */ -#if !defined(PHY_TYPE_NULL) -#define PHY_TYPE_NULL 0xf /* Invalid Phy value */ -#endif /* !defined(PHY_TYPE_NULL) */ - -typedef struct { - uint16 phy_type; - uint16 bandrange; - uint16 chain; - const char *vars; -} pavars_t; - -static const pavars_t pavars[] = { - /* HTPHY */ - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 2, "pa2gw0a2 pa2gw1a2 pa2gw2a2"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 2, "pa5glw0a2 pa5glw1a2 pa5glw2a2"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 2, "pa5gw0a2 pa5gw1a2 pa5gw2a2"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 2, "pa5ghw0a2 pa5ghw1a2 pa5ghw2a2"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 0, "pa5gw0a3 pa5gw1a3 pa5gw2a3"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 1, "pa5glw0a3 pa5glw1a3 pa5glw2a3"}, - {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 2, "pa5ghw0a3 pa5ghw1a3 pa5ghw2a3"}, - /* NPHY */ - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, - /* LPPHY */ - {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_2G, 0, "pa0b0 pa0b1 pa0b2"}, - {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GL, 0, "pa1lob0 pa1lob1 pa1lob2"}, - {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GM, 0, "pa1b0 pa1b1 pa1b2"}, - {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GH, 0, "pa1hib0 pa1hib1 pa1hib2"}, - /* ACPHY */ - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5ga2"}, - {PHY_TYPE_NULL, 0, 0, ""} -}; - -/* pavars table when paparambwver is 1 */ -static const pavars_t pavars_bwver_1[] = { - /* ACPHY */ - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gccka0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga2"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5gbw40a0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw80a0"}, - {PHY_TYPE_NULL, 0, 0, ""} -}; - -/* pavars table when paparambwver is 2 */ -static const pavars_t pavars_bwver_2[] = { - /* ACPHY */ - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw4080a0"}, - {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 3, "pa5gbw4080a1"}, - {PHY_TYPE_NULL, 0, 0, ""} -}; - -typedef struct { - uint16 phy_type; - uint16 bandrange; - const char *vars; -} povars_t; - -static const povars_t povars[] = { - /* NPHY */ - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, "mcs2gpo0 mcs2gpo1 mcs2gpo2 mcs2gpo3 " - "mcs2gpo4 mcs2gpo5 mcs2gpo6 mcs2gpo7"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, "mcs5glpo0 mcs5glpo1 mcs5glpo2 mcs5glpo3 " - "mcs5glpo4 mcs5glpo5 mcs5glpo6 mcs5glpo7"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, "mcs5gpo0 mcs5gpo1 mcs5gpo2 mcs5gpo3 " - "mcs5gpo4 mcs5gpo5 mcs5gpo6 mcs5gpo7"}, - {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, "mcs5ghpo0 mcs5ghpo1 mcs5ghpo2 mcs5ghpo3 " - "mcs5ghpo4 mcs5ghpo5 mcs5ghpo6 mcs5ghpo7"}, - {PHY_TYPE_NULL, 0, ""} -}; - -typedef struct { - uint8 tag; /* Broadcom subtag name */ - uint32 revmask; /* Supported cis_sromrev */ - uint8 len; /* Length field of the tuple, note that it includes the - * subtag name (1 byte): 1 + tuple content length - */ - const char *params; -} cis_tuple_t; - -#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */ -#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */ -#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */ -#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */ - -static const cis_tuple_t cis_hnbuvars[] = { - {OTP_RAW1, 0xffffffff, 0, ""}, /* special case */ - {OTP_VERS_1, 0xffffffff, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */ - {OTP_MANFID, 0xffffffff, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */ - /* Unified OTP: tupple to embed USB manfid inside SDIO CIS */ - {HNBU_UMANFID, 0xffffffff, 8, "8usbmanfid"}, - {HNBU_SROMREV, 0xffffffff, 2, "1sromrev"}, - /* NOTE: subdevid is also written to boardtype. - * Need to write HNBU_BOARDTYPE to change it if it is different. - */ - {HNBU_CHIPID, 0xffffffff, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"}, - {HNBU_BOARDREV, 0xffffffff, 3, "2boardrev"}, - {HNBU_PAPARMS, 0xffffffff, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"}, - {HNBU_AA, 0xffffffff, 3, "1aa2g 1aa5g"}, - {HNBU_AA, 0xffffffff, 3, "1aa0 1aa1"}, /* backward compatibility */ - {HNBU_AG, 0xffffffff, 5, "1ag0 1ag1 1ag2 1ag3"}, - {HNBU_BOARDFLAGS, 0xffffffff, 13, "4boardflags 4boardflags2 4boardflags3"}, - {HNBU_LEDS, 0xffffffff, 17, "1ledbh0 1ledbh1 1ledbh2 1ledbh3 1ledbh4 1ledbh5 " - "1ledbh6 1ledbh7 1ledbh8 1ledbh9 1ledbh10 1ledbh11 1ledbh12 1ledbh13 1ledbh14 1ledbh15"}, - {HNBU_CCODE, 0xffffffff, 4, "2ccode 1cctl"}, - {HNBU_CCKPO, 0xffffffff, 3, "2cckpo"}, - {HNBU_OFDMPO, 0xffffffff, 5, "4ofdmpo"}, - {HNBU_PAPARMS5G, 0xffffffff, 23, "2pa1b0 2pa1b1 2pa1b2 2pa1lob0 2pa1lob1 2pa1lob2 " - "2pa1hib0 2pa1hib1 2pa1hib2 1pa1itssit " - "1pa1maxpwr 1pa1lomaxpwr 1pa1himaxpwr"}, - {HNBU_RDLID, 0xffffffff, 3, "2rdlid"}, - {HNBU_RSSISMBXA2G, 0xffffffff, 3, "0rssismf2g 0rssismc2g " - "0rssisav2g 0bxa2g"}, /* special case */ - {HNBU_RSSISMBXA5G, 0xffffffff, 3, "0rssismf5g 0rssismc5g " - "0rssisav5g 0bxa5g"}, /* special case */ - {HNBU_XTALFREQ, 0xffffffff, 5, "4xtalfreq"}, - {HNBU_TRI2G, 0xffffffff, 2, "1tri2g"}, - {HNBU_TRI5G, 0xffffffff, 4, "1tri5gl 1tri5g 1tri5gh"}, - {HNBU_RXPO2G, 0xffffffff, 2, "1rxpo2g"}, - {HNBU_RXPO5G, 0xffffffff, 2, "1rxpo5g"}, - {HNBU_BOARDNUM, 0xffffffff, 3, "2boardnum"}, - {HNBU_MACADDR, 0xffffffff, 7, "6macaddr"}, /* special case */ - {HNBU_RDLSN, 0xffffffff, 3, "2rdlsn"}, - {HNBU_BOARDTYPE, 0xffffffff, 3, "2boardtype"}, - {HNBU_LEDDC, 0xffffffff, 3, "2leddc"}, - {HNBU_RDLRNDIS, 0xffffffff, 2, "1rdlndis"}, - {HNBU_CHAINSWITCH, 0xffffffff, 5, "1txchain 1rxchain 2antswitch"}, - {HNBU_REGREV, 0xffffffff, 2, "1regrev"}, - {HNBU_FEM, 0x000007fe, 5, "0antswctl2g 0triso2g 0pdetrange2g 0extpagain2g " - "0tssipos2g 0antswctl5g 0triso5g 0pdetrange5g 0extpagain5g 0tssipos5g"}, /* special case */ - {HNBU_PAPARMS_C0, 0x000007fe, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 " - "2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 2pa5gw1a0 2pa5gw2a0 " - "2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 2pa5ghw1a0 2pa5ghw2a0"}, - {HNBU_PAPARMS_C1, 0x000007fe, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 " - "2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 2pa5gw1a1 2pa5gw2a1 " - "2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 2pa5ghw1a1 2pa5ghw2a1"}, - {HNBU_PO_CCKOFDM, 0xffffffff, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo " - "4ofdm5ghpo"}, - {HNBU_PO_MCS2G, 0xffffffff, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 " - "2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"}, - {HNBU_PO_MCS5GM, 0xffffffff, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 " - "2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"}, - {HNBU_PO_MCS5GLH, 0xffffffff, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 " - "2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 " - "2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 " - "2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"}, - {HNBU_CCKFILTTYPE, 0xffffffff, 2, "1cckdigfilttype"}, - {HNBU_PO_CDD, 0xffffffff, 3, "2cddpo"}, - {HNBU_PO_STBC, 0xffffffff, 3, "2stbcpo"}, - {HNBU_PO_40M, 0xffffffff, 3, "2bw40po"}, - {HNBU_PO_40MDUP, 0xffffffff, 3, "2bwduppo"}, - {HNBU_RDLRWU, 0xffffffff, 2, "1rdlrwu"}, - {HNBU_WPS, 0xffffffff, 3, "1wpsgpio 1wpsled"}, - {HNBU_USBFS, 0xffffffff, 2, "1usbfs"}, - {HNBU_ELNA2G, 0xffffffff, 2, "1elna2g"}, - {HNBU_ELNA5G, 0xffffffff, 2, "1elna5g"}, - {HNBU_CUSTOM1, 0xffffffff, 5, "4customvar1"}, - {OTP_RAW, 0xffffffff, 0, ""}, /* special case */ - {HNBU_OFDMPO5G, 0xffffffff, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"}, - {HNBU_USBEPNUM, 0xffffffff, 3, "2usbepnum"}, - {HNBU_CCKBW202GPO, 0xffffffff, 5, "2cckbw202gpo 2cckbw20ul2gpo"}, - {HNBU_LEGOFDMBW202GPO, 0xffffffff, 9, "4legofdmbw202gpo 4legofdmbw20ul2gpo"}, - {HNBU_LEGOFDMBW205GPO, 0xffffffff, 25, "4legofdmbw205glpo 4legofdmbw20ul5glpo " - "4legofdmbw205gmpo 4legofdmbw20ul5gmpo 4legofdmbw205ghpo 4legofdmbw20ul5ghpo"}, - {HNBU_MCS2GPO, 0xffffffff, 13, "4mcsbw202gpo 4mcsbw20ul2gpo 4mcsbw402gpo"}, - {HNBU_MCS5GLPO, 0xffffffff, 13, "4mcsbw205glpo 4mcsbw20ul5glpo 4mcsbw405glpo"}, - {HNBU_MCS5GMPO, 0xffffffff, 13, "4mcsbw205gmpo 4mcsbw20ul5gmpo 4mcsbw405gmpo"}, - {HNBU_MCS5GHPO, 0xffffffff, 13, "4mcsbw205ghpo 4mcsbw20ul5ghpo 4mcsbw405ghpo"}, - {HNBU_MCS32PO, 0xffffffff, 3, "2mcs32po"}, - {HNBU_LEG40DUPPO, 0xffffffff, 3, "2legofdm40duppo"}, - {HNBU_TEMPTHRESH, 0xffffffff, 7, "1tempthresh 0temps_period 0temps_hysteresis " - "1tempoffset 1tempsense_slope 0tempcorrx 0tempsense_option " - "1phycal_tempdelta"}, /* special case */ - {HNBU_MUXENAB, 0xffffffff, 2, "1muxenab"}, - {HNBU_FEM_CFG, 0xfffff800, 5, "0femctrl 0papdcap2g 0tworangetssi2g 0pdgain2g " - "0epagain2g 0tssiposslope2g 0gainctrlsph 0papdcap5g 0tworangetssi5g 0pdgain5g 0epagain5g " - "0tssiposslope5g"}, /* special case */ - {HNBU_ACPA_C0, 0xfffff800, 39, "2subband5gver 2maxp2ga0 2*3pa2ga0 " - "1*4maxp5ga0 2*12pa5ga0"}, - {HNBU_ACPA_C1, 0xfffff800, 37, "2maxp2ga1 2*3pa2ga1 1*4maxp5ga1 2*12pa5ga1"}, - {HNBU_ACPA_C2, 0xfffff800, 37, "2maxp2ga2 2*3pa2ga2 1*4maxp5ga2 2*12pa5ga2"}, - {HNBU_MEAS_PWR, 0xfffff800, 5, "1measpower 1measpower1 1measpower2 2rawtempsense"}, - {HNBU_PDOFF, 0xfffff800, 13, "2pdoffset40ma0 2pdoffset40ma1 2pdoffset40ma2 " - "2pdoffset80ma0 2pdoffset80ma1 2pdoffset80ma2"}, - {HNBU_ACPPR_2GPO, 0xfffff800, 5, "2dot11agofdmhrbw202gpo 2ofdmlrbw202gpo"}, - {HNBU_ACPPR_5GPO, 0xfffff800, 31, "4mcsbw805glpo 4mcsbw1605glpo 4mcsbw805gmpo " - "4mcsbw1605gmpo 4mcsbw805ghpo 4mcsbw1605ghpo 2mcslr5glpo 2mcslr5gmpo 2mcslr5ghpo"}, - {HNBU_ACPPR_SBPO, 0xfffff800, 33, "2sb20in40hrpo 2sb20in80and160hr5glpo " - "2sb40and80hr5glpo 2sb20in80and160hr5gmpo 2sb40and80hr5gmpo 2sb20in80and160hr5ghpo " - "2sb40and80hr5ghpo 2sb20in40lrpo 2sb20in80and160lr5glpo 2sb40and80lr5glpo " - "2sb20in80and160lr5gmpo 2sb40and80lr5gmpo 2sb20in80and160lr5ghpo 2sb40and80lr5ghpo " - "2dot11agduphrpo 2dot11agduplrpo"}, - {HNBU_NOISELVL, 0xfffff800, 16, "1noiselvl2ga0 1noiselvl2ga1 1noiselvl2ga2 " - "1*4noiselvl5ga0 1*4noiselvl5ga1 1*4noiselvl5ga2"}, - {HNBU_RXGAIN_ERR, 0xfffff800, 16, "1rxgainerr2ga0 1rxgainerr2ga1 1rxgainerr2ga2 " - "1*4rxgainerr5ga0 1*4rxgainerr5ga1 1*4rxgainerr5ga2"}, - {HNBU_AGBGA, 0xfffff800, 7, "1agbg0 1agbg1 1agbg2 1aga0 1aga1 1aga2"}, - {HNBU_UUID, 0xffffffff, 17, "16uuid"}, - {HNBU_WOWLGPIO, 0xffffffff, 2, "1wowl_gpio"}, - {HNBU_ACRXGAINS_C0, 0xfffff800, 5, "0rxgains5gtrelnabypa0 0rxgains5gtrisoa0 " - "0rxgains5gelnagaina0 0rxgains2gtrelnabypa0 0rxgains2gtrisoa0 0rxgains2gelnagaina0 " - "0rxgains5ghtrelnabypa0 0rxgains5ghtrisoa0 0rxgains5ghelnagaina0 0rxgains5gmtrelnabypa0 " - "0rxgains5gmtrisoa0 0rxgains5gmelnagaina0"}, /* special case */ - {HNBU_ACRXGAINS_C1, 0xfffff800, 5, "0rxgains5gtrelnabypa1 0rxgains5gtrisoa1 " - "0rxgains5gelnagaina1 0rxgains2gtrelnabypa1 0rxgains2gtrisoa1 0rxgains2gelnagaina1 " - "0rxgains5ghtrelnabypa1 0rxgains5ghtrisoa1 0rxgains5ghelnagaina1 0rxgains5gmtrelnabypa1 " - "0rxgains5gmtrisoa1 0rxgains5gmelnagaina1"}, /* special case */ - {HNBU_ACRXGAINS_C2, 0xfffff800, 5, "0rxgains5gtrelnabypa2 0rxgains5gtrisoa2 " - "0rxgains5gelnagaina2 0rxgains2gtrelnabypa2 0rxgains2gtrisoa2 0rxgains2gelnagaina2 " - "0rxgains5ghtrelnabypa2 0rxgains5ghtrisoa2 0rxgains5ghelnagaina2 0rxgains5gmtrelnabypa2 " - "0rxgains5gmtrisoa2 0rxgains5gmelnagaina2"}, /* special case */ - {HNBU_TXDUTY, 0xfffff800, 9, "2tx_duty_cycle_ofdm_40_5g " - "2tx_duty_cycle_thresh_40_5g 2tx_duty_cycle_ofdm_80_5g 2tx_duty_cycle_thresh_80_5g"}, - {HNBU_PDOFF_2G, 0xfffff800, 3, "0pdoffset2g40ma0 0pdoffset2g40ma1 " - "0pdoffset2g40ma2 0pdoffset2g40mvalid"}, - {HNBU_ACPA_CCK, 0xfffff800, 7, "2*3pa2gccka0"}, - {HNBU_ACPA_40, 0xfffff800, 25, "2*12pa5gbw40a0"}, - {HNBU_ACPA_80, 0xfffff800, 25, "2*12pa5gbw80a0"}, - {HNBU_ACPA_4080, 0xfffff800, 49, "2*12pa5gbw4080a0 2*12pa5gbw4080a1"}, - {HNBU_SUBBAND5GVER, 0xfffff800, 3, "2subband5gver"}, - {HNBU_PAPARAMBWVER, 0xfffff800, 2, "1paparambwver"}, - {0xFF, 0xffffffff, 0, ""} -}; - -#endif /* _bcmsrom_tbl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h b/drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h deleted file mode 100755 index 1103739f30f2..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h +++ /dev/null @@ -1,1238 +0,0 @@ -/* - * Misc useful os-independent macros and functions. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmutils.h 596861 2015-11-03 08:54:58Z $ - */ - -#ifndef _bcmutils_h_ -#define _bcmutils_h_ - -#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) -#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) -#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef PKTQ_LOG -#include -#endif - -/* ctype replacement */ -#define _BCM_U 0x01 /* upper */ -#define _BCM_L 0x02 /* lower */ -#define _BCM_D 0x04 /* digit */ -#define _BCM_C 0x08 /* cntrl */ -#define _BCM_P 0x10 /* punct */ -#define _BCM_S 0x20 /* white space (space/lf/tab) */ -#define _BCM_X 0x40 /* hex digit */ -#define _BCM_SP 0x80 /* hard space (0x20) */ - -extern const unsigned char bcm_ctype[]; -#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) - -#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) -#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) -#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) -#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) -#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) -#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) -#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) -#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) -#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) -#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) -#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) -#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) -#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) - -/* Buffer structure for collecting string-formatted data -* using bcm_bprintf() API. -* Use bcm_binit() to initialize before use -*/ - -struct bcmstrbuf { - char *buf; /* pointer to current position in origbuf */ - unsigned int size; /* current (residual) size in bytes */ - char *origbuf; /* unmodified pointer to orignal buffer */ - unsigned int origsize; /* unmodified orignal buffer size in bytes */ -}; - -/* ** driver-only section ** */ -#ifdef BCMDRIVER -#include - -#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */ - -/* - * 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. - */ -#ifndef SPINWAIT_POLL_PERIOD -#define SPINWAIT_POLL_PERIOD 10 -#endif - -#define SPINWAIT(exp, us) { \ - uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1); \ - while ((exp) && (countdown >= SPINWAIT_POLL_PERIOD)) { \ - OSL_DELAY(SPINWAIT_POLL_PERIOD); \ - countdown -= SPINWAIT_POLL_PERIOD; \ - } \ -} - -/* osl multi-precedence packet queue */ -#define PKTQ_LEN_MAX 0xFFFF /* Max uint16 65535 packets */ -#ifndef PKTQ_LEN_DEFAULT -#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ -#endif -#ifndef PKTQ_MAX_PREC -#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ -#endif - -typedef struct pktq_prec { - void *head; /* first packet to dequeue */ - void *tail; /* last packet to dequeue */ - uint16 len; /* number of queued packets */ - uint16 max; /* maximum number of queued packets */ -} pktq_prec_t; - -#ifdef PKTQ_LOG -typedef struct { - uint32 requested; /* packets requested to be stored */ - uint32 stored; /* packets stored */ - uint32 saved; /* packets saved, - because a lowest priority queue has given away one packet - */ - uint32 selfsaved; /* packets saved, - because an older packet from the same queue has been dropped - */ - uint32 full_dropped; /* packets dropped, - because pktq is full with higher precedence packets - */ - uint32 dropped; /* packets dropped because pktq per that precedence is full */ - uint32 sacrificed; /* packets dropped, - in order to save one from a queue of a highest priority - */ - uint32 busy; /* packets droped because of hardware/transmission error */ - uint32 retry; /* packets re-sent because they were not received */ - uint32 ps_retry; /* packets retried again prior to moving power save mode */ - uint32 suppress; /* packets which were suppressed and not transmitted */ - uint32 retry_drop; /* packets finally dropped after retry limit */ - uint32 max_avail; /* the high-water mark of the queue capacity for packets - - goes to zero as queue fills - */ - uint32 max_used; /* the high-water mark of the queue utilisation for packets - - increases with use ('inverse' of max_avail) - */ - uint32 queue_capacity; /* the maximum capacity of the queue */ - uint32 rtsfail; /* count of rts attempts that failed to receive cts */ - uint32 acked; /* count of packets sent (acked) successfully */ - uint32 txrate_succ; /* running total of phy rate of packets sent successfully */ - uint32 txrate_main; /* running totoal of primary phy rate of all packets */ - uint32 throughput; /* actual data transferred successfully */ - uint32 airtime; /* cumulative total medium access delay in useconds */ - uint32 _logtime; /* timestamp of last counter clear */ -} pktq_counters_t; - -typedef struct { - uint32 _prec_log; - pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */ -} pktq_log_t; -#endif /* PKTQ_LOG */ - - -#define PKTQ_COMMON \ - uint16 num_prec; /* number of precedences in use */ \ - uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ \ - uint16 max; /* total max packets */ \ - uint16 len; /* total number of packets */ - -/* multi-priority pkt queue */ -struct pktq { - PKTQ_COMMON - /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ - struct pktq_prec q[PKTQ_MAX_PREC]; -#ifdef PKTQ_LOG - pktq_log_t* pktqlog; -#endif -}; - -/* simple, non-priority pkt queue */ -struct spktq { - PKTQ_COMMON - /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ - struct pktq_prec q[1]; -}; - -#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) - -/* fn(pkt, arg). return true if pkt belongs to if */ -typedef bool (*ifpkt_cb_t)(void*, int); - -#ifdef BCMPKTPOOL -#define POOL_ENAB(pool) ((pool) && (pool)->inited) -#define SHARED_POOL (pktpool_shared) -#else /* BCMPKTPOOL */ -#define POOL_ENAB(bus) 0 -#define SHARED_POOL ((struct pktpool *)NULL) -#endif /* BCMPKTPOOL */ - -#ifdef BCMFRAGPOOL -#define SHARED_FRAG_POOL (pktpool_shared_lfrag) -#endif -#define SHARED_RXFRAG_POOL (pktpool_shared_rxlfrag) - - -#ifndef PKTPOOL_LEN_MAX -#define PKTPOOL_LEN_MAX 40 -#endif /* PKTPOOL_LEN_MAX */ -#define PKTPOOL_CB_MAX 3 - -struct pktpool; -typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); -typedef struct { - pktpool_cb_t cb; - void *arg; -} pktpool_cbinfo_t; -/* call back fn extension to populate host address in pool pkt */ -typedef int (*pktpool_cb_extn_t)(struct pktpool *pool, void *arg, void* pkt); -typedef struct { - pktpool_cb_extn_t cb; - void *arg; -} pktpool_cbextn_info_t; - - -#ifdef BCMDBG_POOL -/* pkt pool debug states */ -#define POOL_IDLE 0 -#define POOL_RXFILL 1 -#define POOL_RXDH 2 -#define POOL_RXD11 3 -#define POOL_TXDH 4 -#define POOL_TXD11 5 -#define POOL_AMPDU 6 -#define POOL_TXENQ 7 - -typedef struct { - void *p; - uint32 cycles; - uint32 dur; -} pktpool_dbg_t; - -typedef struct { - uint8 txdh; /* tx to host */ - uint8 txd11; /* tx to d11 */ - uint8 enq; /* waiting in q */ - uint8 rxdh; /* rx from host */ - uint8 rxd11; /* rx from d11 */ - uint8 rxfill; /* dma_rxfill */ - uint8 idle; /* avail in pool */ -} pktpool_stats_t; -#endif /* BCMDBG_POOL */ - -typedef struct pktpool { - bool inited; /* pktpool_init was successful */ - uint8 type; /* type of lbuf: basic, frag, etc */ - uint8 id; /* pktpool ID: index in registry */ - bool istx; /* direction: transmit or receive data path */ - - void * freelist; /* free list: see PKTNEXTFREE(), PKTSETNEXTFREE() */ - uint16 avail; /* number of packets in pool's free list */ - uint16 len; /* number of packets managed by pool */ - uint16 maxlen; /* maximum size of pool <= PKTPOOL_LEN_MAX */ - uint16 plen; /* size of pkt buffer, excluding lbuf|lbuf_frag */ - - bool empty; - uint8 cbtoggle; - uint8 cbcnt; - uint8 ecbcnt; - bool emptycb_disable; - pktpool_cbinfo_t *availcb_excl; - pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; - pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; - pktpool_cbextn_info_t cbext; -#ifdef BCMDBG_POOL - uint8 dbg_cbcnt; - pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; - uint16 dbg_qlen; - pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; -#endif -} pktpool_t; - -extern pktpool_t *pktpool_shared; -#ifdef BCMFRAGPOOL -extern pktpool_t *pktpool_shared_lfrag; -#endif -extern pktpool_t *pktpool_shared_rxlfrag; - -/* Incarnate a pktpool registry. On success returns total_pools. */ -extern int pktpool_attach(osl_t *osh, uint32 total_pools); -extern int pktpool_dettach(osl_t *osh); /* Relinquish registry */ - -extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx, uint8 type); -extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); -extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); -extern void* pktpool_get(pktpool_t *pktp); -extern void pktpool_free(pktpool_t *pktp, void *p); -extern int pktpool_add(pktpool_t *pktp, void *p); -extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); -extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); -extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); -extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); -extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); -extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); -extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); -extern bool pktpool_emptycb_disabled(pktpool_t *pktp); -int pktpool_hostaddr_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg); -#define POOLPTR(pp) ((pktpool_t *)(pp)) -#define POOLID(pp) (POOLPTR(pp)->id) - -#define POOLSETID(pp, ppid) (POOLPTR(pp)->id = (ppid)) - -#define pktpool_len(pp) (POOLPTR(pp)->len) -#define pktpool_avail(pp) (POOLPTR(pp)->avail) -#define pktpool_plen(pp) (POOLPTR(pp)->plen) -#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) - - -/* - * ---------------------------------------------------------------------------- - * A pool ID is assigned with a pkt pool during pool initialization. This is - * done by maintaining a registry of all initialized pools, and the registry - * index at which the pool is registered is used as the pool's unique ID. - * ID 0 is reserved and is used to signify an invalid pool ID. - * All packets henceforth allocated from a pool will be tagged with the pool's - * unique ID. Packets allocated from the heap will use the reserved ID = 0. - * Packets with non-zero pool id signify that they were allocated from a pool. - * A maximum of 15 pools are supported, allowing a 4bit pool ID to be used - * in place of a 32bit pool pointer in each packet. - * ---------------------------------------------------------------------------- - */ -#define PKTPOOL_INVALID_ID (0) -#define PKTPOOL_MAXIMUM_ID (15) - -/* Registry of pktpool(s) */ -extern pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; - -/* Pool ID to/from Pool Pointer converters */ -#define PKTPOOL_ID2PTR(id) (pktpools_registry[id]) -#define PKTPOOL_PTR2ID(pp) (POOLID(pp)) - - -#ifdef BCMDBG_POOL -extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); -extern int pktpool_start_trigger(pktpool_t *pktp, void *p); -extern int pktpool_dbg_dump(pktpool_t *pktp); -extern int pktpool_dbg_notify(pktpool_t *pktp); -extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); -#endif /* BCMDBG_POOL */ - -/* forward definition of ether_addr structure used by some function prototypes */ - -struct ether_addr; - -extern int ether_isbcast(const void *ea); -extern int ether_isnulladdr(const void *ea); - -/* operations on a specific precedence in packet queue */ - -#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) -#define pktq_pmax(pq, prec) ((pq)->q[prec].max) -#define pktq_plen(pq, prec) ((pq)->q[prec].len) -#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) -#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) -#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) - -#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) -#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) - -extern void *pktq_penq(struct pktq *pq, int prec, void *p); -extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); -extern void *pktq_pdeq(struct pktq *pq, int prec); -extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); -extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg); -extern void *pktq_pdeq_tail(struct pktq *pq, int prec); -/* Empty the queue at particular precedence level */ -extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, - ifpkt_cb_t fn, int arg); -/* Remove a specified packet from its queue */ -extern bool pktq_pdel(struct pktq *pq, void *p, int prec); - -/* operations on a set of precedences in packet queue */ - -extern int pktq_mlen(struct pktq *pq, uint prec_bmp); -extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); -extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); - -/* operations on packet queue as a whole */ - -#define pktq_len(pq) ((int)(pq)->len) -#define pktq_max(pq) ((int)(pq)->max) -#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) -#define pktq_full(pq) ((pq)->len >= (pq)->max) -#define pktq_empty(pq) ((pq)->len == 0) - -/* operations for single precedence queues */ -#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) -#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) -#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) -#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) -#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) - -extern void pktq_init(struct pktq *pq, int num_prec, int max_len); -extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); - -/* prec_out may be NULL if caller is not interested in return value */ -extern void *pktq_deq(struct pktq *pq, int *prec_out); -extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); -extern void *pktq_peek(struct pktq *pq, int *prec_out); -extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); -extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); - -/* externs */ -/* packet */ -extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); -extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); -extern uint pkttotlen(osl_t *osh, void *p); -extern void *pktlast(osl_t *osh, void *p); -extern uint pktsegcnt(osl_t *osh, void *p); -extern uint pktsegcnt_war(osl_t *osh, void *p); -extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset); -extern void *pktoffset(osl_t *osh, void *p, uint offset); - -/* Get priority from a packet and pass it back in scb (or equiv) */ -#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */ -#define PKTPRIO_VLAN 0x200 /* VLAN prio found */ -#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ -#define PKTPRIO_DSCP 0x800 /* DSCP prio found */ - -/* DSCP type definitions (RFC4594) */ -/* AF1x: High-Throughput Data (RFC2597) */ -#define DSCP_AF11 0x0A -#define DSCP_AF12 0x0C -#define DSCP_AF13 0x0E -/* AF2x: Low-Latency Data (RFC2597) */ -#define DSCP_AF21 0x12 -#define DSCP_AF22 0x14 -#define DSCP_AF23 0x16 -/* AF3x: Multimedia Streaming (RFC2597) */ -#define DSCP_AF31 0x1A -#define DSCP_AF32 0x1C -#define DSCP_AF33 0x1E -/* EF: Telephony (RFC3246) */ -#define DSCP_EF 0x2E - -extern uint pktsetprio(void *pkt, bool update_vtag); - -/* string */ -extern int bcm_atoi(const char *s); -extern ulong bcm_strtoul(const char *cp, char **endp, uint base); -extern char *bcmstrstr(const char *haystack, const char *needle); -extern char *bcmstrcat(char *dest, const char *src); -extern char *bcmstrncat(char *dest, const char *src, uint size); -extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); -char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); -int bcmstricmp(const char *s1, const char *s2); -int bcmstrnicmp(const char* s1, const char* s2, int cnt); - - -/* ethernet address */ -extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); -extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); - -/* ip address */ -struct ipv4_addr; -extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); -extern char *bcm_ipv6_ntoa(void *ipv6, char *buf); -extern int bcm_atoipv4(const char *p, struct ipv4_addr *ip); - -/* delay */ -extern void bcm_mdelay(uint ms); -/* variable access */ -#define NVRAM_RECLAIM_CHECK(name) - -extern char *getvar(char *vars, const char *name); -extern int getintvar(char *vars, const char *name); -extern int getintvararray(char *vars, const char *name, int index); -extern int getintvararraysize(char *vars, const char *name); -extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); -#define bcm_perf_enable() -#define bcmstats(fmt) -#define bcmlog(fmt, a1, a2) -#define bcmdumplog(buf, size) *buf = '\0' -#define bcmdumplogent(buf, idx) -1 - -#define TSF_TICKS_PER_MS 1000 - -#define bcmtslog(tstamp, fmt, a1, a2) -#define bcmprinttslogs() -#define bcmprinttstamp(us) -#define bcmdumptslog(buf, size) - -extern char *bcm_nvram_vars(uint *length); -extern int bcm_nvram_cache(void *sih); - -/* Support for sharing code across in-driver iovar implementations. - * The intent is that a driver use this structure to map iovar names - * to its (private) iovar identifiers, and the lookup function to - * find the entry. Macros are provided to map ids and get/set actions - * into a single number space for a switch statement. - */ - -/* iovar structure */ -typedef struct bcm_iovar { - const char *name; /* name for lookup and display */ - uint16 varid; /* id for switch */ - uint16 flags; /* driver-specific flag bits */ - uint16 type; /* base type of argument */ - uint16 minlen; /* min length for buffer vars */ -} bcm_iovar_t; - -/* varid definitions are per-driver, may use these get/set bits */ - -/* IOVar action bits for id mapping */ -#define IOV_GET 0 /* Get an iovar */ -#define IOV_SET 1 /* Set an iovar */ - -/* Varid to actionid mapping */ -#define IOV_GVAL(id) ((id) * 2) -#define IOV_SVAL(id) ((id) * 2 + IOV_SET) -#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) -#define IOV_ID(actionid) (actionid >> 1) - -/* flags are per-driver based on driver attributes */ - -extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); -extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); -#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ - defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) -extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); -#endif -#endif /* BCMDRIVER */ - -/* Base type definitions */ -#define IOVT_VOID 0 /* no value (implictly set only) */ -#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */ -#define IOVT_INT8 2 /* integer values are range-checked */ -#define IOVT_UINT8 3 /* unsigned int 8 bits */ -#define IOVT_INT16 4 /* int 16 bits */ -#define IOVT_UINT16 5 /* unsigned int 16 bits */ -#define IOVT_INT32 6 /* int 32 bits */ -#define IOVT_UINT32 7 /* unsigned int 32 bits */ -#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */ -#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) - -/* Initializer for IOV type strings */ -#define BCM_IOV_TYPE_INIT { \ - "void", \ - "bool", \ - "int8", \ - "uint8", \ - "int16", \ - "uint16", \ - "int32", \ - "uint32", \ - "buffer", \ - "" } - -#define BCM_IOVT_IS_INT(type) (\ - (type == IOVT_BOOL) || \ - (type == IOVT_INT8) || \ - (type == IOVT_UINT8) || \ - (type == IOVT_INT16) || \ - (type == IOVT_UINT16) || \ - (type == IOVT_INT32) || \ - (type == IOVT_UINT32)) - -/* ** driver/apps-shared section ** */ - -#define BCME_STRLEN 64 /* Max string length for BCM errors */ -#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) - - -/* - * error codes could be added but the defined ones shouldn't be changed/deleted - * these error codes are exposed to the user code - * when ever a new error code is added to this list - * please update errorstring table with the related error string and - * update osl files with os specific errorcode map -*/ - -#define BCME_OK 0 /* Success */ -#define BCME_ERROR -1 /* Error generic */ -#define BCME_BADARG -2 /* Bad Argument */ -#define BCME_BADOPTION -3 /* Bad option */ -#define BCME_NOTUP -4 /* Not up */ -#define BCME_NOTDOWN -5 /* Not down */ -#define BCME_NOTAP -6 /* Not AP */ -#define BCME_NOTSTA -7 /* Not STA */ -#define BCME_BADKEYIDX -8 /* BAD Key Index */ -#define BCME_RADIOOFF -9 /* Radio Off */ -#define BCME_NOTBANDLOCKED -10 /* Not band locked */ -#define BCME_NOCLK -11 /* No Clock */ -#define BCME_BADRATESET -12 /* BAD Rate valueset */ -#define BCME_BADBAND -13 /* BAD Band */ -#define BCME_BUFTOOSHORT -14 /* Buffer too short */ -#define BCME_BUFTOOLONG -15 /* Buffer too long */ -#define BCME_BUSY -16 /* Busy */ -#define BCME_NOTASSOCIATED -17 /* Not Associated */ -#define BCME_BADSSIDLEN -18 /* Bad SSID len */ -#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ -#define BCME_BADCHAN -20 /* Bad Channel */ -#define BCME_BADADDR -21 /* Bad Address */ -#define BCME_NORESOURCE -22 /* Not Enough Resources */ -#define BCME_UNSUPPORTED -23 /* Unsupported */ -#define BCME_BADLEN -24 /* Bad length */ -#define BCME_NOTREADY -25 /* Not Ready */ -#define BCME_EPERM -26 /* Not Permitted */ -#define BCME_NOMEM -27 /* No Memory */ -#define BCME_ASSOCIATED -28 /* Associated */ -#define BCME_RANGE -29 /* Not In Range */ -#define BCME_NOTFOUND -30 /* Not Found */ -#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ -#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ -#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ -#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ -#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ -#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ -#define BCME_VERSION -37 /* Incorrect version */ -#define BCME_TXFAIL -38 /* TX failure */ -#define BCME_RXFAIL -39 /* RX failure */ -#define BCME_NODEVICE -40 /* Device not present */ -#define BCME_NMODE_DISABLED -41 /* NMODE disabled */ -#define BCME_NONRESIDENT -42 /* access to nonresident overlay */ -#define BCME_SCANREJECT -43 /* reject scan request */ -#define BCME_USAGE_ERROR -44 /* WLCMD usage error */ -#define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */ -#define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */ -#define BCME_DISABLED -47 /* Disabled in this build */ -#define BCME_DECERR -48 /* Decrypt error */ -#define BCME_ENCERR -49 /* Encrypt error */ -#define BCME_MICERR -50 /* Integrity/MIC error */ -#define BCME_REPLAY -51 /* Replay */ -#define BCME_IE_NOTFOUND -52 /* IE not found */ -#define BCME_LAST BCME_IE_NOTFOUND - -#define BCME_NOTENABLED BCME_DISABLED - -/* These are collection of BCME Error strings */ -#define BCMERRSTRINGTABLE { \ - "OK", \ - "Undefined error", \ - "Bad Argument", \ - "Bad Option", \ - "Not up", \ - "Not down", \ - "Not AP", \ - "Not STA", \ - "Bad Key Index", \ - "Radio Off", \ - "Not band locked", \ - "No clock", \ - "Bad Rate valueset", \ - "Bad Band", \ - "Buffer too short", \ - "Buffer too long", \ - "Busy", \ - "Not Associated", \ - "Bad SSID len", \ - "Out of Range Channel", \ - "Bad Channel", \ - "Bad Address", \ - "Not Enough Resources", \ - "Unsupported", \ - "Bad length", \ - "Not Ready", \ - "Not Permitted", \ - "No Memory", \ - "Associated", \ - "Not In Range", \ - "Not Found", \ - "WME Not Enabled", \ - "TSPEC Not Found", \ - "ACM Not Supported", \ - "Not WME Association", \ - "SDIO Bus Error", \ - "Dongle Not Accessible", \ - "Incorrect version", \ - "TX Failure", \ - "RX Failure", \ - "Device Not Present", \ - "NMODE Disabled", \ - "Nonresident overlay access", \ - "Scan Rejected", \ - "WLCMD usage error", \ - "WLCMD ioctl error", \ - "RWL serial port error", \ - "Disabled", \ - "Decrypt error", \ - "Encrypt error", \ - "MIC error", \ - "Replay", \ - "IE not found", \ -} - -#ifndef ABS -#define ABS(a) (((a) < 0) ? -(a) : (a)) -#endif /* ABS */ - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif /* MIN */ - -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif /* MAX */ - -/* limit to [min, max] */ -#ifndef LIMIT_TO_RANGE -#define LIMIT_TO_RANGE(x, min, max) \ - ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) -#endif /* LIMIT_TO_RANGE */ - -/* limit to max */ -#ifndef LIMIT_TO_MAX -#define LIMIT_TO_MAX(x, max) \ - (((x) > (max) ? (max) : (x))) -#endif /* LIMIT_TO_MAX */ - -/* limit to min */ -#ifndef LIMIT_TO_MIN -#define LIMIT_TO_MIN(x, min) \ - (((x) < (min) ? (min) : (x))) -#endif /* LIMIT_TO_MIN */ - -#define DELTA(curr, prev) ((curr) > (prev) ? ((curr) - (prev)) : \ - (0xffffffff - (prev) + (curr) + 1)) -#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) -#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) -#define ROUNDDN(p, align) ((p) & ~((align) - 1)) -#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) -#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ - & ~((boundary) - 1)) -#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ - & ~((boundary) - 1)) -#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) -#define VALID_MASK(mask) !((mask) & ((mask) + 1)) - -#ifndef OFFSETOF -#ifdef __ARMCC_VERSION -/* - * The ARM RVCT compiler complains when using OFFSETOF where a constant - * expression is expected, such as an initializer for a static object. - * offsetof from the runtime library doesn't have that problem. - */ -#include -#define OFFSETOF(type, member) offsetof(type, member) -#else -# if ((__GNUC__ >= 4) && (__GNUC_MINOR__ >= 8)) -/* GCC 4.8+ complains when using our OFFSETOF macro in array length declarations. */ -# define OFFSETOF(type, member) __builtin_offsetof(type, member) -# else -# define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) -# endif /* GCC 4.8 or newer */ -#endif /* __ARMCC_VERSION */ -#endif /* OFFSETOF */ - -#ifndef ARRAYSIZE -#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) -#endif - -#ifndef ARRAYLAST /* returns pointer to last array element */ -#define ARRAYLAST(a) (&a[ARRAYSIZE(a)-1]) -#endif - -/* Reference a function; used to prevent a static function from being optimized out */ -extern void *_bcmutils_dummy_fn; -#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) - -/* bit map related macros */ -#ifndef setbit -#ifndef NBBY /* the BSD family defines NBBY */ -#define NBBY 8 /* 8 bits per byte */ -#endif /* #ifndef NBBY */ -#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS -extern void setbit(void *array, uint bit); -extern void clrbit(void *array, uint bit); -extern bool isset(const void *array, uint bit); -extern bool isclr(const void *array, uint bit); -#else -#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) -#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) -#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) -#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) -#endif -#endif /* setbit */ - -#define isbitset(a, i) (((a) & (1 << (i))) != 0) - -#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) - -extern void bcm_bitprint32(const uint32 u32); - -/* - * ---------------------------------------------------------------------------- - * Multiword map of 2bits, nibbles - * setbit2 setbit4 (void *ptr, uint32 ix, uint32 val) - * getbit2 getbit4 (void *ptr, uint32 ix) - * ---------------------------------------------------------------------------- - */ - -#define DECLARE_MAP_API(NB, RSH, LSH, OFF, MSK) \ -static INLINE void setbit##NB(void *ptr, uint32 ix, uint32 val) \ -{ \ - uint32 *addr = (uint32 *)ptr; \ - uint32 *a = addr + (ix >> RSH); /* (ix / 2^RSH) */ \ - uint32 pos = (ix & OFF) << LSH; /* (ix % 2^RSH) * 2^LSH */ \ - uint32 mask = (MSK << pos); \ - uint32 tmp = *a & ~mask; \ - *a = tmp | (val << pos); \ -} \ -static INLINE uint32 getbit##NB(void *ptr, uint32 ix) \ -{ \ - uint32 *addr = (uint32 *)ptr; \ - uint32 *a = addr + (ix >> RSH); \ - uint32 pos = (ix & OFF) << LSH; \ - return ((*a >> pos) & MSK); \ -} - -DECLARE_MAP_API(2, 4, 1, 15U, 0x0003) /* setbit2() and getbit2() */ -DECLARE_MAP_API(4, 3, 2, 7U, 0x000F) /* setbit4() and getbit4() */ - - -/* 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 MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 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)) - -/* modulo add/sub - assumes x, y E [0, bound - 1] */ -#define MODADD(x, y, bound) \ - MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) -#define MODSUB(x, y, bound) \ - MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) - -/* module 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)) - -/* crc defines */ -#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */ -#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */ -#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */ -#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */ -#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */ -#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */ - -/* use for direct output of MAC address in printf etc */ -#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" -#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ - ((struct ether_addr *) (ea))->octet[1], \ - ((struct ether_addr *) (ea))->octet[2], \ - ((struct ether_addr *) (ea))->octet[3], \ - ((struct ether_addr *) (ea))->octet[4], \ - ((struct ether_addr *) (ea))->octet[5] - -#define ETHER_TO_MACF(ea) (ea).octet[0], \ - (ea).octet[1], \ - (ea).octet[2], \ - (ea).octet[3], \ - (ea).octet[4], \ - (ea).octet[5] -#if !defined(SIMPLE_MAC_PRINT) -#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC2STR(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] -#else -#define MACDBG "%02x:%02x:%02x" -#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] -#define MACSTR "%02x:%02x:%02x" -#define MAC2STR(ea) (ea)[0], (ea)[4], (ea)[5] -#endif /* SIMPLE_MAC_PRINT */ - -/* bcm_format_flags() bit description structure */ -typedef struct bcm_bit_desc { - uint32 bit; - const char* name; -} bcm_bit_desc_t; - -/* bcm_format_field */ -typedef struct bcm_bit_desc_ex { - uint32 mask; - const bcm_bit_desc_t *bitfield; -} bcm_bit_desc_ex_t; - -/* buffer length for ethernet address from bcm_ether_ntoa() */ -#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */ - -/* crypto utility function */ -/* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */ -static INLINE void -xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) -{ - if ( -#ifdef __i386__ - 1 || -#endif - (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { - /* ARM CM3 rel time: 1229 (727 if alignment check could be omitted) */ - /* x86 supports unaligned. This version runs 6x-9x faster on x86. */ - ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; - ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; - ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; - ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; - } else { - /* ARM CM3 rel time: 4668 (4191 if alignment check could be omitted) */ - int k; - for (k = 0; k < 16; k++) - dst[k] = src1[k] ^ src2[k]; - } -} - -/* externs */ -/* crc */ -extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); -extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); -extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); - -/* format/print */ -#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ - defined(WLMSG_ASSOC) -/* print out the value a field has: fields may have 1-32 bits and may hold any value */ -extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len); -/* print out which bits in flags are set */ -extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); -#endif - -extern int bcm_format_hex(char *str, const void *bytes, int len); - -extern const char *bcm_crypto_algo_name(uint algo); -extern char *bcm_chipname(uint chipid, char *buf, uint len); -extern char *bcm_brev_str(uint32 brev, char *buf); -extern void printbig(char *buf); -extern void prhex(const char *msg, uchar *buf, uint len); - -/* IE parsing */ - -/* tag_ID/length/value_buffer tuple */ -typedef struct bcm_tlv { - uint8 id; - uint8 len; - uint8 data[1]; -} bcm_tlv_t; - -/* bcm tlv w/ 16 bit id/len */ -typedef struct bcm_xtlv { - uint16 id; - uint16 len; - uint8 data[1]; -} bcm_xtlv_t; - -/* descriptor of xtlv data src or dst */ -typedef struct { - uint16 type; - uint16 len; - void *ptr; /* ptr to memory location */ -} xtlv_desc_t; - -/* xtlv options */ -#define BCM_XTLV_OPTION_NONE 0x0000 -#define BCM_XTLV_OPTION_ALIGN32 0x0001 - -typedef uint16 bcm_xtlv_opts_t; -struct bcm_xtlvbuf { - bcm_xtlv_opts_t opts; - uint16 size; - uint8 *head; /* point to head of buffer */ - uint8 *buf; /* current position of buffer */ - /* allocated buffer may follow, but not necessarily */ -}; -typedef struct bcm_xtlvbuf bcm_xtlvbuf_t; - -#define BCM_TLV_MAX_DATA_SIZE (255) -#define BCM_XTLV_MAX_DATA_SIZE (65535) -#define BCM_TLV_HDR_SIZE (OFFSETOF(bcm_tlv_t, data)) - -#define BCM_XTLV_HDR_SIZE (OFFSETOF(bcm_xtlv_t, data)) -/* LEN only stores the value's length without padding */ -#define BCM_XTLV_LEN(elt) ltoh16_ua(&(elt->len)) -#define BCM_XTLV_ID(elt) ltoh16_ua(&(elt->id)) -/* entire size of the XTLV including header, data, and optional padding */ -#define BCM_XTLV_SIZE(elt, opts) bcm_xtlv_size(elt, opts) -#define bcm_valid_xtlv(elt, buflen, opts) (elt && ((int)(buflen) >= (int)BCM_XTLV_SIZE(elt, opts))) - -/* Check that bcm_tlv_t fits into the given buflen */ -#define bcm_valid_tlv(elt, buflen) (\ - ((int)(buflen) >= (int)BCM_TLV_HDR_SIZE) && \ - ((int)(buflen) >= (int)(BCM_TLV_HDR_SIZE + (elt)->len))) - -extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); -extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); -extern bcm_tlv_t *bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen); - -extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); - -extern bcm_tlv_t *bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, - int type_len); - -extern uint8 *bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst); -extern uint8 *bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, - int dst_maxlen); - -extern uint8 *bcm_copy_tlv(const void *src, uint8 *dst); -extern uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen); - -/* xtlv */ - -/* return the next xtlv element, and update buffer len (remaining). Buffer length - * updated includes padding as specified by options - */ -extern bcm_xtlv_t *bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts); - -/* initialize an xtlv buffer. Use options specified for packing/unpacking using - * the buffer. Caller is responsible for allocating both buffers. - */ -extern int bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, - bcm_xtlv_opts_t opts); - -extern uint16 bcm_xtlv_buf_len(struct bcm_xtlvbuf *tbuf); -extern uint16 bcm_xtlv_buf_rlen(struct bcm_xtlvbuf *tbuf); -extern uint8 *bcm_xtlv_buf(struct bcm_xtlvbuf *tbuf); -extern uint8 *bcm_xtlv_head(struct bcm_xtlvbuf *tbuf); -extern int bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const void *data, uint16 dlen); -extern int bcm_xtlv_put_8(bcm_xtlvbuf_t *tbuf, uint16 type, const int8 data); -extern int bcm_xtlv_put_16(bcm_xtlvbuf_t *tbuf, uint16 type, const int16 data); -extern int bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data); -extern int bcm_unpack_xtlv_entry(uint8 **buf, uint16 xpct_type, uint16 xpct_len, - void *dst, bcm_xtlv_opts_t opts); -extern int bcm_pack_xtlv_entry(uint8 **buf, uint16 *buflen, uint16 type, uint16 len, - void *src, bcm_xtlv_opts_t opts); -extern int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts); - -/* callback for unpacking xtlv from a buffer into context. */ -typedef int (bcm_xtlv_unpack_cbfn_t)(void *ctx, uint8 *buf, uint16 type, uint16 len); - -/* unpack a tlv buffer using buffer, options, and callback */ -extern int bcm_unpack_xtlv_buf(void *ctx, uint8 *buf, uint16 buflen, - bcm_xtlv_opts_t opts, bcm_xtlv_unpack_cbfn_t *cbfn); - -/* unpack a set of tlvs from the buffer using provided xtlv desc */ -extern int bcm_unpack_xtlv_buf_to_mem(void *buf, int *buflen, xtlv_desc_t *items, - bcm_xtlv_opts_t opts); - -/* pack a set of tlvs into buffer using provided xtlv desc */ -extern int bcm_pack_xtlv_buf_from_mem(void **buf, uint16 *buflen, xtlv_desc_t *items, - bcm_xtlv_opts_t opts); - -/* callback to return next tlv id and len to pack, if there is more tlvs to come and - * options e.g. alignment - */ -typedef bool (*bcm_pack_xtlv_next_info_cbfn_t)(void *ctx, uint16 *tlv_id, uint16 *tlv_len); - -/* callback to pack the tlv into length validated buffer */ -typedef void (*bcm_pack_xtlv_pack_next_cbfn_t)(void *ctx, - uint16 tlv_id, uint16 tlv_len, uint8* buf); - -/* pack a set of tlvs into buffer using get_next to interate */ -int bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, - bcm_xtlv_opts_t opts, bcm_pack_xtlv_next_info_cbfn_t get_next, - bcm_pack_xtlv_pack_next_cbfn_t pack_next, int *outlen); - -/* bcmerror */ -extern const char *bcmerrorstr(int bcmerror); - -/* multi-bool data type: set of bools, mbool is true if any is set */ -typedef uint32 mbool; -#define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */ -#define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */ -#define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */ -#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) - -/* generic datastruct to help dump routines */ -struct fielddesc { - const char *nameandfmt; - uint32 offset; - uint32 len; -}; - -extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); -extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); - -extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); -extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); -extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); - -typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); -extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, - char *buf, uint32 bufsize); -extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); - -extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); - -/* power conversion */ -extern uint16 bcm_qdbm_to_mw(uint8 qdbm); -extern uint8 bcm_mw_to_qdbm(uint16 mw); -extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); - -unsigned int process_nvram_vars(char *varbuf, unsigned int len); - -/* calculate a * b + c */ -extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c); -/* calculate a / b */ -extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b); - - -/* Public domain bit twiddling hacks/utilities: Sean Eron Anderson */ - -/* Table driven count set bits. */ -static const uint8 /* Table only for use by bcm_cntsetbits */ -_CSBTBL[256] = -{ -# define B2(n) n, n + 1, n + 1, n + 2 -# define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2) -# define B6(n) B4(n), B4(n + 1), B4(n + 1), B4(n + 2) - B6(0), B6(0 + 1), B6(0 + 1), B6(0 + 2) -}; - -static INLINE uint32 /* Uses table _CSBTBL for fast counting of 1's in a u32 */ -bcm_cntsetbits(const uint32 u32) -{ - /* function local scope declaration of const _CSBTBL[] */ - const uint8 * p = (const uint8 *)&u32; - return (_CSBTBL[p[0]] + _CSBTBL[p[1]] + _CSBTBL[p[2]] + _CSBTBL[p[3]]); -} - - -static INLINE int /* C equivalent count of leading 0's in a u32 */ -C_bcm_count_leading_zeros(uint32 u32) -{ - int shifts = 0; - while (u32) { - shifts++; u32 >>= 1; - } - return (32U - shifts); -} - -#ifdef BCMDRIVER -/* - * Assembly instructions: Count Leading Zeros - * "clz" : MIPS, ARM - * "cntlzw" : PowerPC - * "BSF" : x86 - * "lzcnt" : AMD, SPARC - */ - -#if defined(__arm__) - -#if defined(__ARM_ARCH_7M__) /* Cortex M3 */ -#define __USE_ASM_CLZ__ -#endif /* __ARM_ARCH_7M__ */ - -#if defined(__ARM_ARCH_7R__) /* Cortex R4 */ -#define __USE_ASM_CLZ__ -#endif /* __ARM_ARCH_7R__ */ - -#endif /* __arm__ */ - -static INLINE int -bcm_count_leading_zeros(uint32 u32) -{ -#if defined(__USE_ASM_CLZ__) - int zeros; - __asm__ volatile("clz %0, %1 \n" : "=r" (zeros) : "r" (u32)); - return zeros; -#else /* C equivalent */ - return C_bcm_count_leading_zeros(u32); -#endif /* C equivalent */ -} - -/* INTERFACE: Multiword bitmap based small id allocator. */ -struct bcm_mwbmap; /* forward declaration for use as an opaque mwbmap handle */ - -#define BCM_MWBMAP_INVALID_HDL ((struct bcm_mwbmap *)NULL) -#define BCM_MWBMAP_INVALID_IDX ((uint32)(~0U)) - -/* Incarnate a multiword bitmap based small index allocator */ -extern struct bcm_mwbmap * bcm_mwbmap_init(osl_t * osh, uint32 items_max); - -/* Free up the multiword bitmap index allocator */ -extern void bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl); - -/* Allocate a unique small index using a multiword bitmap index allocator */ -extern uint32 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl); - -/* Force an index at a specified position to be in use */ -extern void bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); - -/* Free a previously allocated index back into the multiword bitmap allocator */ -extern void bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); - -/* Fetch the toal number of free indices in the multiword bitmap allocator */ -extern uint32 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl); - -/* Determine whether an index is inuse or free */ -extern bool bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); - -/* Debug dump a multiword bitmap allocator */ -extern void bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl); - -extern void bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl); -/* End - Multiword bitmap based small Id allocator. */ -#endif /* BCMDRIVER */ - -extern void bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b); - -void bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset); -void bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset); - -#ifdef __cplusplus - } -#endif - -#ifdef DEBUG_COUNTER -#define CNTR_TBL_MAX 10 -typedef struct _counter_tbl_t { - char name[16]; /* name of this counter table */ - uint32 prev_log_print; /* Internal use. Timestamp of the previous log print */ - uint log_print_interval; /* Desired interval to print logs in ms */ - uint needed_cnt; /* How many counters need to be used */ - uint32 cnt[CNTR_TBL_MAX]; /* Counting entries to increase at desired places */ - bool enabled; /* Whether to enable printing log */ -} counter_tbl_t; - - -void counter_printlog(counter_tbl_t *ctr_tbl); -#endif /* DEBUG_COUNTER */ - -#endif /* _bcmutils_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h deleted file mode 100755 index f17c05d52521..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Definitions for nl80211 testmode access to host driver - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: brcm_nl80211.h 596861 2015-11-03 08:54:58Z $ - * - */ - -#ifndef _brcm_nl80211_h_ -#define _brcm_nl80211_h_ - -#define OUI_BRCM 0x001018 - -enum wl_vendor_subcmd { - BRCM_VENDOR_SCMD_UNSPEC, - BRCM_VENDOR_SCMD_PRIV_STR, - BRCM_VENDOR_SCMD_BCM_STR -}; - -struct bcm_nlmsg_hdr { - uint cmd; /* common ioctl definition */ - uint len; /* attached buffer length */ - uint offset; /* user buffer offset */ - uint set; /* get or set request optional */ - uint magic; /* magic number for verification */ -}; - -enum bcmnl_attrs { - BCM_NLATTR_UNSPEC, - - BCM_NLATTR_LEN, - BCM_NLATTR_DATA, - - __BCM_NLATTR_AFTER_LAST, - BCM_NLATTR_MAX = __BCM_NLATTR_AFTER_LAST - 1 -}; - -struct nl_prv_data { - int err; /* return result */ - void *data; /* ioctl return buffer pointer */ - uint len; /* ioctl return buffer length */ - struct bcm_nlmsg_hdr *nlioc; /* bcm_nlmsg_hdr header pointer */ -}; - -#endif /* _brcm_nl80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/dbus.h b/drivers/net/wireless/bcmdhd_suzuran/include/dbus.h deleted file mode 100755 index 80ef80bd97e9..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/dbus.h +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Dongle BUS interface Abstraction layer - * target serial buses like USB, SDIO, SPI, etc. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dbus.h 423346 2013-09-11 22:38:40Z $ - */ - -#ifndef __DBUS_H__ -#define __DBUS_H__ - -#include "typedefs.h" - -#define DBUSTRACE(args) -#define DBUSERR(args) -#define DBUSINFO(args) -#define DBUSDBGLOCK(args) - -enum { - DBUS_OK = 0, - DBUS_ERR = -200, - DBUS_ERR_TIMEOUT, - DBUS_ERR_DISCONNECT, - DBUS_ERR_NODEVICE, - DBUS_ERR_UNSUPPORTED, - DBUS_ERR_PENDING, - DBUS_ERR_NOMEM, - DBUS_ERR_TXFAIL, - DBUS_ERR_TXTIMEOUT, - DBUS_ERR_TXDROP, - DBUS_ERR_RXFAIL, - DBUS_ERR_RXDROP, - DBUS_ERR_TXCTLFAIL, - DBUS_ERR_RXCTLFAIL, - DBUS_ERR_REG_PARAM, - DBUS_STATUS_CANCELLED, - DBUS_ERR_NVRAM, - DBUS_JUMBO_NOMATCH, - DBUS_JUMBO_BAD_FORMAT, - DBUS_NVRAM_NONTXT -}; - -#define BCM_OTP_SIZE_43236 84 /* number of 16 bit values */ -#define BCM_OTP_SW_RGN_43236 24 /* start offset of SW config region */ -#define BCM_OTP_ADDR_43236 0x18000800 /* address of otp base */ - -#define ERR_CBMASK_TXFAIL 0x00000001 -#define ERR_CBMASK_RXFAIL 0x00000002 -#define ERR_CBMASK_ALL 0xFFFFFFFF - -#define DBUS_CBCTL_WRITE 0 -#define DBUS_CBCTL_READ 1 -#if defined(INTR_EP_ENABLE) -#define DBUS_CBINTR_POLL 2 -#endif /* defined(INTR_EP_ENABLE) */ - -#define DBUS_TX_RETRY_LIMIT 3 /* retries for failed txirb */ -#define DBUS_TX_TIMEOUT_INTERVAL 250 /* timeout for txirb complete, in ms */ - -#define DBUS_BUFFER_SIZE_TX 32000 -#define DBUS_BUFFER_SIZE_RX 24000 - -#define DBUS_BUFFER_SIZE_TX_NOAGG 2048 -#define DBUS_BUFFER_SIZE_RX_NOAGG 2048 - -/* DBUS types */ -enum { - DBUS_USB, - DBUS_SDIO, - DBUS_SPI, - DBUS_UNKNOWN -}; - -enum dbus_state { - DBUS_STATE_DL_PENDING, - DBUS_STATE_DL_DONE, - DBUS_STATE_UP, - DBUS_STATE_DOWN, - DBUS_STATE_PNP_FWDL, - DBUS_STATE_DISCONNECT, - DBUS_STATE_SLEEP -}; - -enum dbus_pnp_state { - DBUS_PNP_DISCONNECT, - DBUS_PNP_SLEEP, - DBUS_PNP_RESUME -}; - -enum dbus_file { - DBUS_FIRMWARE, - DBUS_NVFILE -}; - -typedef enum _DEVICE_SPEED { - INVALID_SPEED = -1, - LOW_SPEED = 1, /* USB 1.1: 1.5 Mbps */ - FULL_SPEED, /* USB 1.1: 12 Mbps */ - HIGH_SPEED, /* USB 2.0: 480 Mbps */ - SUPER_SPEED, /* USB 3.0: 4.8 Gbps */ -} DEVICE_SPEED; - -typedef struct { - int bustype; - int vid; - int pid; - int devid; - int chiprev; /* chip revsion number */ - int mtu; - int nchan; /* Data Channels */ - int has_2nd_bulk_in_ep; -} dbus_attrib_t; - -/* FIX: Account for errors related to DBUS; - * Let upper layer account for packets/bytes - */ -typedef struct { - uint32 rx_errors; - uint32 tx_errors; - uint32 rx_dropped; - uint32 tx_dropped; -} dbus_stats_t; - -/* - * Configurable BUS parameters - */ -enum { - DBUS_CONFIG_ID_RXCTL_DEFERRES = 1, - DBUS_CONFIG_ID_TXRXQUEUE -}; -typedef struct { - uint32 config_id; - union { - bool rxctl_deferrespok; - struct { - int maxrxq; - int rxbufsize; - int maxtxq; - int txbufsize; - } txrxqueue; - }; -} dbus_config_t; - -/* - * External Download Info - */ -typedef struct dbus_extdl { - uint8 *fw; - int fwlen; - uint8 *vars; - int varslen; -} dbus_extdl_t; - -struct dbus_callbacks; -struct exec_parms; - -typedef void *(*probe_cb_t)(void *arg, const char *desc, uint32 bustype, uint32 hdrlen); -typedef void (*disconnect_cb_t)(void *arg); -typedef void *(*exec_cb_t)(struct exec_parms *args); - -/* Client callbacks registered during dbus_attach() */ -typedef struct dbus_callbacks { - void (*send_complete)(void *cbarg, void *info, int status); - void (*recv_buf)(void *cbarg, uint8 *buf, int len); - void (*recv_pkt)(void *cbarg, void *pkt); - void (*txflowcontrol)(void *cbarg, bool onoff); - void (*errhandler)(void *cbarg, int err); - void (*ctl_complete)(void *cbarg, int type, int status); - void (*state_change)(void *cbarg, int state); - void *(*pktget)(void *cbarg, uint len, bool send); - void (*pktfree)(void *cbarg, void *p, bool send); -} dbus_callbacks_t; - -struct dbus_pub; -struct bcmstrbuf; -struct dbus_irb; -struct dbus_irb_rx; -struct dbus_irb_tx; -struct dbus_intf_callbacks; - -typedef struct { - void* (*attach)(struct dbus_pub *pub, void *cbarg, struct dbus_intf_callbacks *cbs); - void (*detach)(struct dbus_pub *pub, void *bus); - - int (*up)(void *bus); - int (*down)(void *bus); - int (*send_irb)(void *bus, struct dbus_irb_tx *txirb); - int (*recv_irb)(void *bus, struct dbus_irb_rx *rxirb); - int (*cancel_irb)(void *bus, struct dbus_irb_tx *txirb); - int (*send_ctl)(void *bus, uint8 *buf, int len); - int (*recv_ctl)(void *bus, uint8 *buf, int len); - int (*get_stats)(void *bus, dbus_stats_t *stats); - int (*get_attrib)(void *bus, dbus_attrib_t *attrib); - - int (*pnp)(void *bus, int evnt); - int (*remove)(void *bus); - int (*resume)(void *bus); - int (*suspend)(void *bus); - int (*stop)(void *bus); - int (*reset)(void *bus); - - /* Access to bus buffers directly */ - void *(*pktget)(void *bus, int len); - void (*pktfree)(void *bus, void *pkt); - - int (*iovar_op)(void *bus, const char *name, void *params, int plen, void *arg, int len, - bool set); - void (*dump)(void *bus, struct bcmstrbuf *strbuf); - int (*set_config)(void *bus, dbus_config_t *config); - int (*get_config)(void *bus, dbus_config_t *config); - - bool (*device_exists)(void *bus); - bool (*dlneeded)(void *bus); - int (*dlstart)(void *bus, uint8 *fw, int len); - int (*dlrun)(void *bus); - bool (*recv_needed)(void *bus); - - void *(*exec_rxlock)(void *bus, exec_cb_t func, struct exec_parms *args); - void *(*exec_txlock)(void *bus, exec_cb_t func, struct exec_parms *args); - - int (*tx_timer_init)(void *bus); - int (*tx_timer_start)(void *bus, uint timeout); - int (*tx_timer_stop)(void *bus); - - int (*sched_dpc)(void *bus); - int (*lock)(void *bus); - int (*unlock)(void *bus); - int (*sched_probe_cb)(void *bus); - - int (*shutdown)(void *bus); - - int (*recv_stop)(void *bus); - int (*recv_resume)(void *bus); - - int (*recv_irb_from_ep)(void *bus, struct dbus_irb_rx *rxirb, uint ep_idx); - - int (*readreg)(void *bus, uint32 regaddr, int datalen, uint32 *value); - - /* Add from the bottom */ -} dbus_intf_t; - -typedef struct dbus_pub { - struct osl_info *osh; - dbus_stats_t stats; - dbus_attrib_t attrib; - enum dbus_state busstate; - DEVICE_SPEED device_speed; - int ntxq, nrxq, rxsize; - void *bus; - struct shared_info *sh; - void *dev_info; -} dbus_pub_t; - -#define BUS_INFO(bus, type) (((type *) bus)->pub->bus) - -#define ALIGNED_LOCAL_VARIABLE(var, align) \ - uint8 buffer[SDALIGN+64]; \ - uint8 *var = (uint8 *)(((uintptr)&buffer[0]) & ~(align-1)) + align; - -/* - * Public Bus Function Interface - */ - -/* - * FIX: Is there better way to pass OS/Host handles to DBUS but still - * maintain common interface for all OS?? - * Under NDIS, param1 needs to be MiniportHandle - * For NDIS60, param2 is WdfDevice - * Under Linux, param1 and param2 are NULL; - */ -extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, - void *param1, void *param2); -extern int dbus_deregister(void); - -extern dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq, int ntxq, - void *cbarg, dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh); -extern void dbus_detach(dbus_pub_t *pub); - -extern int dbus_up(dbus_pub_t *pub); -extern int dbus_down(dbus_pub_t *pub); -extern int dbus_stop(dbus_pub_t *pub); -extern int dbus_shutdown(dbus_pub_t *pub); -extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on); - -extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); -extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info); -extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); -extern int dbus_send_ctl(dbus_pub_t *pub, uint8 *buf, int len); -extern int dbus_recv_ctl(dbus_pub_t *pub, uint8 *buf, int len); -extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); -extern int dbus_poll_intr(dbus_pub_t *pub); -extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats); -extern int dbus_get_attrib(dbus_pub_t *pub, dbus_attrib_t *attrib); -extern int dbus_get_device_speed(dbus_pub_t *pub); -extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config); -extern int dbus_get_config(dbus_pub_t *pub, dbus_config_t *config); -extern void * dbus_get_devinfo(dbus_pub_t *pub); - -extern void *dbus_pktget(dbus_pub_t *pub, int len); -extern void dbus_pktfree(dbus_pub_t *pub, void* pkt); - -extern int dbus_set_errmask(dbus_pub_t *pub, uint32 mask); -extern int dbus_pnp_sleep(dbus_pub_t *pub); -extern int dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload); -extern int dbus_pnp_disconnect(dbus_pub_t *pub); - -extern int dbus_iovar_op(dbus_pub_t *pub, const char *name, - void *params, int plen, void *arg, int len, bool set); - -extern void *dhd_dbus_txq(const dbus_pub_t *pub); -extern uint dhd_dbus_hdrlen(const dbus_pub_t *pub); - -/* - * Private Common Bus Interface - */ - -/* IO Request Block (IRB) */ -typedef struct dbus_irb { - struct dbus_irb *next; /* it's casted from dbus_irb_tx or dbus_irb_rx struct */ -} dbus_irb_t; - -typedef struct dbus_irb_rx { - struct dbus_irb irb; /* Must be first */ - uint8 *buf; - int buf_len; - int actual_len; - void *pkt; - void *info; - void *arg; -} dbus_irb_rx_t; - -typedef struct dbus_irb_tx { - struct dbus_irb irb; /* Must be first */ - uint8 *buf; - int len; - void *pkt; - int retry_count; - void *info; - void *arg; - void *send_buf; /* linear bufffer for LINUX when aggreagtion is enabled */ -} dbus_irb_tx_t; - -/* DBUS interface callbacks are different from user callbacks - * so, internally, different info can be passed to upper layer - */ -typedef struct dbus_intf_callbacks { - void (*send_irb_timeout)(void *cbarg, dbus_irb_tx_t *txirb); - void (*send_irb_complete)(void *cbarg, dbus_irb_tx_t *txirb, int status); - void (*recv_irb_complete)(void *cbarg, dbus_irb_rx_t *rxirb, int status); - void (*errhandler)(void *cbarg, int err); - void (*ctl_complete)(void *cbarg, int type, int status); - void (*state_change)(void *cbarg, int state); - bool (*isr)(void *cbarg, bool *wantdpc); - bool (*dpc)(void *cbarg, bool bounded); - void (*watchdog)(void *cbarg); - void *(*pktget)(void *cbarg, uint len, bool send); - void (*pktfree)(void *cbarg, void *p, bool send); - struct dbus_irb* (*getirb)(void *cbarg, bool send); - void (*rxerr_indicate)(void *cbarg, bool on); -} dbus_intf_callbacks_t; - -/* - * Porting: To support new bus, port these functions below - */ - -/* - * Bus specific Interface - * Implemented by dbus_usb.c/dbus_sdio.c - */ -extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, - dbus_intf_t **intf, void *param1, void *param2); -extern int dbus_bus_deregister(void); -extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp); - -/* - * Bus-specific and OS-specific Interface - * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c - */ -extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, - void *prarg, dbus_intf_t **intf, void *param1, void *param2); -extern int dbus_bus_osl_deregister(void); - -/* - * Bus-specific, OS-specific, HW-specific Interface - * Mainly for SDIO Host HW controller - */ -extern int dbus_bus_osl_hw_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, - void *prarg, dbus_intf_t **intf); -extern int dbus_bus_osl_hw_deregister(void); - -extern uint usbdev_bulkin_eps(void); -#if defined(BCM_REQUEST_FW) -extern void *dbus_get_fw_nvfile(int devid, uint8 **fw, int *fwlen, int type, - uint16 boardtype, uint16 boardrev); -extern void dbus_release_fw_nvfile(void *firmware); -#endif /* #if defined(BCM_REQUEST_FW) */ - - -#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) - - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) - /* Backward compatibility */ - typedef unsigned int gfp_t; - - #define dma_pool pci_pool - #define dma_pool_create(name, dev, size, align, alloc) \ - pci_pool_create(name, dev, size, align, alloc, GFP_DMA | GFP_ATOMIC) - #define dma_pool_destroy(pool) pci_pool_destroy(pool) - #define dma_pool_alloc(pool, flags, handle) pci_pool_alloc(pool, flags, handle) - #define dma_pool_free(pool, vaddr, addr) pci_pool_free(pool, vaddr, addr) - - #define dma_map_single(dev, addr, size, dir) pci_map_single(dev, addr, size, dir) - #define dma_unmap_single(dev, hnd, size, dir) pci_unmap_single(dev, hnd, size, dir) - #define DMA_FROM_DEVICE PCI_DMA_FROMDEVICE - #define DMA_TO_DEVICE PCI_DMA_TODEVICE -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ - -/* Availability of these functions varies (when present, they have two arguments) */ -#ifndef hc32_to_cpu - #define hc32_to_cpu(x) le32_to_cpu(x) - #define cpu_to_hc32(x) cpu_to_le32(x) - typedef unsigned int __hc32; -#else - #error Two-argument functions needed -#endif - -/* Private USB opcode base */ -#define EHCI_FASTPATH 0x31 -#define EHCI_SET_EP_BYPASS EHCI_FASTPATH -#define EHCI_SET_BYPASS_CB (EHCI_FASTPATH + 1) -#define EHCI_SET_BYPASS_DEV (EHCI_FASTPATH + 2) -#define EHCI_DUMP_STATE (EHCI_FASTPATH + 3) -#define EHCI_SET_BYPASS_POOL (EHCI_FASTPATH + 4) -#define EHCI_CLR_EP_BYPASS (EHCI_FASTPATH + 5) - -/* - * EHCI QTD structure (hardware and extension) - * NOTE that is does not need to (and does not) match its kernel counterpart - */ -#define EHCI_QTD_NBUFFERS 5 -#define EHCI_QTD_ALIGN 32 -#define EHCI_BULK_PACKET_SIZE 512 -#define EHCI_QTD_XACTERR_MAX 32 - -struct ehci_qtd { - /* Hardware map */ - volatile uint32_t qtd_next; - volatile uint32_t qtd_altnext; - volatile uint32_t qtd_status; -#define EHCI_QTD_GET_BYTES(x) (((x)>>16) & 0x7fff) -#define EHCI_QTD_IOC 0x00008000 -#define EHCI_QTD_GET_CERR(x) (((x)>>10) & 0x3) -#define EHCI_QTD_SET_CERR(x) ((x) << 10) -#define EHCI_QTD_GET_PID(x) (((x)>>8) & 0x3) -#define EHCI_QTD_SET_PID(x) ((x) << 8) -#define EHCI_QTD_ACTIVE 0x80 -#define EHCI_QTD_HALTED 0x40 -#define EHCI_QTD_BUFERR 0x20 -#define EHCI_QTD_BABBLE 0x10 -#define EHCI_QTD_XACTERR 0x08 -#define EHCI_QTD_MISSEDMICRO 0x04 - volatile uint32_t qtd_buffer[EHCI_QTD_NBUFFERS]; - volatile uint32_t qtd_buffer_hi[EHCI_QTD_NBUFFERS]; - - /* Implementation extension */ - dma_addr_t qtd_self; /* own hardware address */ - struct ehci_qtd *obj_next; /* software link to the next QTD */ - void *rpc; /* pointer to the rpc buffer */ - size_t length; /* length of the data in the buffer */ - void *buff; /* pointer to the reassembly buffer */ - int xacterrs; /* retry counter for qtd xact error */ -} __attribute__ ((aligned(EHCI_QTD_ALIGN))); - -#define EHCI_NULL __constant_cpu_to_le32(1) /* HW null pointer shall be odd */ - -#define SHORT_READ_Q(token) (EHCI_QTD_GET_BYTES(token) != 0 && EHCI_QTD_GET_PID(token) == 1) - -/* Queue Head */ -/* NOTE This structure is slightly different from the one in the kernel; but needs to stay - * compatible - */ -struct ehci_qh { - /* Hardware map */ - volatile uint32_t qh_link; - volatile uint32_t qh_endp; - volatile uint32_t qh_endphub; - volatile uint32_t qh_curqtd; - - /* QTD overlay */ - volatile uint32_t ow_next; - volatile uint32_t ow_altnext; - volatile uint32_t ow_status; - volatile uint32_t ow_buffer [EHCI_QTD_NBUFFERS]; - volatile uint32_t ow_buffer_hi [EHCI_QTD_NBUFFERS]; - - /* Extension (should match the kernel layout) */ - dma_addr_t unused0; - void *unused1; - struct list_head unused2; - struct ehci_qtd *dummy; - struct ehci_qh *unused3; - - struct ehci_hcd *unused4; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct kref unused5; - unsigned unused6; - - uint8_t unused7; - - /* periodic schedule info */ - uint8_t unused8; - uint8_t unused9; - uint8_t unused10; - uint16_t unused11; - uint16_t unused12; - uint16_t unused13; - struct usb_device *unused14; -#else - unsigned unused5; - - u8 unused6; - - /* periodic schedule info */ - u8 unused7; - u8 unused8; - u8 unused9; - unsigned short unused10; - unsigned short unused11; -#define NO_FRAME ((unsigned short)~0) -#ifdef EHCI_QUIRK_FIX - struct usb_device *unused12; -#endif /* EHCI_QUIRK_FIX */ -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ - struct ehci_qtd *first_qtd; - /* Link to the first QTD; this is an optimized equivalent of the qtd_list field */ - /* NOTE that ehci_qh in ehci.h shall reserve this word */ -} __attribute__ ((aligned(EHCI_QTD_ALIGN))); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -/* The corresponding structure in the kernel is used to get the QH */ -struct hcd_dev { /* usb_device.hcpriv points to this */ - struct list_head unused0; - struct list_head unused1; - - /* array of QH pointers */ - void *ep[32]; -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ - -int optimize_qtd_fill_with_rpc(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *rpc, - int token, int len); -int optimize_qtd_fill_with_data(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *data, - int token, int len); -int optimize_submit_async(struct ehci_qtd *qtd, int epn); -void inline optimize_ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma); -struct ehci_qtd *optimize_ehci_qtd_alloc(gfp_t flags); -void optimize_ehci_qtd_free(struct ehci_qtd *qtd); -void optimize_submit_rx_request(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd_in, void *buf); -#endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ - -void dbus_flowctrl_tx(void *dbi, bool on); -#endif /* __DBUS_H__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h deleted file mode 100755 index 6001a497ce81..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h +++ /dev/null @@ -1,2030 +0,0 @@ -/* - * Custom OID/ioctl definitions for - * Broadcom 802.11abg Networking Device Driver - * - * Definitions subject to change without notice. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wlioctl_defs.h 403826 2013-05-22 16:40:55Z $ - */ - - -#ifndef wlioctl_defs_h -#define wlioctl_defs_h - - - - - -/* All builds use the new 11ac ratespec/chanspec */ -#undef D11AC_IOTYPES -#define D11AC_IOTYPES - -/* WL_RSPEC defines for rate information */ -#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */ -#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */ -#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */ -#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */ -#define WL_RSPEC_TXEXP_MASK 0x00000300 -#define WL_RSPEC_TXEXP_SHIFT 8 -#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ -#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ -#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ -#define WL_RSPEC_TXBF 0x00200000 /* bit indicates TXBF mode */ -#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ -#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ -#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ -#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */ -#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override both rate & mode */ - -/* WL_RSPEC_ENCODING field defs */ -#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */ -#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */ -#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */ - -/* WL_RSPEC_BW field defs */ -#define WL_RSPEC_BW_UNSPECIFIED 0 -#define WL_RSPEC_BW_20MHZ 0x00010000 -#define WL_RSPEC_BW_40MHZ 0x00020000 -#define WL_RSPEC_BW_80MHZ 0x00030000 -#define WL_RSPEC_BW_160MHZ 0x00040000 - -/* Legacy defines for the nrate iovar */ -#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ -#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ -#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ -#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */ -#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ -#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ -#define OLD_NRATE_SGI 0x00800000 /* sgi mode */ -#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ - -#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */ -#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */ -#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */ -#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */ - -#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ - -#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ -#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ - -#define IBSS_MED 15 /* Mediom in-bss congestion percentage */ -#define IBSS_HI 25 /* Hi in-bss congestion percentage */ -#define OBSS_MED 12 -#define OBSS_HI 25 -#define INTERFER_MED 5 -#define INTERFER_HI 10 - -#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */ -#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */ -#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */ -#define CCA_FLAGS_PREFER_1_6_11 0x10 -#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */ - -#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */ -#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */ -#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */ -#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */ -#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */ - -#define WL_STA_AID(a) ((a) &~ 0xc000) - -/* Flags for sta_info_t indicating properties of STA */ -#define WL_STA_BRCM 0x00000001 /* Running a Broadcom driver */ -#define WL_STA_WME 0x00000002 /* WMM association */ -#define WL_STA_NONERP 0x00000004 /* No ERP */ -#define WL_STA_AUTHE 0x00000008 /* Authenticated */ -#define WL_STA_ASSOC 0x00000010 /* Associated */ -#define WL_STA_AUTHO 0x00000020 /* Authorized */ -#define WL_STA_WDS 0x00000040 /* Wireless Distribution System */ -#define WL_STA_WDS_LINKUP 0x00000080 /* WDS traffic/probes flowing properly */ -#define WL_STA_PS 0x00000100 /* STA is in power save mode from AP's viewpoint */ -#define WL_STA_APSD_BE 0x00000200 /* APSD delv/trigger for AC_BE is default enabled */ -#define WL_STA_APSD_BK 0x00000400 /* APSD delv/trigger for AC_BK is default enabled */ -#define WL_STA_APSD_VI 0x00000800 /* APSD delv/trigger for AC_VI is default enabled */ -#define WL_STA_APSD_VO 0x00001000 /* APSD delv/trigger for AC_VO is default enabled */ -#define WL_STA_N_CAP 0x00002000 /* STA 802.11n capable */ -#define WL_STA_SCBSTATS 0x00004000 /* Per STA debug stats */ -#define WL_STA_AMPDU_CAP 0x00008000 /* STA AMPDU capable */ -#define WL_STA_AMSDU_CAP 0x00010000 /* STA AMSDU capable */ -#define WL_STA_MIMO_PS 0x00020000 /* mimo ps mode is enabled */ -#define WL_STA_MIMO_RTS 0x00040000 /* send rts in mimo ps mode */ -#define WL_STA_RIFS_CAP 0x00080000 /* rifs enabled */ -#define WL_STA_VHT_CAP 0x00100000 /* STA VHT(11ac) capable */ -#define WL_STA_WPS 0x00200000 /* WPS state */ - -#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ - -/* STA HT cap fields */ -#define WL_STA_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ -#define WL_STA_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ -#define WL_STA_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ -#define WL_STA_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ -#define WL_STA_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ -#define WL_STA_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ -#define WL_STA_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ -#define WL_STA_CAP_GF 0x0010 /* Greenfield preamble support */ -#define WL_STA_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ -#define WL_STA_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ -#define WL_STA_CAP_TX_STBC 0x0080 /* Tx STBC support */ -#define WL_STA_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ -#define WL_STA_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ -#define WL_STA_CAP_DELAYED_BA 0x0400 /* delayed BA support */ -#define WL_STA_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ -#define WL_STA_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ -#define WL_STA_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ -#define WL_STA_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ -#define WL_STA_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ - -#define WL_STA_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ -#define WL_STA_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ -#define WL_STA_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ -#define WL_STA_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ - -/* scb vht flags */ -#define WL_STA_VHT_LDPCCAP 0x0001 -#define WL_STA_SGI80 0x0002 -#define WL_STA_SGI160 0x0004 -#define WL_STA_VHT_TX_STBCCAP 0x0008 -#define WL_STA_VHT_RX_STBCCAP 0x0010 -#define WL_STA_SU_BEAMFORMER 0x0020 -#define WL_STA_SU_BEAMFORMEE 0x0040 -#define WL_STA_MU_BEAMFORMER 0x0080 -#define WL_STA_MU_BEAMFORMEE 0x0100 -#define WL_STA_VHT_TXOP_PS 0x0200 -#define WL_STA_HTC_VHT_CAP 0x0400 - -/* Values for TX Filter override mode */ -#define WLC_TXFILTER_OVERRIDE_DISABLED 0 -#define WLC_TXFILTER_OVERRIDE_ENABLED 1 - -#define WL_IOCTL_ACTION_GET 0x0 -#define WL_IOCTL_ACTION_SET 0x1 -#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e -#define WL_IOCTL_ACTION_OVL_RSV 0x20 -#define WL_IOCTL_ACTION_OVL 0x40 -#define WL_IOCTL_ACTION_MASK 0x7e -#define WL_IOCTL_ACTION_OVL_SHIFT 1 - -#define WL_BSSTYPE_INFRA 1 -#define WL_BSSTYPE_INDEP 0 -#define WL_BSSTYPE_ANY 2 - -/* Bitmask for scan_type */ -#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ -#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ -#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ -#define WL_SCANFLAGS_OFFCHAN 0x08 /* allow scanning/reporting off-channel APs */ -#define WL_SCANFLAGS_HOTSPOT 0x10 /* automatic ANQP to hotspot APs */ - -/* wl_iscan_results status values */ -#define WL_SCAN_RESULTS_SUCCESS 0 -#define WL_SCAN_RESULTS_PARTIAL 1 -#define WL_SCAN_RESULTS_PENDING 2 -#define WL_SCAN_RESULTS_ABORTED 3 -#define WL_SCAN_RESULTS_NO_MEM 4 - -#define SCANOL_ENABLED (1 << 0) -#define SCANOL_BCAST_SSID (1 << 1) -#define SCANOL_NOTIFY_BCAST_SSID (1 << 2) -#define SCANOL_RESULTS_PER_CYCLE (1 << 3) - -/* scan times in milliseconds */ -#define SCANOL_HOME_TIME 45 /* for home channel processing */ -#define SCANOL_ASSOC_TIME 20 /* dwell on a channel while associated */ -#define SCANOL_UNASSOC_TIME 40 /* dwell on a channel while unassociated */ -#define SCANOL_PASSIVE_TIME 110 /* listen on a channelfor passive scan */ -#define SCANOL_AWAY_LIMIT 100 /* max time to be away from home channel */ -#define SCANOL_IDLE_REST_TIME 40 -#define SCANOL_IDLE_REST_MULTIPLIER 0 -#define SCANOL_ACTIVE_REST_TIME 20 -#define SCANOL_ACTIVE_REST_MULTIPLIER 0 -#define SCANOL_CYCLE_IDLE_REST_TIME 300000 /* Idle Rest Time between Scan Cycle (msec) */ -#define SCANOL_CYCLE_IDLE_REST_MULTIPLIER 0 /* Idle Rest Time Multiplier */ -#define SCANOL_CYCLE_ACTIVE_REST_TIME 200 -#define SCANOL_CYCLE_ACTIVE_REST_MULTIPLIER 0 -#define SCANOL_MAX_REST_TIME 3600000 /* max rest time between scan cycle (msec) */ -#define SCANOL_CYCLE_DEFAULT 0 /* default for Max Scan Cycle, 0 = forever */ -#define SCANOL_CYCLE_MAX 864000 /* Max Scan Cycle */ - /* 10 sec/scan cycle => 100 days */ -#define SCANOL_NPROBES 2 /* for Active scan; send n probes on each channel */ -#define SCANOL_NPROBES_MAX 5 /* for Active scan; send n probes on each channel */ -#define SCANOL_SCAN_START_DLY 10 /* delay start of offload scan (sec) */ -#define SCANOL_SCAN_START_DLY_MAX 240 /* delay start of offload scan (sec) */ -#define SCANOL_MULTIPLIER_MAX 10 /* Max Multiplier */ -#define SCANOL_UNASSOC_TIME_MAX 100 /* max dwell on a channel while unassociated */ -#define SCANOL_PASSIVE_TIME_MAX 500 /* max listen on a channel for passive scan */ -#define SCANOL_SSID_MAX 16 /* max supported preferred SSID */ - -/* masks for channel and ssid count */ -#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff -#define WL_SCAN_PARAMS_NSSID_SHIFT 16 - -#define WL_SCAN_ACTION_START 1 -#define WL_SCAN_ACTION_CONTINUE 2 -#define WL_SCAN_ACTION_ABORT 3 - - -#define ANTENNA_NUM_1 1 /* total number of antennas to be used */ -#define ANTENNA_NUM_2 2 -#define ANTENNA_NUM_3 3 -#define ANTENNA_NUM_4 4 - -#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 */ - -/* interference source detection and identification mode */ -#define ITFR_MODE_DISABLE 0 /* disable feature */ -#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */ -#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */ - -/* bit definitions for flags in interference source report */ -#define ITFR_INTERFERENCED 1 /* interference detected */ -#define ITFR_HOME_CHANNEL 2 /* home channel has interference */ -#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */ - -#define WL_NUM_RPI_BINS 8 -#define WL_RM_TYPE_BASIC 1 -#define WL_RM_TYPE_CCA 2 -#define WL_RM_TYPE_RPI 3 - -#define WL_RM_FLAG_PARALLEL (1<<0) - -#define WL_RM_FLAG_LATE (1<<1) -#define WL_RM_FLAG_INCAPABLE (1<<2) -#define WL_RM_FLAG_REFUSED (1<<3) - -/* flags */ -#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ - -#define WLC_CIS_DEFAULT 0 /* built-in default */ -#define WLC_CIS_SROM 1 /* source is sprom */ -#define WLC_CIS_OTP 2 /* source is otp */ - -/* PCL - Power Control Loop */ -/* current gain setting is replaced by user input */ -#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ -#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ -/* current gain setting is maintained */ -#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ - -#define PLC_CMD_FAILOVER 1 -#define PLC_CMD_MAC_COST 2 -#define PLC_CMD_LINK_COST 3 -#define PLC_CMD_NODE_LIST 4 - -#define NODE_TYPE_UNKNOWN 0 /* Unknown link */ -#define NODE_TYPE_WIFI_ONLY 1 /* Pure Wireless STA node */ -#define NODE_TYPE_PLC_ONLY 2 /* Pure PLC only node */ -#define NODE_TYPE_WIFI_PLC 3 /* WiFi PLC capable node */ - -/* defines used by poweridx iovar - it controls power in a-band */ -/* current gain setting is maintained */ -#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ -#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ -#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ -#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ -/* value >= 0 causes - * - input to be set to that value - * - PCL to be off - */ - -#define BCM_MAC_STATUS_INDICATION (0x40010200L) - -/* Values for TX Filter override mode */ -#define WLC_TXFILTER_OVERRIDE_DISABLED 0 -#define WLC_TXFILTER_OVERRIDE_ENABLED 1 - -/* magic pattern used for mismatch driver and wl */ -#define WL_TXFIFO_SZ_MAGIC 0xa5a5 - -/* check this magic number */ -#define WLC_IOCTL_MAGIC 0x14e46c77 - -/* bss_info_cap_t flags */ -#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */ -#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */ -#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info received on channel (vs offchannel) */ -#define WL_BSS_FLAGS_HS20 0x08 /* hotspot 2.0 capable */ -#define WL_BSS_FLAGS_RSSI_INVALID 0x10 /* BSS contains invalid RSSI */ -#define WL_BSS_FLAGS_RSSI_INACCURATE 0x20 /* BSS contains inaccurate RSSI */ - -/* bssinfo flag for nbss_cap */ -#define VHT_BI_SGI_80MHZ 0x00000100 -#define VHT_BI_80MHZ 0x00000200 -#define VHT_BI_160MHZ 0x00000400 -#define VHT_BI_8080MHZ 0x00000800 - -/* reference to wl_ioctl_t struct used by usermode driver */ -#define ioctl_subtype set /* subtype param */ -#define ioctl_pid used /* pid param */ -#define ioctl_status needed /* status param */ - - -/* 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_OCB_MSDU 5 -#define CRYPTO_ALGO_AES_OCB_MPDU 6 -#if !defined(BCMCCX) && !defined(BCMEXTCCX) -#define CRYPTO_ALGO_NALG 7 -#else -#define CRYPTO_ALGO_CKIP 7 -#define CRYPTO_ALGO_CKIP_MMH 8 -#define CRYPTO_ALGO_WEP_MMH 9 -#define CRYPTO_ALGO_NALG 10 -#endif /* !BCMCCX && !BCMEXTCCX */ - -#define CRYPTO_ALGO_SMS4 11 -#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ -#define CRYPTO_ALGO_BIP 13 /* 802.11w BIP (aes cmac) */ - -#define CRYPTO_ALGO_AES_GCM 14 /* 128 bit GCM */ -#define CRYPTO_ALGO_AES_CCM256 15 /* 256 bit CCM */ -#define CRYPTO_ALGO_AES_GCM256 16 /* 256 bit GCM */ -#define CRYPTO_ALGO_BIP_CMAC256 17 /* 256 bit BIP CMAC */ -#define CRYPTO_ALGO_BIP_GMAC 18 /* 128 bit BIP GMAC */ -#define CRYPTO_ALGO_BIP_GMAC256 19 /* 256 bit BIP GMAC */ - -#define CRYPTO_ALGO_NONE CRYPTO_ALGO_OFF - -#define WSEC_GEN_MIC_ERROR 0x0001 -#define WSEC_GEN_REPLAY 0x0002 -#define WSEC_GEN_ICV_ERROR 0x0004 -#define WSEC_GEN_MFP_ACT_ERROR 0x0008 -#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 -#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 - -#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ -#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ -#if defined(BCMCCX) || defined(BCMEXTCCX) -#define WL_CKIP_KP (1 << 4) /* CMIC */ -#define WL_CKIP_MMH (1 << 5) /* CKIP */ -#else -#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ -#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ -#endif /* BCMCCX || BCMEXTCCX */ -#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ - -/* wireless security bitvec */ -#define WEP_ENABLED 0x0001 -#define TKIP_ENABLED 0x0002 -#define AES_ENABLED 0x0004 -#define WSEC_SWFLAG 0x0008 -#ifdef BCMCCX -#define CKIP_KP_ENABLED 0x0010 -#define CKIP_MIC_ENABLED 0x0020 -#endif /* BCMCCX */ -#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */ -#ifdef BCMWAPI_WPI -#define SMS4_ENABLED 0x0100 -#endif /* BCMWAPI_WPI */ - -/* wsec macros for operating on the above definitions */ -#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) -#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) -#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) - -#ifdef BCMCCX -#define WSEC_CKIP_KP_ENABLED(wsec) ((wsec) & CKIP_KP_ENABLED) -#define WSEC_CKIP_MIC_ENABLED(wsec) ((wsec) & CKIP_MIC_ENABLED) -#define WSEC_CKIP_ENABLED(wsec) ((wsec) & (CKIP_KP_ENABLED|CKIP_MIC_ENABLED)) - -#ifdef BCMWAPI_WPI -#define WSEC_ENABLED(wsec) \ - ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | \ - CKIP_MIC_ENABLED | SMS4_ENABLED)) -#else /* BCMWAPI_WPI */ -#define WSEC_ENABLED(wsec) \ - ((wsec) & \ - (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | CKIP_MIC_ENABLED)) -#endif /* BCMWAPI_WPI */ -#else /* defined BCMCCX */ -#ifdef BCMWAPI_WPI -#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) -#else /* BCMWAPI_WPI */ -#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) -#endif /* BCMWAPI_WPI */ -#endif /* BCMCCX */ -#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) -#ifdef BCMWAPI_WAI -#define WSEC_SMS4_ENABLED(wsec) ((wsec) & SMS4_ENABLED) -#endif /* BCMWAPI_WAI */ - -#define MFP_CAPABLE 0x0200 -#define MFP_REQUIRED 0x0400 -#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ - -/* 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 */ -#if defined(BCMCCX) || defined(BCMEXTCCX) -#define WPA_AUTH_CCKM 0x0008 /* CCKM */ -#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ -#endif /* BCMCCX || BCMEXTCCX */ -/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ -#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ -#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ -#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */ -#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */ -#if defined(BCMWAPI_WAI) || defined(BCMWAPI_WPI) -#define WPA_AUTH_WAPI 0x0400 -#define WAPI_AUTH_NONE WPA_AUTH_NONE /* none (IBSS) */ -#define WAPI_AUTH_UNSPECIFIED 0x0400 /* over AS */ -#define WAPI_AUTH_PSK 0x0800 /* Pre-shared key */ -#endif /* BCMWAPI_WAI || BCMWAPI_WPI */ -#define WPA2_AUTH_MFP 0x1000 /* MFP (11w) in contrast to CCX */ -#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */ -#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */ -#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ - -/* pmkid */ -#define MAXPMKID 16 - -#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ -#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ -#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ -#if defined(LCNCONF) || defined(LCN40CONF) -#define WLC_SAMPLECOLLECT_MAXLEN 8192 /* Max Sample Collect buffer */ -#else -#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ -#endif -#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192 - -/* common ioctl definitions */ -#define WLC_GET_MAGIC 0 -#define WLC_GET_VERSION 1 -#define WLC_UP 2 -#define WLC_DOWN 3 -#define WLC_GET_LOOP 4 -#define WLC_SET_LOOP 5 -#define WLC_DUMP 6 -#define WLC_GET_MSGLEVEL 7 -#define WLC_SET_MSGLEVEL 8 -#define WLC_GET_PROMISC 9 -#define WLC_SET_PROMISC 10 -/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */ -#define WLC_GET_RATE 12 -#define WLC_GET_MAX_RATE 13 -#define WLC_GET_INSTANCE 14 -/* #define WLC_GET_FRAG 15 */ /* no longer supported */ -/* #define WLC_SET_FRAG 16 */ /* no longer supported */ -/* #define WLC_GET_RTS 17 */ /* no longer supported */ -/* #define WLC_SET_RTS 18 */ /* no longer supported */ -#define WLC_GET_INFRA 19 -#define WLC_SET_INFRA 20 -#define WLC_GET_AUTH 21 -#define WLC_SET_AUTH 22 -#define WLC_GET_BSSID 23 -#define WLC_SET_BSSID 24 -#define WLC_GET_SSID 25 -#define WLC_SET_SSID 26 -#define WLC_RESTART 27 -#define WLC_TERMINATED 28 -/* #define WLC_DUMP_SCB 28 */ /* no longer supported */ -#define WLC_GET_CHANNEL 29 -#define WLC_SET_CHANNEL 30 -#define WLC_GET_SRL 31 -#define WLC_SET_SRL 32 -#define WLC_GET_LRL 33 -#define WLC_SET_LRL 34 -#define WLC_GET_PLCPHDR 35 -#define WLC_SET_PLCPHDR 36 -#define WLC_GET_RADIO 37 -#define WLC_SET_RADIO 38 -#define WLC_GET_PHYTYPE 39 -#define WLC_DUMP_RATE 40 -#define WLC_SET_RATE_PARAMS 41 -#define WLC_GET_FIXRATE 42 -#define WLC_SET_FIXRATE 43 -/* #define WLC_GET_WEP 42 */ /* no longer supported */ -/* #define WLC_SET_WEP 43 */ /* no longer supported */ -#define WLC_GET_KEY 44 -#define WLC_SET_KEY 45 -#define WLC_GET_REGULATORY 46 -#define WLC_SET_REGULATORY 47 -#define WLC_GET_PASSIVE_SCAN 48 -#define WLC_SET_PASSIVE_SCAN 49 -#define WLC_SCAN 50 -#define WLC_SCAN_RESULTS 51 -#define WLC_DISASSOC 52 -#define WLC_REASSOC 53 -#define WLC_GET_ROAM_TRIGGER 54 -#define WLC_SET_ROAM_TRIGGER 55 -#define WLC_GET_ROAM_DELTA 56 -#define WLC_SET_ROAM_DELTA 57 -#define WLC_GET_ROAM_SCAN_PERIOD 58 -#define WLC_SET_ROAM_SCAN_PERIOD 59 -#define WLC_EVM 60 /* diag */ -#define WLC_GET_TXANT 61 -#define WLC_SET_TXANT 62 -#define WLC_GET_ANTDIV 63 -#define WLC_SET_ANTDIV 64 -/* #define WLC_GET_TXPWR 65 */ /* no longer supported */ -/* #define WLC_SET_TXPWR 66 */ /* no longer supported */ -#define WLC_GET_CLOSED 67 -#define WLC_SET_CLOSED 68 -#define WLC_GET_MACLIST 69 -#define WLC_SET_MACLIST 70 -#define WLC_GET_RATESET 71 -#define WLC_SET_RATESET 72 -/* #define WLC_GET_LOCALE 73 */ /* no longer supported */ -#define WLC_LONGTRAIN 74 -#define WLC_GET_BCNPRD 75 -#define WLC_SET_BCNPRD 76 -#define WLC_GET_DTIMPRD 77 -#define WLC_SET_DTIMPRD 78 -#define WLC_GET_SROM 79 -#define WLC_SET_SROM 80 -#define WLC_GET_WEP_RESTRICT 81 -#define WLC_SET_WEP_RESTRICT 82 -#define WLC_GET_COUNTRY 83 -#define WLC_SET_COUNTRY 84 -#define WLC_GET_PM 85 -#define WLC_SET_PM 86 -#define WLC_GET_WAKE 87 -#define WLC_SET_WAKE 88 -/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */ -#define WLC_GET_FORCELINK 90 /* ndis only */ -#define WLC_SET_FORCELINK 91 /* ndis only */ -#define WLC_FREQ_ACCURACY 92 /* diag */ -#define WLC_CARRIER_SUPPRESS 93 /* diag */ -#define WLC_GET_PHYREG 94 -#define WLC_SET_PHYREG 95 -#define WLC_GET_RADIOREG 96 -#define WLC_SET_RADIOREG 97 -#define WLC_GET_REVINFO 98 -#define WLC_GET_UCANTDIV 99 -#define WLC_SET_UCANTDIV 100 -#define WLC_R_REG 101 -#define WLC_W_REG 102 -/* #define WLC_DIAG_LOOPBACK 103 old tray diag */ -/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */ -#define WLC_GET_MACMODE 105 -#define WLC_SET_MACMODE 106 -#define WLC_GET_MONITOR 107 -#define WLC_SET_MONITOR 108 -#define WLC_GET_GMODE 109 -#define WLC_SET_GMODE 110 -#define WLC_GET_LEGACY_ERP 111 -#define WLC_SET_LEGACY_ERP 112 -#define WLC_GET_RX_ANT 113 -#define WLC_GET_CURR_RATESET 114 /* current rateset */ -#define WLC_GET_SCANSUPPRESS 115 -#define WLC_SET_SCANSUPPRESS 116 -#define WLC_GET_AP 117 -#define WLC_SET_AP 118 -#define WLC_GET_EAP_RESTRICT 119 -#define WLC_SET_EAP_RESTRICT 120 -#define WLC_SCB_AUTHORIZE 121 -#define WLC_SCB_DEAUTHORIZE 122 -#define WLC_GET_WDSLIST 123 -#define WLC_SET_WDSLIST 124 -#define WLC_GET_ATIM 125 -#define WLC_SET_ATIM 126 -#define WLC_GET_RSSI 127 -#define WLC_GET_PHYANTDIV 128 -#define WLC_SET_PHYANTDIV 129 -#define WLC_AP_RX_ONLY 130 -#define WLC_GET_TX_PATH_PWR 131 -#define WLC_SET_TX_PATH_PWR 132 -#define WLC_GET_WSEC 133 -#define WLC_SET_WSEC 134 -#define WLC_GET_PHY_NOISE 135 -#define WLC_GET_BSS_INFO 136 -#define WLC_GET_PKTCNTS 137 -#define WLC_GET_LAZYWDS 138 -#define WLC_SET_LAZYWDS 139 -#define WLC_GET_BANDLIST 140 - -#define WLC_GET_BAND 141 -#define WLC_SET_BAND 142 -#define WLC_SCB_DEAUTHENTICATE 143 -#define WLC_GET_SHORTSLOT 144 -#define WLC_GET_SHORTSLOT_OVERRIDE 145 -#define WLC_SET_SHORTSLOT_OVERRIDE 146 -#define WLC_GET_SHORTSLOT_RESTRICT 147 -#define WLC_SET_SHORTSLOT_RESTRICT 148 -#define WLC_GET_GMODE_PROTECTION 149 -#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 -#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 -#define WLC_UPGRADE 152 -/* #define WLC_GET_MRATE 153 */ /* no longer supported */ -/* #define WLC_SET_MRATE 154 */ /* no longer supported */ -#define WLC_GET_IGNORE_BCNS 155 -#define WLC_SET_IGNORE_BCNS 156 -#define WLC_GET_SCB_TIMEOUT 157 -#define WLC_SET_SCB_TIMEOUT 158 -#define WLC_GET_ASSOCLIST 159 -#define WLC_GET_CLK 160 -#define WLC_SET_CLK 161 -#define WLC_GET_UP 162 -#define WLC_OUT 163 -#define WLC_GET_WPA_AUTH 164 -#define WLC_SET_WPA_AUTH 165 -#define WLC_GET_UCFLAGS 166 -#define WLC_SET_UCFLAGS 167 -#define WLC_GET_PWRIDX 168 -#define WLC_SET_PWRIDX 169 -#define WLC_GET_TSSI 170 -#define WLC_GET_SUP_RATESET_OVERRIDE 171 -#define WLC_SET_SUP_RATESET_OVERRIDE 172 -/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */ -/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */ -/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */ -/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */ -/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */ -#define WLC_GET_PROTECTION_CONTROL 178 -#define WLC_SET_PROTECTION_CONTROL 179 -#define WLC_GET_PHYLIST 180 -#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */ -#define WLC_DECRYPT_STATUS 182 /* ndis only */ -#define WLC_GET_KEY_SEQ 183 -#define WLC_GET_SCAN_CHANNEL_TIME 184 -#define WLC_SET_SCAN_CHANNEL_TIME 185 -#define WLC_GET_SCAN_UNASSOC_TIME 186 -#define WLC_SET_SCAN_UNASSOC_TIME 187 -#define WLC_GET_SCAN_HOME_TIME 188 -#define WLC_SET_SCAN_HOME_TIME 189 -#define WLC_GET_SCAN_NPROBES 190 -#define WLC_SET_SCAN_NPROBES 191 -#define WLC_GET_PRB_RESP_TIMEOUT 192 -#define WLC_SET_PRB_RESP_TIMEOUT 193 -#define WLC_GET_ATTEN 194 -#define WLC_SET_ATTEN 195 -#define WLC_GET_SHMEM 196 /* diag */ -#define WLC_SET_SHMEM 197 /* diag */ -/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */ -/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */ -#define WLC_SET_WSEC_TEST 200 -#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 -#define WLC_TKIP_COUNTERMEASURES 202 -#define WLC_GET_PIOMODE 203 -#define WLC_SET_PIOMODE 204 -#define WLC_SET_ASSOC_PREFER 205 -#define WLC_GET_ASSOC_PREFER 206 -#define WLC_SET_ROAM_PREFER 207 -#define WLC_GET_ROAM_PREFER 208 -#define WLC_SET_LED 209 -#define WLC_GET_LED 210 -#define WLC_GET_INTERFERENCE_MODE 211 -#define WLC_SET_INTERFERENCE_MODE 212 -#define WLC_GET_CHANNEL_QA 213 -#define WLC_START_CHANNEL_QA 214 -#define WLC_GET_CHANNEL_SEL 215 -#define WLC_START_CHANNEL_SEL 216 -#define WLC_GET_VALID_CHANNELS 217 -#define WLC_GET_FAKEFRAG 218 -#define WLC_SET_FAKEFRAG 219 -#define WLC_GET_PWROUT_PERCENTAGE 220 -#define WLC_SET_PWROUT_PERCENTAGE 221 -#define WLC_SET_BAD_FRAME_PREEMPT 222 -#define WLC_GET_BAD_FRAME_PREEMPT 223 -#define WLC_SET_LEAP_LIST 224 -#define WLC_GET_LEAP_LIST 225 -#define WLC_GET_CWMIN 226 -#define WLC_SET_CWMIN 227 -#define WLC_GET_CWMAX 228 -#define WLC_SET_CWMAX 229 -#define WLC_GET_WET 230 -#define WLC_SET_WET 231 -#define WLC_GET_PUB 232 -/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */ -/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */ -#define WLC_GET_KEY_PRIMARY 235 -#define WLC_SET_KEY_PRIMARY 236 - - -/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */ -#define WLC_GET_ACI_ARGS 238 -#define WLC_SET_ACI_ARGS 239 -#define WLC_UNSET_CALLBACK 240 -#define WLC_SET_CALLBACK 241 -#define WLC_GET_RADAR 242 -#define WLC_SET_RADAR 243 -#define WLC_SET_SPECT_MANAGMENT 244 -#define WLC_GET_SPECT_MANAGMENT 245 -#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ -#define WLC_WDS_GET_WPA_SUP 247 -#define WLC_SET_CS_SCAN_TIMER 248 -#define WLC_GET_CS_SCAN_TIMER 249 -#define WLC_MEASURE_REQUEST 250 -#define WLC_INIT 251 -#define WLC_SEND_QUIET 252 -#define WLC_KEEPALIVE 253 -#define WLC_SEND_PWR_CONSTRAINT 254 -#define WLC_UPGRADE_STATUS 255 -#define WLC_CURRENT_PWR 256 -#define WLC_GET_SCAN_PASSIVE_TIME 257 -#define WLC_SET_SCAN_PASSIVE_TIME 258 -#define WLC_LEGACY_LINK_BEHAVIOR 259 -#define WLC_GET_CHANNELS_IN_COUNTRY 260 -#define WLC_GET_COUNTRY_LIST 261 -#define WLC_GET_VAR 262 /* get value of named variable */ -#define WLC_SET_VAR 263 /* set named variable to value */ -#define WLC_NVRAM_GET 264 /* deprecated */ -#define WLC_NVRAM_SET 265 -#define WLC_NVRAM_DUMP 266 -#define WLC_REBOOT 267 -#define WLC_SET_WSEC_PMK 268 -#define WLC_GET_AUTH_MODE 269 -#define WLC_SET_AUTH_MODE 270 -#define WLC_GET_WAKEENTRY 271 -#define WLC_SET_WAKEENTRY 272 -#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ -#define WLC_NVOTPW 274 -#define WLC_OTPW 275 -#define WLC_IOV_BLOCK_GET 276 -#define WLC_IOV_MODULES_GET 277 -#define WLC_SOFT_RESET 278 -#define WLC_GET_ALLOW_MODE 279 -#define WLC_SET_ALLOW_MODE 280 -#define WLC_GET_DESIRED_BSSID 281 -#define WLC_SET_DESIRED_BSSID 282 -#define WLC_DISASSOC_MYAP 283 -#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */ -#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */ -#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */ -#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */ -#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */ -#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */ -#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */ -#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */ -#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */ -#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */ -#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */ -#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */ -#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */ -#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */ -#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */ -#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */ -#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */ -#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */ -#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */ -#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */ -#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */ -#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */ -#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */ -#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */ -/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */ -#define WLC_GET_CMD 309 -/* #define WLC_LAST 310 */ /* Never used - can be reused */ -#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */ -#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */ -/* #define WLC_GET_WAI_RESTRICT 313 */ /* for WAPI, deprecated use iovar instead */ -/* #define WLC_SET_WAI_RESTRICT 314 */ /* for WAPI, deprecated use iovar instead */ -/* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */ -#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ -#define WLC_GET_NAT_STATE 317 -#define WLC_GET_TXBF_RATESET 318 -#define WLC_SET_TXBF_RATESET 319 -#define WLC_SCAN_CQ 320 -#define WLC_GET_RSSI_QDB 321 /* qdB portion of the RSSI */ - -#define WLC_LAST 322 -#ifndef EPICTRL_COOKIE -#define EPICTRL_COOKIE 0xABADCEDE -#endif - -/* vx wlc ioctl's offset */ -#define CMN_IOCTL_OFF 0x180 - -/* - * custom OID support - * - * 0xFF - implementation specific OID - * 0xE4 - first byte of Broadcom PCI vendor ID - * 0x14 - second byte of Broadcom PCI vendor ID - * 0xXX - the custom OID number - */ - -/* begin 0x1f values beyond the start of the ET driver range. */ -#define WL_OID_BASE 0xFFE41420 - -/* NDIS overrides */ -#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) -#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) -#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) -#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) -#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) -#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) -#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) - -/* EXT_STA Dongle suuport */ -#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) -#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) -#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) -#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) -#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) -#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) -#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) -#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) -#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) -#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) -#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) -#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) -#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) -#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) -#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) - -/* NAT filter driver support */ -#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG) -#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE) - -#define WL_DECRYPT_STATUS_SUCCESS 1 -#define WL_DECRYPT_STATUS_FAILURE 2 -#define WL_DECRYPT_STATUS_UNKNOWN 3 - -/* allows user-mode app to poll the status of USB image upgrade */ -#define WLC_UPGRADE_SUCCESS 0 -#define WLC_UPGRADE_PENDING 1 - -/* WLC_GET_AUTH, WLC_SET_AUTH values */ -#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ -#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ -#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ - -/* a large TX Power as an init value to factor out of MIN() calculations, - * keep low enough to fit in an int8, units are .25 dBm - */ -#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ - -/* "diag" iovar argument and error code */ -#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */ -#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */ -#define WL_DIAG_MEMORY 3 /* d11 memory test */ -#define WL_DIAG_LED 4 /* LED test */ -#define WL_DIAG_REG 5 /* d11/phy register test */ -#define WL_DIAG_SROM 6 /* srom read/crc test */ -#define WL_DIAG_DMA 7 /* DMA test */ -#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */ - -#define WL_DIAGERR_SUCCESS 0 -#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */ -#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */ -#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */ -#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */ -#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */ -#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */ -#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */ -#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */ -#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */ -#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */ - -#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */ -#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */ - -/* band types */ -#define WLC_BAND_AUTO 0 /* auto-select */ -#define WLC_BAND_5G 1 /* 5 Ghz */ -#define WLC_BAND_2G 2 /* 2.4 Ghz */ -#define WLC_BAND_ALL 3 /* all bands */ - -/* band range returned by band_range iovar */ -#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 - -#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4 -#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5 -#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6 -#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7 -#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8 - -#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 -#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 -#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 -#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 - -#define WL_CHAN_FREQ_RANGE_5G_4BAND 5 - -/* MAC list modes */ -#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */ -#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */ -#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */ - -/* - * 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 - -/* values for PLCPHdr_override */ -#define WLC_PLCP_AUTO -1 -#define WLC_PLCP_SHORT 0 -#define WLC_PLCP_LONG 1 - -/* values for g_protection_override and n_protection_override */ -#define WLC_PROTECTION_AUTO -1 -#define WLC_PROTECTION_OFF 0 -#define WLC_PROTECTION_ON 1 -#define WLC_PROTECTION_MMHDR_ONLY 2 -#define WLC_PROTECTION_CTS_ONLY 3 - -/* values for g_protection_control and n_protection_control */ -#define WLC_PROTECTION_CTL_OFF 0 -#define WLC_PROTECTION_CTL_LOCAL 1 -#define WLC_PROTECTION_CTL_OVERLAP 2 - -/* values for n_protection */ -#define WLC_N_PROTECTION_OFF 0 -#define WLC_N_PROTECTION_OPTIONAL 1 -#define WLC_N_PROTECTION_20IN40 2 -#define WLC_N_PROTECTION_MIXEDMODE 3 - -/* values for n_preamble_type */ -#define WLC_N_PREAMBLE_MIXEDMODE 0 -#define WLC_N_PREAMBLE_GF 1 -#define WLC_N_PREAMBLE_GF_BRCM 2 - -/* values for band specific 40MHz capabilities (deprecated) */ -#define WLC_N_BW_20ALL 0 -#define WLC_N_BW_40ALL 1 -#define WLC_N_BW_20IN2G_40IN5G 2 - -#define WLC_BW_20MHZ_BIT (1<<0) -#define WLC_BW_40MHZ_BIT (1<<1) -#define WLC_BW_80MHZ_BIT (1<<2) -#define WLC_BW_160MHZ_BIT (1<<3) - -/* Bandwidth capabilities */ -#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) -#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) -#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) -#define WLC_BW_CAP_160MHZ (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ - WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) -#define WLC_BW_CAP_UNRESTRICTED 0xFF - -#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) -#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) -#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) -#define WL_BW_CAP_160MHZ(bw_cap)(((bw_cap) & WLC_BW_160MHZ_BIT) ? TRUE : FALSE) - -/* values to force tx/rx chain */ -#define WLC_N_TXRX_CHAIN0 0 -#define WLC_N_TXRX_CHAIN1 1 - -/* bitflags for SGI support (sgi_rx iovar) */ -#define WLC_N_SGI_20 0x01 -#define WLC_N_SGI_40 0x02 -#define WLC_VHT_SGI_80 0x04 - -/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ -#define WLC_SGI_ALL 0x02 - -#define LISTEN_INTERVAL 10 -/* interference mitigation options */ -#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ -#define INTERFERE_NONE 0 /* off */ -#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */ -#define WLAN_MANUAL 2 /* ACI: no auto detection */ -#define WLAN_AUTO 3 /* ACI: auto detect */ -#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ -#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ - -/* interfernece mode bit-masks (ACPHY) */ -#define ACPHY_ACI_GLITCHBASED_DESENSE 1 /* bit 0 */ -#define ACPHY_ACI_HWACI_PKTGAINLMT 2 /* bit 1 */ -#define ACPHY_ACI_W2NB_PKTGAINLMT 4 /* bit 2 */ -#define ACPHY_ACI_PREEMPTION 8 /* bit 3 */ -#define ACPHY_ACI_MAX_MODE 15 - -/* AP environment */ -#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ -#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ -#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ -#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ - -#define TRIGGER_NOW 0 -#define TRIGGER_CRS 0x01 -#define TRIGGER_CRSDEASSERT 0x02 -#define TRIGGER_GOODFCS 0x04 -#define TRIGGER_BADFCS 0x08 -#define TRIGGER_BADPLCP 0x10 -#define TRIGGER_CRSGLITCH 0x20 - -#define WL_SAMPLEDATA_HEADER_TYPE 1 -#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ -#define WL_SAMPLEDATA_TYPE 2 -#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ -#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ - -/* WL_OTA START */ -#define WL_OTA_ARG_PARSE_BLK_SIZE 1200 -#define WL_OTA_TEST_MAX_NUM_RATE 30 -#define WL_OTA_TEST_MAX_NUM_SEQ 100 - -#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */ - -/* radar iovar SET defines */ -#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */ -#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */ -#define WL_RADAR_SIMULATED 2 /* force radar detector to declare - * detection once - */ -#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */ -#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 */ - -#ifndef WL_RSSI_ANT_MAX -#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ -#elif WL_RSSI_ANT_MAX != 4 -#error "WL_RSSI_ANT_MAX does not match" -#endif - -/* dfs_status iovar-related defines */ - -/* cac - channel availability check, - * ism - in-service monitoring - * csa - channel switching announcement - */ - -/* cac state values */ -#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */ -#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */ -#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */ -#define WL_DFS_CACSTATE_CSA 3 /* csa */ -#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */ -#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */ -#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */ -#define WL_DFS_CACSTATES 7 /* this many states exist */ - -/* Defines used with channel_bandwidth for curpower */ -#define WL_BW_20MHZ 0 -#define WL_BW_40MHZ 1 -#define WL_BW_80MHZ 2 -#define WL_BW_160MHZ 3 - -/* tx_power_t.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 -#define WL_TX_POWER_F_HT 0x10 -#define WL_TX_POWER_F_VHT 0x20 -#define WL_TX_POWER_F_OPENLOOP 0x40 - -/* Message levels */ -#define WL_ERROR_VAL 0x00000001 -#define WL_TRACE_VAL 0x00000002 -#define WL_PRHDRS_VAL 0x00000004 -#define WL_PRPKT_VAL 0x00000008 -#define WL_INFORM_VAL 0x00000010 -#define WL_TMP_VAL 0x00000020 -#define WL_OID_VAL 0x00000040 -#define WL_RATE_VAL 0x00000080 -#define WL_ASSOC_VAL 0x00000100 -#define WL_PRUSR_VAL 0x00000200 -#define WL_PS_VAL 0x00000400 -#define WL_TXPWR_VAL 0x00000800 /* retired in TOT on 6/10/2009 */ -#define WL_PORT_VAL 0x00001000 -#define WL_DUAL_VAL 0x00002000 -#define WL_WSEC_VAL 0x00004000 -#define WL_WSEC_DUMP_VAL 0x00008000 -#define WL_LOG_VAL 0x00010000 -#define WL_NRSSI_VAL 0x00020000 /* retired in TOT on 6/10/2009 */ -#define WL_LOFT_VAL 0x00040000 /* retired in TOT on 6/10/2009 */ -#define WL_REGULATORY_VAL 0x00080000 -#define WL_PHYCAL_VAL 0x00100000 /* retired in TOT on 6/10/2009 */ -#define WL_RADAR_VAL 0x00200000 /* retired in TOT on 6/10/2009 */ -#define WL_MPC_VAL 0x00400000 -#define WL_APSTA_VAL 0x00800000 -#define WL_DFS_VAL 0x01000000 -#define WL_BA_VAL 0x02000000 /* retired in TOT on 6/14/2010 */ -#define WL_ACI_VAL 0x04000000 -#define WL_MBSS_VAL 0x04000000 -#define WL_CAC_VAL 0x08000000 -#define WL_AMSDU_VAL 0x10000000 -#define WL_AMPDU_VAL 0x20000000 -#define WL_FFPLD_VAL 0x40000000 - -/* wl_msg_level is full. For new bits take the next one and AND with - * wl_msg_level2 in wl_dbg.h - */ -#define WL_DPT_VAL 0x00000001 -#define WL_SCAN_VAL 0x00000002 -#define WL_WOWL_VAL 0x00000004 -#define WL_COEX_VAL 0x00000008 -#define WL_RTDC_VAL 0x00000010 -#define WL_PROTO_VAL 0x00000020 -#define WL_BTA_VAL 0x00000040 -#define WL_CHANINT_VAL 0x00000080 -#define WL_WMF_VAL 0x00000100 -#define WL_P2P_VAL 0x00000200 -#define WL_ITFR_VAL 0x00000400 -#define WL_MCHAN_VAL 0x00000800 -#define WL_TDLS_VAL 0x00001000 -#define WL_MCNX_VAL 0x00002000 -#define WL_PROT_VAL 0x00004000 -#define WL_PSTA_VAL 0x00008000 -#define WL_TSO_VAL 0x00010000 -#define WL_TRF_MGMT_VAL 0x00020000 -#define WL_LPC_VAL 0x00040000 -#define WL_L2FILTER_VAL 0x00080000 -#define WL_TXBF_VAL 0x00100000 -#define WL_P2PO_VAL 0x00200000 -#define WL_TBTT_VAL 0x00400000 -#define WL_NIC_VAL 0x00800000 -#define WL_MQ_VAL 0x01000000 - -/* This level is currently used in Phoenix2 only */ -#define WL_SRSCAN_VAL 0x02000000 - -#define WL_WNM_VAL 0x04000000 -#define WL_PWRSEL_VAL 0x10000000 -#define WL_NET_DETECT_VAL 0x20000000 -#define WL_PCIE_VAL 0x40000000 - -/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier - * rather than a message-type of its own - */ -#define WL_TIMESTAMP_VAL 0x80000000 - -/* max # of leds supported by GPIO (gpio pin# == led index#) */ -#define WL_LED_NUMGPIO 32 /* gpio 0-31 */ - -/* led per-pin behaviors */ -#define WL_LED_OFF 0 /* always off */ -#define WL_LED_ON 1 /* always on */ -#define WL_LED_ACTIVITY 2 /* activity */ -#define WL_LED_RADIO 3 /* radio enabled */ -#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */ -#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */ -#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */ -#define WL_LED_WI1 7 -#define WL_LED_WI2 8 -#define WL_LED_WI3 9 -#define WL_LED_ASSOC 10 /* associated state indicator */ -#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */ -#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */ -#define WL_LED_WI4 13 -#define WL_LED_WI5 14 -#define WL_LED_BLINKSLOW 15 /* blink slow */ -#define WL_LED_BLINKMED 16 /* blink med */ -#define WL_LED_BLINKFAST 17 /* blink fast */ -#define WL_LED_BLINKCUSTOM 18 /* blink custom */ -#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */ -#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ - /* keep on for 300 sec */ -#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ -#define WL_LED_WI6 22 -#define WL_LED_WI7 23 -#define WL_LED_WI8 24 -#define WL_LED_NUMBEHAVIOR 25 - -/* led behavior numeric value format */ -#define WL_LED_BEH_MASK 0x7f /* behavior mask */ -#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */ - -/* number of bytes needed to define a proper bit mask for MAC event reporting */ -#define BCMIO_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) -#define BCMIO_NBBY 8 -#define WL_EVENTING_MASK_LEN 16 - - -/* join preference types */ -#define WL_JOIN_PREF_RSSI 1 /* by RSSI */ -#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */ -#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */ -#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */ -#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */ - -/* band preference */ -#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */ - -/* any multicast cipher suite */ -#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" - -/* 802.11h measurement types */ -#define WLC_MEASURE_TPC 1 -#define WLC_MEASURE_CHANNEL_BASIC 2 -#define WLC_MEASURE_CHANNEL_CCA 3 -#define WLC_MEASURE_CHANNEL_RPI 4 - -/* regulatory enforcement levels */ -#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */ -#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */ -#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */ -#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */ -/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE - * adoption is done regardless of capability spectrum_management - */ -#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */ - -#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */ -#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */ -#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */ -#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */ -#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */ -#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */ -#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */ - -/* BTC mode used by "btc_mode" iovar */ -#define WL_BTC_DISABLE 0 /* disable BT coexistence */ -#define WL_BTC_FULLTDM 1 /* full TDM COEX */ -#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ -#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ -#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ -#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ -#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ -#define WL_BTC_DEFAULT 8 /* set the default mode for the device */ -#define WL_INF_BTC_DISABLE 0 -#define WL_INF_BTC_ENABLE 1 -#define WL_INF_BTC_AUTO 3 - -/* BTC wire used by "btc_wire" iovar */ -#define WL_BTC_DEFWIRE 0 /* use default wire setting */ -#define WL_BTC_2WIRE 2 /* use 2-wire BTC */ -#define WL_BTC_3WIRE 3 /* use 3-wire BTC */ -#define WL_BTC_4WIRE 4 /* use 4-wire BTC */ - -/* BTC flags: BTC configuration that can be set by host */ -#define WL_BTC_FLAG_PREMPT (1 << 0) -#define WL_BTC_FLAG_BT_DEF (1 << 1) -#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2) -#define WL_BTC_FLAG_SIM_RSP (1 << 3) -#define WL_BTC_FLAG_PS_PROTECT (1 << 4) -#define WL_BTC_FLAG_SIM_TX_LP (1 << 5) -#define WL_BTC_FLAG_ECI (1 << 6) -#define WL_BTC_FLAG_LIGHT (1 << 7) -#define WL_BTC_FLAG_PARALLEL (1 << 8) - -/* maximum channels returned by the get valid channels iovar */ -#define WL_NUMCHANNELS 64 - -/* max number of chanspecs (used by the iovar to calc. buf space) */ -#define WL_NUMCHANSPECS 110 - -/* WDS link local endpoint WPA role */ -#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */ -#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ -#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ - -/* Base offset values */ -#define WL_PKT_FILTER_BASE_PKT 0 -#define WL_PKT_FILTER_BASE_END 1 -#define WL_PKT_FILTER_BASE_D11_H 2 /* May be removed */ -#define WL_PKT_FILTER_BASE_D11_D 3 /* May be removed */ -#define WL_PKT_FILTER_BASE_ETH_H 4 -#define WL_PKT_FILTER_BASE_ETH_D 5 -#define WL_PKT_FILTER_BASE_ARP_H 6 -#define WL_PKT_FILTER_BASE_ARP_D 7 /* May be removed */ -#define WL_PKT_FILTER_BASE_IP4_H 8 -#define WL_PKT_FILTER_BASE_IP4_D 9 -#define WL_PKT_FILTER_BASE_IP6_H 10 -#define WL_PKT_FILTER_BASE_IP6_D 11 -#define WL_PKT_FILTER_BASE_TCP_H 12 -#define WL_PKT_FILTER_BASE_TCP_D 13 /* May be removed */ -#define WL_PKT_FILTER_BASE_UDP_H 14 -#define WL_PKT_FILTER_BASE_UDP_D 15 -#define WL_PKT_FILTER_BASE_IP6_P 16 -#define WL_PKT_FILTER_BASE_COUNT 17 /* May be removed */ - -/* String mapping for bases that may be used by applications or debug */ -#define WL_PKT_FILTER_BASE_NAMES \ - { "START", WL_PKT_FILTER_BASE_PKT }, \ - { "END", WL_PKT_FILTER_BASE_END }, \ - { "ETH_H", WL_PKT_FILTER_BASE_ETH_H }, \ - { "ETH_D", WL_PKT_FILTER_BASE_ETH_D }, \ - { "D11_H", WL_PKT_FILTER_BASE_D11_H }, \ - { "D11_D", WL_PKT_FILTER_BASE_D11_D }, \ - { "ARP_H", WL_PKT_FILTER_BASE_ARP_H }, \ - { "IP4_H", WL_PKT_FILTER_BASE_IP4_H }, \ - { "IP4_D", WL_PKT_FILTER_BASE_IP4_D }, \ - { "IP6_H", WL_PKT_FILTER_BASE_IP6_H }, \ - { "IP6_D", WL_PKT_FILTER_BASE_IP6_D }, \ - { "IP6_P", WL_PKT_FILTER_BASE_IP6_P }, \ - { "TCP_H", WL_PKT_FILTER_BASE_TCP_H }, \ - { "TCP_D", WL_PKT_FILTER_BASE_TCP_D }, \ - { "UDP_H", WL_PKT_FILTER_BASE_UDP_H }, \ - { "UDP_D", WL_PKT_FILTER_BASE_UDP_D } - -/* Flags for a pattern list element */ -#define WL_PKT_FILTER_MFLAG_NEG 0x0001 - -/* - * Packet engine interface - */ - -#define WL_PKTENG_PER_TX_START 0x01 -#define WL_PKTENG_PER_TX_STOP 0x02 -#define WL_PKTENG_PER_RX_START 0x04 -#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 -#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 -#define WL_PKTENG_PER_RX_STOP 0x08 -#define WL_PKTENG_PER_MASK 0xff - -#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ - -#define WL_PKTENG_MAXPKTSZ 16384 /* max pktsz limit for pkteng */ - -#define NUM_80211b_RATES 4 -#define NUM_80211ag_RATES 8 -#define NUM_80211n_RATES 32 -#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) - -/* - * WOWL capability/override settings - */ -#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */ -#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */ -#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */ -#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */ -#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */ -#define WL_WOWL_TST (1 << 5) /* Wakeup after test */ -#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */ -#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */ -#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */ -#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */ -#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */ -#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */ -#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */ -#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */ -#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */ -#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */ -#define WL_WOWL_SCANOL (1 << 16) /* If the bit is set, scan offload is enabled */ -#define WL_WOWL_TCPKEEP_TIME (1 << 17) /* Wakeup on tcpkeep alive timeout */ -#define WL_WOWL_MDNS_CONFLICT (1 << 18) /* Wakeup on mDNS Conflict Resolution */ -#define WL_WOWL_MDNS_SERVICE (1 << 19) /* Wakeup on mDNS Service Connect */ -#define WL_WOWL_TCPKEEP_DATA (1 << 20) /* tcp keepalive got data */ -#define WL_WOWL_FW_HALT (1 << 21) /* Firmware died in wowl mode */ -#define WL_WOWL_ENAB_HWRADIO (1 << 22) /* Enable detection of radio button changes */ -#define WL_WOWL_MIC_FAIL (1 << 23) /* Offloads detected MIC failure(s) */ -#define WL_WOWL_LINKDOWN (1 << 31) /* Link Down indication in WoWL mode */ - -#define WL_WOWL_TCPKEEP (1 << 20) /* temp copy to satisfy automerger */ -#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ - -#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ -#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ - -#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ -#define MAGIC_PKT_NUM_MAC_ADDRS 16 - - -/* Overlap BSS Scan parameters default, minimum, maximum */ -#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */ -#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */ -#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */ -#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */ -#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */ -#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */ -#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 -#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 -#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 -#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */ -#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */ -#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ -#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */ -#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */ -#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */ - -#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */ - -#define WL_COEX_INFO_MASK 0x07 -#define WL_COEX_INFO_REQ 0x01 -#define WL_COEX_40MHZ_INTOLERANT 0x02 -#define WL_COEX_WIDTH20 0x04 - -#define WLC_RSSI_INVALID 0 /* invalid RSSI value */ - -#define MAX_RSSI_LEVELS 8 - -/* **** EXTLOG **** */ -#define EXTLOG_CUR_VER 0x0100 - -#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ - -/* log modules (bitmap) */ -#define LOG_MODULE_COMMON 0x0001 -#define LOG_MODULE_ASSOC 0x0002 -#define LOG_MODULE_EVENT 0x0004 -#define LOG_MODULE_MAX 3 /* Update when adding module */ - -/* log levels */ -#define WL_LOG_LEVEL_DISABLE 0 -#define WL_LOG_LEVEL_ERR 1 -#define WL_LOG_LEVEL_WARN 2 -#define WL_LOG_LEVEL_INFO 3 -#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */ - -/* flag */ -#define LOG_FLAG_EVENT 1 - -/* log arg_type */ -#define LOG_ARGTYPE_NULL 0 -#define LOG_ARGTYPE_STR 1 /* %s */ -#define LOG_ARGTYPE_INT 2 /* %d */ -#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */ -#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */ - -/* 802.11 Mgmt Packet flags */ -#define VNDR_IE_BEACON_FLAG 0x1 -#define VNDR_IE_PRBRSP_FLAG 0x2 -#define VNDR_IE_ASSOCRSP_FLAG 0x4 -#define VNDR_IE_AUTHRSP_FLAG 0x8 -#define VNDR_IE_PRBREQ_FLAG 0x10 -#define VNDR_IE_ASSOCREQ_FLAG 0x20 -#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ -#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ - -#if defined(WLP2P) -/* P2P Action Frames flags (spec ordered) */ -#define VNDR_IE_GONREQ_FLAG 0x001000 -#define VNDR_IE_GONRSP_FLAG 0x002000 -#define VNDR_IE_GONCFM_FLAG 0x004000 -#define VNDR_IE_INVREQ_FLAG 0x008000 -#define VNDR_IE_INVRSP_FLAG 0x010000 -#define VNDR_IE_DISREQ_FLAG 0x020000 -#define VNDR_IE_DISRSP_FLAG 0x040000 -#define VNDR_IE_PRDREQ_FLAG 0x080000 -#define VNDR_IE_PRDRSP_FLAG 0x100000 - -#define VNDR_IE_P2PAF_SHIFT 12 -#endif /* WLP2P */ - -/* channel interference measurement (chanim) related defines */ - -/* chanim mode */ -#define CHANIM_DISABLE 0 /* disabled */ -#define CHANIM_DETECT 1 /* detection only */ -#define CHANIM_EXT 2 /* external state machine */ -#define CHANIM_ACT 3 /* full internal state machine, detect + act */ -#define CHANIM_MODE_MAX 4 - -/* define for apcs reason code */ -#define APCS_INIT 0 -#define APCS_IOCTL 1 -#define APCS_CHANIM 2 -#define APCS_CSTIMER 3 -#define APCS_BTA 4 -#define APCS_TXDLY 5 -#define APCS_NONACSD 6 -#define APCS_DFS_REENTRY 7 -#define APCS_TXFAIL 8 -#define APCS_MAX 9 - -/* number of ACS record entries */ -#define CHANIM_ACS_RECORD 10 - -/* CHANIM */ -#define CCASTATS_TXDUR 0 -#define CCASTATS_INBSS 1 -#define CCASTATS_OBSS 2 -#define CCASTATS_NOCTG 3 -#define CCASTATS_NOPKT 4 -#define CCASTATS_DOZE 5 -#define CCASTATS_TXOP 6 -#define CCASTATS_GDTXDUR 7 -#define CCASTATS_BDTXDUR 8 -#define CCASTATS_MAX 9 - -#define WL_CHANIM_COUNT_ALL 0xff -#define WL_CHANIM_COUNT_ONE 0x1 - -/* ap tpc modes */ -#define AP_TPC_OFF 0 -#define AP_TPC_BSS_PWR 1 /* BSS power control */ -#define AP_TPC_AP_PWR 2 /* AP power control */ -#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ -#define AP_TPC_MAX_LINK_MARGIN 127 - -/* ap tpc modes */ -#define AP_TPC_OFF 0 -#define AP_TPC_BSS_PWR 1 /* BSS power control */ -#define AP_TPC_AP_PWR 2 /* AP power control */ -#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ -#define AP_TPC_MAX_LINK_MARGIN 127 - -/* state */ -#define WL_P2P_DISC_ST_SCAN 0 -#define WL_P2P_DISC_ST_LISTEN 1 -#define WL_P2P_DISC_ST_SEARCH 2 - -/* i/f type */ -#define WL_P2P_IF_CLIENT 0 -#define WL_P2P_IF_GO 1 -#define WL_P2P_IF_DYNBCN_GO 2 -#define WL_P2P_IF_DEV 3 - -/* count */ -#define WL_P2P_SCHED_RSVD 0 -#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */ - -#define WL_P2P_SCHED_FIXED_LEN 3 - -/* schedule type */ -#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */ -#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */ - -/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */ -#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */ -#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */ -/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ -#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */ -/* schedule option - WL_P2P_SCHED_TYPE_XXX */ -#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */ - -/* schedule option - WL_P2P_SCHED_TYPE_ABS */ -#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */ -#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */ -/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ -#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with - * start being an offset of the 'current' TSF - */ - -/* feature flags */ -#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */ -#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe - * requests - */ -#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */ - -/* 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 - -/* Proxy STA modes */ -#define PSTA_MODE_DISABLED 0 -#define PSTA_MODE_PROXY 1 -#define PSTA_MODE_REPEATER 2 - -/* op code in nat_cfg */ -#define NAT_OP_ENABLE 1 /* enable NAT on given interface */ -#define NAT_OP_DISABLE 2 /* disable NAT on given interface */ -#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */ - -/* NAT state */ -#define NAT_STATE_ENABLED 1 /* NAT is enabled */ -#define NAT_STATE_DISABLED 2 /* NAT is disabled */ - -#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */ -#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */ -#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */ -#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */ - -/* D0 Coalescing */ -#define IPV4_ARP_FILTER 0x0001 -#define IPV4_NETBT_FILTER 0x0002 -#define IPV4_LLMNR_FILTER 0x0004 -#define IPV4_SSDP_FILTER 0x0008 -#define IPV4_WSD_FILTER 0x0010 -#define IPV6_NETBT_FILTER 0x0200 -#define IPV6_LLMNR_FILTER 0x0400 -#define IPV6_SSDP_FILTER 0x0800 -#define IPV6_WSD_FILTER 0x1000 - -/* Network Offload Engine */ -#define NWOE_OL_ENABLE 0x00000001 - -/* - * Traffic management structures/defines. - */ - -/* Traffic management bandwidth parameters */ -#define TRF_MGMT_MAX_PRIORITIES 3 - -#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ -#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Don't shape traffic */ -#define TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC 0x0008 /* Manage traffic over our local subnet */ -#define TRF_MGMT_FLAG_FILTER_ON_MACADDR 0x0010 /* filter on MAC address */ -#define TRF_MGMT_FLAG_NO_RX 0x0020 /* do not apply fiters to rx packets */ - -#define TRF_FILTER_MAC_ADDR 0x0001 /* L2 filter use dst mac address for filtering */ -#define TRF_FILTER_IP_ADDR 0x0002 /* L3 filter use ip ddress for filtering */ -#define TRF_FILTER_L4 0x0004 /* L4 filter use tcp/udp for filtering */ -#define TRF_FILTER_DWM 0x0008 /* L3 filter use DSCP for filtering */ -#define TRF_FILTER_FAVORED 0x0010 /* Tag the packet FAVORED */ - -/* WNM/NPS subfeatures mask */ -#define WL_WNM_BSSTRANS 0x00000001 -#define WL_WNM_PROXYARP 0x00000002 -#define WL_WNM_MAXIDLE 0x00000004 -#define WL_WNM_TIMBC 0x00000008 -#define WL_WNM_TFS 0x00000010 -#define WL_WNM_SLEEP 0x00000020 -#define WL_WNM_DMS 0x00000040 -#define WL_WNM_FMS 0x00000080 -#define WL_WNM_NOTIF 0x00000100 -#define WL_WNM_MAX 0x00000200 - -#ifndef ETHER_MAX_DATA -#define ETHER_MAX_DATA 1500 -#endif /* ETHER_MAX_DATA */ - -/* Different discovery modes for dpt */ -#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */ -#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */ -#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */ - -/* different path selection values */ -#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */ -#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */ -#define DPT_PATHSEL_APPATH 2 /* always use AP path */ - -/* different ops for deny list */ -#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */ -#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */ - -/* different ops for manual end point */ -#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ -#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ -#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ - -/* flags to indicate DPT status */ -#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */ -#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */ -#define DPT_STATUS_FAILED 0x04 /* DPT link failed */ - -#ifdef WLTDLS -/* different ops for manual end point */ -#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ -#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ -#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ -#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ -#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ -#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ -#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ -#define TDLS_MANUAL_EP_WFD_TPQ 8 /* WiFi-Display Tunneled Probe reQuest */ - -/* modes */ -#define TDLS_WFD_IE_TX 0 -#define TDLS_WFD_IE_RX 1 -#define TDLS_WFD_PROBE_IE_TX 2 -#define TDLS_WFD_PROBE_IE_RX 3 -#endif /* WLTDLS */ - -/* define for flag */ -#define TSPEC_PENDING 0 /* TSPEC pending */ -#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ -#define TSPEC_REJECTED 2 /* TSPEC rejected */ -#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ -#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ - -#ifdef BCMCCX -/* "wlan_reason" iovar interface */ -#define WL_WLAN_ASSOC_REASON_NORMAL_NETWORK 0 /* normal WLAN network setup */ -#define WL_WLAN_ASSOC_REASON_ROAM_FROM_CELLULAR_NETWORK 1 /* roam from Cellular network */ -#define WL_WLAN_ASSOC_REASON_ROAM_FROM_LAN 2 /* roam from LAN */ -#define WL_WLAN_ASSOC_REASON_MAX 2 /* largest value allowed */ -#endif /* BCMCCX */ - -/* Software feature flag defines used by wlfeatureflag */ -#ifdef WLAFTERBURNER -#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ -#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ -#endif /* WLAFTERBURNER */ -#define WL_SWFL_NOHWRADIO 0x0004 -#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ -#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ - -#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ - -#define CSA_BROADCAST_ACTION_FRAME 0 /* csa broadcast action frame */ -#define CSA_UNICAST_ACTION_FRAME 1 /* csa unicast action frame */ - -/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER. - * - * (-100 < value < 0) value is used directly as a roaming trigger in dBm - * (0 <= value) value specifies a logical roaming trigger level from - * the list below - * - * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never - * the logical roam trigger value. - */ -#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */ -#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */ -#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */ -#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */ -#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */ - -#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */ - -/* Preferred Network Offload (PNO, formerly PFN) defines */ -#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ - -#define SORT_CRITERIA_BIT 0 -#define AUTO_NET_SWITCH_BIT 1 -#define ENABLE_BKGRD_SCAN_BIT 2 -#define IMMEDIATE_SCAN_BIT 3 -#define AUTO_CONNECT_BIT 4 -#define ENABLE_BD_SCAN_BIT 5 -#define ENABLE_ADAPTSCAN_BIT 6 -#define IMMEDIATE_EVENT_BIT 8 -#define SUPPRESS_SSID_BIT 9 -#define ENABLE_NET_OFFLOAD_BIT 10 - -#define SORT_CRITERIA_MASK 0x0001 -#define AUTO_NET_SWITCH_MASK 0x0002 -#define ENABLE_BKGRD_SCAN_MASK 0x0004 -#define IMMEDIATE_SCAN_MASK 0x0008 -#define AUTO_CONNECT_MASK 0x0010 - -#define ENABLE_BD_SCAN_MASK 0x0020 -#define ENABLE_ADAPTSCAN_MASK 0x00c0 -#define IMMEDIATE_EVENT_MASK 0x0100 -#define SUPPRESS_SSID_MASK 0x0200 -#define ENABLE_NET_OFFLOAD_MASK 0x0400 - -#define PFN_VERSION 2 -#define PFN_SCANRESULT_VERSION 1 -#define MAX_PFN_LIST_COUNT 16 - -#define PFN_COMPLETE 1 -#define PFN_INCOMPLETE 0 - -#define DEFAULT_BESTN 2 -#define DEFAULT_MSCAN 0 -#define DEFAULT_REPEAT 10 -#define DEFAULT_EXP 2 - -#define WL_PFN_SUPPRESSFOUND_MASK 0x08 -#define WL_PFN_SUPPRESSLOST_MASK 0x10 -#define WL_PFN_RSSI_MASK 0xff00 -#define WL_PFN_RSSI_SHIFT 8 - -#define WL_PFN_REPORT_ALLNET 0 -#define WL_PFN_REPORT_SSIDNET 1 -#define WL_PFN_REPORT_BSSIDNET 2 - -#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ -#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /* Remaining reserved for future use */ - -#define WL_PFN_HIDDEN_BIT 2 -#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ -#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ -#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ -#define WL_PFN_HIDDEN_MASK 0x4 -#define MAX_SSID_WHITELIST_NUM 4 -#define MAX_BSSID_PREF_LIST_NUM 32 -#define MAX_BSSID_BLACKLIST_NUM 32 - -/* TCP Checksum Offload error injection for testing */ -#define TOE_ERRTEST_TX_CSUM 0x00000001 -#define TOE_ERRTEST_RX_CSUM 0x00000002 -#define TOE_ERRTEST_RX_CSUM2 0x00000004 - -/* ARP Offload feature flags for arp_ol iovar */ -#define ARP_OL_AGENT 0x00000001 -#define ARP_OL_SNOOP 0x00000002 -#define ARP_OL_HOST_AUTO_REPLY 0x00000004 -#define ARP_OL_PEER_AUTO_REPLY 0x00000008 - -/* ARP Offload error injection */ -#define ARP_ERRTEST_REPLY_PEER 0x1 -#define ARP_ERRTEST_REPLY_HOST 0x2 - -#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ -#define ND_MULTIHOMING_MAX 10 /* Maximum local host IP addresses */ -#define ND_REQUEST_MAX 5 /* Max set of offload params */ - - -/* AOAC wake event flag */ -#define WAKE_EVENT_NLO_DISCOVERY_BIT 1 -#define WAKE_EVENT_AP_ASSOCIATION_LOST_BIT 2 -#define WAKE_EVENT_GTK_HANDSHAKE_ERROR_BIT 4 -#define WAKE_EVENT_4WAY_HANDSHAKE_REQUEST_BIT 8 - -#define MAX_NUM_WOL_PATTERN 16 /* LOGO requirements min 16 */ - -/* Packet filter operation mode */ -/* True: 1; False: 0 */ -#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 -/* Enable and disable pkt_filter as a whole */ -#define PKT_FILTER_MODE_DISABLE 2 -/* Cache first matched rx pkt(be queried by host later) */ -#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 -/* If pkt_filter is enabled and no filter is set, don't forward anything */ -#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 - -#ifdef DONGLEOVERLAYS -#define OVERLAY_IDX_MASK 0x000000ff -#define OVERLAY_IDX_SHIFT 0 -#define OVERLAY_FLAGS_MASK 0xffffff00 -#define OVERLAY_FLAGS_SHIFT 8 -/* overlay written to device memory immediately after loading the base image */ -#define OVERLAY_FLAG_POSTLOAD 0x100 -/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */ -#define OVERLAY_FLAG_DEFER_DL 0x200 -/* overlay downloaded prior to the host going to sleep */ -#define OVERLAY_FLAG_PRESLEEP 0x400 -#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 -#endif /* DONGLEOVERLAYS */ - -/* reuse two number in the sc/rc space */ -#define SMFS_CODE_MALFORMED 0xFFFE -#define SMFS_CODE_IGNORED 0xFFFD - -/* RFAWARE def */ -#define BCM_ACTION_RFAWARE 0x77 -#define BCM_ACTION_RFAWARE_DCS 0x01 - -/* DCS reason code define */ -#define BCM_DCS_IOVAR 0x1 -#define BCM_DCS_UNKNOWN 0xFF - - -#ifdef PROP_TXSTATUS -/* Bit definitions for tlv iovar */ -/* - * enable RSSI signals: - * WLFC_CTL_TYPE_RSSI - */ -#define WLFC_FLAGS_RSSI_SIGNALS 0x0001 - -/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals: - * - * WLFC_CTL_TYPE_MAC_OPEN - * WLFC_CTL_TYPE_MAC_CLOSE - * - * WLFC_CTL_TYPE_INTERFACE_OPEN - * WLFC_CTL_TYPE_INTERFACE_CLOSE - * - * WLFC_CTL_TYPE_MACDESC_ADD - * WLFC_CTL_TYPE_MACDESC_DEL - * - */ -#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002 - -/* enable (status, fifo_credit, mac_credit) signals - * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT - * WLFC_CTL_TYPE_TXSTATUS - * WLFC_CTL_TYPE_FIFO_CREDITBACK - */ -#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 - -#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 -#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 -#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 -#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040 -#define WLFC_FLAGS_PKT_STAMP_SIGNALS 0x0080 - -#endif /* PROP_TXSTATUS */ - -#define WL_TIMBC_STATUS_AP_UNKNOWN 255 /* AP status for internal use only */ - -#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ -#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ -#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ - -/* Definitions for Reliable Multicast */ -#define WL_RELMCAST_MAX_CLIENT 32 -#define WL_RELMCAST_FLAG_INBLACKLIST 1 -#define WL_RELMCAST_FLAG_ACTIVEACKER 2 -#define WL_RELMCAST_FLAG_RELMCAST 4 - -/* structures for proximity detection device role */ -#define WL_PROXD_MODE_DISABLE 0 -#define WL_PROXD_MODE_NEUTRAL 1 -#define WL_PROXD_MODE_INITIATOR 2 -#define WL_PROXD_MODE_TARGET 3 -#define WL_PROXD_RANDOM_WAKEUP 0x8000 - - -#ifdef NET_DETECT -#define NET_DETECT_MAX_WAKE_DATA_SIZE 2048 -#define NET_DETECT_MAX_PROFILES 16 -#define NET_DETECT_MAX_CHANNELS 50 -#endif /* NET_DETECT */ - -/* 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) -#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */ - -#define WL_SPURAVOID_OFF 0 -#define WL_SPURAVOID_ON1 1 -#define WL_SPURAVOID_ON2 2 - - -#define WL_4335_SPURAVOID_ON1 1 -#define WL_4335_SPURAVOID_ON2 2 -#define WL_4335_SPURAVOID_ON3 3 -#define WL_4335_SPURAVOID_ON4 4 -#define WL_4335_SPURAVOID_ON5 5 -#define WL_4335_SPURAVOID_ON6 6 -#define WL_4335_SPURAVOID_ON7 7 -#define WL_4335_SPURAVOID_ON8 8 -#define WL_4335_SPURAVOID_ON9 9 - -/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ -#define WL_TXPWR_OVERRIDE (1U<<31) -#define WL_TXPWR_NEG (1U<<30) - - -/* 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_LCN40 10 -#define WLC_PHY_TYPE_AC 11 -#define WLC_PHY_TYPE_NULL 0xf - -/* Values for PM */ -#define PM_OFF 0 -#define PM_MAX 1 -#define PM_FAST 2 -#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */ - -#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ - -/* fbt_cap: FBT assoc / reassoc modes. */ -#define WLC_FBT_CAP_DRV_4WAY_AND_REASSOC 1 /* Driver 4-way handshake & reassoc (WLFBT). */ - -/* monitor_promisc_level bits */ -#define WL_MONPROMISC_PROMISC 0x0001 -#define WL_MONPROMISC_CTRL 0x0002 -#define WL_MONPROMISC_FCS 0x0004 - -/* TCP Checksum Offload defines */ -#define TOE_TX_CSUM_OL 0x00000001 -#define TOE_RX_CSUM_OL 0x00000002 - -#endif /* wlioctl_defs_h */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h b/drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h deleted file mode 100755 index cffb2f3b1de4..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Definitions for ioctls to access DHD iovars. - * Based on wlioctl.h (for Broadcom 802.11abg driver). - * (Moves towards generic ioctls for BCM drivers/iovars.) - * - * Definitions subject to change without notice. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhdioctl.h 516345 2014-11-19 11:58:57Z $ - */ - -#ifndef _dhdioctl_h_ -#define _dhdioctl_h_ - -#include - - -/* require default structure packing */ -#define BWL_DEFAULT_PACKING -#include - - -/* Linux network driver ioctl encoding */ -typedef struct dhd_ioctl { - uint cmd; /* common ioctl definition */ - void *buf; /* pointer to user buffer */ - uint len; /* length of user buffer */ - bool set; /* get or set request (optional) */ - uint used; /* bytes read or written (optional) */ - uint needed; /* bytes needed (optional) */ - uint driver; /* to identify target driver */ -} dhd_ioctl_t; - -/* Underlying BUS definition */ -enum { - BUS_TYPE_USB = 0, /* for USB dongles */ - BUS_TYPE_SDIO, /* for SDIO dongles */ - BUS_TYPE_PCIE /* for PCIE dongles */ -}; - -/* per-driver magic numbers */ -#define DHD_IOCTL_MAGIC 0x00444944 - -/* bump this number if you change the ioctl interface */ -#define DHD_IOCTL_VERSION 1 - -#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ -#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ - -/* common ioctl definitions */ -#define DHD_GET_MAGIC 0 -#define DHD_GET_VERSION 1 -#define DHD_GET_VAR 2 -#define DHD_SET_VAR 3 - -/* message levels */ -#define DHD_ERROR_VAL 0x0001 -#define DHD_TRACE_VAL 0x0002 -#define DHD_INFO_VAL 0x0004 -#define DHD_DATA_VAL 0x0008 -#define DHD_CTL_VAL 0x0010 -#define DHD_TIMER_VAL 0x0020 -#define DHD_HDRS_VAL 0x0040 -#define DHD_BYTES_VAL 0x0080 -#define DHD_INTR_VAL 0x0100 -#define DHD_LOG_VAL 0x0200 -#define DHD_GLOM_VAL 0x0400 -#define DHD_EVENT_VAL 0x0800 -#define DHD_BTA_VAL 0x1000 -#define DHD_ISCAN_VAL 0x2000 -#define DHD_ARPOE_VAL 0x4000 -#define DHD_REORDER_VAL 0x8000 -#define DHD_WL_VAL 0x10000 -#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */ -#define DHD_WL_VAL2 0x40000 -#define DHD_PNO_VAL 0x80000 -#define DHD_RTT_VAL 0x100000 - -#ifdef SDTEST -/* For pktgen iovar */ -typedef struct dhd_pktgen { - uint version; /* To allow structure change tracking */ - uint freq; /* Max ticks between tx/rx attempts */ - uint count; /* Test packets to send/rcv each attempt */ - uint print; /* Print counts every attempts */ - uint total; /* Total packets (or bursts) */ - uint minlen; /* Minimum length of packets to send */ - uint maxlen; /* Maximum length of packets to send */ - uint numsent; /* Count of test packets sent */ - uint numrcvd; /* Count of test packets received */ - uint numfail; /* Count of test send failures */ - uint mode; /* Test mode (type of test packets) */ - uint stop; /* Stop after this many tx failures */ -} dhd_pktgen_t; - -/* Version in case structure changes */ -#define DHD_PKTGEN_VERSION 2 - -/* Type of test packets to use */ -#define DHD_PKTGEN_ECHO 1 /* Send echo requests */ -#define DHD_PKTGEN_SEND 2 /* Send discard packets */ -#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */ -#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ -#endif /* SDTEST */ - -/* Enter idle immediately (no timeout) */ -#define DHD_IDLE_IMMEDIATE (-1) - -/* Values for idleclock iovar: other values are the sd_divisor to use when idle */ -#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */ -#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */ - - -/* require default structure packing */ -#include - -#endif /* _dhdioctl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h b/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h deleted file mode 100755 index d60c79139364..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 $ - * -*/ - -#ifndef _epivers_h_ -#define _epivers_h_ - -#define EPI_MAJOR_VERSION 1 - -#define EPI_MINOR_VERSION 141 - -#define EPI_RC_NUMBER 67 - -#define EPI_INCREMENTAL_NUMBER 33 - -#define EPI_BUILD_NUMBER 0 - -#define EPI_VERSION 1, 141, 67, 33 - -#define EPI_VERSION_NUM 0x018d4321 - -#define EPI_VERSION_DEV 1.141.67 - -/* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.141.67.33 (r)" - -#endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h b/drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h deleted file mode 100755 index a22f39bbf831..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * HND SiliconBackplane PMU support. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hndpmu.h 431134 2013-10-22 18:25:42Z $ - */ - -#ifndef _hndpmu_h_ -#define _hndpmu_h_ - - -extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on, uint32* min_res_mask); -extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength); - -extern void si_pmu_minresmask_htavail_set(si_t *sih, osl_t *osh, bool set_clear); - -#endif /* _hndpmu_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h deleted file mode 100755 index 5c305023d629..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * HNDRTE arm trap handling. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hndrte_armtrap.h 261365 2011-05-24 20:42:23Z $ - */ - -#ifndef _hndrte_armtrap_h -#define _hndrte_armtrap_h - - -/* ARM trap handling */ - -/* Trap types defined by ARM (see arminc.h) */ - -/* Trap locations in lo memory */ -#define TRAP_STRIDE 4 -#define FIRST_TRAP TR_RST -#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) - -#if defined(__ARM_ARCH_4T__) -#define MAX_TRAP_TYPE (TR_FIQ + 1) -#elif defined(__ARM_ARCH_7M__) -#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) -#endif /* __ARM_ARCH_7M__ */ - -/* The trap structure is defined here as offsets for assembly */ -#define TR_TYPE 0x00 -#define TR_EPC 0x04 -#define TR_CPSR 0x08 -#define TR_SPSR 0x0c -#define TR_REGS 0x10 -#define TR_REG(n) (TR_REGS + (n) * 4) -#define TR_SP TR_REG(13) -#define TR_LR TR_REG(14) -#define TR_PC TR_REG(15) - -#define TRAP_T_SIZE 80 - -#ifndef _LANGUAGE_ASSEMBLY - -#include - -typedef struct _trap_struct { - uint32 type; - uint32 epc; - uint32 cpsr; - uint32 spsr; - uint32 r0; /* a1 */ - uint32 r1; /* a2 */ - uint32 r2; /* a3 */ - uint32 r3; /* a4 */ - uint32 r4; /* v1 */ - uint32 r5; /* v2 */ - uint32 r6; /* v3 */ - uint32 r7; /* v4 */ - uint32 r8; /* v5 */ - uint32 r9; /* sb/v6 */ - uint32 r10; /* sl/v7 */ - uint32 r11; /* fp/v8 */ - uint32 r12; /* ip */ - uint32 r13; /* sp */ - uint32 r14; /* lr */ - uint32 pc; /* r15 */ -} trap_t; - -#endif /* !_LANGUAGE_ASSEMBLY */ - -#endif /* _hndrte_armtrap_h */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h deleted file mode 100755 index 40731bf78102..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Console support for hndrte. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hndrte_cons.h 427140 2013-10-02 18:07:07Z $ - */ -#ifndef _HNDRTE_CONS_H -#define _HNDRTE_CONS_H - -#include - -#define CBUF_LEN (128) - -#define LOG_BUF_LEN 1024 - -typedef struct { - uint32 buf; /* Can't be pointer on (64-bit) hosts */ - uint buf_size; - uint idx; - uint out_idx; /* output index */ -} hndrte_log_t; - -typedef struct { - /* 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. - */ - volatile uint vcons_in; - volatile 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. - */ - hndrte_log_t log; - - /* 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]; -} hndrte_cons_t; - -hndrte_cons_t *hndrte_get_active_cons_state(void); - -#endif /* _HNDRTE_CONS_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h b/drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h deleted file mode 100755 index 948f9af92149..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Broadcom HND chip & on-chip-interconnect-related definitions. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: hndsoc.h 432420 2013-10-28 14:14:02Z $ - */ - -#ifndef _HNDSOC_H -#define _HNDSOC_H - -/* Include the soci specific files */ -#include -#include - -/* - * SOC Interconnect Address Map. - * All regions may not exist on all chips. - */ -#define SI_SDRAM_BASE 0x00000000 /* Physical SDRAM */ -#define SI_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */ -#define SI_PCI_MEM_SZ (64 * 1024 * 1024) -#define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */ -#define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ -#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */ - -#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ - -#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ -#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ - -#ifndef SI_MAXCORES -#define SI_MAXCORES 32 /* NorthStar has more cores */ -#endif /* SI_MAXCORES */ - -#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ -#define SI_FASTRAM_SWAPPED 0x19800000 - -#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */ -#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */ -#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */ -#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */ -#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */ -#define SI_FLASH_WINDOW 0x01000000 /* Flash XIP Window */ - -#define SI_NS_NANDFLASH 0x1c000000 /* NorthStar NAND flash base */ -#define SI_NS_NORFLASH 0x1e000000 /* NorthStar NOR flash base */ -#define SI_NS_ROM 0xfffd0000 /* NorthStar ROM */ -#define SI_NS_FLASH_WINDOW 0x02000000 /* Flash XIP Window */ - -#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */ -#define SI_ARMCR4_ROM 0x000f0000 /* ARM Cortex-R4 ROM */ -#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */ -#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */ -#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */ -#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */ - -#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */ -#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */ -#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ -#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 - * (2 ZettaBytes), low 32 bits - */ -#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 - * (2 ZettaBytes), high 32 bits - */ -/* 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 ACPHY_CORE_ID 0x83b /* Dot11 ACPHY */ -#define PCIE2_CORE_ID 0x83c /* pci express Gen2 core */ -#define USB30D_CORE_ID 0x83d /* usb 3.0 device core */ -#define ARMCR4_CORE_ID 0x83e /* ARM CR4 CPU */ -#define GCI_CORE_ID 0x840 /* GCI Core */ -#define APB_BRIDGE_CORE_ID 0x135 /* APB bridge core ID */ -#define AXI_CORE_ID 0x301 /* AXI/GPV core ID */ -#define EROM_CORE_ID 0x366 /* EROM core ID */ -#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 - */ - -#define CC_4706_CORE_ID 0x500 /* chipcommon core */ -#define NS_PCIEG2_CORE_ID 0x501 /* PCIE Gen 2 core */ -#define NS_DMA_CORE_ID 0x502 /* DMA core */ -#define NS_SDIO3_CORE_ID 0x503 /* SDIO3 core */ -#define NS_USB20_CORE_ID 0x504 /* USB2.0 core */ -#define NS_USB30_CORE_ID 0x505 /* USB3.0 core */ -#define NS_A9JTAG_CORE_ID 0x506 /* ARM Cortex A9 JTAG core */ -#define NS_DDR23_CORE_ID 0x507 /* Denali DDR2/DDR3 memory controller */ -#define NS_ROM_CORE_ID 0x508 /* ROM core */ -#define NS_NAND_CORE_ID 0x509 /* NAND flash controller core */ -#define NS_QSPI_CORE_ID 0x50a /* SPI flash controller core */ -#define NS_CCB_CORE_ID 0x50b /* ChipcommonB core */ -#define SOCRAM_4706_CORE_ID 0x50e /* internal memory core */ -#define NS_SOCRAM_CORE_ID SOCRAM_4706_CORE_ID -#define ARMCA9_CORE_ID 0x510 /* ARM Cortex A9 core (ihost) */ -#define NS_IHOST_CORE_ID ARMCA9_CORE_ID /* ARM Cortex A9 core (ihost) */ -#define GMAC_COMMON_4706_CORE_ID 0x5dc /* Gigabit MAC core */ -#define GMAC_4706_CORE_ID 0x52d /* Gigabit MAC core */ -#define AMEMC_CORE_ID 0x52e /* DDR1/2 memory controller core */ -#define ALTA_CORE_ID 0x534 /* I2S core */ -#define DDR23_PHY_CORE_ID 0x5dd - -#define SI_PCI1_MEM 0x40000000 /* Host Mode sb2pcitranslation0 (64 MB) */ -#define SI_PCI1_CFG 0x44000000 /* Host Mode sb2pcitranslation1 (64 MB) */ -#define SI_PCIE1_DMA_H32 0xc0000000 /* PCIE Client Mode sb2pcitranslation2 - * (2 ZettaBytes), high 32 bits - */ -#define CC_4706B0_CORE_REV 0x8000001f /* chipcommon core */ -#define SOCRAM_4706B0_CORE_REV 0x80000005 /* internal memory core */ -#define GMAC_4706B0_CORE_REV 0x80000000 /* Gigabit MAC core */ - -/* There are TWO constants on all HND chips: SI_ENUM_BASE above, - * and chipcommon being the first core: - */ -#define SI_CC_IDX 0 -/* SOC Interconnect types (aka chip types) */ -#define SOCI_SB 0 -#define SOCI_AI 1 -#define SOCI_UBUS 2 -#define SOCI_NAI 3 - -/* 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 - -/* Norstar core status flags */ -#define SISF_NS_BOOTDEV_MASK 0x0003 /* ROM core */ -#define SISF_NS_BOOTDEV_NOR 0x0000 /* ROM core */ -#define SISF_NS_BOOTDEV_NAND 0x0001 /* ROM core */ -#define SISF_NS_BOOTDEV_ROM 0x0002 /* ROM core */ -#define SISF_NS_BOOTDEV_OFFLOAD 0x0003 /* ROM core */ -#define SISF_NS_SKUVEC_MASK 0x000c /* ROM core */ - -/* 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 */ -#define SI_PWR_CTL_ST 0x1e8 /* For memory clock gating */ - -/* 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_HQCLKREQ 0x00000040 /* HQ Clock Required */ -#define CCS_USBCLKREQ 0x00000100 /* USB Clock Req */ -#define CCS_SECICLKREQ 0x00000100 /* SECI Clock Req */ -#define CCS_ARMFASTCLOCKREQ 0x00000100 /* ARM CR4 fast clock request */ -#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: Backplane is running on ALP clock */ -#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */ -#define CCS_ARMFASTCLOCKSTATUS 0x01000000 /* Fast CPU clock is running */ -#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ -#define CCS_ERSRC_STS_SHIFT 24 - -#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */ -#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */ - -/* 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 */ - -/* A boot/binary may have an embedded block that describes its size */ -#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */ -#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */ -#define BISZ_MAGIC_IDX 0 /* Word 0: magic */ -#define BISZ_TXTST_IDX 1 /* 1: text start */ -#define BISZ_TXTEND_IDX 2 /* 2: text end */ -#define BISZ_DATAST_IDX 3 /* 3: data start */ -#define BISZ_DATAEND_IDX 4 /* 4: data end */ -#define BISZ_BSSST_IDX 5 /* 5: bss start */ -#define BISZ_BSSEND_IDX 6 /* 6: bss end */ -#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */ - -/* Boot/Kernel related defintion and functions */ -#define SOC_BOOTDEV_ROM 0x00000001 -#define SOC_BOOTDEV_PFLASH 0x00000002 -#define SOC_BOOTDEV_SFLASH 0x00000004 -#define SOC_BOOTDEV_NANDFLASH 0x00000008 - -#define SOC_KNLDEV_NORFLASH 0x00000002 -#define SOC_KNLDEV_NANDFLASH 0x00000004 - -#ifndef _LANGUAGE_ASSEMBLY -int soc_boot_dev(void *sih); -int soc_knl_dev(void *sih); -#endif /* _LANGUAGE_ASSEMBLY */ - -#endif /* _HNDSOC_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h b/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h deleted file mode 100755 index 228e231a9955..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h +++ /dev/null @@ -1,688 +0,0 @@ -/* - * Linux OS Independent Layer - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: linux_osl.h 432719 2013-10-29 12:04:59Z $ - */ - -#ifndef _linux_osl_h_ -#define _linux_osl_h_ - -#include - -/* Linux Kernel: File Operations: start */ -extern void * osl_os_open_image(char * filename); -extern int osl_os_get_image_block(char * buf, int len, void * image); -extern void osl_os_close_image(void * image); -extern int osl_os_image_size(void *image); -/* Linux Kernel: File Operations: end */ - -#ifdef BCMDRIVER - -/* OSL initialization */ -#ifdef SHARED_OSL_CMN -extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag, void **osh_cmn); -#else -extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); -#endif /* SHARED_OSL_CMN */ - -extern void osl_detach(osl_t *osh); -extern int osl_static_mem_init(osl_t *osh, void *adapter); -extern int osl_static_mem_deinit(osl_t *osh, void *adapter); -extern void osl_set_bus_handle(osl_t *osh, void *bus_handle); -extern void* osl_get_bus_handle(osl_t *osh); - -/* Global ASSERT type */ -extern uint32 g_assert_type; - -/* ASSERT */ -#if defined(BCMASSERT_LOG) - #define ASSERT(exp) \ - do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) -extern void osl_assert(const char *exp, const char *file, int line); -#else - #ifdef __GNUC__ - #define GCC_VERSION \ - (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) - #if GCC_VERSION > 30100 - #define ASSERT(exp) do {} while (0) - #else - /* ASSERT could cause segmentation fault on GCC3.1, use empty instead */ - #define ASSERT(exp) - #endif /* GCC_VERSION > 30100 */ - #endif /* __GNUC__ */ -#endif - -/* microsecond delay */ -#define OSL_DELAY(usec) osl_delay(usec) -extern void osl_delay(uint usec); - -#define OSL_SLEEP(ms) osl_sleep(ms) -extern void osl_sleep(uint ms); - -#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ - osl_pcmcia_read_attr((osh), (offset), (buf), (size)) -#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ - osl_pcmcia_write_attr((osh), (offset), (buf), (size)) -extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); -extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size); - -/* PCI configuration space access macros */ -#define OSL_PCI_READ_CONFIG(osh, offset, size) \ - osl_pci_read_config((osh), (offset), (size)) -#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ - osl_pci_write_config((osh), (offset), (size), (val)) -extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); -extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); - -/* PCI device bus # and slot # */ -#define OSL_PCI_BUS(osh) osl_pci_bus(osh) -#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) -extern uint osl_pci_bus(osl_t *osh); -extern uint osl_pci_slot(osl_t *osh); -extern struct pci_dev *osl_pci_device(osl_t *osh); - -/* Pkttag flag should be part of public information */ -typedef struct { - bool pkttag; - bool mmbus; /* Bus supports memory-mapped register accesses */ - pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ - void *tx_ctx; /* Context to the callback function */ - void *unused[3]; -} osl_pubinfo_t; - -#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ - do { \ - ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ - ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ - } while (0) - - -/* host/bus architecture-specific byte swap */ -#define BUS_SWAP32(v) (v) - #define MALLOC(osh, size) osl_malloc((osh), (size)) - #define MALLOCZ(osh, size) osl_mallocz((osh), (size)) - #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) - #define MALLOCED(osh) osl_malloced((osh)) - #define MEMORY_LEFTOVER(osh) osl_check_memleak(osh) - extern void *osl_malloc(osl_t *osh, uint size); - extern void *osl_mallocz(osl_t *osh, uint size); - extern void osl_mfree(osl_t *osh, void *addr, uint size); - extern uint osl_malloced(osl_t *osh); - extern uint osl_check_memleak(osl_t *osh); - - -#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) -extern uint osl_malloc_failed(osl_t *osh); - -/* allocate/free shared (dma-able) consistent memory */ -#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() -#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ - osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) -#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ - osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) - -#define DMA_ALLOC_CONSISTENT_FORCE32(osh, size, align, tot, pap, dmah) \ - osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) -#define DMA_FREE_CONSISTENT_FORCE32(osh, va, size, pa, dmah) \ - osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) - -extern uint osl_dma_consistent_align(void); -extern void * -osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, uint *tot, dmaaddr_t *pap); -extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa); - -/* map/unmap direction */ -#define DMA_TX 1 /* TX direction for DMA */ -#define DMA_RX 2 /* RX direction for DMA */ - -/* map/unmap shared (dma-able) memory */ -#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ - osl_dma_unmap((osh), (pa), (size), (direction)) -extern dmaaddr_t osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, - hnddma_seg_map_t *txp_dmah); -extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); - -/* API for DMA addressing capability */ -#define OSL_DMADDRWIDTH(osh, addrwidth) ({BCM_REFERENCE(osh); BCM_REFERENCE(addrwidth);}) - - #define OSL_CACHE_FLUSH(va, len) BCM_REFERENCE(va) - #define OSL_CACHE_INV(va, len) BCM_REFERENCE(va) - #define OSL_PREFETCH(ptr) prefetch(ptr) - -/* register access macros */ - #include - #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(osl_get_bus_handle(osh), \ - (uintptr)(r), sizeof(*(r)), (v))) - #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(osl_get_bus_handle(osh), \ - (uintptr)(r), sizeof(*(r)))) - - #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ - mmap_op else bus_op - #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ - mmap_op : bus_op - -#define OSL_ERROR(bcmerror) osl_error(bcmerror) -extern int osl_error(int bcmerror); - -/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ -#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ - -#define OSH_NULL NULL - -/* - * BINOSL selects the slightly slower function-call-based binary compatible osl. - * Macros expand to calls to functions defined in linux_osl.c . - */ -#include /* use current 2.4.x calling conventions */ -#include /* for vsn/printf's */ -#include /* for mem*, str* */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) -#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) -#else -#define OSL_SYSUPTIME() ((uint32)jiffies * msecs_to_jiffies(1)) -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ -#define printf(fmt, args...) printk(fmt , ## args) -#include /* for vsn/printf's */ -#include /* for mem*, str* */ -/* bcopy's: Linux kernel doesn't provide these (anymore) */ -#define bcopy(src, dst, len) memcpy((dst), (src), (len)) -#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) -#define bzero(b, len) memset((b), '\0', (len)) - -/* register access macros */ - -#define R_REG(osh, r) (\ - SELECT_BUS_READ(osh, \ - ({ \ - __typeof(*(r)) __osl_v; \ - switch (sizeof(*(r))) { \ - case sizeof(uint8): __osl_v = \ - readb((volatile uint8*)(r)); break; \ - case sizeof(uint16): __osl_v = \ - readw((volatile uint16*)(r)); break; \ - case sizeof(uint32): __osl_v = \ - readl((volatile uint32*)(r)); break; \ - } \ - __osl_v; \ - }), \ - OSL_READ_REG(osh, r)) \ -) - -#define W_REG(osh, r, v) do { \ - SELECT_BUS_WRITE(osh, \ - switch (sizeof(*(r))) { \ - case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ - case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ - case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ - }, \ - (OSL_WRITE_REG(osh, r, v))); \ - } while (0) - -#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) - -/* bcopy, bcmp, and bzero functions */ -#define bcopy(src, dst, len) memcpy((dst), (src), (len)) -#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) -#define bzero(b, len) memset((b), '\0', (len)) - -/* uncached/cached virtual address */ -#define OSL_UNCACHED(va) ((void *)va) -#define OSL_CACHED(va) ((void *)va) - -#define OSL_PREF_RANGE_LD(va, sz) BCM_REFERENCE(va) -#define OSL_PREF_RANGE_ST(va, sz) BCM_REFERENCE(va) - -/* get processor cycle count */ -#if defined(__i386__) -#define OSL_GETCYCLES(x) rdtscl((x)) -#else -#define OSL_GETCYCLES(x) ((x) = 0) -#endif - -/* dereference an address that may cause a bus exception */ -#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) - -/* map/unmap physical to virtual I/O */ -#if !defined(CONFIG_MMC_MSM7X00A) -#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) -#else -#define REG_MAP(pa, size) (void *)(0) -#endif /* !defined(CONFIG_MMC_MSM7X00A */ -#define REG_UNMAP(va) iounmap((va)) - -/* shared (dma-able) memory access macros */ -#define R_SM(r) *(r) -#define W_SM(r, v) (*(r) = (v)) -#define BZERO_SM(r, len) memset((r), '\0', (len)) - -/* Because the non BINOSL implemenation of the PKT OSL routines are macros (for - * performance reasons), we need the Linux headers. - */ -#include /* use current 2.4.x calling conventions */ - -/* packet primitives */ -#define PKTGET(osh, len, send) osl_pktget((osh), (len)) -#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) -#define PKTLIST_DUMP(osh, buf) BCM_REFERENCE(osh) -#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) -#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) -#ifdef CONFIG_DHD_USE_STATIC_BUF -#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) -#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) -#else -#define PKTGET_STATIC PKTGET -#define PKTFREE_STATIC PKTFREE -#endif /* CONFIG_DHD_USE_STATIC_BUF */ -#define PKTDATA(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->data);}) -#define PKTLEN(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->len);}) -#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) -#define PKTEXPHEADROOM(osh, skb, b) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_realloc_headroom((struct sk_buff*)(skb), (b)); \ - }) -#define PKTTAILROOM(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_tailroom((struct sk_buff*)(skb)); \ - }) -#define PKTPADTAILROOM(osh, skb, padlen) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_pad((struct sk_buff*)(skb), (padlen)); \ - }) -#define PKTNEXT(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->next);}) -#define PKTSETNEXT(osh, skb, x) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)); \ - }) -#define PKTSETLEN(osh, skb, len) \ - ({ \ - BCM_REFERENCE(osh); \ - __skb_trim((struct sk_buff*)(skb), (len)); \ - }) -#define PKTPUSH(osh, skb, bytes) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_push((struct sk_buff*)(skb), (bytes)); \ - }) -#define PKTPULL(osh, skb, bytes) \ - ({ \ - BCM_REFERENCE(osh); \ - skb_pull((struct sk_buff*)(skb), (bytes)); \ - }) -#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) -#define PKTSETPOOL(osh, skb, x, y) BCM_REFERENCE(osh) -#define PKTPOOL(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) -#define PKTFREELIST(skb) PKTLINK(skb) -#define PKTSETFREELIST(skb, x) PKTSETLINK((skb), (x)) -#define PKTPTR(skb) (skb) -#define PKTID(skb) ({BCM_REFERENCE(skb); 0;}) -#define PKTSETID(skb, id) ({BCM_REFERENCE(skb); BCM_REFERENCE(id);}) -#define PKTSHRINK(osh, m) ({BCM_REFERENCE(osh); m;}) - - -#ifdef CTFPOOL -#define CTFPOOL_REFILL_THRESH 3 -typedef struct ctfpool { - void *head; - spinlock_t lock; - uint max_obj; - uint curr_obj; - uint obj_size; - uint refills; - uint fast_allocs; - uint fast_frees; - uint slow_allocs; -} ctfpool_t; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) -#define FASTBUF (1 << 0) -#define PKTSETFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->pktc_flags) |= FASTBUF); \ - }) -#define PKTCLRFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->pktc_flags) &= (~FASTBUF)); \ - }) -#define PKTISFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->pktc_flags) & FASTBUF); \ - }) -#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->pktc_flags) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -#define FASTBUF (1 << 16) -#define PKTSETFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF); \ - }) -#define PKTCLRFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)); \ - }) -#define PKTISFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->mac_len) & FASTBUF); \ - }) -#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) -#else -#define FASTBUF (1 << 0) -#define PKTSETFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->__unused) |= FASTBUF); \ - }) -#define PKTCLRFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)); \ - }) -#define PKTISFAST(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - ((((struct sk_buff*)(skb))->__unused) & FASTBUF); \ - }) -#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) -#endif /* 2.6.22 */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) -#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->ctfpool) -#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->ctfpool)->head) -#else -#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) -#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) -#endif - -extern void *osl_ctfpool_add(osl_t *osh); -extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); -extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); -extern void osl_ctfpool_cleanup(osl_t *osh); -extern void osl_ctfpool_stats(osl_t *osh, void *b); -#else /* CTFPOOL */ -#define PKTSETFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTISFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) -#endif /* CTFPOOL */ - -#define PKTSETCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTISCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) - -#ifdef HNDCTF - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) -#define SKIPCT (1 << 2) -#define CHAINED (1 << 3) -#define PKTSETSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags |= SKIPCT); \ - }) -#define PKTCLRSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags &= (~SKIPCT)); \ - }) -#define PKTSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags & SKIPCT); \ - }) -#define PKTSETCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags |= CHAINED); \ - }) -#define PKTCLRCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->pktc_flags &= (~CHAINED)); \ - }) -#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->pktc_flags & CHAINED) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -#define SKIPCT (1 << 18) -#define CHAINED (1 << 19) -#define PKTSETSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len |= SKIPCT); \ - }) -#define PKTCLRSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)); \ - }) -#define PKTSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len & SKIPCT); \ - }) -#define PKTSETCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len |= CHAINED); \ - }) -#define PKTCLRCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->mac_len &= (~CHAINED)); \ - }) -#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->mac_len & CHAINED) -#else /* 2.6.22 */ -#define SKIPCT (1 << 2) -#define CHAINED (1 << 3) -#define PKTSETSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused |= SKIPCT); \ - }) -#define PKTCLRSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)); \ - }) -#define PKTSKIPCT(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused & SKIPCT); \ - }) -#define PKTSETCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused |= CHAINED); \ - }) -#define PKTCLRCHAINED(osh, skb) \ - ({ \ - BCM_REFERENCE(osh); \ - (((struct sk_buff*)(skb))->__unused &= (~CHAINED)); \ - }) -#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->__unused & CHAINED) -#endif /* 2.6.22 */ -typedef struct ctf_mark { - uint32 value; -} ctf_mark_t; -#define CTF_MARK(m) (m.value) -#else /* HNDCTF */ -#define PKTSETSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define CTF_MARK(m) ({BCM_REFERENCE(m); 0;}) -#endif /* HNDCTF */ - -#ifdef BCMFA -#ifdef BCMFA_HW_HASH -#define PKTSETFAHIDX(skb, idx) (((struct sk_buff*)(skb))->napt_idx = idx) -#else -#define PKTSETFAHIDX(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) -#endif /* BCMFA_SW_HASH */ -#define PKTGETFAHIDX(skb) (((struct sk_buff*)(skb))->napt_idx) -#define PKTSETFADEV(skb, imp) (((struct sk_buff*)(skb))->dev = imp) -#define PKTSETRXDEV(skb) (((struct sk_buff*)(skb))->rxdev = ((struct sk_buff*)(skb))->dev) - -#define AUX_TCP_FIN_RST (1 << 0) -#define AUX_FREED (1 << 1) -#define PKTSETFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_TCP_FIN_RST) -#define PKTCLRFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_TCP_FIN_RST)) -#define PKTISFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_TCP_FIN_RST) -#define PKTSETFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_FREED) -#define PKTCLRFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_FREED)) -#define PKTISFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_FREED) -#define PKTISFABRIDGED(skb) PKTISFAAUX(skb) -#else -#define PKTISFAAUX(skb) ({BCM_REFERENCE(skb); FALSE;}) -#define PKTISFABRIDGED(skb) ({BCM_REFERENCE(skb); FALSE;}) -#define PKTISFAFREED(skb) ({BCM_REFERENCE(skb); FALSE;}) - -#define PKTCLRFAAUX(skb) BCM_REFERENCE(skb) -#define PKTSETFAFREED(skb) BCM_REFERENCE(skb) -#define PKTCLRFAFREED(skb) BCM_REFERENCE(skb) -#endif /* BCMFA */ - -extern void osl_pktfree(osl_t *osh, void *skb, bool send); -extern void *osl_pktget_static(osl_t *osh, uint len); -extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); - -extern void *osl_pkt_frmnative(osl_t *osh, void *skb); -extern void *osl_pktget(osl_t *osh, uint len); -extern void *osl_pktdup(osl_t *osh, void *skb); -extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); -#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), (struct sk_buff*)(skb)) -#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_t *)(osh), (pkt)) - -#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) -#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) -#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) -#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) -#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW) -#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \ - ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) -/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ -#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) - -#ifdef CONFIG_NF_CONNTRACK_MARK -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define PKTMARK(p) (((struct sk_buff *)(p))->mark) -#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->mark = (m) -#else /* !2.6.0 */ -#define PKTMARK(p) (((struct sk_buff *)(p))->nfmark) -#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->nfmark = (m) -#endif /* 2.6.0 */ -#else /* CONFIG_NF_CONNTRACK_MARK */ -#define PKTMARK(p) 0 -#define PKTSETMARK(p, m) -#endif /* CONFIG_NF_CONNTRACK_MARK */ - -#define PKTALLOCED(osh) osl_pktalloced(osh) -extern uint osl_pktalloced(osl_t *osh); - -#define DMA_MAP(osh, va, size, direction, p, dmah) \ - osl_dma_map((osh), (va), (size), (direction), (p), (dmah)) - -#ifdef PKTC -/* Use 8 bytes of skb tstamp field to store below info */ -struct chain_node { - struct sk_buff *link; - unsigned int flags:3, pkts:9, bytes:20; -}; - -#define CHAIN_NODE(skb) ((struct chain_node*)(((struct sk_buff*)skb)->pktc_cb)) - -#define PKTCSETATTR(s, f, p, b) ({CHAIN_NODE(s)->flags = (f); CHAIN_NODE(s)->pkts = (p); \ - CHAIN_NODE(s)->bytes = (b);}) -#define PKTCCLRATTR(s) ({CHAIN_NODE(s)->flags = CHAIN_NODE(s)->pkts = \ - CHAIN_NODE(s)->bytes = 0;}) -#define PKTCGETATTR(s) (CHAIN_NODE(s)->flags << 29 | CHAIN_NODE(s)->pkts << 20 | \ - CHAIN_NODE(s)->bytes) -#define PKTCCNT(skb) (CHAIN_NODE(skb)->pkts) -#define PKTCLEN(skb) (CHAIN_NODE(skb)->bytes) -#define PKTCGETFLAGS(skb) (CHAIN_NODE(skb)->flags) -#define PKTCSETFLAGS(skb, f) (CHAIN_NODE(skb)->flags = (f)) -#define PKTCCLRFLAGS(skb) (CHAIN_NODE(skb)->flags = 0) -#define PKTCFLAGS(skb) (CHAIN_NODE(skb)->flags) -#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c)) -#define PKTCINCRCNT(skb) (CHAIN_NODE(skb)->pkts++) -#define PKTCADDCNT(skb, c) (CHAIN_NODE(skb)->pkts += (c)) -#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l)) -#define PKTCADDLEN(skb, l) (CHAIN_NODE(skb)->bytes += (l)) -#define PKTCSETFLAG(skb, fb) (CHAIN_NODE(skb)->flags |= (fb)) -#define PKTCCLRFLAG(skb, fb) (CHAIN_NODE(skb)->flags &= ~(fb)) -#define PKTCLINK(skb) (CHAIN_NODE(skb)->link) -#define PKTSETCLINK(skb, x) (CHAIN_NODE(skb)->link = (struct sk_buff*)(x)) -#define FOREACH_CHAINED_PKT(skb, nskb) \ - for (; (skb) != NULL; (skb) = (nskb)) \ - if ((nskb) = (PKTISCHAINED(skb) ? PKTCLINK(skb) : NULL), \ - PKTSETCLINK((skb), NULL), 1) -#define PKTCFREE(osh, skb, send) \ -do { \ - void *nskb; \ - ASSERT((skb) != NULL); \ - FOREACH_CHAINED_PKT((skb), nskb) { \ - PKTCLRCHAINED((osh), (skb)); \ - PKTCCLRFLAGS((skb)); \ - PKTFREE((osh), (skb), (send)); \ - } \ -} while (0) -#define PKTCENQTAIL(h, t, p) \ -do { \ - if ((t) == NULL) { \ - (h) = (t) = (p); \ - } else { \ - PKTSETCLINK((t), (p)); \ - (t) = (p); \ - } \ -} while (0) -#endif /* PKTC */ - -#else /* ! BCMDRIVER */ - - -/* ASSERT */ - #define ASSERT(exp) do {} while (0) - -/* MALLOC and MFREE */ -#define MALLOC(o, l) malloc(l) -#define MFREE(o, p, l) free(p) -#include - -/* str* and mem* functions */ -#include - -/* *printf functions */ -#include - -/* bcopy, bcmp, and bzero */ -extern void bcopy(const void *src, void *dst, size_t len); -extern int bcmp(const void *b1, const void *b2, size_t len); -extern void bzero(void *b, size_t len); -#endif /* ! BCMDRIVER */ - -#endif /* _linux_osl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h b/drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h deleted file mode 100755 index 363fb5caa7f5..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h +++ /dev/null @@ -1,748 +0,0 @@ -/* - * Linux-specific abstractions to gain some independence from linux kernel versions. - * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: linuxver.h 431983 2013-10-25 06:53:27Z $ - */ - -#ifndef _linuxver_h_ -#define _linuxver_h_ - -#include -#include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -#include -#else -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) -#include -#else -#include -#endif -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ -#include - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) -#include -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) -/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */ -#ifdef __UNDEF_NO_VERSION__ -#undef __NO_VERSION__ -#else -#define __NO_VERSION__ -#endif -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) -#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i") -#define module_param_string(_name_, _string_, _size_, _perm_) \ - MODULE_PARM(_string_, "c" __MODULE_STRING(_size_)) -#endif - -/* linux/malloc.h is deprecated, use linux/slab.h instead. */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)) -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -#include -#else -#include -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) -#undef IP_TOS -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) */ -#include - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)) -#include -#else -#include -#ifndef work_struct -#define work_struct tq_struct -#endif -#ifndef INIT_WORK -#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data)) -#endif -#ifndef schedule_work -#define schedule_work(_work) schedule_task((_work)) -#endif -#ifndef flush_scheduled_work -#define flush_scheduled_work() flush_scheduled_tasks() -#endif -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -#define DAEMONIZE(a) do { \ - allow_signal(SIGKILL); \ - allow_signal(SIGTERM); \ - } while (0) -#elif ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))) -#define DAEMONIZE(a) daemonize(a); \ - allow_signal(SIGKILL); \ - allow_signal(SIGTERM); -#else /* Linux 2.4 (w/o preemption patch) */ -#define RAISE_RX_SOFTIRQ() \ - cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) -#define DAEMONIZE(a) daemonize(); \ - do { if (a) \ - strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ - } while (0); -#endif /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) -#else -#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) -#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ - (RHEL_MAJOR == 5)) -/* Exclude RHEL 5 */ -typedef void (*work_func_t)(void *work); -#endif -#endif /* >= 2.6.20 */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -/* Some distributions have their own 2.6.x compatibility layers */ -#ifndef IRQ_NONE -typedef void irqreturn_t; -#define IRQ_NONE -#define IRQ_HANDLED -#define IRQ_RETVAL(x) -#endif -#else -typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) -#define IRQF_SHARED SA_SHIRQ -#endif /* < 2.6.18 */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) -#ifdef CONFIG_NET_RADIO -#define CONFIG_WIRELESS_EXT -#endif -#endif /* < 2.6.17 */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) -#include -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) -#include -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -#include -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -#include -#else -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) -#include -#endif -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ - - -#ifndef __exit -#define __exit -#endif -#ifndef __devexit -#define __devexit -#endif -#ifndef __devinit -# if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) -# define __devinit __init -# else -/* All devices are hotpluggable since linux 3.8.0 */ -# define __devinit -# endif -#endif /* !__devinit */ -#ifndef __devinitdata -#define __devinitdata -#endif -#ifndef __devexit_p -#define __devexit_p(x) x -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) - -#define pci_get_drvdata(dev) (dev)->sysdata -#define pci_set_drvdata(dev, value) (dev)->sysdata = (value) - -/* - * New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration - */ - -struct pci_device_id { - unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ - unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ - unsigned long driver_data; /* Data private to the driver */ -}; - -struct pci_driver { - struct list_head node; - char *name; - const struct pci_device_id *id_table; /* NULL if wants all devices */ - int (*probe)(struct pci_dev *dev, - const struct pci_device_id *id); /* New device inserted */ - void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug - * capable driver) - */ - void (*suspend)(struct pci_dev *dev); /* Device suspended */ - void (*resume)(struct pci_dev *dev); /* Device woken up */ -}; - -#define MODULE_DEVICE_TABLE(type, name) -#define PCI_ANY_ID (~0) - -/* compatpci.c */ -#define pci_module_init pci_register_driver -extern int pci_register_driver(struct pci_driver *drv); -extern void pci_unregister_driver(struct pci_driver *drv); - -#endif /* PCI registration */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) -#define pci_module_init pci_register_driver -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) -#ifdef MODULE -#define module_init(x) int init_module(void) { return x(); } -#define module_exit(x) void cleanup_module(void) { x(); } -#else -#define module_init(x) __initcall(x); -#define module_exit(x) __exitcall(x); -#endif -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) -#define WL_USE_NETDEV_OPS -#else -#undef WL_USE_NETDEV_OPS -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL) -#define WL_CONFIG_RFKILL -#else -#undef WL_CONFIG_RFKILL -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13)) -#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) -#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44)) -#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23)) -#define pci_enable_device(dev) do { } while (0) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)) -#define net_device device -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42)) - -/* - * DMA mapping - * - * See linux/Documentation/DMA-mapping.txt - */ - -#ifndef PCI_DMA_TODEVICE -#define PCI_DMA_TODEVICE 1 -#define PCI_DMA_FROMDEVICE 2 -#endif - -typedef u32 dma_addr_t; - -/* Pure 2^n version of get_order */ -static inline int get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - -static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -{ - void *ret; - int gfp = GFP_ATOMIC | GFP_DMA; - - ret = (void *)__get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_bus(ret); - } - return ret; -} -static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} -#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) -#define pci_unmap_single(cookie, address, size, dir) - -#endif /* DMA mapping */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)) - -#define dev_kfree_skb_any(a) dev_kfree_skb(a) -#define netif_down(dev) do { (dev)->start = 0; } while (0) - -/* pcmcia-cs provides its own netdevice compatibility layer */ -#ifndef _COMPAT_NETDEVICE_H - -/* - * SoftNet - * - * For pre-softnet kernels we need to tell the upper layer not to - * re-enter start_xmit() while we are in there. However softnet - * guarantees not to enter while we are in there so there is no need - * to do the netif_stop_queue() dance unless the transmit queue really - * gets stuck. This should also improve performance according to tests - * done by Aman Singla. - */ - -#define dev_kfree_skb_irq(a) dev_kfree_skb(a) -#define netif_wake_queue(dev) \ - do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0) -#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy) - -static inline void netif_start_queue(struct net_device *dev) -{ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; -} - -#define netif_queue_stopped(dev) (dev)->tbusy -#define netif_running(dev) (dev)->start - -#endif /* _COMPAT_NETDEVICE_H */ - -#define netif_device_attach(dev) netif_start_queue(dev) -#define netif_device_detach(dev) netif_stop_queue(dev) - -/* 2.4.x renamed bottom halves to tasklets */ -#define tasklet_struct tq_struct -static inline void tasklet_schedule(struct tasklet_struct *tasklet) -{ - queue_task(tasklet, &tq_immediate); - mark_bh(IMMEDIATE_BH); -} - -static inline void tasklet_init(struct tasklet_struct *tasklet, - void (*func)(unsigned long), - unsigned long data) -{ - tasklet->next = NULL; - tasklet->sync = 0; - tasklet->routine = (void (*)(void *))func; - tasklet->data = (void *)data; -} -#define tasklet_kill(tasklet) { do {} while (0); } - -/* 2.4.x introduced del_timer_sync() */ -#define del_timer_sync(timer) del_timer(timer) - -#else - -#define netif_down(dev) - -#endif /* SoftNet */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)) - -/* - * Emit code to initialise a tq_struct's routine and data pointers - */ -#define PREPARE_TQUEUE(_tq, _routine, _data) \ - do { \ - (_tq)->routine = _routine; \ - (_tq)->data = _data; \ - } while (0) - -/* - * Emit code to initialise all of a tq_struct - */ -#define INIT_TQUEUE(_tq, _routine, _data) \ - do { \ - INIT_LIST_HEAD(&(_tq)->list); \ - (_tq)->sync = 0; \ - PREPARE_TQUEUE((_tq), (_routine), (_data)); \ - } while (0) - -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) */ - -/* Power management related macro & routines */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) -#define PCI_SAVE_STATE(a, b) pci_save_state(a) -#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) -#else -#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) -#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) -static inline int -pci_save_state(struct pci_dev *dev, u32 *buffer) -{ - int i; - if (buffer) { - for (i = 0; i < 16; i++) - pci_read_config_dword(dev, i * 4, &buffer[i]); - } - return 0; -} - -static inline int -pci_restore_state(struct pci_dev *dev, u32 *buffer) -{ - int i; - - if (buffer) { - for (i = 0; i < 16; i++) - pci_write_config_dword(dev, i * 4, buffer[i]); - } - /* - * otherwise, write the context information we know from bootup. - * This works around a problem where warm-booting from Windows - * combined with a D3(hot)->D0 transition causes PCI config - * header data to be forgotten. - */ - else { - for (i = 0; i < 6; i ++) - pci_write_config_dword(dev, - PCI_BASE_ADDRESS_0 + (i * 4), - pci_resource_start(dev, i)); - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } - return 0; -} -#endif /* PCI power management */ - -/* Old cp0 access macros deprecated in 2.4.19 */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19)) -#define read_c0_count() read_32bit_cp0_register(CP0_COUNT) -#endif - -/* Module refcount handled internally in 2.6.x */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) -#ifndef SET_MODULE_OWNER -#define SET_MODULE_OWNER(dev) do {} while (0) -#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -#else -#define OLD_MOD_INC_USE_COUNT do {} while (0) -#define OLD_MOD_DEC_USE_COUNT do {} while (0) -#endif -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ -#ifndef SET_MODULE_OWNER -#define SET_MODULE_OWNER(dev) do {} while (0) -#endif -#ifndef MOD_INC_USE_COUNT -#define MOD_INC_USE_COUNT do {} while (0) -#endif -#ifndef MOD_DEC_USE_COUNT -#define MOD_DEC_USE_COUNT do {} while (0) -#endif -#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ - -#ifndef SET_NETDEV_DEV -#define SET_NETDEV_DEV(net, pdev) do {} while (0) -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)) -#ifndef HAVE_FREE_NETDEV -#define free_netdev(dev) kfree(dev) -#endif -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -/* struct packet_type redefined in 2.6.x */ -#define af_packet_priv data -#endif - -/* suspend args */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) -#define DRV_SUSPEND_STATE_TYPE pm_message_t -#else -#define DRV_SUSPEND_STATE_TYPE uint32 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -#define CHECKSUM_HW CHECKSUM_PARTIAL -#endif - -typedef struct { - void *parent; /* some external entity that the thread supposed to work for */ - char *proc_name; - struct task_struct *p_task; - long thr_pid; - int prio; /* priority */ - struct semaphore sema; - int terminated; - struct completion completed; - spinlock_t spinlock; - int up_cnt; -} tsk_ctl_t; - - -/* requires tsk_ctl_t tsk argument, the caller's priv data is passed in owner ptr */ -/* note this macro assumes there may be only one context waiting on thread's completion */ -#ifdef DHD_DEBUG -#define DBG_THR(x) printk x -#else -#define DBG_THR(x) -#endif - -static inline bool binary_sema_down(tsk_ctl_t *tsk) -{ - if (down_interruptible(&tsk->sema) == 0) { - unsigned long flags = 0; - spin_lock_irqsave(&tsk->spinlock, flags); - if (tsk->up_cnt == 1) - tsk->up_cnt--; - else { - DBG_THR(("dhd_dpc_thread: Unexpected up_cnt %d\n", tsk->up_cnt)); - } - spin_unlock_irqrestore(&tsk->spinlock, flags); - return false; - } else - return true; -} - -static inline bool binary_sema_up(tsk_ctl_t *tsk) -{ - bool sem_up = false; - unsigned long flags = 0; - - spin_lock_irqsave(&tsk->spinlock, flags); - if (tsk->up_cnt == 0) { - tsk->up_cnt++; - sem_up = true; - } else if (tsk->up_cnt == 1) { - /* dhd_sched_dpc: dpc is alread up! */ - } else - DBG_THR(("dhd_sched_dpc: unexpected up cnt %d!\n", tsk->up_cnt)); - - spin_unlock_irqrestore(&tsk->spinlock, flags); - - if (sem_up) - up(&tsk->sema); - - return sem_up; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) -#else -#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) -#endif - -#define PROC_START(thread_func, owner, tsk_ctl, flags, name) \ -{ \ - sema_init(&((tsk_ctl)->sema), 0); \ - init_completion(&((tsk_ctl)->completed)); \ - (tsk_ctl)->parent = owner; \ - (tsk_ctl)->proc_name = name; \ - (tsk_ctl)->terminated = FALSE; \ - (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ - (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ - spin_lock_init(&((tsk_ctl)->spinlock)); \ - DBG_THR(("%s(): thread:%s:%lx started\n", __FUNCTION__, \ - (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ -} - -#define PROC_STOP(tsk_ctl) \ -{ \ - (tsk_ctl)->terminated = TRUE; \ - smp_wmb(); \ - up(&((tsk_ctl)->sema)); \ - wait_for_completion(&((tsk_ctl)->completed)); \ - DBG_THR(("%s(): thread:%s:%lx terminated OK\n", __FUNCTION__, \ - (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ - (tsk_ctl)->thr_pid = -1; \ -} - -/* ----------------------- */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -#define KILL_PROC(nr, sig) \ -{ \ -struct task_struct *tsk; \ -struct pid *pid; \ -pid = find_get_pid((pid_t)nr); \ -tsk = pid_task(pid, PIDTYPE_PID); \ -if (tsk) send_sig(sig, tsk, 1); \ -} -#else -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ - KERNEL_VERSION(2, 6, 30)) -#define KILL_PROC(pid, sig) \ -{ \ - struct task_struct *tsk; \ - tsk = find_task_by_vpid(pid); \ - if (tsk) send_sig(sig, tsk, 1); \ -} -#else -#define KILL_PROC(pid, sig) \ -{ \ - kill_proc(pid, sig, 1); \ -} -#endif -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#include -#include -#else -#include - -#define __wait_event_interruptible_timeout(wq, condition, ret) \ -do { \ - wait_queue_t __wait; \ - init_waitqueue_entry(&__wait, current); \ - \ - add_wait_queue(&wq, &__wait); \ - for (;;) { \ - set_current_state(TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if (!signal_pending(current)) { \ - ret = schedule_timeout(ret); \ - if (!ret) \ - break; \ - continue; \ - } \ - ret = -ERESTARTSYS; \ - break; \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&wq, &__wait); \ -} while (0) - -#define wait_event_interruptible_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - if (!(condition)) \ - __wait_event_interruptible_timeout(wq, condition, __ret); \ - __ret; \ -}) - -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ - -/* -For < 2.6.24, wl creates its own netdev but doesn't -align the priv area like the genuine alloc_netdev(). -Since netdev_priv() always gives us the aligned address, it will -not match our unaligned address for < 2.6.24 -*/ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) -#define DEV_PRIV(dev) (dev->priv) -#else -#define DEV_PRIV(dev) netdev_priv(dev) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -#define WL_ISR(i, d, p) wl_isr((i), (d)) -#else -#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) -#endif /* < 2.6.20 */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -#define netdev_priv(dev) dev->priv -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -#define CAN_SLEEP() ((!in_atomic() && !irqs_disabled())) -#else -#define CAN_SLEEP() (FALSE) -#endif - -#define KMALLOC_FLAG (CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC) - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -#define RANDOM32 prandom_u32 -#else -#define RANDOM32 random32 -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -#define SRANDOM32(entropy) prandom_seed(entropy) -#else -#define SRANDOM32(entropy) srandom32(entropy) -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ - -/* - * Overide latest kfifo functions with - * older version to work on older kernels - */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) -#define kfifo_in_spinlocked(a, b, c, d) kfifo_put(a, (u8 *)b, c) -#define kfifo_out_spinlocked(a, b, c, d) kfifo_get(a, (u8 *)b, c) -#define kfifo_esize(a) 1 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)) && !defined(WL_COMPAT_WIRELESS) -#define kfifo_in_spinlocked(a, b, c, d) kfifo_in_locked(a, b, c, d) -#define kfifo_out_spinlocked(a, b, c, d) kfifo_out_locked(a, b, c, d) -#define kfifo_esize(a) 1 -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ - -#endif /* _linuxver_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h b/drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h deleted file mode 100755 index 722e5737564a..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Command line options parser. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: miniopt.h 241182 2011-02-17 21:50:03Z $ - */ - - -#ifndef MINI_OPT_H -#define MINI_OPT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* ---- Include Files ---------------------------------------------------- */ -/* ---- Constants and Types ---------------------------------------------- */ - -#define MINIOPT_MAXKEY 128 /* Max options */ -typedef struct miniopt { - - /* These are persistent after miniopt_init() */ - const char* name; /* name for prompt in error strings */ - const char* flags; /* option chars that take no args */ - bool longflags; /* long options may be flags */ - bool opt_end; /* at end of options (passed a "--") */ - - /* These are per-call to miniopt() */ - - int consumed; /* number of argv entries cosumed in - * the most recent call to miniopt() - */ - bool positional; - bool good_int; /* 'val' member is the result of a sucessful - * strtol conversion of the option value - */ - char opt; - char key[MINIOPT_MAXKEY]; - char* valstr; /* positional param, or value for the option, - * or null if the option had - * no accompanying value - */ - uint uval; /* strtol translation of valstr */ - int val; /* strtol translation of valstr */ -} miniopt_t; - -void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); -int miniopt(miniopt_t *t, char **argv); - - -/* ---- Variable Externs ------------------------------------------------- */ -/* ---- Function Prototypes ---------------------------------------------- */ - - -#ifdef __cplusplus - } -#endif - -#endif /* MINI_OPT_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h b/drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h deleted file mode 100755 index 4105585989a4..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Trace messages sent over HBUS - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: msgtrace.h 369735 2012-11-19 22:50:22Z $ - */ - -#ifndef _MSGTRACE_H -#define _MSGTRACE_H - -#ifndef _TYPEDEFS_H_ -#include -#endif - - -/* This marks the start of a packed structure section. */ -#include - -#define MSGTRACE_VERSION 1 - -/* Message trace header */ -typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { - uint8 version; - uint8 trace_type; -#define MSGTRACE_HDR_TYPE_MSG 0 -#define MSGTRACE_HDR_TYPE_LOG 1 - uint16 len; /* Len of the trace */ - uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost - * because of DMA error or a bus reset (ex: SDIO Func2) - */ - /* Msgtrace type only */ - uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */ - uint32 discarded_printf; /* Number of discarded printf because of trace overflow */ -} BWL_POST_PACKED_STRUCT msgtrace_hdr_t; - -#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t) - -/* The hbus driver generates traces when sending a trace message. This causes endless traces. - * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put. - * This prevents endless traces but generates hasardous lost of traces only in bus device code. - * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing - * hbus error traces. hbus error trace should not generates endless traces. - */ -extern bool msgtrace_hbus_trace; - -typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, - uint16 hdrlen, uint8 *buf, uint16 buflen); -extern void msgtrace_start(void); -extern void msgtrace_stop(void); -extern int msgtrace_sent(void); -extern void msgtrace_put(char *buf, int count); -extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send); -extern bool msgtrace_event_enabled(void); - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _MSGTRACE_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/osl.h b/drivers/net/wireless/bcmdhd_suzuran/include/osl.h deleted file mode 100755 index 7a101e506e88..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/osl.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * OS Abstraction Layer - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: osl.h 424562 2013-09-18 10:57:30Z $ - */ - -#ifndef _osl_h_ -#define _osl_h_ - -/* osl handle type forward declaration */ -typedef struct osl_info osl_t; -typedef struct osl_dmainfo osldma_t; - -#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ - -/* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ -typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); - -/* Drivers use REGOPSSET() to register register read/write funcitons */ -typedef unsigned int (*osl_rreg_fn_t)(void *ctx, volatile void *reg, unsigned int size); -typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, unsigned int size); - - -#include - -#ifndef PKTDBG_TRACE -#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) -#endif - -#define PKTCTFMAP(osh, p) BCM_REFERENCE(osh) - -/* -------------------------------------------------------------------------- -** Register manipulation macros. -*/ - -#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) - -#ifndef AND_REG -#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -#endif /* !AND_REG */ - -#ifndef OR_REG -#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) -#endif /* !OR_REG */ - -#if !defined(OSL_SYSUPTIME) -#define OSL_SYSUPTIME() (0) -#define OSL_SYSUPTIME_SUPPORT FALSE -#else -#define OSL_SYSUPTIME_SUPPORT TRUE -#endif /* OSL_SYSUPTIME */ - -#if !defined(PKTC) && !defined(PKTC_DONGLE) -#define PKTCGETATTR(skb) (0) -#define PKTCSETATTR(skb, f, p, b) BCM_REFERENCE(skb) -#define PKTCCLRATTR(skb) BCM_REFERENCE(skb) -#define PKTCCNT(skb) (1) -#define PKTCLEN(skb) PKTLEN(NULL, skb) -#define PKTCGETFLAGS(skb) (0) -#define PKTCSETFLAGS(skb, f) BCM_REFERENCE(skb) -#define PKTCCLRFLAGS(skb) BCM_REFERENCE(skb) -#define PKTCFLAGS(skb) (0) -#define PKTCSETCNT(skb, c) BCM_REFERENCE(skb) -#define PKTCINCRCNT(skb) BCM_REFERENCE(skb) -#define PKTCADDCNT(skb, c) BCM_REFERENCE(skb) -#define PKTCSETLEN(skb, l) BCM_REFERENCE(skb) -#define PKTCADDLEN(skb, l) BCM_REFERENCE(skb) -#define PKTCSETFLAG(skb, fb) BCM_REFERENCE(skb) -#define PKTCCLRFLAG(skb, fb) BCM_REFERENCE(skb) -#define PKTCLINK(skb) NULL -#define PKTSETCLINK(skb, x) BCM_REFERENCE(skb) -#define FOREACH_CHAINED_PKT(skb, nskb) \ - for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) -#define PKTCFREE PKTFREE -#define PKTCENQTAIL(h, t, p) \ -do { \ - if ((t) == NULL) { \ - (h) = (t) = (p); \ - } \ -} while (0) -#endif /* !linux || !PKTC */ - -#if !defined(HNDCTF) && !defined(PKTC_TX_DONGLE) -#define PKTSETCHAINED(osh, skb) BCM_REFERENCE(osh) -#define PKTCLRCHAINED(osh, skb) BCM_REFERENCE(osh) -#define PKTISCHAINED(skb) FALSE -#endif - -/* Lbuf with fraglist */ -#define PKTFRAGPKTID(osh, lb) (0) -#define PKTSETFRAGPKTID(osh, lb, id) BCM_REFERENCE(osh) -#define PKTFRAGTOTNUM(osh, lb) (0) -#define PKTSETFRAGTOTNUM(osh, lb, tot) BCM_REFERENCE(osh) -#define PKTFRAGTOTLEN(osh, lb) (0) -#define PKTSETFRAGTOTLEN(osh, lb, len) BCM_REFERENCE(osh) -#define PKTFRAGIFINDEX(osh, lb) (0) -#define PKTSETFRAGIFINDEX(osh, lb, idx) BCM_REFERENCE(osh) - -/* in rx path, reuse totlen as used len */ -#define PKTFRAGUSEDLEN(osh, lb) (0) -#define PKTSETFRAGUSEDLEN(osh, lb, len) BCM_REFERENCE(osh) - -#define PKTFRAGLEN(osh, lb, ix) (0) -#define PKTSETFRAGLEN(osh, lb, ix, len) BCM_REFERENCE(osh) -#define PKTFRAGDATA_LO(osh, lb, ix) (0) -#define PKTSETFRAGDATA_LO(osh, lb, ix, addr) BCM_REFERENCE(osh) -#define PKTFRAGDATA_HI(osh, lb, ix) (0) -#define PKTSETFRAGDATA_HI(osh, lb, ix, addr) BCM_REFERENCE(osh) - -/* RX FRAG */ -#define PKTISRXFRAG(osh, lb) (0) -#define PKTSETRXFRAG(osh, lb) BCM_REFERENCE(osh) -#define PKTRESETRXFRAG(osh, lb) BCM_REFERENCE(osh) - -/* TX FRAG */ -#define PKTISTXFRAG(osh, lb) (0) -#define PKTSETTXFRAG(osh, lb) BCM_REFERENCE(osh) - -#define PKTISFRAG(osh, lb) (0) -#define PKTFRAGISCHAINED(osh, i) (0) - -#endif /* _osl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h b/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h deleted file mode 100755 index cad72104470b..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Declare directives for structure packing. No padding will be provided - * between the members of packed structures, and therefore, there is no - * guarantee that structure members will be aligned. - * - * Declaring packed structures is compiler specific. In order to handle all - * cases, packed structures should be delared as: - * - * #include - * - * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { - * some_struct_members; - * } BWL_POST_PACKED_STRUCT foobar_t; - * - * #include - * - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: packed_section_end.h 241182 2011-02-17 21:50:03Z $ - */ - - -/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h - * and undefined in packed_section_end.h. If it is NOT defined at this - * point, then there is a missing include of packed_section_start.h. - */ -#ifdef BWL_PACKED_SECTION - #undef BWL_PACKED_SECTION -#else - #error "BWL_PACKED_SECTION is NOT defined!" -#endif - - - - -/* Compiler-specific directives for structure packing are declared in - * packed_section_start.h. This marks the end of the structure packing section, - * so, undef them here. - */ -#undef BWL_PRE_PACKED_STRUCT -#undef BWL_POST_PACKED_STRUCT diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h b/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h deleted file mode 100755 index 18f48270fa8c..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Declare directives for structure packing. No padding will be provided - * between the members of packed structures, and therefore, there is no - * guarantee that structure members will be aligned. - * - * Declaring packed structures is compiler specific. In order to handle all - * cases, packed structures should be delared as: - * - * #include - * - * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { - * some_struct_members; - * } BWL_POST_PACKED_STRUCT foobar_t; - * - * #include - * - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: packed_section_start.h 286783 2011-09-29 06:18:57Z $ - */ - - -/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h - * and undefined in packed_section_end.h. If it is already defined at this - * point, then there is a missing include of packed_section_end.h. - */ -#ifdef BWL_PACKED_SECTION - #error "BWL_PACKED_SECTION is already defined!" -#else - #define BWL_PACKED_SECTION -#endif - - - - -/* Declare compiler-specific directives for structure packing. */ -#if defined(__GNUC__) || defined(__lint) - #define BWL_PRE_PACKED_STRUCT - #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) -#elif defined(__CC_ARM) - #define BWL_PRE_PACKED_STRUCT __packed - #define BWL_POST_PACKED_STRUCT -#else - #error "Unknown compiler!" -#endif diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h b/drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h deleted file mode 100755 index 13774d0e510c..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * pcicfg.h: PCI configuration constants and structures. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: pcicfg.h 413666 2013-07-20 01:16:40Z $ - */ - -#ifndef _h_pcicfg_ -#define _h_pcicfg_ - -/* A structure for the config registers is nice, but in most - * systems the config space is not memory mapped, so we need - * field offsetts. :-( - */ -#define PCI_CFG_VID 0 -#define PCI_CFG_DID 2 -#define PCI_CFG_CMD 4 -#define PCI_CFG_STAT 6 -#define PCI_CFG_REV 8 -#define PCI_CFG_PROGIF 9 -#define PCI_CFG_SUBCL 0xa -#define PCI_CFG_BASECL 0xb -#define PCI_CFG_CLSZ 0xc -#define PCI_CFG_LATTIM 0xd -#define PCI_CFG_HDR 0xe -#define PCI_CFG_BIST 0xf -#define PCI_CFG_BAR0 0x10 -#define PCI_CFG_BAR1 0x14 -#define PCI_CFG_BAR2 0x18 -#define PCI_CFG_BAR3 0x1c -#define PCI_CFG_BAR4 0x20 -#define PCI_CFG_BAR5 0x24 -#define PCI_CFG_CIS 0x28 -#define PCI_CFG_SVID 0x2c -#define PCI_CFG_SSID 0x2e -#define PCI_CFG_ROMBAR 0x30 -#define PCI_CFG_CAPPTR 0x34 -#define PCI_CFG_INT 0x3c -#define PCI_CFG_PIN 0x3d -#define PCI_CFG_MINGNT 0x3e -#define PCI_CFG_MAXLAT 0x3f -#define PCI_CFG_DEVCTRL 0xd8 -#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */ -#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */ -#define PCI_SPROM_CONTROL 0x88 /* sprom property control */ -#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */ -#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */ -#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */ -#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */ -#define PCI_BACKPLANE_ADDR 0xa0 /* address an arbitrary location on the system backplane */ -#define PCI_BACKPLANE_DATA 0xa4 /* data at the location specified by above address */ -#define PCI_CLK_CTL_ST 0xa8 /* pci config space clock control/status (>=rev14) */ -#define PCI_BAR0_WIN2 0xac /* backplane addres space accessed by second 4KB of BAR0 */ -#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */ -#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */ -#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */ - -#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) /* bar0 + 2K accesses sprom shadow (in pci core) */ -#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */ -#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */ -#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) /* pci core SB registers are at the end of the - * 8KB window, so their address is the "regular" - * address plus 4K - */ -/* - * PCIE GEN2 changed some of the above locations for - * Bar0WrapperBase, SecondaryBAR0Window and SecondaryBAR0WrapperBase - * BAR0 maps 32K of register space -*/ -#define PCIE2_BAR0_WIN2 0x70 /* backplane addres space accessed by second 4KB of BAR0 */ -#define PCIE2_BAR0_CORE2_WIN 0x74 /* backplane addres space accessed by second 4KB of BAR0 */ -#define PCIE2_BAR0_CORE2_WIN2 0x78 /* backplane addres space accessed by second 4KB of BAR0 */ - -#define PCI_BAR0_WINSZ (16 * 1024) /* bar0 window size Match with corerev 13 */ -/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ -#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) /* bar0 + 8K accesses pci/pcie core registers */ -#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) /* bar0 + 12K accesses chipc core registers */ -#define PCI_16KBB0_WINSZ (16 * 1024) /* bar0 window size */ - - -#define PCI_CONFIG_SPACE_SIZE 256 -#endif /* _h_pcicfg_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h deleted file mode 100755 index a501d8206f87..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h +++ /dev/null @@ -1,3814 +0,0 @@ -/* - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental types and constants relating to 802.11 - * - * $Id: 802.11.h 444070 2013-12-18 13:20:12Z $ - */ - -#ifndef _802_11_H_ -#define _802_11_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -#ifndef _NET_ETHERNET_H_ -#include -#endif - -#include - -/* This marks the start of a packed structure section. */ -#include - - -#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */ - -/* Generic 802.11 frame constants */ -#define DOT11_A3_HDR_LEN 24 /* d11 header length with A3 */ -#define DOT11_A4_HDR_LEN 30 /* d11 header length with A4 */ -#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN /* MAC header length */ -#define DOT11_FCS_LEN 4 /* d11 FCS length */ -#define DOT11_ICV_LEN 4 /* d11 ICV length */ -#define DOT11_ICV_AES_LEN 8 /* d11 ICV/AES length */ -#define DOT11_QOS_LEN 2 /* d11 QoS length */ -#define DOT11_HTC_LEN 4 /* d11 HT Control field length */ - -#define DOT11_KEY_INDEX_SHIFT 6 /* d11 key index shift */ -#define DOT11_IV_LEN 4 /* d11 IV length */ -#define DOT11_IV_TKIP_LEN 8 /* d11 IV TKIP length */ -#define DOT11_IV_AES_OCB_LEN 4 /* d11 IV/AES/OCB length */ -#define DOT11_IV_AES_CCM_LEN 8 /* d11 IV/AES/CCM length */ -#define DOT11_IV_MAX_LEN 8 /* maximum iv len for any encryption */ - -/* Includes MIC */ -#define DOT11_MAX_MPDU_BODY_LEN 2304 /* max MPDU body length */ -/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */ -#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ - DOT11_QOS_LEN + \ - DOT11_IV_AES_CCM_LEN + \ - DOT11_MAX_MPDU_BODY_LEN + \ - DOT11_ICV_LEN + \ - DOT11_FCS_LEN) /* d11 max MPDU length */ - -#define DOT11_MAX_SSID_LEN 32 /* d11 max ssid length */ - -/* dot11RTSThreshold */ -#define DOT11_DEFAULT_RTS_LEN 2347 /* d11 default RTS length */ -#define DOT11_MAX_RTS_LEN 2347 /* d11 max RTS length */ - -/* dot11FragmentationThreshold */ -#define DOT11_MIN_FRAG_LEN 256 /* d11 min fragmentation length */ -#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength - * of the attached PHY - */ -#define DOT11_DEFAULT_FRAG_LEN 2346 /* d11 default fragmentation length */ - -/* dot11BeaconPeriod */ -#define DOT11_MIN_BEACON_PERIOD 1 /* d11 min beacon period */ -#define DOT11_MAX_BEACON_PERIOD 0xFFFF /* d11 max beacon period */ - -/* dot11DTIMPeriod */ -#define DOT11_MIN_DTIM_PERIOD 1 /* d11 min DTIM period */ -#define DOT11_MAX_DTIM_PERIOD 0xFF /* d11 max DTIM period */ - -/* 802.2 LLC/SNAP header used by 802.11 per 802.1H */ -#define DOT11_LLC_SNAP_HDR_LEN 8 /* d11 LLC/SNAP header length */ -#define DOT11_OUI_LEN 3 /* d11 OUI length */ -BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { - uint8 dsap; /* always 0xAA */ - uint8 ssap; /* always 0xAA */ - uint8 ctl; /* always 0x03 */ - uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 - * Bridge-Tunnel: 0x00 0x00 0xF8 - */ - uint16 type; /* ethertype */ -} BWL_POST_PACKED_STRUCT; - -/* RFC1042 header used by 802.11 per 802.1H */ -#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) /* RCF1042 header length */ - -/* Generic 802.11 MAC header */ -/* - * N.B.: This struct reflects the full 4 address 802.11 MAC header. - * The fields are defined such that the shorter 1, 2, and 3 - * address headers just use the first k fields. - */ -BWL_PRE_PACKED_STRUCT struct dot11_header { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr a1; /* address 1 */ - struct ether_addr a2; /* address 2 */ - struct ether_addr a3; /* address 3 */ - uint16 seq; /* sequence control */ - struct ether_addr a4; /* address 4 */ -} BWL_POST_PACKED_STRUCT; - -/* Control frames */ - -BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ - struct ether_addr ta; /* transmitter address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_RTS_LEN 16 /* d11 RTS frame length */ - -BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_CTS_LEN 10 /* d11 CTS frame length */ - -BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_ACK_LEN 10 /* d11 ACK frame length */ - -BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { - uint16 fc; /* frame control */ - uint16 durid; /* AID */ - struct ether_addr bssid; /* receiver address, STA in AP */ - struct ether_addr ta; /* transmitter address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_PS_POLL_LEN 16 /* d11 PS poll frame length */ - -BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ - struct ether_addr bssid; /* transmitter address, STA in AP */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */ - -/* RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling -* category+OUI+vendor specific content ( this can be variable) -*/ -BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { - uint8 category; - uint8 OUI[3]; - uint8 type; - uint8 subtype; - uint8 data[1040]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; - -/* generic vender specific action frame with variable length */ -BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { - uint8 category; - uint8 OUI[3]; - uint8 type; - uint8 subtype; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; - -#define DOT11_ACTION_VS_HDR_LEN 6 - -#define BCM_ACTION_OUI_BYTE0 0x00 -#define BCM_ACTION_OUI_BYTE1 0x90 -#define BCM_ACTION_OUI_BYTE2 0x4c - -/* BA/BAR Control parameters */ -#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */ -#define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */ -#define DOT11_BA_CTL_POLICY_MASK 0x0001 /* ack policy mask */ - -#define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */ -#define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */ - -#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */ -#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */ - -#define DOT11_BA_CTL_TID_MASK 0xF000 /* tid mask */ -#define DOT11_BA_CTL_TID_SHIFT 12 /* tid shift */ - -/* control frame header (BA/BAR) */ -BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ - struct ether_addr ta; /* transmitter address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */ - -/* BAR frame payload */ -BWL_PRE_PACKED_STRUCT struct dot11_bar { - uint16 bar_control; /* BAR Control */ - uint16 seqnum; /* Starting Sequence control */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_BAR_LEN 4 /* BAR frame payload length */ - -#define DOT11_BA_BITMAP_LEN 128 /* bitmap length */ -#define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */ -/* BA frame payload */ -BWL_PRE_PACKED_STRUCT struct dot11_ba { - uint16 ba_control; /* BA Control */ - uint16 seqnum; /* Starting Sequence control */ - uint8 bitmap[DOT11_BA_BITMAP_LEN]; /* Block Ack Bitmap */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_BA_LEN 4 /* BA frame payload len (wo bitmap) */ - -/* Management frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_management_header { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr da; /* receiver address */ - struct ether_addr sa; /* transmitter address */ - struct ether_addr bssid; /* BSS ID */ - uint16 seq; /* sequence control */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_MGMT_HDR_LEN 24 /* d11 management header length */ - -/* Management frame payloads */ - -BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { - uint32 timestamp[2]; - uint16 beacon_interval; - uint16 capability; -} BWL_POST_PACKED_STRUCT; -#define DOT11_BCN_PRB_LEN 12 /* 802.11 beacon/probe frame fixed length */ -#define DOT11_BCN_PRB_FIXED_LEN 12 /* 802.11 beacon/probe frame fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_auth { - uint16 alg; /* algorithm */ - uint16 seq; /* sequence control */ - uint16 status; /* status code */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge IE */ - -BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { - uint16 capability; /* capability information */ - uint16 listen; /* listen interval */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_ASSOC_REQ_FIXED_LEN 4 /* length of assoc frame without info elts */ - -BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { - uint16 capability; /* capability information */ - uint16 listen; /* listen interval */ - struct ether_addr ap; /* Current AP address */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_REASSOC_REQ_FIXED_LEN 10 /* length of assoc frame without info elts */ - -BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { - uint16 capability; /* capability information */ - uint16 status; /* status code */ - uint16 aid; /* association ID */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_ASSOC_RESP_FIXED_LEN 6 /* length of assoc resp frame without info elts */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_measure { - uint8 category; - uint8 action; - uint8 token; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -#define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { - uint8 category; - uint8 action; - uint8 ch_width; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { - uint8 category; - uint8 action; - uint8 control; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { - uint8 category; - uint8 action; - uint16 id; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { - uint8 category; - uint8 action; - uint8 mode; -} BWL_POST_PACKED_STRUCT; - -#define SM_PWRSAVE_ENABLE 1 -#define SM_PWRSAVE_MODE 2 - -/* ************* 802.11h related definitions. ************* */ -BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { - uint8 id; - uint8 len; - uint8 power; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_power_cnst dot11_power_cnst_t; - -BWL_PRE_PACKED_STRUCT struct dot11_power_cap { - uint8 min; - uint8 max; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_power_cap dot11_power_cap_t; - -BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { - uint8 id; - uint8 len; - uint8 tx_pwr; - uint8 margin; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tpc_rep dot11_tpc_rep_t; -#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */ - -BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { - uint8 id; - uint8 len; - uint8 first_channel; - uint8 num_channels; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_supp_channels dot11_supp_channels_t; - -/* Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband - * offset for 40MHz operation. The possible 3 values are: - * 1 = above control channel - * 3 = below control channel - * 0 = no extension channel - */ -BWL_PRE_PACKED_STRUCT struct dot11_extch { - uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ - uint8 len; /* IE length */ - uint8 extch; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_extch dot11_extch_ie_t; - -BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; - uint8 type; /* type inidicates what follows */ - uint8 extch; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; - -#define BRCM_EXTCH_IE_LEN 5 -#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ -#define DOT11_EXTCH_IE_LEN 1 -#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ -#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ -#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ -#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { - uint8 category; - uint8 action; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -#define DOT11_ACTION_FRMHDR_LEN 2 - -/* CSA IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { - uint8 id; /* id DOT11_MNG_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - uint8 mode; /* mode 0 or 1 */ - uint8 channel; /* channel switch to */ - uint8 count; /* number of beacons before switching */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_channel_switch dot11_chan_switch_ie_t; - -#define DOT11_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ -/* CSA mode - 802.11h-2003 $7.3.2.20 */ -#define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */ -#define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { - uint8 category; - uint8 action; - dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */ - dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */ -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_csa_body { - uint8 mode; /* mode 0 or 1 */ - uint8 reg; /* regulatory class */ - uint8 channel; /* channel switch to */ - uint8 count; /* number of beacons before switching */ -} BWL_POST_PACKED_STRUCT; - -/* 11n Extended Channel Switch IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { - uint8 id; /* id DOT11_MNG_EXT_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - struct dot11_csa_body b; /* body of the ie */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ext_csa dot11_ext_csa_ie_t; -#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { - uint8 category; - uint8 action; - dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { - uint8 category; - uint8 action; - struct dot11_csa_body b; /* body of the ie */ -} BWL_POST_PACKED_STRUCT; - -/* Wide Bandwidth Channel Switch IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - uint8 channel_width; /* new channel width */ - uint8 center_frequency_segment_0; /* center frequency segment 0 */ - uint8 center_frequency_segment_1; /* center frequency segment 1 */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; - -#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ - -/* Channel Switch Wrapper IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; - -/* VHT Transmit Power Envelope IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - uint8 transmit_power_info; - uint8 local_max_transmit_power_20; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; - -/* vht transmit power envelope IE length depends on channel width */ -#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_40MHZ 1 -#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_80MHZ 2 -#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_160MHZ 3 - -BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { - uint8 id; - uint8 len; - uint8 info; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_obss_coex dot11_obss_coex_t; -#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */ - -#define DOT11_OBSS_COEX_INFO_REQ 0x01 -#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 -#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 - -BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { - uint8 id; - uint8 len; - uint8 regclass; - uint8 chanlist[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; -#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */ - -BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { - uint8 id; - uint8 len; - uint8 cap[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_extcap_ie dot11_extcap_ie_t; - -#define DOT11_EXTCAP_LEN_MAX 8 - -#define DOT11_EXTCAP_LEN_COEX 1 -#define DOT11_EXTCAP_LEN_BT 3 -#define DOT11_EXTCAP_LEN_IW 4 -#define DOT11_EXTCAP_LEN_SI 6 - -#define DOT11_EXTCAP_LEN_TDLS 5 -#define DOT11_11AC_EXTCAP_LEN_TDLS 8 - -#define DOT11_EXTCAP_LEN_FMS 2 -#define DOT11_EXTCAP_LEN_PROXY_ARP 2 -#define DOT11_EXTCAP_LEN_TFS 3 -#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 -#define DOT11_EXTCAP_LEN_TIMBC 3 -#define DOT11_EXTCAP_LEN_BSSTRANS 3 -#define DOT11_EXTCAP_LEN_DMS 4 -#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 -#define DOT11_EXTCAP_LEN_TDLS_WBW 8 -#define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8 - -BWL_PRE_PACKED_STRUCT struct dot11_extcap { - uint8 extcap[DOT11_EXTCAP_LEN_MAX]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_extcap dot11_extcap_t; - -/* TDLS Capabilities */ -#define DOT11_TDLS_CAP_TDLS 37 /* TDLS support */ -#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ -#define DOT11_TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ -#define DOT11_TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ -#define DOT11_TDLS_CAP_PROH 38 /* TDLS prohibited */ -#define DOT11_TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ -#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 /* TDLS Wider Band-Width */ - -#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ - -/* 802.11h/802.11k Measurement Request/Report IEs */ -/* Measurement Type field */ -#define DOT11_MEASURE_TYPE_BASIC 0 /* d11 measurement basic type */ -#define DOT11_MEASURE_TYPE_CCA 1 /* d11 measurement CCA type */ -#define DOT11_MEASURE_TYPE_RPI 2 /* d11 measurement RPI type */ -#define DOT11_MEASURE_TYPE_CHLOAD 3 /* d11 measurement Channel Load type */ -#define DOT11_MEASURE_TYPE_NOISE 4 /* d11 measurement Noise Histogram type */ -#define DOT11_MEASURE_TYPE_BEACON 5 /* d11 measurement Beacon type */ -#define DOT11_MEASURE_TYPE_FRAME 6 /* d11 measurement Frame type */ -#define DOT11_MEASURE_TYPE_STAT 7 /* d11 measurement STA Statistics type */ -#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ -#define DOT11_MEASURE_TYPE_TXSTREAM 9 /* d11 measurement TX Stream type */ -#define DOT11_MEASURE_TYPE_PAUSE 255 /* d11 measurement pause type */ - -/* Measurement Request Modes */ -#define DOT11_MEASURE_MODE_PARALLEL (1<<0) /* d11 measurement parallel */ -#define DOT11_MEASURE_MODE_ENABLE (1<<1) /* d11 measurement enable */ -#define DOT11_MEASURE_MODE_REQUEST (1<<2) /* d11 measurement request */ -#define DOT11_MEASURE_MODE_REPORT (1<<3) /* d11 measurement report */ -#define DOT11_MEASURE_MODE_DUR (1<<4) /* d11 measurement dur mandatory */ -/* Measurement Report Modes */ -#define DOT11_MEASURE_MODE_LATE (1<<0) /* d11 measurement late */ -#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) /* d11 measurement incapable */ -#define DOT11_MEASURE_MODE_REFUSED (1<<2) /* d11 measurement refuse */ -/* Basic Measurement Map bits */ -#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) /* d11 measurement basic map BSS */ -#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) /* d11 measurement map OFDM */ -#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) /* d11 measurement map unknown */ -#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) /* d11 measurement map radar */ -#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) /* d11 measurement map unmeasuremnt */ - -BWL_PRE_PACKED_STRUCT struct dot11_meas_req { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 channel; - uint8 start_time[8]; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_meas_req dot11_meas_req_t; -#define DOT11_MNG_IE_MREQ_LEN 14 /* d11 measurement request IE length */ -/* length of Measure Request IE data not including variable len */ -#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 /* d11 measurement request IE fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - BWL_PRE_PACKED_STRUCT union - { - BWL_PRE_PACKED_STRUCT struct { - uint8 channel; - uint8 start_time[8]; - uint16 duration; - uint8 map; - } BWL_POST_PACKED_STRUCT basic; - uint8 data[1]; - } BWL_POST_PACKED_STRUCT rep; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_meas_rep dot11_meas_rep_t; - -/* length of Measure Report IE data not including variable len */ -#define DOT11_MNG_IE_MREP_FIXED_LEN 3 /* d11 measurement response IE fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { - uint8 channel; - uint8 start_time[8]; - uint16 duration; - uint8 map; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; -#define DOT11_MEASURE_BASIC_REP_LEN 12 /* d11 measurement basic report length */ - -BWL_PRE_PACKED_STRUCT struct dot11_quiet { - uint8 id; - uint8 len; - uint8 count; /* TBTTs until beacon interval in quiet starts */ - uint8 period; /* Beacon intervals between periodic quiet periods ? */ - uint16 duration; /* Length of quiet period, in TU's */ - uint16 offset; /* TU's offset from TBTT in Count field */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_quiet dot11_quiet_t; - -BWL_PRE_PACKED_STRUCT struct chan_map_tuple { - uint8 channel; - uint8 map; -} BWL_POST_PACKED_STRUCT; -typedef struct chan_map_tuple chan_map_tuple_t; - -BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { - uint8 id; - uint8 len; - uint8 eaddr[ETHER_ADDR_LEN]; - uint8 interval; - chan_map_tuple_t map[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; - -/* WME Elements */ -#define WME_OUI "\x00\x50\xf2" /* WME OUI */ -#define WME_OUI_LEN 3 -#define WME_OUI_TYPE 2 /* WME type */ -#define WME_TYPE 2 /* WME type, deprecated */ -#define WME_SUBTYPE_IE 0 /* Information Element */ -#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ -#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ -#define WME_VER 1 /* WME version */ - -/* WME Access Category Indices (ACIs) */ -#define AC_BE 0 /* Best Effort */ -#define AC_BK 1 /* Background */ -#define AC_VI 2 /* Video */ -#define AC_VO 3 /* Voice */ -#define AC_COUNT 4 /* number of ACs */ - -typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */ - -#define AC_BITMAP_NONE 0x0 /* No ACs */ -#define AC_BITMAP_ALL 0xf /* All ACs */ -#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) -#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) -#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) - -/* WME Information Element (IE) */ -BWL_PRE_PACKED_STRUCT struct wme_ie { - uint8 oui[3]; - uint8 type; - uint8 subtype; - uint8 version; - uint8 qosinfo; -} BWL_POST_PACKED_STRUCT; -typedef struct wme_ie wme_ie_t; -#define WME_IE_LEN 7 /* WME IE length */ - -BWL_PRE_PACKED_STRUCT struct edcf_acparam { - uint8 ACI; - uint8 ECW; - uint16 TXOP; /* stored in network order (ls octet first) */ -} BWL_POST_PACKED_STRUCT; -typedef struct edcf_acparam edcf_acparam_t; - -/* WME Parameter Element (PE) */ -BWL_PRE_PACKED_STRUCT struct wme_param_ie { - uint8 oui[3]; - uint8 type; - uint8 subtype; - uint8 version; - uint8 qosinfo; - uint8 rsvd; - edcf_acparam_t acparam[AC_COUNT]; -} BWL_POST_PACKED_STRUCT; -typedef struct wme_param_ie wme_param_ie_t; -#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ - -/* QoS Info field for IE as sent from AP */ -#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ -#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ -#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ -#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ - -/* QoS Info field for IE as sent from STA */ -#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ -#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ -#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ -#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ -#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ -#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ -#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ -#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ -#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ -#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ -#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ -#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ - -/* ACI */ -#define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */ -#define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */ -#define EDCF_AIFSN_MASK 0x0f /* AIFSN mask */ -#define EDCF_ACM_MASK 0x10 /* ACM mask */ -#define EDCF_ACI_MASK 0x60 /* ACI mask */ -#define EDCF_ACI_SHIFT 5 /* ACI shift */ -#define EDCF_AIFSN_SHIFT 12 /* 4 MSB(0xFFF) in ifs_ctl for AC idx */ - -/* ECW */ -#define EDCF_ECW_MIN 0 /* cwmin/cwmax exponent minimum value */ -#define EDCF_ECW_MAX 15 /* cwmin/cwmax exponent maximum value */ -#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) -#define EDCF_ECWMIN_MASK 0x0f /* cwmin exponent form mask */ -#define EDCF_ECWMAX_MASK 0xf0 /* cwmax exponent form mask */ -#define EDCF_ECWMAX_SHIFT 4 /* cwmax exponent form shift */ - -/* TXOP */ -#define EDCF_TXOP_MIN 0 /* TXOP minimum value */ -#define EDCF_TXOP_MAX 65535 /* TXOP maximum value */ -#define EDCF_TXOP2USEC(txop) ((txop) << 5) - -/* Default BE ACI value for non-WME connection STA */ -#define NON_EDCF_AC_BE_ACI_STA 0x02 - -/* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */ -#define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */ -#define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */ -#define EDCF_AC_BE_TXOP_STA 0x0000 /* STA TXOP value for best effort AC */ -#define EDCF_AC_BK_ACI_STA 0x27 /* STA ACI value for background AC */ -#define EDCF_AC_BK_ECW_STA 0xA4 /* STA ECW value for background AC */ -#define EDCF_AC_BK_TXOP_STA 0x0000 /* STA TXOP value for background AC */ -#define EDCF_AC_VI_ACI_STA 0x42 /* STA ACI value for video AC */ -#define EDCF_AC_VI_ECW_STA 0x43 /* STA ECW value for video AC */ -#define EDCF_AC_VI_TXOP_STA 0x005e /* STA TXOP value for video AC */ -#define EDCF_AC_VO_ACI_STA 0x62 /* STA ACI value for audio AC */ -#define EDCF_AC_VO_ECW_STA 0x32 /* STA ECW value for audio AC */ -#define EDCF_AC_VO_TXOP_STA 0x002f /* STA TXOP value for audio AC */ - -/* Default EDCF parameters that AP uses; WMM draft Table 14 */ -#define EDCF_AC_BE_ACI_AP 0x03 /* AP ACI value for best effort AC */ -#define EDCF_AC_BE_ECW_AP 0x64 /* AP ECW value for best effort AC */ -#define EDCF_AC_BE_TXOP_AP 0x0000 /* AP TXOP value for best effort AC */ -#define EDCF_AC_BK_ACI_AP 0x27 /* AP ACI value for background AC */ -#define EDCF_AC_BK_ECW_AP 0xA4 /* AP ECW value for background AC */ -#define EDCF_AC_BK_TXOP_AP 0x0000 /* AP TXOP value for background AC */ -#define EDCF_AC_VI_ACI_AP 0x41 /* AP ACI value for video AC */ -#define EDCF_AC_VI_ECW_AP 0x43 /* AP ECW value for video AC */ -#define EDCF_AC_VI_TXOP_AP 0x005e /* AP TXOP value for video AC */ -#define EDCF_AC_VO_ACI_AP 0x61 /* AP ACI value for audio AC */ -#define EDCF_AC_VO_ECW_AP 0x32 /* AP ECW value for audio AC */ -#define EDCF_AC_VO_TXOP_AP 0x002f /* AP TXOP value for audio AC */ - -/* EDCA Parameter IE */ -BWL_PRE_PACKED_STRUCT struct edca_param_ie { - uint8 qosinfo; - uint8 rsvd; - edcf_acparam_t acparam[AC_COUNT]; -} BWL_POST_PACKED_STRUCT; -typedef struct edca_param_ie edca_param_ie_t; -#define EDCA_PARAM_IE_LEN 18 /* EDCA Parameter IE length */ - -/* QoS Capability IE */ -BWL_PRE_PACKED_STRUCT struct qos_cap_ie { - uint8 qosinfo; -} BWL_POST_PACKED_STRUCT; -typedef struct qos_cap_ie qos_cap_ie_t; - -BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { - uint8 id; /* 11, DOT11_MNG_QBSS_LOAD_ID */ - uint8 length; - uint16 station_count; /* total number of STAs associated */ - uint8 channel_utilization; /* % of time, normalized to 255, QAP sensed medium busy */ - uint16 aac; /* available admission capacity */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; -#define BSS_LOAD_IE_SIZE 7 /* BSS load IE size */ - -/* nom_msdu_size */ -#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */ -#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */ - -/* surplus_bandwidth */ -/* Represented as 3 bits of integer, binary point, 13 bits fraction */ -#define INTEGER_SHIFT 13 /* integer shift */ -#define FRACTION_MASK 0x1FFF /* fraction mask */ - -/* Management Notification Frame */ -BWL_PRE_PACKED_STRUCT struct dot11_management_notification { - uint8 category; /* DOT11_ACTION_NOTIFICATION */ - uint8 action; - uint8 token; - uint8 status; - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */ - -/* Timeout Interval IE */ -BWL_PRE_PACKED_STRUCT struct ti_ie { - uint8 ti_type; - uint32 ti_val; -} BWL_POST_PACKED_STRUCT; -typedef struct ti_ie ti_ie_t; -#define TI_TYPE_REASSOC_DEADLINE 1 -#define TI_TYPE_KEY_LIFETIME 2 - -/* WME Action Codes */ -#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ -#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ -#define WME_DELTS_REQUEST 2 /* WME DELTS request */ - -/* WME Setup Response Status Codes */ -#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ -#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ -#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ - -/* Macro to take a pointer to a beacon or probe response - * body and return the char* pointer to the SSID info element - */ -#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) - -/* Authentication frame payload constants */ -#define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */ -#define DOT11_SHARED_KEY 1 /* d11 shared authentication */ -#define DOT11_FAST_BSS 2 /* d11 fast bss authentication */ -#define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */ - -/* Frame control macros */ -#define FC_PVER_MASK 0x3 /* PVER mask */ -#define FC_PVER_SHIFT 0 /* PVER shift */ -#define FC_TYPE_MASK 0xC /* type mask */ -#define FC_TYPE_SHIFT 2 /* type shift */ -#define FC_SUBTYPE_MASK 0xF0 /* subtype mask */ -#define FC_SUBTYPE_SHIFT 4 /* subtype shift */ -#define FC_TODS 0x100 /* to DS */ -#define FC_TODS_SHIFT 8 /* to DS shift */ -#define FC_FROMDS 0x200 /* from DS */ -#define FC_FROMDS_SHIFT 9 /* from DS shift */ -#define FC_MOREFRAG 0x400 /* more frag. */ -#define FC_MOREFRAG_SHIFT 10 /* more frag. shift */ -#define FC_RETRY 0x800 /* retry */ -#define FC_RETRY_SHIFT 11 /* retry shift */ -#define FC_PM 0x1000 /* PM */ -#define FC_PM_SHIFT 12 /* PM shift */ -#define FC_MOREDATA 0x2000 /* more data */ -#define FC_MOREDATA_SHIFT 13 /* more data shift */ -#define FC_WEP 0x4000 /* WEP */ -#define FC_WEP_SHIFT 14 /* WEP shift */ -#define FC_ORDER 0x8000 /* order */ -#define FC_ORDER_SHIFT 15 /* order shift */ - -/* sequence control macros */ -#define SEQNUM_SHIFT 4 /* seq. number shift */ -#define SEQNUM_MAX 0x1000 /* max seqnum + 1 */ -#define FRAGNUM_MASK 0xF /* frag. number mask */ - -/* Frame Control type/subtype defs */ - -/* FC Types */ -#define FC_TYPE_MNG 0 /* management type */ -#define FC_TYPE_CTL 1 /* control type */ -#define FC_TYPE_DATA 2 /* data type */ - -/* Management Subtypes */ -#define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */ -#define FC_SUBTYPE_ASSOC_RESP 1 /* assoc. response */ -#define FC_SUBTYPE_REASSOC_REQ 2 /* reassoc. request */ -#define FC_SUBTYPE_REASSOC_RESP 3 /* reassoc. response */ -#define FC_SUBTYPE_PROBE_REQ 4 /* probe request */ -#define FC_SUBTYPE_PROBE_RESP 5 /* probe response */ -#define FC_SUBTYPE_BEACON 8 /* beacon */ -#define FC_SUBTYPE_ATIM 9 /* ATIM */ -#define FC_SUBTYPE_DISASSOC 10 /* disassoc. */ -#define FC_SUBTYPE_AUTH 11 /* authentication */ -#define FC_SUBTYPE_DEAUTH 12 /* de-authentication */ -#define FC_SUBTYPE_ACTION 13 /* action */ -#define FC_SUBTYPE_ACTION_NOACK 14 /* action no-ack */ - -/* Control Subtypes */ -#define FC_SUBTYPE_CTL_WRAPPER 7 /* Control Wrapper */ -#define FC_SUBTYPE_BLOCKACK_REQ 8 /* Block Ack Req */ -#define FC_SUBTYPE_BLOCKACK 9 /* Block Ack */ -#define FC_SUBTYPE_PS_POLL 10 /* PS poll */ -#define FC_SUBTYPE_RTS 11 /* RTS */ -#define FC_SUBTYPE_CTS 12 /* CTS */ -#define FC_SUBTYPE_ACK 13 /* ACK */ -#define FC_SUBTYPE_CF_END 14 /* CF-END */ -#define FC_SUBTYPE_CF_END_ACK 15 /* CF-END ACK */ - -/* Data Subtypes */ -#define FC_SUBTYPE_DATA 0 /* Data */ -#define FC_SUBTYPE_DATA_CF_ACK 1 /* Data + CF-ACK */ -#define FC_SUBTYPE_DATA_CF_POLL 2 /* Data + CF-Poll */ -#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 /* Data + CF-Ack + CF-Poll */ -#define FC_SUBTYPE_NULL 4 /* Null */ -#define FC_SUBTYPE_CF_ACK 5 /* CF-Ack */ -#define FC_SUBTYPE_CF_POLL 6 /* CF-Poll */ -#define FC_SUBTYPE_CF_ACK_POLL 7 /* CF-Ack + CF-Poll */ -#define FC_SUBTYPE_QOS_DATA 8 /* QoS Data */ -#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 /* QoS Data + CF-Ack */ -#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 /* QoS Data + CF-Poll */ -#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 /* QoS Data + CF-Ack + CF-Poll */ -#define FC_SUBTYPE_QOS_NULL 12 /* QoS Null */ -#define FC_SUBTYPE_QOS_CF_POLL 14 /* QoS CF-Poll */ -#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 /* QoS CF-Ack + CF-Poll */ - -/* Data Subtype Groups */ -#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) -#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) -#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) -#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) -#define FC_SUBTYPE_ANY_PSPOLL(s) (((s) & 10) != 0) - -/* Type/Subtype Combos */ -#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */ - -#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) /* FC kind */ - -#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) /* Subtype from FC */ -#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) /* Type from FC */ - -#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) /* assoc. request */ -#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) /* assoc. response */ -#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) /* reassoc. request */ -#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) /* reassoc. response */ -#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) /* probe request */ -#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) /* probe response */ -#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) /* beacon */ -#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) /* disassoc */ -#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) /* authentication */ -#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) /* deauthentication */ -#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) /* action */ -#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) /* action no-ack */ - -#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) /* Control Wrapper */ -#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) /* Block Ack Req */ -#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) /* Block Ack */ -#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) /* PS poll */ -#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) /* RTS */ -#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) /* CTS */ -#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) /* ACK */ -#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) /* CF-END */ -#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) /* CF-END ACK */ - -#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) /* data */ -#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) /* null data */ -#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) /* data CF ACK */ -#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) /* QoS data */ -#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) /* QoS null */ - -/* QoS Control Field */ - -/* 802.1D Priority */ -#define QOS_PRIO_SHIFT 0 /* QoS priority shift */ -#define QOS_PRIO_MASK 0x0007 /* QoS priority mask */ -#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) /* QoS priority */ - -/* Traffic Identifier */ -#define QOS_TID_SHIFT 0 /* QoS TID shift */ -#define QOS_TID_MASK 0x000f /* QoS TID mask */ -#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) /* QoS TID */ - -/* End of Service Period (U-APSD) */ -#define QOS_EOSP_SHIFT 4 /* QoS End of Service Period shift */ -#define QOS_EOSP_MASK 0x0010 /* QoS End of Service Period mask */ -#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) /* Qos EOSP */ - -/* Ack Policy */ -#define QOS_ACK_NORMAL_ACK 0 /* Normal Ack */ -#define QOS_ACK_NO_ACK 1 /* No Ack (eg mcast) */ -#define QOS_ACK_NO_EXP_ACK 2 /* No Explicit Ack */ -#define QOS_ACK_BLOCK_ACK 3 /* Block Ack */ -#define QOS_ACK_SHIFT 5 /* QoS ACK shift */ -#define QOS_ACK_MASK 0x0060 /* QoS ACK mask */ -#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) /* QoS ACK */ - -/* A-MSDU flag */ -#define QOS_AMSDU_SHIFT 7 /* AMSDU shift */ -#define QOS_AMSDU_MASK 0x0080 /* AMSDU mask */ - -/* Management Frames */ - -/* Management Frame Constants */ - -/* Fixed fields */ -#define DOT11_MNG_AUTH_ALGO_LEN 2 /* d11 management auth. algo. length */ -#define DOT11_MNG_AUTH_SEQ_LEN 2 /* d11 management auth. seq. length */ -#define DOT11_MNG_BEACON_INT_LEN 2 /* d11 management beacon interval length */ -#define DOT11_MNG_CAP_LEN 2 /* d11 management cap. length */ -#define DOT11_MNG_AP_ADDR_LEN 6 /* d11 management AP address length */ -#define DOT11_MNG_LISTEN_INT_LEN 2 /* d11 management listen interval length */ -#define DOT11_MNG_REASON_LEN 2 /* d11 management reason length */ -#define DOT11_MNG_AID_LEN 2 /* d11 management AID length */ -#define DOT11_MNG_STATUS_LEN 2 /* d11 management status length */ -#define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */ - -/* DUR/ID field in assoc resp is 0xc000 | AID */ -#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ - -/* Reason Codes */ -#define DOT11_RC_RESERVED 0 /* d11 RC reserved */ -#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */ -#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */ -#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station - * is leaving (or has left) IBSS or ESS - */ -#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */ -#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle - * all currently associated stations - */ -#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from - * nonauthenticated station - */ -#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from - * nonassociated station - */ -#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is - * leaving (or has left) BSS - */ -#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is not - * authenticated with responding station - */ -#define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */ -#define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */ -/* 12 is unused */ - -/* 32-39 are QSTA specific reasons added in 11e */ -#define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */ -#define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */ -#define DOT11_RC_EXCESSIVE_FRAMES 34 /* excessive number of frames need ack */ -#define DOT11_RC_TX_OUTSIDE_TXOP 35 /* transmitting outside the limits of txop */ -#define DOT11_RC_LEAVING_QBSS 36 /* QSTA is leaving the QBSS (or restting) */ -#define DOT11_RC_BAD_MECHANISM 37 /* does not want to use the mechanism */ -#define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */ -#define DOT11_RC_TIMEOUT 39 /* timeout */ - -#define DOT11_RC_MAX 23 /* Reason codes > 23 are reserved */ - -#define DOT11_RC_TDLS_PEER_UNREACH 25 -#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 - -/* Status Codes */ -#define DOT11_SC_SUCCESS 0 /* Successful */ -#define DOT11_SC_FAILURE 1 /* Unspecified failure */ -#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but alternative */ - /* schedule provided */ -#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */ -#define DOT11_SC_TDLS_SEC_DISABLED 5 /* TDLS Security disabled */ -#define DOT11_SC_LIFETIME_REJ 6 /* Unacceptable lifetime */ -#define DOT11_SC_NOT_SAME_BSS 7 /* Not in same BSS */ -#define DOT11_SC_CAP_MISMATCH 10 /* Cannot support all requested - * capabilities in the Capability - * Information field - */ -#define DOT11_SC_REASSOC_FAIL 11 /* Reassociation denied due to inability - * to confirm that association exists - */ -#define DOT11_SC_ASSOC_FAIL 12 /* Association denied due to reason - * outside the scope of this standard - */ -#define DOT11_SC_AUTH_MISMATCH 13 /* Responding station does not support - * the specified authentication - * algorithm - */ -#define DOT11_SC_AUTH_SEQ 14 /* Received an Authentication frame - * with authentication transaction - * sequence number out of expected - * sequence - */ -#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of - * challenge failure - */ -#define DOT11_SC_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout - * waiting for next frame in sequence - */ -#define DOT11_SC_ASSOC_BUSY_FAIL 17 /* Association denied because AP is - * unable to handle additional - * associated stations - */ -#define DOT11_SC_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting - * station not supporting all of the - * data rates in the BSSBasicRateSet - * parameter - */ -#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting - * station not supporting the Short - * Preamble option - */ -#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting - * station not supporting the PBCC - * Modulation option - */ -#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting - * station not supporting the Channel - * Agility option - */ -#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum - * Management capability is required. - */ -#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info - * in the Power Cap element is - * unacceptable. - */ -#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info - * in the Supported Channel element is - * unacceptable - */ -#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting - * station not supporting the Short Slot - * Time option - */ -#define DOT11_SC_ASSOC_DSSSOFDM_REQUIRED 26 /* Association denied because requesting station - * does not support the DSSS-OFDM option - */ -#define DOT11_SC_ASSOC_HT_REQUIRED 27 /* Association denied because the requesting - * station does not support HT features - */ -#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 /* Association denied due to AP - * being unable to reach the R0 Key Holder - */ -#define DOT11_SC_ASSOC_TRY_LATER 30 /* Association denied temporarily, try again later - */ -#define DOT11_SC_ASSOC_MFP_VIOLATION 31 /* Association denied due to Robust Management - * frame policy violation - */ - -#define DOT11_SC_DECLINED 37 /* request declined */ -#define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ -#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */ -#define DOT11_SC_INVALID_AKMP 43 /* Association denied due to invalid AKMP */ -#define DOT11_SC_INVALID_RSNIE_CAP 45 /* invalid RSN IE capabilities */ -#define DOT11_SC_DLS_NOT_ALLOWED 48 /* DLS is not allowed in the BSS by policy */ -#define DOT11_SC_INVALID_PMKID 53 /* Association denied due to invalid PMKID */ -#define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */ -#define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */ - -#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 /* ad proto not supported */ -#define DOT11_SC_NO_OUTSTAND_REQ 60 /* no outstanding req */ -#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 /* no response from server */ -#define DOT11_SC_TIMEOUT 62 /* timeout */ -#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 /* query rsp too large */ -#define DOT11_SC_SERVER_UNREACHABLE 65 /* server unreachable */ - -#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ -#define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */ -#define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */ -#define DOT11_SC_ASSOC_VHT_REQUIRED 104 /* Association denied because the requesting - * station does not support VHT features. - */ - -#define DOT11_SC_TRANSMIT_FAILURE 79 /* transmission failure */ - -/* Info Elts, length of INFORMATION portion of Info Elts */ -#define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ -#define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */ - -/* TIM Info element has 3 bytes fixed info in INFORMATION field, - * followed by 1 to 251 bytes of Partial Virtual Bitmap - */ -#define DOT11_MNG_TIM_FIXED_LEN 3 /* d11 management TIM fixed length */ -#define DOT11_MNG_TIM_DTIM_COUNT 0 /* d11 management DTIM count */ -#define DOT11_MNG_TIM_DTIM_PERIOD 1 /* d11 management DTIM period */ -#define DOT11_MNG_TIM_BITMAP_CTL 2 /* d11 management TIM BITMAP control */ -#define DOT11_MNG_TIM_PVB 3 /* d11 management TIM PVB */ - -/* TLV defines */ -#define TLV_TAG_OFF 0 /* tag offset */ -#define TLV_LEN_OFF 1 /* length offset */ -#define TLV_HDR_LEN 2 /* header length */ -#define TLV_BODY_OFF 2 /* body offset */ -#define TLV_BODY_LEN_MAX 255 /* max body length */ - -/* Management Frame Information Element IDs */ -#define DOT11_MNG_SSID_ID 0 /* d11 management SSID id */ -#define DOT11_MNG_RATES_ID 1 /* d11 management rates id */ -#define DOT11_MNG_FH_PARMS_ID 2 /* d11 management FH parameter id */ -#define DOT11_MNG_DS_PARMS_ID 3 /* d11 management DS parameter id */ -#define DOT11_MNG_CF_PARMS_ID 4 /* d11 management CF parameter id */ -#define DOT11_MNG_TIM_ID 5 /* d11 management TIM id */ -#define DOT11_MNG_IBSS_PARMS_ID 6 /* d11 management IBSS parameter id */ -#define DOT11_MNG_COUNTRY_ID 7 /* d11 management country id */ -#define DOT11_MNG_HOPPING_PARMS_ID 8 /* d11 management hopping parameter id */ -#define DOT11_MNG_HOPPING_TABLE_ID 9 /* d11 management hopping table id */ -#define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */ -#define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */ -#define DOT11_MNG_EDCA_PARAM_ID 12 /* 11E EDCA Parameter id */ -#define DOT11_MNG_TSPEC_ID 13 /* d11 management TSPEC id */ -#define DOT11_MNG_TCLAS_ID 14 /* d11 management TCLAS id */ -#define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */ -#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */ -#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */ -#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */ -#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */ -#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */ -#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement */ -#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ -#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */ -#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */ -#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */ -#define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */ -#define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */ -#define DOT11_MNG_TCLAS_PROC_ID 44 /* d11 management TCLAS processing id */ -#define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */ -#define DOT11_MNG_QOS_CAP_ID 46 /* 11E QoS Capability id */ -#define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */ -#define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */ -#define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */ -#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */ -#define DOT11_MNG_NEIGHBOR_REP_ID 52 /* 11k & 11v Neighbor report id */ -#define DOT11_MNG_RCPI_ID 53 /* 11k RCPI */ -#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */ -#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */ -#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */ -#define DOT11_MNG_RDE_ID 57 /* 11r RIC Data Element id */ -#define DOT11_MNG_REGCLASS_ID 59 /* d11 management regulatory class id */ -#define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */ -#define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */ -#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */ -#define DOT11_MNG_BSS_AVR_ACCESS_DELAY_ID 63 /* 11k bss average access delay */ -#define DOT11_MNG_ANTENNA_ID 64 /* 11k antenna id */ -#define DOT11_MNG_RSNI_ID 65 /* 11k RSNI id */ -#define DOT11_MNG_MEASUREMENT_PILOT_TX_ID 66 /* 11k measurement pilot tx info id */ -#define DOT11_MNG_BSS_AVAL_ADMISSION_CAP_ID 67 /* 11k bss aval admission cap id */ -#define DOT11_MNG_BSS_AC_ACCESS_DELAY_ID 68 /* 11k bss AC access delay id */ -#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ -#define DOT11_MNG_TIME_ADVERTISE_ID 69 /* 11p time advertisement */ -#define DOT11_MNG_RRM_CAP_ID 70 /* 11k radio measurement capability */ -#define DOT11_MNG_MULTIPLE_BSSID_ID 71 /* 11k multiple BSSID id */ -#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 /* d11 mgmt OBSS Coexistence INFO */ -#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 /* d11 mgmt OBSS Intolerant Channel list */ -#define DOT11_MNG_HT_OBSS_ID 74 /* d11 mgmt OBSS HT info */ -#define DOT11_MNG_MMIE_ID 76 /* d11 mgmt MIC IE */ -#define DOT11_MNG_FMS_DESCR_ID 86 /* 11v FMS descriptor */ -#define DOT11_MNG_FMS_REQ_ID 87 /* 11v FMS request id */ -#define DOT11_MNG_FMS_RESP_ID 88 /* 11v FMS response id */ -#define DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID 90 /* 11v bss max idle id */ -#define DOT11_MNG_TFS_REQUEST_ID 91 /* 11v tfs request id */ -#define DOT11_MNG_TFS_RESPONSE_ID 92 /* 11v tfs response id */ -#define DOT11_MNG_WNM_SLEEP_MODE_ID 93 /* 11v wnm-sleep mode id */ -#define DOT11_MNG_TIMBC_REQ_ID 94 /* 11v TIM broadcast request id */ -#define DOT11_MNG_TIMBC_RESP_ID 95 /* 11v TIM broadcast response id */ -#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */ -#define DOT11_MNG_TIME_ZONE_ID 98 /* 11v time zone */ -#define DOT11_MNG_DMS_REQUEST_ID 99 /* 11v dms request id */ -#define DOT11_MNG_DMS_RESPONSE_ID 100 /* 11v dms response id */ -#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */ -#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */ -#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */ -#define DOT11_MNG_PTI_CONTROL_ID 105 /* 11z TDLS PTI Control IE */ -#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 /* 11z TDLS PU Buffer Status IE */ -#define DOT11_MNG_INTERWORKING_ID 107 /* 11u interworking */ -#define DOT11_MNG_ADVERTISEMENT_ID 108 /* 11u advertisement protocol */ -#define DOT11_MNG_EXP_BW_REQ_ID 109 /* 11u expedited bandwith request */ -#define DOT11_MNG_QOS_MAP_ID 110 /* 11u QoS map set */ -#define DOT11_MNG_ROAM_CONSORT_ID 111 /* 11u roaming consortium */ -#define DOT11_MNG_EMERGCY_ALERT_ID 112 /* 11u emergency alert identifier */ -#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */ -#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */ -#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */ -#define DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID 194 /* Wide BW Channel Switch IE */ -#define DOT11_MNG_VHT_TRANSMIT_POWER_ENVELOPE_ID 195 /* VHT transmit Power Envelope IE */ -#define DOT11_MNG_CHANNEL_SWITCH_WRAPPER_ID 196 /* Channel Switch Wrapper IE */ -#define DOT11_MNG_AID_ID 197 /* Association ID IE */ -#define DOT11_MNG_OPER_MODE_NOTIF_ID 199 /* d11 mgmt VHT oper mode notif */ - - -#define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */ -#define DOT11_MNG_PROPR_ID 221 -/* should start using this one instead of above two */ -#define DOT11_MNG_VS_ID 221 /* d11 management Vendor Specific IE */ - -/* Rate Defines */ - -/* Valid rates for the Supported Rates and Extended Supported Rates IEs. - * Encoding is the rate in 500kbps units, rouding up for fractional values. - * 802.11-2012, section 6.5.5.2, DATA_RATE parameter enumerates all the values. - * The rate values cover DSSS, HR/DSSS, ERP, and OFDM phy rates. - * The defines below do not cover the rates specific to 10MHz, {3, 4.5, 27}, - * and 5MHz, {1.5, 2.25, 3, 4.5, 13.5}, which are not supported by Broadcom devices. - */ - -#define DOT11_RATE_1M 2 /* 1 Mbps in 500kbps units */ -#define DOT11_RATE_2M 4 /* 2 Mbps in 500kbps units */ -#define DOT11_RATE_5M5 11 /* 5.5 Mbps in 500kbps units */ -#define DOT11_RATE_11M 22 /* 11 Mbps in 500kbps units */ -#define DOT11_RATE_6M 12 /* 6 Mbps in 500kbps units */ -#define DOT11_RATE_9M 18 /* 9 Mbps in 500kbps units */ -#define DOT11_RATE_12M 24 /* 12 Mbps in 500kbps units */ -#define DOT11_RATE_18M 36 /* 18 Mbps in 500kbps units */ -#define DOT11_RATE_24M 48 /* 24 Mbps in 500kbps units */ -#define DOT11_RATE_36M 72 /* 36 Mbps in 500kbps units */ -#define DOT11_RATE_48M 96 /* 48 Mbps in 500kbps units */ -#define DOT11_RATE_54M 108 /* 54 Mbps in 500kbps units */ -#define DOT11_RATE_MAX 108 /* highest rate (54 Mbps) in 500kbps units */ - -/* Supported Rates and Extended Supported Rates IEs - * The supported rates octets are defined a the MSB indicatin a Basic Rate - * and bits 0-6 as the rate value - */ -#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ -#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ - -/* BSS Membership Selector parameters - * 802.11-2012 and 802.11ac_D4.0 sec 8.4.2.3 - * These selector values are advertised in Supported Rates and Extended Supported Rates IEs - * in the supported rates list with the Basic rate bit set. - * Constants below include the basic bit. - */ -#define DOT11_BSS_MEMBERSHIP_HT 0xFF /* Basic 0x80 + 127, HT Required to join */ -#define DOT11_BSS_MEMBERSHIP_VHT 0xFE /* Basic 0x80 + 126, VHT Required to join */ - -/* ERP info element bit values */ -#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ -#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present - *in the BSS - */ -#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for - *ERP-OFDM frames - */ -#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, - * 1 == not allowed - */ -/* TS Delay element offset & size */ -#define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */ -#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ - -/* Capability Information Field */ -#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */ -#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */ -#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */ -#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */ -#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */ -#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */ -#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ -#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ -#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ -#define DOT11_CAP_QOS 0x0200 /* d11 cap. qos */ -#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ -#define DOT11_CAP_APSD 0x0800 /* d11 cap. apsd */ -#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ -#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ -#define DOT11_CAP_DELAY_BA 0x4000 /* d11 cap. delayed block ack */ -#define DOT11_CAP_IMMEDIATE_BA 0x8000 /* d11 cap. immediate block ack */ - -/* Extended capabilities IE bitfields */ -/* 20/40 BSS Coexistence Management support bit position */ -#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 -/* Extended Channel Switching support bit position */ -#define DOT11_EXT_CAP_EXT_CHAN_SWITCHING 2 -/* scheduled PSMP support bit position */ -#define DOT11_EXT_CAP_SPSMP 6 -/* Flexible Multicast Service */ -#define DOT11_EXT_CAP_FMS 11 -/* proxy ARP service support bit position */ -#define DOT11_EXT_CAP_PROXY_ARP 12 -/* Traffic Filter Service */ -#define DOT11_EXT_CAP_TFS 16 -/* WNM-Sleep Mode */ -#define DOT11_EXT_CAP_WNM_SLEEP 17 -/* TIM Broadcast service */ -#define DOT11_EXT_CAP_TIMBC 18 -/* BSS Transition Management support bit position */ -#define DOT11_EXT_CAP_BSSTRANS_MGMT 19 -/* Direct Multicast Service */ -#define DOT11_EXT_CAP_DMS 26 -/* Interworking support bit position */ -#define DOT11_EXT_CAP_IW 31 -/* service Interval granularity bit position and mask */ -#define DOT11_EXT_CAP_SI 41 -#define DOT11_EXT_CAP_SI_MASK 0x0E -/* WNM notification */ -#define DOT11_EXT_CAP_WNM_NOTIF 46 -/* Operating mode notification - VHT (11ac D3.0 - 8.4.2.29) */ -#define DOT11_EXT_CAP_OPER_MODE_NOTIF 62 - -/* VHT Operating mode bit fields - (11ac D3.0 - 8.4.1.50) */ -#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 -#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 -#define DOT11_OPER_MODE_RXNSS_SHIFT 4 -#define DOT11_OPER_MODE_RXNSS_MASK 0x70 -#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 -#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 - -#define DOT11_OPER_MODE(type, nss, chanw) (\ - ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ - DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ - (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ - ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ - DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) - -#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ - (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ - >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) -#define DOT11_OPER_MODE_RXNSS(mode) \ - ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ - >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) -#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ - (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ - >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) - -#define DOT11_OPER_MODE_20MHZ 0 -#define DOT11_OPER_MODE_40MHZ 1 -#define DOT11_OPER_MODE_80MHZ 2 -#define DOT11_OPER_MODE_160MHZ 3 -#define DOT11_OPER_MODE_8080MHZ 3 - -#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ) - -/* Operating mode information element 802.11ac D3.0 - 8.4.2.168 */ -BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { - uint8 mode; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; - -#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 - -/* Extended Capability Information Field */ -#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 /* 20/40 BSS Coexistence Management support */ - -/* - * Action Frame Constants - */ -#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action field */ -#define DOT11_ACTION_CAT_OFF 0 /* category offset */ -#define DOT11_ACTION_ACT_OFF 1 /* action offset */ - -/* Action Category field (sec 8.4.1.11) */ -#define DOT11_ACTION_CAT_ERR_MASK 0x80 /* category error mask */ -#define DOT11_ACTION_CAT_MASK 0x7F /* category mask */ -#define DOT11_ACTION_CAT_SPECT_MNG 0 /* category spectrum management */ -#define DOT11_ACTION_CAT_QOS 1 /* category QoS */ -#define DOT11_ACTION_CAT_DLS 2 /* category DLS */ -#define DOT11_ACTION_CAT_BLOCKACK 3 /* category block ack */ -#define DOT11_ACTION_CAT_PUBLIC 4 /* category public */ -#define DOT11_ACTION_CAT_RRM 5 /* category radio measurements */ -#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */ -#define DOT11_ACTION_CAT_HT 7 /* category for HT */ -#define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */ -#define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */ -#define DOT11_ACTION_CAT_WNM 10 /* category for WNM */ -#define DOT11_ACTION_CAT_UWNM 11 /* category for Unprotected WNM */ -#define DOT11_ACTION_NOTIFICATION 17 -#define DOT11_ACTION_CAT_VHT 21 /* VHT action */ -#define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */ -#define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */ - -/* Spectrum Management Action IDs (sec 7.4.1) */ -#define DOT11_SM_ACTION_M_REQ 0 /* d11 action measurement request */ -#define DOT11_SM_ACTION_M_REP 1 /* d11 action measurement response */ -#define DOT11_SM_ACTION_TPC_REQ 2 /* d11 action TPC request */ -#define DOT11_SM_ACTION_TPC_REP 3 /* d11 action TPC response */ -#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ -#define DOT11_SM_ACTION_EXT_CSA 5 /* d11 extened CSA for 11n */ - -/* HT action ids */ -#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ -#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ - -/* Public action ids */ -#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 /* 20/40 Coexistence Management action id */ -#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ -#define DOT11_PUB_ACTION_GAS_CB_REQ 12 /* GAS Comeback Request */ - -/* Block Ack action types */ -#define DOT11_BA_ACTION_ADDBA_REQ 0 /* ADDBA Req action frame type */ -#define DOT11_BA_ACTION_ADDBA_RESP 1 /* ADDBA Resp action frame type */ -#define DOT11_BA_ACTION_DELBA 2 /* DELBA action frame type */ - -/* ADDBA action parameters */ -#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 /* AMSDU supported under BA */ -#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 /* policy mask(ack vs delayed) */ -#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 /* policy shift */ -#define DOT11_ADDBA_PARAM_TID_MASK 0x003c /* tid mask */ -#define DOT11_ADDBA_PARAM_TID_SHIFT 2 /* tid shift */ -#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 /* buffer size mask */ -#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 /* buffer size shift */ - -#define DOT11_ADDBA_POLICY_DELAYED 0 /* delayed BA policy */ -#define DOT11_ADDBA_POLICY_IMMEDIATE 1 /* immediate BA policy */ - -/* Fast Transition action types */ -#define DOT11_FT_ACTION_FT_RESERVED 0 -#define DOT11_FT_ACTION_FT_REQ 1 /* FBT request - for over-the-DS FBT */ -#define DOT11_FT_ACTION_FT_RES 2 /* FBT response - for over-the-DS FBT */ -#define DOT11_FT_ACTION_FT_CON 3 /* FBT confirm - for OTDS with RRP */ -#define DOT11_FT_ACTION_FT_ACK 4 /* FBT ack */ - -/* DLS action types */ -#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */ -#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */ -#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */ - -/* Wireless Network Management (WNM) action types */ -#define DOT11_WNM_ACTION_EVENT_REQ 0 -#define DOT11_WNM_ACTION_EVENT_REP 1 -#define DOT11_WNM_ACTION_DIAG_REQ 2 -#define DOT11_WNM_ACTION_DIAG_REP 3 -#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 -#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 -#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6 -#define DOT11_WNM_ACTION_BSSTRANS_REQ 7 -#define DOT11_WNM_ACTION_BSSTRANS_RESP 8 -#define DOT11_WNM_ACTION_FMS_REQ 9 -#define DOT11_WNM_ACTION_FMS_RESP 10 -#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 -#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 -#define DOT11_WNM_ACTION_TFS_REQ 13 -#define DOT11_WNM_ACTION_TFS_RESP 14 -#define DOT11_WNM_ACTION_TFS_NOTIFY_REQ 15 -#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 -#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 -#define DOT11_WNM_ACTION_TIMBC_REQ 18 -#define DOT11_WNM_ACTION_TIMBC_RESP 19 -#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 -#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 -#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 -#define DOT11_WNM_ACTION_DMS_REQ 23 -#define DOT11_WNM_ACTION_DMS_RESP 24 -#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 -#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 -#define DOT11_WNM_ACTION_NOTFCTN_RESP 27 -#define DOT11_WNM_ACTION_TFS_NOTIFY_RESP 28 - -/* Unprotected Wireless Network Management (WNM) action types */ -#define DOT11_UWNM_ACTION_TIM 0 -#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 - -#define DOT11_MNG_COUNTRY_ID_LEN 3 - -/* VHT category action types - 802.11ac D3.0 - 8.5.23.1 */ -#define DOT11_VHT_ACTION_CBF 0 /* Compressed Beamforming */ -#define DOT11_VHT_ACTION_GID_MGMT 1 /* Group ID Management */ -#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 /* Operating mode notif'n */ - -/* DLS Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dls_req { - uint8 category; /* category of action frame (2) */ - uint8 action; /* DLS action: req (0) */ - struct ether_addr da; /* destination address */ - struct ether_addr sa; /* source address */ - uint16 cap; /* capability */ - uint16 timeout; /* timeout value */ - uint8 data[1]; /* IE:support rate, extend support rate, HT cap */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dls_req dot11_dls_req_t; -#define DOT11_DLS_REQ_LEN 18 /* Fixed length */ - -/* DLS response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { - uint8 category; /* category of action frame (2) */ - uint8 action; /* DLS action: req (0) */ - uint16 status; /* status code field */ - struct ether_addr da; /* destination address */ - struct ether_addr sa; /* source address */ - uint8 data[1]; /* optional: capability, rate ... */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dls_resp dot11_dls_resp_t; -#define DOT11_DLS_RESP_LEN 16 /* Fixed length */ - - -/* ************* 802.11v related definitions. ************* */ - -/* BSS Management Transition Query frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_query (6) */ - uint8 token; /* dialog token */ - uint8 reason; /* transition query reason */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bsstrans_query dot11_bsstrans_query_t; -#define DOT11_BSSTRANS_QUERY_LEN 4 /* Fixed length */ - -/* BSS Management Transition Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_req (7) */ - uint8 token; /* dialog token */ - uint8 reqmode; /* transition request mode */ - uint16 disassoc_tmr; /* disassociation timer */ - uint8 validity_intrvl; /* validity interval */ - uint8 data[1]; /* optional: BSS term duration, ... */ - /* ...session info URL, candidate list */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bsstrans_req dot11_bsstrans_req_t; -#define DOT11_BSSTRANS_REQ_LEN 7 /* Fixed length */ - -/* BSS Mgmt Transition Request Mode Field - 802.11v */ -#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01 -#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02 -#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04 -#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08 -#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10 - -/* BSS Management transition response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_resp (8) */ - uint8 token; /* dialog token */ - uint8 status; /* transition status */ - uint8 term_delay; /* validity interval */ - uint8 data[1]; /* optional: BSSID target, candidate list */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t; -#define DOT11_BSSTRANS_RESP_LEN 5 /* Fixed length */ - -/* BSS Mgmt Transition Response Status Field */ -#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0 -#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8 - - -/* BSS Max Idle Period element */ -BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { - uint8 id; /* 90, DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID */ - uint8 len; - uint16 max_idle_period; /* in unit of 1000 TUs */ - uint8 idle_opt; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; -#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 /* bss max idle period IE size */ -#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 /* BSS max idle option */ - -/* TIM Broadcast request element */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { - uint8 id; /* 94, DOT11_MNG_TIMBC_REQ_ID */ - uint8 len; - uint8 interval; /* in unit of beacon interval */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; -#define DOT11_TIMBC_REQ_IE_LEN 1 /* Fixed length */ - -/* TIM Broadcast request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: DOT11_WNM_ACTION_TIMBC_REQ(18) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* TIM broadcast request element */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_req dot11_timbc_req_t; -#define DOT11_TIMBC_REQ_LEN 3 /* Fixed length */ - -/* TIM Broadcast response element */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { - uint8 id; /* 95, DOT11_MNG_TIM_BROADCAST_RESP_ID */ - uint8 len; - uint8 status; /* status of add request */ - uint8 interval; /* in unit of beacon interval */ - int32 offset; /* in unit of ms */ - uint16 high_rate; /* in unit of 0.5 Mb/s */ - uint16 low_rate; /* in unit of 0.5 Mb/s */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; -#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 /* Deny. Fixed length */ -#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 /* Accept. Fixed length */ - -#define DOT11_TIMBC_STATUS_ACCEPT 0 -#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 -#define DOT11_TIMBC_STATUS_DENY 2 -#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 -#define DOT11_TIMBC_STATUS_RESERVED 4 - -/* TIM Broadcast request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* action: DOT11_WNM_ACTION_TIMBC_RESP(19) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* TIM broadcast response element */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_resp dot11_timbc_resp_t; -#define DOT11_TIMBC_RESP_LEN 3 /* Fixed length */ - -/* TIM element */ -BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { - uint8 id; /* 5, DOT11_MNG_TIM_ID */ - uint8 len; /* 4 - 255 */ - uint8 dtim_count; /* DTIM decrementing counter */ - uint8 dtim_period; /* DTIM period */ - uint8 bitmap_control; /* AID 0 + bitmap offset */ - uint8 pvb[1]; /* Partial Virtual Bitmap, variable length */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tim_ie dot11_tim_ie_t; -#define DOT11_TIM_IE_FIXED_LEN 3 /* Fixed length, without id and len */ -#define DOT11_TIM_IE_FIXED_TOTAL_LEN 5 /* Fixed length, with id and len */ - -/* TIM Broadcast frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc { - uint8 category; /* category of action frame (11) */ - uint8 action; /* action: TIM (0) */ - uint8 check_beacon; /* need to check-beacon */ - uint8 tsf[8]; /* Time Synchronization Function */ - dot11_tim_ie_t tim_ie; /* TIM element */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc dot11_timbc_t; -#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) -#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) /* Fixed length */ -#define DOT11_TIMBC_LEN 11 /* Fixed length */ - -/* TCLAS frame classifier type */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { - uint8 type; - uint8 mask; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; -#define DOT11_TCLAS_FC_HDR_LEN 2 /* Fixed length */ - -#define DOT11_TCLAS_MASK_0 0x1 -#define DOT11_TCLAS_MASK_1 0x2 -#define DOT11_TCLAS_MASK_2 0x4 -#define DOT11_TCLAS_MASK_3 0x8 -#define DOT11_TCLAS_MASK_4 0x10 -#define DOT11_TCLAS_MASK_5 0x20 -#define DOT11_TCLAS_MASK_6 0x40 -#define DOT11_TCLAS_MASK_7 0x80 - -#define DOT11_TCLAS_FC_0_ETH 0 -#define DOT11_TCLAS_FC_1_IP 1 -#define DOT11_TCLAS_FC_2_8021Q 2 -#define DOT11_TCLAS_FC_3_OFFSET 3 -#define DOT11_TCLAS_FC_4_IP_HIGHER 4 -#define DOT11_TCLAS_FC_5_8021D 5 - -/* TCLAS frame classifier type 0 parameters for Ethernet */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { - uint8 type; - uint8 mask; - uint8 sa[ETHER_ADDR_LEN]; - uint8 da[ETHER_ADDR_LEN]; - uint16 eth_type; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; -#define DOT11_TCLAS_FC_0_ETH_LEN 16 - -/* TCLAS frame classifier type 1 parameters for IPV4 */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { - uint8 type; - uint8 mask; - uint8 version; - uint32 src_ip; - uint32 dst_ip; - uint16 src_port; - uint16 dst_port; - uint8 dscp; - uint8 protocol; - uint8 reserved; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; -#define DOT11_TCLAS_FC_1_IPV4_LEN 18 - -/* TCLAS frame classifier type 2 parameters for 802.1Q */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { - uint8 type; - uint8 mask; - uint16 tci; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; -#define DOT11_TCLAS_FC_2_8021Q_LEN 4 - -/* TCLAS frame classifier type 3 parameters for filter offset */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { - uint8 type; - uint8 mask; - uint16 offset; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; -#define DOT11_TCLAS_FC_3_FILTER_LEN 4 - -/* TCLAS frame classifier type 4 parameters for IPV4 is the same as TCLAS type 1 */ -typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; -#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN - -/* TCLAS frame classifier type 4 parameters for IPV6 */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { - uint8 type; - uint8 mask; - uint8 version; - uint8 saddr[16]; - uint8 daddr[16]; - uint16 src_port; - uint16 dst_port; - uint8 dscp; - uint8 nexthdr; - uint8 flow_lbl[3]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; -#define DOT11_TCLAS_FC_4_IPV6_LEN 44 - -/* TCLAS frame classifier type 5 parameters for 802.1D */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { - uint8 type; - uint8 mask; - uint8 pcp; - uint8 cfi; - uint16 vid; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; -#define DOT11_TCLAS_FC_5_8021D_LEN 6 - -/* TCLAS frame classifier type parameters */ -BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { - uint8 data[1]; - dot11_tclas_fc_hdr_t hdr; - dot11_tclas_fc_0_eth_t t0_eth; - dot11_tclas_fc_1_ipv4_t t1_ipv4; - dot11_tclas_fc_2_8021q_t t2_8021q; - dot11_tclas_fc_3_filter_t t3_filter; - dot11_tclas_fc_4_ipv4_t t4_ipv4; - dot11_tclas_fc_4_ipv6_t t4_ipv6; - dot11_tclas_fc_5_8021d_t t5_8021d; -} BWL_POST_PACKED_STRUCT; -typedef union dot11_tclas_fc dot11_tclas_fc_t; - -#define DOT11_TCLAS_FC_MIN_LEN 4 /* Classifier Type 2 has the min size */ -#define DOT11_TCLAS_FC_MAX_LEN 254 - -/* TCLAS element */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { - uint8 id; /* 14, DOT11_MNG_TCLAS_ID */ - uint8 len; - uint8 user_priority; - dot11_tclas_fc_t fc; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_ie dot11_tclas_ie_t; -#define DOT11_TCLAS_IE_LEN 3 /* Fixed length, include id and len */ - -/* TCLAS processing element */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { - uint8 id; /* 44, DOT11_MNG_TCLAS_PROC_ID */ - uint8 len; - uint8 process; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; -#define DOT11_TCLAS_PROC_IE_LEN 3 /* Fixed length, include id and len */ - -#define DOT11_TCLAS_PROC_MATCHALL 0 /* All high level element need to match */ -#define DOT11_TCLAS_PROC_MATCHONE 1 /* One high level element need to match */ -#define DOT11_TCLAS_PROC_NONMATCH 2 /* Non match to any high level element */ - - -/* TSPEC element defined in 802.11 std section 8.4.2.32 - Not supported */ -#define DOT11_TSPEC_IE_LEN 57 /* Fixed length */ - -/* TFS request element */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { - uint8 id; /* 91, DOT11_MNG_TFS_REQUEST_ID */ - uint8 len; - uint8 tfs_id; - uint8 actcode; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; -#define DOT11_TFS_REQ_IE_LEN 2 /* Fixed length, without id and len */ - -/* TFS request action codes (bitfield) */ -#define DOT11_TFS_ACTCODE_DELETE 1 -#define DOT11_TFS_ACTCODE_NOTIFY 2 - -/* TFS request subelement IDs */ -#define DOT11_TFS_REQ_TFS_SE_ID 1 -#define DOT11_TFS_REQ_VENDOR_SE_ID 221 - -/* TFS subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { - uint8 sub_id; - uint8 len; - uint8 data[1]; /* TCLAS element(s) + optional TCLAS proc */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_se dot11_tfs_se_t; - - -/* TFS response element */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { - uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ - uint8 len; - uint8 tfs_id; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; -#define DOT11_TFS_RESP_IE_LEN 1 /* Fixed length, without id and len */ - -/* TFS response subelement IDs (same subelments, but different IDs than in TFS request */ -#define DOT11_TFS_RESP_TFS_STATUS_SE_ID 1 -#define DOT11_TFS_RESP_TFS_SE_ID 2 -#define DOT11_TFS_RESP_VENDOR_SE_ID 221 - -/* TFS status subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { - uint8 sub_id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ - uint8 len; - uint8 resp_st; - uint8 data[1]; /* Potential dot11_tfs_se_t included */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; -#define DOT11_TFS_STATUS_SE_LEN 1 /* Fixed length, without id and len */ - -/* Following Definition should be merged to FMS_TFS macro below */ -/* TFS Response status code. Identical to FMS Element status, without N/A */ -#define DOT11_TFS_STATUS_ACCEPT 0 -#define DOT11_TFS_STATUS_DENY_FORMAT 1 -#define DOT11_TFS_STATUS_DENY_RESOURCE 2 -#define DOT11_TFS_STATUS_DENY_POLICY 4 -#define DOT11_TFS_STATUS_DENY_UNSPECIFIED 5 -#define DOT11_TFS_STATUS_ALTPREF_POLICY 7 -#define DOT11_TFS_STATUS_ALTPREF_TCLAS_UNSUPP 14 - -/* FMS Element Status and TFS Response Status Definition */ -#define DOT11_FMS_TFS_STATUS_ACCEPT 0 -#define DOT11_FMS_TFS_STATUS_DENY_FORMAT 1 -#define DOT11_FMS_TFS_STATUS_DENY_RESOURCE 2 -#define DOT11_FMS_TFS_STATUS_DENY_MULTIPLE_DI 3 -#define DOT11_FMS_TFS_STATUS_DENY_POLICY 4 -#define DOT11_FMS_TFS_STATUS_DENY_UNSPECIFIED 5 -#define DOT11_FMS_TFS_STATUS_ALT_DIFF_DI 6 -#define DOT11_FMS_TFS_STATUS_ALT_POLICY 7 -#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_DI 8 -#define DOT11_FMS_TFS_STATUS_ALT_MCRATE 9 -#define DOT11_FMS_TFS_STATUS_TERM_POLICY 10 -#define DOT11_FMS_TFS_STATUS_TERM_RESOURCE 11 -#define DOT11_FMS_TFS_STATUS_TERM_HIGHER_PRIO 12 -#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_MDI 13 -#define DOT11_FMS_TFS_STATUS_ALT_TCLAS_UNSUPP 14 - -/* TFS Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS request (13) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_req dot11_tfs_req_t; -#define DOT11_TFS_REQ_LEN 3 /* Fixed length */ - -/* TFS Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS request (14) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_resp dot11_tfs_resp_t; -#define DOT11_TFS_RESP_LEN 3 /* Fixed length */ - -/* TFS Management Notify frame request header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS notify request (15) */ - uint8 tfs_id_cnt; /* TFS IDs count */ - uint8 tfs_id[1]; /* Array of TFS IDs */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_notify_req dot11_tfs_notify_req_t; -#define DOT11_TFS_NOTIFY_REQ_LEN 3 /* Fixed length */ - -/* TFS Management Notify frame response header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS notify response (28) */ - uint8 tfs_id_cnt; /* TFS IDs count */ - uint8 tfs_id[1]; /* Array of TFS IDs */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_notify_resp dot11_tfs_notify_resp_t; -#define DOT11_TFS_NOTIFY_RESP_LEN 3 /* Fixed length */ - - -/* WNM-Sleep Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: wnm-sleep request (16) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; -#define DOT11_WNM_SLEEP_REQ_LEN 3 /* Fixed length */ - -/* WNM-Sleep Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: wnm-sleep request (17) */ - uint8 token; /* dialog token */ - uint16 key_len; /* key data length */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; -#define DOT11_WNM_SLEEP_RESP_LEN 5 /* Fixed length */ - -#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 -#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 - -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { - uint8 sub_id; - uint8 len; - uint16 key_info; - uint8 key_length; - uint8 rsc[8]; - uint8 key[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; -#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 /* without sub_id, len, and key */ -#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 /* without sub_id and len */ - -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { - uint8 sub_id; - uint8 len; - uint16 key_id; - uint8 pn[6]; - uint8 key[16]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; -#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 /* Fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { - uint8 id; /* 93, DOT11_MNG_WNM_SLEEP_MODE_ID */ - uint8 len; - uint8 act_type; - uint8 resp_status; - uint16 interval; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; -#define DOT11_WNM_SLEEP_IE_LEN 4 /* Fixed length */ - -#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 -#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 - -#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 -#define DOT11_WNM_SLEEP_RESP_UPDATE 1 -#define DOT11_WNM_SLEEP_RESP_DENY 2 -#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 -#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 -#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 -#define DOT11_WNM_SLEEP_RESP_LAST 6 - -/* DMS Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: dms request (23) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_req dot11_dms_req_t; -#define DOT11_DMS_REQ_LEN 3 /* Fixed length */ - -/* DMS Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: dms request (24) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_resp dot11_dms_resp_t; -#define DOT11_DMS_RESP_LEN 3 /* Fixed length */ - -/* DMS request element */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { - uint8 id; /* 99, DOT11_MNG_DMS_REQUEST_ID */ - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; -#define DOT11_DMS_REQ_IE_LEN 2 /* Fixed length */ - -/* DMS response element */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { - uint8 id; /* 100, DOT11_MNG_DMS_RESPONSE_ID */ - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; -#define DOT11_DMS_RESP_IE_LEN 2 /* Fixed length */ - -/* DMS request descriptor */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { - uint8 dms_id; - uint8 len; - uint8 type; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; -#define DOT11_DMS_REQ_DESC_LEN 3 /* Fixed length */ - -#define DOT11_DMS_REQ_TYPE_ADD 0 -#define DOT11_DMS_REQ_TYPE_REMOVE 1 -#define DOT11_DMS_REQ_TYPE_CHANGE 2 - -/* DMS response status */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { - uint8 dms_id; - uint8 len; - uint8 type; - uint16 lsc; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; -#define DOT11_DMS_RESP_STATUS_LEN 5 /* Fixed length */ - -#define DOT11_DMS_RESP_TYPE_ACCEPT 0 -#define DOT11_DMS_RESP_TYPE_DENY 1 -#define DOT11_DMS_RESP_TYPE_TERM 2 - -#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF - -/* FMS Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: fms request (9) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_req dot11_fms_req_t; -#define DOT11_FMS_REQ_LEN 3 /* Fixed length */ - -/* FMS Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: fms request (10) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_resp dot11_fms_resp_t; -#define DOT11_FMS_RESP_LEN 3 /* Fixed length */ - -/* FMS Descriptor element */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_desc { - uint8 id; - uint8 len; - uint8 num_fms_cnt; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_desc dot11_fms_desc_t; -#define DOT11_FMS_DESC_LEN 1 /* Fixed length */ - -#define DOT11_FMS_CNTR_MAX 0x8 -#define DOT11_FMS_CNTR_ID_MASK 0x7 -#define DOT11_FMS_CNTR_ID_SHIFT 0x0 -#define DOT11_FMS_CNTR_COUNT_MASK 0xf1 -#define DOT11_FMS_CNTR_SHIFT 0x3 - -/* FMS request element */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_req_ie { - uint8 id; - uint8 len; - uint8 fms_token; /* token used to identify fms stream set */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_req_ie dot11_fms_req_ie_t; -#define DOT11_FMS_REQ_IE_FIX_LEN 1 /* Fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_rate_id_field { - uint8 mask; - uint8 mcs_idx; - uint16 rate; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rate_id_field dot11_rate_id_field_t; -#define DOT11_RATE_ID_FIELD_MCS_SEL_MASK 0x7 -#define DOT11_RATE_ID_FIELD_MCS_SEL_OFFSET 0 -#define DOT11_RATE_ID_FIELD_RATETYPE_MASK 0x18 -#define DOT11_RATE_ID_FIELD_RATETYPE_OFFSET 3 -#define DOT11_RATE_ID_FIELD_LEN sizeof(dot11_rate_id_field_t) - -/* FMS request subelements */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_se { - uint8 sub_id; - uint8 len; - uint8 interval; - uint8 max_interval; - dot11_rate_id_field_t rate; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_se dot11_fms_se_t; -#define DOT11_FMS_REQ_SE_LEN 6 /* Fixed length */ - -#define DOT11_FMS_REQ_SE_ID_FMS 1 /* FMS subelement */ -#define DOT11_FMS_REQ_SE_ID_VS 221 /* Vendor Specific subelement */ - -/* FMS response element */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_resp_ie { - uint8 id; - uint8 len; - uint8 fms_token; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_resp_ie dot11_fms_resp_ie_t; -#define DOT11_FMS_RESP_IE_FIX_LEN 1 /* Fixed length */ - -/* FMS status subelements */ -#define DOT11_FMS_STATUS_SE_ID_FMS 1 /* FMS Status */ -#define DOT11_FMS_STATUS_SE_ID_TCLAS 2 /* TCLAS Status */ -#define DOT11_FMS_STATUS_SE_ID_VS 221 /* Vendor Specific subelement */ - -/* FMS status subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_status_se { - uint8 sub_id; - uint8 len; - uint8 status; - uint8 interval; - uint8 max_interval; - uint8 fmsid; - uint8 counter; - dot11_rate_id_field_t rate; - uint8 mcast_addr[ETHER_ADDR_LEN]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_status_se dot11_fms_status_se_t; -#define DOT11_FMS_STATUS_SE_LEN 15 /* Fixed length */ - -/* TCLAS status subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_status_se { - uint8 sub_id; - uint8 len; - uint8 fmsid; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_status_se dot11_tclas_status_se_t; -#define DOT11_TCLAS_STATUS_SE_LEN 1 /* Fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_addba_req { - uint8 category; /* category of action frame (3) */ - uint8 action; /* action: addba req */ - uint8 token; /* identifier */ - uint16 addba_param_set; /* parameter set */ - uint16 timeout; /* timeout in seconds */ - uint16 start_seqnum; /* starting sequence number */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_addba_req dot11_addba_req_t; -#define DOT11_ADDBA_REQ_LEN 9 /* length of addba req frame */ - -BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { - uint8 category; /* category of action frame (3) */ - uint8 action; /* action: addba resp */ - uint8 token; /* identifier */ - uint16 status; /* status of add request */ - uint16 addba_param_set; /* negotiated parameter set */ - uint16 timeout; /* negotiated timeout in seconds */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_addba_resp dot11_addba_resp_t; -#define DOT11_ADDBA_RESP_LEN 9 /* length of addba resp frame */ - -/* DELBA action parameters */ -#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 /* initiator mask */ -#define DOT11_DELBA_PARAM_INIT_SHIFT 11 /* initiator shift */ -#define DOT11_DELBA_PARAM_TID_MASK 0xf000 /* tid mask */ -#define DOT11_DELBA_PARAM_TID_SHIFT 12 /* tid shift */ - -BWL_PRE_PACKED_STRUCT struct dot11_delba { - uint8 category; /* category of action frame (3) */ - uint8 action; /* action: addba req */ - uint16 delba_param_set; /* paarmeter set */ - uint16 reason; /* reason for dellba */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_delba dot11_delba_t; -#define DOT11_DELBA_LEN 6 /* length of delba frame */ - -/* SA Query action field value */ -#define SA_QUERY_REQUEST 0 -#define SA_QUERY_RESPONSE 1 - -/* ************* 802.11r related definitions. ************* */ - -/* Over-the-DS Fast Transition Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_ft_req { - uint8 category; /* category of action frame (6) */ - uint8 action; /* action: ft req */ - uint8 sta_addr[ETHER_ADDR_LEN]; - uint8 tgt_ap_addr[ETHER_ADDR_LEN]; - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ft_req dot11_ft_req_t; -#define DOT11_FT_REQ_FIXED_LEN 14 - -/* Over-the-DS Fast Transition Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_ft_res { - uint8 category; /* category of action frame (6) */ - uint8 action; /* action: ft resp */ - uint8 sta_addr[ETHER_ADDR_LEN]; - uint8 tgt_ap_addr[ETHER_ADDR_LEN]; - uint16 status; /* status code */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ft_res dot11_ft_res_t; -#define DOT11_FT_RES_FIXED_LEN 16 - -/* RDE RIC Data Element. */ -BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { - uint8 id; /* 11r, DOT11_MNG_RDE_ID */ - uint8 length; - uint8 rde_id; /* RDE identifier. */ - uint8 rd_count; /* Resource Descriptor Count. */ - uint16 status; /* Status Code. */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rde_ie dot11_rde_ie_t; - -/* 11r - Size of the RDE (RIC Data Element) IE, including TLV header. */ -#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) - - -/* ************* 802.11k related definitions. ************* */ - -/* Radio measurements enabled capability ie */ -#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ -#define RCPI_IE_LEN 1 -#define RSNI_IE_LEN 1 -BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { - uint8 cap[DOT11_RRM_CAP_LEN]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; - -/* Bitmap definitions for cap ie */ -#define DOT11_RRM_CAP_LINK 0 -#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 -#define DOT11_RRM_CAP_PARALLEL 2 -#define DOT11_RRM_CAP_REPEATED 3 -#define DOT11_RRM_CAP_BCN_PASSIVE 4 -#define DOT11_RRM_CAP_BCN_ACTIVE 5 -#define DOT11_RRM_CAP_BCN_TABLE 6 -#define DOT11_RRM_CAP_BCN_REP_COND 7 -#define DOT11_RRM_CAP_FM 8 -#define DOT11_RRM_CAP_CLM 9 -#define DOT11_RRM_CAP_NHM 10 -#define DOT11_RRM_CAP_SM 11 -#define DOT11_RRM_CAP_LCIM 12 -#define DOT11_RRM_CAP_LCIA 13 -#define DOT11_RRM_CAP_TSCM 14 -#define DOT11_RRM_CAP_TTSCM 15 -#define DOT11_RRM_CAP_AP_CHANREP 16 -#define DOT11_RRM_CAP_RMMIB 17 -/* bit18-bit26, not used for RRM_IOVAR */ -#define DOT11_RRM_CAP_MPTI 27 -#define DOT11_RRM_CAP_NBRTSFO 28 -#define DOT11_RRM_CAP_RCPI 29 -#define DOT11_RRM_CAP_RSNI 30 -#define DOT11_RRM_CAP_BSSAAD 31 -#define DOT11_RRM_CAP_BSSAAC 32 -#define DOT11_RRM_CAP_AI 33 - -/* Operating Class (formerly "Regulatory Class") definitions */ -#define DOT11_OP_CLASS_NONE 255 - -BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { - uint8 id; - uint8 len; - uint8 reg; - uint8 chanlist[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct do11_ap_chrep dot11_ap_chrep_t; - -/* Radio Measurements action ids */ -#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ -#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */ -#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */ -#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */ -#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */ -#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */ - -/* Generic radio measurement action frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_rm_action { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rm_action dot11_rm_action_t; -#define DOT11_RM_ACTION_LEN 3 - -BWL_PRE_PACKED_STRUCT struct dot11_rmreq { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - uint16 reps; /* no. of repetitions */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq dot11_rmreq_t; -#define DOT11_RMREQ_LEN 5 - -BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rm_ie dot11_rm_ie_t; -#define DOT11_RM_IE_LEN 5 - -/* Definitions for "mode" bits in rm req */ -#define DOT11_RMREQ_MODE_PARALLEL 1 -#define DOT11_RMREQ_MODE_ENABLE 2 -#define DOT11_RMREQ_MODE_REQUEST 4 -#define DOT11_RMREQ_MODE_REPORT 8 -#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */ - -/* Definitions for "mode" bits in rm rep */ -#define DOT11_RMREP_MODE_LATE 1 -#define DOT11_RMREP_MODE_INCAPABLE 2 -#define DOT11_RMREP_MODE_REFUSED 4 - -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; - uint8 bcn_mode; - struct ether_addr bssid; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; -#define DOT11_RMREQ_BCN_LEN 18 - -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; - uint8 frame_info; - uint8 rcpi; - uint8 rsni; - struct ether_addr bssid; - uint8 antenna_id; - uint32 parent_tsf; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; -#define DOT11_RMREP_BCN_LEN 26 - -/* Beacon request measurement mode */ -#define DOT11_RMREQ_BCN_PASSIVE 0 -#define DOT11_RMREQ_BCN_ACTIVE 1 -#define DOT11_RMREQ_BCN_TABLE 2 - -/* Sub-element IDs for Beacon Request */ -#define DOT11_RMREQ_BCN_SSID_ID 0 -#define DOT11_RMREQ_BCN_REPINFO_ID 1 -#define DOT11_RMREQ_BCN_REPDET_ID 2 -#define DOT11_RMREQ_BCN_REQUEST_ID 10 -#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID - -/* Reporting Detail element definition */ -#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ -#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */ -#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */ - -/* Sub-element IDs for Beacon Report */ -#define DOT11_RMREP_BCN_FRM_BODY 1 - -/* Sub-element IDs for Frame Report */ -#define DOT11_RMREP_FRAME_COUNT_REPORT 1 - -/* Channel load request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; -#define DOT11_RMREQ_CHANLOAD_LEN 11 - -/* Channel load report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; - uint8 channel_load; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; -#define DOT11_RMREP_CHANLOAD_LEN 13 - -/* Noise histogram request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; -#define DOT11_RMREQ_NOISE_LEN 11 - -/* Noise histogram report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; - uint8 antid; - uint8 anpi; - uint8 ipi0_dens; - uint8 ipi1_dens; - uint8 ipi2_dens; - uint8 ipi3_dens; - uint8 ipi4_dens; - uint8 ipi5_dens; - uint8 ipi6_dens; - uint8 ipi7_dens; - uint8 ipi8_dens; - uint8 ipi9_dens; - uint8 ipi10_dens; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; -#define DOT11_RMREP_NOISE_LEN 25 - -/* Frame request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; - uint8 req_type; - struct ether_addr ta; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; -#define DOT11_RMREQ_FRAME_LEN 18 - -/* Frame report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; -#define DOT11_RMREP_FRAME_LEN 12 - -/* Frame report entry */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { - struct ether_addr ta; - struct ether_addr bssid; - uint8 phy_type; - uint8 avg_rcpi; - uint8 last_rsni; - uint8 last_rcpi; - uint8 ant_id; - uint16 frame_cnt; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; -#define DOT11_RMREP_FRMENTRY_LEN 19 - -/* STA statistics request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - struct ether_addr peer; - uint16 interval; - uint16 duration; - uint8 group_id; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; -#define DOT11_RMREQ_STAT_LEN 16 - -/* STA statistics report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { - uint16 duration; - uint8 group_id; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; - -/* Transmit stream/category measurement request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint16 interval; - uint16 duration; - struct ether_addr peer; - uint8 traffic_id; - uint8 bin0_range; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; - -/* Transmit stream/category measurement report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { - uint32 starttime[2]; - uint16 duration; - struct ether_addr peer; - uint8 traffic_id; - uint8 reason; - uint32 txmsdu_cnt; - uint32 msdu_discarded_cnt; - uint32 msdufailed_cnt; - uint32 msduretry_cnt; - uint32 cfpolls_lost_cnt; - uint32 avrqueue_delay; - uint32 avrtx_delay; - uint8 bin0_range; - uint32 bin0; - uint32 bin1; - uint32 bin2; - uint32 bin3; - uint32 bin4; - uint32 bin5; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; - -/* Measurement pause request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint16 pause_time; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; - - -/* Neighbor Report subelements ID (11k & 11v) */ -#define DOT11_NGBR_TSF_INFO_SE_ID 1 -#define DOT11_NGBR_CCS_SE_ID 2 -#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3 -#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4 -#define DOT11_NGBR_BEARING_SE_ID 5 - -/* Neighbor Report, BSS Transition Candidate Preference subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se { - uint8 sub_id; - uint8 len; - uint8 preference; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t; -#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1 - -/* Neighbor Report, BSS Termination Duration subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se { - uint8 sub_id; - uint8 len; - uint8 tsf[8]; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t; -#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10 - -/* Neighbor Report BSSID Information Field */ -#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002 -#define DOT11_NGBR_BI_REACHABILTY 0x0003 -#define DOT11_NGBR_BI_SEC 0x0004 -#define DOT11_NGBR_BI_KEY_SCOPE 0x0008 -#define DOT11_NGBR_BI_CAP 0x03f0 -#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010 -#define DOT11_NGBR_BI_CAP_QOS 0x0020 -#define DOT11_NGBR_BI_CAP_APSD 0x0040 -#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080 -#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100 -#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200 -#define DOT11_NGBR_BI_MOBILITY 0x0400 -#define DOT11_NGBR_BI_HT 0x0800 - -/* Neighbor Report element (11k & 11v) */ -BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie { - uint8 id; - uint8 len; - struct ether_addr bssid; - uint32 bssid_info; - uint8 reg; /* Operating class */ - uint8 channel; - uint8 phytype; - uint8 data[1]; /* Variable size subelements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; -#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13 - - -/* MLME Enumerations */ -#define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ -#define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */ -#define DOT11_BSSTYPE_ANY 2 /* d11 any BSS type */ -#define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */ -#define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */ - -/* Link Measurement */ -BWL_PRE_PACKED_STRUCT struct dot11_lmreq { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - uint8 txpwr; /* Transmit Power Used */ - uint8 maxtxpwr; /* Max Transmit Power */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_lmreq dot11_lmreq_t; -#define DOT11_LMREQ_LEN 5 - -BWL_PRE_PACKED_STRUCT struct dot11_lmrep { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - dot11_tpc_rep_t tpc; /* TPC element */ - uint8 rxant; /* Receive Antenna ID */ - uint8 txant; /* Transmit Antenna ID */ - uint8 rcpi; /* RCPI */ - uint8 rsni; /* RSNI */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_lmrep dot11_lmrep_t; -#define DOT11_LMREP_LEN 11 - -/* 802.11 BRCM "Compromise" Pre N constants */ -#define PREN_PREAMBLE 24 /* green field preamble time */ -#define PREN_MM_EXT 12 /* extra mixed mode preamble time */ -#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ - -/* 802.11N PHY constants */ -#define RIFS_11N_TIME 2 /* NPHY RIFS time */ - -/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3 - * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 - */ -/* HT-SIG1 */ -#define HT_SIG1_MCS_MASK 0x00007F -#define HT_SIG1_CBW 0x000080 -#define HT_SIG1_HT_LENGTH 0xFFFF00 - -/* HT-SIG2 */ -#define HT_SIG2_SMOOTHING 0x000001 -#define HT_SIG2_NOT_SOUNDING 0x000002 -#define HT_SIG2_RESERVED 0x000004 -#define HT_SIG2_AGGREGATION 0x000008 -#define HT_SIG2_STBC_MASK 0x000030 -#define HT_SIG2_STBC_SHIFT 4 -#define HT_SIG2_FEC_CODING 0x000040 -#define HT_SIG2_SHORT_GI 0x000080 -#define HT_SIG2_ESS_MASK 0x000300 -#define HT_SIG2_ESS_SHIFT 8 -#define HT_SIG2_CRC 0x03FC00 -#define HT_SIG2_TAIL 0x1C0000 - -/* HT Timing-related parameters (802.11-2012, sec 20.3.6) */ -#define HT_T_LEG_PREAMBLE 16 -#define HT_T_L_SIG 4 -#define HT_T_SIG 8 -#define HT_T_LTF1 4 -#define HT_T_GF_LTF1 8 -#define HT_T_LTFs 4 -#define HT_T_STF 4 -#define HT_T_GF_STF 8 -#define HT_T_SYML 4 - -#define HT_N_SERVICE 16 /* bits in SERVICE field */ -#define HT_N_TAIL 6 /* tail bits per BCC encoder */ - -/* 802.11 A PHY constants */ -#define APHY_SLOT_TIME 9 /* APHY slot time */ -#define APHY_SIFS_TIME 16 /* APHY SIFS time */ -#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ -#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ -#define APHY_SIGNAL_TIME 4 /* APHY signal time */ -#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ -#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ -#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ -#define APHY_CWMIN 15 /* APHY cwmin */ - -/* 802.11 B PHY constants */ -#define BPHY_SLOT_TIME 20 /* BPHY slot time */ -#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ -#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ -#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ -#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ -#define BPHY_CWMIN 31 /* BPHY cwmin */ - -/* 802.11 G constants */ -#define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */ - -#define PHY_CWMAX 1023 /* PHY cwmax */ - -#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ - -/* 802.11 VHT constants */ - -typedef int vht_group_id_t; - -/* for VHT-A1 */ -/* SIG-A1 reserved bits */ -#define VHT_SIGA1_CONST_MASK 0x800004 - -#define VHT_SIGA1_BW_MASK 0x000003 -#define VHT_SIGA1_20MHZ_VAL 0x000000 -#define VHT_SIGA1_40MHZ_VAL 0x000001 -#define VHT_SIGA1_80MHZ_VAL 0x000002 -#define VHT_SIGA1_160MHZ_VAL 0x000003 - -#define VHT_SIGA1_STBC 0x000008 - -#define VHT_SIGA1_GID_MASK 0x0003f0 -#define VHT_SIGA1_GID_SHIFT 4 -#define VHT_SIGA1_GID_TO_AP 0x00 -#define VHT_SIGA1_GID_NOT_TO_AP 0x3f -#define VHT_SIGA1_GID_MAX_GID 0x3f - -#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 -#define VHT_SIGA1_NSTS_SHIFT 10 - -#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 -#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 - -#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 - -/* for VHT-A2 */ -#define VHT_SIGA2_GI_NONE 0x000000 -#define VHT_SIGA2_GI_SHORT 0x000001 -#define VHT_SIGA2_GI_W_MOD10 0x000002 -#define VHT_SIGA2_CODING_LDPC 0x000004 -#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 -#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 -#define VHT_SIGA2_MCS_SHIFT 4 - -#define VHT_SIGA2_B9_RESERVED 0x000200 -#define VHT_SIGA2_TAIL_MASK 0xfc0000 -#define VHT_SIGA2_TAIL_VALUE 0x000000 - -/* VHT Timing-related parameters (802.11ac D4.0, sec 22.3.6) */ -#define VHT_T_LEG_PREAMBLE 16 -#define VHT_T_L_SIG 4 -#define VHT_T_SIG_A 8 -#define VHT_T_LTF 4 -#define VHT_T_STF 4 -#define VHT_T_SIG_B 4 -#define VHT_T_SYML 4 - -#define VHT_N_SERVICE 16 /* bits in SERVICE field */ -#define VHT_N_TAIL 6 /* tail bits per BCC encoder */ - - -/* dot11Counters Table - 802.11 spec., Annex D */ -typedef struct d11cnt { - uint32 txfrag; /* dot11TransmittedFragmentCount */ - uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ - uint32 txfail; /* dot11FailedCount */ - uint32 txretry; /* dot11RetryCount */ - uint32 txretrie; /* dot11MultipleRetryCount */ - uint32 rxdup; /* dot11FrameduplicateCount */ - uint32 txrts; /* dot11RTSSuccessCount */ - uint32 txnocts; /* dot11RTSFailureCount */ - uint32 txnoack; /* dot11ACKFailureCount */ - uint32 rxfrag; /* dot11ReceivedFragmentCount */ - uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ - uint32 rxcrc; /* dot11FCSErrorCount */ - uint32 txfrmsnt; /* dot11TransmittedFrameCount */ - uint32 rxundec; /* dot11WEPUndecryptableCount */ -} d11cnt_t; - -#define BRCM_PROP_OUI "\x00\x90\x4C" - - -/* Action frame type for RWL */ -#define RWL_WIFI_DEFAULT 0 -#define RWL_WIFI_FIND_MY_PEER 9 /* Used while finding server */ -#define RWL_WIFI_FOUND_PEER 10 /* Server response to the client */ -#define RWL_ACTION_WIFI_FRAG_TYPE 85 /* Fragment indicator for receiver */ - -#define PROXD_AF_TYPE 11 /* Wifi proximity action frame type */ -#define BRCM_RELMACST_AF_TYPE 12 /* RMC action frame type */ - - -/* brcm syscap_ie cap */ -#define BRCM_SYSCAP_WET_TUNNEL 0x0100 /* Device with WET_TUNNEL support */ - -#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ - -/* BRCM info element */ -BWL_PRE_PACKED_STRUCT struct brcm_ie { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; - uint8 ver; /* type/ver of this IE */ - uint8 assoc; /* # of assoc STAs */ - uint8 flags; /* misc flags */ - uint8 flags1; /* misc flags */ - uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ -} BWL_POST_PACKED_STRUCT; -typedef struct brcm_ie brcm_ie_t; -#define BRCM_IE_LEN 11 /* BRCM IE length */ -#define BRCM_IE_VER 2 /* BRCM IE version */ -#define BRCM_IE_LEGACY_AES_VER 1 /* BRCM IE legacy AES version */ - -/* brcm_ie flags */ -#define BRF_LZWDS 0x4 /* lazy wds enabled */ -#define BRF_BLOCKACK 0x8 /* BlockACK capable */ - -/* brcm_ie flags1 */ -#define BRF1_AMSDU 0x1 /* A-MSDU capable */ -#define BRF1_WMEPS 0x4 /* AP is capable of handling WME + PS w/o APSD */ -#define BRF1_PSOFIX 0x8 /* AP has fixed PS mode out-of-order packets */ -#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ -#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ -#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ -#define BRF1_DWDS 0x80 /* DWDS capable */ - -/* Vendor IE structure */ -BWL_PRE_PACKED_STRUCT struct vndr_ie { - uchar id; - uchar len; - uchar oui [3]; - uchar data [1]; /* Variable size data */ -} BWL_POST_PACKED_STRUCT; -typedef struct vndr_ie vndr_ie_t; - -#define VNDR_IE_HDR_LEN 2 /* id + len field */ -#define VNDR_IE_MIN_LEN 3 /* size of the oui field */ -#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) - -#define VNDR_IE_MAX_LEN 255 /* vendor IE max length, without ID and len */ - -/* BRCM PROP DEVICE PRIMARY MAC ADDRESS IE */ -BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { - uchar id; - uchar len; - uchar oui[3]; - uint8 type; /* type inidicates what follows */ - struct ether_addr ea; /* Device Primary MAC Adrress */ -} BWL_POST_PACKED_STRUCT; -typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; - -#define MEMBER_OF_BRCM_PROP_IE_LEN 10 /* IE max length */ -#define MEMBER_OF_BRCM_PROP_IE_HDRLEN (sizeof(member_of_brcm_prop_ie_t)) -#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 - -/* BRCM Reliable Multicast IE */ -BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { - uint8 id; - uint8 len; - uint8 oui[3]; - uint8 type; /* type inidicates what follows */ - struct ether_addr ea; /* The ack sender's MAC Adrress */ - struct ether_addr mcast_ea; /* The multicast MAC address */ - uint8 updtmo; /* time interval(second) for client to send null packet to report its rssi */ -} BWL_POST_PACKED_STRUCT; -typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; - -/* IE length */ -/* BRCM_PROP_IE_LEN = sizeof(relmcast_brcm_prop_ie_t)-((sizeof (id) + sizeof (len)))? */ -#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-(2*sizeof(uint8))) - -#define RELMCAST_BRCM_PROP_IE_TYPE 55 - -/* ************* HT definitions. ************* */ -#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ -#define MAX_MCS_NUM (128) /* max mcs number = 128 */ - -BWL_PRE_PACKED_STRUCT struct ht_cap_ie { - uint16 cap; - uint8 params; - uint8 supp_mcs[MCSSET_LEN]; - uint16 ext_htcap; - uint32 txbf_cap; - uint8 as_cap; -} BWL_POST_PACKED_STRUCT; -typedef struct ht_cap_ie ht_cap_ie_t; - -BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { - uint8 id; - uint8 len; - ht_cap_ie_t ht_cap; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; - -/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ -/* the capability IE is primarily used to convey this nodes abilities */ -BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; - uint8 type; /* type inidicates what follows */ - ht_cap_ie_t cap_ie; -} BWL_POST_PACKED_STRUCT; -typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; - -#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ -#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */ -#define HT_CAP_IE_TYPE 51 - -#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ -#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ -#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ -#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ -#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ -#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ -#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ -#define HT_CAP_GF 0x0010 /* Greenfield preamble support */ -#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ -#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ -#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */ -#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ -#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ -#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */ -#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ - -#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ -#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ -#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ -#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ - -#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ -#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ -#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ -#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ - - -#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 -#define HT_CAP_TXBF_CAP_NDP_TX 0x8 -#define HT_CAP_TXBF_CAP_NDP_RX 0x10 -#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 -#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 -#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 -#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 -#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 -#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 -#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 -#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 -#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 -#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 -#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 -#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 -#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 - -#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 -#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 - -#define HT_CAP_TXBF_FB_TYPE_NONE 0 -#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 -#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 -#define HT_CAP_TXBF_FB_TYPE_BOTH 3 - -#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400 -#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10 -#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000 -#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15 - -#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ -#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ -/* Max AMSDU len - per spec */ -#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) - -#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */ -#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */ - -#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ -#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ -#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ - -/* HT/AMPDU specific define */ -#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */ -#define AMPDU_DENSITY_NONE 0 /* No density requirement */ -#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */ -#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */ -#define AMPDU_DENSITY_1_US 3 /* 1 us density */ -#define AMPDU_DENSITY_2_US 4 /* 2 us density */ -#define AMPDU_DENSITY_4_US 5 /* 4 us density */ -#define AMPDU_DENSITY_8_US 6 /* 8 us density */ -#define AMPDU_DENSITY_16_US 7 /* 16 us density */ -#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */ -#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */ -#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */ -#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */ - -/* AMPDU RX factors for VHT rates */ -#define AMPDU_RX_FACTOR_128K 4 /* max rcv ampdu len (128kb) */ -#define AMPDU_RX_FACTOR_256K 5 /* max rcv ampdu len (256kb) */ -#define AMPDU_RX_FACTOR_512K 6 /* max rcv ampdu len (512kb) */ -#define AMPDU_RX_FACTOR_1024K 7 /* max rcv ampdu len (1024kb) */ - -#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ -#define AMPDU_RX_FACTOR_BASE_PWR 13 /* ampdu factor base for rx len in power of 2 */ - -#define AMPDU_DELIMITER_LEN 4 /* length of ampdu delimiter */ -#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */ - -#define HT_CAP_EXT_PCO 0x0001 -#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 -#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 -#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 -#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 -#define HT_CAP_EXT_HTC 0x0400 -#define HT_CAP_EXT_RD_RESP 0x0800 - -BWL_PRE_PACKED_STRUCT struct ht_add_ie { - uint8 ctl_ch; /* control channel number */ - uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ - uint16 opmode; /* operation mode */ - uint16 misc_bits; /* misc bits */ - uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ -} BWL_POST_PACKED_STRUCT; -typedef struct ht_add_ie ht_add_ie_t; - -/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ -/* the additional IE is primarily used to convey the current BSS configuration */ -BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; - uint8 type; /* indicates what follows */ - ht_add_ie_t add_ie; -} BWL_POST_PACKED_STRUCT; -typedef struct ht_prop_add_ie ht_prop_add_ie_t; - -#define HT_ADD_IE_LEN 22 -#define HT_ADD_IE_TYPE 52 - -/* byte1 defn's */ -#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ -#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */ - -/* opmode defn's */ -#define HT_OPMODE_MASK 0x0003 /* protection mode mask */ -#define HT_OPMODE_SHIFT 0 /* protection mode shift */ -#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */ -#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ -#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ -#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ -#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ -#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ -#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ - -/* misc_bites defn's */ -#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ -#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ -#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */ -#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ -#define HT_PCO_ACTIVE 0x0400 /* PCO active */ -#define HT_PCO_PHASE 0x0800 /* PCO phase */ -#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */ - -/* Tx Burst Limits */ -#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ -#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ - -/* Macros for opmode */ -#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - >> HT_OPMODE_SHIFT) -#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_MIXED) /* mixed mode present */ -#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_HT20IN40) /* 20MHz HT present */ -#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_OPTIONAL) /* Optional protection present */ -#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ - HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */ -#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ - == HT_OPMODE_NONGF) /* non-GF present */ -#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ - == DOT11N_TXBURST) /* Tx Burst present */ -#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ - == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ - -BWL_PRE_PACKED_STRUCT struct obss_params { - uint16 passive_dwell; - uint16 active_dwell; - uint16 bss_widthscan_interval; - uint16 passive_total; - uint16 active_total; - uint16 chanwidth_transition_dly; - uint16 activity_threshold; -} BWL_POST_PACKED_STRUCT; -typedef struct obss_params obss_params_t; - -BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { - uint8 id; - uint8 len; - obss_params_t obss_params; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_obss_ie dot11_obss_ie_t; -#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */ - -/* HT control field */ -#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */ -#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */ -#define HT_CTRL_LA_MAI_SHIFT 2 -#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */ -#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */ -#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */ -#define HT_CTRL_LA_MFSI_SHIFT 6 -#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */ -#define HT_CTRL_LA_MFB_ASELC_SH 9 -#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */ -#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */ -#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */ -#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */ -#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */ -#define HT_CTRL_CSI_STEER_SHIFT 22 -#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */ -#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */ -#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */ -#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */ -#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */ -#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */ -#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */ - -/* ************* VHT definitions. ************* */ - -/* - * VHT Capabilites IE (sec 8.4.2.160) - */ - -BWL_PRE_PACKED_STRUCT struct vht_cap_ie { - uint32 vht_cap_info; - /* supported MCS set - 64 bit field */ - uint16 rx_mcs_map; - uint16 rx_max_rate; - uint16 tx_mcs_map; - uint16 tx_max_rate; -} BWL_POST_PACKED_STRUCT; -typedef struct vht_cap_ie vht_cap_ie_t; - -/* 4B cap_info + 8B supp_mcs */ -#define VHT_CAP_IE_LEN 12 - -/* VHT Capabilities Info field - 32bit - in VHT Cap IE */ -#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 -#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c -#define VHT_CAP_INFO_LDPC 0x00000010 -#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 -#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 -#define VHT_CAP_INFO_TX_STBC 0x00000080 -#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 -#define VHT_CAP_INFO_RX_STBC_SHIFT 8 -#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 -#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 -#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 -#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 -#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 -#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 -#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 -#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 -#define VHT_CAP_INFO_TXOPPS 0x00200000 -#define VHT_CAP_INFO_HTCVHT 0x00400000 -#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 -#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 -#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 -#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 - -/* VHT Supported MCS Set - 64-bit - in VHT Cap IE */ -#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff -#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 - -#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff -#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 - -#define VHT_CAP_MCS_MAP_0_7 0 -#define VHT_CAP_MCS_MAP_0_8 1 -#define VHT_CAP_MCS_MAP_0_9 2 -#define VHT_CAP_MCS_MAP_NONE 3 -#define VHT_CAP_MCS_MAP_S 2 /* num bits for 1-stream */ -#define VHT_CAP_MCS_MAP_M 0x3 /* mask for 1-stream */ -/* assumes VHT_CAP_MCS_MAP_NONE is 3 and 2 bits are used for encoding */ -#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff -/* mcsmap with MCS0-9 for Nss = 3 */ -#define VHT_CAP_MCS_MAP_0_9_NSS3 \ - ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ - (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ - (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) - -#define VHT_CAP_MCS_MAP_NSS_MAX 8 - -/* get mcsmap with given mcs for given nss streams */ -#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ - do { \ - int i; \ - for (i = 1; i <= nss; i++) { \ - VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ - } \ - } while (0) - -/* Map the mcs code to mcs bit map */ -#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ - ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? 0xff : \ - (mcs_code == VHT_CAP_MCS_MAP_0_8) ? 0x1ff : \ - (mcs_code == VHT_CAP_MCS_MAP_0_9) ? 0x3ff : 0) - -/* Map the mcs bit map to mcs code */ -#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ - ((mcs_map == 0xff) ? VHT_CAP_MCS_MAP_0_7 : \ - (mcs_map == 0x1ff) ? VHT_CAP_MCS_MAP_0_8 : \ - (mcs_map == 0x3ff) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) - -/* VHT Capabilities Supported Channel Width */ -typedef enum vht_cap_chan_width { - VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, - VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, - VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 -} vht_cap_chan_width_t; - -/* VHT Capabilities Supported max MPDU LEN (sec 8.4.2.160.2) */ -typedef enum vht_cap_max_mpdu_len { - VHT_CAP_MPDU_MAX_4K = 0x00, - VHT_CAP_MPDU_MAX_8K = 0x01, - VHT_CAP_MPDU_MAX_11K = 0x02 -} vht_cap_max_mpdu_len_t; - -/* Maximum MPDU Length byte counts for the VHT Capabilities advertised limits */ -#define VHT_MPDU_LIMIT_4K 3895 -#define VHT_MPDU_LIMIT_8K 7991 -#define VHT_MPDU_LIMIT_11K 11454 - - -/* - * VHT Operation IE (sec 8.4.2.161) - */ - -BWL_PRE_PACKED_STRUCT struct vht_op_ie { - uint8 chan_width; - uint8 chan1; - uint8 chan2; - uint16 supp_mcs; /* same def as above in vht cap */ -} BWL_POST_PACKED_STRUCT; -typedef struct vht_op_ie vht_op_ie_t; - -/* 3B VHT Op info + 2B Basic MCS */ -#define VHT_OP_IE_LEN 5 - -typedef enum vht_op_chan_width { - VHT_OP_CHAN_WIDTH_20_40 = 0, - VHT_OP_CHAN_WIDTH_80 = 1, - VHT_OP_CHAN_WIDTH_160 = 2, - VHT_OP_CHAN_WIDTH_80_80 = 3 -} vht_op_chan_width_t; - -/* AID length */ -#define AID_IE_LEN 2 -/* - * BRCM vht features IE header - * The header if the fixed part of the IE - * On the 5GHz band this is the entire IE, - * on 2.4GHz the VHT IEs as defined in the 802.11ac - * specification follows - * - * - * VHT features rates bitmap. - * Bit0: 5G MCS 0-9 BW 160MHz - * Bit1: 5G MCS 0-9 support BW 80MHz - * Bit2: 5G MCS 0-9 support BW 20MHz - * Bit3: 2.4G MCS 0-9 support BW 20MHz - * Bits:4-7 Reserved for future use - * - */ -#define VHT_FEATURES_IE_TYPE 0x4 -BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { - uint8 oui[3]; - uint8 type; /* type of this IE = 4 */ - uint8 rate_mask; /* VHT rate mask */ -} BWL_POST_PACKED_STRUCT; -typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; - -/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ -#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) -#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ - (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) -#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ - do { \ - (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ - (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ - } while (0) -#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ - (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) - - -/* ************* WPA definitions. ************* */ -#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ -#define WPA_OUI_LEN 3 /* WPA OUI length */ -#define WPA_OUI_TYPE 1 -#define WPA_VERSION 1 /* WPA version */ -#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ -#define WPA2_OUI_LEN 3 /* WPA2 OUI length */ -#define WPA2_VERSION 1 /* WPA2 version */ -#define WPA2_VERSION_LEN 2 /* WAP2 version length */ - -/* ************* WPS definitions. ************* */ -#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */ -#define WPS_OUI_LEN 3 /* WPS OUI length */ -#define WPS_OUI_TYPE 4 - -/* ************* WFA definitions. ************* */ - -#ifdef P2P_IE_OVRD -#define WFA_OUI MAC_OUI -#else -#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */ -#endif /* P2P_IE_OVRD */ -#define WFA_OUI_LEN 3 /* WFA OUI length */ -#ifdef P2P_IE_OVRD -#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P -#else -#define WFA_OUI_TYPE_TPC 8 -#define WFA_OUI_TYPE_P2P 9 -#endif - -#define WFA_OUI_TYPE_TPC 8 -#ifdef WLTDLS -#define WFA_OUI_TYPE_TPQ 4 /* WFD Tunneled Probe ReQuest */ -#define WFA_OUI_TYPE_TPS 5 /* WFD Tunneled Probe ReSponse */ -#define WFA_OUI_TYPE_WFD 10 -#endif /* WTDLS */ -#define WFA_OUI_TYPE_HS20 0x10 - -/* RSN authenticated key managment suite */ -#define RSN_AKM_NONE 0 /* None (IBSS) */ -#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ -#define RSN_AKM_PSK 2 /* Pre-shared Key */ -#define RSN_AKM_FBT_1X 3 /* Fast Bss transition using 802.1X */ -#define RSN_AKM_FBT_PSK 4 /* Fast Bss transition using Pre-shared Key */ -#define RSN_AKM_MFP_1X 5 /* SHA256 key derivation, using 802.1X */ -#define RSN_AKM_MFP_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ -#define RSN_AKM_TPK 7 /* TPK(TDLS Peer Key) handshake */ - -/* Key related defines */ -#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */ -#define DOT11_MAX_IGTK_KEYS 2 -#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */ -#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */ -#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */ -#define DOT11_WPA_KEY_RSC_LEN 8 /* WPA RSC key len */ - -#define WEP1_KEY_SIZE 5 /* max size of any WEP key */ -#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */ -#define WEP128_KEY_SIZE 13 /* max size of any WEP key */ -#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */ -#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */ -#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */ -#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */ -#define TKIP_KEY_SIZE 32 /* size of any TKIP key, includs MIC keys */ -#define TKIP_TK_SIZE 16 -#define TKIP_MIC_KEY_SIZE 8 -#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */ -#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */ -#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX /* offset to Supplicant MIC RX key */ -#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX /* offset to Supplicant MIC TX key */ -#define AES_KEY_SIZE 16 /* size of AES key */ -#define AES_MIC_SIZE 8 /* size of AES MIC */ -#define BIP_KEY_SIZE 16 /* size of BIP key */ -#define BIP_MIC_SIZE 8 /* sizeof BIP MIC */ - -#define AES_GCM_MIC_SIZE 16 /* size of MIC for 128-bit GCM - .11adD9 */ - -#define AES256_KEY_SIZE 32 /* size of AES 256 key - .11acD5 */ -#define AES256_MIC_SIZE 16 /* size of MIC for 256 bit keys, incl BIP */ - -/* WCN */ -#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ -#define WCN_TYPE 4 /* WCN type */ - -#ifdef BCMWAPI_WPI -#define SMS4_KEY_LEN 16 -#define SMS4_WPI_CBC_MAC_LEN 16 -#endif - -/* 802.11r protocol definitions */ - -/* Mobility Domain IE */ -BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { - uint8 id; - uint8 len; - uint16 mdid; /* Mobility Domain Id */ - uint8 cap; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_mdid_ie dot11_mdid_ie_t; - -#define FBT_MDID_CAP_OVERDS 0x01 /* Fast Bss transition over the DS support */ -#define FBT_MDID_CAP_RRP 0x02 /* Resource request protocol support */ - -/* Fast Bss Transition IE */ -BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { - uint8 id; - uint8 len; - uint16 mic_control; /* Mic Control */ - uint8 mic[16]; - uint8 anonce[32]; - uint8 snonce[32]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ft_ie dot11_ft_ie_t; - -#define TIE_TYPE_RESERVED 0 -#define TIE_TYPE_REASSOC_DEADLINE 1 -#define TIE_TYPE_KEY_LIEFTIME 2 -#define TIE_TYPE_ASSOC_COMEBACK 3 -BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { - uint8 id; - uint8 len; - uint8 type; /* timeout interval type */ - uint32 value; /* timeout interval value */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timeout_ie dot11_timeout_ie_t; - -/* GTK ie */ -BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { - uint8 id; - uint8 len; - uint16 key_info; - uint8 key_len; - uint8 rsc[8]; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_gtk_ie dot11_gtk_ie_t; - -/* Management MIC ie */ -BWL_PRE_PACKED_STRUCT struct mmic_ie { - uint8 id; /* IE ID: DOT11_MNG_MMIE_ID */ - uint8 len; /* IE length */ - uint16 key_id; /* key id */ - uint8 ipn[6]; /* ipn */ - uint8 mic[16]; /* mic */ -} BWL_POST_PACKED_STRUCT; -typedef struct mmic_ie mmic_ie_t; - -#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" -#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" - -#ifdef BCMWAPI_WAI -#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */ -#define WAPI_VERSION 1 /* WAPI version */ -#define WAPI_VERSION_LEN 2 /* WAPI version length */ -#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */ -#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */ -#endif /* BCMWAPI_WAI */ - -/* ************* WMM Parameter definitions. ************* */ -#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */ -#define WMM_OUI_LEN 3 /* WMM OUI length */ -#define WMM_OUI_TYPE 2 /* WMM OUT type */ -#define WMM_VERSION 1 -#define WMM_VERSION_LEN 1 - -/* WMM OUI subtype */ -#define WMM_OUI_SUBTYPE_PARAMETER 1 -#define WMM_PARAMETER_IE_LEN 24 - -/* Link Identifier Element */ -BWL_PRE_PACKED_STRUCT struct link_id_ie { - uint8 id; - uint8 len; - struct ether_addr bssid; - struct ether_addr tdls_init_mac; - struct ether_addr tdls_resp_mac; -} BWL_POST_PACKED_STRUCT; -typedef struct link_id_ie link_id_ie_t; -#define TDLS_LINK_ID_IE_LEN 18 - -/* Link Wakeup Schedule Element */ -BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { - uint8 id; - uint8 len; - uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */ - uint32 interval; /* in ms bwtween the start of 2 Awake Windows */ - uint32 awake_win_slots; /* in backof slots, duration of Awake Window */ - uint32 max_wake_win; /* in ms, max duration of Awake Window */ - uint16 idle_cnt; /* number of consecutive Awake Windows */ -} BWL_POST_PACKED_STRUCT; -typedef struct wakeup_sch_ie wakeup_sch_ie_t; -#define TDLS_WAKEUP_SCH_IE_LEN 18 - -/* Channel Switch Timing Element */ -BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { - uint8 id; - uint8 len; - uint16 switch_time; /* in ms, time to switch channels */ - uint16 switch_timeout; /* in ms */ -} BWL_POST_PACKED_STRUCT; -typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; -#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 - -/* PTI Control Element */ -BWL_PRE_PACKED_STRUCT struct pti_control_ie { - uint8 id; - uint8 len; - uint8 tid; - uint16 seq_control; -} BWL_POST_PACKED_STRUCT; -typedef struct pti_control_ie pti_control_ie_t; -#define TDLS_PTI_CONTROL_IE_LEN 3 - -/* PU Buffer Status Element */ -BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { - uint8 id; - uint8 len; - uint8 status; -} BWL_POST_PACKED_STRUCT; -typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; -#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 -#define TDLS_PU_BUFFER_STATUS_AC_BK 1 -#define TDLS_PU_BUFFER_STATUS_AC_BE 2 -#define TDLS_PU_BUFFER_STATUS_AC_VI 4 -#define TDLS_PU_BUFFER_STATUS_AC_VO 8 - -/* TDLS Action Field Values */ -#define TDLS_SETUP_REQ 0 -#define TDLS_SETUP_RESP 1 -#define TDLS_SETUP_CONFIRM 2 -#define TDLS_TEARDOWN 3 -#define TDLS_PEER_TRAFFIC_IND 4 -#define TDLS_CHANNEL_SWITCH_REQ 5 -#define TDLS_CHANNEL_SWITCH_RESP 6 -#define TDLS_PEER_PSM_REQ 7 -#define TDLS_PEER_PSM_RESP 8 -#define TDLS_PEER_TRAFFIC_RESP 9 -#define TDLS_DISCOVERY_REQ 10 - -/* 802.11z TDLS Public Action Frame action field */ -#define TDLS_DISCOVERY_RESP 14 - -/* 802.11u GAS action frames */ -#define GAS_REQUEST_ACTION_FRAME 10 -#define GAS_RESPONSE_ACTION_FRAME 11 -#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 -#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 - -/* 802.11u interworking access network options */ -#define IW_ANT_MASK 0x0f -#define IW_INTERNET_MASK 0x10 -#define IW_ASRA_MASK 0x20 -#define IW_ESR_MASK 0x40 -#define IW_UESA_MASK 0x80 - -/* 802.11u interworking access network type */ -#define IW_ANT_PRIVATE_NETWORK 0 -#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 -#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 -#define IW_ANT_FREE_PUBLIC_NETWORK 3 -#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 -#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 -#define IW_ANT_TEST_NETWORK 14 -#define IW_ANT_WILDCARD_NETWORK 15 - -/* 802.11u advertisement protocol */ -#define ADVP_ANQP_PROTOCOL_ID 0 - -/* 802.11u advertisement protocol masks */ -#define ADVP_QRL_MASK 0x7f -#define ADVP_PAME_BI_MASK 0x80 - -/* 802.11u advertisement protocol values */ -#define ADVP_QRL_REQUEST 0x00 -#define ADVP_QRL_RESPONSE 0x7f -#define ADVP_PAME_BI_DEPENDENT 0x00 -#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK - -/* 802.11u ANQP information ID */ -#define ANQP_ID_QUERY_LIST 256 -#define ANQP_ID_CAPABILITY_LIST 257 -#define ANQP_ID_VENUE_NAME_INFO 258 -#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 -#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 -#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 -#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 -#define ANQP_ID_NAI_REALM_LIST 263 -#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 -#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 -#define ANQP_ID_AP_CIVIC_LOCATION 266 -#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 -#define ANQP_ID_DOMAIN_NAME_LIST 268 -#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 -#define ANQP_ID_EMERGENCY_NAI 271 -#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 - -/* 802.11u ANQP OUI */ -#define ANQP_OUI_SUBTYPE 9 - -/* 802.11u venue name */ -#define VENUE_LANGUAGE_CODE_SIZE 3 -#define VENUE_NAME_SIZE 255 - -/* 802.11u venue groups */ -#define VENUE_UNSPECIFIED 0 -#define VENUE_ASSEMBLY 1 -#define VENUE_BUSINESS 2 -#define VENUE_EDUCATIONAL 3 -#define VENUE_FACTORY 4 -#define VENUE_INSTITUTIONAL 5 -#define VENUE_MERCANTILE 6 -#define VENUE_RESIDENTIAL 7 -#define VENUE_STORAGE 8 -#define VENUE_UTILITY 9 -#define VENUE_VEHICULAR 10 -#define VENUE_OUTDOOR 11 - -/* 802.11u network authentication type indicator */ -#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 -#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 -#define NATI_HTTP_HTTPS_REDIRECTION 2 -#define NATI_DNS_REDIRECTION 3 - -/* 802.11u IP address type availability - IPv6 */ -#define IPA_IPV6_SHIFT 0 -#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) -#define IPA_IPV6_NOT_AVAILABLE 0x00 -#define IPA_IPV6_AVAILABLE 0x01 -#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 - -/* 802.11u IP address type availability - IPv4 */ -#define IPA_IPV4_SHIFT 2 -#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) -#define IPA_IPV4_NOT_AVAILABLE 0x00 -#define IPA_IPV4_PUBLIC 0x01 -#define IPA_IPV4_PORT_RESTRICT 0x02 -#define IPA_IPV4_SINGLE_NAT 0x03 -#define IPA_IPV4_DOUBLE_NAT 0x04 -#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 -#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 -#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 - -/* 802.11u NAI realm encoding */ -#define REALM_ENCODING_RFC4282 0 -#define REALM_ENCODING_UTF8 1 - -/* 802.11u IANA EAP method type numbers */ -#define REALM_EAP_TLS 13 -#define REALM_EAP_SIM 18 -#define REALM_EAP_TTLS 21 -#define REALM_EAP_AKA 23 -#define REALM_EAP_PSK 47 -#define REALM_EAP_AKAP 50 -#define REALM_EAP_EXPANDED 254 - -/* 802.11u authentication ID */ -#define REALM_EXPANDED_EAP 1 -#define REALM_NON_EAP_INNER_AUTHENTICATION 2 -#define REALM_INNER_AUTHENTICATION_EAP 3 -#define REALM_EXPANDED_INNER_EAP 4 -#define REALM_CREDENTIAL 5 -#define REALM_TUNNELED_EAP_CREDENTIAL 6 -#define REALM_VENDOR_SPECIFIC_EAP 221 - -/* 802.11u non-EAP inner authentication type */ -#define REALM_PAP 1 -#define REALM_CHAP 2 -#define REALM_MSCHAP 3 -#define REALM_MSCHAPV2 4 - -/* 802.11u credential type */ -#define REALM_SIM 1 -#define REALM_USIM 2 -#define REALM_NFC 3 -#define REALM_HARDWARE_TOKEN 4 -#define REALM_SOFTOKEN 5 -#define REALM_CERTIFICATE 6 -#define REALM_USERNAME_PASSWORD 7 -#define REALM_SERVER_SIDE 8 - -/* 802.11u 3GPP PLMN */ -#define G3PP_GUD_VERSION 0 -#define G3PP_PLMN_LIST_IE 0 - -/* hotspot2.0 indication element (vendor specific) */ -BWL_PRE_PACKED_STRUCT struct hs20_ie { - uint8 oui[3]; - uint8 type; - uint8 config; -} BWL_POST_PACKED_STRUCT; -typedef struct hs20_ie hs20_ie_t; -#define HS20_IE_LEN 5 /* HS20 IE length */ - -/* IEEE 802.11 Annex E */ -typedef enum { - DOT11_2GHZ_20MHZ_CLASS_12 = 81, /* Ch 1-11 */ - DOT11_5GHZ_20MHZ_CLASS_1 = 115, /* Ch 36-48 */ - DOT11_5GHZ_20MHZ_CLASS_2_DFS = 118, /* Ch 52-64 */ - DOT11_5GHZ_20MHZ_CLASS_3 = 124, /* Ch 149-161 */ - DOT11_5GHZ_20MHZ_CLASS_4_DFS = 121, /* Ch 100-140 */ - DOT11_5GHZ_20MHZ_CLASS_5 = 125, /* Ch 149-165 */ - DOT11_5GHZ_40MHZ_CLASS_22 = 116, /* Ch 36-44, lower */ - DOT11_5GHZ_40MHZ_CLASS_23_DFS = 119, /* Ch 52-60, lower */ - DOT11_5GHZ_40MHZ_CLASS_24_DFS = 122, /* Ch 100-132, lower */ - DOT11_5GHZ_40MHZ_CLASS_25 = 126, /* Ch 149-157, lower */ - DOT11_5GHZ_40MHZ_CLASS_27 = 117, /* Ch 40-48, upper */ - DOT11_5GHZ_40MHZ_CLASS_28_DFS = 120, /* Ch 56-64, upper */ - DOT11_5GHZ_40MHZ_CLASS_29_DFS = 123, /* Ch 104-136, upper */ - DOT11_5GHZ_40MHZ_CLASS_30 = 127, /* Ch 153-161, upper */ - DOT11_2GHZ_40MHZ_CLASS_32 = 83, /* Ch 1-7, lower */ - DOT11_2GHZ_40MHZ_CLASS_33 = 84, /* Ch 5-11, upper */ -} dot11_op_class_t; - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _802_11_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h deleted file mode 100755 index 7b9baf3c6550..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: 802.11_bta.h 382882 2013-02-04 23:24:31Z $ -*/ - -#ifndef _802_11_BTA_H_ -#define _802_11_BTA_H_ - -#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58" - -/* BT-AMP 802.11 PAL Protocols */ -#define BTA_PROT_L2CAP 1 -#define BTA_PROT_ACTIVITY_REPORT 2 -#define BTA_PROT_SECURITY 3 -#define BTA_PROT_LINK_SUPERVISION_REQUEST 4 -#define BTA_PROT_LINK_SUPERVISION_REPLY 5 - -/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */ -#define BTA_TYPE_ID_MAC_ADDRESS 1 -#define BTA_TYPE_ID_PREFERRED_CHANNELS 2 -#define BTA_TYPE_ID_CONNECTED_CHANNELS 3 -#define BTA_TYPE_ID_CAPABILITIES 4 -#define BTA_TYPE_ID_VERSION 5 -#endif /* _802_11_bta_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h deleted file mode 100755 index 879fa84f3168..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 802.11e protocol header file - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: 802.11e.h 382883 2013-02-04 23:26:09Z $ - */ - -#ifndef _802_11e_H_ -#define _802_11e_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - - -/* WME Traffic Specification (TSPEC) element */ -#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ -#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ - -#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ -#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ -#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ -#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ - -BWL_PRE_PACKED_STRUCT struct tsinfo { - uint8 octets[3]; -} BWL_POST_PACKED_STRUCT; - -typedef struct tsinfo tsinfo_t; - -/* 802.11e TSPEC IE */ -typedef BWL_PRE_PACKED_STRUCT struct tspec { - uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ - uint8 type; /* WME_TYPE */ - uint8 subtype; /* WME_SUBTYPE_TSPEC */ - uint8 version; /* WME_VERSION */ - tsinfo_t tsinfo; /* TS Info bit field */ - uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ - uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ - uint32 min_srv_interval; /* Minimum Service Interval (us) */ - uint32 max_srv_interval; /* Maximum Service Interval (us) */ - uint32 inactivity_interval; /* Inactivity Interval (us) */ - uint32 suspension_interval; /* Suspension Interval (us) */ - uint32 srv_start_time; /* Service Start Time (us) */ - uint32 min_data_rate; /* Minimum Data Rate (bps) */ - uint32 mean_data_rate; /* Mean Data Rate (bps) */ - uint32 peak_data_rate; /* Peak Data Rate (bps) */ - uint32 max_burst_size; /* Maximum Burst Size (bytes) */ - uint32 delay_bound; /* Delay Bound (us) */ - uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ - uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ - uint16 medium_time; /* Medium Time (32 us/s periods) */ -} BWL_POST_PACKED_STRUCT tspec_t; - -#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ - -/* ts_info */ -/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ -#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ -#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ -#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ -#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ -#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ -#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ -#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ -#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ -#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ -#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ -#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ -#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ -/* TS info. user priority mask */ -#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) - -/* Macro to get/set bit(s) field in TSINFO */ -#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) -#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ - TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) -#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) -#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ - TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) - -#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ - ((id) << TS_INFO_TID_SHIFT)) -#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ - ((prio) << TS_INFO_USER_PRIO_SHIFT)) - -/* 802.11e QBSS Load IE */ -#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ -#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ - -#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */ - /* DEFVAL dot11ADDTSResponseTimeout = 1s */ - -/* 802.11e ADDTS status code */ -#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ -#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ -#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ -#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ -#ifdef BCMCCX -#define CCX_STATUS_ASSOC_DENIED_UNKNOWN 0xc8 /* unspecified QoS related failure */ -#define CCX_STATUS_ASSOC_DENIED_AP_POLICY 0xc9 /* TSPEC refused due to AP policy */ -#define CCX_STATUS_ASSOC_DENIED_NO_BW 0xca /* Assoc denied due to AP insufficient BW */ -#define CCX_STATUS_ASSOC_DENIED_BAD_PARAM 0xcb /* one or more TSPEC with invalid parameter */ -#endif /* BCMCCX */ - -/* 802.11e DELTS status code */ -#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ -#define DOT11E_STATUS_END_TS 37 /* END TS */ -#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ -#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ - - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _802_11e_CAC_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h deleted file mode 100755 index ceddd5c767d0..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental types and constants relating to 802.1D - * - * $Id: 802.1d.h 382882 2013-02-04 23:24:31Z $ - */ - -#ifndef _802_1_D_ -#define _802_1_D_ - -/* 802.1D priority defines */ -#define PRIO_8021D_NONE 2 /* None = - */ -#define PRIO_8021D_BK 1 /* BK - Background */ -#define PRIO_8021D_BE 0 /* BE - Best-effort */ -#define PRIO_8021D_EE 3 /* EE - Excellent-effort */ -#define PRIO_8021D_CL 4 /* CL - Controlled Load */ -#define PRIO_8021D_VI 5 /* Vi - Video */ -#define PRIO_8021D_VO 6 /* Vo - Voice */ -#define PRIO_8021D_NC 7 /* NC - Network Control */ -#define MAXPRIO 7 /* 0-7 */ -#define NUMPRIO (MAXPRIO + 1) - -#define ALLPRIO -1 /* All prioirty */ - -/* Converts prio to precedence since the numerical value of - * PRIO_8021D_BE and PRIO_8021D_NONE are swapped. - */ -#define PRIO2PREC(prio) \ - (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) - -#endif /* _802_1_D__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h deleted file mode 100755 index e7728e307f0b..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental constants relating to 802.3 - * - * $Id: 802.3.h 417943 2013-08-13 07:54:04Z $ - */ - -#ifndef _802_3_h_ -#define _802_3_h_ - -/* This marks the start of a packed structure section. */ -#include - -#define SNAP_HDR_LEN 6 /* 802.3 SNAP header length */ -#define DOT3_OUI_LEN 3 /* 802.3 oui length */ - -BWL_PRE_PACKED_STRUCT struct dot3_mac_llc_snap_header { - uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ - uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ - uint16 length; /* frame length incl header */ - uint8 dsap; /* always 0xAA */ - uint8 ssap; /* always 0xAA */ - uint8 ctl; /* always 0x03 */ - uint8 oui[DOT3_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 - * Bridge-Tunnel: 0x00 0x00 0xF8 - */ - uint16 type; /* ethertype */ -} BWL_POST_PACKED_STRUCT; - -/* This marks the end of a packed structure section. */ -#include - -#endif /* #ifndef _802_3_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h deleted file mode 100755 index 8611c682791c..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Broadcom Ethernettype protocol definitions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmeth.h 642536 2016-06-09 02:32:26Z $ - */ - -/* - * Broadcom Ethernet protocol defines - */ - -#ifndef _BCMETH_H_ -#define _BCMETH_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - -/* ETHER_TYPE_BRCM is defined in ethernet.h */ - -/* - * Following the 2byte BRCM ether_type is a 16bit BRCM subtype field - * in one of two formats: (only subtypes 32768-65535 are in use now) - * - * subtypes 0-32767: - * 8 bit subtype (0-127) - * 8 bit length in bytes (0-255) - * - * subtypes 32768-65535: - * 16 bit big-endian subtype - * 16 bit big-endian length in bytes (0-65535) - * - * length is the number of additional bytes beyond the 4 or 6 byte header - * - * Reserved values: - * 0 reserved - * 5-15 reserved for iLine protocol assignments - * 17-126 reserved, assignable - * 127 reserved - * 32768 reserved - * 32769-65534 reserved, assignable - * 65535 reserved - */ - -/* - * While adding the subtypes and their specific processing code make sure - * bcmeth_bcm_hdr_t is the first data structure in the user specific data structure definition - */ - -#define BCMILCP_SUBTYPE_RATE 1 -#define BCMILCP_SUBTYPE_LINK 2 -#define BCMILCP_SUBTYPE_CSA 3 -#define BCMILCP_SUBTYPE_LARQ 4 -#define BCMILCP_SUBTYPE_VENDOR 5 -#define BCMILCP_SUBTYPE_FLH 17 - -#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 -#define BCMILCP_SUBTYPE_CERT 32770 -#define BCMILCP_SUBTYPE_SES 32771 - - -#define BCMILCP_BCM_SUBTYPE_RESERVED 0 -#define BCMILCP_BCM_SUBTYPE_EVENT 1 -#define BCMILCP_BCM_SUBTYPE_SES 2 -/* - * The EAPOL type is not used anymore. Instead EAPOL messages are now embedded - * within BCMILCP_BCM_SUBTYPE_EVENT type messages - */ -/* #define BCMILCP_BCM_SUBTYPE_EAPOL 3 */ -#define BCMILCP_BCM_SUBTYPE_DPT 4 -#define BCMILCP_BCM_SUBTYPE_DNGLEVENT 5 - -#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 -#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 - -/* These fields are stored in network order */ -typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr -{ - uint16 subtype; /* Vendor specific..32769 */ - uint16 length; - uint8 version; /* Version is 0 */ - uint8 oui[3]; /* Broadcom OUI */ - /* user specific Data */ - uint16 usr_subtype; -} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; - - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _BCMETH_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h deleted file mode 100755 index 006213bfff73..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Broadcom Event protocol definitions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Dependencies: proto/bcmeth.h - * - * $Id: bcmevent.h 642536 2016-06-09 02:32:26Z $ - * - */ - -/* - * Broadcom Ethernet Events protocol defines - * - */ - -#ifndef _BCMEVENT_H_ -#define _BCMEVENT_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif -/* #include -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */ -#include -#include - -/* This marks the start of a packed structure section. */ -#include - -#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */ -#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */ - -/* flags */ -#define WLC_EVENT_MSG_LINK 0x01 /* link is up */ -#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */ -#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ -#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */ -#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */ - -/* these fields are stored in network order */ - -/* version 1 */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - uint16 version; - uint16 flags; /* see flags below */ - uint32 event_type; /* Message (see below) */ - uint32 status; /* Status code (see below) */ - uint32 reason; /* Reason code (if applicable) */ - uint32 auth_type; /* WLC_E_AUTH */ - uint32 datalen; /* data buf */ - struct ether_addr addr; /* Station address (if applicable) */ - char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ -} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; - -/* the current version */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - uint16 version; - uint16 flags; /* see flags below */ - uint32 event_type; /* Message (see below) */ - uint32 status; /* Status code (see below) */ - uint32 reason; /* Reason code (if applicable) */ - uint32 auth_type; /* WLC_E_AUTH */ - uint32 datalen; /* data buf */ - struct ether_addr addr; /* Station address (if applicable) */ - char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ - uint8 ifidx; /* destination OS i/f index */ - uint8 bsscfgidx; /* source bsscfg index */ -} BWL_POST_PACKED_STRUCT wl_event_msg_t; - -/* used by driver msgs */ -typedef BWL_PRE_PACKED_STRUCT struct bcm_event { - struct ether_header eth; - bcmeth_hdr_t bcm_hdr; - wl_event_msg_t event; - /* data portion follows */ -} BWL_POST_PACKED_STRUCT bcm_event_t; - -/* - * used by host event - * Note: If additional event types are added, it should come on is_wlc_event_frame() as well. - */ -typedef union bcm_event_msg_u { - wl_event_msg_t event; - bcm_dngl_event_msg_t dngl_event; - - /* add new event here */ -} bcm_event_msg_u_t; - -#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) - -/* Event messages */ -#define WLC_E_SET_SSID 0 /* indicates status of set SSID */ -#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */ -#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */ -#define WLC_E_AUTH 3 /* 802.11 AUTH request */ -#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */ -#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */ -#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */ -#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */ -#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */ -#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */ -#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */ -#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */ -#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */ -#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */ -#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */ -#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */ -#define WLC_E_LINK 16 /* generic link indication */ -#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */ -#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */ -#define WLC_E_ROAM 19 /* roam attempt occurred: indicate status & reason */ -#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */ -#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */ -#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */ -#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */ -#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */ -#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */ -#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */ -#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */ -#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */ -#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */ -#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */ -#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */ -#define WLC_E_ROAM_PREP 32 /* before attempting to roam */ -#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */ -#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */ -#define WLC_E_RESET_COMPLETE 35 -#define WLC_E_JOIN_START 36 -#define WLC_E_ROAM_START 37 -#define WLC_E_ASSOC_START 38 -#define WLC_E_IBSS_ASSOC 39 -#define WLC_E_RADIO 40 -#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */ -#define WLC_E_PROBREQ_MSG 44 /* probe request received */ -#define WLC_E_SCAN_CONFIRM_IND 45 -#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */ -#define WLC_E_COUNTRY_CODE_CHANGED 47 -#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */ -#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */ -#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */ -#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ -#define WLC_E_TRACE 52 -#define WLC_E_IF 54 /* I/F change (for dongle host notification) */ -#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */ -#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */ -/* PFN best network batching event, conflict/share with WLC_E_PFN_SCAN_COMPLETE */ -#define WLC_E_PFN_BEST_BATCHING 57 -#define WLC_E_EXTLOG_MSG 58 -#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */ -#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ -#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */ -#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */ -#define WLC_E_CHANNEL_ADOPTED 63 -#define WLC_E_AP_STARTED 64 /* AP started */ -#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */ -#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */ -#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */ -#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */ -#define WLC_E_ESCAN_RESULT 69 /* escan result event */ -#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */ -#define WLC_E_PROBRESP_MSG 71 /* probe response received */ -#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */ -#define WLC_E_DCS_REQUEST 73 -#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */ -#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH - * wl_event_rx_frame_data_t header - */ -#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */ -#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */ -#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */ -#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */ -#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */ -#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */ -#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */ -/* PFN BSSID network found event, conflict/share with WLC_E_PFN_SCAN_NONE */ -#define WLC_E_PFN_BSSID_NET_FOUND 82 -#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */ -/* PFN BSSID network lost event, conflict/share with WLC_E_PFN_SCAN_ALLGONE */ -#define WLC_E_PFN_BSSID_NET_LOST 83 -#define WLC_E_GTK_PLUMBED 84 -#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */ -#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */ -#define WLC_E_ASSOC_REQ_IE 87 -#define WLC_E_ASSOC_RESP_IE 88 -#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ -#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */ -#define WLC_E_AUTH_REQ 91 /* authentication request received */ -#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected/disconnected peer */ -#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */ -#define WLC_E_NATIVE 94 /* port-specific event and payload (e.g. NDIS) */ -#define WLC_E_PKTDELAY_IND 95 /* event for tx pkt delay suddently jump */ -#define WLC_E_PSTA_PRIMARY_INTF_IND 99 /* psta primary interface indication */ -#define WLC_E_NAN 100 /* NAN event */ -#define WLC_E_BEACON_FRAME_RX 101 -#define WLC_E_SERVICE_FOUND 102 /* desired service found */ -#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ -#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ -#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ -#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ -#define WLC_E_WNM_STA_SLEEP 107 /* WNM event to notify STA enter sleep mode */ -#define WLC_E_TXFAIL_THRESH 108 /* Indication of MAC tx failures (exhaustion of - * 802.11 retries) exceeding threshold(s) - */ -#define WLC_E_PROXD 109 /* Proximity Detection event */ -#define WLC_E_IBSS_COALESCE 110 /* IBSS Coalescing */ -#define WLC_E_AIBSS_TXFAIL 110 /* TXFAIL event for AIBSS, re using event 110 */ -#define WLC_E_CSA_START_IND 121 -#define WLC_E_CSA_DONE_IND 122 -#define WLC_E_CSA_FAILURE_IND 123 -#define WLC_E_CCA_CHAN_QUAL 124 /* CCA based channel quality report */ -#define WLC_E_BSSID 125 /* to report change in BSSID while roaming */ -#define WLC_E_TX_STAT_ERROR 126 /* tx error indication */ -#define WLC_E_BCMC_CREDIT_SUPPORT 127 /* credit check for BCMC supported */ -#define WLC_E_RSSI_LQM 133 /* Enhancement addition for WLC_E_RSSI */ -#define WLC_E_PFN_GSCAN_FULL_RESULT 134 /* Full probe/beacon (IEs etc) results */ -#define WLC_E_PFN_SWC 135 /* Significant change in rssi of bssids being tracked */ -#define WLC_E_PFN_SCAN_COMPLETE 138 /* PFN completed scan of network list */ -#define WLC_E_RMC_EVENT 139 /* RMC event */ -#define WLC_E_PFN_SSID_EXT 142 /* SSID EXT event */ -#define WLC_E_LAST 143 /* highest val + 1 for range checking */ - -#if (WLC_E_LAST > 143) -#error "WLC_E_LAST: Invalid value for last event; must be <= 140." -#endif /* WLC_E_LAST */ - - -/* validate if the event is proper and if valid copy event header to event */ -extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, - bcm_event_msg_u_t *out_event); - -/* Table of event name strings for UIs and debugging dumps */ -typedef struct { - uint event; - const char *name; -} bcmevent_name_t; - -extern const bcmevent_name_t bcmevent_names[]; -extern const int bcmevent_names_size; - -/* Event status codes */ -#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */ -#define WLC_E_STATUS_FAIL 1 /* operation failed */ -#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */ -#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */ -#define WLC_E_STATUS_ABORT 4 /* operation was aborted */ -#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */ -#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */ -#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */ -#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */ -#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */ -#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */ -#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */ -#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */ -#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */ -#ifdef BCMCCX -#define WLC_E_STATUS_CCXFASTRM 14 /* scan aborted due to CCX fast roam */ -#endif /* BCMCCX */ -#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */ -#define WLC_E_STATUS_ERROR 16 /* request failed due to error */ - -/* roam reason codes */ -#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */ -#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */ -#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ -#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ -#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ - -/* Roam codes used primarily by CCX */ -#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ -#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ -#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ -#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ -#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ -#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ -#define WLC_E_REASON_REQUESTED_ROAM 11 /* roamed due to BSS Mgmt Transition REQ by AP */ - -/* prune reason codes */ -#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ -#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ -#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ -#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ -#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ -#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ -#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ -#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ -#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ -#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ -#ifdef BCMCCX -#define WLC_E_PRUNE_CCXFAST_PREVAP 11 /* CCX FAST ROAM: prune previous AP */ -#endif /* def BCMCCX */ -#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ -#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ -#ifdef BCMCCX -#define WLC_E_PRUNE_CCXFAST_DROAM 14 /* CCX FAST ROAM: prune unqualified AP */ -#endif /* def BCMCCX */ -#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ -#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ -#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ -#ifdef BCMCCX -#define WLC_E_PRUNE_AP_BLOCKED 18 /* prune blocked AP */ -#define WLC_E_PRUNE_NO_DIAG_SUPPORT 19 /* prune due to diagnostic mode not supported */ -#endif /* BCMCCX */ - -/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */ -#define WLC_E_SUP_OTHER 0 /* Other reason */ -#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */ -#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */ -#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */ -#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */ -#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */ -#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */ -#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */ -#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */ -#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */ -#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */ -#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */ -#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */ -#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */ -#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */ -#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */ - -/* Event data for events that include frames received over the air */ -/* WLC_E_PROBRESP_MSG - * WLC_E_P2P_PROBREQ_MSG - * WLC_E_ACTION_FRAME_RX - */ -typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { - uint16 version; - uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */ - int32 rssi; - uint32 mactime; - uint32 rate; -} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; - -#define BCM_RX_FRAME_DATA_VERSION 1 - -/* WLC_E_IF event data */ -typedef struct wl_event_data_if { - uint8 ifidx; /* RTE virtual device index (for dongle) */ - uint8 opcode; /* see I/F opcode */ - uint8 reserved; /* bit mask (WLC_E_IF_FLAGS_XXX ) */ - uint8 bssidx; /* bsscfg index */ - uint8 role; /* see I/F role */ -} wl_event_data_if_t; - -/* opcode in WLC_E_IF event */ -#define WLC_E_IF_ADD 1 /* bsscfg add */ -#define WLC_E_IF_DEL 2 /* bsscfg delete */ -#define WLC_E_IF_CHANGE 3 /* bsscfg role change */ - -/* I/F role code in WLC_E_IF event */ -#define WLC_E_IF_ROLE_STA 0 /* Infra STA */ -#define WLC_E_IF_ROLE_AP 1 /* Access Point */ -#define WLC_E_IF_ROLE_WDS 2 /* WDS link */ -#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ -#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ - -/* WLC_E_RSSI event data */ -typedef struct wl_event_data_rssi { - int32 rssi; - int32 snr; - int32 noise; -} wl_event_data_rssi_t; - -/* WLC_E_IF flag */ -#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 /* no host I/F creation needed */ - -/* Reason codes for LINK */ -#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */ -#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */ -#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */ -#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */ - -/* reason codes for WLC_E_OVERLAY_REQ event */ -#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */ -#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */ - -/* reason codes for WLC_E_TDLS_PEER_EVENT event */ -#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */ -#define WLC_E_TDLS_PEER_CONNECTED 1 -#define WLC_E_TDLS_PEER_DISCONNECTED 2 - -#ifdef WLTDLS -/* TDLS Action Category code */ -#define TDLS_AF_CATEGORY 12 -/* Wi-Fi Display (WFD) Vendor Specific Category */ -/* used for WFD Tunneled Probe Request and Response */ -#define TDLS_VENDOR_SPECIFIC 127 -/* TDLS Action Field Values */ -#define TDLS_ACTION_SETUP_REQ 0 -#define TDLS_ACTION_SETUP_RESP 1 -#define TDLS_ACTION_SETUP_CONFIRM 2 -#define TDLS_ACTION_TEARDOWN 3 -#define WLAN_TDLS_SET_PROBE_WFD_IE 11 -#define WLAN_TDLS_SET_SETUP_WFD_IE 12 -#endif - -/* reason codes for WLC_E_RMC_EVENT event */ -#define WLC_E_REASON_RMC_NONE 0 -#define WLC_E_REASON_RMC_AR_LOST 1 -#define WLC_E_REASON_RMC_AR_NO_ACK 2 - - -/* GAS event data */ -typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { - uint16 channel; /* channel of GAS protocol */ - uint8 dialog_token; /* GAS dialog token */ - uint8 fragment_id; /* fragment id */ - uint16 status_code; /* status code on GAS completion */ - uint16 data_len; /* length of data to follow */ - uint8 data[1]; /* variable length specified by data_len */ -} BWL_POST_PACKED_STRUCT wl_event_gas_t; - -/* service discovery TLV */ -typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { - uint16 length; /* length of response_data */ - uint8 protocol; /* service protocol type */ - uint8 transaction_id; /* service transaction id */ - uint8 status_code; /* status code */ - uint8 data[1]; /* response data */ -} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; - -/* service discovery event data */ -typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { - uint16 channel; /* channel */ - uint8 count; /* number of tlvs */ - wl_sd_tlv_t tlv[1]; /* service discovery TLV */ -} BWL_POST_PACKED_STRUCT wl_event_sd_t; - -/* Reason codes for WLC_E_PROXD */ -#define WLC_E_PROXD_FOUND 1 /* Found a proximity device */ -#define WLC_E_PROXD_GONE 2 /* Lost a proximity device */ -#define WLC_E_PROXD_START 3 /* used by: target */ -#define WLC_E_PROXD_STOP 4 /* used by: target */ -#define WLC_E_PROXD_COMPLETED 5 /* used by: initiator completed */ -#define WLC_E_PROXD_ERROR 6 /* used by both initiator and target */ -#define WLC_E_PROXD_COLLECT_START 7 /* used by: target & initiator */ -#define WLC_E_PROXD_COLLECT_STOP 8 /* used by: target */ -#define WLC_E_PROXD_COLLECT_COMPLETED 9 /* used by: initiator completed */ -#define WLC_E_PROXD_COLLECT_ERROR 10 /* used by both initiator and target */ -#define WLC_E_PROXD_NAN_EVENT 11 /* used by both initiator and target */ - -/* proxd_event data */ -typedef struct ftm_sample { - uint32 value; /* RTT in ns */ - int8 rssi; /* RSSI */ -} ftm_sample_t; - -typedef BWL_PRE_PACKED_STRUCT struct proxd_event_data { - uint16 ver; /* version */ - uint16 mode; /* mode: target/initiator */ - uint16 method; /* method: rssi/TOF/AOA */ - uint8 err_code; /* error classification */ - uint8 TOF_type; /* one way or two way TOF */ - uint8 OFDM_frame_type; /* legacy or VHT */ - uint8 bandwidth; /* Bandwidth is 20, 40,80, MHZ */ - struct ether_addr peer_mac; /* (e.g for tgt:initiator's */ - uint32 distance; /* dst to tgt, units meter */ - uint32 meanrtt; /* mean delta */ - uint32 modertt; /* Mode delta */ - uint32 medianrtt; /* median RTT */ - uint32 sdrtt; /* Standard deviation of RTT */ - int gdcalcresult; /* Software or Hardware Kind of redundant, but if */ - /* frame type is VHT, then we should do it by hardware */ - int16 avg_rssi; /* avg rssi accroos the ftm frames */ - int16 validfrmcnt; /* Firmware's valid frame counts */ - char *peer_router_info; /* Peer router information if available in TLV, */ - /* We will add this field later */ - int32 var1; /* average of group delay */ - int32 var2; /* average of threshold crossing */ - int32 var3; /* difference between group delay and threshold crossing */ - /* raw Fine Time Measurements (ftm) data */ - uint16 ftm_unit; /* ftm cnt resolution in picoseconds , 6250ps - default */ - uint16 ftm_cnt; /* num of rtd measurments/length in the ftm buffer */ - ftm_sample_t ftm_buff[1]; /* 1 ... ftm_cnt */ -} BWL_POST_PACKED_STRUCT wl_proxd_event_data_t; - - -/* Video Traffic Interference Monitor Event */ -#define INTFER_EVENT_VERSION 1 -#define INTFER_STREAM_TYPE_NONTCP 1 -#define INTFER_STREAM_TYPE_TCP 2 -#define WLINTFER_STATS_NSMPLS 4 -typedef struct wl_intfer_event { - uint16 version; /* version */ - uint16 status; /* status */ - uint8 txfail_histo[WLINTFER_STATS_NSMPLS]; /* txfail histo */ -} wl_intfer_event_t; - -/* WLC_E_PSTA_PRIMARY_INTF_IND event data */ -typedef struct wl_psta_primary_intf_event { - struct ether_addr prim_ea; /* primary intf ether addr */ -} wl_psta_primary_intf_event_t; - -/* ********** NAN protocol events/subevents ********** */ -#define NAN_EVENT_BUFFER_SIZE 512 /* max size */ -/* nan application events to the host driver */ -enum nan_app_events { - WL_NAN_EVENT_START = 1, /* NAN cluster started */ - WL_NAN_EVENT_JOIN = 2, /* Joined to a NAN cluster */ - WL_NAN_EVENT_ROLE = 3, /* Role or State changed */ - WL_NAN_EVENT_SCAN_COMPLETE = 4, - WL_NAN_EVENT_DISCOVERY_RESULT = 5, - WL_NAN_EVENT_REPLIED = 6, - WL_NAN_EVENT_TERMINATED = 7, /* the instance ID will be present in the ev data */ - WL_NAN_EVENT_RECEIVE = 8, - WL_NAN_EVENT_STATUS_CHG = 9, /* generated on any change in nan_mac status */ - WL_NAN_EVENT_MERGE = 10, /* Merged to a NAN cluster */ - WL_NAN_EVENT_STOP = 11, /* NAN stopped */ - WL_NAN_EVENT_INVALID = 12, /* delimiter for max value */ -}; -#define IS_NAN_EVT_ON(var, evt) ((var & (1 << (evt-1))) != 0) -/* ******************* end of NAN section *************** */ - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _BCMEVENT_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h deleted file mode 100755 index a95a6131324e..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental constants relating to IP Protocol - * - * $Id: bcmip.h 457888 2014-02-25 03:34:39Z $ - */ - -#ifndef _bcmip_h_ -#define _bcmip_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - - -/* IPV4 and IPV6 common */ -#define IP_VER_OFFSET 0x0 /* offset to version field */ -#define IP_VER_MASK 0xf0 /* version mask */ -#define IP_VER_SHIFT 4 /* version shift */ -#define IP_VER_4 4 /* version number for IPV4 */ -#define IP_VER_6 6 /* version number for IPV6 */ - -#define IP_VER(ip_body) \ - ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) - -#define IP_PROT_ICMP 0x1 /* ICMP protocol */ -#define IP_PROT_IGMP 0x2 /* IGMP protocol */ -#define IP_PROT_TCP 0x6 /* TCP protocol */ -#define IP_PROT_UDP 0x11 /* UDP protocol type */ -#define IP_PROT_ICMP6 0x3a /* ICMPv6 protocol type */ - -/* IPV4 field offsets */ -#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ -#define IPV4_TOS_OFFSET 1 /* type of service offset */ -#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ -#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ -#define IPV4_PROT_OFFSET 9 /* protocol type offset */ -#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ -#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ -#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ -#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ -#define IPV4_MIN_HEADER_LEN 20 /* Minimum size for an IP header (no options) */ - -/* IPV4 field decodes */ -#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ -#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ - -#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ -#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) - -#define IPV4_ADDR_LEN 4 /* IPV4 address length */ - -#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ - ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) - -#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ - ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) - -#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ -#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ - -#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) - -#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ -#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ - -#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ -#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ -#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ - -#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) - -#define IPV4_FRAG_RESV 0x8000 /* Reserved */ -#define IPV4_FRAG_DONT 0x4000 /* Don't fragment */ -#define IPV4_FRAG_MORE 0x2000 /* More fragments */ -#define IPV4_FRAG_OFFSET_MASK 0x1fff /* Fragment offset */ - -#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ - -/* IPV4 packet formats */ -BWL_PRE_PACKED_STRUCT struct ipv4_addr { - uint8 addr[IPV4_ADDR_LEN]; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct ipv4_hdr { - uint8 version_ihl; /* Version and Internet Header Length */ - uint8 tos; /* Type Of Service */ - uint16 tot_len; /* Number of bytes in packet (max 65535) */ - uint16 id; - uint16 frag; /* 3 flag bits and fragment offset */ - uint8 ttl; /* Time To Live */ - uint8 prot; /* Protocol */ - uint16 hdr_chksum; /* IP header checksum */ - uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ - uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ -} BWL_POST_PACKED_STRUCT; - -/* IPV6 field offsets */ -#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ -#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ -#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ -#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ -#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ - -/* IPV6 field decodes */ -#define IPV6_TRAFFIC_CLASS(ipv6_body) \ - (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ - ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) - -#define IPV6_FLOW_LABEL(ipv6_body) \ - (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ - (((uint8 *)(ipv6_body))[2] << 8) | \ - (((uint8 *)(ipv6_body))[3])) - -#define IPV6_PAYLOAD_LEN(ipv6_body) \ - ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ - ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) - -#define IPV6_NEXT_HDR(ipv6_body) \ - (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) - -#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) - -#define IPV6_ADDR_LEN 16 /* IPV6 address length */ - -/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ -#define IP_TOS46(ip_body) \ - (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ - IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) - -#define IP_DSCP46(ip_body) (IP_TOS46(ip_body) >> IPV4_TOS_DSCP_SHIFT); - -/* IPV6 extension headers (options) */ -#define IPV6_EXTHDR_HOP 0 -#define IPV6_EXTHDR_ROUTING 43 -#define IPV6_EXTHDR_FRAGMENT 44 -#define IPV6_EXTHDR_AUTH 51 -#define IPV6_EXTHDR_NONE 59 -#define IPV6_EXTHDR_DEST 60 - -#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ - ((prot) == IPV6_EXTHDR_ROUTING) || \ - ((prot) == IPV6_EXTHDR_FRAGMENT) || \ - ((prot) == IPV6_EXTHDR_AUTH) || \ - ((prot) == IPV6_EXTHDR_NONE) || \ - ((prot) == IPV6_EXTHDR_DEST)) - -#define IPV6_MIN_HLEN 40 - -#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) - -BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { - uint8 nexthdr; - uint8 hdrlen; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { - uint8 nexthdr; - uint8 rsvd; - uint16 frag_off; - uint32 ident; -} BWL_POST_PACKED_STRUCT; - -static INLINE int32 -ipv6_exthdr_len(uint8 *h, uint8 *proto) -{ - uint16 len = 0, hlen; - struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; - - while (IPV6_EXTHDR(eh->nexthdr)) { - if (eh->nexthdr == IPV6_EXTHDR_NONE) - return -1; - else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) - hlen = 8; - else if (eh->nexthdr == IPV6_EXTHDR_AUTH) - hlen = (eh->hdrlen + 2) << 2; - else - hlen = IPV6_EXTHDR_LEN(eh); - - len += hlen; - eh = (struct ipv6_exthdr *)(h + len); - } - - *proto = eh->nexthdr; - return len; -} - -#define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000) - -#define IPV4_MCAST_TO_ETHER_MCAST(ipv4, ether) \ -{ \ - ether[0] = 0x01; \ - ether[1] = 0x00; \ - ether[2] = 0x5E; \ - ether[3] = (ipv4 & 0x7f0000) >> 16; \ - ether[4] = (ipv4 & 0xff00) >> 8; \ - ether[5] = (ipv4 & 0xff); \ -} - -/* This marks the end of a packed structure section. */ -#include - -#define IPV4_ADDR_STR "%d.%d.%d.%d" -#define IPV4_ADDR_TO_STR(addr) ((uint32)addr & 0xff000000) >> 24, \ - ((uint32)addr & 0x00ff0000) >> 16, \ - ((uint32)addr & 0x0000ff00) >> 8, \ - ((uint32)addr & 0x000000ff) - -#endif /* _bcmip_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h deleted file mode 100755 index 42068ef5ebc9..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental constants relating to Neighbor Discovery Protocol - * - * $Id: bcmipv6.h 399482 2013-04-30 09:24:37Z $ - */ - -#ifndef _bcmipv6_h_ -#define _bcmipv6_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - -/* Extension headers */ -#define IPV6_EXT_HOP 0 -#define IPV6_EXT_ROUTE 43 -#define IPV6_EXT_FRAG 44 -#define IPV6_EXT_DEST 60 -#define IPV6_EXT_ESEC 50 -#define IPV6_EXT_AUTH 51 - -/* Minimum size (extension header "word" length) */ -#define IPV6_EXT_WORD 8 - -/* Offsets for most extension headers */ -#define IPV6_EXT_NEXTHDR 0 -#define IPV6_EXT_HDRLEN 1 - -/* Constants specific to fragmentation header */ -#define IPV6_FRAG_MORE_MASK 0x0001 -#define IPV6_FRAG_MORE_SHIFT 0 -#define IPV6_FRAG_OFFS_MASK 0xfff8 -#define IPV6_FRAG_OFFS_SHIFT 3 - -/* For icmpv6 */ -#define ICMPV6_HEADER_TYPE 0x3A -#define ICMPV6_PKT_TYPE_NS 135 -#define ICMPV6_PKT_TYPE_NA 136 - -#define ICMPV6_ND_OPT_TYPE_TARGET_MAC 2 -#define ICMPV6_ND_OPT_TYPE_SRC_MAC 1 - -#define ICMPV6_ND_OPT_LEN_LINKADDR 1 - -#define ICMPV6_ND_OPT_LEN_LINKADDR 1 - -#define IPV6_VERSION 6 -#define IPV6_HOP_LIMIT 255 - -#define IPV6_ADDR_NULL(a) ((a[0] | a[1] | a[2] | a[3] | a[4] | \ - a[5] | a[6] | a[7] | a[8] | a[9] | \ - a[10] | a[11] | a[12] | a[13] | \ - a[14] | a[15]) == 0) - -#define IPV6_ADDR_LOCAL(a) (((a[0] == 0xfe) && (a[1] & 0x80))? TRUE: FALSE) - -/* IPV6 address */ -BWL_PRE_PACKED_STRUCT struct ipv6_addr { - uint8 addr[16]; -} BWL_POST_PACKED_STRUCT; - - -/* ICMPV6 Header */ -BWL_PRE_PACKED_STRUCT struct icmp6_hdr { - uint8 icmp6_type; - uint8 icmp6_code; - uint16 icmp6_cksum; - BWL_PRE_PACKED_STRUCT union { - uint32 reserved; - BWL_PRE_PACKED_STRUCT struct nd_advt { - uint32 reserved1:5, - override:1, - solicited:1, - router:1, - reserved2:24; - } BWL_POST_PACKED_STRUCT nd_advt; - } BWL_POST_PACKED_STRUCT opt; -} BWL_POST_PACKED_STRUCT; - -/* Ipv6 Header Format */ -BWL_PRE_PACKED_STRUCT struct ipv6_hdr { - uint8 priority:4, - version:4; - uint8 flow_lbl[3]; - uint16 payload_len; - uint8 nexthdr; - uint8 hop_limit; - struct ipv6_addr saddr; - struct ipv6_addr daddr; -} BWL_POST_PACKED_STRUCT; - -/* Neighbor Advertisement/Solicitation Packet Structure */ -BWL_PRE_PACKED_STRUCT struct nd_msg { - struct icmp6_hdr icmph; - struct ipv6_addr target; -} BWL_POST_PACKED_STRUCT; - - -/* Neighibor Solicitation/Advertisement Optional Structure */ -BWL_PRE_PACKED_STRUCT struct nd_msg_opt { - uint8 type; - uint8 len; - uint8 mac_addr[ETHER_ADDR_LEN]; -} BWL_POST_PACKED_STRUCT; - -/* Ipv6 Fragmentation Header */ -BWL_PRE_PACKED_STRUCT struct ipv6_frag { - uint8 nexthdr; - uint8 reserved; - uint16 frag_offset; - uint32 ident; -} BWL_POST_PACKED_STRUCT; - -/* This marks the end of a packed structure section. */ -#include - -static const struct ipv6_addr all_node_ipv6_maddr = { - { 0xff, 0x2, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 1 - }}; - -#define IPV6_ISMULTI(a) (a[0] == 0xff) - -#define IPV6_MCAST_TO_ETHER_MCAST(ipv6, ether) \ -{ \ - ether[0] = 0x33; \ - ether[1] = 0x33; \ - ether[2] = ipv6[12]; \ - ether[3] = ipv6[13]; \ - ether[4] = ipv6[14]; \ - ether[5] = ipv6[15]; \ -} - -#endif /* !defined(_bcmipv6_h_) */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h deleted file mode 100755 index 2be771af44e7..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Fundamental constants relating to TCP Protocol - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bcmtcp.h 457888 2014-02-25 03:34:39Z $ - */ - -#ifndef _bcmtcp_h_ -#define _bcmtcp_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - - -#define TCP_SRC_PORT_OFFSET 0 /* TCP source port offset */ -#define TCP_DEST_PORT_OFFSET 2 /* TCP dest port offset */ -#define TCP_SEQ_NUM_OFFSET 4 /* TCP sequence number offset */ -#define TCP_ACK_NUM_OFFSET 8 /* TCP acknowledgement number offset */ -#define TCP_HLEN_OFFSET 12 /* HLEN and reserved bits offset */ -#define TCP_FLAGS_OFFSET 13 /* FLAGS and reserved bits offset */ -#define TCP_CHKSUM_OFFSET 16 /* TCP body checksum offset */ - -#define TCP_PORT_LEN 2 /* TCP port field length */ - -/* 8bit TCP flag field */ -#define TCP_FLAG_URG 0x20 -#define TCP_FLAG_ACK 0x10 -#define TCP_FLAG_PSH 0x08 -#define TCP_FLAG_RST 0x04 -#define TCP_FLAG_SYN 0x02 -#define TCP_FLAG_FIN 0x01 - -#define TCP_HLEN_MASK 0xf000 -#define TCP_HLEN_SHIFT 12 - -/* These fields are stored in network order */ -BWL_PRE_PACKED_STRUCT struct bcmtcp_hdr -{ - uint16 src_port; /* Source Port Address */ - uint16 dst_port; /* Destination Port Address */ - uint32 seq_num; /* TCP Sequence Number */ - uint32 ack_num; /* TCP Sequence Number */ - uint16 hdrlen_rsvd_flags; /* Header length, reserved bits and flags */ - uint16 tcpwin; /* TCP window */ - uint16 chksum; /* Segment checksum with pseudoheader */ - uint16 urg_ptr; /* Points to seq-num of byte following urg data */ -} BWL_POST_PACKED_STRUCT; - -#define TCP_MIN_HEADER_LEN 20 - -#define TCP_HDRLEN_MASK 0xf0 -#define TCP_HDRLEN_SHIFT 4 -#define TCP_HDRLEN(hdrlen) (((hdrlen) & TCP_HDRLEN_MASK) >> TCP_HDRLEN_SHIFT) - -#define TCP_FLAGS_MASK 0x1f -#define TCP_FLAGS(hdrlen) ((hdrlen) & TCP_FLAGS_MASK) - -/* This marks the end of a packed structure section. */ -#include - -/* To address round up by 32bit. */ -#define IS_TCPSEQ_GE(a, b) ((a - b) < NBITVAL(31)) /* a >= b */ -#define IS_TCPSEQ_LE(a, b) ((b - a) < NBITVAL(31)) /* a =< b */ -#define IS_TCPSEQ_GT(a, b) !IS_TCPSEQ_LE(a, b) /* a > b */ -#define IS_TCPSEQ_LT(a, b) !IS_TCPSEQ_GE(a, b) /* a < b */ - -#endif /* #ifndef _bcmtcp_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h deleted file mode 100755 index 096794592a8e..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: bt_amp_hci.h 382882 2013-02-04 23:24:31Z $ -*/ - -#ifndef _bt_amp_hci_h -#define _bt_amp_hci_h - -/* This marks the start of a packed structure section. */ -#include - - -/* AMP HCI CMD packet format */ -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd { - uint16 opcode; - uint8 plen; - uint8 parms[1]; -} BWL_POST_PACKED_STRUCT amp_hci_cmd_t; - -#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms) -#define HCI_CMD_DATA_SIZE 255 - -/* AMP HCI CMD opcode layout */ -#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF)) -#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F)) -#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF) - -/* AMP HCI command opcodes */ -#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001) -#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002) -#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003) -#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009) -#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A) -#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B) -#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035) -#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036) -#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037) -#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038) -#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039) -#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A) -#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B) -#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C) -#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067) -#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069) -#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A) -#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B) -#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003) -#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015) -#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016) -#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036) -#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037) -#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F) -#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061) -#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062) -#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063) -#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064) -#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065) -#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001) -#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002) -#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005) -#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A) - -/* AMP HCI command parameters */ -typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms { - uint8 plh; - uint8 offset[2]; /* length so far */ - uint8 max_remote[2]; -} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms { - uint8 plh; - uint8 offset[2]; - uint8 len[2]; - uint8 frag[1]; -} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms { - uint8 plh; - uint8 key_length; - uint8 key_type; - uint8 key[1]; -} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms { - uint8 plh; - uint8 reason; -} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms { - uint8 plh; - uint8 txflow[16]; - uint8 rxflow[16]; -} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec { - uint8 id; - uint8 service_type; - uint8 max_sdu[2]; - uint8 sdu_ia_time[4]; - uint8 access_latency[4]; - uint8 flush_timeout[4]; -} BWL_POST_PACKED_STRUCT ext_flow_spec_t; - -typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms { - uint8 plh; - uint8 tx_fs_ID; -} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms { - uint8 llh[2]; - uint8 txflow[16]; - uint8 rxflow[16]; -} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct plh_pad { - uint8 plh; - uint8 pad; -} BWL_POST_PACKED_STRUCT plh_pad_t; - -typedef BWL_PRE_PACKED_STRUCT union hci_handle { - uint16 bredr; - plh_pad_t amp; -} BWL_POST_PACKED_STRUCT hci_handle_t; - -typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms { - hci_handle_t handle; - uint8 timeout[2]; -} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms { - uint8 llh[2]; - uint8 befto[4]; -} BWL_POST_PACKED_STRUCT befto_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms { - uint8 plh; - uint8 srm; -} BWL_POST_PACKED_STRUCT srm_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms { - uint8 ld_aware; - uint8 ld[2]; - uint8 ld_opts; - uint8 l_opts; -} BWL_POST_PACKED_STRUCT ld_cmd_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms { - uint8 llh[2]; - uint8 packet_type; -} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t; - -/* Generic AMP extended flow spec service types */ -#define EFS_SVCTYPE_NO_TRAFFIC 0 -#define EFS_SVCTYPE_BEST_EFFORT 1 -#define EFS_SVCTYPE_GUARANTEED 2 - -/* AMP HCI event packet format */ -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event { - uint8 ecode; - uint8 plen; - uint8 parms[1]; -} BWL_POST_PACKED_STRUCT amp_hci_event_t; - -#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms) - -/* AMP HCI event codes */ -#define HCI_Command_Complete 0x0E -#define HCI_Command_Status 0x0F -#define HCI_Flush_Occurred 0x11 -#define HCI_Enhanced_Flush_Complete 0x39 -#define HCI_Physical_Link_Complete 0x40 -#define HCI_Channel_Select 0x41 -#define HCI_Disconnect_Physical_Link_Complete 0x42 -#define HCI_Logical_Link_Complete 0x45 -#define HCI_Disconnect_Logical_Link_Complete 0x46 -#define HCI_Flow_Spec_Modify_Complete 0x47 -#define HCI_Number_of_Completed_Data_Blocks 0x48 -#define HCI_Short_Range_Mode_Change_Complete 0x4C -#define HCI_Status_Change_Event 0x4D -#define HCI_Vendor_Specific 0xFF - -/* AMP HCI event mask bit positions */ -#define HCI_Physical_Link_Complete_Event_Mask 0x0001 -#define HCI_Channel_Select_Event_Mask 0x0002 -#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004 -#define HCI_Logical_Link_Complete_Event_Mask 0x0020 -#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040 -#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080 -#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100 -#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000 -#define HCI_Status_Change_Event_Mask 0x2000 -#define HCI_All_Event_Mask 0x31e7 -/* AMP HCI event parameters */ -typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms { - uint8 status; - uint8 cmdpkts; - uint16 opcode; -} BWL_POST_PACKED_STRUCT cmd_status_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms { - uint8 cmdpkts; - uint16 opcode; - uint8 parms[1]; -} BWL_POST_PACKED_STRUCT cmd_complete_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms { - uint16 handle; -} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms { - uint8 status; - uint8 plh; -} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms { - uint8 status; - uint8 plh; - uint16 len; - uint8 frag[1]; -} BWL_POST_PACKED_STRUCT read_local_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms { - uint8 status; - uint8 AMP_status; - uint32 bandwidth; - uint32 gbandwidth; - uint32 latency; - uint32 PDU_size; - uint8 ctrl_type; - uint16 PAL_cap; - uint16 AMP_ASSOC_len; - uint32 max_flush_timeout; - uint32 be_flush_timeout; -} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms { - uint8 status; - uint16 llh; - uint8 plh; - uint8 tx_fs_ID; -} BWL_POST_PACKED_STRUCT log_link_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms { - uint8 status; - uint16 llh; - uint8 reason; -} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms { - uint8 status; - uint8 plh; - uint8 tx_fs_ID; -} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms { - uint8 status; - uint16 llh; -} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms { - uint8 status; - uint8 plh; -} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms { - uint8 status; - uint8 plh; - uint8 reason; -} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms { - uint8 status; - hci_handle_t handle; - uint16 timeout; -} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms { - uint8 status; - uint16 timeout; -} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms { - uint8 status; - uint16 ACL_pkt_len; - uint16 data_block_len; - uint16 data_block_num; -} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct data_blocks { - uint16 handle; - uint16 pkts; - uint16 blocks; -} BWL_POST_PACKED_STRUCT data_blocks_t; - -typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms { - uint16 num_blocks; - uint8 num_handles; - data_blocks_t completed[1]; -} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms { - uint8 status; - uint32 befto; -} BWL_POST_PACKED_STRUCT befto_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms { - uint8 status; - uint8 plh; - uint8 srm; -} BWL_POST_PACKED_STRUCT srm_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms { - uint8 status; - uint8 llh[2]; - uint16 counter; -} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms { - uint8 status; - uint8 llh[2]; -} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms { - uint8 status; - hci_handle_t handle; - uint8 link_quality; -} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms { - uint8 status; - uint8 ld_aware; - uint8 ld[2]; - uint8 ld_opts; - uint8 l_opts; -} BWL_POST_PACKED_STRUCT ld_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms { - uint16 handle; -} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms { - uint8 len; - uint8 parms[1]; -} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms { - uint8 status; - uint8 hci_version; - uint16 hci_revision; - uint8 pal_version; - uint16 mfg_name; - uint16 pal_subversion; -} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t; - -#define MAX_SUPPORTED_CMD_BYTE 64 -typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms { - uint8 status; - uint8 cmd[MAX_SUPPORTED_CMD_BYTE]; -} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t; - -typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms { - uint8 status; - uint8 amp_status; -} BWL_POST_PACKED_STRUCT status_change_evt_parms_t; - -/* AMP HCI error codes */ -#define HCI_SUCCESS 0x00 -#define HCI_ERR_ILLEGAL_COMMAND 0x01 -#define HCI_ERR_NO_CONNECTION 0x02 -#define HCI_ERR_MEMORY_FULL 0x07 -#define HCI_ERR_CONNECTION_TIMEOUT 0x08 -#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 -#define HCI_ERR_CONNECTION_EXISTS 0x0B -#define HCI_ERR_CONNECTION_DISALLOWED 0x0C -#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10 -#define HCI_ERR_UNSUPPORTED_VALUE 0x11 -#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 -#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16 -#define HCI_ERR_UNSPECIFIED 0x1F -#define HCI_ERR_UNIT_KEY_USED 0x26 -#define HCI_ERR_QOS_REJECTED 0x2D -#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 -#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39 -#define HCI_ERR_CHANNEL_MOVE 0xFF - -/* AMP HCI ACL Data packet format */ -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data { - uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */ - uint16 dlen; /* data total length */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t; - -#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data) - -#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14) -#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12) - -#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff) -#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12) - -/* AMP Activity Report packet formats */ -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report { - uint8 ScheduleKnown; - uint8 NumReports; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t; - -typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple { - uint32 StartTime; - uint32 Duration; - uint32 Periodicity; -} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t; - -#define HCI_AR_SCHEDULE_KNOWN 0x01 - - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _bt_amp_hci_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h deleted file mode 100755 index d6a84f24fbc2..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Broadcom Event protocol definitions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Dependencies: proto/bcmeth.h - * - * $Id: dnglevent.h $ - * - */ - -/* - * Broadcom dngl Ethernet Events protocol defines - * - */ - -#ifndef _DNGLEVENT_H_ -#define _DNGLEVENT_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif -#include - -/* This marks the start of a packed structure section. */ -#include -#define BCM_DNGL_EVENT_MSG_VERSION 1 -#define DNGL_E_SOCRAM_IND 0x2 -typedef BWL_PRE_PACKED_STRUCT struct -{ - uint16 version; /* Current version is 1 */ - uint16 reserved; /* reserved for any future extension */ - uint16 event_type; /* DNGL_E_SOCRAM_IND */ - uint16 datalen; /* Length of the event payload */ -} BWL_POST_PACKED_STRUCT bcm_dngl_event_msg_t; - -typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_event { - struct ether_header eth; - bcmeth_hdr_t bcm_hdr; - bcm_dngl_event_msg_t dngl_event; - /* data portion follows */ -} BWL_POST_PACKED_STRUCT bcm_dngl_event_t; - - -/* SOCRAM_IND type tags */ -#define SOCRAM_IND_ASSRT_TAG 0x1 -#define SOCRAM_IND_TAG_HEALTH_CHECK 0x2 -typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_socramind { - uint16 tag; /* data tag */ - uint16 length; /* data length */ - uint8 value[1]; /* data value with variable length specified by length */ -} BWL_POST_PACKED_STRUCT bcm_dngl_socramind_t; - -/* Health check top level module tags */ -#define HEALTH_CHECK_TOP_LEVEL_MODULE_PCIEDEV_RTE 1 -typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_healthcheck { - uint16 top_module_tag; /* top level module tag */ - uint16 top_module_len; /* Type of PCIE issue indication */ - uint8 value[1]; /* data value with variable length specified by length */ -} BWL_POST_PACKED_STRUCT bcm_dngl_healthcheck_t; - -#define HEALTH_CHECK_PCIEDEV_VERSION 1 -#define HEALTH_CHECK_PCIEDEV_FLAG_IN_D3_SHIFT 0 -#define HEALTH_CHECK_PCIEDEV_FLAG_IN_D3_FLAG 1 << HEALTH_CHECK_PCIEDEV_FLAG_IN_D3_SHIFT -/* PCIE Module TAGs */ -#define HEALTH_CHECK_PCIEDEV_INDUCED_IND 0x1 -#define HEALTH_CHECK_PCIEDEV_H2D_DMA_IND 0x2 -#define HEALTH_CHECK_PCIEDEV_D2H_DMA_IND 0x3 -typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_pcie_hc { - uint16 version; /* HEALTH_CHECK_PCIEDEV_VERSION */ - uint16 reserved; - uint16 pcie_err_ind_type; /* PCIE Module TAGs */ - uint16 pcie_flag; - uint32 pcie_control_reg; -} BWL_POST_PACKED_STRUCT bcm_dngl_pcie_hc_t; - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _DNGLEVENT_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h deleted file mode 100755 index 7b012eecb110..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 802.1x EAPOL definitions - * - * See - * IEEE Std 802.1X-2001 - * IEEE 802.1X RADIUS Usage Guidelines - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: eapol.h 528449 2015-01-22 09:38:18Z $ - */ - -#ifndef _eapol_h_ -#define _eapol_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - -#include - -/* EAPOL for 802.3/Ethernet */ -typedef BWL_PRE_PACKED_STRUCT struct { - struct ether_header eth; /* 802.3/Ethernet header */ - unsigned char version; /* EAPOL protocol version */ - unsigned char type; /* EAPOL type */ - unsigned short length; /* Length of body */ - unsigned char body[1]; /* Body (optional) */ -} BWL_POST_PACKED_STRUCT eapol_header_t; - -#define EAPOL_HEADER_LEN 18 - -typedef struct { - unsigned char version; /* EAPOL protocol version */ - unsigned char type; /* EAPOL type */ - unsigned short length; /* Length of body */ -} eapol_hdr_t; - -#define EAPOL_HDR_LEN 4 - -/* EAPOL version */ -#define WPA2_EAPOL_VERSION 2 -#define WPA_EAPOL_VERSION 1 -#define LEAP_EAPOL_VERSION 1 -#define SES_EAPOL_VERSION 1 - -/* EAPOL types */ -#define EAP_PACKET 0 -#define EAPOL_START 1 -#define EAPOL_LOGOFF 2 -#define EAPOL_KEY 3 -#define EAPOL_ASF 4 - -/* EAPOL-Key types */ -#define EAPOL_RC4_KEY 1 -#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ -#define EAPOL_WPA_KEY 254 /* WPA */ - -/* RC4 EAPOL-Key header field sizes */ -#define EAPOL_KEY_REPLAY_LEN 8 -#define EAPOL_KEY_IV_LEN 16 -#define EAPOL_KEY_SIG_LEN 16 - -/* RC4 EAPOL-Key */ -typedef BWL_PRE_PACKED_STRUCT struct { - unsigned char type; /* Key Descriptor Type */ - unsigned short length; /* Key Length (unaligned) */ - unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ - unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ - unsigned char index; /* Key Flags & Index */ - unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ - unsigned char key[1]; /* Key (optional) */ -} BWL_POST_PACKED_STRUCT eapol_key_header_t; - -#define EAPOL_KEY_HEADER_LEN 44 - -/* RC4 EAPOL-Key flags */ -#define EAPOL_KEY_FLAGS_MASK 0x80 -#define EAPOL_KEY_BROADCAST 0 -#define EAPOL_KEY_UNICAST 0x80 - -/* RC4 EAPOL-Key index */ -#define EAPOL_KEY_INDEX_MASK 0x7f - -/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ -#define EAPOL_WPA_KEY_REPLAY_LEN 8 -#define EAPOL_WPA_KEY_NONCE_LEN 32 -#define EAPOL_WPA_KEY_IV_LEN 16 -#define EAPOL_WPA_KEY_RSC_LEN 8 -#define EAPOL_WPA_KEY_ID_LEN 8 -#define EAPOL_WPA_KEY_MIC_LEN 16 -#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) -#define EAPOL_WPA_MAX_KEY_SIZE 32 - -/* WPA EAPOL-Key */ -typedef BWL_PRE_PACKED_STRUCT struct { - unsigned char type; /* Key Descriptor Type */ - unsigned short key_info; /* Key Information (unaligned) */ - unsigned short key_len; /* Key Length (unaligned) */ - unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ - unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ - unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ - unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ - unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ - unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ - unsigned short data_len; /* Key Data Length */ - unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ -} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t; - -#define EAPOL_WPA_KEY_LEN 95 - -/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ -#define WPA_KEY_DESC_V1 0x01 -#define WPA_KEY_DESC_V2 0x02 -#define WPA_KEY_DESC_V3 0x03 -#define WPA_KEY_PAIRWISE 0x08 -#define WPA_KEY_INSTALL 0x40 -#define WPA_KEY_ACK 0x80 -#define WPA_KEY_MIC 0x100 -#define WPA_KEY_SECURE 0x200 -#define WPA_KEY_ERROR 0x400 -#define WPA_KEY_REQ 0x800 - -#define WPA_KEY_DESC_V2_OR_V3 WPA_KEY_DESC_V2 - -/* WPA-only KEY KEY_INFO bits */ -#define WPA_KEY_INDEX_0 0x00 -#define WPA_KEY_INDEX_1 0x10 -#define WPA_KEY_INDEX_2 0x20 -#define WPA_KEY_INDEX_3 0x30 -#define WPA_KEY_INDEX_MASK 0x30 -#define WPA_KEY_INDEX_SHIFT 0x04 - -/* 802.11i/WPA2-only KEY KEY_INFO bits */ -#define WPA_KEY_ENCRYPTED_DATA 0x1000 - -/* Key Data encapsulation */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 type; - uint8 length; - uint8 oui[3]; - uint8 subtype; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; - -#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 - -#define WPA2_KEY_DATA_SUBTYPE_GTK 1 -#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 -#define WPA2_KEY_DATA_SUBTYPE_MAC 3 -#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 -#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 - -/* GTK encapsulation */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 flags; - uint8 reserved; - uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; -} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; - -#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 - -#define WPA2_GTK_INDEX_MASK 0x03 -#define WPA2_GTK_INDEX_SHIFT 0x00 - -#define WPA2_GTK_TRANSMIT 0x04 - -/* IGTK encapsulation */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 key_id; - uint8 ipn[6]; - uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; -} BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; - -#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8 - -/* STAKey encapsulation */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 reserved[2]; - uint8 mac[ETHER_ADDR_LEN]; - uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; -} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t; - -#define WPA2_KEY_DATA_PAD 0xdd - - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _eapol_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h deleted file mode 100755 index 3542492743ec..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: ethernet.h 403353 2013-05-20 14:05:33Z $ - */ - -#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ -#define _NET_ETHERNET_H_ - -#ifndef _TYPEDEFS_H_ -#include "typedefs.h" -#endif - -/* This marks the start of a packed structure section. */ -#include - - -/* - * The number of bytes in an ethernet (MAC) address. - */ -#define ETHER_ADDR_LEN 6 - -/* - * The number of bytes in the type field. - */ -#define ETHER_TYPE_LEN 2 - -/* - * The number of bytes in the trailing CRC field. - */ -#define ETHER_CRC_LEN 4 - -/* - * The length of the combined header. - */ -#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) - -/* - * The minimum packet length. - */ -#define ETHER_MIN_LEN 64 - -/* - * The minimum packet user data length. - */ -#define ETHER_MIN_DATA 46 - -/* - * The maximum packet length. - */ -#define ETHER_MAX_LEN 1518 - -/* - * The maximum packet user data length. - */ -#define ETHER_MAX_DATA 1500 - -/* ether types */ -#define ETHER_TYPE_MIN 0x0600 /* Anything less than MIN is a length */ -#define ETHER_TYPE_IP 0x0800 /* IP */ -#define ETHER_TYPE_ARP 0x0806 /* ARP */ -#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */ -#define ETHER_TYPE_IPV6 0x86dd /* IPv6 */ -#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */ -#define ETHER_TYPE_802_1X 0x888e /* 802.1x */ -#ifdef PLC -#define ETHER_TYPE_88E1 0x88e1 /* GIGLE */ -#define ETHER_TYPE_8912 0x8912 /* GIGLE */ -#define ETHER_TYPE_GIGLED 0xffff /* GIGLE */ -#endif /* PLC */ -#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */ -#define ETHER_TYPE_WAI 0x88b4 /* WAI */ -#define ETHER_TYPE_89_0D 0x890d /* 89-0d frame for TDLS */ - -#define ETHER_TYPE_PPP_SES 0x8864 /* PPPoE Session */ - -#define ETHER_TYPE_IAPP_L2_UPDATE 0x6 /* IAPP L2 update frame */ - -/* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */ -#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */ - -/* ether header */ -#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) /* dest address offset */ -#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) /* src address offset */ -#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) /* ether type offset */ - -/* - * A macro to validate a length with - */ -#define ETHER_IS_VALID_LEN(foo) \ - ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) - -#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ - ((uint8 *)ea)[0] = 0x01; \ - ((uint8 *)ea)[1] = 0x00; \ - ((uint8 *)ea)[2] = 0x5e; \ - ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ - ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ - ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ -} - -#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ -/* - * Structure of a 10Mb/s Ethernet header. - */ -BWL_PRE_PACKED_STRUCT struct ether_header { - uint8 ether_dhost[ETHER_ADDR_LEN]; - uint8 ether_shost[ETHER_ADDR_LEN]; - uint16 ether_type; -} BWL_POST_PACKED_STRUCT; - -/* - * Structure of a 48-bit Ethernet address. - */ -BWL_PRE_PACKED_STRUCT struct ether_addr { - uint8 octet[ETHER_ADDR_LEN]; -} BWL_POST_PACKED_STRUCT; -#endif /* !__INCif_etherh Quick and ugly hack for VxWorks */ - -/* - * Takes a pointer, set, test, clear, toggle locally admininistered - * address bit in the 48-bit Ethernet address. - */ -#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) -#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) -#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) -#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) - -/* Takes a pointer, marks unicast address bit in the MAC address */ -#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) - -/* - * Takes a pointer, returns true if a 48-bit multicast address - * (including broadcast, since it is all ones) - */ -#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) - - -/* compare two ethernet addresses - assumes the pointers can be referenced as shorts */ -#define eacmp(a, b) ((((const uint16 *)(a))[0] ^ ((const uint16 *)(b))[0]) | \ - (((const uint16 *)(a))[1] ^ ((const uint16 *)(b))[1]) | \ - (((const uint16 *)(a))[2] ^ ((const uint16 *)(b))[2])) - -#define ether_cmp(a, b) eacmp(a, b) - -/* copy an ethernet address - assumes the pointers can be referenced as shorts */ -#define eacopy(s, d) \ -do { \ - ((uint16 *)(d))[0] = ((const uint16 *)(s))[0]; \ - ((uint16 *)(d))[1] = ((const uint16 *)(s))[1]; \ - ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \ -} while (0) - -#define ether_copy(s, d) eacopy(s, d) - -/* Copy an ethernet address in reverse order */ -#define ether_rcopy(s, d) \ -do { \ - ((uint16 *)(d))[2] = ((uint16 *)(s))[2]; \ - ((uint16 *)(d))[1] = ((uint16 *)(s))[1]; \ - ((uint16 *)(d))[0] = ((uint16 *)(s))[0]; \ -} while (0) - - - -static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; -static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; -static const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; - -#define ETHER_ISBCAST(ea) ((((const uint8 *)(ea))[0] & \ - ((const uint8 *)(ea))[1] & \ - ((const uint8 *)(ea))[2] & \ - ((const uint8 *)(ea))[3] & \ - ((const uint8 *)(ea))[4] & \ - ((const uint8 *)(ea))[5]) == 0xff) -#define ETHER_ISNULLADDR(ea) ((((const uint8 *)(ea))[0] | \ - ((const uint8 *)(ea))[1] | \ - ((const uint8 *)(ea))[2] | \ - ((const uint8 *)(ea))[3] | \ - ((const uint8 *)(ea))[4] | \ - ((const uint8 *)(ea))[5]) == 0) - -#define ETHER_ISNULLDEST(da) ((((const uint16 *)(da))[0] | \ - ((const uint16 *)(da))[1] | \ - ((const uint16 *)(da))[2]) == 0) -#define ETHER_ISNULLSRC(sa) ETHER_ISNULLDEST(sa) - -#define ETHER_MOVE_HDR(d, s) \ -do { \ - struct ether_header t; \ - t = *(struct ether_header *)(s); \ - *(struct ether_header *)(d) = t; \ -} while (0) - -#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0) - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _NET_ETHERNET_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h deleted file mode 100755 index 0c2d922a6d77..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental types and constants relating to WFA NAN - * (Neighbor Awareness Networking) - * - * $Id$ - */ -#ifndef _NAN_H_ -#define _NAN_H_ - -#include -#include - - -/* This marks the start of a packed structure section. */ -#include - -/* WiFi NAN OUI values */ -#define NAN_OUI WFA_OUI /* WiFi OUI */ -/* For oui_type field identifying the type and version of the NAN IE. */ -#define NAN_OUI_TYPE 0x13 /* Type/Version */ -/* IEEE 802.11 vendor specific information element. (Same as P2P_IE_ID.) */ -#define NAN_IE_ID 0xdd - -/* Same as P2P_PUB_AF_CATEGORY and DOT11_ACTION_CAT_PUBLIC */ -#define NAN_PUB_AF_CATEGORY 0x04 -/* IEEE 802.11 Public Action Frame Vendor Specific. (Same as P2P_PUB_AF_ACTION.) */ -#define NAN_PUB_AF_ACTION 0x09 -/* Number of octents in hash of service name. (Same as P2P_WFDS_HASH_LEN.) */ -#define NAN_SVC_HASH_LEN 6 -/* Size of fixed length part of nan_pub_act_frame_t before attributes. */ -#define NAN_PUB_ACT_FRAME_FIXED_LEN 6 -/* Number of octents in master rank value. */ -#define NAN_MASTER_RANK_LEN 8 -/* NAN public action frame header size */ -#define NAN_PUB_ACT_FRAME_HDR_SIZE (OFFSETOF(nan_pub_act_frame_t, data)) -/* NAN network ID */ -#define NAN_NETWORK_ID "\x51\x6F\x9A\x01\x00\x00" -/* Service Control Type length */ -#define NAN_SVC_CONTROL_TYPE_LEN 2 - -/* Attribute TLV header size */ -#define NAN_ATTR_ID_OFF 0 -#define NAN_ATTR_LEN_OFF 1 -#define NAN_ATTR_DATA_OFF 3 - -#define NAN_ATTR_ID_LEN 1 /* ID field length */ -#define NAN_ATTR_LEN_LEN 2 /* Length field length */ -#define NAN_ATTR_HDR_LEN 3 /* ID + 2-byte length field */ - -/* Vendor-specific public action frame for NAN */ -typedef BWL_PRE_PACKED_STRUCT struct nan_pub_act_frame_s { - /* NAN_PUB_AF_CATEGORY 0x04 */ - uint8 category_id; - /* NAN_PUB_AF_ACTION 0x09 */ - uint8 action_field; - /* NAN_OUI 0x50-6F-9A */ - uint8 oui[DOT11_OUI_LEN]; - /* NAN_OUI_TYPE 0x13 */ - uint8 oui_type; - /* One or more NAN Attributes follow */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT nan_pub_act_frame_t; - -/* NAN attributes as defined in the nan spec */ -enum { - NAN_ATTR_MASTER_IND = 0, - NAN_ATTR_CLUSTER = 1, - NAN_ATTR_SVC_ID_LIST = 2, - NAN_ATTR_SVC_DESCRIPTOR = 3, - NAN_ATTR_CONN_CAP = 4, - NAN_ATTR_INFRA = 5, - NAN_ATTR_P2P = 6, - NAN_ATTR_IBSS = 7, - NAN_ATTR_MESH = 8, - NAN_ATTR_FURTHER_NAN_SD = 9, - NAN_ATTR_FURTHER_AVAIL = 10, - NAN_ATTR_COUNTRY_CODE = 11, - NAN_ATTR_RANGING = 12, - NAN_ATTR_VENDOR_SPECIFIC = 221 -}; - -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ie_s { - uint8 id; /* IE ID: NAN_IE_ID 0xDD */ - uint8 len; /* IE length */ - uint8 oui[DOT11_OUI_LEN]; /* NAN_OUI 50:6F:9A */ - uint8 oui_type; /* NAN_OUI_TYPE 0x13 */ - uint8 attr[1]; /* var len attributes */ -} BWL_POST_PACKED_STRUCT wifi_nan_ie_t; - -#define NAN_IE_HDR_SIZE (OFFSETOF(wifi_nan_ie_t, attr)) - -/* master indication record */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_master_ind_attr_s { - uint8 id; - uint16 len; - uint8 master_preference; - uint8 random_factor; -} BWL_POST_PACKED_STRUCT wifi_nan_master_ind_attr_t; - -/* cluster attr record */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_cluster_attr_s { - uint8 id; - uint16 len; - uint8 amr[NAN_MASTER_RANK_LEN]; - uint8 hop_count; - /* Anchor Master Beacon Transmission Time */ - uint32 ambtt; -} BWL_POST_PACKED_STRUCT wifi_nan_cluster_attr_t; - -/* container for service ID records */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_id_attr_s { - uint8 id; - uint16 len; - uint8 svcid[NAN_SVC_HASH_LEN]; /* 6*len of srvc IDs */ -} BWL_POST_PACKED_STRUCT wifi_nan_svc_id_attr_t; - -/* service_control bitmap for wifi_nan_svc_descriptor_attr_t below */ -#define NAN_SC_PUBLISH 0x0 -#define NAN_SC_SUBSCRIBE 0x1 -#define NAN_SC_FOLLOWUP 0x2 -/* Set to 1 if a Matching Filter field is included in descriptors. */ -#define NAN_SC_MATCHING_FILTER_PRESENT 0x8 -/* Set to 1 if a Service Response Filter field is included in descriptors. */ -#define NAN_SC_SR_FILTER_PRESENT 0x10 -/* Set to 1 if a Service Info field is included in descriptors. */ -#define NAN_SC_SVC_INFO_PRESENT 0x20 -/* range is close proximity only */ -#define NAN_SC_RANGE_LIMITED 0x40 - -/* Service descriptor */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_descriptor_attr_s { - /* Attribute ID - 0x03. */ - uint8 id; - /* Length of the following fields in the attribute */ - uint16 len; - /* Hash of the Service Name */ - uint8 svc_hash[NAN_SVC_HASH_LEN]; - /* Publish or subscribe instance id */ - uint8 instance_id; - /* Requestor Instance ID */ - uint8 requestor_id; - /* Service Control Bitmask. Also determines what data follows. */ - uint8 svc_control; - /* Optional fields follow */ -} BWL_POST_PACKED_STRUCT wifi_nan_svc_descriptor_attr_t; - -/* IBSS attribute */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ibss_attr_s { - /* Attribute ID - 0x07. */ - uint8 id; - /* Length of the following fields in the attribute */ - uint16 len; - /* BSSID of the ibss */ - struct ether_addr bssid; - /* - map control:, bits: - [0-3]: Id for associated further avail map attribute - [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved - [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf? - [7] : reserved - */ - uint8 map_ctrl; - /* avail. intervals bitmap, var len */ - uint8 avail_bmp[1]; -} BWL_POST_PACKED_STRUCT wifi_nan_ibss_attr_t; - -/* Further Availability MAP attr */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_favail_attr_s { - /* Attribute ID - 0x0A. */ - uint8 id; - /* Length of the following fields in the attribute */ - uint16 len; - /* MAP id: val [0..15], values[16-255] reserved */ - uint8 map_id; - /* availibility entry, var len */ - uint8 avil_entry[1]; -} BWL_POST_PACKED_STRUCT wifi_nan_favail_attr_t; - -/* Further Availability MAP attr */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_s { - /* - entry control - [0-1]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; - [2:7] reserved - */ - uint8 entry_ctrl; - /* operating class: freq band etc IEEE 802.11 */ - uint8 opclass; - /* channel number */ - uint8 chan; - uint8 map_id; - /* avail bmp, var len */ - uint8 avail_bmp[1]; -} BWL_POST_PACKED_STRUCT wifi_nan_avail_entry_t; - -/* Map control Field */ -#define NAN_MAPCTRL_IDMASK 0x7 -#define NAN_MAPCTRL_DURSHIFT 3 -#define NAN_MAPCTRL_REPEAT 0x40 - -#define NAN_VENDOR_TYPE_RTT 0 - -/* Vendor Specific Attribute */ -typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_vendor_attr_s { - uint8 id; /* 0xDD */ - uint16 len; /* IE length */ - uint8 oui[DOT11_OUI_LEN]; /* 00-90-4C */ - uint8 type; /* attribute type */ - uint8 attr[1]; /* var len attributes */ -} BWL_POST_PACKED_STRUCT wifi_nan_vendor_attr_t; - -#define NAN_VENDOR_HDR_SIZE (OFFSETOF(wifi_nan_vendor_attr_t, attr)) - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _NAN_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h deleted file mode 100755 index 0ae7ef47e7bf..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) - * - * $Id: p2p.h 444066 2013-12-18 12:49:24Z $ - */ - -#ifndef _P2P_H_ -#define _P2P_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif -#include -#include - -/* This marks the start of a packed structure section. */ -#include - - -/* WiFi P2P OUI values */ -#define P2P_OUI WFA_OUI /* WiFi P2P OUI */ -#define P2P_VER WFA_OUI_TYPE_P2P /* P2P version: 9=WiFi P2P v1.0 */ - -#define P2P_IE_ID 0xdd /* P2P IE element ID */ - -/* WiFi P2P IE */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { - uint8 id; /* IE ID: 0xDD */ - uint8 len; /* IE length */ - uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ - uint8 oui_type; /* Identifies P2P version: P2P_VER */ - uint8 subelts[1]; /* variable length subelements */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_ie wifi_p2p_ie_t; - -#define P2P_IE_FIXED_LEN 6 - -#define P2P_ATTR_ID_OFF 0 -#define P2P_ATTR_LEN_OFF 1 -#define P2P_ATTR_DATA_OFF 3 - -#define P2P_ATTR_ID_LEN 1 /* ID filed length */ -#define P2P_ATTR_LEN_LEN 2 /* length field length */ -#define P2P_ATTR_HDR_LEN 3 /* ID + 2-byte length field spec 1.02 */ - -/* P2P IE Subelement IDs from WiFi P2P Technical Spec 1.00 */ -#define P2P_SEID_STATUS 0 /* Status */ -#define P2P_SEID_MINOR_RC 1 /* Minor Reason Code */ -#define P2P_SEID_P2P_INFO 2 /* P2P Capability (capabilities info) */ -#define P2P_SEID_DEV_ID 3 /* P2P Device ID */ -#define P2P_SEID_INTENT 4 /* Group Owner Intent */ -#define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */ -#define P2P_SEID_CHANNEL 6 /* Listen channel */ -#define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */ -#define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */ -#define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */ -#define P2P_SEID_P2P_MGBTY 10 /* P2P Manageability */ -#define P2P_SEID_CHAN_LIST 11 /* Channel List */ -#define P2P_SEID_ABSENCE 12 /* Notice of Absence */ -#define P2P_SEID_DEV_INFO 13 /* Device Info */ -#define P2P_SEID_GROUP_INFO 14 /* Group Info */ -#define P2P_SEID_GROUP_ID 15 /* Group ID */ -#define P2P_SEID_P2P_IF 16 /* P2P Interface */ -#define P2P_SEID_OP_CHANNEL 17 /* Operating Channel */ -#define P2P_SEID_INVITE_FLAGS 18 /* Invitation Flags */ -#define P2P_SEID_VNDR 221 /* Vendor-specific subelement */ - -#define P2P_SE_VS_ID_SERVICES 0x1b - - -/* WiFi P2P IE subelement: P2P Capability (capabilities info) */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { - uint8 eltId; /* SE ID: P2P_SEID_P2P_INFO */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 dev; /* Device Capability Bitmap */ - uint8 group; /* Group Capability Bitmap */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; - -/* P2P Capability subelement's Device Capability Bitmap bit values */ -#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 /* Service Discovery */ -#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 /* Client Discoverability */ -#define P2P_CAPSE_DEV_CONCURRENT 0x4 /* Concurrent Operation */ -#define P2P_CAPSE_DEV_INFRA_MAN 0x8 /* P2P Infrastructure Managed */ -#define P2P_CAPSE_DEV_LIMIT 0x10 /* P2P Device Limit */ -#define P2P_CAPSE_INVITE_PROC 0x20 /* P2P Invitation Procedure */ - -/* P2P Capability subelement's Group Capability Bitmap bit values */ -#define P2P_CAPSE_GRP_OWNER 0x1 /* P2P Group Owner */ -#define P2P_CAPSE_PERSIST_GRP 0x2 /* Persistent P2P Group */ -#define P2P_CAPSE_GRP_LIMIT 0x4 /* P2P Group Limit */ -#define P2P_CAPSE_GRP_INTRA_BSS 0x8 /* Intra-BSS Distribution */ -#define P2P_CAPSE_GRP_X_CONNECT 0x10 /* Cross Connection */ -#define P2P_CAPSE_GRP_PERSISTENT 0x20 /* Persistent Reconnect */ -#define P2P_CAPSE_GRP_FORMATION 0x40 /* Group Formation */ - - -/* WiFi P2P IE subelement: Group Owner Intent */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { - uint8 eltId; /* SE ID: P2P_SEID_INTENT */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 intent; /* Intent Value 0...15 (0=legacy 15=master only) */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; - -/* WiFi P2P IE subelement: Configuration Timeout */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { - uint8 eltId; /* SE ID: P2P_SEID_CFG_TIMEOUT */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 go_tmo; /* GO config timeout in units of 10 ms */ - uint8 client_tmo; /* Client config timeout in units of 10 ms */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; - -/* WiFi P2P IE subelement: Listen Channel */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_listen_channel_se_s { - uint8 eltId; /* SE ID: P2P_SEID_CHANNEL */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 country[3]; /* Country String */ - uint8 op_class; /* Operating Class */ - uint8 channel; /* Channel */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_listen_channel_se_s wifi_p2p_listen_channel_se_t; - -/* WiFi P2P IE subelement: P2P Group BSSID */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_bssid_se_s { - uint8 eltId; /* SE ID: P2P_SEID_GRP_BSSID */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P group bssid */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; - -/* WiFi P2P IE subelement: P2P Group ID */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { - uint8 eltId; /* SE ID: P2P_SEID_GROUP_ID */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P device address */ - uint8 ssid[1]; /* ssid. device id. variable length */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; - -/* WiFi P2P IE subelement: P2P Interface */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { - uint8 eltId; /* SE ID: P2P_SEID_P2P_IF */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P device address */ - uint8 ifaddrs; /* P2P Interface Address count */ - uint8 ifaddr[1][6]; /* P2P Interface Address list */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; - -/* WiFi P2P IE subelement: Status */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { - uint8 eltId; /* SE ID: P2P_SEID_STATUS */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 status; /* Status Code: P2P_STATSE_* */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; - -/* Status subelement Status Code definitions */ -#define P2P_STATSE_SUCCESS 0 - /* Success */ -#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 - /* Failed, information currently unavailable */ -#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL - /* Old name for above in P2P spec 1.08 and older */ -#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 - /* Failed, incompatible parameters */ -#define P2P_STATSE_FAIL_LIMIT_REACHED 3 - /* Failed, limit reached */ -#define P2P_STATSE_FAIL_INVALID_PARAMS 4 - /* Failed, invalid parameters */ -#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 - /* Failed, unable to accomodate request */ -#define P2P_STATSE_FAIL_PROTO_ERROR 6 - /* Failed, previous protocol error or disruptive behaviour */ -#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 - /* Failed, no common channels */ -#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 - /* Failed, unknown P2P Group */ -#define P2P_STATSE_FAIL_INTENT 9 - /* Failed, both peers indicated Intent 15 in GO Negotiation */ -#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 - /* Failed, incompatible provisioning method */ -#define P2P_STATSE_FAIL_USER_REJECT 11 - /* Failed, rejected by user */ - -/* WiFi P2P IE attribute: Extended Listen Timing */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { - uint8 eltId; /* ID: P2P_SEID_EXT_TIMING */ - uint8 len[2]; /* length not including eltId, len fields */ - uint8 avail[2]; /* availibility period */ - uint8 interval[2]; /* availibility interval */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; - -#define P2P_EXT_MIN 10 /* minimum 10ms */ - -/* WiFi P2P IE subelement: Intended P2P Interface Address */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { - uint8 eltId; /* SE ID: P2P_SEID_INTINTADDR */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* intended P2P interface MAC address */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; - -/* WiFi P2P IE subelement: Channel */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { - uint8 eltId; /* SE ID: P2P_SEID_STATUS */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 band; /* Regulatory Class (band) */ - uint8 channel; /* Channel */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; - - -/* Channel Entry structure within the Channel List SE */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { - uint8 band; /* Regulatory Class (band) */ - uint8 num_channels; /* # of channels in the channel list */ - uint8 channels[WL_NUMCHANNELS]; /* Channel List */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; -#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 - -/* WiFi P2P IE subelement: Channel List */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { - uint8 eltId; /* SE ID: P2P_SEID_CHAN_LIST */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 country[3]; /* Country String */ - uint8 num_entries; /* # of channel entries */ - wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; - /* Channel Entry List */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; - -/* WiFi Primary Device Type structure */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_pri_devtype_s { - uint16 cat_id; /* Category ID */ - uint8 OUI[3]; /* WFA OUI: 0x0050F2 */ - uint8 oui_type; /* WPS_OUI_TYPE */ - uint16 sub_cat_id; /* Sub Category ID */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_pri_devtype_s wifi_p2p_pri_devtype_t; - -/* WiFi P2P Device Info Sub Element Primary Device Type Sub Category - * maximum values for each category - */ -#define P2P_DISE_SUBCATEGORY_MINVAL 1 -#define P2P_DISE_CATEGORY_COMPUTER 1 -#define P2P_DISE_SUBCATEGORY_COMPUTER_MAXVAL 8 -#define P2P_DISE_CATEGORY_INPUT_DEVICE 2 -#define P2P_DISE_SUBCATEGORY_INPUT_DEVICE_MAXVAL 9 -#define P2P_DISE_CATEGORY_PRINTER 3 -#define P2P_DISE_SUBCATEGORY_PRINTER_MAXVAL 5 -#define P2P_DISE_CATEGORY_CAMERA 4 -#define P2P_DISE_SUBCATEGORY_CAMERA_MAXVAL 4 -#define P2P_DISE_CATEGORY_STORAGE 5 -#define P2P_DISE_SUBCATEGORY_STORAGE_MAXVAL 1 -#define P2P_DISE_CATEGORY_NETWORK_INFRA 6 -#define P2P_DISE_SUBCATEGORY_NETWORK_INFRA_MAXVAL 4 -#define P2P_DISE_CATEGORY_DISPLAY 7 -#define P2P_DISE_SUBCATEGORY_DISPLAY_MAXVAL 4 -#define P2P_DISE_CATEGORY_MULTIMEDIA 8 -#define P2P_DISE_SUBCATEGORY_MULTIMEDIA_MAXVAL 6 -#define P2P_DISE_CATEGORY_GAMING 9 -#define P2P_DISE_SUBCATEGORY_GAMING_MAXVAL 5 -#define P2P_DISE_CATEGORY_TELEPHONE 10 -#define P2P_DISE_SUBCATEGORY_TELEPHONE_MAXVAL 5 -#define P2P_DISE_CATEGORY_AUDIO 11 -#define P2P_DISE_SUBCATEGORY_AUDIO_MAXVAL 6 - -/* WiFi P2P IE's Device Info subelement */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { - uint8 eltId; /* SE ID: P2P_SEID_DEVINFO */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P Device MAC address */ - uint16 wps_cfg_meths; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ - uint8 pri_devtype[8]; /* Primary Device Type */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; - -#define P2P_DEV_TYPE_LEN 8 - -/* WiFi P2P IE's Group Info subelement Client Info Descriptor */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { - uint8 len; - uint8 devaddr[ETHER_ADDR_LEN]; /* P2P Device Address */ - uint8 ifaddr[ETHER_ADDR_LEN]; /* P2P Interface Address */ - uint8 devcap; /* Device Capability */ - uint8 cfg_meths[2]; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ - uint8 pridt[P2P_DEV_TYPE_LEN]; /* Primary Device Type */ - uint8 secdts; /* Number of Secondary Device Types */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; - -/* WiFi P2P IE's Device ID subelement */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { - uint8 eltId; - uint8 len[2]; - struct ether_addr addr; /* P2P Device MAC address */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; - -/* WiFi P2P IE subelement: P2P Manageability */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { - uint8 eltId; /* SE ID: P2P_SEID_P2P_MGBTY */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mg_bitmap; /* manageability bitmap */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; -/* mg_bitmap field bit values */ -#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 /* AP supports Managed P2P Device */ - -/* WiFi P2P IE subelement: Group Info */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { - uint8 eltId; /* SE ID: P2P_SEID_GROUP_INFO */ - uint8 len[2]; /* SE length not including eltId, len fields */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; - -/* WiFi IE subelement: Operating Channel */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_op_channel_se_s { - uint8 eltId; /* SE ID: P2P_SEID_OP_CHANNEL */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 country[3]; /* Country String */ - uint8 op_class; /* Operating Class */ - uint8 channel; /* Channel */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_op_channel_se_s wifi_p2p_op_channel_se_t; - -/* WiFi IE subelement: INVITATION FLAGS */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_invite_flags_se_s { - uint8 eltId; /* SE ID: P2P_SEID_INVITE_FLAGS */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 flags; /* Flags */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_invite_flags_se_s wifi_p2p_invite_flags_se_t; - -/* WiFi P2P Action Frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { - uint8 category; /* P2P_AF_CATEGORY */ - uint8 OUI[3]; /* OUI - P2P_OUI */ - uint8 type; /* OUI Type - P2P_VER */ - uint8 subtype; /* OUI Subtype - P2P_AF_* */ - uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ - uint8 elts[1]; /* Variable length information elements. Max size = - * ACTION_FRAME_SIZE - sizeof(this structure) - 1 - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; -#define P2P_AF_CATEGORY 0x7f - -#define P2P_AF_FIXED_LEN 7 - -/* WiFi P2P Action Frame OUI Subtypes */ -#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ -#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ -#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ -#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ - - -/* WiFi P2P Public Action Frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { - uint8 category; /* P2P_PUB_AF_CATEGORY */ - uint8 action; /* P2P_PUB_AF_ACTION */ - uint8 oui[3]; /* P2P_OUI */ - uint8 oui_type; /* OUI type - P2P_VER */ - uint8 subtype; /* OUI subtype - P2P_TYPE_* */ - uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ - uint8 elts[1]; /* Variable length information elements. Max size = - * ACTION_FRAME_SIZE - sizeof(this structure) - 1 - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; -#define P2P_PUB_AF_FIXED_LEN 8 -#define P2P_PUB_AF_CATEGORY 0x04 -#define P2P_PUB_AF_ACTION 0x09 - -/* WiFi P2P Public Action Frame OUI Subtypes */ -#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ -#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ -#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ -#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ -#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ -#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ -#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ -#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ -#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ -#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ - -/* TODO: Stop using these obsolete aliases for P2P_PAF_GON_* */ -#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ -#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP -#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF - -/* WiFi P2P IE subelement: Notice of Absence */ -BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { - uint8 cnt_type; /* Count/Type */ - uint32 duration; /* Duration */ - uint32 interval; /* Interval */ - uint32 start; /* Start Time */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; - -BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { - uint8 eltId; /* Subelement ID */ - uint8 len[2]; /* Length */ - uint8 index; /* Index */ - uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ - wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; - -#define P2P_NOA_SE_FIXED_LEN 5 - -#define P2P_NOA_SE_MAX_DESC 2 /* max NoA descriptors in presence request */ - -/* cnt_type field values */ -#define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */ -#define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */ -#define P2P_NOA_DESC_TYPE_PREFERRED 1 /* preferred values */ -#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 /* acceptable limits */ - -/* ctw_ops_parms field values */ -#define P2P_NOA_CTW_MASK 0x7f -#define P2P_NOA_OPS_MASK 0x80 -#define P2P_NOA_OPS_SHIFT 7 - -#define P2P_CTW_MIN 10 /* minimum 10TU */ - -/* - * P2P Service Discovery related - */ -#define P2PSD_ACTION_CATEGORY 0x04 - /* Public action frame */ -#define P2PSD_ACTION_ID_GAS_IREQ 0x0a - /* Action value for GAS Initial Request AF */ -#define P2PSD_ACTION_ID_GAS_IRESP 0x0b - /* Action value for GAS Initial Response AF */ -#define P2PSD_ACTION_ID_GAS_CREQ 0x0c - /* Action value for GAS Comback Request AF */ -#define P2PSD_ACTION_ID_GAS_CRESP 0x0d - /* Action value for GAS Comback Response AF */ -#define P2PSD_AD_EID 0x6c - /* Advertisement Protocol IE ID */ -#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 - /* Query Response Length Limit 7 bits plus PAME-BI 1 bit */ -#define P2PSD_ADP_PROTO_ID 0x00 - /* Advertisement Protocol ID. Always 0 for P2P SD */ -#define P2PSD_GAS_OUI P2P_OUI - /* WFA OUI */ -#define P2PSD_GAS_OUI_SUBTYPE P2P_VER - /* OUI Subtype for GAS IE */ -#define P2PSD_GAS_NQP_INFOID 0xDDDD - /* NQP Query Info ID: 56797 */ -#define P2PSD_GAS_COMEBACKDEALY 0x00 - /* Not used in the Native GAS protocol */ - -/* Service Protocol Type */ -typedef enum p2psd_svc_protype { - SVC_RPOTYPE_ALL = 0, - SVC_RPOTYPE_BONJOUR = 1, - SVC_RPOTYPE_UPNP = 2, - SVC_RPOTYPE_WSD = 3, - SVC_RPOTYPE_VENDOR = 255 -} p2psd_svc_protype_t; - -/* Service Discovery response status code */ -typedef enum { - P2PSD_RESP_STATUS_SUCCESS = 0, - P2PSD_RESP_STATUS_PROTYPE_NA = 1, - P2PSD_RESP_STATUS_DATA_NA = 2, - P2PSD_RESP_STATUS_BAD_REQUEST = 3 -} p2psd_resp_status_t; - -/* Advertisement Protocol IE tuple field */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { - uint8 llm_pamebi; /* Query Response Length Limit bit 0-6, set to 0 plus - * Pre-Associated Message Exchange BSSID Independent bit 7, set to 0 - */ - uint8 adp_id; /* Advertisement Protocol ID: 0 for NQP Native Query Protocol */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; - -/* Advertisement Protocol IE */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { - uint8 id; /* IE ID: 0x6c - 108 */ - uint8 len; /* IE length */ - wifi_p2psd_adp_tpl_t adp_tpl; /* Advertisement Protocol Tuple field. Only one - * tuple is defined for P2P Service Discovery - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; - -/* NQP Vendor-specific Content */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { - uint8 oui_subtype; /* OUI Subtype: 0x09 */ - uint16 svc_updi; /* Service Update Indicator */ - uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request, - * wifi_p2psd_qresp_tlv_t type for service response - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; - -/* Service Request TLV */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { - uint16 len; /* Length: 5 plus size of Query Data */ - uint8 svc_prot; /* Service Protocol Type */ - uint8 svc_tscid; /* Service Transaction ID */ - uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; - -/* Query Request Frame, defined in generic format, instead of NQP specific */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { - uint16 info_id; /* Info ID: 0xDDDD */ - uint16 len; /* Length of service request TLV, 5 plus the size of request data */ - uint8 oui[3]; /* WFA OUI: 0x0050F2 */ - uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */ - -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; - -/* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { - wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ - uint16 qreq_len; /* Query Request Length */ - uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; - -/* Service Response TLV */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { - uint16 len; /* Length: 5 plus size of Query Data */ - uint8 svc_prot; /* Service Protocol Type */ - uint8 svc_tscid; /* Service Transaction ID */ - uint8 status; /* Value defined in Table 57 of P2P spec. */ - uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; - -/* Query Response Frame, defined in generic format, instead of NQP specific */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { - uint16 info_id; /* Info ID: 0xDDDD */ - uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */ - uint8 oui[3]; /* WFA OUI: 0x0050F2 */ - uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */ - -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; - -/* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { - uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ - uint16 cb_delay; /* GAS Comeback Delay */ - wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ - uint16 qresp_len; /* Query Response Length */ - uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; - -/* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { - uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ - uint8 fragment_id; /* Fragmentation ID */ - uint16 cb_delay; /* GAS Comeback Delay */ - wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ - uint16 qresp_len; /* Query Response Length */ - uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; - -/* Wi-Fi GAS Public Action Frame */ -BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { - uint8 category; /* 0x04 Public Action Frame */ - uint8 action; /* 0x6c Advertisement Protocol */ - uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ - uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t - * or wifi_p2psd_gas_iresp_frame_t format - */ -} BWL_POST_PACKED_STRUCT; -typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _P2P_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h deleted file mode 100755 index 98af94328abf..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SD-SPI Protocol Standard - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sdspi.h 382882 2013-02-04 23:24:31Z $ - */ -#ifndef _SD_SPI_H -#define _SD_SPI_H - -#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ -#define SPI_START_S 31 -#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ -#define SPI_DIR_S 30 -#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ -#define SPI_CMD_INDEX_S 24 -#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ -#define SPI_RW_S 23 -#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ -#define SPI_FUNC_S 20 -#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ -#define SPI_RAW_S 19 -#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ -#define SPI_STUFF_S 18 -#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ -#define SPI_BLKMODE_S 19 -#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ -#define SPI_OPCODE_S 18 -#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ -#define SPI_ADDR_S 1 -#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ -#define SPI_STUFF0_S 0 - -#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ -#define SPI_RSP_START_S 7 -#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ -#define SPI_RSP_PARAM_ERR_S 6 -#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ -#define SPI_RSP_RFU5_S 5 -#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ -#define SPI_RSP_FUNC_ERR_S 4 -#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ -#define SPI_RSP_CRC_ERR_S 3 -#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ -#define SPI_RSP_ILL_CMD_S 2 -#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ -#define SPI_RSP_RFU1_S 1 -#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ -#define SPI_RSP_IDLE_S 0 - -/* SD-SPI Protocol Definitions */ -#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ -#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ -#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ -#define SDSPI_START_BIT_MASK 0x80 - -#endif /* _SD_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h deleted file mode 100755 index 643a73a76a4b..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 802.1Q VLAN protocol definitions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: vlan.h 382883 2013-02-04 23:26:09Z $ - */ - -#ifndef _vlan_h_ -#define _vlan_h_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - -#ifndef VLAN_VID_MASK -#define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */ -#endif - -#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */ -#define VLAN_PRI_SHIFT 13 /* user priority */ - -#define VLAN_PRI_MASK 7 /* 3 bits of priority */ - -#define VLAN_TPID_OFFSET 12 /* offset of tag protocol id field */ -#define VLAN_TCI_OFFSET 14 /* offset of tag ctrl info field */ - -#define VLAN_TAG_LEN 4 -#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */ - -#define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */ - -struct vlan_header { - uint16 vlan_type; /* 0x8100 */ - uint16 vlan_tag; /* priority, cfi and vid */ -}; - -struct ethervlan_header { - uint8 ether_dhost[ETHER_ADDR_LEN]; - uint8 ether_shost[ETHER_ADDR_LEN]; - uint16 vlan_type; /* 0x8100 */ - uint16 vlan_tag; /* priority, cfi and vid */ - uint16 ether_type; -}; - -struct dot3_mac_llc_snapvlan_header { - uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ - uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ - uint16 length; /* frame length incl header */ - uint8 dsap; /* always 0xAA */ - uint8 ssap; /* always 0xAA */ - uint8 ctl; /* always 0x03 */ - uint8 oui[3]; /* RFC1042: 0x00 0x00 0x00 - * Bridge-Tunnel: 0x00 0x00 0xF8 - */ - uint16 vlan_type; /* 0x8100 */ - uint16 vlan_tag; /* priority, cfi and vid */ - uint16 ether_type; /* ethertype */ -}; - -#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) - - -/* This marks the end of a packed structure section. */ -#include - -#define ETHERVLAN_MOVE_HDR(d, s) \ -do { \ - struct ethervlan_header t; \ - t = *(struct ethervlan_header *)(s); \ - *(struct ethervlan_header *)(d) = t; \ -} while (0) - -#endif /* _vlan_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h deleted file mode 100755 index 147016f3730f..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Fundamental types and constants relating to WPA - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wpa.h 384536 2013-02-12 04:13:09Z $ - */ - -#ifndef _proto_wpa_h_ -#define _proto_wpa_h_ - -#include -#include - - -/* This marks the start of a packed structure section. */ -#include - -/* Reason Codes */ - -/* 13 through 23 taken from IEEE Std 802.11i-2004 */ -#define DOT11_RC_INVALID_WPA_IE 13 /* Invalid info. element */ -#define DOT11_RC_MIC_FAILURE 14 /* Michael failure */ -#define DOT11_RC_4WH_TIMEOUT 15 /* 4-way handshake timeout */ -#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 /* Group key update timeout */ -#define DOT11_RC_WPA_IE_MISMATCH 17 /* WPA IE in 4-way handshake differs from - * (re-)assoc. request/probe response - */ -#define DOT11_RC_INVALID_MC_CIPHER 18 /* Invalid multicast cipher */ -#define DOT11_RC_INVALID_UC_CIPHER 19 /* Invalid unicast cipher */ -#define DOT11_RC_INVALID_AKMP 20 /* Invalid authenticated key management protocol */ -#define DOT11_RC_BAD_WPA_VERSION 21 /* Unsupported WPA version */ -#define DOT11_RC_INVALID_WPA_CAP 22 /* Invalid WPA IE capabilities */ -#define DOT11_RC_8021X_AUTH_FAIL 23 /* 802.1X authentication failure */ - -#define WPA2_PMKID_LEN 16 - -/* WPA IE fixed portion */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - uint8 tag; /* TAG */ - uint8 length; /* TAG length */ - uint8 oui[3]; /* IE OUI */ - uint8 oui_type; /* OUI type */ - BWL_PRE_PACKED_STRUCT struct { - uint8 low; - uint8 high; - } BWL_POST_PACKED_STRUCT version; /* IE version */ -} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; -#define WPA_IE_OUITYPE_LEN 4 -#define WPA_IE_FIXED_LEN 8 -#define WPA_IE_TAG_FIXED_LEN 6 - -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 tag; /* TAG */ - uint8 length; /* TAG length */ - BWL_PRE_PACKED_STRUCT struct { - uint8 low; - uint8 high; - } BWL_POST_PACKED_STRUCT version; /* IE version */ -} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; -#define WPA_RSN_IE_FIXED_LEN 4 -#define WPA_RSN_IE_TAG_FIXED_LEN 2 -typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; - -/* WPA suite/multicast suite */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - uint8 oui[3]; - uint8 type; -} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; -#define WPA_SUITE_LEN 4 - -/* WPA unicast suite list/key management suite list */ -typedef BWL_PRE_PACKED_STRUCT struct -{ - BWL_PRE_PACKED_STRUCT struct { - uint8 low; - uint8 high; - } BWL_POST_PACKED_STRUCT count; - wpa_suite_t list[1]; -} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; -#define WPA_IE_SUITE_COUNT_LEN 2 -typedef BWL_PRE_PACKED_STRUCT struct -{ - BWL_PRE_PACKED_STRUCT struct { - uint8 low; - uint8 high; - } BWL_POST_PACKED_STRUCT count; - wpa_pmkid_t list[1]; -} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; - -/* WPA cipher suites */ -#define WPA_CIPHER_NONE 0 /* None */ -#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */ -#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */ -#define WPA_CIPHER_AES_OCB 3 /* AES (OCB) */ -#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */ -#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */ -#define WPA_CIPHER_BIP 6 /* WEP (104-bit) */ -#define WPA_CIPHER_TPK 7 /* Group addressed traffic not allowed */ -#ifdef BCMCCX -#define WPA_CIPHER_CKIP 8 /* KP with no MIC */ -#define WPA_CIPHER_CKIP_MMH 9 /* KP with MIC ("CKIP/MMH", "CKIP+CMIC") */ -#define WPA_CIPHER_WEP_MMH 10 /* MIC with no KP ("WEP/MMH", "CMIC") */ - -#define IS_CCX_CIPHER(cipher) ((cipher) == WPA_CIPHER_CKIP || \ - (cipher) == WPA_CIPHER_CKIP_MMH || \ - (cipher) == WPA_CIPHER_WEP_MMH) -#endif - -#ifdef BCMWAPI_WAI -#define WAPI_CIPHER_NONE WPA_CIPHER_NONE -#define WAPI_CIPHER_SMS4 11 - -#define WAPI_CSE_WPI_SMS4 1 -#endif /* BCMWAPI_WAI */ - -#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ - (cipher) == WPA_CIPHER_WEP_40 || \ - (cipher) == WPA_CIPHER_WEP_104 || \ - (cipher) == WPA_CIPHER_TKIP || \ - (cipher) == WPA_CIPHER_AES_OCB || \ - (cipher) == WPA_CIPHER_AES_CCM || \ - (cipher) == WPA_CIPHER_TPK) - -#ifdef BCMWAPI_WAI -#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ - (cipher) == WAPI_CSE_WPI_SMS4) - -/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */ -#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ - WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) - -#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ - WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) -#endif /* BCMWAPI_WAI */ - -/* WPA TKIP countermeasures parameters */ -#define WPA_TKIP_CM_DETECT 60 /* multiple MIC failure window (seconds) */ -#define WPA_TKIP_CM_BLOCK 60 /* countermeasures active window (seconds) */ - -/* RSN IE defines */ -#define RSN_CAP_LEN 2 /* Length of RSN capabilities field (2 octets) */ - -/* RSN Capabilities defined in 802.11i */ -#define RSN_CAP_PREAUTH 0x0001 -#define RSN_CAP_NOPAIRWISE 0x0002 -#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C -#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 -#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 -#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 -#define RSN_CAP_1_REPLAY_CNTR 0 -#define RSN_CAP_2_REPLAY_CNTRS 1 -#define RSN_CAP_4_REPLAY_CNTRS 2 -#define RSN_CAP_16_REPLAY_CNTRS 3 -#define RSN_CAP_MFPR 0x0040 -#define RSN_CAP_MFPC 0x0080 -#define RSN_CAP_SPPC 0x0400 -#define RSN_CAP_SPPR 0x0800 - -/* WPA capabilities defined in 802.11i */ -#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS -#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS -#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT -#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK - -/* WPA capabilities defined in 802.11zD9.0 */ -#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) /* bit 9 */ - -/* WPA Specific defines */ -#define WPA_CAP_LEN RSN_CAP_LEN /* Length of RSN capabilities in RSN IE (2 octets) */ -#define WPA_PMKID_CNT_LEN 2 /* Length of RSN PMKID count (2 octests) */ - -#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH - -#define WPA2_PMKID_COUNT_LEN 2 - -#ifdef BCMWAPI_WAI -#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH - -/* Other WAI definition */ -#define WAPI_WAI_REQUEST 0x00F1 -#define WAPI_UNICAST_REKEY 0x00F2 -#define WAPI_STA_AGING 0x00F3 -#define WAPI_MUTIL_REKEY 0x00F4 -#define WAPI_STA_STATS 0x00F5 - -#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */ -#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */ -#endif /* BCMWAPI_WAI */ - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _proto_wpa_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h b/drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h deleted file mode 100755 index aa3d19a38236..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h +++ /dev/null @@ -1,379 +0,0 @@ -/* - * WPS IE definitions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id$ - */ - -#ifndef _WPS_ -#define _WPS_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Data Element Definitions */ -#define WPS_ID_AP_CHANNEL 0x1001 -#define WPS_ID_ASSOC_STATE 0x1002 -#define WPS_ID_AUTH_TYPE 0x1003 -#define WPS_ID_AUTH_TYPE_FLAGS 0x1004 -#define WPS_ID_AUTHENTICATOR 0x1005 -#define WPS_ID_CONFIG_METHODS 0x1008 -#define WPS_ID_CONFIG_ERROR 0x1009 -#define WPS_ID_CONF_URL4 0x100A -#define WPS_ID_CONF_URL6 0x100B -#define WPS_ID_CONN_TYPE 0x100C -#define WPS_ID_CONN_TYPE_FLAGS 0x100D -#define WPS_ID_CREDENTIAL 0x100E -#define WPS_ID_DEVICE_NAME 0x1011 -#define WPS_ID_DEVICE_PWD_ID 0x1012 -#define WPS_ID_E_HASH1 0x1014 -#define WPS_ID_E_HASH2 0x1015 -#define WPS_ID_E_SNONCE1 0x1016 -#define WPS_ID_E_SNONCE2 0x1017 -#define WPS_ID_ENCR_SETTINGS 0x1018 -#define WPS_ID_ENCR_TYPE 0x100F -#define WPS_ID_ENCR_TYPE_FLAGS 0x1010 -#define WPS_ID_ENROLLEE_NONCE 0x101A -#define WPS_ID_FEATURE_ID 0x101B -#define WPS_ID_IDENTITY 0x101C -#define WPS_ID_IDENTITY_PROOF 0x101D -#define WPS_ID_KEY_WRAP_AUTH 0x101E -#define WPS_ID_KEY_IDENTIFIER 0x101F -#define WPS_ID_MAC_ADDR 0x1020 -#define WPS_ID_MANUFACTURER 0x1021 -#define WPS_ID_MSG_TYPE 0x1022 -#define WPS_ID_MODEL_NAME 0x1023 -#define WPS_ID_MODEL_NUMBER 0x1024 -#define WPS_ID_NW_INDEX 0x1026 -#define WPS_ID_NW_KEY 0x1027 -#define WPS_ID_NW_KEY_INDEX 0x1028 -#define WPS_ID_NEW_DEVICE_NAME 0x1029 -#define WPS_ID_NEW_PWD 0x102A -#define WPS_ID_OOB_DEV_PWD 0x102C -#define WPS_ID_OS_VERSION 0x102D -#define WPS_ID_POWER_LEVEL 0x102F -#define WPS_ID_PSK_CURRENT 0x1030 -#define WPS_ID_PSK_MAX 0x1031 -#define WPS_ID_PUBLIC_KEY 0x1032 -#define WPS_ID_RADIO_ENABLED 0x1033 -#define WPS_ID_REBOOT 0x1034 -#define WPS_ID_REGISTRAR_CURRENT 0x1035 -#define WPS_ID_REGISTRAR_ESTBLSHD 0x1036 -#define WPS_ID_REGISTRAR_LIST 0x1037 -#define WPS_ID_REGISTRAR_MAX 0x1038 -#define WPS_ID_REGISTRAR_NONCE 0x1039 -#define WPS_ID_REQ_TYPE 0x103A -#define WPS_ID_RESP_TYPE 0x103B -#define WPS_ID_RF_BAND 0x103C -#define WPS_ID_R_HASH1 0x103D -#define WPS_ID_R_HASH2 0x103E -#define WPS_ID_R_SNONCE1 0x103F -#define WPS_ID_R_SNONCE2 0x1040 -#define WPS_ID_SEL_REGISTRAR 0x1041 -#define WPS_ID_SERIAL_NUM 0x1042 -#define WPS_ID_SC_STATE 0x1044 -#define WPS_ID_SSID 0x1045 -#define WPS_ID_TOT_NETWORKS 0x1046 -#define WPS_ID_UUID_E 0x1047 -#define WPS_ID_UUID_R 0x1048 -#define WPS_ID_VENDOR_EXT 0x1049 -#define WPS_ID_VERSION 0x104A -#define WPS_ID_X509_CERT_REQ 0x104B -#define WPS_ID_X509_CERT 0x104C -#define WPS_ID_EAP_IDENTITY 0x104D -#define WPS_ID_MSG_COUNTER 0x104E -#define WPS_ID_PUBKEY_HASH 0x104F -#define WPS_ID_REKEY_KEY 0x1050 -#define WPS_ID_KEY_LIFETIME 0x1051 -#define WPS_ID_PERM_CFG_METHODS 0x1052 -#define WPS_ID_SEL_REG_CFG_METHODS 0x1053 -#define WPS_ID_PRIM_DEV_TYPE 0x1054 -#define WPS_ID_SEC_DEV_TYPE_LIST 0x1055 -#define WPS_ID_PORTABLE_DEVICE 0x1056 -#define WPS_ID_AP_SETUP_LOCKED 0x1057 -#define WPS_ID_APP_LIST 0x1058 -#define WPS_ID_EAP_TYPE 0x1059 -#define WPS_ID_INIT_VECTOR 0x1060 -#define WPS_ID_KEY_PROVIDED_AUTO 0x1061 -#define WPS_ID_8021X_ENABLED 0x1062 -#define WPS_ID_WEP_TRANSMIT_KEY 0x1064 -#define WPS_ID_REQ_DEV_TYPE 0x106A - -/* WSC 2.0, WFA Vendor Extension Subelements */ -#define WFA_VENDOR_EXT_ID "\x00\x37\x2A" -#define WPS_WFA_SUBID_VERSION2 0x00 -#define WPS_WFA_SUBID_AUTHORIZED_MACS 0x01 -#define WPS_WFA_SUBID_NW_KEY_SHAREABLE 0x02 -#define WPS_WFA_SUBID_REQ_TO_ENROLL 0x03 -#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME 0x04 - - -/* WCN-NET Windows Rally Vertical Pairing Vendor Extensions */ -#define MS_VENDOR_EXT_ID "\x00\x01\x37" -#define WPS_MS_ID_VPI 0x1001 /* Vertical Pairing Identifier TLV */ -#define WPS_MS_ID_TRANSPORT_UUID 0x1002 /* Transport UUID TLV */ - -/* Vertical Pairing Identifier TLV Definitions */ -#define WPS_MS_VPI_TRANSPORT_NONE 0x00 /* None */ -#define WPS_MS_VPI_TRANSPORT_DPWS 0x01 /* Devices Profile for Web Services */ -#define WPS_MS_VPI_TRANSPORT_UPNP 0x02 /* uPnP */ -#define WPS_MS_VPI_TRANSPORT_SDNWS 0x03 /* Secure Devices Profile for Web Services */ -#define WPS_MS_VPI_NO_PROFILE_REQ 0x00 /* Wi-Fi profile not requested. - * Not supported in Windows 7 - */ -#define WPS_MS_VPI_PROFILE_REQ 0x01 /* Wi-Fi profile requested. */ - -/* sizes of the fixed size elements */ -#define WPS_ID_AP_CHANNEL_S 2 -#define WPS_ID_ASSOC_STATE_S 2 -#define WPS_ID_AUTH_TYPE_S 2 -#define WPS_ID_AUTH_TYPE_FLAGS_S 2 -#define WPS_ID_AUTHENTICATOR_S 8 -#define WPS_ID_CONFIG_METHODS_S 2 -#define WPS_ID_CONFIG_ERROR_S 2 -#define WPS_ID_CONN_TYPE_S 1 -#define WPS_ID_CONN_TYPE_FLAGS_S 1 -#define WPS_ID_DEVICE_PWD_ID_S 2 -#define WPS_ID_ENCR_TYPE_S 2 -#define WPS_ID_ENCR_TYPE_FLAGS_S 2 -#define WPS_ID_FEATURE_ID_S 4 -#define WPS_ID_MAC_ADDR_S 6 -#define WPS_ID_MSG_TYPE_S 1 -#define WPS_ID_SC_STATE_S 1 -#define WPS_ID_RF_BAND_S 1 -#define WPS_ID_OS_VERSION_S 4 -#define WPS_ID_VERSION_S 1 -#define WPS_ID_SEL_REGISTRAR_S 1 -#define WPS_ID_SEL_REG_CFG_METHODS_S 2 -#define WPS_ID_REQ_TYPE_S 1 -#define WPS_ID_RESP_TYPE_S 1 -#define WPS_ID_AP_SETUP_LOCKED_S 1 - -/* WSC 2.0, WFA Vendor Extension Subelements */ -#define WPS_WFA_SUBID_VERSION2_S 1 -#define WPS_WFA_SUBID_NW_KEY_SHAREABLE_S 1 -#define WPS_WFA_SUBID_REQ_TO_ENROLL_S 1 -#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME_S 1 - -/* Association states */ -#define WPS_ASSOC_NOT_ASSOCIATED 0 -#define WPS_ASSOC_CONN_SUCCESS 1 -#define WPS_ASSOC_CONFIG_FAIL 2 -#define WPS_ASSOC_ASSOC_FAIL 3 -#define WPS_ASSOC_IP_FAIL 4 - -/* Authentication types */ -#define WPS_AUTHTYPE_OPEN 0x0001 -#define WPS_AUTHTYPE_WPAPSK 0x0002 /* Deprecated in WSC 2.0 */ -#define WPS_AUTHTYPE_SHARED 0x0004 /* Deprecated in WSC 2.0 */ -#define WPS_AUTHTYPE_WPA 0x0008 /* Deprecated in WSC 2.0 */ -#define WPS_AUTHTYPE_WPA2 0x0010 -#define WPS_AUTHTYPE_WPA2PSK 0x0020 - -/* Config methods */ -#define WPS_CONFMET_USBA 0x0001 /* Deprecated in WSC 2.0 */ -#define WPS_CONFMET_ETHERNET 0x0002 /* Deprecated in WSC 2.0 */ -#define WPS_CONFMET_LABEL 0x0004 -#define WPS_CONFMET_DISPLAY 0x0008 -#define WPS_CONFMET_EXT_NFC_TOK 0x0010 -#define WPS_CONFMET_INT_NFC_TOK 0x0020 -#define WPS_CONFMET_NFC_INTF 0x0040 -#define WPS_CONFMET_PBC 0x0080 -#define WPS_CONFMET_KEYPAD 0x0100 -/* WSC 2.0 */ -#define WPS_CONFMET_VIRT_PBC 0x0280 -#define WPS_CONFMET_PHY_PBC 0x0480 -#define WPS_CONFMET_VIRT_DISPLAY 0x2008 -#define WPS_CONFMET_PHY_DISPLAY 0x4008 - -/* WPS error messages */ -#define WPS_ERROR_NO_ERROR 0 -#define WPS_ERROR_OOB_INT_READ_ERR 1 -#define WPS_ERROR_DECRYPT_CRC_FAIL 2 -#define WPS_ERROR_CHAN24_NOT_SUPP 3 -#define WPS_ERROR_CHAN50_NOT_SUPP 4 -#define WPS_ERROR_SIGNAL_WEAK 5 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_NW_AUTH_FAIL 6 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_NW_ASSOC_FAIL 7 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_NO_DHCP_RESP 8 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_FAILED_DHCP_CONF 9 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_IP_ADDR_CONFLICT 10 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_FAIL_CONN_REGISTRAR 11 -#define WPS_ERROR_MULTI_PBC_DETECTED 12 -#define WPS_ERROR_ROGUE_SUSPECTED 13 -#define WPS_ERROR_DEVICE_BUSY 14 -#define WPS_ERROR_SETUP_LOCKED 15 -#define WPS_ERROR_MSG_TIMEOUT 16 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_REG_SESSION_TIMEOUT 17 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_DEV_PWD_AUTH_FAIL 18 - -/* Connection types */ -#define WPS_CONNTYPE_ESS 0x01 -#define WPS_CONNTYPE_IBSS 0x02 - -/* Device password ID */ -#define WPS_DEVICEPWDID_DEFAULT 0x0000 -#define WPS_DEVICEPWDID_USER_SPEC 0x0001 -#define WPS_DEVICEPWDID_MACHINE_SPEC 0x0002 -#define WPS_DEVICEPWDID_REKEY 0x0003 -#define WPS_DEVICEPWDID_PUSH_BTN 0x0004 -#define WPS_DEVICEPWDID_REG_SPEC 0x0005 - -/* Encryption type */ -#define WPS_ENCRTYPE_NONE 0x0001 -#define WPS_ENCRTYPE_WEP 0x0002 /* Deprecated in WSC 2.0 */ -#define WPS_ENCRTYPE_TKIP 0x0004 /* Deprecated in version 2.0. TKIP can only - * be advertised on the AP when Mixed Mode - * is enabled (Encryption Type is 0x000c). - */ -#define WPS_ENCRTYPE_AES 0x0008 - - -/* WPS Message Types */ -#define WPS_ID_BEACON 0x01 -#define WPS_ID_PROBE_REQ 0x02 -#define WPS_ID_PROBE_RESP 0x03 -#define WPS_ID_MESSAGE_M1 0x04 -#define WPS_ID_MESSAGE_M2 0x05 -#define WPS_ID_MESSAGE_M2D 0x06 -#define WPS_ID_MESSAGE_M3 0x07 -#define WPS_ID_MESSAGE_M4 0x08 -#define WPS_ID_MESSAGE_M5 0x09 -#define WPS_ID_MESSAGE_M6 0x0A -#define WPS_ID_MESSAGE_M7 0x0B -#define WPS_ID_MESSAGE_M8 0x0C -#define WPS_ID_MESSAGE_ACK 0x0D -#define WPS_ID_MESSAGE_NACK 0x0E -#define WPS_ID_MESSAGE_DONE 0x0F - -/* WSP private ID for local use */ -#define WPS_PRIVATE_ID_IDENTITY (WPS_ID_MESSAGE_DONE + 1) -#define WPS_PRIVATE_ID_WPS_START (WPS_ID_MESSAGE_DONE + 2) -#define WPS_PRIVATE_ID_FAILURE (WPS_ID_MESSAGE_DONE + 3) -#define WPS_PRIVATE_ID_FRAG (WPS_ID_MESSAGE_DONE + 4) -#define WPS_PRIVATE_ID_FRAG_ACK (WPS_ID_MESSAGE_DONE + 5) -#define WPS_PRIVATE_ID_EAPOL_START (WPS_ID_MESSAGE_DONE + 6) - - -/* Device Type categories for primary and secondary device types */ -#define WPS_DEVICE_TYPE_CAT_COMPUTER 1 -#define WPS_DEVICE_TYPE_CAT_INPUT_DEVICE 2 -#define WPS_DEVICE_TYPE_CAT_PRINTER 3 -#define WPS_DEVICE_TYPE_CAT_CAMERA 4 -#define WPS_DEVICE_TYPE_CAT_STORAGE 5 -#define WPS_DEVICE_TYPE_CAT_NW_INFRA 6 -#define WPS_DEVICE_TYPE_CAT_DISPLAYS 7 -#define WPS_DEVICE_TYPE_CAT_MM_DEVICES 8 -#define WPS_DEVICE_TYPE_CAT_GAME_DEVICES 9 -#define WPS_DEVICE_TYPE_CAT_TELEPHONE 10 -#define WPS_DEVICE_TYPE_CAT_AUDIO_DEVICES 11 /* WSC 2.0 */ - -/* Device Type sub categories for primary and secondary device types */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_PC 1 -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_SERVER 2 -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MEDIA_CTR 3 -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_UM_PC 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NOTEBOOK 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_DESKTOP 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MID 7 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NETBOOK 8 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_Keyboard 1 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_MOUSE 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_JOYSTICK 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_TRACKBALL 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_GAM_CTRL 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_REMOTE 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_TOUCHSCREEN 7 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_BIO_READER 8 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_BAR_READER 9 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_PRINTER 1 -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_SCANNER 2 -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_FAX 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_COPIER 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_ALLINONE 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_DGTL_STILL 1 -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_VIDEO_CAM 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_WEB_CAM 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_SECU_CAM 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_STOR_NAS 1 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_AP 1 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_ROUTER 2 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_SWITCH 3 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_GATEWAY 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_NW_BRIDGE 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_TV 1 -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PIC_FRAME 2 -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PROJECTOR 3 -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_MONITOR 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_MM_DAR 1 -#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVR 2 -#define WPS_DEVICE_TYPE_SUB_CAT_MM_MCX 3 -#define WPS_DEVICE_TYPE_SUB_CAT_MM_STB 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_MM_MS_ME 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVP 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX 1 -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX_360 2 -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PS 3 -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_GC 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PGD 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_WM 1 -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PSM 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PDM 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SSM 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SDM 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_TUNER 1 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_SPEAKERS 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_PMP 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HEADSET 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HPHONE 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_MPHONE 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HTS 7 /* WSC 2.0 */ - - -/* Device request/response type */ -#define WPS_MSGTYPE_ENROLLEE_INFO_ONLY 0x00 -#define WPS_MSGTYPE_ENROLLEE_OPEN_8021X 0x01 -#define WPS_MSGTYPE_REGISTRAR 0x02 -#define WPS_MSGTYPE_AP_WLAN_MGR 0x03 - -/* RF Band */ -#define WPS_RFBAND_24GHZ 0x01 -#define WPS_RFBAND_50GHZ 0x02 - -/* Simple Config state */ -#define WPS_SCSTATE_UNCONFIGURED 0x01 -#define WPS_SCSTATE_CONFIGURED 0x02 -#define WPS_SCSTATE_OFF 11 - -/* WPS Vendor extension key */ -#define WPS_OUI_HEADER_LEN 2 -#define WPS_OUI_HEADER_SIZE 4 -#define WPS_OUI_FIXED_HEADER_OFF 16 -#define WPS_WFA_SUBID_V2_OFF 3 -#define WPS_WFA_V2_OFF 5 - -#ifdef __cplusplus -} -#endif - -#endif /* _WPS_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h deleted file mode 100755 index 51a07435bd51..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h +++ /dev/null @@ -1,3304 +0,0 @@ -/* - * SiliconBackplane Chipcommon core hardware definitions. - * - * The chipcommon core provides chip identification, SB control, - * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, - * GPIO interface, extbus, and support for serial and parallel flashes. - * - * $Id: sbchipc.h 527121 2015-01-16 03:22:32Z $ - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - */ - -#ifndef _SBCHIPC_H -#define _SBCHIPC_H - -#ifndef _LANGUAGE_ASSEMBLY - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - -typedef struct eci_prerev35 { - uint32 eci_output; - uint32 eci_control; - uint32 eci_inputlo; - uint32 eci_inputmi; - uint32 eci_inputhi; - uint32 eci_inputintpolaritylo; - uint32 eci_inputintpolaritymi; - uint32 eci_inputintpolarityhi; - uint32 eci_intmasklo; - uint32 eci_intmaskmi; - uint32 eci_intmaskhi; - uint32 eci_eventlo; - uint32 eci_eventmi; - uint32 eci_eventhi; - uint32 eci_eventmasklo; - uint32 eci_eventmaskmi; - uint32 eci_eventmaskhi; - uint32 PAD[3]; -} eci_prerev35_t; - -typedef struct eci_rev35 { - uint32 eci_outputlo; - uint32 eci_outputhi; - uint32 eci_controllo; - uint32 eci_controlhi; - uint32 eci_inputlo; - uint32 eci_inputhi; - uint32 eci_inputintpolaritylo; - uint32 eci_inputintpolarityhi; - uint32 eci_intmasklo; - uint32 eci_intmaskhi; - uint32 eci_eventlo; - uint32 eci_eventhi; - uint32 eci_eventmasklo; - uint32 eci_eventmaskhi; - uint32 eci_auxtx; - uint32 eci_auxrx; - uint32 eci_datatag; - uint32 eci_uartescvalue; - uint32 eci_autobaudctr; - uint32 eci_uartfifolevel; -} eci_rev35_t; - -typedef struct flash_config { - uint32 PAD[19]; - /* Flash struct configuration registers (0x18c) for BCM4706 (corerev = 31) */ - uint32 flashstrconfig; -} flash_config_t; - -typedef volatile struct { - uint32 chipid; /* 0x0 */ - uint32 capabilities; - uint32 corecontrol; /* corerev >= 1 */ - uint32 bist; - - /* OTP */ - uint32 otpstatus; /* 0x10, corerev >= 10 */ - uint32 otpcontrol; - uint32 otpprog; - uint32 otplayout; /* corerev >= 23 */ - - /* Interrupt control */ - uint32 intstatus; /* 0x20 */ - uint32 intmask; - - /* Chip specific regs */ - uint32 chipcontrol; /* 0x28, rev >= 11 */ - uint32 chipstatus; /* 0x2c, rev >= 11 */ - - /* Jtag Master */ - uint32 jtagcmd; /* 0x30, rev >= 10 */ - uint32 jtagir; - uint32 jtagdr; - uint32 jtagctrl; - - /* serial flash interface registers */ - uint32 flashcontrol; /* 0x40 */ - uint32 flashaddress; - uint32 flashdata; - uint32 otplayoutextension; /* rev >= 35 */ - - /* Silicon backplane configuration broadcast control */ - uint32 broadcastaddress; /* 0x50 */ - uint32 broadcastdata; - - /* gpio - cleared only by power-on-reset */ - uint32 gpiopullup; /* 0x58, corerev >= 20 */ - uint32 gpiopulldown; /* 0x5c, corerev >= 20 */ - uint32 gpioin; /* 0x60 */ - uint32 gpioout; /* 0x64 */ - uint32 gpioouten; /* 0x68 */ - uint32 gpiocontrol; /* 0x6C */ - uint32 gpiointpolarity; /* 0x70 */ - uint32 gpiointmask; /* 0x74 */ - - /* GPIO events corerev >= 11 */ - uint32 gpioevent; - uint32 gpioeventintmask; - - /* Watchdog timer */ - uint32 watchdog; /* 0x80 */ - - /* GPIO events corerev >= 11 */ - uint32 gpioeventintpolarity; - - /* GPIO based LED powersave registers corerev >= 16 */ - uint32 gpiotimerval; /* 0x88 */ - uint32 gpiotimeroutmask; - - /* clock control */ - uint32 clockcontrol_n; /* 0x90 */ - uint32 clockcontrol_sb; /* aka m0 */ - uint32 clockcontrol_pci; /* aka m1 */ - uint32 clockcontrol_m2; /* mii/uart/mipsref */ - uint32 clockcontrol_m3; /* cpu */ - uint32 clkdiv; /* corerev >= 3 */ - uint32 gpiodebugsel; /* corerev >= 28 */ - uint32 capabilities_ext; /* 0xac */ - - /* pll delay registers (corerev >= 4) */ - uint32 pll_on_delay; /* 0xb0 */ - uint32 fref_sel_delay; - uint32 slow_clk_ctl; /* 5 < corerev < 10 */ - uint32 PAD; - - /* Instaclock registers (corerev >= 10) */ - uint32 system_clk_ctl; /* 0xc0 */ - uint32 clkstatestretch; - uint32 PAD[2]; - - /* Indirect backplane access (corerev >= 22) */ - uint32 bp_addrlow; /* 0xd0 */ - uint32 bp_addrhigh; - uint32 bp_data; - uint32 PAD; - uint32 bp_indaccess; - /* SPI registers, corerev >= 37 */ - uint32 gsioctrl; - uint32 gsioaddress; - uint32 gsiodata; - - /* More clock dividers (corerev >= 32) */ - uint32 clkdiv2; - /* FAB ID (corerev >= 40) */ - uint32 otpcontrol1; - uint32 fabid; /* 0xf8 */ - - /* In AI chips, pointer to erom */ - uint32 eromptr; /* 0xfc */ - - /* ExtBus control registers (corerev >= 3) */ - uint32 pcmcia_config; /* 0x100 */ - uint32 pcmcia_memwait; - uint32 pcmcia_attrwait; - uint32 pcmcia_iowait; - uint32 ide_config; - uint32 ide_memwait; - uint32 ide_attrwait; - uint32 ide_iowait; - uint32 prog_config; - uint32 prog_waitcount; - uint32 flash_config; - uint32 flash_waitcount; - uint32 SECI_config; /* 0x130 SECI configuration */ - uint32 SECI_status; - uint32 SECI_statusmask; - uint32 SECI_rxnibchanged; - - uint32 PAD[20]; - - /* SROM interface (corerev >= 32) */ - uint32 sromcontrol; /* 0x190 */ - uint32 sromaddress; - uint32 sromdata; - uint32 PAD[1]; /* 0x19C */ - /* NAND flash registers for BCM4706 (corerev = 31) */ - uint32 nflashctrl; /* 0x1a0 */ - uint32 nflashconf; - uint32 nflashcoladdr; - uint32 nflashrowaddr; - uint32 nflashdata; - uint32 nflashwaitcnt0; /* 0x1b4 */ - uint32 PAD[2]; - - uint32 seci_uart_data; /* 0x1C0 */ - uint32 seci_uart_bauddiv; - uint32 seci_uart_fcr; - uint32 seci_uart_lcr; - uint32 seci_uart_mcr; - uint32 seci_uart_lsr; - uint32 seci_uart_msr; - uint32 seci_uart_baudadj; - /* Clock control and hardware workarounds (corerev >= 20) */ - uint32 clk_ctl_st; /* 0x1e0 */ - uint32 hw_war; - uint32 PAD[70]; - - /* UARTs */ - uint8 uart0data; /* 0x300 */ - uint8 uart0imr; - uint8 uart0fcr; - uint8 uart0lcr; - uint8 uart0mcr; - uint8 uart0lsr; - uint8 uart0msr; - uint8 uart0scratch; - uint8 PAD[248]; /* corerev >= 1 */ - - uint8 uart1data; /* 0x400 */ - uint8 uart1imr; - uint8 uart1fcr; - uint8 uart1lcr; - uint8 uart1mcr; - uint8 uart1lsr; - uint8 uart1msr; - uint8 uart1scratch; /* 0x407 */ - uint32 PAD[62]; - - /* save/restore, corerev >= 48 */ - uint32 sr_capability; /* 0x500 */ - uint32 sr_control0; /* 0x504 */ - uint32 sr_control1; /* 0x508 */ - uint32 gpio_control; /* 0x50C */ - uint32 PAD[60]; - - /* PMU registers (corerev >= 20) */ - /* Note: all timers driven by ILP clock are updated asynchronously to HT/ALP. - * The CPU must read them twice, compare, and retry if different. - */ - uint32 pmucontrol; /* 0x600 */ - uint32 pmucapabilities; - uint32 pmustatus; - uint32 res_state; - uint32 res_pending; - uint32 pmutimer; - uint32 min_res_mask; - uint32 max_res_mask; - uint32 res_table_sel; - uint32 res_dep_mask; - uint32 res_updn_timer; - uint32 res_timer; - uint32 clkstretch; - uint32 pmuwatchdog; - uint32 gpiosel; /* 0x638, rev >= 1 */ - uint32 gpioenable; /* 0x63c, rev >= 1 */ - uint32 res_req_timer_sel; - uint32 res_req_timer; - uint32 res_req_mask; - uint32 PAD; - uint32 chipcontrol_addr; /* 0x650 */ - uint32 chipcontrol_data; /* 0x654 */ - uint32 regcontrol_addr; - uint32 regcontrol_data; - uint32 pllcontrol_addr; - uint32 pllcontrol_data; - uint32 pmustrapopt; /* 0x668, corerev >= 28 */ - uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ - uint32 retention_ctl; /* 0x670 */ - uint32 PAD[3]; - uint32 retention_grpidx; /* 0x680 */ - uint32 retention_grpctl; /* 0x684 */ - uint32 PAD[94]; - uint16 sromotp[512]; /* 0x800 */ -#ifdef NFLASH_SUPPORT - /* Nand flash MLC controller registers (corerev >= 38) */ - uint32 nand_revision; /* 0xC00 */ - uint32 nand_cmd_start; - uint32 nand_cmd_addr_x; - uint32 nand_cmd_addr; - uint32 nand_cmd_end_addr; - uint32 nand_cs_nand_select; - uint32 nand_cs_nand_xor; - uint32 PAD; - uint32 nand_spare_rd0; - uint32 nand_spare_rd4; - uint32 nand_spare_rd8; - uint32 nand_spare_rd12; - uint32 nand_spare_wr0; - uint32 nand_spare_wr4; - uint32 nand_spare_wr8; - uint32 nand_spare_wr12; - uint32 nand_acc_control; - uint32 PAD; - uint32 nand_config; - uint32 PAD; - uint32 nand_timing_1; - uint32 nand_timing_2; - uint32 nand_semaphore; - uint32 PAD; - uint32 nand_devid; - uint32 nand_devid_x; - uint32 nand_block_lock_status; - uint32 nand_intfc_status; - uint32 nand_ecc_corr_addr_x; - uint32 nand_ecc_corr_addr; - uint32 nand_ecc_unc_addr_x; - uint32 nand_ecc_unc_addr; - uint32 nand_read_error_count; - uint32 nand_corr_stat_threshold; - uint32 PAD[2]; - uint32 nand_read_addr_x; - uint32 nand_read_addr; - uint32 nand_page_program_addr_x; - uint32 nand_page_program_addr; - uint32 nand_copy_back_addr_x; - uint32 nand_copy_back_addr; - uint32 nand_block_erase_addr_x; - uint32 nand_block_erase_addr; - uint32 nand_inv_read_addr_x; - uint32 nand_inv_read_addr; - uint32 PAD[2]; - uint32 nand_blk_wr_protect; - uint32 PAD[3]; - uint32 nand_acc_control_cs1; - uint32 nand_config_cs1; - uint32 nand_timing_1_cs1; - uint32 nand_timing_2_cs1; - uint32 PAD[20]; - uint32 nand_spare_rd16; - uint32 nand_spare_rd20; - uint32 nand_spare_rd24; - uint32 nand_spare_rd28; - uint32 nand_cache_addr; - uint32 nand_cache_data; - uint32 nand_ctrl_config; - uint32 nand_ctrl_status; -#endif /* NFLASH_SUPPORT */ - uint32 gci_corecaps0; /* GCI starting at 0xC00 */ - uint32 gci_corecaps1; - uint32 gci_corecaps2; - uint32 gci_corectrl; - uint32 gci_corestat; /* 0xC10 */ - uint32 gci_intstat; /* 0xC14 */ - uint32 gci_intmask; /* 0xC18 */ - uint32 gci_wakemask; /* 0xC1C */ - uint32 gci_levelintstat; /* 0xC20 */ - uint32 gci_eventintstat; /* 0xC24 */ - uint32 PAD[6]; - uint32 gci_indirect_addr; /* 0xC40 */ - uint32 gci_gpioctl; /* 0xC44 */ - uint32 gci_gpiostatus; - uint32 gci_gpiomask; /* 0xC4C */ - uint32 PAD; - uint32 gci_miscctl; /* 0xC54 */ - uint32 gci_gpiointmask; - uint32 gci_gpiowakemask; - uint32 gci_input[32]; /* C60 */ - uint32 gci_event[32]; /* CE0 */ - uint32 gci_output[4]; /* D60 */ - uint32 gci_control_0; /* 0xD70 */ - uint32 gci_control_1; /* 0xD74 */ - uint32 gci_level_polreg; /* 0xD78 */ - uint32 gci_levelintmask; /* 0xD7C */ - uint32 gci_eventintmask; /* 0xD80 */ - uint32 PAD[3]; - uint32 gci_inbandlevelintmask; /* 0xD90 */ - uint32 gci_inbandeventintmask; /* 0xD94 */ - uint32 PAD[2]; - uint32 gci_seciauxtx; /* 0xDA0 */ - uint32 gci_seciauxrx; /* 0xDA4 */ - uint32 gci_secitx_datatag; /* 0xDA8 */ - uint32 gci_secirx_datatag; /* 0xDAC */ - uint32 gci_secitx_datamask; /* 0xDB0 */ - uint32 gci_seciusef0tx_reg; /* 0xDB4 */ - uint32 gci_secif0tx_offset; /* 0xDB8 */ - uint32 gci_secif0rx_offset; /* 0xDBC */ - uint32 gci_secif1tx_offset; /* 0xDC0 */ - uint32 PAD[3]; - uint32 gci_uartescval; /* DD0 */ - uint32 PAD[3]; - uint32 gci_secibauddiv; /* DE0 */ - uint32 gci_secifcr; /* DE4 */ - uint32 gci_secilcr; /* DE8 */ - uint32 gci_secimcr; /* DEC */ - uint32 PAD[2]; - uint32 gci_baudadj; /* DF8 */ - uint32 PAD; - uint32 gci_chipctrl; /* 0xE00 */ - uint32 gci_chipsts; /* 0xE04 */ -} chipcregs_t; - -#endif /* _LANGUAGE_ASSEMBLY */ - - -#define CC_CHIPID 0 -#define CC_CAPABILITIES 4 -#define CC_CHIPST 0x2c -#define CC_EROMPTR 0xfc - -#define CC_OTPST 0x10 -#define CC_JTAGCMD 0x30 -#define CC_JTAGIR 0x34 -#define CC_JTAGDR 0x38 -#define CC_JTAGCTRL 0x3c -#define CC_GPIOPU 0x58 -#define CC_GPIOPD 0x5c -#define CC_GPIOIN 0x60 -#define CC_GPIOOUT 0x64 -#define CC_GPIOOUTEN 0x68 -#define CC_GPIOCTRL 0x6c -#define CC_GPIOPOL 0x70 -#define CC_GPIOINTM 0x74 -#define CC_WATCHDOG 0x80 -#define CC_CLKC_N 0x90 -#define CC_CLKC_M0 0x94 -#define CC_CLKC_M1 0x98 -#define CC_CLKC_M2 0x9c -#define CC_CLKC_M3 0xa0 -#define CC_CLKDIV 0xa4 -#define CC_SYS_CLK_CTL 0xc0 -#define CC_CLK_CTL_ST SI_CLK_CTL_ST -#define PMU_CTL 0x600 -#define PMU_CAP 0x604 -#define PMU_ST 0x608 -#define PMU_RES_STATE 0x60c -#define PMU_TIMER 0x614 -#define PMU_MIN_RES_MASK 0x618 -#define PMU_MAX_RES_MASK 0x61c -#define CC_CHIPCTL_ADDR 0x650 -#define CC_CHIPCTL_DATA 0x654 -#define PMU_REG_CONTROL_ADDR 0x658 -#define PMU_REG_CONTROL_DATA 0x65C -#define PMU_PLL_CONTROL_ADDR 0x660 -#define PMU_PLL_CONTROL_DATA 0x664 -#define CC_SROM_CTRL 0x190 -#define CC_SROM_OTP 0x800 /* SROM/OTP address space */ -#define CC_GCI_INDIRECT_ADDR_REG 0xC40 -#define CC_GCI_CHIP_CTRL_REG 0xE00 -#define CC_GCI_CC_OFFSET_2 2 -#define CC_GCI_CC_OFFSET_5 5 - -#define CHIPCTRLREG0 0x0 -#define CHIPCTRLREG1 0x1 -#define CHIPCTRLREG2 0x2 -#define CHIPCTRLREG3 0x3 -#define CHIPCTRLREG4 0x4 -#define CHIPCTRLREG5 0x5 -#define CHIPCTRLREG6 0x6 -#define REGCTRLREG4 0x4 -#define REGCTRLREG5 0x5 -#define REGCTRLREG6 0x6 -#define PMU_RES_STATE 0x60c -#define PMU_RES_PENDING 0x610 -#define PMU_TIMER 0x614 -#define MINRESMASKREG 0x618 -#define MAXRESMASKREG 0x61c -#define CHIPCTRLADDR 0x650 -#define CHIPCTRLDATA 0x654 -#define RSRCTABLEADDR 0x620 -#define PMU_RES_DEP_MASK 0x624 -#define RSRCUPDWNTIME 0x628 -#define PMUREG_RESREQ_MASK 0x68c -#define EXT_LPO_AVAIL 0x100 -#define LPO_SEL (1 << 0) -#define CC_EXT_LPO_PU 0x200000 -#define GC_EXT_LPO_PU 0x2 -#define CC_INT_LPO_PU 0x100000 -#define GC_INT_LPO_PU 0x1 -#define EXT_LPO_SEL 0x8 -#define INT_LPO_SEL 0x4 -#define ENABLE_FINE_CBUCK_CTRL (1 << 30) -#define REGCTRL5_PWM_AUTO_CTRL_MASK 0x007e0000 -#define REGCTRL5_PWM_AUTO_CTRL_SHIFT 17 -#define REGCTRL6_PWM_AUTO_CTRL_MASK 0x3fff0000 -#define REGCTRL6_PWM_AUTO_CTRL_SHIFT 16 - -#ifdef NFLASH_SUPPORT -/* NAND flash support */ -#define CC_NAND_REVISION 0xC00 -#define CC_NAND_CMD_START 0xC04 -#define CC_NAND_CMD_ADDR 0xC0C -#define CC_NAND_SPARE_RD_0 0xC20 -#define CC_NAND_SPARE_RD_4 0xC24 -#define CC_NAND_SPARE_RD_8 0xC28 -#define CC_NAND_SPARE_RD_C 0xC2C -#define CC_NAND_CONFIG 0xC48 -#define CC_NAND_DEVID 0xC60 -#define CC_NAND_DEVID_EXT 0xC64 -#define CC_NAND_INTFC_STATUS 0xC6C -#endif /* NFLASH_SUPPORT */ - -/* 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 */ -#define CC_CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */ -#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_ECI 0x20000000 /* ECI Present, rev >= 21 */ -#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */ -#define CC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */ - -#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ -#define CC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */ - -/* capabilities extension */ -#define CC_CAP_EXT_SECI_PRESENT 0x00000001 /* SECI present */ -#define CC_CAP_EXT_GCI_PRESENT 0x00000004 /* GCI present */ - -/* WL Channel Info to BT via GCI - bits 40 - 47 */ -#define GCI_WL_CHN_INFO_MASK (0xFF00) -/* PLL type */ -#define PLL_NONE 0x00000000 -#define PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */ -#define PLL_TYPE2 0x00020000 /* 48MHz, 4 dividers */ -#define PLL_TYPE3 0x00030000 /* 25MHz, 2 dividers */ -#define PLL_TYPE4 0x00008000 /* 48MHz, 4 dividers */ -#define PLL_TYPE5 0x00018000 /* 25MHz, 4 dividers */ -#define PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */ -#define PLL_TYPE7 0x00038000 /* 25MHz, 4 dividers */ - -/* ILP clock */ -#define ILP_CLOCK 32000 - -/* ALP clock on pre-PMU chips */ -#define ALP_CLOCK 20000000 - -#ifdef CFG_SIM -#define NS_ALP_CLOCK 84922 -#define NS_SLOW_ALP_CLOCK 84922 -#define NS_CPU_CLOCK 534500 -#define NS_SLOW_CPU_CLOCK 534500 -#define NS_SI_CLOCK 271750 -#define NS_SLOW_SI_CLOCK 271750 -#define NS_FAST_MEM_CLOCK 271750 -#define NS_MEM_CLOCK 271750 -#define NS_SLOW_MEM_CLOCK 271750 -#else -#define NS_ALP_CLOCK 125000000 -#define NS_SLOW_ALP_CLOCK 100000000 -#define NS_CPU_CLOCK 1000000000 -#define NS_SLOW_CPU_CLOCK 800000000 -#define NS_SI_CLOCK 250000000 -#define NS_SLOW_SI_CLOCK 200000000 -#define NS_FAST_MEM_CLOCK 800000000 -#define NS_MEM_CLOCK 533000000 -#define NS_SLOW_MEM_CLOCK 400000000 -#endif /* CFG_SIM */ - -/* HT clock */ -#define HT_CLOCK 80000000 - -/* corecontrol */ -#define CC_UARTCLKO 0x00000001 /* Drive UART with internal clock */ -#define CC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ -#define CC_ASYNCGPIO 0x00000004 /* 1=generate GPIO interrupt without backplane clock */ -#define CC_UARTCLKEN 0x00000008 /* enable UART Clock (corerev > = 21 */ - -/* 4321 chipcontrol */ -#define CHIPCTRL_4321A0_DEFAULT 0x3a4 -#define CHIPCTRL_4321A1_DEFAULT 0x0a4 -#define CHIPCTRL_4321_PLL_DOWN 0x800000 /* serdes PLL down override */ - -/* Fields in the otpstatus register in rev >= 21 */ -#define OTPS_OL_MASK 0x000000ff -#define OTPS_OL_MFG 0x00000001 /* manuf row is locked */ -#define OTPS_OL_OR1 0x00000002 /* otp redundancy row 1 is locked */ -#define OTPS_OL_OR2 0x00000004 /* otp redundancy row 2 is locked */ -#define OTPS_OL_GU 0x00000008 /* general use region is locked */ -#define OTPS_GUP_MASK 0x00000f00 -#define OTPS_GUP_SHIFT 8 -#define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */ -#define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */ -#define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */ -#define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */ -#define OTPS_READY 0x00001000 -#define OTPS_RV(x) (1 << (16 + (x))) /* redundancy entry valid */ -#define OTPS_RV_MASK 0x0fff0000 -#define OTPS_PROGOK 0x40000000 - -/* Fields in the otpcontrol register in rev >= 21 */ -#define OTPC_PROGSEL 0x00000001 -#define OTPC_PCOUNT_MASK 0x0000000e -#define OTPC_PCOUNT_SHIFT 1 -#define OTPC_VSEL_MASK 0x000000f0 -#define OTPC_VSEL_SHIFT 4 -#define OTPC_TMM_MASK 0x00000700 -#define OTPC_TMM_SHIFT 8 -#define OTPC_ODM 0x00000800 -#define OTPC_PROGEN 0x80000000 - -/* Fields in the 40nm otpcontrol register in rev >= 40 */ -#define OTPC_40NM_PROGSEL_SHIFT 0 -#define OTPC_40NM_PCOUNT_SHIFT 1 -#define OTPC_40NM_PCOUNT_WR 0xA -#define OTPC_40NM_PCOUNT_V1X 0xB -#define OTPC_40NM_REGCSEL_SHIFT 5 -#define OTPC_40NM_REGCSEL_DEF 0x4 -#define OTPC_40NM_PROGIN_SHIFT 8 -#define OTPC_40NM_R2X_SHIFT 10 -#define OTPC_40NM_ODM_SHIFT 11 -#define OTPC_40NM_DF_SHIFT 15 -#define OTPC_40NM_VSEL_SHIFT 16 -#define OTPC_40NM_VSEL_WR 0xA -#define OTPC_40NM_VSEL_V1X 0xA -#define OTPC_40NM_VSEL_R1X 0x5 -#define OTPC_40NM_COFAIL_SHIFT 30 - -#define OTPC1_CPCSEL_SHIFT 0 -#define OTPC1_CPCSEL_DEF 6 -#define OTPC1_TM_SHIFT 8 -#define OTPC1_TM_WR 0x84 -#define OTPC1_TM_V1X 0x84 -#define OTPC1_TM_R1X 0x4 - -/* Fields in otpprog in rev >= 21 and HND OTP */ -#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 /* HND OTP */ - -/* Fields in otplayout register */ -#define OTPL_HWRGN_OFF_MASK 0x00000FFF -#define OTPL_HWRGN_OFF_SHIFT 0 -#define OTPL_WRAP_REVID_MASK 0x00F80000 -#define OTPL_WRAP_REVID_SHIFT 19 -#define OTPL_WRAP_TYPE_MASK 0x00070000 -#define OTPL_WRAP_TYPE_SHIFT 16 -#define OTPL_WRAP_TYPE_65NM 0 -#define OTPL_WRAP_TYPE_40NM 1 -#define OTPL_ROW_SIZE_MASK 0x0000F000 -#define OTPL_ROW_SIZE_SHIFT 12 - -/* otplayout reg corerev >= 36 */ -#define OTP_CISFORMAT_NEW 0x80000000 - -/* 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 - -/* Opcodes for OTPP_OC field (40NM) */ -#define OTPPOC_READ_40NM 0 -#define OTPPOC_PROG_ENABLE_40NM 1 -#define OTPPOC_PROG_DISABLE_40NM 2 -#define OTPPOC_VERIFY_40NM 3 -#define OTPPOC_WORD_VERIFY_1_40NM 4 -#define OTPPOC_ROW_LOCK_40NM 5 -#define OTPPOC_STBY_40NM 6 -#define OTPPOC_WAKEUP_40NM 7 -#define OTPPOC_WORD_VERIFY_0_40NM 8 -#define OTPPOC_PRESCN_TEST_40NM 9 -#define OTPPOC_BIT_PROG_40NM 10 -#define OTPPOC_WORDPROG_40NM 11 -#define OTPPOC_BURNIN_40NM 12 -#define OTPPOC_AUTORELOAD_40NM 13 -#define OTPPOC_OVST_READ_40NM 14 -#define OTPPOC_OVST_PROG_40NM 15 - -/* Fields in otplayoutextension */ -#define OTPLAYOUTEXT_FUSE_MASK 0x3FF - - -/* Jtagm characteristics that appeared at a given corerev */ -#define JTAGM_CREV_OLD 10 /* Old command set, 16bit max IR */ -#define JTAGM_CREV_IRP 22 /* Able to do pause-ir */ -#define JTAGM_CREV_RTI 28 /* Able to do return-to-idle */ - -/* jtagcmd */ -#define JCMD_START 0x80000000 -#define JCMD_BUSY 0x80000000 -#define JCMD_STATE_MASK 0x60000000 -#define JCMD_STATE_TLR 0x00000000 /* Test-logic-reset */ -#define JCMD_STATE_PIR 0x20000000 /* Pause IR */ -#define JCMD_STATE_PDR 0x40000000 /* Pause DR */ -#define JCMD_STATE_RTI 0x60000000 /* Run-test-idle */ -#define JCMD0_ACC_MASK 0x0000f000 -#define JCMD0_ACC_IRDR 0x00000000 -#define JCMD0_ACC_DR 0x00001000 -#define JCMD0_ACC_IR 0x00002000 -#define JCMD0_ACC_RESET 0x00003000 -#define JCMD0_ACC_IRPDR 0x00004000 -#define JCMD0_ACC_PDR 0x00005000 -#define JCMD0_IRW_MASK 0x00000f00 -#define JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */ -#define JCMD_ACC_IRDR 0x00000000 -#define JCMD_ACC_DR 0x00010000 -#define JCMD_ACC_IR 0x00020000 -#define JCMD_ACC_RESET 0x00030000 -#define JCMD_ACC_IRPDR 0x00040000 -#define JCMD_ACC_PDR 0x00050000 -#define JCMD_ACC_PIR 0x00060000 -#define JCMD_ACC_IRDR_I 0x00070000 /* rev 28: return to run-test-idle */ -#define JCMD_ACC_DR_I 0x00080000 /* rev 28: return to run-test-idle */ -#define JCMD_IRW_MASK 0x00001f00 -#define JCMD_IRW_SHIFT 8 -#define JCMD_DRW_MASK 0x0000003f - -/* jtagctrl */ -#define JCTRL_FORCE_CLK 4 /* Force clock */ -#define JCTRL_EXT_EN 2 /* Enable external targets */ -#define JCTRL_EN 1 /* Enable Jtag master */ - -/* Fields in clkdiv */ -#define CLKD_SFLASH 0x0f000000 -#define CLKD_SFLASH_SHIFT 24 -#define CLKD_OTP 0x000f0000 -#define CLKD_OTP_SHIFT 16 -#define CLKD_JTAG 0x00000f00 -#define CLKD_JTAG_SHIFT 8 -#define CLKD_UART 0x000000ff - -#define CLKD2_SROM 0x00000003 - -/* intstatus/intmask */ -#define CI_GPIO 0x00000001 /* gpio intr */ -#define CI_EI 0x00000002 /* extif intr (corerev >= 3) */ -#define CI_TEMP 0x00000004 /* temp. ctrl intr (corerev >= 15) */ -#define CI_SIRQ 0x00000008 /* serial IRQ intr (corerev >= 15) */ -#define CI_ECI 0x00000010 /* eci intr (corerev >= 21) */ -#define CI_PMU 0x00000020 /* pmu intr (corerev >= 21) */ -#define CI_UART 0x00000040 /* uart intr (corerev >= 21) */ -#define CI_WDRESET 0x80000000 /* watchdog reset occurred */ - -/* slow_clk_ctl */ -#define SCC_SS_MASK 0x00000007 /* slow clock source mask */ -#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */ -#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */ -#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */ -#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ -#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, - * 0: LPO is enabled - */ -#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, - * 0: power logic control - */ -#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors - * PLL clock disable requests from core - */ -#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't - * disable crystal when appropriate - */ -#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ -#define SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ -#define SCC_CD_SHIFT 16 - -/* system_clk_ctl */ -#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */ -#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */ -#define SYCC_FP 0x00000004 /* ForcePLLOn */ -#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */ -#define SYCC_HR 0x00000010 /* Force HT */ -#define SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ -#define SYCC_CD_SHIFT 16 - -/* Indirect backplane access */ -#define BPIA_BYTEEN 0x0000000f -#define BPIA_SZ1 0x00000001 -#define BPIA_SZ2 0x00000003 -#define BPIA_SZ4 0x00000007 -#define BPIA_SZ8 0x0000000f -#define BPIA_WRITE 0x00000100 -#define BPIA_START 0x00000200 -#define BPIA_BUSY 0x00000200 -#define BPIA_ERROR 0x00000400 - -/* pcmcia/prog/flash_config */ -#define CF_EN 0x00000001 /* enable */ -#define CF_EM_MASK 0x0000000e /* mode */ -#define CF_EM_SHIFT 1 -#define CF_EM_FLASH 0 /* flash/asynchronous mode */ -#define CF_EM_SYNC 2 /* synchronous mode */ -#define CF_EM_PCMCIA 4 /* pcmcia mode */ -#define CF_DS 0x00000010 /* destsize: 0=8bit, 1=16bit */ -#define CF_BS 0x00000020 /* byteswap */ -#define CF_CD_MASK 0x000000c0 /* clock divider */ -#define CF_CD_SHIFT 6 -#define CF_CD_DIV2 0x00000000 /* backplane/2 */ -#define CF_CD_DIV3 0x00000040 /* backplane/3 */ -#define CF_CD_DIV4 0x00000080 /* backplane/4 */ -#define CF_CE 0x00000100 /* clock enable */ -#define CF_SB 0x00000200 /* size/bytestrobe (synch only) */ - -/* pcmcia_memwait */ -#define PM_W0_MASK 0x0000003f /* waitcount0 */ -#define PM_W1_MASK 0x00001f00 /* waitcount1 */ -#define PM_W1_SHIFT 8 -#define PM_W2_MASK 0x001f0000 /* waitcount2 */ -#define PM_W2_SHIFT 16 -#define PM_W3_MASK 0x1f000000 /* waitcount3 */ -#define PM_W3_SHIFT 24 - -/* pcmcia_attrwait */ -#define PA_W0_MASK 0x0000003f /* waitcount0 */ -#define PA_W1_MASK 0x00001f00 /* waitcount1 */ -#define PA_W1_SHIFT 8 -#define PA_W2_MASK 0x001f0000 /* waitcount2 */ -#define PA_W2_SHIFT 16 -#define PA_W3_MASK 0x1f000000 /* waitcount3 */ -#define PA_W3_SHIFT 24 - -/* pcmcia_iowait */ -#define PI_W0_MASK 0x0000003f /* waitcount0 */ -#define PI_W1_MASK 0x00001f00 /* waitcount1 */ -#define PI_W1_SHIFT 8 -#define PI_W2_MASK 0x001f0000 /* waitcount2 */ -#define PI_W2_SHIFT 16 -#define PI_W3_MASK 0x1f000000 /* waitcount3 */ -#define PI_W3_SHIFT 24 - -/* prog_waitcount */ -#define PW_W0_MASK 0x0000001f /* waitcount0 */ -#define PW_W1_MASK 0x00001f00 /* waitcount1 */ -#define PW_W1_SHIFT 8 -#define PW_W2_MASK 0x001f0000 /* waitcount2 */ -#define PW_W2_SHIFT 16 -#define PW_W3_MASK 0x1f000000 /* waitcount3 */ -#define PW_W3_SHIFT 24 - -#define PW_W0 0x0000000c -#define PW_W1 0x00000a00 -#define PW_W2 0x00020000 -#define PW_W3 0x01000000 - -/* flash_waitcount */ -#define FW_W0_MASK 0x0000003f /* waitcount0 */ -#define FW_W1_MASK 0x00001f00 /* waitcount1 */ -#define FW_W1_SHIFT 8 -#define FW_W2_MASK 0x001f0000 /* waitcount2 */ -#define FW_W2_SHIFT 16 -#define FW_W3_MASK 0x1f000000 /* waitcount3 */ -#define FW_W3_SHIFT 24 - -/* 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_OTPPRESENT 0x00000020 -#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 - -/* Fields in pmucontrol */ -#define PCTL_ILP_DIV_MASK 0xffff0000 -#define PCTL_ILP_DIV_SHIFT 16 -#define PCTL_LQ_REQ_EN 0x00008000 -#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 - -/* Retention Control */ -#define PMU_RCTL_CLK_DIV_SHIFT 0 -#define PMU_RCTL_CHAIN_LEN_SHIFT 12 -#define PMU_RCTL_MACPHY_DISABLE_SHIFT 26 -#define PMU_RCTL_MACPHY_DISABLE_MASK (1 << 26) -#define PMU_RCTL_LOGIC_DISABLE_SHIFT 27 -#define PMU_RCTL_LOGIC_DISABLE_MASK (1 << 27) -#define PMU_RCTL_MEMSLP_LOG_SHIFT 28 -#define PMU_RCTL_MEMSLP_LOG_MASK (1 << 28) -#define PMU_RCTL_MEMRETSLP_LOG_SHIFT 29 -#define PMU_RCTL_MEMRETSLP_LOG_MASK (1 << 29) - -/* Retention Group Control */ -#define PMU_RCTLGRP_CHAIN_LEN_SHIFT 0 -#define PMU_RCTLGRP_RMODE_ENABLE_SHIFT 14 -#define PMU_RCTLGRP_RMODE_ENABLE_MASK (1 << 14) -#define PMU_RCTLGRP_DFT_ENABLE_SHIFT 15 -#define PMU_RCTLGRP_DFT_ENABLE_MASK (1 << 15) -#define PMU_RCTLGRP_NSRST_DISABLE_SHIFT 16 -#define PMU_RCTLGRP_NSRST_DISABLE_MASK (1 << 16) -/* Retention Group Control special for 4334 */ -#define PMU4334_RCTLGRP_CHAIN_LEN_GRP0 338 -#define PMU4334_RCTLGRP_CHAIN_LEN_GRP1 315 -/* Retention Group Control special for 43341 */ -#define PMU43341_RCTLGRP_CHAIN_LEN_GRP0 366 -#define PMU43341_RCTLGRP_CHAIN_LEN_GRP1 330 - -/* Fields in clkstretch */ -#define CSTRETCH_HT 0xffff0000 -#define CSTRETCH_ALP 0x0000ffff - -/* gpiotimerval */ -#define GPIO_ONTIME_SHIFT 16 - -/* clockcontrol_n */ -#define CN_N1_MASK 0x3f /* n1 control */ -#define CN_N2_MASK 0x3f00 /* n2 control */ -#define CN_N2_SHIFT 8 -#define CN_PLLC_MASK 0xf0000 /* pll control */ -#define CN_PLLC_SHIFT 16 - -/* clockcontrol_sb/pci/uart */ -#define CC_M1_MASK 0x3f /* m1 control */ -#define CC_M2_MASK 0x3f00 /* m2 control */ -#define CC_M2_SHIFT 8 -#define CC_M3_MASK 0x3f0000 /* m3 control */ -#define CC_M3_SHIFT 16 -#define CC_MC_MASK 0x1f000000 /* mux control */ -#define CC_MC_SHIFT 24 - -/* N3M Clock control magic field values */ -#define CC_F6_2 0x02 /* A factor of 2 in */ -#define CC_F6_3 0x03 /* 6-bit fields like */ -#define CC_F6_4 0x05 /* N1, M1 or M3 */ -#define CC_F6_5 0x09 -#define CC_F6_6 0x11 -#define CC_F6_7 0x21 - -#define CC_F5_BIAS 5 /* 5-bit fields get this added */ - -#define CC_MC_BYPASS 0x08 -#define CC_MC_M1 0x04 -#define CC_MC_M1M2 0x02 -#define CC_MC_M1M2M3 0x01 -#define CC_MC_M1M3 0x11 - -/* Type 2 Clock control magic field values */ -#define CC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ -#define CC_T2M2_BIAS 3 /* m2 bias */ - -#define CC_T2MC_M1BYP 1 -#define CC_T2MC_M2BYP 2 -#define CC_T2MC_M3BYP 4 - -/* Type 6 Clock control magic field values */ -#define CC_T6_MMASK 1 /* bits of interest in m */ -#define CC_T6_M0 120000000 /* sb clock for m = 0 */ -#define CC_T6_M1 100000000 /* sb clock for m = 1 */ -#define SB2MIPS_T6(sb) (2 * (sb)) - -/* Common clock base */ -#define CC_CLOCK_BASE1 24000000 /* Half the clock freq */ -#define CC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLLs */ - -/* Clock control values for 200MHz in 5350 */ -#define CLKC_5350_N 0x0311 -#define CLKC_5350_M 0x04020009 - -/* Flash types in the chipcommon capabilities register */ -#define FLASH_NONE 0x000 /* No flash */ -#define SFLASH_ST 0x100 /* ST serial flash */ -#define SFLASH_AT 0x200 /* Atmel serial flash */ -#define NFLASH 0x300 -#define PFLASH 0x700 /* Parallel flash */ -#define QSPIFLASH_ST 0x800 -#define QSPIFLASH_AT 0x900 - -/* Bits in the ExtBus config registers */ -#define CC_CFG_EN 0x0001 /* Enable */ -#define CC_CFG_EM_MASK 0x000e /* Extif Mode */ -#define CC_CFG_EM_ASYNC 0x0000 /* Async/Parallel flash */ -#define CC_CFG_EM_SYNC 0x0002 /* Synchronous */ -#define CC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */ -#define CC_CFG_EM_IDE 0x0006 /* IDE */ -#define CC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */ -#define CC_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */ -#define CC_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */ -#define CC_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */ -#define CC_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */ - -/* ExtBus address space */ -#define CC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */ -#define CC_EB_PCMCIA_MEM 0x1a000000 /* PCMCIA 0 memory base address */ -#define CC_EB_PCMCIA_IO 0x1a200000 /* PCMCIA 0 I/O base address */ -#define CC_EB_PCMCIA_CFG 0x1a400000 /* PCMCIA 0 config base address */ -#define CC_EB_IDE 0x1a800000 /* IDE memory base */ -#define CC_EB_PCMCIA1_MEM 0x1a800000 /* PCMCIA 1 memory base address */ -#define CC_EB_PCMCIA1_IO 0x1aa00000 /* PCMCIA 1 I/O base address */ -#define CC_EB_PCMCIA1_CFG 0x1ac00000 /* PCMCIA 1 config base address */ -#define CC_EB_PROGIF 0x1b000000 /* ProgIF Async/Sync base address */ - - -/* Start/busy bit in flashcontrol */ -#define SFLASH_OPCODE 0x000000ff -#define SFLASH_ACTION 0x00000700 -#define SFLASH_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */ -#define SFLASH_START 0x80000000 -#define SFLASH_BUSY SFLASH_START - -/* flashcontrol action codes */ -#define SFLASH_ACT_OPONLY 0x0000 /* Issue opcode only */ -#define SFLASH_ACT_OP1D 0x0100 /* opcode + 1 data byte */ -#define SFLASH_ACT_OP3A 0x0200 /* opcode + 3 addr bytes */ -#define SFLASH_ACT_OP3A1D 0x0300 /* opcode + 3 addr & 1 data bytes */ -#define SFLASH_ACT_OP3A4D 0x0400 /* opcode + 3 addr & 4 data bytes */ -#define SFLASH_ACT_OP3A4X4D 0x0500 /* opcode + 3 addr, 4 don't care & 4 data bytes */ -#define SFLASH_ACT_OP3A1X4D 0x0700 /* opcode + 3 addr, 1 don't care & 4 data bytes */ - -/* flashcontrol action+opcodes for ST flashes */ -#define SFLASH_ST_WREN 0x0006 /* Write Enable */ -#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */ -#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */ -#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */ -#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */ -#define SFLASH_ST_PP 0x0302 /* Page Program */ -#define SFLASH_ST_SE 0x02d8 /* Sector Erase */ -#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */ -#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */ -#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */ -#define SFLASH_ST_CSA 0x1000 /* Keep chip select asserted */ -#define SFLASH_ST_SSE 0x0220 /* Sub-sector Erase */ - -#define SFLASH_MXIC_RDID 0x0390 /* Read Manufacture ID */ -#define SFLASH_MXIC_MFID 0xc2 /* MXIC Manufacture ID */ - -/* Status register bits for ST flashes */ -#define SFLASH_ST_WIP 0x01 /* Write In Progress */ -#define SFLASH_ST_WEL 0x02 /* Write Enable Latch */ -#define SFLASH_ST_BP_MASK 0x1c /* Block Protect */ -#define SFLASH_ST_BP_SHIFT 2 -#define SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */ - -/* flashcontrol action+opcodes for Atmel flashes */ -#define SFLASH_AT_READ 0x07e8 -#define SFLASH_AT_PAGE_READ 0x07d2 -#define SFLASH_AT_BUF1_READ -#define SFLASH_AT_BUF2_READ -#define SFLASH_AT_STATUS 0x01d7 -#define SFLASH_AT_BUF1_WRITE 0x0384 -#define SFLASH_AT_BUF2_WRITE 0x0387 -#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 -#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 -#define SFLASH_AT_BUF1_PROGRAM 0x0288 -#define SFLASH_AT_BUF2_PROGRAM 0x0289 -#define SFLASH_AT_PAGE_ERASE 0x0281 -#define SFLASH_AT_BLOCK_ERASE 0x0250 -#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 -#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 -#define SFLASH_AT_BUF1_LOAD 0x0253 -#define SFLASH_AT_BUF2_LOAD 0x0255 -#define SFLASH_AT_BUF1_COMPARE 0x0260 -#define SFLASH_AT_BUF2_COMPARE 0x0261 -#define SFLASH_AT_BUF1_REPROGRAM 0x0258 -#define SFLASH_AT_BUF2_REPROGRAM 0x0259 - -/* Status register bits for Atmel flashes */ -#define SFLASH_AT_READY 0x80 -#define SFLASH_AT_MISMATCH 0x40 -#define SFLASH_AT_ID_MASK 0x38 -#define SFLASH_AT_ID_SHIFT 3 - -/* SPI register bits, corerev >= 37 */ -#define GSIO_START 0x80000000 -#define GSIO_BUSY GSIO_START - -/* - * These are the UART port assignments, expressed as offsets from the base - * register. These assignments should hold for any serial port based on - * a 8250, 16450, or 16550(A). - */ - -#define UART_RX 0 /* In: Receive buffer (DLAB=0) */ -#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ -#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ -#define UART_IER 1 /* In/Out: Interrupt Enable Register (DLAB=0) */ -#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */ -#define UART_IIR 2 /* In: Interrupt Identity Register */ -#define UART_FCR 2 /* Out: FIFO Control Register */ -#define UART_LCR 3 /* Out: Line Control Register */ -#define UART_MCR 4 /* Out: Modem Control Register */ -#define UART_LSR 5 /* In: Line Status Register */ -#define UART_MSR 6 /* In: Modem Status Register */ -#define UART_SCR 7 /* I/O: Scratch Register */ -#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ -#define UART_LCR_WLEN8 0x03 /* Word length: 8 bits */ -#define UART_MCR_OUT2 0x08 /* MCR GPIO out 2 */ -#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ -#define UART_LSR_RX_FIFO 0x80 /* Receive FIFO error */ -#define UART_LSR_TDHR 0x40 /* Data-hold-register empty */ -#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ -#define UART_LSR_BREAK 0x10 /* Break interrupt */ -#define UART_LSR_FRAMING 0x08 /* Framing error */ -#define UART_LSR_PARITY 0x04 /* Parity error */ -#define UART_LSR_OVERRUN 0x02 /* Overrun error */ -#define UART_LSR_RXRDY 0x01 /* Receiver ready */ -#define UART_FCR_FIFO_ENABLE 1 /* FIFO control register bit controlling FIFO enable/disable */ - -/* Interrupt Identity Register (IIR) bits */ -#define UART_IIR_FIFO_MASK 0xc0 /* IIR FIFO disable/enabled mask */ -#define UART_IIR_INT_MASK 0xf /* IIR interrupt ID source */ -#define UART_IIR_MDM_CHG 0x0 /* Modem status changed */ -#define UART_IIR_NOINT 0x1 /* No interrupt pending */ -#define UART_IIR_THRE 0x2 /* THR empty */ -#define UART_IIR_RCVD_DATA 0x4 /* Received data available */ -#define UART_IIR_RCVR_STATUS 0x6 /* Receiver status */ -#define UART_IIR_CHAR_TIME 0xc /* Character time */ - -/* Interrupt Enable Register (IER) bits */ -#define UART_IER_PTIME 128 /* Programmable THRE Interrupt Mode Enable */ -#define UART_IER_EDSSI 8 /* enable modem status interrupt */ -#define UART_IER_ELSI 4 /* enable receiver line status interrupt */ -#define UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */ -#define UART_IER_ERBFI 1 /* enable data available interrupt */ - -/* 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 - -/* 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 - -/* PMU Resource Request Timer registers */ -/* This is based on PmuRev0 */ -#define PRRT_TIME_MASK 0x03ff -#define PRRT_INTEN 0x0400 -#define PRRT_REQ_ACTIVE 0x0800 -#define PRRT_ALP_REQ 0x1000 -#define PRRT_HT_REQ 0x2000 -#define PRRT_HQ_REQ 0x4000 - -/* PMU resource bit position */ -#define PMURES_BIT(bit) (1 << (bit)) - -/* PMU resource number limit */ -#define PMURES_MAX_RESNUM 30 - -/* PMU chip control0 register */ -#define PMU_CHIPCTL0 0 -#define PMU43143_CC0_SDIO_DRSTR_OVR (1 << 31) /* sdio drive strength override enable */ - -/* clock req types */ -#define PMU_CC1_CLKREQ_TYPE_SHIFT 19 -#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT) - -#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0 -#define CLKREQ_TYPE_CONFIG_PUSHPULL 1 - -/* PMU chip control1 register */ -#define PMU_CHIPCTL1 1 -#define PMU_CC1_RXC_DLL_BYPASS 0x00010000 -#define PMU_CC1_ENABLE_BBPLL_PWR_DOWN 0x00000010 - -#define PMU_CC1_IF_TYPE_MASK 0x00000030 -#define PMU_CC1_IF_TYPE_RMII 0x00000000 -#define PMU_CC1_IF_TYPE_MII 0x00000010 -#define PMU_CC1_IF_TYPE_RGMII 0x00000020 - -#define PMU_CC1_SW_TYPE_MASK 0x000000c0 -#define PMU_CC1_SW_TYPE_EPHY 0x00000000 -#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040 -#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 -#define PMU_CC1_SW_TYPE_RGMII 0x000000c0 - -/* PMU chip control2 register */ -#define PMU_CHIPCTL2 2 -#define PMU_CC2_FORCE_SUBCORE_PWR_SWITCH_ON (1 << 18) -#define PMU_CC2_FORCE_PHY_PWR_SWITCH_ON (1 << 19) -#define PMU_CC2_FORCE_VDDM_PWR_SWITCH_ON (1 << 20) -#define PMU_CC2_FORCE_MEMLPLDO_PWR_SWITCH_ON (1 << 21) - -/* PMU chip control3 register */ -#define PMU_CHIPCTL3 3 - -/* PMU chip control6 register */ -#define PMU_CHIPCTL6 6 -#define PMU_CC6_ENABLE_CLKREQ_WAKEUP (1 << 4) -#define PMU_CC6_ENABLE_PMU_WAKEUP_ALP (1 << 6) - -#define PMU_CC3_ENABLE_SDIO_WAKEUP_SHIFT 19 -#define PMU_CC3_ENABLE_RF_SHIFT 22 -#define PMU_CC3_RF_DISABLE_IVALUE_SHIFT 23 - -/* PMU chip control5 register */ -#define PMU_CHIPCTL5 5 - -/* PMU chip control6 register */ -#define PMU_CHIPCTL6 6 -#define PMU_CC6_ENABLE_CLKREQ_WAKEUP (1 << 4) -#define PMU_CC6_ENABLE_PMU_WAKEUP_ALP (1 << 6) - -/* 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 */ -/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */ -#define PMU0_PLL0_PLLCTL0 0 -#define PMU0_PLL0_PC0_PDIV_MASK 1 -#define PMU0_PLL0_PC0_PDIV_FREQ 25000 -#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038 -#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3 -#define PMU0_PLL0_PC0_DIV_ARM_BASE 8 - -/* PC0_DIV_ARM for PLLOUT_ARM */ -#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0 -#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1 -#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2 -#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */ -#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4 -#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5 -#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6 -#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7 - -/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */ -#define PMU0_PLL0_PLLCTL1 1 -#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000 -#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28 -#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00 -#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8 -#define PMU0_PLL0_PC1_STOP_MOD 0x00000040 - -/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */ -#define PMU0_PLL0_PLLCTL2 2 -#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf -#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4 - -/* pllcontrol registers */ -/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ -#define PMU1_PLL0_PLLCTL0 0 -#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 -#define PMU1_PLL0_PC0_P1DIV_SHIFT 20 -#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 -#define PMU1_PLL0_PC0_P2DIV_SHIFT 24 - -/* mdiv */ -#define PMU1_PLL0_PLLCTL1 1 -#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff -#define PMU1_PLL0_PC1_M1DIV_SHIFT 0 -#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 -#define PMU1_PLL0_PC1_M2DIV_SHIFT 8 -#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 -#define PMU1_PLL0_PC1_M3DIV_SHIFT 16 -#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 -#define PMU1_PLL0_PC1_M4DIV_SHIFT 24 -#define PMU1_PLL0_PC1_M4DIV_BY_9 9 -#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12 -#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24 - -#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 -#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) -#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) - -/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ -#define PMU1_PLL0_PLLCTL2 2 -#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff -#define PMU1_PLL0_PC2_M5DIV_SHIFT 0 -#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc -#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12 -#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24 -#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 -#define PMU1_PLL0_PC2_M6DIV_SHIFT 8 -#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12 -#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24 -#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 -#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 -#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 -#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */ -#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 -#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 - -/* ndiv_frac */ -#define PMU1_PLL0_PLLCTL3 3 -#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff -#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 - -/* pll_ctrl */ -#define PMU1_PLL0_PLLCTL4 4 - -/* pll_ctrl, vco_rng, clkdrive_ch */ -#define PMU1_PLL0_PLLCTL5 5 -#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 -#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 - -#define PMU1_PLL0_PLLCTL6 6 -#define PMU1_PLL0_PLLCTL7 7 - -/* PMU rev 2 control words */ -#define PMU2_PHY_PLL_PLLCTL 4 -#define PMU2_SI_PLL_PLLCTL 10 - -/* PMU rev 2 */ -/* pllcontrol registers */ -/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ -#define PMU2_PLL_PLLCTL0 0 -#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 -#define PMU2_PLL_PC0_P1DIV_SHIFT 20 -#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 -#define PMU2_PLL_PC0_P2DIV_SHIFT 24 - -/* mdiv */ -#define PMU2_PLL_PLLCTL1 1 -#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff -#define PMU2_PLL_PC1_M1DIV_SHIFT 0 -#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 -#define PMU2_PLL_PC1_M2DIV_SHIFT 8 -#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 -#define PMU2_PLL_PC1_M3DIV_SHIFT 16 -#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000 -#define PMU2_PLL_PC1_M4DIV_SHIFT 24 - -/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ -#define PMU2_PLL_PLLCTL2 2 -#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff -#define PMU2_PLL_PC2_M5DIV_SHIFT 0 -#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 -#define PMU2_PLL_PC2_M6DIV_SHIFT 8 -#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 -#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 -#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 -#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20 - -/* ndiv_frac */ -#define PMU2_PLL_PLLCTL3 3 -#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff -#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 - -/* pll_ctrl */ -#define PMU2_PLL_PLLCTL4 4 - -/* pll_ctrl, vco_rng, clkdrive_ch */ -#define PMU2_PLL_PLLCTL5 5 -#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 -#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 -#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 -#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 -#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 -#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 -#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 -#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 -#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 -#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 -#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 -#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 - -/* PMU rev 5 (& 6) */ -#define PMU5_PLL_P1P2_OFF 0 -#define PMU5_PLL_P1_MASK 0x0f000000 -#define PMU5_PLL_P1_SHIFT 24 -#define PMU5_PLL_P2_MASK 0x00f00000 -#define PMU5_PLL_P2_SHIFT 20 -#define PMU5_PLL_M14_OFF 1 -#define PMU5_PLL_MDIV_MASK 0x000000ff -#define PMU5_PLL_MDIV_WIDTH 8 -#define PMU5_PLL_NM5_OFF 2 -#define PMU5_PLL_NDIV_MASK 0xfff00000 -#define PMU5_PLL_NDIV_SHIFT 20 -#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000 -#define PMU5_PLL_NDIV_MODE_SHIFT 17 -#define PMU5_PLL_FMAB_OFF 3 -#define PMU5_PLL_MRAT_MASK 0xf0000000 -#define PMU5_PLL_MRAT_SHIFT 28 -#define PMU5_PLL_ABRAT_MASK 0x08000000 -#define PMU5_PLL_ABRAT_SHIFT 27 -#define PMU5_PLL_FDIV_MASK 0x07ffffff -#define PMU5_PLL_PLLCTL_OFF 4 -#define PMU5_PLL_PCHI_OFF 5 -#define PMU5_PLL_PCHI_MASK 0x0000003f - -/* pmu XtalFreqRatio */ -#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF -#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 -#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 - -/* Divider allocation in 4716/47162/5356/5357 */ -#define PMU5_MAINPLL_CPU 1 -#define PMU5_MAINPLL_MEM 2 -#define PMU5_MAINPLL_SI 3 - -/* 4706 PMU */ -#define PMU4706_MAINPLL_PLL0 0 -#define PMU6_4706_PROCPLL_OFF 4 /* The CPU PLL */ -#define PMU6_4706_PROC_P2DIV_MASK 0x000f0000 -#define PMU6_4706_PROC_P2DIV_SHIFT 16 -#define PMU6_4706_PROC_P1DIV_MASK 0x0000f000 -#define PMU6_4706_PROC_P1DIV_SHIFT 12 -#define PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 -#define PMU6_4706_PROC_NDIV_INT_SHIFT 3 -#define PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 -#define PMU6_4706_PROC_NDIV_MODE_SHIFT 0 - -#define PMU7_PLL_PLLCTL7 7 -#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000 -#define PMU7_PLL_CTL7_M4DIV_SHIFT 24 -#define PMU7_PLL_CTL7_M4DIV_BY_6 6 -#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc -#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18 -#define PMU7_PLL_PLLCTL8 8 -#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff -#define PMU7_PLL_CTL8_M5DIV_SHIFT 0 -#define PMU7_PLL_CTL8_M5DIV_BY_8 8 -#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc -#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18 -#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00 -#define PMU7_PLL_CTL8_M6DIV_SHIFT 8 -#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc -#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18 -#define PMU7_PLL_PLLCTL11 11 -#define PMU7_PLL_PLLCTL11_MASK 0xffffff00 -#define PMU7_PLL_PLLCTL11_VAL 0x22222200 - -/* PMU rev 15 */ -#define PMU15_PLL_PLLCTL0 0 -#define PMU15_PLL_PC0_CLKSEL_MASK 0x00000003 -#define PMU15_PLL_PC0_CLKSEL_SHIFT 0 -#define PMU15_PLL_PC0_FREQTGT_MASK 0x003FFFFC -#define PMU15_PLL_PC0_FREQTGT_SHIFT 2 -#define PMU15_PLL_PC0_PRESCALE_MASK 0x00C00000 -#define PMU15_PLL_PC0_PRESCALE_SHIFT 22 -#define PMU15_PLL_PC0_KPCTRL_MASK 0x07000000 -#define PMU15_PLL_PC0_KPCTRL_SHIFT 24 -#define PMU15_PLL_PC0_FCNTCTRL_MASK 0x38000000 -#define PMU15_PLL_PC0_FCNTCTRL_SHIFT 27 -#define PMU15_PLL_PC0_FDCMODE_MASK 0x40000000 -#define PMU15_PLL_PC0_FDCMODE_SHIFT 30 -#define PMU15_PLL_PC0_CTRLBIAS_MASK 0x80000000 -#define PMU15_PLL_PC0_CTRLBIAS_SHIFT 31 - -#define PMU15_PLL_PLLCTL1 1 -#define PMU15_PLL_PC1_BIAS_CTLM_MASK 0x00000060 -#define PMU15_PLL_PC1_BIAS_CTLM_SHIFT 5 -#define PMU15_PLL_PC1_BIAS_CTLM_RST_MASK 0x00000040 -#define PMU15_PLL_PC1_BIAS_CTLM_RST_SHIFT 6 -#define PMU15_PLL_PC1_BIAS_SS_DIVR_MASK 0x0001FF80 -#define PMU15_PLL_PC1_BIAS_SS_DIVR_SHIFT 7 -#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_MASK 0x03FE0000 -#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_SHIFT 17 -#define PMU15_PLL_PC1_BIAS_INTG_BW_MASK 0x0C000000 -#define PMU15_PLL_PC1_BIAS_INTG_BW_SHIFT 26 -#define PMU15_PLL_PC1_BIAS_INTG_BYP_MASK 0x10000000 -#define PMU15_PLL_PC1_BIAS_INTG_BYP_SHIFT 28 -#define PMU15_PLL_PC1_OPENLP_EN_MASK 0x40000000 -#define PMU15_PLL_PC1_OPENLP_EN_SHIFT 30 - -#define PMU15_PLL_PLLCTL2 2 -#define PMU15_PLL_PC2_CTEN_MASK 0x00000001 -#define PMU15_PLL_PC2_CTEN_SHIFT 0 - -#define PMU15_PLL_PLLCTL3 3 -#define PMU15_PLL_PC3_DITHER_EN_MASK 0x00000001 -#define PMU15_PLL_PC3_DITHER_EN_SHIFT 0 -#define PMU15_PLL_PC3_DCOCTLSP_MASK 0xFE000000 -#define PMU15_PLL_PC3_DCOCTLSP_SHIFT 25 -#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_MASK 0x01 -#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_SHIFT 0 -#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_MASK 0x02 -#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_SHIFT 1 -#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_MASK 0x04 -#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_SHIFT 2 -#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_MASK 0x18 -#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_SHIFT 3 -#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_MASK 0x60 -#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_SHIFT 5 -#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV1 0 -#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV2 1 -#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV3 2 -#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV5 3 - -#define PMU15_PLL_PLLCTL4 4 -#define PMU15_PLL_PC4_FLLCLK1_DIV_MASK 0x00000007 -#define PMU15_PLL_PC4_FLLCLK1_DIV_SHIFT 0 -#define PMU15_PLL_PC4_FLLCLK2_DIV_MASK 0x00000038 -#define PMU15_PLL_PC4_FLLCLK2_DIV_SHIFT 3 -#define PMU15_PLL_PC4_FLLCLK3_DIV_MASK 0x000001C0 -#define PMU15_PLL_PC4_FLLCLK3_DIV_SHIFT 6 -#define PMU15_PLL_PC4_DBGMODE_MASK 0x00000E00 -#define PMU15_PLL_PC4_DBGMODE_SHIFT 9 -#define PMU15_PLL_PC4_FLL480_CTLSP_LK_MASK 0x00001000 -#define PMU15_PLL_PC4_FLL480_CTLSP_LK_SHIFT 12 -#define PMU15_PLL_PC4_FLL480_CTLSP_MASK 0x000FE000 -#define PMU15_PLL_PC4_FLL480_CTLSP_SHIFT 13 -#define PMU15_PLL_PC4_DINPOL_MASK 0x00100000 -#define PMU15_PLL_PC4_DINPOL_SHIFT 20 -#define PMU15_PLL_PC4_CLKOUT_PD_MASK 0x00200000 -#define PMU15_PLL_PC4_CLKOUT_PD_SHIFT 21 -#define PMU15_PLL_PC4_CLKDIV2_PD_MASK 0x00400000 -#define PMU15_PLL_PC4_CLKDIV2_PD_SHIFT 22 -#define PMU15_PLL_PC4_CLKDIV4_PD_MASK 0x00800000 -#define PMU15_PLL_PC4_CLKDIV4_PD_SHIFT 23 -#define PMU15_PLL_PC4_CLKDIV8_PD_MASK 0x01000000 -#define PMU15_PLL_PC4_CLKDIV8_PD_SHIFT 24 -#define PMU15_PLL_PC4_CLKDIV16_PD_MASK 0x02000000 -#define PMU15_PLL_PC4_CLKDIV16_PD_SHIFT 25 -#define PMU15_PLL_PC4_TEST_EN_MASK 0x04000000 -#define PMU15_PLL_PC4_TEST_EN_SHIFT 26 - -#define PMU15_PLL_PLLCTL5 5 -#define PMU15_PLL_PC5_FREQTGT_MASK 0x000FFFFF -#define PMU15_PLL_PC5_FREQTGT_SHIFT 0 -#define PMU15_PLL_PC5_DCOCTLSP_MASK 0x07F00000 -#define PMU15_PLL_PC5_DCOCTLSP_SHIFT 20 -#define PMU15_PLL_PC5_PRESCALE_MASK 0x18000000 -#define PMU15_PLL_PC5_PRESCALE_SHIFT 27 - -#define PMU15_PLL_PLLCTL6 6 -#define PMU15_PLL_PC6_FREQTGT_MASK 0x000FFFFF -#define PMU15_PLL_PC6_FREQTGT_SHIFT 0 -#define PMU15_PLL_PC6_DCOCTLSP_MASK 0x07F00000 -#define PMU15_PLL_PC6_DCOCTLSP_SHIFT 20 -#define PMU15_PLL_PC6_PRESCALE_MASK 0x18000000 -#define PMU15_PLL_PC6_PRESCALE_SHIFT 27 - -#define PMU15_FREQTGT_480_DEFAULT 0x19AB1 -#define PMU15_FREQTGT_492_DEFAULT 0x1A4F5 -#define PMU15_ARM_96MHZ 96000000 /* 96 Mhz */ -#define PMU15_ARM_98MHZ 98400000 /* 98.4 Mhz */ -#define PMU15_ARM_97MHZ 97000000 /* 97 Mhz */ - - -#define PMU17_PLLCTL2_NDIVTYPE_MASK 0x00000070 -#define PMU17_PLLCTL2_NDIVTYPE_SHIFT 4 - -#define PMU17_PLLCTL2_NDIV_MODE_INT 0 -#define PMU17_PLLCTL2_NDIV_MODE_INT1B8 1 -#define PMU17_PLLCTL2_NDIV_MODE_MASH111 2 -#define PMU17_PLLCTL2_NDIV_MODE_MASH111B8 3 - -#define PMU17_PLLCTL0_BBPLL_PWRDWN 0 -#define PMU17_PLLCTL0_BBPLL_DRST 3 -#define PMU17_PLLCTL0_BBPLL_DISBL_CLK 8 - -/* PLL usage in 4716/47162 */ -#define PMU4716_MAINPLL_PLL0 12 - -/* PLL usage in 4335 */ -#define PMU4335_PLL0_PC2_P1DIV_MASK 0x000f0000 -#define PMU4335_PLL0_PC2_P1DIV_SHIFT 16 -#define PMU4335_PLL0_PC2_NDIV_INT_MASK 0xff800000 -#define PMU4335_PLL0_PC2_NDIV_INT_SHIFT 23 -#define PMU4335_PLL0_PC1_MDIV2_MASK 0x0000ff00 -#define PMU4335_PLL0_PC1_MDIV2_SHIFT 8 - - -/* PLL usage in 5356/5357 */ -#define PMU5356_MAINPLL_PLL0 0 -#define PMU5357_MAINPLL_PLL0 0 - -/* 4716/47162 resources */ -#define RES4716_PROC_PLL_ON 0x00000040 -#define RES4716_PROC_HT_AVAIL 0x00000080 - -/* 4716/4717/4718 Chip specific ChipControl register bits */ -#define CCTRL_471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared w/ pflash */ - -/* 5357 Chip specific ChipControl register bits */ -/* 2nd - 32-bit reg */ -#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000 /* I2S pins enable */ -#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000 /* I2C/SPI pins enable */ - -/* 5354 resources */ -#define RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */ -#define RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */ -#define RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */ -#define RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ -#define RES5354_ILP_REQUEST 4 /* 0x00010 */ -#define RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */ -#define RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */ -#define RES5354_ROM_SWITCH 7 /* 0x00080 */ -#define RES5354_PA_REF_LDO 8 /* 0x00100 */ -#define RES5354_RADIO_LDO 9 /* 0x00200 */ -#define RES5354_AFE_LDO 10 /* 0x00400 */ -#define RES5354_PLL_LDO 11 /* 0x00800 */ -#define RES5354_BG_FILTBYP 12 /* 0x01000 */ -#define RES5354_TX_FILTBYP 13 /* 0x02000 */ -#define RES5354_RX_FILTBYP 14 /* 0x04000 */ -#define RES5354_XTAL_PU 15 /* 0x08000 */ -#define RES5354_XTAL_EN 16 /* 0x10000 */ -#define RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */ -#define RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */ -#define RES5354_BB_PLL_PU 19 /* 0x80000 */ - -/* 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 CCTRL5357_NFLASH (1<<16) /* Nandflash in ChipControl 1, bit 16 */ - -/* 43217 Chip specific ChipControl register bits */ -#define CCTRL43217_EXTPA_C0 (1<<13) /* core0 extPA in ChipControl 1, bit 13 */ -#define CCTRL43217_EXTPA_C1 (1<<8) /* core1 extPA in ChipControl 1, bit 8 */ - -/* 43228 Chip specific ChipControl register bits */ -#define CCTRL43228_EXTPA_C0 (1<<14) /* core1 extPA in ChipControl 1, bit 14 */ -#define CCTRL43228_EXTPA_C1 (1<<9) /* core0 extPA in ChipControl 1, bit 1 */ - -/* 4328 resources */ -#define RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */ -#define RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */ -#define RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */ -#define RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ -#define RES4328_ILP_REQUEST 4 /* 0x00010 */ -#define RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */ -#define RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */ -#define RES4328_ROM_SWITCH 7 /* 0x00080 */ -#define RES4328_PA_REF_LDO 8 /* 0x00100 */ -#define RES4328_RADIO_LDO 9 /* 0x00200 */ -#define RES4328_AFE_LDO 10 /* 0x00400 */ -#define RES4328_PLL_LDO 11 /* 0x00800 */ -#define RES4328_BG_FILTBYP 12 /* 0x01000 */ -#define RES4328_TX_FILTBYP 13 /* 0x02000 */ -#define RES4328_RX_FILTBYP 14 /* 0x04000 */ -#define RES4328_XTAL_PU 15 /* 0x08000 */ -#define RES4328_XTAL_EN 16 /* 0x10000 */ -#define RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */ -#define RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */ -#define RES4328_BB_PLL_PU 19 /* 0x80000 */ - -/* 4325 A0/A1 resources */ -#define RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */ -#define RES4325_CBUCK_BURST 1 /* 0x00000002 */ -#define RES4325_CBUCK_PWM 2 /* 0x00000004 */ -#define RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */ -#define RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */ -#define RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */ -#define RES4325_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4325_ABUCK_BURST 7 /* 0x00000080 */ -#define RES4325_ABUCK_PWM 8 /* 0x00000100 */ -#define RES4325_LNLDO1_PU 9 /* 0x00000200 */ -#define RES4325_OTP_PU 10 /* 0x00000400 */ -#define RES4325_LNLDO3_PU 11 /* 0x00000800 */ -#define RES4325_LNLDO4_PU 12 /* 0x00001000 */ -#define RES4325_XTAL_PU 13 /* 0x00002000 */ -#define RES4325_ALP_AVAIL 14 /* 0x00004000 */ -#define RES4325_RX_PWRSW_PU 15 /* 0x00008000 */ -#define RES4325_TX_PWRSW_PU 16 /* 0x00010000 */ -#define RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */ -#define RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */ -#define RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */ -#define RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */ -#define RES4325_HT_AVAIL 21 /* 0x00200000 */ - -/* 4325 B0/C0 resources */ -#define RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */ -#define RES4325B0_CBUCK_BURST 2 /* 0x00000004 */ -#define RES4325B0_CBUCK_PWM 3 /* 0x00000008 */ -#define RES4325B0_CLDO_PU 4 /* 0x00000010 */ - -/* 4325 C1 resources */ -#define RES4325C1_LNLDO2_PU 12 /* 0x00001000 */ - -/* 4325 chip-specific ChipStatus register bits */ -#define CST4325_SPROM_OTP_SEL_MASK 0x00000003 -#define CST4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ -#define CST4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ -#define CST4325_OTP_SEL 2 /* OTP is powered up, no SPROM */ -#define CST4325_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ -#define CST4325_SDIO_USB_MODE_MASK 0x00000004 -#define CST4325_SDIO_USB_MODE_SHIFT 2 -#define CST4325_RCAL_VALID_MASK 0x00000008 -#define CST4325_RCAL_VALID_SHIFT 3 -#define CST4325_RCAL_VALUE_MASK 0x000001f0 -#define CST4325_RCAL_VALUE_SHIFT 4 -#define CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */ -#define CST4325_PMUTOP_2B_SHIFT 9 - -#define RES4329_RESERVED0 0 /* 0x00000001 */ -#define RES4329_CBUCK_LPOM 1 /* 0x00000002 */ -#define RES4329_CBUCK_BURST 2 /* 0x00000004 */ -#define RES4329_CBUCK_PWM 3 /* 0x00000008 */ -#define RES4329_CLDO_PU 4 /* 0x00000010 */ -#define RES4329_PALDO_PU 5 /* 0x00000020 */ -#define RES4329_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4329_RESERVED7 7 /* 0x00000080 */ -#define RES4329_RESERVED8 8 /* 0x00000100 */ -#define RES4329_LNLDO1_PU 9 /* 0x00000200 */ -#define RES4329_OTP_PU 10 /* 0x00000400 */ -#define RES4329_RESERVED11 11 /* 0x00000800 */ -#define RES4329_LNLDO2_PU 12 /* 0x00001000 */ -#define RES4329_XTAL_PU 13 /* 0x00002000 */ -#define RES4329_ALP_AVAIL 14 /* 0x00004000 */ -#define RES4329_RX_PWRSW_PU 15 /* 0x00008000 */ -#define RES4329_TX_PWRSW_PU 16 /* 0x00010000 */ -#define RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */ -#define RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */ -#define RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */ -#define RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */ -#define RES4329_HT_AVAIL 21 /* 0x00200000 */ - -#define CST4329_SPROM_OTP_SEL_MASK 0x00000003 -#define CST4329_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ -#define CST4329_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ -#define CST4329_OTP_SEL 2 /* OTP is powered up, no SPROM */ -#define CST4329_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ -#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 -#define CST4329_SPI_SDIO_MODE_SHIFT 2 - -/* 4312 chip-specific ChipStatus register bits */ -#define CST4312_SPROM_OTP_SEL_MASK 0x00000003 -#define CST4312_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ -#define CST4312_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ -#define CST4312_OTP_SEL 2 /* OTP is powered up, no SPROM */ -#define CST4312_OTP_BAD 3 /* OTP is broken, SPROM is present */ - -/* 4312 resources (all PMU chips with little memory constraint) */ -#define RES4312_SWITCHER_BURST 0 /* 0x00000001 */ -#define RES4312_SWITCHER_PWM 1 /* 0x00000002 */ -#define RES4312_PA_REF_LDO 2 /* 0x00000004 */ -#define RES4312_CORE_LDO_BURST 3 /* 0x00000008 */ -#define RES4312_CORE_LDO_PWM 4 /* 0x00000010 */ -#define RES4312_RADIO_LDO 5 /* 0x00000020 */ -#define RES4312_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4312_BG_FILTBYP 7 /* 0x00000080 */ -#define RES4312_TX_FILTBYP 8 /* 0x00000100 */ -#define RES4312_RX_FILTBYP 9 /* 0x00000200 */ -#define RES4312_XTAL_PU 10 /* 0x00000400 */ -#define RES4312_ALP_AVAIL 11 /* 0x00000800 */ -#define RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */ -#define RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */ -#define RES4312_HT_AVAIL 14 /* 0x00004000 */ - -/* 4322 resources */ -#define RES4322_RF_LDO 0 -#define RES4322_ILP_REQUEST 1 -#define RES4322_XTAL_PU 2 -#define RES4322_ALP_AVAIL 3 -#define RES4322_SI_PLL_ON 4 -#define RES4322_HT_SI_AVAIL 5 -#define RES4322_PHY_PLL_ON 6 -#define RES4322_HT_PHY_AVAIL 7 -#define RES4322_OTP_PU 8 - -/* 4322 chip-specific ChipStatus register bits */ -#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020 -#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0 -#define CST4322_SPROM_OTP_SEL_SHIFT 6 -#define CST4322_NO_SPROM_OTP 0 /* no OTP, no SPROM */ -#define CST4322_SPROM_PRESENT 1 /* SPROM is present */ -#define CST4322_OTP_PRESENT 2 /* OTP is present */ -#define CST4322_PCI_OR_USB 0x00000100 -#define CST4322_BOOT_MASK 0x00000600 -#define CST4322_BOOT_SHIFT 9 -#define CST4322_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ -#define CST4322_BOOT_FROM_ROM 1 /* boot from ROM */ -#define CST4322_BOOT_FROM_FLASH 2 /* boot from FLASH */ -#define CST4322_BOOT_FROM_INVALID 3 -#define CST4322_ILP_DIV_EN 0x00000800 -#define CST4322_FLASH_TYPE_MASK 0x00001000 -#define CST4322_FLASH_TYPE_SHIFT 12 -#define CST4322_FLASH_TYPE_SHIFT_ST 0 /* ST serial FLASH */ -#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1 /* ATMEL flash */ -#define CST4322_ARM_TAP_SEL 0x00002000 -#define CST4322_RES_INIT_MODE_MASK 0x0000c000 -#define CST4322_RES_INIT_MODE_SHIFT 14 -#define CST4322_RES_INIT_MODE_ILPAVAIL 0 /* resinitmode: ILP available */ -#define CST4322_RES_INIT_MODE_ILPREQ 1 /* resinitmode: ILP request */ -#define CST4322_RES_INIT_MODE_ALPAVAIL 2 /* resinitmode: ALP available */ -#define CST4322_RES_INIT_MODE_HTAVAIL 3 /* resinitmode: HT available */ -#define CST4322_PCIPLLCLK_GATING 0x00010000 -#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 -#define CST4322_PCI_CARDBUS_MODE 0x00040000 - -/* 43224 chip-specific ChipControl register bits */ -#define CCTRL43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */ -#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */ -#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */ - -/* 43236 resources */ -#define RES43236_REGULATOR 0 -#define RES43236_ILP_REQUEST 1 -#define RES43236_XTAL_PU 2 -#define RES43236_ALP_AVAIL 3 -#define RES43236_SI_PLL_ON 4 -#define RES43236_HT_SI_AVAIL 5 - -/* 43236 chip-specific ChipControl register bits */ -#define CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */ -#define CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ -#define CCTRL43236_EXT_LNA (1<<2) /* 0 disable */ -#define CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ -#define CCTRL43236_GSIO (1<<4) /* 0 disable */ - -/* 43236 Chip specific ChipStatus register bits */ -#define CST43236_SFLASH_MASK 0x00000040 -#define CST43236_OTP_SEL_MASK 0x00000080 -#define CST43236_OTP_SEL_SHIFT 7 -#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 - -/* 43237 resources */ -#define RES43237_REGULATOR 0 -#define RES43237_ILP_REQUEST 1 -#define RES43237_XTAL_PU 2 -#define RES43237_ALP_AVAIL 3 -#define RES43237_SI_PLL_ON 4 -#define RES43237_HT_SI_AVAIL 5 - -/* 43237 chip-specific ChipControl register bits */ -#define CCTRL43237_BT_COEXIST (1<<0) /* 0 disable */ -#define CCTRL43237_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ -#define CCTRL43237_EXT_LNA (1<<2) /* 0 disable */ -#define CCTRL43237_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ -#define CCTRL43237_GSIO (1<<4) /* 0 disable */ - -/* 43237 Chip specific ChipStatus register bits */ -#define CST43237_SFLASH_MASK 0x00000040 -#define CST43237_OTP_SEL_MASK 0x00000080 -#define CST43237_OTP_SEL_SHIFT 7 -#define CST43237_HSIC_MASK 0x00000100 /* USB/HSIC */ -#define CST43237_BP_CLK 0x00000200 /* 120/96Mbps */ -#define CST43237_BOOT_MASK 0x00001800 -#define CST43237_BOOT_SHIFT 11 -#define CST43237_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ -#define CST43237_BOOT_FROM_ROM 1 /* boot from ROM */ -#define CST43237_BOOT_FROM_FLASH 2 /* boot from FLASH */ -#define CST43237_BOOT_FROM_INVALID 3 - -/* 43239 resources */ -#define RES43239_OTP_PU 9 -#define RES43239_MACPHY_CLKAVAIL 23 -#define RES43239_HT_AVAIL 24 - -/* 43239 Chip specific ChipStatus register bits */ -#define CST43239_SPROM_MASK 0x00000002 -#define CST43239_SFLASH_MASK 0x00000004 -#define CST43239_RES_INIT_MODE_SHIFT 7 -#define CST43239_RES_INIT_MODE_MASK 0x000001f0 -#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) /* SDIO || gSPI */ -#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15)) /* USB || USBDA */ -#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) /* SDIO */ -#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) /* gSPI */ - -/* 4324 resources */ -/* 43242 use same PMU as 4324 */ -#define RES4324_LPLDO_PU 0 -#define RES4324_RESET_PULLDN_DIS 1 -#define RES4324_PMU_BG_PU 2 -#define RES4324_HSIC_LDO_PU 3 -#define RES4324_CBUCK_LPOM_PU 4 -#define RES4324_CBUCK_PFM_PU 5 -#define RES4324_CLDO_PU 6 -#define RES4324_LPLDO2_LVM 7 -#define RES4324_LNLDO1_PU 8 -#define RES4324_LNLDO2_PU 9 -#define RES4324_LDO3P3_PU 10 -#define RES4324_OTP_PU 11 -#define RES4324_XTAL_PU 12 -#define RES4324_BBPLL_PU 13 -#define RES4324_LQ_AVAIL 14 -#define RES4324_WL_CORE_READY 17 -#define RES4324_ILP_REQ 18 -#define RES4324_ALP_AVAIL 19 -#define RES4324_PALDO_PU 20 -#define RES4324_RADIO_PU 21 -#define RES4324_SR_CLK_STABLE 22 -#define RES4324_SR_SAVE_RESTORE 23 -#define RES4324_SR_PHY_PWRSW 24 -#define RES4324_SR_PHY_PIC 25 -#define RES4324_SR_SUBCORE_PWRSW 26 -#define RES4324_SR_SUBCORE_PIC 27 -#define RES4324_SR_MEM_PM0 28 -#define RES4324_HT_AVAIL 29 -#define RES4324_MACPHY_CLKAVAIL 30 - -/* 4324 Chip specific ChipStatus register bits */ -#define CST4324_SPROM_MASK 0x00000080 -#define CST4324_SFLASH_MASK 0x00400000 -#define CST4324_RES_INIT_MODE_SHIFT 10 -#define CST4324_RES_INIT_MODE_MASK 0x00000c00 -#define CST4324_CHIPMODE_MASK 0x7 -#define CST4324_CHIPMODE_SDIOD(cs) ((~(cs)) & (1 << 2)) /* SDIO || gSPI */ -#define CST4324_CHIPMODE_USB20D(cs) (((cs) & CST4324_CHIPMODE_MASK) == 0x6) /* USB || USBDA */ - -/* 43242 Chip specific ChipStatus register bits */ -#define CST43242_SFLASH_MASK 0x00000008 -#define CST43242_SR_HALT (1<<25) -#define CST43242_SR_CHIP_STATUS_2 27 /* bit 27 */ - -/* 4331 resources */ -#define RES4331_REGULATOR 0 -#define RES4331_ILP_REQUEST 1 -#define RES4331_XTAL_PU 2 -#define RES4331_ALP_AVAIL 3 -#define RES4331_SI_PLL_ON 4 -#define RES4331_HT_SI_AVAIL 5 - -/* 4331 chip-specific ChipControl register bits */ -#define CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */ -#define CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ -#define CCTRL4331_EXT_LNA_G (1<<2) /* 0 disable */ -#define CCTRL4331_SPROM_GPIO13_15 (1<<3) /* sprom/gpio13-15 mux */ -#define CCTRL4331_EXTPA_EN (1<<4) /* 0 ext pa disable, 1 ext pa enabled */ -#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) /* set drive out GPIO_CLK on sprom_cs pin */ -#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) /* use sprom_cs pin as PCIE mdio interface */ -#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) /* aband extpa will be at gpio2/5 and sprom_dout */ -#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) /* override core control on pipe_AuxClkEnable */ -#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) /* override core control on pipe_AuxPowerDown */ -#define CCTRL4331_PCIE_AUXCLKEN (1<<10) /* pcie_auxclkenable */ -#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) /* pcie_pipe_pllpowerdown */ -#define CCTRL4331_EXTPA_EN2 (1<<12) /* 0 ext pa disable, 1 ext pa enabled */ -#define CCTRL4331_EXT_LNA_A (1<<13) /* 0 disable */ -#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */ -#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */ -#define CCTRL4331_EXTPA_ANA_EN (1<<24) /* 0 ext pa disable, 1 ext pa enabled */ - -/* 4331 Chip specific ChipStatus register bits */ -#define CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */ -#define CST4331_SPROM_OTP_SEL_MASK 0x00000006 -#define CST4331_SPROM_OTP_SEL_SHIFT 1 -#define CST4331_SPROM_PRESENT 0x00000002 -#define CST4331_OTP_PRESENT 0x00000004 -#define CST4331_LDO_RF 0x00000008 -#define CST4331_LDO_PAR 0x00000010 - -/* 4315 resource */ -#define RES4315_CBUCK_LPOM 1 /* 0x00000002 */ -#define RES4315_CBUCK_BURST 2 /* 0x00000004 */ -#define RES4315_CBUCK_PWM 3 /* 0x00000008 */ -#define RES4315_CLDO_PU 4 /* 0x00000010 */ -#define RES4315_PALDO_PU 5 /* 0x00000020 */ -#define RES4315_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4315_LNLDO1_PU 9 /* 0x00000200 */ -#define RES4315_OTP_PU 10 /* 0x00000400 */ -#define RES4315_LNLDO2_PU 12 /* 0x00001000 */ -#define RES4315_XTAL_PU 13 /* 0x00002000 */ -#define RES4315_ALP_AVAIL 14 /* 0x00004000 */ -#define RES4315_RX_PWRSW_PU 15 /* 0x00008000 */ -#define RES4315_TX_PWRSW_PU 16 /* 0x00010000 */ -#define RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */ -#define RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */ -#define RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */ -#define RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */ -#define RES4315_HT_AVAIL 21 /* 0x00200000 */ - -/* 4315 chip-specific ChipStatus register bits */ -#define CST4315_SPROM_OTP_SEL_MASK 0x00000003 /* gpio [7:6], SDIO CIS selection */ -#define CST4315_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ -#define CST4315_SPROM_SEL 0x00000001 /* use SPROM, OTP is powered up */ -#define CST4315_OTP_SEL 0x00000002 /* use OTP, OTP is powered up */ -#define CST4315_OTP_PWRDN 0x00000003 /* use SPROM, OTP is powered down */ -#define CST4315_SDIO_MODE 0x00000004 /* gpio [8], sdio/usb mode */ -#define CST4315_RCAL_VALID 0x00000008 -#define CST4315_RCAL_VALUE_MASK 0x000001f0 -#define CST4315_RCAL_VALUE_SHIFT 4 -#define CST4315_PALDO_EXTPNP 0x00000200 /* PALDO is configured with external PNP */ -#define CST4315_CBUCK_MODE_MASK 0x00000c00 -#define CST4315_CBUCK_MODE_BURST 0x00000400 -#define CST4315_CBUCK_MODE_LPBURST 0x00000c00 - -/* 4319 resources */ -#define RES4319_CBUCK_LPOM 1 /* 0x00000002 */ -#define RES4319_CBUCK_BURST 2 /* 0x00000004 */ -#define RES4319_CBUCK_PWM 3 /* 0x00000008 */ -#define RES4319_CLDO_PU 4 /* 0x00000010 */ -#define RES4319_PALDO_PU 5 /* 0x00000020 */ -#define RES4319_ILP_REQUEST 6 /* 0x00000040 */ -#define RES4319_LNLDO1_PU 9 /* 0x00000200 */ -#define RES4319_OTP_PU 10 /* 0x00000400 */ -#define RES4319_LNLDO2_PU 12 /* 0x00001000 */ -#define RES4319_XTAL_PU 13 /* 0x00002000 */ -#define RES4319_ALP_AVAIL 14 /* 0x00004000 */ -#define RES4319_RX_PWRSW_PU 15 /* 0x00008000 */ -#define RES4319_TX_PWRSW_PU 16 /* 0x00010000 */ -#define RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */ -#define RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */ -#define RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */ -#define RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */ -#define RES4319_HT_AVAIL 21 /* 0x00200000 */ - -/* 4319 chip-specific ChipStatus register bits */ -#define CST4319_SPI_CPULESSUSB 0x00000001 -#define CST4319_SPI_CLK_POL 0x00000002 -#define CST4319_SPI_CLK_PH 0x00000008 -#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 /* gpio [7:6], SDIO CIS selection */ -#define CST4319_SPROM_OTP_SEL_SHIFT 6 -#define CST4319_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ -#define CST4319_SPROM_SEL 0x00000040 /* use SPROM, OTP is powered up */ -#define CST4319_OTP_SEL 0x00000080 /* use OTP, OTP is powered up */ -#define CST4319_OTP_PWRDN 0x000000c0 /* use SPROM, OTP is powered down */ -#define CST4319_SDIO_USB_MODE 0x00000100 /* gpio [8], sdio/usb mode */ -#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 -#define CST4319_PALDO_EXTPNP 0x00010000 /* PALDO is configured with external PNP */ -#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 - -#define PMU1_PLL0_CHIPCTL0 0 -#define PMU1_PLL0_CHIPCTL1 1 -#define PMU1_PLL0_CHIPCTL2 2 -#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000 -#define CCTL_4319USB_XTAL_SEL_SHIFT 19 -#define CCTL_4319USB_48MHZ_PLL_SEL 1 -#define CCTL_4319USB_24MHZ_PLL_SEL 2 - -/* PMU resources for 4336 */ -#define RES4336_CBUCK_LPOM 0 -#define RES4336_CBUCK_BURST 1 -#define RES4336_CBUCK_LP_PWM 2 -#define RES4336_CBUCK_PWM 3 -#define RES4336_CLDO_PU 4 -#define RES4336_DIS_INT_RESET_PD 5 -#define RES4336_ILP_REQUEST 6 -#define RES4336_LNLDO_PU 7 -#define RES4336_LDO3P3_PU 8 -#define RES4336_OTP_PU 9 -#define RES4336_XTAL_PU 10 -#define RES4336_ALP_AVAIL 11 -#define RES4336_RADIO_PU 12 -#define RES4336_BG_PU 13 -#define RES4336_VREG1p4_PU_PU 14 -#define RES4336_AFE_PWRSW_PU 15 -#define RES4336_RX_PWRSW_PU 16 -#define RES4336_TX_PWRSW_PU 17 -#define RES4336_BB_PWRSW_PU 18 -#define RES4336_SYNTH_PWRSW_PU 19 -#define RES4336_MISC_PWRSW_PU 20 -#define RES4336_LOGEN_PWRSW_PU 21 -#define RES4336_BBPLL_PWRSW_PU 22 -#define RES4336_MACPHY_CLKAVAIL 23 -#define RES4336_HT_AVAIL 24 -#define RES4336_RSVD 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 - -/* 4336 Chip specific PMU ChipControl register bits */ -#define PCTL_4336_SERIAL_ENAB (1 << 24) - -/* 4330 resources */ -#define RES4330_CBUCK_LPOM 0 -#define RES4330_CBUCK_BURST 1 -#define RES4330_CBUCK_LP_PWM 2 -#define RES4330_CBUCK_PWM 3 -#define RES4330_CLDO_PU 4 -#define RES4330_DIS_INT_RESET_PD 5 -#define RES4330_ILP_REQUEST 6 -#define RES4330_LNLDO_PU 7 -#define RES4330_LDO3P3_PU 8 -#define RES4330_OTP_PU 9 -#define RES4330_XTAL_PU 10 -#define RES4330_ALP_AVAIL 11 -#define RES4330_RADIO_PU 12 -#define RES4330_BG_PU 13 -#define RES4330_VREG1p4_PU_PU 14 -#define RES4330_AFE_PWRSW_PU 15 -#define RES4330_RX_PWRSW_PU 16 -#define RES4330_TX_PWRSW_PU 17 -#define RES4330_BB_PWRSW_PU 18 -#define RES4330_SYNTH_PWRSW_PU 19 -#define RES4330_MISC_PWRSW_PU 20 -#define RES4330_LOGEN_PWRSW_PU 21 -#define RES4330_BBPLL_PWRSW_PU 22 -#define RES4330_MACPHY_CLKAVAIL 23 -#define RES4330_HT_AVAIL 24 -#define RES4330_5gRX_PWRSW_PU 25 -#define RES4330_5gTX_PWRSW_PU 26 -#define RES4330_5g_LOGEN_PWRSW_PU 27 - -/* 4330 chip-specific ChipStatus register bits */ -#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */ -#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */ -#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) /* SDIO */ -#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) /* gSPI */ -#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) /* USB packet-oriented */ -#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) /* USB Direct Access */ -#define CST4330_OTP_PRESENT 0x00000010 -#define CST4330_LPO_AUTODET_EN 0x00000020 -#define CST4330_ARMREMAP_0 0x00000040 -#define CST4330_SPROM_PRESENT 0x00000080 /* takes priority over OTP if both set */ -#define CST4330_ILPDIV_EN 0x00000100 -#define CST4330_LPO_SEL 0x00000200 -#define CST4330_RES_INIT_MODE_SHIFT 10 -#define CST4330_RES_INIT_MODE_MASK 0x00000c00 -#define CST4330_CBUCK_MODE_SHIFT 12 -#define CST4330_CBUCK_MODE_MASK 0x00003000 -#define CST4330_CBUCK_POWER_OK 0x00004000 -#define CST4330_BB_PLL_LOCKED 0x00008000 -#define SOCDEVRAM_BP_ADDR 0x1E000000 -#define SOCDEVRAM_ARM_ADDR 0x00800000 - -/* 4330 Chip specific PMU ChipControl register bits */ -#define PCTL_4330_SERIAL_ENAB (1 << 24) - -/* 4330 Chip specific ChipControl register bits */ -#define CCTRL_4330_GPIO_SEL 0x00000001 /* 1=select GPIOs to be muxed out */ -#define CCTRL_4330_ERCX_SEL 0x00000002 /* 1=select ERCX BT coex to be muxed out */ -#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004 /* SDIO: 1=configure GPIO0 for host wake */ -#define CCTRL_4330_JTAG_DISABLE 0x00000008 /* 1=disable JTAG interface on mux'd pins */ - -#define PMU_VREG0_ADDR 0 -#define PMU_VREG0_DISABLE_PULLD_BT_SHIFT 2 -#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 3 - -#define PMU_VREG4_ADDR 4 - -#define PMU_VREG4_CLDO_PWM_SHIFT 4 -#define PMU_VREG4_CLDO_PWM_MASK 0x7 - -#define PMU_VREG4_LPLDO1_SHIFT 15 -#define PMU_VREG4_LPLDO1_MASK 0x7 -#define PMU_VREG4_LPLDO1_1p20V 0 -#define PMU_VREG4_LPLDO1_1p15V 1 -#define PMU_VREG4_LPLDO1_1p10V 2 -#define PMU_VREG4_LPLDO1_1p25V 3 -#define PMU_VREG4_LPLDO1_1p05V 4 -#define PMU_VREG4_LPLDO1_1p00V 5 -#define PMU_VREG4_LPLDO1_0p95V 6 -#define PMU_VREG4_LPLDO1_0p90V 7 - -#define PMU_VREG4_LPLDO2_LVM_SHIFT 18 -#define PMU_VREG4_LPLDO2_LVM_MASK 0x7 -#define PMU_VREG4_LPLDO2_HVM_SHIFT 21 -#define PMU_VREG4_LPLDO2_HVM_MASK 0x7 -#define PMU_VREG4_LPLDO2_LVM_HVM_MASK 0x3f -#define PMU_VREG4_LPLDO2_1p00V 0 -#define PMU_VREG4_LPLDO2_1p15V 1 -#define PMU_VREG4_LPLDO2_1p20V 2 -#define PMU_VREG4_LPLDO2_1p10V 3 -#define PMU_VREG4_LPLDO2_0p90V 4 /* 4 - 7 is 0.90V */ - -#define PMU_VREG4_HSICLDO_BYPASS_SHIFT 27 -#define PMU_VREG4_HSICLDO_BYPASS_MASK 0x1 - -#define PMU_VREG5_ADDR 5 -#define PMU_VREG5_HSICAVDD_PD_SHIFT 6 -#define PMU_VREG5_HSICAVDD_PD_MASK 0x1 -#define PMU_VREG5_HSICDVDD_PD_SHIFT 11 -#define PMU_VREG5_HSICDVDD_PD_MASK 0x1 - -/* 4334 resources */ -#define RES4334_LPLDO_PU 0 -#define RES4334_RESET_PULLDN_DIS 1 -#define RES4334_PMU_BG_PU 2 -#define RES4334_HSIC_LDO_PU 3 -#define RES4334_CBUCK_LPOM_PU 4 -#define RES4334_CBUCK_PFM_PU 5 -#define RES4334_CLDO_PU 6 -#define RES4334_LPLDO2_LVM 7 -#define RES4334_LNLDO_PU 8 -#define RES4334_LDO3P3_PU 9 -#define RES4334_OTP_PU 10 -#define RES4334_XTAL_PU 11 -#define RES4334_WL_PWRSW_PU 12 -#define RES4334_LQ_AVAIL 13 -#define RES4334_LOGIC_RET 14 -#define RES4334_MEM_SLEEP 15 -#define RES4334_MACPHY_RET 16 -#define RES4334_WL_CORE_READY 17 -#define RES4334_ILP_REQ 18 -#define RES4334_ALP_AVAIL 19 -#define RES4334_MISC_PWRSW_PU 20 -#define RES4334_SYNTH_PWRSW_PU 21 -#define RES4334_RX_PWRSW_PU 22 -#define RES4334_RADIO_PU 23 -#define RES4334_WL_PMU_PU 24 -#define RES4334_VCO_LDO_PU 25 -#define RES4334_AFE_LDO_PU 26 -#define RES4334_RX_LDO_PU 27 -#define RES4334_TX_LDO_PU 28 -#define RES4334_HT_AVAIL 29 -#define RES4334_MACPHY_CLK_AVAIL 30 - -/* 4334 chip-specific ChipStatus register bits */ -#define CST4334_CHIPMODE_MASK 7 -#define CST4334_SDIO_MODE 0x00000000 -#define CST4334_SPI_MODE 0x00000004 -#define CST4334_HSIC_MODE 0x00000006 -#define CST4334_BLUSB_MODE 0x00000007 -#define CST4334_CHIPMODE_HSIC(cs) (((cs) & CST4334_CHIPMODE_MASK) == CST4334_HSIC_MODE) -#define CST4334_OTP_PRESENT 0x00000010 -#define CST4334_LPO_AUTODET_EN 0x00000020 -#define CST4334_ARMREMAP_0 0x00000040 -#define CST4334_SPROM_PRESENT 0x00000080 -#define CST4334_ILPDIV_EN_MASK 0x00000100 -#define CST4334_ILPDIV_EN_SHIFT 8 -#define CST4334_LPO_SEL_MASK 0x00000200 -#define CST4334_LPO_SEL_SHIFT 9 -#define CST4334_RES_INIT_MODE_MASK 0x00000C00 -#define CST4334_RES_INIT_MODE_SHIFT 10 - -/* 4334 Chip specific PMU ChipControl register bits */ -#define PCTL_4334_GPIO3_ENAB (1 << 3) - -/* 4334 Chip control */ -#define CCTRL4334_PMU_WAKEUP_GPIO1 (1 << 0) -#define CCTRL4334_PMU_WAKEUP_HSIC (1 << 1) -#define CCTRL4334_PMU_WAKEUP_AOS (1 << 2) -#define CCTRL4334_HSIC_WAKE_MODE (1 << 3) -#define CCTRL4334_HSIC_INBAND_GPIO1 (1 << 4) -#define CCTRL4334_HSIC_LDO_PU (1 << 23) - -/* 4334 Chip control 3 */ -#define CCTRL4334_BLOCK_EXTRNL_WAKE (1 << 4) -#define CCTRL4334_SAVERESTORE_FIX (1 << 5) - -/* 43341 Chip control 3 */ -#define CCTRL43341_BLOCK_EXTRNL_WAKE (1 << 13) -#define CCTRL43341_SAVERESTORE_FIX (1 << 14) -#define CCTRL43341_BT_ISO_SEL (1 << 16) - -/* 4334 Chip specific ChipControl1 register bits */ -#define CCTRL1_4334_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ -#define CCTRL1_4334_ERCX_SEL (1 << 1) /* 1=select ERCX BT coex to be muxed out */ -#define CCTRL1_4334_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ -#define CCTRL1_4334_JTAG_DISABLE (1 << 3) /* 1=disable JTAG interface on mux'd pins */ -#define CCTRL1_4334_UART_ON_4_5 (1 << 28) /* 1=UART_TX/UART_RX muxed on GPIO_4/5 (4334B0/1) */ - -/* 4324 Chip specific ChipControl1 register bits */ -#define CCTRL1_4324_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ -#define CCTRL1_4324_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ - -/* 43143 chip-specific ChipStatus register bits based on Confluence documentation */ -/* register contains strap values sampled during POR */ -#define CST43143_REMAP_TO_ROM (3 << 0) /* 00=Boot SRAM, 01=Boot ROM, 10=Boot SFLASH */ -#define CST43143_SDIO_EN (1 << 2) /* 0 = USB Enab, SDIO pins are GPIO or I2S */ -#define CST43143_SDIO_ISO (1 << 3) /* 1 = SDIO isolated */ -#define CST43143_USB_CPU_LESS (1 << 4) /* 1 = CPULess mode Enabled */ -#define CST43143_CBUCK_MODE (3 << 6) /* Indicates what controller mode CBUCK is in */ -#define CST43143_POK_CBUCK (1 << 8) /* 1 = 1.2V CBUCK voltage ready */ -#define CST43143_PMU_OVRSPIKE (1 << 9) -#define CST43143_PMU_OVRTEMP (0xF << 10) -#define CST43143_SR_FLL_CAL_DONE (1 << 14) -#define CST43143_USB_PLL_LOCKDET (1 << 15) -#define CST43143_PMU_PLL_LOCKDET (1 << 16) -#define CST43143_CHIPMODE_SDIOD(cs) (((cs) & CST43143_SDIO_EN) != 0) /* SDIO */ - -/* 43143 Chip specific ChipControl register bits */ -/* 00: SECI is disabled (JATG functional), 01: 2 wire, 10: 4 wire */ -#define CCTRL_43143_SECI (1<<0) -#define CCTRL_43143_BT_LEGACY (1<<1) -#define CCTRL_43143_I2S_MODE (1<<2) /* 0: SDIO enabled */ -#define CCTRL_43143_I2S_MASTER (1<<3) /* 0: I2S MCLK input disabled */ -#define CCTRL_43143_I2S_FULL (1<<4) /* 0: I2S SDIN and SPDIF_TX inputs disabled */ -#define CCTRL_43143_GSIO (1<<5) /* 0: sFlash enabled */ -#define CCTRL_43143_RF_SWCTRL_MASK (7<<6) /* 0: disabled */ -#define CCTRL_43143_RF_SWCTRL_0 (1<<6) -#define CCTRL_43143_RF_SWCTRL_1 (2<<6) -#define CCTRL_43143_RF_SWCTRL_2 (4<<6) -#define CCTRL_43143_RF_XSWCTRL (1<<9) /* 0: UART enabled */ -#define CCTRL_43143_HOST_WAKE0 (1<<11) /* 1: SDIO separate interrupt output from GPIO4 */ -#define CCTRL_43143_HOST_WAKE1 (1<<12) /* 1: SDIO separate interrupt output from GPIO16 */ - -/* 43143 resources, based on pmu_params.xls V1.19 */ -#define RES43143_EXT_SWITCHER_PWM 0 /* 0x00001 */ -#define RES43143_XTAL_PU 1 /* 0x00002 */ -#define RES43143_ILP_REQUEST 2 /* 0x00004 */ -#define RES43143_ALP_AVAIL 3 /* 0x00008 */ -#define RES43143_WL_CORE_READY 4 /* 0x00010 */ -#define RES43143_BBPLL_PWRSW_PU 5 /* 0x00020 */ -#define RES43143_HT_AVAIL 6 /* 0x00040 */ -#define RES43143_RADIO_PU 7 /* 0x00080 */ -#define RES43143_MACPHY_CLK_AVAIL 8 /* 0x00100 */ -#define RES43143_OTP_PU 9 /* 0x00200 */ -#define RES43143_LQ_AVAIL 10 /* 0x00400 */ - -#define PMU43143_XTAL_CORE_SIZE_MASK 0x3F - -/* 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 - -/* 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 */ -#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */ - -/* PMU respources for 4314 */ -#define RES4314_LPLDO_PU 0 -#define RES4314_PMU_SLEEP_DIS 1 -#define RES4314_PMU_BG_PU 2 -#define RES4314_CBUCK_LPOM_PU 3 -#define RES4314_CBUCK_PFM_PU 4 -#define RES4314_CLDO_PU 5 -#define RES4314_LPLDO2_LVM 6 -#define RES4314_WL_PMU_PU 7 -#define RES4314_LNLDO_PU 8 -#define RES4314_LDO3P3_PU 9 -#define RES4314_OTP_PU 10 -#define RES4314_XTAL_PU 11 -#define RES4314_WL_PWRSW_PU 12 -#define RES4314_LQ_AVAIL 13 -#define RES4314_LOGIC_RET 14 -#define RES4314_MEM_SLEEP 15 -#define RES4314_MACPHY_RET 16 -#define RES4314_WL_CORE_READY 17 -#define RES4314_ILP_REQ 18 -#define RES4314_ALP_AVAIL 19 -#define RES4314_MISC_PWRSW_PU 20 -#define RES4314_SYNTH_PWRSW_PU 21 -#define RES4314_RX_PWRSW_PU 22 -#define RES4314_RADIO_PU 23 -#define RES4314_VCO_LDO_PU 24 -#define RES4314_AFE_LDO_PU 25 -#define RES4314_RX_LDO_PU 26 -#define RES4314_TX_LDO_PU 27 -#define RES4314_HT_AVAIL 28 -#define RES4314_MACPHY_CLK_AVAIL 29 - -/* 4314 chip-specific ChipStatus register bits */ -#define CST4314_OTP_ENABLED 0x00200000 - -/* 43228 resources */ -#define RES43228_NOT_USED 0 -#define RES43228_ILP_REQUEST 1 -#define RES43228_XTAL_PU 2 -#define RES43228_ALP_AVAIL 3 -#define RES43228_PLL_EN 4 -#define RES43228_HT_PHY_AVAIL 5 - -/* 43228 chipstatus reg bits */ -#define CST43228_ILP_DIV_EN 0x1 -#define CST43228_OTP_PRESENT 0x2 -#define CST43228_SERDES_REFCLK_PADSEL 0x4 -#define CST43228_SDIO_MODE 0x8 -#define CST43228_SDIO_OTP_PRESENT 0x10 -#define CST43228_SDIO_RESET 0x20 - -/* 4706 chipstatus reg bits */ -#define CST4706_PKG_OPTION (1<<0) /* 0: full-featured package 1: low-cost package */ -#define CST4706_SFLASH_PRESENT (1<<1) /* 0: parallel, 1: serial flash is present */ -#define CST4706_SFLASH_TYPE (1<<2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */ -#define CST4706_MIPS_BENDIAN (1<<3) /* 0: little, 1: big endian */ -#define CST4706_PCIE1_DISABLE (1<<5) /* PCIE1 enable strap pin */ - -/* 4706 flashstrconfig reg bits */ -#define FLSTRCF4706_MASK 0x000000ff -#define FLSTRCF4706_SF1 0x00000001 /* 2nd serial flash present */ -#define FLSTRCF4706_PF1 0x00000002 /* 2nd parallel flash present */ -#define FLSTRCF4706_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */ -#define FLSTRCF4706_NF1 0x00000008 /* 2nd NAND flash present */ -#define FLSTRCF4706_1ST_MADDR_SEG_MASK 0x000000f0 /* Valid value mask */ -#define FLSTRCF4706_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */ -#define FLSTRCF4706_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */ - -/* 4360 Chip specific ChipControl register bits */ -#define CCTRL4360_I2C_MODE (1 << 0) -#define CCTRL4360_UART_MODE (1 << 1) -#define CCTRL4360_SECI_MODE (1 << 2) -#define CCTRL4360_BTSWCTRL_MODE (1 << 3) -#define CCTRL4360_DISCRETE_FEMCTRL_MODE (1 << 4) -#define CCTRL4360_DIGITAL_PACTRL_MODE (1 << 5) -#define CCTRL4360_BTSWCTRL_AND_DIGPA_PRESENT (1 << 6) -#define CCTRL4360_EXTRA_GPIO_MODE (1 << 7) -#define CCTRL4360_EXTRA_FEMCTRL_MODE (1 << 8) -#define CCTRL4360_BT_LGCY_MODE (1 << 9) -#define CCTRL4360_CORE2FEMCTRL4_ON (1 << 21) -#define CCTRL4360_SECI_ON_GPIO01 (1 << 24) - -/* 4360 Chip specific Regulator Control register bits */ -#define RCTRL4360_RFLDO_PWR_DOWN (1 << 1) - -/* 4360 PMU resources and chip status bits */ -#define RES4360_REGULATOR 0 -#define RES4360_ILP_AVAIL 1 -#define RES4360_ILP_REQ 2 -#define RES4360_XTAL_LDO_PU 3 -#define RES4360_XTAL_PU 4 -#define RES4360_ALP_AVAIL 5 -#define RES4360_BBPLLPWRSW_PU 6 -#define RES4360_HT_AVAIL 7 -#define RES4360_OTP_PU 8 - -#define CST4360_XTAL_40MZ 0x00000001 -#define CST4360_SFLASH 0x00000002 -#define CST4360_SPROM_PRESENT 0x00000004 -#define CST4360_SFLASH_TYPE 0x00000004 -#define CST4360_OTP_ENABLED 0x00000008 -#define CST4360_REMAP_ROM 0x00000010 -#define CST4360_RSRC_INIT_MODE_MASK 0x00000060 -#define CST4360_RSRC_INIT_MODE_SHIFT 5 -#define CST4360_ILP_DIVEN 0x00000080 -#define CST4360_MODE_USB 0x00000100 -#define CST4360_SPROM_SIZE_MASK 0x00000600 -#define CST4360_SPROM_SIZE_SHIFT 9 -#define CST4360_BBPLL_LOCK 0x00000800 -#define CST4360_AVBBPLL_LOCK 0x00001000 -#define CST4360_USBBBPLL_LOCK 0x00002000 -#define CST4360_RSRC_INIT_MODE(cs) ((cs & CST4360_RSRC_INIT_MODE_MASK) >> \ - CST4360_RSRC_INIT_MODE_SHIFT) - -#define CCTRL_4360_UART_SEL 0x2 - - -/* 43602 PMU resources based on pmu_params.xls version v0.95 */ -#define RES43602_LPLDO_PU 0 -#define RES43602_REGULATOR 1 -#define RES43602_PMU_SLEEP 2 -#define RES43602_RSVD_3 3 -#define RES43602_XTALLDO_PU 4 -#define RES43602_SERDES_PU 5 -#define RES43602_BBPLL_PWRSW_PU 6 -#define RES43602_SR_CLK_START 7 -#define RES43602_SR_PHY_PWRSW 8 -#define RES43602_SR_SUBCORE_PWRSW 9 -#define RES43602_XTAL_PU 10 -#define RES43602_PERST_OVR 11 -#define RES43602_SR_CLK_STABLE 12 -#define RES43602_SR_SAVE_RESTORE 13 -#define RES43602_SR_SLEEP 14 -#define RES43602_LQ_START 15 -#define RES43602_LQ_AVAIL 16 -#define RES43602_WL_CORE_RDY 17 -#define RES43602_ILP_REQ 18 -#define RES43602_ALP_AVAIL 19 -#define RES43602_RADIO_PU 20 -#define RES43602_RFLDO_PU 21 -#define RES43602_HT_START 22 -#define RES43602_HT_AVAIL 23 -#define RES43602_MACPHY_CLKAVAIL 24 -#define RES43602_PARLDO_PU 25 -#define RES43602_RSVD_26 26 - -/* 43602 chip status bits */ -#define CST43602_SPROM_PRESENT (1<<1) -#define CST43602_SPROM_SIZE (1<<10) /* 0 = 16K, 1 = 4K */ -#define CST43602_BBPLL_LOCK (1<<11) -#define CST43602_RF_LDO_OUT_OK (1<<15) /* RF LDO output OK */ - -#define PMU43602_CC2_FORCE_EXT_LPO (1 << 19) /* 1=ext LPO clock is the final LPO clock */ -#define PMU43602_CC2_XTAL32_SEL (1 << 30) /* 0=ext_clock, 1=xtal */ - -#define CC_SR1_43602_SR_ASM_ADDR (0x0) - -/* PLL CTL register values for open loop, used during S/R operation */ -#define PMU43602_PLL_CTL6_VAL 0x68000528 -#define PMU43602_PLL_CTL7_VAL 0x6 - -#define PMU43602_CC3_ARMCR4_DBG_CLK (1 << 29) - - -/* 43430 PMU resources based on pmu_params.xls */ -#define RES43430_LPLDO_PU 0 -#define RES43430_BG_PU 1 -#define RES43430_PMU_SLEEP 2 -#define RES43430_RSVD_3 3 -#define RES43430_CBUCK_LPOM_PU 4 -#define RES43430_CBUCK_PFM_PU 5 -#define RES43430_COLD_START_WAIT 6 -#define RES43430_RSVD_7 7 -#define RES43430_LNLDO_PU 8 -#define RES43430_RSVD_9 9 -#define RES43430_LDO3P3_PU 10 -#define RES43430_OTP_PU 11 -#define RES43430_XTAL_PU 12 -#define RES43430_SR_CLK_START 13 -#define RES43430_LQ_AVAIL 14 -#define RES43430_LQ_START 15 -#define RES43430_RSVD_16 16 -#define RES43430_WL_CORE_RDY 17 -#define RES43430_ILP_REQ 18 -#define RES43430_ALP_AVAIL 19 -#define RES43430_MINI_PMU 20 -#define RES43430_RADIO_PU 21 -#define RES43430_SR_CLK_STABLE 22 -#define RES43430_SR_SAVE_RESTORE 23 -#define RES43430_SR_PHY_PWRSW 24 -#define RES43430_SR_VDDM_PWRSW 25 -#define RES43430_SR_SUBCORE_PWRSW 26 -#define RES43430_SR_SLEEP 27 -#define RES43430_HT_START 28 -#define RES43430_HT_AVAIL 29 -#define RES43430_MACPHY_CLK_AVAIL 30 - -/* 43430 chip status bits */ -#define CST43430_SDIO_MODE 0x00000001 -#define CST43430_GSPI_MODE 0x00000002 -#define CST43430_RSRC_INIT_MODE_0 0x00000080 -#define CST43430_RSRC_INIT_MODE_1 0x00000100 -#define CST43430_SEL0_SDIO 0x00000200 -#define CST43430_SEL1_SDIO 0x00000400 -#define CST43430_SEL2_SDIO 0x00000800 -#define CST43430_BBPLL_LOCKED 0x00001000 -#define CST43430_DBG_INST_DETECT 0x00004000 -#define CST43430_CLB2WL_BT_READY 0x00020000 -#define CST43430_JTAG_MODE 0x00100000 -#define CST43430_HOST_IFACE 0x00400000 -#define CST43430_TRIM_EN 0x00800000 -#define CST43430_DIN_PACKAGE_OPTION 0x10000000 - -/* defines to detect active host interface in use */ -#define CHIP_HOSTIF_PCIEMODE 0x1 -#define CHIP_HOSTIF_USBMODE 0x2 -#define CHIP_HOSTIF_SDIOMODE 0x4 -#define CHIP_HOSTIF_PCIE(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_PCIEMODE) -#define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_USBMODE) -#define CHIP_HOSTIF_SDIO(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_SDIOMODE) - -/* 4335 resources */ -#define RES4335_LPLDO_PO 0 -#define RES4335_PMU_BG_PU 1 -#define RES4335_PMU_SLEEP 2 -#define RES4335_RSVD_3 3 -#define RES4335_CBUCK_LPOM_PU 4 -#define RES4335_CBUCK_PFM_PU 5 -#define RES4335_RSVD_6 6 -#define RES4335_RSVD_7 7 -#define RES4335_LNLDO_PU 8 -#define RES4335_XTALLDO_PU 9 -#define RES4335_LDO3P3_PU 10 -#define RES4335_OTP_PU 11 -#define RES4335_XTAL_PU 12 -#define RES4335_SR_CLK_START 13 -#define RES4335_LQ_AVAIL 14 -#define RES4335_LQ_START 15 -#define RES4335_RSVD_16 16 -#define RES4335_WL_CORE_RDY 17 -#define RES4335_ILP_REQ 18 -#define RES4335_ALP_AVAIL 19 -#define RES4335_MINI_PMU 20 -#define RES4335_RADIO_PU 21 -#define RES4335_SR_CLK_STABLE 22 -#define RES4335_SR_SAVE_RESTORE 23 -#define RES4335_SR_PHY_PWRSW 24 -#define RES4335_SR_VDDM_PWRSW 25 -#define RES4335_SR_SUBCORE_PWRSW 26 -#define RES4335_SR_SLEEP 27 -#define RES4335_HT_START 28 -#define RES4335_HT_AVAIL 29 -#define RES4335_MACPHY_CLKAVAIL 30 - -/* 4335 Chip specific ChipStatus register bits */ -#define CST4335_SPROM_MASK 0x00000020 -#define CST4335_SFLASH_MASK 0x00000040 -#define CST4335_RES_INIT_MODE_SHIFT 7 -#define CST4335_RES_INIT_MODE_MASK 0x00000180 -#define CST4335_CHIPMODE_MASK 0xF -#define CST4335_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ -#define CST4335_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ -#define CST4335_CHIPMODE_USB20D(cs) (((cs) & (1 << 2)) != 0) /* HSIC || USBDA */ -#define CST4335_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ - -/* 4335 Chip specific ChipControl1 register bits */ -#define CCTRL1_4335_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ -#define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ - -#define PATCHTBL_SIZE (0x800) -#define CR4_4335_RAM_BASE (0x180000) -#define CR4_4345_LT_C0_RAM_BASE (0x1b0000) -#define CR4_4345_GE_C0_RAM_BASE (0x198000) -#define CR4_4349_RAM_BASE (0x180000) -#define CR4_4350_RAM_BASE (0x180000) -#define CR4_4360_RAM_BASE (0x0) -#define CR4_43602_RAM_BASE (0x180000) - -/* 4335 chip OTP present & OTP select bits. */ -#define SPROM4335_OTP_SELECT 0x00000010 -#define SPROM4335_OTP_PRESENT 0x00000020 - -/* 4335 GCI specific bits. */ -#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) -#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 -#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 - -/* SFLASH clkdev specific bits. */ -#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 -#define CC4335_SFLASH_CLKDIV_SHIFT 25 - -/* 4335 OTP bits for SFLASH. */ -#define CC4335_SROM_OTP_SFLASH 40 -#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 -#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 -#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C -#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 - - -/* 4335 chip OTP present & OTP select bits. */ -#define SPROM4335_OTP_SELECT 0x00000010 -#define SPROM4335_OTP_PRESENT 0x00000020 - -/* 4335 GCI specific bits. */ -#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) -#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 -#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 - -/* SFLASH clkdev specific bits. */ -#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 -#define CC4335_SFLASH_CLKDIV_SHIFT 25 - -/* 4335 OTP bits for SFLASH. */ -#define CC4335_SROM_OTP_SFLASH 40 -#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 -#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 -#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C -#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 - -/* 4335 resources--END */ - -/* 4345 Chip specific ChipStatus register bits */ -#define CST4345_SPROM_MASK 0x00000020 -#define CST4345_SFLASH_MASK 0x00000040 -#define CST4345_RES_INIT_MODE_SHIFT 7 -#define CST4345_RES_INIT_MODE_MASK 0x00000180 -#define CST4345_CHIPMODE_MASK 0x4000F -#define CST4345_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ -#define CST4345_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ -#define CST4345_CHIPMODE_HSIC(cs) (((cs) & (1 << 2)) != 0) /* HSIC */ -#define CST4345_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ -#define CST4345_CHIPMODE_USB20D(cs) (((cs) & (1 << 18)) != 0) /* USBDA */ - -/* 4350 Chipcommon ChipStatus bits */ -#define CST4350_SDIO_MODE 0x00000001 -#define CST4350_HSIC20D_MODE 0x00000002 -#define CST4350_BP_ON_HSIC_CLK 0x00000004 -#define CST4350_PCIE_MODE 0x00000008 -#define CST4350_USB20D_MODE 0x00000010 -#define CST4350_USB30D_MODE 0x00000020 -#define CST4350_SPROM_PRESENT 0x00000040 -#define CST4350_RSRC_INIT_MODE_0 0x00000080 -#define CST4350_RSRC_INIT_MODE_1 0x00000100 -#define CST4350_SEL0_SDIO 0x00000200 -#define CST4350_SEL1_SDIO 0x00000400 -#define CST4350_SDIO_PAD_MODE 0x00000800 -#define CST4350_BBPLL_LOCKED 0x00001000 -#define CST4350_USBPLL_LOCKED 0x00002000 -#define CST4350_LINE_STATE 0x0000C000 -#define CST4350_SERDES_PIPE_PLLLOCK 0x00010000 -#define CST4350_BT_READY 0x00020000 -#define CST4350_SFLASH_PRESENT 0x00040000 -#define CST4350_CPULESS_ENABLE 0x00080000 -#define CST4350_STRAP_HOST_IFC_1 0x00100000 -#define CST4350_STRAP_HOST_IFC_2 0x00200000 -#define CST4350_STRAP_HOST_IFC_3 0x00400000 -#define CST4350_RAW_SPROM_PRESENT 0x00800000 -#define CST4350_APP_CLK_SWITCH_SEL_RDBACK 0x01000000 -#define CST4350_RAW_RSRC_INIT_MODE_0 0x02000000 -#define CST4350_SDIO_PAD_VDDIO 0x04000000 -#define CST4350_GSPI_MODE 0x08000000 -#define CST4350_PACKAGE_OPTION 0xF0000000 -#define CST4350_PACKAGE_SHIFT 28 - -/* package option for 4350 */ -#define CST4350_PACKAGE_WLCSP 0x0 -#define CST4350_PACKAGE_PCIE 0x1 -#define CST4350_PACKAGE_WLBGA 0x2 -#define CST4350_PACKAGE_DBG 0x3 -#define CST4350_PACKAGE_USB 0x4 -#define CST4350_PACKAGE_USB_HSIC 0x4 - -#define CST4350_PKG_MODE(cs) ((cs & CST4350_PACKAGE_OPTION) >> CST4350_PACKAGE_SHIFT) - -#define CST4350_PKG_WLCSP(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLCSP)) -#define CST4350_PKG_PCIE(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_PCIE)) -#define CST4350_PKG_WLBGA(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLBGA)) -#define CST4350_PKG_USB(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB)) -#define CST4350_PKG_USB_HSIC(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB_HSIC)) - -/* 4350C0 USB PACKAGE using raw_sprom_present to indicate 40mHz xtal */ -#define CST4350_PKG_USB_40M(cs) (cs & CST4350_RAW_SPROM_PRESENT) - -#define CST4350_CHIPMODE_SDIOD(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_SDIOD)) -#define CST4350_CHIPMODE_USB20D(cs) ((CST4350_IFC_MODE(cs)) == (CST4350_IFC_MODE_USB20D)) -#define CST4350_CHIPMODE_HSIC20D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC20D)) -#define CST4350_CHIPMODE_HSIC30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC30D)) -#define CST4350_CHIPMODE_USB30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D)) -#define CST4350_CHIPMODE_USB30D_WL(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D_WL)) -#define CST4350_CHIPMODE_PCIE(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_PCIE)) - -/* strap_host_ifc strap value */ -#define CST4350_HOST_IFC_MASK 0x00700000 -#define CST4350_HOST_IFC_SHIFT 20 - -/* host_ifc raw mode */ -#define CST4350_IFC_MODE_SDIOD 0x0 -#define CST4350_IFC_MODE_HSIC20D 0x1 -#define CST4350_IFC_MODE_HSIC30D 0x2 -#define CST4350_IFC_MODE_PCIE 0x3 -#define CST4350_IFC_MODE_USB20D 0x4 -#define CST4350_IFC_MODE_USB30D 0x5 -#define CST4350_IFC_MODE_USB30D_WL 0x6 -#define CST4350_IFC_MODE_USB30D_BT 0x7 - -#define CST4350_IFC_MODE(cs) ((cs & CST4350_HOST_IFC_MASK) >> CST4350_HOST_IFC_SHIFT) - -#define CST4350_CHIPMODE_SDIOD(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_SDIOD)) -#define CST4350_CHIPMODE_USB20D(cs) ((CST4350_IFC_MODE(cs)) == (CST4350_IFC_MODE_USB20D)) -#define CST4350_CHIPMODE_HSIC20D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC20D)) -#define CST4350_CHIPMODE_HSIC30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC30D)) -#define CST4350_CHIPMODE_USB30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D)) -#define CST4350_CHIPMODE_USB30D_WL(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D_WL)) -#define CST4350_CHIPMODE_PCIE(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_PCIE)) - -/* 4350 PMU resources */ -#define RES4350_LPLDO_PU 0 -#define RES4350_PMU_BG_PU 1 -#define RES4350_PMU_SLEEP 2 -#define RES4350_RSVD_3 3 -#define RES4350_CBUCK_LPOM_PU 4 -#define RES4350_CBUCK_PFM_PU 5 -#define RES4350_COLD_START_WAIT 6 -#define RES4350_RSVD_7 7 -#define RES4350_LNLDO_PU 8 -#define RES4350_XTALLDO_PU 9 -#define RES4350_LDO3P3_PU 10 -#define RES4350_OTP_PU 11 -#define RES4350_XTAL_PU 12 -#define RES4350_SR_CLK_START 13 -#define RES4350_LQ_AVAIL 14 -#define RES4350_LQ_START 15 -#define RES4350_RSVD_16 16 -#define RES4350_WL_CORE_RDY 17 -#define RES4350_ILP_REQ 18 -#define RES4350_ALP_AVAIL 19 -#define RES4350_MINI_PMU 20 -#define RES4350_RADIO_PU 21 -#define RES4350_SR_CLK_STABLE 22 -#define RES4350_SR_SAVE_RESTORE 23 -#define RES4350_SR_PHY_PWRSW 24 -#define RES4350_SR_VDDM_PWRSW 25 -#define RES4350_SR_SUBCORE_PWRSW 26 -#define RES4350_SR_SLEEP 27 -#define RES4350_HT_START 28 -#define RES4350_HT_AVAIL 29 -#define RES4350_MACPHY_CLKAVAIL 30 - -#define MUXENAB4350_UART_MASK (0x0000000f) -#define MUXENAB4350_UART_SHIFT 0 -#define MUXENAB4350_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ -#define MUXENAB4350_HOSTWAKE_SHIFT 4 - - -/* 4350 GCI function sel values */ -#define CC4350_FNSEL_HWDEF (0) -#define CC4350_FNSEL_SAMEASPIN (1) -#define CC4350_FNSEL_UART (2) -#define CC4350_FNSEL_SFLASH (3) -#define CC4350_FNSEL_SPROM (4) -#define CC4350_FNSEL_I2C (5) -#define CC4350_FNSEL_MISC0 (6) -#define CC4350_FNSEL_GCI (7) -#define CC4350_FNSEL_MISC1 (8) -#define CC4350_FNSEL_MISC2 (9) -#define CC4350_FNSEL_PWDOG (10) -#define CC4350_FNSEL_IND (12) -#define CC4350_FNSEL_PDN (13) -#define CC4350_FNSEL_PUP (14) -#define CC4350_FNSEL_TRISTATE (15) -#define CC4350C_FNSEL_UART (3) - - -/* 4350 GPIO */ -#define CC4350_PIN_GPIO_00 (0) -#define CC4350_PIN_GPIO_01 (1) -#define CC4350_PIN_GPIO_02 (2) -#define CC4350_PIN_GPIO_03 (3) -#define CC4350_PIN_GPIO_04 (4) -#define CC4350_PIN_GPIO_05 (5) -#define CC4350_PIN_GPIO_06 (6) -#define CC4350_PIN_GPIO_07 (7) -#define CC4350_PIN_GPIO_08 (8) -#define CC4350_PIN_GPIO_09 (9) -#define CC4350_PIN_GPIO_10 (10) -#define CC4350_PIN_GPIO_11 (11) -#define CC4350_PIN_GPIO_12 (12) -#define CC4350_PIN_GPIO_13 (13) -#define CC4350_PIN_GPIO_14 (14) -#define CC4350_PIN_GPIO_15 (15) - -#define CC2_4350_PHY_PWRSW_UPTIME_MASK (0xf << 0) -#define CC2_4350_PHY_PWRSW_UPTIME_SHIFT (0) -#define CC2_4350_VDDM_PWRSW_UPDELAY_MASK (0xf << 4) -#define CC2_4350_VDDM_PWRSW_UPDELAY_SHIFT (4) -#define CC2_4350_VDDM_PWRSW_UPTIME_MASK (0xf << 8) -#define CC2_4350_VDDM_PWRSW_UPTIME_SHIFT (8) -#define CC2_4350_SBC_PWRSW_DNDELAY_MASK (0x3 << 12) -#define CC2_4350_SBC_PWRSW_DNDELAY_SHIFT (12) -#define CC2_4350_PHY_PWRSW_DNDELAY_MASK (0x3 << 14) -#define CC2_4350_PHY_PWRSW_DNDELAY_SHIFT (14) -#define CC2_4350_VDDM_PWRSW_DNDELAY_MASK (0x3 << 16) -#define CC2_4350_VDDM_PWRSW_DNDELAY_SHIFT (16) -#define CC2_4350_VDDM_PWRSW_EN_MASK (1 << 20) -#define CC2_4350_VDDM_PWRSW_EN_SHIFT (20) -#define CC2_4350_MEMLPLDO_PWRSW_EN_MASK (1 << 21) -#define CC2_4350_MEMLPLDO_PWRSW_EN_SHIFT (21) -#define CC2_4350_SDIO_AOS_WAKEUP_MASK (1 << 24) -#define CC2_4350_SDIO_AOS_WAKEUP_SHIFT (24) - -/* Applies to 4335/4350/4345 */ -#define CC3_SR_CLK_SR_MEM_MASK (1 << 0) -#define CC3_SR_CLK_SR_MEM_SHIFT (0) -#define CC3_SR_BIT1_TBD_MASK (1 << 1) -#define CC3_SR_BIT1_TBD_SHIFT (1) -#define CC3_SR_ENGINE_ENABLE_MASK (1 << 2) -#define CC3_SR_ENGINE_ENABLE_SHIFT (2) -#define CC3_SR_BIT3_TBD_MASK (1 << 3) -#define CC3_SR_BIT3_TBD_SHIFT (3) -#define CC3_SR_MINDIV_FAST_CLK_MASK (0xF << 4) -#define CC3_SR_MINDIV_FAST_CLK_SHIFT (4) -#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_MASK (1 << 8) -#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_SHIFT (8) -#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_MASK (1 << 9) -#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_SHIFT (9) -#define CC3_SR_R23_SR_RISE_EDGE_TRIG_MASK (1 << 10) -#define CC3_SR_R23_SR_RISE_EDGE_TRIG_SHIFT (10) -#define CC3_SR_R23_SR_FALL_EDGE_TRIG_MASK (1 << 11) -#define CC3_SR_R23_SR_FALL_EDGE_TRIG_SHIFT (11) -#define CC3_SR_NUM_CLK_HIGH_MASK (0x7 << 12) -#define CC3_SR_NUM_CLK_HIGH_SHIFT (12) -#define CC3_SR_BIT15_TBD_MASK (1 << 15) -#define CC3_SR_BIT15_TBD_SHIFT (15) -#define CC3_SR_PHY_FUNC_PIC_MASK (1 << 16) -#define CC3_SR_PHY_FUNC_PIC_SHIFT (16) -#define CC3_SR_BIT17_19_TBD_MASK (0x7 << 17) -#define CC3_SR_BIT17_19_TBD_SHIFT (17) -#define CC3_SR_CHIP_TRIGGER_1_MASK (1 << 20) -#define CC3_SR_CHIP_TRIGGER_1_SHIFT (20) -#define CC3_SR_CHIP_TRIGGER_2_MASK (1 << 21) -#define CC3_SR_CHIP_TRIGGER_2_SHIFT (21) -#define CC3_SR_CHIP_TRIGGER_3_MASK (1 << 22) -#define CC3_SR_CHIP_TRIGGER_3_SHIFT (22) -#define CC3_SR_CHIP_TRIGGER_4_MASK (1 << 23) -#define CC3_SR_CHIP_TRIGGER_4_SHIFT (23) -#define CC3_SR_ALLOW_SBC_FUNC_PIC_MASK (1 << 24) -#define CC3_SR_ALLOW_SBC_FUNC_PIC_SHIFT (24) -#define CC3_SR_BIT25_26_TBD_MASK (0x3 << 25) -#define CC3_SR_BIT25_26_TBD_SHIFT (25) -#define CC3_SR_ALLOW_SBC_STBY_MASK (1 << 27) -#define CC3_SR_ALLOW_SBC_STBY_SHIFT (27) -#define CC3_SR_GPIO_MUX_MASK (0xF << 28) -#define CC3_SR_GPIO_MUX_SHIFT (28) - -/* Applies to 4335/4350/4345 */ -#define CC4_SR_INIT_ADDR_MASK (0x3FF0000) -#define CC4_4350_SR_ASM_ADDR (0x30) -#define CC4_4335_SR_ASM_ADDR (0x48) -#define CC4_4345_SR_ASM_ADDR (0x48) -#define CC4_SR_INIT_ADDR_SHIFT (16) - -#define CC4_4350_EN_SR_CLK_ALP_MASK (1 << 30) -#define CC4_4350_EN_SR_CLK_ALP_SHIFT (30) -#define CC4_4350_EN_SR_CLK_HT_MASK (1 << 31) -#define CC4_4350_EN_SR_CLK_HT_SHIFT (31) - -#define VREG4_4350_MEMLPDO_PU_MASK (1 << 31) -#define VREG4_4350_MEMLPDO_PU_SHIFT 31 - -#define CC6_4350_PCIE_CLKREQ_WAKEUP_MASK (1 << 4) -#define CC6_4350_PCIE_CLKREQ_WAKEUP_SHIFT (4) -#define CC6_4350_PMU_WAKEUP_ALPAVAIL_MASK (1 << 6) -#define CC6_4350_PMU_WAKEUP_ALPAVAIL_SHIFT (6) - -/* GCI chipcontrol register indices */ -#define CC_GCI_CHIPCTRL_00 (0) -#define CC_GCI_CHIPCTRL_01 (1) -#define CC_GCI_CHIPCTRL_02 (2) -#define CC_GCI_CHIPCTRL_03 (3) -#define CC_GCI_CHIPCTRL_04 (4) -#define CC_GCI_CHIPCTRL_05 (5) -#define CC_GCI_CHIPCTRL_06 (6) -#define CC_GCI_CHIPCTRL_07 (7) -#define CC_GCI_CHIPCTRL_08 (8) -#define CC_GCI_XTAL_BUFSTRG_NFC (0xff << 12) - -#define CC_GCI_06_JTAG_SEL_SHIFT 4 -#define CC_GCI_06_JTAG_SEL_MASK (1 << 4) - -#define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) - -/* 4345 PMU resources */ -#define RES4345_LPLDO_PU 0 -#define RES4345_PMU_BG_PU 1 -#define RES4345_PMU_SLEEP 2 -#define RES4345_HSICLDO_PU 3 -#define RES4345_CBUCK_LPOM_PU 4 -#define RES4345_CBUCK_PFM_PU 5 -#define RES4345_COLD_START_WAIT 6 -#define RES4345_RSVD_7 7 -#define RES4345_LNLDO_PU 8 -#define RES4345_XTALLDO_PU 9 -#define RES4345_LDO3P3_PU 10 -#define RES4345_OTP_PU 11 -#define RES4345_XTAL_PU 12 -#define RES4345_SR_CLK_START 13 -#define RES4345_LQ_AVAIL 14 -#define RES4345_LQ_START 15 -#define RES4345_PERST_OVR 16 -#define RES4345_WL_CORE_RDY 17 -#define RES4345_ILP_REQ 18 -#define RES4345_ALP_AVAIL 19 -#define RES4345_MINI_PMU 20 -#define RES4345_RADIO_PU 21 -#define RES4345_SR_CLK_STABLE 22 -#define RES4345_SR_SAVE_RESTORE 23 -#define RES4345_SR_PHY_PWRSW 24 -#define RES4345_SR_VDDM_PWRSW 25 -#define RES4345_SR_SUBCORE_PWRSW 26 -#define RES4345_SR_SLEEP 27 -#define RES4345_HT_START 28 -#define RES4345_HT_AVAIL 29 -#define RES4345_MACPHY_CLK_AVAIL 30 - -/* 4335 pins -* note: only the values set as default/used are added here. -*/ -#define CC4335_PIN_GPIO_00 (0) -#define CC4335_PIN_GPIO_01 (1) -#define CC4335_PIN_GPIO_02 (2) -#define CC4335_PIN_GPIO_03 (3) -#define CC4335_PIN_GPIO_04 (4) -#define CC4335_PIN_GPIO_05 (5) -#define CC4335_PIN_GPIO_06 (6) -#define CC4335_PIN_GPIO_07 (7) -#define CC4335_PIN_GPIO_08 (8) -#define CC4335_PIN_GPIO_09 (9) -#define CC4335_PIN_GPIO_10 (10) -#define CC4335_PIN_GPIO_11 (11) -#define CC4335_PIN_GPIO_12 (12) -#define CC4335_PIN_GPIO_13 (13) -#define CC4335_PIN_GPIO_14 (14) -#define CC4335_PIN_GPIO_15 (15) -#define CC4335_PIN_SDIO_CLK (16) -#define CC4335_PIN_SDIO_CMD (17) -#define CC4335_PIN_SDIO_DATA0 (18) -#define CC4335_PIN_SDIO_DATA1 (19) -#define CC4335_PIN_SDIO_DATA2 (20) -#define CC4335_PIN_SDIO_DATA3 (21) -#define CC4335_PIN_RF_SW_CTRL_6 (22) -#define CC4335_PIN_RF_SW_CTRL_7 (23) -#define CC4335_PIN_RF_SW_CTRL_8 (24) -#define CC4335_PIN_RF_SW_CTRL_9 (25) - -/* 4335 GCI function sel values -*/ -#define CC4335_FNSEL_HWDEF (0) -#define CC4335_FNSEL_SAMEASPIN (1) -#define CC4335_FNSEL_GPIO0 (2) -#define CC4335_FNSEL_GPIO1 (3) -#define CC4335_FNSEL_GCI0 (4) -#define CC4335_FNSEL_GCI1 (5) -#define CC4335_FNSEL_UART (6) -#define CC4335_FNSEL_SFLASH (7) -#define CC4335_FNSEL_SPROM (8) -#define CC4335_FNSEL_MISC0 (9) -#define CC4335_FNSEL_MISC1 (10) -#define CC4335_FNSEL_MISC2 (11) -#define CC4335_FNSEL_IND (12) -#define CC4335_FNSEL_PDN (13) -#define CC4335_FNSEL_PUP (14) -#define CC4335_FNSEL_TRI (15) - -/* 4345 pins -* note: only the values set as default/used are added here. -*/ -#define CC4345_PIN_GPIO_00 (0) -#define CC4345_PIN_GPIO_01 (1) -#define CC4345_PIN_GPIO_02 (2) -#define CC4345_PIN_GPIO_03 (3) -#define CC4345_PIN_GPIO_04 (4) -#define CC4345_PIN_GPIO_05 (5) -#define CC4345_PIN_GPIO_06 (6) -#define CC4345_PIN_GPIO_07 (7) -#define CC4345_PIN_GPIO_08 (8) -#define CC4345_PIN_GPIO_09 (9) -#define CC4345_PIN_GPIO_10 (10) -#define CC4345_PIN_GPIO_11 (11) -#define CC4345_PIN_GPIO_12 (12) -#define CC4345_PIN_GPIO_13 (13) -#define CC4345_PIN_GPIO_14 (14) -#define CC4345_PIN_GPIO_15 (15) -#define CC4345_PIN_GPIO_16 (16) -#define CC4345_PIN_SDIO_CLK (17) -#define CC4345_PIN_SDIO_CMD (18) -#define CC4345_PIN_SDIO_DATA0 (19) -#define CC4345_PIN_SDIO_DATA1 (20) -#define CC4345_PIN_SDIO_DATA2 (21) -#define CC4345_PIN_SDIO_DATA3 (22) -#define CC4345_PIN_RF_SW_CTRL_0 (23) -#define CC4345_PIN_RF_SW_CTRL_1 (24) -#define CC4345_PIN_RF_SW_CTRL_2 (25) -#define CC4345_PIN_RF_SW_CTRL_3 (26) -#define CC4345_PIN_RF_SW_CTRL_4 (27) -#define CC4345_PIN_RF_SW_CTRL_5 (28) -#define CC4345_PIN_RF_SW_CTRL_6 (29) -#define CC4345_PIN_RF_SW_CTRL_7 (30) -#define CC4345_PIN_RF_SW_CTRL_8 (31) -#define CC4345_PIN_RF_SW_CTRL_9 (32) - -/* 4345 GCI function sel values -*/ -#define CC4345_FNSEL_HWDEF (0) -#define CC4345_FNSEL_SAMEASPIN (1) -#define CC4345_FNSEL_GPIO0 (2) -#define CC4345_FNSEL_GPIO1 (3) -#define CC4345_FNSEL_GCI0 (4) -#define CC4345_FNSEL_GCI1 (5) -#define CC4345_FNSEL_UART (6) -#define CC4345_FNSEL_SFLASH (7) -#define CC4345_FNSEL_SPROM (8) -#define CC4345_FNSEL_MISC0 (9) -#define CC4345_FNSEL_MISC1 (10) -#define CC4345_FNSEL_MISC2 (11) -#define CC4345_FNSEL_IND (12) -#define CC4345_FNSEL_PDN (13) -#define CC4345_FNSEL_PUP (14) -#define CC4345_FNSEL_TRI (15) - -#define MUXENAB4345_UART_MASK (0x0000000f) -#define MUXENAB4345_UART_SHIFT 0 -#define MUXENAB4345_HOSTWAKE_MASK (0x000000f0) -#define MUXENAB4345_HOSTWAKE_SHIFT 4 - -/* GCI GPIO for function sel GCI-0/GCI-1 */ -#define CC_GCI_GPIO_0 (0) -#define CC_GCI_GPIO_1 (1) -#define CC_GCI_GPIO_2 (2) -#define CC_GCI_GPIO_3 (3) -#define CC_GCI_GPIO_4 (4) -#define CC_GCI_GPIO_5 (5) -#define CC_GCI_GPIO_6 (6) -#define CC_GCI_GPIO_7 (7) - -/* indicates Invalid GPIO, e.g. when PAD GPIO doesn't map to GCI GPIO */ -#define CC_GCI_GPIO_INVALID 0xFF - -/* find the 4 bit mask given the bit position */ -#define GCIMASK(pos) (((uint32)0xF) << pos) -/* get the value which can be used to directly OR with chipcontrol reg */ -#define GCIPOSVAL(val, pos) ((((uint32)val) << pos) & GCIMASK(pos)) -/* Extract nibble from a given position */ -#define GCIGETNBL(val, pos) ((val >> pos) & 0xF) - - -/* find the 8 bit mask given the bit position */ -#define GCIMASK_8B(pos) (((uint32)0xFF) << pos) -/* get the value which can be used to directly OR with chipcontrol reg */ -#define GCIPOSVAL_8B(val, pos) ((((uint32)val) << pos) & GCIMASK_8B(pos)) -/* Extract nibble from a given position */ -#define GCIGETNBL_8B(val, pos) ((val >> pos) & 0xFF) - -/* find the 4 bit mask given the bit position */ -#define GCIMASK_4B(pos) (((uint32)0xF) << pos) -/* get the value which can be used to directly OR with chipcontrol reg */ -#define GCIPOSVAL_4B(val, pos) ((((uint32)val) << pos) & GCIMASK_4B(pos)) -/* Extract nibble from a given position */ -#define GCIGETNBL_4B(val, pos) ((val >> pos) & 0xF) - - -#define GCI_INTSTATUS_GPIOINT (1 << 25) -#define GCI_INTSTATUS_GPIOWAKE (1 << 26) -#define GCI_INTMASK_GPIOINT (1 << 25) -#define GCI_INTMASK_GPIOWAKE (1 << 26) -#define GCI_WAKEMASK_GPIOINT (1 << 25) -#define GCI_WAKEMASK_GPIOWAKE (1 << 26) - - -/* 4335 MUX options. each nibble belongs to a setting. Non-zero value specifies a logic -* for now only UART for bootloader. -*/ -#define MUXENAB4335_UART_MASK (0x0000000f) - -#define MUXENAB4335_UART_SHIFT 0 -#define MUXENAB4335_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ -#define MUXENAB4335_HOSTWAKE_SHIFT 4 -#define MUXENAB4335_GETIX(val, name) \ - ((((val) & MUXENAB4335_ ## name ## _MASK) >> MUXENAB4335_ ## name ## _SHIFT) - 1) - -/* -* Maximum delay for the PMU state transition in us. -* This is an upper bound intended for spinwaits etc. -*/ -#define PMU_MAX_TRANSITION_DLY 15000 - -/* PMU resource up transition time in ILP cycles */ -#define PMURES_UP_TRANSITION 2 - - -/* SECI configuration */ -#define SECI_MODE_UART 0x0 -#define SECI_MODE_SECI 0x1 -#define SECI_MODE_LEGACY_3WIRE_BT 0x2 -#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3 -#define SECI_MODE_HALF_SECI 0x4 - -#define SECI_RESET (1 << 0) -#define SECI_RESET_BAR_UART (1 << 1) -#define SECI_ENAB_SECI_ECI (1 << 2) -#define SECI_ENAB_SECIOUT_DIS (1 << 3) -#define SECI_MODE_MASK 0x7 -#define SECI_MODE_SHIFT 4 /* (bits 5, 6, 7) */ -#define SECI_UPD_SECI (1 << 7) - -#define SECI_SIGNOFF_0 0xDB -#define SECI_SIGNOFF_1 0 - -/* seci clk_ctl_st bits */ -#define CLKCTL_STS_SECI_CLK_REQ (1 << 8) -#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24) - -#define SECI_UART_MSR_CTS_STATE (1 << 0) -#define SECI_UART_MSR_RTS_STATE (1 << 1) -#define SECI_UART_SECI_IN_STATE (1 << 2) -#define SECI_UART_SECI_IN2_STATE (1 << 3) - -/* SECI UART LCR/MCR register bits */ -#define SECI_UART_LCR_STOP_BITS (1 << 0) /* 0 - 1bit, 1 - 2bits */ -#define SECI_UART_LCR_PARITY_EN (1 << 1) -#define SECI_UART_LCR_PARITY (1 << 2) /* 0 - odd, 1 - even */ -#define SECI_UART_LCR_RX_EN (1 << 3) -#define SECI_UART_LCR_LBRK_CTRL (1 << 4) /* 1 => SECI_OUT held low */ -#define SECI_UART_LCR_TXO_EN (1 << 5) -#define SECI_UART_LCR_RTSO_EN (1 << 6) -#define SECI_UART_LCR_SLIPMODE_EN (1 << 7) -#define SECI_UART_LCR_RXCRC_CHK (1 << 8) -#define SECI_UART_LCR_TXCRC_INV (1 << 9) -#define SECI_UART_LCR_TXCRC_LSBF (1 << 10) -#define SECI_UART_LCR_TXCRC_EN (1 << 11) - -#define SECI_UART_MCR_TX_EN (1 << 0) -#define SECI_UART_MCR_PRTS (1 << 1) -#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2) -#define SECI_UART_MCR_HIGHRATE_EN (1 << 3) -#define SECI_UART_MCR_LOOPBK_EN (1 << 4) -#define SECI_UART_MCR_AUTO_RTS (1 << 5) -#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6) -#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7) -#define SECI_UART_MCR_XONOFF_RPT (1 << 9) - -/* WLAN channel numbers - used from wifi.h */ - -/* WLAN BW */ -#define ECI_BW_20 0x0 -#define ECI_BW_25 0x1 -#define ECI_BW_30 0x2 -#define ECI_BW_35 0x3 -#define ECI_BW_40 0x4 -#define ECI_BW_45 0x5 -#define ECI_BW_50 0x6 -#define ECI_BW_ALL 0x7 - -/* WLAN - number of antenna */ -#define WLAN_NUM_ANT1 TXANT_0 -#define WLAN_NUM_ANT2 TXANT_1 - -/* otpctrl1 0xF4 */ -#define OTPC_FORCE_PWR_OFF 0x02000000 -/* chipcommon s/r registers introduced with cc rev >= 48 */ -#define CC_SR_CTL0_ENABLE_MASK 0x1 -#define CC_SR_CTL0_ENABLE_SHIFT 0 -#define CC_SR_CTL0_EN_SR_ENG_CLK_SHIFT 1 /* sr_clk to sr_memory enable */ -#define CC_SR_CTL0_RSRC_TRIGGER_SHIFT 2 /* Rising edge resource trigger 0 to sr_engine */ -#define CC_SR_CTL0_MIN_DIV_SHIFT 6 /* Min division value for fast clk in sr_engine */ -#define CC_SR_CTL0_EN_SBC_STBY_SHIFT 16 /* Allow Subcore mem StandBy? */ -#define CC_SR_CTL0_EN_SR_ALP_CLK_MASK_SHIFT 18 -#define CC_SR_CTL0_EN_SR_HT_CLK_SHIFT 19 -#define CC_SR_CTL0_ALLOW_PIC_SHIFT 20 /* Allow pic to separate power domains */ -#define CC_SR_CTL0_MAX_SR_LQ_CLK_CNT_SHIFT 25 -#define CC_SR_CTL0_EN_MEM_DISABLE_FOR_SLEEP 30 - -#define ECI_INLO_PKTDUR_MASK 0x000000f0 /* [7:4] - 4 bits */ -#define ECI_INLO_PKTDUR_SHIFT 4 - -/* gci chip control bits */ -#define GCI_GPIO_CHIPCTRL_ENAB_IN_BIT 0 -#define GCI_GPIO_CHIPCTRL_ENAB_OP_BIT 1 -#define GCI_GPIO_CHIPCTRL_INVERT_BIT 2 -#define GCI_GPIO_CHIPCTRL_PULLUP_BIT 3 -#define GCI_GPIO_CHIPCTRL_PULLDN_BIT 4 -#define GCI_GPIO_CHIPCTRL_ENAB_BTSIG_BIT 5 -#define GCI_GPIO_CHIPCTRL_ENAB_OD_OP_BIT 6 -#define GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT 7 - -/* gci GPIO input status bits */ -#define GCI_GPIO_STS_VALUE_BIT 0 -#define GCI_GPIO_STS_POS_EDGE_BIT 1 -#define GCI_GPIO_STS_NEG_EDGE_BIT 2 -#define GCI_GPIO_STS_FAST_EDGE_BIT 3 -#define GCI_GPIO_STS_CLEAR 0xF - -#define GCI_GPIO_STS_VALUE (1 << GCI_GPIO_STS_VALUE_BIT) - -#endif /* _SBCHIPC_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h deleted file mode 100755 index 569b0c9b731e..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Broadcom SiliconBackplane hardware register definitions. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbconfig.h 241182 2011-02-17 21:50:03Z $ - */ - -#ifndef _SBCONFIG_H -#define _SBCONFIG_H - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif - -/* enumeration in SB is based on the premise that cores are contiguos in the - * enumeration space. - */ -#define SB_BUS_SIZE 0x10000 /* Each bus gets 64Kbytes for cores */ -#define SB_BUS_BASE(b) (SI_ENUM_BASE + (b) * SB_BUS_SIZE) -#define SB_BUS_MAXCORES (SB_BUS_SIZE / SI_CORE_SIZE) /* Max cores per bus */ - -/* - * Sonics Configuration Space Registers. - */ -#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */ -#define SBCONFIGSIZE 256 /* sizeof (sbconfig_t) */ - -#define SBIPSFLAG 0x08 -#define SBTPSFLAG 0x18 -#define SBTMERRLOGA 0x48 /* sonics >= 2.3 */ -#define SBTMERRLOG 0x50 /* sonics >= 2.3 */ -#define SBADMATCH3 0x60 -#define SBADMATCH2 0x68 -#define SBADMATCH1 0x70 -#define SBIMSTATE 0x90 -#define SBINTVEC 0x94 -#define SBTMSTATELOW 0x98 -#define SBTMSTATEHIGH 0x9c -#define SBBWA0 0xa0 -#define SBIMCONFIGLOW 0xa8 -#define SBIMCONFIGHIGH 0xac -#define SBADMATCH0 0xb0 -#define SBTMCONFIGLOW 0xb8 -#define SBTMCONFIGHIGH 0xbc -#define SBBCONFIG 0xc0 -#define SBBSTATE 0xc8 -#define SBACTCNFG 0xd8 -#define SBFLAGST 0xe8 -#define SBIDLOW 0xf8 -#define SBIDHIGH 0xfc - -/* All the previous registers are above SBCONFIGOFF, but with Sonics 2.3, we have - * a few registers *below* that line. I think it would be very confusing to try - * and change the value of SBCONFIGOFF, so I'm definig them as absolute offsets here, - */ - -#define SBIMERRLOGA 0xea8 -#define SBIMERRLOG 0xeb0 -#define SBTMPORTCONNID0 0xed8 -#define SBTMPORTLOCK0 0xef8 - -#ifndef _LANGUAGE_ASSEMBLY - -typedef volatile struct _sbconfig { - uint32 PAD[2]; - uint32 sbipsflag; /* initiator port ocp slave flag */ - uint32 PAD[3]; - uint32 sbtpsflag; /* target port ocp slave flag */ - uint32 PAD[11]; - uint32 sbtmerrloga; /* (sonics >= 2.3) */ - uint32 PAD; - uint32 sbtmerrlog; /* (sonics >= 2.3) */ - uint32 PAD[3]; - uint32 sbadmatch3; /* address match3 */ - uint32 PAD; - uint32 sbadmatch2; /* address match2 */ - uint32 PAD; - uint32 sbadmatch1; /* address match1 */ - uint32 PAD[7]; - uint32 sbimstate; /* initiator agent state */ - uint32 sbintvec; /* interrupt mask */ - uint32 sbtmstatelow; /* target state */ - uint32 sbtmstatehigh; /* target state */ - uint32 sbbwa0; /* bandwidth allocation table0 */ - uint32 PAD; - uint32 sbimconfiglow; /* initiator configuration */ - uint32 sbimconfighigh; /* initiator configuration */ - uint32 sbadmatch0; /* address match0 */ - uint32 PAD; - uint32 sbtmconfiglow; /* target configuration */ - uint32 sbtmconfighigh; /* target configuration */ - uint32 sbbconfig; /* broadcast configuration */ - uint32 PAD; - uint32 sbbstate; /* broadcast state */ - uint32 PAD[3]; - uint32 sbactcnfg; /* activate configuration */ - uint32 PAD[3]; - uint32 sbflagst; /* current sbflags */ - uint32 PAD[3]; - uint32 sbidlow; /* identification */ - uint32 sbidhigh; /* identification */ -} sbconfig_t; - -#endif /* _LANGUAGE_ASSEMBLY */ - -/* sbipsflag */ -#define SBIPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */ -#define SBIPS_INT1_SHIFT 0 -#define SBIPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */ -#define SBIPS_INT2_SHIFT 8 -#define SBIPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */ -#define SBIPS_INT3_SHIFT 16 -#define SBIPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */ -#define SBIPS_INT4_SHIFT 24 - -/* sbtpsflag */ -#define SBTPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */ -#define SBTPS_F0EN0 0x40 /* interrupt is always sent on the backplane */ - -/* sbtmerrlog */ -#define SBTMEL_CM 0x00000007 /* command */ -#define SBTMEL_CI 0x0000ff00 /* connection id */ -#define SBTMEL_EC 0x0f000000 /* error code */ -#define SBTMEL_ME 0x80000000 /* multiple error */ - -/* sbimstate */ -#define SBIM_PC 0xf /* pipecount */ -#define SBIM_AP_MASK 0x30 /* arbitration policy */ -#define SBIM_AP_BOTH 0x00 /* use both timeslaces and token */ -#define SBIM_AP_TS 0x10 /* use timesliaces only */ -#define SBIM_AP_TK 0x20 /* use token only */ -#define SBIM_AP_RSV 0x30 /* reserved */ -#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 */ -#define SBTML_RESET 0x0001 /* reset */ -#define SBTML_REJ_MASK 0x0006 /* reject field */ -#define SBTML_REJ 0x0002 /* reject */ -#define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */ - -#define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */ - -/* sbtmstatehigh */ -#define SBTMH_SERR 0x0001 /* serror */ -#define SBTMH_INT 0x0002 /* interrupt */ -#define SBTMH_BUSY 0x0004 /* busy */ -#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ - -#define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */ - -/* sbbwa0 */ -#define SBBWA_TAB0_MASK 0xffff /* lookup table 0 */ -#define SBBWA_TAB1_MASK 0xffff /* lookup table 1 */ -#define SBBWA_TAB1_SHIFT 16 - -/* sbimconfiglow */ -#define SBIMCL_STO_MASK 0x7 /* service timeout */ -#define SBIMCL_RTO_MASK 0x70 /* request timeout */ -#define SBIMCL_RTO_SHIFT 4 -#define SBIMCL_CID_MASK 0xff0000 /* connection id */ -#define SBIMCL_CID_SHIFT 16 - -/* sbimconfighigh */ -#define SBIMCH_IEM_MASK 0xc /* inband error mode */ -#define SBIMCH_TEM_MASK 0x30 /* timeout error mode */ -#define SBIMCH_TEM_SHIFT 4 -#define SBIMCH_BEM_MASK 0xc0 /* bus error mode */ -#define SBIMCH_BEM_SHIFT 6 - -/* sbadmatch0 */ -#define SBAM_TYPE_MASK 0x3 /* address type */ -#define SBAM_AD64 0x4 /* reserved */ -#define SBAM_ADINT0_MASK 0xf8 /* type0 size */ -#define SBAM_ADINT0_SHIFT 3 -#define SBAM_ADINT1_MASK 0x1f8 /* type1 size */ -#define SBAM_ADINT1_SHIFT 3 -#define SBAM_ADINT2_MASK 0x1f8 /* type2 size */ -#define SBAM_ADINT2_SHIFT 3 -#define SBAM_ADEN 0x400 /* enable */ -#define SBAM_ADNEG 0x800 /* negative decode */ -#define SBAM_BASE0_MASK 0xffffff00 /* type0 base address */ -#define SBAM_BASE0_SHIFT 8 -#define SBAM_BASE1_MASK 0xfffff000 /* type1 base address for the core */ -#define SBAM_BASE1_SHIFT 12 -#define SBAM_BASE2_MASK 0xffff0000 /* type2 base address for the core */ -#define SBAM_BASE2_SHIFT 16 - -/* sbtmconfiglow */ -#define SBTMCL_CD_MASK 0xff /* clock divide */ -#define SBTMCL_CO_MASK 0xf800 /* clock offset */ -#define SBTMCL_CO_SHIFT 11 -#define SBTMCL_IF_MASK 0xfc0000 /* interrupt flags */ -#define SBTMCL_IF_SHIFT 18 -#define SBTMCL_IM_MASK 0x3000000 /* interrupt mode */ -#define SBTMCL_IM_SHIFT 24 - -/* sbtmconfighigh */ -#define SBTMCH_BM_MASK 0x3 /* busy mode */ -#define SBTMCH_RM_MASK 0x3 /* retry mode */ -#define SBTMCH_RM_SHIFT 2 -#define SBTMCH_SM_MASK 0x30 /* stop mode */ -#define SBTMCH_SM_SHIFT 4 -#define SBTMCH_EM_MASK 0x300 /* sb error mode */ -#define SBTMCH_EM_SHIFT 8 -#define SBTMCH_IM_MASK 0xc00 /* int mode */ -#define SBTMCH_IM_SHIFT 10 - -/* sbbconfig */ -#define SBBC_LAT_MASK 0x3 /* sb latency */ -#define SBBC_MAX0_MASK 0xf0000 /* maxccntr0 */ -#define SBBC_MAX0_SHIFT 16 -#define SBBC_MAX1_MASK 0xf00000 /* maxccntr1 */ -#define SBBC_MAX1_SHIFT 20 - -/* sbbstate */ -#define SBBS_SRD 0x1 /* st reg disable */ -#define SBBS_HRD 0x2 /* hold reg disable */ - -/* sbidlow */ -#define SBIDL_CS_MASK 0x3 /* config space */ -#define SBIDL_AR_MASK 0x38 /* # address ranges supported */ -#define SBIDL_AR_SHIFT 3 -#define SBIDL_SYNCH 0x40 /* sync */ -#define SBIDL_INIT 0x80 /* initiator */ -#define SBIDL_MINLAT_MASK 0xf00 /* minimum backplane latency */ -#define SBIDL_MINLAT_SHIFT 8 -#define SBIDL_MAXLAT 0xf000 /* maximum backplane latency */ -#define SBIDL_MAXLAT_SHIFT 12 -#define SBIDL_FIRST 0x10000 /* this initiator is first */ -#define SBIDL_CW_MASK 0xc0000 /* cycle counter width */ -#define SBIDL_CW_SHIFT 18 -#define SBIDL_TP_MASK 0xf00000 /* target ports */ -#define SBIDL_TP_SHIFT 20 -#define SBIDL_IP_MASK 0xf000000 /* initiator ports */ -#define SBIDL_IP_SHIFT 24 -#define SBIDL_RV_MASK 0xf0000000 /* sonics backplane revision code */ -#define SBIDL_RV_SHIFT 28 -#define SBIDL_RV_2_2 0x00000000 /* version 2.2 or earlier */ -#define SBIDL_RV_2_3 0x10000000 /* version 2.3 */ - -/* 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 - -#define SB_COMMIT 0xfd8 /* update buffered registers value */ - -/* vendor codes */ -#define SB_VEND_BCM 0x4243 /* Broadcom's SB vendor code */ - -#endif /* _SBCONFIG_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h deleted file mode 100755 index 43ec49c47a39..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Generic Broadcom Home Networking Division (HND) DMA engine HW interface - * This supports the following chips: BCM42xx, 44xx, 47xx . - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbhnddma.h 424099 2013-09-16 07:44:34Z $ - */ - -#ifndef _sbhnddma_h_ -#define _sbhnddma_h_ - -/* 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 */ - -/* dma registers per channel(xmt or rcv) */ -typedef volatile struct { - uint32 control; /* enable, et al */ - uint32 addr; /* descriptor ring base address (4K aligned) */ - uint32 ptr; /* last descriptor posted to chip */ - uint32 status; /* current active descriptor, et al */ -} dma32regs_t; - -typedef volatile struct { - dma32regs_t xmt; /* dma tx channel */ - dma32regs_t rcv; /* dma rx channel */ -} dma32regp_t; - -typedef volatile struct { /* diag access */ - uint32 fifoaddr; /* diag address */ - uint32 fifodatalow; /* low 32bits of data */ - uint32 fifodatahigh; /* high 32bits of data */ - uint32 pad; /* reserved */ -} dma32diag_t; - -/* - * DMA Descriptor - * Descriptors are only read by the hardware, never written back. - */ -typedef volatile struct { - uint32 ctrl; /* misc control bits & bufcount */ - uint32 addr; /* data buffer address */ -} dma32dd_t; - -/* - * Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page. - */ -#define D32RINGALIGN_BITS 12 -#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS) -#define D32RINGALIGN (1 << D32RINGALIGN_BITS) - -#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) - -/* transmit channel control */ -#define XC_XE ((uint32)1 << 0) /* transmit enable */ -#define XC_SE ((uint32)1 << 1) /* transmit suspend request */ -#define XC_LE ((uint32)1 << 2) /* loopback enable */ -#define XC_FL ((uint32)1 << 4) /* flush request */ -#define XC_MR_MASK 0x000001C0 /* Multiple outstanding reads */ -#define XC_MR_SHIFT 6 -#define XC_PD ((uint32)1 << 11) /* parity check disable */ -#define XC_AE ((uint32)3 << 16) /* address extension bits */ -#define XC_AE_SHIFT 16 -#define XC_BL_MASK 0x001C0000 /* BurstLen bits */ -#define XC_BL_SHIFT 18 -#define XC_PC_MASK 0x00E00000 /* Prefetch control */ -#define XC_PC_SHIFT 21 -#define XC_PT_MASK 0x03000000 /* Prefetch threshold */ -#define XC_PT_SHIFT 24 - -/* Multiple outstanding reads */ -#define DMA_MR_1 0 -#define DMA_MR_2 1 -#define DMA_MR_4 2 -#define DMA_MR_8 3 -#define DMA_MR_12 4 -#define DMA_MR_16 5 -#define DMA_MR_20 6 -#define DMA_MR_32 7 - -/* DMA Burst Length in bytes */ -#define DMA_BL_16 0 -#define DMA_BL_32 1 -#define DMA_BL_64 2 -#define DMA_BL_128 3 -#define DMA_BL_256 4 -#define DMA_BL_512 5 -#define DMA_BL_1024 6 - -/* Prefetch control */ -#define DMA_PC_0 0 -#define DMA_PC_4 1 -#define DMA_PC_8 2 -#define DMA_PC_16 3 -/* others: reserved */ - -/* Prefetch threshold */ -#define DMA_PT_1 0 -#define DMA_PT_2 1 -#define DMA_PT_4 2 -#define DMA_PT_8 3 - -/* transmit descriptor table pointer */ -#define XP_LD_MASK 0xfff /* last valid descriptor */ - -/* transmit channel status */ -#define XS_CD_MASK 0x0fff /* current descriptor pointer */ -#define XS_XS_MASK 0xf000 /* transmit state */ -#define XS_XS_SHIFT 12 -#define XS_XS_DISABLED 0x0000 /* disabled */ -#define XS_XS_ACTIVE 0x1000 /* active */ -#define XS_XS_IDLE 0x2000 /* idle wait */ -#define XS_XS_STOPPED 0x3000 /* stopped */ -#define XS_XS_SUSP 0x4000 /* suspend pending */ -#define XS_XE_MASK 0xf0000 /* transmit errors */ -#define XS_XE_SHIFT 16 -#define XS_XE_NOERR 0x00000 /* no error */ -#define XS_XE_DPE 0x10000 /* descriptor protocol error */ -#define XS_XE_DFU 0x20000 /* data fifo underrun */ -#define XS_XE_BEBR 0x30000 /* bus error on buffer read */ -#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */ -#define XS_AD_MASK 0xfff00000 /* active descriptor */ -#define XS_AD_SHIFT 20 - -/* receive channel control */ -#define RC_RE ((uint32)1 << 0) /* receive enable */ -#define RC_RO_MASK 0xfe /* receive frame offset */ -#define RC_RO_SHIFT 1 -#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */ -#define RC_SH ((uint32)1 << 9) /* separate rx header descriptor enable */ -#define RC_OC ((uint32)1 << 10) /* overflow continue */ -#define RC_PD ((uint32)1 << 11) /* parity check disable */ -#define RC_AE ((uint32)3 << 16) /* address extension bits */ -#define RC_AE_SHIFT 16 -#define RC_BL_MASK 0x001C0000 /* BurstLen bits */ -#define RC_BL_SHIFT 18 -#define RC_PC_MASK 0x00E00000 /* Prefetch control */ -#define RC_PC_SHIFT 21 -#define RC_PT_MASK 0x03000000 /* Prefetch threshold */ -#define RC_PT_SHIFT 24 - -/* receive descriptor table pointer */ -#define RP_LD_MASK 0xfff /* last valid descriptor */ - -/* receive channel status */ -#define RS_CD_MASK 0x0fff /* current descriptor pointer */ -#define RS_RS_MASK 0xf000 /* receive state */ -#define RS_RS_SHIFT 12 -#define RS_RS_DISABLED 0x0000 /* disabled */ -#define RS_RS_ACTIVE 0x1000 /* active */ -#define RS_RS_IDLE 0x2000 /* idle wait */ -#define RS_RS_STOPPED 0x3000 /* reserved */ -#define RS_RE_MASK 0xf0000 /* receive errors */ -#define RS_RE_SHIFT 16 -#define RS_RE_NOERR 0x00000 /* no error */ -#define RS_RE_DPE 0x10000 /* descriptor protocol error */ -#define RS_RE_DFO 0x20000 /* data fifo overflow */ -#define RS_RE_BEBW 0x30000 /* bus error on buffer write */ -#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */ -#define RS_AD_MASK 0xfff00000 /* active descriptor */ -#define RS_AD_SHIFT 20 - -/* fifoaddr */ -#define FA_OFF_MASK 0xffff /* offset */ -#define FA_SEL_MASK 0xf0000 /* select */ -#define FA_SEL_SHIFT 16 -#define FA_SEL_XDD 0x00000 /* transmit dma data */ -#define FA_SEL_XDP 0x10000 /* transmit dma pointers */ -#define FA_SEL_RDD 0x40000 /* receive dma data */ -#define FA_SEL_RDP 0x50000 /* receive dma pointers */ -#define FA_SEL_XFD 0x80000 /* transmit fifo data */ -#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */ -#define FA_SEL_RFD 0xc0000 /* receive fifo data */ -#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */ -#define FA_SEL_RSD 0xe0000 /* receive frame status data */ -#define FA_SEL_RSP 0xf0000 /* receive frame status pointers */ - -/* descriptor control flags */ -#define CTRL_BC_MASK 0x00001fff /* buffer byte count, real data len must <= 4KB */ -#define CTRL_AE ((uint32)3 << 16) /* address extension bits */ -#define CTRL_AE_SHIFT 16 -#define CTRL_PARITY ((uint32)3 << 18) /* parity bit */ -#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */ -#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */ -#define CTRL_EOF ((uint32)1 << 30) /* end of frame */ -#define CTRL_SOF ((uint32)1 << 31) /* start of frame */ - -/* control flags in the range [27:20] are core-specific and not defined here */ -#define CTRL_CORE_MASK 0x0ff00000 - -/* 64 bits addressing */ - -/* dma registers per channel(xmt or rcv) */ -typedef volatile struct { - uint32 control; /* enable, et al */ - uint32 ptr; /* last descriptor posted to chip */ - uint32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */ - uint32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */ - uint32 status0; /* current descriptor, xmt state */ - uint32 status1; /* active descriptor, xmt error */ -} dma64regs_t; - -typedef volatile struct { - dma64regs_t tx; /* dma64 tx channel */ - dma64regs_t rx; /* dma64 rx channel */ -} dma64regp_t; - -typedef volatile struct { /* diag access */ - uint32 fifoaddr; /* diag address */ - uint32 fifodatalow; /* low 32bits of data */ - uint32 fifodatahigh; /* high 32bits of data */ - uint32 pad; /* reserved */ -} dma64diag_t; - -/* - * DMA Descriptor - * Descriptors are only read by the hardware, never written back. - */ -typedef volatile struct { - uint32 ctrl1; /* misc control bits */ - uint32 ctrl2; /* buffer count and address extension */ - uint32 addrlow; /* memory address of the date buffer, bits 31:0 */ - uint32 addrhigh; /* memory address of the date buffer, bits 63:32 */ -} dma64dd_t; - -/* - * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss. - */ -#define D64RINGALIGN_BITS 13 -#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) -#define D64RINGBOUNDARY (1 << D64RINGALIGN_BITS) - -#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) - -/* for cores with large descriptor ring support, descriptor ring size can be up to 4096 */ -#define D64MAXDD_LARGE ((1 << 16) / sizeof (dma64dd_t)) - -/* for cores with large descriptor ring support (4k descriptors), descriptor ring cannot cross - * 64K boundary - */ -#define D64RINGBOUNDARY_LARGE (1 << 16) - -/* - * Default DMA Burstlen values for USBRev >= 12 and SDIORev >= 11. - * When this field contains the value N, the burst length is 2**(N + 4) bytes. - */ -#define D64_DEF_USBBURSTLEN 2 -#define D64_DEF_SDIOBURSTLEN 1 - - -#ifndef D64_USBBURSTLEN -#define D64_USBBURSTLEN DMA_BL_64 -#endif -#ifndef D64_SDIOBURSTLEN -#define D64_SDIOBURSTLEN DMA_BL_32 -#endif - -/* 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_MR_MASK 0x000001C0 /* Multiple outstanding reads */ -#define D64_XC_MR_SHIFT 6 -#define D64_XC_PD 0x00000800 /* parity check disable */ -#define D64_XC_AE 0x00030000 /* address extension bits */ -#define D64_XC_AE_SHIFT 16 -#define D64_XC_BL_MASK 0x001C0000 /* BurstLen bits */ -#define D64_XC_BL_SHIFT 18 -#define D64_XC_PC_MASK 0x00E00000 /* Prefetch control */ -#define D64_XC_PC_SHIFT 21 -#define D64_XC_PT_MASK 0x03000000 /* Prefetch threshold */ -#define D64_XC_PT_SHIFT 24 - -/* transmit descriptor table pointer */ -#define D64_XP_LD_MASK 0x00001fff /* last valid descriptor */ - -/* transmit channel status */ -#define D64_XS0_CD_MASK (di->d64_xs0_cd_mask) /* 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 (di->d64_xs1_ad_mask) /* 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 */ -#define D64_RC_RE 0x00000001 /* receive enable */ -#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */ -#define D64_RC_RO_SHIFT 1 -#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */ -#define D64_RC_SH 0x00000200 /* separate rx header descriptor enable */ -#define D64_RC_SHIFT 9 /* separate rx header descriptor enable */ -#define D64_RC_OC 0x00000400 /* overflow continue */ -#define D64_RC_PD 0x00000800 /* parity check disable */ -#define D64_RC_GE 0x00004000 /* Glom enable */ -#define D64_RC_AE 0x00030000 /* address extension bits */ -#define D64_RC_AE_SHIFT 16 -#define D64_RC_BL_MASK 0x001C0000 /* BurstLen bits */ -#define D64_RC_BL_SHIFT 18 -#define D64_RC_PC_MASK 0x00E00000 /* Prefetch control */ -#define D64_RC_PC_SHIFT 21 -#define D64_RC_PT_MASK 0x03000000 /* Prefetch threshold */ -#define D64_RC_PT_SHIFT 24 - -/* flags for dma controller */ -#define DMA_CTRL_PEN (1 << 0) /* partity enable */ -#define DMA_CTRL_ROC (1 << 1) /* rx overflow continue */ -#define DMA_CTRL_RXMULTI (1 << 2) /* allow rx scatter to multiple descriptors */ -#define DMA_CTRL_UNFRAMED (1 << 3) /* Unframed Rx/Tx data */ -#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) -#define DMA_CTRL_DMA_AVOIDANCE_WAR (1 << 5) /* DMA avoidance WAR for 4331 */ -#define DMA_CTRL_RXSINGLE (1 << 6) /* always single buffer */ - -/* receive descriptor table pointer */ -#define D64_RP_LD_MASK 0x00001fff /* last valid descriptor */ - -/* receive channel status */ -#define D64_RS0_CD_MASK (di->d64_rs0_cd_mask) /* 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_NOTPCIE ((uint32)1 << 18) /* buirst size control */ -#define D64_CTRL1_EOT ((uint32)1 << 28) /* end of descriptor table */ -#define D64_CTRL1_IOC ((uint32)1 << 29) /* interrupt on completion */ -#define D64_CTRL1_EOF ((uint32)1 << 30) /* end of frame */ -#define D64_CTRL1_SOF ((uint32)1 << 31) /* start of frame */ - -/* descriptor control flags 2 */ -#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count. real data len must <= 16KB */ -#define D64_CTRL2_AE 0x00030000 /* address extension bits */ -#define D64_CTRL2_AE_SHIFT 16 -#define D64_CTRL2_PARITY 0x00040000 /* parity bit */ - -/* 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, d11corerev >= 22 */ -#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */ - -/* receive frame status */ -typedef volatile struct { - uint16 len; - uint16 flags; -} dma_rxh_t; - -#endif /* _sbhnddma_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h deleted file mode 100755 index 27d2f83f7c0a..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbpcmcia.h 427964 2013-10-07 07:13:33Z $ - */ - -#ifndef _SBPCMCIA_H -#define _SBPCMCIA_H - -/* All the addresses that are offsets in attribute space are divided - * by two to account for the fact that odd bytes are invalid in - * attribute space and our read/write routines make the space appear - * as if they didn't exist. Still we want to show the original numbers - * as documented in the hnd_pcmcia core manual. - */ - -/* PCMCIA Function Configuration Registers */ -#define PCMCIA_FCR (0x700 / 2) - -#define FCR0_OFF 0 -#define FCR1_OFF (0x40 / 2) -#define FCR2_OFF (0x80 / 2) -#define FCR3_OFF (0xc0 / 2) - -#define PCMCIA_FCR0 (0x700 / 2) -#define PCMCIA_FCR1 (0x740 / 2) -#define PCMCIA_FCR2 (0x780 / 2) -#define PCMCIA_FCR3 (0x7c0 / 2) - -/* Standard PCMCIA FCR registers */ - -#define PCMCIA_COR 0 - -#define COR_RST 0x80 -#define COR_LEV 0x40 -#define COR_IRQEN 0x04 -#define COR_BLREN 0x01 -#define COR_FUNEN 0x01 - - -#define PCICIA_FCSR (2 / 2) -#define PCICIA_PRR (4 / 2) -#define PCICIA_SCR (6 / 2) -#define PCICIA_ESR (8 / 2) - - -#define PCM_MEMOFF 0x0000 -#define F0_MEMOFF 0x1000 -#define F1_MEMOFF 0x2000 -#define F2_MEMOFF 0x3000 -#define F3_MEMOFF 0x4000 - -/* Memory base in the function fcr's */ -#define MEM_ADDR0 (0x728 / 2) -#define MEM_ADDR1 (0x72a / 2) -#define MEM_ADDR2 (0x72c / 2) - -/* PCMCIA base plus Srom access in fcr0: */ -#define PCMCIA_ADDR0 (0x072e / 2) -#define PCMCIA_ADDR1 (0x0730 / 2) -#define PCMCIA_ADDR2 (0x0732 / 2) - -#define MEM_SEG (0x0734 / 2) -#define SROM_CS (0x0736 / 2) -#define SROM_DATAL (0x0738 / 2) -#define SROM_DATAH (0x073a / 2) -#define SROM_ADDRL (0x073c / 2) -#define SROM_ADDRH (0x073e / 2) -#define SROM_INFO2 (0x0772 / 2) /* Corerev >= 2 && <= 5 */ -#define SROM_INFO (0x07be / 2) /* Corerev >= 6 */ - -/* Values for srom_cs: */ -#define SROM_IDLE 0 -#define SROM_WRITE 1 -#define SROM_READ 2 -#define SROM_WEN 4 -#define SROM_WDS 7 -#define SROM_DONE 8 - -/* Fields in srom_info: */ -#define SRI_SZ_MASK 0x03 -#define SRI_BLANK 0x04 -#define SRI_OTP 0x80 - - -/* sbtmstatelow */ -#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */ -#define SBTML_INT_EN 0x20000 /* enable sb interrupt */ - -/* sbtmstatehigh */ -#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */ - -#endif /* _SBPCMCIA_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h deleted file mode 100755 index cca84bc18f28..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * SDIO device core hardware definitions. - * sdio is a portion of the pcmcia core in core rev 3 - rev 8 - * - * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbsdio.h 383835 2013-02-07 23:32:39Z $ - */ - -#ifndef _SBSDIO_H -#define _SBSDIO_H - -#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */ - -/* function 1 miscellaneous registers */ -#define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */ -#define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */ -#define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */ -#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */ -#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */ -#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */ -#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */ -#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */ -#define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */ -#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */ - -/* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */ -#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */ -#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */ -#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */ -#define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */ -#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */ -#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */ -#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */ -#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */ -#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */ -#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */ -#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D /* MesBusyCtl at 0x1001D (rev 11) */ - -#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ -#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ - -/* Sdio Core Rev 12 */ -#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E -#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1 -#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0 -#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2 -#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1 -#define SBSDIO_FUNC1_SLEEPCSR 0x1001F -#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1 -#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0 -#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1 -#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2 -#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1 - -/* SBSDIO_SPROM_CS */ -#define SBSDIO_SPROM_IDLE 0 -#define SBSDIO_SPROM_WRITE 1 -#define SBSDIO_SPROM_READ 2 -#define SBSDIO_SPROM_WEN 4 -#define SBSDIO_SPROM_WDS 7 -#define SBSDIO_SPROM_DONE 8 - -/* SBSDIO_SPROM_INFO */ -#define SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */ -#define SROM_BLANK 0x04 /* depreciated in corerev 6 */ -#define SROM_OTP 0x80 /* OTP present */ - -/* SBSDIO_CHIP_CTRL */ -#define SBSDIO_CHIP_CTRL_XTAL 0x01 /* or'd with onchip xtal_pu, - * 1: power on oscillator - * (for 4318 only) - */ -/* SBSDIO_WATERMARK */ -#define SBSDIO_WATERMARK_MASK 0x7f /* number of words - 1 for sd device - * to wait before sending data to host - */ - -/* SBSDIO_MESBUSYCTRL */ -/* When RX FIFO has less entries than this & MBE is set - * => busy signal is asserted between data blocks. -*/ -#define SBSDIO_MESBUSYCTRL_MASK 0x7f -#define SBSDIO_MESBUSYCTRL_ENAB 0x80 /* Enable busy capability for MES access */ - -/* SBSDIO_DEVICE_CTL */ -#define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when - * receiving CMD53 - */ -#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is - * synchronous to the sdio clock - */ -#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host - * except the chipActive (rev 8) - */ -#define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put - * external pads in tri-state; requires - * sdio bus power cycle to clear (rev 9) - */ -#define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ -#define SBSDIO_DEVCTL_F2WM_ENAB 0x10 /* Enable F2 Watermark */ -#define SBSDIO_DEVCTL_NONDAT_PADS_ISO 0x20 /* Isolate sdio clk and cmd (non-data) */ - -/* SBSDIO_FUNC1_CHIPCLKCSR */ -#define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */ -#define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */ -#define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */ -#define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */ -#define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */ -#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */ -#define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */ -#define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */ -/* In rev8, actual avail bits followed original docs */ -#define SBSDIO_Rev8_HT_AVAIL 0x40 -#define SBSDIO_Rev8_ALP_AVAIL 0x80 -#define SBSDIO_CSR_MASK 0x1F - -#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))) - -/* SBSDIO_FUNC1_SDIOPULLUP */ -#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */ -#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */ -#define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */ -#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */ -#define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */ - -/* function 1 OCP space */ -#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */ -#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 -#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */ - -/* some duplication with sbsdpcmdev.h here */ -/* 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 */ -#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ - -/* direct(mapped) cis space */ -#define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ -#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */ -#define SBSDIO_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP CIS */ - -#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */ - -#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple, - * link bytes - */ - -/* indirect cis access (in sprom) */ -#define SBSDIO_SPROM_CIS_OFFSET 0x8 /* 8 control bytes first, CIS starts from - * 8th byte - */ - -#define SBSDIO_BYTEMODE_DATALEN_MAX 64 /* sdio byte mode: maximum length of one - * data comamnd - */ - -#define SBSDIO_CORE_ADDR_MASK 0x1FFFF /* sdio core function one address mask */ - -#endif /* _SBSDIO_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h deleted file mode 100755 index 958436e3c45e..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific - * device core support - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbsdpcmdev.h 416730 2013-08-06 09:33:19Z $ - */ - -#ifndef _sbsdpcmdev_h_ -#define _sbsdpcmdev_h_ - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - - -typedef volatile struct { - dma64regs_t xmt; /* dma tx */ - uint32 PAD[2]; - dma64regs_t rcv; /* dma rx */ - uint32 PAD[2]; -} dma64p_t; - -/* dma64 sdiod corerev >= 1 */ -typedef volatile struct { - dma64p_t dma64regs[2]; - dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */ - uint32 PAD[92]; -} sdiodma64_t; - -/* dma32 sdiod corerev == 0 */ -typedef volatile struct { - dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ - dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */ - uint32 PAD[108]; -} sdiodma32_t; - -/* dma32 regs for pcmcia core */ -typedef volatile struct { - dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */ - dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */ - uint32 PAD[116]; -} pcmdma32_t; - -/* core registers */ -typedef volatile struct { - uint32 corecontrol; /* CoreControl, 0x000, rev8 */ - uint32 corestatus; /* CoreStatus, 0x004, rev8 */ - uint32 PAD[1]; - uint32 biststatus; /* BistStatus, 0x00c, rev8 */ - - /* PCMCIA access */ - uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */ - uint16 PAD[1]; - uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */ - uint16 PAD[1]; - uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */ - uint16 PAD[1]; - uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */ - uint16 PAD[1]; - - /* interrupt */ - uint32 intstatus; /* IntStatus, 0x020, rev8 */ - uint32 hostintmask; /* IntHostMask, 0x024, rev8 */ - uint32 intmask; /* IntSbMask, 0x028, rev8 */ - uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */ - uint32 sbintmask; /* SBIntMask, 0x030, rev8 */ - uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */ - uint32 PAD[2]; - uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */ - uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */ - uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */ - uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */ - - /* synchronized access to registers in SDIO clock domain */ - uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */ - uint32 PAD[3]; - - /* PCMCIA frame control */ - uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ - uint8 PAD[3]; - uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ - uint8 PAD[155]; - - /* interrupt batching control */ - uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */ - uint32 PAD[3]; - - /* counters */ - uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */ - uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */ - uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */ - uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */ - uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */ - uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */ - uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */ - uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */ - uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */ - uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */ - uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */ - uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */ - uint32 PAD[40]; - uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */ - uint32 PAD[7]; - - /* DMA engines */ - volatile union { - pcmdma32_t pcm32; - sdiodma32_t sdiod32; - sdiodma64_t sdiod64; - } dma; - - /* SDIO/PCMCIA CIS region */ - char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */ - - /* PCMCIA function control registers */ - char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */ - uint16 PAD[55]; - - /* PCMCIA backplane access */ - uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */ - uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */ - uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */ - uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */ - uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */ - uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */ - uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */ - uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */ - uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */ - uint16 PAD[31]; - - /* sprom "size" & "blank" info */ - uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */ - uint32 PAD[464]; - - /* Sonics SiliconBackplane registers */ - sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */ -} sdpcmd_regs_t; - -/* corecontrol */ -#define CC_CISRDY (1 << 0) /* CIS Ready */ -#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ -#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ -#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ -#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */ -#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */ - -/* corestatus */ -#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */ -#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */ -#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */ - -#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */ -#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */ -#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */ -#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */ - -/* 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 transitioned 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) /* DMA Errors */ -#define I_DMA (I_RI | I_XI | I_ERRORS) - -/* sbintstatus */ -#define I_SB_SERR (1 << 8) /* Backplane SError (write) */ -#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */ -#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */ - -/* sdioaccess */ -#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */ -#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */ -#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */ -#define SDA_WRITE 0x01000000 /* Write bit */ -#define SDA_READ 0x00000000 /* Write bit cleared for Read */ -#define SDA_BUSY 0x80000000 /* Busy bit */ - -/* sdioaccess-accessible register address spaces */ -#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */ -#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */ -#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */ -#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */ - -/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */ -#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */ -#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */ -#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */ -#define SDA_DEVICECONTROL 0x009 /* DeviceControl */ -#define SDA_SBADDRLOW 0x00a /* SbAddrLow */ -#define SDA_SBADDRMID 0x00b /* SbAddrMid */ -#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */ -#define SDA_FRAMECTRL 0x00d /* FrameCtrl */ -#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */ -#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */ -#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */ -#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */ -#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */ -#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */ - -/* SDA_F2WATERMARK */ -#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */ - -/* SDA_SBADDRLOW */ -#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */ - -/* SDA_SBADDRMID */ -#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */ - -/* SDA_SBADDRHIGH */ -#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */ - -/* 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) /* HW reports CRC error for write out of sync */ -#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */ - -/* pcmciaframectrl */ -#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */ -#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */ - -/* intrcvlazy */ -#define IRL_TO_MASK 0x00ffffff /* timeout */ -#define IRL_FC_MASK 0xff000000 /* frame count */ -#define IRL_FC_SHIFT 24 /* frame count */ - -/* rx header */ -typedef volatile struct { - uint16 len; - uint16 flags; -} sdpcmd_rxh_t; - -/* rx header flags */ -#define RXF_CRC 0x0001 /* CRC error detected */ -#define RXF_WOOS 0x0002 /* write frame out of sync */ -#define RXF_WF_TERM 0x0004 /* write frame terminated */ -#define RXF_ABORT 0x0008 /* write frame aborted */ -#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */ - -/* HW frame tag */ -#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ - -#define SDPCM_HWEXT_LEN 8 - -#endif /* _sbsdpcmdev_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h b/drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h deleted file mode 100755 index f9bfa969dc1b..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * BCM47XX Sonics SiliconBackplane embedded ram core - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbsocram.h 481592 2014-05-29 22:10:51Z $ - */ - -#ifndef _SBSOCRAM_H -#define _SBSOCRAM_H - -#ifndef _LANGUAGE_ASSEMBLY - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - -/* Memcsocram core registers */ -typedef volatile struct sbsocramregs { - uint32 coreinfo; - uint32 bwalloc; - uint32 extracoreinfo; - uint32 biststat; - uint32 bankidx; - uint32 standbyctrl; - - uint32 errlogstatus; /* rev 6 */ - uint32 errlogaddr; /* rev 6 */ - /* used for patching rev 3 & 5 */ - uint32 cambankidx; - uint32 cambankstandbyctrl; - uint32 cambankpatchctrl; - uint32 cambankpatchtblbaseaddr; - uint32 cambankcmdreg; - uint32 cambankdatareg; - uint32 cambankmaskreg; - uint32 PAD[1]; - uint32 bankinfo; /* corev 8 */ - uint32 bankpda; - uint32 PAD[14]; - uint32 extmemconfig; - uint32 extmemparitycsr; - uint32 extmemparityerrdata; - uint32 extmemparityerrcnt; - uint32 extmemwrctrlandsize; - uint32 PAD[84]; - uint32 workaround; - uint32 pwrctl; /* corerev >= 2 */ - uint32 PAD[133]; - uint32 sr_control; /* corerev >= 15 */ - uint32 sr_status; /* corerev >= 15 */ - uint32 sr_address; /* corerev >= 15 */ - uint32 sr_data; /* corerev >= 15 */ -} sbsocramregs_t; - -#endif /* _LANGUAGE_ASSEMBLY */ - -/* Register offsets */ -#define SR_COREINFO 0x00 -#define SR_BWALLOC 0x04 -#define SR_BISTSTAT 0x0c -#define SR_BANKINDEX 0x10 -#define SR_BANKSTBYCTL 0x14 -#define SR_PWRCTL 0x1e8 - -/* Coreinfo register */ -#define SRCI_PT_MASK 0x00070000 /* corerev >= 6; port type[18:16] */ -#define SRCI_PT_SHIFT 16 -/* port types : SRCI_PT__ */ -#define SRCI_PT_OCP_OCP 0 -#define SRCI_PT_AXI_OCP 1 -#define SRCI_PT_ARM7AHB_OCP 2 -#define SRCI_PT_CM3AHB_OCP 3 -#define SRCI_PT_AXI_AXI 4 -#define SRCI_PT_AHB_AXI 5 -/* corerev >= 3 */ -#define SRCI_LSS_MASK 0x00f00000 -#define SRCI_LSS_SHIFT 20 -#define SRCI_LRS_MASK 0x0f000000 -#define SRCI_LRS_SHIFT 24 - -/* In corerev 0, the memory size is 2 to the power of the - * base plus 16 plus to the contents of the memsize field plus 1. - */ -#define SRCI_MS0_MASK 0xf -#define SR_MS0_BASE 16 - -/* - * In corerev 1 the bank size is 2 ^ the bank size field plus 14, - * the memory size is number of banks times bank size. - * The same applies to rom size. - */ -#define SRCI_ROMNB_MASK 0xf000 -#define SRCI_ROMNB_SHIFT 12 -#define SRCI_ROMBSZ_MASK 0xf00 -#define SRCI_ROMBSZ_SHIFT 8 -#define SRCI_SRNB_MASK 0xf0 -#define SRCI_SRNB_SHIFT 4 -#define SRCI_SRBSZ_MASK 0xf -#define SRCI_SRBSZ_SHIFT 0 - -#define SR_BSZ_BASE 14 - -/* Standby control register */ -#define SRSC_SBYOVR_MASK 0x80000000 -#define SRSC_SBYOVR_SHIFT 31 -#define SRSC_SBYOVRVAL_MASK 0x60000000 -#define SRSC_SBYOVRVAL_SHIFT 29 -#define SRSC_SBYEN_MASK 0x01000000 /* rev >= 3 */ -#define SRSC_SBYEN_SHIFT 24 - -/* Power control register */ -#define SRPC_PMU_STBYDIS_MASK 0x00000010 /* rev >= 3 */ -#define SRPC_PMU_STBYDIS_SHIFT 4 -#define SRPC_STBYOVRVAL_MASK 0x00000008 -#define SRPC_STBYOVRVAL_SHIFT 3 -#define SRPC_STBYOVR_MASK 0x00000007 -#define SRPC_STBYOVR_SHIFT 0 - -/* Extra core capability register */ -#define SRECC_NUM_BANKS_MASK 0x000000F0 -#define SRECC_NUM_BANKS_SHIFT 4 -#define SRECC_BANKSIZE_MASK 0x0000000F -#define SRECC_BANKSIZE_SHIFT 0 - -#define SRECC_BANKSIZE(value) (1 << (value)) - -/* CAM bank patch control */ -#define SRCBPC_PATCHENABLE 0x80000000 - -#define SRP_ADDRESS 0x0001FFFC -#define SRP_VALID 0x8000 - -/* CAM bank command reg */ -#define SRCMD_WRITE 0x00020000 -#define SRCMD_READ 0x00010000 -#define SRCMD_DONE 0x80000000 - -#define SRCMD_DONE_DLY 1000 - -/* bankidx and bankinfo reg defines corerev >= 8 */ -#define SOCRAM_BANKINFO_SZMASK 0x7f -#define SOCRAM_BANKIDX_ROM_MASK 0x100 - -#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 -/* socram bankinfo memtype */ -#define SOCRAM_MEMTYPE_RAM 0 -#define SOCRAM_MEMTYPE_R0M 1 -#define SOCRAM_MEMTYPE_DEVRAM 2 - -#define SOCRAM_BANKINFO_REG 0x40 -#define SOCRAM_BANKIDX_REG 0x10 -#define SOCRAM_BANKINFO_STDBY_MASK 0x400 -#define SOCRAM_BANKINFO_STDBY_TIMER 0x800 - -/* bankinfo rev >= 10 */ -#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13 -#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000 -#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14 -#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000 -#define SOCRAM_BANKINFO_SLPSUPP_SHIFT 15 -#define SOCRAM_BANKINFO_SLPSUPP_MASK 0x8000 -#define SOCRAM_BANKINFO_RETNTRAM_SHIFT 16 -#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 -#define SOCRAM_BANKINFO_PDASZ_SHIFT 17 -#define SOCRAM_BANKINFO_PDASZ_MASK 0x003E0000 -#define SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT 24 -#define SOCRAM_BANKINFO_DEVRAMREMAP_MASK 0x01000000 - -/* extracoreinfo register */ -#define SOCRAM_DEVRAMBANK_MASK 0xF000 -#define SOCRAM_DEVRAMBANK_SHIFT 12 - -/* bank info to calculate bank size */ -#define SOCRAM_BANKINFO_SZBASE 8192 -#define SOCRAM_BANKSIZE_SHIFT 13 /* SOCRAM_BANKINFO_SZBASE */ - - -#endif /* _SBSOCRAM_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sdio.h b/drivers/net/wireless/bcmdhd_suzuran/include/sdio.h deleted file mode 100755 index 4b9573953bdf..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sdio.h +++ /dev/null @@ -1,619 +0,0 @@ -/* - * SDIO spec header file - * Protocol and standard (common) device definitions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sdio.h 416730 2013-08-06 09:33:19Z $ - */ - -#ifndef _SDIO_H -#define _SDIO_H - - -/* CCCR structure for function 0 */ -typedef volatile struct { - uint8 cccr_sdio_rev; /* RO, cccr and sdio revision */ - uint8 sd_rev; /* RO, sd spec revision */ - uint8 io_en; /* I/O enable */ - uint8 io_rdy; /* I/O ready reg */ - uint8 intr_ctl; /* Master and per function interrupt enable control */ - uint8 intr_status; /* RO, interrupt pending status */ - uint8 io_abort; /* read/write abort or reset all functions */ - uint8 bus_inter; /* bus interface control */ - uint8 capability; /* RO, card capability */ - - uint8 cis_base_low; /* 0x9 RO, common CIS base address, LSB */ - uint8 cis_base_mid; - uint8 cis_base_high; /* 0xB RO, common CIS base address, MSB */ - - /* suspend/resume registers */ - uint8 bus_suspend; /* 0xC */ - uint8 func_select; /* 0xD */ - uint8 exec_flag; /* 0xE */ - uint8 ready_flag; /* 0xF */ - - uint8 fn0_blk_size[2]; /* 0x10(LSB), 0x11(MSB) */ - - uint8 power_control; /* 0x12 (SDIO version 1.10) */ - - uint8 speed_control; /* 0x13 */ -} sdio_regs_t; - -/* SDIO Device CCCR offsets */ -#define SDIOD_CCCR_REV 0x00 -#define SDIOD_CCCR_SDREV 0x01 -#define SDIOD_CCCR_IOEN 0x02 -#define SDIOD_CCCR_IORDY 0x03 -#define SDIOD_CCCR_INTEN 0x04 -#define SDIOD_CCCR_INTPEND 0x05 -#define SDIOD_CCCR_IOABORT 0x06 -#define SDIOD_CCCR_BICTRL 0x07 -#define SDIOD_CCCR_CAPABLITIES 0x08 -#define SDIOD_CCCR_CISPTR_0 0x09 -#define SDIOD_CCCR_CISPTR_1 0x0A -#define SDIOD_CCCR_CISPTR_2 0x0B -#define SDIOD_CCCR_BUSSUSP 0x0C -#define SDIOD_CCCR_FUNCSEL 0x0D -#define SDIOD_CCCR_EXECFLAGS 0x0E -#define SDIOD_CCCR_RDYFLAGS 0x0F -#define SDIOD_CCCR_BLKSIZE_0 0x10 -#define SDIOD_CCCR_BLKSIZE_1 0x11 -#define SDIOD_CCCR_POWER_CONTROL 0x12 -#define SDIOD_CCCR_SPEED_CONTROL 0x13 -#define SDIOD_CCCR_UHSI_SUPPORT 0x14 -#define SDIOD_CCCR_DRIVER_STRENGTH 0x15 -#define SDIOD_CCCR_INTR_EXTN 0x16 - -/* Broadcom extensions (corerev >= 1) */ -#define SDIOD_CCCR_BRCM_CARDCAP 0xf0 -#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02 -#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04 -#define SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08 -#define SDIOD_CCCR_BRCM_CARDCTL 0xf1 -#define SDIOD_CCCR_BRCM_SEPINT 0xf2 - -/* cccr_sdio_rev */ -#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */ -#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */ -#define SDIO_SPEC_VERSION_3_0 0x40 /* SDIO spec version 3.0 */ - -/* sd_rev */ -#define SD_REV_PHY_MASK 0x0f /* SD format version number */ - -/* io_en */ -#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */ -#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */ - -/* io_rdys */ -#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */ -#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */ - -/* intr_ctl */ -#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */ -#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */ -#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */ - -/* intr_status */ -#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */ -#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */ - -/* io_abort */ -#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */ -#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */ - -/* bus_inter */ -#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */ -#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */ -#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */ -#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */ -#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */ -#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */ - -/* capability */ -#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */ -#define SDIO_CAP_LSC 0x40 /* low speed card */ -#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */ -#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */ -#define SDIO_CAP_SBS 0x08 /* support suspend/resume */ -#define SDIO_CAP_SRW 0x04 /* support read wait */ -#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */ -#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */ - -/* power_control */ -#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */ -#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */ - -/* speed_control (control device entry into high-speed clocking mode) */ -#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */ -#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */ -#define SDIO_SPEED_UHSI_DDR50 0x08 - -/* for setting bus speed in card: 0x13h */ -#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3) -#define SDIO_BUS_SPEED_UHSISEL_S 1 - -/* for getting bus speed cap in card: 0x14h */ -#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3) -#define SDIO_BUS_SPEED_UHSICAP_S 0 - -/* for getting driver type CAP in card: 0x15h */ -#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3) -#define SDIO_BUS_DRVR_TYPE_CAP_S 0 - -/* for setting driver type selection in card: 0x15h */ -#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2) -#define SDIO_BUS_DRVR_TYPE_SEL_S 4 - -/* for getting async int support in card: 0x16h */ -#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1) -#define SDIO_BUS_ASYNCINT_CAP_S 0 - -/* for setting async int selection in card: 0x16h */ -#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1) -#define SDIO_BUS_ASYNCINT_SEL_S 1 - -/* brcm sepint */ -#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */ -#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */ -#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */ - -/* FBR structure for function 1-7, FBR addresses and register offsets */ -typedef volatile struct { - uint8 devctr; /* device interface, CSA control */ - uint8 ext_dev; /* extended standard I/O device type code */ - uint8 pwr_sel; /* power selection support */ - uint8 PAD[6]; /* reserved */ - - uint8 cis_low; /* CIS LSB */ - uint8 cis_mid; - uint8 cis_high; /* CIS MSB */ - uint8 csa_low; /* code storage area, LSB */ - uint8 csa_mid; - uint8 csa_high; /* code storage area, MSB */ - uint8 csa_dat_win; /* data access window to function */ - - uint8 fnx_blk_size[2]; /* block size, little endian */ -} sdio_fbr_t; - -/* Maximum number of I/O funcs */ -#define SDIOD_MAX_FUNCS 8 -#define SDIOD_MAX_IOFUNCS 7 - -/* SDIO Device FBR Start Address */ -#define SDIOD_FBR_STARTADDR 0x100 - -/* SDIO Device FBR Size */ -#define SDIOD_FBR_SIZE 0x100 - -/* Macro to calculate FBR register base */ -#define SDIOD_FBR_BASE(n) ((n) * 0x100) - -/* Function register offsets */ -#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */ -#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */ -#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */ - -/* SDIO Function CIS ptr offset */ -#define SDIOD_FBR_CISPTR_0 0x09 -#define SDIOD_FBR_CISPTR_1 0x0A -#define SDIOD_FBR_CISPTR_2 0x0B - -/* Code Storage Area pointer */ -#define SDIOD_FBR_CSA_ADDR_0 0x0C -#define SDIOD_FBR_CSA_ADDR_1 0x0D -#define SDIOD_FBR_CSA_ADDR_2 0x0E -#define SDIOD_FBR_CSA_DATA 0x0F - -/* SDIO Function I/O Block Size */ -#define SDIOD_FBR_BLKSIZE_0 0x10 -#define SDIOD_FBR_BLKSIZE_1 0x11 - -/* devctr */ -#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */ -#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */ -#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */ -/* interface codes */ -#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */ -#define SDIOD_DIC_UART 1 -#define SDIOD_DIC_BLUETOOTH_A 2 -#define SDIOD_DIC_BLUETOOTH_B 3 -#define SDIOD_DIC_GPS 4 -#define SDIOD_DIC_CAMERA 5 -#define SDIOD_DIC_PHS 6 -#define SDIOD_DIC_WLAN 7 -#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */ - -/* pwr_sel */ -#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */ -#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */ - -/* misc defines */ -#define SDIO_FUNC_0 0 -#define SDIO_FUNC_1 1 -#define SDIO_FUNC_2 2 -#define SDIO_FUNC_3 3 -#define SDIO_FUNC_4 4 -#define SDIO_FUNC_5 5 -#define SDIO_FUNC_6 6 -#define SDIO_FUNC_7 7 - -#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */ -#define SD_CARD_TYPE_IO 1 /* IO only card */ -#define SD_CARD_TYPE_MEMORY 2 /* memory only card */ -#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */ - -#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */ -#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */ - -/* Card registers: status bit position */ -#define CARDREG_STATUS_BIT_OUTOFRANGE 31 -#define CARDREG_STATUS_BIT_COMCRCERROR 23 -#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22 -#define CARDREG_STATUS_BIT_ERROR 19 -#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12 -#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11 -#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10 -#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9 -#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4 - - - -#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */ -#define SD_CMD_SEND_OPCOND 1 -#define SD_CMD_MMC_SET_RCA 3 -#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */ -#define SD_CMD_SELECT_DESELECT_CARD 7 -#define SD_CMD_SEND_CSD 9 -#define SD_CMD_SEND_CID 10 -#define SD_CMD_STOP_TRANSMISSION 12 -#define SD_CMD_SEND_STATUS 13 -#define SD_CMD_GO_INACTIVE_STATE 15 -#define SD_CMD_SET_BLOCKLEN 16 -#define SD_CMD_READ_SINGLE_BLOCK 17 -#define SD_CMD_READ_MULTIPLE_BLOCK 18 -#define SD_CMD_WRITE_BLOCK 24 -#define SD_CMD_WRITE_MULTIPLE_BLOCK 25 -#define SD_CMD_PROGRAM_CSD 27 -#define SD_CMD_SET_WRITE_PROT 28 -#define SD_CMD_CLR_WRITE_PROT 29 -#define SD_CMD_SEND_WRITE_PROT 30 -#define SD_CMD_ERASE_WR_BLK_START 32 -#define SD_CMD_ERASE_WR_BLK_END 33 -#define SD_CMD_ERASE 38 -#define SD_CMD_LOCK_UNLOCK 42 -#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */ -#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */ -#define SD_CMD_APP_CMD 55 -#define SD_CMD_GEN_CMD 56 -#define SD_CMD_READ_OCR 58 -#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */ -#define SD_ACMD_SD_STATUS 13 -#define SD_ACMD_SEND_NUM_WR_BLOCKS 22 -#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23 -#define SD_ACMD_SD_SEND_OP_COND 41 -#define SD_ACMD_SET_CLR_CARD_DETECT 42 -#define SD_ACMD_SEND_SCR 51 - -/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */ -#define SD_IO_OP_READ 0 /* Read_Write: Read */ -#define SD_IO_OP_WRITE 1 /* Read_Write: Write */ -#define SD_IO_RW_NORMAL 0 /* no RAW */ -#define SD_IO_RW_RAW 1 /* RAW */ -#define SD_IO_BYTE_MODE 0 /* Byte Mode */ -#define SD_IO_BLOCK_MODE 1 /* BlockMode */ -#define SD_IO_FIXED_ADDRESS 0 /* fix Address */ -#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */ - -/* build SD_CMD_IO_RW_DIRECT Argument */ -#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \ - ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \ - (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF)) - -/* build SD_CMD_IO_RW_EXTENDED Argument */ -#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \ - ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \ - (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF)) - -/* SDIO response parameters */ -#define SD_RSP_NO_NONE 0 -#define SD_RSP_NO_1 1 -#define SD_RSP_NO_2 2 -#define SD_RSP_NO_3 3 -#define SD_RSP_NO_4 4 -#define SD_RSP_NO_5 5 -#define SD_RSP_NO_6 6 - - /* Modified R6 response (to CMD3) */ -#define SD_RSP_MR6_COM_CRC_ERROR 0x8000 -#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000 -#define SD_RSP_MR6_ERROR 0x2000 - - /* Modified R1 in R4 Response (to CMD5) */ -#define SD_RSP_MR1_SBIT 0x80 -#define SD_RSP_MR1_PARAMETER_ERROR 0x40 -#define SD_RSP_MR1_RFU5 0x20 -#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10 -#define SD_RSP_MR1_COM_CRC_ERROR 0x08 -#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04 -#define SD_RSP_MR1_RFU1 0x02 -#define SD_RSP_MR1_IDLE_STATE 0x01 - - /* R5 response (to CMD52 and CMD53) */ -#define SD_RSP_R5_COM_CRC_ERROR 0x80 -#define SD_RSP_R5_ILLEGAL_COMMAND 0x40 -#define SD_RSP_R5_IO_CURRENTSTATE1 0x20 -#define SD_RSP_R5_IO_CURRENTSTATE0 0x10 -#define SD_RSP_R5_ERROR 0x08 -#define SD_RSP_R5_RFU 0x04 -#define SD_RSP_R5_FUNC_NUM_ERROR 0x02 -#define SD_RSP_R5_OUT_OF_RANGE 0x01 - -#define SD_RSP_R5_ERRBITS 0xCB - - -/* ------------------------------------------------ - * SDIO Commands and responses - * - * I/O only commands are: - * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53 - * ------------------------------------------------ - */ - -/* SDIO Commands */ -#define SDIOH_CMD_0 0 -#define SDIOH_CMD_3 3 -#define SDIOH_CMD_5 5 -#define SDIOH_CMD_7 7 -#define SDIOH_CMD_11 11 -#define SDIOH_CMD_14 14 -#define SDIOH_CMD_15 15 -#define SDIOH_CMD_19 19 -#define SDIOH_CMD_52 52 -#define SDIOH_CMD_53 53 -#define SDIOH_CMD_59 59 - -/* SDIO Command Responses */ -#define SDIOH_RSP_NONE 0 -#define SDIOH_RSP_R1 1 -#define SDIOH_RSP_R2 2 -#define SDIOH_RSP_R3 3 -#define SDIOH_RSP_R4 4 -#define SDIOH_RSP_R5 5 -#define SDIOH_RSP_R6 6 - -/* - * SDIO Response Error flags - */ -#define SDIOH_RSP5_ERROR_FLAGS 0xCB - -/* ------------------------------------------------ - * SDIO Command structures. I/O only commands are: - * - * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53 - * ------------------------------------------------ - */ - -#define CMD5_OCR_M BITFIELD_MASK(24) -#define CMD5_OCR_S 0 - -#define CMD5_S18R_M BITFIELD_MASK(1) -#define CMD5_S18R_S 24 - -#define CMD7_RCA_M BITFIELD_MASK(16) -#define CMD7_RCA_S 16 - -#define CMD14_RCA_M BITFIELD_MASK(16) -#define CMD14_RCA_S 16 -#define CMD14_SLEEP_M BITFIELD_MASK(1) -#define CMD14_SLEEP_S 15 - -#define CMD_15_RCA_M BITFIELD_MASK(16) -#define CMD_15_RCA_S 16 - -#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52 - */ -#define CMD52_DATA_S 0 -#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ -#define CMD52_REG_ADDR_S 9 -#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */ -#define CMD52_RAW_S 27 -#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ -#define CMD52_FUNCTION_S 28 -#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ -#define CMD52_RW_FLAG_S 31 - - -#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */ -#define CMD53_BYTE_BLK_CNT_S 0 -#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ -#define CMD53_REG_ADDR_S 9 -#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */ -#define CMD53_OP_CODE_S 26 -#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */ -#define CMD53_BLK_MODE_S 27 -#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ -#define CMD53_FUNCTION_S 28 -#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ -#define CMD53_RW_FLAG_S 31 - -/* ------------------------------------------------------ - * SDIO Command Response structures for SD1 and SD4 modes - * ----------------------------------------------------- - */ -#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */ -#define RSP4_IO_OCR_S 0 - -#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */ -#define RSP4_S18A_S 24 - -#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */ -#define RSP4_STUFF_S 24 -#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */ -#define RSP4_MEM_PRESENT_S 27 -#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */ -#define RSP4_NUM_FUNCS_S 28 -#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */ -#define RSP4_CARD_READY_S 31 - -#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0] - */ -#define RSP6_STATUS_S 0 -#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */ -#define RSP6_IO_RCA_S 16 - -#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */ -#define RSP1_AKE_SEQ_ERROR_S 3 -#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ -#define RSP1_APP_CMD_S 5 -#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */ -#define RSP1_READY_FOR_DATA_S 8 -#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card - * when Cmd was received - */ -#define RSP1_CURR_STATE_S 9 -#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */ -#define RSP1_EARSE_RESET_S 13 -#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */ -#define RSP1_CARD_ECC_DISABLE_S 14 -#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */ -#define RSP1_WP_ERASE_SKIP_S 15 -#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits - * of CSD - */ -#define RSP1_CID_CSD_OVERW_S 16 -#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */ -#define RSP1_ERROR_S 19 -#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */ -#define RSP1_CC_ERROR_S 20 -#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed - * to correct data - */ -#define RSP1_CARD_ECC_FAILED_S 21 -#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */ -#define RSP1_ILLEGAL_CMD_S 22 -#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed - */ -#define RSP1_COM_CRC_ERROR_S 23 -#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */ -#define RSP1_LOCK_UNLOCK_FAIL_S 24 -#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */ -#define RSP1_CARD_LOCKED_S 25 -#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program - * write-protected blocks - */ -#define RSP1_WP_VIOLATION_S 26 -#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */ -#define RSP1_ERASE_PARAM_S 27 -#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */ -#define RSP1_ERASE_SEQ_ERR_S 28 -#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */ -#define RSP1_BLK_LEN_ERR_S 29 -#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */ -#define RSP1_ADDR_ERR_S 30 -#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */ -#define RSP1_OUT_OF_RANGE_S 31 - - -#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */ -#define RSP5_DATA_S 0 -#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */ -#define RSP5_FLAGS_S 8 -#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */ -#define RSP5_STUFF_S 16 - -/* ---------------------------------------------- - * SDIO Command Response structures for SPI mode - * ---------------------------------------------- - */ -#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */ -#define SPIRSP4_IO_OCR_S 0 -#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */ -#define SPIRSP4_STUFF_S 16 -#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */ -#define SPIRSP4_MEM_PRESENT_S 19 -#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */ -#define SPIRSP4_NUM_FUNCS_S 20 -#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */ -#define SPIRSP4_CARD_READY_S 23 -#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */ -#define SPIRSP4_IDLE_STATE_S 24 -#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ -#define SPIRSP4_ILLEGAL_CMD_S 26 -#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ -#define SPIRSP4_COM_CRC_ERROR_S 27 -#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error - */ -#define SPIRSP4_FUNC_NUM_ERROR_S 28 -#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ -#define SPIRSP4_PARAM_ERROR_S 30 -#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ -#define SPIRSP4_START_BIT_S 31 - -#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */ -#define SPIRSP5_DATA_S 16 -#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */ -#define SPIRSP5_IDLE_STATE_S 24 -#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ -#define SPIRSP5_ILLEGAL_CMD_S 26 -#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ -#define SPIRSP5_COM_CRC_ERROR_S 27 -#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error - */ -#define SPIRSP5_FUNC_NUM_ERROR_S 28 -#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ -#define SPIRSP5_PARAM_ERROR_S 30 -#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ -#define SPIRSP5_START_BIT_S 31 - -/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */ -#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error - */ -#define RSP6STAT_AKE_SEQ_ERROR_S 3 -#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ -#define RSP6STAT_APP_CMD_S 5 -#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data - * (buff empty) - */ -#define RSP6STAT_READY_FOR_DATA_S 8 -#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at - * Cmd reception - */ -#define RSP6STAT_CURR_STATE_S 9 -#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19 - */ -#define RSP6STAT_ERROR_S 13 -#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for - * card state Bit 22 - */ -#define RSP6STAT_ILLEGAL_CMD_S 14 -#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command - * failed Bit 23 - */ -#define RSP6STAT_COM_CRC_ERROR_S 15 - -#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ -#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE - -/* command issue options */ -#define CMD_OPTION_DEFAULT 0 -#define CMD_OPTION_TUNING 1 -#endif /* _SDIO_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h b/drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h deleted file mode 100755 index 754e01f6d6db..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h +++ /dev/null @@ -1,445 +0,0 @@ -/* - * SDIO Host Controller Spec header file - * Register map and definitions for the Standard Host Controller - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sdioh.h 345499 2012-07-18 06:59:05Z $ - */ - -#ifndef _SDIOH_H -#define _SDIOH_H - -#define SD_SysAddr 0x000 -#define SD_BlockSize 0x004 -#define SD_BlockCount 0x006 -#define SD_Arg0 0x008 -#define SD_Arg1 0x00A -#define SD_TransferMode 0x00C -#define SD_Command 0x00E -#define SD_Response0 0x010 -#define SD_Response1 0x012 -#define SD_Response2 0x014 -#define SD_Response3 0x016 -#define SD_Response4 0x018 -#define SD_Response5 0x01A -#define SD_Response6 0x01C -#define SD_Response7 0x01E -#define SD_BufferDataPort0 0x020 -#define SD_BufferDataPort1 0x022 -#define SD_PresentState 0x024 -#define SD_HostCntrl 0x028 -#define SD_PwrCntrl 0x029 -#define SD_BlockGapCntrl 0x02A -#define SD_WakeupCntrl 0x02B -#define SD_ClockCntrl 0x02C -#define SD_TimeoutCntrl 0x02E -#define SD_SoftwareReset 0x02F -#define SD_IntrStatus 0x030 -#define SD_ErrorIntrStatus 0x032 -#define SD_IntrStatusEnable 0x034 -#define SD_ErrorIntrStatusEnable 0x036 -#define SD_IntrSignalEnable 0x038 -#define SD_ErrorIntrSignalEnable 0x03A -#define SD_CMD12ErrorStatus 0x03C -#define SD_Capabilities 0x040 -#define SD_Capabilities3 0x044 -#define SD_MaxCurCap 0x048 -#define SD_MaxCurCap_Reserved 0x04C -#define SD_ADMA_ErrStatus 0x054 -#define SD_ADMA_SysAddr 0x58 -#define SD_SlotInterruptStatus 0x0FC -#define SD_HostControllerVersion 0x0FE -#define SD_GPIO_Reg 0x100 -#define SD_GPIO_OE 0x104 -#define SD_GPIO_Enable 0x108 - -/* SD specific registers in PCI config space */ -#define SD_SlotInfo 0x40 - -/* HC 3.0 specific registers and offsets */ -#define SD3_HostCntrl2 0x03E -/* preset regsstart and count */ -#define SD3_PresetValStart 0x060 -#define SD3_PresetValCount 8 -/* preset-indiv regs */ -#define SD3_PresetVal_init 0x060 -#define SD3_PresetVal_default 0x062 -#define SD3_PresetVal_HS 0x064 -#define SD3_PresetVal_SDR12 0x066 -#define SD3_PresetVal_SDR25 0x068 -#define SD3_PresetVal_SDR50 0x06a -#define SD3_PresetVal_SDR104 0x06c -#define SD3_PresetVal_DDR50 0x06e -/* SDIO3.0 Revx specific Registers */ -#define SD3_Tuning_Info_Register 0x0EC -#define SD3_WL_BT_reset_register 0x0F0 - - -/* preset value indices */ -#define SD3_PRESETVAL_INITIAL_IX 0 -#define SD3_PRESETVAL_DESPEED_IX 1 -#define SD3_PRESETVAL_HISPEED_IX 2 -#define SD3_PRESETVAL_SDR12_IX 3 -#define SD3_PRESETVAL_SDR25_IX 4 -#define SD3_PRESETVAL_SDR50_IX 5 -#define SD3_PRESETVAL_SDR104_IX 6 -#define SD3_PRESETVAL_DDR50_IX 7 - -/* SD_Capabilities reg (0x040) */ -#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6) -#define CAP_TO_CLKFREQ_S 0 -#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1) -#define CAP_TO_CLKUNIT_S 7 -/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2 - bits are reserved. going ahead with 8 bits, as it is req for 3.0 -*/ -#define CAP_BASECLK_M BITFIELD_MASK(8) -#define CAP_BASECLK_S 8 -#define CAP_MAXBLOCK_M BITFIELD_MASK(2) -#define CAP_MAXBLOCK_S 16 -#define CAP_ADMA2_M BITFIELD_MASK(1) -#define CAP_ADMA2_S 19 -#define CAP_ADMA1_M BITFIELD_MASK(1) -#define CAP_ADMA1_S 20 -#define CAP_HIGHSPEED_M BITFIELD_MASK(1) -#define CAP_HIGHSPEED_S 21 -#define CAP_DMA_M BITFIELD_MASK(1) -#define CAP_DMA_S 22 -#define CAP_SUSPEND_M BITFIELD_MASK(1) -#define CAP_SUSPEND_S 23 -#define CAP_VOLT_3_3_M BITFIELD_MASK(1) -#define CAP_VOLT_3_3_S 24 -#define CAP_VOLT_3_0_M BITFIELD_MASK(1) -#define CAP_VOLT_3_0_S 25 -#define CAP_VOLT_1_8_M BITFIELD_MASK(1) -#define CAP_VOLT_1_8_S 26 -#define CAP_64BIT_HOST_M BITFIELD_MASK(1) -#define CAP_64BIT_HOST_S 28 - -#define SDIO_OCR_READ_FAIL (2) - - -#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1) -#define CAP_ASYNCINT_SUP_S 29 - -#define CAP_SLOTTYPE_M BITFIELD_MASK(2) -#define CAP_SLOTTYPE_S 30 - -#define CAP3_MSBits_OFFSET (32) -/* note: following are caps MSB32 bits. - So the bits start from 0, instead of 32. that is why - CAP3_MSBits_OFFSET is subtracted. -*/ -#define CAP3_SDR50_SUP_M BITFIELD_MASK(1) -#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET) - -#define CAP3_SDR104_SUP_M BITFIELD_MASK(1) -#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET) - -#define CAP3_DDR50_SUP_M BITFIELD_MASK(1) -#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET) - -/* for knowing the clk caps in a single read */ -#define CAP3_30CLKCAP_M BITFIELD_MASK(3) -#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET) - -#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1) -#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET) - -#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1) -#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET) - -#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1) -#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET) - -#define CAP3_RETUNING_TC_M BITFIELD_MASK(4) -#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET) - -#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1) -#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET) - -#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2) -#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET) - -#define CAP3_CLK_MULT_M BITFIELD_MASK(8) -#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET) - -#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2) -#define PRESET_DRIVR_SELECT_S 14 - -#define PRESET_CLK_DIV_M BITFIELD_MASK(10) -#define PRESET_CLK_DIV_S 0 - -/* SD_MaxCurCap reg (0x048) */ -#define CAP_CURR_3_3_M BITFIELD_MASK(8) -#define CAP_CURR_3_3_S 0 -#define CAP_CURR_3_0_M BITFIELD_MASK(8) -#define CAP_CURR_3_0_S 8 -#define CAP_CURR_1_8_M BITFIELD_MASK(8) -#define CAP_CURR_1_8_S 16 - -/* SD_SysAddr: Offset 0x0000, Size 4 bytes */ - -/* SD_BlockSize: Offset 0x004, Size 2 bytes */ -#define BLKSZ_BLKSZ_M BITFIELD_MASK(12) -#define BLKSZ_BLKSZ_S 0 -#define BLKSZ_BNDRY_M BITFIELD_MASK(3) -#define BLKSZ_BNDRY_S 12 - -/* SD_BlockCount: Offset 0x006, size 2 bytes */ - -/* SD_Arg0: Offset 0x008, size = 4 bytes */ -/* SD_TransferMode Offset 0x00C, size = 2 bytes */ -#define XFER_DMA_ENABLE_M BITFIELD_MASK(1) -#define XFER_DMA_ENABLE_S 0 -#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1) -#define XFER_BLK_COUNT_EN_S 1 -#define XFER_CMD_12_EN_M BITFIELD_MASK(1) -#define XFER_CMD_12_EN_S 2 -#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1) -#define XFER_DATA_DIRECTION_S 4 -#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1) -#define XFER_MULTI_BLOCK_S 5 - -/* SD_Command: Offset 0x00E, size = 2 bytes */ -/* resp_type field */ -#define RESP_TYPE_NONE 0 -#define RESP_TYPE_136 1 -#define RESP_TYPE_48 2 -#define RESP_TYPE_48_BUSY 3 -/* type field */ -#define CMD_TYPE_NORMAL 0 -#define CMD_TYPE_SUSPEND 1 -#define CMD_TYPE_RESUME 2 -#define CMD_TYPE_ABORT 3 - -#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */ -#define CMD_RESP_TYPE_S 0 -#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */ -#define CMD_CRC_EN_S 3 -#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */ -#define CMD_INDEX_EN_S 4 -#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */ -#define CMD_DATA_EN_S 5 -#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc - */ -#define CMD_TYPE_S 6 -#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */ -#define CMD_INDEX_S 8 - -/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */ -/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */ -/* SD_PresentState : Offset 0x024, size = 4 bytes */ -#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */ -#define PRES_CMD_INHIBIT_S 0 -#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */ -#define PRES_DAT_INHIBIT_S 1 -#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */ -#define PRES_DAT_BUSY_S 2 -#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */ -#define PRES_PRESENT_RSVD_S 3 -#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */ -#define PRES_WRITE_ACTIVE_S 8 -#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */ -#define PRES_READ_ACTIVE_S 9 -#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */ -#define PRES_WRITE_DATA_RDY_S 10 -#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */ -#define PRES_READ_DATA_RDY_S 11 -#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */ -#define PRES_CARD_PRESENT_S 16 -#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */ -#define PRES_CARD_STABLE_S 17 -#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */ -#define PRES_CARD_PRESENT_RAW_S 18 -#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */ -#define PRES_WRITE_ENABLED_S 19 -#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */ -#define PRES_DAT_SIGNAL_S 20 -#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */ -#define PRES_CMD_SIGNAL_S 24 - -/* SD_HostCntrl: Offset 0x028, size = 1 bytes */ -#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */ -#define HOST_LED_S 0 -#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */ -#define HOST_DATA_WIDTH_S 1 -#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */ -#define HOST_DMA_SEL_S 3 -#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */ -#define HOST_HI_SPEED_EN_S 2 - -/* Host Control2: */ -#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */ - -#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */ - -#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */ - -#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */ - -#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */ -#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */ - -#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */ -#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */ - -#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */ -#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */ - -#define HOST_CONTR_VER_2 (1) -#define HOST_CONTR_VER_3 (2) - -/* misc defines */ -#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */ -#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */ - -/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */ -#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */ -#define PWR_BUS_EN_S 0 -#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */ -#define PWR_VOLTS_S 1 - -/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */ -#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */ -#define SW_RESET_ALL_S 0 -#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */ -#define SW_RESET_CMD_S 1 -#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */ -#define SW_RESET_DAT_S 2 - -/* SD_IntrStatus: Offset 0x030, size = 2 bytes */ -/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */ -#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */ -#define INTSTAT_CMD_COMPLETE_S 0 -#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1) -#define INTSTAT_XFER_COMPLETE_S 1 -#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1) -#define INTSTAT_BLOCK_GAP_EVENT_S 2 -#define INTSTAT_DMA_INT_M BITFIELD_MASK(1) -#define INTSTAT_DMA_INT_S 3 -#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1) -#define INTSTAT_BUF_WRITE_READY_S 4 -#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1) -#define INTSTAT_BUF_READ_READY_S 5 -#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1) -#define INTSTAT_CARD_INSERTION_S 6 -#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1) -#define INTSTAT_CARD_REMOVAL_S 7 -#define INTSTAT_CARD_INT_M BITFIELD_MASK(1) -#define INTSTAT_CARD_INT_S 8 -#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */ -#define INTSTAT_RETUNING_INT_S 12 -#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */ -#define INTSTAT_ERROR_INT_S 15 - -/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */ -/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */ -#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1) -#define ERRINT_CMD_TIMEOUT_S 0 -#define ERRINT_CMD_CRC_M BITFIELD_MASK(1) -#define ERRINT_CMD_CRC_S 1 -#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1) -#define ERRINT_CMD_ENDBIT_S 2 -#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1) -#define ERRINT_CMD_INDEX_S 3 -#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1) -#define ERRINT_DATA_TIMEOUT_S 4 -#define ERRINT_DATA_CRC_M BITFIELD_MASK(1) -#define ERRINT_DATA_CRC_S 5 -#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1) -#define ERRINT_DATA_ENDBIT_S 6 -#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1) -#define ERRINT_CURRENT_LIMIT_S 7 -#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1) -#define ERRINT_AUTO_CMD12_S 8 -#define ERRINT_VENDOR_M BITFIELD_MASK(4) -#define ERRINT_VENDOR_S 12 -#define ERRINT_ADMA_M BITFIELD_MASK(1) -#define ERRINT_ADMA_S 9 - -/* Also provide definitions in "normal" form to allow combined masks */ -#define ERRINT_CMD_TIMEOUT_BIT 0x0001 -#define ERRINT_CMD_CRC_BIT 0x0002 -#define ERRINT_CMD_ENDBIT_BIT 0x0004 -#define ERRINT_CMD_INDEX_BIT 0x0008 -#define ERRINT_DATA_TIMEOUT_BIT 0x0010 -#define ERRINT_DATA_CRC_BIT 0x0020 -#define ERRINT_DATA_ENDBIT_BIT 0x0040 -#define ERRINT_CURRENT_LIMIT_BIT 0x0080 -#define ERRINT_AUTO_CMD12_BIT 0x0100 -#define ERRINT_ADMA_BIT 0x0200 - -/* Masks to select CMD vs. DATA errors */ -#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\ - ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT) -#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\ - ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT) -#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS) - -/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */ -/* SD_ClockCntrl : Offset 0x02C , size = bytes */ -/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */ -/* SD_IntrStatus : Offset 0x030 , size = bytes */ -/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */ -/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */ -/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */ -/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */ -/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */ -/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */ -/* SD_Capabilities : Offset 0x040 , size = bytes */ -/* SD_MaxCurCap : Offset 0x048 , size = bytes */ -/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */ -/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */ -/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */ - -/* SDIO Host Control Register DMA Mode Definitions */ -#define SDIOH_SDMA_MODE 0 -#define SDIOH_ADMA1_MODE 1 -#define SDIOH_ADMA2_MODE 2 -#define SDIOH_ADMA2_64_MODE 3 - -#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ -#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ -#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ -#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ -#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ -#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ -#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ -#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ - -/* ADMA2 Descriptor Table Entry for 32-bit Address */ -typedef struct adma2_dscr_32b { - uint32 len_attr; - uint32 phys_addr; -} adma2_dscr_32b_t; - -/* ADMA1 Descriptor Table Entry */ -typedef struct adma1_dscr { - uint32 phys_addr_attr; -} adma1_dscr_t; - -#endif /* _SDIOH_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h b/drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h deleted file mode 100755 index 734a17d6a34c..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Structure used by apps whose drivers access SDIO drivers. - * Pulled out separately so dhdu and wlu can both use it. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sdiovar.h 241182 2011-02-17 21:50:03Z $ - */ - -#ifndef _sdiovar_h_ -#define _sdiovar_h_ - -#include - -/* require default structure packing */ -#define BWL_DEFAULT_PACKING -#include - -typedef struct sdreg { - int func; - int offset; - int value; -} sdreg_t; - -/* Common msglevel constants */ -#define SDH_ERROR_VAL 0x0001 /* Error */ -#define SDH_TRACE_VAL 0x0002 /* Trace */ -#define SDH_INFO_VAL 0x0004 /* Info */ -#define SDH_DEBUG_VAL 0x0008 /* Debug */ -#define SDH_DATA_VAL 0x0010 /* Data */ -#define SDH_CTRL_VAL 0x0020 /* Control Regs */ -#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ -#define SDH_DMA_VAL 0x0080 /* DMA */ - -#define NUM_PREV_TRANSACTIONS 16 - - -#include - -#endif /* _sdiovar_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/siutils.h b/drivers/net/wireless/bcmdhd_suzuran/include/siutils.h deleted file mode 100755 index 5ea12f196284..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/siutils.h +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Misc utility routines for accessing the SOC Interconnects - * of Broadcom HNBU chips. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: siutils.h 481592 2014-05-29 22:10:51Z $ - */ - -#ifndef _siutils_h_ -#define _siutils_h_ - - -#include -/* - * Data structure to export all chip specific common variables - * public (read-only) portion of siutils handle returned by si_attach()/si_kattach() - */ -struct si_pub { - uint socitype; /* SOCI_SB, SOCI_AI */ - - uint bustype; /* SI_BUS, PCI_BUS */ - 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 */ - uint32 cccaps; /* chip common capabilities */ - uint32 cccaps_ext; /* chip common capabilities extension */ - int pmurev; /* pmu core rev */ - uint32 pmucaps; /* pmu capabilities */ - uint boardtype; /* board type */ - uint boardrev; /* board rev */ - 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 */ - uint32 chipst; /* chip status */ - bool issim; /* chip is in simulation or emulation */ - uint socirev; /* SOC interconnect rev */ - bool pci_pr32414; - -}; - -/* for HIGH_ONLY driver, the si_t must be writable to allow states sync from BMAC to HIGH driver - * for monolithic driver, it is readonly to prevent accident change - */ -typedef const struct si_pub si_t; - - -/* - * 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. - */ -#define SI_OSH NULL /* Use for si_kattach when no osh is available */ - -#define BADIDX (SI_MAXCORES + 1) - -/* 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 - -#define ISSIM_ENAB(sih) FALSE - -/* PMU clock/power control */ -#if defined(BCMPMUCTL) -#define PMUCTL_ENAB(sih) (BCMPMUCTL) -#else -#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU) -#endif - -/* chipcommon clock/power control (exclusive with PMU's) */ -#if defined(BCMPMUCTL) && BCMPMUCTL -#define CCCTL_ENAB(sih) (0) -#define CCPLL_ENAB(sih) (0) -#else -#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL) -#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK) -#endif - -typedef void (*gpio_handler_t)(uint32 stat, void *arg); -typedef void (*gci_gpio_handler_t)(uint32 stat, void *arg); -/* External BT Coex enable mask */ -#define CC_BTCOEX_EN_MASK 0x01 -/* External PA enable mask */ -#define GPIO_CTRL_EPA_EN_MASK 0x40 -/* WL/BT control enable mask */ -#define GPIO_CTRL_5_6_EN_MASK 0x60 -#define GPIO_CTRL_7_6_EN_MASK 0xC0 -#define GPIO_OUT_7_EN_MASK 0x80 - - -/* CR4 specific defines used by the host driver */ -#define SI_CR4_CAP (0x04) -#define SI_CR4_BANKIDX (0x40) -#define SI_CR4_BANKINFO (0x44) -#define SI_CR4_BANKPDA (0x4C) - -#define ARMCR4_TCBBNB_MASK 0xf0 -#define ARMCR4_TCBBNB_SHIFT 4 -#define ARMCR4_TCBANB_MASK 0xf -#define ARMCR4_TCBANB_SHIFT 0 - -#define SICF_CPUHALT (0x0020) -#define ARMCR4_BSZ_MASK 0x3f -#define ARMCR4_BSZ_MULT 8192 - -/* === exported functions === */ -extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, - void *sdh, char **vars, uint *varsz); -extern si_t *si_kattach(osl_t *osh); -extern void si_detach(si_t *sih); -extern bool si_pci_war16165(si_t *sih); - -extern uint si_corelist(si_t *sih, uint coreid[]); -extern uint si_coreid(si_t *sih); -extern uint si_flag(si_t *sih); -extern uint si_flag_alt(si_t *sih); -extern uint si_intflag(si_t *sih); -extern uint si_coreidx(si_t *sih); -extern uint si_coreunit(si_t *sih); -extern uint si_corevendor(si_t *sih); -extern uint si_corerev(si_t *sih); -extern void *si_osh(si_t *sih); -extern void si_setosh(si_t *sih, osl_t *osh); -extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -extern uint32 *si_corereg_addr(si_t *sih, uint coreidx, uint regoff); -extern void *si_coreregs(si_t *sih); -extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); -extern uint si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val); -extern void *si_wrapperregs(si_t *sih); -extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); -extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); -extern bool si_iscoreup(si_t *sih); -extern uint si_numcoreunits(si_t *sih, uint coreid); -extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); -extern void *si_setcoreidx(si_t *sih, uint coreidx); -extern void *si_setcore(si_t *sih, uint coreid, uint coreunit); -extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); -extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); -extern int si_numaddrspaces(si_t *sih); -extern uint32 si_addrspace(si_t *sih, uint asidx); -extern uint32 si_addrspacesize(si_t *sih, uint asidx); -extern void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); -extern int si_corebist(si_t *sih); -extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -extern void si_core_disable(si_t *sih, uint32 bits); -extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); -extern uint si_chip_hostif(si_t *sih); -extern bool si_read_pmu_autopll(si_t *sih); -extern uint32 si_clock(si_t *sih); -extern uint32 si_alp_clock(si_t *sih); -extern uint32 si_ilp_clock(si_t *sih); -extern void si_pci_setup(si_t *sih, uint coremask); -extern void si_pcmcia_init(si_t *sih); -extern void si_setint(si_t *sih, int siflag); -extern bool si_backplane64(si_t *sih); -extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, - void *intrsenabled_fn, void *intr_arg); -extern void si_deregister_intr_callback(si_t *sih); -extern void si_clkctl_init(si_t *sih); -extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); -extern bool si_clkctl_cc(si_t *sih, uint mode); -extern int si_clkctl_xtal(si_t *sih, uint what, bool on); -extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); -extern void si_btcgpiowar(si_t *sih); -extern bool si_deviceremoved(si_t *sih); -extern uint32 si_socram_size(si_t *sih); -extern uint32 si_socdevram_size(si_t *sih); -extern uint32 si_socram_srmem_size(si_t *sih); -extern void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda); -extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect, uint8 *remap); -extern bool si_socdevram_pkg(si_t *sih); -extern bool si_socdevram_remap_isenb(si_t *sih); -extern uint32 si_socdevram_remap_size(si_t *sih); - -extern void si_watchdog(si_t *sih, uint ticks); -extern void si_watchdog_ms(si_t *sih, uint32 ms); -extern uint32 si_watchdog_msticks(void); -extern void *si_gpiosetcore(si_t *sih); -extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpioin(si_t *sih); -extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); -extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); -extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); -extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); -extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); -extern uint32 si_gpio_int_enable(si_t *sih, bool enable); -extern void si_gci_enable_gpio(si_t *sih, uint8 gpio, uint32 mask, uint32 value); -extern uint8 si_gci_host_wake_gpio_init(si_t *sih); -extern void si_gci_host_wake_gpio_enable(si_t *sih, uint8 gpio, bool state); - -/* GPIO event handlers */ -extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg); -extern void si_gpio_handler_unregister(si_t *sih, void* gpioh); -extern void si_gpio_handler_process(si_t *sih); - -/* GCI interrupt handlers */ -extern void si_gci_handler_process(si_t *sih); - -/* GCI GPIO event handlers */ -extern void *si_gci_gpioint_handler_register(si_t *sih, uint8 gpio, uint8 sts, - gci_gpio_handler_t cb, void *arg); -extern void si_gci_gpioint_handler_unregister(si_t *sih, void* gci_i); - -/* Wake-on-wireless-LAN (WOWL) */ -extern bool si_pci_pmecap(si_t *sih); -struct osl_info; -extern bool si_pci_fastpmecap(struct osl_info *osh); -extern bool si_pci_pmestat(si_t *sih); -extern void si_pci_pmeclr(si_t *sih); -extern void si_pci_pmeen(si_t *sih); -extern void si_pci_pmestatclr(si_t *sih); -extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); -extern uint si_pcie_writereg(void *sih, uint addrtype, uint offset, uint val); - - -extern void si_sdio_init(si_t *sih); - -extern uint16 si_d11_devid(si_t *sih); -extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, - uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); - -#define si_eci(sih) 0 -static INLINE void * si_eci_init(si_t *sih) {return NULL;} -#define si_eci_notify_bt(sih, type, val) (0) -#define si_seci(sih) 0 -#define si_seci_upd(sih, a) do {} while (0) -static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} -static INLINE void * si_gci_init(si_t *sih) {return NULL;} -#define si_seci_down(sih) do {} while (0) -#define si_gci(sih) 0 - -/* OTP status */ -extern bool si_is_otp_disabled(si_t *sih); -extern bool si_is_otp_powered(si_t *sih); -extern void si_otp_power(si_t *sih, bool on, uint32* min_res_mask); - -/* SPROM availability */ -extern bool si_is_sprom_available(si_t *sih); -extern bool si_is_sprom_enabled(si_t *sih); -extern void si_sprom_enable(si_t *sih, bool enable); - -/* OTP/SROM CIS stuff */ -extern int si_cis_source(si_t *sih); -#define CIS_DEFAULT 0 -#define CIS_SROM 1 -#define CIS_OTP 2 - -/* Fab-id information */ -#define DEFAULT_FAB 0x0 /* Original/first fab used for this chip */ -#define CSM_FAB7 0x1 /* CSM Fab7 chip */ -#define TSMC_FAB12 0x2 /* TSMC Fab12/Fab14 chip */ -#define SMIC_FAB4 0x3 /* SMIC Fab4 chip */ - -extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw); -extern uint16 si_fabid(si_t *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 si_devpath(si_t *sih, char *path, int size); -/* Read variable with prepending the devpath to the name */ -extern char *si_getdevpathvar(si_t *sih, const char *name); -extern int si_getdevpathintvar(si_t *sih, const char *name); -extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const char *name); - - -extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); -extern uint8 si_pcieltrenable(si_t *sih, uint32 mask, uint32 val); -extern uint8 si_pcieobffenable(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_pcieltr_reg(si_t *sih, uint32 reg, uint32 mask, uint32 val); -extern uint32 si_pcieltrspacing_reg(si_t *sih, uint32 mask, uint32 val); -extern uint32 si_pcieltrhysteresiscnt_reg(si_t *sih, uint32 mask, uint32 val); -extern void si_pcie_set_error_injection(si_t *sih, uint32 mode); -extern void si_pcie_set_L1substate(si_t *sih, uint32 substate); -extern uint32 si_pcie_get_L1substate(si_t *sih); -extern void si_war42780_clkreq(si_t *sih, bool clkreq); -extern void si_pci_down(si_t *sih); -extern void si_pci_up(si_t *sih); -extern void si_pci_sleep(si_t *sih); -extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); -extern void si_pcie_power_save_enable(si_t *sih, bool enable); -extern void si_pcie_extendL1timer(si_t *sih, bool extend); -extern int si_pci_fixcfg(si_t *sih); -extern void si_chippkg_set(si_t *sih, uint); - -extern void si_chipcontrl_btshd0_4331(si_t *sih, bool on); -extern void si_chipcontrl_restore(si_t *sih, uint32 val); -extern uint32 si_chipcontrl_read(si_t *sih); -extern void si_chipcontrl_epa4331(si_t *sih, bool on); -extern void si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl); -extern void si_chipcontrl_srom4360(si_t *sih, bool on); -/* Enable BT-COEX & Ex-PA for 4313 */ -extern void si_epa_4313war(si_t *sih); -extern void si_btc_enable_chipcontrol(si_t *sih); -/* BT/WL selection for 4313 bt combo >= P250 boards */ -extern void si_btcombo_p250_4313_war(si_t *sih); -extern void si_btcombo_43228_war(si_t *sih); -extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); -extern void si_pmu_synth_pwrsw_4313_war(si_t *sih); -extern uint si_pll_reset(si_t *sih); -/* === debug routines === */ - -extern bool si_taclear(si_t *sih, bool details); - - - -extern uint32 si_ccreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); -extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); -extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); -extern void si_pcie_set_request_size(si_t *sih, uint16 size); -extern uint16 si_pcie_get_request_size(si_t *sih); -extern void si_pcie_set_maxpayload_size(si_t *sih, uint16 size); -extern uint16 si_pcie_get_maxpayload_size(si_t *sih); -extern uint16 si_pcie_get_ssid(si_t *sih); -extern uint32 si_pcie_get_bar0(si_t *sih); -extern int si_pcie_configspace_cache(si_t *sih); -extern int si_pcie_configspace_restore(si_t *sih); -extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); - -char *si_getnvramflvar(si_t *sih, const char *name); - - -extern uint32 si_tcm_size(si_t *sih); -extern bool si_has_flops(si_t *sih); - -extern int si_set_sromctl(si_t *sih, uint32 value); -extern uint32 si_get_sromctl(si_t *sih); - -extern uint32 si_gci_direct(si_t *sih, uint offset, uint32 mask, uint32 val); -extern uint32 si_gci_indirect(si_t *sih, uint regidx, uint offset, uint32 mask, uint32 val); -extern uint32 si_gci_output(si_t *sih, uint reg, uint32 mask, uint32 val); -extern uint32 si_gci_input(si_t *sih, uint reg); -extern uint32 si_gci_int_enable(si_t *sih, bool enable); -extern void si_gci_reset(si_t *sih); -extern void si_ercx_init(si_t *sih); -extern void si_wci2_init(si_t *sih, uint baudrate); -extern void si_gci_seci_init(si_t *sih); -extern void si_gci_set_functionsel(si_t *sih, uint32 pin, uint8 fnsel); -extern uint8 si_gci_get_chipctrlreg_idx(uint32 pin, uint32 *regidx, uint32 *pos); -extern uint32 si_gci_chipcontrol(si_t *sih, uint reg, uint32 mask, uint32 val); -extern uint32 si_gci_chipstatus(si_t *sih, uint reg); -extern uint16 si_cc_get_reg16(uint32 reg_offs); -extern uint32 si_cc_get_reg32(uint32 reg_offs); -extern uint32 si_cc_set_reg32(uint32 reg_offs, uint32 val); -extern uint32 si_gci_preinit_upd_indirect(uint32 regidx, uint32 setval, uint32 mask); -extern uint8 si_enable_device_wake(si_t *sih, uint8 *wake_status, uint8 *cur_status); - -#define CHIPCTRLREG1 0x1 -#define CHIPCTRLREG2 0x2 -#define CHIPCTRLREG3 0x3 -#define CHIPCTRLREG4 0x4 -#define CHIPCTRLREG5 0x5 -#define MINRESMASKREG 0x618 -#define MAXRESMASKREG 0x61c -#define CHIPCTRLADDR 0x650 -#define CHIPCTRLDATA 0x654 -#define RSRCTABLEADDR 0x620 -#define RSRCUPDWNTIME 0x628 -#define PMUREG_RESREQ_MASK 0x68c - -void si_update_masks(si_t *sih); -void si_force_islanding(si_t *sih, bool enable); -extern uint32 si_pmu_res_req_timer_clr(si_t *sih); -extern void si_pmu_rfldo(si_t *sih, bool on); -extern void si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 spert_val); -extern void si_pcie_ltr_war(si_t *sih); - -/* Macro to enable clock gating changes in different cores */ -#define MEM_CLK_GATE_BIT 5 -#define GCI_CLK_GATE_BIT 18 - -#define USBAPP_CLK_BIT 0 -#define PCIE_CLK_BIT 3 -#define ARMCR4_DBG_CLK_BIT 4 -#define SAMPLE_SYNC_CLK_BIT 17 -#define PCIE_TL_CLK_BIT 18 -#define HQ_REQ_BIT 24 -#define PLL_DIV2_BIT_START 9 -#define PLL_DIV2_MASK (0x37 << PLL_DIV2_BIT_START) -#define PLL_DIV2_DIS_OP (0x37 << PLL_DIV2_BIT_START) - -#endif /* _siutils_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/spid.h b/drivers/net/wireless/bcmdhd_suzuran/include/spid.h deleted file mode 100755 index 87d8291c1987..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/spid.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SPI device spec header file - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: spid.h 358377 2012-09-23 11:30:22Z $ - */ - -#ifndef _SPI_H -#define _SPI_H - -/* - * Brcm SPI Device Register Map. - * - */ - -typedef volatile struct { - uint8 config; /* 0x00, len, endian, clock, speed, polarity, wakeup */ - uint8 response_delay; /* 0x01, read response delay in bytes (corerev < 3) */ - uint8 status_enable; /* 0x02, status-enable, intr with status, response_delay - * function selection, command/data error check - */ - uint8 reset_bp; /* 0x03, reset on wlan/bt backplane reset (corerev >= 1) */ - uint16 intr_reg; /* 0x04, Intr status register */ - uint16 intr_en_reg; /* 0x06, Intr mask register */ - uint32 status_reg; /* 0x08, RO, Status bits of last spi transfer */ - uint16 f1_info_reg; /* 0x0c, RO, enabled, ready for data transfer, blocksize */ - uint16 f2_info_reg; /* 0x0e, RO, enabled, ready for data transfer, blocksize */ - uint16 f3_info_reg; /* 0x10, RO, enabled, ready for data transfer, blocksize */ - uint32 test_read; /* 0x14, RO 0xfeedbead signature */ - uint32 test_rw; /* 0x18, RW */ - uint8 resp_delay_f0; /* 0x1c, read resp delay bytes for F0 (corerev >= 3) */ - uint8 resp_delay_f1; /* 0x1d, read resp delay bytes for F1 (corerev >= 3) */ - uint8 resp_delay_f2; /* 0x1e, read resp delay bytes for F2 (corerev >= 3) */ - uint8 resp_delay_f3; /* 0x1f, read resp delay bytes for F3 (corerev >= 3) */ -} spi_regs_t; - -/* SPI device register offsets */ -#define SPID_CONFIG 0x00 -#define SPID_RESPONSE_DELAY 0x01 -#define SPID_STATUS_ENABLE 0x02 -#define SPID_RESET_BP 0x03 /* (corerev >= 1) */ -#define SPID_INTR_REG 0x04 /* 16 bits - Interrupt status */ -#define SPID_INTR_EN_REG 0x06 /* 16 bits - Interrupt mask */ -#define SPID_STATUS_REG 0x08 /* 32 bits */ -#define SPID_F1_INFO_REG 0x0C /* 16 bits */ -#define SPID_F2_INFO_REG 0x0E /* 16 bits */ -#define SPID_F3_INFO_REG 0x10 /* 16 bits */ -#define SPID_TEST_READ 0x14 /* 32 bits */ -#define SPID_TEST_RW 0x18 /* 32 bits */ -#define SPID_RESP_DELAY_F0 0x1c /* 8 bits (corerev >= 3) */ -#define SPID_RESP_DELAY_F1 0x1d /* 8 bits (corerev >= 3) */ -#define SPID_RESP_DELAY_F2 0x1e /* 8 bits (corerev >= 3) */ -#define SPID_RESP_DELAY_F3 0x1f /* 8 bits (corerev >= 3) */ - -/* Bit masks for SPID_CONFIG device register */ -#define WORD_LENGTH_32 0x1 /* 0/1 16/32 bit word length */ -#define ENDIAN_BIG 0x2 /* 0/1 Little/Big Endian */ -#define CLOCK_PHASE 0x4 /* 0/1 clock phase delay */ -#define CLOCK_POLARITY 0x8 /* 0/1 Idle state clock polarity is low/high */ -#define HIGH_SPEED_MODE 0x10 /* 1/0 High Speed mode / Normal mode */ -#define INTR_POLARITY 0x20 /* 1/0 Interrupt active polarity is high/low */ -#define WAKE_UP 0x80 /* 0/1 Wake-up command from Host to WLAN */ - -/* Bit mask for SPID_RESPONSE_DELAY device register */ -#define RESPONSE_DELAY_MASK 0xFF /* Configurable rd response delay in multiples of 8 bits */ - -/* Bit mask for SPID_STATUS_ENABLE device register */ -#define STATUS_ENABLE 0x1 /* 1/0 Status sent/not sent to host after read/write */ -#define INTR_WITH_STATUS 0x2 /* 0/1 Do-not / do-interrupt if status is sent */ -#define RESP_DELAY_ALL 0x4 /* Applicability of resp delay to F1 or all func's read */ -#define DWORD_PKT_LEN_EN 0x8 /* Packet len denoted in dwords instead of bytes */ -#define CMD_ERR_CHK_EN 0x20 /* Command error check enable */ -#define DATA_ERR_CHK_EN 0x40 /* Data error check enable */ - -/* Bit mask for SPID_RESET_BP device register */ -#define RESET_ON_WLAN_BP_RESET 0x4 /* enable reset for WLAN backplane */ -#define RESET_ON_BT_BP_RESET 0x8 /* enable reset for BT backplane */ -#define RESET_SPI 0x80 /* reset the above enabled logic */ - -/* Bit mask for SPID_INTR_REG device register */ -#define DATA_UNAVAILABLE 0x0001 /* Requested data not available; Clear by writing a "1" */ -#define F2_F3_FIFO_RD_UNDERFLOW 0x0002 -#define F2_F3_FIFO_WR_OVERFLOW 0x0004 -#define COMMAND_ERROR 0x0008 /* Cleared by writing 1 */ -#define DATA_ERROR 0x0010 /* Cleared by writing 1 */ -#define F2_PACKET_AVAILABLE 0x0020 -#define F3_PACKET_AVAILABLE 0x0040 -#define F1_OVERFLOW 0x0080 /* Due to last write. Bkplane has pending write requests */ -#define MISC_INTR0 0x0100 -#define MISC_INTR1 0x0200 -#define MISC_INTR2 0x0400 -#define MISC_INTR3 0x0800 -#define MISC_INTR4 0x1000 -#define F1_INTR 0x2000 -#define F2_INTR 0x4000 -#define F3_INTR 0x8000 - -/* Bit mask for 32bit SPID_STATUS_REG device register */ -#define STATUS_DATA_NOT_AVAILABLE 0x00000001 -#define STATUS_UNDERFLOW 0x00000002 -#define STATUS_OVERFLOW 0x00000004 -#define STATUS_F2_INTR 0x00000008 -#define STATUS_F3_INTR 0x00000010 -#define STATUS_F2_RX_READY 0x00000020 -#define STATUS_F3_RX_READY 0x00000040 -#define STATUS_HOST_CMD_DATA_ERR 0x00000080 -#define STATUS_F2_PKT_AVAILABLE 0x00000100 -#define STATUS_F2_PKT_LEN_MASK 0x000FFE00 -#define STATUS_F2_PKT_LEN_SHIFT 9 -#define STATUS_F3_PKT_AVAILABLE 0x00100000 -#define STATUS_F3_PKT_LEN_MASK 0xFFE00000 -#define STATUS_F3_PKT_LEN_SHIFT 21 - -/* Bit mask for 16 bits SPID_F1_INFO_REG device register */ -#define F1_ENABLED 0x0001 -#define F1_RDY_FOR_DATA_TRANSFER 0x0002 -#define F1_MAX_PKT_SIZE 0x01FC - -/* Bit mask for 16 bits SPID_F2_INFO_REG device register */ -#define F2_ENABLED 0x0001 -#define F2_RDY_FOR_DATA_TRANSFER 0x0002 -#define F2_MAX_PKT_SIZE 0x3FFC - -/* Bit mask for 16 bits SPID_F3_INFO_REG device register */ -#define F3_ENABLED 0x0001 -#define F3_RDY_FOR_DATA_TRANSFER 0x0002 -#define F3_MAX_PKT_SIZE 0x3FFC - -/* Bit mask for 32 bits SPID_TEST_READ device register read in 16bit LE mode */ -#define TEST_RO_DATA_32BIT_LE 0xFEEDBEAD - -/* Maximum number of I/O funcs */ -#define SPI_MAX_IOFUNCS 4 - -#define SPI_MAX_PKT_LEN (2048*4) - -/* Misc defines */ -#define SPI_FUNC_0 0 -#define SPI_FUNC_1 1 -#define SPI_FUNC_2 2 -#define SPI_FUNC_3 3 - -#define WAIT_F2RXFIFORDY 100 -#define WAIT_F2RXFIFORDY_DELAY 20 - -#endif /* _SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h b/drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h deleted file mode 100755 index 3cd08f8e1686..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * TRX image file header format. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: trxhdr.h 349211 2012-08-07 09:45:24Z $ - */ - -#ifndef _TRX_HDR_H -#define _TRX_HDR_H - -#include - -#define TRX_MAGIC 0x30524448 /* "HDR0" */ -#define TRX_MAX_LEN 0x3B0000 /* Max length */ -#define TRX_NO_HEADER 1 /* Do not write TRX header */ -#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ -#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ -#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ -#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ -#define TRX_BOOTLOADER 0x40 /* the image is a bootloader */ - -#define TRX_V1 1 -#define TRX_V1_MAX_OFFSETS 3 /* V1: Max number of individual files */ - -#ifndef BCMTRXV2 -#define TRX_VERSION TRX_V1 /* Version 1 */ -#define TRX_MAX_OFFSET TRX_V1_MAX_OFFSETS -#endif - -/* BMAC Host driver/application like bcmdl need to support both Ver 1 as well as - * Ver 2 of trx header. To make it generic, trx_header is structure is modified - * as below where size of "offsets" field will vary as per the TRX version. - * Currently, BMAC host driver and bcmdl are modified to support TRXV2 as well. - * To make sure, other applications like "dhdl" which are yet to be enhanced to support - * TRXV2 are not broken, new macro and structure defintion take effect only when BCMTRXV2 - * is defined. - */ -struct trx_header { - uint32 magic; /* "HDR0" */ - uint32 len; /* Length of file including header */ - uint32 crc32; /* 32-bit CRC from flag_version to end of file */ - uint32 flag_version; /* 0:15 flags, 16:31 version */ -#ifndef BCMTRXV2 - uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ -#else - uint32 offsets[1]; /* Offsets of partitions from start of header */ -#endif -}; - -#ifdef BCMTRXV2 -#define TRX_VERSION TRX_V2 /* Version 2 */ -#define TRX_MAX_OFFSET TRX_V2_MAX_OFFSETS - -#define TRX_V2 2 -/* V2: Max number of individual files - * To support SDR signature + Config data region - */ -#define TRX_V2_MAX_OFFSETS 5 -#define SIZEOF_TRXHDR_V1 (sizeof(struct trx_header)+(TRX_V1_MAX_OFFSETS-1)*sizeof(uint32)) -#define SIZEOF_TRXHDR_V2 (sizeof(struct trx_header)+(TRX_V2_MAX_OFFSETS-1)*sizeof(uint32)) -#define TRX_VER(trx) (trx->flag_version>>16) -#define ISTRX_V1(trx) (TRX_VER(trx) == TRX_V1) -#define ISTRX_V2(trx) (TRX_VER(trx) == TRX_V2) -/* For V2, return size of V2 size: others, return V1 size */ -#define SIZEOF_TRX(trx) (ISTRX_V2(trx) ? SIZEOF_TRXHDR_V2: SIZEOF_TRXHDR_V1) -#else -#define SIZEOF_TRX(trx) (sizeof(struct trx_header)) -#endif /* BCMTRXV2 */ - -/* Compatibility */ -typedef struct trx_header TRXHDR, *PTRXHDR; - -#endif /* _TRX_HDR_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h b/drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h deleted file mode 100755 index 236b22862049..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * $Id: typedefs.h 453696 2014-02-06 01:10:20Z $ - */ - -#ifndef _TYPEDEFS_H_ -#define _TYPEDEFS_H_ - -#ifdef SITE_TYPEDEFS - -/* - * Define SITE_TYPEDEFS in the compile to include a site-specific - * typedef file "site_typedefs.h". - * - * If SITE_TYPEDEFS is not defined, then the code section below makes - * inferences about the compile environment based on defined symbols and - * possibly compiler pragmas. - * - * Following these two sections is the Default Typedefs section. - * This section is only processed if USE_TYPEDEF_DEFAULTS is - * defined. This section has a default set of typedefs and a few - * preprocessor symbols (TRUE, FALSE, NULL, ...). - */ - -#include "site_typedefs.h" - -#else - -/* - * Infer the compile environment based on preprocessor symbols and pragmas. - * Override type definitions as needed, and include configuration-dependent - * header files to define types. - */ - -#ifdef __cplusplus - -#define TYPEDEF_BOOL -#ifndef FALSE -#define FALSE false -#endif -#ifndef TRUE -#define TRUE true -#endif - -#else /* ! __cplusplus */ - - -#endif /* ! __cplusplus */ - -#if defined(__LP64__) -#define TYPEDEF_UINTPTR -typedef unsigned long long int uintptr; -#endif - - - - - -#if defined(_NEED_SIZE_T_) -typedef long unsigned int size_t; -#endif - - - - - -#if defined(__sparc__) -#define TYPEDEF_ULONG -#endif - - -/* - * If this is either a Linux hybrid build or the per-port code of a hybrid build - * then use the Linux header files to get some of the typedefs. Otherwise, define - * them entirely in this file. We can't always define the types because we get - * a duplicate typedef error; there is no way to "undefine" a typedef. - * We know when it's per-port code because each file defines LINUX_PORT at the top. - */ -#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) -#define TYPEDEF_UINT -#ifndef TARGETENV_android -#define TYPEDEF_USHORT -#define TYPEDEF_ULONG -#endif /* TARGETENV_android */ -#ifdef __KERNEL__ -#include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) -#define TYPEDEF_BOOL -#endif /* >= 2.6.19 */ -/* special detection for 2.6.18-128.7.1.0.1.el5 */ -#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) -#include -#ifdef noinline_for_stack -#define TYPEDEF_BOOL -#endif -#endif /* == 2.6.18 */ -#endif /* __KERNEL__ */ -#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ - - - - -/* Do not support the (u)int64 types with strict ansi for GNU C */ -#if defined(__GNUC__) && defined(__STRICT_ANSI__) -#define TYPEDEF_INT64 -#define TYPEDEF_UINT64 -#endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */ - -/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode - * for signed or unsigned - */ -#if defined(__ICL) - -#define TYPEDEF_INT64 - -#if defined(__STDC__) -#define TYPEDEF_UINT64 -#endif - -#endif /* __ICL */ - -#if !defined(__DJGPP__) - -/* pick up ushort & uint from standard types.h */ -#if defined(__KERNEL__) - -/* See note above */ -#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) -#include /* sys/types.h and linux/types.h are oil and water */ -#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ - -#else - - -#include - -#endif /* linux && __KERNEL__ */ - -#endif - - - -/* use the default typedefs in the next section of this file */ -#define USE_TYPEDEF_DEFAULTS - -#endif /* SITE_TYPEDEFS */ - - -/* - * Default Typedefs - */ - -#ifdef USE_TYPEDEF_DEFAULTS -#undef USE_TYPEDEF_DEFAULTS - -#ifndef TYPEDEF_BOOL -typedef /* @abstract@ */ unsigned char bool; -#endif - -/* define uchar, ushort, uint, ulong */ - -#ifndef TYPEDEF_UCHAR -typedef unsigned char uchar; -#endif - -#ifndef TYPEDEF_USHORT -typedef unsigned short ushort; -#endif - -#ifndef TYPEDEF_UINT -typedef unsigned int uint; -#endif - -#ifndef TYPEDEF_ULONG -typedef unsigned long ulong; -#endif - -/* define [u]int8/16/32/64, uintptr */ - -#ifndef TYPEDEF_UINT8 -typedef unsigned char uint8; -#endif - -#ifndef TYPEDEF_UINT16 -typedef unsigned short uint16; -#endif - -#ifndef TYPEDEF_UINT32 -typedef unsigned int uint32; -#endif - -#ifndef TYPEDEF_UINT64 -typedef unsigned long long uint64; -#endif - -#ifndef TYPEDEF_UINTPTR -typedef unsigned int uintptr; -#endif - -#ifndef TYPEDEF_INT8 -typedef signed char int8; -#endif - -#ifndef TYPEDEF_INT16 -typedef signed short int16; -#endif - -#ifndef TYPEDEF_INT32 -typedef signed int int32; -#endif - -#ifndef TYPEDEF_INT64 -typedef signed long long int64; -#endif - -/* define float32/64, float_t */ - -#ifndef TYPEDEF_FLOAT32 -typedef float float32; -#endif - -#ifndef TYPEDEF_FLOAT64 -typedef double float64; -#endif - -/* - * abstracted floating point type allows for compile time selection of - * single or double precision arithmetic. Compiling with -DFLOAT32 - * selects single precision; the default is double precision. - */ - -#ifndef TYPEDEF_FLOAT_T - -#if defined(FLOAT32) -typedef float32 float_t; -#else /* default to double precision floating point */ -typedef float64 float_t; -#endif - -#endif /* TYPEDEF_FLOAT_T */ - -/* define macro values */ - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 /* TRUE */ -#endif - -#ifndef NULL -#define NULL 0 -#endif - -#ifndef OFF -#define OFF 0 -#endif - -#ifndef ON -#define ON 1 /* ON = 1 */ -#endif - -#define AUTO (-1) /* Auto = -1 */ - -/* define PTRSZ, INLINE */ - -#ifndef PTRSZ -#define PTRSZ sizeof(char*) -#endif - - -/* Detect compiler type. */ -#if defined(__GNUC__) || defined(__lint) - #define BWL_COMPILER_GNU -#elif defined(__CC_ARM) && __CC_ARM - #define BWL_COMPILER_ARMCC -#else - #error "Unknown compiler!" -#endif - - -#ifndef INLINE - #if defined(BWL_COMPILER_MICROSOFT) - #define INLINE __inline - #elif defined(BWL_COMPILER_GNU) - #define INLINE __inline__ - #elif defined(BWL_COMPILER_ARMCC) - #define INLINE __inline - #else - #define INLINE - #endif -#endif /* INLINE */ - -#undef TYPEDEF_BOOL -#undef TYPEDEF_UCHAR -#undef TYPEDEF_USHORT -#undef TYPEDEF_UINT -#undef TYPEDEF_ULONG -#undef TYPEDEF_UINT8 -#undef TYPEDEF_UINT16 -#undef TYPEDEF_UINT32 -#undef TYPEDEF_UINT64 -#undef TYPEDEF_UINTPTR -#undef TYPEDEF_INT8 -#undef TYPEDEF_INT16 -#undef TYPEDEF_INT32 -#undef TYPEDEF_INT64 -#undef TYPEDEF_FLOAT32 -#undef TYPEDEF_FLOAT64 -#undef TYPEDEF_FLOAT_T - -#endif /* USE_TYPEDEF_DEFAULTS */ - -/* Suppress unused parameter warning */ -#define UNUSED_PARAMETER(x) (void)(x) - -/* Avoid warning for discarded const or volatile qualifier in special cases (-Wcast-qual) */ -#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) - -/* - * Including the bcmdefs.h here, to make sure everyone including typedefs.h - * gets this automatically -*/ -#include -#endif /* _TYPEDEFS_H_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h deleted file mode 100755 index 4355e72a3e29..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h +++ /dev/null @@ -1,304 +0,0 @@ -/* -* Copyright (C) 1999-2018, Broadcom Corporation -* -* Unless you and Broadcom execute a separate written software license -* agreement governing use of this software, this software is licensed to you -* under the terms of the GNU General Public License version 2 (the "GPL"), -* available at http://www.broadcom.com/licenses/GPLv2.php, with the -* following added to such license: -* -* As a special exception, the copyright holders of this software give you -* permission to link this software with independent modules, and to copy and -* distribute the resulting executable under terms of your choice, provided that -* you also meet, for each linked independent module, the terms and conditions of -* the license of that module. An independent module is a module which is not -* derived from this software. The special exception does not apply to any -* modifications of the software. -* -* Notwithstanding the above, under no circumstances may you combine this -* software in any way with any other Broadcom software provided under a license -* other than the GPL, without Broadcom's express prior written consent. -* $Id: wlfc_proto.h 431159 2013-10-22 19:40:51Z $ -* -*/ -#ifndef __wlfc_proto_definitions_h__ -#define __wlfc_proto_definitions_h__ - - /* Use TLV to convey WLFC information. - --------------------------------------------------------------------------- - | Type | Len | value | Description - --------------------------------------------------------------------------- - | 1 | 1 | (handle) | MAC OPEN - --------------------------------------------------------------------------- - | 2 | 1 | (handle) | MAC CLOSE - --------------------------------------------------------------------------- - | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn - --------------------------------------------------------------------------- - | 4 | 4+ | see pkttag comments | TXSTATUS - | | | TX status & timestamps | Present only when pkt timestamp is enabled - --------------------------------------------------------------------------- - | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] - --------------------------------------------------------------------------- - | 6 | 8 | (handle, ifid, MAC) | MAC ADD - --------------------------------------------------------------------------- - | 7 | 8 | (handle, ifid, MAC) | MAC DEL - --------------------------------------------------------------------------- - | 8 | 1 | (rssi) | RSSI - RSSI value for the packet. - --------------------------------------------------------------------------- - | 9 | 1 | (interface ID) | Interface OPEN - --------------------------------------------------------------------------- - | 10 | 1 | (interface ID) | Interface CLOSE - --------------------------------------------------------------------------- - | 11 | 8 | fifo credit returns map | FIFO credits back to the host - | | | | - | | | | -------------------------------------- - | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim | - | | | | -------------------------------------- - | | | | - --------------------------------------------------------------------------- - | 12 | 2 | MAC handle, | Host provides a bitmap of pending - | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn. - | | | | [host->firmware] - --------------------------------------------------------------------------- - | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific - | | | | MAC destination. - --------------------------------------------------------------------------- - | 15 | 12 | (pkttag, timestamps) | Send TX timestamp at reception from host - --------------------------------------------------------------------------- - | 16 | 12 | (pkttag, timestamps) | Send WLAN RX timestamp along with RX frame - --------------------------------------------------------------------------- - | 255 | N/A | N/A | FILLER - This is a special type - | | | | that has no length or value. - | | | | Typically used for padding. - --------------------------------------------------------------------------- - */ - -#define WLFC_CTL_TYPE_MAC_OPEN 1 -#define WLFC_CTL_TYPE_MAC_CLOSE 2 -#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3 -#define WLFC_CTL_TYPE_TXSTATUS 4 -#define WLFC_CTL_TYPE_PKTTAG 5 - -#define WLFC_CTL_TYPE_MACDESC_ADD 6 -#define WLFC_CTL_TYPE_MACDESC_DEL 7 -#define WLFC_CTL_TYPE_RSSI 8 - -#define WLFC_CTL_TYPE_INTERFACE_OPEN 9 -#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 - -#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11 - -#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12 -#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 -#define WLFC_CTL_TYPE_HOST_REORDER_RXPKTS 14 - - -#define WLFC_CTL_TYPE_TX_ENTRY_STAMP 15 -#define WLFC_CTL_TYPE_RX_STAMP 16 - -#define WLFC_CTL_TYPE_TRANS_ID 18 -#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 - - -#define WLFC_CTL_TYPE_FILLER 255 - -#define WLFC_CTL_VALUE_LEN_MACDESC 8 /* handle, interface, MAC */ - -#define WLFC_CTL_VALUE_LEN_MAC 1 /* MAC-handle */ -#define WLFC_CTL_VALUE_LEN_RSSI 1 - -#define WLFC_CTL_VALUE_LEN_INTERFACE 1 -#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2 - -#define WLFC_CTL_VALUE_LEN_TXSTATUS 4 -#define WLFC_CTL_VALUE_LEN_PKTTAG 4 - -#define WLFC_CTL_VALUE_LEN_SEQ 2 - -/* enough space to host all 4 ACs, bc/mc and atim fifo credit */ -#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6 - -#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ -#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ - - -#define WLFC_PKTFLAG_PKTFROMHOST 0x01 -#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 - -#define WL_TXSTATUS_STATUS_MASK 0xff /* allow 8 bits */ -#define WL_TXSTATUS_STATUS_SHIFT 24 - -#define WL_TXSTATUS_SET_STATUS(x, status) ((x) = \ - ((x) & ~(WL_TXSTATUS_STATUS_MASK << WL_TXSTATUS_STATUS_SHIFT)) | \ - (((status) & WL_TXSTATUS_STATUS_MASK) << WL_TXSTATUS_STATUS_SHIFT)) -#define WL_TXSTATUS_GET_STATUS(x) (((x) >> WL_TXSTATUS_STATUS_SHIFT) & \ - WL_TXSTATUS_STATUS_MASK) - -#define WL_TXSTATUS_GENERATION_MASK 1 /* allow 1 bit */ -#define WL_TXSTATUS_GENERATION_SHIFT 31 - -#define WL_TXSTATUS_SET_GENERATION(x, gen) ((x) = \ - ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ - (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT)) - -#define WL_TXSTATUS_GET_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ - WL_TXSTATUS_GENERATION_MASK) - -#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ -#define WL_TXSTATUS_FLAGS_SHIFT 27 - -#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ - ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ - (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT)) -#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \ - WL_TXSTATUS_FLAGS_MASK) - -#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ -#define WL_TXSTATUS_FIFO_SHIFT 24 - -#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ - ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ - (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) -#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) - -#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ -#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ - ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) -#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) - -#define WL_TXSTATUS_HSLOT_MASK 0xffff /* allow 16 bits */ -#define WL_TXSTATUS_HSLOT_SHIFT 8 - -#define WL_TXSTATUS_SET_HSLOT(x, hslot) ((x) = \ - ((x) & ~(WL_TXSTATUS_HSLOT_MASK << WL_TXSTATUS_HSLOT_SHIFT)) | \ - (((hslot) & WL_TXSTATUS_HSLOT_MASK) << WL_TXSTATUS_HSLOT_SHIFT)) -#define WL_TXSTATUS_GET_HSLOT(x) (((x) >> WL_TXSTATUS_HSLOT_SHIFT)& \ - WL_TXSTATUS_HSLOT_MASK) - -#define WL_TXSTATUS_FREERUNCTR_MASK 0xff /* allow 8 bits */ - -#define WL_TXSTATUS_SET_FREERUNCTR(x, ctr) ((x) = \ - ((x) & ~(WL_TXSTATUS_FREERUNCTR_MASK)) | \ - ((ctr) & WL_TXSTATUS_FREERUNCTR_MASK)) -#define WL_TXSTATUS_GET_FREERUNCTR(x) ((x)& WL_TXSTATUS_FREERUNCTR_MASK) - -#define WL_SEQ_FROMFW_MASK 0x1 /* allow 1 bit */ -#define WL_SEQ_FROMFW_SHIFT 13 -#define WL_SEQ_SET_FROMFW(x, val) ((x) = \ - ((x) & ~(WL_SEQ_FROMFW_MASK << WL_SEQ_FROMFW_SHIFT)) | \ - (((val) & WL_SEQ_FROMFW_MASK) << WL_SEQ_FROMFW_SHIFT)) -#define WL_SEQ_GET_FROMFW(x) (((x) >> WL_SEQ_FROMFW_SHIFT) & \ - WL_SEQ_FROMFW_MASK) - -#define WL_SEQ_FROMDRV_MASK 0x1 /* allow 1 bit */ -#define WL_SEQ_FROMDRV_SHIFT 12 -#define WL_SEQ_SET_FROMDRV(x, val) ((x) = \ - ((x) & ~(WL_SEQ_FROMDRV_MASK << WL_SEQ_FROMDRV_SHIFT)) | \ - (((val) & WL_SEQ_FROMDRV_MASK) << WL_SEQ_FROMDRV_SHIFT)) -#define WL_SEQ_GET_FROMDRV(x) (((x) >> WL_SEQ_FROMDRV_SHIFT) & \ - WL_SEQ_FROMDRV_MASK) - -#define WL_SEQ_NUM_MASK 0xfff /* allow 12 bit */ -#define WL_SEQ_NUM_SHIFT 0 -#define WL_SEQ_SET_NUM(x, val) ((x) = \ - ((x) & ~(WL_SEQ_NUM_MASK << WL_SEQ_NUM_SHIFT)) | \ - (((val) & WL_SEQ_NUM_MASK) << WL_SEQ_NUM_SHIFT)) -#define WL_SEQ_GET_NUM(x) (((x) >> WL_SEQ_NUM_SHIFT) & \ - WL_SEQ_NUM_MASK) - -/* 32 STA should be enough??, 6 bits; Must be power of 2 */ -#define WLFC_MAC_DESC_TABLE_SIZE 32 -#define WLFC_MAX_IFNUM 16 -#define WLFC_MAC_DESC_ID_INVALID 0xff - -/* b[7:5] -reuse guard, b[4:0] -value */ -#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f) - -#define WLFC_PKTFLAG_SET_PKTREQUESTED(x) (x) |= \ - (WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) - -#define WLFC_PKTFLAG_CLR_PKTREQUESTED(x) (x) &= \ - ~(WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) - - -#define WLFC_MAX_PENDING_DATALEN 120 - -/* host is free to discard the packet */ -#define WLFC_CTL_PKTFLAG_DISCARD 0 -/* D11 suppressed a packet */ -#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1 -/* WL firmware suppressed a packet because MAC is - already in PSMode (short time window) -*/ -#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2 -/* Firmware tossed this packet */ -#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3 -/* Firmware tossed after retries */ -#define WLFC_CTL_PKTFLAG_DISCARD_NOACK 4 - -#define WLFC_D11_STATUS_INTERPRET(txs) \ - (((txs)->status.suppr_ind != TX_STATUS_SUPR_NONE) ? \ - WLFC_CTL_PKTFLAG_D11SUPPRESS : \ - ((txs)->status.was_acked ? \ - WLFC_CTL_PKTFLAG_DISCARD : WLFC_CTL_PKTFLAG_DISCARD_NOACK)) - -#ifdef PROP_TXSTATUS_DEBUG -#define WLFC_DBGMESG(x) printf x -/* wlfc-breadcrumb */ -#define WLFC_BREADCRUMB(x) do {if ((x) == NULL) \ - {printf("WLFC: %s():%d:caller:%p\n", \ - __FUNCTION__, __LINE__, __builtin_return_address(0));}} while (0) -#define WLFC_PRINTMAC(banner, ea) do {printf("%s MAC: [%02x:%02x:%02x:%02x:%02x:%02x]\n", \ - banner, ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); } while (0) -#define WLFC_WHEREIS(s) printf("WLFC: at %s():%d, %s\n", __FUNCTION__, __LINE__, (s)) -#else -#define WLFC_DBGMESG(x) -#define WLFC_BREADCRUMB(x) -#define WLFC_PRINTMAC(banner, ea) -#define WLFC_WHEREIS(s) -#endif - -/* AMPDU host reorder packet flags */ -#define WLHOST_REORDERDATA_MAXFLOWS 256 -#define WLHOST_REORDERDATA_LEN 10 -#define WLHOST_REORDERDATA_TOTLEN (WLHOST_REORDERDATA_LEN + 1 + 1) /* +tag +len */ - -#define WLHOST_REORDERDATA_FLOWID_OFFSET 0 -#define WLHOST_REORDERDATA_MAXIDX_OFFSET 2 -#define WLHOST_REORDERDATA_FLAGS_OFFSET 4 -#define WLHOST_REORDERDATA_CURIDX_OFFSET 6 -#define WLHOST_REORDERDATA_EXPIDX_OFFSET 8 - -#define WLHOST_REORDERDATA_DEL_FLOW 0x01 -#define WLHOST_REORDERDATA_FLUSH_ALL 0x02 -#define WLHOST_REORDERDATA_CURIDX_VALID 0x04 -#define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 -#define WLHOST_REORDERDATA_NEW_HOLE 0x10 - -/* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ -#define WLFC_CTL_TRANS_ID_LEN 6 -#define WLFC_TYPE_TRANS_ID_LEN 6 - -#define WLFC_MODE_HANGER 1 /* use hanger */ -#define WLFC_MODE_AFQ 2 /* use afq */ -#define WLFC_IS_OLD_DEF(x) ((x & 1) || (x & 2)) - -#define WLFC_MODE_AFQ_SHIFT 2 /* afq bit */ -#define WLFC_SET_AFQ(x, val) ((x) = \ - ((x) & ~(1 << WLFC_MODE_AFQ_SHIFT)) | \ - (((val) & 1) << WLFC_MODE_AFQ_SHIFT)) -#define WLFC_GET_AFQ(x) (((x) >> WLFC_MODE_AFQ_SHIFT) & 1) - -#define WLFC_MODE_REUSESEQ_SHIFT 3 /* seq reuse bit */ -#define WLFC_SET_REUSESEQ(x, val) ((x) = \ - ((x) & ~(1 << WLFC_MODE_REUSESEQ_SHIFT)) | \ - (((val) & 1) << WLFC_MODE_REUSESEQ_SHIFT)) -#define WLFC_GET_REUSESEQ(x) (((x) >> WLFC_MODE_REUSESEQ_SHIFT) & 1) - -#define WLFC_MODE_REORDERSUPP_SHIFT 4 /* host reorder suppress pkt bit */ -#define WLFC_SET_REORDERSUPP(x, val) ((x) = \ - ((x) & ~(1 << WLFC_MODE_REORDERSUPP_SHIFT)) | \ - (((val) & 1) << WLFC_MODE_REORDERSUPP_SHIFT)) -#define WLFC_GET_REORDERSUPP(x) (((x) >> WLFC_MODE_REORDERSUPP_SHIFT) & 1) - -#endif /* __wlfc_proto_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h b/drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h deleted file mode 100755 index 226d38a2bcd8..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h +++ /dev/null @@ -1,5854 +0,0 @@ -/* - * Custom OID/ioctl definitions for - * Broadcom 802.11abg Networking Device Driver - * - * Definitions subject to change without notice. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wlioctl.h 718508 2017-08-31 02:48:38Z $ - */ - -#ifndef _wlioctl_h_ -#define _wlioctl_h_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - - - -#ifndef INTF_NAME_SIZ -#define INTF_NAME_SIZ 16 -#endif - -/* Used to send ioctls over the transport pipe */ -typedef struct remote_ioctl { - cdc_ioctl_t msg; - uint32 data_len; - char intf_name[INTF_NAME_SIZ]; -} rem_ioctl_t; -#define REMOTE_SIZE sizeof(rem_ioctl_t) - -typedef struct { - uint32 num; - chanspec_t list[1]; -} chanspec_list_t; - -/* association decision information */ -typedef struct { - bool assoc_approved; /* (re)association approved */ - uint16 reject_reason; /* reason code for rejecting association */ - struct ether_addr da; - int64 sys_time; /* current system time */ -} assoc_decision_t; - -#define ACTION_FRAME_SIZE 1800 - -typedef struct wl_action_frame { - struct ether_addr da; - uint16 len; - uint32 packetId; - uint8 data[ACTION_FRAME_SIZE]; -} wl_action_frame_t; - -#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) - -typedef struct ssid_info -{ - uint8 ssid_len; /* the length of SSID */ - uint8 ssid[32]; /* SSID string */ -} ssid_info_t; - -typedef struct wl_af_params { - uint32 channel; - int32 dwell_time; - struct ether_addr BSSID; - wl_action_frame_t action_frame; -} wl_af_params_t; - -#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) - -#define MFP_TEST_FLAG_NORMAL 0 -#define MFP_TEST_FLAG_ANY_KEY 1 -typedef struct wl_sa_query { - uint32 flag; - uint8 action; - uint16 id; - struct ether_addr da; -} wl_sa_query_t; - -/* require default structure packing */ -#define BWL_DEFAULT_PACKING -#include - - - -/* Legacy structure to help keep backward compatible wl tool and tray app */ - -#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ - -typedef struct wl_bss_info_107 { - uint32 version; /* version field */ - uint32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - struct ether_addr BSSID; - uint16 beacon_period; /* units are Kusec */ - uint16 capability; /* Capability information */ - uint8 SSID_len; - uint8 SSID[32]; - struct { - uint count; /* # rates in this set */ - uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - uint8 channel; /* Channel no. */ - uint16 atim_window; /* units are Kusec */ - uint8 dtim_period; /* DTIM period */ - int16 RSSI; /* receive signal strength (in dBm) */ - int8 phy_noise; /* noise (in dBm) */ - uint32 ie_length; /* byte length of Information Elements */ - /* variable length Information Elements */ -} wl_bss_info_107_t; - -/* - * Per-BSS information structure. - */ - -#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */ - -/* BSS info structure - * Applications MUST CHECK ie_offset field and length field to access IEs and - * next bss_info structure in a vector (in wl_scan_results_t) - */ -typedef struct wl_bss_info_108 { - uint32 version; /* version field */ - uint32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - struct ether_addr BSSID; - uint16 beacon_period; /* units are Kusec */ - uint16 capability; /* Capability information */ - uint8 SSID_len; - uint8 SSID[32]; - struct { - uint count; /* # rates in this set */ - uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - chanspec_t chanspec; /* chanspec for bss */ - uint16 atim_window; /* units are Kusec */ - uint8 dtim_period; /* DTIM period */ - int16 RSSI; /* receive signal strength (in dBm) */ - int8 phy_noise; /* noise (in dBm) */ - - uint8 n_cap; /* BSS is 802.11N Capable */ - uint32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ - uint8 ctl_ch; /* 802.11N BSS control channel number */ - uint32 reserved32[1]; /* Reserved for expansion of BSS properties */ - uint8 flags; /* flags */ - uint8 reserved[3]; /* Reserved for expansion of BSS properties */ - uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ - - uint16 ie_offset; /* offset at which IEs start, from beginning */ - uint32 ie_length; /* byte length of Information Elements */ - /* Add new fields here */ - /* variable length Information Elements */ -} wl_bss_info_108_t; - -#define WL_BSS_INFO_VERSION 109 /* current version of wl_bss_info struct */ - -/* BSS info structure - * Applications MUST CHECK ie_offset field and length field to access IEs and - * next bss_info structure in a vector (in wl_scan_results_t) - */ -typedef struct wl_bss_info { - uint32 version; /* version field */ - uint32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - struct ether_addr BSSID; - uint16 beacon_period; /* units are Kusec */ - uint16 capability; /* Capability information */ - uint8 SSID_len; - uint8 SSID[32]; - struct { - uint count; /* # rates in this set */ - uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - chanspec_t chanspec; /* chanspec for bss */ - uint16 atim_window; /* units are Kusec */ - uint8 dtim_period; /* DTIM period */ - int16 RSSI; /* receive signal strength (in dBm) */ - int8 phy_noise; /* noise (in dBm) */ - - uint8 n_cap; /* BSS is 802.11N Capable */ - uint32 nbss_cap; /* 802.11N+AC BSS Capabilities */ - uint8 ctl_ch; /* 802.11N BSS control channel number */ - uint8 padding1[3]; /* explicit struct alignment padding */ - uint16 vht_rxmcsmap; /* VHT rx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ - uint16 vht_txmcsmap; /* VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ - uint8 flags; /* flags */ - uint8 vht_cap; /* BSS is vht capable */ - uint8 reserved[2]; /* Reserved for expansion of BSS properties */ - uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ - - uint16 ie_offset; /* offset at which IEs start, from beginning */ - uint32 ie_length; /* byte length of Information Elements */ - int16 SNR; /* average SNR of during frame reception */ - /* Add new fields here */ - /* variable length Information Elements */ -} wl_bss_info_t; - -#define WL_GSCAN_BSS_INFO_VERSION 1 /* current version of wl_gscan_bss_info struct */ -#define WL_GSCAN_INFO_FIXED_FIELD_SIZE (sizeof(wl_gscan_bss_info_t) - sizeof(wl_bss_info_t)) - -typedef struct wl_gscan_bss_info { - uint32 timestamp[2]; - wl_bss_info_t info; - /* variable length Information Elements */ -} wl_gscan_bss_info_t; - - -typedef struct wl_bsscfg { - uint32 bsscfg_idx; - uint32 wsec; - uint32 WPA_auth; - uint32 wsec_index; - uint32 associated; - uint32 BSS; - uint32 phytest_on; - struct ether_addr prev_BSSID; - struct ether_addr BSSID; - uint32 targetbss_wpa2_flags; - uint32 assoc_type; - uint32 assoc_state; -} wl_bsscfg_t; - -typedef struct wl_if_add { - uint32 bsscfg_flags; - uint32 if_flags; - uint32 ap; - struct ether_addr mac_addr; -} wl_if_add_t; - -typedef struct wl_bss_config { - uint32 atim_window; - uint32 beacon_period; - uint32 chanspec; -} wl_bss_config_t; - -#define WL_BSS_USER_RADAR_CHAN_SELECT 0x1 /* User application will randomly select - * radar channel. - */ - -#define DLOAD_HANDLER_VER 1 /* Downloader version */ -#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ -#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ - -#define DL_CRC_NOT_INUSE 0x0001 - -/* generic download types & flags */ -enum { - DL_TYPE_UCODE = 1, - DL_TYPE_CLM = 2 -}; - -/* ucode type values */ -enum { - UCODE_FW, - INIT_VALS, - BS_INIT_VALS -}; - -struct wl_dload_data { - uint16 flag; - uint16 dload_type; - uint32 len; - uint32 crc; - uint8 data[1]; -}; -typedef struct wl_dload_data wl_dload_data_t; - -struct wl_ucode_info { - uint32 ucode_type; - uint32 num_chunks; - uint32 chunk_len; - uint32 chunk_num; - uint8 data_chunk[1]; -}; -typedef struct wl_ucode_info wl_ucode_info_t; - -struct wl_clm_dload_info { - uint32 ds_id; - uint32 clm_total_len; - uint32 num_chunks; - uint32 chunk_len; - uint32 chunk_offset; - uint8 data_chunk[1]; -}; -typedef struct wl_clm_dload_info wl_clm_dload_info_t; - -typedef struct wlc_ssid { - uint32 SSID_len; - uchar SSID[DOT11_MAX_SSID_LEN]; -} wlc_ssid_t; - -typedef struct wlc_ssid_ext { - bool hidden; - uint16 flags; - uint8 SSID_len; - int8 rssi_thresh; - uchar SSID[DOT11_MAX_SSID_LEN]; -} wlc_ssid_ext_t; - - -#define MAX_PREFERRED_AP_NUM 5 -typedef struct wlc_fastssidinfo { - uint32 SSID_channel[MAX_PREFERRED_AP_NUM]; - wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM]; -} wlc_fastssidinfo_t; - -typedef BWL_PRE_PACKED_STRUCT struct wnm_url { - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT wnm_url_t; - -typedef struct chan_scandata { - uint8 txpower; - uint8 pad; - chanspec_t channel; /* Channel num, bw, ctrl_sb and band */ - uint32 channel_mintime; - uint32 channel_maxtime; -} chan_scandata_t; - -typedef enum wl_scan_type { - EXTDSCAN_FOREGROUND_SCAN, - EXTDSCAN_BACKGROUND_SCAN, - EXTDSCAN_FORCEDBACKGROUND_SCAN -} wl_scan_type_t; - -#define WLC_EXTDSCAN_MAX_SSID 5 - -typedef struct wl_extdscan_params { - int8 nprobes; /* 0, passive, otherwise active */ - int8 split_scan; /* split scan */ - int8 band; /* band */ - int8 pad; - wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /* ssid list */ - uint32 tx_rate; /* in 500ksec units */ - wl_scan_type_t scan_type; /* enum */ - int32 channel_num; - chan_scandata_t channel_list[1]; /* list of chandata structs */ -} wl_extdscan_params_t; - -#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) - -#define WL_SCAN_PARAMS_SSID_MAX 10 - -typedef struct wl_scan_params { - wlc_ssid_t ssid; /* default: {0, ""} */ - struct ether_addr bssid; /* default: bcast */ - int8 bss_type; /* default: any, - * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT - */ - uint8 scan_type; /* flags, 0 use default */ - int32 nprobes; /* -1 use default, number of probes per channel */ - int32 active_time; /* -1 use default, dwell time per channel for - * active scanning - */ - int32 passive_time; /* -1 use default, dwell time per channel - * for passive scanning - */ - int32 home_time; /* -1 use default, dwell time for the home channel - * between channel scans - */ - int32 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 wlc_ssid_t array that - * follows channel_list, aligned for int32 (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 - */ - uint16 channel_list[1]; /* list of chanspecs */ -} wl_scan_params_t; - -/* size of wl_scan_params not including variable length array */ -#define WL_SCAN_PARAMS_FIXED_SIZE 64 - -#define ISCAN_REQ_VERSION 1 - -/* incremental scan struct */ -typedef struct wl_iscan_params { - uint32 version; - uint16 action; - uint16 scan_duration; - wl_scan_params_t params; -} wl_iscan_params_t; - -/* 3 fields + size of wl_scan_params, not including variable length array */ -#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) - -typedef struct wl_scan_results { - uint32 buflen; - uint32 version; - uint32 count; - wl_bss_info_t bss_info[1]; -} wl_scan_results_t; - -/* size of wl_scan_results not including variable length array */ -#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) - -/* Used in EXT_STA */ -#define DNGL_RXCTXT_SIZE 45 - - -#define ESCAN_REQ_VERSION 1 - -typedef struct wl_escan_params { - uint32 version; - uint16 action; - uint16 sync_id; - wl_scan_params_t params; -} wl_escan_params_t; - -#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) - -typedef struct wl_escan_result { - uint32 buflen; - uint32 version; - uint16 sync_id; - uint16 bss_count; - wl_bss_info_t bss_info[1]; -} wl_escan_result_t; - -#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) - -typedef struct wl_gscan_result { - uint32 buflen; - uint32 version; - wl_gscan_bss_info_t bss_info[1]; -} wl_gscan_result_t; - -#define WL_GSCAN_RESULTS_FIXED_SIZE (sizeof(wl_gscan_result_t) - sizeof(wl_gscan_bss_info_t)) - -/* incremental scan results struct */ -typedef struct wl_iscan_results { - uint32 status; - wl_scan_results_t results; -} wl_iscan_results_t; - -/* size of wl_iscan_results not including variable length array */ -#define WL_ISCAN_RESULTS_FIXED_SIZE \ - (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) - -#define SCANOL_PARAMS_VERSION 1 - -typedef struct scanol_params { - uint32 version; - uint32 flags; /* offload scanning flags */ - int32 active_time; /* -1 use default, dwell time per channel for active scanning */ - int32 passive_time; /* -1 use default, dwell time per channel for passive scanning */ - int32 idle_rest_time; /* -1 use default, time idle between scan cycle */ - int32 idle_rest_time_multiplier; - int32 active_rest_time; - int32 active_rest_time_multiplier; - int32 scan_cycle_idle_rest_time; - int32 scan_cycle_idle_rest_multiplier; - int32 scan_cycle_active_rest_time; - int32 scan_cycle_active_rest_multiplier; - int32 max_rest_time; - int32 max_scan_cycles; - int32 nprobes; /* -1 use default, number of probes per channel */ - int32 scan_start_delay; - uint32 nchannels; - uint32 ssid_count; - wlc_ssid_t ssidlist[1]; -} scanol_params_t; - -typedef struct wl_probe_params { - wlc_ssid_t ssid; - struct ether_addr bssid; - struct ether_addr mac; -} wl_probe_params_t; - -#define WL_MAXRATES_IN_SET 16 /* max # of rates in a rateset */ -typedef struct wl_rateset { - uint32 count; /* # rates in this set */ - uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ -} wl_rateset_t; - -typedef struct wl_rateset_args { - uint32 count; /* # rates in this set */ - uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ - uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ - uint16 vht_mcs[VHT_CAP_MCS_MAP_NSS_MAX]; /* supported mcs index bit map per nss */ -} wl_rateset_args_t; - -#define TXBF_RATE_MCS_ALL 4 -#define TXBF_RATE_VHT_ALL 4 -#define TXBF_RATE_OFDM_ALL 8 - -typedef struct wl_txbf_rateset { - uint8 txbf_rate_mcs[TXBF_RATE_MCS_ALL]; /* one for each stream */ - uint8 txbf_rate_mcs_bcm[TXBF_RATE_MCS_ALL]; /* one for each stream */ - uint16 txbf_rate_vht[TXBF_RATE_VHT_ALL]; /* one for each stream */ - uint16 txbf_rate_vht_bcm[TXBF_RATE_VHT_ALL]; /* one for each stream */ - uint8 txbf_rate_ofdm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ - uint8 txbf_rate_ofdm_bcm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ - uint8 txbf_rate_ofdm_cnt; - uint8 txbf_rate_ofdm_cnt_bcm; -} wl_txbf_rateset_t; - -#define OFDM_RATE_MASK 0x0000007f -typedef uint8 ofdm_rates_t; - -typedef struct wl_rates_info { - wl_rateset_t rs_tgt; - uint32 phy_type; - int32 bandtype; - uint8 cck_only; - uint8 rate_mask; - uint8 mcsallow; - uint8 bw; - uint8 txstreams; -} wl_rates_info_t; - -/* uint32 list */ -typedef struct wl_uint32_list { - /* in - # of elements, out - # of entries */ - uint32 count; - /* variable length uint32 list */ - uint32 element[1]; -} wl_uint32_list_t; - -/* used for association with a specific BSSID and chanspec list */ -typedef struct wl_assoc_params { - struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */ - uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, - * otherwise count of chanspecs in chanspec_list - * AND paired bssids following chanspec_list - * also, chanspec_num has to be set to zero - * for bssid list to be used - */ - int32 chanspec_num; /* 0: all available channels, - * otherwise count of chanspecs in chanspec_list - */ - chanspec_t chanspec_list[1]; /* list of chanspecs */ -} wl_assoc_params_t; - -#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) - -/* used for reassociation/roam to a specific BSSID and channel */ -typedef wl_assoc_params_t wl_reassoc_params_t; -#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE - -/* used for association to a specific BSSID and channel */ -typedef wl_assoc_params_t wl_join_assoc_params_t; -#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE - -/* used for join with or without a specific bssid and channel list */ -typedef struct wl_join_params { - wlc_ssid_t ssid; - wl_assoc_params_t params; /* optional field, but it must include the fixed portion - * of the wl_assoc_params_t struct when it does present. - */ -} wl_join_params_t; - -typedef struct wlc_roam_exp_params { - int8 a_band_boost_threshold; - int8 a_band_penalty_threshold; - uint8 a_band_boost_factor; - uint8 a_band_penalty_factor; - uint8 cur_bssid_boost; - int8 alert_roam_trigger_threshold; - uint16 a_band_max_boost; -} wlc_roam_exp_params_t; - -#define ROAM_EXP_CFG_VERSION 1 -#define ROAM_EXP_ENABLE_FLAG (1 << 0) -#define ROAM_EXP_CFG_PRESENT (1 << 1) -typedef struct wl_roam_exp_cfg { - uint8 version; - uint8 flags; - uint16 reserved; - wlc_roam_exp_params_t params; -} wl_roam_exp_cfg_t; - -typedef struct wl_bssid_pref_list { - struct ether_addr bssid; - /* Add this to modify rssi */ - int8 rssi_factor; - int8 flags; -} wl_bssid_pref_list_t; - -#define BSSID_PREF_LIST_VERSION 1 -#define ROAM_EXP_CLEAR_BSSID_PREF (1 << 0) -typedef struct wl_bssid_pref_cfg { - uint8 version; - uint8 flags; - uint16 count; - wl_bssid_pref_list_t bssids[1]; -} wl_bssid_pref_cfg_t; - -#define SSID_WHITELIST_VERSION 1 -#define ROAM_EXP_CLEAR_SSID_WHITELIST (1 << 0) -/* Roam SSID whitelist, ssids in this list are ok to */ -/* be considered as targets to join when considering a roam */ -typedef struct wl_ssid_whitelist { - uint8 version; - uint8 flags; - uint8 ssid_count; - uint8 reserved; - wlc_ssid_t ssids[1]; -} wl_ssid_whitelist_t; - -#define ROAM_EXP_EVENT_VERSION 1 -typedef struct wl_roam_exp_event { - uint8 version; - uint8 flags; - uint16 reserved; - wlc_ssid_t cur_ssid; -} wl_roam_exp_event_t; - -#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \ - WL_ASSOC_PARAMS_FIXED_SIZE) -/* scan params for extended join */ -typedef struct wl_join_scan_params { - uint8 scan_type; /* 0 use default, active or passive scan */ - int32 nprobes; /* -1 use default, number of probes per channel */ - int32 active_time; /* -1 use default, dwell time per channel for - * active scanning - */ - int32 passive_time; /* -1 use default, dwell time per channel - * for passive scanning - */ - int32 home_time; /* -1 use default, dwell time for the home channel - * between channel scans - */ -} wl_join_scan_params_t; - -/* extended join params */ -typedef struct wl_extjoin_params { - wlc_ssid_t ssid; /* {0, ""}: wildcard scan */ - wl_join_scan_params_t scan; - wl_join_assoc_params_t assoc; /* optional field, but it must include the fixed portion - * of the wl_join_assoc_params_t struct when it does - * present. - */ -} wl_extjoin_params_t; -#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \ - WL_JOIN_ASSOC_PARAMS_FIXED_SIZE) - -#define ANT_SELCFG_MAX 4 /* max number of antenna configurations */ -#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ -typedef struct { - uint8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ - uint8 num_antcfg; /* number of available antenna configurations */ -} wlc_antselcfg_t; - -typedef struct { - uint32 duration; /* millisecs spent sampling this channel */ - uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ - /* move if cur bss moves channels) */ - uint32 congest_obss; /* traffic not in our bss */ - uint32 interference; /* millisecs detecting a non 802.11 interferer. */ - uint32 timestamp; /* second timestamp */ -} cca_congest_t; - -typedef struct { - chanspec_t chanspec; /* Which channel? */ - uint8 num_secs; /* How many secs worth of data */ - cca_congest_t secs[1]; /* Data */ -} cca_congest_channel_req_t; - -/* interference sources */ -enum interference_source { - ITFR_NONE = 0, /* interference */ - ITFR_PHONE, /* wireless phone */ - ITFR_VIDEO_CAMERA, /* wireless video camera */ - ITFR_MICROWAVE_OVEN, /* microwave oven */ - ITFR_BABY_MONITOR, /* wireless baby monitor */ - ITFR_BLUETOOTH, /* bluetooth */ - ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /* wireless camera or baby monitor */ - ITFR_BLUETOOTH_OR_BABY_MONITOR, /* bluetooth or baby monitor */ - ITFR_VIDEO_CAMERA_OR_PHONE, /* video camera or phone */ - ITFR_UNIDENTIFIED /* interference from unidentified source */ -}; - -/* structure for interference source report */ -typedef struct { - uint32 flags; /* flags. bit definitions below */ - uint32 source; /* last detected interference source */ - uint32 timestamp; /* second timestamp on interferenced flag change */ -} interference_source_rep_t; - -#define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ - - -typedef struct wl_country { - char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in - * the Country IE - */ - int32 rev; /* revision specifier for ccode - * on set, -1 indicates unspecified. - * on get, rev >= 0 - */ - char ccode[WLC_CNTRY_BUF_SZ]; /* nul-terminated built-in country code. - * variable length, but fixed size in - * struct allows simple allocation for - * expected country strings <= 3 chars. - */ -} wl_country_t; - -typedef struct wl_channels_in_country { - uint32 buflen; - uint32 band; - char country_abbrev[WLC_CNTRY_BUF_SZ]; - uint32 count; - uint32 channel[1]; -} wl_channels_in_country_t; - -typedef struct wl_country_list { - uint32 buflen; - uint32 band_set; - uint32 band; - uint32 count; - char country_abbrev[1]; -} wl_country_list_t; - -typedef struct wl_rm_req_elt { - int8 type; - int8 flags; - chanspec_t chanspec; - uint32 token; /* token for this measurement */ - uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ - uint32 tsf_l; /* TSF low 32-bits */ - uint32 dur; /* TUs */ -} wl_rm_req_elt_t; - -typedef struct wl_rm_req { - uint32 token; /* overall measurement set token */ - uint32 count; /* number of measurement requests */ - void *cb; /* completion callback function: may be NULL */ - void *cb_arg; /* arg to completion callback function */ - wl_rm_req_elt_t req[1]; /* variable length block of requests */ -} wl_rm_req_t; -#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) - -typedef struct wl_rm_rep_elt { - int8 type; - int8 flags; - chanspec_t chanspec; - uint32 token; /* token for this measurement */ - uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ - uint32 tsf_l; /* TSF low 32-bits */ - uint32 dur; /* TUs */ - uint32 len; /* byte length of data block */ - uint8 data[1]; /* variable length data block */ -} wl_rm_rep_elt_t; -#define WL_RM_REP_ELT_FIXED_LEN 24 /* length excluding data block */ - -#define WL_RPI_REP_BIN_NUM 8 -typedef struct wl_rm_rpi_rep { - uint8 rpi[WL_RPI_REP_BIN_NUM]; - int8 rpi_max[WL_RPI_REP_BIN_NUM]; -} wl_rm_rpi_rep_t; - -typedef struct wl_rm_rep { - uint32 token; /* overall measurement set token */ - uint32 len; /* length of measurement report block */ - wl_rm_rep_elt_t rep[1]; /* variable length block of reports */ -} wl_rm_rep_t; -#define WL_RM_REP_FIXED_LEN 8 - -#ifdef BCMCCX - -#define LEAP_USER_MAX 32 -#define LEAP_DOMAIN_MAX 32 -#define LEAP_PASSWORD_MAX 32 - -typedef struct wl_leap_info { - wlc_ssid_t ssid; - uint8 user_len; - uchar user[LEAP_USER_MAX]; - uint8 password_len; - uchar password[LEAP_PASSWORD_MAX]; - uint8 domain_len; - uchar domain[LEAP_DOMAIN_MAX]; -} wl_leap_info_t; - -typedef struct wl_leap_list { - uint32 buflen; - uint32 version; - uint32 count; - wl_leap_info_t leap_info[1]; -} wl_leap_list_t; -#endif /* BCMCCX */ - -typedef enum sup_auth_status { - /* Basic supplicant authentication states */ - WLC_SUP_DISCONNECTED = 0, - WLC_SUP_CONNECTING, - WLC_SUP_IDREQUIRED, - WLC_SUP_AUTHENTICATING, - WLC_SUP_AUTHENTICATED, - WLC_SUP_KEYXCHANGE, - WLC_SUP_KEYED, - WLC_SUP_TIMEOUT, - WLC_SUP_LAST_BASIC_STATE, - - /* Extended supplicant authentication states */ - /* Waiting to receive handshake msg M1 */ - WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, - /* Preparing to send handshake msg M2 */ - WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, - /* Waiting to receive handshake msg M3 */ - WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, - WLC_SUP_KEYXCHANGE_PREP_M4, /* Preparing to send handshake msg M4 */ - WLC_SUP_KEYXCHANGE_WAIT_G1, /* Waiting to receive handshake msg G1 */ - WLC_SUP_KEYXCHANGE_PREP_G2 /* Preparing to send handshake msg G2 */ -} sup_auth_status_t; - -typedef struct wl_wsec_key { - uint32 index; /* key index */ - uint32 len; /* key length */ - uint8 data[DOT11_MAX_KEY_SIZE]; /* key data */ - uint32 pad_1[18]; - uint32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ - uint32 flags; /* misc flags */ - uint32 pad_2[2]; - int pad_3; - int iv_initialized; /* has IV been initialized already? */ - int pad_4; - /* Rx IV */ - struct { - uint32 hi; /* upper 32 bits of IV */ - uint16 lo; /* lower 16 bits of IV */ - } rxiv; - uint32 pad_5[2]; - struct ether_addr ea; /* per station */ -} wl_wsec_key_t; - -#define WSEC_MIN_PSK_LEN 8 -#define WSEC_MAX_PSK_LEN 64 - -/* Flag for key material needing passhash'ing */ -#define WSEC_PASSPHRASE (1<<0) - -/* receptacle for WLC_SET_WSEC_PMK parameter */ -typedef struct { - ushort key_len; /* octets in key material */ - ushort flags; /* key handling qualification */ - uint8 key[WSEC_MAX_PSK_LEN]; /* PMK material */ -} wsec_pmk_t; - -typedef struct _pmkid { - struct ether_addr BSSID; - uint8 PMKID[WPA2_PMKID_LEN]; -} pmkid_t; - -typedef struct _pmkid_list { - uint32 npmkid; - pmkid_t pmkid[1]; -} pmkid_list_t; - -typedef struct _pmkid_cand { - struct ether_addr BSSID; - uint8 preauth; -} pmkid_cand_t; - -typedef struct _pmkid_cand_list { - uint32 npmkid_cand; - pmkid_cand_t pmkid_cand[1]; -} pmkid_cand_list_t; - -#define WL_STA_ANT_MAX 4 /* max possible rx antennas */ - -typedef struct wl_assoc_info { - uint32 req_len; - uint32 resp_len; - uint32 flags; - struct dot11_assoc_req req; - struct ether_addr reassoc_bssid; /* used in reassoc's */ - struct dot11_assoc_resp resp; -} wl_assoc_info_t; - -typedef struct wl_led_info { - uint32 index; /* led index */ - uint32 behavior; - uint8 activehi; -} wl_led_info_t; - - -/* srom read/write struct passed through ioctl */ -typedef struct { - uint byteoff; /* byte offset */ - uint nbytes; /* number of bytes */ - uint16 buf[1]; -} srom_rw_t; - -/* similar cis (srom or otp) struct [iovar: may not be aligned] */ -typedef struct { - uint32 source; /* cis source */ - uint32 byteoff; /* byte offset */ - uint32 nbytes; /* number of bytes */ - /* data follows here */ -} cis_rw_t; - -/* R_REG and W_REG struct passed through ioctl */ -typedef struct { - uint32 byteoff; /* byte offset of the field in d11regs_t */ - uint32 val; /* read/write value of the field */ - uint32 size; /* sizeof the field */ - uint band; /* band (optional) */ -} rw_reg_t; - -/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */ -/* PCL - Power Control Loop */ -typedef struct { - uint16 auto_ctrl; /* WL_ATTEN_XX */ - uint16 bb; /* Baseband attenuation */ - uint16 radio; /* Radio attenuation */ - uint16 txctl1; /* Radio TX_CTL1 value */ -} atten_t; - -/* Per-AC retry parameters */ -struct wme_tx_params_s { - uint8 short_retry; - uint8 short_fallback; - uint8 long_retry; - uint8 long_fallback; - uint16 max_rate; /* In units of 512 Kbps */ -}; - -typedef struct wme_tx_params_s wme_tx_params_t; - -#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) - -typedef struct wl_plc_nodelist { - uint32 count; /* Number of nodes */ - struct _node { - struct ether_addr ea; /* Node ether address */ - uint32 node_type; /* Node type */ - uint32 cost; /* PLC affinity */ - } node[1]; -} wl_plc_nodelist_t; - -typedef struct wl_plc_params { - uint32 cmd; /* Command */ - uint8 plc_failover; /* PLC failover control/status */ - struct ether_addr node_ea; /* Node ether address */ - uint32 cost; /* Link cost or mac cost */ -} wl_plc_params_t; - -/* Used to get specific link/ac parameters */ -typedef struct { - int32 ac; - uint8 val; - struct ether_addr ea; -} link_val_t; - - - -typedef struct { - uint16 ver; /* version of this struct */ - uint16 len; /* length in bytes of this structure */ - uint16 cap; /* sta's advertised capabilities */ - uint32 flags; /* flags defined below */ - uint32 idle; /* time since data pkt rx'd from sta */ - struct ether_addr ea; /* Station address */ - wl_rateset_t rateset; /* rateset in use */ - uint32 in; /* seconds elapsed since associated */ - uint32 listen_interval_inms; /* Min Listen interval in ms for this STA */ - uint32 tx_pkts; /* # of packets transmitted */ - uint32 tx_failures; /* # of packets failed */ - uint32 rx_ucast_pkts; /* # of unicast packets received */ - uint32 rx_mcast_pkts; /* # of multicast packets received */ - uint32 tx_rate; /* Rate of last successful tx frame */ - uint32 rx_rate; /* Rate of last successful rx frame */ - uint32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ - uint32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */ - uint32 tx_tot_pkts; /* # of tx pkts (ucast + mcast) */ - uint32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */ - uint32 tx_mcast_pkts; /* # of mcast pkts txed */ - uint64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */ - uint64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */ - uint64 tx_ucast_bytes; /* data bytes txed (ucast) */ - uint64 tx_mcast_bytes; /* # data bytes txed (mcast) */ - uint64 rx_ucast_bytes; /* data bytes recvd (ucast) */ - uint64 rx_mcast_bytes; /* data bytes recvd (mcast) */ - int8 rssi[WL_STA_ANT_MAX]; /* average rssi per antenna - * of data frames - */ - int8 nf[WL_STA_ANT_MAX]; /* per antenna noise floor */ - uint16 aid; /* association ID */ - uint16 ht_capabilities; /* advertised ht caps */ - uint16 vht_flags; /* converted vht flags */ - uint32 tx_pkts_retried; /* # of frames where a retry was necessary */ - uint32 tx_pkts_retry_exhausted; /* # of frames where a retry was - * exhausted - */ - int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /* Per antenna RSSI of last - * received data frame. - */ -} sta_info_t; - -#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts) - -#define WL_STA_VER 4 - -#define WLC_NUMRATES 16 /* max # of rates in a rateset */ - -typedef struct wlc_rateset { - uint32 count; /* number of rates in rates[] */ - uint8 rates[WLC_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */ - uint8 htphy_membership; /* HT PHY Membership */ - uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ - uint16 vht_mcsmap; /* supported vht mcs nss bit map */ -} wlc_rateset_t; - -/* Used to get specific STA parameters */ -typedef struct { - uint32 val; - struct ether_addr ea; -} scb_val_t; - -/* Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */ -typedef struct { - uint32 code; - scb_val_t ioctl_args; -} authops_t; - -/* channel encoding */ -typedef struct channel_info { - int hw_channel; - int target_channel; - int scan_channel; -} channel_info_t; - -/* For ioctls that take a list of MAC addresses */ -typedef struct maclist { - uint count; /* number of MAC addresses */ - struct ether_addr ea[1]; /* variable length array of MAC addresses */ -} maclist_t; - -/* get pkt count struct passed through ioctl */ -typedef struct get_pktcnt { - uint rx_good_pkt; - uint rx_bad_pkt; - uint tx_good_pkt; - uint tx_bad_pkt; - uint rx_ocast_good_pkt; /* unicast packets destined for others */ -} get_pktcnt_t; - -/* NINTENDO2 */ -#define LQ_IDX_MIN 0 -#define LQ_IDX_MAX 1 -#define LQ_IDX_AVG 2 -#define LQ_IDX_SUM 2 -#define LQ_IDX_LAST 3 -#define LQ_STOP_MONITOR 0 -#define LQ_START_MONITOR 1 - -/* Get averages RSSI, Rx PHY rate and SNR values */ -typedef struct { - int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */ - int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */ - int isvalid; /* Flag indicating whether above data is valid */ -} wl_lq_t; /* Link Quality */ - -typedef enum wl_wakeup_reason_type { - LCD_ON = 1, - LCD_OFF, - DRC1_WAKE, - DRC2_WAKE, - REASON_LAST -} wl_wr_type_t; - -typedef struct { -/* Unique filter id */ - uint32 id; - -/* stores the reason for the last wake up */ - uint8 reason; -} wl_wr_t; - -/* Get MAC specific rate histogram command */ -typedef struct { - struct ether_addr ea; /* MAC Address */ - uint8 ac_cat; /* Access Category */ - uint8 num_pkts; /* Number of packet entries to be averaged */ -} wl_mac_ratehisto_cmd_t; /* MAC Specific Rate Histogram command */ - -/* Get MAC rate histogram response */ -typedef struct { - uint32 rate[DOT11_RATE_MAX + 1]; /* Rates */ - uint32 mcs[WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX]; /* MCS counts */ - uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /* VHT counts */ - uint32 tsf_timer[2][2]; /* Start and End time for 8bytes value */ -} wl_mac_ratehisto_res_t; /* MAC Specific Rate Histogram Response */ - -/* Linux network driver ioctl encoding */ -typedef struct wl_ioctl { - uint cmd; /* common ioctl definition */ - void *buf; /* pointer to user buffer */ - uint len; /* length of user buffer */ - uint8 set; /* 1=set IOCTL; 0=query IOCTL */ - uint used; /* bytes read or written (optional) */ - uint needed; /* bytes needed (optional) */ -} wl_ioctl_t; -#ifdef CONFIG_COMPAT -typedef struct compat_wl_ioctl { - uint cmd; /* common ioctl definition */ - uint32 buf; /* pointer to user buffer */ - uint len; /* length of user buffer */ - uint8 set; /* 1=set IOCTL; 0=query IOCTL */ - uint used; /* bytes read or written (optional) */ - uint needed; /* bytes needed (optional) */ -} compat_wl_ioctl_t; -#endif /* CONFIG_COMPAT */ - - -/* - * Structure for passing hardware and software - * revision info up from the driver. - */ -typedef struct wlc_rev_info { - uint vendorid; /* PCI vendor id */ - uint deviceid; /* device id of chip */ - uint radiorev; /* radio revision */ - uint chiprev; /* chip revision */ - uint corerev; /* core revision */ - uint boardid; /* board identifier (usu. PCI sub-device id) */ - uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ - uint boardrev; /* board revision */ - uint driverrev; /* driver version */ - uint ucoderev; /* microcode version */ - uint bus; /* bus type */ - uint chipnum; /* chip number */ - uint phytype; /* phy type */ - uint phyrev; /* phy revision */ - uint anarev; /* anacore rev */ - uint chippkg; /* chip package info */ - uint nvramrev; /* nvram revision number */ -} wlc_rev_info_t; - -#define WL_REV_INFO_LEGACY_LENGTH 48 - -#define WL_BRAND_MAX 10 -typedef struct wl_instance_info { - uint instance; - char brand[WL_BRAND_MAX]; -} wl_instance_info_t; - -/* structure to change size of tx fifo */ -typedef struct wl_txfifo_sz { - uint16 magic; - uint16 fifo; - uint16 size; -} wl_txfifo_sz_t; - -/* Transfer info about an IOVar from the driver */ -/* Max supported IOV name size in bytes, + 1 for nul termination */ -#define WLC_IOV_NAME_LEN 30 -typedef struct wlc_iov_trx_s { - uint8 module; - uint8 type; - char name[WLC_IOV_NAME_LEN]; -} wlc_iov_trx_t; - -/* bump this number if you change the ioctl interface */ -#define WLC_IOCTL_VERSION 2 -#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1 - -#ifdef CONFIG_USBRNDIS_RETAIL -/* struct passed in for WLC_NDCONFIG_ITEM */ -typedef struct { - char *name; - void *param; -} ndconfig_item_t; -#endif - - -#define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[0] ... */ - -#define WL_PHY_PAVAR_VER 1 /* pavars version */ -#define WL_PHY_PAVARS2_NUM 3 /* a1, b0, b1 */ -typedef struct wl_pavars2 { - uint16 ver; /* version of this struct */ - uint16 len; /* len of this structure */ - uint16 inuse; /* driver return 1 for a1,b0,b1 in current band range */ - uint16 phy_type; /* phy type */ - uint16 bandrange; - uint16 chain; - uint16 inpa[WL_PHY_PAVARS2_NUM]; /* phy pavars for one band range */ -} wl_pavars2_t; - -typedef struct wl_po { - uint16 phy_type; /* Phy type */ - uint16 band; - uint16 cckpo; - uint32 ofdmpo; - uint16 mcspo[8]; -} wl_po_t; - -#define WL_NUM_RPCALVARS 5 /* number of rpcal vars */ - -typedef struct wl_rpcal { - uint16 value; - uint16 update; -} wl_rpcal_t; - -typedef struct wl_aci_args { - int enter_aci_thresh; /* Trigger level to start detecting ACI */ - int exit_aci_thresh; /* Trigger level to exit ACI mode */ - int usec_spin; /* microsecs to delay between rssi samples */ - int glitch_delay; /* interval between ACI scans when glitch count is consistently high */ - uint16 nphy_adcpwr_enter_thresh; /* ADC power to enter ACI mitigation mode */ - uint16 nphy_adcpwr_exit_thresh; /* ADC power to exit ACI mitigation mode */ - uint16 nphy_repeat_ctr; /* Number of tries per channel to compute power */ - uint16 nphy_num_samples; /* Number of samples to compute power on one channel */ - uint16 nphy_undetect_window_sz; /* num of undetects to exit ACI Mitigation mode */ - uint16 nphy_b_energy_lo_aci; /* low ACI power energy threshold for bphy */ - uint16 nphy_b_energy_md_aci; /* mid ACI power energy threshold for bphy */ - uint16 nphy_b_energy_hi_aci; /* high ACI power energy threshold for bphy */ - uint16 nphy_noise_noassoc_glitch_th_up; /* wl interference 4 */ - uint16 nphy_noise_noassoc_glitch_th_dn; - uint16 nphy_noise_assoc_glitch_th_up; - uint16 nphy_noise_assoc_glitch_th_dn; - uint16 nphy_noise_assoc_aci_glitch_th_up; - uint16 nphy_noise_assoc_aci_glitch_th_dn; - uint16 nphy_noise_assoc_enter_th; - uint16 nphy_noise_noassoc_enter_th; - uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; - uint16 nphy_noise_noassoc_crsidx_incr; - uint16 nphy_noise_assoc_crsidx_incr; - uint16 nphy_noise_crsidx_decr; -} wl_aci_args_t; - -#define WL_ACI_ARGS_LEGACY_LENGTH 16 /* bytes of pre NPHY aci args */ -#define WL_SAMPLECOLLECT_T_VERSION 2 /* version of wl_samplecollect_args_t struct */ -typedef struct wl_samplecollect_args { - /* version 0 fields */ - uint8 coll_us; - int cores; - /* add'l version 1 fields */ - uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */ - uint16 length; /* length of entire structure */ - int8 trigger; - uint16 timeout; - uint16 mode; - uint32 pre_dur; - uint32 post_dur; - uint8 gpio_sel; - uint8 downsamp; - uint8 be_deaf; - uint8 agc; /* loop from init gain and going down */ - uint8 filter; /* override high pass corners to lowest */ - /* add'l version 2 fields */ - uint8 trigger_state; - uint8 module_sel1; - uint8 module_sel2; - uint16 nsamps; - int bitStart; - uint32 gpioCapMask; -} wl_samplecollect_args_t; - -#define WL_SAMPLEDATA_T_VERSION 1 /* version of wl_samplecollect_args_t struct */ -/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */ -#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 - -typedef struct wl_sampledata { - uint16 version; /* structure version */ - uint16 size; /* size of structure */ - uint16 tag; /* Header/Data */ - uint16 length; /* data length */ - uint32 flag; /* bit def */ -} wl_sampledata_t; - - -/* WL_OTA START */ -/* OTA Test Status */ -enum { - WL_OTA_TEST_IDLE = 0, /* Default Idle state */ - WL_OTA_TEST_ACTIVE = 1, /* Test Running */ - WL_OTA_TEST_SUCCESS = 2, /* Successfully Finished Test */ - WL_OTA_TEST_FAIL = 3 /* Test Failed in the Middle */ -}; -/* OTA SYNC Status */ -enum { - WL_OTA_SYNC_IDLE = 0, /* Idle state */ - WL_OTA_SYNC_ACTIVE = 1, /* Waiting for Sync */ - WL_OTA_SYNC_FAIL = 2 /* Sync pkt not recieved */ -}; - -/* Various error states dut can get stuck during test */ -enum { - WL_OTA_SKIP_TEST_CAL_FAIL = 1, /* Phy calibration failed */ - WL_OTA_SKIP_TEST_SYNCH_FAIL = 2, /* Sync Packet not recieved */ - WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL = 3, /* Cmd flow file download failed */ - WL_OTA_SKIP_TEST_NO_TEST_FOUND = 4, /* No test found in Flow file */ - WL_OTA_SKIP_TEST_WL_NOT_UP = 5, /* WL UP failed */ - WL_OTA_SKIP_TEST_UNKNOWN_CALL /* Unintentional scheduling on ota test */ -}; - -/* Differentiator for ota_tx and ota_rx */ -enum { - WL_OTA_TEST_TX = 0, /* ota_tx */ - WL_OTA_TEST_RX = 1, /* ota_rx */ -}; - -/* Catch 3 modes of operation: 20Mhz, 40Mhz, 20 in 40 Mhz */ -enum { - WL_OTA_TEST_BW_20_IN_40MHZ = 0, /* 20 in 40 operation */ - WL_OTA_TEST_BW_20MHZ = 1, /* 20 Mhz operation */ - WL_OTA_TEST_BW_40MHZ = 2 /* full 40Mhz operation */ -}; -typedef struct ota_rate_info { - uint8 rate_cnt; /* Total number of rates */ - uint8 rate_val_mbps[WL_OTA_TEST_MAX_NUM_RATE]; /* array of rates from 1mbps to 130mbps */ - /* for legacy rates : ratein mbps * 2 */ - /* for HT rates : mcs index */ -} ota_rate_info_t; - -typedef struct ota_power_info { - int8 pwr_ctrl_on; /* power control on/off */ - int8 start_pwr; /* starting power/index */ - int8 delta_pwr; /* delta power/index */ - int8 end_pwr; /* end power/index */ -} ota_power_info_t; - -typedef struct ota_packetengine { - uint16 delay; /* Inter-packet delay */ - /* for ota_tx, delay is tx ifs in micro seconds */ - /* for ota_rx, delay is wait time in milliseconds */ - uint16 nframes; /* Number of frames */ - uint16 length; /* Packet length */ -} ota_packetengine_t; - -/* Test info vector */ -typedef struct wl_ota_test_args { - uint8 cur_test; /* test phase */ - uint8 chan; /* channel */ - uint8 bw; /* bandwidth */ - uint8 control_band; /* control band */ - uint8 stf_mode; /* stf mode */ - ota_rate_info_t rt_info; /* Rate info */ - ota_packetengine_t pkteng; /* packeteng info */ - uint8 txant; /* tx antenna */ - uint8 rxant; /* rx antenna */ - ota_power_info_t pwr_info; /* power sweep info */ - uint8 wait_for_sync; /* wait for sync or not */ -} wl_ota_test_args_t; - -typedef struct wl_ota_test_vector { - wl_ota_test_args_t test_arg[WL_OTA_TEST_MAX_NUM_SEQ]; /* Test argument struct */ - uint16 test_cnt; /* Total no of test */ - uint8 file_dwnld_valid; /* File successfully downloaded */ - uint8 sync_timeout; /* sync packet timeout */ - int8 sync_fail_action; /* sync fail action */ - struct ether_addr sync_mac; /* macaddress for sync pkt */ - struct ether_addr tx_mac; /* macaddress for tx */ - struct ether_addr rx_mac; /* macaddress for rx */ - int8 loop_test; /* dbg feature to loop the test */ -} wl_ota_test_vector_t; - - -/* struct copied back form dongle to host to query the status */ -typedef struct wl_ota_test_status { - int16 cur_test_cnt; /* test phase */ - int8 skip_test_reason; /* skip test reasoin */ - wl_ota_test_args_t test_arg; /* cur test arg details */ - uint16 test_cnt; /* total no of test downloaded */ - uint8 file_dwnld_valid; /* file successfully downloaded ? */ - uint8 sync_timeout; /* sync timeout */ - int8 sync_fail_action; /* sync fail action */ - struct ether_addr sync_mac; /* macaddress for sync pkt */ - struct ether_addr tx_mac; /* tx mac address */ - struct ether_addr rx_mac; /* rx mac address */ - uint8 test_stage; /* check the test status */ - int8 loop_test; /* Debug feature to puts test enfine in a loop */ - uint8 sync_status; /* sync status */ -} wl_ota_test_status_t; - -/* WL_OTA END */ - -/* wl_radar_args_t */ -typedef struct { - int npulses; /* required number of pulses at n * t_int */ - int ncontig; /* required number of pulses at t_int */ - int min_pw; /* minimum pulse width (20 MHz clocks) */ - int max_pw; /* maximum pulse width (20 MHz clocks) */ - uint16 thresh0; /* Radar detection, thresh 0 */ - uint16 thresh1; /* Radar detection, thresh 1 */ - uint16 blank; /* Radar detection, blank control */ - uint16 fmdemodcfg; /* Radar detection, fmdemod config */ - int npulses_lp; /* Radar detection, minimum long pulses */ - int min_pw_lp; /* Minimum pulsewidth for long pulses */ - int max_pw_lp; /* Maximum pulsewidth for long pulses */ - int min_fm_lp; /* Minimum fm for long pulses */ - int max_span_lp; /* Maximum deltat for long pulses */ - int min_deltat; /* Minimum spacing between pulses */ - int max_deltat; /* Maximum spacing between pulses */ - uint16 autocorr; /* Radar detection, autocorr on or off */ - uint16 st_level_time; /* Radar detection, start_timing level */ - uint16 t2_min; /* minimum clocks needed to remain in state 2 */ - uint32 version; /* version */ - uint32 fra_pulse_err; /* sample error margin for detecting French radar pulsed */ - int npulses_fra; /* Radar detection, minimum French pulses set */ - int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */ - int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */ - uint16 percal_mask; /* defines which period cal is masked from radar detection */ - int quant; /* quantization resolution to pulse positions */ - uint32 min_burst_intv_lp; /* minimum burst to burst interval for bin3 radar */ - uint32 max_burst_intv_lp; /* maximum burst to burst interval for bin3 radar */ - int nskip_rst_lp; /* number of skipped pulses before resetting lp buffer */ - int max_pw_tol; /* maximum tollerance allowed in detected pulse width for radar detection */ - uint16 feature_mask; /* 16-bit mask to specify enabled features */ -} wl_radar_args_t; - -#define WL_RADAR_ARGS_VERSION 2 - -typedef struct { - uint32 version; /* version */ - uint16 thresh0_20_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */ - uint16 thresh1_20_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */ - uint16 thresh0_40_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */ - uint16 thresh1_40_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */ - uint16 thresh0_80_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */ - uint16 thresh1_80_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */ - uint16 thresh0_20_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */ - uint16 thresh1_20_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */ - uint16 thresh0_40_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */ - uint16 thresh1_40_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */ - uint16 thresh0_80_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */ - uint16 thresh1_80_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */ -#ifdef WL11AC160 - uint16 thresh0_160_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */ - uint16 thresh1_160_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */ - uint16 thresh0_160_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */ - uint16 thresh1_160_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */ -#endif /* WL11AC160 */ -} wl_radar_thr_t; - -#define WL_RADAR_THR_VERSION 2 - -/* RSSI per antenna */ -typedef struct { - uint32 version; /* version field */ - uint32 count; /* number of valid antenna rssi */ - int8 rssi_ant[WL_RSSI_ANT_MAX]; /* rssi per antenna */ -} wl_rssi_ant_t; - -/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */ -typedef struct { - uint state; /* noted by WL_DFS_CACSTATE_XX. */ - uint duration; /* time spent in ms in state. */ - /* as dfs enters ISM state, it removes the operational channel from quiet channel - * list and notes the channel in channel_cleared. set to 0 if no channel is cleared - */ - chanspec_t chanspec_cleared; - /* chanspec cleared used to be a uint, add another to uint16 to maintain size */ - uint16 pad; -} wl_dfs_status_t; - -/* data structure used in 'radar_status' wl interface, which is use to query radar det status */ -typedef struct { - bool detected; - int count; - bool pretended; - uint32 radartype; - uint32 timenow; - uint32 timefromL; - int lp_csect_single; - int detected_pulse_index; - int nconsecq_pulses; - chanspec_t ch; - int pw[10]; - int intv[10]; - int fm[10]; -} wl_radar_status_t; - -#define NUM_PWRCTRL_RATES 12 - -typedef struct { - uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /* User set target */ - uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /* reg and local power limit */ - uint8 txpwr_local_max; /* local max according to the AP */ - uint8 txpwr_local_constraint; /* local constraint according to the AP */ - uint8 txpwr_chan_reg_max; /* Regulatory max for this channel */ - uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /* Latest target for 2.4 and 5 Ghz */ - uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ - uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /* On G phy, OFDM power offset */ - uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /* Max CCK power for this band (SROM) */ - uint8 txpwr_bphy_ofdm_max; /* Max OFDM power for this band (SROM) */ - uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /* Max power for A band (SROM) */ - int8 txpwr_antgain[2]; /* Ant gain for each band - from SROM */ - uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ -} tx_power_legacy_t; - -#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 - -typedef struct { - uint32 flags; - chanspec_t chanspec; /* txpwr report for this channel */ - chanspec_t local_chanspec; /* channel on which we are associated */ - uint8 local_max; /* local max according to the AP */ - uint8 local_constraint; /* local constraint according to the AP */ - int8 antgain[2]; /* Ant gain for each band - from SROM */ - uint8 rf_cores; /* count of RF Cores being reported */ - uint8 est_Pout[4]; /* Latest tx power out estimate per RF - * chain without adjustment - */ - uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ - uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */ - uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */ - uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */ - uint8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */ -} tx_power_legacy2_t; - -/* TX Power index defines */ -#define WL_NUM_RATES_CCK 4 /* 1, 2, 5.5, 11 Mbps */ -#define WL_NUM_RATES_OFDM 8 /* 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */ -#define WL_NUM_RATES_MCS_1STREAM 8 /* MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */ -#define WL_NUM_RATES_EXTRA_VHT 2 /* Additional VHT 11AC rates */ -#define WL_NUM_RATES_VHT 10 -#define WL_NUM_RATES_MCS32 1 - -#define WLC_NUM_RATES_CCK WL_NUM_RATES_CCK -#define WLC_NUM_RATES_OFDM WL_NUM_RATES_OFDM -#define WLC_NUM_RATES_MCS_1_STREAM WL_NUM_RATES_MCS_1STREAM -#define WLC_NUM_RATES_MCS_2_STREAM WL_NUM_RATES_MCS_1STREAM -#define WLC_NUM_RATES_MCS32 WL_NUM_RATES_MCS32 -#define WL_TX_POWER_CCK_NUM WL_NUM_RATES_CCK -#define WL_TX_POWER_OFDM_NUM WL_NUM_RATES_OFDM -#define WL_TX_POWER_MCS_1_STREAM_NUM WL_NUM_RATES_MCS_1STREAM -#define WL_TX_POWER_MCS_2_STREAM_NUM WL_NUM_RATES_MCS_1STREAM -#define WL_TX_POWER_MCS_32_NUM WL_NUM_RATES_MCS32 - -#define WL_NUM_2x2_ELEMENTS 4 -#define WL_NUM_3x3_ELEMENTS 6 - -typedef struct { - uint16 ver; /* version of this struct */ - uint16 len; /* length in bytes of this structure */ - uint32 flags; - chanspec_t chanspec; /* txpwr report for this channel */ - chanspec_t local_chanspec; /* channel on which we are associated */ - uint32 buflen; /* ppr buffer length */ - uint8 pprbuf[1]; /* Latest target power buffer */ -} wl_txppr_t; - -#define WL_TXPPR_VERSION 1 -#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) -#define TX_POWER_T_VERSION 44 - - -typedef struct tx_inst_power { - uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ - uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ -} tx_inst_power_t; - -#define WL_NUM_TXCHAIN_MAX 4 -typedef struct wl_txchain_pwr_offsets { - int8 offset[WL_NUM_TXCHAIN_MAX]; /* quarter dBm signed offset for each chain */ -} wl_txchain_pwr_offsets_t; -/* maximum channels returned by the get valid channels iovar */ -#define WL_NUMCHANNELS 64 - -/* - * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, - * a one-byte length, and a variable length value. RSSI type tuple must be present - * in the array. - * - * Types are defined in "join preference types" section. - * - * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple - * and must be set to zero. - * - * Values are defined below. - * - * 1. RSSI - 2 octets - * offset 0: reserved - * offset 1: reserved - * - * 2. WPA - 2 + 12 * n octets (n is # tuples defined below) - * offset 0: reserved - * offset 1: # of tuples - * offset 2: tuple 1 - * offset 14: tuple 2 - * ... - * offset 2 + 12 * (n - 1) octets: tuple n - * - * struct wpa_cfg_tuple { - * uint8 akm[DOT11_OUI_LEN+1]; akm suite - * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite - * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite - * }; - * - * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY. - * - * 3. BAND - 2 octets - * offset 0: reserved - * offset 1: see "band preference" and "band types" - * - * 4. BAND RSSI - 2 octets - * offset 0: band types - * offset 1: +ve RSSI boost value in dB - */ - -struct tsinfo_arg { - uint8 octets[3]; -}; - -#define NFIFO 6 /* # tx/rx fifopairs */ -#define NREINITREASONCOUNT 8 -#define REINITREASONIDX(_x) (((_x) < NREINITREASONCOUNT) ? (_x) : 0) - -#define WL_CNT_T_VERSION 10 /* current version of wl_cnt_t struct */ - -typedef struct { - uint16 version; /* see definition of WL_CNT_T_VERSION */ - uint16 length; /* length of entire structure */ - - /* transmit stat counters */ - uint32 txframe; /* tx data frames */ - uint32 txbyte; /* tx data bytes */ - uint32 txretrans; /* tx mac retransmits */ - uint32 txerror; /* tx data errors (derived: sum of others) */ - uint32 txctl; /* tx management frames */ - uint32 txprshort; /* tx short preamble frames */ - uint32 txserr; /* tx status errors */ - uint32 txnobuf; /* tx out of buffers errors */ - uint32 txnoassoc; /* tx discard because we're not associated */ - uint32 txrunt; /* tx runt frames */ - uint32 txchit; /* tx header cache hit (fastpath) */ - uint32 txcmiss; /* tx header cache miss (slowpath) */ - - /* transmit chip error counters */ - uint32 txuflo; /* tx fifo underflows */ - uint32 txphyerr; /* tx phy errors (indicated in tx status) */ - uint32 txphycrs; - - /* receive stat counters */ - uint32 rxframe; /* rx data frames */ - uint32 rxbyte; /* rx data bytes */ - uint32 rxerror; /* rx data errors (derived: sum of others) */ - uint32 rxctl; /* rx management frames */ - uint32 rxnobuf; /* rx out of buffers errors */ - uint32 rxnondata; /* rx non data frames in the data channel errors */ - uint32 rxbadds; /* rx bad DS errors */ - uint32 rxbadcm; /* rx bad control or management frames */ - uint32 rxfragerr; /* rx fragmentation errors */ - uint32 rxrunt; /* rx runt frames */ - uint32 rxgiant; /* rx giant frames */ - uint32 rxnoscb; /* rx no scb error */ - uint32 rxbadproto; /* rx invalid frames */ - uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ - uint32 rxbadda; /* rx frames tossed for invalid da */ - uint32 rxfilter; /* rx frames filtered out */ - - /* receive chip error counters */ - uint32 rxoflo; /* rx fifo overflow errors */ - uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ - - uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ - uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ - uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ - - /* misc counters */ - uint32 dmade; /* tx/rx dma descriptor errors */ - uint32 dmada; /* tx/rx dma data errors */ - uint32 dmape; /* tx/rx dma descriptor protocol errors */ - uint32 reset; /* reset count */ - uint32 tbtt; /* cnts the TBTT int's */ - uint32 txdmawar; - uint32 pkt_callback_reg_fail; /* callbacks register failure */ - - /* MAC counters: 32-bit version of d11.h's macstat_t */ - uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, - * Control Management (includes retransmissions) - */ - uint32 txrtsfrm; /* number of RTS sent out by the MAC */ - uint32 txctsfrm; /* number of CTS sent out by the MAC */ - uint32 txackfrm; /* number of ACK frames sent out */ - uint32 txdnlfrm; /* Not used */ - uint32 txbcnfrm; /* beacons transmitted */ - uint32 txfunfl[6]; /* per-fifo tx underflows */ - uint32 rxtoolate; /* receive too late */ - uint32 txfbw; /* transmit at fallback bw (dynamic bw) */ - uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS - * or BCN) - */ - uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for - * driver enqueued frames - */ - uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ - uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ - uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not - * data/control/management - */ - uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ - uint32 rxbadplcp; /* parity check of the PLCP header failed */ - uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ - uint32 rxstrt; /* Number of received frames with a good PLCP - * (i.e. passing parity check) - */ - uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ - uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ - uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ - uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ - uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ - uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ - uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ - uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ - uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ - uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ - uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ - uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ - uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ - uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC - * (unlikely to see these) - */ - uint32 rxbeaconmbss; /* beacons received from member of BSS */ - uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from - * other BSS (WDS FRAME) - */ - uint32 rxbeaconobss; /* beacons received from other BSS */ - uint32 rxrsptmout; /* Number of response timeouts for transmitted frames - * expecting a response - */ - uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ - uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ - uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ - uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ - uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ - uint32 pmqovfl; /* Number of PMQ overflows */ - uint32 rxcgprqfrm; /* Number of received Probe requests that made it into - * the PRQ fifo - */ - uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ - uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did - * not get ACK - */ - uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ - uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ - * fifo because a probe response could not be sent out within - * the time limit defined in M_PRS_MAXTIME - */ - uint32 rxnack; /* obsolete */ - uint32 frmscons; /* obsolete */ - uint32 txnack; /* obsolete */ - uint32 rxback; /* blockack rxcnt */ - uint32 txback; /* blockack txcnt */ - - /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ - uint32 txfrag; /* dot11TransmittedFragmentCount */ - uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ - uint32 txfail; /* dot11FailedCount */ - uint32 txretry; /* dot11RetryCount */ - uint32 txretrie; /* dot11MultipleRetryCount */ - uint32 rxdup; /* dot11FrameduplicateCount */ - uint32 txrts; /* dot11RTSSuccessCount */ - uint32 txnocts; /* dot11RTSFailureCount */ - uint32 txnoack; /* dot11ACKFailureCount */ - uint32 rxfrag; /* dot11ReceivedFragmentCount */ - uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ - uint32 rxcrc; /* dot11FCSErrorCount */ - uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ - uint32 rxundec; /* dot11WEPUndecryptableCount */ - - /* WPA2 counters (see rxundec for DecryptFailureCount) */ - uint32 tkipmicfaill; /* TKIPLocalMICFailures */ - uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ - uint32 tkipreplay; /* TKIPReplays */ - uint32 ccmpfmterr; /* CCMPFormatErrors */ - uint32 ccmpreplay; /* CCMPReplays */ - uint32 ccmpundec; /* CCMPDecryptErrors */ - uint32 fourwayfail; /* FourWayHandshakeFailures */ - uint32 wepundec; /* dot11WEPUndecryptableCount */ - uint32 wepicverr; /* dot11WEPICVErrorCount */ - uint32 decsuccess; /* DecryptSuccessCount */ - uint32 tkipicverr; /* TKIPICVErrorCount */ - uint32 wepexcluded; /* dot11WEPExcludedCount */ - - uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ - uint32 psmwds; /* Count PSM watchdogs */ - uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ - - /* MBSS counters, AP only */ - uint32 prq_entries_handled; /* PRQ entries read in */ - uint32 prq_undirected_entries; /* which were bcast bss & ssid */ - uint32 prq_bad_entries; /* which could not be translated to info */ - uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ - uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ - uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ - uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ - - /* per-rate receive stat counters */ - uint32 rx1mbps; /* packets rx at 1Mbps */ - uint32 rx2mbps; /* packets rx at 2Mbps */ - uint32 rx5mbps5; /* packets rx at 5.5Mbps */ - uint32 rx6mbps; /* packets rx at 6Mbps */ - uint32 rx9mbps; /* packets rx at 9Mbps */ - uint32 rx11mbps; /* packets rx at 11Mbps */ - uint32 rx12mbps; /* packets rx at 12Mbps */ - uint32 rx18mbps; /* packets rx at 18Mbps */ - uint32 rx24mbps; /* packets rx at 24Mbps */ - uint32 rx36mbps; /* packets rx at 36Mbps */ - uint32 rx48mbps; /* packets rx at 48Mbps */ - uint32 rx54mbps; /* packets rx at 54Mbps */ - uint32 rx108mbps; /* packets rx at 108mbps */ - uint32 rx162mbps; /* packets rx at 162mbps */ - uint32 rx216mbps; /* packets rx at 216 mbps */ - uint32 rx270mbps; /* packets rx at 270 mbps */ - uint32 rx324mbps; /* packets rx at 324 mbps */ - uint32 rx378mbps; /* packets rx at 378 mbps */ - uint32 rx432mbps; /* packets rx at 432 mbps */ - uint32 rx486mbps; /* packets rx at 486 mbps */ - uint32 rx540mbps; /* packets rx at 540 mbps */ - - /* pkteng rx frame stats */ - uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ - uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ - - uint32 rfdisable; /* count of radio disables */ - uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ - uint32 bphy_badplcp; - - uint32 txexptime; /* Tx frames suppressed due to timer expiration */ - - uint32 txmpdu_sgi; /* count for sgi transmit */ - uint32 rxmpdu_sgi; /* count for sgi received */ - uint32 txmpdu_stbc; /* count for stbc transmit */ - uint32 rxmpdu_stbc; /* count for stbc received */ - - uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ - - /* WPA2 counters (see rxundec for DecryptFailureCount) */ - uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ - uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ - uint32 tkipreplay_mcst; /* TKIPReplays */ - uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ - uint32 ccmpreplay_mcst; /* CCMPReplays */ - uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ - uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ - uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ - uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ - uint32 decsuccess_mcst; /* DecryptSuccessCount */ - uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ - uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ - - uint32 dma_hang; /* count for dma hang */ - uint32 reinit; /* count for reinit */ - - uint32 pstatxucast; /* count of ucast frames xmitted on all psta assoc */ - uint32 pstatxnoassoc; /* count of txnoassoc frames xmitted on all psta assoc */ - uint32 pstarxucast; /* count of ucast frames received on all psta assoc */ - uint32 pstarxbcmc; /* count of bcmc frames received on all psta */ - uint32 pstatxbcmc; /* count of bcmc frames transmitted on all psta */ - - uint32 cso_passthrough; /* hw cso required but passthrough */ - uint32 cso_normal; /* hw cso hdr for normal process */ - uint32 chained; /* number of frames chained */ - uint32 chainedsz1; /* number of chain size 1 frames */ - uint32 unchained; /* number of frames not chained */ - uint32 maxchainsz; /* max chain size so far */ - uint32 currchainsz; /* current chain size */ - uint32 rxdrop20s; /* drop secondary cnt */ - uint32 pciereset; /* Secondary Bus Reset issued by driver */ - uint32 cfgrestore; /* configspace restore by driver */ - uint32 reinitreason[NREINITREASONCOUNT]; /* reinitreason counters; 0: Unknown reason */ - uint32 rxrtry; /* num of received packets with retry bit on */ -} wl_cnt_t; - -typedef struct { - uint16 version; /* see definition of WL_CNT_T_VERSION */ - uint16 length; /* length of entire structure */ - - /* transmit stat counters */ - uint32 txframe; /* tx data frames */ - uint32 txbyte; /* tx data bytes */ - uint32 txretrans; /* tx mac retransmits */ - uint32 txerror; /* tx data errors (derived: sum of others) */ - uint32 txctl; /* tx management frames */ - uint32 txprshort; /* tx short preamble frames */ - uint32 txserr; /* tx status errors */ - uint32 txnobuf; /* tx out of buffers errors */ - uint32 txnoassoc; /* tx discard because we're not associated */ - uint32 txrunt; /* tx runt frames */ - uint32 txchit; /* tx header cache hit (fastpath) */ - uint32 txcmiss; /* tx header cache miss (slowpath) */ - - /* transmit chip error counters */ - uint32 txuflo; /* tx fifo underflows */ - uint32 txphyerr; /* tx phy errors (indicated in tx status) */ - uint32 txphycrs; - - /* receive stat counters */ - uint32 rxframe; /* rx data frames */ - uint32 rxbyte; /* rx data bytes */ - uint32 rxerror; /* rx data errors (derived: sum of others) */ - uint32 rxctl; /* rx management frames */ - uint32 rxnobuf; /* rx out of buffers errors */ - uint32 rxnondata; /* rx non data frames in the data channel errors */ - uint32 rxbadds; /* rx bad DS errors */ - uint32 rxbadcm; /* rx bad control or management frames */ - uint32 rxfragerr; /* rx fragmentation errors */ - uint32 rxrunt; /* rx runt frames */ - uint32 rxgiant; /* rx giant frames */ - uint32 rxnoscb; /* rx no scb error */ - uint32 rxbadproto; /* rx invalid frames */ - uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ - uint32 rxbadda; /* rx frames tossed for invalid da */ - uint32 rxfilter; /* rx frames filtered out */ - - /* receive chip error counters */ - uint32 rxoflo; /* rx fifo overflow errors */ - uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ - - uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ - uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ - uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ - - /* misc counters */ - uint32 dmade; /* tx/rx dma descriptor errors */ - uint32 dmada; /* tx/rx dma data errors */ - uint32 dmape; /* tx/rx dma descriptor protocol errors */ - uint32 reset; /* reset count */ - uint32 tbtt; /* cnts the TBTT int's */ - uint32 txdmawar; - uint32 pkt_callback_reg_fail; /* callbacks register failure */ - - /* MAC counters: 32-bit version of d11.h's macstat_t */ - uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, - * Control Management (includes retransmissions) - */ - uint32 txrtsfrm; /* number of RTS sent out by the MAC */ - uint32 txctsfrm; /* number of CTS sent out by the MAC */ - uint32 txackfrm; /* number of ACK frames sent out */ - uint32 txdnlfrm; /* Not used */ - uint32 txbcnfrm; /* beacons transmitted */ - uint32 txfunfl[6]; /* per-fifo tx underflows */ - uint32 rxtoolate; /* receive too late */ - uint32 txfbw; /* transmit at fallback bw (dynamic bw) */ - uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS - * or BCN) - */ - uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for - * driver enqueued frames - */ - uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ - uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ - uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not - * data/control/management - */ - uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ - uint32 rxbadplcp; /* parity check of the PLCP header failed */ - uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ - uint32 rxstrt; /* Number of received frames with a good PLCP - * (i.e. passing parity check) - */ - uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ - uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ - uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ - uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ - uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ - uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ - uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ - uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ - uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ - uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ - uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ - uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ - uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ - uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC - * (unlikely to see these) - */ - uint32 rxbeaconmbss; /* beacons received from member of BSS */ - uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from - * other BSS (WDS FRAME) - */ - uint32 rxbeaconobss; /* beacons received from other BSS */ - uint32 rxrsptmout; /* Number of response timeouts for transmitted frames - * expecting a response - */ - uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ - uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ - uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ - uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ - uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ - uint32 pmqovfl; /* Number of PMQ overflows */ - uint32 rxcgprqfrm; /* Number of received Probe requests that made it into - * the PRQ fifo - */ - uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ - uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did - * not get ACK - */ - uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ - uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ - * fifo because a probe response could not be sent out within - * the time limit defined in M_PRS_MAXTIME - */ - uint32 rxnack; - uint32 frmscons; - uint32 txnack; /* obsolete */ - uint32 rxback; /* blockack rxcnt */ - uint32 txback; /* blockack txcnt */ - - /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ - uint32 txfrag; /* dot11TransmittedFragmentCount */ - uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ - uint32 txfail; /* dot11FailedCount */ - uint32 txretry; /* dot11RetryCount */ - uint32 txretrie; /* dot11MultipleRetryCount */ - uint32 rxdup; /* dot11FrameduplicateCount */ - uint32 txrts; /* dot11RTSSuccessCount */ - uint32 txnocts; /* dot11RTSFailureCount */ - uint32 txnoack; /* dot11ACKFailureCount */ - uint32 rxfrag; /* dot11ReceivedFragmentCount */ - uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ - uint32 rxcrc; /* dot11FCSErrorCount */ - uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ - uint32 rxundec; /* dot11WEPUndecryptableCount */ - - /* WPA2 counters (see rxundec for DecryptFailureCount) */ - uint32 tkipmicfaill; /* TKIPLocalMICFailures */ - uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ - uint32 tkipreplay; /* TKIPReplays */ - uint32 ccmpfmterr; /* CCMPFormatErrors */ - uint32 ccmpreplay; /* CCMPReplays */ - uint32 ccmpundec; /* CCMPDecryptErrors */ - uint32 fourwayfail; /* FourWayHandshakeFailures */ - uint32 wepundec; /* dot11WEPUndecryptableCount */ - uint32 wepicverr; /* dot11WEPICVErrorCount */ - uint32 decsuccess; /* DecryptSuccessCount */ - uint32 tkipicverr; /* TKIPICVErrorCount */ - uint32 wepexcluded; /* dot11WEPExcludedCount */ - - uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ - - /* WPA2 counters (see rxundec for DecryptFailureCount) */ - uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ - uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ - uint32 tkipreplay_mcst; /* TKIPReplays */ - uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ - uint32 ccmpreplay_mcst; /* CCMPReplays */ - uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ - uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ - uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ - uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ - uint32 decsuccess_mcst; /* DecryptSuccessCount */ - uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ - uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ - - uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ - uint32 txexptime; /* Tx frames suppressed due to timer expiration */ - uint32 psmwds; /* Count PSM watchdogs */ - uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ - - /* MBSS counters, AP only */ - uint32 prq_entries_handled; /* PRQ entries read in */ - uint32 prq_undirected_entries; /* which were bcast bss & ssid */ - uint32 prq_bad_entries; /* which could not be translated to info */ - uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ - uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ - uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ - uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ - - /* per-rate receive stat counters */ - uint32 rx1mbps; /* packets rx at 1Mbps */ - uint32 rx2mbps; /* packets rx at 2Mbps */ - uint32 rx5mbps5; /* packets rx at 5.5Mbps */ - uint32 rx6mbps; /* packets rx at 6Mbps */ - uint32 rx9mbps; /* packets rx at 9Mbps */ - uint32 rx11mbps; /* packets rx at 11Mbps */ - uint32 rx12mbps; /* packets rx at 12Mbps */ - uint32 rx18mbps; /* packets rx at 18Mbps */ - uint32 rx24mbps; /* packets rx at 24Mbps */ - uint32 rx36mbps; /* packets rx at 36Mbps */ - uint32 rx48mbps; /* packets rx at 48Mbps */ - uint32 rx54mbps; /* packets rx at 54Mbps */ - uint32 rx108mbps; /* packets rx at 108mbps */ - uint32 rx162mbps; /* packets rx at 162mbps */ - uint32 rx216mbps; /* packets rx at 216 mbps */ - uint32 rx270mbps; /* packets rx at 270 mbps */ - uint32 rx324mbps; /* packets rx at 324 mbps */ - uint32 rx378mbps; /* packets rx at 378 mbps */ - uint32 rx432mbps; /* packets rx at 432 mbps */ - uint32 rx486mbps; /* packets rx at 486 mbps */ - uint32 rx540mbps; /* packets rx at 540 mbps */ - - /* pkteng rx frame stats */ - uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ - uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ - - uint32 rfdisable; /* count of radio disables */ - uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ - uint32 bphy_badplcp; - - uint32 txmpdu_sgi; /* count for sgi transmit */ - uint32 rxmpdu_sgi; /* count for sgi received */ - uint32 txmpdu_stbc; /* count for stbc transmit */ - uint32 rxmpdu_stbc; /* count for stbc received */ - - uint32 rxdrop20s; /* drop secondary cnt */ - -} wl_cnt_ver_six_t; - -#define WL_DELTA_STATS_T_VERSION 2 /* current version of wl_delta_stats_t struct */ - -typedef struct { - uint16 version; /* see definition of WL_DELTA_STATS_T_VERSION */ - uint16 length; /* length of entire structure */ - - /* transmit stat counters */ - uint32 txframe; /* tx data frames */ - uint32 txbyte; /* tx data bytes */ - uint32 txretrans; /* tx mac retransmits */ - uint32 txfail; /* tx failures */ - - /* receive stat counters */ - uint32 rxframe; /* rx data frames */ - uint32 rxbyte; /* rx data bytes */ - - /* per-rate receive stat counters */ - uint32 rx1mbps; /* packets rx at 1Mbps */ - uint32 rx2mbps; /* packets rx at 2Mbps */ - uint32 rx5mbps5; /* packets rx at 5.5Mbps */ - uint32 rx6mbps; /* packets rx at 6Mbps */ - uint32 rx9mbps; /* packets rx at 9Mbps */ - uint32 rx11mbps; /* packets rx at 11Mbps */ - uint32 rx12mbps; /* packets rx at 12Mbps */ - uint32 rx18mbps; /* packets rx at 18Mbps */ - uint32 rx24mbps; /* packets rx at 24Mbps */ - uint32 rx36mbps; /* packets rx at 36Mbps */ - uint32 rx48mbps; /* packets rx at 48Mbps */ - uint32 rx54mbps; /* packets rx at 54Mbps */ - uint32 rx108mbps; /* packets rx at 108mbps */ - uint32 rx162mbps; /* packets rx at 162mbps */ - uint32 rx216mbps; /* packets rx at 216 mbps */ - uint32 rx270mbps; /* packets rx at 270 mbps */ - uint32 rx324mbps; /* packets rx at 324 mbps */ - uint32 rx378mbps; /* packets rx at 378 mbps */ - uint32 rx432mbps; /* packets rx at 432 mbps */ - uint32 rx486mbps; /* packets rx at 486 mbps */ - uint32 rx540mbps; /* packets rx at 540 mbps */ - - /* phy stats */ - uint32 rxbadplcp; - uint32 rxcrsglitch; - uint32 bphy_rxcrsglitch; - uint32 bphy_badplcp; - -} wl_delta_stats_t; - -typedef struct { - uint32 packets; - uint32 bytes; -} wl_traffic_stats_t; - -typedef struct { - uint16 version; /* see definition of WL_WME_CNT_VERSION */ - uint16 length; /* length of entire structure */ - - wl_traffic_stats_t tx[AC_COUNT]; /* Packets transmitted */ - wl_traffic_stats_t tx_failed[AC_COUNT]; /* Packets dropped or failed to transmit */ - wl_traffic_stats_t rx[AC_COUNT]; /* Packets received */ - wl_traffic_stats_t rx_failed[AC_COUNT]; /* Packets failed to receive */ - - wl_traffic_stats_t forward[AC_COUNT]; /* Packets forwarded by AP */ - - wl_traffic_stats_t tx_expired[AC_COUNT]; /* packets dropped due to lifetime expiry */ - -} wl_wme_cnt_t; - -struct wl_msglevel2 { - uint32 low; - uint32 high; -}; - -typedef struct wl_mkeep_alive_pkt { - uint16 version; /* Version for mkeep_alive */ - uint16 length; /* length of fixed parameters in the structure */ - uint32 period_msec; - uint16 len_bytes; - uint8 keep_alive_id; /* 0 - 3 for N = 4 */ - uint8 data[1]; -} wl_mkeep_alive_pkt_t; - -#define WL_MKEEP_ALIVE_VERSION 1 -#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) -#define WL_MKEEP_ALIVE_PRECISION 500 - -/* TCP Keep-Alive conn struct */ -typedef struct wl_mtcpkeep_alive_conn_pkt { - struct ether_addr saddr; /* src mac address */ - struct ether_addr daddr; /* dst mac address */ - struct ipv4_addr sipaddr; /* source IP addr */ - struct ipv4_addr dipaddr; /* dest IP addr */ - uint16 sport; /* src port */ - uint16 dport; /* dest port */ - uint32 seq; /* seq number */ - uint32 ack; /* ACK number */ - uint16 tcpwin; /* TCP window */ -} wl_mtcpkeep_alive_conn_pkt_t; - -/* TCP Keep-Alive interval struct */ -typedef struct wl_mtcpkeep_alive_timers_pkt { - uint16 interval; /* interval timer */ - uint16 retry_interval; /* retry_interval timer */ - uint16 retry_count; /* retry_count */ -} wl_mtcpkeep_alive_timers_pkt_t; - -typedef struct wake_info { - uint32 wake_reason; - uint32 wake_info_len; /* size of packet */ - uchar packet[1]; -} wake_info_t; - -typedef struct wake_pkt { - uint32 wake_pkt_len; /* size of packet */ - uchar packet[1]; -} wake_pkt_t; - - -#define WL_MTCPKEEP_ALIVE_VERSION 1 - -#ifdef WLBA - -#define WLC_BA_CNT_VERSION 1 /* current version of wlc_ba_cnt_t */ - -/* block ack related stats */ -typedef struct wlc_ba_cnt { - uint16 version; /* WLC_BA_CNT_VERSION */ - uint16 length; /* length of entire structure */ - - /* transmit stat counters */ - uint32 txpdu; /* pdus sent */ - uint32 txsdu; /* sdus sent */ - uint32 txfc; /* tx side flow controlled packets */ - uint32 txfci; /* tx side flow control initiated */ - uint32 txretrans; /* retransmitted pdus */ - uint32 txbatimer; /* ba resend due to timer */ - uint32 txdrop; /* dropped packets */ - uint32 txaddbareq; /* addba req sent */ - uint32 txaddbaresp; /* addba resp sent */ - uint32 txdelba; /* delba sent */ - uint32 txba; /* ba sent */ - uint32 txbar; /* bar sent */ - uint32 txpad[4]; /* future */ - - /* receive side counters */ - uint32 rxpdu; /* pdus recd */ - uint32 rxqed; /* pdus buffered before sending up */ - uint32 rxdup; /* duplicate pdus */ - uint32 rxnobuf; /* pdus discarded due to no buf */ - uint32 rxaddbareq; /* addba req recd */ - uint32 rxaddbaresp; /* addba resp recd */ - uint32 rxdelba; /* delba recd */ - uint32 rxba; /* ba recd */ - uint32 rxbar; /* bar recd */ - uint32 rxinvba; /* invalid ba recd */ - uint32 rxbaholes; /* ba recd with holes */ - uint32 rxunexp; /* unexpected packets */ - uint32 rxpad[4]; /* future */ -} wlc_ba_cnt_t; -#endif /* WLBA */ - -/* structure for per-tid ampdu control */ -struct ampdu_tid_control { - uint8 tid; /* tid */ - uint8 enable; /* enable/disable */ -}; - -/* struct for per-tid, per-mode ampdu control */ -struct ampdu_tid_control_mode { - struct ampdu_tid_control control[NUMPRIO]; /* tid will be 0xff for not used element */ - char mode_name[8]; /* supported mode : AIBSS */ -}; - -/* structure for identifying ea/tid for sending addba/delba */ -struct ampdu_ea_tid { - struct ether_addr ea; /* Station address */ - uint8 tid; /* tid */ -}; -/* structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */ -struct ampdu_retry_tid { - uint8 tid; /* tid */ - uint8 retry; /* retry value */ -}; - -/* structure for dpt iovars */ -typedef struct dpt_iovar { - struct ether_addr ea; /* Station address */ - uint8 mode; /* mode: depends on iovar */ - uint32 pad; /* future */ -} dpt_iovar_t; - -#define DPT_FNAME_LEN 48 /* Max length of friendly name */ - -typedef struct dpt_status { - uint8 status; /* flags to indicate status */ - uint8 fnlen; /* length of friendly name */ - uchar name[DPT_FNAME_LEN]; /* friendly name */ - uint32 rssi; /* RSSI of the link */ - sta_info_t sta; /* sta info */ -} dpt_status_t; - -/* structure for dpt list */ -typedef struct dpt_list { - uint32 num; /* number of entries in struct */ - dpt_status_t status[1]; /* per station info */ -} dpt_list_t; - -/* structure for dpt friendly name */ -typedef struct dpt_fname { - uint8 len; /* length of friendly name */ - uchar name[DPT_FNAME_LEN]; /* friendly name */ -} dpt_fname_t; - -#define BDD_FNAME_LEN 32 /* Max length of friendly name */ -typedef struct bdd_fname { - uint8 len; /* length of friendly name */ - uchar name[BDD_FNAME_LEN]; /* friendly name */ -} bdd_fname_t; - -/* structure for addts arguments */ -/* For ioctls that take a list of TSPEC */ -struct tslist { - int count; /* number of tspecs */ - struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */ -}; - -#ifdef WLTDLS -/* structure for tdls iovars */ -typedef struct tdls_iovar { - struct ether_addr ea; /* Station address */ - uint8 mode; /* mode: depends on iovar */ - chanspec_t chanspec; - uint32 pad; /* future */ -} tdls_iovar_t; - -#define TDLS_WFD_IE_SIZE 512 -/* structure for tdls wfd ie */ -typedef struct tdls_wfd_ie_iovar { - struct ether_addr ea; /* Station address */ - uint8 mode; - uint16 length; - uint8 data[TDLS_WFD_IE_SIZE]; -} tdls_wfd_ie_iovar_t; -#endif /* WLTDLS */ - -/* structure for addts/delts arguments */ -typedef struct tspec_arg { - uint16 version; /* see definition of TSPEC_ARG_VERSION */ - uint16 length; /* length of entire structure */ - uint flag; /* bit field */ - /* TSPEC Arguments */ - struct tsinfo_arg tsinfo; /* TS Info bit field */ - uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ - uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ - uint min_srv_interval; /* Minimum Service Interval (us) */ - uint max_srv_interval; /* Maximum Service Interval (us) */ - uint inactivity_interval; /* Inactivity Interval (us) */ - uint suspension_interval; /* Suspension Interval (us) */ - uint srv_start_time; /* Service Start Time (us) */ - uint min_data_rate; /* Minimum Data Rate (bps) */ - uint mean_data_rate; /* Mean Data Rate (bps) */ - uint peak_data_rate; /* Peak Data Rate (bps) */ - uint max_burst_size; /* Maximum Burst Size (bytes) */ - uint delay_bound; /* Delay Bound (us) */ - uint min_phy_rate; /* Minimum PHY Rate (bps) */ - uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */ - uint16 medium_time; /* Medium Time (32 us/s periods) */ - uint8 dialog_token; /* dialog token */ -} tspec_arg_t; - -/* tspec arg for desired station */ -typedef struct tspec_per_sta_arg { - struct ether_addr ea; - struct tspec_arg ts; -} tspec_per_sta_arg_t; - -/* structure for max bandwidth for each access category */ -typedef struct wme_max_bandwidth { - uint32 ac[AC_COUNT]; /* max bandwidth for each access category */ -} wme_max_bandwidth_t; - -#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) - -/* current version of wl_tspec_arg_t struct */ -#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */ -#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */ -#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */ -#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */ - -#if defined(ANQPO_SUPPORT) -#define ANQPO_MAX_PFN_HS 16 -#define ANQPO_MAX_OI_LENGTH 8 -typedef struct { - uint8 length; - uint8 data[ANQPO_MAX_OI_LENGTH]; -} wl_anqpo_oi_t; - -#define ANQPO_MAX_OI 16 -typedef struct { - uint32 numOi; - wl_anqpo_oi_t oi[ANQPO_MAX_OI]; -} wl_anqpo_roaming_consortium_t; - -#define ANQPO_MAX_REALM_LENGTH 255 -typedef struct { - uint8 length; - uint8 data[ANQPO_MAX_REALM_LENGTH + 1]; /* null terminated */ -} wl_anqpo_realm_data_t; - -#define ANQPO_MCC_LENGTH 3 -#define ANQPO_MNC_LENGTH 3 -typedef struct { - char mcc[ANQPO_MCC_LENGTH + 1]; - char mnc[ANQPO_MNC_LENGTH + 1]; -} wl_anqpo_plmn_t; - -typedef struct { - uint32 version; - uint32 id; - wl_anqpo_plmn_t plmn; - wl_anqpo_realm_data_t realm; - wl_anqpo_roaming_consortium_t rc; -} wl_anqpo_pfn_hs_t; - -typedef struct { - bool is_clear; /* set to clear list (not used on GET) */ - uint16 count; /* number of preferred hotspot in list */ - wl_anqpo_pfn_hs_t hs[]; /* max ANQPO_MAX_PFN_HS */ -} wl_anqpo_pfn_hs_list_t; - -#endif /* ANQPO_SUPPORT */ - -#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80 -#define WLC_WOWL_MAX_KEEPALIVE 2 - -/* Packet lifetime configuration per ac */ -typedef struct wl_lifetime { - uint32 ac; /* access class */ - uint32 lifetime; /* Packet lifetime value in ms */ -} wl_lifetime_t; - -/* Channel Switch Announcement param */ -typedef struct wl_chan_switch { - uint8 mode; /* value 0 or 1 */ - uint8 count; /* count # of beacons before switching */ - chanspec_t chspec; /* chanspec */ - uint8 reg; /* regulatory class */ - uint8 frame_type; /* csa frame type, unicast or broadcast */ -} wl_chan_switch_t; - -enum { - PFN_LIST_ORDER, - PFN_RSSI -}; - -enum { - DISABLE, - ENABLE -}; - -enum { - OFF_ADAPT, - SMART_ADAPT, - STRICT_ADAPT, - SLOW_ADAPT -}; - -#define SORT_CRITERIA_BIT 0 -#define AUTO_NET_SWITCH_BIT 1 -#define ENABLE_BKGRD_SCAN_BIT 2 -#define IMMEDIATE_SCAN_BIT 3 -#define AUTO_CONNECT_BIT 4 -#define ENABLE_BD_SCAN_BIT 5 -#define ENABLE_ADAPTSCAN_BIT 6 -#define IMMEDIATE_EVENT_BIT 8 -#define SUPPRESS_SSID_BIT 9 -#define ENABLE_NET_OFFLOAD_BIT 10 -/* report found/lost events for SSID and BSSID networks seperately */ -#define REPORT_SEPERATELY_BIT 11 - -#define SORT_CRITERIA_MASK 0x0001 -#define AUTO_NET_SWITCH_MASK 0x0002 -#define ENABLE_BKGRD_SCAN_MASK 0x0004 -#define IMMEDIATE_SCAN_MASK 0x0008 -#define AUTO_CONNECT_MASK 0x0010 - -#define ENABLE_BD_SCAN_MASK 0x0020 -#define ENABLE_ADAPTSCAN_MASK 0x00c0 -#define IMMEDIATE_EVENT_MASK 0x0100 -#define SUPPRESS_SSID_MASK 0x0200 -#define ENABLE_NET_OFFLOAD_MASK 0x0400 -/* report found/lost events for SSID and BSSID networks seperately */ -#define REPORT_SEPERATELY_MASK 0x0800 - -#define PFN_VERSION 2 -#define PFN_SCANRESULT_VERSION 1 -#define MAX_PFN_LIST_COUNT 16 - -#define PFN_COMPLETE 1 -#define PFN_INCOMPLETE 0 - -#define DEFAULT_BESTN 2 -#define DEFAULT_MSCAN 0 -#define DEFAULT_REPEAT 10 -#define DEFAULT_EXP 2 - -#define PFN_PARTIAL_SCAN_BIT 0 -#define PFN_PARTIAL_SCAN_MASK 1 - -#define PFN_SWC_RSSI_WINDOW_MAX 8 -#define PFN_SWC_MAX_NUM_APS 16 -#define PFN_HOTLIST_MAX_NUM_APS 64 - -#define MAX_EPNO_HIDDEN_SSID 8 -#define MAX_WHITELIST_SSID 2 - -/* PFN network info structure */ -typedef struct wl_pfn_subnet_info { - struct ether_addr BSSID; - uint8 channel; /* channel number only */ - uint8 SSID_len; - uint8 SSID[32]; -} wl_pfn_subnet_info_t; - -typedef struct wl_pfn_net_info { - wl_pfn_subnet_info_t pfnsubnet; - int16 RSSI; /* receive signal strength (in dBm) */ - uint16 timestamp; /* age in seconds */ -} wl_pfn_net_info_t; - -typedef struct wl_pfn_lnet_info { - wl_pfn_subnet_info_t pfnsubnet; /* BSSID + channel + SSID len + SSID */ - uint16 flags; /* partial scan, etc */ - int16 RSSI; /* receive signal strength (in dBm) */ - uint32 timestamp; /* age in miliseconds */ - uint16 rtt0; /* estimated distance to this AP in centimeters */ - uint16 rtt1; /* standard deviation of the distance to this AP in centimeters */ -} wl_pfn_lnet_info_t; - -typedef struct wl_pfn_lscanresults { - uint32 version; - uint32 status; - uint32 count; - wl_pfn_lnet_info_t netinfo[1]; -} wl_pfn_lscanresults_t; - -typedef struct wl_pfn_scanresults { - uint32 version; - uint32 status; - uint32 count; - wl_pfn_net_info_t netinfo[1]; -} wl_pfn_scanresults_t; - -typedef struct wl_pfn_significant_net { - uint16 flags; - uint16 channel; - struct ether_addr BSSID; - int8 rssi[PFN_SWC_RSSI_WINDOW_MAX]; -} wl_pfn_significant_net_t; - -typedef struct wl_pfn_swc_results { - uint32 version; - uint32 pkt_count; - uint32 total_count; - wl_pfn_significant_net_t list[1]; -} wl_pfn_swc_results_t; - -/* PFN data structure */ -typedef struct wl_pfn_param { - int32 version; /* PNO parameters version */ - int32 scan_freq; /* Scan frequency */ - int32 lost_network_timeout; /* Timeout in sec. to declare - * discovered network as lost - */ - int16 flags; /* Bit field to control features - * of PFN such as sort criteria auto - * enable switch and background scan - */ - int16 rssi_margin; /* Margin to avoid jitter for choosing a - * PFN based on RSSI sort criteria - */ - uint8 bestn; /* number of best networks in each scan */ - uint8 mscan; /* number of scans recorded */ - uint8 repeat; /* Minimum number of scan intervals - *before scan frequency changes in adaptive scan - */ - uint8 exp; /* Exponent of 2 for maximum scan interval */ - int32 slow_freq; /* slow scan period */ -} wl_pfn_param_t; - -typedef struct wl_pfn_bssid { - struct ether_addr macaddr; - /* Bit4: suppress_lost, Bit3: suppress_found */ - uint16 flags; -} wl_pfn_bssid_t; - -typedef struct wl_pfn_significant_bssid { - struct ether_addr macaddr; - int8 rssi_low_threshold; - int8 rssi_high_threshold; -} wl_pfn_significant_bssid_t; - -#define WL_PFN_SUPPRESSFOUND_MASK 0x08 -#define WL_PFN_SUPPRESSLOST_MASK 0x10 -#define WL_PFN_RSSI_MASK 0xff00 -#define WL_PFN_RSSI_SHIFT 8 - -typedef struct wl_pfn_cfg { - uint32 reporttype; - int32 channel_num; - uint16 channel_list[WL_NUMCHANNELS]; - uint32 flags; -} wl_pfn_cfg_t; - -#define CH_BUCKET_REPORT_REGULAR 0 -#define CH_BUCKET_REPORT_FULL_RESULT 2 -#define CH_BUCKET_GSCAN 4 - -typedef struct wl_pfn_gscan_ch_bucket_cfg { - uint8 bucket_end_index; - uint8 bucket_freq_multiple; - uint8 flag; - uint8 reserved; - uint16 repeat; - uint16 max_freq_multiple; -} wl_pfn_gscan_ch_bucket_cfg_t; - -#define GSCAN_SEND_ALL_RESULTS_MASK (1 << 0) -#define GSCAN_CFG_FLAGS_ONLY_MASK (1 << 7) -#define WL_GSCAN_CFG_VERSION 2 -typedef struct wl_pfn_gscan_cfg { - uint16 version; - /* BIT0 1 = send probes/beacons to HOST - * BIT1 Reserved - * BIT2 Reserved - * Add any future flags here - * BIT7 1 = no other useful cfg sent - */ - uint8 flags; - /* Buffer filled threshold in % to generate an event */ - uint8 buffer_threshold; - /* No. of BSSIDs with "change" to generate an evt - * change - crosses rssi threshold/lost - */ - uint8 swc_nbssid_threshold; - /* Max=8 (for now) Size of rssi cache buffer */ - uint8 swc_rssi_window_size; - uint8 count_of_channel_buckets; - uint8 retry_threshold; - uint16 lost_ap_window; - wl_pfn_gscan_ch_bucket_cfg_t channel_bucket[1]; -} wl_pfn_gscan_cfg_t; - -#define WL_PFN_REPORT_ALLNET 0 -#define WL_PFN_REPORT_SSIDNET 1 -#define WL_PFN_REPORT_BSSIDNET 2 - -#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ -#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /* Remaining reserved for future use */ -#define WL_PFN_SSID_A_BAND_TRIG 0x20 -#define WL_PFN_SSID_BG_BAND_TRIG 0x40 -typedef struct wl_pfn { - wlc_ssid_t ssid; /* ssid name and its length */ - int32 flags; /* bit2: hidden */ - int32 infra; /* BSS Vs IBSS */ - int32 auth; /* Open Vs Closed */ - int32 wpa_auth; /* WPA type */ - int32 wsec; /* wsec value */ -} wl_pfn_t; - -typedef struct wl_pfn_list { - uint32 version; - uint32 enabled; - uint32 count; - wl_pfn_t pfn[1]; -} wl_pfn_list_t; - -#define PFN_SSID_EXT_VERSION 2 - -typedef struct wl_pfn_ext { - uint8 flags; - int8 rssi_thresh; /* RSSI threshold, track only if RSSI > threshold */ - uint16 wpa_auth; /* Match the wpa auth type defined in wlioctl_defs.h */ - uint8 ssid[DOT11_MAX_SSID_LEN]; - uint8 ssid_len; - uint8 pad; -} wl_pfn_ext_t; - -typedef struct wl_pfn_ext_list { - uint16 version; - uint16 count; - wl_pfn_ext_t pfn_ext[1]; -} wl_pfn_ext_list_t; - -#define WL_PFN_SSID_EXT_FOUND 0x1 -#define WL_PFN_SSID_EXT_LOST 0x2 -typedef struct wl_pfn_result_ssid { - uint8 flags; - int8 rssi; - /* channel number */ - uint16 channel; - /* Assume idx in order of cfg */ - uint16 index; - struct ether_addr bssid; -} wl_pfn_result_ssid_crc32_t; - -typedef struct wl_pfn_ssid_ext_result { - uint16 version; - uint16 count; - wl_pfn_result_ssid_crc32_t net[1]; -} wl_pfn_ssid_ext_result_t; - -#define PFN_EXT_AUTH_CODE_OPEN 1 /* open */ -#define PFN_EXT_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ -#define PFN_EXT_AUTH_CODE_EAPOL 4 /* any EAPOL */ - -#define WL_PFN_MAC_OUI_ONLY_MASK 1 -#define WL_PFN_SET_MAC_UNASSOC_MASK 2 -/* To configure pfn_macaddr */ -typedef struct wl_pfn_macaddr_cfg { - uint8 version; - uint8 flags; - struct ether_addr macaddr; -} wl_pfn_macaddr_cfg_t; -#define WL_PFN_MACADDR_CFG_VER 1 - -typedef BWL_PRE_PACKED_STRUCT struct pfn_olmsg_params_t { - wlc_ssid_t ssid; - uint32 cipher_type; - uint32 auth_type; - uint8 channels[4]; -} BWL_POST_PACKED_STRUCT pfn_olmsg_params; - -#define WL_PFN_HIDDEN_BIT 2 -#define WL_PFN_HIDDEN_MASK 0x4 - -#ifndef BESTN_MAX -#define BESTN_MAX 3 -#endif - -#ifndef MSCAN_MAX -#define MSCAN_MAX 90 -#endif - -/* Service discovery */ -typedef struct { - uint8 transaction_id; /* Transaction id */ - uint8 protocol; /* Service protocol type */ - uint16 query_len; /* Length of query */ - uint16 response_len; /* Length of response */ - uint8 qrbuf[1]; -} wl_p2po_qr_t; - -typedef struct { - uint16 period; /* extended listen period */ - uint16 interval; /* extended listen interval */ -} wl_p2po_listen_t; - -/* ANQP offload */ - -#define ANQPO_MAX_QUERY_SIZE 256 -typedef struct { - uint16 max_retransmit; /* ~0 use default, max retransmit on no ACK from peer */ - uint16 response_timeout; /* ~0 use default, msec to wait for resp after tx packet */ - uint16 max_comeback_delay; /* ~0 use default, max comeback delay in resp else fail */ - uint16 max_retries; /* ~0 use default, max retries on failure */ - uint16 query_len; /* length of ANQP query */ - uint8 query_data[1]; /* ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */ -} wl_anqpo_set_t; - -typedef struct { - uint16 channel; /* channel of the peer */ - struct ether_addr addr; /* addr of the peer */ -} wl_anqpo_peer_t; - -#define ANQPO_MAX_PEER_LIST 64 -typedef struct { - uint16 count; /* number of peers in list */ - wl_anqpo_peer_t peer[1]; /* max ANQPO_MAX_PEER_LIST */ -} wl_anqpo_peer_list_t; - -#define ANQPO_MAX_IGNORE_SSID 64 -typedef struct { - bool is_clear; /* set to clear list (not used on GET) */ - uint16 count; /* number of SSID in list */ - wlc_ssid_t ssid[1]; /* max ANQPO_MAX_IGNORE_SSID */ -} wl_anqpo_ignore_ssid_list_t; - -#define ANQPO_MAX_IGNORE_BSSID 64 -typedef struct { - bool is_clear; /* set to clear list (not used on GET) */ - uint16 count; /* number of addr in list */ - struct ether_addr bssid[1]; /* max ANQPO_MAX_IGNORE_BSSID */ -} wl_anqpo_ignore_bssid_list_t; - - -struct toe_ol_stats_t { - /* Num of tx packets that don't need to be checksummed */ - uint32 tx_summed; - - /* Num of tx packets where checksum is filled by offload engine */ - uint32 tx_iph_fill; - uint32 tx_tcp_fill; - uint32 tx_udp_fill; - uint32 tx_icmp_fill; - - /* Num of rx packets where toe finds out if checksum is good or bad */ - uint32 rx_iph_good; - uint32 rx_iph_bad; - uint32 rx_tcp_good; - uint32 rx_tcp_bad; - uint32 rx_udp_good; - uint32 rx_udp_bad; - uint32 rx_icmp_good; - uint32 rx_icmp_bad; - - /* Num of tx packets in which csum error is injected */ - uint32 tx_tcp_errinj; - uint32 tx_udp_errinj; - uint32 tx_icmp_errinj; - - /* Num of rx packets in which csum error is injected */ - uint32 rx_tcp_errinj; - uint32 rx_udp_errinj; - uint32 rx_icmp_errinj; -}; - -/* Arp offload statistic counts */ -struct arp_ol_stats_t { - uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ - uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ - - uint32 arp_table_entries; /* ARP table entries */ - uint32 arp_table_overflow; /* ARP table additions skipped due to overflow */ - - uint32 host_request; /* ARP requests from host */ - uint32 host_reply; /* ARP replies from host */ - uint32 host_service; /* ARP requests from host serviced by ARP Agent */ - - uint32 peer_request; /* ARP requests received from network */ - uint32 peer_request_drop; /* ARP requests from network that were dropped */ - uint32 peer_reply; /* ARP replies received from network */ - uint32 peer_reply_drop; /* ARP replies from network that were dropped */ - uint32 peer_service; /* ARP request from host serviced by ARP Agent */ -}; - -/* NS offload statistic counts */ -struct nd_ol_stats_t { - uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ - uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ - uint32 peer_request; /* NS requests received from network */ - uint32 peer_request_drop; /* NS requests from network that were dropped */ - uint32 peer_reply_drop; /* NA replies from network that were dropped */ - uint32 peer_service; /* NS request from host serviced by firmware */ -}; - -/* - * Keep-alive packet offloading. - */ - -/* NAT keep-alive packets format: specifies the re-transmission period, the packet - * length, and packet contents. - */ -typedef struct wl_keep_alive_pkt { - uint32 period_msec; /* Retransmission period (0 to disable packet re-transmits) */ - uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */ - uint8 data[1]; /* Variable length packet to transmit. Contents should include - * entire ethernet packet (enet header, IP header, UDP header, - * and UDP payload) in network byte order. - */ -} wl_keep_alive_pkt_t; - -#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) - - -/* - * Dongle pattern matching filter. - */ - -#define MAX_WAKE_PACKET_CACHE_BYTES 128 /* Maximum cached wake packet */ - -#define MAX_WAKE_PACKET_BYTES (DOT11_A3_HDR_LEN + \ - DOT11_QOS_LEN + \ - sizeof(struct dot11_llc_snap_header) + \ - ETHER_MAX_DATA) - -typedef struct pm_wake_packet { - uint32 status; /* Is the wake reason a packet (if all the other field's valid) */ - uint32 pattern_id; /* Pattern ID that matched */ - uint32 original_packet_size; - uint32 saved_packet_size; - uchar packet[MAX_WAKE_PACKET_CACHE_BYTES]; -} pm_wake_packet_t; - -/* Packet filter types. Currently, only pattern matching is supported. */ -typedef enum wl_pkt_filter_type { - WL_PKT_FILTER_TYPE_PATTERN_MATCH=0, /* Pattern matching filter */ - WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH=1, /* Magic packet match */ - WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH=2 /* A pattern list (match all to match filter) */ -} wl_pkt_filter_type_t; - -#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t - -/* String mapping for types that may be used by applications or debug */ -#define WL_PKT_FILTER_TYPE_NAMES \ - { "PATTERN", WL_PKT_FILTER_TYPE_PATTERN_MATCH }, \ - { "MAGIC", WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH }, \ - { "PATLIST", WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH } - -/* 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. - */ -typedef struct wl_pkt_filter_pattern { - uint32 offset; /* Offset within received packet to start pattern matching. - * Offset '0' is the first byte of the ethernet header. - */ - uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ - uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts - * at offset 0. Pattern immediately follows mask. - */ -} wl_pkt_filter_pattern_t; - -/* A pattern list is a numerically specified list of modified pattern structures. */ -typedef struct wl_pkt_filter_pattern_listel { - uint16 rel_offs; /* Offset to begin match (relative to 'base' below) */ - uint16 base_offs; /* Base for offset (defined below) */ - uint16 size_bytes; /* Size of mask/pattern */ - uint16 match_flags; /* Addition flags controlling the match */ - uint8 mask_and_data[1]; /* Variable length mask followed by data, each size_bytes */ -} wl_pkt_filter_pattern_listel_t; - -typedef struct wl_pkt_filter_pattern_list { - uint8 list_cnt; /* Number of elements in the list */ - uint8 PAD1[1]; /* Reserved (possible version: reserved) */ - uint16 totsize; /* Total size of this pattern list (includes this struct) */ - wl_pkt_filter_pattern_listel_t patterns[1]; /* Variable number of list elements */ -} wl_pkt_filter_pattern_list_t; - -/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ -typedef struct wl_pkt_filter { - uint32 id; /* Unique filter id, specified by app. */ - uint32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ - uint32 negate_match; /* Negate the result of filter matches */ - union { /* Filter definitions */ - wl_pkt_filter_pattern_t pattern; /* Pattern matching filter */ - wl_pkt_filter_pattern_list_t patlist; /* List of patterns to match */ - } u; -} wl_pkt_filter_t; - -/* IOVAR "tcp_keep_set" parameter. Used to install tcp keep_alive stuff. */ -typedef struct wl_tcp_keep_set { - uint32 val1; - uint32 val2; -} wl_tcp_keep_set_t; - -#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) -#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) -#define WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_list_t, patterns) -#define WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN \ - OFFSETOF(wl_pkt_filter_pattern_listel_t, mask_and_data) - -/* IOVAR "pkt_filter_enable" parameter. */ -typedef struct wl_pkt_filter_enable { - uint32 id; /* Unique filter id */ - uint32 enable; /* Enable/disable bool */ -} wl_pkt_filter_enable_t; - -/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ -typedef struct wl_pkt_filter_list { - uint32 num; /* Number of installed packet filters */ - wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */ -} wl_pkt_filter_list_t; - -#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) - -/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ -typedef struct wl_pkt_filter_stats { - uint32 num_pkts_matched; /* # filter matches for specified filter id */ - uint32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */ - uint32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ -} wl_pkt_filter_stats_t; - -/* IOVAR "pkt_filter_ports" parameter. Configure TCP/UDP port filters. */ -typedef struct wl_pkt_filter_ports { - uint8 version; /* Be proper */ - uint8 reserved; /* Be really proper */ - uint16 count; /* Number of ports following */ - /* End of fixed data */ - uint16 ports[1]; /* Placeholder for ports[] */ -} wl_pkt_filter_ports_t; - -#define WL_PKT_FILTER_PORTS_FIXED_LEN OFFSETOF(wl_pkt_filter_ports_t, ports) - -#define WL_PKT_FILTER_PORTS_VERSION 0 -#define WL_PKT_FILTER_PORTS_MAX 128 - -#define RSN_KCK_LENGTH 16 -#define RSN_KEK_LENGTH 16 -#define RSN_REPLAY_LEN 8 -typedef struct _gtkrefresh { - uchar KCK[RSN_KCK_LENGTH]; - uchar KEK[RSN_KEK_LENGTH]; - uchar ReplayCounter[RSN_REPLAY_LEN]; -} gtk_keyinfo_t, *pgtk_keyinfo_t; - -/* Sequential Commands ioctl */ -typedef struct wl_seq_cmd_ioctl { - uint32 cmd; /* common ioctl definition */ - uint32 len; /* length of user buffer */ -} wl_seq_cmd_ioctl_t; - -#define WL_SEQ_CMD_ALIGN_BYTES 4 - -/* These are the set of get IOCTLs that should be allowed when using - * IOCTL sequence commands. These are issued implicitly by wl.exe each time - * it is invoked. We never want to buffer these, or else wl.exe will stop working. - */ -#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ - (((cmd) == WLC_GET_MAGIC) || \ - ((cmd) == WLC_GET_VERSION) || \ - ((cmd) == WLC_GET_AP) || \ - ((cmd) == WLC_GET_INSTANCE)) - -typedef struct wl_pkteng { - uint32 flags; - uint32 delay; /* Inter-packet delay */ - uint32 nframes; /* Number of frames */ - uint32 length; /* Packet length */ - uint8 seqno; /* Enable/disable sequence no. */ - struct ether_addr dest; /* Destination address */ - struct ether_addr src; /* Source address */ -} wl_pkteng_t; - -typedef struct wl_pkteng_stats { - uint32 lostfrmcnt; /* RX PER test: no of frames lost (skip seqno) */ - int32 rssi; /* RSSI */ - int32 snr; /* signal to noise ratio */ - uint16 rxpktcnt[NUM_80211_RATES+1]; - uint8 rssi_qdb; /* qdB portion of the computed rssi */ -} wl_pkteng_stats_t; - - -typedef enum { - wowl_pattern_type_bitmap = 0, - wowl_pattern_type_arp, - wowl_pattern_type_na -} wowl_pattern_type_t; - -typedef struct wl_wowl_pattern { - uint32 masksize; /* Size of the mask in #of bytes */ - uint32 offset; /* Pattern byte offset in packet */ - uint32 patternoffset; /* Offset of start of pattern in the structure */ - uint32 patternsize; /* Size of the pattern itself in #of bytes */ - uint32 id; /* id */ - uint32 reasonsize; /* Size of the wakeup reason code */ - wowl_pattern_type_t type; /* Type of pattern */ - /* Mask follows the structure above */ - /* Pattern follows the mask is at 'patternoffset' from the start */ -} wl_wowl_pattern_t; - -typedef struct wl_wowl_pattern_list { - uint count; - wl_wowl_pattern_t pattern[1]; -} wl_wowl_pattern_list_t; - -typedef struct wl_wowl_wakeind { - uint8 pci_wakeind; /* Whether PCI PMECSR PMEStatus bit was set */ - uint32 ucode_wakeind; /* What wakeup-event indication was set by ucode */ -} wl_wowl_wakeind_t; - -typedef struct { - uint32 pktlen; /* size of packet */ - void *sdu; -} tcp_keepalive_wake_pkt_infop_t; - -/* per AC rate control related data structure */ -typedef struct wl_txrate_class { - uint8 init_rate; - uint8 min_rate; - uint8 max_rate; -} wl_txrate_class_t; - -/* structure for Overlap BSS scan arguments */ -typedef struct wl_obss_scan_arg { - int16 passive_dwell; - int16 active_dwell; - int16 bss_widthscan_interval; - int16 passive_total; - int16 active_total; - int16 chanwidth_transition_delay; - int16 activity_threshold; -} wl_obss_scan_arg_t; - -#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) - -/* RSSI event notification configuration. */ -typedef struct wl_rssi_event { - uint32 rate_limit_msec; /* # of events posted to application will be limited to - * one per specified period (0 to disable rate limit). - */ - uint8 num_rssi_levels; /* Number of entries in rssi_levels[] below */ - int8 rssi_levels[MAX_RSSI_LEVELS]; /* Variable number of RSSI levels. An event - * will be posted each time the RSSI of received - * beacons/packets crosses a level. - */ -} wl_rssi_event_t; - -#define RSSI_MONITOR_VERSION 1 -#define RSSI_MONITOR_STOP (1 << 0) -typedef struct wl_rssi_monitor_cfg { - uint8 version; - uint8 flags; - int8 max_rssi; - int8 min_rssi; -} wl_rssi_monitor_cfg_t; - -typedef struct wl_rssi_monitor_evt { - uint8 version; - int8 cur_rssi; - uint16 pad; -} wl_rssi_monitor_evt_t; - -typedef struct wl_action_obss_coex_req { - uint8 info; - uint8 num; - uint8 ch_list[1]; -} wl_action_obss_coex_req_t; - - -/* IOVar parameter block for small MAC address array with type indicator */ -#define WL_IOV_MAC_PARAM_LEN 4 - -#define WL_IOV_PKTQ_LOG_PRECS 16 - -typedef struct { - uint32 num_addrs; - char addr_type[WL_IOV_MAC_PARAM_LEN]; - struct ether_addr ea[WL_IOV_MAC_PARAM_LEN]; -} wl_iov_mac_params_t; - -/* This is extra info that follows wl_iov_mac_params_t */ -typedef struct { - uint32 addr_info[WL_IOV_MAC_PARAM_LEN]; -} wl_iov_mac_extra_params_t; - -/* Combined structure */ -typedef struct { - wl_iov_mac_params_t params; - wl_iov_mac_extra_params_t extra_params; -} wl_iov_mac_full_params_t; - -/* Parameter block for PKTQ_LOG statistics */ -#define PKTQ_LOG_COUNTERS_V4 \ - /* packets requested to be stored */ \ - uint32 requested; \ - /* packets stored */ \ - uint32 stored; \ - /* packets saved, because a lowest priority queue has given away one packet */ \ - uint32 saved; \ - /* packets saved, because an older packet from the same queue has been dropped */ \ - uint32 selfsaved; \ - /* packets dropped, because pktq is full with higher precedence packets */ \ - uint32 full_dropped; \ - /* packets dropped because pktq per that precedence is full */ \ - uint32 dropped; \ - /* packets dropped, in order to save one from a queue of a highest priority */ \ - uint32 sacrificed; \ - /* packets droped because of hardware/transmission error */ \ - uint32 busy; \ - /* packets re-sent because they were not received */ \ - uint32 retry; \ - /* packets retried again (ps pretend) prior to moving power save mode */ \ - uint32 ps_retry; \ - /* suppressed packet count */ \ - uint32 suppress; \ - /* packets finally dropped after retry limit */ \ - uint32 retry_drop; \ - /* the high-water mark of the queue capacity for packets - goes to zero as queue fills */ \ - uint32 max_avail; \ - /* the high-water mark of the queue utilisation for packets - ('inverse' of max_avail) */ \ - uint32 max_used; \ - /* the maximum capacity of the queue */ \ - uint32 queue_capacity; \ - /* count of rts attempts that failed to receive cts */ \ - uint32 rtsfail; \ - /* count of packets sent (acked) successfully */ \ - uint32 acked; \ - /* running total of phy rate of packets sent successfully */ \ - uint32 txrate_succ; \ - /* running total of phy 'main' rate */ \ - uint32 txrate_main; \ - /* actual data transferred successfully */ \ - uint32 throughput; \ - /* time difference since last pktq_stats */ \ - uint32 time_delta; - -typedef struct { - PKTQ_LOG_COUNTERS_V4 -} pktq_log_counters_v04_t; - -/* v5 is the same as V4 with extra parameter */ -typedef struct { - PKTQ_LOG_COUNTERS_V4 - /* cumulative time to transmit */ - uint32 airtime; -} pktq_log_counters_v05_t; - -typedef struct { - uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; - pktq_log_counters_v04_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; - uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; - uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; - char headings[1]; -} pktq_log_format_v04_t; - -typedef struct { - uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; - pktq_log_counters_v05_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; - uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; - uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; - char headings[1]; -} pktq_log_format_v05_t; - - -typedef struct { - uint32 version; - wl_iov_mac_params_t params; - union { - pktq_log_format_v04_t v04; - pktq_log_format_v05_t v05; - } pktq_log; -} wl_iov_pktq_log_t; - -/* PKTQ_LOG_AUTO, PKTQ_LOG_DEF_PREC flags introduced in v05, they are ignored by v04 */ -#define PKTQ_LOG_AUTO (1 << 31) -#define PKTQ_LOG_DEF_PREC (1 << 30) - -/* - * SCB_BS_DATA iovar definitions start. - */ -#define SCB_BS_DATA_STRUCT_VERSION 1 - -/* The actual counters maintained for each station */ -typedef BWL_PRE_PACKED_STRUCT struct { - /* The following counters are a subset of what pktq_stats provides per precedence. */ - uint32 retry; /* packets re-sent because they were not received */ - uint32 retry_drop; /* packets finally dropped after retry limit */ - uint32 rtsfail; /* count of rts attempts that failed to receive cts */ - uint32 acked; /* count of packets sent (acked) successfully */ - uint32 txrate_succ; /* running total of phy rate of packets sent successfully */ - uint32 txrate_main; /* running total of phy 'main' rate */ - uint32 throughput; /* actual data transferred successfully */ - uint32 time_delta; /* time difference since last pktq_stats */ - uint32 airtime; /* cumulative total medium access delay in useconds */ -} BWL_POST_PACKED_STRUCT iov_bs_data_counters_t; - -/* The structure for individual station information. */ -typedef BWL_PRE_PACKED_STRUCT struct { - struct ether_addr station_address; /* The station MAC address */ - uint16 station_flags; /* Bit mask of flags, for future use. */ - iov_bs_data_counters_t station_counters; /* The actual counter values */ -} BWL_POST_PACKED_STRUCT iov_bs_data_record_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 structure_version; /* Structure version number (for wl/wlu matching) */ - uint16 structure_count; /* Number of iov_bs_data_record_t records following */ - iov_bs_data_record_t structure_record[1]; /* 0 - structure_count records */ -} BWL_POST_PACKED_STRUCT iov_bs_data_struct_t; - -/* Bitmask of options that can be passed in to the iovar. */ -enum { - SCB_BS_DATA_FLAG_NO_RESET = (1<<0) /* Do not clear the counters after reading */ -}; -/* - * SCB_BS_DATA iovar definitions end. - */ - -typedef struct wlc_extlog_cfg { - int max_number; - uint16 module; /* bitmap */ - uint8 level; - uint8 flag; - uint16 version; -} wlc_extlog_cfg_t; - -typedef struct log_record { - uint32 time; - uint16 module; - uint16 id; - uint8 level; - uint8 sub_unit; - uint8 seq_num; - int32 arg; - char str[MAX_ARGSTR_LEN]; -} log_record_t; - -typedef struct wlc_extlog_req { - uint32 from_last; - uint32 num; -} wlc_extlog_req_t; - -typedef struct wlc_extlog_results { - uint16 version; - uint16 record_len; - uint32 num; - log_record_t logs[1]; -} wlc_extlog_results_t; - -typedef struct log_idstr { - uint16 id; - uint16 flag; - uint8 arg_type; - const char *fmt_str; -} log_idstr_t; - -#define FMTSTRF_USER 1 - -/* flat ID definitions - * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will - * affect backward compatibility with pre-existing apps - */ -typedef enum { - FMTSTR_DRIVER_UP_ID = 0, - FMTSTR_DRIVER_DOWN_ID = 1, - FMTSTR_SUSPEND_MAC_FAIL_ID = 2, - FMTSTR_NO_PROGRESS_ID = 3, - FMTSTR_RFDISABLE_ID = 4, - FMTSTR_REG_PRINT_ID = 5, - FMTSTR_EXPTIME_ID = 6, - FMTSTR_JOIN_START_ID = 7, - FMTSTR_JOIN_COMPLETE_ID = 8, - FMTSTR_NO_NETWORKS_ID = 9, - FMTSTR_SECURITY_MISMATCH_ID = 10, - FMTSTR_RATE_MISMATCH_ID = 11, - FMTSTR_AP_PRUNED_ID = 12, - FMTSTR_KEY_INSERTED_ID = 13, - FMTSTR_DEAUTH_ID = 14, - FMTSTR_DISASSOC_ID = 15, - FMTSTR_LINK_UP_ID = 16, - FMTSTR_LINK_DOWN_ID = 17, - FMTSTR_RADIO_HW_OFF_ID = 18, - FMTSTR_RADIO_HW_ON_ID = 19, - FMTSTR_EVENT_DESC_ID = 20, - FMTSTR_PNP_SET_POWER_ID = 21, - FMTSTR_RADIO_SW_OFF_ID = 22, - FMTSTR_RADIO_SW_ON_ID = 23, - FMTSTR_PWD_MISMATCH_ID = 24, - FMTSTR_FATAL_ERROR_ID = 25, - FMTSTR_AUTH_FAIL_ID = 26, - FMTSTR_ASSOC_FAIL_ID = 27, - FMTSTR_IBSS_FAIL_ID = 28, - FMTSTR_EXTAP_FAIL_ID = 29, - FMTSTR_MAX_ID -} log_fmtstr_id_t; - -#ifdef DONGLEOVERLAYS -typedef struct { - uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */ - uint32 offset; /* offset into overlay region to write code */ - uint32 len; /* overlay code len */ - /* overlay code follows this struct */ -} wl_ioctl_overlay_t; -#endif /* DONGLEOVERLAYS */ - -/* 11k Neighbor Report element */ -typedef struct nbr_element { - uint8 id; - uint8 len; - struct ether_addr bssid; - uint32 bssid_info; - uint8 reg; - uint8 channel; - uint8 phytype; - uint8 pad; -} nbr_element_t; - -typedef enum event_msgs_ext_command { - EVENTMSGS_NONE = 0, - EVENTMSGS_SET_BIT = 1, - EVENTMSGS_RESET_BIT = 2, - EVENTMSGS_SET_MASK = 3 -} event_msgs_ext_command_t; - -#define EVENTMSGS_VER 1 -#define EVENTMSGS_EXT_STRUCT_SIZE OFFSETOF(eventmsgs_ext_t, mask[0]) - -/* len- for SET it would be mask size from the application to the firmware */ -/* for GET it would be actual firmware mask size */ -/* maxgetsize - is only used for GET. indicate max mask size that the */ -/* application can read from the firmware */ -typedef struct eventmsgs_ext -{ - uint8 ver; - uint8 command; - uint8 len; - uint8 maxgetsize; - uint8 mask[1]; -} eventmsgs_ext_t; -/* no default structure packing */ -#include - -typedef struct keepalives_max_idle { - uint16 keepalive_count; /* nmbr of keepalives per bss_max_idle period */ - uint8 mkeepalive_index; /* mkeepalive_index for keepalive frame to be used */ - uint8 PAD; /* to align next field */ - uint16 max_interval; /* seconds */ -} keepalives_max_idle_t; - -#define PM_IGNORE_BCMC_PROXY_ARP (1 << 0) -#define PM_IGNORE_BCMC_ALL_DMS_ACCEPTED (1 << 1) - -/* require strict packing */ -#include - - -/* Structures and constants used for "vndr_ie" IOVar interface */ -#define VNDR_IE_CMD_LEN 4 /* length of the set command string: - * "add", "del" (+ NUL) - */ - -#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ - vndr_ie_t vndr_ie_data; /* vendor IE data */ -} BWL_POST_PACKED_STRUCT vndr_ie_info_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - int iecount; /* number of entries in the vndr_ie_list[] array */ - vndr_ie_info_t vndr_ie_list[1]; /* variable size list of vndr_ie_info_t structs */ -} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - char cmd[VNDR_IE_CMD_LEN]; /* vndr_ie IOVar set command : "add", "del" + NUL */ - vndr_ie_buf_t vndr_ie_buffer; /* buffer containing Vendor IE list information */ -} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; - -/* tag_ID/length/value_buffer tuple */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 id; - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT tlv_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ - tlv_t ie_data; /* IE data */ -} BWL_POST_PACKED_STRUCT ie_info_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - int iecount; /* number of entries in the ie_list[] array */ - ie_info_t ie_list[1]; /* variable size list of ie_info_t structs */ -} BWL_POST_PACKED_STRUCT ie_buf_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - char cmd[VNDR_IE_CMD_LEN]; /* ie IOVar set command : "add" + NUL */ - ie_buf_t ie_buffer; /* buffer containing IE list information */ -} BWL_POST_PACKED_STRUCT ie_setbuf_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ - uint8 id; /* IE type */ -} BWL_POST_PACKED_STRUCT ie_getbuf_t; - -/* structures used to define format of wps ie data from probe requests */ -/* passed up to applications via iovar "prbreq_wpsie" */ -typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr { - struct ether_addr staAddr; - uint16 ieLen; -} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t; - -typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { - sta_prbreq_wps_ie_hdr_t hdr; - uint8 ieData[1]; -} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; - -typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { - uint32 totLen; - uint8 ieDataList[1]; -} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; - - -#ifdef WLMEDIA_TXFAILEVENT -typedef BWL_PRE_PACKED_STRUCT struct { - char dest[ETHER_ADDR_LEN]; /* destination MAC */ - uint8 prio; /* Packet Priority */ - uint8 flags; /* Flags */ - uint32 tsf_l; /* TSF timer low */ - uint32 tsf_h; /* TSF timer high */ - uint16 rates; /* Main Rates */ - uint16 txstatus; /* TX Status */ -} BWL_POST_PACKED_STRUCT txfailinfo_t; -#endif /* WLMEDIA_TXFAILEVENT */ - -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 flags; - chanspec_t chanspec; /* txpwr report for this channel */ - chanspec_t local_chanspec; /* channel on which we are associated */ - uint8 local_max; /* local max according to the AP */ - uint8 local_constraint; /* local constraint according to the AP */ - int8 antgain[2]; /* Ant gain for each band - from SROM */ - uint8 rf_cores; /* count of RF Cores being reported */ - uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ - uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain w/o adjustment */ - uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ - uint8 tx_power_max[4]; /* Maximum target power among all rates */ - uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ - int8 clm_limits[WL_NUMRATES]; /* regulatory limits - 20, 40 or 80MHz */ - int8 clm_limits_subchan1[WL_NUMRATES]; /* regulatory limits - 20in40 or 40in80 */ - int8 clm_limits_subchan2[WL_NUMRATES]; /* regulatory limits - 20in80MHz */ - int8 sar; /* SAR limit for display by wl executable */ - int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ - uint8 version; /* Version of the data format wlu <--> driver */ - uint8 display_core; /* Displayed curpower core */ - int8 target_offsets[4]; /* Target power offsets for current rate per core */ - uint32 last_tx_ratespec; /* Ratespec for last transmition */ - uint user_target; /* user limit */ - uint32 board_limit_len; /* length of board limit buffer */ - uint32 target_len; /* length of target power buffer */ - int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; - uint8 pprdata[1]; /* ppr serialization buffer */ -} BWL_POST_PACKED_STRUCT tx_pwr_rpt_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - struct ipv4_addr ipv4_addr; - struct ether_addr nexthop; -} BWL_POST_PACKED_STRUCT ibss_route_entry_t; -typedef BWL_PRE_PACKED_STRUCT struct { - uint32 num_entry; - ibss_route_entry_t route_entry[1]; -} BWL_POST_PACKED_STRUCT ibss_route_tbl_t; - -#define MAX_IBSS_ROUTE_TBL_ENTRY 64 - -#define TXPWR_TARGET_VERSION 0 -typedef BWL_PRE_PACKED_STRUCT struct { - int32 version; /* version number */ - chanspec_t chanspec; /* txpwr report for this channel */ - int8 txpwr[WL_STA_ANT_MAX]; /* Max tx target power, in qdb */ - uint8 rf_cores; /* count of RF Cores being reported */ -} BWL_POST_PACKED_STRUCT txpwr_target_max_t; - -#define BSS_PEER_INFO_PARAM_CUR_VER 0 -/* Input structure for IOV_BSS_PEER_INFO */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - struct ether_addr ea; /* peer MAC address */ -} BWL_POST_PACKED_STRUCT bss_peer_info_param_t; - -#define BSS_PEER_INFO_CUR_VER 0 - -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - struct ether_addr ea; - int32 rssi; - uint32 tx_rate; /* current tx rate */ - uint32 rx_rate; /* current rx rate */ - wl_rateset_t rateset; /* rateset in use */ - uint32 age; /* age in seconds */ -} BWL_POST_PACKED_STRUCT bss_peer_info_t; - -#define BSS_PEER_LIST_INFO_CUR_VER 0 - -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - uint16 bss_peer_info_len; /* length of bss_peer_info_t */ - uint32 count; /* number of peer info */ - bss_peer_info_t peer_info[1]; /* peer info */ -} BWL_POST_PACKED_STRUCT bss_peer_list_info_t; - -#define BSS_PEER_LIST_INFO_FIXED_LEN OFFSETOF(bss_peer_list_info_t, peer_info) - -#define AIBSS_BCN_FORCE_CONFIG_VER_0 0 - -/* structure used to configure AIBSS beacon force xmit */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - uint16 len; - uint32 initial_min_bcn_dur; /* dur in ms to check a bcn in bcn_flood period */ - uint32 min_bcn_dur; /* dur in ms to check a bcn after bcn_flood period */ - uint32 bcn_flood_dur; /* Initial bcn xmit period in ms */ -} BWL_POST_PACKED_STRUCT aibss_bcn_force_config_t; - -#define AIBSS_TXFAIL_CONFIG_VER_0 0 - -/* structure used to configure aibss tx fail event */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint16 version; - uint16 len; - uint32 bcn_timeout; /* dur in seconds to receive 1 bcn */ - uint32 max_tx_retry; /* no of consecutive no acks to send txfail event */ -} BWL_POST_PACKED_STRUCT aibss_txfail_config_t; - -/* no strict structure packing */ -#include - - /* Global ASSERT Logging */ -#define ASSERTLOG_CUR_VER 0x0100 -#define MAX_ASSRTSTR_LEN 64 - - typedef struct assert_record { - uint32 time; - uint8 seq_num; - char str[MAX_ASSRTSTR_LEN]; - } assert_record_t; - - typedef struct assertlog_results { - uint16 version; - uint16 record_len; - uint32 num; - assert_record_t logs[1]; - } assertlog_results_t; - -#define LOGRRC_FIX_LEN 8 -#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) - -#ifdef BCMWAPI_WAI -#define IV_LEN 16 - struct wapi_sta_msg_t - { - uint16 msg_type; - uint16 datalen; - uint8 vap_mac[6]; - uint8 reserve_data1[2]; - uint8 sta_mac[6]; - uint8 reserve_data2[2]; - uint8 gsn[IV_LEN]; - uint8 wie[256]; - }; -#endif /* BCMWAPI_WAI */ - - /* chanim acs record */ - typedef struct { - bool valid; - uint8 trigger; - chanspec_t selected_chspc; - int8 bgnoise; - uint32 glitch_cnt; - uint8 ccastats; - uint timestamp; - } chanim_acs_record_t; - - typedef struct { - chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; - uint8 count; - uint timestamp; - } wl_acs_record_t; - - typedef struct chanim_stats { - uint32 glitchcnt; /* normalized as per second count */ - uint32 badplcp; /* normalized as per second count */ - uint8 ccastats[CCASTATS_MAX]; /* normalized as 0-255 */ - int8 bgnoise; /* background noise level (in dBm) */ - chanspec_t chanspec; - uint32 timestamp; - uint32 bphy_glitchcnt; /* normalized as per second count */ - uint32 bphy_badplcp; /* normalized as per second count */ - uint8 chan_idle; /* normalized as 0~255 */ - } chanim_stats_t; - -#define WL_CHANIM_STATS_VERSION 2 - -typedef struct { - uint32 buflen; - uint32 version; - uint32 count; - chanim_stats_t stats[1]; -} wl_chanim_stats_t; - -#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats) - -/* Noise measurement metrics. */ -#define NOISE_MEASURE_KNOISE 0x1 - -/* scb probe parameter */ -typedef struct { - uint32 scb_timeout; - uint32 scb_activity_time; - uint32 scb_max_probe; -} wl_scb_probe_t; - -/* structure/defines for selective mgmt frame (smf) stats support */ - -#define SMFS_VERSION 1 -/* selected mgmt frame (smf) stats element */ -typedef struct wl_smfs_elem { - uint32 count; - uint16 code; /* SC or RC code */ -} wl_smfs_elem_t; - -typedef struct wl_smf_stats { - uint32 version; - uint16 length; /* reserved for future usage */ - uint8 type; - uint8 codetype; - uint32 ignored_cnt; - uint32 malformed_cnt; - uint32 count_total; /* count included the interested group */ - wl_smfs_elem_t elem[1]; -} wl_smf_stats_t; - -#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); - -enum { - SMFS_CODETYPE_SC, - SMFS_CODETYPE_RC -}; - -typedef enum smfs_type { - SMFS_TYPE_AUTH, - SMFS_TYPE_ASSOC, - SMFS_TYPE_REASSOC, - SMFS_TYPE_DISASSOC_TX, - SMFS_TYPE_DISASSOC_RX, - SMFS_TYPE_DEAUTH_TX, - SMFS_TYPE_DEAUTH_RX, - SMFS_TYPE_MAX -} smfs_type_t; - -#ifdef PHYMON - -#define PHYMON_VERSION 1 - -typedef struct wl_phycal_core_state { - /* Tx IQ/LO calibration coeffs */ - int16 tx_iqlocal_a; - int16 tx_iqlocal_b; - int8 tx_iqlocal_ci; - int8 tx_iqlocal_cq; - int8 tx_iqlocal_di; - int8 tx_iqlocal_dq; - int8 tx_iqlocal_ei; - int8 tx_iqlocal_eq; - int8 tx_iqlocal_fi; - int8 tx_iqlocal_fq; - - /* Rx IQ calibration coeffs */ - int16 rx_iqcal_a; - int16 rx_iqcal_b; - - uint8 tx_iqlocal_pwridx; /* Tx Power Index for Tx IQ/LO calibration */ - uint32 papd_epsilon_table[64]; /* PAPD epsilon table */ - int16 papd_epsilon_offset; /* PAPD epsilon offset */ - uint8 curr_tx_pwrindex; /* Tx power index */ - int8 idle_tssi; /* Idle TSSI */ - int8 est_tx_pwr; /* Estimated Tx Power (dB) */ - int8 est_rx_pwr; /* Estimated Rx Power (dB) from RSSI */ - uint16 rx_gaininfo; /* Rx gain applied on last Rx pkt */ - uint16 init_gaincode; /* initgain required for ACI */ - int8 estirr_tx; - int8 estirr_rx; - -} wl_phycal_core_state_t; - -typedef struct wl_phycal_state { - int version; - int8 num_phy_cores; /* number of cores */ - int8 curr_temperature; /* on-chip temperature sensor reading */ - chanspec_t chspec; /* channspec for this state */ - bool aci_state; /* ACI state: ON/OFF */ - uint16 crsminpower; /* crsminpower required for ACI */ - uint16 crsminpowerl; /* crsminpowerl required for ACI */ - uint16 crsminpoweru; /* crsminpoweru required for ACI */ - wl_phycal_core_state_t phycal_core[1]; -} wl_phycal_state_t; - -#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) -#endif /* PHYMON */ - -/* discovery state */ -typedef struct wl_p2p_disc_st { - uint8 state; /* see state */ - chanspec_t chspec; /* valid in listen state */ - uint16 dwell; /* valid in listen state, in ms */ -} wl_p2p_disc_st_t; - -/* scan request */ -typedef struct wl_p2p_scan { - uint8 type; /* 'S' for WLC_SCAN, 'E' for "escan" */ - uint8 reserved[3]; - /* scan or escan parms... */ -} wl_p2p_scan_t; - -/* i/f request */ -typedef struct wl_p2p_if { - struct ether_addr addr; - uint8 type; /* see i/f type */ - chanspec_t chspec; /* for p2p_ifadd GO */ -} wl_p2p_if_t; - -/* i/f query */ -typedef struct wl_p2p_ifq { - uint bsscfgidx; - char ifname[BCM_MSG_IFNAME_MAX]; -} wl_p2p_ifq_t; - -/* OppPS & CTWindow */ -typedef struct wl_p2p_ops { - uint8 ops; /* 0: disable 1: enable */ - uint8 ctw; /* >= 10 */ -} wl_p2p_ops_t; - -/* absence and presence request */ -typedef struct wl_p2p_sched_desc { - uint32 start; - uint32 interval; - uint32 duration; - uint32 count; /* see count */ -} wl_p2p_sched_desc_t; - -typedef struct wl_p2p_sched { - uint8 type; /* see schedule type */ - uint8 action; /* see schedule action */ - uint8 option; /* see schedule option */ - wl_p2p_sched_desc_t desc[1]; -} wl_p2p_sched_t; - -typedef struct wl_bcmdcs_data { - uint reason; - chanspec_t chspec; -} wl_bcmdcs_data_t; - - -/* NAT configuration */ -typedef struct { - uint32 ipaddr; /* interface ip address */ - uint32 ipaddr_mask; /* interface ip address mask */ - uint32 ipaddr_gateway; /* gateway ip address */ - uint8 mac_gateway[6]; /* gateway mac address */ - uint32 ipaddr_dns; /* DNS server ip address, valid only for public if */ - uint8 mac_dns[6]; /* DNS server mac address, valid only for public if */ - uint8 GUID[38]; /* interface GUID */ -} nat_if_info_t; - -typedef struct { - uint op; /* operation code */ - bool pub_if; /* set for public if, clear for private if */ - nat_if_info_t if_info; /* interface info */ -} nat_cfg_t; - -typedef struct { - int state; /* NAT state returned */ -} nat_state_t; - - -#define BTA_STATE_LOG_SZ 64 - -/* BTAMP Statemachine states */ -enum { - HCIReset = 1, - HCIReadLocalAMPInfo, - HCIReadLocalAMPASSOC, - HCIWriteRemoteAMPASSOC, - HCICreatePhysicalLink, - HCIAcceptPhysicalLinkRequest, - HCIDisconnectPhysicalLink, - HCICreateLogicalLink, - HCIAcceptLogicalLink, - HCIDisconnectLogicalLink, - HCILogicalLinkCancel, - HCIAmpStateChange, - HCIWriteLogicalLinkAcceptTimeout -}; - -typedef struct flush_txfifo { - uint32 txfifobmp; - uint32 hwtxfifoflush; - struct ether_addr ea; -} flush_txfifo_t; - -enum { - SPATIAL_MODE_2G_IDX = 0, - SPATIAL_MODE_5G_LOW_IDX, - SPATIAL_MODE_5G_MID_IDX, - SPATIAL_MODE_5G_HIGH_IDX, - SPATIAL_MODE_5G_UPPER_IDX, - SPATIAL_MODE_MAX_IDX -}; - -#define WLC_TXCORE_MAX 4 /* max number of txcore supports */ -#define WLC_SUBBAND_MAX 4 /* max number of sub-band supports */ -typedef struct { - uint8 band2g[WLC_TXCORE_MAX]; - uint8 band5g[WLC_SUBBAND_MAX][WLC_TXCORE_MAX]; -} sar_limit_t; - -/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ -typedef struct wl_mempool_stats { - int num; /* Number of memory pools */ - bcm_mp_stats_t s[1]; /* Variable array of memory pool stats. */ -} wl_mempool_stats_t; - -typedef struct { - uint32 ipaddr; - uint32 ipaddr_netmask; - uint32 ipaddr_gateway; -} nwoe_ifconfig_t; - -/* Traffic management priority classes */ -typedef enum trf_mgmt_priority_class { - trf_mgmt_priority_low = 0, /* Maps to 802.1p BK */ - trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ - trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ - trf_mgmt_priority_nochange = 3, /* do not update the priority */ - trf_mgmt_priority_invalid = (trf_mgmt_priority_nochange + 1) -} trf_mgmt_priority_class_t; - -/* Traffic management configuration parameters */ -typedef struct trf_mgmt_config { - uint32 trf_mgmt_enabled; /* 0 - disabled, 1 - enabled */ - uint32 flags; /* See TRF_MGMT_FLAG_xxx defines */ - uint32 host_ip_addr; /* My IP address to determine subnet */ - uint32 host_subnet_mask; /* My subnet mask */ - uint32 downlink_bandwidth; /* In units of kbps */ - uint32 uplink_bandwidth; /* In units of kbps */ - uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed tx bandwidth */ - uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed rx bandwidth */ -} trf_mgmt_config_t; - -/* Traffic management filter */ -typedef struct trf_mgmt_filter { - struct ether_addr dst_ether_addr; /* His L2 address */ - uint32 dst_ip_addr; /* His IP address */ - uint16 dst_port; /* His L4 port */ - uint16 src_port; /* My L4 port */ - uint16 prot; /* L4 protocol (only TCP or UDP) */ - uint16 flags; /* TBD. For now, this must be zero. */ - trf_mgmt_priority_class_t priority; /* Priority for filtered packets */ - uint32 dscp; /* DSCP */ -} trf_mgmt_filter_t; - -/* Traffic management filter list (variable length) */ -typedef struct trf_mgmt_filter_list { - uint32 num_filters; - trf_mgmt_filter_t filter[1]; -} trf_mgmt_filter_list_t; - -/* Traffic management global info used for all queues */ -typedef struct trf_mgmt_global_info { - uint32 maximum_bytes_per_second; - uint32 maximum_bytes_per_sampling_period; - uint32 total_bytes_consumed_per_second; - uint32 total_bytes_consumed_per_sampling_period; - uint32 total_unused_bytes_per_sampling_period; -} trf_mgmt_global_info_t; - -/* Traffic management shaping info per priority queue */ -typedef struct trf_mgmt_shaping_info { - uint32 gauranteed_bandwidth_percentage; - uint32 guaranteed_bytes_per_second; - uint32 guaranteed_bytes_per_sampling_period; - uint32 num_bytes_produced_per_second; - uint32 num_bytes_consumed_per_second; - uint32 num_queued_packets; /* Number of packets in queue */ - uint32 num_queued_bytes; /* Number of bytes in queue */ -} trf_mgmt_shaping_info_t; - -/* Traffic management shaping info array */ -typedef struct trf_mgmt_shaping_info_array { - trf_mgmt_global_info_t tx_global_shaping_info; - trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; - trf_mgmt_global_info_t rx_global_shaping_info; - trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; -} trf_mgmt_shaping_info_array_t; - - -/* Traffic management statistical counters */ -typedef struct trf_mgmt_stats { - uint32 num_processed_packets; /* Number of packets processed */ - uint32 num_processed_bytes; /* Number of bytes processed */ - uint32 num_discarded_packets; /* Number of packets discarded from queue */ -} trf_mgmt_stats_t; - -/* Traffic management statisics array */ -typedef struct trf_mgmt_stats_array { - trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; - trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; -} trf_mgmt_stats_array_t; - -typedef struct powersel_params { - /* LPC Params exposed via IOVAR */ - int32 tp_ratio_thresh; /* Throughput ratio threshold */ - uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ - uint8 pwr_stab_thresh; /* Number of successes before power step down */ - uint8 pwr_sel_exp_time; /* Time lapse for expiry of database */ -} powersel_params_t; - -typedef struct lpc_params { - /* LPC Params exposed via IOVAR */ - uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ - uint8 pwr_stab_thresh; /* Number of successes before power step down */ - uint8 lpc_exp_time; /* Time lapse for expiry of database */ - uint8 pwrup_slow_step; /* Step size for slow step up */ - uint8 pwrup_fast_step; /* Step size for fast step up */ - uint8 pwrdn_slow_step; /* Step size for slow step down */ -} lpc_params_t; - -/* tx pkt delay statistics */ -#define SCB_RETRY_SHORT_DEF 7 /* Default Short retry Limit */ -#define WLPKTDLY_HIST_NBINS 16 /* number of bins used in the Delay histogram */ - -/* structure to store per-AC delay statistics */ -typedef struct scb_delay_stats { - uint32 txmpdu_lost; /* number of MPDUs lost */ - uint32 txmpdu_cnt[SCB_RETRY_SHORT_DEF]; /* retry times histogram */ - uint32 delay_sum[SCB_RETRY_SHORT_DEF]; /* cumulative packet latency */ - uint32 delay_min; /* minimum packet latency observed */ - uint32 delay_max; /* maximum packet latency observed */ - uint32 delay_avg; /* packet latency average */ - uint32 delay_hist[WLPKTDLY_HIST_NBINS]; /* delay histogram */ -} scb_delay_stats_t; - -/* structure for txdelay event */ -typedef struct txdelay_event { - uint8 status; - int rssi; - chanim_stats_t chanim_stats; - scb_delay_stats_t delay_stats[AC_COUNT]; -} txdelay_event_t; - -/* structure for txdelay parameters */ -typedef struct txdelay_params { - uint16 ratio; /* Avg Txdelay Delta */ - uint8 cnt; /* Sample cnt */ - uint8 period; /* Sample period */ - uint8 tune; /* Debug */ -} txdelay_params_t; - -enum { - WNM_SERVICE_DMS = 1, - WNM_SERVICE_FMS = 2, - WNM_SERVICE_TFS = 3 -}; - -/* Definitions for WNM/NPS TCLAS */ -typedef struct wl_tclas { - uint8 user_priority; - uint8 fc_len; - dot11_tclas_fc_t fc; -} wl_tclas_t; - -#define WL_TCLAS_FIXED_SIZE OFFSETOF(wl_tclas_t, fc) - -typedef struct wl_tclas_list { - uint32 num; - wl_tclas_t tclas[1]; -} wl_tclas_list_t; - -/* Definitions for WNM/NPS Traffic Filter Service */ -typedef struct wl_tfs_req { - uint8 tfs_id; - uint8 tfs_actcode; - uint8 tfs_subelem_id; - uint8 send; -} wl_tfs_req_t; - -typedef struct wl_tfs_filter { - uint8 status; /* Status returned by the AP */ - uint8 tclas_proc; /* TCLAS processing value (0:and, 1:or) */ - uint8 tclas_cnt; /* count of all wl_tclas_t in tclas array */ - uint8 tclas[1]; /* VLA of wl_tclas_t */ -} wl_tfs_filter_t; -#define WL_TFS_FILTER_FIXED_SIZE OFFSETOF(wl_tfs_filter_t, tclas) - -typedef struct wl_tfs_fset { - struct ether_addr ea; /* Address of AP/STA involved with this filter set */ - uint8 tfs_id; /* TFS ID field chosen by STA host */ - uint8 status; /* Internal status TFS_STATUS_xxx */ - uint8 actcode; /* Action code DOT11_TFS_ACTCODE_xxx */ - uint8 token; /* Token used in last request frame */ - uint8 notify; /* Notify frame sent/received because of this set */ - uint8 filter_cnt; /* count of all wl_tfs_filter_t in filter array */ - uint8 filter[1]; /* VLA of wl_tfs_filter_t */ -} wl_tfs_fset_t; -#define WL_TFS_FSET_FIXED_SIZE OFFSETOF(wl_tfs_fset_t, filter) - -enum { - TFS_STATUS_DISABLED = 0, /* TFS filter set disabled by user */ - TFS_STATUS_DISABLING = 1, /* Empty request just sent to AP */ - TFS_STATUS_VALIDATED = 2, /* Filter set validated by AP (but maybe not enabled!) */ - TFS_STATUS_VALIDATING = 3, /* Filter set just sent to AP */ - TFS_STATUS_NOT_ASSOC = 4, /* STA not associated */ - TFS_STATUS_NOT_SUPPORT = 5, /* TFS not supported by AP */ - TFS_STATUS_DENIED = 6, /* Filter set refused by AP (=> all sets are disabled!) */ -}; - -typedef struct wl_tfs_status { - uint8 fset_cnt; /* count of all wl_tfs_fset_t in fset array */ - wl_tfs_fset_t fset[1]; /* VLA of wl_tfs_fset_t */ -} wl_tfs_status_t; - -typedef struct wl_tfs_set { - uint8 send; /* Immediatly register registered sets on AP side */ - uint8 tfs_id; /* ID of a specific set (existing or new), or nul for all */ - uint8 actcode; /* Action code for this filter set */ - uint8 tclas_proc; /* TCLAS processing operator for this filter set */ -} wl_tfs_set_t; - -typedef struct wl_tfs_term { - uint8 del; /* Delete internal set once confirmation received */ - uint8 tfs_id; /* ID of a specific set (existing), or nul for all */ -} wl_tfs_term_t; - - -#define DMS_DEP_PROXY_ARP (1 << 0) - -/* Definitions for WNM/NPS Directed Multicast Service */ -enum { - DMS_STATUS_DISABLED = 0, /* DMS desc disabled by user */ - DMS_STATUS_ACCEPTED = 1, /* Request accepted by AP */ - DMS_STATUS_NOT_ASSOC = 2, /* STA not associated */ - DMS_STATUS_NOT_SUPPORT = 3, /* DMS not supported by AP */ - DMS_STATUS_DENIED = 4, /* Request denied by AP */ - DMS_STATUS_TERM = 5, /* Request terminated by AP */ - DMS_STATUS_REMOVING = 6, /* Remove request just sent */ - DMS_STATUS_ADDING = 7, /* Add request just sent */ - DMS_STATUS_ERROR = 8, /* Non compliant AP behvior */ - DMS_STATUS_IN_PROGRESS = 9, /* Request just sent */ - DMS_STATUS_REQ_MISMATCH = 10 /* Conditions for sending DMS req not met */ -}; - -typedef struct wl_dms_desc { - uint8 user_id; - uint8 status; - uint8 token; - uint8 dms_id; - uint8 tclas_proc; - uint8 mac_len; /* length of all ether_addr in data array, 0 if STA */ - uint8 tclas_len; /* length of all wl_tclas_t in data array */ - uint8 data[1]; /* VLA of 'ether_addr' and 'wl_tclas_t' (in this order ) */ -} wl_dms_desc_t; - -#define WL_DMS_DESC_FIXED_SIZE OFFSETOF(wl_dms_desc_t, data) - -typedef struct wl_dms_status { - uint32 cnt; - wl_dms_desc_t desc[1]; -} wl_dms_status_t; - -typedef struct wl_dms_set { - uint8 send; - uint8 user_id; - uint8 tclas_proc; -} wl_dms_set_t; - -typedef struct wl_dms_term { - uint8 del; - uint8 user_id; -} wl_dms_term_t; - -typedef struct wl_service_term { - uint8 service; - union { - wl_dms_term_t dms; - } u; -} wl_service_term_t; - -/* Definitions for WNM/NPS BSS Transistion */ -typedef struct wl_bsstrans_req { - uint16 tbtt; /* time of BSS to end of life, in unit of TBTT */ - uint16 dur; /* time of BSS to keep off, in unit of minute */ - uint8 reqmode; /* request mode of BSS transition request */ - uint8 unicast; /* request by unicast or by broadcast */ -} wl_bsstrans_req_t; - -enum { - BSSTRANS_RESP_AUTO = 0, /* Currently equivalent to ENABLE */ - BSSTRANS_RESP_DISABLE = 1, /* Never answer BSS Trans Req frames */ - BSSTRANS_RESP_ENABLE = 2, /* Always answer Req frames with preset data */ - BSSTRANS_RESP_WAIT = 3, /* Send ind, wait and/or send preset data (NOT IMPL) */ - BSSTRANS_RESP_IMMEDIATE = 4 /* After an ind, set data and send resp (NOT IMPL) */ -}; - -typedef struct wl_bsstrans_resp { - uint8 policy; - uint8 status; - uint8 delay; - struct ether_addr target; -} wl_bsstrans_resp_t; - -/* "wnm_bsstrans_resp" argument programming behavior after BSSTRANS Req reception */ -enum { - WL_BSSTRANS_RESP_ROAM_ALWAYS = 0, /* Roam (or disassociate) in all cases */ - WL_BSSTRANS_RESP_ROAM_IF_MODE = 1, /* Roam only if requested by Request Mode field */ - WL_BSSTRANS_RESP_ROAM_IF_PREF = 2, /* Roam only if Preferred BSS provided */ - WL_BSSTRANS_RESP_WAIT = 3 /* Wait for deauth and send Accepted status */ -}; - -/* Definitions for WNM/NPS TIM Broadcast */ -typedef struct wl_timbc_offset { - int16 offset; /* offset in us */ - uint16 fix_intv; /* override interval sent from STA */ - uint16 rate_override; /* use rate override to send high rate TIM broadcast frame */ - uint8 tsf_present; /* show timestamp in TIM broadcast frame */ -} wl_timbc_offset_t; - -typedef struct wl_timbc_set { - uint8 interval; /* Interval in DTIM wished or required. */ - uint8 flags; /* Bitfield described below */ - uint16 rate_min; /* Minimum rate required for High/Low TIM frames. Optionnal */ - uint16 rate_max; /* Maximum rate required for High/Low TIM frames. Optionnal */ -} wl_timbc_set_t; - -enum { - WL_TIMBC_SET_TSF_REQUIRED = 1, /* Enable TIMBC only if TSF in TIM frames */ - WL_TIMBC_SET_NO_OVERRIDE = 2, /* ... if AP does not override interval */ - WL_TIMBC_SET_PROXY_ARP = 4, /* ... if AP support Proxy ARP */ - WL_TIMBC_SET_DMS_ACCEPTED = 8 /* ... if all DMS desc have been accepted */ -}; - -typedef struct wl_timbc_status { - uint8 status_sta; /* Status from internal state machine (check below) */ - uint8 status_ap; /* From AP response frame (check 8.4.2.86 from 802.11) */ - uint8 interval; - uint8 pad; - int32 offset; - uint16 rate_high; - uint16 rate_low; -} wl_timbc_status_t; - -enum { - WL_TIMBC_STATUS_DISABLE = 0, /* TIMBC disabled by user */ - WL_TIMBC_STATUS_REQ_MISMATCH = 1, /* AP settings do no match user requirements */ - WL_TIMBC_STATUS_NOT_ASSOC = 2, /* STA not associated */ - WL_TIMBC_STATUS_NOT_SUPPORT = 3, /* TIMBC not supported by AP */ - WL_TIMBC_STATUS_DENIED = 4, /* Req to disable TIMBC sent to AP */ - WL_TIMBC_STATUS_ENABLE = 5 /* TIMBC enabled */ -}; - -/* Definitions for PM2 Dynamic Fast Return To Sleep */ -typedef struct wl_pm2_sleep_ret_ext { - uint8 logic; /* DFRTS logic: see WL_DFRTS_LOGIC_* below */ - uint16 low_ms; /* Low FRTS timeout */ - uint16 high_ms; /* High FRTS timeout */ - uint16 rx_pkts_threshold; /* switching threshold: # rx pkts */ - uint16 tx_pkts_threshold; /* switching threshold: # tx pkts */ - uint16 txrx_pkts_threshold; /* switching threshold: # (tx+rx) pkts */ - uint32 rx_bytes_threshold; /* switching threshold: # rx bytes */ - uint32 tx_bytes_threshold; /* switching threshold: # tx bytes */ - uint32 txrx_bytes_threshold; /* switching threshold: # (tx+rx) bytes */ -} wl_pm2_sleep_ret_ext_t; - -#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ -#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ -#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ - -/* Values for the passive_on_restricted_mode iovar. When set to non-zero, this iovar - * disables automatic conversions of a channel from passively scanned to - * actively scanned. These values only have an effect for country codes such - * as XZ where some 5 GHz channels are defined to be passively scanned. - */ -#define WL_PASSACTCONV_DISABLE_NONE 0 /* Enable permanent and temporary conversions */ -#define WL_PASSACTCONV_DISABLE_ALL 1 /* Disable permanent and temporary conversions */ -#define WL_PASSACTCONV_DISABLE_PERM 2 /* Disable only permanent conversions */ - -/* Definitions for Reliable Multicast */ -#define WL_RMC_CNT_VERSION 1 -#define WL_RMC_MAX_CLIENT 32 -#define WL_RMC_FLAG_INBLACKLIST 1 -#define WL_RMC_FLAG_ACTIVEACKER 2 -#define WL_RMC_FLAG_RELMCAST 4 -#define WL_RMC_MAX_TABLE_ENTRY 4 - -#define WL_RMC_VER 1 -#define WL_RMC_INDEX_ACK_ALL 255 -#define WL_RMC_NUM_OF_MC_STREAMS 4 -#define WL_RMC_MAX_TRS_PER_GROUP 1 -#define WL_RMC_MAX_TRS_IN_ACKALL 1 -#define WL_RMC_ACK_MCAST0 0x02 -#define WL_RMC_ACK_MCAST_ALL 0x01 -#define WL_RMC_ACTF_TIME_MIN 300 /* time in ms */ -#define WL_RMC_ACTF_TIME_MAX 20000 /* time in ms */ -#define WL_RMC_ARTMO_MIN 350 /* time in ms */ -#define WL_RMC_ARTMO_MAX 40000 /* time in ms */ - -/* RMC events in action frames */ -enum rmc_opcodes { - RELMCAST_ENTRY_OP_DISABLE = 0, /* Disable multi-cast group */ - RELMCAST_ENTRY_OP_DELETE = 1, /* Delete multi-cast group */ - RELMCAST_ENTRY_OP_ENABLE = 2, /* Enable multi-cast group */ - RELMCAST_ENTRY_OP_ACK_ALL = 3 /* Enable ACK ALL bit in AMT */ -}; - -/* RMC operational modes */ -enum rmc_modes { - WL_RMC_MODE_RECEIVER = 0, /* Receiver mode by default */ - WL_RMC_MODE_TRANSMITTER = 1, /* Transmitter mode using wl ackreq */ - WL_RMC_MODE_INITIATOR = 2 /* Initiator mode using wl ackreq */ -}; - -/* Each RMC mcast client info */ -typedef struct wl_relmcast_client { - uint8 flag; /* status of client such as AR, R, or blacklisted */ - int16 rssi; /* rssi value of RMC client */ - struct ether_addr addr; /* mac address of RMC client */ -} wl_relmcast_client_t; - -/* RMC Counters */ -typedef struct wl_rmc_cnts { - uint16 version; /* see definition of WL_CNT_T_VERSION */ - uint16 length; /* length of entire structure */ - uint16 dupcnt; /* counter for duplicate rmc MPDU */ - uint16 ackreq_err; /* counter for wl ackreq error */ - uint16 af_tx_err; /* error count for action frame transmit */ - uint16 null_tx_err; /* error count for rmc null frame transmit */ - uint16 af_unicast_tx_err; /* error count for rmc unicast frame transmit */ - uint16 mc_no_amt_slot; /* No mcast AMT entry available */ - uint16 mc_no_glb_slot; /* No mcast entry available in global table */ - uint16 mc_not_mirrored; /* mcast group is not mirrored */ - uint16 mc_existing_tr; /* mcast group is already taken by transmitter */ - uint16 mc_exist_in_amt; /* mcast group is already programmed in amt */ - uint16 mc_not_exist_in_gbl; /* mcast group is not in global table */ - uint16 mc_not_exist_in_amt; /* mcast group is not in AMT table */ - uint16 mc_utilized; /* mcast addressed is already taken */ - uint16 mc_taken_other_tr; /* multi-cast addressed is already taken */ - uint32 rmc_rx_frames_mac; /* no of mc frames received from mac */ - uint32 rmc_tx_frames_mac; /* no of mc frames transmitted to mac */ - uint32 mc_null_ar_cnt; /* no. of times NULL AR is received */ - uint32 mc_ar_role_selected; /* no. of times took AR role */ - uint32 mc_ar_role_deleted; /* no. of times AR role cancelled */ - uint32 mc_noacktimer_expired; /* no. of times noack timer expired */ -} wl_rmc_cnts_t; - -/* RMC Status */ -typedef struct wl_relmcast_st { - uint8 ver; /* version of RMC */ - uint8 num; /* number of clients detected by transmitter */ - wl_relmcast_client_t clients[WL_RMC_MAX_CLIENT]; - uint16 err; /* error status (used in infra) */ - uint16 actf_time; /* action frame time period */ -} wl_relmcast_status_t; - -/* Entry for each STA/node */ -typedef struct wl_rmc_entry { - /* operation on multi-cast entry such add, - * delete, ack-all - */ - int8 flag; - struct ether_addr addr; /* multi-cast group mac address */ -} wl_rmc_entry_t; - -/* RMC table */ -typedef struct wl_rmc_entry_table { - uint8 index; /* index to a particular mac entry in table */ - uint8 opcode; /* opcodes or operation on entry */ - wl_rmc_entry_t entry[WL_RMC_MAX_TABLE_ENTRY]; -} wl_rmc_entry_table_t; - -/* Transmitter Info */ -typedef struct wl_rmc_trans_info { - struct ether_addr addr; /* transmitter mac */ - uint32 time_val; /* timer val in case aging of entry is required */ - uint16 seq; /* last seq number of packet received from transmitter */ - uint16 artmo; -} wl_rmc_trans_info_t; - -/* Multicast Group */ -typedef struct wl_rmc_grp_entry { - struct ether_addr mcaddr; /* multi-cast group mac */ - struct ether_addr ar; /* active receiver for the group */ - wl_rmc_trans_info_t tr_info[WL_RMC_MAX_TRS_PER_GROUP]; -} wl_rmc_grp_entry_t; - -/* RMC ACKALL Table */ -typedef struct wl_rmc_ackall_entry { - struct ether_addr ar; /* active receiver for the entry */ - wl_rmc_trans_info_t tr_info[WL_RMC_NUM_OF_MC_STREAMS]; -} wl_rmc_ackall_entry_t; - -/* RMC Peers Table */ -typedef struct wl_rmc_gbl_table { - uint8 activeMask; /* mask to denote the entry(s) that are active */ - wl_rmc_ackall_entry_t ackAll; /* structure to keep info related to ACK all */ - wl_rmc_grp_entry_t mc_entry[WL_RMC_NUM_OF_MC_STREAMS]; -} wl_rmc_gbl_table_t; - -/* To update vendor specific ie for RMC */ -typedef struct wl_rmc_vsie { - uint8 oui[DOT11_OUI_LEN]; - uint16 payload; /* IE Data Payload */ -} wl_rmc_vsie_t; - -/* structures & defines for proximity detection */ -enum proxd_method { - PROXD_UNDEFINED_METHOD = 0, - PROXD_RSSI_METHOD = 1, - PROXD_TOF_METHOD = 2 -}; - -/* structures for proximity detection device role */ -#define WL_PROXD_MODE_DISABLE 0 -#define WL_PROXD_MODE_NEUTRAL 1 -#define WL_PROXD_MODE_INITIATOR 2 -#define WL_PROXD_MODE_TARGET 3 - -#define WL_PROXD_ACTION_STOP 0 -#define WL_PROXD_ACTION_START 1 - -#define WL_PROXD_FLAG_TARGET_REPORT 0x1 -#define WL_PROXD_FLAG_REPORT_FAILURE 0x2 -#define WL_PROXD_FLAG_INITIATOR_REPORT 0x4 -#define WL_PROXD_FLAG_NOCHANSWT 0x8 -#define WL_PROXD_FLAG_NETRUAL 0x10 -#define WL_PROXD_FLAG_INITIATOR_RPTRTT 0x20 -#define WL_PROXD_FLAG_ONEWAY 0x40 -#define WL_PROXD_FLAG_SEQ_EN 0x80 - -#define WL_PROXD_RANDOM_WAKEUP 0x8000 - -typedef struct wl_proxd_iovar { - uint16 method; /* Proxmity Detection method */ - uint16 mode; /* Mode (neutral, initiator, target) */ -} wl_proxd_iovar_t; - -/* - * structures for proximity detection parameters - * consists of two parts, common and method specific params - * common params should be placed at the beginning - */ - -/* require strict packing */ -#include - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_common { - chanspec_t chanspec; /* channel spec */ - int16 tx_power; /* tx power of Proximity Detection(PD) frames (in dBm) */ - uint16 tx_rate; /* tx rate of PD rames (in 500kbps units) */ - uint16 timeout; /* timeout value */ - uint16 interval; /* interval between neighbor finding attempts (in TU) */ - uint16 duration; /* duration of neighbor finding attempts (in ms) */ -} BWL_POST_PACKED_STRUCT wl_proxd_params_common_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_rssi_method { - chanspec_t chanspec; /* chanspec for home channel */ - int16 tx_power; /* tx power of Proximity Detection frames (in dBm) */ - uint16 tx_rate; /* tx rate of PD frames, 500kbps units */ - uint16 timeout; /* state machine wait timeout of the frames (in ms) */ - uint16 interval; /* interval between neighbor finding attempts (in TU) */ - uint16 duration; /* duration of neighbor finding attempts (in ms) */ - /* method specific ones go after this line */ - int16 rssi_thresh; /* RSSI threshold (in dBm) */ - uint16 maxconvergtmo; /* max wait converge timeout (in ms) */ -} wl_proxd_params_rssi_method_t; - -#define Q1_NS 25 /* Q1 time units */ - -#define TOF_BW_NUM 3 /* number of bandwidth that the TOF can support */ -#define TOF_BW_SEQ_NUM (TOF_BW_NUM+2) /* number of total index */ -enum tof_bw_index { - TOF_BW_20MHZ_INDEX = 0, - TOF_BW_40MHZ_INDEX = 1, - TOF_BW_80MHZ_INDEX = 2, - TOF_BW_SEQTX_INDEX = 3, - TOF_BW_SEQRX_INDEX = 4 -}; - -#define BANDWIDTH_BASE 20 /* base value of bandwidth */ -#define TOF_BW_20MHZ (BANDWIDTH_BASE << TOF_BW_20MHZ_INDEX) -#define TOF_BW_40MHZ (BANDWIDTH_BASE << TOF_BW_40MHZ_INDEX) -#define TOF_BW_80MHZ (BANDWIDTH_BASE << TOF_BW_80MHZ_INDEX) -#define TOF_BW_10MHZ 10 - -#define NFFT_BASE 64 /* base size of fft */ -#define TOF_NFFT_20MHZ (NFFT_BASE << TOF_BW_20MHZ_INDEX) -#define TOF_NFFT_40MHZ (NFFT_BASE << TOF_BW_40MHZ_INDEX) -#define TOF_NFFT_80MHZ (NFFT_BASE << TOF_BW_80MHZ_INDEX) - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_method { - chanspec_t chanspec; /* chanspec for home channel */ - int16 tx_power; /* tx power of Proximity Detection(PD) frames (in dBm) */ - uint16 tx_rate; /* tx rate of PD rames (in 500kbps units) */ - uint16 timeout; /* state machine wait timeout of the frames (in ms) */ - uint16 interval; /* interval between neighbor finding attempts (in TU) */ - uint16 duration; /* duration of neighbor finding attempts (in ms) */ - /* specific for the method go after this line */ - struct ether_addr tgt_mac; /* target mac addr for TOF method */ - uint16 ftm_cnt; /* number of the frames txed by initiator */ - uint16 retry_cnt; /* number of retransmit attampts for ftm frames */ - int16 vht_rate; /* ht or vht rate */ - /* add more params required for other methods can be added here */ -} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_method_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_tune { - uint32 Ki; /* h/w delay K factor for initiator */ - uint32 Kt; /* h/w delay K factor for target */ - int16 vhtack; /* enable/disable VHT ACK */ - int16 N_log2[TOF_BW_SEQ_NUM]; /* simple threshold crossing */ - int16 w_offset[TOF_BW_NUM]; /* offset of threshold crossing window(per BW) */ - int16 w_len[TOF_BW_NUM]; /* length of threshold crossing window(per BW) */ - int32 maxDT; /* max time difference of T4/T1 or T3/T2 */ - int32 minDT; /* min time difference of T4/T1 or T3/T2 */ - uint8 totalfrmcnt; /* total count of transfered measurement frames */ - uint16 rsv_media; /* reserve media value for TOF */ - uint32 flags; /* flags */ - uint8 core; /* core to use for tx */ - uint8 setflags; /* set flags of K, N. S values */ - int16 N_scale[TOF_BW_SEQ_NUM]; /* simple threshold crossing */ - uint8 sw_adj; /* enable sw assisted timestamp adjustment */ - uint8 hw_adj; /* enable hw assisted timestamp adjustment */ - uint8 seq_en; /* enable ranging sequence */ - uint8 ftm_cnt[TOF_BW_SEQ_NUM]; /* number of ftm frames based on bandwidth */ - int16 N_log2_2g; /* simple threshold crossing for 2g channel */ - int16 N_scale_2g; /* simple threshold crossing for 2g channel */ -} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_tune_t; - -typedef struct wl_proxd_params_iovar { - uint16 method; /* Proxmity Detection method */ - union { - /* common params for pdsvc */ - wl_proxd_params_common_t cmn_params; /* common parameters */ - /* method specific */ - wl_proxd_params_rssi_method_t rssi_params; /* RSSI method parameters */ - wl_proxd_params_tof_method_t tof_params; /* TOF meothod parameters */ - /* tune parameters */ - wl_proxd_params_tof_tune_t tof_tune; /* TOF tune parameters */ - } u; /* Method specific optional parameters */ -} wl_proxd_params_iovar_t; - -#define PROXD_COLLECT_GET_STATUS 0 -#define PROXD_COLLECT_SET_STATUS 1 -#define PROXD_COLLECT_QUERY_HEADER 2 -#define PROXD_COLLECT_QUERY_DATA 3 -#define PROXD_COLLECT_QUERY_DEBUG 4 -#define PROXD_COLLECT_REMOTE_REQUEST 5 - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_query { - uint32 method; /* method */ - uint8 request; /* Query request. */ - uint8 status; /* 0 -- disable, 1 -- enable collection, */ - /* 2 -- enable collection & debug */ - uint16 index; /* The current frame index [0 to total_frames - 1]. */ - uint16 mode; /* Initiator or Target */ - bool busy; /* tof sm is busy */ - bool remote; /* Remote collect data */ -} BWL_POST_PACKED_STRUCT wl_proxd_collect_query_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_header { - uint16 total_frames; /* The totral frames for this collect. */ - uint16 nfft; /* nfft value */ - uint16 bandwidth; /* bandwidth */ - uint16 channel; /* channel number */ - uint32 chanspec; /* channel spec */ - uint32 fpfactor; /* avb timer value factor */ - uint16 fpfactor_shift; /* avb timer value shift bits */ - int32 distance; /* distance calculated by fw */ - uint32 meanrtt; /* mean of RTTs */ - uint32 modertt; /* mode of RTTs */ - uint32 medianrtt; /* median of RTTs */ - uint32 sdrtt; /* standard deviation of RTTs */ - uint32 clkdivisor; /* clock divisor */ - uint16 chipnum; /* chip type */ - uint8 chiprev; /* chip revision */ - uint8 phyver; /* phy version */ - struct ether_addr loaclMacAddr; /* local mac address */ - struct ether_addr remoteMacAddr; /* remote mac address */ - wl_proxd_params_tof_tune_t params; -} BWL_POST_PACKED_STRUCT wl_proxd_collect_header_t; - -/* ********************** NAN wl interface struct types and defs ******************** */ - -#define WL_NAN_IOCTL_VERSION 0x1 - -/* wl_nan_sub_cmd may also be used in dhd */ -typedef struct wl_nan_sub_cmd wl_nan_sub_cmd_t; -typedef int (cmd_handler_t)(void *wl, const wl_nan_sub_cmd_t *cmd, char **argv); -/* nan cmd list entry */ -struct wl_nan_sub_cmd { - char *name; - uint8 version; /* cmd version */ - uint16 id; /* id for the dongle f/w switch/case */ - uint16 type; /* base type of argument */ - cmd_handler_t *handler; /* cmd handler */ -}; - -/* container for nan iovtls & events */ -typedef BWL_PRE_PACKED_STRUCT struct wl_nan_ioc { - uint16 version; /* interface command or event version */ - uint16 id; /* nan ioctl cmd ID */ - uint16 len; /* total length of all tlv records in data[] */ - uint8 data [1]; /* var len payload of bcm_xtlv_t type */ -} BWL_POST_PACKED_STRUCT wl_nan_ioc_t; - -typedef struct wl_nan_status { - uint8 inited; - uint8 joined; - uint8 role; - uint8 hop_count; - uint32 chspec; - uint8 amr[8]; /* Anchor Master Rank */ - uint32 cnt_pend_txfrm; /* pending TX frames */ - uint32 cnt_bcn_tx; /* TX disc/sync beacon count */ - uint32 cnt_bcn_rx; /* RX disc/sync beacon count */ - uint32 cnt_svc_disc_tx; /* TX svc disc frame count */ - uint32 cnt_svc_disc_rx; /* RX svc disc frame count */ - struct ether_addr cid; -} wl_nan_status_t; - -/* various params and ctl swithce for nan_debug instance */ -typedef struct nan_debug_params { - uint8 enabled; /* runtime debuging enabled */ - uint8 collect; /* enables debug svc sdf monitor mode */ - uint16 cmd; /* debug cmd to perform a debug action */ - uint32 msglevel; /* msg level if enabled */ - uint16 status; -} nan_debug_params_t; - - -/* nan passive scan params */ -#define NAN_SCAN_MAX_CHCNT 8 -typedef BWL_PRE_PACKED_STRUCT struct nan_scan_params { - uint16 scan_time; - uint16 home_time; - uint16 ms_intvl; /* interval between merge scan */ - uint16 ms_dur; /* duration of merge scan */ - uint16 chspec_num; - chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /* act. used 3, 5 rfu */ -} BWL_POST_PACKED_STRUCT nan_scan_params_t; - -enum wl_nan_role { - WL_NAN_ROLE_AUTO = 0, - WL_NAN_ROLE_NON_MASTER_NON_SYNC = 1, - WL_NAN_ROLE_NON_MASTER_SYNC = 2, - WL_NAN_ROLE_MASTER = 3, - WL_NAN_ROLE_ANCHOR_MASTER = 4 -}; -#define NAN_MASTER_RANK_LEN 8 -/* nan cmd IDs */ -enum wl_nan_cmds { - /* nan cfg /disc & dbg ioctls */ - WL_NAN_CMD_ENABLE = 1, - WL_NAN_CMD_ATTR = 2, - WL_NAN_CMD_NAN_JOIN = 3, - WL_NAN_CMD_LEAVE = 4, - WL_NAN_CMD_MERGE = 5, - WL_NAN_CMD_STATUS = 6, - /* discovery engine commands */ - WL_NAN_CMD_PUBLISH = 20, - WL_NAN_CMD_SUBSCRIBE = 21, - WL_NAN_CMD_CANCEL_PUBLISH = 22, - WL_NAN_CMD_CANCEL_SUBSCRIBE = 23, - WL_NAN_CMD_TRANSMIT = 24, - WL_NAN_CMD_CONNECTION = 25, - WL_NAN_CMD_SHOW = 26, - WL_NAN_CMD_STOP = 27, /* stop nan for a given cluster ID */ - /* nan debug iovars & cmds */ - WL_NAN_CMD_SCAN_PARAMS = 46, - WL_NAN_CMD_SCAN = 47, - WL_NAN_CMD_SCAN_RESULTS = 48, - WL_NAN_CMD_EVENT_MASK = 49, - WL_NAN_CMD_EVENT_CHECK = 50, - - WL_NAN_CMD_DEBUG = 60, - WL_NAN_CMD_TEST1 = 61, - WL_NAN_CMD_TEST2 = 62, - WL_NAN_CMD_TEST3 = 63 -}; - -/* - * tlv IDs uniquely identifies cmd parameters - * packed into wl_nan_ioc_t container - */ -enum wl_nan_cmd_xtlv_id { - /* 0x00 ~ 0xFF: standard TLV ID whose data format is the same as NAN attribute TLV */ - WL_NAN_XTLV_ZERO = 0, /* used as tlv buf end marker */ -#ifdef NAN_STD_TLV /* rfu, don't use yet */ - WL_NAN_XTLV_MASTER_IND = 1, /* == NAN_ATTR_MASTER_IND, */ - WL_NAN_XTLV_CLUSTER = 2, /* == NAN_ATTR_CLUSTER, */ - WL_NAN_XTLV_VENDOR = 221, /* == NAN_ATTR_VENDOR, */ -#endif - /* 0x02 ~ 0xFF: reserved. In case to use with the same data format as NAN attribute TLV */ - /* 0x100 ~ : private TLV ID defined just for NAN command */ - /* common types */ - WL_NAN_XTLV_BUFFER = 0x101, /* generic type, function depends on cmd context */ - WL_NAN_XTLV_MAC_ADDR = 0x102, /* used in various cmds */ - WL_NAN_XTLV_REASON = 0x103, - WL_NAN_XTLV_ENABLE = 0x104, - /* explicit types, primarily for discovery engine iovars */ - WL_NAN_XTLV_SVC_PARAMS = 0x120, /* Contains required params: wl_nan_disc_params_t */ - WL_NAN_XTLV_MATCH_RX = 0x121, /* Matching filter to evaluate on receive */ - WL_NAN_XTLV_MATCH_TX = 0x122, /* Matching filter to send */ - WL_NAN_XTLV_SVC_INFO = 0x123, /* Service specific info */ - WL_NAN_XTLV_SVC_NAME = 0x124, /* Optional UTF-8 service name, for debugging. */ - WL_NAN_XTLV_INSTANCE_ID = 0x125, /* Identifies unique publish or subscribe instance */ - WL_NAN_XTLV_PRIORITY = 0x126, /* used in transmit cmd context */ - WL_NAN_XTLV_REQUESTOR_ID = 0x127, /* Requestor instance ID */ - WL_NAN_XTLV_VNDR = 0x128, /* Vendor specific attribute */ - /* explicit types, primarily for NAN MAC iovars */ - WL_NAN_XTLV_DW_LEN = 0x140, /* discovery win length */ - WL_NAN_XTLV_BCN_INTERVAL = 0x141, /* beacon interval, both sync and descovery bcns? */ - WL_NAN_XTLV_CLUSTER_ID = 0x142, - WL_NAN_XTLV_IF_ADDR = 0x143, - WL_NAN_XTLV_MC_ADDR = 0x144, - WL_NAN_XTLV_ROLE = 0x145, - WL_NAN_XTLV_START = 0x146, - - WL_NAN_XTLV_MASTER_PREF = 0x147, - WL_NAN_XTLV_DW_INTERVAL = 0x148, - WL_NAN_XTLV_PTBTT_OVERRIDE = 0x149, - /* nan status command xtlvs */ - WL_NAN_XTLV_MAC_INITED = 0x14a, - WL_NAN_XTLV_MAC_ENABLED = 0x14b, - WL_NAN_XTLV_MAC_CHANSPEC = 0x14c, - WL_NAN_XTLV_MAC_AMR = 0x14d, /* anchormaster rank u8 amr[8] */ - WL_NAN_XTLV_MAC_HOPCNT = 0x14e, - WL_NAN_XTLV_MAC_AMBTT = 0x14f, - WL_NAN_XTLV_MAC_TXRATE = 0x150, - WL_NAN_XTLV_MAC_STATUS = 0x151, /* xtlv payload is nan_status_t */ - WL_NAN_XTLV_NAN_SCANPARAMS = 0x152, /* payload is nan_scan_params_t */ - WL_NAN_XTLV_DEBUGPARAMS = 0x153, /* payload is nan_scan_params_t */ - WL_NAN_XTLV_SUBSCR_ID = 0x154, /* subscriber id */ - WL_NAN_XTLV_PUBLR_ID = 0x155, /* publisher id */ - WL_NAN_XTLV_EVENT_MASK = 0x156, - WL_NAN_XTLV_MERGE = 0x157 -}; - -/* Flag bits for Publish and Subscribe (wl_nan_disc_params_t flags) */ -#define WL_NAN_RANGE_LIMITED 0x0040 -/* Bits specific to Publish */ -/* Unsolicited transmissions */ -#define WL_NAN_PUB_UNSOLICIT 0x1000 -/* Solicited transmissions */ -#define WL_NAN_PUB_SOLICIT 0x2000 -#define WL_NAN_PUB_BOTH 0x3000 -/* Set for broadcast solicited transmission - * Do not set for unicast solicited transmission - */ -#define WL_NAN_PUB_BCAST 0x4000 -/* Generate event on each solicited transmission */ -#define WL_NAN_PUB_EVENT 0x8000 -/* Used for one-time solicited Publish functions to indicate transmision occurred */ -#define WL_NAN_PUB_SOLICIT_PENDING 0x10000 -/* Follow-up frames */ -#define WL_NAN_FOLLOWUP 0x20000 -/* Bits specific to Subscribe */ -/* Active subscribe mode (Leave unset for passive) */ -#define WL_NAN_SUB_ACTIVE 0x1000 - -/* Special values for time to live (ttl) parameter */ -#define WL_NAN_TTL_UNTIL_CANCEL 0xFFFFFFFF -/* Publish - runs until first transmission - * Subscribe - runs until first DiscoveryResult event - */ -#define WL_NAN_TTL_FIRST 0 - -/* The service hash (service id) is exactly this many bytes. */ -#define WL_NAN_SVC_HASH_LEN 6 - -/* Instance ID type (unique identifier) */ -typedef uint8 wl_nan_instance_id_t; - -/* Mandatory parameters for publish/subscribe iovars - NAN_TLV_SVC_PARAMS */ -typedef struct wl_nan_disc_params_s { - /* Periodicity of unsolicited/query transmissions, in DWs */ - uint32 period; - /* Time to live in DWs */ - uint32 ttl; - /* Flag bits */ - uint32 flags; - /* Publish or subscribe service id, i.e. hash of the service name */ - uint8 svc_hash[WL_NAN_SVC_HASH_LEN]; - /* Publish or subscribe id */ - wl_nan_instance_id_t instance_id; -} wl_nan_disc_params_t; - -/* -* desovery interface event structures * -*/ - -/* NAN Ranging */ - -/* Bit defines for global flags */ -#define WL_NAN_RANGING_ENABLE 1 /* enable RTT */ -#define WL_NAN_RANGING_RANGED 2 /* Report to host if ranged as target */ -typedef struct nan_ranging_config { - uint32 chanspec; /* Ranging chanspec */ - uint16 timeslot; /* NAN RTT start time slot 1-511 */ - uint16 duration; /* NAN RTT duration in ms */ - struct ether_addr allow_mac; /* peer initiated ranging: the allowed peer mac - * address, a unicast (for one peer) or - * a broadcast for all. Setting it to all zeros - * means responding to none,same as not setting - * the flag bit NAN_RANGING_RESPOND - */ - uint16 flags; -} wl_nan_ranging_config_t; - -/* list of peers for self initiated ranging */ -/* Bit defines for per peer flags */ -#define WL_NAN_RANGING_REPORT (1<<0) /* Enable reporting range to target */ -typedef struct nan_ranging_peer { - uint32 chanspec; /* desired chanspec for this peer */ - uint32 abitmap; /* available bitmap */ - struct ether_addr ea; /* peer MAC address */ - uint8 frmcnt; /* frame count */ - uint8 retrycnt; /* retry count */ - uint16 flags; /* per peer flags, report or not */ -} wl_nan_ranging_peer_t; -typedef struct nan_ranging_list { - uint8 count; /* number of MAC addresses */ - uint8 num_peers_done; /* host set to 0, when read, shows number of peers - * completed, success or fail - */ - uint8 num_dws; /* time period to do the ranging, specified in dws */ - uint8 reserve; /* reserved field */ - wl_nan_ranging_peer_t rp[1]; /* variable length array of peers */ -} wl_nan_ranging_list_t; - -/* ranging results, a list for self initiated ranging and one for peer initiated ranging */ -/* There will be one structure for each peer */ -#define WL_NAN_RANGING_STATUS_SUCCESS 1 -#define WL_NAN_RANGING_STATUS_FAIL 2 -#define WL_NAN_RANGING_STATUS_TIMEOUT 3 -#define WL_NAN_RANGING_STATUS_ABORT 4 /* with partial results if sounding count > 0 */ -typedef struct nan_ranging_result { - uint8 status; /* 1: Success, 2: Fail 3: Timeout 4: Aborted */ - uint8 sounding_count; /* number of measurements completed (0 = failure) */ - struct ether_addr ea; /* initiator MAC address */ - uint32 chanspec; /* Chanspec where the ranging was done */ - uint32 timestamp; /* 32bits of the TSF timestamp ranging was completed at */ - uint32 distance; /* mean distance in meters expressed as Q4 number. - * Only valid when sounding_count > 0. Examples: - * 0x08 = 0.5m - * 0x10 = 1m - * 0x18 = 1.5m - * set to 0xffffffff to indicate invalid number - */ - int32 rtt_var; /* standard deviation in 10th of ns of RTTs measured. - * Only valid when sounding_count > 0 - */ - struct ether_addr tgtea; /* target MAC address */ -} wl_nan_ranging_result_t; -typedef struct nan_ranging_event_data { - uint8 mode; /* 1: Result of host initiated ranging */ - /* 2: Result of peer initiated ranging */ - uint8 reserved; - uint8 success_count; /* number of peers completed successfully */ - uint8 count; /* number of peers in the list */ - wl_nan_ranging_result_t rr[1]; /* variable array of ranging peers */ -} wl_nan_ranging_event_data_t; - -/* ********************* end of NAN section ******************************** */ - -#define RSSI_THRESHOLD_SIZE 16 -#define MAX_IMP_RESP_SIZE 256 - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_rssi_bias { - int32 version; /* version */ - int32 threshold[RSSI_THRESHOLD_SIZE]; /* threshold */ - int32 peak_offset; /* peak offset */ - int32 bias; /* rssi bias */ - int32 gd_delta; /* GD - GD_ADJ */ - int32 imp_resp[MAX_IMP_RESP_SIZE]; /* (Hi*Hi)+(Hr*Hr) */ -} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_rssi_bias_avg { - int32 avg_threshold[RSSI_THRESHOLD_SIZE]; /* avg threshold */ - int32 avg_peak_offset; /* avg peak offset */ - int32 avg_rssi; /* avg rssi */ - int32 avg_bias; /* avg bias */ -} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_avg_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_info { - uint16 type; /* type: 0 channel table, 1 channel smoothing table, 2 and 3 seq */ - uint16 index; /* The current frame index, from 1 to total_frames. */ - uint16 tof_cmd; /* M_TOF_CMD */ - uint16 tof_rsp; /* M_TOF_RSP */ - uint16 tof_avb_rxl; /* M_TOF_AVB_RX_L */ - uint16 tof_avb_rxh; /* M_TOF_AVB_RX_H */ - uint16 tof_avb_txl; /* M_TOF_AVB_TX_L */ - uint16 tof_avb_txh; /* M_TOF_AVB_TX_H */ - uint16 tof_id; /* M_TOF_ID */ - uint8 tof_frame_type; - uint8 tof_frame_bw; - int8 tof_rssi; - int32 tof_cfo; - int32 gd_adj_ns; /* gound delay */ - int32 gd_h_adj_ns; /* group delay + threshold crossing */ -#ifdef RSSI_REFINE - wl_proxd_rssi_bias_t rssi_bias; /* RSSI refinement info */ -#endif - int16 nfft; /* number of samples stored in H */ - -} BWL_POST_PACKED_STRUCT wl_proxd_collect_info_t; - -#define k_tof_collect_H_pad 1 -#define k_tof_collect_H_size (256+16+k_tof_collect_H_pad) -#define k_tof_collect_Hraw_size (2*k_tof_collect_H_size) -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_data { - wl_proxd_collect_info_t info; - uint32 H[k_tof_collect_H_size]; /* raw data read from phy used to adjust timestamps */ - -} BWL_POST_PACKED_STRUCT wl_proxd_collect_data_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_debug_data { - uint8 count; /* number of packets */ - uint8 stage; /* state machone stage */ - uint8 received; /* received or txed */ - uint8 paket_type; /* packet type */ - uint8 category; /* category field */ - uint8 action; /* action field */ - uint8 token; /* token number */ - uint8 follow_token; /* following token number */ - uint16 index; /* index of the packet */ - uint16 tof_cmd; /* M_TOF_CMD */ - uint16 tof_rsp; /* M_TOF_RSP */ - uint16 tof_avb_rxl; /* M_TOF_AVB_RX_L */ - uint16 tof_avb_rxh; /* M_TOF_AVB_RX_H */ - uint16 tof_avb_txl; /* M_TOF_AVB_TX_L */ - uint16 tof_avb_txh; /* M_TOF_AVB_TX_H */ - uint16 tof_id; /* M_TOF_ID */ - uint16 tof_status0; /* M_TOF_STATUS_0 */ - uint16 tof_status2; /* M_TOF_STATUS_2 */ - uint16 tof_chsm0; /* M_TOF_CHNSM_0 */ - uint16 tof_phyctl0; /* M_TOF_PHYCTL0 */ - uint16 tof_phyctl1; /* M_TOF_PHYCTL1 */ - uint16 tof_phyctl2; /* M_TOF_PHYCTL2 */ - uint16 tof_lsig; /* M_TOF_LSIG */ - uint16 tof_vhta0; /* M_TOF_VHTA0 */ - uint16 tof_vhta1; /* M_TOF_VHTA1 */ - uint16 tof_vhta2; /* M_TOF_VHTA2 */ - uint16 tof_vhtb0; /* M_TOF_VHTB0 */ - uint16 tof_vhtb1; /* M_TOF_VHTB1 */ - uint16 tof_apmductl; /* M_TOF_AMPDU_CTL */ - uint16 tof_apmdudlim; /* M_TOF_AMPDU_DLIM */ - uint16 tof_apmdulen; /* M_TOF_AMPDU_LEN */ -} BWL_POST_PACKED_STRUCT wl_proxd_debug_data_t; - -/* version of the wl_wsec_info structure */ -#define WL_WSEC_INFO_VERSION 0x01 - -/* start enum value for BSS properties */ -#define WL_WSEC_INFO_BSS_BASE 0x0100 - -/* size of len and type fields of wl_wsec_info_tlv_t struct */ -#define WL_WSEC_INFO_TLV_HDR_LEN OFFSETOF(wl_wsec_info_tlv_t, data) - -/* Allowed wl_wsec_info properties; not all of them may be supported. */ -typedef enum { - WL_WSEC_INFO_NONE = 0, - WL_WSEC_INFO_MAX_KEYS = 1, - WL_WSEC_INFO_NUM_KEYS = 2, - WL_WSEC_INFO_NUM_HW_KEYS = 3, - WL_WSEC_INFO_MAX_KEY_IDX = 4, - WL_WSEC_INFO_NUM_REPLAY_CNTRS = 5, - WL_WSEC_INFO_SUPPORTED_ALGOS = 6, - WL_WSEC_INFO_MAX_KEY_LEN = 7, - WL_WSEC_INFO_FLAGS = 8, - /* add global/per-wlc properties above */ - WL_WSEC_INFO_BSS_FLAGS = (WL_WSEC_INFO_BSS_BASE + 1), - WL_WSEC_INFO_BSS_WSEC = (WL_WSEC_INFO_BSS_BASE + 2), - WL_WSEC_INFO_BSS_TX_KEY_ID = (WL_WSEC_INFO_BSS_BASE + 3), - WL_WSEC_INFO_BSS_ALGO = (WL_WSEC_INFO_BSS_BASE + 4), - WL_WSEC_INFO_BSS_KEY_LEN = (WL_WSEC_INFO_BSS_BASE + 5), - /* add per-BSS properties above */ - WL_WSEC_INFO_MAX = 0xffff -} wl_wsec_info_type_t; - -/* tlv used to return wl_wsec_info properties */ -typedef struct { - uint16 type; - uint16 len; /* data length */ - uint8 data[1]; /* data follows */ -} wl_wsec_info_tlv_t; - -/* input/output data type for wsec_info iovar */ -typedef struct wl_wsec_info { - uint8 version; /* structure version */ - uint8 pad[2]; - uint8 num_tlvs; - wl_wsec_info_tlv_t tlvs[1]; /* tlv data follows */ -} wl_wsec_info_t; - -/* no default structure packing */ -#include - -enum rssi_reason { - RSSI_REASON_UNKNOW = 0, - RSSI_REASON_LOWRSSI = 1, - RSSI_REASON_NSYC = 2, - RSSI_REASON_TIMEOUT = 3 -}; - -enum tof_reason { - TOF_REASON_OK = 0, - TOF_REASON_REQEND = 1, - TOF_REASON_TIMEOUT = 2, - TOF_REASON_NOACK = 3, - TOF_REASON_INVALIDAVB = 4, - TOF_REASON_INITIAL = 5, - TOF_REASON_ABORT = 6 -}; - -enum rssi_state { - RSSI_STATE_POLL = 0, - RSSI_STATE_TPAIRING = 1, - RSSI_STATE_IPAIRING = 2, - RSSI_STATE_THANDSHAKE = 3, - RSSI_STATE_IHANDSHAKE = 4, - RSSI_STATE_CONFIRMED = 5, - RSSI_STATE_PIPELINE = 6, - RSSI_STATE_NEGMODE = 7, - RSSI_STATE_MONITOR = 8, - RSSI_STATE_LAST = 9 -}; - -enum tof_state { - TOF_STATE_IDLE = 0, - TOF_STATE_IWAITM = 1, - TOF_STATE_TWAITM = 2, - TOF_STATE_ILEGACY = 3, - TOF_STATE_IWAITCL = 4, - TOF_STATE_TWAITCL = 5, - TOF_STATE_ICONFIRM = 6, - TOF_STATE_IREPORT = 7 -}; - -enum tof_mode_type { - TOF_LEGACY_UNKNOWN = 0, - TOF_LEGACY_AP = 1, - TOF_NONLEGACY_AP = 2 -}; - -enum tof_way_type { - TOF_TYPE_ONE_WAY = 0, - TOF_TYPE_TWO_WAY = 1, - TOF_TYPE_REPORT = 2 -}; - -enum tof_rate_type { - TOF_FRAME_RATE_VHT = 0, - TOF_FRAME_RATE_LEGACY = 1 -}; - -#define TOF_ADJ_TYPE_NUM 4 /* number of assisted timestamp adjustment */ -enum tof_adj_mode { - TOF_ADJ_SOFTWARE = 0, - TOF_ADJ_HARDWARE = 1, - TOF_ADJ_SEQ = 2, - TOF_ADJ_NONE = 3 -}; - -#define FRAME_TYPE_NUM 4 /* number of frame type */ -enum frame_type { - FRAME_TYPE_CCK = 0, - FRAME_TYPE_OFDM = 1, - FRAME_TYPE_11N = 2, - FRAME_TYPE_11AC = 3 -}; - -typedef struct wl_proxd_status_iovar { - uint16 method; /* method */ - uint8 mode; /* mode */ - uint8 peermode; /* peer mode */ - uint8 state; /* state */ - uint8 reason; /* reason code */ - uint32 distance; /* distance */ - uint32 txcnt; /* tx pkt counter */ - uint32 rxcnt; /* rx pkt counter */ - struct ether_addr peer; /* peer mac address */ - int8 avg_rssi; /* average rssi */ - int8 hi_rssi; /* highest rssi */ - int8 low_rssi; /* lowest rssi */ - uint32 dbgstatus; /* debug status */ - uint16 frame_type_cnt[FRAME_TYPE_NUM]; /* frame types */ - uint8 adj_type_cnt[TOF_ADJ_TYPE_NUM]; /* adj types HW/SW */ -} wl_proxd_status_iovar_t; - -#ifdef NET_DETECT -typedef struct net_detect_adapter_features { - bool wowl_enabled; - bool net_detect_enabled; - bool nlo_enabled; -} net_detect_adapter_features_t; - -typedef enum net_detect_bss_type { - nd_bss_any = 0, - nd_ibss, - nd_ess -} net_detect_bss_type_t; - -typedef struct net_detect_profile { - wlc_ssid_t ssid; - net_detect_bss_type_t bss_type; /* Ignore for now since Phase 1 is only for ESS */ - uint32 cipher_type; /* DOT11_CIPHER_ALGORITHM enumeration values */ - uint32 auth_type; /* DOT11_AUTH_ALGORITHM enumeration values */ -} net_detect_profile_t; - -typedef struct net_detect_profile_list { - uint32 num_nd_profiles; - net_detect_profile_t nd_profile[0]; -} net_detect_profile_list_t; - -typedef struct net_detect_config { - bool nd_enabled; - uint32 scan_interval; - uint32 wait_period; - bool wake_if_connected; - bool wake_if_disconnected; - net_detect_profile_list_t nd_profile_list; -} net_detect_config_t; - -typedef enum net_detect_wake_reason { - nd_reason_unknown, - nd_net_detected, - nd_wowl_event, - nd_ucode_error -} net_detect_wake_reason_t; - -typedef struct net_detect_wake_data { - net_detect_wake_reason_t nd_wake_reason; - uint32 nd_wake_date_length; - uint8 nd_wake_data[0]; /* Wake data (currently unused) */ -} net_detect_wake_data_t; - -#endif /* NET_DETECT */ - -typedef struct bcnreq { - uint8 bcn_mode; - int dur; - int channel; - struct ether_addr da; - uint16 random_int; - wlc_ssid_t ssid; - uint16 reps; -} bcnreq_t; - -typedef struct rrmreq { - struct ether_addr da; - uint8 reg; - uint8 chan; - uint16 random_int; - uint16 dur; - uint16 reps; -} rrmreq_t; - -typedef struct framereq { - struct ether_addr da; - uint8 reg; - uint8 chan; - uint16 random_int; - uint16 dur; - struct ether_addr ta; - uint16 reps; -} framereq_t; - -typedef struct statreq { - struct ether_addr da; - struct ether_addr peer; - uint16 random_int; - uint16 dur; - uint8 group_id; - uint16 reps; -} statreq_t; - -typedef struct wlc_l2keepalive_ol_params { - uint8 flags; - uint8 prio; - uint16 period_ms; -} wlc_l2keepalive_ol_params_t; - -typedef struct wlc_dwds_config { - uint32 enable; - uint32 mode; /* STA/AP interface */ - struct ether_addr ea; -} wlc_dwds_config_t; - -typedef struct wl_el_set_params_s { - uint8 set; /* Set number */ - uint32 size; /* Size to make/expand */ -} wl_el_set_params_t; - -typedef struct wl_el_tag_params_s { - uint16 tag; - uint8 set; - uint8 flags; -} wl_el_tag_params_t; - -/* Video Traffic Interference Monitor config */ -#define INTFER_VERSION 1 -typedef struct wl_intfer_params { - uint16 version; /* version */ - uint8 period; /* sample period */ - uint8 cnt; /* sample cnt */ - uint8 txfail_thresh; /* non-TCP txfail threshold */ - uint8 tcptxfail_thresh; /* tcptxfail threshold */ -} wl_intfer_params_t; - -typedef struct wl_staprio_cfg { - struct ether_addr ea; /* mac addr */ - uint8 prio; /* scb priority */ -} wl_staprio_cfg_t; - -typedef enum wl_stamon_cfg_cmd_type { - STAMON_CFG_CMD_DEL = 0, - STAMON_CFG_CMD_ADD = 1 -} wl_stamon_cfg_cmd_type_t; - -typedef struct wlc_stamon_sta_config { - wl_stamon_cfg_cmd_type_t cmd; /* 0 - delete, 1 - add */ - struct ether_addr ea; -} wlc_stamon_sta_config_t; - -/* Received Beacons lengths information */ -#define WL_LAST_BCNS_INFO_FIXED_LEN OFFSETOF(wlc_bcn_len_hist_t, bcnlen_ring) -typedef struct wlc_bcn_len_hist { - uint16 ver; /* version field */ - uint16 cur_index; /* current pointed index in ring buffer */ - uint32 max_bcnlen; /* Max beacon length received */ - uint32 min_bcnlen; /* Min beacon length received */ - uint32 ringbuff_len; /* Length of the ring buffer 'bcnlen_ring' */ - uint32 bcnlen_ring[1]; /* ring buffer storing received beacon lengths */ -} wlc_bcn_len_hist_t; - -/* WDS net interface types */ -#define WL_WDSIFTYPE_NONE 0x0 /* The interface type is neither WDS nor DWDS. */ -#define WL_WDSIFTYPE_WDS 0x1 /* The interface is WDS type. */ -#define WL_WDSIFTYPE_DWDS 0x2 /* The interface is DWDS type. */ - -typedef struct wl_bssload_static { - bool is_static; - uint16 sta_count; - uint8 chan_util; - uint16 aac; -} wl_bssload_static_t; - - -#define WL_IF_STATS_T_VERSION 1 /* current version of wl_if_stats structure */ - -/* per interface counters */ -typedef struct wl_if_stats { - uint16 version; /* version of the structure */ - uint16 length; /* length of the entire structure */ - uint32 PAD; /* padding */ - - /* transmit stat counters */ - uint64 txframe; /* tx data frames */ - uint64 txbyte; /* tx data bytes */ - uint64 txerror; /* tx data errors (derived: sum of others) */ - uint64 txnobuf; /* tx out of buffer errors */ - uint64 txrunt; /* tx runt frames */ - uint64 txfail; /* tx failed frames */ - uint64 txretry; /* tx retry frames */ - uint64 txretrie; /* tx multiple retry frames */ - uint64 txfrmsnt; /* tx sent frames */ - uint64 txmulti; /* tx mulitcast sent frames */ - uint64 txfrag; /* tx fragments sent */ - - /* receive stat counters */ - uint64 rxframe; /* rx data frames */ - uint64 rxbyte; /* rx data bytes */ - uint64 rxerror; /* rx data errors (derived: sum of others) */ - uint64 rxnobuf; /* rx out of buffer errors */ - uint64 rxrunt; /* rx runt frames */ - uint64 rxfragerr; /* rx fragment errors */ - uint64 rxmulti; /* rx multicast frames */ - - uint64 txexptime; /* DATA Tx frames suppressed due to timer expiration */ - uint64 txrts; /* RTS/CTS succeeeded count */ - uint64 txnocts; /* RTS/CTS faled count */ -} -wl_if_stats_t; - -/* require strict packing */ -#include -#define WL_PROXD_API_VERSION 0x0300 /* version 3.0 */ - -/* proximity detection methods */ -enum { - WL_PROXD_METHOD_NONE = 0, - WL_PROXD_METHOD_RSVD1 = 1, /* backward compatibility - RSSI, not supported */ - WL_PROXD_METHOD_TOF = 2, /* 11v+BCM proprietary */ - WL_PROXD_METHOD_RSVD2 = 3, /* 11v only - if needed */ - WL_PROXD_METHOD_FTM = 4, /* IEEE rev mc/2014 */ - WL_PROXD_METHOD_MAX -}; -typedef int16 wl_proxd_method_t; - -/* global and method configuration flags */ -enum { - WL_PROXD_FLAG_NONE = 0x00000000, - WL_PROXD_FLAG_RX_ENABLED = 0x00000001, /* respond to requests */ - WL_PROXD_FLAG_RX_RANGE_REQ = 0x00000002, /* 11mc range requests enabled */ - WL_PROXD_FLAG_TX_LCI = 0x00000004, /* transmit location, if available */ - WL_PROXD_FLAG_TX_CIVIC = 0x00000008, /* tx civic loc, if available */ - WL_PROXD_FLAG_RX_AUTO_BURST = 0x00000010, /* respond to requests w/o host action */ - WL_PROXD_FLAG_TX_AUTO_BURST = 0x00000020, /* continue requests w/o host action */ - WL_PROXD_FLAG_ALL = 0xffffffff -}; -typedef uint32 wl_proxd_flags_t; - -/* session flags */ -enum { - WL_PROXD_SESSION_FLAG_NONE = 0x00000000, /* no flags */ - WL_PROXD_SESSION_FLAG_INITIATOR = 0x00000001, /* local device is initiator */ - WL_PROXD_SESSION_FLAG_TARGET = 0x00000002, /* local device is target */ - WL_PROXD_SESSION_FLAG_ONE_WAY = 0x00000004, /* (initiated) 1-way rtt */ - WL_PROXD_SESSION_FLAG_AUTO_BURST = 0x00000008, /* created w/ rx_auto_burst */ - WL_PROXD_SESSION_FLAG_PERSIST = 0x00000010, /* good until cancelled */ - WL_PROXD_SESSION_FLAG_RTT_DETAIL = 0x00000020, /* rtt detail in results */ - WL_PROXD_SESSION_FLAG_TOF_COMPAT = 0x00000040, /* TOF compatibility - TBD */ - WL_PROXD_SESSION_FLAG_AOA = 0x00000080, /* AOA along w/ RTT */ - WL_PROXD_SESSION_FLAG_RX_AUTO_BURST = 0x00000100, /* Same as proxd flags above */ - WL_PROXD_SESSION_FLAG_TX_AUTO_BURST = 0x00000200, /* Same as proxd flags above */ - WL_PROXD_SESSION_FLAG_NAN_BSS = 0x00000400, /* Use NAN BSS, if applicable */ - WL_PROXD_SESSION_FLAG_TS1 = 0x00000800, /* e.g. FTM1 - cap or rx */ - WL_PROXD_SESSION_FLAG_REPORT_FAILURE = 0x00002000, /* report failure to target */ - WL_PROXD_SESSION_FLAG_INITIATOR_RPT = 0x00004000, /* report distance to target */ - WL_PROXD_SESSION_FLAG_NOCHANSWT = 0x00008000, /* No channel switching */ - WL_PROXD_SESSION_FLAG_NETRUAL = 0x00010000, /* netrual mode */ - WL_PROXD_SESSION_FLAG_SEQ_EN = 0x00020000, /* Toast */ - WL_PROXD_SESSION_FLAG_NO_PARAM_OVRD = 0x00040000, /* no param override from target */ - WL_PROXD_SESSION_FLAG_ASAP = 0x00080000, /* ASAP session */ - WL_PROXD_SESSION_FLAG_REQ_LCI = 0x00100000, /* transmit LCI req */ - WL_PROXD_SESSION_FLAG_REQ_CIV = 0x00200000, /* transmit civic loc req */ - WL_PROXD_SESSION_FLAG_COLLECT = 0x80000000, /* debug - collect */ - WL_PROXD_SESSION_FLAG_ALL = 0xffffffff -}; -typedef uint32 wl_proxd_session_flags_t; - -/* time units - mc supports up to 0.1ns resolution */ -enum { - WL_PROXD_TMU_TU = 0, /* 1024us */ - WL_PROXD_TMU_SEC = 1, - WL_PROXD_TMU_MILLI_SEC = 2, - WL_PROXD_TMU_MICRO_SEC = 3, - WL_PROXD_TMU_NANO_SEC = 4, - WL_PROXD_TMU_PICO_SEC = 5 -}; -typedef int16 wl_proxd_tmu_t; - -/* time interval e.g. 10ns */ -typedef struct wl_proxd_intvl { - uint32 intvl; - wl_proxd_tmu_t tmu; - uint8 pad[2]; -} wl_proxd_intvl_t; - -/* commands that can apply to proxd, method or a session */ -enum { - WL_PROXD_CMD_NONE = 0, - WL_PROXD_CMD_GET_VERSION = 1, - WL_PROXD_CMD_ENABLE = 2, - WL_PROXD_CMD_DISABLE = 3, - WL_PROXD_CMD_CONFIG = 4, - WL_PROXD_CMD_START_SESSION = 5, - WL_PROXD_CMD_BURST_REQUEST = 6, - WL_PROXD_CMD_STOP_SESSION = 7, - WL_PROXD_CMD_DELETE_SESSION = 8, - WL_PROXD_CMD_GET_RESULT = 9, - WL_PROXD_CMD_GET_INFO = 10, - WL_PROXD_CMD_GET_STATUS = 11, - WL_PROXD_CMD_GET_SESSIONS = 12, - WL_PROXD_CMD_GET_COUNTERS = 13, - WL_PROXD_CMD_CLEAR_COUNTERS = 14, - WL_PROXD_CMD_COLLECT = 15, - WL_PROXD_CMD_TUNE = 16, - WL_PROXD_CMD_DUMP = 17, - WL_PROXD_CMD_START_RANGING = 18, - WL_PROXD_CMD_STOP_RANGING = 19, - WL_PROXD_CMD_GET_RANGING_INFO = 20, - WL_PROXD_CMD_MAX -}; -typedef int16 wl_proxd_cmd_t; - -/* session ids: - * id 0 is reserved - * ids 1..0x7fff - allocated by host/app - * 0x8000-0xffff - allocated by firmware, used for auto/rx - */ -enum { - WL_PROXD_SESSION_ID_GLOBAL = 0 -}; - -#define WL_PROXD_SID_HOST_MAX 0x7fff -#define WL_PROXD_SID_HOST_ALLOC(_sid) ((_sid) > 0 && (_sid) <= WL_PROXD_SID_HOST_MAX) - -/* maximum number sessions that can be allocated, may be less if tunable */ -#define WL_PROXD_MAX_SESSIONS 16 - -typedef uint16 wl_proxd_session_id_t; - -/* status - TBD BCME_ vs proxd status - range reserved for BCME_ */ -enum { - WL_PROXD_E_INCOMPLETE = -1044, - WL_PROXD_E_OVERRIDDEN = -1043, - WL_PROXD_E_ASAP_FAILED = -1042, - WL_PROXD_E_NOTSTARTED = -1041, - WL_PROXD_E_INVALIDAVB = -1040, - WL_PROXD_E_INCAPABLE = -1039, - WL_PROXD_E_MISMATCH = -1038, - WL_PROXD_E_DUP_SESSION = -1037, - WL_PROXD_E_REMOTE_FAIL = -1036, - WL_PROXD_E_REMOTE_INCAPABLE = -1035, - WL_PROXD_E_SCHED_FAIL = -1034, - WL_PROXD_E_PROTO = -1033, - WL_PROXD_E_EXPIRED = -1032, - WL_PROXD_E_TIMEOUT = -1031, - WL_PROXD_E_NOACK = -1030, - WL_PROXD_E_DEFERRED = -1029, - WL_PROXD_E_INVALID_SID = -1028, - WL_PROXD_E_REMOTE_CANCEL = -1027, - WL_PROXD_E_CANCELED = -1026, /* local */ - WL_PROXD_E_INVALID_SESSION = -1025, - WL_PROXD_E_BAD_STATE = -1024, - WL_PROXD_E_ERROR = -1, - WL_PROXD_E_OK = 0 -}; -typedef int32 wl_proxd_status_t; - -/* session states */ -enum { - WL_PROXD_SESSION_STATE_NONE = 0, - WL_PROXD_SESSION_STATE_CREATED = 1, - WL_PROXD_SESSION_STATE_CONFIGURED = 2, - WL_PROXD_SESSION_STATE_STARTED = 3, - WL_PROXD_SESSION_STATE_DELAY = 4, - WL_PROXD_SESSION_STATE_USER_WAIT = 5, - WL_PROXD_SESSION_STATE_SCHED_WAIT = 6, - WL_PROXD_SESSION_STATE_BURST = 7, - WL_PROXD_SESSION_STATE_STOPPING = 8, - WL_PROXD_SESSION_STATE_ENDED = 9, - WL_PROXD_SESSION_STATE_DESTROYING = -1 -}; -typedef int16 wl_proxd_session_state_t; - -/* RTT sample flags */ -enum { - WL_PROXD_RTT_SAMPLE_NONE = 0x00, - WL_PROXD_RTT_SAMPLE_DISCARD = 0x01 -}; -typedef uint8 wl_proxd_rtt_sample_flags_t; - -typedef struct wl_proxd_rtt_sample { - uint8 id; /* id for the sample - non-zero */ - wl_proxd_rtt_sample_flags_t flags; - int16 rssi; - wl_proxd_intvl_t rtt; /* round trip time */ - uint32 ratespec; -} wl_proxd_rtt_sample_t; - -/* result flags */ -enum { - WL_PRXOD_RESULT_FLAG_NONE = 0x0000, - WL_PROXD_RESULT_FLAG_NLOS = 0x0001, /* LOS - if available */ - WL_PROXD_RESULT_FLAG_LOS = 0x0002, /* NLOS - if available */ - WL_PROXD_RESULT_FLAG_FATAL = 0x0004, /* Fatal error during burst */ - WL_PROXD_RESULT_FLAG_ALL = 0xffff -}; -typedef int16 wl_proxd_result_flags_t; - -/* rtt measurement result */ -typedef struct wl_proxd_rtt_result { - wl_proxd_session_id_t sid; - wl_proxd_result_flags_t flags; - wl_proxd_status_t status; - struct ether_addr peer; - wl_proxd_session_state_t state; /* current state */ - union { - wl_proxd_intvl_t retry_after; /* hint for errors */ - wl_proxd_intvl_t burst_duration; /* burst duration */ - } u; - wl_proxd_rtt_sample_t avg_rtt; - uint32 avg_dist; /* 1/256m units */ - uint16 sd_rtt; /* RTT standard deviation */ - uint8 num_valid_rtt; /* valid rtt cnt */ - uint8 num_ftm; /* actual num of ftm cnt */ - uint16 burst_num; /* in a session */ - uint16 num_rtt; /* 0 if no detail */ - wl_proxd_rtt_sample_t rtt[1]; /* variable */ -} wl_proxd_rtt_result_t; - -/* aoa measurement result */ -typedef struct wl_proxd_aoa_result { - wl_proxd_session_id_t sid; - wl_proxd_result_flags_t flags; - wl_proxd_status_t status; - struct ether_addr peer; - wl_proxd_session_state_t state; - uint16 burst_num; - uint8 pad[2]; - /* wl_proxd_aoa_sample_t sample_avg; TBD */ -} BWL_POST_PACKED_STRUCT wl_proxd_aoa_result_t; - -/* global stats */ -typedef struct wl_proxd_counters { - uint32 tx; /* tx frame count */ - uint32 rx; /* rx frame count */ - uint32 burst; /* total number of burst */ - uint32 sessions; /* total number of sessions */ - uint32 max_sessions; /* max concurrency */ - uint32 sched_fail; /* scheduling failures */ - uint32 timeouts; /* timeouts */ - uint32 protoerr; /* protocol errors */ - uint32 noack; /* tx w/o ack */ - uint32 txfail; /* any tx falure */ - uint32 lci_req_tx; /* tx LCI requests */ - uint32 lci_req_rx; /* rx LCI requests */ - uint32 lci_rep_tx; /* tx LCI reports */ - uint32 lci_rep_rx; /* rx LCI reports */ - uint32 civic_req_tx; /* tx civic requests */ - uint32 civic_req_rx; /* rx civic requests */ - uint32 civic_rep_tx; /* tx civic reports */ - uint32 civic_rep_rx; /* rx civic reports */ - uint32 rctx; /* ranging contexts created */ - uint32 rctx_done; /* count of ranging done */ -} wl_proxd_counters_t; - -typedef struct wl_proxd_counters wl_proxd_session_counters_t; - -enum { - WL_PROXD_CAP_NONE = 0x0000, - WL_PROXD_CAP_ALL = 0xffff -}; -typedef int16 wl_proxd_caps_t; - -/* method capabilities */ -enum { - WL_PROXD_FTM_CAP_NONE = 0x0000, - WL_PROXD_FTM_CAP_FTM1 = 0x0001 -}; -typedef uint16 wl_proxd_ftm_caps_t; - -typedef struct BWL_PRE_PACKED_STRUCT wl_proxd_tlv_id_list { - uint16 num_ids; - uint16 ids[1]; -} BWL_POST_PACKED_STRUCT wl_proxd_tlv_id_list_t; - -typedef struct wl_proxd_session_id_list { - uint16 num_ids; - wl_proxd_session_id_t ids[1]; -} wl_proxd_session_id_list_t; - -/* tlvs returned for get_info on ftm method - * configuration: - * proxd flags - * event mask - * debug mask - * session defaults (session tlvs) - * status tlv - not supported for ftm method - * info tlv - */ -typedef struct wl_proxd_ftm_info { - wl_proxd_ftm_caps_t caps; - uint16 max_sessions; - uint16 num_sessions; - uint16 rx_max_burst; -} wl_proxd_ftm_info_t; - -/* tlvs returned for get_info on session - * session config (tlvs) - * session info tlv - */ -typedef struct wl_proxd_ftm_session_info { - uint16 sid; - uint8 bss_index; - uint8 pad; - struct ether_addr bssid; - wl_proxd_session_state_t state; - wl_proxd_status_t status; - uint16 burst_num; -} wl_proxd_ftm_session_info_t; - -typedef struct wl_proxd_ftm_session_status { - uint16 sid; - wl_proxd_session_state_t state; - wl_proxd_status_t status; - uint16 burst_num; -} wl_proxd_ftm_session_status_t; - -/* rrm range request */ -typedef struct wl_proxd_range_req { - uint16 num_repeat; - uint16 init_delay_range; /* in TUs */ - uint8 pad; - uint8 num_nbr; /* number of (possible) neighbors */ - nbr_element_t nbr[1]; -} wl_proxd_range_req_t; - -#define WL_PROXD_LCI_LAT_OFF 0 -#define WL_PROXD_LCI_LONG_OFF 5 -#define WL_PROXD_LCI_ALT_OFF 10 - -#define WL_PROXD_LCI_GET_LAT(_lci, _lat, _lat_err) { \ - unsigned _off = WL_PROXD_LCI_LAT_OFF; \ - _lat_err = (_lci)->data[(_off)] & 0x3f; \ - _lat = (_lci)->data[(_off)+1]; \ - _lat |= (_lci)->data[(_off)+2] << 8; \ - _lat |= (_lci)->data[_(_off)+3] << 16; \ - _lat |= (_lci)->data[(_off)+4] << 24; \ - _lat <<= 2; \ - _lat |= (_lci)->data[(_off)] >> 6; \ -} - -#define WL_PROXD_LCI_GET_LONG(_lci, _lcilong, _long_err) { \ - unsigned _off = WL_PROXD_LCI_LONG_OFF; \ - _long_err = (_lci)->data[(_off)] & 0x3f; \ - _lcilong = (_lci)->data[(_off)+1]; \ - _lcilong |= (_lci)->data[(_off)+2] << 8; \ - _lcilong |= (_lci)->data[_(_off)+3] << 16; \ - _lcilong |= (_lci)->data[(_off)+4] << 24; \ - __lcilong <<= 2; \ - _lcilong |= (_lci)->data[(_off)] >> 6; \ -} - -#define WL_PROXD_LCI_GET_ALT(_lci, _alt_type, _alt, _alt_err) { \ - unsigned _off = WL_PROXD_LCI_ALT_OFF; \ - _alt_type = (_lci)->data[_off] & 0x0f; \ - _alt_err = (_lci)->data[(_off)] >> 4; \ - _alt_err |= ((_lci)->data[(_off)+1] & 0x03) << 4; \ - _alt = (_lci)->data[(_off)+2]; \ - _alt |= (_lci)->data[(_off)+3] << 8; \ - _alt |= (_lci)->data[_(_off)+4] << 16; \ - _alt <<= 6; \ - _alt |= (_lci)->data[(_off) + 1] >> 2; \ -} - -#define WL_PROXD_LCI_VERSION(_lci) ((_lci)->data[15] >> 6) - -/* availability. advertising mechanism bss specific */ -/* availablity flags */ -enum { - WL_PROXD_AVAIL_NONE = 0, - WL_PROXD_AVAIL_NAN_PUBLISHED = 0x0001, - WL_PROXD_AVAIL_SCHEDULED = 0x0002 /* scheduled by proxd */ -}; -typedef int16 wl_proxd_avail_flags_t; - -/* time reference */ -enum { - WL_PROXD_TREF_NONE = 0, - WL_PROXD_TREF_DEV_TSF = 1, - WL_PROXD_TREF_NAN_DW = 2, - WL_PROXD_TREF_TBTT = 3, - WL_PROXD_TREF_MAX /* last entry */ -}; -typedef int16 wl_proxd_time_ref_t; - -/* proxd channel-time slot */ -typedef struct { - wl_proxd_intvl_t start; /* from ref */ - wl_proxd_intvl_t duration; /* from start */ - uint32 chanspec; -} wl_proxd_time_slot_t; - -/* availability. advertising mechanism bss specific */ -typedef struct wl_proxd_avail { - wl_proxd_avail_flags_t flags; /* for query only */ - wl_proxd_time_ref_t time_ref; - uint16 max_slots; /* for query only */ - uint16 num_slots; - wl_proxd_time_slot_t slots[1]; -} wl_proxd_avail_t; - -/* collect support TBD */ - -/* debugging */ -enum { - WL_PROXD_DEBUG_NONE = 0x00000000, - WL_PROXD_DEBUG_LOG = 0x00000001, - WL_PROXD_DEBUG_IOV = 0x00000002, - WL_PROXD_DEBUG_EVENT = 0x00000004, - WL_PROXD_DEBUG_SESSION = 0x00000008, - WL_PROXD_DEBUG_PROTO = 0x00000010, - WL_PROXD_DEBUG_SCHED = 0x00000020, - WL_PROXD_DEBUG_RANGING = 0x00000040, - WL_PROXD_DEBUG_ALL = 0xffffffff -}; -typedef uint32 wl_proxd_debug_mask_t; - -/* tlv IDs - data length 4 bytes unless overridden by type, alignment 32 bits */ -enum { - WL_PROXD_TLV_ID_NONE = 0, - WL_PROXD_TLV_ID_METHOD = 1, - WL_PROXD_TLV_ID_FLAGS = 2, - WL_PROXD_TLV_ID_CHANSPEC = 3, /* note: uint32 */ - WL_PROXD_TLV_ID_TX_POWER = 4, - WL_PROXD_TLV_ID_RATESPEC = 5, - WL_PROXD_TLV_ID_BURST_DURATION = 6, /* intvl - length of burst */ - WL_PROXD_TLV_ID_BURST_PERIOD = 7, /* intvl - between bursts */ - WL_PROXD_TLV_ID_BURST_FTM_SEP = 8, /* intvl - between FTMs */ - WL_PROXD_TLV_ID_BURST_NUM_FTM = 9, /* uint16 - per burst */ - WL_PROXD_TLV_ID_NUM_BURST = 10, /* uint16 */ - WL_PROXD_TLV_ID_FTM_RETRIES = 11, /* uint16 at FTM level */ - WL_PROXD_TLV_ID_BSS_INDEX = 12, /* uint8 */ - WL_PROXD_TLV_ID_BSSID = 13, - WL_PROXD_TLV_ID_INIT_DELAY = 14, /* intvl - optional, non-standalone only */ - WL_PROXD_TLV_ID_BURST_TIMEOUT = 15, /* expect response within - intvl */ - WL_PROXD_TLV_ID_EVENT_MASK = 16, /* interested events - in/out */ - WL_PROXD_TLV_ID_FLAGS_MASK = 17, /* interested flags - in only */ - WL_PROXD_TLV_ID_PEER_MAC = 18, /* mac address of peer */ - WL_PROXD_TLV_ID_FTM_REQ = 19, /* dot11_ftm_req */ - WL_PROXD_TLV_ID_LCI_REQ = 20, - WL_PROXD_TLV_ID_LCI = 21, - WL_PROXD_TLV_ID_CIVIC_REQ = 22, - WL_PROXD_TLV_ID_CIVIC = 23, - WL_PROXD_TLV_ID_AVAIL = 24, - WL_PROXD_TLV_ID_SESSION_FLAGS = 25, - WL_PROXD_TLV_ID_SESSION_FLAGS_MASK = 26, /* in only */ - WL_PROXD_TLV_ID_RX_MAX_BURST = 27, /* uint16 - limit bursts per session */ - WL_PROXD_TLV_ID_RANGING_INFO = 28, /* ranging info */ - WL_PROXD_TLV_ID_RANGING_FLAGS = 29, /* uint16 */ - WL_PROXD_TLV_ID_RANGING_FLAGS_MASK = 30, /* uint16, in only */ - /* 31 - 34 reserved for other feature */ - WL_PROXD_TLV_ID_FTM_REQ_RETRIES = 35, /* uint16 FTM request retries */ - - /* output - 512 + x */ - WL_PROXD_TLV_ID_STATUS = 512, - WL_PROXD_TLV_ID_COUNTERS = 513, - WL_PROXD_TLV_ID_INFO = 514, - WL_PROXD_TLV_ID_RTT_RESULT = 515, - WL_PROXD_TLV_ID_AOA_RESULT = 516, - WL_PROXD_TLV_ID_SESSION_INFO = 517, - WL_PROXD_TLV_ID_SESSION_STATUS = 518, - WL_PROXD_TLV_ID_SESSION_ID_LIST = 519, - - /* debug tlvs can be added starting 1024 */ - WL_PROXD_TLV_ID_DEBUG_MASK = 1024, - WL_PROXD_TLV_ID_COLLECT = 1025, /* output only */ - WL_PROXD_TLV_ID_STRBUF = 1026, - - WL_PROXD_TLV_ID_MAX -}; - -typedef struct wl_proxd_tlv { - uint16 id; - uint16 len; - uint8 data[1]; -} wl_proxd_tlv_t; - -/* proxd iovar - applies to proxd, method or session */ -typedef struct wl_proxd_iov { - uint16 version; - uint16 len; - wl_proxd_cmd_t cmd; - wl_proxd_method_t method; - wl_proxd_session_id_t sid; - uint8 pad[2]; - wl_proxd_tlv_t tlvs[1]; /* variable */ -} wl_proxd_iov_t; - -#define WL_PROXD_IOV_HDR_SIZE OFFSETOF(wl_proxd_iov_t, tlvs) - -/* The following event definitions may move to bcmevent.h, but sharing proxd types - * across needs more invasive changes unrelated to proxd - */ -enum { - WL_PROXD_EVENT_NONE = 0, /* not an event, reserved */ - WL_PROXD_EVENT_SESSION_CREATE = 1, - WL_PROXD_EVENT_SESSION_START = 2, - WL_PROXD_EVENT_FTM_REQ = 3, - WL_PROXD_EVENT_BURST_START = 4, - WL_PROXD_EVENT_BURST_END = 5, - WL_PROXD_EVENT_SESSION_END = 6, - WL_PROXD_EVENT_SESSION_RESTART = 7, - WL_PROXD_EVENT_BURST_RESCHED = 8, /* burst rescheduled - e.g. partial TSF */ - WL_PROXD_EVENT_SESSION_DESTROY = 9, - WL_PROXD_EVENT_RANGE_REQ = 10, - WL_PROXD_EVENT_FTM_FRAME = 11, - WL_PROXD_EVENT_DELAY = 12, - WL_PROXD_EVENT_VS_INITIATOR_RPT = 13, /* (target) rx initiator-report */ - WL_PROXD_EVENT_RANGING = 14, - - WL_PROXD_EVENT_MAX -}; -typedef int16 wl_proxd_event_type_t; - -/* proxd event mask - upto 32 events for now */ -typedef uint32 wl_proxd_event_mask_t; - -#define WL_PROXD_EVENT_MASK_ALL 0xfffffffe -#define WL_PROXD_EVENT_MASK_EVENT(_event_type) (1 << (_event_type)) -#define WL_PROXD_EVENT_ENABLED(_mask, _event_type) (\ - ((_mask) & WL_PROXD_EVENT_MASK_EVENT(_event_type)) != 0) - -/* proxd event - applies to proxd, method or session */ -typedef struct wl_proxd_event { - uint16 version; - uint16 len; - wl_proxd_event_type_t type; - wl_proxd_method_t method; - wl_proxd_session_id_t sid; - uint8 pad[2]; - wl_proxd_tlv_t tlvs[1]; /* variable */ -} wl_proxd_event_t; - -enum { - WL_PROXD_RANGING_STATE_NONE = 0, - WL_PROXD_RANGING_STATE_NOTSTARTED = 1, - WL_PROXD_RANGING_STATE_INPROGRESS = 2, - WL_PROXD_RANGING_STATE_DONE = 3 -}; -typedef int16 wl_proxd_ranging_state_t; - -/* proxd ranging flags */ -enum { - WL_PROXD_RANGING_FLAG_NONE = 0x0000, /* no flags */ - WL_PROXD_RANGING_FLAG_DEL_SESSIONS_ON_STOP = 0x0001, - WL_PROXD_RANGING_FLAG_ALL = 0xffff -}; -typedef uint16 wl_proxd_ranging_flags_t; - -struct wl_proxd_ranging_info { - wl_proxd_status_t status; - wl_proxd_ranging_state_t state; - wl_proxd_ranging_flags_t flags; - uint16 num_sids; - uint16 num_done; -}; -typedef struct wl_proxd_ranging_info wl_proxd_ranging_info_t; - -/* end proxd definitions */ -/* no default structure packing */ -#include -#endif /* _wlioctl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/linux_osl.c b/drivers/net/wireless/bcmdhd_suzuran/linux_osl.c deleted file mode 100755 index 03d490dc8da2..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/linux_osl.c +++ /dev/null @@ -1,1352 +0,0 @@ -/* - * Linux OS Independent Layer - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: linux_osl.c 548460 2015-04-13 08:55:51Z $ - */ - -#define LINUX_PORT - -#include -#include -#include -#include - - -#include -#include -#include -#include - - - -#include - -#define PCI_CFG_RETRY 10 - -#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ -#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ -#define DUMPBUFSZ 1024 - -#ifdef CONFIG_DHD_USE_STATIC_BUF -#define DHD_SKB_HDRSIZE 336 -#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) -#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) -#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) - -#ifdef CUSTOMER_HW5 -#define STATIC_BUF_MAX_NUM 1 -#else -#define STATIC_BUF_MAX_NUM 16 -#endif /* CUSTOMER_HW5 */ -#define STATIC_BUF_SIZE (PAGE_SIZE*2) -#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) - -typedef struct bcm_static_buf { - spinlock_t static_lock; - unsigned char *buf_ptr; - unsigned char buf_use[STATIC_BUF_MAX_NUM]; -} bcm_static_buf_t; - -static bcm_static_buf_t *bcm_static_buf = 0; - -#define STATIC_PKT_MAX_NUM 8 -#if defined(ENHANCED_STATIC_BUF) -#define STATIC_PKT_4PAGE_NUM 1 -#define DHD_SKB_MAX_BUFSIZE DHD_SKB_4PAGE_BUFSIZE -#else -#define STATIC_PKT_4PAGE_NUM 0 -#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE -#endif /* ENHANCED_STATIC_BUF */ - -typedef struct bcm_static_pkt { - struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM]; - struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM]; -#ifdef ENHANCED_STATIC_BUF - struct sk_buff *skb_16k; -#endif - struct semaphore osl_pkt_sem; - unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM]; -} bcm_static_pkt_t; - -static bcm_static_pkt_t *bcm_static_skb = 0; - -void* wifi_platform_prealloc(void *adapter, int section, unsigned long size); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - -typedef struct bcm_mem_link { - struct bcm_mem_link *prev; - struct bcm_mem_link *next; - uint size; - int line; - void *osh; - char file[BCM_MEM_FILENAME_LEN]; -} bcm_mem_link_t; - -struct osl_cmn_info { - atomic_t malloced; - atomic_t pktalloced; /* Number of allocated packet buffers */ - spinlock_t dbgmem_lock; - bcm_mem_link_t *dbgmem_list; - spinlock_t pktalloc_lock; - atomic_t refcount; /* Number of references to this shared structure. */ -}; -typedef struct osl_cmn_info osl_cmn_t; - -struct osl_info { - osl_pubinfo_t pub; -#ifdef CTFPOOL - ctfpool_t *ctfpool; -#endif /* CTFPOOL */ - uint magic; - void *pdev; - uint failed; - uint bustype; - osl_cmn_t *cmn; /* Common OSL related data shred between two OSH's */ - - void *bus_handle; -}; - -#define OSL_PKTTAG_CLEAR(p) \ -do { \ - struct sk_buff *s = (struct sk_buff *)(p); \ - ASSERT(OSL_PKTTAG_SZ == 32); \ - *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ - *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ - *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ - *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ -} while (0) - -/* PCMCIA attribute space access macros */ - -/* Global ASSERT type flag */ -uint32 g_assert_type = FALSE; - -static int16 linuxbcmerrormap[] = -{ 0, /* 0 */ - -EINVAL, /* BCME_ERROR */ - -EINVAL, /* BCME_BADARG */ - -EINVAL, /* BCME_BADOPTION */ - -EINVAL, /* BCME_NOTUP */ - -EINVAL, /* BCME_NOTDOWN */ - -EINVAL, /* BCME_NOTAP */ - -EINVAL, /* BCME_NOTSTA */ - -EINVAL, /* BCME_BADKEYIDX */ - -EINVAL, /* BCME_RADIOOFF */ - -EINVAL, /* BCME_NOTBANDLOCKED */ - -EINVAL, /* BCME_NOCLK */ - -EINVAL, /* BCME_BADRATESET */ - -EINVAL, /* BCME_BADBAND */ - -E2BIG, /* BCME_BUFTOOSHORT */ - -E2BIG, /* BCME_BUFTOOLONG */ - -EBUSY, /* BCME_BUSY */ - -EINVAL, /* BCME_NOTASSOCIATED */ - -EINVAL, /* BCME_BADSSIDLEN */ - -EINVAL, /* BCME_OUTOFRANGECHAN */ - -EINVAL, /* BCME_BADCHAN */ - -EFAULT, /* BCME_BADADDR */ - -ENOMEM, /* BCME_NORESOURCE */ - -EOPNOTSUPP, /* BCME_UNSUPPORTED */ - -EMSGSIZE, /* BCME_BADLENGTH */ - -EINVAL, /* BCME_NOTREADY */ - -EPERM, /* BCME_EPERM */ - -ENOMEM, /* BCME_NOMEM */ - -EINVAL, /* BCME_ASSOCIATED */ - -ERANGE, /* BCME_RANGE */ - -EINVAL, /* BCME_NOTFOUND */ - -EINVAL, /* BCME_WME_NOT_ENABLED */ - -EINVAL, /* BCME_TSPEC_NOTFOUND */ - -EINVAL, /* BCME_ACM_NOTSUPPORTED */ - -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ - -EIO, /* BCME_SDIO_ERROR */ - -ENODEV, /* BCME_DONGLE_DOWN */ - -EINVAL, /* BCME_VERSION */ - -EIO, /* BCME_TXFAIL */ - -EIO, /* BCME_RXFAIL */ - -ENODEV, /* BCME_NODEVICE */ - -EINVAL, /* BCME_NMODE_DISABLED */ - -ENODATA, /* BCME_NONRESIDENT */ - -EINVAL, /* BCME_SCANREJECT */ - -EINVAL, /* BCME_USAGE_ERROR */ - -EIO, /* BCME_IOCTL_ERROR */ - -EIO, /* BCME_SERIAL_PORT_ERR */ - -EOPNOTSUPP, /* BCME_DISABLED, BCME_NOTENABLED */ - -EIO, /* BCME_DECERR */ - -EIO, /* BCME_ENCERR */ - -EIO, /* BCME_MICERR */ - -ERANGE, /* BCME_REPLAY */ - -EINVAL, /* BCME_IE_NOTFOUND */ - -/* When an new error code is added to bcmutils.h, add os - * specific error translation here as well - */ -/* check if BCME_LAST changed since the last time this function was updated */ -#if BCME_LAST != -52 -#error "You need to add a OS error translation in the linuxbcmerrormap \ - for new error code defined in bcmutils.h" -#endif -}; - -/* translate bcmerrors into linux errors */ -int -osl_error(int bcmerror) -{ - if (bcmerror > 0) - bcmerror = 0; - else if (bcmerror < BCME_LAST) - bcmerror = BCME_ERROR; - - /* Array bounds covered by ASSERT in osl_attach */ - return linuxbcmerrormap[-bcmerror]; -} -#ifdef SHARED_OSL_CMN -osl_t * -osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn) -{ -#else -osl_t * -osl_attach(void *pdev, uint bustype, bool pkttag) -{ - void **osl_cmn = NULL; -#endif /* SHARED_OSL_CMN */ - osl_t *osh; - gfp_t flags; - - flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; - if (!(osh = kmalloc(sizeof(osl_t), flags))) - return osh; - - ASSERT(osh); - - bzero(osh, sizeof(osl_t)); - - if (osl_cmn == NULL || *osl_cmn == NULL) { - if (!(osh->cmn = kmalloc(sizeof(osl_cmn_t), flags))) { - kfree(osh); - return NULL; - } - bzero(osh->cmn, sizeof(osl_cmn_t)); - if (osl_cmn) - *osl_cmn = osh->cmn; - atomic_set(&osh->cmn->malloced, 0); - osh->cmn->dbgmem_list = NULL; - spin_lock_init(&(osh->cmn->dbgmem_lock)); - - spin_lock_init(&(osh->cmn->pktalloc_lock)); - - } else { - osh->cmn = *osl_cmn; - } - atomic_add(1, &osh->cmn->refcount); - - /* Check that error map has the right number of entries in it */ - ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); - - osh->failed = 0; - osh->pdev = pdev; - osh->pub.pkttag = pkttag; - osh->bustype = bustype; - osh->magic = OS_HANDLE_MAGIC; - - switch (bustype) { - case PCI_BUS: - case SI_BUS: - case PCMCIA_BUS: - osh->pub.mmbus = TRUE; - break; - case JTAG_BUS: - case SDIO_BUS: - case USB_BUS: - case SPI_BUS: - case RPC_BUS: - osh->pub.mmbus = FALSE; - break; - default: - ASSERT(FALSE); - break; - } - - - - return osh; -} - -int osl_static_mem_init(osl_t *osh, void *adapter) -{ -#if defined(CONFIG_DHD_USE_STATIC_BUF) - if (!bcm_static_buf && adapter) { - if (!(bcm_static_buf = (bcm_static_buf_t *)wifi_platform_prealloc(adapter, - 3, STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) { - printk("can not alloc static buf!\n"); - bcm_static_skb = NULL; - ASSERT(osh->magic == OS_HANDLE_MAGIC); - kfree(osh); - return -ENOMEM; - } - else - printk("alloc static buf at %p!\n", bcm_static_buf); - - spin_lock_init(&bcm_static_buf->static_lock); - - bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; - } - - if (!bcm_static_skb && adapter) { - int i; - void *skb_buff_ptr = 0; - bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); -#ifdef CUSTOMER_HW5 - /* The SKB static buffer ID is defined as latest id of dhd_prealloc_index - * + 1 in dhd.h - */ - skb_buff_ptr = wifi_platform_prealloc(adapter, 14, 0); -#else - skb_buff_ptr = wifi_platform_prealloc(adapter, 4, 0); -#endif /* CUSTOMER_HW5 */ - if (!skb_buff_ptr) { - printk("cannot alloc static buf!\n"); - bcm_static_buf = NULL; - bcm_static_skb = NULL; - ASSERT(osh->magic == OS_HANDLE_MAGIC); - kfree(osh); - return -ENOMEM; - } - - bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * - (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM)); - for (i = 0; i < STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM; i++) - bcm_static_skb->pkt_use[i] = 0; - - sema_init(&bcm_static_skb->osl_pkt_sem, 1); - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - - return 0; -} - -void osl_set_bus_handle(osl_t *osh, void *bus_handle) -{ - osh->bus_handle = bus_handle; -} - -void* osl_get_bus_handle(osl_t *osh) -{ - return osh->bus_handle; -} - -void -osl_detach(osl_t *osh) -{ - if (osh == NULL) - return; - - ASSERT(osh->magic == OS_HANDLE_MAGIC); - atomic_sub(1, &osh->cmn->refcount); - if (atomic_read(&osh->cmn->refcount) == 0) { - kfree(osh->cmn); - } - kfree(osh); -} - -int osl_static_mem_deinit(osl_t *osh, void *adapter) -{ -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (bcm_static_buf) { - bcm_static_buf = 0; - } - if (bcm_static_skb) { - bcm_static_skb = 0; - } -#endif - return 0; -} - -static struct sk_buff *osl_alloc_skb(osl_t *osh, unsigned int len) -{ - struct sk_buff *skb; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) - gfp_t flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; -#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_ZONE_DMA) - flags |= GFP_ATOMIC; -#endif - skb = __dev_alloc_skb(len, flags); -#else - skb = dev_alloc_skb(len); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) */ - return skb; -} - -#ifdef CTFPOOL - -#ifdef CTFPOOL_SPINLOCK -#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_irqsave(&(ctfpool)->lock, flags) -#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_irqrestore(&(ctfpool)->lock, flags) -#else -#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_bh(&(ctfpool)->lock) -#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_bh(&(ctfpool)->lock) -#endif /* CTFPOOL_SPINLOCK */ -/* - * Allocate and add an object to packet pool. - */ -void * -osl_ctfpool_add(osl_t *osh) -{ - struct sk_buff *skb; -#ifdef CTFPOOL_SPINLOCK - unsigned long flags; -#endif /* CTFPOOL_SPINLOCK */ - - if ((osh == NULL) || (osh->ctfpool == NULL)) - return NULL; - - CTFPOOL_LOCK(osh->ctfpool, flags); - ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj); - - /* No need to allocate more objects */ - if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) { - CTFPOOL_UNLOCK(osh->ctfpool, flags); - return NULL; - } - - /* Allocate a new skb and add it to the ctfpool */ - skb = osl_alloc_skb(osh, osh->ctfpool->obj_size); - if (skb == NULL) { - printf("%s: skb alloc of len %d failed\n", __FUNCTION__, - osh->ctfpool->obj_size); - CTFPOOL_UNLOCK(osh->ctfpool, flags); - return NULL; - } - - /* Add to ctfpool */ - skb->next = (struct sk_buff *)osh->ctfpool->head; - osh->ctfpool->head = skb; - osh->ctfpool->fast_frees++; - osh->ctfpool->curr_obj++; - - /* Hijack a skb member to store ptr to ctfpool */ - CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool; - - /* Use bit flag to indicate skb from fast ctfpool */ - PKTFAST(osh, skb) = FASTBUF; - - CTFPOOL_UNLOCK(osh->ctfpool, flags); - - return skb; -} - -/* - * Add new objects to the pool. - */ -void -osl_ctfpool_replenish(osl_t *osh, uint thresh) -{ - if ((osh == NULL) || (osh->ctfpool == NULL)) - return; - - /* Do nothing if no refills are required */ - while ((osh->ctfpool->refills > 0) && (thresh--)) { - osl_ctfpool_add(osh); - osh->ctfpool->refills--; - } -} - -/* - * Initialize the packet pool with specified number of objects. - */ -int32 -osl_ctfpool_init(osl_t *osh, uint numobj, uint size) -{ - gfp_t flags; - - flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; - osh->ctfpool = kzalloc(sizeof(ctfpool_t), flags); - ASSERT(osh->ctfpool); - - osh->ctfpool->max_obj = numobj; - osh->ctfpool->obj_size = size; - - spin_lock_init(&osh->ctfpool->lock); - - while (numobj--) { - if (!osl_ctfpool_add(osh)) - return -1; - osh->ctfpool->fast_frees--; - } - - return 0; -} - -/* - * Cleanup the packet pool objects. - */ -void -osl_ctfpool_cleanup(osl_t *osh) -{ - struct sk_buff *skb, *nskb; -#ifdef CTFPOOL_SPINLOCK - unsigned long flags; -#endif /* CTFPOOL_SPINLOCK */ - - if ((osh == NULL) || (osh->ctfpool == NULL)) - return; - - CTFPOOL_LOCK(osh->ctfpool, flags); - - skb = osh->ctfpool->head; - - while (skb != NULL) { - nskb = skb->next; - dev_kfree_skb(skb); - skb = nskb; - osh->ctfpool->curr_obj--; - } - - ASSERT(osh->ctfpool->curr_obj == 0); - osh->ctfpool->head = NULL; - CTFPOOL_UNLOCK(osh->ctfpool, flags); - - kfree(osh->ctfpool); - osh->ctfpool = NULL; -} - -void -osl_ctfpool_stats(osl_t *osh, void *b) -{ - struct bcmstrbuf *bb; - - if ((osh == NULL) || (osh->ctfpool == NULL)) - return; - -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (bcm_static_buf) { - bcm_static_buf = 0; - } - if (bcm_static_skb) { - bcm_static_skb = 0; - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - - bb = b; - - ASSERT((osh != NULL) && (bb != NULL)); - - bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n", - osh->ctfpool->max_obj, osh->ctfpool->obj_size, - osh->ctfpool->curr_obj, osh->ctfpool->refills); - bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n", - osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees, - osh->ctfpool->slow_allocs); -} - -static inline struct sk_buff * -osl_pktfastget(osl_t *osh, uint len) -{ - struct sk_buff *skb; -#ifdef CTFPOOL_SPINLOCK - unsigned long flags; -#endif /* CTFPOOL_SPINLOCK */ - - /* Try to do fast allocate. Return null if ctfpool is not in use - * or if there are no items in the ctfpool. - */ - if (osh->ctfpool == NULL) - return NULL; - - CTFPOOL_LOCK(osh->ctfpool, flags); - if (osh->ctfpool->head == NULL) { - ASSERT(osh->ctfpool->curr_obj == 0); - osh->ctfpool->slow_allocs++; - CTFPOOL_UNLOCK(osh->ctfpool, flags); - return NULL; - } - - if (len > osh->ctfpool->obj_size) { - CTFPOOL_UNLOCK(osh->ctfpool, flags); - return NULL; - } - - ASSERT(len <= osh->ctfpool->obj_size); - - /* Get an object from ctfpool */ - skb = (struct sk_buff *)osh->ctfpool->head; - osh->ctfpool->head = (void *)skb->next; - - osh->ctfpool->fast_allocs++; - osh->ctfpool->curr_obj--; - ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head); - CTFPOOL_UNLOCK(osh->ctfpool, flags); - - /* Init skb struct */ - skb->next = skb->prev = NULL; - skb->data = skb->head + 16; - skb->tail = skb->head + 16; - skb->len = 0; - skb->cloned = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) - skb->list = NULL; -#endif - atomic_set(&skb->users, 1); - - PKTSETCLINK(skb, NULL); - PKTCCLRATTR(skb); - PKTFAST(osh, skb) &= ~(CTFBUF | SKIPCT | CHAINED); - - return skb; -} -#endif /* CTFPOOL */ -/* Convert a driver packet to native(OS) packet - * In the process, packettag is zeroed out before sending up - * IP code depends on skb->cb to be setup correctly with various options - * In our case, that means it should be 0 - */ -struct sk_buff * BCMFASTPATH -osl_pkt_tonative(osl_t *osh, void *pkt) -{ - struct sk_buff *nskb; - - if (osh->pub.pkttag) - OSL_PKTTAG_CLEAR(pkt); - - /* Decrement the packet counter */ - for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { - atomic_sub(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced); - - } - return (struct sk_buff *)pkt; -} - -/* Convert a native(OS) packet to driver packet. - * In the process, native packet is destroyed, there is no copying - * Also, a packettag is zeroed out - */ -void * BCMFASTPATH -osl_pkt_frmnative(osl_t *osh, void *pkt) -{ - struct sk_buff *nskb; - - if (osh->pub.pkttag) - OSL_PKTTAG_CLEAR(pkt); - - /* Increment the packet counter */ - for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { - atomic_add(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced); - - } - return (void *)pkt; -} - -/* Return a new packet. zero out pkttag */ -void * BCMFASTPATH -osl_pktget(osl_t *osh, uint len) -{ - struct sk_buff *skb; - -#ifdef CTFPOOL - /* Allocate from local pool */ - skb = osl_pktfastget(osh, len); - if ((skb != NULL) || ((skb = osl_alloc_skb(osh, len)) != NULL)) { -#else /* CTFPOOL */ - if ((skb = osl_alloc_skb(osh, len))) { -#endif /* CTFPOOL */ - skb->tail += len; - skb->len += len; - skb->priority = 0; - - atomic_inc(&osh->cmn->pktalloced); - } - - return ((void*) skb); -} - -#ifdef CTFPOOL -static inline void -osl_pktfastfree(osl_t *osh, struct sk_buff *skb) -{ - ctfpool_t *ctfpool; -#ifdef CTFPOOL_SPINLOCK - unsigned long flags; -#endif /* CTFPOOL_SPINLOCK */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) - skb->tstamp.tv.sec = 0; -#else - skb->stamp.tv_sec = 0; -#endif - - /* We only need to init the fields that we change */ - skb->dev = NULL; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) - skb->dst = NULL; -#endif - OSL_PKTTAG_CLEAR(skb); - skb->ip_summed = 0; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - skb_orphan(skb); -#else - skb->destructor = NULL; -#endif - - ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); - ASSERT(ctfpool != NULL); - - /* Add object to the ctfpool */ - CTFPOOL_LOCK(ctfpool, flags); - skb->next = (struct sk_buff *)ctfpool->head; - ctfpool->head = (void *)skb; - - ctfpool->fast_frees++; - ctfpool->curr_obj++; - - ASSERT(ctfpool->curr_obj <= ctfpool->max_obj); - CTFPOOL_UNLOCK(ctfpool, flags); -} -#endif /* CTFPOOL */ - -/* Free the driver packet. Free the tag if present */ -void BCMFASTPATH -osl_pktfree(osl_t *osh, void *p, bool send) -{ - struct sk_buff *skb, *nskb; - if (osh == NULL) - return; - - skb = (struct sk_buff*) p; - - if (send && osh->pub.tx_fn) - osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); - - PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE); - - /* perversion: we use skb->next to chain multi-skb packets */ - while (skb) { - nskb = skb->next; - skb->next = NULL; - - - -#ifdef CTFPOOL - if (PKTISFAST(osh, skb)) { - if (atomic_read(&skb->users) == 1) - smp_rmb(); - else if (!atomic_dec_and_test(&skb->users)) - goto next_skb; - osl_pktfastfree(osh, skb); - } else -#endif - { - 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); - } -#ifdef CTFPOOL -next_skb: -#endif - atomic_dec(&osh->cmn->pktalloced); - skb = nskb; - } -} - -#ifdef CONFIG_DHD_USE_STATIC_BUF -void* -osl_pktget_static(osl_t *osh, uint len) -{ - int i = 0; - struct sk_buff *skb; - - if (len > DHD_SKB_MAX_BUFSIZE) { - printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len); - return osl_pktget(osh, len); - } - - down(&bcm_static_skb->osl_pkt_sem); - - if (len <= DHD_SKB_1PAGE_BUFSIZE) { - for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { - if (bcm_static_skb->pkt_use[i] == 0) - break; - } - - if (i != STATIC_PKT_MAX_NUM) { - bcm_static_skb->pkt_use[i] = 1; - - skb = bcm_static_skb->skb_4k[i]; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb_set_tail_pointer(skb, len); -#else - skb->tail = skb->data + len; -#endif /* NET_SKBUFF_DATA_USES_OFFSET */ - skb->len = len; - - up(&bcm_static_skb->osl_pkt_sem); - return skb; - } - } - - if (len <= DHD_SKB_2PAGE_BUFSIZE) { - for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { - if (bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] - == 0) - break; - } - - if (i != STATIC_PKT_MAX_NUM) { - bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 1; - skb = bcm_static_skb->skb_8k[i]; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb_set_tail_pointer(skb, len); -#else - skb->tail = skb->data + len; -#endif /* NET_SKBUFF_DATA_USES_OFFSET */ - skb->len = len; - - up(&bcm_static_skb->osl_pkt_sem); - return skb; - } - } - -#if defined(ENHANCED_STATIC_BUF) - if (bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] == 0) { - bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 1; - - skb = bcm_static_skb->skb_16k; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb_set_tail_pointer(skb, len); -#else - skb->tail = skb->data + len; -#endif /* NET_SKBUFF_DATA_USES_OFFSET */ - skb->len = len; - - up(&bcm_static_skb->osl_pkt_sem); - return skb; - } -#endif /* ENHANCED_STATIC_BUF */ - - up(&bcm_static_skb->osl_pkt_sem); - printk("%s: all static pkt in use!\n", __FUNCTION__); - return osl_pktget(osh, len); -} - -void -osl_pktfree_static(osl_t *osh, void *p, bool send) -{ - int i; - if (!bcm_static_skb) { - osl_pktfree(osh, p, send); - return; - } - - down(&bcm_static_skb->osl_pkt_sem); - for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { - if (p == bcm_static_skb->skb_4k[i]) { - bcm_static_skb->pkt_use[i] = 0; - up(&bcm_static_skb->osl_pkt_sem); - return; - } - } - - for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { - if (p == bcm_static_skb->skb_8k[i]) { - bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0; - up(&bcm_static_skb->osl_pkt_sem); - return; - } - } -#ifdef ENHANCED_STATIC_BUF - if (p == bcm_static_skb->skb_16k) { - bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 0; - up(&bcm_static_skb->osl_pkt_sem); - return; - } -#endif - up(&bcm_static_skb->osl_pkt_sem); - osl_pktfree(osh, p, send); -} -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - -uint32 -osl_pci_read_config(osl_t *osh, uint offset, uint size) -{ - uint val = 0; - uint retry = PCI_CFG_RETRY; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - - /* only 4byte access supported */ - ASSERT(size == 4); - - do { - pci_read_config_dword(osh->pdev, offset, &val); - if (val != 0xffffffff) - break; - } while (retry--); - - - return (val); -} - -void -osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) -{ - uint retry = PCI_CFG_RETRY; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - - /* only 4byte access supported */ - ASSERT(size == 4); - - do { - pci_write_config_dword(osh->pdev, offset, val); - if (offset != PCI_BAR0_WIN) - break; - if (osl_pci_read_config(osh, offset, size) == val) - break; - } while (retry--); - -} - -/* return bus # for the pci device pointed by osh->pdev */ -uint -osl_pci_bus(osl_t *osh) -{ - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); - - return ((struct pci_dev *)osh->pdev)->bus->number; -} - -/* return slot # for the pci device pointed by osh->pdev */ -uint -osl_pci_slot(osl_t *osh) -{ - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); - -#if 0 > KERNEL_VERSION(2, 6, 35) - return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn) + 1; -#else - return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); -#endif -} - -/* return the pci device pointed by osh->pdev */ -struct pci_dev * -osl_pci_device(osl_t *osh) -{ - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); - - return osh->pdev; -} - -static void -osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) -{ -} - -void -osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size) -{ - osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE); -} - -void -osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) -{ - osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); -} - -void * -osl_malloc(osl_t *osh, uint size) -{ - void *addr; - gfp_t flags; - - /* only ASSERT if osh is defined */ - if (osh) - ASSERT(osh->magic == OS_HANDLE_MAGIC); -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (bcm_static_buf) - { - unsigned long irq_flags; - int i = 0; - if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE)) - { - spin_lock_irqsave(&bcm_static_buf->static_lock, irq_flags); - - for (i = 0; i < STATIC_BUF_MAX_NUM; i++) - { - if (bcm_static_buf->buf_use[i] == 0) - break; - } - - if (i == STATIC_BUF_MAX_NUM) - { - spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); - printk("all static buff in use!\n"); - goto original; - } - - bcm_static_buf->buf_use[i] = 1; - spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); - - bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size); - if (osh) - atomic_add(size, &osh->cmn->malloced); - - return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i)); - } - } -original: -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - - flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; - if ((addr = kmalloc(size, flags)) == NULL) { - if (osh) - osh->failed++; - return (NULL); - } - if (osh && osh->cmn) - atomic_add(size, &osh->cmn->malloced); - - return (addr); -} - -void * -osl_mallocz(osl_t *osh, uint size) -{ - void *ptr; - - ptr = osl_malloc(osh, size); - - if (ptr != NULL) { - bzero(ptr, size); - } - - return ptr; -} - -void -osl_mfree(osl_t *osh, void *addr, uint size) -{ -#ifdef CONFIG_DHD_USE_STATIC_BUF - unsigned long flags; - - if (bcm_static_buf) - { - if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr - <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN))) - { - int buf_idx = 0; - - buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE; - - spin_lock_irqsave(&bcm_static_buf->static_lock, flags); - bcm_static_buf->buf_use[buf_idx] = 0; - spin_unlock_irqrestore(&bcm_static_buf->static_lock, flags); - - if (osh && osh->cmn) { - ASSERT(osh->magic == OS_HANDLE_MAGIC); - atomic_sub(size, &osh->cmn->malloced); - } - return; - } - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - if (osh && osh->cmn) { - ASSERT(osh->magic == OS_HANDLE_MAGIC); - - ASSERT(size <= osl_malloced(osh)); - - atomic_sub(size, &osh->cmn->malloced); - } - kfree(addr); -} - -uint -osl_check_memleak(osl_t *osh) -{ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - if (atomic_read(&osh->cmn->refcount) == 1) - return (atomic_read(&osh->cmn->malloced)); - else - return 0; -} - -uint -osl_malloced(osl_t *osh) -{ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - return (atomic_read(&osh->cmn->malloced)); -} - -uint -osl_malloc_failed(osl_t *osh) -{ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - return (osh->failed); -} - - -uint -osl_dma_consistent_align(void) -{ - return (PAGE_SIZE); -} - -void* -osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, dmaaddr_t *pap) -{ - void *va; - uint16 align = (1 << align_bits); - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - - if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) - size += align; - *alloced = size; - - { - dma_addr_t pap_lin; - va = pci_alloc_consistent(osh->pdev, size, &pap_lin); - *pap = (dmaaddr_t)pap_lin; - } - return va; -} - -void -osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa) -{ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - - pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); -} - -dmaaddr_t BCMFASTPATH -osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah) -{ - int dir; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; - - - return (pci_map_single(osh->pdev, va, size, dir)); -} - -void BCMFASTPATH -osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) -{ - int dir; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; - pci_unmap_single(osh->pdev, (uint32)pa, size, dir); -} - - -#if defined(BCMASSERT_LOG) -void -osl_assert(const char *exp, const char *file, int line) -{ - char tempbuf[256]; - const char *basename; - - basename = strrchr(file, '/'); - /* skip the '/' */ - if (basename) - basename++; - - if (!basename) - basename = file; - -#ifdef BCMASSERT_LOG - snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", - exp, basename, line); - printk("%s", tempbuf); -#endif /* BCMASSERT_LOG */ - - -} -#endif - -void -osl_delay(uint usec) -{ - uint d; - - while (usec > 0) { - d = MIN(usec, 1000); - udelay(d); - usec -= d; - } -} - -void -osl_sleep(uint ms) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - if (ms < 20) - usleep_range(ms*1000, ms*1000 + 1000); - else -#endif - msleep(ms); -} - - - -/* Clone a packet. - * The pkttag contents are NOT cloned. - */ -void * -osl_pktdup(osl_t *osh, void *skb) -{ - void * p; - - ASSERT(!PKTISCHAINED(skb)); - - /* clear the CTFBUF flag if set and map the rest of the buffer - * before cloning. - */ - PKTCTFMAP(osh, skb); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - if ((p = pskb_copy((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) -#else - if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) -#endif - return NULL; - -#ifdef CTFPOOL - if (PKTISFAST(osh, skb)) { - ctfpool_t *ctfpool; - - /* if the buffer allocated from ctfpool is cloned then - * we can't be sure when it will be freed. since there - * is a chance that we will be losing a buffer - * from our pool, we increment the refill count for the - * object to be alloced later. - */ - ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); - ASSERT(ctfpool != NULL); - PKTCLRFAST(osh, p); - PKTCLRFAST(osh, skb); - ctfpool->refills++; - } -#endif /* CTFPOOL */ - - /* Clear PKTC context */ - PKTSETCLINK(p, NULL); - PKTCCLRFLAGS(p); - PKTCSETCNT(p, 1); - PKTCSETLEN(p, PKTLEN(osh, skb)); - - /* skb_clone copies skb->cb.. we don't want that */ - if (osh->pub.pkttag) - OSL_PKTTAG_CLEAR(p); - - /* Increment the packet counter */ - atomic_inc(&osh->cmn->pktalloced); - return (p); -} - - - -/* - * OSLREGOPS specifies the use of osl_XXX routines to be used for register access - */ - -/* - * BINOSL selects the slightly slower function-call-based binary compatible osl. - */ - -uint -osl_pktalloced(osl_t *osh) -{ - if (atomic_read(&osh->cmn->refcount) == 1) - return (atomic_read(&osh->cmn->pktalloced)); - else - return 0; -} - -/* Linux Kernel: File Operations: start */ -void * -osl_os_open_image(char *filename) -{ - struct file *fp; - - fp = filp_open(filename, O_RDONLY, 0); - /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? - * Alternative: - * fp = open_namei(AT_FDCWD, filename, O_RD, 0); - * ??? - */ - if (IS_ERR(fp)) - fp = NULL; - - return fp; -} - -int -osl_os_get_image_block(char *buf, int len, void *image) -{ - struct file *fp = (struct file *)image; - int rdlen; - - if (!image) - return 0; - - rdlen = kernel_read(fp, fp->f_pos, buf, len); - if (rdlen > 0) - fp->f_pos += rdlen; - - return rdlen; -} - -void -osl_os_close_image(void *image) -{ - if (image) - filp_close((struct file *)image, NULL); -} - -int -osl_os_image_size(void *image) -{ - int len = 0, curroffset; - - if (image) { - /* store the current offset */ - curroffset = generic_file_llseek(image, 0, 1); - /* goto end of file to get length */ - len = generic_file_llseek(image, 0, 2); - /* restore back the offset */ - generic_file_llseek(image, curroffset, 0); - } - return len; -} - -/* Linux Kernel: File Operations: end */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/sbutils.c b/drivers/net/wireless/bcmdhd_suzuran/sbutils.c deleted file mode 100755 index a625d65993d3..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/sbutils.c +++ /dev/null @@ -1,1063 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: sbutils.c 431423 2013-10-23 16:07:35Z $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "siutils_priv.h" - - -/* local prototypes */ -static uint _sb_coreidx(si_info_t *sii, uint32 sba); -static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, - uint ncores); -static uint32 _sb_coresba(si_info_t *sii); -static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); -#define SET_SBREG(sii, r, mask, val) \ - W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) -#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) - -/* sonicsrev */ -#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) -#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT) - -#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr)) -#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v)) -#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v))) -#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v))) - -static uint32 -sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) -{ - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint8 tmp; - uint32 val, intr_val = 0; - - - /* - * compact flash only has 11 bits address, while we needs 12 bits address. - * MEM_SEG will be OR'd with other 11 bits address in hardware, - * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). - * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special - */ - if (PCMCIA(sii)) { - INTR_OFF(sii, intr_val); - tmp = 1; - OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); - sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ - } - - val = R_REG(sii->osh, sbr); - - if (PCMCIA(sii)) { - tmp = 0; - OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); - INTR_RESTORE(sii, intr_val); - } - - return (val); -} - -static void -sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) -{ - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint8 tmp; - volatile uint32 dummy; - uint32 intr_val = 0; - - - /* - * compact flash only has 11 bits address, while we needs 12 bits address. - * MEM_SEG will be OR'd with other 11 bits address in hardware, - * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). - * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special - */ - if (PCMCIA(sii)) { - INTR_OFF(sii, intr_val); - tmp = 1; - OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); - sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ - } - - if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { - dummy = R_REG(sii->osh, sbr); - BCM_REFERENCE(dummy); - W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); - dummy = R_REG(sii->osh, sbr); - BCM_REFERENCE(dummy); - W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); - } else - W_REG(sii->osh, sbr, v); - - if (PCMCIA(sii)) { - tmp = 0; - OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); - INTR_RESTORE(sii, intr_val); - } -} - -uint -sb_coreid(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); -} - -uint -sb_intflag(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - void *corereg; - sbconfig_t *sb; - uint origidx, intflag, intr_val = 0; - - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - corereg = si_setcore(sih, CC_CORE_ID, 0); - ASSERT(corereg != NULL); - sb = REGS2SB(corereg); - intflag = R_SBREG(sii, &sb->sbflagst); - sb_setcoreidx(sih, origidx); - INTR_RESTORE(sii, intr_val); - - return intflag; -} - -uint -sb_flag(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK; -} - -void -sb_setint(si_t *sih, int siflag) -{ - si_info_t *sii; - sbconfig_t *sb; - uint32 vec; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - if (siflag == -1) - vec = 0; - else - vec = 1 << siflag; - W_SBREG(sii, &sb->sbintvec, vec); -} - -/* return core index of the core with address 'sba' */ -static uint -_sb_coreidx(si_info_t *sii, uint32 sba) -{ - uint i; - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - for (i = 0; i < sii->numcores; i ++) - if (sba == cores_info->coresba[i]) - return i; - return BADIDX; -} - -/* return core address of the current core */ -static uint32 -_sb_coresba(si_info_t *sii) -{ - uint32 sbaddr; - - - switch (BUSTYPE(sii->pub.bustype)) { - case SI_BUS: { - sbconfig_t *sb = REGS2SB(sii->curmap); - sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0)); - break; - } - - case PCI_BUS: - sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); - break; - - case PCMCIA_BUS: { - uint8 tmp = 0; - OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); - sbaddr = (uint32)tmp << 12; - OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); - sbaddr |= (uint32)tmp << 16; - OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); - sbaddr |= (uint32)tmp << 24; - break; - } - - case SPI_BUS: - case SDIO_BUS: - sbaddr = (uint32)(uintptr)sii->curmap; - break; - - - default: - sbaddr = BADCOREADDR; - break; - } - - return sbaddr; -} - -uint -sb_corevendor(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); -} - -uint -sb_corerev(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - uint sbidh; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - sbidh = R_SBREG(sii, &sb->sbidhigh); - - return (SBCOREREV(sbidh)); -} - -/* set core-specific control flags */ -void -sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii; - sbconfig_t *sb; - uint32 w; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - ASSERT((val & ~mask) == 0); - - /* mask and set */ - w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | - (val << SBTML_SICF_SHIFT); - W_SBREG(sii, &sb->sbtmstatelow, w); -} - -/* set/clear core-specific control flags */ -uint32 -sb_core_cflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii; - sbconfig_t *sb; - uint32 w; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - ASSERT((val & ~mask) == 0); - - /* mask and set */ - if (mask || val) { - w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | - (val << SBTML_SICF_SHIFT); - W_SBREG(sii, &sb->sbtmstatelow, w); - } - - /* return the new value - * for write operation, the following readback ensures the completion of write opration. - */ - return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT); -} - -/* set/clear core-specific status flags */ -uint32 -sb_core_sflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii; - sbconfig_t *sb; - uint32 w; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - ASSERT((val & ~mask) == 0); - ASSERT((mask & ~SISF_CORE_BITS) == 0); - - /* mask and set */ - if (mask || val) { - w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) | - (val << SBTMH_SISF_SHIFT); - W_SBREG(sii, &sb->sbtmstatehigh, w); - } - - /* return the new value */ - return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT); -} - -bool -sb_iscoreup(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - return ((R_SBREG(sii, &sb->sbtmstatelow) & - (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == - (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); -} - -/* - * 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 fidleing with interrupts or core switches are needed. - * - * Also, when using pci/pcie, we can optimize away the core switching for pci registers - * and (on newer pci cores) chipcommon registers. - */ -uint -sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -{ - uint origidx = 0; - uint32 *r = NULL; - uint w; - uint intr_val = 0; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - ASSERT((val & ~mask) == 0); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sii->pub.bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (uint32 *)((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 = si_coreidx(&sii->pub); - - /* switch core */ - r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff); - } - ASSERT(r != NULL); - - /* mask and set */ - if (mask || val) { - if (regoff >= SBCONFIGOFF) { - w = (R_SBREG(sii, r) & ~mask) | val; - W_SBREG(sii, r, w); - } else { - w = (R_REG(sii->osh, r) & ~mask) | val; - W_REG(sii->osh, r, w); - } - } - - /* readback */ - if (regoff >= SBCONFIGOFF) - w = R_SBREG(sii, r); - else { - if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) && - (coreidx == SI_CC_IDX) && - (regoff == OFFSETOF(chipcregs_t, watchdog))) { - w = val; - } else - w = R_REG(sii->osh, r); - } - - if (!fast) { - /* restore core index */ - if (origidx != coreidx) - sb_setcoreidx(&sii->pub, origidx); - - INTR_RESTORE(sii, intr_val); - } - - return (w); -} - -/* - * If there is no need for fiddling with interrupts or core switches (typically silicon - * back plane registers, pci registers and chipcommon registers), this function - * returns the register offset on this core to a mapped address. This address can - * be used for W_REG/R_REG directly. - * - * For accessing registers that would need a core switch, this function will return - * NULL. - */ -uint32 * -sb_corereg_addr(si_t *sih, uint coreidx, uint regoff) -{ - uint32 *r = NULL; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sii->pub.bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (uint32 *)((char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + - regoff); - } - } - - if (!fast) - return 0; - - return (r); -} - -/* Scan the enumeration space to find all cores starting from the given - * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' - * is the default core address at chip POR time and 'regs' is the virtual - * address that the default core is mapped at. 'ncores' is the number of - * cores expected on bus 'sbba'. It returns the total number of cores - * starting from bus 'sbba', inclusive. - */ -#define SB_MAXBUSES 2 -static uint -_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores) -{ - uint next; - uint ncc = 0; - uint i; - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - if (bus >= SB_MAXBUSES) { - SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus)); - return 0; - } - SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores)); - - /* Scan all cores on the bus starting from core 0. - * Core addresses must be contiguous on each bus. - */ - for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { - cores_info->coresba[next] = sbba + (i * SI_CORE_SIZE); - - /* keep and reuse the initial register mapping */ - if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (cores_info->coresba[next] == sba)) { - SI_VMSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next)); - cores_info->regs[next] = regs; - } - - /* change core to 'next' and read its coreid */ - sii->curmap = _sb_setcoreidx(sii, next); - sii->curidx = next; - - cores_info->coreid[next] = sb_coreid(&sii->pub); - - /* core specific processing... */ - /* chipc provides # cores */ - if (cores_info->coreid[next] == CC_CORE_ID) { - chipcregs_t *cc = (chipcregs_t *)sii->curmap; - uint32 ccrev = sb_corerev(&sii->pub); - - /* determine numcores - this is the total # cores in the chip */ - if (((ccrev == 4) || (ccrev >= 6))) { - ASSERT(cc); - numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> - CID_CC_SHIFT; - } else { - /* Older chips */ - uint chip = CHIPID(sii->pub.chip); - - if (chip == BCM4306_CHIP_ID) /* < 4306c0 */ - numcores = 6; - else if (chip == BCM4704_CHIP_ID) - numcores = 9; - else if (chip == BCM5365_CHIP_ID) - numcores = 7; - else { - SI_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", - chip)); - ASSERT(0); - numcores = 1; - } - } - SI_VMSG(("_sb_scan: there are %u cores in the chip %s\n", numcores, - sii->pub.issim ? "QT" : "")); - } - /* scan bridged SB(s) and add results to the end of the list */ - else if (cores_info->coreid[next] == OCP_CORE_ID) { - sbconfig_t *sb = REGS2SB(sii->curmap); - uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); - uint nsbcc; - - sii->numcores = next + 1; - - if ((nsbba & 0xfff00000) != SI_ENUM_BASE) - continue; - nsbba &= 0xfffff000; - if (_sb_coreidx(sii, nsbba) != BADIDX) - continue; - - nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16; - nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc); - if (sbba == SI_ENUM_BASE) - numcores -= nsbcc; - ncc += nsbcc; - } - } - - SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba)); - - sii->numcores = i + ncc; - return sii->numcores; -} - -/* scan the sb enumerated space to identify all cores */ -void -sb_scan(si_t *sih, void *regs, uint devid) -{ - uint32 origsba; - sbconfig_t *sb; - si_info_t *sii = SI_INFO(sih); - - sb = REGS2SB(sii->curmap); - - sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; - - /* Save the current core info and validate it later till we know - * for sure what is good and what is bad. - */ - origsba = _sb_coresba(sii); - - /* scan all SB(s) starting from SI_ENUM_BASE */ - sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1); -} - -/* - * 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 * -sb_setcoreidx(si_t *sih, uint coreidx) -{ - si_info_t *sii = SI_INFO(sih); - - if (coreidx >= sii->numcores) - return (NULL); - - /* - * If the user has provided an interrupt mask enabled function, - * then assert interrupts are disabled before switching the core. - */ - ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); - - sii->curmap = _sb_setcoreidx(sii, coreidx); - sii->curidx = coreidx; - - return (sii->curmap); -} - -/* This function changes the logical "focus" to the indicated core. - * Return the current core's virtual address. - */ -static void * -_sb_setcoreidx(si_info_t *sii, uint coreidx) -{ - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 sbaddr = cores_info->coresba[coreidx]; - void *regs; - - switch (BUSTYPE(sii->pub.bustype)) { - case SI_BUS: - /* map new one */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - regs = cores_info->regs[coreidx]; - break; - - case PCI_BUS: - /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr); - regs = sii->curmap; - break; - - case PCMCIA_BUS: { - uint8 tmp = (sbaddr >> 12) & 0x0f; - OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); - tmp = (sbaddr >> 16) & 0xff; - OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); - tmp = (sbaddr >> 24) & 0xff; - OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); - regs = sii->curmap; - break; - } - case SPI_BUS: - case SDIO_BUS: - /* map new one */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = (void *)(uintptr)sbaddr; - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - regs = cores_info->regs[coreidx]; - break; - - - default: - ASSERT(0); - regs = NULL; - break; - } - - return regs; -} - -/* Return the address of sbadmatch0/1/2/3 register */ -static volatile uint32 * -sb_admatch(si_info_t *sii, uint asidx) -{ - sbconfig_t *sb; - volatile uint32 *addrm; - - sb = REGS2SB(sii->curmap); - - switch (asidx) { - case 0: - addrm = &sb->sbadmatch0; - break; - - case 1: - addrm = &sb->sbadmatch1; - break; - - case 2: - addrm = &sb->sbadmatch2; - break; - - case 3: - addrm = &sb->sbadmatch3; - break; - - default: - SI_ERROR(("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx)); - return 0; - } - - return (addrm); -} - -/* Return the number of address spaces in current core */ -int -sb_numaddrspaces(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - sb = REGS2SB(sii->curmap); - - /* + 1 because of enumeration space */ - return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1; -} - -/* Return the address of the nth address space in the current core */ -uint32 -sb_addrspace(si_t *sih, uint asidx) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - - return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx)))); -} - -/* Return the size of the nth address space in the current core */ -uint32 -sb_addrspacesize(si_t *sih, uint asidx) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - - return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx)))); -} - - -/* do buffered registers update */ -void -sb_commit(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - - origidx = sii->curidx; - ASSERT(GOODIDX(origidx)); - - INTR_OFF(sii, intr_val); - - /* switch over to chipcommon core if there is one, else use pci */ - if (sii->pub.ccrev != NOREV) { - chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - ASSERT(ccregs != NULL); - - /* do the buffer registers update */ - W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT); - W_REG(sii->osh, &ccregs->broadcastdata, 0x0); - } else - ASSERT(0); - - /* restore core index */ - sb_setcoreidx(sih, origidx); - INTR_RESTORE(sii, intr_val); -} - -void -sb_core_disable(si_t *sih, uint32 bits) -{ - si_info_t *sii; - volatile uint32 dummy; - sbconfig_t *sb; - - sii = SI_INFO(sih); - - ASSERT(GOODREGS(sii->curmap)); - sb = REGS2SB(sii->curmap); - - /* if core is already in reset, just return */ - if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET) - return; - - /* if clocks are not enabled, put into reset and return */ - if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0) - goto disable; - - /* set target reject and spin until busy is clear (preserve core-specific bits) */ - OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000); - if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY) - SI_ERROR(("%s: target state still busy\n", __FUNCTION__)); - - if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) { - OR_SBREG(sii, &sb->sbimstate, SBIM_RJ); - dummy = R_SBREG(sii, &sb->sbimstate); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000); - } - - /* set reset and reject while enabling the clocks */ - W_SBREG(sii, &sb->sbtmstatelow, - (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | - SBTML_REJ | SBTML_RESET)); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(10); - - /* don't forget to clear the initiator reject bit */ - if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) - AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ); - -disable: - /* leave reset and reject asserted */ - W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET)); - OSL_DELAY(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 -sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) -{ - si_info_t *sii; - sbconfig_t *sb; - volatile uint32 dummy; - - sii = SI_INFO(sih); - ASSERT(GOODREGS(sii->curmap)); - sb = REGS2SB(sii->curmap); - - /* - * Must do the disable sequence first to work for arbitrary current core state. - */ - sb_core_disable(sih, (bits | resetbits)); - - /* - * Now do the initialization sequence. - */ - - /* set reset while enabling the clock and forcing them on throughout the core */ - W_SBREG(sii, &sb->sbtmstatelow, - (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | - SBTML_RESET)); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - - if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) { - W_SBREG(sii, &sb->sbtmstatehigh, 0); - } - if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) { - AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); - } - - /* clear reset and allow it to propagate throughout the core */ - W_SBREG(sii, &sb->sbtmstatelow, - ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - - /* leave clock enabled */ - W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); - dummy = R_SBREG(sii, &sb->sbtmstatelow); - BCM_REFERENCE(dummy); - OSL_DELAY(1); -} - -/* - * Set the initiator timeout for the "master core". - * The master core is defined to be the core in control - * of the chip and so it issues accesses to non-memory - * locations (Because of dma *any* core can access memeory). - * - * The routine uses the bus to decide who is the master: - * SI_BUS => mips - * JTAG_BUS => chipc - * PCI_BUS => pci or pcie - * PCMCIA_BUS => pcmcia - * SDIO_BUS => pcmcia - * - * This routine exists so callers can disable initiator - * timeouts so accesses to very slow devices like otp - * won't cause an abort. The routine allows arbitrary - * settings of the service and request timeouts, though. - * - * Returns the timeout state before changing it or -1 - * on error. - */ - -#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK) - -uint32 -sb_set_initiator_to(si_t *sih, uint32 to, uint idx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - uint32 tmp, ret = 0xffffffff; - sbconfig_t *sb; - - - if ((to & ~TO_MASK) != 0) - return ret; - - /* Figure out the master core */ - if (idx == BADIDX) { - switch (BUSTYPE(sii->pub.bustype)) { - case PCI_BUS: - idx = sii->pub.buscoreidx; - break; - case JTAG_BUS: - idx = SI_CC_IDX; - break; - case PCMCIA_BUS: - case SDIO_BUS: - idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0); - break; - case SI_BUS: - idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0); - break; - default: - ASSERT(0); - } - if (idx == BADIDX) - return ret; - } - - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - sb = REGS2SB(sb_setcoreidx(sih, idx)); - - tmp = R_SBREG(sii, &sb->sbimconfiglow); - ret = tmp & TO_MASK; - W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to); - - sb_commit(sih); - sb_setcoreidx(sih, origidx); - INTR_RESTORE(sii, intr_val); - return ret; -} - -uint32 -sb_base(uint32 admatch) -{ - uint32 base; - uint type; - - type = admatch & SBAM_TYPE_MASK; - ASSERT(type < 3); - - base = 0; - - if (type == 0) { - base = admatch & SBAM_BASE0_MASK; - } else if (type == 1) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - base = admatch & SBAM_BASE1_MASK; - } else if (type == 2) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - base = admatch & SBAM_BASE2_MASK; - } - - return (base); -} - -uint32 -sb_size(uint32 admatch) -{ - uint32 size; - uint type; - - type = admatch & SBAM_TYPE_MASK; - ASSERT(type < 3); - - size = 0; - - if (type == 0) { - size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); - } else if (type == 1) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1); - } else if (type == 2) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1); - } - - return (size); -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/siutils.c b/drivers/net/wireless/bcmdhd_suzuran/siutils.c deleted file mode 100755 index bf91a266e74b..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/siutils.c +++ /dev/null @@ -1,2840 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: siutils.c 527126 2015-01-16 03:33:51Z $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef BCM_SDRBL -#include -#endif /* BCM_SDRBL */ - -#include "siutils_priv.h" - -/* local prototypes */ -static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, - uint bustype, void *sdh, char **vars, uint *varsz); -static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); -static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, - uint *origidx, void *regs); - - - -/* global variable to indicate reservation/release of gpio's */ -static uint32 si_gpioreservation = 0; - -/* global flag to prevent shared resources from being initialized multiple times in si_attach() */ - -int do_4360_pcie2_war = 0; - -/* global kernel resource */ -static si_info_t ksii; -static si_cores_info_t ksii_cores_info; - -/** - * Allocate an si handle. This function may be called multiple times. - * - * devid - pci device id (used to determine chip#) - * osh - opaque OS handle - * regs - virtual address of initial core registers - * bustype - pci/pcmcia/sb/sdio/etc - * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this - * function set 'vars' to NULL, making dereferencing of this parameter undesired. - * varsz - pointer to int to return the size of the vars - */ -si_t * -si_attach(uint devid, osl_t *osh, void *regs, - uint bustype, void *sdh, char **vars, uint *varsz) -{ - si_info_t *sii; - si_cores_info_t *cores_info; - /* alloc si_info_t */ - if ((sii = MALLOCZ(osh, sizeof (si_info_t))) == NULL) { - SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); - return (NULL); - } - - /* alloc si_cores_info_t */ - if ((cores_info = (si_cores_info_t *)MALLOCZ(osh, sizeof (si_cores_info_t))) == NULL) { - SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); - MFREE(osh, sii, sizeof(si_info_t)); - return (NULL); - } - sii->cores_info = cores_info; - - if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { - MFREE(osh, sii, sizeof(si_info_t)); - MFREE(osh, cores_info, sizeof(si_cores_info_t)); - return (NULL); - } - sii->vars = vars ? *vars : NULL; - sii->varsz = varsz ? *varsz : 0; - - return (si_t *)sii; -} - - -static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */ - -/** generic kernel variant of si_attach() */ -si_t * -si_kattach(osl_t *osh) -{ - static bool ksii_attached = FALSE; - si_cores_info_t *cores_info; - - if (!ksii_attached) { - void *regs = NULL; - regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); - cores_info = (si_cores_info_t *)&ksii_cores_info; - ksii.cores_info = cores_info; - - ASSERT(osh); - if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, - SI_BUS, NULL, - osh != SI_OSH ? &(ksii.vars) : NULL, - osh != SI_OSH ? &(ksii.varsz) : NULL) == NULL) { - SI_ERROR(("si_kattach: si_doattach failed\n")); - REG_UNMAP(regs); - return NULL; - } - REG_UNMAP(regs); - - /* save ticks normalized to ms for si_watchdog_ms() */ - if (PMUCTL_ENAB(&ksii.pub)) { - /* based on 32KHz ILP clock */ - wd_msticks = 32; - } else { - wd_msticks = ALP_CLOCK / 1000; - } - - ksii_attached = TRUE; - SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n", - ksii.pub.ccrev, wd_msticks)); - } - - return &ksii.pub; -} - - -static bool -si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) -{ - /* need to set memseg flag for CF card first before any sb registers access */ - if (BUSTYPE(bustype) == PCMCIA_BUS) - sii->memseg = TRUE; - - - if (BUSTYPE(bustype) == SDIO_BUS) { - int err; - uint8 clkset; - - /* Try forcing SDIO core to do ALPAvail request only */ - clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); - if (!err) { - uint8 clkval; - - /* If register supported, wait for ALPAvail and then force ALP */ - clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); - if ((clkval & ~SBSDIO_AVBITS) == clkset) { - SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), - PMU_MAX_TRANSITION_DLY); - if (!SBSDIO_ALPAV(clkval)) { - SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", - clkval)); - return FALSE; - } - clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - clkset, &err); - OSL_DELAY(65); - } - } - - /* Also, disable the extra SDIO pull-ups */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); - } - - - return TRUE; -} - -static bool -si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, - uint *origidx, void *regs) -{ - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - bool pci, pcie, pcie_gen2 = FALSE; - uint i; - uint pciidx, pcieidx, pcirev, pcierev; - - cc = si_setcoreidx(&sii->pub, SI_CC_IDX); - ASSERT((uintptr)cc); - - /* get chipcommon rev */ - sii->pub.ccrev = (int)si_corerev(&sii->pub); - - /* get chipcommon chipstatus */ - if (sii->pub.ccrev >= 11) - sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); - - /* get chipcommon capabilites */ - sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); - /* get chipcommon extended capabilities */ - - if (sii->pub.ccrev >= 35) - sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); - - /* get pmu rev and caps */ - if (sii->pub.cccaps & CC_CAP_PMU) { - sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); - sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; - } - - SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", - sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, - sii->pub.pmucaps)); - - /* figure out bus/orignal core idx */ - sii->pub.buscoretype = NODEV_CORE_ID; - sii->pub.buscorerev = (uint)NOREV; - sii->pub.buscoreidx = BADIDX; - - pci = pcie = FALSE; - pcirev = pcierev = (uint)NOREV; - pciidx = pcieidx = BADIDX; - - for (i = 0; i < sii->numcores; i++) { - uint cid, crev; - - si_setcoreidx(&sii->pub, i); - cid = si_coreid(&sii->pub); - crev = si_corerev(&sii->pub); - - /* Display cores found */ - SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", - i, cid, crev, cores_info->coresba[i], cores_info->regs[i])); - - if (BUSTYPE(bustype) == SI_BUS) { - /* now look at the chipstatus register to figure the pacakge */ - /* for SDIO but downloaded on PCIE dev */ - if (cid == PCIE2_CORE_ID) { - if ((CHIPID(sii->pub.chip) == BCM43602_CHIP_ID) || - ((CHIPID(sii->pub.chip) == BCM4345_CHIP_ID || - CHIPID(sii->pub.chip) == BCM43454_CHIP_ID) && - CST4345_CHIPMODE_PCIE(sii->pub.chipst))) { - pcieidx = i; - pcierev = crev; - pcie = TRUE; - pcie_gen2 = TRUE; - } - } - - } - else if (BUSTYPE(bustype) == PCI_BUS) { - if (cid == PCI_CORE_ID) { - pciidx = i; - pcirev = crev; - pci = TRUE; - } else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) { - pcieidx = i; - pcierev = crev; - pcie = TRUE; - if (cid == PCIE2_CORE_ID) - pcie_gen2 = TRUE; - } - } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && - (cid == PCMCIA_CORE_ID)) { - sii->pub.buscorerev = crev; - sii->pub.buscoretype = cid; - sii->pub.buscoreidx = i; - } - else if (((BUSTYPE(bustype) == SDIO_BUS) || - (BUSTYPE(bustype) == SPI_BUS)) && - ((cid == PCMCIA_CORE_ID) || - (cid == SDIOD_CORE_ID))) { - sii->pub.buscorerev = crev; - sii->pub.buscoretype = cid; - sii->pub.buscoreidx = i; - } - - /* find the core idx before entering this func. */ - if ((savewin && (savewin == cores_info->coresba[i])) || - (regs == cores_info->regs[i])) - *origidx = i; - } - -#if defined(PCIE_FULL_DONGLE) - pci = FALSE; -#endif - if (pci) { - sii->pub.buscoretype = PCI_CORE_ID; - sii->pub.buscorerev = pcirev; - sii->pub.buscoreidx = pciidx; - } else if (pcie) { - if (pcie_gen2) - sii->pub.buscoretype = PCIE2_CORE_ID; - else - sii->pub.buscoretype = PCIE_CORE_ID; - sii->pub.buscorerev = pcierev; - sii->pub.buscoreidx = pcieidx; - } - - SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, - sii->pub.buscorerev)); - - if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && - (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3)) - OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); - - - /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was - * already running. - */ - if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { - if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || - si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) - si_core_disable(&sii->pub, 0); - } - - /* return to the original core */ - si_setcoreidx(&sii->pub, *origidx); - - return TRUE; -} - - - - -/** - * Allocate an si handle. This function may be called multiple times. - * - * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this - * function set 'vars' to NULL. - */ -static si_info_t * -si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, - uint bustype, void *sdh, char **vars, uint *varsz) -{ - struct si_pub *sih = &sii->pub; - uint32 w, savewin; - chipcregs_t *cc; - char *pvars = NULL; - uint origidx; -#if !defined(_CFEZ_) || defined(CFG_WL) -#endif - - ASSERT(GOODREGS(regs)); - - savewin = 0; - - sih->buscoreidx = BADIDX; - - sii->curmap = regs; - sii->sdh = sdh; - sii->osh = osh; - - - /* check to see if we are a si core mimic'ing a pci core */ - if ((bustype == PCI_BUS) && - (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(uint32)) == 0xffffffff)) { - SI_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SI " - "devid:0x%x\n", __FUNCTION__, devid)); - bustype = SI_BUS; - } - - /* find Chipcommon address */ - if (bustype == PCI_BUS) { - savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); - if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) - savewin = SI_ENUM_BASE; - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); - if (!regs) - return NULL; - cc = (chipcregs_t *)regs; - } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { - cc = (chipcregs_t *)sii->curmap; - } else { - cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); - } - - sih->bustype = bustype; -#ifdef BCMBUSTYPE - if (bustype != BUSTYPE(bustype)) { - SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", - bustype, BUSTYPE(bustype))); - return NULL; - } -#endif - /* bus/core/clk setup for register access */ - if (!si_buscore_prep(sii, bustype, devid, sdh)) { - SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); - 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. - */ - if (!cc) { - SI_ERROR(("%s: chipcommon register space is null \n", __FUNCTION__)); - return NULL; - } - w = R_REG(osh, &cc->chipid); - if ((w & 0xfffff) == 148277) w -= 65532; - sih->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; - - if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && - (sih->chippkg != BCM4329_289PIN_PKG_ID)) { - sih->chippkg = BCM4329_182PIN_PKG_ID; - } - sih->issim = IS_SIM(sih->chippkg); - - /* scan for cores */ - if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { - SI_MSG(("Found chip type SB (0x%08x)\n", w)); - sb_scan(&sii->pub, regs, devid); - } else if ((CHIPTYPE(sii->pub.socitype) == SOCI_AI) || - (CHIPTYPE(sii->pub.socitype) == SOCI_NAI)) { - if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) - SI_MSG(("Found chip type AI (0x%08x)\n", w)); - else - SI_MSG(("Found chip type NAI (0x%08x)\n", w)); - /* pass chipc address instead of original core base */ - ai_scan(&sii->pub, (void *)(uintptr)cc, devid); - } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { - SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip)); - /* pass chipc address instead of original core base */ - ub_scan(&sii->pub, (void *)(uintptr)cc, devid); - } else { - SI_ERROR(("Found chip of unknown type (0x%08x)\n", w)); - return NULL; - } - /* no cores found, bail out */ - if (sii->numcores == 0) { - SI_ERROR(("si_doattach: could not find any cores\n")); - return NULL; - } - /* bus/core/clk setup */ - origidx = SI_CC_IDX; - if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { - SI_ERROR(("si_doattach: si_buscore_setup failed\n")); - goto exit; - } - -#if !defined(_CFEZ_) || defined(CFG_WL) - if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) - >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | - CST4322_SPROM_PRESENT))) { - SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__)); - return NULL; - } - - /* assume current core is CC */ - if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || - CHIPID(sih->chip) == BCM43235_CHIP_ID || - CHIPID(sih->chip) == BCM43234_CHIP_ID || - CHIPID(sih->chip) == BCM43238_CHIP_ID) && - (CHIPREV(sii->pub.chiprev) <= 2))) { - - if ((cc->chipstatus & CST43236_BP_CLK) != 0) { - uint clkdiv; - clkdiv = R_REG(osh, &cc->clkdiv); - /* otp_clk_div is even number, 120/14 < 9mhz */ - clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); - W_REG(osh, &cc->clkdiv, clkdiv); - SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv)); - } - OSL_DELAY(10); - } - - if (bustype == PCI_BUS) { - - } -#endif -#ifdef BCM_SDRBL - /* 4360 rom bootloader in PCIE case, if the SDR is enabled, But preotection is - * not turned on, then we want to hold arm in reset. - * Bottomline: In sdrenable case, we allow arm to boot only when protection is - * turned on. - */ - if (CHIP_HOSTIF_PCIE(&(sii->pub))) { - uint32 sflags = si_arm_sflags(&(sii->pub)); - - /* If SDR is enabled but protection is not turned on - * then we want to force arm to WFI. - */ - if ((sflags & (SISF_SDRENABLE | SISF_TCMPROT)) == SISF_SDRENABLE) { - disable_arm_irq(); - while (1) { - hnd_cpu_wait(sih); - } - } - } -#endif /* BCM_SDRBL */ - - pvars = NULL; - BCM_REFERENCE(pvars); - - - - if (sii->pub.ccrev >= 20) { - uint32 gpiopullup = 0, gpiopulldown = 0; - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - ASSERT(cc != NULL); - - /* 4314/43142 has pin muxing, don't clear gpio bits */ - if ((CHIPID(sih->chip) == BCM4314_CHIP_ID) || - (CHIPID(sih->chip) == BCM43142_CHIP_ID)) { - gpiopullup |= 0x402e0; - gpiopulldown |= 0x20500; - } - - W_REG(osh, &cc->gpiopullup, gpiopullup); - W_REG(osh, &cc->gpiopulldown, gpiopulldown); - si_setcoreidx(sih, origidx); - } - - - /* clear any previous epidiag-induced target abort */ - ASSERT(!si_taclear(sih, FALSE)); - - - return (sii); - -exit: - - return NULL; -} - -/** may be called with core in reset */ -void -si_detach(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint idx; - - - if (BUSTYPE(sih->bustype) == SI_BUS) - for (idx = 0; idx < SI_MAXCORES; idx++) - if (cores_info->regs[idx]) { - REG_UNMAP(cores_info->regs[idx]); - cores_info->regs[idx] = NULL; - } - - -#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) - if (cores_info != &ksii_cores_info) -#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ - MFREE(sii->osh, cores_info, sizeof(si_cores_info_t)); - -#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) - if (sii != &ksii) -#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ - MFREE(sii->osh, sii, sizeof(si_info_t)); -} - -void * -si_osh(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - return sii->osh; -} - -void -si_setosh(si_t *sih, osl_t *osh) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - if (sii->osh != NULL) { - SI_ERROR(("osh is already set....\n")); - ASSERT(!sii->osh); - } - sii->osh = osh; -} - -/** register driver interrupt disabling and restoring callback functions */ -void -si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, - void *intrsenabled_fn, void *intr_arg) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - sii->intr_arg = intr_arg; - sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn; - sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn; - sii->intrsenabled_fn = (si_intrsenabled_t)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 = cores_info->coreid[sii->curidx]; -} - -void -si_deregister_intr_callback(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - sii->intrsoff_fn = NULL; -} - -uint -si_intflag(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_intflag(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return R_REG(sii->osh, ((uint32 *)(uintptr) - (sii->oob_router + OOB_STATUSA))); - else { - ASSERT(0); - return 0; - } -} - -uint -si_flag(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_flag(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_flag(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_flag(sih); - else { - ASSERT(0); - return 0; - } -} - -uint -si_flag_alt(si_t *sih) -{ - if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_flag_alt(sih); - else { - ASSERT(0); - return 0; - } -} - -void -si_setint(si_t *sih, int siflag) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - sb_setint(sih, siflag); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_setint(sih, siflag); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - ub_setint(sih, siflag); - else - ASSERT(0); -} - -uint -si_coreid(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - return cores_info->coreid[sii->curidx]; -} - -uint -si_coreidx(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - return sii->curidx; -} - -/** return the core-type instantiation # of the current core */ -uint -si_coreunit(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint idx; - uint coreid; - uint coreunit; - uint i; - - coreunit = 0; - - idx = sii->curidx; - - ASSERT(GOODREGS(sii->curmap)); - coreid = si_coreid(sih); - - /* count the cores of our type */ - for (i = 0; i < idx; i++) - if (cores_info->coreid[i] == coreid) - coreunit++; - - return (coreunit); -} - -uint -si_corevendor(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_corevendor(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_corevendor(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_corevendor(sih); - else { - ASSERT(0); - return 0; - } -} - -bool -si_backplane64(si_t *sih) -{ - return ((sih->cccaps & CC_CAP_BKPLN64) != 0); -} - -uint -si_corerev(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_corerev(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_corerev(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_corerev(sih); - else { - ASSERT(0); - return 0; - } -} - -/** return index of coreid or BADIDX if not found */ -uint -si_findcoreidx(si_t *sih, uint coreid, uint coreunit) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint found; - uint i; - - - found = 0; - - for (i = 0; i < sii->numcores; i++) - if (cores_info->coreid[i] == coreid) { - if (found == coreunit) - return (i); - found++; - } - - return (BADIDX); -} - -/** return total coreunit of coreid or zero if not found */ -uint -si_numcoreunits(si_t *sih, uint coreid) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint found; - uint i; - - found = 0; - - for (i = 0; i < sii->numcores; i++) - if (cores_info->coreid[i] == coreid) { - found++; - } - - return (found == 0? 0:found); -} - -/** return list of found cores */ -uint -si_corelist(si_t *sih, uint coreid[]) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - bcopy((uchar*)cores_info->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); - return (sii->numcores); -} - -/** return current wrapper mapping */ -void * -si_wrapperregs(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - ASSERT(GOODREGS(sii->curwrap)); - - return (sii->curwrap); -} - -/** return current register mapping */ -void * -si_coreregs(si_t *sih) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - ASSERT(GOODREGS(sii->curmap)); - - return (sii->curmap); -} - -/** - * 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 * -si_setcore(si_t *sih, uint coreid, uint coreunit) -{ - uint idx; - - idx = si_findcoreidx(sih, coreid, coreunit); - if (!GOODIDX(idx)) - return (NULL); - - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_setcoreidx(sih, idx); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_setcoreidx(sih, idx); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_setcoreidx(sih, idx); - else { - ASSERT(0); - return NULL; - } -} - -void * -si_setcoreidx(si_t *sih, uint coreidx) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_setcoreidx(sih, coreidx); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_setcoreidx(sih, coreidx); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_setcoreidx(sih, coreidx); - else { - ASSERT(0); - return NULL; - } -} - -/** Turn off interrupt as required by sb_setcore, before switch core */ -void * -si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) -{ - void *cc; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - 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 (void *)CCREGS_FAST(sii); - else if (coreid == sih->buscoretype) - return (void *)PCIEREGS(sii); - } - INTR_OFF(sii, *intr_val); - *origidx = sii->curidx; - cc = si_setcore(sih, coreid, 0); - ASSERT(cc != NULL); - - return cc; -} - -/* restore coreidx and restore interrupt */ -void -si_restore_core(si_t *sih, uint coreid, uint intr_val) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) - return; - - si_setcoreidx(sih, coreid); - INTR_RESTORE(sii, intr_val); -} - -int -si_numaddrspaces(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_numaddrspaces(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_numaddrspaces(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_numaddrspaces(sih); - else { - ASSERT(0); - return 0; - } -} - -uint32 -si_addrspace(si_t *sih, uint asidx) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_addrspace(sih, asidx); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_addrspace(sih, asidx); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_addrspace(sih, asidx); - else { - ASSERT(0); - return 0; - } -} - -uint32 -si_addrspacesize(si_t *sih, uint asidx) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_addrspacesize(sih, asidx); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_addrspacesize(sih, asidx); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_addrspacesize(sih, asidx); - else { - ASSERT(0); - return 0; - } -} - -void -si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) -{ - /* Only supported for SOCI_AI */ - if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_coreaddrspaceX(sih, asidx, addr, size); - else - *size = 0; -} - -uint32 -si_core_cflags(si_t *sih, uint32 mask, uint32 val) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_core_cflags(sih, mask, val); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_core_cflags(sih, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_core_cflags(sih, mask, val); - else { - ASSERT(0); - return 0; - } -} - -void -si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - sb_core_cflags_wo(sih, mask, val); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_core_cflags_wo(sih, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - ub_core_cflags_wo(sih, mask, val); - else - ASSERT(0); -} - -uint32 -si_core_sflags(si_t *sih, uint32 mask, uint32 val) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_core_sflags(sih, mask, val); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_core_sflags(sih, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_core_sflags(sih, mask, val); - else { - ASSERT(0); - return 0; - } -} - -bool -si_iscoreup(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_iscoreup(sih); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_iscoreup(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_iscoreup(sih); - else { - ASSERT(0); - return FALSE; - } -} - -uint -si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) -{ - /* only for AI back plane chips */ - if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return (ai_wrap_reg(sih, offset, mask, val)); - return 0; -} - -uint -si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_corereg(sih, coreidx, regoff, mask, val); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_corereg(sih, coreidx, regoff, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - return ub_corereg(sih, coreidx, regoff, mask, val); - else { - ASSERT(0); - return 0; - } -} - -/* - * If there is no need for fiddling with interrupts or core switches (typically silicon - * back plane registers, pci registers and chipcommon registers), this function - * returns the register offset on this core to a mapped address. This address can - * be used for W_REG/R_REG directly. - * - * For accessing registers that would need a core switch, this function will return - * NULL. - */ -uint32 * -si_corereg_addr(si_t *sih, uint coreidx, uint regoff) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - return sb_corereg_addr(sih, coreidx, regoff); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - return ai_corereg_addr(sih, coreidx, regoff); - else { - return 0; - } -} - -void -si_core_disable(si_t *sih, uint32 bits) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - sb_core_disable(sih, bits); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_core_disable(sih, bits); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - ub_core_disable(sih, bits); -} - -void -si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - sb_core_reset(sih, bits, resetbits); - else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) - ai_core_reset(sih, bits, resetbits); - else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) - ub_core_reset(sih, bits, resetbits); -} - -/** Run bist on current core. Caller needs to take care of core-specific bist hazards */ -int -si_corebist(si_t *sih) -{ - uint32 cflags; - int result = 0; - - /* Read core control flags */ - cflags = si_core_cflags(sih, 0, 0); - - /* Set bist & fgc */ - si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); - - /* Wait for bist done */ - SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); - - if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) - result = BCME_ERROR; - - /* Reset core control flags */ - si_core_cflags(sih, 0xffff, cflags); - - return result; -} - -static uint32 -factor6(uint32 x) -{ - switch (x) { - case CC_F6_2: return 2; - case CC_F6_3: return 3; - case CC_F6_4: return 4; - case CC_F6_5: return 5; - case CC_F6_6: return 6; - case CC_F6_7: return 7; - default: return 0; - } -} - -/** calculate the speed the SI would run at given a set of clockcontrol values */ -uint32 -si_clock_rate(uint32 pll_type, uint32 n, uint32 m) -{ - uint32 n1, n2, clock, m1, m2, m3, mc; - - n1 = n & CN_N1_MASK; - n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; - - if (pll_type == PLL_TYPE6) { - if (m & CC_T6_MMASK) - return CC_T6_M1; - else - return CC_T6_M0; - } else if ((pll_type == PLL_TYPE1) || - (pll_type == PLL_TYPE3) || - (pll_type == PLL_TYPE4) || - (pll_type == PLL_TYPE7)) { - n1 = factor6(n1); - n2 += CC_F5_BIAS; - } else if (pll_type == PLL_TYPE2) { - n1 += CC_T2_BIAS; - n2 += CC_T2_BIAS; - ASSERT((n1 >= 2) && (n1 <= 7)); - ASSERT((n2 >= 5) && (n2 <= 23)); - } else if (pll_type == PLL_TYPE5) { - return (100000000); - } else - ASSERT(0); - /* PLL types 3 and 7 use BASE2 (25Mhz) */ - if ((pll_type == PLL_TYPE3) || - (pll_type == PLL_TYPE7)) { - clock = CC_CLOCK_BASE2 * n1 * n2; - } else - clock = CC_CLOCK_BASE1 * n1 * n2; - - if (clock == 0) - return 0; - - m1 = m & CC_M1_MASK; - m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; - m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; - mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; - - if ((pll_type == PLL_TYPE1) || - (pll_type == PLL_TYPE3) || - (pll_type == PLL_TYPE4) || - (pll_type == PLL_TYPE7)) { - m1 = factor6(m1); - if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) - m2 += CC_F5_BIAS; - else - m2 = factor6(m2); - m3 = factor6(m3); - - switch (mc) { - case CC_MC_BYPASS: return (clock); - case CC_MC_M1: return (clock / m1); - case CC_MC_M1M2: return (clock / (m1 * m2)); - case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3)); - case CC_MC_M1M3: return (clock / (m1 * m3)); - default: return (0); - } - } else { - ASSERT(pll_type == PLL_TYPE2); - - m1 += CC_T2_BIAS; - m2 += CC_T2M2_BIAS; - m3 += CC_T2_BIAS; - ASSERT((m1 >= 2) && (m1 <= 7)); - ASSERT((m2 >= 3) && (m2 <= 10)); - ASSERT((m3 >= 2) && (m3 <= 7)); - - if ((mc & CC_T2MC_M1BYP) == 0) - clock /= m1; - if ((mc & CC_T2MC_M2BYP) == 0) - clock /= m2; - if ((mc & CC_T2MC_M3BYP) == 0) - clock /= m3; - - return (clock); - } -} - -/** - * Some chips could have multiple host interfaces, however only one will be active. - * For a given chip. Depending pkgopt and cc_chipst return the active host interface. - */ -uint -si_chip_hostif(si_t *sih) -{ - uint hosti = 0; - - switch (CHIPID(sih->chip)) { - - case BCM43602_CHIP_ID: - hosti = CHIP_HOSTIF_PCIEMODE; - break; - - case BCM4360_CHIP_ID: - /* chippkg bit-0 == 0 is PCIE only pkgs - * chippkg bit-0 == 1 has both PCIE and USB cores enabled - */ - if ((sih->chippkg & 0x1) && (sih->chipst & CST4360_MODE_USB)) - hosti = CHIP_HOSTIF_USBMODE; - else - hosti = CHIP_HOSTIF_PCIEMODE; - - break; - - case BCM4335_CHIP_ID: - /* TBD: like in 4360, do we need to check pkg? */ - if (CST4335_CHIPMODE_USB20D(sih->chipst)) - hosti = CHIP_HOSTIF_USBMODE; - else if (CST4335_CHIPMODE_SDIOD(sih->chipst)) - hosti = CHIP_HOSTIF_SDIOMODE; - else - hosti = CHIP_HOSTIF_PCIEMODE; - break; - - case BCM4345_CHIP_ID: - case BCM43454_CHIP_ID: - if (CST4345_CHIPMODE_USB20D(sih->chipst) || CST4345_CHIPMODE_HSIC(sih->chipst)) - hosti = CHIP_HOSTIF_USBMODE; - else if (CST4345_CHIPMODE_SDIOD(sih->chipst)) - hosti = CHIP_HOSTIF_SDIOMODE; - else if (CST4345_CHIPMODE_PCIE(sih->chipst)) - hosti = CHIP_HOSTIF_PCIEMODE; - break; - - - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM4356_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43569_CHIP_ID: - if (CST4350_CHIPMODE_USB20D(sih->chipst) || - CST4350_CHIPMODE_HSIC20D(sih->chipst) || - CST4350_CHIPMODE_USB30D(sih->chipst) || - CST4350_CHIPMODE_USB30D_WL(sih->chipst) || - CST4350_CHIPMODE_HSIC30D(sih->chipst)) - hosti = CHIP_HOSTIF_USBMODE; - else if (CST4350_CHIPMODE_SDIOD(sih->chipst)) - hosti = CHIP_HOSTIF_SDIOMODE; - else if (CST4350_CHIPMODE_PCIE(sih->chipst)) - hosti = CHIP_HOSTIF_PCIEMODE; - break; - - default: - break; - } - - return hosti; -} - - -/** set chip watchdog reset timer to fire in 'ticks' */ -void -si_watchdog(si_t *sih, uint ticks) -{ - uint nb, maxt; - - if (PMUCTL_ENAB(sih)) { - -#if !defined(_CFEZ_) || defined(CFG_WL) - if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && - (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { - si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); - si_setcore(sih, USB20D_CORE_ID, 0); - si_core_disable(sih, 1); - si_setcore(sih, CC_CORE_ID, 0); - } -#endif - - nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); - /* The mips compiler uses the sllv instruction, - * so we specially handle the 32-bit case. - */ - if (nb == 32) - maxt = 0xffffffff; - else - maxt = ((1 << nb) - 1); - - if (ticks == 1) - ticks = 2; - else if (ticks > maxt) - ticks = maxt; - - si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks); - } else { - maxt = (1 << 28) - 1; - if (ticks > maxt) - ticks = maxt; - - si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); - } -} - -/** trigger watchdog reset after ms milliseconds */ -void -si_watchdog_ms(si_t *sih, uint32 ms) -{ - si_watchdog(sih, wd_msticks * ms); -} - -uint32 si_watchdog_msticks(void) -{ - return wd_msticks; -} - -bool -si_taclear(si_t *sih, bool details) -{ - return FALSE; -} - - - -/** return the slow clock source - LPO, XTAL, or PCI */ -static uint -si_slowclk_src(si_info_t *sii) -{ - chipcregs_t *cc; - - ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); - - if (sii->pub.ccrev < 6) { - if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && - (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) & - PCI_CFG_GPIO_SCS)) - return (SCC_SS_PCI); - else - return (SCC_SS_XTAL); - } else if (sii->pub.ccrev < 10) { - cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); - ASSERT(cc); - return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); - } else /* Insta-clock */ - return (SCC_SS_XTAL); -} - -/** return the ILP (slowclock) min or max frequency */ -static uint -si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) -{ - uint32 slowclk; - uint div; - - ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); - - /* shouldn't be here unless we've established the chip has dynamic clk control */ - ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); - - slowclk = si_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(sii->osh, &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 - ASSERT(0); - } else { - /* Chipc rev 10 is InstaClock */ - div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; - div = 4 * (div + 1); - return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); - } - return (0); -} - -static void -si_clkctl_setdelay(si_info_t *sii, void *chipcregs) -{ - chipcregs_t *cc = (chipcregs_t *)chipcregs; - 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 = si_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 = si_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(sii->osh, &cc->pll_on_delay, pll_on_delay); - W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); -} - -/** initialize power control delay registers */ -void -si_clkctl_init(si_t *sih) -{ - si_info_t *sii; - uint origidx = 0; - chipcregs_t *cc; - bool fast; - - if (!CCCTL_ENAB(sih)) - return; - - sii = SI_INFO(sih); - fast = SI_FAST(sii); - if (!fast) { - origidx = sii->curidx; - if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) - return; - } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) - return; - ASSERT(cc != NULL); - - /* set all Instaclk chip ILP to 1 MHz */ - if (sih->ccrev >= 10) - SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, - (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); - - si_clkctl_setdelay(sii, (void *)(uintptr)cc); - - OSL_DELAY(20000); - - if (!fast) - si_setcoreidx(sih, origidx); -} - - -/** change logical "focus" to the gpio core for optimized access */ -void * -si_gpiosetcore(si_t *sih) -{ - return (si_setcoreidx(sih, SI_CC_IDX)); -} - -/** - * mask & set gpiocontrol bits. - * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin. - * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated - * to some chip-specific purpose. - */ -uint32 -si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - regoff = 0; - - /* gpios could be shared on router platforms - * ignore reservation if it's high priority (e.g., test apps) - */ - if ((priority != GPIO_HI_PRIORITY) && - (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpiocontrol); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/** mask&set gpio output enable bits */ -uint32 -si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - regoff = 0; - - /* gpios could be shared on router platforms - * ignore reservation if it's high priority (e.g., test apps) - */ - if ((priority != GPIO_HI_PRIORITY) && - (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpioouten); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/** mask&set gpio output bits */ -uint32 -si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - regoff = 0; - - /* gpios could be shared on router platforms - * ignore reservation if it's high priority (e.g., test apps) - */ - if ((priority != GPIO_HI_PRIORITY) && - (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpioout); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/** reserve one gpio */ -uint32 -si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) -{ - /* only cores on SI_BUS share GPIO's and only applcation users need to - * reserve/release GPIO - */ - if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { - ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); - return 0xffffffff; - } - /* make sure only one bit is set */ - if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { - ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); - return 0xffffffff; - } - - /* already reserved */ - if (si_gpioreservation & gpio_bitmask) - return 0xffffffff; - /* set reservation */ - si_gpioreservation |= gpio_bitmask; - - return si_gpioreservation; -} - -/** - * release one gpio. - * - * releasing the gpio doesn't change the current value on the GPIO last write value - * persists till someone overwrites it. - */ -uint32 -si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) -{ - /* only cores on SI_BUS share GPIO's and only applcation users need to - * reserve/release GPIO - */ - if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { - ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); - return 0xffffffff; - } - /* make sure only one bit is set */ - if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { - ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); - return 0xffffffff; - } - - /* already released */ - if (!(si_gpioreservation & gpio_bitmask)) - return 0xffffffff; - - /* clear reservation */ - si_gpioreservation &= ~gpio_bitmask; - - return si_gpioreservation; -} - -/* return the current gpioin register value */ -uint32 -si_gpioin(si_t *sih) -{ - uint regoff; - - regoff = OFFSETOF(chipcregs_t, gpioin); - return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0)); -} - -/* mask&set gpio interrupt polarity bits */ -uint32 -si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - /* gpios could be shared on router platforms */ - if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpiointpolarity); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/* mask&set gpio interrupt mask bits */ -uint32 -si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) -{ - uint regoff; - - /* gpios could be shared on router platforms */ - if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { - mask = priority ? (si_gpioreservation & mask) : - ((si_gpioreservation | mask) & ~(si_gpioreservation)); - val &= mask; - } - - regoff = OFFSETOF(chipcregs_t, gpiointmask); - return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -} - -/* assign the gpio to an led */ -uint32 -si_gpioled(si_t *sih, uint32 mask, uint32 val) -{ - if (sih->ccrev < 16) - return 0xffffffff; - - /* gpio led powersave reg */ - return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); -} - -/* mask&set gpio timer val */ -uint32 -si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) -{ - if (sih->ccrev < 16) - return 0xffffffff; - - return (si_corereg(sih, SI_CC_IDX, - OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); -} - -uint32 -si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) -{ - uint offs; - - if (sih->ccrev < 20) - return 0xffffffff; - - offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); - return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); -} - -uint32 -si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) -{ - uint offs; - - if (sih->ccrev < 11) - return 0xffffffff; - - if (regtype == GPIO_REGEVT) - offs = OFFSETOF(chipcregs_t, gpioevent); - else if (regtype == GPIO_REGEVT_INTMSK) - offs = OFFSETOF(chipcregs_t, gpioeventintmask); - else if (regtype == GPIO_REGEVT_INTPOL) - offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); - else - return 0xffffffff; - - return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); -} - -void * -si_gpio_handler_register(si_t *sih, uint32 event, - bool level, gpio_handler_t cb, void *arg) -{ - si_info_t *sii = SI_INFO(sih); - gpioh_item_t *gi; - - ASSERT(event); - ASSERT(cb != NULL); - - if (sih->ccrev < 11) - return NULL; - - if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL) - return NULL; - - bzero(gi, sizeof(gpioh_item_t)); - gi->event = event; - gi->handler = cb; - gi->arg = arg; - gi->level = level; - - gi->next = sii->gpioh_head; - sii->gpioh_head = gi; - - return (void *)(gi); -} - -void -si_gpio_handler_unregister(si_t *sih, void *gpioh) -{ - si_info_t *sii = SI_INFO(sih); - gpioh_item_t *p, *n; - - if (sih->ccrev < 11) - return; - - ASSERT(sii->gpioh_head != NULL); - if ((void*)sii->gpioh_head == gpioh) { - sii->gpioh_head = sii->gpioh_head->next; - MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); - return; - } else { - p = sii->gpioh_head; - n = p->next; - while (n) { - if ((void*)n == gpioh) { - p->next = n->next; - MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); - return; - } - p = n; - n = n->next; - } - } - - ASSERT(0); /* Not found in list */ -} - -void -si_gpio_handler_process(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - gpioh_item_t *h; - uint32 level = si_gpioin(sih); - uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0); - uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); - uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0); - - for (h = sii->gpioh_head; h != NULL; h = h->next) { - if (h->handler) { - uint32 status = (h->level ? level : edge) & h->event; - uint32 polarity = (h->level ? levelp : edgep) & h->event; - - /* polarity bitval is opposite of status bitval */ - if (status ^ polarity) - h->handler(status, h->arg); - } - } - - si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ -} - -uint32 -si_gpio_int_enable(si_t *sih, bool enable) -{ - uint offs; - - if (sih->ccrev < 11) - return 0xffffffff; - - offs = OFFSETOF(chipcregs_t, intmask); - return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); -} - - -/** Return the size of the specified SOCRAM bank */ -static uint -socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) -{ - uint banksize, bankinfo; - uint bankidx = idx | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); - - ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); - - W_REG(sii->osh, ®s->bankidx, bankidx); - bankinfo = R_REG(sii->osh, ®s->bankinfo); - banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); - return banksize; -} - -void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - sbsocramregs_t *regs; - bool wasup; - uint corerev; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 16) { - W_REG(sii->osh, ®s->bankidx, bankidx); - W_REG(sii->osh, ®s->bankpda, bankpda); - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); -} - -void -si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect, uint8 *remap) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - sbsocramregs_t *regs; - bool wasup; - uint corerev; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - if (!set) - *enable = *protect = *remap = 0; - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 10) { - uint32 extcinfo; - uint8 nb; - uint8 i; - uint32 bankidx, bankinfo; - - extcinfo = R_REG(sii->osh, ®s->extracoreinfo); - nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); - for (i = 0; i < nb; i++) { - bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); - W_REG(sii->osh, ®s->bankidx, bankidx); - bankinfo = R_REG(sii->osh, ®s->bankinfo); - if (set) { - bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; - bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; - bankinfo &= ~SOCRAM_BANKINFO_DEVRAMREMAP_MASK; - if (*enable) { - bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); - if (*protect) - bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); - if ((corerev >= 16) && *remap) - bankinfo |= - (1 << SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT); - } - W_REG(sii->osh, ®s->bankinfo, bankinfo); - } - else if (i == 0) { - if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { - *enable = 1; - if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) - *protect = 1; - if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) - *remap = 1; - } - } - } - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); -} - -bool -si_socdevram_remap_isenb(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - sbsocramregs_t *regs; - bool wasup, remap = FALSE; - uint corerev; - uint32 extcinfo; - uint8 nb; - uint8 i; - uint32 bankidx, bankinfo; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 16) { - extcinfo = R_REG(sii->osh, ®s->extracoreinfo); - nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); - for (i = 0; i < nb; i++) { - bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); - W_REG(sii->osh, ®s->bankidx, bankidx); - bankinfo = R_REG(sii->osh, ®s->bankinfo); - if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { - remap = TRUE; - break; - } - } - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - return remap; -} - -bool -si_socdevram_pkg(si_t *sih) -{ - if (si_socdevram_size(sih) > 0) - return TRUE; - else - return FALSE; -} - -uint32 -si_socdevram_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - uint32 memsize = 0; - sbsocramregs_t *regs; - bool wasup; - uint corerev; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 10) { - uint32 extcinfo; - uint8 nb; - uint8 i; - - extcinfo = R_REG(sii->osh, ®s->extracoreinfo); - nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); - for (i = 0; i < nb; i++) - memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - -uint32 -si_socdevram_remap_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - uint32 memsize = 0, banksz; - sbsocramregs_t *regs; - bool wasup; - uint corerev; - uint32 extcinfo; - uint8 nb; - uint8 i; - uint32 bankidx, bankinfo; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - - corerev = si_corerev(sih); - if (corerev >= 16) { - extcinfo = R_REG(sii->osh, ®s->extracoreinfo); - nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); - - /* - * FIX: A0 Issue: Max addressable is 512KB, instead 640KB - * Only four banks are accessible to ARM - */ - if ((corerev == 16) && (nb == 5)) - nb = 4; - - for (i = 0; i < nb; i++) { - bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); - W_REG(sii->osh, ®s->bankidx, bankidx); - bankinfo = R_REG(sii->osh, ®s->bankinfo); - if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { - banksz = socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); - memsize += banksz; - } else { - /* Account only consecutive banks for now */ - break; - } - } - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - -/** Return the RAM size of the SOCRAM core */ -uint32 -si_socram_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - - sbsocramregs_t *regs; - bool wasup; - uint corerev; - uint32 coreinfo; - uint memsize = 0; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - corerev = si_corerev(sih); - coreinfo = R_REG(sii->osh, ®s->coreinfo); - - /* Calculate size from coreinfo based on rev */ - if (corerev == 0) - memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); - else if (corerev < 3) { - memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); - memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - } else if ((corerev <= 7) || (corerev == 12)) { - uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - uint bsz = (coreinfo & SRCI_SRBSZ_MASK); - uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; - if (lss != 0) - nb --; - memsize = nb * (1 << (bsz + SR_BSZ_BASE)); - if (lss != 0) - memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); - } else { - uint8 i; - uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - for (i = 0; i < nb; i++) - memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - - -/** Return the TCM-RAM size of the ARMCR4 core. */ -uint32 -si_tcm_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - uint8 *regs; - bool wasup; - uint32 corecap; - uint memsize = 0; - uint32 nab = 0; - uint32 nbb = 0; - uint32 totb = 0; - uint32 bxinfo = 0; - uint32 idx = 0; - uint32 *arm_cap_reg; - uint32 *arm_bidx; - uint32 *arm_binfo; - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to CR4 core */ - if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0))) - goto done; - - /* Get info for determining size. If in reset, come out of reset, - * but remain in halt - */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT); - - arm_cap_reg = (uint32 *)(regs + SI_CR4_CAP); - corecap = R_REG(sii->osh, arm_cap_reg); - - nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; - nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; - totb = nab + nbb; - - arm_bidx = (uint32 *)(regs + SI_CR4_BANKIDX); - arm_binfo = (uint32 *)(regs + SI_CR4_BANKINFO); - for (idx = 0; idx < totb; idx++) { - W_REG(sii->osh, arm_bidx, idx); - - bxinfo = R_REG(sii->osh, arm_binfo); - memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - -bool -si_has_flops(si_t *sih) -{ - uint origidx, cr4_rev; - - /* Find out CR4 core revision */ - origidx = si_coreidx(sih); - if (si_setcore(sih, ARMCR4_CORE_ID, 0)) { - cr4_rev = si_corerev(sih); - si_setcoreidx(sih, origidx); - - if (cr4_rev == 1 || cr4_rev >= 3) - return TRUE; - } - return FALSE; -} - -uint32 -si_socram_srmem_size(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - - sbsocramregs_t *regs; - bool wasup; - uint corerev; - uint32 coreinfo; - uint memsize = 0; - - if ((CHIPID(sih->chip) == BCM4334_CHIP_ID) && (CHIPREV(sih->chiprev) < 2)) { - return (32 * 1024); - } - - if (CHIPID(sih->chip) == BCM43430_CHIP_ID) { - return (64 * 1024); - } - - /* Block ints and save current core */ - INTR_OFF(sii, intr_val); - origidx = si_coreidx(sih); - - /* Switch to SOCRAM core */ - if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) - goto done; - - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); - corerev = si_corerev(sih); - coreinfo = R_REG(sii->osh, ®s->coreinfo); - - /* Calculate size from coreinfo based on rev */ - if (corerev >= 16) { - uint8 i; - uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - for (i = 0; i < nb; i++) { - W_REG(sii->osh, ®s->bankidx, i); - if (R_REG(sii->osh, ®s->bankinfo) & SOCRAM_BANKINFO_RETNTRAM_MASK) - memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); - } - } - - /* Return to previous state and core */ - if (!wasup) - si_core_disable(sih, 0); - si_setcoreidx(sih, origidx); - -done: - INTR_RESTORE(sii, intr_val); - - return memsize; -} - - -#if !defined(_CFEZ_) || defined(CFG_WL) -void -si_btcgpiowar(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint origidx; - uint intr_val = 0; - chipcregs_t *cc; - - /* Make sure that there is ChipCommon core present && - * UART_TX is strapped to 1 - */ - if (!(sih->cccaps & CC_CAP_UARTGPIO)) - return; - - /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */ - INTR_OFF(sii, intr_val); - - origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - ASSERT(cc != NULL); - - W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04); - - /* restore the original index */ - si_setcoreidx(sih, origidx); - - INTR_RESTORE(sii, intr_val); -} - -void -si_chipcontrl_btshd0_4331(si_t *sih, bool on) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - chipcregs_t *cc; - uint origidx; - uint32 val; - uint intr_val = 0; - - INTR_OFF(sii, intr_val); - - origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - val = R_REG(sii->osh, &cc->chipcontrol); - - /* bt_shd0 controls are same for 4331 chiprevs 0 and 1, packages 12x9 and 12x12 */ - if (on) { - /* Enable bt_shd0 on gpio4: */ - val |= (CCTRL4331_BT_SHD0_ON_GPIO4); - W_REG(sii->osh, &cc->chipcontrol, val); - } else { - val &= ~(CCTRL4331_BT_SHD0_ON_GPIO4); - W_REG(sii->osh, &cc->chipcontrol, val); - } - - /* restore the original index */ - si_setcoreidx(sih, origidx); - - INTR_RESTORE(sii, intr_val); -} - -void -si_chipcontrl_restore(si_t *sih, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - W_REG(sii->osh, &cc->chipcontrol, val); - si_setcoreidx(sih, origidx); -} - -uint32 -si_chipcontrl_read(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - uint32 val; - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - val = R_REG(sii->osh, &cc->chipcontrol); - si_setcoreidx(sih, origidx); - return val; -} - -void -si_chipcontrl_epa4331(si_t *sih, bool on) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - uint32 val; - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - val = R_REG(sii->osh, &cc->chipcontrol); - - if (on) { - if (sih->chippkg == 9 || sih->chippkg == 0xb) { - val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); - /* Ext PA Controls for 4331 12x9 Package */ - W_REG(sii->osh, &cc->chipcontrol, val); - } else { - /* Ext PA Controls for 4331 12x12 Package */ - if (sih->chiprev > 0) { - W_REG(sii->osh, &cc->chipcontrol, val | - (CCTRL4331_EXTPA_EN) | (CCTRL4331_EXTPA_EN2)); - } else { - W_REG(sii->osh, &cc->chipcontrol, val | (CCTRL4331_EXTPA_EN)); - } - } - } else { - val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_EN2 | CCTRL4331_EXTPA_ON_GPIO2_5); - W_REG(sii->osh, &cc->chipcontrol, val); - } - - si_setcoreidx(sih, origidx); -} - -/** switch muxed pins, on: SROM, off: FEMCTRL. Called for a family of ac chips, not just 4360. */ -void -si_chipcontrl_srom4360(si_t *sih, bool on) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - uint32 val; - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - val = R_REG(sii->osh, &cc->chipcontrol); - - if (on) { - val &= ~(CCTRL4360_SECI_MODE | - CCTRL4360_BTSWCTRL_MODE | - CCTRL4360_EXTRA_FEMCTRL_MODE | - CCTRL4360_BT_LGCY_MODE | - CCTRL4360_CORE2FEMCTRL4_ON); - - W_REG(sii->osh, &cc->chipcontrol, val); - } else { - } - - si_setcoreidx(sih, origidx); -} - -void -si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl) -{ - si_info_t *sii; - chipcregs_t *cc; - uint origidx; - uint32 val; - bool sel_chip; - - sel_chip = (CHIPID(sih->chip) == BCM4331_CHIP_ID) || - (CHIPID(sih->chip) == BCM43431_CHIP_ID); - sel_chip &= ((sih->chippkg == 9 || sih->chippkg == 0xb)); - - if (!sel_chip) - return; - - sii = SI_INFO(sih); - origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - val = R_REG(sii->osh, &cc->chipcontrol); - - if (enter_wowl) { - val |= CCTRL4331_EXTPA_EN; - W_REG(sii->osh, &cc->chipcontrol, val); - } else { - val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); - W_REG(sii->osh, &cc->chipcontrol, val); - } - si_setcoreidx(sih, origidx); -} -#endif - -uint -si_pll_reset(si_t *sih) -{ - uint err = 0; - - return (err); -} - -/** Enable BT-COEX & Ex-PA for 4313 */ -void -si_epa_4313war(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - /* EPA Fix */ - W_REG(sii->osh, &cc->gpiocontrol, - R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); - - si_setcoreidx(sih, origidx); -} - -void -si_clk_pmu_htavail_set(si_t *sih, bool set_clear) -{ -} - -/** Re-enable synth_pwrsw resource in min_res_mask for 4313 */ -void -si_pmu_synth_pwrsw_4313_war(si_t *sih) -{ -} - -/** WL/BT control for 4313 btcombo boards >= P250 */ -void -si_btcombo_p250_4313_war(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - W_REG(sii->osh, &cc->gpiocontrol, - R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_5_6_EN_MASK); - - W_REG(sii->osh, &cc->gpioouten, - R_REG(sii->osh, &cc->gpioouten) | GPIO_CTRL_5_6_EN_MASK); - - si_setcoreidx(sih, origidx); -} -void -si_btc_enable_chipcontrol(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - /* BT fix */ - W_REG(sii->osh, &cc->chipcontrol, - R_REG(sii->osh, &cc->chipcontrol) | CC_BTCOEX_EN_MASK); - - si_setcoreidx(sih, origidx); -} -void -si_btcombo_43228_war(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - - W_REG(sii->osh, &cc->gpioouten, GPIO_CTRL_7_6_EN_MASK); - W_REG(sii->osh, &cc->gpioout, GPIO_OUT_7_EN_MASK); - - si_setcoreidx(sih, origidx); -} - -/** check if the device is removed */ -bool -si_deviceremoved(si_t *sih) -{ - uint32 w; - - switch (BUSTYPE(sih->bustype)) { - case PCI_BUS: - ASSERT(SI_INFO(sih)->osh != NULL); - w = OSL_PCI_READ_CONFIG(SI_INFO(sih)->osh, PCI_CFG_VID, sizeof(uint32)); - if ((w & 0xFFFF) != VENDOR_BROADCOM) - return TRUE; - break; - } - return FALSE; -} - -bool -si_is_sprom_available(si_t *sih) -{ - if (sih->ccrev >= 31) { - si_info_t *sii; - uint origidx; - chipcregs_t *cc; - uint32 sromctrl; - - if ((sih->cccaps & CC_CAP_SROM) == 0) - return FALSE; - - sii = SI_INFO(sih); - origidx = sii->curidx; - cc = si_setcoreidx(sih, SI_CC_IDX); - ASSERT(cc); - sromctrl = R_REG(sii->osh, &cc->sromcontrol); - si_setcoreidx(sih, origidx); - return (sromctrl & SRC_PRESENT); - } - - switch (CHIPID(sih->chip)) { - case BCM4312_CHIP_ID: - return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL); - case BCM4325_CHIP_ID: - return (sih->chipst & CST4325_SPROM_SEL) != 0; - case BCM4322_CHIP_ID: case BCM43221_CHIP_ID: case BCM43231_CHIP_ID: - case BCM43222_CHIP_ID: case BCM43111_CHIP_ID: case BCM43112_CHIP_ID: - case BCM4342_CHIP_ID: { - uint32 spromotp; - spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >> - CST4322_SPROM_OTP_SEL_SHIFT; - return (spromotp & CST4322_SPROM_PRESENT) != 0; - } - case BCM4329_CHIP_ID: - return (sih->chipst & CST4329_SPROM_SEL) != 0; - case BCM4315_CHIP_ID: - return (sih->chipst & CST4315_SPROM_SEL) != 0; - case BCM4319_CHIP_ID: - return (sih->chipst & CST4319_SPROM_SEL) != 0; - case BCM4336_CHIP_ID: - case BCM43362_CHIP_ID: - return (sih->chipst & CST4336_SPROM_PRESENT) != 0; - case BCM4330_CHIP_ID: - return (sih->chipst & CST4330_SPROM_PRESENT) != 0; - case BCM4313_CHIP_ID: - return (sih->chipst & CST4313_SPROM_PRESENT) != 0; - case BCM4331_CHIP_ID: - case BCM43431_CHIP_ID: - return (sih->chipst & CST4331_SPROM_PRESENT) != 0; - case BCM43239_CHIP_ID: - return ((sih->chipst & CST43239_SPROM_MASK) && - !(sih->chipst & CST43239_SFLASH_MASK)); - case BCM4324_CHIP_ID: - case BCM43242_CHIP_ID: - return ((sih->chipst & CST4324_SPROM_MASK) && - !(sih->chipst & CST4324_SFLASH_MASK)); - case BCM4335_CHIP_ID: - case BCM4345_CHIP_ID: - case BCM43454_CHIP_ID: - return ((sih->chipst & CST4335_SPROM_MASK) && - !(sih->chipst & CST4335_SFLASH_MASK)); - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM4356_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43569_CHIP_ID: - return (sih->chipst & CST4350_SPROM_PRESENT) != 0; - case BCM43602_CHIP_ID: - return (sih->chipst & CST43602_SPROM_PRESENT) != 0; - case BCM43131_CHIP_ID: - case BCM43217_CHIP_ID: - case BCM43227_CHIP_ID: - case BCM43228_CHIP_ID: - case BCM43428_CHIP_ID: - return (sih->chipst & CST43228_OTP_PRESENT) != CST43228_OTP_PRESENT; - default: - return TRUE; - } -} - - -uint32 si_get_sromctl(si_t *sih) -{ - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - uint32 sromctl; - osl_t *osh = si_osh(sih); - - cc = si_setcoreidx(sih, SI_CC_IDX); - ASSERT((uintptr)cc); - - sromctl = R_REG(osh, &cc->sromcontrol); - - /* return to the original core */ - si_setcoreidx(sih, origidx); - return sromctl; -} - -int si_set_sromctl(si_t *sih, uint32 value) -{ - chipcregs_t *cc; - uint origidx = si_coreidx(sih); - osl_t *osh = si_osh(sih); - - cc = si_setcoreidx(sih, SI_CC_IDX); - ASSERT((uintptr)cc); - - /* get chipcommon rev */ - if (si_corerev(sih) < 32) - return BCME_UNSUPPORTED; - - W_REG(osh, &cc->sromcontrol, value); - - /* return to the original core */ - si_setcoreidx(sih, origidx); - return BCME_OK; - -} - -uint -si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val) -{ - uint origidx; - uint ret_val; - - origidx = si_coreidx(sih); - - si_setcoreidx(sih, coreidx); - - ret_val = si_wrapperreg(sih, offset, mask, val); - - /* return to the original core */ - si_setcoreidx(sih, origidx); - return ret_val; -} - - -/* cleanup the hndrte timer from the host when ARM is been halted - * without a chance for ARM cleanup its resources - * If left not cleanup, Intr from a software timer can still - * request HT clk when ARM is halted. - */ -uint32 -si_pmu_res_req_timer_clr(si_t *sih) -{ - uint32 mask; - - mask = PRRT_REQ_ACTIVE | PRRT_INTEN; - if (CHIPID(sih->chip) != BCM4328_CHIP_ID) - mask <<= 14; - /* clear mask bits */ - si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, res_req_timer), mask, 0); - /* readback to ensure write completes */ - return si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, res_req_timer), 0, 0); -} - -/** turn on/off rfldo */ -void -si_pmu_rfldo(si_t *sih, bool on) -{ -} - -#ifdef SURVIVE_PERST_ENAB -static uint32 -si_pcie_survive_perst(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii; - - sii = SI_INFO(sih); - - if (!PCIE(sii)) - return (0); - - return pcie_survive_perst(sii->pch, mask, val); -} - -static void -si_watchdog_reset(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - chipcregs_t *cc; - uint32 origidx, i; - - origidx = si_coreidx(sih); - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - /* issue a watchdog reset */ - W_REG(sii->osh, &cc->pmuwatchdog, 2); - /* do busy wait for 20ms */ - for (i = 0; i < 2000; i++) { - OSL_DELAY(10); - } - si_setcoreidx(sih, origidx); -} -#endif /* SURVIVE_PERST_ENAB */ - -void -si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 sperst_val) -{ -#ifdef SURVIVE_PERST_ENAB - if (BUSTYPE(sih->bustype) != PCI_BUS) - return; - - if ((CHIPID(sih->chip) != BCM4360_CHIP_ID && CHIPID(sih->chip) != BCM4352_CHIP_ID) || - (CHIPREV(sih->chiprev) >= 4)) - return; - - if (reset) { - si_info_t *sii = SI_INFO(sih); - uint32 bar0win, bar0win_after; - - /* save the bar0win */ - bar0win = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); - - si_watchdog_reset(sih); - - bar0win_after = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); - if (bar0win_after != bar0win) { - SI_ERROR(("%s: bar0win before %08x, bar0win after %08x\n", - __FUNCTION__, bar0win, bar0win_after)); - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32), bar0win); - } - } - if (sperst_mask) { - /* enable survive perst */ - si_pcie_survive_perst(sih, sperst_mask, sperst_val); - } -#endif /* SURVIVE_PERST_ENAB */ -} - -void -si_pcie_ltr_war(si_t *sih) -{ -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h b/drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h deleted file mode 100755 index 1712409c7d70..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Include file private to the SOC Interconnect support files. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: siutils_priv.h 431423 2013-10-23 16:07:35Z $ - */ - -#ifndef _siutils_priv_h_ -#define _siutils_priv_h_ - -#define SI_ERROR(args) - -#define SI_MSG(args) - -#ifdef BCMDBG_SI -#define SI_VMSG(args) printf args -#else -#define SI_VMSG(args) -#endif - -#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) - -typedef uint32 (*si_intrsoff_t)(void *intr_arg); -typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg); -typedef bool (*si_intrsenabled_t)(void *intr_arg); - -typedef struct gpioh_item { - void *arg; - bool level; - gpio_handler_t handler; - uint32 event; - struct gpioh_item *next; -} gpioh_item_t; - - -#define SI_GPIO_MAX 16 - -typedef struct gci_gpio_item { - void *arg; - uint8 gci_gpio; - uint8 status; - gci_gpio_handler_t handler; - struct gci_gpio_item *next; -} gci_gpio_item_t; - - -typedef struct si_cores_info { - void *regs[SI_MAXCORES]; /* other regs va */ - - uint coreid[SI_MAXCORES]; /* id of each core */ - uint32 coresba[SI_MAXCORES]; /* backplane address of each core */ - void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */ - uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */ - uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */ - uint32 coresba2_size[SI_MAXCORES]; /* second address space size */ - - void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ - uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ - - uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */ - uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */ -} si_cores_info_t; - -/* misc si info needed by some of the routines */ -typedef struct si_info { - struct si_pub pub; /* back plane public state (must be first field) */ - - void *osh; /* osl os handle */ - void *sdh; /* bcmsdh handle */ - - uint dev_coreid; /* the core provides driver functions */ - void *intr_arg; /* interrupt callback function arg */ - si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ - si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ - si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ - - void *pch; /* PCI/E core handle */ - - gpioh_item_t *gpioh_head; /* GPIO event handlers list */ - - bool memseg; /* flag to toggle MEM_SEG register */ - - char *vars; - uint varsz; - - void *curmap; /* current regs va */ - - uint curidx; /* current core index */ - uint numcores; /* # discovered cores */ - - void *curwrap; /* current wrapper va */ - - uint32 oob_router; /* oob router registers for axi */ - - void *cores_info; - gci_gpio_item_t *gci_gpio_head; /* gci gpio interrupts head */ -} si_info_t; - - -#define SI_INFO(sih) ((si_info_t *)(uintptr)sih) - -#define GOODCOREADDR(x, b) (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ - ISALIGNED((x), SI_CORE_SIZE)) -#define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE)) -#define BADCOREADDR 0 -#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES) -#define NOREV -1 /* Invalid rev */ - -#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ - ((si)->pub.buscoretype == PCI_CORE_ID)) - -#define PCIE_GEN1(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ - ((si)->pub.buscoretype == PCIE_CORE_ID)) - -#define PCIE_GEN2(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ - ((si)->pub.buscoretype == PCIE2_CORE_ID)) - -#define PCIE(si) (PCIE_GEN1(si) || PCIE_GEN2(si)) - -#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE)) - -/* Newer chips can access PCI/PCIE and CC core without requiring to change - * PCI BAR0 WIN - */ -#define SI_FAST(si) (PCIE(si) || (PCI(si) && ((si)->pub.buscorerev >= 13))) - -#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET)) -#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET)) - -/* - * 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 && (cores_info)->coreid[(si)->curidx] == (si)->dev_coreid) { \ - intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); } -#define INTR_RESTORE(si, intr_val) \ - if ((si)->intrsrestore_fn && (cores_info)->coreid[(si)->curidx] == (si)->dev_coreid) { \ - (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } - -/* 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 */ - -/* Force fast clock for 4360b0 */ -#define PCI_FORCEHT(si) \ - (((PCIE_GEN1(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \ - ((PCI(si) || PCIE_GEN1(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \ - (PCIE_GEN1(si) && (si->pub.chip == BCM4716_CHIP_ID)) || \ - (PCIE_GEN1(si) && (si->pub.chip == BCM4748_CHIP_ID))) - -/* GPIO Based LED powersave defines */ -#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ -#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ - -#ifndef DEFAULT_GPIOTIMERVAL -#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) -#endif - -/* Silicon Backplane externs */ -extern void sb_scan(si_t *sih, void *regs, uint devid); -extern uint sb_coreid(si_t *sih); -extern uint sb_intflag(si_t *sih); -extern uint sb_flag(si_t *sih); -extern void sb_setint(si_t *sih, int siflag); -extern uint sb_corevendor(si_t *sih); -extern uint sb_corerev(si_t *sih); -extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -extern uint32 *sb_corereg_addr(si_t *sih, uint coreidx, uint regoff); -extern bool sb_iscoreup(si_t *sih); -extern void *sb_setcoreidx(si_t *sih, uint coreidx); -extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val); -extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); -extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val); -extern void sb_commit(si_t *sih); -extern uint32 sb_base(uint32 admatch); -extern uint32 sb_size(uint32 admatch); -extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -extern void sb_core_disable(si_t *sih, uint32 bits); -extern uint32 sb_addrspace(si_t *sih, uint asidx); -extern uint32 sb_addrspacesize(si_t *sih, uint asidx); -extern int sb_numaddrspaces(si_t *sih); - -extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); - -extern bool sb_taclear(si_t *sih, bool details); - - -/* Wake-on-wireless-LAN (WOWL) */ -extern bool sb_pci_pmecap(si_t *sih); -struct osl_info; -extern bool sb_pci_fastpmecap(struct osl_info *osh); -extern bool sb_pci_pmeclr(si_t *sih); -extern void sb_pci_pmeen(si_t *sih); -extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset); - -/* AMBA Interconnect exported externs */ -extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, - void *sdh, char **vars, uint *varsz); -extern si_t *ai_kattach(osl_t *osh); -extern void ai_scan(si_t *sih, void *regs, uint devid); - -extern uint ai_flag(si_t *sih); -extern uint ai_flag_alt(si_t *sih); -extern void ai_setint(si_t *sih, int siflag); -extern uint ai_coreidx(si_t *sih); -extern uint ai_corevendor(si_t *sih); -extern uint ai_corerev(si_t *sih); -extern uint32 *ai_corereg_addr(si_t *sih, uint coreidx, uint regoff); -extern bool ai_iscoreup(si_t *sih); -extern void *ai_setcoreidx(si_t *sih, uint coreidx); -extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val); -extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); -extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val); -extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -extern void ai_core_disable(si_t *sih, uint32 bits); -extern int ai_numaddrspaces(si_t *sih); -extern uint32 ai_addrspace(si_t *sih, uint asidx); -extern uint32 ai_addrspacesize(si_t *sih, uint asidx); -extern void ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); -extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val); - - - -#define ub_scan(a, b, c) do {} while (0) -#define ub_flag(a) (0) -#define ub_setint(a, b) do {} while (0) -#define ub_coreidx(a) (0) -#define ub_corevendor(a) (0) -#define ub_corerev(a) (0) -#define ub_iscoreup(a) (0) -#define ub_setcoreidx(a, b) (0) -#define ub_core_cflags(a, b, c) (0) -#define ub_core_cflags_wo(a, b, c) do {} while (0) -#define ub_core_sflags(a, b, c) (0) -#define ub_corereg(a, b, c, d, e) (0) -#define ub_core_reset(a, b, c) do {} while (0) -#define ub_core_disable(a, b) do {} while (0) -#define ub_numaddrspaces(a) (0) -#define ub_addrspace(a, b) (0) -#define ub_addrspacesize(a, b) (0) -#define ub_view(a, b) do {} while (0) -#define ub_dumpregs(a, b) do {} while (0) - -#endif /* _siutils_priv_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/uamp_api.h b/drivers/net/wireless/bcmdhd_suzuran/uamp_api.h deleted file mode 100755 index 01935148ee9b..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/uamp_api.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Name: uamp_api.h - * - * Description: Universal AMP API - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: uamp_api.h 294267 2011-11-04 23:41:52Z $ - * - */ -#ifndef UAMP_API_H -#define UAMP_API_H - - -#include "typedefs.h" - - -/***************************************************************************** -** Constant and Type Definitions -****************************************************************************** -*/ - -#define BT_API - -/* Types. */ -typedef bool BOOLEAN; -typedef uint8 UINT8; -typedef uint16 UINT16; - - -/* UAMP identifiers */ -#define UAMP_ID_1 1 -#define UAMP_ID_2 2 -typedef UINT8 tUAMP_ID; - -/* UAMP event ids (used by UAMP_CBACK) */ -#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */ -#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */ -#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */ -typedef UINT8 tUAMP_EVT; - - -/* UAMP Channels */ -#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */ -#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */ -#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */ -typedef UINT8 tUAMP_CH; - -/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */ -typedef union { - tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */ -} tUAMP_EVT_DATA; - - -/***************************************************************************** -** -** Function: UAMP_CBACK -** -** Description: Callback for events. Register callback using UAMP_Init. -** -** Parameters amp_id: AMP device identifier that generated the event -** amp_evt: event id -** p_amp_evt_data: pointer to event-specific data -** -****************************************************************************** -*/ -typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data); - -/***************************************************************************** -** external function declarations -****************************************************************************** -*/ -#ifdef __cplusplus -extern "C" -{ -#endif - -/***************************************************************************** -** -** Function: UAMP_Init -** -** Description: Initialize UAMP driver -** -** Parameters p_cback: Callback function for UAMP event notification -** -****************************************************************************** -*/ -BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback); - - -/***************************************************************************** -** -** Function: UAMP_Open -** -** Description: Open connection to local AMP device. -** -** Parameters app_id: Application specific AMP identifer. This value -** will be included in AMP messages sent to the -** BTU task, to identify source of the message -** -****************************************************************************** -*/ -BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id); - -/***************************************************************************** -** -** Function: UAMP_Close -** -** Description: Close connection to local AMP device. -** -** Parameters app_id: Application specific AMP identifer. -** -****************************************************************************** -*/ -BT_API void UAMP_Close(tUAMP_ID amp_id); - - -/***************************************************************************** -** -** Function: UAMP_Write -** -** Description: Send buffer to AMP device. Frees GKI buffer when done. -** -** -** Parameters: app_id: AMP identifer. -** p_buf: pointer to buffer to write -** num_bytes: number of bytes to write -** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD -** -** Returns: number of bytes written -** -****************************************************************************** -*/ -BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel); - -/***************************************************************************** -** -** Function: UAMP_Read -** -** Description: Read incoming data from AMP. Call after receiving a -** UAMP_EVT_RX_READY callback event. -** -** Parameters: app_id: AMP identifer. -** p_buf: pointer to buffer for holding incoming AMP data -** buf_size: size of p_buf -** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT -** -** Returns: number of bytes read -** -****************************************************************************** -*/ -BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel); - -#ifdef __cplusplus -} -#endif - -#endif /* UAMP_API_H */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c b/drivers/net/wireless/bcmdhd_suzuran/wl_android.c deleted file mode 100755 index 8c62fe4545b6..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c +++ /dev/null @@ -1,2357 +0,0 @@ -/* - * Linux cfg80211 driver - Android related functions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * Copyright (C) 2015 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_android.c 736234 2017-12-14 04:22:25Z $ - */ - -#include -#include -#include -#ifdef CONFIG_COMPAT -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef PNO_SUPPORT -#include -#endif -#include -#ifdef WL_CFG80211 -#include -#endif -#ifdef WL_NAN -#include -#endif /* WL_NAN */ - -/* - * Android private command strings, PLEASE define new private commands here - * so they can be updated easily in the future (if needed) - */ - -#define CMD_START "START" -#define CMD_STOP "STOP" -#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" -#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" -#define CMD_RSSI "RSSI" -#define CMD_LINKSPEED "LINKSPEED" -#define CMD_RXFILTER_START "RXFILTER-START" -#define CMD_RXFILTER_STOP "RXFILTER-STOP" -#define CMD_RXFILTER_ADD "RXFILTER-ADD" -#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" -#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" -#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" -#define CMD_BTCOEXMODE "BTCOEXMODE" -#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" -#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" -#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" -#define CMD_SETFWPATH "SETFWPATH" -#define CMD_SETBAND "SETBAND" -#define CMD_GETBAND "GETBAND" -#define CMD_COUNTRY "COUNTRY" -#define CMD_P2P_SET_NOA "P2P_SET_NOA" -#if !defined WL_ENABLE_P2P_IF -#define CMD_P2P_GET_NOA "P2P_GET_NOA" -#endif /* WL_ENABLE_P2P_IF */ -#define CMD_P2P_SD_OFFLOAD "P2P_SD_" -#define CMD_P2P_SET_PS "P2P_SET_PS" -#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" -#define CMD_SETROAMMODE "SETROAMMODE" -#define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA" -#define CMD_MIRACAST "MIRACAST" -#define CMD_NAN "NAN_" - -#if defined(WL_SUPPORT_AUTO_CHANNEL) -#define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS" -#endif /* WL_SUPPORT_AUTO_CHANNEL */ - -#ifdef WLFBT -#define CMD_GET_FTKEY "GET_FTKEY" -#endif -#define CMD_KEEP_ALIVE "KEEPALIVE" - - -/* CCX Private Commands */ -#ifdef BCMCCX -#define CMD_GETCCKM_RN "get cckm_rn" -#define CMD_SETCCKM_KRK "set cckm_krk" -#define CMD_GET_ASSOC_RES_IES "get assoc_res_ies" -#endif - -#ifdef PNO_SUPPORT -#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" -#define CMD_PNOSETUP_SET "PNOSETUP " -#define CMD_PNOENABLE_SET "PNOFORCE" -#define CMD_PNODEBUG_SET "PNODEBUG" -#define CMD_WLS_BATCHING "WLS_BATCHING" -#endif /* PNO_SUPPORT */ - -#define CMD_OKC_SET_PMK "SET_PMK" -#define CMD_OKC_ENABLE "OKC_ENABLE" - -#define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER" - - -#ifdef WLAIBSS -#define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT" -#define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO" -#define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL" -#define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE" -#define CMD_SETIBSSAMPDU "SETIBSSAMPDU" -#define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE" -#endif /* WLAIBSS */ - -#define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD" - -/* miracast related definition */ -#define MIRACAST_MODE_OFF 0 -#define MIRACAST_MODE_SOURCE 1 -#define MIRACAST_MODE_SINK 2 - -#ifndef MIRACAST_AMPDU_SIZE -#define MIRACAST_AMPDU_SIZE 8 -#endif - -#ifndef MIRACAST_MCHAN_ALGO -#define MIRACAST_MCHAN_ALGO 1 -#endif - -#ifndef MIRACAST_MCHAN_BW -#define MIRACAST_MCHAN_BW 25 -#endif - -#ifdef CHANGE_SCAN_TIME -static int miracast_scan_time[3][2] = { - { WLC_GET_SCAN_CHANNEL_TIME, 20 }, - { WLC_GET_SCAN_UNASSOC_TIME, 20 }, - { WLC_GET_SCAN_PASSIVE_TIME, 40 } - }; -#endif - -#ifdef CONNECTION_STATISTICS -#define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS" - -struct connection_stats { - u32 txframe; - u32 txbyte; - u32 txerror; - u32 rxframe; - u32 rxbyte; - u32 txfail; - u32 txretry; - u32 txretrie; - u32 txrts; - u32 txnocts; - u32 txexptime; - u32 txrate; - u8 chan_idle; -}; -#endif /* CONNECTION_STATISTICS */ - -static LIST_HEAD(miracast_resume_list); -static u8 miracast_cur_mode; - -struct io_cfg { - s8 *iovar; - s32 param; - u32 ioctl; - void *arg; - u32 len; - struct list_head list; -}; - -typedef struct _android_wifi_priv_cmd { - char *buf; - int used_len; - int total_len; -} android_wifi_priv_cmd; - -#ifdef CONFIG_COMPAT -typedef struct _compat_android_wifi_priv_cmd { - compat_caddr_t buf; - int used_len; - int total_len; -} compat_android_wifi_priv_cmd; -#endif /* CONFIG_COMPAT */ - -#if defined(BCMFW_ROAM_ENABLE) -#define CMD_SET_ROAMPREF "SET_ROAMPREF" - -#define MAX_NUM_SUITES 10 -#define WIDTH_AKM_SUITE 8 -#define JOIN_PREF_RSSI_LEN 0x02 -#define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */ -#define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */ -#define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */ -#define JOIN_PREF_MAX_WPA_TUPLES 16 -#define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \ - (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES)) -#endif /* BCMFW_ROAM_ENABLE */ - - -/** - * Extern function declarations (TODO: move them to dhd_linux.h) - */ -int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); -int dhd_dev_init_ioctl(struct net_device *dev); -#ifdef WL_CFG80211 -int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); -int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command); -#else -int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) -{ return 0; } -int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) -{ return 0; } -int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) -{ return 0; } -int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) -{ return 0; } -#endif /* WK_CFG80211 */ - - -#ifdef ENABLE_4335BT_WAR -extern int bcm_bt_lock(int cookie); -extern void bcm_bt_unlock(int cookie); -static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ -#endif /* ENABLE_4335BT_WAR */ - -extern bool ap_fw_loaded; -#if defined(CUSTOMER_HW2) -extern char iface_name[IFNAMSIZ]; -#endif - -/** - * Local (static) functions and variables - */ - -/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first - * time (only) in dhd_open, subsequential wifi on will be handled by - * wl_android_wifi_on - */ -static int g_wifi_on = TRUE; - -/** - * Local (static) function definitions - */ -static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) -{ - int link_speed; - int bytes_written; - int error; - - error = wldev_get_link_speed(net, &link_speed); - if (error) - return -1; - - /* Convert Kbps to Android Mbps */ - link_speed = link_speed / 1000; - bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); - DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); - return bytes_written; -} - -static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) -{ - wlc_ssid_t ssid = {0}; - int rssi; - int bytes_written = 0; - int error; - - error = wldev_get_rssi(net, &rssi); - if (error) - return -1; - - error = wldev_get_ssid(net, &ssid); - if (error) - return -1; - if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { - DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); - } else { - if (total_len > ssid.SSID_len) { - memcpy(command, ssid.SSID, ssid.SSID_len); - bytes_written = ssid.SSID_len; - } else { - return BCME_ERROR; - } - } - - if ((total_len - bytes_written) >= (strlen(" rssi -XXX") + 1)) { - bytes_written += snprintf(&command[bytes_written], total_len - bytes_written, - " rssi %d", rssi); - command[bytes_written] = '\0'; - } else { - return BCME_ERROR; - } - - DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); - return bytes_written; -} - -static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) -{ - int suspend_flag; - int ret_now; - int ret = 0; - - suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; - - if (suspend_flag != 0) - suspend_flag = 1; - ret_now = net_os_set_suspend_disable(dev, suspend_flag); - - if (ret_now != suspend_flag) { - if (!(ret = net_os_set_suspend(dev, ret_now, 1))) - DHD_INFO(("%s: Suspend Flag %d -> %d\n", - __FUNCTION__, ret_now, suspend_flag)); - else - DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); - } - return ret; -} - -static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) -{ - int ret = 0; - -#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) - int suspend_flag; - - suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; - if (suspend_flag != 0) - suspend_flag = 1; - - if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) - DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag)); - else - DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); -#endif - - return ret; -} - -static int wl_android_get_band(struct net_device *dev, char *command, int total_len) -{ - uint band; - int bytes_written; - int error; - - error = wldev_get_band(dev, &band); - if (error) - return -1; - bytes_written = snprintf(command, total_len, "Band %d", band); - return bytes_written; -} - - -#ifdef PNO_SUPPORT -#define PNO_PARAM_SIZE 50 -#define VALUE_SIZE 50 -#define LIMIT_STR_FMT ("%50s %50s") -static int -wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) -{ - int err = BCME_OK; - uint i, tokens; - char *pos, *pos2, *token, *token2, *delim; - char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1]; - struct dhd_pno_batch_params batch_params; - DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); - if (total_len < strlen(CMD_WLS_BATCHING)) { - DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); - err = BCME_ERROR; - goto exit; - } - pos = command + strlen(CMD_WLS_BATCHING) + 1; - memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params)); - - if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) { - pos += strlen(PNO_BATCHING_SET) + 1; - while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) { - memset(param, 0, sizeof(param)); - memset(value, 0, sizeof(value)); - if (token == NULL || !*token) - break; - if (*token == '\0') - continue; - delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER); - if (delim != NULL) - *delim = ' '; - - tokens = sscanf(token, LIMIT_STR_FMT, param, value); - if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) { - batch_params.scan_fr = simple_strtol(value, NULL, 0); - DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr)); - } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) { - batch_params.bestn = simple_strtol(value, NULL, 0); - DHD_PNO(("bestn : %d\n", batch_params.bestn)); - } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) { - batch_params.mscan = simple_strtol(value, NULL, 0); - DHD_PNO(("mscan : %d\n", batch_params.mscan)); - } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) { - i = 0; - pos2 = value; - tokens = sscanf(value, "<%s>", value); - if (tokens != 1) { - err = BCME_ERROR; - DHD_ERROR(("%s : invalid format for channel" - " <> params\n", __FUNCTION__)); - goto exit; - } - while ((token2 = strsep(&pos2, - PNO_PARAM_CHANNEL_DELIMETER)) != NULL) { - if (token2 == NULL || !*token2) - break; - if (*token2 == '\0') - continue; - if (*token2 == 'A' || *token2 == 'B') { - batch_params.band = (*token2 == 'A')? - WLC_BAND_5G : WLC_BAND_2G; - DHD_PNO(("band : %s\n", - (*token2 == 'A')? "A" : "B")); - } else { - if ((batch_params.nchan >= WL_NUMCHANNELS) || - (i >= WL_NUMCHANNELS)) { - DHD_ERROR(("Too many nchan %d\n", - batch_params.nchan)); - err = BCME_BUFTOOSHORT; - goto exit; - } - batch_params.chan_list[i++] = - simple_strtol(token2, NULL, 0); - batch_params.nchan++; - DHD_PNO(("channel :%d\n", - batch_params.chan_list[i-1])); - } - } - } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) { - batch_params.rtt = simple_strtol(value, NULL, 0); - DHD_PNO(("rtt : %d\n", batch_params.rtt)); - } else { - DHD_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param)); - err = BCME_ERROR; - goto exit; - } - } - err = dhd_dev_pno_set_for_batch(dev, &batch_params); - if (err < 0) { - DHD_ERROR(("failed to configure batch scan\n")); - } else { - memset(command, 0, total_len); - err = sprintf(command, "%d", err); - } - } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) { - err = dhd_dev_pno_get_for_batch(dev, command, total_len); - if (err < 0) { - DHD_ERROR(("failed to getting batching results\n")); - } else { - err = strlen(command); - } - } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) { - err = dhd_dev_pno_stop_for_batch(dev); - if (err < 0) { - DHD_ERROR(("failed to stop batching scan\n")); - } else { - memset(command, 0, total_len); - err = sprintf(command, "OK"); - } - } else { - DHD_ERROR(("%s : unknown command\n", __FUNCTION__)); - err = BCME_ERROR; - goto exit; - } -exit: - return err; -} -#ifndef WL_SCHED_SCAN -static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) -{ - wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; - int res = -1; - int nssid = 0; - cmd_tlv_t *cmd_tlv_temp; - char *str_ptr; - int tlv_size_left; - int pno_time = 0; - int pno_repeat = 0; - int pno_freq_expo_max = 0; - -#ifdef PNO_SET_DEBUG - int i; - char pno_in_example[] = { - 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', - 'S', '1', '2', '0', - 'S', - 0x05, - 'd', 'l', 'i', 'n', 'k', - 'S', - 0x04, - 'G', 'O', 'O', 'G', - 'T', - '0', 'B', - 'R', - '2', - 'M', - '2', - 0x00 - }; -#endif /* PNO_SET_DEBUG */ - DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); - - if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { - DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); - goto exit_proc; - } -#ifdef PNO_SET_DEBUG - memcpy(command, pno_in_example, sizeof(pno_in_example)); - total_len = sizeof(pno_in_example); -#endif - str_ptr = command + strlen(CMD_PNOSETUP_SET); - tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); - - cmd_tlv_temp = (cmd_tlv_t *)str_ptr; - memset(ssids_local, 0, sizeof(ssids_local)); - - if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && - (cmd_tlv_temp->version == PNO_TLV_VERSION) && - (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) { - - str_ptr += sizeof(cmd_tlv_t); - tlv_size_left -= sizeof(cmd_tlv_t); - - if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local, - MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { - DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); - goto exit_proc; - } else { - if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { - DHD_ERROR(("%s scan duration corrupted field size %d\n", - __FUNCTION__, tlv_size_left)); - goto exit_proc; - } - str_ptr++; - pno_time = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); - - if (str_ptr[0] != 0) { - if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { - DHD_ERROR(("%s pno repeat : corrupted field\n", - __FUNCTION__)); - goto exit_proc; - } - str_ptr++; - pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); - if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { - DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", - __FUNCTION__)); - goto exit_proc; - } - str_ptr++; - pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_PNO(("%s: pno_freq_expo_max=%d\n", - __FUNCTION__, pno_freq_expo_max)); - } - } - } else { - DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); - goto exit_proc; - } - - res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat, - pno_freq_expo_max, NULL, 0); -exit_proc: - return res; -} -#endif /* !WL_SCHED_SCAN */ -#endif /* PNO_SUPPORT */ - -static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) -{ - int ret; - int bytes_written = 0; - - ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command); - if (ret) - return 0; - bytes_written = sizeof(struct ether_addr); - return bytes_written; -} - -#ifdef BCMCCX -static int wl_android_get_cckm_rn(struct net_device *dev, char *command) -{ - int error, rn; - - WL_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name)); - - error = wldev_iovar_getint(dev, "cckm_rn", &rn); - if (unlikely(error)) { - WL_ERR(("wl_android_get_cckm_rn error (%d)\n", error)); - return -1; - } - memcpy(command, &rn, sizeof(int)); - - return sizeof(int); -} - -static int wl_android_set_cckm_krk(struct net_device *dev, char *command) -{ - int error; - unsigned char key[16]; - static char iovar_buf[WLC_IOCTL_MEDLEN]; - - WL_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name)); - - memset(iovar_buf, 0, sizeof(iovar_buf)); - memcpy(key, command+strlen("set cckm_krk")+1, 16); - - error = wldev_iovar_setbuf(dev, "cckm_krk", key, sizeof(key), - iovar_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(error)) - { - WL_ERR((" cckm_krk set error (%d)\n", error)); - return -1; - } - return 0; -} - -static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command) -{ - int error; - u8 buf[WL_ASSOC_INFO_MAX]; - wl_assoc_info_t assoc_info; - u32 resp_ies_len = 0; - int bytes_written = 0; - - WL_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name)); - - error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf, WL_ASSOC_INFO_MAX, NULL); - if (unlikely(error)) { - WL_ERR(("could not get assoc info (%d)\n", error)); - return -1; - } - - memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t)); - assoc_info.req_len = htod32(assoc_info.req_len); - assoc_info.resp_len = htod32(assoc_info.resp_len); - assoc_info.flags = htod32(assoc_info.flags); - - if (assoc_info.resp_len) { - resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); - } - - /* first 4 bytes are ie len */ - memcpy(command, &resp_ies_len, sizeof(u32)); - bytes_written = sizeof(u32); - - /* get the association resp IE's if there are any */ - if (resp_ies_len) { - error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0, - buf, WL_ASSOC_INFO_MAX, NULL); - if (unlikely(error)) { - WL_ERR(("could not get assoc resp_ies (%d)\n", error)); - return -1; - } - - memcpy(command+sizeof(u32), buf, resp_ies_len); - bytes_written += resp_ies_len; - } - return bytes_written; -} - -#endif /* BCMCCX */ - -int -wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist) -{ - int i, j, match; - int ret = 0; - char mac_buf[MAX_NUM_OF_ASSOCLIST * - sizeof(struct ether_addr) + sizeof(uint)] = {0}; - struct maclist *assoc_maclist = (struct maclist *)mac_buf; - - /* set filtering mode */ - if ((ret = wldev_ioctl(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode), true)) != 0) { - DHD_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret)); - return ret; - } - if (macmode != MACLIST_MODE_DISABLED) { - /* set the MAC filter list */ - if ((ret = wldev_ioctl(dev, WLC_SET_MACLIST, maclist, - sizeof(int) + sizeof(struct ether_addr) * maclist->count, true)) != 0) { - DHD_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret)); - return ret; - } - /* get the current list of associated STAs */ - assoc_maclist->count = MAX_NUM_OF_ASSOCLIST; - if ((ret = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, - sizeof(mac_buf), false)) != 0) { - DHD_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret)); - return ret; - } - /* do we have any STA associated? */ - if (assoc_maclist->count) { - /* iterate each associated STA */ - for (i = 0; i < assoc_maclist->count; i++) { - match = 0; - /* compare with each entry */ - for (j = 0; j < maclist->count; j++) { - DHD_INFO(("%s : associated="MACDBG " list="MACDBG "\n", - __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet), - MAC2STRDBG(maclist->ea[j].octet))); - if (memcmp(assoc_maclist->ea[i].octet, - maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) { - match = 1; - break; - } - } - /* do conditional deauth */ - /* "if not in the allow list" or "if in the deny list" */ - if ((macmode == MACLIST_MODE_ALLOW && !match) || - (macmode == MACLIST_MODE_DENY && match)) { - scb_val_t scbval; - - scbval.val = htod32(1); - memcpy(&scbval.ea, &assoc_maclist->ea[i], - ETHER_ADDR_LEN); - if ((ret = wldev_ioctl(dev, - WLC_SCB_DEAUTHENTICATE_FOR_REASON, - &scbval, sizeof(scb_val_t), true)) != 0) - DHD_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n", - __FUNCTION__, ret)); - } - } - } - } - return ret; -} - -/* - * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2 - * - */ -static int -wl_android_set_mac_address_filter(struct net_device *dev, const char* str) -{ - int i; - int ret = 0; - int macnum = 0; - int macmode = MACLIST_MODE_DISABLED; - struct maclist *list; - char eabuf[ETHER_ADDR_STR_LEN]; - - /* string should look like below (macmode/macnum/maclist) */ - /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */ - - /* get the MAC filter mode */ - macmode = bcm_atoi(strsep((char**)&str, " ")); - - if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) { - DHD_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode)); - return -1; - } - - macnum = bcm_atoi(strsep((char**)&str, " ")); - if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { - DHD_ERROR(("%s : invalid number of MAC address entries %d\n", - __FUNCTION__, macnum)); - return -1; - } - /* allocate memory for the MAC list */ - list = (struct maclist*)kmalloc(sizeof(int) + - sizeof(struct ether_addr) * macnum, GFP_KERNEL); - if (!list) { - DHD_ERROR(("%s : failed to allocate memory\n", __FUNCTION__)); - return -1; - } - /* prepare the MAC list */ - list->count = htod32(macnum); - bzero((char *)eabuf, ETHER_ADDR_STR_LEN); - for (i = 0; i < list->count; i++) { - strncpy(eabuf, strsep((char**)&str, " "), ETHER_ADDR_STR_LEN - 1); - if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) { - DHD_ERROR(("%s : mac parsing err index=%d, addr=%s\n", - __FUNCTION__, i, eabuf)); - list->count--; - break; - } - DHD_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf)); - } - /* set the list */ - if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0) - DHD_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); - - kfree(list); - - return 0; -} - -/** - * Global function definitions (declared in wl_android.h) - */ - -int wl_android_wifi_on(struct net_device *dev) -{ - int ret = 0; - int retry = POWERUP_MAX_RETRY; - - DHD_ERROR(("%s in\n", __FUNCTION__)); - if (!dev) { - DHD_ERROR(("%s: dev is null\n", __FUNCTION__)); - return -EINVAL; - } - - dhd_net_if_lock(dev); - if (!g_wifi_on) { - do { - dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY); - ret = dhd_net_bus_resume(dev, 0); - if (ret == 0) - break; - DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n", - retry+1)); - dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); - } while (retry-- >= 0); - if (ret != 0) { - DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n")); - goto exit; - } - ret = dhd_net_bus_devreset(dev, FALSE); - dhd_net_bus_resume(dev, 1); - if (!ret) { - if (dhd_dev_init_ioctl(dev) < 0) - ret = -EFAULT; - } - g_wifi_on = TRUE; - } - -exit: - dhd_net_if_unlock(dev); - - return ret; -} - -int wl_android_wifi_off(struct net_device *dev) -{ - int ret = 0; - - DHD_ERROR(("%s in\n", __FUNCTION__)); - if (!dev) { - DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); - return -EINVAL; - } - - dhd_net_if_lock(dev); - if (g_wifi_on) { - ret = dhd_net_bus_devreset(dev, TRUE); - dhd_net_bus_suspend(dev); - dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); - g_wifi_on = FALSE; - } - dhd_net_if_unlock(dev); - - return ret; -} - -static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len) -{ - if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN) - return -1; - return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1); -} - -#ifdef CONNECTION_STATISTICS -static int -wl_chanim_stats(struct net_device *dev, u8 *chan_idle) -{ - int err; - wl_chanim_stats_t *list; - /* Parameter _and_ returned buffer of chanim_stats. */ - wl_chanim_stats_t param; - u8 result[WLC_IOCTL_SMLEN]; - chanim_stats_t *stats; - - memset(¶m, 0, sizeof(param)); - - param.buflen = htod32(sizeof(wl_chanim_stats_t)); - param.count = htod32(WL_CHANIM_COUNT_ONE); - - if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)¶m, sizeof(wl_chanim_stats_t), - (char*)result, sizeof(result), 0)) < 0) { - WL_ERR(("Failed to get chanim results %d \n", err)); - return err; - } - - list = (wl_chanim_stats_t*)result; - - list->buflen = dtoh32(list->buflen); - list->version = dtoh32(list->version); - list->count = dtoh32(list->count); - - if (list->buflen == 0) { - list->version = 0; - list->count = 0; - } else if (list->version != WL_CHANIM_STATS_VERSION) { - WL_ERR(("Sorry, firmware has wl_chanim_stats version %d " - "but driver supports only version %d.\n", - list->version, WL_CHANIM_STATS_VERSION)); - list->buflen = 0; - list->count = 0; - } - - stats = list->stats; - stats->glitchcnt = dtoh32(stats->glitchcnt); - stats->badplcp = dtoh32(stats->badplcp); - stats->chanspec = dtoh16(stats->chanspec); - stats->timestamp = dtoh32(stats->timestamp); - stats->chan_idle = dtoh32(stats->chan_idle); - - WL_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n", - stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle, - stats->timestamp)); - - *chan_idle = stats->chan_idle; - - return (err); -} - -static int -wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len) -{ - wl_cnt_t* cnt = NULL; -#ifndef DISABLE_IF_COUNTERS - wl_if_stats_t* if_stats = NULL; -#endif /* DISABLE_IF_COUNTERS */ - - int link_speed = 0; - struct connection_stats *output; - unsigned int bufsize = 0; - int bytes_written = -1; - int ret = 0; - - WL_INFO(("%s: enter Get Connection Stats\n", __FUNCTION__)); - - if (total_len <= 0) { - WL_ERR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len)); - goto error; - } - - bufsize = total_len; - if (bufsize < sizeof(struct connection_stats)) { - WL_ERR(("%s: not enough buffer size, provided=%u, requires=%zu\n", - __FUNCTION__, bufsize, - sizeof(struct connection_stats))); - goto error; - } - - output = (struct connection_stats *)command; - -#ifndef DISABLE_IF_COUNTERS - if ((if_stats = kmalloc(sizeof(*if_stats), GFP_KERNEL)) == NULL) { - WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); - goto error; - } - ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0, - (char *)if_stats, sizeof(*if_stats), NULL); - if (ret) { - WL_ERR(("%s: if_counters not supported ret=%d\n", - __FUNCTION__, ret)); - - /* In case if_stats IOVAR is not supported, get information from counters. */ -#endif /* DISABLE_IF_COUNTERS */ - if ((cnt = kmalloc(sizeof(*cnt), GFP_KERNEL)) == NULL) { - WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); - goto error; - } - - ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, - (char *)cnt, sizeof(wl_cnt_t), NULL); - if (ret) { - WL_ERR(("%s: wldev_iovar_getbuf() failed, ret=%d\n", - __FUNCTION__, ret)); - goto error; - } - - if (dtoh16(cnt->version) > WL_CNT_T_VERSION) { - WL_ERR(("%s: incorrect version of wl_cnt_t, expected=%u got=%u\n", - __FUNCTION__, WL_CNT_T_VERSION, cnt->version)); - goto error; - } - - output->txframe = dtoh32(cnt->txframe); - output->txbyte = dtoh32(cnt->txbyte); - output->txerror = dtoh32(cnt->txerror); - output->rxframe = dtoh32(cnt->rxframe); - output->rxbyte = dtoh32(cnt->rxbyte); - output->txfail = dtoh32(cnt->txfail); - output->txretry = dtoh32(cnt->txretry); - output->txretrie = dtoh32(cnt->txretrie); - output->txrts = dtoh32(cnt->txrts); - output->txnocts = dtoh32(cnt->txnocts); - output->txexptime = dtoh32(cnt->txexptime); -#ifndef DISABLE_IF_COUNTERS - } else { - /* Populate from if_stats. */ - if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) { - WL_ERR(("%s: incorrect version of wl_if_stats_t, expected=%u got=%u\n", - __FUNCTION__, WL_IF_STATS_T_VERSION, if_stats->version)); - goto error; - } - - output->txframe = (uint32)dtoh64(if_stats->txframe); - output->txbyte = (uint32)dtoh64(if_stats->txbyte); - output->txerror = (uint32)dtoh64(if_stats->txerror); - output->rxframe = (uint32)dtoh64(if_stats->rxframe); - output->rxbyte = (uint32)dtoh64(if_stats->rxbyte); - output->txfail = (uint32)dtoh64(if_stats->txfail); - output->txretry = (uint32)dtoh64(if_stats->txretry); - output->txretrie = (uint32)dtoh64(if_stats->txretrie); - if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) { - output->txexptime = (uint32)dtoh64(if_stats->txexptime); - output->txrts = (uint32)dtoh64(if_stats->txrts); - output->txnocts = (uint32)dtoh64(if_stats->txnocts); - } else { - output->txexptime = 0; - output->txrts = 0; - output->txnocts = 0; - } - } -#endif /* DISABLE_IF_COUNTERS */ - - /* link_speed is in kbps */ - ret = wldev_get_link_speed(dev, &link_speed); - if (ret || link_speed < 0) { - WL_ERR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n", - __FUNCTION__, ret, link_speed)); - goto error; - } - output->txrate = link_speed; - - /* Channel idle ratio. */ - if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) { - output->chan_idle = 0; - }; - - bytes_written = sizeof(struct connection_stats); - -error: -#ifndef DISABLE_IF_COUNTERS - if (if_stats) { - kfree(if_stats); - } -#endif /* DISABLE_IF_COUNTERS */ - if (cnt) { - kfree(cnt); - } - - return bytes_written; -} -#endif /* CONNECTION_STATISTICS */ - -static int -wl_android_set_pmk(struct net_device *dev, char *command, int total_len) -{ - uchar pmk[33]; - int error = 0; - char smbuf[WLC_IOCTL_SMLEN]; -#ifdef OKC_DEBUG - int i = 0; -#endif - - bzero(pmk, sizeof(pmk)); - memcpy((char *)pmk, command + strlen("SET_PMK "), 32); - error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL); - if (error) { - DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error)); - } -#ifdef OKC_DEBUG - DHD_ERROR(("PMK is ")); - for (i = 0; i < 32; i++) - DHD_ERROR(("%02X ", pmk[i])); - - DHD_ERROR(("\n")); -#endif - return error; -} - -static int -wl_android_okc_enable(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - char okc_enable = 0; - - okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0'; - error = wldev_iovar_setint(dev, "okc_enable", okc_enable); - if (error) { - DHD_ERROR(("Failed to %s OKC, error = %d\n", - okc_enable ? "enable" : "disable", error)); - } - - wldev_iovar_setint(dev, "ccx_enable", 0); - - return error; -} - - - -int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - int mode = 0; - - if (sscanf(command, "%*s %d", &mode) != 1) { - DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); - return -1; - } - - error = wldev_iovar_setint(dev, "roam_off", mode); - if (error) { - DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n", - __FUNCTION__, mode, error)); - return -1; - } - else - DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n", - __FUNCTION__, mode, error)); - return 0; -} - -int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len) -{ - char ie_buf[VNDR_IE_MAX_LEN]; - char *ioctl_buf = NULL; - char hex[] = "XX"; - char *pcmd = NULL; - int ielen = 0, datalen = 0, idx = 0, tot_len = 0; - vndr_ie_setbuf_t *vndr_ie = NULL; - s32 iecount; - uint32 pktflag; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - s32 err = BCME_OK; - - /* Check the VSIE (Vendor Specific IE) which was added. - * If exist then send IOVAR to delete it - */ - if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) { - return -EINVAL; - } - - pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1; - for (idx = 0; idx < DOT11_OUI_LEN; idx++) { - hex[0] = *pcmd++; - hex[1] = *pcmd++; - ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16); - } - pcmd++; - while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) { - hex[0] = *pcmd++; - hex[1] = *pcmd++; - ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16); - datalen++; - } - tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1); - vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags); - if (!vndr_ie) { - WL_ERR(("IE memory alloc failed\n")); - return -ENOMEM; - } - /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ - strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1); - vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - - /* Set the IE count - the buffer contains only 1 IE */ - iecount = htod32(1); - memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32)); - - /* Set packet flag to indicate that BEACON's will contain this IE */ - pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG); - memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, - sizeof(u32)); - /* Set the IE ID */ - vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID; - - memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf, - DOT11_OUI_LEN); - memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, - &ie_buf[DOT11_OUI_LEN], datalen); - - ielen = DOT11_OUI_LEN + datalen; - vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen; - - ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (!ioctl_buf) { - WL_ERR(("ioctl memory alloc failed\n")); - if (vndr_ie) { - kfree(vndr_ie); - } - return -ENOMEM; - } - memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */ - err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - - - if (err != BCME_OK) { - err = -EINVAL; - if (vndr_ie) { - kfree(vndr_ie); - } - } - else { - /* do NOT free 'vndr_ie' for the next process */ - wl_cfg80211_ibss_vsie_set_buffer(vndr_ie, tot_len); - } - - if (ioctl_buf) { - kfree(ioctl_buf); - } - - return err; -} - -#if defined(BCMFW_ROAM_ENABLE) -static int -wl_android_set_roampref(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - char smbuf[WLC_IOCTL_SMLEN]; - uint8 buf[MAX_BUF_SIZE]; - uint8 *pref = buf; - char *pcmd; - int num_ucipher_suites = 0; - int num_akm_suites = 0; - wpa_suite_t ucipher_suites[MAX_NUM_SUITES]; - wpa_suite_t akm_suites[MAX_NUM_SUITES]; - int num_tuples = 0; - int total_bytes = 0; - int total_len_left; - int i, j; - char hex[] = "XX"; - - pcmd = command + strlen(CMD_SET_ROAMPREF) + 1; - total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1; - - num_akm_suites = simple_strtoul(pcmd, NULL, 16); - if (num_akm_suites > MAX_NUM_SUITES) { - DHD_ERROR(("too many AKM suites = %d\n", num_akm_suites)); - return -1; - } - - /* Increment for number of AKM suites field + space */ - pcmd += 3; - total_len_left -= 3; - - /* check to make sure pcmd does not overrun */ - if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE)) - return -1; - - memset(buf, 0, sizeof(buf)); - memset(akm_suites, 0, sizeof(akm_suites)); - memset(ucipher_suites, 0, sizeof(ucipher_suites)); - - /* Save the AKM suites passed in the command */ - for (i = 0; i < num_akm_suites; i++) { - /* Store the MSB first, as required by join_pref */ - for (j = 0; j < 4; j++) { - hex[0] = *pcmd++; - hex[1] = *pcmd++; - buf[j] = (uint8)simple_strtoul(hex, NULL, 16); - } - memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32)); - } - - total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); - num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); - if (num_ucipher_suites > MAX_NUM_SUITES) { - DHD_ERROR(("too many UCIPHER suites = %d\n", num_ucipher_suites)); - return -1; - } - /* Increment for number of cipher suites field + space */ - pcmd += 3; - total_len_left -= 3; - - if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE)) - return -1; - - /* Save the cipher suites passed in the command */ - for (i = 0; i < num_ucipher_suites; i++) { - /* Store the MSB first, as required by join_pref */ - for (j = 0; j < 4; j++) { - hex[0] = *pcmd++; - hex[1] = *pcmd++; - buf[j] = (uint8)simple_strtoul(hex, NULL, 16); - } - memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32)); - } - - /* Join preference for RSSI - * Type : 1 byte (0x01) - * Length : 1 byte (0x02) - * Value : 2 bytes (reserved) - */ - *pref++ = WL_JOIN_PREF_RSSI; - *pref++ = JOIN_PREF_RSSI_LEN; - *pref++ = 0; - *pref++ = 0; - - /* Join preference for WPA - * Type : 1 byte (0x02) - * Length : 1 byte (not used) - * Value : (variable length) - * reserved: 1 byte - * count : 1 byte (no of tuples) - * Tuple1 : 12 bytes - * akm[4] - * ucipher[4] - * mcipher[4] - * Tuple2 : 12 bytes - * Tuplen : 12 bytes - */ - num_tuples = num_akm_suites * num_ucipher_suites; - if (num_tuples != 0) { - if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) { - *pref++ = WL_JOIN_PREF_WPA; - *pref++ = 0; - *pref++ = 0; - *pref++ = (uint8)num_tuples; - total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + - (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples); - } else { - DHD_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__)); - return -1; - } - } else { - /* No WPA config, configure only RSSI preference */ - total_bytes = JOIN_PREF_RSSI_SIZE; - } - - /* akm-ucipher-mcipher tuples in the format required for join_pref */ - for (i = 0; i < num_ucipher_suites; i++) { - for (j = 0; j < num_akm_suites; j++) { - memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN); - pref += WPA_SUITE_LEN; - memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN); - pref += WPA_SUITE_LEN; - /* Set to 0 to match any available multicast cipher */ - memset(pref, 0, WPA_SUITE_LEN); - pref += WPA_SUITE_LEN; - } - } - - prhex("join pref", (uint8 *)buf, total_bytes); - error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL); - if (error) { - DHD_ERROR(("Failed to set join_pref, error = %d\n", error)); - } - return error; -} -#endif /* defined(BCMFW_ROAM_ENABLE */ - -static int -wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config) -{ - struct io_cfg *resume_cfg; - s32 ret; - - resume_cfg = kzalloc(sizeof(struct io_cfg), GFP_KERNEL); - if (!resume_cfg) - return -ENOMEM; - - if (config->iovar) { - ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param); - if (ret) { - DHD_ERROR(("%s: Failed to get current %s value\n", - __FUNCTION__, config->iovar)); - goto error; - } - - ret = wldev_iovar_setint(dev, config->iovar, config->param); - if (ret) { - DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, - config->iovar, config->param)); - goto error; - } - - resume_cfg->iovar = config->iovar; - } else { - resume_cfg->arg = kzalloc(config->len, GFP_KERNEL); - if (!resume_cfg->arg) { - ret = -ENOMEM; - goto error; - } - ret = wldev_ioctl(dev, config->ioctl, resume_cfg->arg, config->len, false); - if (ret) { - DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__, - config->ioctl)); - goto error; - } - ret = wldev_ioctl(dev, config->ioctl + 1, config->arg, config->len, true); - if (ret) { - DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, - config->iovar, config->param)); - goto error; - } - if (config->ioctl + 1 == WLC_SET_PM) - wl_cfg80211_update_power_mode(dev); - resume_cfg->ioctl = config->ioctl; - resume_cfg->len = config->len; - } - - list_add(&resume_cfg->list, head); - - return 0; -error: - kfree(resume_cfg->arg); - kfree(resume_cfg); - return ret; -} - -static void -wl_android_iolist_resume(struct net_device *dev, struct list_head *head) -{ - struct io_cfg *config; - struct list_head *cur, *q; - s32 ret = 0; - - list_for_each_safe(cur, q, head) { - config = list_entry(cur, struct io_cfg, list); - if (config->iovar) { - if (!ret) - ret = wldev_iovar_setint(dev, config->iovar, - config->param); - } else { - if (!ret) - ret = wldev_ioctl(dev, config->ioctl + 1, - config->arg, config->len, true); - if (config->ioctl + 1 == WLC_SET_PM) - wl_cfg80211_update_power_mode(dev); - kfree(config->arg); - } - list_del(cur); - kfree(config); - } -} - -static int -wl_android_set_miracast(struct net_device *dev, char *command, int total_len) -{ - int mode, val = 0; - int ret = 0; - struct io_cfg config; -#ifdef CHANGE_SCAN_TIME - int i; -#endif - - if (sscanf(command, "%*s %d", &mode) != 1) { - DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); - return -1; - } - - DHD_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode)); - - if (miracast_cur_mode == mode) - return 0; - - wl_android_iolist_resume(dev, &miracast_resume_list); - miracast_cur_mode = MIRACAST_MODE_OFF; - - switch (mode) { - case MIRACAST_MODE_SOURCE: - /* setting mchan_algo to platform specific value */ - config.iovar = "mchan_algo"; - - ret = wldev_ioctl(dev, WLC_GET_BCNPRD, &val, sizeof(int), false); - if (!ret && val > 100) { - config.param = 0; - DHD_ERROR(("%s: Connected station's beacon interval: " - "%d and set mchan_algo to %d \n", - __FUNCTION__, val, config.param)); - } - else { - config.param = MIRACAST_MCHAN_ALGO; - } - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) - goto resume; - - /* setting mchan_bw to platform specific value */ - config.iovar = "mchan_bw"; - config.param = MIRACAST_MCHAN_BW; - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) - goto resume; - - /* setting apmdu to platform specific value */ - config.iovar = "ampdu_mpdu"; - config.param = MIRACAST_AMPDU_SIZE; - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) - goto resume; - /* FALLTROUGH */ - /* Source mode shares most configurations with sink mode. - * Fall through here to avoid code duplication - */ - case MIRACAST_MODE_SINK: - /* disable internal roaming */ - config.iovar = "roam_off"; - config.param = 1; - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) - goto resume; - /* tunr off pm */ - val = 0; - config.iovar = NULL; - config.ioctl = WLC_GET_PM; - config.arg = &val; - config.len = sizeof(int); - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) - goto resume; - -#ifdef CHANGE_SCAN_TIME - for (int i = 0; i < sizeof(miracast_scan_time) / sizeof(miracast_scan_time[0]); i++) { - config.iovar = NULL; - config.ioctl = miracast_scan_time[i][0]; - config.arg = &miracast_scan_time[i][1]; - config.len = sizeof(int); - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) { - goto resume; - } - } -#endif - - break; - case MIRACAST_MODE_OFF: - default: - break; - } - miracast_cur_mode = mode; - - return 0; - -resume: - DHD_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret)); - wl_android_iolist_resume(dev, &miracast_resume_list); - return ret; -} - -#define NETLINK_OXYGEN 30 -#define AIBSS_BEACON_TIMEOUT 10 - -static struct sock *nl_sk = NULL; - -static void wl_netlink_recv(struct sk_buff *skb) -{ - WL_ERR(("netlink_recv called\n")); -} - -static int wl_netlink_init(void) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - struct netlink_kernel_cfg cfg = { - .input = wl_netlink_recv, - }; -#endif - - if (nl_sk != NULL) { - WL_ERR(("nl_sk already exist\n")); - return BCME_ERROR; - } - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) - nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, - 0, wl_netlink_recv, NULL, THIS_MODULE); -#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) - nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg); -#else - nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg); -#endif - - if (nl_sk == NULL) { - WL_ERR(("nl_sk is not ready\n")); - return BCME_ERROR; - } - - return BCME_OK; -} - -static void wl_netlink_deinit(void) -{ - if (nl_sk) { - netlink_kernel_release(nl_sk); - nl_sk = NULL; - } -} - -s32 -wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size) -{ - struct sk_buff *skb = NULL; - struct nlmsghdr *nlh = NULL; - int ret = -1; - - if (nl_sk == NULL) { - WL_ERR(("nl_sk was not initialized\n")); - goto nlmsg_failure; - } - - skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC); - if (skb == NULL) { - WL_ERR(("failed to allocate memory\n")); - goto nlmsg_failure; - } - - nlh = nlmsg_put(skb, 0, 0, 0, size, 0); - if (nlh == NULL) { - WL_ERR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n", - skb_tailroom(skb), nlmsg_total_size(size))); - dev_kfree_skb(skb); - goto nlmsg_failure; - } - - memcpy(nlmsg_data(nlh), data, size); - nlh->nlmsg_seq = seq; - nlh->nlmsg_type = type; - - /* netlink_unicast() takes ownership of the skb and frees it itself. */ - ret = netlink_unicast(nl_sk, skb, pid, 0); - WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret)); - -nlmsg_failure: - return ret; -} - -#ifdef WLAIBSS -static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len) -{ - int err = 0; - int retry = 0; - int pid = 0; - aibss_txfail_config_t txfail_config = {0, 0, 0, 0}; - char smbuf[WLC_IOCTL_SMLEN]; - - if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) { - WL_ERR(("Failed to get Parameter from : %s\n", command)); - return -1; - } - - /* set pid, and if the event was happened, let's send a notification through netlink */ - wl_cfg80211_set_txfail_pid(pid); - - /* If retry value is 0, it disables the functionality for TX Fail. */ - if (retry > 0) { - txfail_config.max_tx_retry = retry; - txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */ - } - txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0; - txfail_config.len = sizeof(txfail_config); - - err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config, - sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL); - WL_DBG(("retry=%d, pid=%d, err=%d\n", retry, pid, err)); - - return ((err == 0)?total_len:err); -} - -static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command, - int total_len, bool bAll) -{ - int error; - int bytes_written = 0; - void *buf = NULL; - bss_peer_list_info_t peer_list_info; - bss_peer_info_t *peer_info; - int i; - bool found = false; - struct ether_addr mac_ea; - - WL_DBG(("get ibss peer info(%s)\n", bAll?"true":"false")); - - if (!bAll) { - if (sscanf (command, "GETIBSSPEERINFO %02x:%02x:%02x:%02x:%02x:%02x", - (unsigned int *)&mac_ea.octet[0], (unsigned int *)&mac_ea.octet[1], - (unsigned int *)&mac_ea.octet[2], (unsigned int *)&mac_ea.octet[3], - (unsigned int *)&mac_ea.octet[4], (unsigned int *)&mac_ea.octet[5]) != 6) { - WL_DBG(("invalid MAC address\n")); - return -1; - } - } - - if ((buf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL)) == NULL) { - WL_ERR(("kmalloc failed\n")); - return -1; - } - - error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL); - if (unlikely(error)) { - WL_ERR(("could not get ibss peer info (%d)\n", error)); - kfree(buf); - return -1; - } - - memcpy(&peer_list_info, buf, sizeof(peer_list_info)); - peer_list_info.version = htod16(peer_list_info.version); - peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len); - peer_list_info.count = htod32(peer_list_info.count); - - WL_DBG(("ver:%d, len:%d, count:%d\n", peer_list_info.version, - peer_list_info.bss_peer_info_len, peer_list_info.count)); - - if (peer_list_info.count > 0) { - if (bAll) - bytes_written += sprintf(&command[bytes_written], "%u ", - peer_list_info.count); - - peer_info = (bss_peer_info_t *) ((void *)buf + BSS_PEER_LIST_INFO_FIXED_LEN); - - - for (i = 0; i < peer_list_info.count; i++) { - - WL_DBG(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi, - peer_info->tx_rate, peer_info->rx_rate)); - - if (!bAll && - memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) { - found = true; - } - - if (bAll || found) { - bytes_written += sprintf(&command[bytes_written], MACF, - ETHER_TO_MACF(peer_info->ea)); - bytes_written += sprintf(&command[bytes_written], " %u %d ", - peer_info->tx_rate/1000, peer_info->rssi); - } - - if (found) - break; - - peer_info = (bss_peer_info_t *)((void *)peer_info+sizeof(bss_peer_info_t)); - } - } - else { - WL_ERR(("could not get ibss peer info : no item\n")); - } - bytes_written += sprintf(&command[bytes_written], "%s", "\0"); - - WL_DBG(("command(%u):%s\n", total_len, command)); - WL_DBG(("bytes_written:%d\n", bytes_written)); - - kfree(buf); - return bytes_written; -} - -int wl_android_set_ibss_routetable(struct net_device *dev, char *command, int total_len) -{ - - char *pcmd = command; - char *str = NULL; - - ibss_route_tbl_t *route_tbl = NULL; - char *ioctl_buf = NULL; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - s32 err = BCME_OK; - uint32 route_tbl_len; - uint32 entries; - char *endptr; - uint32 i = 0; - struct ipv4_addr dipaddr; - struct ether_addr ea; - - route_tbl_len = sizeof(ibss_route_tbl_t) + - (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t); - route_tbl = (ibss_route_tbl_t *)kzalloc(route_tbl_len, kflags); - if (!route_tbl) { - WL_ERR(("Route TBL alloc failed\n")); - return -ENOMEM; - } - ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (!ioctl_buf) { - WL_ERR(("ioctl memory alloc failed\n")); - if (route_tbl) { - kfree(route_tbl); - } - return -ENOMEM; - } - memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); - - /* drop command */ - str = bcmstrtok(&pcmd, " ", NULL); - - /* get count */ - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - WL_ERR(("Invalid number parameter %s\n", str)); - err = -EINVAL; - goto exit; - } - entries = bcm_strtoul(str, &endptr, 0); - if (*endptr != '\0') { - WL_ERR(("Invalid number parameter %s\n", str)); - err = -EINVAL; - goto exit; - } - WL_INFO(("Routing table count:%d\n", entries)); - route_tbl->num_entry = entries; - - for (i = 0; i < entries; i++) { - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_atoipv4(str, &dipaddr)) { - WL_ERR(("Invalid ip string %s\n", str)); - err = -EINVAL; - goto exit; - } - - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_ether_atoe(str, &ea)) { - WL_ERR(("Invalid ethernet string %s\n", str)); - err = -EINVAL; - goto exit; - } - bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN); - bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN); - } - - route_tbl_len = sizeof(ibss_route_tbl_t) + - ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t)); - err = wldev_iovar_setbuf(dev, "ibss_route_tbl", - route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (err != BCME_OK) { - WL_ERR(("Fail to set iovar %d\n", err)); - err = -EINVAL; - } - -exit: - if (route_tbl) - kfree(route_tbl); - if (ioctl_buf) - kfree(ioctl_buf); - return err; - -} - -int wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len) -{ - char *pcmd = command; - char *str = NULL, *endptr = NULL; - int category[4]; - int tid2category[NUMPRIO] = {2, 3, 3, 2, 1, 1, 0, 0}; - struct ampdu_tid_control_mode control; - char smbuf[WLC_IOCTL_SMLEN]; - int idx; - int err = 0; - - WL_DBG(("set ibss ampdu:%s\n", command)); - - /* acquire parameters */ - /* drop command */ - str = bcmstrtok(&pcmd, " ", NULL); - - for (idx = 0; idx < 4; idx++) { - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - WL_ERR(("Invalid parameter : %s\n", pcmd)); - return -EINVAL; - } - category[idx] = bcm_strtoul(str, &endptr, 0); - if (*endptr != '\0') { - WL_ERR(("Invalid number format %s\n", str)); - return -EINVAL; - } - } - sprintf(control.mode_name, "AIBSS"); - for (idx = 0; idx < NUMPRIO; idx++) { - control.control[idx].tid = idx; - control.control[idx].enable = category[tid2category[idx]]; - } - - err = wldev_iovar_setbuf(dev, "ampdu_tid_mode", (void *) &control, - sizeof(struct ampdu_tid_control_mode), smbuf, WLC_IOCTL_SMLEN, NULL); - return ((err == 0)?total_len:err); -} - -int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len) -{ - char *pcmd = command; - char *str = NULL; - int txchain, rxchain; - int err = 0; - - WL_DBG(("set ibss antenna:%s\n", command)); - - /* acquire parameters */ - /* drop command */ - str = bcmstrtok(&pcmd, " ", NULL); - - /* TX chain */ - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - WL_ERR(("Invalid parameter : %s\n", pcmd)); - return -EINVAL; - } - txchain = bcm_atoi(str); - - /* RX chain */ - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - WL_ERR(("Invalid parameter : %s\n", pcmd)); - return -EINVAL; - } - rxchain = bcm_atoi(str); - - err = wldev_iovar_setint(dev, "txchain", txchain); - if (err != 0) - return err; - err = wldev_iovar_setint(dev, "rxchain", rxchain); - return ((err == 0)?total_len:err); -} -#endif /* WLAIBSS */ - -int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len) -{ - wl_mkeep_alive_pkt_t mkeep_alive_pkt; - int ret; - uint period_msec = 0; - char *buf; - - if (extra == NULL) - { - DHD_ERROR(("%s: extra is NULL\n", __FUNCTION__)); - return -1; - } - if (sscanf(extra, "%d", &period_msec) != 1) - { - DHD_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__)); - return -EINVAL; - } - DHD_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec)); - - memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - - mkeep_alive_pkt.period_msec = period_msec; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - - /* Setup keep alive zero for null packet generation */ - mkeep_alive_pkt.keep_alive_id = 0; - mkeep_alive_pkt.len_bytes = 0; - - buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); - if (!buf) { - DHD_ERROR(("%s: buffer alloc failed\n", __FUNCTION__)); - return BCME_NOMEM; - } - ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt, - WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL); - if (ret < 0) - DHD_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret)); - else - DHD_TRACE(("%s:keep_alive set ok\n", __FUNCTION__)); - kfree(buf); - return ret; -} - -int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) -{ -#define PRIVATE_COMMAND_MAX_LEN 8192 -#define PRIVATE_COMMAND_DEF_LEN 4096 - int ret = 0; - char *command = NULL; - int bytes_written = 0; - android_wifi_priv_cmd priv_cmd; - int buf_size = 0; - - net_os_wake_lock(net); - - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto exit; - } - - if (!ifr->ifr_data) { - ret = -EINVAL; - goto exit; - } - -#ifdef CONFIG_COMPAT - if (is_compat_task()) { - compat_android_wifi_priv_cmd compat_priv_cmd; - if (copy_from_user(&compat_priv_cmd, ifr->ifr_data, - sizeof(compat_android_wifi_priv_cmd))) { - ret = -EFAULT; - goto exit; - - } - priv_cmd.buf = compat_ptr(compat_priv_cmd.buf); - priv_cmd.used_len = compat_priv_cmd.used_len; - priv_cmd.total_len = compat_priv_cmd.total_len; - } else -#endif /* CONFIG_COMPAT */ - { - if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) { - ret = -EFAULT; - goto exit; - } - } - if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) { - DHD_ERROR(("%s: invalid length of private command : %d \n", - __FUNCTION__, priv_cmd.total_len)); - ret = -EINVAL; - goto exit; - } - - if (priv_cmd.total_len < PRIVATE_COMMAND_DEF_LEN) { - buf_size = PRIVATE_COMMAND_DEF_LEN; - } else { - buf_size = priv_cmd.total_len; - } - - command = kmalloc((buf_size + 1), GFP_KERNEL); - - if (!command) - { - DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__)); - ret = -ENOMEM; - goto exit; - } - if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { - ret = -EFAULT; - goto exit; - } - command[priv_cmd.total_len] = '\0'; - - DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); - - if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { - DHD_INFO(("%s, Received regular START command\n", __FUNCTION__)); - bytes_written = wl_android_wifi_on(net); - } - else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) { - bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len); - } - - if (!g_wifi_on) { - DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n", - __FUNCTION__, command, ifr->ifr_name)); - ret = 0; - goto exit; - } - - if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) { - bytes_written = wl_android_wifi_off(net); - } - else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { - /* TBD: SCAN-ACTIVE */ - } - else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) { - /* TBD: SCAN-PASSIVE */ - } - else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) { - bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { - bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len); - } -#ifdef PKT_FILTER_SUPPORT - else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) { - bytes_written = net_os_enable_packet_filter(net, 1); - } - else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) { - bytes_written = net_os_enable_packet_filter(net, 0); - } - else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) { - int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; - bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num); - } - else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) { - int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; - bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); - } -#endif /* PKT_FILTER_SUPPORT */ - else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { - /* TBD: BTCOEXSCAN-START */ - } - else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) { - /* TBD: BTCOEXSCAN-STOP */ - } - else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { -#ifdef WL_CFG80211 - void *dhdp = wl_cfg80211_get_dhdp(); - bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command); -#else -#ifdef PKT_FILTER_SUPPORT - uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; - - if (mode == 1) - net_os_enable_packet_filter(net, 0); /* DHCP starts */ - else - net_os_enable_packet_filter(net, 1); /* DHCP ends */ -#endif /* PKT_FILTER_SUPPORT */ -#endif /* WL_CFG80211 */ - } - else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { - bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { - bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { - uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; - bytes_written = wldev_set_band(net, band); - } - else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { - bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); - } -#ifdef WL_CFG80211 - /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ - else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { - char *country_code = command + strlen(CMD_COUNTRY) + 1; -#ifdef CUSTOMER_HW5 - /* Customer_hw5 want to keep connections */ - bytes_written = wldev_set_country(net, country_code, true, false); -#else - bytes_written = wldev_set_country(net, country_code, true, true); -#endif - } -#endif /* WL_CFG80211 */ - - -#ifdef PNO_SUPPORT - else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { - bytes_written = dhd_dev_pno_stop_for_ssid(net); - } -#ifndef WL_SCHED_SCAN - else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { - bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len); - } -#endif /* !WL_SCHED_SCAN */ - else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { - int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; - bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net); - } - else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) { - bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len); - } -#endif /* PNO_SUPPORT */ - else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { - bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) { - int skip = strlen(CMD_P2P_SET_NOA) + 1; - bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, - priv_cmd.total_len - skip); - } -#ifdef WL_NAN - else if (strnicmp(command, CMD_NAN, strlen(CMD_NAN)) == 0) { - bytes_written = wl_cfg80211_nan_cmd_handler(net, command, - priv_cmd.total_len); - } -#endif /* WL_NAN */ -#if !defined WL_ENABLE_P2P_IF - else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { - bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); - } -#endif /* WL_ENABLE_P2P_IF */ - else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { - int skip = strlen(CMD_P2P_SET_PS) + 1; - bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, - priv_cmd.total_len - skip); - } -#ifdef WL_CFG80211 - else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE, - strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) { - int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3; - bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, - priv_cmd.total_len - skip, *(command + skip - 2) - '0'); - } -#ifdef WLFBT - else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) { - wl_cfg80211_get_fbt_key(command); - bytes_written = FBT_KEYLEN; - } -#endif /* WLFBT */ -#endif /* WL_CFG80211 */ - else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) - bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) - bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); -#ifdef BCMCCX - else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) { - bytes_written = wl_android_get_cckm_rn(net, command); - } - else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) { - bytes_written = wl_android_set_cckm_krk(net, command); - } - else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) { - bytes_written = wl_android_get_assoc_res_ies(net, command); - } -#endif /* BCMCCX */ -#if defined(WL_SUPPORT_AUTO_CHANNEL) - else if (strnicmp(command, CMD_GET_BEST_CHANNELS, - strlen(CMD_GET_BEST_CHANNELS)) == 0) { - bytes_written = wl_cfg80211_get_best_channels(net, command, - priv_cmd.total_len); - } -#endif /* WL_SUPPORT_AUTO_CHANNEL */ - else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) { - int skip = strlen(CMD_HAPD_MAC_FILTER) + 1; - wl_android_set_mac_address_filter(net, (const char*)command+skip); - } - else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0) - bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len); -#if defined(BCMFW_ROAM_ENABLE) - else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) { - bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len); - } -#endif /* BCMFW_ROAM_ENABLE */ - else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) - bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0) - bytes_written = wl_android_set_ibss_beacon_ouidata(net, - command, priv_cmd.total_len); -#ifdef WLAIBSS - else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT, - strlen(CMD_SETIBSSTXFAILEVENT)) == 0) - bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL, - strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0) - bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, - TRUE); - else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO, - strlen(CMD_GET_IBSS_PEER_INFO)) == 0) - bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, - FALSE); - else if (strnicmp(command, CMD_SETIBSSROUTETABLE, - strlen(CMD_SETIBSSROUTETABLE)) == 0) - bytes_written = wl_android_set_ibss_routetable(net, command, - priv_cmd.total_len); - else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0) - bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0) - bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len); -#endif /* WLAIBSS */ - else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) { - int skip = strlen(CMD_KEEP_ALIVE) + 1; - bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip); - } - else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) { - int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0'; - bytes_written = wl_cfg80211_enable_roam_offload(net, enable); - } -#ifdef CONNECTION_STATISTICS - else if (strnicmp(command, CMD_GET_CONNECTION_STATS, - strlen(CMD_GET_CONNECTION_STATS)) == 0) { - bytes_written = wl_android_get_connection_stats(net, command, - priv_cmd.total_len); - } -#endif - else { - DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); - snprintf(command, 5, "FAIL"); - bytes_written = strlen("FAIL"); - } - - if (bytes_written >= 0) { - if ((bytes_written == 0) && (priv_cmd.total_len > 0)) { - command[0] = '\0'; - } - if (bytes_written >= priv_cmd.total_len) { - DHD_ERROR(("%s: not enough for output. bytes_written:%d >= total_len:%d \n", - __FUNCTION__, bytes_written, priv_cmd.total_len)); - ret = BCME_BUFTOOSHORT; - goto exit; - } else { - bytes_written++; - } - priv_cmd.used_len = bytes_written; - if (copy_to_user(priv_cmd.buf, command, bytes_written)) { - DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); - ret = -EFAULT; - } - } - else { - ret = bytes_written; - } - -exit: - net_os_wake_unlock(net); - if (command) { - kfree(command); - } - - return ret; -} - -int wl_android_init(void) -{ - int ret = 0; - -#ifdef ENABLE_INSMOD_NO_FW_LOAD - dhd_download_fw_on_driverload = FALSE; -#endif /* ENABLE_INSMOD_NO_FW_LOAD */ -#if defined(CUSTOMER_HW2) - if (!iface_name[0]) { - memset(iface_name, 0, IFNAMSIZ); - bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); - } -#endif - - wl_netlink_init(); - - return ret; -} - -int wl_android_exit(void) -{ - int ret = 0; - struct io_cfg *cur, *q; - - wl_netlink_deinit(); - - list_for_each_entry_safe(cur, q, &miracast_resume_list, list) { - list_del(&cur->list); - kfree(cur); - } - - return ret; -} - -void wl_android_post_init(void) -{ - -#ifdef ENABLE_4335BT_WAR - bcm_bt_unlock(lock_cookie_wifi); - printk("%s: btlock released\n", __FUNCTION__); -#endif /* ENABLE_4335BT_WAR */ - - if (!dhd_download_fw_on_driverload) - g_wifi_on = FALSE; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_android.h b/drivers/net/wireless/bcmdhd_suzuran/wl_android.h deleted file mode 100755 index 1045e6ea2e32..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_android.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Linux cfg80211 driver - Android related functions - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_android.h 516345 2014-11-19 11:58:57Z $ - */ - -#include -#include -#include - -/* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL - * automatically - */ -#if defined(WL_NAN) -#define WL_GENL -#endif - - - -/** - * Android platform dependent functions, feel free to add Android specific functions here - * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd - * or cfg, define them as static in wl_android.c - */ - -/** - * wl_android_init will be called from module init function (dhd_module_init now), similarly - * wl_android_exit will be called from module exit function (dhd_module_cleanup now) - */ -int wl_android_init(void); -int wl_android_exit(void); -void wl_android_post_init(void); -int wl_android_wifi_on(struct net_device *dev); -int wl_android_wifi_off(struct net_device *dev); -int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); - -s32 wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size); - -/* hostap mac mode */ -#define MACLIST_MODE_DISABLED 0 -#define MACLIST_MODE_DENY 1 -#define MACLIST_MODE_ALLOW 2 - -/* max number of assoc list */ -#define MAX_NUM_OF_ASSOCLIST 64 - -/* max number of mac filter list - * restrict max number to 10 as maximum cmd string size is 255 - */ -#define MAX_NUM_MAC_FILT 10 - -int wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist); diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c deleted file mode 100755 index cff5b0b42ac4..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ /dev/null @@ -1,13226 +0,0 @@ -/* - * Linux cfg80211 driver - * - * Copyright (C) 1999-2018, Broadcom Corporation - * Copyright (C) 2015 Sony Mobile Communications Inc. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.c 751081 2018-03-09 08:06:41Z $ - */ -/* */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#ifdef PNO_SUPPORT -#include -#endif /* PNO_SUPPORT */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifdef WL_NAN -#include -#endif /* WL_NAN */ -#ifdef PROP_TXSTATUS -#include -#endif - -#include -#ifdef WL11U -#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) -#error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \ - according to Kernel version and is supported only in Android-JB -#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ -#endif /* WL11U */ - -#ifdef BCMWAPI_WPI -/* these items should evetually go into wireless.h of the linux system headfile dir */ -#ifndef IW_ENCODE_ALG_SM4 -#define IW_ENCODE_ALG_SM4 0x20 -#endif - -#ifndef IW_AUTH_WAPI_ENABLED -#define IW_AUTH_WAPI_ENABLED 0x20 -#endif - -#ifndef IW_AUTH_WAPI_VERSION_1 -#define IW_AUTH_WAPI_VERSION_1 0x00000008 -#endif - -#ifndef IW_AUTH_CIPHER_SMS4 -#define IW_AUTH_CIPHER_SMS4 0x00000020 -#endif - -#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK -#define IW_AUTH_KEY_MGMT_WAPI_PSK 4 -#endif - -#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT -#define IW_AUTH_KEY_MGMT_WAPI_CERT 8 -#endif -#endif /* BCMWAPI_WPI */ - -#ifdef BCMWAPI_WPI -#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) -#else /* BCMWAPI_WPI */ -#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) -#endif /* BCMWAPI_WPI */ - -static struct device *cfg80211_parent_dev = NULL; -/* g_bcm_cfg should be static. Do not change */ -static struct bcm_cfg80211 *g_bcm_cfg = NULL; -u32 wl_dbg_level = WL_DBG_ERR; - -#define MAX_WAIT_TIME 1500 - -#ifdef VSDB -/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */ -#define DEFAULT_SLEEP_TIME_VSDB 120 -#define OFF_CHAN_TIME_THRESHOLD_MS 200 -#define AF_RETRY_DELAY_TIME 40 - -/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */ -#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \ - do { \ - if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \ - wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \ - OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \ - } \ - } while (0) -#else /* VSDB */ -/* if not VSDB, do nothing */ -#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) -#endif /* VSDB */ - -#ifdef WL_CFG80211_SYNC_GON -#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) \ - (wl_get_drv_status_all(cfg, SENDING_ACT_FRM) || \ - wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) -#else -#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) wl_get_drv_status_all(cfg, SENDING_ACT_FRM) -#endif /* WL_CFG80211_SYNC_GON */ -#define WL_IS_P2P_DEV_EVENT(e) ((e->emsg.ifidx == 0) && \ - (e->emsg.bsscfgidx == P2PAPI_BSSCFG_DEVICE)) - -#define DNGL_FUNC(func, parameters) func parameters -#define COEX_DHCP - -#define WLAN_EID_SSID 0 -#define CH_MIN_5G_CHANNEL 34 -#define CH_MIN_2G_CHANNEL 1 - -#ifdef WLAIBSS -enum abiss_event_type { - AIBSS_EVENT_TXFAIL -}; -#endif - -enum rmc_event_type { - RMC_EVENT_NONE, - RMC_EVENT_LEADER_CHECK_FAIL -}; - -/* This is to override regulatory domains defined in cfg80211 module (reg.c) - * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN - * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165). - * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels. - * All the chnages in world regulatory domain are to be done here. - */ -static const struct ieee80211_regdomain brcm_regdom = { - .n_reg_rules = 4, - .alpha2 = "99", - .reg_rules = { - /* IEEE 802.11b/g, channels 1..11 */ - REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), - /* If any */ - /* IEEE 802.11 channel 14 - Only JP enables - * this and for 802.11b only - */ - REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), - /* IEEE 802.11a, channel 36..64 */ - REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), - /* IEEE 802.11a, channel 100..165 */ - REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } -}; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) -/* - * Possible interface combinations supported by driver - * - * ADHOC Mode - #ADHOC <= 1 on channels = 1 - * SoftAP Mode - #AP <= 1 on channels = 1 - * STA + P2P Mode - #STA <= 2, #{P2P-GO, P2P-client} <= 1, #P2P-device <= 1 - * on channels = 2 - */ -static const struct ieee80211_iface_limit common_if_limits[] = { - { - .max = 1, - .types = BIT(NL80211_IFTYPE_AP), - }, - { - /* - * During P2P-GO removal, P2P-GO is first changed to STA and later only - * removed. So setting maximum possible number of STA interfaces according - * to kernel version. - * - * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x) - * linux-3.8 and above - max:2 (wlan0 + group removal of p2p-wlan0-x) - */ -#ifdef WL_ENABLE_P2P_IF - .max = 3, -#else - .max = 2, -#endif /* WL_ENABLE_P2P_IF */ - .types = BIT(NL80211_IFTYPE_STATION), - }, - { - .max = 2, - .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), - }, -#if defined(WL_CFG80211_P2P_DEV_IF) - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_DEVICE), - }, -#endif /* WL_CFG80211_P2P_DEV_IF */ - { - .max = 1, - .types = BIT(NL80211_IFTYPE_ADHOC), - }, -}; -#ifdef BCM4330_CHIP -#define NUM_DIFF_CHANNELS 1 -#else -#define NUM_DIFF_CHANNELS 2 -#endif -static const struct ieee80211_iface_combination -common_iface_combinations[] = { - { - .num_different_channels = NUM_DIFF_CHANNELS, - .max_interfaces = 4, - .limits = common_if_limits, - .n_limits = ARRAY_SIZE(common_if_limits), - }, -}; -#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ - -/* Data Element Definitions */ -#define WPS_ID_CONFIG_METHODS 0x1008 -#define WPS_ID_REQ_TYPE 0x103A -#define WPS_ID_DEVICE_NAME 0x1011 -#define WPS_ID_VERSION 0x104A -#define WPS_ID_DEVICE_PWD_ID 0x1012 -#define WPS_ID_REQ_DEV_TYPE 0x106A -#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053 -#define WPS_ID_PRIM_DEV_TYPE 0x1054 - -/* Device Password ID */ -#define DEV_PW_DEFAULT 0x0000 -#define DEV_PW_USER_SPECIFIED 0x0001, -#define DEV_PW_MACHINE_SPECIFIED 0x0002 -#define DEV_PW_REKEY 0x0003 -#define DEV_PW_PUSHBUTTON 0x0004 -#define DEV_PW_REGISTRAR_SPECIFIED 0x0005 - -/* Config Methods */ -#define WPS_CONFIG_USBA 0x0001 -#define WPS_CONFIG_ETHERNET 0x0002 -#define WPS_CONFIG_LABEL 0x0004 -#define WPS_CONFIG_DISPLAY 0x0008 -#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010 -#define WPS_CONFIG_INT_NFC_TOKEN 0x0020 -#define WPS_CONFIG_NFC_INTERFACE 0x0040 -#define WPS_CONFIG_PUSHBUTTON 0x0080 -#define WPS_CONFIG_KEYPAD 0x0100 -#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280 -#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480 -#define WPS_CONFIG_VIRT_DISPLAY 0x2008 -#define WPS_CONFIG_PHY_DISPLAY 0x4008 - -#define PM_BLOCK 1 -#define PM_ENABLE 0 - -#ifdef BCMCCX -#ifndef WLAN_AKM_SUITE_CCKM -#define WLAN_AKM_SUITE_CCKM 0x00409600 -#endif -#define DOT11_LEAP_AUTH 0x80 /* LEAP auth frame paylod constants */ -#endif /* BCMCCX */ - -#ifdef MFP -#define WL_AKM_SUITE_MFP_1X 0x000FAC05 -#define WL_AKM_SUITE_MFP_PSK 0x000FAC06 -#define WL_MFP_CAPABLE 0x1 -#define WL_MFP_REQUIRED 0x2 -#endif /* MFP */ - -#ifndef IBSS_COALESCE_ALLOWED -#define IBSS_COALESCE_ALLOWED 0 -#endif - -#ifndef IBSS_INITIAL_SCAN_ALLOWED -#define IBSS_INITIAL_SCAN_ALLOWED 0 -#endif - -#define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */ -/* - * cfg80211_ops api/callback list - */ -static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, - const struct ether_addr *sa, const struct ether_addr *bssid, - u8 **pheader, u32 *body_len, u8 *pbody); -static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request, - struct cfg80211_ssid *this_ssid); -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); -#else -static s32 -wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request); -#endif /* WL_CFG80211_P2P_DEV_IF */ -static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); -static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params); -static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, - struct net_device *dev); -static s32 wl_cfg80211_get_station(struct wiphy *wiphy, - struct net_device *dev, u8 *mac, - struct station_info *sinfo); -static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, - struct net_device *dev, bool enabled, - s32 timeout); -static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code); -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, s32 mbm); -#else -static s32 -wl_cfg80211_set_tx_power(struct wiphy *wiphy, - enum nl80211_tx_power_setting type, s32 dbm); -#endif /* WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, s32 *dbm); -#else -static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); -#endif /* WL_CFG80211_P2P_DEV_IF */ -static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, - struct net_device *dev, - u8 key_idx, bool unicast, bool multicast); -static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - struct key_params *params); -static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr); -static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - void *cookie, void (*callback) (void *cookie, - struct key_params *params)); -static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *dev, u8 key_idx); -static s32 wl_cfg80211_resume(struct wiphy *wiphy); -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 2, 0)) -static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, - bcm_struct_cfgdev *cfgdev, u64 cookie); -static s32 wl_cfg80211_del_station( - struct wiphy *wiphy, struct net_device *ndev, - struct station_del_parameters *params); -static s32 wl_cfg80211_change_station(struct wiphy *wiphy, - struct net_device *dev, u8 *mac, struct station_parameters *params); -#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) -static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); -#else -static s32 wl_cfg80211_suspend(struct wiphy *wiphy); -#endif -static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa); -static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa); -static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, - struct net_device *dev); -static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg); -#if defined(WL_ABORT_SCAN) -static void wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *dev); -#endif /* WL_ABORT_SCAN */ -static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, - struct net_device *ndev, bool aborted, bool fw_abort); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) -#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) -static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, - u32 peer_capability, const u8 *data, size_t len); -#else -static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data, - size_t len); -#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ -static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, enum nl80211_tdls_operation oper); -#endif -#ifdef WL_SCHED_SCAN -static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev); -#endif - -/* - * event & event Q handlers for cfg80211 interfaces - */ -static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg); -static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg); -static s32 wl_event_handler(void *data); -static void wl_init_eq(struct bcm_cfg80211 *cfg); -static void wl_flush_eq(struct bcm_cfg80211 *cfg); -static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg); -static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags); -static void wl_init_eq_lock(struct bcm_cfg80211 *cfg); -static void wl_init_event_handler(struct bcm_cfg80211 *cfg); -static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg); -static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type, - const wl_event_msg_t *msg, void *data); -static void wl_put_event(struct wl_event_q *e); -static void wl_wakeup_event(struct bcm_cfg80211 *cfg); -static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data); -static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data, bool completed); -static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data); -static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -#ifdef WL_SCHED_SCAN -static s32 -wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data); -#endif /* WL_SCHED_SCAN */ -#ifdef PNO_SUPPORT -static s32 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -#endif /* PNO_SUPPORT */ -#ifdef GSCAN_SUPPORT -static s32 wl_notify_gscan_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -#endif /* GSCAN_SUPPORT */ -#ifdef RSSI_MONITOR_SUPPORT -static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -#endif /* RSSI_MONITOR_SUPPORT */ -static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, - enum wl_status state, bool set); - -#ifdef DHD_LOSSLESS_ROAMING -static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg); -#endif /* DHD_LOSSLESS_ROAMING */ - - -#ifdef WLTDLS -static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -#endif /* WLTDLS */ -/* - * register/deregister parent device - */ -static void wl_cfg80211_clear_parent_dev(void); - -/* - * ioctl utilites - */ - -/* - * cfg80211 set_wiphy_params utilities - */ -static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); -static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold); -static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); - -/* - * cfg profile utilities - */ -static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data, s32 item); -static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item); -static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev); - -/* - * cfg80211 connect utilites - */ -static s32 wl_set_wpa_version(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_set_auth_type(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_set_set_cipher(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_set_key_mgmt(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 wl_set_set_sharedkey(struct net_device *dev, - struct cfg80211_connect_params *sme); -#ifdef BCMWAPI_WPI -static s32 wl_set_set_wapi_ie(struct net_device *dev, - struct cfg80211_connect_params *sme); -#endif -static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev); -static void wl_ch_to_chanspec(int ch, - struct wl_join_params *join_params, size_t *join_params_size); - -/* - * information element utilities - */ -static void wl_rst_ie(struct bcm_cfg80211 *cfg); -static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v); -static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam); -static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size); -static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size); -static u32 wl_get_ielen(struct bcm_cfg80211 *cfg); -#ifdef MFP -static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa); -#endif - -#ifdef WL11U -bcm_tlv_t * -wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); -static s32 -wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, - uint8 ie_id, uint8 *data, uint8 data_len); -#endif /* WL11U */ - -static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data); -static void wl_free_wdev(struct bcm_cfg80211 *cfg); -#ifdef CONFIG_CFG80211_INTERNAL_REGDB -static int -wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); -#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ - -static s32 wl_inform_bss(struct bcm_cfg80211 *cfg); -static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam); -static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam); -static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); -s32 wl_cfg80211_channel_to_freq(u32 channel); - - -static void wl_cfg80211_work_handler(struct work_struct *work); -static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, const u8 *mac_addr, - struct key_params *params); -/* - * key indianess swap utilities - */ -static void swap_key_from_BE(struct wl_wsec_key *key); -static void swap_key_to_BE(struct wl_wsec_key *key); - -/* - * bcm_cfg80211 memory init/deinit utilities - */ -static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg); -static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg); - -static void wl_delay(u32 ms); - -/* - * ibss mode utilities - */ -static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev); -static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg); - -/* - * link up/down , default configuration utilities - */ -static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg); -static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg); -static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); -static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, - struct net_device *ndev); -static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); -static void wl_link_up(struct bcm_cfg80211 *cfg); -static void wl_link_down(struct bcm_cfg80211 *cfg); -static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype); -static void wl_init_conf(struct wl_conf *conf); -static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info, - struct net_device* ndev); - -int wl_cfg80211_get_ioctl_version(void); - -/* - * find most significant bit set - */ -static __used u32 wl_find_msb(u16 bit16); - -/* - * rfkill support - */ -static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup); -static int wl_rfkill_set(void *data, bool blocked); -#ifdef DEBUGFS_CFG80211 -static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg); -static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg); -#endif - -static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel, - int nprobes, int *out_params_size); -static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role); - -#ifdef WL_CFG80211_ACL -/* ACL */ -static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, - const struct cfg80211_acl_data *acl); -#endif /* WL_CFG80211_ACL */ - -/* - * Some external functions, TODO: move them to dhd_linux.h - */ -int dhd_add_monitor(char *name, struct net_device **new_ndev); -int dhd_del_monitor(struct net_device *ndev); -int dhd_monitor_init(void *dhd_pub); -int dhd_monitor_uninit(void); -int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); - - -static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const struct ether_addr *bssid); - - -#ifdef RSSI_OFFSET -static s32 wl_rssi_offset(s32 rssi) -{ - rssi += RSSI_OFFSET; - if (rssi > 0) - rssi = 0; - return rssi; -} -#else -#define wl_rssi_offset(x) x -#endif - -#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ - (akm) == RSN_AKM_UNSPECIFIED || \ - (akm) == RSN_AKM_PSK) - - -extern int dhd_wait_pend8021x(struct net_device *dev); -#ifdef PROP_TXSTATUS_VSDB -extern int disable_proptx; -#endif /* PROP_TXSTATUS_VSDB */ - -#if (WL_DBG_LEVEL > 0) -#define WL_DBG_ESTR_MAX 50 -static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { - "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND", - "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC", - "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END", - "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM", - "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH", - "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND", - "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", - "PFN_NET_LOST", - "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", - "IBSS_ASSOC", - "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT", - "PROBREQ_MSG", - "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", - "EXCEEDED_MEDIUM_TIME", "ICV_ERROR", - "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE", - "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE", - "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG", - "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND", - "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED", - "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT", - "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE", - "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP", - "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE" -}; -#endif /* WL_DBG_LEVEL */ - -#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(DOT11_RATE_1M, 0), - RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(DOT11_RATE_6M, 0), - RATETAB_ENT(DOT11_RATE_9M, 0), - RATETAB_ENT(DOT11_RATE_12M, 0), - RATETAB_ENT(DOT11_RATE_18M, 0), - RATETAB_ENT(DOT11_RATE_24M, 0), - RATETAB_ENT(DOT11_RATE_36M, 0), - RATETAB_ENT(DOT11_RATE_48M, 0), - RATETAB_ENT(DOT11_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(144, 0), - CHAN5G(149, 0), CHAN5G(153, 0), - CHAN5G(157, 0), CHAN5G(161, 0), - CHAN5G(165, 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 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, -#ifdef BCMWAPI_WPI - WLAN_CIPHER_SUITE_SMS4, -#endif -#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK) - WLAN_CIPHER_SUITE_PMK, -#endif -}; - - -#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) -static int maxrxpktglom = 0; -#endif - -/* IOCtl version read from targeted driver */ -static int ioctl_version; -#ifdef DEBUGFS_CFG80211 -#define S_SUBLOGLEVEL 20 -static const struct { - u32 log_level; - char *sublogname; -} sublogname_map[] = { - {WL_DBG_ERR, "ERR"}, - {WL_DBG_INFO, "INFO"}, - {WL_DBG_DBG, "DBG"}, - {WL_DBG_SCAN, "SCAN"}, - {WL_DBG_TRACE, "TRACE"}, - {WL_DBG_P2P_ACTION, "P2PACTION"} -}; -#endif - - -static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg, bool add_remove, - enum wl_handler_del_type type) -{ - if (cfg == NULL) - return; - - if (cfg->pm_enable_work_on) { - if (add_remove) { - schedule_delayed_work(&cfg->pm_enable_work, - msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); - } else { - cancel_delayed_work_sync(&cfg->pm_enable_work); - switch (type) { - case WL_HANDLER_MAINTAIN: - schedule_delayed_work(&cfg->pm_enable_work, - msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); - break; - case WL_HANDLER_PEND: - schedule_delayed_work(&cfg->pm_enable_work, - msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT*2)); - break; - case WL_HANDLER_DEL: - default: - cfg->pm_enable_work_on = false; - break; - } - } - } -} - -/* Return a new chanspec given a legacy chanspec - * Returns INVCHANSPEC on error - */ -static chanspec_t -wl_chspec_from_legacy(chanspec_t legacy_chspec) -{ - chanspec_t chspec; - - /* get the channel number */ - chspec = LCHSPEC_CHANNEL(legacy_chspec); - - /* convert the band */ - if (LCHSPEC_IS2G(legacy_chspec)) { - chspec |= WL_CHANSPEC_BAND_2G; - } else { - chspec |= WL_CHANSPEC_BAND_5G; - } - - /* convert the bw and sideband */ - if (LCHSPEC_IS20(legacy_chspec)) { - chspec |= WL_CHANSPEC_BW_20; - } else { - chspec |= WL_CHANSPEC_BW_40; - if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { - chspec |= WL_CHANSPEC_CTL_SB_L; - } else { - chspec |= WL_CHANSPEC_CTL_SB_U; - } - } - - if (wf_chspec_malformed(chspec)) { - WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", - chspec)); - return INVCHANSPEC; - } - - return chspec; -} - -/* Return a legacy chanspec given a new chanspec - * Returns INVCHANSPEC on error - */ -static chanspec_t -wl_chspec_to_legacy(chanspec_t chspec) -{ - chanspec_t lchspec; - - if (wf_chspec_malformed(chspec)) { - WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", - chspec)); - return INVCHANSPEC; - } - - /* get the channel number */ - lchspec = CHSPEC_CHANNEL(chspec); - - /* convert the band */ - if (CHSPEC_IS2G(chspec)) { - lchspec |= WL_LCHANSPEC_BAND_2G; - } else { - lchspec |= WL_LCHANSPEC_BAND_5G; - } - - /* convert the bw and sideband */ - if (CHSPEC_IS20(chspec)) { - lchspec |= WL_LCHANSPEC_BW_20; - lchspec |= WL_LCHANSPEC_CTL_SB_NONE; - } else if (CHSPEC_IS40(chspec)) { - lchspec |= WL_LCHANSPEC_BW_40; - if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { - lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; - } else { - lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; - } - } else { - /* cannot express the bandwidth */ - char chanbuf[CHANSPEC_STR_LEN]; - WL_ERR(( - "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " - "to pre-11ac format\n", - wf_chspec_ntoa(chspec, chanbuf), chspec)); - return INVCHANSPEC; - } - - return lchspec; -} - -/* given a chanspec value, do the endian and chanspec version conversion to - * a chanspec_t value - * Returns INVCHANSPEC on error - */ -chanspec_t -wl_chspec_host_to_driver(chanspec_t chanspec) -{ - if (ioctl_version == 1) { - chanspec = wl_chspec_to_legacy(chanspec); - if (chanspec == INVCHANSPEC) { - return chanspec; - } - } - chanspec = htodchanspec(chanspec); - - return chanspec; -} - -/* given a channel value, do the endian and chanspec version conversion to - * a chanspec_t value - * Returns INVCHANSPEC on error - */ -chanspec_t -wl_ch_host_to_driver(u16 channel) -{ - - chanspec_t chanspec; - - chanspec = channel & WL_CHANSPEC_CHAN_MASK; - - if (channel <= 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; - - return wl_chspec_host_to_driver(chanspec); -} - -/* given a chanspec value from the driver, do the endian and chanspec version conversion to - * a chanspec_t value - * Returns INVCHANSPEC on error - */ -static chanspec_t -wl_chspec_driver_to_host(chanspec_t chanspec) -{ - chanspec = dtohchanspec(chanspec); - if (ioctl_version == 1) { - chanspec = wl_chspec_from_legacy(chanspec); - } - - return chanspec; -} - -/* - * convert ASCII string to MAC address (colon-delimited format) - * eg: 00:11:22:33:44:55 - */ -int -wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n) -{ - char *c = NULL; - int count = 0; - - memset(n, 0, ETHER_ADDR_LEN); - for (;;) { - n->octet[count++] = (uint8)simple_strtoul(a, &c, 16); - if (!*c++ || count == ETHER_ADDR_LEN) - break; - a = c; - } - return (count == ETHER_ADDR_LEN); -} - -/* convert hex string buffer to binary */ -int -wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str) -{ - int count, slen; - int hvalue; - char tmp[3] = {0}; - char *ptr = str, *endp = NULL; - - if (!data || !str || !dlen) { - WL_DBG((" passed buffer is empty \n")); - return 0; - } - - slen = strlen(str); - if (dlen * 2 < slen) { - WL_DBG((" destination buffer too short \n")); - return 0; - } - - if (slen % 2) { - WL_DBG((" source buffer is of odd length \n")); - return 0; - } - - for (count = 0; count < slen; count += 2) { - memcpy(tmp, ptr, 2); - hvalue = simple_strtol(tmp, &endp, 16); - if (*endp != '\0') { - WL_DBG((" non hexadecimal character encountered \n")); - return 0; - } - *data++ = (unsigned char)hvalue; - ptr += 2; - } - - return (slen / 2); -} - -/* There isn't a lot of sense in it, but you can transmit anything you like */ -static const struct ieee80211_txrx_stypes -wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { - [NL80211_IFTYPE_ADHOC] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) - }, - [NL80211_IFTYPE_STATION] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, - [NL80211_IFTYPE_AP] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | - BIT(IEEE80211_STYPE_DISASSOC >> 4) | - BIT(IEEE80211_STYPE_AUTH >> 4) | - BIT(IEEE80211_STYPE_DEAUTH >> 4) | - BIT(IEEE80211_STYPE_ACTION >> 4) - }, - [NL80211_IFTYPE_AP_VLAN] = { - /* copy AP */ - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | - BIT(IEEE80211_STYPE_DISASSOC >> 4) | - BIT(IEEE80211_STYPE_AUTH >> 4) | - BIT(IEEE80211_STYPE_DEAUTH >> 4) | - BIT(IEEE80211_STYPE_ACTION >> 4) - }, - [NL80211_IFTYPE_P2P_CLIENT] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, - [NL80211_IFTYPE_P2P_GO] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | - BIT(IEEE80211_STYPE_DISASSOC >> 4) | - BIT(IEEE80211_STYPE_AUTH >> 4) | - BIT(IEEE80211_STYPE_DEAUTH >> 4) | - BIT(IEEE80211_STYPE_ACTION >> 4) - }, -#if defined(WL_CFG80211_P2P_DEV_IF) - [NL80211_IFTYPE_P2P_DEVICE] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, -#endif /* WL_CFG80211_P2P_DEV_IF */ -}; - -static void swap_key_from_BE(struct wl_wsec_key *key) -{ - key->index = htod32(key->index); - key->len = htod32(key->len); - key->algo = htod32(key->algo); - key->flags = htod32(key->flags); - key->rxiv.hi = htod32(key->rxiv.hi); - key->rxiv.lo = htod16(key->rxiv.lo); - key->iv_initialized = htod32(key->iv_initialized); -} - -static void swap_key_to_BE(struct wl_wsec_key *key) -{ - key->index = dtoh32(key->index); - key->len = dtoh32(key->len); - key->algo = dtoh32(key->algo); - key->flags = dtoh32(key->flags); - key->rxiv.hi = dtoh32(key->rxiv.hi); - key->rxiv.lo = dtoh16(key->rxiv.lo); - key->iv_initialized = dtoh32(key->iv_initialized); -} - -/* Dump the contents of the encoded wps ie buffer and get pbc value */ -static void -wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) -{ - #define WPS_IE_FIXED_LEN 6 - u16 len; - u8 *subel = NULL; - u16 subelt_id; - u16 subelt_len; - u16 val; - u8 *valptr = (uint8*) &val; - if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) { - WL_ERR(("invalid argument : NULL\n")); - return; - } - len = (u16)wps_ie[TLV_LEN_OFF]; - - if (len > wps_ie_len) { - WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len)); - return; - } - WL_DBG(("wps_ie len=%d\n", len)); - len -= 4; /* for the WPS IE's OUI, oui_type fields */ - subel = wps_ie + WPS_IE_FIXED_LEN; - while (len >= 4) { /* must have attr id, attr len fields */ - valptr[0] = *subel++; - valptr[1] = *subel++; - subelt_id = HTON16(val); - - valptr[0] = *subel++; - valptr[1] = *subel++; - subelt_len = HTON16(val); - - len -= 4; /* for the attr id, attr len fields */ - - if (len < subelt_len) { - WL_ERR(("not enough data, len %d, subelt_len %d\n", len, - subelt_len)); - break; - } - len -= subelt_len; /* for the remaining fields in this attribute */ - - WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n", - subel, subelt_id, subelt_len)); - - if (subelt_id == WPS_ID_VERSION) { - WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel)); - } else if (subelt_id == WPS_ID_REQ_TYPE) { - WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel)); - } else if (subelt_id == WPS_ID_CONFIG_METHODS) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val))); - } else if (subelt_id == WPS_ID_DEVICE_NAME) { - char devname[100]; - int namelen = MIN(subelt_len, (sizeof(devname) - 1)); - - if (namelen) { - memcpy(devname, subel, namelen); - devname[namelen] = '\0'; - /* Printing len as rx'ed in the IE */ - WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n", - devname, subelt_len)); - } - } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val))); - *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false; - } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val))); - valptr[0] = *(subel + 6); - valptr[1] = *(subel + 7); - WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val))); - } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val))); - valptr[0] = *(subel + 6); - valptr[1] = *(subel + 7); - WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val))); - } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) { - valptr[0] = *subel; - valptr[1] = *(subel + 1); - WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS" - ": cat=%u\n", HTON16(val))); - } else { - WL_DBG((" unknown attr 0x%x\n", subelt_id)); - } - - subel += subelt_len; - } -} - -s32 wl_set_tx_power(struct net_device *dev, - enum nl80211_tx_power_setting type, s32 dbm) -{ - s32 err = 0; - s32 disable = 0; - s32 txpwrqdbm; - struct bcm_cfg80211 *cfg = g_bcm_cfg; -#ifdef TEST_TX_POWER_CONTROL - char *tmppwr_str; -#endif /* TEST_TX_POWER_CONTROL */ - - /* Make sure radio is off or on as far as software is concerned */ - disable = WL_RADIO_SW_DISABLE << 16; - disable = htod32(disable); - err = wldev_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable), true); - if (unlikely(err)) { - WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); - return err; - } - - if (dbm > 0xffff) - dbm = 0xffff; - txpwrqdbm = dbm * 4; -#ifdef SUPPORT_WL_TXPOWER - if (type == NL80211_TX_POWER_AUTOMATIC) { - txpwrqdbm = 127; -#ifdef TEST_TX_POWER_CONTROL - err = wldev_iovar_setint(dev, "qtxpower", txpwrqdbm); - if (unlikely(err)) - WL_ERR(("qtxpower error (%d)\n", err)); - else - WL_ERR(("mW=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm)); - - tmppwr_str = kzalloc(0x71a, GFP_KERNEL); - if (!tmppwr_str) { - WL_ERR(("tmppwr memory alloc failed\n")); - } else { - err = wldev_iovar_getbuf(dev, "curpower", NULL, 0, tmppwr_str, 0x71a, NULL); - if (unlikely(err)) { - WL_ERR(("curpower error (%d)\n", err)); - } - kfree(tmppwr_str); - } -#endif /* TEST_TX_POWER_CONTROL */ - } else { - txpwrqdbm |= WL_TXPWR_OVERRIDE; - } -#endif /* SUPPORT_WL_TXPOWER */ - - err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm, - sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, - &cfg->ioctl_buf_sync); - - if (unlikely(err)) - WL_ERR(("qtxpower error (%d)\n", err)); - else - WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm)); - - return err; -} - -s32 wl_get_tx_power(struct net_device *dev, s32 *dbm) -{ - s32 err = 0; - s32 txpwrdbm; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - err = wldev_iovar_getint(dev, "qtxpower", &txpwrdbm); - err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower", - NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - - memcpy(&txpwrdbm, cfg->ioctl_buf, sizeof(txpwrdbm)); - txpwrdbm = dtoh32(txpwrdbm); - *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4; - - WL_INFO(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm)); - - return err; -} - -static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) -{ - chanspec_t chspec; - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - struct ether_addr bssid; - struct wl_bss_info *bss = NULL; - char *buf; - - memset(&bssid, 0, sizeof(bssid)); - if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { - /* STA interface is not associated. So start the new interface on a temp - * channel . Later proper channel will be applied by the above framework - * via set_channel (cfg80211 API). - */ - WL_DBG(("Not associated. Return a temp channel. \n")); - return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); - } - - buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); - if (!buf) { - WL_ERR(("buf alloc failed. use temp channel\n")); - return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); - } - - *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX); - if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, buf, - WL_EXTRA_BUF_MAX, false))) { - WL_ERR(("Failed to get associated bss info, use temp channel \n")); - chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); - } - else { - bss = (wl_bss_info_t *) (buf + 4); - chspec = bss->chanspec; - - WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec)); - } - - kfree(buf); - return chspec; -} - -static bcm_struct_cfgdev * -wl_cfg80211_add_monitor_if(char *name) -{ -#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) - WL_INFO(("wl_cfg80211_add_monitor_if: No more support monitor interface\n")); - return ERR_PTR(-EOPNOTSUPP); -#else - struct net_device* ndev = NULL; - - dhd_add_monitor(name, &ndev); - WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); - return ndev_to_cfgdev(ndev); -#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */ -} - -static bcm_struct_cfgdev * -wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, -#if defined(WL_CFG80211_P2P_DEV_IF) - const char *name, -#else - char *name, -#endif /* WL_CFG80211_P2P_DEV_IF */ - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) -{ - s32 err; - s32 timeout = -1; - s32 wlif_type = -1; - s32 mode = 0; - s32 val = 0; - s32 dhd_mode = 0; - chanspec_t chspec; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *primary_ndev; - struct net_device *new_ndev; - struct ether_addr primary_mac; -#ifdef PROP_TXSTATUS_VSDB - s32 up = 1; - dhd_pub_t *dhd; - bool enabled; -#endif /* PROP_TXSTATUS_VSDB */ - - if (!cfg) - return ERR_PTR(-EINVAL); - -#ifdef PROP_TXSTATUS_VSDB - dhd = (dhd_pub_t *)(cfg->pub); -#endif /* PROP_TXSTATUS_VSDB */ - - - /* Use primary I/F for sending cmds down to firmware */ - primary_ndev = bcmcfg_to_prmry_ndev(cfg); - - if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) { - WL_ERR(("device is not ready\n")); - return ERR_PTR(-ENODEV); - } - - WL_DBG(("if name: %s, type: %d\n", name, type)); - switch (type) { - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MESH_POINT: - WL_ERR(("Unsupported interface type\n")); - mode = WL_MODE_IBSS; - return NULL; - case NL80211_IFTYPE_MONITOR: - return wl_cfg80211_add_monitor_if((char *)name); -#if defined(WL_CFG80211_P2P_DEV_IF) - case NL80211_IFTYPE_P2P_DEVICE: - return wl_cfgp2p_add_p2p_disc_if(cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ - case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_STATION: - wlif_type = WL_P2P_IF_CLIENT; - mode = WL_MODE_BSS; - break; - case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_AP: - wlif_type = WL_P2P_IF_GO; - mode = WL_MODE_AP; - break; - default: - WL_ERR(("Unsupported interface type\n")); - return NULL; - break; - } - - if (!name) { - WL_ERR(("name is NULL\n")); - return NULL; - } - if (cfg->p2p_supported && (wlif_type != -1)) { - ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */ - -#ifdef PROP_TXSTATUS_VSDB - if (!dhd) - return ERR_PTR(-ENODEV); -#endif /* PROP_TXSTATUS_VSDB */ - if (!cfg->p2p) - return ERR_PTR(-ENODEV); - - if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { - p2p_on(cfg) = true; - wl_cfgp2p_set_firm_p2p(cfg); - wl_cfgp2p_init_discovery(cfg); - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, - &cfg->p2p->dev_addr, &cfg->p2p->int_addr); - } - - memset(cfg->p2p->vir_ifname, 0, IFNAMSIZ); - strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1); - - wl_cfg80211_scan_abort(cfg); -#ifdef PROP_TXSTATUS_VSDB - if (!cfg->wlfc_on && !disable_proptx) { - dhd_wlfc_get_enable(dhd, &enabled); - if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) { - dhd_wlfc_init(dhd); - err = wldev_ioctl(primary_ndev, WLC_UP, &up, sizeof(s32), true); - if (err < 0) - WL_ERR(("WLC_UP return err:%d\n", err)); - } - cfg->wlfc_on = true; - } -#endif /* PROP_TXSTATUS_VSDB */ - - /* In concurrency case, STA may be already associated in a particular channel. - * so retrieve the current channel of primary interface and then start the virtual - * interface on that. - */ - chspec = wl_cfg80211_get_shared_freq(wiphy); - - /* For P2P mode, use P2P-specific driver features to create the - * bss: "cfg p2p_ifadd" - */ - wl_set_p2p_status(cfg, IF_ADDING); - memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); - if (wlif_type == WL_P2P_IF_GO) - wldev_iovar_setint(primary_ndev, "mpc", 0); - err = wl_cfgp2p_ifadd(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec); - if (unlikely(err)) { - wl_clr_p2p_status(cfg, IF_ADDING); - WL_ERR((" virtual iface add failed (%d) \n", err)); - return ERR_PTR(-ENOMEM); - } - - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - (wl_get_p2p_status(cfg, IF_ADDING) == false), - msecs_to_jiffies(MAX_WAIT_TIME)); - - if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) { - struct wireless_dev *vwdev; - int pm_mode = PM_ENABLE; - wl_if_event_info *event = &cfg->if_event_info; - - /* IF_ADD event has come back, we can proceed to to register - * the new interface now, use the interface name provided by caller (thus - * ignore the one from wlc) - */ - strncpy(cfg->if_event_info.name, name, IFNAMSIZ - 1); - new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname, - event->mac, event->bssidx); - if (new_ndev == NULL) - goto fail; - - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = new_ndev; - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = event->bssidx; - vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); - if (unlikely(!vwdev)) { - WL_ERR(("Could not allocate wireless device\n")); - goto fail; - } - vwdev->wiphy = cfg->wdev->wiphy; - WL_INFO(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname)); - vwdev->iftype = type; - vwdev->netdev = new_ndev; - new_ndev->ieee80211_ptr = vwdev; - SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy)); - wl_set_drv_status(cfg, READY, new_ndev); - cfg->p2p->vif_created = true; - wl_set_mode_by_netdev(cfg, new_ndev, mode); - - if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) { - wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev); - goto fail; - } - wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode); - val = 1; - /* Disable firmware roaming for P2P interface */ - wldev_iovar_setint(new_ndev, "roam_off", val); - - if (mode != WL_MODE_AP) - wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1); - - WL_ERR((" virtual interface(%s) is " - "created net attach done\n", cfg->p2p->vir_ifname)); - if (mode == WL_MODE_AP) - wl_set_drv_status(cfg, CONNECTED, new_ndev); - if (type == NL80211_IFTYPE_P2P_CLIENT) - dhd_mode = DHD_FLAG_P2P_GC_MODE; - else if (type == NL80211_IFTYPE_P2P_GO) - dhd_mode = DHD_FLAG_P2P_GO_MODE; - DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode)); - /* reinitialize completion to clear previous count */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) - INIT_COMPLETION(cfg->iface_disable); -#else - init_completion(&cfg->iface_disable); -#endif - return ndev_to_cfgdev(new_ndev); - } else { - wl_clr_p2p_status(cfg, IF_ADDING); - WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname)); - memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ); - cfg->p2p->vif_created = false; -#ifdef PROP_TXSTATUS_VSDB - dhd_wlfc_get_enable(dhd, &enabled); - if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) { - dhd_wlfc_deinit(dhd); - cfg->wlfc_on = false; - } -#endif /* PROP_TXSTATUS_VSDB */ - } - } - -fail: - if (wlif_type == WL_P2P_IF_GO) - wldev_iovar_setint(primary_ndev, "mpc", 1); - return ERR_PTR(-ENODEV); -} - -static s32 -wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) -{ - struct net_device *dev = NULL; - struct ether_addr p2p_mac; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 timeout = -1; - s32 ret = 0; - s32 index = -1; - WL_DBG(("Enter\n")); - -#if defined(WL_CFG80211_P2P_DEV_IF) - if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { - return wl_cfgp2p_del_p2p_disc_if(cfgdev, cfg); - } -#endif /* WL_CFG80211_P2P_DEV_IF */ - dev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if (wl_cfgp2p_find_idx(cfg, dev, &index) != BCME_OK) { - WL_ERR(("Find p2p index from ndev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (cfg->p2p_supported) { - memcpy(p2p_mac.octet, cfg->p2p->int_addr.octet, ETHER_ADDR_LEN); - - /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases - */ - WL_DBG(("P2P: GO_NEG_PHASE status cleared ")); - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - if (cfg->p2p->vif_created) { - if (wl_get_drv_status(cfg, SCANNING, dev)) { - wl_notify_escan_complete(cfg, dev, true, true); - } - wldev_iovar_setint(dev, "mpc", 1); - /* Delete pm_enable_work */ - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - - /* for GC */ - if (wl_get_drv_status(cfg, DISCONNECTING, dev) && - (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)) { - WL_ERR(("Wait for Link Down event for GC !\n")); - wait_for_completion_timeout - (&cfg->iface_disable, msecs_to_jiffies(500)); - } - - memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); - wl_set_p2p_status(cfg, IF_DELETING); - DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg)); - - /* for GO */ - if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); - /* disable interface before bsscfg free */ - ret = wl_cfgp2p_ifdisable(cfg, &p2p_mac); - /* if fw doesn't support "ifdis", - do not wait for link down of ap mode - */ - if (ret == 0) { - WL_ERR(("Wait for Link Down event for GO !!!\n")); - wait_for_completion_timeout(&cfg->iface_disable, - msecs_to_jiffies(500)); - } else if (ret != BCME_UNSUPPORTED) { - msleep(300); - } - } - wl_cfgp2p_clear_management_ie(cfg, index); - - if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) - wldev_iovar_setint(dev, "buf_key_b4_m4", 0); - - /* delete interface after link down */ - ret = wl_cfgp2p_ifdel(cfg, &p2p_mac); - - if (ret != BCME_OK) { - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - - WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n", - ret, ndev->name)); - #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID) - #ifdef CONFIG_BCM_WLAN_RAMDUMP - bcm_add_crash_reason(((dhd_pub_t *)(cfg->pub))->crash_reason, - ("p2p_ifdel failed, error %d, sent HANG event to %s\n", - ret, ndev->name); - #endif /* CONFIG_BCM_WLAN_RAMDUMP */ - net_os_send_hang_message(ndev); - #endif - } else { - /* Wait for IF_DEL operation to be finished */ - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - (wl_get_p2p_status(cfg, IF_DELETING) == false), - msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) && - cfg->if_event_info.valid) { - - WL_DBG(("IFDEL operation done\n")); - wl_cfg80211_handle_ifdel(cfg, &cfg->if_event_info, dev); - } else { - WL_ERR(("IFDEL didn't complete properly\n")); - } - } - - ret = dhd_del_monitor(dev); - if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL((dhd_pub_t *)(cfg->pub)); - } - } - } - return ret; -} - -static s32 -wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) -{ - s32 ap = 0; - s32 infra = 0; - s32 ibss = 0; - s32 wlif_type; - s32 mode = 0; - s32 err = BCME_OK; - chanspec_t chspec; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - WL_DBG(("Enter type %d\n", type)); - switch (type) { - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MESH_POINT: - ap = 1; - WL_ERR(("type (%d) : currently we do not support this type\n", - type)); - break; - case NL80211_IFTYPE_ADHOC: - mode = WL_MODE_IBSS; - ibss = 1; - break; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - mode = WL_MODE_BSS; - infra = 1; - break; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_P2P_GO: - mode = WL_MODE_AP; - ap = 1; - break; - default: - return -EINVAL; - } - if (!dhd) - return -EINVAL; - if (ap) { - wl_set_mode_by_netdev(cfg, ndev, mode); - if (cfg->p2p_supported && cfg->p2p->vif_created) { - WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", cfg->p2p->vif_created, - p2p_on(cfg))); - wldev_iovar_setint(ndev, "mpc", 0); - wl_notify_escan_complete(cfg, ndev, true, true); - - /* In concurrency case, STA may be already associated in a particular - * channel. so retrieve the current channel of primary interface and - * then start the virtual interface on that. - */ - chspec = wl_cfg80211_get_shared_freq(wiphy); - - wlif_type = WL_P2P_IF_GO; - WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", - ndev->name, ap, infra, type)); - wl_set_p2p_status(cfg, IF_CHANGING); - wl_clr_p2p_status(cfg, IF_CHANGED); - wl_cfgp2p_ifchange(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec); - wait_event_interruptible_timeout(cfg->netif_change_event, - (wl_get_p2p_status(cfg, IF_CHANGED) == true), - msecs_to_jiffies(MAX_WAIT_TIME)); - wl_set_mode_by_netdev(cfg, ndev, mode); - dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE; - dhd->op_mode |= DHD_FLAG_P2P_GO_MODE; - wl_clr_p2p_status(cfg, IF_CHANGING); - wl_clr_p2p_status(cfg, IF_CHANGED); - if (mode == WL_MODE_AP) - wl_set_drv_status(cfg, CONNECTED, ndev); - } else if (ndev == bcmcfg_to_prmry_ndev(cfg) && - !wl_get_drv_status(cfg, AP_CREATED, ndev)) { - wl_set_drv_status(cfg, AP_CREATING, ndev); - if (!cfg->ap_info && - !(cfg->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) { - WL_ERR(("struct ap_saved_ie allocation failed\n")); - return -ENOMEM; - } - } else { - WL_ERR(("Cannot change the interface for GO or SOFTAP\n")); - return -EINVAL; - } - } else { - WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA")); - } - - if (ibss) { - infra = 0; - wl_set_mode_by_netdev(cfg, ndev, mode); - err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET Adhoc error %d\n", err)); - return -EINVAL; - } - } - - ndev->ieee80211_ptr->iftype = type; - return 0; -} - -s32 -wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd") - * redirect the IF_ADD event to ifchange as it is not a real "new" interface - */ - if (wl_get_p2p_status(cfg, IF_CHANGING)) - return wl_cfg80211_notify_ifchange(ifidx, name, mac, bssidx); - - /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */ - if (wl_get_p2p_status(cfg, IF_ADDING)) { - wl_if_event_info *if_event_info = &cfg->if_event_info; - - if_event_info->valid = TRUE; - if_event_info->ifidx = ifidx; - if_event_info->bssidx = bssidx; - strncpy(if_event_info->name, name, IFNAMSIZ); - if_event_info->name[IFNAMSIZ] = '\0'; - if (mac) - memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN); - - wl_clr_p2p_status(cfg, IF_ADDING); - wake_up_interruptible(&cfg->netif_change_event); - return BCME_OK; - } - - return BCME_ERROR; -} - -s32 -wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - wl_if_event_info *if_event_info = &cfg->if_event_info; - - if (wl_get_p2p_status(cfg, IF_DELETING)) { - if_event_info->valid = TRUE; - if_event_info->ifidx = ifidx; - if_event_info->bssidx = bssidx; - wl_clr_p2p_status(cfg, IF_DELETING); - wake_up_interruptible(&cfg->netif_change_event); - return BCME_OK; - } - - return BCME_ERROR; -} - -s32 -wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - if (wl_get_p2p_status(cfg, IF_CHANGING)) { - wl_set_p2p_status(cfg, IF_CHANGED); - wake_up_interruptible(&cfg->netif_change_event); - return BCME_OK; - } - - return BCME_ERROR; -} - -static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info, - struct net_device* ndev) -{ - s32 type = -1; - s32 bssidx = -1; -#ifdef PROP_TXSTATUS_VSDB - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - bool enabled; -#endif /* PROP_TXSTATUS_VSDB */ - - bssidx = if_event_info->bssidx; - if (bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION)) { - WL_ERR(("got IF_DEL for if %d, not owned by cfg driver\n", bssidx)); - return BCME_ERROR; - } - - if (p2p_is_on(cfg) && cfg->p2p->vif_created) { - - if (cfg->scan_request && (cfg->escan_info.ndev == ndev)) { - /* Abort any pending scan requests */ - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - WL_DBG(("ESCAN COMPLETED\n")); - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, false); - } - - memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ); - if (wl_cfgp2p_find_type(cfg, bssidx, &type) != BCME_OK) { - WL_ERR(("Find p2p type from bssidx(%d) failed\n", bssidx)); - return BCME_ERROR; - } - wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, type)); - wl_to_p2p_bss_ndev(cfg, type) = NULL; - wl_to_p2p_bss_bssidx(cfg, type) = WL_INVALID; - cfg->p2p->vif_created = false; - -#ifdef PROP_TXSTATUS_VSDB - dhd_wlfc_get_enable(dhd, &enabled); - if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) { - dhd_wlfc_deinit(dhd); - cfg->wlfc_on = false; - } -#endif /* PROP_TXSTATUS_VSDB */ - } - - wl_cfg80211_remove_if(cfg, if_event_info->ifidx, ndev); - return BCME_OK; -} - -/* Find listen channel */ -static s32 wl_find_listen_channel(struct bcm_cfg80211 *cfg, - const u8 *ie, u32 ie_len) -{ - wifi_p2p_ie_t *p2p_ie; - u8 *end, *pos; - s32 listen_channel; - - pos = (u8 *)ie; - p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len); - - if (p2p_ie == NULL) - return 0; - - pos = p2p_ie->subelts; - end = p2p_ie->subelts + (p2p_ie->len - 4); - - CFGP2P_DBG((" found p2p ie ! lenth %d \n", - p2p_ie->len)); - - while (pos < end) { - uint16 attr_len; - if (pos + 2 >= end) { - CFGP2P_DBG((" -- Invalid P2P attribute")); - return 0; - } - attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0])); - - if (pos + 3 + attr_len > end) { - CFGP2P_DBG(("P2P: Attribute underflow " - "(len=%u left=%d)", - attr_len, (int) (end - pos - 3))); - return 0; - } - - /* if Listen Channel att id is 6 and the vailue is valid, - * return the listen channel - */ - if (pos[0] == 6) { - /* listen channel subel length format - * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num) - */ - listen_channel = pos[1 + 2 + 3 + 1]; - - if (listen_channel == SOCIAL_CHAN_1 || - listen_channel == SOCIAL_CHAN_2 || - listen_channel == SOCIAL_CHAN_3) { - CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel)); - return listen_channel; - } - } - pos += 3 + attr_len; - } - return 0; -} - -static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) -{ - u32 n_ssids; - u32 n_channels; - u16 channel; - chanspec_t chanspec; - s32 i = 0, j = 0, offset; - char *ptr; - wlc_ssid_t ssid; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); - params->bss_type = DOT11_BSSTYPE_ANY; - params->scan_type = 0; - params->nprobes = -1; - params->active_time = -1; - params->passive_time = -1; - params->home_time = -1; - params->channel_num = 0; - memset(¶ms->ssid, 0, sizeof(wlc_ssid_t)); - - WL_SCAN(("Preparing Scan request\n")); - WL_SCAN(("nprobes=%d\n", params->nprobes)); - WL_SCAN(("active_time=%d\n", params->active_time)); - WL_SCAN(("passive_time=%d\n", params->passive_time)); - WL_SCAN(("home_time=%d\n", params->home_time)); - WL_SCAN(("scan_type=%d\n", params->scan_type)); - - params->nprobes = htod32(params->nprobes); - params->active_time = htod32(params->active_time); - params->passive_time = htod32(params->passive_time); - params->home_time = htod32(params->home_time); - - /* if request is null just exit so it will be all channel broadcast scan */ - if (!request) - return; - - n_ssids = request->n_ssids; - n_channels = request->n_channels; - - /* Copy channel array if applicable */ - WL_SCAN(("### List of channelspecs to scan ###\n")); - if (n_channels > 0) { - for (i = 0; i < n_channels; i++) { - chanspec = 0; - channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); - /* SKIP DFS channels for Secondary interface */ - if ((cfg->escan_info.ndev != bcmcfg_to_prmry_ndev(cfg)) && - (request->channels[i]->flags & -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) - (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) -#else - (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR))) -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */ - continue; - - if (request->channels[i]->band == IEEE80211_BAND_2GHZ) { - chanspec |= WL_CHANSPEC_BAND_2G; - } else { - chanspec |= WL_CHANSPEC_BAND_5G; - } - - chanspec |= WL_CHANSPEC_BW_20; - chanspec |= WL_CHANSPEC_CTL_SB_NONE; - - params->channel_list[j] = channel; - params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK; - params->channel_list[j] |= chanspec; - WL_SCAN(("Chan : %d, Channel spec: %x \n", - channel, params->channel_list[j])); - params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]); - j++; - } - } else { - WL_SCAN(("Scanning all channels\n")); - } - n_channels = j; - /* Copy ssid array if applicable */ - WL_SCAN(("### List of SSIDs to scan ###\n")); - if (n_ssids > 0) { - offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); - offset = roundup(offset, sizeof(u32)); - ptr = (char*)params + offset; - for (i = 0; i < n_ssids; i++) { - memset(&ssid, 0, sizeof(wlc_ssid_t)); - ssid.SSID_len = MIN(request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN); - memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); - if (!ssid.SSID_len) - WL_SCAN(("%d: Broadcast scan\n", i)); - else - WL_SCAN(("%d: scan for %s size =%d\n", i, - ssid.SSID, ssid.SSID_len)); - memcpy(ptr, &ssid, sizeof(wlc_ssid_t)); - ptr += sizeof(wlc_ssid_t); - } - } else { - WL_SCAN(("Broadcast scan\n")); - } - /* Adding mask to channel numbers */ - params->channel_num = - htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | - (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); - - if (n_channels == 1) { - params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); - params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS); - } -} - -static s32 -wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) -{ - wl_uint32_list_t *list; - s32 err = BCME_OK; - if (valid_chan_list == NULL || size <= 0) - return -ENOMEM; - - memset(valid_chan_list, 0, size); - list = (wl_uint32_list_t *)(void *) valid_chan_list; - list->count = htod32(WL_NUMCHANNELS); - err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false); - if (err != 0) { - WL_ERR(("get channels failed with %d\n", err)); - } - - return err; -} - -#if defined(USE_INITIAL_SHORT_DWELL_TIME) -#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40 -bool g_first_broadcast_scan = TRUE; -#endif - -static s32 -wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, - struct cfg80211_scan_request *request, uint16 action) -{ - s32 err = BCME_OK; - u32 n_channels; - u32 n_ssids; - s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); - wl_escan_params_t *params = NULL; - u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)]; - u32 num_chans = 0; - s32 channel; - s32 n_valid_chan; - s32 search_state = WL_P2P_DISC_ST_SCAN; - u32 i, j, n_nodfs = 0; - u16 *default_chan_list = NULL; - wl_uint32_list_t *list; - struct net_device *dev = NULL; -#if defined(USE_INITIAL_SHORT_DWELL_TIME) - bool is_first_init_2g_scan = false; -#endif - p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN; - - WL_DBG(("Enter \n")); - - /* scan request can come with empty request : perform all default scan */ - if (!cfg) { - err = -EINVAL; - goto exit; - } - if (!cfg->p2p_supported || !p2p_scan(cfg)) { - /* LEGACY SCAN TRIGGER */ - WL_SCAN((" LEGACY E-SCAN START\n")); - -#if defined(USE_INITIAL_SHORT_DWELL_TIME) - if (!request) { - err = -EINVAL; - goto exit; - } - if (ndev == bcmcfg_to_prmry_ndev(cfg) && g_first_broadcast_scan == true) { - is_first_init_2g_scan = true; - g_first_broadcast_scan = false; - } -#endif - - /* if scan request is not empty parse scan request paramters */ - if (request != NULL) { - n_channels = request->n_channels; - n_ssids = request->n_ssids; - if (n_channels % 2) - /* If n_channels is odd, add a padd of u16 */ - params_size += sizeof(u16) * (n_channels + 1); - else - params_size += sizeof(u16) * n_channels; - - /* Allocate space for populating ssids in wl_escan_params_t struct */ - params_size += sizeof(struct wlc_ssid) * n_ssids; - } - params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); - if (params == NULL) { - err = -ENOMEM; - goto exit; - } - wl_scan_prep(¶ms->params, request); - -#if defined(USE_INITIAL_SHORT_DWELL_TIME) - /* Override active_time to reduce scan time if it's first bradcast scan. */ - if (is_first_init_2g_scan) - params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; -#endif - - params->version = htod32(ESCAN_REQ_VERSION); - params->action = htod16(action); - wl_escan_set_sync_id(params->sync_id, cfg); - wl_escan_set_type(cfg, WL_SCANTYPE_LEGACY); - if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { - WL_ERR(("ioctl buffer length not sufficient\n")); - kfree(params); - err = -ENOMEM; - goto exit; - } - err = wldev_iovar_setbuf(ndev, "escan", params, params_size, - cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(err)) { - if (err == BCME_EPERM) - /* Scan Not permitted at this point of time */ - WL_DBG((" Escan not permitted at this time (%d)\n", err)); - else - WL_ERR((" Escan set error (%d)\n", err)); - } - kfree(params); - } - else if (p2p_is_on(cfg) && p2p_scan(cfg)) { - /* P2P SCAN TRIGGER */ - s32 _freq = 0; - n_nodfs = 0; - if (request && request->n_channels) { - num_chans = request->n_channels; - WL_SCAN((" chann number : %d\n", num_chans)); - default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), - GFP_KERNEL); - if (default_chan_list == NULL) { - WL_ERR(("channel list allocation failed \n")); - err = -ENOMEM; - goto exit; - } - if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { - list = (wl_uint32_list_t *) chan_buf; - n_valid_chan = dtoh32(list->count); - if (n_valid_chan > WL_NUMCHANNELS) { - WL_ERR(("wrong n_valid_chan:%d\n", n_valid_chan)); - kfree(default_chan_list); - err = -EINVAL; - goto exit; - } - - for (i = 0; i < num_chans; i++) - { - _freq = request->channels[i]->center_freq; - channel = ieee80211_frequency_to_channel(_freq); - - /* ignore DFS channels */ - if (request->channels[i]->flags & -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - (IEEE80211_CHAN_NO_IR - | IEEE80211_CHAN_RADAR)) -#else - (IEEE80211_CHAN_RADAR -#ifdef CUSTOMER_HW5 - | 0)) -#else - | IEEE80211_CHAN_PASSIVE_SCAN)) -#endif /* CUSTOMER_HW5 */ -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ - continue; - - for (j = 0; j < n_valid_chan; j++) { - /* allows only supported channel on - * current reguatory - */ - if (n_nodfs >= num_chans) { - break; - } - if (channel == (dtoh32(list->element[j]))) { - default_chan_list[n_nodfs++] = - channel; - } - } - - } - } - if (num_chans == SOCIAL_CHAN_CNT && ( - (default_chan_list[0] == SOCIAL_CHAN_1) && - (default_chan_list[1] == SOCIAL_CHAN_2) && - (default_chan_list[2] == SOCIAL_CHAN_3))) { - /* SOCIAL CHANNELS 1, 6, 11 */ - search_state = WL_P2P_DISC_ST_SEARCH; - p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; - WL_INFO(("P2P SEARCH PHASE START \n")); - } else if ((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) && - (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) { - /* If you are already a GO, then do SEARCH only */ - WL_INFO(("Already a GO. Do SEARCH Only")); - search_state = WL_P2P_DISC_ST_SEARCH; - num_chans = n_nodfs; - p2p_scan_purpose = P2P_SCAN_NORMAL; - - } else if (num_chans == 1) { - p2p_scan_purpose = P2P_SCAN_CONNECT_TRY; - } else if (num_chans == SOCIAL_CHAN_CNT + 1) { - /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by - * the supplicant - */ - p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; - } else { - WL_INFO(("P2P SCAN STATE START \n")); - num_chans = n_nodfs; - p2p_scan_purpose = P2P_SCAN_NORMAL; - } - } else { - err = -EINVAL; - goto exit; - } - err = wl_cfgp2p_escan(cfg, ndev, cfg->active_scan, num_chans, default_chan_list, - search_state, action, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE), NULL, - p2p_scan_purpose); - - if (!err) - cfg->p2p->search_state = search_state; - - kfree(default_chan_list); - } -exit: - if (unlikely(err)) { - /* Don't print Error incase of Scan suppress */ - if ((err == BCME_EPERM) && cfg->scan_suppressed) - WL_DBG(("Escan failed: Scan Suppressed \n")); - else - WL_ERR(("error (%d)\n", err)); - } - return err; -} - - -static s32 -wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request) -{ - s32 err = BCME_OK; - s32 passive_scan; - wl_scan_results_t *results; - WL_SCAN(("Enter \n")); - mutex_lock(&cfg->usr_sync); - - results = wl_escan_get_buf(cfg, FALSE); - results->version = 0; - results->count = 0; - results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; - - cfg->escan_info.ndev = ndev; - cfg->escan_info.wiphy = wiphy; - cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING; - passive_scan = cfg->active_scan ? 0 : 1; - err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan), true); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - goto exit; - } - - err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START); -exit: - mutex_unlock(&cfg->usr_sync); - return err; -} - -static s32 -__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request, - struct cfg80211_ssid *this_ssid) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct cfg80211_ssid *ssids; - struct ether_addr primary_mac; - bool p2p_ssid; -#ifdef WL11U - bcm_tlv_t *interworking_ie; -#endif - s32 err = 0; - s32 bssidx = -1; - s32 i; - - unsigned long flags; - static s32 busy_count = 0; -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - struct net_device *remain_on_channel_ndev = NULL; -#endif - - dhd_pub_t *dhd; - - dhd = (dhd_pub_t *)(cfg->pub); - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - WL_ERR(("Invalid Scan Command at SoftAP mode\n")); - return -EINVAL; - } - - ndev = ndev_to_wlc_ndev(ndev, cfg); - - if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) { - WL_ERR(("Sending Action Frames. Try it again.\n")); - return -EAGAIN; - } - - WL_DBG(("Enter wiphy (%p)\n", wiphy)); - if (wl_get_drv_status_all(cfg, SCANNING)) { - if (cfg->scan_request == NULL) { - wl_clr_drv_status_all(cfg, SCANNING); - WL_DBG(("<<<<<<<<<<>>>>>>>>>>\n")); - } else { - WL_ERR(("Scanning already\n")); - return -EAGAIN; - } - } - if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) { - WL_ERR(("Scanning being aborted\n")); - return -EAGAIN; - } - if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { - WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); - return -EOPNOTSUPP; - } -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg); - if (remain_on_channel_ndev) { - WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n")); - wl_notify_escan_complete(cfg, remain_on_channel_ndev, true, true); - } -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - - - /* Arm scan timeout timer */ - mod_timer(&cfg->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); - if (request) { /* scan bss */ - ssids = request->ssids; - p2p_ssid = false; - for (i = 0; i < request->n_ssids; i++) { - if (ssids[i].ssid_len && - IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { - p2p_ssid = true; - break; - } - } - if (p2p_ssid) { - if (cfg->p2p_supported) { - /* p2p scan trigger */ - if (p2p_on(cfg) == false) { - /* p2p on at the first time */ - p2p_on(cfg) = true; - wl_cfgp2p_set_firm_p2p(cfg); - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, - &cfg->p2p->dev_addr, &cfg->p2p->int_addr); - } - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); - p2p_scan(cfg) = true; - } - } else { - /* legacy scan trigger - * So, we have to disable p2p discovery if p2p discovery is on - */ - if (cfg->p2p_supported) { - p2p_scan(cfg) = false; - /* If Netdevice is not equals to primary and p2p is on - * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. - */ - - if (p2p_scan(cfg) == false) { - if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { - err = wl_cfgp2p_discover_enable_search(cfg, - false); - if (unlikely(err)) { - goto scan_out; - } - - } - } - } - if (!cfg->p2p_supported || !p2p_scan(cfg)) { - - if (wl_cfgp2p_find_idx(cfg, ndev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from ndev(%p) failed\n", - ndev)); - err = BCME_ERROR; - goto scan_out; - } -#ifdef WL11U - if ((interworking_ie = wl_cfg80211_find_interworking_ie( - (u8 *)request->ie, request->ie_len)) != NULL) { - err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, - VNDR_IE_CUSTOM_FLAG, interworking_ie->id, - interworking_ie->data, interworking_ie->len); - - if (unlikely(err)) { - goto scan_out; - } - } else if (cfg->iw_ie_len != 0) { - /* we have to clear IW IE and disable gratuitous APR */ - wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, - VNDR_IE_CUSTOM_FLAG, - DOT11_MNG_INTERWORKING_ID, - 0, 0); - - wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, - bssidx); - cfg->iw_ie_len = 0; - memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN); - - cfg->wl11u = FALSE; - /* we don't care about error */ - } -#endif /* WL11U */ - err = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, - VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, - request->ie_len); - - if (unlikely(err)) { - goto scan_out; - } - - } - } - } else { /* scan in ibss */ - ssids = this_ssid; - } - - if (request && !p2p_scan(cfg)) { - WL_TRACE_HW4(("START SCAN\n")); - } - - cfg->scan_request = request; - wl_set_drv_status(cfg, SCANNING, ndev); - - if (cfg->p2p_supported) { - if (p2p_on(cfg) && p2p_scan(cfg)) { - - /* find my listen channel */ - cfg->afx_hdl->my_listen_chan = - wl_find_listen_channel(cfg, request->ie, - request->ie_len); - err = wl_cfgp2p_enable_discovery(cfg, ndev, - request->ie, request->ie_len); - - if (unlikely(err)) { - goto scan_out; - } - } - } - err = wl_do_escan(cfg, wiphy, ndev, request); - if (likely(!err)) - goto scan_success; - else - goto scan_out; - -scan_success: - busy_count = 0; - - return 0; - -scan_out: - if (err == BCME_BUSY || err == BCME_NOTREADY) { - WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY)); - err = -EBUSY; - } - -#define SCAN_EBUSY_RETRY_LIMIT 10 - if (err == -EBUSY) { - if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) { - struct ether_addr bssid; - s32 ret = 0; - busy_count = 0; - WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n", - wl_get_drv_status(cfg, SCANNING, ndev), - wl_get_drv_status(cfg, SCAN_ABORTING, ndev), - wl_get_drv_status(cfg, CONNECTING, ndev), - wl_get_drv_status(cfg, CONNECTED, ndev), - wl_get_drv_status(cfg, DISCONNECTING, ndev), - wl_get_drv_status(cfg, AP_CREATING, ndev), - wl_get_drv_status(cfg, AP_CREATED, ndev), - wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev), - wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev))); - - bzero(&bssid, sizeof(bssid)); - if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID, - &bssid, ETHER_ADDR_LEN, false)) == 0) - WL_ERR(("FW is connected with " MACDBG "/n", - MAC2STRDBG(bssid.octet))); - else - WL_ERR(("GET BSSID failed with %d\n", ret)); - - wl_cfg80211_scan_abort(cfg); - - } - } else { - busy_count = 0; - } - - wl_clr_drv_status(cfg, SCANNING, ndev); - if (timer_pending(&cfg->scan_timeout)) - del_timer_sync(&cfg->scan_timeout); - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - cfg->scan_request = NULL; - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - return err; -} - -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) -#else -static s32 -wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request) -#endif /* WL_CFG80211_P2P_DEV_IF */ -{ - s32 err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); -#if defined(WL_CFG80211_P2P_DEV_IF) - struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ - - WL_DBG(("Enter \n")); - RETURN_EIO_IF_NOT_UP(cfg); - - err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); - if (unlikely(err)) { - if ((err == BCME_EPERM) && cfg->scan_suppressed) - WL_DBG(("scan not permitted at this time (%d)\n", err)); - else - WL_ERR(("scan error (%d)\n", err)); - return err; - } - - return err; -} - -static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) -{ - s32 err = 0; - - err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold); - if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); - return err; - } - return err; -} - -static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) -{ - s32 err = 0; - - err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0); - if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); - return err; - } - return err; -} - -static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) -{ - s32 err = 0; - u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); - - retry = htod32(retry); - err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true); - if (unlikely(err)) { - WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); - return err; - } - return err; -} - -static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; - - RETURN_EIO_IF_NOT_UP(cfg); - WL_DBG(("Enter\n")); - if (changed & WIPHY_PARAM_RTS_THRESHOLD && - (cfg->conf->rts_threshold != wiphy->rts_threshold)) { - cfg->conf->rts_threshold = wiphy->rts_threshold; - err = wl_set_rts(ndev, cfg->conf->rts_threshold); - if (err != BCME_OK) - return err; - } - if (changed & WIPHY_PARAM_FRAG_THRESHOLD && - (cfg->conf->frag_threshold != wiphy->frag_threshold)) { - cfg->conf->frag_threshold = wiphy->frag_threshold; - err = wl_set_frag(ndev, cfg->conf->frag_threshold); - if (err != BCME_OK) - return err; - } - if (changed & WIPHY_PARAM_RETRY_LONG && - (cfg->conf->retry_long != wiphy->retry_long)) { - cfg->conf->retry_long = wiphy->retry_long; - err = wl_set_retry(ndev, cfg->conf->retry_long, true); - if (err != BCME_OK) - return err; - } - if (changed & WIPHY_PARAM_RETRY_SHORT && - (cfg->conf->retry_short != wiphy->retry_short)) { - cfg->conf->retry_short = wiphy->retry_short; - err = wl_set_retry(ndev, cfg->conf->retry_short, false); - if (err != BCME_OK) { - return err; - } - } - - return err; -} -static chanspec_t -channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - u8 *buf = NULL; - wl_uint32_list_t *list; - int err = BCME_OK; - chanspec_t c = 0, ret_c = 0; - int bw = 0, tmp_bw = 0; - int i; - u32 tmp_c, sb; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; -#define LOCAL_BUF_SIZE 1024 - buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags); - if (!buf) { - WL_ERR(("buf memory alloc failed\n")); - goto exit; - } - err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, - 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync); - if (err != BCME_OK) { - WL_ERR(("get chanspecs failed with %d\n", err)); - goto exit; - } - - list = (wl_uint32_list_t *)(void *)buf; - for (i = 0; i < dtoh32(list->count); i++) { - c = dtoh32(list->element[i]); - if (channel <= CH_MAX_2G_CHANNEL) { - if (!CHSPEC_IS20(c)) - continue; - if (channel == CHSPEC_CHANNEL(c)) { - ret_c = c; - bw = 20; - goto exit; - } - } - if (CHSPEC_IS20(c)) { - tmp_c = CHSPEC_CHANNEL(c); - tmp_bw = WLC_BW_CAP_20MHZ; - } - else if (CHSPEC_IS40(c)) { - tmp_c = CHSPEC_CHANNEL(c); - if (CHSPEC_SB_UPPER(c)) { - tmp_c += CH_10MHZ_APART; - } else { - tmp_c -= CH_10MHZ_APART; - } - tmp_bw = WLC_BW_CAP_40MHZ; - } - else { - tmp_c = CHSPEC_CHANNEL(c); - sb = c & WL_CHANSPEC_CTL_SB_MASK; - if (sb == WL_CHANSPEC_CTL_SB_LL) { - tmp_c -= (CH_10MHZ_APART + CH_20MHZ_APART); - } else if (sb == WL_CHANSPEC_CTL_SB_LU) { - tmp_c -= CH_10MHZ_APART; - } else if (sb == WL_CHANSPEC_CTL_SB_UL) { - tmp_c += CH_10MHZ_APART; - } else { - /* WL_CHANSPEC_CTL_SB_UU */ - tmp_c += (CH_10MHZ_APART + CH_20MHZ_APART); - } - tmp_bw = WLC_BW_CAP_80MHZ; - } - if (tmp_c != channel) - continue; - - if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) { - bw = tmp_bw; - ret_c = c; - if (bw == bw_cap) - goto exit; - } - } -exit: - if (buf) - kfree(buf); -#undef LOCAL_BUF_SIZE - WL_INFO(("return chanspec %x %d\n", ret_c, bw)); - return ret_c; -} - -void -wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - if (cfg != NULL && ibss_vsie != NULL) { - if (cfg->ibss_vsie != NULL) { - kfree(cfg->ibss_vsie); - } - cfg->ibss_vsie = ibss_vsie; - cfg->ibss_vsie_len = ibss_vsie_len; - } -} - -static void -wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg) -{ - /* free & initiralize VSIE (Vendor Specific IE) */ - if (cfg->ibss_vsie != NULL) { - kfree(cfg->ibss_vsie); - cfg->ibss_vsie = NULL; - cfg->ibss_vsie_len = 0; - } -} - -s32 -wl_cfg80211_ibss_vsie_delete(struct net_device *dev) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - char *ioctl_buf = NULL; - s32 ret = BCME_OK; - - if (cfg != NULL && cfg->ibss_vsie != NULL) { - ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (!ioctl_buf) { - WL_ERR(("ioctl memory alloc failed\n")); - return -ENOMEM; - } - - /* change the command from "add" to "del" */ - strncpy(cfg->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1); - cfg->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - - ret = wldev_iovar_setbuf(dev, "ie", - cfg->ibss_vsie, cfg->ibss_vsie_len, - ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - WL_ERR(("ret=%d\n", ret)); - - if (ret == BCME_OK) { - /* free & initiralize VSIE */ - kfree(cfg->ibss_vsie); - cfg->ibss_vsie = NULL; - cfg->ibss_vsie_len = 0; - } - - if (ioctl_buf) { - kfree(ioctl_buf); - } - } - - return ret; -} - -static s32 -wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct cfg80211_bss *bss; - struct ieee80211_channel *chan; - struct wl_join_params join_params; - int scan_suppress; - struct cfg80211_ssid ssid; - s32 scan_retry = 0; - s32 err = 0; - size_t join_params_size; - chanspec_t chanspec = 0; - u32 param[2] = {0, 0}; - u32 bw_cap = 0; - - WL_TRACE(("In\n")); - RETURN_EIO_IF_NOT_UP(cfg); - WL_INFO(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid))); - if (!params->ssid || params->ssid_len <= 0 || - params->ssid_len > DOT11_MAX_SSID_LEN) { - WL_ERR(("Invalid parameter\n")); - return -EINVAL; - } -#if defined(WL_CFG80211_P2P_DEV_IF) - chan = params->chandef.chan; -#else - chan = params->channel; -#endif /* WL_CFG80211_P2P_DEV_IF */ - if (chan) - cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); - if (wl_get_drv_status(cfg, CONNECTED, dev)) { - struct wlc_ssid *ssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID); - u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID); - u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN); - if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) && - (memcmp(params->ssid, ssid->SSID, ssid->SSID_len) == 0) && - (*channel == cfg->channel))) { - WL_ERR(("Connection already existed to " MACDBG "\n", - MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID)))); - return -EISCONN; - } - WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n", - ssid->SSID, MAC2STRDBG(bssid))); - } - - /* remove the VSIE */ - wl_cfg80211_ibss_vsie_delete(dev); - - bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); - if (!bss) { - if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) { - memcpy(ssid.ssid, params->ssid, params->ssid_len); - ssid.ssid_len = params->ssid_len; - do { - if (unlikely - (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == - -EBUSY)) { - wl_delay(150); - } else { - break; - } - } while (++scan_retry < WL_SCAN_RETRY_MAX); - - /* rtnl lock code is removed here. don't see why rtnl lock - * needs to be released. - */ - - /* wait 4 secons till scan done.... */ - schedule_timeout_interruptible(msecs_to_jiffies(4000)); - - bss = cfg80211_get_ibss(wiphy, NULL, - params->ssid, params->ssid_len); - } - } - if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) || - ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid && - !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) { - cfg->ibss_starter = false; - WL_DBG(("Found IBSS\n")); - } else { - cfg->ibss_starter = true; - } - if (chan) { - if (chan->band == IEEE80211_BAND_5GHZ) - param[0] = WLC_BAND_5G; - else if (chan->band == IEEE80211_BAND_2GHZ) - param[0] = WLC_BAND_2G; - err = wldev_iovar_getint(dev, "bw_cap", param); - if (unlikely(err)) { - WL_ERR(("Get bw_cap Failed (%d)\n", err)); - return err; - } - bw_cap = param[0]; - chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap); - } - /* - * Join with specific BSSID and cached SSID - * If SSID is zero join based on BSSID only - */ - memset(&join_params, 0, sizeof(join_params)); - memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, - params->ssid_len); - join_params.ssid.SSID_len = htod32(params->ssid_len); - if (params->bssid) { - memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN); - err = wldev_ioctl(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid, - ETHER_ADDR_LEN, true); - if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); - return err; - } - } else - memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); - wldev_iovar_setint(dev, "ibss_coalesce_allowed", IBSS_COALESCE_ALLOWED); - - if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { - scan_suppress = TRUE; - /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */ - err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, - &scan_suppress, sizeof(int), true); - if (unlikely(err)) { - WL_ERR(("Scan Suppress Setting Failed (%d)\n", err)); - return err; - } - } - - join_params.params.chanspec_list[0] = chanspec; - join_params.params.chanspec_num = 1; - wldev_iovar_setint(dev, "chanspec", chanspec); - join_params_size = sizeof(join_params); - - /* Disable Authentication, IBSS will add key if it required */ - wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED); - wldev_iovar_setint(dev, "wsec", 0); - -#ifdef WLAIBSS - /* Enable custom ibss features */ - err = wldev_iovar_setint(dev, "aibss", TRUE); - - if (unlikely(err)) { - WL_ERR(("Enable custom IBSS mode failed (%d)\n", err)); - return err; - } -#endif /* WLAIBSS */ - - err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - join_params_size, true); - if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); - return err; - } - - if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { - scan_suppress = FALSE; - /* Reset the SCAN SUPPRESS Flag */ - err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, - &scan_suppress, sizeof(int), true); - if (unlikely(err)) { - WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err)); - return err; - } - } - wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); - wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN); -#ifdef WLAIBSS - cfg->aibss_txfail_seq = 0; /* initialize the sequence */ -#endif /* WLAIBSS */ - cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */ - return err; -} - -static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = 0; - scb_val_t scbval; - u8 *curbssid; - - RETURN_EIO_IF_NOT_UP(cfg); - wl_link_down(cfg); - - WL_ERR(("Leave IBSS\n")); - curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); - wl_set_drv_status(cfg, DISCONNECTING, dev); - scbval.val = 0; - memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - if (unlikely(err)) { - wl_clr_drv_status(cfg, DISCONNECTING, dev); - WL_ERR(("error(%d)\n", err)); - return err; - } - - /* remove the VSIE */ - wl_cfg80211_ibss_vsie_delete(dev); - - return err; -} - -#ifdef MFP -static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa) -{ - u16 suite_count; - wpa_suite_mcast_t *mcast; - wpa_suite_ucast_t *ucast; - u16 len; - wpa_suite_auth_key_mgmt_t *mgmt; - - if (!wpa2ie) - return -1; - - len = wpa2ie->len; - mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; - if ((len -= WPA_SUITE_LEN) <= 0) - return BCME_BADLEN; - ucast = (wpa_suite_ucast_t *)&mcast[1]; - suite_count = ltoh16_ua(&ucast->count); - if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || - (len -= (WPA_IE_SUITE_COUNT_LEN + - (WPA_SUITE_LEN * suite_count))) <= 0) - return BCME_BADLEN; - - mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; - suite_count = ltoh16_ua(&mgmt->count); - - if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || - (len -= (WPA_IE_SUITE_COUNT_LEN + - (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { - capa[0] = *(u8 *)&mgmt->list[suite_count]; - capa[1] = *((u8 *)&mgmt->list[suite_count] + 1); - } else - return BCME_BADLEN; - - return 0; -} -#endif /* MFP */ - -static s32 -wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - s32 val = 0; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) - val = WPA_AUTH_PSK | -#ifdef BCMCCX - WPA_AUTH_CCKM | -#endif - WPA_AUTH_UNSPECIFIED; - else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) - val = WPA2_AUTH_PSK| -#ifdef BCMCCX - WPA2_AUTH_CCKM | -#endif - WPA2_AUTH_UNSPECIFIED; - else - val = WPA_AUTH_DISABLED; - - if (is_wps_conn(sme)) - val = WPA_AUTH_DISABLED; - -#ifdef BCMWAPI_WPI - if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { - WL_DBG((" * wl_set_wpa_version, set wpa_auth" - " to WPA_AUTH_WAPI 0x400")); - val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED; - } -#endif - WL_DBG(("setting wpa_auth to 0x%0x\n", val)); - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); - if (unlikely(err)) { - WL_ERR(("set wpa_auth failed (%d)\n", err)); - return err; - } - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - sec->wpa_versions = sme->crypto.wpa_versions; - return err; -} - -#ifdef BCMWAPI_WPI -static s32 -wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - WL_DBG((" %s \n", __FUNCTION__)); - - if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { - err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", sme->ie, sme->ie_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - if (unlikely(err)) { - WL_ERR(("===> set_wapi_ie Error (%d)\n", err)); - return err; - } - } else - WL_DBG((" * skip \n")); - return err; -} -#endif /* BCMWAPI_WPI */ - -static s32 -wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - s32 val = 0; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - switch (sme->auth_type) { - case NL80211_AUTHTYPE_OPEN_SYSTEM: - val = WL_AUTH_OPEN_SYSTEM; - WL_DBG(("open system\n")); - break; - case NL80211_AUTHTYPE_SHARED_KEY: - val = WL_AUTH_SHARED_KEY; - WL_DBG(("shared key\n")); - break; - case NL80211_AUTHTYPE_AUTOMATIC: - val = WL_AUTH_OPEN_SHARED; - WL_DBG(("automatic\n")); - break; -#ifdef BCMCCX - case NL80211_AUTHTYPE_NETWORK_EAP: - WL_DBG(("network eap\n")); - val = DOT11_LEAP_AUTH; - break; -#endif - default: - val = 2; - WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); - break; - } - - err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); - if (unlikely(err)) { - WL_ERR(("set auth failed (%d)\n", err)); - return err; - } - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - sec->auth_type = sme->auth_type; - return err; -} - -static s32 -wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - s32 pval = 0; - s32 gval = 0; - s32 err = 0; - s32 wsec_val = 0; -#ifdef MFP - s32 mfp = 0; - bcm_tlv_t *wpa2_ie; - u8 rsn_cap[2]; -#endif /* MFP */ - -#ifdef BCMWAPI_WPI - s32 val = 0; -#endif - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - 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: - case WLAN_CIPHER_SUITE_AES_CMAC: - pval = AES_ENABLED; - break; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - val = SMS4_ENABLED; - pval = SMS4_ENABLED; - break; -#endif - 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; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - val = SMS4_ENABLED; - gval = SMS4_ENABLED; - break; -#endif - default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); - return -EINVAL; - } - } - - WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); - - if (is_wps_conn(sme)) { - if (sme->privacy) - err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); - else - /* WPS-2.0 allows no security */ - err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); - } else { -#ifdef BCMWAPI_WPI - if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) { - WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED")); - err = wldev_iovar_setint_bsscfg(dev, "wsec", val, bssidx); - } else { -#endif - WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); - wsec_val = pval | gval; - -#ifdef MFP - if (pval == AES_ENABLED) { - if (((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, - DOT11_MNG_RSN_ID)) != NULL) && - (wl_cfg80211_get_rsn_capa(wpa2_ie, rsn_cap) == 0)) { - - if (rsn_cap[0] & RSN_CAP_MFPC) { - /* MFP Capability advertised by supplicant. Check - * whether MFP is supported in the firmware - */ - if ((err = wldev_iovar_getint_bsscfg(dev, - "mfp", &mfp, bssidx)) < 0) { - WL_ERR(("Get MFP failed! " - "Check MFP support in FW \n")); - return -1; - } - - if ((sme->crypto.n_akm_suites == 1) && - ((sme->crypto.akm_suites[0] == - WL_AKM_SUITE_MFP_PSK) || - (sme->crypto.akm_suites[0] == - WL_AKM_SUITE_MFP_1X))) { - wsec_val |= MFP_SHA256; - } else if (sme->crypto.n_akm_suites > 1) { - WL_ERR(("Multiple AKM Specified \n")); - return -EINVAL; - } - - wsec_val |= MFP_CAPABLE; - if (rsn_cap[0] & RSN_CAP_MFPR) - wsec_val |= MFP_REQUIRED; - if (rsn_cap[0] & RSN_CAP_MFPR) - mfp = WL_MFP_REQUIRED; - else - mfp = WL_MFP_CAPABLE; - - err = wldev_iovar_setint_bsscfg(dev, "mfp", - mfp, bssidx); - } - } - } -#endif /* MFP */ - WL_DBG((" Set WSEC to fW 0x%x \n", wsec_val)); - err = wldev_iovar_setint_bsscfg(dev, "wsec", - wsec_val, bssidx); -#ifdef BCMWAPI_WPI - } -#endif - } - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; - sec->cipher_group = sme->crypto.cipher_group; - - return err; -} - -static s32 -wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - s32 val = 0; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - if (sme->crypto.n_akm_suites) { - err = wldev_iovar_getint(dev, "wpa_auth", &val); - if (unlikely(err)) { - WL_ERR(("could not get wpa_auth (%d)\n", err)); - return err; - } - if (val & (WPA_AUTH_PSK | -#ifdef BCMCCX - WPA_AUTH_CCKM | -#endif - 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; -#ifdef BCMCCX - case WLAN_AKM_SUITE_CCKM: - val = WPA_AUTH_CCKM; - break; -#endif - default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); - return -EINVAL; - } - } else if (val & (WPA2_AUTH_PSK | -#ifdef BCMCCX - WPA2_AUTH_CCKM | -#endif - WPA2_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_8021X: - val = WPA2_AUTH_UNSPECIFIED; - break; -#ifdef MFP - case WL_AKM_SUITE_MFP_1X: - val = WPA2_AUTH_UNSPECIFIED; - break; - case WL_AKM_SUITE_MFP_PSK: - val = WPA2_AUTH_PSK; - break; -#endif - case WLAN_AKM_SUITE_PSK: - val = WPA2_AUTH_PSK; - break; -#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X) - case WLAN_AKM_SUITE_FT_8021X: - val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; - break; -#endif -#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK) - case WLAN_AKM_SUITE_FT_PSK: - val = WPA2_AUTH_PSK | WPA2_AUTH_FT; - break; -#endif -#ifdef BCMCCX - case WLAN_AKM_SUITE_CCKM: - val = WPA2_AUTH_CCKM; - break; -#endif - default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); - return -EINVAL; - } - } -#ifdef BCMWAPI_WPI - else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_WAPI_CERT: - val = WAPI_AUTH_UNSPECIFIED; - break; - case WLAN_AKM_SUITE_WAPI_PSK: - val = WAPI_AUTH_PSK; - break; - default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); - return -EINVAL; - } - } -#endif - WL_DBG(("setting wpa_auth to %d\n", val)); - - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); - if (unlikely(err)) { - WL_ERR(("could not set wpa_auth (%d)\n", err)); - return err; - } - } - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - sec->wpa_auth = sme->crypto.akm_suites[0]; - - return err; -} - -static s32 -wl_set_set_sharedkey(struct net_device *dev, - struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_security *sec; - struct wl_wsec_key key; - s32 val; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - WL_DBG(("key len (%d)\n", sme->key_len)); - if (sme->key_len) { - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", - sec->wpa_versions, sec->cipher_pairwise)); - if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | -#ifdef BCMWAPI_WPI - NL80211_WPA_VERSION_2 | NL80211_WAPI_VERSION_1)) && -#else - NL80211_WPA_VERSION_2)) && -#endif - (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | -#ifdef BCMWAPI_WPI - WLAN_CIPHER_SUITE_WEP104 | WLAN_CIPHER_SUITE_SMS4))) -#else - WLAN_CIPHER_SUITE_WEP104))) -#endif - { - memset(&key, 0, sizeof(key)); - key.len = (u32) sme->key_len; - key.index = (u32) sme->key_idx; - if (unlikely(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 = WL_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; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - key.algo = CRYPTO_ALGO_SMS4; - break; -#endif - default: - WL_ERR(("Invalid algorithm (%d)\n", - sme->crypto.ciphers_pairwise[0])); - return -EINVAL; - } - /* Set the new key/index */ - WL_DBG(("key length (%d) key index (%d) algo (%d)\n", - key.len, key.index, key.algo)); - WL_DBG(("key \"%s\"\n", key.data)); - swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - return err; - } - if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { - WL_DBG(("set auth_type to shared key\n")); - val = WL_AUTH_SHARED_KEY; /* shared key */ - err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); - if (unlikely(err)) { - WL_ERR(("set auth failed (%d)\n", err)); - return err; - } - } - } - } - return err; -} - -#if defined(ESCAN_RESULT_PATCH) -static u8 connect_req_bssid[6]; -static u8 broad_bssid[6]; -#endif /* ESCAN_RESULT_PATCH */ - - - -#if defined(CONFIG_TCPACK_FASTTX) -static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd) -{ - u32 chanspec = 0; - bool isvht80 = 0; - - if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK) - chanspec = wl_chspec_driver_to_host(chanspec); - - isvht80 = chanspec & WL_CHANSPEC_BW_80; - WL_INFO(("%s: chanspec(%x:%d)\n", __FUNCTION__, chanspec, isvht80)); - - return isvht80; -} -#endif - -static s32 -wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct ieee80211_channel *chan = sme->channel; - wl_extjoin_params_t *ext_join_params; - struct wl_join_params join_params; - size_t join_params_size; -#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - s32 roam_trigger[2] = {0, 0}; -#endif /* ROAM_AP_ENV_DETECTION */ - s32 err = 0; - wpa_ie_fixed_t *wpa_ie; - bcm_tlv_t *wpa2_ie; - u8* wpaie = 0; - u32 wpaie_len = 0; - u32 chan_cnt = 0; - struct ether_addr bssid; - s32 bssidx; - int ret; - int wait_cnt; - - WL_DBG(("In\n")); - - if (unlikely(!sme->ssid)) { - WL_ERR(("Invalid ssid\n")); - return -EOPNOTSUPP; - } - - if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) { - WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n", - sme->ssid, sme->ssid_len)); - return -EINVAL; - } - - RETURN_EIO_IF_NOT_UP(cfg); - - /* - * Cancel ongoing scan to sync up with sme state machine of cfg80211. - */ -#if !defined(ESCAN_RESULT_PATCH) - if (cfg->scan_request) { - wl_notify_escan_complete(cfg, dev, true, true); - } -#endif -#ifdef WL_SCHED_SCAN - if (cfg->sched_scan_req) { - wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg)); - } -#endif -#if defined(ESCAN_RESULT_PATCH) - if (sme->bssid) - memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); - else - bzero(connect_req_bssid, ETHER_ADDR_LEN); - bzero(broad_bssid, ETHER_ADDR_LEN); -#endif -#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) - maxrxpktglom = 0; -#endif - bzero(&bssid, sizeof(bssid)); - if (!wl_get_drv_status(cfg, CONNECTED, dev)&& - (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { - if (!ETHER_ISNULLADDR(&bssid)) { - scb_val_t scbval; - wl_set_drv_status(cfg, DISCONNECTING, dev); - scbval.val = DOT11_RC_DISASSOC_LEAVING; - memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN); - scbval.val = htod32(scbval.val); - - WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n", - MAC2STRDBG(bssid.octet))); - err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - if (unlikely(err)) { - wl_clr_drv_status(cfg, DISCONNECTING, dev); - WL_ERR(("error (%d)\n", err)); - return err; - } - wait_cnt = 500/10; - while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) { - WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", - wait_cnt)); - wait_cnt--; - OSL_SLEEP(10); - } - } else - WL_DBG(("Currently not associated!\n")); - } else { - /* if status is DISCONNECTING, wait for disconnection terminated max 500 ms */ - wait_cnt = 500/10; - while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) { - WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt)); - wait_cnt--; - OSL_SLEEP(10); - } - } - - /* Clean BSSID */ - bzero(&bssid, sizeof(bssid)); - if (!wl_get_drv_status(cfg, DISCONNECTING, dev)) - wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID); - - if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) { - /* we only allow to connect using virtual interface in case of P2P */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); - } else if (dev == bcmcfg_to_prmry_ndev(cfg)) { - /* find the RSN_IE */ - if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, - DOT11_MNG_RSN_ID)) != NULL) { - WL_DBG((" WPA2 IE is found\n")); - } - /* find the WPA_IE */ - if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, - sme->ie_len)) != NULL) { - WL_DBG((" WPA IE is found\n")); - } - if (wpa_ie != NULL || wpa2_ie != NULL) { - wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; - wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; - wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; - wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - } else { - wldev_iovar_setbuf(dev, "wpaie", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - } - - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len); - if (unlikely(err)) { - return err; - } - } -#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) - if (dhd->roam_env_detection) { - bool is_roamtrig_reset = TRUE; - bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection", - AP_ENV_DETECT_NOT_USED) == BCME_OK); - if (is_roamtrig_reset && is_roam_env_ok) { - roam_trigger[0] = WL_AUTO_ROAM_TRIGGER; - roam_trigger[1] = WLC_BAND_ALL; - err = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, - sizeof(roam_trigger), true); - if (unlikely(err)) { - WL_ERR((" failed to restore roam_trigger for auto env" - " detection\n")); - } - } - } -#endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */ - if (chan) { - cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); - chan_cnt = 1; - WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel, - chan->center_freq, chan_cnt)); - } else - cfg->channel = 0; -#ifdef BCMWAPI_WPI - WL_DBG(("1. enable wapi auth\n")); - if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { - WL_DBG(("2. set wapi ie \n")); - err = wl_set_set_wapi_ie(dev, sme); - if (unlikely(err)) - return err; - } else - WL_DBG(("2. Not wapi ie \n")); -#endif - WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); - WL_DBG(("3. set wapi version \n")); - err = wl_set_wpa_version(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid wpa_version\n")); - return err; - } -#ifdef BCMWAPI_WPI - if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) - WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n")); - else { - WL_DBG(("4. wl_set_auth_type\n")); -#endif - err = wl_set_auth_type(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid auth type\n")); - return err; - } -#ifdef BCMWAPI_WPI - } -#endif - - err = wl_set_set_cipher(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid ciper\n")); - return err; - } - - err = wl_set_key_mgmt(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid key mgmt\n")); - return err; - } - - err = wl_set_set_sharedkey(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid shared key\n")); - return err; - } - - /* - * Join with specific BSSID and cached SSID - * If SSID is zero join based on BSSID only - */ - join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + - chan_cnt * sizeof(chanspec_t); - ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL); - if (ext_join_params == NULL) { - err = -ENOMEM; - wl_clr_drv_status(cfg, CONNECTING, dev); - goto exit; - } - ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); - memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); - wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID); - ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); - /* increate dwell time to receive probe response or detect Beacon - * from target AP at a noisy air only during connect command - */ - ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1; - ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1; - /* Set up join scan parameters */ - ext_join_params->scan.scan_type = -1; - ext_join_params->scan.nprobes = chan_cnt ? - (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1; - ext_join_params->scan.home_time = -1; - - if (sme->bssid) - memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN); - else - memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN); - ext_join_params->assoc.chanspec_num = chan_cnt; - if (chan_cnt) { - u16 channel, band, bw, ctl_sb; - chanspec_t chspec; - channel = cfg->channel; - band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G - : WL_CHANSPEC_BAND_5G; - bw = WL_CHANSPEC_BW_20; - ctl_sb = WL_CHANSPEC_CTL_SB_NONE; - chspec = (channel | band | bw | ctl_sb); - ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; - ext_join_params->assoc.chanspec_list[0] |= chspec; - ext_join_params->assoc.chanspec_list[0] = - wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); - } - ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); - if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { - WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID, - ext_join_params->ssid.SSID_len)); - } - wl_set_drv_status(cfg, CONNECTING, dev); - - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - kfree(ext_join_params); - return BCME_ERROR; - } - err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - WL_ERR(("Connectting with" MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n", - MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), cfg->channel, - ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len)); - - kfree(ext_join_params); - if (err) { - wl_clr_drv_status(cfg, CONNECTING, dev); - if (err == BCME_UNSUPPORTED) { - WL_DBG(("join iovar is not supported\n")); - goto set_ssid; - } else { - WL_ERR(("error (%d)\n", err)); - goto exit; - } - } else - goto exit; - -set_ssid: - memset(&join_params, 0, sizeof(join_params)); - join_params_size = sizeof(join_params.ssid); - - join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len); - memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); - join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); - wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); - if (sme->bssid) - memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); - else - memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); - - wl_ch_to_chanspec(cfg->channel, &join_params, &join_params_size); - WL_DBG(("join_param_size %zu\n", join_params_size)); - - if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { - WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, - join_params.ssid.SSID_len)); - } - wl_set_drv_status(cfg, CONNECTING, dev); - err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true); - if (err) { - WL_ERR(("error (%d)\n", err)); - wl_clr_drv_status(cfg, CONNECTING, dev); - } -exit: - return err; -} - -static s32 -wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - scb_val_t scbval; - bool act = false; - s32 err = 0; - u8 *curbssid; - WL_ERR(("Reason %d\n", reason_code)); - RETURN_EIO_IF_NOT_UP(cfg); - act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT); - curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); - if (act) { - /* - * Cancel ongoing scan to sync up with sme state machine of cfg80211. - */ -#if !defined(ESCAN_RESULT_PATCH) - /* Let scan aborted by F/W */ - if (cfg->scan_request) { - wl_notify_escan_complete(cfg, dev, true, true); - } -#endif /* ESCAN_RESULT_PATCH */ - wl_set_drv_status(cfg, DISCONNECTING, dev); - scbval.val = reason_code; - memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - scbval.val = htod32(scbval.val); - err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - if (unlikely(err)) { - wl_clr_drv_status(cfg, DISCONNECTING, dev); - WL_ERR(("error (%d)\n", err)); - return err; - } - } - - return err; -} - -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, s32 mbm) -#else -static s32 -wl_cfg80211_set_tx_power(struct wiphy *wiphy, - enum nl80211_tx_power_setting type, s32 dbm) -#endif /* WL_CFG80211_P2P_DEV_IF */ -{ - - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; -#if defined(WL_CFG80211_P2P_DEV_IF) - s32 dbm = MBM_TO_DBM(mbm); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \ - defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES) - dbm = MBM_TO_DBM(dbm); -#endif /* WL_CFG80211_P2P_DEV_IF */ - - RETURN_EIO_IF_NOT_UP(cfg); - switch (type) { - case NL80211_TX_POWER_AUTOMATIC: - break; - case NL80211_TX_POWER_LIMITED: - if (dbm < 0) { - WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n")); - return -EINVAL; - } - break; - case NL80211_TX_POWER_FIXED: - if (dbm < 0) { - WL_ERR(("TX_POWER_FIXED - dbm is negative..\n")); - return -EINVAL; - } - break; - } - - err = wl_set_tx_power(ndev, type, dbm); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - - cfg->conf->tx_power = dbm; - - return err; -} - -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, s32 *dbm) -#else -static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) -#endif /* WL_CFG80211_P2P_DEV_IF */ -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; - - RETURN_EIO_IF_NOT_UP(cfg); - err = wl_get_tx_power(ndev, dbm); - if (unlikely(err)) - WL_ERR(("error (%d)\n", err)); - - return err; -} - -static s32 -wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool unicast, bool multicast) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - u32 index; - s32 wsec; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - WL_DBG(("key index (%d)\n", key_idx)); - RETURN_EIO_IF_NOT_UP(cfg); - err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); - if (unlikely(err)) { - WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); - return err; - } - if (wsec == WEP_ENABLED) { - /* Just select a new current key */ - index = (u32) key_idx; - index = htod32(index); - err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, - sizeof(index), true); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - } - } - return err; -} - -static s32 -wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, const u8 *mac_addr, struct key_params *params) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct wl_wsec_key key; - s32 err = 0; - s32 bssidx; - s32 mode = wl_get_mode_by_netdev(cfg, dev); - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - memset(&key, 0, sizeof(key)); - key.index = (u32) key_idx; - - if (!ETHER_ISMULTI(mac_addr)) - memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); - key.len = (u32) params->key_len; - - /* check for key index change */ - if (key.len == 0) { - /* key delete */ - swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("key delete error (%d)\n", err)); - return err; - } - } else { - if (key.len > sizeof(key.data)) { - WL_ERR(("Invalid key length (%d)\n", key.len)); - return -EINVAL; - } - WL_DBG(("Setting the key index %d\n", key.index)); - memcpy(key.data, params->key, key.len); - - if ((mode == WL_MODE_BSS) && - (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_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); - break; - case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); - break; - case WLAN_CIPHER_SUITE_TKIP: - key.algo = CRYPTO_ALGO_TKIP; - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - key.algo = CRYPTO_ALGO_AES_CCM; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); - break; - case WLAN_CIPHER_SUITE_CCMP: - key.algo = CRYPTO_ALGO_AES_CCM; - WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); - break; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - key.algo = CRYPTO_ALGO_SMS4; - WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); - break; -#endif - default: - WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); - return -EINVAL; - } - swap_key_from_BE(&key); - /* need to guarantee EAPOL 4/4 send out before set key */ - dhd_wait_pend8021x(dev); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - return err; - } - } - return err; -} - -int -wl_cfg80211_enable_roam_offload(struct net_device *dev, bool enable) -{ - int err; - wl_eventmsg_buf_t ev_buf; - - if (dev != bcmcfg_to_prmry_ndev(g_bcm_cfg)) { - /* roam offload is only for the primary device */ - return -1; - } - err = wldev_iovar_setint(dev, "roam_offload", (int)enable); - if (err) - return err; - - bzero(&ev_buf, sizeof(wl_eventmsg_buf_t)); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable); - wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable); - err = wl_cfg80211_apply_eventbuffer(dev, g_bcm_cfg, &ev_buf); - if (!err) { - g_bcm_cfg->roam_offload = enable; - } - return err; -} - -static s32 -wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - struct key_params *params) -{ - struct wl_wsec_key key; - s32 val = 0; - s32 wsec = 0; - s32 err = 0; - u8 keybuf[8]; - s32 bssidx = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 mode = wl_get_mode_by_netdev(cfg, dev); - WL_DBG(("key index (%d)\n", key_idx)); - RETURN_EIO_IF_NOT_UP(cfg); - - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - if (mac_addr && - ((params->cipher != WLAN_CIPHER_SUITE_WEP40) && - (params->cipher != WLAN_CIPHER_SUITE_WEP104))) { - wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); - goto exit; - } - memset(&key, 0, sizeof(key)); - - key.len = (u32) params->key_len; - key.index = (u32) key_idx; - - if (unlikely(key.len > sizeof(key.data))) { - WL_ERR(("Too long key length (%u)\n", key.len)); - return -EINVAL; - } - memcpy(key.data, params->key, key.len); - - key.flags = WL_PRIMARY_KEY; - switch (params->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - key.algo = CRYPTO_ALGO_WEP1; - val = WEP_ENABLED; - WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); - break; - case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; - val = WEP_ENABLED; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); - break; - case WLAN_CIPHER_SUITE_TKIP: - key.algo = CRYPTO_ALGO_TKIP; - val = TKIP_ENABLED; - /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ - if (mode == WL_MODE_BSS) { - bcopy(&key.data[24], keybuf, sizeof(keybuf)); - bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); - bcopy(keybuf, &key.data[16], sizeof(keybuf)); - } - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - key.algo = CRYPTO_ALGO_AES_CCM; - val = AES_ENABLED; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); - break; - case WLAN_CIPHER_SUITE_CCMP: - key.algo = CRYPTO_ALGO_AES_CCM; - val = AES_ENABLED; - WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); - break; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - key.algo = CRYPTO_ALGO_SMS4; - WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); - val = SMS4_ENABLED; - break; -#endif /* BCMWAPI_WPI */ -#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK) - case WLAN_CIPHER_SUITE_PMK: { - int j; - wsec_pmk_t pmk; - char keystring[WSEC_MAX_PSK_LEN + 1]; - char* charptr = keystring; - uint len; - struct wl_security *sec; - - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - if (sec->wpa_auth == WLAN_AKM_SUITE_8021X) { - err = wldev_iovar_setbuf(dev, "okc_info_pmk", params->key, - WSEC_MAX_PSK_LEN / 2, keystring, sizeof(keystring), NULL); - if (err) { - /* could fail in case that 'okc' is not supported */ - WL_INFO(("Setting 'okc_info_pmk' failed, err=%d\n", err)); - } - } - /* copy the raw hex key to the appropriate format */ - for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { - sprintf(charptr, "%02x", params->key[j]); - charptr += 2; - } - len = strlen(keystring); - pmk.key_len = htod16(len); - bcopy(keystring, pmk.key, len); - pmk.flags = htod16(WSEC_PASSPHRASE); - - err = wldev_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk), true); - if (err) - return err; - } break; -#endif /* WLFBT && WLAN_CIPHER_SUITE_PMK */ - default: - WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); - return -EINVAL; - } - - /* Set the new key/index */ - if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) { - WL_ERR(("IBSS KEY setted\n")); - wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE); - } - swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - return err; - } - -exit: - err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); - if (unlikely(err)) { - WL_ERR(("get wsec error (%d)\n", err)); - return err; - } - - wsec |= val; - err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); - if (unlikely(err)) { - WL_ERR(("set wsec error (%d)\n", err)); - return err; - } - - return err; -} - -static s32 -wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr) -{ - struct wl_wsec_key key; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - WL_DBG(("Enter\n")); - -#ifndef IEEE80211W - if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) - return -EINVAL; -#endif - - RETURN_EIO_IF_NOT_UP(cfg); - memset(&key, 0, sizeof(key)); - - key.flags = WL_PRIMARY_KEY; - key.algo = CRYPTO_ALGO_OFF; - key.index = (u32) key_idx; - - WL_DBG(("key index (%d)\n", key_idx)); - /* Set the new key/index */ - swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - if (err == -EINVAL) { - if (key.index >= DOT11_MAX_DEFAULT_KEYS) { - /* we ignore this key index in this case */ - WL_DBG(("invalid key index (%d)\n", key_idx)); - } - } else { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - } - return err; - } - return err; -} - -static s32 -wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, - void (*callback) (void *cookie, struct key_params * params)) -{ - struct key_params params; - struct wl_wsec_key key; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct wl_security *sec; - s32 wsec; - s32 err = 0; - s32 bssidx; - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - WL_DBG(("key index (%d)\n", key_idx)); - RETURN_EIO_IF_NOT_UP(cfg); - memset(&key, 0, sizeof(key)); - key.index = key_idx; - swap_key_to_BE(&key); - memset(¶ms, 0, sizeof(params)); - params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); - memcpy(params.key, key.data, params.key_len); - - err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); - if (unlikely(err)) { - WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); - return err; - } - switch (wsec & ~SES_OW_ENABLED) { - case WEP_ENABLED: - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { - params.cipher = WLAN_CIPHER_SUITE_WEP40; - WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); - } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { - params.cipher = WLAN_CIPHER_SUITE_WEP104; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); - } - break; - case TKIP_ENABLED: - params.cipher = WLAN_CIPHER_SUITE_TKIP; - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); - break; - case AES_ENABLED: - params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); - break; -#ifdef BCMWAPI_WPI - case WLAN_CIPHER_SUITE_SMS4: - key.algo = CRYPTO_ALGO_SMS4; - WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); - break; -#endif - default: - WL_ERR(("Invalid algo (0x%x)\n", wsec)); - return -EINVAL; - } - - callback(cookie, ¶ms); - return err; -} - -static s32 -wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *dev, u8 key_idx) -{ -#ifdef MFP - return 0; -#else - WL_INFO(("Not supported\n")); - return -EOPNOTSUPP; -#endif /* MFP */ -} - -static s32 -wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac, struct station_info *sinfo) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - scb_val_t scb_val; - s32 rssi; - s32 rate; - s32 err = 0; - sta_info_t *sta; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - s8 eabuf[ETHER_ADDR_STR_LEN]; -#endif - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - RETURN_EIO_IF_NOT_UP(cfg); - if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { - err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, - ETHER_ADDR_LEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); - if (err < 0) { - WL_ERR(("GET STA INFO failed, %d\n", err)); - return err; - } - sinfo->filled = STATION_INFO_INACTIVE_TIME; - sta = (sta_info_t *)cfg->ioctl_buf; - sta->len = dtoh16(sta->len); - sta->cap = dtoh16(sta->cap); - sta->flags = dtoh32(sta->flags); - sta->idle = dtoh32(sta->idle); - sta->in = dtoh32(sta->in); - sinfo->inactive_time = sta->idle * 1000; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - if (sta->flags & WL_STA_ASSOC) { - sinfo->filled |= STATION_INFO_CONNECTED_TIME; - sinfo->connected_time = sta->in; - } - WL_INFO(("STA %s : idle time : %d sec, connected time :%d ms\n", - bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time, - sta->idle * 1000)); -#endif - } else if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS || - wl_get_mode_by_netdev(cfg, dev) == WL_MODE_IBSS) { - get_pktcnt_t pktcnt; - u8 *curmacp; - - if (cfg->roam_offload) { - struct ether_addr bssid; - memset(&bssid, 0, sizeof(bssid)); - err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - if (err) { - WL_ERR(("Failed to get current BSSID\n")); - } else { - if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) { - /* roaming is detected */ - err = wl_cfg80211_delayed_roam(cfg, dev, &bssid); - if (err) - WL_ERR(("Failed to handle the delayed roam, " - "err=%d", err)); - mac = (u8 *)bssid.octet; - } - } - } - if (!wl_get_drv_status(cfg, CONNECTED, dev) || - (dhd_is_associated(dhd, NULL, &err) == FALSE)) { - WL_ERR(("NOT assoc\n")); - if (err == -ERESTARTSYS) - return err; - err = -ENODEV; - return err; - } - curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID); - if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { - WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n", - MAC2STRDBG(mac), MAC2STRDBG(curmacp))); - } - - /* Report the current tx rate */ - rate = 0; - err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); - if (err) { - WL_ERR(("Could not get rate (%d)\n", err)); - } else { -#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) - int rxpktglom; -#endif - rate = dtoh32(rate); - sinfo->filled |= STATION_INFO_TX_BITRATE; - sinfo->txrate.legacy = rate * 5; - WL_DBG(("Rate %d Mbps\n", (rate / 2))); -#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) - rxpktglom = ((rate/2) > 150) ? 20 : 10; - - if (maxrxpktglom != rxpktglom) { - maxrxpktglom = rxpktglom; - WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2), - maxrxpktglom)); - err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom", - (char*)&maxrxpktglom, 4, cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, NULL); - if (err < 0) { - WL_ERR(("set bus:maxtxpktglom failed, %d\n", err)); - } - } -#endif - } - - memset(&scb_val, 0, sizeof(scb_val)); - scb_val.val = 0; - err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t), false); - if (err) { - WL_ERR(("Could not get rssi (%d)\n", err)); - goto get_station_err; - } - rssi = wl_rssi_offset(dtoh32(scb_val.val)); - sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = rssi; - WL_DBG(("RSSI %d dBm\n", rssi)); - memset(&pktcnt, 0, sizeof(pktcnt)); - err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt, - sizeof(pktcnt), false); - if (!err) { - sinfo->filled |= (STATION_INFO_RX_PACKETS | - STATION_INFO_RX_DROP_MISC | - STATION_INFO_TX_PACKETS | - STATION_INFO_TX_FAILED); - sinfo->rx_packets = pktcnt.rx_good_pkt; - sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt; - sinfo->tx_packets = pktcnt.tx_good_pkt; - sinfo->tx_failed = pktcnt.tx_bad_pkt; - } -get_station_err: - if (err && (err != -ERESTARTSYS)) { - /* Disconnect due to zero BSSID or error to get RSSI */ - WL_ERR(("force cfg80211_disconnected: %d\n", err)); - wl_clr_drv_status(cfg, CONNECTED, dev); - cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL); - wl_link_down(cfg); - } - } - else { - WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev))); - } - - return err; -} - -static s32 -wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - bool enabled, s32 timeout) -{ - s32 pm; - s32 err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev); - - RETURN_EIO_IF_NOT_UP(cfg); - WL_DBG(("Enter\n")); - if (cfg->p2p_net == dev || _net_info == NULL || cfg->vsdb_mode || - !wl_get_drv_status(cfg, CONNECTED, dev)) { - return err; - } - - /* Delete pm_enable_work */ - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_PEND); - - pm = enabled ? PM_FAST : PM_OFF; - if (_net_info->pm_block) { - WL_ERR(("%s:Do not enable the power save for pm_block %d\n", - dev->name, _net_info->pm_block)); - pm = PM_OFF; - } - pm = htod32(pm); - WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled"))); - err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true); - if (unlikely(err)) { - if (err == -ENODEV) - WL_DBG(("net_device is not ready yet\n")); - else - WL_ERR(("error (%d)\n", err)); - return err; - } - wl_cfg80211_update_power_mode(dev); - return err; -} - -void wl_cfg80211_update_power_mode(struct net_device *dev) -{ - int err, pm = -1; - - err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), false); - if (err) - WL_ERR(("%s:error (%d)\n", __FUNCTION__, err)); - else if (pm != -1 && dev->ieee80211_ptr) - dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true; -} - -static __used u32 wl_find_msb(u16 bit16) -{ - u32 ret = 0; - - if (bit16 & 0xff00) { - ret += 8; - bit16 >>= 8; - } - - if (bit16 & 0xf0) { - ret += 4; - bit16 >>= 4; - } - - if (bit16 & 0xc) { - ret += 2; - bit16 >>= 2; - } - - if (bit16 & 2) - ret += bit16 & 2; - else if (bit16) - ret += bit16; - - return ret; -} - -static s32 wl_cfg80211_resume(struct wiphy *wiphy) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; - - if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) { - WL_INFO(("device is not ready\n")); - return 0; - } - - return err; -} - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) -static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) -#else -static s32 wl_cfg80211_suspend(struct wiphy *wiphy) -#endif -{ -#ifdef DHD_CLEAR_ON_SUSPEND - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_info *iter, *next; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - unsigned long flags; - if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) { - WL_INFO(("device is not ready : status (%d)\n", - (int)cfg->status)); - return 0; - } - for_each_ndev(cfg, iter, next) - wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - if (cfg->scan_request) { - cfg80211_scan_done(cfg->scan_request, true); - cfg->scan_request = NULL; - } - for_each_ndev(cfg, iter, next) { - wl_clr_drv_status(cfg, SCANNING, iter->ndev); - wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev); - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - for_each_ndev(cfg, iter, next) { - if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) { - wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false); - } - } -#endif /* DHD_CLEAR_ON_SUSPEND */ - return 0; -} - -static s32 -wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, - s32 err) -{ - int i, j; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); - - if (!pmk_list) { - printk("pmk_list is NULL\n"); - return -EINVAL; - } - /* pmk list is supported only for STA interface i.e. primary interface - * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init - */ - if (primary_dev != dev) { - WL_INFO(("Not supporting Flushing pmklist on virtual" - " interfaces than primary interface\n")); - return err; - } - - WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid)); - for (i = 0; i < pmk_list->pmkids.npmkid; i++) { - WL_DBG(("PMKID[%d]: %pM =\n", i, - &pmk_list->pmkids.pmkid[i].BSSID)); - for (j = 0; j < WPA2_PMKID_LEN; j++) { - WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j])); - } - } - if (likely(!err)) { - err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, - sizeof(*pmk_list), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - } - - return err; -} - -static s32 -wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = 0; - int i; - - RETURN_EIO_IF_NOT_UP(cfg); - for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++) - if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, - ETHER_ADDR_LEN)) - break; - if (i < WL_NUM_PMKIDS_MAX) { - memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, - ETHER_ADDR_LEN); - memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, - WPA2_PMKID_LEN); - if (i == cfg->pmk_list->pmkids.npmkid) - cfg->pmk_list->pmkids.npmkid++; - } else { - err = -EINVAL; - } - WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", - &cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].BSSID)); - for (i = 0; i < WPA2_PMKID_LEN; i++) { - WL_DBG(("%02x\n", - cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1]. - PMKID[i])); - } - - err = wl_update_pmklist(dev, cfg->pmk_list, err); - - return err; -} - -static s32 -wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct _pmkid_list pmkid = {0}; - s32 err = 0; - int i; - - RETURN_EIO_IF_NOT_UP(cfg); - memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); - memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); - - WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", - &pmkid.pmkid[0].BSSID)); - for (i = 0; i < WPA2_PMKID_LEN; i++) { - WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i])); - } - - for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++) - if (!memcmp - (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, - ETHER_ADDR_LEN)) - break; - - if ((cfg->pmk_list->pmkids.npmkid > 0) && - (i < cfg->pmk_list->pmkids.npmkid)) { - memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t)); - for (; i < (cfg->pmk_list->pmkids.npmkid - 1); i++) { - memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, - &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID, - ETHER_ADDR_LEN); - memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, - &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID, - WPA2_PMKID_LEN); - } - cfg->pmk_list->pmkids.npmkid--; - } else { - err = -EINVAL; - } - - err = wl_update_pmklist(dev, cfg->pmk_list, err); - - return err; - -} - -static s32 -wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = 0; - RETURN_EIO_IF_NOT_UP(cfg); - memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list)); - err = wl_update_pmklist(dev, cfg->pmk_list, err); - return err; - -} - -static wl_scan_params_t * -wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) -{ - wl_scan_params_t *params; - int params_size; - int num_chans; - - *out_params_size = 0; - - /* Our scan params only need space for 1 channel and 0 ssids */ - params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); - params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); - if (params == NULL) { - WL_ERR(("mem alloc failed (%d bytes)\n", params_size)); - return params; - } - memset(params, 0, params_size); - params->nprobes = nprobes; - - num_chans = (channel == 0) ? 0 : 1; - - memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); - params->bss_type = DOT11_BSSTYPE_ANY; - params->scan_type = DOT11_SCANTYPE_ACTIVE; - params->nprobes = htod32(1); - params->active_time = htod32(-1); - params->passive_time = htod32(-1); - params->home_time = htod32(10); - if (channel == -1) - params->channel_list[0] = htodchanspec(channel); - else - params->channel_list[0] = wl_ch_host_to_driver(channel); - - /* Our scan params have 1 channel and 0 ssids */ - params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | - (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); - - *out_params_size = params_size; /* rtn size to the caller */ - return params; -} - -#if defined(WL_CFG80211_P2P_DEV_IF) -static s32 -wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - struct ieee80211_channel *channel, unsigned int duration, u64 *cookie) -#else -static s32 -wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - struct ieee80211_channel * channel, - enum nl80211_channel_type channel_type, - unsigned int duration, u64 *cookie) -#endif /* WL_CFG80211_P2P_DEV_IF */ -{ - s32 target_channel; - u32 id; - s32 err = BCME_OK; - struct ether_addr primary_mac; - struct net_device *ndev = NULL; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n", - ieee80211_frequency_to_channel(channel->center_freq), - duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO")); - - if (!cfg->p2p) { - WL_ERR(("cfg->p2p is not initialized\n")); - err = BCME_ERROR; - goto exit; - } - -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - if (wl_get_drv_status_all(cfg, SCANNING)) { - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); - } -#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - - target_channel = ieee80211_frequency_to_channel(channel->center_freq); - memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel)); -#if defined(WL_ENABLE_P2P_IF) - cfg->remain_on_chan_type = channel_type; -#endif /* WL_ENABLE_P2P_IF */ - id = ++cfg->last_roc_id; - if (id == 0) - id = ++cfg->last_roc_id; - *cookie = id; - -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - if (wl_get_drv_status(cfg, SCANNING, ndev)) { - struct timer_list *_timer; - WL_DBG(("scan is running. go to fake listen state\n")); - - wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); - - if (timer_pending(&cfg->p2p->listen_timer)) { - WL_DBG(("cancel current listen timer \n")); - del_timer_sync(&cfg->p2p->listen_timer); - } - - _timer = &cfg->p2p->listen_timer; - wl_clr_p2p_status(cfg, LISTEN_EXPIRED); - - INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0); - - err = BCME_OK; - goto exit; - } -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - -#ifdef WL_CFG80211_SYNC_GON - if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { - /* do not enter listen mode again if we are in listen mode already for next af. - * remain on channel completion will be returned by waiting next af completion. - */ -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); -#else - wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - goto exit; - } -#endif /* WL_CFG80211_SYNC_GON */ - if (cfg->p2p && !cfg->p2p->on) { - /* In case of p2p_listen command, supplicant send remain_on_channel - * without turning on P2P - */ - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr, &cfg->p2p->int_addr); - p2p_on(cfg) = true; - } - - if (p2p_is_on(cfg)) { - err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0); - if (unlikely(err)) { - goto exit; - } -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); -#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - err = wl_cfgp2p_discover_listen(cfg, target_channel, duration); - -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - if (err == BCME_OK) { - wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); - } else { - /* if failed, firmware may be internal scanning state. - * so other scan request shall not abort it - */ - wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); - } -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant - * and expire timer will send a completion to the upper layer - */ - err = BCME_OK; - } - -exit: - if (err == BCME_OK) { - WL_INFO(("Success\n")); -#if defined(WL_CFG80211_P2P_DEV_IF) - cfg80211_ready_on_channel(cfgdev, *cookie, channel, - duration, GFP_KERNEL); -#else - cfg80211_ready_on_channel(cfgdev, *cookie, channel, - channel_type, duration, GFP_KERNEL); -#endif /* WL_CFG80211_P2P_DEV_IF */ - } else { - WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); - } - return err; -} - -static s32 -wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, - bcm_struct_cfgdev *cfgdev, u64 cookie) -{ - s32 err = 0; - -#if defined(WL_CFG80211_P2P_DEV_IF) - if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { - WL_DBG((" enter ) on P2P dedicated discover interface\n")); - } -#else - WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex)); -#endif /* WL_CFG80211_P2P_DEV_IF */ - return err; -} - -static void -wl_cfg80211_afx_handler(struct work_struct *work) -{ - struct afx_hdl *afx_instance; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - s32 ret = BCME_OK; - - afx_instance = container_of(work, struct afx_hdl, work); - if (afx_instance != NULL && cfg->afx_hdl->is_active) { - if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) { - ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan, - (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */ - } else { - ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev, - cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan, - NULL); - } - if (unlikely(ret != BCME_OK)) { - WL_ERR(("ERROR occurred! returned value is (%d)\n", ret)); - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) - complete(&cfg->act_frm_scan); - } - } -} - -static s32 -wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev) -{ - u32 max_retry = WL_CHANNEL_SYNC_RETRY; - - if (dev == NULL) - return -1; - - WL_DBG((" enter ) \n")); - - wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev); - cfg->afx_hdl->is_active = TRUE; - - /* Loop to wait until we find a peer's channel or the - * pending action frame tx is cancelled. - */ - while ((cfg->afx_hdl->retry < max_retry) && - (cfg->afx_hdl->peer_chan == WL_INVALID)) { - cfg->afx_hdl->is_listen = FALSE; - wl_set_drv_status(cfg, SCANNING, dev); - WL_DBG(("Scheduling the action frame for sending.. retry %d\n", - cfg->afx_hdl->retry)); - /* search peer on peer's listen channel */ - schedule_work(&cfg->afx_hdl->work); - wait_for_completion_timeout(&cfg->act_frm_scan, - msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); - - if ((cfg->afx_hdl->peer_chan != WL_INVALID) || - !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) - break; - - if (cfg->afx_hdl->my_listen_chan) { - WL_DBG(("Scheduling Listen peer in my listen channel = %d\n", - cfg->afx_hdl->my_listen_chan)); - /* listen on my listen channel */ - cfg->afx_hdl->is_listen = TRUE; - schedule_work(&cfg->afx_hdl->work); - wait_for_completion_timeout(&cfg->act_frm_scan, - msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); - } - if ((cfg->afx_hdl->peer_chan != WL_INVALID) || - !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) - break; - - cfg->afx_hdl->retry++; - - WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg); - } - - cfg->afx_hdl->is_active = FALSE; - - wl_clr_drv_status(cfg, SCANNING, dev); - wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev); - - return (cfg->afx_hdl->peer_chan); -} - -struct p2p_config_af_params { - s32 max_tx_retry; /* max tx retry count if tx no ack */ - /* To make sure to send successfully action frame, we have to turn off mpc - * 0: off, 1: on, (-1): do nothing - */ - s32 mpc_onoff; -#ifdef WL_CFG80211_SYNC_GON - bool extra_listen; -#endif - bool search_channel; /* 1: search peer's channel to send af */ -}; - -static s32 -wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, - wl_action_frame_t *action_frame, wl_af_params_t *af_params, - struct p2p_config_af_params *config_af_params) -{ - s32 err = BCME_OK; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - wifi_p2p_pub_act_frame_t *act_frm = - (wifi_p2p_pub_act_frame_t *) (action_frame->data); - - /* initialize default value */ -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = true; -#endif - config_af_params->search_channel = false; - config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; - config_af_params->mpc_onoff = -1; - cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; - - switch (act_frm->subtype) { - case P2P_PAF_GON_REQ: { - WL_DBG(("P2P: GO_NEG_PHASE status set \n")); - wl_set_p2p_status(cfg, GO_NEG_PHASE); - - config_af_params->mpc_onoff = 0; - config_af_params->search_channel = true; - cfg->next_af_subtype = act_frm->subtype + 1; - - /* increase dwell time to wait for RESP frame */ - af_params->dwell_time = WL_MED_DWELL_TIME; - - break; - } - case P2P_PAF_GON_RSP: { - cfg->next_af_subtype = act_frm->subtype + 1; - /* increase dwell time to wait for CONF frame */ - af_params->dwell_time = WL_MED_DWELL_TIME + 100; - break; - } - case P2P_PAF_GON_CONF: { - /* If we reached till GO Neg confirmation reset the filter */ - WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - - /* turn on mpc again if go nego is done */ - config_af_params->mpc_onoff = 1; - - /* minimize dwell time */ - af_params->dwell_time = WL_MIN_DWELL_TIME; - -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = false; -#endif /* WL_CFG80211_SYNC_GON */ - break; - } - case P2P_PAF_INVITE_REQ: { - config_af_params->search_channel = true; - cfg->next_af_subtype = act_frm->subtype + 1; - - /* increase dwell time */ - af_params->dwell_time = WL_MED_DWELL_TIME; - break; - } - case P2P_PAF_INVITE_RSP: - /* minimize dwell time */ - af_params->dwell_time = WL_MIN_DWELL_TIME; -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = false; -#endif /* WL_CFG80211_SYNC_GON */ - break; - case P2P_PAF_DEVDIS_REQ: { - if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0], - action_frame->len)) { - config_af_params->search_channel = true; - } - - cfg->next_af_subtype = act_frm->subtype + 1; - /* maximize dwell time to wait for RESP frame */ - af_params->dwell_time = WL_LONG_DWELL_TIME; - break; - } - case P2P_PAF_DEVDIS_RSP: - /* minimize dwell time */ - af_params->dwell_time = WL_MIN_DWELL_TIME; -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = false; -#endif /* WL_CFG80211_SYNC_GON */ - break; - case P2P_PAF_PROVDIS_REQ: { - if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0], - action_frame->len)) { - config_af_params->search_channel = true; - } - - config_af_params->mpc_onoff = 0; - cfg->next_af_subtype = act_frm->subtype + 1; - /* increase dwell time to wait for RESP frame */ - af_params->dwell_time = WL_MED_DWELL_TIME; - break; - } - case P2P_PAF_PROVDIS_RSP: { - cfg->next_af_subtype = P2P_PAF_GON_REQ; - af_params->dwell_time = WL_MIN_DWELL_TIME; -#ifdef WL_CFG80211_SYNC_GON - config_af_params->extra_listen = false; -#endif /* WL_CFG80211_SYNC_GON */ - break; - } - default: - WL_DBG(("Unknown p2p pub act frame subtype: %d\n", - act_frm->subtype)); - err = BCME_BADARG; - } - return err; -} - -#ifdef WL11U -static bool -wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params, - void *frame, u16 frame_len) -{ - struct wl_scan_results *bss_list; - struct wl_bss_info *bi = NULL; - bool result = false; - s32 i; - chanspec_t chanspec; - - /* If DFS channel is 52~148, check to block it or not */ - if (af_params && - (af_params->channel >= 52 && af_params->channel <= 148)) { - if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) { - bss_list = cfg->bss_list; - bi = next_bss(bss_list, bi); - for_each_bss(bss_list, bi, i) { - chanspec = wl_chspec_driver_to_host(bi->chanspec); - if (CHSPEC_IS5G(chanspec) && - ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec)) - == af_params->channel)) { - result = true; /* do not block the action frame */ - break; - } - } - } - } - else { - result = true; - } - - WL_DBG(("result=%s", result?"true":"false")); - return result; -} -#endif /* WL11U */ - - -static bool -wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, - bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params, - wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) -{ -#ifdef WL11U - struct net_device *ndev = NULL; -#endif /* WL11U */ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - bool ack = false; - u8 category, action; - s32 tx_retry; - struct p2p_config_af_params config_af_params; -#ifdef VSDB - ulong off_chan_started_jiffies = 0; -#endif - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - - - /* Add the default dwell time - * Dwell time to stay off-channel to wait for a response action frame - * after transmitting an GO Negotiation action frame - */ - af_params->dwell_time = WL_DWELL_TIME; - -#ifdef WL11U -#if defined(WL_CFG80211_P2P_DEV_IF) - ndev = dev; -#else - ndev = ndev_to_cfgdev(cfgdev); -#endif /* WL_CFG80211_P2P_DEV_IF */ -#endif /* WL11U */ - - category = action_frame->data[DOT11_ACTION_CAT_OFF]; - action = action_frame->data[DOT11_ACTION_ACT_OFF]; - - /* initialize variables */ - tx_retry = 0; - cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; - config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY; - config_af_params.mpc_onoff = -1; - config_af_params.search_channel = false; -#ifdef WL_CFG80211_SYNC_GON - config_af_params.extra_listen = false; -#endif - - /* config parameters */ - /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */ - if (category == DOT11_ACTION_CAT_PUBLIC) { - if ((action == P2P_PUB_AF_ACTION) && - (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) { - /* p2p public action frame process */ - if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy, - action_frame, af_params, &config_af_params)) { - WL_DBG(("Unknown subtype.\n")); - } - - } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) { - /* service discovery process */ - if (action == P2PSD_ACTION_ID_GAS_IREQ || - action == P2PSD_ACTION_ID_GAS_CREQ) { - /* configure service discovery query frame */ - - config_af_params.search_channel = true; - - /* save next af suptype to cancel remained dwell time */ - cfg->next_af_subtype = action + 1; - - af_params->dwell_time = WL_MED_DWELL_TIME; - } else if (action == P2PSD_ACTION_ID_GAS_IRESP || - action == P2PSD_ACTION_ID_GAS_CRESP) { - /* configure service discovery response frame */ - af_params->dwell_time = WL_MIN_DWELL_TIME; - } else { - WL_DBG(("Unknown action type: %d\n", action)); - } - } else { - WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n", - category, action, action_frame_len)); - } - } else if (category == P2P_AF_CATEGORY) { - /* do not configure anything. it will be sent with a default configuration */ - } else { - WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n", - category, action)); - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev); - return false; - } - } - - /* To make sure to send successfully action frame, we have to turn off mpc */ - if (config_af_params.mpc_onoff == 0) { - wldev_iovar_setint(dev, "mpc", 0); - } - - /* validate channel and p2p ies */ - if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) && - wl_to_p2p_bss_saved_ie(cfg, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { - config_af_params.search_channel = true; - } else { - config_af_params.search_channel = false; - } -#ifdef WL11U - if (ndev == bcmcfg_to_prmry_ndev(cfg)) - config_af_params.search_channel = false; -#endif /* WL11U */ - -#ifdef VSDB - /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ - if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { - OSL_SLEEP(50); - } -#endif - - /* if scan is ongoing, abort current scan. */ - if (wl_get_drv_status_all(cfg, SCANNING)) { - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); - } - - /* Abort P2P listen */ - if (discover_cfgdev(cfgdev, cfg)) { - if (cfg->p2p_supported && cfg->p2p) { - wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - } - } - -#ifdef WL11U - /* handling DFS channel exceptions */ - if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) { - return false; /* the action frame was blocked */ - } -#endif /* WL11U */ - - /* set status and destination address before sending af */ - if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { - /* set this status to cancel the remained dwell time in rx process */ - wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev); - } - wl_set_drv_status(cfg, SENDING_ACT_FRM, dev); - memcpy(cfg->afx_hdl->tx_dst_addr.octet, - af_params->action_frame.da.octet, - sizeof(cfg->afx_hdl->tx_dst_addr.octet)); - - /* save af_params for rx process */ - cfg->afx_hdl->pending_tx_act_frm = af_params; - - /* search peer's channel */ - if (config_af_params.search_channel) { - /* initialize afx_hdl */ - if (wl_cfgp2p_find_idx(cfg, dev, &cfg->afx_hdl->bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - goto exit; - } - cfg->afx_hdl->dev = dev; - cfg->afx_hdl->retry = 0; - cfg->afx_hdl->peer_chan = WL_INVALID; - - if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) { - WL_ERR(("couldn't find peer's channel.\n")); - wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, - af_params->channel); - goto exit; - } - - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - /* - * Abort scan even for VSDB scenarios. Scan gets aborted in firmware - * but after the check of piggyback algorithm. - * To take care of current piggback algo, lets abort the scan here itself. - */ - wl_notify_escan_complete(cfg, dev, true, true); - /* Suspend P2P discovery's search-listen to prevent it from - * starting a scan or changing the channel. - */ - wl_cfgp2p_discover_enable_search(cfg, false); - - /* update channel */ - af_params->channel = cfg->afx_hdl->peer_chan; - } - -#ifdef VSDB - off_chan_started_jiffies = jiffies; -#endif /* VSDB */ - - wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel); - - wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true); - - /* Now send a tx action frame */ - ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true; - - /* if failed, retry it. tx_retry_max value is configure by .... */ - while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) { -#ifdef VSDB - if (af_params->channel) { - if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) > - OFF_CHAN_TIME_THRESHOLD_MS) { - WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg); - off_chan_started_jiffies = jiffies; - } else - OSL_SLEEP(AF_RETRY_DELAY_TIME); - } -#endif /* VSDB */ - ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? - false : true; - } - - if (ack == false) { - WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry)); - } - WL_DBG(("Complete to send action frame\n")); -exit: - /* Clear SENDING_ACT_FRM after all sending af is done */ - wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev); - -#ifdef WL_CFG80211_SYNC_GON - /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. - * if we coundn't get the next action response frame and dongle does not keep - * the dwell time, go to listen state again to get next action response frame. - */ - if (ack && config_af_params.extra_listen && - wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) && - cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) { - s32 extar_listen_time; - - extar_listen_time = af_params->dwell_time - - jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies); - - if (extar_listen_time > 50) { - wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev); - WL_DBG(("Wait more time! actual af time:%d," - "calculated extar listen:%d\n", - af_params->dwell_time, extar_listen_time)); - if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel, - extar_listen_time + 100) == BCME_OK) { - wait_for_completion_timeout(&cfg->wait_next_af, - msecs_to_jiffies(extar_listen_time + 100 + 300)); - } - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev); - } - } -#endif /* WL_CFG80211_SYNC_GON */ - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev); - - if (cfg->afx_hdl->pending_tx_act_frm) - cfg->afx_hdl->pending_tx_act_frm = NULL; - - WL_INFO(("-- sending Action Frame is %s, listen chan: %d\n", - (ack) ? "Succeeded!!":"Failed!!", cfg->afx_hdl->my_listen_chan)); - - - /* if all done, turn mpc on again */ - if (config_af_params.mpc_onoff == 1) { - wldev_iovar_setint(dev, "mpc", 1); - } - - return ack; -} - -#define MAX_NUM_OF_ASSOCIATED_DEV 64 -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) -static s32 -wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - struct cfg80211_mgmt_tx_params *params, u64 *cookie) -#else -static s32 -wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - struct ieee80211_channel *channel, bool offchan, -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0)) - enum nl80211_channel_type channel_type, - bool channel_type_valid, -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) */ - unsigned int wait, const u8* buf, size_t len, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - bool no_cck, -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) - bool dont_wait_for_ack, -#endif - u64 *cookie) -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ -{ - wl_action_frame_t *action_frame; - wl_af_params_t *af_params; - scb_val_t scb_val; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - struct ieee80211_channel *channel = params->chan; - const u8 *buf = params->buf; - size_t len = params->len; -#endif - const struct ieee80211_mgmt *mgmt; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *dev = NULL; - s32 err = BCME_OK; - s32 bssidx = 0; - u32 id; - bool ack = false; - s8 eabuf[ETHER_ADDR_STR_LEN]; - - WL_DBG(("Enter \n")); - - if (len > (ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN)) { - WL_ERR(("bad length:%zu\n", len)); - return BCME_BADLEN; - } - - dev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */ - if (discover_cfgdev(cfgdev, cfg)) { - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - } - else { - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - } - - WL_DBG(("TX target bssidx=%d\n", bssidx)); - - if (p2p_is_on(cfg)) { - /* Suspend P2P discovery search-listen to prevent it from changing the - * channel. - */ - if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) { - WL_ERR(("Can not disable discovery mode\n")); - return -EFAULT; - } - } - *cookie = 0; - id = cfg->send_action_id++; - if (id == 0) - id = cfg->send_action_id++; - *cookie = id; - mgmt = (const struct ieee80211_mgmt *)buf; - if (ieee80211_is_mgmt(mgmt->frame_control)) { - if (ieee80211_is_probe_resp(mgmt->frame_control)) { - s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; - s32 ie_len = len - ie_offset; - if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); - cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); - goto exit; - } else if (ieee80211_is_disassoc(mgmt->frame_control) || - ieee80211_is_deauth(mgmt->frame_control)) { - char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * - sizeof(struct ether_addr) + sizeof(uint)] = {0}; - int num_associated = 0; - struct maclist *assoc_maclist = (struct maclist *)mac_buf; - if (!bcmp((const uint8 *)BSSID_BROADCAST, - (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) { - assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; - err = wldev_ioctl(dev, WLC_GET_ASSOCLIST, - assoc_maclist, sizeof(mac_buf), false); - if (err < 0) - WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); - else - num_associated = assoc_maclist->count; - } - memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); - scb_val.val = mgmt->u.disassoc.reason_code; - err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, - sizeof(scb_val_t), true); - if (err < 0) - WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err)); - WL_ERR(("Disconnect STA : %s scb_val.val %d\n", - bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), - scb_val.val)); - - if (num_associated > 0 && ETHER_ISBCAST(mgmt->da)) - wl_delay(400); - - cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); - goto exit; - - } else if (ieee80211_is_action(mgmt->frame_control)) { - /* Abort the dwell time of any previous off-channel - * action frame that may be still in effect. Sending - * off-channel action frames relies on the driver's - * scan engine. If a previous off-channel action frame - * tx is still in progress (including the dwell time), - * then this new action frame will not be sent out. - */ -/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary. - * And previous off-channel action frame must be ended before new af tx. - */ -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_notify_escan_complete(cfg, dev, true, true); -#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - } - - } else { - WL_ERR(("Driver only allows MGMT packet type\n")); - goto exit; - } - - af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); - - if (af_params == NULL) - { - WL_ERR(("unable to allocate frame\n")); - return -ENOMEM; - } - - action_frame = &af_params->action_frame; - - /* Add the packet Id */ - action_frame->packetId = *cookie; - WL_DBG(("action frame %d\n", action_frame->packetId)); - /* Add BSSID */ - memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); - memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN); - - /* Add the length exepted for 802.11 header */ - action_frame->len = len - DOT11_MGMT_HDR_LEN; - WL_DBG(("action_frame->len: %d\n", action_frame->len)); - - /* Add the channel */ - af_params->channel = - ieee80211_frequency_to_channel(channel->center_freq); - /* Save listen_chan for searching common channel */ - cfg->afx_hdl->peer_listen_chan = af_params->channel; - WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan)); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - af_params->dwell_time = params->wait; -#else - af_params->dwell_time = wait; -#endif - - memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); - - ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params, - action_frame, action_frame->len, bssidx); - cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL); - - kfree(af_params); -exit: - return err; -} - - -static void -wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, - u16 frame_type, bool reg) -{ - - WL_DBG(("frame_type: %x, reg: %d\n", frame_type, reg)); - - if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) - return; - - return; -} - - -static s32 -wl_cfg80211_change_bss(struct wiphy *wiphy, - struct net_device *dev, - struct bss_parameters *params) -{ - s32 err = 0; - s32 ap_isolate = 0; -#if defined(SUPPORT_HOSTAPD_BGN_MODE) - dhd_pub_t *dhd; - s32 gmode = -1, nmode = -1; - s32 gmode_prev = -1, nmode_prev = -1; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); -#if defined(WL_ENABLE_P2P_IF) - if (cfg->p2p_net == dev) - dev = bcmcfg_to_prmry_ndev(cfg); -#endif - dhd = (dhd_pub_t *)(cfg->pub); -#endif /* SUPPORT_HOSTAPD_BGN_MODE */ - - if (params->use_cts_prot >= 0) { - } - - if (params->use_short_preamble >= 0) { - } - - if (params->use_short_slot_time >= 0) { - } - - if (params->basic_rates) { -#if defined(SUPPORT_HOSTAPD_BGN_MODE) - switch ((int)(params->basic_rates[params->basic_rates_len -1])) { - case 22: /* B only , rate 11 */ - gmode = 0; - nmode = 0; - break; - case 108: /* G only , rate 54 */ - gmode = 2; - nmode = 0; - break; - default: - gmode = -1; - nmode = -1; - break; - } -#endif /* SUPPORT_HOSTAPD_BGN_MODE */ - } - - if (params->ap_isolate >= 0) { - ap_isolate = params->ap_isolate; - err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate); - if (unlikely(err)) - { - WL_ERR(("set ap_isolate Error (%d)\n", err)); - } - } - - if (params->ht_opmode >= 0) { -#if defined(SUPPORT_HOSTAPD_BGN_MODE) - nmode = 1; - gmode = 1; - } else { - nmode = 0; -#endif /* SUPPORT_HOSTAPD_BGN_MODE */ - } - -#if defined(SUPPORT_HOSTAPD_BGN_MODE) - err = wldev_iovar_getint(dev, "nmode", &nmode_prev); - if (unlikely(err)) { - WL_ERR(("error reading nmode (%d)\n", err)); - } - if (nmode == nmode_prev) { - nmode = -1; - } - err = wldev_ioctl(dev, WLC_GET_GMODE, &gmode_prev, sizeof(gmode_prev), 0); - if (unlikely(err)) { - WL_ERR(("error reading gmode (%d)\n", err)); - } - if (gmode == gmode_prev) { - gmode = -1; - } - - if (((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) == DHD_FLAG_HOSTAP_MODE) && - ((gmode > -1) || (nmode > -1))) { - s32 val = 0; - - err = wldev_ioctl(dev, WLC_DOWN, &val, sizeof(s32), true); - if (unlikely(err)) - WL_ERR(("WLC_DOWN command failed:[%d]\n", err)); - - if (nmode > -1) { - err = wldev_iovar_setint(dev, "nmode", nmode); - if (unlikely(err)) - WL_ERR(("nmode command failed:mode[%d]:err[%d]\n", nmode, err)); - } - - if (gmode > -1) { - err = wldev_ioctl(dev, WLC_SET_GMODE, &gmode, sizeof(s32), true); - if (unlikely(err)) - WL_ERR(("WLC_SET_GMODE command failed:mode[%d]:err[%d]\n", - gmode, err)); - } - - val = 0; - err = wldev_ioctl(dev, WLC_UP, &val, sizeof(s32), true); - if (unlikely(err)) - WL_ERR(("WLC_UP command failed:err[%d]\n", err)); - - } -#endif /* SUPPORT_HOSTAPD_BGN_MODE */ - - return 0; -} - -static s32 -wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_channel *chan, -#ifdef WL_SUPPORT_CHAN_BW - enum nl80211_chan_width chan_width) -#else - enum nl80211_channel_type channel_type) -#endif /* WL_SUPPORT_CHAN_BW */ -{ - s32 _chan; - chanspec_t chspec = 0; - chanspec_t fw_chspec = 0; - u32 bw = WL_CHANSPEC_BW_20; - - s32 err = BCME_OK; - s32 bw_cap = 0; - struct { - u32 band; - u32 bw_cap; - } param = {0, 0}; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - dev = ndev_to_wlc_ndev(dev, cfg); - _chan = ieee80211_frequency_to_channel(chan->center_freq); -#ifdef WL_SUPPORT_CHAN_BW - WL_ERR(("netdev_ifidx(%d), chan_width(%d) target channel(%d) \n", - dev->ifindex, chan_width, _chan)); - - switch (chan_width) { - case NL80211_CHAN_WIDTH_20_NOHT: - case NL80211_CHAN_WIDTH_20: - bw = WL_CHANSPEC_BW_20; - goto set_channel; - case NL80211_CHAN_WIDTH_40: - bw = WL_CHANSPEC_BW_40; - goto set_channel; - case NL80211_CHAN_WIDTH_80: - bw = WL_CHANSPEC_BW_80; - goto set_channel; - default: - WL_ERR(("chanwidth not defined")); - return BCME_ERROR; - } -#else - WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", - dev->ifindex, channel_type, _chan)); -#endif /* WL_SUPPORT_CHAN_BW */ - - - if (chan->band == IEEE80211_BAND_5GHZ) { - param.band = WLC_BAND_5G; - err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), - cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); - if (err) { - if (err != BCME_UNSUPPORTED) { - WL_ERR(("bw_cap failed, %d\n", err)); - return err; - } else { - err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); - if (err) { - WL_ERR(("error get mimo_bw_cap (%d)\n", err)); - } - if (bw_cap != WLC_N_BW_20ALL) - bw = WL_CHANSPEC_BW_40; - } - } else { - if (WL_BW_CAP_80MHZ(cfg->ioctl_buf[0])) - bw = WL_CHANSPEC_BW_80; - else if (WL_BW_CAP_40MHZ(cfg->ioctl_buf[0])) - bw = WL_CHANSPEC_BW_40; - else - bw = WL_CHANSPEC_BW_20; - - } - - } else if (chan->band == IEEE80211_BAND_2GHZ) - bw = WL_CHANSPEC_BW_20; -set_channel: - chspec = wf_channel2chspec(_chan, bw); - if (wf_chspec_valid(chspec)) { - fw_chspec = wl_chspec_host_to_driver(chspec); - if (fw_chspec != INVCHANSPEC) { - if ((err = wldev_iovar_setint(dev, "chanspec", - fw_chspec)) == BCME_BADCHAN) { - if (bw == WL_CHANSPEC_BW_80) - goto change_bw; - err = wldev_ioctl(dev, WLC_SET_CHANNEL, - &_chan, sizeof(_chan), true); - if (err < 0) { - WL_ERR(("WLC_SET_CHANNEL error %d" - "chip may not be supporting this channel\n", err)); - } - } else if (err) { - WL_ERR(("failed to set chanspec error %d\n", err)); - } - } else { - WL_ERR(("failed to convert host chanspec to fw chanspec\n")); - err = BCME_ERROR; - } - } else { -change_bw: - if (bw == WL_CHANSPEC_BW_80) - bw = WL_CHANSPEC_BW_40; - else if (bw == WL_CHANSPEC_BW_40) - bw = WL_CHANSPEC_BW_20; - else - bw = 0; - if (bw) - goto set_channel; - WL_ERR(("Invalid chanspec 0x%x\n", chspec)); - err = BCME_ERROR; - } - return err; -} - -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -struct net_device * -wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg) -{ - struct net_info *_net_info, *next; - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (_net_info->ndev && - test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state)) - return _net_info->ndev; - } - return NULL; -} -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - -static s32 -wl_validate_opensecurity(struct net_device *dev, s32 bssidx) -{ - s32 err = BCME_OK; - - /* set auth */ - err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx); - if (err < 0) { - WL_ERR(("auth error %d\n", err)); - return BCME_ERROR; - } - /* set wsec */ - err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); - if (err < 0) { - WL_ERR(("wsec error %d\n", err)); - return BCME_ERROR; - } - - /* set upper-layer auth */ - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WPA_AUTH_NONE, bssidx); - if (err < 0) { - WL_ERR(("wpa_auth error %d\n", err)); - return BCME_ERROR; - } - - return 0; -} - -static s32 -wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) -{ - s32 len = 0; - s32 err = BCME_OK; - u16 auth = 0; /* d11 open authentication */ - u32 wsec; - u32 pval = 0; - u32 gval = 0; - u32 wpa_auth = 0; - wpa_suite_mcast_t *mcast; - wpa_suite_ucast_t *ucast; - wpa_suite_auth_key_mgmt_t *mgmt; - wpa_pmkid_list_t *pmkid; - int cnt = 0; -#ifdef MFP - int mfp = 0; - struct bcm_cfg80211 *cfg = g_bcm_cfg; -#endif /* MFP */ - - u16 suite_count; - u8 rsn_cap[2]; - u32 wme_bss_disable; - - if (wpa2ie == NULL) - goto exit; - - WL_DBG(("Enter \n")); - len = wpa2ie->len - WPA2_VERSION_LEN; - /* check the mcast cipher */ - mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; - switch (mcast->type) { - case WPA_CIPHER_NONE: - gval = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - gval = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - gval = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - gval = AES_ENABLED; - break; -#ifdef BCMWAPI_WPI - case WAPI_CIPHER_SMS4: - gval = SMS4_ENABLED; - break; -#endif - default: - WL_ERR(("No Security Info\n")); - break; - } - if ((len -= WPA_SUITE_LEN) <= 0) - return BCME_BADLEN; - - /* check the unicast cipher */ - ucast = (wpa_suite_ucast_t *)&mcast[1]; - suite_count = ltoh16_ua(&ucast->count); - switch (ucast->list[0].type) { - case WPA_CIPHER_NONE: - pval = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - pval = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - pval = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - pval = AES_ENABLED; - break; -#ifdef BCMWAPI_WPI - case WAPI_CIPHER_SMS4: - pval = SMS4_ENABLED; - break; -#endif - default: - WL_ERR(("No Security Info\n")); - } - if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0) - return BCME_BADLEN; - - /* FOR WPS , set SEC_OW_ENABLED */ - wsec = (pval | gval | SES_OW_ENABLED); - /* check the AKM */ - mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; - suite_count = cnt = ltoh16_ua(&mgmt->count); - while (cnt--) { - switch (mgmt->list[cnt].type) { - case RSN_AKM_NONE: - wpa_auth = WPA_AUTH_NONE; - break; - case RSN_AKM_UNSPECIFIED: - wpa_auth = WPA2_AUTH_UNSPECIFIED; - break; - case RSN_AKM_PSK: - wpa_auth = WPA2_AUTH_PSK; - break; -#ifdef MFP - case RSN_AKM_MFP_PSK: - wpa_auth |= WPA2_AUTH_PSK; - wsec |= MFP_SHA256; - break; - case RSN_AKM_MFP_1X: - wpa_auth |= WPA2_AUTH_UNSPECIFIED; - wsec |= MFP_SHA256; - break; -#endif /* MFP */ - - default: - WL_ERR(("No Key Mgmt Info\n")); - } - } - - if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { - rsn_cap[0] = *(u8 *)&mgmt->list[suite_count]; - rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1); - - if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) { - wme_bss_disable = 0; - } else { - wme_bss_disable = 1; - } -#ifdef MFP - if (rsn_cap[0] & RSN_CAP_MFPR) { - WL_DBG(("MFP Required \n")); - mfp = WL_MFP_REQUIRED; - } else if (rsn_cap[0] & RSN_CAP_MFPC) { - WL_DBG(("MFP Capable \n")); - mfp = WL_MFP_CAPABLE; - } -#endif /* MFP */ - - /* set wme_bss_disable to sync RSN Capabilities */ - err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx); - if (err < 0) { - WL_ERR(("wme_bss_disable error %d\n", err)); - return BCME_ERROR; - } - } else { - WL_DBG(("There is no RSN Capabilities. remained len %d\n", len)); - } - - len -= RSN_CAP_LEN; - if (len >= WPA2_PMKID_COUNT_LEN) { - pmkid = (wpa_pmkid_list_t *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN); - cnt = ltoh16_ua(&pmkid->count); - if (cnt != 0) { - WL_ERR(("AP has non-zero PMKID count. Wrong!\n")); - return BCME_ERROR; - } - /* since PMKID cnt is known to be 0 for AP, */ - /* so don't bother to send down this info to firmware */ - } - -#ifdef MFP - len -= WPA2_PMKID_COUNT_LEN; - if (len >= WPA_SUITE_LEN) { - err = wldev_iovar_setbuf_bsscfg(dev, "bip", - (void *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN), - WPA_SUITE_LEN, - cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync); - if (err < 0) { - WL_ERR(("bip set error %d\n", err)); - } - } -#endif - - /* set auth */ - err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); - if (err < 0) { - WL_ERR(("auth error %d\n", err)); - return BCME_ERROR; - } - /* set wsec */ - err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); - if (err < 0) { - WL_ERR(("wsec error %d\n", err)); - return BCME_ERROR; - } -#ifdef MFP - if (mfp) { - /* This needs to go after wsec otherwise the wsec command will - * overwrite the values set by MFP - */ - if ((err = wldev_iovar_setint_bsscfg(dev, "mfp", mfp, bssidx)) < 0) { - WL_ERR(("MFP Setting failed. ret = %d \n", err)); - return err; - } - } -#endif /* MFP */ - /* set upper-layer auth */ - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); - if (err < 0) { - WL_ERR(("wpa_auth error %d\n", err)); - return BCME_ERROR; - } -exit: - return 0; -} - -static s32 -wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) -{ - wpa_suite_mcast_t *mcast; - wpa_suite_ucast_t *ucast; - wpa_suite_auth_key_mgmt_t *mgmt; - u16 auth = 0; /* d11 open authentication */ - u16 count; - s32 err = BCME_OK; - s32 len = 0; - u32 i; - u32 wsec; - u32 pval = 0; - u32 gval = 0; - u32 wpa_auth = 0; - u32 tmp = 0; - - if (wpaie == NULL) - goto exit; - WL_DBG(("Enter \n")); - len = wpaie->length; /* value length */ - len -= WPA_IE_TAG_FIXED_LEN; - /* check for multicast cipher suite */ - if (len < WPA_SUITE_LEN) { - WL_INFO(("no multicast cipher suite\n")); - goto exit; - } - - /* pick up multicast cipher */ - mcast = (wpa_suite_mcast_t *)&wpaie[1]; - len -= WPA_SUITE_LEN; - if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) { - if (IS_WPA_CIPHER(mcast->type)) { - tmp = 0; - switch (mcast->type) { - case WPA_CIPHER_NONE: - tmp = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - tmp = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - tmp = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - tmp = AES_ENABLED; - break; - default: - WL_ERR(("No Security Info\n")); - } - gval |= tmp; - } - } - /* Check for unicast suite(s) */ - if (len < WPA_IE_SUITE_COUNT_LEN) { - WL_INFO(("no unicast suite\n")); - goto exit; - } - /* walk thru unicast cipher list and pick up what we recognize */ - ucast = (wpa_suite_ucast_t *)&mcast[1]; - count = ltoh16_ua(&ucast->count); - len -= WPA_IE_SUITE_COUNT_LEN; - for (i = 0; i < count && len >= WPA_SUITE_LEN; - i++, len -= WPA_SUITE_LEN) { - if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { - if (IS_WPA_CIPHER(ucast->list[i].type)) { - tmp = 0; - switch (ucast->list[i].type) { - case WPA_CIPHER_NONE: - tmp = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - tmp = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - tmp = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - tmp = AES_ENABLED; - break; - default: - WL_ERR(("No Security Info\n")); - } - pval |= tmp; - } - } - } - len -= (count - i) * WPA_SUITE_LEN; - /* Check for auth key management suite(s) */ - if (len < WPA_IE_SUITE_COUNT_LEN) { - WL_INFO((" no auth key mgmt suite\n")); - goto exit; - } - /* walk thru auth management suite list and pick up what we recognize */ - mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count]; - count = ltoh16_ua(&mgmt->count); - len -= WPA_IE_SUITE_COUNT_LEN; - for (i = 0; i < count && len >= WPA_SUITE_LEN; - i++, len -= WPA_SUITE_LEN) { - if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { - if (IS_WPA_AKM(mgmt->list[i].type)) { - tmp = 0; - switch (mgmt->list[i].type) { - case RSN_AKM_NONE: - tmp = WPA_AUTH_NONE; - break; - case RSN_AKM_UNSPECIFIED: - tmp = WPA_AUTH_UNSPECIFIED; - break; - case RSN_AKM_PSK: - tmp = WPA_AUTH_PSK; - break; - default: - WL_ERR(("No Key Mgmt Info\n")); - } - wpa_auth |= tmp; - } - } - - } - /* FOR WPS , set SEC_OW_ENABLED */ - wsec = (pval | gval | SES_OW_ENABLED); - /* set auth */ - err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); - if (err < 0) { - WL_ERR(("auth error %d\n", err)); - return BCME_ERROR; - } - /* set wsec */ - err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); - if (err < 0) { - WL_ERR(("wsec error %d\n", err)); - return BCME_ERROR; - } - /* set upper-layer auth */ - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); - if (err < 0) { - WL_ERR(("wpa_auth error %d\n", err)); - return BCME_ERROR; - } -exit: - return 0; -} - - -static s32 -wl_cfg80211_bcn_validate_sec( - struct net_device *dev, - struct parsed_ies *ies, - u32 dev_role, - s32 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) { - /* For P2P GO, the sec type is WPA2-PSK */ - WL_DBG(("P2P GO: validating wpa2_ie")); - if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0) - return BCME_ERROR; - - } else if (dev_role == NL80211_IFTYPE_AP) { - - WL_DBG(("SoftAP: validating security")); - /* If wpa2_ie or wpa_ie is present validate it */ - - if ((ies->wpa2_ie || ies->wpa_ie) && - ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || - wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) { - cfg->ap_info->security_mode = false; - return BCME_ERROR; - } - - cfg->ap_info->security_mode = true; - if (cfg->ap_info->rsn_ie) { - kfree(cfg->ap_info->rsn_ie); - cfg->ap_info->rsn_ie = NULL; - } - if (cfg->ap_info->wpa_ie) { - kfree(cfg->ap_info->wpa_ie); - cfg->ap_info->wpa_ie = NULL; - } - if (cfg->ap_info->wps_ie) { - kfree(cfg->ap_info->wps_ie); - cfg->ap_info->wps_ie = NULL; - } - if (ies->wpa_ie != NULL) { - /* WPAIE */ - cfg->ap_info->rsn_ie = NULL; - cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, - ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } else if (ies->wpa2_ie != NULL) { - /* RSNIE */ - cfg->ap_info->wpa_ie = NULL; - cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, - ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } - if (!ies->wpa2_ie && !ies->wpa_ie) { - wl_validate_opensecurity(dev, bssidx); - cfg->ap_info->security_mode = false; - } - - if (ies->wps_ie) { - cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); - } - } - - return 0; - -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) -static s32 wl_cfg80211_bcn_set_params( - struct cfg80211_ap_settings *info, - struct net_device *dev, - u32 dev_role, s32 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - s32 err = BCME_OK; - - WL_DBG(("interval (%d) \ndtim_period (%d) \n", - info->beacon_interval, info->dtim_period)); - - if (info->beacon_interval) { - if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, - &info->beacon_interval, sizeof(s32), true)) < 0) { - WL_ERR(("Beacon Interval Set Error, %d\n", err)); - return err; - } - } - - if (info->dtim_period) { - if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, - &info->dtim_period, sizeof(s32), true)) < 0) { - WL_ERR(("DTIM Interval Set Error, %d\n", err)); - return err; - } - } - - if ((info->ssid) && (info->ssid_len > 0) && - (info->ssid_len <= DOT11_MAX_SSID_LEN)) { - WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len)); - if (dev_role == NL80211_IFTYPE_AP) { - /* Store the hostapd SSID */ - memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); - memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len); - cfg->hostapd_ssid.SSID_len = info->ssid_len; - } else { - /* P2P GO */ - memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); - memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len); - cfg->p2p->ssid.SSID_len = info->ssid_len; - } - } - - if (info->hidden_ssid) { - if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) - WL_ERR(("failed to set hidden : %d\n", err)); - WL_ERR(("hidden_ssid_enum_val: %d \n", info->hidden_ssid)); - } - - return err; -} -#endif - -static s32 -wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies) -{ - s32 err = BCME_OK; - - memset(ies, 0, sizeof(struct parsed_ies)); - - /* find the WPSIE */ - if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) { - WL_DBG(("WPSIE in beacon \n")); - ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; - } else { - WL_ERR(("No WPSIE in beacon \n")); - } - - /* find the RSN_IE */ - if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, - DOT11_MNG_RSN_ID)) != NULL) { - WL_DBG((" WPA2 IE found\n")); - ies->wpa2_ie_len = ies->wpa2_ie->len; - } - - /* find the WPA_IE */ - if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) { - WL_DBG((" WPA found\n")); - ies->wpa_ie_len = ies->wpa_ie->length; - } - - return err; - -} - -static s32 -wl_cfg80211_bcn_bringup_ap( - struct net_device *dev, - struct parsed_ies *ies, - u32 dev_role, s32 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wl_join_params join_params; - bool is_bssup = false; - s32 infra = 1; - s32 join_params_size = 0; - s32 ap = 1; -#ifdef DISABLE_11H_SOFTAP - s32 spect = 0; -#endif /* DISABLE_11H_SOFTAP */ - s32 err = BCME_OK; - - WL_DBG(("Enter dev_role: %d\n", dev_role)); - - /* Common code for SoftAP and P2P GO */ - wldev_iovar_setint(dev, "mpc", 0); - - if (dev_role == NL80211_IFTYPE_P2P_GO) { - is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); - if (!is_bssup && (ies->wpa2_ie != NULL)) { - - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET INFRA error %d\n", err)); - goto exit; - } - - err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid, - sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, - bssidx, &cfg->ioctl_buf_sync); - if (err < 0) { - WL_ERR(("GO SSID setting error %d\n", err)); - goto exit; - } - - /* Do abort scan before creating GO */ - wl_cfg80211_scan_abort(cfg); - - if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) { - WL_ERR(("GO Bring up error %d\n", err)); - goto exit; - } - } else - WL_DBG(("Bss is already up\n")); - } else if ((dev_role == NL80211_IFTYPE_AP) && - (wl_get_drv_status(cfg, AP_CREATING, dev))) { - /* Device role SoftAP */ - err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); - if (err < 0) { - WL_ERR(("WLC_DOWN error %d\n", err)); - goto exit; - } - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET INFRA error %d\n", err)); - goto exit; - } - if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { - WL_ERR(("setting AP mode failed %d \n", err)); - goto exit; - } -#ifdef DISABLE_11H_SOFTAP - err = wldev_ioctl(dev, WLC_SET_SPECT_MANAGMENT, - &spect, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET SPECT_MANAGMENT error %d\n", err)); - goto exit; - } -#endif /* DISABLE_11H_SOFTAP */ - - err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); - if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); - goto exit; - } - - memset(&join_params, 0, sizeof(join_params)); - /* join parameters starts with ssid */ - join_params_size = sizeof(join_params.ssid); - join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len, - (uint32)DOT11_MAX_SSID_LEN); - memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID, - join_params.ssid.SSID_len); - join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); - - /* create softap */ - if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - join_params_size, true)) == 0) { - WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID)); - wl_clr_drv_status(cfg, AP_CREATING, dev); - wl_set_drv_status(cfg, AP_CREATED, dev); - } - } - - -exit: - return err; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) -s32 -wl_cfg80211_parse_ap_ies( - struct net_device *dev, - struct cfg80211_beacon_data *info, - struct parsed_ies *ies) -{ - struct parsed_ies prb_ies; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - u8 *vndr = NULL; - u32 vndr_ie_len = 0; - s32 err = BCME_OK; - - /* Parse Beacon IEs */ - if (wl_cfg80211_parse_ies((u8 *)info->tail, - info->tail_len, ies) < 0) { - WL_ERR(("Beacon get IEs failed \n")); - err = -EINVAL; - goto fail; - } - - vndr = (u8 *)info->proberesp_ies; - vndr_ie_len = info->proberesp_ies_len; - - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - /* SoftAP mode */ - struct ieee80211_mgmt *mgmt; - mgmt = (struct ieee80211_mgmt *)info->probe_resp; - if (mgmt != NULL) { - vndr = (u8 *)&mgmt->u.probe_resp.variable; - vndr_ie_len = info->probe_resp_len - - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - } - } - - /* Parse Probe Response IEs */ - if (wl_cfg80211_parse_ies(vndr, vndr_ie_len, &prb_ies) < 0) { - WL_ERR(("PROBE RESP get IEs failed \n")); - err = -EINVAL; - } - -fail: - - return err; -} - -s32 -wl_cfg80211_set_ies( - struct net_device *dev, - struct cfg80211_beacon_data *info, - s32 bssidx) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - u8 *vndr = NULL; - u32 vndr_ie_len = 0; - s32 err = BCME_OK; - - /* Set Beacon IEs to FW */ - if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_BEACON_FLAG, (u8 *)info->tail, - info->tail_len)) < 0) { - WL_ERR(("Set Beacon IE Failed \n")); - } else { - WL_DBG(("Applied Vndr IEs for Beacon \n")); - } - - vndr = (u8 *)info->proberesp_ies; - vndr_ie_len = info->proberesp_ies_len; - - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - /* SoftAP mode */ - struct ieee80211_mgmt *mgmt; - mgmt = (struct ieee80211_mgmt *)info->probe_resp; - if (mgmt != NULL) { - vndr = (u8 *)&mgmt->u.probe_resp.variable; - vndr_ie_len = info->probe_resp_len - - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - } - } - - /* Set Probe Response IEs to FW */ - if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) { - WL_ERR(("Set Probe Resp IE Failed \n")); - } else { - WL_DBG(("Applied Vndr IEs for Probe Resp \n")); - } - - return err; -} -#endif - -static s32 wl_cfg80211_hostapd_sec( - struct net_device *dev, - struct parsed_ies *ies, - s32 bssidx) -{ - bool update_bss = 0; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - - if (ies->wps_ie) { - if (cfg->ap_info->wps_ie && - memcmp(cfg->ap_info->wps_ie, ies->wps_ie, ies->wps_ie_len)) { - WL_DBG((" WPS IE is changed\n")); - kfree(cfg->ap_info->wps_ie); - cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); - } else if (cfg->ap_info->wps_ie == NULL) { - WL_DBG((" WPS IE is added\n")); - cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); - } - - if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) { - if (!cfg->ap_info->security_mode) { - /* change from open mode to security mode */ - update_bss = true; - if (ies->wpa_ie != NULL) { - cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, - ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } else { - cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, - ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } - } else if (cfg->ap_info->wpa_ie) { - /* change from WPA2 mode to WPA mode */ - if (ies->wpa_ie != NULL) { - update_bss = true; - kfree(cfg->ap_info->rsn_ie); - cfg->ap_info->rsn_ie = NULL; - cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, - ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - } else if (memcmp(cfg->ap_info->rsn_ie, - ies->wpa2_ie, ies->wpa2_ie->len - + WPA_RSN_IE_TAG_FIXED_LEN)) { - update_bss = true; - kfree(cfg->ap_info->rsn_ie); - cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, - ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, - GFP_KERNEL); - cfg->ap_info->wpa_ie = NULL; - } - } - if (update_bss) { - cfg->ap_info->security_mode = true; - wl_cfgp2p_bss(cfg, dev, bssidx, 0); - if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || - wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) { - return BCME_ERROR; - } - wl_cfgp2p_bss(cfg, dev, bssidx, 1); - } - } - } else { - WL_ERR(("No WPSIE in beacon \n")); - } - return 0; -} - -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 2, 0)) -static s32 -wl_cfg80211_del_station( - struct wiphy *wiphy, struct net_device *ndev, - struct station_del_parameters *params) -{ - struct net_device *dev; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - scb_val_t scb_val; - s8 eabuf[ETHER_ADDR_STR_LEN]; - int err; - char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * - sizeof(struct ether_addr) + sizeof(uint)] = {0}; - struct maclist *assoc_maclist = (struct maclist *)mac_buf; - int num_associated = 0; - - const u8 *mac_addr = params->mac; - - WL_DBG(("Entry\n")); - if (mac_addr == NULL) { - WL_DBG(("mac_addr is NULL ignore it\n")); - return 0; - } - - dev = ndev_to_wlc_ndev(ndev, cfg); - - if (p2p_is_on(cfg)) { - /* Suspend P2P discovery search-listen to prevent it from changing the - * channel. - */ - if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) { - WL_ERR(("Can not disable discovery mode\n")); - return -EFAULT; - } - } - - assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; - err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST, - assoc_maclist, sizeof(mac_buf), false); - if (err < 0) - WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); - else - num_associated = assoc_maclist->count; - - memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN); - scb_val.val = DOT11_RC_DEAUTH_LEAVING; - err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, - sizeof(scb_val_t), true); - if (err < 0) - WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err)); - WL_ERR(("Disconnect STA : %s scb_val.val %d\n", - bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf), - scb_val.val)); - - if (num_associated > 0 && ETHER_ISBCAST(mac_addr)) - wl_delay(400); - - return 0; -} - -static s32 -wl_cfg80211_change_station( - struct wiphy *wiphy, - struct net_device *dev, - u8 *mac, - struct station_parameters *params) -{ - int err; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); - - /* Processing only authorize/de-authorize flag for now */ - if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) - return -ENOTSUPP; - - if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) { - err = wldev_ioctl(primary_ndev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN, true); - if (err) - WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err)); - return err; - } - - err = wldev_ioctl(primary_ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true); - if (err) - WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err)); -#ifdef DHD_LOSSLESS_ROAMING - wl_del_roam_timeout(cfg); -#endif /* DHD_LOSSLESS_ROAMING */ - return err; -} -#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) -static s32 -wl_cfg80211_start_ap( - struct wiphy *wiphy, - struct net_device *dev, - struct cfg80211_ap_settings *info) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 err = BCME_OK; - struct parsed_ies ies; - s32 bssidx = 0; - u32 dev_role = 0; - - WL_DBG(("Enter \n")); - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - WL_DBG(("Start AP req on primary iface: Softap\n")); - dev_role = NL80211_IFTYPE_AP; - } -#if defined(WL_ENABLE_P2P_IF) - else if (dev == cfg->p2p_net) { - /* Group Add request on p2p0 */ - WL_DBG(("Start AP req on P2P iface: GO\n")); - dev = bcmcfg_to_prmry_ndev(cfg); - dev_role = NL80211_IFTYPE_P2P_GO; - } -#endif /* WL_ENABLE_P2P_IF */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (p2p_is_on(cfg) && - (bssidx == wl_to_p2p_bss_bssidx(cfg, - P2PAPI_BSSCFG_CONNECTION))) { - dev_role = NL80211_IFTYPE_P2P_GO; - WL_DBG(("Start AP req on P2P connection iface\n")); - } - - if (!check_dev_role_integrity(cfg, dev_role)) - goto fail; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - if ((err = wl_cfg80211_set_channel(wiphy, dev, - dev->ieee80211_ptr->preset_chandef.chan, -#ifdef WL_SUPPORT_CHAN_BW - dev->ieee80211_ptr->preset_chandef.width) < 0)) { -#else - NL80211_CHAN_HT20) < 0)) { -#endif /* WL_SUPPORT_CHAN_BW */ - WL_ERR(("Set channel failed \n")); - goto fail; - } -#endif - - if ((err = wl_cfg80211_bcn_set_params(info, dev, - dev_role, bssidx)) < 0) { - WL_ERR(("Beacon params set failed \n")); - goto fail; - } - - /* Parse IEs */ - if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) { - WL_ERR(("Set IEs failed \n")); - goto fail; - } - - if ((wl_cfg80211_bcn_validate_sec(dev, &ies, - dev_role, bssidx)) < 0) - { - WL_ERR(("Beacon set security failed \n")); - goto fail; - } - - if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, - dev_role, bssidx)) < 0) { - WL_ERR(("Beacon bring up AP/GO failed \n")); - goto fail; - } - - WL_DBG(("** AP/GO Created **\n")); - -#ifdef WL_CFG80211_ACL - /* Enfoce Admission Control. */ - if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) { - WL_ERR(("Set ACL failed\n")); - } -#endif /* WL_CFG80211_ACL */ - - /* Set IEs to FW */ - if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0) - WL_ERR(("Set IEs failed \n")); - - /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ - if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) { - bool pbc = 0; - wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); - if (pbc) { - WL_DBG(("set WLC_E_PROBREQ_MSG\n")); - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); - } - } - -fail: - if (err) { - WL_ERR(("ADD/SET beacon failed\n")); - wldev_iovar_setint(dev, "mpc", 1); - } - - return err; -} - -static s32 -wl_cfg80211_stop_ap( - struct wiphy *wiphy, - struct net_device *dev) -{ - int err = 0; - u32 dev_role = 0; - int infra = 0; - int ap = 0; - s32 bssidx = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - WL_DBG(("Enter \n")); - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - dev_role = NL80211_IFTYPE_AP; - } -#if defined(WL_ENABLE_P2P_IF) - else if (dev == cfg->p2p_net) { - /* Group Add request on p2p0 */ - dev = bcmcfg_to_prmry_ndev(cfg); - dev_role = NL80211_IFTYPE_P2P_GO; - } -#endif /* WL_ENABLE_P2P_IF */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (p2p_is_on(cfg) && - (bssidx == wl_to_p2p_bss_bssidx(cfg, - P2PAPI_BSSCFG_CONNECTION))) { - dev_role = NL80211_IFTYPE_P2P_GO; - } - - if (!check_dev_role_integrity(cfg, dev_role)) - goto exit; - - if (dev_role == NL80211_IFTYPE_AP) { - /* SoftAp on primary Interface. - * Shut down AP and turn on MPC - */ - if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { - WL_ERR(("setting AP mode failed %d \n", err)); - err = -ENOTSUPP; - goto exit; - } - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET INFRA error %d\n", err)); - err = -ENOTSUPP; - goto exit; - } - - err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); - if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); - err = -EINVAL; - goto exit; - } - - wl_clr_drv_status(cfg, AP_CREATED, dev); - /* Turn on the MPC */ - wldev_iovar_setint(dev, "mpc", 1); - if (cfg->ap_info) { - kfree(cfg->ap_info->wpa_ie); - kfree(cfg->ap_info->rsn_ie); - kfree(cfg->ap_info->wps_ie); - kfree(cfg->ap_info); - cfg->ap_info = NULL; - } - } else { - WL_DBG(("Stopping P2P GO \n")); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub), - DHD_EVENT_TIMEOUT_MS*3); - DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub)); - } - -exit: - return err; -} - -static s32 -wl_cfg80211_change_beacon( - struct wiphy *wiphy, - struct net_device *dev, - struct cfg80211_beacon_data *info) -{ - s32 err = BCME_OK; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct parsed_ies ies; - u32 dev_role = 0; - s32 bssidx = 0; - bool pbc = 0; - - WL_DBG(("Enter \n")); - - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - dev_role = NL80211_IFTYPE_AP; - } -#if defined(WL_ENABLE_P2P_IF) - else if (dev == cfg->p2p_net) { - /* Group Add request on p2p0 */ - dev = bcmcfg_to_prmry_ndev(cfg); - dev_role = NL80211_IFTYPE_P2P_GO; - } -#endif /* WL_ENABLE_P2P_IF */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (p2p_is_on(cfg) && - (bssidx == wl_to_p2p_bss_bssidx(cfg, - P2PAPI_BSSCFG_CONNECTION))) { - dev_role = NL80211_IFTYPE_P2P_GO; - } - - if (!check_dev_role_integrity(cfg, dev_role)) - goto fail; - - /* Parse IEs */ - if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) { - WL_ERR(("Parse IEs failed \n")); - goto fail; - } - - /* Set IEs to FW */ - if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) { - WL_ERR(("Set IEs failed \n")); - goto fail; - } - - if (dev_role == NL80211_IFTYPE_AP) { - if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { - WL_ERR(("Hostapd update sec failed \n")); - err = -EINVAL; - goto fail; - } - /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ - if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) { - wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); - WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc)); - if (pbc) - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); - else - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); - } - } - -fail: - return err; -} -#else -static s32 -wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info) -{ - s32 err = BCME_OK; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - s32 ie_offset = 0; - s32 bssidx = 0; - u32 dev_role = NL80211_IFTYPE_AP; - struct parsed_ies ies; - bcm_tlv_t *ssid_ie; - bool pbc = 0; - WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", - info->interval, info->dtim_period, info->head_len, info->tail_len)); - - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - dev_role = NL80211_IFTYPE_AP; - } -#if defined(WL_ENABLE_P2P_IF) - else if (dev == cfg->p2p_net) { - /* Group Add request on p2p0 */ - dev = bcmcfg_to_prmry_ndev(cfg); - dev_role = NL80211_IFTYPE_P2P_GO; - } -#endif /* WL_ENABLE_P2P_IF */ - if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - if (p2p_is_on(cfg) && - (bssidx == wl_to_p2p_bss_bssidx(cfg, - P2PAPI_BSSCFG_CONNECTION))) { - dev_role = NL80211_IFTYPE_P2P_GO; - } - - if (!check_dev_role_integrity(cfg, dev_role)) - goto fail; - - ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; - /* find the SSID */ - if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], - info->head_len - ie_offset, - DOT11_MNG_SSID_ID)) != NULL) { - if (dev_role == NL80211_IFTYPE_AP) { - /* Store the hostapd SSID */ - memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); - cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN); - memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data, - cfg->hostapd_ssid.SSID_len); - } else { - /* P2P GO */ - memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); - cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN); - memcpy(cfg->p2p->ssid.SSID, ssid_ie->data, - cfg->p2p->ssid.SSID_len); - } - } - - if (wl_cfg80211_parse_ies((u8 *)info->tail, - info->tail_len, &ies) < 0) { - WL_ERR(("Beacon get IEs failed \n")); - err = -EINVAL; - goto fail; - } - - if (wl_cfgp2p_set_management_ie(cfg, dev, bssidx, - VNDR_IE_BEACON_FLAG, (u8 *)info->tail, - info->tail_len) < 0) { - WL_ERR(("Beacon set IEs failed \n")); - goto fail; - } else { - WL_DBG(("Applied Vndr IEs for Beacon \n")); - } - if (!wl_cfgp2p_bss_isup(dev, bssidx) && - (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx) < 0)) - { - WL_ERR(("Beacon set security failed \n")); - goto fail; - } - - /* Set BI and DTIM period */ - if (info->interval) { - if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, - &info->interval, sizeof(s32), true)) < 0) { - WL_ERR(("Beacon Interval Set Error, %d\n", err)); - return err; - } - } - if (info->dtim_period) { - if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, - &info->dtim_period, sizeof(s32), true)) < 0) { - WL_ERR(("DTIM Interval Set Error, %d\n", err)); - return err; - } - } - - if (wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx) < 0) { - WL_ERR(("Beacon bring up AP/GO failed \n")); - goto fail; - } - - if (wl_get_drv_status(cfg, AP_CREATED, dev)) { - /* Soft AP already running. Update changed params */ - if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { - WL_ERR(("Hostapd update sec failed \n")); - err = -EINVAL; - goto fail; - } - } - - /* Enable Probe Req filter */ - if (((dev_role == NL80211_IFTYPE_P2P_GO) || - (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) { - wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); - if (pbc) - wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); - } - - WL_DBG(("** ADD/SET beacon done **\n")); - -fail: - if (err) { - WL_ERR(("ADD/SET beacon failed\n")); - wldev_iovar_setint(dev, "mpc", 1); - } - return err; - -} -#endif - -#ifdef WL_SCHED_SCAN -#define PNO_TIME 120 -#define PNO_REPEAT 2 -#define PNO_FREQ_EXPO_MAX 1 -static bool -is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count) -{ - int i; - - if (!ssid || !ssid_list) - return FALSE; - - for (i = 0; i < count; i++) { - if (ssid->ssid_len == ssid_list[i].ssid_len) { - if (strncmp(ssid->ssid, ssid_list[i].ssid, ssid->ssid_len) == 0) - return TRUE; - } - } - return FALSE; -} - -static int -wl_cfg80211_sched_scan_start(struct wiphy *wiphy, - struct net_device *dev, - struct cfg80211_sched_scan_request *request) -{ - ushort pno_time = PNO_TIME; - int pno_repeat = PNO_REPEAT; - int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; - wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct cfg80211_ssid *ssid = NULL; - struct cfg80211_ssid *hidden_ssid_list = NULL; - int ssid_cnt = 0; - int i; - int ret = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - s32 rssi_thold = 0; -#endif /* KERNEL_VER >= 3.6 */ - - if (!request) { - WL_ERR(("Sched scan request was NULL\n")); - return -EINVAL; - } - - WL_DBG(("Enter \n")); - WL_ERR((">>> SCHED SCAN START\n")); - WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n", - request->n_match_sets, request->n_ssids)); - WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n", - request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max)); - - - if (!request->n_ssids || !request->n_match_sets) { - WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids)); - return -EINVAL; - } - - memset(&ssids_local, 0, sizeof(ssids_local)); - - if (request->n_ssids > 0) - hidden_ssid_list = request->ssids; - - for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) { - ssid = &request->match_sets[i].ssid; - /* No need to include null ssid */ - if (ssid->ssid_len) { - ssids_local[ssid_cnt].SSID_len = MIN(ssid->ssid_len, - (uint32)DOT11_MAX_SSID_LEN); - memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid, - ssids_local[ssid_cnt].SSID_len); - if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) { - ssids_local[ssid_cnt].hidden = TRUE; - WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid)); - } else { - ssids_local[ssid_cnt].hidden = FALSE; - WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid->ssid)); - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) - rssi_thold = request->match_sets[i].rssi_thold; -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - rssi_thold = request->rssi_thold; -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - if (rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) { - ssids_local[ssid_cnt].rssi_thresh = (int8)rssi_thold; - } -#endif /* KERNEL_VER >= 3.6 */ - ssid_cnt++; - } - } - - if (ssid_cnt) { - if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, ssid_cnt, pno_time, - pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) { - WL_ERR(("PNO setup failed!! ret=%d \n", ret)); - return -EINVAL; - } - cfg->sched_scan_req = request; - } else { - return -EINVAL; - } - - return 0; -} - -static int -wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - WL_DBG(("Enter \n")); - WL_PNO((">>> SCHED SCAN STOP\n")); - - if (dhd_dev_pno_stop_for_ssid(dev) < 0) - WL_ERR(("PNO Stop for SSID failed")); - - if (cfg->scan_request && cfg->sched_scan_running) { - WL_PNO((">>> Sched scan running. Aborting it..\n")); - wl_notify_escan_complete(cfg, dev, true, true); - } - - cfg->sched_scan_req = NULL; - cfg->sched_scan_running = FALSE; - - return 0; -} -#endif /* WL_SCHED_SCAN */ - -static struct cfg80211_ops wl_cfg80211_ops = { - .add_virtual_intf = wl_cfg80211_add_virtual_iface, - .del_virtual_intf = wl_cfg80211_del_virtual_iface, - .change_virtual_intf = wl_cfg80211_change_virtual_iface, -#if defined(WL_CFG80211_P2P_DEV_IF) - .start_p2p_device = wl_cfgp2p_start_p2p_device, - .stop_p2p_device = wl_cfgp2p_stop_p2p_device, -#endif /* WL_CFG80211_P2P_DEV_IF */ - .scan = wl_cfg80211_scan, - .set_wiphy_params = wl_cfg80211_set_wiphy_params, - .join_ibss = wl_cfg80211_join_ibss, - .leave_ibss = wl_cfg80211_leave_ibss, - .get_station = wl_cfg80211_get_station, - .set_tx_power = wl_cfg80211_set_tx_power, - .get_tx_power = wl_cfg80211_get_tx_power, - .add_key = wl_cfg80211_add_key, - .del_key = wl_cfg80211_del_key, - .get_key = wl_cfg80211_get_key, - .set_default_key = wl_cfg80211_config_default_key, - .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key, - .set_power_mgmt = wl_cfg80211_set_power_mgmt, - .connect = wl_cfg80211_connect, - .disconnect = wl_cfg80211_disconnect, - .suspend = wl_cfg80211_suspend, - .resume = wl_cfg80211_resume, - .set_pmksa = wl_cfg80211_set_pmksa, - .del_pmksa = wl_cfg80211_del_pmksa, - .flush_pmksa = wl_cfg80211_flush_pmksa, - .remain_on_channel = wl_cfg80211_remain_on_channel, - .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel, - .mgmt_tx = wl_cfg80211_mgmt_tx, - .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, - .change_bss = wl_cfg80211_change_bss, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) - .set_channel = wl_cfg80211_set_channel, -#endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) - .set_beacon = wl_cfg80211_add_set_beacon, - .add_beacon = wl_cfg80211_add_set_beacon, -#else - .change_beacon = wl_cfg80211_change_beacon, - .start_ap = wl_cfg80211_start_ap, - .stop_ap = wl_cfg80211_stop_ap, -#endif -#ifdef WL_SCHED_SCAN - .sched_scan_start = wl_cfg80211_sched_scan_start, - .sched_scan_stop = wl_cfg80211_sched_scan_stop, -#endif /* WL_SCHED_SCAN */ -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 2, 0)) - .del_station = wl_cfg80211_del_station, - .change_station = wl_cfg80211_change_station, - .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, -#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) - .tdls_mgmt = wl_cfg80211_tdls_mgmt, - .tdls_oper = wl_cfg80211_tdls_oper, -#endif -#ifdef WL_CFG80211_ACL - .set_mac_acl = wl_cfg80211_set_mac_acl, -#endif /* WL_CFG80211_ACL */ -#if defined(WL_ABORT_SCAN) - .abort_scan = wl_cfg80211_abort_scan, -#endif /* WL_ABORT_SCAN */ - CFG80211_TESTMODE_CMD(dhd_cfg80211_testmode_cmd) -}; - -s32 wl_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; - case WL_MODE_AP: - return NL80211_IFTYPE_AP; - default: - return NL80211_IFTYPE_UNSPECIFIED; - } - - return err; -} - -#ifdef CONFIG_CFG80211_INTERNAL_REGDB -static int -wl_cfg80211_reg_notifier( - struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy); - int ret = 0; - - if (!request || !cfg) { - WL_ERR(("Invalid arg\n")); - return -EINVAL; - } - - WL_DBG(("ccode: %c%c Initiator: %d\n", - request->alpha2[0], request->alpha2[1], request->initiator)); - - /* We support only REGDOM_SET_BY_USER as of now */ - if ((request->initiator != NL80211_REGDOM_SET_BY_USER) && - (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) { - WL_ERR(("reg_notifier for intiator:%d not supported : set default\n", - request->initiator)); - /* in case of no supported country by regdb - lets driver setup platform default Locale - */ - } - - WL_ERR(("Set country code %c%c from %s\n", - request->alpha2[0], request->alpha2[1], - ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User"))); - - if ((ret = wldev_set_country(bcmcfg_to_prmry_ndev(cfg), request->alpha2, - false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false))) < 0) { - WL_ERR(("set country Failed :%d\n", ret)); - } - - return ret; -} -#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ - -#ifdef CONFIG_PM -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) -static const struct wiphy_wowlan_support brcm_wowlan_support = { - .flags = WIPHY_WOWLAN_ANY, -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) -static struct cfg80211_wowlan brcm_wowlan_config = { - .disconnect = true, - .gtk_rekey_failure = true, - .eap_identity_req = true, - .four_way_handshake = true, -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ -#endif /* CONFIG_PM */ - -static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context) -{ - s32 err = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) - dhd_pub_t *dhd = (dhd_pub_t *)context; - BCM_REFERENCE(dhd); - - if (!dhd) { - WL_ERR(("DHD is NULL!!")); - err = -ENODEV; - return err; - } -#endif - - wdev->wiphy = - wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211)); - if (unlikely(!wdev->wiphy)) { - WL_ERR(("Couldn not allocate wiphy device\n")); - err = -ENOMEM; - return err; - } - set_wiphy_dev(wdev->wiphy, sdiofunc_dev); - wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; - /* Report how many SSIDs Driver can support per Scan request */ - wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; - wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; -#ifdef WL_SCHED_SCAN - wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; - wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; - wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; -#endif /* WL_SCHED_SCAN */ - wdev->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) - | BIT(NL80211_IFTYPE_ADHOC) -#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) - | BIT(NL80211_IFTYPE_MONITOR) -#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF) - | BIT(NL80211_IFTYPE_P2P_CLIENT) - | BIT(NL80211_IFTYPE_P2P_GO) -#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_CFG80211_P2P_DEV_IF) - | BIT(NL80211_IFTYPE_P2P_DEVICE) -#endif /* WL_CFG80211_P2P_DEV_IF */ - | BIT(NL80211_IFTYPE_AP); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) - WL_DBG(("Setting interface combinations for common mode\n")); - wdev->wiphy->iface_combinations = common_iface_combinations; - wdev->wiphy->n_iface_combinations = - ARRAY_SIZE(common_iface_combinations); -#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ - - wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - - 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->max_remain_on_channel_duration = 5000; - wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes; -#ifndef WL_POWERSAVE_DISABLED - wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; -#else - wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; -#endif /* !WL_POWERSAVE_DISABLED */ - wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | - WIPHY_FLAG_4ADDR_AP | -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) - WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | -#endif - WIPHY_FLAG_4ADDR_STATION; -#if (defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && (LINUX_VERSION_CODE >= \ - KERNEL_VERSION(3, 2, 0)) - /* Please use supplicant ver >= 76 if FW_ROAM is enabled - * If driver advertises FW_ROAM, older supplicant wouldn't - * send the BSSID & Freq in the connect req command. This - * will delay the ASSOC as the FW need to do a full scan - * before attempting to connect. Supplicant >=76 has patch - * to allow bssid & freq to be sent down to driver even if - * FW ROAM is advertised. - */ - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) - wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_OFFCHAN_TX; -#endif -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 4, 0)) - /* From 3.4 kernel ownards AP_SME flag can be advertised - * to remove the patch from supplicant - */ - wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; - -#ifdef WL_CFG80211_ACL - /* Configure ACL capabilities. */ - wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT; -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) - /* Supplicant distinguish between the SoftAP mode and other - * modes (e.g. P2P, WPS, HS2.0) when it builds the probe - * response frame from Supplicant MR1 and Kernel 3.4.0 or - * later version. To add Vendor specific IE into the - * probe response frame in case of SoftAP mode, - * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable. - */ - if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) { - wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - wdev->wiphy->probe_resp_offload = 0; - } -#endif -#endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */ - -#ifdef CONFIG_CFG80211_INTERNAL_REGDB - wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier; -#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; -#endif - -#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF) - /* - * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the - * disconnection of connected network before suspend. So a dummy wowlan - * filter is configured for kernels linux-3.8 and above. - */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) - wdev->wiphy->wowlan = &brcm_wowlan_support; - - /* If this is not provided cfg stack will get disconnect - * during suspend. - */ - wdev->wiphy->wowlan_config = &brcm_wowlan_config; -#else - wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ -#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */ - - WL_DBG(("Registering custom regulatory)\n")); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; -#else - wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; -#endif - wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) - WL_ERR(("Registering Vendor80211)\n")); - err = wl_cfgvendor_attach(wdev->wiphy); - if (unlikely(err < 0)) { - WL_ERR(("Couldn not attach vendor commands (%d)\n", err)); - } -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ - - - /* Now we can register wiphy with cfg80211 module */ - err = wiphy_register(wdev->wiphy); - if (unlikely(err < 0)) { - WL_ERR(("Couldn not register wiphy device (%d)\n", err)); - wiphy_free(wdev->wiphy); - } - -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \ - KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS) - wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS; -#endif - - return err; -} - -static void wl_free_wdev(struct bcm_cfg80211 *cfg) -{ - struct wireless_dev *wdev = cfg->wdev; - struct wiphy *wiphy; - if (!wdev) { - WL_ERR(("wdev is invalid\n")); - return; - } - wiphy = wdev->wiphy; - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) - wl_cfgvendor_detach(wdev->wiphy); -#endif /* if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ - - wiphy_unregister(wdev->wiphy); - wdev->wiphy->dev.parent = NULL; - - wl_delete_all_netinfo(cfg); - wiphy_free(wiphy); - /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg", - * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! - */ -} - -static s32 wl_inform_bss(struct bcm_cfg80211 *cfg) -{ - struct wl_scan_results *bss_list; - struct wl_bss_info *bi = NULL; /* must be initialized */ - s32 err = 0; - s32 i; - - bss_list = cfg->bss_list; - WL_DBG(("scanned AP count (%d)\n", bss_list->count)); - bi = next_bss(bss_list, bi); - for_each_bss(bss_list, bi, i) { - err = wl_inform_single_bss(cfg, bi, false); - if (unlikely(err)) - break; - } - return err; -} - -static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam) -{ - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - struct ieee80211_mgmt *mgmt; - struct ieee80211_channel *channel; - struct ieee80211_supported_band *band; - struct wl_cfg80211_bss_info *notif_bss_info; - struct wl_scan_req *sr = wl_to_sr(cfg); - struct beacon_proberesp *beacon_proberesp; - struct cfg80211_bss *cbss = NULL; - s32 mgmt_type; - s32 signal; - u32 freq; - s32 err = 0; - gfp_t aflags; - - if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { - WL_DBG(("Beacon is larger than buffer. Discarding\n")); - return err; - } - aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; - notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - - sizeof(u8) + WL_BSS_INFO_MAX, aflags); - if (unlikely(!notif_bss_info)) { - WL_ERR(("notif_bss_info alloc failed\n")); - return -ENOMEM; - } - mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; - notif_bss_info->channel = - bi->ctl_ch ? bi->ctl_ch : wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); - - if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - if (!band) { - WL_ERR(("No valid band")); - kfree(notif_bss_info); - return -EINVAL; - } - notif_bss_info->rssi = wl_rssi_offset(dtoh16(bi->RSSI)); - memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); - mgmt_type = cfg->active_scan ? - IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; - if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type); - } - beacon_proberesp = cfg->active_scan ? - (struct beacon_proberesp *)&mgmt->u.probe_resp : - (struct beacon_proberesp *)&mgmt->u.beacon; - beacon_proberesp->timestamp = 0; - beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); - beacon_proberesp->capab_info = cpu_to_le16(bi->capability); - wl_rst_ie(cfg); - wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, roam); - wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length); - wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX - - offsetof(struct wl_cfg80211_bss_info, frame_buf)); - notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, - u.beacon.variable) + wl_get_ielen(cfg); -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) - freq = ieee80211_channel_to_frequency(notif_bss_info->channel); - (void)band->band; -#else - freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); -#endif - if (freq == 0) { - WL_ERR(("Invalid channel, fail to chcnage channel to freq\n")); - kfree(notif_bss_info); - return -EINVAL; - } - channel = ieee80211_get_channel(wiphy, freq); - if (unlikely(!channel)) { - WL_ERR(("ieee80211_get_channel error\n")); - kfree(notif_bss_info); - return -EINVAL; - } - WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM" - "mgmt_type %d frame_len %d\n", bi->SSID, - notif_bss_info->rssi, notif_bss_info->channel, - mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type, - notif_bss_info->frame_len)); - - signal = notif_bss_info->rssi * 100; - if (!mgmt->u.probe_resp.timestamp) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) - struct timespec ts; - get_monotonic_boottime(&ts); - mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) - + ts.tv_nsec / 1000; -#else - struct timeval tv; - do_gettimeofday(&tv); - mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000) - + tv.tv_usec; -#endif - } - - - cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, - le16_to_cpu(notif_bss_info->frame_len), signal, aflags); - if (unlikely(!cbss)) { - WL_ERR(("cfg80211_inform_bss_frame error\n")); - kfree(notif_bss_info); - return -EINVAL; - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) - cfg80211_put_bss(wiphy, cbss); -#else - cfg80211_put_bss(cbss); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ - kfree(notif_bss_info); - return err; -} - -static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev) -{ - u32 event = ntoh32(e->event_type); - u32 status = ntoh32(e->status); - u16 flags = ntoh16(e->flags); - - WL_DBG(("event %d, status %d flags %x\n", event, status, flags)); - if (event == WLC_E_SET_SSID) { - if (status == WLC_E_STATUS_SUCCESS) { - if (!wl_is_ibssmode(cfg, ndev)) - return true; - } - } else if (event == WLC_E_LINK) { - if (flags & WLC_EVENT_MSG_LINK) - return true; - } - - WL_DBG(("wl_is_linkup false\n")); - return false; -} - -static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e) -{ - u32 event = ntoh32(e->event_type); - u16 flags = ntoh16(e->flags); - - if (event == WLC_E_DEAUTH_IND || - event == WLC_E_DISASSOC_IND || - event == WLC_E_DISASSOC || - event == WLC_E_DEAUTH) { -#if (WL_DBG_LEVEL > 0) - WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); -#endif /* (WL_DBG_LEVEL > 0) */ - return true; - } else if (event == WLC_E_LINK) { - if (!(flags & WLC_EVENT_MSG_LINK)) { -#if (WL_DBG_LEVEL > 0) - WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); -#endif /* (WL_DBG_LEVEL > 0) */ - return true; - } - } - - return false; -} - -static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e) -{ - u32 event = ntoh32(e->event_type); - u32 status = ntoh32(e->status); - - if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) - return true; - if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) - return true; - - return false; -} - -/* The mainline kernel >= 3.2.0 has support for indicating new/del station - * to AP/P2P GO via events. If this change is backported to kernel for which - * this driver is being built, then define WL_CFG80211_STA_EVENT. You - * should use this new/del sta event mechanism for BRCM supplicant >= 22. - */ -static s32 -wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - s32 err = 0; - u32 event = ntoh32(e->event_type); - u32 reason = ntoh32(e->reason); - u32 len = ntoh32(e->datalen); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) - bool isfree = false; - u8 *mgmt_frame; - u8 bsscfgidx = e->bsscfgidx; - s32 freq; - s32 channel; - u8 *body = NULL; - u16 fc = 0; - - struct ieee80211_supported_band *band; - struct ether_addr da; - struct ether_addr bssid; - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - channel_info_t ci; -#else - struct station_info sinfo; -#endif - - WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason)); - /* if link down, bsscfg is disabled. */ - if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS && - wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) { - wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false); - WL_INFO(("AP mode link down !! \n")); - complete(&cfg->iface_disable); - return 0; - } - - if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) { - WL_ERR(("event %s(%d) status %d reason %d\n", - bcmevent_names[event].name, event, ntoh32(e->status), reason)); - } - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) - WL_DBG(("Enter \n")); - if (!len && (event == WLC_E_DEAUTH)) { - len = 2; /* reason code field */ - data = &reason; - } - if (len) { - body = kzalloc(len, GFP_KERNEL); - - if (body == NULL) { - WL_ERR(("wl_notify_connect_status: Failed to allocate body\n")); - return WL_INVALID; - } - } - memset(&bssid, 0, ETHER_ADDR_LEN); - WL_DBG(("Enter event %d ndev %p\n", event, ndev)); - if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) { - kfree(body); - return WL_INVALID; - } - if (len) - memcpy(body, data, len); - - wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", - NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); - memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); - memset(&bssid, 0, sizeof(bssid)); - err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - switch (event) { - case WLC_E_ASSOC_IND: - fc = FC_ASSOC_REQ; - break; - case WLC_E_REASSOC_IND: - fc = FC_REASSOC_REQ; - break; - case WLC_E_DISASSOC_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH: - fc = FC_DISASSOC; - break; - default: - fc = 0; - goto exit; - } - - memset(&ci, 0, sizeof(ci)); - if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { - kfree(body); - return err; - } - - channel = dtoh32(ci.hw_channel); - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - if (!band) { - WL_ERR(("No valid band")); - if (body) - kfree(body); - return -EINVAL; - } -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) - freq = ieee80211_channel_to_frequency(channel); - (void)band->band; -#else - freq = ieee80211_channel_to_frequency(channel, band->band); -#endif - - err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, - &mgmt_frame, &len, body); - if (err < 0) - goto exit; - isfree = true; - - if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); -#else - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -#endif - } else if (event == WLC_E_DISASSOC_IND) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); -#else - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -#endif - } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); -#else - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -#endif - } - -exit: - if (isfree) - kfree(mgmt_frame); - if (body) - kfree(body); -#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ - sinfo.filled = 0; - if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && - reason == DOT11_SC_SUCCESS) { - sinfo.filled = STATION_INFO_ASSOC_REQ_IES; - if (!data) { - WL_ERR(("No IEs present in ASSOC/REASSOC_IND")); - return -EINVAL; - } - sinfo.assoc_req_ies = data; - sinfo.assoc_req_ies_len = len; - cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); - } else if (event == WLC_E_DISASSOC_IND) { - cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); - } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { - cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); - } -#endif - return err; -} - -static s32 -wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e) -{ - u32 reason = ntoh32(e->reason); - u32 event = ntoh32(e->event_type); - struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); - WL_DBG(("event type : %d, reason : %d\n", event, reason)); - if (sec) { - switch (event) { - case WLC_E_ASSOC: - case WLC_E_AUTH: - sec->auth_assoc_res_status = reason; - default: - break; - } - } else - WL_ERR(("sec is NULL\n")); - return 0; -} - -static s32 -wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - s32 err = 0; - u32 event = ntoh32(e->event_type); - u16 flags = ntoh16(e->flags); - u32 status = ntoh32(e->status); - bool active; - - if (event == WLC_E_JOIN) { - WL_DBG(("joined in IBSS network\n")); - } - if (event == WLC_E_START) { - WL_DBG(("started IBSS network\n")); - } - if (event == WLC_E_JOIN || event == WLC_E_START || - (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) { - if (wl_get_drv_status(cfg, CONNECTED, ndev)) { - /* ROAM or Redundant */ - u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) { - WL_DBG(("IBSS connected event from same BSSID(" - MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid))); - return err; - } - WL_INFO(("IBSS BSSID is changed from " MACDBG " to " MACDBG "\n", - MAC2STRDBG(cur_bssid), MAC2STRDBG((u8 *)&e->addr))); - wl_get_assoc_ies(cfg, ndev); - wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, false); - cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); - } - else { - /* New connection */ - WL_INFO(("IBSS connected to " MACDBG "\n", MAC2STRDBG((u8 *)&e->addr))); - wl_link_up(cfg); - wl_get_assoc_ies(cfg, ndev); - wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, false); - cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); - wl_set_drv_status(cfg, CONNECTED, ndev); - active = true; - wl_update_prof(cfg, ndev, NULL, (void *)&active, WL_PROF_ACT); - } - } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) || - event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) { - wl_clr_drv_status(cfg, CONNECTED, ndev); - wl_link_down(cfg); - wl_init_prof(cfg, ndev); - } - else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) { - WL_DBG(("no action - join fail (IBSS mode)\n")); - } - else { - WL_DBG(("no action (IBSS mode)\n")); -} - return err; -} - -static s32 -wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - bool act; - struct net_device *ndev = NULL; - s32 err = 0; - u32 event = ntoh32(e->event_type); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { - err = wl_notify_connect_status_ap(cfg, ndev, e, data); - } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS) { - err = wl_notify_connect_status_ibss(cfg, ndev, e, data); - } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) { - WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", - ntoh32(e->event_type), ntoh32(e->status), ndev)); - if (event == WLC_E_ASSOC || event == WLC_E_AUTH) { - wl_get_auth_assoc_status(cfg, ndev, e); - return 0; - } - if (wl_is_linkup(cfg, e, ndev)) { - wl_link_up(cfg); - act = true; - if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) { -#ifdef DHD_LOSSLESS_ROAMING - bool is_connected = wl_get_drv_status(cfg, CONNECTED, ndev); -#endif /* DHD_LOSSLESS_ROAMING */ - printk("wl_bss_connect_done succeeded with " MACDBG "\n", - MAC2STRDBG((u8*)(&e->addr))); - wl_bss_connect_done(cfg, ndev, e, data, true); - WL_DBG(("joined in BSS network \"%s\"\n", - ((struct wlc_ssid *) - wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID)); -#ifdef DHD_LOSSLESS_ROAMING - if (event == WLC_E_LINK && is_connected && - !cfg->roam_offload) { - wl_bss_roaming_done(cfg, ndev, e, data); - } -#endif /* DHD_LOSSLESS_ROAMING */ - } - wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); - wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - - } else if (wl_is_linkdown(cfg, e)) { -#ifdef DHD_LOSSLESS_ROAMING - wl_del_roam_timeout(cfg); -#endif /* DHD_LOSSLESS_ROAMING */ - if (cfg->scan_request) - wl_notify_escan_complete(cfg, ndev, true, true); - if (wl_get_drv_status(cfg, CONNECTED, ndev)) { - scb_val_t scbval; - u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - s32 reason = 0; - if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) - reason = ntoh32(e->reason); - /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ - reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; - - printk("link down if %s may call cfg80211_disconnected. " - "event : %d, reason=%d from " MACDBG "\n", - ndev->name, event, ntoh32(e->reason), - MAC2STRDBG((u8*)(&e->addr))); - if (!cfg->roam_offload && - memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) { - WL_ERR(("BSSID of event is not the connected BSSID" - "(ignore it) cur: " MACDBG " event: " MACDBG"\n", - MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr)))); - return 0; - } - wl_clr_drv_status(cfg, CONNECTED, ndev); - if (! wl_get_drv_status(cfg, DISCONNECTING, ndev)) { - /* To make sure disconnect, explictly send dissassoc - * for BSSID 00:00:00:00:00:00 issue - */ - scbval.val = WLAN_REASON_DEAUTH_LEAVING; - - memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - scbval.val = htod32(scbval.val); - err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - if (err < 0) { - WL_ERR(("WLC_DISASSOC error %d\n", err)); - err = 0; - } - cfg80211_disconnected(ndev, reason, NULL, 0, GFP_KERNEL); - wl_link_down(cfg); - wl_init_prof(cfg, ndev); - } - } - else if (wl_get_drv_status(cfg, CONNECTING, ndev)) { - printk("link down, during connecting\n"); -#ifdef ESCAN_RESULT_PATCH - if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) || - (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) || - (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0)) - /* In case this event comes while associating another AP */ -#endif /* ESCAN_RESULT_PATCH */ - wl_bss_connect_done(cfg, ndev, e, data, false); - } - wl_clr_drv_status(cfg, DISCONNECTING, ndev); - - /* if link down, bsscfg is diabled */ - if (ndev != bcmcfg_to_prmry_ndev(cfg)) - complete(&cfg->iface_disable); - - } else if (wl_is_nonetwork(cfg, e)) { - printk("connect failed event=%d e->status %d e->reason %d \n", - event, (int)ntoh32(e->status), (int)ntoh32(e->reason)); - /* Clean up any pending scan request */ - if (cfg->scan_request) - wl_notify_escan_complete(cfg, ndev, true, true); - if (wl_get_drv_status(cfg, CONNECTING, ndev)) - wl_bss_connect_done(cfg, ndev, e, data, false); - } else { - WL_DBG(("%s nothing\n", __FUNCTION__)); - } - } - else { - WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev))); - } - return err; -} - -void wl_cfg80211_set_rmc_pid(int pid) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - if (pid > 0) - cfg->rmc_event_pid = pid; - WL_DBG(("set pid for rmc event : pid=%d\n", pid)); -} - -#ifdef WLAIBSS -void wl_cfg80211_set_txfail_pid(int pid) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - if (pid > 0) - cfg->aibss_txfail_pid = pid; - WL_DBG(("set pid for aibss fail event : pid=%d\n", pid)); -} - -static s32 -wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - u32 evt = ntoh32(e->event_type); - int ret = -1; - - if (cfg->aibss_txfail_pid != 0) { - ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL, - cfg->aibss_txfail_seq++, (void *)&e->addr, ETHER_ADDR_LEN); - } - - WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n", - evt, cfg->aibss_txfail_pid, ret, ETHERP_TO_MACF(&e->addr))); - return ret; -} -#endif /* WLAIBSS */ - -static s32 -wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - u32 evt = ntoh32(e->event_type); - u32 reason = ntoh32(e->reason); - int ret = -1; - - switch (reason) { - case WLC_E_REASON_RMC_AR_LOST: - case WLC_E_REASON_RMC_AR_NO_ACK: - if (cfg->rmc_event_pid != 0) { - ret = wl_netlink_send_msg(cfg->rmc_event_pid, - RMC_EVENT_LEADER_CHECK_FAIL, - cfg->rmc_event_seq++, NULL, 0); - } - break; - default: - break; - } - WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret)); - return ret; -} - -#ifdef RSSI_MONITOR_SUPPORT -static s32 -wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ -#if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT) - u32 datalen = be32_to_cpu(e->datalen); - struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - - if (datalen) { - wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data; - if (evt_data->version == RSSI_MONITOR_VERSION) { - dhd_rssi_monitor_evt_t monitor_data; - monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION; - monitor_data.cur_rssi = evt_data->cur_rssi; - memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN); - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_RSSI_MONITOR_EVENT, - &monitor_data, sizeof(monitor_data)); - } else { - WL_ERR(("Version mismatch %d, expected %d", evt_data->version, - RSSI_MONITOR_VERSION)); - } - } -#endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */ - return BCME_OK; -} -#endif /* RSSI_MONITOR_SUPPORT */ - -static s32 -wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - bool act; - struct net_device *ndev = NULL; - s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); -#ifdef DHD_LOSSLESS_ROAMING - struct wl_security *sec; -#endif - WL_DBG(("Enter \n")); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) { - wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false); - cfg->disable_roam_event = TRUE; - } - - if ((cfg->disable_roam_event) && (event == WLC_E_ROAM)) - return err; - - if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) { - if (wl_get_drv_status(cfg, CONNECTED, ndev)) { -#ifdef DHD_LOSSLESS_ROAMING - if (cfg->roam_offload) { - wl_bss_roaming_done(cfg, ndev, e, data); - wl_del_roam_timeout(cfg); - } - else { - sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); - /* In order to reduce roaming delay, wl_bss_roaming_done is - * early called with WLC_E_LINK event. It is called from - * here only if WLC_E_LINK event is blocked for specific - * security type. - */ - if (IS_AKM_SUITE_FT(sec)) { - wl_bss_roaming_done(cfg, ndev, e, data); - } - /* Roam timer is deleted mostly from wl_cfg80211_change_station - * after roaming is finished successfully. We need to delete - * the timer from here only for some security types that aren't - * using wl_cfg80211_change_station to authorize SCB - */ - if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) { - wl_del_roam_timeout(cfg); - } - } -#else /* DHD_LOSSLESS_ROAMING */ - wl_bss_roaming_done(cfg, ndev, e, data); -#endif /* DHD_LOSSLESS_ROAMING */ - } else { - wl_bss_connect_done(cfg, ndev, e, data, true); - } - act = true; - wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); - wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - } -#ifdef DHD_LOSSLESS_ROAMING - else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) { - wl_del_roam_timeout(cfg); - } -#endif /* DHD_LOSSLESS_ROAMING */ - - return err; -} - -#ifdef DHD_LOSSLESS_ROAMING -static s32 -wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - s32 err = 0; - struct wl_security *sec; - struct net_device *ndev; - dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); - /* Disable Lossless Roaming for specific AKM suite - * Any other AKM suite can be added below if transition time - * is delayed because of Lossless Roaming - * and it causes any certication failure - */ - if (IS_AKM_SUITE_FT(sec)) { - return err; - } - - dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC; - /* Restore flow control */ - dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF); - - mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS)); - - return err; -} -#endif /* DHD_LOSSLESS_ROAMING */ - -static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - wl_assoc_info_t assoc_info; - struct wl_connect_info *conn_info = wl_to_conn(cfg); - s32 err = 0; - - WL_DBG(("Enter \n")); - err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); - if (unlikely(err)) { - WL_ERR(("could not get assoc info (%d)\n", err)); - return err; - } - memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t)); - assoc_info.req_len = htod32(assoc_info.req_len); - assoc_info.resp_len = htod32(assoc_info.resp_len); - assoc_info.flags = htod32(assoc_info.flags); - - if (assoc_info.req_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + - ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0))) { - err = BCME_BADLEN; - goto exit; - } - if ((assoc_info.req_len > 0) && - (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + - ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0)))) { - err = BCME_BADLEN; - goto exit; - } - if (assoc_info.resp_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { - err = BCME_BADLEN; - goto exit; - } - if ((assoc_info.resp_len > 0) && (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { - err = BCME_BADLEN; - goto exit; - } - - if (conn_info->req_ie_len) { - conn_info->req_ie_len = 0; - bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); - } - if (conn_info->resp_ie_len) { - conn_info->resp_ie_len = 0; - bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); - } - if (assoc_info.req_len) { - err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, - assoc_info.req_len, NULL); - if (unlikely(err)) { - WL_ERR(("could not get assoc req (%d)\n", err)); - goto exit; - } - conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); - if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { - conn_info->req_ie_len -= ETHER_ADDR_LEN; - } - memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); - } - if (assoc_info.resp_len) { - err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, - assoc_info.resp_len, NULL); - if (unlikely(err)) { - WL_ERR(("could not get assoc resp (%d)\n", err)); - goto exit; - } - conn_info->resp_ie_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); - memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); - } - -exit: - if (err) { - WL_ERR(("err:%d, assoc_info-req:%u,resp:%u conn_info-req:%u,resp:%u\n", - err, assoc_info.req_len, assoc_info.resp_len, - conn_info->req_ie_len, conn_info->resp_ie_len)); - } - - return err; -} - -static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, - size_t *join_params_size) -{ - chanspec_t chanspec = 0; - if (ch != 0) { - join_params->params.chanspec_num = 1; - join_params->params.chanspec_list[0] = ch; - - if (join_params->params.chanspec_list[0] <= 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 += WL_ASSOC_PARAMS_FIXED_SIZE + - join_params->params.chanspec_num * sizeof(chanspec_t); - - join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; - join_params->params.chanspec_list[0] |= chanspec; - join_params->params.chanspec_list[0] = - wl_chspec_host_to_driver(join_params->params.chanspec_list[0]); - - join_params->params.chanspec_num = - htod32(join_params->params.chanspec_num); - WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n", - join_params->params.chanspec_list[0], - join_params->params.chanspec_num)); - } -} - -static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam) -{ - struct cfg80211_bss *bss; - struct wl_bss_info *bi; - struct wlc_ssid *ssid; - struct bcm_tlv *tim; - s32 beacon_interval; - s32 dtim_period; - size_t ie_len; - u8 *ie; - u8 *curbssid; - s32 err = 0; - struct wiphy *wiphy; - u32 channel; - char *buf; - - wiphy = bcmcfg_to_wiphy(cfg); - - ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID); - curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - bss = cfg80211_get_bss(wiphy, NULL, curbssid, - ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, - WLAN_CAPABILITY_ESS); - - mutex_lock(&cfg->usr_sync); - - buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_ATOMIC); - if (!buf) { - WL_ERR(("buffer alloc failed.\n")); - return BCME_NOMEM; - } - *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX); - err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, - buf, WL_EXTRA_BUF_MAX, false); - if (unlikely(err)) { - WL_ERR(("Could not get bss info %d\n", err)); - goto update_bss_info_out; - } - bi = (wl_bss_info_t *)(buf + 4); - channel = bi->ctl_ch ? bi->ctl_ch : - CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); - wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN); - - if (!bss) { - WL_DBG(("Could not find the AP\n")); - if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) { - WL_ERR(("Bssid doesn't match\n")); - err = -EIO; - goto update_bss_info_out; - } - err = wl_inform_single_bss(cfg, bi, roam); - if (unlikely(err)) - goto update_bss_info_out; - - ie = ((u8 *)bi) + bi->ie_offset; - ie_len = bi->ie_length; - beacon_interval = cpu_to_le16(bi->beacon_period); - } else { - WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); -#if defined(WL_CFG80211_P2P_DEV_IF) - ie = (u8 *)bss->ies->data; - ie_len = bss->ies->len; -#else - ie = bss->information_elements; - ie_len = bss->len_information_elements; -#endif /* WL_CFG80211_P2P_DEV_IF */ - beacon_interval = bss->beacon_interval; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) - cfg80211_put_bss(wiphy, bss); -#else - cfg80211_put_bss(bss); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ - } - - tim = bcm_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. - */ - dtim_period = 0; - err = wldev_ioctl(ndev, WLC_GET_DTIMPRD, - &dtim_period, sizeof(dtim_period), false); - if (unlikely(err)) { - WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); - goto update_bss_info_out; - } - } - - wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT); - wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); - -update_bss_info_out: - if (unlikely(err)) { - WL_ERR(("Failed with error %d\n", err)); - } - - kfree(buf); - mutex_unlock(&cfg->usr_sync); - return err; -} - -static s32 -wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - struct wl_connect_info *conn_info = wl_to_conn(cfg); - s32 err = 0; - u8 *curbssid; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - struct ieee80211_supported_band *band; - struct ieee80211_channel *notify_channel = NULL; - u32 *channel; - u32 freq; -#endif - -#ifdef WLFBT - uint32 data_len = 0; - if (data) - data_len = ntoh32(e->datalen); -#endif /* WLFBT */ - - wl_get_assoc_ies(cfg, ndev); - wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); - curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, true); - wl_update_pmklist(ndev, cfg->pmk_list, err); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) - /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */ - channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN); - 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); -#endif -#ifdef WLFBT - /* back up the given FBT key for the further supplicant request, - * currently not checking the FBT is enabled for current BSS in DHD, - * because the supplicant decides to take it or not. - */ - if (data && (data_len == FBT_KEYLEN)) { - memcpy(cfg->fbt_key, data, FBT_KEYLEN); - } -#endif /* WLFBT */ - printk("wl_bss_roaming_done succeeded to " MACDBG "\n", - MAC2STRDBG((u8*)(&e->addr))); - - cfg80211_roamed(ndev, -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) - notify_channel, -#endif - curbssid, - conn_info->req_ie, conn_info->req_ie_len, - conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); - WL_DBG(("Report roaming result\n")); - - wl_set_drv_status(cfg, CONNECTED, ndev); - - return err; -} - -static s32 -wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data, bool completed) -{ - struct wl_connect_info *conn_info = wl_to_conn(cfg); - struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); -#if (defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)) - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif - s32 err = 0; - u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - if (!sec) { - WL_ERR(("sec is NULL\n")); - return -ENODEV; - } - WL_DBG((" enter\n")); -#ifdef ESCAN_RESULT_PATCH - if (wl_get_drv_status(cfg, CONNECTED, ndev)) { - if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) { - WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n", - ntoh32(e->event_type), ntoh32(e->status))); - return err; - } - } - if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 && - memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) { - WL_DBG(("copy bssid\n")); - memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); - } - -#else - if (cfg->scan_request) { - wl_notify_escan_complete(cfg, ndev, true, true); - } -#endif /* ESCAN_RESULT_PATCH */ - if (wl_get_drv_status(cfg, CONNECTING, ndev)) { - wl_cfg80211_scan_abort(cfg); - wl_clr_drv_status(cfg, CONNECTING, ndev); - if (completed) { - wl_get_assoc_ies(cfg, ndev); - wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); - curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, false); - wl_update_pmklist(ndev, cfg->pmk_list, err); - wl_set_drv_status(cfg, CONNECTED, ndev); -#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) - if (dhd->roam_env_detection) - wldev_iovar_setint(ndev, "roam_env_detection", - AP_ENV_INDETERMINATE); -#endif /* ROAM_AP_ENV_DETECTION */ - if (ndev != bcmcfg_to_prmry_ndev(cfg)) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) - init_completion(&cfg->iface_disable); -#else - /* reinitialize completion to clear previous count */ - INIT_COMPLETION(cfg->iface_disable); -#endif - } - - } - cfg80211_connect_result(ndev, - curbssid, - conn_info->req_ie, - conn_info->req_ie_len, - conn_info->resp_ie, - conn_info->resp_ie_len, - completed ? WLAN_STATUS_SUCCESS : - (sec->auth_assoc_res_status) ? - sec->auth_assoc_res_status : - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); - if (completed) - WL_INFO(("Report connect result - connection succeeded\n")); - else - WL_ERR(("Report connect result - connection failed\n")); - } -#ifdef CONFIG_TCPACK_FASTTX - if (wl_get_chan_isvht80(ndev, dhd)) - wldev_iovar_setint(ndev, "tcpack_fast_tx", 0); - else - wldev_iovar_setint(ndev, "tcpack_fast_tx", 1); -#endif /* CONFIG_TCPACK_FASTTX */ - - return err; -} - -static s32 -wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct net_device *ndev = NULL; - u16 flags = ntoh16(e->flags); - enum nl80211_key_type key_type; - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - mutex_lock(&cfg->usr_sync); - if (flags & WLC_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); - mutex_unlock(&cfg->usr_sync); - - return 0; -} - -#ifdef PNO_SUPPORT -static s32 -wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct net_device *ndev = NULL; -#ifdef GSCAN_SUPPORT - void *ptr; - int send_evt_bytes = 0; - u32 event = be32_to_cpu(e->event_type); - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); -#endif /* GSCAN_SUPPORT */ - - WL_ERR((">>> PNO Event\n")); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - -#ifdef GSCAN_SUPPORT - ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes); - if (ptr) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes); - kfree(ptr); - } - if (!dhd_dev_is_legacy_pno_enabled(ndev)) - return 0; -#endif /* GSCAN_SUPPORT */ - -#ifndef WL_SCHED_SCAN - mutex_lock(&cfg->usr_sync); - /* TODO: Use cfg80211_sched_scan_results(wiphy); */ - cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); - mutex_unlock(&cfg->usr_sync); -#else - /* If cfg80211 scheduled scan is supported, report the pno results via sched - * scan results - */ - wl_notify_sched_scan_results(cfg, ndev, e, data); -#endif /* WL_SCHED_SCAN */ - return 0; -} -#endif /* PNO_SUPPORT */ - -#ifdef GSCAN_SUPPORT -static s32 -wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - void *ptr; - int send_evt_bytes = 0; - int batch_event_result_dummy = 0; - struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - u32 len = ntoh32(e->datalen); - - switch (event) { - case WLC_E_PFN_BEST_BATCHING: - err = dhd_dev_retrieve_batch_scan(ndev); - if (err < 0) { - WL_ERR(("Batch retrieval already in progress %d\n", err)); - } else { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_GSCAN_BATCH_SCAN_EVENT, - &batch_event_result_dummy, sizeof(int)); - } - break; - case WLC_E_PFN_SCAN_COMPLETE: - batch_event_result_dummy = WIFI_SCAN_COMPLETE; - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_COMPLETE_EVENT, - &batch_event_result_dummy, sizeof(int)); - break; - case WLC_E_PFN_BSSID_NET_FOUND: - ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes, - HOTLIST_FOUND); - if (ptr) { - wl_cfgvendor_send_hotlist_event(wiphy, ndev, - ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT); - dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_FOUND); - } else { - err = -ENOMEM; - } - break; - case WLC_E_PFN_BSSID_NET_LOST: - /* WLC_E_PFN_BSSID_NET_LOST is conflict shared with WLC_E_PFN_SCAN_ALLGONE - * We currently do not use WLC_E_PFN_SCAN_ALLGONE, so if we get it, ignore - */ - if (len) { - ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes, - HOTLIST_LOST); - if (ptr) { - wl_cfgvendor_send_hotlist_event(wiphy, ndev, - ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT); - dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_LOST); - } else { - err = -ENOMEM; - } - } else { - err = -EINVAL; - } - break; - case WLC_E_PFN_GSCAN_FULL_RESULT: - ptr = dhd_dev_process_full_gscan_result(ndev, data, len, &send_evt_bytes); - if (ptr) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes); - kfree(ptr); - } else { - err = -ENOMEM; - } - break; - case WLC_E_PFN_SSID_EXT: - ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes); - if (ptr) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes); - kfree(ptr); - } else { - err = -ENOMEM; - } - break; -#ifdef ANQPO_SUPPORT - case WLC_E_PFN_NET_FOUND: - ptr = dhd_dev_process_anqpo_result(ndev, data, event, &len); - if (ptr) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_PNO_HOTSPOT_FOUND_EVENT, ptr, len); - kfree(ptr); - } else - err = -ENOMEM; - break; -#endif /* ANQPO_SUPPORT */ - default: - WL_ERR(("Unknown event %d\n", event)); - break; - } - return err; -} -#endif /* GSCAN_SUPPORT */ - -static s32 -wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct channel_info channel_inform; - struct wl_scan_results *bss_list; - struct net_device *ndev = NULL; - u32 len = WL_SCAN_BUF_MAX; - s32 err = 0; - unsigned long flags; - - WL_DBG(("Enter \n")); - if (!wl_get_drv_status(cfg, SCANNING, ndev)) { - WL_ERR(("scan is not ready \n")); - return err; - } - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - mutex_lock(&cfg->usr_sync); - wl_clr_drv_status(cfg, SCANNING, ndev); - memset(&channel_inform, 0, sizeof(channel_inform)); - err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, - sizeof(channel_inform), false); - if (unlikely(err)) { - WL_ERR(("scan busy (%d)\n", err)); - goto scan_done_out; - } - channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); - if (unlikely(channel_inform.scan_channel)) { - - WL_DBG(("channel_inform.scan_channel (%d)\n", - channel_inform.scan_channel)); - } - cfg->bss_list = cfg->scan_results; - bss_list = cfg->bss_list; - memset(bss_list, 0, len); - bss_list->buflen = htod32(len); - err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false); - if (unlikely(err) && unlikely(!cfg->scan_suppressed)) { - WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); - err = -EINVAL; - goto scan_done_out; - } - bss_list->buflen = dtoh32(bss_list->buflen); - bss_list->version = dtoh32(bss_list->version); - bss_list->count = dtoh32(bss_list->count); - - err = wl_inform_bss(cfg); - -scan_done_out: - del_timer_sync(&cfg->scan_timeout); - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - if (cfg->scan_request) { - cfg80211_scan_done(cfg->scan_request, false); - cfg->scan_request = NULL; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - WL_DBG(("cfg80211_scan_done\n")); - mutex_unlock(&cfg->usr_sync); - return err; -} - -static s32 -wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, - const struct ether_addr *sa, const struct ether_addr *bssid, - u8 **pheader, u32 *body_len, u8 *pbody) -{ - struct dot11_management_header *hdr; - u32 totlen = 0; - s32 err = 0; - u8 *offset; - u32 prebody_len = *body_len; - switch (fc) { - case FC_ASSOC_REQ: - /* capability , listen interval */ - totlen = DOT11_ASSOC_REQ_FIXED_LEN; - *body_len += DOT11_ASSOC_REQ_FIXED_LEN; - break; - - case FC_REASSOC_REQ: - /* capability, listen inteval, ap address */ - totlen = DOT11_REASSOC_REQ_FIXED_LEN; - *body_len += DOT11_REASSOC_REQ_FIXED_LEN; - break; - } - totlen += DOT11_MGMT_HDR_LEN + prebody_len; - *pheader = kzalloc(totlen, GFP_KERNEL); - if (*pheader == NULL) { - WL_ERR(("memory alloc failed \n")); - return -ENOMEM; - } - hdr = (struct dot11_management_header *) (*pheader); - hdr->fc = htol16(fc); - hdr->durid = 0; - hdr->seq = 0; - offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len); - bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN); - bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN); - bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN); - if ((pbody != NULL) && prebody_len) - bcopy((const char*)pbody, offset, prebody_len); - *body_len = totlen; - return err; -} - - -void -wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - if (timer_pending(&cfg->p2p->listen_timer)) { - del_timer_sync(&cfg->p2p->listen_timer); - } - if (cfg->afx_hdl != NULL) { - if (cfg->afx_hdl->dev != NULL) { - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev); - } - cfg->afx_hdl->peer_chan = WL_INVALID; - } - complete(&cfg->act_frm_scan); - WL_DBG(("*** Wake UP ** Working afx searching is cleared\n")); - } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) { - if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) || - wl_get_p2p_status(cfg, ACTION_TX_NOACK))) - wl_set_p2p_status(cfg, ACTION_TX_COMPLETED); - - WL_DBG(("*** Wake UP ** abort actframe iovar\n")); - /* if channel is not zero, "actfame" uses off channel scan. - * So abort scan for off channel completion. - */ - if (cfg->af_sent_channel) - wl_cfg80211_scan_abort(cfg); - } -#ifdef WL_CFG80211_SYNC_GON - else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { - WL_DBG(("*** Wake UP ** abort listen for next af frame\n")); - /* So abort scan to cancel listen */ - wl_cfg80211_scan_abort(cfg); - } -#endif /* WL_CFG80211_SYNC_GON */ -} - - -int wl_cfg80211_get_ioctl_version(void) -{ - return ioctl_version; -} - -static s32 -wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct ieee80211_supported_band *band; - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - struct ether_addr da; - struct ether_addr bssid; - bool isfree = false; - s32 err = 0; - s32 freq; - struct net_device *ndev = NULL; - wifi_p2p_pub_act_frame_t *act_frm = NULL; - wifi_p2p_action_frame_t *p2p_act_frm = NULL; - wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; - wl_event_rx_frame_data_t *rxframe; - u32 event; - u8 *mgmt_frame; - u8 bsscfgidx; - u32 mgmt_frame_len; - u16 channel; - if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) { - WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen))); - return -EINVAL; - } - mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); - event = ntoh32(e->event_type); - bsscfgidx = e->bsscfgidx; - rxframe = (wl_event_rx_frame_data_t *)data; - if (!rxframe) { - WL_ERR(("rxframe: NULL\n")); - return -EINVAL; - } - channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK); - memset(&bssid, 0, ETHER_ADDR_LEN); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - if (!band) { - WL_ERR(("No valid band")); - return -EINVAL; - } -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) - freq = ieee80211_channel_to_frequency(channel); - (void)band->band; -#else - freq = ieee80211_channel_to_frequency(channel, band->band); -#endif - if (event == WLC_E_ACTION_FRAME_RX) { - wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", - NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); - - memset(&bssid, 0, sizeof(bssid)); - err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - if (err < 0) - WL_ERR(("WLC_GET_BSSID error %d\n", err)); - memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); - err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, - &mgmt_frame, &mgmt_frame_len, - (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); - if (err < 0) { - WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n", - mgmt_frame_len, channel, freq)); - goto exit; - } - isfree = true; - if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { - act_frm = (wifi_p2p_pub_act_frame_t *) - (&mgmt_frame[DOT11_MGMT_HDR_LEN]); - } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { - p2p_act_frm = (wifi_p2p_action_frame_t *) - (&mgmt_frame[DOT11_MGMT_HDR_LEN]); - (void) p2p_act_frm; - } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { - - sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) - (&mgmt_frame[DOT11_MGMT_HDR_LEN]); - if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) { - if (cfg->next_af_subtype == sd_act_frm->action) { - WL_DBG(("We got a right next frame of SD!(%d)\n", - sd_act_frm->action)); - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); - - /* Stop waiting for next AF. */ - wl_stop_wait_next_action_frame(cfg, ndev); - } - } - (void) sd_act_frm; -#ifdef WLTDLS - } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) { - WL_DBG((" TDLS Action Frame Received type = %d \n", - mgmt_frame[DOT11_MGMT_HDR_LEN + 1])); - - if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) { - cfg->tdls_mgmt_frame = mgmt_frame; - cfg->tdls_mgmt_frame_len = mgmt_frame_len; - cfg->tdls_mgmt_freq = freq; - return 0; - } - - } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_VENDOR_SPECIFIC) { - WL_DBG((" TDLS Vendor Specific Received type \n")); -#endif - } else { - - if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { - u8 action = 0; - if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) { - WL_DBG(("Recived action is not public action frame\n")); - } else if (cfg->next_af_subtype == action) { - WL_DBG(("Recived action is the waiting action(%d)\n", - action)); - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); - - /* Stop waiting for next AF. */ - wl_stop_wait_next_action_frame(cfg, ndev); - } - } - } - - if (act_frm) { - - if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) { - if (cfg->next_af_subtype == act_frm->subtype) { - WL_DBG(("We got a right next frame!(%d)\n", - act_frm->subtype)); - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); - - if (cfg->next_af_subtype == P2P_PAF_GON_CONF) { - OSL_SLEEP(20); - } - - /* Stop waiting for next AF. */ - wl_stop_wait_next_action_frame(cfg, ndev); - } - } - } - - wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], - mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel); - /* - * After complete GO Negotiation, roll back to mpc mode - */ - if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || - (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { - wldev_iovar_setint(ndev, "mpc", 1); - } - if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { - WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - } - } else if (event == WLC_E_PROBREQ_MSG) { - - /* Handle probe reqs frame - * WPS-AP certification 4.2.13 - */ - struct parsed_ies prbreq_ies; - u32 prbreq_ie_len = 0; - bool pbc = 0; - - WL_DBG((" Event WLC_E_PROBREQ_MSG received\n")); - mgmt_frame = (u8 *)(data); - mgmt_frame_len = ntoh32(e->datalen); - if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) { - WL_ERR(("wrong datalen:%d\n", mgmt_frame_len)); - return -EINVAL; - } - prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN; - - /* Parse prob_req IEs */ - if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN], - prbreq_ie_len, &prbreq_ies) < 0) { - WL_ERR(("Prob req get IEs failed\n")); - return 0; - } - if (prbreq_ies.wps_ie != NULL) { - wl_validate_wps_ie((char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc); - WL_DBG((" wps_ie exist pbc = %d\n", pbc)); - /* if pbc method, send prob_req mgmt frame to upper layer */ - if (!pbc) - return 0; - } else - return 0; - } else { - mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); - - /* wpa supplicant use probe request event for restarting another GON Req. - * but it makes GON Req repetition. - * so if src addr of prb req is same as my target device, - * do not send probe request event during sending action frame. - */ - if (event == WLC_E_P2P_PROBREQ_MSG) { - WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ? - "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG")); - - - /* Filter any P2P probe reqs arriving during the - * GO-NEG Phase - */ - if (cfg->p2p && - wl_get_p2p_status(cfg, GO_NEG_PHASE)) { - WL_DBG(("Filtering P2P probe_req while " - "being in GO-Neg state\n")); - return 0; - } - } - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) - cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) - cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); -#else - cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); -#endif /* LINUX_VERSION >= VERSION(3, 13, 0) */ - - WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", - mgmt_frame_len, ntoh32(e->datalen), channel, freq)); -exit: - if (isfree) - kfree(mgmt_frame); - return 0; -} - -#ifdef WL_SCHED_SCAN -/* If target scan is not reliable, set the below define to "1" to do a - * full escan - */ -#define FULL_ESCAN_ON_PFN_NET_FOUND 0 -static s32 -wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - wl_pfn_net_info_t *netinfo, *pnetinfo; - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - int err = 0; - struct cfg80211_scan_request *request = NULL; - struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; - struct ieee80211_channel *channel = NULL; - int channel_req = 0; - int band = 0; - struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; - int n_pfn_results = pfn_result->count; - - WL_DBG(("Enter\n")); - - if ((e->event_type == WLC_E_PFN_NET_LOST) || !data) { - WL_PNO(("Do Nothing %d\n", e->event_type)); - return 0; - } - if (pfn_result->version != PFN_SCANRESULT_VERSION) { - WL_ERR(("Incorrect version %d, expected %d\n", pfn_result->version, - PFN_SCANRESULT_VERSION)); - return 0; - } - WL_PNO((">>> PFN NET FOUND event. count:%d \n", n_pfn_results)); - if (n_pfn_results > 0) { - int i; - - if (n_pfn_results > MAX_PFN_LIST_COUNT) - n_pfn_results = MAX_PFN_LIST_COUNT; - pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) - - sizeof(wl_pfn_net_info_t)); - - memset(&ssid, 0x00, sizeof(ssid)); - - request = kzalloc(sizeof(*request) - + sizeof(*request->channels) * n_pfn_results, - GFP_KERNEL); - channel = (struct ieee80211_channel *)kzalloc( - (sizeof(struct ieee80211_channel) * n_pfn_results), - GFP_KERNEL); - if (!request || !channel) { - WL_ERR(("No memory")); - err = -ENOMEM; - goto out_err; - } - - request->wiphy = wiphy; - - for (i = 0; i < n_pfn_results; i++) { - netinfo = &pnetinfo[i]; - if (!netinfo) { - WL_ERR(("Invalid netinfo ptr. index:%d", i)); - err = -EINVAL; - goto out_err; - } - WL_PNO((">>> SSID:%s Channel:%d \n", - netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel)); - /* PFN result doesn't have all the info which are required by the supplicant - * (For e.g IEs) Do a target Escan so that sched scan results are reported - * via wl_inform_single_bss in the required format. Escan does require the - * scan request in the form of cfg80211_scan_request. For timebeing, create - * cfg80211_scan_request one out of the received PNO event. - */ - ssid[i].ssid_len = MIN(netinfo->pfnsubnet.SSID_len, DOT11_MAX_SSID_LEN); - memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, ssid[i].ssid_len); - request->n_ssids++; - - channel_req = netinfo->pfnsubnet.channel; - band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ - : NL80211_BAND_5GHZ; - channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); - channel[i].band = band; - channel[i].flags |= IEEE80211_CHAN_NO_HT40; - request->channels[i] = &channel[i]; - request->n_channels++; - } - - /* assign parsed ssid array */ - if (request->n_ssids) - request->ssids = &ssid[0]; - - if (wl_get_drv_status_all(cfg, SCANNING)) { - /* Abort any on-going scan */ - wl_notify_escan_complete(cfg, ndev, true, true); - } - - if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { - WL_PNO((">>> P2P discovery was ON. Disabling it\n")); - err = wl_cfgp2p_discover_enable_search(cfg, false); - if (unlikely(err)) { - wl_clr_drv_status(cfg, SCANNING, ndev); - goto out_err; - } - p2p_scan(cfg) = false; - } - - wl_set_drv_status(cfg, SCANNING, ndev); -#if FULL_ESCAN_ON_PFN_NET_FOUND - WL_PNO((">>> Doing Full ESCAN on PNO event\n")); - err = wl_do_escan(cfg, wiphy, ndev, NULL); -#else - WL_PNO((">>> Doing targeted ESCAN on PNO event\n")); - err = wl_do_escan(cfg, wiphy, ndev, request); -#endif - if (err) { - wl_clr_drv_status(cfg, SCANNING, ndev); - goto out_err; - } - cfg->sched_scan_running = TRUE; - } - else { - WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); - } -out_err: - if (request) - kfree(request); - if (channel) - kfree(channel); - return err; -} -#endif /* WL_SCHED_SCAN */ - -static void wl_init_conf(struct wl_conf *conf) -{ - WL_DBG(("Enter \n")); - 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 wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - unsigned long flags; - struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); - - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - memset(profile, 0, sizeof(struct wl_profile)); - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); -} - -static void wl_init_event_handler(struct bcm_cfg80211 *cfg) -{ - memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler)); - - cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; - cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; - cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; - cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; - cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; - cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; - cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; - cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; - cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; - cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; - cfg->evt_handler[WLC_E_START] = wl_notify_connect_status; -#ifdef PNO_SUPPORT - cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; -#endif /* PNO_SUPPORT */ -#ifdef GSCAN_SUPPORT - cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event; -#ifdef ANQPO_SUPPORT - cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event; -#endif /* ANQPO_SUPPORT */ -#endif /* GSCAN_SUPPORT */ -#ifdef RSSI_MONITOR_SUPPORT - cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event; -#endif /* RSSI_MONITOR_SUPPORT */ -#ifdef WLTDLS - cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler; -#endif /* WLTDLS */ - cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status; -#ifdef WLAIBSS - cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail; -#endif /* WLAIBSS */ - cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status; -#ifdef WL_NAN - cfg->evt_handler[WLC_E_NAN] = wl_cfgnan_notify_nan_status; - cfg->evt_handler[WLC_E_PROXD] = wl_cfgnan_notify_proxd_status; -#endif /* WL_NAN */ -#ifdef DHD_LOSSLESS_ROAMING - cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status; -#endif - -} - -#if defined(STATIC_WL_PRIV_STRUCT) -static void -wl_init_escan_result_buf(struct bcm_cfg80211 *cfg) -{ - cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub, DHD_PREALLOC_WIPHY_ESCAN0, 0); - bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE); -} - -static void -wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg) -{ - cfg->escan_info.escan_buf = NULL; - -} -#endif /* STATIC_WL_PRIV_STRUCT */ - -static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg) -{ - WL_DBG(("Enter \n")); - cfg->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); - if (unlikely(!cfg->scan_results)) { - WL_ERR(("Scan results alloc failed\n")); - goto init_priv_mem_out; - } - cfg->conf = (void *)kzalloc(sizeof(*cfg->conf), GFP_KERNEL); - if (unlikely(!cfg->conf)) { - WL_ERR(("wl_conf alloc failed\n")); - goto init_priv_mem_out; - } - cfg->scan_req_int = - (void *)kzalloc(sizeof(*cfg->scan_req_int), GFP_KERNEL); - if (unlikely(!cfg->scan_req_int)) { - WL_ERR(("Scan req alloc failed\n")); - goto init_priv_mem_out; - } - cfg->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); - if (unlikely(!cfg->ioctl_buf)) { - WL_ERR(("Ioctl buf alloc failed\n")); - goto init_priv_mem_out; - } - cfg->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); - if (unlikely(!cfg->escan_ioctl_buf)) { - WL_ERR(("Ioctl buf alloc failed\n")); - goto init_priv_mem_out; - } - cfg->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); - if (unlikely(!cfg->extra_buf)) { - WL_ERR(("Extra buf alloc failed\n")); - goto init_priv_mem_out; - } - cfg->pmk_list = (void *)kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL); - if (unlikely(!cfg->pmk_list)) { - WL_ERR(("pmk list alloc failed\n")); - goto init_priv_mem_out; - } - cfg->sta_info = (void *)kzalloc(sizeof(*cfg->sta_info), GFP_KERNEL); - if (unlikely(!cfg->sta_info)) { - WL_ERR(("sta info alloc failed\n")); - goto init_priv_mem_out; - } - -#if defined(STATIC_WL_PRIV_STRUCT) - cfg->conn_info = (void *)kzalloc(sizeof(*cfg->conn_info), GFP_KERNEL); - if (unlikely(!cfg->conn_info)) { - WL_ERR(("cfg->conn_info alloc failed\n")); - goto init_priv_mem_out; - } - cfg->ie = (void *)kzalloc(sizeof(*cfg->ie), GFP_KERNEL); - if (unlikely(!cfg->ie)) { - WL_ERR(("cfg->ie alloc failed\n")); - goto init_priv_mem_out; - } - wl_init_escan_result_buf(cfg); -#endif /* STATIC_WL_PRIV_STRUCT */ - cfg->afx_hdl = (void *)kzalloc(sizeof(*cfg->afx_hdl), GFP_KERNEL); - if (unlikely(!cfg->afx_hdl)) { - WL_ERR(("afx hdl alloc failed\n")); - goto init_priv_mem_out; - } else { - init_completion(&cfg->act_frm_scan); - init_completion(&cfg->wait_next_af); - - INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler); - } - return 0; - -init_priv_mem_out: - wl_deinit_priv_mem(cfg); - - return -ENOMEM; -} - -static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg) -{ - kfree(cfg->scan_results); - cfg->scan_results = NULL; - kfree(cfg->conf); - cfg->conf = NULL; - kfree(cfg->scan_req_int); - cfg->scan_req_int = NULL; - kfree(cfg->ioctl_buf); - cfg->ioctl_buf = NULL; - kfree(cfg->escan_ioctl_buf); - cfg->escan_ioctl_buf = NULL; - kfree(cfg->extra_buf); - cfg->extra_buf = NULL; - kfree(cfg->pmk_list); - cfg->pmk_list = NULL; - kfree(cfg->sta_info); - cfg->sta_info = NULL; -#if defined(STATIC_WL_PRIV_STRUCT) - kfree(cfg->conn_info); - cfg->conn_info = NULL; - kfree(cfg->ie); - cfg->ie = NULL; - wl_deinit_escan_result_buf(cfg); -#endif /* STATIC_WL_PRIV_STRUCT */ - if (cfg->afx_hdl) { - cancel_work_sync(&cfg->afx_hdl->work); - kfree(cfg->afx_hdl); - cfg->afx_hdl = NULL; - } - - if (cfg->ap_info) { - kfree(cfg->ap_info->wpa_ie); - kfree(cfg->ap_info->rsn_ie); - kfree(cfg->ap_info->wps_ie); - kfree(cfg->ap_info); - cfg->ap_info = NULL; - } -#ifdef WLTDLS - if (cfg->tdls_mgmt_frame) { - kfree(cfg->tdls_mgmt_frame); - cfg->tdls_mgmt_frame = NULL; - } -#endif /* WLTDLS */ -} - -static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg) -{ - int ret = 0; - WL_DBG(("Enter \n")); - - /* Do not use DHD in cfg driver */ - cfg->event_tsk.thr_pid = -1; - - PROC_START(wl_event_handler, cfg, &cfg->event_tsk, 0, "wl_event_handler"); - if (cfg->event_tsk.thr_pid < 0) - ret = -ENOMEM; - return ret; -} - -static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg) -{ - if (cfg->event_tsk.thr_pid >= 0) - PROC_STOP(&cfg->event_tsk); -} - -static void wl_scan_timeout(unsigned long data) -{ - wl_event_msg_t msg; - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; - - if (!(cfg->scan_request)) { - WL_ERR(("timer expired but no scan request\n")); - return; - } - bzero(&msg, sizeof(wl_event_msg_t)); - WL_ERR(("timer expired\n")); - msg.event_type = hton32(WLC_E_ESCAN_RESULT); - msg.status = hton32(WLC_E_STATUS_TIMEOUT); - msg.reason = 0xFFFFFFFF; - wl_cfg80211_event(bcmcfg_to_prmry_ndev(cfg), &msg, NULL); -} - -#ifdef DHD_LOSSLESS_ROAMING -static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); - - /* restore prec_map to ALLPRIO */ - dhdp->dequeue_prec_map = ALLPRIO; - if (timer_pending(&cfg->roam_timeout)) { - del_timer_sync(&cfg->roam_timeout); - } - -} - -static void wl_roam_timeout(unsigned long data) -{ - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; - dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); - - WL_ERR(("roam timer expired\n")); - - /* restore prec_map to ALLPRIO */ - dhdp->dequeue_prec_map = ALLPRIO; -} - -#endif /* DHD_LOSSLESS_ROAMING */ - -static s32 -wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, - unsigned long state, - void *ndev) -{ - struct net_device *dev = ndev; - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - WL_DBG(("Enter \n")); - - if (!wdev || !cfg || dev == bcmcfg_to_prmry_ndev(cfg)) - return NOTIFY_DONE; - - switch (state) { - case NETDEV_DOWN: - { -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) - int max_wait_timeout = 2; - int max_wait_count = 100; - int refcnt = 0; - unsigned long limit = jiffies + max_wait_timeout * msecs_to_jiffies(1000); - while (work_pending(&wdev->cleanup_work)) { - if (refcnt%5 == 0) { - WL_ERR(("[NETDEV_DOWN] wait for " - "complete of cleanup_work" - " (%d th)\n", refcnt)); - } - if (!time_before(jiffies, limit)) { - WL_ERR(("[NETDEV_DOWN] cleanup_work" - " of CFG80211 is not" - " completed in %d sec\n", - max_wait_timeout)); - break; - } - if (refcnt >= max_wait_count) { - WL_ERR(("[NETDEV_DOWN] cleanup_work" - " of CFG80211 is not" - " completed in %d loop\n", - max_wait_count)); - break; - } - set_current_state(TASK_INTERRUPTIBLE); - (void)schedule_timeout(HZ); - set_current_state(TASK_RUNNING); - refcnt++; - } -#endif /* LINUX_VERSION < VERSION(3, 13, 0) */ - break; - } - - case NETDEV_UNREGISTER: - /* after calling list_del_rcu(&wdev->list) */ - wl_dealloc_netinfo(cfg, ndev); - break; - case NETDEV_GOING_DOWN: - /* At NETDEV_DOWN state, wdev_cleanup_work work will be called. - * In front of door, the function checks - * whether current scan is working or not. - * If the scanning is still working, wdev_cleanup_work call WARN_ON and - * make the scan done forcibly. - */ - if (wl_get_drv_status(cfg, SCANNING, dev)) - wl_notify_escan_complete(cfg, dev, true, true); - break; - } - return NOTIFY_DONE; -} -static struct notifier_block wl_cfg80211_netdev_notifier = { - .notifier_call = wl_cfg80211_netdev_notifier_call, -}; -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool wl_cfg80211_netdev_notifier_registered = FALSE; - -static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg) -{ - wl_scan_params_t *params = NULL; - s32 params_size = 0; - s32 err = BCME_OK; - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - if (!in_atomic()) { - /* Our scan params only need space for 1 channel and 0 ssids */ - params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); - if (params == NULL) { - WL_ERR(("scan params allocation failed \n")); - err = -ENOMEM; - } else { - /* Do a scan abort to stop the driver's scan engine */ - err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); - if (err < 0) { - WL_ERR(("scan abort failed \n")); - } - kfree(params); - } - } -} - -#if defined(WL_ABORT_SCAN) -static void wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (cfg == NULL) { - WL_ERR(("Parsing parameter failed\n")); - return; - } - wl_cfg80211_scan_abort(cfg); -} -#endif /* WL_ABORT_SCAN */ - -static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, - struct net_device *ndev, - bool aborted, bool fw_abort) -{ - s32 err = BCME_OK; - unsigned long flags; - struct net_device *dev; - - WL_DBG(("Enter \n")); - if (!ndev) { - WL_ERR(("ndev is null\n")); - err = BCME_ERROR; - return err; - } - - if (cfg->escan_info.ndev != ndev) { - WL_ERR(("ndev is different %p %p\n", cfg->escan_info.ndev, ndev)); - err = BCME_ERROR; - return err; - } - - if (cfg->scan_request) { - dev = bcmcfg_to_prmry_ndev(cfg); -#if defined(WL_ENABLE_P2P_IF) - if (cfg->scan_request->dev != cfg->p2p_net) - dev = cfg->scan_request->dev; -#endif /* WL_ENABLE_P2P_IF */ - } - else { - WL_DBG(("cfg->scan_request is NULL may be internal scan." - "doing scan_abort for ndev %p primary %p", - ndev, bcmcfg_to_prmry_ndev(cfg))); - dev = ndev; - } - if (fw_abort && !in_atomic()) - wl_cfg80211_scan_abort(cfg); - if (timer_pending(&cfg->scan_timeout)) - del_timer_sync(&cfg->scan_timeout); -#if defined(ESCAN_RESULT_PATCH) - if (likely(cfg->scan_request)) { - cfg->bss_list = wl_escan_get_buf(cfg, aborted); - wl_inform_bss(cfg); - } -#endif /* ESCAN_RESULT_PATCH */ - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); -#ifdef WL_SCHED_SCAN - if (cfg->sched_scan_req && !cfg->scan_request) { - WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n")); - if (!aborted) - cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy); - cfg->sched_scan_running = FALSE; - cfg->sched_scan_req = NULL; - } -#endif /* WL_SCHED_SCAN */ - if (likely(cfg->scan_request)) { - cfg80211_scan_done(cfg->scan_request, aborted); - cfg->scan_request = NULL; - } - if (p2p_is_on(cfg)) - wl_clr_p2p_status(cfg, SCANNING); - wl_clr_drv_status(cfg, SCANNING, dev); - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - return err; -} - -static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - s32 err = BCME_OK; - s32 status = ntoh32(e->status); - wl_bss_info_t *bi; - wl_escan_result_t *escan_result; - wl_bss_info_t *bss = NULL; - wl_scan_results_t *list; - wifi_p2p_ie_t * p2p_ie; - struct net_device *ndev = NULL; - u32 bi_length; - u32 i; - u8 *p2p_dev_addr = NULL; - - WL_DBG((" enter event type : %d, status : %d \n", - ntoh32(e->event_type), ntoh32(e->status))); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - mutex_lock(&cfg->usr_sync); - /* P2P SCAN is coming from primary interface */ - if (wl_get_p2p_status(cfg, SCANNING)) { - if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) - ndev = cfg->afx_hdl->dev; - else - ndev = cfg->escan_info.ndev; - - } - if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) { - WL_ERR(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n", - ndev, wl_get_drv_status(cfg, SCANNING, ndev), - ntoh32(e->event_type), ntoh32(e->status))); - goto exit; - } - escan_result = (wl_escan_result_t *)data; - - if (status == WLC_E_STATUS_PARTIAL) { - WL_INFO(("WLC_E_STATUS_PARTIAL \n")); - if (!escan_result) { - WL_ERR(("Invalid escan result (NULL pointer)\n")); - goto exit; - } - if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) || - (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) { - WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen))); - goto exit; - } - if (dtoh16(escan_result->bss_count) != 1) { - WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); - goto exit; - } - bi = escan_result->bss_info; - if (!bi) { - WL_ERR(("Invalid escan bss info (NULL pointer)\n")); - goto exit; - } - bi_length = dtoh32(bi->length); - if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { - WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); - goto exit; - } - if (wl_escan_check_sync_id(status, escan_result->sync_id, - cfg->escan_info.cur_sync_id) < 0) - goto exit; - - if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { - if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { - WL_DBG(("Ignoring IBSS result\n")); - goto exit; - } - } - - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); - if (p2p_dev_addr && !memcmp(p2p_dev_addr, - cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) { - s32 channel = wf_chspec_ctlchan( - wl_chspec_driver_to_host(bi->chanspec)); - - if ((channel > MAXCHANNEL) || (channel <= 0)) - channel = WL_INVALID; - else - WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found," - " channel : %d\n", - MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet), - channel)); - - wl_clr_p2p_status(cfg, SCANNING); - cfg->afx_hdl->peer_chan = channel; - complete(&cfg->act_frm_scan); - goto exit; - } - - } else { - int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; - list = wl_escan_get_buf(cfg, FALSE); - if (scan_req_match(cfg)) { - /* p2p scan && allow only probe response */ - if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) && - (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) - goto exit; - if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, - bi->ie_length)) == NULL) { - WL_ERR(("Couldn't find P2PIE in probe" - " response/beacon\n")); - goto exit; - } - } - for (i = 0; i < list->count; i++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) - : list->bss_info; - - if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && - (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec)) - == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) && - bi->SSID_len == bss->SSID_len && - !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { - - /* do not allow beacon data to update - *the data recd from a probe response - */ - if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) && - (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) - goto exit; - - WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d" - " flags 0x%x, new: RSSI %d flags 0x%x\n", - bss->SSID, MAC2STRDBG(bi->BSSID.octet), i, - bss->RSSI, bss->flags, bi->RSSI, bi->flags)); - - if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == - (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) { - /* preserve max RSSI if the measurements are - * both on-channel or both off-channel - */ - WL_SCAN(("%s("MACDBG"), same onchan" - ", RSSI: prev %d new %d\n", - bss->SSID, MAC2STRDBG(bi->BSSID.octet), - bss->RSSI, bi->RSSI)); - bi->RSSI = MAX(bss->RSSI, bi->RSSI); - } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && - (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { - /* preserve the on-channel rssi measurement - * if the new measurement is off channel - */ - WL_SCAN(("%s("MACDBG"), prev onchan" - ", RSSI: prev %d new %d\n", - bss->SSID, MAC2STRDBG(bi->BSSID.octet), - bss->RSSI, bi->RSSI)); - bi->RSSI = bss->RSSI; - bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; - } - if (dtoh32(bss->length) != bi_length) { - u32 prev_len = dtoh32(bss->length); - - WL_SCAN(("bss info replacement" - " is occured(bcast:%d->probresp%d)\n", - bss->ie_length, bi->ie_length)); - WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n", - bss->SSID, MAC2STRDBG(bi->BSSID.octet), - prev_len, bi_length)); - - if (list->buflen - prev_len + bi_length - > ESCAN_BUF_SIZE) { - WL_ERR(("Buffer is too small: keep the" - " previous result of this AP\n")); - /* Only update RSSI */ - bss->RSSI = bi->RSSI; - bss->flags |= (bi->flags - & WL_BSS_FLAGS_RSSI_ONCHANNEL); - goto exit; - } - - if (i < list->count - 1) { - /* memory copy required by this case only */ - memmove((u8 *)bss + bi_length, - (u8 *)bss + prev_len, - list->buflen - cur_len - prev_len); - } - list->buflen -= prev_len; - list->buflen += bi_length; - } - list->version = dtoh32(bi->version); - memcpy((u8 *)bss, (u8 *)bi, bi_length); - goto exit; - } - cur_len += dtoh32(bss->length); - } - if (bi_length > ESCAN_BUF_SIZE - list->buflen) { - WL_ERR(("Buffer is too small: ignoring\n")); - goto exit; - } - - memcpy(&(((char *)list)[list->buflen]), bi, bi_length); - list->version = dtoh32(bi->version); - list->buflen += bi_length; - list->count++; - - /* - * !Broadcast && number of ssid = 1 && number of channels =1 - * means specific scan to association - */ - if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) { - WL_ERR(("P2P assoc scan fast aborted.\n")); - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false, true); - goto exit; - } - } - - } - else if (status == WLC_E_STATUS_SUCCESS) { - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id, - escan_result->sync_id); - - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - WL_INFO(("ACTION FRAME SCAN DONE\n")); - wl_clr_p2p_status(cfg, SCANNING); - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - if (cfg->afx_hdl->peer_chan == WL_INVALID) - complete(&cfg->act_frm_scan); - } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { - WL_INFO(("ESCAN COMPLETED\n")); - cfg->bss_list = wl_escan_get_buf(cfg, FALSE); - if (!scan_req_match(cfg)) { - WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n", - cfg->bss_list->count)); - } - wl_inform_bss(cfg); - wl_notify_escan_complete(cfg, ndev, false, false); - } - wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); - } - else if (status == WLC_E_STATUS_ABORT) { - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - wl_escan_print_sync_id(status, escan_result->sync_id, - cfg->escan_info.cur_sync_id); - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - WL_INFO(("ACTION FRAME SCAN DONE\n")); - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - wl_clr_p2p_status(cfg, SCANNING); - if (cfg->afx_hdl->peer_chan == WL_INVALID) - complete(&cfg->act_frm_scan); - } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { - WL_INFO(("ESCAN ABORTED\n")); - cfg->bss_list = wl_escan_get_buf(cfg, TRUE); - if (!scan_req_match(cfg)) { - WL_TRACE_HW4(("SCAN ABORTED: scanned AP count=%d\n", - cfg->bss_list->count)); - } - wl_inform_bss(cfg); - wl_notify_escan_complete(cfg, ndev, true, false); - } - wl_escan_increment_sync_id(cfg, SCAN_BUF_CNT); - } else if (status == WLC_E_STATUS_NEWSCAN) { - WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, - escan_result->bss_count)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("reason[0x%x]\n", e->reason)); - if (e->reason == 0xFFFFFFFF) { - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); - } - } else { - WL_ERR(("unexpected Escan Event %d : abort\n", status)); - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - wl_escan_print_sync_id(status, escan_result->sync_id, - cfg->escan_info.cur_sync_id); - if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - WL_INFO(("ACTION FRAME SCAN DONE\n")); - wl_clr_p2p_status(cfg, SCANNING); - wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); - if (cfg->afx_hdl->peer_chan == WL_INVALID) - complete(&cfg->act_frm_scan); - } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { - cfg->bss_list = wl_escan_get_buf(cfg, TRUE); - if (!scan_req_match(cfg)) { - WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): " - "scanned AP count=%d\n", - cfg->bss_list->count)); - } - wl_inform_bss(cfg); - wl_notify_escan_complete(cfg, ndev, true, false); - } - wl_escan_increment_sync_id(cfg, 2); - } -exit: - mutex_unlock(&cfg->usr_sync); - return err; -} - -static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable) -{ - u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED); - struct net_info *iter, *next; - int err; - - if (!cfg->roamoff_on_concurrent) - return; - if (enable && connected_cnt > 1) { - for_each_ndev(cfg, iter, next) { - /* Save the current roam setting */ - if ((err = wldev_iovar_getint(iter->ndev, "roam_off", - (s32 *)&iter->roam_off)) != BCME_OK) { - WL_ERR(("%s:Failed to get current roam setting err %d\n", - iter->ndev->name, err)); - continue; - } - if ((err = wldev_iovar_setint(iter->ndev, "roam_off", 1)) != BCME_OK) { - WL_ERR((" %s:failed to set roam_off : %d\n", - iter->ndev->name, err)); - } - } - } - else if (!enable) { - for_each_ndev(cfg, iter, next) { - if (iter->roam_off != WL_INVALID) { - if ((err = wldev_iovar_setint(iter->ndev, "roam_off", - iter->roam_off)) == BCME_OK) - iter->roam_off = WL_INVALID; - else { - WL_ERR((" %s:failed to set roam_off : %d\n", - iter->ndev->name, err)); - } - } - } - } - return; -} - -static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg) -{ - struct net_info *iter, *next; - u32 ctl_chan = 0; - u32 chanspec = 0; - u32 pre_ctl_chan = 0; - u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED); - cfg->vsdb_mode = false; - - if (connected_cnt <= 1) { - return; - } - for_each_ndev(cfg, iter, next) { - chanspec = 0; - ctl_chan = 0; - if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) { - if (wldev_iovar_getint(iter->ndev, "chanspec", - (s32 *)&chanspec) == BCME_OK) { - chanspec = wl_chspec_driver_to_host(chanspec); - ctl_chan = wf_chspec_ctlchan(chanspec); - wl_update_prof(cfg, iter->ndev, NULL, - &ctl_chan, WL_PROF_CHAN); - } - if (!cfg->vsdb_mode) { - if (!pre_ctl_chan && ctl_chan) - pre_ctl_chan = ctl_chan; - else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) { - cfg->vsdb_mode = true; - } - } - } - } - WL_ERR(("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel")); - return; -} - -static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, - enum wl_status state, bool set) -{ - s32 pm = PM_FAST; - s32 err = BCME_OK; - u32 mode; - u32 chan = 0; - struct net_info *iter, *next; - struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); - WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n", - state, set, _net_info->pm_restore, _net_info->ndev->name)); - - if (state != WL_STATUS_CONNECTED) - return 0; - mode = wl_get_mode_by_netdev(cfg, _net_info->ndev); - if (set) { - wl_cfg80211_concurrent_roam(cfg, 1); - - if (mode == WL_MODE_AP) { - - if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false)) - WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); - } - wl_cfg80211_determine_vsdb_mode(cfg); - if (cfg->vsdb_mode || _net_info->pm_block) { - /* Delete pm_enable_work */ - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_MAINTAIN); - /* save PM_FAST in _net_info to restore this - * if _net_info->pm_block is false - */ - if (!_net_info->pm_block && (mode == WL_MODE_BSS)) { - _net_info->pm = PM_FAST; - _net_info->pm_restore = true; - } - pm = PM_OFF; - for_each_ndev(cfg, iter, next) { - if (iter->pm_restore) - continue; - /* Save the current power mode */ - iter->pm = 0; - err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, - sizeof(iter->pm), false); - WL_DBG(("%s:power save %s\n", iter->ndev->name, - iter->pm ? "enabled" : "disabled")); - if (!err && iter->pm) { - iter->pm_restore = true; - } - - } - for_each_ndev(cfg, iter, next) { - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, - sizeof(pm), true)) != 0) { - if (err == -ENODEV) - WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); - else - WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); - wl_cfg80211_update_power_mode(iter->ndev); - } - } - } else { - /* add PM Enable timer to go to power save mode - * if supplicant control pm mode, it will be cleared or - * updated by wl_cfg80211_set_power_mgmt() if not - for static IP & HW4 P2P, - * PM will be configured when timer expired - */ - - /* - * before calling pm_enable_timer, we need to set PM -1 for all ndev - */ - pm = PM_OFF; - - for_each_ndev(cfg, iter, next) { - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, - sizeof(pm), true)) != 0) { - if (err == -ENODEV) - WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); - else - WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); - } - } - - if (cfg->pm_enable_work_on) { - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - } - - cfg->pm_enable_work_on = true; - wl_add_remove_pm_enable_work(cfg, TRUE, WL_HANDLER_NOTUSE); - } -#if defined(WLTDLS) -#if defined(DISABLE_TDLS_IN_P2P) - if (cfg->vsdb_mode || p2p_is_on(cfg)) -#else - if (cfg->vsdb_mode) -#endif /* defined(DISABLE_TDLS_IN_P2P) */ - { - - err = wldev_iovar_setint(primary_dev, "tdls_enable", 0); - } -#endif /* defined(WLTDLS) */ - } - else { /* clear */ - chan = 0; - /* clear chan information when the net device is disconnected */ - wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); - wl_cfg80211_determine_vsdb_mode(cfg); - for_each_ndev(cfg, iter, next) { - if (iter->pm_restore && iter->pm) { - WL_DBG(("%s:restoring power save %s\n", - iter->ndev->name, (iter->pm ? "enabled" : "disabled"))); - err = wldev_ioctl(iter->ndev, - WLC_SET_PM, &iter->pm, sizeof(iter->pm), true); - if (unlikely(err)) { - if (err == -ENODEV) - WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); - else - WL_ERR(("%s:error(%d)\n", iter->ndev->name, err)); - break; - } - iter->pm_restore = 0; - wl_cfg80211_update_power_mode(iter->ndev); - } - } - wl_cfg80211_concurrent_roam(cfg, 0); -#if defined(WLTDLS) - if (!cfg->vsdb_mode) { - err = wldev_iovar_setint(primary_dev, "tdls_enable", 1); - } -#endif /* defined(WLTDLS) */ - } - return err; -} -static s32 wl_init_scan(struct bcm_cfg80211 *cfg) -{ - int err = 0; - - cfg->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - wl_escan_init_sync_id(cfg); - - /* Init scan_timeout timer */ - init_timer(&cfg->scan_timeout); - cfg->scan_timeout.data = (unsigned long) cfg; - cfg->scan_timeout.function = wl_scan_timeout; - - return err; -} - -#ifdef DHD_LOSSLESS_ROAMING -static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg) -{ - int err = 0; - - /* Init roam timer */ - init_timer(&cfg->roam_timeout); - cfg->roam_timeout.data = (unsigned long) cfg; - cfg->roam_timeout.function = wl_roam_timeout; - - return err; -} -#endif /* DHD_LOSSLESS_ROAMING */ - -static s32 wl_init_priv(struct bcm_cfg80211 *cfg) -{ - struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - s32 err = 0; - - cfg->scan_request = NULL; - cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); - cfg->roam_on = false; - cfg->active_scan = true; - cfg->rf_blocked = false; - cfg->vsdb_mode = false; - cfg->wlfc_on = false; - cfg->roamoff_on_concurrent = true; - cfg->disable_roam_event = false; - /* register interested state */ - set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state); - spin_lock_init(&cfg->cfgdrv_lock); - mutex_init(&cfg->ioctl_buf_sync); - init_waitqueue_head(&cfg->netif_change_event); - init_completion(&cfg->send_af_done); - init_completion(&cfg->iface_disable); - wl_init_eq(cfg); - err = wl_init_priv_mem(cfg); - if (err) - return err; - if (wl_create_event_handler(cfg)) - return -ENOMEM; - wl_init_event_handler(cfg); - mutex_init(&cfg->usr_sync); - mutex_init(&cfg->event_sync); - err = wl_init_scan(cfg); - if (err) - return err; -#ifdef DHD_LOSSLESS_ROAMING - err = wl_init_roam_timeout(cfg); - if (err) { - return err; - } -#endif /* DHD_LOSSLESS_ROAMING */ - - wl_init_conf(cfg->conf); - wl_init_prof(cfg, ndev); - wl_link_down(cfg); - DNGL_FUNC(dhd_cfg80211_init, (cfg)); - - return err; -} - -static void wl_deinit_priv(struct bcm_cfg80211 *cfg) -{ - DNGL_FUNC(dhd_cfg80211_deinit, (cfg)); - wl_destroy_event_handler(cfg); - wl_flush_eq(cfg); - wl_link_down(cfg); - del_timer_sync(&cfg->scan_timeout); -#ifdef DHD_LOSSLESS_ROAMING - del_timer_sync(&cfg->roam_timeout); -#endif - wl_deinit_priv_mem(cfg); - if (wl_cfg80211_netdev_notifier_registered) { - wl_cfg80211_netdev_notifier_registered = FALSE; - unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); - } -} - -#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) -static s32 wl_cfg80211_attach_p2p(void) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - WL_TRACE(("Enter \n")); - - if (wl_cfgp2p_register_ndev(cfg) < 0) { - WL_ERR(("P2P attach failed. \n")); - return -ENODEV; - } - - return 0; -} - -static s32 wl_cfg80211_detach_p2p(void) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct wireless_dev *wdev; - - WL_DBG(("Enter \n")); - if (!cfg) { - WL_ERR(("Invalid Ptr\n")); - return -EINVAL; - } else - wdev = cfg->p2p_wdev; - -#ifndef WL_NEWCFG_PRIVCMD_SUPPORT - if (!wdev) { - WL_ERR(("Invalid Ptr\n")); - return -EINVAL; - } -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - - wl_cfgp2p_unregister_ndev(cfg); - - cfg->p2p_wdev = NULL; - cfg->p2p_net = NULL; -#ifndef WL_NEWCFG_PRIVCMD_SUPPORT - WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev)); - kfree(wdev); -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - - return 0; -} -#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ - -s32 wl_cfg80211_attach_post(struct net_device *ndev) -{ - struct bcm_cfg80211 * cfg = NULL; - s32 err = 0; - s32 ret = 0; - WL_TRACE(("In\n")); - if (unlikely(!ndev)) { - WL_ERR(("ndev is invaild\n")); - return -ENODEV; - } - cfg = g_bcm_cfg; - if (unlikely(!cfg)) { - WL_ERR(("cfg is invaild\n")); - return -EINVAL; - } - if (!wl_get_drv_status(cfg, READY, ndev)) { - if (cfg->wdev) { - ret = wl_cfgp2p_supported(cfg, ndev); - if (ret > 0) { -#if !defined(WL_ENABLE_P2P_IF) - cfg->wdev->wiphy->interface_modes |= - (BIT(NL80211_IFTYPE_P2P_CLIENT)| - BIT(NL80211_IFTYPE_P2P_GO)); -#endif /* !WL_ENABLE_P2P_IF */ - if ((err = wl_cfgp2p_init_priv(cfg)) != 0) - goto fail; - -#if defined(WL_ENABLE_P2P_IF) - if (cfg->p2p_net) { - /* Update MAC addr for p2p0 interface here. */ - memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); - cfg->p2p_net->dev_addr[0] |= 0x02; - WL_ERR(("%s: p2p_dev_addr="MACDBG "\n", - cfg->p2p_net->name, - MAC2STRDBG(cfg->p2p_net->dev_addr))); - } else { - WL_ERR(("p2p_net not yet populated." - " Couldn't update the MAC Address for p2p0 \n")); - return -ENODEV; - } -#endif /* WL_ENABLE_P2P_IF */ - cfg->p2p_supported = true; - } else if (ret == 0) { - if ((err = wl_cfgp2p_init_priv(cfg)) != 0) - goto fail; - } else { - /* SDIO bus timeout */ - err = -ENODEV; - goto fail; - } - } - } - wl_set_drv_status(cfg, READY, ndev); -fail: - return err; -} - -s32 wl_cfg80211_attach(struct net_device *ndev, void *context) -{ - struct wireless_dev *wdev; - struct bcm_cfg80211 *cfg; - s32 err = 0; - struct device *dev; - - WL_TRACE(("In\n")); - if (!ndev) { - WL_ERR(("ndev is invaild\n")); - return -ENODEV; - } - WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev())); - dev = wl_cfg80211_get_parent_dev(); - - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (unlikely(!wdev)) { - WL_ERR(("Could not allocate wireless device\n")); - return -ENOMEM; - } - err = wl_setup_wiphy(wdev, dev, context); - if (unlikely(err)) { - kfree(wdev); - return -ENOMEM; - } - wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); - cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy); - cfg->wdev = wdev; - cfg->pub = context; - INIT_LIST_HEAD(&cfg->net_list); - ndev->ieee80211_ptr = wdev; - SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); - wdev->netdev = ndev; - cfg->state_notifier = wl_notifier_change_state; - err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE); - if (err) { - WL_ERR(("Failed to alloc net_info (%d)\n", err)); - goto cfg80211_attach_out; - } - err = wl_init_priv(cfg); - if (err) { - WL_ERR(("Failed to init iwm_priv (%d)\n", err)); - goto cfg80211_attach_out; - } - - err = wl_setup_rfkill(cfg, TRUE); - if (err) { - WL_ERR(("Failed to setup rfkill %d\n", err)); - goto cfg80211_attach_out; - } -#ifdef DEBUGFS_CFG80211 - err = wl_setup_debugfs(cfg); - if (err) { - WL_ERR(("Failed to setup debugfs %d\n", err)); - goto cfg80211_attach_out; - } -#endif - if (!wl_cfg80211_netdev_notifier_registered) { - wl_cfg80211_netdev_notifier_registered = TRUE; - err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); - if (err) { - wl_cfg80211_netdev_notifier_registered = FALSE; - WL_ERR(("Failed to register notifierl %d\n", err)); - goto cfg80211_attach_out; - } - } -#if defined(COEX_DHCP) - cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev); - if (!cfg->btcoex_info) - goto cfg80211_attach_out; -#endif - - g_bcm_cfg = cfg; - -#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) - err = wl_cfg80211_attach_p2p(); - if (err) - goto cfg80211_attach_out; -#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ - - return err; - -cfg80211_attach_out: - wl_setup_rfkill(cfg, FALSE); - wl_free_wdev(cfg); - return err; -} - -void wl_cfg80211_detach(void *para) -{ - struct bcm_cfg80211 *cfg; - - (void)para; - cfg = g_bcm_cfg; - - WL_TRACE(("In\n")); - - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - -#if defined(COEX_DHCP) - wl_cfg80211_btcoex_deinit(); - cfg->btcoex_info = NULL; -#endif - - wl_setup_rfkill(cfg, FALSE); -#ifdef DEBUGFS_CFG80211 - wl_free_debugfs(cfg); -#endif - if (cfg->p2p_supported) { - if (timer_pending(&cfg->p2p->listen_timer)) - del_timer_sync(&cfg->p2p->listen_timer); - wl_cfgp2p_deinit_priv(cfg); - } - - if (timer_pending(&cfg->scan_timeout)) - del_timer_sync(&cfg->scan_timeout); -#ifdef DHD_LOSSLESS_ROAMING - if (timer_pending(&cfg->roam_timeout)) { - del_timer_sync(&cfg->roam_timeout); - } -#endif /* DHD_LOSSLESS_ROAMING */ - -#if defined(WL_CFG80211_P2P_DEV_IF) - wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) - wl_cfg80211_detach_p2p(); -#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ - - wl_cfg80211_ibss_vsie_free(cfg); - wl_deinit_priv(cfg); - g_bcm_cfg = NULL; - wl_cfg80211_clear_parent_dev(); - wl_free_wdev(cfg); - /* PLEASE do NOT call any function after wl_free_wdev, the driver's private - * structure "cfg", which is the private part of wiphy, has been freed in - * wl_free_wdev !!!!!!!!!!! - */ -} - -static void wl_wakeup_event(struct bcm_cfg80211 *cfg) -{ - if (cfg->event_tsk.thr_pid >= 0) { - DHD_OS_WAKE_LOCK(cfg->pub); - up(&cfg->event_tsk.sema); - } -} - -static s32 wl_event_handler(void *data) -{ - struct bcm_cfg80211 *cfg = NULL; - struct wl_event_q *e; - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - bcm_struct_cfgdev *cfgdev = NULL; - - cfg = (struct bcm_cfg80211 *)tsk->parent; - - WL_ERR(("tsk Enter, tsk = 0x%p\n", tsk)); - - while (down_interruptible (&tsk->sema) == 0) { - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - DHD_OS_WAKE_UNLOCK(cfg->pub); - break; - } - while ((e = wl_deq_event(cfg))) { - WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx)); - /* All P2P device address related events comes on primary interface since - * there is no corresponding bsscfg for P2P interface. Map it to p2p0 - * interface. - */ -#if defined(WL_CFG80211_P2P_DEV_IF) - if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_wdev)) { - cfgdev = bcmcfg_to_p2p_wdev(cfg); - } else { - struct net_device *ndev = NULL; - - ndev = dhd_idx2net((struct dhd_pub *)(cfg->pub), e->emsg.ifidx); - if (ndev) - cfgdev = ndev_to_wdev(ndev); - } -#elif defined(WL_ENABLE_P2P_IF) - if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_net)) { - cfgdev = cfg->p2p_net; - } else { - cfgdev = dhd_idx2net((struct dhd_pub *)(cfg->pub), - e->emsg.ifidx); - } -#endif /* WL_CFG80211_P2P_DEV_IF */ - - if (!cfgdev) { -#if defined(WL_CFG80211_P2P_DEV_IF) - cfgdev = bcmcfg_to_prmry_wdev(cfg); -#elif defined(WL_ENABLE_P2P_IF) - cfgdev = bcmcfg_to_prmry_ndev(cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ - } - if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) { - dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub); - if (dhd->busstate == DHD_BUS_DOWN) { - WL_ERR((": BUS is DOWN.\n")); - } else - cfg->evt_handler[e->etype](cfg, cfgdev, &e->emsg, e->edata); - } else { - WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); - } - wl_put_event(e); - } - DHD_OS_WAKE_UNLOCK(cfg->pub); - } - WL_ERR(("was terminated\n")); - complete_and_exit(&tsk->completed, 0); - return 0; -} - -void -wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) -{ - u32 event_type = ntoh32(e->event_type); - struct bcm_cfg80211 *cfg = g_bcm_cfg; - -#if (WL_DBG_LEVEL > 0) - s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? - wl_dbg_estr[event_type] : (s8 *) "Unknown"; - WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); -#endif /* (WL_DBG_LEVEL > 0) */ - - if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) { - WL_ERR(("during IF change, ignore event %d\n", event_type)); - return; - } - - if (ndev != bcmcfg_to_prmry_ndev(cfg) && cfg->p2p_supported) { - if (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) && -#if defined(WL_ENABLE_P2P_IF) - (ndev != (cfg->p2p_net ? cfg->p2p_net : - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE))) && -#else - (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE)) && -#endif /* WL_ENABLE_P2P_IF */ - TRUE) { - WL_ERR(("ignore event %d, not interested\n", event_type)); - return; - } - } - - if (event_type == WLC_E_PFN_NET_FOUND) { - WL_DBG((" PNOEVENT: PNO_NET_FOUND\n")); - } - else if (event_type == WLC_E_PFN_NET_LOST) { - WL_DBG((" PNOEVENT: PNO_NET_LOST\n")); - } - - if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) - wl_wakeup_event(cfg); -} - -static void wl_init_eq(struct bcm_cfg80211 *cfg) -{ - wl_init_eq_lock(cfg); - INIT_LIST_HEAD(&cfg->eq_list); -} - -static void wl_flush_eq(struct bcm_cfg80211 *cfg) -{ - struct wl_event_q *e; - unsigned long flags; - - flags = wl_lock_eq(cfg); - while (!list_empty(&cfg->eq_list)) { - e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list); - list_del(&e->eq_list); - kfree(e); - } - wl_unlock_eq(cfg, flags); -} - -/* -* retrieve first queued event from head -*/ - -static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg) -{ - struct wl_event_q *e = NULL; - unsigned long flags; - - flags = wl_lock_eq(cfg); - if (likely(!list_empty(&cfg->eq_list))) { - e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list); - list_del(&e->eq_list); - } - wl_unlock_eq(cfg, flags); - - return e; -} - -/* - * push event to tail of the queue - */ - -static s32 -wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event, - const wl_event_msg_t *msg, void *data) -{ - struct wl_event_q *e; - s32 err = 0; - uint32 evtq_size; - uint32 data_len; - unsigned long flags; - gfp_t aflags; - - data_len = 0; - if (data) - data_len = ntoh32(msg->datalen); - evtq_size = sizeof(struct wl_event_q) + data_len; - aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; - e = kzalloc(evtq_size, aflags); - if (unlikely(!e)) { - WL_ERR(("event alloc failed\n")); - return -ENOMEM; - } - e->etype = event; - memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); - if (data) - memcpy(e->edata, data, data_len); - flags = wl_lock_eq(cfg); - list_add_tail(&e->eq_list, &cfg->eq_list); - wl_unlock_eq(cfg, flags); - - return err; -} - -static void wl_put_event(struct wl_event_q *e) -{ - kfree(e); -} - -static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype) -{ - s32 infra = 0; - s32 err = 0; - s32 mode = 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: - mode = WL_MODE_IBSS; - break; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - mode = WL_MODE_BSS; - infra = 1; - break; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - mode = WL_MODE_AP; - infra = 1; - break; - default: - err = -EINVAL; - WL_ERR(("invalid type (%d)\n", iftype)); - return err; - } - infra = htod32(infra); - err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true); - if (unlikely(err)) { - WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); - return err; - } - - wl_set_mode_by_netdev(cfg, ndev, mode); - - return 0; -} - -void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set) -{ - if (!ev || (event > WLC_E_LAST)) - return; - - if (ev->num < MAX_EVENT_BUF_NUM) { - ev->event[ev->num].type = event; - ev->event[ev->num].set = set; - ev->num++; - } else { - WL_ERR(("evenbuffer doesn't support > %u events. Update" - " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM)); - ASSERT(0); - } -} - -s32 wl_cfg80211_apply_eventbuffer( - struct net_device *ndev, - struct bcm_cfg80211 *cfg, - wl_eventmsg_buf_t *ev) -{ - char eventmask[WL_EVENTING_MASK_LEN]; - int i, ret = 0; - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - if (!ev || (!ev->num)) - return -EINVAL; - - mutex_lock(&cfg->event_sync); - - /* Read event_msgs mask */ - ret = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL); - if (unlikely(ret)) { - WL_ERR(("Get event_msgs error (%d)\n", ret)); - goto exit; - } - memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); - - /* apply the set bits */ - for (i = 0; i < ev->num; i++) { - if (ev->event[i].set) - setbit(eventmask, ev->event[i].type); - else - clrbit(eventmask, ev->event[i].type); - } - - /* Write updated Event mask */ - ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf, - sizeof(iovbuf), NULL); - if (unlikely(ret)) { - WL_ERR(("Set event_msgs error (%d)\n", ret)); - } - -exit: - mutex_unlock(&cfg->event_sync); - return ret; -} - -s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) -{ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - s8 eventmask[WL_EVENTING_MASK_LEN]; - s32 err = 0; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - if (!ndev || !cfg) - return -ENODEV; - - mutex_lock(&cfg->event_sync); - - /* Setup event_msgs */ - err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL); - if (unlikely(err)) { - WL_ERR(("Get event_msgs error (%d)\n", err)); - goto eventmsg_out; - } - memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); - if (add) { - setbit(eventmask, event); - } else { - clrbit(eventmask, event); - } - err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, - sizeof(iovbuf), NULL); - if (unlikely(err)) { - WL_ERR(("Set event_msgs error (%d)\n", err)); - goto eventmsg_out; - } - -eventmsg_out: - mutex_unlock(&cfg->event_sync); - return err; -} - -static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) -{ - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - struct ieee80211_channel *band_chan_arr = NULL; - wl_uint32_list_t *list; - u32 i, j, index, n_2g, n_5g, band, channel, array_size; - u32 *n_cnt = NULL; - chanspec_t c = 0; - s32 err = BCME_OK; - bool update; - bool ht40_allowed; - u8 *pbuf = NULL; - bool dfs_radar_disabled = FALSE; - -#define LOCAL_BUF_LEN 1024 - pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); - - if (pbuf == NULL) { - WL_ERR(("failed to allocate local buf\n")); - return -ENOMEM; - } - - err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, - 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync); - if (err != 0) { - WL_ERR(("get chanspecs failed with %d\n", err)); - kfree(pbuf); - return err; - } -#undef LOCAL_BUF_LEN - - list = (wl_uint32_list_t *)(void *)pbuf; - - if ((list) && (dtoh32(list->count) > htod32(WL_NUMCHANSPECS))) { - WL_ERR(("Invalid channel list : %d\n", dtoh32(list->count))); - kfree(pbuf); - return INVCHANSPEC; - } - - band = array_size = n_2g = n_5g = 0; - for (i = 0; i < dtoh32(list->count); i++) { - index = 0; - update = false; - ht40_allowed = false; - c = (chanspec_t)dtoh32(list->element[i]); - c = wl_chspec_driver_to_host(c); - channel = CHSPEC_CHANNEL(c); - if (CHSPEC_IS40(c)) { - if (CHSPEC_SB_UPPER(c)) - channel += CH_10MHZ_APART; - else - channel -= CH_10MHZ_APART; - } else if (CHSPEC_IS80(c)) { - WL_DBG(("HT80 center channel : %d\n", channel)); - continue; - } - if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) && - (channel <= CH_MAX_2G_CHANNEL)) { - band_chan_arr = __wl_2ghz_channels; - array_size = ARRAYSIZE(__wl_2ghz_channels); - n_cnt = &n_2g; - band = IEEE80211_BAND_2GHZ; - ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; - } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) { - band_chan_arr = __wl_5ghz_a_channels; - array_size = ARRAYSIZE(__wl_5ghz_a_channels); - n_cnt = &n_5g; - band = IEEE80211_BAND_5GHZ; - ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; - } else { - WL_ERR(("Invalid channel Sepc. 0x%x.\n", c)); - continue; - } - if (!ht40_allowed && CHSPEC_IS40(c)) - continue; - for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { - if (band_chan_arr[j].hw_value == channel) { - update = true; - break; - } - } - if (update) - index = j; - else - index = *n_cnt; - if (index < array_size) { -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) - band_chan_arr[index].center_freq = - ieee80211_channel_to_frequency(channel); -#else - band_chan_arr[index].center_freq = - ieee80211_channel_to_frequency(channel, band); -#endif - band_chan_arr[index].hw_value = channel; - band_chan_arr[index].beacon_found = false; - - if (CHSPEC_IS40(c) && ht40_allowed) { - /* assuming the order is HT20, HT40 Upper, - * HT40 lower from chanspecs - */ - u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; - if (CHSPEC_SB_UPPER(c)) { - if (ht40_flag == IEEE80211_CHAN_NO_HT40) - band_chan_arr[index].flags &= - ~IEEE80211_CHAN_NO_HT40; - band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; - } else { - /* It should be one of - * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS - */ - band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; - if (ht40_flag == IEEE80211_CHAN_NO_HT40) - band_chan_arr[index].flags |= - IEEE80211_CHAN_NO_HT40MINUS; - } - } else { - band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; - if (!dfs_radar_disabled) { - if (band == IEEE80211_BAND_2GHZ) - channel |= WL_CHANSPEC_BAND_2G; - else - channel |= WL_CHANSPEC_BAND_5G; - channel |= WL_CHANSPEC_BW_20; - channel = wl_chspec_host_to_driver(channel); - err = wldev_iovar_getint(dev, "per_chan_info", &channel); - if (!err) { - if (channel & WL_CHAN_RADAR) { -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) - band_chan_arr[index].flags |= - (IEEE80211_CHAN_RADAR - | IEEE80211_CHAN_NO_IBSS); -#else - band_chan_arr[index].flags |= - IEEE80211_CHAN_RADAR; -#endif - } - - if (channel & WL_CHAN_PASSIVE) -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) - band_chan_arr[index].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; -#else - band_chan_arr[index].flags |= - IEEE80211_CHAN_NO_IR; -#endif - } else if (err == BCME_UNSUPPORTED) { - dfs_radar_disabled = TRUE; - WL_ERR(("does not support per_chan_info\n")); - } - } - } - if (!update) - (*n_cnt)++; - } - - } - __wl_band_2ghz.n_channels = n_2g; - __wl_band_5ghz_a.n_channels = n_5g; - kfree(pbuf); - return err; -} - -s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) -{ - struct wiphy *wiphy; - struct net_device *dev; - u32 bandlist[3]; - u32 nband = 0; - u32 i = 0; - s32 err = 0; - s32 index = 0; - s32 nmode = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - u32 j = 0; - s32 vhtmode = 0; - s32 txstreams = 0; - s32 rxstreams = 0; - s32 ldpc_cap = 0; - s32 stbc_rx = 0; - s32 stbc_tx = 0; - s32 txbf_bfe_cap = 0; - s32 txbf_bfr_cap = 0; -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - bool rollback_lock = false; - s32 bw_cap = 0; - s32 cur_band = -1; - struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, }; - - if (cfg == NULL) { - cfg = g_bcm_cfg; - mutex_lock(&cfg->usr_sync); - rollback_lock = true; - } - dev = bcmcfg_to_prmry_ndev(cfg); - - memset(bandlist, 0, sizeof(bandlist)); - err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist, - sizeof(bandlist), false); - if (unlikely(err)) { - WL_ERR(("error read bandlist (%d)\n", err)); - goto end_bands; - } - err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band, - sizeof(s32), false); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - goto end_bands; - } - - err = wldev_iovar_getint(dev, "nmode", &nmode); - if (unlikely(err)) { - WL_ERR(("error reading nmode (%d)\n", err)); - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - err = wldev_iovar_getint(dev, "vhtmode", &vhtmode); - if (unlikely(err)) { - WL_ERR(("error reading vhtmode (%d)\n", err)); - } - - if (vhtmode) { - err = wldev_iovar_getint(dev, "txstreams", &txstreams); - if (unlikely(err)) { - WL_ERR(("error reading txstreams (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "rxstreams", &rxstreams); - if (unlikely(err)) { - WL_ERR(("error reading rxstreams (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap); - if (unlikely(err)) { - WL_ERR(("error reading ldpc_cap (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx); - if (unlikely(err)) { - WL_ERR(("error reading stbc_rx (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx); - if (unlikely(err)) { - WL_ERR(("error reading stbc_tx (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap); - if (unlikely(err)) { - WL_ERR(("error reading txbf_bfe_cap (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap); - if (unlikely(err)) { - WL_ERR(("error reading txbf_bfr_cap (%d)\n", err)); - } - } -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - - /* For nmode and vhtmode check bw cap */ - if (nmode || -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - vhtmode || -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - 0) { - err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); - if (unlikely(err)) { - WL_ERR(("error get mimo_bw_cap (%d)\n", err)); - } - } - - err = wl_construct_reginfo(cfg, bw_cap); - if (err) { - WL_ERR(("wl_construct_reginfo() fails err=%d\n", err)); - if (err != BCME_UNSUPPORTED) - goto end_bands; - err = 0; - } - wiphy = bcmcfg_to_wiphy(cfg); - nband = bandlist[0]; - - for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { - index = -1; - if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) { - bands[IEEE80211_BAND_5GHZ] = - &__wl_band_5ghz_a; - index = IEEE80211_BAND_5GHZ; - if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G)) - bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - /* VHT capabilities. */ - if (vhtmode) { - /* Supported */ - bands[index]->vht_cap.vht_supported = TRUE; - - for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) { - /* TX stream rates. */ - if (j <= txstreams) { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, - bands[index]->vht_cap.vht_mcs.tx_mcs_map); - } else { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, - bands[index]->vht_cap.vht_mcs.tx_mcs_map); - } - - /* RX stream rates. */ - if (j <= rxstreams) { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, - bands[index]->vht_cap.vht_mcs.rx_mcs_map); - } else { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, - bands[index]->vht_cap.vht_mcs.rx_mcs_map); - } - } - - - /* Capabilities */ - /* 80 MHz is mandatory */ - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SHORT_GI_80; - - if (WL_BW_CAP_160MHZ(bw_cap)) { - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SHORT_GI_160; - } - - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; - - if (ldpc_cap) - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_RXLDPC; - - if (stbc_tx) - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_TXSTBC; - - if (stbc_rx) - bands[index]->vht_cap.cap |= - (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT); - - if (txbf_bfe_cap) - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; - - if (txbf_bfr_cap) { - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; - } - - if (txbf_bfe_cap || txbf_bfr_cap) { - bands[index]->vht_cap.cap |= - (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT); - bands[index]->vht_cap.cap |= - ((txstreams - 1) << - VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT); - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; - } - - /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */ - bands[index]->vht_cap.cap |= - (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT); - WL_INFO(("%s band[%d] vht_enab=%d vht_cap=%08x " - "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n", - __FUNCTION__, index, - bands[index]->vht_cap.vht_supported, - bands[index]->vht_cap.cap, - bands[index]->vht_cap.vht_mcs.rx_mcs_map, - bands[index]->vht_cap.vht_mcs.tx_mcs_map)); - } -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - } - else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { - bands[IEEE80211_BAND_2GHZ] = - &__wl_band_2ghz; - index = IEEE80211_BAND_2GHZ; - if (bw_cap == WLC_N_BW_40ALL) - bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; - } - - if ((index >= 0) && nmode) { - bands[index]->ht_cap.cap |= - (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); - bands[index]->ht_cap.ht_supported = TRUE; - bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; - /* An HT shall support all EQM rates for one spatial stream */ - bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; - } - - } - - wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; - wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; - - /* check if any bands populated otherwise makes 2Ghz as default */ - if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL && - wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) { - /* Setup 2Ghz band as default */ - wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - } - - if (notify) - wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); - - end_bands: - if (rollback_lock) - mutex_unlock(&cfg->usr_sync); - return err; -} - -static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) -{ - s32 err = 0; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - struct wireless_dev *wdev = ndev->ieee80211_ptr; - - WL_DBG(("In\n")); - - err = dhd_config_dongle(cfg); - if (unlikely(err)) - return err; - - err = wl_config_ifmode(cfg, ndev, wdev->iftype); - if (unlikely(err && err != -EINPROGRESS)) { - WL_ERR(("wl_config_ifmode failed\n")); - if (err == -1) { - WL_ERR(("return error %d\n", err)); - return err; - } - } - err = wl_update_wiphybands(cfg, true); - if (unlikely(err)) { - WL_ERR(("wl_update_wiphybands failed\n")); - if (err == -1) { - WL_ERR(("return error %d\n", err)); - return err; - } - } - - err = dhd_monitor_init(cfg->pub); - - INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler); - wl_set_drv_status(cfg, READY, ndev); - return err; -} - -static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) -{ - s32 err = 0; - unsigned long flags; - struct net_info *iter, *next; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); -#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \ - defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP) - struct net_device *p2p_net = cfg->p2p_net; -#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) || !PLATFORM_SLP */ - u32 bssidx = 0; -#ifdef PROP_TXSTATUS_VSDB - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif /* PROP_TXSTATUS_VSDB */ - WL_DBG(("In\n")); - /* Delete pm_enable_work */ - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - -#ifdef WL_NAN - wl_cfgnan_stop_handler(ndev, g_bcm_cfg, NULL, NULL); -#endif /* WL_NAN */ - - if (cfg->p2p_supported) { - wl_clr_p2p_status(cfg, GO_NEG_PHASE); -#ifdef PROP_TXSTATUS_VSDB - if (cfg->p2p->vif_created) { - bool enabled = false; - dhd_wlfc_get_enable(dhd, &enabled); - if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) { - dhd_wlfc_deinit(dhd); - cfg->wlfc_on = false; - } - } -#endif /* PROP_TXSTATUS_VSDB */ - } - - - /* If primary BSS is operational (for e.g SoftAP), bring it down */ - if (!(wl_cfgp2p_find_idx(cfg, ndev, &bssidx)) && - wl_cfgp2p_bss_isup(ndev, bssidx)) { - if (wl_cfgp2p_bss(cfg, ndev, bssidx, 0) < 0) - WL_ERR(("BSS down failed \n")); - } - - /* Check if cfg80211 interface is already down */ - if (!wl_get_drv_status(cfg, READY, ndev)) - return err; /* it is even not ready */ - for_each_ndev(cfg, iter, next) - wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); - - - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - if (cfg->scan_request) { - cfg80211_scan_done(cfg->scan_request, true); - cfg->scan_request = NULL; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - for_each_ndev(cfg, iter, next) { - wl_clr_drv_status(cfg, READY, iter->ndev); - wl_clr_drv_status(cfg, SCANNING, iter->ndev); - wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev); - wl_clr_drv_status(cfg, CONNECTING, iter->ndev); - wl_clr_drv_status(cfg, CONNECTED, iter->ndev); - wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev); - wl_clr_drv_status(cfg, AP_CREATED, iter->ndev); - wl_clr_drv_status(cfg, AP_CREATING, iter->ndev); - } - bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype = - NL80211_IFTYPE_STATION; -#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \ - defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP) - if (p2p_net) - dev_close(p2p_net); -#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) || !PLATFORM_SLP */ - DNGL_FUNC(dhd_cfg80211_down, (cfg)); - wl_flush_eq(cfg); - wl_link_down(cfg); - if (cfg->p2p_supported) - wl_cfgp2p_down(cfg); - -#ifdef DHD_LOSSLESS_ROAMING - if (timer_pending(&cfg->roam_timeout)) { - del_timer_sync(&cfg->roam_timeout); - } -#endif /* DHD_LOSSLESS_ROAMING */ - - if (cfg->ap_info) { - kfree(cfg->ap_info->wpa_ie); - kfree(cfg->ap_info->rsn_ie); - kfree(cfg->ap_info->wps_ie); - kfree(cfg->ap_info); - cfg->ap_info = NULL; - } - dhd_monitor_uninit(); - -#ifdef WL11U - /* Clear interworking element. */ - if (cfg->wl11u) { - cfg->wl11u = FALSE; - cfg->iw_ie_len = 0; - memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN); - } -#endif /* WL11U */ - - return err; -} - -s32 wl_cfg80211_up(void *para) -{ - struct bcm_cfg80211 *cfg; - s32 err = 0; - int val = 1; - dhd_pub_t *dhd; - - (void)para; - WL_DBG(("In\n")); - cfg = g_bcm_cfg; - - if ((err = wldev_ioctl(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val, - sizeof(int), false) < 0)) { - WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err)); - return err; - } - val = dtoh32(val); - if (val != WLC_IOCTL_VERSION && val != 1) { - WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n", - val, WLC_IOCTL_VERSION)); - return BCME_VERSION; - } - ioctl_version = val; - WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version)); - - mutex_lock(&cfg->usr_sync); - dhd = (dhd_pub_t *)(cfg->pub); - if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { - err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg)); - if (unlikely(err)) - return err; - } - err = __wl_cfg80211_up(cfg); - if (unlikely(err)) - WL_ERR(("__wl_cfg80211_up failed\n")); - mutex_unlock(&cfg->usr_sync); - return err; -} - -/* Private Event to Supplicant with indication that chip hangs */ -int wl_cfg80211_hang(struct net_device *dev, u16 reason) -{ - struct bcm_cfg80211 *cfg; - cfg = g_bcm_cfg; - - WL_ERR(("In : chip crash eventing\n")); - wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); - cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL); - if (cfg != NULL) { - wl_link_down(cfg); - } - return 0; -} - -s32 wl_cfg80211_down(void *para) -{ - struct bcm_cfg80211 *cfg; - s32 err = 0; - - (void)para; - WL_DBG(("In\n")); - cfg = g_bcm_cfg; - mutex_lock(&cfg->usr_sync); - err = __wl_cfg80211_down(cfg); - mutex_unlock(&cfg->usr_sync); - - return err; -} - -static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item) -{ - unsigned long flags; - void *rptr = NULL; - struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); - - if (!profile) - return NULL; - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - switch (item) { - case WL_PROF_SEC: - rptr = &profile->sec; - break; - case WL_PROF_ACT: - rptr = &profile->active; - break; - case WL_PROF_BSSID: - rptr = profile->bssid; - break; - case WL_PROF_SSID: - rptr = &profile->ssid; - break; - case WL_PROF_CHAN: - rptr = &profile->channel; - break; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - if (!rptr) - WL_ERR(("invalid item (%d)\n", item)); - return rptr; -} - -static s32 -wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const wl_event_msg_t *e, void *data, s32 item) -{ - s32 err = 0; - struct wlc_ssid *ssid; - unsigned long flags; - struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); - - if (!profile) - return WL_INVALID; - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); - switch (item) { - case WL_PROF_SSID: - ssid = (wlc_ssid_t *) data; - memset(profile->ssid.SSID, 0, - sizeof(profile->ssid.SSID)); - profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN); - memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len); - break; - case WL_PROF_BSSID: - if (data) - memcpy(profile->bssid, data, ETHER_ADDR_LEN); - else - memset(profile->bssid, 0, ETHER_ADDR_LEN); - break; - case WL_PROF_SEC: - memcpy(&profile->sec, data, sizeof(profile->sec)); - break; - case WL_PROF_ACT: - profile->active = *(bool *)data; - break; - case WL_PROF_BEACONINT: - profile->beacon_interval = *(u16 *)data; - break; - case WL_PROF_DTIMPERIOD: - profile->dtim_period = *(u8 *)data; - break; - case WL_PROF_CHAN: - profile->channel = *(u32*)data; - break; - default: - err = -EOPNOTSUPP; - break; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - if (err == -EOPNOTSUPP) - WL_ERR(("unsupported item (%d)\n", item)); - - return err; -} - -void wl_cfg80211_dbg_level(u32 level) -{ - /* - * prohibit to change debug level - * by insmod parameter. - * eventually debug level will be configured - * in compile time by using CONFIG_XXX - */ - /* wl_dbg_level = level; */ -} - -static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS; -} - -static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg) -{ - return cfg->ibss_starter; -} - -static void wl_rst_ie(struct bcm_cfg80211 *cfg) -{ - struct wl_ie *ie = wl_to_ie(cfg); - - ie->offset = 0; -} - -static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v) -{ - struct wl_ie *ie = wl_to_ie(cfg); - s32 err = 0; - - if (unlikely(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; -} - -static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam) -{ - u8 *ssidie; - int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); - int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len; - ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); - - /* ERROR out if - * 1. No ssid IE is FOUND or - * 2. New ssid length is > what was allocated for existing ssid (as - * we do not want to overwrite the rest of the IEs) or - * 3. If in case of erroneous buffer input where ssid length doesnt match the space - * allocated to it. - */ - if (!ssidie) { - return; - } - available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream); - remaining_ie_buf_len = available_buffer_len - (int)ssidie[1]; - unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size); - if (ssidie[1] > available_buffer_len) { - WL_ERR(("%s: skip wl_update_hidden_ap_ie : overflow\n", __FUNCTION__)); - return; - } - - if (ssidie[1] != ssid_len) { - if (ssidie[1]) { - WL_INFO(("%s: Wrong SSID len: %d != %d\n", - __FUNCTION__, ssidie[1], bi->SSID_len)); - } - if ((roam && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) { - WL_INFO(("Changing the SSID Info.\n")); - memmove(ssidie + ssid_len + 2, - (ssidie + 2) + ssidie[1], - remaining_ie_buf_len); - memcpy(ssidie + 2, bi->SSID, ssid_len); - *ie_size = *ie_size + ssid_len - ssidie[1]; - ssidie[1] = ssid_len; - } else if (ssid_len < ssidie[1]) { - WL_ERR(("%s: Invalid SSID len: %d < %d\n", - __FUNCTION__, ssidie[1], bi->SSID_len)); - } - return; - } - if (*(ssidie + 2) == '\0') - memcpy(ssidie + 2, bi->SSID, ssid_len); - return; -} - -static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size) -{ - struct wl_ie *ie = wl_to_ie(cfg); - s32 err = 0; - - if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { - WL_ERR(("ei_stream crosses buffer boundary\n")); - return -ENOSPC; - } - memcpy(&ie->buf[ie->offset], ie_stream, ie_size); - ie->offset += ie_size; - - return err; -} - -static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size) -{ - struct wl_ie *ie = wl_to_ie(cfg); - s32 err = 0; - - if (unlikely(ie->offset > dst_size)) { - WL_ERR(("dst_size is not enough\n")); - return -ENOSPC; - } - memcpy(dst, &ie->buf[0], ie->offset); - - return err; -} - -static u32 wl_get_ielen(struct bcm_cfg80211 *cfg) -{ - struct wl_ie *ie = wl_to_ie(cfg); - - return ie->offset; -} - -static void wl_link_up(struct bcm_cfg80211 *cfg) -{ - cfg->link_up = true; -} - -static void wl_link_down(struct bcm_cfg80211 *cfg) -{ - struct wl_connect_info *conn_info = wl_to_conn(cfg); - - WL_DBG(("In\n")); - cfg->link_up = false; - conn_info->req_ie_len = 0; - conn_info->resp_ie_len = 0; -} - -static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg) -{ - unsigned long flags; - - spin_lock_irqsave(&cfg->eq_lock, flags); - return flags; -} - -static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags) -{ - spin_unlock_irqrestore(&cfg->eq_lock, flags); -} - -static void wl_init_eq_lock(struct bcm_cfg80211 *cfg) -{ - spin_lock_init(&cfg->eq_lock); -} - -static void wl_delay(u32 ms) -{ - if (in_atomic() || (ms < jiffies_to_msecs(1))) { - OSL_DELAY(ms*1000); - } else { - OSL_SLEEP(ms); - } -} - -s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - struct ether_addr p2pif_addr; - struct ether_addr primary_mac; - if (!cfg->p2p) - return -1; - if (!p2p_is_on(cfg)) { - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); - } else { - memcpy(p2pdev_addr->octet, - cfg->p2p->dev_addr.octet, ETHER_ADDR_LEN); - } - - - return 0; -} -s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) -{ - struct bcm_cfg80211 *cfg; - - cfg = g_bcm_cfg; - - return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len); -} - -s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) -{ - struct bcm_cfg80211 *cfg; - cfg = g_bcm_cfg; - - return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len); -} - -s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) -{ - struct bcm_cfg80211 *cfg; - cfg = g_bcm_cfg; - - return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len); -} - -s32 wl_cfg80211_channel_to_freq(u32 channel) -{ - int freq = 0; - -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) - freq = ieee80211_channel_to_frequency(channel); -#else - { - u16 band = 0; - if (channel <= CH_MAX_2G_CHANNEL) - band = IEEE80211_BAND_2GHZ; - else - band = IEEE80211_BAND_5GHZ; - freq = ieee80211_channel_to_frequency(channel, band); - } -#endif - return freq; -} - - -#ifdef WLTDLS -static s32 -wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) { - - struct net_device *ndev = NULL; - u32 reason = ntoh32(e->reason); - s8 *msg = NULL; - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - switch (reason) { - case WLC_E_TDLS_PEER_DISCOVERED : - msg = " TDLS PEER DISCOVERD "; - break; - case WLC_E_TDLS_PEER_CONNECTED : - if (cfg->tdls_mgmt_frame) { - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) - cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0, - cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, - GFP_ATOMIC); - #else - cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, - cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, - GFP_ATOMIC); - #endif - } - msg = " TDLS PEER CONNECTED "; - break; - case WLC_E_TDLS_PEER_DISCONNECTED : - if (cfg->tdls_mgmt_frame) { - kfree(cfg->tdls_mgmt_frame); - cfg->tdls_mgmt_frame = NULL; - cfg->tdls_mgmt_freq = 0; - } - msg = "TDLS PEER DISCONNECTED "; - break; - } - if (msg) { - WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((u8*)(&e->addr)), - (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary")); - } - return 0; - -} -#endif /* WLTDLS */ - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) -static s32 -#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) -wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, - u32 peer_capability, const u8 *data, size_t len) -#else -wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data, - size_t len) -#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ -{ - s32 ret = 0; -#ifdef WLTDLS - struct bcm_cfg80211 *cfg; - tdls_wfd_ie_iovar_t info; - memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t)); - cfg = g_bcm_cfg; - -#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) - /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10 - * and that cuases build error - */ - BCM_REFERENCE(peer_capability); -#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ - - switch (action_code) { - /* We need to set TDLS Wifi Display IE to firmware - * using tdls_wfd_ie iovar - */ - case WLAN_TDLS_SET_PROBE_WFD_IE: - info.mode = TDLS_WFD_PROBE_IE_TX; - memcpy(&info.data, data, len); - info.length = len; - break; - case WLAN_TDLS_SET_SETUP_WFD_IE: - info.mode = TDLS_WFD_IE_TX; - memcpy(&info.data, data, len); - info.length = len; - break; - default: - WL_ERR(("Unsupported action code : %d\n", action_code)); - goto out; - } - - ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (ret) { - WL_ERR(("tdls_wfd_ie error %d\n", ret)); - } -out: -#endif /* WLTDLS */ - return ret; -} - -static s32 -wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, - u8 *peer, enum nl80211_tdls_operation oper) -{ - s32 ret = 0; -#ifdef WLTDLS - struct bcm_cfg80211 *cfg; - tdls_iovar_t info; - cfg = g_bcm_cfg; - memset(&info, 0, sizeof(tdls_iovar_t)); - if (peer) - memcpy(&info.ea, peer, ETHER_ADDR_LEN); - switch (oper) { - case NL80211_TDLS_DISCOVERY_REQ: - /* turn on TDLS */ - ret = dhd_tdls_enable(dev, true, false, NULL); - if (ret < 0) - return ret; - /* If the discovery request is broadcast then we need to set - * info.mode to Tunneled Probe Request - */ - if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) { - info.mode = TDLS_MANUAL_EP_WFD_TPQ; - } - else { - info.mode = TDLS_MANUAL_EP_DISCOVERY; - } - break; - case NL80211_TDLS_SETUP: - /* auto mode on */ - ret = dhd_tdls_enable(dev, true, true, (struct ether_addr *)peer); - if (ret < 0) - return ret; - break; - case NL80211_TDLS_TEARDOWN: - info.mode = TDLS_MANUAL_EP_DELETE; - /* auto mode off */ - ret = dhd_tdls_enable(dev, true, false, (struct ether_addr *)peer); - if (ret < 0) - return ret; - break; - default: - WL_ERR(("Unsupported operation : %d\n", oper)); - goto out; - } - if (info.mode) { - ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (ret) { - WL_ERR(("tdls_endpoint error %d\n", ret)); - } - } -out: -#endif /* WLTDLS */ - return ret; -} -#endif - -s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, - enum wl_management_type type) -{ - struct bcm_cfg80211 *cfg; - struct net_device *ndev = NULL; - struct ether_addr primary_mac; - s32 ret = 0; - s32 bssidx = 0; - s32 pktflag = 0; - cfg = g_bcm_cfg; - - if (wl_get_drv_status(cfg, AP_CREATING, net)) { - /* Vendor IEs should be set to FW - * after SoftAP interface is brought up - */ - goto exit; - } else if (wl_get_drv_status(cfg, AP_CREATED, net)) { - ndev = net; - bssidx = 0; - } else if (cfg->p2p) { - net = ndev_to_wlc_ndev(net, cfg); - if (!cfg->p2p->on) { - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr, - &cfg->p2p->int_addr); - /* In case of p2p_listen command, supplicant send remain_on_channel - * without turning on P2P - */ - - p2p_on(cfg) = true; - ret = wl_cfgp2p_enable_discovery(cfg, net, NULL, 0); - - if (unlikely(ret)) { - goto exit; - } - } - if (net != bcmcfg_to_prmry_ndev(cfg)) { - if (wl_get_mode_by_netdev(cfg, net) == WL_MODE_AP) { - ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION); - } - } else { - ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - } - } - if (ndev != NULL) { - switch (type) { - case WL_BEACON: - pktflag = VNDR_IE_BEACON_FLAG; - break; - case WL_PROBE_RESP: - pktflag = VNDR_IE_PRBRSP_FLAG; - break; - case WL_ASSOC_RESP: - pktflag = VNDR_IE_ASSOCRSP_FLAG; - break; - } - if (pktflag) - ret = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, pktflag, buf, len); - } -exit: - return ret; -} - -#ifdef WL_SUPPORT_AUTO_CHANNEL -static s32 -wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev) -{ - u32 val = 0; - s32 ret = BCME_ERROR; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - /* Disable mpc, to avoid automatic interface down. */ - val = 0; - - ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, - sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, - &cfg->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("set 'mpc' failed, error = %d\n", ret)); - goto done; - } - - /* Set interface up, explicitly. */ - val = 1; - - ret = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true); - if (ret < 0) { - WL_ERR(("set interface up failed, error = %d\n", ret)); - goto done; - } - - /* Stop all scan explicitly, till auto channel selection complete. */ - wl_set_drv_status(cfg, SCANNING, ndev); - if (cfg->escan_info.ndev == NULL) { - ret = BCME_OK; - goto done; - } - ret = wl_notify_escan_complete(cfg, ndev, true, true); - if (ret < 0) { - WL_ERR(("set scan abort failed, error = %d\n", ret)); - goto done; - } - -done: - return ret; -} - -static bool -wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec) -{ - bool valid = false; - - if (ioctl_version != 1) { - if ((chanspec = wl_chspec_to_legacy(chanspec)) == INVCHANSPEC) { - return valid; - } - } - - /* channel 1 to 14 */ - if ((chanspec >= 0x2b01) && (chanspec <= 0x2b0e)) { - valid = true; - } - /* channel 36 to 48 */ - else if ((chanspec >= 0x1b24) && (chanspec <= 0x1b30)) { - valid = true; - } - /* channel 149 to 161 */ - else if ((chanspec >= 0x1b95) && (chanspec <= 0x1ba1)) { - valid = true; - } - else { - valid = false; - WL_INFO(("invalid P2P chanspec, channel = %d, chanspec = %04x\n", - CHSPEC_CHANNEL(chanspec), chanspec)); - } - - return valid; -} - -static s32 -wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen) -{ - s32 ret = BCME_ERROR; - struct bcm_cfg80211 *cfg = NULL; - chanspec_t chanspec = 0; - - cfg = g_bcm_cfg; - - /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */ - chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 | - WL_CHANSPEC_CTL_SB_NONE); - chanspec = wl_chspec_host_to_driver(chanspec); - - ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, - sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); - } - - return ret; -} - -static s32 -wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen) -{ - u32 channel = 0; - s32 ret = BCME_ERROR; - s32 i = 0; - s32 j = 0; - struct bcm_cfg80211 *cfg = NULL; - wl_uint32_list_t *list = NULL; - chanspec_t chanspec = 0; - - cfg = g_bcm_cfg; - - /* Restrict channels to 5GHz, 20MHz BW, no SB. */ - chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 | - WL_CHANSPEC_CTL_SB_NONE); - chanspec = wl_chspec_host_to_driver(chanspec); - - ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, - sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); - goto done; - } - - list = (wl_uint32_list_t *)buf; - /* Skip DFS and inavlid P2P channel. */ - for (i = 0, j = 0; i < dtoh32(list->count); i++) { - chanspec = (chanspec_t) dtoh32(list->element[i]); - channel = CHSPEC_CHANNEL(chanspec); - - ret = wldev_iovar_getint(ndev, "per_chan_info", &channel); - if (ret < 0) { - WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret)); - goto done; - } - - if (CHANNEL_IS_RADAR(channel) || - !(wl_cfg80211_valid_chanspec_p2p(chanspec))) { - continue; - } else { - list->element[j] = list->element[i]; - } - - j++; - } - - list->count = j; - -done: - return ret; -} - -static s32 -wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen, - int *channel) -{ - s32 ret = BCME_ERROR; - int chosen = 0; - int retry = 0; - - /* Start auto channel selection scan. */ - ret = wldev_ioctl(ndev, WLC_START_CHANNEL_SEL, buf, buflen, true); - if (ret < 0) { - WL_ERR(("can't start auto channel scan, error = %d\n", ret)); - *channel = 0; - goto done; - } - - /* Wait for auto channel selection, worst case possible delay is 5250ms. */ - retry = CHAN_SEL_RETRY_COUNT; - - while (retry--) { - OSL_SLEEP(CHAN_SEL_IOCTL_DELAY); - chosen = 0; - ret = wldev_ioctl(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), - false); - if ((ret == 0) && (dtoh32(chosen) != 0)) { - *channel = (u16)(chosen & 0x00FF); - WL_INFO(("selected channel = %d\n", *channel)); - break; - } - WL_INFO(("attempt = %d, ret = %d, chosen = %d\n", - (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen))); - } - - if (retry <= 0) { - WL_ERR(("failure, auto channel selection timed out\n")); - *channel = 0; - ret = BCME_ERROR; - } - -done: - return ret; -} - -static s32 -wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev) -{ - u32 val = 0; - s32 ret = BCME_ERROR; - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - /* Clear scan stop driver status. */ - wl_clr_drv_status(cfg, SCANNING, ndev); - - /* Enable mpc back to 1, irrespective of initial state. */ - val = 1; - - ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, - sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, - &cfg->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("set 'mpc' failed, error = %d\n", ret)); - } - - return ret; -} - -s32 -wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len) -{ - int channel = 0; - s32 ret = BCME_ERROR; - u8 *buf = NULL; - char *pos = cmd; - struct bcm_cfg80211 *cfg = NULL; - struct net_device *ndev = NULL; - - memset(cmd, 0, total_len); - - buf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL); - if (buf == NULL) { - WL_ERR(("failed to allocate chanspec buffer\n")); - return -ENOMEM; - } - - /* - * Always use primary interface, irrespective of interface on which - * command came. - */ - cfg = g_bcm_cfg; - ndev = bcmcfg_to_prmry_ndev(cfg); - - /* - * Make sure that FW and driver are in right state to do auto channel - * selection scan. - */ - ret = wl_cfg80211_set_auto_channel_scan_state(ndev); - if (ret < 0) { - WL_ERR(("can't set auto channel scan state, error = %d\n", ret)); - goto done; - } - - /* Best channel selection in 2.4GHz band. */ - ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); - if (ret < 0) { - WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret)); - goto done; - } - - ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, - &channel); - if (ret < 0) { - WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret)); - goto done; - } - - if (CHANNEL_IS_2G(channel)) { - channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); - } else { - WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel)); - channel = 0; - } - - sprintf(pos, "%04d ", channel); - pos += 5; - - /* Best channel selection in 5GHz band. */ - ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); - if (ret < 0) { - WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret)); - goto done; - } - - ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, - &channel); - if (ret < 0) { - WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret)); - goto done; - } - - if (CHANNEL_IS_5G(channel)) { - channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); - } else { - WL_ERR(("invalid 5GHz channel, channel = %d\n", channel)); - channel = 0; - } - - sprintf(pos, "%04d ", channel); - pos += 5; - - /* Set overall best channel same as 5GHz best channel. */ - sprintf(pos, "%04d ", channel); - pos += 5; - -done: - if (NULL != buf) { - kfree(buf); - } - - /* Restore FW and driver back to normal state. */ - ret = wl_cfg80211_restore_auto_channel_scan_state(ndev); - if (ret < 0) { - WL_ERR(("can't restore auto channel scan state, error = %d\n", ret)); - } - - return (pos - cmd); -} -#endif /* WL_SUPPORT_AUTO_CHANNEL */ - -static const struct rfkill_ops wl_rfkill_ops = { - .set_block = wl_rfkill_set -}; - -static int wl_rfkill_set(void *data, bool blocked) -{ - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; - - WL_DBG(("Enter \n")); - WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked")); - - if (!cfg) - return -EINVAL; - - cfg->rf_blocked = blocked; - - return 0; -} - -static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup) -{ - s32 err = 0; - - WL_DBG(("Enter \n")); - if (!cfg) - return -EINVAL; - if (setup) { - cfg->rfkill = rfkill_alloc("brcmfmac-wifi", - wl_cfg80211_get_parent_dev(), - RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg); - - if (!cfg->rfkill) { - err = -ENOMEM; - goto err_out; - } - - err = rfkill_register(cfg->rfkill); - - if (err) - rfkill_destroy(cfg->rfkill); - } else { - if (!cfg->rfkill) { - err = -ENOMEM; - goto err_out; - } - - rfkill_unregister(cfg->rfkill); - rfkill_destroy(cfg->rfkill); - } - -err_out: - return err; -} - -#ifdef DEBUGFS_CFG80211 -/** -* Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level -* to turn on SCAN and DBG log. -* To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level -* To see current setting of debug level, -* cat /sys/kernel/debug/dhd/debug_level -*/ -static ssize_t -wl_debuglevel_write(struct file *file, const char __user *userbuf, - size_t count, loff_t *ppos) -{ - char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL]; - char *params, *token, *colon; - uint i, tokens, log_on = 0; - memset(tbuf, 0, sizeof(tbuf)); - memset(sublog, 0, sizeof(sublog)); - if (copy_from_user(&tbuf, userbuf, min_t(size_t, sizeof(tbuf), count))) - return -EFAULT; - - params = &tbuf[0]; - colon = strchr(params, '\n'); - if (colon != NULL) - *colon = '\0'; - while ((token = strsep(¶ms, " ")) != NULL) { - memset(sublog, 0, sizeof(sublog)); - if (token == NULL || !*token) - break; - if (*token == '\0') - continue; - colon = strchr(token, ':'); - if (colon != NULL) { - *colon = ' '; - } - tokens = sscanf(token, "%s %u", sublog, &log_on); - if (colon != NULL) - *colon = ':'; - - if (tokens == 2) { - for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { - if (!strncmp(sublog, sublogname_map[i].sublogname, - strlen(sublogname_map[i].sublogname))) { - if (log_on) - wl_dbg_level |= - (sublogname_map[i].log_level); - else - wl_dbg_level &= - ~(sublogname_map[i].log_level); - } - } - } else - WL_ERR(("%s: can't parse '%s' as a " - "SUBMODULE:LEVEL (%d tokens)\n", - tbuf, token, tokens)); - - - } - return count; -} - -static ssize_t -wl_debuglevel_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - char *param; - char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)]; - uint i; - memset(tbuf, 0, sizeof(tbuf)); - param = &tbuf[0]; - for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { - param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ", - sublogname_map[i].sublogname, - (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0); - } - *param = '\n'; - return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0])); - -} -static const struct file_operations fops_debuglevel = { - .open = NULL, - .write = wl_debuglevel_write, - .read = wl_debuglevel_read, - .owner = THIS_MODULE, - .llseek = NULL, -}; - -static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg) -{ - s32 err = 0; - struct dentry *_dentry; - if (!cfg) - return -EINVAL; - cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!cfg->debugfs || IS_ERR(cfg->debugfs)) { - if (cfg->debugfs == ERR_PTR(-ENODEV)) - WL_ERR(("Debugfs is not enabled on this kernel\n")); - else - WL_ERR(("Can not create debugfs directory\n")); - cfg->debugfs = NULL; - goto exit; - - } - _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR, - cfg->debugfs, cfg, &fops_debuglevel); - if (!_dentry || IS_ERR(_dentry)) { - WL_ERR(("failed to create debug_level debug file\n")); - wl_free_debugfs(cfg); - } -exit: - return err; -} -static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg) -{ - if (!cfg) - return -EINVAL; - if (cfg->debugfs) - debugfs_remove_recursive(cfg->debugfs); - cfg->debugfs = NULL; - return 0; -} -#endif /* DEBUGFS_CFG80211 */ - -struct device *wl_cfg80211_get_parent_dev(void) -{ - return cfg80211_parent_dev; -} - -void wl_cfg80211_set_parent_dev(void *dev) -{ - cfg80211_parent_dev = dev; -} - -static void wl_cfg80211_clear_parent_dev(void) -{ - cfg80211_parent_dev = NULL; -} - -void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac) -{ - wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr", NULL, - 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync); - memcpy(mac->octet, cfg->ioctl_buf, ETHER_ADDR_LEN); -} -static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role) -{ - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - if (((dev_role == NL80211_IFTYPE_AP) && - !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) || - ((dev_role == NL80211_IFTYPE_P2P_GO) && - !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE))) - { - WL_ERR(("device role select failed\n")); - return false; - } - return true; -} - -int wl_cfg80211_do_driver_init(struct net_device *net) -{ - struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net); - - if (!cfg || !cfg->wdev) - return -EINVAL; - - if (dhd_do_driver_init(cfg->wdev->netdev) < 0) - return -1; - - return 0; -} - -void wl_cfg80211_enable_trace(bool set, u32 level) -{ - if (set) - wl_dbg_level = level & WL_DBG_LEVEL; - else - wl_dbg_level |= (WL_DBG_LEVEL & level); -} -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ - 2, 0)) -static s32 -wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, - bcm_struct_cfgdev *cfgdev, u64 cookie) -{ - /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION - * is passed with CMD_FRAME. This callback is supposed to cancel - * the OFFCHANNEL Wait. Since we are already taking care of that - * with the tx_mgmt logic, do nothing here. - */ - - return 0; -} -#endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */ - -#ifdef WL11U -bcm_tlv_t * -wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) { - return (bcm_tlv_t *)ie; - } - return NULL; -} - - -static s32 -wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, - uint8 ie_id, uint8 *data, uint8 data_len) -{ - s32 err = BCME_OK; - s32 buf_len; - s32 iecount; - ie_setbuf_t *ie_setbuf; - - if (ie_id != DOT11_MNG_INTERWORKING_ID) - return BCME_UNSUPPORTED; - - /* access network options (1 octet) is the mandatory field */ - if (!data || data_len == 0 || data_len > IW_IES_MAX_BUF_LEN) { - WL_ERR(("wrong interworking IE (len=%d)\n", data_len)); - return BCME_BADARG; - } - - /* Validate the pktflag parameter */ - if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | - VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | - VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| - VNDR_IE_CUSTOM_FLAG))) { - WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag)); - return -1; - } - - /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ - pktflag = htod32(pktflag); - - buf_len = sizeof(ie_setbuf_t) + data_len - 1; - ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); - - if (!ie_setbuf) { - WL_ERR(("Error allocating buffer for IE\n")); - return -ENOMEM; - } - - if (cfg->iw_ie_len == data_len && !memcmp(cfg->iw_ie, data, data_len)) { - WL_ERR(("Previous IW IE is equals to current IE\n")); - err = BCME_OK; - goto exit; - } - - strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); - ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - - /* Buffer contains only 1 IE */ - iecount = htod32(1); - memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); - memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); - - /* Now, add the IE to the buffer */ - ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; - - /* if already set with previous values, delete it first */ - if (cfg->iw_ie_len != 0) { - WL_DBG(("Different IW_IE was already set. clear first\n")); - - ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; - - err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - if (err != BCME_OK) - goto exit; - } - - ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; - memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); - - err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - if (err == BCME_OK) { - memcpy(cfg->iw_ie, data, data_len); - cfg->iw_ie_len = data_len; - cfg->wl11u = TRUE; - - err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); - } - -exit: - if (ie_setbuf) - kfree(ie_setbuf); - return err; -} -#endif /* WL11U */ - - - -int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev) -{ - struct bcm_cfg80211 *cfg = NULL; - struct net_device *ndev = NULL; - unsigned long flags; - int clear_flag = 0; - int ret = 0; - - WL_TRACE(("Enter\n")); - - cfg = g_bcm_cfg; - if (!cfg) - return -EINVAL; - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); -#ifdef WL_CFG80211_P2P_DEV_IF - if (cfg->scan_request && cfg->scan_request->wdev == cfgdev) { -#else - if (cfg->scan_request && cfg->scan_request->dev == cfgdev) { -#endif - cfg80211_scan_done(cfg->scan_request, true); - cfg->scan_request = NULL; - clear_flag = 1; - } - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); - - if (clear_flag) - wl_clr_drv_status(cfg, SCANNING, ndev); - - return ret; -} - -bool wl_cfg80211_is_vsdb_mode(void) -{ - return (g_bcm_cfg && g_bcm_cfg->vsdb_mode); -} - -void* wl_cfg80211_get_dhdp() -{ - struct bcm_cfg80211 *cfg = g_bcm_cfg; - - return cfg->pub; -} - -bool wl_cfg80211_is_p2p_active(void) -{ - return (g_bcm_cfg && g_bcm_cfg->p2p); -} - -static void wl_cfg80211_work_handler(struct work_struct * work) -{ - struct bcm_cfg80211 *cfg = NULL; - struct net_info *iter, *next; - s32 err = BCME_OK; - s32 pm = PM_FAST; - - cfg = container_of(work, struct bcm_cfg80211, pm_enable_work.work); - WL_DBG(("Enter \n")); - if (cfg->pm_enable_work_on) { - cfg->pm_enable_work_on = false; - for_each_ndev(cfg, iter, next) { - if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) || - (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS)) - continue; - if (iter->ndev) { - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, - &pm, sizeof(pm), true)) != 0) { - if (err == -ENODEV) - WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); - else - WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); - } else - wl_cfg80211_update_power_mode(iter->ndev); - } - } - } -} - -u8 -wl_get_action_category(void *frame, u32 frame_len) -{ - u8 category; - u8 *ptr = (u8 *)frame; - if (frame == NULL) - return DOT11_ACTION_CAT_ERR_MASK; - if (frame_len < DOT11_ACTION_HDR_LEN) - return DOT11_ACTION_CAT_ERR_MASK; - category = ptr[DOT11_ACTION_CAT_OFF]; - WL_INFO(("Action Category: %d\n", category)); - return category; -} - -int -wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action) -{ - u8 *ptr = (u8 *)frame; - if (frame == NULL || ret_action == NULL) - return BCME_ERROR; - if (frame_len < DOT11_ACTION_HDR_LEN) - return BCME_ERROR; - if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len)) - return BCME_ERROR; - *ret_action = ptr[DOT11_ACTION_ACT_OFF]; - WL_INFO(("Public Action : %d\n", *ret_action)); - return BCME_OK; -} - -static int -wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev, - const struct ether_addr *bssid) -{ - s32 err; - wl_event_msg_t e; - - bzero(&e, sizeof(e)); - e.event_type = cpu_to_be32(WLC_E_ROAM); - memcpy(&e.addr, bssid, ETHER_ADDR_LEN); - /* trigger the roam event handler */ - err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL); - - return err; -} - -#ifdef WLFBT -void -wl_cfg80211_get_fbt_key(uint8 *key) -{ - memcpy(key, g_bcm_cfg->fbt_key, FBT_KEYLEN); -} -#endif /* WLFBT */ - -#ifdef WL_CFG80211_ACL -static int -wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, - const struct cfg80211_acl_data *acl) -{ - int i; - int ret = 0; - int macnum = 0; - int macmode = MACLIST_MODE_DISABLED; - struct maclist *list; - - /* get the MAC filter mode */ - if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) { - macmode = MACLIST_MODE_ALLOW; - } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED && - acl->n_acl_entries) { - macmode = MACLIST_MODE_DENY; - } - - /* if acl == NULL, macmode is still disabled.. */ - if (macmode == MACLIST_MODE_DISABLED) { - if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0) - WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); - - return ret; - } - - macnum = acl->n_acl_entries; - if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { - WL_ERR(("%s : invalid number of MAC address entries %d\n", - __FUNCTION__, macnum)); - return -1; - } - - /* allocate memory for the MAC list */ - list = (struct maclist*)kmalloc(sizeof(int) + - sizeof(struct ether_addr) * macnum, GFP_KERNEL); - if (!list) { - WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__)); - return -1; - } - - /* prepare the MAC list */ - list->count = htod32(macnum); - for (i = 0; i < macnum; i++) { - memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN); - } - /* set the list */ - if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0) - WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); - - kfree(list); - - return ret; -} -#endif /* WL_CFG80211_ACL */ - -#ifdef WL_NAN -int -wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd, int cmd_len) -{ - return wl_cfgnan_cmd_handler(ndev, g_bcm_cfg, cmd, cmd_len); -} -#endif /* WL_NAN */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h deleted file mode 100755 index 08a8c258e0f1..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * Linux cfg80211 driver - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.h 751081 2018-03-09 08:06:41Z $ - */ - -#ifndef _wl_cfg80211_h_ -#define _wl_cfg80211_h_ - -#include -#include -#include -#include -#include -#include -#include - -#include - -struct wl_conf; -struct wl_iface; -struct bcm_cfg80211; -struct wl_security; -struct wl_ibss; - - -#define htod32(i) (i) -#define htod16(i) (i) -#define dtoh64(i) (i) -#define dtoh32(i) (i) -#define dtoh16(i) (i) -#define htodchanspec(i) (i) -#define dtohchanspec(i) (i) - -#define WL_DBG_NONE 0 -#define WL_DBG_P2P_ACTION (1 << 5) -#define WL_DBG_TRACE (1 << 4) -#define WL_DBG_SCAN (1 << 3) -#define WL_DBG_DBG (1 << 2) -#define WL_DBG_INFO (1 << 1) -#define WL_DBG_ERR (1 << 0) - -/* 0 invalidates all debug messages. default is 1 */ -#define WL_DBG_LEVEL 0xFF - -#define CFG80211_ERROR_TEXT "CFG80211-ERROR) " - -#if defined(DHD_DEBUG) -#define WL_ERR(args) \ -do { \ - if (wl_dbg_level & WL_DBG_ERR) { \ - printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ - printk args; \ - } \ -} while (0) -#else /* defined(DHD_DEBUG) */ -#define WL_ERR(args) \ -do { \ - if ((wl_dbg_level & WL_DBG_ERR) && net_ratelimit()) { \ - printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ - printk args; \ - } \ -} while (0) -#endif /* defined(DHD_DEBUG) */ - -#ifdef WL_INFO -#undef WL_INFO -#endif -#define WL_INFO(args) \ -do { \ - if (wl_dbg_level & WL_DBG_INFO) { \ - printk(KERN_INFO "CFG80211-INFO) %s : ", __func__); \ - printk args; \ - } \ -} while (0) -#ifdef WL_SCAN -#undef WL_SCAN -#endif -#define WL_SCAN(args) \ -do { \ - if (wl_dbg_level & WL_DBG_SCAN) { \ - printk(KERN_INFO "CFG80211-SCAN) %s :", __func__); \ - printk args; \ - } \ -} while (0) -#ifdef WL_TRACE -#undef WL_TRACE -#endif -#define WL_TRACE(args) \ -do { \ - if (wl_dbg_level & WL_DBG_TRACE) { \ - printk(KERN_INFO "CFG80211-TRACE) %s :", __func__); \ - printk args; \ - } \ -} while (0) -#ifdef WL_TRACE_HW4 -#undef WL_TRACE_HW4 -#endif -#define WL_TRACE_HW4 WL_TRACE -#if (WL_DBG_LEVEL > 0) -#define WL_DBG(args) \ -do { \ - if (wl_dbg_level & WL_DBG_DBG) { \ - printk(KERN_DEBUG "CFG80211-DEBUG) %s :", __func__); \ - printk args; \ - } \ -} while (0) -#else /* !(WL_DBG_LEVEL > 0) */ -#define WL_DBG(args) -#endif /* (WL_DBG_LEVEL > 0) */ -#define WL_PNO(x) -#define WL_SD(x) - - -#define WL_SCAN_RETRY_MAX 3 -#define WL_NUM_PMKIDS_MAX MAXPMKID -#define WL_SCAN_BUF_MAX (1024 * 8) -#define WL_TLV_INFO_MAX 1500 -#define WL_SCAN_IE_LEN_MAX 2048 -#define WL_BSS_INFO_MAX 2048 -#define WL_ASSOC_INFO_MAX 512 -#define WL_IOCTL_LEN_MAX 2048 -#define WL_EXTRA_BUF_MAX 2048 -#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) -#define WL_AP_MAX 256 -#define WL_FILE_NAME_MAX 256 -#define WL_DWELL_TIME 200 -#define WL_MED_DWELL_TIME 400 -#define WL_MIN_DWELL_TIME 100 -#define WL_LONG_DWELL_TIME 1000 -#define IFACE_MAX_CNT 2 -#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 -#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 -#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 -#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 -#define WL_AF_TX_MAX_RETRY 5 - -#define WL_AF_SEARCH_TIME_MAX 450 -#define WL_AF_TX_EXTRA_TIME_MAX 200 - -#define WL_SCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */ -#define WL_CHANNEL_SYNC_RETRY 5 -#define WL_INVALID -1 - -#ifdef DHD_LOSSLESS_ROAMING -#define WL_ROAM_TIMEOUT_MS 1000 /* Roam timeout */ -#endif /* DHD_LOSSLESS_ROAMING */ - -/* Bring down SCB Timeout to 20secs from 60secs default */ -#ifndef WL_SCB_TIMEOUT -#define WL_SCB_TIMEOUT 20 -#endif - -/* SCAN_SUPPRESS timer values in ms */ -#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */ -#define WL_SCAN_SUPPRESS_RETRY 3000 - -#define WL_PM_ENABLE_TIMEOUT 10000 - -#ifdef WLAIBSS -/* Custom AIBSS beacon parameters */ -#define AIBSS_INITIAL_MIN_BCN_DUR 500 -#define AIBSS_MIN_BCN_DUR 5000 -#define AIBSS_BCN_FLOOD_DUR 5000 -#endif /* WLAIBSS */ - -/* driver status */ -enum wl_status { - WL_STATUS_READY = 0, - WL_STATUS_SCANNING, - WL_STATUS_SCAN_ABORTING, - WL_STATUS_CONNECTING, - WL_STATUS_CONNECTED, - WL_STATUS_DISCONNECTING, - WL_STATUS_AP_CREATING, - WL_STATUS_AP_CREATED, - /* whole sending action frame procedure: - * includes a) 'finding common channel' for public action request frame - * and b) 'sending af via 'actframe' iovar' - */ - WL_STATUS_SENDING_ACT_FRM, - /* find a peer to go to a common channel before sending public action req frame */ - WL_STATUS_FINDING_COMMON_CHANNEL, - /* waiting for next af to sync time of supplicant. - * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN - */ - WL_STATUS_WAITING_NEXT_ACT_FRM, -#ifdef WL_CFG80211_SYNC_GON - /* go to listen state to wait for next af after SENDING_ACT_FRM */ - WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN, -#endif /* WL_CFG80211_SYNC_GON */ - /* it will be set when upper layer requests listen and succeed in setting listen mode. - * if set, other scan request can abort current listen state - */ - WL_STATUS_REMAINING_ON_CHANNEL, -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - /* it's fake listen state to keep current scan state. - * it will be set when upper layer requests listen but scan is running. then just run - * a expire timer without actual listen state. - * if set, other scan request does not need to abort scan. - */ - WL_STATUS_FAKE_REMAINING_ON_CHANNEL -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -}; - -/* wi-fi mode */ -enum wl_mode { - WL_MODE_BSS, - WL_MODE_IBSS, - WL_MODE_AP -}; - -/* driver profile list */ -enum wl_prof_list { - WL_PROF_MODE, - WL_PROF_SSID, - WL_PROF_SEC, - WL_PROF_IBSS, - WL_PROF_BAND, - WL_PROF_CHAN, - WL_PROF_BSSID, - WL_PROF_ACT, - WL_PROF_BEACONINT, - WL_PROF_DTIMPERIOD -}; - -/* donlge escan state */ -enum wl_escan_state { - WL_ESCAN_STATE_IDLE, - WL_ESCAN_STATE_SCANING -}; -/* fw downloading status */ -enum wl_fw_status { - WL_FW_LOADING_DONE, - WL_NVRAM_LOADING_DONE -}; - -enum wl_management_type { - WL_BEACON = 0x1, - WL_PROBE_RESP = 0x2, - WL_ASSOC_RESP = 0x4 -}; - -enum wl_handler_del_type { - WL_HANDLER_NOTUSE, - WL_HANDLER_DEL, - WL_HANDLER_MAINTAIN, - WL_HANDLER_PEND -}; - -/* beacon / probe_response */ -struct beacon_proberesp { - __le64 timestamp; - __le16 beacon_int; - __le16 capab_info; - u8 variable[0]; -} __attribute__ ((packed)); - -/* driver configuration */ -struct wl_conf { - u32 frag_threshold; - u32 rts_threshold; - u32 retry_short; - u32 retry_long; - s32 tx_power; - struct ieee80211_channel channel; -}; - -typedef s32(*EVENT_HANDLER) (struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); - -/* bss inform structure for cfg80211 interface */ -struct wl_cfg80211_bss_info { - u16 band; - u16 channel; - s16 rssi; - u16 frame_len; - u8 frame_buf[1]; -}; - -/* basic structure of scan request */ -struct wl_scan_req { - struct wlc_ssid ssid; -}; - -/* basic structure of information element */ -struct wl_ie { - u16 offset; - u8 buf[WL_TLV_INFO_MAX]; -}; - -/* event queue for cfg80211 main event */ -struct wl_event_q { - struct list_head eq_list; - u32 etype; - wl_event_msg_t emsg; - s8 edata[1]; -}; - -/* security information with currently associated ap */ -struct wl_security { - u32 wpa_versions; - u32 auth_type; - u32 cipher_pairwise; - u32 cipher_group; - u32 wpa_auth; - u32 auth_assoc_res_status; -}; - -/* ibss information for currently joined ibss network */ -struct wl_ibss { - u8 beacon_interval; /* in millisecond */ - u8 atim; /* in millisecond */ - s8 join_only; - u8 band; - u8 channel; -}; - -/* cfg driver profile */ -struct wl_profile { - u32 mode; - s32 band; - u32 channel; - struct wlc_ssid ssid; - struct wl_security sec; - struct wl_ibss ibss; - u8 bssid[ETHER_ADDR_LEN]; - u16 beacon_interval; - u8 dtim_period; - bool active; -}; - -struct net_info { - struct net_device *ndev; - struct wireless_dev *wdev; - struct wl_profile profile; - s32 mode; - s32 roam_off; - unsigned long sme_state; - bool pm_restore; - bool pm_block; - s32 pm; - struct list_head list; /* list of all net_info structure */ -}; - -/* association inform */ -#define MAX_REQ_LINE 1024u -struct wl_connect_info { - u8 req_ie[MAX_REQ_LINE]; - u32 req_ie_len; - u8 resp_ie[MAX_REQ_LINE]; - u32 resp_ie_len; -}; - -/* firmware /nvram downloading controller */ -struct wl_fw_ctrl { - const struct firmware *fw_entry; - unsigned long status; - u32 ptr; - s8 fw_name[WL_FILE_NAME_MAX]; - s8 nvram_name[WL_FILE_NAME_MAX]; -}; - -/* assoc ie length */ -struct wl_assoc_ielen { - u32 req_len; - u32 resp_len; -}; - -/* wpa2 pmk list */ -struct wl_pmk_list { - pmkid_list_t pmkids; - pmkid_t foo[MAXPMKID - 1]; -}; - - -#define ESCAN_BUF_SIZE (64 * 1024) - -struct escan_info { - u32 escan_state; -#if defined(STATIC_WL_PRIV_STRUCT) -#ifndef CONFIG_DHD_USE_STATIC_BUF -#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - u8 *escan_buf; -#else - u8 escan_buf[ESCAN_BUF_SIZE]; -#endif /* STATIC_WL_PRIV_STRUCT */ - struct wiphy *wiphy; - struct net_device *ndev; -}; - -struct ap_info { -/* Structure to hold WPS, WPA IEs for a AP */ - u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN]; - u8 beacon_ie[VNDR_IES_MAX_BUF_LEN]; - u8 assoc_res_ie[VNDR_IES_MAX_BUF_LEN]; - u32 probe_res_ie_len; - u32 beacon_ie_len; - u32 assoc_res_ie_len; - u8 *wpa_ie; - u8 *rsn_ie; - u8 *wps_ie; - bool security_mode; -}; - -struct sta_info { - /* Structure to hold WPS IE for a STA */ - u8 probe_req_ie[VNDR_IES_BUF_LEN]; - u8 assoc_req_ie[VNDR_IES_BUF_LEN]; - u32 probe_req_ie_len; - u32 assoc_req_ie_len; -}; - -struct afx_hdl { - wl_af_params_t *pending_tx_act_frm; - struct ether_addr tx_dst_addr; - struct net_device *dev; - struct work_struct work; - u32 bssidx; - u32 retry; - s32 peer_chan; - s32 peer_listen_chan; /* search channel: configured by upper layer */ - s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */ - bool is_listen; - bool ack_recv; - bool is_active; -}; - -struct parsed_ies { - wpa_ie_fixed_t *wps_ie; - u32 wps_ie_len; - wpa_ie_fixed_t *wpa_ie; - u32 wpa_ie_len; - bcm_tlv_t *wpa2_ie; - u32 wpa2_ie_len; -}; - - -#ifdef WL11U -/* Max length of Interworking element */ -#define IW_IES_MAX_BUF_LEN 9 -#endif -#ifdef WLFBT -#define FBT_KEYLEN 32 -#endif -#define MAX_EVENT_BUF_NUM 16 -typedef struct wl_eventmsg_buf { - u16 num; - struct { - u16 type; - bool set; - } event [MAX_EVENT_BUF_NUM]; -} wl_eventmsg_buf_t; - -typedef struct wl_if_event_info { - bool valid; - int ifidx; - int bssidx; - uint8 mac[ETHER_ADDR_LEN]; - char name[IFNAMSIZ+1]; -} wl_if_event_info; - -/* private data of cfg80211 interface */ -struct bcm_cfg80211 { - struct wireless_dev *wdev; /* representing cfg cfg80211 device */ - - struct wireless_dev *p2p_wdev; /* representing cfg cfg80211 device for P2P */ - struct net_device *p2p_net; /* reference to p2p0 interface */ - - struct wl_conf *conf; - struct cfg80211_scan_request *scan_request; /* scan request object */ - EVENT_HANDLER evt_handler[WLC_E_LAST]; - struct list_head eq_list; /* used for event queue */ - struct list_head net_list; /* used for struct net_info */ - spinlock_t eq_lock; /* for event queue synchronization */ - spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ - struct completion act_frm_scan; - struct completion iface_disable; - struct completion wait_next_af; - struct mutex usr_sync; /* maily for up/down synchronization */ - struct wl_scan_results *bss_list; - struct wl_scan_results *scan_results; - - /* scan request object for internal purpose */ - struct wl_scan_req *scan_req_int; - /* information element object for internal purpose */ -#if defined(STATIC_WL_PRIV_STRUCT) - struct wl_ie *ie; -#else - struct wl_ie ie; -#endif - - /* association information container */ -#if defined(STATIC_WL_PRIV_STRUCT) - struct wl_connect_info *conn_info; -#else - struct wl_connect_info conn_info; -#endif -#ifdef DEBUGFS_CFG80211 - struct dentry *debugfs; -#endif /* DEBUGFS_CFG80211 */ - struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ - tsk_ctl_t event_tsk; /* task of main event handler thread */ - void *pub; - u32 iface_cnt; - u32 channel; /* current channel */ - u32 af_sent_channel; /* channel action frame is sent */ - /* next af subtype to cancel the remained dwell time in rx process */ - u8 next_af_subtype; -#ifdef WL_CFG80211_SYNC_GON - ulong af_tx_sent_jiffies; -#endif /* WL_CFG80211_SYNC_GON */ - struct escan_info escan_info; /* escan information */ - bool active_scan; /* current scan mode */ - bool ibss_starter; /* indicates this sta is ibss starter */ - bool link_up; /* link/connection up flag */ - - /* indicate whether chip to support power save mode */ - bool pwr_save; - bool roam_on; /* on/off switch for self-roaming */ - bool scan_tried; /* indicates if first scan attempted */ - bool wlfc_on; - bool vsdb_mode; - bool roamoff_on_concurrent; - u8 *ioctl_buf; /* ioctl buffer */ - struct mutex ioctl_buf_sync; - u8 *escan_ioctl_buf; - u8 *extra_buf; /* maily to grab assoc information */ - struct dentry *debugfsdir; - struct rfkill *rfkill; - bool rf_blocked; - struct ieee80211_channel remain_on_chan; - enum nl80211_channel_type remain_on_chan_type; - u64 send_action_id; - u64 last_roc_id; - wait_queue_head_t netif_change_event; - wl_if_event_info if_event_info; - struct completion send_af_done; - struct afx_hdl *afx_hdl; - struct ap_info *ap_info; - struct sta_info *sta_info; - struct p2p_info *p2p; - bool p2p_supported; - void *btcoex_info; - struct timer_list scan_timeout; /* Timer for catch scan event timeout */ - s32(*state_notifier) (struct bcm_cfg80211 *cfg, - struct net_info *_net_info, enum wl_status state, bool set); - unsigned long interrested_state; - wlc_ssid_t hostapd_ssid; -#ifdef WL11U - bool wl11u; - u8 iw_ie[IW_IES_MAX_BUF_LEN]; - u32 iw_ie_len; -#endif /* WL11U */ - bool sched_scan_running; /* scheduled scan req status */ -#ifdef WL_SCHED_SCAN - struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ -#endif /* WL_SCHED_SCAN */ - bool scan_suppressed; - struct timer_list scan_supp_timer; - struct work_struct wlan_work; - struct mutex event_sync; /* maily for up/down synchronization */ - bool disable_roam_event; - bool pm_enable_work_on; - struct delayed_work pm_enable_work; - vndr_ie_setbuf_t *ibss_vsie; /* keep the VSIE for IBSS */ - int ibss_vsie_len; -#ifdef WLAIBSS - u32 aibss_txfail_pid; - u32 aibss_txfail_seq; -#endif /* WLAIBSS */ - u32 rmc_event_pid; - u32 rmc_event_seq; - bool roam_offload; -#ifdef WLFBT - uint8 fbt_key[FBT_KEYLEN]; -#endif - bool nan_enable; -#ifdef WLTDLS - u8 *tdls_mgmt_frame; - u32 tdls_mgmt_frame_len; - s32 tdls_mgmt_freq; -#endif /* WLTDLS */ - bool nan_running; - bool need_wait_afrx; -#ifdef DHD_LOSSLESS_ROAMING - struct timer_list roam_timeout; -#endif /* DHD_LOSSLESS_ROAMING */ -}; - - -static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) -{ - return bss = bss ? - (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; -} -static inline s32 -wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev, - struct wireless_dev * wdev, s32 mode, bool pm_block) -{ - struct net_info *_net_info; - s32 err = 0; - if (cfg->iface_cnt == IFACE_MAX_CNT) - return -ENOMEM; - _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL); - if (!_net_info) - err = -ENOMEM; - else { - _net_info->mode = mode; - _net_info->ndev = ndev; - _net_info->wdev = wdev; - _net_info->pm_restore = 0; - _net_info->pm = 0; - _net_info->pm_block = pm_block; - _net_info->roam_off = WL_INVALID; - cfg->iface_cnt++; - list_add(&_net_info->list, &cfg->net_list); - } - return err; -} -static inline void -wl_dealloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) { - list_del(&_net_info->list); - cfg->iface_cnt--; - kfree(_net_info); - } - } - -} -static inline void -wl_delete_all_netinfo(struct bcm_cfg80211 *cfg) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - list_del(&_net_info->list); - if (_net_info->wdev) - kfree(_net_info->wdev); - kfree(_net_info); - } - cfg->iface_cnt = 0; -} -static inline u32 -wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status) - -{ - struct net_info *_net_info, *next; - u32 cnt = 0; - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (_net_info->ndev && - test_bit(status, &_net_info->sme_state)) - cnt++; - } - return cnt; -} -static inline void -wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op) -{ - struct net_info *_net_info, *next; - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - switch (op) { - case 1: - return; /* set all status is not allowed */ - case 2: - clear_bit(status, &_net_info->sme_state); - if (cfg->state_notifier && - test_bit(status, &(cfg->interrested_state))) - cfg->state_notifier(cfg, _net_info, status, false); - break; - case 4: - return; /* change all status is not allowed */ - default: - return; /* unknown operation */ - } - } -} -static inline void -wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, - struct net_device *ndev, u32 op) -{ - - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) { - switch (op) { - case 1: - set_bit(status, &_net_info->sme_state); - if (cfg->state_notifier && - test_bit(status, &(cfg->interrested_state))) - cfg->state_notifier(cfg, _net_info, status, true); - break; - case 2: - clear_bit(status, &_net_info->sme_state); - if (cfg->state_notifier && - test_bit(status, &(cfg->interrested_state))) - cfg->state_notifier(cfg, _net_info, status, false); - break; - case 4: - change_bit(status, &_net_info->sme_state); - break; - } - } - - } - -} - -static inline u32 -wl_get_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, - struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - return test_bit(status, &_net_info->sme_state); - } - return 0; -} - -static inline s32 -wl_get_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - return _net_info->mode; - } - return -1; -} - - -static inline void -wl_set_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev, - s32 mode) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - _net_info->mode = mode; - } -} -static inline struct wl_profile * -wl_get_profile_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - return &_net_info->profile; - } - return NULL; -} -static inline struct net_info * -wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - struct net_info *_net_info, *next; - - list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { - if (ndev && (_net_info->ndev == ndev)) - return _net_info; - } - return NULL; -} -#define bcmcfg_to_wiphy(cfg) (cfg->wdev->wiphy) -#define bcmcfg_to_prmry_ndev(cfg) (cfg->wdev->netdev) -#define bcmcfg_to_prmry_wdev(cfg) (cfg->wdev) -#define bcmcfg_to_p2p_wdev(cfg) (cfg->p2p_wdev) -#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) -#define ndev_to_wdev(ndev) (ndev->ieee80211_ptr) -#define wdev_to_ndev(wdev) (wdev->netdev) - -#if defined(WL_ENABLE_P2P_IF) -#define ndev_to_wlc_ndev(ndev, cfg) ((ndev == cfg->p2p_net) ? \ - bcmcfg_to_prmry_ndev(cfg) : ndev) -#else -#define ndev_to_wlc_ndev(ndev, cfg) (ndev) -#endif /* WL_ENABLE_P2P_IF */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -#define wdev_to_wlc_ndev(wdev, cfg) \ - ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) ? \ - bcmcfg_to_prmry_ndev(cfg) : wdev_to_ndev(wdev)) -#define cfgdev_to_wlc_ndev(cfgdev, cfg) wdev_to_wlc_ndev(cfgdev, cfg) -#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_wdev(cfg) -#elif defined(WL_ENABLE_P2P_IF) -#define cfgdev_to_wlc_ndev(cfgdev, cfg) ndev_to_wlc_ndev(cfgdev, cfg) -#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_ndev(cfg) -#else -#define cfgdev_to_wlc_ndev(cfgdev, cfg) (cfgdev) -#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) (cfgdev) -#endif /* WL_CFG80211_P2P_DEV_IF */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -#define ndev_to_cfgdev(ndev) ndev_to_wdev(ndev) -#define discover_cfgdev(cfgdev, cfg) (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) -#else -#define ndev_to_cfgdev(ndev) (ndev) -#define discover_cfgdev(cfgdev, cfg) (cfgdev == cfg->p2p_net) -#endif /* WL_CFG80211_P2P_DEV_IF */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \ - (cfg->scan_request->wdev == cfg->p2p_wdev)) ? true : false) -#elif defined(WL_ENABLE_P2P_IF) -#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \ - (cfg->scan_request->dev == cfg->p2p_net)) ? true : false) -#else -#define scan_req_match(cfg) (((cfg) && p2p_is_on(cfg) && p2p_scan(cfg)) ? \ - true : false) -#endif /* WL_CFG80211_P2P_DEV_IF */ - -#define wl_to_sr(w) (w->scan_req_int) -#if defined(STATIC_WL_PRIV_STRUCT) -#define wl_to_ie(w) (w->ie) -#define wl_to_conn(w) (w->conn_info) -#else -#define wl_to_ie(w) (&w->ie) -#define wl_to_conn(w) (&w->conn_info) -#endif -#define wiphy_from_scan(w) (w->escan_info.wiphy) -#define wl_get_drv_status_all(cfg, stat) \ - (wl_get_status_all(cfg, WL_STATUS_ ## stat)) -#define wl_get_drv_status(cfg, stat, ndev) \ - (wl_get_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev)) -#define wl_set_drv_status(cfg, stat, ndev) \ - (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 1)) -#define wl_clr_drv_status(cfg, stat, ndev) \ - (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 2)) -#define wl_clr_drv_status_all(cfg, stat) \ - (wl_set_status_all(cfg, WL_STATUS_ ## stat, 2)) -#define wl_chg_drv_status(cfg, stat, ndev) \ - (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 4)) - -#define for_each_bss(list, bss, __i) \ - for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) - -#define for_each_ndev(cfg, iter, next) \ - list_for_each_entry_safe(iter, next, &cfg->net_list, list) - - -/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0. - * In addtion to that, wpa_version is WPA_VERSION_1 - */ -#define is_wps_conn(_sme) \ - ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \ - (!_sme->crypto.n_ciphers_pairwise) && \ - (!_sme->crypto.cipher_group)) - -#ifdef WLFBT -#if defined(WLAN_AKM_SUITE_FT_8021X) && defined(WLAN_AKM_SUITE_FT_PSK) -#define IS_AKM_SUITE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_8021X || \ - sec->wpa_auth == WLAN_AKM_SUITE_FT_PSK) -#elif defined(WLAN_AKM_SUITE_FT_8021X) -#define IS_AKM_SUITE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_8021X) -#elif defined(WLAN_AKM_SUITE_FT_PSK) -#define IS_AKM_SUITE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_PSK) -#else -#define IS_AKM_SUITE_FT(sec) false -#endif /* WLAN_AKM_SUITE_FT_8021X && WLAN_AKM_SUITE_FT_PSK */ -#else -#define IS_AKM_SUITE_FT(sec) false -#endif /* WLFBT */ - -#ifdef BCMCCX -#define IS_AKM_SUITE_CCKM(sec) (sec->wpa_auth == WLAN_AKM_SUITE_CCKM) -#else -#define IS_AKM_SUITE_CCKM(sec) false -#endif /* BCMCCX */ - -extern s32 wl_cfg80211_attach(struct net_device *ndev, void *context); -extern s32 wl_cfg80211_attach_post(struct net_device *ndev); -extern void wl_cfg80211_detach(void *para); - -extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, - void *data); -void wl_cfg80211_set_parent_dev(void *dev); -struct device *wl_cfg80211_get_parent_dev(void); - -extern s32 wl_cfg80211_up(void *para); -extern s32 wl_cfg80211_down(void *para); -extern s32 wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx); -extern s32 wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx); -extern s32 wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx); -extern struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, - uint8 *mac, uint8 bssidx); -extern int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev); -extern int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev); -extern int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev); -extern bool wl_cfg80211_is_vsdb_mode(void); -extern void* wl_cfg80211_get_dhdp(void); -extern bool wl_cfg80211_is_p2p_active(void); -extern void wl_cfg80211_dbg_level(u32 level); -extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); -extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len); -extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); -extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, - enum wl_management_type type); -extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); - -/* btcoex functions */ -void* wl_cfg80211_btcoex_init(struct net_device *ndev); -void wl_cfg80211_btcoex_deinit(void); - -#ifdef WL_SUPPORT_AUTO_CHANNEL -#define CHANSPEC_BUF_SIZE 1024 -#define CHAN_SEL_IOCTL_DELAY 300 -#define CHAN_SEL_RETRY_COUNT 15 -#define CHANNEL_IS_RADAR(channel) (((channel & WL_CHAN_RADAR) || \ - (channel & WL_CHAN_PASSIVE)) ? true : false) -#define CHANNEL_IS_2G(channel) (((channel >= 1) && (channel <= 14)) ? \ - true : false) -#define CHANNEL_IS_5G(channel) (((channel >= 36) && (channel <= 165)) ? \ - true : false) -extern s32 wl_cfg80211_get_best_channels(struct net_device *dev, char* command, - int total_len); -#endif /* WL_SUPPORT_AUTO_CHANNEL */ - -extern int wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n); -extern int wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str); -extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); -extern s32 wl_mode_to_nl80211_iftype(s32 mode); -int wl_cfg80211_do_driver_init(struct net_device *net); -void wl_cfg80211_enable_trace(bool set, u32 level); -extern s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify); -extern s32 wl_cfg80211_if_is_group_owner(void); -extern chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec); -extern chanspec_t wl_ch_host_to_driver(u16 channel); -extern s32 wl_set_tx_power(struct net_device *dev, - enum nl80211_tx_power_setting type, s32 dbm); -extern s32 wl_get_tx_power(struct net_device *dev, s32 *dbm); -extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); -extern void wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev); -extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set); -extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, - struct bcm_cfg80211 *cfg, wl_eventmsg_buf_t *ev); -extern void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac); -extern void wl_cfg80211_update_power_mode(struct net_device *dev); -#define SCAN_BUF_CNT 2 -#define SCAN_BUF_NEXT 1 -#define WL_SCANTYPE_LEGACY 0x1 -#define WL_SCANTYPE_P2P 0x2 -#define wl_escan_set_sync_id(a, b) ((a) = htod16(0x1234)) -#define wl_escan_set_type(a, b) -#define wl_escan_get_buf(a, b) ((wl_scan_results_t *) (a)->escan_info.escan_buf) -#define wl_escan_check_sync_id(a, b, c) 0 -#define wl_escan_print_sync_id(a, b, c) -#define wl_escan_increment_sync_id(a, b) -#define wl_escan_init_sync_id(a) - -extern void wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len); -extern s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev); -#ifdef WLAIBSS -extern void wl_cfg80211_set_txfail_pid(int pid); -#endif /* WLAIBSS */ -extern void wl_cfg80211_set_rmc_pid(int pid); - -#ifdef WLFBT -extern void wl_cfg80211_get_fbt_key(uint8 *key); -#endif - -/* Action frame specific functions */ -extern u8 wl_get_action_category(void *frame, u32 frame_len); -extern int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action); - -extern int wl_cfg80211_enable_roam_offload(struct net_device *dev, bool enable); -#ifdef WL_NAN -extern int wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd, - int cmd_len); -#endif /* WL_NAN */ - -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -struct net_device *wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - -extern int wl_cfg80211_get_ioctl_version(void); - -#define RETURN_EIO_IF_NOT_UP(wlpriv) \ - do { \ - struct net_device *checkSysUpNDev = bcmcfg_to_prmry_ndev(wlpriv); \ - if (unlikely(!wl_get_drv_status(wlpriv, READY, checkSysUpNDev))) { \ - WL_INFO(("device is not ready\n")); \ - return -EIO; \ - } \ - } while (0) - -#endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c deleted file mode 100755 index eb02ffaf2b1c..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg_btcoex.c 701450 2017-05-25 02:10:23Z $ - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef PKT_FILTER_SUPPORT -extern uint dhd_pkt_filter_enable; -extern uint dhd_master_mode; -extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -#endif - -struct btcoex_info { - struct timer_list timer; - u32 timer_ms; - u32 timer_on; - u32 ts_dhcp_start; /* ms ts ecord time stats */ - u32 ts_dhcp_ok; /* ms ts ecord time stats */ - bool dhcp_done; /* flag, indicates that host done with - * dhcp before t1/t2 expiration - */ - s32 bt_state; - struct work_struct work; - struct net_device *dev; -}; - -static struct btcoex_info *btcoex_info_loc = NULL; - -/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ - -/* use New SCO/eSCO smart YG suppression */ -#define BT_DHCP_eSCO_FIX -/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ -#define BT_DHCP_USE_FLAGS -/* T1 start SCO/ESCo priority suppression */ -#define BT_DHCP_OPPR_WIN_TIME 2500 -/* T2 turn off SCO/SCO supperesion is (timeout) */ -#define BT_DHCP_FLAG_FORCE_TIME 5500 - -enum wl_cfg80211_btcoex_status { - BT_DHCP_IDLE, - BT_DHCP_START, - BT_DHCP_OPPR_WIN, - BT_DHCP_FLAG_FORCE_TIMEOUT -}; - -/* - * get named driver variable to uint register value and return error indication - * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) - */ -static int -dev_wlc_intvar_get_reg(struct net_device *dev, char *name, - uint reg, int *retval) -{ - union { - char buf[WLC_IOCTL_SMLEN]; - int val; - } var; - int error; - - memset(&var, 0, sizeof(var)); - error = bcm_mkiovar(name, (char *)(®), sizeof(reg), (char *)(&var), sizeof(var.buf)); - if (error == 0) { - return BCME_BUFTOOSHORT; - } - error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); - - *retval = dtoh32(var.val); - return (error); -} - -static int -dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) -{ - char ioctlbuf_local[WLC_IOCTL_SMLEN]; - int ret; - - memset(ioctlbuf_local, 0, sizeof(ioctlbuf_local)); - ret = bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); - if (ret == 0) - return BCME_BUFTOOSHORT; - return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); -} -/* -get named driver variable to uint register value and return error indication -calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) -*/ -static int -dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) -{ - char reg_addr[8]; - - memset(reg_addr, 0, sizeof(reg_addr)); - memcpy((char *)®_addr[0], (char *)addr, 4); - memcpy((char *)®_addr[4], (char *)val, 4); - - return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); -} - -static bool btcoex_is_sco_active(struct net_device *dev) -{ - int ioc_res = 0; - bool res = FALSE; - int sco_id_cnt = 0; - int param27; - int i; - - for (i = 0; i < 12; i++) { - - ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); - - WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27)); - - if (ioc_res < 0) { - WL_ERR(("ioc read btc params error\n")); - break; - } - - if ((param27 & 0x6) == 2) { /* count both sco & esco */ - sco_id_cnt++; - } - - if (sco_id_cnt > 2) { - WL_TRACE(("sco/esco detected, pkt id_cnt:%d samples:%d\n", - sco_id_cnt, i)); - res = TRUE; - break; - } - - OSL_SLEEP(5); - } - - return res; -} - -#if defined(BT_DHCP_eSCO_FIX) -/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ -static int set_btc_esco_params(struct net_device *dev, bool trump_sco) -{ - static bool saved_status = FALSE; - - char buf_reg50va_dhcp_on[8] = - { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; - char buf_reg51va_dhcp_on[8] = - { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg64va_dhcp_on[8] = - { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg65va_dhcp_on[8] = - { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg71va_dhcp_on[8] = - { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - uint32 regaddr; - static uint32 saved_reg50; - static uint32 saved_reg51; - static uint32 saved_reg64; - static uint32 saved_reg65; - static uint32 saved_reg71; - - if (trump_sco) { - /* this should reduce eSCO agressive retransmit - * w/o breaking it - */ - - /* 1st save current */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { - saved_status = TRUE; - WL_TRACE(("saved bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - saved_reg50, saved_reg51, - saved_reg64, saved_reg65, saved_reg71)); - } else { - WL_ERR((":%s: save btc_params failed\n", - __FUNCTION__)); - saved_status = FALSE; - return -1; - } - - WL_TRACE(("override with [50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - *(u32 *)(buf_reg50va_dhcp_on+4), - *(u32 *)(buf_reg51va_dhcp_on+4), - *(u32 *)(buf_reg64va_dhcp_on+4), - *(u32 *)(buf_reg65va_dhcp_on+4), - *(u32 *)(buf_reg71va_dhcp_on+4))); - - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg50va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg51va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg64va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg65va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg71va_dhcp_on[0], 8); - - saved_status = TRUE; - } else if (saved_status) { - /* restore previously saved bt params */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - - regaddr = 50; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg50); - regaddr = 51; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg51); - regaddr = 64; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg64); - regaddr = 65; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg65); - regaddr = 71; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg71); - - WL_TRACE(("restore bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - saved_reg50, saved_reg51, saved_reg64, - saved_reg65, saved_reg71)); - - saved_status = FALSE; - } else { - WL_ERR((":%s att to restore not saved BTCOEX params\n", - __FUNCTION__)); - return -1; - } - return 0; -} -#endif /* BT_DHCP_eSCO_FIX */ - -static void -wl_cfg80211_bt_setflag(struct net_device *dev, bool set) -{ -#if defined(BT_DHCP_USE_FLAGS) - char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; -#endif - - -#if defined(BT_DHCP_eSCO_FIX) - /* set = 1, save & turn on 0 - off & restore prev settings */ - set_btc_esco_params(dev, set); -#endif - -#if defined(BT_DHCP_USE_FLAGS) - WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); - if (set == TRUE) - /* Forcing bt_flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_dhcp_on[0], - sizeof(buf_flag7_dhcp_on)); - else - /* Restoring default bt flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], - sizeof(buf_flag7_default)); -#endif -} - -static void wl_cfg80211_bt_timerfunc(ulong data) -{ - struct btcoex_info *bt_local = (struct btcoex_info *)data; - WL_TRACE(("Enter\n")); - bt_local->timer_on = 0; - schedule_work(&bt_local->work); -} - -static void wl_cfg80211_bt_handler(struct work_struct *work) -{ - struct btcoex_info *btcx_inf; - - btcx_inf = container_of(work, struct btcoex_info, work); - - if (btcx_inf->timer_on) { - btcx_inf->timer_on = 0; - del_timer_sync(&btcx_inf->timer); - } - - switch (btcx_inf->bt_state) { - case BT_DHCP_START: - /* DHCP started - * provide OPPORTUNITY window to get DHCP address - */ - WL_TRACE(("bt_dhcp stm: started \n")); - - btcx_inf->bt_state = BT_DHCP_OPPR_WIN; - mod_timer(&btcx_inf->timer, - jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); - btcx_inf->timer_on = 1; - break; - - case BT_DHCP_OPPR_WIN: - if (btcx_inf->dhcp_done) { - WL_TRACE(("DHCP Done before T1 expiration\n")); - goto btc_coex_idle; - } - - /* DHCP is not over yet, start lowering BT priority - * enforce btc_params + flags if necessary - */ - WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); - btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; - mod_timer(&btcx_inf->timer, - jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); - btcx_inf->timer_on = 1; - break; - - case BT_DHCP_FLAG_FORCE_TIMEOUT: - if (btcx_inf->dhcp_done) { - WL_TRACE(("DHCP Done before T2 expiration\n")); - } else { - /* Noo dhcp during T1+T2, restore BT priority */ - WL_TRACE(("DHCP wait interval T2:%d msec expired\n", - BT_DHCP_FLAG_FORCE_TIME)); - } - - /* Restoring default bt priority */ - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); -btc_coex_idle: - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - - default: - WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - } - - net_os_wake_unlock(btcx_inf->dev); -} - -void* wl_cfg80211_btcoex_init(struct net_device *ndev) -{ - struct btcoex_info *btco_inf = NULL; - - btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); - if (!btco_inf) - return NULL; - - btco_inf->bt_state = BT_DHCP_IDLE; - btco_inf->ts_dhcp_start = 0; - btco_inf->ts_dhcp_ok = 0; - /* Set up timer for BT */ - btco_inf->timer_ms = 10; - init_timer(&btco_inf->timer); - btco_inf->timer.data = (ulong)btco_inf; - btco_inf->timer.function = wl_cfg80211_bt_timerfunc; - - btco_inf->dev = ndev; - - INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); - - btcoex_info_loc = btco_inf; - return btco_inf; -} - -void wl_cfg80211_btcoex_deinit() -{ - if (!btcoex_info_loc) - return; - - if (btcoex_info_loc->timer_on) { - btcoex_info_loc->timer_on = 0; - del_timer_sync(&btcoex_info_loc->timer); - } - - cancel_work_sync(&btcoex_info_loc->work); - - kfree(btcoex_info_loc); -} - -int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command) -{ - - struct btcoex_info *btco_inf = btcoex_info_loc; - char powermode_val = 0; - char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; - char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; - char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; - - uint32 regaddr; - static uint32 saved_reg66; - static uint32 saved_reg41; - static uint32 saved_reg68; - static bool saved_status = FALSE; - - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; - - /* Figure out powermode 1 or o command */ - strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); - - if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { - WL_TRACE_HW4(("DHCP session starts\n")); - - -#ifdef PKT_FILTER_SUPPORT - dhd->dhcp_in_progress = 1; - - if (dhd->early_suspended) { - WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n")); - dhd_enable_packet_filter(0, dhd); - } -#endif - - /* Retrieve and saved orig regs value */ - if ((saved_status == FALSE) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { - saved_status = TRUE; - WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); - - /* Disable PM mode during dhpc session */ - - /* Disable PM mode during dhpc session */ - /* Start BT timer only for SCO connection */ - if (btcoex_is_sco_active(dev)) { - /* btc_params 66 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg66va_dhcp_on[0], - sizeof(buf_reg66va_dhcp_on)); - /* btc_params 41 0x33 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg41va_dhcp_on[0], - sizeof(buf_reg41va_dhcp_on)); - /* btc_params 68 0x190 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg68va_dhcp_on[0], - sizeof(buf_reg68va_dhcp_on)); - saved_status = TRUE; - - btco_inf->bt_state = BT_DHCP_START; - btco_inf->timer_on = 1; - mod_timer(&btco_inf->timer, btco_inf->timer.expires); - WL_TRACE(("enable BT DHCP Timer\n")); - } - } - else if (saved_status == TRUE) { - WL_ERR(("was called w/o DHCP OFF. Continue\n")); - } - } - else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { - - - -#ifdef PKT_FILTER_SUPPORT - dhd->dhcp_in_progress = 0; - WL_TRACE_HW4(("DHCP is complete \n")); - - /* Enable packet filtering */ - if (dhd->early_suspended) { - WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); - dhd_enable_packet_filter(1, dhd); - } -#endif /* PKT_FILTER_SUPPORT */ - - /* Restoring PM mode */ - - /* Stop any bt timer because DHCP session is done */ - WL_TRACE(("disable BT DHCP Timer\n")); - if (btco_inf->timer_on) { - btco_inf->timer_on = 0; - del_timer_sync(&btco_inf->timer); - - if (btco_inf->bt_state != BT_DHCP_IDLE) { - /* need to restore original btc flags & extra btc params */ - WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state)); - /* wake up btcoex thread to restore btlags+params */ - schedule_work(&btco_inf->work); - } - } - - /* Restoring btc_flag paramter anyway */ - if (saved_status == TRUE) - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); - - /* Restore original values */ - if (saved_status == TRUE) { - regaddr = 66; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg66); - regaddr = 41; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg41); - regaddr = 68; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg68); - - WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); - } - saved_status = FALSE; - - } - else { - WL_ERR(("Unkwown yet power setting, ignored\n")); - } - - snprintf(command, 3, "OK"); - - return (strlen("OK")); -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c deleted file mode 100755 index 974548ae33c3..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c +++ /dev/null @@ -1,1856 +0,0 @@ -/* - * Neighbor Awareness Networking - * - * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgnan.c 487532 2014-06-26 05:09:36Z $ - */ - -/** - * @file - * @brief - * NAN (Neighbor Awareness Networking) is to provide a low-power mechanism - * that will run in the background to make the devices neighbor aware. NAN - * enables mobile devices to efficiently discover devices and services in - * their proximity. The purpose of NAN is only to discover device and its - * services. Then it is handed over to post NAN discovery and connection - * is established using the actual service data channel (e.g., WLAN - * infrastructure, P2P, IBSS, etc.) - */ - - -#include -#include -#include -#include - -#include -#include -#include - -#ifdef WL_NAN_DEBUG -static u8 g_nan_debug = true; -#else -static u8 g_nan_debug = false; -#endif /* WL_NAN_DEBUG */ - -static nan_cmd_t nan_cmds [] = { - { "NAN_START", wl_cfgnan_start_handler }, - { "NAN_STOP", wl_cfgnan_stop_handler }, - { "NAN_SUPPORT", wl_cfgnan_support_handler }, - { "NAN_STATUS", wl_cfgnan_status_handler }, - { "NAN_PUBLISH", wl_cfgnan_pub_handler }, - { "NAN_SUBSCRIBE", wl_cfgnan_sub_handler }, - { "NAN_CANCEL_PUBLISH", wl_cfgnan_cancel_pub_handler }, - { "NAN_CANCEL_SUBSCRIBE", wl_cfgnan_cancel_sub_handler }, - { "NAN_TRANSMIT", wl_cfgnan_transmit_handler }, - { "NAN_SET_CONFIG", wl_cfgnan_set_config_handler }, - { "NAN_GET_CONFIG", NULL }, - { "NAN_RTT_CONFIG", wl_cfgnan_rtt_config_handler }, - { "NAN_RTT_FIND", wl_cfgnan_rtt_find_handler }, - { "NAN_DEBUG", wl_cfgnan_debug_handler }, - { NULL, NULL }, -}; - -static nan_config_attr_t nan_config_attrs [] = { - { "ATTR_MASTER", WL_NAN_XTLV_MASTER_PREF }, - { "ATTR_ID", WL_NAN_XTLV_CLUSTER_ID }, - { "ATTR_ADDR", WL_NAN_XTLV_IF_ADDR }, - { "ATTR_ROLE", WL_NAN_XTLV_ROLE }, - { "ATTR_BCN_INT", WL_NAN_XTLV_BCN_INTERVAL }, - { "ATTR_CHAN", WL_NAN_XTLV_MAC_CHANSPEC }, - { "ATTR_TX_RATE", WL_NAN_XTLV_MAC_TXRATE }, - { "ATTR_DW_LEN", WL_NAN_XTLV_DW_LEN }, - { {0}, 0 } -}; - -static char nan_event_str[][NAN_EVENT_STR_MAX_LEN] = { - "NAN-INVALID", - "NAN-STARTED", - "NAN-JOINED", - "NAN-ROLE-CHANGE", - "NAN-SCAN-COMPLETE", - "NAN-SDF-RX", - "NAN-REPLIED", - "NAN-TERMINATED", - "NAN-FOLLOWUP-RX", - "NAN-STATUS-CHANGE", - "NAN-MERGED", - "NAN-STOPPED" - "NAN-INVALID", -}; - -static char nan_event_name[][NAN_EVENT_NAME_MAX_LEN] = { - "WL_NAN_EVENT_INVALID", - "WL_NAN_EVENT_START", - "WL_NAN_EVENT_JOIN", - "WL_NAN_EVENT_ROLE", - "WL_NAN_EVENT_SCAN_COMPLETE", - "WL_NAN_EVENT_DISCOVERY_RESULT", - "WL_NAN_EVENT_REPLIED", - "WL_NAN_EVENT_TERMINATED", - "WL_NAN_EVENT_RECEIVE", - "WL_NAN_EVENT_STATUS_CHG", - "WL_NAN_EVENT_MERGE", - "WL_NAN_EVENT_STOP", - "WL_NAN_EVENT_INVALID" -}; - -int -wl_cfgnan_set_vars_cbfn(void *ctx, uint8 *buf, uint16 type, uint16 len) -{ - wl_nan_tlv_data_t *ndata = ((wl_nan_tlv_data_t *)(ctx)); - int ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - WL_DBG((" enter, xtlv_type: 0x%x \n", type)); - - switch (type) { - case WL_NAN_XTLV_ENABLE: - memcpy(&ndata->enabled, buf, len); - break; - case WL_NAN_XTLV_MASTER_PREF: - /* - * master role and preference mac has them as two u8's, - * - * masterpref: val & 0x0ff - * rnd_factor: val >> 8 - */ - memcpy(&ndata->master_pref, buf, len); - break; - case WL_NAN_XTLV_IF_ADDR: - memcpy(&ndata->mac_addr, buf, len); - break; - case WL_NAN_XTLV_CLUSTER_ID: - memcpy(&ndata->clus_id, buf, len); - break; - case WL_NAN_XTLV_ROLE: - /* nan device role, master, master-sync nosync etc */ - memcpy(&ndata->dev_role, buf, len); - break; - case WL_NAN_XTLV_MAC_CHANSPEC: - memcpy(&ndata->chanspec, buf, len); - if (wf_chspec_valid(ndata->chanspec)) { - wf_chspec_ntoa(ndata->chanspec, buf); - WL_DBG((" chanspec: %s 0x%x \n", buf, ndata->chanspec)); - } else { - WL_DBG((" chanspec: 0x%x is not valid \n", ndata->chanspec)); - } - break; - case WL_NAN_XTLV_MAC_AMR: - memcpy(&ndata->amr, buf, len); - break; - case WL_NAN_XTLV_MAC_AMBTT: - memcpy(&ndata->ambtt, buf, len); - break; - case WL_NAN_XTLV_MAC_HOPCNT: - memcpy(&ndata->hop_count, buf, len); - break; - case WL_NAN_XTLV_INSTANCE_ID: - memcpy(&ndata->inst_id, buf, len); - break; - case WL_NAN_XTLV_SVC_NAME: - memcpy(&ndata->svc_name, buf, len); - break; - case WL_NAN_XTLV_SVC_PARAMS: - memcpy(&ndata->params, buf, len); - break; - case WL_NAN_XTLV_MAC_STATUS: - memcpy(&ndata->nstatus, buf, len); - break; - case WL_NAN_XTLV_PUBLR_ID: - memcpy(&ndata->pub_id, buf, len); - break; - case WL_NAN_XTLV_SUBSCR_ID: - memcpy(&ndata->sub_id, buf, len); - break; - case WL_NAN_XTLV_MAC_ADDR: - memcpy(&ndata->mac_addr, buf, len); - break; - case WL_NAN_XTLV_VNDR: - ndata->vend_info.dlen = len; - ndata->vend_info.data = kzalloc(ndata->vend_info.dlen, kflags); - if (!ndata->vend_info.data) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - if (ndata->vend_info.data && ndata->vend_info.dlen) { - memcpy(ndata->vend_info.data, buf, len); - } - break; - case WL_NAN_XTLV_SVC_INFO: - ndata->svc_info.dlen = len; - ndata->svc_info.data = kzalloc(ndata->svc_info.dlen, kflags); - if (!ndata->svc_info.data) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - if (ndata->svc_info.data && ndata->svc_info.dlen) { - memcpy(&ndata->svc_info.data, buf, len); - } - break; - case WL_NAN_XTLV_PEER_INSTANCE_ID: - memcpy(&ndata->peer_inst_id, buf, len); - break; - case WL_NAN_XTLV_NAN_SCANPARAMS: - memcpy(&ndata->scan_params, buf, len); - break; - case WL_NAN_XTLV_ZERO: - /* don't parse empty space in the buffer */ - ret = BCME_ERROR; - break; - - default: - break; - } - -fail: - return ret; -} - -int -wl_cfgnan_enable_events(struct net_device *ndev, struct bcm_cfg80211 *cfg) -{ - wl_nan_ioc_t *nanioc = NULL; - uint8 *pxtlv; - u32 event_mask = 0; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - ret = wl_add_remove_eventmsg(ndev, WLC_E_NAN, true); - if (unlikely(ret)) { - WL_ERR((" nan event enable failed, error = %d \n", ret)); - goto fail; - } - if (g_nan_debug) { - /* enable all nan events */ - event_mask = NAN_EVENT_MASK_ALL; - } else { - /* enable only selected nan events to avoid unnecessary host wake up */ - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_START); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_JOIN); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_DISCOVERY_RESULT); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_RECEIVE); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_TERMINATED); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_STOP); - event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_CLEAR_BIT); - event_mask = htod32(event_mask); - } - - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_EVENT_MASK); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_EVENT_MASK, - sizeof(event_mask), &event_mask, BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan event selective enable failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan event selective enable successful \n")); - } - - ret = wl_add_remove_eventmsg(ndev, WLC_E_PROXD, true); - if (unlikely(ret)) { - WL_ERR((" proxd event enable failed, error = %d \n", ret)); - goto fail; - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_enable_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - uint8 *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - uint8 val; - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan 1 - * - * wpa_cli: DRIVER NAN_ENABLE - */ - - /* nan enable */ - val = 1; - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_ENABLE); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE, - sizeof(val), &val, BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan enable failed, error = %d \n", ret)); - goto fail; - } else { - cfg->nan_enable = true; - WL_DBG((" nan enable successful \n")); - } - - /* enable nan events */ - ret = wl_cfgnan_enable_events(ndev, cfg); - if (unlikely(ret)) { - goto fail; - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_start_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - struct ether_addr cluster_id = ether_null; - uint8 *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - uint8 val; - - if (cfg->nan_enable != true) { - ret = wl_cfgnan_enable_handler(ndev, cfg, cmd, cmd_data); - if (unlikely(ret)) { - goto fail; - } - } - - /* - * command to test - * - * wl: wl nan join -start - * - * wpa_cli: DRIVER NAN_START - */ - - /* nan join */ - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - val = 1; - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_NAN_JOIN); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, - ETHER_ADDR_LEN, &cluster_id, BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_START, - sizeof(val), &val, BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan join failed, error = %d \n", ret)); - goto fail; - } - - WL_DBG((" nan join successful \n")); - cfg->nan_running = true; - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_stop_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - struct ether_addr cluster_id = ether_null; - uint8 *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - uint8 nan_enable = FALSE; - - /* - * command to test - * - * wl: wl nan stop - * wl nan 0 - * - * wpa_cli: DRIVER NAN_STOP - */ - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - if (cfg->nan_running == true) { - /* nan stop */ - - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_STOP); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, - ETHER_ADDR_LEN, &cluster_id, BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan stop failed, error = %d \n", ret)); - goto fail; - } else { - cfg->nan_running = false; - WL_DBG((" nan stop successful \n")); - } - } - - /* nan disable */ - if (cfg->nan_enable == true) { - memset(nanioc, 0, nanioc_size); - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_ENABLE); - pxtlv = nanioc->data; - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE, - sizeof(nan_enable), &nan_enable, BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan disable failed, error = %d \n", ret)); - goto fail; - } else { - cfg->nan_enable = false; - WL_DBG((" nan disable successful \n")); - } - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_support_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - uint8 *pxtlv; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan - * - * wpa_cli: DRIVER NAN_SUPPORT - */ - - /* nan support */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_ENABLE); - pxtlv = nanioc->data; - nanioc->len = htod16(BCM_XTLV_HDR_SIZE + 1); - nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); - ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); - if (unlikely(ret)) { - WL_ERR((" nan is not supported, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan is supported \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_status_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - wl_nan_ioc_t *ioc_ret = NULL; - void *pxtlv; - char *ptr = cmd; - wl_nan_tlv_data_t tlv_data; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan status - * - * wpa_cli: DRIVER NAN_STATUS - */ - - /* nan status */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_STATUS); - pxtlv = nanioc->data; - nanioc->len = NAN_IOCTL_BUF_SIZE; - nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); - ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan status failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan status successful \n")); - } - - /* unpack the tlvs */ - memset(&tlv_data, 0, sizeof(tlv_data)); - ioc_ret = (wl_nan_ioc_t *)cfg->ioctl_buf; - if (g_nan_debug) { - prhex(" nanioc->data: ", (uint8 *)ioc_ret->data, ioc_ret->len); - } - bcm_unpack_xtlv_buf(&tlv_data, ioc_ret->data, ioc_ret->len, - BCM_XTLV_OPTION_ALIGN32, wl_cfgnan_set_vars_cbfn); - - ptr += sprintf(ptr, ROLE_PREFIX"%d", tlv_data.dev_role); - ptr += sprintf(ptr, " " AMR_PREFIX); - ptr += bcm_format_hex(ptr, tlv_data.amr, NAN_MASTER_RANK_LEN); - ptr += sprintf(ptr, " " CLUS_ID_PREFIX MACF, ETHER_TO_MACF(tlv_data.clus_id)); - ptr += sprintf(ptr, " " AMBTT_PREFIX"0x%x", tlv_data.ambtt); - ptr += sprintf(ptr, " " HOP_COUNT_PREFIX"%d", tlv_data.hop_count); - - /* nan scan param */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_SCAN_PARAMS); - pxtlv = nanioc->data; - nanioc->len = NAN_IOCTL_BUF_SIZE; - nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); - ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan scan params failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan scan params successful \n")); - } - - /* unpack the tlvs */ - memset(&tlv_data, 0, sizeof(tlv_data)); - ioc_ret = (wl_nan_ioc_t *)cfg->ioctl_buf; - ASSERT(ioc_ret != NULL); - if (g_nan_debug) { - prhex(" nanioc->data: ", (uint8 *)ioc_ret->data, ioc_ret->len); - } - bcm_unpack_xtlv_buf(&tlv_data, ioc_ret->data, ioc_ret->len, - BCM_XTLV_OPTION_ALIGN32, wl_cfgnan_set_vars_cbfn); - - ptr += sprintf(ptr, " " SCAN_PERIOD_PREFIX"%d", - tlv_data.scan_params.ms_dur); - ptr += sprintf(ptr, " " SCAN_INTERVAL_PREFIX"%d", - tlv_data.scan_params.ms_intvl*512); - - WL_DBG((" formatted string for userspace: %s, len: %zu \n", - cmd, strlen(cmd))); - -fail: - if (nanioc) { - kfree(nanioc); - } - if (tlv_data.svc_info.data) { - kfree(tlv_data.svc_info.data); - tlv_data.svc_info.data = NULL; - tlv_data.svc_info.dlen = 0; - } - if (tlv_data.vend_info.data) { - kfree(tlv_data.vend_info.data); - tlv_data.vend_info.data = NULL; - tlv_data.vend_info.dlen = 0; - } - - return ret; -} - -/* - * packs user data (in hex string) into tlv record - * advances tlv pointer to next xtlv slot - * buflen is used for tlv_buf space check - */ -static int -get_ie_data(uchar *data_str, uchar *ie_data, int len) -{ - uchar *src, *dest; - uchar val; - int idx; - char hexstr[3]; - - src = data_str; - dest = ie_data; - - for (idx = 0; idx < len; idx++) { - hexstr[0] = src[0]; - hexstr[1] = src[1]; - hexstr[2] = '\0'; - -#ifdef BCMDRIVER - val = (uchar) simple_strtoul(hexstr, NULL, 16); -#else - val = (uchar) strtoul(hexstr, NULL, 16); -#endif - - *dest++ = val; - src += 2; - } - - return 0; -} - -int -wl_cfgnan_pub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - wl_nan_disc_params_t params; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - uint8 *pxtlv; - u16 start, end; - uchar *buf = NULL; - - /* - * proceed only if mandatory arguments are present - publisher id, - * service hash - */ - if ((!cmd_data->pub_id) || (!cmd_data->svc_hash.data) || - (!cmd_data->svc_hash.dlen)) { - WL_ERR((" mandatory arguments are not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan publish 10 NAN123 -info - * DRIVER NAN_PUBLISH PUB_ID=10 SVC_HASH=NAN123 - * SVC_INFO= PUB_PR=1 PUB_INT=0xffffffff - */ - - /* nan publish */ - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_PUBLISH); - pxtlv = nanioc->data; - - /* disovery parameters */ - if (cmd_data->pub_pr) { - params.period = cmd_data->pub_pr; - } else { - params.period = 1; - } - if (cmd_data->pub_int) { - params.ttl = cmd_data->pub_int; - } else { - params.ttl = WL_NAN_TTL_UNTIL_CANCEL; - } - params.flags = 0; - if (cmd_data->flags & WL_NAN_PUB_UNSOLICIT) { - params.flags |= WL_NAN_PUB_UNSOLICIT; - WL_DBG((" nan publish type - unsolicited\n")); - } - if (cmd_data->flags & WL_NAN_PUB_SOLICIT) { - params.flags |= WL_NAN_PUB_SOLICIT; - WL_DBG((" nan publish type - solicited\n")); - } - if (!params.flags) { - params.flags = WL_NAN_PUB_BOTH; /* default. */ - } - params.instance_id = (wl_nan_instance_id_t)cmd_data->pub_id; - memcpy((char *)params.svc_hash, cmd_data->svc_hash.data, - cmd_data->svc_hash.dlen); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_SVC_PARAMS, - sizeof(params), ¶ms, BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { - uint16 len = cmd_data->svc_info.dlen/2; - - WL_DBG((" optional svc_info present, pack it \n")); - buf = kzalloc(len, kflags); - if (!buf) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - if (get_ie_data((uchar*)cmd_data->svc_info.data, buf, len)) { - goto fail; - } - - ret = bcm_pack_xtlv_entry(&pxtlv, - &end, WL_NAN_XTLV_SVC_INFO, len, buf, BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - } - - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan publish failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan publish successful \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - if (buf) { - kfree(buf); - } - - return ret; -} - -int -wl_cfgnan_sub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - bcm_xtlvbuf_t tbuf; - wl_nan_disc_params_t params; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - /* - * proceed only if mandatory arguments are present - subscriber id, - * service hash - */ - if ((!cmd_data->sub_id) || (!cmd_data->svc_hash.data) || - (!cmd_data->svc_hash.dlen)) { - WL_ERR((" mandatory arguments are not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - bcm_xtlv_buf_init(&tbuf, nanioc->data, - BCM_XTLV_HDR_SIZE + sizeof(params), BCM_XTLV_OPTION_ALIGN32); - - /* - * command to test - * - * wl: wl nan subscribe 10 NAN123 - * - * wpa_cli: DRIVER NAN_SUBSCRIBE SUB_ID=10 SVC_HASH=NAN123 - */ - - /* nan subscribe */ - params.period = 1; - params.ttl = WL_NAN_TTL_UNTIL_CANCEL; - params.flags = 0; - if (cmd_data->flags & WL_NAN_SUB_ACTIVE) { - params.flags = WL_NAN_SUB_ACTIVE; - WL_DBG((" nan subscribe type - Active\n")); - } - params.instance_id = (wl_nan_instance_id_t)cmd_data->sub_id; - memcpy((char *)params.svc_hash, cmd_data->svc_hash.data, - cmd_data->svc_hash.dlen); - bcm_xtlv_put_data(&tbuf, WL_NAN_XTLV_SVC_PARAMS, ¶ms, sizeof(params)); - - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_SUBSCRIBE); - nanioc->len = htod16(bcm_xtlv_buf_len(&tbuf)); - nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(&tbuf); - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan subscribe failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan subscribe successful \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_cancel_pub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - bcm_xtlvbuf_t tbuf; - wl_nan_disc_params_t params; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - /* proceed only if mandatory argument is present - publisher id */ - if (!cmd_data->pub_id) { - WL_ERR((" mandatory argument is not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - bcm_xtlv_buf_init(&tbuf, nanioc->data, - BCM_XTLV_HDR_SIZE + sizeof(params), BCM_XTLV_OPTION_ALIGN32); - - /* - * command to test - * - * wl: wl nan cancel_publish 10 - * - * wpa_cli: DRIVER NAN_CANCEL_PUBLISH PUB_ID=10 - */ - - bcm_xtlv_put_data(&tbuf, WL_NAN_XTLV_INSTANCE_ID, &cmd_data->pub_id, - sizeof(wl_nan_instance_id_t)); - - /* nan cancel publish */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_CANCEL_PUBLISH); - nanioc->len = htod16(bcm_xtlv_buf_len(&tbuf)); - nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(&tbuf); - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan cancel publish failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan cancel publish successful \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_cancel_sub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - bcm_xtlvbuf_t tbuf; - wl_nan_disc_params_t params; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - /* proceed only if mandatory argument is present - subscriber id */ - if (!cmd_data->sub_id) { - WL_ERR((" mandatory argument is not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - bcm_xtlv_buf_init(&tbuf, nanioc->data, - BCM_XTLV_HDR_SIZE + sizeof(params), BCM_XTLV_OPTION_ALIGN32); - - /* - * command to test - * - * wl: wl nan cancel_subscribe 10 - * - * wpa_cli: DRIVER NAN_CANCEL_SUBSCRIBE PUB_ID=10 - */ - - bcm_xtlv_put_data(&tbuf, WL_NAN_XTLV_INSTANCE_ID, &cmd_data->sub_id, - sizeof(wl_nan_instance_id_t)); - - /* nan cancel subscribe */ - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_CANCEL_SUBSCRIBE); - nanioc->len = htod16(bcm_xtlv_buf_len(&tbuf)); - nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(&tbuf); - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan cancel subscribe failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan cancel subscribe successful \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_transmit_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - uint8 *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - uchar *buf = NULL; - - /* - * proceed only if mandatory arguments are present - subscriber id, - * publisher id, mac address - */ - if ((!cmd_data->sub_id) || (!cmd_data->pub_id) || - ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) { - WL_ERR((" mandatory arguments are not present \n")); - return -EINVAL; - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan trasnmit -info - * - * wpa_cli: DRIVER NAN_TRANSMIT SUB_ID= PUB_ID= - * MAC_ADDR= SVC_INFO= - */ - - /* nan transmit */ - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_TRANSMIT); - pxtlv = nanioc->data; - - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_INSTANCE_ID, - sizeof(cmd_data->local_id), &cmd_data->local_id, - BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_REQUESTOR_ID, - sizeof(cmd_data->remote_id), &cmd_data->remote_id, - BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_ADDR, - ETHER_ADDR_LEN, &cmd_data->mac_addr.octet, - BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { - uint16 len = cmd_data->svc_info.dlen/2; - - WL_DBG((" optional svc_info present, pack it \n")); - buf = kzalloc(len, kflags); - if (!buf) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - if (get_ie_data((uchar*)cmd_data->svc_info.data, buf, len)) { - goto fail; - } - - ret = bcm_pack_xtlv_entry(&pxtlv, - &end, WL_NAN_XTLV_SVC_INFO, len, buf, - BCM_XTLV_OPTION_ALIGN32); - if (unlikely(ret)) { - goto fail; - } - } - - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan transmit failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan transmit successful \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - if (buf) { - kfree(buf); - } - - return ret; -} - -int -wl_cfgnan_set_config_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ioc_t *nanioc = NULL; - uint8 *pxtlv; - s32 ret = BCME_OK; - u16 start, end; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; - - if (cfg->nan_running == true) { - WL_ERR((" Stop nan (NAN_STOP) before issuing NAN_CONFIG command\n")); - return BCME_ERROR; - } - - if (cfg->nan_enable != true) { - ret = wl_cfgnan_enable_handler(ndev, cfg, cmd, cmd_data); - if (unlikely(ret)) { - goto fail; - } - } - - nanioc = kzalloc(nanioc_size, kflags); - if (!nanioc) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl nan (wl nan role 1) - * - * wpa_cli: DRIVER NAN_CONFIG_SET ATTR= ... - * - * wpa_cli: DRIVER NAN_SET_CONFIG ATTR=ATTR_ROLE ROLE=1 - */ - - /* nan set config */ - start = end = NAN_IOCTL_BUF_SIZE; - nanioc->version = htod16(WL_NAN_IOCTL_VERSION); - nanioc->id = htod16(WL_NAN_CMD_ATTR); - pxtlv = nanioc->data; - - switch (cmd_data->attr.type) { - case WL_NAN_XTLV_ROLE: - WL_DBG((" set nan ROLE = %#x\n", cmd_data->role)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ROLE, - sizeof(cmd_data->role), &cmd_data->role, - BCM_XTLV_OPTION_ALIGN32); - break; - case WL_NAN_XTLV_MASTER_PREF: - WL_DBG((" set nan MASTER PREF = %#x\n", cmd_data->master_pref)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MASTER_PREF, - sizeof(cmd_data->master_pref), &cmd_data->master_pref, - BCM_XTLV_OPTION_ALIGN32); - break; - case WL_NAN_XTLV_DW_LEN: - WL_DBG((" set nan DW LEN = %#x\n", cmd_data->dw_len)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_DW_LEN, - sizeof(cmd_data->dw_len), &cmd_data->dw_len, - BCM_XTLV_OPTION_ALIGN32); - break; - case WL_NAN_XTLV_CLUSTER_ID: - WL_DBG((" set nan CLUSTER ID ")); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, - sizeof(cmd_data->clus_id), &cmd_data->clus_id, - BCM_XTLV_OPTION_ALIGN32); - break; - case WL_NAN_XTLV_IF_ADDR: - WL_DBG((" set nan IFADDR ")); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_IF_ADDR, - sizeof(cmd_data->if_addr), &cmd_data->if_addr, - BCM_XTLV_OPTION_ALIGN32); - break; - case WL_NAN_XTLV_MAC_CHANSPEC: - WL_DBG((" set nan CHANSPEC = %#x\n", cmd_data->chanspec)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_CHANSPEC, - sizeof(cmd_data->chanspec), &cmd_data->chanspec, - BCM_XTLV_OPTION_ALIGN32); - break; - case WL_NAN_XTLV_BCN_INTERVAL: - WL_DBG((" set nan BCN_INTERVAL = %#x\n", cmd_data->beacon_int)); - ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_BCN_INTERVAL, - sizeof(cmd_data->beacon_int), &cmd_data->beacon_int, - BCM_XTLV_OPTION_ALIGN32); - break; - case WL_NAN_XTLV_MAC_TXRATE: - default: - ret = -EINVAL; - break; - } - if (unlikely(ret)) { - WL_ERR((" unsupported attribute, attr = %s (%d) \n", - cmd_data->attr.name, cmd_data->attr.type)); - goto fail; - } - - nanioc->len = start - end; - nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; - ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, - cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan set config failed, error = %d \n", ret)); - goto fail; - } else { - WL_DBG((" nan set config successful \n")); - } - -fail: - if (nanioc) { - kfree(nanioc); - } - - return ret; -} - -int -wl_cfgnan_rtt_config_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - wl_nan_ranging_config_t rtt_config; - s32 ret = BCME_OK; - - /* proceed only if mandatory argument is present - channel */ - if (!cmd_data->chanspec) { - WL_ERR((" mandatory argument is not present \n")); - return -EINVAL; - } - - /* - * command to test - * - * wl: wl proxd_nancfg 44/80 128 32 ff:ff:ff:ff:ff:ff 1 - * - * wpa_cli: DRIVER NAN_RTT_CONFIG CHAN=44/80 - */ - - memset(&rtt_config, 0, sizeof(wl_nan_ranging_config_t)); - rtt_config.chanspec = cmd_data->chanspec; - rtt_config.timeslot = 128; - rtt_config.duration = 32; - memcpy(&rtt_config.allow_mac, ðer_bcast, ETHER_ADDR_LEN); - rtt_config.flags = 1; - - ret = wldev_iovar_setbuf(ndev, "proxd_nancfg", &rtt_config, - sizeof(wl_nan_ranging_config_t), cfg->ioctl_buf, - WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan rtt config failed, error = %d \n", ret)); - } else { - WL_DBG((" nan rtt config successful \n")); - } - - return ret; -} - -int -wl_cfgnan_rtt_find_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - void *iovbuf; - wl_nan_ranging_list_t *rtt_list; - s32 iovbuf_size = NAN_RTT_IOVAR_BUF_SIZE; - s32 ret = BCME_OK; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - /* - * proceed only if mandatory arguments are present - channel, bitmap, - * mac address - */ - if ((!cmd_data->chanspec) || (!cmd_data->bmap) || - ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) { - WL_ERR((" mandatory arguments are not present \n")); - return -EINVAL; - } - - iovbuf = kzalloc(iovbuf_size, kflags); - if (!iovbuf) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - /* - * command to test - * - * wl: wl proxd_nanfind 1 44/80 0x300 5 6 1 - * - * wpa_cli: DRIVER NAN_RTT_FIND MAC_ADDR= CHAN=44/80 BMAP=0x300 - * - */ - rtt_list = (wl_nan_ranging_list_t *)iovbuf; - rtt_list->count = 1; - rtt_list->num_peers_done = 0; - rtt_list->num_dws = 1; - rtt_list->rp[0].chanspec = cmd_data->chanspec; - memcpy(&rtt_list->rp[0].ea, &cmd_data->mac_addr, - sizeof(struct ether_addr)); - rtt_list->rp[0].abitmap = cmd_data->bmap; - rtt_list->rp[0].frmcnt = 5; - rtt_list->rp[0].retrycnt = 6; - rtt_list->rp[0].flags = 1; - - iovbuf_size = sizeof(wl_nan_ranging_list_t) + - sizeof(wl_nan_ranging_peer_t); - ret = wldev_iovar_setbuf(ndev, "proxd_nanfind", iovbuf, - iovbuf_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (unlikely(ret)) { - WL_ERR((" nan rtt find failed, error = %d \n", ret)); - } else { - WL_DBG((" nan rtt find successful \n")); - } - - if (iovbuf) { - kfree(iovbuf); - } - - return ret; -} - -int -wl_cfgnan_debug_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) -{ - /* - * command to test - * - * wpa_cli: DRIVER NAN_DEBUG DEBUG=1 - * - */ - - g_nan_debug = cmd_data->debug_flag; - - /* reconfigure nan events */ - return wl_cfgnan_enable_events(ndev, cfg); -} - -static int wl_cfgnan_config_attr(char *buf, nan_config_attr_t *attr) -{ - s32 ret = BCME_OK; - nan_config_attr_t *nanc = NULL; - - /* only one attribute at a time */ - for (nanc = &nan_config_attrs[0]; strlen(nanc->name) != 0; nanc++) { - if (!strncmp(nanc->name, buf, strlen(nanc->name))) { - strncpy((char *)attr->name, buf, strlen(nanc->name)); - attr->type = nanc->type; - ret = strlen(nanc->name); - break; - } - } - - return ret; -} - -static int wl_cfgnan_parse_args(char *buf, nan_cmd_data_t *cmd_data) -{ - s32 ret = BCME_OK; - char *token = buf; - char delim[] = " "; - - while ((buf != NULL) && (token != NULL)) { - if (!strncmp(buf, PUB_ID_PREFIX, strlen(PUB_ID_PREFIX))) { - buf += strlen(PUB_ID_PREFIX); - token = strsep(&buf, delim); - cmd_data->pub_id = simple_strtoul(token, NULL, 10); - if (NAN_INVALID_ID(cmd_data->pub_id)) { - WL_ERR((" invalid publisher id, pub_id = %d \n", - cmd_data->pub_id)); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, SUB_ID_PREFIX, strlen(SUB_ID_PREFIX))) { - buf += strlen(SUB_ID_PREFIX); - token = strsep(&buf, delim); - cmd_data->sub_id = simple_strtoul(token, NULL, 10); - if (NAN_INVALID_ID(cmd_data->sub_id)) { - WL_ERR((" invalid subscriber id, sub_id = %d \n", - cmd_data->sub_id)); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, MAC_ADDR_PREFIX, strlen(MAC_ADDR_PREFIX))) { - buf += strlen(MAC_ADDR_PREFIX); - token = strsep(&buf, delim); - if (!wl_cfg80211_ether_atoe(token, &cmd_data->mac_addr)) { - WL_ERR((" invalid mac address, mac_addr = "MACDBG "\n", - MAC2STRDBG(cmd_data->mac_addr.octet))); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, SVC_HASH_PREFIX, strlen(SVC_HASH_PREFIX))) { - buf += strlen(SVC_HASH_PREFIX); - token = strsep(&buf, delim); - cmd_data->svc_hash.data = token; - cmd_data->svc_hash.dlen = WL_NAN_SVC_HASH_LEN; - } else if (!strncmp(buf, SVC_INFO_PREFIX, strlen(SVC_INFO_PREFIX))) { - buf += strlen(SVC_INFO_PREFIX); - token = strsep(&buf, delim); - cmd_data->svc_info.data = token; - cmd_data->svc_info.dlen = strlen(token); - } else if (!strncmp(buf, CHAN_PREFIX, strlen(CHAN_PREFIX))) { - buf += strlen(CHAN_PREFIX); - token = strsep(&buf, delim); - cmd_data->chanspec = wf_chspec_aton(token); - cmd_data->chanspec = wl_chspec_host_to_driver(cmd_data->chanspec); - if (NAN_INVALID_CHANSPEC(cmd_data->chanspec)) { - WL_ERR((" invalid chanspec, chanspec = 0x%04x \n", - cmd_data->chanspec)); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, BITMAP_PREFIX, strlen(BITMAP_PREFIX))) { - buf += strlen(BITMAP_PREFIX); - token = strsep(&buf, delim); - cmd_data->bmap = simple_strtoul(token, NULL, 16); - } else if (!strncmp(buf, ATTR_PREFIX, strlen(ATTR_PREFIX))) { - buf += strlen(ATTR_PREFIX); - token = strsep(&buf, delim); - if (!wl_cfgnan_config_attr(token, &cmd_data->attr)) { - WL_ERR((" invalid attribute, attr = %s \n", - cmd_data->attr.name)); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, ROLE_PREFIX, strlen(ROLE_PREFIX))) { - buf += strlen(ROLE_PREFIX); - token = strsep(&buf, delim); - cmd_data->role = simple_strtoul(token, NULL, 10); - if (NAN_INVALID_ROLE(cmd_data->role)) { - WL_ERR((" invalid role, role = %d \n", cmd_data->role)); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, MASTER_PREF_PREFIX, - strlen(MASTER_PREF_PREFIX))) { - buf += strlen(MASTER_PREF_PREFIX); - token = strsep(&buf, delim); - cmd_data->master_pref = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, CLUS_ID_PREFIX, strlen(CLUS_ID_PREFIX))) { - buf += strlen(CLUS_ID_PREFIX); - token = strsep(&buf, delim); - if (!wl_cfg80211_ether_atoe(token, &cmd_data->clus_id)) { - WL_ERR((" invalid cluster id, CLUS_ID = "MACDBG "\n", - MAC2STRDBG(cmd_data->clus_id.octet))); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, IF_ADDR_PREFIX, strlen(IF_ADDR_PREFIX))) { - buf += strlen(IF_ADDR_PREFIX); - token = strsep(&buf, delim); - if (!wl_cfg80211_ether_atoe(token, &cmd_data->if_addr)) { - WL_ERR((" invalid cluster id, IF_ADDR = "MACDBG "\n", - MAC2STRDBG(cmd_data->if_addr.octet))); - ret = -EINVAL; - goto fail; - } - } else if (!strncmp(buf, BCN_INTERVAL_PREFIX, - strlen(BCN_INTERVAL_PREFIX))) { - buf += strlen(BCN_INTERVAL_PREFIX); - token = strsep(&buf, delim); - cmd_data->beacon_int = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, PUB_PR_PREFIX, strlen(PUB_PR_PREFIX))) { - buf += strlen(PUB_PR_PREFIX); - token = strsep(&buf, delim); - cmd_data->pub_pr = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, PUB_INT_PREFIX, strlen(PUB_INT_PREFIX))) { - buf += strlen(PUB_INT_PREFIX); - token = strsep(&buf, delim); - cmd_data->pub_int = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, DW_LEN_PREFIX, strlen(DW_LEN_PREFIX))) { - buf += strlen(DW_LEN_PREFIX); - token = strsep(&buf, delim); - cmd_data->dw_len = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, DEBUG_PREFIX, strlen(DEBUG_PREFIX))) { - buf += strlen(DEBUG_PREFIX); - token = strsep(&buf, delim); - cmd_data->debug_flag = simple_strtoul(token, NULL, 10); - } else if (!strncmp(buf, ACTIVE_OPTION, strlen(ACTIVE_OPTION))) { - buf += strlen(ACTIVE_OPTION); - token = strsep(&buf, delim); - cmd_data->flags |= WL_NAN_SUB_ACTIVE; - } else if (!strncmp(buf, SOLICITED_OPTION, strlen(SOLICITED_OPTION))) { - buf += strlen(SOLICITED_OPTION); - token = strsep(&buf, delim); - cmd_data->flags |= WL_NAN_PUB_SOLICIT; - } else if (!strncmp(buf, UNSOLICITED_OPTION, strlen(UNSOLICITED_OPTION))) { - buf += strlen(UNSOLICITED_OPTION); - token = strsep(&buf, delim); - cmd_data->flags |= WL_NAN_PUB_UNSOLICIT; - } else { - WL_ERR((" unknown token, token = %s, buf = %s \n", token, buf)); - ret = -EINVAL; - goto fail; - } - } - -fail: - return ret; -} - -int -wl_cfgnan_cmd_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, - char *cmd, int cmd_len) -{ - nan_cmd_data_t cmd_data; - u8 *buf = cmd; - u8 *cmd_name = NULL; - nan_cmd_t *nanc = NULL; - int buf_len = 0; - int ret = BCME_OK; - - cmd_name = strsep((char **)&buf, " "); - if (buf) { - buf_len = strlen(buf); - } - - WL_DBG((" cmd_name: %s, buf_len: %d, buf: %s \n", cmd_name, buf_len, buf)); - - memset(&cmd_data, 0, sizeof(nan_cmd_data_t)); - ret = wl_cfgnan_parse_args(buf, &cmd_data); - if (unlikely(ret)) { - WL_ERR((" argument parsing failed with error (%d), buf = %s \n", - ret, buf)); - goto fail; - } - - for (nanc = nan_cmds; nanc->name; nanc++) { - if (strncmp(nanc->name, cmd_name, strlen(nanc->name)) == 0) { - ret = (*nanc->func)(ndev, cfg, cmd, &cmd_data); - if (ret < BCME_OK) { - WL_ERR((" command (%s) failed with error (%d) \n", - cmd_name, ret)); - } - } - } - -fail: - return ret; -} - -s32 -wl_cfgnan_notify_proxd_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data) -{ - s32 ret = BCME_OK; - wl_nan_ranging_event_data_t *rdata; - s32 status; - u16 data_len; - s32 event_type; - s32 event_num; - u8 *buf = NULL; - u32 buf_len; - u8 *ptr; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - s32 i; - - if (!event || !data) { - WL_ERR((" event data is NULL \n")); - return -EINVAL; - } - - status = ntoh32(event->reason); - event_type = ntoh32(event->event_type); - event_num = ntoh32(event->reason); - data_len = ntoh32(event->datalen); - - WL_DBG((" proxd event: type: %d num: %d len: %d \n", - event_type, event_num, data_len)); - - if (NAN_INVALID_PROXD_EVENT(event_num)) { - WL_ERR((" unsupported event, num: %d \n", event_num)); - return -EINVAL; - } - - if (g_nan_debug) { - WL_DBG((" event name: WLC_E_PROXD_NAN_EVENT \n")); - WL_DBG((" event data: \n")); - prhex(NULL, data, data_len); - } - - if (data_len < sizeof(wl_nan_ranging_event_data_t)) { - WL_ERR((" wrong data len \n")); - return -EINVAL; - } - - rdata = (wl_nan_ranging_event_data_t *)data; - - WL_DBG((" proxd event: count:%d success_count:%d mode:%d \n", - rdata->count, rdata->success_count, rdata->mode)); - - if (g_nan_debug) { - prhex(" event data: ", data, data_len); - } - - buf_len = NAN_IOCTL_BUF_SIZE; - buf = kzalloc(buf_len, kflags); - if (!buf) { - WL_ERR((" memory allocation failed \n")); - return -ENOMEM; - } - - for (i = 0; i < rdata->count; i++) { - if (&rdata->rr[i] == NULL) { - ret = -EINVAL; - goto fail; - } - - ptr = buf; - WL_DBG((" ranging data for mac:"MACDBG" \n", - MAC2STRDBG(rdata->rr[i].ea.octet))); - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " MAC_ADDR_PREFIX MACF - " "STATUS_PREFIX"%s", EVENT_RTT_STATUS_STR, - ETHER_TO_MACF(rdata->rr[i].ea), (rdata->rr[i].status == 1) ? - "success" : "fail"); - - if (rdata->rr[i].status == 1) { - /* add tsf and distance only if status is success */ - ptr += sprintf(ptr, " "TIMESTAMP_PREFIX"0x%x " - DISTANCE_PREFIX"%d.%04d", rdata->rr[i].timestamp, - rdata->rr[i].distance >> 4, - ((rdata->rr[i].distance & 0x0f) * 625)); - } - - } - -fail: - if (buf) { - kfree(buf); - } - - return ret; -} - -s32 -wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data) -{ - s32 ret = BCME_OK; - u16 data_len; - u32 event_num; - s32 event_type; - nan_event_hdr_t nan_hdr; - wl_nan_tlv_data_t tlv_data; - u8 *buf = NULL; - u32 buf_len; - u8 *ptr; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - if (!event || !data) { - WL_ERR((" event data is NULL \n")); - return -EINVAL; - } - - event_type = ntoh32(event->event_type); - event_num = ntoh32(event->reason); - data_len = ntoh32(event->datalen); - memset(&nan_hdr, 0, sizeof(nan_event_hdr_t)); - nan_hdr.event_subtype = event_num; - - WL_DBG((" nan event: type: %d num: %d len: %d \n", - event_type, event_num, data_len)); - - if (NAN_INVALID_EVENT(event_num)) { - WL_ERR((" unsupported event, num: %d \n", event_num)); - return -EINVAL; - } - - if (g_nan_debug) { - WL_DBG((" event name: %s \n", nan_event_name[event_num])); - WL_DBG((" event data: \n")); - prhex(NULL, data, data_len); - } - - /* unpack the tlvs */ - memset(&tlv_data, 0, sizeof(wl_nan_tlv_data_t)); - bcm_unpack_xtlv_buf(&tlv_data, data, data_len, - BCM_XTLV_OPTION_ALIGN32, wl_cfgnan_set_vars_cbfn); - - /* - * send as preformatted hex string - * - * EVENT_NAN - */ - - buf_len = NAN_IOCTL_BUF_SIZE; - buf = ptr = kzalloc(buf_len, kflags); - if (!buf) { - WL_ERR((" memory allocation failed \n")); - ret = -ENOMEM; - goto fail; - } - - switch (event_num) { - case WL_NAN_EVENT_START: - case WL_NAN_EVENT_JOIN: - case WL_NAN_EVENT_STOP: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, - nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; - case WL_NAN_EVENT_ROLE: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s "ROLE_PREFIX "%d " - CLUS_ID_PREFIX MACF, nan_event_str[event_num], - tlv_data.nstatus.role, ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; - case WL_NAN_EVENT_DISCOVERY_RESULT: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " - SUB_ID_PREFIX"%d " MAC_ADDR_PREFIX MACF, - nan_event_str[event_num], tlv_data.pub_id, tlv_data.sub_id, - ETHER_TO_MACF(tlv_data.mac_addr)); - if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) { - WL_DBG((" service info present \n")); - if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) { - WL_ERR((" service info length = %d\n", - tlv_data.svc_info.dlen)); - WL_ERR((" insufficent buffer to copy service info \n")); - ret = -EOVERFLOW; - goto fail; - } - ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX); - ptr += bcm_format_hex(ptr, tlv_data.svc_info.data, - tlv_data.svc_info.dlen); - } else { - WL_DBG((" service info not present \n")); - } - - if (tlv_data.vend_info.data && tlv_data.vend_info.dlen) { - struct ether_addr *ea; - u8 *temp_data = tlv_data.vend_info.data; - uint32 bitmap; - u16 dlen = tlv_data.vend_info.dlen; - chanspec_t chanspec; - uint8 mapcontrol; - uint8 proto; - - WL_DBG((" vendor info present \n")); - if ((*temp_data != NAN_ATTR_VENDOR_SPECIFIC) || - (dlen < NAN_VENDOR_HDR_SIZE)) { - WL_ERR((" error in vendor info attribute \n")); - ret = -EINVAL; - goto fail; - } else { - WL_DBG((" vendor info not present \n")); - } - - if (*(temp_data + 6) == NAN_VENDOR_TYPE_RTT) { - temp_data += NAN_VENDOR_HDR_SIZE; - ea = (struct ether_addr *)temp_data; - temp_data += ETHER_ADDR_LEN; - mapcontrol = *temp_data++; - proto = *temp_data++; - bitmap = *(uint32 *)temp_data; - temp_data += 4; - chanspec = *(chanspec_t *)temp_data; - ptr += sprintf(ptr, " "BITMAP_PREFIX"0x%x "CHAN_PREFIX"%d/%s", - bitmap, wf_chspec_ctlchan(chanspec), - wf_chspec_to_bw_str(chanspec)); - WL_DBG((" bitmap: 0x%x channel: %d bandwidth: %s \n", bitmap, - wf_chspec_ctlchan(chanspec), - wf_chspec_to_bw_str(chanspec))); - } - } - break; - case WL_NAN_EVENT_REPLIED: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " - MAC_ADDR_PREFIX MACF, nan_event_str[event_num], - tlv_data.pub_id, ETHER_TO_MACF(tlv_data.mac_addr)); - break; - case WL_NAN_EVENT_TERMINATED: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d ", - nan_event_str[event_num], tlv_data.pub_id); - break; - case WL_NAN_EVENT_RECEIVE: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " - MAC_ADDR_PREFIX MACF, nan_event_str[event_num], - tlv_data.pub_id, ETHER_TO_MACF(tlv_data.mac_addr)); - if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) { - WL_DBG((" service info present \n")); - if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) { - WL_ERR((" service info length = %d\n", - tlv_data.svc_info.dlen)); - WL_ERR((" insufficent buffer to copy service info \n")); - ret = -EOVERFLOW; - goto fail; - } - ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX); - ptr += bcm_format_hex(ptr, tlv_data.svc_info.data, - tlv_data.svc_info.dlen); - } else { - WL_DBG((" service info not present \n")); - } - break; - case WL_NAN_EVENT_SCAN_COMPLETE: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, - nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; - case WL_NAN_EVENT_STATUS_CHG: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, - nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; - case WL_NAN_EVENT_MERGE: - ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, - nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); - break; - default: - WL_ERR((" unknown event \n")); - break; - } - - -fail: - if (buf) { - kfree(buf); - } - if (tlv_data.svc_info.data) { - kfree(tlv_data.svc_info.data); - tlv_data.svc_info.data = NULL; - tlv_data.svc_info.dlen = 0; - } - if (tlv_data.vend_info.data) { - kfree(tlv_data.vend_info.data); - tlv_data.vend_info.data = NULL; - tlv_data.vend_info.dlen = 0; - } - - return ret; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h deleted file mode 100755 index bec3b72be0b0..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Neighbor Awareness Networking - * - * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgnan.h 487532 2014-06-26 05:09:36Z $ - */ - -#ifndef _wl_cfgnan_h_ -#define _wl_cfgnan_h_ - -#define NAN_IOCTL_BUF_SIZE 512 -#define NAN_EVENT_STR_MAX_LEN 30 -#define NAN_EVENT_NAME_MAX_LEN 40 -#define NAN_CONFIG_ATTR_MAX_LEN 24 -#define NAN_RTT_IOVAR_BUF_SIZE 1024 -#define WL_NAN_EVENT_CLEAR_BIT 32 -#define NAN_EVENT_MASK_ALL 0x7fffffff - -#define NAN_INVALID_ID(id) ((id > 255) ? true : false) -#define NAN_INVALID_ROLE(role) ((role > WL_NAN_ROLE_ANCHOR_MASTER) ? true : false) -#define NAN_INVALID_CHANSPEC(chanspec) ((chanspec == INVCHANSPEC) || \ - (chanspec == 0) ? true : false) -#define NAN_INVALID_EVENT(num) (((num < WL_NAN_EVENT_START) || \ - (num >= WL_NAN_EVENT_INVALID)) ? true : false) -#define NAN_INVALID_PROXD_EVENT(num) ((num != WLC_E_PROXD_NAN_EVENT) ? \ - true : false) -#define NAN_EVENT_BIT(event) (1U << (event - WL_NAN_EVENT_START)) - -#define SUPP_EVENT_PREFIX "CTRL-EVENT-" -#define EVENT_RTT_STATUS_STR "NAN-RTT-STATUS" - -#define TIMESTAMP_PREFIX "TSF=" /* timestamp */ -#define AMR_PREFIX "AMR=" /* anchor master rank */ -#define DISTANCE_PREFIX "DIST=" /* distance */ -#define ATTR_PREFIX "ATTR=" /* attribute */ -#define ROLE_PREFIX "ROLE=" /* role */ -#define CHAN_PREFIX "CHAN=" /* channel */ -#define BITMAP_PREFIX "BMAP=" /* bitmap */ -#define DEBUG_PREFIX "DEBUG=" /* debug enable/disable flag */ -#define DW_LEN_PREFIX "DW_LEN=" /* discovery window length */ -#define DW_INT_PREFIX "DW_INT=" /* discovery window interval */ -#define STATUS_PREFIX "STATUS=" /* status */ -#define PUB_ID_PREFIX "PUB_ID=" /* publisher id */ -#define SUB_ID_PREFIX "SUB_ID=" /* subscriber id */ -#define PUB_PR_PREFIX "PUB_PR=" /* publish period */ -#define PUB_INT_PREFIX "PUB_INT=" /* publish interval (ttl) */ -#define CLUS_ID_PREFIX "CLUS_ID=" /* cluster id */ -#define IF_ADDR_PREFIX "IF_ADDR=" /* IF address */ -#define MAC_ADDR_PREFIX "MAC_ADDR=" /* mac address */ -#define SVC_HASH_PREFIX "SVC_HASH=" /* service hash */ -#define SVC_INFO_PREFIX "SVC_INFO=" /* service information */ -#define HOP_COUNT_PREFIX "HOP_COUNT=" /* hop count */ -#define MASTER_PREF_PREFIX "MASTER_PREF=" /* master preference */ -#define ACTIVE_OPTION "ACTIVE" /* Active Subscribe. */ -#define SOLICITED_OPTION "SOLICITED" /* Solicited Publish. */ -#define UNSOLICITED_OPTION "UNSOLICITED" /* Unsolicited Publish. */ -/* anchor master beacon transmission time */ -#define AMBTT_PREFIX "AMBTT=" -/* passive scan period for cluster merge */ -#define SCAN_PERIOD_PREFIX "SCAN_PERIOD=" -/* passive scan interval for cluster merge */ -#define SCAN_INTERVAL_PREFIX "SCAN_INTERVAL=" -#define BCN_INTERVAL_PREFIX "BCN_INTERVAL=" - -typedef struct nan_str_data { - u8 *data; - u32 dlen; -} nan_str_data_t; - -typedef struct nan_config_attr { - char name[NAN_CONFIG_ATTR_MAX_LEN]; /* attribute name */ - u16 type; /* attribute xtlv type */ -} nan_config_attr_t; - -typedef struct nan_cmd_data { - nan_config_attr_t attr; /* set config attributes */ - nan_str_data_t svc_hash; /* service hash */ - nan_str_data_t svc_info; /* service information */ - struct ether_addr mac_addr; /* mac address */ - struct ether_addr clus_id; /* cluster id */ - struct ether_addr if_addr; /* if addr */ - u32 beacon_int; /* beacon interval */ - u32 pub_int; /* publish interval (ttl) */ - u32 pub_pr; /* publish period */ - u32 bmap; /* bitmap */ - u32 role; /* role */ - u16 pub_id; /* publisher id */ - u16 sub_id; /* subscriber id */ - uint32 flags; /* Flag bits */ - u16 dw_len; /* discovery window length */ - u16 master_pref; /* master preference */ - chanspec_t chanspec; /* channel */ - u8 debug_flag; /* debug enable/disable flag */ -} nan_cmd_data_t; - -typedef int (nan_func_t)(struct net_device *ndev, struct bcm_cfg80211 *cfg, - char *cmd, nan_cmd_data_t *cmd_data); - -typedef struct nan_cmd { - const char *name; /* command name */ - nan_func_t *func; /* command hadler */ -} nan_cmd_t; - -typedef struct nan_event_hdr { - u16 event_subtype; - u32 flags; /* future use */ -} nan_event_hdr_t; - -typedef struct wl_nan_tlv_data { - wl_nan_status_t nstatus; /* status data */ - wl_nan_disc_params_t params; /* discovery parameters */ - struct ether_addr mac_addr; /* peer mac address */ - struct ether_addr clus_id; /* cluster id */ - nan_str_data_t svc_info; /* service info */ - nan_str_data_t vend_info; /* vendor info */ - /* anchor master beacon transmission time */ - u32 ambtt; - u32 dev_role; /* device role */ - u16 inst_id; /* instance id */ - u16 pub_id; /* publisher id */ - u16 sub_id; /* subscriber id */ - u16 master_pref; /* master preference */ - chanspec_t chanspec; /* channel */ - u8 amr[NAN_MASTER_RANK_LEN]; /* anchor master role */ - u8 svc_name[WL_NAN_SVC_HASH_LEN]; /* service name */ - u8 hop_count; /* hop count */ - u8 enabled; /* nan status flag */ - nan_scan_params_t scan_params; /* scan_param */ -} wl_nan_tlv_data_t; - -extern int wl_cfgnan_set_vars_cbfn(void *ctx, uint8 *tlv_buf, - uint16 type, uint16 len); -extern int wl_cfgnan_enable_events(struct net_device *ndev, - struct bcm_cfg80211 *cfg); -extern int wl_cfgnan_start_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_stop_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_support_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_status_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_pub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_sub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_cancel_pub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_cancel_sub_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_transmit_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_set_config_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_rtt_config_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_rtt_find_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_debug_handler(struct net_device *ndev, - struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); -extern int wl_cfgnan_cmd_handler(struct net_device *dev, - struct bcm_cfg80211 *cfg, char *cmd, int cmd_len); -extern s32 wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -extern s32 wl_cfgnan_notify_proxd_status(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); - -#endif /* _wl_cfgnan_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c deleted file mode 100755 index d6c063f22656..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c +++ /dev/null @@ -1,2726 +0,0 @@ -/* - * Linux cfgp2p driver - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgp2p.c 711630 2017-07-19 04:16:07Z $ - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -static s8 scanparambuf[WLC_IOCTL_SMLEN]; -static s8 g_mgmt_ie_buf[2048]; -static bool -wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); - -static u32 -wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag, - s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd); -static s32 wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, - struct wireless_dev *wdev, bool notify); - -#if defined(WL_ENABLE_P2P_IF) -static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); -static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); -static int wl_cfgp2p_if_open(struct net_device *net); -static int wl_cfgp2p_if_stop(struct net_device *net); - -static const struct net_device_ops wl_cfgp2p_if_ops = { - .ndo_open = wl_cfgp2p_if_open, - .ndo_stop = wl_cfgp2p_if_stop, - .ndo_do_ioctl = wl_cfgp2p_do_ioctl, - .ndo_start_xmit = wl_cfgp2p_start_xmit, -}; -#endif /* WL_ENABLE_P2P_IF */ - -#if defined(WL_NEWCFG_PRIVCMD_SUPPORT) -static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); -static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); - -static int wl_cfgp2p_if_dummy(struct net_device *net) -{ - return 0; -} - -static const struct net_device_ops wl_cfgp2p_if_ops = { - .ndo_open = wl_cfgp2p_if_dummy, - .ndo_stop = wl_cfgp2p_if_dummy, - .ndo_do_ioctl = wl_cfgp2p_do_ioctl, - .ndo_start_xmit = wl_cfgp2p_start_xmit, -}; -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - -bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) -{ - wifi_p2p_pub_act_frame_t *pact_frm; - - if (frame == NULL) - return false; - pact_frm = (wifi_p2p_pub_act_frame_t *)frame; - if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1) - return false; - - if (pact_frm->category == P2P_PUB_AF_CATEGORY && - pact_frm->action == P2P_PUB_AF_ACTION && - pact_frm->oui_type == P2P_VER && - memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) { - return true; - } - - return false; -} - -bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) -{ - wifi_p2p_action_frame_t *act_frm; - - if (frame == NULL) - return false; - act_frm = (wifi_p2p_action_frame_t *)frame; - if (frame_len < sizeof(wifi_p2p_action_frame_t) -1) - return false; - - if (act_frm->category == P2P_AF_CATEGORY && - act_frm->type == P2P_VER && - memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) { - return true; - } - - return false; -} - -#define GAS_RESP_LEN 2 -#define DOUBLE_TLV_BODY_OFF 4 -#define GAS_RESP_OFFSET 4 -#define GAS_CRESP_OFFSET 5 - -bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len) -{ - bcm_tlv_t *ie = (bcm_tlv_t *)data; - u8 *frame = NULL; - u16 id, flen; - - /* Skipped first ANQP Element, if frame has anqp elemnt */ - ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID); - - if (ie == NULL) - return false; - - frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN; - id = ((u16) (((frame)[1] << 8) | (frame)[0])); - flen = ((u16) (((frame)[3] << 8) | (frame)[2])); - - /* If the contents match the OUI and the type */ - if (flen >= WFA_OUI_LEN + 1 && - id == P2PSD_GAS_NQP_INFOID && - !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) && - subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) { - return true; - } - - return false; -} - -bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) -{ - - wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; - - if (frame == NULL) - return false; - - sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; - if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)) - return false; - if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) - return false; - - if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) - return true; - else - return false; -} -void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel) -{ - wifi_p2p_pub_act_frame_t *pact_frm; - wifi_p2p_action_frame_t *act_frm; - wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; - if (!frame || frame_len <= 2) - return; - - if (wl_cfgp2p_is_pub_action(frame, frame_len)) { - pact_frm = (wifi_p2p_pub_act_frame_t *)frame; - switch (pact_frm->subtype) { - case P2P_PAF_GON_REQ: - CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_GON_RSP: - CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_GON_CONF: - CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_INVITE_REQ: - CFGP2P_ACTION(("%s P2P Invitation Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_INVITE_RSP: - CFGP2P_ACTION(("%s P2P Invitation Response Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_DEVDIS_REQ: - CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_DEVDIS_RSP: - CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_PROVDIS_REQ: - CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_PAF_PROVDIS_RSP: - CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - default: - CFGP2P_ACTION(("%s Unknown P2P Public Action Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - - } - - } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) { - act_frm = (wifi_p2p_action_frame_t *)frame; - switch (act_frm->subtype) { - case P2P_AF_NOTICE_OF_ABSENCE: - CFGP2P_ACTION(("%s P2P Notice of Absence Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_AF_PRESENCE_REQ: - CFGP2P_ACTION(("%s P2P Presence Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_AF_PRESENCE_RSP: - CFGP2P_ACTION(("%s P2P Presence Response Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - case P2P_AF_GO_DISC_REQ: - CFGP2P_ACTION(("%s P2P Discoverability Request Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - break; - default: - CFGP2P_ACTION(("%s Unknown P2P Action Frame," - " channel=%d\n", (tx)? "TX": "RX", channel)); - } - - } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { - sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; - switch (sd_act_frm->action) { - case P2PSD_ACTION_ID_GAS_IREQ: - CFGP2P_ACTION(("%s P2P GAS Initial Request," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - break; - case P2PSD_ACTION_ID_GAS_IRESP: - CFGP2P_ACTION(("%s P2P GAS Initial Response," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - break; - case P2PSD_ACTION_ID_GAS_CREQ: - CFGP2P_ACTION(("%s P2P GAS Comback Request," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - break; - case P2PSD_ACTION_ID_GAS_CRESP: - CFGP2P_ACTION(("%s P2P GAS Comback Response," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - break; - default: - CFGP2P_ACTION(("%s Unknown P2P GAS Frame," - " channel=%d\n", (tx)? "TX" : "RX", channel)); - } - - - } -} - -/* - * Initialize variables related to P2P - * - */ -s32 -wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg) -{ - if (!(cfg->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) { - CFGP2P_ERR(("struct p2p_info allocation failed\n")); - return -ENOMEM; - } -#define INIT_IE(IE_TYPE, BSS_TYPE) \ - do { \ - memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ - sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ - wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ - } while (0); - - INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY); - INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE); - INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE); - INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE); - INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE); - INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE); - INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION); - INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION); - INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION); - INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION); - INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION); -#undef INIT_IE - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg); - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0; - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = NULL; - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = 0; - return BCME_OK; - -} -/* - * Deinitialize variables related to P2P - * - */ -void -wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg) -{ - CFGP2P_DBG(("In\n")); - if (cfg->p2p) { - kfree(cfg->p2p); - cfg->p2p = NULL; - } - cfg->p2p_supported = 0; -} -/* - * Set P2P functions into firmware - */ -s32 -wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg) -{ - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } }; - s32 ret = BCME_OK; - s32 val = 0; - /* Do we have to check whether APSTA is enabled or not ? */ - ret = wldev_iovar_getint(ndev, "apsta", &val); - if (ret < 0) { - CFGP2P_ERR(("get apsta error %d\n", ret)); - return ret; - } - if (val == 0) { - val = 1; - ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); - if (ret < 0) { - CFGP2P_ERR(("WLC_DOWN error %d\n", ret)); - return ret; - } - wldev_iovar_setint(ndev, "apsta", val); - ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); - if (ret < 0) { - CFGP2P_ERR(("WLC_UP error %d\n", ret)); - return ret; - } - } - - /* In case of COB type, firmware has default mac address - * After Initializing firmware, we have to set current mac address to - * firmware for P2P device address - */ - ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr, - sizeof(null_eth_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &cfg->ioctl_buf_sync); - if (ret && ret != BCME_UNSUPPORTED) { - CFGP2P_ERR(("failed to update device address ret %d\n", ret)); - } - return ret; -} - -/* Create a new P2P BSS. - * Parameters: - * @mac : MAC address of the BSS to create - * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT - * @chspec : chspec to use if creating a GO BSS. - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, - chanspec_t chspec) -{ - wl_p2p_if_t ifreq; - s32 err; - u32 scb_timeout = WL_SCB_TIMEOUT; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - - ifreq.type = if_type; - ifreq.chspec = chspec; - memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); - - CFGP2P_DBG(("---cfg p2p_ifadd "MACDBG" %s %u\n", - MAC2STRDBG(ifreq.addr.octet), - (if_type == WL_P2P_IF_GO) ? "go" : "client", - (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); - - err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (unlikely(err < 0)) - printk("'cfg p2p_ifadd' error %d\n", err); - else if (if_type == WL_P2P_IF_GO) { - err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); - if (unlikely(err < 0)) - printk("'cfg scb_timeout' error %d\n", err); - } - return err; -} - -/* Disable a P2P BSS. - * Parameters: - * @mac : MAC address of the BSS to disable - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac) -{ - s32 ret; - struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); - - CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdis "MACDBG"\n", - netdev->ifindex, MAC2STRDBG(mac->octet))); - ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(ret < 0)) { - printk("'cfg p2p_ifdis' error %d\n", ret); - } - return ret; -} - -/* Delete a P2P BSS. - * Parameters: - * @mac : MAC address of the BSS to delete - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac) -{ - s32 ret; - struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); - - CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdel "MACDBG"\n", - netdev->ifindex, MAC2STRDBG(mac->octet))); - ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(ret < 0)) { - printk("'cfg p2p_ifdel' error %d\n", ret); - } - return ret; -} - -/* Change a P2P Role. - * Parameters: - * @mac : MAC address of the BSS to change a role - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, - chanspec_t chspec) -{ - wl_p2p_if_t ifreq; - s32 err; - u32 scb_timeout = WL_SCB_TIMEOUT; - - struct net_device *netdev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); - - ifreq.type = if_type; - ifreq.chspec = chspec; - memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); - - CFGP2P_INFO(("---cfg p2p_ifchange "MACDBG" %s %u" - " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet), - (if_type == WL_P2P_IF_GO) ? "go" : "client", - (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT, - ifreq.chspec)); - - err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (unlikely(err < 0)) { - printk("'cfg p2p_ifupd' error %d\n", err); - } else if (if_type == WL_P2P_IF_GO) { - err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); - if (unlikely(err < 0)) - printk("'cfg scb_timeout' error %d\n", err); - } - return err; -} - - -/* Get the index of a created P2P BSS. - * Parameters: - * @mac : MAC address of the created BSS - * @index : output: index of created BSS - * Returns 0 if success. - */ -s32 -wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index) -{ - s32 ret; - u8 getbuf[64]; - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - - CFGP2P_INFO(("---cfg p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet))); - - ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, - sizeof(getbuf), wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY), NULL); - - if (ret == 0) { - memcpy(index, getbuf, sizeof(s32)); - CFGP2P_INFO(("---cfg p2p_if ==> %d\n", *index)); - } - - return ret; -} - -static s32 -wl_cfgp2p_set_discovery(struct bcm_cfg80211 *cfg, s32 on) -{ - s32 ret = BCME_OK; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - CFGP2P_DBG(("enter\n")); - - ret = wldev_iovar_setint(ndev, "p2p_disc", on); - - if (unlikely(ret < 0)) { - CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret)); - } - - return ret; -} - -/* Set the WL driver's P2P mode. - * Parameters : - * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}. - * @channel : the channel to listen - * @listen_ms : the time (milli seconds) to wait - * @bssidx : bss index for BSSCFG - * Returns 0 if success - */ - -s32 -wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, u32 channel, u16 listen_ms, int bssidx) -{ - wl_p2p_disc_st_t discovery_mode; - s32 ret; - struct net_device *dev; - CFGP2P_DBG(("enter\n")); - - if (unlikely(bssidx == WL_INVALID)) { - CFGP2P_ERR((" %d index out of range\n", bssidx)); - return -1; - } - - dev = wl_cfgp2p_find_ndev(cfg, bssidx); - if (unlikely(dev == NULL)) { - CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx)); - return BCME_NOTFOUND; - } - - /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */ - discovery_mode.state = mode; - discovery_mode.chspec = wl_ch_host_to_driver(channel); - discovery_mode.dwell = listen_ms; - ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode, - sizeof(discovery_mode), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, - bssidx, &cfg->ioctl_buf_sync); - - return ret; -} - -/* Get the index of the P2P Discovery BSS */ -static s32 -wl_cfgp2p_get_disc_idx(struct bcm_cfg80211 *cfg, s32 *index) -{ - s32 ret; - struct net_device *dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); - - ret = wldev_iovar_getint(dev, "p2p_dev", index); - CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret)); - - if (unlikely(ret < 0)) { - CFGP2P_ERR(("'p2p_dev' error %d\n", ret)); - return ret; - } - return ret; -} - -s32 -wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg) -{ - - s32 index = 0; - s32 ret = BCME_OK; - - CFGP2P_DBG(("enter\n")); - - if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) != 0) { - CFGP2P_ERR(("do nothing, already initialized\n")); - return ret; - } - - ret = wl_cfgp2p_set_discovery(cfg, 1); - if (ret < 0) { - CFGP2P_ERR(("set discover error\n")); - return ret; - } - /* Enable P2P Discovery in the WL Driver */ - ret = wl_cfgp2p_get_disc_idx(cfg, &index); - - if (ret < 0) { - return ret; - } - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = index; - - /* Set the initial discovery state to SCAN */ - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - - if (unlikely(ret != 0)) { - CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); - wl_cfgp2p_set_discovery(cfg, 0); - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; - return 0; - } - return ret; -} - -/* Deinitialize P2P Discovery - * Parameters : - * @cfg : wl_private data - * Returns 0 if succes - */ -static s32 -wl_cfgp2p_deinit_discovery(struct bcm_cfg80211 *cfg) -{ - s32 ret = BCME_OK; - CFGP2P_DBG(("enter\n")); - - if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) == 0) { - CFGP2P_ERR(("do nothing, not initialized\n")); - return -1; - } - /* Set the discovery state to SCAN */ - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */ - ret = wl_cfgp2p_set_discovery(cfg, 0); - - /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver - * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery - * BSS. - */ - - /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we - * have no discovery BSS. - */ - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = WL_INVALID; - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; - - return ret; - -} -/* Enable P2P Discovery - * Parameters: - * @cfg : wl_private data - * @ie : probe request ie (WPS IE + P2P IE) - * @ie_len : probe request ie length - * Returns 0 if success. - */ -s32 -wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, - const u8 *ie, u32 ie_len) -{ - s32 ret = BCME_OK; - s32 bssidx; - - if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { - CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n")); - goto set_ie; - } - - wl_set_p2p_status(cfg, DISCOVERY_ON); - - CFGP2P_DBG(("enter\n")); - - ret = wl_cfgp2p_init_discovery(cfg); - if (unlikely(ret < 0)) { - CFGP2P_ERR((" init discovery error %d\n", ret)); - goto exit; - } - /* Set wsec to any non-zero value in the discovery bsscfg to ensure our - * P2P probe responses have the privacy bit set in the 802.11 WPA IE. - * Some peer devices may not initiate WPS with us if this bit is not set. - */ - ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), - "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - if (unlikely(ret < 0)) { - CFGP2P_ERR((" wsec error %d\n", ret)); - } -set_ie: - if (ie_len) { - if (bcmcfg_to_prmry_ndev(cfg) == dev) { - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - } else if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { - WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); - return BCME_ERROR; - } - - ret = wl_cfgp2p_set_management_ie(cfg, dev, - bssidx, - VNDR_IE_PRBREQ_FLAG, ie, ie_len); - - if (unlikely(ret < 0)) { - CFGP2P_ERR(("set probreq ie occurs error %d\n", ret)); - goto exit; - } - } -exit: - return ret; -} - -/* Disable P2P Discovery - * Parameters: - * @cfg : wl_private_data - * Returns 0 if success. - */ -s32 -wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg) -{ - s32 ret = BCME_OK; - CFGP2P_DBG((" enter\n")); - wl_clr_p2p_status(cfg, DISCOVERY_ON); - - if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) == 0) { - CFGP2P_ERR((" do nothing, not initialized\n")); - goto exit; - } - - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - - if (unlikely(ret < 0)) { - - CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); - } - /* Do a scan abort to stop the driver's scan engine in case it is still - * waiting out an action frame tx dwell time. - */ - wl_clr_p2p_status(cfg, DISCOVERY_ON); - ret = wl_cfgp2p_deinit_discovery(cfg); - -exit: - return ret; -} - -s32 -wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, - u32 num_chans, u16 *channels, - s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, - p2p_scan_purpose_t p2p_scan_purpose) -{ - s32 ret = BCME_OK; - s32 memsize; - s32 eparams_size; - u32 i; - s8 *memblk; - wl_p2p_scan_t *p2p_params; - wl_escan_params_t *eparams; - wlc_ssid_t ssid; - /* Scan parameters */ -#define P2PAPI_SCAN_NPROBES 1 -#define P2PAPI_SCAN_DWELL_TIME_MS 80 -#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 -#define P2PAPI_SCAN_HOME_TIME_MS 60 -#define P2PAPI_SCAN_NPROBS_TIME_MS 30 -#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 - - struct net_device *pri_dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); - /* Allocate scan params which need space for 3 channels and 0 ssids */ - eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + - OFFSETOF(wl_escan_params_t, params)) + - num_chans * sizeof(eparams->params.channel_list[0]); - - memsize = sizeof(wl_p2p_scan_t) + eparams_size; - memblk = scanparambuf; - if (memsize > sizeof(scanparambuf)) { - CFGP2P_ERR((" scanpar buf too small (%u > %zu)\n", - memsize, sizeof(scanparambuf))); - return -1; - } - memset(memblk, 0, memsize); - memset(cfg->ioctl_buf, 0, WLC_IOCTL_MAXLEN); - if (search_state == WL_P2P_DISC_ST_SEARCH) { - /* - * If we in SEARCH STATE, we don't need to set SSID explictly - * because dongle use P2P WILDCARD internally by default - */ - wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx); - /* use null ssid */ - ssid.SSID_len = 0; - memset(&ssid.SSID, 0, sizeof(ssid.SSID)); - } else if (search_state == WL_P2P_DISC_ST_SCAN) { - /* SCAN STATE 802.11 SCAN - * WFD Supplicant has p2p_find command with (type=progressive, type= full) - * So if P2P_find command with type=progressive, - * we have to set ssid to P2P WILDCARD because - * we just do broadcast scan unless setting SSID - */ - wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); - /* use wild card ssid */ - ssid.SSID_len = WL_P2P_WILDCARD_SSID_LEN; - memset(&ssid.SSID, 0, sizeof(ssid.SSID)); - memcpy(&ssid.SSID, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN); - } else { - CFGP2P_ERR((" invalid search state %d\n", search_state)); - return -1; - } - - - /* Fill in the P2P scan structure at the start of the iovar param block */ - p2p_params = (wl_p2p_scan_t*) memblk; - p2p_params->type = 'E'; - /* Fill in the Scan structure that follows the P2P scan structure */ - eparams = (wl_escan_params_t*) (p2p_params + 1); - eparams->params.bss_type = DOT11_BSSTYPE_ANY; - if (active) - eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE; - else - eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE; - - if (tx_dst_addr == NULL) - memcpy(&eparams->params.bssid, ðer_bcast, ETHER_ADDR_LEN); - else - memcpy(&eparams->params.bssid, tx_dst_addr, ETHER_ADDR_LEN); - - if (ssid.SSID_len) - memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); - - eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); - - switch (p2p_scan_purpose) { - case P2P_SCAN_SOCIAL_CHANNEL: - eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); - break; - case P2P_SCAN_AFX_PEER_NORMAL: - case P2P_SCAN_AFX_PEER_REDUCED: - eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); - break; - case P2P_SCAN_CONNECT_TRY: - eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); - break; - default : - if (wl_get_drv_status_all(cfg, CONNECTED)) - eparams->params.active_time = -1; - else - eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); - break; - } - - if (p2p_scan_purpose == P2P_SCAN_CONNECT_TRY) - eparams->params.nprobes = htod32(eparams->params.active_time / - WL_SCAN_JOIN_PROBE_INTERVAL_MS); - else - eparams->params.nprobes = htod32((eparams->params.active_time / - P2PAPI_SCAN_NPROBS_TIME_MS)); - - - if (eparams->params.nprobes <= 0) - eparams->params.nprobes = 1; - CFGP2P_DBG(("nprobes # %d, active_time %d\n", - eparams->params.nprobes, eparams->params.active_time)); - eparams->params.passive_time = htod32(-1); - eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | - (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); - - for (i = 0; i < num_chans; i++) { - eparams->params.channel_list[i] = wl_ch_host_to_driver(channels[i]); - } - eparams->version = htod32(ESCAN_REQ_VERSION); - eparams->action = htod16(action); - wl_escan_set_sync_id(eparams->sync_id, cfg); - wl_escan_set_type(cfg, WL_SCANTYPE_P2P); - CFGP2P_INFO(("SCAN CHANNELS : ")); - - for (i = 0; i < num_chans; i++) { - if (i == 0) CFGP2P_INFO(("%d", channels[i])); - else CFGP2P_INFO((",%d", channels[i])); - } - - CFGP2P_INFO(("\n")); - - ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan", - memblk, memsize, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - if (ret == BCME_OK) - wl_set_p2p_status(cfg, SCANNING); - return ret; -} - -/* search function to reach at common channel to send action frame - * Parameters: - * @cfg : wl_private data - * @ndev : net device for bssidx - * @bssidx : bssidx for BSS - * Returns 0 if success. - */ -s32 -wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, - s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr) -{ - s32 ret = 0; - u32 chan_cnt = 0; - u16 *default_chan_list = NULL; - p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_AFX_PEER_NORMAL; - if (!p2p_is_on(cfg) || ndev == NULL || bssidx == WL_INVALID) - return -BCME_ERROR; - WL_TRACE_HW4((" Enter\n")); - if (bssidx == wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY)) - bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - if (channel) - chan_cnt = AF_PEER_SEARCH_CNT; - else - chan_cnt = SOCIAL_CHAN_CNT; - default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL); - if (default_chan_list == NULL) { - CFGP2P_ERR(("channel list allocation failed \n")); - ret = -ENOMEM; - goto exit; - } - if (channel) { - u32 i; - /* insert same channel to the chan_list */ - for (i = 0; i < chan_cnt; i++) { - default_chan_list[i] = channel; - } - } else { - default_chan_list[0] = SOCIAL_CHAN_1; - default_chan_list[1] = SOCIAL_CHAN_2; - default_chan_list[2] = SOCIAL_CHAN_3; - } - ret = wl_cfgp2p_escan(cfg, ndev, true, chan_cnt, - default_chan_list, WL_P2P_DISC_ST_SEARCH, - WL_SCAN_ACTION_START, bssidx, NULL, p2p_scan_purpose); - kfree(default_chan_list); -exit: - return ret; -} - -/* Check whether pointed-to IE looks like WPA. */ -#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) -/* Check whether pointed-to IE looks like WPS. */ -#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) -/* Check whether the given IE looks like WFA P2P IE. */ -#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) -/* Check whether the given IE looks like WFA WFDisplay IE. */ -#ifndef WFA_OUI_TYPE_WFD -#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ -#endif -#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) - -static s32 -wl_cfgp2p_parse_vndr_ies(u8 *parse, u32 len, - struct parsed_vndr_ies *vndr_ies) -{ - s32 err = BCME_OK; - vndr_ie_t *vndrie; - bcm_tlv_t *ie; - struct parsed_vndr_ie_info *parsed_info; - u32 count = 0; - s32 remained_len; - - remained_len = (s32)len; - memset(vndr_ies, 0, sizeof(*vndr_ies)); - - WL_INFO(("---> len %d\n", len)); - ie = (bcm_tlv_t *) parse; - if (!bcm_valid_tlv(ie, remained_len)) - ie = NULL; - while (ie) { - if (count >= MAX_VNDR_IE_NUMBER) - break; - if (ie->id == DOT11_MNG_VS_ID) { - vndrie = (vndr_ie_t *) ie; - /* len should be bigger than OUI length + one data length at least */ - if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) { - CFGP2P_ERR(("%s: invalid vndr ie. length is too small %d\n", - __FUNCTION__, vndrie->len)); - goto end; - } - /* if wpa or wme ie, do not add ie */ - if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) && - ((vndrie->data[0] == WPA_OUI_TYPE) || - (vndrie->data[0] == WME_OUI_TYPE))) { - CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n")); - goto end; - } - - parsed_info = &vndr_ies->ie_info[count++]; - - /* save vndr ie information */ - parsed_info->ie_ptr = (char *)vndrie; - parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN); - memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t)); - - vndr_ies->count = count; - - CFGP2P_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x \n", - parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1], - parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0])); - } -end: - ie = bcm_next_tlv(ie, &remained_len); - } - return err; -} - - -/* Delete and Set a management vndr ie to firmware - * Parameters: - * @cfg : wl_private data - * @ndev : net device for bssidx - * @bssidx : bssidx for BSS - * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, - * VNDR_IE_ASSOCREQ_FLAG) - * @ie : VNDR IE (such as P2P IE , WPS IE) - * @ie_len : VNDR IE Length - * Returns 0 if success. - */ - -s32 -wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, - s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) -{ - s32 ret = BCME_OK; - u8 *curr_ie_buf = NULL; - u8 *mgmt_ie_buf = NULL; - u32 mgmt_ie_buf_len = 0; - u32 *mgmt_ie_len = 0; - u32 del_add_ie_buf_len = 0; - u32 total_ie_buf_len = 0; - u32 parsed_ie_buf_len = 0; - struct parsed_vndr_ies old_vndr_ies; - struct parsed_vndr_ies new_vndr_ies; - s32 i; - u8 *ptr; - s32 type = -1; - s32 remained_buf_len; -#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie) -#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie_len) - memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf)); - curr_ie_buf = g_mgmt_ie_buf; - CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag)); - if (cfg->p2p != NULL) { - if (wl_cfgp2p_find_type(cfg, bssidx, &type)) { - CFGP2P_ERR(("cannot find type from bssidx : %d\n", bssidx)); - return BCME_ERROR; - } - - switch (pktflag) { - case VNDR_IE_PRBREQ_FLAG : - mgmt_ie_buf = IE_TYPE(probe_req, type); - mgmt_ie_len = &IE_TYPE_LEN(probe_req, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, type)); - break; - case VNDR_IE_PRBRSP_FLAG : - mgmt_ie_buf = IE_TYPE(probe_res, type); - mgmt_ie_len = &IE_TYPE_LEN(probe_res, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, type)); - break; - case VNDR_IE_ASSOCREQ_FLAG : - mgmt_ie_buf = IE_TYPE(assoc_req, type); - mgmt_ie_len = &IE_TYPE_LEN(assoc_req, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, type)); - break; - case VNDR_IE_ASSOCRSP_FLAG : - mgmt_ie_buf = IE_TYPE(assoc_res, type); - mgmt_ie_len = &IE_TYPE_LEN(assoc_res, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, type)); - break; - case VNDR_IE_BEACON_FLAG : - mgmt_ie_buf = IE_TYPE(beacon, type); - mgmt_ie_len = &IE_TYPE_LEN(beacon, type); - mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, type)); - break; - default: - mgmt_ie_buf = NULL; - mgmt_ie_len = NULL; - CFGP2P_ERR(("not suitable type\n")); - return BCME_ERROR; - } - } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { - if (cfg->ap_info == NULL) { - CFGP2P_ERR(("hostapd ap_info null ptr refrence while setting IE\n")); - return BCME_ERROR; - - } - switch (pktflag) { - case VNDR_IE_PRBRSP_FLAG : - mgmt_ie_buf = cfg->ap_info->probe_res_ie; - mgmt_ie_len = &cfg->ap_info->probe_res_ie_len; - mgmt_ie_buf_len = sizeof(cfg->ap_info->probe_res_ie); - break; - case VNDR_IE_BEACON_FLAG : - mgmt_ie_buf = cfg->ap_info->beacon_ie; - mgmt_ie_len = &cfg->ap_info->beacon_ie_len; - mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie); - break; - case VNDR_IE_ASSOCRSP_FLAG : - /* WPS-AP WSC2.0 assoc res includes wps_ie */ - mgmt_ie_buf = cfg->ap_info->assoc_res_ie; - mgmt_ie_len = &cfg->ap_info->assoc_res_ie_len; - mgmt_ie_buf_len = sizeof(cfg->ap_info->assoc_res_ie); - break; - default: - mgmt_ie_buf = NULL; - mgmt_ie_len = NULL; - CFGP2P_ERR(("not suitable type\n")); - return BCME_ERROR; - } - bssidx = 0; - } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) { - switch (pktflag) { - case VNDR_IE_PRBREQ_FLAG : - mgmt_ie_buf = cfg->sta_info->probe_req_ie; - mgmt_ie_len = &cfg->sta_info->probe_req_ie_len; - mgmt_ie_buf_len = sizeof(cfg->sta_info->probe_req_ie); - break; - case VNDR_IE_ASSOCREQ_FLAG : - mgmt_ie_buf = cfg->sta_info->assoc_req_ie; - mgmt_ie_len = &cfg->sta_info->assoc_req_ie_len; - mgmt_ie_buf_len = sizeof(cfg->sta_info->assoc_req_ie); - break; - default: - mgmt_ie_buf = NULL; - mgmt_ie_len = NULL; - CFGP2P_ERR(("not suitable type\n")); - return BCME_ERROR; - } - bssidx = 0; - } else { - CFGP2P_ERR(("not suitable type\n")); - return BCME_ERROR; - } - - if (vndr_ie_len > mgmt_ie_buf_len) { - CFGP2P_ERR(("extra IE size too big\n")); - ret = -ENOMEM; - } else { - /* parse and save new vndr_ie in curr_ie_buff before comparing it */ - if (vndr_ie && vndr_ie_len && curr_ie_buf) { - ptr = curr_ie_buf; - - wl_cfgp2p_parse_vndr_ies((u8*)vndr_ie, - vndr_ie_len, &new_vndr_ies); - - for (i = 0; i < new_vndr_ies.count; i++) { - struct parsed_vndr_ie_info *vndrie_info = - &new_vndr_ies.ie_info[i]; - - memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr, - vndrie_info->ie_len); - parsed_ie_buf_len += vndrie_info->ie_len; - } - } - - if (mgmt_ie_buf != NULL) { - if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && - (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { - CFGP2P_INFO(("Previous mgmt IE is equals to current IE")); - goto exit; - } - - /* parse old vndr_ie */ - wl_cfgp2p_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, - &old_vndr_ies); - - /* make a command to delete old ie */ - for (i = 0; i < old_vndr_ies.count; i++) { - struct parsed_vndr_ie_info *vndrie_info = - &old_vndr_ies.ie_info[i]; - - CFGP2P_INFO(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", - vndrie_info->vndrie.id, vndrie_info->vndrie.len, - vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], - vndrie_info->vndrie.oui[2])); - - del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, - pktflag, vndrie_info->vndrie.oui, - vndrie_info->vndrie.id, - vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, - vndrie_info->ie_len - VNDR_IE_FIXED_LEN, - "del"); - - curr_ie_buf += del_add_ie_buf_len; - total_ie_buf_len += del_add_ie_buf_len; - } - } - - *mgmt_ie_len = 0; - /* Add if there is any extra IE */ - if (mgmt_ie_buf && parsed_ie_buf_len) { - ptr = mgmt_ie_buf; - - remained_buf_len = mgmt_ie_buf_len; - - /* make a command to add new ie */ - for (i = 0; i < new_vndr_ies.count; i++) { - struct parsed_vndr_ie_info *vndrie_info = - &new_vndr_ies.ie_info[i]; - - CFGP2P_INFO(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n", - vndrie_info->vndrie.id, vndrie_info->vndrie.len, - vndrie_info->ie_len - 2, - vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], - vndrie_info->vndrie.oui[2])); - - del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, - pktflag, vndrie_info->vndrie.oui, - vndrie_info->vndrie.id, - vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, - vndrie_info->ie_len - VNDR_IE_FIXED_LEN, - "add"); - - /* verify remained buf size before copy data */ - if (remained_buf_len >= vndrie_info->ie_len) { - remained_buf_len -= vndrie_info->ie_len; - } else { - CFGP2P_ERR(("no space in mgmt_ie_buf: pktflag = %d, " - "found vndr ies # = %d(cur %d), remained len %d, " - "cur mgmt_ie_len %d, new ie len = %d\n", - pktflag, new_vndr_ies.count, i, remained_buf_len, - *mgmt_ie_len, vndrie_info->ie_len)); - break; - } - - /* save the parsed IE in cfg struct */ - memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, - vndrie_info->ie_len); - *mgmt_ie_len += vndrie_info->ie_len; - - curr_ie_buf += del_add_ie_buf_len; - total_ie_buf_len += del_add_ie_buf_len; - } - } - if (total_ie_buf_len) { - ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, - total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, - bssidx, &cfg->ioctl_buf_sync); - if (ret) - CFGP2P_ERR(("vndr ie set error : %d\n", ret)); - } - } -#undef IE_TYPE -#undef IE_TYPE_LEN -exit: - return ret; -} - -/* Clear the manament IE buffer of BSSCFG - * Parameters: - * @cfg : wl_private data - * @bssidx : bssidx for BSS - * - * Returns 0 if success. - */ -s32 -wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx) -{ - - s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, - VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG}; - s32 index = -1; - s32 type = -1; - struct net_device *ndev = wl_cfgp2p_find_ndev(cfg, bssidx); -#define INIT_IE(IE_TYPE, BSS_TYPE) \ - do { \ - memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ - sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ - wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ - } while (0); - - if (bssidx < 0 || ndev == NULL) { - CFGP2P_ERR(("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev")); - return BCME_BADARG; - } - - if (wl_cfgp2p_find_type(cfg, bssidx, &type)) { - CFGP2P_ERR(("invalid argument\n")); - return BCME_BADARG; - } - for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) { - /* clean up vndr ies in dongle */ - wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, vndrie_flag[index], NULL, 0); - } - INIT_IE(probe_req, type); - INIT_IE(probe_res, type); - INIT_IE(assoc_req, type); - INIT_IE(assoc_res, type); - INIT_IE(beacon, type); - return BCME_OK; -} - - -/* Is any of the tlvs the expected entry? If - * not update the tlvs buffer pointer/length. - */ -static bool -wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type) -{ - /* If the contents match the OUI and the type */ - if (ie[TLV_LEN_OFF] >= oui_len + 1 && - !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && - type == ie[TLV_BODY_OFF + oui_len]) { - return TRUE; - } - - if (tlvs == NULL) - return FALSE; - /* point to the next ie */ - ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; - /* calculate the length of the rest of the buffer */ - *tlvs_len -= (int)(ie - *tlvs); - /* update the pointer to the start of the buffer */ - *tlvs = ie; - - return FALSE; -} - -wpa_ie_fixed_t * -wl_cfgp2p_find_wpaie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) { - return (wpa_ie_fixed_t *)ie; - } - } - return NULL; -} - -wpa_ie_fixed_t * -wl_cfgp2p_find_wpsie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) { - return (wpa_ie_fixed_t *)ie; - } - } - return NULL; -} - -wifi_p2p_ie_t * -wl_cfgp2p_find_p2pie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) { - return (wifi_p2p_ie_t *)ie; - } - } - return NULL; -} - -wifi_wfd_ie_t * -wl_cfgp2p_find_wfdie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - - while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) { - return (wifi_wfd_ie_t *)ie; - } - } - return NULL; -} -static u32 -wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag, - s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd) -{ - vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */ - s32 iecount; - u32 data_offset; - - /* Validate the pktflag parameter */ - if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | - VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | - VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) { - CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag)); - return -1; - } - - /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ - strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1); - hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - - /* Set the IE count - the buffer contains only 1 IE */ - iecount = htod32(1); - memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32)); - - /* Copy packet flags that indicate which packets will contain this IE */ - pktflag = htod32(pktflag); - memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, - sizeof(u32)); - - /* Add the IE ID to the buffer */ - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; - - /* Add the IE length to the buffer */ - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = - (uint8) VNDR_IE_MIN_LEN + datalen; - - /* Add the IE OUI to the buffer */ - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0]; - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1]; - hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2]; - - /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */ - memcpy(iebuf, &hdr, sizeof(hdr) - 1); - - /* Copy the IE data to the IE buffer */ - data_offset = - (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] - - (u8*)&hdr; - memcpy(iebuf + data_offset, data, datalen); - return data_offset + datalen; - -} - -/* - * Search the bssidx based on dev argument - * Parameters: - * @cfg : wl_private data - * @ndev : net device to search bssidx - * @bssidx : output arg to store bssidx of the bsscfg of firmware. - * Returns error - */ -s32 -wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *bssidx) -{ - u32 i; - if (ndev == NULL || bssidx == NULL) { - CFGP2P_ERR((" argument is invalid\n")); - return BCME_BADARG; - } - if (!cfg->p2p_supported) { - *bssidx = P2PAPI_BSSCFG_PRIMARY; - return BCME_OK; - } - /* we cannot find the bssidx of DISCOVERY BSS - * because the ndev is same with ndev of PRIMARY BSS. - */ - for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { - if (ndev == wl_to_p2p_bss_ndev(cfg, i)) { - *bssidx = wl_to_p2p_bss_bssidx(cfg, i); - return BCME_OK; - } - } - return BCME_BADARG; -} -struct net_device * -wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx) -{ - u32 i; - struct net_device *ndev = NULL; - if (bssidx < 0) { - CFGP2P_ERR((" bsscfg idx is invalid\n")); - goto exit; - } - - for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { - if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) { - ndev = wl_to_p2p_bss_ndev(cfg, i); - break; - } - } - -exit: - return ndev; -} -/* - * Search the driver array idx based on bssidx argument - * Parameters: - * @cfg : wl_private data - * @bssidx : bssidx which indicate bsscfg->idx of firmware. - * @type : output arg to store array idx of p2p->bss. - * Returns error - */ - -s32 -wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type) -{ - u32 i; - if (bssidx < 0 || type == NULL) { - CFGP2P_ERR((" argument is invalid\n")); - goto exit; - } - - for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { - if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) { - *type = i; - return BCME_OK; - } - } - -exit: - return BCME_BADARG; -} - -/* - * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE - */ -s32 -wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - s32 ret = BCME_OK; - struct net_device *ndev = NULL; - - if (!cfg || !cfg->p2p) - return BCME_ERROR; - - CFGP2P_DBG((" Enter\n")); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if (wl_get_p2p_status(cfg, LISTEN_EXPIRED) == 0) { - wl_set_p2p_status(cfg, LISTEN_EXPIRED); - if (timer_pending(&cfg->p2p->listen_timer)) { - del_timer_sync(&cfg->p2p->listen_timer); - } - - if (cfg->afx_hdl->is_listen == TRUE && - wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { - WL_DBG(("Listen DONE for action frame\n")); - complete(&cfg->act_frm_scan); - } -#ifdef WL_CFG80211_SYNC_GON - else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, ndev); - WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n", - jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies))); - - if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) - wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); - - complete(&cfg->wait_next_af); - } -#endif /* WL_CFG80211_SYNC_GON */ - -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL)) { -#else - if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL) || - wl_get_drv_status_all(cfg, FAKE_REMAINING_ON_CHANNEL)) { -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - WL_DBG(("Listen DONE for ramain on channel expired\n")); - wl_clr_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_clr_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - if (ndev && (ndev->ieee80211_ptr != NULL)) { -#if defined(WL_CFG80211_P2P_DEV_IF) - cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id, - &cfg->remain_on_chan, GFP_KERNEL); -#else - cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id, - &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL); -#endif /* WL_CFG80211_P2P_DEV_IF */ - } - } - if (wl_add_remove_eventmsg(bcmcfg_to_prmry_ndev(cfg), - WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) { - CFGP2P_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); - } - } else - wl_clr_p2p_status(cfg, LISTEN_EXPIRED); - - return ret; - -} - -/* - * Timer expire callback function for LISTEN - * We can't report cfg80211_remain_on_channel_expired from Timer ISR context, - * so lets do it from thread context. - */ -void -wl_cfgp2p_listen_expired(unsigned long data) -{ - wl_event_msg_t msg; - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *) data; - CFGP2P_DBG((" Enter\n")); - bzero(&msg, sizeof(wl_event_msg_t)); - msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); -#if defined(WL_ENABLE_P2P_IF) - wl_cfg80211_event(cfg->p2p_net ? cfg->p2p_net : - wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, NULL); -#else - wl_cfg80211_event(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, - NULL); -#endif /* WL_ENABLE_P2P_IF */ -} -/* - * Routine for cancelling the P2P LISTEN - */ -static s32 -wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, - struct wireless_dev *wdev, bool notify) -{ - WL_DBG(("Enter \n")); - /* Irrespective of whether timer is running or not, reset - * the LISTEN state. - */ - if (timer_pending(&cfg->p2p->listen_timer)) { - del_timer_sync(&cfg->p2p->listen_timer); - if (notify) { -#if defined(WL_CFG80211_P2P_DEV_IF) - if (wdev) - cfg80211_remain_on_channel_expired(wdev, cfg->last_roc_id, - &cfg->remain_on_chan, GFP_KERNEL); -#else - if (ndev && ndev->ieee80211_ptr) - cfg80211_remain_on_channel_expired(ndev, cfg->last_roc_id, - &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL); -#endif /* WL_CFG80211_P2P_DEV_IF */ - } - } - return 0; -} -/* - * Do a P2P Listen on the given channel for the given duration. - * A listen consists of sitting idle and responding to P2P probe requests - * with a P2P probe response. - * - * This fn assumes dongle p2p device discovery is already enabled. - * Parameters : - * @cfg : wl_private data - * @channel : channel to listen - * @duration_ms : the time (milli seconds) to wait - */ -s32 -wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms) -{ -#define EXTRA_DELAY_TIME 100 - s32 ret = BCME_OK; - struct timer_list *_timer; - s32 extra_delay; - struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); - - CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms)); - if (unlikely(wl_get_p2p_status(cfg, DISCOVERY_ON) == 0)) { - - CFGP2P_ERR((" Discovery is not set, so we have noting to do\n")); - - ret = BCME_NOTREADY; - goto exit; - } - if (timer_pending(&cfg->p2p->listen_timer)) { - CFGP2P_DBG(("previous LISTEN is not completed yet\n")); - goto exit; - - } -#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - else - wl_clr_p2p_status(cfg, LISTEN_EXPIRED); -#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) { - CFGP2P_ERR((" failed to set WLC_E_P2P_PROPREQ_MSG\n")); - } - - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - _timer = &cfg->p2p->listen_timer; - - /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , - * otherwise we will wait up to duration_ms + 100ms + duration / 10 - */ - if (ret == BCME_OK) { - extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10); - } else { - /* if failed to set listen, it doesn't need to wait whole duration. */ - duration_ms = 100 + duration_ms / 20; - extra_delay = 0; - } - - INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_clr_p2p_status(cfg, LISTEN_EXPIRED); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - -#undef EXTRA_DELAY_TIME -exit: - return ret; -} - - -s32 -wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable) -{ - s32 ret = BCME_OK; - CFGP2P_DBG((" Enter\n")); - if (!wl_get_p2p_status(cfg, DISCOVERY_ON)) { - - CFGP2P_DBG((" do nothing, discovery is off\n")); - return ret; - } - if (wl_get_p2p_status(cfg, SEARCH_ENABLED) == enable) { - CFGP2P_DBG(("already : %d\n", enable)); - return ret; - } - - wl_chg_p2p_status(cfg, SEARCH_ENABLED); - /* When disabling Search, reset the WL driver's p2p discovery state to - * WL_P2P_DISC_ST_SCAN. - */ - if (!enable) { - wl_clr_p2p_status(cfg, SCANNING); - ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - } - - return ret; -} - -/* - * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE - */ -s32 -wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - s32 ret = BCME_OK; - u32 event_type = ntoh32(e->event_type); - u32 status = ntoh32(e->status); - struct net_device *ndev = NULL; - CFGP2P_DBG((" Enter\n")); - - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - - if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) { - if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { - - CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); - if (status == WLC_E_STATUS_SUCCESS) { - wl_set_p2p_status(cfg, ACTION_TX_COMPLETED); - CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n")); - if (!cfg->need_wait_afrx && cfg->af_sent_channel) { - CFGP2P_DBG(("no need to wait next AF.\n")); - wl_stop_wait_next_action_frame(cfg, ndev); - } - } - else if (!wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { - wl_set_p2p_status(cfg, ACTION_TX_NOACK); - CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); - wl_stop_wait_next_action_frame(cfg, ndev); - } - } else { - CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," - "status : %d\n", status)); - - if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) - complete(&cfg->send_af_done); - } - } - return ret; -} -/* Send an action frame immediately without doing channel synchronization. - * - * This function does not wait for a completion event before returning. - * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action - * frame is transmitted. - * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an - * 802.11 ack has been received for the sent action frame. - */ -s32 -wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, - wl_af_params_t *af_params, s32 bssidx) -{ - s32 ret = BCME_OK; - s32 evt_ret = BCME_OK; - s32 timeout = 0; - wl_eventmsg_buf_t buf; - - - CFGP2P_INFO(("\n")); - CFGP2P_INFO(("channel : %u , dwell time : %u\n", - af_params->channel, af_params->dwell_time)); - - wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED); - wl_clr_p2p_status(cfg, ACTION_TX_NOACK); - - bzero(&buf, sizeof(wl_eventmsg_buf_t)); - wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true); - wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true); - if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) - return evt_ret; - - cfg->af_sent_channel = af_params->channel; -#ifdef WL_CFG80211_SYNC_GON - cfg->af_tx_sent_jiffies = jiffies; -#endif /* WL_CFG80211_SYNC_GON */ - - ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - if (ret < 0) { - CFGP2P_ERR((" sending action frame is failed\n")); - goto exit; - } - - timeout = wait_for_completion_timeout(&cfg->send_af_done, - msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX)); - - if (timeout >= 0 && wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { - CFGP2P_INFO(("tx action frame operation is completed\n")); - ret = BCME_OK; - } else if (ETHER_ISBCAST(&cfg->afx_hdl->tx_dst_addr)) { - CFGP2P_INFO(("bcast tx action frame operation is completed\n")); - ret = BCME_OK; - } else { - ret = BCME_ERROR; - CFGP2P_INFO(("tx action frame operation is failed\n")); - } - /* clear status bit for action tx */ - wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED); - wl_clr_p2p_status(cfg, ACTION_TX_NOACK); - -exit: - CFGP2P_INFO((" via act frame iovar : status = %d\n", ret)); - - bzero(&buf, sizeof(wl_eventmsg_buf_t)); - wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false); - wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false); - if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) { - WL_ERR(("TX frame events revert back failed \n")); - return evt_ret; - } - - return ret; -} - -/* Generate our P2P Device Address and P2P Interface Address from our primary - * MAC address. - */ -void -wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, - struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr) -{ - memset(out_dev_addr, 0, sizeof(*out_dev_addr)); - memset(out_int_addr, 0, sizeof(*out_int_addr)); - - /* Generate the P2P Device Address. This consists of the device's - * primary MAC address with the locally administered bit set. - */ - memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr)); - out_dev_addr->octet[0] |= 0x02; - - /* Generate the P2P Interface Address. If the discovery and connection - * BSSCFGs need to simultaneously co-exist, then this address must be - * different from the P2P Device Address. - */ - memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr)); - out_int_addr->octet[4] ^= 0x80; - -} - -/* P2P IF Address change to Virtual Interface MAC Address */ -void -wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id) -{ - wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf; - u16 len = ie->len; - u8 *subel; - u8 subelt_id; - u16 subelt_len; - CFGP2P_DBG((" Enter\n")); - - /* Point subel to the P2P IE's subelt field. - * Subtract the preceding fields (id, len, OUI, oui_type) from the length. - */ - subel = ie->subelts; - len -= 4; /* exclude OUI + OUI_TYPE */ - - while (len >= 3) { - /* attribute id */ - subelt_id = *subel; - subel += 1; - len -= 1; - - /* 2-byte little endian */ - subelt_len = *subel++; - subelt_len |= *subel++ << 8; - - len -= 2; - len -= subelt_len; /* for the remaining subelt fields */ - - if (subelt_id == element_id) { - if (subelt_id == P2P_SEID_INTINTADDR) { - memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); - CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n")); - } else if (subelt_id == P2P_SEID_DEV_ID) { - memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); - CFGP2P_INFO(("Device ID ATTR FOUND\n")); - } else if (subelt_id == P2P_SEID_DEV_INFO) { - memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); - CFGP2P_INFO(("Device INFO ATTR FOUND\n")); - } else if (subelt_id == P2P_SEID_GROUP_ID) { - memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); - CFGP2P_INFO(("GROUP ID ATTR FOUND\n")); - } return; - } else { - CFGP2P_DBG(("OTHER id : %d\n", subelt_id)); - } - subel += subelt_len; - } -} -/* - * Check if a BSS is up. - * This is a common implementation called by most OSL implementations of - * p2posl_bss_isup(). DO NOT call this function directly from the - * common code -- call p2posl_bss_isup() instead to allow the OSL to - * override the common implementation if necessary. - */ -bool -wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) -{ - s32 result, val; - bool isup = false; - s8 getbuf[64]; - - /* Check if the BSS is up */ - *(int*)getbuf = -1; - result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, - sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL); - if (result != 0) { - CFGP2P_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result)); - CFGP2P_ERR(("NOTE: this ioctl error is normal " - "when the BSS has not been created yet.\n")); - } else { - val = *(int*)getbuf; - val = dtoh32(val); - CFGP2P_INFO(("---cfg bss -C %d ==> %d\n", bsscfg_idx, val)); - isup = (val ? TRUE : FALSE); - } - return isup; -} - - -/* Bring up or down a BSS */ -s32 -wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up) -{ - s32 ret = BCME_OK; - s32 val = up ? 1 : 0; - - struct { - s32 cfg; - s32 val; - } bss_setbuf; - - bss_setbuf.cfg = htod32(bsscfg_idx); - bss_setbuf.val = htod32(val); - CFGP2P_INFO(("---cfg bss -C %d %s\n", bsscfg_idx, up ? "up" : "down")); - ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (ret != 0) { - CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret)); - } - - return ret; -} - -/* Check if 'p2p' is supported in the driver */ -s32 -wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - s32 ret = BCME_OK; - s32 p2p_supported = 0; - ret = wldev_iovar_getint(ndev, "p2p", - &p2p_supported); - if (ret < 0) { - if (ret == BCME_UNSUPPORTED) { - CFGP2P_INFO(("p2p is unsupported\n")); - return 0; - } else { - CFGP2P_ERR(("cfg p2p error %d\n", ret)); - return ret; - } - } - if (p2p_supported == 1) { - CFGP2P_INFO(("p2p is supported\n")); - } else { - CFGP2P_INFO(("p2p is unsupported\n")); - p2p_supported = 0; - } - return p2p_supported; -} -/* Cleanup P2P resources */ -s32 -wl_cfgp2p_down(struct bcm_cfg80211 *cfg) -{ - struct net_device *ndev = NULL; - struct wireless_dev *wdev = NULL; - s32 i = 0, index = -1; - -#if defined(WL_CFG80211_P2P_DEV_IF) - ndev = bcmcfg_to_prmry_ndev(cfg); - wdev = bcmcfg_to_p2p_wdev(cfg); -#elif defined(WL_ENABLE_P2P_IF) - ndev = cfg->p2p_net ? cfg->p2p_net : bcmcfg_to_prmry_ndev(cfg); - wdev = ndev_to_wdev(ndev); -#endif /* WL_CFG80211_P2P_DEV_IF */ - - wl_cfgp2p_cancel_listen(cfg, ndev, wdev, TRUE); - for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { - index = wl_to_p2p_bss_bssidx(cfg, i); - if (index != WL_INVALID) - wl_cfgp2p_clear_management_ie(cfg, index); - } - wl_cfgp2p_deinit_priv(cfg); - return 0; -} -s32 -wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len) -{ - s32 ret = -1; - int count, start, duration; - wl_p2p_sched_t dongle_noa; - - CFGP2P_DBG((" Enter\n")); - - memset(&dongle_noa, 0, sizeof(dongle_noa)); - - if (cfg->p2p && cfg->p2p->vif_created) { - - cfg->p2p->noa.desc[0].start = 0; - - sscanf(buf, "%10d %10d %10d", &count, &start, &duration); - CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n", - count, start, duration)); - if (count != -1) - cfg->p2p->noa.desc[0].count = count; - - /* supplicant gives interval as start */ - if (start != -1) - cfg->p2p->noa.desc[0].interval = start; - - if (duration != -1) - cfg->p2p->noa.desc[0].duration = duration; - - if (cfg->p2p->noa.desc[0].count < 255 && cfg->p2p->noa.desc[0].count > 1) { - cfg->p2p->noa.desc[0].start = 0; - dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; - dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; - dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; - } - else if (cfg->p2p->noa.desc[0].count == 1) { - cfg->p2p->noa.desc[0].start = 200; - dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS; - dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF; - dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; - } - else if (cfg->p2p->noa.desc[0].count == 0) { - cfg->p2p->noa.desc[0].start = 0; - dongle_noa.action = WL_P2P_SCHED_ACTION_RESET; - } - else { - /* Continuous NoA interval. */ - dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; - dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; - if ((cfg->p2p->noa.desc[0].interval == 102) || - (cfg->p2p->noa.desc[0].interval == 100)) { - cfg->p2p->noa.desc[0].start = 100 - - cfg->p2p->noa.desc[0].duration; - dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT; - } - else { - dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; - } - } - /* Put the noa descriptor in dongle format for dongle */ - dongle_noa.desc[0].count = htod32(cfg->p2p->noa.desc[0].count); - if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) { - dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start); - dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration); - } - else { - dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start*1000); - dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration*1000); - } - dongle_noa.desc[0].interval = htod32(cfg->p2p->noa.desc[0].interval*1000); - - ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION), - "p2p_noa", &dongle_noa, sizeof(dongle_noa), cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - - if (ret < 0) { - CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret)); - } - } - else { - CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n")); - } - return ret; -} -s32 -wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int buf_len) -{ - - wifi_p2p_noa_desc_t *noa_desc; - int len = 0, i; - char _buf[200]; - - CFGP2P_DBG((" Enter\n")); - buf[0] = '\0'; - if (cfg->p2p && cfg->p2p->vif_created) { - if (cfg->p2p->noa.desc[0].count || cfg->p2p->ops.ops) { - _buf[0] = 1; /* noa index */ - _buf[1] = (cfg->p2p->ops.ops ? 0x80: 0) | - (cfg->p2p->ops.ctw & 0x7f); /* ops + ctw */ - len += 2; - if (cfg->p2p->noa.desc[0].count) { - noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len]; - noa_desc->cnt_type = cfg->p2p->noa.desc[0].count; - noa_desc->duration = cfg->p2p->noa.desc[0].duration; - noa_desc->interval = cfg->p2p->noa.desc[0].interval; - noa_desc->start = cfg->p2p->noa.desc[0].start; - len += sizeof(wifi_p2p_noa_desc_t); - } - if (buf_len <= len * 2) { - CFGP2P_ERR(("ERROR: buf_len %d in not enough for" - "returning noa in string format\n", buf_len)); - return -1; - } - /* We have to convert the buffer data into ASCII strings */ - for (i = 0; i < len; i++) { - snprintf(buf, 3, "%02x", _buf[i]); - buf += 2; - } - buf[i*2] = '\0'; - } - } - else { - CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n")); - return -1; - } - return len * 2; -} -s32 -wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len) -{ - int ps, ctw; - int ret = -1; - s32 legacy_ps; - struct net_device *dev; - - CFGP2P_DBG((" Enter\n")); - if (cfg->p2p && cfg->p2p->vif_created) { - sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw); - CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw)); - dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); - if (ctw != -1) { - cfg->p2p->ops.ctw = ctw; - ret = 0; - } - if (ps != -1) { - cfg->p2p->ops.ops = ps; - ret = wldev_iovar_setbuf(dev, - "p2p_ops", &cfg->p2p->ops, sizeof(cfg->p2p->ops), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (ret < 0) { - CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret)); - } - } - - if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) { - ret = wldev_ioctl(dev, - WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true); - if (unlikely(ret)) - CFGP2P_ERR(("error (%d)\n", ret)); - wl_cfg80211_update_power_mode(dev); - } - else - CFGP2P_ERR(("ilegal setting\n")); - } - else { - CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n")); - ret = -1; - } - return ret; -} - -u8 * -wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) -{ - wifi_p2p_ie_t *ie = NULL; - u16 len = 0; - u8 *subel; - u8 subelt_id; - u16 subelt_len; - - if (!buf) { - WL_ERR(("P2P IE not present")); - return 0; - } - - ie = (wifi_p2p_ie_t*) buf; - len = ie->len; - - /* Point subel to the P2P IE's subelt field. - * Subtract the preceding fields (id, len, OUI, oui_type) from the length. - */ - subel = ie->subelts; - len -= 4; /* exclude OUI + OUI_TYPE */ - - while (len >= 3) { - /* attribute id */ - subelt_id = *subel; - subel += 1; - len -= 1; - - /* 2-byte little endian */ - subelt_len = *subel++; - subelt_len |= *subel++ << 8; - - len -= 2; - len -= subelt_len; /* for the remaining subelt fields */ - - if (subelt_id == element_id) { - /* This will point to start of subelement attrib after - * attribute id & len - */ - return subel; - } - - /* Go to next subelement */ - subel += subelt_len; - } - - /* Not Found */ - return NULL; -} - -#define P2P_GROUP_CAPAB_GO_BIT 0x01 - -u8* -wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib) -{ - bcm_tlv_t *ie; - u8* pAttrib; - - CFGP2P_INFO(("Starting parsing parse %p attrib %d remaining len %d ", parse, attrib, len)); - while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { - if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len) == TRUE) { - /* Have the P2p ie. Now check for attribute */ - if ((pAttrib = wl_cfgp2p_retreive_p2pattrib(parse, attrib)) != NULL) { - CFGP2P_INFO(("P2P attribute %d was found at parse %p", - attrib, parse)); - return pAttrib; - } - else { - /* move to next IE */ - len -= (u32)((u8 *)ie + TLV_HDR_LEN + ie->len - parse); - parse = (uint8 *)ie + TLV_HDR_LEN + ie->len; - CFGP2P_INFO(("P2P Attribute %d not found Moving parse" - " to %p len to %d", attrib, parse, len)); - } - } - else { - /* It was not p2p IE. parse will get updated automatically to next TLV */ - CFGP2P_INFO(("IT was NOT P2P IE parse %p len %d", parse, len)); - } - } - CFGP2P_ERR(("P2P attribute %d was NOT found", attrib)); - return NULL; -} - -u8 * -wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) -{ - u8 *capability = NULL; - bool p2p_go = 0; - u8 *ptr = NULL; - - if ((capability = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, - bi->ie_length, P2P_SEID_P2P_INFO)) == NULL) { - WL_ERR(("P2P Capability attribute not found")); - return NULL; - } - - /* Check Group capability for Group Owner bit */ - p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT; - if (!p2p_go) { - return bi->BSSID.octet; - } - - /* In probe responses, DEVICE INFO attribute will be present */ - if (!(ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, - bi->ie_length, P2P_SEID_DEV_INFO))) { - /* If DEVICE_INFO is not found, this might be a beacon frame. - * check for DEVICE_ID in the beacon frame. - */ - ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, - bi->ie_length, P2P_SEID_DEV_ID); - } - - if (!ptr) - WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE ")); - - return ptr; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -static void -wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) -{ - snprintf(info->driver, sizeof(info->driver), "p2p"); - snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0)); -} - -struct ethtool_ops cfgp2p_ethtool_ops = { - .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - -#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) -s32 -wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg) -{ - int ret = 0; - struct net_device* net = NULL; -#ifndef WL_NEWCFG_PRIVCMD_SUPPORT - struct wireless_dev *wdev = NULL; -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; - - if (cfg->p2p_net) { - CFGP2P_ERR(("p2p_net defined already.\n")); - return -EINVAL; - } - - /* Allocate etherdev, including space for private structure */ - if (!(net = alloc_etherdev(sizeof(struct bcm_cfg80211 *)))) { - CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); - return -ENODEV; - } - -#ifndef WL_NEWCFG_PRIVCMD_SUPPORT - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (unlikely(!wdev)) { - WL_ERR(("Could not allocate wireless device\n")); - free_netdev(net); - return -ENOMEM; - } -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - - strncpy(net->name, "p2p%d", sizeof(net->name) - 1); - net->name[IFNAMSIZ - 1] = '\0'; - - /* Copy the reference to bcm_cfg80211 */ - memcpy((void *)netdev_priv(net), &cfg, sizeof(struct bcm_cfg80211 *)); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - ASSERT(!net->open); - net->do_ioctl = wl_cfgp2p_do_ioctl; - net->hard_start_xmit = wl_cfgp2p_start_xmit; - net->open = wl_cfgp2p_if_open; - net->stop = wl_cfgp2p_if_stop; -#else - ASSERT(!net->netdev_ops); - net->netdev_ops = &wl_cfgp2p_if_ops; -#endif - - /* Register with a dummy MAC addr */ - memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); - -#ifndef WL_NEWCFG_PRIVCMD_SUPPORT - wdev->wiphy = cfg->wdev->wiphy; - - wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); - - net->ieee80211_ptr = wdev; -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - net->ethtool_ops = &cfgp2p_ethtool_ops; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - -#ifndef WL_NEWCFG_PRIVCMD_SUPPORT - SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy)); - - /* Associate p2p0 network interface with new wdev */ - wdev->netdev = net; -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - - ret = register_netdev(net); - if (ret) { - CFGP2P_ERR((" register_netdevice failed (%d)\n", ret)); - free_netdev(net); -#ifndef WL_NEWCFG_PRIVCMD_SUPPORT - kfree(wdev); -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - return -ENODEV; - } - - /* store p2p net ptr for further reference. Note that iflist won't have this - * entry as there corresponding firmware interface is a "Hidden" interface. - */ -#ifndef WL_NEWCFG_PRIVCMD_SUPPORT - cfg->p2p_wdev = wdev; -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - cfg->p2p_net = net; - - printk("%s: P2P Interface Registered\n", net->name); - - return ret; -} - -s32 -wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg) -{ - - if (!cfg || !cfg->p2p_net) { - CFGP2P_ERR(("Invalid Ptr\n")); - return -EINVAL; - } - - unregister_netdev(cfg->p2p_net); - free_netdev(cfg->p2p_net); - - return 0; -} - -static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - - if (skb) - { - CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n", - ndev->name)); - dev_kfree_skb_any(skb); - } - - return 0; -} - -static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd) -{ - int ret = 0; - struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net); - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); - - /* There is no ifidx corresponding to p2p0 in our firmware. So we should - * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs. - * For Android PRIV CMD handling map it to primary I/F - */ - if (cmd == SIOCDEVPRIVATE+1) { - ret = wl_android_priv_cmd(ndev, ifr, cmd); - - } else { - CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n", - __FUNCTION__, cmd)); - return -1; - } - - return ret; -} -#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ - - -#if defined(WL_ENABLE_P2P_IF) -static int wl_cfgp2p_if_open(struct net_device *net) -{ - struct wireless_dev *wdev = net->ieee80211_ptr; - - if (!wdev || !wl_cfg80211_is_p2p_active()) - return -EINVAL; - WL_TRACE(("Enter\n")); -#if !defined(WL_IFACE_COMB_NUM_CHANNELS) - /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, - * do it here. This will make sure that in concurrent mode, supplicant - * is not dependent on a particular order of interface initialization. - * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N - * -iwlan0. - */ - wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) - | BIT(NL80211_IFTYPE_P2P_GO)); -#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ - wl_cfg80211_do_driver_init(net); - - - return 0; -} - -static int wl_cfgp2p_if_stop(struct net_device *net) -{ - struct wireless_dev *wdev = net->ieee80211_ptr; - - if (!wdev) - return -EINVAL; - - wl_cfg80211_scan_stop(net); - -#if !defined(WL_IFACE_COMB_NUM_CHANNELS) - wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) - & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| - BIT(NL80211_IFTYPE_P2P_GO))); -#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ - - - return 0; -} - -bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops) -{ - return (if_ops == &wl_cfgp2p_if_ops); -} -#endif /* WL_ENABLE_P2P_IF */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -struct wireless_dev * -wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg) -{ - struct wireless_dev *wdev = NULL; - struct ether_addr primary_mac; - - if (!cfg) - return ERR_PTR(-EINVAL); - - WL_TRACE(("Enter\n")); - - if (cfg->p2p_wdev) { - CFGP2P_ERR(("p2p_wdev defined already.\n")); - wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); - CFGP2P_ERR(("p2p_wdev deleted.\n")); - } - - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (unlikely(!wdev)) { - WL_ERR(("Could not allocate wireless device\n")); - return ERR_PTR(-ENOMEM); - } - - memset(&primary_mac, 0, sizeof(primary_mac)); - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, - &cfg->p2p->dev_addr, &cfg->p2p->int_addr); - - wdev->wiphy = cfg->wdev->wiphy; - wdev->iftype = NL80211_IFTYPE_P2P_DEVICE; - memcpy(wdev->address, &cfg->p2p->dev_addr, ETHER_ADDR_LEN); - -#if defined(WL_NEWCFG_PRIVCMD_SUPPORT) - if (cfg->p2p_net) - memcpy(cfg->p2p_net->dev_addr, &cfg->p2p->dev_addr, ETHER_ADDR_LEN); -#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ - - /* store p2p wdev ptr for further reference. */ - cfg->p2p_wdev = wdev; - - CFGP2P_ERR(("P2P interface registered\n")); - - return wdev; -} - -int -wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) -{ - int ret = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (!cfg) - return -EINVAL; - - WL_TRACE(("Enter\n")); - - ret = wl_cfgp2p_set_firm_p2p(cfg); - if (unlikely(ret < 0)) { - CFGP2P_ERR(("Set P2P in firmware failed, ret=%d\n", ret)); - goto exit; - } - - ret = wl_cfgp2p_enable_discovery(cfg, bcmcfg_to_prmry_ndev(cfg), NULL, 0); - if (unlikely(ret < 0)) { - CFGP2P_ERR(("P2P enable discovery failed, ret=%d\n", ret)); - goto exit; - } - - p2p_on(cfg) = true; - - CFGP2P_DBG(("P2P interface started\n")); - -exit: - return ret; -} - -void -wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) -{ - int ret = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (!cfg) - return; - - WL_TRACE(("Enter\n")); - - ret = wl_cfg80211_scan_stop(wdev); - if (unlikely(ret < 0)) { - CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret)); - } - - if (!cfg->p2p) - return; - - ret = wl_cfgp2p_disable_discovery(cfg); - if (unlikely(ret < 0)) { - CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret)); - } - - p2p_on(cfg) = false; - - CFGP2P_DBG(("P2P interface stopped\n")); - - return; -} - -int -wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg) -{ - bool rollback_lock = false; - - if (!wdev) - return -EINVAL; - - WL_TRACE(("Enter\n")); - - if (!rtnl_is_locked()) { - rtnl_lock(); - rollback_lock = true; - } - - cfg80211_unregister_wdev(wdev); - - if (rollback_lock) - rtnl_unlock(); - - kfree(wdev); - - if (cfg) - cfg->p2p_wdev = NULL; - - CFGP2P_ERR(("P2P interface unregistered\n")); - - return 0; -} -#endif /* WL_CFG80211_P2P_DEV_IF */ - -void -wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx) -{ - wifi_p2p_pub_act_frame_t *pact_frm; - int status = 0; - - if (!frame || (frame_len < (sizeof(*pact_frm) + WL_P2P_AF_STATUS_OFFSET - 1))) { - return; - } - - if (wl_cfgp2p_is_pub_action(frame, frame_len)) { - pact_frm = (wifi_p2p_pub_act_frame_t *)frame; - if (pact_frm->subtype == P2P_PAF_GON_RSP && tx) { - CFGP2P_ACTION(("Check TX P2P Group Owner Negotiation Rsp Frame status\n")); - status = pact_frm->elts[WL_P2P_AF_STATUS_OFFSET]; - if (status) { - cfg->need_wait_afrx = false; - return; - } - } - } - - cfg->need_wait_afrx = true; - return; -} - -int -wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request) -{ - if (request && (request->n_ssids == 1) && - (request->n_channels == 1) && - IS_P2P_SSID(request->ssids[0].ssid, WL_P2P_WILDCARD_SSID_LEN) && - (request->ssids[0].ssid_len > WL_P2P_WILDCARD_SSID_LEN)) { - return true; - } - return false; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h deleted file mode 100755 index 40fa2a169708..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Linux cfgp2p driver - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgp2p.h 528496 2015-01-22 10:52:40Z $ - */ -#ifndef _wl_cfgp2p_h_ -#define _wl_cfgp2p_h_ -#include -#include - -struct bcm_cfg80211; -extern u32 wl_dbg_level; - -typedef struct wifi_p2p_ie wifi_wfd_ie_t; -/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not - * confuse this with a bsscfg index. This value is an index into the - * saved_ie[] array of structures which in turn contains a bsscfg index field. - */ -typedef enum { - P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ - P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ - P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ - P2PAPI_BSSCFG_MAX -} p2p_bsscfg_type_t; - -typedef enum { - P2P_SCAN_PURPOSE_MIN, - P2P_SCAN_SOCIAL_CHANNEL, /* scan for social channel */ - P2P_SCAN_AFX_PEER_NORMAL, /* scan for action frame search */ - P2P_SCAN_AFX_PEER_REDUCED, /* scan for action frame search with short time */ - P2P_SCAN_DURING_CONNECTED, /* scan during connected status */ - P2P_SCAN_CONNECT_TRY, /* scan for connecting */ - P2P_SCAN_NORMAL, /* scan during not-connected status */ - P2P_SCAN_PURPOSE_MAX -} p2p_scan_purpose_t; - -/* vendor ies max buffer length for probe response or beacon */ -#define VNDR_IES_MAX_BUF_LEN 1400 -/* normal vendor ies buffer length */ -#define VNDR_IES_BUF_LEN 512 - -/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */ -struct p2p_saved_ie { - u8 p2p_probe_req_ie[VNDR_IES_BUF_LEN]; - u8 p2p_probe_res_ie[VNDR_IES_MAX_BUF_LEN]; - u8 p2p_assoc_req_ie[VNDR_IES_BUF_LEN]; - u8 p2p_assoc_res_ie[VNDR_IES_BUF_LEN]; - u8 p2p_beacon_ie[VNDR_IES_MAX_BUF_LEN]; - u32 p2p_probe_req_ie_len; - u32 p2p_probe_res_ie_len; - u32 p2p_assoc_req_ie_len; - u32 p2p_assoc_res_ie_len; - u32 p2p_beacon_ie_len; -}; - -struct p2p_bss { - u32 bssidx; - struct net_device *dev; - struct p2p_saved_ie saved_ie; - void *private_data; -}; - -struct p2p_info { - bool on; /* p2p on/off switch */ - bool scan; - int16 search_state; - bool vif_created; - s8 vir_ifname[IFNAMSIZ]; - unsigned long status; - struct ether_addr dev_addr; - struct ether_addr int_addr; - struct p2p_bss bss[P2PAPI_BSSCFG_MAX]; - struct timer_list listen_timer; - wl_p2p_sched_t noa; - wl_p2p_ops_t ops; - wlc_ssid_t ssid; -}; - -#define MAX_VNDR_IE_NUMBER 5 - -struct parsed_vndr_ie_info { - char *ie_ptr; - u32 ie_len; /* total length including id & length field */ - vndr_ie_t vndrie; -}; - -struct parsed_vndr_ies { - u32 count; - struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; -}; - -/* dongle status */ -enum wl_cfgp2p_status { - WLP2P_STATUS_DISCOVERY_ON = 0, - WLP2P_STATUS_SEARCH_ENABLED, - WLP2P_STATUS_IF_ADDING, - WLP2P_STATUS_IF_DELETING, - WLP2P_STATUS_IF_CHANGING, - WLP2P_STATUS_IF_CHANGED, - WLP2P_STATUS_LISTEN_EXPIRED, - WLP2P_STATUS_ACTION_TX_COMPLETED, - WLP2P_STATUS_ACTION_TX_NOACK, - WLP2P_STATUS_SCANNING, - WLP2P_STATUS_GO_NEG_PHASE, - WLP2P_STATUS_DISC_IN_PROGRESS -}; - - -#define wl_to_p2p_bss_ndev(cfg, type) ((cfg)->p2p->bss[type].dev) -#define wl_to_p2p_bss_bssidx(cfg, type) ((cfg)->p2p->bss[type].bssidx) -#define wl_to_p2p_bss_saved_ie(cfg, type) ((cfg)->p2p->bss[type].saved_ie) -#define wl_to_p2p_bss_private(cfg, type) ((cfg)->p2p->bss[type].private_data) -#define wl_to_p2p_bss(cfg, type) ((cfg)->p2p->bss[type]) -#define wl_get_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ - test_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) -#define wl_set_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ - set_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) -#define wl_clr_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ - clear_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) -#define wl_chg_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ - change_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) -#define p2p_on(cfg) ((cfg)->p2p->on) -#define p2p_scan(cfg) ((cfg)->p2p->scan) -#define p2p_is_on(cfg) ((cfg)->p2p && (cfg)->p2p->on) - -/* dword align allocation */ -#define WLC_IOCTL_MAXLEN 8192 - -#define CFGP2P_ERROR_TEXT "CFGP2P-ERROR) " - - -#define CFGP2P_ERR(args) \ - do { \ - if (wl_dbg_level & WL_DBG_ERR) { \ - printk(KERN_INFO CFGP2P_ERROR_TEXT "%s : ", __func__); \ - printk args; \ - } \ - } while (0) -#define CFGP2P_INFO(args) \ - do { \ - if (wl_dbg_level & WL_DBG_INFO) { \ - printk(KERN_INFO "CFGP2P-INFO) %s : ", __func__); \ - printk args; \ - } \ - } while (0) -#define CFGP2P_DBG(args) \ - do { \ - if (wl_dbg_level & WL_DBG_DBG) { \ - printk(KERN_DEBUG "CFGP2P-DEBUG) %s :", __func__); \ - printk args; \ - } \ - } while (0) - -#define CFGP2P_ACTION(args) \ - do { \ - if (wl_dbg_level & WL_DBG_P2P_ACTION) { \ - printk(KERN_DEBUG "CFGP2P-ACTION) %s :", __func__); \ - printk args; \ - } \ - } while (0) -#define INIT_TIMER(timer, func, duration, extra_delay) \ - do { \ - init_timer(timer); \ - timer->function = func; \ - timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ - timer->data = (unsigned long) cfg; \ - add_timer(timer); \ - } while (0); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_CFG80211_P2P_DEV_IF) -#define WL_CFG80211_P2P_DEV_IF - -#ifdef WL_ENABLE_P2P_IF -#undef WL_ENABLE_P2P_IF -#endif - -#ifdef WL_SUPPORT_BACKPORTED_KPATCHES -#undef WL_SUPPORT_BACKPORTED_KPATCHES -#endif -#endif /* (LINUX_VERSION >= VERSION(3, 8, 0)) */ - -#ifndef WL_CFG80211_P2P_DEV_IF -#ifdef WL_NEWCFG_PRIVCMD_SUPPORT -#undef WL_NEWCFG_PRIVCMD_SUPPORT -#endif -#endif /* WL_CFG80211_P2P_DEV_IF */ - -#if defined(WL_ENABLE_P2P_IF) && (defined(WL_CFG80211_P2P_DEV_IF) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))) -#error Disable 'WL_ENABLE_P2P_IF', if 'WL_CFG80211_P2P_DEV_IF' is enabled \ - or kernel version is 3.8.0 or above -#endif /* WL_ENABLE_P2P_IF && (WL_CFG80211_P2P_DEV_IF || (LINUX_VERSION >= VERSION(3, 8, 0))) */ - -#if !defined(WLP2P) && (defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)) -#error WLP2P not defined -#endif /* !WLP2P && (WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF) */ - -#if defined(WL_CFG80211_P2P_DEV_IF) -#define bcm_struct_cfgdev struct wireless_dev -#else -#define bcm_struct_cfgdev struct net_device -#endif /* WL_CFG80211_P2P_DEV_IF */ - -extern void -wl_cfgp2p_listen_expired(unsigned long data); -extern bool -wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); -extern bool -wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); -extern bool -wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); -extern bool -wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len); -extern void -wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel); -extern s32 -wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg); -extern void -wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg); -extern s32 -wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg); -extern s32 -wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, - u32 channel, u16 listen_ms, int bssidx); -extern s32 -wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, - chanspec_t chspec); -extern s32 -wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac); -extern s32 -wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac); -extern s32 -wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, chanspec_t chspec); - -extern s32 -wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index); - -extern s32 -wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg); -extern s32 -wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *ie, - u32 ie_len); -extern s32 -wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg); -extern s32 -wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, u32 num_chans, - u16 *channels, - s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, - p2p_scan_purpose_t p2p_scan_purpose); - -extern s32 -wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, - s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr); - -extern wpa_ie_fixed_t * -wl_cfgp2p_find_wpaie(u8 *parse, u32 len); - -extern wpa_ie_fixed_t * -wl_cfgp2p_find_wpsie(u8 *parse, u32 len); - -extern wifi_p2p_ie_t * -wl_cfgp2p_find_p2pie(u8 *parse, u32 len); - -extern wifi_wfd_ie_t * -wl_cfgp2p_find_wfdie(u8 *parse, u32 len); -extern s32 -wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, - s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len); -extern s32 -wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx); - -extern s32 -wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *index); -extern struct net_device * -wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx); -extern s32 -wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type); - - -extern s32 -wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); -extern s32 -wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms); - -extern s32 -wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable); - -extern s32 -wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data); - -extern s32 -wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, - wl_af_params_t *af_params, s32 bssidx); - -extern void -wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr, - struct ether_addr *out_int_addr); - -extern void -wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); -extern bool -wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); - -extern s32 -wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up); - - -extern s32 -wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev); - -extern s32 -wl_cfgp2p_down(struct bcm_cfg80211 *cfg); - -extern s32 -wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); - -extern s32 -wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); - -extern s32 -wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); - -extern u8 * -wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id); - -extern u8* -wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib); - -extern u8 * -wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length); - -extern s32 -wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg); - -extern s32 -wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg); - -extern bool -wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops); - -#if defined(WL_CFG80211_P2P_DEV_IF) -extern struct wireless_dev * -wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg); - -extern int -wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); - -extern void -wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); - -extern int -wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg); -#endif /* WL_CFG80211_P2P_DEV_IF */ - -extern void -wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx); - -extern int -wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request); - -/* WiFi Direct */ -#define SOCIAL_CHAN_1 1 -#define SOCIAL_CHAN_2 6 -#define SOCIAL_CHAN_3 11 -#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ - (channel == SOCIAL_CHAN_2) || \ - (channel == SOCIAL_CHAN_3)) -#define SOCIAL_CHAN_CNT 3 -#define AF_PEER_SEARCH_CNT 2 -#define WL_P2P_WILDCARD_SSID "DIRECT-" -#define WL_P2P_WILDCARD_SSID_LEN 7 -#define WL_P2P_INTERFACE_PREFIX "p2p" -#define WL_P2P_TEMP_CHAN 11 -#define WL_P2P_AF_STATUS_OFFSET 9 - -/* If the provision discovery is for JOIN operations, - * or the device discoverablity frame is destined to GO - * then we need not do an internal scan to find GO. - */ -#define IS_ACTPUB_WITHOUT_GROUP_ID(p2p_ie, len) \ - (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL) - -#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ - ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ - (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) - -#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \ - ((subtype == P2P_PAF_GON_CONF) || \ - (subtype == P2P_PAF_INVITE_RSP) || \ - (subtype == P2P_PAF_PROVDIS_RSP))) -#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) -#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \ - (len == WL_P2P_WILDCARD_SSID_LEN)) -#endif /* _wl_cfgp2p_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c deleted file mode 100755 index 114c68d26db7..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c +++ /dev/null @@ -1,2396 +0,0 @@ -/* - * Linux cfg80211 Vendor Extension Code - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgvendor.c 455257 2014-02-13 08:10:24Z $ -*/ - -/* - * New vendor interface additon to nl80211/cfg80211 to allow vendors - * to implement proprietary features over the cfg80211 stack. -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#ifdef PNO_SUPPORT -#include -#endif /* PNO_SUPPORT */ -#ifdef RTT_SUPPORT -#include -#endif /* RTT_SUPPORT */ -#ifdef RTT_SUPPORT -#include -#endif /* RTT_SUPPORT */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#ifdef PROP_TXSTATUS -#include -#endif -#include - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) -/* - * This API is to be used for asynchronous vendor events. This - * shouldn't be used in response to a vendor command from its - * do_it handler context (instead wl_cfgvendor_send_cmd_reply should - * be used). - */ -int wl_cfgvendor_send_async_event(struct wiphy *wiphy, - struct net_device *dev, int event_id, const void *data, int len) -{ - u16 kflags; - struct sk_buff *skb; - - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags); - if (!skb) { - WL_ERR(("skb alloc failed")); - return -ENOMEM; - } - - /* Push the data to the skb */ - nla_put_nohdr(skb, len, data); - - cfg80211_vendor_event(skb, kflags); - - return 0; -} - -static int wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy, - struct net_device *dev, const void *data, int len) -{ - struct sk_buff *skb; - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); - if (unlikely(!skb)) { - WL_ERR(("skb alloc failed")); - return -ENOMEM; - } - - /* Push the data to the skb */ - nla_put_nohdr(skb, len, data); - - return cfg80211_vendor_cmd_reply(skb); -} - -static int wl_cfgvendor_get_feature_set(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int reply; - - reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg)); - - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - &reply, sizeof(int)); - - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - - return err; -} - -static int wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct sk_buff *skb; - int *reply; - int num, mem_needed, i; - - reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), &num); - - if (!reply) { - WL_ERR(("Could not get feature list matrix\n")); - err = -EINVAL; - return err; - } - - mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * num) + - ATTRIBUTE_U32_LEN; - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); - if (unlikely(!skb)) { - WL_ERR(("skb alloc failed")); - err = -ENOMEM; - goto exit; - } - - nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, num); - for (i = 0; i < num; i++) { - nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply[i]); - } - - err = cfg80211_vendor_cmd_reply(skb); - - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); -exit: - kfree(reply); - return err; -} - -static int -wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type; - uint8 random_mac_oui[DOT11_OUI_LEN]; - - type = nla_type(data); - - if (type == ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI) { - memcpy(random_mac_oui, nla_data(data), DOT11_OUI_LEN); - - err = dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg), random_mac_oui); - - if (unlikely(err)) - WL_ERR(("Bad OUI, could not set:%d \n", err)); - - } else { - err = -1; - } - - return err; -} - -#ifdef CUSTOM_FORCE_NODFS_FLAG -static int -wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type; - u32 nodfs; - - type = nla_type(data); - if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) { - nodfs = nla_get_u32(data); - err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs); - } else { - err = -1; - } - return err; -} -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - -#ifdef GSCAN_SUPPORT -int -wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, - struct net_device *dev, void *data, int len, wl_vendor_event_t event) -{ - u16 kflags; - const void *ptr; - struct sk_buff *skb; - int malloc_len, total, iter_cnt_to_send, cnt; - gscan_results_cache_t *cache = (gscan_results_cache_t *)data; - - total = len/sizeof(wifi_gscan_result_t); - while (total > 0) { - malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD; - if (malloc_len > NLMSG_DEFAULT_SIZE) { - malloc_len = NLMSG_DEFAULT_SIZE; - } - iter_cnt_to_send = - (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t); - total = total - iter_cnt_to_send; - - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags); - if (!skb) { - WL_ERR(("skb alloc failed")); - return -ENOMEM; - } - - while (cache && iter_cnt_to_send) { - ptr = (const void *) &cache->results[cache->tot_consumed]; - - if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) { - cnt = iter_cnt_to_send; - } else { - cnt = (cache->tot_count - cache->tot_consumed); - } - - iter_cnt_to_send -= cnt; - cache->tot_consumed += cnt; - /* Push the data to the skb */ - nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr); - if (cache->tot_consumed == cache->tot_count) { - cache = cache->next; - } - - } - - cfg80211_vendor_event(skb, kflags); - } - - return 0; -} - -static int -wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_pno_gscan_capabilities_t *reply = NULL; - uint32 reply_len = 0; - - - reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GET_CAPABILITIES, NULL, &reply_len); - if (!reply) { - WL_ERR(("Could not get capabilities\n")); - err = -EINVAL; - return err; - } - - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - reply, reply_len); - - if (unlikely(err)) { - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - } - - kfree(reply); - return err; -} - -static int -wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0, type, band; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - uint16 *reply = NULL; - uint32 reply_len = 0, num_channels, mem_needed; - struct sk_buff *skb; - - type = nla_type(data); - - if (type == GSCAN_ATTRIBUTE_BAND) { - band = nla_get_u32(data); - } else { - return -EINVAL; - } - - reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len); - - if (!reply) { - WL_ERR(("Could not get channel list\n")); - err = -EINVAL; - return err; - } - num_channels = reply_len/ sizeof(uint32); - mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2); - - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); - if (unlikely(!skb)) { - WL_ERR(("skb alloc failed")); - err = -ENOMEM; - goto exit; - } - - nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels); - nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply); - - err = cfg80211_vendor_cmd_reply(skb); - - if (unlikely(err)) { - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - } -exit: - kfree(reply); - return err; -} - -static int -wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_results_cache_t *results, *iter; - uint32 reply_len, complete = 1; - int32 mem_needed, num_results_iter; - wifi_gscan_result_t *ptr; - uint16 num_scan_ids, num_results; - struct sk_buff *skb; - struct nlattr *scan_hdr, *complete_flag; - - err = dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg)); - if (err != BCME_OK) - return -EBUSY; - - err = dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); - if (err != BCME_OK) { - WL_ERR(("Can't obtain lock to access batch results %d\n", err)); - return -EBUSY; - } - results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len); - - if (!results) { - WL_ERR(("No results to send %d\n", err)); - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - results, 0); - - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); - return err; - } - num_scan_ids = reply_len & 0xFFFF; - num_results = (reply_len & 0xFFFF0000) >> 16; - mem_needed = (num_results * sizeof(wifi_gscan_result_t)) + - (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) + - VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN; - - if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) { - mem_needed = (int32)NLMSG_DEFAULT_SIZE; - } - - WL_TRACE(("complete %d mem_needed %d max_mem %d\n", complete, mem_needed, - (int)NLMSG_DEFAULT_SIZE)); - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); - if (unlikely(!skb)) { - WL_ERR(("skb alloc failed")); - dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); - return -ENOMEM; - } - iter = results; - complete_flag = nla_reserve(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, - sizeof(complete)); - mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD); - - while (iter) { - num_results_iter = (mem_needed - (int32)GSCAN_BATCH_RESULT_HDR_LEN); - num_results_iter /= ((int32)sizeof(wifi_gscan_result_t)); - if (num_results_iter <= 0 || - ((iter->tot_count - iter->tot_consumed) > num_results_iter)) { - break; - } - scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS); - /* no more room? we are done then (for now) */ - if (scan_hdr == NULL) { - complete = 0; - break; - } - nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id); - nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag); - num_results_iter = iter->tot_count - iter->tot_consumed; - - nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter); - if (num_results_iter) { - ptr = &iter->results[iter->tot_consumed]; - iter->tot_consumed += num_results_iter; - nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, - num_results_iter * sizeof(wifi_gscan_result_t), ptr); - } - nla_nest_end(skb, scan_hdr); - mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN + - (num_results_iter * sizeof(wifi_gscan_result_t)); - iter = iter->next; - } - /* Returns TRUE if all result consumed */ - complete = dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg)); - memcpy(nla_data(complete_flag), &complete, sizeof(complete)); - dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); - return cfg80211_vendor_cmd_reply(skb); -} - -static int -wl_cfgvendor_initiate_gscan(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type, tmp = len; - int run = 0xFF; - int flush = 0; - const struct nlattr *iter; - - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE) - run = nla_get_u32(iter); - else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE) - flush = nla_get_u32(iter); - } - - if (run != 0xFF) { - err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush); - - if (unlikely(err)) { - WL_ERR(("Could not run gscan:%d \n", err)); - } - return err; - } else { - return -EINVAL; - } - - -} - -static int -wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type; - bool real_time = FALSE; - - type = nla_type(data); - - if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) { - real_time = nla_get_u32(data); - - err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time); - - if (unlikely(err)) { - WL_ERR(("Could not run gscan:%d \n", err)); - } - - } else { - err = -EINVAL; - } - - return err; -} - -static int -wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev, - gscan_scan_params_t *scan_param, int num) -{ - struct dhd_pno_gscan_channel_bucket *ch_bucket; - int k = 0; - int type, err = 0, rem; - const struct nlattr *cur, *next; - - nla_for_each_nested(cur, prev, rem) { - type = nla_type(cur); - ch_bucket = scan_param->channel_bucket; - - switch (type) { - case GSCAN_ATTRIBUTE_BUCKET_ID: - break; - case GSCAN_ATTRIBUTE_BUCKET_PERIOD: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - - ch_bucket[num].bucket_freq_multiple = - nla_get_u32(cur)/1000; - break; - case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].num_channels = - nla_get_u32(cur); - if (ch_bucket[num].num_channels > - GSCAN_MAX_CHANNELS_IN_BUCKET) { - WL_ERR(("channel range:%d,bucket:%d\n", - ch_bucket[num].num_channels, - num)); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_BUCKET_CHANNELS: - nla_for_each_nested(next, cur, rem) { - if (k >= - GSCAN_MAX_CHANNELS_IN_BUCKET) { - break; - } - if (nla_len(next) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].chan_list[k] = - nla_get_u32(next); - k++; - } - break; - case GSCAN_ATTRIBUTE_BUCKETS_BAND: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].band = (uint16) - nla_get_u32(cur); - break; - case GSCAN_ATTRIBUTE_REPORT_EVENTS: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].report_flag = (uint8) - nla_get_u32(cur); - break; - case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].repeat = (uint16) - nla_get_u32(cur); - break; - case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD: - if (nla_len(cur) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - ch_bucket[num].bucket_max_multiple = - nla_get_u32(cur)/1000; - break; - default: - WL_ERR(("bucket attribute type error %d\n", - type)); - err = -EINVAL; - goto exit; - } - } - -exit: - return err; -} - - -static int -wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_scan_params_t *scan_param; - int j = 0; - int type, tmp; - const struct nlattr *iter; - - scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL); - if (!scan_param) { - WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n")); - err = -EINVAL; - return err; - - } - - scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC; - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - - if (j >= GSCAN_MAX_CH_BUCKETS) { - break; - } - - switch (type) { - case GSCAN_ATTRIBUTE_BASE_PERIOD: - if (nla_len(iter) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - scan_param->scan_fr = nla_get_u32(iter)/1000; - break; - case GSCAN_ATTRIBUTE_NUM_BUCKETS: - if (nla_len(iter) != sizeof(uint32)) { - err = -EINVAL; - goto exit; - } - scan_param->nchannel_buckets = nla_get_u32(iter); - if (scan_param->nchannel_buckets >= - GSCAN_MAX_CH_BUCKETS) { - WL_ERR(("ncha_buck out of range %d\n", - scan_param->nchannel_buckets)); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_CH_BUCKET_1: - case GSCAN_ATTRIBUTE_CH_BUCKET_2: - case GSCAN_ATTRIBUTE_CH_BUCKET_3: - case GSCAN_ATTRIBUTE_CH_BUCKET_4: - case GSCAN_ATTRIBUTE_CH_BUCKET_5: - case GSCAN_ATTRIBUTE_CH_BUCKET_6: - case GSCAN_ATTRIBUTE_CH_BUCKET_7: - err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j); - if (err < 0) { - WL_ERR(("set_scan_cfg_buck error:%d\n", err)); - goto exit; - } - j++; - break; - default: - WL_ERR(("Unknown type %d\n", type)); - err = -EINVAL; - goto exit; - } - } - - err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_SCAN_CFG_ID, scan_param, 0); - - if (err < 0) { - WL_ERR(("Could not set GSCAN scan cfg\n")); - err = -EINVAL; - } - -exit: - kfree(scan_param); - return err; - -} - -static int -wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_hotlist_scan_params_t *hotlist_params; - int tmp, tmp1, tmp2, type, j = 0, dummy; - const struct nlattr *outer, *inner = NULL, *iter; - uint8 flush = 0; - struct bssid_t *pbssid; - - if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) { - WL_ERR(("buffer length :%d wrong - bail out.\n", len)); - return -EINVAL; - } - hotlist_params = kzalloc(sizeof(*hotlist_params) - + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)), - GFP_KERNEL); - - if (!hotlist_params) { - WL_ERR(("Cannot Malloc memory.\n")); - return -ENOMEM; - } - - hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT; - - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS: - pbssid = hotlist_params->bssid; - nla_for_each_nested(outer, iter, tmp) { - nla_for_each_nested(inner, outer, tmp1) { - type = nla_type(inner); - - switch (type) { - case GSCAN_ATTRIBUTE_BSSID: - if (nla_len(inner) != sizeof(pbssid[j].macaddr)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - memcpy(&(pbssid[j].macaddr), - nla_data(inner), - sizeof(pbssid[j].macaddr)); - break; - case GSCAN_ATTRIBUTE_RSSI_LOW: - if (nla_len(inner) != sizeof(uint8)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - pbssid[j].rssi_reporting_threshold = - (int8)nla_get_u8(inner); - break; - case GSCAN_ATTRIBUTE_RSSI_HIGH: - if (nla_len(inner) != sizeof(uint8)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - dummy = (int8)nla_get_u8(inner); - break; - default: - WL_ERR(("ATTR unknown %d\n", type)); - err = -EINVAL; - goto exit; - } - } - if (++j >= PFN_SWC_MAX_NUM_APS) { - WL_ERR(("cap hotlist max:%d\n", j)); - break; - } - } - hotlist_params->nbssid = j; - break; - case GSCAN_ATTRIBUTE_HOTLIST_FLUSH: - if (nla_len(iter) != sizeof(uint8)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - flush = nla_get_u8(iter); - break; - case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: - if (nla_len(iter) != sizeof(uint32)) { - WL_ERR(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter); - break; - default: - WL_ERR(("Unknown type %d\n", type)); - err = -EINVAL; - goto exit; - } - } - - if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) { - WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err)); - err = -EINVAL; - goto exit; - } -exit: - kfree(hotlist_params); - return err; -} - -#ifdef EPNO_SUPPORT -static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_epno_params_t *epno_params; - int tmp, tmp1, tmp2, type, num = 0; - const struct nlattr *outer, *inner, *iter; - uint8 flush = 0, i = 0; - uint16 num_visible_ssid = 0; - - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_EPNO_SSID_LIST: - nla_for_each_nested(outer, iter, tmp) { - epno_params = (dhd_epno_params_t *) - dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_GET_EPNO_SSID_ELEM, NULL, &num); - if (!epno_params) { - WL_ERR(("Failed to get SSID LIST buffer\n")); - err = -ENOMEM; - goto exit; - } - i++; - nla_for_each_nested(inner, outer, tmp1) { - type = nla_type(inner); - - switch (type) { - case GSCAN_ATTRIBUTE_EPNO_SSID: - memcpy(epno_params->ssid, - nla_data(inner), - DOT11_MAX_SSID_LEN); - break; - case GSCAN_ATTRIBUTE_EPNO_SSID_LEN: - len = nla_get_u8(inner); - if (len < DOT11_MAX_SSID_LEN) { - epno_params->ssid_len = len; - } else { - WL_ERR(("SSID toolong %d\n", - len)); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_EPNO_RSSI: - epno_params->rssi_thresh = - (int8) nla_get_u32(inner); - break; - case GSCAN_ATTRIBUTE_EPNO_FLAGS: - epno_params->flags = - nla_get_u8(inner); - if (!(epno_params->flags & - DHD_PNO_USE_SSID)) - num_visible_ssid++; - break; - case GSCAN_ATTRIBUTE_EPNO_AUTH: - epno_params->auth = - nla_get_u8(inner); - break; - } - } - } - break; - case GSCAN_ATTRIBUTE_EPNO_SSID_NUM: - num = nla_get_u8(iter); - break; - case GSCAN_ATTRIBUTE_EPNO_FLUSH: - flush = nla_get_u8(iter); - dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_EPNO_CFG_ID, NULL, flush); - break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - err = -EINVAL; - goto exit; - } - - } - if (i != num) { - WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__, - num, i)); - err = -EINVAL; - } -exit: - /* Flush all configs if error condition */ - flush = (err < 0) ? TRUE: FALSE; - dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_EPNO_CFG_ID, &num_visible_ssid, flush); - return err; -} -#endif /* EPNO_SUPPORT */ - -#ifdef ANQPO_SUPPORT -static int wl_cfgvendor_gscan_anqpo_config(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = BCME_ERROR, rem, type, malloc_size, i = 0; - uint32 hs_list_size = 0; - int j, k, num_oi, oi_len; - wifi_passpoint_network *hs_list = NULL, *src_hs; - wl_anqpo_pfn_hs_list_t *anqpo_hs_list; - wl_anqpo_pfn_hs_t *dst_hs; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int tmp, tmp1; - const struct nlattr *outer, *inner, *iter; - static char iovar_buf[WLC_IOCTL_MAXLEN]; - char *rcid; - - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_ANQPO_HS_LIST: - if (hs_list) { - err = -EINVAL; - goto exit; - } - if (hs_list_size > GSCAN_ANQPO_MAX_HS_LIST_SIZE) { - err = -EINVAL; - goto exit; - } - if (hs_list_size > 0) { - hs_list = kmalloc(hs_list_size * - sizeof(wifi_passpoint_network), GFP_KERNEL); - if (!hs_list) { - WL_ERR(("%s: failed to allocate hs_list\n", - __func__)); - return -ENOMEM; - } - } - nla_for_each_nested(outer, iter, tmp) { - if (i == hs_list_size) - break; - - nla_for_each_nested(inner, outer, tmp1) { - type = nla_type(inner); - - switch (type) { - case GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID: - if (nla_len(inner) != sizeof(hs_list[i].id)) { - err = -EINVAL; - goto exit; - } - hs_list[i].id = nla_get_u32(inner); - WL_DBG(("%s: net id: %d\n", __func__, - hs_list[i].id)); - break; - case GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM: - if (nla_len(inner) != sizeof(hs_list[i].realm)) { - err = -EINVAL; - goto exit; - } - memcpy(hs_list[i].realm, nla_data(inner), - sizeof(hs_list[i].realm)); - WL_DBG(("%s: realm: %s\n", __func__, - hs_list[i].realm)); - break; - case GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID: - if (nla_len(inner) != - sizeof(hs_list[i].roamingConsortiumIds)) { - err = -EINVAL; - goto exit; - } - memcpy(hs_list[i].roamingConsortiumIds, - nla_data(inner), - sizeof(hs_list[i].roamingConsortiumIds)); - break; - case GSCAN_ATTRIBUTE_ANQPO_HS_PLMN: - if (nla_len(inner) != sizeof(hs_list[i].plmn)) { - err = -EINVAL; - goto exit; - } - memcpy(hs_list[i].plmn, nla_data(inner), - sizeof(hs_list[i].plmn)); - WL_DBG(("%s: plmn: %c %c %c\n", __func__, - hs_list[i].plmn[0], hs_list[i].plmn[1], - hs_list[i].plmn[2])); - break; - } - } - i++; - } - break; - case GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE: - if (nla_len(iter) != sizeof(hs_list_size)) { - err = -EINVAL; - goto exit; - } - hs_list_size = nla_get_u32(iter); - if ((hs_list_size == 0) || - (hs_list_size > GSCAN_ANQPO_MAX_HS_LIST_SIZE)) { - WL_ERR(("%s: ANQPO: %d\n", __func__, hs_list_size)); - err = -EINVAL; - goto exit; - } - WL_DBG(("%s: ANQPO: %d\n", __func__, hs_list_size)); - break; - default: - WL_ERR(("Unknown type: %d\n", type)); - err = -EINVAL; - goto exit; - } - } - - malloc_size = OFFSETOF(wl_anqpo_pfn_hs_list_t, hs) + - (hs_list_size * (sizeof(wl_anqpo_pfn_hs_t))); - anqpo_hs_list = (wl_anqpo_pfn_hs_list_t *)kmalloc(malloc_size, GFP_KERNEL); - if (anqpo_hs_list == NULL) { - WL_ERR(("failed to allocate anqpo_hs_list\n")); - err = -ENOMEM; - goto exit; - } - anqpo_hs_list->count = hs_list_size; - anqpo_hs_list->is_clear = (hs_list_size == 0) ? TRUE : FALSE; - - if ((hs_list_size > 0) && (NULL != hs_list)) { - src_hs = hs_list; - dst_hs = &anqpo_hs_list->hs[0]; - for (i = 0; i < hs_list_size; i++, src_hs++, dst_hs++) { - num_oi = 0; - dst_hs->id = src_hs->id; - dst_hs->realm.length = strlen(src_hs->realm)+1; - memcpy(dst_hs->realm.data, src_hs->realm, dst_hs->realm.length); - memcpy(dst_hs->plmn.mcc, src_hs->plmn, ANQPO_MCC_LENGTH); - memcpy(dst_hs->plmn.mnc, src_hs->plmn, ANQPO_MCC_LENGTH); - for (j = 0; j < ANQPO_MAX_PFN_HS; j++) { - oi_len = 0; - if (0 != src_hs->roamingConsortiumIds[j]) { - num_oi++; - rcid = (char *)&src_hs->roamingConsortiumIds[j]; - for (k = 0; k < ANQPO_MAX_OI_LENGTH; k++) - if (0 != rcid[k]) oi_len++; - - dst_hs->rc.oi[j].length = oi_len; - memcpy(dst_hs->rc.oi[j].data, rcid, oi_len); - } - } - dst_hs->rc.numOi = num_oi; - } - } - - err = wldev_iovar_setbuf(bcmcfg_to_prmry_ndev(cfg), "anqpo_pfn_hs_list", - anqpo_hs_list, malloc_size, iovar_buf, WLC_IOCTL_MAXLEN, NULL); - - kfree(anqpo_hs_list); -exit: - kfree(hs_list); - return err; -} -#endif /* ANQPO_SUPPORT */ - -static int -wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0, tmp, type; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_batch_params_t batch_param; - const struct nlattr *iter; - - batch_param.mscan = batch_param.bestn = 0; - batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET; - - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - - switch (type) { - case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN: - batch_param.bestn = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE: - batch_param.mscan = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_REPORT_THRESHOLD: - batch_param.buffer_threshold = nla_get_u32(iter); - break; - default: - WL_ERR(("Unknown type %d\n", type)); - break; - } - } - - if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_BATCH_SCAN_CFG_ID, - &batch_param, 0) < 0) { - WL_ERR(("Could not set batch cfg\n")); - err = -EINVAL; - return err; - } - - return err; -} - -static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = -EINVAL; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int type; - uint32 lazy_roam_enable_flag; - - type = nla_type(data); - - if (type == GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE) { - lazy_roam_enable_flag = nla_get_u32(data); - - err = dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg), - lazy_roam_enable_flag); - - if (unlikely(err)) - WL_ERR(("Could not enable lazy roam:%d \n", err)); - - } - return err; -} - -static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0, tmp, type; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - wlc_roam_exp_params_t roam_param; - const struct nlattr *iter; - - memset(&roam_param, 0, sizeof(roam_param)); - - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - - switch (type) { - case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD: - roam_param.a_band_boost_threshold = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD: - roam_param.a_band_penalty_threshold = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR: - roam_param.a_band_boost_factor = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR: - roam_param.a_band_penalty_factor = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST: - roam_param.a_band_max_boost = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS: - roam_param.cur_bssid_boost = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER: - roam_param.alert_roam_trigger_threshold = nla_get_u32(iter); - break; - } - } - - if (dhd_dev_set_lazy_roam_cfg(bcmcfg_to_prmry_ndev(cfg), &roam_param) < 0) { - WL_ERR(("Could not set batch cfg\n")); - err = -EINVAL; - } - return err; -} - -/* small helper function */ -static wl_bssid_pref_cfg_t * -create_bssid_pref_cfg(uint32 num) -{ - uint32 mem_needed; - wl_bssid_pref_cfg_t *bssid_pref; - - mem_needed = sizeof(wl_bssid_pref_cfg_t); - if (num) - mem_needed += (num - 1) * sizeof(wl_bssid_pref_list_t); - bssid_pref = (wl_bssid_pref_cfg_t *) kmalloc(mem_needed, GFP_KERNEL); - return bssid_pref; -} - -static int -wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - wl_bssid_pref_cfg_t *bssid_pref = NULL; - wl_bssid_pref_list_t *bssids; - int tmp, tmp1, tmp2, type; - const struct nlattr *outer, *inner, *iter; - uint32 flush = 0, i = 0, num = 0; - - /* Assumption: NUM attribute must come first */ - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_NUM_BSSID: - num = nla_get_u32(iter); - if (num > MAX_BSSID_PREF_LIST_NUM) { - WL_ERR(("Too many Preferred BSSIDs!\n")); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH: - flush = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_BSSID_PREF_LIST: - if (!num) - return -EINVAL; - if ((bssid_pref = create_bssid_pref_cfg(num)) == NULL) { - WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__)); - err = -ENOMEM; - goto exit; - } - bssid_pref->count = num; - bssids = bssid_pref->bssids; - nla_for_each_nested(outer, iter, tmp) { - if (i >= num) { - WL_ERR(("CFGs don't seem right!\n")); - err = -EINVAL; - goto exit; - } - nla_for_each_nested(inner, outer, tmp1) { - type = nla_type(inner); - switch (type) { - case GSCAN_ATTRIBUTE_BSSID_PREF: - memcpy(&(bssids[i].bssid), - nla_data(inner), ETHER_ADDR_LEN); - /* not used for now */ - bssids[i].flags = 0; - break; - case GSCAN_ATTRIBUTE_RSSI_MODIFIER: - bssids[i].rssi_factor = - (int8) nla_get_u32(inner); - break; - } - } - i++; - } - break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - break; - } - } - - if (!bssid_pref) { - /* What if only flush is desired? */ - if (flush) { - if ((bssid_pref = create_bssid_pref_cfg(0)) == NULL) { - WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__)); - err = -ENOMEM; - goto exit; - } - bssid_pref->count = 0; - } else { - err = -EINVAL; - goto exit; - } - } - err = dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg), - bssid_pref, flush); -exit: - kfree(bssid_pref); - return err; -} - - -static int -wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - maclist_t *blacklist = NULL; - int err = 0; - int type, tmp; - const struct nlattr *iter; - uint32 mem_needed = 0, flush = 0, num = 0; - - /* Assumption: NUM attribute must come first */ - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_NUM_BSSID: - if (num != 0) { - WL_ERR(("attempt to change BSSID num\n")); - err = -EINVAL; - goto exit; - } - if (nla_len(iter) != sizeof(uint32)) { - WL_ERR(("not matching nla_len.\n")); - err = -EINVAL; - goto exit; - } - num = nla_get_u32(iter); - if (num == 0 || num > MAX_BSSID_BLACKLIST_NUM) { - WL_ERR(("wrong BSSID count:%d\n", num)); - err = -EINVAL; - goto exit; - } - if (!blacklist) { - mem_needed = OFFSETOF(maclist_t, ea) + - sizeof(struct ether_addr) * (num); - blacklist = (maclist_t *) - kzalloc(mem_needed, GFP_KERNEL); - if (!blacklist) { - WL_ERR(("kzalloc failed.\n")); - err = -ENOMEM; - goto exit; - } - } - break; - case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH: - if (nla_len(iter) != sizeof(uint32)) { - WL_ERR(("not matching nla_len.\n")); - err = -EINVAL; - goto exit; - } - flush = nla_get_u32(iter); - if (flush != 1) { - WL_ERR(("flush arg is worng:%d\n", flush)); - err = -EINVAL; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_BLACKLIST_BSSID: - if (num == 0 || !blacklist) { - WL_ERR(("number of BSSIDs not received.\n")); - err = -EINVAL; - goto exit; - } - if (nla_len(iter) != ETHER_ADDR_LEN) { - WL_ERR(("not matching nla_len.\n")); - err = -EINVAL; - goto exit; - } - if (blacklist->count >= num) { - WL_ERR(("too many BSSIDs than expected:%d\n", - blacklist->count)); - err = -EINVAL; - goto exit; - } - memcpy(&(blacklist->ea[blacklist->count]), nla_data(iter), - ETHER_ADDR_LEN); - blacklist->count++; - break; - default: - WL_ERR(("No such attribute:%d\n", type)); - break; - } - } - - if (blacklist && (blacklist->count != num)) { - WL_ERR(("not matching bssid count:%d to expected:%d\n", - blacklist->count, num)); - err = -EINVAL; - goto exit; - } - - err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg), - blacklist, mem_needed, flush); -exit: - kfree(blacklist); - return err; -} - -static int -wl_cfgvendor_set_ssid_whitelist(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - wl_ssid_whitelist_t *ssid_whitelist = NULL; - wlc_ssid_t *ssid_elem; - int tmp, tmp2, mem_needed = 0, type; - const struct nlattr *inner, *iter; - uint32 flush = 0, i = 0, num = 0; - - /* Assumption: NUM attribute must come first */ - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - switch (type) { - case GSCAN_ATTRIBUTE_NUM_WL_SSID: - num = nla_get_u32(iter); - if (num > MAX_SSID_WHITELIST_NUM) { - WL_ERR(("Too many WL SSIDs!\n")); - err = -EINVAL; - goto exit; - } - mem_needed = sizeof(wl_ssid_whitelist_t); - if (num) - mem_needed += (num - 1) * sizeof(ssid_info_t); - ssid_whitelist = (wl_ssid_whitelist_t *) - kzalloc(mem_needed, GFP_KERNEL); - if (ssid_whitelist == NULL) { - WL_ERR(("%s: Can't malloc %d bytes\n", - __FUNCTION__, mem_needed)); - err = -ENOMEM; - goto exit; - } - ssid_whitelist->ssid_count = num; - break; - case GSCAN_ATTRIBUTE_WL_SSID_FLUSH: - flush = nla_get_u32(iter); - break; - case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM: - if (!num || !ssid_whitelist) { - WL_ERR(("num ssid is not set!\n")); - return -EINVAL; - } - if (i >= num) { - WL_ERR(("CFGs don't seem right!\n")); - err = -EINVAL; - goto exit; - } - ssid_elem = &ssid_whitelist->ssids[i]; - nla_for_each_nested(inner, iter, tmp) { - type = nla_type(inner); - switch (type) { - case GSCAN_ATTRIBUTE_WHITELIST_SSID: - memcpy(ssid_elem->SSID, - nla_data(inner), - DOT11_MAX_SSID_LEN); - break; - case GSCAN_ATTRIBUTE_WL_SSID_LEN: - ssid_elem->SSID_len = (uint8) - nla_get_u32(inner); - break; - } - } - i++; - break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - break; - } - } - - err = dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg), - ssid_whitelist, mem_needed, flush); -exit: - kfree(ssid_whitelist); - return err; -} -#endif /* GSCAN_SUPPORT */ - -#ifdef RSSI_MONITOR_SUPPORT -static int -wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0, tmp, type, start = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int8 max_rssi = 0, min_rssi = 0; - const struct nlattr *iter; - - nla_for_each_attr(iter, data, len, tmp) { - type = nla_type(iter); - switch (type) { - case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI: - max_rssi = (int8) nla_get_u32(iter); - break; - case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI: - min_rssi = (int8) nla_get_u32(iter); - break; - case RSSI_MONITOR_ATTRIBUTE_START: - start = nla_get_u32(iter); - } - } - - if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg), - start, max_rssi, min_rssi) < 0) { - WL_ERR(("Could not set rssi monitor cfg\n")); - err = -EINVAL; - } - return err; -} -#endif /* RSSI_MONITOR_SUPPORT */ - -#ifdef RTT_SUPPORT -void -wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data) -{ - struct wireless_dev *wdev = (struct wireless_dev *)ctx; - struct wiphy *wiphy; - struct sk_buff *skb; - uint32 complete = 0; - gfp_t kflags; - rtt_result_t *rtt_result; - rtt_results_header_t *rtt_header; - struct list_head *rtt_cache_list; - struct nlattr *rtt_nl_hdr; - wiphy = wdev->wiphy; - - WL_DBG(("In\n")); - /* Push the data to the skb */ - if (!rtt_data) { - WL_ERR(("rtt_data is NULL\n")); - goto exit; - } - rtt_cache_list = (struct list_head *)rtt_data; - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - list_for_each_entry(rtt_header, rtt_cache_list, list) { - /* Alloc the SKB for vendor_event */ - skb = cfg80211_vendor_event_alloc(wiphy, rtt_header->result_tot_len + 100, - GOOGLE_RTT_COMPLETE_EVENT, kflags); - if (!skb) { - WL_ERR(("skb alloc failed")); - goto exit; - } - if (list_is_last(&rtt_header->list, rtt_cache_list)) { - complete = 1; - } - nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, complete); - rtt_nl_hdr = nla_nest_start(skb, RTT_ATTRIBUTE_RESULTS_PER_TARGET); - if (!rtt_nl_hdr) { - WL_ERR(("rtt_nl_hdr is NULL\n")); - break; - } - nla_put(skb, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN, &rtt_header->peer_mac); - nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_CNT, rtt_header->result_cnt); - list_for_each_entry(rtt_result, &rtt_header->result_list, list) { - nla_put(skb, RTT_ATTRIBUTE_RESULT, - rtt_result->report_len, &rtt_result->report); - } - nla_nest_end(skb, rtt_nl_hdr); - cfg80211_vendor_event(skb, kflags); - } -exit: - return; -} - -static int -wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) { - int err = 0, rem, rem1, rem2, type; - int target_cnt; - rtt_config_params_t rtt_param; - rtt_target_info_t* rtt_target = NULL; - const struct nlattr *iter, *iter1, *iter2; - int8 eabuf[ETHER_ADDR_STR_LEN]; - int8 chanbuf[CHANSPEC_STR_LEN]; - int32 feature_set = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - rtt_capabilities_t capability; - feature_set = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg)); - - WL_DBG(("In\n")); - err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt); - if (err < 0) { - WL_ERR(("failed to register rtt_noti_callback\n")); - goto exit; - } - err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability); - if (err < 0) { - WL_ERR(("failed to get the capability\n")); - goto exit; - } - memset(&rtt_param, 0, sizeof(rtt_param)); - if (len <= 0) { - WL_ERR(("Length of the nlattr is not valid len : %d\n", len)); - err = BCME_ERROR; - goto exit; - } - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case RTT_ATTRIBUTE_TARGET_CNT: - target_cnt = nla_get_u8(iter); - if ((target_cnt <= 0) || (target_cnt > RTT_MAX_TARGET_CNT)) { - WL_ERR(("target_cnt is not valid : %d\n", - target_cnt)); - err = BCME_RANGE; - goto exit; - } - rtt_param.rtt_target_cnt = target_cnt; - rtt_param.target_info = kzalloc(TARGET_INFO_SIZE(target_cnt), GFP_KERNEL); - if (rtt_param.target_info == NULL) { - WL_ERR(("failed to allocate target info for (%d)\n", target_cnt)); - err = BCME_NOMEM; - goto exit; - } - break; - case RTT_ATTRIBUTE_TARGET_INFO: - /* Added this variable for safe check to avoid crash - * incase the caller did not respect the order - */ - if (rtt_param.target_info == NULL) { - WL_ERR(("rtt_target_info is NULL\n")); - err = BCME_NOMEM; - goto exit; - } - rtt_target = rtt_param.target_info; - nla_for_each_nested(iter1, iter, rem1) { - nla_for_each_nested(iter2, iter1, rem2) { - type = nla_type(iter2); - switch (type) { - case RTT_ATTRIBUTE_TARGET_MAC: - memcpy(&rtt_target->addr, nla_data(iter2), - ETHER_ADDR_LEN); - break; - case RTT_ATTRIBUTE_TARGET_TYPE: - rtt_target->type = nla_get_u8(iter2); - if (rtt_target->type == RTT_INVALID || - (rtt_target->type == RTT_ONE_WAY && - !capability.rtt_one_sided_supported)) { - WL_ERR(("doesn't support RTT type" - " : %d\n", - rtt_target->type)); - err = -EINVAL; - goto exit; - } - break; - case RTT_ATTRIBUTE_TARGET_PEER: - rtt_target->peer = nla_get_u8(iter2); - break; - case RTT_ATTRIBUTE_TARGET_CHAN: - memcpy(&rtt_target->channel, nla_data(iter2), - sizeof(rtt_target->channel)); - break; - case RTT_ATTRIBUTE_TARGET_INTERVAL: - rtt_target->interval = nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_NUM_BURST: - rtt_target->num_burst = nla_get_u32(iter2); - if (!(rtt_target->num_burst == 1 || - ISPOWEROF2(rtt_target->num_burst))) { - WL_ERR(("%d value must be power of 2" - " or 1\n", - rtt_target->num_burst)); - err = -EINVAL; - goto exit; - } - break; - case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST: - rtt_target->num_frames_per_burst = - nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM: - rtt_target->num_retries_per_ftm = - nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR: - rtt_target->num_retries_per_ftmr = - nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_LCI: - rtt_target->LCI_request = nla_get_u8(iter2); - break; - case RTT_ATTRIBUTE_TARGET_LCR: - rtt_target->LCI_request = nla_get_u8(iter2); - break; - case RTT_ATTRIBUTE_TARGET_BURST_TIMEOUT: - rtt_target->burst_timeout = nla_get_u32(iter2); - break; - case RTT_ATTRIBUTE_TARGET_BW: - rtt_target->bw = nla_get_u8(iter2); - } - } - /* convert to chanspec value */ - rtt_target->chanspec = - dhd_rtt_convert_to_chspec(rtt_target->channel); - if (rtt_target->chanspec == 0) { - WL_ERR(("Channel is not valid \n")); - err = -EINVAL; - goto exit; - } - WL_INFO(("Target addr %s, Channel : %s for RTT \n", - bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, - eabuf), - wf_chspec_ntoa(rtt_target->chanspec, chanbuf))); - rtt_target++; - } - break; - } - } - WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt)); - if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) { - WL_ERR(("Could not set RTT configuration\n")); - err = -EINVAL; - } -exit: - /* free the target info list */ - if (rtt_param.target_info) { - kfree(rtt_param.target_info); - rtt_param.target_info = NULL; - } - return err; -} - -static int -wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) -{ - int err = 0, rem, type, target_cnt = 0; - int target_cnt_chk = 0; - const struct nlattr *iter; - struct ether_addr *mac_list = NULL, *mac_addr = NULL; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (len <= 0) { - WL_ERR(("Length of nlattr is not valid len : %d\n", len)); - err = -EINVAL; - goto exit; - } - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case RTT_ATTRIBUTE_TARGET_CNT: - if (mac_list != NULL) { - WL_ERR(("mac_list is not NULL\n")); - err = -EINVAL; - goto exit; - } - target_cnt = nla_get_u8(iter); - if ((target_cnt > 0) && (target_cnt < RTT_MAX_TARGET_CNT)) { - mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN, - GFP_KERNEL); - if (mac_list == NULL) { - WL_ERR(("failed to allocate mem for mac list\n")); - err = -EINVAL; - goto exit; - } - mac_addr = &mac_list[0]; - } else { - /* cancel the current whole RTT process */ - goto cancel; - } - break; - case RTT_ATTRIBUTE_TARGET_MAC: - if (mac_addr) { - memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN); - target_cnt_chk++; - if (target_cnt_chk > target_cnt) { - WL_ERR(("over target count\n")); - err = -EINVAL; - goto exit; - } - break; - } else { - WL_ERR(("mac_list is NULL\n")); - err = -EINVAL; - goto exit; - } - } - } -cancel: - if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) { - WL_ERR(("Could not cancel RTT configuration\n")); - err = -EINVAL; - } - -exit: - if (mac_list) { - kfree(mac_list); - } - return err; -} -static int -wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - rtt_capabilities_t capability; - - err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability); - if (unlikely(err)) { - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - goto exit; - } - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - &capability, sizeof(capability)); - - if (unlikely(err)) { - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - } -exit: - return err; -} - -#endif /* RTT_SUPPORT */ - -#if defined(KEEP_ALIVE) -static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) -{ - /* max size of IP packet for keep alive */ - const int MKEEP_ALIVE_IP_PKT_MAX = 256; - - int ret = BCME_OK, rem, type; - u8 mkeep_alive_id = 0; - u8 *ip_pkt = NULL; - u16 ip_pkt_len = 0; - u8 src_mac[ETHER_ADDR_LEN]; - u8 dst_mac[ETHER_ADDR_LEN]; - u32 period_msec = 0; - const struct nlattr *iter; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_pub_t *dhd_pub = cfg->pub; - gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case MKEEP_ALIVE_ATTRIBUTE_ID: - mkeep_alive_id = nla_get_u8(iter); - break; - case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN: - ip_pkt_len = nla_get_u16(iter); - if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) { - ret = BCME_BADARG; - goto exit; - } - break; - case MKEEP_ALIVE_ATTRIBUTE_IP_PKT: - ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags); - if (ip_pkt == NULL) { - ret = BCME_NOMEM; - WL_ERR(("Failed to allocate mem for ip packet\n")); - goto exit; - } - memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len); - break; - case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR: - memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN); - break; - case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR: - memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN); - break; - case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC: - period_msec = nla_get_u32(iter); - break; - default: - WL_ERR(("Unknown type: %d\n", type)); - ret = BCME_BADARG; - goto exit; - } - } - - ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac, - dst_mac, period_msec); - if (ret < 0) { - WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret)); - } - -exit: - if (ip_pkt) { - kfree(ip_pkt); - } - - return ret; -} - -static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int len) -{ - int ret = BCME_OK, rem, type; - u8 mkeep_alive_id = 0; - const struct nlattr *iter; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - dhd_pub_t *dhd_pub = cfg->pub; - - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case MKEEP_ALIVE_ATTRIBUTE_ID: - mkeep_alive_id = nla_get_u8(iter); - break; - default: - WL_ERR(("Unknown type: %d\n", type)); - ret = BCME_BADARG; - break; - } - } - - ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id); - if (ret < 0) { - WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret)); - } - - return ret; -} -#endif /* defined(KEEP_ALIVE) */ - -#ifdef LINKSTAT_SUPPORT -#define NUM_RATE 32 -#define NUM_PEER 1 -#define NUM_CHAN 11 -static int -wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - char *iovar_buf = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int err = 0; - wifi_iface_stat *iface; - wifi_radio_stat *radio; - wl_wme_cnt_t *wl_wme_cnt; - wl_cnt_t *wl_cnt; - char *output; -#ifdef LINKSTAT_V2 - int i = 0; - wifi_radio_stat_v2 *p_radio_stat_v2 = NULL; - wifi_rate_stat_v2 *p_wifi_rate_stat_v2 = NULL; - wifi_rate_stat *p_wifi_rate_stat = NULL; -#endif /* LINKSTAT_V2 */ - - int radstat_buflen = sizeof(wifi_radio_stat) + NUM_CHAN * sizeof(wifi_channel_stat); - int iface_buflen = sizeof(wifi_iface_stat) + NUM_PEER * sizeof(wifi_peer_info); - int ratestat_buflen = NUM_RATE * sizeof(wifi_rate_stat); - - WL_TRACE(("%s: Enter \n", __FUNCTION__)); - - RETURN_EIO_IF_NOT_UP(cfg); - - iovar_buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL); - if (unlikely(!iovar_buf)) { - WL_ERR(("%s: link stats buf alloc fails\n", __FUNCTION__)); - return -ENOMEM; - } - - ASSERT((radstat_buflen + iface_buflen + ratestat_buflen) <= - (sizeof(char) * WLC_IOCTL_MAXLEN)); - - output = iovar_buf; - radio = (wifi_radio_stat *)output; - - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("%s: ioctl error(%d) for radiostat - size = %zu\n", - __FUNCTION__, err, sizeof(wifi_radio_stat))); - goto exit; - } - -#ifdef LINKSTAT_V2 - p_radio_stat_v2 = (wifi_radio_stat_v2 *)cfg->ioctl_buf; - memcpy(output, &(p_radio_stat_v2->radio), sizeof(wifi_radio_stat)); -#else - memcpy(output, cfg->ioctl_buf, sizeof(wifi_radio_stat)); -#endif /* LINKSTAT_V2 */ - radio->num_channels = NUM_CHAN; - output += radstat_buflen; - - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "wme_counters", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("%s: ioctl error(%d) for wme_counters\n", __FUNCTION__, err)); - goto exit; - } - wl_wme_cnt = (wl_wme_cnt_t *)cfg->ioctl_buf; - iface = (wifi_iface_stat *)output; - - iface->ac[WIFI_AC_VO].ac = WIFI_AC_VO; - iface->ac[WIFI_AC_VO].tx_mpdu = wl_wme_cnt->tx[AC_VO].packets; - iface->ac[WIFI_AC_VO].rx_mpdu = wl_wme_cnt->rx[AC_VO].packets; - iface->ac[WIFI_AC_VO].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VO].packets; - - iface->ac[WIFI_AC_VI].ac = WIFI_AC_VI; - iface->ac[WIFI_AC_VI].tx_mpdu = wl_wme_cnt->tx[AC_VI].packets; - iface->ac[WIFI_AC_VI].rx_mpdu = wl_wme_cnt->rx[AC_VI].packets; - iface->ac[WIFI_AC_VI].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VI].packets; - - iface->ac[WIFI_AC_BE].ac = WIFI_AC_BE; - iface->ac[WIFI_AC_BE].tx_mpdu = wl_wme_cnt->tx[AC_BE].packets; - iface->ac[WIFI_AC_BE].rx_mpdu = wl_wme_cnt->rx[AC_BE].packets; - iface->ac[WIFI_AC_BE].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BE].packets; - - iface->ac[WIFI_AC_BK].ac = WIFI_AC_BK; - iface->ac[WIFI_AC_BK].tx_mpdu = wl_wme_cnt->tx[AC_BK].packets; - iface->ac[WIFI_AC_BK].rx_mpdu = wl_wme_cnt->rx[AC_BK].packets; - iface->ac[WIFI_AC_BK].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BK].packets; - - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("%s: ioctl error(%d) for counters - size = %zu\n", - __FUNCTION__, err, sizeof(wl_cnt_t))); - goto exit; - } - wl_cnt = (wl_cnt_t *)cfg->ioctl_buf; - iface->ac[WIFI_AC_BE].retries = wl_cnt->txretry; - iface->beacon_rx = wl_cnt->rxbeaconmbss; - - err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &iface->rssi_mgmt); - if (unlikely(err)) { - WL_ERR(("%s: get_rssi error(%d)\n", __FUNCTION__, err)); - goto exit; - } - - iface->num_peers = NUM_PEER; - iface->peer_info->num_rate = NUM_RATE; - - output = (char *)iface + iface_buflen; - - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("%s: ioctl error(%d) for ratestat - size = %d\n", - __FUNCTION__, err, ratestat_buflen)); - goto exit; - } -#ifdef LINKSTAT_V2 - /* ratestat structure is mismatched with android framework need to recompose it */ - for (i = 0; i < NUM_RATE; i++) { - p_wifi_rate_stat_v2 = - (wifi_rate_stat_v2 *)(cfg->ioctl_buf + i*sizeof(wifi_rate_stat_v2)); - - /* transform wifi_rate_v2 to wifi_rate */ - p_wifi_rate_stat = (wifi_rate_stat *)output; - p_wifi_rate_stat->rate.preamble = p_wifi_rate_stat_v2->rate.preamble; - p_wifi_rate_stat->rate.nss = p_wifi_rate_stat_v2->rate.nss; - p_wifi_rate_stat->rate.bw = p_wifi_rate_stat_v2->rate.bw; - p_wifi_rate_stat->rate.rateMcsIdx = p_wifi_rate_stat_v2->rate.rateMcsIdx; - p_wifi_rate_stat->rate.bitrate = p_wifi_rate_stat_v2->rate.bitrate; - p_wifi_rate_stat->tx_mpdu = p_wifi_rate_stat_v2->tx_mpdu; - p_wifi_rate_stat->rx_mpdu = p_wifi_rate_stat_v2->rx_mpdu; - p_wifi_rate_stat->mpdu_lost = p_wifi_rate_stat_v2->mpdu_lost; - p_wifi_rate_stat->retries = p_wifi_rate_stat_v2->retries; - p_wifi_rate_stat->retries_short = p_wifi_rate_stat_v2->retries_short; - p_wifi_rate_stat->retries_long = p_wifi_rate_stat_v2->retries_long; - - output += sizeof(wifi_rate_stat); - } -#else - memcpy(output, cfg->ioctl_buf, ratestat_buflen); -#endif /* LINKSTAT_V2 */ - if (unlikely(radio->num_channels != NUM_CHAN)) { - WL_ERR(("%s: error! num_channels corrupted. value=%d \n", - __FUNCTION__, (int)radio->num_channels)); - goto exit; - } - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - iovar_buf, radstat_buflen + iface_buflen + ratestat_buflen); - if (unlikely(err)) { - WL_ERR(("%s: Vendor Command reply failed ret:%d \n", __FUNCTION__, err)); - } - -exit: - if (iovar_buf) { - kfree(iovar_buf); - } - - return err; -} -#endif /* LINKSTAT_SUPPORT */ - -static int wl_cfgvendor_set_country(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = BCME_ERROR, rem, type; - char country_code[WLC_CNTRY_BUF_SZ] = {0}; - const struct nlattr *iter; - - nla_for_each_attr(iter, data, len, rem) { - type = nla_type(iter); - switch (type) { - case ANDR_WIFI_ATTRIBUTE_COUNTRY: - memcpy(country_code, nla_data(iter), - MIN(nla_len(iter), WLC_CNTRY_BUF_SZ)); - break; - default: - WL_ERR(("Unknown type: %d\n", type)); - return err; - } - } - - err = wldev_set_country(wdev->netdev, country_code, true, true); - if (err < 0) { - WL_ERR(("Set country failed ret:%d\n", err)); - } - - return err; -} - -static const struct wiphy_vendor_command wl_vendor_cmds [] = { -#ifdef GSCAN_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_get_capabilities - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_scan_cfg - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_batch_scan_cfg - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_initiate_gscan - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_enable_full_scan_result - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_HOTLIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_hotlist_cfg - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_get_batch_results - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_get_channel_list - }, -#endif /* GSCAN_SUPPORT */ -#ifdef RTT_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_SET_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_set_config - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_CANCEL_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_cancel_config - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_GETCAPABILITY - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_get_capability - }, -#endif /* RTT_SUPPORT */ - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_get_feature_set - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_get_feature_set_matrix - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_RANDOM_MAC_OUI - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_rand_mac_oui - }, -#ifdef CUSTOM_FORCE_NODFS_FLAG - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_NODFS_CHANNELS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_nodfs_flag - - }, -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -#ifdef LINKSTAT_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = LSTATS_SUBCMD_GET_INFO - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_lstats_get_info - }, -#endif /* LINKSTAT_SUPPORT */ -#ifdef KEEP_ALIVE - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_start_mkeep_alive - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_stop_mkeep_alive - }, -#endif /* KEEP_ALIVE */ - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_SET_COUNTRY - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_country - }, -#ifdef GSCAN_SUPPORT -#ifdef EPNO_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_epno_cfg - - }, -#endif /* EPNO_SUPPORT */ - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_ssid_whitelist - - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_lazy_roam_cfg - - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_enable_lazy_roam - - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_BSSID_PREF - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_bssid_pref - - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_bssid_blacklist - }, -#ifdef ANQPO_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_ANQPO_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_anqpo_config - }, -#endif /* ANQPO_SUPPORT */ -#endif /* GSCAN_SUPPORT */ -#ifdef RSSI_MONITOR_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_rssi_monitor - }, -#endif /* RSSI_MONITOR_SUPPORT */ -}; - -static const struct nl80211_vendor_cmd_info wl_vendor_events [] = { - { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC }, - { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR }, -#ifdef GSCAN_SUPPORT - { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT }, - { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT }, - { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT }, - { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT }, -#endif /* GSCAN_SUPPORT */ - { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT }, -#ifdef GSCAN_SUPPORT - { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT }, - { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT }, - { OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT }, -#endif /* GSCAN_SUPPORT */ - { OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT }, - { OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT }, -#ifdef ANQPO_SUPPORT - { OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT }, -#endif /* ANQPO_SUPPORT */ - { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT }, -#ifdef KEEP_ALIVE - { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT }, -#endif /* KEEP_ALIVE */ -}; - -int wl_cfgvendor_attach(struct wiphy *wiphy) -{ - - WL_INFO(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n", - NL80211_CMD_VENDOR)); - - wiphy->vendor_commands = wl_vendor_cmds; - wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds); - wiphy->vendor_events = wl_vendor_events; - wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events); - - return 0; -} - -int wl_cfgvendor_detach(struct wiphy *wiphy) -{ - WL_INFO(("Vendor: Unregister BRCM cfg80211 vendor interface \n")); - - wiphy->vendor_commands = NULL; - wiphy->vendor_events = NULL; - wiphy->n_vendor_commands = 0; - wiphy->n_vendor_events = 0; - - return 0; -} -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h deleted file mode 100755 index 2212ec3beae9..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Linux cfg80211 Vendor Extension Code - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfgvendor.h 455257 2014-02-13 08:10:24Z $ - */ - -/* - * New vendor interface additon to nl80211/cfg80211 to allow vendors - * to implement proprietary features over the cfg80211 stack. - */ - -#ifndef _wl_cfgvendor_h_ -#define _wl_cfgvendor_h_ - -#define OUI_BRCM 0x001018 -#define OUI_GOOGLE 0x001A11 -#define BRCM_VENDOR_SUBCMD_PRIV_STR 1 -#define ATTRIBUTE_U32_LEN (NLA_HDRLEN + 4) -#define VENDOR_ID_OVERHEAD ATTRIBUTE_U32_LEN -#define VENDOR_SUBCMD_OVERHEAD ATTRIBUTE_U32_LEN -#define VENDOR_DATA_OVERHEAD (NLA_HDRLEN) - -#define SCAN_RESULTS_COMPLETE_FLAG_LEN ATTRIBUTE_U32_LEN -#define SCAN_INDEX_HDR_LEN (NLA_HDRLEN) -#define SCAN_ID_HDR_LEN ATTRIBUTE_U32_LEN -#define SCAN_FLAGS_HDR_LEN ATTRIBUTE_U32_LEN -#define GSCAN_NUM_RESULTS_HDR_LEN ATTRIBUTE_U32_LEN -#define GSCAN_RESULTS_HDR_LEN (NLA_HDRLEN) -#define GSCAN_BATCH_RESULT_HDR_LEN (SCAN_INDEX_HDR_LEN + SCAN_ID_HDR_LEN + \ - SCAN_FLAGS_HDR_LEN + \ - GSCAN_NUM_RESULTS_HDR_LEN + \ - GSCAN_RESULTS_HDR_LEN) - -#define VENDOR_REPLY_OVERHEAD (VENDOR_ID_OVERHEAD + \ - VENDOR_SUBCMD_OVERHEAD + \ - VENDOR_DATA_OVERHEAD) - -typedef enum { - /* don't use 0 as a valid subcommand */ - VENDOR_NL80211_SUBCMD_UNSPECIFIED, - - /* define all vendor startup commands between 0x0 and 0x0FFF */ - VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001, - VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF, - - /* define all GScan related commands between 0x1000 and 0x10FF */ - ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000, - ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF, - - /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */ - ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100, - ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF, - - /* define all RTT related commands between 0x1100 and 0x11FF */ - ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100, - ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF, - - ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200, - ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF, - - ANDROID_NL80211_SUBCMD_TDLS_RANGE_START = 0x1300, - ANDROID_NL80211_SUBCMD_TDLS_RANGE_END = 0x13FF, - - /* define all wifi calling related commands between 0x1600 and 0x16FF */ - ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600, - ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF, - - /* This is reserved for future usage */ - -} ANDROID_VENDOR_SUB_COMMAND; - -enum andr_vendor_subcmd { - GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START, - GSCAN_SUBCMD_SET_CONFIG, - GSCAN_SUBCMD_SET_SCAN_CONFIG, - GSCAN_SUBCMD_ENABLE_GSCAN, - GSCAN_SUBCMD_GET_SCAN_RESULTS, - GSCAN_SUBCMD_SCAN_RESULTS, - GSCAN_SUBCMD_SET_HOTLIST, - GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, - GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, - GSCAN_SUBCMD_GET_CHANNEL_LIST, - ANDR_WIFI_SUBCMD_GET_FEATURE_SET, - ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, - ANDR_WIFI_RANDOM_MAC_OUI, - ANDR_WIFI_NODFS_CHANNELS, - ANDR_WIFI_SET_COUNTRY, - GSCAN_SUBCMD_SET_EPNO_SSID, - WIFI_SUBCMD_SET_SSID_WHITELIST, - WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS, - WIFI_SUBCMD_ENABLE_LAZY_ROAM, - WIFI_SUBCMD_SET_BSSID_PREF, - WIFI_SUBCMD_SET_BSSID_BLACKLIST, - GSCAN_SUBCMD_ANQPO_CONFIG, - WIFI_SUBCMD_SET_RSSI_MONITOR, - RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, - RTT_SUBCMD_CANCEL_CONFIG, - RTT_SUBCMD_GETCAPABILITY, - - LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START, - - WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START, - WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE, - - /* Add more sub commands here */ - VENDOR_SUBCMD_MAX -}; - -enum gscan_attributes { - GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, - GSCAN_ATTRIBUTE_BASE_PERIOD, - GSCAN_ATTRIBUTE_BUCKETS_BAND, - GSCAN_ATTRIBUTE_BUCKET_ID, - GSCAN_ATTRIBUTE_BUCKET_PERIOD, - GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, - GSCAN_ATTRIBUTE_BUCKET_CHANNELS, - GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, - GSCAN_ATTRIBUTE_REPORT_THRESHOLD, - GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, - GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND, - - GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, - GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, - GSCAN_ATTRIBUTE_FLUSH_FEATURE, - GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS, - GSCAN_ATTRIBUTE_REPORT_EVENTS, - /* remaining reserved for additional attributes */ - GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, - GSCAN_ATTRIBUTE_FLUSH_RESULTS, - GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ - GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ - GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ - GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ - GSCAN_ATTRIBUTE_NUM_CHANNELS, - GSCAN_ATTRIBUTE_CHANNEL_LIST, - - /* remaining reserved for additional attributes */ - - GSCAN_ATTRIBUTE_SSID = 40, - GSCAN_ATTRIBUTE_BSSID, - GSCAN_ATTRIBUTE_CHANNEL, - GSCAN_ATTRIBUTE_RSSI, - GSCAN_ATTRIBUTE_TIMESTAMP, - GSCAN_ATTRIBUTE_RTT, - GSCAN_ATTRIBUTE_RTTSD, - - /* remaining reserved for additional attributes */ - - GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, - GSCAN_ATTRIBUTE_RSSI_LOW, - GSCAN_ATTRIBUTE_RSSI_HIGH, - GSCAN_ATTRIBUTE_HOSTLIST_BSSID_ELEM, - GSCAN_ATTRIBUTE_HOTLIST_FLUSH, - - /* remaining reserved for additional attributes */ - GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, - GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, - GSCAN_ATTRIBUTE_MIN_BREACHING, - GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, - GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, - /* EPNO */ - GSCAN_ATTRIBUTE_EPNO_SSID_LIST = 70, - GSCAN_ATTRIBUTE_EPNO_SSID, - GSCAN_ATTRIBUTE_EPNO_SSID_LEN, - GSCAN_ATTRIBUTE_EPNO_RSSI, - GSCAN_ATTRIBUTE_EPNO_FLAGS, - GSCAN_ATTRIBUTE_EPNO_AUTH, - GSCAN_ATTRIBUTE_EPNO_SSID_NUM, - GSCAN_ATTRIBUTE_EPNO_FLUSH, - - /* Roam SSID Whitelist and BSSID pref */ - GSCAN_ATTRIBUTE_WHITELIST_SSID = 80, - GSCAN_ATTRIBUTE_NUM_WL_SSID, - GSCAN_ATTRIBUTE_WL_SSID_LEN, - GSCAN_ATTRIBUTE_WL_SSID_FLUSH, - GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM, - GSCAN_ATTRIBUTE_NUM_BSSID, - GSCAN_ATTRIBUTE_BSSID_PREF_LIST, - GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH, - GSCAN_ATTRIBUTE_BSSID_PREF, - GSCAN_ATTRIBUTE_RSSI_MODIFIER, - - - /* Roam cfg */ - GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD = 90, - GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD, - GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR, - GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR, - GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST, - GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS, - GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER, - GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE, - - /* BSSID blacklist */ - GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH = 100, - GSCAN_ATTRIBUTE_BLACKLIST_BSSID, - - GSCAN_ATTRIBUTE_ANQPO_HS_LIST = 110, - GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, - GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, - GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, - GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID, - GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, - - /* Adaptive scan attributes */ - GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 120, - GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD, - - GSCAN_ATTRIBUTE_MAX -}; - -enum gscan_bucket_attributes { - GSCAN_ATTRIBUTE_CH_BUCKET_1, - GSCAN_ATTRIBUTE_CH_BUCKET_2, - GSCAN_ATTRIBUTE_CH_BUCKET_3, - GSCAN_ATTRIBUTE_CH_BUCKET_4, - GSCAN_ATTRIBUTE_CH_BUCKET_5, - GSCAN_ATTRIBUTE_CH_BUCKET_6, - GSCAN_ATTRIBUTE_CH_BUCKET_7 -}; - -enum gscan_ch_attributes { - GSCAN_ATTRIBUTE_CH_ID_1, - GSCAN_ATTRIBUTE_CH_ID_2, - GSCAN_ATTRIBUTE_CH_ID_3, - GSCAN_ATTRIBUTE_CH_ID_4, - GSCAN_ATTRIBUTE_CH_ID_5, - GSCAN_ATTRIBUTE_CH_ID_6, - GSCAN_ATTRIBUTE_CH_ID_7 -}; - -enum rtt_attributes { - RTT_ATTRIBUTE_TARGET_CNT, - RTT_ATTRIBUTE_TARGET_INFO, - RTT_ATTRIBUTE_TARGET_MAC, - RTT_ATTRIBUTE_TARGET_TYPE, - RTT_ATTRIBUTE_TARGET_PEER, - RTT_ATTRIBUTE_TARGET_CHAN, - RTT_ATTRIBUTE_TARGET_INTERVAL, - RTT_ATTRIBUTE_TARGET_NUM_BURST, - RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, - RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, - RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, - RTT_ATTRIBUTE_TARGET_LCI, - RTT_ATTRIBUTE_TARGET_LCR, - RTT_ATTRIBUTE_TARGET_BURST_TIMEOUT, - RTT_ATTRIBUTE_TARGET_PREAMBLE, - RTT_ATTRIBUTE_TARGET_BW, - RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, - RTT_ATTRIBUTE_RESULTS_PER_TARGET, - RTT_ATTRIBUTE_RESULT_CNT, - RTT_ATTRIBUTE_RESULT -}; - -enum wifi_rssi_monitor_attr { - RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, - RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, - RSSI_MONITOR_ATTRIBUTE_START -}; - -typedef enum wl_vendor_event { - BRCM_VENDOR_EVENT_UNSPEC, - BRCM_VENDOR_EVENT_PRIV_STR, - GOOGLE_GSCAN_SIGNIFICANT_EVENT, - GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT, - GOOGLE_GSCAN_BATCH_SCAN_EVENT, - GOOGLE_SCAN_FULL_RESULTS_EVENT, - GOOGLE_RTT_COMPLETE_EVENT, - GOOGLE_SCAN_COMPLETE_EVENT, - GOOGLE_GSCAN_GEOFENCE_LOST_EVENT, - GOOGLE_SCAN_EPNO_EVENT, - GOOGLE_DEBUG_RING_EVENT, - GOOGLE_FW_DUMP_EVENT, - GOOGLE_PNO_HOTSPOT_FOUND_EVENT, - GOOGLE_RSSI_MONITOR_EVENT, - GOOGLE_MKEEP_ALIVE_EVENT -} wl_vendor_event_t; - -enum andr_wifi_attr { - ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, - ANDR_WIFI_ATTRIBUTE_FEATURE_SET, - ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI, - ANDR_WIFI_ATTRIBUTE_NODFS_SET, - ANDR_WIFI_ATTRIBUTE_COUNTRY -}; - -typedef enum wl_vendor_gscan_attribute { - ATTR_START_GSCAN, - ATTR_STOP_GSCAN, - ATTR_SET_SCAN_BATCH_CFG_ID, /* set batch scan params */ - ATTR_SET_SCAN_GEOFENCE_CFG_ID, /* set list of bssids to track */ - ATTR_SET_SCAN_SIGNIFICANT_CFG_ID, /* set list of bssids, rssi threshold etc.. */ - ATTR_SET_SCAN_CFG_ID, /* set common scan config params here */ - ATTR_GET_GSCAN_CAPABILITIES_ID, - /* Add more sub commands here */ - ATTR_GSCAN_MAX -} wl_vendor_gscan_attribute_t; - -typedef enum gscan_batch_attribute { - ATTR_GSCAN_BATCH_BESTN, - ATTR_GSCAN_BATCH_MSCAN, - ATTR_GSCAN_BATCH_BUFFER_THRESHOLD -} gscan_batch_attribute_t; - -typedef enum gscan_geofence_attribute { - ATTR_GSCAN_NUM_HOTLIST_BSSID, - ATTR_GSCAN_HOTLIST_BSSID -} gscan_geofence_attribute_t; - -typedef enum gscan_complete_event { - WIFI_SCAN_BUFFER_FULL, - WIFI_SCAN_COMPLETE -} gscan_complete_event_t; - -enum mkeep_alive_attributes { - MKEEP_ALIVE_ATTRIBUTE_ID, - MKEEP_ALIVE_ATTRIBUTE_IP_PKT, - MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, - MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, - MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, - MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC -}; - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) -extern int wl_cfgvendor_attach(struct wiphy *wiphy); -extern int wl_cfgvendor_detach(struct wiphy *wiphy); -extern int wl_cfgvendor_send_async_event(struct wiphy *wiphy, - struct net_device *dev, int event_id, const void *data, int len); -extern int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, - struct net_device *dev, void *data, int len, wl_vendor_event_t event); -#else -static INLINE int cfgvendor_attach(struct wiphy *wiphy) { return 0; } -static INLINE int cfgvendor_detach(struct wiphy *wiphy) { return 0; } -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ - -#endif /* _wl_cfgvendor_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h b/drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h deleted file mode 100755 index e41c479a0835..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Minimal debug/trace/assert driver definitions for - * Broadcom 802.11 Networking Adapter. - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_dbg.h 430628 2013-10-19 04:07:25Z $ - */ - - -#ifndef _wl_dbg_h_ -#define _wl_dbg_h_ - -/* wl_msg_level is a bit vector with defs in wlioctl.h */ -extern uint32 wl_msg_level; -extern uint32 wl_msg_level2; - -#define WL_TIMESTAMP() - -#define WL_PRINT(args) do { WL_TIMESTAMP(); printf args; } while (0) - -#if defined(EVENT_LOG_COMPILE) && defined(WLMSG_SRSCAN) -#define _WL_SRSCAN(fmt, ...) EVENT_LOG(EVENT_LOG_TAG_SRSCAN, fmt, ##__VA_ARGS__) -#define WL_SRSCAN(args) _WL_SRSCAN args -#else -#define WL_SRSCAN(args) -#endif - - -/* To disable a message completely ... until you need it again */ -#define WL_NONE(args) - -#define WL_ERROR(args) -#define WL_TRACE(args) -#define WL_APSTA_UPDN(args) -#define WL_APSTA_RX(args) -#ifdef WLMSG_WSEC -#define WL_WSEC(args) WL_PRINT(args) -#define WL_WSEC_DUMP(args) WL_PRINT(args) -#else -#define WL_WSEC(args) -#define WL_WSEC_DUMP(args) -#endif -#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0) -#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL) - -extern uint32 wl_msg_level; -extern uint32 wl_msg_level2; -#endif /* _wl_dbg_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c b/drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c deleted file mode 100755 index 271dfc250a03..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Linux monitor network interface - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_linux_mon.c 425343 2013-09-23 23:04:47Z $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -typedef enum monitor_states -{ - MONITOR_STATE_DEINIT = 0x0, - MONITOR_STATE_INIT = 0x1, - MONITOR_STATE_INTERFACE_ADDED = 0x2, - MONITOR_STATE_INTERFACE_DELETED = 0x4 -} monitor_states_t; -int dhd_add_monitor(char *name, struct net_device **new_ndev); -extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); -int dhd_del_monitor(struct net_device *ndev); -int dhd_monitor_init(void *dhd_pub); -int dhd_monitor_uninit(void); - -/** - * Local declarations and defintions (not exposed) - */ -#ifndef DHD_MAX_IFS -#define DHD_MAX_IFS 16 -#endif -#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__) -#define MON_TRACE MON_PRINT - -typedef struct monitor_interface { - int radiotap_enabled; - struct net_device* real_ndev; /* The real interface that the monitor is on */ - struct net_device* mon_ndev; -} monitor_interface; - -typedef struct dhd_linux_monitor { - void *dhd_pub; - monitor_states_t monitor_state; - monitor_interface mon_if[DHD_MAX_IFS]; - struct mutex lock; /* lock to protect mon_if */ -} dhd_linux_monitor_t; - -static dhd_linux_monitor_t g_monitor; - -static struct net_device* lookup_real_netdev(char *name); -static monitor_interface* ndev_to_monif(struct net_device *ndev); -static int dhd_mon_if_open(struct net_device *ndev); -static int dhd_mon_if_stop(struct net_device *ndev); -static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev); -static void dhd_mon_if_set_multicast_list(struct net_device *ndev); -static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr); - -static const struct net_device_ops dhd_mon_if_ops = { - .ndo_open = dhd_mon_if_open, - .ndo_stop = dhd_mon_if_stop, - .ndo_start_xmit = dhd_mon_if_subif_start_xmit, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - .ndo_set_rx_mode = dhd_mon_if_set_multicast_list, -#else - .ndo_set_multicast_list = dhd_mon_if_set_multicast_list, -#endif - .ndo_set_mac_address = dhd_mon_if_change_mac, -}; - -/** - * Local static function defintions - */ - -/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0" - * "p2p-eth0-0" is a match for "mon.p2p-eth0-0") - */ -static struct net_device* lookup_real_netdev(char *name) -{ - struct net_device *ndev_found = NULL; - - int i; - int len = 0; - int last_name_len = 0; - struct net_device *ndev; - - /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0", - * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon - * iface would be mon-p2p0-0. - */ - for (i = 0; i < DHD_MAX_IFS; i++) { - ndev = dhd_idx2net(g_monitor.dhd_pub, i); - - /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it - * it matches, then this netdev is the corresponding real_netdev. - */ - if (ndev && strstr(ndev->name, "p2p-p2p0")) { - len = strlen("p2p"); - } else { - /* if p2p- is not present, then the IFNAMSIZ have reached and name - * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x - */ - len = 0; - } - if (ndev && strstr(name, (ndev->name + len))) { - if (strlen(ndev->name) > last_name_len) { - ndev_found = ndev; - last_name_len = strlen(ndev->name); - } - } - } - - return ndev_found; -} - -static monitor_interface* ndev_to_monif(struct net_device *ndev) -{ - int i; - - for (i = 0; i < DHD_MAX_IFS; i++) { - if (g_monitor.mon_if[i].mon_ndev == ndev) - return &g_monitor.mon_if[i]; - } - - return NULL; -} - -static int dhd_mon_if_open(struct net_device *ndev) -{ - int ret = 0; - - MON_PRINT("enter\n"); - return ret; -} - -static int dhd_mon_if_stop(struct net_device *ndev) -{ - int ret = 0; - - MON_PRINT("enter\n"); - return ret; -} - -static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - int ret = 0; - int rtap_len; - int qos_len = 0; - int dot11_hdr_len = 24; - int snap_len = 6; - unsigned char *pdata; - unsigned short frame_ctl; - unsigned char src_mac_addr[6]; - unsigned char dst_mac_addr[6]; - struct ieee80211_hdr *dot11_hdr; - struct ieee80211_radiotap_header *rtap_hdr; - monitor_interface* mon_if; - - MON_PRINT("enter\n"); - - mon_if = ndev_to_monif(ndev); - if (mon_if == NULL || mon_if->real_ndev == NULL) { - MON_PRINT(" cannot find matched net dev, skip the packet\n"); - goto fail; - } - - if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) - goto fail; - - rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; - if (unlikely(rtap_hdr->it_version)) - goto fail; - - rtap_len = ieee80211_get_radiotap_len(skb->data); - if (unlikely(skb->len < rtap_len)) - goto fail; - - MON_PRINT("radiotap len (should be 14): %d\n", rtap_len); - - /* Skip the ratio tap header */ - skb_pull(skb, rtap_len); - - dot11_hdr = (struct ieee80211_hdr *)skb->data; - frame_ctl = le16_to_cpu(dot11_hdr->frame_control); - /* Check if the QoS bit is set */ - if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { - /* Check if this ia a Wireless Distribution System (WDS) frame - * which has 4 MAC addresses - */ - if (dot11_hdr->frame_control & 0x0080) - qos_len = 2; - if ((dot11_hdr->frame_control & 0x0300) == 0x0300) - dot11_hdr_len += 6; - - memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); - memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); - - /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for - * for two MAC addresses - */ - skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); - pdata = (unsigned char*)skb->data; - memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); - memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); - PKTSETPRIO(skb, 0); - - MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); - - /* Use the real net device to transmit the packet */ - ret = dhd_start_xmit(skb, mon_if->real_ndev); - - return ret; - } -fail: - dev_kfree_skb(skb); - return 0; -} - -static void dhd_mon_if_set_multicast_list(struct net_device *ndev) -{ - monitor_interface* mon_if; - - mon_if = ndev_to_monif(ndev); - if (mon_if == NULL || mon_if->real_ndev == NULL) { - MON_PRINT(" cannot find matched net dev, skip the packet\n"); - } else { - MON_PRINT("enter, if name: %s, matched if name %s\n", - ndev->name, mon_if->real_ndev->name); - } -} - -static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) -{ - int ret = 0; - monitor_interface* mon_if; - - mon_if = ndev_to_monif(ndev); - if (mon_if == NULL || mon_if->real_ndev == NULL) { - MON_PRINT(" cannot find matched net dev, skip the packet\n"); - } else { - MON_PRINT("enter, if name: %s, matched if name %s\n", - ndev->name, mon_if->real_ndev->name); - } - return ret; -} - -/** - * Global function definitions (declared in dhd_linux_mon.h) - */ - -int dhd_add_monitor(char *name, struct net_device **new_ndev) -{ - int i; - int idx = -1; - int ret = 0; - struct net_device* ndev = NULL; - dhd_linux_monitor_t **dhd_mon; - - mutex_lock(&g_monitor.lock); - - MON_TRACE("enter, if name: %s\n", name); - if (!name || !new_ndev) { - MON_PRINT("invalid parameters\n"); - ret = -EINVAL; - goto out; - } - - /* - * Find a vacancy - */ - for (i = 0; i < DHD_MAX_IFS; i++) - if (g_monitor.mon_if[i].mon_ndev == NULL) { - idx = i; - break; - } - if (idx == -1) { - MON_PRINT("exceeds maximum interfaces\n"); - ret = -EFAULT; - goto out; - } - - ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*)); - if (!ndev) { - MON_PRINT("failed to allocate memory\n"); - ret = -ENOMEM; - goto out; - } - - ndev->type = ARPHRD_IEEE80211_RADIOTAP; - strncpy(ndev->name, name, IFNAMSIZ); - ndev->name[IFNAMSIZ - 1] = 0; - ndev->netdev_ops = &dhd_mon_if_ops; - - ret = register_netdevice(ndev); - if (ret) { - MON_PRINT(" register_netdevice failed (%d)\n", ret); - goto out; - } - - *new_ndev = ndev; - g_monitor.mon_if[idx].radiotap_enabled = TRUE; - g_monitor.mon_if[idx].mon_ndev = ndev; - g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name); - dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev); - *dhd_mon = &g_monitor; - g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED; - MON_PRINT("net device returned: 0x%p\n", ndev); - MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name); - -out: - if (ret && ndev) - free_netdev(ndev); - - mutex_unlock(&g_monitor.lock); - return ret; - -} - -int dhd_del_monitor(struct net_device *ndev) -{ - int i; - if (!ndev) - return -EINVAL; - mutex_lock(&g_monitor.lock); - for (i = 0; i < DHD_MAX_IFS; i++) { - if (g_monitor.mon_if[i].mon_ndev == ndev || - g_monitor.mon_if[i].real_ndev == ndev) { - - g_monitor.mon_if[i].real_ndev = NULL; - unregister_netdevice(g_monitor.mon_if[i].mon_ndev); - free_netdev(g_monitor.mon_if[i].mon_ndev); - g_monitor.mon_if[i].mon_ndev = NULL; - g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED; - break; - } - } - - if (g_monitor.monitor_state != MONITOR_STATE_INTERFACE_DELETED) - MON_PRINT("IF not found in monitor array, is this a monitor IF? 0x%p\n", ndev); - mutex_unlock(&g_monitor.lock); - - return 0; -} - -int dhd_monitor_init(void *dhd_pub) -{ - if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) { - g_monitor.dhd_pub = dhd_pub; - mutex_init(&g_monitor.lock); - g_monitor.monitor_state = MONITOR_STATE_INIT; - } - return 0; -} - -int dhd_monitor_uninit(void) -{ - int i; - struct net_device *ndev; - mutex_lock(&g_monitor.lock); - if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) { - for (i = 0; i < DHD_MAX_IFS; i++) { - ndev = g_monitor.mon_if[i].mon_ndev; - if (ndev) { - unregister_netdevice(ndev); - free_netdev(ndev); - g_monitor.mon_if[i].real_ndev = NULL; - g_monitor.mon_if[i].mon_ndev = NULL; - } - } - g_monitor.monitor_state = MONITOR_STATE_DEINIT; - } - mutex_unlock(&g_monitor.lock); - return 0; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_roam.c b/drivers/net/wireless/bcmdhd_suzuran/wl_roam.c deleted file mode 100755 index 50180753ad77..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_roam.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Linux roam cache - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_roam.c 459591 2014-03-04 08:53:45Z $ - */ - -#include -#include -#include -#include -#include -#ifdef WL_CFG80211 -#include -#endif -#include - -#define MAX_ROAM_CACHE 100 -#define MAX_CHANNEL_LIST 20 -#define MAX_SSID_BUFSIZE 36 - -#define ROAMSCAN_MODE_NORMAL 0 -#define ROAMSCAN_MODE_WES 1 - -typedef struct { - chanspec_t chanspec; - int ssid_len; - char ssid[MAX_SSID_BUFSIZE]; -} roam_channel_cache; - -typedef struct { - int n; - chanspec_t channels[MAX_CHANNEL_LIST]; -} channel_list_t; - -static int n_roam_cache = 0; -static int roam_band = WLC_BAND_AUTO; -static roam_channel_cache roam_cache[MAX_ROAM_CACHE]; -static uint band2G, band5G, band_bw; - -void init_roam(int ioctl_ver) -{ -#ifdef D11AC_IOTYPES - if (ioctl_ver == 1) { - /* legacy chanspec */ - band2G = WL_LCHANSPEC_BAND_2G; - band5G = WL_LCHANSPEC_BAND_5G; - band_bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE; - } else { - band2G = WL_CHANSPEC_BAND_2G; - band5G = WL_CHANSPEC_BAND_5G; - band_bw = WL_CHANSPEC_BW_20; - } -#else - band2G = WL_CHANSPEC_BAND_2G; - band5G = WL_CHANSPEC_BAND_5G; - band_bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; -#endif /* D11AC_IOTYPES */ - - n_roam_cache = 0; - roam_band = WLC_BAND_AUTO; -} - - -void set_roam_band(int band) -{ - roam_band = band; -} - -void reset_roam_cache(void) -{ - - n_roam_cache = 0; -} - -void add_roam_cache(wl_bss_info_t *bi) -{ - int i; - uint8 channel; - - - if (n_roam_cache >= MAX_ROAM_CACHE) - return; - - for (i = 0; i < n_roam_cache; i++) { - if ((roam_cache[i].ssid_len == bi->SSID_len) && - (roam_cache[i].chanspec == bi->chanspec) && - (memcmp(roam_cache[i].ssid, bi->SSID, bi->SSID_len) == 0)) { - /* identical one found, just return */ - return; - } - } - - roam_cache[n_roam_cache].ssid_len = bi->SSID_len; - channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch; - WL_DBG(("CHSPEC 0x%X %d, CTL %d\n", - bi->chanspec, CHSPEC_CHANNEL(bi->chanspec), bi->ctl_ch)); - roam_cache[n_roam_cache].chanspec = - (channel <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw | channel; - memcpy(roam_cache[n_roam_cache].ssid, bi->SSID, bi->SSID_len); - - n_roam_cache++; -} - -static bool is_duplicated_channel(const chanspec_t *channels, int n_channels, chanspec_t new) -{ - int i; - - for (i = 0; i < n_channels; i++) { - if (channels[i] == new) - return TRUE; - } - - return FALSE; -} - -int get_roam_channel_list(int target_chan, - chanspec_t *channels, const wlc_ssid_t *ssid, int ioctl_ver) -{ - int i, n = 1; - - /* first index is filled with the given target channel */ - channels[0] = (target_chan & WL_CHANSPEC_CHAN_MASK) | - (target_chan <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw; - - WL_DBG((" %s: %03d 0x%04X\n", __FUNCTION__, target_chan, channels[0])); - - - for (i = 0; i < n_roam_cache; i++) { - chanspec_t ch = roam_cache[i].chanspec; - bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch); - bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch); - bool band_match = ((roam_band == WLC_BAND_AUTO) || - ((roam_band == WLC_BAND_2G) && is_2G) || - ((roam_band == WLC_BAND_5G) && is_5G)); - - ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw; - if ((roam_cache[i].ssid_len == ssid->SSID_len) && - band_match && !is_duplicated_channel(channels, n, ch) && - (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) { - /* match found, add it */ - WL_DBG((" %s: %03d(0x%04X)\n", __FUNCTION__, - CHSPEC_CHANNEL(ch), ch)); - channels[n++] = ch; - } - } - - return n; -} - - -void print_roam_cache(void) -{ - int i; - - WL_DBG((" %d cache\n", n_roam_cache)); - - for (i = 0; i < n_roam_cache; i++) { - roam_cache[i].ssid[roam_cache[i].ssid_len] = 0; - WL_DBG(("0x%02X %02d %s\n", roam_cache[i].chanspec, - roam_cache[i].ssid_len, roam_cache[i].ssid)); - } -} - -static void add_roamcache_channel(channel_list_t *channels, chanspec_t ch) -{ - int i; - - if (channels->n >= MAX_CHANNEL_LIST) /* buffer full */ - return; - - for (i = 0; i < channels->n; i++) { - if (channels->channels[i] == ch) /* already in the list */ - return; - } - - channels->channels[i] = ch; - channels->n++; - - WL_DBG((" RCC: %02d 0x%04X\n", - ch & WL_CHANSPEC_CHAN_MASK, ch)); -} - -void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver) -{ - int error, i, prev_channels; - channel_list_t channel_list; - char iobuf[WLC_IOCTL_SMLEN]; - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - wlc_ssid_t ssid; - - - if (!wl_get_drv_status(cfg, CONNECTED, dev)) { - WL_DBG(("Not associated\n")); - return; - } - - /* need to read out the current cache list - as the firmware may change dynamically - */ - error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0, - (void *)&channel_list, sizeof(channel_list), NULL); - - WL_DBG(("%d AP, %d cache item(s), err=%d\n", n_roam_cache, channel_list.n, error)); - - error = wldev_get_ssid(dev, &ssid); - if (error) { - WL_ERR(("Failed to get SSID, err=%d\n", error)); - return; - } - - prev_channels = channel_list.n; - for (i = 0; i < n_roam_cache; i++) { - chanspec_t ch = roam_cache[i].chanspec; - bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch); - bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch); - bool band_match = ((roam_band == WLC_BAND_AUTO) || - ((roam_band == WLC_BAND_2G) && is_2G) || - ((roam_band == WLC_BAND_5G) && is_5G)); - - if ((roam_cache[i].ssid_len == ssid.SSID_len) && - band_match && (memcmp(roam_cache[i].ssid, ssid.SSID, ssid.SSID_len) == 0)) { - /* match found, add it */ - ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw; - add_roamcache_channel(&channel_list, ch); - } - } - if (prev_channels != channel_list.n) { - /* channel list updated */ - error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list, - sizeof(channel_list), iobuf, sizeof(iobuf), NULL); - if (error) { - WL_ERR(("Failed to update roamscan channels, error = %d\n", error)); - } - } -} - -void wl_update_roamscan_cache_by_band(struct net_device *dev, int band) -{ - int i, error, ioctl_ver, wes_mode; - channel_list_t chanlist_before, chanlist_after; - char iobuf[WLC_IOCTL_SMLEN]; - - roam_band = band; - if (band == WLC_BAND_AUTO) - return; - - error = wldev_iovar_getint(dev, "roamscan_mode", &wes_mode); - if (error) { - WL_ERR(("Failed to get roamscan mode, error = %d\n", error)); - return; - } - /* in case of WES mode, then skip the update */ - if (wes_mode) - return; - - error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0, - (void *)&chanlist_before, sizeof(channel_list_t), NULL); - if (error) { - WL_ERR(("Failed to get roamscan channels, error = %d\n", error)); - return; - } - ioctl_ver = wl_cfg80211_get_ioctl_version(); - chanlist_after.n = 0; - /* filtering by the given band */ - for (i = 0; i < chanlist_before.n; i++) { - chanspec_t chspec = chanlist_before.channels[i]; - bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(chspec) : CHSPEC_IS2G(chspec); - bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(chspec) : CHSPEC_IS5G(chspec); - bool band_match = ((band == WLC_BAND_2G) && is_2G) || - ((band == WLC_BAND_5G) && is_5G); - if (band_match) { - chanlist_after.channels[chanlist_after.n++] = chspec; - } - } - - if (chanlist_before.n == chanlist_after.n) - return; - - error = wldev_iovar_setbuf(dev, "roamscan_channels", &chanlist_after, - sizeof(channel_list_t), iobuf, sizeof(iobuf), NULL); - if (error) { - WL_ERR(("Failed to update roamscan channels, error = %d\n", error)); - } -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c b/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c deleted file mode 100755 index decaf3560d42..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Common function shared by Linux WEXT, cfg80211 and p2p drivers - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wldev_common.c 701450 2017-05-25 02:10:23Z $ - */ - -#include -#include -#include -#include - -#include -#include -#include - -#define htod32(i) (i) -#define htod16(i) (i) -#define dtoh32(i) (i) -#define dtoh16(i) (i) -#define htodchanspec(i) (i) -#define dtohchanspec(i) (i) - -#define WLDEV_ERROR(args) \ - do { \ - printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__); \ - printk args; \ - } while (0) - -extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd); - -s32 wldev_ioctl( - struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) -{ - s32 ret = 0; - struct wl_ioctl ioc; - - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; - ioc.set = set; - - ret = dhd_ioctl_entry_local(dev, &ioc, cmd); - - return ret; -} - -/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be - * taken care of in dhd_ioctl_entry. Internal use only, not exposed to - * wl_iw, wl_cfg80211 and wl_cfgp2p - */ -static s32 wldev_mkiovar( - s8 *iovar_name, s8 *param, s32 paramlen, - s8 *iovar_buf, u32 buflen) -{ - s32 iolen = 0; - - iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen); - return iolen; -} - -s32 wldev_iovar_getbuf( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) -{ - s32 ret = 0; - if (buf_sync) { - mutex_lock(buf_sync); - } - if (buf && (buflen > 0)) { - /* initialize the response buffer */ - memset(buf, 0, buflen); - } else { - ret = BCME_BADARG; - goto exit; - } - ret = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); - if (!ret) { - ret = BCME_BUFTOOSHORT; - goto exit; - } - - ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); - -exit: - if (buf_sync) - mutex_unlock(buf_sync); - return ret; -} - - -s32 wldev_iovar_setbuf( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) -{ - s32 ret = 0; - s32 iovar_len; - if (buf_sync) { - mutex_lock(buf_sync); - } - if (buf && (buflen > 0)) { - /* initialize the response buffer */ - memset(buf, 0, buflen); - } else { - ret = BCME_BADARG; - goto exit; - } - iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); - if (iovar_len > 0) - ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); - else - ret = BCME_BUFTOOSHORT; - -exit: - if (buf_sync) - mutex_unlock(buf_sync); - return ret; -} - -s32 wldev_iovar_setint( - struct net_device *dev, s8 *iovar, s32 val) -{ - s8 iovar_buf[WLC_IOCTL_SMLEN]; - - val = htod32(val); - return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf, - sizeof(iovar_buf), NULL); -} - - -s32 wldev_iovar_getint( - struct net_device *dev, s8 *iovar, s32 *pval) -{ - s8 iovar_buf[WLC_IOCTL_SMLEN]; - s32 err; - - err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf, - sizeof(iovar_buf), NULL); - if (err == 0) - { - memcpy(pval, iovar_buf, sizeof(*pval)); - *pval = dtoh32(*pval); - } - return err; -} - -/** Format a bsscfg indexed iovar buffer. The bsscfg index will be - * taken care of in dhd_ioctl_entry. Internal use only, not exposed to - * wl_iw, wl_cfg80211 and wl_cfgp2p - */ -s32 wldev_mkiovar_bsscfg( - const s8 *iovar_name, s8 *param, s32 paramlen, - s8 *iovar_buf, s32 buflen, s32 bssidx) -{ - const s8 *prefix = "bsscfg:"; - s8 *p; - u32 prefixlen; - u32 namelen; - u32 iolen; - - /* initialize buffer */ - if (!iovar_buf || buflen == 0) - return BCME_BADARG; - memset(iovar_buf, 0, buflen); - - if (bssidx == 0) { - return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen, - (s8 *) iovar_buf, buflen); - } - - prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ - namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */ - iolen = prefixlen + namelen + sizeof(u32) + paramlen; - - if (buflen < 0 || iolen > (u32)buflen) - { - WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__)); - return BCME_BUFTOOSHORT; - } - - p = (s8 *)iovar_buf; - - /* copy prefix, no null */ - memcpy(p, prefix, prefixlen); - p += prefixlen; - - /* copy iovar name including null */ - memcpy(p, iovar_name, namelen); - p += namelen; - - /* bss config index as first param */ - bssidx = htod32(bssidx); - memcpy(p, &bssidx, sizeof(u32)); - p += sizeof(u32); - - /* parameter buffer follows */ - if (paramlen) - memcpy(p, param, paramlen); - - return iolen; - -} - -s32 wldev_iovar_getbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) -{ - s32 ret = 0; - if (buf_sync) { - mutex_lock(buf_sync); - } - - wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); - ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); - if (buf_sync) { - mutex_unlock(buf_sync); - } - return ret; - -} - -s32 wldev_iovar_setbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) -{ - s32 ret = 0; - s32 iovar_len; - if (buf_sync) { - mutex_lock(buf_sync); - } - iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); - if (iovar_len > 0) - ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); - else { - ret = BCME_BUFTOOSHORT; - } - - if (buf_sync) { - mutex_unlock(buf_sync); - } - return ret; -} - -s32 wldev_iovar_setint_bsscfg( - struct net_device *dev, s8 *iovar, s32 val, s32 bssidx) -{ - s8 iovar_buf[WLC_IOCTL_SMLEN]; - - val = htod32(val); - - return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, - sizeof(iovar_buf), bssidx, NULL); -} - - -s32 wldev_iovar_getint_bsscfg( - struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx) -{ - s8 iovar_buf[WLC_IOCTL_SMLEN]; - s32 err; - - err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf, - sizeof(iovar_buf), bssidx, NULL); - if (err == 0) - { - memcpy(pval, iovar_buf, sizeof(*pval)); - *pval = dtoh32(*pval); - } - return err; -} - -int wldev_get_link_speed( - struct net_device *dev, int *plink_speed) -{ - int error; - - if (!plink_speed) - return -ENOMEM; - *plink_speed = 0; - error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0); - if (unlikely(error)) - return error; - - /* Convert internal 500Kbps to Kbps */ - *plink_speed *= 500; - return error; -} - -int wldev_get_rssi( - struct net_device *dev, int *prssi) -{ - scb_val_t scb_val; - int error; - - if (!prssi) - return -ENOMEM; - bzero(&scb_val, sizeof(scb_val_t)); - - error = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); - if (unlikely(error)) - return error; - - *prssi = dtoh32(scb_val.val); - return error; -} - -int wldev_get_ssid( - struct net_device *dev, wlc_ssid_t *pssid) -{ - int error; - - if (!pssid) - return -ENOMEM; - memset(pssid, 0, sizeof(wlc_ssid_t)); - error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0); - if (unlikely(error)) - return error; - pssid->SSID_len = dtoh32(pssid->SSID_len); - return error; -} - -int wldev_get_band( - struct net_device *dev, uint *pband) -{ - int error; - - *pband = 0; - error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0); - return error; -} - -int wldev_set_band( - struct net_device *dev, uint band) -{ - int error = -1; - - if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { - error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true); - if (!error) - dhd_bus_band_set(dev, band); - } - return error; -} - -int wldev_set_country( - struct net_device *dev, char *country_code, bool notify, bool user_enforced) -{ - int error = -1; - wl_country_t cspec = {{0}, 0, {0}}; - scb_val_t scbval; - char smbuf[WLC_IOCTL_SMLEN]; - struct wireless_dev *wdev = ndev_to_wdev(dev); - struct wiphy *wiphy = wdev->wiphy; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - - if (!country_code) - return error; - - bzero(&scbval, sizeof(scb_val_t)); - error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL); - if (error < 0) { - WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error)); - return error; - } - - if ((error < 0) || - (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { - - if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) { - bzero(&scbval, sizeof(scb_val_t)); - error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); - if (error < 0) { - WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", - __FUNCTION__, error)); - return error; - } - } -#ifdef CUSTOMER_HW5 - else { - if (dhd_is_p2p_connection(dev)) { - WLDEV_ERROR(("Skip to set country code for preventing " - "p2p disconnection\n")); - return -1; - } - } -#endif /* CUSTOMER_HW5 */ - - cspec.rev = -1; - memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); - memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); - dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec); - error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), - smbuf, sizeof(smbuf), NULL); - if (error < 0) { - WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - return error; - } - dhd_bus_country_set(dev, &cspec, notify); - WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - } - return 0; -} diff --git a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.h b/drivers/net/wireless/bcmdhd_suzuran/wldev_common.h deleted file mode 100755 index 07f3d56b4cb2..000000000000 --- a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Common function shared by Linux WEXT, cfg80211 and p2p drivers - * - * Copyright (C) 1999-2018, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wldev_common.h 684925 2017-02-15 01:55:31Z $ - */ -#ifndef __WLDEV_COMMON_H__ -#define __WLDEV_COMMON_H__ - -#include - -/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or - * netdev_ops->ndo_do_ioctl in new kernels) - * @dev: the net_device handle - */ -s32 wldev_ioctl( - struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); - -/** Retrieve named IOVARs, this function calls wl_dev_ioctl with - * WLC_GET_VAR IOCTL code - */ -s32 wldev_iovar_getbuf( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); - -/** Set named IOVARs, this function calls wl_dev_ioctl with - * WLC_SET_VAR IOCTL code - */ -s32 wldev_iovar_setbuf( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); - -s32 wldev_iovar_setint( - struct net_device *dev, s8 *iovar, s32 val); - -s32 wldev_iovar_getint( - struct net_device *dev, s8 *iovar, s32 *pval); - -/** The following function can be implemented if there is a need for bsscfg - * indexed IOVARs - */ - -s32 wldev_mkiovar_bsscfg( - const s8 *iovar_name, s8 *param, s32 paramlen, - s8 *iovar_buf, s32 buflen, s32 bssidx); - -/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with - * WLC_GET_VAR IOCTL code - */ -s32 wldev_iovar_getbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, - void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); - -/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with - * WLC_SET_VAR IOCTL code - */ -s32 wldev_iovar_setbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, - void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); - -s32 wldev_iovar_getint_bsscfg( - struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx); - -s32 wldev_iovar_setint_bsscfg( - struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); - -extern int dhd_net_set_fw_path(struct net_device *dev, char *fw); -extern int dhd_net_bus_suspend(struct net_device *dev); -extern int dhd_net_bus_resume(struct net_device *dev, uint8 stage); -extern int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, - unsigned long delay_msec); -extern void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, - wl_country_t *cspec); -extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify); -extern void dhd_bus_band_set(struct net_device *dev, uint band); -extern int wldev_set_country(struct net_device *dev, char *country_code, bool notify, - bool user_enforced); -extern int net_os_wake_lock(struct net_device *dev); -extern int net_os_wake_unlock(struct net_device *dev); -extern int net_os_wake_lock_timeout(struct net_device *dev); -extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); -extern int net_os_set_dtim_skip(struct net_device *dev, int val); -extern int net_os_set_suspend_disable(struct net_device *dev, int val); -extern int net_os_set_suspend(struct net_device *dev, int val, int force); -extern int wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, - int max, int *bytes_left); - -/* Get the link speed from dongle, speed is in kpbs */ -int wldev_get_link_speed(struct net_device *dev, int *plink_speed); - -int wldev_get_rssi(struct net_device *dev, int *prssi); - -int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid); - -int wldev_get_band(struct net_device *dev, uint *pband); - -int wldev_set_band(struct net_device *dev, uint band); -#ifdef CUSTOMER_HW5 -extern bool dhd_is_p2p_connection(struct net_device *ndev); -#endif -#endif /* __WLDEV_COMMON_H__ */ -- GitLab From 9290896f819195320fe582c97f3b75f8465a5267 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Thu, 9 Nov 2017 22:41:49 +0300 Subject: [PATCH 185/528] drivers/net/wireless: Import BCM4356, version 1.71.25 * Sony package version: 32.4.A.1.54 * Required for Sony Xperia Z3+/Z5/Z5P Signed-off-by: Andrey Cherepkov (cherry picked from commit 5b5848e1fb68710d244a65485e8d84be53f01c32) --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 2 + drivers/net/wireless/bcmdhd_bcm4356/Kconfig | 82 + drivers/net/wireless/bcmdhd_bcm4356/Makefile | 537 + .../net/wireless/bcmdhd_bcm4356/Makefile.bcm | 448 + .../net/wireless/bcmdhd_bcm4356/Makefile.kk | 430 + .../wireless/bcmdhd_bcm4356/Makefile_Shamu | 439 + drivers/net/wireless/bcmdhd_bcm4356/aiutils.c | 1123 ++ .../net/wireless/bcmdhd_bcm4356/bcmevent.c | 304 + drivers/net/wireless/bcmdhd_bcm4356/bcmsdh.c | 705 + .../wireless/bcmdhd_bcm4356/bcmsdh_linux.c | 457 + .../wireless/bcmdhd_bcm4356/bcmsdh_sdmmc.c | 1456 ++ .../bcmdhd_bcm4356/bcmsdh_sdmmc_linux.c | 387 + .../wireless/bcmdhd_bcm4356/bcmsdspi_linux.c | 249 + .../net/wireless/bcmdhd_bcm4356/bcmspibrcm.c | 1810 ++ .../net/wireless/bcmdhd_bcm4356/bcmutils.c | 3066 ++++ .../bcmdhd_bcm4356/bcmwifi_channels.c | 1229 ++ .../bcmdhd_bcm4356/bcmwifi_channels.h | 548 + .../wireless/bcmdhd_bcm4356/bcmwifi_rates.h | 466 + drivers/net/wireless/bcmdhd_bcm4356/bcmxtlv.c | 399 + drivers/net/wireless/bcmdhd_bcm4356/dhd.h | 1338 ++ drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.c | 328 + drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.h | 39 + drivers/net/wireless/bcmdhd_bcm4356/dhd_bus.h | 199 + drivers/net/wireless/bcmdhd_bcm4356/dhd_cdc.c | 811 + .../wireless/bcmdhd_bcm4356/dhd_cfg80211.c | 219 + .../wireless/bcmdhd_bcm4356/dhd_cfg80211.h | 48 + .../wireless/bcmdhd_bcm4356/dhd_cfg_vendor.c | 171 + .../net/wireless/bcmdhd_bcm4356/dhd_common.c | 2792 +++ .../wireless/bcmdhd_bcm4356/dhd_custom_gpio.c | 596 + .../bcmdhd_bcm4356/dhd_custom_memprealloc.c | 361 + drivers/net/wireless/bcmdhd_bcm4356/dhd_dbg.h | 128 + .../wireless/bcmdhd_bcm4356/dhd_flowring.c | 831 + .../wireless/bcmdhd_bcm4356/dhd_flowring.h | 177 + drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.c | 1318 ++ drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.h | 76 + .../net/wireless/bcmdhd_bcm4356/dhd_linux.c | 10935 ++++++++++++ .../net/wireless/bcmdhd_bcm4356/dhd_linux.h | 127 + .../bcmdhd_bcm4356/dhd_linux_platdev.c | 839 + .../wireless/bcmdhd_bcm4356/dhd_linux_sched.c | 48 + .../wireless/bcmdhd_bcm4356/dhd_linux_wq.c | 317 + .../wireless/bcmdhd_bcm4356/dhd_linux_wq.h | 65 + .../net/wireless/bcmdhd_bcm4356/dhd_msgbuf.c | 5046 ++++++ .../net/wireless/bcmdhd_bcm4356/dhd_pcie.c | 5251 ++++++ .../net/wireless/bcmdhd_bcm4356/dhd_pcie.h | 258 + .../wireless/bcmdhd_bcm4356/dhd_pcie_linux.c | 1392 ++ drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c | 4076 +++++ drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h | 561 + .../net/wireless/bcmdhd_bcm4356/dhd_proto.h | 150 + drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c | 1970 +++ drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h | 284 + .../net/wireless/bcmdhd_bcm4356/dhd_sdio.c | 8586 +++++++++ .../wireless/bcmdhd_bcm4356/dhd_somc_custom.c | 352 + .../wireless/bcmdhd_bcm4356/dhd_somc_custom.h | 18 + .../net/wireless/bcmdhd_bcm4356/dhd_wlfc.c | 4109 +++++ .../net/wireless/bcmdhd_bcm4356/dhd_wlfc.h | 517 + .../net/wireless/bcmdhd_bcm4356/dngl_stats.h | 271 + .../net/wireless/bcmdhd_bcm4356/dngl_wlhdr.h | 40 + .../net/wireless/bcmdhd_bcm4356/hnd_pktpool.c | 751 + .../net/wireless/bcmdhd_bcm4356/hnd_pktq.c | 602 + drivers/net/wireless/bcmdhd_bcm4356/hndpmu.c | 274 + .../wireless/bcmdhd_bcm4356/include/Makefile | 71 + .../wireless/bcmdhd_bcm4356/include/aidmp.h | 387 + .../wireless/bcmdhd_bcm4356/include/bcm_cfg.h | 29 + .../bcmdhd_bcm4356/include/bcm_mpool_pub.h | 361 + .../wireless/bcmdhd_bcm4356/include/bcmcdc.h | 132 + .../wireless/bcmdhd_bcm4356/include/bcmdefs.h | 399 + .../wireless/bcmdhd_bcm4356/include/bcmdevs.h | 731 + .../bcmdhd_bcm4356/include/bcmendian.h | 329 + .../bcmdhd_bcm4356/include/bcmmsgbuf.h | 749 + .../bcmdhd_bcm4356/include/bcmnvram.h | 272 + .../wireless/bcmdhd_bcm4356/include/bcmpcie.h | 227 + .../bcmdhd_bcm4356/include/bcmpcispi.h | 181 + .../wireless/bcmdhd_bcm4356/include/bcmperf.h | 36 + .../bcmdhd_bcm4356/include/bcmsdbus.h | 143 + .../wireless/bcmdhd_bcm4356/include/bcmsdh.h | 252 + .../bcmdhd_bcm4356/include/bcmsdh_sdmmc.h | 117 + .../bcmdhd_bcm4356/include/bcmsdpcm.h | 278 + .../bcmdhd_bcm4356/include/bcmsdspi.h | 135 + .../bcmdhd_bcm4356/include/bcmsdstd.h | 282 + .../wireless/bcmdhd_bcm4356/include/bcmspi.h | 40 + .../bcmdhd_bcm4356/include/bcmspibrcm.h | 162 + .../bcmdhd_bcm4356/include/bcmsrom_fmt.h | 633 + .../bcmdhd_bcm4356/include/bcmsrom_tbl.h | 1029 ++ .../bcmdhd_bcm4356/include/bcmutils.h | 1174 ++ .../bcmdhd_bcm4356/include/brcm_nl80211.h | 64 + .../wireless/bcmdhd_bcm4356/include/dbus.h | 582 + .../include/devctrl_if/wlioctl_defs.h | 2110 +++ .../bcmdhd_bcm4356/include/dhdioctl.h | 136 + .../wireless/bcmdhd_bcm4356/include/epivers.h | 48 + .../bcmdhd_bcm4356/include/hnd_armtrap.h | 88 + .../bcmdhd_bcm4356/include/hnd_cons.h | 77 + .../bcmdhd_bcm4356/include/hnd_pktpool.h | 204 + .../bcmdhd_bcm4356/include/hnd_pktq.h | 186 + .../wireless/bcmdhd_bcm4356/include/hndpmu.h | 41 + .../wireless/bcmdhd_bcm4356/include/hndsoc.h | 286 + .../bcmdhd_bcm4356/include/linux_osl.h | 986 ++ .../bcmdhd_bcm4356/include/linuxver.h | 748 + .../wireless/bcmdhd_bcm4356/include/miniopt.h | 79 + .../bcmdhd_bcm4356/include/msgtrace.h | 78 + .../net/wireless/bcmdhd_bcm4356/include/osl.h | 149 + .../bcmdhd_bcm4356/include/osl_decl.h | 34 + .../include/packed_section_end.h | 59 + .../include/packed_section_start.h | 63 + .../wireless/bcmdhd_bcm4356/include/pcicfg.h | 260 + .../bcmdhd_bcm4356/include/pcie_core.h | 642 + .../bcmdhd_bcm4356/include/proto/802.11.h | 3853 +++++ .../bcmdhd_bcm4356/include/proto/802.11_bta.h | 45 + .../bcmdhd_bcm4356/include/proto/802.11e.h | 138 + .../bcmdhd_bcm4356/include/proto/802.1d.h | 50 + .../bcmdhd_bcm4356/include/proto/802.3.h | 52 + .../bcmdhd_bcm4356/include/proto/bcmdhcp.h | 89 + .../bcmdhd_bcm4356/include/proto/bcmeth.h | 112 + .../bcmdhd_bcm4356/include/proto/bcmevent.h | 529 + .../bcmdhd_bcm4356/include/proto/bcmip.h | 245 + .../bcmdhd_bcm4356/include/proto/bcmipv6.h | 160 + .../bcmdhd_bcm4356/include/proto/bcmtcp.h | 90 + .../bcmdhd_bcm4356/include/proto/bcmudp.h | 58 + .../bcmdhd_bcm4356/include/proto/bt_amp_hci.h | 441 + .../bcmdhd_bcm4356/include/proto/eapol.h | 212 + .../bcmdhd_bcm4356/include/proto/ethernet.h | 228 + .../bcmdhd_bcm4356/include/proto/nan.h | 238 + .../bcmdhd_bcm4356/include/proto/p2p.h | 710 + .../bcmdhd_bcm4356/include/proto/sdspi.h | 75 + .../bcmdhd_bcm4356/include/proto/vlan.h | 95 + .../bcmdhd_bcm4356/include/proto/wpa.h | 217 + .../bcmdhd_bcm4356/include/proto/wps.h | 386 + .../wireless/bcmdhd_bcm4356/include/sbchipc.h | 3646 ++++ .../bcmdhd_bcm4356/include/sbconfig.h | 282 + .../bcmdhd_bcm4356/include/sbhnddma.h | 417 + .../bcmdhd_bcm4356/include/sbpcmcia.h | 131 + .../wireless/bcmdhd_bcm4356/include/sbsdio.h | 186 + .../bcmdhd_bcm4356/include/sbsdpcmdev.h | 295 + .../bcmdhd_bcm4356/include/sbsocram.h | 200 + .../wireless/bcmdhd_bcm4356/include/sdio.h | 622 + .../wireless/bcmdhd_bcm4356/include/sdioh.h | 445 + .../wireless/bcmdhd_bcm4356/include/sdiovar.h | 58 + .../wireless/bcmdhd_bcm4356/include/siutils.h | 589 + .../wireless/bcmdhd_bcm4356/include/spid.h | 165 + .../wireless/bcmdhd_bcm4356/include/trxhdr.h | 92 + .../bcmdhd_bcm4356/include/typedefs.h | 339 + .../bcmdhd_bcm4356/include/wlfc_proto.h | 301 + .../wireless/bcmdhd_bcm4356/include/wlioctl.h | 6681 +++++++ .../net/wireless/bcmdhd_bcm4356/linux_osl.c | 1815 ++ .../net/wireless/bcmdhd_bcm4356/pcie_core.c | 88 + drivers/net/wireless/bcmdhd_bcm4356/sbutils.c | 1105 ++ drivers/net/wireless/bcmdhd_bcm4356/siutils.c | 3047 ++++ .../wireless/bcmdhd_bcm4356/siutils_priv.h | 283 + .../net/wireless/bcmdhd_bcm4356/uamp_api.h | 178 + .../net/wireless/bcmdhd_bcm4356/wl_android.c | 3190 ++++ .../net/wireless/bcmdhd_bcm4356/wl_android.h | 120 + .../net/wireless/bcmdhd_bcm4356/wl_cfg80211.c | 14387 ++++++++++++++++ .../net/wireless/bcmdhd_bcm4356/wl_cfg80211.h | 1040 ++ .../wireless/bcmdhd_bcm4356/wl_cfg_btcoex.c | 554 + .../net/wireless/bcmdhd_bcm4356/wl_cfgnan.c | 2060 +++ .../net/wireless/bcmdhd_bcm4356/wl_cfgnan.h | 207 + .../net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c | 2742 +++ .../net/wireless/bcmdhd_bcm4356/wl_cfgp2p.h | 422 + .../wireless/bcmdhd_bcm4356/wl_cfgvendor.c | 2304 +++ .../wireless/bcmdhd_bcm4356/wl_cfgvendor.h | 353 + drivers/net/wireless/bcmdhd_bcm4356/wl_dbg.h | 206 + .../wireless/bcmdhd_bcm4356/wl_linux_mon.c | 403 + drivers/net/wireless/bcmdhd_bcm4356/wl_roam.c | 306 + .../wireless/bcmdhd_bcm4356/wldev_common.c | 516 + .../wireless/bcmdhd_bcm4356/wldev_common.h | 124 + 165 files changed, 143400 insertions(+) create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/Kconfig create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/Makefile create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/Makefile.bcm create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/Makefile.kk create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/Makefile_Shamu create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/aiutils.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmsdh.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_linux.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc_linux.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmsdspi_linux.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmspibrcm.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmutils.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_rates.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/bcmxtlv.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_bus.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_cdc.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg_vendor.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_gpio.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_memprealloc.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_dbg.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_platdev.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_sched.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_msgbuf.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie_linux.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_proto.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dngl_stats.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/dngl_wlhdr.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/hnd_pktpool.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/hnd_pktq.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/hndpmu.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/Makefile create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/aidmp.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcm_cfg.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcm_mpool_pub.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmcdc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmdefs.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmdevs.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmendian.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmmsgbuf.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmnvram.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcie.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcispi.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmperf.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdbus.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh_sdmmc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdpcm.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdspi.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdstd.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmspi.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmspibrcm.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_fmt.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_tbl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/bcmutils.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/brcm_nl80211.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/dbus.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/devctrl_if/wlioctl_defs.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/dhdioctl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/hnd_armtrap.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/hnd_cons.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktpool.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktq.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/hndpmu.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/hndsoc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/linuxver.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/miniopt.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/msgtrace.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/osl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/osl_decl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_end.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_start.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/pcicfg.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/pcie_core.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11_bta.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11e.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.1d.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.3.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmdhcp.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmeth.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmevent.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmip.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmipv6.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmtcp.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmudp.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/bt_amp_hci.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/eapol.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/ethernet.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/nan.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/p2p.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/sdspi.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/vlan.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/wpa.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/proto/wps.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sbchipc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sbconfig.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sbhnddma.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sbpcmcia.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sbsdio.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sbsdpcmdev.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sbsocram.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sdio.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sdioh.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/sdiovar.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/siutils.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/spid.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/trxhdr.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/typedefs.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/wlfc_proto.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/include/wlioctl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/linux_osl.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/pcie_core.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/sbutils.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/siutils.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/siutils_priv.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/uamp_api.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_android.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_android.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_cfg_btcoex.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_dbg.h create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_linux_mon.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wl_roam.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c create mode 100644 drivers/net/wireless/bcmdhd_bcm4356/wldev_common.h diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 542ef0717bb3..be053439b566 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -357,6 +357,7 @@ 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/bcmdhd_bcm4356/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/ipw2x00/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 1a1e05e1a159..d5ddd8daab74 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -57,6 +57,8 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/ obj-$(CONFIG_SOMC_WIFI_CONTROL) += somcwifictrl/ +obj-$(CONFIG_BCMDHD_BCM4356) += bcmdhd_bcm4356/ + obj-$(CONFIG_BRCMFMAC) += brcm80211/ obj-$(CONFIG_BRCMSMAC) += brcm80211/ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig new file mode 100644 index 000000000000..599f99af9cd4 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig @@ -0,0 +1,82 @@ +menuconfig BCMDHD_BCM4356 + tristate "Broadcom wireless cards support" + +if BCMDHD_BCM4356 + +config BCMDHD + tristate "Broadcom wireless cards support" + depends on MMC || PCI + ---help--- + This module adds support for wireless adapters based on + Broadcom chipset. + +config BCMDHD_SDIO + bool "SDIO bus interface support" + depends on BCMDHD && MMC && !BCMDHD_PCIE + +config BCMDHD_PCIE + bool "PCIe bus interface support" + depends on BCMDHD && PCI + +config BCM4339 + bool "Broadcom 4339 wireless cards support" + depends on BCMDHD && BCMDHD_SDIO + ---help--- + This module adds support for wireless adapters based on + Broadcom 4339 chipset. + +config BCM4354 + bool "Broadcom 4354 wireless cards support" + depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) + ---help--- + This module adds support for wireless adapters based on + Broadcom 4354 chipset. + +config BCM4356 + bool "Broadcom 4356 wireless cards support" + depends on BCMDHD && BCMDHD_PCIE + ---help--- + This module adds support for wireless adapters based on + Broadcom 4356 chipset. + +config BCMDHD_FW_PATH + depends on BCMDHD + string "Firmware path" + default "/system/etc/firmware/fw_bcmdhd.bin" + ---help--- + Path to the firmware file. + +config BCMDHD_NVRAM_PATH + depends on BCMDHD + string "NVRAM path" + default "/system/etc/wifi/bcmdhd.cal" + ---help--- + Path to the calibration file. + +config DHD_USE_STATIC_BUF + bool "Enable memory preallocation" + depends on BCMDHD + default n + ---help--- + Use memory preallocated in platform + +config DHD_USE_SCHED_SCAN + bool "Use CFG80211 sched scan" + depends on BCMDHD && CFG80211 + default n + ---help--- + Use CFG80211 sched scan + +config BROADCOM_WIFI_RESERVED_MEM + bool "BROADCOM Reserved memory for wifi device" + depends on BCMDHD + ---help--- + This is a configuration for broadcom WLAN driver. + +config BCMDHD_DEBUG_PAGEALLOC + bool "Enable Memory Pagealloc Debugging Support" + depends on (BCM4354 || BCM4356) + ---help--- + Enable Memory Pagealloc Debugging + +endif diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Makefile b/drivers/net/wireless/bcmdhd_bcm4356/Makefile new file mode 100644 index 000000000000..e19b954080a0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/Makefile @@ -0,0 +1,537 @@ +# bcmdhd +##################### +# Basic feature +##################### + +DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DKEEP_ALIVE -DCSCAN \ + -DPKT_FILTER_SUPPORT -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ + -DCONFIG_DTS + +##################### +# Bus Interface Type +##################### +ifneq ($(CONFIG_BCMDHD_PCIE),) + BUS_IFACE_PCIE=y +else + BUS_IFACE_SDIO=y +endif + +##################### +# SDIO I/F +##################### +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT + DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR + DHDCFLAGS += -U__ARM_ARCH_7A__ + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + # idle count + DHDCFLAGS += -DDHD_USE_IDLECOUNT + # SKB TAILPAD to avoid out of boundary memory access + DHDCFLAGS += -DDHDENABLE_TAILPAD + DHDCFLAGS += -DSUPPORT_P2P_GO_PS +endif + +##################### +# PCIE I/F +##################### +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=-1 + # Enable Link down recovery + DHDCFLAGS += -DSUPPORT_LINKDOWN_RECOVERY + # Enable Firmware Coredump + DHDCFLAGS += -DDHD_FW_COREDUMP + # Enable packet audit at host side + DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED +endif + + + +################# +# Common feature +################# + +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Enable wakelock debug function +DHDCFLAGS += -DDHD_TRACE_WAKE_LOCK +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS + +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE +DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# For setting custom short & long retry limit +DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + +# HW5 specific features +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DBLOCK_IPV6_PACKET -DPASS_IPV4_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS +# END HW5 specific features + + +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# For Passing all multicast packets to host when not in suspend mode. +DHDCFLAGS += -DPASS_ALL_MCAST_PKTS + + +# Early suspend +DHDCFLAGS += -DDHD_USE_EARLYSUSPEND + +# WiFi turn off delay +DHDCFLAGS += -DWIFI_TURNOFF_DELAY=100 + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER +DHDCFLAGS += -DESCAN_BUF_OVERFLOW_MGMT + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DDHD_USE_STATIC_IOCTLBUF +endif +ifeq ($(CONFIG_BCMDHD_DEBUG_PAGEALLOC),y) +# Preallocation for memory dump + DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP +endif +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# Ioctl Rx count timeout +DHDCFLAGS += -DMAX_CNTL_RX_TIMEOUT=3 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +DHDCFLAGS += -DWL_ABORT_SCAN + +# Disable to delay link down event +DHDCFLAGS += -DDISABLE_BCN_DLY + +############################## +# Android Platform Definition +############################## +BCM_SRC_DIR := ./ + +########### +# Lollipop +########### +DHDCFLAGS += -DWL_ENABLE_P2P_IF +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS + +ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD +endif + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o + + +########################## +# driver type +# m: module type driver +# y: built-in type driver +########################## +DRIVER_TYPE ?= m + +######################### +# Chip dependent feature +######################### + +# Chipsets supported both SDIO and PCIE +ifneq ($(CONFIG_BCM4356),) + DHDCFLAGS += -DSOMC_MIMO + DHDCFLAGS += -DBCM4356_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DDISABLE_FRAMEBURST_VSDB + DHDCFLAGS += -DDISABLE_PM_BCNRX + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +# DHDCFLAGS += -DCUSTOM_AMSDU_AGGSF=4 +# DHDCFLAGS += -DSET_PCIEIRQ_CPU0 +endif + + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE + DHDCFLAGS += -DCUSTOM_DHD_WATCHDOG_MS=125 + DHDCFLAGS += -DDHD_USE_IDLECOUNT -DMAX_IDLE_COUNT=16 -DMAX_RESUME_WAIT=500 +endif + +ifeq ($(CONFIG_ARCH_MSM),y) + #DHDCFLAGS += -DSET_RPS_CPUS +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_DISABLE_ASYNC_SUSPEND +endif +endif + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_TXBFR +ifeq ($(CONFIG_BCM4356),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +endif + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE +endif + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC +# DHDCFLAGS += -DWLAIBSS + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +# Chipsets supported SDIO only +ifeq ($(BUS_IFACE_SDIO),y) +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +endif +endif + +############################# +# Platform dependent feature +############################# +# read custom mac address function +DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE + +# Default Beacon timeout +ifneq ($(CONFIG_SOMC_WLAN_BCN_TIMEOUT),) + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=$(CONFIG_SOMC_WLAN_BCN_TIMEOUT) +else + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=3 +endif + +# The number of the maximum devices which phone can associate +DHDCFLAGS += -DSOMC_MAX_ASSOC_NUM=10 + +# Default Listen Interval in Beacons +ifneq ($(CONFIG_SOMC_WLAN_LISTEN_INTERVAL),) + DHDCFLAGS += -DCUSTOM_LISTEN_INTERVAL=$(CONFIG_SOMC_WLAN_LISTEN_INTERVAL) +endif + +# WAPI +DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI + +# Set keep alive period +ifneq ($(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING),) + DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=$(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING) +endif + +# Set the number of probe requests per channel +ifneq ($(CONFIG_SOMC_WLAN_SCAN_NPROBES),) + DHDCFLAGS += -DSOMC_WLAN_SCAN_NPROBES=$(CONFIG_SOMC_WLAN_SCAN_NPROBES) +endif + +# Set special NV paths for 1DK chip +ifneq ($(CONFIG_SOMC_WLAN_1DK_NV_PATH),) + DHDCFLAGS += -DSOMC_1DK_NV_PATH=\"$(CONFIG_SOMC_WLAN_1DK_NV_PATH)\" +ifneq ($(CONFIG_SOMC_WLAN_LOW_POWER_NV_PATH),) + DHDCFLAGS += -DSOMC_LOW_POWER_NV_PATH=\"$(CONFIG_SOMC_WLAN_LOW_POWER_NV_PATH)\" +endif +endif + +# Disable to delay link down event +#ifeq ($(CONFIG_SOMC_WLAN_DISABLE_BCM_DLY),y) +# DHDCFLAGS += -DDISABLE_BCN_DLY +#endif + +# Change scan time +ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) + DHDCFLAGS += -DCHANGE_SCAN_TIME +endif + +# Enable scan ps(scan power optimization) +ifeq ($(CONFIG_SOMC_WLAN_ENABLE_SCAN_PS),y) + DHDCFLAGS += -DSOMC_WLAN_ENABLE_SCAN_PS +endif + +# Set default nvram path +ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) + DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" +endif + +# Enable Disconnection timing log +ifeq ($(CONFIG_SOMC_WLAN_ENABLE_DISC_TIME_LOG),y) + DHDCFLAGS += -DDHD_ENABLE_DISC_TIME_LOG +endif + + +######### +# Others +######### + +EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +MODNAME := wlan + +DHDOFILES := dhd_pno.o \ + dhd_common.o \ + dhd_ip.o \ + dhd_custom_gpio.o \ + dhd_linux.o \ + dhd_linux_sched.o \ + dhd_cfg80211.o \ + dhd_linux_wq.o \ + aiutils.o \ + bcmevent.o \ + bcmutils.o \ + bcmwifi_channels.o \ + hndpmu.o \ + linux_osl.o \ + sbutils.o \ + siutils.o \ + wl_android.o \ + wl_cfg80211.o \ + wl_cfgp2p.o \ + wl_cfg_btcoex.o \ + wldev_common.o \ + wl_linux_mon.o \ + wl_roam.o \ + dhd_linux_platdev.o \ + dhd_wlfc.o \ + hnd_pktq.o \ + hnd_pktpool.o \ + wl_cfgnan.o \ + bcmxtlv.o \ + dhd_somc_custom.o + +ifeq ($(BUS_IFACE_SDIO),y) +DHDOFILES += bcmsdh.o \ + bcmsdh_linux.o \ + bcmsdh_sdmmc.o \ + bcmsdh_sdmmc_linux.o \ + dhd_cdc.o \ + dhd_sdio.o +endif + + +ifeq ($(BUS_IFACE_PCIE),y) +DHDOFILES += dhd_pcie.o \ + dhd_pcie_linux.o \ + pcie_core.o \ + dhd_flowring.o \ + dhd_msgbuf.o +endif + + +DHDOFILES += $(ANDROID_OFILES) + +# Module information used by KBuild framework +obj-$(CONFIG_BCMDHD_BCM4356) += $(MODNAME).o + +$(MODNAME)-objs := $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Makefile.bcm b/drivers/net/wireless/bcmdhd_bcm4356/Makefile.bcm new file mode 100644 index 000000000000..2bfbf9a59a8e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/Makefile.bcm @@ -0,0 +1,448 @@ +# bcmdhd +##################### +# Basic feature +##################### + +DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DKEEP_ALIVE -DCSCAN \ + -DPKT_FILTER_SUPPORT -DEMBEDDED_PLATFORM -DPNO_SUPPORT + +##################### +# Bus Interface Type +##################### +ifneq ($(CONFIG_BCMDHD_PCIE),) + BUS_IFACE_PCIE=y +else + BUS_IFACE_SDIO=y +endif + +##################### +# SDIO I/F +##################### +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT + DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR + DHDCFLAGS += -U__ARM_ARCH_7A__ + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + # idle count + DHDCFLAGS += -DDHD_USE_IDLECOUNT + # SKB TAILPAD to avoid out of boundary memory access + DHDCFLAGS += -DDHDENABLE_TAILPAD + DHDCFLAGS += -DSUPPORT_P2P_GO_PS +endif + +##################### +# PCIE I/F +##################### +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=-1 + # Enable Link down recovery + DHDCFLAGS += -DSUPPORT_LINKDOWN_RECOVERY + # Enable Firmware Coredump + DHDCFLAGS += -DDHD_FW_COREDUMP + + # Enable packet audit at host side + DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED +endif + + + +################# +# Common feature +################# + +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Enable wakelock debug function +DHDCFLAGS += -DDHD_TRACE_WAKE_LOCK +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS + +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + + + + + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE +DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# For setting custom short & long retry limit +DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + +# HW5 specific features +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DBLOCK_IPV6_PACKET -DPASS_IPV4_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS +# END HW5 specific features + + +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# For Passing all multicast packets to host when not in suspend mode. +DHDCFLAGS += -DPASS_ALL_MCAST_PKTS + + +# Early suspend +DHDCFLAGS += -DDHD_USE_EARLYSUSPEND + +# WiFi turn off delay +DHDCFLAGS += -DWIFI_TURNOFF_DELAY=100 + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER +DHDCFLAGS += -DESCAN_BUF_OVERFLOW_MGMT + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DDHD_USE_STATIC_IOCTLBUF +endif +ifeq ($(CONFIG_BCMDHD_DEBUG_PAGEALLOC),y) +# Preallocation for memory dump + DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP +endif +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# Ioctl Rx count timeout +DHDCFLAGS += -DMAX_CNTL_RX_TIMEOUT=3 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +#DHDCFLAGS += -DWL_ABORT_SCAN + +############################## +# Android Platform Definition +############################## + +########### +# Lollipop +########### +DHDCFLAGS += -DWL_ENABLE_P2P_IF +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o + + + + +########################## +# driver type +# m: module type driver +# y: built-in type driver +########################## +DRIVER_TYPE ?= m + +######################### +# Chip dependent feature +######################### + +# Chipsets supported both SDIO and PCIE +ifneq ($(CONFIG_BCM4356),) + DHDCFLAGS += -DBCM4356_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DDISABLE_FRAMEBURST_VSDB + DHDCFLAGS += -DDISABLE_PM_BCNRX + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +# DHDCFLAGS += -DCUSTOM_AMSDU_AGGSF=4 +# DHDCFLAGS += -DSET_PCIEIRQ_CPU0 +endif + + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE + DHDCFLAGS += -DCUSTOM_DHD_WATCHDOG_MS=125 + DHDCFLAGS += -DDHD_USE_IDLECOUNT -DMAX_IDLE_COUNT=16 -DMAX_RESUME_WAIT=500 +endif + +ifeq ($(CONFIG_ARCH_MSM),y) + #DHDCFLAGS += -DSET_RPS_CPUS +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_DISABLE_ASYNC_SUSPEND +endif +endif + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_TXBFR + +ifeq ($(CONFIG_BCM4356),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +endif + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE +endif + + + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC +# DHDCFLAGS += -DWLAIBSS + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +# Chipsets supported SDIO only +ifeq ($(BUS_IFACE_SDIO),y) +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +endif +endif +############################# +# Platform dependent feature +############################# +######### +# Others +######### + + +EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +DHDOFILES := dhd_pno.o dhd_common.o dhd_ip.o dhd_custom_gpio.o \ + dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_linux_wq.o aiutils.o bcmevent.o \ + bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_cfg_btcoex.o wldev_common.o \ + wl_linux_mon.o wl_roam.o dhd_linux_platdev.o dhd_linux_wq.o wl_cfg_btcoex.o \ + dhd_wlfc.o hnd_pktq.o hnd_pktpool.o wl_cfgnan.o bcmxtlv.o + + +ifeq ($(BUS_IFACE_SDIO),y) +DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o +DHDOFILES += dhd_cdc.o dhd_sdio.o +endif + + +ifeq ($(BUS_IFACE_PCIE),y) +DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o dhd_msgbuf.o +endif + + +DHDOFILES += $(ANDROID_OFILES) + +bcmdhd-objs := $(DHDOFILES) +obj-$(DRIVER_TYPE) += bcmdhd.o + +all: + @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules" + @$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules + +clean: + rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd \ + Module.symvers modules.order .tmp_versions modules.builtin + +install: + @$(MAKE) --no-print-directory -C $(KDIR) \ + SUBDIRS=$(CURDIR) modules_install diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Makefile.kk b/drivers/net/wireless/bcmdhd_bcm4356/Makefile.kk new file mode 100644 index 000000000000..841621adc0cb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/Makefile.kk @@ -0,0 +1,430 @@ +# bcmdhd +##################### +# Basic feature +##################### + +DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DKEEP_ALIVE -DCSCAN \ + -DPKT_FILTER_SUPPORT -DEMBEDDED_PLATFORM -DPNO_SUPPORT + +##################### +# Bus Interface Type +##################### +ifneq ($(CONFIG_BCMDHD_PCIE),) + BUS_IFACE_PCIE=y +else + BUS_IFACE_SDIO=y +endif + +##################### +# SDIO I/F +##################### +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT + DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR + DHDCFLAGS += -U__ARM_ARCH_7A__ + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + # idle count + DHDCFLAGS += -DDHD_USE_IDLECOUNT + # SKB TAILPAD to avoid out of boundary memory access + DHDCFLAGS += -DDHDENABLE_TAILPAD + DHDCFLAGS += -DSUPPORT_P2P_GO_PS +endif + +##################### +# PCIE I/F +##################### +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=-1 + # Enable Link down recovery + DHDCFLAGS += -DSUPPORT_LINKDOWN_RECOVERY + # Enable Firmware Coredump + DHDCFLAGS += -DDHD_FW_COREDUMP + + # Enable packet audit at host side + DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED +endif + + + +################# +# Common feature +################# + +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Enable wakelock debug function +DHDCFLAGS += -DDHD_TRACE_WAKE_LOCK +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS + +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + + + + + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE +DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# For setting custom short & long retry limit +DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + +# HW5 specific features +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DBLOCK_IPV6_PACKET -DPASS_IPV4_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS +# END HW5 specific features + + +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# For Passing all multicast packets to host when not in suspend mode. +DHDCFLAGS += -DPASS_ALL_MCAST_PKTS + + +# Early suspend +DHDCFLAGS += -DDHD_USE_EARLYSUSPEND + +# WiFi turn off delay +DHDCFLAGS += -DWIFI_TURNOFF_DELAY=100 + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER +DHDCFLAGS += -DESCAN_BUF_OVERFLOW_MGMT + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DDHD_USE_STATIC_IOCTLBUF +endif +ifeq ($(CONFIG_BCMDHD_DEBUG_PAGEALLOC),y) +# Preallocation for memory dump + DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP +endif +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# Ioctl Rx count timeout +DHDCFLAGS += -DMAX_CNTL_RX_TIMEOUT=3 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +#DHDCFLAGS += -DWL_ABORT_SCAN + +############################## +# Android Platform Definition +############################## + +## Andrioid KitKat ## + +DHDCFLAGS += -DWL_ENABLE_P2P_IF +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS + + + + +########################## +# driver type +# m: module type driver +# y: built-in type driver +########################## +DRIVER_TYPE ?= m + +######################### +# Chip dependent feature +######################### + +# Chipsets supported both SDIO and PCIE +ifneq ($(CONFIG_BCM4356),) + DHDCFLAGS += -DBCM4356_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DDISABLE_FRAMEBURST_VSDB + DHDCFLAGS += -DDISABLE_PM_BCNRX + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +# DHDCFLAGS += -DCUSTOM_AMSDU_AGGSF=4 +# DHDCFLAGS += -DSET_PCIEIRQ_CPU0 +endif + + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE + DHDCFLAGS += -DCUSTOM_DHD_WATCHDOG_MS=125 + DHDCFLAGS += -DDHD_USE_IDLECOUNT -DMAX_IDLE_COUNT=16 -DMAX_RESUME_WAIT=500 +endif + +ifeq ($(CONFIG_ARCH_MSM),y) + #DHDCFLAGS += -DSET_RPS_CPUS +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_DISABLE_ASYNC_SUSPEND +endif +endif + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_TXBFR + +ifeq ($(CONFIG_BCM4356),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +endif + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE +endif + + + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC +# DHDCFLAGS += -DWLAIBSS + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +# Chipsets supported SDIO only +ifeq ($(BUS_IFACE_SDIO),y) +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +endif +endif +############################# +# Platform dependent feature +############################# +######### +# Others +######### + + +EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +DHDOFILES := dhd_pno.o dhd_common.o dhd_ip.o dhd_custom_gpio.o \ + dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_linux_wq.o aiutils.o bcmevent.o \ + bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_cfg_btcoex.o wldev_common.o \ + wl_linux_mon.o wl_roam.o dhd_linux_platdev.o dhd_linux_wq.o wl_cfg_btcoex.o \ + dhd_wlfc.o hnd_pktq.o hnd_pktpool.o wl_cfgnan.o bcmxtlv.o + + +ifeq ($(BUS_IFACE_SDIO),y) +DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o +DHDOFILES += dhd_cdc.o dhd_sdio.o +endif + + +ifeq ($(BUS_IFACE_PCIE),y) +DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o dhd_msgbuf.o +endif + + +DHDOFILES += $(ANDROID_OFILES) + +bcmdhd-objs := $(DHDOFILES) +obj-$(DRIVER_TYPE) += bcmdhd.o + +all: + @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules" + @$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules + +clean: + rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd \ + Module.symvers modules.order .tmp_versions modules.builtin + +install: + @$(MAKE) --no-print-directory -C $(KDIR) \ + SUBDIRS=$(CURDIR) modules_install diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Makefile_Shamu b/drivers/net/wireless/bcmdhd_bcm4356/Makefile_Shamu new file mode 100644 index 000000000000..b007f79ff33a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/Makefile_Shamu @@ -0,0 +1,439 @@ +# bcmdhd +##################### +# Basic feature +##################### + +DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DKEEP_ALIVE -DCSCAN \ + -DPKT_FILTER_SUPPORT -DEMBEDDED_PLATFORM -DPNO_SUPPORT + +##################### +# Bus Interface Type +##################### +ifneq ($(CONFIG_BCMDHD_PCIE),) + BUS_IFACE_PCIE=y +else + BUS_IFACE_SDIO=y +endif + +##################### +# SDIO I/F +##################### +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT + DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR + DHDCFLAGS += -U__ARM_ARCH_7A__ + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + # idle count + DHDCFLAGS += -DDHD_USE_IDLECOUNT + # SKB TAILPAD to avoid out of boundary memory access + DHDCFLAGS += -DDHDENABLE_TAILPAD + DHDCFLAGS += -DSUPPORT_P2P_GO_PS +endif + +##################### +# PCIE I/F +##################### +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=-1 + # Enable Link down recovery + DHDCFLAGS += -DSUPPORT_LINKDOWN_RECOVERY + # Enable Firmware Coredump + DHDCFLAGS += -DDHD_FW_COREDUMP +endif + + + +################# +# Common feature +################# + +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS + +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + + + + + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE +DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + +# HW5 specific features +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DBLOCK_IPV6_PACKET -DPASS_IPV4_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS +# END HW5 specific features + + +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# For Passing all multicast packets to host when not in suspend mode. +DHDCFLAGS += -DPASS_ALL_MCAST_PKTS + + +# Early suspend +DHDCFLAGS += -DDHD_USE_EARLYSUSPEND + +# WiFi turn off delay +DHDCFLAGS += -DWIFI_TURNOFF_DELAY=100 + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER +DHDCFLAGS += -DESCAN_BUF_OVERFLOW_MGMT + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DDHD_USE_STATIC_IOCTLBUF +endif +ifeq ($(CONFIG_BCMDHD_DEBUG_PAGEALLOC),y) +# Preallocation for memory dump + DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP +endif +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# Ioctl Rx count timeout +DHDCFLAGS += -DMAX_CNTL_RX_TIMEOUT=3 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +############################## +# Android Platform Definition +############################## + +########### +# Lollipop +########### +DHDCFLAGS += -DWL_ENABLE_P2P_IF +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o + + + + +########################## +# driver type +# m: module type driver +# y: built-in type driver +########################## +DRIVER_TYPE ?= m + +######################### +# Chip dependent feature +######################### + +# Chipsets supported both SDIO and PCIE +ifneq ($(CONFIG_BCM4356),) + DHDCFLAGS += -DBCM4356_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DDISABLE_FRAMEBURST_VSDB + DHDCFLAGS += -DDISABLE_PM_BCNRX + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +# DHDCFLAGS += -DCUSTOM_AMSDU_AGGSF=4 +# DHDCFLAGS += -DSET_PCIEIRQ_CPU0 +endif + + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE + DHDCFLAGS += -DCUSTOM_DHD_WATCHDOG_MS=0 +# DHDCFLAGS += -DDHD_USE_IDLECOUNT -DMAX_IDLE_COUNT=16 -DMAX_RESUME_WAIT=100 +endif + +ifeq ($(CONFIG_ARCH_MSM),y) + #DHDCFLAGS += -DSET_RPS_CPUS +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_DISABLE_ASYNC_SUSPEND +endif +endif + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_TXBFR + +ifeq ($(CONFIG_BCM4356),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD +# DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +endif + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE +endif + + + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC +# DHDCFLAGS += -DWLAIBSS + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +# Chipsets supported SDIO only +ifeq ($(BUS_IFACE_SDIO),y) +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +endif +endif +############################# +# Platform dependent feature +############################# +######### +# Others +######### + + +EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +DHDOFILES := dhd_pno.o dhd_common.o dhd_ip.o dhd_custom_gpio.o \ + dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_linux_wq.o aiutils.o bcmevent.o \ + bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_cfg_btcoex.o wldev_common.o \ + wl_linux_mon.o wl_roam.o dhd_linux_platdev.o dhd_linux_wq.o wl_cfg_btcoex.o \ + dhd_wlfc.o hnd_pktq.o hnd_pktpool.o wl_cfgnan.o bcmxtlv.o + + +ifeq ($(BUS_IFACE_SDIO),y) +DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o +DHDOFILES += dhd_cdc.o dhd_sdio.o +endif + + +ifeq ($(BUS_IFACE_PCIE),y) +DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o dhd_msgbuf.o +endif + + +DHDOFILES += $(ANDROID_OFILES) + +bcmdhd-objs := $(DHDOFILES) +obj-$(DRIVER_TYPE) += bcmdhd.o + +all: + @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules" + @$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules + +clean: + rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd \ + Module.symvers modules.order .tmp_versions modules.builtin + +install: + @$(MAKE) --no-print-directory -C $(KDIR) \ + SUBDIRS=$(CURDIR) modules_install diff --git a/drivers/net/wireless/bcmdhd_bcm4356/aiutils.c b/drivers/net/wireless/bcmdhd_bcm4356/aiutils.c new file mode 100644 index 000000000000..3f061ab4093d --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/aiutils.c @@ -0,0 +1,1123 @@ +/* + * Misc utility routines for accessing chip-specific features + * of the SiliconBackplane-based Broadcom chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: aiutils.c 511882 2014-10-31 06:08:29Z $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "siutils_priv.h" + +#define BCM47162_DMP() (0) +#define BCM5357_DMP() (0) +#define BCM4707_DMP() (0) +#define PMU_DMP() (0) +#define remap_coreid(sih, coreid) (coreid) +#define remap_corerev(sih, corerev) (corerev) + +/* EROM parsing */ + +static uint32 +get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) +{ + uint32 ent; + uint inv = 0, nom = 0; + uint32 size = 0; + + while (TRUE) { + ent = R_REG(si_osh(sih), *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; + + /* escape condition related EROM size if it has invalid values */ + size += sizeof(*eromptr); + if (size >= ER_SZ_MAX) { + SI_ERROR(("Failed to find end of EROM marker\n")); + break; + } + + nom++; + } + + SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); + if (inv + nom) { + SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); + } + return ent; +} + +static uint32 +get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, + uint32 *sizel, uint32 *sizeh) +{ + uint32 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); + + SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", + sp, ad, st, *sizeh, *sizel, *addrh, *addrl)); + + return asd; +} + +static void +ai_hwfixup(si_info_t *sii) +{ +} + + +/* parse the enumeration rom to identify all cores */ +void +ai_scan(si_t *sih, void *regs, uint devid) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + chipcregs_t *cc = (chipcregs_t *)regs; + uint32 erombase, *eromptr, *eromlim; + + erombase = R_REG(sii->osh, &cc->eromptr); + + switch (BUSTYPE(sih->bustype)) { + case SI_BUS: + eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); + break; + + case PCI_BUS: + /* Set wrappers address */ + sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); + + /* Now point the window at the erom */ + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); + eromptr = regs; + break; + +#ifdef BCMSDIO + case SPI_BUS: + case SDIO_BUS: + eromptr = (uint32 *)(uintptr)erombase; + break; +#endif /* BCMSDIO */ + + case PCMCIA_BUS: + default: + SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype)); + ASSERT(0); + return; + } + eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); + + SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", + regs, erombase, eromptr, eromlim)); + while (eromptr < eromlim) { + uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; + uint32 mpd, asd, addrl, addrh, sizel, sizeh; + 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)) { + SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); + ai_hwfixup(sii); + return; + } + + cib = get_erom_ent(sih, &eromptr, 0, 0); + + if ((cib & ER_TAG) != ER_CI) { + SI_ERROR(("CIA not followed by CIB\n")); + 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; + +#ifdef BCMDBG_SI + SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " + "nsw = %d, nmp = %d & nsp = %d\n", + mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp)); +#else + BCM_REFERENCE(crev); +#endif + + 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; + } + } + if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID && + cid != PMU_CORE_ID && cid != GCI_CORE_ID) + continue; + } + + idx = sii->numcores; + + cores_info->cia[idx] = cia; + cores_info->cib[idx] = cib; + cores_info->coreid[idx] = remap_coreid(sih, cid); + + for (i = 0; i < nmp; i++) { + mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); + if ((mpd & ER_TAG) != ER_MP) { + SI_ERROR(("Not enough MP entries for component 0x%x\n", cid)); + goto error; + } + SI_VMSG((" Master port %d, mp: %d id: %d\n", i, + (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, + (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); + } + + /* 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) { + do { + /* 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 (br == TRUE) { + break; + } + else if ((addrh != 0) || (sizeh != 0) || + (sizel != SI_CORE_SIZE)) { + SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 =" + "0x%x\n", addrh, sizeh, sizel)); + SI_ERROR(("First Slave ASD for" + "core 0x%04x malformed " + "(0x%08x)\n", cid, asd)); + goto error; + } + } + } while (1); + } + cores_info->coresba[idx] = addrl; + cores_info->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)) { + cores_info->coresba2[idx] = addrl; + cores_info->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); + + if (asd == 0) + break; + j++; + } while (1); + if (j == 0) { + SI_ERROR((" SP %d has no address descriptors\n", i)); + 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) { + SI_ERROR(("Missing descriptor for MW %d\n", i)); + goto error; + } + if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { + SI_ERROR(("Master wrapper %d is not 4KB\n", i)); + goto error; + } + if (i == 0) + cores_info->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) { + SI_ERROR(("Missing descriptor for SW %d\n", i)); + goto error; + } + if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { + SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); + goto error; + } + if ((nmw == 0) && (i == 0)) + cores_info->wrapba[idx] = addrl; + } + + + /* Don't record bridges */ + if (br) + continue; + + /* Done with core */ + sii->numcores++; + } + + SI_ERROR(("Reached end of erom without finding END")); + +error: + sii->numcores = 0; + return; +} + +#define AI_SETCOREIDX_MAPSIZE(coreid) \ + (((coreid) == NS_CCB_CORE_ID) ? 15 * SI_CORE_SIZE : SI_CORE_SIZE) + +/* This function changes the logical "focus" to the indicated core. + * Return the current core's virtual address. + */ +void * +ai_setcoreidx(si_t *sih, uint coreidx) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint32 addr, wrap; + void *regs; + + if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) + return (NULL); + + addr = cores_info->coresba[coreidx]; + wrap = cores_info->wrapba[coreidx]; + + /* + * If the user has provided an interrupt mask enabled function, + * then assert interrupts are disabled before switching the core. + */ + ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); + + switch (BUSTYPE(sih->bustype)) { + case SI_BUS: + /* map new one */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(addr, + AI_SETCOREIDX_MAPSIZE(cores_info->coreid[coreidx])); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + sii->curmap = regs = cores_info->regs[coreidx]; + if (!cores_info->wrappers[coreidx] && (wrap != 0)) { + cores_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->wrappers[coreidx])); + } + sii->curwrap = cores_info->wrappers[coreidx]; + break; + + case PCI_BUS: + /* point bar0 window */ + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); + regs = sii->curmap; + /* point bar0 2nd 4KB window to the primary wrapper */ + if (PCIE_GEN2(sii)) + OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap); + else + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); + break; + +#ifdef BCMSDIO + case SPI_BUS: + case SDIO_BUS: + sii->curmap = regs = (void *)((uintptr)addr); + sii->curwrap = (void *)((uintptr)wrap); + break; +#endif /* BCMSDIO */ + + case PCMCIA_BUS: + default: + ASSERT(0); + regs = NULL; + break; + } + + sii->curmap = regs; + sii->curidx = coreidx; + + return regs; +} + + +void +ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + chipcregs_t *cc = NULL; + uint32 erombase, *eromptr, *eromlim; + uint i, j, cidx; + uint32 cia, cib, nmp, nsp; + uint32 asd, addrl, addrh, sizel, sizeh; + + for (i = 0; i < sii->numcores; i++) { + if (cores_info->coreid[i] == CC_CORE_ID) { + cc = (chipcregs_t *)cores_info->regs[i]; + break; + } + } + if (cc == NULL) + goto error; + + erombase = R_REG(sii->osh, &cc->eromptr); + eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); + eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); + + cidx = sii->curidx; + cia = cores_info->cia[cidx]; + cib = cores_info->cib[cidx]; + + nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; + nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; + + /* scan for cores */ + while (eromptr < eromlim) { + if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && + (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { + break; + } + } + + /* skip master ports */ + for (i = 0; i < nmp; i++) + get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); + + /* Skip ASDs in port 0 */ + 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); + } + + j = 1; + do { + asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, + &sizel, &sizeh); + 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); + if (asd == 0) + break; + + if (!asidx--) { + *addr = addrl; + *size = sizel; + return; + } + j++; + } while (1); + + if (j == 0) { + SI_ERROR((" SP %d has no address descriptors\n", i)); + break; + } + } + +error: + *size = 0; + return; +} + +/* Return the number of address spaces in current core */ +int +ai_numaddrspaces(si_t *sih) +{ + return 2; +} + +/* Return the address of the nth address space in the current core */ +uint32 +ai_addrspace(si_t *sih, uint asidx) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint cidx; + + cidx = sii->curidx; + + if (asidx == 0) + return cores_info->coresba[cidx]; + else if (asidx == 1) + return cores_info->coresba2[cidx]; + else { + SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", + __FUNCTION__, asidx)); + return 0; + } +} + +/* Return the size of the nth address space in the current core */ +uint32 +ai_addrspacesize(si_t *sih, uint asidx) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint cidx; + + cidx = sii->curidx; + + if (asidx == 0) + return cores_info->coresba_size[cidx]; + else if (asidx == 1) + return cores_info->coresba2_size[cidx]; + else { + SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", + __FUNCTION__, asidx)); + return 0; + } +} + +uint +ai_flag(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); + return sii->curidx; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); + return sii->curidx; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", + __FUNCTION__)); + return sii->curidx; + } + +#ifdef REROUTE_OOBINT + if (PMU_DMP()) { + SI_ERROR(("%s: Attempting to read PMU DMP registers\n", + __FUNCTION__)); + return PMU_OOB_BIT; + } +#endif /* REROUTE_OOBINT */ + + ai = sii->curwrap; + ASSERT(ai != NULL); + + return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); +} + +uint +ai_flag_alt(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); + return sii->curidx; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); + return sii->curidx; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", + __FUNCTION__)); + return sii->curidx; + } +#ifdef REROUTE_OOBINT + if (PMU_DMP()) { + SI_ERROR(("%s: Attempting to read PMU DMP registers\n", + __FUNCTION__)); + return PMU_OOB_BIT; + } +#endif /* REROUTE_OOBINT */ + + ai = sii->curwrap; + + return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK); +} + +void +ai_setint(si_t *sih, int siflag) +{ +} + +uint +ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + uint32 *map = (uint32 *) sii->curwrap; + + if (mask || val) { + uint32 w = R_REG(sii->osh, map+(offset/4)); + w &= ~mask; + w |= val; + W_REG(sii->osh, map+(offset/4), w); + } + + return (R_REG(sii->osh, map+(offset/4))); +} + +uint +ai_corevendor(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint32 cia; + + cia = cores_info->cia[sii->curidx]; + return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); +} + +uint +ai_corerev(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint32 cib; + + + cib = cores_info->cib[sii->curidx]; + return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); +} + +bool +ai_iscoreup(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + + ai = sii->curwrap; + + return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && + ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); +} + +/* + * 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(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) +{ + uint origidx = 0; + uint32 *r = NULL; + uint w; + uint intr_val = 0; + bool fast = FALSE; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + + ASSERT(GOODIDX(coreidx)); + ASSERT(regoff < SI_CORE_SIZE); + ASSERT((val & ~mask) == 0); + + if (coreidx >= SI_MAXCORES) + return 0; + + if (BUSTYPE(sih->bustype) == SI_BUS) { + /* If internal bus, we can always get at everything */ + fast = TRUE; + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + } else if (BUSTYPE(sih->bustype) == PCI_BUS) { + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + + fast = TRUE; + r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (uint32 *)((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 = si_coreidx(&sii->pub); + + /* switch core */ + r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); + } + ASSERT(r != NULL); + + /* mask and set */ + if (mask || val) { + w = (R_REG(sii->osh, r) & ~mask) | val; + W_REG(sii->osh, r, w); + } + + /* readback */ + w = R_REG(sii->osh, r); + + if (!fast) { + /* restore core index */ + if (origidx != coreidx) + ai_setcoreidx(&sii->pub, origidx); + + INTR_RESTORE(sii, intr_val); + } + + return (w); +} + +/* + * If there is no need for fiddling with interrupts or core switches (typically silicon + * back plane registers, pci registers and chipcommon registers), this function + * returns the register offset on this core to a mapped address. This address can + * be used for W_REG/R_REG directly. + * + * For accessing registers that would need a core switch, this function will return + * NULL. + */ +uint32 * +ai_corereg_addr(si_t *sih, uint coreidx, uint regoff) +{ + uint32 *r = NULL; + bool fast = FALSE; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + + ASSERT(GOODIDX(coreidx)); + ASSERT(regoff < SI_CORE_SIZE); + + if (coreidx >= SI_MAXCORES) + return 0; + + if (BUSTYPE(sih->bustype) == SI_BUS) { + /* If internal bus, we can always get at everything */ + fast = TRUE; + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + } else if (BUSTYPE(sih->bustype) == PCI_BUS) { + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + + fast = TRUE; + r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (uint32 *)((char *)sii->curmap + + ((regoff >= SBCONFIGOFF) ? + PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + + regoff); + } + } + + if (!fast) + return 0; + + return (r); +} + +void +ai_core_disable(si_t *sih, uint32 bits) +{ + si_info_t *sii = SI_INFO(sih); + volatile uint32 dummy; + uint32 status; + aidmp_t *ai; + + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + /* if core is already in reset, just return */ + if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) + return; + + /* ensure there are no pending backplane operations */ + SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + /* if pending backplane ops still, try waiting longer */ + if (status != 0) { + /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ + /* during driver load we may need more time */ + SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); + /* if still pending ops, continue on and try disable anyway */ + /* this is in big hammer path, so don't call wl_reinit in this case... */ + } + + W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); + dummy = R_REG(sii->osh, &ai->resetctrl); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + + W_REG(sii->osh, &ai->ioctrl, bits); + dummy = R_REG(sii->osh, &ai->ioctrl); + BCM_REFERENCE(dummy); + OSL_DELAY(10); +} + +/* 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(si_t *sih, uint32 bits, uint32 resetbits) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + volatile uint32 dummy; + uint loop_counter = 10; + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + /* ensure there are no pending backplane operations */ + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + + /* put core into reset state */ + W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); + OSL_DELAY(10); + + /* ensure there are no pending backplane operations */ + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); + + W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN)); + dummy = R_REG(sii->osh, &ai->ioctrl); + BCM_REFERENCE(dummy); + + /* ensure there are no pending backplane operations */ + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + + while (R_REG(sii->osh, &ai->resetctrl) != 0 && --loop_counter != 0) { + /* ensure there are no pending backplane operations */ + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + + /* take core out of reset */ + W_REG(sii->osh, &ai->resetctrl, 0); + + /* ensure there are no pending backplane operations */ + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); + } + + + W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); + dummy = R_REG(sii->osh, &ai->ioctrl); + BCM_REFERENCE(dummy); + OSL_DELAY(1); +} + +void +ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + uint32 w; + + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", + __FUNCTION__)); + return; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", + __FUNCTION__)); + return; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", + __FUNCTION__)); + return; + } + if (PMU_DMP()) { + SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", + __FUNCTION__)); + return; + } + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + ASSERT((val & ~mask) == 0); + + if (mask || val) { + w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); + W_REG(sii->osh, &ai->ioctrl, w); + } +} + +uint32 +ai_core_cflags(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + uint32 w; + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", + __FUNCTION__)); + return 0; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", + __FUNCTION__)); + return 0; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", + __FUNCTION__)); + return 0; + } + + if (PMU_DMP()) { + SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", + __FUNCTION__)); + return 0; + } + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + ASSERT((val & ~mask) == 0); + + if (mask || val) { + w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); + W_REG(sii->osh, &ai->ioctrl, w); + } + + return R_REG(sii->osh, &ai->ioctrl); +} + +uint32 +ai_core_sflags(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + uint32 w; + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", + __FUNCTION__)); + return 0; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", + __FUNCTION__)); + return 0; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", + __FUNCTION__)); + return 0; + } + if (PMU_DMP()) { + SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", + __FUNCTION__)); + return 0; + } + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + ASSERT((val & ~mask) == 0); + ASSERT((mask & ~SISF_CORE_BITS) == 0); + + if (mask || val) { + w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); + W_REG(sii->osh, &ai->iostatus, w); + } + + return R_REG(sii->osh, &ai->iostatus); +} + +#if defined(BCMDBG_PHYDUMP) +/* print interesting aidmp registers */ +void +ai_dumpregs(si_t *sih, struct bcmstrbuf *b) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + osl_t *osh; + aidmp_t *ai; + uint i; + + osh = sii->osh; + + for (i = 0; i < sii->numcores; i++) { + si_setcoreidx(&sii->pub, i); + ai = sii->curwrap; + + bcm_bprintf(b, "core 0x%x: \n", cores_info->coreid[i]); + if (BCM47162_DMP()) { + bcm_bprintf(b, "Skipping mips74k in 47162a0\n"); + continue; + } + if (BCM5357_DMP()) { + bcm_bprintf(b, "Skipping usb20h in 5357\n"); + continue; + } + if (BCM4707_DMP()) { + bcm_bprintf(b, "Skipping chipcommonb in 4707\n"); + continue; + } + + if (PMU_DMP()) { + bcm_bprintf(b, "Skipping pmu core\n"); + continue; + } + + bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x" + "ioctrlwidth 0x%x iostatuswidth 0x%x\n" + "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n" + "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x" + "errlogaddrlo 0x%x errlogaddrhi 0x%x\n" + "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n" + "intstatus 0x%x config 0x%x itcr 0x%x\n", + R_REG(osh, &ai->ioctrlset), + R_REG(osh, &ai->ioctrlclear), + R_REG(osh, &ai->ioctrl), + R_REG(osh, &ai->iostatus), + R_REG(osh, &ai->ioctrlwidth), + R_REG(osh, &ai->iostatuswidth), + R_REG(osh, &ai->resetctrl), + R_REG(osh, &ai->resetstatus), + R_REG(osh, &ai->resetreadid), + R_REG(osh, &ai->resetwriteid), + R_REG(osh, &ai->errlogctrl), + R_REG(osh, &ai->errlogdone), + R_REG(osh, &ai->errlogstatus), + R_REG(osh, &ai->errlogaddrlo), + R_REG(osh, &ai->errlogaddrhi), + R_REG(osh, &ai->errlogid), + R_REG(osh, &ai->errloguser), + R_REG(osh, &ai->errlogflags), + R_REG(osh, &ai->intstatus), + R_REG(osh, &ai->config), + R_REG(osh, &ai->itcr)); + } +} +#endif diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c new file mode 100644 index 000000000000..82f2af8eb11d --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c @@ -0,0 +1,304 @@ +/* + * bcmevent read-only data shared by kernel or app layers + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: bcmevent.c 696772 2017-04-28 04:41:32Z $ + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Table of event name strings for UIs and debugging dumps */ +typedef struct { + uint event; + const char *name; +} bcmevent_name_str_t; + +/* Use the actual name for event tracing */ +#define BCMEVENT_NAME(_event) {(_event), #_event} + +static const bcmevent_name_str_t bcmevent_names[] = { + BCMEVENT_NAME(WLC_E_SET_SSID), + BCMEVENT_NAME(WLC_E_JOIN), + BCMEVENT_NAME(WLC_E_START), + BCMEVENT_NAME(WLC_E_AUTH), + BCMEVENT_NAME(WLC_E_AUTH_IND), + BCMEVENT_NAME(WLC_E_DEAUTH), + BCMEVENT_NAME(WLC_E_DEAUTH_IND), + BCMEVENT_NAME(WLC_E_ASSOC), + BCMEVENT_NAME(WLC_E_ASSOC_IND), + BCMEVENT_NAME(WLC_E_REASSOC), + BCMEVENT_NAME(WLC_E_REASSOC_IND), + BCMEVENT_NAME(WLC_E_DISASSOC), + BCMEVENT_NAME(WLC_E_DISASSOC_IND), + BCMEVENT_NAME(WLC_E_QUIET_START), + BCMEVENT_NAME(WLC_E_QUIET_END), + BCMEVENT_NAME(WLC_E_BEACON_RX), + BCMEVENT_NAME(WLC_E_LINK), + BCMEVENT_NAME(WLC_E_MIC_ERROR), + BCMEVENT_NAME(WLC_E_NDIS_LINK), + BCMEVENT_NAME(WLC_E_ROAM), + BCMEVENT_NAME(WLC_E_TXFAIL), + BCMEVENT_NAME(WLC_E_PMKID_CACHE), + BCMEVENT_NAME(WLC_E_RETROGRADE_TSF), + BCMEVENT_NAME(WLC_E_PRUNE), + BCMEVENT_NAME(WLC_E_AUTOAUTH), + BCMEVENT_NAME(WLC_E_EAPOL_MSG), + BCMEVENT_NAME(WLC_E_SCAN_COMPLETE), + BCMEVENT_NAME(WLC_E_ADDTS_IND), + BCMEVENT_NAME(WLC_E_DELTS_IND), + BCMEVENT_NAME(WLC_E_BCNSENT_IND), + BCMEVENT_NAME(WLC_E_BCNRX_MSG), + BCMEVENT_NAME(WLC_E_BCNLOST_MSG), + BCMEVENT_NAME(WLC_E_ROAM_PREP), + BCMEVENT_NAME(WLC_E_PFN_NET_FOUND), + BCMEVENT_NAME(WLC_E_PFN_NET_LOST), +#if defined(IBSS_PEER_DISCOVERY_EVENT) + BCMEVENT_NAME(WLC_E_IBSS_ASSOC), +#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */ + BCMEVENT_NAME(WLC_E_RADIO), + BCMEVENT_NAME(WLC_E_PSM_WATCHDOG), + BCMEVENT_NAME(WLC_E_PROBREQ_MSG), + BCMEVENT_NAME(WLC_E_SCAN_CONFIRM_IND), + BCMEVENT_NAME(WLC_E_PSK_SUP), + BCMEVENT_NAME(WLC_E_COUNTRY_CODE_CHANGED), + BCMEVENT_NAME(WLC_E_EXCEEDED_MEDIUM_TIME), + BCMEVENT_NAME(WLC_E_ICV_ERROR), + BCMEVENT_NAME(WLC_E_UNICAST_DECODE_ERROR), + BCMEVENT_NAME(WLC_E_MULTICAST_DECODE_ERROR), + BCMEVENT_NAME(WLC_E_TRACE), + BCMEVENT_NAME(WLC_E_IF), +#ifdef WLP2P + BCMEVENT_NAME(WLC_E_P2P_DISC_LISTEN_COMPLETE), +#endif + BCMEVENT_NAME(WLC_E_RSSI), + BCMEVENT_NAME(WLC_E_PFN_SCAN_COMPLETE), + BCMEVENT_NAME(WLC_E_EXTLOG_MSG), +#ifdef WIFI_ACT_FRAME + BCMEVENT_NAME(WLC_E_ACTION_FRAME), + BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX), + BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE), +#endif +#ifdef BCMWAPI_WAI + BCMEVENT_NAME(WLC_E_WAI_STA_EVENT), + BCMEVENT_NAME(WLC_E_WAI_MSG), +#endif /* BCMWAPI_WAI */ + BCMEVENT_NAME(WLC_E_ESCAN_RESULT), + BCMEVENT_NAME(WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE), +#ifdef WLP2P + BCMEVENT_NAME(WLC_E_PROBRESP_MSG), + BCMEVENT_NAME(WLC_E_P2P_PROBREQ_MSG), +#endif +#ifdef PROP_TXSTATUS + BCMEVENT_NAME(WLC_E_FIFO_CREDIT_MAP), +#endif + BCMEVENT_NAME(WLC_E_WAKE_EVENT), + BCMEVENT_NAME(WLC_E_DCS_REQUEST), + BCMEVENT_NAME(WLC_E_RM_COMPLETE), +#ifdef WLMEDIA_HTSF + BCMEVENT_NAME(WLC_E_HTSFSYNC), +#endif + BCMEVENT_NAME(WLC_E_OVERLAY_REQ), + BCMEVENT_NAME(WLC_E_CSA_COMPLETE_IND), + BCMEVENT_NAME(WLC_E_EXCESS_PM_WAKE_EVENT), + BCMEVENT_NAME(WLC_E_PFN_SCAN_NONE), + BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE), +#ifdef SOFTAP + BCMEVENT_NAME(WLC_E_GTK_PLUMBED), +#endif + BCMEVENT_NAME(WLC_E_ASSOC_REQ_IE), + BCMEVENT_NAME(WLC_E_ASSOC_RESP_IE), + BCMEVENT_NAME(WLC_E_BEACON_FRAME_RX), +#ifdef WLTDLS + BCMEVENT_NAME(WLC_E_TDLS_PEER_EVENT), +#endif /* WLTDLS */ + BCMEVENT_NAME(WLC_E_NATIVE), +#ifdef WLPKTDLYSTAT + BCMEVENT_NAME(WLC_E_PKTDELAY_IND), +#endif /* WLPKTDLYSTAT */ + BCMEVENT_NAME(WLC_E_SERVICE_FOUND), + BCMEVENT_NAME(WLC_E_GAS_FRAGMENT_RX), + BCMEVENT_NAME(WLC_E_GAS_COMPLETE), + BCMEVENT_NAME(WLC_E_P2PO_ADD_DEVICE), + BCMEVENT_NAME(WLC_E_P2PO_DEL_DEVICE), +#ifdef WLWNM + BCMEVENT_NAME(WLC_E_WNM_STA_SLEEP), +#endif /* WLWNM */ +#if defined(WL_PROXDETECT) + BCMEVENT_NAME(WLC_E_PROXD), +#endif + BCMEVENT_NAME(WLC_E_CCA_CHAN_QUAL), + BCMEVENT_NAME(WLC_E_BSSID), +#ifdef PROP_TXSTATUS + BCMEVENT_NAME(WLC_E_BCMC_CREDIT_SUPPORT), +#endif + BCMEVENT_NAME(WLC_E_TXFAIL_THRESH), +#ifdef GSCAN_SUPPORT + BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT), + BCMEVENT_NAME(WLC_E_PFN_SWC), +#endif /* GSCAN_SUPPORT */ +#ifdef WLBSSLOAD_REPORT + BCMEVENT_NAME(WLC_E_BSS_LOAD), +#endif +#if defined(BT_WIFI_HANDOVER) || defined(WL_TBOW) + BCMEVENT_NAME(WLC_E_BT_WIFI_HANDOVER_REQ), +#endif +#ifdef GSCAN_SUPPORT + BCMEVENT_NAME(WLC_E_PFN_SSID_EXT), +#endif /* GSCAN_SUPPORT */ +#ifdef WLFBT + BCMEVENT_NAME(WLC_E_FBT_AUTH_REQ_IND), +#endif /* WLFBT */ + BCMEVENT_NAME(WLC_E_RMC_EVENT), +}; + + +const char *bcmevent_get_name(uint event_type) +{ + /* note: first coded this as a static const but some + * ROMs already have something called event_name so + * changed it so we don't have a variable for the + * 'unknown string + */ + const char *event_name = NULL; + + uint idx; + for (idx = 0; idx < (uint)ARRAYSIZE(bcmevent_names); idx++) { + + if (bcmevent_names[idx].event == event_type) { + event_name = bcmevent_names[idx].name; + break; + } + } + + /* if we find an event name in the array, return it. + * otherwise return unknown string. + */ + return ((event_name) ? event_name : "Unknown Event"); +} + +/* + * Validate if the event is proper and if valid copy event header to event. + * If proper event pointer is passed, to just validate, pass NULL to event. + * + * Return values are + * BCME_OK - It is a BRCM event or BRCM dongle event + * BCME_NOTFOUND - Not BRCM, not an event, may be okay + * BCME_BADLEN - Bad length, should not process, just drop + */ +int +is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, + void *out_event) +{ + uint16 evlen = 0; /* length in bcmeth_hdr */ + uint16 subtype; + uint16 usr_subtype; + bcm_event_t *bcm_event; + uint8 *pktend; + uint8 *evend; + int err = BCME_OK; + uint32 data_len = 0; /* data length in bcm_event */ + + pktend = (uint8 *)pktdata + pktlen; + bcm_event = (bcm_event_t *)pktdata; + + /* only care about 16-bit subtype / length versions */ + if ((uint8 *)&bcm_event->bcm_hdr < pktend) { + uint8 short_subtype = *(uint8 *)&bcm_event->bcm_hdr; + if (!(short_subtype & 0x80)) { + err = BCME_NOTFOUND; + goto done; + } + } + + /* must have both ether_header and bcmeth_hdr */ + if (pktlen < OFFSETOF(bcm_event_t, event)) { + err = BCME_BADLEN; + goto done; + } + + /* check length in bcmeth_hdr */ + /* temporary - header length not always set properly. When the below + * !BCMDONGLEHOST is in all branches that use trunk DHD, the code + * under BCMDONGLEHOST can be removed. + */ + evlen = (uint16)(pktend - (uint8 *)&bcm_event->bcm_hdr.version); + evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen; + if (evend > pktend) { + err = BCME_BADLEN; + goto done; + } + + /* match on subtype, oui and usr subtype for BRCM events */ + subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.subtype); + if (subtype != BCMILCP_SUBTYPE_VENDOR_LONG) { + err = BCME_NOTFOUND; + goto done; + } + + if (bcmp(BRCM_OUI, &bcm_event->bcm_hdr.oui[0], DOT11_OUI_LEN)) { + err = BCME_NOTFOUND; + goto done; + } + + /* if it is a bcm_event, validate it */ + usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype); + switch (usr_subtype) { + case BCMILCP_BCM_SUBTYPE_EVENT: + /* check that header length and pkt length are sufficient */ + if ((pktlen < sizeof(bcm_event_t)) || + (evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) { + err = BCME_BADLEN; + goto done; + } + + /* ensure data length in event is not beyond the packet. */ + data_len = ntoh32_ua((void *)&bcm_event->event.datalen); + if (data_len > (pktlen - sizeof(bcm_event_t))) { + err = BCME_BADLEN; + goto done; + } + + if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) { + err = BCME_NOTFOUND; + goto done; + } + + if (out_event) { + /* ensure BRCM event pkt aligned */ + memcpy(out_event, &bcm_event->event, sizeof(wl_event_msg_t)); + } + + break; + default: + err = BCME_NOTFOUND; + goto done; + } + + BCM_REFERENCE(data_len); +done: + return err; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh.c new file mode 100644 index 000000000000..920f3a51f5ea --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh.c @@ -0,0 +1,705 @@ +/* + * BCMSDH interface glue + * implement bcmsdh API for SDIOH driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh.c 450676 2014-01-22 22:45:13Z $ + */ + +/** + * @file bcmsdh.c + */ + +/* ****************** BCMSDH Interface Functions *************************** */ + +#include +#include +#include +#include +#include +#include +#include + +#include /* BRCM API for SDIO clients (such as wl, dhd) */ +#include /* common SDIO/controller interface */ +#include /* SDIO device core hardware definitions. */ +#include /* SDIO Device and Protocol Specs */ + +#define SDIOH_API_ACCESS_RETRY_LIMIT 2 +const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; + +/* local copy of bcm sd handler */ +bcmsdh_info_t * l_bcmsdh = NULL; + + +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) +extern int +sdioh_enable_hw_oob_intr(void *sdioh, bool enable); + +void +bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) +{ + sdioh_enable_hw_oob_intr(sdh->sdioh, enable); +} +#endif + +/* Attach BCMSDH layer to SDIO Host Controller Driver + * + * @param osh OSL Handle. + * @param cfghdl Configuration Handle. + * @param regsva Virtual address of controller registers. + * @param irq Interrupt number of SDIO controller. + * + * @return bcmsdh_info_t Handle to BCMSDH context. + */ +bcmsdh_info_t * +bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva) +{ + bcmsdh_info_t *bcmsdh; + + if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) { + BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); + return NULL; + } + bzero((char *)bcmsdh, sizeof(bcmsdh_info_t)); + bcmsdh->sdioh = sdioh; + bcmsdh->osh = osh; + bcmsdh->init_success = TRUE; + *regsva = SI_ENUM_BASE; + + /* Report the BAR, to fix if needed */ + bcmsdh->sbwad = SI_ENUM_BASE; + + /* save the handler locally */ + l_bcmsdh = bcmsdh; + + return bcmsdh; +} + +int +bcmsdh_detach(osl_t *osh, void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + if (bcmsdh != NULL) { + MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t)); + } + + l_bcmsdh = NULL; + + return 0; +} + +int +bcmsdh_iovar_op(void *sdh, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set); +} + +bool +bcmsdh_intr_query(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + bool on; + + ASSERT(bcmsdh); + status = sdioh_interrupt_query(bcmsdh->sdioh, &on); + if (SDIOH_API_SUCCESS(status)) + return FALSE; + else + return on; +} + +int +bcmsdh_intr_enable(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + ASSERT(bcmsdh); + + status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE); + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_intr_disable(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + ASSERT(bcmsdh); + + status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE); + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + ASSERT(bcmsdh); + + status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh); + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_intr_dereg(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + ASSERT(bcmsdh); + + status = sdioh_interrupt_deregister(bcmsdh->sdioh); + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +#if defined(DHD_DEBUG) +bool +bcmsdh_intr_pending(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + ASSERT(sdh); + return sdioh_interrupt_pending(bcmsdh->sdioh); +} +#endif + + +int +bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) +{ + ASSERT(sdh); + + /* don't support yet */ + return BCME_UNSUPPORTED; +} + +/** + * Read from SDIO Configuration Space + * @param sdh SDIO Host context. + * @param func_num Function number to read from. + * @param addr Address to read from. + * @param err Error return. + * @return value read from SDIO configuration space. + */ +uint8 +bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + int32 retry = 0; +#endif + uint8 data = 0; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + do { + if (retry) /* wait for 1 ms till bus get settled down */ + OSL_DELAY(1000); +#endif + status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); +#endif + if (err) + *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, + fnc_num, addr, data)); + + return data; +} + +void +bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + int32 retry = 0; +#endif + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + do { + if (retry) /* wait for 1 ms till bus get settled down */ + OSL_DELAY(1000); +#endif + status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); +#endif + if (err) + *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR; + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, + fnc_num, addr, data)); +} + +uint32 +bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + uint32 data = 0; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + + status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num, + addr, &data, 4); + + if (err) + *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, + fnc_num, addr, data)); + + return data; +} + +void +bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + + status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num, + addr, &data, 4); + + if (err) + *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num, + addr, data)); +} + + +int +bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + + uint8 *tmp_buf, *tmp_ptr; + uint8 *ptr; + bool ascii = func & ~0xf; + func &= 0x7; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + ASSERT(cis); + ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT); + + status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length); + + if (ascii) { + /* Move binary bits to tmp and format them into the provided buffer. */ + if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) { + BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__)); + return BCME_NOMEM; + } + bcopy(cis, tmp_buf, length); + for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) { + ptr += snprintf((char*)ptr, (cis + length - ptr - 4), + "%.2x ", *tmp_ptr & 0xff); + if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) + ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n"); + } + MFREE(bcmsdh->osh, tmp_buf, length); + } + + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + + +int +bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set) +{ + int err = 0; + uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK; + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + if (bar0 != bcmsdh->sbwad || force_set) { + bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, + (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); + if (!err) + bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, + (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); + if (!err) + bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, + (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); + + if (!err) + bcmsdh->sbwad = bar0; + else + /* invalidate cached window var */ + bcmsdh->sbwad = 0; + + } + + return err; +} + +uint32 +bcmsdh_reg_read(void *sdh, uint32 addr, uint size) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + uint32 word = 0; + + BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr)); + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + + if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)) + return 0xFFFFFFFF; + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + if (size == 4) + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + + status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, + SDIOH_READ, SDIO_FUNC_1, addr, &word, size); + + bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); + + BCMSDH_INFO(("uint32data = 0x%x\n", word)); + + /* if ok, return appropriately masked word */ + if (SDIOH_API_SUCCESS(status)) { + switch (size) { + case sizeof(uint8): + return (word & 0xff); + case sizeof(uint16): + return (word & 0xffff); + case sizeof(uint32): + return word; + default: + bcmsdh->regfail = TRUE; + + } + } + + /* otherwise, bad sdio access or invalid size */ + BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size)); + return 0xFFFFFFFF; +} + +uint32 +bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + int err = 0; + + BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", + __FUNCTION__, addr, size*8, data)); + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + + if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) + return err; + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + if (size == 4) + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1, + addr, &data, size); + bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); + + if (SDIOH_API_SUCCESS(status)) + return 0; + + BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n", + __FUNCTION__, data, addr, size)); + return 0xFFFFFFFF; +} + +bool +bcmsdh_regfail(void *sdh) +{ + return ((bcmsdh_info_t *)sdh)->regfail; +} + +int +bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, void *pkt, + bcmsdh_cmplt_fn_t complete_fn, void *handle) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + uint incr_fix; + uint width; + int err = 0; + + ASSERT(bcmsdh); + ASSERT(bcmsdh->init_success); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", + __FUNCTION__, fn, addr, nbytes)); + + /* Async not implemented yet */ + ASSERT(!(flags & SDIO_REQ_ASYNC)); + if (flags & SDIO_REQ_ASYNC) + return BCME_UNSUPPORTED; + + if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) + return err; + + 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 = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, + SDIOH_READ, fn, addr, width, nbytes, buf, pkt); + + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); +} + +int +bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, void *pkt, + bcmsdh_cmplt_fn_t complete_fn, void *handle) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + uint incr_fix; + uint width; + int err = 0; + + ASSERT(bcmsdh); + ASSERT(bcmsdh->init_success); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", + __FUNCTION__, fn, addr, nbytes)); + + /* Async not implemented yet */ + ASSERT(!(flags & SDIO_REQ_ASYNC)); + if (flags & SDIO_REQ_ASYNC) + return BCME_UNSUPPORTED; + + if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) + return err; + + 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 = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, + SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt); + + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + + ASSERT(bcmsdh); + ASSERT(bcmsdh->init_success); + ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0); + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + + status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC, + (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, + addr, 4, nbytes, buf, NULL); + + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_abort(void *sdh, uint fn) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_abort(bcmsdh->sdioh, fn); +} + +int +bcmsdh_start(void *sdh, int stage) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_start(bcmsdh->sdioh, stage); +} + +int +bcmsdh_stop(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_stop(bcmsdh->sdioh); +} + +int +bcmsdh_waitlockfree(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_waitlockfree(bcmsdh->sdioh); +} + + +int +bcmsdh_query_device(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0; + return (bcmsdh->vendevid); +} + +uint +bcmsdh_query_iofnum(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + return (sdioh_query_iofnum(bcmsdh->sdioh)); +} + +int +bcmsdh_reset(bcmsdh_info_t *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_sdio_reset(bcmsdh->sdioh); +} + +void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh) +{ + ASSERT(sdh); + return sdh->sdioh; +} + +/* Function to pass device-status bits to DHD. */ +uint32 +bcmsdh_get_dstatus(void *sdh) +{ + return 0; +} +uint32 +bcmsdh_cur_sbwad(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + return (bcmsdh->sbwad); +} + +void +bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev) +{ + return; +} + + +int +bcmsdh_sleep(void *sdh, bool enab) +{ +#ifdef SDIOH_SLEEP_ENABLED + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_sleep(sd, enab); +#else + return BCME_UNSUPPORTED; +#endif +} + +int +bcmsdh_gpio_init(void *sdh) +{ + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_gpio_init(sd); +} + +bool +bcmsdh_gpioin(void *sdh, uint32 gpio) +{ + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_gpioin(sd, gpio); +} + +int +bcmsdh_gpioouten(void *sdh, uint32 gpio) +{ + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_gpioouten(sd, gpio); +} + +int +bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) +{ + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_gpioout(sd, gpio, enab); +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_linux.c new file mode 100644 index 000000000000..c9efdb77874c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_linux.c @@ -0,0 +1,457 @@ +/* + * SDIO access interface for drivers - linux specific (pci only) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh_linux.c 461444 2014-03-12 02:55:28Z $ + */ + +/** + * @file bcmsdh_linux.c + */ + +#define __UNDEF_NO_VERSION__ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +extern void dhdsdio_isr(void * args); +#include +#include +#include +#include + +/* driver info, initialized when bcmsdh_register is called */ +static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL}; + +typedef enum { + DHD_INTR_INVALID = 0, + DHD_INTR_INBAND, + DHD_INTR_HWOOB, + DHD_INTR_SWOOB +} DHD_HOST_INTR_TYPE; + +/* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g. + * bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather + * than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this + * structure. + */ +typedef struct bcmsdh_os_info { + DHD_HOST_INTR_TYPE intr_type; + int oob_irq_num; /* valid when hardware or software oob in use */ + unsigned long oob_irq_flags; /* valid when hardware or software oob in use */ + bool oob_irq_registered; + bool oob_irq_enabled; + bool oob_irq_wake_enabled; + spinlock_t oob_irq_spinlock; + bcmsdh_cb_fn_t oob_irq_handler; + void *oob_irq_handler_context; + void *context; /* context returned from upper layer */ + void *sdioh; /* handle to lower layer (sdioh) */ + void *dev; /* handle to the underlying device */ + bool dev_wake_enabled; +} bcmsdh_os_info_t; + +/* debugging macros */ +#define SDLX_MSG(x) + +/** + * Checks to see if vendor and device IDs match a supported SDIO Host Controller. + */ +bool +bcmsdh_chipmatch(uint16 vendor, uint16 device) +{ + /* Add other vendors and devices as required */ + +#ifdef BCMSDIOH_STD + /* Check for Arasan host controller */ + if (vendor == VENDOR_SI_IMAGE) { + return (TRUE); + } + /* Check for BRCM 27XX Standard host controller */ + if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) { + return (TRUE); + } + /* Check for BRCM Standard host controller */ + if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) { + return (TRUE); + } + /* Check for TI PCIxx21 Standard host controller */ + if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) { + return (TRUE); + } + if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) { + return (TRUE); + } + /* Ricoh R5C822 Standard SDIO Host */ + if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) { + return (TRUE); + } + /* JMicron Standard SDIO Host */ + if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) { + return (TRUE); + } + +#endif /* BCMSDIOH_STD */ +#ifdef BCMSDIOH_SPI + /* This is the PciSpiHost. */ + if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) { + printf("Found PCI SPI Host Controller\n"); + return (TRUE); + } + +#endif /* BCMSDIOH_SPI */ + + return (FALSE); +} + +void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, + uint bus_num, uint slot_num) +{ + ulong regs; + bcmsdh_info_t *bcmsdh; + uint32 vendevid; + bcmsdh_os_info_t *bcmsdh_osinfo = NULL; + + bcmsdh = bcmsdh_attach(osh, sdioh, ®s); + if (bcmsdh == NULL) { + SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__)); + goto err; + } + bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t)); + if (bcmsdh_osinfo == NULL) { + SDLX_MSG(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__)); + goto err; + } + bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); + bcmsdh->os_cxt = bcmsdh_osinfo; + bcmsdh_osinfo->sdioh = sdioh; + bcmsdh_osinfo->dev = dev; + osl_set_bus_handle(osh, bcmsdh); + +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (dev && device_init_wakeup(dev, true) == 0) + bcmsdh_osinfo->dev_wake_enabled = TRUE; +#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ + +#if defined(OOB_INTR_ONLY) + spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock); + /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */ + bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info, + &bcmsdh_osinfo->oob_irq_flags); + if (bcmsdh_osinfo->oob_irq_num < 0) { + SDLX_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__)); + goto err; + } +#endif /* defined(BCMLXSDMMC) */ + + /* Read the vendor/device ID from the CIS */ + vendevid = bcmsdh_query_device(bcmsdh); + /* try to attach to the target device */ + bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num, + slot_num, 0, bus_type, (void *)regs, osh, bcmsdh); + if (bcmsdh_osinfo->context == NULL) { + SDLX_MSG(("%s: device attach failed\n", __FUNCTION__)); + goto err; + } + + return bcmsdh; + + /* error handling */ +err: + if (bcmsdh != NULL) + bcmsdh_detach(osh, bcmsdh); + if (bcmsdh_osinfo != NULL) + MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); + return NULL; +} + +int bcmsdh_remove(bcmsdh_info_t *bcmsdh) +{ + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (bcmsdh_osinfo->dev) + device_init_wakeup(bcmsdh_osinfo->dev, false); + bcmsdh_osinfo->dev_wake_enabled = FALSE; +#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ + + drvinfo.remove(bcmsdh_osinfo->context); + MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t)); + bcmsdh_detach(bcmsdh->osh, bcmsdh); + + return 0; +} + +int bcmsdh_suspend(bcmsdh_info_t *bcmsdh) +{ + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context)) + return -EBUSY; + return 0; +} + +int bcmsdh_resume(bcmsdh_info_t *bcmsdh) +{ + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + if (drvinfo.resume) + return drvinfo.resume(bcmsdh_osinfo->context); + return 0; +} + +extern int bcmsdh_register_client_driver(void); +extern void bcmsdh_unregister_client_driver(void); +extern int sdio_func_reg_notify(void* semaphore); +extern void sdio_func_unreg_notify(void); + +#if defined(BCMLXSDMMC) +int bcmsdh_reg_sdio_notify(void* semaphore) +{ + return sdio_func_reg_notify(semaphore); +} + +void bcmsdh_unreg_sdio_notify(void) +{ + sdio_func_unreg_notify(); +} +#endif /* defined(BCMLXSDMMC) */ + +int +bcmsdh_register(bcmsdh_driver_t *driver) +{ + int error = 0; + + drvinfo = *driver; + SDLX_MSG(("%s: register client driver\n", __FUNCTION__)); + error = bcmsdh_register_client_driver(); + if (error) + SDLX_MSG(("%s: failed %d\n", __FUNCTION__, error)); + + return error; +} + +void +bcmsdh_unregister(void) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) + if (bcmsdh_pci_driver.node.next == NULL) + return; +#endif + + bcmsdh_unregister_client_driver(); +} + +void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh) +{ +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + pm_stay_awake(bcmsdh_osinfo->dev); +#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ +} + +void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh) +{ +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + pm_relax(bcmsdh_osinfo->dev); +#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ +} + +bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh) +{ + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + return bcmsdh_osinfo->dev_wake_enabled; +} + +#if defined(OOB_INTR_ONLY) +void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable) +{ + unsigned long flags; + bcmsdh_os_info_t *bcmsdh_osinfo; + + if (!bcmsdh) + return; + + bcmsdh_osinfo = bcmsdh->os_cxt; + spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags); + if (bcmsdh_osinfo->oob_irq_enabled != enable) { + if (enable) + enable_irq(bcmsdh_osinfo->oob_irq_num); + else + disable_irq_nosync(bcmsdh_osinfo->oob_irq_num); + bcmsdh_osinfo->oob_irq_enabled = enable; + } + spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags); +} + +static irqreturn_t wlan_oob_irq(int irq, void *dev_id) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id; + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + bcmsdh_oob_intr_set(bcmsdh, FALSE); + bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context); + + return IRQ_HANDLED; +} + +int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, + void* oob_irq_handler_context) +{ + int err = 0; + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + SDLX_MSG(("%s: Enter\n", __FUNCTION__)); + if (bcmsdh_osinfo->oob_irq_registered) { + SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__)); + return -EBUSY; + } + SDLX_MSG(("%s OOB irq=%d flags=%X \n", __FUNCTION__, + (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags)); + bcmsdh_osinfo->oob_irq_handler = oob_irq_handler; + bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context; + err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, + bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); + if (err) { + SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err)); + return err; + } + + err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num); + if (!err) + bcmsdh_osinfo->oob_irq_wake_enabled = TRUE; + bcmsdh_osinfo->oob_irq_enabled = TRUE; + bcmsdh_osinfo->oob_irq_registered = TRUE; + return err; +} + +void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh) +{ + int err = 0; + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + SDLX_MSG(("%s: Enter\n", __FUNCTION__)); + if (!bcmsdh_osinfo->oob_irq_registered) { + SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__)); + return; + } + if (bcmsdh_osinfo->oob_irq_wake_enabled) { + err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num); + if (!err) + bcmsdh_osinfo->oob_irq_wake_enabled = FALSE; + } + if (bcmsdh_osinfo->oob_irq_enabled) { + disable_irq(bcmsdh_osinfo->oob_irq_num); + bcmsdh_osinfo->oob_irq_enabled = FALSE; + } + free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh); + bcmsdh_osinfo->oob_irq_registered = FALSE; +} +#endif + +/* Module parameters specific to each host-controller driver */ + +extern uint sd_msglevel; /* Debug message level */ +module_param(sd_msglevel, uint, 0); + +extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */ +module_param(sd_power, uint, 0); + +extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */ +module_param(sd_clock, uint, 0); + +extern uint sd_divisor; /* Divisor (-1 means external clock) */ +module_param(sd_divisor, uint, 0); + +extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */ +module_param(sd_sdmode, uint, 0); + +extern uint sd_hiok; /* Ok to use hi-speed mode */ +module_param(sd_hiok, uint, 0); + +extern uint sd_f2_blocksize; +module_param(sd_f2_blocksize, int, 0); + +#ifdef BCMSDIOH_STD +extern int sd_uhsimode; +module_param(sd_uhsimode, int, 0); +extern uint sd_tuning_period; +module_param(sd_tuning_period, uint, 0); +extern int sd_delay_value; +module_param(sd_delay_value, uint, 0); + +/* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */ +extern char dhd_sdiod_uhsi_ds_override[2]; +module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0); + +#endif + +#ifdef BCMSDH_MODULE +EXPORT_SYMBOL(bcmsdh_attach); +EXPORT_SYMBOL(bcmsdh_detach); +EXPORT_SYMBOL(bcmsdh_intr_query); +EXPORT_SYMBOL(bcmsdh_intr_enable); +EXPORT_SYMBOL(bcmsdh_intr_disable); +EXPORT_SYMBOL(bcmsdh_intr_reg); +EXPORT_SYMBOL(bcmsdh_intr_dereg); + +#if defined(DHD_DEBUG) +EXPORT_SYMBOL(bcmsdh_intr_pending); +#endif + +EXPORT_SYMBOL(bcmsdh_devremove_reg); +EXPORT_SYMBOL(bcmsdh_cfg_read); +EXPORT_SYMBOL(bcmsdh_cfg_write); +EXPORT_SYMBOL(bcmsdh_cis_read); +EXPORT_SYMBOL(bcmsdh_reg_read); +EXPORT_SYMBOL(bcmsdh_reg_write); +EXPORT_SYMBOL(bcmsdh_regfail); +EXPORT_SYMBOL(bcmsdh_send_buf); +EXPORT_SYMBOL(bcmsdh_recv_buf); + +EXPORT_SYMBOL(bcmsdh_rwdata); +EXPORT_SYMBOL(bcmsdh_abort); +EXPORT_SYMBOL(bcmsdh_query_device); +EXPORT_SYMBOL(bcmsdh_query_iofnum); +EXPORT_SYMBOL(bcmsdh_iovar_op); +EXPORT_SYMBOL(bcmsdh_register); +EXPORT_SYMBOL(bcmsdh_unregister); +EXPORT_SYMBOL(bcmsdh_chipmatch); +EXPORT_SYMBOL(bcmsdh_reset); +EXPORT_SYMBOL(bcmsdh_waitlockfree); + +EXPORT_SYMBOL(bcmsdh_get_dstatus); +EXPORT_SYMBOL(bcmsdh_cfg_read_word); +EXPORT_SYMBOL(bcmsdh_cfg_write_word); +EXPORT_SYMBOL(bcmsdh_cur_sbwad); +EXPORT_SYMBOL(bcmsdh_chipinfo); + +#endif /* BCMSDH_MODULE */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc.c new file mode 100644 index 000000000000..cb042eba94af --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc.c @@ -0,0 +1,1456 @@ +/* + * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh_sdmmc.c 459285 2014-03-03 02:54:39Z $ + */ +#include + +#include +#include +#include +#include +#include /* SDIO Device and Protocol Specs */ +#include /* Standard SDIO Host Controller Specification */ +#include /* bcmsdh to/from specific controller APIs */ +#include /* ioctl/iovars */ + +#include +#include +#include +#include +#include + +#include +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#include +extern volatile bool dhd_mmc_suspend; +#endif +#include "bcmsdh_sdmmc.h" + +#ifndef BCMSDH_MODULE +extern int sdio_function_init(void); +extern void sdio_function_cleanup(void); +#endif /* BCMSDH_MODULE */ + +#if !defined(OOB_INTR_ONLY) +static void IRQHandler(struct sdio_func *func); +static void IRQHandlerF2(struct sdio_func *func); +#endif /* !defined(OOB_INTR_ONLY) */ +static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); +extern int sdio_reset_comm(struct mmc_card *card); + +#define DEFAULT_SDIO_F2_BLKSIZE 512 +#ifndef CUSTOM_SDIO_F2_BLKSIZE +#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE +#endif + +#define MAX_IO_RW_EXTENDED_BLK 511 + +uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ +uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; +uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ + +uint sd_power = 1; /* Default to SD Slot powered ON */ +uint sd_clock = 1; /* Default to SD Clock turned ON */ +uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ +uint sd_msglevel = 0x01; +uint sd_use_dma = TRUE; + +#ifndef CUSTOM_RXCHAIN +#define CUSTOM_RXCHAIN 0 +#endif + +DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); +DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); +DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); +DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); + +#define DMA_ALIGN_MASK 0x03 +#define MMC_SDIO_ABORT_RETRY_LIMIT 5 + +int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); + +static int +sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) +{ + int err_ret; + uint32 fbraddr; + uint8 func; + + sd_trace(("%s\n", __FUNCTION__)); + + /* Get the Card's common CIS address */ + sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); + sd->func_cis_ptr[0] = sd->com_cis_ptr; + sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); + + /* Get the Card's function CIS (for each function) */ + for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; + func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { + sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); + sd_info(("%s: Function %d CIS Ptr = 0x%x\n", + __FUNCTION__, func, sd->func_cis_ptr[func])); + } + + sd->func_cis_ptr[0] = sd->com_cis_ptr; + sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); + + /* Enable Function 1 */ + sdio_claim_host(sd->func[1]); + err_ret = sdio_enable_func(sd->func[1]); + sdio_release_host(sd->func[1]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret)); + } + + return FALSE; +} + +/* + * Public entry points & extern's + */ +extern sdioh_info_t * +sdioh_attach(osl_t *osh, struct sdio_func *func) +{ + sdioh_info_t *sd = NULL; + int err_ret; + + sd_trace(("%s\n", __FUNCTION__)); + + if (func == NULL) { + sd_err(("%s: sdio function device is NULL\n", __FUNCTION__)); + return NULL; + } + + if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { + sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); + return NULL; + } + bzero((char *)sd, sizeof(sdioh_info_t)); + sd->osh = osh; + sd->fake_func0.num = 0; + sd->fake_func0.card = func->card; + sd->func[0] = &sd->fake_func0; + sd->func[1] = func->card->sdio_func[0]; + sd->func[2] = func->card->sdio_func[1]; + sd->num_funcs = 2; + sd->sd_blockmode = TRUE; + sd->use_client_ints = TRUE; + sd->client_block_size[0] = 64; + sd->use_rxchain = CUSTOM_RXCHAIN; + if (sd->func[1] == NULL || sd->func[2] == NULL) { + sd_err(("%s: func 1 or 2 is null \n", __FUNCTION__)); + goto fail; + } + sdio_set_drvdata(sd->func[1], sd); + + sdio_claim_host(sd->func[1]); + sd->client_block_size[1] = 64; + err_ret = sdio_set_block_size(sd->func[1], 64); + sdio_release_host(sd->func[1]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize(%d)\n", err_ret)); + goto fail; + } + + sdio_claim_host(sd->func[2]); + sd->client_block_size[2] = sd_f2_blocksize; + err_ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); + sdio_release_host(sd->func[2]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d(%d)\n", + sd_f2_blocksize, err_ret)); + goto fail; + } + + sdioh_sdmmc_card_enablefuncs(sd); + + sd_trace(("%s: Done\n", __FUNCTION__)); + return sd; + +fail: + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; +} + + +extern SDIOH_API_RC +sdioh_detach(osl_t *osh, sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + + if (sd) { + + /* Disable Function 2 */ + if (sd->func[2]) { + sdio_claim_host(sd->func[2]); + sdio_disable_func(sd->func[2]); + sdio_release_host(sd->func[2]); + } + + /* Disable Function 1 */ + if (sd->func[1]) { + sdio_claim_host(sd->func[1]); + sdio_disable_func(sd->func[1]); + sdio_release_host(sd->func[1]); + } + + sd->func[1] = NULL; + sd->func[2] = NULL; + + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + } + return SDIOH_API_RC_SUCCESS; +} + +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) + +extern SDIOH_API_RC +sdioh_enable_func_intr(sdioh_info_t *sd) +{ + uint8 reg; + int err; + + if (sd->func[0] == NULL) { + sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + sdio_claim_host(sd->func[0]); + reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); + if (err) { + sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); + sdio_release_host(sd->func[0]); + return SDIOH_API_RC_FAIL; + } + /* Enable F1 and F2 interrupts, clear master enable */ + reg &= ~INTR_CTL_MASTER_EN; + reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); + sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); + sdio_release_host(sd->func[0]); + + if (err) { + sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); + return SDIOH_API_RC_FAIL; + } + + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_disable_func_intr(sdioh_info_t *sd) +{ + uint8 reg; + int err; + + if (sd->func[0] == NULL) { + sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + sdio_claim_host(sd->func[0]); + reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); + if (err) { + sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); + sdio_release_host(sd->func[0]); + return SDIOH_API_RC_FAIL; + } + reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); + /* Disable master interrupt with the last function interrupt */ + if (!(reg & 0xFE)) + reg = 0; + sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); + sdio_release_host(sd->func[0]); + + if (err) { + sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); + return SDIOH_API_RC_FAIL; + } + + return SDIOH_API_RC_SUCCESS; +} +#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ + +/* Configure callback to client when we recieve client interrupt */ +extern SDIOH_API_RC +sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + if (fn == NULL) { + sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } +#if !defined(OOB_INTR_ONLY) + sd->intr_handler = fn; + sd->intr_handler_arg = argh; + sd->intr_handler_valid = TRUE; + + /* register and unmask irq */ + if (sd->func[2]) { + sdio_claim_host(sd->func[2]); + sdio_claim_irq(sd->func[2], IRQHandlerF2); + sdio_release_host(sd->func[2]); + } + + if (sd->func[1]) { + sdio_claim_host(sd->func[1]); + sdio_claim_irq(sd->func[1], IRQHandler); + sdio_release_host(sd->func[1]); + } +#elif defined(HW_OOB) + sdioh_enable_func_intr(sd); +#endif /* !defined(OOB_INTR_ONLY) */ + + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_deregister(sdioh_info_t *sd) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + +#if !defined(OOB_INTR_ONLY) + if (sd->func[1]) { + /* register and unmask irq */ + sdio_claim_host(sd->func[1]); + sdio_release_irq(sd->func[1]); + sdio_release_host(sd->func[1]); + } + + if (sd->func[2]) { + /* Claim host controller F2 */ + sdio_claim_host(sd->func[2]); + sdio_release_irq(sd->func[2]); + /* Release host controller F2 */ + sdio_release_host(sd->func[2]); + } + + sd->intr_handler_valid = FALSE; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; +#elif defined(HW_OOB) + sdioh_disable_func_intr(sd); +#endif /* !defined(OOB_INTR_ONLY) */ + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + *onoff = sd->client_intr_enabled; + return SDIOH_API_RC_SUCCESS; +} + +#if defined(DHD_DEBUG) +extern bool +sdioh_interrupt_pending(sdioh_info_t *sd) +{ + return (0); +} +#endif + +uint +sdioh_query_iofnum(sdioh_info_t *sd) +{ + return sd->num_funcs; +} + +/* IOVar table */ +enum { + IOV_MSGLEVEL = 1, + IOV_BLOCKMODE, + IOV_BLOCKSIZE, + IOV_DMA, + IOV_USEINTS, + IOV_NUMINTS, + IOV_NUMLOCALINTS, + IOV_HOSTREG, + IOV_DEVREG, + IOV_DIVISOR, + IOV_SDMODE, + IOV_HISPEED, + IOV_HCIREGS, + IOV_POWER, + IOV_CLOCK, + IOV_RXCHAIN +}; + +const bcm_iovar_t sdioh_iovars[] = { + {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, + {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, + {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ + {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, + {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, + {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, + {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, + {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, + {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, + {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, + {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, + {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 }, + {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +int +sdioh_iovar_op(sdioh_info_t *si, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + int32 int_val = 0; + bool bool_val; + uint32 actionid; + + ASSERT(name); + ASSERT(len >= 0); + + /* Get must have return space; Set does not take qualifiers */ + ASSERT(set || (arg && len)); + ASSERT(!set || (!params && !plen)); + + sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); + + if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { + bcmerror = BCME_UNSUPPORTED; + goto exit; + } + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) + goto exit; + + /* Set up params so get and set can share the convenience variables */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + val_size = sizeof(int); + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + BCM_REFERENCE(bool_val); + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + switch (actionid) { + case IOV_GVAL(IOV_MSGLEVEL): + int_val = (int32)sd_msglevel; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MSGLEVEL): + sd_msglevel = int_val; + break; + + case IOV_GVAL(IOV_BLOCKMODE): + int_val = (int32)si->sd_blockmode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_BLOCKMODE): + si->sd_blockmode = (bool)int_val; + /* Haven't figured out how to make non-block mode with DMA */ + break; + + case IOV_GVAL(IOV_BLOCKSIZE): + if ((uint32)int_val > si->num_funcs) { + bcmerror = BCME_BADARG; + break; + } + int_val = (int32)si->client_block_size[int_val]; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_BLOCKSIZE): + { + uint func = ((uint32)int_val >> 16); + uint blksize = (uint16)int_val; + uint maxsize; + + if (func > si->num_funcs) { + bcmerror = BCME_BADARG; + break; + } + + switch (func) { + case 0: maxsize = 32; break; + case 1: maxsize = BLOCK_SIZE_4318; break; + case 2: maxsize = BLOCK_SIZE_4328; break; + default: maxsize = 0; + } + if (blksize > maxsize) { + bcmerror = BCME_BADARG; + break; + } + if (!blksize) { + blksize = maxsize; + } + + /* Now set it */ + si->client_block_size[func] = blksize; + + break; + } + + case IOV_GVAL(IOV_RXCHAIN): + int_val = (int32)si->use_rxchain; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_DMA): + int_val = (int32)si->sd_use_dma; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DMA): + si->sd_use_dma = (bool)int_val; + break; + + case IOV_GVAL(IOV_USEINTS): + int_val = (int32)si->use_client_ints; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_USEINTS): + si->use_client_ints = (bool)int_val; + if (si->use_client_ints) + si->intmask |= CLIENT_INTR; + else + si->intmask &= ~CLIENT_INTR; + + break; + + case IOV_GVAL(IOV_DIVISOR): + int_val = (uint32)sd_divisor; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DIVISOR): + sd_divisor = int_val; + break; + + case IOV_GVAL(IOV_POWER): + int_val = (uint32)sd_power; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_POWER): + sd_power = int_val; + break; + + case IOV_GVAL(IOV_CLOCK): + int_val = (uint32)sd_clock; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_CLOCK): + sd_clock = int_val; + break; + + case IOV_GVAL(IOV_SDMODE): + int_val = (uint32)sd_sdmode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDMODE): + sd_sdmode = int_val; + break; + + case IOV_GVAL(IOV_HISPEED): + int_val = (uint32)sd_hiok; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_HISPEED): + sd_hiok = int_val; + break; + + case IOV_GVAL(IOV_NUMINTS): + int_val = (int32)si->intrcount; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_NUMLOCALINTS): + int_val = (int32)0; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_HOSTREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + + if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { + sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); + bcmerror = BCME_BADARG; + break; + } + + sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__, + (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), + sd_ptr->offset)); + if (sd_ptr->offset & 1) + int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */ + else if (sd_ptr->offset & 2) + int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */ + else + int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */ + + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_HOSTREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + + if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { + sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); + bcmerror = BCME_BADARG; + break; + } + + sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value, + (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), + sd_ptr->offset)); + break; + } + + case IOV_GVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data = 0; + + if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + + int_val = (int)data; + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data = (uint8)sd_ptr->value; + + if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + } + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } +exit: + + return bcmerror; +} + +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) + +SDIOH_API_RC +sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) +{ + SDIOH_API_RC status; + uint8 data; + + if (enable) + data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; + else + data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ + + status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); + return status; +} +#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ + +extern SDIOH_API_RC +sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + SDIOH_API_RC status; + /* No lock needed since sdioh_request_byte does locking */ + status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + /* No lock needed since sdioh_request_byte does locking */ + SDIOH_API_RC status; + status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); + return status; +} + +static int +sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) +{ + /* read 24 bits and return valid 17 bit addr */ + int i; + uint32 scratch, regdata; + uint8 *ptr = (uint8 *)&scratch; + for (i = 0; i < 3; i++) { + if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) + sd_err(("%s: Can't read!\n", __FUNCTION__)); + + *ptr++ = (uint8) regdata; + regaddr++; + } + + /* Only the lower 17-bits are valid */ + scratch = ltoh32(scratch); + scratch &= 0x0001FFFF; + return (scratch); +} + +extern SDIOH_API_RC +sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) +{ + uint32 count; + int offset; + uint32 foo; + uint8 *cis = cisd; + + sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); + + if (!sd->func_cis_ptr[func]) { + bzero(cis, length); + sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); + return SDIOH_API_RC_FAIL; + } + + sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); + + for (count = 0; count < length; count++) { + offset = sd->func_cis_ptr[func] + count; + if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { + sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + *cis = (uint8)(foo & 0xff); + cis++; + } + + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) +{ + int err_ret = 0; +#if defined(MMC_SDIO_ABORT) + int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; +#endif + + sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); + + DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); + DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); + if(rw) { /* CMD52 Write */ + if (func == 0) { + /* Can only directly write to some F0 registers. Handle F2 enable + * as a special case. + */ + if (regaddr == SDIOD_CCCR_IOEN) { + if (sd->func[2]) { + sdio_claim_host(sd->func[2]); + if (*byte & SDIO_FUNC_ENABLE_2) { + /* Enable Function 2 */ + err_ret = sdio_enable_func(sd->func[2]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: enable F2 failed:%d", + err_ret)); + } + } else { + /* Disable Function 2 */ + err_ret = sdio_disable_func(sd->func[2]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d", + err_ret)); + } + } + sdio_release_host(sd->func[2]); + } + } +#if defined(MMC_SDIO_ABORT) + /* to allow abort command through F1 */ + else if (regaddr == SDIOD_CCCR_IOABORT) { + while (sdio_abort_retry--) { + if (sd->func[func]) { + sdio_claim_host(sd->func[func]); + /* + * this sdio_f0_writeb() can be replaced with + * another api depending upon MMC driver change. + * As of this time, this is temporaray one + */ + sdio_writeb(sd->func[func], + *byte, regaddr, &err_ret); + sdio_release_host(sd->func[func]); + } + if (!err_ret) + break; + } + } +#endif /* MMC_SDIO_ABORT */ + else if (regaddr < 0xF0) { + sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); + } else { + /* Claim host controller, perform F0 write, and release */ + if (sd->func[func]) { + sdio_claim_host(sd->func[func]); + sdio_f0_writeb(sd->func[func], + *byte, regaddr, &err_ret); + sdio_release_host(sd->func[func]); + } + } + } else { + /* Claim host controller, perform Fn write, and release */ + if (sd->func[func]) { + sdio_claim_host(sd->func[func]); + sdio_writeb(sd->func[func], *byte, regaddr, &err_ret); + sdio_release_host(sd->func[func]); + } + } + } else { /* CMD52 Read */ + /* Claim host controller, perform Fn read, and release */ + if (sd->func[func]) { + sdio_claim_host(sd->func[func]); + if (func == 0) { + *byte = sdio_f0_readb(sd->func[func], regaddr, &err_ret); + } else { + *byte = sdio_readb(sd->func[func], regaddr, &err_ret); + } + sdio_release_host(sd->func[func]); + } + } + + if (err_ret) { + if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ))) { + } else { + sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", + rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); + } + } + + return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + +extern SDIOH_API_RC +sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, + uint32 *word, uint nbytes) +{ + int err_ret = SDIOH_API_RC_FAIL; +#if defined(MMC_SDIO_ABORT) + int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; +#endif + + if (func == 0) { + sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", + __FUNCTION__, cmd_type, rw, func, addr, nbytes)); + + DHD_PM_RESUME_WAIT(sdioh_request_word_wait); + DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); + /* Claim host controller */ + sdio_claim_host(sd->func[func]); + + if(rw) { /* CMD52 Write */ + if (nbytes == 4) { + sdio_writel(sd->func[func], *word, addr, &err_ret); + } else if (nbytes == 2) { + sdio_writew(sd->func[func], (*word & 0xFFFF), addr, &err_ret); + } else { + sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); + } + } else { /* CMD52 Read */ + if (nbytes == 4) { + *word = sdio_readl(sd->func[func], addr, &err_ret); + } else if (nbytes == 2) { + *word = sdio_readw(sd->func[func], addr, &err_ret) & 0xFFFF; + } else { + sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); + } + } + + /* Release host controller */ + sdio_release_host(sd->func[func]); + + if (err_ret) { +#if defined(MMC_SDIO_ABORT) + /* Any error on CMD53 transaction should abort that function using function 0. */ + while (sdio_abort_retry--) { + if (sd->func[0]) { + sdio_claim_host(sd->func[0]); + /* + * this sdio_f0_writeb() can be replaced with another api + * depending upon MMC driver change. + * As of this time, this is temporaray one + */ + sdio_writeb(sd->func[0], + func, SDIOD_CCCR_IOABORT, &err_ret); + sdio_release_host(sd->func[0]); + } + if (!err_ret) + break; + } + if (err_ret) +#endif /* MMC_SDIO_ABORT */ + { + sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x", + rw ? "Write" : "Read", err_ret)); + } + } + + return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + +static SDIOH_API_RC +sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func, + uint addr, void *pkt) +{ + bool fifo = (fix_inc == SDIOH_DATA_FIX); + int err_ret = 0; + void *pnext; + uint ttl_len, pkt_offset; + uint blk_num; + uint blk_size; + uint max_blk_count; + uint max_req_size; + struct mmc_request mmc_req; + struct mmc_command mmc_cmd; + struct mmc_data mmc_dat; + uint32 sg_count; + struct sdio_func *sdio_func = sd->func[func]; + struct mmc_host *host = sdio_func->card->host; + + sd_trace(("%s: Enter\n", __FUNCTION__)); + ASSERT(pkt); + DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); + DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); + + blk_size = sd->client_block_size[func]; + max_blk_count = min(host->max_blk_count, (uint)MAX_IO_RW_EXTENDED_BLK); + max_req_size = min(max_blk_count * blk_size, host->max_req_size); + + pkt_offset = 0; + pnext = pkt; + + while (pnext != NULL) { + ttl_len = 0; + sg_count = 0; + memset(&mmc_req, 0, sizeof(struct mmc_request)); + memset(&mmc_cmd, 0, sizeof(struct mmc_command)); + memset(&mmc_dat, 0, sizeof(struct mmc_data)); + sg_init_table(sd->sg_list, ARRAYSIZE(sd->sg_list)); + + /* Set up scatter-gather DMA descriptors. this loop is to find out the max + * data we can transfer with one command 53. blocks per command is limited by + * host max_req_size and 9-bit max block number. when the total length of this + * packet chain is bigger than max_req_size, use multiple SD_IO_RW_EXTENDED + * commands (each transfer is still block aligned) + */ + while (pnext != NULL && ttl_len < max_req_size) { + int pkt_len; + int sg_data_size; + uint8 *pdata = (uint8*)PKTDATA(sd->osh, pnext); + + ASSERT(pdata != NULL); + pkt_len = PKTLEN(sd->osh, pnext); + sd_trace(("%s[%d] data=%p, len=%d\n", __FUNCTION__, write, pdata, pkt_len)); + /* sg_count is unlikely larger than the array size, and this is + * NOT something we can handle here, but in case it happens, PLEASE put + * a restriction on max tx/glom count (based on host->max_segs). + */ + if (sg_count >= ARRAYSIZE(sd->sg_list)) { + sd_err(("%s: sg list entries exceed limit\n", __FUNCTION__)); + return (SDIOH_API_RC_FAIL); + } + pdata += pkt_offset; + + sg_data_size = pkt_len - pkt_offset; + if (sg_data_size > max_req_size - ttl_len) + sg_data_size = max_req_size - ttl_len; + /* some platforms put a restriction on the data size of each scatter-gather + * DMA descriptor, use multiple sg buffers when xfer_size is bigger than + * max_seg_size + */ + if (sg_data_size > host->max_seg_size) + sg_data_size = host->max_seg_size; + sg_set_buf(&sd->sg_list[sg_count++], pdata, sg_data_size); + + ttl_len += sg_data_size; + pkt_offset += sg_data_size; + if (pkt_offset == pkt_len) { + pnext = PKTNEXT(sd->osh, pnext); + pkt_offset = 0; + } + } + + if (ttl_len % blk_size != 0) { + sd_err(("%s, data length %d not aligned to block size %d\n", + __FUNCTION__, ttl_len, blk_size)); + return SDIOH_API_RC_FAIL; + } + blk_num = ttl_len / blk_size; + mmc_dat.sg = sd->sg_list; + mmc_dat.sg_len = sg_count; + mmc_dat.blksz = blk_size; + mmc_dat.blocks = blk_num; + mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ + mmc_cmd.arg = write ? 1<<31 : 0; + mmc_cmd.arg |= (func & 0x7) << 28; + mmc_cmd.arg |= 1<<27; + mmc_cmd.arg |= fifo ? 0 : 1<<26; + mmc_cmd.arg |= (addr & 0x1FFFF) << 9; + mmc_cmd.arg |= blk_num & 0x1FF; + mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; + mmc_req.cmd = &mmc_cmd; + mmc_req.data = &mmc_dat; + if (!fifo) + addr += ttl_len; + + sdio_claim_host(sdio_func); + mmc_set_data_timeout(&mmc_dat, sdio_func->card); + mmc_wait_for_req(host, &mmc_req); + sdio_release_host(sdio_func); + + err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; + if (0 != err_ret) { + sd_err(("%s:CMD53 %s failed with code %d\n", + __FUNCTION__, write ? "write" : "read", err_ret)); + return SDIOH_API_RC_FAIL; + } + } + + sd_trace(("%s: Exit\n", __FUNCTION__)); + return SDIOH_API_RC_SUCCESS; +} + +static SDIOH_API_RC +sdioh_buffer_tofrom_bus(sdioh_info_t *sd, uint fix_inc, uint write, uint func, + uint addr, uint8 *buf, uint len) +{ + bool fifo = (fix_inc == SDIOH_DATA_FIX); + int err_ret = 0; + + sd_trace(("%s: Enter\n", __FUNCTION__)); + ASSERT(buf); + + /* NOTE: + * For all writes, each packet length is aligned to 32 (or 4) + * bytes in dhdsdio_txpkt_preprocess, and for glom the last packet length + * is aligned to block boundary. If you want to align each packet to + * a custom size, please do it in dhdsdio_txpkt_preprocess, NOT here + * + * For reads, the alignment is doen in sdioh_request_buffer. + * + */ + sdio_claim_host(sd->func[func]); + + if ((write) && (!fifo)) + err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); + else if (write) + err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); + else if (fifo) + err_ret = sdio_readsb(sd->func[func], buf, addr, len); + else + err_ret = sdio_memcpy_fromio(sd->func[func], buf, addr, len); + + sdio_release_host(sd->func[func]); + + if (err_ret) + sd_err(("%s: %s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=%d\n", __FUNCTION__, + (write) ? "TX" : "RX", buf, addr, len, err_ret)); + else + sd_trace(("%s: %s xfr'd %p, addr=0x%05x, len=%d\n", __FUNCTION__, + (write) ? "TX" : "RX", buf, addr, len)); + + sd_trace(("%s: Exit\n", __FUNCTION__)); + return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + + +/* + * 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. + * + */ +extern SDIOH_API_RC +sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, + uint addr, uint reg_width, uint buf_len, uint8 *buffer, void *pkt) +{ + SDIOH_API_RC status; + void *tmppkt; + + sd_trace(("%s: Enter\n", __FUNCTION__)); + DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); + DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); + + if (pkt) { + /* packet chain, only used for tx/rx glom, all packets length + * are aligned, total length is a block multiple + */ + if (PKTNEXT(sd->osh, pkt)) + return sdioh_request_packet_chain(sd, fix_inc, write, func, addr, pkt); + + /* non-glom mode, ignore the buffer parameter and use the packet pointer + * (this shouldn't happen) + */ + buffer = PKTDATA(sd->osh, pkt); + buf_len = PKTLEN(sd->osh, pkt); + } + + ASSERT(buffer); + + /* buffer and length are aligned, use it directly so we can avoid memory copy */ + if (((ulong)buffer & DMA_ALIGN_MASK) == 0 && (buf_len & DMA_ALIGN_MASK) == 0) + return sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, buffer, buf_len); + + sd_err(("%s: [%d] doing memory copy buf=%p, len=%d\n", + __FUNCTION__, write, buffer, buf_len)); + + /* otherwise, a memory copy is needed as the input buffer is not aligned */ + tmppkt = PKTGET_STATIC(sd->osh, buf_len + DEFAULT_SDIO_F2_BLKSIZE, write ? TRUE : FALSE); + if (tmppkt == NULL) { + sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, buf_len)); + return SDIOH_API_RC_FAIL; + } + + if (write) + bcopy(buffer, PKTDATA(sd->osh, tmppkt), buf_len); + + status = sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, + PKTDATA(sd->osh, tmppkt), ROUNDUP(buf_len, (DMA_ALIGN_MASK+1))); + + if (!write) + bcopy(PKTDATA(sd->osh, tmppkt), buffer, buf_len); + + PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE); + + return status; +} + +/* this function performs "abort" for both of host & device */ +extern int +sdioh_abort(sdioh_info_t *sd, uint func) +{ +#if defined(MMC_SDIO_ABORT) + char t_func = (char) func; +#endif /* defined(MMC_SDIO_ABORT) */ + sd_trace(("%s: Enter\n", __FUNCTION__)); + +#if defined(MMC_SDIO_ABORT) + /* issue abort cmd52 command through F1 */ + sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); +#endif /* defined(MMC_SDIO_ABORT) */ + + sd_trace(("%s: Exit\n", __FUNCTION__)); + return SDIOH_API_RC_SUCCESS; +} + +/* Reset and re-initialize the device */ +int sdioh_sdio_reset(sdioh_info_t *si) +{ + sd_trace(("%s: Enter\n", __FUNCTION__)); + sd_trace(("%s: Exit\n", __FUNCTION__)); + return SDIOH_API_RC_SUCCESS; +} + +/* Disable device interrupt */ +void +sdioh_sdmmc_devintr_off(sdioh_info_t *sd) +{ + sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); + sd->intmask &= ~CLIENT_INTR; +} + +/* Enable device interrupt */ +void +sdioh_sdmmc_devintr_on(sdioh_info_t *sd) +{ + sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); + sd->intmask |= CLIENT_INTR; +} + +/* Read client card reg */ +int +sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + + if ((func == 0) || (regsize == 1)) { + uint8 temp = 0; + + sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); + *data = temp; + *data &= 0xff; + sd_data(("%s: byte read data=0x%02x\n", + __FUNCTION__, *data)); + } else { + sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize); + if (regsize == 2) + *data &= 0xffff; + + sd_data(("%s: word read data=0x%08x\n", + __FUNCTION__, *data)); + } + + return SUCCESS; +} + +#if !defined(OOB_INTR_ONLY) +/* bcmsdh_sdmmc interrupt handler */ +static void IRQHandler(struct sdio_func *func) +{ + sdioh_info_t *sd; + + sd = sdio_get_drvdata(func); + + ASSERT(sd != NULL); + sdio_release_host(sd->func[0]); + + if (sd->use_client_ints) { + sd->intrcount++; + ASSERT(sd->intr_handler); + ASSERT(sd->intr_handler_arg); + (sd->intr_handler)(sd->intr_handler_arg); + } else { + sd_err(("bcmsdh_sdmmc: ***IRQHandler\n")); + + sd_err(("%s: Not ready for intr: enabled %d, handler %p\n", + __FUNCTION__, sd->client_intr_enabled, sd->intr_handler)); + } + + sdio_claim_host(sd->func[0]); +} + +/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ +static void IRQHandlerF2(struct sdio_func *func) +{ + sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n")); +} +#endif /* !defined(OOB_INTR_ONLY) */ + +#ifdef NOTUSED +/* Write client card reg */ +static int +sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) +{ + + if ((func == 0) || (regsize == 1)) { + uint8 temp; + + temp = data & 0xff; + sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); + sd_data(("%s: byte write data=0x%02x\n", + __FUNCTION__, data)); + } else { + if (regsize == 2) + data &= 0xffff; + + sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); + + sd_data(("%s: word write data=0x%08x\n", + __FUNCTION__, data)); + } + + return SUCCESS; +} +#endif /* NOTUSED */ + +int +sdioh_start(sdioh_info_t *sd, int stage) +{ + int ret; + + if (!sd) { + sd_err(("%s Failed, sd is NULL\n", __FUNCTION__)); + return (0); + } + + /* Need to do this stages as we can't enable the interrupt till + downloading of the firmware is complete, other wise polling + sdio access will come in way + */ + if (sd->func[0]) { + if (stage == 0) { + /* Since the power to the chip is killed, we will have + re enumerate the device again. Set the block size + and enable the fucntion 1 for in preparation for + downloading the code + */ + /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux + 2.6.27. The implementation prior to that is buggy, and needs broadcom's + patch for it + */ + if ((ret = sdio_reset_comm(sd->func[0]->card))) { + sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); + return ret; + } + else { + sd->num_funcs = 2; + sd->sd_blockmode = TRUE; + sd->use_client_ints = TRUE; + sd->client_block_size[0] = 64; + + if (sd->func[1]) { + /* Claim host controller */ + sdio_claim_host(sd->func[1]); + + sd->client_block_size[1] = 64; + ret = sdio_set_block_size(sd->func[1], 64); + if (ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 " + "blocksize(%d)\n", ret)); + } + + /* Release host controller F1 */ + sdio_release_host(sd->func[1]); + } + + if (sd->func[2]) { + /* Claim host controller F2 */ + sdio_claim_host(sd->func[2]); + + sd->client_block_size[2] = sd_f2_blocksize; + ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); + if (ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F2 " + "blocksize to %d(%d)\n", sd_f2_blocksize, ret)); + } + + /* Release host controller F2 */ + sdio_release_host(sd->func[2]); + } + + sdioh_sdmmc_card_enablefuncs(sd); + } + } else { +#if !defined(OOB_INTR_ONLY) + sdio_claim_host(sd->func[0]); + if (sd->func[2]) + sdio_claim_irq(sd->func[2], IRQHandlerF2); + if (sd->func[1]) + sdio_claim_irq(sd->func[1], IRQHandler); + sdio_release_host(sd->func[0]); +#else /* defined(OOB_INTR_ONLY) */ +#if defined(HW_OOB) + sdioh_enable_func_intr(sd); +#endif + bcmsdh_oob_intr_set(sd->bcmsdh, TRUE); +#endif /* !defined(OOB_INTR_ONLY) */ + } + } + else + sd_err(("%s Failed\n", __FUNCTION__)); + + return (0); +} + +int +sdioh_stop(sdioh_info_t *sd) +{ + /* MSM7201A Android sdio stack has bug with interrupt + So internaly within SDIO stack they are polling + which cause issue when device is turned off. So + unregister interrupt with SDIO stack to stop the + polling + */ + if (sd->func[0]) { +#if !defined(OOB_INTR_ONLY) + sdio_claim_host(sd->func[0]); + if (sd->func[1]) + sdio_release_irq(sd->func[1]); + if (sd->func[2]) + sdio_release_irq(sd->func[2]); + sdio_release_host(sd->func[0]); +#else /* defined(OOB_INTR_ONLY) */ +#if defined(HW_OOB) + sdioh_disable_func_intr(sd); +#endif + bcmsdh_oob_intr_set(sd->bcmsdh, FALSE); +#endif /* !defined(OOB_INTR_ONLY) */ + } + else + sd_err(("%s Failed\n", __FUNCTION__)); + return (0); +} + +int +sdioh_waitlockfree(sdioh_info_t *sd) +{ + return (1); +} + + +SDIOH_API_RC +sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) +{ + return SDIOH_API_RC_FAIL; +} + +SDIOH_API_RC +sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) +{ + return SDIOH_API_RC_FAIL; +} + +bool +sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) +{ + return FALSE; +} + +SDIOH_API_RC +sdioh_gpio_init(sdioh_info_t *sd) +{ + return SDIOH_API_RC_FAIL; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc_linux.c new file mode 100644 index 000000000000..9753e2c6981a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc_linux.c @@ -0,0 +1,387 @@ +/* + * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh_sdmmc_linux.c 434777 2013-11-07 09:30:27Z $ + */ + +#include +#include +#include /* SDIO Device and Protocol Specs */ +#include /* bcmsdh to/from specific controller APIs */ +#include /* to get msglevel bit values */ + +#include /* request_irq() */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(SDIO_VENDOR_ID_BROADCOM) +#define SDIO_VENDOR_ID_BROADCOM 0x02d0 +#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ + +#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 + +#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) +#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4325) +#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4329) +#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) +#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) +#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) +#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4324) +#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) +#define SDIO_DEVICE_ID_BROADCOM_43239 43239 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ + +extern void wl_cfg80211_set_parent_dev(void *dev); +extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); +extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); +extern void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, + uint bus_num, uint slot_num); +extern int bcmsdh_remove(bcmsdh_info_t *bcmsdh); + +int sdio_function_init(void); +void sdio_function_cleanup(void); + +#define DESCRIPTION "bcmsdh_sdmmc Driver" +#define AUTHOR "Broadcom Corporation" + +/* module param defaults */ +static int clockoverride = 0; + +module_param(clockoverride, int, 0644); +MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); + +/* Maximum number of bcmsdh_sdmmc devices supported by driver */ +#define BCMSDH_SDMMC_MAX_DEVICES 1 + +extern volatile bool dhd_mmc_suspend; + +static int sdioh_probe(struct sdio_func *func) +{ + int host_idx = func->card->host->index; + uint32 rca = func->card->rca; + wifi_adapter_info_t *adapter; + osl_t *osh = NULL; + sdioh_info_t *sdioh = NULL; + + sd_err(("bus num (host idx)=%d, slot num (rca)=%d\n", host_idx, rca)); + adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca); + if (adapter != NULL) + sd_err(("found adapter info '%s'\n", adapter->name)); + else + sd_err(("can't find adapter info for this chip\n")); + +#ifdef WL_CFG80211 + wl_cfg80211_set_parent_dev(&func->dev); +#endif + + /* allocate SDIO Host Controller state info */ + osh = osl_attach(&func->dev, SDIO_BUS, TRUE); + if (osh == NULL) { + sd_err(("%s: osl_attach failed\n", __FUNCTION__)); + goto fail; + } + osl_static_mem_init(osh, adapter); + sdioh = sdioh_attach(osh, func); + if (sdioh == NULL) { + sd_err(("%s: sdioh_attach failed\n", __FUNCTION__)); + goto fail; + } + sdioh->bcmsdh = bcmsdh_probe(osh, &func->dev, sdioh, adapter, SDIO_BUS, host_idx, rca); + if (sdioh->bcmsdh == NULL) { + sd_err(("%s: bcmsdh_probe failed\n", __FUNCTION__)); + goto fail; + } + + sdio_set_drvdata(func, sdioh); + return 0; + +fail: + if (sdioh != NULL) + sdioh_detach(osh, sdioh); + if (osh != NULL) + osl_detach(osh); + return -ENOMEM; +} + +static void sdioh_remove(struct sdio_func *func) +{ + sdioh_info_t *sdioh; + osl_t *osh; + + sdioh = sdio_get_drvdata(func); + if (sdioh == NULL) { + sd_err(("%s: error, no sdioh handler found\n", __FUNCTION__)); + return; + } + + osh = sdioh->osh; + bcmsdh_remove(sdioh->bcmsdh); + sdioh_detach(osh, sdioh); + osl_detach(osh); +} + +static int bcmsdh_sdmmc_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret = 0; + + if (func == NULL) + return -EINVAL; + + sd_err(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); + sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); + sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); + sd_info(("sdio_device: 0x%04x\n", func->device)); + sd_info(("Function#: 0x%04x\n", func->num)); + + /* 4318 doesn't have function 2 */ + if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) + ret = sdioh_probe(func); + + return ret; +} + +static void bcmsdh_sdmmc_remove(struct sdio_func *func) +{ + if (func == NULL) { + sd_err(("%s is called with NULL SDIO function pointer\n", __FUNCTION__)); + return; + } + + sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); + sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); + sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); + sd_info(("sdio_device: 0x%04x\n", func->device)); + sd_info(("Function#: 0x%04x\n", func->num)); + + if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) + sdioh_remove(func); +} + +/* devices we support, null terminated */ +static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, + { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) +static int bcmsdh_sdmmc_suspend(struct device *pdev) +{ + int err; + sdioh_info_t *sdioh; + struct sdio_func *func = dev_to_sdio_func(pdev); + mmc_pm_flag_t sdio_flags; + + sd_err(("%s Enter\n", __FUNCTION__)); + if (func->num != 2) + return 0; + + sdioh = sdio_get_drvdata(func); + err = bcmsdh_suspend(sdioh->bcmsdh); + if (err) + return err; + + sdio_flags = sdio_get_host_pm_caps(func); + if (!(sdio_flags & MMC_PM_KEEP_POWER)) { + sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__)); + return -EINVAL; + } + + /* keep power while host suspended */ + err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (err) { + sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); + return err; + } +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE); +#endif + dhd_mmc_suspend = TRUE; + smp_mb(); + + return 0; +} + +static int bcmsdh_sdmmc_resume(struct device *pdev) +{ + sdioh_info_t *sdioh; + struct sdio_func *func = dev_to_sdio_func(pdev); + + sd_err(("%s Enter\n", __FUNCTION__)); + if (func->num != 2) + return 0; + + sdioh = sdio_get_drvdata(func); + dhd_mmc_suspend = FALSE; +#if defined(OOB_INTR_ONLY) + bcmsdh_resume(sdioh->bcmsdh); +#endif + + smp_mb(); + return 0; +} + +static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { + .suspend = bcmsdh_sdmmc_suspend, + .resume = bcmsdh_sdmmc_resume, +}; +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ + +#if defined(BCMLXSDMMC) +static struct semaphore *notify_semaphore = NULL; + +static int dummy_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + if (func && (func->num != 2)) { + return 0; + } + + if (notify_semaphore) + up(notify_semaphore); + return 0; +} + +static void dummy_remove(struct sdio_func *func) +{ +} + +static struct sdio_driver dummy_sdmmc_driver = { + .probe = dummy_probe, + .remove = dummy_remove, + .name = "dummy_sdmmc", + .id_table = bcmsdh_sdmmc_ids, + }; + +int sdio_func_reg_notify(void* semaphore) +{ + notify_semaphore = semaphore; + return sdio_register_driver(&dummy_sdmmc_driver); +} + +void sdio_func_unreg_notify(void) +{ + OSL_SLEEP(15); + sdio_unregister_driver(&dummy_sdmmc_driver); +} + +#endif /* defined(BCMLXSDMMC) */ + +static struct sdio_driver bcmsdh_sdmmc_driver = { + .probe = bcmsdh_sdmmc_probe, + .remove = bcmsdh_sdmmc_remove, + .name = "bcmsdh_sdmmc", + .id_table = bcmsdh_sdmmc_ids, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) + .drv = { + .pm = &bcmsdh_sdmmc_pm_ops, + }, +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ + }; + +struct sdos_info { + sdioh_info_t *sd; + spinlock_t lock; +}; + +/* Interrupt enable/disable */ +SDIOH_API_RC +sdioh_interrupt_set(sdioh_info_t *sd, bool enable) +{ + if (!sd) + return BCME_BADARG; + + sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); + return SDIOH_API_RC_SUCCESS; +} + +#ifdef BCMSDH_MODULE +static int __init +bcmsdh_module_init(void) +{ + int error = 0; + error = sdio_function_init(); + return error; +} + +static void __exit +bcmsdh_module_cleanup(void) +{ + sdio_function_cleanup(); +} + +module_init(bcmsdh_module_init); +module_exit(bcmsdh_module_cleanup); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(DESCRIPTION); +MODULE_AUTHOR(AUTHOR); + +#endif /* BCMSDH_MODULE */ +/* + * module init +*/ +int bcmsdh_register_client_driver(void) +{ + return sdio_register_driver(&bcmsdh_sdmmc_driver); +} + +/* + * module cleanup +*/ +void bcmsdh_unregister_client_driver(void) +{ + sdio_unregister_driver(&bcmsdh_sdmmc_driver); +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdspi_linux.c new file mode 100644 index 000000000000..5f152518cd8e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdspi_linux.c @@ -0,0 +1,249 @@ +/* + * Broadcom SPI Host Controller Driver - Linux Per-port + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdspi_linux.c 406045 2013-06-05 22:09:52Z $ + */ + +#include +#include + +#include /* bcmsdh to/from specific controller APIs */ +#include /* to get msglevel bit values */ + +#include +#include /* SDIO Device and Protocol Specs */ +#include /* request_irq(), free_irq() */ +#include +#include + +extern uint sd_crc; +module_param(sd_crc, uint, 0); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define KERNEL26 +#endif + +struct sdos_info { + sdioh_info_t *sd; + spinlock_t lock; + wait_queue_head_t intr_wait_queue; +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define BLOCKABLE() (!in_atomic()) +#else +#define BLOCKABLE() (!in_interrupt()) +#endif + +/* Interrupt handler */ +static irqreturn_t +sdspi_isr(int irq, void *dev_id +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +, struct pt_regs *ptregs +#endif +) +{ + sdioh_info_t *sd; + struct sdos_info *sdos; + bool ours; + + sd = (sdioh_info_t *)dev_id; + sd->local_intrcount++; + + if (!sd->card_init_done) { + sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq)); + return IRQ_RETVAL(FALSE); + } else { + ours = spi_check_client_intr(sd, NULL); + + /* For local interrupts, wake the waiting process */ + if (ours && sd->got_hcint) { + sdos = (struct sdos_info *)sd->sdos_info; + wake_up_interruptible(&sdos->intr_wait_queue); + } + + return IRQ_RETVAL(ours); + } +} + + +/* Register with Linux for interrupts */ +int +spi_register_irq(sdioh_info_t *sd, uint irq) +{ + sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq)); + if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) { + sd_err(("%s: request_irq() failed\n", __FUNCTION__)); + return ERROR; + } + return SUCCESS; +} + +/* Free Linux irq */ +void +spi_free_irq(uint irq, sdioh_info_t *sd) +{ + free_irq(irq, sd); +} + +/* Map Host controller registers */ +uint32 * +spi_reg_map(osl_t *osh, uintptr addr, int size) +{ + return (uint32 *)REG_MAP(addr, size); +} + +void +spi_reg_unmap(osl_t *osh, uintptr addr, int size) +{ + REG_UNMAP((void*)(uintptr)addr); +} + +int +spi_osinit(sdioh_info_t *sd) +{ + struct sdos_info *sdos; + + sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); + sd->sdos_info = (void*)sdos; + if (sdos == NULL) + return BCME_NOMEM; + + sdos->sd = sd; + spin_lock_init(&sdos->lock); + init_waitqueue_head(&sdos->intr_wait_queue); + return BCME_OK; +} + +void +spi_osfree(sdioh_info_t *sd) +{ + struct sdos_info *sdos; + ASSERT(sd && sd->sdos_info); + + sdos = (struct sdos_info *)sd->sdos_info; + MFREE(sd->osh, sdos, sizeof(struct sdos_info)); +} + +/* Interrupt enable/disable */ +SDIOH_API_RC +sdioh_interrupt_set(sdioh_info_t *sd, bool enable) +{ + ulong flags; + struct sdos_info *sdos; + + sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); + + sdos = (struct sdos_info *)sd->sdos_info; + ASSERT(sdos); + + if (!(sd->host_init_done && sd->card_init_done)) { + sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { + sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + /* Ensure atomicity for enable/disable calls */ + spin_lock_irqsave(&sdos->lock, flags); + + sd->client_intr_enabled = enable; + if (enable && !sd->lockcount) + spi_devintr_on(sd); + else + spi_devintr_off(sd); + + spin_unlock_irqrestore(&sdos->lock, flags); + + return SDIOH_API_RC_SUCCESS; +} + +/* Protect against reentrancy (disable device interrupts while executing) */ +void +spi_lock(sdioh_info_t *sd) +{ + ulong flags; + struct sdos_info *sdos; + + sdos = (struct sdos_info *)sd->sdos_info; + ASSERT(sdos); + + sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount)); + + spin_lock_irqsave(&sdos->lock, flags); + if (sd->lockcount) { + sd_err(("%s: Already locked!\n", __FUNCTION__)); + ASSERT(sd->lockcount == 0); + } + spi_devintr_off(sd); + sd->lockcount++; + spin_unlock_irqrestore(&sdos->lock, flags); +} + +/* Enable client interrupt */ +void +spi_unlock(sdioh_info_t *sd) +{ + ulong flags; + struct sdos_info *sdos; + + sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled)); + ASSERT(sd->lockcount > 0); + + sdos = (struct sdos_info *)sd->sdos_info; + ASSERT(sdos); + + spin_lock_irqsave(&sdos->lock, flags); + if (--sd->lockcount == 0 && sd->client_intr_enabled) { + spi_devintr_on(sd); + } + spin_unlock_irqrestore(&sdos->lock, flags); +} + +void spi_waitbits(sdioh_info_t *sd, bool yield) +{ +#ifndef BCMSDYIELD + ASSERT(!yield); +#endif + sd_trace(("%s: yield %d canblock %d\n", + __FUNCTION__, yield, BLOCKABLE())); + + /* Clear the "interrupt happened" flag and last intrstatus */ + sd->got_hcint = FALSE; + +#ifdef BCMSDYIELD + if (yield && BLOCKABLE()) { + struct sdos_info *sdos; + sdos = (struct sdos_info *)sd->sdos_info; + /* Wait for the indication, the interrupt will be masked when the ISR fires. */ + wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint)); + } else +#endif /* BCMSDYIELD */ + { + spi_spinbits(sd); + } + +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmspibrcm.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmspibrcm.c new file mode 100644 index 000000000000..19cd1828eaf5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmspibrcm.c @@ -0,0 +1,1810 @@ +/* + * Broadcom BCMSDH to gSPI Protocol Conversion Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmspibrcm.c 373331 2012-12-07 04:46:22Z $ + */ + +#define HSMODE + +#include + +#include +#include +#include +#include +#include +#include +#include +#include /* SDIO device core hardware definitions. */ +#include + +#include /* bcmsdh to/from specific controller APIs */ +#include /* ioctl/iovars */ +#include /* SDIO Device and Protocol Specs */ + +#include + + +#include +#include + +/* these are for the older cores... for newer cores we have control for each of them */ +#define F0_RESPONSE_DELAY 16 +#define F1_RESPONSE_DELAY 16 +#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY + + +#define GSPI_F0_RESP_DELAY 0 +#define GSPI_F1_RESP_DELAY F1_RESPONSE_DELAY +#define GSPI_F2_RESP_DELAY 0 +#define GSPI_F3_RESP_DELAY 0 + +#define CMDLEN 4 + +#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE) + +/* Globals */ +#if defined(DHD_DEBUG) +uint sd_msglevel = SDH_ERROR_VAL; +#else +uint sd_msglevel = 0; +#endif + +uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ +uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ +uint sd_f2_blocksize = 64; /* Default blocksize */ + + +uint sd_divisor = 2; +uint sd_power = 1; /* Default to SD Slot powered ON */ +uint sd_clock = 1; /* Default to SD Clock turned ON */ +uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ +uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ + +uint8 spi_outbuf[SPI_MAX_PKT_LEN]; +uint8 spi_inbuf[SPI_MAX_PKT_LEN]; + +/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits + * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. + */ +#define BUF2_PKT_LEN 128 +uint8 spi_outbuf2[BUF2_PKT_LEN]; +uint8 spi_inbuf2[BUF2_PKT_LEN]; + +#define SPISWAP_WD4(x) bcmswap32(x); +#define SPISWAP_WD2(x) (bcmswap16(x & 0xffff)) | \ + (bcmswap16((x & 0xffff0000) >> 16) << 16); + +/* Prototypes */ +static bool bcmspi_test_card(sdioh_info_t *sd); +static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); +static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); +static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen); +static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 *data); +static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 data); +static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, + uint8 *data); +static int bcmspi_driver_init(sdioh_info_t *sd); +static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data); +static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, + uint32 *data); +static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); +static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); + +/* + * Public entry points & extern's + */ +extern sdioh_info_t * +sdioh_attach(osl_t *osh, void *bar0, uint irq) +{ + sdioh_info_t *sd; + + sd_trace(("%s\n", __FUNCTION__)); + if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { + sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); + return NULL; + } + bzero((char *)sd, sizeof(sdioh_info_t)); + sd->osh = osh; + if (spi_osinit(sd) != 0) { + sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; + } + + sd->bar0 = bar0; + sd->irq = irq; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; + sd->intr_handler_valid = FALSE; + + /* Set defaults */ + sd->use_client_ints = TRUE; + sd->sd_use_dma = FALSE; /* DMA Not supported */ + + /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit + * mode + */ + sd->wordlen = 2; + + + if (!spi_hw_attach(sd)) { + sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + if (bcmspi_driver_init(sd) != SUCCESS) { + sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + if (spi_register_irq(sd, irq) != SUCCESS) { + sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + sd_trace(("%s: Done\n", __FUNCTION__)); + + return sd; +} + +extern SDIOH_API_RC +sdioh_detach(osl_t *osh, sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if (sd) { + sd_err(("%s: detaching from hardware\n", __FUNCTION__)); + spi_free_irq(sd->irq, sd); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + } + return SDIOH_API_RC_SUCCESS; +} + +/* Configure callback to client when we recieve client interrupt */ +extern SDIOH_API_RC +sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); +#if !defined(OOB_INTR_ONLY) + sd->intr_handler = fn; + sd->intr_handler_arg = argh; + sd->intr_handler_valid = TRUE; +#endif /* !defined(OOB_INTR_ONLY) */ + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_deregister(sdioh_info_t *sd) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); +#if !defined(OOB_INTR_ONLY) + sd->intr_handler_valid = FALSE; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; +#endif /* !defined(OOB_INTR_ONLY) */ + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + *onoff = sd->client_intr_enabled; + return SDIOH_API_RC_SUCCESS; +} + +#if defined(DHD_DEBUG) +extern bool +sdioh_interrupt_pending(sdioh_info_t *sd) +{ + return 0; +} +#endif + +extern SDIOH_API_RC +sdioh_query_device(sdioh_info_t *sd) +{ + /* Return a BRCM ID appropriate to the dongle class */ + return (sd->num_funcs > 1) ? BCM4329_D11N_ID : BCM4318_D11G_ID; +} + +/* Provide dstatus bits of spi-transaction for dhd layers. */ +extern uint32 +sdioh_get_dstatus(sdioh_info_t *sd) +{ + return sd->card_dstatus; +} + +extern void +sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) +{ + sd->chip = chip; + sd->chiprev = chiprev; +} + +extern void +sdioh_dwordmode(sdioh_info_t *sd, bool set) +{ + uint8 reg = 0; + int status; + + if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } + + if (set) { + reg |= DWORD_PKT_LEN_EN; + sd->dwordmode = TRUE; + sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ + } else { + reg &= ~DWORD_PKT_LEN_EN; + sd->dwordmode = FALSE; + sd->client_block_size[SPI_FUNC_2] = 2048; + } + + if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } +} + + +uint +sdioh_query_iofnum(sdioh_info_t *sd) +{ + return sd->num_funcs; +} + +/* IOVar table */ +enum { + IOV_MSGLEVEL = 1, + IOV_BLOCKMODE, + IOV_BLOCKSIZE, + IOV_DMA, + IOV_USEINTS, + IOV_NUMINTS, + IOV_NUMLOCALINTS, + IOV_HOSTREG, + IOV_DEVREG, + IOV_DIVISOR, + IOV_SDMODE, + IOV_HISPEED, + IOV_HCIREGS, + IOV_POWER, + IOV_CLOCK, + IOV_SPIERRSTATS, + IOV_RESP_DELAY_ALL +}; + +const bcm_iovar_t sdioh_iovars[] = { + {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, + {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ + {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, + {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, + {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, + {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, + {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, + {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, + {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, + {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, + {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, + {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, + {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +int +sdioh_iovar_op(sdioh_info_t *si, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + int32 int_val = 0; + bool bool_val; + uint32 actionid; +/* + sdioh_regs_t *regs; +*/ + + ASSERT(name); + ASSERT(len >= 0); + + /* Get must have return space; Set does not take qualifiers */ + ASSERT(set || (arg && len)); + ASSERT(!set || (!params && !plen)); + + sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); + + if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { + bcmerror = BCME_UNSUPPORTED; + goto exit; + } + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) + goto exit; + + /* Set up params so get and set can share the convenience variables */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + val_size = sizeof(int); + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + switch (actionid) { + case IOV_GVAL(IOV_MSGLEVEL): + int_val = (int32)sd_msglevel; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MSGLEVEL): + sd_msglevel = int_val; + break; + + case IOV_GVAL(IOV_BLOCKSIZE): + if ((uint32)int_val > si->num_funcs) { + bcmerror = BCME_BADARG; + break; + } + int_val = (int32)si->client_block_size[int_val]; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_DMA): + int_val = (int32)si->sd_use_dma; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DMA): + si->sd_use_dma = (bool)int_val; + break; + + case IOV_GVAL(IOV_USEINTS): + int_val = (int32)si->use_client_ints; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_USEINTS): + break; + + case IOV_GVAL(IOV_DIVISOR): + int_val = (uint32)sd_divisor; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DIVISOR): + sd_divisor = int_val; + if (!spi_start_clock(si, (uint16)sd_divisor)) { + sd_err(("%s: set clock failed\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + } + break; + + case IOV_GVAL(IOV_POWER): + int_val = (uint32)sd_power; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_POWER): + sd_power = int_val; + break; + + case IOV_GVAL(IOV_CLOCK): + int_val = (uint32)sd_clock; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_CLOCK): + sd_clock = int_val; + break; + + case IOV_GVAL(IOV_SDMODE): + int_val = (uint32)sd_sdmode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDMODE): + sd_sdmode = int_val; + break; + + case IOV_GVAL(IOV_HISPEED): + int_val = (uint32)sd_hiok; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_HISPEED): + sd_hiok = int_val; + + if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { + sd_err(("%s: Failed changing highspeed mode to %d.\n", + __FUNCTION__, sd_hiok)); + bcmerror = BCME_ERROR; + return ERROR; + } + break; + + case IOV_GVAL(IOV_NUMINTS): + int_val = (int32)si->intrcount; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_NUMLOCALINTS): + int_val = (int32)si->local_intrcount; + bcopy(&int_val, arg, val_size); + break; + case IOV_GVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data; + + if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + + int_val = (int)data; + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data = (uint8)sd_ptr->value; + + if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + } + + + case IOV_GVAL(IOV_SPIERRSTATS): + { + bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); + break; + } + + case IOV_SVAL(IOV_SPIERRSTATS): + { + bzero(&si->spierrstats, sizeof(struct spierrstats_t)); + break; + } + + case IOV_GVAL(IOV_RESP_DELAY_ALL): + int_val = (int32)si->resp_delay_all; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RESP_DELAY_ALL): + si->resp_delay_all = (bool)int_val; + int_val = STATUS_ENABLE|INTR_WITH_STATUS; + if (si->resp_delay_all) + int_val |= RESP_DELAY_ALL; + else { + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, + F1_RESPONSE_DELAY) != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + } + + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) + != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } +exit: + + return bcmerror; +} + +extern SDIOH_API_RC +sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + SDIOH_API_RC status; + /* No lock needed since sdioh_request_byte does locking */ + status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + /* No lock needed since sdioh_request_byte does locking */ + SDIOH_API_RC status; + + if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { + uint8 dummy_data; + status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); + if (status) { + sd_err(("sdioh_cfg_read() failed.\n")); + return status; + } + } + + status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) +{ + uint32 count; + int offset; + uint32 cis_byte; + uint16 *cis = (uint16 *)cisd; + uint bar0 = SI_ENUM_BASE; + int status; + uint8 data; + + sd_trace(("%s: Func %d\n", __FUNCTION__, func)); + + spi_lock(sd); + + /* Set sb window address to 0x18000000 */ + data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); + if (status == SUCCESS) { + data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + if (status == SUCCESS) { + data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + offset = CC_SROM_OTP; /* OTP offset in chipcommon. */ + for (count = 0; count < length/2; count++) { + if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { + sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + *cis = (uint16)cis_byte; + cis++; + offset += 2; + } + + spi_unlock(sd); + + return (BCME_OK); +} + +extern SDIOH_API_RC +sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + spi_lock(sd); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + if (rw == SDIOH_READ) { + sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr)); + } else { + sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr, data)); + } + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) { + spi_unlock(sd); + return status; + } + + if (rw == SDIOH_READ) { + *byte = (uint8)data; + sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *byte)); + } + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus=0x%x\n", dstatus)); + + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, + uint32 *word, uint nbytes) +{ + int status; + + spi_lock(sd); + + if (rw == SDIOH_READ) + status = bcmspi_card_regread(sd, func, addr, nbytes, word); + else + status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); + + spi_unlock(sd); + return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + +extern SDIOH_API_RC +sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, + uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) +{ + int len; + int buflen = (int)buflen_u; + bool fifo = (fix_inc == SDIOH_DATA_FIX); + + spi_lock(sd); + + ASSERT(reg_width == 4); + ASSERT(buflen_u < (1 << 30)); + ASSERT(sd->client_block_size[func]); + + sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", + __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', + buflen_u, sd->r_cnt, sd->t_cnt, pkt)); + + /* Break buffer down into blocksize chunks. */ + while (buflen > 0) { + len = MIN(sd->client_block_size[func], buflen); + if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { + sd_err(("%s: bcmspi_card_buf %s failed\n", + __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); + spi_unlock(sd); + return SDIOH_API_RC_FAIL; + } + buffer += len; + buflen -= len; + if (!fifo) + addr += len; + } + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. + * Its main aim is to have simpler spi writes rather than recursive writes. + * e.g. When there is a need to program response delay on the fly after detecting the SPI-func + * this call will allow to program the response delay. + */ +static int +bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) +{ + uint32 cmd_arg; + uint32 datalen = 1; + uint32 hostlen; + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf2 = SPISWAP_WD4(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)spi_outbuf2 = SPISWAP_WD2(cmd_arg); + if (datalen & 0x1) + datalen++; + } else { + sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (datalen != 0) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD4(byte); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD2(byte); + } + } + + /* +4 for cmd, +4 for dstatus */ + hostlen = datalen + 8; + hostlen += (4 - (hostlen & 0x3)); + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +/* Program the response delay corresponding to the spi function */ +static int +bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) +{ + if (sd->resp_delay_all == FALSE) + return (BCME_OK); + + if (sd->prev_fun == func) + return (BCME_OK); + + if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) + return (BCME_OK); + + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); + + /* Remember function for which to avoid reprogramming resp-delay in next iteration */ + sd->prev_fun = func; + + return (BCME_OK); + +} + +#define GSPI_RESYNC_PATTERN 0x0 + +/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. + * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is + * synchronised and all queued resuests are cancelled. + */ +static int +bcmspi_resync_f1(sdioh_info_t *sd) +{ + uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + *(uint32 *)spi_outbuf2 = cmd_arg; + + /* for Write, put the data into the output buffer */ + *(uint32 *)&spi_outbuf2[CMDLEN] = data; + + /* +4 for cmd, +4 for dstatus */ + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +uint32 dstatus_count = 0; + +static int +bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) +{ + uint32 dstatus = sd->card_dstatus; + struct spierrstats_t *spierrstats = &sd->spierrstats; + int err = SUCCESS; + + sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); + + /* Store dstatus of last few gSPI transactions */ + spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; + spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; + dstatus_count++; + + if (sd->card_init_done == FALSE) + return err; + + if (dstatus & STATUS_DATA_NOT_AVAILABLE) { + spierrstats->dna++; + sd_trace(("Read data not available on F1 addr = 0x%x\n", + GFIELD(cmd_arg, SPI_REG_ADDR))); + /* Clear dna bit */ + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); + } + + if (dstatus & STATUS_UNDERFLOW) { + spierrstats->rdunderflow++; + sd_err(("FIFO underflow happened due to current F2 read command.\n")); + } + + if (dstatus & STATUS_OVERFLOW) { + spierrstats->wroverflow++; + sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); + bcmspi_resync_f1(sd); + sd_err(("Recovering from F1 FIFO overflow.\n")); + } + + if (dstatus & STATUS_F2_INTR) { + spierrstats->f2interrupt++; + sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_F3_INTR) { + spierrstats->f3interrupt++; + sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_HOST_CMD_DATA_ERR) { + spierrstats->hostcmddataerr++; + sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); + } + + if (dstatus & STATUS_F2_PKT_AVAILABLE) { + spierrstats->f2pktavailable++; + sd_trace(("Packet is available/ready in F2 TX FIFO\n")); + sd_trace(("Packet length = %d\n", sd->dwordmode ? + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); + } + + if (dstatus & STATUS_F3_PKT_AVAILABLE) { + spierrstats->f3pktavailable++; + sd_err(("Packet is available/ready in F3 TX FIFO\n")); + sd_err(("Packet length = %d\n", + (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); + } + + return err; +} + +extern int +sdioh_abort(sdioh_info_t *sd, uint func) +{ + return 0; +} + +int +sdioh_start(sdioh_info_t *sd, int stage) +{ + return SUCCESS; +} + +int +sdioh_stop(sdioh_info_t *sd) +{ + return SUCCESS; +} + +int +sdioh_waitlockfree(sdioh_info_t *sd) +{ + return SUCCESS; +} + + +/* + * Private/Static work routines + */ +static int +bcmspi_host_init(sdioh_info_t *sd) +{ + + /* Default power on mode */ + sd->sd_mode = SDIOH_MODE_SPI; + sd->polled_mode = TRUE; + sd->host_init_done = TRUE; + sd->card_init_done = FALSE; + sd->adapter_slot = 1; + + return (SUCCESS); +} + +static int +get_client_blocksize(sdioh_info_t *sd) +{ + uint32 regdata[2]; + int status; + + /* Find F1/F2/F3 max packet size */ + if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, + 8, regdata)) != SUCCESS) { + return status; + } + + sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", + regdata[0], regdata[1])); + + sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; + sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); + ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); + + sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; + sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); + ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); + + sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; + sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); + ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); + + return 0; +} + +static int +bcmspi_client_init(sdioh_info_t *sd) +{ + uint32 status_en_reg = 0; + sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); + +#ifdef HSMODE + if (!spi_start_clock(sd, (uint16)sd_divisor)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#else + /* Start at ~400KHz clock rate for initialization */ + if (!spi_start_clock(sd, 128)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* HSMODE */ + + if (!bcmspi_host_device_init_adapt(sd)) { + sd_err(("bcmspi_host_device_init_adapt failed\n")); + return ERROR; + } + + if (!bcmspi_test_card(sd)) { + sd_err(("bcmspi_test_card failed\n")); + return ERROR; + } + + sd->num_funcs = SPI_MAX_IOFUNCS; + + get_client_blocksize(sd); + + /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ + bcmspi_resync_f1(sd); + + sd->dwordmode = FALSE; + + bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); + + sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); + status_en_reg |= INTR_WITH_STATUS; + + if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, + status_en_reg & 0xff) != SUCCESS) { + sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); + return ERROR; + } + +#ifndef HSMODE + /* After configuring for High-Speed mode, set the desired clock rate. */ + if (!spi_start_clock(sd, 4)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* HSMODE */ + + /* check to see if the response delay needs to be programmed properly */ + { + uint32 f1_respdelay = 0; + bcmspi_card_regread(sd, 0, SPID_RESP_DELAY_F1, 1, &f1_respdelay); + if ((f1_respdelay == 0) || (f1_respdelay == 0xFF)) { + /* older sdiodevice core and has no separte resp delay for each of */ + sd_err(("older corerev < 4 so use the same resp delay for all funcs\n")); + sd->resp_delay_new = FALSE; + } + else { + /* older sdiodevice core and has no separte resp delay for each of */ + int ret_val; + sd->resp_delay_new = TRUE; + sd_err(("new corerev >= 4 so set the resp delay for each of the funcs\n")); + sd_trace(("resp delay for funcs f0(%d), f1(%d), f2(%d), f3(%d)\n", + GSPI_F0_RESP_DELAY, GSPI_F1_RESP_DELAY, + GSPI_F2_RESP_DELAY, GSPI_F3_RESP_DELAY)); + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F0, 1, + GSPI_F0_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F0\n", __FUNCTION__)); + return ERROR; + } + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F1, 1, + GSPI_F1_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F1\n", __FUNCTION__)); + return ERROR; + } + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F2, 1, + GSPI_F2_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); + return ERROR; + } + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F3, 1, + GSPI_F3_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); + return ERROR; + } + } + } + + + sd->card_init_done = TRUE; + + /* get the device rev to program the prop respdelays */ + + return SUCCESS; +} + +static int +bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, + 4, ®data)) != SUCCESS) + return status; + + sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); + + + if (hsmode == TRUE) { + sd_trace(("Attempting to enable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + sd_trace(("Device is already in High-Speed mode.\n")); + return status; + } else { + regdata |= HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) { + return status; + } + } + } else { + sd_trace(("Attempting to disable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + regdata &= ~HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) + return status; + } + else { + sd_trace(("Device is already in Low-Speed mode.\n")); + return status; + } + } + spi_controller_highspeed_mode(sd, hsmode); + + return TRUE; +} + +#define bcmspi_find_curr_mode(sd) { \ + sd->wordlen = 2; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd->wordlen = 4; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd_trace(("Silicon testability issue: regdata = 0x%x." \ + " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ + OSL_DELAY(100000); \ +} + +#define INIT_ADAPT_LOOP 100 + +/* Adapt clock-phase-speed-bitwidth between host and device */ +static bool +bcmspi_host_device_init_adapt(sdioh_info_t *sd) +{ + uint32 wrregdata, regdata = 0; + int status; + int i; + + /* Due to a silicon testability issue, the first command from the Host + * to the device will get corrupted (first bit will be lost). So the + * Host should poll the device with a safe read request. ie: The Host + * should try to read F0 addr 0x14 using the Fixed address mode + * (This will prevent a unintended write command to be detected by device) + */ + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + /* If device was not power-cycled it will stay in 32bit mode with + * response-delay-all bit set. Alternate the iteration so that + * read either with or without response-delay for F0 to succeed. + */ + bcmspi_find_curr_mode(sd); + sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = TRUE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = FALSE; + } + + /* Bail out, device not detected */ + if (i == INIT_ADAPT_LOOP) + return FALSE; + + /* Softreset the spid logic */ + if ((sd->dwordmode) || (sd->wordlen == 4)) { + bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); + bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); + sd_trace(("reset reg read = 0x%x\n", regdata)); + sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, + sd->wordlen, sd->resp_delay_all)); + /* Restore default state after softreset */ + sd->wordlen = 2; + sd->dwordmode = FALSE; + } + + if (sd->wordlen == 4) { + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != + SUCCESS) + return FALSE; + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", + regdata)); + sd_trace(("Spid power was left on.\n")); + } else { + sd_err(("Spid power was left on but signature read failed." + " Value read = 0x%x\n", regdata)); + return FALSE; + } + } else { + sd->wordlen = 2; + +#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ + + wrregdata = (CTRL_REG_DEFAULT); + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); + +#ifndef HSMODE + wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); + wrregdata &= ~HIGH_SPEED_MODE; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); +#endif /* HSMODE */ + + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { + sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, + ®data)) != SUCCESS) + return FALSE; + } + OSL_DELAY(1000); + } + + /* Change to host controller intr-polarity of active-low */ + wrregdata &= ~INTR_POLARITY; + sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", + wrregdata)); + /* Change to 32bit mode */ + wrregdata |= WORD_LENGTH_32; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); + + /* Change command/data packaging in 32bit LE mode */ + sd->wordlen = 4; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); + sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); + } else { + sd_err(("Stale spid reg values read as it was kept powered. Value read =" + "0x%x\n", regdata)); + return FALSE; + } + } + + + return TRUE; +} + +static bool +bcmspi_test_card(sdioh_info_t *sd) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == (TEST_RO_DATA_32BIT_LE)) + sd_trace(("32bit LE regdata = 0x%x\n", regdata)); + else { + sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); + return FALSE; + } + + +#define RW_PATTERN1 0xA0A1A2A3 +#define RW_PATTERN2 0x4B5B6B7B + + regdata = RW_PATTERN1; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN1) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN1, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + regdata = RW_PATTERN2; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN2) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN2, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + return TRUE; +} + +static int +bcmspi_driver_init(sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if ((bcmspi_host_init(sd)) != SUCCESS) { + return ERROR; + } + + if (bcmspi_client_init(sd) != SUCCESS) { + return ERROR; + } + + return SUCCESS; +} + +/* Read device reg */ +static int +bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", + __FUNCTION__, cmd_arg, func, regaddr, regsize)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +static int +bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + + int status; + uint32 cmd_arg; + uint32 dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); + + sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", + __FUNCTION__, cmd_arg, func, regaddr, regsize)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) + return status; + + sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *data)); + + bcmspi_cmd_getdstatus(sd, &dstatus); + sd_trace(("dstatus =0x%x\n", dstatus)); + return SUCCESS; +} + +/* write a device register */ +static int +bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d data=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr, regsize, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus=0x%x\n", dstatus)); + + return SUCCESS; +} + +/* write a device register - 1 byte */ +static int +bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +void +bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) +{ + *dstatus_buffer = sd->card_dstatus; +} + +/* 'data' is of type uint32 whereas other buffers are of type uint8 */ +static int +bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen) +{ + uint32 i, j; + uint8 resp_delay = 0; + int err = SUCCESS; + uint32 hostlen; + uint32 spilen = 0; + uint32 dstatus_idx = 0; + uint16 templen, buslen, len, *ptr = NULL; + + sd_trace(("spi cmd = 0x%x\n", cmd_arg)); + + if (DWORDMODE_ON) { + spilen = GFIELD(cmd_arg, SPI_LEN); + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) || + (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1)) + dstatus_idx = spilen * 3; + + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + spilen = spilen << 2; + dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0; + /* convert len to mod16 size */ + spilen = ROUNDUP(spilen, 16); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } + } + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf = SPISWAP_WD4(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)spi_outbuf = SPISWAP_WD2(cmd_arg); + if (datalen & 0x1) + datalen++; + if (datalen < 4) + datalen = ROUNDUP(datalen, 4); + } else { + sd_err(("Host is %d bit spid, could not create SPI command.\n", + 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { + /* We send len field of hw-header always a mod16 size, both from host and dongle */ + if (DWORDMODE_ON) { + if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + /* ASSERT(*ptr == ~*(ptr + 1)); */ + templen = ROUNDUP(templen, 16); + *ptr = templen; + sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1)))); + } + } + + if (datalen != 0) { + for (i = 0; i < datalen/4; i++) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = + SPISWAP_WD4(data[i]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = + SPISWAP_WD2(data[i]); + } + } + } + } + + /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ + if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 0)) { + int func = GFIELD(cmd_arg, SPI_FUNCTION); + switch (func) { + case 0: + if (sd->resp_delay_new) + resp_delay = GSPI_F0_RESP_DELAY; + else + resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; + break; + case 1: + if (sd->resp_delay_new) + resp_delay = GSPI_F1_RESP_DELAY; + else + resp_delay = F1_RESPONSE_DELAY; + break; + case 2: + if (sd->resp_delay_new) + resp_delay = GSPI_F2_RESP_DELAY; + else + resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; + break; + default: + ASSERT(0); + break; + } + /* Program response delay */ + if (sd->resp_delay_new == FALSE) + bcmspi_prog_resp_delay(sd, func, resp_delay); + } + + /* +4 for cmd and +4 for dstatus */ + hostlen = datalen + 8 + resp_delay; + hostlen += dstatus_idx; + hostlen += (4 - (hostlen & 0x3)); + spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); + + /* for Read, get the data into the input buffer */ + if (datalen != 0) { + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ + for (j = 0; j < datalen/4; j++) { + if (sd->wordlen == 4) { /* 32bit spid */ + data[j] = SPISWAP_WD4(*(uint32 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + data[j] = SPISWAP_WD2(*(uint32 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay]); + } + } + + if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + buslen = len = ~(*(ptr + 1)); + buslen = ROUNDUP(buslen, 16); + /* populate actual len in hw-header */ + if (templen == buslen) + *ptr = len; + } + } + } + + /* Restore back the len field of the hw header */ + if (DWORDMODE_ON) { + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + ptr = (uint16 *)&data[0]; + *ptr = (uint16)(~*(ptr+1)); + } + } + + dstatus_idx += (datalen + CMDLEN + resp_delay); + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf[dstatus_idx]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf[dstatus_idx]); + } else { + sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", + 8 * sd->wordlen)); + return ERROR; + } + if (sd->card_dstatus == 0xffffffff) { + sd_err(("looks like not a GSPI device or device is not powered.\n")); + } + + err = bcmspi_update_stats(sd, cmd_arg); + + return err; + +} + +static int +bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data) +{ + int status; + uint32 cmd_arg; + bool write = rw == SDIOH_READ ? 0 : 1; + uint retries = 0; + + bool enable; + uint32 spilen; + + cmd_arg = 0; + + ASSERT(nbytes); + ASSERT(nbytes <= sd->client_block_size[func]); + + if (write) sd->t_cnt++; else sd->r_cnt++; + + if (func == 2) { + /* Frame len check limited by gSPI. */ + if ((nbytes > 2000) && write) { + sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); + } + /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ + /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ + if (write) { + uint32 dstatus; + /* check F2 ready with cached one */ + bcmspi_cmd_getdstatus(sd, &dstatus); + if ((dstatus & STATUS_F2_RX_READY) == 0) { + retries = WAIT_F2RXFIFORDY; + enable = 0; + while (retries-- && !enable) { + OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); + bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, + &dstatus); + if (dstatus & STATUS_F2_RX_READY) + enable = TRUE; + } + if (!enable) { + struct spierrstats_t *spierrstats = &sd->spierrstats; + spierrstats->f2rxnotready++; + sd_err(("F2 FIFO is not ready to receive data.\n")); + return ERROR; + } + sd_trace(("No of retries on F2 ready %d\n", + (WAIT_F2RXFIFORDY - retries))); + } + } + } + + /* F2 transfers happen on 0 addr */ + addr = (func == 2) ? 0 : addr; + + /* In pio mode buffer is read using fixed address fifo in func 1 */ + if ((func == 1) && (fifo)) + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); + else + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); + + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); + spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); + if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + /* convert len to mod4 size */ + spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } else + cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); + + if ((func == 2) && (fifo == 1)) { + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + } + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, nbytes)) != SUCCESS) { + sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, + (write ? "write" : "read"))); + return status; + } + + /* gSPI expects that hw-header-len is equal to spi-command-len */ + if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { + ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); + ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); + } + + if ((nbytes > 2000) && !write) { + sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); + } + + return SUCCESS; +} + +/* Reset and re-initialize the device */ +int +sdioh_sdio_reset(sdioh_info_t *si) +{ + si->card_init_done = FALSE; + return bcmspi_client_init(si); +} + +SDIOH_API_RC +sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) +{ + return SDIOH_API_RC_FAIL; +} + +SDIOH_API_RC +sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) +{ + return SDIOH_API_RC_FAIL; +} + +bool +sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) +{ + return FALSE; +} + +SDIOH_API_RC +sdioh_gpio_init(sdioh_info_t *sd) +{ + return SDIOH_API_RC_FAIL; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmutils.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmutils.c new file mode 100644 index 000000000000..d37ada4e7495 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmutils.c @@ -0,0 +1,3066 @@ +/* + * Driver O/S-independent utility routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: bcmutils.c 701287 2017-05-24 10:33:19Z $ + */ + +#include +#include +#include +#include +#ifdef BCMDRIVER + +#include +#include + +#else /* !BCMDRIVER */ + +#include +#include +#include + +#if defined(BCMEXTSUP) +#include +#endif + +#ifndef ASSERT +#define ASSERT(exp) +#endif + +#endif /* !BCMDRIVER */ + +#include +#include +#include +#include +#include +#include +#include + + +void *_bcmutils_dummy_fn = NULL; + + + + +#ifdef BCMDRIVER + + + +/* copy a pkt buffer chain into a buffer */ +uint +pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) +{ + uint n, ret = 0; + + if (len < 0) + len = 4096; /* "infinite" */ + + /* skip 'offset' bytes */ + for (; p && offset; p = PKTNEXT(osh, p)) { + if (offset < (uint)PKTLEN(osh, p)) + break; + offset -= PKTLEN(osh, p); + } + + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = PKTNEXT(osh, p)) { + n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); + bcopy(PKTDATA(osh, p) + offset, buf, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; +} + +/* copy a buffer into a pkt buffer chain */ +uint +pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) +{ + uint n, ret = 0; + + + /* skip 'offset' bytes */ + for (; p && offset; p = PKTNEXT(osh, p)) { + if (offset < (uint)PKTLEN(osh, p)) + break; + offset -= PKTLEN(osh, p); + } + + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = PKTNEXT(osh, p)) { + n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); + bcopy(buf, PKTDATA(osh, p) + offset, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; +} + + + +/* return total length of buffer chain */ +uint BCMFASTPATH +pkttotlen(osl_t *osh, void *p) +{ + uint total; + int len; + + total = 0; + for (; p; p = PKTNEXT(osh, p)) { + len = PKTLEN(osh, p); + total += len; +#ifdef BCMLFRAG + if (BCMLFRAG_ENAB()) { + if (PKTISFRAG(osh, p)) { + total += PKTFRAGTOTLEN(osh, p); + } + } +#endif + } + + return (total); +} + +/* return the last buffer of chained pkt */ +void * +pktlast(osl_t *osh, void *p) +{ + for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) + ; + + return (p); +} + +/* count segments of a chained packet */ +uint BCMFASTPATH +pktsegcnt(osl_t *osh, void *p) +{ + uint cnt; + + for (cnt = 0; p; p = PKTNEXT(osh, p)) { + cnt++; +#ifdef BCMLFRAG + if (BCMLFRAG_ENAB()) { + if (PKTISFRAG(osh, p)) { + cnt += PKTFRAGTOTNUM(osh, p); + } + } +#endif + } + + return cnt; +} + + +/* count segments of a chained packet */ +uint BCMFASTPATH +pktsegcnt_war(osl_t *osh, void *p) +{ + uint cnt; + uint8 *pktdata; + uint len, remain, align64; + + for (cnt = 0; p; p = PKTNEXT(osh, p)) { + cnt++; + len = PKTLEN(osh, p); + if (len > 128) { + pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ + /* Check for page boundary straddle (2048B) */ + if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) + cnt++; + + align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ + align64 = (64 - align64) & 0x3f; + len -= align64; /* bytes from aligned 64B to end */ + /* if aligned to 128B, check for MOD 128 between 1 to 4B */ + remain = len % 128; + if (remain > 0 && remain <= 4) + cnt++; /* add extra seg */ + } + } + + return cnt; +} + +uint8 * BCMFASTPATH +pktdataoffset(osl_t *osh, void *p, uint offset) +{ + uint total = pkttotlen(osh, p); + uint pkt_off = 0, len = 0; + uint8 *pdata = (uint8 *) PKTDATA(osh, p); + + if (offset > total) + return NULL; + + for (; p; p = PKTNEXT(osh, p)) { + pdata = (uint8 *) PKTDATA(osh, p); + pkt_off = offset - len; + len += PKTLEN(osh, p); + if (len > offset) + break; + } + return (uint8*) (pdata+pkt_off); +} + + +/* given a offset in pdata, find the pkt seg hdr */ +void * +pktoffset(osl_t *osh, void *p, uint offset) +{ + uint total = pkttotlen(osh, p); + uint len = 0; + + if (offset > total) + return NULL; + + for (; p; p = PKTNEXT(osh, p)) { + len += PKTLEN(osh, p); + if (len > offset) + break; + } + return p; +} + +#endif /* BCMDRIVER */ + +#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) +const unsigned char bcm_ctype[] = { + + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ + _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, + _BCM_C, /* 8-15 */ + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ + _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ + _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ + _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ + _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ + _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, + _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ + _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, + _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ + _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ + _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ + _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ + _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ +}; + +ulong +bcm_strtoul(const char *cp, char **endp, uint base) +{ + ulong result, last_result = 0, value; + bool minus; + + minus = FALSE; + + while (bcm_isspace(*cp)) + cp++; + + if (cp[0] == '+') + cp++; + else if (cp[0] == '-') { + minus = TRUE; + cp++; + } + + if (base == 0) { + if (cp[0] == '0') { + if ((cp[1] == 'x') || (cp[1] == 'X')) { + base = 16; + cp = &cp[2]; + } else { + base = 8; + cp = &cp[1]; + } + } else + base = 10; + } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { + cp = &cp[2]; + } + + result = 0; + + while (bcm_isxdigit(*cp) && + (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { + result = result*base + value; + /* Detected overflow */ + if (result < last_result && !minus) + return (ulong)-1; + last_result = result; + cp++; + } + + if (minus) + result = (ulong)(-(long)result); + + if (endp) + *endp = DISCARD_QUAL(cp, char); + + return (result); +} + +int +bcm_atoi(const char *s) +{ + return (int)bcm_strtoul(s, NULL, 10); +} + +/* return pointer to location of substring 'needle' in 'haystack' */ +char * +bcmstrstr(const char *haystack, const char *needle) +{ + int len, nlen; + int i; + + if ((haystack == NULL) || (needle == NULL)) + return DISCARD_QUAL(haystack, char); + + nlen = (int)strlen(needle); + len = (int)strlen(haystack) - nlen + 1; + + for (i = 0; i < len; i++) + if (memcmp(needle, &haystack[i], nlen) == 0) + return DISCARD_QUAL(&haystack[i], char); + return (NULL); +} + +char * +bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len) +{ + for (; s_len >= substr_len; s++, s_len--) + if (strncmp(s, substr, substr_len) == 0) + return DISCARD_QUAL(s, char); + + return NULL; +} + +char * +bcmstrcat(char *dest, const char *src) +{ + char *p; + + p = dest + strlen(dest); + + while ((*p++ = *src++) != '\0') + ; + + return (dest); +} + +char * +bcmstrncat(char *dest, const char *src, uint size) +{ + char *endp; + char *p; + + p = dest + strlen(dest); + endp = p + size; + + while (p != endp && (*p++ = *src++) != '\0') + ; + + return (dest); +} + + +/**************************************************************************** +* Function: bcmstrtok +* +* Purpose: +* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), +* but allows strToken() to be used by different strings or callers at the same +* time. Each call modifies '*string' by substituting a NULL character for the +* first delimiter that is encountered, and updates 'string' to point to the char +* after the delimiter. Leading delimiters are skipped. +* +* Parameters: +* string (mod) Ptr to string ptr, updated by token. +* delimiters (in) Set of delimiter characters. +* tokdelim (out) Character that delimits the returned token. (May +* be set to NULL if token delimiter is not required). +* +* Returns: Pointer to the next token found. NULL when no more tokens are found. +***************************************************************************** +*/ +char * +bcmstrtok(char **string, const char *delimiters, char *tokdelim) +{ + unsigned char *str; + unsigned long map[8]; + int count; + char *nextoken; + + if (tokdelim != NULL) { + /* Prime the token delimiter */ + *tokdelim = '\0'; + } + + /* Clear control map */ + for (count = 0; count < 8; count++) { + map[count] = 0; + } + + /* Set bits in delimiter table */ + do { + map[*delimiters >> 5] |= (1 << (*delimiters & 31)); + } + while (*delimiters++); + + str = (unsigned char*)*string; + + /* Find beginning of token (skip over leading delimiters). Note that + * there is no token iff this loop sets str to point to the terminal + * null (*str == '\0') + */ + while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { + str++; + } + + nextoken = (char*)str; + + /* Find the end of the token. If it is not the end of the string, + * put a null there. + */ + for (; *str; str++) { + if (map[*str >> 5] & (1 << (*str & 31))) { + if (tokdelim != NULL) { + *tokdelim = *str; + } + + *str++ = '\0'; + break; + } + } + + *string = (char*)str; + + /* Determine if a token has been found. */ + if (nextoken == (char *) str) { + return NULL; + } + else { + return nextoken; + } +} + + +#define xToLower(C) \ + ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) + + +/**************************************************************************** +* Function: bcmstricmp +* +* Purpose: Compare to strings case insensitively. +* +* Parameters: s1 (in) First string to compare. +* s2 (in) Second string to compare. +* +* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if +* t1 > t2, when ignoring case sensitivity. +***************************************************************************** +*/ +int +bcmstricmp(const char *s1, const char *s2) +{ + char dc, sc; + + while (*s2 && *s1) { + dc = xToLower(*s1); + sc = xToLower(*s2); + if (dc < sc) return -1; + if (dc > sc) return 1; + s1++; + s2++; + } + + if (*s1 && !*s2) return 1; + if (!*s1 && *s2) return -1; + return 0; +} + + +/**************************************************************************** +* Function: bcmstrnicmp +* +* Purpose: Compare to strings case insensitively, upto a max of 'cnt' +* characters. +* +* Parameters: s1 (in) First string to compare. +* s2 (in) Second string to compare. +* cnt (in) Max characters to compare. +* +* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if +* t1 > t2, when ignoring case sensitivity. +***************************************************************************** +*/ +int +bcmstrnicmp(const char* s1, const char* s2, int cnt) +{ + char dc, sc; + + while (*s2 && *s1 && cnt) { + dc = xToLower(*s1); + sc = xToLower(*s2); + if (dc < sc) return -1; + if (dc > sc) return 1; + s1++; + s2++; + cnt--; + } + + if (!cnt) return 0; + if (*s1 && !*s2) return 1; + if (!*s1 && *s2) return -1; + return 0; +} + +/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ +int +bcm_ether_atoe(const char *p, struct ether_addr *ea) +{ + int i = 0; + char *ep; + + for (;;) { + ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); + p = ep; + if (!*p++ || i == 6) + break; + } + + return (i == 6); +} + +int +bcm_atoipv4(const char *p, struct ipv4_addr *ip) +{ + + int i = 0; + char *c; + for (;;) { + ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0); + if (*c++ != '.' || i == IPV4_ADDR_LEN) + break; + p = c; + } + return (i == IPV4_ADDR_LEN); +} +#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ + + +#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) +/* registry routine buffer preparation utility functions: + * parameter order is like strncpy, but returns count + * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) + */ +ulong +wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) +{ + ulong copyct = 1; + ushort i; + + if (abuflen == 0) + return 0; + + /* wbuflen is in bytes */ + wbuflen /= sizeof(ushort); + + for (i = 0; i < wbuflen; ++i) { + if (--abuflen == 0) + break; + *abuf++ = (char) *wbuf++; + ++copyct; + } + *abuf = '\0'; + + return copyct; +} +#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ + +char * +bcm_ether_ntoa(const struct ether_addr *ea, char *buf) +{ + static const char hex[] = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + const uint8 *octet = ea->octet; + char *p = buf; + int i; + + for (i = 0; i < 6; i++, octet++) { + *p++ = hex[(*octet >> 4) & 0xf]; + *p++ = hex[*octet & 0xf]; + *p++ = ':'; + } + + *(p-1) = '\0'; + + return (buf); +} + +char * +bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) +{ + snprintf(buf, 16, "%d.%d.%d.%d", + ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); + return (buf); +} + +char * +bcm_ipv6_ntoa(void *ipv6, char *buf) +{ + /* Implementing RFC 5952 Sections 4 + 5 */ + /* Not thoroughly tested */ + uint16 tmp[8]; + uint16 *a = &tmp[0]; + char *p = buf; + int i, i_max = -1, cnt = 0, cnt_max = 1; + uint8 *a4 = NULL; + memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN); + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if (a[i]) { + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + cnt = 0; + } else + cnt++; + } + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + if (i_max == 0 && + /* IPv4-translated: ::ffff:0:a.b.c.d */ + ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || + /* IPv4-mapped: ::ffff:a.b.c.d */ + (cnt_max == 5 && a[5] == 0xffff))) + a4 = (uint8*) (a + 6); + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if ((uint8*) (a + i) == a4) { + snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); + break; + } else if (i == i_max) { + *p++ = ':'; + i += cnt_max - 1; + p[0] = ':'; + p[1] = '\0'; + } else { + if (i) + *p++ = ':'; + p += snprintf(p, 8, "%x", ntoh16(a[i])); + } + } + + return buf; +} +#ifdef BCMDRIVER + +void +bcm_mdelay(uint ms) +{ + uint i; + + for (i = 0; i < ms; i++) { + OSL_DELAY(1000); + } +} + + + + + +#if defined(DHD_DEBUG) +/* pretty hex print a pkt buffer chain */ +void +prpkt(const char *msg, osl_t *osh, void *p0) +{ + void *p; + + if (msg && (msg[0] != '\0')) + printf("%s:\n", msg); + + for (p = p0; p; p = PKTNEXT(osh, p)) + prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); +} +#endif + +/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. + * Also updates the inplace vlan tag if requested. + * For debugging, it returns an indication of what it did. + */ +uint BCMFASTPATH +pktsetprio(void *pkt, bool update_vtag) +{ + struct ether_header *eh; + struct ethervlan_header *evh; + uint8 *pktdata; + int priority = 0; + int rc = 0; + + pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); + ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); + + eh = (struct ether_header *) pktdata; + + if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { + uint16 vlan_tag; + int vlan_prio, dscp_prio = 0; + + evh = (struct ethervlan_header *)eh; + + vlan_tag = ntoh16(evh->vlan_tag); + vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; + + if ((evh->ether_type == hton16(ETHER_TYPE_IP)) || + (evh->ether_type == hton16(ETHER_TYPE_IPV6))) { + uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); + uint8 tos_tc = IP_TOS46(ip_body); + dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + } + + /* DSCP priority gets precedence over 802.1P (vlan tag) */ + if (dscp_prio != 0) { + priority = dscp_prio; + rc |= PKTPRIO_VDSCP; + } else { + priority = vlan_prio; + rc |= PKTPRIO_VLAN; + } + /* + * If the DSCP priority is not the same as the VLAN priority, + * then overwrite the priority field in the vlan tag, with the + * DSCP priority value. This is required for Linux APs because + * the VLAN driver on Linux, overwrites the skb->priority field + * with the priority value in the vlan tag + */ + if (update_vtag && (priority != vlan_prio)) { + vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); + vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; + evh->vlan_tag = hton16(vlan_tag); + rc |= PKTPRIO_UPD; + } + } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) || + (eh->ether_type == hton16(ETHER_TYPE_IPV6))) { + uint8 *ip_body = pktdata + sizeof(struct ether_header); + uint8 tos_tc = IP_TOS46(ip_body); + uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; + switch (dscp) { + case DSCP_EF: + priority = PRIO_8021D_VO; + break; + case DSCP_AF31: + case DSCP_AF32: + case DSCP_AF33: + priority = PRIO_8021D_CL; + break; + case DSCP_AF21: + case DSCP_AF22: + case DSCP_AF23: + case DSCP_AF11: + case DSCP_AF12: + case DSCP_AF13: + priority = PRIO_8021D_EE; + break; + default: + priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + break; + } + + rc |= PKTPRIO_DSCP; + } + + ASSERT(priority >= 0 && priority <= MAXPRIO); + PKTSETPRIO(pkt, priority); + return (rc | priority); +} + +/* Returns TRUE and DSCP if IP header found, FALSE otherwise. + */ +bool BCMFASTPATH +pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp) +{ + struct ether_header *eh; + struct ethervlan_header *evh; + uint8 *ip_body; + bool rc = FALSE; + + /* minimum length is ether header and IP header */ + if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN) + return FALSE; + + eh = (struct ether_header *) pktdata; + + if (eh->ether_type == HTON16(ETHER_TYPE_IP)) { + ip_body = pktdata + sizeof(struct ether_header); + *dscp = IP_DSCP46(ip_body); + rc = TRUE; + } + else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) { + evh = (struct ethervlan_header *)eh; + + /* minimum length is ethervlan header and IP header */ + if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN && + evh->ether_type == HTON16(ETHER_TYPE_IP)) { + ip_body = pktdata + sizeof(struct ethervlan_header); + *dscp = IP_DSCP46(ip_body); + rc = TRUE; + } + } + + return rc; +} + +/* The 0.5KB string table is not removed by compiler even though it's unused */ + +static char bcm_undeferrstr[32]; +static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; + +/* Convert the error codes into related error strings */ +const char * +bcmerrorstr(int bcmerror) +{ + /* check if someone added a bcmerror code but forgot to add errorstring */ + ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); + + if (bcmerror > 0 || bcmerror < BCME_LAST) { + snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); + return bcm_undeferrstr; + } + + ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); + + return bcmerrorstrtable[-bcmerror]; +} + + + +/* iovar table lookup */ +/* could mandate sorted tables and do a binary search */ +const bcm_iovar_t* +bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) +{ + const bcm_iovar_t *vi; + const char *lookup_name; + + /* skip any ':' delimited option prefixes */ + lookup_name = strrchr(name, ':'); + if (lookup_name != NULL) + lookup_name++; + else + lookup_name = name; + + ASSERT(table != NULL); + + for (vi = table; vi->name; vi++) { + if (!strcmp(vi->name, lookup_name)) + return vi; + } + /* ran to end of table */ + + return NULL; /* var name not found */ +} + +int +bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) +{ + int bcmerror = 0; + + /* length check on io buf */ + switch (vi->type) { + case IOVT_BOOL: + case IOVT_INT8: + case IOVT_INT16: + case IOVT_INT32: + case IOVT_UINT8: + case IOVT_UINT16: + case IOVT_UINT32: + /* all integers are int32 sized args at the ioctl interface */ + if (len < (int)sizeof(int)) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_BUFFER: + /* buffer must meet minimum length requirement */ + if (len < vi->minlen) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_VOID: + if (!set) { + /* Cannot return nil... */ + bcmerror = BCME_UNSUPPORTED; + } else if (len) { + /* Set is an action w/o parameters */ + bcmerror = BCME_BUFTOOLONG; + } + break; + + default: + /* unknown type for length check in iovar info */ + ASSERT(0); + bcmerror = BCME_UNSUPPORTED; + } + + return bcmerror; +} + +#endif /* BCMDRIVER */ + + +uint8 * +bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst) +{ + uint8 *new_dst = dst; + bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst; + + /* dst buffer should always be valid */ + ASSERT(dst); + + /* data len must be within valid range */ + ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)); + + /* source data buffer pointer should be valid, unless datalen is 0 + * meaning no data with this TLV + */ + ASSERT((data != NULL) || (datalen == 0)); + + /* only do work if the inputs are valid + * - must have a dst to write to AND + * - datalen must be within range AND + * - the source data pointer must be non-NULL if datalen is non-zero + * (this last condition detects datalen > 0 with a NULL data pointer) + */ + if ((dst != NULL) && + ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) && + ((data != NULL) || (datalen == 0))) { + + /* write type, len fields */ + dst_tlv->id = (uint8)type; + dst_tlv->len = (uint8)datalen; + + /* if data is present, copy to the output buffer and update + * pointer to output buffer + */ + if (datalen > 0) { + + memcpy(dst_tlv->data, data, datalen); + } + + /* update the output destination poitner to point past + * the TLV written + */ + new_dst = dst + BCM_TLV_HDR_SIZE + datalen; + } + + return (new_dst); +} + +uint8 * +bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen) +{ + uint8 *new_dst = dst; + + if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) { + + /* if len + tlv hdr len is more than destlen, don't do anything + * just return the buffer untouched + */ + if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) { + + new_dst = bcm_write_tlv(type, data, datalen, dst); + } + } + + return (new_dst); +} + +uint8 * +bcm_copy_tlv(const void *src, uint8 *dst) +{ + uint8 *new_dst = dst; + const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; + uint totlen; + + ASSERT(dst && src); + if (dst && src) { + + totlen = BCM_TLV_HDR_SIZE + src_tlv->len; + memcpy(dst, src_tlv, totlen); + new_dst = dst + totlen; + } + + return (new_dst); +} + + +uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen) +{ + uint8 *new_dst = dst; + const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; + + ASSERT(src); + if (src) { + if (bcm_valid_tlv(src_tlv, dst_maxlen)) { + new_dst = bcm_copy_tlv(src, dst); + } + } + + return (new_dst); +} + + +#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) +/******************************************************************************* + * crc8 + * + * Computes a crc8 over the input data using the polynomial: + * + * x^8 + x^7 +x^6 + x^4 + x^2 + 1 + * + * The caller provides the initial value (either CRC8_INIT_VALUE + * or the previous returned value) to allow for processing of + * discontiguous blocks of data. When generating the CRC the + * caller is responsible for complementing the final return value + * and inserting it into the byte stream. When checking, a final + * return value of CRC8_GOOD_VALUE indicates a valid CRC. + * + * Reference: Dallas Semiconductor Application Note 27 + * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", + * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., + * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt + * + * **************************************************************************** + */ + +static const uint8 crc8_table[256] = { + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F +}; + +#define CRC_INNER_LOOP(n, c, x) \ + (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] + +uint8 +hndcrc8( + uint8 *pdata, /* pointer to array of data to process */ + uint nbytes, /* number of input data bytes to process */ + uint8 crc /* either CRC8_INIT_VALUE or previous return value */ +) +{ + /* hard code the crc loop instead of using CRC_INNER_LOOP macro + * to avoid the undefined and unnecessary (uint8 >> 8) operation. + */ + while (nbytes-- > 0) + crc = crc8_table[(crc ^ *pdata++) & 0xff]; + + return crc; +} + +/******************************************************************************* + * crc16 + * + * Computes a crc16 over the input data using the polynomial: + * + * x^16 + x^12 +x^5 + 1 + * + * The caller provides the initial value (either CRC16_INIT_VALUE + * or the previous returned value) to allow for processing of + * discontiguous blocks of data. When generating the CRC the + * caller is responsible for complementing the final return value + * and inserting it into the byte stream. When checking, a final + * return value of CRC16_GOOD_VALUE indicates a valid CRC. + * + * Reference: Dallas Semiconductor Application Note 27 + * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", + * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., + * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt + * + * **************************************************************************** + */ + +static const uint16 crc16_table[256] = { + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, + 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, + 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, + 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, + 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, + 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, + 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, + 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, + 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, + 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, + 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, + 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, + 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, + 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, + 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, + 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, + 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, + 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, + 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, + 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, + 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, + 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, + 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, + 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, + 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, + 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, + 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, + 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, + 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, + 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, + 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, + 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 +}; + +uint16 +hndcrc16( + uint8 *pdata, /* pointer to array of data to process */ + uint nbytes, /* number of input data bytes to process */ + uint16 crc /* either CRC16_INIT_VALUE or previous return value */ +) +{ + while (nbytes-- > 0) + CRC_INNER_LOOP(16, crc, *pdata++); + return crc; +} + +static const uint32 crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +/* + * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if + * accumulating over multiple pieces. + */ +uint32 +hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) +{ + uint8 *pend; + pend = pdata + nbytes; + while (pdata < pend) + CRC_INNER_LOOP(32, crc, *pdata++); + + return crc; +} + +#ifdef notdef +#define CLEN 1499 /* CRC Length */ +#define CBUFSIZ (CLEN+4) +#define CNBUFS 5 /* # of bufs */ + +void +testcrc32(void) +{ + uint j, k, l; + uint8 *buf; + uint len[CNBUFS]; + uint32 crcr; + uint32 crc32tv[CNBUFS] = + {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; + + ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); + + /* step through all possible alignments */ + for (l = 0; l <= 4; l++) { + for (j = 0; j < CNBUFS; j++) { + len[j] = CLEN; + for (k = 0; k < len[j]; k++) + *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; + } + + for (j = 0; j < CNBUFS; j++) { + crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); + ASSERT(crcr == crc32tv[j]); + } + } + + MFREE(buf, CBUFSIZ*CNBUFS); + return; +} +#endif /* notdef */ + +/* + * Advance from the current 1-byte tag/1-byte length/variable-length value + * triple, to the next, returning a pointer to the next. + * If the current or next TLV is invalid (does not fit in given buffer length), + * NULL is returned. + * *buflen is not modified if the TLV elt parameter is invalid, or is decremented + * by the TLV parameter's length if it is valid. + */ +bcm_tlv_t * +bcm_next_tlv(bcm_tlv_t *elt, int *buflen) +{ + int len; + + /* validate current elt */ + if (!bcm_valid_tlv(elt, *buflen)) { + return NULL; + } + + /* advance to next elt */ + len = elt->len; + elt = (bcm_tlv_t*)(elt->data + len); + *buflen -= (TLV_HDR_LEN + len); + + /* validate next elt */ + if (!bcm_valid_tlv(elt, *buflen)) { + return NULL; + } + + return elt; +} + +/* + * 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 + */ +bcm_tlv_t * +bcm_parse_tlvs(void *buf, int buflen, uint key) +{ + bcm_tlv_t *elt; + int totlen; + + if ((elt = (bcm_tlv_t*)buf) == NULL) { + return NULL; + } + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= TLV_HDR_LEN) { + int len = elt->len; + + /* validate remaining totlen */ + if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { + + return (elt); + } + + elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + + return NULL; +} + +/* + * 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 + * return NULL if not found or length field < min_varlen + */ +bcm_tlv_t * +bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen) +{ + bcm_tlv_t * ret = bcm_parse_tlvs(buf, buflen, key); + if (ret == NULL || ret->len < min_bodylen) { + return NULL; + } + return ret; +} + +/* + * 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. Stop parsing when we see an element whose ID is greater + * than the target key. + */ +bcm_tlv_t * +bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) +{ + bcm_tlv_t *elt; + int totlen; + + elt = (bcm_tlv_t*)buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= TLV_HDR_LEN) { + uint id = elt->id; + int len = elt->len; + + /* Punt if we start seeing IDs > than target key */ + if (id > key) { + return (NULL); + } + + /* validate remaining totlen */ + if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { + return (elt); + } + + elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + return NULL; +} +#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ + +#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ + defined(DHD_DEBUG) +int +bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len) +{ + int i, slen = 0; + uint32 bit, mask; + const char *name; + mask = bd->mask; + if (len < 2 || !buf) + return 0; + + buf[0] = '\0'; + + for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) { + bit = bd->bitfield[i].bit; + if ((flags & mask) == bit) { + if (len > (int)strlen(name)) { + slen = strlen(name); + strncpy(buf, name, slen+1); + } + break; + } + } + return slen; +} + +int +bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) +{ + int i; + char* p = buf; + char hexstr[16]; + int slen = 0, nlen = 0; + uint32 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, " "); + } + + /* 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 + +/* print bytes formatted as hex to a string. return the resulting string length */ +int +bcm_format_hex(char *str, const void *bytes, int len) +{ + int i; + char *p = str; + const uint8 *src = (const uint8*)bytes; + + for (i = 0; i < len; i++) { + p += snprintf(p, 3, "%02X", *src); + src++; + } + return (int)(p - str); +} + +/* pretty hex print a contiguous buffer */ +void +prhex(const char *msg, uchar *buf, uint nbytes) +{ + char line[128], *p; + int len = sizeof(line); + int nchar; + uint i; + + if (msg && (msg[0] != '\0')) + printf("%s:\n", msg); + + p = line; + for (i = 0; i < nbytes; i++) { + if (i % 16 == 0) { + nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ + p += nchar; + len -= nchar; + } + if (len > 0) { + nchar = snprintf(p, len, "%02x ", buf[i]); + p += nchar; + len -= nchar; + } + + if (i % 16 == 15) { + printf("%s\n", line); /* flush line */ + p = line; + len = sizeof(line); + } + } + + /* flush last partial line */ + if (p != line) + printf("%s\n", line); +} + +static const char *crypto_algo_names[] = { + "NONE", + "WEP1", + "TKIP", + "WEP128", + "AES_CCM", + "AES_OCB_MSDU", + "AES_OCB_MPDU", +#ifdef BCMCCX + "CKIP", + "CKIP_MMH", + "WEP_MMH", + "NALG", +#else + "NALG", + "UNDEF", + "UNDEF", + "UNDEF", +#endif /* BCMCCX */ + "WAPI", + "PMK", + "BIP", + "AES_GCM", + "AES_CCM256", + "AES_GCM256", + "BIP_CMAC256", + "BIP_GMAC", + "BIP_GMAC256", + "UNDEF" +}; + +const char * +bcm_crypto_algo_name(uint algo) +{ + return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; +} + + +char * +bcm_chipname(uint chipid, char *buf, uint len) +{ + const char *fmt; + + fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; + snprintf(buf, len, fmt, chipid); + return buf; +} + +/* Produce a human-readable string for boardrev */ +char * +bcm_brev_str(uint32 brev, char *buf) +{ + if (brev < 0x100) + snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); + else + snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); + + return (buf); +} + +#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ + +/* dump large strings to console */ +void +printbig(char *buf) +{ + uint len, max_len; + char c; + + len = (uint)strlen(buf); + + max_len = BUFSIZE_TODUMP_ATONCE; + + while (len > max_len) { + c = buf[max_len]; + buf[max_len] = '\0'; + printf("%s", buf); + buf[max_len] = c; + + buf += max_len; + len -= max_len; + } + /* print the remaining string */ + printf("%s\n", buf); + return; +} + +/* routine to dump fields in a fileddesc structure */ +uint +bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, + char *buf, uint32 bufsize) +{ + uint filled_len; + int len; + struct fielddesc *cur_ptr; + + filled_len = 0; + cur_ptr = fielddesc_array; + + while (bufsize > 1) { + if (cur_ptr->nameandfmt == NULL) + break; + len = snprintf(buf, bufsize, cur_ptr->nameandfmt, + read_rtn(arg0, arg1, cur_ptr->offset)); + /* check for snprintf overflow or error */ + if (len < 0 || (uint32)len >= bufsize) + len = bufsize - 1; + buf += len; + bufsize -= len; + filled_len += len; + cur_ptr++; + } + return filled_len; +} + +uint +bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) +{ + uint len; + + len = (uint)strlen(name) + 1; + + if ((len + datalen) > buflen) + return 0; + + strncpy(buf, name, buflen); + + /* append data onto the end of the name string */ + if (data && datalen != 0) { + memcpy(&buf[len], data, datalen); + len += datalen; + } + + return len; +} + +/* 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 uint16. + */ + +#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 uint16 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 +}; + +uint16 +bcm_qdbm_to_mw(uint8 qdbm) +{ + uint factor = 1; + int idx = qdbm - QDBM_OFFSET; + + if (idx >= QDBM_TABLE_LEN) { + /* clamp to max uint16 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); +} + +uint8 +bcm_mw_to_qdbm(uint16 mw) +{ + uint8 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 += (uint8)offset; + + return (qdbm); +} + + +uint +bcm_bitcount(uint8 *bitmap, uint length) +{ + uint bitcount = 0, i; + uint8 tmp; + for (i = 0; i < length; i++) { + tmp = bitmap[i]; + while (tmp) { + bitcount++; + tmp &= (tmp - 1); + } + } + return bitcount; +} + +#ifdef BCMDRIVER + +/* Initialization of bcmstrbuf structure */ +void +bcm_binit(struct bcmstrbuf *b, char *buf, uint size) +{ + b->origsize = b->size = size; + b->origbuf = b->buf = buf; +} + +/* Buffer sprintf wrapper to guard against buffer overflow */ +int +bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + + r = vsnprintf(b->buf, b->size, fmt, ap); + + /* Non Ansi C99 compliant returns -1, + * Ansi compliant return r >= b->size, + * bcmstdlib returns 0, handle all + */ + /* r == 0 is also the case when strlen(fmt) is zero. + * typically the case when "" is passed as argument. + */ + if ((r == -1) || (r >= (int)b->size)) { + b->size = 0; + } else { + b->size -= r; + b->buf += r; + } + + va_end(ap); + + return r; +} + +void +bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len) +{ + int i; + + if (msg != NULL && msg[0] != '\0') + bcm_bprintf(b, "%s", msg); + for (i = 0; i < len; i ++) + bcm_bprintf(b, "%02X", buf[i]); + if (newline) + bcm_bprintf(b, "\n"); +} + +void +bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) +{ + int i; + + for (i = 0; i < num_bytes; i++) { + num[i] += amount; + if (num[i] >= amount) + break; + amount = 1; + } +} + +int +bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) +{ + int i; + + for (i = nbytes - 1; i >= 0; i--) { + if (arg1[i] != arg2[i]) + return (arg1[i] - arg2[i]); + } + return 0; +} + +void +bcm_print_bytes(const char *name, const uchar *data, int len) +{ + int i; + int per_line = 0; + + printf("%s: %d \n", name ? name : "", len); + for (i = 0; i < len; i++) { + printf("%02x ", *data++); + per_line++; + if (per_line == 16) { + per_line = 0; + printf("\n"); + } + } + printf("\n"); +} + +/* Look for vendor-specific IE with specified OUI and optional type */ +bcm_tlv_t * +bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len) +{ + bcm_tlv_t *ie; + uint8 ie_len; + + ie = (bcm_tlv_t*)tlvs; + + /* make sure we are looking at a valid IE */ + if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) { + return NULL; + } + + /* Walk through the IEs looking for an OUI match */ + do { + ie_len = ie->len; + if ((ie->id == DOT11_MNG_PROPR_ID) && + (ie_len >= (DOT11_OUI_LEN + type_len)) && + !bcmp(ie->data, voui, DOT11_OUI_LEN)) + { + /* compare optional type */ + if (type_len == 0 || + !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { + return (ie); /* a match */ + } + } + } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL); + + return NULL; +} + +#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ + defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) +#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) + +int +bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) +{ + uint i, c; + char *p = buf; + char *endp = buf + SSID_FMT_BUF_LEN; + + if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; + + for (i = 0; i < ssid_len; i++) { + c = (uint)ssid[i]; + if (c == '\\') { + *p++ = '\\'; + *p++ = '\\'; + } else if (bcm_isprint((uchar)c)) { + *p++ = (char)c; + } else { + p += snprintf(p, (endp - p), "\\x%02X", c); + } + } + *p = '\0'; + ASSERT(p < endp); + + return (int)(p - buf); +} +#endif + +#endif /* BCMDRIVER */ + +/* + * ProcessVars:Takes a buffer of "=\n" lines read from a file and ending in a NUL. + * also accepts nvram files which are already in the format of =\0\=\0 + * 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. +*/ + +unsigned int +process_nvram_vars(char *varbuf, unsigned int len) +{ + char *dp; + bool findNewline; + int column; + unsigned int buf_len, n; + unsigned int pad = 0; + + dp = varbuf; + + findNewline = FALSE; + column = 0; + + for (n = 0; n < len; n++) { + 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 = (unsigned int)(dp - varbuf); + if (buf_len % 4) { + pad = 4 - buf_len % 4; + if (pad && (buf_len + pad <= len)) { + buf_len += pad; + } + } + + while (dp < varbuf + n) + *dp++ = 0; + + return buf_len; +} + +/* calculate a * b + c */ +void +bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c) +{ +#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;} + uint32 r1, r0; + uint32 a1, a0, b1, b0, t, cc = 0; + + a1 = a >> 16; + a0 = a & 0xffff; + b1 = b >> 16; + b0 = b & 0xffff; + + r0 = a0 * b0; + FORMALIZE(r0); + + t = (a1 * b0) << 16; + FORMALIZE(t); + + r0 += t; + FORMALIZE(r0); + + t = (a0 * b1) << 16; + FORMALIZE(t); + + r0 += t; + FORMALIZE(r0); + + FORMALIZE(c); + + r0 += c; + FORMALIZE(r0); + + r0 |= (cc % 2) ? 0x80000000 : 0; + r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2); + + *r_high = r1; + *r_low = r0; +} + +/* calculate a / b */ +void +bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b) +{ + uint32 a1 = a_high, a0 = a_low, r0 = 0; + + if (b < 2) + return; + + while (a1 != 0) { + r0 += (0xffffffff / b) * a1; + bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0); + } + + r0 += a0 / b; + *r = r0; +} + +#ifndef setbit /* As in the header file */ +#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS +/* Set bit in byte array. */ +void +setbit(void *array, uint bit) +{ + ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY); +} + +/* Clear bit in byte array. */ +void +clrbit(void *array, uint bit) +{ + ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY)); +} + +/* Test if bit is set in byte array. */ +bool +isset(const void *array, uint bit) +{ + return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))); +} + +/* Test if bit is clear in byte array. */ +bool +isclr(const void *array, uint bit) +{ + return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0); +} +#endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */ +#endif /* setbit */ + +void +set_bitrange(void *array, uint start, uint end, uint maxbit) +{ + uint startbyte = start/NBBY; + uint endbyte = end/NBBY; + uint i, startbytelastbit, endbytestartbit; + + if (end >= start) { + if (endbyte - startbyte > 1) + { + startbytelastbit = (startbyte+1)*NBBY - 1; + endbytestartbit = endbyte*NBBY; + for (i = startbyte+1; i < endbyte; i++) + ((uint8 *)array)[i] = 0xFF; + for (i = start; i <= startbytelastbit; i++) + setbit(array, i); + for (i = endbytestartbit; i <= end; i++) + setbit(array, i); + } else { + for (i = start; i <= end; i++) + setbit(array, i); + } + } + else { + set_bitrange(array, start, maxbit, maxbit); + set_bitrange(array, 0, end, maxbit); + } +} + +void +bcm_bitprint32(const uint32 u32) +{ + int i; + for (i = NBITS(uint32) - 1; i >= 0; i--) { + isbitset(u32, i) ? printf("1") : printf("0"); + if ((i % NBBY) == 0) printf(" "); + } + printf("\n"); +} + +/* calculate checksum for ip header, tcp / udp header / data */ +uint16 +bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum) +{ + while (len > 1) { + sum += (buf[0] << 8) | buf[1]; + buf += 2; + len -= 2; + } + + if (len > 0) { + sum += (*buf) << 8; + } + + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16); + } + + return ((uint16)~sum); +} + +#ifdef BCMDRIVER +/* + * Hierarchical Multiword bitmap based small id allocator. + * + * Multilevel hierarchy bitmap. (maximum 2 levels) + * First hierarchy uses a multiword bitmap to identify 32bit words in the + * second hierarchy that have at least a single bit set. Each bit in a word of + * the second hierarchy represents a unique ID that may be allocated. + * + * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed. + * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word + * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs. + * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non + * non-zero bitmap word carrying at least one free ID. + * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations. + * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID + * + * Design Notes: + * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many + * bits are computed each time on allocation and deallocation, requiring 4 + * array indexed access and 3 arithmetic operations. When not defined, a runtime + * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed. + * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation. + * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may + * be used by defining BCM_MWBMAP_USE_CNTSETBITS. + * + * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array + * size is fixed. No intention to support larger than 4K indice allocation. ID + * allocators for ranges smaller than 4K will have a wastage of only 12Bytes + * with savings in not having to use an indirect access, had it been dynamically + * allocated. + */ +#ifdef DHD_PKTID_AUDIT_ENABLED +#define BCM_MWBMAP_ITEMS_MAX (16 * 1024) /* May increase to 16K */ +#else +#define BCM_MWBMAP_ITEMS_MAX (4 * 1024) /* May increase to 16K */ +#endif /* DHD_PKTID_AUDIT_ENABLED */ + +#define BCM_MWBMAP_BITS_WORD (NBITS(uint32)) +#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD) +#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD) +#define BCM_MWBMAP_SHIFT_OP (5) +#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1)) +#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP) +#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP) + +/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */ +#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl)) +#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr)) + +#if defined(BCM_MWBMAP_DEBUG) +#define BCM_MWBMAP_AUDIT(mwb) \ + do { \ + ASSERT((mwb != NULL) && \ + (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \ + bcm_mwbmap_audit(mwb); \ + } while (0) +#define MWBMAP_ASSERT(exp) ASSERT(exp) +#define MWBMAP_DBG(x) printf x +#else /* !BCM_MWBMAP_DEBUG */ +#define BCM_MWBMAP_AUDIT(mwb) do {} while (0) +#define MWBMAP_ASSERT(exp) do {} while (0) +#define MWBMAP_DBG(x) +#endif /* !BCM_MWBMAP_DEBUG */ + + +typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ + uint16 wmaps; /* Total number of words in free wd bitmap */ + uint16 imaps; /* Total number of words in free id bitmap */ + int16 ifree; /* Count of free indices. Used only in audits */ + uint16 total; /* Total indices managed by multiword bitmap */ + + void * magic; /* Audit handle parameter from user */ + + uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */ +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */ +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + + uint32 id_bitmap[0]; /* Second level bitmap */ +} bcm_mwbmap_t; + +/* Incarnate a hierarchical multiword bitmap based small index allocator. */ +struct bcm_mwbmap * +bcm_mwbmap_init(osl_t *osh, uint32 items_max) +{ + struct bcm_mwbmap * mwbmap_p; + uint32 wordix, size, words, extra; + + /* Implementation Constraint: Uses 32bit word bitmap */ + MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U); + MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U); + MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX)); + MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U); + + ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX); + + /* Determine the number of words needed in the multiword bitmap */ + extra = BCM_MWBMAP_MODOP(items_max); + words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U); + + /* Allocate runtime state of multiword bitmap */ + /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ + size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); + mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); + if (mwbmap_p == (bcm_mwbmap_t *)NULL) { + ASSERT(0); + goto error1; + } + memset(mwbmap_p, 0, size); + + /* Initialize runtime multiword bitmap state */ + mwbmap_p->imaps = (uint16)words; + mwbmap_p->ifree = (int16)items_max; + mwbmap_p->total = (uint16)items_max; + + /* Setup magic, for use in audit of handle */ + mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p); + + /* Setup the second level bitmap of free indices */ + /* Mark all indices as available */ + for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) { + mwbmap_p->id_bitmap[wordix] = (uint32)(~0U); +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD; +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + } + + /* Ensure that extra indices are tagged as un-available */ + if (extra) { /* fixup the free ids in last bitmap and wd_count */ + uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1]; + *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */ +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + } + + /* Setup the first level bitmap hierarchy */ + extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps); + words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U); + + mwbmap_p->wmaps = (uint16)words; + + for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) + mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U); + if (extra) { + uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1]; + *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ + } + + return mwbmap_p; + +error1: + return BCM_MWBMAP_INVALID_HDL; +} + +/* Release resources used by multiword bitmap based small index allocator. */ +void +bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap) + + (sizeof(uint32) * mwbmap_p->imaps)); + return; +} + +/* Allocate a unique small index using a multiword bitmap index allocator. */ +uint32 BCMFASTPATH +bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + /* Start with the first hierarchy */ + for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) { + + bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */ + + if (bitmap != 0U) { + + uint32 count, bitix, *bitmap_p; + + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + + /* clear all except trailing 1 */ + bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); + MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == + bcm_count_leading_zeros(bitmap)); + bitix = (BCM_MWBMAP_BITS_WORD - 1) + - bcm_count_leading_zeros(bitmap); /* use asm clz */ + wordix = BCM_MWBMAP_MULOP(wordix) + bitix; + + /* Clear bit if wd count is 0, without conditional branch */ +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1; +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + mwbmap_p->wd_count[wordix]--; + count = mwbmap_p->wd_count[wordix]; + MWBMAP_ASSERT(count == + (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1)); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + MWBMAP_ASSERT(count >= 0); + + /* clear wd_bitmap bit if id_map count is 0 */ + bitmap = (count == 0) << bitix; + + MWBMAP_DBG(( + "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count)); + + *bitmap_p ^= bitmap; + + /* Use bitix in the second hierarchy */ + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */ + MWBMAP_ASSERT(bitmap != 0U); + + /* clear all except trailing 1 */ + bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); + MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == + bcm_count_leading_zeros(bitmap)); + bitix = BCM_MWBMAP_MULOP(wordix) + + (BCM_MWBMAP_BITS_WORD - 1) + - bcm_count_leading_zeros(bitmap); /* use asm clz */ + + mwbmap_p->ifree--; /* decrement system wide free count */ + MWBMAP_ASSERT(mwbmap_p->ifree >= 0); + + MWBMAP_DBG(( + "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, + mwbmap_p->ifree)); + + *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */ + + return bitix; + } + } + + ASSERT(mwbmap_p->ifree == 0); + + return BCM_MWBMAP_INVALID_IDX; +} + +/* Force an index at a specified position to be in use */ +void +bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 count, wordix, bitmap, *bitmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + /* Start with second hierarchy */ + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + ASSERT((*bitmap_p & bitmap) == bitmap); + + mwbmap_p->ifree--; /* update free count */ + ASSERT(mwbmap_p->ifree >= 0); + + MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, + mwbmap_p->ifree)); + + *bitmap_p ^= bitmap; /* mark as in use */ + + /* Update first hierarchy */ + bitix = wordix; + + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + mwbmap_p->wd_count[bitix]--; + count = mwbmap_p->wd_count[bitix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + MWBMAP_ASSERT(count >= 0); + + bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix); + + MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", + BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, + (*bitmap_p) ^ bitmap, count)); + + *bitmap_p ^= bitmap; /* mark as in use */ + + return; +} + +/* Free a previously allocated index back into the multiword bitmap allocator */ +void BCMFASTPATH +bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap, *bitmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + /* Start with second level hierarchy */ + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */ + + mwbmap_p->ifree++; /* update free count */ + ASSERT(mwbmap_p->ifree <= mwbmap_p->total); + + MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, + mwbmap_p->ifree)); + + *bitmap_p |= bitmap; /* mark as available */ + + /* Now update first level hierarchy */ + + bitix = wordix; + + wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */ + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[bitix]++; +#endif + +#if defined(BCM_MWBMAP_DEBUG) + { + uint32 count; +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[bitix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + + MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD); + + MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count)); + } +#endif /* BCM_MWBMAP_DEBUG */ + + *bitmap_p |= bitmap; + + return; +} + +/* Fetch the toal number of free indices in the multiword bitmap allocator */ +uint32 +bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(mwbmap_p->ifree >= 0); + + return mwbmap_p->ifree; +} + +/* Determine whether an index is inuse or free */ +bool +bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + + return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U); +} + +/* Debug dump a multiword bitmap allocator */ +void +bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl) +{ + uint32 ix, count; + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p, + mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total); + for (ix = 0U; ix < mwbmap_p->wmaps; ix++) { + printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]); + bcm_bitprint32(mwbmap_p->wd_bitmap[ix]); + printf("\n"); + } + for (ix = 0U; ix < mwbmap_p->imaps; ix++) { +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[ix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count); + bcm_bitprint32(mwbmap_p->id_bitmap[ix]); + printf("\n"); + } + + return; +} + +/* Audit a hierarchical multiword bitmap */ +void +bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p; + + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) { + + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + + for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { + if ((*bitmap_p) & (1 << bitix)) { + idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[idmap_ix]; + ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + ASSERT(count != 0U); + free_cnt += count; + } + } + } + + ASSERT((int)free_cnt == mwbmap_p->ifree); +} +/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ + +/* Simple 16bit Id allocator using a stack implementation. */ +typedef struct id16_map { + uint16 total; /* total number of ids managed by allocator */ + uint16 start; /* start value of 16bit ids to be managed */ + uint32 failures; /* count of failures */ + void *dbg; /* debug placeholder */ + int stack_idx; /* index into stack of available ids */ + uint16 stack[0]; /* stack of 16 bit ids */ +} id16_map_t; + +#define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \ + (sizeof(uint16) * (items))) + +#if defined(BCM_DBG) + +/* Uncomment BCM_DBG_ID16 to debug double free */ +/* #define BCM_DBG_ID16 */ + +typedef struct id16_map_dbg { + uint16 total; + bool avail[0]; +} id16_map_dbg_t; +#define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \ + (sizeof(bool) * (items))) +#define ID16_MAP_MSG(x) print x +#else +#define ID16_MAP_MSG(x) +#endif /* BCM_DBG */ + +void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */ +id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16) +{ + uint16 idx, val16; + id16_map_t * id16_map; + + ASSERT(total_ids > 0); + ASSERT((start_val16 + total_ids) < ID16_INVALID); + + id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids)); + if (id16_map == NULL) { + return NULL; + } + + id16_map->total = total_ids; + id16_map->start = start_val16; + id16_map->failures = 0; + id16_map->dbg = NULL; + + /* Populate stack with 16bit id values, commencing with start_val16 */ + id16_map->stack_idx = 0; + val16 = start_val16; + + for (idx = 0; idx < total_ids; idx++, val16++) { + id16_map->stack_idx = idx; + id16_map->stack[id16_map->stack_idx] = val16; + } + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids)); + + if (id16_map->dbg) { + id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; + + id16_map_dbg->total = total_ids; + for (idx = 0; idx < total_ids; idx++) { + id16_map_dbg->avail[idx] = TRUE; + } + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + + return (void *)id16_map; +} + +void * /* Destruct an id16 allocator instance */ +id16_map_fini(osl_t *osh, void * id16_map_hndl) +{ + uint16 total_ids; + id16_map_t * id16_map; + + if (id16_map_hndl == NULL) + return NULL; + + id16_map = (id16_map_t *)id16_map_hndl; + + total_ids = id16_map->total; + ASSERT(total_ids > 0); + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + if (id16_map->dbg) { + MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids)); + id16_map->dbg = NULL; + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + + id16_map->total = 0; + MFREE(osh, id16_map, ID16_MAP_SZ(total_ids)); + + return NULL; +} + +void +id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16) +{ + uint16 idx, val16; + id16_map_t * id16_map; + + ASSERT(total_ids > 0); + ASSERT((start_val16 + total_ids) < ID16_INVALID); + + id16_map = (id16_map_t *)id16_map_hndl; + if (id16_map == NULL) { + return; + } + + id16_map->total = total_ids; + id16_map->start = start_val16; + id16_map->failures = 0; + + /* Populate stack with 16bit id values, commencing with start_val16 */ + id16_map->stack_idx = 0; + val16 = start_val16; + + for (idx = 0; idx < total_ids; idx++, val16++) { + id16_map->stack_idx = idx; + id16_map->stack[id16_map->stack_idx] = val16; + } + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + if (id16_map->dbg) { + id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; + + id16_map_dbg->total = total_ids; + for (idx = 0; idx < total_ids; idx++) { + id16_map_dbg->avail[idx] = TRUE; + } + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ +} + +uint16 BCMFASTPATH /* Allocate a unique 16bit id */ +id16_map_alloc(void * id16_map_hndl) +{ + uint16 val16; + id16_map_t * id16_map; + + ASSERT(id16_map_hndl != NULL); + + id16_map = (id16_map_t *)id16_map_hndl; + + ASSERT(id16_map->total > 0); + + if (id16_map->stack_idx < 0) { + id16_map->failures++; + return ID16_INVALID; + } + + val16 = id16_map->stack[id16_map->stack_idx]; + id16_map->stack_idx--; + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + + ASSERT(val16 < (id16_map->start + id16_map->total)); + + if (id16_map->dbg) { /* Validate val16 */ + id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; + + ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE); + id16_map_dbg->avail[val16 - id16_map->start] = FALSE; + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + + return val16; +} + + +void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */ +id16_map_free(void * id16_map_hndl, uint16 val16) +{ + id16_map_t * id16_map; + + ASSERT(id16_map_hndl != NULL); + + id16_map = (id16_map_t *)id16_map_hndl; + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + + ASSERT(val16 < (id16_map->start + id16_map->total)); + + if (id16_map->dbg) { /* Validate val16 */ + id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; + + ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE); + id16_map_dbg->avail[val16 - id16_map->start] = TRUE; + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + + if (id16_map->stack_idx >= id16_map->total) + return; + + id16_map->stack_idx++; + id16_map->stack[id16_map->stack_idx] = val16; +} + +uint32 /* Returns number of failures to allocate an unique id16 */ +id16_map_failures(void * id16_map_hndl) +{ + ASSERT(id16_map_hndl != NULL); + return ((id16_map_t *)id16_map_hndl)->failures; +} + +bool +id16_map_audit(void * id16_map_hndl) +{ + int idx; + int insane = 0; + id16_map_t * id16_map; + + ASSERT(id16_map_hndl != NULL); + + id16_map = (id16_map_t *)id16_map_hndl; + + ASSERT((id16_map->stack_idx > 0) && (id16_map->stack_idx < id16_map->total)); + for (idx = 0; idx <= id16_map->stack_idx; idx++) { + ASSERT(id16_map->stack[idx] >= id16_map->start); + ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total)); + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + if (id16_map->dbg) { + uint16 val16 = id16_map->stack[idx]; + if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) { + insane |= 1; + ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n", + id16_map_hndl, idx, val16)); + } + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + } + +#if defined(BCM_DBG) && defined(BCM_DBG_ID16) + if (id16_map->dbg) { + uint16 avail = 0; /* Audit available ids counts */ + for (idx = 0; idx < id16_map_dbg->total; idx++) { + if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE) + avail++; + } + if (avail && (avail != (id16_map->stack_idx + 1))) { + insane |= 1; + ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n", + id16_map_hndl, avail, id16_map->stack_idx)); + } + } +#endif /* BCM_DBG && BCM_DBG_ID16 */ + + return (!!insane); +} +/* END: Simple id16 allocator */ + + +#endif /* BCMDRIVER */ + +/* calculate a >> b; and returns only lower 32 bits */ +void +bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b) +{ + uint32 a1 = a_high, a0 = a_low, r0 = 0; + + if (b == 0) { + r0 = a_low; + *r = r0; + return; + } + + if (b < 32) { + a0 = a0 >> b; + a1 = a1 & ((1 << b) - 1); + a1 = a1 << (32 - b); + r0 = a0 | a1; + *r = r0; + return; + } else { + r0 = a1 >> (b - 32); + *r = r0; + return; + } + +} + +/* calculate a + b where a is a 64 bit number and b is a 32 bit number */ +void +bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset) +{ + uint32 r1_lo = *r_lo; + (*r_lo) += offset; + if (*r_lo < r1_lo) + (*r_hi) ++; +} + +/* calculate a - b where a is a 64 bit number and b is a 32 bit number */ +void +bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset) +{ + uint32 r1_lo = *r_lo; + (*r_lo) -= offset; + if (*r_lo > r1_lo) + (*r_hi) --; +} + +#ifdef DEBUG_COUNTER +#if (OSL_SYSUPTIME_SUPPORT == TRUE) +void counter_printlog(counter_tbl_t *ctr_tbl) +{ + uint32 now; + + if (!ctr_tbl->enabled) + return; + + now = OSL_SYSUPTIME(); + + if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) { + uint8 i = 0; + printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print); + + for (i = 0; i < ctr_tbl->needed_cnt; i++) { + printf(" %u", ctr_tbl->cnt[i]); + } + printf("\n"); + + ctr_tbl->prev_log_print = now; + bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint)); + } +} +#else +/* OSL_SYSUPTIME is not supported so no way to get time */ +#define counter_printlog(a) do {} while (0) +#endif /* OSL_SYSUPTIME_SUPPORT == TRUE */ +#endif /* DEBUG_COUNTER */ + +#ifdef BCMDRIVER +void +dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size) +{ + uint32 mem_size; + mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); + if (pool) + MFREE(osh, pool, mem_size); +} +dll_pool_t * +dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size) +{ + uint32 mem_size, i; + dll_pool_t * dll_pool_p; + dll_t * elem_p; + + ASSERT(elem_size > sizeof(dll_t)); + + mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); + + if ((dll_pool_p = (dll_pool_t *)MALLOC(osh, mem_size)) == NULL) { + printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n", + elems_max, elem_size); + ASSERT(0); + return dll_pool_p; + } + + bzero(dll_pool_p, mem_size); + + dll_init(&dll_pool_p->free_list); + dll_pool_p->elems_max = elems_max; + dll_pool_p->elem_size = elem_size; + + elem_p = dll_pool_p->elements; + for (i = 0; i < elems_max; i++) { + dll_append(&dll_pool_p->free_list, elem_p); + elem_p = (dll_t *)((uintptr)elem_p + elem_size); + } + + dll_pool_p->free_count = elems_max; + + return dll_pool_p; +} + + +void * +dll_pool_alloc(dll_pool_t * dll_pool_p) +{ + dll_t * elem_p; + + if (dll_pool_p->free_count == 0) { + ASSERT(dll_empty(&dll_pool_p->free_list)); + return NULL; + } + + elem_p = dll_head_p(&dll_pool_p->free_list); + dll_delete(elem_p); + dll_pool_p->free_count -= 1; + + return (void *)elem_p; +} + +void +dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p) +{ + dll_t * node_p = (dll_t *)elem_p; + dll_prepend(&dll_pool_p->free_list, node_p); + dll_pool_p->free_count += 1; +} + + +void +dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p) +{ + dll_t * node_p = (dll_t *)elem_p; + dll_append(&dll_pool_p->free_list, node_p); + dll_pool_p->free_count += 1; +} + +#endif /* BCMDRIVER */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.c new file mode 100644 index 000000000000..1a4b0f8992ac --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.c @@ -0,0 +1,1229 @@ +/* + * Misc utility routines used by kernel or app-level. + * Contents are wifi-specific, used by any kernel or app-level + * software that might want wifi things as it grows. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ + */ + +#include +#include +#include + +#ifdef BCMDRIVER +#include +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#else +#include +#include +#include +#ifndef ASSERT +#define ASSERT(exp) +#endif +#endif /* BCMDRIVER */ + +#include + +#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) +#include /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ +#endif + +/* Definitions for D11AC capable Chanspec type */ + +/* Chanspec ASCII representation with 802.11ac capability: + * [ 'g'] ['/' []['/'<1st80channel>'-'<2nd80channel>]] + * + * : + * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. + * Default value is 2g if channel <= 14, otherwise 5g. + * : + * channel number of the 5MHz, 10MHz, 20MHz channel, + * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. + * : + * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. + * : + * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. + * + * For 2.4GHz band 40MHz channels, the same primary channel may be the + * upper sideband for one 40MHz channel, and the lower sideband for an + * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel + * is being specified. + * + * For 40MHz in the 5GHz band and all channel bandwidths greater than + * 40MHz, the U/L specificaion is not allowed since the channels are + * non-overlapping and the primary sub-band is derived from its + * position in the wide bandwidth channel. + * + * <1st80Channel>: + * <2nd80Channel>: + * Required for 80+80, otherwise not allowed. + * Specifies the center channel of the first and second 80MHz band. + * + * In its simplest form, it is a 20MHz channel number, with the implied band + * of 2.4GHz if channel number <= 14, and 5GHz otherwise. + * + * To allow for backward compatibility with scripts, the old form for + * 40MHz channels is also allowed: + * + * : + * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz + * : + * "U" for upper, "L" for lower (or lower case "u" "l") + * + * 5 GHz Examples: + * Chanspec BW Center Ch Channel Range Primary Ch + * 5g8 20MHz 8 - - + * 52 20MHz 52 - - + * 52/40 40MHz 54 52-56 52 + * 56/40 40MHz 54 52-56 56 + * 52/80 80MHz 58 52-64 52 + * 56/80 80MHz 58 52-64 56 + * 60/80 80MHz 58 52-64 60 + * 64/80 80MHz 58 52-64 64 + * 52/160 160MHz 50 36-64 52 + * 36/160 160MGz 50 36-64 36 + * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 + * + * 2 GHz Examples: + * Chanspec BW Center Ch Channel Range Primary Ch + * 2g8 20MHz 8 - - + * 8 20MHz 8 - - + * 6 20MHz 6 - - + * 6/40l 40MHz 8 6-10 6 + * 6l 40MHz 8 6-10 6 + * 6/40u 40MHz 4 2-6 6 + * 6u 40MHz 4 2-6 6 + */ + +/* bandwidth ASCII string */ +static const char *wf_chspec_bw_str[] = +{ + "5", + "10", + "20", + "40", + "80", + "160", + "80+80", + "na" +}; + +static const uint8 wf_chspec_bw_mhz[] = +{5, 10, 20, 40, 80, 160, 160}; + +#define WF_NUM_BW \ + (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) + +/* 40MHz channels in 5GHz band */ +static const uint8 wf_5g_40m_chans[] = +{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; +#define WF_NUM_5G_40M_CHANS \ + (sizeof(wf_5g_40m_chans)/sizeof(uint8)) + +/* 80MHz channels in 5GHz band */ +static const uint8 wf_5g_80m_chans[] = +{42, 58, 106, 122, 138, 155}; +#define WF_NUM_5G_80M_CHANS \ + (sizeof(wf_5g_80m_chans)/sizeof(uint8)) + +/* 160MHz channels in 5GHz band */ +static const uint8 wf_5g_160m_chans[] = +{50, 114}; +#define WF_NUM_5G_160M_CHANS \ + (sizeof(wf_5g_160m_chans)/sizeof(uint8)) + + +/* convert bandwidth from chanspec to MHz */ +static uint +bw_chspec_to_mhz(chanspec_t chspec) +{ + uint bw; + + bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; + return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); +} + +/* bw in MHz, return the channel count from the center channel to the + * the channel at the edge of the band + */ +static uint8 +center_chan_to_edge(uint bw) +{ + /* edge channels separated by BW - 10MHz on each side + * delta from cf to edge is half of that, + * MHz to channel num conversion is 5MHz/channel + */ + return (uint8)(((bw - 20) / 2) / 5); +} + +/* return channel number of the low edge of the band + * given the center channel and BW + */ +static uint8 +channel_low_edge(uint center_ch, uint bw) +{ + return (uint8)(center_ch - center_chan_to_edge(bw)); +} + +/* return side band number given center channel and control channel + * return -1 on error + */ +static int +channel_to_sb(uint center_ch, uint ctl_ch, uint bw) +{ + uint lowest = channel_low_edge(center_ch, bw); + uint sb; + + if ((ctl_ch - lowest) % 4) { + /* bad ctl channel, not mult 4 */ + return -1; + } + + sb = ((ctl_ch - lowest) / 4); + + /* sb must be a index to a 20MHz channel in range */ + if (sb >= (bw / 20)) { + /* ctl_ch must have been too high for the center_ch */ + return -1; + } + + return sb; +} + +/* return control channel given center channel and side band */ +static uint8 +channel_to_ctl_chan(uint center_ch, uint bw, uint sb) +{ + return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); +} + +/* return index of 80MHz channel from channel number + * return -1 on error + */ +static int +channel_80mhz_to_id(uint ch) +{ + uint i; + for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { + if (ch == wf_5g_80m_chans[i]) + return i; + } + + return -1; +} + +/* wrapper function for wf_chspec_ntoa. In case of an error it puts + * the original chanspec in the output buffer, prepended with "invalid". + * Can be directly used in print routines as it takes care of null + */ +char * +wf_chspec_ntoa_ex(chanspec_t chspec, char *buf) +{ + if (wf_chspec_ntoa(chspec, buf) == NULL) + snprintf(buf, CHANSPEC_STR_LEN, "invalid 0x%04x", chspec); + return buf; +} + +/* given a chanspec and a string buffer, format the chanspec as a + * string, and return the original pointer a. + * Min buffer length must be CHANSPEC_STR_LEN. + * On error return NULL + */ +char * +wf_chspec_ntoa(chanspec_t chspec, char *buf) +{ + const char *band; + uint ctl_chan; + + if (wf_chspec_malformed(chspec)) + return NULL; + + band = ""; + + /* check for non-default band spec */ + if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || + (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) + band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; + + /* ctl channel */ + ctl_chan = wf_chspec_ctlchan(chspec); + + /* bandwidth and ctl sideband */ + if (CHSPEC_IS20(chspec)) { + snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); + } else if (!CHSPEC_IS8080(chspec)) { + const char *bw; + const char *sb = ""; + + bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; + +#ifdef CHANSPEC_NEW_40MHZ_FORMAT + /* ctl sideband string if needed for 2g 40MHz */ + if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { + sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; + } + + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); +#else + /* ctl sideband string instead of BW for 40MHz */ + if (CHSPEC_IS40(chspec)) { + sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; + snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); + } else { + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); + } +#endif /* CHANSPEC_NEW_40MHZ_FORMAT */ + + } else { + /* 80+80 */ + uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; + uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; + + /* convert to channel number */ + chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; + chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; + + /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ + snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); + } + + return (buf); +} + +static int +read_uint(const char **p, unsigned int *num) +{ + unsigned long val; + char *endp = NULL; + + val = strtoul(*p, &endp, 10); + /* if endp is the initial pointer value, then a number was not read */ + if (endp == *p) + return 0; + + /* advance the buffer pointer to the end of the integer string */ + *p = endp; + /* return the parsed integer */ + *num = (unsigned int)val; + + return 1; +} + +/* given a chanspec string, convert to a chanspec. + * On error return 0 + */ +chanspec_t +wf_chspec_aton(const char *a) +{ + chanspec_t chspec; + uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; + uint num, ctl_ch; + uint ch1, ch2; + char c, sb_ul = '\0'; + int i; + + bw = 20; + chspec_sb = 0; + chspec_ch = ch1 = ch2 = 0; + + /* parse channel num or band */ + if (!read_uint(&a, &num)) + return 0; + + /* if we are looking at a 'g', then the first number was a band */ + c = tolower((int)a[0]); + if (c == 'g') { + a ++; /* consume the char */ + + /* band must be "2" or "5" */ + if (num == 2) + chspec_band = WL_CHANSPEC_BAND_2G; + else if (num == 5) + chspec_band = WL_CHANSPEC_BAND_5G; + else + return 0; + + /* read the channel number */ + if (!read_uint(&a, &ctl_ch)) + return 0; + + c = tolower((int)a[0]); + } + else { + /* first number is channel, use default for band */ + ctl_ch = num; + chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); + } + + if (c == '\0') { + /* default BW of 20MHz */ + chspec_bw = WL_CHANSPEC_BW_20; + goto done_read; + } + + a ++; /* consume the 'u','l', or '/' */ + + /* check 'u'/'l' */ + if (c == 'u' || c == 'l') { + sb_ul = c; + chspec_bw = WL_CHANSPEC_BW_40; + goto done_read; + } + + /* next letter must be '/' */ + if (c != '/') + return 0; + + /* read bandwidth */ + if (!read_uint(&a, &bw)) + return 0; + + /* convert to chspec value */ + if (bw == 20) { + chspec_bw = WL_CHANSPEC_BW_20; + } else if (bw == 40) { + chspec_bw = WL_CHANSPEC_BW_40; + } else if (bw == 80) { + chspec_bw = WL_CHANSPEC_BW_80; + } else if (bw == 160) { + chspec_bw = WL_CHANSPEC_BW_160; + } else { + return 0; + } + + /* So far we have g/ + * Can now be followed by u/l if bw = 40, + * or '+80' if bw = 80, to make '80+80' bw. + */ + + c = tolower((int)a[0]); + + /* if we have a 2g/40 channel, we should have a l/u spec now */ + if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { + if (c == 'u' || c == 'l') { + a ++; /* consume the u/l char */ + sb_ul = c; + goto done_read; + } + } + + /* check for 80+80 */ + if (c == '+') { + /* 80+80 */ + static const char *plus80 = "80/"; + + /* must be looking at '+80/' + * check and consume this string. + */ + chspec_bw = WL_CHANSPEC_BW_8080; + + a ++; /* consume the char '+' */ + + /* consume the '80/' string */ + for (i = 0; i < 3; i++) { + if (*a++ != *plus80++) { + return 0; + } + } + + /* read primary 80MHz channel */ + if (!read_uint(&a, &ch1)) + return 0; + + /* must followed by '-' */ + if (a[0] != '-') + return 0; + a ++; /* consume the char */ + + /* read secondary 80MHz channel */ + if (!read_uint(&a, &ch2)) + return 0; + } + +done_read: + /* skip trailing white space */ + while (a[0] == ' ') { + a ++; + } + + /* must be end of string */ + if (a[0] != '\0') + return 0; + + /* Now have all the chanspec string parts read; + * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. + * chspec_band and chspec_bw are chanspec values. + * Need to convert ctl_ch, sb_ul, and ch1,ch2 into + * a center channel (or two) and sideband. + */ + + /* if a sb u/l string was given, just use that, + * guaranteed to be bw = 40 by sting parse. + */ + if (sb_ul != '\0') { + if (sb_ul == 'l') { + chspec_ch = UPPER_20_SB(ctl_ch); + chspec_sb = WL_CHANSPEC_CTL_SB_LLL; + } else if (sb_ul == 'u') { + chspec_ch = LOWER_20_SB(ctl_ch); + chspec_sb = WL_CHANSPEC_CTL_SB_LLU; + } + } + /* if the bw is 20, center and sideband are trivial */ + else if (chspec_bw == WL_CHANSPEC_BW_20) { + chspec_ch = ctl_ch; + chspec_sb = WL_CHANSPEC_CTL_SB_NONE; + } + /* if the bw is 40/80/160, not 80+80, a single method + * can be used to to find the center and sideband + */ + else if (chspec_bw != WL_CHANSPEC_BW_8080) { + /* figure out ctl sideband based on ctl channel and bandwidth */ + const uint8 *center_ch = NULL; + int num_ch = 0; + int sb = -1; + + if (chspec_bw == WL_CHANSPEC_BW_40) { + center_ch = wf_5g_40m_chans; + num_ch = WF_NUM_5G_40M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_80) { + center_ch = wf_5g_80m_chans; + num_ch = WF_NUM_5G_80M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_160) { + center_ch = wf_5g_160m_chans; + num_ch = WF_NUM_5G_160M_CHANS; + } else { + return 0; + } + + for (i = 0; i < num_ch; i ++) { + sb = channel_to_sb(center_ch[i], ctl_ch, bw); + if (sb >= 0) { + chspec_ch = center_ch[i]; + chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; + break; + } + } + + /* check for no matching sb/center */ + if (sb < 0) { + return 0; + } + } + /* Otherwise, bw is 80+80. Figure out channel pair and sb */ + else { + int ch1_id = 0, ch2_id = 0; + int sb; + + /* look up the channel ID for the specified channel numbers */ + ch1_id = channel_80mhz_to_id(ch1); + ch2_id = channel_80mhz_to_id(ch2); + + /* validate channels */ + if (ch1_id < 0 || ch2_id < 0) + return 0; + + /* combine 2 channel IDs in channel field of chspec */ + chspec_ch = (((uint)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | + ((uint)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); + + /* figure out primary 20 MHz sideband */ + + /* is the primary channel contained in the 1st 80MHz channel? */ + sb = channel_to_sb(ch1, ctl_ch, bw); + if (sb < 0) { + /* no match for primary channel 'ctl_ch' in segment0 80MHz channel */ + return 0; + } + + chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; + } + + chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); + + if (wf_chspec_malformed(chspec)) + return 0; + + return chspec; +} + +/* + * 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. + */ +bool +wf_chspec_malformed(chanspec_t chanspec) +{ + uint chspec_bw = CHSPEC_BW(chanspec); + uint chspec_ch = CHSPEC_CHANNEL(chanspec); + + /* must be 2G or 5G band */ + if (CHSPEC_IS2G(chanspec)) { + /* must be valid bandwidth */ + if (chspec_bw != WL_CHANSPEC_BW_20 && + chspec_bw != WL_CHANSPEC_BW_40) { + return TRUE; + } + } else if (CHSPEC_IS5G(chanspec)) { + if (chspec_bw == WL_CHANSPEC_BW_8080) { + uint ch1_id, ch2_id; + + /* channel IDs in 80+80 must be in range */ + ch1_id = CHSPEC_CHAN1(chanspec); + ch2_id = CHSPEC_CHAN2(chanspec); + if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) + return TRUE; + + } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || + chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { + + if (chspec_ch > MAXCHANNEL) { + return TRUE; + } + } else { + /* invalid bandwidth */ + return TRUE; + } + } else { + /* must be 2G or 5G band */ + return TRUE; + } + + /* side band needs to be consistent with bandwidth */ + if (chspec_bw == WL_CHANSPEC_BW_20) { + if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_40) { + if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_80 || + chspec_bw == WL_CHANSPEC_BW_8080) { + if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) + return TRUE; + } + else if (chspec_bw == WL_CHANSPEC_BW_160) { + ASSERT(CHSPEC_CTL_SB(chanspec) <= WL_CHANSPEC_CTL_SB_UUU); + } + return FALSE; +} + +/* + * Verify the chanspec specifies a valid channel according to 802.11. + * RETURNS: TRUE if the chanspec is a valid 802.11 channel + */ +bool +wf_chspec_valid(chanspec_t chanspec) +{ + uint chspec_bw = CHSPEC_BW(chanspec); + uint chspec_ch = CHSPEC_CHANNEL(chanspec); + + if (wf_chspec_malformed(chanspec)) + return FALSE; + + if (CHSPEC_IS2G(chanspec)) { + /* must be valid bandwidth and channel range */ + if (chspec_bw == WL_CHANSPEC_BW_20) { + if (chspec_ch >= 1 && chspec_ch <= 14) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_40) { + if (chspec_ch >= 3 && chspec_ch <= 11) + return TRUE; + } + } else if (CHSPEC_IS5G(chanspec)) { + if (chspec_bw == WL_CHANSPEC_BW_8080) { + uint16 ch1, ch2; + + ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; + ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; + + /* the two channels must be separated by more than 80MHz by VHT req */ + if ((ch2 > ch1 + CH_80MHZ_APART) || + (ch1 > ch2 + CH_80MHZ_APART)) + return TRUE; + } else { + const uint8 *center_ch; + uint num_ch, i; + + if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { + center_ch = wf_5g_40m_chans; + num_ch = WF_NUM_5G_40M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_80) { + center_ch = wf_5g_80m_chans; + num_ch = WF_NUM_5G_80M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_160) { + center_ch = wf_5g_160m_chans; + num_ch = WF_NUM_5G_160M_CHANS; + } else { + /* invalid bandwidth */ + return FALSE; + } + + /* check for a valid center channel */ + if (chspec_bw == WL_CHANSPEC_BW_20) { + /* We don't have an array of legal 20MHz 5G channels, but they are + * each side of the legal 40MHz channels. Check the chanspec + * channel against either side of the 40MHz channels. + */ + for (i = 0; i < num_ch; i ++) { + if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || + chspec_ch == (uint)UPPER_20_SB(center_ch[i])) + break; /* match found */ + } + + if (i == num_ch) { + /* check for channel 165 which is not the side band + * of 40MHz 5G channel + */ + if (chspec_ch == 165) + i = 0; + + /* check for legacy JP channels on failure */ + if (chspec_ch == 34 || chspec_ch == 38 || + chspec_ch == 42 || chspec_ch == 46) + i = 0; + } + } else { + /* check the chanspec channel to each legal channel */ + for (i = 0; i < num_ch; i ++) { + if (chspec_ch == center_ch[i]) + break; /* match found */ + } + } + + if (i < num_ch) { + /* match found */ + return TRUE; + } + } + } + + return FALSE; +} + +/* + * This function returns the channel number that control traffic is being sent on, for 20MHz + * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ + * sideband depending on the chanspec selected + */ +uint8 +wf_chspec_ctlchan(chanspec_t chspec) +{ + uint center_chan; + uint bw_mhz; + uint sb; + + ASSERT(!wf_chspec_malformed(chspec)); + + /* Is there a sideband ? */ + if (CHSPEC_IS20(chspec)) { + return CHSPEC_CHANNEL(chspec); + } else { + sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; + + if (CHSPEC_IS8080(chspec)) { + /* For an 80+80 MHz channel, the sideband 'sb' field is an 80 MHz sideband + * (LL, LU, UL, LU) for the 80 MHz frequency segment 0. + */ + uint chan_id = CHSPEC_CHAN1(chspec); + + bw_mhz = 80; + + /* convert from channel index to channel number */ + center_chan = wf_5g_80m_chans[chan_id]; + } + else { + bw_mhz = bw_chspec_to_mhz(chspec); + center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; + } + + return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); + } +} + +/* given a chanspec, return the bandwidth string */ +char * +wf_chspec_to_bw_str(chanspec_t chspec) +{ + return (char *)wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)]; +} + +/* + * This function returns the chanspec of the control channel of a given chanspec + */ +chanspec_t +wf_chspec_ctlchspec(chanspec_t chspec) +{ + chanspec_t ctl_chspec = chspec; + uint8 ctl_chan; + + ASSERT(!wf_chspec_malformed(chspec)); + + /* Is there a sideband ? */ + if (!CHSPEC_IS20(chspec)) { + ctl_chan = wf_chspec_ctlchan(chspec); + ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; + ctl_chspec |= CHSPEC_BAND(chspec); + } + return ctl_chspec; +} + +/* return chanspec given control channel and bandwidth + * return 0 on error + */ +uint16 +wf_channel2chspec(uint ctl_ch, uint bw) +{ + uint16 chspec; + const uint8 *center_ch = NULL; + int num_ch = 0; + int sb = -1; + int i = 0; + + chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); + + chspec |= bw; + + if (bw == WL_CHANSPEC_BW_40) { + center_ch = wf_5g_40m_chans; + num_ch = WF_NUM_5G_40M_CHANS; + bw = 40; + } else if (bw == WL_CHANSPEC_BW_80) { + center_ch = wf_5g_80m_chans; + num_ch = WF_NUM_5G_80M_CHANS; + bw = 80; + } else if (bw == WL_CHANSPEC_BW_160) { + center_ch = wf_5g_160m_chans; + num_ch = WF_NUM_5G_160M_CHANS; + bw = 160; + } else if (bw == WL_CHANSPEC_BW_20) { + chspec |= ctl_ch; + return chspec; + } else { + return 0; + } + + for (i = 0; i < num_ch; i ++) { + sb = channel_to_sb(center_ch[i], ctl_ch, bw); + if (sb >= 0) { + chspec |= center_ch[i]; + chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); + break; + } + } + + /* check for no matching sb/center */ + if (sb < 0) { + return 0; + } + + return chspec; +} + +/* + * This function returns the chanspec for the primary 40MHz of an 80MHz channel. + * The control sideband specifies the same 20MHz channel that the 80MHz channel is using + * as the primary 20MHz channel. + */ +extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) +{ + chanspec_t chspec40 = chspec; + uint center_chan; + uint sb; + + ASSERT(!wf_chspec_malformed(chspec)); + + /* if the chanspec is > 80MHz, use the helper routine to find the primary 80 MHz channel */ + if (CHSPEC_IS8080(chspec) || CHSPEC_IS160(chspec)) { + chspec = wf_chspec_primary80_chspec(chspec); + } + + /* determine primary 40 MHz sub-channel of an 80 MHz chanspec */ + if (CHSPEC_IS80(chspec)) { + center_chan = CHSPEC_CHANNEL(chspec); + sb = CHSPEC_CTL_SB(chspec); + + if (sb < WL_CHANSPEC_CTL_SB_UL) { + /* Primary 40MHz is on lower side */ + center_chan -= CH_20MHZ_APART; + /* sideband bits are the same for LL/LU and L/U */ + } else { + /* Primary 40MHz is on upper side */ + center_chan += CH_20MHZ_APART; + /* sideband bits need to be adjusted by UL offset */ + sb -= WL_CHANSPEC_CTL_SB_UL; + } + + /* Create primary 40MHz chanspec */ + chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | + sb | center_chan); + } + + return chspec40; +} + +/* + * Return the channel number for a given frequency and base frequency. + * The returned channel number is relative to the given base frequency. + * If the given base frequency is zero, a base frequency of 5 GHz is assumed for + * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. + * + * Frequency is specified in MHz. + * The base frequency is specified as (start_factor * 500 kHz). + * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for + * 2.4 GHz and 5 GHz bands. + * + * The returned channel will be in the range [1, 14] in the 2.4 GHz band + * and [0, 200] otherwise. + * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the + * frequency is not a 2.4 GHz channel, or if the frequency is not and even + * multiple of 5 MHz from the base frequency to the base plus 1 GHz. + * + * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + */ +int +wf_mhz2channel(uint freq, uint start_factor) +{ + int ch = -1; + uint base; + int offset; + + /* take the default channel start frequency */ + if (start_factor == 0) { + if (freq >= 2400 && freq <= 2500) + start_factor = WF_CHAN_FACTOR_2_4_G; + else if (freq >= 5000 && freq <= 6000) + start_factor = WF_CHAN_FACTOR_5_G; + } + + if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) + return 14; + + base = start_factor / 2; + + /* check that the frequency is in 1GHz range of the base */ + if ((freq < base) || (freq > base + 1000)) + return -1; + + offset = freq - base; + ch = offset / 5; + + /* check that frequency is a 5MHz multiple from the base */ + if (offset != (ch * 5)) + return -1; + + /* restricted channel range check for 2.4G */ + if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) + return -1; + + return ch; +} + +/* + * Return the center frequency in MHz of the given channel and base frequency. + * The channel number is interpreted relative to the given base frequency. + * + * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. + * The base frequency is specified as (start_factor * 500 kHz). + * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G + * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands. + * The channel range of [1, 14] is only checked for a start_factor of + * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2). + * Odd start_factors produce channels on .5 MHz boundaries, in which case + * the answer is rounded down to an integral MHz. + * -1 is returned for an out of range channel. + * + * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + */ +int +wf_channel2mhz(uint ch, uint start_factor) +{ + int freq; + + if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || + (ch > 200)) + freq = -1; + else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) + freq = 2484; + else + freq = ch * 5 + start_factor / 2; + + return freq; +} + +static const uint16 sidebands[] = { + WL_CHANSPEC_CTL_SB_LLL, WL_CHANSPEC_CTL_SB_LLU, + WL_CHANSPEC_CTL_SB_LUL, WL_CHANSPEC_CTL_SB_LUU, + WL_CHANSPEC_CTL_SB_ULL, WL_CHANSPEC_CTL_SB_ULU, + WL_CHANSPEC_CTL_SB_UUL, WL_CHANSPEC_CTL_SB_UUU +}; + +/* + * Returns the chanspec 80Mhz channel corresponding to the following input + * parameters + * + * primary_channel - primary 20Mhz channel + * center_channel - center frequecny of the 80Mhz channel + * + * The center_channel can be one of {42, 58, 106, 122, 138, 155} + * + * returns INVCHANSPEC in case of error + */ +chanspec_t +wf_chspec_80(uint8 center_channel, uint8 primary_channel) +{ + + chanspec_t chanspec = INVCHANSPEC; + chanspec_t chanspec_cur; + uint i; + + for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) { + chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]); + if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) { + chanspec = chanspec_cur; + break; + } + } + /* If the loop ended early, we are good, otherwise we did not + * find a 80MHz chanspec with the given center_channel that had a primary channel + *matching the given primary_channel. + */ + return chanspec; +} + +/* + * Returns the 80+80 chanspec corresponding to the following input parameters + * + * primary_20mhz - Primary 20 MHz channel + * chan0 - center channel number of one frequency segment + * chan1 - center channel number of the other frequency segment + * + * Parameters chan0 and chan1 are channel numbers in {42, 58, 106, 122, 138, 155}. + * The primary channel must be contained in one of the 80MHz channels. This routine + * will determine which frequency segment is the primary 80 MHz segment. + * + * Returns INVCHANSPEC in case of error. + * + * Refer to IEEE802.11ac section 22.3.14 "Channelization". + */ +chanspec_t +wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan0, uint8 chan1) +{ + int sb = 0; + uint16 chanspec = 0; + int chan0_id = 0, chan1_id = 0; + int seg0, seg1; + + chan0_id = channel_80mhz_to_id(chan0); + chan1_id = channel_80mhz_to_id(chan1); + + /* make sure the channel numbers were valid */ + if (chan0_id == -1 || chan1_id == -1) + return INVCHANSPEC; + + /* does the primary channel fit with the 1st 80MHz channel ? */ + sb = channel_to_sb(chan0, primary_20mhz, 80); + if (sb >= 0) { + /* yes, so chan0 is frequency segment 0, and chan1 is seg 1 */ + seg0 = chan0_id; + seg1 = chan1_id; + } else { + /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ + sb = channel_to_sb(chan1, primary_20mhz, 80); + if (sb < 0) { + /* no match for ctl_ch to either 80MHz center channel */ + return INVCHANSPEC; + } + /* swapped, so chan1 is frequency segment 0, and chan0 is seg 1 */ + seg0 = chan1_id; + seg1 = chan0_id; + } + + chanspec = ((seg0 << WL_CHANSPEC_CHAN1_SHIFT) | + (seg1 << WL_CHANSPEC_CHAN2_SHIFT) | + (sb << WL_CHANSPEC_CTL_SB_SHIFT) | + WL_CHANSPEC_BW_8080 | + WL_CHANSPEC_BAND_5G); + + return chanspec; +} + +/* + * This function returns the 80Mhz channel for the given id. + */ +static uint8 +wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id) +{ + if (chan_80Mhz_id < WF_NUM_5G_80M_CHANS) + return wf_5g_80m_chans[chan_80Mhz_id]; + + return 0; +} + +/* + * Returns the primary 80 Mhz channel for the provided chanspec + * + * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved + * + * returns -1 in case the provided channel is 20/40 Mhz chanspec + */ + +uint8 +wf_chspec_primary80_channel(chanspec_t chanspec) +{ + uint8 primary80_chan; + + if (CHSPEC_IS80(chanspec)) { + primary80_chan = CHSPEC_CHANNEL(chanspec); + } + else if (CHSPEC_IS8080(chanspec)) { + /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ + primary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); + } + else if (CHSPEC_IS160(chanspec)) { + uint8 center_chan = CHSPEC_CHANNEL(chanspec); + uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; + + /* based on the sb value primary 80 channel can be retrieved + * if sb is in range 0 to 3 the lower band is the 80Mhz primary band + */ + if (sb < 4) { + primary80_chan = center_chan - CH_40MHZ_APART; + } + /* if sb is in range 4 to 7 the upper band is the 80Mhz primary band */ + else + { + primary80_chan = center_chan + CH_40MHZ_APART; + } + } + else { + /* for 20 and 40 Mhz */ + primary80_chan = -1; + } + return primary80_chan; +} + +/* + * Returns the secondary 80 Mhz channel for the provided chanspec + * + * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved + * + * returns -1 in case the provided channel is 20/40/80 Mhz chanspec + */ +uint8 +wf_chspec_secondary80_channel(chanspec_t chanspec) +{ + uint8 secondary80_chan; + + if (CHSPEC_IS8080(chanspec)) { + secondary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); + } + else if (CHSPEC_IS160(chanspec)) { + uint8 center_chan = CHSPEC_CHANNEL(chanspec); + uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; + + /* based on the sb value secondary 80 channel can be retrieved + * if sb is in range 0 to 3 upper band is the secondary 80Mhz band + */ + if (sb < 4) { + secondary80_chan = center_chan + CH_40MHZ_APART; + } + /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */ + else + { + secondary80_chan = center_chan - CH_40MHZ_APART; + } + } + else { + /* for 20, 40, and 80 Mhz */ + secondary80_chan = -1; + } + return secondary80_chan; +} + +/* + * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. + * + * chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived + * + * returns the input chanspec in case the provided chanspec is an 80 MHz chanspec + * returns INVCHANSPEC in case the provided channel is 20/40 MHz chanspec + */ +chanspec_t +wf_chspec_primary80_chspec(chanspec_t chspec) +{ + chanspec_t chspec80; + uint center_chan; + uint sb; + + ASSERT(!wf_chspec_malformed(chspec)); + if (CHSPEC_IS80(chspec)) { + chspec80 = chspec; + } + else if (CHSPEC_IS8080(chspec)) { + + /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ + center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); + + sb = CHSPEC_CTL_SB(chspec); + + /* Create primary 80MHz chanspec */ + chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); + } + else if (CHSPEC_IS160(chspec)) { + center_chan = CHSPEC_CHANNEL(chspec); + sb = CHSPEC_CTL_SB(chspec); + + if (sb < WL_CHANSPEC_CTL_SB_ULL) { + /* Primary 80MHz is on lower side */ + center_chan -= CH_40MHZ_APART; + } + else { + /* Primary 80MHz is on upper side */ + center_chan += CH_40MHZ_APART; + sb -= WL_CHANSPEC_CTL_SB_ULL; + } + /* Create primary 80MHz chanspec */ + chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); + } + else { + chspec80 = INVCHANSPEC; + } + + return chspec80; +} + +#ifdef WL11AC_80P80 +uint8 +wf_chspec_channel(chanspec_t chspec) +{ + if (CHSPEC_IS8080(chspec)) { + return wf_chspec_primary80_channel(chspec); + } + else { + return ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)); + } +} +#endif /* WL11AC_80P80 */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.h new file mode 100644 index 000000000000..44852f9ea30e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.h @@ -0,0 +1,548 @@ +/* + * Misc utility routines for WL and Apps + * This header file housing the define and function prototype use by + * both the wl driver, tools & Apps. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ + */ + +#ifndef _bcmwifi_channels_h_ +#define _bcmwifi_channels_h_ + + +/* A chanspec holds the channel number, band, bandwidth and control sideband */ +typedef uint16 chanspec_t; + +/* channel defines */ +#define CH_UPPER_SB 0x01 +#define CH_LOWER_SB 0x02 +#define CH_EWA_VALID 0x04 +#define CH_80MHZ_APART 16 +#define CH_40MHZ_APART 8 +#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 MAXCHANNEL 224 /* max # supported channels. The max channel no is above, + * this is that + 1 rounded up to a multiple of NBBY (8). + * DO NOT MAKE it > 255: channels are uint8's all over + */ +#define MAXCHANNEL_NUM (MAXCHANNEL - 1) /* max channel number */ + +/* make sure channel num is within valid range */ +#define CH_NUM_VALID_RANGE(ch_num) ((ch_num) > 0 && (ch_num) <= MAXCHANNEL_NUM) + +#define CHSPEC_CTLOVLP(sp1, sp2, sep) (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < \ + (sep)) + +/* All builds use the new 11ac ratespec/chanspec */ +#undef D11AC_IOTYPES +#define D11AC_IOTYPES + +#define WL_CHANSPEC_CHAN_MASK 0x00ff +#define WL_CHANSPEC_CHAN_SHIFT 0 +#define WL_CHANSPEC_CHAN1_MASK 0x000f +#define WL_CHANSPEC_CHAN1_SHIFT 0 +#define WL_CHANSPEC_CHAN2_MASK 0x00f0 +#define WL_CHANSPEC_CHAN2_SHIFT 4 + +#define WL_CHANSPEC_CTL_SB_MASK 0x0700 +#define WL_CHANSPEC_CTL_SB_SHIFT 8 +#define WL_CHANSPEC_CTL_SB_LLL 0x0000 +#define WL_CHANSPEC_CTL_SB_LLU 0x0100 +#define WL_CHANSPEC_CTL_SB_LUL 0x0200 +#define WL_CHANSPEC_CTL_SB_LUU 0x0300 +#define WL_CHANSPEC_CTL_SB_ULL 0x0400 +#define WL_CHANSPEC_CTL_SB_ULU 0x0500 +#define WL_CHANSPEC_CTL_SB_UUL 0x0600 +#define WL_CHANSPEC_CTL_SB_UUU 0x0700 +#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL +#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU +#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL + +#define WL_CHANSPEC_BW_MASK 0x3800 +#define WL_CHANSPEC_BW_SHIFT 11 +#define WL_CHANSPEC_BW_5 0x0000 +#define WL_CHANSPEC_BW_10 0x0800 +#define WL_CHANSPEC_BW_20 0x1000 +#define WL_CHANSPEC_BW_40 0x1800 +#define WL_CHANSPEC_BW_80 0x2000 +#define WL_CHANSPEC_BW_160 0x2800 +#define WL_CHANSPEC_BW_8080 0x3000 + +#define WL_CHANSPEC_BAND_MASK 0xc000 +#define WL_CHANSPEC_BAND_SHIFT 14 +#define WL_CHANSPEC_BAND_2G 0x0000 +#define WL_CHANSPEC_BAND_3G 0x4000 +#define WL_CHANSPEC_BAND_4G 0x8000 +#define WL_CHANSPEC_BAND_5G 0xc000 +#define INVCHANSPEC 255 + +/* channel defines */ +#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ + ((channel) - CH_10MHZ_APART) : 0) +#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ + ((channel) + CH_10MHZ_APART) : 0) + +#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) +#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ + ((channel) + 3 * CH_10MHZ_APART) : 0) +#define LU_20_SB(channel) LOWER_20_SB(channel) +#define UL_20_SB(channel) UPPER_20_SB(channel) + +#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) +#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) +#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) +#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ + (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) +#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ + ((channel) + CH_20MHZ_APART) : 0) +#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ + ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ + WL_CHANSPEC_BAND_5G)) +#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | \ + WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) +#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | \ + WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) + +/* simple MACROs to get different fields of chanspec */ +#ifdef WL11AC_80P80 +#define CHSPEC_CHANNEL(chspec) wf_chspec_channel(chspec) +#else +#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) +#endif +#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT +#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT +#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) + +#ifdef WL11N_20MHZONLY + +#define CHSPEC_IS10(chspec) 0 +#define CHSPEC_IS20(chspec) 1 +#ifndef CHSPEC_IS40 +#define CHSPEC_IS40(chspec) 0 +#endif +#ifndef CHSPEC_IS80 +#define CHSPEC_IS80(chspec) 0 +#endif +#ifndef CHSPEC_IS160 +#define CHSPEC_IS160(chspec) 0 +#endif +#ifndef CHSPEC_IS8080 +#define CHSPEC_IS8080(chspec) 0 +#endif + +#else /* !WL11N_20MHZONLY */ + +#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 +#ifndef CHSPEC_IS80 +#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) +#endif +#ifndef CHSPEC_IS160 +#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) +#endif +#ifndef CHSPEC_IS8080 +#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) +#endif + +#endif /* !WL11N_20MHZONLY */ + +#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_UPPER(chspec) \ + ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) +#define CHSPEC_SB_LOWER(chspec) \ + ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) +#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) + +/** + * Number of chars needed for wf_chspec_ntoa() destination character buffer. + */ +#define CHANSPEC_STR_LEN 20 + + +#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\ + CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080) + +/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made +* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80, +* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080). +* +* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide. +* If both chspec bandwidth and bw is not 160 wide, then the comparison is made. +*/ +#define CHSPEC_BW_GE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) >= bw)) + +#define CHSPEC_BW_LE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) <= bw)) + +#define CHSPEC_BW_GT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) > bw)) + +#define CHSPEC_BW_LT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) < bw)) + +/* Legacy Chanspec defines + * These are the defines for the previous format of the chanspec_t + */ +#define WL_LCHANSPEC_CHAN_MASK 0x00ff +#define WL_LCHANSPEC_CHAN_SHIFT 0 + +#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 +#define WL_LCHANSPEC_CTL_SB_SHIFT 8 +#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 +#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 +#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 + +#define WL_LCHANSPEC_BW_MASK 0x0C00 +#define WL_LCHANSPEC_BW_SHIFT 10 +#define WL_LCHANSPEC_BW_10 0x0400 +#define WL_LCHANSPEC_BW_20 0x0800 +#define WL_LCHANSPEC_BW_40 0x0C00 + +#define WL_LCHANSPEC_BAND_MASK 0xf000 +#define WL_LCHANSPEC_BAND_SHIFT 12 +#define WL_LCHANSPEC_BAND_5G 0x1000 +#define WL_LCHANSPEC_BAND_2G 0x2000 + +#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) +#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) +#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) +#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) +#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) +#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) +#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) +#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) +#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) + +#define LCHSPEC_SB_UPPER(chspec) \ + ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \ + (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) +#define LCHSPEC_SB_LOWER(chspec) \ + ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \ + (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) + +#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) + +#define CH20MHZ_LCHSPEC(channel) \ + (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \ + WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G)) + +/* + * WF_CHAN_FACTOR_* constants are used to calculate channel frequency + * given a channel number. + * chan_freq = chan_factor * 500Mhz + chan_number * 5 + */ + +/** + * Channel Factor for the starting frequence of 2.4 GHz channels. + * The value corresponds to 2407 MHz. + */ +#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ + +/** + * Channel Factor for the starting frequence of 5 GHz channels. + * The value corresponds to 5000 MHz. + */ +#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ + +/** + * Channel Factor for the starting frequence of 4.9 GHz channels. + * The value corresponds to 4000 MHz. + */ +#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ + +#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ + +/** + * No of sub-band vlaue of the specified Mhz chanspec + */ +#define WF_NUM_SIDEBANDS_40MHZ 2 +#define WF_NUM_SIDEBANDS_80MHZ 4 +#define WF_NUM_SIDEBANDS_8080MHZ 4 +#define WF_NUM_SIDEBANDS_160MHZ 8 + +/** + * Convert chanspec to ascii string + * + * @param chspec chanspec format + * @param buf ascii string of chanspec + * + * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes + * Original chanspec in case of error + * + * @see CHANSPEC_STR_LEN + */ +extern char * wf_chspec_ntoa_ex(chanspec_t chspec, char *buf); + +/** + * Convert chanspec to ascii string + * + * @param chspec chanspec format + * @param buf ascii string of chanspec + * + * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes + * NULL in case of error + * + * @see CHANSPEC_STR_LEN + */ +extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); + +/** + * Convert ascii string to chanspec + * + * @param a pointer to input string + * + * @return >= 0 if successful or 0 otherwise + */ +extern chanspec_t wf_chspec_aton(const char *a); + +/** + * Verify the chanspec fields are valid. + * + * Verify the chanspec is using a legal set field values, i.e. that the chanspec + * specified a band, bw, ctl_sb and channel and that the combination could be + * legal given some set of circumstances. + * + * @param chanspec input chanspec to verify + * + * @return TRUE if the chanspec is malformed, FALSE if it looks good. + */ +extern bool wf_chspec_malformed(chanspec_t chanspec); + +/** + * Verify the chanspec specifies a valid channel according to 802.11. + * + * @param chanspec input chanspec to verify + * + * @return TRUE if the chanspec is a valid 802.11 channel + */ +extern bool wf_chspec_valid(chanspec_t chanspec); + +/** + * Return the primary (control) channel. + * + * This function returns the channel number of the primary 20MHz channel. For + * 20MHz channels this is just the channel number. For 40MHz or wider channels + * it is the primary 20MHz channel specified by the chanspec. + * + * @param chspec input chanspec + * + * @return Returns the channel number of the primary 20MHz channel + */ +extern uint8 wf_chspec_ctlchan(chanspec_t chspec); + +/** + * Return the bandwidth string. + * + * This function returns the bandwidth string for the passed chanspec. + * + * @param chspec input chanspec + * + * @return Returns the bandwidth string + */ +extern char * wf_chspec_to_bw_str(chanspec_t chspec); + +/** + * Return the primary (control) chanspec. + * + * This function returns the chanspec of the primary 20MHz channel. For 20MHz + * channels this is just the chanspec. For 40MHz or wider channels it is the + * chanspec of the primary 20MHZ channel specified by the chanspec. + * + * @param chspec input chanspec + * + * @return Returns the chanspec of the primary 20MHz channel + */ +extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); + +/** + * Return a channel number corresponding to a frequency. + * + * This function returns the chanspec for the primary 40MHz of an 80MHz channel. + * The control sideband specifies the same 20MHz channel that the 80MHz channel is using + * as the primary 20MHz channel. + */ +extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); + +/* + * Return the channel number for a given frequency and base frequency. + * The returned channel number is relative to the given base frequency. + * If the given base frequency is zero, a base frequency of 5 GHz is assumed for + * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. + * + * Frequency is specified in MHz. + * The base frequency is specified as (start_factor * 500 kHz). + * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for + * 2.4 GHz and 5 GHz bands. + * + * The returned channel will be in the range [1, 14] in the 2.4 GHz band + * and [0, 200] otherwise. + * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the + * frequency is not a 2.4 GHz channel, or if the frequency is not and even + * multiple of 5 MHz from the base frequency to the base plus 1 GHz. + * + * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + * + * @param freq frequency in MHz + * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz + * + * @return Returns a channel number + * + * @see WF_CHAN_FACTOR_2_4_G + * @see WF_CHAN_FACTOR_5_G + */ +extern int wf_mhz2channel(uint freq, uint start_factor); + +/** + * Return the center frequency in MHz of the given channel and base frequency. + * + * Return the center frequency in MHz of the given channel and base frequency. + * The channel number is interpreted relative to the given base frequency. + * + * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. + * The base frequency is specified as (start_factor * 500 kHz). + * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for + * 2.4 GHz and 5 GHz bands. + * The channel range of [1, 14] is only checked for a start_factor of + * WF_CHAN_FACTOR_2_4_G (4814). + * Odd start_factors produce channels on .5 MHz boundaries, in which case + * the answer is rounded down to an integral MHz. + * -1 is returned for an out of range channel. + * + * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + * + * @param channel input channel number + * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz + * + * @return Returns a frequency in MHz + * + * @see WF_CHAN_FACTOR_2_4_G + * @see WF_CHAN_FACTOR_5_G + */ +extern int wf_channel2mhz(uint channel, uint start_factor); + +/** + * Returns the chanspec 80Mhz channel corresponding to the following input + * parameters + * + * primary_channel - primary 20Mhz channel + * center_channel - center frequecny of the 80Mhz channel + * + * The center_channel can be one of {42, 58, 106, 122, 138, 155} + * + * returns INVCHANSPEC in case of error + */ +extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel); + +/** + * Convert ctl chan and bw to chanspec + * + * @param ctl_ch channel + * @param bw bandwidth + * + * @return > 0 if successful or 0 otherwise + * + */ +extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); + +extern uint wf_channel2freq(uint channel); +extern uint wf_freq2channel(uint freq); + +/* + * Returns the 80+80 MHz chanspec corresponding to the following input parameters + * + * primary_20mhz - Primary 20 MHz channel + * chan0_80MHz - center channel number of one frequency segment + * chan1_80MHz - center channel number of the other frequency segment + * + * Parameters chan0_80MHz and chan1_80MHz are channel numbers in {42, 58, 106, 122, 138, 155}. + * The primary channel must be contained in one of the 80MHz channels. This routine + * will determine which frequency segment is the primary 80 MHz segment. + * + * Returns INVCHANSPEC in case of error. + * + * Refer to IEEE802.11ac section 22.3.14 "Channelization". + */ +extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz, + uint8 chan0_80Mhz, uint8 chan1_80Mhz); + +/* + * Returns the primary 80 Mhz channel for the provided chanspec + * + * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved + * + * returns -1 in case the provided channel is 20/40 Mhz chanspec + */ +extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec); + +/* + * Returns the secondary 80 Mhz channel for the provided chanspec + * + * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved + * + * returns -1 in case the provided channel is 20/40 Mhz chanspec + */ +extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec); + +/* + * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. + */ +extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec); + +#ifdef WL11AC_80P80 +/* + * This function returns the centre chanel for the given chanspec. + * In case of 80+80 chanspec it returns the primary 80 Mhz centre channel + */ +extern uint8 wf_chspec_channel(chanspec_t chspec); +#endif +#endif /* _bcmwifi_channels_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_rates.h new file mode 100644 index 000000000000..04575dfaeb71 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_rates.h @@ -0,0 +1,466 @@ +/* + * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmwifi_rates.h 5187 2012-06-29 06:17:50Z $ + */ + +#ifndef _bcmwifi_rates_h_ +#define _bcmwifi_rates_h_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define WL_RATESET_SZ_DSSS 4 +#define WL_RATESET_SZ_OFDM 8 +#define WL_RATESET_SZ_VHT_MCS 10 + +#define WL_RATESET_SZ_HT_MCS 8 + +#define WL_RATESET_SZ_HT_IOCTL 8 /* MAC histogram, compatibility with wl utility */ + +#define WL_TX_CHAINS_MAX 3 + +#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */ + +/* Transmit channel bandwidths */ +typedef enum wl_tx_bw { + WL_TX_BW_20, + WL_TX_BW_40, + WL_TX_BW_80, + WL_TX_BW_20IN40, + WL_TX_BW_20IN80, + WL_TX_BW_40IN80, + WL_TX_BW_160, + WL_TX_BW_20IN160, + WL_TX_BW_40IN160, + WL_TX_BW_80IN160, + WL_TX_BW_ALL, + WL_TX_BW_8080, + WL_TX_BW_8080CHAN2, + WL_TX_BW_20IN8080, + WL_TX_BW_40IN8080, + WL_TX_BW_80IN8080 +} wl_tx_bw_t; + + +/* + * Transmit modes. + * Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed + */ +typedef enum wl_tx_mode { + WL_TX_MODE_NONE, + WL_TX_MODE_STBC, + WL_TX_MODE_CDD, + WL_TX_MODE_TXBF, + WL_NUM_TX_MODES +} wl_tx_mode_t; + + +/* Number of transmit chains */ +typedef enum wl_tx_chains { + WL_TX_CHAINS_1 = 1, + WL_TX_CHAINS_2, + WL_TX_CHAINS_3 +} wl_tx_chains_t; + + +/* Number of transmit streams */ +typedef enum wl_tx_nss { + WL_TX_NSS_1 = 1, + WL_TX_NSS_2, + WL_TX_NSS_3 +} wl_tx_nss_t; + + +typedef enum clm_rates { + /************ + * 1 chain * + ************ + */ + + /* 1 Stream */ + WL_RATE_1X1_DSSS_1 = 0, + WL_RATE_1X1_DSSS_2 = 1, + WL_RATE_1X1_DSSS_5_5 = 2, + WL_RATE_1X1_DSSS_11 = 3, + + WL_RATE_1X1_OFDM_6 = 4, + WL_RATE_1X1_OFDM_9 = 5, + WL_RATE_1X1_OFDM_12 = 6, + WL_RATE_1X1_OFDM_18 = 7, + WL_RATE_1X1_OFDM_24 = 8, + WL_RATE_1X1_OFDM_36 = 9, + WL_RATE_1X1_OFDM_48 = 10, + WL_RATE_1X1_OFDM_54 = 11, + + WL_RATE_1X1_MCS0 = 12, + WL_RATE_1X1_MCS1 = 13, + WL_RATE_1X1_MCS2 = 14, + WL_RATE_1X1_MCS3 = 15, + WL_RATE_1X1_MCS4 = 16, + WL_RATE_1X1_MCS5 = 17, + WL_RATE_1X1_MCS6 = 18, + WL_RATE_1X1_MCS7 = 19, + + WL_RATE_1X1_VHT0SS1 = 12, + WL_RATE_1X1_VHT1SS1 = 13, + WL_RATE_1X1_VHT2SS1 = 14, + WL_RATE_1X1_VHT3SS1 = 15, + WL_RATE_1X1_VHT4SS1 = 16, + WL_RATE_1X1_VHT5SS1 = 17, + WL_RATE_1X1_VHT6SS1 = 18, + WL_RATE_1X1_VHT7SS1 = 19, + WL_RATE_1X1_VHT8SS1 = 20, + WL_RATE_1X1_VHT9SS1 = 21, + + + /************ + * 2 chains * + ************ + */ + + /* 1 Stream expanded + 1 */ + WL_RATE_1X2_DSSS_1 = 22, + WL_RATE_1X2_DSSS_2 = 23, + WL_RATE_1X2_DSSS_5_5 = 24, + WL_RATE_1X2_DSSS_11 = 25, + + WL_RATE_1X2_CDD_OFDM_6 = 26, + WL_RATE_1X2_CDD_OFDM_9 = 27, + WL_RATE_1X2_CDD_OFDM_12 = 28, + WL_RATE_1X2_CDD_OFDM_18 = 29, + WL_RATE_1X2_CDD_OFDM_24 = 30, + WL_RATE_1X2_CDD_OFDM_36 = 31, + WL_RATE_1X2_CDD_OFDM_48 = 32, + WL_RATE_1X2_CDD_OFDM_54 = 33, + + WL_RATE_1X2_CDD_MCS0 = 34, + WL_RATE_1X2_CDD_MCS1 = 35, + WL_RATE_1X2_CDD_MCS2 = 36, + WL_RATE_1X2_CDD_MCS3 = 37, + WL_RATE_1X2_CDD_MCS4 = 38, + WL_RATE_1X2_CDD_MCS5 = 39, + WL_RATE_1X2_CDD_MCS6 = 40, + WL_RATE_1X2_CDD_MCS7 = 41, + + WL_RATE_1X2_VHT0SS1 = 34, + WL_RATE_1X2_VHT1SS1 = 35, + WL_RATE_1X2_VHT2SS1 = 36, + WL_RATE_1X2_VHT3SS1 = 37, + WL_RATE_1X2_VHT4SS1 = 38, + WL_RATE_1X2_VHT5SS1 = 39, + WL_RATE_1X2_VHT6SS1 = 40, + WL_RATE_1X2_VHT7SS1 = 41, + WL_RATE_1X2_VHT8SS1 = 42, + WL_RATE_1X2_VHT9SS1 = 43, + + /* 2 Streams */ + WL_RATE_2X2_STBC_MCS0 = 44, + WL_RATE_2X2_STBC_MCS1 = 45, + WL_RATE_2X2_STBC_MCS2 = 46, + WL_RATE_2X2_STBC_MCS3 = 47, + WL_RATE_2X2_STBC_MCS4 = 48, + WL_RATE_2X2_STBC_MCS5 = 49, + WL_RATE_2X2_STBC_MCS6 = 50, + WL_RATE_2X2_STBC_MCS7 = 51, + + WL_RATE_2X2_STBC_VHT0SS1 = 44, + WL_RATE_2X2_STBC_VHT1SS1 = 45, + WL_RATE_2X2_STBC_VHT2SS1 = 46, + WL_RATE_2X2_STBC_VHT3SS1 = 47, + WL_RATE_2X2_STBC_VHT4SS1 = 48, + WL_RATE_2X2_STBC_VHT5SS1 = 49, + WL_RATE_2X2_STBC_VHT6SS1 = 50, + WL_RATE_2X2_STBC_VHT7SS1 = 51, + WL_RATE_2X2_STBC_VHT8SS1 = 52, + WL_RATE_2X2_STBC_VHT9SS1 = 53, + + WL_RATE_2X2_SDM_MCS8 = 54, + WL_RATE_2X2_SDM_MCS9 = 55, + WL_RATE_2X2_SDM_MCS10 = 56, + WL_RATE_2X2_SDM_MCS11 = 57, + WL_RATE_2X2_SDM_MCS12 = 58, + WL_RATE_2X2_SDM_MCS13 = 59, + WL_RATE_2X2_SDM_MCS14 = 60, + WL_RATE_2X2_SDM_MCS15 = 61, + + WL_RATE_2X2_VHT0SS2 = 54, + WL_RATE_2X2_VHT1SS2 = 55, + WL_RATE_2X2_VHT2SS2 = 56, + WL_RATE_2X2_VHT3SS2 = 57, + WL_RATE_2X2_VHT4SS2 = 58, + WL_RATE_2X2_VHT5SS2 = 59, + WL_RATE_2X2_VHT6SS2 = 60, + WL_RATE_2X2_VHT7SS2 = 61, + WL_RATE_2X2_VHT8SS2 = 62, + WL_RATE_2X2_VHT9SS2 = 63, + + /************ + * 3 chains * + ************ + */ + + /* 1 Stream expanded + 2 */ + WL_RATE_1X3_DSSS_1 = 64, + WL_RATE_1X3_DSSS_2 = 65, + WL_RATE_1X3_DSSS_5_5 = 66, + WL_RATE_1X3_DSSS_11 = 67, + + WL_RATE_1X3_CDD_OFDM_6 = 68, + WL_RATE_1X3_CDD_OFDM_9 = 69, + WL_RATE_1X3_CDD_OFDM_12 = 70, + WL_RATE_1X3_CDD_OFDM_18 = 71, + WL_RATE_1X3_CDD_OFDM_24 = 72, + WL_RATE_1X3_CDD_OFDM_36 = 73, + WL_RATE_1X3_CDD_OFDM_48 = 74, + WL_RATE_1X3_CDD_OFDM_54 = 75, + + WL_RATE_1X3_CDD_MCS0 = 76, + WL_RATE_1X3_CDD_MCS1 = 77, + WL_RATE_1X3_CDD_MCS2 = 78, + WL_RATE_1X3_CDD_MCS3 = 79, + WL_RATE_1X3_CDD_MCS4 = 80, + WL_RATE_1X3_CDD_MCS5 = 81, + WL_RATE_1X3_CDD_MCS6 = 82, + WL_RATE_1X3_CDD_MCS7 = 83, + + WL_RATE_1X3_VHT0SS1 = 76, + WL_RATE_1X3_VHT1SS1 = 77, + WL_RATE_1X3_VHT2SS1 = 78, + WL_RATE_1X3_VHT3SS1 = 79, + WL_RATE_1X3_VHT4SS1 = 80, + WL_RATE_1X3_VHT5SS1 = 81, + WL_RATE_1X3_VHT6SS1 = 82, + WL_RATE_1X3_VHT7SS1 = 83, + WL_RATE_1X3_VHT8SS1 = 84, + WL_RATE_1X3_VHT9SS1 = 85, + + /* 2 Streams expanded + 1 */ + WL_RATE_2X3_STBC_MCS0 = 86, + WL_RATE_2X3_STBC_MCS1 = 87, + WL_RATE_2X3_STBC_MCS2 = 88, + WL_RATE_2X3_STBC_MCS3 = 89, + WL_RATE_2X3_STBC_MCS4 = 90, + WL_RATE_2X3_STBC_MCS5 = 91, + WL_RATE_2X3_STBC_MCS6 = 92, + WL_RATE_2X3_STBC_MCS7 = 93, + + WL_RATE_2X3_STBC_VHT0SS1 = 86, + WL_RATE_2X3_STBC_VHT1SS1 = 87, + WL_RATE_2X3_STBC_VHT2SS1 = 88, + WL_RATE_2X3_STBC_VHT3SS1 = 89, + WL_RATE_2X3_STBC_VHT4SS1 = 90, + WL_RATE_2X3_STBC_VHT5SS1 = 91, + WL_RATE_2X3_STBC_VHT6SS1 = 92, + WL_RATE_2X3_STBC_VHT7SS1 = 93, + WL_RATE_2X3_STBC_VHT8SS1 = 94, + WL_RATE_2X3_STBC_VHT9SS1 = 95, + + WL_RATE_2X3_SDM_MCS8 = 96, + WL_RATE_2X3_SDM_MCS9 = 97, + WL_RATE_2X3_SDM_MCS10 = 98, + WL_RATE_2X3_SDM_MCS11 = 99, + WL_RATE_2X3_SDM_MCS12 = 100, + WL_RATE_2X3_SDM_MCS13 = 101, + WL_RATE_2X3_SDM_MCS14 = 102, + WL_RATE_2X3_SDM_MCS15 = 103, + + WL_RATE_2X3_VHT0SS2 = 96, + WL_RATE_2X3_VHT1SS2 = 97, + WL_RATE_2X3_VHT2SS2 = 98, + WL_RATE_2X3_VHT3SS2 = 99, + WL_RATE_2X3_VHT4SS2 = 100, + WL_RATE_2X3_VHT5SS2 = 101, + WL_RATE_2X3_VHT6SS2 = 102, + WL_RATE_2X3_VHT7SS2 = 103, + WL_RATE_2X3_VHT8SS2 = 104, + WL_RATE_2X3_VHT9SS2 = 105, + + /* 3 Streams */ + WL_RATE_3X3_SDM_MCS16 = 106, + WL_RATE_3X3_SDM_MCS17 = 107, + WL_RATE_3X3_SDM_MCS18 = 108, + WL_RATE_3X3_SDM_MCS19 = 109, + WL_RATE_3X3_SDM_MCS20 = 110, + WL_RATE_3X3_SDM_MCS21 = 111, + WL_RATE_3X3_SDM_MCS22 = 112, + WL_RATE_3X3_SDM_MCS23 = 113, + + WL_RATE_3X3_VHT0SS3 = 106, + WL_RATE_3X3_VHT1SS3 = 107, + WL_RATE_3X3_VHT2SS3 = 108, + WL_RATE_3X3_VHT3SS3 = 109, + WL_RATE_3X3_VHT4SS3 = 110, + WL_RATE_3X3_VHT5SS3 = 111, + WL_RATE_3X3_VHT6SS3 = 112, + WL_RATE_3X3_VHT7SS3 = 113, + WL_RATE_3X3_VHT8SS3 = 114, + WL_RATE_3X3_VHT9SS3 = 115, + + + /**************************** + * TX Beamforming, 2 chains * + **************************** + */ + + /* 1 Stream expanded + 1 */ + + WL_RATE_1X2_TXBF_OFDM_6 = 116, + WL_RATE_1X2_TXBF_OFDM_9 = 117, + WL_RATE_1X2_TXBF_OFDM_12 = 118, + WL_RATE_1X2_TXBF_OFDM_18 = 119, + WL_RATE_1X2_TXBF_OFDM_24 = 120, + WL_RATE_1X2_TXBF_OFDM_36 = 121, + WL_RATE_1X2_TXBF_OFDM_48 = 122, + WL_RATE_1X2_TXBF_OFDM_54 = 123, + + WL_RATE_1X2_TXBF_MCS0 = 124, + WL_RATE_1X2_TXBF_MCS1 = 125, + WL_RATE_1X2_TXBF_MCS2 = 126, + WL_RATE_1X2_TXBF_MCS3 = 127, + WL_RATE_1X2_TXBF_MCS4 = 128, + WL_RATE_1X2_TXBF_MCS5 = 129, + WL_RATE_1X2_TXBF_MCS6 = 130, + WL_RATE_1X2_TXBF_MCS7 = 131, + + WL_RATE_1X2_TXBF_VHT0SS1 = 124, + WL_RATE_1X2_TXBF_VHT1SS1 = 125, + WL_RATE_1X2_TXBF_VHT2SS1 = 126, + WL_RATE_1X2_TXBF_VHT3SS1 = 127, + WL_RATE_1X2_TXBF_VHT4SS1 = 128, + WL_RATE_1X2_TXBF_VHT5SS1 = 129, + WL_RATE_1X2_TXBF_VHT6SS1 = 130, + WL_RATE_1X2_TXBF_VHT7SS1 = 131, + WL_RATE_1X2_TXBF_VHT8SS1 = 132, + WL_RATE_1X2_TXBF_VHT9SS1 = 133, + + /* 2 Streams */ + + WL_RATE_2X2_TXBF_SDM_MCS8 = 134, + WL_RATE_2X2_TXBF_SDM_MCS9 = 135, + WL_RATE_2X2_TXBF_SDM_MCS10 = 136, + WL_RATE_2X2_TXBF_SDM_MCS11 = 137, + WL_RATE_2X2_TXBF_SDM_MCS12 = 138, + WL_RATE_2X2_TXBF_SDM_MCS13 = 139, + WL_RATE_2X2_TXBF_SDM_MCS14 = 140, + WL_RATE_2X2_TXBF_SDM_MCS15 = 141, + + WL_RATE_2X2_TXBF_VHT0SS2 = 134, + WL_RATE_2X2_TXBF_VHT1SS2 = 135, + WL_RATE_2X2_TXBF_VHT2SS2 = 136, + WL_RATE_2X2_TXBF_VHT3SS2 = 137, + WL_RATE_2X2_TXBF_VHT4SS2 = 138, + WL_RATE_2X2_TXBF_VHT5SS2 = 139, + WL_RATE_2X2_TXBF_VHT6SS2 = 140, + WL_RATE_2X2_TXBF_VHT7SS2 = 141, + + + /**************************** + * TX Beamforming, 3 chains * + **************************** + */ + + /* 1 Stream expanded + 2 */ + + WL_RATE_1X3_TXBF_OFDM_6 = 142, + WL_RATE_1X3_TXBF_OFDM_9 = 143, + WL_RATE_1X3_TXBF_OFDM_12 = 144, + WL_RATE_1X3_TXBF_OFDM_18 = 145, + WL_RATE_1X3_TXBF_OFDM_24 = 146, + WL_RATE_1X3_TXBF_OFDM_36 = 147, + WL_RATE_1X3_TXBF_OFDM_48 = 148, + WL_RATE_1X3_TXBF_OFDM_54 = 149, + + WL_RATE_1X3_TXBF_MCS0 = 150, + WL_RATE_1X3_TXBF_MCS1 = 151, + WL_RATE_1X3_TXBF_MCS2 = 152, + WL_RATE_1X3_TXBF_MCS3 = 153, + WL_RATE_1X3_TXBF_MCS4 = 154, + WL_RATE_1X3_TXBF_MCS5 = 155, + WL_RATE_1X3_TXBF_MCS6 = 156, + WL_RATE_1X3_TXBF_MCS7 = 157, + + WL_RATE_1X3_TXBF_VHT0SS1 = 150, + WL_RATE_1X3_TXBF_VHT1SS1 = 151, + WL_RATE_1X3_TXBF_VHT2SS1 = 152, + WL_RATE_1X3_TXBF_VHT3SS1 = 153, + WL_RATE_1X3_TXBF_VHT4SS1 = 154, + WL_RATE_1X3_TXBF_VHT5SS1 = 155, + WL_RATE_1X3_TXBF_VHT6SS1 = 156, + WL_RATE_1X3_TXBF_VHT7SS1 = 157, + WL_RATE_1X3_TXBF_VHT8SS1 = 158, + WL_RATE_1X3_TXBF_VHT9SS1 = 159, + + /* 2 Streams expanded + 1 */ + + WL_RATE_2X3_TXBF_SDM_MCS8 = 160, + WL_RATE_2X3_TXBF_SDM_MCS9 = 161, + WL_RATE_2X3_TXBF_SDM_MCS10 = 162, + WL_RATE_2X3_TXBF_SDM_MCS11 = 163, + WL_RATE_2X3_TXBF_SDM_MCS12 = 164, + WL_RATE_2X3_TXBF_SDM_MCS13 = 165, + WL_RATE_2X3_TXBF_SDM_MCS14 = 166, + WL_RATE_2X3_TXBF_SDM_MCS15 = 167, + + WL_RATE_2X3_TXBF_VHT0SS2 = 160, + WL_RATE_2X3_TXBF_VHT1SS2 = 161, + WL_RATE_2X3_TXBF_VHT2SS2 = 162, + WL_RATE_2X3_TXBF_VHT3SS2 = 163, + WL_RATE_2X3_TXBF_VHT4SS2 = 164, + WL_RATE_2X3_TXBF_VHT5SS2 = 165, + WL_RATE_2X3_TXBF_VHT6SS2 = 166, + WL_RATE_2X3_TXBF_VHT7SS2 = 167, + WL_RATE_2X3_TXBF_VHT8SS2 = 168, + WL_RATE_2X3_TXBF_VHT9SS2 = 169, + + /* 3 Streams */ + + WL_RATE_3X3_TXBF_SDM_MCS16 = 170, + WL_RATE_3X3_TXBF_SDM_MCS17 = 171, + WL_RATE_3X3_TXBF_SDM_MCS18 = 172, + WL_RATE_3X3_TXBF_SDM_MCS19 = 173, + WL_RATE_3X3_TXBF_SDM_MCS20 = 174, + WL_RATE_3X3_TXBF_SDM_MCS21 = 175, + WL_RATE_3X3_TXBF_SDM_MCS22 = 176, + WL_RATE_3X3_TXBF_SDM_MCS23 = 177, + + WL_RATE_3X3_TXBF_VHT0SS3 = 170, + WL_RATE_3X3_TXBF_VHT1SS3 = 171, + WL_RATE_3X3_TXBF_VHT2SS3 = 172, + WL_RATE_3X3_TXBF_VHT3SS3 = 173, + WL_RATE_3X3_TXBF_VHT4SS3 = 174, + WL_RATE_3X3_TXBF_VHT5SS3 = 175, + WL_RATE_3X3_TXBF_VHT6SS3 = 176, + WL_RATE_3X3_TXBF_VHT7SS3 = 177 +} clm_rates_t; + +/* Number of rate codes */ +#define WL_NUMRATES 178 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _bcmwifi_rates_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmxtlv.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmxtlv.c new file mode 100644 index 000000000000..2514d965d6ab --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmxtlv.c @@ -0,0 +1,399 @@ +/* + * Driver O/S-independent utility routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: bcmxtlv.c 487603 2014-06-26 12:33:22Z $ + */ + +#include + +#include +#include + +#include + +#ifdef BCMDRIVER +#include +#else /* !BCMDRIVER */ +#include +#include +#include +#ifndef ASSERT +#define ASSERT(exp) +#endif +inline void* MALLOCZ(void *o, size_t s) { BCM_REFERENCE(o); return calloc(1, s); } +inline void MFREE(void *o, void *p, size_t s) { BCM_REFERENCE(o); BCM_REFERENCE(s); free(p); } +#endif /* !BCMDRIVER */ + +#include +#include + +bcm_xtlv_t * +bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen) +{ + int sz; + + /* validate current elt */ + if (!bcm_valid_xtlv(elt, *buflen)) + return NULL; + + /* advance to next elt */ + sz = BCM_XTLV_SIZE(elt); + elt = (bcm_xtlv_t*)((uint8 *)elt + sz); + *buflen -= sz; + + /* validate next elt */ + if (!bcm_valid_xtlv(elt, *buflen)) + return NULL; + + return elt; +} + +struct bcm_tlvbuf * +bcm_xtlv_buf_alloc(void *osh, uint16 len) +{ + struct bcm_tlvbuf *tbuf = MALLOCZ(osh, sizeof(struct bcm_tlvbuf) + len); + if (tbuf == NULL) { + return NULL; + } + tbuf->size = len; + tbuf->head = tbuf->buf = (uint8 *)(tbuf + 1); + return tbuf; +} +void +bcm_xtlv_buf_free(void *osh, struct bcm_tlvbuf *tbuf) +{ + if (tbuf == NULL) + return; + MFREE(osh, tbuf, (tbuf->size + sizeof(struct bcm_tlvbuf))); +} +uint16 +bcm_xtlv_buf_len(struct bcm_tlvbuf *tbuf) +{ + if (tbuf == NULL) return 0; + return (tbuf->buf - tbuf->head); +} +uint16 +bcm_xtlv_buf_rlen(struct bcm_tlvbuf *tbuf) +{ + if (tbuf == NULL) return 0; + return tbuf->size - bcm_xtlv_buf_len(tbuf); +} +uint8 * +bcm_xtlv_buf(struct bcm_tlvbuf *tbuf) +{ + if (tbuf == NULL) return NULL; + return tbuf->buf; +} +uint8 * +bcm_xtlv_head(struct bcm_tlvbuf *tbuf) +{ + if (tbuf == NULL) return NULL; + return tbuf->head; +} +int +bcm_xtlv_put_data(struct bcm_tlvbuf *tbuf, uint16 type, const void *data, uint16 dlen) +{ + bcm_xtlv_t *xtlv; + if (tbuf == NULL || bcm_xtlv_buf_rlen(tbuf) < (dlen + BCM_XTLV_HDR_SIZE)) + return BCME_BADARG; + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); + xtlv->id = htol16(type); + xtlv->len = htol16(dlen); + memcpy(xtlv->data, data, dlen); + tbuf->buf += BCM_XTLV_SIZE(xtlv); + return BCME_OK; +} +int +bcm_xtlv_put_8(struct bcm_tlvbuf *tbuf, uint16 type, const int8 data) +{ + bcm_xtlv_t *xtlv; + if (tbuf == NULL || bcm_xtlv_buf_rlen(tbuf) < (1 + BCM_XTLV_HDR_SIZE)) + return BCME_BADARG; + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); + xtlv->id = htol16(type); + xtlv->len = htol16(sizeof(data)); + xtlv->data[0] = data; + tbuf->buf += BCM_XTLV_SIZE(xtlv); + return BCME_OK; +} +int +bcm_xtlv_put_16(struct bcm_tlvbuf *tbuf, uint16 type, const int16 data) +{ + bcm_xtlv_t *xtlv; + if (tbuf == NULL || bcm_xtlv_buf_rlen(tbuf) < (2 + BCM_XTLV_HDR_SIZE)) + return BCME_BADARG; + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); + xtlv->id = htol16(type); + xtlv->len = htol16(sizeof(data)); + htol16_ua_store(data, xtlv->data); + tbuf->buf += BCM_XTLV_SIZE(xtlv); + return BCME_OK; +} +int +bcm_xtlv_put_32(struct bcm_tlvbuf *tbuf, uint16 type, const int32 data) +{ + bcm_xtlv_t *xtlv; + if (tbuf == NULL || bcm_xtlv_buf_rlen(tbuf) < (4 + BCM_XTLV_HDR_SIZE)) + return BCME_BADARG; + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); + xtlv->id = htol16(type); + xtlv->len = htol16(sizeof(data)); + htol32_ua_store(data, xtlv->data); + tbuf->buf += BCM_XTLV_SIZE(xtlv); + return BCME_OK; +} + +int +bcm_skip_xtlv(void **tlv_buf) +{ + bcm_xtlv_t *ptlv = *tlv_buf; + uint16 len; + uint16 type; + + ASSERT(ptlv); + /* tlv headr is always packed in LE order */ + len = ltoh16(ptlv->len); + type = ltoh16(ptlv->id); + + printf("xtlv_skip: Skipping tlv [type:%d,len:%d]\n", type, len); + + *tlv_buf += BCM_XTLV_SIZE(ptlv); + return BCME_OK; +} + +/* + * upacks xtlv record from buf checks the type + * copies data to callers buffer + * advances tlv pointer to next record + * caller's resposible for dst space check + */ +int +bcm_unpack_xtlv_entry(void **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst) +{ + bcm_xtlv_t *ptlv = *tlv_buf; + uint16 len; + uint16 type; + + ASSERT(ptlv); + /* tlv headr is always packed in LE order */ + len = ltoh16(ptlv->len); + type = ltoh16(ptlv->id); + if (len == 0) { + /* z-len tlv headers: allow, but don't process */ + printf("z-len, skip unpack\n"); + } else { + if ((type != xpct_type) || + (len > xpct_len)) { + printf("xtlv_unpack Error: found[type:%d,len:%d] != xpct[type:%d,len:%d]\n", + type, len, xpct_type, xpct_len); + return BCME_BADARG; + } + /* copy tlv record to caller's buffer */ + memcpy(dst, ptlv->data, ptlv->len); + } + *tlv_buf += BCM_XTLV_SIZE(ptlv); + return BCME_OK; +} + +/* + * packs user data into tlv record + * advances tlv pointer to next xtlv slot + * buflen is used for tlv_buf space check + */ +int +bcm_pack_xtlv_entry(void **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src) +{ + bcm_xtlv_t *ptlv = *tlv_buf; + + /* copy data from tlv buffer to dst provided by user */ + + ASSERT(ptlv); + ASSERT(src); + + if ((BCM_XTLV_HDR_SIZE + len) > *buflen) { + printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n", + ((int)BCM_XTLV_HDR_SIZE + len), *buflen); + return BCME_BADLEN; + } + ptlv->id = htol16(type); + ptlv->len = htol16(len); + + /* copy callers data */ + memcpy(ptlv->data, src, len); + + /* advance callers pointer to tlv buff */ + *tlv_buf += BCM_XTLV_SIZE(ptlv); + /* decrement the len */ + *buflen -= BCM_XTLV_SIZE(ptlv); + return BCME_OK; +} + +/* + * unpack all xtlv records from the issue a callback + * to set function one call per found tlv record + */ +int +bcm_unpack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_set_var_from_tlv_cbfn_t *cbfn) +{ + uint16 len; + uint16 type; + int res = 0; + bcm_xtlv_t *ptlv = tlv_buf; + int sbuflen = buflen; + + ASSERT(ptlv); + ASSERT(cbfn); + + while (sbuflen >= 0) { + ptlv = tlv_buf; + + /* tlv header is always packed in LE order */ + len = ltoh16(ptlv->len); + if (len == 0) /* can't be zero */ + break; + type = ltoh16(ptlv->id); + + sbuflen -= (BCM_XTLV_HDR_SIZE + len); + + /* check for possible buffer overrun */ + if (sbuflen < 0) + break; + + if ((res = cbfn(ctx, &tlv_buf, type, len)) != BCME_OK) + break; + } + return res; +} + +/* + * pack xtlv buffer from memory according to xtlv_desc_t + */ +int +bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items) +{ + int res = 0; + void *ptlv = *tlv_buf; + + while (items->len != 0) { + if ((res = bcm_pack_xtlv_entry(&ptlv, + buflen, items->type, + items->len, items->ptr) != BCME_OK)) { + break; + } + items++; + } + *tlv_buf = ptlv; /* update the external pointer */ + return res; +} + +/* + * unpack xtlv buffer to memory according to xtlv_desc_t + * + */ +int +bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items) +{ + int res = 0; + bcm_xtlv_t *elt = tlv_buf; + + /* iterate through tlvs in the buffer */ + while ((elt = bcm_next_xtlv(elt, buflen)) != NULL) { + + /* find matches in desc_t items */ + xtlv_desc_t *dst_desc = items; + while (dst_desc->len != 0) { + + if ((elt->id == dst_desc->type) && + (elt->len == dst_desc->len)) { + /* copy xtlv data to mem dst */ + memcpy(dst_desc->ptr, elt->data, elt->len); + if ((*buflen -= elt->len) < 0) { + printf("%s:Error: dst buf overrun\n", __FUNCTION__); + return BCME_NOMEM; + } + } + } + } + return res; +} + +/* + * packs user data (in hex string) into tlv record + * advances tlv pointer to next xtlv slot + * buflen is used for tlv_buf space check + */ +static int +get_ie_data(uchar *data_str, uchar *ie_data, int len) +{ + uchar *src, *dest; + uchar val; + int idx; + char hexstr[3]; + + src = data_str; + dest = ie_data; + + for (idx = 0; idx < len; idx++) { + hexstr[0] = src[0]; + hexstr[1] = src[1]; + hexstr[2] = '\0'; + +#ifdef BCMDRIVER + val = (uchar) simple_strtoul(hexstr, NULL, 16); +#else + val = (uchar) strtoul(hexstr, NULL, 16); +#endif + + *dest++ = val; + src += 2; + } + + return 0; +} + +int +bcm_pack_xtlv_entry_from_hex_string(void **tlv_buf, uint16 *buflen, uint16 type, char *hex) +{ + bcm_xtlv_t *ptlv = *tlv_buf; + uint16 len = strlen(hex)/2; + + /* copy data from tlv buffer to dst provided by user */ + + if ((BCM_XTLV_HDR_SIZE + len) > *buflen) { + printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n", + ((int)BCM_XTLV_HDR_SIZE + len), *buflen); + return BCME_BADLEN; + } + ptlv->id = htol16(type); + ptlv->len = htol16(len); + + /* copy callers data */ + if (get_ie_data((uchar*)hex, ptlv->data, len)) { + return BCME_BADARG; + } + + /* advance callers pointer to tlv buff */ + *tlv_buf += BCM_XTLV_SIZE(ptlv); + /* decrement the len */ + *buflen -= BCM_XTLV_SIZE(ptlv); + return BCME_OK; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd.h new file mode 100644 index 000000000000..f77554c2c43f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd.h @@ -0,0 +1,1338 @@ +/* + * Header file describing the internal (inter-module) DHD interfaces. + * + * Provides type definitions and function prototypes used to link the + * DHD OS, bus, and protocol modules. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd.h 701287 2017-05-24 10:33:19Z $ + */ + +/**************** + * Common types * + */ + +#ifndef _dhd_h_ +#define _dhd_h_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ +/* The kernel threading is sdio-specific */ +struct task_struct; +struct sched_param; +int setScheduler(struct task_struct *p, int policy, struct sched_param *param); +int get_scheduler_policy(struct task_struct *p); +#define MAX_EVENT 16 + +#define ALL_INTERFACES 0xff + +#include +#include + +#if defined(BCMWDF) +#include +#include +#endif /* (BCMWDF) */ + +#ifdef CONFIG_BCM_WLAN_RAMDUMP +#include +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + +#if defined(WL11U) && !defined(MFP) +#define MFP /* Applying interaction with MFP by spec HS2.0 REL2 */ +#endif /* WL11U */ + +#if defined(KEEP_ALIVE) +/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ +#define KEEP_ALIVE_PERIOD 55000 +#define NULL_PKT_STR "null_pkt" +#endif /* KEEP_ALIVE */ +/* Forward decls */ +struct dhd_bus; +struct dhd_prot; +struct dhd_info; +struct dhd_ioctl; + +/* The level of bus communication with the dongle */ +enum dhd_bus_state { + DHD_BUS_DOWN, /* Not ready for frame transfers */ + DHD_BUS_LOAD, /* Download access only (CPU reset) */ + DHD_BUS_DATA, /* Ready for frame transfers */ + DHD_BUS_SUSPEND, /* Bus has been suspended */ +}; + + +#define DHD_IF_ROLE_STA(role) (role == WLC_E_IF_ROLE_STA ||\ + role == WLC_E_IF_ROLE_P2P_CLIENT) + +/* For supporting multiple interfaces */ +#define DHD_MAX_IFS 16 +#define DHD_DEL_IF -0xE +#define DHD_BAD_IF -0xF + +enum dhd_op_flags { +/* Firmware requested operation mode */ + DHD_FLAG_STA_MODE = (1 << (0)), /* STA only */ + DHD_FLAG_HOSTAP_MODE = (1 << (1)), /* SOFTAP only */ + DHD_FLAG_P2P_MODE = (1 << (2)), /* P2P Only */ + /* STA + P2P */ + DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), + DHD_FLAG_CONCURR_MULTI_CHAN_MODE = (1 << (4)), /* STA + P2P */ + /* Current P2P mode for P2P connection */ + DHD_FLAG_P2P_GC_MODE = (1 << (5)), + DHD_FLAG_P2P_GO_MODE = (1 << (6)), + DHD_FLAG_MBSS_MODE = (1 << (7)), /* MBSS in future */ + DHD_FLAG_IBSS_MODE = (1 << (8)), + DHD_FLAG_MFG_MODE = (1 << (9)) +}; + +/* Max sequential TX/RX Control timeouts to set HANG event */ +#ifndef MAX_CNTL_TX_TIMEOUT +#define MAX_CNTL_TX_TIMEOUT 2 +#endif /* MAX_CNTL_TX_TIMEOUT */ +#ifndef MAX_CNTL_RX_TIMEOUT +#define MAX_CNTL_RX_TIMEOUT 1 +#endif /* MAX_CNTL_RX_TIMEOUT */ + +#ifdef BCMPCIE +#ifndef MAX_CNTL_D3ACK_TIMEOUT +#define MAX_CNTL_D3ACK_TIMEOUT 2 +#endif /* MAX_CNTL_D3ACK_TIMEOUT */ +#endif /* BCMPCIE */ + +#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ +#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ +#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ + +#ifndef POWERUP_MAX_RETRY +#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ +#endif +#ifndef POWERUP_WAIT_MS +#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ +#endif + +enum dhd_bus_wake_state { + WAKE_LOCK_OFF, + WAKE_LOCK_PRIV, + WAKE_LOCK_DPC, + WAKE_LOCK_IOCTL, + WAKE_LOCK_DOWNLOAD, + WAKE_LOCK_TMOUT, + WAKE_LOCK_WATCHDOG, + WAKE_LOCK_LINK_DOWN_TMOUT, + WAKE_LOCK_PNO_FIND_TMOUT, + WAKE_LOCK_SOFTAP_SET, + WAKE_LOCK_SOFTAP_STOP, + WAKE_LOCK_SOFTAP_START, + WAKE_LOCK_SOFTAP_THREAD +}; + +enum dhd_prealloc_index { + DHD_PREALLOC_PROT = 0, + DHD_PREALLOC_RXBUF, + DHD_PREALLOC_DATABUF, + DHD_PREALLOC_OSL_BUF, +#if defined(STATIC_WL_PRIV_STRUCT) + DHD_PREALLOC_WIPHY_ESCAN0 = 5, +#endif /* STATIC_WL_PRIV_STRUCT */ + DHD_PREALLOC_DHD_INFO = 7, + DHD_PREALLOC_DHD_WLFC_INFO = 8, + DHD_PREALLOC_IF_FLOW_LKUP = 9, + /* 10 */ + DHD_PREALLOC_MEMDUMP_RAM = 11, + DHD_PREALLOC_PKTID_MAP = 12 +}; + +/* Packet alignment for most efficient SDIO (can change based on platform) */ +#ifndef DHD_SDALIGN +#define DHD_SDALIGN 32 +#endif + +/* host reordering packts logic */ +/* followed the structure to hold the reorder buffers (void **p) */ +typedef struct reorder_info { + void **p; + uint8 flow_id; + uint8 cur_idx; + uint8 exp_idx; + uint8 max_idx; + uint8 pend_pkts; +} reorder_info_t; + +#ifdef DHDTCPACK_SUPPRESS + +enum { + /* TCPACK suppress off */ + TCPACK_SUP_OFF, + /* Replace TCPACK in txq when new coming one has higher ACK number. */ + TCPACK_SUP_REPLACE, + /* TCPACK_SUP_REPLACE + delayed TCPACK TX unless ACK to PSH DATA. + * This will give benefits to Half-Duplex bus interface(e.g. SDIO) that + * 1. we are able to read TCP DATA packets first from the bus + * 2. TCPACKs that don't need to hurry delivered remains longer in TXQ so can be suppressed. + */ + TCPACK_SUP_DELAYTX, + TCPACK_SUP_HOLD, + TCPACK_SUP_LAST_MODE +}; +#endif /* DHDTCPACK_SUPPRESS */ + + +/* DMA'ing r/w indices for rings supported */ +#ifdef BCM_INDX_TCM /* FW gets r/w indices in TCM */ +#define DMA_INDX_ENAB(dma_indxsup) 0 +#elif defined BCM_INDX_DMA /* FW gets r/w indices from Host memory */ +#define DMA_INDX_ENAB(dma_indxsup) 1 +#else /* r/w indices in TCM or host memory based on FW/Host agreement */ +#define DMA_INDX_ENAB(dma_indxsup) dma_indxsup +#endif /* BCM_INDX_TCM */ + +#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) +struct tdls_peer_node { + uint8 addr[ETHER_ADDR_LEN]; + struct tdls_peer_node *next; +}; +typedef struct tdls_peer_node tdls_peer_node_t; +typedef struct { + tdls_peer_node_t *node; + uint8 tdls_peer_count; +} tdls_peer_tbl_t; +#endif /* defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */ + +/* Common structure for module and instance linkage */ +typedef struct dhd_pub { + /* Linkage ponters */ + osl_t *osh; /* OSL handle */ + struct dhd_bus *bus; /* Bus module handle */ + struct dhd_prot *prot; /* Protocol module handle */ + struct dhd_info *info; /* Info module handle */ + + /* to NDIS developer, the structure dhd_common is redundant, + * please do NOT merge it back from other branches !!! + */ + + + /* Internal dhd items */ + bool up; /* Driver up/down (to OS) */ + bool txoff; /* Transmit flow-controlled */ + bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ + uint8 ioctl_state; + + enum dhd_bus_state busstate; + uint hdrlen; /* Total DHD header length (proto + bus) */ + uint maxctl; /* Max size rxctl request from proto to bus */ + uint rxsz; /* Rx buffer size bus module should use */ + uint8 wme_dp; /* wme discard priority */ + + /* Dongle media info */ + bool iswl; /* Dongle-resident driver is wl */ + ulong drv_version; /* Version of dongle-resident driver */ + struct ether_addr mac; /* MAC address obtained from dongle */ + dngl_stats_t dstats; /* Stats for dongle-based data */ + + /* Additional stats for the bus level */ + ulong tx_packets; /* Data packets sent to dongle */ + ulong tx_dropped; /* Data packets dropped in dhd */ + ulong tx_multicast; /* Multicast data packets sent to dongle */ + ulong tx_errors; /* Errors in sending data to dongle */ + ulong tx_ctlpkts; /* Control packets sent to dongle */ + ulong tx_ctlerrs; /* Errors sending control frames to dongle */ + ulong rx_packets; /* Packets sent up the network interface */ + ulong rx_multicast; /* Multicast packets sent up the network interface */ + ulong rx_errors; /* Errors processing rx data packets */ + ulong rx_ctlpkts; /* Control frames processed from dongle */ + ulong rx_ctlerrs; /* Errors in processing rx control frames */ + ulong rx_dropped; /* Packets dropped locally (no memory) */ + ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ + ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ + + ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ + ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ + ulong fc_packets; /* Number of flow control pkts recvd */ + + /* Last error return */ + int bcmerror; + uint tickcnt; + + /* Last error from dongle */ + int dongle_error; + + uint8 country_code[WLC_CNTRY_BUF_SZ]; + + /* Suspend disable flag and "in suspend" flag */ + int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ + int in_suspend; /* flag set to 1 when early suspend called */ +#ifdef PNO_SUPPORT + int pno_enable; /* pno status : "1" is pno enable */ + int pno_suspend; /* pno suspend status : "1" is pno suspended */ +#endif /* PNO_SUPPORT */ + /* DTIM skip value, default 0(or 1) means wake each DTIM + * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) + */ + int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ +#ifdef PKT_FILTER_SUPPORT + int early_suspended; /* Early suspend status */ + int dhcp_in_progress; /* DHCP period */ +#endif + + /* Pkt filter defination */ + char * pktfilter[100]; + int pktfilter_count; + + wl_country_t dhd_cspec; /* Current Locale info */ +#ifdef CUSTOM_FORCE_NODFS_FLAG + uint dhd_cflags; +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + bool force_country_change; + char eventmask[WL_EVENTING_MASK_LEN]; + int op_mode; /* STA, HostAPD, WFD, SoftAP */ + +/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. + * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework + * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile + */ +/* #define WL_ENABLE_P2P_IF 1 */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ + struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ +#endif + +#ifdef PROP_TXSTATUS + bool wlfc_enabled; + int wlfc_mode; + void* wlfc_state; + /* + Mode in which the dhd flow control shall operate. Must be set before + traffic starts to the device. + 0 - Do not do any proptxtstatus flow control + 1 - Use implied credit from a packet status + 2 - Use explicit credit + 3 - Only AMPDU hostreorder used. no wlfc. + */ + uint8 proptxstatus_mode; + bool proptxstatus_txoff; + bool proptxstatus_module_ignore; + bool proptxstatus_credit_ignore; + bool proptxstatus_txstatus_ignore; + + bool wlfc_rxpkt_chk; + /* + * implement below functions in each platform if needed. + */ + /* platform specific function whether to skip flow control */ + bool (*skip_fc)(void); + /* platform specific function for wlfc_enable and wlfc_deinit */ + void (*plat_init)(void *dhd); + void (*plat_deinit)(void *dhd); +#endif /* PROP_TXSTATUS */ +#ifdef PNO_SUPPORT + void *pno_state; +#endif +#ifdef RTT_SUPPORT + void *rtt_state; +#endif +#ifdef ROAM_AP_ENV_DETECTION + bool roam_env_detection; +#endif + bool dongle_isolation; + bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ + int hang_was_sent; + int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ + int txcnt_timeout; /* counter txcnt timeout to send HANG */ +#ifdef BCMPCIE + int d3ackcnt_timeout; /* counter d3ack timeout to send HANG */ +#endif /* BCMPCIE */ + bool hang_report; /* enable hang report by default */ +#ifdef WLMEDIA_HTSF + uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ +#endif +#ifdef WLTDLS + bool tdls_enable; +#endif + struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; + char fw_capabilities[WLC_IOCTL_SMLEN]; + #define MAXSKBPEND 1024 + void *skbbuf[MAXSKBPEND]; + uint32 store_idx; + uint32 sent_idx; +#ifdef DHDTCPACK_SUPPRESS + uint8 tcpack_sup_mode; /* TCPACK suppress mode */ + void *tcpack_sup_module; /* TCPACK suppress module */ + uint32 tcpack_sup_ratio; + uint32 tcpack_sup_delay; +#endif /* DHDTCPACK_SUPPRESS */ +#if defined(ARP_OFFLOAD_SUPPORT) + uint32 arp_version; +#endif +#ifdef CUSTOM_SET_CPUCORE + struct task_struct * current_dpc; + struct task_struct * current_rxf; + int chan_isvht80; +#endif /* CUSTOM_SET_CPUCORE */ + + void *sta_pool; /* pre-allocated pool of sta objects */ + void *staid_allocator; /* allocator of sta indexes */ + + void *flowid_allocator; /* unique flowid allocator */ + void *flow_ring_table; /* flow ring table, include prot and bus info */ + void *if_flow_lkup; /* per interface flowid lkup hash table */ + void *flowid_lock; /* per os lock for flowid info protection */ + uint32 num_flow_rings; + + uint32 d2h_sync_mode; /* D2H DMA completion sync mode */ + + uint8 flow_prio_map[NUMPRIO]; + uint8 flow_prio_map_type; + char enable_log[MAX_EVENT]; + bool dma_d2h_ring_upd_support; + bool dma_h2d_ring_upd_support; +#ifdef DHD_WMF + bool wmf_ucast_igmp; +#ifdef DHD_IGMP_UCQUERY + bool wmf_ucast_igmp_query; +#endif +#ifdef DHD_UCAST_UPNP + bool wmf_ucast_upnp; +#endif +#endif /* DHD_WMF */ +#ifdef DHD_UNICAST_DHCP + bool dhcp_unicast; +#endif /* DHD_UNICAST_DHCP */ +#ifdef DHD_L2_FILTER + bool block_ping; +#endif +#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) + tdls_peer_tbl_t peer_tbl; +#endif /* defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */ +#ifdef CONFIG_BCM_WLAN_RAMDUMP + char crash_reason[BCM_WLAN_CRASH_REASON_LEN]; +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ +#ifdef GSCAN_SUPPORT + bool lazy_roam_enable; +#endif /* GSCAN_SUPPORT */ + uint8 *soc_ram; + uint32 soc_ram_length; + bool tx_in_progress; + uint8 rand_mac_oui[DOT11_OUI_LEN]; +} dhd_pub_t; + +#if defined(BCMWDF) +typedef struct { + dhd_pub_t *dhd_pub; +} dhd_workitem_context_t; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(dhd_workitem_context_t, dhd_get_dhd_workitem_context) +#endif /* (BCMWDF) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) + +#define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); +#define _DHD_PM_RESUME_WAIT(a, b) do {\ + int retry = 0; \ + SMP_RD_BARRIER_DEPENDS(); \ + while (dhd_mmc_suspend && retry++ != b) { \ + SMP_RD_BARRIER_DEPENDS(); \ + wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ + } \ + } while (0) +#define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) +#define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) +#define DHD_PM_RESUME_RETURN_ERROR(a) do { \ + if (dhd_mmc_suspend) return a; } while (0) +#define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) + +#define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); +#define SPINWAIT_SLEEP(a, exp, us) do { \ + uint countdown = (us) + 9999; \ + while ((exp) && (countdown >= 10000)) { \ + wait_event_interruptible_timeout(a, FALSE, 1); \ + countdown -= 10000; \ + } \ +} while (0) + +#else + +#define DHD_PM_RESUME_WAIT_INIT(a) +#define DHD_PM_RESUME_WAIT(a) +#define DHD_PM_RESUME_WAIT_FOREVER(a) +#define DHD_PM_RESUME_RETURN_ERROR(a) +#define DHD_PM_RESUME_RETURN + +#define DHD_SPINWAIT_SLEEP_INIT(a) +#define SPINWAIT_SLEEP(a, exp, us) do { \ + uint countdown = (us) + 9; \ + while ((exp) && (countdown >= 10)) { \ + OSL_DELAY(10); \ + countdown -= 10; \ + } \ +} while (0) + +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + +#ifdef CONFIG_BCM_WLAN_RAMDUMP +extern char bcm_wlan_ver_info[BCM_WLAN_CRASH_REASON_LEN]; +#define bcm_add_crash_reason(dst, fmt, ...) do { \ + int rest = 0; \ + int pos = strnlen(dst, sizeof(dst)); \ + if (pos == 0) \ + pos += snprintf(&dst[0], sizeof(dst), "%s", bcm_wlan_ver_info); \ + rest = sizeof(dst) - pos; \ + if (rest > 1) { \ + snprintf(&dst[pos], rest, (fmt), ##__VA_ARGS__); \ + } \ + } while (0) +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + +#ifndef OSL_SLEEP +#define OSL_SLEEP(ms) OSL_DELAY(ms*1000) +#endif /* OSL_SLEEP */ + +#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ + +#ifdef PNO_SUPPORT +int dhd_pno_clean(dhd_pub_t *dhd); +#endif /* PNO_SUPPORT */ +/* + * Wake locks are an Android power management concept. They are used by applications and services + * to request CPU resources. + */ +extern int dhd_os_wake_lock(dhd_pub_t *pub); +extern int dhd_os_wake_unlock(dhd_pub_t *pub); +extern int dhd_os_wake_lock_waive(dhd_pub_t *pub); +extern int dhd_os_wake_lock_restore(dhd_pub_t *pub); +extern void dhd_os_wake_lock_init(struct dhd_info *dhd); +extern void dhd_os_wake_lock_destroy(struct dhd_info *dhd); +extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); +extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); +extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); +extern int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub); +extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); +extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); +extern int dhd_event_wake_lock(dhd_pub_t *pub); +extern int dhd_event_wake_unlock(dhd_pub_t *pub); +extern void dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val); +extern void dhd_txfl_wake_unlock(dhd_pub_t *pub); + +#ifdef BCMPCIE_OOB_HOST_WAKE +extern int dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val); +extern int dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + +inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_init(&dhdp->wl_softap_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +} + +inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_lock(&dhdp->wl_softap_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +} + +inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_unlock(&dhdp->wl_softap_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +} + +#ifdef DHD_DEBUG_WAKE_LOCK +#define DHD_OS_WAKE_LOCK(pub) \ + do { \ + printf("call wake_lock: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_lock(pub); \ + } while (0) +#define DHD_OS_WAKE_UNLOCK(pub) \ + do { \ + printf("call wake_unlock: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_unlock(pub); \ + } while (0) +#define DHD_EVENT_WAKE_LOCK(pub) \ + do { \ + printf("call event wake_lock: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_event_wake_lock(pub); \ + } while (0) +#define DHD_EVENT_WAKE_UNLOCK(pub) \ + do { \ + printf("call event wake_unlock: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_event_wake_unlock(pub); \ + } while (0) +#define DHD_TXFL_WAKE_LOCK_TIMEOUT(pub, val) \ + do { \ + printf("call txfl wake_lock_timeout[%d]: %s %d\n", \ + val, __FUNCTION__, __LINE__); \ + dhd_txfl_wake_lock_timeout(pub, val); \ + } while (0) +#define DHD_TXFL_WAKE_UNLOCK(pub) \ + do { \ + printf("call txfl wake_unlock: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_txfl_wake_unlock(pub); \ + } while (0) +#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) \ + do { \ + printf("call wake_lock_timeout: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_lock_timeout(pub); \ + } while (0) +#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ + do { \ + printf("call wake_lock_rx_timeout_enable[%d]: %s %d\n", \ + val, __FUNCTION__, __LINE__); \ + dhd_os_wake_lock_rx_timeout_enable(pub, val); \ + } while (0) +#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ + do { \ + printf("call wake_lock_ctrl_timeout_enable[%d]: %s %d\n", \ + val, __FUNCTION__, __LINE__); \ + dhd_os_wake_lock_ctrl_timeout_enable(pub, val); \ + } while (0) +#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \ + do { \ + printf("call wake_lock_ctrl_timeout_cancel: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_lock_ctrl_timeout_cancel(pub); \ + } while (0) +#define DHD_OS_WAKE_LOCK_WAIVE(pub) \ + do { \ + printf("call wake_lock_waive: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_lock_waive(pub); \ + } while (0) +#define DHD_OS_WAKE_LOCK_RESTORE(pub) \ + do { \ + printf("call wake_lock_restore: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_lock_restore(pub); \ + } while (0) +#define DHD_OS_WAKE_LOCK_INIT(dhd) \ + do { \ + printf("call wake_lock_init: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_lock_init(dhd); \ + } while (0) +#define DHD_OS_WAKE_LOCK_DESTROY(dhd) \ + do { \ + printf("call wake_lock_destroy: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_os_wake_lock_destroy(dhd); \ + } while (0) +#else +#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) +#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) +#define DHD_EVENT_WAKE_LOCK(pub) dhd_event_wake_lock(pub) +#define DHD_EVENT_WAKE_UNLOCK(pub) dhd_event_wake_unlock(pub) +#define DHD_TXFL_WAKE_LOCK_TIMEOUT(pub, val) dhd_txfl_wake_lock_timeout(pub, val) +#define DHD_TXFL_WAKE_UNLOCK(pub) dhd_txfl_wake_unlock(pub) +#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) +#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ + dhd_os_wake_lock_rx_timeout_enable(pub, val) +#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ + dhd_os_wake_lock_ctrl_timeout_enable(pub, val) +#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \ + dhd_os_wake_lock_ctrl_timeout_cancel(pub) +#define DHD_OS_WAKE_LOCK_WAIVE(pub) dhd_os_wake_lock_waive(pub) +#define DHD_OS_WAKE_LOCK_RESTORE(pub) dhd_os_wake_lock_restore(pub) +#define DHD_OS_WAKE_LOCK_INIT(dhd) dhd_os_wake_lock_init(dhd) +#define DHD_OS_WAKE_LOCK_DESTROY(dhd) dhd_os_wake_lock_destroy(dhd) +#endif /* DHD_DEBUG_WAKE_LOCK */ + +#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub) +#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub) +#ifdef BCMPCIE_OOB_HOST_WAKE +#define OOB_WAKE_LOCK_TIMEOUT 500 +#define DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(pub, val) dhd_os_oob_irq_wake_lock_timeout(pub, val) +#define DHD_OS_OOB_IRQ_WAKE_UNLOCK(pub) dhd_os_oob_irq_wake_unlock(pub) +#endif /* BCMPCIE_OOB_HOST_WAKE */ +#define DHD_PACKET_TIMEOUT_MS 500 +#define DHD_EVENT_TIMEOUT_MS 1500 +#define MAX_TX_TIMEOUT 500 + +/* interface operations (register, remove) should be atomic, use this lock to prevent race + * condition among wifi on/off and interface operation functions + */ +void dhd_net_if_lock(struct net_device *dev); +void dhd_net_if_unlock(struct net_device *dev); + + +typedef enum dhd_attach_states +{ + DHD_ATTACH_STATE_INIT = 0x0, + DHD_ATTACH_STATE_NET_ALLOC = 0x1, + DHD_ATTACH_STATE_DHD_ALLOC = 0x2, + DHD_ATTACH_STATE_ADD_IF = 0x4, + DHD_ATTACH_STATE_PROT_ATTACH = 0x8, + DHD_ATTACH_STATE_WL_ATTACH = 0x10, + DHD_ATTACH_STATE_THREADS_CREATED = 0x20, + DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, + DHD_ATTACH_STATE_CFG80211 = 0x80, + DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, + DHD_ATTACH_STATE_DONE = 0x200 +} dhd_attach_states_t; + +/* Value -1 means we are unsuccessful in creating the kthread. */ +#define DHD_PID_KT_INVALID -1 +/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ +#define DHD_PID_KT_TL_INVALID -2 + +/* + * Exported from dhd OS modules (dhd_linux/dhd_ndis) + */ + +/* Indication from bus module regarding presence/insertion of dongle. + * Return dhd_pub_t 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 dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); +#if defined(WLP2P) && defined(WL_CFG80211) +/* To allow attach/detach calls corresponding to p2p0 interface */ +extern int dhd_attach_p2p(dhd_pub_t *); +extern int dhd_detach_p2p(dhd_pub_t *); +#endif /* WLP2P && WL_CFG80211 */ +extern int dhd_register_if(dhd_pub_t *dhdp, int idx, bool need_rtnl_lock); + +/* Indication from bus module regarding removal/absence of dongle */ +extern void dhd_detach(dhd_pub_t *dhdp); +extern void dhd_free(dhd_pub_t *dhdp); +extern void dhd_clear(dhd_pub_t *dhdp); + +/* Indication from bus module to change flow-control state */ +extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); + +/* Store the status of a connection attempt for later retrieval by an iovar */ +extern void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason); + +extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); + +/* Receive frame for delivery to OS. Callee disposes of rxp. */ +extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); + +/* Return pointer to interface name */ +extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); + +/* Request scheduling of the bus dpc */ +extern void dhd_sched_dpc(dhd_pub_t *dhdp); + +/* Notify tx completion */ +extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); + +#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */ +#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */ +#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */ +#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */ +#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */ +#define WIFI_FEATURE_GSCAN 0x0020 /* Google-Scan APIs */ +#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness Networking */ +#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */ +#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */ +#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */ +#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */ +#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */ +#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link setup */ +#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off channel */ +#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */ +#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA Concurrency */ +#define WIFI_FEATURE_LINKSTAT 0x10000 /* Support for Linkstats */ +#define WIFI_FEATURE_HAL_EPNO 0x40000 /* WiFi PNO enhanced */ +#define WIFI_FEATURE_RSSI_MONITOR 0x80000 /* RSSI Monitor */ + +#define MAX_FEATURE_SET_CONCURRRENT_GROUPS 3 + +extern int dhd_dev_get_feature_set(struct net_device *dev); +extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); +#ifdef CUSTOM_FORCE_NODFS_FLAG +extern int dhd_dev_set_nodfs(struct net_device *dev, uint nodfs); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +extern int dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui); +extern int dhd_set_rand_mac_oui(dhd_pub_t *dhd); + +#ifdef GSCAN_SUPPORT +extern int dhd_dev_set_lazy_roam_cfg(struct net_device *dev, + wlc_roam_exp_params_t *roam_param); +extern int dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable); +extern int dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, + wl_bssid_pref_cfg_t *bssid_pref, uint32 flush); +extern int dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, + uint32 len, uint32 flush); +extern int dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *whitelist, + uint32 len, uint32 flush); +#endif /* GSCAN_SUPPORT */ + +extern int dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, + int8 max_rssi, int8 min_rssi); + +#define DHD_RSSI_MONITOR_EVT_VERSION 1 +typedef struct { + uint8 version; + int8 cur_rssi; + struct ether_addr BSSID; +} dhd_rssi_monitor_evt_t; + +/* OS independent layer functions */ +extern int dhd_os_proto_block(dhd_pub_t * pub); +extern int dhd_os_proto_unblock(dhd_pub_t * pub); +extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending); +extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); +extern unsigned int dhd_os_get_ioctl_resp_timeout(void); +extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); + +extern int dhd_os_get_image_block(char * buf, int len, void * image); +extern void * dhd_os_open_image(char * filename); +extern void dhd_os_close_image(void * image); +extern void dhd_os_wd_timer(void *bus, uint wdtick); +extern void dhd_os_sdlock(dhd_pub_t * pub); +extern void dhd_os_sdunlock(dhd_pub_t * pub); +extern void dhd_os_sdlock_txq(dhd_pub_t * pub); +extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); +extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); +extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); +extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); +#ifdef DHDTCPACK_SUPPRESS +extern void dhd_os_tcpacklock(dhd_pub_t *pub); +extern void dhd_os_tcpackunlock(dhd_pub_t *pub); +#endif /* DHDTCPACK_SUPPRESS */ + +extern int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr); +extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff); +#ifdef GET_CUSTOM_MAC_ENABLE +extern int somc_get_mac_address(unsigned char *buf); +#endif /* GET_CUSTOM_MAC_ENABLE */ +extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf); +#ifdef CUSTOM_FORCE_NODFS_FLAG +extern void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec, u32 flags); +#else +extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); +extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); +extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); +extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); +extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); +extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); +extern bool dhd_os_check_if_up(dhd_pub_t *pub); +extern int dhd_os_check_wakelock(dhd_pub_t *pub); +extern int dhd_os_check_wakelock_all(dhd_pub_t *pub); +extern int dhd_get_instance(dhd_pub_t *pub); +#ifdef CUSTOM_SET_CPUCORE +extern void dhd_set_cpucore(dhd_pub_t *dhd, int set); +#endif /* CUSTOM_SET_CPUCORE */ + +#if defined(KEEP_ALIVE) +extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); +#endif /* KEEP_ALIVE */ + +#if defined(DHD_FW_COREDUMP) +void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size); +#endif /* DHD_FW_COREDUMP */ + + + + +#ifdef PKT_FILTER_SUPPORT +#define DHD_UNICAST_FILTER_NUM 0 +#define DHD_BROADCAST_FILTER_NUM 1 +#define DHD_MULTICAST4_FILTER_NUM 2 +#define DHD_MULTICAST6_FILTER_NUM 3 +#define DHD_MDNS_FILTER_NUM 4 +#define DHD_ARP_FILTER_NUM 5 + + +extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val); +extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); +extern int net_os_enable_packet_filter(struct net_device *dev, int val); +extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); +#endif /* PKT_FILTER_SUPPORT */ + +extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); +extern bool dhd_support_sta_mode(dhd_pub_t *dhd); + +extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); + +typedef struct { + uint32 limit; /* Expiration time (usec) */ + uint32 increment; /* Current expiration increment (usec) */ + uint32 elapsed; /* Current elapsed time (usec) */ + uint32 tick; /* O/S tick time (usec) */ +} dhd_timeout_t; + +#ifdef SHOW_LOGTRACE +typedef struct { + int num_fmts; + char **fmts; + char *raw_fmts; +} dhd_event_log_t; +#endif /* SHOW_LOGTRACE */ + +#if defined(KEEP_ALIVE) +extern int dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, + u16 ip_pkt_len, u8* src_mac_addr, u8* dst_mac_addr, u32 period_msec); +extern int dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id); +#endif /* defined(KEEP_ALIVE) */ + +extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); +extern int dhd_timeout_expired(dhd_timeout_t *tmo); + +extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); +extern int dhd_ifidx2hostidx(struct dhd_info *dhd, int ifidx); +extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); +extern struct net_device * dhd_idx2net(void *pub, int ifidx); +extern int net_os_send_hang_message(struct net_device *dev); +extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, size_t pktlen, + wl_event_msg_t *, void **data_ptr, void *); +extern void wl_event_to_host_order(wl_event_msg_t * evt); +extern int wl_host_event_get_data(void *pktdata, uint pktlen, void *evt); + +extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); +extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, + int ifindex); +extern void dhd_common_init(osl_t *osh); + +extern int dhd_do_driver_init(struct net_device *net); +extern int dhd_event_ifadd(struct dhd_info *dhd, struct wl_event_data_if *ifevent, + char *name, uint8 *mac); +extern int dhd_event_ifdel(struct dhd_info *dhd, struct wl_event_data_if *ifevent, + char *name, uint8 *mac); +extern struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name, + uint8 *mac, uint8 bssidx, bool need_rtnl_lock); +extern int dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock); +extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); +extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); +extern void dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx); +extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); + +/* Send packet to dongle via data channel */ +extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); + +/* send up locally generated event */ +extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); +/* Send event to host */ +extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); +#ifdef LOG_INTO_TCPDUMP +extern void dhd_sendup_log(dhd_pub_t *dhdp, void *data, int len); +#endif /* LOG_INTO_TCPDUMP */ +extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); +extern uint dhd_bus_status(dhd_pub_t *dhdp); +extern int dhd_bus_start(dhd_pub_t *dhdp); +extern int dhd_bus_suspend(dhd_pub_t *dhdpub); +extern int dhd_bus_resume(dhd_pub_t *dhdpub, int stage); +extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); +extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); +extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); +#if defined(BCMSDIO) || defined(BCMPCIE) +extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); +extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); +extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); +#endif /* defined(BCMSDIO) || defined(BCMPCIE) */ + +#if defined(KEEP_ALIVE) +extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); +#endif /* KEEP_ALIVE */ + +/* OS spin lock API */ +extern void *dhd_os_spin_lock_init(osl_t *osh); +extern void dhd_os_spin_lock_deinit(osl_t *osh, void *lock); +extern unsigned long dhd_os_spin_lock(void *lock); +void dhd_os_spin_unlock(void *lock, unsigned long flags); + +/* + * Manage sta objects in an interface. Interface is identified by an ifindex and + * sta(s) within an interfaces are managed using a MacAddress of the sta. + */ +struct dhd_sta; +extern struct dhd_sta *dhd_findadd_sta(void *pub, int ifidx, void *ea); +extern void dhd_del_sta(void *pub, int ifidx, void *ea); +extern int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx); +extern int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val); +extern int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx); +extern int dhd_os_d3ack_wait(dhd_pub_t * pub, uint * condition, bool * pending); +extern int dhd_os_d3ack_wake(dhd_pub_t * pub); + +extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); +int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, + char *res_buf, uint res_len, int set); +extern int dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, + uint cmd_len, char **resptr, uint resp_len); +typedef enum cust_gpio_modes { + WLAN_RESET_ON, + WLAN_RESET_OFF, + WLAN_POWER_ON, + WLAN_POWER_OFF +} cust_gpio_modes_t; + +extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); +extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); +/* + * Insmod parameters for debug/test + */ + +/* Watchdog timer interval */ +extern uint dhd_watchdog_ms; + +#if defined(DHD_DEBUG) +/* Console output poll interval */ +extern uint dhd_console_ms; +extern uint wl_msg_level; +#endif /* defined(DHD_DEBUG) */ + +extern uint dhd_slpauto; + +/* Use interrupts */ +extern uint dhd_intr; + +/* Use polling */ +extern uint dhd_poll; + +/* ARP offload agent mode */ +extern uint dhd_arp_mode; + +/* ARP offload enable */ +extern uint dhd_arp_enable; + +/* Pkt filte enable control */ +extern uint dhd_pkt_filter_enable; + +/* Pkt filter init setup */ +extern uint dhd_pkt_filter_init; + +/* Pkt filter mode control */ +extern uint dhd_master_mode; + +/* Roaming mode control */ +extern uint dhd_roam_disable; + +/* Roaming mode control */ +extern uint dhd_radio_up; + +/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ +extern int dhd_idletime; +#ifdef DHD_USE_IDLECOUNT +#define DHD_IDLETIME_TICKS 5 +#else +#define DHD_IDLETIME_TICKS 1 +#endif /* DHD_USE_IDLECOUNT */ + +/* SDIO Drive Strength */ +extern uint dhd_sdiod_drive_strength; + +/* Override to force tx queueing all the time */ +extern uint dhd_force_tx_queueing; +/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ +#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */ +#ifndef CUSTOM_KEEP_ALIVE_SETTING +#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE +#endif /* DEFAULT_KEEP_ALIVE_VALUE */ + +#define NULL_PKT_STR "null_pkt" + +/* hooks for custom glom setting option via Makefile */ +#define DEFAULT_GLOM_VALUE -1 +#ifndef CUSTOM_GLOM_SETTING +#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE +#endif +#define WL_AUTO_ROAM_TRIGGER -75 +/* hooks for custom Roaming Trigger setting via Makefile */ +#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ +#define DEFAULT_ROAM_TRIGGER_SETTING -1 +#ifndef CUSTOM_ROAM_TRIGGER_SETTING +#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE +#endif + +/* hooks for custom Roaming Romaing setting via Makefile */ +#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ +#define DEFAULT_ROAM_DELTA_SETTING -1 +#ifndef CUSTOM_ROAM_DELTA_SETTING +#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE +#endif + +/* hooks for custom PNO Event wake lock to guarantee enough time + for the Platform to detect Event before system suspended +*/ +#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */ +#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME +#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME +#endif +/* hooks for custom dhd_dpc_prio setting option via Makefile */ +#define DEFAULT_DHP_DPC_PRIO 1 +#ifndef CUSTOM_DPC_PRIO_SETTING +#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO +#endif + +#ifndef CUSTOM_LISTEN_INTERVAL +#define CUSTOM_LISTEN_INTERVAL LISTEN_INTERVAL +#endif /* CUSTOM_LISTEN_INTERVAL */ + +#define DEFAULT_SUSPEND_BCN_LI_DTIM 3 +#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM +#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM +#endif + +#ifndef CUSTOM_RXF_PRIO_SETTING +#define CUSTOM_RXF_PRIO_SETTING MAX((CUSTOM_DPC_PRIO_SETTING - 1), 1) +#endif + +#define DEFAULT_WIFI_TURNOFF_DELAY 0 +#ifndef WIFI_TURNOFF_DELAY +#define WIFI_TURNOFF_DELAY DEFAULT_WIFI_TURNOFF_DELAY +#endif /* WIFI_TURNOFF_DELAY */ + +#define DEFAULT_WIFI_TURNON_DELAY 200 +#ifndef WIFI_TURNON_DELAY +#define WIFI_TURNON_DELAY DEFAULT_WIFI_TURNON_DELAY +#endif /* WIFI_TURNON_DELAY */ + +#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS 10 /* msec */ +#ifndef CUSTOM_DHD_WATCHDOG_MS +#define CUSTOM_DHD_WATCHDOG_MS DEFAULT_DHD_WATCHDOG_INTERVAL_MS +#endif /* DEFAULT_DHD_WATCHDOG_INTERVAL_MS */ + +#ifdef WLTDLS +#ifndef CUSTOM_TDLS_IDLE_MODE_SETTING +#define CUSTOM_TDLS_IDLE_MODE_SETTING 60000 /* 60sec to tear down TDLS of not active */ +#endif +#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_HIGH +#define CUSTOM_TDLS_RSSI_THRESHOLD_HIGH -70 /* rssi threshold for establishing TDLS link */ +#endif +#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_LOW +#define CUSTOM_TDLS_RSSI_THRESHOLD_LOW -80 /* rssi threshold for tearing down TDLS link */ +#endif +#endif /* WLTDLS */ + +#define DEFAULT_BCN_TIMEOUT 8 +#ifndef CUSTOM_BCN_TIMEOUT +#define CUSTOM_BCN_TIMEOUT DEFAULT_BCN_TIMEOUT +#endif + +#ifdef SET_RETRY_LIMIT +#define DEFAULT_SHORT_RETRY_LIMIT 13 +#ifndef CUSTOM_SRL_SETTING +#define CUSTOM_SRL_SETTING DEFAULT_SHORT_RETRY_LIMIT +#endif + +#define DEFAULT_LONG_RETRY_LIMIT 13 +#ifndef CUSTOM_LRL_SETTING +#define CUSTOM_LRL_SETTING DEFAULT_LONG_RETRY_LIMIT +#endif +#endif /* SET_RETRY_LIMIT */ + +#define MAX_DTIM_SKIP_BEACON_INTERVAL 100 /* max allowed associated AP beacon for DTIM skip */ +#ifndef MAX_DTIM_ALLOWED_INTERVAL +#define MAX_DTIM_ALLOWED_INTERVAL 600 /* max allowed total beacon interval for DTIM skip */ +#endif +#define NO_DTIM_SKIP 1 +#ifdef SDTEST +/* Echo packet generator (SDIO), pkts/s */ +extern uint dhd_pktgen; + +/* Echo packet len (0 => sawtooth, max 1800) */ +extern uint dhd_pktgen_len; +#define MAX_PKTGEN_LEN 1800 +#endif + + +/* optionally set by a module_param_string() */ +#define MOD_PARAM_PATHLEN 2048 +#define MOD_PARAM_INFOLEN 512 + +#ifdef SOFTAP +extern char fw_path2[MOD_PARAM_PATHLEN]; +#endif + +/* Flag to indicate if we should download firmware on driver load */ +extern uint dhd_download_fw_on_driverload; + + +extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); +extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); + +#define IFLOCK_INIT(lock) *lock = 0 +#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ + NdisStallExecution(1); +#define IFUNLOCK(lock) InterlockedExchange((lock), 0) +#define IFLOCK_FREE(lock) +#define FW_SUPPORTED(dhd, capa) ((strstr(dhd->fw_capabilities, #capa) != NULL)) +#ifdef ARP_OFFLOAD_SUPPORT +#define MAX_IPV4_ENTRIES 8 +void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); +void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); + +/* dhd_commn arp offload wrapers */ +void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx); +void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); +int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); +void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef WLTDLS +int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac); +#ifdef PCIE_FULL_DONGLE +void dhd_tdls_update_peer_info(struct net_device *dev, bool connect_disconnect, uint8 *addr); +#endif /* PCIE_FULL_DONGLE */ +#endif /* WLTDLS */ +/* Neighbor Discovery Offload Support */ +int dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable); +int dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipaddr, int idx); +int dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx); +/* ioctl processing for nl80211 */ +int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, struct dhd_ioctl *ioc, void *data_buf); + +#if defined(SUPPORT_MULTIPLE_REVISION) +extern int +concate_revision(struct dhd_bus *bus, char *fwpath, char *nvpath); +#endif /* SUPPORT_MULTIPLE_REVISION */ +void dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path); +void dhd_set_bus_state(void *bus, uint32 state); + +/* Remove proper pkts(either one no-frag pkt or whole fragmented pkts) */ +typedef int (*f_droppkt_t)(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ); +extern bool dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn); + +#ifdef PROP_TXSTATUS +int dhd_os_wlfc_block(dhd_pub_t *pub); +int dhd_os_wlfc_unblock(dhd_pub_t *pub); +extern const uint8 prio2fifo[]; +#endif /* PROP_TXSTATUS */ + +uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail); +void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size); + +int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost); + +#if defined(CONFIG_DHD_USE_STATIC_BUF) +#define DHD_OS_PREALLOC(dhdpub, section, size) dhd_os_prealloc(dhdpub, section, size, FALSE) +#define DHD_OS_PREFREE(dhdpub, addr, size) dhd_os_prefree(dhdpub, addr, size) +#else +#define DHD_OS_PREALLOC(dhdpub, section, size) MALLOC(dhdpub->osh, size) +#define DHD_OS_PREFREE(dhdpub, addr, size) MFREE(dhdpub->osh, addr, size) +#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ + + +#define dhd_add_flowid(pub, ifidx, ac_prio, ea, flowid) do {} while (0) +#define dhd_del_flowid(pub, ifidx, flowid) do {} while (0) + +extern unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub); +extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags); + +/** Miscellaenous DHD Spin Locks */ + +/* Disable router 3GMAC bypass path perimeter lock */ +#define DHD_PERIM_LOCK(dhdp) do {} while (0) +#define DHD_PERIM_UNLOCK(dhdp) do {} while (0) + +/* Enable DHD general spin lock/unlock */ +#define DHD_GENERAL_LOCK(dhdp, flags) \ + (flags) = dhd_os_general_spin_lock(dhdp) +#define DHD_GENERAL_UNLOCK(dhdp, flags) \ + dhd_os_general_spin_unlock((dhdp), (flags)) + +/* Enable DHD flowring spin lock/unlock */ +#define DHD_FLOWRING_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) +#define DHD_FLOWRING_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) + +/* Enable DHD common flowring info spin lock/unlock */ +#define DHD_FLOWID_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) +#define DHD_FLOWID_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) + + + +typedef struct wl_io_pport { + dhd_pub_t *dhd_pub; + uint ifidx; +} wl_io_pport_t; + +extern void *dhd_pub_wlinfo(dhd_pub_t *dhd_pub); +#ifdef CONFIG_MACH_UNIVERSAL5433 +extern int check_rev(void); +#endif + +#if defined(SET_RPS_CPUS) +int dhd_rps_cpus_enable(struct net_device *net, int enable); +int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len); +void custom_rps_map_clear(struct netdev_rx_queue *queue); +#define PRIMARY_INF 0 +#define VIRTUAL_INF 1 +#ifdef CONFIG_MACH_UNIVERSAL5433 +#define RPS_CPUS_MASK "10" +#define RPS_CPUS_MASK_P2P "10" +#define RPS_CPUS_MASK_IBSS "10" +#define RPS_CPUS_WLAN_CORE_ID 4 +#else +#define RPS_CPUS_MASK "6" +#define RPS_CPUS_MASK_P2P "6" +#define RPS_CPUS_MASK_IBSS "6" +#endif /* CONFIG_MACH_UNIVERSAL5433 */ +#endif /* SET_RPS_CPUS */ + +#ifdef DHD_FW_COREDUMP +void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length); +#endif /* DHD_FW_COREDUMP */ +#if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) +extern int dhdpcie_set_suspend_resume(struct pci_dev *dev, bool state); +#endif /* DHD_USE_IDLECOUNT && BCMPCIE */ + +/* + * Enable this macro if you want to track the calls to wake lock + * This records can be printed using the following command + * cat /sys/bcm-dhd/wklock_trace + * DHD_TRACE_WAKE_LOCK supports over linux 2.6.0 version + */ +/* #define DHD_TRACE_WAKE_LOCK */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +#ifdef DHD_TRACE_WAKE_LOCK +#undef DHD_TRACE_WAKE_LOCK +#warning according to Kernel version DHD_TRACE_WAKE_LOCK cannot be supported +#endif +#endif /* KERNEL_VER < KERNEL_VERSION(2, 6, 0) */ + +#if defined(DHD_TRACE_WAKE_LOCK) +void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp); +#endif + +#if defined(CONFIG_64BIT) +#define DHD_SUPPORT_64BIT +#elif defined(DHD_EFI) +#define DHD_SUPPORT_64BIT +/* by default disabled for other platforms, can enable appropriate macro to enable 64 bit support */ +#endif /* (linux || LINUX) && CONFIG_64BIT */ + +#endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.c new file mode 100644 index 000000000000..c830b3cf5d87 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.c @@ -0,0 +1,328 @@ +/* + * BT-AMP support routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_bta.c 701287 2017-05-24 10:33:19Z $ + */ +#error "WLBTAMP is not defined" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#ifdef SEND_HCI_CMD_VIA_IOCTL +#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE + +/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */ +int +dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) +{ + amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; + int ret; + + if (cmd_len < HCI_CMD_PREAMBLE_SIZE) + return BCME_BADLEN; + + if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) + return BCME_BADLEN; + + ret = dhd_iovar(pub, 0, "HCI_cmd", (char *)cmd, + (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, NULL, 0, TRUE); + + + return ret; +} +#else /* !SEND_HCI_CMD_VIA_IOCTL */ + +static void +dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh) +{ + int prec; + struct pktq *q; + uint count = 0; + + q = dhd_bus_txq(pub->bus); + if (q == NULL) + return; + + DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh)); + + dhd_os_sdlock_txq(pub); + + /* Walk through the txq and toss all HCI ACL data packets */ + PKTQ_PREC_ITER(q, prec) { + void *head_pkt = NULL; + + while (pktq_ppeek(q, prec) != head_pkt) { + void *pkt = pktq_pdeq(q, prec); + int ifidx; + + dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL); + + if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) { + struct ether_header *eh = + (struct ether_header *)PKTDATA(pub->osh, pkt); + + if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { + struct dot11_llc_snap_header *lsh = + (struct dot11_llc_snap_header *)&eh[1]; + + if (bcmp(lsh, BT_SIG_SNAP_MPROT, + DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && + ntoh16(lsh->type) == BTA_PROT_L2CAP) { + amp_hci_ACL_data_t *ACL_data = + (amp_hci_ACL_data_t *)&lsh[1]; + uint16 handle = ltoh16(ACL_data->handle); + + if (HCI_ACL_DATA_HANDLE(handle) == llh) { + PKTFREE(pub->osh, pkt, TRUE); + count ++; + continue; + } + } + } + } + + dhd_prot_hdrpush(pub, ifidx, pkt); + + if (head_pkt == NULL) + head_pkt = pkt; + pktq_penq(q, prec, pkt); + } + } + + dhd_os_sdunlock_txq(pub); + + DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh)); +} + +/* Handle HCI cmd locally. + * Return 0: continue to send the cmd across SDIO + * < 0: stop, fail + * > 0: stop, succuess + */ +static int +_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd) +{ + int status = 0; + + switch (ltoh16_ua((uint8 *)&cmd->opcode)) { + case HCI_Enhanced_Flush: { + eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms; + dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh)); + break; + } + default: + break; + } + + return status; +} + +/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */ +int +dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) +{ + amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; + struct ether_header *eh; + struct dot11_llc_snap_header *lsh; + osl_t *osh = pub->osh; + uint len; + void *p; + int status; + + if (cmd_len < HCI_CMD_PREAMBLE_SIZE) { + DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len)); + return BCME_BADLEN; + } + + if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) { + DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n", + len, cmd_len)); + /* return BCME_BADLEN; */ + } + + p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); + if (p == NULL) { + DHD_ERROR(("dhd_bta_docmd: out of memory\n")); + return BCME_NOMEM; + } + + + /* intercept and handle the HCI cmd locally */ + if ((status = _dhd_bta_docmd(pub, cmd)) > 0) + return 0; + else if (status < 0) + return status; + + /* copy in HCI cmd */ + PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); + bcopy(cmd, PKTDATA(osh, p), len); + + /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ + PKTPUSH(osh, p, RFC1042_HDR_LEN); + eh = (struct ether_header *)PKTDATA(osh, p); + bzero(eh->ether_dhost, ETHER_ADDR_LEN); + ETHER_SET_LOCALADDR(eh->ether_dhost); + bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); + eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); + lsh = (struct dot11_llc_snap_header *)&eh[1]; + bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); + lsh->type = 0; + + return dhd_sendpkt(pub, 0, p); +} +#endif /* !SEND_HCI_CMD_VIA_IOCTL */ + +/* Send HCI ACL data to dongle via data channel */ +int +dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len) +{ + amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf; + struct ether_header *eh; + struct dot11_llc_snap_header *lsh; + osl_t *osh = pub->osh; + uint len; + void *p; + + if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) { + DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len)); + return BCME_BADLEN; + } + + if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) { + DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n", + len, data_len)); + /* return BCME_BADLEN; */ + } + + p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); + if (p == NULL) { + DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n")); + return BCME_NOMEM; + } + + + /* copy in HCI ACL data header and HCI ACL data */ + PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); + bcopy(data, PKTDATA(osh, p), len); + + /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ + PKTPUSH(osh, p, RFC1042_HDR_LEN); + eh = (struct ether_header *)PKTDATA(osh, p); + bzero(eh->ether_dhost, ETHER_ADDR_LEN); + bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); + eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); + lsh = (struct dot11_llc_snap_header *)&eh[1]; + bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); + lsh->type = HTON16(BTA_PROT_L2CAP); + + return dhd_sendpkt(pub, 0, p); +} + +/* txcomplete callback */ +void +dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success) +{ + uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp); + amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN); + uint16 handle = ltoh16(ACL_data->handle); + uint16 llh = HCI_ACL_DATA_HANDLE(handle); + + wl_event_msg_t event; + uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)]; + amp_hci_event_t *evt; + num_completed_data_blocks_evt_parms_t *parms; + + uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t); + + /* update the event struct */ + memset(&event, 0, sizeof(event)); + event.version = hton16(BCM_EVENT_MSG_VERSION); + event.event_type = hton32(WLC_E_BTA_HCI_EVENT); + event.status = 0; + event.reason = 0; + event.auth_type = 0; + event.datalen = hton32(len); + event.flags = 0; + + /* generate Number of Completed Blocks event */ + evt = (amp_hci_event_t *)data; + evt->ecode = HCI_Number_of_Completed_Data_Blocks; + evt->plen = sizeof(num_completed_data_blocks_evt_parms_t); + + parms = (num_completed_data_blocks_evt_parms_t *)evt->parms; + htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks); + parms->num_handles = 1; + htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle); + parms->completed[0].pkts = 1; + parms->completed[0].blocks = 1; + + dhd_sendup_event_common(dhdp, &event, data); +} + +/* event callback */ +void +dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) +{ + amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; + + ASSERT(dhdp); + ASSERT(evt); + + switch (evt->ecode) { + case HCI_Command_Complete: { + cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; + switch (ltoh16_ua((uint8 *)&parms->opcode)) { + case HCI_Read_Data_Block_Size: { + read_data_block_size_evt_parms_t *parms2 = + (read_data_block_size_evt_parms_t *)parms->parms; + dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num); + break; + } + } + break; + } + + case HCI_Flush_Occurred: { + flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms; + dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle)); + break; + } + default: + break; + } +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.h new file mode 100644 index 000000000000..0c5e9de534e9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.h @@ -0,0 +1,39 @@ +/* + * BT-AMP support routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_bta.h 291086 2011-10-21 01:17:24Z $ + */ +#ifndef __dhd_bta_h__ +#define __dhd_bta_h__ + +struct dhd_pub; + +extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len); + +extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len); + +extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len); +extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success); + + +#endif /* __dhd_bta_h__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_bus.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bus.h new file mode 100644 index 000000000000..971ac1a73166 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bus.h @@ -0,0 +1,199 @@ +/* + * Header file describing the internal (inter-module) DHD interfaces. + * + * Provides type definitions and function prototypes used to link the + * DHD OS, bus, and protocol modules. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_bus.h 619942 2016-02-19 02:20:35Z $ + */ + +#ifndef _dhd_bus_h_ +#define _dhd_bus_h_ + +/* + * Exported from dhd bus module (dhd_usb, dhd_sdio) + */ + +/* Indicate (dis)interest in finding dongles. */ +extern int dhd_bus_register(void); +extern void dhd_bus_unregister(void); + +/* Download firmware image and nvram image */ +extern int dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, char *fw_path, char *nv_path); + +/* Stop bus module: clear pending frames, disable data flow */ +extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); + +/* Initialize bus module: prepare for communication w/dongle */ +extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); + +/* Get the Bus Idle Time */ +extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); + +/* Set the Bus Idle Time */ +extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); + +/* Send a data frame to the dongle. Callee disposes of txp. */ +#ifdef BCMPCIE +extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx); +#else +extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); +#endif + + +/* Send/receive a control message to/from the dongle. + * Expects caller to enforce a single outstanding transaction. + */ +extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); +extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); + +/* Watchdog timer function */ +extern bool dhd_bus_watchdog(dhd_pub_t *dhd); + +extern int dhd_bus_oob_intr_register(dhd_pub_t *dhdp); +extern void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp); +extern void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable); +extern void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub); +extern void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub); +extern bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub); + +#if defined(DHD_DEBUG) +/* Device console input function */ +extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); +extern int dhd_bus_mem_dump(dhd_pub_t *dhd); +#endif /* defined(DHD_DEBUG) */ + +/* Deferred processing for the bus, return TRUE requests reschedule */ +extern bool dhd_bus_dpc(struct dhd_bus *bus); +extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); + + +/* Check for and handle local prot-specific iovar commands */ +extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set); + +/* Add bus dump output to a buffer */ +extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); + +/* Clear any bus counters */ +extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); + +/* return the dongle chipid */ +extern uint dhd_bus_chip(struct dhd_bus *bus); + +/* return the dongle chiprev */ +extern uint dhd_bus_chiprev(struct dhd_bus *bus); + +/* Set user-specified nvram parameters. */ +extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); + +extern void *dhd_bus_pub(struct dhd_bus *bus); +extern void *dhd_bus_txq(struct dhd_bus *bus); +extern void *dhd_bus_sih(struct dhd_bus *bus); +extern uint dhd_bus_hdrlen(struct dhd_bus *bus); +#ifdef BCMSDIO +extern void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val); +#else +#define dhd_bus_set_dotxinrx(a, b) do {} while (0) +#endif + +#define DHD_SET_BUS_STATE_DOWN(_bus) do { \ + (_bus)->dhd->busstate = DHD_BUS_DOWN; \ +} while (0) + +/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ +extern int dhd_bus_reg_sdio_notify(void* semaphore); +extern void dhd_bus_unreg_sdio_notify(void); +extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable); +extern int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, + uint32 *slot_num); + +#ifdef BCMPCIE +enum { + DNGL_TO_HOST_BUF_IOCT, + DNGL_TO_HOST_DMA_SCRATCH_BUFFER, + DNGL_TO_HOST_DMA_SCRATCH_BUFFER_LEN, + HOST_TO_DNGL_DMA_WRITEINDX_BUFFER, + HOST_TO_DNGL_DMA_READINDX_BUFFER, + DNGL_TO_HOST_DMA_WRITEINDX_BUFFER, + DNGL_TO_HOST_DMA_READINDX_BUFFER, + TOTAL_LFRAG_PACKET_CNT, + HTOD_MB_DATA, + DTOH_MB_DATA, + RING_BUF_ADDR, + H2D_DMA_WRITEINDX, + H2D_DMA_READINDX, + D2H_DMA_WRITEINDX, + D2H_DMA_READINDX, + RING_READ_PTR, + RING_WRITE_PTR, + RING_LEN_ITEMS, + RING_MAX_ITEM, + MAX_HOST_RXBUFS +}; +typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32); +extern void dhd_bus_cmn_writeshared(struct dhd_bus *bus, void * data, uint32 len, uint8 type, + uint16 ringid); +extern void dhd_bus_ringbell(struct dhd_bus *bus, uint32 value); +extern void dhd_bus_cmn_readshared(struct dhd_bus *bus, void* data, uint8 type, uint16 ringid); +extern uint32 dhd_bus_get_sharedflags(struct dhd_bus *bus); +extern void dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count); +extern void dhd_bus_start_queue(struct dhd_bus *bus); +extern void dhd_bus_stop_queue(struct dhd_bus *bus); +extern void dhd_bus_update_retlen(struct dhd_bus *bus, uint32 retlen, uint32 cmd_id, uint16 status, + uint32 resp_len); +extern dhd_mb_ring_t dhd_bus_get_mbintr_fn(struct dhd_bus *bus); +extern void dhd_bus_write_flow_ring_states(struct dhd_bus *bus, + void * data, uint16 flowid); +extern void dhd_bus_read_flow_ring_states(struct dhd_bus *bus, + void * data, uint8 flowid); +extern int dhd_bus_flow_ring_create_request(struct dhd_bus *bus, void *flow_ring_node); +extern void dhd_bus_clean_flow_ring(struct dhd_bus *bus, void *flow_ring_node); +extern void dhd_bus_flow_ring_create_response(struct dhd_bus *bus, uint16 flow_id, int32 status); +extern int dhd_bus_flow_ring_delete_request(struct dhd_bus *bus, void *flow_ring_node); +extern void dhd_bus_flow_ring_delete_response(struct dhd_bus *bus, uint16 flowid, uint32 status); +extern int dhd_bus_flow_ring_flush_request(struct dhd_bus *bus, void *flow_ring_node); +extern void dhd_bus_flow_ring_flush_response(struct dhd_bus *bus, uint16 flowid, uint32 status); +extern uint8 dhd_bus_is_txmode_push(struct dhd_bus *bus); +extern uint32 dhd_bus_max_h2d_queues(struct dhd_bus *bus, uint8 *txpush); +extern int dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs); +extern int dhdpcie_bus_clock_start(struct dhd_bus *bus); +extern int dhdpcie_bus_clock_stop(struct dhd_bus *bus); +extern int dhdpcie_bus_enable_device(struct dhd_bus *bus); +extern int dhdpcie_bus_disable_device(struct dhd_bus *bus); +extern int dhdpcie_bus_alloc_resource(struct dhd_bus *bus); +extern void dhdpcie_bus_free_resource(struct dhd_bus *bus); +extern bool dhdpcie_bus_dongle_attach(struct dhd_bus *bus); +extern int dhd_bus_release_dongle(struct dhd_bus *bus); +extern int dhd_bus_request_irq(struct dhd_bus *bus); + + +#ifdef DHD_USE_IDLECOUNT +extern bool dhd_bus_is_resume_done(dhd_pub_t *dhdp); +extern bool bus_wake(struct dhd_bus *bus); +extern bool bus_wakeup(struct dhd_bus *bus); +extern bool dhd_bus_wake(dhd_pub_t *dhdp); +extern bool dhd_bus_wakeup(dhd_pub_t *dhdp); +#endif /* DHD_USE_IDLECOUNT */ +#endif /* BCMPCIE */ +#endif /* _dhd_bus_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_cdc.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cdc.c new file mode 100644 index 000000000000..bb88f46a51d6 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cdc.c @@ -0,0 +1,811 @@ +/* + * DHD Protocol Module for CDC and BDC. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_cdc.c 492377 2014-07-21 19:54:06Z $ + * + * BDC is like CDC, except it includes a header for data packets to convey + * packet priority over the bus, and flags (e.g. to indicate checksum status + * for dongle offload.) + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + + +#ifdef PROP_TXSTATUS +#include +#include +#endif + + +#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ +#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE + * defined in dhd_sdio.c (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 + */ + +typedef struct dhd_prot { + uint16 reqid; + uint8 pending; + uint32 lastcmd; + uint8 bus_header[BUS_HEADER_LEN]; + cdc_ioctl_t msg; + unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; +} dhd_prot_t; + + +static int +dhdcdc_msg(dhd_pub_t *dhd) +{ + int err = 0; + dhd_prot_t *prot = dhd->prot; + int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + DHD_OS_WAKE_LOCK(dhd); + + /* 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 */ + err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); + + DHD_OS_WAKE_UNLOCK(dhd); + return err; +} + +static int +dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) +{ + int ret; + int cdc_len = len + sizeof(cdc_ioctl_t); + dhd_prot_t *prot = dhd->prot; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + + do { + ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); + if (ret < 0) + break; + } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); + + + return ret; +} + +static int +dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) +{ + dhd_prot_t *prot = dhd->prot; + cdc_ioctl_t *msg = &prot->msg; + int ret = 0, retries = 0; + uint32 id, flags = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); + + + /* Respond "bcmerror" and "bcmerrorstr" with local cache */ + if (cmd == WLC_GET_VAR && buf) + { + if (!strcmp((char *)buf, "bcmerrorstr")) + { + strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN); + goto done; + } + else if (!strcmp((char *)buf, "bcmerror")) + { + *(int *)buf = dhd->dongle_error; + goto done; + } + } + + memset(msg, 0, sizeof(cdc_ioctl_t)); + + msg->cmd = htol32(cmd); + msg->len = htol32(len); + msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); + CDC_SET_IF_IDX(msg, ifidx); + /* add additional action bits */ + action &= WL_IOCTL_ACTION_MASK; + msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); + msg->flags = htol32(msg->flags); + + if (buf) + memcpy(prot->buf, buf, len); + + if ((ret = dhdcdc_msg(dhd)) < 0) { + if (!dhd->hang_was_sent) + DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret)); + goto done; + } + +retry: + /* wait for interrupt and get first fragment */ + if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) + goto done; + + flags = ltoh32(msg->flags); + id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; + + if ((id < prot->reqid) && (++retries < RETRIES)) + goto retry; + if (id != prot->reqid) { + DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", + dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); + ret = -EINVAL; + goto done; + } + + /* Copy info buffer */ + if (buf) + { + if (ret < (int)len) + len = ret; + memcpy(buf, (void*) prot->buf, len); + } + + /* Check the ERROR flag */ + if (flags & CDCF_IOC_ERROR) + { + ret = ltoh32(msg->status); + /* Cache error from dongle */ + dhd->dongle_error = ret; + } + +done: + return ret; +} + + +static int +dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) +{ + dhd_prot_t *prot = dhd->prot; + cdc_ioctl_t *msg = &prot->msg; + int ret = 0; + uint32 flags, id; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); + + if (dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + return -EIO; + } + + /* don't talk to the dongle if fw is about to be reloaded */ + if (dhd->hang_was_sent) { + DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", + __FUNCTION__)); + return -EIO; + } + + memset(msg, 0, sizeof(cdc_ioctl_t)); + + msg->cmd = htol32(cmd); + msg->len = htol32(len); + msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); + CDC_SET_IF_IDX(msg, ifidx); + /* add additional action bits */ + action &= WL_IOCTL_ACTION_MASK; + msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; + msg->flags = htol32(msg->flags); + + if (buf) + memcpy(prot->buf, buf, len); + + if ((ret = dhdcdc_msg(dhd)) < 0) { + DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret)); + goto done; + } + + if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) + goto done; + + flags = ltoh32(msg->flags); + id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; + + if (id != prot->reqid) { + DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", + dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); + ret = -EINVAL; + goto done; + } + + /* Check the ERROR flag */ + if (flags & CDCF_IOC_ERROR) + { + ret = ltoh32(msg->status); + /* Cache error from dongle */ + dhd->dongle_error = ret; + } + +done: + return ret; +} + + +int +dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) +{ + dhd_prot_t *prot = dhd->prot; + int ret = -1; + uint8 action; + + if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + goto done; + } + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(len <= WLC_IOCTL_MAXLEN); + + if (len > WLC_IOCTL_MAXLEN) + goto done; + + if (prot->pending == TRUE) { + DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", + ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, + (unsigned long)prot->lastcmd)); + if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { + DHD_TRACE(("iovar cmd=%s\n", (char*)buf)); + } + goto done; + } + + prot->pending = TRUE; + prot->lastcmd = ioc->cmd; + action = ioc->set; + if (action & WL_IOCTL_ACTION_SET) + ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); + else { + ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); + if (ret > 0) + ioc->used = ret - sizeof(cdc_ioctl_t); + } + + /* Too many programs assume ioctl() returns 0 on success */ + if (ret >= 0) + ret = 0; + else { + cdc_ioctl_t *msg = &prot->msg; + ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ + } + + /* Intercept the wme_dp ioctl here */ + if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { + int slen, val = 0; + + slen = strlen("wme_dp") + 1; + if (len >= (int)(slen + sizeof(int))) + bcopy(((char *)buf + slen), &val, sizeof(int)); + dhd->wme_dp = (uint8) ltoh32(val); + } + + prot->pending = FALSE; + +done: + + return ret; +} + +int +dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + return BCME_UNSUPPORTED; +} + +void +dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); +#ifdef PROP_TXSTATUS + dhd_wlfc_dump(dhdp, strbuf); +#endif +} + +/* The FreeBSD PKTPUSH could change the packet buf pinter + so we need to make it changable +*/ +#define PKTBUF pktbuf +void +dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) +{ +#ifdef BDC + struct bdc_header *h; +#endif /* BDC */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + +#ifdef BDC + /* Push BDC header used to convey priority for buses that don't */ + + PKTPUSH(dhd->osh, PKTBUF, BDC_HEADER_LEN); + + h = (struct bdc_header *)PKTDATA(dhd->osh, PKTBUF); + + h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); + if (PKTSUMNEEDED(PKTBUF)) + h->flags |= BDC_FLAG_SUM_NEEDED; + + + h->priority = (PKTPRIO(PKTBUF) & BDC_PRIORITY_MASK); + h->flags2 = 0; + h->dataOffset = 0; +#endif /* BDC */ + BDC_SET_IF_IDX(h, ifidx); +} +#undef PKTBUF /* Only defined in the above routine */ + +uint +dhd_prot_hdrlen(dhd_pub_t *dhd, void *PKTBUF) +{ + uint hdrlen = 0; +#ifdef BDC + /* Length of BDC(+WLFC) headers pushed */ + hdrlen = BDC_HEADER_LEN + (((struct bdc_header *)PKTBUF)->dataOffset * 4); +#endif + return hdrlen; +} + +int +dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, + uint *reorder_info_len) +{ +#ifdef BDC + struct bdc_header *h; +#endif + uint8 data_offset = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + +#ifdef BDC + if (reorder_info_len) + *reorder_info_len = 0; + /* Pop BDC header used to convey priority for buses that don't */ + + if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { + DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN)); + return BCME_ERROR; + } + + h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); + + if (!ifidx) { + /* for tx packet, skip the analysis */ + data_offset = h->dataOffset; + PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); + goto exit; + } + + if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { + DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", + __FUNCTION__, *ifidx)); + return BCME_ERROR; + } + + if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { + DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", + dhd_ifname(dhd, *ifidx), h->flags)); + if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) + h->dataOffset = 0; + else + return BCME_ERROR; + } + + if (h->flags & BDC_FLAG_SUM_GOOD) { + DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n", + dhd_ifname(dhd, *ifidx), h->flags)); + PKTSETSUMGOOD(pktbuf, TRUE); + } + + PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); + data_offset = h->dataOffset; + PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); +#endif /* BDC */ + + +#ifdef PROP_TXSTATUS + if (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf))) { + /* + - parse txstatus only for packets that came from the firmware + */ + dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), + reorder_buf_info, reorder_info_len); + + } +#endif /* PROP_TXSTATUS */ + +exit: + PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); + return 0; +} + + +int +dhd_prot_attach(dhd_pub_t *dhd) +{ + dhd_prot_t *cdc; + + if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } + memset(cdc, 0, sizeof(dhd_prot_t)); + + /* ensure that the msg buf directly follows the cdc msg struct */ + if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) { + DHD_ERROR(("dhd_prot_t is not correctly defined\n")); + goto fail; + } + + dhd->prot = cdc; +#ifdef BDC + dhd->hdrlen += BDC_HEADER_LEN; +#endif + dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN; + return 0; + +fail: + if (cdc != NULL) + DHD_OS_PREFREE(dhd, cdc, sizeof(dhd_prot_t)); + return BCME_NOMEM; +} + +/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ +void +dhd_prot_detach(dhd_pub_t *dhd) +{ +#ifdef PROP_TXSTATUS + dhd_wlfc_deinit(dhd); +#endif + DHD_OS_PREFREE(dhd, dhd->prot, sizeof(dhd_prot_t)); + dhd->prot = NULL; +} + +void +dhd_prot_dstats(dhd_pub_t *dhd) +{ + /* copy bus stats */ + + dhd->dstats.tx_packets = dhd->tx_packets; + dhd->dstats.tx_errors = dhd->tx_errors; + dhd->dstats.rx_packets = dhd->rx_packets; + dhd->dstats.rx_errors = dhd->rx_errors; + dhd->dstats.rx_dropped = dhd->rx_dropped; + dhd->dstats.multicast = dhd->rx_multicast; + return; +} + +int +dhd_sync_with_dongle(dhd_pub_t *dhd) +{ + int ret = 0; + wlc_rev_info_t revinfo; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + + /* Get the device rev info */ + memset(&revinfo, 0, sizeof(revinfo)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); + if (ret < 0) + goto done; + + + dhd_process_cid_mac(dhd, TRUE); + + ret = dhd_preinit_ioctls(dhd); + + if (!ret) + dhd_process_cid_mac(dhd, FALSE); + + /* Always assumes wl for now */ + dhd->iswl = TRUE; + +done: + return ret; +} + +int dhd_prot_init(dhd_pub_t *dhd) +{ + return TRUE; +} + +void +dhd_prot_stop(dhd_pub_t *dhd) +{ +/* Nothing to do for CDC */ +} + + +static void +dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, + uint32 *pkt_count, void **pplast, uint8 start, uint8 end) +{ + void *plast = NULL, *p; + uint32 pkt_cnt = 0; + + if (ptr->pend_pkts == 0) { + DHD_REORDER(("%s: no packets in reorder queue \n", __FUNCTION__)); + *pplast = NULL; + *pkt_count = 0; + *pkt = NULL; + return; + } + do { + p = (void *)(ptr->p[start]); + ptr->p[start] = NULL; + + if (p != NULL) { + if (plast == NULL) + *pkt = p; + else + PKTSETNEXT(osh, plast, p); + + plast = p; + pkt_cnt++; + } + start++; + if (start > ptr->max_idx) + start = 0; + } while (start != end); + *pplast = plast; + *pkt_count = pkt_cnt; + ptr->pend_pkts -= (uint8)pkt_cnt; +} + +int +dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, + void **pkt, uint32 *pkt_count) +{ + uint8 flow_id, max_idx, cur_idx, exp_idx; + struct reorder_info *ptr; + uint8 flags; + void *cur_pkt, *plast = NULL; + uint32 cnt = 0; + + if (pkt == NULL) { + if (pkt_count != NULL) + *pkt_count = 0; + return 0; + } + + flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; + flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; + + DHD_REORDER(("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags, + reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET], + reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET], + reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET])); + + /* validate flags and flow id */ + if (flags == 0xFF) { + DHD_ERROR(("%s: invalid flags...so ignore this packet\n", __FUNCTION__)); + *pkt_count = 1; + return 0; + } + + cur_pkt = *pkt; + *pkt = NULL; + + ptr = dhd->reorder_bufs[flow_id]; + if (flags & WLHOST_REORDERDATA_DEL_FLOW) { + uint32 buf_size = sizeof(struct reorder_info); + + DHD_REORDER(("%s: Flags indicating to delete a flow id %d\n", + __FUNCTION__, flow_id)); + + if (ptr == NULL) { + DHD_REORDER(("%s: received flags to cleanup, but no flow (%d) yet\n", + __FUNCTION__, flow_id)); + *pkt_count = 1; + *pkt = cur_pkt; + return 0; + } + + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, + ptr->exp_idx, ptr->exp_idx); + /* set it to the last packet */ + if (plast) { + PKTSETNEXT(dhd->osh, plast, cur_pkt); + cnt++; + } + else { + if (cnt != 0) { + DHD_ERROR(("%s: del flow: something fishy, pending packets %d\n", + __FUNCTION__, cnt)); + } + *pkt = cur_pkt; + cnt = 1; + } + buf_size += ((ptr->max_idx + 1) * sizeof(void *)); + MFREE(dhd->osh, ptr, buf_size); + dhd->reorder_bufs[flow_id] = NULL; + *pkt_count = cnt; + return 0; + } + /* all the other cases depend on the existance of the reorder struct for that flow id */ + if (ptr == NULL) { + uint32 buf_size_alloc = sizeof(reorder_info_t); + max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; + + buf_size_alloc += ((max_idx + 1) * sizeof(void*)); + /* allocate space to hold the buffers, index etc */ + + DHD_REORDER(("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n", + __FUNCTION__, buf_size_alloc, flow_id, max_idx)); + ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc); + if (ptr == NULL) { + DHD_ERROR(("%s: Malloc failed to alloc buffer\n", __FUNCTION__)); + *pkt_count = 1; + return 0; + } + bzero(ptr, buf_size_alloc); + dhd->reorder_bufs[flow_id] = ptr; + ptr->p = (void *)(ptr+1); + ptr->max_idx = max_idx; + } + if (flags & WLHOST_REORDERDATA_NEW_HOLE) { + DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__)); + if (ptr->pend_pkts) { + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, + ptr->exp_idx, ptr->exp_idx); + ptr->pend_pkts = 0; + } + ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; + ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; + ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; + ptr->p[ptr->cur_idx] = cur_pkt; + ptr->pend_pkts++; + *pkt_count = cnt; + } + else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) { + cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; + exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; + + + if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) { + /* still in the current hole */ + /* enqueue the current on the buffer chain */ + if (ptr->p[cur_idx] != NULL) { + DHD_REORDER(("%s: HOLE: ERROR buffer pending..free it\n", + __FUNCTION__)); + PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); + ptr->p[cur_idx] = NULL; + } + ptr->p[cur_idx] = cur_pkt; + ptr->pend_pkts++; + ptr->cur_idx = cur_idx; + DHD_REORDER(("%s: fill up a hole..pending packets is %d\n", + __FUNCTION__, ptr->pend_pkts)); + *pkt_count = 0; + *pkt = NULL; + } + else if (ptr->exp_idx == cur_idx) { + /* got the right one ..flush from cur to exp and update exp */ + DHD_REORDER(("%s: got the right one now, cur_idx is %d\n", + __FUNCTION__, cur_idx)); + if (ptr->p[cur_idx] != NULL) { + DHD_REORDER(("%s: Error buffer pending..free it\n", + __FUNCTION__)); + PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); + ptr->p[cur_idx] = NULL; + } + ptr->p[cur_idx] = cur_pkt; + ptr->pend_pkts++; + + ptr->cur_idx = cur_idx; + ptr->exp_idx = exp_idx; + + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, + cur_idx, exp_idx); + *pkt_count = cnt; + DHD_REORDER(("%s: freeing up buffers %d, still pending %d\n", + __FUNCTION__, cnt, ptr->pend_pkts)); + } + else { + uint8 end_idx; + bool flush_current = FALSE; + /* both cur and exp are moved now .. */ + DHD_REORDER(("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n", + __FUNCTION__, flow_id, ptr->cur_idx, cur_idx, + ptr->exp_idx, exp_idx)); + if (flags & WLHOST_REORDERDATA_FLUSH_ALL) + end_idx = ptr->exp_idx; + else + end_idx = exp_idx; + + /* flush pkts first */ + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, + ptr->exp_idx, end_idx); + + if (cur_idx == ptr->max_idx) { + if (exp_idx == 0) + flush_current = TRUE; + } else { + if (exp_idx == cur_idx + 1) + flush_current = TRUE; + } + if (flush_current) { + if (plast) + PKTSETNEXT(dhd->osh, plast, cur_pkt); + else + *pkt = cur_pkt; + cnt++; + } + else { + ptr->p[cur_idx] = cur_pkt; + ptr->pend_pkts++; + } + ptr->exp_idx = exp_idx; + ptr->cur_idx = cur_idx; + *pkt_count = cnt; + } + } + else { + uint8 end_idx; + /* no real packet but update to exp_seq...that means explicit window move */ + exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; + + DHD_REORDER(("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n", + __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx)); + if (flags & WLHOST_REORDERDATA_FLUSH_ALL) + end_idx = ptr->exp_idx; + else + end_idx = exp_idx; + + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx); + if (plast) + PKTSETNEXT(dhd->osh, plast, cur_pkt); + else + *pkt = cur_pkt; + cnt++; + *pkt_count = cnt; + /* set the new expected idx */ + ptr->exp_idx = exp_idx; + } + return 0; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.c new file mode 100644 index 000000000000..db75a2e36b5e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.c @@ -0,0 +1,219 @@ +/* + * Linux cfg80211 driver - Dongle Host Driver (DHD) related + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + */ + +#include +#include + +#include +#include +#include +#include + +#ifdef PKT_FILTER_SUPPORT +#include +#include +#endif + +extern struct bcm_cfg80211 *g_bcm_cfg; + +#ifdef PKT_FILTER_SUPPORT +extern uint dhd_pkt_filter_enable; +extern uint dhd_master_mode; +extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); +#endif + +static int dhd_dongle_up = FALSE; + +#include +#include +#include +#include +#include +#include + +static s32 wl_dongle_up(struct net_device *ndev); +static s32 wl_dongle_down(struct net_device *ndev); + +/** + * Function implementations + */ + +s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg) +{ + dhd_dongle_up = FALSE; + return 0; +} + +s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg) +{ + dhd_dongle_up = FALSE; + return 0; +} + +s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg) +{ + struct net_device *ndev; + s32 err = 0; + + WL_TRACE(("In\n")); + if (!dhd_dongle_up) { + WL_ERR(("Dongle is already down\n")); + return err; + } + + ndev = bcmcfg_to_prmry_ndev(cfg); + wl_dongle_down(ndev); + dhd_dongle_up = FALSE; + return 0; +} + +s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + dhd->op_mode |= val; + WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode)); +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd->arp_version == 1) { + /* IF P2P is enabled, disable arpoe */ + dhd_arp_offload_set(dhd, 0); + dhd_arp_offload_enable(dhd, false); + } +#endif /* ARP_OFFLOAD_SUPPORT */ + + return 0; +} + +s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); + WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode)); + +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd->arp_version == 1) { + /* IF P2P is disabled, enable arpoe back for STA mode. */ + dhd_arp_offload_set(dhd, dhd_arp_mode); + dhd_arp_offload_enable(dhd, true); + } +#endif /* ARP_OFFLOAD_SUPPORT */ + + return 0; +} + +struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, + uint8 *mac, uint8 bssidx) +{ + return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE); +} + +int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) +{ + return dhd_register_if(cfg->pub, ifidx, FALSE); +} + +int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) +{ + return dhd_remove_if(cfg->pub, ifidx, FALSE); +} + +struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev) +{ + if (ndev) { + if (ndev->ieee80211_ptr) { + kfree(ndev->ieee80211_ptr); + ndev->ieee80211_ptr = NULL; + } + free_netdev(ndev); + return NULL; + } + + return ndev; +} + +void dhd_netdev_free(struct net_device *ndev) +{ +#ifdef WL_CFG80211 + ndev = dhd_cfg80211_netdev_free(ndev); +#endif + if (ndev) + free_netdev(ndev); +} + +static s32 +wl_dongle_up(struct net_device *ndev) +{ + s32 err = 0; + u32 up = 0; + + err = wldev_ioctl_set(ndev, WLC_UP, &up, sizeof(up)); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + } + return err; +} + +static s32 +wl_dongle_down(struct net_device *ndev) +{ + s32 err = 0; + u32 down = 0; + + err = wldev_ioctl_set(ndev, WLC_DOWN, &down, sizeof(down)); + if (unlikely(err)) { + WL_ERR(("WLC_DOWN error (%d)\n", err)); + } + return err; +} + + +s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) +{ +#ifndef DHD_SDALIGN +#define DHD_SDALIGN 32 +#endif + struct net_device *ndev; + s32 err = 0; + + WL_TRACE(("In\n")); + if (dhd_dongle_up) { + WL_ERR(("Dongle is already up\n")); + return err; + } + + ndev = bcmcfg_to_prmry_ndev(cfg); + + err = wl_dongle_up(ndev); + if (unlikely(err)) { + WL_ERR(("wl_dongle_up failed\n")); + goto default_conf_out; + } + dhd_dongle_up = true; + +default_conf_out: + + return err; + +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.h new file mode 100644 index 000000000000..2bdde11bcfdc --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.h @@ -0,0 +1,48 @@ +/* + * Linux cfg80211 driver - Dongle Host Driver (DHD) related + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + */ + + +#ifndef __DHD_CFG80211__ +#define __DHD_CFG80211__ + +#include +#include + +#ifndef WL_ERR +#define WL_ERR CFG80211_ERR +#endif +#ifndef WL_TRACE +#define WL_TRACE CFG80211_TRACE +#endif + +s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg); +s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg); +s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg); +s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val); +s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg); +s32 dhd_config_dongle(struct bcm_cfg80211 *cfg); + +#endif /* __DHD_CFG80211__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg_vendor.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg_vendor.c new file mode 100644 index 000000000000..a84f2ff910e4 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg_vendor.c @@ -0,0 +1,171 @@ +/* + * Linux cfg80211 vendor command/event handlers of DHD + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_cfg_vendor.c 514708 2014-11-11 23:59:07Z $ + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef VENDOR_EXT_SUPPORT +static int dhd_cfgvendor_priv_string_handler(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + const struct bcm_nlmsg_hdr *nlioc = data; + struct net_device *ndev = NULL; + struct bcm_cfg80211 *cfg; + struct sk_buff *reply; + void *buf = NULL, *cur; + dhd_pub_t *dhd; + dhd_ioctl_t ioc = { 0 }; + int ret = 0, ret_len, payload, msglen; + int maxmsglen = PAGE_SIZE - 0x100; + int8 index; + + WL_TRACE(("entry: cmd = %d\n", nlioc->cmd)); + DHD_ERROR(("entry: cmd = %d\n", nlioc->cmd)); + + cfg = wiphy_priv(wiphy); + dhd = cfg->pub; + + DHD_OS_WAKE_LOCK(dhd); + + /* send to dongle only if we are not waiting for reload already */ + if (dhd->hang_was_sent) { + WL_ERR(("HANG was sent up earlier\n")); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS); + DHD_OS_WAKE_UNLOCK(dhd); + return OSL_ERROR(BCME_DONGLE_DOWN); + } + + len -= sizeof(struct bcm_nlmsg_hdr); + ret_len = nlioc->len; + if (ret_len > 0 || len > 0) { + if (len > DHD_IOCTL_MAXLEN) { + WL_ERR(("oversize input buffer %d\n", len)); + len = DHD_IOCTL_MAXLEN; + } + if (ret_len > DHD_IOCTL_MAXLEN) { + WL_ERR(("oversize return buffer %d\n", ret_len)); + ret_len = DHD_IOCTL_MAXLEN; + } + payload = max(ret_len, len) + 1; + buf = vzalloc(payload); + if (!buf) { + DHD_OS_WAKE_UNLOCK(dhd); + return -ENOMEM; + } + memcpy(buf, (void *)nlioc + nlioc->offset, len); + *(char *)(buf + len) = '\0'; + } + + ndev = wdev_to_wlc_ndev(wdev, cfg); + index = dhd_net2idx(dhd->info, ndev); + if (index == DHD_BAD_IF) { + WL_ERR(("Bad ifidx from wdev:%p\n", wdev)); + ret = BCME_ERROR; + goto done; + } + + ioc.cmd = nlioc->cmd; + ioc.len = nlioc->len; + ioc.set = nlioc->set; + ioc.driver = nlioc->magic; + ret = dhd_ioctl_process(dhd, index, &ioc, buf); + if (ret) { + WL_TRACE(("dhd_ioctl_process return err %d\n", ret)); + ret = OSL_ERROR(ret); + goto done; + } + + cur = buf; + while (ret_len > 0) { + msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len; + ret_len -= msglen; + payload = msglen + sizeof(msglen); + reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload); + if (!reply) { + WL_ERR(("Failed to allocate reply msg\n")); + ret = -ENOMEM; + break; + } + + if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) || + nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) { + kfree_skb(reply); + ret = -ENOBUFS; + break; + } + + ret = cfg80211_vendor_cmd_reply(reply); + if (ret) { + WL_ERR(("testmode reply failed:%d\n", ret)); + break; + } + cur += msglen; + } + +done: + vfree(buf); + DHD_OS_WAKE_UNLOCK(dhd); + return ret; +} + +const struct wiphy_vendor_command dhd_cfgvendor_cmds [] = { + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_PRIV_STR + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = dhd_cfgvendor_priv_string_handler + }, +}; + +int cfgvendor_attach(struct wiphy *wiphy) +{ + wiphy->vendor_commands = dhd_cfgvendor_cmds; + wiphy->n_vendor_commands = ARRAY_SIZE(dhd_cfgvendor_cmds); + + return 0; +} + +int cfgvendor_detach(struct wiphy *wiphy) +{ + wiphy->vendor_commands = NULL; + wiphy->n_vendor_commands = 0; + + return 0; +} +#endif /* VENDOR_EXT_SUPPORT */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c new file mode 100644 index 000000000000..b8bfca228627 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c @@ -0,0 +1,2792 @@ +/* + * Broadcom Dongle Host Driver (DHD), common DHD core. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_common.c 701287 2017-05-24 10:33:19Z $ + */ +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef SHOW_LOGTRACE +#include +#endif /* SHOW_LOGTRACE */ + +#ifdef BCMPCIE +#include +#endif + +#include +#include +#include +#include + +#ifdef WL_CFG80211 +#include +#endif +#ifdef PNO_SUPPORT +#include +#endif +#ifdef RTT_SUPPORT +#include +#endif + +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) + +#ifdef PROP_TXSTATUS +#include +#include +#endif + +#ifdef DHD_WMF +#include +#include +#endif /* DHD_WMF */ + + +#ifdef WLMEDIA_HTSF +extern void htsf_update(struct dhd_info *dhd, void *data); +#endif +int dhd_msg_level = DHD_ERROR_VAL; + + +#if defined(WL_WIRELESS_EXT) +#include +#endif + +#ifdef SOFTAP +char fw_path2[MOD_PARAM_PATHLEN]; +extern bool softap_enabled; +#endif + +/* Last connection success/failure status */ +uint32 dhd_conn_event; +uint32 dhd_conn_status; +uint32 dhd_conn_reason; + +#if defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE) +static int check_event_log_sequence_number(uint32 seq_no); +#endif /* defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE) */ +extern int dhd_iscan_request(void * dhdp, uint16 action); +extern void dhd_ind_scan_confirm(void *h, bool status); +extern int dhd_iscan_in_progress(void *h); +void dhd_iscan_lock(void); +void dhd_iscan_unlock(void); +extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); +#if !defined(AP) && defined(WLP2P) +extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); +#endif +bool ap_cfg_running = FALSE; +bool ap_fw_loaded = FALSE; + +/* Version string to report */ +#ifdef DHD_DEBUG +#ifndef SRCBASE +#define SRCBASE "drivers/net/wireless/bcmdhd_bcm4356" +#endif +#define DHD_COMPILED "\nCompiled in " SRCBASE +#endif /* DHD_DEBUG */ + +#if defined(DHD_DEBUG) +const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR + DHD_COMPILED " on " __DATE__ " at " __TIME__; +#else +const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nCompiled from "; +#endif + +void dhd_set_timer(void *bus, uint wdtick); + + + +/* IOVar table */ +enum { + IOV_VERSION = 1, + IOV_MSGLEVEL, + IOV_BCMERRORSTR, + IOV_BCMERROR, + IOV_WDTICK, + IOV_DUMP, + IOV_CLEARCOUNTS, + IOV_LOGDUMP, + IOV_LOGCAL, + IOV_LOGSTAMP, + IOV_GPIOOB, + IOV_IOCTLTIMEOUT, +#if defined(DHD_DEBUG) + IOV_CONS, + IOV_DCONSOLE_POLL, +#endif /* defined(DHD_DEBUG) */ +#ifdef PROP_TXSTATUS + IOV_PROPTXSTATUS_ENABLE, + IOV_PROPTXSTATUS_MODE, + IOV_PROPTXSTATUS_OPT, + IOV_PROPTXSTATUS_MODULE_IGNORE, + IOV_PROPTXSTATUS_CREDIT_IGNORE, + IOV_PROPTXSTATUS_TXSTATUS_IGNORE, + IOV_PROPTXSTATUS_RXPKT_CHK, +#endif /* PROP_TXSTATUS */ + IOV_BUS_TYPE, +#ifdef WLMEDIA_HTSF + IOV_WLPKTDLYSTAT_SZ, +#endif + IOV_CHANGEMTU, + IOV_HOSTREORDER_FLOWS, +#ifdef DHDTCPACK_SUPPRESS + IOV_TCPACK_SUPPRESS, +#endif /* DHDTCPACK_SUPPRESS */ +#ifdef DHD_WMF + IOV_WMF_BSS_ENAB, + IOV_WMF_UCAST_IGMP, + IOV_WMF_MCAST_DATA_SENDUP, +#ifdef WL_IGMP_UCQUERY + IOV_WMF_UCAST_IGMP_QUERY, +#endif /* WL_IGMP_UCQUERY */ +#ifdef DHD_UCAST_UPNP + IOV_WMF_UCAST_UPNP, +#endif /* DHD_UCAST_UPNP */ +#endif /* DHD_WMF */ + IOV_AP_ISOLATE, +#ifdef DHD_UNICAST_DHCP + IOV_DHCP_UNICAST, +#endif /* DHD_UNICAST_DHCP */ +#ifdef DHD_L2_FILTER + IOV_BLOCK_PING, +#endif + IOV_LMTEST, + IOV_LAST +}; + +const bcm_iovar_t dhd_iovars[] = { + {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, +#ifdef DHD_DEBUG + {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, +#endif /* DHD_DEBUG */ + {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, + {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, + {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, + {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, +#ifdef DHD_DEBUG + {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, + {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, +#endif + {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, + {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, + {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, +#ifdef PROP_TXSTATUS + {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_BOOL, 0 }, + /* + set the proptxtstatus operation mode: + 0 - Do not do any proptxtstatus flow control + 1 - Use implied credit from a packet status + 2 - Use explicit credit + */ + {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, + {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, IOVT_UINT32, 0 }, + {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, IOVT_BOOL, 0 }, + {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, IOVT_BOOL, 0 }, + {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, IOVT_BOOL, 0 }, + {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, IOVT_BOOL, 0 }, +#endif /* PROP_TXSTATUS */ + {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, +#ifdef WLMEDIA_HTSF + {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, +#endif + {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, + {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER, + (WLHOST_REORDERDATA_MAXFLOWS + 1) }, +#ifdef DHDTCPACK_SUPPRESS + {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, IOVT_UINT8, 0 }, +#endif /* DHDTCPACK_SUPPRESS */ +#ifdef DHD_WMF + {"wmf_bss_enable", IOV_WMF_BSS_ENAB, 0, IOVT_BOOL, 0 }, + {"wmf_ucast_igmp", IOV_WMF_UCAST_IGMP, 0, IOVT_BOOL, 0 }, + {"wmf_mcast_data_sendup", IOV_WMF_MCAST_DATA_SENDUP, 0, IOVT_BOOL, 0 }, +#ifdef WL_IGMP_UCQUERY + {"wmf_ucast_igmp_query", IOV_WMF_UCAST_IGMP_QUERY, (0), IOVT_BOOL, 0 }, +#endif /* WL_IGMP_UCQUERY */ +#ifdef DHD_UCAST_UPNP + {"wmf_ucast_upnp", IOV_WMF_UCAST_UPNP, (0), IOVT_BOOL, 0 }, +#endif /* DHD_UCAST_UPNP */ +#endif /* DHD_WMF */ +#ifdef DHD_UNICAST_DHCP + {"dhcp_unicast", IOV_DHCP_UNICAST, (0), IOVT_BOOL, 0 }, +#endif /* DHD_UNICAST_DHCP */ + {"ap_isolate", IOV_AP_ISOLATE, (0), IOVT_BOOL, 0}, +#ifdef DHD_L2_FILTER + {"block_ping", IOV_BLOCK_PING, (0), IOVT_BOOL, 0}, +#endif + {"lmtest", IOV_LMTEST, 0, IOVT_UINT32, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +#define DHD_IOVAR_BUF_SIZE 128 + +#ifdef DHD_FW_COREDUMP +void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length) +{ + if (!dhd_pub->soc_ram) { +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) + dhd_pub->soc_ram = (uint8*)DHD_OS_PREALLOC(dhd_pub, + DHD_PREALLOC_MEMDUMP_RAM, length); +#else + dhd_pub->soc_ram = (uint8*) MALLOC(dhd_pub->osh, length); +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ + } + + if (dhd_pub->soc_ram == NULL) { + DHD_ERROR(("%s: Failed to allocate memory for fw crash snap shot.\n", + __FUNCTION__)); + dhd_pub->soc_ram_length = 0; + } else { + memset(dhd_pub->soc_ram, 0, length); + dhd_pub->soc_ram_length = length; + } + + /* soc_ram free handled in dhd_{free,clear} */ + return dhd_pub->soc_ram; +} +#endif /* DHD_FW_COREDUMP */ + +/* to NDIS developer, the structure dhd_common is redundant, + * please do NOT merge it back from other branches !!! + */ + +static int +dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) +{ + char eabuf[ETHER_ADDR_STR_LEN]; + + struct bcmstrbuf b; + struct bcmstrbuf *strbuf = &b; + + bcm_binit(strbuf, buf, buflen); + + /* Base DHD info */ + bcm_bprintf(strbuf, "%s\n", dhd_version); + bcm_bprintf(strbuf, "\n"); + bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", + dhdp->up, dhdp->txoff, dhdp->busstate); + bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n", + dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); + bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", + dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); + bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt); + + bcm_bprintf(strbuf, "dongle stats:\n"); + bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n", + dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, + dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); + bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n", + dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, + dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); + bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast); + + bcm_bprintf(strbuf, "bus stats:\n"); + bcm_bprintf(strbuf, "tx_packets %lu tx_dropped %lu tx_multicast %lu tx_errors %lu\n", + dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast, dhdp->tx_errors); + bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", + dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); + bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n", + dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); + bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n", + dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); + bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n", + dhdp->rx_readahead_cnt, dhdp->tx_realloc); + bcm_bprintf(strbuf, "\n"); + + /* Add any prot info */ + dhd_prot_dump(dhdp, strbuf); + bcm_bprintf(strbuf, "\n"); + + /* Add any bus info */ + dhd_bus_dump(dhdp, strbuf); + + + return (!strbuf->size ? BCME_BUFTOOSHORT : 0); +} + +int +dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifidx) +{ + wl_ioctl_t ioc; + + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + ioc.set = set; + + return dhd_wl_ioctl(dhd_pub, ifidx, &ioc, arg, len); +} + +int +dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) +{ + int ret = BCME_ERROR; + + if (dhd_pub->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s Bus is down: %d(%s)\n", __FUNCTION__, ioc->cmd, (char*)(ioc->buf))); + return BCME_NOTUP; + } + + if (dhd_os_proto_block(dhd_pub)) + { +#if defined(WL_WLC_SHIM) + wl_info_t *wl = dhd_pub_wlinfo(dhd_pub); + + wl_io_pport_t io_pport; + io_pport.dhd_pub = dhd_pub; + io_pport.ifidx = ifidx; + + ret = wl_shim_ioctl(wl->shim, ioc, &io_pport); + if (ret != BCME_OK) { + DHD_ERROR(("%s: wl_shim_ioctl(%d) ERR %d\n", __FUNCTION__, ioc->cmd, ret)); + } +#else + ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len); +#endif /* defined(WL_WLC_SHIM) */ + + if (ret && dhd_pub->up) { + /* Send hang event only if dhd_open() was success */ + dhd_os_check_hang(dhd_pub, ifidx, ret); + } + + if (ret == -ETIMEDOUT && !dhd_pub->up) { + DHD_ERROR(("%s: 'resumed on timeout' error is " + "occurred before the interface does not" + " bring up\n", __FUNCTION__)); + dhd_pub->busstate = DHD_BUS_DOWN; + } + + dhd_os_proto_unblock(dhd_pub); + + } + + return ret; +} + +uint wl_get_port_num(wl_io_pport_t *io_pport) +{ + return 0; +} + +/* Get bssidx from iovar params + * Input: dhd_pub - pointer to dhd_pub_t + * params - IOVAR params + * Output: idx - BSS index + * val - ponter to the IOVAR arguments + */ +static int +dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, char *params, int *idx, char **val) +{ + char *prefix = "bsscfg:"; + uint32 bssidx; + + if (!(strncmp(params, prefix, strlen(prefix)))) { + /* per bss setting should be prefixed with 'bsscfg:' */ + char *p = (char *)params + strlen(prefix); + + /* Skip Name */ + while (*p != '\0') + p++; + /* consider null */ + p = p + 1; + bcopy(p, &bssidx, sizeof(uint32)); + /* Get corresponding dhd index */ + bssidx = dhd_bssidx2idx(dhd_pub, bssidx); + + if (bssidx >= DHD_MAX_IFS) { + DHD_ERROR(("%s Wrong bssidx provided\n", __FUNCTION__)); + return BCME_ERROR; + } + + /* skip bss idx */ + p += sizeof(uint32); + *val = p; + *idx = bssidx; + } else { + DHD_ERROR(("%s: bad parameter for per bss iovar\n", __FUNCTION__)); + return BCME_ERROR; + } + + return BCME_OK; +} + +static int +dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, + void *params, int plen, void *arg, int len, int val_size) +{ + int bcmerror = 0; + int32 int_val = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) + goto exit; + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + switch (actionid) { + case IOV_GVAL(IOV_VERSION): + /* Need to have checked buffer length */ + bcm_strncpy_s((char*)arg, len, dhd_version, len); + break; + + case IOV_GVAL(IOV_MSGLEVEL): + int_val = (int32)dhd_msg_level; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MSGLEVEL): +#ifdef WL_CFG80211 + /* Enable DHD and WL logs in oneshot */ + if (int_val & DHD_WL_VAL2) + wl_cfg80211_enable_trace(TRUE, int_val & (~DHD_WL_VAL2)); + else if (int_val & DHD_WL_VAL) + wl_cfg80211_enable_trace(FALSE, WL_DBG_DBG); + if (!(int_val & DHD_WL_VAL2)) +#endif /* WL_CFG80211 */ + dhd_msg_level = int_val; + break; + case IOV_GVAL(IOV_BCMERRORSTR): + bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); + ((char *)arg)[BCME_STRLEN - 1] = 0x00; + break; + + case IOV_GVAL(IOV_BCMERROR): + int_val = (int32)dhd_pub->bcmerror; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_WDTICK): + int_val = (int32)dhd_watchdog_ms; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_WDTICK): + if (!dhd_pub->up) { + bcmerror = BCME_NOTUP; + break; + } + dhd_os_wd_timer(dhd_pub, (uint)int_val); + break; + + case IOV_GVAL(IOV_DUMP): + bcmerror = dhd_dump(dhd_pub, arg, len); + break; + +#ifdef DHD_DEBUG + case IOV_GVAL(IOV_DCONSOLE_POLL): + int_val = (int32)dhd_console_ms; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DCONSOLE_POLL): + dhd_console_ms = (uint)int_val; + break; + + case IOV_SVAL(IOV_CONS): + if (len > 0) + bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); + break; +#endif /* DHD_DEBUG */ + + case IOV_SVAL(IOV_CLEARCOUNTS): + dhd_pub->tx_packets = dhd_pub->rx_packets = 0; + dhd_pub->tx_errors = dhd_pub->rx_errors = 0; + dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; + dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; + dhd_pub->tx_dropped = 0; + dhd_pub->rx_dropped = 0; + dhd_pub->rx_readahead_cnt = 0; + dhd_pub->tx_realloc = 0; + dhd_pub->wd_dpc_sched = 0; + memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); + dhd_bus_clearcounts(dhd_pub); +#ifdef PROP_TXSTATUS + /* clear proptxstatus related counters */ + dhd_wlfc_clear_counts(dhd_pub); +#endif /* PROP_TXSTATUS */ + break; + + + case IOV_GVAL(IOV_IOCTLTIMEOUT): { + int_val = (int32)dhd_os_get_ioctl_resp_timeout(); + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_IOCTLTIMEOUT): { + if (int_val <= 0) + bcmerror = BCME_BADARG; + else + dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); + break; + } + + +#ifdef PROP_TXSTATUS + case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): { + bool wlfc_enab = FALSE; + bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); + if (bcmerror != BCME_OK) + goto exit; + int_val = wlfc_enab ? 1 : 0; + bcopy(&int_val, arg, val_size); + break; + } + case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): { + bool wlfc_enab = FALSE; + bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); + if (bcmerror != BCME_OK) + goto exit; + + /* wlfc is already set as desired */ + if (wlfc_enab == (int_val == 0 ? FALSE : TRUE)) + goto exit; + + if (int_val == TRUE) + bcmerror = dhd_wlfc_init(dhd_pub); + else + bcmerror = dhd_wlfc_deinit(dhd_pub); + + break; + } + case IOV_GVAL(IOV_PROPTXSTATUS_MODE): + bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_MODE): + dhd_wlfc_set_mode(dhd_pub, int_val); + break; + + case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): + bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): + dhd_wlfc_set_module_ignore(dhd_pub, int_val); + break; + + case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): + bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): + dhd_wlfc_set_credit_ignore(dhd_pub, int_val); + break; + + case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): + bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): + dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val); + break; + + case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK): + bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK): + dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val); + break; + +#endif /* PROP_TXSTATUS */ + + case IOV_GVAL(IOV_BUS_TYPE): + /* The dhd application queries the driver to check if its usb or sdio. */ +#ifdef BCMDHDUSB + int_val = BUS_TYPE_USB; +#endif +#ifdef BCMSDIO + int_val = BUS_TYPE_SDIO; +#endif +#ifdef PCIE_FULL_DONGLE + int_val = BUS_TYPE_PCIE; +#endif + bcopy(&int_val, arg, val_size); + break; + + +#ifdef WLMEDIA_HTSF + case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): + int_val = dhd_pub->htsfdlystat_sz; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): + dhd_pub->htsfdlystat_sz = int_val & 0xff; + printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); + break; +#endif + case IOV_SVAL(IOV_CHANGEMTU): + int_val &= 0xffff; + bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); + break; + + case IOV_GVAL(IOV_HOSTREORDER_FLOWS): + { + uint i = 0; + uint8 *ptr = (uint8 *)arg; + uint8 count = 0; + + ptr++; + for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { + if (dhd_pub->reorder_bufs[i] != NULL) { + *ptr = dhd_pub->reorder_bufs[i]->flow_id; + ptr++; + count++; + } + } + ptr = (uint8 *)arg; + *ptr = count; + break; + } +#ifdef DHDTCPACK_SUPPRESS + case IOV_GVAL(IOV_TCPACK_SUPPRESS): { + int_val = (uint32)dhd_pub->tcpack_sup_mode; + bcopy(&int_val, arg, val_size); + break; + } + case IOV_SVAL(IOV_TCPACK_SUPPRESS): { + bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val); + break; + } +#endif /* DHDTCPACK_SUPPRESS */ +#ifdef DHD_WMF + case IOV_GVAL(IOV_WMF_BSS_ENAB): { + uint32 bssidx; + dhd_wmf_t *wmf; + char *val; + + if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { + DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__)); + bcmerror = BCME_BADARG; + break; + } + + wmf = dhd_wmf_conf(dhd_pub, bssidx); + int_val = wmf->wmf_enable ? 1 :0; + bcopy(&int_val, arg, val_size); + break; + } + case IOV_SVAL(IOV_WMF_BSS_ENAB): { + /* Enable/Disable WMF */ + uint32 bssidx; + dhd_wmf_t *wmf; + char *val; + + if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { + DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__)); + bcmerror = BCME_BADARG; + break; + } + + ASSERT(val); + bcopy(val, &int_val, sizeof(uint32)); + wmf = dhd_wmf_conf(dhd_pub, bssidx); + if (wmf->wmf_enable == int_val) + break; + if (int_val) { + /* Enable WMF */ + if (dhd_wmf_instance_add(dhd_pub, bssidx) != BCME_OK) { + DHD_ERROR(("%s: Error in creating WMF instance\n", + __FUNCTION__)); + break; + } + if (dhd_wmf_start(dhd_pub, bssidx) != BCME_OK) { + DHD_ERROR(("%s: Failed to start WMF\n", __FUNCTION__)); + break; + } + wmf->wmf_enable = TRUE; + } else { + /* Disable WMF */ + wmf->wmf_enable = FALSE; + dhd_wmf_stop(dhd_pub, bssidx); + dhd_wmf_instance_del(dhd_pub, bssidx); + } + break; + } + case IOV_GVAL(IOV_WMF_UCAST_IGMP): + int_val = dhd_pub->wmf_ucast_igmp ? 1 : 0; + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_WMF_UCAST_IGMP): + if (dhd_pub->wmf_ucast_igmp == int_val) + break; + + if (int_val >= OFF && int_val <= ON) + dhd_pub->wmf_ucast_igmp = int_val; + else + bcmerror = BCME_RANGE; + break; + case IOV_GVAL(IOV_WMF_MCAST_DATA_SENDUP): + int_val = dhd_wmf_mcast_data_sendup(dhd_pub, 0, FALSE, FALSE); + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_WMF_MCAST_DATA_SENDUP): + dhd_wmf_mcast_data_sendup(dhd_pub, 0, TRUE, int_val); + break; + +#ifdef WL_IGMP_UCQUERY + case IOV_GVAL(IOV_WMF_UCAST_IGMP_QUERY): + int_val = dhd_pub->wmf_ucast_igmp_query ? 1 : 0; + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_WMF_UCAST_IGMP_QUERY): + if (dhd_pub->wmf_ucast_igmp_query == int_val) + break; + + if (int_val >= OFF && int_val <= ON) + dhd_pub->wmf_ucast_igmp_query = int_val; + else + bcmerror = BCME_RANGE; + break; +#endif /* WL_IGMP_UCQUERY */ +#ifdef DHD_UCAST_UPNP + case IOV_GVAL(IOV_WMF_UCAST_UPNP): + int_val = dhd_pub->wmf_ucast_upnp ? 1 : 0; + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_WMF_UCAST_UPNP): + if (dhd_pub->wmf_ucast_upnp == int_val) + break; + + if (int_val >= OFF && int_val <= ON) + dhd_pub->wmf_ucast_upnp = int_val; + else + bcmerror = BCME_RANGE; + break; +#endif /* DHD_UCAST_UPNP */ +#endif /* DHD_WMF */ + + +#ifdef DHD_UNICAST_DHCP + case IOV_GVAL(IOV_DHCP_UNICAST): + int_val = dhd_pub->dhcp_unicast; + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_DHCP_UNICAST): + if (dhd_pub->dhcp_unicast == int_val) + break; + + if (int_val >= OFF || int_val <= ON) { + dhd_pub->dhcp_unicast = int_val; + } else { + bcmerror = BCME_RANGE; + } + break; +#endif /* DHD_UNICAST_DHCP */ +#ifdef DHD_L2_FILTER + case IOV_GVAL(IOV_BLOCK_PING): + int_val = dhd_pub->block_ping; + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_BLOCK_PING): + if (dhd_pub->block_ping == int_val) + break; + if (int_val >= OFF || int_val <= ON) { + dhd_pub->block_ping = int_val; + } else { + bcmerror = BCME_RANGE; + } + break; +#endif + + case IOV_GVAL(IOV_AP_ISOLATE): { + uint32 bssidx; + char *val; + + if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { + DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__)); + bcmerror = BCME_BADARG; + break; + } + + int_val = dhd_get_ap_isolate(dhd_pub, bssidx); + bcopy(&int_val, arg, val_size); + break; + } + case IOV_SVAL(IOV_AP_ISOLATE): { + uint32 bssidx; + char *val; + + if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { + DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__)); + bcmerror = BCME_BADARG; + break; + } + + ASSERT(val); + bcopy(val, &int_val, sizeof(uint32)); + dhd_set_ap_isolate(dhd_pub, bssidx, int_val); + break; + } + + case IOV_GVAL(IOV_LMTEST): { + *(uint32 *)arg = (uint32)lmtest; + break; + } + + case IOV_SVAL(IOV_LMTEST): { + uint32 val = *(uint32 *)arg; + if (val > 50) + bcmerror = BCME_BADARG; + else { + lmtest = (uint)val; + DHD_ERROR(("%s: lmtest %s\n", __FUNCTION__, + (lmtest == FALSE)? "OFF" : "ON")); + } + break; + } + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } + +exit: + DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); + return bcmerror; +} + +/* Store the status of a connection attempt for later retrieval by an iovar */ +void +dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) +{ + /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID + * because an encryption/rsn mismatch results in both events, and + * the important information is in the WLC_E_PRUNE. + */ + if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && + dhd_conn_event == WLC_E_PRUNE)) { + dhd_conn_event = event; + dhd_conn_status = status; + dhd_conn_reason = reason; + } +} + +bool +dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) +{ + void *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)) { + 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 = pktq_peek_tail(q, &eprec); + ASSERT(p); + if (eprec > prec || eprec < 0) + return FALSE; + } + + /* Evict if needed */ + if (eprec >= 0) { + /* Detect queueing to unconfigured precedence */ + ASSERT(!pktq_pempty(q, eprec)); + discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); + if (eprec == prec && !discard_oldest) + return FALSE; /* refuse newer (incoming) packet */ + /* Evict packet according to discard policy */ + p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); + ASSERT(p); +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + PKTFREE(dhdp->osh, p, TRUE); + } + + /* Enqueue */ + p = pktq_penq(q, prec, pkt); + ASSERT(p); + + return TRUE; +} + +/* + * Functions to drop proper pkts from queue: + * If one pkt in queue is non-fragmented, drop first non-fragmented pkt only + * If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts + * If can't find pkts matching upper 2 cases, drop first pkt anyway + */ +bool +dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn) +{ + struct pktq_prec *q = NULL; + void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL; + pkt_frag_t frag_info; + + ASSERT(dhdp && pq); + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + p = q->head; + + if (p == NULL) + return FALSE; + + while (p) { + frag_info = pkt_frag_info(dhdp->osh, p); + if (frag_info == DHD_PKT_FRAG_NONE) { + break; + } else if (frag_info == DHD_PKT_FRAG_FIRST) { + if (first) { + /* No last frag pkt, use prev as last */ + last = prev; + break; + } else { + first = p; + prev_first = prev; + } + } else if (frag_info == DHD_PKT_FRAG_LAST) { + if (first) { + last = p; + break; + } + } + + prev = p; + p = PKTLINK(p); + } + + if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) { + /* Not found matching pkts, use oldest */ + prev = NULL; + p = q->head; + frag_info = 0; + } + + if (frag_info == DHD_PKT_FRAG_NONE) { + first = last = p; + prev_first = prev; + } + + p = first; + while (p) { + next = PKTLINK(p); + q->len--; + pq->len--; + + PKTSETLINK(p, NULL); + + if (fn) + fn(dhdp, prec, p, TRUE); + + if (p == last) + break; + + p = next; + } + + if (prev_first == NULL) { + if ((q->head = next) == NULL) + q->tail = NULL; + } else { + PKTSETLINK(prev_first, next); + if (!next) + q->tail = prev_first; + } + + return TRUE; +} + +static int +dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + int bcmerror = 0; + int val_size; + const bcm_iovar_t *vi = NULL; + uint32 actionid; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(name); + ASSERT(len >= 0); + + /* Get MUST have return space */ + ASSERT(set || (arg && len)); + + /* Set does NOT take qualifiers */ + ASSERT(!set || (!params && !plen)); + + if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { + bcmerror = BCME_UNSUPPORTED; + goto exit; + } + + DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, + name, (set ? "set" : "get"), len, plen)); + + /* set up 'params' pointer in case this is a set command so that + * the convenience int and bool code can be common to set and get + */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + /* all other types are integer sized */ + val_size = sizeof(int); + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + + bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); + +exit: + return bcmerror; +} + +int +dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) +{ + int bcmerror = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!buf) { + return BCME_BADARG; + } + + switch (ioc->cmd) { + case DHD_GET_MAGIC: + if (buflen < sizeof(int)) + bcmerror = BCME_BUFTOOSHORT; + else + *(int*)buf = DHD_IOCTL_MAGIC; + break; + + case DHD_GET_VERSION: + if (buflen < sizeof(int)) + bcmerror = BCME_BUFTOOSHORT; + else + *(int*)buf = DHD_IOCTL_VERSION; + break; + + case DHD_GET_VAR: + case DHD_SET_VAR: { + char *arg; + uint arglen; + + /* scan past the name to any arguments */ + for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) + ; + + if (*arg) { + bcmerror = BCME_BUFTOOSHORT; + break; + } + + /* account for the NUL terminator */ + arg++, arglen--; + + /* call with the appropriate arguments */ + if (ioc->cmd == DHD_GET_VAR) + bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, + buf, buflen, IOV_GET); + else + bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); + if (bcmerror != BCME_UNSUPPORTED) + break; + + /* not in generic table, try protocol module */ + if (ioc->cmd == DHD_GET_VAR) + bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, + arglen, buf, buflen, IOV_GET); + else + bcmerror = dhd_prot_iovar_op(dhd_pub, buf, + NULL, 0, arg, arglen, IOV_SET); + if (bcmerror != BCME_UNSUPPORTED) + break; + + /* if still not found, try bus module */ + if (ioc->cmd == DHD_GET_VAR) { + bcmerror = dhd_bus_iovar_op(dhd_pub, buf, + arg, arglen, buf, buflen, IOV_GET); + } else { + bcmerror = dhd_bus_iovar_op(dhd_pub, buf, + NULL, 0, arg, arglen, IOV_SET); + } + + break; + } + + default: + bcmerror = BCME_UNSUPPORTED; + } + + return bcmerror; +} + +#ifdef SHOW_EVENTS +#ifdef SHOW_LOGTRACE + +#define AVOID_BYTE 64 +#define MAX_NO_OF_ARG 16 + +static int +check_event_log_sequence_number(uint32 seq_no) +{ + int32 diff; + uint32 ret; + static uint32 logtrace_seqnum_prev = 0; + + diff = ntoh32(seq_no)-logtrace_seqnum_prev; + switch (diff) + { + case 0: + ret = -1; /* duplicate packet . drop */ + break; + + case 1: + ret =0; /* in order */ + break; + + default: + if ((ntoh32(seq_no) == 0) && + (logtrace_seqnum_prev == 0xFFFFFFFF) ) { /* in-order - Roll over */ + ret = 0; + } else { + + if (diff > 0) { + DHD_EVENT(("WLC_E_TRACE:" + "Event lost (log) seqnum %d nblost %d\n", + ntoh32(seq_no), (diff-1))); + } else { + DHD_EVENT(("WLC_E_TRACE:" + "Event Packets coming out of order!!\n")); + } + ret = 0; + } + } + + logtrace_seqnum_prev = ntoh32(seq_no); + + return ret; +} +#endif /* SHOW_LOGTRACE */ + +static void +wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, + void *raw_event_ptr, char *eventmask) +{ + uint i, status, reason; + bool group = FALSE, flush_txq = FALSE, link = FALSE; + const char *auth_str; + const char *event_name; + uchar *buf; + char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; + uint event_type, flags, auth_type, datalen; + + event_type = ntoh32(event->event_type); + flags = ntoh16(event->flags); + status = ntoh32(event->status); + reason = ntoh32(event->reason); + BCM_REFERENCE(reason); + auth_type = ntoh32(event->auth_type); + datalen = ntoh32(event->datalen); + + /* debug dump of event messages */ + snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", + (uchar)event->addr.octet[0]&0xff, + (uchar)event->addr.octet[1]&0xff, + (uchar)event->addr.octet[2]&0xff, + (uchar)event->addr.octet[3]&0xff, + (uchar)event->addr.octet[4]&0xff, + (uchar)event->addr.octet[5]&0xff); + + event_name = bcmevent_get_name(event_type); + BCM_REFERENCE(event_name); + + if (flags & WLC_EVENT_MSG_LINK) + link = TRUE; + if (flags & WLC_EVENT_MSG_GROUP) + group = TRUE; + if (flags & WLC_EVENT_MSG_FLUSHTXQ) + flush_txq = TRUE; + + switch (event_type) { + case WLC_E_START: + case WLC_E_DEAUTH: + case WLC_E_DISASSOC: + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + break; + + case WLC_E_ASSOC_IND: + case WLC_E_REASSOC_IND: + + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + break; + + case WLC_E_ASSOC: + case WLC_E_REASSOC: + if (status == WLC_E_STATUS_SUCCESS) { + DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); + } else if (status == WLC_E_STATUS_TIMEOUT) { + DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); + } else if (status == WLC_E_STATUS_FAIL) { + DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", + event_name, eabuf, (int)reason)); + } else { + DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n", + event_name, eabuf, (int)status)); + } + break; + + case WLC_E_DEAUTH_IND: + case WLC_E_DISASSOC_IND: + DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); + break; + + case WLC_E_AUTH: + case WLC_E_AUTH_IND: + if (auth_type == DOT11_OPEN_SYSTEM) + auth_str = "Open System"; + else if (auth_type == DOT11_SHARED_KEY) + auth_str = "Shared Key"; + else { + snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); + auth_str = err_msg; + } + if (event_type == WLC_E_AUTH_IND) { + DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); + } else if (status == WLC_E_STATUS_SUCCESS) { + DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", + event_name, eabuf, auth_str)); + } else if (status == WLC_E_STATUS_TIMEOUT) { + DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", + event_name, eabuf, auth_str)); + } else if (status == WLC_E_STATUS_FAIL) { + DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", + event_name, eabuf, auth_str, (int)reason)); + } + BCM_REFERENCE(auth_str); + + break; + + case WLC_E_JOIN: + case WLC_E_ROAM: + case WLC_E_SET_SSID: + if (status == WLC_E_STATUS_SUCCESS) { + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + } else if (status == WLC_E_STATUS_FAIL) { + DHD_EVENT(("MACEVENT: %s, failed\n", event_name)); + } else if (status == WLC_E_STATUS_NO_NETWORKS) { + DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name)); + } else { + DHD_EVENT(("MACEVENT: %s, unexpected status %d\n", + event_name, (int)status)); + } + break; + + case WLC_E_BEACON_RX: + if (status == WLC_E_STATUS_SUCCESS) { + DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); + } else if (status == WLC_E_STATUS_FAIL) { + DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); + } else { + DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); + } + break; + + case WLC_E_LINK: + DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); + BCM_REFERENCE(link); + break; + + case WLC_E_MIC_ERROR: + DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", + event_name, eabuf, group, flush_txq)); + BCM_REFERENCE(group); + BCM_REFERENCE(flush_txq); + break; + + case WLC_E_ICV_ERROR: + case WLC_E_UNICAST_DECODE_ERROR: + case WLC_E_MULTICAST_DECODE_ERROR: + DHD_EVENT(("MACEVENT: %s, MAC %s\n", + event_name, eabuf)); + break; + + case WLC_E_TXFAIL: + case WLC_E_AIBSS_TXFAIL: + DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf)); + break; + + case WLC_E_SCAN_COMPLETE: + case WLC_E_ASSOC_REQ_IE: + case WLC_E_ASSOC_RESP_IE: + case WLC_E_PMKID_CACHE: + DHD_EVENT(("MACEVENT: %s\n", event_name)); + break; + + case WLC_E_PFN_NET_FOUND: + case WLC_E_PFN_NET_LOST: + case WLC_E_PFN_SCAN_COMPLETE: + case WLC_E_PFN_SCAN_NONE: + case WLC_E_PFN_SCAN_ALLGONE: + DHD_EVENT(("PNOEVENT: %s\n", event_name)); + break; + + case WLC_E_PSK_SUP: + case WLC_E_PRUNE: + DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", + event_name, (int)status, (int)reason)); + break; + +#ifdef WIFI_ACT_FRAME + case WLC_E_ACTION_FRAME: + DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); + break; +#endif /* WIFI_ACT_FRAME */ + +#ifdef SHOW_LOGTRACE + case WLC_E_TRACE: + { + msgtrace_hdr_t hdr; + uint32 nblost; + uint8 count; + char *s, *p; + static uint32 seqnum_prev = 0; + uint32 *record = NULL; + uint32 *log_ptr = NULL; + uint32 writeindex = 0; + event_log_hdr_t event_hdr; + int no_of_fmts = 0; + char *fmt = NULL; + dhd_event_log_t *raw_event = (dhd_event_log_t *) raw_event_ptr; + + buf = (uchar *) event_data; + memcpy(&hdr, buf, MSGTRACE_HDRLEN); + + if (hdr.version != MSGTRACE_VERSION) { + DHD_EVENT(("\nMACEVENT: %s [unsupported version --> " + "dhd version:%d dongle version:%d]\n", + event_name, MSGTRACE_VERSION, hdr.version)); + /* Reset datalen to avoid display below */ + datalen = 0; + break; + } + + if (hdr.trace_type == MSGTRACE_HDR_TYPE_MSG) { + /* There are 2 bytes available at the end of data */ + buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; + + if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { + DHD_EVENT(("WLC_E_TRACE: [Discarded traces in dongle -->" + "discarded_bytes %d discarded_printf %d]\n", + ntoh32(hdr.discarded_bytes), + ntoh32(hdr.discarded_printf))); + } + + nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; + if (nblost > 0) { + DHD_EVENT(("WLC_E_TRACE:" + "[Event lost (msg) --> seqnum %d nblost %d\n", + ntoh32(hdr.seqnum), nblost)); + } + seqnum_prev = ntoh32(hdr.seqnum); + + /* Display the trace buffer. Advance from + * \n to \n to avoid display big + * printf (issue with Linux printk ) + */ + p = (char *)&buf[MSGTRACE_HDRLEN]; + while (*p != '\0' && (s = strstr(p, "\n")) != NULL) { + *s = '\0'; + DHD_EVENT(("%s\n", p)); + p = s+1; + } + if (*p) + DHD_EVENT(("%s", p)); + + /* Reset datalen to avoid display below */ + datalen = 0; + + } else if (hdr.trace_type == MSGTRACE_HDR_TYPE_LOG) { + /* Let the standard event printing work for now */ + uint32 timestamp, w, malloc_len; + + if (check_event_log_sequence_number(hdr.seqnum)) { + + DHD_EVENT(("%s: WLC_E_TRACE:" + "[Event duplicate (log) %d] dropping!!\n", + __FUNCTION__, hdr.seqnum)); + return; /* drop duplicate events */ + } + + p = (char *)&buf[MSGTRACE_HDRLEN]; + datalen -= MSGTRACE_HDRLEN; + w = ntoh32((uint32)*p); + p += 4; + datalen -= 4; + timestamp = ntoh32((uint32)*p); + BCM_REFERENCE(timestamp); + BCM_REFERENCE(w); + + DHD_EVENT(("timestamp %x%x\n", timestamp, w)); + + if (raw_event->fmts) { + malloc_len = datalen+ AVOID_BYTE; + record = (uint32 *)MALLOC(dhd_pub->osh, malloc_len); + if (record == NULL) { + DHD_EVENT(("MSGTRACE_HDR_TYPE_LOG:" + "malloc failed\n")); + return; + } + log_ptr = (uint32 *) (p + datalen); + writeindex = datalen/4; + + if (record) { + while (datalen > 4) { + log_ptr--; + datalen -= 4; + event_hdr.t = *log_ptr; + /* + * Check for partially overriten entries + */ + if (log_ptr - (uint32 *) p < event_hdr.count) { + break; + } + /* + * Check for end of the Frame. + */ + if (event_hdr.tag == EVENT_LOG_TAG_NULL) { + continue; + } + /* + * Check For Special Time Stamp Packet + */ + if (event_hdr.tag == EVENT_LOG_TAG_TS) { + datalen -= 12; + log_ptr = log_ptr - 3; + continue; + } + + log_ptr[0] = event_hdr.t; + if (event_hdr.count > MAX_NO_OF_ARG) { + break; + } + /* Now place the header at the front + * and copy back. + */ + log_ptr -= event_hdr.count; + + writeindex = writeindex - event_hdr.count; + record[writeindex++] = event_hdr.t; + for (count = 0; count < (event_hdr.count-1); + count++) { + record[writeindex++] = log_ptr[count]; + } + writeindex = writeindex - event_hdr.count; + datalen = datalen - (event_hdr.count * 4); + no_of_fmts++; + } + } + + while (no_of_fmts--) + { + event_log_hdr_t event_hdr; + event_hdr.t = record[writeindex]; + + if ((event_hdr.fmt_num>>2) < raw_event->num_fmts) { + fmt = raw_event->fmts[event_hdr.fmt_num>>2]; + DHD_EVENT((fmt, + record[writeindex + 1], + record[writeindex + 2], + record[writeindex + 3], + record[writeindex + 4], + record[writeindex + 5], + record[writeindex + 6], + record[writeindex + 7], + record[writeindex + 8], + record[writeindex + 9], + record[writeindex + 10], + record[writeindex + 11], + record[writeindex + 12], + record[writeindex + 13], + record[writeindex + 14], + record[writeindex + 15], + record[writeindex + 16])); + + if (fmt[strlen(fmt) - 1] != '\n') { + /* Add newline if missing */ + DHD_EVENT(("\n")); + } + } + + writeindex = writeindex + event_hdr.count; + } + + if (record) { + MFREE(dhd_pub->osh, record, malloc_len); + record = NULL; + } + } else { + while (datalen > 4) { + p += 4; + datalen -= 4; + /* Print each word. DO NOT ntoh it. */ + DHD_EVENT((" %8.8x", *((uint32 *) p))); + } + DHD_EVENT(("\n")); + } + datalen = 0; + } + break; + } +#endif /* SHOW_LOGTRACE */ + + case WLC_E_RSSI: + DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); + break; + + case WLC_E_SERVICE_FOUND: + case WLC_E_P2PO_ADD_DEVICE: + case WLC_E_P2PO_DEL_DEVICE: + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + break; + +#ifdef BT_WIFI_HANDOBER + case WLC_E_BT_WIFI_HANDOVER_REQ: + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + break; +#endif + + default: + DHD_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 (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen) { + buf = (uchar *) event_data; + BCM_REFERENCE(buf); + DHD_EVENT((" data (%d) : ", datalen)); + for (i = 0; i < datalen; i++) + DHD_EVENT((" 0x%02x ", *buf++)); + DHD_EVENT(("\n")); + } +} +#endif /* SHOW_EVENTS */ + +/* Check whether packet is a BRCM event pkt. If it is, record event data. */ +int +wl_host_event_get_data(void *pktdata, uint pktlen, void *evt) +{ + int ret; + + ret = is_wlc_event_frame(pktdata, pktlen, 0, evt); + if (ret != BCME_OK) { + DHD_ERROR(("%s: Invalid event frame, err = %d\n", + __FUNCTION__, ret)); + } + + return ret; +} + +int +wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, size_t pktlen, + wl_event_msg_t *event, void **data_ptr, void *raw_event) +{ + bcm_event_t *pvt_data = (bcm_event_t *)pktdata; + uint8 *event_data; + uint32 type, status, datalen; + uint16 flags; + uint evlen; + int hostidx; + int ret; + uint16 usr_subtype; + wl_event_msg_t evtmsg; + + ret = wl_host_event_get_data(pktdata, pktlen, &evtmsg); + if (ret != BCME_OK) { + return ret; + } + + usr_subtype = ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype); + switch (usr_subtype) { + case BCMILCP_BCM_SUBTYPE_EVENT: + memcpy(event, &evtmsg, sizeof(wl_event_msg_t)); + *data_ptr = &pvt_data[1]; + break; + default: + return BCME_NOTFOUND; + } + + /* start wl_event_msg process */ + event_data = *data_ptr; + + type = ntoh32_ua((void *)&event->event_type); + flags = ntoh16_ua((void *)&event->flags); + status = ntoh32_ua((void *)&event->status); + datalen = ntoh32_ua((void *)&event->datalen); + + evlen = datalen + sizeof(bcm_event_t); + + /* find equivalent host index for event ifidx */ + hostidx = dhd_ifidx2hostidx(dhd_pub->info, event->ifidx); + + switch (type) { +#ifdef PROP_TXSTATUS + case WLC_E_FIFO_CREDIT_MAP: + dhd_wlfc_enable(dhd_pub); + dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data); + WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " + "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], + event_data[2], + event_data[3], event_data[4], event_data[5])); + break; + + case WLC_E_BCMC_CREDIT_SUPPORT: + dhd_wlfc_BCMCCredit_support_event(dhd_pub); + break; +#endif + + case WLC_E_IF: + { + struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data; + + /* Ignore the event if NOIF is set */ + if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) { + DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n")); + return (BCME_UNSUPPORTED); + } +#ifdef PCIE_FULL_DONGLE + dhd_update_interface_flow_info(dhd_pub, ifevent->ifidx, + ifevent->opcode, ifevent->role); +#endif +#ifdef PROP_TXSTATUS + { + uint8* ea = pvt_data->eth.ether_dhost; + WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " + "[%02x:%02x:%02x:%02x:%02x:%02x]\n", + ifevent->ifidx, + ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD":"DEL"), + ((ifevent->role == 0) ? "STA":"AP "), + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); + (void)ea; + + if (ifevent->opcode == WLC_E_IF_CHANGE) + dhd_wlfc_interface_event(dhd_pub, + eWLFC_MAC_ENTRY_ACTION_UPDATE, + ifevent->ifidx, ifevent->role, ea); + else + dhd_wlfc_interface_event(dhd_pub, + ((ifevent->opcode == WLC_E_IF_ADD) ? + eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), + ifevent->ifidx, ifevent->role, ea); + + /* dhd already has created an interface by default, for 0 */ + if (ifevent->ifidx == 0) + break; + } +#endif /* PROP_TXSTATUS */ + + if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { + if (ifevent->opcode == WLC_E_IF_ADD) { + if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname, + event->addr.octet)) { + + DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d %s\n", + __FUNCTION__, ifevent->ifidx, event->ifname)); + return (BCME_ERROR); + } + } else if (ifevent->opcode == WLC_E_IF_DEL) { + dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname, + event->addr.octet); + } else if (ifevent->opcode == WLC_E_IF_CHANGE) { +#ifdef WL_CFG80211 + wl_cfg80211_notify_ifchange(ifevent->ifidx, + event->ifname, event->addr.octet, ifevent->bssidx); +#endif /* WL_CFG80211 */ + } + } else { +#if !defined(PROP_TXSTATUS) || !defined(PCIE_FULL_DONGLE) + DHD_ERROR(("%s: Invalid ifidx %d for %s\n", + __FUNCTION__, ifevent->ifidx, event->ifname)); +#endif /* !PROP_TXSTATUS */ + } + /* send up the if event: btamp user needs it */ + *ifidx = hostidx; + /* push up to external supp/auth */ + dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); + break; + } + +#ifdef WLMEDIA_HTSF + case WLC_E_HTSFSYNC: + htsf_update(dhd_pub->info, event_data); + break; +#endif /* WLMEDIA_HTSF */ + case WLC_E_PFN_NET_FOUND: + case WLC_E_PFN_NET_LOST: + break; +#if defined(PNO_SUPPORT) + case WLC_E_PFN_BSSID_NET_FOUND: + case WLC_E_PFN_BSSID_NET_LOST: + case WLC_E_PFN_BEST_BATCHING: + dhd_pno_event_handler(dhd_pub, event, (void *)event_data); + break; +#endif +#if defined(RTT_SUPPORT) + case WLC_E_PROXD: + dhd_rtt_event_handler(dhd_pub, event, (void *)event_data); + break; +#endif /* RTT_SUPPORT */ + /* These are what external supplicant/authenticator wants */ + case WLC_E_ASSOC_IND: + case WLC_E_AUTH_IND: + case WLC_E_REASSOC_IND: + dhd_findadd_sta(dhd_pub, hostidx, &event->addr.octet); + break; + case WLC_E_LINK: +#ifdef PCIE_FULL_DONGLE + if (dhd_update_interface_link_status(dhd_pub, (uint8)hostidx, + (uint8)flags) != BCME_OK) + break; + if (!flags) { + dhd_flow_rings_delete(dhd_pub, hostidx); + } + /* fall through */ +#endif + case WLC_E_DEAUTH: + case WLC_E_DEAUTH_IND: + case WLC_E_DISASSOC: + case WLC_E_DISASSOC_IND: + if (type != WLC_E_LINK) { + dhd_del_sta(dhd_pub, hostidx, &event->addr.octet); + } + DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", + __FUNCTION__, type, flags, status)); +#ifdef PCIE_FULL_DONGLE + if (type != WLC_E_LINK) { + uint8 ifindex = (uint8)hostidx; + uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex); + if (DHD_IF_ROLE_STA(role)) { + dhd_flow_rings_delete(dhd_pub, ifindex); + } else { + dhd_flow_rings_delete_for_peer(dhd_pub, ifindex, + &event->addr.octet[0]); + } + } +#endif + /* fall through */ + default: + *ifidx = hostidx; + /* push up to external supp/auth */ + dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); + DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", + __FUNCTION__, type, flags, status)); + BCM_REFERENCE(flags); + BCM_REFERENCE(status); + + break; + } + +#ifdef SHOW_EVENTS + wl_show_host_event(dhd_pub, event, + (void *)event_data, raw_event, dhd_pub->enable_log); +#endif /* SHOW_EVENTS */ + + return (BCME_OK); +} + +void +wl_event_to_host_order(wl_event_msg_t * evt) +{ + /* Event struct members passed from dongle to host are stored in network + * byte order. Convert all members to host-order. + */ + evt->event_type = ntoh32(evt->event_type); + evt->flags = ntoh16(evt->flags); + evt->status = ntoh32(evt->status); + evt->reason = ntoh32(evt->reason); + evt->auth_type = ntoh32(evt->auth_type); + evt->datalen = ntoh32(evt->datalen); + evt->version = ntoh16(evt->version); +} + +void +dhd_print_buf(void *pbuf, int len, int bytes_per_line) +{ +#ifdef DHD_DEBUG + int i, j = 0; + unsigned char *buf = pbuf; + + if (bytes_per_line == 0) { + bytes_per_line = len; + } + + for (i = 0; i < len; i++) { + printf("%2.2x", *buf++); + j++; + if (j == bytes_per_line) { + printf("\n"); + j = 0; + } else { + printf(":"); + } + } + printf("\n"); +#endif /* DHD_DEBUG */ +} +#ifndef strtoul +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#endif + +#ifdef PKT_FILTER_SUPPORT +/* Convert user's input in hex pattern to byte-size mask */ +static int +wl_pattern_atoh(char *src, char *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && + strncmp(src, "0X", 2) != 0) { + DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); + return -1; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); + return -1; + } + for (i = 0; *src != '\0'; i++) { + char num[3]; + bcm_strncpy_s(num, sizeof(num), src, 2); + num[2] = '\0'; + dst[i] = (uint8)strtoul(num, NULL, 16); + src += 2; + } + return i; +} + +void +dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) +{ + char *argv[8]; + int i = 0; + const char *str; + int buf_len; + int str_len; + char *arg_save = 0, *arg_org = 0; + int rc; + char buf[32] = {0}; + wl_pkt_filter_enable_t enable_parm; + wl_pkt_filter_enable_t * pkt_filterp; + + if (!arg) + return; + + if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { + DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); + goto fail; + } + arg_org = arg_save; + memcpy(arg_save, arg, strlen(arg) + 1); + + argv[i] = bcmstrtok(&arg_save, " ", 0); + + i = 0; + if (argv[i] == NULL) { + DHD_ERROR(("No args provided\n")); + goto fail; + } + + str = "pkt_filter_enable"; + str_len = strlen(str); + bcm_strncpy_s(buf, sizeof(buf) - 1, str, sizeof(buf) - 1); + buf[ sizeof(buf) - 1 ] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); + + /* Parse packet filter id. */ + enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); + + /* Parse enable/disable value. */ + enable_parm.enable = htod32(enable); + + buf_len += sizeof(enable_parm); + memcpy((char *)pkt_filterp, + &enable_parm, + sizeof(enable_parm)); + + /* Enable/disable the specified filter. */ + rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); + rc = rc >= 0 ? 0 : rc; + if (rc) + DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", + __FUNCTION__, arg, rc)); + else + DHD_TRACE(("%s: successfully added pktfilter %s\n", + __FUNCTION__, arg)); + + /* Contorl the master mode */ + rc = dhd_iovar(dhd, 0, "pkt_filter_mode", (char *)&master_mode, + sizeof(master_mode), NULL, 0, TRUE); + rc = rc >= 0 ? 0 : rc; + if (rc) + DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", + __FUNCTION__, arg, rc)); + +fail: + if (arg_org) + MFREE(dhd->osh, arg_org, strlen(arg) + 1); +} + +void +dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) +{ + const char *str; + wl_pkt_filter_t pkt_filter; + wl_pkt_filter_t *pkt_filterp; + int buf_len; + int str_len; + int rc; + uint32 mask_size; + uint32 pattern_size; + char *argv[8], * buf = 0; + int i = 0; + char *arg_save = 0, *arg_org = 0; +#define BUF_SIZE 2048 + + if (!arg) + return; + + if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { + DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); + goto fail; + } + + arg_org = arg_save; + + if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { + DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); + goto fail; + } + + memcpy(arg_save, arg, strlen(arg) + 1); + + if (strlen(arg) > BUF_SIZE) { + DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); + goto fail; + } + + argv[i] = bcmstrtok(&arg_save, " ", 0); + while (argv[i++]) + argv[i] = bcmstrtok(&arg_save, " ", 0); + + i = 0; + if (argv[i] == NULL) { + DHD_ERROR(("No args provided\n")); + goto fail; + } + + str = "pkt_filter_add"; + str_len = strlen(str); + bcm_strncpy_s(buf, BUF_SIZE, str, str_len); + buf[ str_len ] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); + + /* Parse packet filter id. */ + pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Polarity not provided\n")); + goto fail; + } + + /* Parse filter polarity. */ + pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Filter type not provided\n")); + goto fail; + } + + /* Parse filter type. */ + pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Offset not provided\n")); + goto fail; + } + + /* Parse pattern filter offset. */ + pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Bitmask not provided\n")); + goto fail; + } + + /* Parse pattern filter mask. */ + mask_size = + htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Pattern not provided\n")); + goto fail; + } + + /* Parse pattern filter pattern. */ + pattern_size = + htod32(wl_pattern_atoh(argv[i], + (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); + + if (mask_size != pattern_size) { + DHD_ERROR(("Mask and pattern not the same size\n")); + goto fail; + } + + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_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, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); + + rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); + rc = rc >= 0 ? 0 : rc; + + if (rc) + DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", + __FUNCTION__, arg, rc)); + else + DHD_TRACE(("%s: successfully added pktfilter %s\n", + __FUNCTION__, arg)); + +fail: + if (arg_org) + MFREE(dhd->osh, arg_org, strlen(arg) + 1); + + if (buf) + MFREE(dhd->osh, buf, BUF_SIZE); +} + +void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id) +{ + int ret; + + ret = dhd_iovar(dhd, 0, "pkt_filter_delete", (char *)&id, + sizeof(id), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n", + __FUNCTION__, id, ret)); + } +} +#endif /* PKT_FILTER_SUPPORT */ + +/* ========================== */ +/* ==== ARP OFFLOAD SUPPORT = */ +/* ========================== */ +#ifdef ARP_OFFLOAD_SUPPORT +void +dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) +{ + int retcode; + + retcode = dhd_iovar(dhd, 0, "arp_ol", (char *)&arp_mode, + sizeof(arp_mode), NULL, 0, TRUE); + retcode = retcode >= 0 ? 0 : retcode; + if (retcode) + DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", + __FUNCTION__, arp_mode, retcode)); + else + DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", + __FUNCTION__, arp_mode)); +} + +void +dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) +{ + char iovbuf[DHD_IOVAR_BUF_SIZE]; + int retcode; + + retcode = dhd_iovar(dhd, 0, "arpoe", (char *)&arp_enable, + sizeof(arp_enable), NULL, 0, TRUE); + retcode = retcode >= 0 ? 0 : retcode; + if (retcode) + DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n", + __FUNCTION__, arp_enable, retcode)); + else + DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", + __FUNCTION__, arp_enable)); + if (arp_enable) { + uint32 version; + memset(iovbuf, 0, sizeof(iovbuf)); + retcode = dhd_iovar(dhd, 0, "arp_version", NULL, 0, iovbuf, sizeof(iovbuf), + FALSE); + if (retcode) { + DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n", + __FUNCTION__, retcode)); + dhd->arp_version = 1; + } + else { + memcpy(&version, iovbuf, sizeof(version)); + DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version)); + dhd->arp_version = version; + } + } +} + +void +dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) +{ + int ret = 0; + + if (dhd == NULL) return; + if (dhd->arp_version == 1) + idx = 0; + + ret = dhd_iovar(dhd, idx, "arp_table_clear", NULL, 0, NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); +} + +void +dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) +{ + int ret = 0; + + if (dhd == NULL) return; + if (dhd->arp_version == 1) + idx = 0; + + ret = dhd_iovar(dhd, idx, "arp_hostip_clear", NULL, 0, NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); +} + +void +dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) +{ + int ret; + + if (dhd == NULL) return; + if (dhd->arp_version == 1) + idx = 0; + + ret = dhd_iovar(dhd, idx, "arp_hostip", (char *)&ipaddr, sizeof(ipaddr), + NULL, 0, TRUE); + if (ret) + DHD_TRACE(("%s: ARP ip addr add failed, ret = %d\n", __FUNCTION__, ret)); + else + DHD_TRACE(("%s: sARP H ipaddr entry added \n", + __FUNCTION__)); +} + +int +dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) +{ + int ret, i; + uint32 *ptr32 = buf; + bool clr_bottom = FALSE; + + if (!buf) + return -1; + if (dhd == NULL) return -1; + if (dhd->arp_version == 1) + idx = 0; + + ret = dhd_iovar(dhd, idx, "arp_hostip", NULL, 0, (char *)buf, buflen, + FALSE); + if (ret) { + DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", + __FUNCTION__, ret)); + + return -1; + } + + /* clean up the buf, ascii reminder */ + for (i = 0; i < MAX_IPV4_ENTRIES; i++) { + if (!clr_bottom) { + if (*ptr32 == 0) + clr_bottom = TRUE; + } else { + *ptr32 = 0; + } + ptr32++; + } + + return 0; +} +#endif /* ARP_OFFLOAD_SUPPORT */ + +/* + * Neighbor Discovery Offload: enable NDO feature + * Called by ipv6 event handler when interface comes up/goes down + */ +int +dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable) +{ + int retcode; + + if (dhd == NULL) + return -1; + + retcode = dhd_iovar(dhd, 0, "ndoe", (char *)&ndo_enable, + sizeof(ndo_enable), NULL, 0, TRUE); + if (retcode) + DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n", + __FUNCTION__, ndo_enable, retcode)); + else + DHD_TRACE(("%s: successfully enabed ndo offload to %d\n", + __FUNCTION__, ndo_enable)); + + return retcode; +} + +/* + * Neighbor Discover Offload: enable NDO feature + * Called by ipv6 event handler when interface comes up + */ +int +dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx) +{ + int retcode; + + if (dhd == NULL) + return -1; + + retcode = dhd_iovar(dhd, idx, "nd_hostip", ipv6addr, + IPV6_ADDR_LEN, NULL, 0, TRUE); + + if (retcode) + DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n", + __FUNCTION__, retcode)); + else + DHD_TRACE(("%s: ndo ipaddr entry added \n", + __FUNCTION__)); + + return retcode; +} +/* + * Neighbor Discover Offload: enable NDO feature + * Called by ipv6 event handler when interface goes down + */ +int +dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx) +{ + int retcode; + + if (dhd == NULL) + return -1; + + retcode = dhd_iovar(dhd, idx, "nd_hostip_clear", NULL, 0, + NULL, 0, TRUE); + + if (retcode) + DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n", + __FUNCTION__, retcode)); + else + DHD_TRACE(("%s: ndo ipaddr entry removed \n", + __FUNCTION__)); + + return retcode; +} + +/* send up locally generated event */ +void +dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) +{ + switch (ntoh32(event->event_type)) { + default: + break; + } + + /* Call per-port handler. */ + dhd_sendup_event(dhdp, event, data); +} + + +/* + * returns = TRUE if associated, FALSE if not associated + */ +bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) +{ + char bssid[6], zbuf[6]; + int ret = -1; + + bzero(bssid, 6); + bzero(zbuf, 6); + + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0); + DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); + + if (ret == BCME_NOTASSOCIATED) { + DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); + } + + if (retval) + *retval = ret; + + if (ret < 0) + return FALSE; + + if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { + /* STA is assocoated BSSID is non zero */ + + if (bss_buf) { + /* return bss if caller provided buf */ + memcpy(bss_buf, bssid, ETHER_ADDR_LEN); + } + return TRUE; + } else { + DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); + return FALSE; + } +} + +/* Function to estimate possible DTIM_SKIP value */ +int +dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) +{ + int bcn_li_dtim = 1; /* deafult no dtim skip setting */ + int ret = -1; + int dtim_period = 0; + int ap_beacon = 0; + int allowed_skip_dtim_cnt = 0; + /* Check if associated */ + if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { + DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); + goto exit; + } + + /* read associated AP beacon interval */ + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, + &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) { + DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); + goto exit; + } + + /* read associated ap's dtim setup */ + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, + &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) { + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); + goto exit; + } + + /* if not assocated just eixt */ + if (dtim_period == 0) { + goto exit; + } + + /* attemp to use platform defined dtim skip interval */ + bcn_li_dtim = dhd->suspend_bcn_li_dtim; + + /* check if sta listen interval fits into AP dtim */ + if (dtim_period > CUSTOM_LISTEN_INTERVAL) { + /* AP DTIM to big for our Listen Interval : no dtim skiping */ + bcn_li_dtim = NO_DTIM_SKIP; + DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", + __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL)); + goto exit; + } + + if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { + allowed_skip_dtim_cnt = MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon); + bcn_li_dtim = (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; + } + + if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) { + /* Round up dtim_skip to fit into STAs Listen Interval */ + bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period); + DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); + } + + DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", + __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL)); + +exit: + return bcn_li_dtim; +} + +/* Check if the mode supports STA MODE */ +bool dhd_support_sta_mode(dhd_pub_t *dhd) +{ + +#ifdef WL_CFG80211 + if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) + return FALSE; + else +#endif /* WL_CFG80211 */ + return TRUE; +} + +#if defined(KEEP_ALIVE) +int dhd_keep_alive_onoff(dhd_pub_t *dhd) +{ + char buf[32] = {0}; + const char *str; + wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0}; + wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + int buf_len; + int str_len; + int res = -1; + + if (!dhd_support_sta_mode(dhd)) + return res; + + DHD_TRACE(("%s execution\n", __FUNCTION__)); + + str = "mkeep_alive"; + str_len = strlen(str); + strncpy(buf, str, sizeof(buf) - 1); + buf[ sizeof(buf) - 1 ] = '\0'; + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); + mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING; + buf_len = str_len + 1; + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + /* Setup keep alive zero for null packet generation */ + mkeep_alive_pkt.keep_alive_id = 0; + mkeep_alive_pkt.len_bytes = 0; + buf_len += WL_MKEEP_ALIVE_FIXED_LEN; + bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); + /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and + * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); + + res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); + + return res; +} +#endif /* defined(KEEP_ALIVE) */ +#define CSCAN_TLV_TYPE_SSID_IE 'S' +/* + * SSIDs list parsing from cscan tlv list + */ +int +wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left) +{ + char* str; + int idx = 0; + + if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + str = *list_str; + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { + *list_str = str; + DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + return idx; + } + + /* Get proper CSCAN_TLV_TYPE_SSID_IE */ + *bytes_left -= 1; + str += 1; + ssid[idx].rssi_thresh = 0; + if (str[0] == 0) { + /* Broadcast SSID */ + ssid[idx].SSID_len = 0; + memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); + *bytes_left -= 1; + str += 1; + + DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); + } + else if (str[0] <= DOT11_MAX_SSID_LEN) { + /* Get proper SSID size */ + ssid[idx].SSID_len = str[0]; + *bytes_left -= 1; + str += 1; + + /* Get SSID */ + if (ssid[idx].SSID_len > *bytes_left) { + DHD_ERROR(("%s out of memory range len=%d but left=%d\n", + __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); + return -1; + } + + memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); + + *bytes_left -= ssid[idx].SSID_len; + str += ssid[idx].SSID_len; + ssid[idx].hidden = TRUE; + + DHD_TRACE(("%s :size=%d left=%d\n", + (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); + } + else { + DHD_ERROR(("### SSID size more that %d\n", str[0])); + return -1; + } + + if (idx++ > max) { + DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); + return -1; + } + } + + *list_str = str; + return idx; +} +#if defined(WL_WIRELESS_EXT) +/* Android ComboSCAN support */ + +/* + * data parsing from ComboScan tlv list +*/ +int +wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, + int input_size, int *bytes_left) +{ + char* str; + uint16 short_temp; + uint32 int_temp; + + if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + str = *list_str; + + /* Clean all dest bytes */ + memset(dst, 0, dst_size); + while (*bytes_left > 0) { + + if (str[0] != token) { + DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", + __FUNCTION__, token, str[0], *bytes_left)); + return -1; + } + + *bytes_left -= 1; + str += 1; + + if (input_size == 1) { + memcpy(dst, str, input_size); + } + else if (input_size == 2) { + memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), + input_size); + } + else if (input_size == 4) { + memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), + input_size); + } + + *bytes_left -= input_size; + str += input_size; + *list_str = str; + return 1; + } + return 1; +} + +/* + * channel list parsing from cscan tlv list +*/ +int +wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, + int channel_num, int *bytes_left) +{ + char* str; + int idx = 0; + + if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + str = *list_str; + + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { + *list_str = str; + DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + return idx; + } + /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ + *bytes_left -= 1; + str += 1; + + if (str[0] == 0) { + /* All channels */ + channel_list[idx] = 0x0; + } + else { + channel_list[idx] = (uint16)str[0]; + DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); + } + *bytes_left -= 1; + str += 1; + + if (idx++ > 255) { + DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); + return -1; + } + } + + *list_str = str; + return idx; +} + +/* Parse a comma-separated list from list_str into ssid array, starting + * at index idx. Max specifies size of the ssid array. Parses ssids + * and returns updated idx; if idx >= max not all fit, the excess have + * not been copied. Returns -1 on empty string, or on ssid too long. + */ +int +wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) +{ + char* str, *ptr; + + if ((list_str == NULL) || (*list_str == NULL)) + return -1; + + for (str = *list_str; str != NULL; str = ptr) { + + /* check for next TAG */ + if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { + *list_str = str + strlen(GET_CHANNEL); + return idx; + } + + if ((ptr = strchr(str, ',')) != NULL) { + *ptr++ = '\0'; + } + + if (strlen(str) > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); + return -1; + } + + if (strlen(str) == 0) + ssid[idx].SSID_len = 0; + + if (idx < max) { + bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); + strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); + ssid[idx].SSID_len = strlen(str); + } + idx++; + } + return idx; +} + +/* + * Parse channel list from iwpriv CSCAN + */ +int +wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) +{ + int num; + int val; + char* str; + char* endptr = NULL; + + if ((list_str == NULL)||(*list_str == NULL)) + return -1; + + str = *list_str; + num = 0; + while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { + val = (int)strtoul(str, &endptr, 0); + if (endptr == str) { + printf("could not parse channel number starting at" + " substring \"%s\" in list:\n%s\n", + str, *list_str); + return -1; + } + str = endptr + strspn(endptr, " ,"); + + if (num == channel_num) { + DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", + channel_num, *list_str)); + return -1; + } + + channel_list[num++] = (uint16)val; + } + *list_str = str; + return num; +} + +#endif diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_gpio.c new file mode 100644 index 000000000000..fba369c89542 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_gpio.c @@ -0,0 +1,596 @@ +/* +* Customer code to add GPIO control during WLAN start/stop +* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 2013 Sony Mobile Communications Inc. +* +* Unless you and Broadcom execute a separate written software license +* agreement governing use of this software, this software is licensed to you +* under the terms of the GNU General Public License version 2 (the "GPL"), +* available at http://www.broadcom.com/licenses/GPLv2.php, with the +* following added to such license: +* +* As a special exception, the copyright holders of this software give you +* permission to link this software with independent modules, and to copy and +* distribute the resulting executable under terms of your choice, provided that +* you also meet, for each linked independent module, the terms and conditions of +* the license of that module. An independent module is a module which is not +* derived from this software. The special exception does not apply to any +* modifications of the software. +* +* Notwithstanding the above, under no circumstances may you combine this +* software in any way with any other Broadcom software provided under a license +* other than the GPL, without Broadcom's express prior written consent. +* +* $Id: dhd_custom_gpio.c 684939 2017-02-15 02:39:44Z $ +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#if defined(WL_WIRELESS_EXT) +#include +#endif + +#define WL_ERROR(x) printf x +#define WL_TRACE(x) + +#if defined(CUSTOMER_HW2) + + +#endif + +#ifdef GET_CUSTOM_MAC_ENABLE +#define MACADDR_BUF_LEN 64 +#define MACADDR_PATH "/data/etc/wlan_macaddr0" +#endif /* GET_CUSTOM_MAC_ENABLE */ + +#if defined(OOB_INTR_ONLY) + +#if defined(BCMLXSDMMC) +extern int sdioh_mmc_irq(int irq); +#endif /* (BCMLXSDMMC) */ + +#if defined(CUSTOMER_HW3) +#include +#endif + +/* Customer specific Host GPIO defintion */ +static int dhd_oob_gpio_num = -1; + +module_param(dhd_oob_gpio_num, int, 0644); +MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); + +/* This function will return: + * 1) return : Host gpio interrupt number per customer platform + * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge + * + * NOTE : + * Customer should check his platform definitions + * and his Host Interrupt spec + * to figure out the proper setting for his platform. + * Broadcom provides just reference settings as example. + * + */ +int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr) +{ + int host_oob_irq = 0; + +#if defined(CUSTOMER_HW2) + host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr); + +#else +#if defined(CUSTOM_OOB_GPIO_NUM) + if (dhd_oob_gpio_num < 0) { + dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; + } +#endif /* CUSTOMER_OOB_GPIO_NUM */ + + if (dhd_oob_gpio_num < 0) { + WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", + __FUNCTION__)); + return (dhd_oob_gpio_num); + } + + WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", + __FUNCTION__, dhd_oob_gpio_num)); + +#if defined CUSTOMER_HW3 + gpio_request(dhd_oob_gpio_num, "oob irq"); + host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); + gpio_direction_input(dhd_oob_gpio_num); +#endif +#endif + + return (host_oob_irq); +} +#endif + +/* Customer function to control hw specific wlan gpios */ +int +dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff) +{ + int err = 0; + + return err; +} + +#ifdef GET_CUSTOM_MAC_ENABLE +int somc_get_mac_address(unsigned char *buf) +{ + int ret = -EINVAL; + int len; + unsigned char macaddr_buf[MACADDR_BUF_LEN]; + void *fp = NULL; + struct ether_addr eth; + + if (!buf) + return -EINVAL; + + fp = dhd_os_open_image(MACADDR_PATH); + if (!fp) { + WL_ERROR(("%s: file open error\n", __FUNCTION__)); + goto err; + } + + len = dhd_os_get_image_block(macaddr_buf, MACADDR_BUF_LEN, fp); + if (len <= 0 || MACADDR_BUF_LEN <= len) { + WL_ERROR(("%s: file read error\n", __FUNCTION__)); + goto err; + } + macaddr_buf[len] = '\0'; + + /* convert mac address */ + ret = !bcm_ether_atoe(macaddr_buf, ð); + if (ret) { + WL_ERROR(("%s: convert mac value fail\n", __FUNCTION__)); + goto err; + } + + memcpy(buf, eth.octet, ETHER_ADDR_LEN); +err: + if (fp) + dhd_os_close_image(fp); + return ret; +} + +/* Function to get custom MAC address */ +int +dhd_custom_get_mac_address(void *adapter, unsigned char *buf) +{ + int ret = 0; + + WL_TRACE(("%s Enter\n", __FUNCTION__)); + if (!buf) + return -EINVAL; + + /* Customer access to MAC address stored outside of DHD driver */ +#if defined(CUSTOMER_HW2) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + ret = wifi_platform_get_mac_addr(adapter, buf); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) */ +#endif + +#ifdef EXAMPLE_GET_MAC + /* EXAMPLE code */ + { + struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; + bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); + } +#endif /* EXAMPLE_GET_MAC */ + + return ret; +} +#endif /* GET_CUSTOM_MAC_ENABLE */ + +struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ + char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ + int32 custom_locale_rev; /* Custom local revisin default -1 */ +}; +/* Customized Locale table : OPTIONAL feature */ +const struct cntry_locales_custom translate_custom_table[] = { +/* Table should be filled out based on custom platform regulatory requirement */ +#ifdef EXAMPLE_TABLE + {"", "XY", 4}, /* Universal if Country code is unknown or empty */ + {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ + {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ + {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ + {"AT", "EU", 5}, + {"BE", "EU", 5}, + {"BG", "EU", 5}, + {"CY", "EU", 5}, + {"CZ", "EU", 5}, + {"DK", "EU", 5}, + {"EE", "EU", 5}, + {"FI", "EU", 5}, + {"FR", "EU", 5}, + {"DE", "EU", 5}, + {"GR", "EU", 5}, + {"HU", "EU", 5}, + {"IE", "EU", 5}, + {"IT", "EU", 5}, + {"LV", "EU", 5}, + {"LI", "EU", 5}, + {"LT", "EU", 5}, + {"LU", "EU", 5}, + {"MT", "EU", 5}, + {"NL", "EU", 5}, + {"PL", "EU", 5}, + {"PT", "EU", 5}, + {"RO", "EU", 5}, + {"SK", "EU", 5}, + {"SI", "EU", 5}, + {"ES", "EU", 5}, + {"SE", "EU", 5}, + {"GB", "EU", 5}, + {"KR", "XY", 3}, + {"AU", "XY", 3}, + {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ + {"TW", "XY", 3}, + {"AR", "XY", 3}, + {"MX", "XY", 3}, + {"IL", "IL", 0}, + {"CH", "CH", 0}, + {"TR", "TR", 0}, + {"NO", "NO", 0}, +#endif /* EXMAPLE_TABLE */ +#if defined(CUSTOMER_HW2) && !defined(CUSTOMER_HW5) +#if defined(BCM4335_CHIP) + {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ +#endif + {"AE", "AE", 1}, + {"AR", "AR", 1}, + {"AT", "AT", 1}, + {"AU", "AU", 2}, + {"BE", "BE", 1}, + {"BG", "BG", 1}, + {"BN", "BN", 1}, + {"CA", "CA", 2}, + {"CH", "CH", 1}, + {"CY", "CY", 1}, + {"CZ", "CZ", 1}, + {"DE", "DE", 3}, + {"DK", "DK", 1}, + {"EE", "EE", 1}, + {"ES", "ES", 1}, + {"FI", "FI", 1}, + {"FR", "FR", 1}, + {"GB", "GB", 1}, + {"GR", "GR", 1}, + {"HR", "HR", 1}, + {"HU", "HU", 1}, + {"IE", "IE", 1}, + {"IS", "IS", 1}, + {"IT", "IT", 1}, + {"ID", "ID", 1}, + {"JP", "JP", 8}, + {"KR", "KR", 24}, + {"KW", "KW", 1}, + {"LI", "LI", 1}, + {"LT", "LT", 1}, + {"LU", "LU", 1}, + {"LV", "LV", 1}, + {"MA", "MA", 1}, + {"MT", "MT", 1}, + {"MX", "MX", 1}, + {"NL", "NL", 1}, + {"NO", "NO", 1}, + {"PL", "PL", 1}, + {"PT", "PT", 1}, + {"PY", "PY", 1}, + {"RO", "RO", 1}, + {"SE", "SE", 1}, + {"SI", "SI", 1}, + {"SK", "SK", 1}, + {"TR", "TR", 7}, + {"TW", "TW", 1}, + {"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ + {"SD", "XZ", 11}, /* Universal if Country code is SUDAN */ + {"SY", "XZ", 11}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ + {"GL", "XZ", 11}, /* Universal if Country code is GREENLAND */ + {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ + {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ + {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ +#ifdef BCM4330_CHIP + {"RU", "RU", 1}, + {"US", "US", 5} +#endif + +#elif defined(CUSTOMER_HW5) + /* default ccode/regrev */ + {"", "XT", 54}, /* Universal if Country code is unknown or empty */ + {"IR", "XT", 54}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ + {"SD", "XT", 54}, /* Universal if Country code is SUDAN */ + {"SY", "XT", 54}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ + {"GL", "E0", 979}, /* Universal if Country code is GREENLAND */ + {"PS", "XT", 54}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ + {"TL", "XT", 54}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ + {"MH", "XT", 54}, /* Universal if Country code is MARSHALL ISLANDS */ + {"CK", "XT", 54}, /* Universal if Country code is Cook Islands */ + {"CU", "XT", 54}, /* Universal if Country code is Cuba */ + {"FO", "XT", 54}, /* Universal if Country code is Faroe Islands */ + {"GI", "XT", 54}, /* Universal if Country code is Gibraltar */ + {"KP", "XT", 54}, /* Universal if Country code is North Korea */ + {"NE", "XT", 54}, /* Universal if Country code is Niger (Republic of the) */ + {"PM", "XT", 54}, /* Universal if Country code is Saint Pierre and Miquelon */ + {"WF", "XT", 54}, /* Universal if Country code is Wallis and Futuna */ + + {"XA", "XX", 4}, /* Default country code for INDONESIA */ + {"XC", "XT", 998}, /* Default country code for RUSSIA */ + + {"AD", "AD", 0}, + {"AE", "AE", 212}, + {"AF", "AF", 0}, + {"AG", "XT", 54}, + {"AI", "AI", 2}, + {"AL", "AL", 2}, + {"AM", "AM", 0}, + {"AN", "AN", 3}, + {"AO", "AO", 0}, + {"AR", "AR", 212}, + {"AS", "AS", 15}, + {"AT", "E0", 979}, + {"AU", "AU", 212}, + {"AW", "XT", 54}, + {"AZ", "XT", 54}, + {"BA", "BA", 2}, + {"BB", "BB", 0}, + {"BD", "XT", 54}, + {"BE", "E0", 979}, + {"BF", "XT", 54}, + {"BG", "E0", 979}, + {"BH", "BH", 4}, + {"BI", "BI", 0}, + {"BJ", "BJ", 0}, + {"BM", "BM", 15}, + {"BN", "BN", 4}, + {"BO", "XT", 54}, + {"BR", "BR", 212}, + {"BS", "XT", 54}, + {"BT", "XT", 54}, + {"BW", "BW", 1}, + {"BY", "XT", 54}, + {"BZ", "XT", 54}, + {"CA", "CA", 212}, + {"CD", "CD", 0}, + {"CF", "CF", 0}, + {"CG", "CG", 0}, + {"CH", "E0", 979}, + {"CI", "CI", 0}, + {"CL", "CL", 212}, + {"CM", "CM", 0}, + {"CN", "CN", 212}, + {"CO", "CO", 212}, + {"CR", "CR", 21}, + {"CV", "CV", 0}, + {"CX", "CX", 1}, + {"CY", "E0", 979}, + {"CZ", "E0", 979}, + {"DE", "E0", 979}, + {"DJ", "DJ", 0}, + {"DK", "E0", 979}, + {"DM", "XT", 54}, + {"DO", "XT", 54}, + {"DZ", "DZ", 1}, + {"EC", "EC", 23}, + {"EE", "E0", 979}, + {"EG", "EG", 212}, + {"ER", "ER", 0}, + {"ES", "E0", 979}, + {"ET", "ET", 2}, + {"FI", "E0", 979}, + {"FJ", "XT", 54}, + {"FK", "FK", 0}, + {"FM", "XT", 54}, + {"FR", "E0", 979}, + {"GA", "GA", 0}, + {"GB", "E0", 979}, + {"GD", "XT", 54}, + {"GE", "GE", 0}, + {"GF", "GF", 2}, + {"GH", "GH", 0}, + {"GM", "GM", 0}, + {"GN", "GN", 0}, + {"GP", "GP", 2}, + {"GQ", "GQ", 0}, + {"GR", "E0", 979}, + {"GT", "XT", 54}, + {"GU", "GU", 17}, + {"GW", "GW", 0}, + {"GY", "GY", 0}, + {"HK", "HK", 212}, + {"HN", "HN", 0}, + {"HR", "E0", 979}, + {"HT", "HT", 0}, + {"HU", "E0", 979}, + {"ID", "ID", 212}, + {"IE", "E0", 979}, + {"IL", "IL", 7}, + {"IN", "IN", 212}, + {"IQ", "IQ", 0}, + {"IS", "E0", 979}, + {"IT", "E0", 979}, + {"JM", "JM", 0}, + {"JO", "JO", 3}, + {"JP", "JP", 212}, + {"KE", "KE", 0}, + {"KG", "KG", 0}, + {"KH", "KH", 4}, + {"KI", "KI", 1}, + {"KM", "KM", 0}, + {"KN", "XT", 54}, + {"KR", "KR", 212}, + {"KW", "KW", 5}, + {"KY", "KY", 4}, + {"KZ", "KZ", 212}, + {"LA", "LA", 4}, + {"LB", "LB", 6}, + {"LC", "XT", 54}, + {"LI", "E0", 979}, + {"LK", "XT", 54}, + {"LR", "LR", 2}, + {"LS", "LS", 2}, + {"LT", "E0", 979}, + {"LU", "E0", 979}, + {"LV", "E0", 979}, + {"LY", "LY", 0}, + {"MA", "MA", 2}, + {"MC", "E0", 979}, + {"MD", "MD", 2}, + {"ME", "ME", 2}, + {"MF", "XT", 54}, + {"MG", "MG", 0}, + {"MK", "E0", 979}, + {"ML", "ML", 0}, + {"MM", "MM", 0}, + {"MN", "XT", 54}, + {"MO", "MO", 2}, + {"MP", "XT", 54}, + {"MQ", "MQ", 2}, + {"MR", "MR", 2}, + {"MS", "MS", 0}, + {"MT", "E0", 979}, + {"MU", "MU", 2}, + {"MV", "MV", 3}, + {"MW", "XT", 54}, + {"MX", "MX", 212}, + {"MY", "MY", 998}, + {"MZ", "XT", 54}, + {"NA", "XT", 54}, + {"NC", "NC", 0}, + {"NG", "NG", 0}, + {"NI", "NI", 0}, + {"NL", "E0", 979}, + {"NO", "E0", 979}, + {"NP", "NP", 3}, + {"NR", "NR", 0}, + {"NZ", "NZ", 9}, + {"OM", "OM", 4}, + {"PA", "PA", 17}, + {"PE", "PE", 212}, + {"PF", "PF", 0}, + {"PG", "PG", 2}, + {"PH", "PH", 212}, + {"PK", "PK", 0}, + {"PL", "E0", 979}, + {"PR", "PR", 25}, + {"PT", "E0", 979}, + {"PW", "XT", 54}, + {"PY", "PY", 4}, + {"QA", "QA", 0}, + {"RE", "RE", 2}, + {"RO", "E0", 979}, + {"RS", "RS", 2}, + {"RU", "RU", 212}, + {"RW", "XT", 54}, + {"SA", "SA", 212}, + {"SB", "SB", 0}, + {"SC", "XT", 54}, + {"SE", "E0", 979}, + {"SG", "SG", 212}, + {"SI", "E0", 979}, + {"SK", "E0", 979}, + {"SL", "SL", 0}, + {"SM", "SM", 0}, + {"SN", "SN", 2}, + {"SO", "SO", 0}, + {"SR", "SR", 0}, + {"ST", "ST", 0}, + {"SV", "XT", 54}, + {"SZ", "SZ", 0}, + {"TC", "TC", 0}, + {"TD", "TD", 0}, + {"TF", "TF", 0}, + {"TG", "TG", 0}, + {"TH", "TH", 212}, + {"TJ", "TJ", 0}, + {"TM", "TM", 0}, + {"TN", "TN", 0}, + {"TO", "TO", 0}, + {"TR", "E0", 979}, + {"TT", "TT", 5}, + {"TV", "TV", 0}, + {"TW", "TW", 996}, + {"TZ", "XT", 54}, + {"UA", "UA", 212}, + {"UG", "XT", 54}, + {"US", "US", 996}, + {"UY", "UY", 5}, + {"UZ", "XT", 54}, + {"VA", "VA", 2}, + {"VC", "XT", 54}, + {"VE", "VE", 3}, + {"VG", "XT", 54}, + {"VI", "VI", 18}, + {"VN", "XT", 54}, + {"VU", "XT", 54}, + {"WS", "XT", 54}, + {"YE", "XT", 54}, + {"YT", "YT", 2}, + {"ZA", "ZA", 212}, + {"ZM", "ZM", 2}, + {"ZW", "XT", 54}, +#endif /* CUSTOMER_HW2 and CUSTOMER_HW5 */ +}; + + +/* Customized Locale convertor +* input : ISO 3166-1 country abbreviation +* output: customized cspec +*/ +#ifdef CUSTOM_FORCE_NODFS_FLAG +void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec, u32 flags) +#else +void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec) +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +{ +#if 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))) + + struct cntry_locales_custom *cloc_ptr; + + if (!cspec) + return; + +#ifdef CUSTOM_FORCE_NODFS_FLAG + cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code, + flags); +#else + cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + if (cloc_ptr) { + strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = cloc_ptr->custom_locale_rev; + } + return; +#else + int size, i; + + size = ARRAYSIZE(translate_custom_table); + + if (cspec == 0) + return; + + if (size == 0) + return; + + for (i = 0; i < size; i++) { + if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { + memcpy(cspec->ccode, + translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = translate_custom_table[i].custom_locale_rev; + return; + } + } + /* if no country code matched return first universal code from translate_custom_table */ + memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = translate_custom_table[0].custom_locale_rev; + return; +#endif /* 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))) */ +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_memprealloc.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_memprealloc.c new file mode 100644 index 000000000000..e164beec85aa --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_memprealloc.c @@ -0,0 +1,361 @@ +/* + * Platform Dependent file for usage of Preallocted Memory + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_custom_memprealloc.c 536912 2015-02-24 16:09:31Z $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + +#define WLAN_STATIC_SCAN_BUF0 5 +#define WLAN_STATIC_SCAN_BUF1 6 +#define WLAN_STATIC_DHD_INFO_BUF 7 +#define WLAN_STATIC_DHD_WLFC_BUF 8 +#define WLAN_STATIC_DHD_IF_FLOW_LKUP 9 +#define WLAN_STATIC_DHD_MEMDUMP_RAM 11 +#define WLAN_STATIC_DHD_PKTID_MAP 12 + +#define WLAN_SCAN_BUF_SIZE (64 * 1024) + +#if defined(CONFIG_64BIT) +#define WLAN_DHD_INFO_BUF_SIZE (24 * 1024) +#define WLAN_DHD_WLFC_BUF_SIZE (64 * 1024) +#define WLAN_DHD_IF_FLOW_LKUP_SIZE (64 * 1024) +#else +#define WLAN_DHD_INFO_BUF_SIZE (16 * 1024) +#define WLAN_DHD_WLFC_BUF_SIZE (16 * 1024) +#define WLAN_DHD_IF_FLOW_LKUP_SIZE (20 * 1024) +#endif /* CONFIG_64BIT */ +#define WLAN_DHD_MEMDUMP_SIZE (800 * 1024) + +#define PREALLOC_WLAN_SEC_NUM 4 +#define PREALLOC_WLAN_BUF_NUM 160 +#define PREALLOC_WLAN_SECTION_HEADER 24 + +#ifdef CONFIG_BCMDHD_PCIE +#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1) +#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2) +#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4) + +#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_1 0 +#define WLAN_SECTION_SIZE_2 0 +#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) + +#define DHD_SKB_1PAGE_BUF_NUM 0 +#define DHD_SKB_2PAGE_BUF_NUM 64 +#define DHD_SKB_4PAGE_BUF_NUM 0 + +#else +#define DHD_SKB_HDRSIZE 336 +#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) +#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) +#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) + +#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512) +#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) + +#define DHD_SKB_1PAGE_BUF_NUM 8 +#define DHD_SKB_2PAGE_BUF_NUM 8 +#define DHD_SKB_4PAGE_BUF_NUM 1 +#endif /* CONFIG_BCMDHD_PCIE */ + +#define WLAN_SKB_1_2PAGE_BUF_NUM ((DHD_SKB_1PAGE_BUF_NUM) + \ + (DHD_SKB_2PAGE_BUF_NUM)) +#define WLAN_SKB_BUF_NUM ((WLAN_SKB_1_2PAGE_BUF_NUM) + \ + (DHD_SKB_4PAGE_BUF_NUM)) + +#define DHD_PKTIDMAP_FIFO_MAX 4 +#define WLAN_MAX_PKTID_ITEMS (8192) +#if defined(CONFIG_64BIT) +#define WLAN_DHD_PKTID_MAP_HDR_SIZE (64) +#define WLAN_DHD_PKTID_MAP_ITEM_SIZE (48) +#else +#define WLAN_DHD_PKTID_MAP_HDR_SIZE (36) +#define WLAN_DHD_PKTID_MAP_ITEM_SIZE (28) +#endif /* CONFIG_64BIT */ +#define WLAN_DHD_PKTID_MAP_SIZE ((WLAN_DHD_PKTID_MAP_HDR_SIZE) + \ + (DHD_PKTIDMAP_FIFO_MAX * (WLAN_MAX_PKTID_ITEMS+1) * WLAN_DHD_PKTID_MAP_ITEM_SIZE)) + + +static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM]; + +struct wlan_mem_prealloc { + void *mem_ptr; + unsigned long size; +}; + +static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = { + {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)} +}; + +void *wlan_static_scan_buf0 = NULL; +void *wlan_static_scan_buf1 = NULL; +void *wlan_static_dhd_info_buf = NULL; +void *wlan_static_dhd_wlfc_buf = NULL; +void *wlan_static_if_flow_lkup = NULL; +void *wlan_static_dhd_memdump_ram = NULL; +void *wlan_static_dhd_pktid_map = NULL; + +static void +*dhd_wlan_mem_prealloc(int section, unsigned long size) +{ + if (section == PREALLOC_WLAN_SEC_NUM) { + return wlan_static_skb; + } + + if (section == WLAN_STATIC_SCAN_BUF0) { + return wlan_static_scan_buf0; + } + + if (section == WLAN_STATIC_SCAN_BUF1) { + return wlan_static_scan_buf1; + } + + if (section == WLAN_STATIC_DHD_INFO_BUF) { + if (size > WLAN_DHD_INFO_BUF_SIZE) { + pr_err("request DHD_INFO size(%lu) is bigger than" + " static size(%d).\n", size, + WLAN_DHD_INFO_BUF_SIZE); + return NULL; + } + return wlan_static_dhd_info_buf; + } + + if (section == WLAN_STATIC_DHD_WLFC_BUF) { + if (size > WLAN_DHD_WLFC_BUF_SIZE) { + pr_err("request DHD_WLFC size(%lu) is bigger than" + " static size(%d).\n", + size, WLAN_DHD_WLFC_BUF_SIZE); + return NULL; + } + return wlan_static_dhd_wlfc_buf; + } + + if (section == WLAN_STATIC_DHD_IF_FLOW_LKUP) { + if (size > WLAN_DHD_IF_FLOW_LKUP_SIZE) { + pr_err("request DHD_WLFC size(%lu) is bigger than" + " static size(%d).\n", + size, WLAN_DHD_WLFC_BUF_SIZE); + return NULL; + } + return wlan_static_if_flow_lkup; + } + + if (section == WLAN_STATIC_DHD_MEMDUMP_RAM) { + if (size > WLAN_DHD_MEMDUMP_SIZE) { + pr_err("request DHD_MEMDUMP_RAM size(%lu) is bigger" + " than static size(%d).\n", + size, WLAN_DHD_MEMDUMP_SIZE); + return NULL; + } + return wlan_static_dhd_memdump_ram; + } + + if (section == WLAN_STATIC_DHD_PKTID_MAP) { + if (size > WLAN_DHD_PKTID_MAP_SIZE) { + pr_err("request DHD_PKTID_MAP size(%lu) is bigger than" + " static size(%d).\n", + size, WLAN_DHD_PKTID_MAP_SIZE); + return NULL; + } + return wlan_static_dhd_pktid_map; + } + + if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM)) { + return NULL; + } + + if (wlan_mem_array[section].size < size) { + return NULL; + } + + return wlan_mem_array[section].mem_ptr; +} +EXPORT_SYMBOL(dhd_wlan_mem_prealloc); + +static int +dhd_init_wlan_mem(void) +{ + int i; + int j; + + for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) { + wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE); + if (!wlan_static_skb[i]) { + goto err_skb_alloc; + } + } + + for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) { + wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE); + if (!wlan_static_skb[i]) { + goto err_skb_alloc; + } + } + +#if !defined(CONFIG_BCMDHD_PCIE) + wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE); + if (!wlan_static_skb[i]) { + goto err_skb_alloc; + } +#endif /* !CONFIG_BCMDHD_PCIE */ + + for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) { + if (wlan_mem_array[i].size > 0) { + wlan_mem_array[i].mem_ptr = + kmalloc(wlan_mem_array[i].size, GFP_KERNEL); + + if (!wlan_mem_array[i].mem_ptr) { + goto err_mem_alloc; + } + } + } + + wlan_static_scan_buf0 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); + if (!wlan_static_scan_buf0) { + pr_err("Failed to alloc wlan_static_scan_buf0\n"); + goto err_mem_alloc; + } + + wlan_static_scan_buf1 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); + if (!wlan_static_scan_buf1) { + pr_err("Failed to alloc wlan_static_scan_buf1\n"); + goto err_mem_alloc; + } + + wlan_static_dhd_info_buf = kmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL); + if (!wlan_static_dhd_info_buf) { + pr_err("Failed to alloc wlan_static_dhd_info_buf\n"); + goto err_mem_alloc; + } + +#ifdef CONFIG_BCMDHD_PCIE + wlan_static_if_flow_lkup = kmalloc(WLAN_DHD_IF_FLOW_LKUP_SIZE, + GFP_KERNEL); + if (!wlan_static_if_flow_lkup) { + pr_err("Failed to alloc wlan_static_if_flow_lkup\n"); + goto err_mem_alloc; + } + +#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP + wlan_static_dhd_pktid_map = kmalloc(WLAN_DHD_PKTID_MAP_SIZE, + GFP_KERNEL); + if (!wlan_static_dhd_pktid_map) { + pr_err("Failed to alloc wlan_static_dhd_pktid_map\n"); + goto err_mem_alloc; + } + +#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */ +#else + wlan_static_dhd_wlfc_buf = kmalloc(WLAN_DHD_WLFC_BUF_SIZE, + GFP_KERNEL); + if (!wlan_static_dhd_wlfc_buf) { + pr_err("Failed to alloc wlan_static_dhd_wlfc_buf\n"); + goto err_mem_alloc; + } +#endif /* CONFIG_BCMDHD_PCIE */ + +#ifdef CONFIG_BCMDHD_DEBUG_PAGEALLOC + wlan_static_dhd_memdump_ram = kmalloc(WLAN_DHD_MEMDUMP_SIZE, GFP_KERNEL); + if (!wlan_static_dhd_memdump_ram) { + pr_err("Failed to alloc wlan_static_dhd_memdump_ram\n"); + goto err_mem_alloc; + } +#endif /* CONFIG_BCMDHD_DEBUG_PAGEALLOC */ + + pr_err("%s: WIFI MEM Allocated\n", __FUNCTION__); + return 0; + +err_mem_alloc: +#ifdef CONFIG_BCMDHD_DEBUG_PAGEALLOC + if (wlan_static_dhd_memdump_ram) { + kfree(wlan_static_dhd_memdump_ram); + } + +#endif /* CONFIG_BCMDHD_DEBUG_PAGEALLOC */ + +#ifdef CONFIG_BCMDHD_PCIE + if (wlan_static_if_flow_lkup) { + kfree(wlan_static_if_flow_lkup); + } + +#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP + if (wlan_static_dhd_pktid_map) { + kfree(wlan_static_dhd_pktid_map); + } + +#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */ +#else + if (wlan_static_dhd_wlfc_buf) { + kfree(wlan_static_dhd_wlfc_buf); + } +#endif /* CONFIG_BCMDHD_PCIE */ + if (wlan_static_dhd_info_buf) { + kfree(wlan_static_dhd_info_buf); + } + + if (wlan_static_scan_buf1) { + kfree(wlan_static_scan_buf1); + } + + if (wlan_static_scan_buf0) { + kfree(wlan_static_scan_buf0); + } + + pr_err("Failed to mem_alloc for WLAN\n"); + + for (j = 0; j < i; j++) { + kfree(wlan_mem_array[j].mem_ptr); + } + + i = WLAN_SKB_BUF_NUM; + +err_skb_alloc: + pr_err("Failed to skb_alloc for WLAN\n"); + for (j = 0; j < i; j++) { + dev_kfree_skb(wlan_static_skb[j]); + } + + return -ENOMEM; +} +EXPORT_SYMBOL(dhd_init_wlan_mem); +#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_dbg.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_dbg.h new file mode 100644 index 000000000000..1784e44df708 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_dbg.h @@ -0,0 +1,128 @@ +/* + * Debug/trace/assert driver definitions for Dongle Host Driver. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_dbg.h 518127 2014-11-28 08:44:47Z $ + */ + +#ifndef _dhd_dbg_ +#define _dhd_dbg_ + +#define USE_NET_RATELIMIT 1 + +#if defined(DHD_DEBUG) + +#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && USE_NET_RATELIMIT) \ + printf args;} while (0) +#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) +#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) +#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) +#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0) +#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0) +#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0) +#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0) +#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0) +#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) +#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) +#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0) +#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) +#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) +#define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) +#define DHD_PNO(args) do {if (dhd_msg_level & DHD_PNO_VAL) printf args;} while (0) +#define DHD_RTT(args) do {if (dhd_msg_level & DHD_RTT_VAL) printf args;} while (0) + +#define DHD_TRACE_HW4 DHD_TRACE +#define DHD_INFO_HW4 DHD_INFO + +#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) +#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) +#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) +#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL) +#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL) +#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL) +#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL) +#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL) +#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL) +#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) +#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) +#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) +#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) +#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL) +#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL) +#define DHD_NOCHECKDIED_ON() (dhd_msg_level & DHD_NOCHECKDIED_VAL) +#define DHD_PNO_ON() (dhd_msg_level & DHD_PNO_VAL) +#define DHD_RTT_ON() (dhd_msg_level & DHD_RTT_VAL) + +#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ + +#define DHD_ERROR(args) do {if (USE_NET_RATELIMIT) printf args;} while (0) +#define DHD_TRACE(args) +#define DHD_INFO(args) +#define DHD_DATA(args) +#define DHD_CTL(args) +#define DHD_TIMER(args) +#define DHD_HDRS(args) +#define DHD_BYTES(args) +#define DHD_INTR(args) +#define DHD_GLOM(args) +#define DHD_EVENT(args) +#define DHD_BTA(args) +#define DHD_ISCAN(args) +#define DHD_ARPOE(args) +#define DHD_REORDER(args) +#define DHD_PNO(args) + +#define DHD_TRACE_HW4 DHD_TRACE +#define DHD_INFO_HW4 DHD_INFO + +#define DHD_ERROR_ON() 0 +#define DHD_TRACE_ON() 0 +#define DHD_INFO_ON() 0 +#define DHD_DATA_ON() 0 +#define DHD_CTL_ON() 0 +#define DHD_TIMER_ON() 0 +#define DHD_HDRS_ON() 0 +#define DHD_BYTES_ON() 0 +#define DHD_INTR_ON() 0 +#define DHD_GLOM_ON() 0 +#define DHD_EVENT_ON() 0 +#define DHD_BTA_ON() 0 +#define DHD_ISCAN_ON() 0 +#define DHD_ARPOE_ON() 0 +#define DHD_REORDER_ON() 0 +#define DHD_NOCHECKDIED_ON() 0 +#define DHD_PNO_ON() 0 +#define DHD_RTT_ON() 0 + +#endif + +#define DHD_LOG(args) + +#define DHD_BLOG(cp, size) + +#define DHD_NONE(args) +extern int dhd_msg_level; + +/* Defines msg bits */ +#include + +#endif /* _dhd_dbg_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.c new file mode 100644 index 000000000000..89ebb2b9a9dd --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.c @@ -0,0 +1,831 @@ +/* + * Broadcom Dongle Host Driver (DHD), Flow ring specific code at top level + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_flowrings.c jaganlv $ + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static INLINE uint16 dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, + uint8 prio, char *sa, char *da); + +static INLINE int dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, + uint8 prio, char *sa, char *da, uint16 *flowid); +int BCMFASTPATH dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt); + +#define FLOW_QUEUE_PKT_NEXT(p) PKTLINK(p) +#define FLOW_QUEUE_PKT_SETNEXT(p, x) PKTSETLINK((p), (x)) + +const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 }; +const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + +int BCMFASTPATH +dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt) +{ + return BCME_NORESOURCE; +} + +/* Flow ring's queue management functions */ + +void /* Initialize a flow ring's queue */ +dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max) +{ + ASSERT((queue != NULL) && (max > 0)); + + dll_init(&queue->list); + queue->head = queue->tail = NULL; + queue->len = 0; + queue->max = max - 1; + queue->failures = 0U; + queue->cb = &dhd_flow_queue_overflow; +} + +void /* Register an enqueue overflow callback handler */ +dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb) +{ + ASSERT(queue != NULL); + queue->cb = cb; +} + + +int BCMFASTPATH /* Enqueue a packet in a flow ring's queue */ +dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt) +{ + int ret = BCME_OK; + + ASSERT(queue != NULL); + + if (queue->len >= queue->max) { + queue->failures++; + ret = (*queue->cb)(queue, pkt); + goto done; + } + + if (queue->head) { + FLOW_QUEUE_PKT_SETNEXT(queue->tail, pkt); + } else { + queue->head = pkt; + } + + FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); + + queue->tail = pkt; /* at tail */ + + queue->len++; + +done: + return ret; +} + +void * BCMFASTPATH /* Dequeue a packet from a flow ring's queue, from head */ +dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue) +{ + void * pkt; + + ASSERT(queue != NULL); + + pkt = queue->head; /* from head */ + + if (pkt == NULL) { + ASSERT((queue->len == 0) && (queue->tail == NULL)); + goto done; + } + + queue->head = FLOW_QUEUE_PKT_NEXT(pkt); + if (queue->head == NULL) + queue->tail = NULL; + + queue->len--; + + FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); /* dettach packet from queue */ + +done: + return pkt; +} + +void BCMFASTPATH /* Reinsert a dequeued packet back at the head */ +dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt) +{ + if (queue->head == NULL) { + queue->tail = pkt; + } + + FLOW_QUEUE_PKT_SETNEXT(pkt, queue->head); + queue->head = pkt; + queue->len++; +} + + +/* Init Flow Ring specific data structures */ +int +dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings) +{ + uint32 idx; + uint32 flow_ring_table_sz; + uint32 if_flow_lkup_sz; + void * flowid_allocator; + flow_ring_table_t *flow_ring_table; + if_flow_lkup_t *if_flow_lkup = NULL; +#ifdef PCIE_TX_DEFERRAL + uint32 count; +#endif + void *lock = NULL; + unsigned long flags; + + DHD_INFO(("%s\n", __FUNCTION__)); + + /* Construct a 16bit flow1d allocator */ + flowid_allocator = id16_map_init(dhdp->osh, + num_flow_rings - FLOW_RING_COMMON, FLOWID_RESERVED); + if (flowid_allocator == NULL) { + DHD_ERROR(("%s: flowid allocator init failure\n", __FUNCTION__)); + return BCME_NOMEM; + } + + /* Allocate a flow ring table, comprising of requested number of rings */ + flow_ring_table_sz = (num_flow_rings * sizeof(flow_ring_node_t)); + flow_ring_table = (flow_ring_table_t *)MALLOCZ(dhdp->osh, flow_ring_table_sz); + if (flow_ring_table == NULL) { + DHD_ERROR(("%s: flow ring table alloc failure\n", __FUNCTION__)); + goto fail; + } + + /* Initialize flow ring table state */ + for (idx = 0; idx < num_flow_rings; idx++) { + flow_ring_table[idx].status = FLOW_RING_STATUS_CLOSED; + flow_ring_table[idx].flowid = (uint16)idx; + flow_ring_table[idx].lock = dhd_os_spin_lock_init(dhdp->osh); + if (flow_ring_table[idx].lock == NULL) { + DHD_ERROR(("%s: Failed to init spinlock for queue!\n", __FUNCTION__)); + goto fail; + } + + dll_init(&flow_ring_table[idx].list); + + /* Initialize the per flow ring backup queue */ + dhd_flow_queue_init(dhdp, &flow_ring_table[idx].queue, + FLOW_RING_QUEUE_THRESHOLD); + } + + /* Allocate per interface hash table */ + if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS; + if_flow_lkup = (if_flow_lkup_t *)DHD_OS_PREALLOC(dhdp, + DHD_PREALLOC_IF_FLOW_LKUP, if_flow_lkup_sz); + if (if_flow_lkup == NULL) { + DHD_ERROR(("%s: if flow lkup alloc failure\n", __FUNCTION__)); + goto fail; + } + + /* Initialize per interface hash table */ + bzero((uchar *)if_flow_lkup, if_flow_lkup_sz); + for (idx = 0; idx < DHD_MAX_IFS; idx++) { + int hash_ix; + if_flow_lkup[idx].status = 0; + if_flow_lkup[idx].role = 0; + for (hash_ix = 0; hash_ix < DHD_FLOWRING_HASH_SIZE; hash_ix++) + if_flow_lkup[idx].fl_hash[hash_ix] = NULL; + } + +#ifdef PCIE_TX_DEFERRAL + count = BITS_TO_LONGS(num_flow_rings); + dhdp->bus->delete_flow_map = kzalloc(count, GFP_ATOMIC); + if (!dhdp->bus->delete_flow_map) { + DHD_ERROR(("%s: delete_flow_map alloc failure\n", __FUNCTION__)); + goto fail; + } +#endif + + lock = dhd_os_spin_lock_init(dhdp->osh); + if (lock == NULL) + goto fail; + + dhdp->flow_prio_map_type = DHD_FLOW_PRIO_AC_MAP; + bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); + + /* Now populate into dhd pub */ + DHD_FLOWID_LOCK(lock, flags); + dhdp->num_flow_rings = num_flow_rings; + dhdp->flowid_allocator = (void *)flowid_allocator; + dhdp->flow_ring_table = (void *)flow_ring_table; + dhdp->if_flow_lkup = (void *)if_flow_lkup; + dhdp->flowid_lock = lock; + DHD_FLOWID_UNLOCK(lock, flags); + + DHD_INFO(("%s done\n", __FUNCTION__)); + return BCME_OK; + +fail: + +#ifdef PCIE_TX_DEFERRAL + if (dhdp->bus->delete_flow_map) + kfree(dhdp->bus->delete_flow_map); +#endif + /* Destruct the per interface flow lkup table */ + if (dhdp->if_flow_lkup != NULL) { + DHD_OS_PREFREE(dhdp, if_flow_lkup, if_flow_lkup_sz); + } + if (flow_ring_table != NULL) { + for (idx = 0; idx < num_flow_rings; idx++) { + if (flow_ring_table[idx].lock != NULL) + dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock); + } + MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz); + } + id16_map_fini(dhdp->osh, flowid_allocator); + + return BCME_NOMEM; +} + +/* Deinit Flow Ring specific data structures */ +void dhd_flow_rings_deinit(dhd_pub_t *dhdp) +{ + uint16 idx; + uint32 flow_ring_table_sz; + uint32 if_flow_lkup_sz; + flow_ring_table_t *flow_ring_table; + unsigned long flags; + void *lock; + + DHD_INFO(("dhd_flow_rings_deinit\n")); + + if (dhdp->flow_ring_table != NULL) { + + ASSERT(dhdp->num_flow_rings > 0); + + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; + dhdp->flow_ring_table = NULL; + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + for (idx = 0; idx < dhdp->num_flow_rings; idx++) { + if (flow_ring_table[idx].active) { + dhd_bus_clean_flow_ring(dhdp->bus, &flow_ring_table[idx]); + } + ASSERT(flow_queue_empty(&flow_ring_table[idx].queue)); + + /* Deinit flow ring queue locks before destroying flow ring table */ + if (flow_ring_table[idx].lock != NULL) { + dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock); + } + flow_ring_table[idx].lock = NULL; + } + + /* Destruct the flow ring table */ + flow_ring_table_sz = dhdp->num_flow_rings * sizeof(flow_ring_table_t); + MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz); + } + + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + + /* Destruct the per interface flow lkup table */ + if (dhdp->if_flow_lkup != NULL) { + if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS; + bzero(dhdp->if_flow_lkup, sizeof(if_flow_lkup_sz)); + DHD_OS_PREFREE(dhdp, dhdp->if_flow_lkup, if_flow_lkup_sz); + dhdp->if_flow_lkup = NULL; + } + +#ifdef PCIE_TX_DEFERRAL + if (dhdp->bus->delete_flow_map) + kfree(dhdp->bus->delete_flow_map); +#endif + + /* Destruct the flowid allocator */ + if (dhdp->flowid_allocator != NULL) + dhdp->flowid_allocator = id16_map_fini(dhdp->osh, dhdp->flowid_allocator); + + dhdp->num_flow_rings = 0U; + lock = dhdp->flowid_lock; + dhdp->flowid_lock = NULL; + + if (lock) { + DHD_FLOWID_UNLOCK(lock, flags); + dhd_os_spin_lock_deinit(dhdp->osh, lock); + } +} + +uint8 +dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex) +{ + if_flow_lkup_t *if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; + ASSERT(if_flow_lkup); + return if_flow_lkup[ifindex].role; +} + +#ifdef WLTDLS +bool is_tdls_destination(dhd_pub_t *dhdp, uint8 *da) +{ + tdls_peer_node_t *cur = dhdp->peer_tbl.node; + while (cur != NULL) { + if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { + return TRUE; + } + cur = cur->next; + } + return FALSE; +} +#endif /* WLTDLS */ + +/* For a given interface, search the hash table for a matching flow */ +uint16 +dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) +{ + int hash; + bool ismcast = FALSE; + flow_hash_info_t *cur; + if_flow_lkup_t *if_flow_lkup; + unsigned long flags; + + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; + + if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) { +#ifdef WLTDLS + if (dhdp->peer_tbl.tdls_peer_count && !(ETHER_ISMULTI(da)) && + is_tdls_destination(dhdp, da)) { + hash = DHD_FLOWRING_HASHINDEX(da, prio); + cur = if_flow_lkup[ifindex].fl_hash[hash]; + while (cur != NULL) { + if (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN)) { + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + return cur->flowid; + } + cur = cur->next; + } + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + return FLOWID_INVALID; + } +#endif /* WLTDLS */ + cur = if_flow_lkup[ifindex].fl_hash[prio]; + if (cur) { + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + return cur->flowid; + } + + } else { + + if (ETHER_ISMULTI(da)) { + ismcast = TRUE; + hash = 0; + } else { + hash = DHD_FLOWRING_HASHINDEX(da, prio); + } + + cur = if_flow_lkup[ifindex].fl_hash[hash]; + + while (cur) { + if ((ismcast && ETHER_ISMULTI(cur->flow_info.da)) || + (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN) && + (cur->flow_info.tid == prio))) { + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + return cur->flowid; + } + cur = cur->next; + } + } + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + + return FLOWID_INVALID; +} + +/* Allocate Flow ID */ +static INLINE uint16 +dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) +{ + flow_hash_info_t *fl_hash_node, *cur; + if_flow_lkup_t *if_flow_lkup; + int hash; + uint16 flowid; + unsigned long flags; + + fl_hash_node = (flow_hash_info_t *) MALLOC(dhdp->osh, sizeof(flow_hash_info_t)); + memcpy(fl_hash_node->flow_info.da, da, sizeof(fl_hash_node->flow_info.da)); + + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + ASSERT(dhdp->flowid_allocator != NULL); + flowid = id16_map_alloc(dhdp->flowid_allocator); + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + + if (flowid == FLOWID_INVALID) { + MFREE(dhdp->osh, fl_hash_node, sizeof(flow_hash_info_t)); + DHD_ERROR(("%s: cannot get free flowid \n", __FUNCTION__)); + return FLOWID_INVALID; + } + + fl_hash_node->flowid = flowid; + fl_hash_node->flow_info.tid = prio; + fl_hash_node->flow_info.ifindex = ifindex; + fl_hash_node->next = NULL; + + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; + if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) { + /* For STA non TDLS dest we allocate entry based on prio only */ +#ifdef WLTDLS + if (dhdp->peer_tbl.tdls_peer_count && + (is_tdls_destination(dhdp, da))) { + hash = DHD_FLOWRING_HASHINDEX(da, prio); + cur = if_flow_lkup[ifindex].fl_hash[hash]; + if (cur) { + while (cur->next) { + cur = cur->next; + } + cur->next = fl_hash_node; + } else { + if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; + } + } else +#endif /* WLTDLS */ + if_flow_lkup[ifindex].fl_hash[prio] = fl_hash_node; + } else { + + /* For bcast/mcast assign first slot in in interface */ + hash = ETHER_ISMULTI(da) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio); + cur = if_flow_lkup[ifindex].fl_hash[hash]; + if (cur) { + while (cur->next) { + cur = cur->next; + } + cur->next = fl_hash_node; + } else + if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; + } + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + + DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid)); + + return fl_hash_node->flowid; +} + +/* Get flow ring ID, if not present try to create one */ +static INLINE int +dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, + uint8 prio, char *sa, char *da, uint16 *flowid) +{ + uint16 id; + flow_ring_node_t *flow_ring_node; + flow_ring_table_t *flow_ring_table; + unsigned long flags; + + DHD_INFO(("%s\n", __FUNCTION__)); + + if (!dhdp->flow_ring_table) + return BCME_ERROR; + + flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; + + id = dhd_flowid_find(dhdp, ifindex, prio, sa, da); + + if (id == FLOWID_INVALID) { + + if_flow_lkup_t *if_flow_lkup; + if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; + + if (!if_flow_lkup[ifindex].status) + return BCME_ERROR; + + id = dhd_flowid_alloc(dhdp, ifindex, prio, sa, da); + if (id == FLOWID_INVALID) { + DHD_ERROR(("%s: alloc flowid ifindex %u status %u\n", + __FUNCTION__, ifindex, if_flow_lkup[ifindex].status)); + return BCME_ERROR; + } + + /* register this flowid in dhd_pub */ + dhd_add_flowid(dhdp, ifindex, prio, da, id); + } + + ASSERT(id < dhdp->num_flow_rings); + + flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id]; + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + if (flow_ring_node->active) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + *flowid = id; + return BCME_OK; + } + /* Init Flow info */ + memcpy(flow_ring_node->flow_info.sa, sa, sizeof(flow_ring_node->flow_info.sa)); + memcpy(flow_ring_node->flow_info.da, da, sizeof(flow_ring_node->flow_info.da)); + flow_ring_node->flow_info.tid = prio; + flow_ring_node->flow_info.ifindex = ifindex; + flow_ring_node->active = TRUE; + flow_ring_node->status = FLOW_RING_STATUS_PENDING; + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + dll_prepend(&dhdp->bus->const_flowring, &flow_ring_node->list); + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + + /* Create and inform device about the new flow */ + if (dhd_bus_flow_ring_create_request(dhdp->bus, (void *)flow_ring_node) + != BCME_OK) { + DHD_ERROR(("%s: create error %d\n", __FUNCTION__, id)); + return BCME_ERROR; + } + + *flowid = id; + return BCME_OK; +} + +/* Update flowid information on the packet */ +int BCMFASTPATH +dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void *pktbuf) +{ + uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); + struct ether_header *eh = (struct ether_header *)pktdata; + uint16 flowid; + + if (dhd_bus_is_txmode_push(dhdp->bus)) + return BCME_OK; + + ASSERT(ifindex < DHD_MAX_IFS); + if (ifindex >= DHD_MAX_IFS) { + return BCME_BADARG; + } + + if (!dhdp->flowid_allocator) { + DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); + return BCME_ERROR; + } + if (dhd_flowid_lookup(dhdp, ifindex, prio, eh->ether_shost, eh->ether_dhost, + &flowid) != BCME_OK) { + return BCME_ERROR; + } + + DHD_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid)); + + /* Tag the packet with flowid */ + DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(pktbuf), flowid); + return BCME_OK; +} + +void +dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid) +{ + int hashix; + bool found = FALSE; + flow_hash_info_t *cur, *prev; + if_flow_lkup_t *if_flow_lkup; + unsigned long flags; + + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; + + for (hashix = 0; hashix < DHD_FLOWRING_HASH_SIZE; hashix++) { + + cur = if_flow_lkup[ifindex].fl_hash[hashix]; + + if (cur) { + if (cur->flowid == flowid) { + found = TRUE; + } + + prev = NULL; + while (!found && cur) { + if (cur->flowid == flowid) { + found = TRUE; + break; + } + prev = cur; + cur = cur->next; + } + if (found) { + if (!prev) { + if_flow_lkup[ifindex].fl_hash[hashix] = cur->next; + } else { + prev->next = cur->next; + } + + /* deregister flowid from dhd_pub. */ + dhd_del_flowid(dhdp, ifindex, flowid); + + id16_map_free(dhdp->flowid_allocator, flowid); + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + MFREE(dhdp->osh, cur, sizeof(flow_hash_info_t)); + + return; + } + } + } + + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + DHD_ERROR(("%s: could not free flow ring hash entry flowid %d\n", + __FUNCTION__, flowid)); +} + + +/* Delete all Flow rings assocaited with the given Interface */ +void +dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex) +{ + uint32 id; + flow_ring_table_t *flow_ring_table; + + DHD_INFO(("%s: ifindex %u\n", __FUNCTION__, ifindex)); + + ASSERT(ifindex < DHD_MAX_IFS); + if (ifindex >= DHD_MAX_IFS) + return; + + if (!dhdp->flow_ring_table) + return; + + flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; + for (id = 0; id < dhdp->num_flow_rings; id++) { + if (flow_ring_table[id].active && + (flow_ring_table[id].flow_info.ifindex == ifindex) && + (flow_ring_table[id].status != FLOW_RING_STATUS_DELETE_PENDING)) { + DHD_INFO(("%s: deleting flowid %d\n", + __FUNCTION__, flow_ring_table[id].flowid)); + dhd_bus_flow_ring_delete_request(dhdp->bus, + (void *) &flow_ring_table[id]); + } + } +} + +/* Delete flow/s for given peer address */ +void +dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr) +{ + uint32 id; + flow_ring_table_t *flow_ring_table; + + DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex)); + + ASSERT(ifindex < DHD_MAX_IFS); + if (ifindex >= DHD_MAX_IFS) + return; + + if (!dhdp->flow_ring_table) + return; + + flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; + for (id = 0; id < dhdp->num_flow_rings; id++) { + if (flow_ring_table[id].active && + (flow_ring_table[id].flow_info.ifindex == ifindex) && + (!memcmp(flow_ring_table[id].flow_info.da, addr, ETHER_ADDR_LEN)) && + (flow_ring_table[id].status != FLOW_RING_STATUS_DELETE_PENDING)) { + DHD_INFO(("%s: deleting flowid %d\n", + __FUNCTION__, flow_ring_table[id].flowid)); + dhd_bus_flow_ring_delete_request(dhdp->bus, + (void *) &flow_ring_table[id]); + } + } +} + +/* Handle Interface ADD, DEL operations */ +void +dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex, + uint8 op, uint8 role) +{ + if_flow_lkup_t *if_flow_lkup; + unsigned long flags; + + ASSERT(ifindex < DHD_MAX_IFS); + if (ifindex >= DHD_MAX_IFS) + return; + + DHD_INFO(("%s: ifindex %u op %u role is %u \n", + __FUNCTION__, ifindex, op, role)); + if (!dhdp->flowid_allocator) { + DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); + return; + } + + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; + + if (op == WLC_E_IF_ADD || op == WLC_E_IF_CHANGE) { + + if_flow_lkup[ifindex].role = role; + + if (!(DHD_IF_ROLE_STA(role))) { + if_flow_lkup[ifindex].status = TRUE; + DHD_INFO(("%s: Mcast Flow ring for ifindex %d role is %d \n", + __FUNCTION__, ifindex, role)); + /* Create Mcast Flow */ + } + } else if (op == WLC_E_IF_DEL) { + if_flow_lkup[ifindex].status = FALSE; + DHD_INFO(("%s: cleanup all Flow rings for ifindex %d role is %d \n", + __FUNCTION__, ifindex, role)); + } + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); +} + +/* Handle a STA interface link status update */ +int +dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, uint8 status) +{ + if_flow_lkup_t *if_flow_lkup; + unsigned long flags; + + ASSERT(ifindex < DHD_MAX_IFS); + if (ifindex >= DHD_MAX_IFS) + return BCME_BADARG; + + DHD_INFO(("%s: ifindex %d status %d\n", __FUNCTION__, ifindex, status)); + + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; + + if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) { + if (status) + if_flow_lkup[ifindex].status = TRUE; + else + if_flow_lkup[ifindex].status = FALSE; + } + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + + return BCME_OK; +} +/* Update flow priority mapping */ +int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map) +{ + uint16 flowid; + flow_ring_node_t *flow_ring_node; + + if (map > DHD_FLOW_PRIO_TID_MAP) + return BCME_BADOPTION; + + /* Check if we need to change prio map */ + if (map == dhdp->flow_prio_map_type) + return BCME_OK; + + /* If any ring is active we cannot change priority mapping for flow rings */ + for (flowid = 0; flowid < dhdp->num_flow_rings; flowid++) { + flow_ring_node = DHD_FLOW_RING(dhdp, flowid); + if (flow_ring_node->active) + return BCME_EPERM; + } + /* Infor firmware about new mapping type */ + if (BCME_OK != dhd_flow_prio_map(dhdp, &map, TRUE)) + return BCME_ERROR; + + /* update internal structures */ + dhdp->flow_prio_map_type = map; + if (dhdp->flow_prio_map_type == DHD_FLOW_PRIO_TID_MAP) + bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); + else + bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); + + return BCME_OK; +} + +/* Set/Get flwo ring priority map */ +int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set) +{ + uint8 iovbuf[24] = {0}; + if (!set) { + bcm_mkiovar("bus:fl_prio_map", NULL, 0, (char*)iovbuf, sizeof(iovbuf)); + if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) { + DHD_ERROR(("%s: failed to get fl_prio_map\n", __FUNCTION__)); + return BCME_ERROR; + } + *map = iovbuf[0]; + return BCME_OK; + } + bcm_mkiovar("bus:fl_prio_map", (char *)map, 4, (char*)iovbuf, sizeof(iovbuf)); + if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { + DHD_ERROR(("%s: failed to set fl_prio_map \n", + __FUNCTION__)); + return BCME_ERROR; + } + return BCME_OK; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.h new file mode 100644 index 000000000000..e0d6bca22084 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.h @@ -0,0 +1,177 @@ +/* + * Header file describing the flow rings DHD interfaces. + * + * Provides type definitions and function prototypes used to create, delete and manage + * + * flow rings at high level + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_flowrings.h jaganlv $ + */ + +/**************** + * Common types * + */ + +#ifndef _dhd_flowrings_h_ +#define _dhd_flowrings_h_ + +/* Max pkts held in a flow ring's backup queue */ +#define FLOW_RING_QUEUE_THRESHOLD (2048) + +/* Number of H2D common rings : PCIE Spec Rev? */ +#define FLOW_RING_COMMON 2 + +#define FLOWID_INVALID (ID16_INVALID) +#define FLOWID_RESERVED (FLOW_RING_COMMON) + +#define FLOW_RING_STATUS_OPEN 0 +#define FLOW_RING_STATUS_PENDING 1 +#define FLOW_RING_STATUS_CLOSED 2 +#define FLOW_RING_STATUS_DELETE_PENDING 3 +#define FLOW_RING_STATUS_FLUSH_PENDING 4 + +#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 2048 + +#define DHD_FLOW_PRIO_AC_MAP 0 +#define DHD_FLOW_PRIO_TID_MAP 1 + + +/* Pkttag not compatible with PROP_TXSTATUS or WLFC */ +typedef struct dhd_pkttag_fr { + uint16 flowid; + int dataoff; +} dhd_pkttag_fr_t; + +#define DHD_PKTTAG_SET_FLOWID(tag, flow) ((tag)->flowid = (uint16)(flow)) +#define DHD_PKTTAG_SET_DATAOFF(tag, offset) ((tag)->dataoff = (int)(offset)) + +#define DHD_PKTTAG_FLOWID(tag) ((tag)->flowid) +#define DHD_PKTTAG_DATAOFF(tag) ((tag)->dataoff) + +/* Hashing a MacAddress for lkup into a per interface flow hash table */ +#define DHD_FLOWRING_HASH_SIZE 256 +#define DHD_FLOWRING_HASHINDEX(ea, prio) \ + ((((uint8 *)(ea))[3] ^ ((uint8 *)(ea))[4] ^ ((uint8 *)(ea))[5] ^ ((uint8)(prio))) \ + % DHD_FLOWRING_HASH_SIZE) + +#define DHD_IF_ROLE(pub, idx) (((if_flow_lkup_t *)(pub)->if_flow_lkup)[idx].role) +#define DHD_IF_ROLE_AP(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_AP) +#define DHD_IF_ROLE_P2PGO(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_P2P_GO) +#define DHD_FLOW_RING(dhdp, flowid) \ + (flow_ring_node_t *)&(((flow_ring_node_t *)((dhdp)->flow_ring_table))[flowid]) + +struct flow_queue; + +/* Flow Ring Queue Enqueue overflow callback */ +typedef int (*flow_queue_cb_t)(struct flow_queue * queue, void * pkt); + +typedef struct flow_queue { + dll_t list; /* manage a flowring queue in a dll */ + void * head; /* first packet in the queue */ + void * tail; /* last packet in the queue */ + uint16 len; /* number of packets in the queue */ + uint16 max; /* maximum number of packets, queue may hold */ + uint32 failures; /* enqueue failures due to queue overflow */ + flow_queue_cb_t cb; /* callback invoked on threshold crossing */ +} flow_queue_t; + +#define flow_queue_len(queue) ((int)(queue)->len) +#define flow_queue_max(queue) ((int)(queue)->max) +#define flow_queue_avail(queue) ((int)((queue)->max - (queue)->len)) +#define flow_queue_full(queue) ((queue)->len >= (queue)->max) +#define flow_queue_empty(queue) ((queue)->len == 0) + +typedef struct flow_info { + uint8 tid; + uint8 ifindex; + char sa[ETHER_ADDR_LEN]; + char da[ETHER_ADDR_LEN]; +} flow_info_t; + +typedef struct flow_ring_node { + dll_t list; /* manage a constructed flowring in a dll, must be at first place */ + flow_queue_t queue; + bool active; + uint8 status; + uint16 flowid; + flow_info_t flow_info; + void *prot_info; + void *lock; /* lock for flowring access protection */ +} flow_ring_node_t; +typedef flow_ring_node_t flow_ring_table_t; + +typedef struct flow_hash_info { + uint16 flowid; + flow_info_t flow_info; + struct flow_hash_info *next; +} flow_hash_info_t; + +typedef struct if_flow_lkup { + bool status; + uint8 role; /* Interface role: STA/AP */ + flow_hash_info_t *fl_hash[DHD_FLOWRING_HASH_SIZE]; /* Lkup Hash table */ +} if_flow_lkup_t; + +static INLINE flow_ring_node_t * +dhd_constlist_to_flowring(dll_t *item) +{ + return ((flow_ring_node_t *)item); +} + +/* Exported API */ + +/* Flow ring's queue management functions */ +extern void dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max); +extern void dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb); +extern int dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt); +extern void * dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue); +extern void dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt); + +extern int dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings); + +extern void dhd_flow_rings_deinit(dhd_pub_t *dhdp); + +extern uint16 dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da); + +extern int dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, + void *pktbuf); + +extern void dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid); + +extern void dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex); + +extern void dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, + char *addr); + +/* Handle Interface ADD, DEL operations */ +extern void dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex, + uint8 op, uint8 role); + +/* Handle a STA interface link status update */ +extern int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, + uint8 status); +extern int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set); +extern int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map); + +extern uint8 dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex); +#endif /* _dhd_flowrings_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.c new file mode 100644 index 000000000000..2d21052601f9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.c @@ -0,0 +1,1318 @@ +/* + * IP Packet Parser Module. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_ip.c 528525 2015-01-22 12:50:08Z $ + */ +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef DHDTCPACK_SUPPRESS +#include +#include +#include +#endif /* DHDTCPACK_SUPPRESS */ + +/* special values */ +/* 802.3 llc/snap header */ +static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; + +pkt_frag_t pkt_frag_info(osl_t *osh, void *p) +{ + uint8 *frame; + int length; + uint8 *pt; /* Pointer to type field */ + uint16 ethertype; + struct ipv4_hdr *iph; /* IP frame pointer */ + int ipl; /* IP frame length */ + uint16 iph_frag; + + ASSERT(osh && p); + + frame = PKTDATA(osh, p); + length = PKTLEN(osh, p); + + /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ + if (length < ETHER_HDR_LEN) { + DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length)); + return DHD_PKT_FRAG_NONE; + } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { + /* Frame is Ethernet II */ + pt = frame + ETHER_TYPE_OFFSET; + } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && + !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { + pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; + } else { + DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__)); + return DHD_PKT_FRAG_NONE; + } + + ethertype = ntoh16(*(uint16 *)pt); + + /* Skip VLAN tag, if any */ + if (ethertype == ETHER_TYPE_8021Q) { + pt += VLAN_TAG_LEN; + + if (pt + ETHER_TYPE_LEN > frame + length) { + DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length)); + return DHD_PKT_FRAG_NONE; + } + + ethertype = ntoh16(*(uint16 *)pt); + } + + if (ethertype != ETHER_TYPE_IP) { + DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n", + __FUNCTION__, ethertype, length)); + return DHD_PKT_FRAG_NONE; + } + + iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); + ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame)); + + /* We support IPv4 only */ + if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) { + DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl)); + return DHD_PKT_FRAG_NONE; + } + + iph_frag = ntoh16(iph->frag); + + if (iph_frag & IPV4_FRAG_DONT) { + return DHD_PKT_FRAG_NONE; + } else if ((iph_frag & IPV4_FRAG_MORE) == 0) { + return DHD_PKT_FRAG_LAST; + } else { + return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST; + } +} + +bool pkt_is_dhcp(osl_t *osh, void *p) +{ + uint8 *frame; + int length; + uint8 *pt; /* Pointer to type field */ + uint16 ethertype; + struct ipv4_hdr *iph; /* IP frame pointer */ + int ipl; /* IP frame length */ + uint16 src_port; + + ASSERT(osh && p); + + frame = PKTDATA(osh, p); + length = PKTLEN(osh, p); + + /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ + if (length < ETHER_HDR_LEN) { + DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length)); + return FALSE; + } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { + /* Frame is Ethernet II */ + pt = frame + ETHER_TYPE_OFFSET; + } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && + !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { + pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; + } else { + DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__)); + return FALSE; + } + + ethertype = ntoh16(*(uint16 *)pt); + + /* Skip VLAN tag, if any */ + if (ethertype == ETHER_TYPE_8021Q) { + pt += VLAN_TAG_LEN; + + if (pt + ETHER_TYPE_LEN > frame + length) { + DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length)); + return FALSE; + } + + ethertype = ntoh16(*(uint16 *)pt); + } + + if (ethertype != ETHER_TYPE_IP) { + DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n", + __FUNCTION__, ethertype, length)); + return FALSE; + } + + iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); + ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame)); + + /* We support IPv4 only */ + if ((ipl < (IPV4_OPTIONS_OFFSET + 2)) || (IP_VER(iph) != IP_VER_4)) { + DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl)); + return FALSE; + } + + src_port = ntoh16(*(uint16 *)(pt + ETHER_TYPE_LEN + IPV4_OPTIONS_OFFSET)); + + return (src_port == 0x43 || src_port == 0x44); +} + +#ifdef DHDTCPACK_SUPPRESS + +typedef struct { + void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */ + void *pkt_ether_hdr; /* Ethernet header pointer of pkt_in_q */ + int ifidx; + uint8 supp_cnt; + dhd_pub_t *dhdp; + struct timer_list timer; +} tcpack_info_t; + +typedef struct _tdata_psh_info_t { + uint32 end_seq; /* end seq# of a received TCP PSH DATA pkt */ + struct _tdata_psh_info_t *next; /* next pointer of the link chain */ +} tdata_psh_info_t; + +typedef struct { + uint8 src_ip_addr[IPV4_ADDR_LEN]; /* SRC ip addrs of this TCP stream */ + uint8 dst_ip_addr[IPV4_ADDR_LEN]; /* DST ip addrs of this TCP stream */ + uint8 src_tcp_port[TCP_PORT_LEN]; /* SRC tcp ports of this TCP stream */ + uint8 dst_tcp_port[TCP_PORT_LEN]; /* DST tcp ports of this TCP stream */ + tdata_psh_info_t *tdata_psh_info_head; /* Head of received TCP PSH DATA chain */ + tdata_psh_info_t *tdata_psh_info_tail; /* Tail of received TCP PSH DATA chain */ + uint32 last_used_time; /* The last time this tcpdata_info was used(in ms) */ +} tcpdata_info_t; + +/* TCPACK SUPPRESS module */ +typedef struct { + int tcpack_info_cnt; + tcpack_info_t tcpack_info_tbl[TCPACK_INFO_MAXNUM]; /* Info of TCP ACK to send */ + int tcpdata_info_cnt; + tcpdata_info_t tcpdata_info_tbl[TCPDATA_INFO_MAXNUM]; /* Info of received TCP DATA */ + tdata_psh_info_t *tdata_psh_info_pool; /* Pointer to tdata_psh_info elements pool */ + tdata_psh_info_t *tdata_psh_info_free; /* free tdata_psh_info elements chain in pool */ +#ifdef DHDTCPACK_SUP_DBG + int psh_info_enq_num; /* Number of free TCP PSH DATA info elements in pool */ +#endif /* DHDTCPACK_SUP_DBG */ +} tcpack_sup_module_t; + +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) +counter_tbl_t tack_tbl = {"tcpACK", 0, 1000, 10, {0, }, 1}; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + +static void +_tdata_psh_info_pool_enq(tcpack_sup_module_t *tcpack_sup_mod, + tdata_psh_info_t *tdata_psh_info) +{ + if ((tcpack_sup_mod == NULL) || (tdata_psh_info == NULL)) { + DHD_ERROR(("%s %d: ERROR %p %p\n", __FUNCTION__, __LINE__, + tcpack_sup_mod, tdata_psh_info)); + return; + } + + ASSERT(tdata_psh_info->next == NULL); + tdata_psh_info->next = tcpack_sup_mod->tdata_psh_info_free; + tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info; +#ifdef DHDTCPACK_SUP_DBG + tcpack_sup_mod->psh_info_enq_num++; +#endif +} + +static tdata_psh_info_t* +_tdata_psh_info_pool_deq(tcpack_sup_module_t *tcpack_sup_mod) +{ + tdata_psh_info_t *tdata_psh_info = NULL; + + if (tcpack_sup_mod == NULL) { + DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__, __LINE__, + tcpack_sup_mod)); + return NULL; + } + + tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free; + if (tdata_psh_info == NULL) + DHD_ERROR(("%s %d: Out of tdata_disc_grp\n", __FUNCTION__, __LINE__)); + else { + tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; + tdata_psh_info->next = NULL; +#ifdef DHDTCPACK_SUP_DBG + tcpack_sup_mod->psh_info_enq_num--; +#endif /* DHDTCPACK_SUP_DBG */ + } + + return tdata_psh_info; +} + +#ifdef BCMSDIO +static int _tdata_psh_info_pool_init(dhd_pub_t *dhdp, + tcpack_sup_module_t *tcpack_sup_mod) +{ + tdata_psh_info_t *tdata_psh_info_pool = NULL; + uint i; + + DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); + + if (tcpack_sup_mod == NULL) + return BCME_ERROR; + + ASSERT(tcpack_sup_mod->tdata_psh_info_pool == NULL); + ASSERT(tcpack_sup_mod->tdata_psh_info_free == NULL); + + tdata_psh_info_pool = + MALLOC(dhdp->osh, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); + + if (tdata_psh_info_pool == NULL) + return BCME_NOMEM; + bzero(tdata_psh_info_pool, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); +#ifdef DHDTCPACK_SUP_DBG + tcpack_sup_mod->psh_info_enq_num = 0; +#endif /* DHDTCPACK_SUP_DBG */ + + /* Enqueue newly allocated tcpdata psh info elements to the pool */ + for (i = 0; i < TCPDATA_PSH_INFO_MAXNUM; i++) + _tdata_psh_info_pool_enq(tcpack_sup_mod, &tdata_psh_info_pool[i]); + + ASSERT(tcpack_sup_mod->tdata_psh_info_free != NULL); + tcpack_sup_mod->tdata_psh_info_pool = tdata_psh_info_pool; + + return BCME_OK; +} + +static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp, + tcpack_sup_module_t *tcpack_sup_mod) +{ + uint i; + tdata_psh_info_t *tdata_psh_info; + + DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); + + if (tcpack_sup_mod == NULL) { + DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n", + __FUNCTION__, __LINE__)); + return; + } + + for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { + tcpdata_info_t *tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; + /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */ + while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { + tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; + tdata_psh_info->next = NULL; + _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); + } + tcpdata_info->tdata_psh_info_tail = NULL; + } +#ifdef DHDTCPACK_SUP_DBG + DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); +#endif /* DHDTCPACK_SUP_DBG */ + + i = 0; + /* Be sure we recollected all tdata_psh_info elements */ + while ((tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free)) { + tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; + tdata_psh_info->next = NULL; + i++; + } + ASSERT(i == TCPDATA_PSH_INFO_MAXNUM); + MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool, + sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); + tcpack_sup_mod->tdata_psh_info_pool = NULL; + + return; +} +#endif /* BCMSDIO */ + +static void dhd_tcpack_send(ulong data) +{ + tcpack_sup_module_t *tcpack_sup_mod; + tcpack_info_t *cur_tbl = (tcpack_info_t *)data; + dhd_pub_t *dhdp; + int ifidx; + void* pkt; + + if (!cur_tbl) { + return; + } + + dhdp = cur_tbl->dhdp; + if (!dhdp) { + return; + } + + dhd_os_tcpacklock(dhdp); + + tcpack_sup_mod = dhdp->tcpack_sup_module; + pkt = cur_tbl->pkt_in_q; + ifidx = cur_tbl->ifidx; + if (!pkt) { + dhd_os_tcpackunlock(dhdp); + return; + } + cur_tbl->pkt_in_q = NULL; + cur_tbl->pkt_ether_hdr = NULL; + cur_tbl->ifidx = 0; + cur_tbl->supp_cnt = 0; + if (--tcpack_sup_mod->tcpack_info_cnt < 0) { + DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); + } + + dhd_os_tcpackunlock(dhdp); + + dhd_sendpkt(dhdp, ifidx, pkt); +} + +int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode) +{ + int ret = BCME_OK; + + dhd_os_tcpacklock(dhdp); + + if (dhdp->tcpack_sup_mode == mode) { + DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode)); + goto exit; + } + + if (mode >= TCPACK_SUP_LAST_MODE || +#ifndef BCMSDIO + mode == TCPACK_SUP_DELAYTX || +#endif /* !BCMSDIO */ + FALSE) { + DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__, __LINE__, mode)); + ret = BCME_BADARG; + goto exit; + } + + DHD_TRACE(("%s: %d -> %d\n", + __FUNCTION__, dhdp->tcpack_sup_mode, mode)); + +#ifdef BCMSDIO + /* Old tcpack_sup_mode is TCPACK_SUP_DELAYTX */ + if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX) { + tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; + /* We won't need tdata_psh_info pool and tcpddata_info_tbl anymore */ + _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_mod); + tcpack_sup_mod->tcpdata_info_cnt = 0; + bzero(tcpack_sup_mod->tcpdata_info_tbl, + sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM); + /* For half duplex bus interface, tx precedes rx by default */ + if (dhdp->bus) + dhd_bus_set_dotxinrx(dhdp->bus, TRUE); + } +#endif + dhdp->tcpack_sup_mode = mode; + + if (mode == TCPACK_SUP_OFF) { + ASSERT(dhdp->tcpack_sup_module != NULL); + /* Clean up timer/data structure for any remaining/pending packet or timer. */ + dhd_tcpack_info_tbl_clean(dhdp); + MFREE(dhdp->osh, dhdp->tcpack_sup_module, sizeof(tcpack_sup_module_t)); + dhdp->tcpack_sup_module = NULL; + goto exit; + } + + if (dhdp->tcpack_sup_module == NULL) { + tcpack_sup_module_t *tcpack_sup_mod = + MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t)); + if (tcpack_sup_mod == NULL) { + DHD_ERROR(("%s %d: No MEM\n", __FUNCTION__, __LINE__)); + dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; + ret = BCME_NOMEM; + goto exit; + } + bzero(tcpack_sup_mod, sizeof(tcpack_sup_module_t)); + dhdp->tcpack_sup_module = tcpack_sup_mod; + } + +#ifdef BCMSDIO + if (mode == TCPACK_SUP_DELAYTX) { + ret = _tdata_psh_info_pool_init(dhdp, dhdp->tcpack_sup_module); + if (ret != BCME_OK) + DHD_ERROR(("%s %d: pool init fail with %d\n", __FUNCTION__, __LINE__, ret)); + else if (dhdp->bus) + dhd_bus_set_dotxinrx(dhdp->bus, FALSE); + } +#endif /* BCMSDIO */ + + if (mode == TCPACK_SUP_HOLD) { + int i; + tcpack_sup_module_t *tcpack_sup_mod = + (tcpack_sup_module_t *)dhdp->tcpack_sup_module; + dhdp->tcpack_sup_ratio = TCPACK_SUPP_RATIO; + dhdp->tcpack_sup_delay = TCPACK_DELAY_TIME; + for (i = 0; i < TCPACK_INFO_MAXNUM; i++) + { + tcpack_sup_mod->tcpack_info_tbl[i].dhdp = dhdp; + init_timer(&tcpack_sup_mod->tcpack_info_tbl[i].timer); + tcpack_sup_mod->tcpack_info_tbl[i].timer.data = + (ulong)&tcpack_sup_mod->tcpack_info_tbl[i]; + tcpack_sup_mod->tcpack_info_tbl[i].timer.function = dhd_tcpack_send; + } + } + +exit: + dhd_os_tcpackunlock(dhdp); + return ret; +} + +void +dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp) +{ + tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; + int i; + + if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) + goto exit; + + dhd_os_tcpacklock(dhdp); + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", + __FUNCTION__, __LINE__)); + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) { + for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { + if (tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q) { + PKTFREE(dhdp->osh, tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q, + TRUE); + tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q = NULL; + tcpack_sup_mod->tcpack_info_tbl[i].pkt_ether_hdr = NULL; + tcpack_sup_mod->tcpack_info_tbl[i].ifidx = 0; + tcpack_sup_mod->tcpack_info_tbl[i].supp_cnt = 0; + } + } + } else { + tcpack_sup_mod->tcpack_info_cnt = 0; + bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM); + } + + dhd_os_tcpackunlock(dhdp); + + if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) { + for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { + del_timer_sync(&tcpack_sup_mod->tcpack_info_tbl[i].timer); + } + } + +exit: + return; +} + +inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt) +{ + uint8 i; + tcpack_sup_module_t *tcpack_sup_mod; + tcpack_info_t *tcpack_info_tbl; + int tbl_cnt; + int ret = BCME_OK; + void *pdata; + uint32 pktlen; + + if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) + goto exit; + + pdata = PKTDATA(dhdp->osh, pkt); + pktlen = PKTLEN(dhdp->osh, pkt) - dhd_prot_hdrlen(dhdp, pdata); + + if (pktlen < TCPACKSZMIN || pktlen > TCPACKSZMAX) { + DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", + __FUNCTION__, __LINE__, pktlen)); + goto exit; + } + + dhd_os_tcpacklock(dhdp); + tcpack_sup_mod = dhdp->tcpack_sup_module; + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); + ret = BCME_ERROR; + dhd_os_tcpackunlock(dhdp); + goto exit; + } + tbl_cnt = tcpack_sup_mod->tcpack_info_cnt; + tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; + + ASSERT(tbl_cnt <= TCPACK_INFO_MAXNUM); + + for (i = 0; i < tbl_cnt; i++) { + if (tcpack_info_tbl[i].pkt_in_q == pkt) { + DHD_TRACE(("%s %d: pkt %p sent out. idx %d, tbl_cnt %d\n", + __FUNCTION__, __LINE__, pkt, i, tbl_cnt)); + /* This pkt is being transmitted so remove the tcp_ack_info of it. */ + if (i < tbl_cnt - 1) { + bcopy(&tcpack_info_tbl[tbl_cnt - 1], + &tcpack_info_tbl[i], sizeof(tcpack_info_t)); + } + bzero(&tcpack_info_tbl[tbl_cnt - 1], sizeof(tcpack_info_t)); + if (--tcpack_sup_mod->tcpack_info_cnt < 0) { + DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); + ret = BCME_ERROR; + } + break; + } + } + dhd_os_tcpackunlock(dhdp); + +exit: + return ret; +} + +static INLINE bool dhd_tcpdata_psh_acked(dhd_pub_t *dhdp, uint8 *ip_hdr, + uint8 *tcp_hdr, uint32 tcp_ack_num) +{ + tcpack_sup_module_t *tcpack_sup_mod; + int i; + tcpdata_info_t *tcpdata_info = NULL; + tdata_psh_info_t *tdata_psh_info = NULL; + bool ret = FALSE; + + if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) + goto exit; + + tcpack_sup_mod = dhdp->tcpack_sup_module; + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); + goto exit; + } + + DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d, ack %u\n", __FUNCTION__, __LINE__, + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), + tcp_ack_num)); + + for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { + tcpdata_info_t *tcpdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; + DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d\n", __FUNCTION__, __LINE__, i, + IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->src_ip_addr)), + IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->dst_ip_addr)), + ntoh16_ua(tcpdata_info_tmp->src_tcp_port), + ntoh16_ua(tcpdata_info_tmp->dst_tcp_port))); + + /* If either IP address or TCP port number does not match, skip. */ + if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], + tcpdata_info_tmp->dst_ip_addr, IPV4_ADDR_LEN) == 0 && + memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET], + tcpdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN) == 0 && + memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], + tcpdata_info_tmp->dst_tcp_port, TCP_PORT_LEN) == 0 && + memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET], + tcpdata_info_tmp->src_tcp_port, TCP_PORT_LEN) == 0) { + tcpdata_info = tcpdata_info_tmp; + break; + } + } + + if (tcpdata_info == NULL) { + DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__, __LINE__)); + goto exit; + } + + if (tcpdata_info->tdata_psh_info_head == NULL) { + DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__, __LINE__)); + } + + while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { + if (IS_TCPSEQ_GE(tcp_ack_num, tdata_psh_info->end_seq)) { + DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n", + __FUNCTION__, __LINE__, tcp_ack_num, tdata_psh_info->end_seq)); + tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; + tdata_psh_info->next = NULL; + _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); + ret = TRUE; + } else + break; + } + if (tdata_psh_info == NULL) + tcpdata_info->tdata_psh_info_tail = NULL; + +#ifdef DHDTCPACK_SUP_DBG + DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); +#endif /* DHDTCPACK_SUP_DBG */ + +exit: + return ret; +} + +bool +dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt) +{ + uint8 *new_ether_hdr; /* Ethernet header of the new packet */ + uint16 new_ether_type; /* Ethernet type of the new packet */ + uint8 *new_ip_hdr; /* IP header of the new packet */ + uint8 *new_tcp_hdr; /* TCP header of the new packet */ + uint32 new_ip_hdr_len; /* IP header length of the new packet */ + uint32 cur_framelen; + uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ + uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ + uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ + tcpack_sup_module_t *tcpack_sup_mod; + tcpack_info_t *tcpack_info_tbl; + int i; + bool ret = FALSE; + bool set_dotxinrx = TRUE; + + if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) + goto exit; + + new_ether_hdr = PKTDATA(dhdp->osh, pkt); + cur_framelen = PKTLEN(dhdp->osh, pkt); + + if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { + DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", + __FUNCTION__, __LINE__, cur_framelen)); + goto exit; + } + + new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; + + if (new_ether_type != ETHER_TYPE_IP) { + DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", + __FUNCTION__, __LINE__, new_ether_type)); + goto exit; + } + + DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); + + new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; + cur_framelen -= ETHER_HDR_LEN; + + ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); + + new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); + if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { + DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", + __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); + goto exit; + } + + new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; + cur_framelen -= new_ip_hdr_len; + + ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); + + DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); + + /* is it an ack ? Allow only ACK flag, not to suppress others. */ + if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { + DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", + __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); + goto exit; + } + + new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); + new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); + + /* This packet has TCP data, so just send */ + if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { + DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); + goto exit; + } + + ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); + + new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); + + DHD_TRACE(("%s %d: TCP ACK with zero DATA length" + " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", + __FUNCTION__, __LINE__, + IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); + + /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ + dhd_os_tcpacklock(dhdp); +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + counter_printlog(&tack_tbl); + tack_tbl.cnt[0]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + + tcpack_sup_mod = dhdp->tcpack_sup_module; + tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); + ret = BCME_ERROR; + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + if (dhd_tcpdata_psh_acked(dhdp, new_ip_hdr, new_tcp_hdr, new_tcp_ack_num)) { + /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */ +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[5]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + } else + set_dotxinrx = FALSE; + + for (i = 0; i < tcpack_sup_mod->tcpack_info_cnt; i++) { + void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ + uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; + uint32 old_ip_hdr_len, old_tcp_hdr_len; + uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ + + if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { + DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n", + __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); + break; + } + + if (PKTDATA(dhdp->osh, oldpkt) == NULL) { + DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n", + __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); + break; + } + + old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; + old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; + old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); + old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; + old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); + + DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, + IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); + + /* If either of IP address or TCP port number does not match, skip. */ + if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], + &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || + memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], + &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) + continue; + + old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); + + if (IS_TCPSEQ_GT(new_tcp_ack_num, old_tcpack_num)) { + /* New packet has higher TCP ACK number, so it replaces the old packet */ + if (new_ip_hdr_len == old_ip_hdr_len && + new_tcp_hdr_len == old_tcp_hdr_len) { + ASSERT(memcmp(new_ether_hdr, old_ether_hdr, ETHER_HDR_LEN) == 0); + bcopy(new_ip_hdr, old_ip_hdr, new_ip_total_len); + PKTFREE(dhdp->osh, pkt, FALSE); + DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n", + __FUNCTION__, __LINE__, old_tcpack_num, new_tcp_ack_num)); +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[2]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + ret = TRUE; + } else { +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[6]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d" + " ACK %u -> %u\n", __FUNCTION__, __LINE__, + new_ip_hdr_len, old_ip_hdr_len, + new_tcp_hdr_len, old_tcp_hdr_len, + old_tcpack_num, new_tcp_ack_num)); + } + } else if (new_tcp_ack_num == old_tcpack_num) { + set_dotxinrx = TRUE; + /* TCPACK retransmission */ +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[3]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + } else { + DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n", + __FUNCTION__, __LINE__, old_tcpack_num, oldpkt, + new_tcp_ack_num, pkt)); + } + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + if (i == tcpack_sup_mod->tcpack_info_cnt && i < TCPACK_INFO_MAXNUM) { + /* No TCPACK packet with the same IP addr and TCP port is found + * in tcp_ack_info_tbl. So add this packet to the table. + */ + DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", + __FUNCTION__, __LINE__, pkt, new_ether_hdr, + tcpack_sup_mod->tcpack_info_cnt)); + + tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_in_q = pkt; + tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_ether_hdr = new_ether_hdr; + tcpack_sup_mod->tcpack_info_cnt++; +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[1]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + } else { + ASSERT(i == tcpack_sup_mod->tcpack_info_cnt); + DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", + __FUNCTION__, __LINE__)); + } + dhd_os_tcpackunlock(dhdp); + +exit: + /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */ + if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX && set_dotxinrx) + dhd_bus_set_dotxinrx(dhdp->bus, TRUE); + + return ret; +} + +bool +dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt) +{ + uint8 *ether_hdr; /* Ethernet header of the new packet */ + uint16 ether_type; /* Ethernet type of the new packet */ + uint8 *ip_hdr; /* IP header of the new packet */ + uint8 *tcp_hdr; /* TCP header of the new packet */ + uint32 ip_hdr_len; /* IP header length of the new packet */ + uint32 cur_framelen; + uint16 ip_total_len; /* Total length of IP packet for the new packet */ + uint32 tcp_hdr_len; /* TCP header length of the new packet */ + uint32 tcp_seq_num; /* TCP sequence number of the new packet */ + uint16 tcp_data_len; /* TCP DATA length that excludes IP and TCP headers */ + uint32 end_tcp_seq_num; /* TCP seq number of the last byte in the new packet */ + tcpack_sup_module_t *tcpack_sup_mod; + tcpdata_info_t *tcpdata_info = NULL; + tdata_psh_info_t *tdata_psh_info; + + int i; + bool ret = FALSE; + + if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) + goto exit; + + ether_hdr = PKTDATA(dhdp->osh, pkt); + cur_framelen = PKTLEN(dhdp->osh, pkt); + + ether_type = ether_hdr[12] << 8 | ether_hdr[13]; + + if (ether_type != ETHER_TYPE_IP) { + DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", + __FUNCTION__, __LINE__, ether_type)); + goto exit; + } + + DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, ether_type)); + + ip_hdr = ether_hdr + ETHER_HDR_LEN; + cur_framelen -= ETHER_HDR_LEN; + + ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); + + ip_hdr_len = IPV4_HLEN(ip_hdr); + if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { + DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", + __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr))); + goto exit; + } + + tcp_hdr = ip_hdr + ip_hdr_len; + cur_framelen -= ip_hdr_len; + + ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); + + DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); + + ip_total_len = ntoh16_ua(&ip_hdr[IPV4_PKTLEN_OFFSET]); + tcp_hdr_len = 4 * TCP_HDRLEN(tcp_hdr[TCP_HLEN_OFFSET]); + + /* This packet is mere TCP ACK, so do nothing */ + if (ip_total_len == ip_hdr_len + tcp_hdr_len) { + DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__, __LINE__)); + goto exit; + } + + ASSERT(ip_total_len > ip_hdr_len + tcp_hdr_len); + + if ((tcp_hdr[TCP_FLAGS_OFFSET] & TCP_FLAG_PSH) == 0) { + DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__, __LINE__)); + goto exit; + } + + DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length" + " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d, flag 0x%x\n", + __FUNCTION__, __LINE__, + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), + tcp_hdr[TCP_FLAGS_OFFSET])); + + dhd_os_tcpacklock(dhdp); + tcpack_sup_mod = dhdp->tcpack_sup_module; + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); + ret = BCME_ERROR; + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */ + i = 0; + while (i < tcpack_sup_mod->tcpdata_info_cnt) { + tcpdata_info_t *tdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; + uint32 now_in_ms = OSL_SYSUPTIME(); + DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d\n", __FUNCTION__, __LINE__, i, + IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->src_ip_addr)), + IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->dst_ip_addr)), + ntoh16_ua(tdata_info_tmp->src_tcp_port), + ntoh16_ua(tdata_info_tmp->dst_tcp_port))); + + /* If both IP address and TCP port number match, we found it so break. */ + if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], tdata_info_tmp->src_ip_addr, + IPV4_ADDR_LEN) == 0 && + memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET], tdata_info_tmp->dst_ip_addr, + IPV4_ADDR_LEN) == 0 && + memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], tdata_info_tmp->src_tcp_port, + TCP_PORT_LEN) == 0 && + memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET], tdata_info_tmp->dst_tcp_port, + TCP_PORT_LEN) == 0) { + tcpdata_info = tdata_info_tmp; + tcpdata_info->last_used_time = now_in_ms; + break; + } + + if (now_in_ms - tdata_info_tmp->last_used_time > TCPDATA_INFO_TIMEOUT) { + tdata_psh_info_t *tdata_psh_info_tmp; + tcpdata_info_t *last_tdata_info; + + while ((tdata_psh_info_tmp = tdata_info_tmp->tdata_psh_info_head)) { + tdata_info_tmp->tdata_psh_info_head = tdata_psh_info_tmp->next; + tdata_psh_info_tmp->next = NULL; + DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n", + __FUNCTION__, __LINE__, tdata_psh_info_tmp->end_seq)); + _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info_tmp); + } +#ifdef DHDTCPACK_SUP_DBG + DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); +#endif /* DHDTCPACK_SUP_DBG */ + tcpack_sup_mod->tcpdata_info_cnt--; + ASSERT(tcpack_sup_mod->tcpdata_info_cnt >= 0); + + last_tdata_info = + &tcpack_sup_mod->tcpdata_info_tbl[tcpack_sup_mod->tcpdata_info_cnt]; + if (i < tcpack_sup_mod->tcpdata_info_cnt) { + ASSERT(last_tdata_info != tdata_info_tmp); + bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t)); + } + bzero(last_tdata_info, sizeof(tcpdata_info_t)); + DHD_INFO(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n", + __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt)); + /* Don't increase "i" here, so that the prev last tcpdata_info is checked */ + } else + i++; + } + + tcp_seq_num = ntoh32_ua(&tcp_hdr[TCP_SEQ_NUM_OFFSET]); + tcp_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len; + end_tcp_seq_num = tcp_seq_num + tcp_data_len; + + if (tcpdata_info == NULL) { + ASSERT(i == tcpack_sup_mod->tcpdata_info_cnt); + if (i >= TCPDATA_INFO_MAXNUM) { + DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d" + " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", + __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt, + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); + dhd_os_tcpackunlock(dhdp); + goto exit; + } + tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; + + /* No TCP flow with the same IP addr and TCP port is found + * in tcp_data_info_tbl. So add this flow to the table. + */ + DHD_INFO(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt, + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); + + bcopy(&ip_hdr[IPV4_SRC_IP_OFFSET], tcpdata_info->src_ip_addr, + IPV4_ADDR_LEN); + bcopy(&ip_hdr[IPV4_DEST_IP_OFFSET], tcpdata_info->dst_ip_addr, + IPV4_ADDR_LEN); + bcopy(&tcp_hdr[TCP_SRC_PORT_OFFSET], tcpdata_info->src_tcp_port, + TCP_PORT_LEN); + bcopy(&tcp_hdr[TCP_DEST_PORT_OFFSET], tcpdata_info->dst_tcp_port, + TCP_PORT_LEN); + + tcpdata_info->last_used_time = OSL_SYSUPTIME(); + tcpack_sup_mod->tcpdata_info_cnt++; + } + + ASSERT(tcpdata_info != NULL); + + tdata_psh_info = _tdata_psh_info_pool_deq(tcpack_sup_mod); +#ifdef DHDTCPACK_SUP_DBG + DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); +#endif /* DHDTCPACK_SUP_DBG */ + + if (tdata_psh_info == NULL) { + DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__, __LINE__)); + ret = BCME_ERROR; + dhd_os_tcpackunlock(dhdp); + goto exit; + } + tdata_psh_info->end_seq = end_tcp_seq_num; + +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[4]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + + DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n", + __FUNCTION__, __LINE__, tdata_psh_info->end_seq)); + + ASSERT(tdata_psh_info->next == NULL); + + if (tcpdata_info->tdata_psh_info_head == NULL) + tcpdata_info->tdata_psh_info_head = tdata_psh_info; + else { + ASSERT(tcpdata_info->tdata_psh_info_tail); + tcpdata_info->tdata_psh_info_tail->next = tdata_psh_info; + } + tcpdata_info->tdata_psh_info_tail = tdata_psh_info; + + dhd_os_tcpackunlock(dhdp); + +exit: + return ret; +} + +bool +dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx) +{ + uint8 *new_ether_hdr; /* Ethernet header of the new packet */ + uint16 new_ether_type; /* Ethernet type of the new packet */ + uint8 *new_ip_hdr; /* IP header of the new packet */ + uint8 *new_tcp_hdr; /* TCP header of the new packet */ + uint32 new_ip_hdr_len; /* IP header length of the new packet */ + uint32 cur_framelen; + uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ + uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ + uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ + tcpack_sup_module_t *tcpack_sup_mod; + tcpack_info_t *tcpack_info_tbl; + int i, free_slot = TCPACK_INFO_MAXNUM; + bool hold = FALSE; + + if (dhdp->tcpack_sup_mode != TCPACK_SUP_HOLD) { + goto exit; + } + + if (dhdp->tcpack_sup_ratio == 1) { + goto exit; + } + + new_ether_hdr = PKTDATA(dhdp->osh, pkt); + cur_framelen = PKTLEN(dhdp->osh, pkt); + + if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { + DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", + __FUNCTION__, __LINE__, cur_framelen)); + goto exit; + } + + new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; + + if (new_ether_type != ETHER_TYPE_IP) { + DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", + __FUNCTION__, __LINE__, new_ether_type)); + goto exit; + } + + DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); + + new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; + cur_framelen -= ETHER_HDR_LEN; + + ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); + + new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); + if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { + DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", + __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); + goto exit; + } + + new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; + cur_framelen -= new_ip_hdr_len; + + ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); + + DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); + + /* is it an ack ? Allow only ACK flag, not to suppress others. */ + if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { + DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", + __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); + goto exit; + } + + new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); + new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); + + /* This packet has TCP data, so just send */ + if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { + DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); + goto exit; + } + + ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); + + new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); + + DHD_TRACE(("%s %d: TCP ACK with zero DATA length" + " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", + __FUNCTION__, __LINE__, + IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); + + /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ + dhd_os_tcpacklock(dhdp); + + tcpack_sup_mod = dhdp->tcpack_sup_module; + tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + hold = TRUE; + + for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { + void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ + uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; + uint32 old_ip_hdr_len, old_tcp_hdr_len; + uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ + + if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { + if (free_slot == TCPACK_INFO_MAXNUM) { + free_slot = i; + } + continue; + } + + if (PKTDATA(dhdp->osh, oldpkt) == NULL) { + DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d\n", + __FUNCTION__, __LINE__, i)); + hold = FALSE; + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; + old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; + old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); + old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; + old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); + + DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, + IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); + + /* If either of IP address or TCP port number does not match, skip. */ + if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], + &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || + memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], + &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) { + continue; + } + + old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); + + if (IS_TCPSEQ_GE(new_tcp_ack_num, old_tcpack_num)) { + tcpack_info_tbl[i].supp_cnt++; + if (tcpack_info_tbl[i].supp_cnt >= dhdp->tcpack_sup_ratio) { + tcpack_info_tbl[i].pkt_in_q = NULL; + tcpack_info_tbl[i].pkt_ether_hdr = NULL; + tcpack_info_tbl[i].ifidx = 0; + tcpack_info_tbl[i].supp_cnt = 0; + hold = FALSE; + } else { + tcpack_info_tbl[i].pkt_in_q = pkt; + tcpack_info_tbl[i].pkt_ether_hdr = new_ether_hdr; + tcpack_info_tbl[i].ifidx = ifidx; + } + PKTFREE(dhdp->osh, oldpkt, TRUE); + } else { + PKTFREE(dhdp->osh, pkt, TRUE); + } + dhd_os_tcpackunlock(dhdp); + + if (!hold) { + del_timer_sync(&tcpack_info_tbl[i].timer); + } + goto exit; + } + + if (free_slot < TCPACK_INFO_MAXNUM) { + /* No TCPACK packet with the same IP addr and TCP port is found + * in tcp_ack_info_tbl. So add this packet to the table. + */ + DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", + __FUNCTION__, __LINE__, pkt, new_ether_hdr, + free_slot)); + + tcpack_info_tbl[free_slot].pkt_in_q = pkt; + tcpack_info_tbl[free_slot].pkt_ether_hdr = new_ether_hdr; + tcpack_info_tbl[free_slot].ifidx = ifidx; + tcpack_info_tbl[free_slot].supp_cnt = 1; + mod_timer(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer, + jiffies + msecs_to_jiffies(dhdp->tcpack_sup_delay)); + tcpack_sup_mod->tcpack_info_cnt++; + } else { + DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", + __FUNCTION__, __LINE__)); + } + dhd_os_tcpackunlock(dhdp); + +exit: + return hold; +} +#endif /* DHDTCPACK_SUPPRESS */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.h new file mode 100644 index 000000000000..af715710f474 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.h @@ -0,0 +1,76 @@ +/* + * Header file describing the common ip parser function. + * + * Provides type definitions and function prototypes used to parse ip packet. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_ip.h 502735 2014-09-16 00:53:02Z $ + */ + +#ifndef _dhd_ip_h_ +#define _dhd_ip_h_ + +#ifdef DHDTCPACK_SUPPRESS +#include +#include +#include +#endif /* DHDTCPACK_SUPPRESS */ + +typedef enum pkt_frag +{ + DHD_PKT_FRAG_NONE = 0, + DHD_PKT_FRAG_FIRST, + DHD_PKT_FRAG_CONT, + DHD_PKT_FRAG_LAST +} pkt_frag_t; + +extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p); +extern bool pkt_is_dhcp(osl_t *osh, void *p); + +#ifdef DHDTCPACK_SUPPRESS +#define TCPACKSZMIN (ETHER_HDR_LEN + IPV4_MIN_HEADER_LEN + TCP_MIN_HEADER_LEN) +/* Size of MAX possible TCP ACK packet. Extra bytes for IP/TCP option fields */ +#define TCPACKSZMAX (TCPACKSZMIN + 100) + +/* Max number of TCP streams that have own src/dst IP addrs and TCP ports */ +#define TCPACK_INFO_MAXNUM 4 +#define TCPDATA_INFO_MAXNUM 4 +#define TCPDATA_PSH_INFO_MAXNUM (8 * TCPDATA_INFO_MAXNUM) + +#define TCPDATA_INFO_TIMEOUT 5000 /* Remove tcpdata_info if inactive for this time (in ms) */ + +#define TCPACK_SUPP_RATIO 3 +#define TCPACK_DELAY_TIME 10 /* ms */ + +extern int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 on); +extern void dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp); +extern int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt); +extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt); +extern bool dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt); +extern bool dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx); +/* #define DHDTCPACK_SUP_DBG */ +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) +extern counter_tbl_t tack_tbl; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ +#endif /* DHDTCPACK_SUPPRESS */ + +#endif /* _dhd_ip_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c new file mode 100644 index 000000000000..eeada222b3e5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c @@ -0,0 +1,10935 @@ +/* + * Broadcom Dongle Host Driver (DHD), Linux-specific network interface + * Basically selected code segments from usb-cdc.c and usb-rndis.c + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux.c 701287 2017-05-24 10:33:19Z $ + */ + +#include +#include +#include +#ifdef SHOW_LOGTRACE +#include +#include +#endif /* SHOW_LOGTRACE */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef ENABLE_ADAPTIVE_SCHED +#include +#endif /* ENABLE_ADAPTIVE_SCHED */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#ifdef DHD_L2_FILTER +#include +#endif +#include + +#include +#include +#include +#include +#ifdef PCIE_FULL_DONGLE +#include +#endif +#include +#include +#include +#ifdef CONFIG_HAS_WAKELOCK +#include +#endif +#ifdef WL_CFG80211 +#include +#endif +#ifdef PNO_SUPPORT +#include +#endif +#ifdef RTT_SUPPORT +#include +#endif + +#ifdef CONFIG_COMPAT +#include +#endif + +#ifdef DHD_WMF +#include +#endif /* DHD_WMF */ + +#ifdef AMPDU_VO_ENABLE +#include +#endif /* AMPDU_VO_ENABLE */ +#ifdef DHDTCPACK_SUPPRESS +#include +#endif /* DHDTCPACK_SUPPRESS */ + + +#ifdef WLMEDIA_HTSF +#include +#include + +#define HTSF_MINLEN 200 /* min. packet length to timestamp */ +#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ +#define TSMAX 1000 /* max no. of timing record kept */ +#define NUMBIN 34 + +static uint32 tsidx = 0; +static uint32 htsf_seqnum = 0; +uint32 tsfsync; +struct timeval tsync; +static uint32 tsport = 5010; + +typedef struct histo_ { + uint32 bin[NUMBIN]; +} histo_t; + +#if !ISPOWEROF2(DHD_SDALIGN) +#error DHD_SDALIGN is not a power of 2! +#endif + +static histo_t vi_d1, vi_d2, vi_d3, vi_d4; +#endif /* WLMEDIA_HTSF */ + + + +#if defined(SOFTAP) +extern bool ap_cfg_running; +extern bool ap_fw_loaded; +#endif + + +#ifdef ENABLE_ADAPTIVE_SCHED +#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */ +#ifndef CUSTOM_CPUFREQ_THRESH +#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH +#endif /* CUSTOM_CPUFREQ_THRESH */ +#endif /* ENABLE_ADAPTIVE_SCHED */ + +/* enable HOSTIP cache update from the host side when an eth0:N is up */ +#define AOE_IP_ALIAS_SUPPORT 1 + +#ifdef BCM_FD_AGGR +#include +#include +#endif +#ifdef PROP_TXSTATUS +#include +#include +#endif + +#include + +#include + +#ifdef SOMC_MIMO +#define SOMC_TXPWR_5G 0x20 +#define SOMC_TXPWR_OVERRIDE 0x80 +#endif + +/* Maximum STA per radio */ +#define DHD_MAX_STA 32 + + +const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; +const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; +#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] + +#ifdef ARP_OFFLOAD_SUPPORT +void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); +static int dhd_inetaddr_notifier_call(struct notifier_block *this, + unsigned long event, void *ptr); +static struct notifier_block dhd_inetaddr_notifier = { + .notifier_call = dhd_inetaddr_notifier_call +}; +/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be + * created in kernel notifier link list (with 'next' pointing to itself) + */ +static bool dhd_inetaddr_notifier_registered = FALSE; +#endif /* ARP_OFFLOAD_SUPPORT */ + +#ifdef CONFIG_IPV6 +static int dhd_inet6addr_notifier_call(struct notifier_block *this, + unsigned long event, void *ptr); +static struct notifier_block dhd_inet6addr_notifier = { + .notifier_call = dhd_inet6addr_notifier_call +}; +/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be + * created in kernel notifier link list (with 'next' pointing to itself) + */ +static bool dhd_inet6addr_notifier_registered = FALSE; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#include +volatile bool dhd_mmc_suspend = FALSE; +DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + +#if defined(OOB_INTR_ONLY) +extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +static void dhd_hang_process(void *dhd_info, void *event_data, u8 event); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +MODULE_LICENSE("GPL and additional rights"); +#endif /* LinuxVer */ + +#include + +#ifdef BCM_FD_AGGR +#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) +#else +#ifndef PROP_TXSTATUS +#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) +#else +#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) +#endif +#endif /* BCM_FD_AGGR */ + +#ifdef PROP_TXSTATUS +extern bool dhd_wlfc_skip_fc(void); +extern void dhd_wlfc_plat_init(void *dhd); +extern void dhd_wlfc_plat_deinit(void *dhd); +#endif /* PROP_TXSTATUS */ + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) +const char * +print_tainted() +{ + return ""; +} +#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ + +/* Linux wireless extension support */ +#if defined(WL_WIRELESS_EXT) +#include +extern wl_iw_extra_params_t g_wl_iw_params; +#endif /* defined(WL_WIRELESS_EXT) */ + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) +#include +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ + +extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); + +#ifdef PKT_FILTER_SUPPORT +extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); +extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); +extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id); +#endif + + +#ifdef READ_MACADDR +extern int dhd_read_macaddr(struct dhd_info *dhd); +#else +static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; } +#endif +#ifdef WRITE_MACADDR +extern int dhd_write_macaddr(struct ether_addr *mac); +#else +static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; } +#endif + + + + +#if defined(DHD_DEBUG) +static void dhd_mem_dump(void *dhd_info, void *event_info, u8 event); +#endif /* DHD_DEBUG */ + +static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused); +static struct notifier_block dhd_reboot_notifier = { + .notifier_call = dhd_reboot_callback, + .priority = 1, +}; + + +typedef struct dhd_if_event { + struct list_head list; + wl_event_data_if_t event; + char name[IFNAMSIZ+1]; + uint8 mac[ETHER_ADDR_LEN]; +} dhd_if_event_t; + +/* Interface control information */ +typedef struct dhd_if { + struct dhd_info *info; /* back pointer to dhd_info */ + /* OS/stack specifics */ + struct net_device *net; + int idx; /* iface idx in dongle */ + uint subunit; /* subunit */ + uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ + bool set_macaddress; + bool set_multicast; + uint8 bssidx; /* bsscfg index for the interface */ + bool attached; /* Delayed attachment when unset */ + bool txflowcontrol; /* Per interface flow control indicator */ + char name[IFNAMSIZ+1]; /* linux interface name */ + struct net_device_stats stats; +#ifdef DHD_WMF + dhd_wmf_t wmf; /* per bsscfg wmf setting */ +#endif /* DHD_WMF */ +#ifdef PCIE_FULL_DONGLE + struct list_head sta_list; /* sll of associated stations */ +#if !defined(BCM_GMAC3) + spinlock_t sta_list_lock; /* lock for manipulating sll */ +#endif /* ! BCM_GMAC3 */ +#endif /* PCIE_FULL_DONGLE */ + uint32 ap_isolate; /* ap-isolation settings */ +} dhd_if_t; + +#ifdef WLMEDIA_HTSF +typedef struct { + uint32 low; + uint32 high; +} tsf_t; + +typedef struct { + uint32 last_cycle; + uint32 last_sec; + uint32 last_tsf; + uint32 coef; /* scaling factor */ + uint32 coefdec1; /* first decimal */ + uint32 coefdec2; /* second decimal */ +} htsf_t; + +typedef struct { + uint32 t1; + uint32 t2; + uint32 t3; + uint32 t4; +} tstamp_t; + +static tstamp_t ts[TSMAX]; +static tstamp_t maxdelayts; +static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; + +#endif /* WLMEDIA_HTSF */ + +struct ipv6_work_info_t { + uint8 if_idx; + char ipv6_addr[16]; + unsigned long event; +}; + + +#if defined(DHD_DEBUG) +typedef struct dhd_dump { + uint8 *buf; + int bufsize; +} dhd_dump_t; +#endif /* DHD_DEBUG */ + +/* When Perimeter locks are deployed, any blocking calls must be preceeded + * with a PERIM UNLOCK and followed by a PERIM LOCK. + * Examples of blocking calls are: schedule_timeout(), down_interruptible(), + * wait_event_timeout(). + */ + +/* Local private structure (extension of pub) */ +typedef struct dhd_info { +#if defined(WL_WIRELESS_EXT) + wl_iw_t iw; /* wireless extensions state (must be first) */ +#endif /* defined(WL_WIRELESS_EXT) */ + dhd_pub_t pub; + dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */ + + void *adapter; /* adapter information, interrupt, fw path etc. */ + char fw_path[PATH_MAX]; /* path to firmware image */ + char nv_path[PATH_MAX]; /* path to nvram vars file */ + + struct semaphore proto_sem; +#ifdef PROP_TXSTATUS + spinlock_t wlfc_spinlock; + +#endif /* PROP_TXSTATUS */ +#ifdef WLMEDIA_HTSF + htsf_t htsf; +#endif + wait_queue_head_t ioctl_resp_wait; + wait_queue_head_t d3ack_wait; + uint32 default_wd_interval; + + struct timer_list timer; + bool wd_timer_valid; + struct tasklet_struct tasklet; + spinlock_t sdlock; + spinlock_t txqlock; + spinlock_t dhd_lock; + + struct semaphore sdsem; + tsk_ctl_t thr_dpc_ctl; + tsk_ctl_t thr_wdt_ctl; + + tsk_ctl_t thr_rxf_ctl; + spinlock_t rxf_lock; + bool rxthread_enabled; + + /* Wakelocks */ +#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + struct wake_lock wl_wifi; /* Wifi wakelock */ + struct wake_lock wl_rxwake; /* Wifi rx wakelock */ + struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */ + struct wake_lock wl_wdwake; /* Wifi wd wakelock */ + struct wake_lock wl_evtwake; /* Wifi event wakelock */ + struct wake_lock wl_txflwake; /* Wifi tx flow wakelock */ +#ifdef BCMPCIE_OOB_HOST_WAKE + struct wake_lock wl_intrwake; /* Host wakeup wakelock */ +#endif /* BCMPCIE_OOB_HOST_WAKE */ +#endif /* CONFIG_HAS_WAKELOCK && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + /* net_device interface lock, prevent race conditions among net_dev interface + * calls and wifi_on or wifi_off + */ + struct mutex dhd_net_if_mutex; + struct mutex dhd_suspend_mutex; +#endif + spinlock_t wakelock_spinlock; + spinlock_t wakelock_evt_spinlock; + uint32 wakelock_event_counter; + uint32 wakelock_counter; + int wakelock_wd_counter; + int wakelock_rx_timeout_enable; + int wakelock_ctrl_timeout_enable; + bool waive_wakelock; + uint32 wakelock_before_waive; + + /* Thread to issue ioctl for multicast */ + wait_queue_head_t ctrl_wait; + atomic_t pend_8021x_cnt; + dhd_attach_states_t dhd_state; +#ifdef SHOW_LOGTRACE + dhd_event_log_t event_data; +#endif /* SHOW_LOGTRACE */ + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ + +#ifdef ARP_OFFLOAD_SUPPORT + u32 pend_ipaddr; +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef BCM_FD_AGGR + void *rpc_th; + void *rpc_osh; + struct timer_list rpcth_timer; + bool rpcth_timer_active; + bool fdaggr; +#endif +#ifdef DHDTCPACK_SUPPRESS + spinlock_t tcpack_lock; +#endif /* DHDTCPACK_SUPPRESS */ + void *dhd_deferred_wq; +#ifdef DEBUG_CPU_FREQ + struct notifier_block freq_trans; + int __percpu *new_freq; +#endif + unsigned int unit; + struct notifier_block pm_notifier; +#if defined(BCMPCIE) && defined(CUSTOMER_HW5) + bool register_if_done; +#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ + struct kobject dhd_kobj; +} dhd_info_t; + +#define DHDIF_FWDER(dhdif) FALSE + +/* Flag to indicate if we should download firmware on driver load */ +uint dhd_download_fw_on_driverload = TRUE; + +/* Definitions to provide path to the firmware and nvram + * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" + */ +char firmware_path[MOD_PARAM_PATHLEN]; +char nvram_path[MOD_PARAM_PATHLEN]; + +/* backup buffer for firmware and nvram path */ +char fw_bak_path[MOD_PARAM_PATHLEN]; +char nv_bak_path[MOD_PARAM_PATHLEN]; + +/* information string to keep firmware, chio, cheip version info visiable from log */ +char info_string[MOD_PARAM_INFOLEN]; +module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); +#ifdef CONFIG_BCM_WLAN_RAMDUMP +char bcm_wlan_ver_info[BCM_WLAN_CRASH_REASON_LEN]; +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ +int op_mode = 0; +int disable_proptx = 0; +module_param(op_mode, int, 0644); +extern int wl_control_wl_start(struct net_device *dev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC) +struct semaphore dhd_registration_sem; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + +/* deferred handlers */ +static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event); +static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event); +static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event); +static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event); +#ifdef CONFIG_IPV6 +static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event); +#endif +#if defined(DHD_TRACE_WAKE_LOCK) +static void dhd_wk_lock_trace_init(struct dhd_info *dhd); +static void dhd_wk_lock_trace_deinit(struct dhd_info *dhd); +#endif /* DHD_TRACE_WAKE_LOCK */ + +/* Functions to manage sysfs interface for dhd */ +static int dhd_sysfs_init(dhd_info_t *dhd); +static void dhd_sysfs_exit(dhd_info_t *dhd); + +#ifdef WL_CFG80211 +extern void dhd_netdev_free(struct net_device *ndev); +#endif /* WL_CFG80211 */ + +/* Error bits */ +module_param(dhd_msg_level, int, 0); + +#ifdef ARP_OFFLOAD_SUPPORT +/* ARP offload enable */ +uint dhd_arp_enable = TRUE; +module_param(dhd_arp_enable, uint, 0); + +/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ + +uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; + +module_param(dhd_arp_mode, uint, 0); +#endif /* ARP_OFFLOAD_SUPPORT */ + +/* Disable Prop tx */ +module_param(disable_proptx, int, 0644); +/* load firmware and/or nvram values from the filesystem */ +module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); +module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660); + +/* Disable VHT(11ac) mode */ +#if !defined(DISABLE_11AC) +int somc_disable_vht = 0; +module_param(somc_disable_vht, int, 0660); +#endif /* ! DISABLE_11AC */ + +/* Watchdog interval */ + +/* extend watchdog expiration to 2 seconds when DPC is running */ +#define WATCHDOG_EXTEND_INTERVAL (2000) + +uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS; +module_param(dhd_watchdog_ms, uint, 0); + +#if defined(DHD_DEBUG) +/* Console poll interval */ +uint dhd_console_ms = 0; +module_param(dhd_console_ms, uint, 0644); +#endif /* defined(DHD_DEBUG) */ + + +uint dhd_slpauto = TRUE; +module_param(dhd_slpauto, uint, 0); + +#ifdef PKT_FILTER_SUPPORT +/* Global Pkt filter enable control */ +uint dhd_pkt_filter_enable = TRUE; +module_param(dhd_pkt_filter_enable, uint, 0); +#endif + +/* Pkt filter init setup */ +uint dhd_pkt_filter_init = 0; +module_param(dhd_pkt_filter_init, uint, 0); + +/* Pkt filter mode control */ +uint dhd_master_mode = TRUE; +module_param(dhd_master_mode, uint, 0); + +int dhd_watchdog_prio = 0; +module_param(dhd_watchdog_prio, int, 0); + +/* DPC thread priority */ +int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; +module_param(dhd_dpc_prio, int, 0); + +/* RX frame thread priority */ +int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; +module_param(dhd_rxf_prio, int, 0); + +int passive_channel_skip = 0; +module_param(passive_channel_skip, int, (S_IRUSR|S_IWUSR)); + +#if !defined(BCMDHDUSB) +extern int dhd_dongle_ramsize; +module_param(dhd_dongle_ramsize, int, 0); +#endif /* BCMDHDUSB */ + +/* Keep track of number of instances */ +static int dhd_found = 0; +static int instance_base = 0; /* Starting instance number */ +module_param(instance_base, int, 0644); + + + + +/* DHD Perimiter lock only used in router with bypass forwarding. */ +#define DHD_PERIM_RADIO_INIT() do { /* noop */ } while (0) +#define DHD_PERIM_LOCK_TRY(unit, flag) do { /* noop */ } while (0) +#define DHD_PERIM_UNLOCK_TRY(unit, flag) do { /* noop */ } while (0) +#define DHD_PERIM_LOCK_ALL() do { /* noop */ } while (0) +#define DHD_PERIM_UNLOCK_ALL() do { /* noop */ } while (0) + +#ifdef PCIE_FULL_DONGLE +#if defined(BCM_GMAC3) +#define DHD_IF_STA_LIST_LOCK_INIT(ifp) do { /* noop */ } while (0) +#define DHD_IF_STA_LIST_LOCK(ifp, flags) ({ BCM_REFERENCE(flags); }) +#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) ({ BCM_REFERENCE(flags); }) +#else /* ! BCM_GMAC3 */ +#define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock) +#define DHD_IF_STA_LIST_LOCK(ifp, flags) \ + spin_lock_irqsave(&(ifp)->sta_list_lock, (flags)) +#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \ + spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags)) +#endif /* ! BCM_GMAC3 */ +#endif /* PCIE_FULL_DONGLE */ + +/* Control fw roaming */ +#ifdef BCMCCX +uint dhd_roam_disable = 0; +#else +uint dhd_roam_disable = 0; +#endif /* BCMCCX */ + +/* Control radio state */ +uint dhd_radio_up = 1; + +/* Network inteface name */ +char iface_name[IFNAMSIZ] = {'\0'}; +module_param_string(iface_name, iface_name, IFNAMSIZ, 0); + +/* The following are specific to the SDIO dongle */ + +/* IOCTL response timeout */ +int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; + +/* Idle timeout for backplane clock */ +int dhd_idletime = DHD_IDLETIME_TICKS; +module_param(dhd_idletime, int, 0); + +/* Use polling */ +uint dhd_poll = FALSE; +module_param(dhd_poll, uint, 0); + +/* Use interrupts */ +uint dhd_intr = TRUE; +module_param(dhd_intr, uint, 0); + +/* SDIO Drive Strength (in milliamps) */ +uint dhd_sdiod_drive_strength = 6; +module_param(dhd_sdiod_drive_strength, uint, 0); + +#ifdef BCMSDIO +/* Tx/Rx bounds */ +extern uint dhd_txbound; +extern uint dhd_rxbound; +module_param(dhd_txbound, uint, 0); +module_param(dhd_rxbound, uint, 0); + +/* Deferred transmits */ +extern uint dhd_deferred_tx; +module_param(dhd_deferred_tx, uint, 0); + +#ifdef BCMDBGFS +extern void dhd_dbg_init(dhd_pub_t *dhdp); +extern void dhd_dbg_remove(void); +#endif /* BCMDBGFS */ + +#endif /* BCMSDIO */ + + +#ifdef SDTEST +/* Echo packet generator (pkts/s) */ +uint dhd_pktgen = 0; +module_param(dhd_pktgen, uint, 0); + +/* Echo packet len (0 => sawtooth, max 2040) */ +uint dhd_pktgen_len = 0; +module_param(dhd_pktgen_len, uint, 0); +#endif /* SDTEST */ + + +extern char dhd_version[]; + +int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); +static void dhd_net_if_lock_local(dhd_info_t *dhd); +static void dhd_net_if_unlock_local(dhd_info_t *dhd); +static void dhd_suspend_lock(dhd_pub_t *dhdp); +static void dhd_suspend_unlock(dhd_pub_t *dhdp); + +#ifdef WLMEDIA_HTSF +void htsf_update(dhd_info_t *dhd, void *data); +tsf_t prev_tsf, cur_tsf; + +uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); +static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); +static void dhd_dump_latency(void); +static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); +static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); +static void dhd_dump_htsfhisto(histo_t *his, char *s); +#endif /* WLMEDIA_HTSF */ + +/* Monitor interface */ +int dhd_monitor_init(void *dhd_pub); +int dhd_monitor_uninit(void); + + +#if defined(WL_WIRELESS_EXT) +struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); +#endif /* defined(WL_WIRELESS_EXT) */ + +static void dhd_dpc(ulong data); +/* forward decl */ +extern int dhd_wait_pend8021x(struct net_device *dev); +void dhd_os_wd_timer_extend(void *bus, bool extend); + +#ifdef TOE +#ifndef BDC +#error TOE requires BDC +#endif /* !BDC */ +static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); +static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); +#endif /* TOE */ + +static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, + wl_event_msg_t *event_ptr, void **data_ptr); +#ifdef DHD_UNICAST_DHCP +static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; +static int dhd_get_pkt_ip_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr, + int *len_ptr, uint8 *prot_ptr); +static int dhd_get_pkt_ether_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr, + int *len_ptr, uint16 *et_ptr, bool *snap_ptr); + +static int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx); +#endif /* DHD_UNICAST_DHCP */ +#ifdef DHD_L2_FILTER +static int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx); +#endif +#if defined(CONFIG_PM_SLEEP) +static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) +{ + int ret = NOTIFY_DONE; + bool suspend = FALSE; + dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier); + + BCM_REFERENCE(dhdinfo); + switch (action) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + suspend = TRUE; + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + suspend = FALSE; + break; + } + +#if defined(SUPPORT_P2P_GO_PS) +#ifdef PROP_TXSTATUS + if (suspend) { + DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub); + dhd_wlfc_suspend(&dhdinfo->pub); + DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub); + } else + dhd_wlfc_resume(&dhdinfo->pub); +#endif +#endif /* defined(SUPPORT_P2P_GO_PS) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(2, 6, 39)) + dhd_mmc_suspend = suspend; + smp_mb(); +#endif + + return ret; +} + +static struct notifier_block dhd_pm_notifier = { + .notifier_call = dhd_pm_callback, + .priority = 10 +}; +/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be + * created in kernel notifier link list (with 'next' pointing to itself) + */ +static bool dhd_pm_notifier_registered = FALSE; + +extern int register_pm_notifier(struct notifier_block *nb); +extern int unregister_pm_notifier(struct notifier_block *nb); +#endif /* CONFIG_PM_SLEEP */ + +/* Request scheduling of the bus rx frame */ +static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb); +static void dhd_os_rxflock(dhd_pub_t *pub); +static void dhd_os_rxfunlock(dhd_pub_t *pub); + +/** priv_link is the link between netdev and the dhdif and dhd_info structs. */ +typedef struct dhd_dev_priv { + dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */ + dhd_if_t * ifp; /* cached pointer to dhd_if in netdevice priv */ + int ifidx; /* interface index */ +} dhd_dev_priv_t; + +#define DHD_DEV_PRIV_SIZE (sizeof(dhd_dev_priv_t)) +#define DHD_DEV_PRIV(dev) ((dhd_dev_priv_t *)DEV_PRIV(dev)) +#define DHD_DEV_INFO(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd) +#define DHD_DEV_IFP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp) +#define DHD_DEV_IFIDX(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx) + +/** Clear the dhd net_device's private structure. */ +static inline void +dhd_dev_priv_clear(struct net_device * dev) +{ + dhd_dev_priv_t * dev_priv; + ASSERT(dev != (struct net_device *)NULL); + dev_priv = DHD_DEV_PRIV(dev); + dev_priv->dhd = (dhd_info_t *)NULL; + dev_priv->ifp = (dhd_if_t *)NULL; + dev_priv->ifidx = DHD_BAD_IF; +} + +/** Setup the dhd net_device's private structure. */ +static inline void +dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp, + int ifidx) +{ + dhd_dev_priv_t * dev_priv; + ASSERT(dev != (struct net_device *)NULL); + dev_priv = DHD_DEV_PRIV(dev); + dev_priv->dhd = dhd; + dev_priv->ifp = ifp; + dev_priv->ifidx = ifidx; +} + +#ifdef PCIE_FULL_DONGLE + +/** Dummy objects are defined with state representing bad|down. + * Performance gains from reducing branch conditionals, instruction parallelism, + * dual issue, reducing load shadows, avail of larger pipelines. + * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer + * is accessed via the dhd_sta_t. + */ + +/* Dummy dhd_info object */ +dhd_info_t dhd_info_null = { +#if defined(BCM_GMAC3) + .fwdh = FWDER_NULL, +#endif + .pub = { + .info = &dhd_info_null, +#ifdef DHDTCPACK_SUPPRESS + .tcpack_sup_mode = TCPACK_SUP_REPLACE, +#endif /* DHDTCPACK_SUPPRESS */ + .up = FALSE, .busstate = DHD_BUS_DOWN + } +}; +#define DHD_INFO_NULL (&dhd_info_null) +#define DHD_PUB_NULL (&dhd_info_null.pub) + +/* Dummy netdevice object */ +struct net_device dhd_net_dev_null = { + .reg_state = NETREG_UNREGISTERED +}; +#define DHD_NET_DEV_NULL (&dhd_net_dev_null) + +/* Dummy dhd_if object */ +dhd_if_t dhd_if_null = { +#if defined(BCM_GMAC3) + .fwdh = FWDER_NULL, +#endif +#ifdef WMF + .wmf = { .wmf_enable = TRUE }, +#endif + .info = DHD_INFO_NULL, + .net = DHD_NET_DEV_NULL, + .idx = DHD_BAD_IF +}; +#define DHD_IF_NULL (&dhd_if_null) + +#define DHD_STA_NULL ((dhd_sta_t *)NULL) + +/** Interface STA list management. */ + +/** Fetch the dhd_if object, given the interface index in the dhd. */ +static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx); + +/** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */ +static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta); +static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp); + +/* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */ +static void dhd_if_del_sta_list(dhd_if_t * ifp); +static void dhd_if_flush_sta(dhd_if_t * ifp); + +/* Construct/Destruct a sta pool. */ +static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta); +static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta); +static void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta); + + +/* Return interface pointer */ +static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx) +{ + ASSERT(ifidx < DHD_MAX_IFS); + + if (ifidx >= DHD_MAX_IFS) + return NULL; + + return dhdp->info->iflist[ifidx]; +} + +/** Reset a dhd_sta object and free into the dhd pool. */ +static void +dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta) +{ + int prio; + + ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID)); + + ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL)); + id16_map_free(dhdp->staid_allocator, sta->idx); + for (prio = 0; prio < (int)NUMPRIO; prio++) + sta->flowid[prio] = FLOWID_INVALID; + sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */ + sta->ifidx = DHD_BAD_IF; + bzero(sta->ea.octet, ETHER_ADDR_LEN); + INIT_LIST_HEAD(&sta->list); + sta->idx = ID16_INVALID; /* implying free */ +} + +/** Allocate a dhd_sta object from the dhd pool. */ +static dhd_sta_t * +dhd_sta_alloc(dhd_pub_t * dhdp) +{ + uint16 idx; + dhd_sta_t * sta; + dhd_sta_pool_t * sta_pool; + + ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL)); + + idx = id16_map_alloc(dhdp->staid_allocator); + if (idx == ID16_INVALID) { + DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__)); + return DHD_STA_NULL; + } + + sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool); + sta = &sta_pool[idx]; + + ASSERT((sta->idx == ID16_INVALID) && + (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF)); + sta->idx = idx; /* implying allocated */ + + return sta; +} + +/** Delete all STAs in an interface's STA list. */ +static void +dhd_if_del_sta_list(dhd_if_t *ifp) +{ + dhd_sta_t *sta, *next; + unsigned long flags; + + DHD_IF_STA_LIST_LOCK(ifp, flags); + + list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { +#if defined(BCM_GMAC3) + if (ifp->fwdh) { + /* Remove sta from WOFA forwarder. */ + fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (wofa_t)sta); + } +#endif /* BCM_GMAC3 */ + list_del(&sta->list); + dhd_sta_free(&ifp->info->pub, sta); + } + + DHD_IF_STA_LIST_UNLOCK(ifp, flags); + + return; +} + +/** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */ +static void +dhd_if_flush_sta(dhd_if_t * ifp) +{ +#if defined(BCM_GMAC3) + + if (ifp && (ifp->fwdh != FWDER_NULL)) { + dhd_sta_t *sta, *next; + unsigned long flags; + + DHD_IF_STA_LIST_LOCK(ifp, flags); + + list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { + /* Remove any sta entry from WOFA forwarder. */ + fwder_flush(ifp->fwdh, (wofa_t)sta); + } + + DHD_IF_STA_LIST_UNLOCK(ifp, flags); + } +#endif /* BCM_GMAC3 */ +} + +/** Construct a pool of dhd_sta_t objects to be used by interfaces. */ +static int +dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) +{ + int idx, sta_pool_memsz; + dhd_sta_t * sta; + dhd_sta_pool_t * sta_pool; + void * staid_allocator; + + ASSERT(dhdp != (dhd_pub_t *)NULL); + ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL)); + + /* dhd_sta objects per radio are managed in a table. id#0 reserved. */ + staid_allocator = id16_map_init(dhdp->osh, max_sta, 1); + if (staid_allocator == NULL) { + DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__)); + return BCME_ERROR; + } + + /* Pre allocate a pool of dhd_sta objects (one extra). */ + sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */ + sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz); + if (sta_pool == NULL) { + DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__)); + id16_map_fini(dhdp->osh, staid_allocator); + return BCME_ERROR; + } + + dhdp->sta_pool = sta_pool; + dhdp->staid_allocator = staid_allocator; + + /* Initialize all sta(s) for the pre-allocated free pool. */ + bzero((uchar *)sta_pool, sta_pool_memsz); + for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */ + sta = &sta_pool[idx]; + sta->idx = id16_map_alloc(staid_allocator); + ASSERT(sta->idx <= max_sta); + } + /* Now place them into the pre-allocated free pool. */ + for (idx = 1; idx <= max_sta; idx++) { + sta = &sta_pool[idx]; + dhd_sta_free(dhdp, sta); + } + + return BCME_OK; +} + +/** Destruct the pool of dhd_sta_t objects. + * Caller must ensure that no STA objects are currently associated with an if. + */ +static void +dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) +{ + dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool; + + if (sta_pool) { + int idx; + int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); + for (idx = 1; idx <= max_sta; idx++) { + ASSERT(sta_pool[idx].ifp == DHD_IF_NULL); + ASSERT(sta_pool[idx].idx == ID16_INVALID); + } + MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz); + dhdp->sta_pool = NULL; + } + + id16_map_fini(dhdp->osh, dhdp->staid_allocator); + dhdp->staid_allocator = NULL; +} + +/* Clear the pool of dhd_sta_t objects for built-in type driver */ +static void +dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) +{ + int idx, sta_pool_memsz; + dhd_sta_t * sta; + dhd_sta_pool_t * sta_pool; + void *staid_allocator; + + if (!dhdp) { + DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); + return; + } + + sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool; + staid_allocator = dhdp->staid_allocator; + + if (!sta_pool) { + DHD_ERROR(("%s: sta_pool is NULL\n", __FUNCTION__)); + return; + } + + if (!staid_allocator) { + DHD_ERROR(("%s: staid_allocator is NULL\n", __FUNCTION__)); + return; + } + + /* clear free pool */ + sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); + bzero((uchar *)sta_pool, sta_pool_memsz); + + /* dhd_sta objects per radio are managed in a table. id#0 reserved. */ + id16_map_clear(staid_allocator, max_sta, 1); + + /* Initialize all sta(s) for the pre-allocated free pool. */ + for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */ + sta = &sta_pool[idx]; + sta->idx = id16_map_alloc(staid_allocator); + ASSERT(sta->idx <= max_sta); + } + /* Now place them into the pre-allocated free pool. */ + for (idx = 1; idx <= max_sta; idx++) { + sta = &sta_pool[idx]; + dhd_sta_free(dhdp, sta); + } +} + +/** Find STA with MAC address ea in an interface's STA list. */ +dhd_sta_t * +dhd_find_sta(void *pub, int ifidx, void *ea) +{ + dhd_sta_t *sta, *next; + dhd_if_t *ifp; + unsigned long flags; + + ASSERT(ea != NULL); + ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); + if (ifp == NULL) + return DHD_STA_NULL; + + DHD_IF_STA_LIST_LOCK(ifp, flags); + + list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { + if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { + DHD_IF_STA_LIST_UNLOCK(ifp, flags); + return sta; + } + } + + DHD_IF_STA_LIST_UNLOCK(ifp, flags); + + return DHD_STA_NULL; +} + +/** Add STA into the interface's STA list. */ +dhd_sta_t * +dhd_add_sta(void *pub, int ifidx, void *ea) +{ + dhd_sta_t *sta; + dhd_if_t *ifp; + unsigned long flags; + + ASSERT(ea != NULL); + ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); + if (ifp == NULL) + return DHD_STA_NULL; + + sta = dhd_sta_alloc((dhd_pub_t *)pub); + if (sta == DHD_STA_NULL) { + DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__)); + return DHD_STA_NULL; + } + + memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN); + + /* link the sta and the dhd interface */ + sta->ifp = ifp; + sta->ifidx = ifidx; + INIT_LIST_HEAD(&sta->list); + + DHD_IF_STA_LIST_LOCK(ifp, flags); + + list_add_tail(&sta->list, &ifp->sta_list); + +#if defined(BCM_GMAC3) + if (ifp->fwdh) { + ASSERT(ISALIGNED(ea, 2)); + /* Add sta to WOFA forwarder. */ + fwder_reassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta); + } +#endif /* BCM_GMAC3 */ + + DHD_IF_STA_LIST_UNLOCK(ifp, flags); + + return sta; +} + +/** Delete STA from the interface's STA list. */ +void +dhd_del_sta(void *pub, int ifidx, void *ea) +{ + dhd_sta_t *sta, *next; + dhd_if_t *ifp; + unsigned long flags; + + ASSERT(ea != NULL); + ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); + if (ifp == NULL) + return; + + DHD_IF_STA_LIST_LOCK(ifp, flags); + + list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { + if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { +#if defined(BCM_GMAC3) + if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */ + ASSERT(ISALIGNED(ea, 2)); + fwder_deassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta); + } +#endif /* BCM_GMAC3 */ + list_del(&sta->list); + dhd_sta_free(&ifp->info->pub, sta); + } + } + + DHD_IF_STA_LIST_UNLOCK(ifp, flags); + + return; +} + +/** Add STA if it doesn't exist. Not reentrant. */ +dhd_sta_t* +dhd_findadd_sta(void *pub, int ifidx, void *ea) +{ + dhd_sta_t *sta; + + sta = dhd_find_sta(pub, ifidx, ea); + + if (!sta) { + /* Add entry */ + sta = dhd_add_sta(pub, ifidx, ea); + } + + return sta; +} +#else +static inline void dhd_if_flush_sta(dhd_if_t * ifp) { } +static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {} +static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; } +static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {} +static inline void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) {} +dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; } +void dhd_del_sta(void *pub, int ifidx, void *ea) {} +#endif /* PCIE_FULL_DONGLE */ + + +/* Returns dhd iflist index correspondig the the bssidx provided by apps */ +int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx) +{ + dhd_if_t *ifp; + dhd_info_t *dhd = dhdp->info; + int i; + + ASSERT(bssidx < DHD_MAX_IFS); + ASSERT(dhdp); + + for (i = 0; i < DHD_MAX_IFS; i++) { + ifp = dhd->iflist[i]; + if (ifp && (ifp->bssidx == bssidx)) { + DHD_TRACE(("Index manipulated for %s from %d to %d\n", + ifp->name, bssidx, i)); + break; + } + } + return i; +} + +static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb) +{ + uint32 store_idx; + uint32 sent_idx; + + if (!skb) { + DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n")); + return BCME_ERROR; + } + + dhd_os_rxflock(dhdp); + store_idx = dhdp->store_idx; + sent_idx = dhdp->sent_idx; + if (dhdp->skbbuf[store_idx] != NULL) { + /* Make sure the previous packets are processed */ + dhd_os_rxfunlock(dhdp); + DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", + skb, store_idx, sent_idx)); + /* removed msleep here, should use wait_event_timeout if we + * want to give rx frame thread a chance to run + */ +#if defined(WAIT_DEQUEUE) + OSL_SLEEP(1); +#endif + return BCME_ERROR; + } + DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n", + skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1))); + dhdp->skbbuf[store_idx] = skb; + dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1); + dhd_os_rxfunlock(dhdp); + + return BCME_OK; +} + +static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp) +{ + uint32 store_idx; + uint32 sent_idx; + void *skb; + + dhd_os_rxflock(dhdp); + + store_idx = dhdp->store_idx; + sent_idx = dhdp->sent_idx; + skb = dhdp->skbbuf[sent_idx]; + + if (skb == NULL) { + dhd_os_rxfunlock(dhdp); + DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n", + store_idx, sent_idx)); + return NULL; + } + + dhdp->skbbuf[sent_idx] = NULL; + dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1); + + DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n", + skb, sent_idx)); + + dhd_os_rxfunlock(dhdp); + + return skb; +} + +int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + if (prepost) { /* pre process */ + dhd_read_macaddr(dhd); + } else { /* post process */ + dhd_write_macaddr(&dhd->pub.mac); + } + + return 0; +} + +#if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) +static bool +_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode) +{ + bool _apply = FALSE; + /* In case of IBSS mode, apply arp pkt filter */ + if (op_mode & DHD_FLAG_IBSS_MODE) { + _apply = TRUE; + goto exit; + } + /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */ + if ((dhd->arp_version == 1) && + (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { + _apply = TRUE; + goto exit; + } + +exit: + return _apply; +} +#endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */ + + +void dhd_set_packet_filter(dhd_pub_t *dhd) +{ +#ifdef PKT_FILTER_SUPPORT + int i; + + DHD_TRACE(("%s: enter\n", __FUNCTION__)); + if (dhd_pkt_filter_enable) { + for (i = 0; i < dhd->pktfilter_count; i++) { + dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); + } + } +#endif /* PKT_FILTER_SUPPORT */ +} + +void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) +{ +#ifdef PKT_FILTER_SUPPORT + int i; + + DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value)); + + + /* 1 - Enable packet filter, only allow unicast packet to send up */ + /* 0 - Disable packet filter */ + if (dhd_pkt_filter_enable && (!value || + (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) + { + for (i = 0; i < dhd->pktfilter_count; i++) { +#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER + if (value && (i == DHD_ARP_FILTER_NUM) && + !_turn_on_arp_filter(dhd, dhd->op_mode)) { + DHD_TRACE(("Do not turn on ARP white list pkt filter:" + "val %d, cnt %d, op_mode 0x%x\n", + value, i, dhd->op_mode)); + continue; + } +#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ + dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], + value, dhd_master_mode); + } + } +#endif /* PKT_FILTER_SUPPORT */ +} + +static int dhd_set_suspend(int value, dhd_pub_t *dhd) +{ +#ifndef SUPPORT_PM2_ONLY + int power_mode = PM_MAX; +#endif /* SUPPORT_PM2_ONLY */ + /* wl_pkt_filter_enable_t enable_parm; */ + int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ +#ifndef ENABLE_FW_ROAM_SUSPEND + uint roamvar = 1; +#endif /* ENABLE_FW_ROAM_SUSPEND */ + uint nd_ra_filter = 0; + int ret = 0; + + if (!dhd) + return -ENODEV; + + + DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", + __FUNCTION__, value, dhd->in_suspend)); + + dhd_suspend_lock(dhd); + +#ifdef CUSTOM_SET_CPUCORE + DHD_TRACE(("%s set cpucore(suspend%d)\n", __FUNCTION__, value)); + /* set specific cpucore */ + dhd_set_cpucore(dhd, TRUE); +#endif /* CUSTOM_SET_CPUCORE */ + if (dhd->up) { + if (value && dhd->in_suspend) { +#ifdef PKT_FILTER_SUPPORT + dhd->early_suspended = 1; +#endif + /* Kernel suspended */ + DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); + +#ifndef SUPPORT_PM2_ONLY + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); +#endif /* SUPPORT_PM2_ONLY */ + + /* Enable packet filter, only allow unicast packet to send up */ + dhd_enable_packet_filter(1, dhd); + + + /* If DTIM skip is set up as default, force it to wake + * each third DTIM for better power savings. Note that + * one side effect is a chance to miss BC/MC packet. + */ + bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); + if (dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, + sizeof(bcn_li_dtim), NULL, 0, TRUE) < 0) + DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); + +#ifndef ENABLE_FW_ROAM_SUSPEND + /* Disable firmware roaming during suspend */ + dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), + NULL, 0, TRUE); +#endif /* ENABLE_FW_ROAM_SUSPEND */ + if (FW_SUPPORTED(dhd, ndoe)) { + /* enable IPv6 RA filter in firmware during suspend */ + nd_ra_filter = 1; + ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", + (char *)&nd_ra_filter, sizeof(nd_ra_filter), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("failed to set nd_ra_filter (%d)\n", + ret)); + } + } else { +#ifdef PKT_FILTER_SUPPORT + dhd->early_suspended = 0; +#endif + /* Kernel resumed */ + DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__)); + +#ifndef SUPPORT_PM2_ONLY + power_mode = PM_FAST; + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); +#endif /* SUPPORT_PM2_ONLY */ +#ifdef PKT_FILTER_SUPPORT + /* disable pkt filter */ + dhd_enable_packet_filter(0, dhd); +#endif /* PKT_FILTER_SUPPORT */ + + /* restore pre-suspend setting for dtim_skip */ + dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, + sizeof(bcn_li_dtim), NULL, 0, TRUE); +#ifndef ENABLE_FW_ROAM_SUSPEND + roamvar = dhd_roam_disable; + dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), + NULL, 0, TRUE); +#endif /* ENABLE_FW_ROAM_SUSPEND */ + if (FW_SUPPORTED(dhd, ndoe)) { + /* disable IPv6 RA filter in firmware during suspend */ + nd_ra_filter = 0; + ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", + (char *)&nd_ra_filter, sizeof(nd_ra_filter), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("nd_ra_filter: %d\n", ret)); + } + } + } + dhd_suspend_unlock(dhd); + + return 0; +} + +static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) +{ + dhd_pub_t *dhdp = &dhd->pub; + int ret = 0; + + DHD_OS_WAKE_LOCK(dhdp); + DHD_PERIM_LOCK(dhdp); + + /* Set flag when early suspend was called */ + dhdp->in_suspend = val; + if ((force || !dhdp->suspend_disable_flag) && + dhd_support_sta_mode(dhdp)) + { + ret = dhd_set_suspend(val, dhdp); + } + + DHD_PERIM_UNLOCK(dhdp); + DHD_OS_WAKE_UNLOCK(dhdp); + return ret; +} + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) +static void dhd_early_suspend(struct early_suspend *h) +{ + struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); + DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); + + if (dhd) + dhd_suspend_resume_helper(dhd, 1, 0); +} + +static void dhd_late_resume(struct early_suspend *h) +{ + struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); + DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); + + if (dhd) + dhd_suspend_resume_helper(dhd, 0, 0); +} +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ + +/* + * Generalized timeout mechanism. Uses spin sleep with exponential back-off until + * the sleep time reaches one jiffy, then switches over to task delay. Usage: + * + * dhd_timeout_start(&tmo, usec); + * while (!dhd_timeout_expired(&tmo)) + * if (poll_something()) + * break; + * if (dhd_timeout_expired(&tmo)) + * fatal(); + */ + +void +dhd_timeout_start(dhd_timeout_t *tmo, uint usec) +{ + tmo->limit = usec; + tmo->increment = 0; + tmo->elapsed = 0; + tmo->tick = jiffies_to_usecs(1); +} + +int +dhd_timeout_expired(dhd_timeout_t *tmo) +{ + /* Does nothing the first call */ + if (tmo->increment == 0) { + tmo->increment = 1; + return 0; + } + + if (tmo->elapsed >= tmo->limit) + return 1; + + /* Add the delay that's about to take place */ + tmo->elapsed += tmo->increment; + + if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) { + OSL_DELAY(tmo->increment); + tmo->increment *= 2; + if (tmo->increment > tmo->tick) + tmo->increment = tmo->tick; + } else { + wait_queue_head_t delay_wait; + DECLARE_WAITQUEUE(wait, current); + init_waitqueue_head(&delay_wait); + add_wait_queue(&delay_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + (void)schedule_timeout(1); + remove_wait_queue(&delay_wait, &wait); + set_current_state(TASK_RUNNING); + } + + return 0; +} + +int +dhd_net2idx(dhd_info_t *dhd, struct net_device *net) +{ + int i = 0; + + if (!dhd) { + DHD_ERROR(("%s : DHD_BAD_IF return\n", __FUNCTION__)); + return DHD_BAD_IF; + } + while (i < DHD_MAX_IFS) { + if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net)) + return i; + i++; + } + + return DHD_BAD_IF; +} + +struct net_device * dhd_idx2net(void *pub, int ifidx) +{ + struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; + struct dhd_info *dhd_info; + + if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) + return NULL; + dhd_info = dhd_pub->info; + if (dhd_info && dhd_info->iflist[ifidx]) + return dhd_info->iflist[ifidx]->net; + return NULL; +} + +int +dhd_ifname2idx(dhd_info_t *dhd, char *name) +{ + int i = DHD_MAX_IFS; + + ASSERT(dhd); + + if (name == NULL || *name == '\0') + return 0; + + while (--i > 0) + if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ)) + break; + + DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name)); + + return i; /* default - the primary interface */ +} + +int +dhd_ifidx2hostidx(dhd_info_t *dhd, int ifidx) +{ + int i = DHD_MAX_IFS; + + ASSERT(dhd); + + while (--i > 0) + if (dhd->iflist[i] && (dhd->iflist[i]->idx == ifidx)) + break; + + DHD_TRACE(("%s: return hostidx %d for ifidx %d\n", __FUNCTION__, i, ifidx)); + + return i; /* default - the primary interface */ +} + +char * +dhd_ifname(dhd_pub_t *dhdp, int ifidx) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + ASSERT(dhd); + + if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { + DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); + return ""; + } + + if (dhd->iflist[ifidx] == NULL) { + DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); + return ""; + } + + if (dhd->iflist[ifidx]->net) + return dhd->iflist[ifidx]->net->name; + + return ""; +} + +uint8 * +dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) +{ + int i; + dhd_info_t *dhd = (dhd_info_t *)dhdp; + + ASSERT(dhd); + for (i = 0; i < DHD_MAX_IFS; i++) + if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) + return dhd->iflist[i]->mac_addr; + + return NULL; +} + + +static void +_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) +{ + struct net_device *dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + struct netdev_hw_addr *ha; +#else + struct dev_mc_list *mclist; +#endif + uint32 allmulti, cnt; + + wl_ioctl_t ioc; + char *buf, *bufp; + uint buflen; + int ret; + +#ifdef MCAST_LIST_ACCUMULATION + int i; + uint32 cnt_iface[DHD_MAX_IFS]; + cnt = 0; + allmulti = 0; + + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + dev = dhd->iflist[i]->net; + if (!dev) + continue; +#else + ASSERT(dhd && dhd->iflist[ifidx]); + dev = dhd->iflist[ifidx]->net; + if (!dev) + return; +#endif /* MCAST_LIST_ACCUMULATION */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_lock_bh(dev); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) +#ifdef MCAST_LIST_ACCUMULATION + cnt_iface[i] = netdev_mc_count(dev); + cnt += cnt_iface[i]; +#else + cnt = netdev_mc_count(dev); +#endif /* MCAST_LIST_ACCUMULATION */ +#else +#ifdef MCAST_LIST_ACCUMULATION + cnt += dev->mc_count; +#else + cnt = dev->mc_count; +#endif /* MCAST_LIST_ACCUMULATION */ +#endif /* LINUX_VERSION_CODE */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_unlock_bh(dev); +#endif + + /* Determine initial value of allmulti flag */ +#ifdef MCAST_LIST_ACCUMULATION + allmulti |= (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; + } + } +#else + allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; +#endif /* MCAST_LIST_ACCUMULATION */ + + /* Send down the multicast list first. */ + + + buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); + if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { + DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", + dhd_ifname(&dhd->pub, ifidx), cnt)); + return; + } + + strncpy(bufp, "mcast_list", buflen - 1); + bufp[buflen - 1] = '\0'; + bufp += strlen("mcast_list") + 1; + + cnt = htol32(cnt); + memcpy(bufp, &cnt, sizeof(cnt)); + bufp += sizeof(cnt); + +#ifdef MCAST_LIST_ACCUMULATION + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + DHD_TRACE(("_dhd_set_multicast_list: ifidx %d\n", i)); + dev = dhd->iflist[i]->net; +#endif /* MCAST_LIST_ACCUMULATION */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_lock_bh(dev); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + netdev_for_each_mc_addr(ha, dev) { +#ifdef MCAST_LIST_ACCUMULATION + if (!cnt_iface[i]) +#else + if (!cnt) +#endif /* MCAST_LIST_ACCUMULATION */ + break; + memcpy(bufp, ha->addr, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; +#ifdef MCAST_LIST_ACCUMULATION + DHD_TRACE(("_dhd_set_multicast_list: cnt " + "%d " MACDBG "\n", + cnt_iface[i], MAC2STRDBG(ha->addr))); + cnt_iface[i]--; +#else + cnt--; +#endif /* MCAST_LIST_ACCUMULATION */ + } +#else +#ifdef MCAST_LIST_ACCUMULATION + for (mclist = dev->mc_list; (mclist && (cnt_iface[i] > 0)); + cnt_iface[i]--, mclist = mclist->next) { +#else + for (mclist = dev->mc_list; (mclist && (cnt > 0)); + cnt--, mclist = mclist->next) { +#endif /* MCAST_LIST_ACCUMULATION */ + memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; + } +#endif /* LINUX_VERSION_CODE */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_unlock_bh(dev); +#endif +#ifdef MCAST_LIST_ACCUMULATION + } + } +#endif /* MCAST_LIST_ACCUMULATION */ + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = WLC_SET_VAR; + ioc.buf = buf; + ioc.len = buflen; + ioc.set = TRUE; + + ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + if (ret < 0) { + DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", + dhd_ifname(&dhd->pub, ifidx), cnt)); + allmulti = cnt ? TRUE : allmulti; + } + + MFREE(dhd->pub.osh, buf, buflen); + + /* 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... + */ + + allmulti = htol32(allmulti); + ret = dhd_iovar(&dhd->pub, ifidx, "allmulti", (char *)&allmulti, + sizeof(allmulti), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: set allmulti %d failed\n", + dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); + } + + /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ + +#ifdef MCAST_LIST_ACCUMULATION + allmulti = 0; + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + dev = dhd->iflist[i]->net; + allmulti |= (dev->flags & IFF_PROMISC) ? TRUE : FALSE; + } + } +#else + allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; +#endif /* MCAST_LIST_ACCUMULATION */ + + allmulti = htol32(allmulti); + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = WLC_SET_PROMISC; + ioc.buf = &allmulti; + ioc.len = sizeof(allmulti); + ioc.set = TRUE; + + ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + if (ret < 0) { + DHD_ERROR(("%s: set promisc %d failed\n", + dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); + } +} + +int +_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr) +{ + int ret; + + ret = dhd_iovar(&dhd->pub, ifidx, "cur_etheraddr", (char *)addr, + ETHER_ADDR_LEN, NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); + } else { + memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); + if (ifidx == 0) + memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); + } + + return ret; +} + +#ifdef SOFTAP +extern struct net_device *ap_net_dev; +extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ +#endif + +static void +dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + dhd_if_event_t *if_event = event_info; + struct net_device *ndev; + int ifidx, bssidx; + int ret; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + struct wireless_dev *vwdev, *primary_wdev; + struct net_device *primary_ndev; +#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ + + if (event != DHD_WQ_WORK_IF_ADD) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return; + } + + if (!if_event) { + DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); + return; + } + + dhd_net_if_lock_local(dhd); + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_PERIM_LOCK(&dhd->pub); + + ifidx = if_event->event.ifidx; + bssidx = if_event->event.bssidx; + DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx)); + + ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name, + if_event->mac, bssidx, TRUE); + if (!ndev) { + DHD_ERROR(("%s: net device alloc failed \n", __FUNCTION__)); + goto done; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); + if (unlikely(!vwdev)) { + WL_ERR(("Could not allocate wireless device\n")); + goto done; + } + primary_ndev = dhd->pub.info->iflist[0]->net; + primary_wdev = ndev_to_wdev(primary_ndev); + vwdev->wiphy = primary_wdev->wiphy; + vwdev->iftype = if_event->event.role; + vwdev->netdev = ndev; + ndev->ieee80211_ptr = vwdev; + SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy)); + DHD_ERROR(("virtual interface(%s) is created\n", if_event->name)); +#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ + + DHD_PERIM_UNLOCK(&dhd->pub); + ret = dhd_register_if(&dhd->pub, ifidx, TRUE); + DHD_PERIM_LOCK(&dhd->pub); + if (ret != BCME_OK) { + DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__)); + dhd_remove_if(&dhd->pub, ifidx, TRUE); + goto done; + } +#ifndef PCIE_FULL_DONGLE + /* Turn on AP isolation in the firmware for interfaces operating in AP mode */ + if (FW_SUPPORTED((&dhd->pub), ap) && !(DHD_IF_ROLE_STA(if_event->event.role))) { + uint32 var_int = 1; + + ret = dhd_iovar(&dhd->pub, ifidx, "ap_isolate", (char *)&var_int, sizeof(var_int), + NULL, 0, TRUE); + + if (ret != BCME_OK) { + DHD_ERROR(("%s: Failed to set ap_isolate to dongle\n", __FUNCTION__)); + dhd_remove_if(&dhd->pub, ifidx, TRUE); + } + } +#endif /* PCIE_FULL_DONGLE */ +done: + MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); + + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_net_if_unlock_local(dhd); +} + +static void +dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + int ifidx; + dhd_if_event_t *if_event = event_info; + + + if (event != DHD_WQ_WORK_IF_DEL) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return; + } + + if (!if_event) { + DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); + return; + } + + dhd_net_if_lock_local(dhd); + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_PERIM_LOCK(&dhd->pub); + + ifidx = if_event->event.ifidx; + DHD_TRACE(("Removing interface with idx %d\n", ifidx)); + + dhd_remove_if(&dhd->pub, ifidx, TRUE); + + MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); + + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_net_if_unlock_local(dhd); +} + +static void +dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + dhd_if_t *ifp = event_info; + + if (event != DHD_WQ_WORK_SET_MAC) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + } + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return; + } + + dhd_net_if_lock_local(dhd); + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_PERIM_LOCK(&dhd->pub); + +#ifdef SOFTAP + { + unsigned long flags; + bool in_ap = FALSE; + DHD_GENERAL_LOCK(&dhd->pub, flags); + in_ap = (ap_net_dev != NULL); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + + if (in_ap) { + DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n", + ifp->net->name)); + goto done; + } + } +#endif /* SOFTAP */ + + if (ifp == NULL || !dhd->pub.up) { + DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); + goto done; + } + + DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__)); + ifp->set_macaddress = FALSE; + if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0) + DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); + else + DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); + +done: + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_net_if_unlock_local(dhd); +} + +static void +dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + dhd_if_t *ifp = event_info; + int ifidx; + + if (event != DHD_WQ_WORK_SET_MCAST_LIST) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return; + } + + dhd_net_if_lock_local(dhd); + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_PERIM_LOCK(&dhd->pub); + +#ifdef SOFTAP + { + bool in_ap = FALSE; + unsigned long flags; + DHD_GENERAL_LOCK(&dhd->pub, flags); + in_ap = (ap_net_dev != NULL); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + + if (in_ap) { + DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n", + ifp->net->name)); + ifp->set_multicast = FALSE; + goto done; + } + } +#endif /* SOFTAP */ + + if (ifp == NULL || !dhd->pub.up) { + DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); + goto done; + } + + ifidx = ifp->idx; + +#ifdef MCAST_LIST_ACCUMULATION + ifidx = 0; +#endif /* MCAST_LIST_ACCUMULATION */ + + _dhd_set_multicast_list(dhd, ifidx); + DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx)); + +done: + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_net_if_unlock_local(dhd); +} + +static int +dhd_set_mac_address(struct net_device *dev, void *addr) +{ + int ret = 0; + + dhd_info_t *dhd = DHD_DEV_INFO(dev); + struct sockaddr *sa = (struct sockaddr *)addr; + int ifidx; + dhd_if_t *dhdif; + + ifidx = dhd_net2idx(dhd, dev); + if (ifidx == DHD_BAD_IF) + return -1; + + dhdif = dhd->iflist[ifidx]; + + dhd_net_if_lock_local(dhd); + memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN); + dhdif->set_macaddress = TRUE; + dhd_net_if_unlock_local(dhd); + dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC, + dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW); + return ret; +} + +static void +dhd_set_multicast_list(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ifidx; + + ifidx = dhd_net2idx(dhd, dev); + if (ifidx == DHD_BAD_IF) + return; + + dhd->iflist[ifidx]->set_multicast = TRUE; + dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx], + DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW); +} + +#ifdef PROP_TXSTATUS +int +dhd_os_wlfc_block(dhd_pub_t *pub) +{ + dhd_info_t *di = (dhd_info_t *)(pub->info); + ASSERT(di != NULL); + spin_lock_bh(&di->wlfc_spinlock); + return 1; +} + +int +dhd_os_wlfc_unblock(dhd_pub_t *pub) +{ + dhd_info_t *di = (dhd_info_t *)(pub->info); + + ASSERT(di != NULL); + spin_unlock_bh(&di->wlfc_spinlock); + return 1; +} + +#endif /* PROP_TXSTATUS */ + +#if defined(DHD_8021X_DUMP) +void +dhd_tx_dump(osl_t *osh, void *pkt) +{ + uint8 *dump_data; + uint16 protocol; + + dump_data = PKTDATA(osh, pkt); + protocol = (dump_data[12] << 8) | dump_data[13]; + + if (protocol == ETHER_TYPE_802_1X) { + DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n", + dump_data[14], dump_data[15], dump_data[30])); + } +} +#endif /* DHD_8021X_DUMP */ + +int BCMFASTPATH +dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) +{ + int ret = BCME_OK; + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct ether_header *eh = NULL; + + /* Reject if down */ + if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { + /* free the packet here since the caller won't */ + PKTFREE(dhdp->osh, pktbuf, TRUE); + return -ENODEV; + } + +#if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) + if (bus_wakeup(dhdp->bus) == TRUE) { + DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); + PKTFREE(dhdp->osh, pktbuf, TRUE); + return -EBUSY; + } +#endif /* DHD_USE_IDLECOUNT && BCMPCIE */ + +#ifdef PCIE_FULL_DONGLE + if (dhdp->busstate == DHD_BUS_SUSPEND) { + DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); + PKTFREE(dhdp->osh, pktbuf, TRUE); + return -EBUSY; + } +#endif /* PCIE_FULL_DONGLE */ + +#ifdef DHD_UNICAST_DHCP + /* if dhcp_unicast is enabled, we need to convert the */ + /* broadcast DHCP ACK/REPLY packets to Unicast. */ + if (dhdp->dhcp_unicast) { + dhd_convert_dhcp_broadcast_ack_to_unicast(dhdp, pktbuf, ifidx); + } +#endif /* DHD_UNICAST_DHCP */ + /* Update multicast statistic */ + if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { + uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); + eh = (struct ether_header *)pktdata; + + if (ETHER_ISMULTI(eh->ether_dhost)) + dhdp->tx_multicast++; + if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) + atomic_inc(&dhd->pend_8021x_cnt); +#ifdef DHD_DHCP_DUMP + if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { + uint16 dump_hex; + uint16 source_port; + uint16 dest_port; + uint16 udp_port_pos; + uint8 *ptr8 = (uint8 *)&pktdata[ETHER_HDR_LEN]; + uint8 ip_header_len = (*ptr8 & 0x0f)<<2; + + udp_port_pos = ETHER_HDR_LEN + ip_header_len; + source_port = (pktdata[udp_port_pos] << 8) | pktdata[udp_port_pos+1]; + dest_port = (pktdata[udp_port_pos+2] << 8) | pktdata[udp_port_pos+3]; + if (source_port == 0x0044 || dest_port == 0x0044) { + dump_hex = (pktdata[udp_port_pos+249] << 8) | + pktdata[udp_port_pos+250]; + if (dump_hex == 0x0101) { + DHD_ERROR(("DHCP - DISCOVER [TX]\n")); + } else if (dump_hex == 0x0102) { + DHD_ERROR(("DHCP - OFFER [TX]\n")); + } else if (dump_hex == 0x0103) { + DHD_ERROR(("DHCP - REQUEST [TX]\n")); + } else if (dump_hex == 0x0105) { + DHD_ERROR(("DHCP - ACK [TX]\n")); + } else { + DHD_ERROR(("DHCP - 0x%X [TX]\n", dump_hex)); + } + } else if (source_port == 0x0043 || dest_port == 0x0043) { + DHD_ERROR(("DHCP - BOOTP [RX]\n")); + } + } +#endif /* DHD_DHCP_DUMP */ + } else { + PKTFREE(dhd->pub.osh, pktbuf, TRUE); + return BCME_ERROR; + } + + /* Look into the packet and update the packet priority */ +#ifndef PKTPRIO_OVERRIDE + if (PKTPRIO(pktbuf) == 0) +#endif + pktsetprio(pktbuf, FALSE); + + +#if defined(PCIE_FULL_DONGLE) && !defined(PCIE_TX_DEFERRAL) + /* + * Lkup the per interface hash table, for a matching flowring. If one is not + * available, allocate a unique flowid and add a flowring entry. + * The found or newly created flowid is placed into the pktbuf's tag. + */ + ret = dhd_flowid_update(dhdp, ifidx, dhdp->flow_prio_map[(PKTPRIO(pktbuf))], pktbuf); + if (ret != BCME_OK) { + PKTCFREE(dhd->pub.osh, pktbuf, TRUE); + return ret; + } +#endif + +#ifdef PROP_TXSTATUS + if (dhd_wlfc_is_supported(dhdp)) { + /* store the interface ID */ + DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); + + /* store destination MAC in the tag as well */ + DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); + + /* decide which FIFO this packet belongs to */ + if (ETHER_ISMULTI(eh->ether_dhost)) + /* one additional queue index (highest AC + 1) is used for bc/mc queue */ + DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); + else + DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); + } else +#endif /* PROP_TXSTATUS */ + /* If the protocol uses a data header, apply it */ + dhd_prot_hdrpush(dhdp, ifidx, pktbuf); + + /* Use bus module to send data frame */ +#ifdef WLMEDIA_HTSF + dhd_htsf_addtxts(dhdp, pktbuf); +#endif +#if defined(DHD_8021X_DUMP) + dhd_tx_dump(dhdp->osh, pktbuf); +#endif +#ifdef PROP_TXSTATUS + { + if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata, + dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) { + /* non-proptxstatus way */ +#ifdef BCMPCIE + ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); +#else + ret = dhd_bus_txdata(dhdp->bus, pktbuf); +#endif /* BCMPCIE */ + } + } +#else +#ifdef BCMPCIE + ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); +#else + ret = dhd_bus_txdata(dhdp->bus, pktbuf); +#endif /* BCMPCIE */ +#endif /* PROP_TXSTATUS */ + + return ret; +} + +int BCMFASTPATH +dhd_start_xmit(struct sk_buff *skb, struct net_device *net) +{ + int ret; + uint datalen; + void *pktbuf; + dhd_info_t *dhd = DHD_DEV_INFO(net); + dhd_if_t *ifp = NULL; + int ifidx; + unsigned long flags; +#ifdef WLMEDIA_HTSF + uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; +#else + uint8 htsfdlystat_sz = 0; +#endif +#ifdef DHD_WMF + struct ether_header *eh; + uint8 *iph; +#endif /* DHD_WMF */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); +#if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) + if (dhd_bus_wakeup(&dhd->pub)) { + /* In order to avoid pkt loss. Return NETDEV_TX_BUSY until run-time resumed. */ + /* stop the network queue temporarily until resume done */ + if (!dhd_bus_is_resume_done(&dhd->pub)) { + netif_stop_queue(net); + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) + return -ENODEV; +#else + return NETDEV_TX_BUSY; +#endif + } +#endif /* DHD_USE_IDLECOUNT && BCMPCIE */ + + DHD_GENERAL_LOCK(&dhd->pub, flags); + dhd->pub.tx_in_progress = TRUE; +#ifdef PCIE_FULL_DONGLE + if (dhd->pub.busstate == DHD_BUS_SUSPEND) { + DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); + dev_kfree_skb(skb); + ifp = DHD_DEV_IFP(net); + ifp->stats.tx_dropped++; + dhd->pub.tx_dropped++; + dhd->pub.tx_in_progress = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + return -EBUSY; + } +#endif /* PCIE_FULL_DONGLE */ + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); + + DHD_GENERAL_LOCK(&dhd->pub, flags); + /* Reject if down */ + if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) { + DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", + __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); + netif_stop_queue(net); + /* Send Event when bus down detected during data session */ + if (dhd->pub.up) { + DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); + net_os_send_hang_message(net); + } + dhd->pub.tx_in_progress = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) + return -ENODEV; +#else + return NETDEV_TX_BUSY; +#endif + } + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + + ifp = DHD_DEV_IFP(net); + ifidx = DHD_DEV_IFIDX(net); + + ASSERT(ifidx == dhd_net2idx(dhd, net)); + ASSERT((ifp != NULL) && (ifp == dhd->iflist[ifidx])); + + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); + netif_stop_queue(net); + DHD_GENERAL_LOCK(&dhd->pub, flags); + dhd->pub.tx_in_progress = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) + return -ENODEV; +#else + return NETDEV_TX_BUSY; +#endif + } + + /* re-align socket buffer if "skb->data" is odd address */ + if (((unsigned long)(skb->data)) & 0x1) { + unsigned char *data = skb->data; + uint32 length = skb->len; + PKTPUSH(dhd->pub.osh, skb, 1); + memmove(skb->data, data, length); + PKTSETLEN(dhd->pub.osh, skb, length); + } + + datalen = PKTLEN(dhd->pub.osh, skb); + + /* Make sure there's enough room for any header */ + + if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { + struct sk_buff *skb2; + + DHD_INFO(("%s: insufficient headroom\n", + dhd_ifname(&dhd->pub, ifidx))); + dhd->pub.tx_realloc++; + + skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); + + dev_kfree_skb(skb); + if ((skb = skb2) == NULL) { + DHD_ERROR(("%s: skb_realloc_headroom failed\n", + dhd_ifname(&dhd->pub, ifidx))); + ret = -ENOMEM; + goto done; + } + } + + /* Convert to packet */ + if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { + DHD_ERROR(("%s: PKTFRMNATIVE failed\n", + dhd_ifname(&dhd->pub, ifidx))); + dev_kfree_skb_any(skb); + ret = -ENOMEM; + goto done; + } +#ifdef WLMEDIA_HTSF + if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { + uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); + struct ether_header *eh = (struct ether_header *)pktdata; + + if (!ETHER_ISMULTI(eh->ether_dhost) && + (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { + eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); + } + } +#endif +#ifdef DHD_WMF + eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf); + iph = (uint8 *)eh + ETHER_HDR_LEN; + + /* WMF processing for multicast packets + * Only IPv4 packets are handled + */ + if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) && + (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) || + ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) { +#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) + void *sdu_clone; + bool ucast_convert = FALSE; +#ifdef DHD_UCAST_UPNP + uint32 dest_ip; + + dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET))); + ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip); +#endif /* DHD_UCAST_UPNP */ +#ifdef DHD_IGMP_UCQUERY + ucast_convert |= dhd->pub.wmf_ucast_igmp_query && + (IPV4_PROT(iph) == IP_PROT_IGMP) && + (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY); +#endif /* DHD_IGMP_UCQUERY */ + if (ucast_convert) { + dhd_sta_t *sta; + unsigned long flags; + + DHD_IF_STA_LIST_LOCK(ifp, flags); + + /* Convert upnp/igmp query to unicast for each assoc STA */ + list_for_each_entry(sta, &ifp->sta_list, list) { + if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) { + DHD_IF_STA_LIST_UNLOCK(ifp, flags); + DHD_GENERAL_LOCK(&dhd->pub, flags); + dhd->pub.tx_in_progress = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return (WMF_NOP); + } + dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1); + } + + DHD_IF_STA_LIST_UNLOCK(ifp, flags); + DHD_GENERAL_LOCK(&dhd->pub, flags); + dhd->pub.tx_in_progress = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + PKTFREE(dhd->pub.osh, pktbuf, TRUE); + return NETDEV_TX_OK; + } else +#endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */ + { + /* There will be no STA info if the packet is coming from LAN host + * Pass as NULL + */ + ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0); + switch (ret) { + case WMF_TAKEN: + case WMF_DROP: + /* Either taken by WMF or we should drop it. + * Exiting send path + */ + DHD_GENERAL_LOCK(&dhd->pub, flags); + dhd->pub.tx_in_progress = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return NETDEV_TX_OK; + default: + /* Continue the transmit path */ + break; + } + } + } +#endif /* DHD_WMF */ + +#ifdef DHDTCPACK_SUPPRESS + if (dhd->pub.tcpack_sup_mode == TCPACK_SUP_HOLD) { + /* If this packet has been hold or got freed, just return */ + if (dhd_tcpack_hold(&dhd->pub, pktbuf, ifidx)) { + ret = 0; + goto done; + } + } else { + /* If this packet has replaced another packet and got freed, just return */ + if (dhd_tcpack_suppress(&dhd->pub, pktbuf)) { + ret = 0; + goto done; + } + } +#endif /* DHDTCPACK_SUPPRESS */ + + ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); + +done: + if (ret) { + ifp->stats.tx_dropped++; + dhd->pub.tx_dropped++; + } + else { + +#ifdef PROP_TXSTATUS + /* tx_packets counter can counted only when wlfc is disabled */ + if (!dhd_wlfc_is_supported(&dhd->pub)) +#endif + { + dhd->pub.tx_packets++; + ifp->stats.tx_packets++; + ifp->stats.tx_bytes += datalen; + } + } + + DHD_GENERAL_LOCK(&dhd->pub, flags); + dhd->pub.tx_in_progress = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + /* Return ok: we always eat the packet */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) + return 0; +#else + return NETDEV_TX_OK; +#endif +} + + +void +dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) +{ + struct net_device *net; + dhd_info_t *dhd = dhdp->info; + int i; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(dhd); + + if (ifidx == ALL_INTERFACES) { + /* Flow control on all active interfaces */ + dhdp->txoff = state; + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + net = dhd->iflist[i]->net; + if (state == ON) + netif_stop_queue(net); + else + netif_wake_queue(net); + } + } + } + else { + if (dhd->iflist[ifidx]) { + net = dhd->iflist[ifidx]->net; + if (state == ON) + netif_stop_queue(net); + else + netif_wake_queue(net); + } + } +} + +#ifdef DHD_RX_DUMP +typedef struct { + uint16 type; + const char *str; +} PKTTYPE_INFO; + +static const PKTTYPE_INFO packet_type_info[] = +{ + { ETHER_TYPE_IP, "IP" }, + { ETHER_TYPE_ARP, "ARP" }, + { ETHER_TYPE_BRCM, "BRCM" }, + { ETHER_TYPE_802_1X, "802.1X" }, + { ETHER_TYPE_WAI, "WAPI" }, + { 0, ""} +}; + +static const char *_get_packet_type_str(uint16 type) +{ + int i; + int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; + + for (i = 0; i < n; i++) { + if (packet_type_info[i].type == type) + return packet_type_info[i].str; + } + + return packet_type_info[n].str; +} +#endif /* DHD_RX_DUMP */ + + +#ifdef DHD_WMF +bool +dhd_is_rxthread_enabled(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd = dhdp->info; + + return dhd->rxthread_enabled; +} +#endif /* DHD_WMF */ + +void +dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + struct sk_buff *skb; + uchar *eth; + uint len; + void *data, *pnext = NULL; + int i; + dhd_if_t *ifp; + wl_event_msg_t event; + int tout_rx = 0; + int tout_ctrl = 0; + void *skbhead = NULL; + void *skbprev = NULL; +#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) + char *dump_data; + uint16 protocol; +#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { + struct ether_header *eh; + + pnext = PKTNEXT(dhdp->osh, pktbuf); + PKTSETNEXT(dhdp->osh, pktbuf, NULL); + + ifp = dhd->iflist[ifidx]; + if (ifp == NULL) { + DHD_ERROR(("%s: ifp is NULL. drop packet\n", + __FUNCTION__)); + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + + eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); + + /* Dropping only data packets before registering net device to avoid kernel panic */ +#ifndef PROP_TXSTATUS_VSDB + if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) && + (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { +#else + if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) && + (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { +#endif /* PROP_TXSTATUS_VSDB */ + DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", + __FUNCTION__)); + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + + +#ifdef PROP_TXSTATUS + if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) { + /* WLFC may send header only packet when + there is an urgent message but no packet to + piggy-back on + */ + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + } +#endif +#ifdef DHD_L2_FILTER + /* If block_ping is enabled drop the ping packet */ + if (dhdp->block_ping) { + if (dhd_l2_filter_block_ping(dhdp, pktbuf, ifidx) == BCME_OK) { + PKTFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + } +#endif +#ifdef DHD_WMF + /* WMF processing for multicast packets */ + if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) { + dhd_sta_t *sta; + int ret; + + sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost); + ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1); + switch (ret) { + case WMF_TAKEN: + /* The packet is taken by WMF. Continue to next iteration */ + continue; + case WMF_DROP: + /* Packet DROP decision by WMF. Toss it */ + DHD_ERROR(("%s: WMF decides to drop packet\n", + __FUNCTION__)); + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + default: + /* Continue the transmit path */ + break; + } + } +#endif /* DHD_WMF */ +#ifdef DHDTCPACK_SUPPRESS + dhd_tcpdata_info_get(dhdp, pktbuf); +#endif + skb = PKTTONATIVE(dhdp->osh, pktbuf); + + ifp = dhd->iflist[ifidx]; + if (ifp == NULL) + ifp = dhd->iflist[0]; + + ASSERT(ifp); + skb->dev = ifp->net; + +#ifdef PCIE_FULL_DONGLE + if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) && + (!ifp->ap_isolate)) { + eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); + if (ETHER_ISUCAST(eh->ether_dhost)) { + if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) { + dhd_sendpkt(dhdp, ifidx, pktbuf); + continue; + } + } else { + void *npktbuf = PKTDUP(dhdp->osh, pktbuf); + dhd_sendpkt(dhdp, ifidx, npktbuf); + } + } +#endif /* PCIE_FULL_DONGLE */ + + /* 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; + +#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_DHCP_DUMP) + dump_data = skb->data; + protocol = (dump_data[12] << 8) | dump_data[13]; +#endif /* DHD_RX_DUMP || DHD_8021X_DUMP || DHD_DHCP_DUMP */ +#ifdef DHD_8021X_DUMP + if (protocol == ETHER_TYPE_802_1X) { + DHD_ERROR(("ETHER_TYPE_802_1X [RX]: " + "ver %d, type %d, replay %d\n", + dump_data[14], dump_data[15], + dump_data[30])); + } +#endif /* DHD_8021X_DUMP */ +#ifdef DHD_DHCP_DUMP + if (protocol != ETHER_TYPE_BRCM && protocol == ETHER_TYPE_IP) { + uint16 dump_hex; + uint16 source_port; + uint16 dest_port; + uint16 udp_port_pos; + uint8 *ptr8 = (uint8 *)&dump_data[ETHER_HDR_LEN]; + uint8 ip_header_len = (*ptr8 & 0x0f)<<2; + + udp_port_pos = ETHER_HDR_LEN + ip_header_len; + source_port = (dump_data[udp_port_pos] << 8) | dump_data[udp_port_pos+1]; + dest_port = (dump_data[udp_port_pos+2] << 8) | dump_data[udp_port_pos+3]; + if (source_port == 0x0044 || dest_port == 0x0044) { + dump_hex = (dump_data[udp_port_pos+249] << 8) | + dump_data[udp_port_pos+250]; + if (dump_hex == 0x0101) { + DHD_ERROR(("DHCP - DISCOVER [RX]\n")); + } else if (dump_hex == 0x0102) { + DHD_ERROR(("DHCP - OFFER [RX]\n")); + } else if (dump_hex == 0x0103) { + DHD_ERROR(("DHCP - REQUEST [RX]\n")); + } else if (dump_hex == 0x0105) { + DHD_ERROR(("DHCP - ACK [RX]\n")); + } else { + DHD_ERROR(("DHCP - 0x%X [RX]\n", dump_hex)); + } + } else if (source_port == 0x0043 || dest_port == 0x0043) { + DHD_ERROR(("DHCP - BOOTP [RX]\n")); + } + } +#endif /* DHD_DHCP_DUMP */ +#if defined(DHD_RX_DUMP) + DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol))); + if (protocol != ETHER_TYPE_BRCM) { + if (dump_data[0] == 0xFF) { + DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__)); + + if ((dump_data[12] == 8) && + (dump_data[13] == 6)) { + DHD_ERROR(("%s: ARP %d\n", + __FUNCTION__, dump_data[0x15])); + } + } else if (dump_data[0] & 1) { + DHD_ERROR(("%s: MULTICAST: " MACDBG "\n", + __FUNCTION__, MAC2STRDBG(dump_data))); + } +#ifdef DHD_RX_FULL_DUMP + { + int k; + for (k = 0; k < skb->len; k++) { + DHD_ERROR(("%02X ", dump_data[k])); + if ((k & 15) == 15) + DHD_ERROR(("\n")); + } + DHD_ERROR(("\n")); + } +#endif /* DHD_RX_FULL_DUMP */ + } +#endif /* DHD_RX_DUMP */ + + skb->protocol = eth_type_trans(skb, skb->dev); + + if (skb->pkt_type == PACKET_MULTICAST) { + dhd->pub.rx_multicast++; + ifp->stats.multicast++; + } + + skb->data = eth; + skb->len = len; + +#ifdef WLMEDIA_HTSF + dhd_htsf_addrxts(dhdp, pktbuf); +#endif + /* Strip header, count, deliver upward */ + skb_pull(skb, ETH_HLEN); + + /* Process special event packets and then discard them */ + memset(&event, 0, sizeof(event)); + if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { + int ret_event; + + ret_event = dhd_wl_host_event(dhd, &ifidx, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + skb_mac_header(skb), +#else + skb->mac.raw, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ + len, + &event, + &data); + + if (ret_event != BCME_OK) { + PKTFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + + wl_event_to_host_order(&event); + if (!tout_ctrl) + tout_ctrl = DHD_PACKET_TIMEOUT_MS; + +#if defined(PNO_SUPPORT) + if (event.event_type == WLC_E_PFN_NET_FOUND) { + /* enforce custom wake lock to garantee that Kernel not suspended */ + tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; + } +#endif /* PNO_SUPPORT */ + +#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + PKTFREE(dhdp->osh, pktbuf, FALSE); + + continue; +#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ + } else { + tout_rx = DHD_PACKET_TIMEOUT_MS; + +#ifdef PROP_TXSTATUS + dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb)); +#endif /* PROP_TXSTATUS */ + } + + ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); + ifp = dhd->iflist[ifidx]; + + if (ifp->net) + ifp->net->last_rx = jiffies; + + if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { + dhdp->dstats.rx_bytes += skb->len; + dhdp->rx_packets++; /* Local count */ + ifp->stats.rx_bytes += skb->len; + ifp->stats.rx_packets++; + } + + if (in_interrupt()) { + netif_rx(skb); + } else { + if (dhd->rxthread_enabled) { + if (!skbhead) + skbhead = skb; + else + PKTSETNEXT(dhdp->osh, skbprev, skb); + skbprev = 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. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + netif_rx_ni(skb); +#else + ulong flags; + netif_rx(skb); + local_irq_save(flags); + RAISE_RX_SOFTIRQ(); + local_irq_restore(flags); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ + } + } + } + + if (dhd->rxthread_enabled && skbhead) + dhd_sched_rxf(dhdp, skbhead); + + DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); +} + +void +dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx) +{ + /* Linux version has nothing to do */ + return; +} + +void +dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) +{ + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct ether_header *eh; + uint16 type; + + dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); + + eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); + type = ntoh16(eh->ether_type); + + if (type == ETHER_TYPE_802_1X) + atomic_dec(&dhd->pend_8021x_cnt); + +#ifdef PROP_TXSTATUS + if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) { + dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))]; + uint datalen = PKTLEN(dhd->pub.osh, txp); + + if (success) { + dhd->pub.tx_packets++; + ifp->stats.tx_packets++; + ifp->stats.tx_bytes += datalen; + } else { + ifp->stats.tx_dropped++; + } + } +#endif +} + +static struct net_device_stats * +dhd_get_stats(struct net_device *net) +{ + dhd_info_t *dhd = DHD_DEV_INFO(net); + dhd_if_t *ifp; + int ifidx; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ifidx = dhd_net2idx(dhd, net); + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); + + memset(&net->stats, 0, sizeof(net->stats)); + return &net->stats; + } + + ifp = dhd->iflist[ifidx]; + ASSERT(dhd && ifp); + + if (dhd->pub.up) { + /* Use the protocol to get dongle stats */ + dhd_prot_dstats(&dhd->pub); + } + return &ifp->stats; +} + +static int +dhd_watchdog_thread(void *data) +{ + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; + /* This thread doesn't need any user-level access, + * so get rid of all our resources + */ + if (dhd_watchdog_prio > 0) { + struct sched_param param; + param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? + dhd_watchdog_prio:(MAX_RT_PRIO-1); + setScheduler(current, SCHED_FIFO, ¶m); + } + + while (1) + if (down_interruptible (&tsk->sema) == 0) { + unsigned long flags; + unsigned long jiffies_at_start = jiffies; + unsigned long time_lapse; + + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } + + if (dhd->pub.dongle_reset == FALSE) { + DHD_TIMER(("%s:\n", __FUNCTION__)); + + /* Call the bus module watchdog */ + dhd_bus_watchdog(&dhd->pub); + + + DHD_GENERAL_LOCK(&dhd->pub, flags); + /* Count the tick for reference */ + dhd->pub.tickcnt++; + time_lapse = jiffies - jiffies_at_start; + + /* Reschedule the watchdog */ + if (dhd->wd_timer_valid) + mod_timer(&dhd->timer, + jiffies + + msecs_to_jiffies(dhd_watchdog_ms) - + min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + } + } else { + break; + } + + complete_and_exit(&tsk->completed, 0); +} + +static void dhd_watchdog(ulong data) +{ + dhd_info_t *dhd = (dhd_info_t *)data; + unsigned long flags; + + if (dhd->pub.dongle_reset) { + return; + } + + if (dhd->thr_wdt_ctl.thr_pid >= 0) { + up(&dhd->thr_wdt_ctl.sema); + return; + } + + /* Call the bus module watchdog */ + dhd_bus_watchdog(&dhd->pub); + + DHD_GENERAL_LOCK(&dhd->pub, flags); + /* Count the tick for reference */ + dhd->pub.tickcnt++; + + /* Reschedule the watchdog */ + if (dhd->wd_timer_valid) + mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + +} + +#ifdef ENABLE_ADAPTIVE_SCHED +static void +dhd_sched_policy(int prio) +{ + struct sched_param param; + if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) { + param.sched_priority = 0; + setScheduler(current, SCHED_NORMAL, ¶m); + } else { + if (get_scheduler_policy(current) != SCHED_FIFO) { + param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1); + setScheduler(current, SCHED_FIFO, ¶m); + } + } +} +#endif /* ENABLE_ADAPTIVE_SCHED */ +#ifdef DEBUG_CPU_FREQ +static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) +{ + dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans); + struct cpufreq_freqs *freq = data; + if (dhd) { + if (!dhd->new_freq) + goto exit; + if (val == CPUFREQ_POSTCHANGE) { + DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n", + freq->new, freq->cpu)); + *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new; + } + } +exit: + return 0; +} +#endif /* DEBUG_CPU_FREQ */ +static int +dhd_dpc_thread(void *data) +{ + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; + + /* This thread doesn't need any user-level access, + * so get rid of all our resources + */ + if (dhd_dpc_prio > 0) + { + struct sched_param param; + param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); + setScheduler(current, SCHED_FIFO, ¶m); + } + +#ifdef CUSTOM_DPC_CPUCORE + set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE)); +#endif +#ifdef CUSTOM_SET_CPUCORE + dhd->pub.current_dpc = current; +#endif /* CUSTOM_SET_CPUCORE */ + /* Run until signal received */ + while (1) { + if (!binary_sema_down(tsk)) { +#ifdef ENABLE_ADAPTIVE_SCHED + dhd_sched_policy(dhd_dpc_prio); +#endif /* ENABLE_ADAPTIVE_SCHED */ + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } + + /* Call bus dpc unless it indicated down (then clean stop) */ + if (dhd->pub.busstate != DHD_BUS_DOWN) { + dhd_os_wd_timer_extend(&dhd->pub, TRUE); + while (dhd_bus_dpc(dhd->pub.bus)) { + /* process all data */ + } + dhd_os_wd_timer_extend(&dhd->pub, FALSE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + } else { + if (dhd->pub.up) + dhd_bus_stop(dhd->pub.bus, TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + } + } + else + break; + } + complete_and_exit(&tsk->completed, 0); +} + +static int +dhd_rxf_thread(void *data) +{ + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; +#if defined(WAIT_DEQUEUE) +#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */ + ulong watchdogTime = OSL_SYSUPTIME(); /* msec */ +#endif + dhd_pub_t *pub = &dhd->pub; + + /* This thread doesn't need any user-level access, + * so get rid of all our resources + */ + if (dhd_rxf_prio > 0) + { + struct sched_param param; + param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1); + setScheduler(current, SCHED_FIFO, ¶m); + } + + DAEMONIZE("dhd_rxf"); + /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ + + /* signal: thread has started */ + complete(&tsk->completed); +#ifdef CUSTOM_SET_CPUCORE + dhd->pub.current_rxf = current; +#endif /* CUSTOM_SET_CPUCORE */ + /* Run until signal received */ + while (1) { + if (down_interruptible(&tsk->sema) == 0) { + void *skb; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + ulong flags; +#endif +#ifdef ENABLE_ADAPTIVE_SCHED + dhd_sched_policy(dhd_rxf_prio); +#endif /* ENABLE_ADAPTIVE_SCHED */ + + SMP_RD_BARRIER_DEPENDS(); + + if (tsk->terminated) { + break; + } + skb = dhd_rxf_dequeue(pub); + + if (skb == NULL) { + continue; + } + while (skb) { + void *skbnext = PKTNEXT(pub->osh, skb); + PKTSETNEXT(pub->osh, skb, NULL); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + netif_rx_ni(skb); +#else + netif_rx(skb); + local_irq_save(flags); + RAISE_RX_SOFTIRQ(); + local_irq_restore(flags); + +#endif + skb = skbnext; + } +#if defined(WAIT_DEQUEUE) + if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) { + OSL_SLEEP(1); + watchdogTime = OSL_SYSUPTIME(); + } +#endif + + DHD_OS_WAKE_UNLOCK(pub); + } + else + break; + } + complete_and_exit(&tsk->completed, 0); +} + +#ifdef BCMPCIE +void dhd_dpc_kill(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd; + + if (!dhdp) + return; + + dhd = dhdp->info; + + if (!dhd) + return; + + tasklet_kill(&dhd->tasklet); + DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__)); +} +#endif /* BCMPCIE */ + +static void +dhd_dpc(ulong data) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)data; + + /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] + * down below , wake lock is set, + * the tasklet is initialized in dhd_attach() + */ + /* Call bus dpc unless it indicated down (then clean stop) */ + if (dhd->pub.busstate != DHD_BUS_DOWN) { + if (dhd_bus_dpc(dhd->pub.bus)) + tasklet_schedule(&dhd->tasklet); + else + DHD_OS_WAKE_UNLOCK(&dhd->pub); + } else { + dhd_bus_stop(dhd->pub.bus, TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + } +} + +void +dhd_sched_dpc(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + DHD_OS_WAKE_LOCK(dhdp); + if (dhd->thr_dpc_ctl.thr_pid >= 0) { + /* If the semaphore does not get up, + * wake unlock should be done here + */ + if (!binary_sema_up(&dhd->thr_dpc_ctl)) + DHD_OS_WAKE_UNLOCK(dhdp); + return; + } else { + tasklet_schedule(&dhd->tasklet); + } +} + +static void +dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + DHD_OS_WAKE_LOCK(dhdp); + + DHD_TRACE(("dhd_sched_rxf: Enter\n")); + do { + if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK) + break; + } while (1); + if (dhd->thr_rxf_ctl.thr_pid >= 0) { + up(&dhd->thr_rxf_ctl.sema); + } + return; +} + +#ifdef TOE +/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ +static int +dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) +{ + char buf[32]; + int ret; + + ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", NULL, 0, (char *)buf, sizeof(buf), FALSE); + + if (ret < 0) { + if (ret == -EIO) { + DHD_ERROR(("%s: toe not supported by device\n", dhd_ifname(&dhd->pub, + ifidx))); + return -EOPNOTSUPP; + } + + DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); + return ret; + } + + memcpy(toe_ol, buf, sizeof(uint32)); + return 0; +} + +/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ +static int +dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) +{ + int toe, ret; + + /* Set toe_ol as requested */ + ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", (char *)&toe_ol, sizeof(toe_ol), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", + dhd_ifname(&dhd->pub, ifidx), ret)); + return ret; + } + + /* Enable toe globally only if any components are enabled. */ + toe = (toe_ol != 0); + ret = dhd_iovar(&dhd->pub, ifidx, "toe", (char *)&toe, sizeof(toe), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); + return ret; + } + + return 0; +} +#endif /* TOE */ + +#if defined(WL_CFG80211) +void dhd_set_scb_probe(dhd_pub_t *dhd) +{ +#define NUM_SCB_MAX_PROBE 3 + int ret = 0; + wl_scb_probe_t scb_probe; + + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) + return; + + ret = dhd_iovar(dhd, 0, "scb_probe", NULL, 0, (char *)&scb_probe, sizeof(wl_scb_probe_t), + FALSE); + if (ret < 0) { + DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__)); + } + + scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE; + + ret = dhd_iovar(dhd, 0, "scb_probe", (char *)&scb_probe, + sizeof(wl_scb_probe_t), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__)); + } +#undef NUM_SCB_MAX_PROBE + return; +} +#endif /* WL_CFG80211 */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +static void +dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) +{ + dhd_info_t *dhd = DHD_DEV_INFO(net); + + snprintf(info->driver, sizeof(info->driver), "wl"); + snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); +} + +struct ethtool_ops dhd_ethtool_ops = { + .get_drvinfo = dhd_ethtool_get_drvinfo +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) +static int +dhd_ethtool(dhd_info_t *dhd, void *uaddr) +{ + struct ethtool_drvinfo info; + char drvname[sizeof(info.driver)]; + uint32 cmd; +#ifdef TOE + struct ethtool_value edata; + uint32 toe_cmpnt, csum_dir; + int ret; +#endif + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* all ethtool calls start with a cmd word */ + if (copy_from_user(&cmd, uaddr, sizeof (uint32))) + 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 dhd requested, identify ourselves */ + if (strcmp(drvname, "?dhd") == 0) { + snprintf(info.driver, sizeof(info.driver), "dhd"); + strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); + info.version[sizeof(info.version) - 1] = '\0'; + } + + /* otherwise, require dongle to be up */ + else if (!dhd->pub.up) { + DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); + return -ENODEV; + } + + /* finally, report dongle driver type */ + else if (dhd->pub.iswl) + snprintf(info.driver, sizeof(info.driver), "wl"); + else + snprintf(info.driver, sizeof(info.driver), "xx"); + + snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); + if (copy_to_user(uaddr, &info, sizeof(info))) + return -EFAULT; + DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, + (int)sizeof(drvname), drvname, info.driver)); + break; + +#ifdef TOE + /* Get toe offload components from dongle */ + case ETHTOOL_GRXCSUM: + case ETHTOOL_GTXCSUM: + if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 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 */ + if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 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; + + if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) + return ret; + + /* If setting TX checksum mode, tell Linux the new mode */ + if (cmd == ETHTOOL_STXCSUM) { + if (edata.data) + dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; + else + dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; + } + + break; +#endif /* TOE */ + + default: + return -EOPNOTSUPP; + } + + return 0; +} +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ + +static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) +{ + dhd_info_t *dhd; + + if (!dhdp) { + DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); + return FALSE; + } + + if (!dhdp->up) + return FALSE; + + dhd = (dhd_info_t *)dhdp->info; +#if !defined(BCMPCIE) + if (dhd->thr_dpc_ctl.thr_pid < 0) { + DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); + return FALSE; + } +#endif + +#ifdef CONFIG_MACH_UNIVERSAL5433 + /* old revision does not send hang message */ + if ((check_rev() && (error == -ETIMEDOUT)) || (error == -EREMOTEIO) || +#else + if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || +#endif /* CONFIG_MACH_UNIVERSAL5433 */ + ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { +#ifdef BCMPCIE + DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d d3acke=%d e=%d s=%d\n", + __FUNCTION__, dhdp->rxcnt_timeout, dhdp->txcnt_timeout, + dhdp->d3ackcnt_timeout, error, dhdp->busstate)); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(dhd->pub.crash_reason, + "%s: Event HANG send up due to re=%d te=%d d3acke=%d e=%d s=%d\n", + __FUNCTION__, dhdp->rxcnt_timeout, dhdp->txcnt_timeout, + dhdp->d3ackcnt_timeout, error, dhdp->busstate); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ +#else + DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, + dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(dhd->pub.crash_reason, + "%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, + dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ +#endif /* BCMPCIE */ + + net_os_send_hang_message(net); + return TRUE; + } + return FALSE; +} + +int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf) +{ + int bcmerror = BCME_OK; + int buflen = 0; + struct net_device *net; + + net = dhd_idx2net(pub, ifidx); + if (!net) { + bcmerror = BCME_BADARG; + goto done; + } + + if (data_buf) + buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN); + + /* check for local dhd ioctl and handle it */ + if (ioc->driver == DHD_IOCTL_MAGIC) { + bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen); + if (bcmerror) + pub->bcmerror = bcmerror; + goto done; + } + + /* send to dongle (must be up, and wl). */ + if (pub->busstate != DHD_BUS_DATA) { + bcmerror = BCME_DONGLE_DOWN; + goto done; + } + + if (!pub->iswl) { + bcmerror = BCME_DONGLE_DOWN; + goto done; + } + + /* + * Flush the TX queue if required for proper message serialization: + * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to + * prevent M4 encryption and + * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to + * prevent disassoc frame being sent before WPS-DONE frame. + */ + if (ioc->cmd == WLC_SET_KEY || + (ioc->cmd == WLC_SET_VAR && data_buf != NULL && + strncmp("wsec_key", data_buf, 9) == 0) || + (ioc->cmd == WLC_SET_VAR && data_buf != NULL && + strncmp("bsscfg:wsec_key", data_buf, 15) == 0) || + ioc->cmd == WLC_DISASSOC) + dhd_wait_pend8021x(net); + +#ifdef WLMEDIA_HTSF + if (data_buf) { + /* short cut wl ioctl calls here */ + if (strcmp("htsf", data_buf) == 0) { + dhd_ioctl_htsf_get(dhd, 0); + return BCME_OK; + } + + if (strcmp("htsflate", data_buf) == 0) { + if (ioc->set) { + memset(ts, 0, sizeof(tstamp_t)*TSMAX); + memset(&maxdelayts, 0, sizeof(tstamp_t)); + maxdelay = 0; + tspktcnt = 0; + maxdelaypktno = 0; + memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); + } else { + dhd_dump_latency(); + } + return BCME_OK; + } + if (strcmp("htsfclear", data_buf) == 0) { + memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); + htsf_seqnum = 0; + return BCME_OK; + } + if (strcmp("htsfhis", data_buf) == 0) { + dhd_dump_htsfhisto(&vi_d1, "H to D"); + dhd_dump_htsfhisto(&vi_d2, "D to D"); + dhd_dump_htsfhisto(&vi_d3, "D to H"); + dhd_dump_htsfhisto(&vi_d4, "H to H"); + return BCME_OK; + } + if (strcmp("tsport", data_buf) == 0) { + if (ioc->set) { + memcpy(&tsport, data_buf + 7, 4); + } else { + DHD_ERROR(("current timestamp port: %d \n", tsport)); + } + return BCME_OK; + } + } +#endif /* WLMEDIA_HTSF */ + + if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) && + data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) { +#ifdef BCM_FD_AGGR + bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); +#else + bcmerror = BCME_UNSUPPORTED; +#endif + goto done; + } + + if (ioc->cmd == WLC_SET_VAR && data_buf != NULL && + strncmp("qtxpower", data_buf, 8) == 0) { +#ifdef SOMC_MIMO + if (*((char *)data_buf + 12) & SOMC_TXPWR_5G && + *((char *)data_buf + 9) != WLC_TXPWR_MAX && + *((char *)data_buf + 10) != WLC_TXPWR_MAX) { + *((char *)data_buf + 12) |= SOMC_TXPWR_OVERRIDE; + } +#endif + if (somc_update_qtxpower((char *)data_buf + 9, *((char *)data_buf + 12), 0) != 0) { + DHD_ERROR(("qtxpower on chain0 failed\n")); + bcmerror = BCME_ERROR; + goto done; + } +#ifdef SOMC_MIMO + if (somc_update_qtxpower((char *)data_buf + 10, *((char *)data_buf + 12), 1) != 0) { + DHD_ERROR(("qtxpower on chain1 failed\n")); + bcmerror = BCME_ERROR; + goto done; + } +#else + /* initialize chain1 value just in case since it's not needed for SISO */ + *((char *)data_buf + 10) = 0; +#endif + } + + bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); + +done: + dhd_check_hang(net, pub, bcmerror); + + return bcmerror; +} + +static int +dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) +{ + dhd_info_t *dhd = DHD_DEV_INFO(net); + dhd_ioctl_t ioc; + int bcmerror = 0; + int ifidx; + int ret; + void *local_buf = NULL; + u16 buflen = 0; + +#if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) + /* Just wake watchdog and wait. Don't care the return value here. */ + dhd_bus_wake(&dhd->pub); +#endif /* DHD_USE_IDLECOUNT && BCMPCIE */ + + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_PERIM_LOCK(&dhd->pub); + + /* Interface up check for built-in type */ + if (!dhd_download_fw_on_driverload && dhd->pub.up == 0) { + DHD_TRACE(("%s: Interface is down \n", __FUNCTION__)); + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return BCME_NOTUP; + } + + /* send to dongle only if we are not waiting for reload already */ + if (dhd->pub.hang_was_sent) { + DHD_TRACE(("%s: HANG was sent up earlier\n", __FUNCTION__)); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return OSL_ERROR(BCME_DONGLE_DOWN); + } + + ifidx = dhd_net2idx(dhd, net); + DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); + + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return -1; + } + +#if defined(WL_WIRELESS_EXT) + /* linux wireless extensions */ + if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { + /* may recurse, do NOT lock */ + ret = wl_iw_ioctl(net, ifr, cmd); + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } +#endif /* defined(WL_WIRELESS_EXT) */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) + if (cmd == SIOCETHTOOL) { + ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ + + if (cmd == SIOCDEVPRIVATE+1) { + ret = wl_android_priv_cmd(net, ifr, cmd); + dhd_check_hang(net, &dhd->pub, ret); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } + + if (cmd != SIOCDEVPRIVATE) { + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return -EOPNOTSUPP; + } + + memset(&ioc, 0, sizeof(ioc)); + +#ifdef CONFIG_COMPAT + if (is_compat_task()) { + compat_wl_ioctl_t compat_ioc; + if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) { + bcmerror = BCME_BADADDR; + goto done; + } + ioc.cmd = compat_ioc.cmd; + ioc.buf = compat_ptr(compat_ioc.buf); + ioc.len = compat_ioc.len; + ioc.set = compat_ioc.set; + ioc.used = compat_ioc.used; + ioc.needed = compat_ioc.needed; + /* To differentiate between wl and dhd read 4 more byes */ + if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), + sizeof(uint)) != 0)) { + bcmerror = BCME_BADADDR; + goto done; + } + } else +#endif /* CONFIG_COMPAT */ + { + /* Copy the ioc control structure part of ioctl request */ + if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { + bcmerror = BCME_BADADDR; + goto done; + } + + /* To differentiate between wl and dhd read 4 more byes */ + if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), + sizeof(uint)) != 0)) { + bcmerror = BCME_BADADDR; + goto done; + } + } + + if (!capable(CAP_NET_ADMIN)) { + bcmerror = BCME_EPERM; + goto done; + } + + if (ioc.len > 0) { + buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); + if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) { + bcmerror = BCME_NOMEM; + goto done; + } + + DHD_PERIM_UNLOCK(&dhd->pub); + if (copy_from_user(local_buf, ioc.buf, buflen)) { + DHD_PERIM_LOCK(&dhd->pub); + bcmerror = BCME_BADADDR; + goto done; + } + DHD_PERIM_LOCK(&dhd->pub); + + *(char *)(local_buf + buflen) = '\0'; + } + + bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf); + + if (!bcmerror && buflen && local_buf && ioc.buf) { + DHD_PERIM_UNLOCK(&dhd->pub); + if (copy_to_user(ioc.buf, local_buf, buflen)) + bcmerror = -EFAULT; + DHD_PERIM_LOCK(&dhd->pub); + } + +done: + if (local_buf) + MFREE(dhd->pub.osh, local_buf, buflen+1); + + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + return OSL_ERROR(bcmerror); +} + + + +static int +dhd_stop(struct net_device *net) +{ + int ifidx = 0; + dhd_info_t *dhd = DHD_DEV_INFO(net); + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_PERIM_LOCK(&dhd->pub); + DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); + dhd->pub.rxcnt_timeout = 0; + dhd->pub.txcnt_timeout = 0; + + if (dhd->pub.up == 0) { + goto exit; + } + + dhd_if_flush_sta(DHD_DEV_IFP(net)); + + + ifidx = dhd_net2idx(dhd, net); + BCM_REFERENCE(ifidx); + + /* Stop OS transmissions */ + netif_stop_queue(net); + +#ifdef WL_CFG80211 + if (ifidx == 0) { + wl_cfg80211_down(NULL); + + /* + * For CFG80211: Clean up all the left over virtual interfaces + * when the primary Interface is brought down. [ifconfig wlan0 down] + */ + if (!dhd_download_fw_on_driverload) { + if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && + (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { + int i; + + + dhd_net_if_lock_local(dhd); + for (i = 1; i < DHD_MAX_IFS; i++) + dhd_remove_if(&dhd->pub, i, FALSE); + dhd_net_if_unlock_local(dhd); + } + } + } +#endif /* WL_CFG80211 */ + +#ifdef PROP_TXSTATUS + dhd_wlfc_cleanup(&dhd->pub, NULL, 0); +#endif + /* Stop the protocol module */ + dhd_prot_stop(&dhd->pub); + + OLD_MOD_DEC_USE_COUNT; +exit: +#if defined(WL_CFG80211) + if (ifidx == 0 && !dhd_download_fw_on_driverload) + wl_android_wifi_off(net); +#endif + /* Set state */ + dhd->pub.up = 0; + +#ifdef BCMPCIE + dhd->pub.d3ackcnt_timeout = 0; +#endif /* BCMPCIE */ + + dhd->pub.hang_was_sent = 0; + dhd->pub.ioctl_state = 0; + + /* Clear country spec for for built-in type driver */ + if (!dhd_download_fw_on_driverload) { + dhd->pub.dhd_cspec.country_abbrev[0] = 0x00; + dhd->pub.dhd_cspec.rev = 0; + dhd->pub.dhd_cspec.ccode[0] = 0x00; + } + + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + /* Destroy wakelock */ + if (!dhd_download_fw_on_driverload && + (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { + DHD_OS_WAKE_LOCK_DESTROY(dhd); + dhd->dhd_state &= ~DHD_ATTACH_STATE_WAKELOCKS_INIT; + } + + return 0; +} + +#if defined(WL_CFG80211) && (defined(USE_INITIAL_2G_SCAN) || \ + defined(USE_INITIAL_SHORT_DWELL_TIME)) +extern bool g_first_broadcast_scan; +#endif /* OEM_ANDROID && WL_CFG80211 && (USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME) */ + +#ifdef WL11U +static int dhd_interworking_enable(dhd_pub_t *dhd) +{ + uint32 enable = true; + int ret = BCME_OK; + + ret = dhd_iovar(dhd, 0, "interworking", (char *)&enable, sizeof(enable), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret)); + } + + if (ret == BCME_OK) { + /* basic capabilities for HS20 REL2 */ + uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF; + ret = dhd_iovar(dhd, 0, "wnm", (char *)&cap, sizeof(cap), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret)); + } + } + + return ret; +} +#endif /* WL11u */ + +static int +dhd_open(struct net_device *net) +{ + dhd_info_t *dhd = DHD_DEV_INFO(net); +#ifdef TOE + uint32 toe_ol; +#endif + int ifidx; + int32 ret = 0; + + /* Init wakelock */ + if (!dhd_download_fw_on_driverload && + !(dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { + DHD_OS_WAKE_LOCK_INIT(dhd); + dhd->dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; + } + + + + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_PERIM_LOCK(&dhd->pub); + dhd->pub.dongle_trap_occured = 0; + dhd->pub.hang_was_sent = 0; + dhd->pub.ioctl_state = 0; + +#if !defined(WL_CFG80211) + /* + * Force start if ifconfig_up gets called before START command + * We keep WEXT's wl_control_wl_start to provide backward compatibility + * This should be removed in the future + */ + ret = wl_control_wl_start(net); + if (ret != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } + +#endif + + ifidx = dhd_net2idx(dhd, net); + DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); + + if (ifidx < 0) { + DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__)); + ret = -1; + goto exit; + } + + if (!dhd->iflist[ifidx]) { + DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); + ret = -1; + goto exit; + } + + if (ifidx == 0) { + +#if defined(BCMPCIE) && defined(CUSTOMER_HW5) + if (!dhd->register_if_done) { + DHD_ERROR(("%s: Registering interface has not done yet\n", __FUNCTION__)); + ret = -1; + goto exit; + } +#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ + + atomic_set(&dhd->pend_8021x_cnt, 0); +#if defined(WL_CFG80211) + if (!dhd_download_fw_on_driverload) { + DHD_ERROR(("\n%s\n", dhd_version)); +#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) + g_first_broadcast_scan = TRUE; +#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ + ret = wl_android_wifi_on(net); + if (ret != 0) { + DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n", + __FUNCTION__, ret)); + ret = -1; + goto exit; + } + } +#endif + + if (dhd->pub.busstate != DHD_BUS_DATA) { + + /* try to bring up bus */ + DHD_PERIM_UNLOCK(&dhd->pub); + ret = dhd_bus_start(&dhd->pub); + DHD_PERIM_LOCK(&dhd->pub); + if (ret) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } + + } + + /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */ + memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); + +#ifdef TOE + /* Get current TOE mode from dongle */ + if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) + dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; + else + dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; +#endif /* TOE */ + +#if defined(WL_CFG80211) + if (unlikely(wl_cfg80211_up(NULL))) { + DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); + ret = -1; + goto exit; + } + dhd_set_scb_probe(&dhd->pub); +#endif /* WL_CFG80211 */ + } + + /* Allow transmit calls */ + netif_start_queue(net); + dhd->pub.up = 1; + +#ifdef BCMDBGFS + dhd_dbg_init(&dhd->pub); +#endif + + OLD_MOD_INC_USE_COUNT; +exit: + if (ret) + dhd_stop(net); + + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + + return ret; +} + +int dhd_do_driver_init(struct net_device *net) +{ + dhd_info_t *dhd = NULL; + + if (!net) { + DHD_ERROR(("Primary Interface not initialized \n")); + return -EINVAL; + } + + + /* && defined(OEM_ANDROID) && defined(BCMSDIO) */ + dhd = DHD_DEV_INFO(net); + + /* If driver is already initialized, do nothing + */ + if (dhd->pub.busstate == DHD_BUS_DATA) { + DHD_TRACE(("Driver already Inititalized. Nothing to do")); + return 0; + } + + if (dhd_open(net) < 0) { + DHD_ERROR(("Driver Init Failed \n")); + return -1; + } + + return 0; +} + +int +dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) +{ + +#ifdef WL_CFG80211 + if (wl_cfg80211_notify_ifadd(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) + return BCME_OK; +#endif + + /* handle IF event caused by wl commands, SoftAP, WEXT and + * anything else. This has to be done asynchronously otherwise + * DPC will be blocked (and iovars will timeout as DPC has no chance + * to read the response back) + */ + if (ifevent->ifidx > 0) { + dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); + + memcpy(&if_event->event, ifevent, sizeof(if_event->event)); + memcpy(if_event->mac, mac, ETHER_ADDR_LEN); + strncpy(if_event->name, name, IFNAMSIZ); + if_event->name[IFNAMSIZ - 1] = '\0'; + dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, + DHD_WQ_WORK_IF_ADD, dhd_ifadd_event_handler, DHD_WORK_PRIORITY_LOW); + } + + return BCME_OK; +} + +int +dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) +{ + dhd_if_event_t *if_event; + +#if defined(WL_CFG80211) + if (wl_cfg80211_notify_ifdel(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) + return BCME_OK; +#endif /* WL_CFG80211 */ + + /* handle IF event caused by wl commands, SoftAP, WEXT and + * anything else + */ + if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); + memcpy(&if_event->event, ifevent, sizeof(if_event->event)); + memcpy(if_event->mac, mac, ETHER_ADDR_LEN); + strncpy(if_event->name, name, IFNAMSIZ); + if_event->name[IFNAMSIZ - 1] = '\0'; + dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_DEL, + dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW); + + return BCME_OK; +} + +/* unregister and free the existing net_device interface (if any) in iflist and + * allocate a new one. the slot is reused. this function does NOT register the + * new interface to linux kernel. dhd_register_if does the job + */ +struct net_device* +dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name, + uint8 *mac, uint8 bssidx, bool need_rtnl_lock) +{ + dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; + dhd_if_t *ifp; + + ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS)); + ifp = dhdinfo->iflist[ifidx]; + + if (ifp != NULL) { + if (ifp->net != NULL) { + DHD_ERROR(("%s: free existing IF %s\n", __FUNCTION__, ifp->net->name)); + + dhd_dev_priv_clear(ifp->net); /* clear net_device private */ + + /* in unregister_netdev case, the interface gets freed by net->destructor + * (which is set to free_netdev) + */ + if (ifp->net->reg_state == NETREG_UNINITIALIZED) { + free_netdev(ifp->net); + } else { + netif_stop_queue(ifp->net); + if (need_rtnl_lock) + unregister_netdev(ifp->net); + else + unregister_netdevice(ifp->net); + } + ifp->net = NULL; + } + } else { + ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t)); + if (ifp == NULL) { + DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t))); + return NULL; + } + } + + memset(ifp, 0, sizeof(dhd_if_t)); + ifp->info = dhdinfo; + ifp->idx = ifidx; + ifp->bssidx = bssidx; + if (mac != NULL) + memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN); + + /* Allocate etherdev, including space for private structure */ + ifp->net = alloc_etherdev(DHD_DEV_PRIV_SIZE); + if (ifp->net == NULL) { + DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo))); + goto fail; + } + + /* Setup the dhd interface's netdevice private structure. */ + dhd_dev_priv_save(ifp->net, dhdinfo, ifp, ifidx); + + if (name && name[0]) { + strncpy(ifp->net->name, name, IFNAMSIZ); + ifp->net->name[IFNAMSIZ - 1] = '\0'; + } +#ifdef WL_CFG80211 + if (ifidx == 0) + ifp->net->destructor = free_netdev; + else + ifp->net->destructor = dhd_netdev_free; +#else + ifp->net->destructor = free_netdev; +#endif /* WL_CFG80211 */ + strncpy(ifp->name, ifp->net->name, IFNAMSIZ); + ifp->name[IFNAMSIZ - 1] = '\0'; + dhdinfo->iflist[ifidx] = ifp; + +#ifdef PCIE_FULL_DONGLE + /* Initialize STA info list */ + INIT_LIST_HEAD(&ifp->sta_list); + DHD_IF_STA_LIST_LOCK_INIT(ifp); +#endif /* PCIE_FULL_DONGLE */ + + return ifp->net; + +fail: + if (ifp != NULL) { + if (ifp->net != NULL) { + dhd_dev_priv_clear(ifp->net); + free_netdev(ifp->net); + ifp->net = NULL; + } + MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); + ifp = NULL; + } + dhdinfo->iflist[ifidx] = NULL; + return NULL; +} + +/* unregister and free the the net_device interface associated with the indexed + * slot, also free the slot memory and set the slot pointer to NULL + */ +int +dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) +{ + dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; + dhd_if_t *ifp; + + ifp = dhdinfo->iflist[ifidx]; + if (ifp != NULL) { + if (ifp->net != NULL) { + DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx)); + + /* in unregister_netdev case, the interface gets freed by net->destructor + * (which is set to free_netdev) + */ + if (ifp->net->reg_state == NETREG_UNINITIALIZED) { + free_netdev(ifp->net); + } else { + netif_stop_queue(ifp->net); + + + +#ifdef SET_RPS_CPUS + custom_rps_map_clear(ifp->net->_rx); +#endif /* SET_RPS_CPUS */ + if (need_rtnl_lock) + unregister_netdev(ifp->net); + else + unregister_netdevice(ifp->net); + } + ifp->net = NULL; +#if defined(BCMPCIE) && defined(CUSTOMER_HW5) + if (ifidx == 0) + dhdinfo->register_if_done = FALSE; +#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ + } +#ifdef DHD_WMF + dhd_wmf_cleanup(dhdpub, ifidx); +#endif /* DHD_WMF */ + + dhd_if_del_sta_list(ifp); + + dhdinfo->iflist[ifidx] = NULL; + MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); + + } + + return BCME_OK; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) +static struct net_device_ops dhd_ops_pri = { + .ndo_open = dhd_open, + .ndo_stop = dhd_stop, + .ndo_get_stats = dhd_get_stats, + .ndo_do_ioctl = dhd_ioctl_entry, + .ndo_start_xmit = dhd_start_xmit, + .ndo_set_mac_address = dhd_set_mac_address, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + .ndo_set_rx_mode = dhd_set_multicast_list, +#else + .ndo_set_multicast_list = dhd_set_multicast_list, +#endif +}; + +static struct net_device_ops dhd_ops_virt = { + .ndo_get_stats = dhd_get_stats, + .ndo_do_ioctl = dhd_ioctl_entry, + .ndo_start_xmit = dhd_start_xmit, + .ndo_set_mac_address = dhd_set_mac_address, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + .ndo_set_rx_mode = dhd_set_multicast_list, +#else + .ndo_set_multicast_list = dhd_set_multicast_list, +#endif +}; + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ + +#ifdef DEBUGGER +extern void debugger_init(void *bus_handle); +#endif + + +#ifdef SHOW_LOGTRACE +static char *logstrs_path = "/root/logstrs.bin"; +module_param(logstrs_path, charp, S_IRUGO); + +int +dhd_init_logstrs_array(dhd_event_log_t *temp) +{ + struct file *filep = NULL; + struct kstat stat; + mm_segment_t fs; + char *raw_fmts = NULL; + int logstrs_size = 0; + + logstr_header_t *hdr = NULL; + uint32 *lognums = NULL; + char *logstrs = NULL; + int ram_index = 0; + char **fmts; + int num_fmts = 0; + uint32 i = 0; + int error = 0; + set_fs(KERNEL_DS); + fs = get_fs(); + filep = filp_open(logstrs_path, O_RDONLY, 0); + if (IS_ERR(filep)) { + DHD_ERROR(("Failed to open the file logstrs.bin in %s", __FUNCTION__)); + goto fail; + } + error = vfs_stat(logstrs_path, &stat); + if (error) { + DHD_ERROR(("Failed in %s to find file stat", __FUNCTION__)); + goto fail; + } + logstrs_size = (int) stat.size; + + raw_fmts = kmalloc(logstrs_size, GFP_KERNEL); + if (raw_fmts == NULL) { + DHD_ERROR(("Failed to allocate raw_fmts memory")); + goto fail; + } + if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) { + DHD_ERROR(("Error: Log strings file read failed")); + goto fail; + } + + /* Remember header from the logstrs.bin file */ + hdr = (logstr_header_t *) (raw_fmts + logstrs_size - + sizeof(logstr_header_t)); + + if (hdr->log_magic == LOGSTRS_MAGIC) { + /* + * logstrs.bin start with header. + */ + num_fmts = hdr->rom_logstrs_offset / sizeof(uint32); + ram_index = (hdr->ram_lognums_offset - + hdr->rom_lognums_offset) / sizeof(uint32); + lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset]; + logstrs = (char *) &raw_fmts[hdr->rom_logstrs_offset]; + } else { + /* + * Legacy logstrs.bin format without header. + */ + num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32); + if (num_fmts == 0) { + /* Legacy ROM/RAM logstrs.bin format: + * - ROM 'lognums' section + * - RAM 'lognums' section + * - ROM 'logstrs' section. + * - RAM 'logstrs' section. + * + * 'lognums' is an array of indexes for the strings in the + * 'logstrs' section. The first uint32 is 0 (index of first + * string in ROM 'logstrs' section). + * + * The 4324b5 is the only ROM that uses this legacy format. Use the + * fixed number of ROM fmtnums to find the start of the RAM + * 'lognums' section. Use the fixed first ROM string ("Con\n") to + * find the ROM 'logstrs' section. + */ + #define NUM_4324B5_ROM_FMTS 186 + #define FIRST_4324B5_ROM_LOGSTR "Con\n" + ram_index = NUM_4324B5_ROM_FMTS; + lognums = (uint32 *) raw_fmts; + num_fmts = ram_index; + logstrs = (char *) &raw_fmts[num_fmts << 2]; + while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) { + num_fmts++; + logstrs = (char *) &raw_fmts[num_fmts << 2]; + } + } else { + /* Legacy RAM-only logstrs.bin format: + * - RAM 'lognums' section + * - RAM 'logstrs' section. + * + * 'lognums' is an array of indexes for the strings in the + * 'logstrs' section. The first uint32 is an index to the + * start of 'logstrs'. Therefore, if this index is divided + * by 'sizeof(uint32)' it provides the number of logstr + * entries. + */ + ram_index = 0; + lognums = (uint32 *) raw_fmts; + logstrs = (char *) &raw_fmts[num_fmts << 2]; + } + } + fmts = kmalloc(num_fmts * sizeof(char *), GFP_KERNEL); + if (fmts == NULL) { + DHD_ERROR(("Failed to allocate fmts memory")); + goto fail; + } + + for (i = 0; i < num_fmts; i++) { + /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base + * (they are 0-indexed relative to 'rom_logstrs_offset'). + * + * RAM lognums are already indexed to point to the correct RAM logstrs (they + * are 0-indexed relative to the start of the logstrs.bin file). + */ + if (i == ram_index) { + logstrs = raw_fmts; + } + fmts[i] = &logstrs[lognums[i]]; + } + temp->fmts = fmts; + temp->raw_fmts = raw_fmts; + temp->num_fmts = num_fmts; + filp_close(filep, NULL); + set_fs(fs); + return 0; +fail: + if (raw_fmts) { + kfree(raw_fmts); + raw_fmts = NULL; + } + if (!IS_ERR(filep)) + filp_close(filep, NULL); + set_fs(fs); + temp->fmts = NULL; + return -1; +} +#endif /* SHOW_LOGTRACE */ + + +dhd_pub_t * +dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) +{ + dhd_info_t *dhd = NULL; + struct net_device *net = NULL; + char if_name[IFNAMSIZ] = {'\0'}; + uint32 bus_type = -1; + uint32 bus_num = -1; + uint32 slot_num = -1; + wifi_adapter_info_t *adapter = NULL; + + dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* will implement get_ids for DBUS later */ +#if defined(BCMSDIO) + dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); +#endif + adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); + + /* Allocate primary dhd_info */ + dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t)); + if (dhd == NULL) { + dhd = MALLOC(osh, sizeof(dhd_info_t)); + if (dhd == NULL) { + DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); + goto fail; + } + } + memset(dhd, 0, sizeof(dhd_info_t)); + dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; + + dhd->unit = dhd_found + instance_base; /* do not increment dhd_found, yet */ + + dhd->pub.osh = osh; + dhd->adapter = adapter; + +#ifdef GET_CUSTOM_MAC_ENABLE + wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet); +#endif /* GET_CUSTOM_MAC_ENABLE */ +#ifdef CUSTOM_FORCE_NODFS_FLAG + dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; + dhd->pub.force_country_change = TRUE; +#endif + dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; + dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; + + /* Initialize thread based operation and lock */ + sema_init(&dhd->sdsem, 1); + + /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name. + * This is indeed a hack but we have to make it work properly before we have a better + * solution + */ + dhd_update_fw_nv_path(dhd); + + /* Link to info module */ + dhd->pub.info = dhd; + + + /* Link to bus module */ + dhd->pub.bus = bus; + dhd->pub.hdrlen = bus_hdrlen; + + /* Set network interface name if it was provided as module parameter */ + if (iface_name[0]) { + int len; + char ch; + strncpy(if_name, iface_name, IFNAMSIZ); + if_name[IFNAMSIZ - 1] = 0; + len = strlen(if_name); + ch = if_name[len - 1]; + if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) + strcat(if_name, "%d"); + } + net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE); + if (net == NULL) + goto fail; + dhd_state |= DHD_ATTACH_STATE_ADD_IF; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + net->open = NULL; +#else + net->netdev_ops = NULL; +#endif + + sema_init(&dhd->proto_sem, 1); + +#ifdef PROP_TXSTATUS + spin_lock_init(&dhd->wlfc_spinlock); + + dhd->pub.skip_fc = dhd_wlfc_skip_fc; + dhd->pub.plat_init = dhd_wlfc_plat_init; + dhd->pub.plat_deinit = dhd_wlfc_plat_deinit; +#endif /* PROP_TXSTATUS */ + + /* Initialize other structure content */ + init_waitqueue_head(&dhd->ioctl_resp_wait); + init_waitqueue_head(&dhd->d3ack_wait); + init_waitqueue_head(&dhd->ctrl_wait); + + /* Initialize the spinlocks */ + spin_lock_init(&dhd->sdlock); + spin_lock_init(&dhd->txqlock); + spin_lock_init(&dhd->dhd_lock); + spin_lock_init(&dhd->rxf_lock); +#if defined(RXFRAME_THREAD) + dhd->rxthread_enabled = TRUE; +#endif /* defined(RXFRAME_THREAD) */ + +#ifdef DHDTCPACK_SUPPRESS + spin_lock_init(&dhd->tcpack_lock); +#endif /* DHDTCPACK_SUPPRESS */ + + /* Initialize Wakelock stuff */ + spin_lock_init(&dhd->wakelock_spinlock); + spin_lock_init(&dhd->wakelock_evt_spinlock); + DHD_OS_WAKE_LOCK_INIT(dhd); + dhd->wakelock_wd_counter = 0; +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); +#endif /* CONFIG_HAS_WAKELOCK */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_init(&dhd->dhd_net_if_mutex); + mutex_init(&dhd->dhd_suspend_mutex); +#endif + dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; + + /* Attach and link in the protocol */ + if (dhd_prot_attach(&dhd->pub) != 0) { + DHD_ERROR(("dhd_prot_attach failed\n")); + goto fail; + } + dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; + +#ifdef WL_CFG80211 + /* Attach and link in the cfg80211 */ + if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { + DHD_ERROR(("wl_cfg80211_attach failed\n")); + goto fail; + } + + dhd_monitor_init(&dhd->pub); + dhd_state |= DHD_ATTACH_STATE_CFG80211; +#endif +#if defined(WL_WIRELESS_EXT) + /* Attach and link in the iw */ + if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { + if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { + DHD_ERROR(("wl_iw_attach failed\n")); + goto fail; + } + dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; + } +#endif /* defined(WL_WIRELESS_EXT) */ + +#ifdef SHOW_LOGTRACE + dhd_init_logstrs_array(&dhd->event_data); +#endif /* SHOW_LOGTRACE */ + + if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) { + DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA)); + goto fail; + } + + + /* Set up the watchdog timer */ + init_timer(&dhd->timer); + dhd->timer.data = (ulong)dhd; + dhd->timer.function = dhd_watchdog; + dhd->default_wd_interval = dhd_watchdog_ms; + + if (dhd_watchdog_prio >= 0) { + /* Initialize watchdog thread */ + PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); + + } else { + dhd->thr_wdt_ctl.thr_pid = -1; + } + +#ifdef DEBUGGER + debugger_init((void *) bus); +#endif + + /* Set up the bottom half handler */ + if (dhd_dpc_prio >= 0) { + /* Initialize DPC thread */ + PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); + } else { + /* use tasklet for dpc */ + tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); + dhd->thr_dpc_ctl.thr_pid = -1; + } + + if (dhd->rxthread_enabled) { + bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND); + /* Initialize RXF thread */ + PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf"); + } + + dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; + +#if defined(CONFIG_PM_SLEEP) + if (!dhd_pm_notifier_registered) { + dhd_pm_notifier_registered = TRUE; + register_pm_notifier(&dhd_pm_notifier); + } +#endif /* CONFIG_PM_SLEEP */ + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) + dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; + dhd->early_suspend.suspend = dhd_early_suspend; + dhd->early_suspend.resume = dhd_late_resume; + register_early_suspend(&dhd->early_suspend); + dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ + +#ifdef ARP_OFFLOAD_SUPPORT + dhd->pend_ipaddr = 0; + if (!dhd_inetaddr_notifier_registered) { + dhd_inetaddr_notifier_registered = TRUE; + register_inetaddr_notifier(&dhd_inetaddr_notifier); + } +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef CONFIG_IPV6 + if (!dhd_inet6addr_notifier_registered) { + dhd_inet6addr_notifier_registered = TRUE; + register_inet6addr_notifier(&dhd_inet6addr_notifier); + } +#endif + dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd); +#ifdef DEBUG_CPU_FREQ + dhd->new_freq = alloc_percpu(int); + dhd->freq_trans.notifier_call = dhd_cpufreq_notifier; + cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); +#endif +#ifdef DHDTCPACK_SUPPRESS +#ifdef BCMSDIO + dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DELAYTX); +#elif defined(BCMPCIE) + dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_HOLD); +#else + dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); +#endif /* BCMSDIO */ +#endif /* DHDTCPACK_SUPPRESS */ + + dhd_state |= DHD_ATTACH_STATE_DONE; + dhd->dhd_state = dhd_state; + + dhd_found++; + + (void)dhd_sysfs_init(dhd); + + return &dhd->pub; + +fail: + if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) { + DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", + __FUNCTION__, dhd_state, &dhd->pub)); + dhd->dhd_state = dhd_state; + dhd_detach(&dhd->pub); + dhd_free(&dhd->pub); + } + + return NULL; +} + +int dhd_get_fw_mode(dhd_info_t *dhdinfo) +{ + if (strstr(dhdinfo->fw_path, "_apsta") != NULL) + return DHD_FLAG_HOSTAP_MODE; + if (strstr(dhdinfo->fw_path, "_p2p") != NULL) + return DHD_FLAG_P2P_MODE; + if (strstr(dhdinfo->fw_path, "_ibss") != NULL) + return DHD_FLAG_IBSS_MODE; + if (strstr(dhdinfo->fw_path, "_mfg") != NULL) + return DHD_FLAG_MFG_MODE; + + return DHD_FLAG_STA_MODE; +} + +bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) +{ + int fw_len; + int nv_len; + const char *fw = NULL; + const char *nv = NULL; + wifi_adapter_info_t *adapter = dhdinfo->adapter; + + + /* Update firmware and nvram path. The path may be from adapter info or module parameter + * The path from adapter info is used for initialization only (as it won't change). + * + * The firmware_path/nvram_path module parameter may be changed by the system at run + * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private + * command may change dhdinfo->fw_path. As such we need to clear the path info in + * module parameter after it is copied. We won't update the path until the module parameter + * is changed again (first character is not '\0') + */ + + /* set default firmware and nvram path for built-in type driver */ + if (!dhd_download_fw_on_driverload) { +#ifdef CONFIG_BCMDHD_FW_PATH + fw = CONFIG_BCMDHD_FW_PATH; +#endif /* CONFIG_BCMDHD_FW_PATH */ +#ifdef CONFIG_BCMDHD_NVRAM_PATH + nv = CONFIG_BCMDHD_NVRAM_PATH; +#endif /* CONFIG_BCMDHD_NVRAM_PATH */ + } + + /* check if we need to initialize the path */ + if (dhdinfo->fw_path[0] == '\0') { + if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0') + fw = adapter->fw_path; + + } + if (dhdinfo->nv_path[0] == '\0') { + if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0') + nv = adapter->nv_path; + } + + /* Use module parameter if it is valid, EVEN IF the path has not been initialized + * + * TODO: need a solution for multi-chip, can't use the same firmware for all chips + */ + if (firmware_path[0] != '\0') + fw = firmware_path; + if (nvram_path[0] != '\0') + nv = nvram_path; + + if (fw && fw[0] != '\0') { + fw_len = strlen(fw); + if (fw_len >= sizeof(dhdinfo->fw_path)) { + DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n")); + return FALSE; + } + strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path)); + if (dhdinfo->fw_path[fw_len-1] == '\n') + dhdinfo->fw_path[fw_len-1] = '\0'; + } + if (nv && nv[0] != '\0') { + nv_len = strlen(nv); + if (nv_len >= sizeof(dhdinfo->nv_path)) { + DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n")); + return FALSE; + } + strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path)); + if (dhdinfo->nv_path[nv_len-1] == '\n') + dhdinfo->nv_path[nv_len-1] = '\0'; + } + + /* clear the path in module parameter */ + firmware_path[0] = '\0'; + nvram_path[0] = '\0'; + +#ifndef BCMEMBEDIMAGE + /* fw_path and nv_path are not mandatory for BCMEMBEDIMAGE */ + if (dhdinfo->fw_path[0] == '\0') { + DHD_ERROR(("firmware path not found\n")); + return FALSE; + } + if (dhdinfo->nv_path[0] == '\0') { + DHD_ERROR(("nvram path not found\n")); + return FALSE; + } +#endif /* BCMEMBEDIMAGE */ + + return TRUE; +} + + +int +dhd_bus_start(dhd_pub_t *dhdp) +{ + int ret = -1; + dhd_info_t *dhd = (dhd_info_t*)dhdp->info; + unsigned long flags; + + ASSERT(dhd); + + DHD_TRACE(("Enter %s:\n", __FUNCTION__)); + + DHD_PERIM_LOCK(dhdp); + + /* try to download image and nvram to the dongle */ + if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) { + DHD_INFO(("%s download fw %s, nv %s\n", __FUNCTION__, dhd->fw_path, dhd->nv_path)); + ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, + dhd->fw_path, dhd->nv_path); + if (ret < 0) { + DHD_ERROR(("%s: failed to download firmware %s\n", + __FUNCTION__, dhd->fw_path)); + DHD_PERIM_UNLOCK(dhdp); + return ret; + } + } + if (dhd->pub.busstate != DHD_BUS_LOAD) { + DHD_PERIM_UNLOCK(dhdp); + return -ENETDOWN; + } + + dhd_os_sdlock(dhdp); + + /* Start the watchdog timer */ + dhd->pub.tickcnt = 0; + dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); + + /* Bring up the bus */ + if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { + + DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); + dhd_os_sdunlock(dhdp); + DHD_PERIM_UNLOCK(dhdp); + return ret; + } +#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE) +#if defined(BCMPCIE_OOB_HOST_WAKE) + dhd_os_sdunlock(dhdp); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + /* Host registration for OOB interrupt */ + if (dhd_bus_oob_intr_register(dhdp)) { + /* deactivate timer and wait for the handler to finish */ +#if !defined(BCMPCIE_OOB_HOST_WAKE) + DHD_GENERAL_LOCK(&dhd->pub, flags); + dhd->wd_timer_valid = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + del_timer_sync(&dhd->timer); + + dhd_os_sdunlock(dhdp); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + DHD_PERIM_UNLOCK(dhdp); + DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); + DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); + return -ENODEV; + } + +#if defined(BCMPCIE_OOB_HOST_WAKE) + dhd_os_sdlock(dhdp); + dhd_bus_oob_intr_set(dhdp, TRUE); +#else + /* Enable oob at firmware */ + dhd_enable_oob_intr(dhd->pub.bus, TRUE); +#endif /* BCMPCIE_OOB_HOST_WAKE */ +#endif +#ifdef PCIE_FULL_DONGLE + { + uint8 txpush = 0; + uint32 num_flowrings; /* includes H2D common rings */ + num_flowrings = dhd_bus_max_h2d_queues(dhd->pub.bus, &txpush); + DHD_ERROR(("%s: Initializing %u flowrings\n", __FUNCTION__, + num_flowrings)); + if ((ret = dhd_flow_rings_init(&dhd->pub, num_flowrings)) != BCME_OK) { + dhd_os_sdunlock(dhdp); + DHD_PERIM_UNLOCK(dhdp); + return ret; + } + } +#endif /* PCIE_FULL_DONGLE */ + + /* Do protocol initialization necessary for IOCTL/IOVAR */ + dhd_prot_init(&dhd->pub); + + /* If bus is not ready, can't come up */ + if (dhd->pub.busstate != DHD_BUS_DATA) { + DHD_GENERAL_LOCK(&dhd->pub, flags); + dhd->wd_timer_valid = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + del_timer_sync(&dhd->timer); + DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); + dhd_os_sdunlock(dhdp); + DHD_PERIM_UNLOCK(dhdp); + DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); + return -ENODEV; + } + + dhd_os_sdunlock(dhdp); + + /* Bus is ready, query any dongle information */ + if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) { + DHD_PERIM_UNLOCK(dhdp); + return ret; + } + +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd->pend_ipaddr) { +#ifdef AOE_IP_ALIAS_SUPPORT + aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); +#endif /* AOE_IP_ALIAS_SUPPORT */ + dhd->pend_ipaddr = 0; + } +#endif /* ARP_OFFLOAD_SUPPORT */ + + DHD_PERIM_UNLOCK(dhdp); + return 0; +} +#ifdef WLTDLS +int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac) +{ + uint32 tdls = tdls_on; + int ret = 0; + uint32 tdls_auto_op = 0; + uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING; + int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH; + int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW; + BCM_REFERENCE(mac); + if (!FW_SUPPORTED(dhd, tdls)) + return BCME_ERROR; + + if (dhd->tdls_enable == tdls_on) + goto auto_mode; + ret = dhd_iovar(dhd, 0, "tdls_enable", (char *)&tdls, sizeof(tdls), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret)); + goto exit; + } + dhd->tdls_enable = tdls_on; +auto_mode: + + tdls_auto_op = auto_on; + ret = dhd_iovar(dhd, 0, "tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), NULL, + 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); + goto exit; + } + + if (tdls_auto_op) { + ret = dhd_iovar(dhd, 0, "tdls_idle_time", (char *)&tdls_idle_time, + sizeof(tdls_idle_time), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); + goto exit; + } + ret = dhd_iovar(dhd, 0, "tdls_rssi_high", (char *)&tdls_rssi_high, + sizeof(tdls_rssi_high), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret)); + goto exit; + } + ret = dhd_iovar(dhd, 0, "tdls_rssi_low", (char *)&tdls_rssi_low, + sizeof(tdls_rssi_low), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret)); + goto exit; + } + } + +exit: + return ret; +} +int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret = 0; + if (dhd) + ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac); + else + ret = BCME_ERROR; + return ret; +} +#ifdef PCIE_FULL_DONGLE +void dhd_tdls_update_peer_info(struct net_device *dev, bool connect, uint8 *da) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + dhd_pub_t *dhdp = (dhd_pub_t *)&dhd->pub; + tdls_peer_node_t *cur = dhdp->peer_tbl.node; + tdls_peer_node_t *new = NULL, *prev = NULL; + dhd_if_t *dhdif; + uint8 sa[ETHER_ADDR_LEN]; + int ifidx = dhd_net2idx(dhd, dev); + + if (ifidx == DHD_BAD_IF) + return; + + dhdif = dhd->iflist[ifidx]; + memcpy(sa, dhdif->mac_addr, ETHER_ADDR_LEN); + + if (connect) { + while (cur != NULL) { + if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { + DHD_ERROR(("%s: TDLS Peer exist already %d\n", + __FUNCTION__, __LINE__)); + return; + } + cur = cur->next; + } + + new = MALLOC(dhdp->osh, sizeof(tdls_peer_node_t)); + if (new == NULL) { + DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__)); + return; + } + memcpy(new->addr, da, ETHER_ADDR_LEN); + new->next = dhdp->peer_tbl.node; + dhdp->peer_tbl.node = new; + dhdp->peer_tbl.tdls_peer_count++; + + } else { + while (cur != NULL) { + if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { + dhd_flow_rings_delete_for_peer(dhdp, ifidx, da); + if (prev) + prev->next = cur->next; + else + dhdp->peer_tbl.node = cur->next; + MFREE(dhdp->osh, cur, sizeof(tdls_peer_node_t)); + dhdp->peer_tbl.tdls_peer_count--; + return; + } + prev = cur; + cur = cur->next; + } + DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__)); + } +} +#endif /* PCIE_FULL_DONGLE */ +#endif + +bool dhd_is_concurrent_mode(dhd_pub_t *dhd) +{ + if (!dhd) + return FALSE; + + if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) + return TRUE; + else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == + DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) + return TRUE; + else + return FALSE; +} +#if !defined(AP) && defined(WLP2P) +/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware + * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA + * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware + * would still be named as fw_bcmdhd_apsta. + */ +uint32 +dhd_get_concurrent_capabilites(dhd_pub_t *dhd) +{ + int32 ret = 0; + char buf[WLC_IOCTL_SMLEN]; + bool mchan_supported = FALSE; + /* if dhd->op_mode is already set for HOSTAP and Manufacturing + * test mode, that means we only will use the mode as it is + */ + if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE)) + return 0; + if (FW_SUPPORTED(dhd, vsdb)) { + mchan_supported = TRUE; + } + if (!FW_SUPPORTED(dhd, p2p)) { + DHD_TRACE(("Chip does not support p2p\n")); + return 0; + } + else { + /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ + memset(buf, 0, sizeof(buf)); + ret = dhd_iovar(dhd, 0, "p2p", NULL, 0, (char *)buf, + sizeof(buf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); + return 0; + } + else { + if (buf[0] == 1) { + /* By default, chip supports single chan concurrency, + * now lets check for mchan + */ + ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; + if (mchan_supported) + ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; +#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) + /* For customer_hw4, although ICS, + * we still support concurrent mode + */ + return ret; +#else + return 0; +#endif + } + } + } + return 0; +} +#endif + + + + +int +dhd_preinit_ioctls(dhd_pub_t *dhd) +{ + int ret = 0; + char eventmask[WL_EVENTING_MASK_LEN]; + char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ + uint32 buf_key_b4_m4 = 1; + uint8 msglen; + eventmsgs_ext_t *eventmask_msg = NULL; + char* iov_buf = NULL; + int ret2 = 0; +#ifdef WLAIBSS + aibss_bcn_force_config_t bcn_config; + uint32 aibss; +#ifdef WLAIBSS_PS + uint32 aibss_ps; +#endif /* WLAIBSS_PS */ +#endif /* WLAIBSS */ +#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ + defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) + uint32 ampdu_ba_wsize = 0; +#endif /* CUSTOM_AMPDU_BA_WSIZE ||(WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ +#if defined(CUSTOM_AMPDU_MPDU) + int32 ampdu_mpdu = 0; +#endif +#if defined(CUSTOM_AMPDU_RELEASE) + int32 ampdu_release = 0; +#endif +#if defined(CUSTOM_AMSDU_AGGSF) + int32 amsdu_aggsf = 0; +#endif + +#if defined(BCMSDIO) +#ifdef PROP_TXSTATUS + int wlfc_enable = TRUE; +#ifndef DISABLE_11N + uint32 hostreorder = 1; +#endif /* DISABLE_11N */ +#endif /* PROP_TXSTATUS */ +#endif +#ifndef PCIE_FULL_DONGLE + uint32 wl_ap_isolate; +#endif /* PCIE_FULL_DONGLE */ + +#ifdef DHD_ENABLE_LPC + uint32 lpc = 1; +#endif /* DHD_ENABLE_LPC */ + uint power_mode = PM_FAST; + uint32 dongle_align = DHD_SDALIGN; +#if defined(BCMSDIO) + uint32 glom = CUSTOM_GLOM_SETTING; +#endif /* defined(BCMSDIO) */ +#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) + uint32 credall = 1; +#endif +#ifdef SOMC_WLAN_BCN_TIMEOUT + uint bcn_timeout = SOMC_WLAN_BCN_TIMEOUT; +#else +#if defined(VSDB) || defined(ROAM_ENABLE) + uint bcn_timeout = CUSTOM_BCN_TIMEOUT; +#else + uint bcn_timeout = 4; +#endif +#endif /* SOMC_WLAN_BCN_TIMEOUT */ + uint retry_max = 3; +#if defined(ARP_OFFLOAD_SUPPORT) + int arpoe = 1; +#endif + int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; + int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; + int scan_passive_time = DHD_SCAN_PASSIVE_TIME; + char buf[WLC_IOCTL_SMLEN]; + char *ptr; + uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ +#ifdef ROAM_ENABLE + uint roamvar = 0; + int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; + int roam_scan_period[2] = {10, WLC_BAND_ALL}; + int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; +#ifdef ROAM_AP_ENV_DETECTION + int roam_env_mode = AP_ENV_INDETERMINATE; +#endif /* ROAM_AP_ENV_DETECTION */ +#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC + int roam_fullscan_period = 60; +#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ + int roam_fullscan_period = 120; +#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ +#else +#ifdef DISABLE_BUILTIN_ROAM + uint roamvar = 1; +#endif /* DISABLE_BUILTIN_ROAM */ +#endif /* ROAM_ENABLE */ + +#if defined(SOFTAP) + uint dtim = 1; +#endif +#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) + uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ + struct ether_addr p2p_ea; +#endif +#ifdef BCMCCX + uint32 ccx = 1; +#endif +#ifdef SOFTAP_UAPSD_OFF + uint32 wme_apsd = 0; +#endif /* SOFTAP_UAPSD_OFF */ +#ifdef SET_RETRY_LIMIT + uint srl = CUSTOM_SRL_SETTING; + uint lrl = CUSTOM_LRL_SETTING; +#endif /* SET_RETRY_LIMIT */ +#if (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) + uint32 apsta = 1; /* Enable APSTA mode */ +#elif defined(SOFTAP_AND_GC) + uint32 apsta = 0; + int ap_mode = 1; +#endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */ +#ifdef GET_CUSTOM_MAC_ENABLE + struct ether_addr ea_addr; +#endif /* GET_CUSTOM_MAC_ENABLE */ + +#ifdef DISABLE_11N + uint32 nmode = 0; +#endif /* DISABLE_11N */ + + uint32 vhtmode = 0; +#ifdef USE_WL_TXBF + uint32 txbf = 1; +#endif /* USE_WL_TXBF */ +#ifdef DISABLE_TXBFR + uint32 txbf_bfr_cap = 0; +#endif /* DISABLE_TXBFR */ +#ifdef AMPDU_VO_ENABLE + struct ampdu_tid_control tid; +#endif +#ifdef USE_WL_FRAMEBURST + uint32 frameburst = 1; +#endif /* USE_WL_FRAMEBURST */ +#ifdef DHD_SET_FW_HIGHSPEED + uint32 ack_ratio = 250; + uint32 ack_ratio_depth = 64; +#endif /* DHD_SET_FW_HIGHSPEED */ +#ifdef SUPPORT_2G_VHT + uint32 vht_features = 0x3; /* 2G enable | rates all */ +#endif /* SUPPORT_2G_VHT */ +#ifdef CUSTOM_PSPRETEND_THR + uint32 pspretend_thr = CUSTOM_PSPRETEND_THR; +#endif +#ifdef DISABLE_BCN_DLY + uint bcn_to_dly = 0; +#endif +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = TRUE; +#endif /* PKT_FILTER_SUPPORT */ +#ifdef WLTDLS + dhd->tdls_enable = FALSE; +#endif /* WLTDLS */ + dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; + DHD_TRACE(("Enter %s\n", __FUNCTION__)); + dhd->op_mode = 0; + if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || + (op_mode == DHD_FLAG_MFG_MODE)) { + /* Check and adjust IOCTL response timeout for Manufactring firmware */ + dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT); + DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n", + __FUNCTION__)); + } + else { + dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); + DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__)); + } +#ifdef GET_CUSTOM_MAC_ENABLE + ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet); + if (!ret) { + ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)&ea_addr, ETHER_ADDR_LEN, NULL, 0, + TRUE); + if (ret < 0) { + DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); + ret = BCME_NOTUP; + goto done; + } + memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN); + } else { +#endif /* GET_CUSTOM_MAC_ENABLE */ + /* Get the default device MAC address directly from firmware */ + ret = dhd_iovar(dhd, 0, "cur_etheraddr", NULL, 0, (char *)&buf, sizeof(buf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); + ret = BCME_NOTUP; + goto done; + } + /* Update public MAC address after reading from Firmware */ + memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); + +#ifdef GET_CUSTOM_MAC_ENABLE + } +#endif /* GET_CUSTOM_MAC_ENABLE */ + + /* get a capabilities from firmware */ + memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities)); + ret = dhd_iovar(dhd, 0, "cap", NULL, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities), + FALSE); + if (ret < 0) { + DHD_ERROR(("%s: Get Capability failed (error=%d)\n", + __FUNCTION__, ret)); + goto done; + } + if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) || + (op_mode == DHD_FLAG_HOSTAP_MODE)) { +#ifdef SET_RANDOM_MAC_SOFTAP + uint rand_mac; +#endif + dhd->op_mode = DHD_FLAG_HOSTAP_MODE; +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 0; +#endif +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = FALSE; +#endif +#ifdef SET_RANDOM_MAC_SOFTAP + SRANDOM32((uint)jiffies); + rand_mac = RANDOM32(); + iovbuf[0] = 0x02; /* locally administered bit */ + iovbuf[1] = 0x1A; + iovbuf[2] = 0x11; + iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; + iovbuf[4] = (unsigned char)(rand_mac >> 8); + iovbuf[5] = (unsigned char)(rand_mac >> 16); + + ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)iovbuf, ETHER_ADDR_LEN, NULL, 0, + TRUE); + if (ret < 0) { + DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); + } else + memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); +#endif /* SET_RANDOM_MAC_SOFTAP */ +#if !defined(AP) && defined(WL_CFG80211) + /* Turn off MPC in AP mode */ + ret = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, + sizeof(mpc), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); + } +#endif +#ifdef SOFTAP_UAPSD_OFF + ret = dhd_iovar(dhd, 0, "wme_apsd", (char *)&wme_apsd, sizeof(wme_apsd), NULL, 0, + TRUE); + if (ret < 0) { + DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n", + __FUNCTION__, ret)); + } +#endif /* SOFTAP_UAPSD_OFF */ +#ifdef SET_RETRY_LIMIT + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SRL, (char *)&srl, + sizeof(srl), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set SRL failed %d\n", __FUNCTION__, ret)); + } + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_LRL, (char *)&lrl, + sizeof(lrl), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set LRL failed %d\n", __FUNCTION__, ret)); + } +#endif /* SET_RETRY_LIMIT */ + } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || + (op_mode == DHD_FLAG_MFG_MODE)) { +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 0; +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = FALSE; +#endif /* PKT_FILTER_SUPPORT */ + dhd->op_mode = DHD_FLAG_MFG_MODE; + } else { + uint32 concurrent_mode = 0; + if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) || + (op_mode == DHD_FLAG_P2P_MODE)) { +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 0; +#endif +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = FALSE; +#endif + dhd->op_mode = DHD_FLAG_P2P_MODE; + } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) || + (op_mode == DHD_FLAG_IBSS_MODE)) { + dhd->op_mode = DHD_FLAG_IBSS_MODE; + } else + dhd->op_mode = DHD_FLAG_STA_MODE; +#if !defined(AP) && defined(WLP2P) + if (dhd->op_mode != DHD_FLAG_IBSS_MODE && + (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 1; +#endif + dhd->op_mode |= concurrent_mode; + } + + /* Check if we are enabling p2p */ + if (dhd->op_mode & DHD_FLAG_P2P_MODE) { + ret = dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, + TRUE); + if (ret < 0) + DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret)); + +#if defined(SOFTAP_AND_GC) + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP, + (char *)&ap_mode, sizeof(ap_mode), TRUE, 0)) < 0) { + DHD_ERROR(("%s WLC_SET_AP failed %d\n", __FUNCTION__, ret)); + } +#endif + memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); + ETHER_SET_LOCALADDR(&p2p_ea); + ret = dhd_iovar(dhd, 0, "p2p_da_override", (char *)&p2p_ea, sizeof(p2p_ea), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); + else + DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); + } +#else + (void)concurrent_mode; +#endif + } + + DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n", + dhd->op_mode, MAC2STRDBG(dhd->mac.octet))); + /* Set Country code */ + if (dhd->dhd_cspec.ccode[0] != 0) { + ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); + } + +#if !defined(DISABLE_11AC) + if (somc_disable_vht) + { +#endif /* ! DISABLE_11AC */ + ret = dhd_iovar(dhd, 0, "vhtmode", (char *)&vhtmode, sizeof(vhtmode), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s wl vhtmode 0 failed %d\n", __FUNCTION__, ret)); + else + DHD_ERROR(("%s VHT(11ac) mode is disabled\n", __FUNCTION__)); +#if !defined(DISABLE_11AC) + } +#endif /* ! DISABLE_11AC */ + + /* Set Listen Interval */ + ret = dhd_iovar(dhd, 0, "assoc_listen", (char *)&listen_interval, sizeof(listen_interval), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); + +#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) + /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ + dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), NULL, 0, TRUE); +#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ +#if defined(ROAM_ENABLE) + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, + sizeof(roam_scan_period), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret)); + if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, + sizeof(roam_delta), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); + ret = dhd_iovar(dhd, 0, "fullroamperiod", (char *)&roam_fullscan_period, + sizeof(roam_fullscan_period), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); +#ifdef ROAM_AP_ENV_DETECTION + if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) { + if (dhd_iovar(dhd, 0, "roam_env_detection", (char *)&roam_env_mode, + sizeof(roam_env_mode), NULL, 0, TRUE) == BCME_OK) + dhd->roam_env_detection = TRUE; + else + dhd->roam_env_detection = FALSE; + } +#endif /* ROAM_AP_ENV_DETECTION */ +#endif /* ROAM_ENABLE */ + +#ifdef BCMCCX + dhd_iovar(dhd, 0, "ccx_enable", (char *)&ccx, sizeof(ccx), NULL, 0, TRUE); +#endif /* BCMCCX */ +#ifdef WLTDLS + /* by default TDLS on and auto mode off */ + _dhd_tdls_enable(dhd, true, false, NULL); +#endif /* WLTDLS */ + +#ifdef DHD_ENABLE_LPC + /* Set lpc 1 */ + ret = dhd_iovar(dhd, 0, "lpc", (char *)&lpc, sizeof(lpc), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); + } +#endif /* DHD_ENABLE_LPC */ + + /* Set PowerSave mode */ + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); + + /* Match Host and Dongle rx alignment */ + dhd_iovar(dhd, 0, "bus:txglomalign", (char *)&dongle_align, sizeof(dongle_align), + NULL, 0, TRUE); + +#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) + /* enable credall to reduce the chance of no bus credit happened. */ + dhd_iovar(dhd, 0, "bus:credall", (char *)&credall, sizeof(credall), NULL, 0, TRUE); +#endif + +#if defined(BCMSDIO) + if (glom != DEFAULT_GLOM_VALUE) { + DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom)); + dhd_iovar(dhd, 0, "bus:txglom", (char *)&glom, sizeof(glom), NULL, 0, TRUE); + } +#endif /* defined(BCMSDIO) */ + + /* Setup timeout if Beacons are lost and roam is off to report link down */ + dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, sizeof(bcn_timeout), NULL, 0, TRUE); +#ifdef SOMC_WLAN_SCAN_NPROBES + { + const uint32 scan_nprobes = SOMC_WLAN_SCAN_NPROBES; + if (( ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_NPROBES, (char *)&scan_nprobes, + sizeof(scan_nprobes), TRUE, 0)) < 0) + DHD_ERROR(("%s: set scan_nprobes failed %d\n", __FUNCTION__, ret)); + } +#endif + +#ifdef SOMC_WLAN_ENABLE_SCAN_PS + { + const uint32 scan_ps = 1; + dhd_iovar(dhd, 0, "scan_ps", (char *)&scan_ps, sizeof(scan_ps), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s scan_ps failed %d\n", __FUNCTION__, ret)); + } +#endif + +#ifdef DISABLE_BCN_DLY + /* Set bcn_to_dly to delay link down until roam complete */ + dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, sizeof(bcn_to_dly), NULL, 0, TRUE); +#endif + /* Setup assoc_retry_max count to reconnect target AP in dongle */ + dhd_iovar(dhd, 0, "assoc_retry_max", (char *)&retry_max, sizeof(retry_max), NULL, 0, TRUE); +#if defined(AP) && !defined(WLP2P) + /* Turn off MPC in AP mode */ + dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); + dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, TRUE); +#endif /* defined(AP) && !defined(WLP2P) */ + + +#if defined(SOFTAP) + if (ap_fw_loaded == TRUE) { + dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); + } +#endif + +#if defined(KEEP_ALIVE) + { + /* Set Keep Alive : be sure to use FW with -keepalive */ + int res; + +#if defined(SOFTAP) + if (ap_fw_loaded == FALSE) +#endif + if (!(dhd->op_mode & + (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) { + if ((res = dhd_keep_alive_onoff(dhd)) < 0) + DHD_ERROR(("%s set keeplive failed %d\n", + __FUNCTION__, res)); + } + } +#endif /* defined(KEEP_ALIVE) */ + +#ifdef USE_WL_TXBF + ret = dhd_iovar(dhd, 0, "txbf", (char *)&txbf, sizeof(txbf), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret)); + } +#endif /* USE_WL_TXBF */ +#ifdef DISABLE_TXBFR + ret = dhd_iovar(dhd, 0, "txbf_bfr_cap", (char *)&txbf_bfr_cap, sizeof(txbf_bfr_cap), NULL, + 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Clear txbf_bfr_cap failed %d\n", __FUNCTION__, ret)); + } +#endif /* DISABLE_TXBFR */ +#ifdef USE_WL_FRAMEBURST + /* Set frameburst to value */ + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst, + sizeof(frameburst), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set frameburst failed %d\n", __FUNCTION__, ret)); + } +#endif /* USE_WL_FRAMEBURST */ +#ifdef DHD_SET_FW_HIGHSPEED + /* Set ack_ratio */ + ret = dhd_iovar(dhd, 0, "ack_ratio", (char *)&ack_ratio, sizeof(ack_ratio), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set ack_ratio failed %d\n", __FUNCTION__, ret)); + } + + /* Set ack_ratio_depth */ + ret = dhd_iovar(dhd, 0, "ack_ratio_depth", (char *)&ack_ratio_depth, + sizeof(ack_ratio_depth), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set ack_ratio_depth failed %d\n", __FUNCTION__, ret)); + } +#endif /* DHD_SET_FW_HIGHSPEED */ +#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ + defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) + /* Set ampdu ba wsize to 64 or 16 */ +#ifdef CUSTOM_AMPDU_BA_WSIZE + ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE; +#endif +#if defined(WLAIBSS) && defined(CUSTOM_IBSS_AMPDU_BA_WSIZE) + if (dhd->op_mode == DHD_FLAG_IBSS_MODE) + ampdu_ba_wsize = CUSTOM_IBSS_AMPDU_BA_WSIZE; +#endif /* WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE */ + if (ampdu_ba_wsize != 0) { + ret = dhd_iovar(dhd, 0, "ampdu_ba_wsize", (char *)&du_ba_wsize, + sizeof(ampdu_ba_wsize), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n", + __FUNCTION__, ampdu_ba_wsize, ret)); + } + } +#endif /* CUSTOM_AMPDU_BA_WSIZE || (WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ + + iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + if (iov_buf == NULL) { + DHD_ERROR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN)); + ret = BCME_NOMEM; + goto done; + } +#ifdef WLAIBSS + /* Configure custom IBSS beacon transmission */ + if (dhd->op_mode & DHD_FLAG_IBSS_MODE) + { + aibss = 1; + ret = dhd_iovar(dhd, 0, "aibss", (char *)&aibss, sizeof(aibss), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set aibss to %d failed %d\n", + __FUNCTION__, aibss, ret)); + } +#ifdef WLAIBSS_PS + aibss_ps = 1; + ret = dhd_iovar(dhd, 0, "aibss_ps", (char *)&aibss_ps, sizeof(aibss_ps), + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set aibss PS to %d failed %d\n", + __FUNCTION__, aibss, ret)); + } +#endif /* WLAIBSS_PS */ + } + memset(&bcn_config, 0, sizeof(bcn_config)); + bcn_config.initial_min_bcn_dur = AIBSS_INITIAL_MIN_BCN_DUR; + bcn_config.min_bcn_dur = AIBSS_MIN_BCN_DUR; + bcn_config.bcn_flood_dur = AIBSS_BCN_FLOOD_DUR; + bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0; + bcn_config.len = sizeof(bcn_config); + + ret = dhd_iovar(dhd, 0, "aibss_bcn_force_config", (char *)&bcn_config, + sizeof(aibss_bcn_force_config_t), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set aibss_bcn_force_config to %d, %d, %d failed %d\n", + __FUNCTION__, AIBSS_INITIAL_MIN_BCN_DUR, AIBSS_MIN_BCN_DUR, + AIBSS_BCN_FLOOD_DUR, ret)); + } +#endif /* WLAIBSS */ + +#if defined(CUSTOM_AMPDU_MPDU) + ampdu_mpdu = CUSTOM_AMPDU_MPDU; + if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) { + ret = dhd_iovar(dhd, 0, "ampdu_mpdu", (char *)&du_mpdu, sizeof(ampdu_mpdu), + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n", + __FUNCTION__, CUSTOM_AMPDU_MPDU, ret)); + } + } +#endif /* CUSTOM_AMPDU_MPDU */ + +#if defined(CUSTOM_AMPDU_RELEASE) + ampdu_release = CUSTOM_AMPDU_RELEASE; + if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) { + ret = dhd_iovar(dhd, 0, "ampdu_release", (char *)&du_release, + sizeof(ampdu_release), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set ampdu_release to %d failed %d\n", + __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret)); + } + } +#endif /* CUSTOM_AMPDU_RELEASE */ + +#if defined(CUSTOM_AMSDU_AGGSF) + amsdu_aggsf = CUSTOM_AMSDU_AGGSF; + if (amsdu_aggsf != 0) { + ret = dhd_iovar(dhd, 0, "amsdu_aggsf", (char *)&amsdu_aggsf, sizeof(amsdu_aggsf), + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set amsdu_aggsf to %d failed %d\n", + __FUNCTION__, CUSTOM_AMSDU_AGGSF, ret)); + } + } +#endif /* CUSTOM_AMSDU_AGGSF */ + +#ifdef SUPPORT_2G_VHT + ret = dhd_iovar(dhd, 0, "vht_features", (char *)&vht_features, sizeof(vht_features), + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret)); + } +#endif /* SUPPORT_2G_VHT */ +#ifdef CUSTOM_PSPRETEND_THR + /* Turn off MPC in AP mode */ + ret = dhd_iovar(dhd, 0, "pspretend_threshold", (char *)&pspretend_thr, + sizeof(pspretend_thr), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n", + __FUNCTION__, ret)); + } +#endif + + ret = dhd_iovar(dhd, 0, "buf_key_b4_m4", (char *)&buf_key_b4_m4, sizeof(buf_key_b4_m4), + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret)); + } + + /* Read event_msgs mask */ + ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, + sizeof(iovbuf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret)); + goto done; + } + bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); + + /* Setup event_msgs */ + setbit(eventmask, WLC_E_SET_SSID); + setbit(eventmask, WLC_E_PRUNE); + setbit(eventmask, WLC_E_AUTH); + setbit(eventmask, WLC_E_AUTH_IND); + setbit(eventmask, WLC_E_ASSOC); + setbit(eventmask, WLC_E_REASSOC); + setbit(eventmask, WLC_E_REASSOC_IND); + setbit(eventmask, WLC_E_DEAUTH); + setbit(eventmask, WLC_E_DEAUTH_IND); + setbit(eventmask, WLC_E_DISASSOC_IND); + setbit(eventmask, WLC_E_DISASSOC); + setbit(eventmask, WLC_E_JOIN); + setbit(eventmask, WLC_E_START); + setbit(eventmask, WLC_E_ASSOC_IND); + setbit(eventmask, WLC_E_PSK_SUP); + setbit(eventmask, WLC_E_LINK); + setbit(eventmask, WLC_E_NDIS_LINK); + setbit(eventmask, WLC_E_MIC_ERROR); + setbit(eventmask, WLC_E_ASSOC_REQ_IE); + setbit(eventmask, WLC_E_ASSOC_RESP_IE); +#ifndef WL_CFG80211 + setbit(eventmask, WLC_E_PMKID_CACHE); + setbit(eventmask, WLC_E_TXFAIL); +#endif + setbit(eventmask, WLC_E_JOIN_START); + setbit(eventmask, WLC_E_SCAN_COMPLETE); +#ifdef WLMEDIA_HTSF + setbit(eventmask, WLC_E_HTSFSYNC); +#endif /* WLMEDIA_HTSF */ +#ifdef PNO_SUPPORT + setbit(eventmask, WLC_E_PFN_NET_FOUND); + setbit(eventmask, WLC_E_PFN_BEST_BATCHING); + setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND); + setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST); +#endif /* PNO_SUPPORT */ + /* enable dongle roaming event */ + setbit(eventmask, WLC_E_ROAM); + setbit(eventmask, WLC_E_BSSID); +#ifdef BCMCCX + setbit(eventmask, WLC_E_ADDTS_IND); + setbit(eventmask, WLC_E_DELTS_IND); +#endif /* BCMCCX */ +#ifdef WLTDLS + setbit(eventmask, WLC_E_TDLS_PEER_EVENT); +#endif /* WLTDLS */ +#ifdef RTT_SUPPORT + setbit(eventmask, WLC_E_PROXD); +#endif /* RTT_SUPPORT */ +#ifdef WL_CFG80211 + setbit(eventmask, WLC_E_ESCAN_RESULT); + if (dhd->op_mode & DHD_FLAG_P2P_MODE) { + setbit(eventmask, WLC_E_ACTION_FRAME_RX); + setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); + } +#endif /* WL_CFG80211 */ +#ifdef WLAIBSS + setbit(eventmask, WLC_E_AIBSS_TXFAIL); +#endif /* WLAIBSS */ + setbit(eventmask, WLC_E_TRACE); + setbit(eventmask, WLC_E_CSA_COMPLETE_IND); + /* Write updated Event mask */ + ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret)); + goto done; + } + + /* make up event mask ext message iovar for event larger than 128 */ + msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE; + eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL); + if (eventmask_msg == NULL) { + DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen)); + ret = BCME_NOMEM; + goto done; + } + bzero(eventmask_msg, msglen); + eventmask_msg->ver = EVENTMSGS_VER; + eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; + + /* Read event_msgs_ext mask */ + ret2 = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, + WLC_IOCTL_SMLEN, FALSE); + if (ret2 != BCME_UNSUPPORTED) + ret = ret2; + if (ret2 == 0) { /* event_msgs_ext must be supported */ + bcopy(iov_buf, eventmask_msg, msglen); +#ifdef GSCAN_SUPPORT + setbit(eventmask_msg->mask, WLC_E_PFN_GSCAN_FULL_RESULT); + setbit(eventmask_msg->mask, WLC_E_PFN_SCAN_COMPLETE); + setbit(eventmask_msg->mask, WLC_E_PFN_SWC); + setbit(eventmask_msg->mask, WLC_E_PFN_SSID_EXT); +#endif /* GSCAN_SUPPORT */ +#ifdef BT_WIFI_HANDOVER + setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ); +#endif /* BT_WIFI_HANDOVER */ + + /* Write updated Event mask */ + eventmask_msg->ver = EVENTMSGS_VER; + eventmask_msg->command = EVENTMSGS_SET_MASK; + eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; + ret = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, NULL, 0, + TRUE); + if (ret < 0) { + DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret)); + goto done; + } + } else if (ret2 < 0 && ret2 != BCME_UNSUPPORTED) { + DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2)); + goto done; + } /* unsupported is ok */ + + dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, + sizeof(scan_assoc_time), TRUE, 0); + dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, + sizeof(scan_unassoc_time), TRUE, 0); + dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, + sizeof(scan_passive_time), TRUE, 0); + +#ifdef ARP_OFFLOAD_SUPPORT + /* Set and enable ARP offload feature for STA only */ +#if defined(SOFTAP) + if (arpoe && !ap_fw_loaded) { +#else + if (arpoe) { +#endif + dhd_arp_offload_enable(dhd, TRUE); + dhd_arp_offload_set(dhd, dhd_arp_mode); + } else { + dhd_arp_offload_enable(dhd, FALSE); + dhd_arp_offload_set(dhd, 0); + } + dhd_arp_enable = arpoe; +#endif /* ARP_OFFLOAD_SUPPORT */ + +#ifdef PKT_FILTER_SUPPORT + /* Setup default defintions for pktfilter , enable in suspend */ + dhd->pktfilter_count = 6; + /* Setup filter to allow only unicast */ + dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; + dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; + dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; + dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; + /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ + dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; + /* apply APP pktfilter */ + dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; + + +#if defined(SOFTAP) + if (ap_fw_loaded) { + dhd_enable_packet_filter(0, dhd); + } +#endif /* defined(SOFTAP) */ + dhd_set_packet_filter(dhd); +#endif /* PKT_FILTER_SUPPORT */ +#ifdef DISABLE_11N + ret = dhd_iovar(dhd, 0, "nmode", (char *)&nmode, sizeof(nmode), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); +#endif /* DISABLE_11N */ + +#ifdef AMPDU_VO_ENABLE + tid.tid = PRIO_8021D_VO; /* Enable TID(6) for voice */ + tid.enable = TRUE; + dhd_iovar(dhd, 0, "ampdu_tid", (char *)&tid, sizeof(tid), NULL, 0, TRUE); + + tid.tid = PRIO_8021D_NC; /* Enable TID(7) for voice */ + tid.enable = TRUE; + dhd_iovar(dhd, 0, "ampdu_tid", (char *)&tid, sizeof(tid), NULL, 0, TRUE); +#endif +#ifdef SOMC_MAX_ASSOC_NUM + { + /* Set the maximum number of stations for P2P / SoftAP */ + const uint32 max = SOMC_MAX_ASSOC_NUM; + dhd_iovar(dhd, 0, "maxassoc", (char *)&max, sizeof(max), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s: maxassoc set failed %d\n", __FUNCTION__, ret)); + } +#endif /* SOMC_MAX_ASSOC_NUM */ + + /* query for 'ver' to get version info from firmware */ + memset(buf, 0, sizeof(buf)); + ptr = buf; + ret = dhd_iovar(dhd, 0, "ver", NULL, 0, (char *)&buf, sizeof(buf), FALSE); + if (ret < 0) + DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); + else { + bcmstrtok(&ptr, "\n", 0); + /* Print fw version info */ + DHD_ERROR(("Firmware version = %s\n", buf)); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + snprintf(bcm_wlan_ver_info, sizeof(bcm_wlan_ver_info), + "firmware_version %s\ndhd_version %s\n", + buf, EPI_VERSION_STR); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ +#if defined(BCMSDIO) + dhd_set_version_info(dhd, buf); +#endif /* defined(BCMSDIO) */ + } + +#if defined(BCMSDIO) + dhd_txglom_enable(dhd, TRUE); +#endif /* defined(BCMSDIO) */ + +#if defined(BCMSDIO) +#ifdef PROP_TXSTATUS + if (disable_proptx || +#ifdef PROP_TXSTATUS_VSDB + /* enable WLFC only if the firmware is VSDB when it is in STA mode */ + (dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) || +#endif /* PROP_TXSTATUS_VSDB */ + FALSE) { + wlfc_enable = FALSE; + } + +#ifndef DISABLE_11N + ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, sizeof(hostreorder), + NULL, 0, TRUE); + if (ret2 < 0) { + DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2)); + if (ret2 != BCME_UNSUPPORTED) + ret = ret2; +#if defined(CUSTOMER_HW5) + if (ret == BCME_NOTDOWN) { + uint wl_down = 1; + ret2 = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, + sizeof(wl_down), TRUE, 0); + DHD_ERROR(("%s ampdu_hostreorder fail WL_DOWN : %d, hostreorder :%d\n", + __FUNCTION__, ret2, hostreorder)); + + ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, + sizeof(hostreorder), NULL, 0, TRUE); + DHD_ERROR(("%s wl ampdu_hostreorder. ret --> %d\n", __FUNCTION__, ret2)); + if (ret2 != BCME_UNSUPPORTED) + ret = ret2; + } +#endif + if (ret2 != BCME_OK) + hostreorder = 0; + } +#endif /* DISABLE_11N */ + + + if (wlfc_enable) + dhd_wlfc_init(dhd); +#ifndef DISABLE_11N + else if (hostreorder) + dhd_wlfc_hostreorder_init(dhd); +#endif /* DISABLE_11N */ + +#endif /* PROP_TXSTATUS */ +#endif /* BCMSDIO || BCMBUS */ +#ifndef PCIE_FULL_DONGLE + /* For FD we need all the packets at DHD to handle intra-BSS forwarding */ + if (FW_SUPPORTED(dhd, ap)) { + wl_ap_isolate = AP_ISOLATE_SENDUP_ALL; + ret = dhd_iovar(dhd, 0, "ap_isolate", (char *)&wl_ap_isolate, sizeof(wl_ap_isolate), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); + } +#endif /* PCIE_FULL_DONGLE */ +#ifdef PNO_SUPPORT + if (!dhd->pno_state) { + dhd_pno_init(dhd); + } +#endif +#ifdef RTT_SUPPORT + if (!dhd->rtt_state) { + ret = dhd_rtt_init(dhd); + if (ret < 0) { + DHD_ERROR(("%s failed to initialize RTT\n", __FUNCTION__)); + } + } +#endif +#ifdef WL11U + dhd_interworking_enable(dhd); +#endif /* WL11U */ + +done: + + if (eventmask_msg) + kfree(eventmask_msg); + if (iov_buf) + kfree(iov_buf); + + return ret; +} + +int +dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, char *res_buf, + uint res_len, int set) +{ + char *buf = NULL; + int input_len; + wl_ioctl_t ioc; + int ret; + + if (res_len > WLC_IOCTL_MAXLEN || param_len > WLC_IOCTL_MAXLEN) + return BCME_BADARG; + + input_len = strlen(name) + 1 + param_len; + if (input_len > WLC_IOCTL_MAXLEN) + return BCME_BADARG; + + buf = NULL; + if (set) { + if (res_buf || res_len != 0) { + DHD_ERROR(("%s: SET wrong arguemnet\n", __FUNCTION__)); + ret = BCME_BADARG; + goto exit; + } + buf = kzalloc(input_len, GFP_KERNEL); + if (!buf) { + DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); + if (!ret) { + ret = BCME_NOMEM; + goto exit; + } + + ioc.cmd = WLC_SET_VAR; + ioc.buf = buf; + ioc.len = input_len; + ioc.set = set; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + } else { + if (!res_buf || !res_len) { + DHD_ERROR(("%s: GET failed. resp_buf NULL or length 0.\n", __FUNCTION__)); + ret = BCME_BADARG; + goto exit; + } + + if (res_len < input_len) { + DHD_INFO(("%s: res_len(%d) < input_len(%d)\n", __FUNCTION__, + res_len, input_len)); + buf = kzalloc(input_len, GFP_KERNEL); + if (!buf) { + DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); + if (!ret) { + ret = BCME_NOMEM; + goto exit; + } + + ioc.cmd = WLC_GET_VAR; + ioc.buf = buf; + ioc.len = input_len; + ioc.set = set; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + + if (ret == BCME_OK) { + memcpy(res_buf, buf, res_len); + } + } else { + memset(res_buf, 0, res_len); + ret = bcm_mkiovar(name, param_buf, param_len, res_buf, res_len); + if (!ret) { + ret = BCME_NOMEM; + goto exit; + } + + ioc.cmd = WLC_GET_VAR; + ioc.buf = res_buf; + ioc.len = res_len; + ioc.set = set; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + } + } +exit: + kfree(buf); + return ret; +} + +int +dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, + uint cmd_len, char **resptr, uint resp_len) +{ + int len = resp_len; + int ret; + char *buf = *resptr; + wl_ioctl_t ioc; + if (resp_len > WLC_IOCTL_MAXLEN) + return BCME_BADARG; + + memset(buf, 0, resp_len); + + bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); + + memset(&ioc, 0, sizeof(ioc)); + + ioc.cmd = WLC_GET_VAR; + ioc.buf = buf; + ioc.len = len; + ioc.set = 0; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + + return ret; +} + +int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) +{ + struct dhd_info *dhd = dhdp->info; + struct net_device *dev = NULL; + + ASSERT(dhd && dhd->iflist[ifidx]); + dev = dhd->iflist[ifidx]->net; + ASSERT(dev); + + if (netif_running(dev)) { + DHD_ERROR(("%s: Must be down to change its MTU", dev->name)); + return BCME_NOTDOWN; + } + +#define DHD_MIN_MTU 1500 +#define DHD_MAX_MTU 1752 + + if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { + DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu)); + return BCME_BADARG; + } + + dev->mtu = new_mtu; + return 0; +} + +#ifdef ARP_OFFLOAD_SUPPORT +/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ +void +aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx) +{ + u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ + int i; + int ret; + + bzero(ipv4_buf, sizeof(ipv4_buf)); + + /* display what we've got */ + ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); + DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__)); + if (ret) { + DHD_ERROR(("%s failed\n", __FUNCTION__)); + return; + } +#ifdef AOE_DBG + dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ +#endif + /* now we saved hoste_ip table, clr it in the dongle AOE */ + dhd_aoe_hostip_clr(dhd_pub, idx); + + for (i = 0; i < MAX_IPV4_ENTRIES; i++) { + if (add && (ipv4_buf[i] == 0)) { + ipv4_buf[i] = ipa; + add = FALSE; /* added ipa to local table */ + DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n", + __FUNCTION__, i)); + } else if (ipv4_buf[i] == ipa) { + ipv4_buf[i] = 0; + DHD_ARPOE(("%s: removed IP:%x from temp table %d\n", + __FUNCTION__, ipa, i)); + } + + if (ipv4_buf[i] != 0) { + /* add back host_ip entries from our local cache */ + dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx); + DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n", + __FUNCTION__, ipv4_buf[i], i)); + } + } +#ifdef AOE_DBG + /* see the resulting hostip table */ + dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); + DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__)); + dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ +#endif +} + +/* + * Notification mechanism from kernel to our driver. This function is called by the Linux kernel + * whenever there is an event related to an IP address. + * ptr : kernel provided pointer to IP address that has changed + */ +static int dhd_inetaddr_notifier_call(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + + dhd_info_t *dhd; + dhd_pub_t *dhd_pub; + int idx; + + if (!dhd_arp_enable) + return NOTIFY_DONE; + if (!ifa || !(ifa->ifa_dev->dev)) + return NOTIFY_DONE; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) + /* Filter notifications meant for non Broadcom devices */ + if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) && + (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) { +#if defined(WL_ENABLE_P2P_IF) + if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) +#endif /* WL_ENABLE_P2P_IF */ + return NOTIFY_DONE; + } +#endif /* LINUX_VERSION_CODE */ + + dhd = DHD_DEV_INFO(ifa->ifa_dev->dev); + if (!dhd) + return NOTIFY_DONE; + + dhd_pub = &dhd->pub; + + if (dhd_pub->arp_version == 1) { + idx = 0; + } + else { + for (idx = 0; idx < DHD_MAX_IFS; idx++) { + if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev) + break; + } + if (idx < DHD_MAX_IFS) + DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net, + dhd->iflist[idx]->name, dhd->iflist[idx]->idx)); + else { + DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label)); + idx = 0; + } + } + + switch (event) { + case NETDEV_UP: + DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", + __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); + + if (dhd->pub.busstate != DHD_BUS_DATA) { + DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); + if (dhd->pend_ipaddr) { + DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", + __FUNCTION__, dhd->pend_ipaddr)); + } + dhd->pend_ipaddr = ifa->ifa_address; + break; + } + +#ifdef AOE_IP_ALIAS_SUPPORT + DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", + __FUNCTION__)); + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx); +#endif /* AOE_IP_ALIAS_SUPPORT */ + break; + + case NETDEV_DOWN: + DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", + __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); + dhd->pend_ipaddr = 0; +#ifdef AOE_IP_ALIAS_SUPPORT + DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n", + __FUNCTION__)); + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx); +#else + dhd_aoe_hostip_clr(&dhd->pub, idx); + dhd_aoe_arp_clr(&dhd->pub, idx); +#endif /* AOE_IP_ALIAS_SUPPORT */ + break; + + default: + DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n", + __func__, ifa->ifa_label, event)); + break; + } + return NOTIFY_DONE; +} +#endif /* ARP_OFFLOAD_SUPPORT */ + +#ifdef CONFIG_IPV6 +/* Neighbor Discovery Offload: defered handler */ +static void +dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event) +{ + struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data; + dhd_pub_t *pub = &((dhd_info_t *)dhd_info)->pub; + int ret; + + if (event != DHD_WQ_WORK_IPV6_NDO) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + + if (!ndo_work) { + DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__)); + return; + } + + if (!pub) { + DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__)); + return; + } + + if (ndo_work->if_idx) { + DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx)); + return; + } + + switch (ndo_work->event) { + case NETDEV_UP: + DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__)); + ret = dhd_ndo_enable(pub, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret)); + } + + ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx); + if (ret < 0) { + DHD_ERROR(("%s: Adding host ip for NDO failed %d\n", + __FUNCTION__, ret)); + } + break; + case NETDEV_DOWN: + DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__)); + ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx); + if (ret < 0) { + DHD_ERROR(("%s: Removing host ip for NDO failed %d\n", + __FUNCTION__, ret)); + goto done; + } + + ret = dhd_ndo_enable(pub, FALSE); + if (ret < 0) { + DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret)); + goto done; + } + break; + default: + DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__)); + break; + } +done: + /* free ndo_work. alloced while scheduling the work */ + kfree(ndo_work); + + return; +} + +/* + * Neighbor Discovery Offload: Called when an interface + * is assigned with ipv6 address. + * Handles only primary interface + */ +static int dhd_inet6addr_notifier_call(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + dhd_info_t *dhd; + dhd_pub_t *dhd_pub; + struct inet6_ifaddr *inet6_ifa = ptr; + struct in6_addr *ipv6_addr = &inet6_ifa->addr; + struct ipv6_work_info_t *ndo_info; + int idx = 0; /* REVISIT */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) + /* Filter notifications meant for non Broadcom devices */ + if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) { + return NOTIFY_DONE; + } +#endif /* LINUX_VERSION_CODE */ + + dhd = DHD_DEV_INFO(inet6_ifa->idev->dev); + if (!dhd) + return NOTIFY_DONE; + + if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev) + return NOTIFY_DONE; + dhd_pub = &dhd->pub; + if (!FW_SUPPORTED(dhd_pub, ndoe)) + return NOTIFY_DONE; + + ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC); + if (!ndo_info) { + DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__)); + return NOTIFY_DONE; + } + + ndo_info->event = event; + ndo_info->if_idx = idx; + memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN); + + /* defer the work to thread as it may block kernel */ + dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)ndo_info, DHD_WQ_WORK_IPV6_NDO, + dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW); + return NOTIFY_DONE; +} +#endif /* #ifdef CONFIG_IPV6 */ + +int +dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + dhd_if_t *ifp; + struct net_device *net = NULL; + int err = 0; + uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; + + DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); + + ASSERT(dhd && dhd->iflist[ifidx]); + ifp = dhd->iflist[ifidx]; + net = ifp->net; + ASSERT(net && (ifp->idx == ifidx)); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + ASSERT(!net->open); + net->get_stats = dhd_get_stats; + net->do_ioctl = dhd_ioctl_entry; + net->hard_start_xmit = dhd_start_xmit; + net->set_mac_address = dhd_set_mac_address; + net->set_multicast_list = dhd_set_multicast_list; + net->open = net->stop = NULL; +#else + ASSERT(!net->netdev_ops); + net->netdev_ops = &dhd_ops_virt; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + + /* Ok, link into the network layer... */ + if (ifidx == 0) { +#if defined(BCMPCIE) && defined(CUSTOMER_HW5) + dhd->register_if_done = FALSE; +#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ + /* + * device functions for the primary interface only + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + net->open = dhd_open; + net->stop = dhd_stop; +#else + net->netdev_ops = &dhd_ops_pri; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) + memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); + } else { + /* + * We have to use the primary MAC for virtual interfaces + */ + memcpy(temp_addr, ifp->mac_addr, ETHER_ADDR_LEN); + /* + * Android sets the locally administered bit to indicate that this is a + * portable hotspot. This will not work in simultaneous AP/STA mode, + * nor with P2P. Need to set the Donlge's MAC address, and then use that. + */ + if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, + ETHER_ADDR_LEN)) { + DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", + __func__, net->name)); + temp_addr[0] |= 0x02; + } + } + + net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + net->ethtool_ops = &dhd_ethtool_ops; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + +#if defined(WL_WIRELESS_EXT) +#if WIRELESS_EXT < 19 + net->get_wireless_stats = dhd_get_wireless_stats; +#endif /* WIRELESS_EXT < 19 */ +#if WIRELESS_EXT > 12 + net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; +#endif /* WIRELESS_EXT > 12 */ +#endif /* defined(WL_WIRELESS_EXT) */ + + dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); + + memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); + + if (ifidx == 0) + printf("%s\n", dhd_version); + + if (need_rtnl_lock) + err = register_netdev(net); + else + err = register_netdevice(net); + + if (err != 0) { + DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err)); + goto fail; + } + + + + printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name, + MAC2STRDBG(net->dev_addr)); + +#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211) + wl_iw_iscan_set_scan_broadcast_prep(net, 1); +#endif + +#if (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \ + KERNEL_VERSION(2, 6, 27)))) + if (ifidx == 0) { +#ifdef BCMLXSDMMC + up(&dhd_registration_sem); +#endif + if (!dhd_download_fw_on_driverload) { +#ifdef WL_CFG80211 + wl_reinit_event_handler(); +#endif /* WL_CFG80211 */ + + dhd_net_bus_devreset(net, TRUE); +#ifdef BCMLXSDMMC + dhd_net_bus_suspend(net); +#endif /* BCMLXSDMMC */ + wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY); + } + +#if defined(BCMPCIE) && defined(CUSTOMER_HW5) + dhd->register_if_done = TRUE; +#endif /* OEM_ANDROID && BCMPCIE && CUSTOMER_HW5 */ + } +#endif /* OEM_ANDROID && (BCMPCIE || (BCMLXSDMMC && KERNEL_VERSION >= 2.6.27)) */ + + return 0; + +fail: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) + net->open = NULL; +#else + net->netdev_ops = NULL; +#endif + return err; +} + +void +dhd_bus_detach(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (dhdp) { + dhd = (dhd_info_t *)dhdp->info; + if (dhd) { + + /* + * In case of Android cfg80211 driver, the bus is down in dhd_stop, + * calling stop again will cuase SD read/write errors. + */ + if (dhd->pub.busstate != DHD_BUS_DOWN) { + /* Stop the protocol module */ + dhd_prot_stop(&dhd->pub); + + /* Stop the bus module */ + dhd_bus_stop(dhd->pub.bus, TRUE); + } + +#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE) + dhd_bus_oob_intr_unregister(dhdp); +#endif + } + } +} + + +void dhd_detach(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd; + unsigned long flags; + int timer_valid = FALSE; + + if (!dhdp) + return; + + dhd = (dhd_info_t *)dhdp->info; + if (!dhd) + return; + + + DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); + + dhd->pub.up = 0; + if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { + /* Give sufficient time for threads to start running in case + * dhd_attach() has failed + */ + OSL_SLEEP(100); + } + + if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { + dhd_bus_detach(dhdp); +#ifdef PCIE_FULL_DONGLE + dhd_flow_rings_deinit(dhdp); +#endif + + if (dhdp->prot) + dhd_prot_detach(dhdp); + } + +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd_inetaddr_notifier_registered) { + dhd_inetaddr_notifier_registered = FALSE; + unregister_inetaddr_notifier(&dhd_inetaddr_notifier); + } +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef CONFIG_IPV6 + if (dhd_inet6addr_notifier_registered) { + dhd_inet6addr_notifier_registered = FALSE; + unregister_inet6addr_notifier(&dhd_inet6addr_notifier); + } +#endif + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) + if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { + if (dhd->early_suspend.suspend) + unregister_early_suspend(&dhd->early_suspend); + } +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ + +#if defined(WL_WIRELESS_EXT) + if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { + /* Detatch and unlink in the iw */ + wl_iw_detach(); + } +#endif /* defined(WL_WIRELESS_EXT) */ + + /* delete all interfaces, start with virtual */ + if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { + int i = 1; + dhd_if_t *ifp; + + /* Cleanup virtual interfaces */ + dhd_net_if_lock_local(dhd); + for (i = 1; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) + dhd_remove_if(&dhd->pub, i, TRUE); + } + dhd_net_if_unlock_local(dhd); + + /* delete primary interface 0 */ + ifp = dhd->iflist[0]; + ASSERT(ifp); + ASSERT(ifp->net); + if (ifp && ifp->net) { + + + + /* in unregister_netdev case, the interface gets freed by net->destructor + * (which is set to free_netdev) + */ + if (ifp->net->reg_state == NETREG_UNINITIALIZED) + free_netdev(ifp->net); + else { +#ifdef SET_RPS_CPUS + custom_rps_map_clear(ifp->net->_rx); +#endif /* SET_RPS_CPUS */ + unregister_netdev(ifp->net); + } + ifp->net = NULL; +#ifdef DHD_WMF + dhd_wmf_cleanup(dhdp, 0); +#endif /* DHD_WMF */ + + dhd_if_del_sta_list(ifp); + + MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); + dhd->iflist[0] = NULL; + } + } + + /* Clear the watchdog timer */ + DHD_GENERAL_LOCK(&dhd->pub, flags); + timer_valid = dhd->wd_timer_valid; + dhd->wd_timer_valid = FALSE; + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + if (timer_valid) + del_timer_sync(&dhd->timer); + + if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { + if (dhd->thr_wdt_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_wdt_ctl); + } + + if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_rxf_ctl); + } + + if (dhd->thr_dpc_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_dpc_ctl); + } else + tasklet_kill(&dhd->tasklet); + } +#ifdef WL_CFG80211 + if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { + wl_cfg80211_detach(NULL); + dhd_monitor_uninit(); + } +#endif + /* free deferred work queue */ + dhd_deferred_work_deinit(dhd->dhd_deferred_wq); + dhd->dhd_deferred_wq = NULL; + +#ifdef SHOW_LOGTRACE + if (dhd->event_data.fmts) + kfree(dhd->event_data.fmts); + if (dhd->event_data.raw_fmts) + kfree(dhd->event_data.raw_fmts); +#endif /* SHOW_LOGTRACE */ + +#ifdef PNO_SUPPORT + if (dhdp->pno_state) + dhd_pno_deinit(dhdp); +#endif +#ifdef RTT_SUPPORT + if (dhdp->rtt_state) { + dhd_rtt_deinit(dhdp); + } +#endif +#if defined(CONFIG_PM_SLEEP) + if (dhd_pm_notifier_registered) { + unregister_pm_notifier(&dhd_pm_notifier); + dhd_pm_notifier_registered = FALSE; + } +#endif /* CONFIG_PM_SLEEP */ +#ifdef DEBUG_CPU_FREQ + if (dhd->new_freq) + free_percpu(dhd->new_freq); + dhd->new_freq = NULL; + cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); +#endif + + DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); + dhd->wakelock_wd_counter = 0; +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_destroy(&dhd->wl_wdwake); +#endif /* CONFIG_HAS_WAKELOCK */ + + if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { + DHD_OS_WAKE_LOCK_DESTROY(dhd); + } + + + + +#ifdef DHDTCPACK_SUPPRESS + /* This will free all MEM allocated for TCPACK SUPPRESS */ + dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); +#endif /* DHDTCPACK_SUPPRESS */ + + dhd_sysfs_exit(dhd); +} + + +void +dhd_free(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (dhdp) { + int i; + for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { + if (dhdp->reorder_bufs[i]) { + reorder_info_t *ptr; + uint32 buf_size = sizeof(struct reorder_info); + + ptr = dhdp->reorder_bufs[i]; + + buf_size += ((ptr->max_idx + 1) * sizeof(void*)); + DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", + i, ptr->max_idx, buf_size)); + + MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); + dhdp->reorder_bufs[i] = NULL; + } + } + + dhd_sta_pool_fini(dhdp, DHD_MAX_STA); + + dhd = (dhd_info_t *)dhdp->info; + if (dhdp->soc_ram) { +#ifdef DHD_USE_STATIC_MEMDUMP + DHD_OS_PREFREE(dhdp, dhdp->soc_ram, dhdp->soc_ram_length); +#else + MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length); +#endif /* DHD_USE_STATIC_MEMDUMP */ + dhdp->soc_ram = NULL; + } + + /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */ + if (dhd && + dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE)) + MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); + dhd = NULL; + } +} + +void +dhd_clear(dhd_pub_t *dhdp) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (dhdp) { + int i; + dhd_if_t *ifp; +#ifdef DHDTCPACK_SUPPRESS + /* Clean up timer/data structure for any remaining/pending packet or timer. */ + dhd_tcpack_info_tbl_clean(dhdp); +#endif /* DHDTCPACK_SUPPRESS */ + for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { + if (dhdp->reorder_bufs[i]) { + reorder_info_t *ptr; + uint32 buf_size = sizeof(struct reorder_info); + + ptr = dhdp->reorder_bufs[i]; + + buf_size += ((ptr->max_idx + 1) * sizeof(void*)); + DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", + i, ptr->max_idx, buf_size)); + + MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); + dhdp->reorder_bufs[i] = NULL; + } + } + + /* It would only need to delete iflist[0] because all other dynamically + * generated interfaces' iflists will be deleted in interface removal + */ + ifp = dhdp->info->iflist[0]; + if (ifp && ifp->net) { + DHD_ERROR(("%s: Delete sta list before clear\n", __FUNCTION__)); + dhd_if_del_sta_list(ifp); + } + + dhd_sta_pool_clear(dhdp, DHD_MAX_STA); + + if (dhdp->soc_ram) { +#ifdef DHD_USE_STATIC_MEMDUMP + DHD_OS_PREFREE(dhdp, dhdp->soc_ram, dhdp->soc_ram_length); +#else + MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length); +#endif /* DHD_USE_STATIC_MEMDUMP */ + dhdp->soc_ram = NULL; + } + } +} + +static void +dhd_module_cleanup(void) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + dhd_bus_unregister(); + + wl_android_exit(); + + dhd_wifi_platform_unregister_drv(); +} + +static void __exit +dhd_module_exit(void) +{ + dhd_module_cleanup(); + unregister_reboot_notifier(&dhd_reboot_notifier); +} + +#define BCMCONF "/data/misc/wifi/bcm_debug.conf" + +static int __init +dhd_module_init(void) +{ + int err; + int retry = POWERUP_MAX_RETRY; + void *fp = NULL; + + DHD_ERROR(("%s in\n", __FUNCTION__)); + + DHD_PERIM_RADIO_INIT(); + + if (firmware_path[0] != '\0') { + strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN); + fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0'; + } + + if (nvram_path[0] != '\0') { + strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN); + nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0'; + } + + do { + err = dhd_wifi_platform_register_drv(); + if (!err) { + register_reboot_notifier(&dhd_reboot_notifier); + break; + } + else { + DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n", + __FUNCTION__, retry)); + strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN); + firmware_path[MOD_PARAM_PATHLEN-1] = '\0'; + strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN); + nvram_path[MOD_PARAM_PATHLEN-1] = '\0'; + } + } while (retry--); + + if (err) + DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__)); + + fp = dhd_os_open_image(BCMCONF); + if (fp) { + unsigned char buf[7]; + long res = 0; + int len = dhd_os_get_image_block(buf, 7, fp); + if (len > 0 && len < 7) { + buf[len] = '\0'; + if (!kstrtol(buf, 16, &res)) + dhd_msg_level = (int)res; + } else { + DHD_ERROR(("Error in dbg level pattern\n")); + } + dhd_os_close_image(fp); + } + + DHD_ERROR(("%s out\n", __FUNCTION__)); + + return err; +} + +static int +dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused) +{ + DHD_TRACE(("%s: code = %ld\n", __FUNCTION__, code)); + if (code == SYS_RESTART) { + } + + return NOTIFY_DONE; +} + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +#if defined(CONFIG_DEFERRED_INITCALLS) +deferred_module_init(dhd_module_init); +#elif defined(USE_LATE_INITCALL_SYNC) +late_initcall_sync(dhd_module_init); +#else +late_initcall(dhd_module_init); +#endif /* USE_LATE_INITCALL_SYNC */ +#else +module_init(dhd_module_init); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ + +module_exit(dhd_module_exit); + +/* + * OS specific functions required to implement DHD driver in OS independent way + */ +int +dhd_os_proto_block(dhd_pub_t *pub) +{ + dhd_info_t * dhd = (dhd_info_t *)(pub->info); + + if (dhd) { + DHD_PERIM_UNLOCK(pub); + + down(&dhd->proto_sem); + + DHD_PERIM_LOCK(pub); + return 1; + } + + return 0; +} + +int +dhd_os_proto_unblock(dhd_pub_t *pub) +{ + dhd_info_t * dhd = (dhd_info_t *)(pub->info); + + if (dhd) { + up(&dhd->proto_sem); + return 1; + } + + return 0; +} + +unsigned int +dhd_os_get_ioctl_resp_timeout(void) +{ + return ((unsigned int)dhd_ioctl_timeout_msec); +} + +void +dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) +{ + dhd_ioctl_timeout_msec = (int)timeout_msec; +} + +int +dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) +{ + dhd_info_t * dhd = (dhd_info_t *)(pub->info); + int timeout; + + /* Convert timeout in millsecond to jiffies */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); +#else + timeout = dhd_ioctl_timeout_msec * HZ / 1000; +#endif + + DHD_PERIM_UNLOCK(pub); + + timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); + + DHD_PERIM_LOCK(pub); + + return timeout; +} + +int +dhd_os_ioctl_resp_wake(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + wake_up(&dhd->ioctl_resp_wait); + return 0; +} + +int +dhd_os_d3ack_wait(dhd_pub_t *pub, uint *condition, bool *pending) +{ + dhd_info_t * dhd = (dhd_info_t *)(pub->info); + int timeout; + + /* Convert timeout in millsecond to jiffies */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); +#else + timeout = dhd_ioctl_timeout_msec * HZ / 1000; +#endif + + DHD_PERIM_UNLOCK(pub); + + timeout = wait_event_timeout(dhd->d3ack_wait, (*condition), timeout); + + DHD_PERIM_LOCK(pub); + + return timeout; +} + +int +dhd_os_d3ack_wake(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + wake_up(&dhd->d3ack_wait); + return 0; +} + +void +dhd_os_wd_timer_extend(void *bus, bool extend) +{ + dhd_pub_t *pub = bus; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + + if (extend) + dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL); + else + dhd_os_wd_timer(bus, dhd->default_wd_interval); +} + + +void +dhd_os_wd_timer(void *bus, uint wdtick) +{ + dhd_pub_t *pub = bus; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + unsigned long flags; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!dhd) { + DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); + return; + } + + DHD_GENERAL_LOCK(pub, flags); + + /* don't start the wd until fw is loaded */ + if (pub->busstate == DHD_BUS_DOWN) { + DHD_GENERAL_UNLOCK(pub, flags); +#if !defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) + if (!wdtick) + DHD_OS_WD_WAKE_UNLOCK(pub); +#endif /* !DHD_USE_IDLECOUNT && BCMPCIE */ + return; + } + + /* Totally stop the timer */ + if (!wdtick && dhd->wd_timer_valid == TRUE) { + dhd->wd_timer_valid = FALSE; + DHD_GENERAL_UNLOCK(pub, flags); + del_timer_sync(&dhd->timer); +#if !defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) + DHD_OS_WD_WAKE_UNLOCK(pub); +#endif /* !DHD_USE_IDLECOUNT && BCMPCIE */ + return; + } + + if (wdtick) { +#if !defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) + DHD_OS_WD_WAKE_LOCK(pub); +#endif /* !DHD_USE_IDLECOUNT && BCMPCIE */ + dhd_watchdog_ms = (uint)wdtick; + /* Re arm the timer, at last watchdog period */ + mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); + dhd->wd_timer_valid = TRUE; + } + DHD_GENERAL_UNLOCK(pub, flags); +} + +void * +dhd_os_open_image(char *filename) +{ + struct file *fp; + + fp = filp_open(filename, O_RDONLY, 0); + /* + * 2.6.11 (FC4) supports filp_open() but later revs don't? + * Alternative: + * fp = open_namei(AT_FDCWD, filename, O_RD, 0); + * ??? + */ + if (IS_ERR(fp)) + fp = NULL; + + return fp; +} + +int +dhd_os_get_image_block(char *buf, int len, void *image) +{ + struct file *fp = (struct file *)image; + int rdlen; + + if (!image) + return 0; + + rdlen = kernel_read(fp, fp->f_pos, buf, len); + if (rdlen > 0) + fp->f_pos += rdlen; + + return rdlen; +} + +void +dhd_os_close_image(void *image) +{ + if (image) + filp_close((struct file *)image, NULL); +} + +void +dhd_os_sdlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + + if (dhd_dpc_prio >= 0) + down(&dhd->sdsem); + else + spin_lock_bh(&dhd->sdlock); +} + +void +dhd_os_sdunlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + + if (dhd_dpc_prio >= 0) + up(&dhd->sdsem); + else + spin_unlock_bh(&dhd->sdlock); +} + +void +dhd_os_sdlock_txq(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_bh(&dhd->txqlock); +} + +void +dhd_os_sdunlock_txq(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_bh(&dhd->txqlock); +} + +void +dhd_os_sdlock_rxq(dhd_pub_t *pub) +{ +} + +void +dhd_os_sdunlock_rxq(dhd_pub_t *pub) +{ +} + +static void +dhd_os_rxflock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_bh(&dhd->rxf_lock); + +} + +static void +dhd_os_rxfunlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_bh(&dhd->rxf_lock); +} + +#ifdef DHDTCPACK_SUPPRESS +void +dhd_os_tcpacklock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_bh(&dhd->tcpack_lock); + +} + +void +dhd_os_tcpackunlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_bh(&dhd->tcpack_lock); +} +#endif /* DHDTCPACK_SUPPRESS */ + +uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail) +{ + uint8* buf; + gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; + + buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size); + if (buf == NULL) { + DHD_ERROR(("%s: failed to alloc memory, section: %d," + " size: %dbytes", __FUNCTION__, section, size)); + if (kmalloc_if_fail) + buf = kmalloc(size, flags); + } + + return buf; +} + +void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size) +{ +} + +#if defined(WL_WIRELESS_EXT) +struct iw_statistics * +dhd_get_wireless_stats(struct net_device *dev) +{ + int res = 0; + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + if (!dhd->pub.up) { + return NULL; + } + + res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); + + if (res == 0) + return &dhd->iw.wstats; + else + return NULL; +} +#endif /* defined(WL_WIRELESS_EXT) */ + +static int +dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, + wl_event_msg_t *event, void **data) +{ + int bcmerror = 0; + + ASSERT(dhd != NULL); + + +#ifdef SHOW_LOGTRACE + bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data, &dhd->event_data); +#else + bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data, NULL); +#endif /* SHOW_LOGTRACE */ + + if (bcmerror != BCME_OK) + return (bcmerror); + +#if defined(WL_WIRELESS_EXT) + if (event->bsscfgidx == 0) { + /* + * Wireless ext is on primary interface only + */ + + ASSERT(dhd->iflist[*ifidx] != NULL); + ASSERT(dhd->iflist[*ifidx]->net != NULL); + + if (dhd->iflist[*ifidx]->net) { + wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); + } + } +#endif /* defined(WL_WIRELESS_EXT) */ + +#ifdef WL_CFG80211 + ASSERT(dhd->iflist[*ifidx] != NULL); + ASSERT(dhd->iflist[*ifidx]->net != NULL); + if (dhd->iflist[*ifidx]->net) + wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); +#endif /* defined(WL_CFG80211) */ + + return (bcmerror); +} + +/* send up locally generated event */ +void +dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) +{ + switch (ntoh32(event->event_type)) { + + default: + break; + } +} + +#ifdef LOG_INTO_TCPDUMP +void +dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len) +{ + struct sk_buff *p, *skb; + uint32 pktlen; + int len; + dhd_if_t *ifp; + dhd_info_t *dhd; + uchar *skb_data; + int ifidx = 0; + struct ether_header eth; + + pktlen = sizeof(eth) + data_len; + dhd = dhdp->info; + + if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { + ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); + + bcopy(&dhdp->mac, ð.ether_dhost, ETHER_ADDR_LEN); + bcopy(&dhdp->mac, ð.ether_shost, ETHER_ADDR_LEN); + ETHER_TOGGLE_LOCALADDR(ð.ether_shost); + eth.ether_type = hton16(ETHER_TYPE_BRCM); + + bcopy((void *)ð, PKTDATA(dhdp->osh, p), sizeof(eth)); + bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len); + skb = PKTTONATIVE(dhdp->osh, p); + skb_data = skb->data; + len = skb->len; + + ifidx = dhd_ifname2idx(dhd, "wlan0"); + ifp = dhd->iflist[ifidx]; + if (ifp == NULL) + ifp = dhd->iflist[0]; + + ASSERT(ifp); + skb->dev = ifp->net; + skb->protocol = eth_type_trans(skb, skb->dev); + skb->data = skb_data; + skb->len = len; + + /* Strip header, count, deliver upward */ + skb_pull(skb, ETH_HLEN); + + /* Send the packet */ + if (in_interrupt()) { + netif_rx(skb); + } else { + netif_rx_ni(skb); + } + } + else { + /* Could not allocate a sk_buf */ + DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__)); + } +} +#endif /* LOG_INTO_TCPDUMP */ + +void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) +{ +#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + struct dhd_info *dhdinfo = dhd->info; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); +#else + int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + + dhd_os_sdunlock(dhd); + wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); + dhd_os_sdlock(dhd); +#endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ + return; +} + +void dhd_wait_event_wakeup(dhd_pub_t *dhd) +{ +#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + struct dhd_info *dhdinfo = dhd->info; + if (waitqueue_active(&dhdinfo->ctrl_wait)) + wake_up(&dhdinfo->ctrl_wait); +#endif + return; +} + +#if defined(BCMSDIO) || defined(BCMPCIE) +int +dhd_net_bus_devreset(struct net_device *dev, uint8 flag) +{ + int ret = 0; + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + if (flag == TRUE) { + /* Issue wl down command before resetting the chip */ + if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { + DHD_TRACE(("%s: wl down failed\n", __FUNCTION__)); + } +#ifdef PROP_TXSTATUS + if (dhd->pub.wlfc_enabled) + dhd_wlfc_deinit(&dhd->pub); +#endif /* PROP_TXSTATUS */ +#ifdef PNO_SUPPORT + if (dhd->pub.pno_state) + dhd_pno_deinit(&dhd->pub); +#endif +#ifdef RTT_SUPPORT + if (dhd->pub.rtt_state) { + dhd_rtt_deinit(&dhd->pub); + } +#endif /* RTT_SUPPORT */ + } + +#ifdef BCMSDIO + if (!flag) { + dhd_update_fw_nv_path(dhd); + /* update firmware and nvram path to sdio bus */ + dhd_bus_update_fw_nv_path(dhd->pub.bus, + dhd->fw_path, dhd->nv_path); + } +#endif /* BCMSDIO */ + + ret = dhd_bus_devreset(&dhd->pub, flag); + if (ret) { + DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); + return ret; + } + + return ret; +} + +#ifdef BCMSDIO +int +dhd_net_bus_suspend(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + return dhd_bus_suspend(&dhd->pub); +} + +int +dhd_net_bus_resume(struct net_device *dev, uint8 stage) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + return dhd_bus_resume(&dhd->pub, stage); +} + +#endif /* BCMSDIO */ +#endif /* BCMSDIO || BCMPCIE */ + +int net_os_set_suspend_disable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret = 0; + + if (dhd) { + ret = dhd->pub.suspend_disable_flag; + dhd->pub.suspend_disable_flag = val; + } + return ret; +} + +int net_os_set_suspend(struct net_device *dev, int val, int force) +{ + int ret = 0; + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + if (dhd) { +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) + ret = dhd_set_suspend(val, &dhd->pub); +#else + ret = dhd_suspend_resume_helper(dhd, val, force); +#endif +#ifdef WL_CFG80211 + wl_cfg80211_update_power_mode(dev); +#endif + } + return ret; +} + +int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + if (dhd) + dhd->pub.suspend_bcn_li_dtim = val; + + return 0; +} + +#ifdef PKT_FILTER_SUPPORT +int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + char *filterp = NULL; + int filter_id = 0; + int ret = 0; + + if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || + (num == DHD_MDNS_FILTER_NUM)) + return ret; + if (num >= dhd->pub.pktfilter_count) + return -EINVAL; + switch (num) { + case DHD_BROADCAST_FILTER_NUM: + filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; + filter_id = 101; + break; + case DHD_MULTICAST4_FILTER_NUM: + filterp = "102 0 0 0 0xFFFFFF 0x01005E"; + filter_id = 102; + break; + case DHD_MULTICAST6_FILTER_NUM: + filterp = "103 0 0 0 0xFFFF 0x3333"; + filter_id = 103; + break; + default: + return -EINVAL; + } + + /* Add filter */ + if (add_remove) { + dhd->pub.pktfilter[num] = filterp; + dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); + } else { /* Delete filter */ + if (dhd->pub.pktfilter[num] != NULL) { + dhd_pktfilter_offload_delete(&dhd->pub, filter_id); + dhd->pub.pktfilter[num] = NULL; + } + } + return ret; +} + +int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) + +{ + int ret = 0; + + /* Packet filtering is set only if we still in early-suspend and + * we need either to turn it ON or turn it OFF + * We can always turn it OFF in case of early-suspend, but we turn it + * back ON only if suspend_disable_flag was not set + */ + if (dhdp && dhdp->up) { + if (dhdp->in_suspend) { + if (!val || (val && !dhdp->suspend_disable_flag)) + dhd_enable_packet_filter(val, dhdp); + } + } + return ret; +} + +/* function to enable/disable packet for Network device */ +int net_os_enable_packet_filter(struct net_device *dev, int val) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + return dhd_os_enable_packet_filter(&dhd->pub, val); +} +#endif /* PKT_FILTER_SUPPORT */ + +int +dhd_dev_init_ioctl(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret; + + if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) + goto done; + +done: + return ret; +} + +int dhd_dev_get_feature_set(struct net_device *dev) +{ + dhd_info_t *ptr = *(dhd_info_t **)netdev_priv(dev); + dhd_pub_t *dhd = (&ptr->pub); + int feature_set = 0; + + if (!dhd) + return feature_set; + + if (FW_SUPPORTED(dhd, sta)) + feature_set |= WIFI_FEATURE_INFRA; + if (FW_SUPPORTED(dhd, dualband)) + feature_set |= WIFI_FEATURE_INFRA_5G; + if (FW_SUPPORTED(dhd, p2p)) + feature_set |= WIFI_FEATURE_P2P; + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) + feature_set |= WIFI_FEATURE_SOFT_AP; + if (FW_SUPPORTED(dhd, tdls)) + feature_set |= WIFI_FEATURE_TDLS; + if (FW_SUPPORTED(dhd, vsdb)) + feature_set |= WIFI_FEATURE_TDLS_OFFCHANNEL; + if (FW_SUPPORTED(dhd, nan)) { + feature_set |= WIFI_FEATURE_NAN; + /* NAN is essentail for d2d rtt */ + if (FW_SUPPORTED(dhd, rttd2d)) { + feature_set |= WIFI_FEATURE_D2D_RTT; + } + } +#ifdef RTT_SUPPORT + feature_set |= WIFI_FEATURE_D2AP_RTT; +#endif /* RTT_SUPPORT */ +#ifdef LINKSTAT_SUPPORT + feature_set |= WIFI_FEATURE_LINKSTAT; +#endif /* LINKSTAT_SUPPORT */ + /* Supports STA + STA always */ + feature_set |= WIFI_FEATURE_ADDITIONAL_STA; +#ifdef PNO_SUPPORT + if (dhd_is_pno_supported(dhd)) { + feature_set |= WIFI_FEATURE_PNO; + feature_set |= WIFI_FEATURE_BATCH_SCAN; +#ifdef GSCAN_SUPPORT + feature_set |= WIFI_FEATURE_GSCAN; +#endif /* GSCAN_SUPPORT */ + } + if (FW_SUPPORTED(dhd, rssi_mon)) { + feature_set |= WIFI_FEATURE_RSSI_MONITOR; + } +#endif /* PNO_SUPPORT */ +#ifdef WL11U + feature_set |= WIFI_FEATURE_HOTSPOT; +#endif /* WL11U */ + return feature_set; +} + +int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num) +{ + int feature_set_full, mem_needed; + int *ret; + + *num = 0; + mem_needed = sizeof(int) * MAX_FEATURE_SET_CONCURRRENT_GROUPS; + ret = (int *) kmalloc(mem_needed, GFP_KERNEL); + + if (!ret) { + DHD_ERROR(("%s: failed to allocate %d bytes\n", __FUNCTION__, + mem_needed)); + return ret; + } + + feature_set_full = dhd_dev_get_feature_set(dev); + + ret[0] = (feature_set_full & WIFI_FEATURE_INFRA) | + (feature_set_full & WIFI_FEATURE_INFRA_5G) | + (feature_set_full & WIFI_FEATURE_NAN) | + (feature_set_full & WIFI_FEATURE_D2D_RTT) | + (feature_set_full & WIFI_FEATURE_D2AP_RTT) | + (feature_set_full & WIFI_FEATURE_PNO) | + (feature_set_full & WIFI_FEATURE_HAL_EPNO) | + (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | + (feature_set_full & WIFI_FEATURE_BATCH_SCAN) | + (feature_set_full & WIFI_FEATURE_GSCAN) | + (feature_set_full & WIFI_FEATURE_HOTSPOT) | + (feature_set_full & WIFI_FEATURE_ADDITIONAL_STA) | + (feature_set_full & WIFI_FEATURE_EPR); + + ret[1] = (feature_set_full & WIFI_FEATURE_INFRA) | + (feature_set_full & WIFI_FEATURE_INFRA_5G) | + (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | + /* Not yet verified NAN with P2P */ + /* (feature_set_full & WIFI_FEATURE_NAN) | */ + (feature_set_full & WIFI_FEATURE_P2P) | + (feature_set_full & WIFI_FEATURE_D2AP_RTT) | + (feature_set_full & WIFI_FEATURE_D2D_RTT) | + (feature_set_full & WIFI_FEATURE_EPR); + + ret[2] = (feature_set_full & WIFI_FEATURE_INFRA) | + (feature_set_full & WIFI_FEATURE_INFRA_5G) | + (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | + (feature_set_full & WIFI_FEATURE_NAN) | + (feature_set_full & WIFI_FEATURE_D2D_RTT) | + (feature_set_full & WIFI_FEATURE_D2AP_RTT) | + (feature_set_full & WIFI_FEATURE_TDLS) | + (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL) | + (feature_set_full & WIFI_FEATURE_EPR); + *num = MAX_FEATURE_SET_CONCURRRENT_GROUPS; + + return ret; +} +#ifdef CUSTOM_FORCE_NODFS_FLAG +int +dhd_dev_set_nodfs(struct net_device *dev, u32 nodfs) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + if (nodfs) + dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; + else + dhd->pub.dhd_cflags &= ~WLAN_PLAT_NODFS_FLAG; + dhd->pub.force_country_change = TRUE; + return 0; +} +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +#ifdef PNO_SUPPORT +/* Linux wrapper to call common dhd_pno_stop_for_ssid */ +int +dhd_dev_pno_stop_for_ssid(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + return (dhd_pno_stop_for_ssid(&dhd->pub)); +} +/* Linux wrapper to call common dhd_pno_set_for_ssid */ +int +dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr, + pno_repeat, pno_freq_expo_max, channel_list, nchan)); +} + +/* Linux wrapper to call common dhd_pno_enable */ +int +dhd_dev_pno_enable(struct net_device *dev, int enable) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + return (dhd_pno_enable(&dhd->pub, enable)); +} + +/* Linux wrapper to call common dhd_pno_set_for_hotlist */ +int +dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params)); +} +/* Linux wrapper to call common dhd_dev_pno_stop_for_batch */ +int +dhd_dev_pno_stop_for_batch(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + return (dhd_pno_stop_for_batch(&dhd->pub)); +} +/* Linux wrapper to call common dhd_dev_pno_set_for_batch */ +int +dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + return (dhd_pno_set_for_batch(&dhd->pub, batch_params)); +} +/* Linux wrapper to call common dhd_dev_pno_get_for_batch */ +int +dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL)); +} + +bool +dhd_dev_is_legacy_pno_enabled(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_is_legacy_pno_enabled(&dhd->pub)); +} +#endif /* PNO_SUPPORT */ + +#ifdef GSCAN_SUPPORT +/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ +int +dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, + void *buf, uint8 flush) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_set_cfg_gscan(&dhd->pub, type, buf, flush)); +} + +/* Linux wrapper to call common dhd_pno_get_gscan */ +void * +dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, + void *info, uint32 *len) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_get_gscan(&dhd->pub, type, info, len)); +} + +/* Linux wrapper to call common dhd_wait_batch_results_complete */ +int +dhd_dev_wait_batch_results_complete(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_wait_batch_results_complete(&dhd->pub)); +} + +/* Linux wrapper to call common dhd_pno_lock_batch_results */ +int +dhd_dev_pno_lock_access_batch_results(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_lock_batch_results(&dhd->pub)); +} +/* Linux wrapper to call common dhd_pno_unlock_batch_results */ +void +dhd_dev_pno_unlock_access_batch_results(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_unlock_batch_results(&dhd->pub)); +} + +/* Linux wrapper to call common dhd_pno_initiate_gscan_request */ +int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_initiate_gscan_request(&dhd->pub, run, flush)); +} + +/* Linux wrapper to call common dhd_pno_enable_full_scan_result */ +int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time_flag) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_enable_full_scan_result(&dhd->pub, real_time_flag)); +} + +/* Linux wrapper to call common dhd_handle_swc_evt */ +void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_handle_swc_evt(&dhd->pub, data, send_evt_bytes)); +} + +/* Linux wrapper to call common dhd_handle_hotlist_scan_evt */ +void * dhd_dev_hotlist_scan_event(struct net_device *dev, + const void *data, int *send_evt_bytes, hotlist_type_t type) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_handle_hotlist_scan_evt(&dhd->pub, data, send_evt_bytes, type)); +} + +/* Linux wrapper to call common dhd_process_full_gscan_result */ +void * dhd_dev_process_full_gscan_result(struct net_device *dev, +const void *data, int *send_evt_bytes) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_process_full_gscan_result(&dhd->pub, data, send_evt_bytes)); +} + +void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + dhd_gscan_hotlist_cache_cleanup(&dhd->pub, type); + + return; +} + +int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_gscan_batch_cache_cleanup(&dhd->pub)); +} + +/* Linux wrapper to call common dhd_retreive_batch_scan_results */ +int dhd_dev_retrieve_batch_scan(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_retreive_batch_scan_results(&dhd->pub)); +} +/* Linux wrapper to call common dhd_pno_process_epno_result */ +void * dhd_dev_process_epno_result(struct net_device *dev, + const void *data, uint32 event, int *send_evt_bytes) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_process_epno_result(&dhd->pub, data, event, send_evt_bytes)); +} + +int +dhd_dev_set_lazy_roam_cfg(struct net_device *dev, + wlc_roam_exp_params_t *roam_param) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + wl_roam_exp_cfg_t roam_exp_cfg; + int err; + + if (!roam_param) { + return BCME_BADARG; + } + + DHD_ERROR(("a_band_boost_thr %d a_band_penalty_thr %d\n", + roam_param->a_band_boost_threshold, roam_param->a_band_penalty_threshold)); + DHD_ERROR(("a_band_boost_factor %d a_band_penalty_factor %d cur_bssid_boost %d\n", + roam_param->a_band_boost_factor, roam_param->a_band_penalty_factor, + roam_param->cur_bssid_boost)); + DHD_ERROR(("alert_roam_trigger_thr %d a_band_max_boost %d\n", + roam_param->alert_roam_trigger_threshold, roam_param->a_band_max_boost)); + + memcpy(&roam_exp_cfg.params, roam_param, sizeof(*roam_param)); + roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; + roam_exp_cfg.flags = ROAM_EXP_CFG_PRESENT; + if (dhd->pub.lazy_roam_enable) { + roam_exp_cfg.flags |= ROAM_EXP_ENABLE_FLAG; + } + err = dhd_iovar(&(dhd->pub), 0, "roam_exp_params", (char *)&roam_exp_cfg, + sizeof(roam_exp_cfg), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); + } + return err; +} + +int +dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable) +{ + int err; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + wl_roam_exp_cfg_t roam_exp_cfg; + + memset(&roam_exp_cfg, 0, sizeof(roam_exp_cfg)); + roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; + if (enable) { + roam_exp_cfg.flags = ROAM_EXP_ENABLE_FLAG; + } + + err = dhd_iovar(&(dhd->pub), 0, "roam_exp_params", (char *)&roam_exp_cfg, + sizeof(roam_exp_cfg), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); + } else { + dhd->pub.lazy_roam_enable = (enable != 0); + } + return err; +} +int +dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, + wl_bssid_pref_cfg_t *bssid_pref, uint32 flush) +{ + int err; + int len; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + bssid_pref->version = BSSID_PREF_LIST_VERSION; + /* By default programming bssid pref flushes out old values */ + bssid_pref->flags = (flush && !bssid_pref->count) ? ROAM_EXP_CLEAR_BSSID_PREF: 0; + len = sizeof(wl_bssid_pref_cfg_t); + len += (bssid_pref->count - 1) * sizeof(wl_bssid_pref_list_t); + err = dhd_iovar(&dhd->pub, 0, "roam_exp_bssid_pref", + (char *)bssid_pref, len, NULL, 0, TRUE); + if (err != BCME_OK) { + DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); + } + return err; +} +int +dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, + uint32 len, uint32 flush) +{ + int err; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int macmode; + + if (blacklist) { + err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACLIST, (char *)blacklist, + len, TRUE, 0); + if (err != BCME_OK) { + DHD_ERROR(("%s : WLC_SET_MACLIST failed %d\n", __FUNCTION__, err)); + return err; + } + } + /* By default programming blacklist flushes out old values */ + macmode = (flush && !blacklist) ? WLC_MACMODE_DISABLED : WLC_MACMODE_DENY; + err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACMODE, (char *)&macmode, + sizeof(macmode), TRUE, 0); + if (err != BCME_OK) { + DHD_ERROR(("%s : WLC_SET_MACMODE failed %d\n", __FUNCTION__, err)); + } + return err; +} +int +dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid_whitelist, + uint32 len, uint32 flush) +{ + int err; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + wl_ssid_whitelist_t whitelist_ssid_flush; + + if (!ssid_whitelist) { + if (flush) { + ssid_whitelist = &whitelist_ssid_flush; + ssid_whitelist->ssid_count = 0; + } else { + DHD_ERROR(("%s : Nothing to do here\n", __FUNCTION__)); + return BCME_BADARG; + } + } + ssid_whitelist->version = SSID_WHITELIST_VERSION; + ssid_whitelist->flags = flush ? ROAM_EXP_CLEAR_SSID_WHITELIST : 0; + err = dhd_iovar(&dhd->pub, 0, "roam_exp_ssid_whitelist", (char *)ssid_whitelist, len, NULL, + 0, TRUE); + if (err != BCME_OK) { + DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); + } + return err; +} +#endif /* GSCAN_SUPPORT */ + +#if defined(KEEP_ALIVE) +#define TEMP_BUF_SIZE 512 +#define FRAME_SIZE 300 +int +dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, u16 ip_pkt_len, + u8* src_mac, u8* dst_mac, u32 period_msec) +{ + char *pbuf; + const char *str; + wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0}; + wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + int buf_len; + int str_len; + int res = BCME_ERROR; + int len_bytes = 0; + int i; + + /* ether frame to have both max IP pkt (256 bytes) and ether header */ + char *pmac_frame; + + /* + * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, + * dongle shall reject a mkeep_alive request. + */ + if (!dhd_support_sta_mode(dhd_pub)) + return res; + + DHD_TRACE(("%s execution\n", __FUNCTION__)); + + if ((pbuf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { + DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE)); + res = BCME_NOMEM; + return res; + } + + if ((pmac_frame = kzalloc(FRAME_SIZE, GFP_KERNEL)) == NULL) { + DHD_ERROR(("failed to allocate mac_frame with size %d\n", FRAME_SIZE)); + res = BCME_NOMEM; + goto exit; + } + + /* + * Get current mkeep-alive status. + */ + res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, + TEMP_BUF_SIZE, FALSE); + if (res < 0) { + DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); + goto exit; + } else { + /* Check available ID whether it is occupied */ + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; + if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { + DHD_ERROR(("%s: Get mkeep_alive failed, ID %u is in use.\n", + __FUNCTION__, mkeep_alive_id)); + + /* Current occupied ID info */ + DHD_ERROR(("%s: mkeep_alive\n", __FUNCTION__)); + DHD_ERROR((" Id : %d\n" + " Period: %d msec\n" + " Length: %d\n" + " Packet: 0x", + mkeep_alive_pktp->keep_alive_id, + dtoh32(mkeep_alive_pktp->period_msec), + dtoh16(mkeep_alive_pktp->len_bytes))); + + for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { + DHD_ERROR(("%02x", mkeep_alive_pktp->data[i])); + } + DHD_ERROR(("\n")); + + res = BCME_NOTFOUND; + goto exit; + } + } + + /* Request the specified ID */ + memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); + memset(pbuf, 0, TEMP_BUF_SIZE); + str = "mkeep_alive"; + str_len = strlen(str); + strncpy(pbuf, str, str_len); + pbuf[str_len] = '\0'; + + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1); + mkeep_alive_pkt.period_msec = htod32(period_msec); + buf_len = str_len + 1; + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + + /* ID assigned */ + mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; + + buf_len += WL_MKEEP_ALIVE_FIXED_LEN; + + /* + * Build up Ethernet Frame + */ + + /* Mapping dest mac addr */ + memcpy(pmac_frame, dst_mac, ETHER_ADDR_LEN); + pmac_frame += ETHER_ADDR_LEN; + + /* Mapping src mac addr */ + memcpy(pmac_frame, src_mac, ETHER_ADDR_LEN); + pmac_frame += ETHER_ADDR_LEN; + + /* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */ + *(pmac_frame++) = 0x08; + *(pmac_frame++) = 0x00; + + /* Mapping IP pkt */ + memcpy(pmac_frame, ip_pkt, ip_pkt_len); + pmac_frame += ip_pkt_len; + + /* + * Length of ether frame (assume to be all hexa bytes) + * = src mac + dst mac + ether type + ip pkt len + */ + len_bytes = ETHER_ADDR_LEN*2 + ETHER_TYPE_LEN + ip_pkt_len; + /* Get back to the beginning. */ + pmac_frame -= len_bytes; + memcpy(mkeep_alive_pktp->data, pmac_frame, len_bytes); + buf_len += len_bytes; + mkeep_alive_pkt.len_bytes = htod16(len_bytes); + + /* + * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and + * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); + + res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0); +exit: + kfree(pmac_frame); + kfree(pbuf); + return res; +} + +int +dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id) +{ + char *pbuf; + wl_mkeep_alive_pkt_t mkeep_alive_pkt; + wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + int res = BCME_ERROR; + int i; + + /* + * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, + * dongle shall reject a mkeep_alive request. + */ + if (!dhd_support_sta_mode(dhd_pub)) + return res; + + DHD_TRACE(("%s execution\n", __FUNCTION__)); + + /* + * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt. + */ + if ((pbuf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { + DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE)); + return res; + } + + res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, + sizeof(mkeep_alive_id), pbuf, TEMP_BUF_SIZE, FALSE); + if (res < 0) { + DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); + goto exit; + } else { + /* Check occupied ID */ + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; + DHD_INFO(("%s: mkeep_alive\n", __FUNCTION__)); + DHD_INFO((" Id : %d\n" + " Period: %d msec\n" + " Length: %d\n" + " Packet: 0x", + mkeep_alive_pktp->keep_alive_id, + dtoh32(mkeep_alive_pktp->period_msec), + dtoh16(mkeep_alive_pktp->len_bytes))); + + for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { + DHD_INFO(("%02x", mkeep_alive_pktp->data[i])); + } + DHD_INFO(("\n")); + } + + /* Make it stop if available */ + if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { + DHD_INFO(("stop mkeep_alive on ID %d\n", mkeep_alive_id)); + memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); + + mkeep_alive_pkt.period_msec = 0; + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; + + /* + * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and + * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + res = dhd_iovar(dhd_pub, 0, "mkeep_alive", + (char *)&mkeep_alive_pkt, + WL_MKEEP_ALIVE_FIXED_LEN, NULL, 0, TRUE); + } else { + DHD_ERROR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id)); + res = BCME_NOTFOUND; + } +exit: + kfree(pbuf); + return res; +} +#endif /* defined(KEEP_ALIVE) */ + +int +dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, + int8 max_rssi, int8 min_rssi) +{ + int err; + wl_rssi_monitor_cfg_t rssi_monitor; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + rssi_monitor.version = RSSI_MONITOR_VERSION; + rssi_monitor.max_rssi = max_rssi; + rssi_monitor.min_rssi = min_rssi; + rssi_monitor.flags = start ? 0: RSSI_MONITOR_STOP; + err = dhd_iovar(&dhd->pub, 0, "rssi_monitor", (char *)&rssi_monitor, sizeof(rssi_monitor), + NULL, 0, TRUE); + if (err < 0 && err != BCME_UNSUPPORTED) { + DHD_ERROR(("%s : Failed to execute rssi_monitor %d\n", __FUNCTION__, err)); + } + return err; +} + +int +dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + dhd_pub_t *dhdp = &dhd->pub; + + if (!dhdp || !oui) { + DHD_ERROR(("NULL POINTER : %s\n", + __FUNCTION__)); + return BCME_ERROR; + } + if (ETHER_ISMULTI(oui)) { + DHD_ERROR(("Expected unicast OUI\n")); + return BCME_ERROR; + } else { + uint8 *rand_mac_oui = dhdp->rand_mac_oui; + memcpy(rand_mac_oui, oui, DOT11_OUI_LEN); + DHD_ERROR(("Random MAC OUI to be used - %02x:%02x:%02x\n", rand_mac_oui[0], + rand_mac_oui[1], rand_mac_oui[2])); + } + return BCME_OK; +} + +int +dhd_set_rand_mac_oui(dhd_pub_t *dhd) +{ + int err; + wl_pfn_macaddr_cfg_t cfg; + uint8 *rand_mac_oui = dhd->rand_mac_oui; + + memset(&cfg.macaddr, 0, ETHER_ADDR_LEN); + memcpy(&cfg.macaddr, rand_mac_oui, DOT11_OUI_LEN); + cfg.version = WL_PFN_MACADDR_CFG_VER; + if (ETHER_ISNULLADDR(&cfg.macaddr)) + cfg.flags = 0; + else + cfg.flags = (WL_PFN_MAC_OUI_ONLY_MASK | WL_PFN_SET_MAC_UNASSOC_MASK); + + DHD_ERROR(("Setting rand mac oui to FW - %02x:%02x:%02x\n", rand_mac_oui[0], + rand_mac_oui[1], rand_mac_oui[2])); + + err = dhd_iovar(dhd, 0, "pfn_macaddr", (char *)&cfg, sizeof(cfg), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_macaddr %d\n", __FUNCTION__, err)); + } + return err; +} + +#ifdef RTT_SUPPORT +/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ +int +dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_set_cfg(&dhd->pub, buf)); +} +int +dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_stop(&dhd->pub, mac_list, mac_cnt)); +} + +int +dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, dhd_rtt_compl_noti_fn noti_fn) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_register_noti_callback(&dhd->pub, ctx, noti_fn)); +} +int +dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_unregister_noti_callback(&dhd->pub, noti_fn)); +} + +int +dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_capability(&dhd->pub, capa)); +} +#endif /* RTT_SUPPORT */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +static void dhd_hang_process(void *dhd_info, void *event_info, u8 event) +{ + dhd_info_t *dhd; + struct net_device *dev; + + dhd = (dhd_info_t *)dhd_info; + dev = dhd->iflist[0]->net; + + if (dev) { + rtnl_lock(); + dev_close(dev); + rtnl_unlock(); +#if defined(WL_WIRELESS_EXT) + wl_iw_send_priv_event(dev, "HANG"); +#endif +#if defined(WL_CFG80211) + wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); +#endif + } +} + + +int dhd_os_send_hang_message(dhd_pub_t *dhdp) +{ + int ret = 0; + if (dhdp) { + if (!dhdp->hang_was_sent) { + dhdp->hang_was_sent = 1; + dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dhdp, + DHD_WQ_WORK_HANG_MSG, dhd_hang_process, DHD_WORK_PRIORITY_HIGH); + } + } + return ret; +} + +int net_os_send_hang_message(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret = 0; + + if (dhd) { + /* Report FW problem when enabled */ + if (dhd->pub.hang_report) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + ret = dhd_os_send_hang_message(&dhd->pub); +#else + ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); +#endif + } else { + DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n", + __FUNCTION__)); + /* Enforce bus down to stop any future traffic */ + dhd->pub.busstate = DHD_BUS_DOWN; + } + } + return ret; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ + + +int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + return wifi_platform_set_power(dhd->adapter, on, delay_msec); +} + +void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, + wl_country_t *cspec) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); +#ifdef CUSTOM_FORCE_NODFS_FLAG + get_customized_country_code(dhd->adapter, country_iso_code, cspec, + dhd->pub.dhd_cflags); + +#else + get_customized_country_code(dhd->adapter, country_iso_code, cspec); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + +} +void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + if (dhd && dhd->pub.up) { + memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); +#ifdef WL_CFG80211 + wl_update_wiphybands(NULL, notify); +#endif + } +} + +void dhd_bus_band_set(struct net_device *dev, uint band) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + if (dhd && dhd->pub.up) { +#ifdef WL_CFG80211 + wl_update_wiphybands(NULL, true); +#endif + } +} + +int dhd_net_set_fw_path(struct net_device *dev, char *fw) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + if (!fw || fw[0] == '\0') + return -EINVAL; + + strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1); + dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0'; + +#if defined(SOFTAP) + if (strstr(fw, "apsta") != NULL) { + DHD_INFO(("GOT APSTA FIRMWARE\n")); + ap_fw_loaded = TRUE; + } else { + DHD_INFO(("GOT STA FIRMWARE\n")); + ap_fw_loaded = FALSE; + } +#endif + return 0; +} + +void dhd_net_if_lock(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + dhd_net_if_lock_local(dhd); +} + +void dhd_net_if_unlock(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + dhd_net_if_unlock_local(dhd); +} + +static void dhd_net_if_lock_local(dhd_info_t *dhd) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + if (dhd) + mutex_lock(&dhd->dhd_net_if_mutex); +#endif +} + +static void dhd_net_if_unlock_local(dhd_info_t *dhd) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + if (dhd) + mutex_unlock(&dhd->dhd_net_if_mutex); +#endif +} + +static void dhd_suspend_lock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_lock(&dhd->dhd_suspend_mutex); +#endif +} + +static void dhd_suspend_unlock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_unlock(&dhd->dhd_suspend_mutex); +#endif +} + +unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags = 0; + + if (dhd) + spin_lock_irqsave(&dhd->dhd_lock, flags); + + return flags; +} + +void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + spin_unlock_irqrestore(&dhd->dhd_lock, flags); +} + +/* Linux specific multipurpose spinlock API */ +void * +dhd_os_spin_lock_init(osl_t *osh) +{ + /* Adding 4 bytes since the sizeof(spinlock_t) could be 0 */ + /* if CONFIG_SMP and CONFIG_DEBUG_SPINLOCK are not defined */ + /* and this results in kernel asserts in internal builds */ + spinlock_t * lock = MALLOC(osh, sizeof(spinlock_t) + 4); + if (lock) + spin_lock_init(lock); + return ((void *)lock); +} +void +dhd_os_spin_lock_deinit(osl_t *osh, void *lock) +{ + MFREE(osh, lock, sizeof(spinlock_t) + 4); +} +unsigned long +dhd_os_spin_lock(void *lock) +{ + unsigned long flags = 0; + + if (lock) + spin_lock_irqsave((spinlock_t *)lock, flags); + + return flags; +} +void +dhd_os_spin_unlock(void *lock, unsigned long flags) +{ + if (lock) + spin_unlock_irqrestore((spinlock_t *)lock, flags); +} + +static int +dhd_get_pend_8021x_cnt(dhd_info_t *dhd) +{ + return (atomic_read(&dhd->pend_8021x_cnt)); +} + +#define MAX_WAIT_FOR_8021X_TX 100 + +int +dhd_wait_pend8021x(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int timeout = msecs_to_jiffies(10); + int ntimes = MAX_WAIT_FOR_8021X_TX; + int pend = dhd_get_pend_8021x_cnt(dhd); + + while (ntimes && pend) { + if (pend) { + set_current_state(TASK_INTERRUPTIBLE); + DHD_PERIM_UNLOCK(&dhd->pub); + schedule_timeout(timeout); + DHD_PERIM_LOCK(&dhd->pub); + set_current_state(TASK_RUNNING); + ntimes--; + } + pend = dhd_get_pend_8021x_cnt(dhd); + } + if (ntimes == 0) + { + atomic_set(&dhd->pend_8021x_cnt, 0); + DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__)); + } + return pend; +} + +#ifdef DHD_DEBUG +int +write_to_file(dhd_pub_t *dhd, uint8 *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 */ +#if defined(CUSTOMER_HW5) + fp = filp_open("/data/mem_dump", O_WRONLY|O_CREAT, 0640); +#else + fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640); +#endif + + if (IS_ERR(fp)) { + fp = NULL; + printf("%s: open file error\n", __FUNCTION__); + ret = -1; + goto exit; + } + + /* Write buf to file */ + fp->f_op->write(fp, buf, size, &pos); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) + fp->f_op->fsync(fp, 0, size-1, 1); +#else + fp->f_op->fsync(fp, 1); +#endif /* KERNEL_VERSION(3, 1, 0) */ + +exit: + /* buf is actually dhd_pub->soc_ram and freed in in dhd_{free,clear} */ + + /* close file before return */ + if (fp) + filp_close(fp, current->files); + /* restore previous address limit */ + set_fs(old_fs); + + return ret; +} +#endif /* DHD_DEBUG */ + +int dhd_os_wake_lock_timeout(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? + dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; +#ifdef CONFIG_HAS_WAKELOCK + if (dhd->wakelock_rx_timeout_enable) + wake_lock_timeout(&dhd->wl_rxwake, + msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); + if (dhd->wakelock_ctrl_timeout_enable) + wake_lock_timeout(&dhd->wl_ctrlwake, + msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); +#endif + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +int net_os_wake_lock_timeout(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_timeout(&dhd->pub); + return ret; +} + +int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (val > dhd->wakelock_rx_timeout_enable) + dhd->wakelock_rx_timeout_enable = val; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return 0; +} + +int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (val > dhd->wakelock_ctrl_timeout_enable) + dhd->wakelock_ctrl_timeout_enable = val; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return 0; +} + +int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + dhd->wakelock_ctrl_timeout_enable = 0; +#ifdef CONFIG_HAS_WAKELOCK + if (wake_lock_active(&dhd->wl_ctrlwake)) + wake_unlock(&dhd->wl_ctrlwake); +#endif + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return 0; +} + +int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); + return ret; +} + +int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); + return ret; +} +#if defined(DHD_TRACE_WAKE_LOCK) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +#include +#else +#include +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +/* Define 2^5 = 32 bucket size hash table */ +DEFINE_HASHTABLE(wklock_history, 5); +#else +/* Define 2^5 = 32 bucket size hash table */ +struct hlist_head wklock_history[32] = { [0 ... 31] = HLIST_HEAD_INIT }; +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ + +int trace_wklock_onoff = 1; +typedef enum dhd_wklock_type { + DHD_WAKE_LOCK, + DHD_WAKE_UNLOCK, + DHD_WAIVE_LOCK, + DHD_RESTORE_LOCK +} dhd_wklock_t; + +struct wk_trace_record { + unsigned long addr; /* Address of the instruction */ + dhd_wklock_t lock_type; /* lock_type */ + unsigned long long counter; /* counter information */ + struct hlist_node wklock_node; /* hash node */ +}; + +static struct wk_trace_record *find_wklock_entry(unsigned long addr) +{ + struct wk_trace_record *wklock_info; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) + hash_for_each_possible(wklock_history, wklock_info, wklock_node, addr) +#else + struct hlist_node *entry; + int index = hash_long(addr, ilog2(ARRAY_SIZE(wklock_history))); + hlist_for_each_entry(wklock_info, entry, &wklock_history[index], wklock_node) +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ + { + if (wklock_info->addr == addr) { + return wklock_info; + } + } + return NULL; +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +#define HASH_ADD(hashtable, node, key) \ + do { \ + hash_add(hashtable, node, key); \ + } while (0); + +#else /* KERNEL_VER < KERNEL_VERSION(3, 7, 0) */ +#define HASH_ADD(hashtable, node, key) \ + do { \ + int index = hash_long(key, ilog2(ARRAY_SIZE(hashtable))); \ + hlist_add_head(node, &hashtable[index]); \ + } while (0); +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ +#define STORE_WKLOCK_RECORD(wklock_type) \ + do { \ + struct wk_trace_record *wklock_info = NULL; \ + unsigned long func_addr = (unsigned long)__builtin_return_address(0); \ + wklock_info = find_wklock_entry(func_addr); \ + if (wklock_info) { \ + if (wklock_type == DHD_WAIVE_LOCK || wklock_type == DHD_RESTORE_LOCK) { \ + wklock_info->counter = dhd->wakelock_counter; \ + } else { \ + wklock_info->counter++; \ + } \ + } else { \ + wklock_info = kzalloc(sizeof(*wklock_info), GFP_ATOMIC); \ + if (!wklock_info) {\ + printk("Can't allocate wk_trace_record \n"); \ + } else { \ + wklock_info->addr = func_addr; \ + wklock_info->lock_type = wklock_type; \ + if (wklock_type == DHD_WAIVE_LOCK || \ + wklock_type == DHD_RESTORE_LOCK) { \ + wklock_info->counter = dhd->wakelock_counter; \ + } else { \ + wklock_info->counter++; \ + } \ + HASH_ADD(wklock_history, &wklock_info->wklock_node, func_addr); \ + } \ + } \ + } while (0); +static inline void dhd_wk_lock_rec_dump(void) +{ + int bkt; + struct wk_trace_record *wklock_info; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) + hash_for_each(wklock_history, bkt, wklock_info, wklock_node) +#else + struct hlist_node *entry = NULL; + int max_index = ARRAY_SIZE(wklock_history); + for (bkt = 0; bkt < max_index; bkt++) + hlist_for_each_entry(wklock_info, entry, &wklock_history[bkt], wklock_node) +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ + { + switch (wklock_info->lock_type) { + case DHD_WAKE_LOCK: + printk("wakelock lock : %pS lock_counter : %llu \n", + (void *)wklock_info->addr, wklock_info->counter); + break; + case DHD_WAKE_UNLOCK: + printk("wakelock unlock : %pS, unlock_counter : %llu \n", + (void *)wklock_info->addr, wklock_info->counter); + break; + case DHD_WAIVE_LOCK: + printk("wakelock waive : %pS before_waive : %llu \n", + (void *)wklock_info->addr, wklock_info->counter); + break; + case DHD_RESTORE_LOCK: + printk("wakelock restore : %pS, after_waive : %llu \n", + (void *)wklock_info->addr, wklock_info->counter); + break; + } + } +} + +static void dhd_wk_lock_trace_init(struct dhd_info *dhd) +{ + unsigned long flags; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + int i; +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ + + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) + hash_init(wklock_history); +#else + for (i = 0; i < ARRAY_SIZE(wklock_history); i++) + INIT_HLIST_HEAD(&wklock_history[i]); +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); +} + +static void dhd_wk_lock_trace_deinit(struct dhd_info *dhd) +{ + int bkt; + struct wk_trace_record *wklock_info; + struct hlist_node *tmp; + unsigned long flags; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + struct hlist_node *entry = NULL; + int max_index = ARRAY_SIZE(wklock_history); +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ + + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) + hash_for_each_safe(wklock_history, bkt, tmp, wklock_info, wklock_node) +#else + for (bkt = 0; bkt < max_index; bkt++) + hlist_for_each_entry_safe(wklock_info, entry, tmp, + &wklock_history[bkt], wklock_node) +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0)) */ + { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) + hash_del(&wklock_info->wklock_node); +#else + hlist_del_init(&wklock_info->wklock_node); +#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0)) */ + kfree(wklock_info); + } + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); +} + +void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + unsigned long flags; + + printk(KERN_ERR"DHD Printing wl_wake Lock/Unlock Record \r\n"); + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + dhd_wk_lock_rec_dump(); + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + DHD_ERROR((KERN_ERR"Event wakelock counter %u\n", dhd->wakelock_event_counter)); +} +#else +#define STORE_WKLOCK_RECORD(wklock_type) +#endif /* ! DHD_TRACE_WAKE_LOCK */ + + +int dhd_os_wake_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + + if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { +#ifdef CONFIG_HAS_WAKELOCK + wake_lock(&dhd->wl_wifi); +#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_stay_awake(pub); +#endif + } +#ifdef DHD_TRACE_WAKE_LOCK + if (trace_wklock_onoff) { + STORE_WKLOCK_RECORD(DHD_WAKE_LOCK); + } +#endif /* DHD_TRACE_WAKE_LOCK */ + dhd->wakelock_counter++; + ret = dhd->wakelock_counter; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_event_wake_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_evt_spinlock, flags); + if (dhd->wakelock_event_counter == 0) { +#ifdef CONFIG_HAS_WAKELOCK + wake_lock(&dhd->wl_evtwake); +#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_stay_awake(pub); +#endif + } + dhd->wakelock_event_counter++; + ret = dhd->wakelock_event_counter; + spin_unlock_irqrestore(&dhd->wakelock_evt_spinlock, flags); + } + + return ret; +} + +void dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val) +{ +#ifdef CONFIG_HAS_WAKELOCK + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) { + wake_lock_timeout(&dhd->wl_txflwake, msecs_to_jiffies(val)); + } +#endif /* CONFIG_HAS_WAKE_LOCK */ +} + +int net_os_wake_lock(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock(&dhd->pub); + return ret; +} + +int dhd_os_wake_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + dhd_os_wake_lock_timeout(pub); + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (dhd->wakelock_counter > 0) { + dhd->wakelock_counter--; +#ifdef DHD_TRACE_WAKE_LOCK + if (trace_wklock_onoff) { + STORE_WKLOCK_RECORD(DHD_WAKE_UNLOCK); + } +#endif /* DHD_TRACE_WAKE_LOCK */ + if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { +#ifdef CONFIG_HAS_WAKELOCK + wake_unlock(&dhd->wl_wifi); +#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_relax(pub); +#endif + } + ret = dhd->wakelock_counter; + } + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_event_wake_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_evt_spinlock, flags); + + if (dhd->wakelock_event_counter > 0) { + dhd->wakelock_event_counter--; + if (dhd->wakelock_event_counter == 0) { +#ifdef CONFIG_HAS_WAKELOCK + wake_unlock(&dhd->wl_evtwake); +#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_relax(pub); +#endif + } + ret = dhd->wakelock_event_counter; + } + spin_unlock_irqrestore(&dhd->wakelock_evt_spinlock, flags); + } + return ret; +} + +void dhd_txfl_wake_unlock(dhd_pub_t *pub) +{ +#ifdef CONFIG_HAS_WAKELOCK + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) { + /* if wl_txflwake is active, unlock it */ + if (wake_lock_active(&dhd->wl_txflwake)) { + wake_unlock(&dhd->wl_txflwake); + } + } +#endif /* CONFIG_HAS_WAKELOCK */ +} + +int dhd_os_check_wakelock(dhd_pub_t *pub) +{ +#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \ + KERNEL_VERSION(2, 6, 36))) + dhd_info_t *dhd; + + if (!pub) + return 0; + dhd = (dhd_info_t *)(pub->info); +#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ + +#ifdef CONFIG_HAS_WAKELOCK + /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ + if (dhd && (wake_lock_active(&dhd->wl_wifi) || + (wake_lock_active(&dhd->wl_wdwake)))) + return 1; +#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) + return 1; +#endif + return 0; +} + +int dhd_os_check_wakelock_all(dhd_pub_t *pub) +{ +#ifdef CONFIG_HAS_WAKELOCK + int l1, l2, l3, l4, l6, l7; + int l5 = 0; + int c, lock_active; +#endif /* CONFIG_HAS_WAKELOCK */ + +#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \ + KERNEL_VERSION(2, 6, 36))) + dhd_info_t *dhd; + + if (!pub) + return 0; + + dhd = (dhd_info_t *)(pub->info); + if (!dhd) { + return 0; + } +#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ + +#ifdef CONFIG_HAS_WAKELOCK + c = dhd->wakelock_counter; + l1 = wake_lock_active(&dhd->wl_wifi); + l2 = wake_lock_active(&dhd->wl_wdwake); + l3 = wake_lock_active(&dhd->wl_rxwake); + l4 = wake_lock_active(&dhd->wl_ctrlwake); +#ifdef BCMPCIE_OOB_HOST_WAKE + l5 = wake_lock_active(&dhd->wl_intrwake); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + l6 = wake_lock_active(&dhd->wl_evtwake); + l7 = wake_lock_active(&dhd->wl_txflwake); + + lock_active = (l1 || l2 || l3 || l4 || l5 || l6 || l7); + + /* Indicate to the Host to avoid going to suspend if internal locks are up */ + if (dhd && lock_active) { + DHD_ERROR(("%s wakelock c-%d wl-%d wd-%d rx-%d " + "ctl-%d intr-%d evt-%d txfl-%d\n", + __FUNCTION__, c, l1, l2, l3, l4, l5, l6, l7)); + + return 1; + } +#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) + return 1; +#endif /* CONFIG_HAS_WAKELOCK */ + return 0; +} + +int net_os_wake_unlock(struct net_device *dev) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_unlock(&dhd->pub); + return ret; +} + +int dhd_os_wd_wake_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); +#ifdef CONFIG_HAS_WAKELOCK + /* if wakelock_wd_counter was never used : lock it at once */ + if (!dhd->wakelock_wd_counter) + wake_lock(&dhd->wl_wdwake); +#endif + dhd->wakelock_wd_counter++; + ret = dhd->wakelock_wd_counter; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_os_wd_wake_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (dhd->wakelock_wd_counter) { + dhd->wakelock_wd_counter = 0; +#ifdef CONFIG_HAS_WAKELOCK + wake_unlock(&dhd->wl_wdwake); +#endif + } + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +#ifdef BCMPCIE_OOB_HOST_WAKE +int dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + int ret = 0; + + if (dhd) { +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_timeout(&dhd->wl_intrwake, msecs_to_jiffies(val)); +#endif + } + return ret; +} + +int dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + int ret = 0; + + if (dhd) { +#ifdef CONFIG_HAS_WAKELOCK + /* if wl_intrwake is active, unlock it */ + if (wake_lock_active(&dhd->wl_intrwake)) { + wake_unlock(&dhd->wl_intrwake); + } +#endif + } + return ret; +} +#endif /* BCMPCIE_OOB_HOST_WAKE */ + +/* waive wakelocks for operations such as IOVARs in suspend function, must be closed + * by a paired function call to dhd_wakelock_restore. returns current wakelock counter + */ +int dhd_os_wake_lock_waive(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ + if (dhd->waive_wakelock == FALSE) { +#ifdef DHD_TRACE_WAKE_LOCK + if (trace_wklock_onoff) { + STORE_WKLOCK_RECORD(DHD_WAIVE_LOCK); + } +#endif /* DHD_TRACE_WAKE_LOCK */ + /* record current lock status */ + dhd->wakelock_before_waive = dhd->wakelock_counter; + dhd->waive_wakelock = TRUE; + } + ret = dhd->wakelock_wd_counter; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_os_wake_lock_restore(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (!dhd) + return 0; + + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ + if (!dhd->waive_wakelock) + goto exit; + + dhd->waive_wakelock = FALSE; + /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore, + * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases + * the lock in between, do the same by calling wake_unlock or pm_relax + */ +#ifdef DHD_TRACE_WAKE_LOCK + if (trace_wklock_onoff) { + STORE_WKLOCK_RECORD(DHD_RESTORE_LOCK); + } +#endif /* DHD_TRACE_WAKE_LOCK */ + + if (dhd->wakelock_before_waive == 0 && dhd->wakelock_counter > 0) { +#ifdef CONFIG_HAS_WAKELOCK + wake_lock(&dhd->wl_wifi); +#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_stay_awake(&dhd->pub); +#endif + } else if (dhd->wakelock_before_waive > 0 && dhd->wakelock_counter == 0) { +#ifdef CONFIG_HAS_WAKELOCK + wake_unlock(&dhd->wl_wifi); +#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_relax(&dhd->pub); +#endif + } + dhd->wakelock_before_waive = 0; +exit: + ret = dhd->wakelock_wd_counter; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + return ret; +} + +void dhd_os_wake_lock_init(struct dhd_info *dhd) +{ + DHD_TRACE(("%s: initialize wake_lock_counters\n", __FUNCTION__)); + dhd->wakelock_event_counter = 0; + dhd->wakelock_counter = 0; + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); + wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); + wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); + wake_lock_init(&dhd->wl_evtwake, WAKE_LOCK_SUSPEND, "wlan_evt_wake"); + wake_lock_init(&dhd->wl_txflwake, WAKE_LOCK_SUSPEND, "wlan_txfl_wake"); +#ifdef BCMPCIE_OOB_HOST_WAKE + wake_lock_init(&dhd->wl_intrwake, WAKE_LOCK_SUSPEND, "wlan_oob_irq_wake"); +#endif /* BCMPCIE_OOB_HOST_WAKE */ +#ifdef DHD_TRACE_WAKE_LOCK + dhd_wk_lock_trace_init(dhd); +#endif /* DHD_TRACE_WAKE_LOCK */ +#endif /* CONFIG_HAS_WAKELOCK */ +} + +void dhd_os_wake_lock_destroy(struct dhd_info *dhd) +{ + DHD_TRACE(("%s: deinit wake_lock_counters\n", __FUNCTION__)); + dhd->wakelock_event_counter = 0; + dhd->wakelock_counter = 0; + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_destroy(&dhd->wl_wifi); + wake_lock_destroy(&dhd->wl_rxwake); + wake_lock_destroy(&dhd->wl_ctrlwake); + wake_lock_destroy(&dhd->wl_evtwake); + wake_lock_destroy(&dhd->wl_txflwake); +#ifdef BCMPCIE_OOB_HOST_WAKE + wake_lock_destroy(&dhd->wl_intrwake); +#endif /* BCMPCIE_OOB_HOST_WAKE */ +#ifdef DHD_TRACE_WAKE_LOCK + dhd_wk_lock_trace_deinit(dhd); +#endif /* DHD_TRACE_WAKE_LOCK */ +#endif /* CONFIG_HAS_WAKELOCK */ +} + +bool dhd_os_check_if_up(dhd_pub_t *pub) +{ + if (!pub) + return FALSE; + return pub->up; +} + +#if defined(BCMSDIO) +/* function to collect firmware, chip id and chip version info */ +void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) +{ + int i; + + i = snprintf(info_string, sizeof(info_string), + " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); + + if (!dhdp) + return; + + i = snprintf(&info_string[i], sizeof(info_string) - i, + "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), + dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); +} +#endif /* defined(BCMSDIO) */ +int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) +{ + int ifidx; + int ret = 0; + dhd_info_t *dhd = NULL; + + if (!net || !DEV_PRIV(net)) { + DHD_ERROR(("%s invalid parameter\n", __FUNCTION__)); + return -EINVAL; + } + + dhd = DHD_DEV_INFO(net); + if (!dhd) + return -EINVAL; + + ifidx = dhd_net2idx(dhd, net); + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); + return -ENODEV; + } + + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_PERIM_LOCK(&dhd->pub); + + ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); + dhd_check_hang(net, &dhd->pub, ret); + + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + return ret; +} + +bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) +{ + struct net_device *net; + + net = dhd_idx2net(dhdp, ifidx); + if (!net) { + DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx)); + return -EINVAL; + } + + return dhd_check_hang(net, dhdp, ret); +} + +/* Return instance */ +int dhd_get_instance(dhd_pub_t *dhdp) +{ + return dhdp->info->unit; +} + + +#ifdef PROP_TXSTATUS + +void dhd_wlfc_plat_init(void *dhd) +{ + return; +} + +void dhd_wlfc_plat_deinit(void *dhd) +{ + return; +} + +bool dhd_wlfc_skip_fc(void) +{ + return FALSE; +} +#endif /* PROP_TXSTATUS */ + +#ifdef BCMDBGFS + +#include + +extern uint32 dhd_readregl(void *bp, uint32 addr); +extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); + +typedef struct dhd_dbgfs { + struct dentry *debugfs_dir; + struct dentry *debugfs_mem; + dhd_pub_t *dhdp; + uint32 size; +} dhd_dbgfs_t; + +dhd_dbgfs_t g_dbgfs; + +static int +dhd_dbg_state_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t +dhd_dbg_state_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + ssize_t rval; + uint32 tmp; + loff_t pos = *ppos; + size_t ret; + + if (pos < 0) + return -EINVAL; + if (pos >= g_dbgfs.size || !count) + return 0; + if (count > g_dbgfs.size - pos) + count = g_dbgfs.size - pos; + + /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ + tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); + + ret = copy_to_user(ubuf, &tmp, 4); + if (ret == count) + return -EFAULT; + + count -= ret; + *ppos = pos + count; + rval = count; + + return rval; +} + + +static ssize_t +dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) +{ + loff_t pos = *ppos; + size_t ret; + uint32 buf; + + if (pos < 0) + return -EINVAL; + if (pos >= g_dbgfs.size || !count) + return 0; + if (count > g_dbgfs.size - pos) + count = g_dbgfs.size - pos; + + ret = copy_from_user(&buf, ubuf, sizeof(uint32)); + if (ret == count) + return -EFAULT; + + /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ + dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); + + return count; +} + + +loff_t +dhd_debugfs_lseek(struct file *file, loff_t off, int whence) +{ + loff_t pos = -1; + + switch (whence) { + case 0: + pos = off; + break; + case 1: + pos = file->f_pos + off; + break; + case 2: + pos = g_dbgfs.size - off; + } + return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); +} + +static const struct file_operations dhd_dbg_state_ops = { + .read = dhd_dbg_state_read, + .write = dhd_debugfs_write, + .open = dhd_dbg_state_open, + .llseek = dhd_debugfs_lseek +}; + +static void dhd_dbg_create(void) +{ + if (g_dbgfs.debugfs_dir) { + g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, + NULL, &dhd_dbg_state_ops); + } +} + +void dhd_dbg_init(dhd_pub_t *dhdp) +{ + int err; + + g_dbgfs.dhdp = dhdp; + g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ + + g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); + if (IS_ERR(g_dbgfs.debugfs_dir)) { + err = PTR_ERR(g_dbgfs.debugfs_dir); + g_dbgfs.debugfs_dir = NULL; + return; + } + + dhd_dbg_create(); + + return; +} + +void dhd_dbg_remove(void) +{ + debugfs_remove(g_dbgfs.debugfs_mem); + debugfs_remove(g_dbgfs.debugfs_dir); + + bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); + +} +#endif /* ifdef BCMDBGFS */ + +#ifdef WLMEDIA_HTSF + +static +void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) +{ + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct sk_buff *skb; + uint32 htsf = 0; + uint16 dport = 0, oldmagic = 0xACAC; + char *p1; + htsfts_t ts; + + /* timestamp packet */ + + p1 = (char*) PKTDATA(dhdp->osh, pktbuf); + + if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { +/* memcpy(&proto, p1+26, 4); */ + memcpy(&dport, p1+40, 2); +/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ + dport = ntoh16(dport); + } + + /* timestamp only if icmp or udb iperf with port 5555 */ +/* if (proto == 17 && dport == tsport) { */ + if (dport >= tsport && dport <= tsport + 20) { + + skb = (struct sk_buff *) pktbuf; + + htsf = dhd_get_htsf(dhd, 0); + memset(skb->data + 44, 0, 2); /* clear checksum */ + memcpy(skb->data+82, &oldmagic, 2); + memcpy(skb->data+84, &htsf, 4); + + memset(&ts, 0, sizeof(htsfts_t)); + ts.magic = HTSFMAGIC; + ts.prio = PKTPRIO(pktbuf); + ts.seqnum = htsf_seqnum++; + ts.c10 = get_cycles(); + ts.t10 = htsf; + ts.endmagic = HTSFENDMAGIC; + + memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); + } +} + +static void dhd_dump_htsfhisto(histo_t *his, char *s) +{ + int pktcnt = 0, curval = 0, i; + for (i = 0; i < (NUMBIN-2); i++) { + curval += 500; + printf("%d ", his->bin[i]); + pktcnt += his->bin[i]; + } + printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, + his->bin[NUMBIN-1], s); +} + +static +void sorttobin(int value, histo_t *histo) +{ + int i, binval = 0; + + if (value < 0) { + histo->bin[NUMBIN-1]++; + return; + } + if (value > histo->bin[NUMBIN-2]) /* store the max value */ + histo->bin[NUMBIN-2] = value; + + for (i = 0; i < (NUMBIN-2); i++) { + binval += 500; /* 500m s bins */ + if (value <= binval) { + histo->bin[i]++; + return; + } + } + histo->bin[NUMBIN-3]++; +} + +static +void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + struct sk_buff *skb; + char *p1; + uint16 old_magic; + int d1, d2, d3, end2end; + htsfts_t *htsf_ts; + uint32 htsf; + + skb = PKTTONATIVE(dhdp->osh, pktbuf); + p1 = (char*)PKTDATA(dhdp->osh, pktbuf); + + if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { + memcpy(&old_magic, p1+78, 2); + htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); + } + else + return; + + if (htsf_ts->magic == HTSFMAGIC) { + htsf_ts->tE0 = dhd_get_htsf(dhd, 0); + htsf_ts->cE0 = get_cycles(); + } + + if (old_magic == 0xACAC) { + + tspktcnt++; + htsf = dhd_get_htsf(dhd, 0); + memcpy(skb->data+92, &htsf, sizeof(uint32)); + + memcpy(&ts[tsidx].t1, skb->data+80, 16); + + d1 = ts[tsidx].t2 - ts[tsidx].t1; + d2 = ts[tsidx].t3 - ts[tsidx].t2; + d3 = ts[tsidx].t4 - ts[tsidx].t3; + end2end = ts[tsidx].t4 - ts[tsidx].t1; + + sorttobin(d1, &vi_d1); + sorttobin(d2, &vi_d2); + sorttobin(d3, &vi_d3); + sorttobin(end2end, &vi_d4); + + if (end2end > 0 && end2end > maxdelay) { + maxdelay = end2end; + maxdelaypktno = tspktcnt; + memcpy(&maxdelayts, &ts[tsidx], 16); + } + if (++tsidx >= TSMAX) + tsidx = 0; + } +} + +uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) +{ + uint32 htsf = 0, cur_cycle, delta, delta_us; + uint32 factor, baseval, baseval2; + cycles_t t; + + t = get_cycles(); + cur_cycle = t; + + if (cur_cycle > dhd->htsf.last_cycle) + delta = cur_cycle - dhd->htsf.last_cycle; + else { + delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); + } + + delta = delta >> 4; + + if (dhd->htsf.coef) { + /* times ten to get the first digit */ + factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); + baseval = (delta*10)/factor; + baseval2 = (delta*10)/(factor+1); + delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); + htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; + } + else { + DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n")); + } + + return htsf; +} + +static void dhd_dump_latency(void) +{ + int i, max = 0; + int d1, d2, d3, d4, d5; + + printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); + for (i = 0; i < TSMAX; i++) { + d1 = ts[i].t2 - ts[i].t1; + d2 = ts[i].t3 - ts[i].t2; + d3 = ts[i].t4 - ts[i].t3; + d4 = ts[i].t4 - ts[i].t1; + d5 = ts[max].t4-ts[max].t1; + if (d4 > d5 && d4 > 0) { + max = i; + } + printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", + ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, + d1, d2, d3, d4, i); + } + + printf("current idx = %d \n", tsidx); + + printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); + printf("%08X %08X %08X %08X \t%d %d %d %d\n", + maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, + maxdelayts.t2 - maxdelayts.t1, + maxdelayts.t3 - maxdelayts.t2, + maxdelayts.t4 - maxdelayts.t3, + maxdelayts.t4 - maxdelayts.t1); +} + + +static int +dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) +{ + char buf[32]; + int ret; + uint32 s1, s2; + + struct tsf { + uint32 low; + uint32 high; + } tsf_buf; + + memset(&tsf_buf, 0, sizeof(tsf_buf)); + + s1 = dhd_get_htsf(dhd, 0); + ret = dhd_iovar(&dhd->pub, ifidx, "tsf", NULL, 0, buf, sizeof(buf), FALSE); + if (ret < 0) { + if (ret == -EIO) { + DHD_ERROR(("%s: tsf is not supported by device\n", + dhd_ifname(&dhd->pub, ifidx))); + return -EOPNOTSUPP; + } + return ret; + } + s2 = dhd_get_htsf(dhd, 0); + + memcpy(&tsf_buf, buf, sizeof(tsf_buf)); + printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", + tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, + dhd->htsf.coefdec2, s2-tsf_buf.low); + printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); + return 0; +} + +void htsf_update(dhd_info_t *dhd, void *data) +{ + static ulong cur_cycle = 0, prev_cycle = 0; + uint32 htsf, tsf_delta = 0; + uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; + ulong b, a; + cycles_t t; + + /* cycles_t in inlcude/mips/timex.h */ + + t = get_cycles(); + + prev_cycle = cur_cycle; + cur_cycle = t; + + if (cur_cycle > prev_cycle) + cyc_delta = cur_cycle - prev_cycle; + else { + b = cur_cycle; + a = prev_cycle; + cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); + } + + if (data == NULL) + printf(" tsf update ata point er is null \n"); + + memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); + memcpy(&cur_tsf, data, sizeof(tsf_t)); + + if (cur_tsf.low == 0) { + DHD_INFO((" ---- 0 TSF, do not update, return\n")); + return; + } + + if (cur_tsf.low > prev_tsf.low) + tsf_delta = (cur_tsf.low - prev_tsf.low); + else { + DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", + cur_tsf.low, prev_tsf.low)); + if (cur_tsf.high > prev_tsf.high) { + tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); + DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta)); + } + else + return; /* do not update */ + } + + if (tsf_delta) { + hfactor = cyc_delta / tsf_delta; + tmp = (cyc_delta - (hfactor * tsf_delta))*10; + dec1 = tmp/tsf_delta; + dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; + tmp = (tmp - (dec1*tsf_delta))*10; + dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; + + if (dec3 > 4) { + if (dec2 == 9) { + dec2 = 0; + if (dec1 == 9) { + dec1 = 0; + hfactor++; + } + else { + dec1++; + } + } + else + dec2++; + } + } + + if (hfactor) { + htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; + dhd->htsf.coef = hfactor; + dhd->htsf.last_cycle = cur_cycle; + dhd->htsf.last_tsf = cur_tsf.low; + dhd->htsf.coefdec1 = dec1; + dhd->htsf.coefdec2 = dec2; + } + else { + htsf = prev_tsf.low; + } +} + +#endif /* WLMEDIA_HTSF */ + +#ifdef CUSTOM_SET_CPUCORE +void dhd_set_cpucore(dhd_pub_t *dhd, int set) +{ + int e_dpc = 0, e_rxf = 0, retry_set = 0; + + if (!(dhd->chan_isvht80)) { + DHD_ERROR(("%s: chan_status(%d) cpucore!!!\n", __FUNCTION__, dhd->chan_isvht80)); + return; + } + + if (DPC_CPUCORE) { + do { + if (set == TRUE) { + e_dpc = set_cpus_allowed_ptr(dhd->current_dpc, + cpumask_of(DPC_CPUCORE)); + } else { + e_dpc = set_cpus_allowed_ptr(dhd->current_dpc, + cpumask_of(PRIMARY_CPUCORE)); + } + if (retry_set++ > MAX_RETRY_SET_CPUCORE) { + DHD_ERROR(("%s: dpc(%d) invalid cpu!\n", __FUNCTION__, e_dpc)); + return; + } + if (e_dpc < 0) + OSL_SLEEP(1); + } while (e_dpc < 0); + } + if (RXF_CPUCORE) { + do { + if (set == TRUE) { + e_rxf = set_cpus_allowed_ptr(dhd->current_rxf, + cpumask_of(RXF_CPUCORE)); + } else { + e_rxf = set_cpus_allowed_ptr(dhd->current_rxf, + cpumask_of(PRIMARY_CPUCORE)); + } + if (retry_set++ > MAX_RETRY_SET_CPUCORE) { + DHD_ERROR(("%s: rxf(%d) invalid cpu!\n", __FUNCTION__, e_rxf)); + return; + } + if (e_rxf < 0) + OSL_SLEEP(1); + } while (e_rxf < 0); + } +#ifdef DHD_OF_SUPPORT + interrupt_set_cpucore(set); +#endif /* DHD_OF_SUPPORT */ + DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set)); + + return; +} +#endif /* CUSTOM_SET_CPUCORE */ + +/* Get interface specific ap_isolate configuration */ +int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx) +{ + dhd_info_t *dhd = dhdp->info; + dhd_if_t *ifp; + + ASSERT(idx < DHD_MAX_IFS); + + ifp = dhd->iflist[idx]; + + return ifp->ap_isolate; +} + +/* Set interface specific ap_isolate configuration */ +int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val) +{ + dhd_info_t *dhd = dhdp->info; + dhd_if_t *ifp; + + ASSERT(idx < DHD_MAX_IFS); + + ifp = dhd->iflist[idx]; + + if (ifp) + ifp->ap_isolate = val; + + return 0; +} + +#ifdef DHD_DEBUG +void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size) +{ + dhd_dump_t *dump = NULL; + dump = (dhd_dump_t *)MALLOC(dhdp->osh, sizeof(dhd_dump_t)); + if (dump == NULL) { + DHD_ERROR(("%s: dhd dump memory allocation failed\n", __FUNCTION__)); + return; + } + dump->buf = buf; + dump->bufsize = size; + dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dump, + DHD_WQ_WORK_SOC_RAM_DUMP, dhd_mem_dump, DHD_WORK_PRIORITY_HIGH); +} + +static void +dhd_mem_dump(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + dhd_dump_t *dump = event_info; + + if (!dhd || !dump) + return; + +#ifndef CONFIG_BCM_WLAN_RAMDUMP + if (write_to_file(&dhd->pub, dump->buf, dump->bufsize)) { + DHD_ERROR(("%s: writing SoC_RAM dump to the file failed\n", __FUNCTION__)); + } +#else + bcm_wlan_crash_reason(dhd->pub.crash_reason); + bcm_wlan_ramdump(dump->buf, dump->bufsize); + memset(dhd->pub.crash_reason, 0 , sizeof(dhd->pub.crash_reason)); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + MFREE(dhd->pub.osh, dump, sizeof(dhd_dump_t)); +} +#endif /* DHD_DEBUG */ + +#ifdef DHD_WMF +/* Returns interface specific WMF configuration */ +dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx) +{ + dhd_info_t *dhd = dhdp->info; + dhd_if_t *ifp; + + ASSERT(idx < DHD_MAX_IFS); + + ifp = dhd->iflist[idx]; + return &ifp->wmf; +} +#endif /* DHD_WMF */ + + +#ifdef DHD_UNICAST_DHCP +static int +dhd_get_pkt_ether_type(dhd_pub_t *pub, void *pktbuf, + uint8 **data_ptr, int *len_ptr, uint16 *et_ptr, bool *snap_ptr) +{ + uint8 *frame = PKTDATA(pub->osh, pktbuf); + int length = PKTLEN(pub->osh, pktbuf); + uint8 *pt; /* Pointer to type field */ + uint16 ethertype; + bool snap = FALSE; + /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ + if (length < ETHER_HDR_LEN) { + DHD_ERROR(("dhd: %s: short eth frame (%d)\n", + __FUNCTION__, length)); + return BCME_ERROR; + } else if (ntoh16_ua(frame + ETHER_TYPE_OFFSET) >= ETHER_TYPE_MIN) { + /* Frame is Ethernet II */ + pt = frame + ETHER_TYPE_OFFSET; + } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && + !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { + pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; + snap = TRUE; + } else { + DHD_INFO(("DHD: %s: non-SNAP 802.3 frame\n", + __FUNCTION__)); + return BCME_ERROR; + } + + ethertype = ntoh16_ua(pt); + + /* Skip VLAN tag, if any */ + if (ethertype == ETHER_TYPE_8021Q) { + pt += VLAN_TAG_LEN; + + if ((pt + ETHER_TYPE_LEN) > (frame + length)) { + DHD_ERROR(("dhd: %s: short VLAN frame (%d)\n", + __FUNCTION__, length)); + return BCME_ERROR; + } + + ethertype = ntoh16_ua(pt); + } + + *data_ptr = pt + ETHER_TYPE_LEN; + *len_ptr = length - (pt + ETHER_TYPE_LEN - frame); + *et_ptr = ethertype; + *snap_ptr = snap; + return BCME_OK; +} + +static int +dhd_get_pkt_ip_type(dhd_pub_t *pub, void *pktbuf, + uint8 **data_ptr, int *len_ptr, uint8 *prot_ptr) +{ + struct ipv4_hdr *iph; /* IP frame pointer */ + int iplen; /* IP frame length */ + uint16 ethertype, iphdrlen, ippktlen; + uint16 iph_frag; + uint8 prot; + bool snap; + + if (dhd_get_pkt_ether_type(pub, pktbuf, (uint8 **)&iph, + &iplen, ðertype, &snap) != 0) + return BCME_ERROR; + + if (ethertype != ETHER_TYPE_IP) { + return BCME_ERROR; + } + + /* We support IPv4 only */ + if (iplen < IPV4_OPTIONS_OFFSET || (IP_VER(iph) != IP_VER_4)) { + return BCME_ERROR; + } + + /* Header length sanity */ + iphdrlen = IPV4_HLEN(iph); + + /* + * Packet length sanity; sometimes we receive eth-frame size bigger + * than the IP content, which results in a bad tcp chksum + */ + ippktlen = ntoh16(iph->tot_len); + if (ippktlen < iplen) { + + DHD_INFO(("%s: extra frame length ignored\n", + __FUNCTION__)); + iplen = ippktlen; + } else if (ippktlen > iplen) { + DHD_ERROR(("dhd: %s: truncated IP packet (%d)\n", + __FUNCTION__, ippktlen - iplen)); + return BCME_ERROR; + } + + if (iphdrlen < IPV4_OPTIONS_OFFSET || iphdrlen > iplen) { + DHD_ERROR(("DHD: %s: IP-header-len (%d) out of range (%d-%d)\n", + __FUNCTION__, iphdrlen, IPV4_OPTIONS_OFFSET, iplen)); + return BCME_ERROR; + } + + /* + * We don't handle fragmented IP packets. A first frag is indicated by the MF + * (more frag) bit and a subsequent frag is indicated by a non-zero frag offset. + */ + iph_frag = ntoh16(iph->frag); + + if ((iph_frag & IPV4_FRAG_MORE) || (iph_frag & IPV4_FRAG_OFFSET_MASK) != 0) { + DHD_INFO(("DHD:%s: IP fragment not handled\n", + __FUNCTION__)); + return BCME_ERROR; + } + + prot = IPV4_PROT(iph); + + *data_ptr = (((uint8 *)iph) + iphdrlen); + *len_ptr = iplen - iphdrlen; + *prot_ptr = prot; + return BCME_OK; +} + +/** check the packet type, if it is DHCP ACK/REPLY, convert into unicast packet */ +static +int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx) +{ + dhd_sta_t* stainfo; + uint8 *eh = PKTDATA(pub->osh, pktbuf); + uint8 *udph; + uint8 *dhcp; + uint8 *chaddr; + int udpl; + int dhcpl; + uint16 port; + uint8 prot; + + if (!ETHER_ISMULTI(eh + ETHER_DEST_OFFSET)) + return BCME_ERROR; + if (dhd_get_pkt_ip_type(pub, pktbuf, &udph, &udpl, &prot) != 0) + return BCME_ERROR; + if (prot != IP_PROT_UDP) + return BCME_ERROR; + /* check frame length, at least UDP_HDR_LEN */ + if (udpl < UDP_HDR_LEN) { + DHD_ERROR(("DHD: %s: short UDP frame, ignored\n", + __FUNCTION__)); + return BCME_ERROR; + } + port = ntoh16_ua(udph + UDP_DEST_PORT_OFFSET); + /* only process DHCP packets from server to client */ + if (port != DHCP_PORT_CLIENT) + return BCME_ERROR; + + dhcp = udph + UDP_HDR_LEN; + dhcpl = udpl - UDP_HDR_LEN; + + if (dhcpl < DHCP_CHADDR_OFFSET + ETHER_ADDR_LEN) { + DHD_ERROR(("DHD: %s: short DHCP frame, ignored\n", + __FUNCTION__)); + return BCME_ERROR; + } + /* only process DHCP reply(offer/ack) packets */ + if (*(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY) + return BCME_ERROR; + chaddr = dhcp + DHCP_CHADDR_OFFSET; + stainfo = dhd_find_sta(pub, ifidx, chaddr); + if (stainfo) { + bcopy(chaddr, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); + return BCME_OK; + } + return BCME_ERROR; +} +#endif /* DHD_UNICAST_DHD */ +#ifdef DHD_L2_FILTER +/* Check if packet type is ICMP ECHO */ +static +int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx) +{ + struct bcmicmp_hdr *icmph; + int udpl; + uint8 prot; + + if (dhd_get_pkt_ip_type(pub, pktbuf, (uint8 **)&icmph, &udpl, &prot) != 0) + return BCME_ERROR; + if (prot == IP_PROT_ICMP) { + if (icmph->type == ICMP_TYPE_ECHO_REQUEST) + return BCME_OK; + } + return BCME_ERROR; +} +#endif /* DHD_L2_FILTER */ + +#if defined(SET_RPS_CPUS) +int dhd_rps_cpus_enable(struct net_device *net, int enable) +{ + dhd_info_t *dhd = DHD_DEV_INFO(net); + dhd_if_t *ifp; + int ifidx; + char * RPS_CPU_SETBUF; + + ifidx = dhd_net2idx(dhd, net); + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); + return -ENODEV; + } + + if (ifidx == PRIMARY_INF) { + if (dhd->pub.op_mode == DHD_FLAG_IBSS_MODE) { + DHD_INFO(("%s : set for IBSS.\n", __FUNCTION__)); + RPS_CPU_SETBUF = RPS_CPUS_MASK_IBSS; + } else { + DHD_INFO(("%s : set for BSS.\n", __FUNCTION__)); + RPS_CPU_SETBUF = RPS_CPUS_MASK; + } + } else if (ifidx == VIRTUAL_INF) { + DHD_INFO(("%s : set for P2P.\n", __FUNCTION__)); + RPS_CPU_SETBUF = RPS_CPUS_MASK_P2P; + } else { + DHD_ERROR(("%s : Invalid index : %d.\n", __FUNCTION__, ifidx)); + return -EINVAL; + } + + ifp = dhd->iflist[ifidx]; + if (ifp) { + if (enable) { + DHD_INFO(("%s : set rps_cpus as [%s]\n", __FUNCTION__, RPS_CPU_SETBUF)); + custom_rps_map_set(ifp->net->_rx, RPS_CPU_SETBUF, strlen(RPS_CPU_SETBUF)); + } else { + custom_rps_map_clear(ifp->net->_rx); + } + } else { + DHD_ERROR(("%s : ifp is NULL!!\n", __FUNCTION__)); + return -ENODEV; + } + return BCME_OK; +} + +int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len) +{ + struct rps_map *old_map, *map; + cpumask_var_t mask; + int err, cpu, i; + static DEFINE_SPINLOCK(rps_map_lock); + + DHD_INFO(("%s : Entered.\n", __FUNCTION__)); + + if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { + DHD_ERROR(("%s : alloc_cpumask_var fail.\n", __FUNCTION__)); + return -ENOMEM; + } + + err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); + if (err) { + free_cpumask_var(mask); + DHD_ERROR(("%s : bitmap_parse fail.\n", __FUNCTION__)); + return err; + } + + map = kzalloc(max_t(unsigned int, + RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), + GFP_KERNEL); + if (!map) { + free_cpumask_var(mask); + DHD_ERROR(("%s : map malloc fail.\n", __FUNCTION__)); + return -ENOMEM; + } + + i = 0; + for_each_cpu(cpu, mask) + map->cpus[i++] = cpu; + + if (i) + map->len = i; + else { + kfree(map); + map = NULL; + free_cpumask_var(mask); + DHD_ERROR(("%s : mapping cpu fail.\n", __FUNCTION__)); + return -1; + } + + spin_lock(&rps_map_lock); + old_map = rcu_dereference_protected(queue->rps_map, + lockdep_is_held(&rps_map_lock)); + rcu_assign_pointer(queue->rps_map, map); + spin_unlock(&rps_map_lock); + + if (map) + static_key_slow_inc(&rps_needed); + if (old_map) { + kfree_rcu(old_map, rcu); + static_key_slow_dec(&rps_needed); + } + free_cpumask_var(mask); + + DHD_INFO(("%s : Done. mapping cpu nummber : %d\n", __FUNCTION__, map->len)); + return map->len; +} + +void custom_rps_map_clear(struct netdev_rx_queue *queue) +{ + struct rps_map *map; + + DHD_INFO(("%s : Entered.\n", __FUNCTION__)); + + map = rcu_dereference_protected(queue->rps_map, 1); + if (map) { + RCU_INIT_POINTER(queue->rps_map, NULL); + kfree_rcu(map, rcu); + DHD_INFO(("%s : rps_cpus map clear.\n", __FUNCTION__)); + } +} +#endif /* SET_RPS_CPUS */ + + +/* ---------------------------------------------------------------------------- + * Infrastructure code for sysfs interface support for DHD + * + * What is sysfs interface? + * https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt + * + * Why sysfs interface? + * This is the Linux standard way of changing/configuring Run Time parameters + * for a driver. We can use this interface to control "linux" specific driver + * parameters. + * + * ----------------------------------------------------------------------------- + */ + +#include +#include + +#if defined(DHD_TRACE_WAKE_LOCK) + +/* Function to show the history buffer */ +static ssize_t +show_wklock_trace(struct dhd_info *dev, char *buf) +{ + ssize_t ret = 0; + dhd_info_t *dhd = (dhd_info_t *)dev; + + buf[ret] = '\n'; + buf[ret+1] = 0; + + dhd_wk_lock_stats_dump(&dhd->pub); + return ret+1; +} + +/* Function to enable/disable wakelock trace */ +static ssize_t +wklock_trace_onoff(struct dhd_info *dev, const char *buf, size_t count) +{ + unsigned long onoff; + unsigned long flags; + dhd_info_t *dhd = (dhd_info_t *)dev; + + onoff = bcm_strtoul(buf, NULL, 10); + if (onoff != 0 && onoff != 1) { + return -EINVAL; + } + + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + trace_wklock_onoff = onoff; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + if (trace_wklock_onoff) { + printk("ENABLE WAKELOCK TRACE\n"); + } else { + printk("DISABLE WAKELOCK TRACE\n"); + } + + return (ssize_t)(onoff+1); +} +#endif /* DHD_TRACE_WAKE_LOCK */ + +/* + * Generic Attribute Structure for DHD. + * If we have to add a new sysfs entry under /sys/bcm-dhd/, we have + * to instantiate an object of type dhd_attr, populate it with + * the required show/store functions (ex:- dhd_attr_cpumask_primary) + * and add the object to default_attrs[] array, that gets registered + * to the kobject of dhd (named bcm-dhd). + */ + +struct dhd_attr { + struct attribute attr; + ssize_t(*show)(struct dhd_info *, char *); + ssize_t(*store)(struct dhd_info *, const char *, size_t count); +}; + +#if defined(DHD_TRACE_WAKE_LOCK) +static struct dhd_attr dhd_attr_wklock = + __ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff); +#endif /* defined(DHD_TRACE_WAKE_LOCK */ + +/* Attribute object that gets registered with "bcm-dhd" kobject tree */ +static struct attribute *default_attrs[] = { +#if defined(DHD_TRACE_WAKE_LOCK) + &dhd_attr_wklock.attr, +#endif + NULL +}; + +#define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj) +#define to_attr(a) container_of(a, struct dhd_attr, attr) + +/* + * bcm-dhd kobject show function, the "attr" attribute specifices to which + * node under "bcm-dhd" the show function is called. + */ +static ssize_t dhd_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + + dhd_info_t *dhd = to_dhd(kobj); + struct dhd_attr *d_attr = to_attr(attr); +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + int ret; + + if (d_attr->show) + ret = d_attr->show(dhd, buf); + else + ret = -EIO; + + return ret; +} + + +/* + * bcm-dhd kobject show function, the "attr" attribute specifices to which + * node under "bcm-dhd" the store function is called. + */ +static ssize_t dhd_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + dhd_info_t *dhd = to_dhd(kobj); + struct dhd_attr *d_attr = to_attr(attr); +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + int ret; + + if (d_attr->store) + ret = d_attr->store(dhd, buf, count); + else + ret = -EIO; + + return ret; + +} + +static struct sysfs_ops dhd_sysfs_ops = { + .show = dhd_show, + .store = dhd_store, +}; + +static struct kobj_type dhd_ktype = { + .sysfs_ops = &dhd_sysfs_ops, + .default_attrs = default_attrs, +}; + +/* Create a kobject and attach to sysfs interface */ +static int dhd_sysfs_init(dhd_info_t *dhd) +{ + int ret = -1; + + if (dhd == NULL) { + DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__)); + return ret; + } + + /* Initialize the kobject */ + ret = kobject_init_and_add(&dhd->dhd_kobj, &dhd_ktype, NULL, "bcm-dhd"); + if (ret) { + kobject_put(&dhd->dhd_kobj); + DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__)); + return ret; + } + + /* + * We are always responsible for sending the uevent that the kobject + * was added to the system. + */ + kobject_uevent(&dhd->dhd_kobj, KOBJ_ADD); + + return ret; +} + +/* Done with the kobject and detach the sysfs interface */ +static void dhd_sysfs_exit(dhd_info_t *dhd) +{ + if (dhd == NULL) { + DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__)); + return; + } + + /* Releae the kobject */ + kobject_put(&dhd->dhd_kobj); +} + +/* ---------------------------- End of sysfs implementation ------------------------------------- */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.h new file mode 100644 index 000000000000..529f2be46fbb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.h @@ -0,0 +1,127 @@ +/* + * DHD Linux header file (dhd_linux exports for cfg80211 and other components) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux.h 399301 2013-04-29 21:41:52Z $ + */ + +/* wifi platform functions for power, interrupt and pre-alloc, either + * from Android-like platform device data, or Broadcom wifi platform + * device data. + * + */ +#ifndef __DHD_LINUX_H__ +#define __DHD_LINUX_H__ + +#include +#include +#include +#include +#include +#ifdef DHD_WMF +#include +#endif +/* Linux wireless extension support */ +#if defined(WL_WIRELESS_EXT) +#include +#endif /* defined(WL_WIRELESS_EXT) */ +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) +#include +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ +#if defined(CONFIG_WIFI_CONTROL_FUNC) +#include +#endif +#ifdef CUSTOM_FORCE_NODFS_FLAG +#define WLAN_PLAT_NODFS_FLAG 0x01 +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +#if !defined(CONFIG_WIFI_CONTROL_FUNC) +struct wifi_platform_data { + int (*set_power)(int val); + int (*set_reset)(int val); + int (*set_carddetect)(int val); + void *(*mem_prealloc)(int section, unsigned long size); + int (*get_mac_addr)(unsigned char *buf); +#ifdef DHD_WAKE_STATUS + int (*get_wake_irq)(void); +#endif /* DHD_WAKE_STATUS */ +#ifdef CUSTOM_FORCE_NODFS_FLAG + void *(*get_country_code)(char *ccode, u32 flags); +#else + void *(*get_country_code)(char *ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +}; +#endif /* CONFIG_WIFI_CONTROL_FUNC */ + +#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ + +typedef struct wifi_adapter_info { + const char *name; + uint irq_num; + uint intr_flags; + const char *fw_path; + const char *nv_path; + void *wifi_plat_data; /* wifi ctrl func, for backward compatibility */ + uint bus_type; + uint bus_num; + uint slot_num; +} wifi_adapter_info_t; + +typedef struct bcmdhd_wifi_platdata { + uint num_adapters; + wifi_adapter_info_t *adapters; +} bcmdhd_wifi_platdata_t; + +/** Per STA params. A list of dhd_sta objects are managed in dhd_if */ +typedef struct dhd_sta { + uint16 flowid[NUMPRIO]; /* allocated flow ring ids (by priority) */ + void * ifp; /* associated dhd_if */ + struct ether_addr ea; /* stations ethernet mac address */ + struct list_head list; /* link into dhd_if::sta_list */ + int idx; /* index of self in dhd_pub::sta_pool[] */ + int ifidx; /* index of interface in dhd */ +} dhd_sta_t; +typedef dhd_sta_t dhd_sta_pool_t; + +int dhd_wifi_platform_register_drv(void); +void dhd_wifi_platform_unregister_drv(void); +wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, + uint32 slot_num); +int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec); +int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present); +int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr); +int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf); +#ifdef CUSTOM_FORCE_NODFS_FLAG +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, + u32 flags); +#else +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size); +void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter); + +int dhd_get_fw_mode(struct dhd_info *dhdinfo); +bool dhd_update_fw_nv_path(struct dhd_info *dhdinfo); + +#ifdef DHD_WMF +dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx); +#endif /* DHD_WMF */ +#endif /* __DHD_LINUX_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_platdev.c new file mode 100644 index 000000000000..1e4e72d4b9ae --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_platdev.c @@ -0,0 +1,839 @@ +/* + * Linux platform device for DHD WLAN adapter + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux_platdev.c 401742 2013-05-13 15:03:21Z $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_WIFI_CONTROL_FUNC) +#include +#endif +#ifdef CONFIG_DTS +#include +#include +#endif /* CONFIG_DTS */ +#ifdef CONFIG_SOMC_WIFI_CONTROL +#include +#endif /* CONFIG_SOMC_WIFI_CONTROL */ + +#define WIFI_PLAT_NAME "bcmdhd_wlan" +#define WIFI_PLAT_NAME2 "bcm4329_wlan" +#define WIFI_PLAT_EXT "bcmdhd_wifi_platform" + +#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) +struct regulator *wifi_regulator = NULL; +#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ + +bool cfg_multichip = FALSE; +bcmdhd_wifi_platdata_t *dhd_wifi_platdata = NULL; +static int wifi_plat_dev_probe_ret = 0; +static bool is_power_on = FALSE; +#if !defined(CONFIG_DTS) +#if defined(DHD_OF_SUPPORT) +static bool dts_enabled = TRUE; +extern struct resource dhd_wlan_resources; +extern struct wifi_platform_data dhd_wlan_control; +#else +static bool dts_enabled = FALSE; +struct resource dhd_wlan_resources = {0}; +struct wifi_platform_data dhd_wlan_control = {0}; +#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */ +#endif /* !defind(CONFIG_DTS) */ + +static int dhd_wifi_platform_load(void); + +extern void* wl_cfg80211_get_dhdp(void); + +#ifdef ENABLE_4335BT_WAR +extern int bcm_bt_lock(int cookie); +extern void bcm_bt_unlock(int cookie); +static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ +#endif /* ENABLE_4335BT_WAR */ + +wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num) +{ + int i; + + if (dhd_wifi_platdata == NULL) + return NULL; + + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; + if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && + (adapter->bus_num == -1 || adapter->bus_num == bus_num) && + (adapter->slot_num == -1 || adapter->slot_num == slot_num)) { + DHD_TRACE(("found adapter info '%s'\n", adapter->name)); + return adapter; + } + } + return NULL; +} + +void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size) +{ + void *alloc_ptr = NULL; + struct wifi_platform_data *plat_data; + + if (!adapter || !adapter->wifi_plat_data) + return NULL; + plat_data = adapter->wifi_plat_data; + if (plat_data->mem_prealloc) { + alloc_ptr = plat_data->mem_prealloc(section, size); + if (alloc_ptr) { + DHD_INFO(("success alloc section %d\n", section)); + if (size != 0L) + bzero(alloc_ptr, size); + return alloc_ptr; + } + } + + DHD_ERROR(("%s: failed to alloc static mem section %d\n", __FUNCTION__, section)); + return NULL; +} + +void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter) +{ + struct wifi_platform_data *plat_data; + + if (!adapter || !adapter->wifi_plat_data) + return NULL; + plat_data = adapter->wifi_plat_data; + return plat_data->mem_prealloc; +} + +int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr) +{ + if (adapter == NULL) + return -1; + if (irq_flags_ptr) + *irq_flags_ptr = adapter->intr_flags; + return adapter->irq_num; +} + +int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec) +{ + int err = 0; +#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) + if (on) { + err = regulator_enable(wifi_regulator); + is_power_on = TRUE; + } + else { + err = regulator_disable(wifi_regulator); + is_power_on = FALSE; + } + if (err < 0) + DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__)); +#else + struct wifi_platform_data *plat_data; + + if (!adapter || !adapter->wifi_plat_data) + return -EINVAL; + plat_data = adapter->wifi_plat_data; + + DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); + if (plat_data->set_power) { +#ifdef ENABLE_4335BT_WAR + if (on) { + printk("WiFi: trying to acquire BT lock\n"); + if (bcm_bt_lock(lock_cookie_wifi) != 0) + printk("** WiFi: timeout in acquiring bt lock**\n"); + printk("%s: btlock acquired\n", __FUNCTION__); + } + else { + /* For a exceptional case, release btlock */ + bcm_bt_unlock(lock_cookie_wifi); + } +#endif /* ENABLE_4335BT_WAR */ + + err = plat_data->set_power(on); + } + + if (msec && !err) + OSL_SLEEP(msec); + + if (on && !err) + is_power_on = TRUE; + else + is_power_on = FALSE; + +#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ + + return err; +} + +int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present) +{ + int err = 0; + struct wifi_platform_data *plat_data; + + if (!adapter || !adapter->wifi_plat_data) + return -EINVAL; + plat_data = adapter->wifi_plat_data; + + DHD_ERROR(("%s device present %d\n", __FUNCTION__, device_present)); + if (plat_data->set_carddetect) { + err = plat_data->set_carddetect(device_present); + } + return err; + +} + +int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf) +{ + struct wifi_platform_data *plat_data; + + DHD_ERROR(("%s\n", __FUNCTION__)); + if (!buf || !adapter || !adapter->wifi_plat_data) + return -EINVAL; + plat_data = adapter->wifi_plat_data; + if (plat_data->get_mac_addr) { + return plat_data->get_mac_addr(buf); + } +#ifdef GET_CUSTOM_MAC_ENABLE + return somc_get_mac_address(buf); +#else + return -EOPNOTSUPP; +#endif +} +#ifdef CUSTOM_FORCE_NODFS_FLAG +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, + u32 flags) +#else +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +{ + /* get_country_code was added after 2.6.39 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) + struct wifi_platform_data *plat_data; + + if (!ccode || !adapter || !adapter->wifi_plat_data) + return NULL; + plat_data = adapter->wifi_plat_data; + + DHD_TRACE(("%s\n", __FUNCTION__)); + if (plat_data->get_country_code) { +#ifdef CUSTOM_FORCE_NODFS_FLAG + return plat_data->get_country_code(ccode, flags); +#else + return plat_data->get_country_code(ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ + + return NULL; +} + +static int wifi_plat_dev_drv_probe(struct platform_device *pdev) +{ + struct resource *resource; + wifi_adapter_info_t *adapter; +#ifdef CONFIG_DTS + int irq, gpio; +#endif /* CONFIG_DTS */ + + /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") + * is kept for backward compatibility and supports only 1 adapter + */ + ASSERT(dhd_wifi_platdata != NULL); + ASSERT(dhd_wifi_platdata->num_adapters == 1); + adapter = &dhd_wifi_platdata->adapters[0]; +#ifdef CONFIG_SOMC_WIFI_CONTROL + adapter->wifi_plat_data = (void *)&somc_wifi_control; +#else + adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data); +#endif /* CONFIG_SOMC_WIFI_CONTROL */ + resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); + if (resource == NULL) + resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); + if (resource) { + adapter->irq_num = resource->start; + adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK; + } +#ifdef CONFIG_SOMC_WIFI_CONTROL + somc_wifi_init(pdev); +#endif /* CONFIG_SOMC_WIFI_CONTROL */ +#ifdef CONFIG_DTS +#ifndef CUSTOMER_HW5 + wifi_regulator = regulator_get(&pdev->dev, "wlreg_on"); + if (wifi_regulator == NULL) { + DHD_ERROR(("%s regulator is null\n", __FUNCTION__)); + return -1; + } +#endif /* CUSTOMER_HW5 */ + /* This is to get the irq for the OOB */ +#ifdef CONFIG_SOMC_WIFI_CONTROL + gpio = of_get_gpio(pdev->dev.of_node, 1); +#else + gpio = of_get_gpio(pdev->dev.of_node, 0); +#endif /* CONFIG_SOMC_WIFI_CONTROL */ + if (gpio < 0) { + DHD_ERROR(("%s gpio information is incorrect\n", __FUNCTION__)); + return -1; + } + irq = gpio_to_irq(gpio); + if (irq < 0) { + DHD_ERROR(("%s irq information is incorrect\n", __FUNCTION__)); + return -1; + } + adapter->irq_num = irq; + + /* need to change the flags according to our requirement */ + adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE; +#endif /* CONFIG_DTS */ + + wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); + return wifi_plat_dev_probe_ret; +} + +static int wifi_plat_dev_drv_remove(struct platform_device *pdev) +{ + wifi_adapter_info_t *adapter; + + /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") + * is kept for backward compatibility and supports only 1 adapter + */ + ASSERT(dhd_wifi_platdata != NULL); + ASSERT(dhd_wifi_platdata->num_adapters == 1); + adapter = &dhd_wifi_platdata->adapters[0]; + if (is_power_on) { +#ifdef BCMPCIE + wifi_platform_bus_enumerate(adapter, FALSE); + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); +#else + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + wifi_platform_bus_enumerate(adapter, FALSE); +#endif /* BCMPCIE */ + } + +#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) + regulator_put(wifi_regulator); +#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ +#ifdef CONFIG_SOMC_WIFI_CONTROL + somc_wifi_deinit(pdev); +#endif /* CONFIG_SOMC_WIFI_CONTROL */ + return 0; +} + +static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \ + defined(BCMSDIO) + bcmsdh_oob_intr_set(0); +#endif /* (OOB_INTR_ONLY) */ + return 0; +} + +static int wifi_plat_dev_drv_resume(struct platform_device *pdev) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \ + defined(BCMSDIO) + if (dhd_os_check_if_up(wl_cfg80211_get_dhdp())) + bcmsdh_oob_intr_set(1); +#endif /* (OOB_INTR_ONLY) */ + return 0; +} + +#ifdef CONFIG_DTS +static const struct of_device_id wifi_device_dt_match[] = { + { .compatible = "android,bcmdhd_wlan", }, + {}, +}; +#endif /* CONFIG_DTS */ +static struct platform_driver wifi_platform_dev_driver = { + .probe = wifi_plat_dev_drv_probe, + .remove = wifi_plat_dev_drv_remove, + .suspend = wifi_plat_dev_drv_suspend, + .resume = wifi_plat_dev_drv_resume, + .driver = { + .name = WIFI_PLAT_NAME, +#ifdef CONFIG_DTS + .of_match_table = wifi_device_dt_match, +#endif /* CONFIG_DTS */ + } +}; + +static struct platform_driver wifi_platform_dev_driver_legacy = { + .probe = wifi_plat_dev_drv_probe, + .remove = wifi_plat_dev_drv_remove, + .suspend = wifi_plat_dev_drv_suspend, + .resume = wifi_plat_dev_drv_resume, + .driver = { + .name = WIFI_PLAT_NAME2, + } +}; + +static int wifi_platdev_match(struct device *dev, void *data) +{ + char *name = (char*)data; + struct platform_device *pdev = to_platform_device(dev); + + if (strcmp(pdev->name, name) == 0) { + DHD_ERROR(("found wifi platform device %s\n", name)); + return TRUE; + } + + return FALSE; +} + +static int wifi_ctrlfunc_register_drv(void) +{ + int err = 0; + struct device *dev1, *dev2; + wifi_adapter_info_t *adapter; + + dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); + dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); + +#if !defined(CONFIG_DTS) + if (!dts_enabled) { + if (dev1 == NULL && dev2 == NULL) { + DHD_ERROR(("no wifi platform data, skip\n")); + return -ENXIO; + } + } +#endif /* !defined(CONFIG_DTS) */ + + /* multi-chip support not enabled, build one adapter information for + * DHD (either SDIO, USB or PCIe) + */ + adapter = kzalloc(sizeof(wifi_adapter_info_t), GFP_KERNEL); + adapter->name = "DHD generic adapter"; + adapter->bus_type = -1; + adapter->bus_num = -1; + adapter->slot_num = -1; + adapter->irq_num = -1; + is_power_on = FALSE; + wifi_plat_dev_probe_ret = 0; + dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL); + dhd_wifi_platdata->num_adapters = 1; + dhd_wifi_platdata->adapters = adapter; + + if (dev1) { + err = platform_driver_register(&wifi_platform_dev_driver); + if (err) { + DHD_ERROR(("%s: failed to register wifi ctrl func driver\n", + __FUNCTION__)); + return err; + } + } + if (dev2) { + err = platform_driver_register(&wifi_platform_dev_driver_legacy); + if (err) { + DHD_ERROR(("%s: failed to register wifi ctrl func legacy driver\n", + __FUNCTION__)); + return err; + } + } + +#if !defined(CONFIG_DTS) + if (dts_enabled) { + struct resource *resource; + adapter->wifi_plat_data = (void *)&dhd_wlan_control; + resource = &dhd_wlan_resources; + adapter->irq_num = resource->start; + adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK; + wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); + } +#endif /* !defined(CONFIG_DTS) */ + + +#ifdef CONFIG_DTS + wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver); +#endif /* CONFIG_DTS */ + + /* return probe function's return value if registeration succeeded */ + return wifi_plat_dev_probe_ret; +} + +void wifi_ctrlfunc_unregister_drv(void) +{ + +#ifdef CONFIG_DTS + DHD_ERROR(("unregister wifi platform drivers\n")); + platform_driver_unregister(&wifi_platform_dev_driver); +#else + struct device *dev1, *dev2; + dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); + dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); + if (!dts_enabled) + if (dev1 == NULL && dev2 == NULL) + return; + + DHD_ERROR(("unregister wifi platform drivers\n")); + if (dev1) + platform_driver_unregister(&wifi_platform_dev_driver); + if (dev2) + platform_driver_unregister(&wifi_platform_dev_driver_legacy); + if (dts_enabled) { + wifi_adapter_info_t *adapter; + adapter = &dhd_wifi_platdata->adapters[0]; + if (is_power_on) { + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + wifi_platform_bus_enumerate(adapter, FALSE); + } + } +#endif /* !defined(CONFIG_DTS) */ + + kfree(dhd_wifi_platdata->adapters); + dhd_wifi_platdata->adapters = NULL; + dhd_wifi_platdata->num_adapters = 0; + kfree(dhd_wifi_platdata); + dhd_wifi_platdata = NULL; +} + +static int bcmdhd_wifi_plat_dev_drv_probe(struct platform_device *pdev) +{ + dhd_wifi_platdata = (bcmdhd_wifi_platdata_t *)(pdev->dev.platform_data); + + return dhd_wifi_platform_load(); +} + +static int bcmdhd_wifi_plat_dev_drv_remove(struct platform_device *pdev) +{ + int i; + wifi_adapter_info_t *adapter; + ASSERT(dhd_wifi_platdata != NULL); + + /* power down all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + adapter = &dhd_wifi_platdata->adapters[i]; + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + wifi_platform_bus_enumerate(adapter, FALSE); + } + return 0; +} + +static struct platform_driver dhd_wifi_platform_dev_driver = { + .probe = bcmdhd_wifi_plat_dev_drv_probe, + .remove = bcmdhd_wifi_plat_dev_drv_remove, + .driver = { + .name = WIFI_PLAT_EXT, + } +}; + +int dhd_wifi_platform_register_drv(void) +{ + int err = 0; + struct device *dev; + + /* register Broadcom wifi platform data driver if multi-chip is enabled, + * otherwise use Android style wifi platform data (aka wifi control function) + * if it exists + * + * to support multi-chip DHD, Broadcom wifi platform data device must + * be added in kernel early boot (e.g. board config file). + */ + if (cfg_multichip) { + dev = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_EXT, wifi_platdev_match); + if (dev == NULL) { + DHD_ERROR(("bcmdhd wifi platform data device not found!!\n")); + return -ENXIO; + } + err = platform_driver_register(&dhd_wifi_platform_dev_driver); + } else { + err = wifi_ctrlfunc_register_drv(); + + /* no wifi ctrl func either, load bus directly and ignore this error */ + if (err) { + if (err == -ENXIO) { + /* wifi ctrl function does not exist */ + err = dhd_wifi_platform_load(); + } else { + /* unregister driver due to initialization failure */ + wifi_ctrlfunc_unregister_drv(); + } + } + } + + return err; +} + +#ifdef BCMPCIE +static int dhd_wifi_platform_load_pcie(void) +{ + int err = 0; + int i; + wifi_adapter_info_t *adapter; + + BCM_REFERENCE(i); + BCM_REFERENCE(adapter); + + if (dhd_wifi_platdata == NULL) { + err = dhd_bus_register(); + } else { +#ifndef CUSTOMER_HW5 + if (dhd_download_fw_on_driverload) { +#else + { +#endif /* CUSTOMER_HW5 */ + /* power up all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + int retry = POWERUP_MAX_RETRY; + adapter = &dhd_wifi_platdata->adapters[i]; + + DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); + DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", + adapter->irq_num, adapter->intr_flags, adapter->fw_path, + adapter->nv_path)); + DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", + adapter->bus_type, adapter->bus_num, adapter->slot_num)); + + do { + err = wifi_platform_set_power(adapter, + TRUE, WIFI_TURNON_DELAY); + if (err) { + DHD_ERROR(("failed to power up %s," + " %d retry left\n", + adapter->name, retry)); + /* WL_REG_ON state unknown, Power off forcely */ + wifi_platform_set_power(adapter, + FALSE, WIFI_TURNOFF_DELAY); + continue; + } else { + err = wifi_platform_bus_enumerate(adapter, TRUE); + if (err) { + DHD_ERROR(("failed to enumerate bus %s, " + "%d retry left\n", + adapter->name, retry)); + wifi_platform_set_power(adapter, FALSE, + WIFI_TURNOFF_DELAY); + } else { + break; + } + } + } while (retry--); + + if (retry < 0) { + DHD_ERROR(("failed to power up %s, max retry reached**\n", + adapter->name)); + return -ENODEV; + } + } + } + + err = dhd_bus_register(); + + if (err) { + DHD_ERROR(("%s: pcie_register_driver failed\n", __FUNCTION__)); +#ifndef CUSTOMER_HW5 + if (dhd_download_fw_on_driverload) { +#else + { +#endif /* CUSTOMER_HW5 */ + /* power down all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + adapter = &dhd_wifi_platdata->adapters[i]; + wifi_platform_bus_enumerate(adapter, FALSE); + wifi_platform_set_power(adapter, + FALSE, WIFI_TURNOFF_DELAY); + } + } + } + } + + return err; +} +#else +static int dhd_wifi_platform_load_pcie(void) +{ + return 0; +} +#endif /* BCMPCIE */ + + +void dhd_wifi_platform_unregister_drv(void) +{ + if (cfg_multichip) + platform_driver_unregister(&dhd_wifi_platform_dev_driver); + else + wifi_ctrlfunc_unregister_drv(); +} + +extern int dhd_watchdog_prio; +extern int dhd_dpc_prio; +extern uint dhd_deferred_tx; +#if defined(BCMLXSDMMC) +extern struct semaphore dhd_registration_sem; +#endif + +#ifdef BCMSDIO +static int dhd_wifi_platform_load_sdio(void) +{ + int i; + int err = 0; + wifi_adapter_info_t *adapter; + + BCM_REFERENCE(i); + BCM_REFERENCE(adapter); + /* Sanity check on the module parameters + * - Both watchdog and DPC as tasklets are ok + * - If both watchdog and DPC are threads, TX must be deferred + */ + if (!(dhd_watchdog_prio < 0 && dhd_dpc_prio < 0) && + !(dhd_watchdog_prio >= 0 && dhd_dpc_prio >= 0 && dhd_deferred_tx)) + return -EINVAL; + +#if defined(BCMLXSDMMC) + if (dhd_wifi_platdata == NULL) { + DHD_ERROR(("DHD wifi platform data is required for Android build\n")); + return -EINVAL; + } + + sema_init(&dhd_registration_sem, 0); + /* power up all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + bool chip_up = FALSE; + int retry = POWERUP_MAX_RETRY; + struct semaphore dhd_chipup_sem; + + adapter = &dhd_wifi_platdata->adapters[i]; + + DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); + DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", + adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); + DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", + adapter->bus_type, adapter->bus_num, adapter->slot_num)); + + do { + sema_init(&dhd_chipup_sem, 0); + err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); + if (err) { + DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n", + __FUNCTION__, err)); + return err; + } + err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); + if (err) { + /* WL_REG_ON state unknown, Power off forcely */ + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + continue; + } else { + wifi_platform_bus_enumerate(adapter, TRUE); + err = 0; + } + + if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { + dhd_bus_unreg_sdio_notify(); + chip_up = TRUE; + break; + } + + DHD_ERROR(("failed to power up %s, %d retry left\n", adapter->name, retry)); + dhd_bus_unreg_sdio_notify(); + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + wifi_platform_bus_enumerate(adapter, FALSE); + } while (retry--); + + if (!chip_up) { + DHD_ERROR(("failed to power up %s, max retry reached**\n", adapter->name)); + return -ENODEV; + } + + } + + err = dhd_bus_register(); + + if (err) { + DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); + goto fail; + } + + + /* + * Wait till MMC sdio_register_driver callback called and made driver attach. + * It's needed to make sync up exit from dhd insmod and + * Kernel MMC sdio device callback registration + */ + err = down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); + if (err) { + DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__)); + dhd_bus_unregister(); + goto fail; + } + + return err; + +fail: + /* power down all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + adapter = &dhd_wifi_platdata->adapters[i]; + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + wifi_platform_bus_enumerate(adapter, FALSE); + } +#else + + /* x86 bring-up PC needs no power-up operations */ + err = dhd_bus_register(); + +#endif + + return err; +} +#else /* BCMSDIO */ +static int dhd_wifi_platform_load_sdio(void) +{ + return 0; +} +#endif /* BCMSDIO */ + +static int dhd_wifi_platform_load_usb(void) +{ + return 0; +} + +static int dhd_wifi_platform_load() +{ + int err = 0; + + wl_android_init(); + + if ((err = dhd_wifi_platform_load_usb())) + goto end; + else if ((err = dhd_wifi_platform_load_sdio())) + goto end; + else + err = dhd_wifi_platform_load_pcie(); + +end: + if (err) + wl_android_exit(); + else + wl_android_post_init(); + + return err; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_sched.c new file mode 100644 index 000000000000..753cb64236d6 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_sched.c @@ -0,0 +1,48 @@ +/* + * Expose some of the kernel scheduler routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux_sched.c 457570 2014-02-23 13:54:46Z $ + */ +#include +#include +#include +#include +#include + +int setScheduler(struct task_struct *p, int policy, struct sched_param *param) +{ + int rc = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + rc = sched_setscheduler(p, policy, param); +#endif /* LinuxVer */ + return rc; +} + +int get_scheduler_policy(struct task_struct *p) +{ + int rc = SCHED_NORMAL; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + rc = p->policy; +#endif /* LinuxVer */ + return rc; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.c new file mode 100644 index 000000000000..8b86bc6122c8 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.c @@ -0,0 +1,317 @@ +/* + * Broadcom Dongle Host Driver (DHD), Generic work queue framework + * Generic interface to handle dhd deferred work events + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux_wq.c 449578 2014-01-17 13:53:20Z $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct dhd_deferred_event_t { + u8 event; /* holds the event */ + void *event_data; /* Holds event specific data */ + event_handler_t event_handler; +}; +#define DEFRD_EVT_SIZE sizeof(struct dhd_deferred_event_t) + +struct dhd_deferred_wq { + struct work_struct deferred_work; /* should be the first member */ + + /* + * work events may occur simultaneously. + * Can hold upto 64 low priority events and 4 high priority events + */ +#define DHD_PRIO_WORK_FIFO_SIZE (4 * sizeof(struct dhd_deferred_event_t)) +#define DHD_WORK_FIFO_SIZE (64 * sizeof(struct dhd_deferred_event_t)) + struct kfifo *prio_fifo; + struct kfifo *work_fifo; + u8 *prio_fifo_buf; + u8 *work_fifo_buf; + spinlock_t work_lock; + void *dhd_info; /* review: does it require */ +}; + +static inline struct kfifo* +dhd_kfifo_init(u8 *buf, int size, spinlock_t *lock) +{ + struct kfifo *fifo; + gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) + fifo = kfifo_init(buf, size, flags, lock); +#else + fifo = (struct kfifo *)kzalloc(sizeof(struct kfifo), flags); + if (!fifo) { + return NULL; + } + kfifo_init(fifo, buf, size); +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ + return fifo; +} + +static inline void +dhd_kfifo_free(struct kfifo *fifo) +{ + kfifo_free(fifo); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) + /* FC11 releases the fifo memory */ + kfree(fifo); +#endif +} + +/* deferred work functions */ +static void dhd_deferred_work_handler(struct work_struct *data); + +void* +dhd_deferred_work_init(void *dhd_info) +{ + struct dhd_deferred_wq *work = NULL; + u8* buf; + unsigned long fifo_size = 0; + gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC; + + if (!dhd_info) { + DHD_ERROR(("%s: dhd info not initialized\n", __FUNCTION__)); + goto return_null; + } + + work = (struct dhd_deferred_wq *)kzalloc(sizeof(struct dhd_deferred_wq), + flags); + + if (!work) { + DHD_ERROR(("%s: work queue creation failed \n", __FUNCTION__)); + goto return_null; + } + + INIT_WORK((struct work_struct *)work, dhd_deferred_work_handler); + + /* initialize event fifo */ + spin_lock_init(&work->work_lock); + + /* allocate buffer to hold prio events */ + fifo_size = DHD_PRIO_WORK_FIFO_SIZE; + fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); + buf = (u8*)kzalloc(fifo_size, flags); + if (!buf) { + DHD_ERROR(("%s: prio work fifo allocation failed \n", __FUNCTION__)); + goto return_null; + } + + /* Initialize prio event fifo */ + work->prio_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); + if (!work->prio_fifo) { + kfree(buf); + goto return_null; + } + + /* allocate buffer to hold work events */ + fifo_size = DHD_WORK_FIFO_SIZE; + fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); + buf = (u8*)kzalloc(fifo_size, flags); + if (!buf) { + DHD_ERROR(("%s: work fifo allocation failed \n", __FUNCTION__)); + goto return_null; + } + + /* Initialize event fifo */ + work->work_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); + if (!work->work_fifo) { + kfree(buf); + goto return_null; + } + + work->dhd_info = dhd_info; + DHD_ERROR(("%s: work queue initialized \n", __FUNCTION__)); + return work; + +return_null: + + if (work) + dhd_deferred_work_deinit(work); + + return NULL; +} + +void +dhd_deferred_work_deinit(void *work) +{ + struct dhd_deferred_wq *deferred_work = work; + + + if (!deferred_work) { + DHD_ERROR(("%s: deferred work has been freed alread \n", __FUNCTION__)); + return; + } + + /* cancel the deferred work handling */ + cancel_work_sync((struct work_struct *)deferred_work); + + /* + * free work event fifo. + * kfifo_free frees locally allocated fifo buffer + */ + if (deferred_work->prio_fifo) + dhd_kfifo_free(deferred_work->prio_fifo); + + if (deferred_work->work_fifo) + dhd_kfifo_free(deferred_work->work_fifo); + + kfree(deferred_work); +} + +/* + * Prepares event to be queued + * Schedules the event + */ +int +dhd_deferred_schedule_work(void *workq, void *event_data, u8 event, + event_handler_t event_handler, u8 priority) +{ + struct dhd_deferred_wq *deferred_wq = (struct dhd_deferred_wq *) workq; + struct dhd_deferred_event_t deferred_event; + int status; + + if (!deferred_wq) { + DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); + ASSERT(0); + return DHD_WQ_STS_UNINITIALIZED; + } + + if (!event || (event >= DHD_MAX_WQ_EVENTS)) { + DHD_ERROR(("%s: Unknown event \n", __FUNCTION__)); + return DHD_WQ_STS_UNKNOWN_EVENT; + } + + /* + * default element size is 1, which can be changed + * using kfifo_esize(). Older kernel(FC11) doesn't support + * changing element size. For compatibility changing + * element size is not prefered + */ + ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); + ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); + + deferred_event.event = event; + deferred_event.event_data = event_data; + deferred_event.event_handler = event_handler; + + if (priority == DHD_WORK_PRIORITY_HIGH) { + status = kfifo_in_spinlocked(deferred_wq->prio_fifo, &deferred_event, + DEFRD_EVT_SIZE, &deferred_wq->work_lock); + } else { + status = kfifo_in_spinlocked(deferred_wq->work_fifo, &deferred_event, + DEFRD_EVT_SIZE, &deferred_wq->work_lock); + } + + if (!status) { + return DHD_WQ_STS_SCHED_FAILED; + } + schedule_work((struct work_struct *)deferred_wq); + return DHD_WQ_STS_OK; +} + +static int +dhd_get_scheduled_work(struct dhd_deferred_wq *deferred_wq, struct dhd_deferred_event_t *event) +{ + int status = 0; + + if (!deferred_wq) { + DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); + return DHD_WQ_STS_UNINITIALIZED; + } + + /* + * default element size is 1 byte, which can be changed + * using kfifo_esize(). Older kernel(FC11) doesn't support + * changing element size. For compatibility changing + * element size is not prefered + */ + ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); + ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); + + /* first read priorit event fifo */ + status = kfifo_out_spinlocked(deferred_wq->prio_fifo, event, + DEFRD_EVT_SIZE, &deferred_wq->work_lock); + + if (!status) { + /* priority fifo is empty. Now read low prio work fifo */ + status = kfifo_out_spinlocked(deferred_wq->work_fifo, event, + DEFRD_EVT_SIZE, &deferred_wq->work_lock); + } + + return status; +} + +/* + * Called when work is scheduled + */ +static void +dhd_deferred_work_handler(struct work_struct *work) +{ + struct dhd_deferred_wq *deferred_work = (struct dhd_deferred_wq *)work; + struct dhd_deferred_event_t work_event; + int status; + + if (!deferred_work) { + DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); + return; + } + + do { + status = dhd_get_scheduled_work(deferred_work, &work_event); + DHD_TRACE(("%s: event to handle %d \n", __FUNCTION__, status)); + if (!status) { + DHD_TRACE(("%s: No event to handle %d \n", __FUNCTION__, status)); + break; + } + + if (work_event.event > DHD_MAX_WQ_EVENTS) { + DHD_TRACE(("%s: Unknown event %d \n", __FUNCTION__, work_event.event)); + break; + } + + if (work_event.event_handler) { + work_event.event_handler(deferred_work->dhd_info, + work_event.event_data, work_event.event); + } else { + DHD_ERROR(("%s: event not defined %d\n", __FUNCTION__, work_event.event)); + } + } while (1); + return; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.h new file mode 100644 index 000000000000..7e06ac8cea92 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.h @@ -0,0 +1,65 @@ +/* + * Broadcom Dongle Host Driver (DHD), Generic work queue framework + * Generic interface to handle dhd deferred work events + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux_wq.h 513049 2014-11-05 09:36:42Z $ + */ +#ifndef _dhd_linux_wq_h_ +#define _dhd_linux_wq_h_ +/* + * Work event definitions + */ +enum _wq_event { + DHD_WQ_WORK_IF_ADD = 1, + DHD_WQ_WORK_IF_DEL, + DHD_WQ_WORK_SET_MAC, + DHD_WQ_WORK_SET_MCAST_LIST, + DHD_WQ_WORK_IPV6_NDO, + DHD_WQ_WORK_HANG_MSG, + DHD_WQ_WORK_SOC_RAM_DUMP, + + DHD_MAX_WQ_EVENTS +}; + +/* + * Work event priority + */ +#define DHD_WORK_PRIORITY_LOW 0 +#define DHD_WORK_PRIORITY_HIGH 1 + +/* + * Error definitions + */ +#define DHD_WQ_STS_OK 0 +#define DHD_WQ_STS_FAILED -1 /* General failure */ +#define DHD_WQ_STS_UNINITIALIZED -2 +#define DHD_WQ_STS_SCHED_FAILED -3 +#define DHD_WQ_STS_UNKNOWN_EVENT -4 + +typedef void (*event_handler_t)(void *handle, void *event_data, u8 event); + +void *dhd_deferred_work_init(void *dhd); +void dhd_deferred_work_deinit(void *workq); +int dhd_deferred_schedule_work(void *workq, void *event_data, u8 event, + event_handler_t evt_handler, u8 priority); +#endif /* _dhd_linux_wq_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_msgbuf.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_msgbuf.c new file mode 100644 index 000000000000..2998dd4c4d6e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_msgbuf.c @@ -0,0 +1,5046 @@ +/* + * Header file describing the internal (inter-module) DHD interfaces. + * + * Provides type definitions and function prototypes used to link the + * DHD OS, bus, and protocol modules. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_msgbuf.c 687068 2017-02-27 11:13:31Z $ + */ +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +#include + +#include +#include +#include +#include + +/* + * PCIE D2H DMA Complete Sync Modes + * + * Firmware may interrupt the host, prior to the D2H Mem2Mem DMA completes into + * Host system memory. A WAR using one of 3 approaches is needed: + * 1. Dongle places ia modulo-253 seqnum in last word of each D2H message + * 2. XOR Checksum, with epoch# in each work item. Dongle builds an XOR checksum + * writes in the last word of each work item. Each work item has a seqnum + * number = sequence num % 253. + * 3. Read Barrier: Dongle does a host memory read access prior to posting an + * interrupt. + * Host does not participate with option #3, other than reserving a host system + * memory location for the dongle to read. + */ +#define PCIE_D2H_SYNC +#define PCIE_D2H_SYNC_WAIT_TRIES (512UL) +#define PCIE_D2H_SYNC_NUM_OF_STEPS (3UL) +#define PCIE_D2H_SYNC_DELAY (50UL) /* in terms of usecs */ + +#if !defined(CONFIG_ARCH_MSM8994) +#define PCIE_D2H_SYNC_BZERO /* bzero a message before updating the RD offset */ +#endif + +#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ +#define IOCTL_HDR_LEN 12 + +#define DEFAULT_RX_BUFFERS_TO_POST 256 +#define RXBUFPOST_THRESHOLD 32 +#define RX_BUF_BURST 16 + +#define DHD_STOP_QUEUE_THRESHOLD 200 +#define DHD_START_QUEUE_THRESHOLD 100 + +#define MODX(x, n) ((x) & ((n) -1)) +#define align(x, n) (MODX(x, n) ? ((x) - MODX(x, n) + (n)) : ((x) - MODX(x, n))) +#define RX_DMA_OFFSET 8 +#define IOCT_RETBUF_SIZE (RX_DMA_OFFSET + WLC_IOCTL_MAXLEN) + +/* flags for ioctl pending status */ +#define MSGBUF_IOCTL_ACK_PENDING (1<<0) +#define MSGBUF_IOCTL_RESP_PENDING (1<<1) + +#define DMA_D2H_SCRATCH_BUF_LEN 8 +#define DMA_ALIGN_LEN 4 +#define DMA_XFER_LEN_LIMIT 0x400000 + +#define DHD_FLOWRING_IOCTL_BUFPOST_PKTSZ 8192 + +#define DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D 1 +#define DHD_FLOWRING_MAX_EVENTBUF_POST 8 +#define DHD_FLOWRING_MAX_IOCTLRESPBUF_POST 8 + +#define DHD_PROT_FUNCS 22 + +typedef struct dhd_mem_map { + void *va; + dmaaddr_t pa; + void *dmah; +} dhd_mem_map_t; + +typedef struct dhd_dmaxfer { + dhd_mem_map_t srcmem; + dhd_mem_map_t destmem; + uint32 len; + uint32 srcdelay; + uint32 destdelay; +} dhd_dmaxfer_t; + +#define TXP_FLUSH_NITEMS +#define TXP_FLUSH_MAX_ITEMS_FLUSH_CNT 48 + +typedef struct msgbuf_ring { + bool inited; + uint16 idx; + uchar name[24]; + dhd_mem_map_t ring_base; +#ifdef TXP_FLUSH_NITEMS + void* start_addr; + uint16 pend_items_count; +#endif /* TXP_FLUSH_NITEMS */ + ring_mem_t *ringmem; + ring_state_t *ringstate; +#if defined(PCIE_D2H_SYNC) + uint32 seqnum; +#endif /* PCIE_D2H_SYNC */ +} msgbuf_ring_t; + +#if defined(PCIE_D2H_SYNC) +/* Custom callback attached based upon D2H DMA Sync mode used in dongle. */ +typedef uint8 (* d2h_sync_cb_t)(dhd_pub_t *dhd, msgbuf_ring_t *ring, + volatile cmn_msg_hdr_t *msg, int msglen); +#endif /* PCIE_D2H_SYNC */ + +typedef struct dhd_prot { + osl_t *osh; /* OSL handle */ + uint32 reqid; + uint32 lastcmd; + uint32 pending; + uint16 rxbufpost; + uint16 max_rxbufpost; + uint16 max_eventbufpost; + uint16 max_ioctlrespbufpost; + uint16 cur_event_bufs_posted; + uint16 cur_ioctlresp_bufs_posted; + uint16 active_tx_count; + uint16 max_tx_count; + uint16 txp_threshold; + /* Ring info */ + msgbuf_ring_t *h2dring_txp_subn; + msgbuf_ring_t *h2dring_rxp_subn; + msgbuf_ring_t *h2dring_ctrl_subn; /* Cbuf handle for H2D ctrl ring */ + msgbuf_ring_t *d2hring_tx_cpln; + msgbuf_ring_t *d2hring_rx_cpln; + msgbuf_ring_t *d2hring_ctrl_cpln; /* Cbuf handle for D2H ctrl ring */ + uint32 rx_dataoffset; + dhd_mem_map_t retbuf; + dhd_mem_map_t ioctbuf; /* For holding ioct request buf */ + dhd_mb_ring_t mb_ring_fn; + + uint32 d2h_dma_scratch_buf_len; /* For holding ioct request buf */ + dhd_mem_map_t d2h_dma_scratch_buf; /* For holding ioct request buf */ + + uint32 h2d_dma_writeindx_buf_len; /* For holding dma ringupd buf - submission write */ + dhd_mem_map_t h2d_dma_writeindx_buf; /* For holding dma ringupd buf - submission write */ + + uint32 h2d_dma_readindx_buf_len; /* For holding dma ringupd buf - submission read */ + dhd_mem_map_t h2d_dma_readindx_buf; /* For holding dma ringupd buf - submission read */ + + uint32 d2h_dma_writeindx_buf_len; /* For holding dma ringupd buf - completion write */ + dhd_mem_map_t d2h_dma_writeindx_buf; /* For holding dma ringupd buf - completion write */ + + uint32 d2h_dma_readindx_buf_len; /* For holding dma ringupd buf - completion read */ + dhd_mem_map_t d2h_dma_readindx_buf; /* For holding dma ringupd buf - completion read */ + +#if defined(PCIE_D2H_SYNC) + d2h_sync_cb_t d2h_sync_cb; /* Sync on D2H DMA done: SEQNUM or XORCSUM */ + ulong d2h_sync_wait_max; /* max number of wait loops to receive one msg */ + ulong d2h_sync_wait_tot; /* total wait loops */ +#endif /* PCIE_D2H_SYNC */ + dhd_dmaxfer_t dmaxfer; + bool dmaxfer_in_progress; + + uint16 ioctl_seq_no; + uint16 data_seq_no; + uint16 ioctl_trans_id; + void *pktid_map_handle; + uint16 rx_metadata_offset; + uint16 tx_metadata_offset; + uint16 rx_cpln_early_upd_idx; + struct mutex ioctl_mutex; /* Make IOCTL singleton in Prot Layer */ +} dhd_prot_t; + +static int dhdmsgbuf_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, + void *buf, uint len, uint8 action); +static int dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, + void *buf, uint len, uint8 action); +static int dhdmsgbuf_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len, void* buf, void* retbuf); + +static int dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd); +static int dhd_prot_rxbufpost(dhd_pub_t *dhd, uint16 count); +static void dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint16 rxcnt); +static void dhd_prot_rxcmplt_process(dhd_pub_t *dhd, void* buf, uint16 msglen); +static void dhd_prot_event_process(dhd_pub_t *dhd, void* buf, uint16 len); +static int dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len); +static int dhd_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len); + +static void dhd_prot_noop(dhd_pub_t *dhd, void * buf, uint16 msglen); +static void dhd_prot_txstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen); +static void dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void * buf, uint16 msglen); +static void dhd_prot_ioctack_process(dhd_pub_t *dhd, void * buf, uint16 msglen); +static void dhd_prot_ringstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen); +static void dhd_prot_genstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen); +static void* dhd_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, + uint16 msglen, uint16 *alloced); +static int dhd_fillup_ioct_reqst_ptrbased(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, + int ifidx); +#ifdef DHD_FW_COREDUMP +extern int dhdpcie_mem_dump(dhd_bus_t *bus); +#endif /* DHD_FW_COREDUMP */ +static INLINE void dhd_prot_packet_free(dhd_pub_t *dhd, uint32 pktid, uint8 buf_type); +static INLINE void *dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid, uint8 buf_type); +static void dmaxfer_free_dmaaddr(dhd_pub_t *dhd, dhd_dmaxfer_t *dma); +static int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, uint srcdelay, + uint destdelay, dhd_dmaxfer_t *dma); +static void dhdmsgbuf_dmaxfer_compare(dhd_pub_t *dhd, void *buf, uint16 msglen); +static void dhd_prot_process_flow_ring_create_response(dhd_pub_t *dhd, void* buf, uint16 msglen); +static void dhd_prot_process_flow_ring_delete_response(dhd_pub_t *dhd, void* buf, uint16 msglen); +static void dhd_prot_process_flow_ring_flush_response(dhd_pub_t *dhd, void* buf, uint16 msglen); + + + + +#ifdef DHD_RX_CHAINING +#define PKT_CTF_CHAINABLE(dhd, ifidx, evh, prio, h_sa, h_da, h_prio) \ + (!ETHER_ISNULLDEST(((struct ether_header *)(evh))->ether_dhost) && \ + !ETHER_ISMULTI(((struct ether_header *)(evh))->ether_dhost) && \ + !eacmp((h_da), ((struct ether_header *)(evh))->ether_dhost) && \ + !eacmp((h_sa), ((struct ether_header *)(evh))->ether_shost) && \ + ((h_prio) == (prio)) && (dhd_ctf_hotbrc_check((dhd), (evh), (ifidx))) && \ + ((((struct ether_header *)(evh))->ether_type == HTON16(ETHER_TYPE_IP)) || \ + (((struct ether_header *)(evh))->ether_type == HTON16(ETHER_TYPE_IPV6)))) + +static INLINE void BCMFASTPATH dhd_rxchain_reset(rxchain_info_t *rxchain); +static void BCMFASTPATH dhd_rxchain_frame(dhd_pub_t *dhd, void *pkt, uint ifidx); +static void BCMFASTPATH dhd_rxchain_commit(dhd_pub_t *dhd); + +#define DHD_PKT_CTF_MAX_CHAIN_LEN 64 +#endif /* DHD_RX_CHAINING */ + +static uint16 dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, bool event_buf, uint32 max_to_post); +static int dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd_pub_t *pub); +static int dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *pub); + +static void dhd_prot_ring_detach(dhd_pub_t *dhd, msgbuf_ring_t * ring); +static void dhd_ring_init(dhd_pub_t *dhd, msgbuf_ring_t *ring); +static msgbuf_ring_t* prot_ring_attach(dhd_prot_t * prot, char* name, uint16 max_item, + uint16 len_item, uint16 ringid); +static void* prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced); +static void dhd_set_dmaed_index(dhd_pub_t *dhd, uint8 type, uint16 ringid, uint16 new_index); +static uint16 dhd_get_dmaed_index(dhd_pub_t *dhd, uint8 type, uint16 ringid); +static void prot_ring_write_complete(dhd_pub_t *dhd, msgbuf_ring_t * ring, void* p, uint16 len); +static void prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring); +static uint8* prot_get_src_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint16 *available_len); +static void prot_store_rxcpln_read_idx(dhd_pub_t *dhd, msgbuf_ring_t *ring); +static void prot_early_upd_rxcpln_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring); + +typedef void (*dhd_msgbuf_func_t)(dhd_pub_t *dhd, void * buf, uint16 msglen); +static dhd_msgbuf_func_t table_lookup[DHD_PROT_FUNCS] = { + dhd_prot_noop, /* 0 is invalid message type */ + dhd_prot_genstatus_process, /* MSG_TYPE_GEN_STATUS */ + dhd_prot_ringstatus_process, /* MSG_TYPE_RING_STATUS */ + NULL, + dhd_prot_process_flow_ring_create_response, /* MSG_TYPE_FLOW_RING_CREATE_CMPLT */ + NULL, + dhd_prot_process_flow_ring_delete_response, /* MSG_TYPE_FLOW_RING_DELETE_CMPLT */ + NULL, + dhd_prot_process_flow_ring_flush_response, /* MSG_TYPE_FLOW_RING_FLUSH_CMPLT */ + NULL, + dhd_prot_ioctack_process, /* MSG_TYPE_IOCTLPTR_REQ_ACK */ + NULL, + dhd_prot_ioctcmplt_process, /* MSG_TYPE_IOCTL_CMPLT */ + NULL, + dhd_prot_event_process, /* MSG_TYPE_WL_EVENT */ + NULL, + dhd_prot_txstatus_process, /* MSG_TYPE_TX_STATUS */ + NULL, + dhd_prot_rxcmplt_process, /* MSG_TYPE_RX_CMPLT */ + NULL, + dhdmsgbuf_dmaxfer_compare, /* MSG_TYPE_LPBK_DMAXFER_CMPLT */ + NULL, +}; + + +#if defined(PCIE_D2H_SYNC) + +/* + * D2H DMA to completion callback handlers. Based on the mode advertised by the + * dongle through the PCIE shared region, the appropriate callback will be + * registered in the proto layer to be invoked prior to precessing any message + * from a D2H DMA ring. If the dongle uses a read barrier or another mode that + * does not require host participation, then a noop callback handler will be + * bound that simply returns the msgtype. + */ +static void dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, msgbuf_ring_t *ring, + uint32 tries, uchar *msg, int msglen); +static uint8 dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring, + volatile cmn_msg_hdr_t *msg, int msglen); +static uint8 dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring, + volatile cmn_msg_hdr_t *msg, int msglen); +static uint8 dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring, + volatile cmn_msg_hdr_t *msg, int msglen); +static void dhd_prot_d2h_sync_init(dhd_pub_t *dhd, dhd_prot_t * prot); + +/* Debug print a livelock avert by dropping a D2H message */ +static void +dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 tries, + uchar *msg, int msglen) +{ + uint32 seqnum = ring->seqnum; + DHD_ERROR(("LIVELOCK DHD<%p> name<%s> seqnum<%u:%u> tries<%u> max<%lu> tot<%lu>" + "msg<%p>\n", + dhd, ring->name, seqnum, seqnum% D2H_EPOCH_MODULO, tries, + dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot, + msg)); + prhex("D2H MsgBuf Failure", (uchar *)msg, msglen); + +#if defined(SUPPORT_LINKDOWN_RECOVERY) && defined(CONFIG_ARCH_MSM) + dhd->bus->islinkdown = TRUE; + dhd_os_check_hang(dhd, 0, -ETIMEDOUT); +#endif /* SUPPORT_LINKDOWN_RECOVERY && CONFIG_ARCH_MSM */ + +} + +/* Sync on a D2H DMA to complete using SEQNUM mode */ +static uint8 BCMFASTPATH +dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring, + volatile cmn_msg_hdr_t *msg, int msglen) +{ + uint32 tries; + uint32 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO; + int num_words = msglen / sizeof(uint32); /* num of 32bit words */ + volatile uint32 *marker = (uint32 *)msg + (num_words - 1); /* last word */ + dhd_prot_t *prot = dhd->prot; + uint32 step = 0; + uint32 delay = PCIE_D2H_SYNC_DELAY; + uint32 total_tries = 0; + + ASSERT(msglen == RING_LEN_ITEMS(ring)); + + BCM_REFERENCE(delay); + + /* + * For retries we have to make some sort of stepper algorithm. + * We see that every time when the Dongle comes out of the D3 + * Cold state, the first D2H mem2mem DMA takes more time to + * complete, leading to livelock issues. + * + * Case 1 - Apart from Host CPU some other bus master is + * accessing the DDR port, probably page close to the ring + * so, PCIE does not get a change to update the memory. + * Solution - Increase the number of tries. + * + * Case 2 - The 50usec delay given by the Host CPU is not + * sufficient for the PCIe RC to start its work. + * In this case the breathing time of 50usec given by + * the Host CPU is not sufficient. + * Solution: Increase the delay in a stepper fashion. + * This is done to ensure that there are no + * unwanted extra delay introdcued in normal conditions. + */ + for (step = 1; step <= PCIE_D2H_SYNC_NUM_OF_STEPS; step++) { + for (tries = 1; tries <= PCIE_D2H_SYNC_WAIT_TRIES; tries++) { + uint32 msg_seqnum = *marker; + if (ltoh32(msg_seqnum) == ring_seqnum) { /* dma upto last word done */ + ring->seqnum++; /* next expected sequence number */ + goto dma_completed; + } + + total_tries = ((step-1) * PCIE_D2H_SYNC_WAIT_TRIES) + tries; + + if (total_tries > prot->d2h_sync_wait_max) + prot->d2h_sync_wait_max = total_tries; + + OSL_CACHE_INV(msg, msglen); /* invalidate and try again */ + OSL_CPU_RELAX(); /* CPU relax for msg_seqnum value to update */ +#if defined(CONFIG_ARCH_MSM8994) + /* For ARM there is no pause in cpu_relax, so add extra delay */ + OSL_DELAY(delay * step); +#endif /* defined(CONFIG_ARCH_MSM8994) */ + } /* for PCIE_D2H_SYNC_WAIT_TRIES */ + } /* for number of steps */ + + dhd_prot_d2h_sync_livelock(dhd, ring, total_tries, (uchar *)msg, msglen); + + ring->seqnum++; /* skip this message ... leak of a pktid */ + return 0; /* invalid msgtype 0 -> noop callback */ + +dma_completed: + + prot->d2h_sync_wait_tot += total_tries; + return msg->msg_type; +} + +/* Sync on a D2H DMA to complete using XORCSUM mode */ +static uint8 BCMFASTPATH +dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring, + volatile cmn_msg_hdr_t *msg, int msglen) +{ + uint32 tries; + uint32 prot_checksum = 0; /* computed checksum */ + int num_words = msglen / sizeof(uint32); /* num of 32bit words */ + uint8 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO; + dhd_prot_t *prot = dhd->prot; + uint32 step = 0; + uint32 delay = PCIE_D2H_SYNC_DELAY; + uint32 total_tries = 0; + + ASSERT(msglen == RING_LEN_ITEMS(ring)); + + BCM_REFERENCE(delay); + + /* + * For retries we have to make some sort of stepper algorithm. + * We see that every time when the Dongle comes out of the D3 + * Cold state, the first D2H mem2mem DMA takes more time to + * complete, leading to livelock issues. + * + * Case 1 - Apart from Host CPU some other bus master is + * accessing the DDR port, probably page close to the ring + * so, PCIE does not get a change to update the memory. + * Solution - Increase the number of tries. + * + * Case 2 - The 50usec delay given by the Host CPU is not + * sufficient for the PCIe RC to start its work. + * In this case the breathing time of 50usec given by + * the Host CPU is not sufficient. + * Solution: Increase the delay in a stepper fashion. + * This is done to ensure that there are no + * unwanted extra delay introdcued in normal conditions. + */ + for (step = 1; step <= PCIE_D2H_SYNC_NUM_OF_STEPS; step++) { + for (tries = 1; tries <= PCIE_D2H_SYNC_WAIT_TRIES; tries++) { + prot_checksum = bcm_compute_xor32((volatile uint32 *)msg, num_words); + if (prot_checksum == 0U) { /* checksum is OK */ + if (msg->epoch == ring_seqnum) { + ring->seqnum++; /* next expected sequence number */ + goto dma_completed; + } + } + + total_tries = ((step-1) * PCIE_D2H_SYNC_WAIT_TRIES) + tries; + + if (total_tries > prot->d2h_sync_wait_max) + prot->d2h_sync_wait_max = total_tries; + + OSL_CACHE_INV(msg, msglen); /* invalidate and try again */ + OSL_CPU_RELAX(); /* CPU relax for msg_seqnum value to update */ +#if defined(CONFIG_ARCH_MSM8994) + /* For ARM there is no pause in cpu_relax, so add extra delay */ + OSL_DELAY(delay * step); +#endif /* defined(CONFIG_ARCH_MSM8994) */ + } /* for PCIE_D2H_SYNC_WAIT_TRIES */ + } /* for number of steps */ + + dhd_prot_d2h_sync_livelock(dhd, ring, total_tries, (uchar *)msg, msglen); + + ring->seqnum++; /* skip this message ... leak of a pktid */ + return 0; /* invalid msgtype 0 -> noop callback */ + +dma_completed: + + prot->d2h_sync_wait_tot += total_tries; + return msg->msg_type; +} + +/* Do not sync on a D2H DMA */ +static uint8 BCMFASTPATH +dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring, + volatile cmn_msg_hdr_t *msg, int msglen) +{ + return msg->msg_type; +} + +/* Initialize the D2H DMA Sync mode, per D2H ring seqnum and dhd stats */ +static void +dhd_prot_d2h_sync_init(dhd_pub_t *dhd, dhd_prot_t * prot) +{ + prot->d2h_sync_wait_max = 0UL; + prot->d2h_sync_wait_tot = 0UL; + + prot->d2hring_tx_cpln->seqnum = D2H_EPOCH_INIT_VAL; + prot->d2hring_rx_cpln->seqnum = D2H_EPOCH_INIT_VAL; + prot->d2hring_ctrl_cpln->seqnum = D2H_EPOCH_INIT_VAL; + + if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM) + prot->d2h_sync_cb = dhd_prot_d2h_sync_seqnum; + else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM) + prot->d2h_sync_cb = dhd_prot_d2h_sync_xorcsum; + else + prot->d2h_sync_cb = dhd_prot_d2h_sync_none; +} + +#endif /* PCIE_D2H_SYNC */ + +/* + * +---------------------------------------------------------------------------+ + * PktId Map: Provides a native packet pointer to unique 32bit PktId mapping. + * The packet id map, also includes storage for some packet parameters that + * may be saved. A native packet pointer along with the parameters may be saved + * and a unique 32bit pkt id will be returned. Later, the saved packet pointer + * and the metadata may be retrieved using the previously allocated packet id. + * +---------------------------------------------------------------------------+ + */ + +/* + * PktId (Locker) #0 is never allocated and is considered invalid. + * + * On request for a pktid, a value DHD_PKTID_INVALID must be treated as a + * depleted pktid pool and must not be used by the caller. + * + * Likewise, a caller must never free a pktid of value DHD_PKTID_INVALID. + */ +#define DHD_PKTID_INVALID (0U) +#define DHD_IOCTL_REQ_PKTID 0xFFFE + + +#define MAX_PKTID_ITEMS (8192) /* Maximum number of pktids supported */ + +/* + * DHD_PKTID_AUDIT_ENABLED: Audit of PktIds in DHD for duplicate alloc and frees + * + * DHD_PKTID_AUDIT_MAP: Audit the LIFO or FIFO PktIdMap allocator + * DHD_PKTID_AUDIT_RING: Audit the pktid during producer/consumer ring operation + * + * CAUTION: When DHD_PKTID_AUDIT_ENABLED is defined, + * either DHD_PKTID_AUDIT_MAP or DHD_PKTID_AUDIT_RING may be selected. + */ + +/* Disable Host side Pktid Audit, enabling this makes the mem corruption + * problem disappear + */ +/* #define DHD_PKTID_AUDIT_ENABLED */ + +#if defined(DHD_PKTID_AUDIT_ENABLED) + +/* Audit the pktidmap allocator */ +/* #define DHD_PKTID_AUDIT_MAP */ + +/* Audit the pktid during production/consumption of workitems */ +#define DHD_PKTID_AUDIT_RING + +#if defined(DHD_PKTID_AUDIT_MAP) && defined(DHD_PKTID_AUDIT_RING) +#error "May only enabled audit of MAP or RING, at a time." +#endif /* DHD_PKTID_AUDIT_MAP && DHD_PKTID_AUDIT_RING */ + +#define DHD_DUPLICATE_ALLOC 1 +#define DHD_DUPLICATE_FREE 2 +#define DHD_TEST_IS_ALLOC 3 +#define DHD_TEST_IS_FREE 4 + +#define USE_DHD_PKTID_AUDIT_LOCK 1 + +#ifdef USE_DHD_PKTID_AUDIT_LOCK +#define DHD_PKTID_AUDIT_LOCK_INIT(osh) dhd_os_spin_lock_init(osh) +#define DHD_PKTID_AUDIT_LOCK_DEINIT(osh, lock) dhd_os_spin_lock_deinit(osh, lock) +#define DHD_PKTID_AUDIT_LOCK(lock) dhd_os_spin_lock(lock) +#define DHD_PKTID_AUDIT_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, flags) + +#else + +#define DHD_PKTID_AUDIT_LOCK_INIT(osh) (void *)(1) +#define DHD_PKTID_AUDIT_LOCK_DEINIT(osh, lock) do { /* noop */ } while (0) +#define DHD_PKTID_AUDIT_LOCK(lock) 0 +#define DHD_PKTID_AUDIT_UNLOCK(lock, flags) do { /* noop */ } while (0) + +#endif /* !USE_DHD_PKTID_AUDIT_LOCK */ + +#endif /* DHD_PKTID_AUDIT_ENABLED */ + +#if defined(DHD_PKTID_AUDIT_ENABLED) +/* + * Going back to 1 from 2, we are any way using LIFO method now. + * Also note that if this is 2 then our times would 2 * 8192 + 1 + * But the bit map is only for 16K. Increasing the bitmap size for + * more than 16K failed. So doing this change to fit in into the + * bit map size. + */ +#define DHD_PKTIDMAP_FIFO 1 + +#else /* DHD_PKTID_AUDIT_ENABLED */ + +/* + * Uses a FIFO dll with Nx more pktids instead of a LIFO stack. + * If you wish to enable pktidaudit in firmware with FIFO PktId allocator, then + * the total number of PktIds managed by the pktidaudit must be multiplied by + * this DHD_PKTIDMAP_FIFO factor. + */ +#define DHD_PKTIDMAP_FIFO 4 + +#endif /* DHD_PKTID_AUDIT_ENABLED */ + +typedef void * dhd_pktid_map_handle_t; /* opaque handle to a pktid map */ + +/* Construct a packet id mapping table, returning an opaque map handle */ +static dhd_pktid_map_handle_t *dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items); + +/* Destroy a packet id mapping table, freeing all packets active in the table */ +static void dhd_pktid_map_fini(dhd_pktid_map_handle_t *map); + +/* Determine number of pktids that are available */ +static INLINE uint32 dhd_pktid_map_avail_cnt(dhd_pktid_map_handle_t *handle); + +/* Allocate a unique pktid against which a pkt and some metadata is saved */ +static INLINE uint32 dhd_pktid_map_reserve(dhd_pktid_map_handle_t *handle, + void *pkt); +static INLINE void dhd_pktid_map_save(dhd_pktid_map_handle_t *handle, void *pkt, + uint32 nkey, dmaaddr_t physaddr, uint32 len, uint8 dma, + uint8 buf_type); +static uint32 dhd_pktid_map_alloc(dhd_pktid_map_handle_t *map, void *pkt, + dmaaddr_t physaddr, uint32 len, uint8 dma, + uint8 buf_type); +/* Return an allocated pktid, retrieving previously saved pkt and metadata */ +static void *dhd_pktid_map_free(dhd_pktid_map_handle_t *map, uint32 id, + dmaaddr_t *physaddr, uint32 *len, + uint8 buf_type); + +#ifdef USE_DHD_PKTID_LOCK +#define DHD_PKTID_LOCK_INIT(osh) dhd_os_spin_lock_init(osh) +#define DHD_PKTID_LOCK_DEINIT(osh, lock) dhd_os_spin_lock_deinit(osh, lock) +#define DHD_PKTID_LOCK(lock) dhd_os_spin_lock(lock) +#define DHD_PKTID_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, flags) +#else +#define DHD_PKTID_LOCK_INIT(osh) (void *)(1) +#define DHD_PKTID_LOCK_DEINIT(osh, lock) do { \ + BCM_REFERENCE(osh); \ + BCM_REFERENCE(lock); \ + } while (0) +#define DHD_PKTID_LOCK(lock) 0 +#define DHD_PKTID_UNLOCK(lock, flags) do { \ + BCM_REFERENCE(lock); \ + BCM_REFERENCE(flags); \ + } while (0) +#endif /* !USE_DHD_PKTID_LOCK */ + +/* Packet metadata saved in packet id mapper */ + +typedef enum pkt_buf_type { + BUFF_TYPE_DATA_TX = 0, + BUFF_TYPE_DATA_RX, + BUFF_TYPE_IOCTL_RX, + BUFF_TYPE_EVENT_RX, + BUFF_TYPE_NO_CHECK +} pkt_buf_type_t; + +typedef struct dhd_pktid_item { +#if defined(DHD_PKTIDMAP_FIFO) + dll_t list_node; /* MUST BE FIRST field */ + uint32 nkey; +#endif + bool inuse; /* tag an item to be in use */ + uint8 dma; /* map direction: flush or invalidate */ + uint8 buf_type; + /* This filed is used to colour the + * buffer pointers held in the locker. + */ + uint16 len; /* length of mapped packet's buffer */ + void *pkt; /* opaque native pointer to a packet */ + dmaaddr_t physaddr; /* physical address of mapped packet's buffer */ +} dhd_pktid_item_t; + +typedef struct dhd_pktid_map { + dhd_pub_t *dhd; + uint32 items; /* total items in map */ + uint32 avail; /* total available items */ + uint32 failures; /* lockers unavailable count */ + /* Spinlock to protect dhd_pktid_map in process/tasklet context */ + void *pktid_lock; /* Used when USE_DHD_PKTID_LOCK is defined */ + +#if defined(DHD_PKTID_AUDIT_ENABLED) + void *pktid_audit_lock; + struct bcm_mwbmap *pktid_audit; /* multi word bitmap based audit */ +#endif /* DHD_PKTID_AUDIT_ENABLED */ + + /* Unique PktId Allocator: FIFO dll, or LIFO:stack of keys */ +#if defined(DHD_PKTIDMAP_FIFO) + dll_t list_free; /* allocate from head, free to tail */ + dll_t list_inuse; +#else /* ! DHD_PKTIDMAP_FIFO */ + uint32 keys[MAX_PKTID_ITEMS + 1]; /* stack of unique pkt ids */ +#endif /* ! DHD_PKTIDMAP_FIFO */ + dhd_pktid_item_t lockers[0]; /* metadata storage */ +} dhd_pktid_map_t; + +#define DHD_PKTID_ITEM_SZ (sizeof(dhd_pktid_item_t)) + +#if defined(DHD_PKTIDMAP_FIFO) +/* A 4x pool of pktids are managed with FIFO allocation. */ +#define DHD_PKIDMAP_ITEMS(items) (items * DHD_PKTIDMAP_FIFO) +#define DHD_PKTID_MAP_SZ(items) (sizeof(dhd_pktid_map_t) + \ + (DHD_PKTID_ITEM_SZ * ((DHD_PKTIDMAP_FIFO * (items)) + 1))) +#else /* ! DHD_PKTIDMAP_FIFO */ +#define DHD_PKIDMAP_ITEMS(items) (items) +#define DHD_PKTID_MAP_SZ(items) (sizeof(dhd_pktid_map_t) + \ + (DHD_PKTID_ITEM_SZ * ((items) + 1))) +#endif /* ! DHD_PKTIDMAP_FIFO */ + +#define NATIVE_TO_PKTID_INIT(dhd, items) dhd_pktid_map_init((dhd), (items)) +#define NATIVE_TO_PKTID_FINI(map) dhd_pktid_map_fini(map) +#define NATIVE_TO_PKTID_CLEAR(map) dhd_pktid_map_clear(map) + +#define NATIVE_TO_PKTID_RSV(map, pkt) dhd_pktid_map_reserve((map), (pkt)) +#define NATIVE_TO_PKTID_SAVE(map, pkt, nkey, pa, len, dma, buf_type) \ + dhd_pktid_map_save((map), (void *)(pkt), (nkey), (pa), (uint32)(len), \ + (uint8)dma, (uint8)buf_type) +#define NATIVE_TO_PKTID(map, pkt, pa, len, dma, buf_type) \ + dhd_pktid_map_alloc((map), (void *)(pkt), (pa), (uint32)(len), \ + (uint8)dma, (uint8)buf_type) +#define PKTID_TO_NATIVE(map, pktid, pa, len, buf_type) \ + dhd_pktid_map_free((map), (uint32)(pktid), \ + (dmaaddr_t *)&(pa), (uint32 *)&(len), (uint8)buf_type) + +#define PKTID_AVAIL(map) dhd_pktid_map_avail_cnt(map) + +#if defined(DHD_PKTID_AUDIT_ENABLED) + +static int dhd_pktid_audit(dhd_pktid_map_t *pktid_map, uint32 pktid, + const int test_for, const char *errmsg); + +static int +dhd_pktid_audit(dhd_pktid_map_t *pktid_map, uint32 pktid, const int test_for, + const char *errmsg) +{ +#define DHD_PKT_AUDIT_STR "ERROR: %16s Host PktId Audit: " + +#if defined(DHD_PKTIDMAP_FIFO) + const uint32 max_pktid_items = (MAX_PKTID_ITEMS * DHD_PKTIDMAP_FIFO); +#else + const uint32 max_pktid_items = (MAX_PKTID_ITEMS); +#endif /* DHD_PKTIDMAP_FIFO */ + struct bcm_mwbmap *handle; + u32 flags; + + if (pktid_map == (dhd_pktid_map_t *)NULL) { + DHD_ERROR((DHD_PKT_AUDIT_STR "Pkt id map NULL\n", errmsg)); + return BCME_OK; + } + + flags = DHD_PKTID_AUDIT_LOCK(pktid_map->pktid_audit_lock); + + handle = pktid_map->pktid_audit; + if (handle == (struct bcm_mwbmap *)NULL) { + DHD_ERROR((DHD_PKT_AUDIT_STR "Handle NULL\n", errmsg)); + DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); + return BCME_OK; + } + + if ((pktid == DHD_PKTID_INVALID) || (pktid > max_pktid_items)) { + DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> invalid\n", errmsg, pktid)); + /* lock is released in "error" */ + goto error; + } + + if (pktid == DHD_IOCTL_REQ_PKTID) { + DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); + return BCME_OK; + } + + switch (test_for) { + case DHD_DUPLICATE_ALLOC: + if (!bcm_mwbmap_isfree(handle, pktid)) { + DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> alloc duplicate\n", + errmsg, pktid)); + goto error; + } + bcm_mwbmap_force(handle, pktid); + break; + + case DHD_DUPLICATE_FREE: + if (bcm_mwbmap_isfree(handle, pktid)) { + DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> free duplicate\n", + errmsg, pktid)); + goto error; + } + bcm_mwbmap_free(handle, pktid); + break; + + case DHD_TEST_IS_ALLOC: + if (bcm_mwbmap_isfree(handle, pktid)) { + DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> is not allocated\n", + errmsg, pktid)); + goto error; + } + break; + + case DHD_TEST_IS_FREE: + if (!bcm_mwbmap_isfree(handle, pktid)) { + DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> is not free", + errmsg, pktid)); + goto error; + } + break; + + default: + goto error; + } + + DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); + return BCME_OK; + +error: + + DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); + /* May insert any trap mechanism here ! */ + ASSERT(0); + return BCME_ERROR; +} + +#define DHD_PKTID_AUDIT(map, pktid, test_for) \ + dhd_pktid_audit((dhd_pktid_map_t *)(map), (pktid), (test_for), __FUNCTION__) + +#endif /* DHD_PKTID_AUDIT_ENABLED */ + +/* + * +---------------------------------------------------------------------------+ + * Packet to Packet Id mapper using a paradigm. + * + * dhd_pktid_map manages a set of unique Packet Ids range[1..MAX_PKTID_ITEMS]. + * + * dhd_pktid_map_alloc() may be used to save some packet metadata, and a unique + * packet id is returned. This unique packet id may be used to retrieve the + * previously saved packet metadata, using dhd_pktid_map_free(). On invocation + * of dhd_pktid_map_free(), the unique packet id is essentially freed. A + * subsequent call to dhd_pktid_map_alloc() may reuse this packet id. + * + * Implementation Note: + * Convert this into a abstraction and place into bcmutils ! + * Locker abstraction should treat contents as opaque storage, and a + * callback should be registered to handle inuse lockers on destructor. + * + * +---------------------------------------------------------------------------+ + */ + +/* Allocate and initialize a mapper of num_items */ +static dhd_pktid_map_handle_t * +dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items) +{ + uint32 nkey; + dhd_pktid_map_t *map; + uint32 dhd_pktid_map_sz; + uint32 map_items; + + ASSERT((num_items >= 1) && (num_items <= MAX_PKTID_ITEMS)); + dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(num_items); + + if ((map = (dhd_pktid_map_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PKTID_MAP, + dhd_pktid_map_sz)) == NULL) { + DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", + __FUNCTION__, __LINE__, dhd_pktid_map_sz)); + goto error; + } + bzero(map, dhd_pktid_map_sz); + + /* Initialize the lock that protects this structure */ + map->pktid_lock = DHD_PKTID_LOCK_INIT(dhd->osh); + if (map->pktid_lock == NULL) { + DHD_ERROR(("%s:%d: Lock init failed \r\n", __FUNCTION__, __LINE__)); + goto error; + } + + map->dhd = dhd; + map->items = num_items; + map->avail = num_items; + + map_items = DHD_PKIDMAP_ITEMS(map->items); + +#if defined(DHD_PKTID_AUDIT_ENABLED) + /* Incarnate a hierarchical multiword bitmap for auditing pktid allocator */ + map->pktid_audit = bcm_mwbmap_init(dhd->osh, map_items + 1); + if (map->pktid_audit == (struct bcm_mwbmap *)NULL) { + DHD_ERROR(("%s:%d: pktid_audit init failed\r\n", __FUNCTION__, __LINE__)); + goto error; + } + + map->pktid_audit_lock = DHD_PKTID_AUDIT_LOCK_INIT(dhd->osh); +#endif /* DHD_PKTID_AUDIT_ENABLED */ + +#if defined(DHD_PKTIDMAP_FIFO) + + /* Initialize all dll */ + dll_init(&map->list_free); + dll_init(&map->list_inuse); + + /* Initialize and place all 4 x items in map's list_free */ + for (nkey = 0; nkey <= map_items; nkey++) { + dll_init(&map->lockers[nkey].list_node); + map->lockers[nkey].inuse = FALSE; + map->lockers[nkey].nkey = nkey; + map->lockers[nkey].pkt = NULL; /* bzero: redundant */ + map->lockers[nkey].len = 0; + /* Free at tail */ + dll_append(&map->list_free, &map->lockers[nkey].list_node); + } + + /* Reserve pktid #0, i.e. DHD_PKTID_INVALID to be inuse */ + map->lockers[DHD_PKTID_INVALID].inuse = TRUE; + dll_delete(&map->lockers[DHD_PKTID_INVALID].list_node); + dll_append(&map->list_inuse, &map->lockers[DHD_PKTID_INVALID].list_node); + +#else /* ! DHD_PKTIDMAP_FIFO */ + + map->lockers[DHD_PKTID_INVALID].inuse = TRUE; /* tag locker #0 as inuse */ + + for (nkey = 1; nkey <= map_items; nkey++) { /* locker #0 is reserved */ + map->keys[nkey] = nkey; /* populate with unique keys */ + map->lockers[nkey].inuse = FALSE; + map->lockers[nkey].pkt = NULL; /* bzero: redundant */ + map->lockers[nkey].len = 0; + } + +#endif /* ! DHD_PKTIDMAP_FIFO */ + + /* Reserve pktid #0, i.e. DHD_PKTID_INVALID to be inuse */ + map->lockers[DHD_PKTID_INVALID].inuse = TRUE; /* tag locker #0 as inuse */ + map->lockers[DHD_PKTID_INVALID].pkt = NULL; /* bzero: redundant */ + map->lockers[DHD_PKTID_INVALID].len = 0; + +#if defined(DHD_PKTID_AUDIT_ENABLED) + /* do not use dhd_pktid_audit() here, use bcm_mwbmap_force directly */ + bcm_mwbmap_force(map->pktid_audit, DHD_PKTID_INVALID); +#endif /* DHD_PKTID_AUDIT_ENABLED */ + + return (dhd_pktid_map_handle_t *)map; /* opaque handle */ + +error: + + if (map) { +#if defined(DHD_PKTID_AUDIT_ENABLED) + if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { + bcm_mwbmap_fini(dhd->osh, map->pktid_audit); /* Destruct pktid_audit */ + map->pktid_audit = (struct bcm_mwbmap *)NULL; + if (map->pktid_audit_lock) { + DHD_PKTID_AUDIT_LOCK_DEINIT(dhd->osh, map->pktid_audit_lock); + } + } +#endif /* DHD_PKTID_AUDIT_ENABLED */ + + if (map->pktid_lock) { + DHD_PKTID_LOCK_DEINIT(dhd->osh, map->pktid_lock); + } + + DHD_OS_PREFREE(map->dhd, map, dhd_pktid_map_sz); + } + + return (dhd_pktid_map_handle_t *)NULL; +} + +/* + * Retrieve all allocated keys and free all . + * Freeing implies: unmapping the buffers and freeing the native packet + * This could have been a callback registered with the pktid mapper. + */ +static void +dhd_pktid_map_fini(dhd_pktid_map_handle_t *handle) +{ + void *osh; + int nkey; + dhd_pktid_map_t *map; + uint32 dhd_pktid_map_sz; + dhd_pktid_item_t *locker; + uint32 map_items; + unsigned long flags; + + if (handle == NULL) + return; + + map = (dhd_pktid_map_t *)handle; + flags = DHD_PKTID_LOCK(map->pktid_lock); + + osh = map->dhd->osh; + dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(map->items); + + nkey = 1; /* skip reserved KEY #0, and start from 1 */ + locker = &map->lockers[nkey]; + + map_items = DHD_PKIDMAP_ITEMS(map->items); + + for (; nkey <= map_items; nkey++, locker++) { + if (locker->inuse == TRUE) { /* numbered key still in use */ + locker->inuse = FALSE; /* force open the locker */ + +#if defined(DHD_PKTID_AUDIT_ENABLED) + DHD_PKTID_AUDIT(map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */ +#endif /* DHD_PKTID_AUDIT_ENABLED */ + { + if (!PHYSADDRISZERO(locker->physaddr)) { + /* This could be a callback registered with dhd_pktid_map */ + DMA_UNMAP(osh, locker->physaddr, locker->len, + locker->dma, 0, 0); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + if (locker->buf_type == BUFF_TYPE_IOCTL_RX) { + PKTFREE_STATIC(osh, (ulong*)locker->pkt, FALSE); + } else { +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + PKTFREE(osh, (ulong*)locker->pkt, FALSE); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + } else { + DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__)); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + if (locker->buf_type == BUFF_TYPE_IOCTL_RX) { + PKTINVALIDATE_STATIC(osh, (ulong*)locker->pkt); + } else { +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + PKTFREE(osh, (ulong*)locker->pkt, FALSE); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + } + } + } +#if defined(DHD_PKTID_AUDIT_ENABLED) + else { + DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_FREE); + } +#endif /* DHD_PKTID_AUDIT_ENABLED */ + + locker->pkt = NULL; /* clear saved pkt */ + locker->len = 0; + } + +#if defined(DHD_PKTID_AUDIT_ENABLED) + if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { + bcm_mwbmap_fini(osh, map->pktid_audit); /* Destruct pktid_audit */ + map->pktid_audit = (struct bcm_mwbmap *)NULL; + if (map->pktid_audit_lock) { + DHD_PKTID_AUDIT_LOCK_DEINIT(osh, map->pktid_audit_lock); + } + } +#endif /* DHD_PKTID_AUDIT_ENABLED */ + + DHD_PKTID_UNLOCK(map->pktid_lock, flags); + DHD_PKTID_LOCK_DEINIT(map->dhd->osh, map->pktid_lock); + + DHD_OS_PREFREE(map->dhd, map, dhd_pktid_map_sz); +} + +static void +dhd_pktid_map_clear(dhd_pktid_map_handle_t *handle) +{ + void *osh; + int nkey; + dhd_pktid_map_t *map; + dhd_pktid_item_t *locker; + uint32 map_items; + unsigned long flags; + + DHD_TRACE(("%s\n", __FUNCTION__)); + + if (handle == NULL) + return; + + map = (dhd_pktid_map_t *)handle; + flags = DHD_PKTID_LOCK(map->pktid_lock); + + osh = map->dhd->osh; + map->failures = 0; + + nkey = 1; /* skip reserved KEY #0, and start from 1 */ + locker = &map->lockers[nkey]; + + map_items = DHD_PKIDMAP_ITEMS(map->items); + for (; nkey <= map_items; nkey++, locker++) { + +#if !defined(DHD_PKTIDMAP_FIFO) + map->keys[nkey] = nkey; /* populate with unique keys */ +#endif /* ! DHD_PKTIDMAP_FIFO */ + + if (locker->inuse == TRUE) { /* numbered key still in use */ + locker->inuse = FALSE; /* force open the locker */ +#if defined(DHD_PKTID_AUDIT_ENABLED) + DHD_PKTID_AUDIT(map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */ +#endif /* DHD_PKTID_AUDIT_ENABLED */ + +#if defined(DHD_PKTIDMAP_FIFO) + ASSERT(locker->nkey == nkey); + dll_delete(&locker->list_node); + dll_append(&map->list_free, &locker->list_node); +#endif /* DHD_PKTIDMAP_FIFO */ + + DHD_TRACE(("%s free id%d\n", __FUNCTION__, nkey)); + if (!PHYSADDRISZERO(locker->physaddr)) { + DMA_UNMAP(osh, locker->physaddr, locker->len, + locker->dma, 0, 0); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + if (locker->buf_type == BUFF_TYPE_IOCTL_RX) { + PKTFREE_STATIC(osh, (ulong*)locker->pkt, FALSE); + } else { +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + PKTFREE(osh, (ulong*)locker->pkt, FALSE); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + } else { + DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__)); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + if (locker->buf_type == BUFF_TYPE_IOCTL_RX) { + PKTINVALIDATE_STATIC(osh, (ulong*)locker->pkt); + } else { +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + PKTFREE(osh, (ulong*)locker->pkt, FALSE); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + } + } +#if defined(DHD_PKTID_AUDIT_ENABLED) + else { + DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_FREE); + } +#endif /* DHD_PKTID_AUDIT_ENABLED */ + + locker->pkt = NULL; /* clear saved pkt */ + locker->len = 0; + + } + map->avail = map->items; + + DHD_PKTID_UNLOCK(map->pktid_lock, flags); +} + +/* Get the pktid free count */ +static INLINE uint32 BCMFASTPATH +dhd_pktid_map_avail_cnt(dhd_pktid_map_handle_t *handle) +{ + dhd_pktid_map_t *map; + unsigned long flags; + uint32 avail; + + ASSERT(handle != NULL); + map = (dhd_pktid_map_t *)handle; + + flags = DHD_PKTID_LOCK(map->pktid_lock); + avail = map->avail; + DHD_PKTID_UNLOCK(map->pktid_lock, flags); + + return avail; +} + +/* + * Allocate locker, save pkt contents, and return the locker's numbered key. + * dhd_pktid_map_alloc() is not reentrant, and is the caller's responsibility. + * Caller must treat a returned value DHD_PKTID_INVALID as a failure case, + * implying a depleted pool of pktids. + */ +static INLINE uint32 +__dhd_pktid_map_reserve(dhd_pktid_map_handle_t *handle, void *pkt) +{ + uint32 nkey; + dhd_pktid_map_t *map; + dhd_pktid_item_t *locker; + + ASSERT(handle != NULL); + map = (dhd_pktid_map_t *)handle; + + if (map->avail <= 0) { /* no more pktids to allocate */ + map->failures++; + DHD_ERROR(("%s:%d: failed, no free keys\n", __FUNCTION__, __LINE__)); + return DHD_PKTID_INVALID; /* failed alloc request */ + } + ASSERT(map->avail <= map->items); + +#if defined(DHD_PKTIDMAP_FIFO) + + ASSERT(!dll_empty(&map->list_free)); + + /* Move list_free head item to inuse list, fetch key in head node */ + locker = (dhd_pktid_item_t *)dll_head_p(&map->list_free); + dll_delete(&locker->list_node); + nkey = locker->nkey; + dll_append(&map->list_inuse, &locker->list_node); + +#else /* ! DHD_PKTIDMAP_FIFO */ + + nkey = map->keys[map->avail]; /* fetch a free locker, pop stack */ + locker = &map->lockers[nkey]; /* save packet metadata in locker */ + +#endif /* ! DHD_PKTIDMAP_FIFO */ + + if (nkey > DHD_PKIDMAP_ITEMS(map->items)) { + DHD_ERROR(("%s:%d: invalid nkey (%d)\n", __FUNCTION__, __LINE__, nkey)); + return DHD_PKTID_INVALID; /* failed alloc request */ + } + map->avail--; + + locker->inuse = TRUE; /* reserve this locker */ + locker->pkt = pkt; /* pkt is saved, other params not yet saved. */ + locker->len = 0; + +#if defined(DHD_PKTID_AUDIT_MAP) + DHD_PKTID_AUDIT(map, nkey, DHD_DUPLICATE_ALLOC); /* Audit duplicate alloc */ +#endif /* DHD_PKTID_AUDIT_MAP */ + + ASSERT(nkey != DHD_PKTID_INVALID); + return nkey; /* return locker's numbered key */ +} + +/* Wrapper that takes the required lock when called directly */ +static INLINE uint32 +dhd_pktid_map_reserve(dhd_pktid_map_handle_t *handle, void *pkt) +{ + dhd_pktid_map_t *map; + unsigned long flags; + uint32 ret; + + ASSERT(handle != NULL); + map = (dhd_pktid_map_t *)handle; + flags = DHD_PKTID_LOCK(map->pktid_lock); + ret = __dhd_pktid_map_reserve(handle, pkt); + DHD_PKTID_UNLOCK(map->pktid_lock, flags); + + return ret; +} + +static INLINE void +__dhd_pktid_map_save(dhd_pktid_map_handle_t *handle, void *pkt, uint32 nkey, + dmaaddr_t physaddr, uint32 len, uint8 dma, uint8 buf_type) +{ + dhd_pktid_map_t *map; + dhd_pktid_item_t *locker; + + ASSERT(handle != NULL); + map = (dhd_pktid_map_t *)handle; + + ASSERT((nkey != DHD_PKTID_INVALID) && (nkey <= DHD_PKIDMAP_ITEMS(map->items))); + + locker = &map->lockers[nkey]; + ASSERT((locker->pkt == pkt) && (locker->inuse == TRUE)); + +#if defined(DHD_PKTID_AUDIT_MAP) + DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_ALLOC); /* apriori, reservation */ +#endif /* DHD_PKTID_AUDIT_MAP */ + + locker->dma = dma; /* store contents in locker */ + locker->buf_type = buf_type; + locker->physaddr = physaddr; + locker->len = (uint16)len; /* 16bit len */ +} + +/* Wrapper that takes the required lock when called directly */ +static INLINE void +dhd_pktid_map_save(dhd_pktid_map_handle_t *handle, void *pkt, uint32 nkey, + dmaaddr_t physaddr, uint32 len, uint8 dma, uint8 buf_type) +{ + dhd_pktid_map_t *map; + unsigned long flags; + + ASSERT(handle != NULL); + map = (dhd_pktid_map_t *)handle; + flags = DHD_PKTID_LOCK(map->pktid_lock); + __dhd_pktid_map_save(handle, pkt, nkey, physaddr, len, dma, buf_type); + DHD_PKTID_UNLOCK(map->pktid_lock, flags); +} + +static uint32 BCMFASTPATH +dhd_pktid_map_alloc(dhd_pktid_map_handle_t *handle, void *pkt, + dmaaddr_t physaddr, uint32 len, uint8 dma, uint8 buf_type) +{ + uint32 nkey; + unsigned long flags; + dhd_pktid_map_t *map; + + ASSERT(handle != NULL); + map = (dhd_pktid_map_t *)handle; + + flags = DHD_PKTID_LOCK(map->pktid_lock); + + nkey = __dhd_pktid_map_reserve(handle, pkt); + if (nkey != DHD_PKTID_INVALID) { + __dhd_pktid_map_save(handle, pkt, nkey, physaddr, len, + dma, buf_type); +#if defined(DHD_PKTID_AUDIT_MAP) + DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_ALLOC); /* apriori, reservation */ +#endif /* DHD_PKTID_AUDIT_MAP */ + } + + DHD_PKTID_UNLOCK(map->pktid_lock, flags); + + return nkey; +} + +/* + * Given a numbered key, return the locker contents. + * dhd_pktid_map_free() is not reentrant, and is the caller's responsibility. + * Caller may not free a pktid value DHD_PKTID_INVALID or an arbitrary pktid + * value. Only a previously allocated pktid may be freed. + */ +static void * BCMFASTPATH +dhd_pktid_map_free(dhd_pktid_map_handle_t *handle, uint32 nkey, + dmaaddr_t *physaddr, uint32 *len, uint8 buf_type) +{ + dhd_pktid_map_t *map; + dhd_pktid_item_t *locker; + void * pkt; + unsigned long flags; + + ASSERT(handle != NULL); + + map = (dhd_pktid_map_t *)handle; + flags = DHD_PKTID_LOCK(map->pktid_lock); + +#ifdef CUSTOMER_HW5 + if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { + DHD_ERROR(("%s:%d: Error! freeing out of range pktid<%u>\n", + __FUNCTION__, __LINE__, nkey)); + ASSERT((nkey != DHD_PKTID_INVALID) && (nkey <= DHD_PKIDMAP_ITEMS(map->items))); + DHD_PKTID_UNLOCK(map->pktid_lock, flags); + return NULL; + } +#endif /* CUSTOMER_HW5 */ + + locker = &map->lockers[nkey]; + +#if defined(DHD_PKTID_AUDIT_MAP) + DHD_PKTID_AUDIT(map, nkey, DHD_DUPLICATE_FREE); /* Audit duplicate FREE */ +#endif /* DHD_PKTID_AUDIT_MAP */ + + if (locker->inuse == FALSE) { /* Debug check for cloned numbered key */ + DHD_ERROR(("%s:%d: Error! freeing invalid pktid<%u>\n", + __FUNCTION__, __LINE__, nkey)); + DHD_ERROR(("%s:%d: locker->pkt=%p locker->len=%d\n", + __FUNCTION__, __LINE__, locker->pkt, locker->len)); + ASSERT(locker->inuse != FALSE); + /* dump free list */ + { + dll_t *elem_p = NULL; + dll_t *next_p = NULL; + dhd_pktid_item_t *lr; + int i = 0; + + for (elem_p = dll_head_p(&map->list_free); + !dll_end(&map->list_free, elem_p); elem_p = next_p) { + /* in case the list is broken... */ + if (i > 65535) break; + i++; + next_p = dll_next_p(elem_p); + lr = (dhd_pktid_item_t *)elem_p; + if (locker == lr) { + printf("locker is found in free list.\n"); + } + if (lr->pkt) { + printf("locker(%p) pkt(%p) is not null.\n", lr, lr->pkt); + } + } + } + dump_stack(); + DHD_PKTID_UNLOCK(map->pktid_lock, flags); + return NULL; + } + + /* Check for the colour of the buffer i.e The buffer posted for TX, + * should be freed for TX completion. Similarly the buffer posted for + * IOCTL should be freed for IOCT completion etc. + */ + if ((buf_type != BUFF_TYPE_NO_CHECK) && (locker->buf_type != buf_type)) { + DHD_ERROR(("%s:%d: Error! Invalid Buffer Free for pktid<%u> \n", + __FUNCTION__, __LINE__, nkey)); + ASSERT(locker->buf_type == buf_type); + + DHD_PKTID_UNLOCK(map->pktid_lock, flags); + return NULL; + } + + map->avail++; + +#if defined(DHD_PKTIDMAP_FIFO) + ASSERT(locker->nkey == nkey); + + dll_delete(&locker->list_node); /* Free locker to "tail" of free list */ + dll_append(&map->list_free, &locker->list_node); +#else /* ! DHD_PKTIDMAP_FIFO */ + map->keys[map->avail] = nkey; /* make this numbered key available */ +#endif /* ! DHD_PKTIDMAP_FIFO */ + + locker->inuse = FALSE; /* open and free Locker */ + +#if defined(DHD_PKTID_AUDIT_MAP) + DHD_PKTID_AUDIT(map, nkey, DHD_TEST_IS_FREE); +#endif /* DHD_PKTID_AUDIT_MAP */ + + *physaddr = locker->physaddr; /* return contents of locker */ + *len = (uint32)locker->len; + + pkt = locker->pkt; + locker->pkt = NULL; /* Clear pkt */ + locker->len = 0; + + DHD_PKTID_UNLOCK(map->pktid_lock, flags); + + return pkt; +} + +/* Linkage, sets prot link and updates hdrlen in pub */ +int dhd_prot_attach(dhd_pub_t *dhd) +{ + uint alloced = 0; + + dhd_prot_t *prot; + + /* Allocate prot structure */ + if (!(prot = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, + sizeof(dhd_prot_t)))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } + memset(prot, 0, sizeof(*prot)); + + prot->osh = dhd->osh; + dhd->prot = prot; + + /* DMAing ring completes supported? FALSE by default */ + dhd->dma_d2h_ring_upd_support = FALSE; + dhd->dma_h2d_ring_upd_support = FALSE; + + /* Ring Allocations */ + /* 1.0 H2D TXPOST ring */ + if (!(prot->h2dring_txp_subn = prot_ring_attach(prot, "h2dtxp", + H2DRING_TXPOST_MAX_ITEM, H2DRING_TXPOST_ITEMSIZE, + BCMPCIE_H2D_TXFLOWRINGID))) { + DHD_ERROR(("%s: kmalloc for H2D TXPOST ring failed\n", __FUNCTION__)); + goto fail; + } + + /* 2.0 H2D RXPOST ring */ + if (!(prot->h2dring_rxp_subn = prot_ring_attach(prot, "h2drxp", + H2DRING_RXPOST_MAX_ITEM, H2DRING_RXPOST_ITEMSIZE, + BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT))) { + DHD_ERROR(("%s: kmalloc for H2D RXPOST ring failed\n", __FUNCTION__)); + goto fail; + + } + + /* 3.0 H2D CTRL_SUBMISSION ring */ + if (!(prot->h2dring_ctrl_subn = prot_ring_attach(prot, "h2dctrl", + H2DRING_CTRL_SUB_MAX_ITEM, H2DRING_CTRL_SUB_ITEMSIZE, + BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT))) { + DHD_ERROR(("%s: kmalloc for H2D CTRL_SUBMISSION ring failed\n", + __FUNCTION__)); + goto fail; + + } + + /* 4.0 D2H TX_COMPLETION ring */ + if (!(prot->d2hring_tx_cpln = prot_ring_attach(prot, "d2htxcpl", + D2HRING_TXCMPLT_MAX_ITEM, D2HRING_TXCMPLT_ITEMSIZE, + BCMPCIE_D2H_MSGRING_TX_COMPLETE))) { + DHD_ERROR(("%s: kmalloc for D2H TX_COMPLETION ring failed\n", + __FUNCTION__)); + goto fail; + + } + + /* 5.0 D2H RX_COMPLETION ring */ + if (!(prot->d2hring_rx_cpln = prot_ring_attach(prot, "d2hrxcpl", + D2HRING_RXCMPLT_MAX_ITEM, D2HRING_RXCMPLT_ITEMSIZE, + BCMPCIE_D2H_MSGRING_RX_COMPLETE))) { + DHD_ERROR(("%s: kmalloc for D2H RX_COMPLETION ring failed\n", + __FUNCTION__)); + goto fail; + + } + + /* 6.0 D2H CTRL_COMPLETION ring */ + if (!(prot->d2hring_ctrl_cpln = prot_ring_attach(prot, "d2hctrl", + D2HRING_CTRL_CMPLT_MAX_ITEM, D2HRING_CTRL_CMPLT_ITEMSIZE, + BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE))) { + DHD_ERROR(("%s: kmalloc for D2H CTRL_COMPLETION ring failed\n", + __FUNCTION__)); + goto fail; + } + + /* Return buffer for ioctl */ + prot->retbuf.va = DMA_ALLOC_CONSISTENT(dhd->osh, IOCT_RETBUF_SIZE, DMA_ALIGN_LEN, + &alloced, &prot->retbuf.pa, &prot->retbuf.dmah); + if (prot->retbuf.va == NULL) { + ASSERT(0); + DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", + __FUNCTION__, __LINE__, IOCT_RETBUF_SIZE)); + return BCME_NOMEM; + } + + ASSERT(MODX((unsigned long)prot->retbuf.va, DMA_ALIGN_LEN) == 0); + bzero(prot->retbuf.va, IOCT_RETBUF_SIZE); + OSL_CACHE_FLUSH((void *) prot->retbuf.va, IOCT_RETBUF_SIZE); + + /* IOCTL request buffer */ + prot->ioctbuf.va = DMA_ALLOC_CONSISTENT(dhd->osh, IOCT_RETBUF_SIZE, DMA_ALIGN_LEN, + &alloced, &prot->ioctbuf.pa, &prot->ioctbuf.dmah); + + if (prot->ioctbuf.va == NULL) { + ASSERT(0); + DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", + __FUNCTION__, __LINE__, IOCT_RETBUF_SIZE)); + return BCME_NOMEM; + } + + ASSERT(MODX((unsigned long)prot->ioctbuf.va, DMA_ALIGN_LEN) == 0); + bzero(prot->ioctbuf.va, IOCT_RETBUF_SIZE); + OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, IOCT_RETBUF_SIZE); + + /* Scratch buffer for dma rx offset */ + prot->d2h_dma_scratch_buf_len = DMA_D2H_SCRATCH_BUF_LEN; + prot->d2h_dma_scratch_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, DMA_D2H_SCRATCH_BUF_LEN, + DMA_ALIGN_LEN, &alloced, &prot->d2h_dma_scratch_buf.pa, + &prot->d2h_dma_scratch_buf.dmah); + + if (prot->d2h_dma_scratch_buf.va == NULL) { + ASSERT(0); + DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", + __FUNCTION__, __LINE__, DMA_D2H_SCRATCH_BUF_LEN)); + return BCME_NOMEM; + } + ASSERT(MODX((unsigned long)prot->d2h_dma_scratch_buf.va, DMA_ALIGN_LEN) == 0); + bzero(prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); + OSL_CACHE_FLUSH((void *)prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); + + + /* PKTID handle INIT */ + prot->pktid_map_handle = NATIVE_TO_PKTID_INIT(dhd, MAX_PKTID_ITEMS); + if (prot->pktid_map_handle == NULL) { + ASSERT(0); + return BCME_NOMEM; + } + + prot->dmaxfer.srcmem.va = NULL; + prot->dmaxfer.destmem.va = NULL; + prot->dmaxfer_in_progress = FALSE; + + prot->rx_metadata_offset = 0; + prot->tx_metadata_offset = 0; + +#ifdef DHD_RX_CHAINING + dhd_rxchain_reset(&prot->rxchain); +#endif + + return 0; + +fail: +#ifndef CONFIG_DHD_USE_STATIC_BUF + if (prot != NULL) + dhd_prot_detach(dhd); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + return BCME_NOMEM; +} + +/* Init memory block on host DMA'ing indices */ +int +dhd_prot_init_index_dma_block(dhd_pub_t *dhd, uint8 type, uint32 length) +{ + uint alloced = 0; + + dhd_prot_t *prot = dhd->prot; + uint32 dma_block_size = 4 * length; + + if (prot == NULL) { + DHD_ERROR(("prot is not inited\n")); + return BCME_ERROR; + } + + switch (type) { + case HOST_TO_DNGL_DMA_WRITEINDX_BUFFER: + /* ring update dma buffer for submission write */ + prot->h2d_dma_writeindx_buf_len = dma_block_size; + prot->h2d_dma_writeindx_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, + dma_block_size, DMA_ALIGN_LEN, &alloced, + &prot->h2d_dma_writeindx_buf.pa, + &prot->h2d_dma_writeindx_buf.dmah); + + if (prot->h2d_dma_writeindx_buf.va == NULL) { + return BCME_NOMEM; + } + + ASSERT(ISALIGNED(prot->h2d_dma_writeindx_buf.va, 4)); + bzero(prot->h2d_dma_writeindx_buf.va, dma_block_size); + OSL_CACHE_FLUSH((void *)prot->h2d_dma_writeindx_buf.va, dma_block_size); + DHD_ERROR(("H2D_WRITEINDX_ARRAY_HOST: %d-bytes " + "inited for dma'ing h2d-w indices\n", + prot->h2d_dma_writeindx_buf_len)); + break; + + case HOST_TO_DNGL_DMA_READINDX_BUFFER: + /* ring update dma buffer for submission read */ + prot->h2d_dma_readindx_buf_len = dma_block_size; + prot->h2d_dma_readindx_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, + dma_block_size, DMA_ALIGN_LEN, &alloced, + &prot->h2d_dma_readindx_buf.pa, + &prot->h2d_dma_readindx_buf.dmah); + if (prot->h2d_dma_readindx_buf.va == NULL) { + return BCME_NOMEM; + } + + ASSERT(ISALIGNED(prot->h2d_dma_readindx_buf.va, 4)); + bzero(prot->h2d_dma_readindx_buf.va, dma_block_size); + OSL_CACHE_FLUSH((void *)prot->h2d_dma_readindx_buf.va, dma_block_size); + DHD_ERROR(("H2D_READINDX_ARRAY_HOST %d-bytes " + "inited for dma'ing h2d-r indices\n", + prot->h2d_dma_readindx_buf_len)); + break; + + case DNGL_TO_HOST_DMA_WRITEINDX_BUFFER: + /* ring update dma buffer for completion write */ + prot->d2h_dma_writeindx_buf_len = dma_block_size; + prot->d2h_dma_writeindx_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, + dma_block_size, DMA_ALIGN_LEN, &alloced, + &prot->d2h_dma_writeindx_buf.pa, + &prot->d2h_dma_writeindx_buf.dmah); + + if (prot->d2h_dma_writeindx_buf.va == NULL) { + return BCME_NOMEM; + } + + ASSERT(ISALIGNED(prot->d2h_dma_writeindx_buf.va, 4)); + bzero(prot->d2h_dma_writeindx_buf.va, dma_block_size); + OSL_CACHE_FLUSH((void *)prot->d2h_dma_writeindx_buf.va, dma_block_size); + DHD_ERROR(("D2H_WRITEINDX_ARRAY_HOST %d-bytes " + "inited for dma'ing d2h-w indices\n", + prot->d2h_dma_writeindx_buf_len)); + break; + + case DNGL_TO_HOST_DMA_READINDX_BUFFER: + /* ring update dma buffer for completion read */ + prot->d2h_dma_readindx_buf_len = dma_block_size; + prot->d2h_dma_readindx_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, + dma_block_size, DMA_ALIGN_LEN, &alloced, + &prot->d2h_dma_readindx_buf.pa, + &prot->d2h_dma_readindx_buf.dmah); + + if (prot->d2h_dma_readindx_buf.va == NULL) { + return BCME_NOMEM; + } + + ASSERT(ISALIGNED(prot->d2h_dma_readindx_buf.va, 4)); + bzero(prot->d2h_dma_readindx_buf.va, dma_block_size); + OSL_CACHE_FLUSH((void *)prot->d2h_dma_readindx_buf.va, dma_block_size); + DHD_ERROR(("D2H_READINDX_ARRAY_HOST %d-bytes " + "inited for dma'ing d2h-r indices\n", + prot->d2h_dma_readindx_buf_len)); + break; + + default: + DHD_ERROR(("%s: Unexpected option\n", __FUNCTION__)); + return BCME_BADOPTION; + } + + return BCME_OK; + +} + +/* Unlink, frees allocated protocol memory (including dhd_prot) */ +void dhd_prot_detach(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + /* Stop the protocol module */ + if (dhd->prot) { + + /* free up scratch buffer */ + if (prot->d2h_dma_scratch_buf.va) { + DMA_FREE_CONSISTENT(dhd->osh, prot->d2h_dma_scratch_buf.va, + DMA_D2H_SCRATCH_BUF_LEN, prot->d2h_dma_scratch_buf.pa, + prot->d2h_dma_scratch_buf.dmah); + prot->d2h_dma_scratch_buf.va = NULL; + } + /* free up ring upd buffer for submission writes */ + if (prot->h2d_dma_writeindx_buf.va) { + DMA_FREE_CONSISTENT(dhd->osh, prot->h2d_dma_writeindx_buf.va, + prot->h2d_dma_writeindx_buf_len, prot->h2d_dma_writeindx_buf.pa, + prot->h2d_dma_writeindx_buf.dmah); + prot->h2d_dma_writeindx_buf.va = NULL; + } + + /* free up ring upd buffer for submission reads */ + if (prot->h2d_dma_readindx_buf.va) { + DMA_FREE_CONSISTENT(dhd->osh, prot->h2d_dma_readindx_buf.va, + prot->h2d_dma_readindx_buf_len, prot->h2d_dma_readindx_buf.pa, + prot->h2d_dma_readindx_buf.dmah); + prot->h2d_dma_readindx_buf.va = NULL; + } + + /* free up ring upd buffer for completion writes */ + if (prot->d2h_dma_writeindx_buf.va) { + DMA_FREE_CONSISTENT(dhd->osh, prot->d2h_dma_writeindx_buf.va, + prot->d2h_dma_writeindx_buf_len, prot->d2h_dma_writeindx_buf.pa, + prot->d2h_dma_writeindx_buf.dmah); + prot->d2h_dma_writeindx_buf.va = NULL; + } + + /* free up ring upd buffer for completion writes */ + if (prot->d2h_dma_readindx_buf.va) { + DMA_FREE_CONSISTENT(dhd->osh, prot->d2h_dma_readindx_buf.va, + prot->d2h_dma_readindx_buf_len, prot->d2h_dma_readindx_buf.pa, + prot->d2h_dma_readindx_buf.dmah); + prot->d2h_dma_readindx_buf.va = NULL; + } + + /* ioctl return buffer */ + if (prot->retbuf.va) { + DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->retbuf.va, + IOCT_RETBUF_SIZE, dhd->prot->retbuf.pa, dhd->prot->retbuf.dmah); + dhd->prot->retbuf.va = NULL; + } + + /* ioctl request buffer */ + if (prot->ioctbuf.va) { + DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->ioctbuf.va, + IOCT_RETBUF_SIZE, dhd->prot->ioctbuf.pa, dhd->prot->ioctbuf.dmah); + + dhd->prot->ioctbuf.va = NULL; + } + + + /* 1.0 H2D TXPOST ring */ + dhd_prot_ring_detach(dhd, prot->h2dring_txp_subn); + /* 2.0 H2D RXPOST ring */ + dhd_prot_ring_detach(dhd, prot->h2dring_rxp_subn); + /* 3.0 H2D CTRL_SUBMISSION ring */ + dhd_prot_ring_detach(dhd, prot->h2dring_ctrl_subn); + /* 4.0 D2H TX_COMPLETION ring */ + dhd_prot_ring_detach(dhd, prot->d2hring_tx_cpln); + /* 5.0 D2H RX_COMPLETION ring */ + dhd_prot_ring_detach(dhd, prot->d2hring_rx_cpln); + /* 6.0 D2H CTRL_COMPLETION ring */ + dhd_prot_ring_detach(dhd, prot->d2hring_ctrl_cpln); + + NATIVE_TO_PKTID_FINI(dhd->prot->pktid_map_handle); + +#ifndef CONFIG_DHD_USE_STATIC_BUF + MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + + /* No need to do anything to prot->ioctl_mutex + * Unlike semaphores no memory is allocated during mutex_init + * So there is no call to free up the same. + */ + dhd->prot = NULL; + } +} + +void +dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 rx_offset) +{ + dhd_prot_t *prot = dhd->prot; + prot->rx_dataoffset = rx_offset; +} + +/* Initialize protocol: sync w/dongle state. + * Sets dongle media info (iswl, drv_version, mac address). + */ +int dhd_sync_with_dongle(dhd_pub_t *dhd) +{ + int ret = 0; + wlc_rev_info_t revinfo; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Post event buffer after shim layer is attached */ + ret = dhd_msgbuf_rxbuf_post_event_bufs(dhd); + if (ret <= 0) { + DHD_ERROR(("%s : Post event buffer fail. ret = %d\n", __FUNCTION__, ret)); + return ret; + } + + dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); + + + /* Get the device rev info */ + memset(&revinfo, 0, sizeof(revinfo)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); + if (ret < 0) + goto done; + + dhd_process_cid_mac(dhd, TRUE); + + ret = dhd_preinit_ioctls(dhd); + + if (!ret) + dhd_process_cid_mac(dhd, FALSE); + + /* Always assumes wl for now */ + dhd->iswl = TRUE; +done: + return ret; +} + +/* This function does all necessary initialization needed +* for IOCTL/IOVAR path +*/ +int dhd_prot_init(dhd_pub_t *dhd) +{ + int ret = 0; + dhd_prot_t *prot = dhd->prot; + + /* Max pkts in ring */ + prot->max_tx_count = H2DRING_TXPOST_MAX_ITEM; + + DHD_INFO(("%s:%d: MAX_TX_COUNT = %d\n", __FUNCTION__, __LINE__, prot->max_tx_count)); + + /* Read max rx packets supported by dongle */ + dhd_bus_cmn_readshared(dhd->bus, &prot->max_rxbufpost, MAX_HOST_RXBUFS, 0); + if (prot->max_rxbufpost == 0) { + /* This would happen if the dongle firmware is not */ + /* using the latest shared structure template */ + prot->max_rxbufpost = DEFAULT_RX_BUFFERS_TO_POST; + } + DHD_INFO(("%s:%d: MAX_RXBUFPOST = %d\n", __FUNCTION__, __LINE__, prot->max_rxbufpost)); + + prot->max_eventbufpost = DHD_FLOWRING_MAX_EVENTBUF_POST; + prot->max_ioctlrespbufpost = DHD_FLOWRING_MAX_IOCTLRESPBUF_POST; + + prot->active_tx_count = 0; + prot->data_seq_no = 0; + prot->ioctl_seq_no = 0; + prot->txp_threshold = TXP_FLUSH_MAX_ITEMS_FLUSH_CNT; + + prot->ioctl_trans_id = 1; + + /* + * Initialize the mutex that serializes the calls to + * dhd_prot_ioctl, if the ioctls are issued from + * multiple process/CPU contexts + */ + mutex_init(&prot->ioctl_mutex); + + /* Register the interrupt function upfront */ + /* remove corerev checks in data path */ + prot->mb_ring_fn = dhd_bus_get_mbintr_fn(dhd->bus); + + /* Initialise rings */ + /* 1.0 H2D TXPOST ring */ + if (dhd_bus_is_txmode_push(dhd->bus)) { + dhd_ring_init(dhd, prot->h2dring_txp_subn); + } + + /* 2.0 H2D RXPOST ring */ + dhd_ring_init(dhd, prot->h2dring_rxp_subn); + /* 3.0 H2D CTRL_SUBMISSION ring */ + dhd_ring_init(dhd, prot->h2dring_ctrl_subn); + /* 4.0 D2H TX_COMPLETION ring */ + dhd_ring_init(dhd, prot->d2hring_tx_cpln); + /* 5.0 D2H RX_COMPLETION ring */ + dhd_ring_init(dhd, prot->d2hring_rx_cpln); + /* 6.0 D2H CTRL_COMPLETION ring */ + dhd_ring_init(dhd, prot->d2hring_ctrl_cpln); + +#if defined(PCIE_D2H_SYNC) + dhd_prot_d2h_sync_init(dhd, prot); +#endif /* PCIE_D2H_SYNC */ + + /* init the scratch buffer */ + dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_scratch_buf.pa, + sizeof(prot->d2h_dma_scratch_buf.pa), DNGL_TO_HOST_DMA_SCRATCH_BUFFER, 0); + dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_scratch_buf_len, + sizeof(prot->d2h_dma_scratch_buf_len), DNGL_TO_HOST_DMA_SCRATCH_BUFFER_LEN, 0); + + /* If supported by the host, indicate the memory block + * for comletion writes / submission reads to shared space + */ + if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) { + dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_writeindx_buf.pa, + sizeof(prot->d2h_dma_writeindx_buf.pa), + DNGL_TO_HOST_DMA_WRITEINDX_BUFFER, 0); + dhd_bus_cmn_writeshared(dhd->bus, &prot->h2d_dma_readindx_buf.pa, + sizeof(prot->h2d_dma_readindx_buf.pa), + HOST_TO_DNGL_DMA_READINDX_BUFFER, 0); + } + + if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) { + dhd_bus_cmn_writeshared(dhd->bus, &prot->h2d_dma_writeindx_buf.pa, + sizeof(prot->h2d_dma_writeindx_buf.pa), + HOST_TO_DNGL_DMA_WRITEINDX_BUFFER, 0); + dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_readindx_buf.pa, + sizeof(prot->d2h_dma_readindx_buf.pa), + DNGL_TO_HOST_DMA_READINDX_BUFFER, 0); + + } + + ret = dhd_msgbuf_rxbuf_post(dhd); + ret = dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd); + + return ret; +} + +#define DHD_DBG_SHOW_METADATA 0 +#if DHD_DBG_SHOW_METADATA +static void BCMFASTPATH +dhd_prot_print_metadata(dhd_pub_t *dhd, void *ptr, int len) +{ + uint8 tlv_t; + uint8 tlv_l; + uint8 *tlv_v = (uint8 *)ptr; + + if (len <= BCMPCIE_D2H_METADATA_HDRLEN) + return; + + len -= BCMPCIE_D2H_METADATA_HDRLEN; + tlv_v += BCMPCIE_D2H_METADATA_HDRLEN; + + while (len > TLV_HDR_LEN) { + tlv_t = tlv_v[TLV_TAG_OFF]; + tlv_l = tlv_v[TLV_LEN_OFF]; + + len -= TLV_HDR_LEN; + tlv_v += TLV_HDR_LEN; + if (len < tlv_l) + break; + if ((tlv_t == 0) || (tlv_t == WLFC_CTL_TYPE_FILLER)) + break; + + switch (tlv_t) { + case WLFC_CTL_TYPE_TXSTATUS: + bcm_print_bytes("METADATA TX_STATUS", tlv_v, tlv_l); + break; + + case WLFC_CTL_TYPE_RSSI: + bcm_print_bytes("METADATA RX_RSSI", tlv_v, tlv_l); + break; + + case WLFC_CTL_TYPE_FIFO_CREDITBACK: + bcm_print_bytes("METADATA FIFO_CREDITBACK", tlv_v, tlv_l); + break; + + case WLFC_CTL_TYPE_TX_ENTRY_STAMP: + bcm_print_bytes("METADATA TX_ENTRY", tlv_v, tlv_l); + break; + + case WLFC_CTL_TYPE_RX_STAMP: + bcm_print_bytes("METADATA RX_TIMESTAMP", tlv_v, tlv_l); + break; + + case WLFC_CTL_TYPE_TRANS_ID: + bcm_print_bytes("METADATA TRANS_ID", tlv_v, tlv_l); + break; + + case WLFC_CTL_TYPE_COMP_TXSTATUS: + bcm_print_bytes("METADATA COMP_TXSTATUS", tlv_v, tlv_l); + break; + + default: + bcm_print_bytes("METADATA UNKNOWN", tlv_v, tlv_l); + break; + } + + len -= tlv_l; + tlv_v += tlv_l; + } +} +#endif /* DHD_DBG_SHOW_METADATA */ + +static INLINE void BCMFASTPATH +dhd_prot_packet_free(dhd_pub_t *dhd, uint32 pktid, uint8 buf_type) +{ + void *PKTBUF; + dmaaddr_t pa; + uint32 pa_len; + PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, + pa_len, buf_type); + + if (PKTBUF) { + if (!PHYSADDRISZERO(pa)) { + if (buf_type == BUFF_TYPE_DATA_TX) { + DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_TX, 0, 0); + } else { + DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_RX, 0, 0); + } +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + if (buf_type == BUFF_TYPE_IOCTL_RX) { + PKTFREE_STATIC(dhd->osh, PKTBUF, FALSE); + } else { +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + PKTFREE(dhd->osh, PKTBUF, FALSE); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + } else { + DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__)); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + if (buf_type == BUFF_TYPE_IOCTL_RX) { + PKTINVALIDATE_STATIC(dhd->osh, PKTBUF); + } else { +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + PKTFREE(dhd->osh, PKTBUF, FALSE); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + } + } else { + printf("%s: pkt id invaild. dump dongle memory.\n", __FUNCTION__); + /* write core dump to file */ +#ifdef DHD_FW_COREDUMP + dhdpcie_mem_dump(dhd->bus); +#endif /* DHD_FW_COREDUMP */ + } + + return; +} + +static INLINE void * BCMFASTPATH +dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid, uint8 buf_type) +{ + void *PKTBUF; + dmaaddr_t pa; + uint32 pa_len; + PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, pa_len, buf_type); + if (PKTBUF) { + if (!PHYSADDRISZERO(pa)) { + if (buf_type == BUFF_TYPE_DATA_TX) { + DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_TX, 0, 0); + } else { + DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_RX, 0, 0); + } + } else { + DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__)); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + if (buf_type == BUFF_TYPE_IOCTL_RX || + buf_type == BUFF_TYPE_EVENT_RX) { + PKTINVALIDATE_STATIC(dhd->osh, PKTBUF); + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + } + } + + return PKTBUF; +} + +static int BCMFASTPATH +dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + int16 fillbufs; + uint16 cnt = 64; + int retcount = 0; + + fillbufs = prot->max_rxbufpost - prot->rxbufpost; + while (fillbufs > 0) { + cnt--; + if (cnt == 0) { + /* find a better way to reschedule rx buf post if space not available */ + DHD_ERROR(("h2d rx post ring not available to post host buffers \n")); + DHD_ERROR(("Current posted host buf count %d \n", prot->rxbufpost)); + break; + } + + /* Post in a burst of 8 buffers ata time */ + fillbufs = MIN(fillbufs, RX_BUF_BURST); + + /* Post buffers */ + retcount = dhd_prot_rxbufpost(dhd, fillbufs); + + if (retcount > 0) { + prot->rxbufpost += (uint16)retcount; + + /* how many more to post */ + fillbufs = prot->max_rxbufpost - prot->rxbufpost; + } else { + /* Make sure we don't run loop any further */ + fillbufs = 0; + } + } + + return 0; +} + +/* Post count no of rx buffers down to dongle */ +static int BCMFASTPATH +dhd_prot_rxbufpost(dhd_pub_t *dhd, uint16 count) +{ + void *p; + uint16 pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; + uint8 *rxbuf_post_tmp; + host_rxbuf_post_t *rxbuf_post; + void* msg_start; + dmaaddr_t physaddr; + uint32 pktlen; + dhd_prot_t *prot = dhd->prot; + msgbuf_ring_t * ring = prot->h2dring_rxp_subn; + uint8 i = 0; + uint16 alloced = 0; + unsigned long flags; + uint32 pktid; + + DHD_GENERAL_LOCK(dhd, flags); + /* Claim space for 'count' no of messages */ + msg_start = (void *)dhd_alloc_ring_space(dhd, ring, count, &alloced); + DHD_GENERAL_UNLOCK(dhd, flags); + + if (msg_start == NULL) { + DHD_INFO(("%s:%d: Rxbufpost Msgbuf Not available\n", __FUNCTION__, __LINE__)); + return -1; + } + /* if msg_start != NULL, we should have alloced space for atleast 1 item */ + ASSERT(alloced > 0); + + rxbuf_post_tmp = (uint8*)msg_start; + + /* loop through each message */ + for (i = 0; i < alloced; i++) { + rxbuf_post = (host_rxbuf_post_t *)rxbuf_post_tmp; + /* Create a rx buffer */ + if ((p = PKTGET(dhd->osh, pktsz, FALSE)) == NULL) { + DHD_ERROR(("%s:%d: PKTGET for rxbuf failed\n", __FUNCTION__, __LINE__)); + break; + } + + pktlen = PKTLEN(dhd->osh, p); + physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0); + if (PHYSADDRISZERO(physaddr)) { + PKTFREE(dhd->osh, p, FALSE); + DHD_ERROR(("Invalid phyaddr 0\n")); + ASSERT(0); + break; + } + + PKTPULL(dhd->osh, p, prot->rx_metadata_offset); + pktlen = PKTLEN(dhd->osh, p); + + /* CMN msg header */ + rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_RXBUF_POST; + rxbuf_post->cmn_hdr.if_id = 0; + + /* get the lock before calling NATIVE_TO_PKTID */ + DHD_GENERAL_LOCK(dhd, flags); + + pktid = htol32(NATIVE_TO_PKTID(dhd->prot->pktid_map_handle, p, physaddr, + pktlen, DMA_RX, BUFF_TYPE_DATA_RX)); + + /* free lock */ + DHD_GENERAL_UNLOCK(dhd, flags); + + if (pktid == DHD_PKTID_INVALID) { + DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0); + PKTFREE(dhd->osh, p, FALSE); + DHD_ERROR(("Pktid pool depleted.\n")); + break; + } + + /* CMN msg header */ + rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_RXBUF_POST; + rxbuf_post->cmn_hdr.if_id = 0; + + rxbuf_post->data_buf_len = htol16((uint16)pktlen); + rxbuf_post->data_buf_addr.high_addr = htol32(PHYSADDRHI(physaddr)); + rxbuf_post->data_buf_addr.low_addr = + htol32(PHYSADDRLO(physaddr) + prot->rx_metadata_offset); + + if (prot->rx_metadata_offset) { + rxbuf_post->metadata_buf_len = prot->rx_metadata_offset; + rxbuf_post->metadata_buf_addr.high_addr = htol32(PHYSADDRHI(physaddr)); + rxbuf_post->metadata_buf_addr.low_addr = htol32(PHYSADDRLO(physaddr)); + } else { + rxbuf_post->metadata_buf_len = 0; + rxbuf_post->metadata_buf_addr.high_addr = 0; + rxbuf_post->metadata_buf_addr.low_addr = 0; + } + +#if defined(DHD_PKTID_AUDIT_RING) + DHD_PKTID_AUDIT(prot->pktid_map_handle, pktid, DHD_DUPLICATE_ALLOC); +#endif /* DHD_PKTID_AUDIT_RING */ + + rxbuf_post->cmn_hdr.request_id = htol32(pktid); + + /* Move rxbuf_post_tmp to next item */ + rxbuf_post_tmp = rxbuf_post_tmp + RING_LEN_ITEMS(ring); + } + + if (i < alloced) { + if (RING_WRITE_PTR(ring) < (alloced - i)) + RING_WRITE_PTR(ring) = RING_MAX_ITEM(ring) - (alloced - i); + else + RING_WRITE_PTR(ring) -= (alloced - i); + + alloced = i; + } + + /* Update the write pointer in TCM & ring bell */ + if (alloced > 0) + prot_ring_write_complete(dhd, prot->h2dring_rxp_subn, msg_start, alloced); + + return alloced; +} + +static int +dhd_prot_rxbufpost_ctrl(dhd_pub_t *dhd, bool event_buf) +{ + void *p; + uint16 pktsz; + ioctl_resp_evt_buf_post_msg_t *rxbuf_post; + dmaaddr_t physaddr; + uint32 pktlen; + dhd_prot_t *prot = dhd->prot; + uint16 alloced = 0; + unsigned long flags; + uint8 buf_type; + uint32 pktid; + + if (dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); + return -1; + } + + if (event_buf) { + /* Allocate packet for event buffer post */ + pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; + } else { + /* Allocate packet for ctrl/ioctl buffer post */ + pktsz = DHD_FLOWRING_IOCTL_BUFPOST_PKTSZ; + } + +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + if (!event_buf) { + p = PKTGET_STATIC(dhd->osh, pktsz, FALSE); + } else { +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + p = PKTGET(dhd->osh, pktsz, FALSE); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + + if (p == NULL) { + DHD_ERROR(("%s:%d: PKTGET for %s rxbuf failed\n", + __FUNCTION__, __LINE__, event_buf ? "event" : + "ioctl")); + return -1; + } + + pktlen = PKTLEN(dhd->osh, p); + physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0); + if (PHYSADDRISZERO(physaddr)) { + + DHD_ERROR(("Invalid phyaddr 0\n")); + ASSERT(0); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + PKTINVALIDATE_STATIC(dhd->osh, p); + return -1; +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + goto free_pkt_return; + } + + DHD_GENERAL_LOCK(dhd, flags); + rxbuf_post = (ioctl_resp_evt_buf_post_msg_t *)dhd_alloc_ring_space(dhd, + prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); + if (rxbuf_post == NULL) { + DHD_GENERAL_UNLOCK(dhd, flags); + DHD_ERROR(("%s:%d: Ctrl submit Msgbuf Not available to post buffer" + " for %s\n", __FUNCTION__, __LINE__, event_buf ? "event" : + "ioctl")); + DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0); + + goto free_pkt_return; + } + + buf_type = ((event_buf == 1) ? BUFF_TYPE_EVENT_RX : + BUFF_TYPE_IOCTL_RX); + + pktid = htol32(NATIVE_TO_PKTID(dhd->prot->pktid_map_handle, p, physaddr, + pktlen, DMA_RX, buf_type)); + + if (pktid == DHD_PKTID_INVALID) { + if (RING_WRITE_PTR(prot->h2dring_ctrl_subn) == 0) { + RING_WRITE_PTR(prot->h2dring_ctrl_subn) = + RING_MAX_ITEM(prot->h2dring_ctrl_subn) - 1; + } else { + RING_WRITE_PTR(prot->h2dring_ctrl_subn)--; + } + DHD_GENERAL_UNLOCK(dhd, flags); + DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0); + + goto free_pkt_return; + } + +#if defined(DHD_PKTID_AUDIT_RING) + DHD_PKTID_AUDIT(prot->pktid_map_handle, pktid, DHD_DUPLICATE_ALLOC); +#endif /* DHD_PKTID_AUDIT_RING */ + + /* CMN msg header */ + if (event_buf) { + rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_EVENT_BUF_POST; + } else { + rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_IOCTLRESP_BUF_POST; + } + + rxbuf_post->cmn_hdr.if_id = 0; + rxbuf_post->cmn_hdr.flags = 0; + + rxbuf_post->host_buf_len = htol16((uint16)PKTLEN(dhd->osh, p)); + rxbuf_post->host_buf_addr.high_addr = htol32(PHYSADDRHI(physaddr)); + rxbuf_post->host_buf_addr.low_addr = htol32(PHYSADDRLO(physaddr)); + rxbuf_post->cmn_hdr.request_id = htol32(pktid); + + /* Update the write pointer in TCM & ring bell */ + prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, rxbuf_post, + DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); + DHD_GENERAL_UNLOCK(dhd, flags); + + return 1; + +free_pkt_return: +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + if (!event_buf) { + PKTFREE_STATIC(dhd->osh, p, FALSE); + } else { +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + + PKTFREE(dhd->osh, p, FALSE); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + + return -1; +} + +static uint16 +dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, bool event_buf, uint32 max_to_post) +{ + uint32 i = 0; + int32 ret_val; + + DHD_INFO(("max to post %d, event %d \n", max_to_post, event_buf)); + + if (dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); + return 0; + } + + while (i < max_to_post) { + ret_val = dhd_prot_rxbufpost_ctrl(dhd, event_buf); + if (ret_val < 0) + break; + i++; + } + DHD_INFO(("posted %d buffers to event_pool/ioctl_resp_pool %d\n", i, event_buf)); + return (uint16)i; +} + +static int +dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + uint16 retcnt = 0; + + DHD_INFO(("ioctl resp buf post\n")); + + if (dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); + return 0; + } + + retcnt = dhd_msgbuf_rxbuf_post_ctrlpath(dhd, FALSE, + prot->max_ioctlrespbufpost - prot->cur_ioctlresp_bufs_posted); + prot->cur_ioctlresp_bufs_posted += retcnt; + return retcnt; +} + +static int +dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + uint16 retcnt = 0; + + if (dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); + return 0; + } + + retcnt = dhd_msgbuf_rxbuf_post_ctrlpath(dhd, TRUE, + prot->max_eventbufpost - prot->cur_event_bufs_posted); + + prot->cur_event_bufs_posted += retcnt; + return retcnt; +} + +bool BCMFASTPATH +dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound) +{ + dhd_prot_t *prot = dhd->prot; + bool more = TRUE; + uint n = 0; + + /* Process all the messages - DTOH direction */ + while (TRUE) { + uint8 *src_addr; + uint16 src_len; + + if (dhd->hang_was_sent) { + more = FALSE; + break; + } + + /* Store current read pointer */ + /* Read pointer will be updated in prot_early_upd_rxcpln_read_idx */ + prot_store_rxcpln_read_idx(dhd, prot->d2hring_rx_cpln); + + /* Get the message from ring */ + src_addr = prot_get_src_addr(dhd, prot->d2hring_rx_cpln, &src_len); + if (src_addr == NULL) { + more = FALSE; + break; + } + + /* Prefetch data to populate the cache */ + OSL_PREFETCH(src_addr); + + if (dhd_prot_process_msgtype(dhd, prot->d2hring_rx_cpln, src_addr, + src_len) != BCME_OK) { + prot_upd_read_idx(dhd, prot->d2hring_rx_cpln); + DHD_ERROR(("%s: Error at process rxpl msgbuf of len %d\n", + __FUNCTION__, src_len)); + } + + /* After batch processing, check RX bound */ + n += src_len/RING_LEN_ITEMS(prot->d2hring_rx_cpln); + if (n >= bound) { + break; + } + } + + return more; +} + +void +dhd_prot_update_txflowring(dhd_pub_t *dhd, uint16 flow_id, void *msgring_info) +{ + uint16 r_index = 0; + msgbuf_ring_t *ring = (msgbuf_ring_t *)msgring_info; + + /* Update read pointer */ + if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) { + r_index = dhd_get_dmaed_index(dhd, H2D_DMA_READINDX, ring->idx); + ring->ringstate->r_offset = r_index; + } + + DHD_TRACE(("flow %d, write %d read %d \n\n", flow_id, RING_WRITE_PTR(ring), + RING_READ_PTR(ring))); + + /* Need more logic here, but for now use it directly */ + dhd_bus_schedule_queue(dhd->bus, flow_id, TRUE); +} + + +bool BCMFASTPATH +dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound) +{ + dhd_prot_t *prot = dhd->prot; + bool more = TRUE; + uint n = 0; + + /* Process all the messages - DTOH direction */ + while (TRUE) { + uint8 *src_addr; + uint16 src_len; + + if (dhd->hang_was_sent) { + more = FALSE; + break; + } + + src_addr = prot_get_src_addr(dhd, prot->d2hring_tx_cpln, &src_len); + if (src_addr == NULL) { + more = FALSE; + break; + } + + /* Prefetch data to populate the cache */ + OSL_PREFETCH(src_addr); + + if (dhd_prot_process_msgtype(dhd, prot->d2hring_tx_cpln, src_addr, + src_len) != BCME_OK) { + DHD_ERROR(("%s: Error at process txcmpl msgbuf of len %d\n", + __FUNCTION__, src_len)); + } + + /* Write to dngl rd ptr */ + prot_upd_read_idx(dhd, prot->d2hring_tx_cpln); + + /* After batch processing, check bound */ + n += src_len/RING_LEN_ITEMS(prot->d2hring_tx_cpln); + if (n >= bound) { + break; + } + } + + return more; +} + +int BCMFASTPATH +dhd_prot_process_ctrlbuf(dhd_pub_t * dhd) +{ + dhd_prot_t *prot = dhd->prot; + + /* Process all the messages - DTOH direction */ + while (TRUE) { + uint8 *src_addr; + uint16 src_len; + + if (dhd->hang_was_sent) { + break; + } + + src_addr = prot_get_src_addr(dhd, prot->d2hring_ctrl_cpln, &src_len); + + if (src_addr == NULL) { + break; + } + + /* Prefetch data to populate the cache */ + OSL_PREFETCH(src_addr); + if (dhd_prot_process_msgtype(dhd, prot->d2hring_ctrl_cpln, src_addr, + src_len) != BCME_OK) { + DHD_ERROR(("%s: Error at process ctrlmsgbuf of len %d\n", + __FUNCTION__, src_len)); + } + + /* Write to dngl rd ptr */ + prot_upd_read_idx(dhd, prot->d2hring_ctrl_cpln); + } + + return 0; +} + +static int BCMFASTPATH +dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len) +{ + dhd_prot_t *prot = dhd->prot; + uint32 cur_dma_len = 0; + int ret = BCME_OK; + + DHD_INFO(("%s: process msgbuf of len %d\n", __FUNCTION__, len)); + + while (len > 0) { + ASSERT(len > (sizeof(cmn_msg_hdr_t) + prot->rx_dataoffset)); + + if (dhd->hang_was_sent) { + ret = BCME_ERROR; + break; + } + + if (prot->rx_dataoffset) { + cur_dma_len = *(uint32 *) buf; + ASSERT(cur_dma_len <= len); + buf += prot->rx_dataoffset; + len -= (uint16)prot->rx_dataoffset; + } + else { + cur_dma_len = len; + } + if (dhd_process_msgtype(dhd, ring, buf, (uint16)cur_dma_len) != BCME_OK) { + DHD_ERROR(("%s: Error at process msg of dmalen %d\n", + __FUNCTION__, cur_dma_len)); + ret = BCME_ERROR; + } + + len -= (uint16)cur_dma_len; + buf += cur_dma_len; + } + return ret; +} + +static int BCMFASTPATH +dhd_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len) +{ + uint16 pktlen = len; + uint16 msglen; + uint8 msgtype; + cmn_msg_hdr_t *msg = NULL; + int ret = BCME_OK; + +#if defined(PCIE_D2H_SYNC_BZERO) + uint8 *buf_head = buf; +#endif /* PCIE_D2H_SYNC_BZERO */ + + ASSERT(ring && ring->ringmem); + msglen = RING_LEN_ITEMS(ring); + if (msglen == 0) { + DHD_ERROR(("%s: ringidx %d, msglen is %d, pktlen is %d \n", + __FUNCTION__, ring->idx, msglen, pktlen)); + return BCME_ERROR; + } + + while (pktlen > 0) { + if (dhd->hang_was_sent) { + ret = BCME_ERROR; + goto done; + } + + msg = (cmn_msg_hdr_t *)buf; + +#if defined(PCIE_D2H_SYNC) + /* Wait until DMA completes, then fetch msgtype */ + msgtype = dhd->prot->d2h_sync_cb(dhd, ring, msg, msglen); +#else + msgtype = msg->msg_type; +#endif /* !PCIE_D2H_SYNC */ + + DHD_INFO(("msgtype %d, msglen is %d, pktlen is %d \n", + msgtype, msglen, pktlen)); + if (msgtype == MSG_TYPE_LOOPBACK) { + bcm_print_bytes("LPBK RESP: ", (uint8 *)msg, msglen); + DHD_ERROR((" MSG_TYPE_LOOPBACK, len %d\n", msglen)); + } + + + if (msgtype >= DHD_PROT_FUNCS) { + DHD_ERROR(("%s: msgtype %d, msglen is %d, pktlen is %d \n", + __FUNCTION__, msgtype, msglen, pktlen)); + ret = BCME_ERROR; + goto done; + } + + if (table_lookup[msgtype]) { + table_lookup[msgtype](dhd, buf, msglen); + } + + if (pktlen < msglen) { + ret = BCME_ERROR; + goto done; + } + pktlen = pktlen - msglen; + buf = buf + msglen; + + if (ring->idx == BCMPCIE_D2H_MSGRING_RX_COMPLETE) + prot_early_upd_rxcpln_read_idx(dhd, ring); + } +done: + +#if defined(PCIE_D2H_SYNC_BZERO) + OSL_CACHE_FLUSH(buf_head, len - pktlen); /* Flush the bzeroed msg */ +#endif /* PCIE_D2H_SYNC_BZERO */ + +#ifdef DHD_RX_CHAINING + dhd_rxchain_commit(dhd); +#endif + + return ret; +} + +static void +dhd_prot_noop(dhd_pub_t *dhd, void * buf, uint16 msglen) +{ + return; +} + +static void +dhd_prot_ringstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen) +{ + pcie_ring_status_t * ring_status = (pcie_ring_status_t *)buf; + DHD_ERROR(("ring status: request_id %d, status 0x%04x, flow ring %d, w_offset %d \n", + ring_status->cmn_hdr.request_id, ring_status->compl_hdr.status, + ring_status->compl_hdr.flow_ring_id, ring_status->write_idx)); + /* How do we track this to pair it with ??? */ + return; +} + +static void +dhd_prot_genstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen) +{ + pcie_gen_status_t * gen_status = (pcie_gen_status_t *)buf; + DHD_ERROR(("gen status: request_id %d, status 0x%04x, flow ring %d \n", + gen_status->cmn_hdr.request_id, gen_status->compl_hdr.status, + gen_status->compl_hdr.flow_ring_id)); + + /* How do we track this to pair it with ??? */ + return; +} + +static void +dhd_prot_ioctack_process(dhd_pub_t *dhd, void * buf, uint16 msglen) +{ + ioctl_req_ack_msg_t * ioct_ack = (ioctl_req_ack_msg_t *)buf; + unsigned long flags; + +#if defined(DHD_PKTID_AUDIT_RING) + uint32 pktid; + pktid = ltoh32(ioct_ack->cmn_hdr.request_id); + if (pktid != DHD_IOCTL_REQ_PKTID) { + DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pktid, + DHD_TEST_IS_ALLOC); + } +#endif /* DHD_PKTID_AUDIT_RING */ + DHD_GENERAL_LOCK(dhd, flags); + if ((dhd->ioctl_state & MSGBUF_IOCTL_ACK_PENDING) && + (dhd->ioctl_state & MSGBUF_IOCTL_RESP_PENDING)) { + dhd->ioctl_state &= ~MSGBUF_IOCTL_ACK_PENDING; + } else { + DHD_ERROR(("%s: received ioctl ACK with state %02x trans_id = %d\n", + __FUNCTION__, dhd->ioctl_state, dhd->prot->ioctl_trans_id)); + prhex("dhd_prot_ioctack_process:", + (uchar *)buf, D2HRING_CTRL_CMPLT_ITEMSIZE); + } + DHD_GENERAL_UNLOCK(dhd, flags); + + DHD_CTL(("ioctl req ack: request_id %d, status 0x%04x, flow ring %d \n", + ioct_ack->cmn_hdr.request_id, ioct_ack->compl_hdr.status, + ioct_ack->compl_hdr.flow_ring_id)); + if (ioct_ack->compl_hdr.status != 0) { + DHD_ERROR(("got an error status for the ioctl request...need to handle that\n")); + } + +#if defined(PCIE_D2H_SYNC_BZERO) + memset(buf, 0, msglen); +#endif /* PCIE_D2H_SYNC_BZERO */ +} + +static void +dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void * buf, uint16 msglen) +{ + uint16 status; + uint32 resp_len = 0; + uint32 pkt_id, xt_id; + ioctl_comp_resp_msg_t * ioct_resp = (ioctl_comp_resp_msg_t *)buf; + unsigned long flags; + + resp_len = ltoh16(ioct_resp->resp_len); + xt_id = ltoh16(ioct_resp->trans_id); + BCM_REFERENCE(xt_id); + pkt_id = ltoh32(ioct_resp->cmn_hdr.request_id); + status = ioct_resp->compl_hdr.status; + +#if defined(PCIE_D2H_SYNC_BZERO) + memset(buf, 0, msglen); +#endif /* PCIE_D2H_SYNC_BZERO */ + +#if defined(DHD_PKTID_AUDIT_RING) + /* will be freed later */ + DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pkt_id, + DHD_TEST_IS_ALLOC); +#endif /* DHD_PKTID_AUDIT_RING */ + + DHD_GENERAL_LOCK(dhd, flags); + if ((dhd->ioctl_state & MSGBUF_IOCTL_ACK_PENDING) || + !(dhd->ioctl_state & MSGBUF_IOCTL_RESP_PENDING)) { + DHD_ERROR(("%s: received ioctl response with state %02x trans_id = %d\n", + __FUNCTION__, dhd->ioctl_state, dhd->prot->ioctl_trans_id)); + prhex("dhd_prot_ioctcmplt_process:", + (uchar *)buf, D2HRING_CTRL_CMPLT_ITEMSIZE); + DHD_GENERAL_UNLOCK(dhd, flags); + return; + } + DHD_GENERAL_UNLOCK(dhd, flags); + + DHD_CTL(("IOCTL_COMPLETE: pktid %x xtid %d status %x resplen %d\n", + pkt_id, xt_id, status, resp_len)); + + dhd_bus_update_retlen(dhd->bus, sizeof(ioctl_comp_resp_msg_t), pkt_id, status, resp_len); + dhd_os_ioctl_resp_wake(dhd); +} + +static void BCMFASTPATH +dhd_prot_txstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen) +{ + dhd_prot_t *prot = dhd->prot; + host_txbuf_cmpl_t * txstatus; + unsigned long flags; + uint32 pktid; + void *pkt; + /* locks required to protect circular buffer accesses */ + DHD_GENERAL_LOCK(dhd, flags); + + txstatus = (host_txbuf_cmpl_t *)buf; + pktid = ltoh32(txstatus->cmn_hdr.request_id); +#if defined(DHD_PKTID_AUDIT_RING) + DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pktid, + DHD_DUPLICATE_FREE); +#endif /* DHD_PKTID_AUDIT_RING */ + + DHD_INFO(("txstatus for pktid 0x%04x\n", pktid)); + if (prot->active_tx_count) { + prot->active_tx_count--; + /* Release the Lock when no more tx packets are pending */ + if (prot->active_tx_count == 0) + DHD_TXFL_WAKE_UNLOCK(dhd); + } else { + DHD_ERROR(("Extra packets are freed\n")); + } + + ASSERT(pktid != 0); + + pkt = dhd_prot_packet_get(dhd, pktid, BUFF_TYPE_DATA_TX); + if (pkt) { +#if defined(BCMPCIE) + dhd_txcomplete(dhd, pkt, true); +#endif + +#if DHD_DBG_SHOW_METADATA + if (dhd->prot->tx_metadata_offset && txstatus->metadata_len) { + uchar *ptr; + /* The Ethernet header of TX frame was copied and removed. + * Here, move the data pointer forward by Ethernet header size. + */ + PKTPULL(dhd->osh, pkt, ETHER_HDR_LEN); + ptr = PKTDATA(dhd->osh, pkt) - (dhd->prot->tx_metadata_offset); + bcm_print_bytes("txmetadata", ptr, txstatus->metadata_len); + dhd_prot_print_metadata(dhd, ptr, txstatus->metadata_len); + } +#endif /* DHD_DBG_SHOW_METADATA */ + PKTFREE(dhd->osh, pkt, TRUE); + } + +#if defined(PCIE_D2H_SYNC_BZERO) + memset(buf, 0, msglen); +#endif /* PCIE_D2H_SYNC_BZERO */ + + DHD_GENERAL_UNLOCK(dhd, flags); + + return; +} + +static void +dhd_msgbuf_dump_ctrlrings(dhd_pub_t *dhd) +{ + int i; + msgbuf_ring_t *ring; + uchar *msg; + + ring = dhd->prot->h2dring_ctrl_subn; + DHD_ERROR(("%s: ctrl post ring RP %d, WP %d\n", + __FUNCTION__, RING_READ_PTR(ring), RING_WRITE_PTR(ring))); + msg = (uchar *)ring->ring_base.va; + for (i = 0; i < RING_MAX_ITEM(ring); i++) { + prhex(NULL, msg, RING_LEN_ITEMS(ring)); + msg += RING_LEN_ITEMS(ring); + } + + ring = dhd->prot->d2hring_ctrl_cpln; + DHD_ERROR(("%s: ctrl complete ring RP %d, WP %d\n", + __FUNCTION__, RING_READ_PTR(ring), RING_WRITE_PTR(ring))); + msg = (uchar *)ring->ring_base.va; + for (i = 0; i < RING_MAX_ITEM(ring); i++) { + prhex(NULL, msg, RING_LEN_ITEMS(ring)); + msg += RING_LEN_ITEMS(ring); + } +} + +static void +dhd_prot_event_process(dhd_pub_t *dhd, void* buf, uint16 len) +{ + wlevent_req_msg_t *evnt; + uint32 pktid; + uint16 buflen; + int ifidx = 0; + void* pkt; + unsigned long flags; + dhd_prot_t *prot = dhd->prot; + int post_cnt = 0; + bool zero_posted = FALSE; + + /* Event complete header */ + evnt = (wlevent_req_msg_t *)buf; + pktid = ltoh32(evnt->cmn_hdr.request_id); + +#if defined(DHD_PKTID_AUDIT_RING) + DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pktid, + DHD_DUPLICATE_FREE); +#endif /* DHD_PKTID_AUDIT_RING */ + + buflen = ltoh16(evnt->event_data_len); + + ifidx = BCMMSGBUF_API_IFIDX(&evnt->cmn_hdr); + + /* Post another rxbuf to the device */ + if (prot->cur_event_bufs_posted) + prot->cur_event_bufs_posted--; + else + zero_posted = TRUE; + + + post_cnt = dhd_msgbuf_rxbuf_post_event_bufs(dhd); + if (zero_posted && (post_cnt <= 0)) { + return; + } + +#if defined(PCIE_D2H_SYNC_BZERO) + memset(buf, 0, len); +#endif /* PCIE_D2H_SYNC_BZERO */ + + /* locks required to protect pktid_map */ + DHD_GENERAL_LOCK(dhd, flags); + pkt = dhd_prot_packet_get(dhd, pktid, BUFF_TYPE_EVENT_RX); + + DHD_GENERAL_UNLOCK(dhd, flags); + + if (!pkt) { + DHD_ERROR(("%s: pkt is NULL\n", __FUNCTION__)); + dhd_msgbuf_dump_ctrlrings(dhd); + return; + } + + /* DMA RX offset updated through shared area */ + if (dhd->prot->rx_dataoffset) + PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset); + + PKTSETLEN(dhd->osh, pkt, buflen); + + dhd_bus_rx_frame(dhd->bus, pkt, ifidx, 1); +} + +static void BCMFASTPATH +dhd_prot_rxcmplt_process(dhd_pub_t *dhd, void* buf, uint16 msglen) +{ + host_rxbuf_cmpl_t *rxcmplt_h; + uint16 data_offset; /* offset at which data starts */ + void * pkt; + unsigned long flags; + static uint8 current_phase = 0; + uint ifidx; + uint32 pktid; + + /* RXCMPLT HDR */ + rxcmplt_h = (host_rxbuf_cmpl_t *)buf; + + /* Post another set of rxbufs to the device */ + dhd_prot_return_rxbuf(dhd, 1); + + pktid = ltoh32(rxcmplt_h->cmn_hdr.request_id); + +#if defined(DHD_PKTID_AUDIT_RING) + DHD_PKTID_AUDIT(dhd->prot->pktid_map_handle, pktid, + DHD_DUPLICATE_FREE); +#endif /* DHD_PKTID_AUDIT_RING */ + + /* offset from which data starts is populated in rxstatus0 */ + data_offset = ltoh16(rxcmplt_h->data_offset); + + DHD_GENERAL_LOCK(dhd, flags); + pkt = dhd_prot_packet_get(dhd, pktid, BUFF_TYPE_DATA_RX); + DHD_GENERAL_UNLOCK(dhd, flags); + + if (!pkt) { + return; + } + + DHD_INFO(("id 0x%04x, offset %d, len %d, idx %d, phase 0x%02x, pktdata %p, metalen %d\n", + pktid, data_offset, ltoh16(rxcmplt_h->data_len), + rxcmplt_h->cmn_hdr.if_id, rxcmplt_h->cmn_hdr.flags, PKTDATA(dhd->osh, pkt), + ltoh16(rxcmplt_h->metadata_len))); + +#if DHD_DBG_SHOW_METADATA + if (dhd->prot->rx_metadata_offset && rxcmplt_h->metadata_len) { + uchar *ptr; + ptr = PKTDATA(dhd->osh, pkt) - (dhd->prot->rx_metadata_offset); + /* header followed by data */ + bcm_print_bytes("rxmetadata", ptr, rxcmplt_h->metadata_len); + dhd_prot_print_metadata(dhd, ptr, rxcmplt_h->metadata_len); + } +#endif /* DHD_DBG_SHOW_METADATA */ + + if (current_phase != rxcmplt_h->cmn_hdr.flags) { + current_phase = rxcmplt_h->cmn_hdr.flags; + } + if (rxcmplt_h->flags & BCMPCIE_PKT_FLAGS_FRAME_802_11) + DHD_INFO(("D11 frame rxed \n")); + /* data_offset from buf start */ + if (data_offset) { + /* data offset given from dongle after split rx */ + PKTPULL(dhd->osh, pkt, data_offset); /* data offset */ + } else { + /* DMA RX offset updated through shared area */ + if (dhd->prot->rx_dataoffset) + PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset); + } + /* Actual length of the packet */ + PKTSETLEN(dhd->osh, pkt, ltoh16(rxcmplt_h->data_len)); + + ifidx = rxcmplt_h->cmn_hdr.if_id; + +#if defined(PCIE_D2H_SYNC_BZERO) + memset(buf, 0, msglen); +#endif /* PCIE_D2H_SYNC_BZERO */ + +#ifdef DHD_RX_CHAINING + /* Chain the packets */ + dhd_rxchain_frame(dhd, pkt, ifidx); +#else /* ! DHD_RX_CHAINING */ + /* offset from which data starts is populated in rxstatus0 */ + dhd_bus_rx_frame(dhd->bus, pkt, ifidx, 1); +#endif /* ! DHD_RX_CHAINING */ + +} + +/* Stop protocol: sync w/dongle state. */ +void dhd_prot_stop(dhd_pub_t *dhd) +{ + /* nothing to do for pcie */ +} + +/* Add any protocol-specific data header. + * Caller must reserve prot_hdrlen prepend space. + */ +void BCMFASTPATH +dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) +{ + return; +} + +uint +dhd_prot_hdrlen(dhd_pub_t *dhd, void *PKTBUF) +{ + return 0; +} + + +#define PKTBUF pktbuf + +int BCMFASTPATH +dhd_prot_txdata(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) +{ + unsigned long flags; + dhd_prot_t *prot = dhd->prot; + dhd_pktid_map_handle_t *map; + host_txbuf_post_t *txdesc = NULL; + dmaaddr_t physaddr, meta_physaddr; + uint8 *pktdata; + uint32 pktlen; + uint32 pktid; + uint8 prio; + uint16 flowid = 0; + uint16 alloced = 0; + uint16 headroom; + + msgbuf_ring_t *msg_ring; + + if (!dhd->flow_ring_table) { + return BCME_NORESOURCE; + } + + map = dhd->prot->pktid_map_handle; + + if (!dhd_bus_is_txmode_push(dhd->bus)) { + flow_ring_table_t *flow_ring_table; + flow_ring_node_t *flow_ring_node; + + flowid = (uint16)DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(PKTBUF)); + + flow_ring_table = (flow_ring_table_t *)dhd->flow_ring_table; + flow_ring_node = (flow_ring_node_t *)&flow_ring_table[flowid]; + + msg_ring = (msgbuf_ring_t *)flow_ring_node->prot_info; + } else { + msg_ring = prot->h2dring_txp_subn; + } + + + + DHD_GENERAL_LOCK(dhd, flags); + + /* Create a unique 32-bit packet id */ + pktid = NATIVE_TO_PKTID_RSV(map, PKTBUF); + if (pktid == DHD_PKTID_INVALID) { + DHD_ERROR(("Pktid pool depleted.\n")); + /* + * If we return error here, the caller would queue the packet + * again. So we'll just free the skb allocated in DMA Zone. + * Since we have not freed the original SKB yet the caller would + * requeue the same. + */ + goto err_no_res_pktfree; + } + + /* Reserve space in the circular buffer */ + txdesc = (host_txbuf_post_t *)dhd_alloc_ring_space(dhd, + msg_ring, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); + if (txdesc == NULL) { + void *PKTBUF; + DHD_INFO(("%s:%d: HTOD Msgbuf Not available TxCount = %d\n", + __FUNCTION__, __LINE__, prot->active_tx_count)); + /* Free up the PKTID */ + PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, physaddr, + pktlen, BUFF_TYPE_NO_CHECK); + if (!PKTBUF) { + printf("%s: PKT ID invaild. dump dongle memory.\n", __FUNCTION__); + /* write core dump to file */ +#ifdef DHD_FW_COREDUMP + dhdpcie_mem_dump(dhd->bus); +#endif /* DHD_FW_COREDUMP */ + } + goto err_no_res_pktfree; + } + + /* Extract the data pointer and length information */ + pktdata = PKTDATA(dhd->osh, PKTBUF); + pktlen = PKTLEN(dhd->osh, PKTBUF); + + /* Ethernet header: Copy before we cache flush packet using DMA_MAP */ + bcopy(pktdata, txdesc->txhdr, ETHER_HDR_LEN); + + /* Extract the ethernet header and adjust the data pointer and length */ + pktdata = PKTPULL(dhd->osh, PKTBUF, ETHER_HDR_LEN); + pktlen -= ETHER_HDR_LEN; + + /* Map the data pointer to a DMA-able address */ + physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), pktlen, DMA_TX, PKTBUF, 0); + if (PHYSADDRISZERO(physaddr)) { + DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n")); + ASSERT(0); + } + + /* No need to lock. Save the rest of the packet's metadata */ + NATIVE_TO_PKTID_SAVE(map, PKTBUF, pktid, physaddr, pktlen, + DMA_TX, BUFF_TYPE_DATA_TX); + +#ifdef TXP_FLUSH_NITEMS + if (msg_ring->pend_items_count == 0) + msg_ring->start_addr = (void *)txdesc; + msg_ring->pend_items_count++; +#endif + + /* Form the Tx descriptor message buffer */ + + /* Common message hdr */ + txdesc->cmn_hdr.msg_type = MSG_TYPE_TX_POST; + txdesc->cmn_hdr.if_id = ifidx; + txdesc->flags = BCMPCIE_PKT_FLAGS_FRAME_802_3; + prio = (uint8)PKTPRIO(PKTBUF); + + + txdesc->flags |= (prio & 0x7) << BCMPCIE_PKT_FLAGS_PRIO_SHIFT; + txdesc->seg_cnt = 1; + + txdesc->data_len = htol16((uint16)pktlen); + txdesc->data_buf_addr.high_addr = htol32(PHYSADDRHI(physaddr)); + txdesc->data_buf_addr.low_addr = htol32(PHYSADDRLO(physaddr)); + + /* Move data pointer to keep ether header in local PKTBUF for later reference */ + PKTPUSH(dhd->osh, PKTBUF, ETHER_HDR_LEN); + + /* Handle Tx metadata */ + headroom = (uint16)PKTHEADROOM(dhd->osh, PKTBUF); + if (prot->tx_metadata_offset && (headroom < prot->tx_metadata_offset)) + DHD_ERROR(("No headroom for Metadata tx %d %d\n", + prot->tx_metadata_offset, headroom)); + + if (prot->tx_metadata_offset && (headroom >= prot->tx_metadata_offset)) { + DHD_TRACE(("Metadata in tx %d\n", prot->tx_metadata_offset)); + + /* Adjust the data pointer to account for meta data in DMA_MAP */ + PKTPUSH(dhd->osh, PKTBUF, prot->tx_metadata_offset); + meta_physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), + prot->tx_metadata_offset, DMA_RX, PKTBUF, 0); + if (PHYSADDRISZERO(meta_physaddr)) { + DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n")); + ASSERT(0); + } + + /* Adjust the data pointer back to original value */ + PKTPULL(dhd->osh, PKTBUF, prot->tx_metadata_offset); + + txdesc->metadata_buf_len = prot->tx_metadata_offset; + txdesc->metadata_buf_addr.high_addr = htol32(PHYSADDRHI(meta_physaddr)); + txdesc->metadata_buf_addr.low_addr = htol32(PHYSADDRLO(meta_physaddr)); + } + else { + txdesc->metadata_buf_len = htol16(0); + txdesc->metadata_buf_addr.high_addr = 0; + txdesc->metadata_buf_addr.low_addr = 0; + } + +#if defined(DHD_PKTID_AUDIT_RING) + DHD_PKTID_AUDIT(prot->pktid_map_handle, pktid, + DHD_DUPLICATE_ALLOC); +#endif /* DHD_PKTID_AUDIT_RING */ + + txdesc->cmn_hdr.request_id = htol32(pktid); + + DHD_TRACE(("txpost: data_len %d, pktid 0x%04x\n", txdesc->data_len, + txdesc->cmn_hdr.request_id)); + + /* Update the write pointer in TCM & ring bell */ +#ifdef TXP_FLUSH_NITEMS + /* Flush if we have either hit the txp_threshold or if this msg is */ + /* occupying the last slot in the flow_ring - before wrap around. */ + if ((msg_ring->pend_items_count == prot->txp_threshold) || + ((uint8 *) txdesc == (uint8 *) HOST_RING_END(msg_ring))) { + dhd_prot_txdata_write_flush(dhd, flowid, TRUE); + } +#else + prot_ring_write_complete(dhd, msg_ring, txdesc, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); +#endif + + prot->active_tx_count++; + + /* + * Take a wake lock, do not sleep if we have atleast one packet + * to finish. + */ + if (prot->active_tx_count >= 1) + DHD_TXFL_WAKE_LOCK_TIMEOUT(dhd, MAX_TX_TIMEOUT); + + DHD_GENERAL_UNLOCK(dhd, flags); + + return BCME_OK; + +err_no_res_pktfree: + + + + DHD_GENERAL_UNLOCK(dhd, flags); + return BCME_NORESOURCE; + +} + +/* called with a lock */ +void BCMFASTPATH +dhd_prot_txdata_write_flush(dhd_pub_t *dhd, uint16 flowid, bool in_lock) +{ +#ifdef TXP_FLUSH_NITEMS + unsigned long flags = 0; + flow_ring_table_t *flow_ring_table; + flow_ring_node_t *flow_ring_node; + msgbuf_ring_t *msg_ring; + + if (!dhd->flow_ring_table) + return; + + if (!in_lock) { + DHD_GENERAL_LOCK(dhd, flags); + } + + flow_ring_table = (flow_ring_table_t *)dhd->flow_ring_table; + flow_ring_node = (flow_ring_node_t *)&flow_ring_table[flowid]; + msg_ring = (msgbuf_ring_t *)flow_ring_node->prot_info; + + /* Update the write pointer in TCM & ring bell */ + if (msg_ring->pend_items_count) { + prot_ring_write_complete(dhd, msg_ring, msg_ring->start_addr, + msg_ring->pend_items_count); + msg_ring->pend_items_count = 0; + msg_ring->start_addr = NULL; + } + + if (!in_lock) { + DHD_GENERAL_UNLOCK(dhd, flags); + } +#endif /* TXP_FLUSH_NITEMS */ +} + +#undef PKTBUF /* Only defined in the above routine */ +int BCMFASTPATH +dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pkt, uchar *buf, uint *len) +{ + return 0; +} + +static void BCMFASTPATH +dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint16 rxcnt) +{ + dhd_prot_t *prot = dhd->prot; + + if (prot->rxbufpost >= rxcnt) { + prot->rxbufpost -= rxcnt; + } else { + /* ASSERT(0); */ + prot->rxbufpost = 0; + } + + if (prot->rxbufpost <= (prot->max_rxbufpost - RXBUFPOST_THRESHOLD)) + dhd_msgbuf_rxbuf_post(dhd); + + return; +} + + + +/* Use protocol to issue ioctl to dongle */ +int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) +{ + dhd_prot_t *prot = dhd->prot; + int ret = -1; + uint8 action; + + if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + goto done; + } + +#ifdef DHD_USE_IDLECOUNT + if (!bus_wake(dhd->bus)) { + DHD_ERROR(("%s : bus_wake returns 0\n", __FUNCTION__)); + } +#endif /* DHD_USE_IDLECOUNT */ + + if (dhd->busstate == DHD_BUS_SUSPEND) { + DHD_ERROR(("%s : bus is suspended, bus->suspend[%d], bus->host_suspended[%d]\n", + __FUNCTION__, dhd->bus->suspended, dhd->bus->host_suspend)); + goto done; + } + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(len <= WLC_IOCTL_MAXLEN); + + if (len > WLC_IOCTL_MAXLEN) + goto done; + + /* All sanity done ... we either go ahead and run the IOCTL or + * wait for our turn based on the availability of the mutex. + */ + mutex_lock(&prot->ioctl_mutex); + + if (prot->pending == TRUE) { + DHD_ERROR(("packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", + ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, + (unsigned long)prot->lastcmd)); + if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { + DHD_TRACE(("iovar cmd=%s\n", (char*)buf)); + } + /* With mutex in place we should never see this. That is + * we make prot->pending = TRUE only after grabbing the + * mutex, and release the mutex only after making pending + * as FALSE. So there won't be a scenario where we get + * the mutex and find prot->pending as TRUE. Neverthless + * handling this scenario. + */ + mutex_unlock(&prot->ioctl_mutex); + goto done; + } + + prot->pending = TRUE; + prot->lastcmd = ioc->cmd; + action = ioc->set; + + + if (action & WL_IOCTL_ACTION_SET) { + ret = dhd_msgbuf_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); + } else { + ret = dhdmsgbuf_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); + if (ret > 0) + ioc->used = ret; + } + /* Too many programs assume ioctl() returns 0 on success */ + if (ret >= 0) { + ret = 0; + } else { +#ifndef CUSTOMER_HW5 + DHD_ERROR(("%s: status ret value is %d \n", __FUNCTION__, ret)); +#endif /* CUSTOMER_HW5 */ + dhd->dongle_error = ret; + } + + /* Intercept the wme_dp ioctl here */ + if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { + int slen, val = 0; + + slen = strlen("wme_dp") + 1; + if (len >= (int)(slen + sizeof(int))) + bcopy(((char *)buf + slen), &val, sizeof(int)); + dhd->wme_dp = (uint8) ltoh32(val); + } + + + prot->pending = FALSE; + + /* Release the lock if there are other contexts waiting to fire an + * IOCTL, they'll grab this lock and proceed. + */ + mutex_unlock(&prot->ioctl_mutex); +done: + return ret; + +} + +int +dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len) +{ + unsigned long flags; + dhd_prot_t *prot = dhd->prot; + uint16 alloced = 0; + + ioct_reqst_hdr_t *ioct_rqst; + + uint16 hdrlen = sizeof(ioct_reqst_hdr_t); + uint16 msglen = len + hdrlen; + + + if (msglen > MSGBUF_MAX_MSG_SIZE) + msglen = MSGBUF_MAX_MSG_SIZE; + + msglen = align(msglen, DMA_ALIGN_LEN); + + DHD_GENERAL_LOCK(dhd, flags); + ioct_rqst = (ioct_reqst_hdr_t *)dhd_alloc_ring_space(dhd, + prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); + + if (ioct_rqst == NULL) { + DHD_GENERAL_UNLOCK(dhd, flags); + return 0; + } + + { + uint8 *ptr; + uint16 i; + + ptr = (uint8 *)ioct_rqst; + for (i = 0; i < msglen; i++) { + ptr[i] = i % 256; + } + } + + + /* Common msg buf hdr */ + ioct_rqst->msg.msg_type = MSG_TYPE_LOOPBACK; + ioct_rqst->msg.if_id = 0; + + bcm_print_bytes("LPBK REQ: ", (uint8 *)ioct_rqst, msglen); + + /* Update the write pointer in TCM & ring bell */ + prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, ioct_rqst, + DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); + DHD_GENERAL_UNLOCK(dhd, flags); + + return 0; +} + +void dmaxfer_free_dmaaddr(dhd_pub_t *dhd, dhd_dmaxfer_t *dma) +{ + if (dma == NULL) + return; + + if (dma->srcmem.va) { + DMA_FREE_CONSISTENT(dhd->osh, dma->srcmem.va, + dma->len, dma->srcmem.pa, dma->srcmem.dmah); + dma->srcmem.va = NULL; + } + if (dma->destmem.va) { + DMA_FREE_CONSISTENT(dhd->osh, dma->destmem.va, + dma->len + 8, dma->destmem.pa, dma->destmem.dmah); + dma->destmem.va = NULL; + } +} + +int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, + uint srcdelay, uint destdelay, dhd_dmaxfer_t *dma) +{ + uint i; + + if (!dma) + return BCME_ERROR; + + /* First free up exisiting buffers */ + dmaxfer_free_dmaaddr(dhd, dma); + + dma->srcmem.va = DMA_ALLOC_CONSISTENT(dhd->osh, len, DMA_ALIGN_LEN, + &i, &dma->srcmem.pa, &dma->srcmem.dmah); + if (dma->srcmem.va == NULL) { + return BCME_NOMEM; + } + + /* Populate source with a pattern */ + for (i = 0; i < len; i++) { + ((uint8*)dma->srcmem.va)[i] = i % 256; + } + OSL_CACHE_FLUSH(dma->srcmem.va, len); + + dma->destmem.va = DMA_ALLOC_CONSISTENT(dhd->osh, len + 8, DMA_ALIGN_LEN, + &i, &dma->destmem.pa, &dma->destmem.dmah); + if (dma->destmem.va == NULL) { + DMA_FREE_CONSISTENT(dhd->osh, dma->srcmem.va, + dma->len, dma->srcmem.pa, dma->srcmem.dmah); + dma->srcmem.va = NULL; + return BCME_NOMEM; + } + + + /* Clear the destination buffer */ + bzero(dma->destmem.va, len +8); + OSL_CACHE_FLUSH(dma->destmem.va, len+8); + + dma->len = len; + dma->srcdelay = srcdelay; + dma->destdelay = destdelay; + + return BCME_OK; +} + +static void +dhdmsgbuf_dmaxfer_compare(dhd_pub_t *dhd, void * buf, uint16 msglen) +{ + dhd_prot_t *prot = dhd->prot; + + OSL_CACHE_INV(prot->dmaxfer.destmem.va, prot->dmaxfer.len); + if (prot->dmaxfer.srcmem.va && prot->dmaxfer.destmem.va) { + if (memcmp(prot->dmaxfer.srcmem.va, + prot->dmaxfer.destmem.va, + prot->dmaxfer.len)) { + bcm_print_bytes("XFER SRC: ", + prot->dmaxfer.srcmem.va, prot->dmaxfer.len); + bcm_print_bytes("XFER DEST: ", + prot->dmaxfer.destmem.va, prot->dmaxfer.len); + } + else { + DHD_INFO(("DMA successful\n")); + } + } + dmaxfer_free_dmaaddr(dhd, &prot->dmaxfer); + dhd->prot->dmaxfer_in_progress = FALSE; +} + +int +dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd, uint len, uint srcdelay, uint destdelay) +{ + unsigned long flags; + int ret = BCME_OK; + dhd_prot_t *prot = dhd->prot; + pcie_dma_xfer_params_t *dmap; + uint32 xferlen = len > DMA_XFER_LEN_LIMIT ? DMA_XFER_LEN_LIMIT : len; + uint16 msglen = sizeof(pcie_dma_xfer_params_t); + uint16 alloced = 0; + + if (prot->dmaxfer_in_progress) { + DHD_ERROR(("DMA is in progress...\n")); + return ret; + } + prot->dmaxfer_in_progress = TRUE; + if ((ret = dmaxfer_prepare_dmaaddr(dhd, xferlen, srcdelay, destdelay, + &prot->dmaxfer)) != BCME_OK) { + prot->dmaxfer_in_progress = FALSE; + return ret; + } + + + if (msglen > MSGBUF_MAX_MSG_SIZE) + msglen = MSGBUF_MAX_MSG_SIZE; + + msglen = align(msglen, DMA_ALIGN_LEN); + + DHD_GENERAL_LOCK(dhd, flags); + dmap = (pcie_dma_xfer_params_t *)dhd_alloc_ring_space(dhd, + prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); + + if (dmap == NULL) { + dmaxfer_free_dmaaddr(dhd, &prot->dmaxfer); + prot->dmaxfer_in_progress = FALSE; + DHD_GENERAL_UNLOCK(dhd, flags); + return BCME_NOMEM; + } + + /* Common msg buf hdr */ + dmap->cmn_hdr.msg_type = MSG_TYPE_LPBK_DMAXFER; + dmap->cmn_hdr.request_id = 0x1234; + + dmap->host_input_buf_addr.high = htol32(PHYSADDRHI(prot->dmaxfer.srcmem.pa)); + dmap->host_input_buf_addr.low = htol32(PHYSADDRLO(prot->dmaxfer.srcmem.pa)); + dmap->host_ouput_buf_addr.high = htol32(PHYSADDRHI(prot->dmaxfer.destmem.pa)); + dmap->host_ouput_buf_addr.low = htol32(PHYSADDRLO(prot->dmaxfer.destmem.pa)); + dmap->xfer_len = htol32(prot->dmaxfer.len); + dmap->srcdelay = htol32(prot->dmaxfer.srcdelay); + dmap->destdelay = htol32(prot->dmaxfer.destdelay); + + /* Update the write pointer in TCM & ring bell */ + prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, dmap, + DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); + DHD_GENERAL_UNLOCK(dhd, flags); + + DHD_ERROR(("DMA Started...\n")); + + return BCME_OK; +} + +static int +dhdmsgbuf_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) +{ + dhd_prot_t *prot = dhd->prot; + + int ret = 0; + uint copylen = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (cmd == WLC_GET_VAR && buf) + { + if (!len || !*(uint8 *)buf) { + DHD_ERROR(("%s(): Zero length bailing\n", __FUNCTION__)); + ret = BCME_BADARG; + goto done; + } + + /* Respond "bcmerror" and "bcmerrorstr" with local cache */ + copylen = MIN(len, BCME_STRLEN); + + if ((len >= strlen("bcmerrorstr")) && + (!strcmp((char *)buf, "bcmerrorstr"))) { + + strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), copylen); + *(uint8 *)((uint8 *)buf + (copylen - 1)) = '\0'; + + goto done; + } else if ((len >= strlen("bcmerror")) && + !strcmp((char *)buf, "bcmerror")) { + + *(uint32 *)(uint32 *)buf = dhd->dongle_error; + + goto done; + } + } + + ret = dhd_fillup_ioct_reqst_ptrbased(dhd, (uint16)len, cmd, buf, ifidx); + if (ret < 0) { + DHD_ERROR(("%s : dhd_fillup_ioct_reqst_ptrbased error : %d\n", __FUNCTION__, ret)); + return ret; + } + + DHD_INFO(("ACTION %d ifdix %d cmd %d len %d \n", + action, ifidx, cmd, len)); + + /* wait for interrupt and get first fragment */ + ret = dhdmsgbuf_cmplt(dhd, prot->reqid, len, buf, prot->retbuf.va); + +done: + return ret; +} +static int +dhdmsgbuf_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len, void* buf, void* retbuf) +{ + dhd_prot_t *prot = dhd->prot; + ioctl_comp_resp_msg_t ioct_resp; + void* pkt = NULL; + int retlen; + int msgbuf_len = 0; + int post_cnt = 0; + unsigned long flags; + bool zero_posted = FALSE; + uint32 pktid; + int ret = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); + ret = -1; + goto out; + } + + if (prot->cur_ioctlresp_bufs_posted) + prot->cur_ioctlresp_bufs_posted--; + else + zero_posted = TRUE; + + post_cnt = dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd); + if (zero_posted && (post_cnt <= 0)) { + ret = -1; + goto out; + } + + memset(&ioct_resp, 0, sizeof(ioctl_comp_resp_msg_t)); + + retlen = dhd_bus_rxctl(dhd->bus, (uchar*)&ioct_resp, msgbuf_len); + if (retlen <= 0) { + DHD_ERROR(("IOCTL request failed with error code %d\n", retlen)); + ret = retlen; + goto out; + } + + pktid = ioct_resp.cmn_hdr.request_id; /* no need for ltoh32 */ + +#if defined(DHD_PKTID_AUDIT_RING) + DHD_PKTID_AUDIT(prot->pktid_map_handle, pktid, DHD_DUPLICATE_FREE); +#endif /* DHD_PKTID_AUDIT_RING */ + + DHD_INFO(("ioctl resp retlen %d status %d, resp_len %d, pktid %d\n", + retlen, ioct_resp.compl_hdr.status, ioct_resp.resp_len, pktid)); + if (ioct_resp.resp_len != 0) { + DHD_GENERAL_LOCK(dhd, flags); + pkt = dhd_prot_packet_get(dhd, pktid, BUFF_TYPE_IOCTL_RX); + DHD_GENERAL_UNLOCK(dhd, flags); + + DHD_INFO(("ioctl ret buf %p retlen %d status %x \n", pkt, retlen, + ioct_resp.compl_hdr.status)); + /* get ret buf */ + if ((buf) && (pkt)) { + /* bcopy(PKTDATA(dhd->osh, pkt), buf, ioct_resp.resp_len); */ + /* ioct_resp.resp_len could have been changed to make it > 8 bytes */ + bcopy(PKTDATA(dhd->osh, pkt), buf, len); + } + if (pkt) { +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_IOCTLBUF) + PKTFREE_STATIC(dhd->osh, pkt, FALSE); +#else + PKTFREE(dhd->osh, pkt, FALSE); +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTLBUF */ + } + } else { + DHD_GENERAL_LOCK(dhd, flags); + dhd_prot_packet_free(dhd, pktid, BUFF_TYPE_IOCTL_RX); + DHD_GENERAL_UNLOCK(dhd, flags); + } + + ret = (int)(ioct_resp.compl_hdr.status); + +out: + DHD_GENERAL_LOCK(dhd, flags); + dhd->ioctl_state = 0; + DHD_GENERAL_UNLOCK(dhd, flags); + + return ret; +} +static int +dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) +{ + dhd_prot_t *prot = dhd->prot; + + int ret = 0; + + DHD_TRACE(("%s: Enter \n", __FUNCTION__)); + DHD_TRACE(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); + + if (dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + return -EIO; + } + + /* don't talk to the dongle if fw is about to be reloaded */ + if (dhd->hang_was_sent) { + DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", + __FUNCTION__)); + return -EIO; + } + + /* Fill up msgbuf for ioctl req */ + ret = dhd_fillup_ioct_reqst_ptrbased(dhd, (uint16)len, cmd, buf, ifidx); + if (ret < 0) { + DHD_ERROR(("%s : dhd_fillup_ioct_reqst_ptrbased error : %d\n", __FUNCTION__, ret)); + return ret; + } + + DHD_INFO(("ACTIOn %d ifdix %d cmd %d len %d \n", + action, ifidx, cmd, len)); + + ret = dhdmsgbuf_cmplt(dhd, prot->reqid, len, buf, prot->retbuf.va); + + return ret; +} +/* Handles a protocol control response asynchronously */ +int dhd_prot_ctl_complete(dhd_pub_t *dhd) +{ + return 0; +} + +/* Check for and handle local prot-specific iovar commands */ +int dhd_prot_iovar_op(dhd_pub_t *dhd, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + return BCME_UNSUPPORTED; +} + +/* Add prot dump output to a buffer */ +void dhd_prot_dump(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) +{ +#if defined(PCIE_D2H_SYNC) + if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM) + bcm_bprintf(strbuf, "\nd2h_sync: SEQNUM:"); + else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM) + bcm_bprintf(strbuf, "\nd2h_sync: XORCSUM:"); + else + bcm_bprintf(strbuf, "\nd2h_sync: NONE:"); + bcm_bprintf(strbuf, " d2h_sync_wait max<%lu> tot<%lu>\n", + dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot); +#endif /* PCIE_D2H_SYNC */ +} + +/* Update local copy of dongle statistics */ +void dhd_prot_dstats(dhd_pub_t *dhd) +{ + return; +} + +int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, + uint reorder_info_len, void **pkt, uint32 *free_buf_count) +{ + return 0; +} +/* post a dummy message to interrupt dongle */ +/* used to process cons commands */ +int +dhd_post_dummy_msg(dhd_pub_t *dhd) +{ + unsigned long flags; + hostevent_hdr_t *hevent = NULL; + uint16 alloced = 0; + + dhd_prot_t *prot = dhd->prot; + + DHD_GENERAL_LOCK(dhd, flags); + hevent = (hostevent_hdr_t *)dhd_alloc_ring_space(dhd, + prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); + + if (hevent == NULL) { + DHD_GENERAL_UNLOCK(dhd, flags); + return -1; + } + + /* CMN msg header */ + hevent->msg.msg_type = MSG_TYPE_HOST_EVNT; + hevent->msg.if_id = 0; + + /* Event payload */ + hevent->evnt_pyld = htol32(HOST_EVENT_CONS_CMD); + + /* Since, we are filling the data directly into the bufptr obtained + * from the msgbuf, we can directly call the write_complete + */ + prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, hevent, + DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); + DHD_GENERAL_UNLOCK(dhd, flags); + + return 0; +} + +static void * BCMFASTPATH +dhd_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced) +{ + void * ret_buf; + uint16 r_index = 0; + + /* Alloc space for nitems in the ring */ + ret_buf = prot_get_ring_space(ring, nitems, alloced); + + if (ret_buf == NULL) { + /* if alloc failed , invalidate cached read ptr */ + if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) { + r_index = dhd_get_dmaed_index(dhd, H2D_DMA_READINDX, ring->idx); + ring->ringstate->r_offset = r_index; + } else + dhd_bus_cmn_readshared(dhd->bus, &(RING_READ_PTR(ring)), + RING_READ_PTR, ring->idx); + + /* Try allocating once more */ + ret_buf = prot_get_ring_space(ring, nitems, alloced); + + if (ret_buf == NULL) { + DHD_INFO(("RING space not available on ring %s for %d items \n", + ring->name, nitems)); + DHD_INFO(("write %d read %d \n\n", RING_WRITE_PTR(ring), + RING_READ_PTR(ring))); + return NULL; + } + } + + /* Return alloced space */ + return ret_buf; +} + +/* Non inline ioct request */ +/* Form a ioctl request first as per ioctptr_reqst_hdr_t header in the circular buffer */ +/* Form a separate request buffer where a 4 byte cmn header is added in the front */ +/* buf contents from parent function is copied to remaining section of this buffer */ +static int +dhd_fillup_ioct_reqst_ptrbased(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx) +{ + dhd_prot_t *prot = dhd->prot; + ioctl_req_msg_t *ioct_rqst; + void * ioct_buf; /* For ioctl payload */ + uint16 rqstlen, resplen; + unsigned long flags; + uint16 alloced = 0; + + rqstlen = len; + resplen = len; + + /* Limit ioct request to MSGBUF_MAX_MSG_SIZE bytes including hdrs */ + /* 8K allocation of dongle buffer fails */ + /* dhd doesnt give separate input & output buf lens */ + /* so making the assumption that input length can never be more than 1.5k */ + rqstlen = MIN(rqstlen, MSGBUF_MAX_MSG_SIZE); + + DHD_GENERAL_LOCK(dhd, flags); + + if (dhd->ioctl_state) { + DHD_ERROR(("%s: pending ioctl %02x\n", __FUNCTION__, dhd->ioctl_state)); + DHD_GENERAL_UNLOCK(dhd, flags); + return BCME_BUSY; + } else { + dhd->ioctl_state = MSGBUF_IOCTL_ACK_PENDING | MSGBUF_IOCTL_RESP_PENDING; + } + + /* Request for cbuf space */ + ioct_rqst = (ioctl_req_msg_t*)dhd_alloc_ring_space(dhd, prot->h2dring_ctrl_subn, + DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); + if (ioct_rqst == NULL) { + dhd->ioctl_state = 0; + DHD_ERROR(("couldn't allocate space on msgring to send ioctl request\n")); + DHD_GENERAL_UNLOCK(dhd, flags); + return -1; + } + + /* Common msg buf hdr */ + ioct_rqst->cmn_hdr.msg_type = MSG_TYPE_IOCTLPTR_REQ; + ioct_rqst->cmn_hdr.if_id = (uint8)ifidx; + ioct_rqst->cmn_hdr.flags = 0; + ioct_rqst->cmn_hdr.request_id = DHD_IOCTL_REQ_PKTID; + + ioct_rqst->cmd = htol32(cmd); + ioct_rqst->output_buf_len = htol16(resplen); + ioct_rqst->trans_id = prot->ioctl_trans_id ++; + + /* populate ioctl buffer info */ + ioct_rqst->input_buf_len = htol16(rqstlen); + ioct_rqst->host_input_buf_addr.high = htol32(PHYSADDRHI(prot->ioctbuf.pa)); + ioct_rqst->host_input_buf_addr.low = htol32(PHYSADDRLO(prot->ioctbuf.pa)); + /* copy ioct payload */ + ioct_buf = (void *) prot->ioctbuf.va; + + if (buf) + memcpy(ioct_buf, buf, len); + + OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, len); + + if ((ulong)ioct_buf % DMA_ALIGN_LEN) + DHD_ERROR(("host ioct address unaligned !!!!! \n")); + + DHD_CTL(("submitted IOCTL request request_id %d, cmd %d, output_buf_len %d, tx_id %d\n", + ioct_rqst->cmn_hdr.request_id, cmd, ioct_rqst->output_buf_len, + ioct_rqst->trans_id)); + + /* upd wrt ptr and raise interrupt */ + prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, ioct_rqst, + DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); + DHD_GENERAL_UNLOCK(dhd, flags); + + return 0; +} + +/* Packet to PacketID mapper */ +typedef struct { + ulong native; + dmaaddr_t pa; + uint32 pa_len; + uchar dma; +} pktid_t; + +typedef struct { + void *osh; + void *mwbmap_hdl; + pktid_t *pktid_list; + uint32 count; +} pktid_map_t; + + +void *pktid_map_init(void *osh, uint32 count) +{ + pktid_map_t *handle; + + handle = (pktid_map_t *) MALLOC(osh, sizeof(pktid_map_t)); + if (handle == NULL) { + printf("%s:%d: MALLOC failed for size %d\n", + __FUNCTION__, __LINE__, (uint32) sizeof(pktid_map_t)); + return NULL; + } + handle->osh = osh; + handle->count = count; + handle->mwbmap_hdl = bcm_mwbmap_init(osh, count); + if (handle->mwbmap_hdl == NULL) { + printf("%s:%d: bcm_mwbmap_init failed for count %d\n", + __FUNCTION__, __LINE__, count); + MFREE(osh, handle, sizeof(pktid_map_t)); + return NULL; + } + + handle->pktid_list = (pktid_t *) MALLOC(osh, sizeof(pktid_t) * (count+1)); + if (handle->pktid_list == NULL) { + printf("%s:%d: MALLOC failed for count %d / total = %d\n", + __FUNCTION__, __LINE__, count, (uint32) sizeof(pktid_t) * count); + bcm_mwbmap_fini(osh, handle->mwbmap_hdl); + MFREE(osh, handle, sizeof(pktid_map_t)); + return NULL; + } + + return handle; +} + +void +pktid_map_uninit(void *pktid_map_handle) +{ + pktid_map_t *handle = (pktid_map_t *) pktid_map_handle; + uint32 ix; + + if (handle != NULL) { + void *osh = handle->osh; + for (ix = 0; ix < MAX_PKTID_ITEMS; ix++) + { + if (!bcm_mwbmap_isfree(handle->mwbmap_hdl, ix)) { + /* Mark the slot as free */ + bcm_mwbmap_free(handle->mwbmap_hdl, ix); + /* + Here we can do dma unmapping for 32 bit also. + Since this in removal path, it will not affect performance + */ + DMA_UNMAP(osh, handle->pktid_list[ix+1].pa, + (uint) handle->pktid_list[ix+1].pa_len, + handle->pktid_list[ix+1].dma, 0, 0); + PKTFREE(osh, (unsigned long*)handle->pktid_list[ix+1].native, TRUE); + } + } + bcm_mwbmap_fini(osh, handle->mwbmap_hdl); + MFREE(osh, handle->pktid_list, sizeof(pktid_t) * (handle->count+1)); + MFREE(osh, handle, sizeof(pktid_map_t)); + } + return; +} + +uint32 BCMFASTPATH +pktid_map_unique(void *pktid_map_handle, void *pkt, dmaaddr_t physaddr, uint32 physlen, uint32 dma) +{ + uint32 id; + pktid_map_t *handle = (pktid_map_t *) pktid_map_handle; + + if (handle == NULL) { + printf("%s:%d: Error !!! pktid_map_unique called without initing pktid_map\n", + __FUNCTION__, __LINE__); + return 0; + } + id = bcm_mwbmap_alloc(handle->mwbmap_hdl); + if (id == BCM_MWBMAP_INVALID_IDX) { + printf("%s:%d: bcm_mwbmap_alloc failed. Free Count = %d\n", + __FUNCTION__, __LINE__, bcm_mwbmap_free_cnt(handle->mwbmap_hdl)); + return 0; + } + + /* id=0 is invalid as we use this for error checking in the dongle */ + id += 1; + handle->pktid_list[id].native = (ulong) pkt; + handle->pktid_list[id].pa = physaddr; + handle->pktid_list[id].pa_len = (uint32) physlen; + handle->pktid_list[id].dma = (uchar)dma; + + return id; +} + +void * BCMFASTPATH +pktid_get_packet(void *pktid_map_handle, uint32 id, dmaaddr_t *physaddr, uint32 *physlen) +{ + void *native = NULL; + pktid_map_t *handle = (pktid_map_t *) pktid_map_handle; + if (handle == NULL) { + printf("%s:%d: Error !!! pktid_get_packet called without initing pktid_map\n", + __FUNCTION__, __LINE__); + return NULL; + } + + /* Debug check */ + if (bcm_mwbmap_isfree(handle->mwbmap_hdl, (id-1))) { + printf("%s:%d: Error !!!. slot (%d/0x%04x) free but the app is using it.\n", + __FUNCTION__, __LINE__, (id-1), (id-1)); + return NULL; + } + + native = (void *) handle->pktid_list[id].native; + *physaddr = handle->pktid_list[id].pa; + *physlen = (uint32) handle->pktid_list[id].pa_len; + + /* Mark the slot as free */ + bcm_mwbmap_free(handle->mwbmap_hdl, (id-1)); + + return native; +} +static msgbuf_ring_t* +prot_ring_attach(dhd_prot_t * prot, char* name, uint16 max_item, uint16 len_item, uint16 ringid) +{ + uint alloced = 0; + msgbuf_ring_t *ring; + dmaaddr_t physaddr; + uint16 size; + + ASSERT(name); + BCM_REFERENCE(physaddr); + + /* allocate ring info */ + ring = MALLOC(prot->osh, sizeof(msgbuf_ring_t)); + if (ring == NULL) { + ASSERT(0); + return NULL; + } + bzero(ring, sizeof(*ring)); + + /* Init name */ + strncpy(ring->name, name, sizeof(ring->name) - 1); + + /* Ringid in the order given in bcmpcie.h */ + ring->idx = ringid; + + /* init ringmem */ + ring->ringmem = MALLOC(prot->osh, sizeof(ring_mem_t)); + if (ring->ringmem == NULL) + goto fail; + bzero(ring->ringmem, sizeof(*ring->ringmem)); + + ring->ringmem->max_item = max_item; + ring->ringmem->len_items = len_item; + size = max_item * len_item; + + /* Ring Memmory allocation */ + ring->ring_base.va = DMA_ALLOC_CONSISTENT(prot->osh, size, DMA_ALIGN_LEN, + &alloced, &ring->ring_base.pa, &ring->ring_base.dmah); + + if (ring->ring_base.va == NULL) + goto fail; + ring->ringmem->base_addr.high_addr = htol32(PHYSADDRHI(ring->ring_base.pa)); + ring->ringmem->base_addr.low_addr = htol32(PHYSADDRLO(ring->ring_base.pa)); + + ASSERT(MODX((unsigned long)ring->ring_base.va, DMA_ALIGN_LEN) == 0); + bzero(ring->ring_base.va, size); + + OSL_CACHE_FLUSH((void *) ring->ring_base.va, size); + + /* Ring state init */ + ring->ringstate = MALLOC(prot->osh, sizeof(ring_state_t)); + if (ring->ringstate == NULL) + goto fail; + bzero(ring->ringstate, sizeof(*ring->ringstate)); + + DHD_INFO(("RING_ATTACH : %s Max item %d len item %d total size %d " + "ring start %p buf phys addr %x:%x \n", + ring->name, ring->ringmem->max_item, ring->ringmem->len_items, + size, ring->ring_base.va, ring->ringmem->base_addr.high_addr, + ring->ringmem->base_addr.low_addr)); + return ring; +fail: + if (ring->ring_base.va && ring->ringmem) { + PHYSADDRHISET(physaddr, ring->ringmem->base_addr.high_addr); + PHYSADDRLOSET(physaddr, ring->ringmem->base_addr.low_addr); + size = ring->ringmem->max_item * ring->ringmem->len_items; + DMA_FREE_CONSISTENT(prot->osh, ring->ring_base.va, size, ring->ring_base.pa, NULL); + ring->ring_base.va = NULL; + } + if (ring->ringmem) + MFREE(prot->osh, ring->ringmem, sizeof(ring_mem_t)); + MFREE(prot->osh, ring, sizeof(msgbuf_ring_t)); + ASSERT(0); + return NULL; +} +static void +dhd_ring_init(dhd_pub_t *dhd, msgbuf_ring_t *ring) +{ + /* update buffer address of ring */ + dhd_bus_cmn_writeshared(dhd->bus, &ring->ringmem->base_addr, + sizeof(ring->ringmem->base_addr), RING_BUF_ADDR, ring->idx); + + /* Update max items possible in ring */ + dhd_bus_cmn_writeshared(dhd->bus, &ring->ringmem->max_item, + sizeof(ring->ringmem->max_item), RING_MAX_ITEM, ring->idx); + + /* Update length of each item in the ring */ + dhd_bus_cmn_writeshared(dhd->bus, &ring->ringmem->len_items, + sizeof(ring->ringmem->len_items), RING_LEN_ITEMS, ring->idx); + + /* ring inited */ + ring->inited = TRUE; +} +static void +dhd_prot_ring_detach(dhd_pub_t *dhd, msgbuf_ring_t * ring) +{ + dmaaddr_t phyaddr; + uint16 size; + dhd_prot_t *prot = dhd->prot; + + BCM_REFERENCE(phyaddr); + + if (ring == NULL) + return; + + + if (ring->ringmem == NULL) { + DHD_ERROR(("%s: ring->ringmem is NULL\n", __FUNCTION__)); + return; + } + + ring->inited = FALSE; + + PHYSADDRHISET(phyaddr, ring->ringmem->base_addr.high_addr); + PHYSADDRLOSET(phyaddr, ring->ringmem->base_addr.low_addr); + size = ring->ringmem->max_item * ring->ringmem->len_items; + /* Free up ring */ + if (ring->ring_base.va) { + DMA_FREE_CONSISTENT(prot->osh, ring->ring_base.va, size, ring->ring_base.pa, + ring->ring_base.dmah); + ring->ring_base.va = NULL; + } + + /* Free up ring mem space */ + if (ring->ringmem) { + MFREE(prot->osh, ring->ringmem, sizeof(ring_mem_t)); + ring->ringmem = NULL; + } + + /* Free up ring state info */ + if (ring->ringstate) { + MFREE(prot->osh, ring->ringstate, sizeof(ring_state_t)); + ring->ringstate = NULL; + } + + /* free up ring info */ + MFREE(prot->osh, ring, sizeof(msgbuf_ring_t)); +} +/* Assumes only one index is updated ata time */ +static void *BCMFASTPATH +prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced) +{ + void *ret_ptr = NULL; + uint16 ring_avail_cnt; + + ASSERT(nitems <= RING_MAX_ITEM(ring)); + + ring_avail_cnt = CHECK_WRITE_SPACE(RING_READ_PTR(ring), RING_WRITE_PTR(ring), + RING_MAX_ITEM(ring)); + + if (ring_avail_cnt == 0) { + return NULL; + } + *alloced = MIN(nitems, ring_avail_cnt); + + /* Return next available space */ + ret_ptr = (char*)HOST_RING_BASE(ring) + (RING_WRITE_PTR(ring) * RING_LEN_ITEMS(ring)); + + /* Update write pointer */ + if ((RING_WRITE_PTR(ring) + *alloced) == RING_MAX_ITEM(ring)) + RING_WRITE_PTR(ring) = 0; + else if ((RING_WRITE_PTR(ring) + *alloced) < RING_MAX_ITEM(ring)) + RING_WRITE_PTR(ring) += *alloced; + else { + /* Should never hit this */ + ASSERT(0); + return NULL; + } + + return ret_ptr; +} + +static void BCMFASTPATH +prot_ring_write_complete(dhd_pub_t *dhd, msgbuf_ring_t * ring, void* p, uint16 nitems) +{ + dhd_prot_t *prot = dhd->prot; + + /* cache flush */ + OSL_CACHE_FLUSH(p, RING_LEN_ITEMS(ring) * nitems); + + /* update write pointer */ + /* If dma'ing h2d indices are supported + * update the values in the host memory + * o/w update the values in TCM + */ + if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) + dhd_set_dmaed_index(dhd, H2D_DMA_WRITEINDX, + ring->idx, (uint16)RING_WRITE_PTR(ring)); + else + dhd_bus_cmn_writeshared(dhd->bus, &(RING_WRITE_PTR(ring)), + sizeof(uint16), RING_WRITE_PTR, ring->idx); + + /* raise h2d interrupt */ + prot->mb_ring_fn(dhd->bus, RING_WRITE_PTR(ring)); +} + +/* If dma'ing h2d indices are supported + * this function updates the indices in + * the host memory + */ +static void +dhd_set_dmaed_index(dhd_pub_t *dhd, uint8 type, uint16 ringid, uint16 new_index) +{ + dhd_prot_t *prot = dhd->prot; + + uint32 *ptr = NULL; + uint16 offset = 0; + + switch (type) { + case H2D_DMA_WRITEINDX: + ptr = (uint32 *)(prot->h2d_dma_writeindx_buf.va); + + /* Flow-Rings start at Id BCMPCIE_COMMON_MSGRINGS + * but in host memory their indices start + * after H2D Common Rings + */ + if (ringid >= BCMPCIE_COMMON_MSGRINGS) + offset = ringid - BCMPCIE_COMMON_MSGRINGS + + BCMPCIE_H2D_COMMON_MSGRINGS; + else + offset = ringid; + ptr += offset; + + *ptr = htol16(new_index); + + /* cache flush */ + OSL_CACHE_FLUSH((void *)prot->h2d_dma_writeindx_buf.va, + prot->h2d_dma_writeindx_buf_len); + + break; + + case D2H_DMA_READINDX: + ptr = (uint32 *)(prot->d2h_dma_readindx_buf.va); + + /* H2D Common Righs start at Id BCMPCIE_H2D_COMMON_MSGRINGS */ + offset = ringid - BCMPCIE_H2D_COMMON_MSGRINGS; + ptr += offset; + + *ptr = htol16(new_index); + /* cache flush */ + OSL_CACHE_FLUSH((void *)prot->d2h_dma_readindx_buf.va, + prot->d2h_dma_readindx_buf_len); + + break; + + default: + DHD_ERROR(("%s: Invalid option for DMAing read/write index\n", + __FUNCTION__)); + + break; + } + DHD_TRACE(("%s: Data 0x%p, ringId %d, new_index %d\n", + __FUNCTION__, ptr, ringid, new_index)); +} + + +static uint16 +dhd_get_dmaed_index(dhd_pub_t *dhd, uint8 type, uint16 ringid) +{ + uint32 *ptr = NULL; + uint16 data = 0; + uint16 offset = 0; + + switch (type) { + case H2D_DMA_WRITEINDX: + OSL_CACHE_INV((void *)dhd->prot->h2d_dma_writeindx_buf.va, + dhd->prot->h2d_dma_writeindx_buf_len); + ptr = (uint32 *)(dhd->prot->h2d_dma_writeindx_buf.va); + + /* Flow-Rings start at Id BCMPCIE_COMMON_MSGRINGS + * but in host memory their indices start + * after H2D Common Rings + */ + if (ringid >= BCMPCIE_COMMON_MSGRINGS) + offset = ringid - BCMPCIE_COMMON_MSGRINGS + + BCMPCIE_H2D_COMMON_MSGRINGS; + else + offset = ringid; + ptr += offset; + + data = LTOH16((uint16)*ptr); + break; + + case H2D_DMA_READINDX: + OSL_CACHE_INV((void *)dhd->prot->h2d_dma_readindx_buf.va, + dhd->prot->h2d_dma_readindx_buf_len); + ptr = (uint32 *)(dhd->prot->h2d_dma_readindx_buf.va); + + /* Flow-Rings start at Id BCMPCIE_COMMON_MSGRINGS + * but in host memory their indices start + * after H2D Common Rings + */ + if (ringid >= BCMPCIE_COMMON_MSGRINGS) + offset = ringid - BCMPCIE_COMMON_MSGRINGS + + BCMPCIE_H2D_COMMON_MSGRINGS; + else + offset = ringid; + ptr += offset; + + data = LTOH16((uint16)*ptr); + break; + + case D2H_DMA_WRITEINDX: + OSL_CACHE_INV((void *)dhd->prot->d2h_dma_writeindx_buf.va, + dhd->prot->d2h_dma_writeindx_buf_len); + ptr = (uint32 *)(dhd->prot->d2h_dma_writeindx_buf.va); + + /* H2D Common Righs start at Id BCMPCIE_H2D_COMMON_MSGRINGS */ + offset = ringid - BCMPCIE_H2D_COMMON_MSGRINGS; + ptr += offset; + + data = LTOH16((uint16)*ptr); + break; + + case D2H_DMA_READINDX: + OSL_CACHE_INV((void *)dhd->prot->d2h_dma_readindx_buf.va, + dhd->prot->d2h_dma_readindx_buf_len); + ptr = (uint32 *)(dhd->prot->d2h_dma_readindx_buf.va); + + /* H2D Common Righs start at Id BCMPCIE_H2D_COMMON_MSGRINGS */ + offset = ringid - BCMPCIE_H2D_COMMON_MSGRINGS; + ptr += offset; + + data = LTOH16((uint16)*ptr); + break; + + default: + DHD_ERROR(("%s: Invalid option for DMAing read/write index\n", + __FUNCTION__)); + + break; + } + DHD_TRACE(("%s: Data 0x%p, data %d\n", __FUNCTION__, ptr, data)); + return (data); +} + +/* D2H dircetion: get next space to read from */ +static uint8* +prot_get_src_addr(dhd_pub_t *dhd, msgbuf_ring_t * ring, uint16* available_len) +{ + uint16 w_ptr; + uint16 r_ptr; + uint16 depth; + void* ret_addr = NULL; + uint16 d2h_w_index = 0; + + DHD_TRACE(("%s: h2d_dma_readindx_buf %p, d2h_dma_writeindx_buf %p\n", + __FUNCTION__, (uint32 *)(dhd->prot->h2d_dma_readindx_buf.va), + (uint32 *)(dhd->prot->d2h_dma_writeindx_buf.va))); + + /* update write pointer */ + if (DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support)) { + /* DMAing write/read indices supported */ + d2h_w_index = dhd_get_dmaed_index(dhd, D2H_DMA_WRITEINDX, ring->idx); + ring->ringstate->w_offset = d2h_w_index; + } else + dhd_bus_cmn_readshared(dhd->bus, + &(RING_WRITE_PTR(ring)), RING_WRITE_PTR, ring->idx); + + w_ptr = ring->ringstate->w_offset; + r_ptr = ring->ringstate->r_offset; + depth = ring->ringmem->max_item; + + /* check for avail space */ + *available_len = READ_AVAIL_SPACE(w_ptr, r_ptr, depth); + if (*available_len == 0) + return NULL; + + if (*available_len > ring->ringmem->max_item) { + DHD_ERROR(("%s: *available_len %d, ring->ringmem->max_item %d\n", + __FUNCTION__, *available_len, ring->ringmem->max_item)); + return NULL; + } + + /* if space available, calculate address to be read */ + ret_addr = (char*)ring->ring_base.va + (r_ptr * ring->ringmem->len_items); + + /* update read pointer */ + if ((ring->ringstate->r_offset + *available_len) >= ring->ringmem->max_item) + ring->ringstate->r_offset = 0; + else + ring->ringstate->r_offset += *available_len; + + ASSERT(ring->ringstate->r_offset < ring->ringmem->max_item); + + /* convert index to bytes */ + *available_len = *available_len * ring->ringmem->len_items; + + /* Cache invalidate */ + OSL_CACHE_INV((void *) ret_addr, *available_len); + + /* return read address */ + return ret_addr; +} +static void +prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) +{ + /* update read index */ + /* If dma'ing h2d indices supported + * update the r -indices in the + * host memory o/w in TCM + */ + if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) + dhd_set_dmaed_index(dhd, D2H_DMA_READINDX, + ring->idx, (uint16)RING_READ_PTR(ring)); + else + dhd_bus_cmn_writeshared(dhd->bus, &(RING_READ_PTR(ring)), + sizeof(uint16), RING_READ_PTR, ring->idx); +} + +static void +prot_store_rxcpln_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) +{ + dhd_prot_t *prot; + + if (!dhd || !dhd->prot) + return; + + prot = dhd->prot; + prot->rx_cpln_early_upd_idx = RING_READ_PTR(ring); +} + +static void +prot_early_upd_rxcpln_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) +{ + dhd_prot_t *prot; + + if (!dhd || !dhd->prot) + return; + + prot = dhd->prot; + + if (prot->rx_cpln_early_upd_idx == RING_READ_PTR(ring)) + return; + + if (++prot->rx_cpln_early_upd_idx >= RING_MAX_ITEM(ring)) + prot->rx_cpln_early_upd_idx = 0; + + if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) + dhd_set_dmaed_index(dhd, D2H_DMA_READINDX, + ring->idx, (uint16)prot->rx_cpln_early_upd_idx); + else + dhd_bus_cmn_writeshared(dhd->bus, &(prot->rx_cpln_early_upd_idx), + sizeof(uint16), RING_READ_PTR, ring->idx); +} + +int +dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) +{ + tx_flowring_create_request_t *flow_create_rqst; + msgbuf_ring_t *msgbuf_flow_info; + dhd_prot_t *prot = dhd->prot; + uint16 hdrlen = sizeof(tx_flowring_create_request_t); + uint16 msglen = hdrlen; + unsigned long flags; + uint16 alloced = 0; + + if (!(msgbuf_flow_info = prot_ring_attach(prot, "h2dflr", + H2DRING_TXPOST_MAX_ITEM, H2DRING_TXPOST_ITEMSIZE, + BCMPCIE_H2D_TXFLOWRINGID + + (flow_ring_node->flowid - BCMPCIE_H2D_COMMON_MSGRINGS)))) { + DHD_ERROR(("%s: kmalloc for H2D TX Flow ring failed\n", __FUNCTION__)); + return BCME_NOMEM; + } + /* Clear write pointer of the ring */ + flow_ring_node->prot_info = (void *)msgbuf_flow_info; + + /* align it to 4 bytes, so that all start addr form cbuf is 4 byte aligned */ + msglen = align(msglen, DMA_ALIGN_LEN); + + + DHD_GENERAL_LOCK(dhd, flags); + /* Request for ring buffer space */ + flow_create_rqst = (tx_flowring_create_request_t *)dhd_alloc_ring_space(dhd, + prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); + + if (flow_create_rqst == NULL) { + DHD_ERROR(("%s: No space in control ring for Flow create req\n", __FUNCTION__)); + DHD_GENERAL_UNLOCK(dhd, flags); + return BCME_NOMEM; + } + msgbuf_flow_info->inited = TRUE; + + /* Common msg buf hdr */ + flow_create_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_CREATE; + flow_create_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; + flow_create_rqst->msg.request_id = htol16(0); /* TBD */ + + /* Update flow create message */ + flow_create_rqst->tid = flow_ring_node->flow_info.tid; + flow_create_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); + memcpy(flow_create_rqst->sa, flow_ring_node->flow_info.sa, sizeof(flow_create_rqst->sa)); + memcpy(flow_create_rqst->da, flow_ring_node->flow_info.da, sizeof(flow_create_rqst->da)); + flow_create_rqst->flow_ring_ptr.low_addr = msgbuf_flow_info->ringmem->base_addr.low_addr; + flow_create_rqst->flow_ring_ptr.high_addr = msgbuf_flow_info->ringmem->base_addr.high_addr; + flow_create_rqst->max_items = htol16(H2DRING_TXPOST_MAX_ITEM); + flow_create_rqst->len_item = htol16(H2DRING_TXPOST_ITEMSIZE); + DHD_ERROR(("%s Send Flow create Req msglen flow ID %d for peer " MACDBG + " prio %d ifindex %d\n", __FUNCTION__, flow_ring_node->flowid, + MAC2STRDBG(flow_ring_node->flow_info.da), flow_ring_node->flow_info.tid, + flow_ring_node->flow_info.ifindex)); + + /* upd wrt ptr and raise interrupt */ + prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, flow_create_rqst, + DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); + + /* If dma'ing indices supported + * update the w-index in host memory o/w in TCM + */ + if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) + dhd_set_dmaed_index(dhd, H2D_DMA_WRITEINDX, + msgbuf_flow_info->idx, (uint16)RING_WRITE_PTR(msgbuf_flow_info)); + else + dhd_bus_cmn_writeshared(dhd->bus, &(RING_WRITE_PTR(msgbuf_flow_info)), + sizeof(uint16), RING_WRITE_PTR, msgbuf_flow_info->idx); + DHD_GENERAL_UNLOCK(dhd, flags); + + return BCME_OK; +} + +static void +dhd_prot_process_flow_ring_create_response(dhd_pub_t *dhd, void* buf, uint16 msglen) +{ + tx_flowring_create_response_t *flow_create_resp = (tx_flowring_create_response_t *)buf; + + DHD_ERROR(("%s Flow create Response status = %d Flow %d\n", __FUNCTION__, + flow_create_resp->cmplt.status, flow_create_resp->cmplt.flow_ring_id)); + + dhd_bus_flow_ring_create_response(dhd->bus, flow_create_resp->cmplt.flow_ring_id, + flow_create_resp->cmplt.status); +} + +void dhd_prot_clean_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info) +{ + msgbuf_ring_t *flow_ring = (msgbuf_ring_t *)msgbuf_flow_info; + dhd_prot_ring_detach(dhd, flow_ring); + DHD_INFO(("%s Cleaning up Flow \n", __FUNCTION__)); +} + +void dhd_prot_print_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info, + struct bcmstrbuf *strbuf) +{ + msgbuf_ring_t *flow_ring = (msgbuf_ring_t *)msgbuf_flow_info; + uint16 rd, wrt; + dhd_bus_cmn_readshared(dhd->bus, &rd, RING_READ_PTR, flow_ring->idx); + dhd_bus_cmn_readshared(dhd->bus, &wrt, RING_WRITE_PTR, flow_ring->idx); + bcm_bprintf(strbuf, "RD %d WR %d\n", rd, wrt); +} + +void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) +{ + bcm_bprintf(strbuf, "CtrlPost: "); + dhd_prot_print_flow_ring(dhd, dhd->prot->h2dring_ctrl_subn, strbuf); + bcm_bprintf(strbuf, "CtrlCpl: "); + dhd_prot_print_flow_ring(dhd, dhd->prot->d2hring_ctrl_cpln, strbuf); + bcm_bprintf(strbuf, "RxPost: "); + bcm_bprintf(strbuf, "RBP %d ", dhd->prot->rxbufpost); + dhd_prot_print_flow_ring(dhd, dhd->prot->h2dring_rxp_subn, strbuf); + bcm_bprintf(strbuf, "RxCpl: "); + dhd_prot_print_flow_ring(dhd, dhd->prot->d2hring_rx_cpln, strbuf); + if (dhd_bus_is_txmode_push(dhd->bus)) { + bcm_bprintf(strbuf, "TxPost: "); + dhd_prot_print_flow_ring(dhd, dhd->prot->h2dring_txp_subn, strbuf); + } + bcm_bprintf(strbuf, "TxCpl: "); + dhd_prot_print_flow_ring(dhd, dhd->prot->d2hring_tx_cpln, strbuf); + bcm_bprintf(strbuf, "active_tx_count %d pktidmap_avail %d\n", + dhd->prot->active_tx_count, + dhd_pktid_map_avail_cnt(dhd->prot->pktid_map_handle)); +} + +int +dhd_prot_flow_ring_delete(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) +{ + tx_flowring_delete_request_t *flow_delete_rqst; + dhd_prot_t *prot = dhd->prot; + uint16 msglen = sizeof(tx_flowring_delete_request_t); + unsigned long flags; + uint16 alloced = 0; + + /* align it to 4 bytes, so that all start addr form cbuf is 4 byte aligned */ + msglen = align(msglen, DMA_ALIGN_LEN); + + /* Request for ring buffer space */ + DHD_GENERAL_LOCK(dhd, flags); + flow_delete_rqst = (tx_flowring_delete_request_t *)dhd_alloc_ring_space(dhd, + prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); + + if (flow_delete_rqst == NULL) { + DHD_GENERAL_UNLOCK(dhd, flags); + DHD_ERROR(("%s Flow Delete req failure no ring mem %d \n", __FUNCTION__, msglen)); + return BCME_NOMEM; + } + + /* Common msg buf hdr */ + flow_delete_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_DELETE; + flow_delete_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; + flow_delete_rqst->msg.request_id = htol16(0); /* TBD */ + + /* Update Delete info */ + flow_delete_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); + flow_delete_rqst->reason = htol16(BCME_OK); + + DHD_ERROR(("%s sending FLOW RING ID %d for peer " MACDBG " prio %d ifindex %d" + " Delete req msglen %d\n", __FUNCTION__, flow_ring_node->flowid, + MAC2STRDBG(flow_ring_node->flow_info.da), flow_ring_node->flow_info.tid, + flow_ring_node->flow_info.ifindex, msglen)); + + /* upd wrt ptr and raise interrupt */ + prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, flow_delete_rqst, + DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); + DHD_GENERAL_UNLOCK(dhd, flags); + + return BCME_OK; +} + +static void +dhd_prot_process_flow_ring_delete_response(dhd_pub_t *dhd, void* buf, uint16 msglen) +{ + tx_flowring_delete_response_t *flow_delete_resp = (tx_flowring_delete_response_t *)buf; + + DHD_INFO(("%s Flow Delete Response status = %d \n", __FUNCTION__, + flow_delete_resp->cmplt.status)); + +#ifdef PCIE_TX_DEFERRAL + if (flow_delete_resp->cmplt.status != BCME_OK) { + DHD_ERROR(("%s Flow Delete Response failure error status = %d \n", + __FUNCTION__, flow_delete_resp->cmplt.status)); + return; + } + set_bit(flow_delete_resp->cmplt.flow_ring_id, dhd->bus->delete_flow_map); + queue_work(dhd->bus->tx_wq, &dhd->bus->delete_flow_work); +#else + dhd_bus_flow_ring_delete_response(dhd->bus, flow_delete_resp->cmplt.flow_ring_id, + flow_delete_resp->cmplt.status); +#endif /* PCIE_TX_DEFERRAL */ +} + +int +dhd_prot_flow_ring_flush(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) +{ + tx_flowring_flush_request_t *flow_flush_rqst; + dhd_prot_t *prot = dhd->prot; + uint16 msglen = sizeof(tx_flowring_flush_request_t); + unsigned long flags; + uint16 alloced = 0; + + /* align it to 4 bytes, so that all start addr form cbuf is 4 byte aligned */ + msglen = align(msglen, DMA_ALIGN_LEN); + + /* Request for ring buffer space */ + DHD_GENERAL_LOCK(dhd, flags); + flow_flush_rqst = (tx_flowring_flush_request_t *)dhd_alloc_ring_space(dhd, + prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced); + if (flow_flush_rqst == NULL) { + DHD_GENERAL_UNLOCK(dhd, flags); + DHD_ERROR(("%s Flow Flush req failure no ring mem %d \n", __FUNCTION__, msglen)); + return BCME_NOMEM; + } + + /* Common msg buf hdr */ + flow_flush_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_FLUSH; + flow_flush_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; + flow_flush_rqst->msg.request_id = htol16(0); /* TBD */ + + flow_flush_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); + flow_flush_rqst->reason = htol16(BCME_OK); + + DHD_INFO(("%s sending FLOW RING Flush req msglen %d \n", __FUNCTION__, msglen)); + + /* upd wrt ptr and raise interrupt */ + prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, flow_flush_rqst, + DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); + DHD_GENERAL_UNLOCK(dhd, flags); + + return BCME_OK; +} + +static void +dhd_prot_process_flow_ring_flush_response(dhd_pub_t *dhd, void* buf, uint16 msglen) +{ + tx_flowring_flush_response_t *flow_flush_resp = (tx_flowring_flush_response_t *)buf; + + DHD_INFO(("%s Flow Flush Response status = %d \n", __FUNCTION__, + flow_flush_resp->cmplt.status)); + + dhd_bus_flow_ring_flush_response(dhd->bus, flow_flush_resp->cmplt.flow_ring_id, + flow_flush_resp->cmplt.status); +} + +int +dhd_prot_ringupd_dump(dhd_pub_t *dhd, struct bcmstrbuf *b) +{ + uint32 *ptr; + uint32 value; + uint32 i; + uint8 txpush = 0; + uint32 max_h2d_queues = dhd_bus_max_h2d_queues(dhd->bus, &txpush); + + OSL_CACHE_INV((void *)dhd->prot->d2h_dma_writeindx_buf.va, + dhd->prot->d2h_dma_writeindx_buf_len); + + ptr = (uint32 *)(dhd->prot->d2h_dma_writeindx_buf.va); + + bcm_bprintf(b, "\n max_tx_queues %d, txpush mode %d\n", max_h2d_queues, txpush); + + bcm_bprintf(b, "\nRPTR block H2D common rings, 0x%04x\n", ptr); + value = ltoh32(*ptr); + bcm_bprintf(b, "\tH2D CTRL: value 0x%04x\n", value); + ptr++; + value = ltoh32(*ptr); + bcm_bprintf(b, "\tH2D RXPOST: value 0x%04x\n", value); + + if (txpush) { + ptr++; + value = ltoh32(*ptr); + bcm_bprintf(b, "\tH2D TXPOST value 0x%04x\n", value); + } + else { + ptr++; + bcm_bprintf(b, "RPTR block Flow rings , 0x%04x\n", ptr); + for (i = BCMPCIE_H2D_COMMON_MSGRINGS; i < max_h2d_queues; i++) { + value = ltoh32(*ptr); + bcm_bprintf(b, "\tflowring ID %d: value 0x%04x\n", i, value); + ptr++; + } + } + + OSL_CACHE_INV((void *)dhd->prot->h2d_dma_readindx_buf.va, + dhd->prot->h2d_dma_readindx_buf_len); + + ptr = (uint32 *)(dhd->prot->h2d_dma_readindx_buf.va); + + bcm_bprintf(b, "\nWPTR block D2H common rings, 0x%04x\n", ptr); + value = ltoh32(*ptr); + bcm_bprintf(b, "\tD2H CTRLCPLT: value 0x%04x\n", value); + ptr++; + value = ltoh32(*ptr); + bcm_bprintf(b, "\tD2H TXCPLT: value 0x%04x\n", value); + ptr++; + value = ltoh32(*ptr); + bcm_bprintf(b, "\tD2H RXCPLT: value 0x%04x\n", value); + + return 0; +} + +uint32 +dhd_prot_metadatalen_set(dhd_pub_t *dhd, uint32 val, bool rx) +{ + dhd_prot_t *prot = dhd->prot; + if (rx) + prot->rx_metadata_offset = (uint16)val; + else + prot->tx_metadata_offset = (uint16)val; + return dhd_prot_metadatalen_get(dhd, rx); +} + +uint32 +dhd_prot_metadatalen_get(dhd_pub_t *dhd, bool rx) +{ + dhd_prot_t *prot = dhd->prot; + if (rx) + return prot->rx_metadata_offset; + else + return prot->tx_metadata_offset; +} + +uint32 +dhd_prot_txp_threshold(dhd_pub_t *dhd, bool set, uint32 val) +{ + dhd_prot_t *prot = dhd->prot; + if (set) + prot->txp_threshold = (uint16)val; + val = prot->txp_threshold; + return val; +} + +#ifdef DHD_RX_CHAINING +static INLINE void BCMFASTPATH +dhd_rxchain_reset(rxchain_info_t *rxchain) +{ + rxchain->pkt_count = 0; +} + +static void BCMFASTPATH +dhd_rxchain_frame(dhd_pub_t *dhd, void *pkt, uint ifidx) +{ + uint8 *eh; + uint8 prio; + dhd_prot_t *prot = dhd->prot; + rxchain_info_t *rxchain = &prot->rxchain; + + eh = PKTDATA(dhd->osh, pkt); + prio = IP_TOS46(eh + ETHER_HDR_LEN) >> IPV4_TOS_PREC_SHIFT; + + /* For routers, with HNDCTF, link the packets using PKTSETCLINK, */ + /* so that the chain can be handed off to CTF bridge as is. */ + if (rxchain->pkt_count == 0) { + /* First packet in chain */ + rxchain->pkthead = rxchain->pkttail = pkt; + + /* Keep a copy of ptr to ether_da, ether_sa and prio */ + rxchain->h_da = ((struct ether_header *)eh)->ether_dhost; + rxchain->h_sa = ((struct ether_header *)eh)->ether_shost; + rxchain->h_prio = prio; + rxchain->ifidx = ifidx; + rxchain->pkt_count++; + } else { + if (PKT_CTF_CHAINABLE(dhd, ifidx, eh, prio, rxchain->h_sa, + rxchain->h_da, rxchain->h_prio)) { + /* Same flow - keep chaining */ + PKTSETCLINK(rxchain->pkttail, pkt); + rxchain->pkttail = pkt; + rxchain->pkt_count++; + } else { + /* Different flow - First release the existing chain */ + dhd_rxchain_commit(dhd); + + /* Create a new chain */ + rxchain->pkthead = rxchain->pkttail = pkt; + + /* Keep a copy of ptr to ether_da, ether_sa and prio */ + rxchain->h_da = ((struct ether_header *)eh)->ether_dhost; + rxchain->h_sa = ((struct ether_header *)eh)->ether_shost; + rxchain->h_prio = prio; + rxchain->ifidx = ifidx; + rxchain->pkt_count++; + } + } + + if ((!ETHER_ISMULTI(rxchain->h_da)) && + ((((struct ether_header *)eh)->ether_type == HTON16(ETHER_TYPE_IP)) || + (((struct ether_header *)eh)->ether_type == HTON16(ETHER_TYPE_IPV6)))) { + PKTSETCHAINED(dhd->osh, pkt); + PKTCINCRCNT(rxchain->pkthead); + PKTCADDLEN(rxchain->pkthead, PKTLEN(dhd->osh, pkt)); + } else { + dhd_rxchain_commit(dhd); + return; + } + + /* If we have hit the max chain length, dispatch the chain and reset */ + if (rxchain->pkt_count >= DHD_PKT_CTF_MAX_CHAIN_LEN) { + dhd_rxchain_commit(dhd); + } +} + +static void BCMFASTPATH +dhd_rxchain_commit(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + rxchain_info_t *rxchain = &prot->rxchain; + + if (rxchain->pkt_count == 0) + return; + + /* Release the packets to dhd_linux */ + dhd_bus_rx_frame(dhd->bus, rxchain->pkthead, rxchain->ifidx, rxchain->pkt_count); + + /* Reset the chain */ + dhd_rxchain_reset(rxchain); +} +#endif /* DHD_RX_CHAINING */ + +static void +dhd_prot_ring_clear(msgbuf_ring_t* ring) +{ + uint16 size; + + DHD_TRACE(("%s\n", __FUNCTION__)); + + size = ring->ringmem->max_item * ring->ringmem->len_items; + ASSERT(MODX((unsigned long)ring->ring_base.va, DMA_ALIGN_LEN) == 0); + OSL_CACHE_INV((void *) ring->ring_base.va, size); + bzero(ring->ring_base.va, size); + + OSL_CACHE_FLUSH((void *) ring->ring_base.va, size); + + bzero(ring->ringstate, sizeof(*ring->ringstate)); +} + +void +dhd_prot_clear(dhd_pub_t *dhd) +{ + struct dhd_prot *prot = dhd->prot; + + DHD_TRACE(("%s\n", __FUNCTION__)); + + if (prot == NULL) + return; + + if (prot->h2dring_txp_subn) + dhd_prot_ring_clear(prot->h2dring_txp_subn); + if (prot->h2dring_rxp_subn) + dhd_prot_ring_clear(prot->h2dring_rxp_subn); + if (prot->h2dring_ctrl_subn) + dhd_prot_ring_clear(prot->h2dring_ctrl_subn); + if (prot->d2hring_tx_cpln) + dhd_prot_ring_clear(prot->d2hring_tx_cpln); + if (prot->d2hring_rx_cpln) + dhd_prot_ring_clear(prot->d2hring_rx_cpln); + if (prot->d2hring_ctrl_cpln) + dhd_prot_ring_clear(prot->d2hring_ctrl_cpln); + + if (prot->retbuf.va) { + OSL_CACHE_INV((void *) prot->retbuf.va, IOCT_RETBUF_SIZE); + bzero(prot->retbuf.va, IOCT_RETBUF_SIZE); + OSL_CACHE_FLUSH((void *) prot->retbuf.va, IOCT_RETBUF_SIZE); + } + + if (prot->ioctbuf.va) { + OSL_CACHE_INV((void *) prot->ioctbuf.va, IOCT_RETBUF_SIZE); + bzero(prot->ioctbuf.va, IOCT_RETBUF_SIZE); + OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, IOCT_RETBUF_SIZE); + } + + if (prot->d2h_dma_scratch_buf.va) { + OSL_CACHE_INV((void *)prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); + bzero(prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); + OSL_CACHE_FLUSH((void *)prot->d2h_dma_scratch_buf.va, DMA_D2H_SCRATCH_BUF_LEN); + } + + if (prot->h2d_dma_readindx_buf.va) { + OSL_CACHE_INV((void *)prot->h2d_dma_readindx_buf.va, + prot->h2d_dma_readindx_buf_len); + bzero(prot->h2d_dma_readindx_buf.va, + prot->h2d_dma_readindx_buf_len); + OSL_CACHE_FLUSH((void *)prot->h2d_dma_readindx_buf.va, + prot->h2d_dma_readindx_buf_len); + } + + if (prot->h2d_dma_writeindx_buf.va) { + OSL_CACHE_INV((void *)prot->h2d_dma_writeindx_buf.va, + prot->h2d_dma_writeindx_buf_len); + bzero(prot->h2d_dma_writeindx_buf.va, prot->h2d_dma_writeindx_buf_len); + OSL_CACHE_FLUSH((void *)prot->h2d_dma_writeindx_buf.va, + prot->h2d_dma_writeindx_buf_len); + } + + if (prot->d2h_dma_readindx_buf.va) { + OSL_CACHE_INV((void *)prot->d2h_dma_readindx_buf.va, + prot->d2h_dma_readindx_buf_len); + bzero(prot->d2h_dma_readindx_buf.va, prot->d2h_dma_readindx_buf_len); + OSL_CACHE_FLUSH((void *)prot->d2h_dma_readindx_buf.va, + prot->d2h_dma_readindx_buf_len); + } + + if (prot->d2h_dma_writeindx_buf.va) { + OSL_CACHE_INV((void *)prot->d2h_dma_writeindx_buf.va, + prot->d2h_dma_writeindx_buf_len); + bzero(prot->d2h_dma_writeindx_buf.va, prot->d2h_dma_writeindx_buf_len); + OSL_CACHE_FLUSH((void *)prot->d2h_dma_writeindx_buf.va, + prot->d2h_dma_writeindx_buf_len); + } + + prot->rx_metadata_offset = 0; + prot->tx_metadata_offset = 0; + + prot->rxbufpost = 0; + prot->cur_event_bufs_posted = 0; + prot->cur_ioctlresp_bufs_posted = 0; + + prot->active_tx_count = 0; + prot->data_seq_no = 0; + prot->ioctl_seq_no = 0; + prot->pending = 0; + prot->lastcmd = 0; + + prot->ioctl_trans_id = 1; + + /* dhd_flow_rings_init is located at dhd_bus_start, + * so when stopping bus, flowrings shall be deleted + */ + dhd_flow_rings_deinit(dhd); + NATIVE_TO_PKTID_CLEAR(prot->pktid_map_handle); +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.c new file mode 100644 index 000000000000..03fcc06aa31f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.c @@ -0,0 +1,5251 @@ +/* + * DHD Bus Module for PCIE + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_pcie.c 680504 2017-01-20 06:13:53Z $ + */ + + +/* include files */ +#include +#include +#include +#include +#include +#include +#include +#if defined(DHD_DEBUG) +#include +#include +#endif /* defined(DHD_DEBUG) */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DHDTCPACK_SUPPRESS +#include +#endif /* DHDTCPACK_SUPPRESS */ +#include + +#include + +#ifdef BCMEMBEDIMAGE +#include BCMEMBEDIMAGE +#endif /* BCMEMBEDIMAGE */ + +#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ +#define MAX_NVRAMBUF_SIZE 6144 /* max nvram buf size */ + +#define ARMCR4REG_BANKIDX (0x40/sizeof(uint32)) +#define ARMCR4REG_BANKPDA (0x4C/sizeof(uint32)) +/* Temporary war to fix precommit till sync issue between trunk & precommit branch is resolved */ + +#if defined(SUPPORT_MULTIPLE_BOARD_REV) + extern unsigned int system_rev; +#endif /* SUPPORT_MULTIPLE_BOARD_REV */ + +int dhd_dongle_memsize; +int dhd_dongle_ramsize; +#ifdef DHD_DEBUG +static int dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size); +static int dhdpcie_bus_readconsole(dhd_bus_t *bus); +#endif /* DHD_DEBUG */ + +#if defined(DHD_FW_COREDUMP) +int dhdpcie_mem_dump(dhd_bus_t *bus); +#endif /* DHD_FW_COREDUMP */ + +static int dhdpcie_bus_membytes(dhd_bus_t *bus, bool write, ulong address, uint8 *data, uint size); +static int dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, + const char *name, void *params, + int plen, void *arg, int len, int val_size); +static int dhdpcie_bus_lpback_req(struct dhd_bus *bus, uint32 intval); +static int dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus, + uint32 len, uint32 srcdelay, uint32 destdelay); +static int dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter); +static int _dhdpcie_download_firmware(struct dhd_bus *bus); +static int dhdpcie_download_firmware(dhd_bus_t *bus, osl_t *osh); +static int dhdpcie_bus_write_vars(dhd_bus_t *bus); +static bool dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus); +static bool dhdpci_bus_read_frames(dhd_bus_t *bus); +static int dhdpcie_readshared(dhd_bus_t *bus); +static void dhdpcie_init_shared_addr(dhd_bus_t *bus); +static bool dhdpcie_dongle_attach(dhd_bus_t *bus); +static void dhdpcie_bus_intr_enable(dhd_bus_t *bus); +static void dhdpcie_bus_dongle_setmemsize(dhd_bus_t *bus, int mem_size); +static void dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, + bool dongle_isolation, bool reset_flag); +static void dhdpcie_bus_release_malloc(dhd_bus_t *bus, osl_t *osh); +static int dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len); +static uint8 dhdpcie_bus_rtcm8(dhd_bus_t *bus, ulong offset); +static void dhdpcie_bus_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data); +static void dhdpcie_bus_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data); +static uint16 dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset); +static void dhdpcie_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data); +static uint32 dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset); +#ifdef DHD_SUPPORT_64BIT +static void dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data); +static uint64 dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset); +#endif /* DHD_SUPPORT_64BIT */ +static void dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data); +#ifdef CONFIG_ARCH_MSM8994 +static void dhdpcie_bus_cfg_set_bar1_win(dhd_bus_t *bus, uint32 data); +static ulong dhd_bus_cmn_check_offset(dhd_bus_t *bus, ulong offset); +#endif +static void dhdpcie_bus_reg_unmap(osl_t *osh, ulong addr, int size); +static int dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b); +static void dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data); +static void dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info); +extern void dhd_dpc_kill(dhd_pub_t *dhdp); +static void dhdpcie_handle_mb_data(dhd_bus_t *bus); + +#ifdef BCMEMBEDIMAGE +static int dhdpcie_download_code_array(dhd_bus_t *bus); +#endif /* BCMEMBEDIMAGE */ + + + +#define PCI_VENDOR_ID_BROADCOM 0x14e4 + +/* IOVar table */ +enum { + IOV_INTR = 1, + IOV_MEMBYTES, + IOV_MEMSIZE, + IOV_SET_DOWNLOAD_STATE, + IOV_DEVRESET, + IOV_VARS, + IOV_MSI_SIM, + IOV_PCIE_LPBK, + IOV_CC_NVMSHADOW, + IOV_RAMSIZE, + IOV_RAMSTART, + IOV_SLEEP_ALLOWED, + IOV_PCIE_DMAXFER, + IOV_PCIE_SUSPEND, + IOV_DONGLEISOLATION, + IOV_LTRSLEEPON_UNLOOAD, + IOV_RX_METADATALEN, + IOV_TX_METADATALEN, + IOV_TXP_THRESHOLD, + IOV_BUZZZ_DUMP, + IOV_DUMP_RINGUPD_BLOCK, + IOV_DMA_RINGINDICES, + IOV_DB1_FOR_MB, + IOV_FLOW_PRIO_MAP, +#ifdef DHD_USE_IDLECOUNT + IOV_IDLETIME, +#endif /* DHD_USE_IDLECOUNT */ + IOV_RXBOUND, + IOV_TXBOUND +}; + + +const bcm_iovar_t dhdpcie_iovars[] = { + {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, + {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, + {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 }, + {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, + {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, + {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, + {"pcie_lpbk", IOV_PCIE_LPBK, 0, IOVT_UINT32, 0 }, + {"cc_nvmshadow", IOV_CC_NVMSHADOW, 0, IOVT_BUFFER, 0 }, + {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 }, + {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 }, + {"pcie_dmaxfer", IOV_PCIE_DMAXFER, 0, IOVT_BUFFER, 3 * sizeof(int32) }, + {"pcie_suspend", IOV_PCIE_SUSPEND, 0, IOVT_UINT32, 0 }, + {"sleep_allowed", IOV_SLEEP_ALLOWED, 0, IOVT_BOOL, 0 }, + {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, + {"ltrsleep_on_unload", IOV_LTRSLEEPON_UNLOOAD, 0, IOVT_UINT32, 0 }, + {"dump_ringupdblk", IOV_DUMP_RINGUPD_BLOCK, 0, IOVT_BUFFER, 0 }, + {"dma_ring_indices", IOV_DMA_RINGINDICES, 0, IOVT_UINT32, 0}, + {"rx_metadata_len", IOV_RX_METADATALEN, 0, IOVT_UINT32, 0 }, + {"tx_metadata_len", IOV_TX_METADATALEN, 0, IOVT_UINT32, 0 }, + {"db1_for_mb", IOV_DB1_FOR_MB, 0, IOVT_UINT32, 0 }, + {"txp_thresh", IOV_TXP_THRESHOLD, 0, IOVT_UINT32, 0 }, + {"buzzz_dump", IOV_BUZZZ_DUMP, 0, IOVT_UINT32, 0 }, + {"flow_prio_map", IOV_FLOW_PRIO_MAP, 0, IOVT_UINT32, 0 }, +#ifdef DHD_USE_IDLECOUNT + {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, +#endif /* DHD_USE_IDLECOUNT */ + {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, + {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +#define MAX_READ_TIMEOUT 5 * 1000 * 1000 + +#ifndef DHD_RXBOUND +#define DHD_RXBOUND 64 +#endif +#ifndef DHD_TXBOUND +#define DHD_TXBOUND 64 +#endif +uint dhd_rxbound = DHD_RXBOUND; +uint dhd_txbound = DHD_TXBOUND; + +/* Register/Unregister functions are called by the main DHD entry + * point (e.g. module insertion) to link with the bus driver, in + * order to look for or await the device. + */ + +int +dhd_bus_register(void) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + return dhdpcie_bus_register(); +} + +void +dhd_bus_unregister(void) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + dhdpcie_bus_unregister(); + return; +} + + +/** returns a host virtual address */ +uint32 * +dhdpcie_bus_reg_map(osl_t *osh, ulong addr, int size) +{ + return (uint32 *)REG_MAP(addr, size); +} + +void +dhdpcie_bus_reg_unmap(osl_t *osh, ulong addr, int size) +{ + REG_UNMAP((void*)(uintptr)addr); + return; +} + +/** + * 'regs' is the host virtual address that maps to the start of the PCIe BAR0 window. The first 4096 + * bytes in this window are mapped to the backplane address in the PCIEBAR0Window register. The + * precondition is that the PCIEBAR0Window register 'points' at the PCIe core. + * + * 'tcm' is the *host* virtual address at which tcm is mapped. + */ +dhd_bus_t* dhdpcie_bus_attach(osl_t *osh, volatile char* regs, volatile char* tcm, uint32 tcm_size) +{ + dhd_bus_t *bus; + + DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); + + do { + if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { + DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); + break; + } + bzero(bus, sizeof(dhd_bus_t)); + bus->regs = regs; + bus->tcm = tcm; + bus->tcm_size = tcm_size; + bus->osh = osh; + + dll_init(&bus->const_flowring); + mutex_init(&bus->host_clock_lock); + mutex_init(&bus->pm_lock); + + /* Attach pcie shared structure */ + bus->pcie_sh = MALLOC(osh, sizeof(pciedev_shared_t)); + if (!bus->pcie_sh) { + DHD_ERROR(("%s: MALLOC of bus->pcie_sh failed\n", __FUNCTION__)); + break; + } + + /* dhd_common_init(osh); */ + if (dhdpcie_dongle_attach(bus)) { + DHD_ERROR(("%s: dhdpcie_probe_attach failed\n", __FUNCTION__)); + break; + } + + /* software resources */ + if (!(bus->dhd = dhd_attach(osh, bus, PCMSGBUF_HDRLEN))) { + DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); + + break; + } + bus->dhd->busstate = DHD_BUS_DOWN; + bus->db1_for_mb = TRUE; + bus->dhd->hang_report = TRUE; + + bus->d3_ack_war_cnt = 0; + + DHD_TRACE(("%s: EXIT SUCCESS\n", + __FUNCTION__)); + + return bus; + } while (0); + + DHD_TRACE(("%s: EXIT FAILURE\n", __FUNCTION__)); + + if (bus && bus->pcie_sh) + MFREE(osh, bus->pcie_sh, sizeof(pciedev_shared_t)); + + if (bus) + MFREE(osh, bus, sizeof(dhd_bus_t)); + + return NULL; +} + +uint +dhd_bus_chip(struct dhd_bus *bus) +{ + ASSERT(bus->sih != NULL); + return bus->sih->chip; +} + +uint +dhd_bus_chiprev(struct dhd_bus *bus) +{ + ASSERT(bus); + ASSERT(bus->sih != NULL); + return bus->sih->chiprev; +} + +void * +dhd_bus_pub(struct dhd_bus *bus) +{ + return bus->dhd; +} + +void * +dhd_bus_sih(struct dhd_bus *bus) +{ + return (void *)bus->sih; +} + +void * +dhd_bus_txq(struct dhd_bus *bus) +{ + return &bus->txq; +} + +/* Get Chip ID version */ +uint dhd_bus_chip_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + return bus->sih->chip; +} + +/* Get Chip Rev ID version */ +uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + return bus->sih->chiprev; +} + +/* Get Chip Pkg ID version */ +uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + return bus->sih->chippkg; +} + + +/* + +Name: dhdpcie_bus_isr + +Parametrs: + +1: IN int irq -- interrupt vector +2: IN void *arg -- handle to private data structure + +Return value: + +Status (TRUE or FALSE) + +Description: +Interrupt Service routine checks for the status register, +disable interrupt and queue DPC if mail box interrupts are raised. +*/ + + +int32 +dhdpcie_bus_isr(dhd_bus_t *bus) +{ + + do { + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + /* verify argument */ + if (!bus) { + DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); + break; + } + if (bus->dhd->dongle_reset) { + DHD_ERROR(("%s : dongle reset , exit \n", __FUNCTION__)); + break; + } + + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_TRACE(("%s : bus is down. we have nothing to do\n", + __FUNCTION__)); + break; + } + + /* Overall operation: + * - Mask further interrupts + * - Read/ack intstatus + * - Take action based on bits and state + * - Reenable interrupts (as per state) + */ + + /* Count the interrupt call */ + bus->intrcount++; + + if (bus->ipend && bus->intdis) { + if (bus->lastintrs == 0) { + bus->lastintrs = bus->intrcount; + } else if (bus->intrcount > bus->lastintrs + 10) { + DHD_ERROR(("%s : hang recover, lastintrs %d intrcount %d\n", + __FUNCTION__, bus->lastintrs, bus->intrcount)); + bus->lastintrs = 0; + dhd_os_send_hang_message(bus->dhd); + break; + } + } else { + bus->lastintrs = 0; + } + + /* read interrupt status register!! Status bits will be cleared in DPC !! */ + bus->ipend = TRUE; + dhdpcie_bus_intr_disable(bus); /* Disable interrupt!! */ + +#if defined(PCIE_ISR_THREAD) + + DHD_TRACE(("Calling dhd_bus_dpc() from %s\n", __FUNCTION__)); + DHD_OS_WAKE_LOCK(bus->dhd); + while (dhd_bus_dpc(bus)); + DHD_OS_WAKE_UNLOCK(bus->dhd); +#else + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); /* queue DPC now!! */ +#endif /* defined(SDIO_ISR_THREAD) */ + + DHD_TRACE(("%s: Exit Success DPC Queued\n", __FUNCTION__)); + return TRUE; + + } while (0); + + DHD_TRACE(("%s: Exit Failure\n", __FUNCTION__)); + return FALSE; +} + +static bool +dhdpcie_dongle_attach(dhd_bus_t *bus) +{ + + osl_t *osh = bus->osh; + void *regsva = (void*)bus->regs; + uint16 devid = bus->cl_devid; + uint32 val; + sbpcieregs_t *sbpcieregs; + + DHD_TRACE(("%s: ENTER\n", + __FUNCTION__)); + + + bus->alp_only = TRUE; + bus->sih = NULL; + + /* Set bar0 window to si_enum_base */ + dhdpcie_bus_cfg_set_bar0_win(bus, SI_ENUM_BASE); + +#ifdef CONFIG_ARCH_MSM8994 + /* Read bar1 window */ + bus->bar1_win_base = OSL_PCI_READ_CONFIG(bus->osh, PCI_BAR1_WIN, 4); + DHD_ERROR(("%s: PCI_BAR1_WIN = %x\n", __FUNCTION__, bus->bar1_win_base)); +#endif +#ifdef SOMC_1DK_NV_PATH + bus->subsystem_id = (uint16)((OSL_PCI_READ_CONFIG(osh, PCI_CFG_SVID, 4) >> 16) & 0xffff); + DHD_ERROR(("%s: PCI_CFG_SSID = %d\n", __FUNCTION__, bus->subsystem_id)); +#endif /* SOMC_1DK_NV_PATH */ + /* si_attach() will provide an SI handle and scan the backplane */ + if (!(bus->sih = si_attach((uint)devid, osh, regsva, PCI_BUS, bus, + &bus->vars, &bus->varsz))) { + DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); + goto fail; + } + + + si_setcore(bus->sih, PCIE2_CORE_ID, 0); + sbpcieregs = (sbpcieregs_t*)(bus->regs); + + /* WAR where the BAR1 window may not be sized properly */ + W_REG(osh, &sbpcieregs->configaddr, 0x4e0); + val = R_REG(osh, &sbpcieregs->configdata); +#ifdef CONFIG_ARCH_MSM8994 + bus->bar1_win_mask = 0xffffffff - (bus->tcm_size - 1); + DHD_ERROR(("%s: BAR1 window val=%d mask=%x\n", __FUNCTION__, val, bus->bar1_win_mask)); +#endif + W_REG(osh, &sbpcieregs->configdata, val); + + /* Get info on the ARM and SOCRAM cores... */ + /* Should really be qualified by device id */ + if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || + (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || + (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { + bus->armrev = si_corerev(bus->sih); + } else { + DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); + goto fail; + } + + if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { + DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); + goto fail; + } + } else { + /* cr4 has a different way to find the RAM size from TCM's */ + if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { + DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); + goto fail; + } + /* also populate base address */ + switch ((uint16)bus->sih->chip) { + case BCM4339_CHIP_ID: + case BCM4335_CHIP_ID: + bus->dongle_ram_base = CR4_4335_RAM_BASE; + break; + case BCM4358_CHIP_ID: + case BCM4356_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM43567_CHIP_ID: + case BCM43569_CHIP_ID: + case BCM4350_CHIP_ID: + case BCM43570_CHIP_ID: + bus->dongle_ram_base = CR4_4350_RAM_BASE; + break; + case BCM4360_CHIP_ID: + bus->dongle_ram_base = CR4_4360_RAM_BASE; + break; + case BCM4345_CHIP_ID: + bus->dongle_ram_base = CR4_4345_RAM_BASE; + break; + case BCM43602_CHIP_ID: + bus->dongle_ram_base = CR4_43602_RAM_BASE; + break; + case BCM4349_CHIP_GRPID: + bus->dongle_ram_base = CR4_4349_RAM_BASE; + break; + default: + bus->dongle_ram_base = 0; + DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", + __FUNCTION__, bus->dongle_ram_base)); + } + } + bus->ramsize = bus->orig_ramsize; + if (dhd_dongle_memsize) + dhdpcie_bus_dongle_setmemsize(bus, dhd_dongle_memsize); + + DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", + bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); + + bus->srmemsize = si_socram_srmem_size(bus->sih); + + + bus->def_intmask = PCIE_MB_D2H_MB_MASK | PCIE_MB_TOPCIE_FN0_0 | PCIE_MB_TOPCIE_FN0_1; + + /* Set the poll and/or interrupt flags */ + bus->intr = (bool)dhd_intr; + + bus->wait_for_d3_ack = 1; + bus->suspended = FALSE; + bus->force_suspend = 0; + DHD_TRACE(("%s: EXIT: SUCCESS\n", + __FUNCTION__)); + return 0; + +fail: + if (bus->sih != NULL) + si_detach(bus->sih); + DHD_TRACE(("%s: EXIT: FAILURE\n", + __FUNCTION__)); + return -1; +} + +int +dhpcie_bus_unmask_interrupt(dhd_bus_t *bus) +{ + dhdpcie_bus_cfg_write_dword(bus, PCIIntmask, 4, I_MB); + return 0; +} +int +dhpcie_bus_mask_interrupt(dhd_bus_t *bus) +{ + dhdpcie_bus_cfg_write_dword(bus, PCIIntmask, 4, 0x0); + return 0; +} + +void +dhdpcie_bus_intr_enable(dhd_bus_t *bus) +{ + DHD_TRACE(("enable interrupts\n")); + + if (!bus || !bus->sih) + return; + + bus->intdis = FALSE; + if (bus && bus->dev && bus->dev->irq) { + struct irq_desc *desc = irq_to_desc(bus->dev->irq); + if (desc->depth > 0) { + DHD_INTR(("%s enable_irq irq=%d\n", __FUNCTION__, + bus->dev->irq)); + enable_irq(bus->dev->irq); + } + } + if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || + (bus->sih->buscorerev == 4)) { + dhpcie_bus_unmask_interrupt(bus); + } + else if (bus->sih) { + si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, + bus->def_intmask, bus->def_intmask); + } +} + +void +dhdpcie_bus_intr_disable(dhd_bus_t *bus) +{ + + DHD_TRACE(("%s Enter\n", __FUNCTION__)); + + if (!bus || !bus->sih) + return; + + if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || + (bus->sih->buscorerev == 4)) { + dhpcie_bus_mask_interrupt(bus); + } + else if (bus->sih) { + si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, + bus->def_intmask, 0); + } + if (bus && bus->dev && bus->dev->irq) { + struct irq_desc *desc = irq_to_desc(bus->dev->irq); + if (desc->depth == 0) { + DHD_INTR(("%s disable_irq_nosync irq=%d\n", __FUNCTION__, + bus->dev->irq)); + disable_irq_nosync(bus->dev->irq); + } + } + bus->intdis = TRUE; + + DHD_TRACE(("%s Exit\n", __FUNCTION__)); +} + +void +dhdpcie_bus_remove_prep(dhd_bus_t *bus) +{ + DHD_TRACE(("%s Enter\n", __FUNCTION__)); + + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_TRACE(("%s Exit, bus is already down\n", __FUNCTION__)); + return; + } + dhd_os_sdlock(bus->dhd); + + bus->dhd->busstate = DHD_BUS_DOWN; + dhdpcie_bus_intr_disable(bus); + pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *)(bus->regs)); + + dhd_os_sdunlock(bus->dhd); + + DHD_TRACE(("%s Exit\n", __FUNCTION__)); +} + + +/* Detach and free everything */ +void +dhdpcie_bus_release(dhd_bus_t *bus) +{ + bool dongle_isolation = FALSE; + osl_t *osh = NULL; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus) { + + osh = bus->osh; + ASSERT(osh); + + if (bus->dhd) { + dongle_isolation = bus->dhd->dongle_isolation; + if (bus->intr && (bus->dhd->busstate != DHD_BUS_DOWN)) { + dhdpcie_bus_intr_disable(bus); + dhdpcie_free_irq(bus); + } + dhd_detach(bus->dhd); + dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE); + dhd_free(bus->dhd); + bus->dhd = NULL; + } + + /* unmap the regs and tcm here!! */ + if (bus->regs) { + dhdpcie_bus_reg_unmap(osh, (ulong)bus->regs, DONGLE_REG_MAP_SIZE); + bus->regs = NULL; + } + if (bus->tcm) { + dhdpcie_bus_reg_unmap(osh, (ulong)bus->tcm, bus->tcm_size); + bus->tcm = NULL; + } + + dhdpcie_bus_release_malloc(bus, osh); + /* Detach pcie shared structure */ + if (bus->pcie_sh) + MFREE(osh, bus->pcie_sh, sizeof(pciedev_shared_t)); + +#ifdef DHD_DEBUG + + if (bus->console.buf != NULL) + MFREE(osh, bus->console.buf, bus->console.bufsize); +#endif + + + /* Finally free bus info */ + MFREE(osh, bus, sizeof(dhd_bus_t)); + + } + DHD_TRACE(("%s: Exit\n", __FUNCTION__)); +} + +void +dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) +{ + + DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, + bus->dhd, bus->dhd->dongle_reset)); + + if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) { + DHD_TRACE(("%s Exit\n", __FUNCTION__)); + return; + } + + if (bus->sih) { + + if (!dongle_isolation) + pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *)(bus->regs)); + + if (bus->ltrsleep_on_unload) { + si_corereg(bus->sih, bus->sih->buscoreidx, + OFFSETOF(sbpcieregs_t, u.pcie2.ltr_state), ~0, 0); + } + si_detach(bus->sih); + if (bus->vars && bus->varsz) + MFREE(osh, bus->vars, bus->varsz); + bus->vars = NULL; + } + + DHD_TRACE(("%s Exit\n", __FUNCTION__)); +} + +uint32 +dhdpcie_bus_cfg_read_dword(dhd_bus_t *bus, uint32 addr, uint32 size) +{ + uint32 data = OSL_PCI_READ_CONFIG(bus->osh, addr, size); + return data; +} + +/* 32 bit config write */ +void +dhdpcie_bus_cfg_write_dword(dhd_bus_t *bus, uint32 addr, uint32 size, uint32 data) +{ + OSL_PCI_WRITE_CONFIG(bus->osh, addr, size, data); +} + +void +dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data) +{ + OSL_PCI_WRITE_CONFIG(bus->osh, PCI_BAR0_WIN, 4, data); +} + +#ifdef CONFIG_ARCH_MSM8994 +void +dhdpcie_bus_cfg_set_bar1_win(dhd_bus_t *bus, uint32 data) +{ + OSL_PCI_WRITE_CONFIG(bus->osh, PCI_BAR1_WIN, 4, data); +} +#endif + +void +dhdpcie_bus_dongle_setmemsize(struct dhd_bus *bus, int mem_size) +{ + int32 min_size = DONGLE_MIN_MEMSIZE; + /* Restrict the memsize to user specified limit */ + DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", + dhd_dongle_memsize, min_size)); + if ((dhd_dongle_memsize > min_size) && + (dhd_dongle_memsize < (int32)bus->orig_ramsize)) + bus->ramsize = dhd_dongle_memsize; +} + +void +dhdpcie_bus_release_malloc(dhd_bus_t *bus, osl_t *osh) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd && bus->dhd->dongle_reset) + return; + + if (bus->vars && bus->varsz) { + MFREE(osh, bus->vars, bus->varsz); + bus->vars = NULL; + } + + DHD_TRACE(("%s: Exit\n", __FUNCTION__)); + return; + +} + +/* Stop bus module: clear pending frames, disable data flow */ +void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) +{ + uint32 status; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!bus->dhd) + return; + + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: already down by net_dev_reset\n", __FUNCTION__)); + goto done; + } +#ifdef DHD_USE_IDLECOUNT + bus_wake(bus); +#endif /* DHD_USE_IDLECOUNT */ + + bus->dhd->busstate = DHD_BUS_DOWN; + dhdpcie_bus_intr_disable(bus); + status = dhdpcie_bus_cfg_read_dword(bus, PCIIntstatus, 4); + dhdpcie_bus_cfg_write_dword(bus, PCIIntstatus, 4, status); + if (!dhd_download_fw_on_driverload) + dhd_dpc_kill(bus->dhd); + + /* Clear rx control and wake any waiters */ + bus->rxlen = 0; + dhd_os_ioctl_resp_wake(bus->dhd); + +done: + return; +} + +/* Watchdog timer function */ +bool dhd_bus_watchdog(dhd_pub_t *dhd) +{ + dhd_bus_t *bus = dhd->bus; + + if (bus->dhd->hang_was_sent) { + dhd_os_wd_timer(bus->dhd, 0); + return FALSE; + } + +#ifdef DHD_DEBUG + + + /* Poll for console output periodically */ + if (dhd->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { + bus->console.count += dhd_watchdog_ms; + if (bus->console.count >= dhd_console_ms) { + bus->console.count -= dhd_console_ms; + /* Make sure backplane clock is on */ + if (dhdpcie_bus_readconsole(bus) < 0) + dhd_console_ms = 0; /* On error, stop trying */ + } + } +#endif /* DHD_DEBUG */ + +#ifdef DHD_USE_IDLECOUNT + if (bus->suspended == TRUE || bus->host_suspend == TRUE) { + DHD_ERROR(("bus->suspended : %d, bus->host_suspend : %d\n", + bus->suspended, bus->host_suspend)); + return BCME_BUSY; + } + bus->idlecount++; + + if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) { + bus->idlecount = 0; + bus->host_suspend = TRUE; + bus->bus_wake = 0; + + if (!dhd->up) { + DHD_INFO(("%s: DHD is not up\n", __FUNCTION__)); + return FALSE; + } + + atomic_set(&bus->runtime_suspend, 1); + DHD_ERROR(("%s: DHD Idle state!! - idletime :%d, wdtick :%d \n", + __FUNCTION__, bus->idletime, dhd_watchdog_ms)); + + /* if device suspended, wd needs to turn off */ + if (dhdpcie_set_suspend_resume(bus->dev, TRUE)) { + DHD_ERROR(("%s: runtime suspend failed \n", __FUNCTION__)); + atomic_set(&bus->runtime_suspend, 0); + return FALSE; + } + wait_event_interruptible(bus->rpm_queue, bus->bus_wake); + dhdpcie_set_suspend_resume(bus->dev, FALSE); + atomic_set(&bus->runtime_suspend, 0); + smp_wmb(); + wake_up_interruptible(&bus->rpm_queue); + DHD_ERROR(("%s: Runtime resume ended.\n", __FUNCTION__)); + } + +#endif /* DHD_USE_IDLECOUNT */ + + return FALSE; +} + +#if defined(SUPPORT_MULTIPLE_REVISION) +static int concate_revision_bcm4354(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + uint32 chip_id, chip_ver; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[10] = "_4354"; +#else + char chipver_tag[4] = {0, }; +#endif /* SUPPORT_MULTIPLE_CHIPS */ + + chip_id = si_chipid(bus->sih); + chip_ver = bus->sih->chiprev; + if (chip_ver == 0) { + DHD_ERROR(("----- CHIP 4354 A0 -----\n")); + strcat(chipver_tag, "_a0"); + } else if (chip_ver == 1) { + DHD_ERROR(("----- CHIP 4354 A1 -----\n")); + strcat(chipver_tag, "_a1"); + } else { + DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); + } + + strcat(fw_path, chipver_tag); + strcat(nv_path, chipver_tag); + + return 0; +} + +static int concate_revision_bcm4356(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + uint32 chip_id, chip_ver; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[10] = "_4356"; +#else + char chipver_tag[4] = {0, }; +#endif /* SUPPORT_MULTIPLE_CHIPS */ + + chip_id = si_chipid(bus->sih); + chip_ver = bus->sih->chiprev; + if (chip_ver == 2) { + DHD_ERROR(("----- CHIP 4356 A2 -----\n")); + strcat(chipver_tag, "_a2"); + } else { + DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); + } + + strcat(fw_path, chipver_tag); + strcat(nv_path, chipver_tag); + + return 0; +} + +static int concate_revision_bcm4358(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + uint32 chip_id, chip_ver; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[20] = "_4358"; +#else + char chipver_tag[10] = {0, }; +#endif /* SUPPORT_MULTIPLE_CHIPS */ + + chip_id = si_chipid(bus->sih); + chip_ver = bus->sih->chiprev; + if (chip_ver == 0) { + DHD_ERROR(("----- CHIP 4358 A0 -----\n")); + strcat(chipver_tag, "_a0"); + } else if (chip_ver == 1) { + DHD_ERROR(("----- CHIP 4358 A1 -----\n")); +#if defined(SUPPORT_MULTIPLE_CHIPS) + strcat(chipver_tag, "_a1"); +#endif /* SUPPORT_MULTIPLE_CHIPS */ + } else { + DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); + } + + strcat(fw_path, chipver_tag); +#if defined(SUPPORT_MULTIPLE_BOARD_REV) + if (system_rev >= 10) { + DHD_ERROR(("----- Board Rev [%d]-----\n", system_rev)); + strcat(chipver_tag, "_r10"); + } +#endif /* SUPPORT_MULTIPLE_BOARD_REV */ + strcat(nv_path, chipver_tag); + + return 0; +} + + +int +concate_revision(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + int res = 0; + + if (!bus || !bus->sih) { + DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__)); + return -1; + } + + DHD_ERROR(("concate_revision \n")); + + switch (si_chipid(bus->sih)) { + + case BCM4354_CHIP_ID: + res = concate_revision_bcm4354(bus, fw_path, nv_path); + break; + + case BCM4356_CHIP_ID: + res = concate_revision_bcm4356(bus, fw_path, nv_path); + break; + + case BCM43569_CHIP_ID: + case BCM4358_CHIP_ID: + res = concate_revision_bcm4358(bus, fw_path, nv_path); + break; + + default: + DHD_ERROR(("REVISION SPECIFIC feature is not required\n")); + return res; + } + + return res; +} +#endif /* SUPPORT_MULTIPLE_REVISION */ + + +/* Download firmware image and nvram image */ +int +dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, + char *pfw_path, char *pnv_path) +{ + int ret; + + bus->fw_path = pfw_path; + bus->nv_path = pnv_path; + + ret = dhdpcie_download_firmware(bus, osh); + + return ret; +} + +static int +dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) +{ + int ret = 0; +#if defined(BCM_REQUEST_FW) + uint chipid = bus->sih->chip; + uint revid = bus->sih->chiprev; + char fw_path[64] = "/lib/firmware/brcm/bcm"; /* path to firmware image */ + char nv_path[64]; /* path to nvram vars file */ + bus->fw_path = fw_path; + bus->nv_path = nv_path; + switch (chipid) { + case BCM43570_CHIP_ID: + bcmstrncat(fw_path, "43570", 5); + switch (revid) { + case 0: + bcmstrncat(fw_path, "a0", 2); + break; + case 2: + bcmstrncat(fw_path, "a2", 2); + break; + default: + DHD_ERROR(("%s: revid is not found %x\n", __FUNCTION__, + revid)); + break; + } + break; + default: + DHD_ERROR(("%s: unsupported device %x\n", __FUNCTION__, + chipid)); + return 0; + } + /* load board specific nvram file */ + snprintf(bus->nv_path, sizeof(nv_path), "%s.nvm", fw_path); + /* load firmware */ + snprintf(bus->fw_path, sizeof(fw_path), "%s-firmware.bin", fw_path); +#endif /* BCM_REQUEST_FW */ + +#if defined(SUPPORT_MULTIPLE_REVISION) + if (concate_revision(bus, bus->fw_path, bus->nv_path) != 0) { + DHD_ERROR(("%s: fail to concatnate revison \n", + __FUNCTION__)); + return BCME_BADARG; + } +#endif /* SUPPORT_MULTIPLE_REVISION */ +#ifdef SOMC_1DK_NV_PATH +#define SOMC_SUBSYSTEMID_FOR_1DK_CHIP 0xcdab + if (bus->subsystem_id != 0x0000) { + if (bus->subsystem_id == SOMC_SUBSYSTEMID_FOR_1DK_CHIP) + bus->nv_path = SOMC_1DK_NV_PATH; +#ifdef SOMC_LOW_POWER_NV_PATH + else + bus->nv_path = SOMC_LOW_POWER_NV_PATH; +#endif /* SOMC_LOW_POWER_NV_PATH */ + } +#endif /* SOMC_1DK_NV_PATH */ + DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n", + __FUNCTION__, bus->fw_path, bus->nv_path)); + + DHD_OS_WAKE_LOCK(bus->dhd); + + ret = _dhdpcie_download_firmware(bus); + + DHD_OS_WAKE_UNLOCK(bus->dhd); + return ret; +} + +static int +dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) +{ + int bcmerror = -1; + int offset = 0; + int len; + void *image = NULL; + uint8 *memblock = NULL, *memptr; + + DHD_ERROR(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); + + /* Should succeed in opening image if it is actually given through registry + * entry or in module param. + */ + image = dhd_os_open_image(pfw_path); + if (image == NULL) + goto err; + + memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); + if (memblock == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); + goto err; + } + if ((uint32)(uintptr)memblock % DHD_SDALIGN) + memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); + + /* Download image */ + while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { + if (len < 0) { + DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); + bcmerror = BCME_ERROR; + goto err; + } + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)memptr)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + + bcmerror = dhdpcie_bus_membytes(bus, TRUE, offset, memptr, len); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + + offset += MEMBLOCK; + } + +err: + if (memblock) + MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); + + if (image) + dhd_os_close_image(image); + + return bcmerror; +} + + +static int +dhdpcie_download_nvram(struct dhd_bus *bus) +{ + int bcmerror = -1; + uint len; + void * image = NULL; + char * memblock = NULL; + char *bufp; + char *pnv_path; + bool nvram_file_exists; + + pnv_path = bus->nv_path; + + nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); + if (!nvram_file_exists && (bus->nvram_params == NULL)) + return (0); + + if (nvram_file_exists) { + image = dhd_os_open_image(pnv_path); + if (image == NULL) + goto err; + } + + memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); + if (memblock == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", + __FUNCTION__, MAX_NVRAMBUF_SIZE)); + goto err; + } + + /* Download variables */ + if (nvram_file_exists) { + len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); + } + else { + + /* nvram is string with null terminated. cannot use strlen */ + len = bus->nvram_params_len; + ASSERT(len <= MAX_NVRAMBUF_SIZE); + memcpy(memblock, bus->nvram_params, len); + } + if (len > 0 && len < MAX_NVRAMBUF_SIZE) { + bufp = (char *)memblock; + bufp[len] = 0; + + if (somc_txpower_calibrate(memblock, len) != BCME_OK) { + DHD_ERROR(("%s: error calibrating tx power\n", __FUNCTION__)); + goto err; + } + + if (nvram_file_exists) + len = process_nvram_vars(bufp, len); + + if (len % 4) { + len += 4 - (len % 4); + } + bufp += len; + *bufp++ = 0; + if (len) + bcmerror = dhdpcie_downloadvars(bus, memblock, len + 1); + if (bcmerror) { + DHD_ERROR(("%s: error downloading vars: %d\n", + __FUNCTION__, bcmerror)); + } + } + else { + DHD_ERROR(("%s: error reading nvram file: %d\n", + __FUNCTION__, len)); + bcmerror = BCME_ERROR; + } + +err: + if (memblock) + MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); + + if (image) + dhd_os_close_image(image); + + return bcmerror; +} + + +#ifdef BCMEMBEDIMAGE +int +dhdpcie_download_code_array(struct dhd_bus *bus) +{ + int bcmerror = -1; + int offset = 0; + unsigned char *p_dlarray = NULL; + unsigned int dlarray_size = 0; + unsigned int downloded_len, remaining_len, len; + char *p_dlimagename, *p_dlimagever, *p_dlimagedate; + uint8 *memblock = NULL, *memptr; + + downloded_len = 0; + remaining_len = 0; + len = 0; + + p_dlarray = dlarray; + dlarray_size = sizeof(dlarray); + p_dlimagename = dlimagename; + p_dlimagever = dlimagever; + p_dlimagedate = dlimagedate; + + if ((p_dlarray == 0) || (dlarray_size == 0) ||(dlarray_size > bus->ramsize) || + (p_dlimagename == 0) || (p_dlimagever == 0) || (p_dlimagedate == 0)) + goto err; + + memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); + if (memblock == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); + goto err; + } + if ((uint32)(uintptr)memblock % DHD_SDALIGN) + memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); + + while (downloded_len < dlarray_size) { + remaining_len = dlarray_size - downloded_len; + if (remaining_len >= MEMBLOCK) + len = MEMBLOCK; + else + len = remaining_len; + + memcpy(memptr, (p_dlarray + downloded_len), len); + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + if (offset == 0) { + bus->resetinstr = *(((uint32*)memptr)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + bcmerror = dhdpcie_bus_membytes(bus, TRUE, offset, (uint8 *)memptr, len); + downloded_len += len; + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + offset += MEMBLOCK; + } + +#ifdef DHD_DEBUG + /* Upload and compare the downloaded code */ + { + unsigned char *ularray = NULL; + unsigned int uploded_len; + uploded_len = 0; + bcmerror = -1; + ularray = MALLOC(bus->dhd->osh, dlarray_size); + if (ularray == NULL) + goto upload_err; + /* Upload image to verify downloaded contents. */ + offset = bus->dongle_ram_base; + memset(ularray, 0xaa, dlarray_size); + while (uploded_len < dlarray_size) { + remaining_len = dlarray_size - uploded_len; + if (remaining_len >= MEMBLOCK) + len = MEMBLOCK; + else + len = remaining_len; + bcmerror = dhdpcie_bus_membytes(bus, FALSE, offset, + (uint8 *)(ularray + uploded_len), len); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto upload_err; + } + + uploded_len += len; + offset += MEMBLOCK; + } + + if (memcmp(p_dlarray, ularray, dlarray_size)) { + DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", + __FUNCTION__, p_dlimagename, p_dlimagever, p_dlimagedate)); + goto upload_err; + + } else + DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", + __FUNCTION__, p_dlimagename, p_dlimagever, p_dlimagedate)); +upload_err: + if (ularray) + MFREE(bus->dhd->osh, ularray, dlarray_size); + } +#endif /* DHD_DEBUG */ +err: + + if (memblock) + MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); + + return bcmerror; +} +#endif /* BCMEMBEDIMAGE */ + + +static int +_dhdpcie_download_firmware(struct dhd_bus *bus) +{ + int bcmerror = -1; + + bool embed = FALSE; /* download embedded firmware */ + bool dlok = FALSE; /* download firmware succeeded */ + + /* Out immediately if no image to download */ + if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { +#ifdef BCMEMBEDIMAGE + embed = TRUE; +#else + DHD_ERROR(("%s: no fimrware file\n", __FUNCTION__)); + return 0; +#endif + } + + /* Keep arm in reset */ + if (dhdpcie_bus_download_state(bus, TRUE)) { + DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); + goto err; + } + + /* External image takes precedence if specified */ + if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { + if (dhdpcie_download_code_file(bus, bus->fw_path)) { + DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); +#ifdef BCMEMBEDIMAGE + embed = TRUE; +#else + goto err; +#endif + } + else { + embed = FALSE; + dlok = TRUE; + } + } + +#ifdef BCMEMBEDIMAGE + if (embed) { + if (dhdpcie_download_code_array(bus)) { + DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); + goto err; + } + else { + dlok = TRUE; + } + } +#else + BCM_REFERENCE(embed); +#endif + if (!dlok) { + DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); + goto err; + } + + /* EXAMPLE: nvram_array */ + /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ + /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ + + + /* External nvram takes precedence if specified */ + if (dhdpcie_download_nvram(bus)) { + DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); + goto err; + } + + /* Take arm out of reset */ + if (dhdpcie_bus_download_state(bus, FALSE)) { + DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); + goto err; + } + + bcmerror = 0; + +err: + return bcmerror; +} + +int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) +{ + int timeleft; + uint rxlen = 0; + bool pending; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) + return -EIO; + +#ifdef DHD_USE_IDLECOUNT + bus_wake(bus); +#endif /* DHD_USE_IDLECOUNT */ + /* Wait until control frame is available */ + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); + rxlen = bus->rxlen; + bcopy(&bus->ioct_resp, msg, MIN(rxlen, sizeof(ioctl_comp_resp_msg_t))); + bus->rxlen = 0; + + if (rxlen) { + DHD_CTL(("%s: resumed on rxctl frame, got %d\n", __FUNCTION__, rxlen)); + } else if (timeleft == 0) { + DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); +#ifdef DHD_USE_IDLECOUNT + /* must do bus wake again due to ioctl response timeout */ + bus_wake(bus); +#endif /* DHD_USE_IDLECOUNT */ +#if defined(DHD_FW_COREDUMP) && defined(CUSTOMER_HW5) + if (bus->dhd->rxcnt_timeout == 0) { + /* write core dump to file */ + dhdpcie_mem_dump(bus); + } +#endif + bus->ioct_resp.cmn_hdr.request_id = 0; + bus->ioct_resp.compl_hdr.status = 0xffff; + bus->dhd->rxcnt_timeout++; + DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout)); + } else if (pending == TRUE) { + DHD_CTL(("%s: canceled\n", __FUNCTION__)); + return -ERESTARTSYS; + } else { + DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); + } + + if (timeleft != 0) + bus->dhd->rxcnt_timeout = 0; + + if (rxlen) + bus->dhd->rx_ctlpkts++; + else + bus->dhd->rx_ctlerrs++; + + if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) { +#ifdef SUPPORT_LINKDOWN_RECOVERY +#ifdef CONFIG_ARCH_MSM + bus->islinkdown = TRUE; +#endif /* CONFIG_ARCH_MSM */ +#endif /* SUPPORT_LINKDOWN_RECOVERY */ + return -ETIMEDOUT; + } + + if (bus->dhd->dongle_trap_occured) { +#ifdef SUPPORT_LINKDOWN_RECOVERY +#ifdef CONFIG_ARCH_MSM + bus->islinkdown = TRUE; +#endif /* CONFIG_ARCH_MSM */ +#endif /* SUPPORT_LINKDOWN_RECOVERY */ + return -EREMOTEIO; + } + + return rxlen ? (int)rxlen : -EIO; + +} + +#define CONSOLE_LINE_MAX 192 + +#ifdef DHD_DEBUG +static int +dhdpcie_bus_readconsole(dhd_bus_t *bus) +{ + dhd_console_t *c = &bus->console; + uint8 line[CONSOLE_LINE_MAX], ch; + uint32 n, idx, addr; + int rv; + + /* Don't do anything until FWREADY updates console address */ + if (bus->console_addr == 0) + return -1; + + /* Read console log struct */ + addr = bus->console_addr + OFFSETOF(hnd_cons_t, log); + + if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) + return rv; + + /* Allocate console buffer (one time only) */ + if (c->buf == NULL) { + c->bufsize = ltoh32(c->log.buf_size); + if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) + return BCME_NOMEM; + } + idx = ltoh32(c->log.idx); + + /* Protect against corrupt value */ + if (idx > c->bufsize) + return BCME_ERROR; + + /* Skip reading the console buffer if the index pointer has not moved */ + if (idx == c->last) + return BCME_OK; + + /* Read the console buffer */ + addr = ltoh32(c->log.buf); + if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 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; + printf("CONSOLE: %s\n", line); + } + } +break2: + + return BCME_OK; +} +#endif /* DHD_DEBUG */ + +static int +dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size) +{ + int bcmerror = 0; + uint msize = 512; + char *mbuffer = NULL; + char *console_buffer = NULL; + uint maxstrlen = 256; + char *str = NULL; + trap_t tr; + pciedev_shared_t *pciedev_shared = bus->pcie_sh; + struct bcmstrbuf strbuf; + uint32 console_ptr, console_size, console_index; + uint8 line[CONSOLE_LINE_MAX], ch; + uint32 n, i, addr; + int rv; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (DHD_NOCHECKDIED_ON()) { + return 0; + } + + if (data == NULL) { + /* + * Called after a rx ctrl timeout. "data" is NULL. + * allocate memory to trace the trap or assert. + */ + size = msize; + mbuffer = data = MALLOC(bus->dhd->osh, msize); + + if (mbuffer == NULL) { + DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); + bcmerror = BCME_NOMEM; + goto done; + } + } + + if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { + DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); + bcmerror = BCME_NOMEM; + goto done; + } + + if ((bcmerror = dhdpcie_readshared(bus)) < 0) { + goto done; + } + + bcm_binit(&strbuf, data, size); + + bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", + pciedev_shared->msgtrace_addr, pciedev_shared->console_addr); + + if ((pciedev_shared->flags & PCIE_SHARED_ASSERT_BUILT) == 0) { + /* NOTE: Misspelled assert is intentional - DO NOT FIX. + * (Avoids conflict with real asserts for programmatic parsing of output.) + */ + bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); + } + + if ((bus->pcie_sh->flags & (PCIE_SHARED_ASSERT|PCIE_SHARED_TRAP)) == 0) { + /* NOTE: Misspelled assert is intentional - DO NOT FIX. + * (Avoids conflict with real asserts for programmatic parsing of output.) + */ + bcm_bprintf(&strbuf, "No trap%s in dongle", + (bus->pcie_sh->flags & PCIE_SHARED_ASSERT_BUILT) + ?"/assrt" :""); + } else { + if (bus->pcie_sh->flags & PCIE_SHARED_ASSERT) { + /* Download assert */ + bcm_bprintf(&strbuf, "Dongle assert"); + if (bus->pcie_sh->assert_exp_addr != 0) { + str[0] = '\0'; + if ((bcmerror = dhdpcie_bus_membytes(bus, FALSE, + bus->pcie_sh->assert_exp_addr, + (uint8 *)str, maxstrlen)) < 0) { + goto done; + } + + str[maxstrlen - 1] = '\0'; + bcm_bprintf(&strbuf, " expr \"%s\"", str); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + " expr \"%s\"", str); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + } + + if (bus->pcie_sh->assert_file_addr != 0) { + str[0] = '\0'; + if ((bcmerror = dhdpcie_bus_membytes(bus, FALSE, + bus->pcie_sh->assert_file_addr, + (uint8 *)str, maxstrlen)) < 0) { + goto done; + } + + str[maxstrlen - 1] = '\0'; + bcm_bprintf(&strbuf, " file \"%s\"", str); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + " file \"%s\"", str); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + } + + bcm_bprintf(&strbuf, " line %d ", bus->pcie_sh->assert_line); + } + + if (bus->pcie_sh->flags & PCIE_SHARED_TRAP) { + bus->dhd->dongle_trap_occured = TRUE; + if ((bcmerror = dhdpcie_bus_membytes(bus, FALSE, + bus->pcie_sh->trap_addr, (uint8*)&tr, sizeof(trap_t))) < 0) { + goto done; + } + + bcm_bprintf(&strbuf, + "\nTRAP type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," + " lp 0x%x, rpc 0x%x" + "\nTrap offset 0x%x, r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " + "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", + ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), + ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), + ltoh32(bus->pcie_sh->trap_addr), + ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), + ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); + +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + "\nTRAP type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," + " lp 0x%x, rpc 0x%x" + "\nTrap offset 0x%x, r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " + "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", + ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), + ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), + ltoh32(bus->pcie_sh->trap_addr), + ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), + ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + addr = bus->pcie_sh->console_addr + OFFSETOF(hnd_cons_t, log); + if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, + (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) { + goto printbuf; + } + + addr = bus->pcie_sh->console_addr + OFFSETOF(hnd_cons_t, log.buf_size); + if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, + (uint8 *)&console_size, sizeof(console_size))) < 0) { + goto printbuf; + } + + addr = bus->pcie_sh->console_addr + OFFSETOF(hnd_cons_t, log.idx); + if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, + (uint8 *)&console_index, sizeof(console_index))) < 0) { + goto printbuf; + } + + console_ptr = ltoh32(console_ptr); + console_size = ltoh32(console_size); + console_index = ltoh32(console_index); + + if (console_size > CONSOLE_BUFFER_MAX || + !(console_buffer = MALLOC(bus->dhd->osh, console_size))) { + goto printbuf; + } + + if ((rv = dhdpcie_bus_membytes(bus, FALSE, console_ptr, + (uint8 *)console_buffer, console_size)) < 0) { + goto printbuf; + } + + for (i = 0, n = 0; i < console_size; i += n + 1) { + for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { + ch = console_buffer[(console_index + i + n) % console_size]; + if (ch == '\n') + break; + line[n] = ch; + } + + + if (n > 0) { + if (line[n - 1] == '\r') + n--; + line[n] = 0; + /* Don't use DHD_ERROR macro since we print + * a lot of information quickly. The macro + * will truncate a lot of the printfs + */ + + printf("CONSOLE: %s\n", line); + } + } + } + } + +printbuf: + if (bus->pcie_sh->flags & (PCIE_SHARED_ASSERT | PCIE_SHARED_TRAP)) { + DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); + +#if defined(DHD_FW_COREDUMP) + /* save core dump or write to a file */ + dhdpcie_mem_dump(bus); + + /* Get backtrace in the kernel log. */ + WARN_ON(1); +#endif /* DHD_FW_COREDUMP */ + + + } + +done: + if (mbuffer) + MFREE(bus->dhd->osh, mbuffer, msize); + if (str) + MFREE(bus->dhd->osh, str, maxstrlen); + + if (console_buffer) + MFREE(bus->dhd->osh, console_buffer, console_size); + + return bcmerror; +} /* dhdpcie_checkdied */ + +#if defined(DHD_FW_COREDUMP) +int +dhdpcie_mem_dump(dhd_bus_t *bus) +{ + int ret = 0; + int size; /* Full mem size */ + int start = bus->dongle_ram_base; /* Start address */ + int read_size = 0; /* Read size of each iteration */ + uint8 *buf = NULL, *databuf = NULL; + +#ifdef DHD_USE_IDLECOUNT + DHD_ERROR(("%s: bus_wake\n", __FUNCTION__)); + if (!bus_wake(bus)) { + DHD_ERROR(("%s: bus_wake failed\n", __FUNCTION__)); + return BCME_ERROR; + } +#endif /* DHD_USE_IDLECOUNT */ + +#ifdef SUPPORT_LINKDOWN_RECOVERY + if (bus->islinkdown) { + DHD_ERROR(("%s: PCIe link is down so skip\n", __FUNCTION__)); + return BCME_ERROR; + } +#endif /* SUPPORT_LINKDOWN_RECOVERY */ + + /* Get full mem size */ + size = bus->ramsize; + buf = dhd_get_fwdump_buf(bus->dhd, size); + if (!buf) { + DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size)); + return BCME_ERROR; + } + + /* Read mem content */ + DHD_TRACE(("Dump dongle memory")); + databuf = buf; + while (size) + { + read_size = MIN(MEMBLOCK, size); + if ((ret = dhdpcie_bus_membytes(bus, FALSE, start, databuf, read_size))) + { + DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret)); + return BCME_ERROR; + } + DHD_TRACE((".")); + + /* Decrement size and increment start address */ + size -= read_size; + start += read_size; + databuf += read_size; + } + + dhd_schedule_memdump(bus->dhd, buf, bus->ramsize); + + /* buf, actually soc_ram free handled in dhd_{free,clear} */ + return ret; +} + +int +dhd_bus_mem_dump(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + return dhdpcie_mem_dump(bus); +} +#endif /* DHD_FW_COREDUMP */ + +/** + * Transfers bytes from host to dongle using pio mode. + * Parameter 'address' is a backplane address. + */ +static int +dhdpcie_bus_membytes(dhd_bus_t *bus, bool write, ulong address, uint8 *data, uint size) +{ + int bcmerror = 0; + uint dsize; + int detect_endian_flag = 0x01; + bool little_endian; +#ifdef CONFIG_ARCH_MSM8994 + bool is_64bit_unaligned; +#endif + + /* Detect endianness. */ + little_endian = *(char *)&detect_endian_flag; + +#ifdef CONFIG_ARCH_MSM8994 + /* Check 64bit aligned or not. */ + is_64bit_unaligned = (address & 0x7); +#endif + /* In remap mode, adjust address beyond socram and redirect + * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize + * is not backplane accessible + */ + + /* Determine initial transfer parameters */ +#ifdef DHD_SUPPORT_64BIT + dsize = sizeof(uint64); +#else /* !DHD_SUPPORT_64BIT */ + dsize = sizeof(uint32); +#endif /* DHD_SUPPORT_64BIT */ + + /* Do the transfer(s) */ + if (write) { + while (size) { +#ifdef DHD_SUPPORT_64BIT + if (size >= sizeof(uint64) && little_endian && !(address % 8)) { +#ifdef CONFIG_ARCH_MSM8994 + if (is_64bit_unaligned) { + DHD_INFO(("%s: write unaligned %lx\n", + __FUNCTION__, address)); + dhdpcie_bus_wtcm32(bus, address, *((uint32 *)data)); + data += 4; + size -= 4; + address += 4; + is_64bit_unaligned = (address & 0x7); + continue; + } + else +#endif + dhdpcie_bus_wtcm64(bus, address, *((uint64 *)data)); + } +#else /* !DHD_SUPPORT_64BIT */ + if (size >= sizeof(uint32) && little_endian && !(address % 4)) { + dhdpcie_bus_wtcm32(bus, address, *((uint32*)data)); + } +#endif /* DHD_SUPPORT_64BIT */ + else { + dsize = sizeof(uint8); + dhdpcie_bus_wtcm8(bus, address, *data); + } + + /* Adjust for next transfer (if any) */ + if ((size -= dsize)) { + data += dsize; + address += dsize; + } + } + } else { + while (size) { +#ifdef DHD_SUPPORT_64BIT + if (size >= sizeof(uint64) && little_endian && !(address % 8)) + { +#ifdef CONFIG_ARCH_MSM8994 + if (is_64bit_unaligned) { + DHD_INFO(("%s: read unaligned %lx\n", + __FUNCTION__, address)); + *(uint32 *)data = dhdpcie_bus_rtcm32(bus, address); + data += 4; + size -= 4; + address += 4; + is_64bit_unaligned = (address & 0x7); + continue; + } + else +#endif + *(uint64 *)data = dhdpcie_bus_rtcm64(bus, address); + } +#else /* !DHD_SUPPORT_64BIT */ + if (size >= sizeof(uint32) && little_endian && !(address % 4)) + { + *(uint32 *)data = dhdpcie_bus_rtcm32(bus, address); + } +#endif /* DHD_SUPPORT_64BIT */ + else { + dsize = sizeof(uint8); + *data = dhdpcie_bus_rtcm8(bus, address); + } + + /* Adjust for next transfer (if any) */ + if ((size -= dsize) > 0) { + data += dsize; + address += dsize; + } + } + } + return bcmerror; +} + +int BCMFASTPATH +dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs) +{ + flow_ring_node_t *flow_ring_node; + int ret = BCME_OK; + + DHD_INFO(("%s: flow_id is %d\n", __FUNCTION__, flow_id)); + /* ASSERT on flow_id */ + if (flow_id >= bus->max_sub_queues) { + DHD_ERROR(("%s: flow_id is invalid %d, max %d\n", __FUNCTION__, + flow_id, bus->max_sub_queues)); + return 0; + } + + flow_ring_node = DHD_FLOW_RING(bus->dhd, flow_id); + + { + unsigned long flags; + void *txp = NULL; + flow_queue_t *queue; + + queue = &flow_ring_node->queue; /* queue associated with flow ring */ + + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + + if (flow_ring_node->status != FLOW_RING_STATUS_OPEN) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + return BCME_NOTREADY; + } + + while ((txp = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { + PKTORPHAN(txp); + +#ifdef DHDTCPACK_SUPPRESS + if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_HOLD) { + dhd_tcpack_check_xmit(bus->dhd, txp); + } +#endif /* DHDTCPACK_SUPPRESS */ + /* Attempt to transfer packet over flow ring */ + + ret = dhd_prot_txdata(bus->dhd, txp, flow_ring_node->flow_info.ifindex); + if (ret != BCME_OK) { /* may not have resources in flow ring */ + DHD_INFO(("%s: Reinserrt %d\n", __FUNCTION__, ret)); + dhd_prot_txdata_write_flush(bus->dhd, flow_id, FALSE); + /* reinsert at head */ + dhd_flow_queue_reinsert(bus->dhd, queue, txp); + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + + /* If we are able to requeue back, return success */ + return BCME_OK; + } + } + + dhd_prot_txdata_write_flush(bus->dhd, flow_id, FALSE); + + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + } + + return ret; +} + +#ifndef PCIE_TX_DEFERRAL +/* Send a data frame to the dongle. Callee disposes of txp. */ +int BCMFASTPATH +dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx) +{ + unsigned long flags; + int ret = BCME_OK; + void *txp_pend = NULL; + +#ifdef DHD_USE_IDLECOUNT + bus_wake(bus); +#endif /* DHD_USE_IDLECOUNT */ + if (!bus->txmode_push) { + uint16 flowid; + flow_queue_t *queue; + flow_ring_node_t *flow_ring_node; + if (!bus->dhd->flowid_allocator) { + DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); + goto toss; + } + + flowid = DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(txp)); + + flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); + + DHD_TRACE(("%s: pkt flowid %d, status %d active %d\n", + __FUNCTION__, flowid, flow_ring_node->status, + flow_ring_node->active)); + + if ((flowid >= bus->dhd->num_flow_rings) || + (!flow_ring_node->active) || + (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING)) { + DHD_INFO(("%s: Dropping pkt flowid %d, status %d active %d\n", + __FUNCTION__, flowid, flow_ring_node->status, + flow_ring_node->active)); + ret = BCME_ERROR; + goto toss; + } + + queue = &flow_ring_node->queue; /* queue associated with flow ring */ + + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + + if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp)) != BCME_OK) + txp_pend = txp; + + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + + if (flow_ring_node->status) { + DHD_INFO(("%s: Enq pkt flowid %d, status %d active %d\n", + __FUNCTION__, flowid, flow_ring_node->status, + flow_ring_node->active)); + if (txp_pend) { + txp = txp_pend; + goto toss; + } + return BCME_OK; + } + ret = dhd_bus_schedule_queue(bus, flowid, FALSE); + + /* If we have anything pending, try to push into q */ + if (txp_pend) { + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + + if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp_pend)) != BCME_OK) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + txp = txp_pend; + goto toss; + } + + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + } + + return ret; + + } else { /* bus->txmode_push */ + return dhd_prot_txdata(bus->dhd, txp, ifidx); + } + +toss: + DHD_INFO(("%s: Toss %d\n", __FUNCTION__, ret)); + PKTCFREE(bus->dhd->osh, txp, TRUE); + return ret; +} +#else /* PCIE_TX_DEFERRAL */ +int BCMFASTPATH +dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx) +{ + unsigned long flags; + int ret = BCME_OK; + uint16 flowid; + flow_queue_t *queue; + flow_ring_node_t *flow_ring_node; + uint8 *pktdata = (uint8 *)PKTDATA(bus->dhd->osh, txp); + struct ether_header *eh = (struct ether_header *)pktdata; + + if (!bus->dhd->flowid_allocator) { + DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); + goto toss; + } + + flowid = dhd_flowid_find(bus->dhd, ifidx, + bus->dhd->flow_prio_map[(PKTPRIO(txp))], + eh->ether_shost, eh->ether_dhost); + if (flowid == FLOWID_INVALID) { + DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(txp), ifidx); + skb_queue_tail(&bus->orphan_list, txp); + queue_work(bus->tx_wq, &bus->create_flow_work); + return BCME_OK; + } + + DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(txp), flowid); + flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); + queue = &flow_ring_node->queue; /* queue associated with flow ring */ + + DHD_DATA(("%s: pkt flowid %d, status %d active %d\n", + __FUNCTION__, flowid, flow_ring_node->status, + flow_ring_node->active)); + + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + if ((flowid >= bus->dhd->num_flow_rings) || + (!flow_ring_node->active) || + (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING)) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + DHD_DATA(("%s: Dropping pkt flowid %d, status %d active %d\n", + __FUNCTION__, flowid, flow_ring_node->status, + flow_ring_node->active)); + ret = BCME_ERROR; + goto toss; + } + + if (flow_ring_node->status == FLOW_RING_STATUS_PENDING) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(txp), ifidx); + skb_queue_tail(&bus->orphan_list, txp); + queue_work(bus->tx_wq, &bus->create_flow_work); + return BCME_OK; + } + + if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp)) != BCME_OK) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + goto toss; + } + + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + + ret = dhd_bus_schedule_queue(bus, flowid, FALSE); + + return ret; + +toss: + DHD_DATA(("%s: Toss %d\n", __FUNCTION__, ret)); + PKTCFREE(bus->dhd->osh, txp, TRUE); + return ret; +} +#endif /* !PCIE_TX_DEFERRAL */ + + +void +dhd_bus_stop_queue(struct dhd_bus *bus) +{ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); + bus->bus_flowctrl = TRUE; +} + +void +dhd_bus_start_queue(struct dhd_bus *bus) +{ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); + bus->bus_flowctrl = TRUE; +} + +void +dhd_bus_update_retlen(dhd_bus_t *bus, uint32 retlen, uint32 pkt_id, uint16 status, + uint32 resp_len) +{ + bus->ioct_resp.cmn_hdr.request_id = pkt_id; + bus->ioct_resp.compl_hdr.status = status; + bus->ioct_resp.resp_len = (uint16)resp_len; + + bus->rxlen = retlen; +} + +#if defined(DHD_DEBUG) +/* Device console input function */ +int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen) +{ + dhd_bus_t *bus = dhd->bus; + uint32 addr, val; + int rv; + /* Address could be zero if CONSOLE := 0 in dongle Makefile */ + if (bus->console_addr == 0) + return BCME_UNSUPPORTED; + + /* Don't allow input if dongle is in reset */ + if (bus->dhd->dongle_reset) { + dhd_os_sdunlock(bus->dhd); + return BCME_NOTREADY; + } + +#ifdef DHD_USE_IDLECOUNT + bus_wake(bus); +#endif /* DHD_USE_IDLECOUNT */ + /* Zero cbuf_index */ + addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx); + val = htol32(0); + if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) + goto done; + + /* Write message into cbuf */ + addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf); + if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) + goto done; + + /* Write length into vcons_in */ + addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in); + val = htol32(msglen); + if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) + goto done; + + /* generate an interurpt to dongle to indicate that it needs to process cons command */ + dhdpcie_send_mb_data(bus, H2D_HOST_CONS_INT); +done: + return rv; +} +#endif /* defined(DHD_DEBUG) */ + +/* Process rx frame , Send up the layer to netif */ +void BCMFASTPATH +dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count) +{ +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif + dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, 0); +} + +#ifdef CONFIG_ARCH_MSM8994 +static ulong dhd_bus_cmn_check_offset(dhd_bus_t *bus, ulong offset) +{ + uint new_bar1_wbase = 0; + ulong address = 0; + + new_bar1_wbase = (uint)offset & bus->bar1_win_mask; + if (bus->bar1_win_base != new_bar1_wbase) { + bus->bar1_win_base = new_bar1_wbase; + dhdpcie_bus_cfg_set_bar1_win(bus, bus->bar1_win_base); + DHD_ERROR(("%s: offset=%lx, switch bar1_win_base to %x\n", + __FUNCTION__, offset, bus->bar1_win_base)); + } + + address = offset - bus->bar1_win_base; + + return address; +} +#else +#define dhd_bus_cmn_check_offset(x, y) y +#endif /* CONFIG_ARCH_MSM8994 */ + +/** 'offset' is a backplane address */ +void +dhdpcie_bus_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data) +{ + W_REG(bus->dhd->osh, + (volatile uint8 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)), data); +} + +uint8 +dhdpcie_bus_rtcm8(dhd_bus_t *bus, ulong offset) +{ + volatile uint8 data; + + data = R_REG(bus->dhd->osh, + (volatile uint8 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset))); + + return data; +} + +void +dhdpcie_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data) +{ + W_REG(bus->dhd->osh, + (volatile uint32 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)), data); +} +void +dhdpcie_bus_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data) +{ + W_REG(bus->dhd->osh, + (volatile uint16 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)), data); +} +#ifdef DHD_SUPPORT_64BIT +void +dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data) +{ + W_REG(bus->dhd->osh, + (volatile uint64 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)), data); +} +#endif /* DHD_SUPPORT_64BIT */ + +uint16 +dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset) +{ + volatile uint16 data; + data = R_REG(bus->dhd->osh, + (volatile uint16 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset))); + return data; +} + +uint32 +dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset) +{ + volatile uint32 data; + data = R_REG(bus->dhd->osh, + (volatile uint32 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset))); + return data; +} +#ifdef DHD_SUPPORT_64BIT +uint64 +dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset) +{ + volatile uint64 data; + data = R_REG(bus->dhd->osh, + (volatile uint64 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset))); + return data; +} +#endif /* DHD_SUPPORT_64BIT */ + +void +dhd_bus_cmn_writeshared(dhd_bus_t *bus, void * data, uint32 len, uint8 type, uint16 ringid) +{ + uint64 long_data; + ulong tcm_offset; + pciedev_shared_t *sh; + pciedev_shared_t *shmem = NULL; + + sh = (pciedev_shared_t*)bus->shared_addr; + + DHD_INFO(("%s: writing to msgbuf type %d, len %d\n", __FUNCTION__, type, len)); + + switch (type) { + case DNGL_TO_HOST_DMA_SCRATCH_BUFFER: + long_data = HTOL64(*(uint64 *)data); + tcm_offset = (ulong)&(sh->host_dma_scratch_buffer); + dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); + prhex(__FUNCTION__, data, len); + break; + + case DNGL_TO_HOST_DMA_SCRATCH_BUFFER_LEN : + tcm_offset = (ulong)&(sh->host_dma_scratch_buffer_len); + dhdpcie_bus_wtcm32(bus, tcm_offset, (uint32) HTOL32(*(uint32 *)data)); + prhex(__FUNCTION__, data, len); + break; + + case HOST_TO_DNGL_DMA_WRITEINDX_BUFFER: + /* ring_info_ptr stored in pcie_sh */ + shmem = (pciedev_shared_t *)bus->pcie_sh; + + long_data = HTOL64(*(uint64 *)data); + tcm_offset = (ulong)shmem->rings_info_ptr; + tcm_offset += OFFSETOF(ring_info_t, h2d_w_idx_hostaddr); + dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); + prhex(__FUNCTION__, data, len); + break; + + case HOST_TO_DNGL_DMA_READINDX_BUFFER: + /* ring_info_ptr stored in pcie_sh */ + shmem = (pciedev_shared_t *)bus->pcie_sh; + + long_data = HTOL64(*(uint64 *)data); + tcm_offset = (ulong)shmem->rings_info_ptr; + tcm_offset += OFFSETOF(ring_info_t, h2d_r_idx_hostaddr); + dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); + prhex(__FUNCTION__, data, len); + break; + + case DNGL_TO_HOST_DMA_WRITEINDX_BUFFER: + /* ring_info_ptr stored in pcie_sh */ + shmem = (pciedev_shared_t *)bus->pcie_sh; + + long_data = HTOL64(*(uint64 *)data); + tcm_offset = (ulong)shmem->rings_info_ptr; + tcm_offset += OFFSETOF(ring_info_t, d2h_w_idx_hostaddr); + dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); + prhex(__FUNCTION__, data, len); + break; + + case DNGL_TO_HOST_DMA_READINDX_BUFFER: + /* ring_info_ptr stored in pcie_sh */ + shmem = (pciedev_shared_t *)bus->pcie_sh; + + long_data = HTOL64(*(uint64 *)data); + tcm_offset = (ulong)shmem->rings_info_ptr; + tcm_offset += OFFSETOF(ring_info_t, d2h_r_idx_hostaddr); + dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len); + prhex(__FUNCTION__, data, len); + break; + + case RING_LEN_ITEMS : + tcm_offset = bus->ring_sh[ringid].ring_mem_addr; + tcm_offset += OFFSETOF(ring_mem_t, len_items); + dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data)); + break; + + case RING_MAX_ITEM : + tcm_offset = bus->ring_sh[ringid].ring_mem_addr; + tcm_offset += OFFSETOF(ring_mem_t, max_item); + dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data)); + break; + + case RING_BUF_ADDR : + long_data = HTOL64(*(uint64 *)data); + tcm_offset = bus->ring_sh[ringid].ring_mem_addr; + tcm_offset += OFFSETOF(ring_mem_t, base_addr); + dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8 *) &long_data, len); + prhex(__FUNCTION__, data, len); + break; + + case RING_WRITE_PTR : + tcm_offset = bus->ring_sh[ringid].ring_state_w; + dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data)); + break; + case RING_READ_PTR : + tcm_offset = bus->ring_sh[ringid].ring_state_r; + dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data)); + break; + + case DTOH_MB_DATA: + dhdpcie_bus_wtcm32(bus, bus->d2h_mb_data_ptr_addr, + (uint32) HTOL32(*(uint32 *)data)); + break; + + case HTOD_MB_DATA: + dhdpcie_bus_wtcm32(bus, bus->h2d_mb_data_ptr_addr, + (uint32) HTOL32(*(uint32 *)data)); + break; + default: + break; + } +} + + +void +dhd_bus_cmn_readshared(dhd_bus_t *bus, void* data, uint8 type, uint16 ringid) +{ + pciedev_shared_t *sh; + ulong tcm_offset; + + sh = (pciedev_shared_t*)bus->shared_addr; + + switch (type) { + case RING_WRITE_PTR : + tcm_offset = bus->ring_sh[ringid].ring_state_w; + *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset)); + break; + case RING_READ_PTR : + tcm_offset = bus->ring_sh[ringid].ring_state_r; + *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset)); + break; + case TOTAL_LFRAG_PACKET_CNT : + *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, + (ulong) &sh->total_lfrag_pkt_cnt)); + break; + case HTOD_MB_DATA: + *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->h2d_mb_data_ptr_addr)); + break; + case DTOH_MB_DATA: + *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->d2h_mb_data_ptr_addr)); + break; + case MAX_HOST_RXBUFS : + *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, + (ulong) &sh->max_host_rxbufs)); + break; + default : + break; + } +} + +uint32 dhd_bus_get_sharedflags(dhd_bus_t *bus) +{ + return ((pciedev_shared_t*)bus->pcie_sh)->flags; +} + +void +dhd_bus_clearcounts(dhd_pub_t *dhdp) +{ +} + +int +dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + dhd_bus_t *bus = dhdp->bus; + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + uint32 actionid; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(name); + ASSERT(len >= 0); + + /* Get MUST have return space */ + ASSERT(set || (arg && len)); + + /* Set does NOT take qualifiers */ + ASSERT(!set || (!params && !plen)); + + DHD_INFO(("%s: %s %s, len %d plen %d\n", __FUNCTION__, + name, (set ? "set" : "get"), len, plen)); + + /* Look up var locally; if not found pass to host driver */ + if ((vi = bcm_iovar_lookup(dhdpcie_iovars, name)) == NULL) { + goto exit; + } + + + /* set up 'params' pointer in case this is a set command so that + * the convenience int and bool code can be common to set and get + */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + /* all other types are integer sized */ + val_size = sizeof(int); + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + bcmerror = dhdpcie_bus_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); + +exit: + return bcmerror; +} + +#ifdef BCM_BUZZZ +#include + +int dhd_buzzz_dump_cntrs3(char *p, uint32 *core, uint32 * ovhd, uint32 *log) +{ + int bytes = 0; + uint32 ctr, curr[3], prev[3], delta[3]; + + /* Compute elapsed counter values per counter event type */ + for (ctr = 0U; ctr < 3; ctr++) { + prev[ctr] = core[ctr]; + curr[ctr] = *log++; + core[ctr] = curr[ctr]; /* saved for next log */ + + if (curr[ctr] < prev[ctr]) + delta[ctr] = curr[ctr] + (~0U - prev[ctr]); + else + delta[ctr] = (curr[ctr] - prev[ctr]); + + /* Adjust for instrumentation overhead */ + if (delta[ctr] >= ovhd[ctr]) + delta[ctr] -= ovhd[ctr]; + else + delta[ctr] = 0; + + bytes += sprintf(p + bytes, "%12u ", delta[ctr]); + } + + return bytes; +} + +typedef union cm3_cnts { /* export this in bcm_buzzz.h */ + uint32 u32; + uint8 u8[4]; + struct { + uint8 cpicnt; + uint8 exccnt; + uint8 sleepcnt; + uint8 lsucnt; + }; +} cm3_cnts_t; + +int dhd_buzzz_dump_cntrs6(char *p, uint32 *core, uint32 * ovhd, uint32 *log) +{ + int bytes = 0; + + uint32 cyccnt, instrcnt; + cm3_cnts_t cm3_cnts; + uint8 foldcnt; + + { /* 32bit cyccnt */ + uint32 curr, prev, delta; + prev = core[0]; curr = *log++; core[0] = curr; + if (curr < prev) + delta = curr + (~0U - prev); + else + delta = (curr - prev); + if (delta >= ovhd[0]) + delta -= ovhd[0]; + else + delta = 0; + + bytes += sprintf(p + bytes, "%12u ", delta); + cyccnt = delta; + } + + { /* Extract the 4 cnts: cpi, exc, sleep and lsu */ + int i; + uint8 max8 = ~0; + cm3_cnts_t curr, prev, delta; + prev.u32 = core[1]; curr.u32 = * log++; core[1] = curr.u32; + for (i = 0; i < 4; i++) { + if (curr.u8[i] < prev.u8[i]) + delta.u8[i] = curr.u8[i] + (max8 - prev.u8[i]); + else + delta.u8[i] = (curr.u8[i] - prev.u8[i]); + if (delta.u8[i] >= ovhd[i + 1]) + delta.u8[i] -= ovhd[i + 1]; + else + delta.u8[i] = 0; + bytes += sprintf(p + bytes, "%4u ", delta.u8[i]); + } + cm3_cnts.u32 = delta.u32; + } + + { /* Extract the foldcnt from arg0 */ + uint8 curr, prev, delta, max8 = ~0; + buzzz_arg0_t arg0; arg0.u32 = *log; + prev = core[2]; curr = arg0.klog.cnt; core[2] = curr; + if (curr < prev) + delta = curr + (max8 - prev); + else + delta = (curr - prev); + if (delta >= ovhd[5]) + delta -= ovhd[5]; + else + delta = 0; + bytes += sprintf(p + bytes, "%4u ", delta); + foldcnt = delta; + } + + instrcnt = cyccnt - (cm3_cnts.u8[0] + cm3_cnts.u8[1] + cm3_cnts.u8[2] + + cm3_cnts.u8[3]) + foldcnt; + if (instrcnt > 0xFFFFFF00) + bytes += sprintf(p + bytes, "[%10s] ", "~"); + else + bytes += sprintf(p + bytes, "[%10u] ", instrcnt); + return bytes; +} + +int dhd_buzzz_dump_log(char * p, uint32 * core, uint32 * log, buzzz_t * buzzz) +{ + int bytes = 0; + buzzz_arg0_t arg0; + static uint8 * fmt[] = BUZZZ_FMT_STRINGS; + + if (buzzz->counters == 6) { + bytes += dhd_buzzz_dump_cntrs6(p, core, buzzz->ovhd, log); + log += 2; /* 32bit cyccnt + (4 x 8bit) CM3 */ + } else { + bytes += dhd_buzzz_dump_cntrs3(p, core, buzzz->ovhd, log); + log += 3; /* (3 x 32bit) CR4 */ + } + + /* Dump the logged arguments using the registered formats */ + arg0.u32 = *log++; + + switch (arg0.klog.args) { + case 0: + bytes += sprintf(p + bytes, fmt[arg0.klog.id]); + break; + case 1: + { + uint32 arg1 = *log++; + bytes += sprintf(p + bytes, fmt[arg0.klog.id], arg1); + break; + } + default: + printf("Maximum one argument supported\n"); + break; + } + bytes += sprintf(p + bytes, "\n"); + + return bytes; +} + +void dhd_buzzz_dump(buzzz_t * buzzz_p, void * buffer_p, char * p) +{ + int i; + uint32 total, part1, part2, log_sz, core[BUZZZ_COUNTERS_MAX]; + void * log; + + for (i = 0; i < BUZZZ_COUNTERS_MAX; i++) + core[i] = 0; + + log_sz = buzzz_p->log_sz; + + part1 = ((uint32)buzzz_p->cur - (uint32)buzzz_p->log) / log_sz; + + if (buzzz_p->wrap == TRUE) { + part2 = ((uint32)buzzz_p->end - (uint32)buzzz_p->cur) / log_sz; + total = (buzzz_p->buffer_sz - BUZZZ_LOGENTRY_MAXSZ) / log_sz; + } else { + part2 = 0U; + total = buzzz_p->count; + } + + if (total == 0U) { + printf("buzzz_dump total<%u> done\n", total); + return; + } else { + printf("buzzz_dump total<%u> : part2<%u> + part1<%u>\n", + total, part2, part1); + } + + if (part2) { /* with wrap */ + log = (void*)((size_t)buffer_p + (buzzz_p->cur - buzzz_p->log)); + while (part2--) { /* from cur to end : part2 */ + p[0] = '\0'; + dhd_buzzz_dump_log(p, core, (uint32 *)log, buzzz_p); + printf("%s", p); + log = (void*)((size_t)log + buzzz_p->log_sz); + } + } + + log = (void*)buffer_p; + while (part1--) { + p[0] = '\0'; + dhd_buzzz_dump_log(p, core, (uint32 *)log, buzzz_p); + printf("%s", p); + log = (void*)((size_t)log + buzzz_p->log_sz); + } + + printf("buzzz_dump done.\n"); +} + +int dhd_buzzz_dump_dngl(dhd_bus_t *bus) +{ + buzzz_t * buzzz_p = NULL; + void * buffer_p = NULL; + char * page_p = NULL; + pciedev_shared_t *sh; + int ret = 0; + + if (bus->dhd->busstate != DHD_BUS_DATA) { + return BCME_UNSUPPORTED; + } + if ((page_p = (char *)MALLOC(bus->dhd->osh, 4096)) == NULL) { + printf("Page memory allocation failure\n"); + goto done; + } + if ((buzzz_p = MALLOC(bus->dhd->osh, sizeof(buzzz_t))) == NULL) { + printf("Buzzz memory allocation failure\n"); + goto done; + } + + ret = dhdpcie_readshared(bus); + if (ret < 0) { + DHD_ERROR(("%s :Shared area read failed \n", __FUNCTION__)); + goto done; + } + + sh = bus->pcie_sh; + + DHD_INFO(("%s buzzz:%08x\n", __FUNCTION__, sh->buzzz)); + + if (sh->buzzz != 0U) { /* Fetch and display dongle BUZZZ Trace */ + dhdpcie_bus_membytes(bus, FALSE, (ulong)sh->buzzz, + (uint8 *)buzzz_p, sizeof(buzzz_t)); + if (buzzz_p->count == 0) { + printf("Empty dongle BUZZZ trace\n\n"); + goto done; + } + if (buzzz_p->counters != 3) { /* 3 counters for CR4 */ + printf("Counters<%u> mismatch\n", buzzz_p->counters); + goto done; + } + /* Allocate memory for trace buffer and format strings */ + buffer_p = MALLOC(bus->dhd->osh, buzzz_p->buffer_sz); + if (buffer_p == NULL) { + printf("Buffer memory allocation failure\n"); + goto done; + } + /* Fetch the trace and format strings */ + dhdpcie_bus_membytes(bus, FALSE, (uint32)buzzz_p->log, /* Trace */ + (uint8 *)buffer_p, buzzz_p->buffer_sz); + /* Process and display the trace using formatted output */ + printf("<#cycle> <#instruction> <#ctr3> \n"); + dhd_buzzz_dump(buzzz_p, buffer_p, page_p); + printf("----- End of dongle BUZZZ Trace -----\n\n"); + MFREE(bus->dhd->osh, buffer_p, buzzz_p->buffer_sz); buffer_p = NULL; + } + +done: + + if (page_p) MFREE(bus->dhd->osh, page_p, 4096); + if (buzzz_p) MFREE(bus->dhd->osh, buzzz_p, sizeof(buzzz_t)); + if (buffer_p) MFREE(bus->dhd->osh, buffer_p, buzzz_p->buffer_sz); + + return BCME_OK; +} +#endif /* BCM_BUZZZ */ + +#define PCIE_GEN2(sih) ((BUSTYPE((sih)->bustype) == PCI_BUS) && \ + ((sih)->buscoretype == PCIE2_CORE_ID)) + +int +dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) +{ + dhd_bus_t *bus = dhdp->bus; + int bcmerror = 0; +#ifdef CONFIG_ARCH_MSM + int retry = POWERUP_MAX_RETRY; +#endif /* CONFIG_ARCH_MSM */ + + if (dhd_download_fw_on_driverload) { + bcmerror = dhd_bus_start(dhdp); + } else { + if (flag == TRUE) { /* Turn off WLAN */ + /* Ensure everything is on before accesssing registers. */ +#ifdef DHD_USE_IDLECOUNT + if (!bus_wake(bus)) { + DHD_ERROR(("%s Couldn't wake. Start clock.\n", __FUNCTION__)); + bcmerror = dhdpcie_bus_clock_start(bus); + if (bcmerror) { + DHD_ERROR(("%s: Reenable clock %d\n", + __FUNCTION__, bcmerror)); + } + } +#endif /* DHD_USE_IDLECOUNT */ + /* Removing Power */ + DHD_ERROR(("%s: == Power OFF ==\n", __FUNCTION__)); + mutex_lock(&bus->pm_lock); + bus->dhd->up = FALSE; + if (bus->dhd->busstate != DHD_BUS_DOWN) { + if (bus->intr) { + dhdpcie_bus_intr_disable(bus); + dhdpcie_free_irq(bus); + } +#ifdef BCMPCIE_OOB_HOST_WAKE + /* Clean up any pending host wake IRQ */ + dhd_bus_oob_intr_set(bus->dhd, FALSE); + dhd_bus_oob_intr_unregister(bus->dhd); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + dhd_os_wd_timer(dhdp, 0); + dhd_bus_stop(bus, TRUE); + dhd_prot_clear(dhdp); + dhd_clear(dhdp); + dhd_bus_release_dongle(bus); + dhdpcie_bus_free_resource(bus); + bcmerror = dhdpcie_bus_disable_device(bus); + if (bcmerror) { + DHD_ERROR(("%s: dhdpcie_bus_disable_device: %d\n", + __FUNCTION__, bcmerror)); + mutex_unlock(&bus->pm_lock); + goto done; + } +#ifdef CONFIG_ARCH_MSM + bcmerror = dhdpcie_bus_clock_stop(bus); + if (bcmerror) { + DHD_ERROR(("%s: host clock stop failed: %d\n", + __FUNCTION__, bcmerror)); + mutex_unlock(&bus->pm_lock); + goto done; + } +#endif /* CONFIG_ARCH_MSM */ + bus->dhd->busstate = DHD_BUS_DOWN; + } else { + if (bus->intr) { + dhdpcie_free_irq(bus); + } +#ifdef BCMPCIE_OOB_HOST_WAKE + /* Clean up any pending host wake IRQ */ + dhd_bus_oob_intr_set(bus->dhd, FALSE); + dhd_bus_oob_intr_unregister(bus->dhd); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + dhd_prot_clear(dhdp); + dhd_clear(dhdp); + dhd_bus_release_dongle(bus); + dhdpcie_bus_free_resource(bus); + bcmerror = dhdpcie_bus_disable_device(bus); + if (bcmerror) { + DHD_ERROR(("%s: dhdpcie_bus_disable_device: %d\n", + __FUNCTION__, bcmerror)); + mutex_unlock(&bus->pm_lock); + goto done; + } + +#ifdef CONFIG_ARCH_MSM + bcmerror = dhdpcie_bus_clock_stop(bus); + if (bcmerror) { + DHD_ERROR(("%s: host clock stop failed: %d\n", + __FUNCTION__, bcmerror)); + mutex_unlock(&bus->pm_lock); + goto done; + } +#endif /* CONFIG_ARCH_MSM */ + } + + bus->dhd->dongle_reset = TRUE; + mutex_unlock(&bus->pm_lock); + DHD_ERROR(("%s: WLAN OFF Done\n", __FUNCTION__)); + + } else { /* Turn on WLAN */ + if (bus->dhd->busstate == DHD_BUS_DOWN) { + /* Powering On */ + DHD_ERROR(("%s: == Power ON ==\n", __FUNCTION__)); +#ifdef CONFIG_ARCH_MSM + while (--retry) { + bcmerror = dhdpcie_bus_clock_start(bus); + if (!bcmerror) { + DHD_ERROR(("%s: dhdpcie_bus_clock_start OK\n", + __FUNCTION__)); + break; + } + else + OSL_SLEEP(10); + } + + if (bcmerror && !retry) { + DHD_ERROR(("%s: host pcie clock enable failed: %d\n", + __FUNCTION__, bcmerror)); + goto done; + } +#endif /* CONFIG_ARCH_MSM */ + bcmerror = dhdpcie_bus_enable_device(bus); + if (bcmerror) { + DHD_ERROR(("%s: host configuration restore failed: %d\n", + __FUNCTION__, bcmerror)); + goto done; + } + + bcmerror = dhdpcie_bus_alloc_resource(bus); + if (bcmerror) { + DHD_ERROR(("%s: dhdpcie_bus_resource_alloc failed: %d\n", + __FUNCTION__, bcmerror)); + goto done; + } + + bcmerror = dhdpcie_bus_dongle_attach(bus); + if (bcmerror) { + DHD_ERROR(("%s: dhdpcie_bus_dongle_attach failed: %d\n", + __FUNCTION__, bcmerror)); + goto done; + } + + bcmerror = dhd_bus_request_irq(bus); + if (bcmerror) { + DHD_ERROR(("%s: dhd_bus_request_irq failed: %d\n", + __FUNCTION__, bcmerror)); + goto done; + } + + bus->dhd->dongle_reset = FALSE; + + bcmerror = dhd_bus_start(dhdp); + if (bcmerror) { + DHD_ERROR(("%s: dhd_bus_start: %d\n", + __FUNCTION__, bcmerror)); + goto done; + } + + bus->dhd->up = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; + bus->idletime = (int32)MAX_IDLE_COUNT; + bus->host_suspend = FALSE; + init_waitqueue_head(&bus->rpm_queue); +#endif /* DHD_USE_IDLECOUNT */ + DHD_ERROR(("%s: WLAN Power On Done\n", __FUNCTION__)); + } else { + DHD_ERROR(("%s: what should we do here\n", __FUNCTION__)); + goto done; + } + } + } +done: + if (bcmerror) + bus->dhd->busstate = DHD_BUS_DOWN; + + return bcmerror; +} + +static int +dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, + void *params, int plen, void *arg, int len, int val_size) +{ + int bcmerror = 0; + int32 int_val = 0; + int32 int_val2 = 0; + int32 int_val3 = 0; + bool bool_val = 0; + + DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", + __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) + goto exit; + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + if (plen >= (int)sizeof(int_val) * 2) + bcopy((void*)((uintptr)params + sizeof(int_val)), &int_val2, sizeof(int_val2)); + + if (plen >= (int)sizeof(int_val) * 3) + bcopy((void*)((uintptr)params + 2 * sizeof(int_val)), &int_val3, sizeof(int_val3)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + + /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ + if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || + actionid == IOV_GVAL(IOV_DEVRESET))) { + bcmerror = BCME_NOTREADY; + goto exit; + } + +#ifdef DHD_USE_IDLECOUNT + bus_wake(bus); +#endif /* DHD_USE_IDLECOUNT */ + switch (actionid) { + + + case IOV_SVAL(IOV_VARS): + bcmerror = dhdpcie_downloadvars(bus, arg, len); + break; + + case IOV_SVAL(IOV_PCIE_LPBK): + bcmerror = dhdpcie_bus_lpback_req(bus, int_val); + break; + + case IOV_SVAL(IOV_PCIE_DMAXFER): + bcmerror = dhdpcie_bus_dmaxfer_req(bus, int_val, int_val2, int_val3); + break; + + case IOV_GVAL(IOV_PCIE_SUSPEND): + int_val = (bus->dhd->busstate == DHD_BUS_SUSPEND) ? 1 : 0; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PCIE_SUSPEND): + bus->force_suspend = 1; + dhdpcie_bus_suspend(bus, bool_val); + bus->force_suspend = 0; + break; + + case IOV_GVAL(IOV_MEMSIZE): + int_val = (int32)bus->ramsize; + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_MEMBYTES): + case IOV_GVAL(IOV_MEMBYTES): + { + uint32 address; /* absolute backplane address */ + uint size, dsize; + uint8 *data; + + bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); + + ASSERT(plen >= 2*sizeof(int)); + + address = (uint32)int_val; + bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); + size = (uint)int_val; + + /* Do some validation */ + dsize = set ? plen - (2 * sizeof(int)) : len; + if (dsize < size) { + DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", + __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); + bcmerror = BCME_BADARG; + break; + } + + DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n dsize %d ", __FUNCTION__, + (set ? "write" : "read"), size, address, dsize)); + + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + if (set && address == bus->dongle_ram_base) { + bus->resetinstr = *(((uint32*)params) + 2); + } + } else { + /* If we know about SOCRAM, check for a fit */ + if ((bus->orig_ramsize) && + ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) + { + uint8 enable, protect, remap; + si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); + if (!enable || protect) { + DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", + __FUNCTION__, bus->orig_ramsize, size, address)); + DHD_ERROR(("%s: socram enable %d, protect %d\n", + __FUNCTION__, enable, protect)); + bcmerror = BCME_BADARG; + break; + } + + if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { + uint32 devramsize = si_socdevram_size(bus->sih); + if ((address < SOCDEVRAM_ARM_ADDR) || + (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { + DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n", + __FUNCTION__, address, size)); + DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n", + __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize)); + bcmerror = BCME_BADARG; + break; + } + /* move it such that address is real now */ + address -= SOCDEVRAM_ARM_ADDR; + address += SOCDEVRAM_BP_ADDR; + DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", + __FUNCTION__, (set ? "write" : "read"), size, address)); + } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { + /* Can not access remap region while devram remap bit is set + * ROM content would be returned in this case + */ + DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n", + __FUNCTION__, address)); + bcmerror = BCME_ERROR; + break; + } + } + } + + /* Generate the actual data pointer */ + data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; + + /* Call to do the transfer */ + bcmerror = dhdpcie_bus_membytes(bus, set, address, data, size); + + break; + } + +#ifdef BCM_BUZZZ + case IOV_GVAL(IOV_BUZZZ_DUMP): + bcmerror = dhd_buzzz_dump_dngl(bus); + break; +#endif /* BCM_BUZZZ */ + + case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): + bcmerror = dhdpcie_bus_download_state(bus, bool_val); + break; + + case IOV_GVAL(IOV_RAMSIZE): + int_val = (int32)bus->ramsize; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_RAMSTART): + int_val = (int32)bus->dongle_ram_base; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_CC_NVMSHADOW): + { + struct bcmstrbuf dump_b; + + bcm_binit(&dump_b, arg, len); + bcmerror = dhdpcie_cc_nvmshadow(bus, &dump_b); + break; + } + + case IOV_GVAL(IOV_SLEEP_ALLOWED): + bool_val = bus->sleep_allowed; + bcopy(&bool_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SLEEP_ALLOWED): + bus->sleep_allowed = bool_val; + break; + + case IOV_GVAL(IOV_DONGLEISOLATION): + int_val = bus->dhd->dongle_isolation; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DONGLEISOLATION): + bus->dhd->dongle_isolation = bool_val; + break; + + case IOV_GVAL(IOV_LTRSLEEPON_UNLOOAD): + int_val = bus->ltrsleep_on_unload; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_LTRSLEEPON_UNLOOAD): + bus->ltrsleep_on_unload = bool_val; + break; + + case IOV_GVAL(IOV_DUMP_RINGUPD_BLOCK): + { + struct bcmstrbuf dump_b; + bcm_binit(&dump_b, arg, len); + bcmerror = dhd_prot_ringupd_dump(bus->dhd, &dump_b); + break; + } + case IOV_GVAL(IOV_DMA_RINGINDICES): + { int h2d_support, d2h_support; + + d2h_support = DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support) ? 1 : 0; + h2d_support = DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support) ? 1 : 0; + int_val = d2h_support | (h2d_support << 1); + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + case IOV_SVAL(IOV_DMA_RINGINDICES): + /* Can change it only during initialization/FW download */ + if (bus->dhd->busstate == DHD_BUS_DOWN) { + if ((int_val > 3) || (int_val < 0)) { + DHD_ERROR(("Bad argument. Possible values: 0, 1, 2 & 3\n")); + bcmerror = BCME_BADARG; + } else { + bus->dhd->dma_d2h_ring_upd_support = (int_val & 1) ? TRUE : FALSE; + bus->dhd->dma_h2d_ring_upd_support = (int_val & 2) ? TRUE : FALSE; + } + } else { + DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", + __FUNCTION__)); + bcmerror = BCME_NOTDOWN; + } + break; + + case IOV_GVAL(IOV_RX_METADATALEN): + int_val = dhd_prot_metadatalen_get(bus->dhd, TRUE); + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RX_METADATALEN): + if (int_val > 64) { + bcmerror = BCME_BUFTOOLONG; + break; + } + dhd_prot_metadatalen_set(bus->dhd, int_val, TRUE); + break; + + case IOV_SVAL(IOV_TXP_THRESHOLD): + dhd_prot_txp_threshold(bus->dhd, TRUE, int_val); + break; + + case IOV_GVAL(IOV_TXP_THRESHOLD): + int_val = dhd_prot_txp_threshold(bus->dhd, FALSE, int_val); + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DB1_FOR_MB): + if (int_val) + bus->db1_for_mb = TRUE; + else + bus->db1_for_mb = FALSE; + break; + + case IOV_GVAL(IOV_DB1_FOR_MB): + if (bus->db1_for_mb) + int_val = 1; + else + int_val = 0; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_TX_METADATALEN): + int_val = dhd_prot_metadatalen_get(bus->dhd, FALSE); + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TX_METADATALEN): + if (int_val > 64) { + bcmerror = BCME_BUFTOOLONG; + break; + } + dhd_prot_metadatalen_set(bus->dhd, int_val, FALSE); + break; + + case IOV_GVAL(IOV_FLOW_PRIO_MAP): + int_val = bus->dhd->flow_prio_map_type; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_FLOW_PRIO_MAP): + int_val = (int32)dhd_update_flow_prio_map(bus->dhd, (uint8)int_val); + bcopy(&int_val, arg, val_size); + break; + +#ifdef DHD_USE_IDLECOUNT + case IOV_GVAL(IOV_IDLETIME): + int_val = bus->idletime; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_IDLETIME): + if (int_val < 0) { + bcmerror = BCME_BADARG; + } else { + bus->idletime = int_val; + } + break; +#endif /* DHD_USE_IDLECOUNT */ + + case IOV_GVAL(IOV_TXBOUND): + int_val = (int32)dhd_txbound; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TXBOUND): + dhd_txbound = (uint)int_val; + break; + + case IOV_GVAL(IOV_RXBOUND): + int_val = (int32)dhd_rxbound; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RXBOUND): + dhd_rxbound = (uint)int_val; + break; + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } + +exit: + return bcmerror; +} + +/* Transfers bytes from host to dongle using pio mode */ +static int +dhdpcie_bus_lpback_req(struct dhd_bus *bus, uint32 len) +{ + if (bus->dhd == NULL) { + DHD_ERROR(("bus not inited\n")); + return 0; + } + if (bus->dhd->prot == NULL) { + DHD_ERROR(("prot is not inited\n")); + return 0; + } + if (bus->dhd->busstate != DHD_BUS_DATA) { + DHD_ERROR(("not in a readystate to LPBK is not inited\n")); + return 0; + } + dhdmsgbuf_lpbk_req(bus->dhd, len); + return 0; +} + +void +dhd_bus_set_suspend_resume(dhd_pub_t *dhdp, bool state) +{ + struct dhd_bus *bus = dhdp->bus; + if (bus) { + dhdpcie_bus_suspend(bus, state); + } +} + +int +dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) +{ + + int timeleft; + bool pending; + unsigned long flags; + int rc = 0; + + struct net_device *netdev = NULL; + dhd_pub_t *pub = (dhd_pub_t *)(bus->dhd); + netdev = dhd_idx2net(pub, 0); + + if (bus->dhd == NULL) { + DHD_ERROR(("bus not inited\n")); + return BCME_ERROR; + } + if (bus->dhd->prot == NULL) { + DHD_ERROR(("prot is not inited\n")); + return BCME_ERROR; + } + DHD_GENERAL_LOCK(bus->dhd, flags); + if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) { + DHD_ERROR(("not in a readystate to LPBK is not inited\n")); + DHD_GENERAL_UNLOCK(bus->dhd, flags); + return BCME_ERROR; + } + DHD_GENERAL_UNLOCK(bus->dhd, flags); + if (bus->dhd->dongle_reset) + return -EIO; + + if (bus->suspended == state) /* Set to same state */ + return BCME_OK; + + if (state) { + DHD_GENERAL_LOCK(bus->dhd, flags); + /* Atomically check we can suspend and flag suspend, set busstate */ + if (!bus->force_suspend && dhd_os_check_wakelock_all(bus->dhd)) { + DHD_ERROR(("Suspend failed because of wakelock " + "before sending D3_INFORM\n")); +#ifdef DHD_USE_IDLECOUNT + if (bus->host_suspend == TRUE) { + bus->host_suspend = FALSE; + } +#endif /* DHD_USE_IDLECOUNT */ + DHD_GENERAL_UNLOCK(bus->dhd, flags); + return BCME_ERROR; + } + bus->wait_for_d3_ack = 0; + bus->suspended = TRUE; + bus->dhd->busstate = DHD_BUS_SUSPEND; +#ifndef DHD_USE_IDLECOUNT + netif_stop_queue(netdev); +#endif /* DHD_USE_IDLECOUNT */ + DHD_INFO(("prepare in suspend mode stop net device traffic\n")); + if (bus->dhd->tx_in_progress) { + DHD_ERROR(("Tx Request is not ended\n")); + bus->dhd->busstate = DHD_BUS_DATA; +#ifdef DHD_USE_IDLECOUNT + if (bus->host_suspend == TRUE) { + bus->host_suspend = FALSE; + } +#else + DHD_INFO(("1. fail to suspend, start net device traffic\n")); + netif_start_queue(netdev); +#endif /* DHD_USE_IDLECOUNT */ + + bus->wait_for_d3_ack = 1; + DHD_GENERAL_UNLOCK(bus->dhd, flags); + bus->suspended = FALSE; + return -EBUSY; + } + DHD_GENERAL_UNLOCK(bus->dhd, flags); + DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); + dhd_os_set_ioctl_resp_timeout(D3_ACK_RESP_TIMEOUT); + dhdpcie_send_mb_data(bus, H2D_HOST_D3_INFORM); + timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack, &pending); + dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); + DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); + + /* If wait_for_d3_ack was not updated because D2H MB was not received */ + if (bus->wait_for_d3_ack == 0) { + /* Check the mailbox anyway. */ + dhdpcie_handle_mb_data(bus); + if (bus->wait_for_d3_ack) { + DHD_ERROR(("D3ack without interrupt.\n")); + bus->d3_ack_war_cnt++; + } + } + + if (bus->wait_for_d3_ack) { +#if defined(BCMPCIE_OOB_HOST_WAKE) + dhdpcie_oob_intr_set(bus, TRUE); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + /* Got D3 Ack. Suspend the bus */ + DHD_GENERAL_LOCK(bus->dhd, flags); + if (!bus->force_suspend && dhd_os_check_wakelock_all(bus->dhd)) { + DHD_ERROR(("%s():Suspend failed because of wakelock " + "restoring Dongle to D0\n", __FUNCTION__)); + + /* + * Dongle still thinks that it has to be in D3 state until + * it gets a D0 Inform, but we are backing off from suspend. + * Ensure that Dongle is brought back to D0. + * + * Bringing back Dongle from D3 Ack state to D0 state is a + * 2 step process. Dongle would want to know that D0 Inform + * would be sent as a MB interrupt to bring it out of D3 Ack + * state to D0 state. So we have to send both this message. + */ + DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); + dhdpcie_send_mb_data(bus, + (H2D_HOST_D0_INFORM_IN_USE|H2D_HOST_D0_INFORM)); + DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); + + bus->suspended = FALSE; + bus->dhd->busstate = DHD_BUS_DATA; + rc = BCME_ERROR; +#ifdef DHD_USE_IDLECOUNT + if (bus->host_suspend == TRUE) { + bus->host_suspend = FALSE; + } +#else + DHD_INFO(("2. fail to suspend, start net device traffic\n")); + netif_start_queue(netdev); +#endif /* DHD_USE_IDLECOUNT */ + DHD_GENERAL_UNLOCK(bus->dhd, flags); + } else { + DHD_GENERAL_UNLOCK(bus->dhd, flags); + DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); + dhdpcie_send_mb_data(bus, H2D_HOST_D0_INFORM_IN_USE); + DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); + dhdpcie_bus_intr_disable(bus); + rc = dhdpcie_pci_suspend_resume(bus, state); +#ifdef DHD_USE_IDLECOUNT + if (bus->host_suspend == TRUE) { + dhdpcie_bus_clock_stop(bus); + } +#endif /* DHD_USE_IDLECOUNT */ + } + bus->dhd->d3ackcnt_timeout = 0; + } else if (timeleft == 0) { + bus->dhd->d3ackcnt_timeout++; + DHD_ERROR(("%s: resumed on timeout for D3 ACK d3ackcnt_timeout %d \n", + __FUNCTION__, bus->dhd->d3ackcnt_timeout)); +#if defined(DHD_FW_COREDUMP) + if (bus->dhd->d3ackcnt_timeout == 1) { + /* write core dump to file */ + dhdpcie_mem_dump(bus); + } +#endif /* DHD_FW_COREDUMP */ + bus->suspended = FALSE; + DHD_GENERAL_LOCK(bus->dhd, flags); + bus->dhd->busstate = DHD_BUS_DATA; +#ifdef DHD_USE_IDLECOUNT + if (bus->host_suspend == TRUE) { + bus->host_suspend = FALSE; + } +#else + DHD_INFO(("3. fail to suspend, start net device traffic\n")); + netif_start_queue(netdev); +#endif /* DHD_USE_IDLECOUNT */ + DHD_GENERAL_UNLOCK(bus->dhd, flags); + if (bus->dhd->d3ackcnt_timeout >= MAX_CNTL_D3ACK_TIMEOUT) { + DHD_ERROR(("%s: Event HANG send up " + "due to PCIe linkdown\n", __FUNCTION__)); +#ifdef SUPPORT_LINKDOWN_RECOVERY +#ifdef CONFIG_ARCH_MSM + bus->islinkdown = TRUE; +#endif /* CONFIG_ARCH_MSM */ +#endif /* SUPPORT_LINKDOWN_RECOVERY */ + dhd_os_check_hang(bus->dhd, 0, -ETIMEDOUT); + } + rc = -ETIMEDOUT; + } + bus->wait_for_d3_ack = 1; + } else { + /* Resume */ +#ifdef BCMPCIE_OOB_HOST_WAKE + DHD_OS_OOB_IRQ_WAKE_UNLOCK(bus->dhd); +#endif /* BCMPCIE_OOB_HOST_WAKE */ +#ifdef DHD_USE_IDLECOUNT + /* wake up host controller if suspend with runtime PM */ + if (bus->host_suspend == TRUE) { + dhdpcie_bus_clock_start(bus); + } +#endif /* DHD_USE_IDLECOUNT */ + rc = dhdpcie_pci_suspend_resume(bus, state); + if (bus->dhd->busstate == DHD_BUS_SUSPEND) { + DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); + dhdpcie_send_mb_data(bus, H2D_HOST_D0_INFORM); + DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); + } + bus->suspended = FALSE; + DHD_GENERAL_LOCK(bus->dhd, flags); + bus->dhd->busstate = DHD_BUS_DATA; + DHD_GENERAL_UNLOCK(bus->dhd, flags); + DHD_INFO(("Resume completed, start net device traffic\n")); + /* resume all interface network queue. */ + dhd_bus_start_queue(bus); + dhdpcie_bus_intr_enable(bus); +#ifdef DHD_USE_IDLECOUNT + /* wake up host controller if suspend with runtime PM */ + if (bus->host_suspend == TRUE) { + bus->host_suspend = FALSE; + } +#endif /* DHD_USE_IDLECOUNT */ + } + return rc; +} + +/* Transfers bytes from host to dongle and to host again using DMA */ +static int +dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus, uint32 len, uint32 srcdelay, uint32 destdelay) +{ + if (bus->dhd == NULL) { + DHD_ERROR(("bus not inited\n")); + return BCME_ERROR; + } + if (bus->dhd->prot == NULL) { + DHD_ERROR(("prot is not inited\n")); + return BCME_ERROR; + } + if (bus->dhd->busstate != DHD_BUS_DATA) { + DHD_ERROR(("not in a readystate to LPBK is not inited\n")); + return BCME_ERROR; + } + + if (len < 5 || len > 4194296) { + DHD_ERROR(("len is too small or too large\n")); + return BCME_ERROR; + } + return dhdmsgbuf_dmaxfer_req(bus->dhd, len, srcdelay, destdelay); +} + + + +static int +dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter) +{ + int bcmerror = 0; + uint32 *cr4_regs; + + if (!bus->sih) + return BCME_ERROR; + /* 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; + + /* some chips (e.g. 43602) have two ARM cores, the CR4 is receives the firmware. */ + cr4_regs = si_setcore(bus->sih, ARMCR4_CORE_ID, 0); + + if (cr4_regs == NULL && !(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && + !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + if (cr4_regs == NULL) { /* no CR4 present on chip */ + si_core_disable(bus->sih, 0); + + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + si_core_reset(bus->sih, 0, 0); + + + /* Clear the top bit of memory */ + if (bus->ramsize) { + uint32 zeros = 0; + if (dhdpcie_bus_membytes(bus, TRUE, bus->ramsize - 4, + (uint8*)&zeros, 4) < 0) { + bcmerror = BCME_ERROR; + goto fail; + } + } + } else { + /* For CR4, + * Halt ARM + * Remove ARM reset + * Read RAM base address [0x18_0000] + * [next] Download firmware + * [done at else] Populate the reset vector + * [done at else] Remove ARM halt + */ + /* Halt ARM & remove reset */ + si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); + if (bus->sih->chip == BCM43602_CHIP_ID) { + W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKIDX, 5); + W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKPDA, 0); + W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKIDX, 7); + W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKPDA, 0); + } + /* reset last 4 bytes of RAM address. to be used for shared area */ + dhdpcie_init_shared_addr(bus); + } + } else { + if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + if (!si_iscoreup(bus->sih)) { + DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + + /* Enable remap before ARM reset but after vars. + * No backplane access in remap mode + */ + + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && + !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + + if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && + !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + } else { + if (bus->sih->chip == BCM43602_CHIP_ID) { + /* Firmware crashes on SOCSRAM access when core is in reset */ + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", + __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + si_core_reset(bus->sih, 0, 0); + si_setcore(bus->sih, ARMCR4_CORE_ID, 0); + } + + /* write vars */ + if ((bcmerror = dhdpcie_bus_write_vars(bus))) { + DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); + goto fail; + } + + + /* switch back to arm core again */ + if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + /* write address 0 with reset instruction */ + bcmerror = dhdpcie_bus_membytes(bus, TRUE, 0, + (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); + + /* now remove reset and halt and continue to run CR4 */ + } + + si_core_reset(bus->sih, 0, 0); + + /* Allow HT Clock now that the ARM is running. */ + bus->alp_only = FALSE; + + bus->dhd->busstate = DHD_BUS_LOAD; + } + +fail: + /* Always return to PCIE core */ + si_setcore(bus->sih, PCIE2_CORE_ID, 0); + + return bcmerror; +} + +static int +dhdpcie_bus_write_vars(dhd_bus_t *bus) +{ + int bcmerror = 0; + uint32 varsize, phys_size; + uint32 varaddr; + uint8 *vbuffer; + uint32 varsizew; +#ifdef DHD_DEBUG + uint8 *nvram_ularray; +#endif /* DHD_DEBUG */ + + /* 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; + + varaddr += bus->dongle_ram_base; + + if (bus->vars) { + + vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); + if (!vbuffer) + return BCME_NOMEM; + + bzero(vbuffer, varsize); + bcopy(bus->vars, vbuffer, bus->varsz); + /* Write the vars list */ + bcmerror = dhdpcie_bus_membytes(bus, TRUE, varaddr, vbuffer, varsize); + + /* Implement read back and verify later */ +#ifdef DHD_DEBUG + /* Verify NVRAM bytes */ + DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); + nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); + if (!nvram_ularray) + return BCME_NOMEM; + + /* Upload image to verify downloaded contents. */ + memset(nvram_ularray, 0xaa, varsize); + + /* Read the vars list to temp buffer for comparison */ + bcmerror = dhdpcie_bus_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", + __FUNCTION__, bcmerror, varsize, varaddr)); + } + + /* Compare the org NVRAM with the one read from RAM */ + if (memcmp(vbuffer, nvram_ularray, varsize)) { + DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); + } else + DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", + __FUNCTION__)); + + MFREE(bus->dhd->osh, nvram_ularray, varsize); +#endif /* DHD_DEBUG */ + + MFREE(bus->dhd->osh, vbuffer, varsize); + } + + phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; + + phys_size += bus->dongle_ram_base; + + /* adjust to the user specified RAM */ + DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", + phys_size, bus->ramsize)); + DHD_INFO(("Vars are at %d, orig varsize is %d\n", + varaddr, varsize)); + varsize = ((phys_size - 4) - varaddr); + + /* + * Determine the length token: + * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. + */ + if (bcmerror) { + varsizew = 0; + bus->nvram_csm = varsizew; + } else { + varsizew = varsize / 4; + varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); + bus->nvram_csm = varsizew; + varsizew = htol32(varsizew); + } + + DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); + + /* Write the length token to the last word */ + bcmerror = dhdpcie_bus_membytes(bus, TRUE, (phys_size - 4), + (uint8*)&varsizew, 4); + + return bcmerror; +} + +int +dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len) +{ + int bcmerror = BCME_OK; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Basic sanity checks */ + if (bus->dhd->up) { + bcmerror = BCME_NOTDOWN; + goto err; + } + if (!len) { + bcmerror = BCME_BUFTOOSHORT; + goto err; + } + + /* Free the old ones and replace with passed variables */ + if (bus->vars) + MFREE(bus->dhd->osh, bus->vars, bus->varsz); + + bus->vars = MALLOC(bus->dhd->osh, len); + bus->varsz = bus->vars ? len : 0; + if (bus->vars == NULL) { + bcmerror = BCME_NOMEM; + goto err; + } + + /* Copy the passed variables, which should include the terminating double-null */ + bcopy(arg, bus->vars, bus->varsz); + + +err: + return bcmerror; +} + +#ifndef BCMPCIE_OOB_HOST_WAKE +/* loop through the capability list and see if the pcie capabilty exists */ +uint8 +dhdpcie_find_pci_capability(osl_t *osh, uint8 req_cap_id) +{ + uint8 cap_id; + uint8 cap_ptr = 0; + uint8 byte_val; + + /* check for Header type 0 */ + byte_val = read_pci_cfg_byte(PCI_CFG_HDR); + if ((byte_val & 0x7f) != PCI_HEADER_NORMAL) { + DHD_ERROR(("%s : PCI config header not normal.\n", __FUNCTION__)); + goto end; + } + + /* check if the capability pointer field exists */ + byte_val = read_pci_cfg_byte(PCI_CFG_STAT); + if (!(byte_val & PCI_CAPPTR_PRESENT)) { + DHD_ERROR(("%s : PCI CAP pointer not present.\n", __FUNCTION__)); + goto end; + } + + cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR); + /* check if the capability pointer is 0x00 */ + if (cap_ptr == 0x00) { + DHD_ERROR(("%s : PCI CAP pointer is 0x00.\n", __FUNCTION__)); + goto end; + } + + /* loop thr'u the capability list and see if the pcie capabilty exists */ + + cap_id = read_pci_cfg_byte(cap_ptr); + + while (cap_id != req_cap_id) { + cap_ptr = read_pci_cfg_byte((cap_ptr + 1)); + if (cap_ptr == 0x00) break; + cap_id = read_pci_cfg_byte(cap_ptr); + } + +end: + return cap_ptr; +} + +void +dhdpcie_pme_active(osl_t *osh, bool enable) +{ + uint8 cap_ptr; + uint32 pme_csr; + + cap_ptr = dhdpcie_find_pci_capability(osh, PCI_CAP_POWERMGMTCAP_ID); + + if (!cap_ptr) { + DHD_ERROR(("%s : Power Management Capability not present\n", __FUNCTION__)); + return; + } + + pme_csr = OSL_PCI_READ_CONFIG(osh, cap_ptr + PME_CSR_OFFSET, sizeof(uint32)); + DHD_ERROR(("%s : pme_sts_ctrl 0x%x suspend(%d)\n", __FUNCTION__, pme_csr, enable)); + + pme_csr |= PME_CSR_PME_STAT; + if (enable) { + pme_csr |= PME_CSR_PME_EN; + } else { + pme_csr &= ~PME_CSR_PME_EN; + } + + OSL_PCI_WRITE_CONFIG(osh, cap_ptr + PME_CSR_OFFSET, sizeof(uint32), pme_csr); +} +#endif /* BCMPCIE_OOB_HOST_WAKE */ + +/* Add bus dump output to a buffer */ +void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + uint16 flowid; + flow_ring_node_t *flow_ring_node; + +#ifdef DHD_USE_IDLECOUNT + bus_wake(dhdp->bus); +#endif /* DHD_USE_IDLECOUNT */ + dhd_prot_print_info(dhdp, strbuf); + for (flowid = 0; flowid < dhdp->num_flow_rings; flowid++) { + flow_ring_node = DHD_FLOW_RING(dhdp, flowid); + if (flow_ring_node->active) { + bcm_bprintf(strbuf, "Flow:%d IF %d Prio %d Qlen %d ", + flow_ring_node->flowid, flow_ring_node->flow_info.ifindex, + flow_ring_node->flow_info.tid, flow_ring_node->queue.len); + dhd_prot_print_flow_ring(dhdp, flow_ring_node->prot_info, strbuf); + } + } + bcm_bprintf(strbuf, "D0 inform cnt %d\n", dhdp->bus->d0_inform_cnt); + bcm_bprintf(strbuf, "D0 inform in use cnt %d\n", dhdp->bus->d0_inform_in_use_cnt); + bcm_bprintf(strbuf, "D3 Ack WAR cnt %d\n", dhdp->bus->d3_ack_war_cnt); +} + +static void +dhd_update_txflowrings(dhd_pub_t *dhd) +{ + dll_t *item, *next; + flow_ring_node_t *flow_ring_node; + struct dhd_bus *bus = dhd->bus; + + for (item = dll_head_p(&bus->const_flowring); + !dll_end(&bus->const_flowring, item); item = next) { + if (dhd->hang_was_sent) { + break; + } + + next = dll_next_p(item); + + flow_ring_node = dhd_constlist_to_flowring(item); + dhd_prot_update_txflowring(dhd, flow_ring_node->flowid, flow_ring_node->prot_info); + } +} + +/* Mailbox ringbell Function */ +static void +dhd_bus_gen_devmb_intr(struct dhd_bus *bus) +{ + if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || + (bus->sih->buscorerev == 4)) { + DHD_ERROR(("mailbox communication not supported\n")); + return; + } + if (bus->db1_for_mb) { + /* this is a pcie core register, not the config regsiter */ + DHD_INFO(("writing a mail box interrupt to the device, through doorbell 1\n")); + si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_DB1, ~0, 0x12345678); + } + else { + DHD_INFO(("writing a mail box interrupt to the device, through config space\n")); + dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0)); + dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0)); + } +} + +/* doorbell ring Function */ +void +dhd_bus_ringbell(struct dhd_bus *bus, uint32 value) +{ + if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || + (bus->sih->buscorerev == 4)) { + si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, PCIE_INTB, PCIE_INTB); + } else { + /* this is a pcie core register, not the config regsiter */ + DHD_INFO(("writing a door bell to the device\n")); + si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_MailBox, ~0, 0x12345678); + } +} + +static void +dhd_bus_ringbell_fast(struct dhd_bus *bus, uint32 value) +{ + if (bus->pcie_mb_intr_addr) { + W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr, value); + } +} + +static void +dhd_bus_ringbell_oldpcie(struct dhd_bus *bus, uint32 value) +{ + uint32 w; + w = (R_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr) & ~PCIE_INTB) | PCIE_INTB; + W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr, w); +} + +dhd_mb_ring_t +dhd_bus_get_mbintr_fn(struct dhd_bus *bus) +{ + if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || + (bus->sih->buscorerev == 4)) { + bus->pcie_mb_intr_addr = si_corereg_addr(bus->sih, bus->sih->buscoreidx, + PCIMailBoxInt); + if (bus->pcie_mb_intr_addr) { + bus->pcie_mb_intr_osh = si_osh(bus->sih); + return dhd_bus_ringbell_oldpcie; + } + } else { + bus->pcie_mb_intr_addr = si_corereg_addr(bus->sih, bus->sih->buscoreidx, + PCIH2D_MailBox); + if (bus->pcie_mb_intr_addr) { + bus->pcie_mb_intr_osh = si_osh(bus->sih); + return dhd_bus_ringbell_fast; + } + } + return dhd_bus_ringbell; +} + +bool BCMFASTPATH +dhd_bus_dpc(struct dhd_bus *bus) +{ + uint32 intstatus = 0; + uint32 newstatus = 0; + bool resched = FALSE; /* Flag indicating resched wanted */ + unsigned long flags; + + DHD_INTR(("%s: Enter\n", __FUNCTION__)); + + DHD_GENERAL_LOCK(bus->dhd, flags); + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); + bus->intstatus = 0; + DHD_GENERAL_UNLOCK(bus->dhd, flags); + return 0; + } + DHD_GENERAL_UNLOCK(bus->dhd, flags); + + bus->ipend = FALSE; + intstatus = bus->intstatus; + + if ((bus->sih->buscorerev == 6) || (bus->sih->buscorerev == 4) || + (bus->sih->buscorerev == 2)) { + newstatus = dhdpcie_bus_cfg_read_dword(bus, PCIIntstatus, 4); + dhdpcie_bus_cfg_write_dword(bus, PCIIntstatus, 4, newstatus); + /* Merge new bits with previous */ + intstatus |= newstatus; + bus->intstatus = 0; + if (intstatus & I_MB) { + resched = dhdpcie_bus_process_mailbox_intr(bus, intstatus); + } + } else { + /* this is a PCIE core register..not a config register... */ + newstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); + intstatus |= (newstatus & bus->def_intmask); + si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, newstatus, newstatus); + if (intstatus & bus->def_intmask) { + resched = dhdpcie_bus_process_mailbox_intr(bus, intstatus); + intstatus &= ~bus->def_intmask; + } + } + + if (!resched) { + bus->intstatus = 0; + DHD_INTR(("%s: enable PCIE interrupts\n", __FUNCTION__)); + dhdpcie_bus_intr_enable(bus); + } + + DHD_INTR(("%s: Exit %d\n", __FUNCTION__, resched)); + return resched; + +} + + +static void +dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data) +{ + uint32 cur_h2d_mb_data = 0; + + DHD_INFO_HW4(("%s: H2D_MB_DATA: 0x%08X\n", __FUNCTION__, h2d_mb_data)); + dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, HTOD_MB_DATA, 0); + + if (cur_h2d_mb_data != 0) { + uint32 i = 0; + DHD_INFO(("GRRRRRRR: MB transaction is already pending 0x%04x\n", cur_h2d_mb_data)); + while ((i++ < 100) && cur_h2d_mb_data) { + OSL_DELAY(10); + dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, HTOD_MB_DATA, 0); + } + if (i >= 100) + DHD_ERROR(("waited 1ms for the dngl to ack the previous mb transaction\n")); + } + + dhd_bus_cmn_writeshared(bus, &h2d_mb_data, sizeof(uint32), HTOD_MB_DATA, 0); + dhd_bus_gen_devmb_intr(bus); + + if (h2d_mb_data == H2D_HOST_D3_INFORM) + DHD_INFO_HW4(("%s: send H2D_HOST_D3_INFORM to dongle\n", __FUNCTION__)); + if (h2d_mb_data == H2D_HOST_D0_INFORM_IN_USE) { + DHD_INFO_HW4(("%s: send H2D_HOST_D0_INFORM_IN_USE to dongle\n", __FUNCTION__)); + bus->d0_inform_in_use_cnt++; + } + if (h2d_mb_data == H2D_HOST_D0_INFORM) { + DHD_INFO_HW4(("%s: send H2D_HOST_D0_INFORM to dongle\n", __FUNCTION__)); + bus->d0_inform_cnt++; + } +} + +static void +dhdpcie_handle_mb_data(dhd_bus_t *bus) +{ + uint32 d2h_mb_data = 0; + uint32 zero = 0; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ + + dhd_bus_cmn_readshared(bus, &d2h_mb_data, DTOH_MB_DATA, 0); + if (D2H_DEV_MB_INVALIDATED(d2h_mb_data)) { + DHD_INFO_HW4(("%s: Invalid D2H_MB_DATA: 0x%08x\n", + __FUNCTION__, d2h_mb_data)); + return; + } + + dhd_bus_cmn_writeshared(bus, &zero, sizeof(uint32), DTOH_MB_DATA, 0); + + DHD_INFO_HW4(("D2H_MB_DATA: 0x%08x\n", d2h_mb_data)); + if (d2h_mb_data & D2H_DEV_DS_ENTER_REQ) { + /* what should we do */ + DHD_INFO(("D2H_MB_DATA: DEEP SLEEP REQ\n")); + dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); + DHD_INFO(("D2H_MB_DATA: sent DEEP SLEEP ACK\n")); + } + if (d2h_mb_data & D2H_DEV_DS_EXIT_NOTE) { + /* what should we do */ + DHD_INFO(("D2H_MB_DATA: DEEP SLEEP EXIT\n")); + } + if (d2h_mb_data & D2H_DEV_D3_ACK) { + /* what should we do */ + DHD_INFO_HW4(("%s D2H_MB_DATA: Received D3 ACK\n", __FUNCTION__)); + if (!bus->wait_for_d3_ack) { + bus->wait_for_d3_ack = 1; + dhd_os_d3ack_wake(bus->dhd); + } + } + if (d2h_mb_data & D2H_DEV_FWHALT) { + DHD_INFO(("FW trap has happened\n")); +#ifdef DHD_DEBUG + dhdpcie_checkdied(bus, NULL, 0); +#endif + bus->dhd->busstate = DHD_BUS_DOWN; + } +} + +static bool +dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus) +{ + bool resched = FALSE; + + if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || + (bus->sih->buscorerev == 4)) { + /* Msg stream interrupt */ + if (intstatus & I_BIT1) { + resched = dhdpci_bus_read_frames(bus); + } else if (intstatus & I_BIT0) { + /* do nothing for Now */ + } + } + else { + if (intstatus & (PCIE_MB_TOPCIE_FN0_0 | PCIE_MB_TOPCIE_FN0_1)) + dhdpcie_handle_mb_data(bus); + + if (bus->dhd->busstate == DHD_BUS_SUSPEND) { + goto exit; + } + + if (intstatus & PCIE_MB_D2H_MB_MASK) { + resched = dhdpci_bus_read_frames(bus); + } + } +exit: + return resched; +} + +/* Decode dongle to host message stream */ +static bool +dhdpci_bus_read_frames(dhd_bus_t *bus) +{ + bool more = FALSE; + +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ + /* There may be frames in both ctrl buf and data buf; check ctrl buf first */ + DHD_PERIM_LOCK(bus->dhd); /* Take the perimeter lock */ + dhd_prot_process_ctrlbuf(bus->dhd); + /* Unlock to give chance for resp to be handled */ + DHD_PERIM_UNLOCK(bus->dhd); /* Release the perimeter lock */ + + DHD_PERIM_LOCK(bus->dhd); /* Take the perimeter lock */ + /* update the flow ring cpls */ + dhd_update_txflowrings(bus->dhd); + + /* With heavy TX traffic, we could get a lot of TxStatus + * so add bound + */ + more |= dhd_prot_process_msgbuf_txcpl(bus->dhd, dhd_txbound); + + /* With heavy RX traffic, this routine potentially could spend some time + * processing RX frames without RX bound + */ + more |= dhd_prot_process_msgbuf_rxcpl(bus->dhd, dhd_rxbound); + + /* don't talk to the dongle if fw is about to be reloaded */ + if (bus->dhd->hang_was_sent) { + more = FALSE; + } + DHD_PERIM_UNLOCK(bus->dhd); /* Release the perimeter lock */ + + return more; +} + +static int +dhdpcie_readshared(dhd_bus_t *bus) +{ + uint32 addr = 0; + int rv, w_init, r_init; + uint32 shaddr = 0; + pciedev_shared_t *sh = bus->pcie_sh; + dhd_timeout_t tmo; + + shaddr = bus->dongle_ram_base + bus->ramsize - 4; + /* start a timer for 5 seconds */ + dhd_timeout_start(&tmo, MAX_READ_TIMEOUT); + + while (((addr == 0) || (addr == bus->nvram_csm)) && !dhd_timeout_expired(&tmo)) { + /* Read last word in memory to determine address of sdpcm_shared structure */ + addr = LTOH32(dhdpcie_bus_rtcm32(bus, shaddr)); + } + + if ((addr == 0) || (addr == bus->nvram_csm) || (addr < bus->dongle_ram_base) || + (addr > shaddr)) { + DHD_ERROR(("%s: address (0x%08x) of pciedev_shared invalid\n", + __FUNCTION__, addr)); + DHD_ERROR(("Waited %u usec, dongle is not ready\n", tmo.elapsed)); + return BCME_ERROR; + } else { + bus->shared_addr = (ulong)addr; + DHD_ERROR(("PCIe shared addr read took %u usec " + "before dongle is ready\n", tmo.elapsed)); + } + + /* Read hndrte_shared structure */ + if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)sh, + sizeof(pciedev_shared_t))) < 0) { + DHD_ERROR(("Failed to read PCIe shared struct," + "size read %d < %d\n", rv, (int)sizeof(pciedev_shared_t))); + return rv; + } + + /* Endianness */ + sh->flags = ltoh32(sh->flags); + sh->trap_addr = ltoh32(sh->trap_addr); + sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); + sh->assert_file_addr = ltoh32(sh->assert_file_addr); + sh->assert_line = ltoh32(sh->assert_line); + sh->console_addr = ltoh32(sh->console_addr); + sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); + sh->dma_rxoffset = ltoh32(sh->dma_rxoffset); + sh->rings_info_ptr = ltoh32(sh->rings_info_ptr); + /* load bus console address */ + +#ifdef DHD_DEBUG + bus->console_addr = sh->console_addr; +#endif + + /* Read the dma rx offset */ + bus->dma_rxoffset = bus->pcie_sh->dma_rxoffset; + dhd_prot_rx_dataoffset(bus->dhd, bus->dma_rxoffset); + + DHD_ERROR(("DMA RX offset from shared Area %d\n", bus->dma_rxoffset)); + + if ((sh->flags & PCIE_SHARED_VERSION_MASK) > PCIE_SHARED_VERSION) { + DHD_ERROR(("%s: pcie_shared version %d in dhd " + "is older than pciedev_shared version %d in dongle\n", + __FUNCTION__, PCIE_SHARED_VERSION, + sh->flags & PCIE_SHARED_VERSION_MASK)); + return BCME_ERROR; + } + if ((sh->flags & PCIE_SHARED_VERSION_MASK) >= 4) { + if (sh->flags & PCIE_SHARED_TXPUSH_SPRT) { +#ifdef DHDTCPACK_SUPPRESS + /* Do not use tcpack suppress as packets don't stay in queue */ + dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); +#endif + bus->txmode_push = TRUE; + } else + bus->txmode_push = FALSE; + } + DHD_ERROR(("bus->txmode_push is set to %d\n", bus->txmode_push)); + + /* Does the FW support DMA'ing r/w indices */ + if (sh->flags & PCIE_SHARED_DMA_INDEX) { + + DHD_ERROR(("%s: Host support DMAing indices: H2D:%d - D2H:%d. FW supports it\n", + __FUNCTION__, + (DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support) ? 1 : 0), + (DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support) ? 1 : 0))); + + } else if (DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support) || + DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support)) { + +#ifdef BCM_INDX_DMA + DHD_ERROR(("%s: Incompatible FW. FW does not support DMAing indices\n", + __FUNCTION__)); + return BCME_ERROR; +#endif + DHD_ERROR(("%s: Host supports DMAing indices but FW does not\n", + __FUNCTION__)); + bus->dhd->dma_d2h_ring_upd_support = FALSE; + bus->dhd->dma_h2d_ring_upd_support = FALSE; + } + + + /* get ring_info, ring_state and mb data ptrs and store the addresses in bus structure */ + { + ring_info_t ring_info; + + if ((rv = dhdpcie_bus_membytes(bus, FALSE, sh->rings_info_ptr, + (uint8 *)&ring_info, sizeof(ring_info_t))) < 0) + return rv; + + bus->h2d_mb_data_ptr_addr = ltoh32(sh->h2d_mb_data_ptr); + bus->d2h_mb_data_ptr_addr = ltoh32(sh->d2h_mb_data_ptr); + + + bus->max_sub_queues = ltoh16(ring_info.max_sub_queues); + + /* If both FW and Host support DMA'ing indices, allocate memory and notify FW + * The max_sub_queues is read from FW initialized ring_info + */ + if (DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support)) { + w_init = dhd_prot_init_index_dma_block(bus->dhd, + HOST_TO_DNGL_DMA_WRITEINDX_BUFFER, + bus->max_sub_queues); + r_init = dhd_prot_init_index_dma_block(bus->dhd, + DNGL_TO_HOST_DMA_READINDX_BUFFER, + BCMPCIE_D2H_COMMON_MSGRINGS); + + if ((w_init != BCME_OK) || (r_init != BCME_OK)) { + DHD_ERROR(("%s: Failed to allocate memory for dma'ing h2d indices" + "Host will use w/r indices in TCM\n", + __FUNCTION__)); + bus->dhd->dma_h2d_ring_upd_support = FALSE; + } + } + + if (DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support)) { + w_init = dhd_prot_init_index_dma_block(bus->dhd, + DNGL_TO_HOST_DMA_WRITEINDX_BUFFER, + BCMPCIE_D2H_COMMON_MSGRINGS); + r_init = dhd_prot_init_index_dma_block(bus->dhd, + HOST_TO_DNGL_DMA_READINDX_BUFFER, + bus->max_sub_queues); + + if ((w_init != BCME_OK) || (r_init != BCME_OK)) { + DHD_ERROR(("%s: Failed to allocate memory for dma'ing d2h indices" + "Host will use w/r indices in TCM\n", + __FUNCTION__)); + bus->dhd->dma_d2h_ring_upd_support = FALSE; + } + } + + /* read ringmem and ringstate ptrs from shared area and store in host variables */ + dhd_fillup_ring_sharedptr_info(bus, &ring_info); + + bcm_print_bytes("ring_info_raw", (uchar *)&ring_info, sizeof(ring_info_t)); + DHD_INFO(("ring_info\n")); + + DHD_ERROR(("max H2D queues %d\n", ltoh16(ring_info.max_sub_queues))); + + DHD_INFO(("mail box address\n")); + DHD_INFO(("h2d_mb_data_ptr_addr 0x%04x\n", bus->h2d_mb_data_ptr_addr)); + DHD_INFO(("d2h_mb_data_ptr_addr 0x%04x\n", bus->d2h_mb_data_ptr_addr)); + } + + bus->dhd->d2h_sync_mode = sh->flags & PCIE_SHARED_D2H_SYNC_MODE_MASK; + DHD_INFO(("d2h_sync_mode 0x%08x\n", bus->dhd->d2h_sync_mode)); + + return BCME_OK; +} +/* Read ring mem and ring state ptr info from shared are in TCM */ +static void +dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info) +{ + uint16 i = 0; + uint16 j = 0; + uint32 tcm_memloc; + uint32 d2h_w_idx_ptr, d2h_r_idx_ptr, h2d_w_idx_ptr, h2d_r_idx_ptr; + + /* Ring mem ptr info */ + /* Alloated in the order + H2D_MSGRING_CONTROL_SUBMIT 0 + H2D_MSGRING_RXPOST_SUBMIT 1 + D2H_MSGRING_CONTROL_COMPLETE 2 + D2H_MSGRING_TX_COMPLETE 3 + D2H_MSGRING_RX_COMPLETE 4 + TX_FLOW_RING 5 + */ + + { + /* ringmemptr holds start of the mem block address space */ + tcm_memloc = ltoh32(ring_info->ringmem_ptr); + + /* Find out ringmem ptr for each ring common ring */ + for (i = 0; i <= BCMPCIE_COMMON_MSGRING_MAX_ID; i++) { + bus->ring_sh[i].ring_mem_addr = tcm_memloc; + /* Update mem block */ + tcm_memloc = tcm_memloc + sizeof(ring_mem_t); + DHD_INFO(("ring id %d ring mem addr 0x%04x \n", + i, bus->ring_sh[i].ring_mem_addr)); + } + + /* Tx flow Ring */ + if (bus->txmode_push) { + bus->ring_sh[i].ring_mem_addr = tcm_memloc; + DHD_INFO(("TX ring ring id %d ring mem addr 0x%04x \n", + i, bus->ring_sh[i].ring_mem_addr)); + } + } + + /* Ring state mem ptr info */ + { + d2h_w_idx_ptr = ltoh32(ring_info->d2h_w_idx_ptr); + d2h_r_idx_ptr = ltoh32(ring_info->d2h_r_idx_ptr); + h2d_w_idx_ptr = ltoh32(ring_info->h2d_w_idx_ptr); + h2d_r_idx_ptr = ltoh32(ring_info->h2d_r_idx_ptr); + /* Store h2d common ring write/read pointers */ + for (i = 0; i < BCMPCIE_H2D_COMMON_MSGRINGS; i++) { + bus->ring_sh[i].ring_state_w = h2d_w_idx_ptr; + bus->ring_sh[i].ring_state_r = h2d_r_idx_ptr; + + /* update mem block */ + h2d_w_idx_ptr = h2d_w_idx_ptr + sizeof(uint32); + h2d_r_idx_ptr = h2d_r_idx_ptr + sizeof(uint32); + + DHD_INFO(("h2d w/r : idx %d write %x read %x \n", i, + bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); + } + /* Store d2h common ring write/read pointers */ + for (j = 0; j < BCMPCIE_D2H_COMMON_MSGRINGS; j++, i++) { + bus->ring_sh[i].ring_state_w = d2h_w_idx_ptr; + bus->ring_sh[i].ring_state_r = d2h_r_idx_ptr; + + /* update mem block */ + d2h_w_idx_ptr = d2h_w_idx_ptr + sizeof(uint32); + d2h_r_idx_ptr = d2h_r_idx_ptr + sizeof(uint32); + + DHD_INFO(("d2h w/r : idx %d write %x read %x \n", i, + bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); + } + + /* Store txflow ring write/read pointers */ + if (bus->txmode_push) { + bus->ring_sh[i].ring_state_w = h2d_w_idx_ptr; + bus->ring_sh[i].ring_state_r = h2d_r_idx_ptr; + + DHD_INFO(("txflow : idx %d write %x read %x \n", i, + bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); + } else { + for (j = 0; j < (bus->max_sub_queues - BCMPCIE_H2D_COMMON_MSGRINGS); + i++, j++) + { + bus->ring_sh[i].ring_state_w = h2d_w_idx_ptr; + bus->ring_sh[i].ring_state_r = h2d_r_idx_ptr; + + /* update mem block */ + h2d_w_idx_ptr = h2d_w_idx_ptr + sizeof(uint32); + h2d_r_idx_ptr = h2d_r_idx_ptr + sizeof(uint32); + + DHD_INFO(("FLOW Rings h2d w/r : idx %d write %x read %x \n", i, + bus->ring_sh[i].ring_state_w, + bus->ring_sh[i].ring_state_r)); + } + } + } +} + +/* Initialize bus module: prepare for communication w/dongle */ +int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) +{ + dhd_bus_t *bus = dhdp->bus; + int ret = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(bus->dhd); + if (!bus->dhd) + return 0; + + /* Make sure we're talking to the core. */ + bus->reg = si_setcore(bus->sih, PCIE2_CORE_ID, 0); + ASSERT(bus->reg != NULL); + + /* before opening up bus for data transfer, check if shared are is intact */ + ret = dhdpcie_readshared(bus); + if (ret < 0) { + DHD_ERROR(("%s :Shared area read failed \n", __FUNCTION__)); + return ret; + } + + + /* Make sure we're talking to the core. */ + bus->reg = si_setcore(bus->sih, PCIE2_CORE_ID, 0); + ASSERT(bus->reg != NULL); + + /* Set bus state according to enable result */ + dhdp->busstate = DHD_BUS_DATA; + + /* Enable the interrupt after device is up */ + dhdpcie_bus_intr_enable(bus); + + /* bcmsdh_intr_unmask(bus->sdh); */ + +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; + bus->idletime = (int32)MAX_IDLE_COUNT; + bus->host_suspend = FALSE; + atomic_set(&bus->runtime_suspend, 0); + init_waitqueue_head(&bus->rpm_queue); +#endif /* DHD_USE_IDLECOUNT */ + + /* Init counter. */ + bus->d3_ack_war_cnt = 0; + + return ret; + +} + + +static void +dhdpcie_init_shared_addr(dhd_bus_t *bus) +{ + uint32 addr = 0; + uint32 val = 0; + addr = bus->dongle_ram_base + bus->ramsize - 4; +#ifdef DHD_USE_IDLECOUNT + bus_wake(bus); +#endif /* DHD_USE_IDLECOUNT */ + dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val)); +} + + +bool +dhdpcie_chipmatch(uint16 vendor, uint16 device) +{ + if (vendor != PCI_VENDOR_ID_BROADCOM) { + DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, + vendor, device)); + return (-ENODEV); + } + + if ((device == BCM4350_D11AC_ID) || (device == BCM4350_D11AC2G_ID) || + (device == BCM4350_D11AC5G_ID) || BCM4350_CHIP(device)) + return 0; + + if ((device == BCM4354_D11AC_ID) || (device == BCM4354_D11AC2G_ID) || + (device == BCM4354_D11AC5G_ID) || (device == BCM4354_CHIP_ID)) + return 0; + + if ((device == BCM4356_D11AC_ID) || (device == BCM4356_D11AC2G_ID) || + (device == BCM4356_D11AC5G_ID) || (device == BCM4356_CHIP_ID)) + return 0; + + if ((device == BCM4345_D11AC_ID) || (device == BCM4345_D11AC2G_ID) || + (device == BCM4345_D11AC5G_ID) || (device == BCM4345_CHIP_ID)) + return 0; + + if ((device == BCM4335_D11AC_ID) || (device == BCM4335_D11AC2G_ID) || + (device == BCM4335_D11AC5G_ID) || (device == BCM4335_CHIP_ID)) + return 0; + + if ((device == BCM43602_D11AC_ID) || (device == BCM43602_D11AC2G_ID) || + (device == BCM43602_D11AC5G_ID) || (device == BCM43602_CHIP_ID)) + return 0; + + if ((device == BCM43569_D11AC_ID) || (device == BCM43569_D11AC2G_ID) || + (device == BCM43569_D11AC5G_ID) || (device == BCM43569_CHIP_ID)) + return 0; + + if ((device == BCM4358_D11AC_ID) || (device == BCM4358_D11AC2G_ID) || + (device == BCM4358_D11AC5G_ID) || (device == BCM4358_CHIP_ID)) + return 0; + + if ((device == BCM4349_D11AC_ID) || (device == BCM4349_D11AC2G_ID) || + (device == BCM4349_D11AC5G_ID) || (device == BCM4349_CHIP_ID)) + return 0; + if ((device == BCM4355_D11AC_ID) || (device == BCM4355_D11AC2G_ID) || + (device == BCM4355_D11AC5G_ID) || (device == BCM4355_CHIP_ID)) + return 0; + if ((device == BCM4359_D11AC_ID) || (device == BCM4359_D11AC2G_ID) || + (device == BCM4359_D11AC5G_ID) || (device == BCM4359_CHIP_ID)) + return 0; + + + DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, vendor, device)); + return (-ENODEV); +} + + +/* + +Name: dhdpcie_cc_nvmshadow + +Description: +A shadow of OTP/SPROM exists in ChipCommon Region +betw. 0x800 and 0xBFF (Backplane Addr. 0x1800_0800 and 0x1800_0BFF). +Strapping option (SPROM vs. OTP), presence of OTP/SPROM and its size +can also be read from ChipCommon Registers. +*/ + +static int +dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b) +{ + uint16 dump_offset = 0; + uint32 dump_size = 0, otp_size = 0, sprom_size = 0; + + /* Table for 65nm OTP Size (in bits) */ + int otp_size_65nm[8] = {0, 2048, 4096, 8192, 4096, 6144, 512, 1024}; + + volatile uint16 *nvm_shadow; + + uint cur_coreid; + uint chipc_corerev; + chipcregs_t *chipcregs; + + + /* Save the current core */ + cur_coreid = si_coreid(bus->sih); + /* Switch to ChipC */ + chipcregs = (chipcregs_t *)si_setcore(bus->sih, CC_CORE_ID, 0); + chipc_corerev = si_corerev(bus->sih); + + /* Check ChipcommonCore Rev */ + if (chipc_corerev < 44) { + DHD_ERROR(("%s: ChipcommonCore Rev %d < 44\n", __FUNCTION__, chipc_corerev)); + return BCME_UNSUPPORTED; + } + + /* Check ChipID */ + if (((uint16)bus->sih->chip != BCM4350_CHIP_ID) && + ((uint16)bus->sih->chip != BCM4345_CHIP_ID)) { + DHD_ERROR(("%s: cc_nvmdump cmd. supported for 4350/4345 only\n", + __FUNCTION__)); + return BCME_UNSUPPORTED; + } + + /* Check if SRC_PRESENT in SpromCtrl(0x190 in ChipCommon Regs) is set */ + if (chipcregs->sromcontrol & SRC_PRESENT) { + /* SPROM Size: 1Kbits (0x0), 4Kbits (0x1), 16Kbits(0x2) */ + sprom_size = (1 << (2 * ((chipcregs->sromcontrol & SRC_SIZE_MASK) + >> SRC_SIZE_SHIFT))) * 1024; + bcm_bprintf(b, "\nSPROM Present (Size %d bits)\n", sprom_size); + } + + if (chipcregs->sromcontrol & SRC_OTPPRESENT) { + bcm_bprintf(b, "\nOTP Present"); + + if (((chipcregs->otplayout & OTPL_WRAP_TYPE_MASK) >> OTPL_WRAP_TYPE_SHIFT) + == OTPL_WRAP_TYPE_40NM) { + /* 40nm OTP: Size = (OtpSize + 1) * 1024 bits */ + otp_size = (((chipcregs->capabilities & CC_CAP_OTPSIZE) + >> CC_CAP_OTPSIZE_SHIFT) + 1) * 1024; + bcm_bprintf(b, "(Size %d bits)\n", otp_size); + } else { + /* This part is untested since newer chips have 40nm OTP */ + otp_size = otp_size_65nm[(chipcregs->capabilities & CC_CAP_OTPSIZE) + >> CC_CAP_OTPSIZE_SHIFT]; + bcm_bprintf(b, "(Size %d bits)\n", otp_size); + DHD_INFO(("%s: 65nm/130nm OTP Size not tested. \n", + __FUNCTION__)); + } + } + + if (((chipcregs->sromcontrol & SRC_PRESENT) == 0) && + ((chipcregs->capabilities & CC_CAP_OTPSIZE) == 0)) { + DHD_ERROR(("%s: SPROM and OTP could not be found \n", + __FUNCTION__)); + return BCME_NOTFOUND; + } + + /* Check the strapping option in SpromCtrl: Set = OTP otherwise SPROM */ + if ((chipcregs->sromcontrol & SRC_OTPSEL) && + (chipcregs->sromcontrol & SRC_OTPPRESENT)) { + + bcm_bprintf(b, "OTP Strap selected.\n" + "\nOTP Shadow in ChipCommon:\n"); + + dump_size = otp_size / 16 ; /* 16bit words */ + + } else if (((chipcregs->sromcontrol & SRC_OTPSEL) == 0) && + (chipcregs->sromcontrol & SRC_PRESENT)) { + + bcm_bprintf(b, "SPROM Strap selected\n" + "\nSPROM Shadow in ChipCommon:\n"); + + /* If SPROM > 8K only 8Kbits is mapped to ChipCommon (0x800 - 0xBFF) */ + /* dump_size in 16bit words */ + dump_size = sprom_size > 8 ? (8 * 1024) / 16 : sprom_size / 16; + } + else { + DHD_ERROR(("%s: NVM Shadow does not exist in ChipCommon\n", + __FUNCTION__)); + return BCME_NOTFOUND; + } + + if (bus->regs == NULL) { + DHD_ERROR(("ChipCommon Regs. not initialized\n")); + return BCME_NOTREADY; + } else { + bcm_bprintf(b, "\n OffSet:"); + + /* Point to the SPROM/OTP shadow in ChipCommon */ + nvm_shadow = chipcregs->sromotp; + + /* + * Read 16 bits / iteration. + * dump_size & dump_offset in 16-bit words + */ + while (dump_offset < dump_size) { + if (dump_offset % 2 == 0) + /* Print the offset in the shadow space in Bytes */ + bcm_bprintf(b, "\n 0x%04x", dump_offset * 2); + + bcm_bprintf(b, "\t0x%04x", *(nvm_shadow + dump_offset)); + dump_offset += 0x1; + } + } + + /* Switch back to the original core */ + si_setcore(bus->sih, cur_coreid, 0); + + return BCME_OK; +} + + +uint8 BCMFASTPATH +dhd_bus_is_txmode_push(dhd_bus_t *bus) +{ + return bus->txmode_push; +} + +void dhd_bus_clean_flow_ring(dhd_bus_t *bus, void *node) +{ + void *pkt; + flow_queue_t *queue; + flow_ring_node_t *flow_ring_node = (flow_ring_node_t *)node; + unsigned long flags; + + queue = &flow_ring_node->queue; + +#ifdef DHDTCPACK_SUPPRESS + /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, + * when there is a newly coming packet from network stack. + */ + dhd_tcpack_info_tbl_clean(bus->dhd); +#endif /* DHDTCPACK_SUPPRESS */ + + /* clean up BUS level info */ + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + + /* Flush all pending packets in the queue, if any */ + while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { + PKTFREE(bus->dhd->osh, pkt, TRUE); + } + ASSERT(flow_queue_empty(queue)); + + flow_ring_node->status = FLOW_RING_STATUS_CLOSED; + flow_ring_node->active = FALSE; + dll_delete(&flow_ring_node->list); + + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + + /* Call Flow ring clean up */ + dhd_prot_clean_flow_ring(bus->dhd, flow_ring_node->prot_info); + dhd_flowid_free(bus->dhd, flow_ring_node->flow_info.ifindex, + flow_ring_node->flowid); + +} + +/* + * Allocate a Flow ring buffer, + * Init Ring buffer, + * Send Msg to device about flow ring creation +*/ +int +dhd_bus_flow_ring_create_request(dhd_bus_t *bus, void *arg) +{ + flow_ring_node_t *flow_ring_node = (flow_ring_node_t *)arg; + + DHD_INFO(("%s :Flow create\n", __FUNCTION__)); + + /* Send Msg to device about flow ring creation */ + if (dhd_prot_flow_ring_create(bus->dhd, flow_ring_node) != BCME_OK) + return BCME_NOMEM; + + return BCME_OK; +} + +void +dhd_bus_flow_ring_create_response(dhd_bus_t *bus, uint16 flowid, int32 status) +{ + flow_ring_node_t *flow_ring_node; + unsigned long flags; + + DHD_INFO(("%s :Flow Response %d \n", __FUNCTION__, flowid)); + + flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); + ASSERT(flow_ring_node->flowid == flowid); + + if (status != BCME_OK) { + DHD_ERROR(("%s Flow create Response failure error status = %d \n", + __FUNCTION__, status)); + /* Call Flow clean up */ + dhd_bus_clean_flow_ring(bus, flow_ring_node); + return; + } + + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + flow_ring_node->status = FLOW_RING_STATUS_OPEN; + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + + dhd_bus_schedule_queue(bus, flowid, FALSE); + + return; +} + +int +dhd_bus_flow_ring_delete_request(dhd_bus_t *bus, void *arg) +{ + void * pkt; + flow_queue_t *queue; + flow_ring_node_t *flow_ring_node; + unsigned long flags; + + DHD_INFO(("%s :Flow Delete\n", __FUNCTION__)); + + flow_ring_node = (flow_ring_node_t *)arg; + + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + if (flow_ring_node->status & FLOW_RING_STATUS_DELETE_PENDING) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + DHD_ERROR(("%s :Delete Pending\n", __FUNCTION__)); + return BCME_ERROR; + } + flow_ring_node->status = FLOW_RING_STATUS_DELETE_PENDING; + + queue = &flow_ring_node->queue; /* queue associated with flow ring */ + +#ifdef DHDTCPACK_SUPPRESS + /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, + * when there is a newly coming packet from network stack. + */ + dhd_tcpack_info_tbl_clean(bus->dhd); +#endif /* DHDTCPACK_SUPPRESS */ + /* Flush all pending packets in the queue, if any */ + while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { + PKTFREE(bus->dhd->osh, pkt, TRUE); + } + ASSERT(flow_queue_empty(queue)); + + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + + /* Send Msg to device about flow ring deletion */ + dhd_prot_flow_ring_delete(bus->dhd, flow_ring_node); + + return BCME_OK; +} + +void +dhd_bus_flow_ring_delete_response(dhd_bus_t *bus, uint16 flowid, uint32 status) +{ + flow_ring_node_t *flow_ring_node; + + DHD_INFO(("%s :Flow Delete Response %d \n", __FUNCTION__, flowid)); + + flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); + ASSERT(flow_ring_node->flowid == flowid); + + if (status != BCME_OK) { + DHD_ERROR(("%s Flow Delete Response failure error status = %d \n", + __FUNCTION__, status)); + return; + } + /* Call Flow clean up */ + dhd_bus_clean_flow_ring(bus, flow_ring_node); + + return; + +} + +int dhd_bus_flow_ring_flush_request(dhd_bus_t *bus, void *arg) +{ + void *pkt; + flow_queue_t *queue; + flow_ring_node_t *flow_ring_node; + unsigned long flags; + + DHD_INFO(("%s :Flow Delete\n", __FUNCTION__)); + + flow_ring_node = (flow_ring_node_t *)arg; + queue = &flow_ring_node->queue; /* queue associated with flow ring */ + + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + +#ifdef DHDTCPACK_SUPPRESS + /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, + * when there is a newly coming packet from network stack. + */ + dhd_tcpack_info_tbl_clean(bus->dhd); +#endif /* DHDTCPACK_SUPPRESS */ + /* Flush all pending packets in the queue, if any */ + while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { + PKTFREE(bus->dhd->osh, pkt, TRUE); + } + ASSERT(flow_queue_empty(queue)); + + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + + /* Send Msg to device about flow ring flush */ + dhd_prot_flow_ring_flush(bus->dhd, flow_ring_node); + + flow_ring_node->status = FLOW_RING_STATUS_FLUSH_PENDING; + return BCME_OK; +} + +void +dhd_bus_flow_ring_flush_response(dhd_bus_t *bus, uint16 flowid, uint32 status) +{ + flow_ring_node_t *flow_ring_node; + + if (status != BCME_OK) { + DHD_ERROR(("%s Flow flush Response failure error status = %d \n", + __FUNCTION__, status)); + return; + } + + flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); + ASSERT(flow_ring_node->flowid == flowid); + + flow_ring_node->status = FLOW_RING_STATUS_OPEN; + return; +} + +uint32 +dhd_bus_max_h2d_queues(struct dhd_bus *bus, uint8 *txpush) +{ + if (bus->txmode_push) + *txpush = 1; + else + *txpush = 0; + return bus->max_sub_queues; +} + +int +dhdpcie_bus_clock_start(struct dhd_bus *bus) +{ + return dhdpcie_start_host_pcieclock(bus); +} + +int +dhdpcie_bus_clock_stop(struct dhd_bus *bus) +{ + return dhdpcie_stop_host_pcieclock(bus); +} + +int +dhdpcie_bus_disable_device(struct dhd_bus *bus) +{ + return dhdpcie_disable_device(bus); +} + +int +dhdpcie_bus_enable_device(struct dhd_bus *bus) +{ + return dhdpcie_enable_device(bus); +} + +int +dhdpcie_bus_alloc_resource(struct dhd_bus *bus) +{ + return dhdpcie_alloc_resource(bus); +} + +void +dhdpcie_bus_free_resource(struct dhd_bus *bus) +{ + dhdpcie_free_resource(bus); +} + +int +dhd_bus_request_irq(struct dhd_bus *bus) +{ + return dhdpcie_bus_request_irq(bus); +} + +bool +dhdpcie_bus_dongle_attach(struct dhd_bus *bus) +{ + return dhdpcie_dongle_attach(bus); +} + +int +dhd_bus_release_dongle(struct dhd_bus *bus) +{ + bool dongle_isolation; + osl_t *osh; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus) { + osh = bus->osh; + ASSERT(osh); + + if (bus->dhd) { + dongle_isolation = bus->dhd->dongle_isolation; + dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE); + } + } + + return 0; +} + +#ifdef DHD_USE_IDLECOUNT +bool dhd_bus_is_resume_done(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + + return (atomic_read(&bus->runtime_suspend) == 0); +} + +bool bus_wake(dhd_bus_t *bus) +{ + int retry = 0; + + DHD_TRACE(("%s Enter\n", __FUNCTION__)); + + if (!bus || !bus->dhd) + return FALSE; + + bus->idlecount = 0; + + if (bus->dhd->up == FALSE) { + return FALSE; + } + + if (bus->suspended && bus->host_suspend) { + bus->bus_wake = 1; + smp_wmb(); + wake_up_interruptible(&bus->rpm_queue); + SMP_RD_BARRIER_DEPENDS(); + while (atomic_read(&bus->runtime_suspend) && retry++ != MAX_RESUME_WAIT) { + SMP_RD_BARRIER_DEPENDS(); + wait_event_interruptible_timeout(bus->rpm_queue, + !atomic_read(&bus->runtime_suspend), + msecs_to_jiffies(1)); + } + DHD_ERROR(("%s wakeup the bus with retry count : %d \n", __FUNCTION__, retry)); + if (atomic_read(&bus->runtime_suspend)) { + DHD_ERROR(("%s wakeup the bus failed with retry count : %d\n", + __FUNCTION__, retry)); + return FALSE; + } + } + + return TRUE; +} + +bool dhd_bus_wake(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + return bus_wake(bus); +} + +bool bus_wakeup(dhd_bus_t *bus) +{ + bus->idlecount = 0; + SMP_RD_BARRIER_DEPENDS(); + if (bus->suspended && bus->host_suspend) { + bus->bus_wake = 1; + smp_wmb(); + wake_up_interruptible(&bus->rpm_queue); + SMP_RD_BARRIER_DEPENDS(); + return TRUE; + } + + return FALSE; +} + +bool dhd_bus_wakeup(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + return bus_wakeup(bus); +} +#endif /* DHD_USE_IDLECOUNT */ + +#ifdef BCMPCIE_OOB_HOST_WAKE +int dhd_bus_oob_intr_register(dhd_pub_t *dhdp) +{ + return dhdpcie_oob_intr_register(dhdp->bus); +} + +void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp) +{ + dhdpcie_oob_intr_unregister(dhdp->bus); +} + +void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable) +{ + dhdpcie_oob_intr_set(dhdp->bus, enable); +} +#endif /* BCMPCIE_OOB_HOST_WAKE */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.h new file mode 100644 index 000000000000..e75d26eb8e32 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.h @@ -0,0 +1,258 @@ +/* + * Linux DHD Bus Module for PCIE + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_pcie.h 614103 2016-01-21 04:01:39Z $ + */ + + +#ifndef dhd_pcie_h +#define dhd_pcie_h + +#include +#include +#ifdef SUPPORT_LINKDOWN_RECOVERY +#ifdef CONFIG_ARCH_MSM +#ifdef CONFIG_ARCH_MSM8994 +#include +#else +#include +#endif +#endif /* CONFIG_ARCH_MSM */ +#endif /* SUPPORT_LINKDOWN_RECOVERY */ +#ifdef DHD_USE_IDLECOUNT +#include +#include + +#if !defined(CUSTOM_DHD_WATCHDOG_MS) || (CUSTOM_DHD_WATCHDOG_MS <= 0) +#error "MUST define CUSTOM_DHD_WATCHDOG_MS > 0 when DHD_USE_IDLECOUNT defined." +#endif + +#ifndef MAX_IDLE_COUNT +#define MAX_IDLE_COUNT 16 +#endif /* MAX_IDLE_COUNT */ + +#ifndef MAX_RESUME_WAIT +#define MAX_RESUME_WAIT 100 +#endif /* MAX_RESUME_WAIT */ +#endif /* DHD_USE_IDLECOUNT */ + +/* defines */ + +#define PCMSGBUF_HDRLEN 0 +#define DONGLE_REG_MAP_SIZE (32 * 1024) +#define DONGLE_TCM_MAP_SIZE (4096 * 1024) +#define DONGLE_MIN_MEMSIZE (128 *1024) +#ifdef DHD_DEBUG +#define DHD_PCIE_SUCCESS 0 +#define DHD_PCIE_FAILURE 1 +#endif /* DHD_DEBUG */ +#define REMAP_ENAB(bus) ((bus)->remap) +#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) + +#define MAX_DHD_TX_FLOWS 256 + +/* user defined data structures */ +#ifdef DHD_DEBUG +/* Device console log buffer state */ +#define CONSOLE_LINE_MAX 192 +#define CONSOLE_BUFFER_MAX 2024 + + +typedef struct dhd_console { + uint count; /* Poll interval msec counter */ + uint log_addr; /* Log struct address (fixed) */ + hnd_log_t log; /* Log struct (host copy) */ + uint bufsize; /* Size of log buffer */ + uint8 *buf; /* Log buffer (host copy) */ + uint last; /* Last buffer read index */ +} dhd_console_t; +#endif /* DHD_DEBUG */ +typedef struct ring_sh_info { + uint32 ring_mem_addr; + uint32 ring_state_w; + uint32 ring_state_r; +} ring_sh_info_t; + +typedef struct dhd_bus { + dhd_pub_t *dhd; + struct pci_dev *dev; /* pci device handle */ + dll_t const_flowring; /* constructed list of tx flowring queues */ + + si_t *sih; /* Handle for SI calls */ + char *vars; /* Variables (from CIS and/or other) */ + uint varsz; /* Size of variables buffer */ + uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ + sbpcieregs_t *reg; /* Registers for PCIE core */ + + uint armrev; /* CPU core revision */ + uint ramrev; /* SOCRAM core revision */ + uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ + uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ + uint32 srmemsize; /* Size of SRMEM */ + + uint32 bus; /* gSPI or SDIO bus */ + uint32 intstatus; /* Intstatus bits (events) pending */ + bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ + bool fcstate; /* State of dongle flow-control */ + + uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ + char *fw_path; /* module_param: path to firmware image */ + char *nv_path; /* module_param: path to nvram vars file */ + char *nvram_params; /* user specified nvram params. */ + int nvram_params_len; + + struct pktq txq; /* Queue length used for flow-control */ + + uint rxlen; /* Length of valid data in buffer */ + + + bool intr; /* Use interrupts */ + bool ipend; /* Device interrupt is pending */ + bool intdis; /* Interrupts disabled by isr */ + uint intrcount; /* Count of device interrupt callbacks */ + uint lastintrs; /* Count as of last watchdog timer */ + +#ifdef DHD_DEBUG + dhd_console_t console; /* Console output polling support */ + uint console_addr; /* Console address from shared struct */ +#endif /* DHD_DEBUG */ + + bool alp_only; /* Don't use HT clock (ALP only) */ + + bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram + * Available with socram rev 16 + * Remap region not DMA-able + */ + uint32 resetinstr; + uint32 dongle_ram_base; + + ulong shared_addr; + pciedev_shared_t *pcie_sh; + bool bus_flowctrl; + ioctl_comp_resp_msg_t ioct_resp; + uint32 dma_rxoffset; + volatile char *regs; /* pci device memory va */ + volatile char *tcm; /* pci device memory va */ + uint32 tcm_size; +#ifdef CONFIG_ARCH_MSM8994 + uint32 bar1_win_base; + uint32 bar1_win_mask; +#endif + osl_t *osh; + uint32 nvram_csm; /* Nvram checksum */ + uint16 pollrate; + uint16 polltick; + + uint32 *pcie_mb_intr_addr; + void *pcie_mb_intr_osh; + bool sleep_allowed; + + /* version 3 shared struct related info start */ + ring_sh_info_t ring_sh[BCMPCIE_COMMON_MSGRINGS + MAX_DHD_TX_FLOWS]; + uint8 h2d_ring_count; + uint8 d2h_ring_count; + uint32 ringmem_ptr; + uint32 ring_state_ptr; + + uint32 d2h_dma_scratch_buffer_mem_addr; + + uint32 h2d_mb_data_ptr_addr; + uint32 d2h_mb_data_ptr_addr; + /* version 3 shared struct related info end */ + + uint32 def_intmask; + bool ltrsleep_on_unload; + uint wait_for_d3_ack; + uint8 txmode_push; + uint32 max_sub_queues; + bool db1_for_mb; + bool suspended; +#ifdef SUPPORT_LINKDOWN_RECOVERY +#ifdef CONFIG_ARCH_MSM + struct msm_pcie_register_event pcie_event; + bool islinkdown; +#endif /* CONFIG_ARCH_MSM */ +#endif /* SUPPORT_LINKDOWN_RECOVERY */ +#ifdef PCIE_TX_DEFERRAL + struct workqueue_struct *tx_wq; + struct work_struct create_flow_work; + struct work_struct delete_flow_work; + unsigned long *delete_flow_map; + struct sk_buff_head orphan_list; +#endif /* PCIE_TX_DEFERRAL */ +#ifdef DHD_USE_IDLECOUNT + int32 idlecount; /* Activity timeout counter */ + int32 idletime; /* Control for activity timeout */ + int32 bus_wake; /* For wake up the bus */ + atomic_t runtime_suspend; /* For check runtime suspend end */ + bool host_suspend; /* For checking host is suspended */ + wait_queue_head_t rpm_queue; /* wait-queue for bus wake up */ +#endif /* DHD_USE_IDLECOUNT */ + struct mutex pm_lock; /* Synchronize for system PM & runtime PM */ + struct mutex host_clock_lock; /* Synchronize for host clock switching. */ + uint32 d0_inform_cnt; + uint32 d0_inform_in_use_cnt; + uint8 force_suspend; + uint32 d3_ack_war_cnt; +#ifdef SOMC_1DK_NV_PATH + uint16 subsystem_id; +#endif /* SOMC_1DK_NV_PATH */ +} dhd_bus_t; + +/* function declarations */ + +extern uint32* dhdpcie_bus_reg_map(osl_t *osh, ulong addr, int size); +extern int dhdpcie_bus_register(void); +extern void dhdpcie_bus_unregister(void); +extern bool dhdpcie_chipmatch(uint16 vendor, uint16 device); + +extern struct dhd_bus* dhdpcie_bus_attach(osl_t *osh, volatile char* regs, + volatile char* tcm, uint32 tcm_size); +extern uint32 dhdpcie_bus_cfg_read_dword(struct dhd_bus *bus, uint32 addr, uint32 size); +extern void dhdpcie_bus_cfg_write_dword(struct dhd_bus *bus, uint32 addr, uint32 size, uint32 data); +extern void dhdpcie_bus_intr_disable(struct dhd_bus *bus); +extern void dhdpcie_bus_remove_prep(struct dhd_bus *bus); +extern void dhdpcie_bus_release(struct dhd_bus *bus); +extern int32 dhdpcie_bus_isr(struct dhd_bus *bus); +extern void dhdpcie_free_irq(dhd_bus_t *bus); +extern int dhdpcie_bus_suspend(struct dhd_bus *bus, bool state); +extern int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state); +#ifndef BCMPCIE_OOB_HOST_WAKE +extern void dhdpcie_pme_active(osl_t *osh, bool enable); +#endif /* !BCMPCIE_OOB_HOST_WAKE */ +extern int dhdpcie_start_host_pcieclock(dhd_bus_t *bus); +extern int dhdpcie_stop_host_pcieclock(dhd_bus_t *bus); +extern int dhdpcie_disable_device(dhd_bus_t *bus); +extern int dhdpcie_enable_device(dhd_bus_t *bus); +extern int dhdpcie_alloc_resource(dhd_bus_t *bus); +extern void dhdpcie_free_resource(dhd_bus_t *bus); +extern int dhdpcie_bus_request_irq(struct dhd_bus *bus); +#ifdef BCMPCIE_OOB_HOST_WAKE +extern int dhdpcie_oob_intr_register(dhd_bus_t *bus); +extern void dhdpcie_oob_intr_unregister(dhd_bus_t *bus); +extern void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + +extern int dhd_buzzz_dump_dngl(dhd_bus_t *bus); +#endif /* dhd_pcie_h */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie_linux.c new file mode 100644 index 000000000000..357079c30fec --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie_linux.c @@ -0,0 +1,1392 @@ +/* + * Linux DHD Bus Module for PCIE + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_pcie_linux.c 627805 2016-03-28 13:12:47Z $ + */ + + +/* include files */ +#include +#include +#include +#include +#include +#include +#include +#if defined(DHD_DEBUG) +#include +#include +#endif /* defined(DHD_DEBUG) */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ARCH_MSM +#ifdef CONFIG_ARCH_MSM8994 +#include +#else +#include +#endif +#endif /* CONFIG_ARCH_MSM */ + +#define PCI_CFG_RETRY 10 +#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ +#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ + +#define OSL_PKTTAG_CLEAR(p) \ +do { \ + struct sk_buff *s = (struct sk_buff *)(p); \ + ASSERT(OSL_PKTTAG_SZ == 32); \ + *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ + *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ + *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ + *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ +} while (0) + + +/* user defined data structures */ + +typedef struct dhd_pc_res { + uint32 bar0_size; + void* bar0_addr; + uint32 bar1_size; + void* bar1_addr; +} pci_config_res, *pPci_config_res; + +typedef bool (*dhdpcie_cb_fn_t)(void *); + +typedef struct dhdpcie_info +{ + dhd_bus_t *bus; + osl_t *osh; + struct pci_dev *dev; /* pci device handle */ + volatile char *regs; /* pci device memory va */ + volatile char *tcm; /* pci device memory va */ + uint32 tcm_size; /* pci device memory size */ + struct pcos_info *pcos_info; + uint16 last_intrstatus; /* to cache intrstatus */ + int irq; + char pciname[32]; + struct pci_saved_state* default_state; + struct pci_saved_state* state; +#ifdef BCMPCIE_OOB_HOST_WAKE + void *os_cxt; /* Pointer to per-OS private data */ +#endif /* BCMPCIE_OOB_HOST_WAKE */ +} dhdpcie_info_t; + + +struct pcos_info { + dhdpcie_info_t *pc; + spinlock_t lock; + wait_queue_head_t intr_wait_queue; + struct timer_list tuning_timer; + int tuning_timer_exp; + atomic_t timer_enab; + struct tasklet_struct tuning_tasklet; +}; + +#ifdef BCMPCIE_OOB_HOST_WAKE +typedef struct dhdpcie_os_info { + int oob_irq_num; /* valid when hardware or software oob in use */ + unsigned long oob_irq_flags; /* valid when hardware or software oob in use */ + bool oob_irq_registered; + bool oob_irq_enabled; + bool oob_irq_wake_enabled; + spinlock_t oob_irq_spinlock; + void *dev; /* handle to the underlying device */ +} dhdpcie_os_info_t; +#endif /* BCMPCIE_OOB_HOST_WAKE */ + +/* function declarations */ +static int __devinit +dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static void __devexit +dhdpcie_pci_remove(struct pci_dev *pdev); +static int dhdpcie_init(struct pci_dev *pdev); +static irqreturn_t dhdpcie_isr(int irq, void *arg); +/* OS Routine functions for PCI suspend/resume */ + +static int dhdpcie_pci_suspend(struct pci_dev *dev, pm_message_t state); +static int dhdpcie_pci_resume(struct pci_dev *dev); +static int dhdpcie_resume_dev(struct pci_dev *dev); +static int dhdpcie_suspend_dev(struct pci_dev *dev); +static struct pci_device_id dhdpcie_pci_devid[] __devinitdata = { + { vendor: 0x14e4, + device: PCI_ANY_ID, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + class: PCI_CLASS_NETWORK_OTHER << 8, + class_mask: 0xffff00, + driver_data: 0, + }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, dhdpcie_pci_devid); + +static struct pci_driver dhdpcie_driver = { + node: {}, + name: "pcieh", + id_table: dhdpcie_pci_devid, + probe: dhdpcie_pci_probe, + remove: dhdpcie_pci_remove, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) + save_state: NULL, +#endif + suspend: dhdpcie_pci_suspend, + resume: dhdpcie_pci_resume, +}; + +int dhdpcie_init_succeeded = FALSE; + +int dhdpcie_set_suspend_resume(struct pci_dev *pdev, bool state) +{ + int ret = 0; + dhdpcie_info_t *pch = pci_get_drvdata(pdev); + dhd_bus_t *bus = NULL; + + if (pch) { + bus = pch->bus; + } + + if (bus && (bus->dhd->busstate == DHD_BUS_DOWN) && + bus->dhd->dongle_reset) { + DHD_ERROR(("%s: Dongle isn't up!\n", __FUNCTION__)); + return ret; + } + + if (bus) + mutex_lock(&bus->pm_lock); + +#ifdef DHD_USE_IDLECOUNT + /* Wake up runtime PM when system PM trigger */ + if (bus && (bus->suspended == TRUE) && (bus->host_suspend == TRUE)) { + if (state == TRUE) { + mutex_unlock(&bus->pm_lock); + if (!bus_wake(bus)) { + DHD_ERROR(("%s: Failed to resume the bus.\n", + __FUNCTION__)); + return -EAGAIN; + } else { + /* Carry on suspending */ + DHD_ERROR(("%s: Woke up from runtime suspend. " + "Carry on legacy suspend.\n", __FUNCTION__)); + mutex_lock(&bus->pm_lock); + } + } else { + ret = dhdpcie_bus_suspend(bus, state); + mutex_unlock(&bus->pm_lock); + return ret; + } + } +#endif /* DHD_USE_IDLECOUNT */ + + /* When firmware is not loaded do the PCI bus */ + /* suspend/resume only */ + if (bus && (bus->dhd->busstate == DHD_BUS_DOWN) && +#ifdef CONFIG_MACH_UNIVERSAL5433 + /* RB:34285 check_rev() : return 1 - new rev., 0 - old rev. */ + (!check_rev() || (check_rev() && !bus->dhd->dongle_reset))) { +#else + !bus->dhd->dongle_reset) { +#endif /* CONFIG_MACH_UNIVERSAL5433 */ + ret = dhdpcie_pci_suspend_resume(bus, state); + mutex_unlock(&bus->pm_lock); + return ret; + } + + if (bus && ((bus->dhd->busstate == DHD_BUS_SUSPEND)|| + (bus->dhd->busstate == DHD_BUS_DATA)) && + (bus->suspended != state)) { +#ifdef DHD_USE_IDLECOUNT + struct net_device *netdev = NULL; + bool runtime_pm = FALSE; + + dhd_pub_t *pub = (dhd_pub_t *)(bus->dhd); + netdev = dhd_idx2net(pub, 0); + + runtime_pm = bus->host_suspend; + + if (!runtime_pm && state) { + netif_stop_queue(netdev); + DHD_ERROR(("prepare in suspend mode stop net device traffic\n")); + } +#endif /* DHD_USE_IDLECOUNT */ + ret = dhdpcie_bus_suspend(bus, state); +#ifdef DHD_USE_IDLECOUNT + if (!runtime_pm) { + if (state) { + if (ret != BCME_OK) { + DHD_ERROR(("fail to suspend, start net device traffic\n")); + netif_start_queue(netdev); + } + } + } +#endif /* DHD_USE_IDLECOUNT */ + } + + if (bus) + mutex_unlock(&bus->pm_lock); + + return ret; +} + +static int dhdpcie_pci_suspend(struct pci_dev * pdev, pm_message_t state) +{ + BCM_REFERENCE(state); + return dhdpcie_set_suspend_resume(pdev, TRUE); +} + +static int dhdpcie_pci_resume(struct pci_dev *pdev) +{ + return dhdpcie_set_suspend_resume(pdev, FALSE); +} + +static int dhdpcie_suspend_dev(struct pci_dev *dev) +{ + int ret; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + dhdpcie_info_t *pch = pci_get_drvdata(dev); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) */ + DHD_TRACE_HW4(("%s: Enter\n", __FUNCTION__)); + pci_save_state(dev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + pch->state = pci_store_saved_state(dev); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) */ + pci_enable_wake(dev, PCI_D0, TRUE); + if (pci_is_enabled(dev)) { + pci_disable_device(dev); + } + ret = pci_set_power_state(dev, PCI_D3hot); + if (ret) { + DHD_ERROR(("%s: pci_set_power_state error %d\n", + __FUNCTION__, ret)); + } + return ret; +} + +static int dhdpcie_resume_dev(struct pci_dev *dev) +{ + int err = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + dhdpcie_info_t *pch = pci_get_drvdata(dev); + pci_load_and_free_saved_state(dev, &pch->state); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) */ + DHD_TRACE_HW4(("%s: Enter\n", __FUNCTION__)); + pci_restore_state(dev); + err = pci_enable_device(dev); + if (err) { + printf("%s:pci_enable_device error %d \n", __FUNCTION__, err); + return err; + } + pci_set_master(dev); + err = pci_set_power_state(dev, PCI_D0); + if (err) { + printf("%s:pci_set_power_state error %d \n", __FUNCTION__, err); + return err; + } + return err; +} + +int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state) +{ + int rc; + struct pci_dev *dev = bus->dev; + + if (state) { +#ifndef BCMPCIE_OOB_HOST_WAKE + dhdpcie_pme_active(bus->osh, state); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + rc = dhdpcie_suspend_dev(dev); + } else { + rc = dhdpcie_resume_dev(dev); +#ifndef BCMPCIE_OOB_HOST_WAKE + dhdpcie_pme_active(bus->osh, state); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + } + return rc; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +static int dhdpcie_device_scan(struct device *dev, void *data) +{ + struct pci_dev *pcidev; + int *cnt = data; + + pcidev = container_of(dev, struct pci_dev, dev); + if (pcidev->vendor != 0x14e4) + return 0; + + DHD_INFO(("Found Broadcom PCI device 0x%04x\n", pcidev->device)); + *cnt += 1; + if (pcidev->driver && strcmp(pcidev->driver->name, dhdpcie_driver.name)) + DHD_ERROR(("Broadcom PCI Device 0x%04x has allocated with driver %s\n", + pcidev->device, pcidev->driver->name)); + + return 0; +} +#endif /* LINUX_VERSION >= 2.6.0 */ + +int +dhdpcie_bus_register(void) +{ + int error = 0; + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) + if (!(error = pci_module_init(&dhdpcie_driver))) + return 0; + + DHD_ERROR(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error)); +#else + if (!(error = pci_register_driver(&dhdpcie_driver))) { + bus_for_each_dev(dhdpcie_driver.driver.bus, NULL, &error, dhdpcie_device_scan); + if (!error) { + DHD_ERROR(("No Broadcom PCI device enumerated!\n")); + } else if (!dhdpcie_init_succeeded) { + DHD_ERROR(("%s: dhdpcie initialize failed.\n", __FUNCTION__)); + } else { + return 0; + } + + pci_unregister_driver(&dhdpcie_driver); + error = BCME_ERROR; + } +#endif /* LINUX_VERSION < 2.6.0 */ + + return error; +} + + +void +dhdpcie_bus_unregister(void) +{ + pci_unregister_driver(&dhdpcie_driver); +} + +int __devinit +dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + + if (dhdpcie_chipmatch (pdev->vendor, pdev->device)) { + DHD_ERROR(("%s: chipmatch failed!!\n", __FUNCTION__)); + return -ENODEV; + } + printf("PCI_PROBE: bus %X, slot %X,vendor %X, device %X" + "(good PCI location)\n", pdev->bus->number, + PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device); + +#if defined(CUSTOMER_HW5) && defined(CONFIG_ARCH_MSM) + if (msm_pcie_pm_control(MSM_PCIE_RESUME, pdev->bus->number, pdev, NULL, 0)) { + DHD_ERROR(("%s Failed to resume PCIE link\n", __FUNCTION__)); + return -ENODEV; + } + + if (msm_pcie_recover_config(pdev)) { + DHD_ERROR(("%s Failed to recover PCIE config\n", __FUNCTION__)); + return -ENODEV; + } +#endif /* CUSTOMER_HW5 && CONFIG_ARCH_MSM */ + + if (dhdpcie_init (pdev)) { + DHD_ERROR(("%s: PCIe Enumeration failed\n", __FUNCTION__)); + return -ENODEV; + } + +#ifdef BCMPCIE_DISABLE_ASYNC_SUSPEND + /* disable async suspend */ + device_disable_async_suspend(&pdev->dev); +#endif /* BCMPCIE_DISABLE_ASYNC_SUSPEND */ + + DHD_TRACE(("%s: PCIe Enumeration done!!\n", __FUNCTION__)); + return 0; +} + +int +dhdpcie_detach(dhdpcie_info_t *pch) +{ + if (pch) { + osl_t *osh = pch->osh; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (!dhd_download_fw_on_driverload) { + pci_load_and_free_saved_state(pch->dev, &pch->default_state); + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ + MFREE(osh, pch, sizeof(dhdpcie_info_t)); + } + return 0; +} + + +void __devexit +dhdpcie_pci_remove(struct pci_dev *pdev) +{ + osl_t *osh = NULL; + dhdpcie_info_t *pch = NULL; + dhd_bus_t *bus = NULL; +#ifdef PCIE_TX_DEFERRAL + struct sk_buff *skb; +#endif + + DHD_TRACE(("%s Enter\n", __FUNCTION__)); + pch = pci_get_drvdata(pdev); + bus = pch->bus; + osh = pch->osh; + +#ifdef PCIE_TX_DEFERRAL + if (bus->tx_wq) + destroy_workqueue(bus->tx_wq); + skb = skb_dequeue(&bus->orphan_list); + while (skb) { + PKTCFREE(osh, skb, TRUE); + skb = skb_dequeue(&bus->orphan_list); + } +#endif + +#ifdef SUPPORT_LINKDOWN_RECOVERY +#ifdef CONFIG_ARCH_MSM + if (bus) + msm_pcie_deregister_event(&bus->pcie_event); +#endif /* CONFIG_ARCH_MSM */ +#endif /* SUPPORT_LINKDOWN_RECOVERY */ + + dhdpcie_bus_remove_prep(bus); + dhdpcie_bus_release(bus); + if (pci_is_enabled(pdev)) + pci_disable_device(pdev); +#ifdef BCMPCIE_OOB_HOST_WAKE + /* pcie os info detach */ + MFREE(osh, pch->os_cxt, sizeof(dhdpcie_os_info_t)); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + /* pcie info detach */ + dhdpcie_detach(pch); + /* osl detach */ + osl_detach(osh); + + dhdpcie_init_succeeded = FALSE; + + DHD_TRACE(("%s Exit\n", __FUNCTION__)); + + return; +} + +/* Free Linux irq */ +int +dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info) +{ + dhd_bus_t *bus = dhdpcie_info->bus; + struct pci_dev *pdev = dhdpcie_info->bus->dev; + +#ifdef SET_PCIEIRQ_CPU0 + int ret; +#endif + + snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname), + "dhdpcie:%s", pci_name(pdev)); + if (request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED, + dhdpcie_info->pciname, bus) < 0) { + DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__)); + return -1; + } + + DHD_TRACE(("%s %s\n", __FUNCTION__, dhdpcie_info->pciname)); + +#ifdef SET_PCIEIRQ_CPU0 + /* make sure the irq only from cpu core 0 */ + ret = irq_set_affinity(pdev->irq, cpumask_of(0)); + if (ret) { + DHD_ERROR(("%s: irq_set_affinity error(%d)\n", __FUNCTION__, ret)); + } +#endif + + + return 0; /* SUCCESS */ +} + +#ifdef CONFIG_PHYS_ADDR_T_64BIT +#define PRINTF_RESOURCE "0x%016llx" +#else +#define PRINTF_RESOURCE "0x%08x" +#endif + +/* + +Name: osl_pci_get_resource + +Parametrs: + +1: struct pci_dev *pdev -- pci device structure +2: pci_res -- structure containing pci configuration space values + + +Return value: + +int - Status (TRUE or FALSE) + +Description: +Access PCI configuration space, retrieve PCI allocated resources , updates in resource structure. + + */ +int dhdpcie_get_resource(dhdpcie_info_t *dhdpcie_info) +{ + phys_addr_t bar0_addr, bar1_addr; + ulong bar1_size; + struct pci_dev *pdev = NULL; + pdev = dhdpcie_info->dev; + do { + if (pci_enable_device(pdev)) { + printf("%s: Cannot enable PCI device\n", __FUNCTION__); + break; + } + pci_set_master(pdev); + bar0_addr = pci_resource_start(pdev, 0); /* Bar-0 mapped address */ + bar1_addr = pci_resource_start(pdev, 2); /* Bar-1 mapped address */ + + /* read Bar-1 mapped memory range */ + bar1_size = pci_resource_len(pdev, 2); + + if ((bar1_size == 0) || (bar1_addr == 0)) { + printf("%s: BAR1 Not enabled for this device size(%ld)," + " addr(0x"PRINTF_RESOURCE")\n", + __FUNCTION__, bar1_size, bar1_addr); + goto err; + } + + dhdpcie_info->regs = (volatile char *) REG_MAP(bar0_addr, DONGLE_REG_MAP_SIZE); + dhdpcie_info->tcm_size = + (bar1_size < DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE; + dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size); + + if (!dhdpcie_info->regs || !dhdpcie_info->tcm) { + DHD_ERROR(("%s:ioremap() failed\n", __FUNCTION__)); + break; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (!dhd_download_fw_on_driverload) { + /* Backup PCIe configuration so as to use Wi-Fi on/off process + * in case of built in driver + */ + pci_save_state(pdev); + dhdpcie_info->default_state = pci_store_saved_state(pdev); + + if (dhdpcie_info->default_state == NULL) { + DHD_ERROR(("%s pci_store_saved_state returns NULL\n", + __FUNCTION__)); + REG_UNMAP(dhdpcie_info->regs); + REG_UNMAP(dhdpcie_info->tcm); + pci_disable_device(pdev); + break; + } + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ + + DHD_TRACE(("%s:Phys addr : reg space = %p base addr 0x"PRINTF_RESOURCE" \n", + __FUNCTION__, dhdpcie_info->regs, bar0_addr)); + DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n", + __FUNCTION__, dhdpcie_info->tcm, bar1_addr)); + + return 0; /* SUCCESS */ + } while (0); +err: + return -1; /* FAILURE */ +} + +int dhdpcie_scan_resource(dhdpcie_info_t *dhdpcie_info) +{ + + DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); + + do { + /* define it here only!! */ + if (dhdpcie_get_resource (dhdpcie_info)) { + DHD_ERROR(("%s: Failed to get PCI resources\n", __FUNCTION__)); + break; + } + DHD_TRACE(("%s:Exit - SUCCESS \n", + __FUNCTION__)); + + return 0; /* SUCCESS */ + + } while (0); + + DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__)); + + return -1; /* FAILURE */ + +} + +#ifdef SUPPORT_LINKDOWN_RECOVERY +#ifdef CONFIG_ARCH_MSM +void dhdpcie_linkdown_cb(struct msm_pcie_notify *noti) +{ + struct pci_dev *pdev = (struct pci_dev *)noti->user; + dhdpcie_info_t *pch = NULL; + + if (pdev) { + pch = pci_get_drvdata(pdev); + if (pch) { + dhd_bus_t *bus = pch->bus; + if (bus) { + dhd_pub_t *dhd = bus->dhd; + if (dhd) { + DHD_ERROR(("%s: Event HANG send up " + "due to PCIe linkdown\n", + __FUNCTION__)); + bus->islinkdown = TRUE; + DHD_OS_WAKE_LOCK(dhd); + dhd_os_check_hang(dhd, 0, -ETIMEDOUT); + } + } + } + } + +} +#endif /* CONFIG_ARCH_MSM */ +#endif /* SUPPORT_LINKDOWN_RECOVERY */ + +#ifdef PCIE_TX_DEFERRAL +static void dhd_pcie_create_flow_worker(struct work_struct *worker) +{ + dhd_bus_t *bus; + struct sk_buff *skb; + uint16 ifidx, flowid; + flow_queue_t *queue; + flow_ring_node_t *flow_ring_node; + unsigned long flags; + + bus = container_of(worker, dhd_bus_t, create_flow_work); + skb = skb_dequeue(&bus->orphan_list); + while (skb) { + ifidx = DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(skb)); + if (BCME_OK != dhd_flowid_update(bus->dhd, ifidx, + bus->dhd->flow_prio_map[(PKTPRIO(skb))], skb)) { + PKTCFREE(bus->dhd->osh, skb, TRUE); + skb = skb_dequeue(&bus->orphan_list); + continue; + } + flowid = DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(skb)); + flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); + queue = &flow_ring_node->queue; + DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); + if ((flowid >= bus->dhd->num_flow_rings) || + (!flow_ring_node->active) || + (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING)) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + DHD_ERROR(("%s: Dropping pkt flowid %d, status %d active %d\n", + __FUNCTION__, flowid, flow_ring_node->status, + flow_ring_node->active)); + PKTCFREE(bus->dhd->osh, skb, TRUE); + skb = skb_dequeue(&bus->orphan_list); + continue; + } + if (BCME_OK != dhd_flow_queue_enqueue(bus->dhd, queue, skb)) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + PKTCFREE(bus->dhd->osh, skb, TRUE); + skb = skb_dequeue(&bus->orphan_list); + continue; + } + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + + if (flow_ring_node->status == FLOW_RING_STATUS_OPEN) + dhd_bus_schedule_queue(bus, flowid, FALSE); + + skb = skb_dequeue(&bus->orphan_list); + } +} + +static void dhd_pcie_delete_flow_worker(struct work_struct *worker) +{ + dhd_bus_t *bus; + uint16 flowid; + + bus = container_of(worker, dhd_bus_t, delete_flow_work); + for_each_set_bit(flowid, bus->delete_flow_map, bus->dhd->num_flow_rings) { + clear_bit(flowid, bus->delete_flow_map); + dhd_bus_flow_ring_delete_response(bus, flowid, BCME_OK); + } +} + +#endif /* PCIE_TX_DEFERRAL */ + +int dhdpcie_init(struct pci_dev *pdev) +{ + + osl_t *osh = NULL; + dhd_bus_t *bus = NULL; + dhdpcie_info_t *dhdpcie_info = NULL; + wifi_adapter_info_t *adapter = NULL; +#ifdef BCMPCIE_OOB_HOST_WAKE + dhdpcie_os_info_t *dhdpcie_osinfo = NULL; +#endif /* BCMPCIE_OOB_HOST_WAKE */ + + do { + /* osl attach */ + if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { + DHD_ERROR(("%s: osl_attach failed\n", __FUNCTION__)); + break; + } + + /* initialize static buffer */ + adapter = dhd_wifi_platform_get_adapter(PCI_BUS, pdev->bus->number, + PCI_SLOT(pdev->devfn)); + if (adapter != NULL) + DHD_ERROR(("%s: found adapter info '%s'\n", __FUNCTION__, adapter->name)); + else + DHD_ERROR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); + osl_static_mem_init(osh, adapter); + + /* allocate linux spcific pcie structure here */ + if (!(dhdpcie_info = MALLOC(osh, sizeof(dhdpcie_info_t)))) { + DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); + break; + } + bzero(dhdpcie_info, sizeof(dhdpcie_info_t)); + dhdpcie_info->osh = osh; + dhdpcie_info->dev = pdev; + +#ifdef BCMPCIE_OOB_HOST_WAKE + /* allocate OS speicific structure */ + dhdpcie_osinfo = MALLOC(osh, sizeof(dhdpcie_os_info_t)); + if (dhdpcie_osinfo == NULL) { + DHD_ERROR(("%s: MALLOC of dhdpcie_os_info_t failed\n", + __FUNCTION__)); + break; + } + bzero(dhdpcie_osinfo, sizeof(dhdpcie_os_info_t)); + dhdpcie_info->os_cxt = (void *)dhdpcie_osinfo; + + /* Initialize host wake IRQ */ + spin_lock_init(&dhdpcie_osinfo->oob_irq_spinlock); + /* Get customer specific host wake IRQ parametres: IRQ number as IRQ type */ + dhdpcie_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter, + &dhdpcie_osinfo->oob_irq_flags); + if (dhdpcie_osinfo->oob_irq_num < 0) { + DHD_ERROR(("%s: Host OOB irq is not defined\n", __FUNCTION__)); + } +#endif /* BCMPCIE_OOB_HOST_WAKE */ + + /* Find the PCI resources, verify the */ + /* vendor and device ID, map BAR regions and irq, update in structures */ + if (dhdpcie_scan_resource(dhdpcie_info)) { + DHD_ERROR(("%s: dhd_Scan_PCI_Res failed\n", __FUNCTION__)); + + break; + } + + /* Bus initialization */ + bus = dhdpcie_bus_attach(osh, dhdpcie_info->regs, + dhdpcie_info->tcm, dhdpcie_info->tcm_size); + if (!bus) { + DHD_ERROR(("%s:dhdpcie_bus_attach() failed\n", __FUNCTION__)); + break; + } + + dhdpcie_info->bus = bus; + dhdpcie_info->bus->dev = pdev; + +#ifdef SUPPORT_LINKDOWN_RECOVERY +#ifdef CONFIG_ARCH_MSM + bus->pcie_event.events = MSM_PCIE_EVENT_LINKDOWN; + bus->pcie_event.user = pdev; + bus->pcie_event.mode = MSM_PCIE_TRIGGER_CALLBACK; + bus->pcie_event.callback = dhdpcie_linkdown_cb; + bus->pcie_event.options = MSM_PCIE_CONFIG_NO_RECOVERY; + msm_pcie_register_event(&bus->pcie_event); + bus->islinkdown = FALSE; +#endif /* CONFIG_ARCH_MSM */ +#endif /* SUPPORT_LINKDOWN_RECOVERY */ + + if (bus->intr) { + /* Register interrupt callback, but mask it (not operational yet). */ + DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__)); + dhdpcie_bus_intr_disable(bus); + + if (dhdpcie_request_irq(dhdpcie_info)) { + DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__)); + break; + } + } else { + bus->pollrate = 1; + DHD_INFO(("%s: PCIe interrupt function is NOT registered " + "due to polling mode\n", __FUNCTION__)); + } + +#if defined(BCM_REQUEST_FW) + if (dhd_bus_download_firmware(bus, osh, NULL, NULL) < 0) { + DHD_ERROR(("%s: failed to download firmware\n", __FUNCTION__)); + } + bus->nv_path = NULL; + bus->fw_path = NULL; +#endif /* BCM_REQUEST_FW */ + + if (dhd_download_fw_on_driverload) { + if (dhd_bus_start(bus->dhd)) { + DHD_ERROR(("%s: dhd_bud_start() failed\n", __FUNCTION__)); + break; + } + } + + /* set private data for pci_dev */ + pci_set_drvdata(pdev, dhdpcie_info); + +#ifdef PCIE_TX_DEFERRAL + bus->tx_wq = create_singlethread_workqueue("bcmdhd_tx"); + if (bus->tx_wq == NULL) { + DHD_ERROR(("%s workqueue creation failed\n", __FUNCTION__)); + break; + } + INIT_WORK(&bus->create_flow_work, dhd_pcie_create_flow_worker); + INIT_WORK(&bus->delete_flow_work, dhd_pcie_delete_flow_worker); + skb_queue_head_init(&bus->orphan_list); +#endif /* PCIE_TX_DEFERRAL */ + + /* Attach to the OS network interface */ + DHD_TRACE(("%s(): Calling dhd_register_if() \n", __FUNCTION__)); + if (dhd_register_if(bus->dhd, 0, TRUE)) { + DHD_ERROR(("%s(): ERROR.. dhd_register_if() failed\n", __FUNCTION__)); + break; + } + + dhdpcie_init_succeeded = TRUE; + + DHD_TRACE(("%s:Exit - SUCCESS \n", __FUNCTION__)); + return 0; /* return SUCCESS */ + + } while (0); + /* reverse the initialization in order in case of error */ + + if (bus) + dhdpcie_bus_release(bus); + +#ifdef BCMPCIE_OOB_HOST_WAKE + if (dhdpcie_osinfo) + MFREE(osh, dhdpcie_osinfo, sizeof(dhdpcie_os_info_t)); +#endif /* BCMPCIE_OOB_HOST_WAKE */ + + if (dhdpcie_info) + dhdpcie_detach(dhdpcie_info); + pci_disable_device(pdev); + if (osh) + osl_detach(osh); + + dhdpcie_init_succeeded = FALSE; + + DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__)); + + return -1; /* return FAILURE */ +} + +/* Free Linux irq */ +void +dhdpcie_free_irq(dhd_bus_t *bus) +{ + struct pci_dev *pdev = NULL; + + DHD_TRACE(("%s: freeing up the IRQ\n", __FUNCTION__)); + if (bus) { + pdev = bus->dev; + free_irq(pdev->irq, bus); + } + DHD_TRACE(("%s: Exit\n", __FUNCTION__)); + return; +} + +/* + +Name: dhdpcie_isr + +Parametrs: + +1: IN int irq -- interrupt vector +2: IN void *arg -- handle to private data structure + +Return value: + +Status (TRUE or FALSE) + +Description: +Interrupt Service routine checks for the status register, +disable interrupt and queue DPC if mail box interrupts are raised. +*/ + + +irqreturn_t +dhdpcie_isr(int irq, void *arg) +{ + dhd_bus_t *bus = (dhd_bus_t*)arg; + if (dhdpcie_bus_isr(bus)) + return TRUE; + else + return FALSE; +} + +int +dhdpcie_start_host_pcieclock(dhd_bus_t *bus) +{ + int ret = 0; +#ifdef CONFIG_ARCH_MSM +#ifdef SUPPORT_LINKDOWN_RECOVERY + int options = 0; +#endif /* SUPPORT_LINKDOWN_RECOVERY */ +#endif /* CONFIG_ARCH_MSM */ + DHD_TRACE(("%s Enter:\n", __FUNCTION__)); + + if (bus == NULL) + return BCME_ERROR; + + if (bus->dev == NULL) + return BCME_ERROR; + + mutex_lock(&bus->host_clock_lock); +#ifdef CONFIG_ARCH_MSM +#ifdef SUPPORT_LINKDOWN_RECOVERY + if (bus->islinkdown) { + options = MSM_PCIE_CONFIG_NO_CFG_RESTORE; + } + ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number, + bus->dev, NULL, options); + if (bus->islinkdown && !ret) { + msm_pcie_recover_config(bus->dev); + if (bus->dhd) + DHD_OS_WAKE_UNLOCK(bus->dhd); + bus->islinkdown = FALSE; + } +#else + ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number, + bus->dev, NULL, 0); +#endif /* SUPPORT_LINKDOWN_RECOVERY */ + if (ret) { + DHD_ERROR(("%s Failed to bring up PCIe link\n", __FUNCTION__)); + goto done; + } + +done: +#endif /* CONFIG_ARCH_MSM */ + mutex_unlock(&bus->host_clock_lock); + DHD_TRACE(("%s Exit:\n", __FUNCTION__)); + return ret; +} + +int +dhdpcie_stop_host_pcieclock(dhd_bus_t *bus) +{ + int ret = 0; + +#ifdef CONFIG_ARCH_MSM +#ifdef SUPPORT_LINKDOWN_RECOVERY + int options = 0; +#endif /* SUPPORT_LINKDOWN_RECOVERY */ +#endif /* CONFIG_ARCH_MSM */ + DHD_TRACE(("%s Enter:\n", __FUNCTION__)); + + if (bus == NULL) + return BCME_ERROR; + + if (bus->dev == NULL) + return BCME_ERROR; + + mutex_lock(&bus->host_clock_lock); +#ifdef CONFIG_ARCH_MSM +#ifdef SUPPORT_LINKDOWN_RECOVERY + if (bus->islinkdown) + options = MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN; + + ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number, + bus->dev, NULL, options); +#else + ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number, + bus->dev, NULL, 0); +#endif /* SUPPORT_LINKDOWN_RECOVERY */ + if (ret) { + DHD_ERROR(("Failed to stop PCIe link\n")); + goto done; + } +done: +#endif /* CONFIG_ARCH_MSM */ + mutex_unlock(&bus->host_clock_lock); + DHD_TRACE(("%s Exit:\n", __FUNCTION__)); + return ret; +} + +int +dhdpcie_disable_device(dhd_bus_t *bus) +{ + if (bus == NULL) + return BCME_ERROR; + + if (bus->dev == NULL) + return BCME_ERROR; + + pci_disable_device(bus->dev); + + return 0; +} + +int +dhdpcie_enable_device(dhd_bus_t *bus) +{ + int ret = BCME_ERROR; + dhdpcie_info_t *pch; + + DHD_TRACE(("%s Enter:\n", __FUNCTION__)); + + if (bus == NULL) + return BCME_ERROR; + + if (bus->dev == NULL) + return BCME_ERROR; + + pch = pci_get_drvdata(bus->dev); + if (pch == NULL) + return BCME_ERROR; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + /* Updated with pci_load_and_free_saved_state to compatible + * with kernel 3.14 or higher + */ + if (pci_load_and_free_saved_state(bus->dev, &pch->default_state)) { + pci_disable_device(bus->dev); + } else { +#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))) + if (pci_load_saved_state(bus->dev, pch->default_state)) + pci_disable_device(bus->dev); + else { +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) and + * (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + * (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) + */ + + pci_restore_state(bus->dev); + ret = pci_enable_device(bus->dev); + if (!ret) + pci_set_master(bus->dev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) and + * (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + * (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) + */ + + if (ret) + pci_disable_device(bus->dev); + + return ret; +} + +int +dhdpcie_alloc_resource(dhd_bus_t *bus) +{ + dhdpcie_info_t *dhdpcie_info; + phys_addr_t bar0_addr, bar1_addr; + ulong bar1_size; + + do { + if (bus == NULL) { + DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); + break; + } + + if (bus->dev == NULL) { + DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); + break; + } + + dhdpcie_info = pci_get_drvdata(bus->dev); + if (dhdpcie_info == NULL) { + DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__)); + break; + } + + bar0_addr = pci_resource_start(bus->dev, 0); /* Bar-0 mapped address */ + bar1_addr = pci_resource_start(bus->dev, 2); /* Bar-1 mapped address */ + + /* read Bar-1 mapped memory range */ + bar1_size = pci_resource_len(bus->dev, 2); + + if ((bar1_size == 0) || (bar1_addr == 0)) { + printf("%s: BAR1 Not enabled for this device size(%ld)," + " addr(0x"PRINTF_RESOURCE")\n", + __FUNCTION__, bar1_size, bar1_addr); + break; + } + + dhdpcie_info->regs = (volatile char *) REG_MAP(bar0_addr, DONGLE_REG_MAP_SIZE); + if (!dhdpcie_info->regs) { + DHD_ERROR(("%s: ioremap() for regs is failed\n", __FUNCTION__)); + break; + } + + bus->regs = dhdpcie_info->regs; + dhdpcie_info->tcm_size = + (bar1_size < DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE; + dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size); + if (!dhdpcie_info->tcm) { + DHD_ERROR(("%s: ioremap() for regs is failed\n", __FUNCTION__)); + REG_UNMAP(dhdpcie_info->regs); + bus->regs = NULL; + break; + } + + bus->tcm = dhdpcie_info->tcm; + bus->tcm_size = dhdpcie_info->tcm_size; + + DHD_TRACE(("%s:Phys addr : reg space = %p base addr 0x"PRINTF_RESOURCE" \n", + __FUNCTION__, dhdpcie_info->regs, bar0_addr)); + DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n", + __FUNCTION__, dhdpcie_info->tcm, bar1_addr)); + + return 0; + } while (0); + + return BCME_ERROR; +} + +void +dhdpcie_free_resource(dhd_bus_t *bus) +{ + dhdpcie_info_t *dhdpcie_info; + + if (bus == NULL) { + DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); + return; + } + + if (bus->dev == NULL) { + DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); + return; + } + + dhdpcie_info = pci_get_drvdata(bus->dev); + if (dhdpcie_info == NULL) { + DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__)); + return; + } + + if (bus->regs) { + REG_UNMAP(dhdpcie_info->regs); + bus->regs = NULL; + } + + if (bus->tcm) { + REG_UNMAP(dhdpcie_info->tcm); + bus->tcm = NULL; + } + + if (bus->pcie_mb_intr_addr) { + bus->pcie_mb_intr_addr = NULL; + } +} + +int +dhdpcie_bus_request_irq(struct dhd_bus *bus) +{ + dhdpcie_info_t *dhdpcie_info; + int ret = 0; + + if (bus == NULL) { + DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); + return BCME_ERROR; + } + + if (bus->dev == NULL) { + DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); + return BCME_ERROR; + } + + dhdpcie_info = pci_get_drvdata(bus->dev); + if (dhdpcie_info == NULL) { + DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__)); + return BCME_ERROR; + } + + if (bus->intr) { + /* Register interrupt callback, but mask it (not operational yet). */ + DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__)); + dhdpcie_bus_intr_disable(bus); + ret = dhdpcie_request_irq(dhdpcie_info); + if (ret) { + DHD_ERROR(("%s: request_irq() failed, ret=%d\n", + __FUNCTION__, ret)); + return ret; + } + } + + return ret; +} + +#ifdef BCMPCIE_OOB_HOST_WAKE +void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable) +{ + unsigned long flags; + dhdpcie_info_t *pch; + dhdpcie_os_info_t *dhdpcie_osinfo; + + if (bus == NULL) { + DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); + return; + } + + if (bus->dev == NULL) { + DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); + return; + } + + pch = pci_get_drvdata(bus->dev); + if (pch == NULL) { + DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__)); + return; + } + + dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt; + spin_lock_irqsave(&dhdpcie_osinfo->oob_irq_spinlock, flags); + if ((dhdpcie_osinfo->oob_irq_enabled != enable) && + (dhdpcie_osinfo->oob_irq_num > 0)) { + if (enable) + enable_irq(dhdpcie_osinfo->oob_irq_num); + else + disable_irq_nosync(dhdpcie_osinfo->oob_irq_num); + dhdpcie_osinfo->oob_irq_enabled = enable; + } + spin_unlock_irqrestore(&dhdpcie_osinfo->oob_irq_spinlock, flags); +} + +static irqreturn_t wlan_oob_irq(int irq, void *data) +{ + dhd_bus_t *bus; + DHD_TRACE(("%s: IRQ Triggered\n", __FUNCTION__)); + bus = (dhd_bus_t *)data; + + dhdpcie_oob_intr_set(bus, FALSE); + +#ifdef DHD_USE_IDLECOUNT + bus_wakeup(bus); +#endif /* DHD_USE_IDLECOUNT */ + if (bus->dhd->up && bus->suspended) { + DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(bus->dhd, OOB_WAKE_LOCK_TIMEOUT); + } + return IRQ_HANDLED; +} + +int dhdpcie_oob_intr_register(dhd_bus_t *bus) +{ + int err = 0; + dhdpcie_info_t *pch; + dhdpcie_os_info_t *dhdpcie_osinfo; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (bus == NULL) { + DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); + return -EINVAL; + } + + if (bus->dev == NULL) { + DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); + return -EINVAL; + } + + pch = pci_get_drvdata(bus->dev); + if (pch == NULL) { + DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__)); + return -EINVAL; + } + + dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt; + if (dhdpcie_osinfo->oob_irq_registered) { + DHD_ERROR(("%s: irq is already registered\n", __FUNCTION__)); + return -EBUSY; + } + + if (dhdpcie_osinfo->oob_irq_num > 0) { + DHD_INFO_HW4(("%s OOB irq=%d flags=%X \n", __FUNCTION__, + (int)dhdpcie_osinfo->oob_irq_num, + (int)dhdpcie_osinfo->oob_irq_flags)); + err = request_irq(dhdpcie_osinfo->oob_irq_num, wlan_oob_irq, + dhdpcie_osinfo->oob_irq_flags, "dhdpcie_host_wake", + bus); + if (err) { + DHD_ERROR(("%s: request_irq failed with %d\n", + __FUNCTION__, err)); + return err; + } + err = enable_irq_wake(dhdpcie_osinfo->oob_irq_num); + if (!err) + dhdpcie_osinfo->oob_irq_wake_enabled = TRUE; + dhdpcie_osinfo->oob_irq_enabled = TRUE; + } + + dhdpcie_osinfo->oob_irq_registered = TRUE; + + return err; +} + +void dhdpcie_oob_intr_unregister(dhd_bus_t *bus) +{ + int err = 0; + dhdpcie_info_t *pch; + dhdpcie_os_info_t *dhdpcie_osinfo; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (bus == NULL) { + DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); + return; + } + + if (bus->dev == NULL) { + DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); + return; + } + + pch = pci_get_drvdata(bus->dev); + if (pch == NULL) { + DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__)); + return; + } + + dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt; + if (!dhdpcie_osinfo->oob_irq_registered) { + DHD_ERROR(("%s: irq is not registered\n", __FUNCTION__)); + return; + } + if (dhdpcie_osinfo->oob_irq_num > 0) { + if (dhdpcie_osinfo->oob_irq_wake_enabled) { + err = disable_irq_wake(dhdpcie_osinfo->oob_irq_num); + if (!err) + dhdpcie_osinfo->oob_irq_wake_enabled = FALSE; + } + if (dhdpcie_osinfo->oob_irq_enabled) { + disable_irq(dhdpcie_osinfo->oob_irq_num); + dhdpcie_osinfo->oob_irq_enabled = FALSE; + } + free_irq(dhdpcie_osinfo->oob_irq_num, bus); + } + dhdpcie_osinfo->oob_irq_registered = FALSE; +} +#endif /* BCMPCIE_OOB_HOST_WAKE */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c new file mode 100644 index 000000000000..0c7ada8d66a6 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c @@ -0,0 +1,4076 @@ +/* + * Broadcom Dongle Host Driver (DHD) + * Prefered Network Offload and Wi-Fi Location Service(WLS) code. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_pno.c 423669 2013-09-18 13:01:55Z yangj$ + */ +#ifdef PNO_SUPPORT +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef GSCAN_SUPPORT +#include +#endif /* GSCAN_SUPPORT */ + +#ifdef __BIG_ENDIAN +#include +#define htod32(i) (bcmswap32(i)) +#define htod16(i) (bcmswap16(i)) +#define dtoh32(i) (bcmswap32(i)) +#define dtoh16(i) (bcmswap16(i)) +#define htodchanspec(i) htod16(i) +#define dtohchanspec(i) dtoh16(i) +#else +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) +#endif /* IL_BIGENDINA */ + +#define NULL_CHECK(p, s, err) \ + do { \ + if (!(p)) { \ + printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ + err = BCME_ERROR; \ + return err; \ + } \ + } while (0) +#define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) +#define PNO_BESTNET_LEN 2048 +#define PNO_ON 1 +#define PNO_OFF 0 +#define CHANNEL_2G_MAX 14 +#define CHANNEL_5G_MAX 165 +#define MAX_NODE_CNT 5 +#define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE) +#define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \ + - (uint32)(timestamp2/1000))) +#define TIME_DIFF_MS(timestamp1, timestamp2) (abs((uint32)(timestamp1) \ + - (uint32)(timestamp2))) +#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ + (ts).tv_nsec / NSEC_PER_USEC) + +#define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") +#define TIME_MIN_DIFF 5 +static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, + dhd_pno_status_info_t *pno_state); +#ifdef GSCAN_SUPPORT +static wl_pfn_gscan_ch_bucket_cfg_t * +dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state, +uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw); +#endif /* GSCAN_SUPPORT */ +static inline bool +is_dfs(uint16 channel) +{ + if (channel >= 52 && channel <= 64) /* class 2 */ + return TRUE; + else if (channel >= 100 && channel <= 140) /* class 4 */ + return TRUE; + else + return FALSE; +} +int +dhd_pno_clean(dhd_pub_t *dhd) +{ + int pfn = 0; + int err; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + /* Disable PNO */ + err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn(error : %d)\n", + __FUNCTION__, err)); + goto exit; + } + _pno_state->pno_status = DHD_PNO_DISABLED; + err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfnclear(error : %d)\n", + __FUNCTION__, err)); + } +exit: + return err; +} + +bool +dhd_is_pno_supported(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + + if (!dhd || !dhd->pno_state) { + DHD_ERROR(("NULL POINTER : %s\n", + __FUNCTION__)); + return FALSE; + } + _pno_state = PNO_GET_PNOSTATE(dhd); + return WLS_SUPPORTED(_pno_state); +} + +bool +dhd_is_legacy_pno_enabled(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + + if (!dhd || !dhd->pno_state) { + DHD_ERROR(("NULL POINTER : %s\n", + __FUNCTION__)); + return FALSE; + } + _pno_state = PNO_GET_PNOSTATE(dhd); + return ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) != 0); +} + +#ifdef GSCAN_SUPPORT +static uint64 +convert_fw_rel_time_to_systime(uint32 fw_ts_ms) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + return ((uint64)(TIMESPEC_TO_US(ts)) - (uint64)(fw_ts_ms * 1000)); +} + +static void +dhd_pno_idx_to_ssid(struct dhd_pno_gscan_params *gscan_params, + dhd_epno_results_t *res, uint32 idx) +{ + dhd_epno_params_t *iter, *next; + + if (gscan_params->num_epno_ssid > 0) { + list_for_each_entry_safe(iter, next, + &gscan_params->epno_ssid_list, list) { + if (iter->index == idx) { + memcpy(res->ssid, iter->ssid, iter->ssid_len); + res->ssid_len = iter->ssid_len; + return; + } + } + } + /* If we are here then there was no match */ + res->ssid[0] = '\0'; + res->ssid_len = 0; + return; +} + +/* Cleanup all results */ +static void +dhd_gscan_clear_all_batch_results(dhd_pub_t *dhd) +{ + struct dhd_pno_gscan_params *gscan_params; + dhd_pno_status_info_t *_pno_state; + gscan_results_cache_t *iter; + + _pno_state = PNO_GET_PNOSTATE(dhd); + gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; + iter = gscan_params->gscan_batch_cache; + /* Mark everything as consumed */ + while (iter) { + iter->tot_consumed = iter->tot_count; + iter = iter->next; + } + dhd_gscan_batch_cache_cleanup(dhd); + return; +} + +static int +_dhd_pno_gscan_cfg(dhd_pub_t *dhd, wl_pfn_gscan_cfg_t *pfncfg_gscan_param, int size) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + + err = dhd_iovar(dhd, 0, "pfn_gscan_cfg", (char *)pfncfg_gscan_param, size, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfncfg_gscan_param\n", __FUNCTION__)); + goto exit; + } +exit: + return err; +} + +static bool +is_batch_retrieval_complete(struct dhd_pno_gscan_params *gscan_params) +{ + smp_rmb(); + return (gscan_params->get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE); +} +#endif /* GSCAN_SUPPORT */ + +static int +_dhd_pno_suspend(dhd_pub_t *dhd) +{ + int err; + int suspend = 1; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err)); + goto exit; + + } + _pno_state->pno_status = DHD_PNO_SUSPEND; +exit: + return err; +} +static int +_dhd_pno_enable(dhd_pub_t *dhd, int enable) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (enable & 0xfffe) { + DHD_ERROR(("%s invalid value\n", __FUNCTION__)); + err = BCME_BADARG; + goto exit; + } + if (!dhd_support_sta_mode(dhd)) { + DHD_ERROR(("PNO is not allowed for non-STA mode")); + err = BCME_BADOPTION; + goto exit; + } + if (enable) { + if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && + dhd_is_associated(dhd, NULL, NULL)) { + DHD_ERROR(("%s Legacy PNO mode cannot be enabled " + "in assoc mode , ignore it\n", __FUNCTION__)); + err = BCME_BADOPTION; + goto exit; + } + } + /* Enable/Disable PNO */ + err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_set - %d\n", __FUNCTION__, err)); + goto exit; + } + _pno_state->pno_status = (enable)? + DHD_PNO_ENABLED : DHD_PNO_DISABLED; + if (!enable) + _pno_state->pno_mode = DHD_PNO_NONE_MODE; + + DHD_PNO(("%s set pno as %s\n", + __FUNCTION__, enable ? "Enable" : "Disable")); +exit: + return err; +} + +static int +_dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode) +{ + int err = BCME_OK; + wl_pfn_param_t pfn_param; + dhd_pno_params_t *_params; + dhd_pno_status_info_t *_pno_state; + bool combined_scan = FALSE; + DHD_PNO(("%s enter\n", __FUNCTION__)); + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + memset(&pfn_param, 0, sizeof(pfn_param)); + + /* set pfn parameters */ + pfn_param.version = htod32(PFN_VERSION); + pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) | + (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT)); + if (mode == DHD_PNO_LEGACY_MODE) { + /* check and set extra pno params */ + if ((pno_params->params_legacy.pno_repeat != 0) || + (pno_params->params_legacy.pno_freq_expo_max != 0)) { + pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); + pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); + pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max); + } + /* set up pno scan fr */ + if (pno_params->params_legacy.scan_fr != 0) + pfn_param.scan_freq = htod32(pno_params->params_legacy.scan_fr); + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + DHD_PNO(("will enable combined scan with BATCHIG SCAN MODE\n")); + mode |= DHD_PNO_BATCH_MODE; + combined_scan = TRUE; + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + DHD_PNO(("will enable combined scan with HOTLIST SCAN MODE\n")); + mode |= DHD_PNO_HOTLIST_MODE; + combined_scan = TRUE; + } +#ifdef GSCAN_SUPPORT + else if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + DHD_PNO(("will enable combined scan with GSCAN SCAN MODE\n")); + mode |= DHD_PNO_GSCAN_MODE; + } +#endif /* GSCAN_SUPPORT */ + } + if (mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { + /* Scan frequency of 30 sec */ + pfn_param.scan_freq = htod32(30); + /* slow adapt scan is off by default */ + pfn_param.slow_freq = htod32(0); + /* RSSI margin of 30 dBm */ + pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); + /* Network timeout 60 sec */ + pfn_param.lost_network_timeout = htod32(60); + /* best n = 2 by default */ + pfn_param.bestn = DEFAULT_BESTN; + /* mscan m=0 by default, so not record best networks by default */ + pfn_param.mscan = DEFAULT_MSCAN; + /* default repeat = 10 */ + pfn_param.repeat = DEFAULT_REPEAT; + /* by default, maximum scan interval = 2^2 + * scan_freq when adaptive scan is turned on + */ + pfn_param.exp = DEFAULT_EXP; + if (mode == DHD_PNO_BATCH_MODE) { + /* In case of BATCH SCAN */ + if (pno_params->params_batch.bestn) + pfn_param.bestn = pno_params->params_batch.bestn; + if (pno_params->params_batch.scan_fr) + pfn_param.scan_freq = htod32(pno_params->params_batch.scan_fr); + if (pno_params->params_batch.mscan) + pfn_param.mscan = pno_params->params_batch.mscan; + /* enable broadcast scan */ + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + } else if (mode == DHD_PNO_HOTLIST_MODE) { + /* In case of HOTLIST SCAN */ + if (pno_params->params_hotlist.scan_fr) + pfn_param.scan_freq = htod32(pno_params->params_hotlist.scan_fr); + pfn_param.bestn = 0; + pfn_param.repeat = 0; + /* enable broadcast scan */ + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + } + if (combined_scan) { + /* Disable Adaptive Scan */ + pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT)); + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + pfn_param.repeat = 0; + pfn_param.exp = 0; + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + /* In case of Legacy PNO + BATCH SCAN */ + _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + if (_params->params_batch.bestn) + pfn_param.bestn = _params->params_batch.bestn; + if (_params->params_batch.scan_fr) + pfn_param.scan_freq = htod32(_params->params_batch.scan_fr); + if (_params->params_batch.mscan) + pfn_param.mscan = _params->params_batch.mscan; + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + /* In case of Legacy PNO + HOTLIST SCAN */ + _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + if (_params->params_hotlist.scan_fr) + pfn_param.scan_freq = htod32(_params->params_hotlist.scan_fr); + pfn_param.bestn = 0; + pfn_param.repeat = 0; + } + } + } +#ifdef GSCAN_SUPPORT + if (mode & DHD_PNO_GSCAN_MODE) { + uint32 lost_network_timeout; + + pfn_param.scan_freq = htod32(pno_params->params_gscan.scan_fr); + if (pno_params->params_gscan.mscan) { + pfn_param.bestn = pno_params->params_gscan.bestn; + pfn_param.mscan = pno_params->params_gscan.mscan; + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + } + /* RSSI margin of 30 dBm */ + pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); + pfn_param.repeat = 0; + pfn_param.exp = 0; + pfn_param.slow_freq = 0; + pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); + + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + dhd_pno_params_t *_params; + + _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + + pfn_param.scan_freq = htod32(gcd(pno_params->params_gscan.scan_fr, + _params->params_legacy.scan_fr)); + + if ((_params->params_legacy.pno_repeat != 0) || + (_params->params_legacy.pno_freq_expo_max != 0)) { + pfn_param.repeat = (uchar) (_params->params_legacy.pno_repeat); + pfn_param.exp = (uchar) (_params->params_legacy.pno_freq_expo_max); + } + } + + lost_network_timeout = (pno_params->params_gscan.max_ch_bucket_freq * + pfn_param.scan_freq * + pno_params->params_gscan.lost_ap_window); + if (lost_network_timeout) { + pfn_param.lost_network_timeout = htod32(MIN(lost_network_timeout, + GSCAN_MIN_BSSID_TIMEOUT)); + } else { + pfn_param.lost_network_timeout = htod32(GSCAN_MIN_BSSID_TIMEOUT); + } + } else +#endif /* GSCAN_SUPPORT */ + { + if (pfn_param.scan_freq < htod32(PNO_SCAN_MIN_FW_SEC) || + pfn_param.scan_freq > htod32(PNO_SCAN_MAX_FW_SEC)) { + DHD_ERROR(("%s pno freq(%d sec) is not valid \n", + __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); + err = BCME_BADARG; + goto exit; + } + } + + err = dhd_set_rand_mac_oui(dhd); + /* Ignore if chip doesnt support the feature */ + if (err < 0 && err != BCME_UNSUPPORTED) { + DHD_ERROR(("%s : failed to set random mac for PNO scan, %d\n", __FUNCTION__, err)); + goto exit; + } + +#ifdef GSCAN_SUPPORT + if (mode == DHD_PNO_BATCH_MODE || + ((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) { +#else + if (mode == DHD_PNO_BATCH_MODE) { +#endif /* GSCAN_SUPPORT */ + int _tmp = pfn_param.bestn; + /* set bestn to calculate the max mscan which firmware supports */ + err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to set pfnmem\n", __FUNCTION__)); + goto exit; + } + /* get max mscan which the firmware supports */ + err = dhd_iovar(dhd, 0, "pfnmem", NULL, 0, (char *)&_tmp, sizeof(_tmp), FALSE); + if (err < 0) { + DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__)); + goto exit; + } + pfn_param.mscan = MIN(pfn_param.mscan, _tmp); + DHD_PNO((" returned mscan : %d, set bestn : %d mscan %d\n", _tmp, pfn_param.bestn, + pfn_param.mscan)); + } + err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err)); + goto exit; + } + /* need to return mscan if this is for batch scan instead of err */ + err = (mode == DHD_PNO_BATCH_MODE)? pfn_param.mscan : err; +exit: + return err; +} +static int +_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssids_list, int nssid) +{ + int err = BCME_OK; + int i = 0; + wl_pfn_t pfn_element; + + NULL_CHECK(dhd, "dhd is NULL", err); + if (nssid) { + NULL_CHECK(ssids_list, "ssid list is NULL", err); + } + memset(&pfn_element, 0, sizeof(pfn_element)); + { + int j; + for (j = 0; j < nssid; j++) { + DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n", + ssids_list[j].SSID, ssids_list[j].SSID_len, ssids_list[j].hidden, + ssids_list[j].flags, ssids_list[i].rssi_thresh)); + } + } + /* Check for broadcast ssid */ + for (i = 0; i < nssid; i++) { + if (!ssids_list[i].SSID_len) { + DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", i)); + err = BCME_ERROR; + goto exit; + } + } + /* set all pfn ssid */ + for (i = 0; i < nssid; i++) { + pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); + pfn_element.auth = (DOT11_OPEN_SYSTEM); + pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); + pfn_element.wsec = htod32(0); + pfn_element.infra = htod32(1); + if (ssids_list[i].hidden) { + pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); + } else { + pfn_element.flags = 0; + } + pfn_element.flags |= htod32(ssids_list[i].flags); + /* If a single RSSI threshold is defined, use that */ +#ifdef PNO_MIN_RSSI_TRIGGER + pfn_element.flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT); +#else + pfn_element.flags |= ((ssids_list[i].rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT); +#endif /* PNO_MIN_RSSI_TRIGGER */ + memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, + ssids_list[i].SSID_len); + pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; + err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, sizeof(wl_pfn_t), + NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); + goto exit; + } + } +exit: + return err; +} +/* qsort compare function */ +static int +_dhd_pno_cmpfunc(const void *a, const void *b) +{ + return (*(uint16*)a - *(uint16*)b); +} +static int +_dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan, + uint16 *chan_list1, int nchan1, uint16 *chan_list2, int nchan2) +{ + int err = BCME_OK; + int i = 0, j = 0, k = 0; + uint16 tmp; + NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); + NULL_CHECK(nchan, "nchan is NULL", err); + NULL_CHECK(chan_list1, "chan_list1 is NULL", err); + NULL_CHECK(chan_list2, "chan_list2 is NULL", err); + /* chan_list1 and chan_list2 should be sorted at first */ + while (i < nchan1 && j < nchan2) { + tmp = chan_list1[i] < chan_list2[j]? + chan_list1[i++] : chan_list2[j++]; + for (; i < nchan1 && chan_list1[i] == tmp; i++); + for (; j < nchan2 && chan_list2[j] == tmp; j++); + d_chan_list[k++] = tmp; + } + + while (i < nchan1) { + tmp = chan_list1[i++]; + for (; i < nchan1 && chan_list1[i] == tmp; i++); + d_chan_list[k++] = tmp; + } + + while (j < nchan2) { + tmp = chan_list2[j++]; + for (; j < nchan2 && chan_list2[j] == tmp; j++); + d_chan_list[k++] = tmp; + + } + *nchan = k; + return err; +} +static int +_dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list, + int *nchan, uint8 band, bool skip_dfs) +{ + int err = BCME_OK; + int i, j; + uint32 chan_buf[WL_NUMCHANNELS+1]; + wl_uint32_list_t *list; + NULL_CHECK(dhd, "dhd is NULL", err); + if (*nchan) { + NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); + } + memset(&chan_buf, 0, sizeof(chan_buf)); + list = (wl_uint32_list_t *) (void *)chan_buf; + list->count = htod32(WL_NUMCHANNELS); + err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); + if (err < 0) { + DHD_ERROR(("failed to get channel list (err: %d)\n", err)); + goto exit; + } + for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) { + if (band == WLC_BAND_2G) { + if (dtoh32(list->element[i]) > CHANNEL_2G_MAX) + continue; + } else if (band == WLC_BAND_5G) { + if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX) + continue; + if (skip_dfs && is_dfs(dtoh32(list->element[i]))) + continue; + + } else if (band == WLC_BAND_AUTO) { + if (skip_dfs || !is_dfs(dtoh32(list->element[i]))) + continue; + + } else { /* All channels */ + if (skip_dfs && is_dfs(dtoh32(list->element[i]))) + continue; + } + if (dtoh32(list->element[i]) <= CHANNEL_5G_MAX) { + d_chan_list[j++] = (uint16) dtoh32(list->element[i]); + } else { + err = BCME_BADCHAN; + goto exit; + } + } + *nchan = j; +exit: + return err; +} +static int +_dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batch, + char *buf, int nbufsize) +{ + int err = BCME_OK; + int bytes_written = 0, nreadsize = 0; + int t_delta = 0; + int nleftsize = nbufsize; + uint8 cnt = 0; + char *bp = buf; + char eabuf[ETHER_ADDR_STR_LEN]; +#ifdef PNO_DEBUG + char *_base_bp; + char msg[150]; +#endif + dhd_pno_bestnet_entry_t *iter, *next; + dhd_pno_scan_results_t *siter, *snext; + dhd_pno_best_header_t *phead, *pprev; + NULL_CHECK(params_batch, "params_batch is NULL", err); + if (nbufsize > 0) + NULL_CHECK(buf, "buf is NULL", err); + /* initialize the buffer */ + memset(buf, 0, nbufsize); + DHD_PNO(("%s enter \n", __FUNCTION__)); + /* # of scans */ + if (!params_batch->get_batch.batch_started) { + bp += nreadsize = sprintf(bp, "scancount=%d\n", + params_batch->get_batch.expired_tot_scan_cnt); + nleftsize -= nreadsize; + params_batch->get_batch.batch_started = TRUE; + } + DHD_PNO(("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt)); + /* preestimate scan count until which scan result this report is going to end */ + list_for_each_entry_safe(siter, snext, + ¶ms_batch->get_batch.expired_scan_results_list, list) { + phead = siter->bestnetheader; + while (phead != NULL) { + /* if left_size is less than bestheader total size , stop this */ + if (nleftsize <= + (phead->tot_size + phead->tot_cnt * ENTRY_OVERHEAD)) + goto exit; + /* increase scan count */ + cnt++; + /* # best of each scan */ + DHD_PNO(("\n\n", cnt - 1, phead->tot_cnt)); + /* attribute of the scan */ + if (phead->reason & PNO_STATUS_ABORT_MASK) { + bp += nreadsize = sprintf(bp, "trunc\n"); + nleftsize -= nreadsize; + } + list_for_each_entry_safe(iter, next, + &phead->entry_list, list) { + t_delta = jiffies_to_msecs(jiffies - iter->recorded_time); +#ifdef PNO_DEBUG + _base_bp = bp; + memset(msg, 0, sizeof(msg)); +#endif + /* BSSID info */ + bp += nreadsize = sprintf(bp, "bssid=%s\n", + bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf)); + nleftsize -= nreadsize; + /* SSID */ + bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID); + nleftsize -= nreadsize; + /* channel */ + bp += nreadsize = sprintf(bp, "freq=%d\n", + wf_channel2mhz(iter->channel, + iter->channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + nleftsize -= nreadsize; + /* RSSI */ + bp += nreadsize = sprintf(bp, "level=%d\n", iter->RSSI); + nleftsize -= nreadsize; + /* add the time consumed in Driver to the timestamp of firmware */ + iter->timestamp += t_delta; + bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp); + nleftsize -= nreadsize; + /* RTT0 */ + bp += nreadsize = sprintf(bp, "dist=%d\n", + (iter->rtt0 == 0)? -1 : iter->rtt0); + nleftsize -= nreadsize; + /* RTT1 */ + bp += nreadsize = sprintf(bp, "distSd=%d\n", + (iter->rtt0 == 0)? -1 : iter->rtt1); + nleftsize -= nreadsize; + bp += nreadsize = sprintf(bp, "%s", AP_END_MARKER); + nleftsize -= nreadsize; + list_del(&iter->list); + MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); +#ifdef PNO_DEBUG + memcpy(msg, _base_bp, bp - _base_bp); + DHD_PNO(("Entry : \n%s", msg)); +#endif + } + bp += nreadsize = sprintf(bp, "%s", SCAN_END_MARKER); + DHD_PNO(("%s", SCAN_END_MARKER)); + nleftsize -= nreadsize; + pprev = phead; + /* reset the header */ + siter->bestnetheader = phead = phead->next; + MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); + + siter->cnt_header--; + } + if (phead == NULL) { + /* we store all entry in this scan , so it is ok to delete */ + list_del(&siter->list); + MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); + } + } +exit: + if (cnt < params_batch->get_batch.expired_tot_scan_cnt) { + DHD_ERROR(("Buffer size is small to save all batch entry," + " cnt : %d (remained_scan_cnt): %d\n", + cnt, params_batch->get_batch.expired_tot_scan_cnt - cnt)); + } + params_batch->get_batch.expired_tot_scan_cnt -= cnt; + /* set FALSE only if the link list is empty after returning the data */ + if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) { + params_batch->get_batch.batch_started = FALSE; + bp += sprintf(bp, "%s", RESULTS_END_MARKER); + DHD_PNO(("%s", RESULTS_END_MARKER)); + DHD_PNO(("%s : Getting the batching data is complete\n", __FUNCTION__)); + } + /* return used memory in buffer */ + bytes_written = (int32)(bp - buf); + return bytes_written; +} +static int +_dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last) +{ + int err = BCME_OK; + int removed_scan_cnt = 0; + dhd_pno_scan_results_t *siter, *snext; + dhd_pno_best_header_t *phead, *pprev; + dhd_pno_bestnet_entry_t *iter, *next; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(head, "head is NULL", err); + NULL_CHECK(head->next, "head->next is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + list_for_each_entry_safe(siter, snext, + head, list) { + if (only_last) { + /* in case that we need to delete only last one */ + if (!list_is_last(&siter->list, head)) { + /* skip if the one is not last */ + continue; + } + } + /* delete all data belong if the one is last */ + phead = siter->bestnetheader; + while (phead != NULL) { + removed_scan_cnt++; + list_for_each_entry_safe(iter, next, + &phead->entry_list, list) { + list_del(&iter->list); + MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); + } + pprev = phead; + phead = phead->next; + MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); + } + if (phead == NULL) { + /* it is ok to delete top node */ + list_del(&siter->list); + MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); + } + } + return removed_scan_cnt; +} + +static int +_dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) +{ + int err = BCME_OK; + int i = 0; + wl_pfn_cfg_t pfncfg_param; + NULL_CHECK(dhd, "dhd is NULL", err); + if (nchan) { + NULL_CHECK(channel_list, "nchan is NULL", err); + } + if (nchan > WL_NUMCHANNELS) { + return BCME_RANGE; + } + DHD_PNO(("%s enter : nchan : %d\n", __FUNCTION__, nchan)); + memset(&pfncfg_param, 0, sizeof(wl_pfn_cfg_t)); + /* Setup default values */ + pfncfg_param.reporttype = htod32(WL_PFN_REPORT_ALLNET); + pfncfg_param.channel_num = htod32(0); + + for (i = 0; i < nchan; i++) + pfncfg_param.channel_list[i] = channel_list[i]; + + pfncfg_param.channel_num = htod32(nchan); + err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), NULL, 0, + TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); + goto exit; + } +exit: + return err; +} +static int +_dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL\n", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + mutex_lock(&_pno_state->pno_mutex); + switch (mode) { + case DHD_PNO_LEGACY_MODE: { + struct dhd_pno_ssid *iter, *next; + if (params->params_legacy.nssid > 0) { + list_for_each_entry_safe(iter, next, + ¶ms->params_legacy.ssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + params->params_legacy.nssid = 0; + params->params_legacy.scan_fr = 0; + params->params_legacy.pno_freq_expo_max = 0; + params->params_legacy.pno_repeat = 0; + params->params_legacy.nchan = 0; + memset(params->params_legacy.chan_list, 0, + sizeof(params->params_legacy.chan_list)); + break; + } + case DHD_PNO_BATCH_MODE: { + params->params_batch.scan_fr = 0; + params->params_batch.mscan = 0; + params->params_batch.nchan = 0; + params->params_batch.rtt = 0; + params->params_batch.bestn = 0; + params->params_batch.nchan = 0; + params->params_batch.band = WLC_BAND_AUTO; + memset(params->params_batch.chan_list, 0, + sizeof(params->params_batch.chan_list)); + params->params_batch.get_batch.batch_started = FALSE; + params->params_batch.get_batch.buf = NULL; + params->params_batch.get_batch.bufsize = 0; + params->params_batch.get_batch.reason = 0; + _dhd_pno_clear_all_batch_results(dhd, + ¶ms->params_batch.get_batch.scan_results_list, FALSE); + _dhd_pno_clear_all_batch_results(dhd, + ¶ms->params_batch.get_batch.expired_scan_results_list, FALSE); + params->params_batch.get_batch.tot_scan_cnt = 0; + params->params_batch.get_batch.expired_tot_scan_cnt = 0; + params->params_batch.get_batch.top_node_cnt = 0; + INIT_LIST_HEAD(¶ms->params_batch.get_batch.scan_results_list); + INIT_LIST_HEAD(¶ms->params_batch.get_batch.expired_scan_results_list); + break; + } + case DHD_PNO_HOTLIST_MODE: { + struct dhd_pno_bssid *iter, *next; + if (params->params_hotlist.nbssid > 0) { + list_for_each_entry_safe(iter, next, + ¶ms->params_hotlist.bssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + params->params_hotlist.scan_fr = 0; + params->params_hotlist.nbssid = 0; + params->params_hotlist.nchan = 0; + params->params_batch.band = WLC_BAND_AUTO; + memset(params->params_hotlist.chan_list, 0, + sizeof(params->params_hotlist.chan_list)); + break; + } + default: + DHD_ERROR(("%s : unknown mode : %d\n", __FUNCTION__, mode)); + break; + } + mutex_unlock(&_pno_state->pno_mutex); + return err; +} +static int +_dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + if (nbssid) { + NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); + } + err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)p_pfn_bssid, + sizeof(wl_pfn_bssid_t) * nbssid, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); + goto exit; + } +exit: + return err; +} + +#ifdef GSCAN_SUPPORT +static int +_dhd_pno_add_significant_bssid(dhd_pub_t *dhd, + wl_pfn_significant_bssid_t *p_pfn_significant_bssid, int nbssid) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + + if (!nbssid) { + err = BCME_ERROR; + goto exit; + } + + NULL_CHECK(p_pfn_significant_bssid, "bssid list is NULL", err); + + err = dhd_iovar(dhd, 0, "pfn_add_swc_bssid", (char *)p_pfn_significant_bssid, + sizeof(wl_pfn_significant_bssid_t) * nbssid, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_significant_bssid %d\n", __FUNCTION__, err)); + goto exit; + } +exit: + return err; +} +#endif /* GSCAN_SUPPORT */ + +int +dhd_pno_stop_for_ssid(dhd_pub_t *dhd) +{ + int err = BCME_OK; + uint32 mode = 0; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + wl_pfn_bssid_t *p_pfn_bssid = NULL; + NULL_CHECK(dhd, "dev is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { + DHD_ERROR(("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__)); + goto exit; + } + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + struct dhd_pno_gscan_params *gscan_params; + + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + gscan_params = &_params->params_gscan; + if (gscan_params->mscan) { + /* retrieve the batching data from firmware into host */ + err = dhd_wait_batch_results_complete(dhd); + if (err != BCME_OK) + goto exit; + } + /* save current pno_mode before calling dhd_pno_clean */ + mutex_lock(&_pno_state->pno_mutex); + mode = _pno_state->pno_mode; + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + mutex_unlock(&_pno_state->pno_mutex); + goto exit; + } + /* restore previous pno_mode */ + _pno_state->pno_mode = mode; + mutex_unlock(&_pno_state->pno_mutex); + /* Restart gscan */ + err = dhd_pno_initiate_gscan_request(dhd, 1, 0); + goto exit; + } +#endif /* GSCAN_SUPPORT */ + /* restart Batch mode if the batch mode is on */ + if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { + /* retrieve the batching data from firmware into host */ + dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); + /* save current pno_mode before calling dhd_pno_clean */ + mode = _pno_state->pno_mode; + dhd_pno_clean(dhd); + /* restore previous pno_mode */ + _pno_state->pno_mode = mode; + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + /* restart BATCH SCAN */ + err = dhd_pno_set_for_batch(dhd, &_params->params_batch); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + /* restart HOTLIST SCAN */ + struct dhd_pno_bssid *iter, *next; + _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * + _params->params_hotlist.nbssid, GFP_KERNEL); + if (p_pfn_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" + " (count: %d)", + __FUNCTION__, _params->params_hotlist.nbssid)); + err = BCME_ERROR; + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + goto exit; + } + /* convert dhd_pno_bssid to wl_pfn_bssid */ + list_for_each_entry_safe(iter, next, + &_params->params_hotlist.bssid_list, list) { + memcpy(&p_pfn_bssid->macaddr, + &iter->macaddr, ETHER_ADDR_LEN); + p_pfn_bssid->flags = iter->flags; + p_pfn_bssid++; + } + err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + } else { + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } +exit: + if (p_pfn_bssid) + kfree(p_pfn_bssid); + return err; +} + +int +dhd_pno_enable(dhd_pub_t *dhd, int enable) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + return (_dhd_pno_enable(dhd, enable)); +} + +static wlc_ssid_ext_t * +dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state) +{ + int err = BCME_OK; + int i; + struct dhd_pno_ssid *iter, *next; + dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + wlc_ssid_ext_t *p_ssid_list; + + p_ssid_list = kzalloc(sizeof(wlc_ssid_ext_t) * + _params1->params_legacy.nssid, GFP_KERNEL); + if (p_ssid_list == NULL) { + DHD_ERROR(("%s : failed to allocate wlc_ssid_ext_t array (count: %d)", + __FUNCTION__, _params1->params_legacy.nssid)); + err = BCME_ERROR; + pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + goto exit; + } + i = 0; + /* convert dhd_pno_ssid to wlc_ssid_ext_t */ + list_for_each_entry_safe(iter, next, &_params1->params_legacy.ssid_list, list) { + p_ssid_list[i].SSID_len = iter->SSID_len; + p_ssid_list[i].hidden = iter->hidden; + p_ssid_list[i].rssi_thresh = iter->rssi_thresh; + memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); + i++; + } +exit: + return p_ssid_list; +} + +#ifdef GSCAN_SUPPORT +static int dhd_epno_set_ssid(dhd_pub_t *dhd, + dhd_pno_status_info_t *pno_state) +{ + int err = BCME_OK; + dhd_epno_params_t *iter, *next; + dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + struct dhd_pno_gscan_params *gscan_params; + wlc_ssid_ext_t ssid_elem; + wl_pfn_ext_list_t *p_ssid_ext_elem = NULL; + uint32 mem_needed = 0, i = 0; + uint16 num_visible_epno_ssid; + uint8 flags; + + gscan_params = &_params1->params_gscan; + num_visible_epno_ssid = gscan_params->num_visible_epno_ssid; + + if (num_visible_epno_ssid) { + mem_needed = sizeof(wl_pfn_ext_list_t) + (sizeof(wl_pfn_ext_t) * + (num_visible_epno_ssid - 1)); + p_ssid_ext_elem = kzalloc(mem_needed, GFP_KERNEL); + if (p_ssid_ext_elem == NULL) { + DHD_ERROR(("%s : failed to allocate memory %u\n", + __FUNCTION__, mem_needed)); + err = BCME_NOMEM; + goto exit; + } + p_ssid_ext_elem->version = PFN_SSID_EXT_VERSION; + p_ssid_ext_elem->count = num_visible_epno_ssid; + } + + DHD_PNO(("Total ssids %d, visible SSIDs %d\n", gscan_params->num_epno_ssid, + num_visible_epno_ssid)); + + /* convert dhd_pno_ssid to wlc_ssid_ext_t */ + list_for_each_entry_safe(iter, next, &gscan_params->epno_ssid_list, list) { + if (iter->flags & DHD_PNO_USE_SSID) { + memset(&ssid_elem, 0, sizeof(ssid_elem)); + ssid_elem.SSID_len = iter->ssid_len; + ssid_elem.hidden = TRUE; + flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? + WL_PFN_SSID_A_BAND_TRIG: 0; + flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? + WL_PFN_SSID_BG_BAND_TRIG: 0; + ssid_elem.flags = flags; + ssid_elem.rssi_thresh = iter->rssi_thresh; + memcpy(ssid_elem.SSID, iter->ssid, iter->ssid_len); + if ((err = _dhd_pno_add_ssid(dhd, &ssid_elem, 1)) < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + } else if (i < num_visible_epno_ssid) { + p_ssid_ext_elem->pfn_ext[i].rssi_thresh = iter->rssi_thresh; + switch (iter->auth) { + case DHD_PNO_AUTH_CODE_OPEN: + p_ssid_ext_elem->pfn_ext[i].wpa_auth = WPA_AUTH_DISABLED; + break; + case DHD_PNO_AUTH_CODE_PSK: + p_ssid_ext_elem->pfn_ext[i].wpa_auth = + (WPA2_AUTH_PSK | WPA_AUTH_PSK); + break; + case DHD_PNO_AUTH_CODE_EAPOL: + p_ssid_ext_elem->pfn_ext[i].wpa_auth = + (uint16)WPA_AUTH_PFN_ANY; + break; + default: + p_ssid_ext_elem->pfn_ext[i].wpa_auth = + (uint16)WPA_AUTH_PFN_ANY; + break; + } + memcpy(p_ssid_ext_elem->pfn_ext[i].ssid, iter->ssid, iter->ssid_len); + p_ssid_ext_elem->pfn_ext[i].ssid_len = iter->ssid_len; + iter->index = gscan_params->ssid_ext_last_used_index++; + flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? + WL_PFN_SSID_A_BAND_TRIG: 0; + flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? + WL_PFN_SSID_BG_BAND_TRIG: 0; + p_ssid_ext_elem->pfn_ext[i].flags = flags; + DHD_PNO(("SSID %s idx %d rssi thresh %d flags %x\n", iter->ssid, + iter->index, iter->rssi_thresh, flags)); + i++; + } + } + if (num_visible_epno_ssid) { + err = dhd_iovar(dhd, 0, "pfn_add_ssid_ext", (char *)p_ssid_ext_elem, + mem_needed, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_add_pno_ext_ssid %d\n", __FUNCTION__, + err)); + } + } +exit: + kfree(p_ssid_ext_elem); + return err; +} +#endif /* GSCAN_SUPPORT */ + +static int +dhd_pno_add_to_ssid_list(dhd_pno_params_t *params, wlc_ssid_ext_t *ssid_list, + int nssid) +{ + int ret = 0; + int i; + struct dhd_pno_ssid *_pno_ssid; + + for (i = 0; i < nssid; i++) { + if (ssid_list[i].SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s : Invalid SSID length %d\n", + __FUNCTION__, ssid_list[i].SSID_len)); + ret = BCME_ERROR; + goto exit; + } + _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); + if (_pno_ssid == NULL) { + DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n", + __FUNCTION__)); + ret = BCME_ERROR; + goto exit; + } + _pno_ssid->SSID_len = ssid_list[i].SSID_len; + _pno_ssid->hidden = ssid_list[i].hidden; + _pno_ssid->rssi_thresh = ssid_list[i].rssi_thresh; + memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); + list_add_tail(&_pno_ssid->list, ¶ms->params_legacy.ssid_list); + params->params_legacy.nssid++; + } + +exit: + return ret; +} + +int +dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) +{ + dhd_pno_params_t *_params; + dhd_pno_params_t *_params2; + dhd_pno_status_info_t *_pno_state; + uint16 _chan_list[WL_NUMCHANNELS]; + int32 tot_nchan = 0; + int err = BCME_OK; + int i; + int mode = 0; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit_no_clear; + } + DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d," + "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, + scan_fr, pno_repeat, pno_freq_expo_max, nchan)); + + _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + /* If GSCAN is also ON will handle this down below */ +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE && + !(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { +#else + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { +#endif /* GSCAN_SUPPORT */ + DHD_ERROR(("%s : Legacy PNO mode was already started, " + "will disable previous one to start new one\n", __FUNCTION__)); + err = dhd_pno_stop_for_ssid(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to stop legacy PNO (err %d)\n", + __FUNCTION__, err)); + goto exit_no_clear; + } + } + _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", + __FUNCTION__, err)); + goto exit_no_clear; + } + memset(_chan_list, 0, sizeof(_chan_list)); + tot_nchan = MIN(nchan, WL_NUMCHANNELS); + if (tot_nchan > 0 && channel_list) { + for (i = 0; i < tot_nchan; i++) + _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i]; + } +#ifdef GSCAN_SUPPORT + else { + tot_nchan = WL_NUMCHANNELS; + err = _dhd_pno_get_channels(dhd, _chan_list, &tot_nchan, + (WLC_BAND_2G | WLC_BAND_5G), FALSE); + if (err < 0) { + tot_nchan = 0; + DHD_PNO(("Could not get channel list for PNO SSID\n")); + } else { + for (i = 0; i < tot_nchan; i++) { + _params->params_legacy.chan_list[i] = _chan_list[i]; + } + } + } +#endif /* GSCAN_SUPPORT */ + + if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { + DHD_PNO(("BATCH SCAN is on progress in firmware\n")); + /* retrieve the batching data from firmware into host */ + dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = _dhd_pno_enable(dhd, PNO_OFF); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + goto exit_no_clear; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + /* use superset of channel list between two mode */ + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + if (_params2->params_batch.nchan > 0 && tot_nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_batch.chan_list[0], + _params2->params_batch.nchan, + &channel_list[0], tot_nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + " between legacy and batch\n", + __FUNCTION__)); + goto exit_no_clear; + } + } else { + DHD_PNO(("superset channel will use" + " all channels in firmware\n")); + } + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + if (_params2->params_hotlist.nchan > 0 && tot_nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_hotlist.chan_list[0], + _params2->params_hotlist.nchan, + &channel_list[0], tot_nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + " between legacy and hotlist\n", + __FUNCTION__)); + goto exit_no_clear; + } + } + } + } + _params->params_legacy.scan_fr = scan_fr; + _params->params_legacy.pno_repeat = pno_repeat; + _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max; + _params->params_legacy.nchan = tot_nchan; + _params->params_legacy.nssid = 0; + INIT_LIST_HEAD(&_params->params_legacy.ssid_list); +#ifdef GSCAN_SUPPORT + /* dhd_pno_initiate_gscan_request will handle simultaneous Legacy PNO and GSCAN */ + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { + err = BCME_ERROR; + goto exit; + } + DHD_PNO(("GSCAN mode is ON! Will restart GSCAN+Legacy PNO\n")); + err = dhd_pno_initiate_gscan_request(dhd, 1, 0); + goto exit; + } +#endif /* GSCAN_SUPPORT */ + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_LEGACY_MODE)) < 0) { + DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); + goto exit; + } + if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { + DHD_ERROR(("failed to add ssid list(err %d), %d in firmware\n", err, nssid)); + goto exit; + } + if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { + err = BCME_ERROR; + goto exit; + } + if (tot_nchan > 0) { + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + } + if (_pno_state->pno_status == DHD_PNO_DISABLED) { + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) + DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); + } +exit: + if (err < 0) { + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + } +exit_no_clear: + /* clear mode in case of error */ + if (err < 0) { + int ret = dhd_pno_clean(dhd); + + if (ret < 0) { + DHD_ERROR(("%s : dhd_pno_clean failure (err: %d)\n", + __FUNCTION__, ret)); + } else { + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + } + } + return err; +} +int +dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) +{ + int err = BCME_OK; + uint16 _chan_list[WL_NUMCHANNELS]; + int rem_nchan = 0, tot_nchan = 0; + int mode = 0, mscan = 0; + dhd_pno_params_t *_params; + dhd_pno_params_t *_params2; + dhd_pno_status_info_t *_pno_state; + wlc_ssid_ext_t *p_ssid_list = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + NULL_CHECK(batch_params, "batch_params is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + _pno_state->pno_mode |= DHD_PNO_BATCH_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", + __FUNCTION__)); + goto exit; + } + } else { + /* batch mode is already started */ + return -EBUSY; + } + _params->params_batch.scan_fr = batch_params->scan_fr; + _params->params_batch.bestn = batch_params->bestn; + _params->params_batch.mscan = (batch_params->mscan)? + batch_params->mscan : DEFAULT_BATCH_MSCAN; + _params->params_batch.nchan = batch_params->nchan; + memcpy(_params->params_batch.chan_list, batch_params->chan_list, + sizeof(_params->params_batch.chan_list)); + + memset(_chan_list, 0, sizeof(_chan_list)); + + rem_nchan = ARRAYSIZE(batch_params->chan_list) - batch_params->nchan; + if (batch_params->band == WLC_BAND_2G || batch_params->band == WLC_BAND_5G) { + /* get a valid channel list based on band B or A */ + err = _dhd_pno_get_channels(dhd, + &_params->params_batch.chan_list[batch_params->nchan], + &rem_nchan, batch_params->band, FALSE); + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", + __FUNCTION__, batch_params->band)); + goto exit; + } + /* now we need to update nchan because rem_chan has valid channel count */ + _params->params_batch.nchan += rem_nchan; + /* need to sort channel list */ + sort(_params->params_batch.chan_list, _params->params_batch.nchan, + sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL); + } +#ifdef PNO_DEBUG +{ + DHD_PNO(("Channel list : ")); + for (i = 0; i < _params->params_batch.nchan; i++) { + DHD_PNO(("%d ", _params->params_batch.chan_list[i])); + } + DHD_PNO(("\n")); +} +#endif + if (_params->params_batch.nchan) { + /* copy the channel list into local array */ + memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list)); + tot_nchan = _params->params_batch.nchan; + } + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + DHD_PNO(("PNO SSID is on progress in firmware\n")); + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = _dhd_pno_enable(dhd, PNO_OFF); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + goto exit; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + /* Use the superset for channelist between two mode */ + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + if (_params2->params_legacy.nchan > 0 && _params->params_batch.nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_legacy.chan_list[0], + _params2->params_legacy.nchan, + &_params->params_batch.chan_list[0], _params->params_batch.nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + " between legacy and batch\n", + __FUNCTION__)); + goto exit; + } + } else { + DHD_PNO(("superset channel will use all channels in firmware\n")); + } + p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!p_ssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list, + _params2->params_legacy.nssid)) < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + } + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_BATCH_MODE)) < 0) { + DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } else { + /* we need to return mscan */ + mscan = err; + } + if (tot_nchan > 0) { + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + } + if (_pno_state->pno_status == DHD_PNO_DISABLED) { + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) + DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); + } +exit: + /* clear mode in case of error */ + if (err < 0) + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + else { + /* return #max scan firmware can do */ + err = mscan; + } + if (p_ssid_list) + kfree(p_ssid_list); + return err; +} + + +#ifdef GSCAN_SUPPORT +static void dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params, + dhd_pno_status_info_t *_pno_state, uint8 flags) +{ + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (flags & GSCAN_FLUSH_SCAN_CFG) { + _params->params_gscan.bestn = 0; + _params->params_gscan.mscan = 0; + _params->params_gscan.buffer_threshold = GSCAN_BATCH_NO_THR_SET; + _params->params_gscan.scan_fr = 0; + _params->params_gscan.send_all_results_flag = 0; + memset(_params->params_gscan.channel_bucket, 0, + _params->params_gscan.nchannel_buckets * + sizeof(struct dhd_pno_gscan_channel_bucket)); + _params->params_gscan.nchannel_buckets = 0; + DHD_PNO(("Flush Scan config\n")); + } + if (flags & GSCAN_FLUSH_HOTLIST_CFG) { + struct dhd_pno_bssid *iter, *next; + if (_params->params_gscan.nbssid_hotlist > 0) { + list_for_each_entry_safe(iter, next, + &_params->params_gscan.hotlist_bssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + _params->params_gscan.nbssid_hotlist = 0; + DHD_PNO(("Flush Hotlist Config\n")); + } + if (flags & GSCAN_FLUSH_SIGNIFICANT_CFG) { + dhd_pno_significant_bssid_t *iter, *next; + + if (_params->params_gscan.nbssid_significant_change > 0) { + list_for_each_entry_safe(iter, next, + &_params->params_gscan.significant_bssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + _params->params_gscan.nbssid_significant_change = 0; + DHD_PNO(("Flush Significant Change Config\n")); + } + if (flags & GSCAN_FLUSH_EPNO_CFG) { + dhd_epno_params_t *iter, *next; + + if (_params->params_gscan.num_epno_ssid > 0) { + list_for_each_entry_safe(iter, next, + &_params->params_gscan.epno_ssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + _params->params_gscan.num_epno_ssid = 0; + _params->params_gscan.num_visible_epno_ssid = 0; + _params->params_gscan.ssid_ext_last_used_index = 0; + DHD_PNO(("Flushed ePNO Config\n")); + } + + return; +} + +int +dhd_pno_lock_batch_results(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + int err = BCME_OK; + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + mutex_lock(&_pno_state->pno_mutex); + return err; +} + +void +dhd_pno_unlock_batch_results(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + _pno_state = PNO_GET_PNOSTATE(dhd); + mutex_unlock(&_pno_state->pno_mutex); + return; +} + +int +dhd_wait_batch_results_complete(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + int err = BCME_OK; + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + /* Has the workqueue finished its job already?? */ + if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_IN_PROGRESS) { + DHD_PNO(("%s: Waiting to complete retrieval..\n", __FUNCTION__)); + wait_event_interruptible_timeout(_pno_state->batch_get_wait, + is_batch_retrieval_complete(&_params->params_gscan), + msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); + } else { /* GSCAN_BATCH_RETRIEVAL_COMPLETE */ + gscan_results_cache_t *iter; + uint16 num_results = 0; + + mutex_lock(&_pno_state->pno_mutex); + iter = _params->params_gscan.gscan_batch_cache; + while (iter) { + num_results += iter->tot_count - iter->tot_consumed; + iter = iter->next; + } + mutex_unlock(&_pno_state->pno_mutex); + + /* All results consumed/No results cached?? + * Get fresh results from FW + */ + if ((_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) && !num_results) { + DHD_PNO(("%s: No results cached, getting from FW..\n", __FUNCTION__)); + err = dhd_retreive_batch_scan_results(dhd); + if (err == BCME_OK) { + wait_event_interruptible_timeout(_pno_state->batch_get_wait, + is_batch_retrieval_complete(&_params->params_gscan), + msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); + } + } + } + DHD_PNO(("%s: Wait complete\n", __FUNCTION__)); + return err; +} + +static void * +dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len) +{ + gscan_results_cache_t *iter, *results; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + uint16 num_scan_ids = 0, num_results = 0; + + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + iter = results = _params->params_gscan.gscan_batch_cache; + while (iter) { + num_results += iter->tot_count - iter->tot_consumed; + num_scan_ids++; + iter = iter->next; + } + + *len = ((num_results << 16) | (num_scan_ids)); + return results; +} + +void * +dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, + void *info, uint32 *len) +{ + void *ret = NULL; + dhd_pno_gscan_capabilities_t *ptr; + dhd_epno_params_t *epno_params; + dhd_pno_params_t *_params; + dhd_pno_status_info_t *_pno_state; + + if (!dhd || !dhd->pno_state) { + DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__)); + return NULL; + } + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + if (!len) { + DHD_ERROR(("%s: len is NULL\n", __FUNCTION__)); + return NULL; + } + + switch (type) { + case DHD_PNO_GET_CAPABILITIES: + ptr = (dhd_pno_gscan_capabilities_t *) + kmalloc(sizeof(dhd_pno_gscan_capabilities_t), GFP_KERNEL); + if (!ptr) + break; + /* Hardcoding these values for now, need to get + * these values from FW, will change in a later check-in + */ + ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE; + ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS; + ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; + ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX; + ptr->max_scan_reporting_threshold = 100; + ptr->max_hotlist_aps = PFN_HOTLIST_MAX_NUM_APS; + ptr->max_significant_wifi_change_aps = PFN_SWC_MAX_NUM_APS; + ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; + ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; + ptr->max_white_list_ssid = MAX_WHITELIST_SSID; + ret = (void *)ptr; + *len = sizeof(dhd_pno_gscan_capabilities_t); + break; + + case DHD_PNO_GET_BATCH_RESULTS: + ret = dhd_get_gscan_batch_results(dhd, len); + break; + case DHD_PNO_GET_CHANNEL_LIST: + if (info) { + uint16 ch_list[WL_NUMCHANNELS]; + uint32 *ptr, mem_needed, i; + int32 err, nchan = WL_NUMCHANNELS; + uint32 *gscan_band = (uint32 *) info; + uint8 band = 0; + + /* No band specified?, nothing to do */ + if ((*gscan_band & GSCAN_BAND_MASK) == 0) { + DHD_PNO(("No band specified\n")); + *len = 0; + break; + } + + /* HAL and DHD use different bits for 2.4G and + * 5G in bitmap. Hence translating it here... + */ + if (*gscan_band & GSCAN_BG_BAND_MASK) { + band |= WLC_BAND_2G; + } + if (*gscan_band & GSCAN_A_BAND_MASK) { + band |= WLC_BAND_5G; + } + err = _dhd_pno_get_channels(dhd, ch_list, &nchan, + (band & GSCAN_ABG_BAND_MASK), + !(*gscan_band & GSCAN_DFS_MASK)); + + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list\n", + __FUNCTION__)); + *len = 0; + } else { + mem_needed = sizeof(uint32) * nchan; + ptr = (uint32 *) kmalloc(mem_needed, GFP_KERNEL); + if (!ptr) { + DHD_ERROR(("%s: Unable to malloc %d bytes\n", + __FUNCTION__, mem_needed)); + break; + } + for (i = 0; i < nchan; i++) { + ptr[i] = wf_channel2mhz(ch_list[i], + (ch_list[i] <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + } + ret = ptr; + *len = mem_needed; + } + } else { + *len = 0; + DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__)); + } + break; + case DHD_PNO_GET_EPNO_SSID_ELEM: + if (_params->params_gscan.num_epno_ssid >= + (MAX_EPNO_SSID_NUM + MAX_EPNO_HIDDEN_SSID)) { + DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n", + _params->params_gscan.num_epno_ssid)); + return NULL; + } + + if (!_params->params_gscan.num_epno_ssid) + INIT_LIST_HEAD(&_params->params_gscan.epno_ssid_list); + + epno_params = kzalloc(sizeof(dhd_epno_params_t), GFP_KERNEL); + if (!epno_params) { + DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes", + sizeof(dhd_epno_params_t))); + return NULL; + } + _params->params_gscan.num_epno_ssid++; + epno_params->index = DHD_EPNO_DEFAULT_INDEX; + list_add_tail(&epno_params->list, &_params->params_gscan.epno_ssid_list); + ret = epno_params; + default: + DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); + break; + } + + return ret; + +} + +int +dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, + void *buf, uint8 flush) +{ + int err = BCME_OK; + dhd_pno_params_t *_params; + int i; + dhd_pno_status_info_t *_pno_state; + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + mutex_lock(&_pno_state->pno_mutex); + + switch (type) { + case DHD_PNO_BATCH_SCAN_CFG_ID: + { + gscan_batch_params_t *ptr = (gscan_batch_params_t *)buf; + _params->params_gscan.bestn = ptr->bestn; + _params->params_gscan.mscan = ptr->mscan; + _params->params_gscan.buffer_threshold = ptr->buffer_threshold; + } + break; + case DHD_PNO_GEOFENCE_SCAN_CFG_ID: + { + gscan_hotlist_scan_params_t *ptr = (gscan_hotlist_scan_params_t *)buf; + struct dhd_pno_bssid *_pno_bssid; + struct bssid_t *bssid_ptr; + int8 flags; + + if (flush) { + dhd_pno_reset_cfg_gscan(_params, _pno_state, + GSCAN_FLUSH_HOTLIST_CFG); + } + + if (!ptr->nbssid) + break; + + if (!_params->params_gscan.nbssid_hotlist) + INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list); + + if ((_params->params_gscan.nbssid_hotlist + + ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { + DHD_ERROR(("Excessive number of hotlist APs programmed %d\n", + (_params->params_gscan.nbssid_hotlist + + ptr->nbssid))); + err = BCME_RANGE; + goto exit; + } + + for (i = 0, bssid_ptr = ptr->bssid; i < ptr->nbssid; i++, bssid_ptr++) { + _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); + + if (!_pno_bssid) { + DHD_ERROR(("_pno_bssid is NULL, cannot kalloc %zd bytes", + sizeof(struct dhd_pno_bssid))); + err = BCME_NOMEM; + goto exit; + } + memcpy(&_pno_bssid->macaddr, &bssid_ptr->macaddr, ETHER_ADDR_LEN); + + flags = (int8) bssid_ptr->rssi_reporting_threshold; + _pno_bssid->flags = flags << WL_PFN_RSSI_SHIFT; + list_add_tail(&_pno_bssid->list, + &_params->params_gscan.hotlist_bssid_list); + } + + _params->params_gscan.nbssid_hotlist += ptr->nbssid; + _params->params_gscan.lost_ap_window = ptr->lost_ap_window; + } + break; + case DHD_PNO_SIGNIFICANT_SCAN_CFG_ID: + { + gscan_swc_params_t *ptr = (gscan_swc_params_t *)buf; + dhd_pno_significant_bssid_t *_pno_significant_change_bssid; + wl_pfn_significant_bssid_t *significant_bssid_ptr; + + if (flush) { + dhd_pno_reset_cfg_gscan(_params, _pno_state, + GSCAN_FLUSH_SIGNIFICANT_CFG); + } + + if (!ptr->nbssid) + break; + + if (!_params->params_gscan.nbssid_significant_change) + INIT_LIST_HEAD(&_params->params_gscan.significant_bssid_list); + + if ((_params->params_gscan.nbssid_significant_change + + ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { + DHD_ERROR(("Excessive number of SWC APs programmed %d\n", + (_params->params_gscan.nbssid_significant_change + + ptr->nbssid))); + err = BCME_RANGE; + goto exit; + } + + for (i = 0, significant_bssid_ptr = ptr->bssid_elem_list; + i < ptr->nbssid; i++, significant_bssid_ptr++) { + _pno_significant_change_bssid = + kzalloc(sizeof(dhd_pno_significant_bssid_t), + GFP_KERNEL); + + if (!_pno_significant_change_bssid) { + DHD_ERROR(("SWC bssidptr is NULL, cannot kalloc %zd bytes", + sizeof(dhd_pno_significant_bssid_t))); + err = BCME_NOMEM; + goto exit; + } + memcpy(&_pno_significant_change_bssid->BSSID, + &significant_bssid_ptr->macaddr, ETHER_ADDR_LEN); + _pno_significant_change_bssid->rssi_low_threshold = + significant_bssid_ptr->rssi_low_threshold; + _pno_significant_change_bssid->rssi_high_threshold = + significant_bssid_ptr->rssi_high_threshold; + list_add_tail(&_pno_significant_change_bssid->list, + &_params->params_gscan.significant_bssid_list); + } + + _params->params_gscan.swc_nbssid_threshold = ptr->swc_threshold; + _params->params_gscan.swc_rssi_window_size = ptr->rssi_window; + _params->params_gscan.lost_ap_window = ptr->lost_ap_window; + _params->params_gscan.nbssid_significant_change += ptr->nbssid; + + } + break; + case DHD_PNO_SCAN_CFG_ID: + { + int i, k; + uint16 band; + gscan_scan_params_t *ptr = (gscan_scan_params_t *)buf; + struct dhd_pno_gscan_channel_bucket *ch_bucket; + + if (ptr->nchannel_buckets <= GSCAN_MAX_CH_BUCKETS) { + _params->params_gscan.nchannel_buckets = ptr->nchannel_buckets; + + memcpy(_params->params_gscan.channel_bucket, ptr->channel_bucket, + _params->params_gscan.nchannel_buckets * + sizeof(struct dhd_pno_gscan_channel_bucket)); + ch_bucket = _params->params_gscan.channel_bucket; + + for (i = 0; i < ptr->nchannel_buckets; i++) { + band = ch_bucket[i].band; + for (k = 0; k < ptr->channel_bucket[i].num_channels; k++) { + ch_bucket[i].chan_list[k] = + wf_mhz2channel(ptr->channel_bucket[i].chan_list[k], + 0); + } + ch_bucket[i].band = 0; + /* HAL and DHD use different bits for 2.4G and + * 5G in bitmap. Hence translating it here... + */ + if (band & GSCAN_BG_BAND_MASK) + ch_bucket[i].band |= WLC_BAND_2G; + if (band & GSCAN_A_BAND_MASK) + ch_bucket[i].band |= WLC_BAND_5G; + if (band & GSCAN_DFS_MASK) + ch_bucket[i].band |= GSCAN_DFS_MASK; + + DHD_PNO(("band %d report_flag %d\n", ch_bucket[i].band, + ch_bucket[i].report_flag)); + } + + for (i = 0; i < ptr->nchannel_buckets; i++) { + ch_bucket[i].bucket_freq_multiple = + ch_bucket[i].bucket_freq_multiple/ptr->scan_fr; + ch_bucket[i].bucket_max_multiple = + ch_bucket[i].bucket_max_multiple/ptr->scan_fr; + DHD_PNO(("mult %d max_mult %d\n", + ch_bucket[i].bucket_freq_multiple, + ch_bucket[i].bucket_max_multiple)); + } + _params->params_gscan.scan_fr = ptr->scan_fr; + + DHD_PNO(("num_buckets %d scan_fr %d\n", + ptr->nchannel_buckets, + _params->params_gscan.scan_fr)); + } else { + err = BCME_BADARG; + } + } + break; + case DHD_PNO_EPNO_CFG_ID: + if (flush) { + dhd_pno_reset_cfg_gscan(_params, _pno_state, + GSCAN_FLUSH_EPNO_CFG); + } else { + _params->params_gscan.num_visible_epno_ssid += *((uint16 *)buf); + } + break; + default: + err = BCME_BADARG; + DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); + break; + } +exit: + mutex_unlock(&_pno_state->pno_mutex); + return err; + +} + + +static bool +validate_gscan_params(struct dhd_pno_gscan_params *gscan_params) +{ + unsigned int i, k; + + if (!gscan_params->scan_fr || !gscan_params->nchannel_buckets) { + DHD_ERROR(("%s : Scan freq - %d or number of channel buckets - %d is empty\n", + __FUNCTION__, gscan_params->scan_fr, gscan_params->nchannel_buckets)); + return false; + } + + for (i = 0; i < gscan_params->nchannel_buckets; i++) { + if (!gscan_params->channel_bucket[i].band) { + for (k = 0; k < gscan_params->channel_bucket[i].num_channels; k++) { + if (gscan_params->channel_bucket[i].chan_list[k] > CHANNEL_5G_MAX) { + DHD_ERROR(("%s : Unknown channel %d\n", __FUNCTION__, + gscan_params->channel_bucket[i].chan_list[k])); + return false; + } + } + } + } + + return true; +} + +static int +dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) +{ + int err = BCME_OK; + int mode, i = 0, k; + uint16 _chan_list[WL_NUMCHANNELS]; + int tot_nchan = 0; + int num_buckets_to_fw, tot_num_buckets, gscan_param_size; + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL; + wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL; + wl_pfn_significant_bssid_t *p_pfn_significant_bssid = NULL; + wl_pfn_bssid_t *p_pfn_bssid = NULL; + wlc_ssid_ext_t *pssid_list = NULL; + dhd_pno_params_t *params_legacy; + dhd_pno_params_t *_params; + + params_legacy = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + NULL_CHECK(gscan_params, "gscan_params is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + + if (!validate_gscan_params(gscan_params)) { + DHD_ERROR(("%s : Cannot start gscan - bad params\n", __FUNCTION__)); + err = BCME_BADARG; + goto exit; + } + /* Create channel list based on channel buckets */ + if (!(ch_bucket = dhd_pno_gscan_create_channel_list(dhd, _pno_state, + _chan_list, &tot_num_buckets, &num_buckets_to_fw))) { + goto exit; + } + + mutex_lock(&_pno_state->pno_mutex); + /* Clear any pre-existing results in our cache + * not consumed by framework + */ + dhd_gscan_clear_all_batch_results(dhd); + if (_pno_state->pno_mode & (DHD_PNO_GSCAN_MODE | DHD_PNO_LEGACY_MODE)) { + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + mutex_unlock(&_pno_state->pno_mutex); + goto exit; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + } + _pno_state->pno_mode |= DHD_PNO_GSCAN_MODE; + mutex_unlock(&_pno_state->pno_mutex); + + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + + if (!pssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + + if ((err = _dhd_pno_add_ssid(dhd, pssid_list, + params_legacy->params_legacy.nssid)) < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + } + + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_GSCAN_MODE)) < 0) { + DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); + goto exit; + } + + gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + + (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); + pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOC(dhd->osh, gscan_param_size); + + if (!pfn_gscan_cfg_t) { + DHD_ERROR(("%s: failed to malloc memory of size %d\n", + __FUNCTION__, gscan_param_size)); + err = BCME_NOMEM; + goto exit; + } + + pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION; + if (gscan_params->mscan) { + pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold; + } else { + pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; + } + if (gscan_params->nbssid_significant_change) { + pfn_gscan_cfg_t->swc_nbssid_threshold = gscan_params->swc_nbssid_threshold; + pfn_gscan_cfg_t->swc_rssi_window_size = gscan_params->swc_rssi_window_size; + pfn_gscan_cfg_t->lost_ap_window = gscan_params->lost_ap_window; + } else { + pfn_gscan_cfg_t->swc_nbssid_threshold = 0; + pfn_gscan_cfg_t->swc_rssi_window_size = 0; + pfn_gscan_cfg_t->lost_ap_window = 0; + } + pfn_gscan_cfg_t->flags = + (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); + pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw; + pfn_gscan_cfg_t->retry_threshold = GSCAN_RETRY_THRESHOLD; + + for (i = 0, k = 0; i < tot_num_buckets; i++) { + if (ch_bucket[i].bucket_end_index != CHANNEL_BUCKET_EMPTY_INDEX) { + pfn_gscan_cfg_t->channel_bucket[k].bucket_end_index = + ch_bucket[i].bucket_end_index; + pfn_gscan_cfg_t->channel_bucket[k].bucket_freq_multiple = + ch_bucket[i].bucket_freq_multiple; + pfn_gscan_cfg_t->channel_bucket[k].max_freq_multiple = + ch_bucket[i].max_freq_multiple; + pfn_gscan_cfg_t->channel_bucket[k].repeat = + ch_bucket[i].repeat; + pfn_gscan_cfg_t->channel_bucket[k].flag = + ch_bucket[i].flag; + k++; + } + } + + tot_nchan = pfn_gscan_cfg_t->channel_bucket[num_buckets_to_fw - 1].bucket_end_index + 1; + DHD_PNO(("Total channel num %d total ch_buckets %d ch_buckets_to_fw %d \n", tot_nchan, + tot_num_buckets, num_buckets_to_fw)); + + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + + if ((err = _dhd_pno_gscan_cfg(dhd, pfn_gscan_cfg_t, gscan_param_size)) < 0) { + DHD_ERROR(("%s : failed to set call pno_gscan_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + if (gscan_params->nbssid_significant_change) { + dhd_pno_significant_bssid_t *iter, *next; + + p_pfn_significant_bssid = kzalloc(sizeof(wl_pfn_significant_bssid_t) * + gscan_params->nbssid_significant_change, GFP_KERNEL); + if (p_pfn_significant_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate memory %zd\n", + __FUNCTION__, + sizeof(wl_pfn_significant_bssid_t) * + gscan_params->nbssid_significant_change)); + err = BCME_NOMEM; + goto exit; + } + i = 0; + /* convert dhd_pno_significant_bssid_t to wl_pfn_significant_bssid_t */ + list_for_each_entry_safe(iter, next, &gscan_params->significant_bssid_list, list) { + p_pfn_significant_bssid[i].rssi_low_threshold = iter->rssi_low_threshold; + p_pfn_significant_bssid[i].rssi_high_threshold = iter->rssi_high_threshold; + memcpy(&p_pfn_significant_bssid[i].macaddr, &iter->BSSID, ETHER_ADDR_LEN); + i++; + } + DHD_PNO(("nbssid_significant_change %d \n", + gscan_params->nbssid_significant_change)); + err = _dhd_pno_add_significant_bssid(dhd, p_pfn_significant_bssid, + gscan_params->nbssid_significant_change); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_add_significant_bssid(err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + } + + if (gscan_params->nbssid_hotlist) { + struct dhd_pno_bssid *iter, *next; + wl_pfn_bssid_t *ptr; + p_pfn_bssid = (wl_pfn_bssid_t *)kzalloc(sizeof(wl_pfn_bssid_t) * + gscan_params->nbssid_hotlist, GFP_KERNEL); + if (p_pfn_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" + " (count: %d)", + __FUNCTION__, _params->params_hotlist.nbssid)); + err = BCME_NOMEM; + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + goto exit; + } + ptr = p_pfn_bssid; + /* convert dhd_pno_bssid to wl_pfn_bssid */ + DHD_PNO(("nhotlist %d\n", gscan_params->nbssid_hotlist)); + list_for_each_entry_safe(iter, next, + &gscan_params->hotlist_bssid_list, list) { + memcpy(&ptr->macaddr, + &iter->macaddr, ETHER_ADDR_LEN); + ptr->flags = iter->flags; + ptr++; + } + + err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, gscan_params->nbssid_hotlist); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + } + + if (gscan_params->num_epno_ssid > 0) { + DHD_PNO(("num_epno_ssid %d\n", gscan_params->num_epno_ssid)); + err = dhd_epno_set_ssid(dhd, _pno_state); + if (err < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + } + + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) { + DHD_ERROR(("%s : failed to enable PNO err %d\n", __FUNCTION__, err)); + } + +exit: + /* clear mode in case of error */ + if (err < 0) { + int ret = dhd_pno_clean(dhd); + if (ret < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, ret)); + + } else { + _pno_state->pno_mode &= ~DHD_PNO_GSCAN_MODE; + + } + } + kfree(pssid_list); + kfree(p_pfn_significant_bssid); + kfree(p_pfn_bssid); + if (pfn_gscan_cfg_t) { + MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size); + } + if (ch_bucket) { + MFREE(dhd->osh, ch_bucket, + (tot_num_buckets * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); + } + return err; + +} + +static wl_pfn_gscan_ch_bucket_cfg_t * +dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, + dhd_pno_status_info_t *_pno_state, + uint16 *chan_list, + uint32 *num_buckets, + uint32 *num_buckets_to_fw) +{ + int i, num_channels, err, nchan = WL_NUMCHANNELS, ch_cnt; + uint16 *ptr = chan_list, max; + wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket; + dhd_pno_params_t *_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + bool is_pno_legacy_running = _pno_state->pno_mode & DHD_PNO_LEGACY_MODE; + dhd_pno_gscan_channel_bucket_t *gscan_buckets = _params->params_gscan.channel_bucket; + + if (is_pno_legacy_running) + *num_buckets = _params->params_gscan.nchannel_buckets + 1; + else + *num_buckets = _params->params_gscan.nchannel_buckets; + + *num_buckets_to_fw = 0; + + ch_bucket = (wl_pfn_gscan_ch_bucket_cfg_t *) MALLOC(dhd->osh, + ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); + + if (!ch_bucket) { + DHD_ERROR(("%s: failed to malloc memory of size %zd\n", + __FUNCTION__, (*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); + *num_buckets_to_fw = *num_buckets = 0; + return NULL; + } + + max = gscan_buckets[0].bucket_freq_multiple; + num_channels = 0; + /* nchan is the remaining space left in chan_list buffer + * So any overflow list of channels is ignored + */ + for (i = 0; i < _params->params_gscan.nchannel_buckets && nchan; i++) { + if (!gscan_buckets[i].band) { + ch_cnt = MIN(gscan_buckets[i].num_channels, (uint8)nchan); + num_channels += ch_cnt; + memcpy(ptr, gscan_buckets[i].chan_list, + ch_cnt * sizeof(uint16)); + ptr = ptr + ch_cnt; + } else { + /* get a valid channel list based on band B or A */ + err = _dhd_pno_get_channels(dhd, ptr, + &nchan, (gscan_buckets[i].band & GSCAN_ABG_BAND_MASK), + !(gscan_buckets[i].band & GSCAN_DFS_MASK)); + + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", + __FUNCTION__, gscan_buckets[i].band)); + MFREE(dhd->osh, ch_bucket, + ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); + *num_buckets_to_fw = *num_buckets = 0; + return NULL; + } + + num_channels += nchan; + ptr = ptr + nchan; + } + + ch_bucket[i].bucket_end_index = num_channels - 1; + ch_bucket[i].bucket_freq_multiple = gscan_buckets[i].bucket_freq_multiple; + ch_bucket[i].repeat = gscan_buckets[i].repeat; + ch_bucket[i].max_freq_multiple = gscan_buckets[i].bucket_max_multiple; + ch_bucket[i].flag = gscan_buckets[i].report_flag; + /* HAL and FW interpretations are opposite for this bit */ + ch_bucket[i].flag ^= DHD_PNO_REPORT_NO_BATCH; + if (max < gscan_buckets[i].bucket_freq_multiple) + max = gscan_buckets[i].bucket_freq_multiple; + nchan = WL_NUMCHANNELS - num_channels; + *num_buckets_to_fw = *num_buckets_to_fw + 1; + DHD_PNO(("end_idx %d freq_mult - %d\n", + ch_bucket[i].bucket_end_index, ch_bucket[i].bucket_freq_multiple)); + } + + _params->params_gscan.max_ch_bucket_freq = max; + /* Legacy PNO maybe running, which means we need to create a legacy PNO bucket + * Get GCF of Legacy PNO and Gscan scanfreq + */ + if (is_pno_legacy_running) { + dhd_pno_params_t *_params1 = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + uint16 *legacy_chan_list = _params1->params_legacy.chan_list; + uint16 common_freq; + uint32 legacy_bucket_idx = _params->params_gscan.nchannel_buckets; + /* If no space is left then only the gscan buckets will be sent to FW */ + if (nchan) { + common_freq = gcd(_params->params_gscan.scan_fr, + _params1->params_legacy.scan_fr); + max = gscan_buckets[0].bucket_freq_multiple; + /* GSCAN buckets */ + for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) { + ch_bucket[i].bucket_freq_multiple *= _params->params_gscan.scan_fr; + ch_bucket[i].bucket_freq_multiple /= common_freq; + if (max < gscan_buckets[i].bucket_freq_multiple) + max = gscan_buckets[i].bucket_freq_multiple; + } + /* Legacy PNO bucket */ + ch_bucket[legacy_bucket_idx].bucket_freq_multiple = + _params1->params_legacy.scan_fr; + ch_bucket[legacy_bucket_idx].bucket_freq_multiple /= + common_freq; + _params->params_gscan.max_ch_bucket_freq = MAX(max, + ch_bucket[legacy_bucket_idx].bucket_freq_multiple); + ch_bucket[legacy_bucket_idx].flag = CH_BUCKET_REPORT_REGULAR; + /* Now add channels to the legacy scan bucket */ + for (i = 0; i < _params1->params_legacy.nchan && nchan; i++, nchan--) { + ptr[i] = legacy_chan_list[i]; + num_channels++; + } + ch_bucket[legacy_bucket_idx].bucket_end_index = num_channels - 1; + *num_buckets_to_fw = *num_buckets_to_fw + 1; + DHD_PNO(("end_idx %d freq_mult - %d\n", + ch_bucket[legacy_bucket_idx].bucket_end_index, + ch_bucket[legacy_bucket_idx].bucket_freq_multiple)); + } + } + return ch_bucket; +} + +static int +dhd_pno_stop_for_gscan(dhd_pub_t *dhd) +{ + int err = BCME_OK; + int mode; + dhd_pno_status_info_t *_pno_state; + wlc_ssid_ext_t *pssid_list = NULL; + + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", + __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + + if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { + DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); + goto exit; + } + if (_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.mscan) { + /* retrieve the batching data from firmware into host */ + err = dhd_wait_batch_results_complete(dhd); + if (err != BCME_OK) + goto exit; + } + mutex_lock(&_pno_state->pno_mutex); + mode = _pno_state->pno_mode & ~DHD_PNO_GSCAN_MODE; + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + mutex_unlock(&_pno_state->pno_mutex); + return err; + } + _pno_state->pno_mode = mode; + mutex_unlock(&_pno_state->pno_mutex); + _pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.ssid_ext_last_used_index = 0; + + /* Reprogram Legacy PNO if it was running */ + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + struct dhd_pno_legacy_params *params_legacy; + uint16 chan_list[WL_NUMCHANNELS]; + + params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!pssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + + DHD_PNO(("Restarting Legacy PNO SSID scan...\n")); + memcpy(chan_list, params_legacy->chan_list, + (params_legacy->nchan * sizeof(uint16))); + err = dhd_pno_set_for_ssid(dhd, pssid_list, params_legacy->nssid, + params_legacy->scan_fr, params_legacy->pno_repeat, + params_legacy->pno_freq_expo_max, chan_list, + params_legacy->nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + + } + +exit: + kfree(pssid_list); + return err; +} + +int +dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush) +{ + int err = BCME_OK; + dhd_pno_params_t *params; + dhd_pno_status_info_t *_pno_state; + struct dhd_pno_gscan_params *gscan_params; + + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + DHD_ERROR(("%s enter - run %d flush %d\n", __FUNCTION__, run, flush)); + + params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + gscan_params = ¶ms->params_gscan; + + if (run) { + err = dhd_pno_set_for_gscan(dhd, gscan_params); + } else { + if (flush) { + mutex_lock(&_pno_state->pno_mutex); + dhd_pno_reset_cfg_gscan(params, _pno_state, GSCAN_FLUSH_ALL_CFG); + mutex_unlock(&_pno_state->pno_mutex); + } + /* Need to stop all gscan */ + err = dhd_pno_stop_for_gscan(dhd); + } + + return err; +} + +int +dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag) +{ + int err = BCME_OK; + dhd_pno_params_t *params; + dhd_pno_status_info_t *_pno_state; + struct dhd_pno_gscan_params *gscan_params; + uint8 old_flag; + + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + + params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + gscan_params = ¶ms->params_gscan; + + mutex_lock(&_pno_state->pno_mutex); + + old_flag = gscan_params->send_all_results_flag; + gscan_params->send_all_results_flag = (uint8) real_time_flag; + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + if (old_flag != gscan_params->send_all_results_flag) { + wl_pfn_gscan_cfg_t gscan_cfg; + gscan_cfg.version = WL_GSCAN_CFG_VERSION; + gscan_cfg.flags = (gscan_params->send_all_results_flag & + GSCAN_SEND_ALL_RESULTS_MASK); + gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK; + + if ((err = _dhd_pno_gscan_cfg(dhd, &gscan_cfg, + sizeof(wl_pfn_gscan_cfg_t))) < 0) { + DHD_ERROR(("%s : pno_gscan_cfg failed (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit_mutex_unlock; + } + } else { + DHD_PNO(("No change in flag - %d\n", old_flag)); + } + } else { + DHD_PNO(("Gscan not started\n")); + } +exit_mutex_unlock: + mutex_unlock(&_pno_state->pno_mutex); +exit: + return err; +} + +/* Cleanup any consumed results + * Return TRUE if all results consumed, else FALSE + */ +int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd) +{ + int ret = 0; + dhd_pno_params_t *params; + struct dhd_pno_gscan_params *gscan_params; + dhd_pno_status_info_t *_pno_state; + gscan_results_cache_t *iter, *tmp; + + _pno_state = PNO_GET_PNOSTATE(dhd); + params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + gscan_params = ¶ms->params_gscan; + iter = gscan_params->gscan_batch_cache; + + while (iter) { + if (iter->tot_consumed == iter->tot_count) { + tmp = iter->next; + kfree(iter); + iter = tmp; + } else + break; + } + gscan_params->gscan_batch_cache = iter; + ret = (iter == NULL); + return ret; +} + +static int +_dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) +{ + int err = BCME_OK; + uint32 timestamp = 0, ts = 0, i, j, timediff; + dhd_pno_params_t *params; + dhd_pno_status_info_t *_pno_state; + wl_pfn_lnet_info_t *plnetinfo; + struct dhd_pno_gscan_params *gscan_params; + wl_pfn_lscanresults_t *plbestnet = NULL; + gscan_results_cache_t *iter, *tail; + wifi_gscan_result_t *result; + uint8 *nAPs_per_scan = NULL; + uint8 num_scans_in_cur_iter; + uint16 count; + + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + + _pno_state = PNO_GET_PNOSTATE(dhd); + params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { + DHD_ERROR(("%s: GSCAN is not enabled\n", __FUNCTION__)); + goto exit; + } + gscan_params = ¶ms->params_gscan; + nAPs_per_scan = (uint8 *) MALLOC(dhd->osh, gscan_params->mscan); + + if (!nAPs_per_scan) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, + gscan_params->mscan)); + err = BCME_NOMEM; + goto exit; + } + + plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + + mutex_lock(&_pno_state->pno_mutex); + + dhd_gscan_clear_all_batch_results(dhd); + + if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { + DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); + goto exit_mutex_unlock; + } + + timediff = gscan_params->scan_fr * 1000; + timediff = timediff >> 1; + + /* Ok, now lets start getting results from the FW */ + plbestnet->status = PFN_INCOMPLETE; + tail = gscan_params->gscan_batch_cache; + while (plbestnet->status != PFN_COMPLETE) { + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, + (char *)plbestnet, PNO_BESTNET_LEN, FALSE); + if (err < 0) { + DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n", + __FUNCTION__, err)); + goto exit_mutex_unlock; + } + DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, + plbestnet->status, plbestnet->count)); + if (plbestnet->version != PFN_SCANRESULT_VERSION) { + err = BCME_VERSION; + DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", + plbestnet->version, PFN_SCANRESULT_VERSION)); + goto exit_mutex_unlock; + } + if (plbestnet->count == 0) { + DHD_PNO(("No more batch results\n")); + goto exit_mutex_unlock; + } + num_scans_in_cur_iter = 0; + timestamp = plbestnet->netinfo[0].timestamp; + /* find out how many scans' results did we get in this batch of FW results */ + for (i = 0, count = 0; i < plbestnet->count; i++, count++) { + plnetinfo = &plbestnet->netinfo[i]; + /* Unlikely to happen, but just in case the results from + * FW doesnt make sense..... Assume its part of one single scan + */ + if (num_scans_in_cur_iter > gscan_params->mscan) { + num_scans_in_cur_iter = 0; + count = plbestnet->count; + break; + } + if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) { + nAPs_per_scan[num_scans_in_cur_iter] = count; + count = 0; + num_scans_in_cur_iter++; + } + timestamp = plnetinfo->timestamp; + } + nAPs_per_scan[num_scans_in_cur_iter] = count; + num_scans_in_cur_iter++; + + DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter)); + plnetinfo = &plbestnet->netinfo[0]; + + for (i = 0; i < num_scans_in_cur_iter; i++) { + iter = (gscan_results_cache_t *) + kmalloc(((nAPs_per_scan[i] - 1) * sizeof(wifi_gscan_result_t)) + + sizeof(gscan_results_cache_t), GFP_KERNEL); + if (!iter) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", + __FUNCTION__, gscan_params->mscan)); + err = BCME_NOMEM; + goto exit_mutex_unlock; + } + /* Need this check because the new set of results from FW + * maybe a continuation of previous sets' scan results + */ + if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) { + iter->scan_id = ++gscan_params->scan_id; + } else { + iter->scan_id = gscan_params->scan_id; + } + DHD_PNO(("scan_id %d tot_count %d\n", gscan_params->scan_id, + nAPs_per_scan[i])); + iter->tot_count = nAPs_per_scan[i]; + iter->tot_consumed = 0; + iter->flag = 0; + if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { + DHD_PNO(("This scan is aborted\n")); + iter->flag = (ENABLE << PNO_STATUS_ABORT); + } else if (gscan_params->reason) { + iter->flag = (ENABLE << gscan_params->reason); + } + + if (!tail) { + gscan_params->gscan_batch_cache = iter; + } else { + tail->next = iter; + } + tail = iter; + iter->next = NULL; + for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) { + result = &iter->results[j]; + + result->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, + (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + result->rssi = (int32) plnetinfo->RSSI; + /* Info not available & not expected */ + result->beacon_period = 0; + result->capability = 0; + result->ie_length = 0; + result->rtt = (uint64) plnetinfo->rtt0; + result->rtt_sd = (uint64) plnetinfo->rtt1; + result->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); + ts = plnetinfo->timestamp; + if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length %d\n", + __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); + plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + memcpy(result->ssid, plnetinfo->pfnsubnet.SSID, + plnetinfo->pfnsubnet.SSID_len); + result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; + memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID, + ETHER_ADDR_LEN); + + DHD_PNO(("\tSSID : ")); + DHD_PNO(("\n")); + DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", + result->macaddr.octet[0], + result->macaddr.octet[1], + result->macaddr.octet[2], + result->macaddr.octet[3], + result->macaddr.octet[4], + result->macaddr.octet[5])); + DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", + plnetinfo->pfnsubnet.channel, + plnetinfo->RSSI, plnetinfo->timestamp)); + DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", + plnetinfo->rtt0, plnetinfo->rtt1)); + + } + } + } +exit_mutex_unlock: + mutex_unlock(&_pno_state->pno_mutex); +exit: + params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_COMPLETE; + smp_wmb(); + wake_up_interruptible(&_pno_state->batch_get_wait); + if (nAPs_per_scan) { + MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan); + } + if (plbestnet) { + MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); + } + DHD_PNO(("Batch retrieval done!\n")); + return err; +} +#endif /* GSCAN_SUPPORT */ + +static int +_dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) +{ + int err = BCME_OK; + int i, j; + uint32 timestamp = 0; + dhd_pno_params_t *_params = NULL; + dhd_pno_status_info_t *_pno_state = NULL; + wl_pfn_lscanresults_t *plbestnet = NULL; + wl_pfn_lnet_info_t *plnetinfo; + dhd_pno_bestnet_entry_t *pbestnet_entry; + dhd_pno_best_header_t *pbestnetheader = NULL; + dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext; + bool allocate_header = FALSE; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit_no_unlock; + } + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit_no_unlock; + } + + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); + goto exit_no_unlock; + } + mutex_lock(&_pno_state->pno_mutex); + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + if (buf && bufsize) { + if (!list_empty(&_params->params_batch.get_batch.expired_scan_results_list)) { + /* need to check whether we have cashed data or not */ + DHD_PNO(("%s: have cashed batching data in Driver\n", + __FUNCTION__)); + /* convert to results format */ + goto convert_format; + } else { + /* this is a first try to get batching results */ + if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { + /* move the scan_results_list to expired_scan_results_lists */ + list_for_each_entry_safe(siter, snext, + &_params->params_batch.get_batch.scan_results_list, list) { + list_move_tail(&siter->list, + &_params->params_batch.get_batch.expired_scan_results_list); + } + _params->params_batch.get_batch.top_node_cnt = 0; + _params->params_batch.get_batch.expired_tot_scan_cnt = + _params->params_batch.get_batch.tot_scan_cnt; + _params->params_batch.get_batch.tot_scan_cnt = 0; + goto convert_format; + } + } + } + /* create dhd_pno_scan_results_t whenever we got event WLC_E_PFN_BEST_BATCHING */ + pscan_results = (dhd_pno_scan_results_t *)MALLOC(dhd->osh, SCAN_RESULTS_SIZE); + if (pscan_results == NULL) { + err = BCME_NOMEM; + DHD_ERROR(("failed to allocate dhd_pno_scan_results_t\n")); + goto exit; + } + pscan_results->bestnetheader = NULL; + pscan_results->cnt_header = 0; + /* add the element into list unless total node cnt is less than MAX_NODE_ CNT */ + if (_params->params_batch.get_batch.top_node_cnt < MAX_NODE_CNT) { + list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); + _params->params_batch.get_batch.top_node_cnt++; + } else { + int _removed_scan_cnt; + /* remove oldest one and add new one */ + DHD_PNO(("%s : Remove oldest node and add new one\n", __FUNCTION__)); + _removed_scan_cnt = _dhd_pno_clear_all_batch_results(dhd, + &_params->params_batch.get_batch.scan_results_list, TRUE); + _params->params_batch.get_batch.tot_scan_cnt -= _removed_scan_cnt; + list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); + + } + plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + memset(plbestnet, 0, PNO_BESTNET_LEN); + while (plbestnet->status != PFN_COMPLETE) { + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, + (char *)plbestnet, PNO_BESTNET_LEN, FALSE); + if (err < 0) { + if (err == BCME_EPERM) { + DHD_ERROR(("we cannot get the batching data " + "during scanning in firmware, try again\n,")); + msleep(500); + continue; + } else { + DHD_ERROR(("%s : failed to execute pfnlbest (err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + } + DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, + plbestnet->status, plbestnet->count)); + if (plbestnet->version != PFN_SCANRESULT_VERSION) { + err = BCME_VERSION; + DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", + plbestnet->version, PFN_SCANRESULT_VERSION)); + goto exit; + } + plnetinfo = plbestnet->netinfo; + for (i = 0; i < plbestnet->count; i++) { + pbestnet_entry = (dhd_pno_bestnet_entry_t *) + MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); + if (pbestnet_entry == NULL) { + err = BCME_NOMEM; + DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); + goto exit; + } + memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE); + pbestnet_entry->recorded_time = jiffies; /* record the current time */ + /* create header for the first entry */ + allocate_header = (i == 0)? TRUE : FALSE; + /* check whether the new generation is started or not */ + if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) + > TIME_MIN_DIFF)) + allocate_header = TRUE; + timestamp = plnetinfo->timestamp; + if (allocate_header) { + pbestnetheader = (dhd_pno_best_header_t *) + MALLOC(dhd->osh, BEST_HEADER_SIZE); + if (pbestnetheader == NULL) { + err = BCME_NOMEM; + if (pbestnet_entry) + MFREE(dhd->osh, pbestnet_entry, + BESTNET_ENTRY_SIZE); + DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); + goto exit; + } + /* increase total cnt of bestnet header */ + pscan_results->cnt_header++; + /* need to record the reason to call dhd_pno_get_for_bach */ + if (reason) + pbestnetheader->reason = (ENABLE << reason); + memset(pbestnetheader, 0, BEST_HEADER_SIZE); + /* initialize the head of linked list */ + INIT_LIST_HEAD(&(pbestnetheader->entry_list)); + /* link the pbestnet heaer into existed list */ + if (pscan_results->bestnetheader == NULL) + /* In case of header */ + pscan_results->bestnetheader = pbestnetheader; + else { + dhd_pno_best_header_t *head = pscan_results->bestnetheader; + pscan_results->bestnetheader = pbestnetheader; + pbestnetheader->next = head; + } + } + /* fills the best network info */ + pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; + pbestnet_entry->RSSI = plnetinfo->RSSI; + if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { + /* if RSSI is positive value, we assume that + * this scan is aborted by other scan + */ + DHD_PNO(("This scan is aborted\n")); + pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); + } + pbestnet_entry->rtt0 = plnetinfo->rtt0; + pbestnet_entry->rtt1 = plnetinfo->rtt1; + pbestnet_entry->timestamp = plnetinfo->timestamp; + if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length %d: trimming it to max\n", + __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); + plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; + memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, + pbestnet_entry->SSID_len); + memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); + /* add the element into list */ + list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); + /* increase best entry count */ + pbestnetheader->tot_cnt++; + pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; + DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1)); + DHD_PNO(("\tSSID : ")); + for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) + DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j])); + DHD_PNO(("\n")); + DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", + plnetinfo->pfnsubnet.BSSID.octet[0], + plnetinfo->pfnsubnet.BSSID.octet[1], + plnetinfo->pfnsubnet.BSSID.octet[2], + plnetinfo->pfnsubnet.BSSID.octet[3], + plnetinfo->pfnsubnet.BSSID.octet[4], + plnetinfo->pfnsubnet.BSSID.octet[5])); + DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", + plnetinfo->pfnsubnet.channel, + plnetinfo->RSSI, plnetinfo->timestamp)); + DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1)); + plnetinfo++; + } + } + if (pscan_results->cnt_header == 0) { + /* In case that we didn't get any data from the firmware + * Remove the current scan_result list from get_bach.scan_results_list. + */ + DHD_PNO(("NO BATCH DATA from Firmware, Delete current SCAN RESULT LIST\n")); + list_del(&pscan_results->list); + MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE); + _params->params_batch.get_batch.top_node_cnt--; + } else { + /* increase total scan count using current scan count */ + _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; + } + + if (buf && bufsize) { + /* This is a first try to get batching results */ + if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { + /* move the scan_results_list to expired_scan_results_lists */ + list_for_each_entry_safe(siter, snext, + &_params->params_batch.get_batch.scan_results_list, list) { + list_move_tail(&siter->list, + &_params->params_batch.get_batch.expired_scan_results_list); + } + /* reset gloval values after moving to expired list */ + _params->params_batch.get_batch.top_node_cnt = 0; + _params->params_batch.get_batch.expired_tot_scan_cnt = + _params->params_batch.get_batch.tot_scan_cnt; + _params->params_batch.get_batch.tot_scan_cnt = 0; + } +convert_format: + err = _dhd_pno_convert_format(dhd, &_params->params_batch, buf, bufsize); + if (err < 0) { + DHD_ERROR(("failed to convert the data into upper layer format\n")); + goto exit; + } + } +exit: + if (plbestnet) + MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); + if (_params) { + _params->params_batch.get_batch.buf = NULL; + _params->params_batch.get_batch.bufsize = 0; + _params->params_batch.get_batch.bytes_written = err; + } + mutex_unlock(&_pno_state->pno_mutex); +exit_no_unlock: + if (waitqueue_active(&_pno_state->get_batch_done.wait)) + complete(&_pno_state->get_batch_done); + return err; +} +static void +_dhd_pno_get_batch_handler(struct work_struct *work) +{ + dhd_pno_status_info_t *_pno_state; + dhd_pub_t *dhd; + struct dhd_pno_batch_params *params_batch; + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = container_of(work, struct dhd_pno_status_info, work); + dhd = _pno_state->dhd; + if (dhd == NULL) { + DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); + return; + } +#ifdef GSCAN_SUPPORT + _dhd_pno_get_gscan_batch_from_fw(dhd); +#endif /* GSCAN_SUPPORT */ + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; + + _dhd_pno_get_for_batch(dhd, params_batch->get_batch.buf, + params_batch->get_batch.bufsize, params_batch->get_batch.reason); + } +} + +int +dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) +{ + int err = BCME_OK; + char *pbuf = buf; + dhd_pno_status_info_t *_pno_state; + struct dhd_pno_batch_params *params_batch; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + struct dhd_pno_gscan_params *gscan_params; + gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; + gscan_params->reason = reason; + err = dhd_retreive_batch_scan_results(dhd); + if (err == BCME_OK) { + wait_event_interruptible_timeout(_pno_state->batch_get_wait, + is_batch_retrieval_complete(gscan_params), + msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); + } + } else +#endif + { + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); + memset(pbuf, 0, bufsize); + pbuf += sprintf(pbuf, "scancount=%d\n", 0); + sprintf(pbuf, "%s", RESULTS_END_MARKER); + err = strlen(buf); + goto exit; + } + params_batch->get_batch.buf = buf; + params_batch->get_batch.bufsize = bufsize; + params_batch->get_batch.reason = reason; + params_batch->get_batch.bytes_written = 0; + schedule_work(&_pno_state->work); + wait_for_completion(&_pno_state->get_batch_done); + } + +#ifdef GSCAN_SUPPORT + if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) +#endif + err = params_batch->get_batch.bytes_written; +exit: + return err; +} + +int +dhd_pno_stop_for_batch(dhd_pub_t *dhd) +{ + int err = BCME_OK; + int mode = 0; + int i = 0; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + wl_pfn_bssid_t *p_pfn_bssid = NULL; + wlc_ssid_ext_t *p_ssid_list = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", + __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + DHD_PNO(("Gscan is ongoing, nothing to stop here\n")); + return err; + } +#endif + + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + DHD_ERROR(("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__)); + goto exit; + } + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { + mode = _pno_state->pno_mode; + dhd_pno_clean(dhd); + _pno_state->pno_mode = mode; + /* restart Legacy PNO if the Legacy PNO is on */ + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + struct dhd_pno_legacy_params *_params_legacy; + _params_legacy = + &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); + p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!p_ssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, + _params_legacy->scan_fr, _params_legacy->pno_repeat, + _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, + _params_legacy->nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + struct dhd_pno_bssid *iter, *next; + _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * + _params->params_hotlist.nbssid, GFP_KERNEL); + if (p_pfn_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" + " (count: %d)", + __FUNCTION__, _params->params_hotlist.nbssid)); + err = BCME_ERROR; + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + goto exit; + } + i = 0; + /* convert dhd_pno_bssid to wl_pfn_bssid */ + list_for_each_entry_safe(iter, next, + &_params->params_hotlist.bssid_list, list) { + memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN); + p_pfn_bssid[i].flags = iter->flags; + i++; + } + err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + } else { + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } +exit: + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); + if (p_ssid_list) + kfree(p_ssid_list); + if (p_pfn_bssid) + kfree(p_pfn_bssid); + return err; +} + +int +dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params) +{ + int err = BCME_OK; + int i; + uint16 _chan_list[WL_NUMCHANNELS]; + int rem_nchan = 0; + int tot_nchan = 0; + int mode = 0; + dhd_pno_params_t *_params; + dhd_pno_params_t *_params2; + struct dhd_pno_bssid *_pno_bssid; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + NULL_CHECK(hotlist_params, "hotlist_params is NULL", err); + NULL_CHECK(p_pfn_bssid, "p_pfn_bssid is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + _params = &_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]; + if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { + _pno_state->pno_mode |= DHD_PNO_HOTLIST_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_HOTLIST_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", + __FUNCTION__)); + goto exit; + } + } + _params->params_batch.nchan = hotlist_params->nchan; + _params->params_batch.scan_fr = hotlist_params->scan_fr; + if (hotlist_params->nchan) + memcpy(_params->params_hotlist.chan_list, hotlist_params->chan_list, + sizeof(_params->params_hotlist.chan_list)); + memset(_chan_list, 0, sizeof(_chan_list)); + + rem_nchan = ARRAYSIZE(hotlist_params->chan_list) - hotlist_params->nchan; + if (hotlist_params->band == WLC_BAND_2G || hotlist_params->band == WLC_BAND_5G) { + /* get a valid channel list based on band B or A */ + err = _dhd_pno_get_channels(dhd, + &_params->params_hotlist.chan_list[hotlist_params->nchan], + &rem_nchan, hotlist_params->band, FALSE); + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", + __FUNCTION__, hotlist_params->band)); + goto exit; + } + /* now we need to update nchan because rem_chan has valid channel count */ + _params->params_hotlist.nchan += rem_nchan; + /* need to sort channel list */ + sort(_params->params_hotlist.chan_list, _params->params_hotlist.nchan, + sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL); + } +#ifdef PNO_DEBUG +{ + int i; + DHD_PNO(("Channel list : ")); + for (i = 0; i < _params->params_batch.nchan; i++) { + DHD_PNO(("%d ", _params->params_batch.chan_list[i])); + } + DHD_PNO(("\n")); +} +#endif + if (_params->params_hotlist.nchan) { + /* copy the channel list into local array */ + memcpy(_chan_list, _params->params_hotlist.chan_list, + sizeof(_chan_list)); + tot_nchan = _params->params_hotlist.nchan; + } + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + DHD_PNO(("PNO SSID is on progress in firmware\n")); + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = _dhd_pno_enable(dhd, PNO_OFF); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + goto exit; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + /* Use the superset for channelist between two mode */ + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + if (_params2->params_legacy.nchan > 0 && + _params->params_hotlist.nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_legacy.chan_list[0], + _params2->params_legacy.nchan, + &_params->params_hotlist.chan_list[0], + _params->params_hotlist.nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + "between legacy and hotlist\n", + __FUNCTION__)); + goto exit; + } + } + + } + + INIT_LIST_HEAD(&(_params->params_hotlist.bssid_list)); + + err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, hotlist_params->nbssid); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_HOTLIST_MODE)) < 0) { + DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + if (tot_nchan > 0) { + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + } + for (i = 0; i < hotlist_params->nbssid; i++) { + _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); + NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err); + memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN); + _pno_bssid->flags = p_pfn_bssid[i].flags; + list_add_tail(&_pno_bssid->list, &_params->params_hotlist.bssid_list); + } + _params->params_hotlist.nbssid = hotlist_params->nbssid; + if (_pno_state->pno_status == DHD_PNO_DISABLED) { + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) + DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); + } +exit: + /* clear mode in case of error */ + if (err < 0) + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + return err; +} + +int +dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) +{ + int err = BCME_OK; + uint32 mode = 0; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + wlc_ssid_ext_t *p_ssid_list = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", + __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + + if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { + DHD_ERROR(("%s : Hotlist MODE is not enabled\n", + __FUNCTION__)); + goto exit; + } + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + + if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_BATCH_MODE)) { + /* retrieve the batching data from firmware into host */ + dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); + /* save current pno_mode before calling dhd_pno_clean */ + mode = _pno_state->pno_mode; + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + /* restore previos pno mode */ + _pno_state->pno_mode = mode; + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + /* restart Legacy PNO Scan */ + struct dhd_pno_legacy_params *_params_legacy; + _params_legacy = + &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); + p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!p_ssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, + _params_legacy->scan_fr, _params_legacy->pno_repeat, + _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, + _params_legacy->nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } else if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + /* restart Batching Scan */ + _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + /* restart BATCH SCAN */ + err = dhd_pno_set_for_batch(dhd, &_params->params_batch); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + } else { + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } +exit: + if (p_ssid_list) + kfree(p_ssid_list); + return err; +} + +#ifdef GSCAN_SUPPORT +int +dhd_retreive_batch_scan_results(dhd_pub_t *dhd) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + struct dhd_pno_batch_params *params_batch; + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; + if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE) { + DHD_PNO(("Retreive batch results\n")); + params_batch->get_batch.buf = NULL; + params_batch->get_batch.bufsize = 0; + params_batch->get_batch.reason = PNO_STATUS_EVENT; + _params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_IN_PROGRESS; + smp_wmb(); + schedule_work(&_pno_state->work); + } else { + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING retrieval" + "already in progress, will skip\n", __FUNCTION__)); + err = BCME_ERROR; + } + + return err; +} + +/* Handle Significant WiFi Change (SWC) event from FW + * Send event to HAL when all results arrive from FW + */ +void * +dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes) +{ + void *ptr = NULL; + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + struct dhd_pno_gscan_params *gscan_params; + struct dhd_pno_swc_evt_param *params; + wl_pfn_swc_results_t *results = (wl_pfn_swc_results_t *)event_data; + wl_pfn_significant_net_t *change_array; + int i; + + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + params = &(gscan_params->param_significant); + + if (!results->total_count) { + *send_evt_bytes = 0; + return ptr; + } + + if (!params->results_rxed_so_far) { + if (!params->change_array) { + params->change_array = (wl_pfn_significant_net_t *) + kmalloc(sizeof(wl_pfn_significant_net_t) * results->total_count, + GFP_KERNEL); + + if (!params->change_array) { + DHD_ERROR(("%s Cannot Malloc %zd bytes!!\n", __FUNCTION__, + sizeof(wl_pfn_significant_net_t) * results->total_count)); + *send_evt_bytes = 0; + return ptr; + } + } else { + DHD_ERROR(("RX'ed WLC_E_PFN_SWC evt from FW, previous evt not complete!!")); + *send_evt_bytes = 0; + return ptr; + } + + } + + DHD_PNO(("%s: pkt_count %d total_count %d\n", __FUNCTION__, + results->pkt_count, results->total_count)); + + for (i = 0; i < results->pkt_count; i++) { + DHD_PNO(("\t %02x:%02x:%02x:%02x:%02x:%02x\n", + results->list[i].BSSID.octet[0], + results->list[i].BSSID.octet[1], + results->list[i].BSSID.octet[2], + results->list[i].BSSID.octet[3], + results->list[i].BSSID.octet[4], + results->list[i].BSSID.octet[5])); + } + + change_array = ¶ms->change_array[params->results_rxed_so_far]; + if ((params->results_rxed_so_far + results->pkt_count) <= results->total_count) { + memcpy(change_array, results->list, + sizeof(wl_pfn_significant_net_t) * results->pkt_count); + params->results_rxed_so_far += results->pkt_count; + } else { + /* In case of spurious event or invalid data send hang event */ + dhd_os_send_hang_message(dhd); + } + + if (params->results_rxed_so_far == results->total_count) { + params->results_rxed_so_far = 0; + *send_evt_bytes = sizeof(wl_pfn_significant_net_t) * results->total_count; + /* Pack up change buffer to send up and reset + * results_rxed_so_far, after its done. + */ + ptr = (void *) params->change_array; + /* expecting the callee to free this mem chunk */ + params->change_array = NULL; + } else { + *send_evt_bytes = 0; + } + + return ptr; +} + +void +dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) +{ + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + struct dhd_pno_gscan_params *gscan_params; + gscan_results_cache_t *iter, *tmp; + + if (!_pno_state) + return; + + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + + if (type == HOTLIST_FOUND) { + iter = gscan_params->gscan_hotlist_found; + gscan_params->gscan_hotlist_found = NULL; + } else { + iter = gscan_params->gscan_hotlist_lost; + gscan_params->gscan_hotlist_lost = NULL; + } + + while (iter) { + tmp = iter->next; + kfree(iter); + iter = tmp; + } + + return; +} + +void * +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) +{ + wl_bss_info_t *bi = NULL; + wl_gscan_result_t *gscan_result; + wifi_gscan_result_t *result = NULL; + u32 bi_length = 0; + uint8 channel; + uint32 mem_needed; + struct timespec ts; + + *size = 0; + + gscan_result = (wl_gscan_result_t *)data; + + if (!gscan_result) { + DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); + goto exit; + } + if (!gscan_result->bss_info) { + DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); + goto exit; + } + bi = &gscan_result->bss_info[0].info; + bi_length = dtoh32(bi->length); + if (bi_length != (dtoh32(gscan_result->buflen) - + WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) { + DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); + goto exit; + } + if (bi->SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", bi->SSID_len)); + bi->SSID_len = DOT11_MAX_SSID_LEN; + } + + mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi->ie_length; + result = kmalloc(mem_needed, GFP_KERNEL); + + if (!result) { + DHD_ERROR(("%s Cannot malloc scan result buffer %d bytes\n", + __FUNCTION__, mem_needed)); + goto exit; + } + + memcpy(result->ssid, bi->SSID, bi->SSID_len); + result->ssid[bi->SSID_len] = '\0'; + channel = wf_chspec_ctlchan(bi->chanspec); + result->channel = wf_channel2mhz(channel, + (channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + result->rssi = (int32) bi->RSSI; + result->rtt = 0; + result->rtt_sd = 0; + get_monotonic_boottime(&ts); + result->ts = (uint64) TIMESPEC_TO_US(ts); + result->beacon_period = dtoh16(bi->beacon_period); + result->capability = dtoh16(bi->capability); + result->ie_length = dtoh32(bi->ie_length); + memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN); + memcpy(result->ie_data, ((uint8 *)bi + bi->ie_offset), bi->ie_length); + *size = mem_needed; +exit: + return result; +} + +void * +dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size) +{ + dhd_epno_results_t *results = NULL; + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + struct dhd_pno_gscan_params *gscan_params; + uint32 count, mem_needed = 0, i; + uint8 ssid[DOT11_MAX_SSID_LEN + 1]; + struct ether_addr *bssid; + + *size = 0; + if (!_pno_state) + return NULL; + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + + if (event == WLC_E_PFN_SSID_EXT) { + wl_pfn_ssid_ext_result_t *evt_data; + evt_data = (wl_pfn_ssid_ext_result_t *) data; + + if (evt_data->version != PFN_SSID_EXT_VERSION) { + DHD_PNO(("ePNO event: Incorrect version %d %d\n", evt_data->version, + PFN_SSID_EXT_VERSION)); + return NULL; + } + count = evt_data->count; + mem_needed = sizeof(dhd_epno_results_t) * count; + results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); + if (!results) { + DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, + mem_needed)); + return NULL; + } + DHD_ERROR(("Rx'ed WLC_E_PFN_SSID_EXT event: %d results\n", count)); + for (i = 0; i < count; i++) { + results[i].rssi = evt_data->net[i].rssi; + results[i].channel = wf_channel2mhz(evt_data->net[i].channel, + (evt_data->net[i].channel <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + results[i].flags = evt_data->net[i].flags; + dhd_pno_idx_to_ssid(gscan_params, &results[i], + evt_data->net[i].index); + memcpy(ssid, results[i].ssid, results[i].ssid_len); + bssid = &results[i].bssid; + memcpy(bssid, &evt_data->net[i].bssid, ETHER_ADDR_LEN); + ssid[results[i].ssid_len] = '\0'; + DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " + "idx %d ch %d rssi %d flags %d\n", ssid, + bssid->octet[0], bssid->octet[1], + bssid->octet[2], bssid->octet[3], + bssid->octet[4], bssid->octet[5], + evt_data->net[i].index, results[i].channel, + results[i].rssi, results[i].flags)); + } + } else if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) { + wl_pfn_scanresults_t *pfn_result = (wl_pfn_scanresults_t *)data; + wl_pfn_net_info_t *net; + + if (pfn_result->version != PFN_SCANRESULT_VERSION) { + DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, + pfn_result->version, PFN_SCANRESULT_VERSION)); + return NULL; + } + count = pfn_result->count; + mem_needed = sizeof(dhd_epno_results_t) * count; + results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); + if (!results) { + DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, + mem_needed)); + return NULL; + } + for (i = 0; i < count; i++) { + net = &pfn_result->netinfo[i]; + results[i].rssi = net->RSSI; + results[i].channel = wf_channel2mhz(net->pfnsubnet.channel, + (net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + results[i].flags = (event == WLC_E_PFN_NET_FOUND) ? + WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST; + results[i].ssid_len = min(net->pfnsubnet.SSID_len, + (uint8)DOT11_MAX_SSID_LEN); + bssid = &results[i].bssid; + memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN); + memcpy(results[i].ssid, net->pfnsubnet.SSID, results[i].ssid_len); + memcpy(ssid, results[i].ssid, results[i].ssid_len); + ssid[results[i].ssid_len] = '\0'; + DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " + "ch %d rssi %d flags %d\n", ssid, + bssid->octet[0], bssid->octet[1], + bssid->octet[2], bssid->octet[3], + bssid->octet[4], bssid->octet[5], + results[i].channel, results[i].rssi, results[i].flags)); + } + } + *size = mem_needed; + return results; +} + + +void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, + hotlist_type_t type) +{ + void *ptr = NULL; + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + struct dhd_pno_gscan_params *gscan_params; + wl_pfn_scanresults_t *results = (wl_pfn_scanresults_t *)event_data; + wifi_gscan_result_t *hotlist_found_array; + wl_pfn_net_info_t *plnetinfo; + gscan_results_cache_t *gscan_hotlist_cache; + int malloc_size = 0, i, total = 0; + + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + + if (!results->count) { + *send_evt_bytes = 0; + return ptr; + } + + malloc_size = sizeof(gscan_results_cache_t) + + ((results->count - 1) * sizeof(wifi_gscan_result_t)); + gscan_hotlist_cache = (gscan_results_cache_t *) kmalloc(malloc_size, GFP_KERNEL); + + if (!gscan_hotlist_cache) { + DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size)); + *send_evt_bytes = 0; + return ptr; + } + + if (type == HOTLIST_FOUND) { + gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found; + gscan_params->gscan_hotlist_found = gscan_hotlist_cache; + DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, results->count)); + } else { + gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost; + gscan_params->gscan_hotlist_lost = gscan_hotlist_cache; + DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, results->count)); + } + + gscan_hotlist_cache->tot_count = results->count; + gscan_hotlist_cache->tot_consumed = 0; + plnetinfo = results->netinfo; + + for (i = 0; i < results->count; i++, plnetinfo++) { + hotlist_found_array = &gscan_hotlist_cache->results[i]; + hotlist_found_array->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, + (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + hotlist_found_array->rssi = (int32) plnetinfo->RSSI; + /* Info not available & not expected */ + hotlist_found_array->beacon_period = 0; + hotlist_found_array->capability = 0; + hotlist_found_array->ie_length = 0; + + hotlist_found_array->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); + if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", + plnetinfo->pfnsubnet.SSID_len)); + plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + memcpy(hotlist_found_array->ssid, plnetinfo->pfnsubnet.SSID, + plnetinfo->pfnsubnet.SSID_len); + hotlist_found_array->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; + + memcpy(&hotlist_found_array->macaddr, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); + DHD_PNO(("\t%s %02x:%02x:%02x:%02x:%02x:%02x rssi %d\n", hotlist_found_array->ssid, + hotlist_found_array->macaddr.octet[0], + hotlist_found_array->macaddr.octet[1], + hotlist_found_array->macaddr.octet[2], + hotlist_found_array->macaddr.octet[3], + hotlist_found_array->macaddr.octet[4], + hotlist_found_array->macaddr.octet[5], + hotlist_found_array->rssi)); + } + + + if (results->status == PFN_COMPLETE) { + ptr = (void *) gscan_hotlist_cache; + while (gscan_hotlist_cache) { + total += gscan_hotlist_cache->tot_count; + gscan_hotlist_cache = gscan_hotlist_cache->next; + } + *send_evt_bytes = total * sizeof(wifi_gscan_result_t); + } + + return ptr; +} +#endif /* GSCAN_SUPPORT */ +int +dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) +{ + int err = BCME_OK; + uint status, event_type, flags, datalen; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + event_type = ntoh32(event->event_type); + flags = ntoh16(event->flags); + status = ntoh32(event->status); + datalen = ntoh32(event->datalen); + DHD_PNO(("%s enter : event_type :%d\n", __FUNCTION__, event_type)); + switch (event_type) { + case WLC_E_PFN_BSSID_NET_FOUND: + case WLC_E_PFN_BSSID_NET_LOST: + /* TODO : need to implement event logic using generic netlink */ + break; + case WLC_E_PFN_BEST_BATCHING: +#ifndef GSCAN_SUPPORT + { + struct dhd_pno_batch_params *params_batch; + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; + if (!waitqueue_active(&_pno_state->get_batch_done.wait)) { + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); + params_batch->get_batch.buf = NULL; + params_batch->get_batch.bufsize = 0; + params_batch->get_batch.reason = PNO_STATUS_EVENT; + schedule_work(&_pno_state->work); + } else + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING" + "will skip this event\n", __FUNCTION__)); + break; + } +#else + break; +#endif /* !GSCAN_SUPPORT */ + default: + DHD_ERROR(("unknown event : %d\n", event_type)); + } +exit: + return err; +} + +int dhd_pno_init(dhd_pub_t *dhd) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + char *buf = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + UNUSED_PARAMETER(_dhd_pno_suspend); + if (dhd->pno_state) + goto exit; + dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t)); + NULL_CHECK(dhd->pno_state, "failed to create dhd_pno_state", err); + memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t)); + /* need to check whether current firmware support batching and hotlist scan */ + _pno_state = PNO_GET_PNOSTATE(dhd); + _pno_state->wls_supported = TRUE; + _pno_state->dhd = dhd; + mutex_init(&_pno_state->pno_mutex); + INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler); + init_completion(&_pno_state->get_batch_done); +#ifdef GSCAN_SUPPORT + init_waitqueue_head(&_pno_state->batch_get_wait); +#endif /* GSCAN_SUPPORT */ + buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + if (!buf) { + DHD_ERROR((":%s buf alloc err.\n", __FUNCTION__)); + return BCME_NOMEM; + } + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, buf, WLC_IOCTL_SMLEN, + FALSE); + if (err == BCME_UNSUPPORTED) { + _pno_state->wls_supported = FALSE; + DHD_INFO(("Current firmware doesn't support" + " Android Location Service\n")); + } +exit: + kfree(buf); + return err; +} +int dhd_pno_deinit(dhd_pub_t *dhd) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + NULL_CHECK(dhd, "dhd is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + NULL_CHECK(_pno_state, "pno_state is NULL", err); + /* may need to free legacy ssid_list */ + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + _params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + } + +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + mutex_lock(&_pno_state->pno_mutex); + dhd_pno_reset_cfg_gscan(_params, _pno_state, GSCAN_FLUSH_ALL_CFG); + mutex_unlock(&_pno_state->pno_mutex); + } +#endif /* GSCAN_SUPPORT */ + + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + /* clear resource if the BATCH MODE is on */ + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); + } + cancel_work_sync(&_pno_state->work); + MFREE(dhd->osh, _pno_state, sizeof(dhd_pno_status_info_t)); + dhd->pno_state = NULL; + return err; +} +#endif /* PNO_SUPPORT */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h new file mode 100644 index 000000000000..2f48e5fc55e5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h @@ -0,0 +1,561 @@ +/* + * Header file of Broadcom Dongle Host Driver (DHD) + * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_pno.h 423669 2013-09-18 13:01:55Z $ + */ + +#ifndef __DHD_PNO_H__ +#define __DHD_PNO_H__ + +#if defined(PNO_SUPPORT) +#define PNO_TLV_PREFIX 'S' +#define PNO_TLV_VERSION '1' +#define PNO_TLV_SUBTYPE_LEGACY_PNO '2' +#define PNO_TLV_RESERVED '0' + +#define PNO_BATCHING_SET "SET" +#define PNO_BATCHING_GET "GET" +#define PNO_BATCHING_STOP "STOP" + +#define PNO_PARAMS_DELIMETER " " +#define PNO_PARAM_CHANNEL_DELIMETER "," +#define PNO_PARAM_VALUE_DELLIMETER '=' +#define PNO_PARAM_SCANFREQ "SCANFREQ" +#define PNO_PARAM_BESTN "BESTN" +#define PNO_PARAM_MSCAN "MSCAN" +#define PNO_PARAM_CHANNEL "CHANNEL" +#define PNO_PARAM_RTT "RTT" + +#define PNO_TLV_TYPE_SSID_IE 'S' +#define PNO_TLV_TYPE_TIME 'T' +#define PNO_TLV_FREQ_REPEAT 'R' +#define PNO_TLV_FREQ_EXPO_MAX 'M' + +#define MAXNUM_SSID_PER_ADD 16 +#define MAXNUM_PNO_PARAMS 2 +#define PNO_TLV_COMMON_LENGTH 1 +#define DEFAULT_BATCH_MSCAN 16 + +#define RESULTS_END_MARKER "----\n" +#define SCAN_END_MARKER "####\n" +#define AP_END_MARKER "====\n" +#define PNO_RSSI_MARGIN_DBM 30 + +#ifdef GSCAN_SUPPORT + +#define GSCAN_MAX_CH_BUCKETS 8 +#define GSCAN_MAX_CHANNELS_IN_BUCKET 32 +#define GSCAN_MAX_AP_CACHE_PER_SCAN 32 +#define GSCAN_MAX_AP_CACHE 320 +#define GSCAN_BG_BAND_MASK (1 << 0) +#define GSCAN_A_BAND_MASK (1 << 1) +#define GSCAN_DFS_MASK (1 << 2) +#define GSCAN_ABG_BAND_MASK (GSCAN_A_BAND_MASK | GSCAN_BG_BAND_MASK) +#define GSCAN_BAND_MASK (GSCAN_ABG_BAND_MASK | GSCAN_DFS_MASK) + +#define GSCAN_FLUSH_HOTLIST_CFG (1 << 0) +#define GSCAN_FLUSH_SIGNIFICANT_CFG (1 << 1) +#define GSCAN_FLUSH_SCAN_CFG (1 << 2) +#define GSCAN_FLUSH_EPNO_CFG (1 << 3) +#define GSCAN_FLUSH_ALL_CFG (GSCAN_FLUSH_SCAN_CFG | \ + GSCAN_FLUSH_SIGNIFICANT_CFG | \ + GSCAN_FLUSH_HOTLIST_CFG | \ + GSCAN_FLUSH_EPNO_CFG) +#define DHD_EPNO_HIDDEN_SSID (1 << 0) +#define DHD_EPNO_A_BAND_TRIG (1 << 1) +#define DHD_EPNO_BG_BAND_TRIG (1 << 2) +#define DHD_EPNO_STRICT_MATCH (1 << 3) +#define DHD_PNO_USE_SSID (DHD_EPNO_HIDDEN_SSID | DHD_EPNO_STRICT_MATCH) + +/* Do not change GSCAN_BATCH_RETRIEVAL_COMPLETE */ +#define GSCAN_BATCH_RETRIEVAL_COMPLETE 0 +#define GSCAN_BATCH_RETRIEVAL_IN_PROGRESS 1 +#define GSCAN_BATCH_NO_THR_SET 101 +#define GSCAN_LOST_AP_WINDOW_DEFAULT 4 +#define GSCAN_MIN_BSSID_TIMEOUT 90 +#define GSCAN_BATCH_GET_MAX_WAIT 500 +#define CHANNEL_BUCKET_EMPTY_INDEX 0xFF +#define GSCAN_RETRY_THRESHOLD 3 +#define MAX_EPNO_SSID_NUM 32 + +#endif /* GSCAN_SUPPORT */ + +enum scan_status { + /* SCAN ABORT by other scan */ + PNO_STATUS_ABORT, + /* RTT is presence or not */ + PNO_STATUS_RTT_PRESENCE, + /* Disable PNO by Driver */ + PNO_STATUS_DISABLE, + /* NORMAL BATCHING GET */ + PNO_STATUS_NORMAL, + /* WLC_E_PFN_BEST_BATCHING */ + PNO_STATUS_EVENT, + PNO_STATUS_MAX +}; +#define PNO_STATUS_ABORT_MASK 0x0001 +#define PNO_STATUS_RTT_MASK 0x0002 +#define PNO_STATUS_DISABLE_MASK 0x0004 +#define PNO_STATUS_OOM_MASK 0x0010 + +enum index_mode { + INDEX_OF_LEGACY_PARAMS, + INDEX_OF_BATCH_PARAMS, + INDEX_OF_HOTLIST_PARAMS, + /* GSCAN includes hotlist scan and they do not run + * independent of each other + */ +#ifdef GSCAN_SUPPORT + INDEX_OF_GSCAN_PARAMS = INDEX_OF_HOTLIST_PARAMS, +#endif /* GSCAN_SUPPORT */ + INDEX_MODE_MAX +}; +enum dhd_pno_status { + DHD_PNO_DISABLED, + DHD_PNO_ENABLED, + DHD_PNO_SUSPEND +}; +typedef struct cmd_tlv { + char prefix; + char version; + char subtype; + char reserved; +} cmd_tlv_t; +#ifdef GSCAN_SUPPORT +typedef enum { + WIFI_BAND_UNSPECIFIED, + WIFI_BAND_BG = 1, /* 2.4 GHz */ + WIFI_BAND_A = 2, /* 5 GHz without DFS */ + WIFI_BAND_A_DFS = 4, /* 5 GHz DFS only */ + WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ + WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ + WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ +} gscan_wifi_band_t; + +typedef enum { + HOTLIST_LOST, + HOTLIST_FOUND +} hotlist_type_t; + +typedef enum dhd_pno_gscan_cmd_cfg { + DHD_PNO_BATCH_SCAN_CFG_ID, + DHD_PNO_GEOFENCE_SCAN_CFG_ID, + DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, + DHD_PNO_SCAN_CFG_ID, + DHD_PNO_GET_CAPABILITIES, + DHD_PNO_GET_BATCH_RESULTS, + DHD_PNO_GET_CHANNEL_LIST, + DHD_PNO_GET_EPNO_SSID_ELEM, + DHD_PNO_EPNO_CFG_ID, + DHD_PNO_GET_AUTOJOIN_CAPABILITIES +} dhd_pno_gscan_cmd_cfg_t; + +typedef enum dhd_pno_mode { + /* Wi-Fi Legacy PNO Mode */ + DHD_PNO_NONE_MODE = 0, + DHD_PNO_LEGACY_MODE = (1 << (0)), + /* Wi-Fi Android BATCH SCAN Mode */ + DHD_PNO_BATCH_MODE = (1 << (1)), + /* Wi-Fi Android Hotlist SCAN Mode */ + DHD_PNO_HOTLIST_MODE = (1 << (2)), + /* Wi-Fi Google Android SCAN Mode */ + DHD_PNO_GSCAN_MODE = (1 << (3)) +} dhd_pno_mode_t; +#else +typedef enum dhd_pno_mode { + /* Wi-Fi Legacy PNO Mode */ + DHD_PNO_NONE_MODE = 0, + DHD_PNO_LEGACY_MODE = (1 << (0)), + /* Wi-Fi Android BATCH SCAN Mode */ + DHD_PNO_BATCH_MODE = (1 << (1)), + /* Wi-Fi Android Hotlist SCAN Mode */ + DHD_PNO_HOTLIST_MODE = (1 << (2)) +} dhd_pno_mode_t; +#endif /* GSCAN_SUPPORT */ +struct dhd_pno_ssid { + bool hidden; + int8 rssi_thresh; + uint8 dummy; + uint16 SSID_len; + uchar SSID[DOT11_MAX_SSID_LEN]; + struct list_head list; +}; +struct dhd_pno_bssid { + struct ether_addr macaddr; + /* Bit4: suppress_lost, Bit3: suppress_found */ + uint16 flags; + struct list_head list; +}; +typedef struct dhd_pno_bestnet_entry { + struct ether_addr BSSID; + uint8 SSID_len; + uint8 SSID[DOT11_MAX_SSID_LEN]; + int8 RSSI; + uint8 channel; + uint32 timestamp; + uint16 rtt0; /* distance_cm based on RTT */ + uint16 rtt1; /* distance_cm based on sample standard deviation */ + unsigned long recorded_time; + struct list_head list; +} dhd_pno_bestnet_entry_t; +#define BESTNET_ENTRY_SIZE (sizeof(dhd_pno_bestnet_entry_t)) + +typedef struct dhd_pno_bestnet_header { + struct dhd_pno_bestnet_header *next; + uint8 reason; + uint32 tot_cnt; + uint32 tot_size; + struct list_head entry_list; +} dhd_pno_best_header_t; +#define BEST_HEADER_SIZE (sizeof(dhd_pno_best_header_t)) + +typedef struct dhd_pno_scan_results { + dhd_pno_best_header_t *bestnetheader; + uint8 cnt_header; + struct list_head list; +} dhd_pno_scan_results_t; +#define SCAN_RESULTS_SIZE (sizeof(dhd_pno_scan_results_t)) + +struct dhd_pno_get_batch_info { + /* info related to get batch */ + char *buf; + bool batch_started; + uint32 tot_scan_cnt; + uint32 expired_tot_scan_cnt; + uint32 top_node_cnt; + uint32 bufsize; + uint32 bytes_written; + int reason; + struct list_head scan_results_list; + struct list_head expired_scan_results_list; +}; +struct dhd_pno_legacy_params { + uint16 scan_fr; + uint16 chan_list[WL_NUMCHANNELS]; + uint16 nchan; + int pno_repeat; + int pno_freq_expo_max; + int nssid; + struct list_head ssid_list; +}; +struct dhd_pno_batch_params { + int32 scan_fr; + uint8 bestn; + uint8 mscan; + uint8 band; + uint16 chan_list[WL_NUMCHANNELS]; + uint16 nchan; + uint16 rtt; + struct dhd_pno_get_batch_info get_batch; +}; +struct dhd_pno_hotlist_params { + uint8 band; + int32 scan_fr; + uint16 chan_list[WL_NUMCHANNELS]; + uint16 nchan; + uint16 nbssid; + struct list_head bssid_list; +}; +#ifdef GSCAN_SUPPORT +#define DHD_PNO_REPORT_NO_BATCH (1 << 2) + +typedef struct dhd_pno_gscan_channel_bucket { + uint16 bucket_freq_multiple; + /* band = 1 All bg band channels, + * band = 2 All a band channels, + * band = 0 chan_list channels + */ + uint16 band; + uint8 report_flag; + uint8 num_channels; + uint16 repeat; + uint16 bucket_max_multiple; + uint16 chan_list[GSCAN_MAX_CHANNELS_IN_BUCKET]; +} dhd_pno_gscan_channel_bucket_t; + + +#define DHD_PNO_AUTH_CODE_OPEN 1 /* Open */ +#define DHD_PNO_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ +#define DHD_PNO_AUTH_CODE_EAPOL 4 /* any EAPOL */ + +#define DHD_EPNO_DEFAULT_INDEX 0xFFFFFFFF + +typedef struct dhd_epno_params { + uint8 ssid[DOT11_MAX_SSID_LEN]; + uint8 ssid_len; + int8 rssi_thresh; + uint8 flags; + uint8 auth; + /* index required only for visble ssid */ + uint32 index; + struct list_head list; +} dhd_epno_params_t; + +typedef struct dhd_epno_results { + uint8 ssid[DOT11_MAX_SSID_LEN]; + uint8 ssid_len; + int8 rssi; + uint16 channel; + uint16 flags; + struct ether_addr bssid; +} dhd_epno_results_t; + +struct dhd_pno_swc_evt_param { + uint16 results_rxed_so_far; + wl_pfn_significant_net_t *change_array; +}; + +typedef struct wifi_gscan_result { + uint64 ts; /* Time of discovery */ + char ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated */ + struct ether_addr macaddr; /* BSSID */ + uint32 channel; /* channel frequency in MHz */ + int32 rssi; /* in db */ + uint64 rtt; /* in nanoseconds */ + uint64 rtt_sd; /* standard deviation in rtt */ + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint32 ie_length; /* byte length of Information Elements */ + char ie_data[1]; /* IE data to follow */ +} wifi_gscan_result_t; + +typedef struct gscan_results_cache { + struct gscan_results_cache *next; + uint8 scan_id; + uint8 flag; + uint8 tot_count; + uint8 tot_consumed; + wifi_gscan_result_t results[1]; +} gscan_results_cache_t; + +typedef struct dhd_pno_gscan_capabilities { + int max_scan_cache_size; + int max_scan_buckets; + int max_ap_cache_per_scan; + int max_rssi_sample_size; + int max_scan_reporting_threshold; + int max_hotlist_aps; + int max_significant_wifi_change_aps; + int max_epno_ssid_crc32; + int max_epno_hidden_ssid; + int max_white_list_ssid; +} dhd_pno_gscan_capabilities_t; + +struct dhd_pno_gscan_params { + int32 scan_fr; + uint8 bestn; + uint8 mscan; + uint8 buffer_threshold; + uint8 swc_nbssid_threshold; + uint8 swc_rssi_window_size; + uint8 lost_ap_window; + uint8 nchannel_buckets; + uint8 reason; + uint8 get_batch_flag; + uint8 send_all_results_flag; + uint16 max_ch_bucket_freq; + gscan_results_cache_t *gscan_batch_cache; + gscan_results_cache_t *gscan_hotlist_found; + gscan_results_cache_t *gscan_hotlist_lost; + uint16 nbssid_significant_change; + uint16 nbssid_hotlist; + uint16 num_epno_ssid; + uint8 num_visible_epno_ssid; + /* To keep track of visble ssid index + * across multiple FW configs i.e. config + * w/o clear in between + */ + uint8 ssid_ext_last_used_index; + struct dhd_pno_swc_evt_param param_significant; + struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; + struct list_head hotlist_bssid_list; + struct list_head significant_bssid_list; + struct list_head epno_ssid_list; + uint32 scan_id; +}; + +typedef struct gscan_scan_params { + int32 scan_fr; + uint16 nchannel_buckets; + struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; +} gscan_scan_params_t; + +typedef struct gscan_batch_params { + uint8 bestn; + uint8 mscan; + uint8 buffer_threshold; +} gscan_batch_params_t; + +struct bssid_t { + struct ether_addr macaddr; + int16 rssi_reporting_threshold; /* 0 -> no reporting threshold */ +}; + +typedef struct gscan_hotlist_scan_params { + uint16 lost_ap_window; /* number of scans to declare LOST */ + uint16 nbssid; /* number of bssids */ + struct bssid_t bssid[1]; /* n bssids to follow */ +} gscan_hotlist_scan_params_t; + +/* SWC (Significant WiFi Change) params */ +typedef struct gscan_swc_params { + /* Rssi averaging window size */ + uint8 rssi_window; + /* Number of scans that the AP has to be absent before + * being declared LOST + */ + uint8 lost_ap_window; + /* if x Aps have a significant change generate an event. */ + uint8 swc_threshold; + uint8 nbssid; + wl_pfn_significant_bssid_t bssid_elem_list[1]; +} gscan_swc_params_t; + +typedef struct dhd_pno_significant_bssid { + struct ether_addr BSSID; + int8 rssi_low_threshold; + int8 rssi_high_threshold; + struct list_head list; +} dhd_pno_significant_bssid_t; +#endif /* GSCAN_SUPPORT */ +typedef union dhd_pno_params { + struct dhd_pno_legacy_params params_legacy; + struct dhd_pno_batch_params params_batch; + struct dhd_pno_hotlist_params params_hotlist; +#ifdef GSCAN_SUPPORT + struct dhd_pno_gscan_params params_gscan; +#endif /* GSCAN_SUPPORT */ +} dhd_pno_params_t; +typedef struct dhd_pno_status_info { + dhd_pub_t *dhd; + struct work_struct work; + struct mutex pno_mutex; +#ifdef GSCAN_SUPPORT + wait_queue_head_t batch_get_wait; +#endif /* GSCAN_SUPPORT */ + struct completion get_batch_done; + bool wls_supported; /* wifi location service supported or not */ + enum dhd_pno_status pno_status; + enum dhd_pno_mode pno_mode; + dhd_pno_params_t pno_params_arr[INDEX_MODE_MAX]; + struct list_head head_list; +} dhd_pno_status_info_t; + +/* wrapper functions */ +extern int +dhd_dev_pno_enable(struct net_device *dev, int enable); + +extern int +dhd_dev_pno_stop_for_ssid(struct net_device *dev); + +extern int +dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); + +extern int +dhd_dev_pno_set_for_batch(struct net_device *dev, + struct dhd_pno_batch_params *batch_params); + +extern int +dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize); + +extern int +dhd_dev_pno_stop_for_batch(struct net_device *dev); + +extern int +dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params); +extern bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev); +#ifdef GSCAN_SUPPORT +extern int +dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, + void *buf, uint8 flush); +extern void * +dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, void *info, + uint32 *len); +int dhd_dev_pno_lock_access_batch_results(struct net_device *dev); +void dhd_dev_pno_unlock_access_batch_results(struct net_device *dev); +extern int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush); +extern int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time); +extern void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, + int *send_evt_bytes); +int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); +extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, + const void *data, int *send_evt_bytes, hotlist_type_t type); +void * dhd_dev_process_full_gscan_result(struct net_device *dev, + const void *data, int *send_evt_bytes); +extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); +extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); +extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); +extern void * dhd_dev_process_epno_result(struct net_device *dev, + const void *data, uint32 event, int *send_evt_bytes); +#endif /* GSCAN_SUPPORT */ +/* dhd pno fuctions */ +extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd); +extern int dhd_pno_enable(dhd_pub_t *dhd, int enable); +extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); + +extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params); + +extern int dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason); + + +extern int dhd_pno_stop_for_batch(dhd_pub_t *dhd); + +extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params); + +extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd); + +extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); +extern int dhd_pno_init(dhd_pub_t *dhd); +extern int dhd_pno_deinit(dhd_pub_t *dhd); +extern bool dhd_is_pno_supported(dhd_pub_t *dhd); +extern int dhd_pno_set_mac_oui(dhd_pub_t *dhd, uint8 *oui); +extern bool dhd_is_legacy_pno_enabled(dhd_pub_t *dhd); +#ifdef GSCAN_SUPPORT +extern int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, + void *buf, uint8 flush); +extern void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *info, + uint32 *len); +extern int dhd_pno_lock_batch_results(dhd_pub_t *dhd); +extern void dhd_pno_unlock_batch_results(dhd_pub_t *dhd); +extern int dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush); +extern int dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag); +extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *buf); +extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); +extern void *dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes); +extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, + int *send_evt_bytes, hotlist_type_t type); +extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, + int *send_evt_bytes); +extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); +extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); +extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); +extern void * dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, + uint32 event, int *size); +#endif /* GSCAN_SUPPORT */ +#endif + +#endif /* __DHD_PNO_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_proto.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_proto.h new file mode 100644 index 000000000000..b7299dee3e47 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_proto.h @@ -0,0 +1,150 @@ +/* + * Header file describing the internal (inter-module) DHD interfaces. + * + * Provides type definitions and function prototypes used to link the + * DHD OS, bus, and protocol modules. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_proto.h 574949 2015-07-28 13:02:30Z $ + */ + +#ifndef _dhd_proto_h_ +#define _dhd_proto_h_ + +#include +#include +#ifdef BCMPCIE +#include +#endif + +#define DEFAULT_IOCTL_RESP_TIMEOUT 2000 +#ifndef IOCTL_RESP_TIMEOUT +/* In milli second default value for Production FW */ +#define IOCTL_RESP_TIMEOUT DEFAULT_IOCTL_RESP_TIMEOUT +#endif /* IOCTL_RESP_TIMEOUT */ + +#ifndef MFG_IOCTL_RESP_TIMEOUT +#define MFG_IOCTL_RESP_TIMEOUT 20000 /* In milli second default value for MFG FW */ +#endif /* MFG_IOCTL_RESP_TIMEOUT */ + +#define DEFAULT_D3_ACK_RESP_TIMEOUT 4000 +#ifndef D3_ACK_RESP_TIMEOUT +#define D3_ACK_RESP_TIMEOUT DEFAULT_D3_ACK_RESP_TIMEOUT +#endif /* D3_ACK_RESP_TIMEOUT */ + +/* + * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) + */ + +/* Linkage, sets prot link and updates hdrlen in pub */ +extern int dhd_prot_attach(dhd_pub_t *dhdp); + +/* Initilizes the index block for dma'ing indices */ +extern int dhd_prot_init_index_dma_block(dhd_pub_t *dhdp, uint8 type, uint32 length); + +/* Unlink, frees allocated protocol memory (including dhd_prot) */ +extern void dhd_prot_detach(dhd_pub_t *dhdp); + +/* Initialize protocol: sync w/dongle state. + * Sets dongle media info (iswl, drv_version, mac address). + */ +extern int dhd_sync_with_dongle(dhd_pub_t *dhdp); + +/* Protocol initialization needed for IOCTL/IOVAR path */ +extern int dhd_prot_init(dhd_pub_t *dhd); + +/* Stop protocol: sync w/dongle state. */ +extern void dhd_prot_stop(dhd_pub_t *dhdp); + +/* Add any protocol-specific data header. + * Caller must reserve prot_hdrlen prepend space. + */ +extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); +extern uint dhd_prot_hdrlen(dhd_pub_t *, void *txp); + +/* Remove any protocol-specific data header. */ +extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); + +/* Use protocol to issue ioctl to dongle */ +extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); + +/* Handles a protocol control response asynchronously */ +extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); + +/* Check for and handle local prot-specific iovar commands */ +extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set); + +/* Add prot dump output to a buffer */ +extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); + +/* Update local copy of dongle statistics */ +extern void dhd_prot_dstats(dhd_pub_t *dhdp); + +extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); + +extern int dhd_preinit_ioctls(dhd_pub_t *dhd); + +extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, + uint reorder_info_len, void **pkt, uint32 *free_buf_count); + +#ifdef BCMPCIE +extern bool dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound); +extern bool dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound); +extern int dhd_prot_process_ctrlbuf(dhd_pub_t * dhd); +extern bool dhd_prot_dtohsplit(dhd_pub_t * dhd); +extern int dhd_post_dummy_msg(dhd_pub_t *dhd); +extern int dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len); +extern void dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 offset); +extern int dhd_prot_txdata(dhd_pub_t *dhd, void *p, uint8 ifidx); +extern int dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd, uint len, uint srcdelay, uint destdelay); + +extern int dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); +extern void dhd_prot_clean_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info); +extern int dhd_post_tx_ring_item(dhd_pub_t *dhd, void *PKTBUF, uint8 ifindex); +extern int dhd_prot_flow_ring_delete(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); +extern int dhd_prot_flow_ring_flush(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); +extern int dhd_prot_ringupd_dump(dhd_pub_t *dhd, struct bcmstrbuf *b); +extern uint32 dhd_prot_metadatalen_set(dhd_pub_t *dhd, uint32 val, bool rx); +extern uint32 dhd_prot_metadatalen_get(dhd_pub_t *dhd, bool rx); +extern void dhd_prot_print_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info, + struct bcmstrbuf *strbuf); +extern void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf); +extern void dhd_prot_update_txflowring(dhd_pub_t *dhdp, uint16 flow_id, void *msgring_info); +extern void dhd_prot_txdata_write_flush(dhd_pub_t *dhd, uint16 flow_id, bool in_lock); +extern uint32 dhd_prot_txp_threshold(dhd_pub_t *dhd, bool set, uint32 val); +extern void dhd_prot_clear(dhd_pub_t *dhd); + +#endif /* BCMPCIE */ + +/******************************** + * For version-string expansion * + */ +#if defined(BDC) +#define DHD_PROTOCOL "bdc" +#elif defined(CDC) +#define DHD_PROTOCOL "cdc" +#else +#define DHD_PROTOCOL "unknown" +#endif /* proto */ + +#endif /* _dhd_proto_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c new file mode 100644 index 000000000000..c307875acb1f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c @@ -0,0 +1,1970 @@ +/* + * Header file of Broadcom Dongle Host Driver (DHD) + * Copyright (C) 1999-2014, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_rtt.c 423669 2014-07-01 13:01:55Z $ + */ +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#define GET_RTTSTATE(dhd) ((rtt_status_info_t *)dhd->rtt_state) +static DEFINE_SPINLOCK(noti_list_lock); +#define NULL_CHECK(p, s, err) \ + do { \ + if (!(p)) { \ + printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ + err = BCME_ERROR; \ + return err; \ + } \ + } while (0) + +#define RTT_IS_ENABLED(rtt_status) (rtt_status->status == RTT_ENABLED) +#define RTT_IS_STOPPED(rtt_status) (rtt_status->status == RTT_STOPPED) +#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ + (ts).tv_nsec / NSEC_PER_USEC) + +#define FTM_IOC_BUFSZ 2048 /* ioc buffsize for our module (> BCM_XTLV_HDR_SIZE) */ +#define FTM_AVAIL_MAX_SLOTS 32 +#define FTM_MAX_CONFIGS 10 +#define FTM_MAX_PARAMS 10 +#define FTM_DEFAULT_SESSION 1 +#define FTM_BURST_TIMEOUT_UNIT 250 /* 250 ns */ +#define FTM_INVALID -1 +#define FTM_DEFAULT_CNT_20M 12 +#define FTM_DEFAULT_CNT_40M 10 +#define FTM_DEFAULT_CNT_80M 5 + +/* convenience macros */ +#define FTM_TU2MICRO(_tu) ((uint64)(_tu) << 10) +#define FTM_MICRO2TU(_tu) ((uint64)(_tu) >> 10) +#define FTM_TU2MILLI(_tu) ((uint32)FTM_TU2MICRO(_tu) / 1000) +#define FTM_MICRO2MILLI(_x) ((uint32)(_x) / 1000) +#define FTM_MICRO2SEC(_x) ((uint32)(_x) / 1000000) +#define FTM_INTVL2NSEC(_intvl) ((uint32)ftm_intvl2nsec(_intvl)) +#define FTM_INTVL2USEC(_intvl) ((uint32)ftm_intvl2usec(_intvl)) +#define FTM_INTVL2MSEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000) +#define FTM_INTVL2SEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000000) +#define FTM_USECIN100MILLI(_usec) ((_usec) / 100000) + +/* broadcom specific set to have more accurate data */ +#define ENABLE_VHT_ACK + +struct rtt_noti_callback { + struct list_head list; + void *ctx; + dhd_rtt_compl_noti_fn noti_fn; +}; + +typedef struct rtt_status_info { + dhd_pub_t *dhd; + int8 status; /* current status for the current entry */ + int8 txchain; /* current device tx chain */ + int8 mpc; /* indicate we change mpc mode */ + int8 cur_idx; /* current entry to do RTT */ + struct capability { + int32 proto :8; + int32 feature :8; + int32 preamble :8; + int32 bw :8; + } rtt_capa; /* rtt capability */ + struct mutex rtt_mutex; + rtt_config_params_t rtt_config; + struct work_struct work; + struct list_head noti_fn_list; + struct list_head rtt_results_cache; /* store results for RTT */ +} rtt_status_info_t; + +/* bitmask indicating which command groups; */ +typedef enum { + FTM_SUBCMD_FLAG_METHOD = 0x01, /* FTM method command */ + FTM_SUBCMD_FLAG_SESSION = 0x02, /* FTM session command */ + FTM_SUBCMD_FLAG_ALL = FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION +} ftm_subcmd_flag_t; + +/* proxd ftm config-category definition */ +typedef enum { + FTM_CONFIG_CAT_GENERAL = 1, /* generial configuration */ + FTM_CONFIG_CAT_OPTIONS = 2, /* 'config options' */ + FTM_CONFIG_CAT_AVAIL = 3, /* 'config avail' */ +} ftm_config_category_t; + + +typedef struct ftm_subcmd_info { + int16 version; /* FTM version (optional) */ + char *name; /* cmd-name string as cmdline input */ + wl_proxd_cmd_t cmdid; /* cmd-id */ + bcm_xtlv_unpack_cbfn_t *handler; /* cmd response handler (optional) */ + ftm_subcmd_flag_t cmdflag; /* CMD flag (optional) */ +} ftm_subcmd_info_t; + + +typedef struct ftm_config_options_info { + uint32 flags; /* wl_proxd_flags_t/wl_proxd_session_flags_t */ + bool enable; +} ftm_config_options_info_t; + +typedef struct ftm_config_param_info { + uint16 tlvid; /* mapping TLV id for the item */ + union { + uint32 chanspec; + struct ether_addr mac_addr; + wl_proxd_intvl_t data_intvl; + uint32 data32; + uint16 data16; + uint8 data8; + }; +} ftm_config_param_info_t; + +/* +* definition for id-string mapping. +* This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string +* for debug-display or cmd-log-display +*/ +typedef struct ftm_strmap_entry { + int32 id; + char *text; +} ftm_strmap_entry_t; + + +typedef struct ftm_status_map_host_entry { + wl_proxd_status_t proxd_status; + rtt_reason_t rtt_reason; +} ftm_status_map_host_entry_t; + +static int +dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len); + +static wifi_rate_t +dhd_rtt_convert_rate_to_host(uint32 ratespec); + +static int +dhd_rtt_start(dhd_pub_t *dhd); + +/* ftm status mapping to host status */ +static const ftm_status_map_host_entry_t ftm_status_map_info[] = { + {WL_PROXD_E_INCOMPLETE, RTT_REASON_FAILURE}, + {WL_PROXD_E_OVERRIDDEN, RTT_REASON_FAILURE}, + {WL_PROXD_E_ASAP_FAILED, RTT_REASON_FAILURE}, + {WL_PROXD_E_NOTSTARTED, RTT_REASON_FAIL_NOT_SCHEDULED_YET}, + {WL_PROXD_E_INVALIDAVB, RTT_REASON_FAIL_INVALID_TS}, + {WL_PROXD_E_INCAPABLE, RTT_REASON_FAIL_NO_CAPABILITY}, + {WL_PROXD_E_MISMATCH, RTT_REASON_FAILURE}, + {WL_PROXD_E_DUP_SESSION, RTT_REASON_FAILURE}, + {WL_PROXD_E_REMOTE_FAIL, RTT_REASON_FAILURE}, + {WL_PROXD_E_REMOTE_INCAPABLE, RTT_REASON_FAILURE}, + {WL_PROXD_E_SCHED_FAIL, RTT_REASON_FAIL_SCHEDULE}, + {WL_PROXD_E_PROTO, RTT_REASON_FAIL_PROTOCOL}, + {WL_PROXD_E_EXPIRED, RTT_REASON_FAILURE}, + {WL_PROXD_E_TIMEOUT, RTT_REASON_FAIL_TM_TIMEOUT}, + {WL_PROXD_E_NOACK, RTT_REASON_FAIL_NO_RSP}, + {WL_PROXD_E_DEFERRED, RTT_REASON_FAILURE}, + {WL_PROXD_E_INVALID_SID, RTT_REASON_FAILURE}, + {WL_PROXD_E_REMOTE_CANCEL, RTT_REASON_FAILURE}, + {WL_PROXD_E_CANCELED, RTT_REASON_ABORTED}, + {WL_PROXD_E_INVALID_SESSION, RTT_REASON_FAILURE}, + {WL_PROXD_E_BAD_STATE, RTT_REASON_FAILURE}, + {WL_PROXD_E_ERROR, RTT_REASON_FAILURE}, + {WL_PROXD_E_OK, RTT_REASON_SUCCESS} +}; + +/* ftm tlv-id mapping */ +static const ftm_strmap_entry_t ftm_tlvid_loginfo[] = { + /* { WL_PROXD_TLV_ID_xxx, "text for WL_PROXD_TLV_ID_xxx" }, */ + { WL_PROXD_TLV_ID_NONE, "none" }, + { WL_PROXD_TLV_ID_METHOD, "method" }, + { WL_PROXD_TLV_ID_FLAGS, "flags" }, + { WL_PROXD_TLV_ID_CHANSPEC, "chanspec" }, + { WL_PROXD_TLV_ID_TX_POWER, "tx power" }, + { WL_PROXD_TLV_ID_RATESPEC, "ratespec" }, + { WL_PROXD_TLV_ID_BURST_DURATION, "burst duration" }, + { WL_PROXD_TLV_ID_BURST_PERIOD, "burst period" }, + { WL_PROXD_TLV_ID_BURST_FTM_SEP, "burst ftm sep" }, + { WL_PROXD_TLV_ID_BURST_NUM_FTM, "burst num ftm" }, + { WL_PROXD_TLV_ID_NUM_BURST, "num burst" }, + { WL_PROXD_TLV_ID_FTM_RETRIES, "ftm retries" }, + { WL_PROXD_TLV_ID_BSS_INDEX, "BSS index" }, + { WL_PROXD_TLV_ID_BSSID, "bssid" }, + { WL_PROXD_TLV_ID_INIT_DELAY, "burst init delay" }, + { WL_PROXD_TLV_ID_BURST_TIMEOUT, "burst timeout" }, + { WL_PROXD_TLV_ID_EVENT_MASK, "event mask" }, + { WL_PROXD_TLV_ID_FLAGS_MASK, "flags mask" }, + { WL_PROXD_TLV_ID_PEER_MAC, "peer addr" }, + { WL_PROXD_TLV_ID_FTM_REQ, "ftm req" }, + { WL_PROXD_TLV_ID_LCI_REQ, "lci req" }, + { WL_PROXD_TLV_ID_LCI, "lci" }, + { WL_PROXD_TLV_ID_CIVIC_REQ, "civic req" }, + { WL_PROXD_TLV_ID_CIVIC, "civic" }, + { WL_PROXD_TLV_ID_AVAIL, "availability" }, + { WL_PROXD_TLV_ID_SESSION_FLAGS, "session flags" }, + { WL_PROXD_TLV_ID_SESSION_FLAGS_MASK, "session flags mask" }, + { WL_PROXD_TLV_ID_RX_MAX_BURST, "rx max bursts" }, + { WL_PROXD_TLV_ID_RANGING_INFO, "ranging info" }, + { WL_PROXD_TLV_ID_RANGING_FLAGS, "ranging flags" }, + { WL_PROXD_TLV_ID_RANGING_FLAGS_MASK, "ranging flags mask" }, + /* output - 512 + x */ + { WL_PROXD_TLV_ID_STATUS, "status" }, + { WL_PROXD_TLV_ID_COUNTERS, "counters" }, + { WL_PROXD_TLV_ID_INFO, "info" }, + { WL_PROXD_TLV_ID_RTT_RESULT, "rtt result" }, + { WL_PROXD_TLV_ID_AOA_RESULT, "aoa result" }, + { WL_PROXD_TLV_ID_SESSION_INFO, "session info" }, + { WL_PROXD_TLV_ID_SESSION_STATUS, "session status" }, + { WL_PROXD_TLV_ID_SESSION_ID_LIST, "session ids" }, + /* debug tlvs can be added starting 1024 */ + { WL_PROXD_TLV_ID_DEBUG_MASK, "debug mask" }, + { WL_PROXD_TLV_ID_COLLECT, "collect" }, + { WL_PROXD_TLV_ID_STRBUF, "result" } +}; + +static const ftm_strmap_entry_t ftm_event_type_loginfo[] = { + /* wl_proxd_event_type_t, text-string */ + { WL_PROXD_EVENT_NONE, "none" }, + { WL_PROXD_EVENT_SESSION_CREATE, "session create" }, + { WL_PROXD_EVENT_SESSION_START, "session start" }, + { WL_PROXD_EVENT_FTM_REQ, "FTM req" }, + { WL_PROXD_EVENT_BURST_START, "burst start" }, + { WL_PROXD_EVENT_BURST_END, "burst end" }, + { WL_PROXD_EVENT_SESSION_END, "session end" }, + { WL_PROXD_EVENT_SESSION_RESTART, "session restart" }, + { WL_PROXD_EVENT_BURST_RESCHED, "burst rescheduled" }, + { WL_PROXD_EVENT_SESSION_DESTROY, "session destroy" }, + { WL_PROXD_EVENT_RANGE_REQ, "range request" }, + { WL_PROXD_EVENT_FTM_FRAME, "FTM frame" }, + { WL_PROXD_EVENT_DELAY, "delay" }, + { WL_PROXD_EVENT_VS_INITIATOR_RPT, "initiator-report " }, /* rx initiator-rpt */ + { WL_PROXD_EVENT_RANGING, "ranging " }, +}; + +/* +* session-state --> text string mapping +*/ +static const ftm_strmap_entry_t ftm_session_state_value_loginfo[] = { + /* wl_proxd_session_state_t, text string */ + { WL_PROXD_SESSION_STATE_CREATED, "created" }, + { WL_PROXD_SESSION_STATE_CONFIGURED, "configured" }, + { WL_PROXD_SESSION_STATE_STARTED, "started" }, + { WL_PROXD_SESSION_STATE_DELAY, "delay" }, + { WL_PROXD_SESSION_STATE_USER_WAIT, "user-wait" }, + { WL_PROXD_SESSION_STATE_SCHED_WAIT, "sched-wait" }, + { WL_PROXD_SESSION_STATE_BURST, "burst" }, + { WL_PROXD_SESSION_STATE_STOPPING, "stopping" }, + { WL_PROXD_SESSION_STATE_ENDED, "ended" }, + { WL_PROXD_SESSION_STATE_DESTROYING, "destroying" }, + { WL_PROXD_SESSION_STATE_NONE, "none" } +}; + +/* +* ranging-state --> text string mapping +*/ +static const ftm_strmap_entry_t ftm_ranging_state_value_loginfo [] = { + /* wl_proxd_ranging_state_t, text string */ + { WL_PROXD_RANGING_STATE_NONE, "none" }, + { WL_PROXD_RANGING_STATE_NOTSTARTED, "nonstarted" }, + { WL_PROXD_RANGING_STATE_INPROGRESS, "inprogress" }, + { WL_PROXD_RANGING_STATE_DONE, "done" }, +}; + +/* +* status --> text string mapping +*/ +static const ftm_strmap_entry_t ftm_status_value_loginfo[] = { + /* wl_proxd_status_t, text-string */ + { WL_PROXD_E_OVERRIDDEN, "overridden" }, + { WL_PROXD_E_ASAP_FAILED, "ASAP failed" }, + { WL_PROXD_E_NOTSTARTED, "not started" }, + { WL_PROXD_E_INVALIDAVB, "invalid AVB" }, + { WL_PROXD_E_INCAPABLE, "incapable" }, + { WL_PROXD_E_MISMATCH, "mismatch"}, + { WL_PROXD_E_DUP_SESSION, "dup session" }, + { WL_PROXD_E_REMOTE_FAIL, "remote fail" }, + { WL_PROXD_E_REMOTE_INCAPABLE, "remote incapable" }, + { WL_PROXD_E_SCHED_FAIL, "sched failure" }, + { WL_PROXD_E_PROTO, "protocol error" }, + { WL_PROXD_E_EXPIRED, "expired" }, + { WL_PROXD_E_TIMEOUT, "timeout" }, + { WL_PROXD_E_NOACK, "no ack" }, + { WL_PROXD_E_DEFERRED, "deferred" }, + { WL_PROXD_E_INVALID_SID, "invalid session id" }, + { WL_PROXD_E_REMOTE_CANCEL, "remote cancel" }, + { WL_PROXD_E_CANCELED, "canceled" }, + { WL_PROXD_E_INVALID_SESSION, "invalid session" }, + { WL_PROXD_E_BAD_STATE, "bad state" }, + { WL_PROXD_E_ERROR, "error" }, + { WL_PROXD_E_OK, "OK" } +}; + +/* +* time interval unit --> text string mapping +*/ +static const ftm_strmap_entry_t ftm_tmu_value_loginfo[] = { + /* wl_proxd_tmu_t, text-string */ + { WL_PROXD_TMU_TU, "TU" }, + { WL_PROXD_TMU_SEC, "sec" }, + { WL_PROXD_TMU_MILLI_SEC, "ms" }, + { WL_PROXD_TMU_MICRO_SEC, "us" }, + { WL_PROXD_TMU_NANO_SEC, "ns" }, + { WL_PROXD_TMU_PICO_SEC, "ps" } +}; + +#define RSPEC_BW(rspec) ((rspec) & WL_RSPEC_BW_MASK) +#define RSPEC_IS20MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_20MHZ) +#define RSPEC_IS40MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_40MHZ) +#define RSPEC_IS80MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_80MHZ) +#define RSPEC_IS160MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_160MHZ) + +#define IS_MCS(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) != WL_RSPEC_ENCODE_RATE) +#define IS_STBC(rspec) (((((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) || \ + (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)) && \ + (((rspec) & WL_RSPEC_STBC) == WL_RSPEC_STBC)) +#define RSPEC_ISSGI(rspec) (((rspec) & WL_RSPEC_SGI) != 0) +#define RSPEC_ISLDPC(rspec) (((rspec) & WL_RSPEC_LDPC) != 0) +#define RSPEC_ISSTBC(rspec) (((rspec) & WL_RSPEC_STBC) != 0) +#define RSPEC_ISTXBF(rspec) (((rspec) & WL_RSPEC_TXBF) != 0) +#define RSPEC_ISVHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) +#define RSPEC_ISHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) +#define RSPEC_ISLEGACY(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) +#define RSPEC2RATE(rspec) (RSPEC_ISLEGACY(rspec) ? \ + ((rspec) & RSPEC_RATE_MASK) : rate_rspec2rate(rspec)) +/* return rate in unit of 500Kbps -- for internal use in wlc_rate_sel.c */ +#define RSPEC2KBPS(rspec) rate_rspec2rate(rspec) + +struct ieee_80211_mcs_rate_info { + uint8 constellation_bits; + uint8 coding_q; + uint8 coding_d; +}; + +static const struct ieee_80211_mcs_rate_info wl_mcs_info[] = { + { 1, 1, 2 }, /* MCS 0: MOD: BPSK, CR 1/2 */ + { 2, 1, 2 }, /* MCS 1: MOD: QPSK, CR 1/2 */ + { 2, 3, 4 }, /* MCS 2: MOD: QPSK, CR 3/4 */ + { 4, 1, 2 }, /* MCS 3: MOD: 16QAM, CR 1/2 */ + { 4, 3, 4 }, /* MCS 4: MOD: 16QAM, CR 3/4 */ + { 6, 2, 3 }, /* MCS 5: MOD: 64QAM, CR 2/3 */ + { 6, 3, 4 }, /* MCS 6: MOD: 64QAM, CR 3/4 */ + { 6, 5, 6 }, /* MCS 7: MOD: 64QAM, CR 5/6 */ + { 8, 3, 4 }, /* MCS 8: MOD: 256QAM, CR 3/4 */ + { 8, 5, 6 } /* MCS 9: MOD: 256QAM, CR 5/6 */ +}; + +/** + * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination. + * 'mcs' : a *single* spatial stream MCS (11n or 11ac) + */ +uint +rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) +{ + const int ksps = 250; /* kilo symbols per sec, 4 us sym */ + const int Nsd_20MHz = 52; + const int Nsd_40MHz = 108; + const int Nsd_80MHz = 234; + const int Nsd_160MHz = 468; + uint rate; + + if (mcs == 32) { + /* just return fixed values for mcs32 instead of trying to parametrize */ + rate = (sgi == 0) ? 6000 : 6778; + } else if (mcs <= 9) { + /* This calculation works for 11n HT and 11ac VHT if the HT mcs values + * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. + * That is, HT MCS 23 is a base MCS = 7, Nss = 3 + */ + + /* find the number of complex numbers per symbol */ + if (RSPEC_IS20MHZ(bw)) { + rate = Nsd_20MHz; + } else if (RSPEC_IS40MHZ(bw)) { + rate = Nsd_40MHz; + } else if (bw == WL_RSPEC_BW_80MHZ) { + rate = Nsd_80MHz; + } else if (bw == WL_RSPEC_BW_160MHZ) { + rate = Nsd_160MHz; + } else { + rate = 0; + } + + /* multiply by bits per number from the constellation in use */ + rate = rate * wl_mcs_info[mcs].constellation_bits; + + /* adjust for the number of spatial streams */ + rate = rate * nss; + + /* adjust for the coding rate given as a quotient and divisor */ + rate = (rate * wl_mcs_info[mcs].coding_q) / wl_mcs_info[mcs].coding_d; + + /* multiply by Kilo symbols per sec to get Kbps */ + rate = rate * ksps; + + /* adjust the symbols per sec for SGI + * symbol duration is 4 us without SGI, and 3.6 us with SGI, + * so ratio is 10 / 9 + */ + if (sgi) { + /* add 4 for rounding of division by 9 */ + rate = ((rate * 10) + 4) / 9; + } + } else { + rate = 0; + } + + return rate; +} /* wlc_rate_mcs2rate */ + +/** take a well formed ratespec_t arg and return phy rate in [Kbps] units */ +int +rate_rspec2rate(uint32 rspec) +{ + int rate = -1; + + if (RSPEC_ISLEGACY(rspec)) { + rate = 500 * (rspec & WL_RSPEC_RATE_MASK); + } else if (RSPEC_ISHT(rspec)) { + uint mcs = (rspec & WL_RSPEC_RATE_MASK); + + if (mcs == 32) { + rate = rate_mcs2rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec)); + } else { + uint nss = 1 + (mcs / 8); + mcs = mcs % 8; + rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); + } + } else if (RSPEC_ISVHT(rspec)) { + uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK); + uint nss = (rspec & WL_RSPEC_VHT_MCS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; + + ASSERT(mcs <= 9); + ASSERT(nss <= 8); + + rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); + } else { + ASSERT(0); + } + + return (rate == 0) ? -1 : rate; +} + +char resp_buf[WLC_IOCTL_SMLEN]; + +static uint64 +ftm_intvl2nsec(const wl_proxd_intvl_t *intvl) +{ + uint64 ret; + ret = intvl->intvl; + switch (intvl->tmu) { + case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret) * 1000; break; + case WL_PROXD_TMU_SEC: ret *= 1000000000; break; + case WL_PROXD_TMU_MILLI_SEC: ret *= 1000000; break; + case WL_PROXD_TMU_MICRO_SEC: ret *= 1000; break; + case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000; break; + case WL_PROXD_TMU_NANO_SEC: /* fall through */ + default: break; + } + return ret; +} +uint64 +ftm_intvl2usec(const wl_proxd_intvl_t *intvl) +{ + uint64 ret; + ret = intvl->intvl; + switch (intvl->tmu) { + case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret); break; + case WL_PROXD_TMU_SEC: ret *= 1000000; break; + case WL_PROXD_TMU_NANO_SEC: ret = intvl->intvl / 1000; break; + case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000000; break; + case WL_PROXD_TMU_MILLI_SEC: ret *= 1000; break; + case WL_PROXD_TMU_MICRO_SEC: /* fall through */ + default: break; + } + return ret; +} + +/* +* lookup 'id' (as a key) from a fw status to host map table +* if found, return the corresponding reason code +*/ + +static rtt_reason_t +ftm_get_statusmap_info(wl_proxd_status_t id, const ftm_status_map_host_entry_t *p_table, + uint32 num_entries) +{ + int i; + const ftm_status_map_host_entry_t *p_entry; + /* scan thru the table till end */ + p_entry = p_table; + for (i = 0; i < (int) num_entries; i++) + { + if (p_entry->proxd_status == id) { + return p_entry->rtt_reason; + } + p_entry++; /* next entry */ + } + return RTT_REASON_FAILURE; /* not found */ +} +/* +* lookup 'id' (as a key) from a table +* if found, return the entry pointer, otherwise return NULL +*/ +static const ftm_strmap_entry_t* +ftm_get_strmap_info(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) +{ + int i; + const ftm_strmap_entry_t *p_entry; + + /* scan thru the table till end */ + p_entry = p_table; + for (i = 0; i < (int) num_entries; i++) + { + if (p_entry->id == id) + return p_entry; + p_entry++; /* next entry */ + } + return NULL; /* not found */ +} + +/* +* map enum to a text-string for display, this function is called by the following: +* For debug/trace: +* ftm_[cmdid|tlvid]_to_str() +* For TLV-output log for 'get' commands +* ftm_[method|tmu|caps|status|state]_value_to_logstr() +* Input: +* pTable -- point to a 'enum to string' table. +*/ +static const char * +ftm_map_id_to_str(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) +{ + const ftm_strmap_entry_t*p_entry = ftm_get_strmap_info(id, p_table, num_entries); + if (p_entry) + return (p_entry->text); + + return "invalid"; +} + + +#ifdef RTT_DEBUG + +/* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */ +#define DEF_STRMAP_ENTRY(id) { (id), #id } + +/* ftm cmd-id mapping */ +static const ftm_strmap_entry_t ftm_cmdid_map[] = { + /* {wl_proxd_cmd_t(WL_PROXD_CMD_xxx), "WL_PROXD_CMD_xxx" }, */ + DEF_STRMAP_ENTRY(WL_PROXD_CMD_NONE), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_VERSION), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_ENABLE), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_DISABLE), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_CONFIG), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_SESSION), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_BURST_REQUEST), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_SESSION), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_DELETE_SESSION), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RESULT), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_INFO), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_STATUS), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_SESSIONS), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_COUNTERS), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_CLEAR_COUNTERS), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_COLLECT), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_TUNE), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_DUMP), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_RANGING), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_RANGING), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RANGING_INFO), +}; + +/* +* map a ftm cmd-id to a text-string for display +*/ +static const char * +ftm_cmdid_to_str(uint16 cmdid) +{ + return ftm_map_id_to_str((int32) cmdid, &ftm_cmdid_map[0], ARRAYSIZE(ftm_cmdid_map)); +} +#endif /* RTT_DEBUG */ + + +/* +* convert BCME_xxx error codes into related error strings +* note, bcmerrorstr() defined in bcmutils is for BCMDRIVER only, +* this duplicate copy is for WL access and may need to clean up later +*/ +static const char *ftm_bcmerrorstrtable[] = BCMERRSTRINGTABLE; +static const char * +ftm_status_value_to_logstr(wl_proxd_status_t status) +{ + static char ftm_msgbuf_status_undef[32]; + const ftm_strmap_entry_t *p_loginfo; + int bcmerror; + + /* check if within BCME_xxx error range */ + bcmerror = (int) status; + if (VALID_BCMERROR(bcmerror)) + return ftm_bcmerrorstrtable[-bcmerror]; + + /* otherwise, look for 'proxd ftm status' range */ + p_loginfo = ftm_get_strmap_info((int32) status, + &ftm_status_value_loginfo[0], ARRAYSIZE(ftm_status_value_loginfo)); + if (p_loginfo) + return p_loginfo->text; + + /* report for 'out of range' FTM-status error code */ + memset(ftm_msgbuf_status_undef, 0, sizeof(ftm_msgbuf_status_undef)); + snprintf(ftm_msgbuf_status_undef, sizeof(ftm_msgbuf_status_undef), + "Undefined status %d", status); + return &ftm_msgbuf_status_undef[0]; +} + +static const char * +ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu) +{ + return ftm_map_id_to_str((int32)tmu, + &ftm_tmu_value_loginfo[0], ARRAYSIZE(ftm_tmu_value_loginfo)); +} + +static const ftm_strmap_entry_t* +ftm_get_event_type_loginfo(wl_proxd_event_type_t event_type) +{ + /* look up 'event-type' from a predefined table */ + return ftm_get_strmap_info((int32) event_type, + ftm_event_type_loginfo, ARRAYSIZE(ftm_event_type_loginfo)); +} + +static const char * +ftm_session_state_value_to_logstr(wl_proxd_session_state_t state) +{ + return ftm_map_id_to_str((int32)state, &ftm_session_state_value_loginfo[0], + ARRAYSIZE(ftm_session_state_value_loginfo)); +} + + +/* +* send 'proxd' iovar for all ftm get-related commands +*/ +static int +rtt_do_get_ioctl(dhd_pub_t *dhd, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize, + ftm_subcmd_info_t *p_subcmd_info) +{ + + wl_proxd_iov_t *p_iovresp = (wl_proxd_iov_t *)resp_buf; + int status; + int tlvs_len; + /* send getbuf proxd iovar */ + status = dhd_getiovar(dhd, 0, "proxd", (char *)p_proxd_iov, + proxd_iovsize, (char **)&p_iovresp, WLC_IOCTL_SMLEN); + if (status != BCME_OK) { + DHD_ERROR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n", + __FUNCTION__, p_subcmd_info->cmdid, status)); + return status; + } + if (p_subcmd_info->cmdid == WL_PROXD_CMD_GET_VERSION) { + p_subcmd_info->version = ltoh16(p_iovresp->version); + DHD_RTT(("ftm version: 0x%x\n", ltoh16(p_iovresp->version))); + goto exit; + } + + tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE; + if (tlvs_len < 0) { + DHD_ERROR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n", + __FUNCTION__, ltoh16(p_iovresp->len), (int) WL_PROXD_IOV_HDR_SIZE)); + tlvs_len = 0; + } + + if (tlvs_len > 0 && p_subcmd_info->handler) { + /* unpack TLVs and invokes the cbfn for processing */ + status = bcm_unpack_xtlv_buf(p_proxd_iov, (uint8 *)p_iovresp->tlvs, + tlvs_len, BCM_XTLV_OPTION_ALIGN32, p_subcmd_info->handler); + } +exit: + return status; +} + + +static wl_proxd_iov_t * +rtt_alloc_getset_buf(wl_proxd_method_t method, wl_proxd_session_id_t session_id, + wl_proxd_cmd_t cmdid, uint16 tlvs_bufsize, uint16 *p_out_bufsize) +{ + uint16 proxd_iovsize; + uint16 kflags; + wl_proxd_tlv_t *p_tlv; + wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) NULL; + + *p_out_bufsize = 0; /* init */ + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + /* calculate the whole buffer size, including one reserve-tlv entry in the header */ + proxd_iovsize = sizeof(wl_proxd_iov_t) + tlvs_bufsize; + + p_proxd_iov = kzalloc(proxd_iovsize, kflags); + if (p_proxd_iov == NULL) { + DHD_ERROR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize)); + return NULL; + } + + /* setup proxd-FTM-method iovar header */ + p_proxd_iov->version = htol16(WL_PROXD_API_VERSION); + p_proxd_iov->len = htol16(proxd_iovsize); /* caller may adjust it based on #of TLVs */ + p_proxd_iov->cmd = htol16(cmdid); + p_proxd_iov->method = htol16(method); + p_proxd_iov->sid = htol16(session_id); + + /* initialize the reserved/dummy-TLV in iovar header */ + p_tlv = p_proxd_iov->tlvs; + p_tlv->id = htol16(WL_PROXD_TLV_ID_NONE); + p_tlv->len = htol16(0); + + *p_out_bufsize = proxd_iovsize; /* for caller's reference */ + + return p_proxd_iov; +} + + +static int +dhd_rtt_common_get_handler(dhd_pub_t *dhd, ftm_subcmd_info_t *p_subcmd_info, + wl_proxd_method_t method, wl_proxd_session_id_t session_id) +{ + int status = BCME_OK; + uint16 proxd_iovsize = 0; + wl_proxd_iov_t *p_proxd_iov; +#ifdef RTT_DEBUG + DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", + __FUNCTION__, method, session_id, p_subcmd_info->cmdid, + ftm_cmdid_to_str(p_subcmd_info->cmdid))); +#endif + /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ + p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, + 0, &proxd_iovsize); + + if (p_proxd_iov == NULL) + return BCME_NOMEM; + + status = rtt_do_get_ioctl(dhd, p_proxd_iov, proxd_iovsize, p_subcmd_info); + + if (status != BCME_OK) { + DHD_RTT(("%s failed: status=%d\n", __FUNCTION__, status)); + } + kfree(p_proxd_iov); + return status; +} + +/* +* common handler for set-related proxd method commands which require no TLV as input +* wl proxd ftm [session-id] +* e.g. +* wl proxd ftm enable -- to enable ftm +* wl proxd ftm disable -- to disable ftm +* wl proxd ftm start -- to start a specified session +* wl proxd ftm stop -- to cancel a specified session; +* state is maintained till session is delete. +* wl proxd ftm delete -- to delete a specified session +* wl proxd ftm [] clear-counters -- to clear counters +* wl proxd ftm burst-request -- on initiator: to send burst request; +* on target: send FTM frame +* wl proxd ftm collect +* wl proxd ftm tune (TBD) +*/ +static int +dhd_rtt_common_set_handler(dhd_pub_t *dhd, const ftm_subcmd_info_t *p_subcmd_info, + wl_proxd_method_t method, wl_proxd_session_id_t session_id) +{ + uint16 proxd_iovsize; + wl_proxd_iov_t *p_proxd_iov; + int ret; + +#ifdef RTT_DEBUG + DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", + __FUNCTION__, method, session_id, p_subcmd_info->cmdid, + ftm_cmdid_to_str(p_subcmd_info->cmdid))); +#endif + + /* allocate and initialize a temp buffer for 'set proxd' iovar */ + proxd_iovsize = 0; + p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, + 0, &proxd_iovsize); /* no TLV */ + if (p_proxd_iov == NULL) + return BCME_NOMEM; + + /* no TLV to pack, simply issue a set-proxd iovar */ + ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, proxd_iovsize, NULL, 0, TRUE); +#ifdef RTT_DEBUG + if (ret != BCME_OK) { + DHD_RTT(("error: IOVAR failed, status=%d\n", ret)); + } +#endif + /* clean up */ + kfree(p_proxd_iov); + + return ret; +} + +static int +rtt_unpack_xtlv_cbfn(void *ctx, uint8 *p_data, uint16 tlvid, uint16 len) +{ + int ret = BCME_OK; + wl_proxd_ftm_session_status_t *p_data_info; + switch (tlvid) { + case WL_PROXD_TLV_ID_RTT_RESULT: + ret = dhd_rtt_convert_results_to_host((rtt_report_t *)ctx, + p_data, tlvid, len); + break; + case WL_PROXD_TLV_ID_SESSION_STATUS: + memcpy(ctx, p_data, sizeof(wl_proxd_ftm_session_status_t)); + p_data_info = (wl_proxd_ftm_session_status_t *)ctx; + p_data_info->state = ltoh16_ua(&p_data_info->state); + p_data_info->status = ltoh32_ua(&p_data_info->status); + break; + default: + DHD_ERROR(("> Unsupported TLV ID %d\n", tlvid)); + ret = BCME_ERROR; + break; + } + + return ret; +} +static int +rtt_handle_config_options(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, + uint16 *p_buf_space_left, ftm_config_options_info_t *ftm_configs, int ftm_cfg_cnt) +{ + int ret = BCME_OK; + int cfg_idx = 0; + uint32 flags = WL_PROXD_FLAG_NONE; + uint32 flags_mask = WL_PROXD_FLAG_NONE; + uint32 new_mask; /* cmdline input */ + ftm_config_options_info_t *p_option_info; + uint16 type = (session_id == WL_PROXD_SESSION_ID_GLOBAL) ? + WL_PROXD_TLV_ID_FLAGS_MASK : WL_PROXD_TLV_ID_SESSION_FLAGS_MASK; + for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { + p_option_info = (ftm_configs + cfg_idx); + if (p_option_info != NULL) { + new_mask = p_option_info->flags; + /* update flags mask */ + flags_mask |= new_mask; + if (p_option_info->enable) { + flags |= new_mask; /* set the bit on */ + } else { + flags &= ~new_mask; /* set the bit off */ + } + } + } + flags = htol32(flags); + flags_mask = htol32(flags_mask); + /* setup flags_mask TLV */ + ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, + type, sizeof(uint32), &flags_mask, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + DHD_ERROR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n", + __FUNCTION__, ret)); + goto exit; + } + + type = (session_id == WL_PROXD_SESSION_ID_GLOBAL)? + WL_PROXD_TLV_ID_FLAGS : WL_PROXD_TLV_ID_SESSION_FLAGS; + /* setup flags TLV */ + ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, + type, sizeof(uint32), &flags, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { +#ifdef RTT_DEBUG + DHD_RTT(("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n", + __FUNCTION__, ret)); +#endif + } +exit: + return ret; +} + +static int +rtt_handle_config_general(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, + uint16 *p_buf_space_left, ftm_config_param_info_t *ftm_configs, int ftm_cfg_cnt) +{ + int ret = BCME_OK; + int cfg_idx = 0; + uint32 chanspec; + ftm_config_param_info_t *p_config_param_info; + void *p_src_data; + uint16 src_data_size; /* size of data pointed by p_src_data as 'source' */ + for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { + p_config_param_info = (ftm_configs + cfg_idx); + if (p_config_param_info != NULL) { + switch (p_config_param_info->tlvid) { + case WL_PROXD_TLV_ID_BSS_INDEX: + p_src_data = &p_config_param_info->data8; + src_data_size = sizeof(uint8); + break; + case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* uint16 */ + case WL_PROXD_TLV_ID_NUM_BURST: + case WL_PROXD_TLV_ID_FTM_RETRIES: + case WL_PROXD_TLV_ID_RX_MAX_BURST: + case WL_PROXD_TLV_ID_FTM_REQ_RETRIES: + p_src_data = &p_config_param_info->data16; + src_data_size = sizeof(uint16); + break; + case WL_PROXD_TLV_ID_TX_POWER: /* uint32 */ + case WL_PROXD_TLV_ID_RATESPEC: + case WL_PROXD_TLV_ID_EVENT_MASK: /* wl_proxd_event_mask_t/uint32 */ + case WL_PROXD_TLV_ID_DEBUG_MASK: + p_src_data = &p_config_param_info->data32; + src_data_size = sizeof(uint32); + break; + case WL_PROXD_TLV_ID_CHANSPEC: /* chanspec_t --> 32bit */ + chanspec = p_config_param_info->chanspec; + p_src_data = (void *) &chanspec; + src_data_size = sizeof(uint32); + break; + case WL_PROXD_TLV_ID_BSSID: /* mac address */ + case WL_PROXD_TLV_ID_PEER_MAC: + p_src_data = &p_config_param_info->mac_addr; + src_data_size = sizeof(struct ether_addr); + break; + case WL_PROXD_TLV_ID_BURST_DURATION: /* wl_proxd_intvl_t */ + case WL_PROXD_TLV_ID_BURST_PERIOD: + case WL_PROXD_TLV_ID_BURST_FTM_SEP: + case WL_PROXD_TLV_ID_BURST_TIMEOUT: + case WL_PROXD_TLV_ID_INIT_DELAY: + p_src_data = &p_config_param_info->data_intvl; + src_data_size = sizeof(wl_proxd_intvl_t); + break; + default: + ret = BCME_BADARG; + break; + } + if (ret != BCME_OK) { + DHD_ERROR(("%s bad TLV ID : %d\n", + __FUNCTION__, p_config_param_info->tlvid)); + break; + } + + ret = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left, + p_config_param_info->tlvid, src_data_size, p_src_data, + BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + DHD_ERROR(("%s: bcm_pack_xltv_entry() failed," + " status=%d\n", __FUNCTION__, ret)); + break; + } + + } + } + return ret; +} + +static int +dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version) +{ + int ret; + ftm_subcmd_info_t subcmd_info; + subcmd_info.name = "ver"; + subcmd_info.cmdid = WL_PROXD_CMD_GET_VERSION; + subcmd_info.handler = NULL; + ret = dhd_rtt_common_get_handler(dhd, &subcmd_info, + WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); + *out_version = (ret == BCME_OK) ? subcmd_info.version : 0; + return ret; +} + +static int +dhd_rtt_ftm_enable(dhd_pub_t *dhd, bool enable) +{ + ftm_subcmd_info_t subcmd_info; + subcmd_info.name = (enable)? "enable" : "disable"; + subcmd_info.cmdid = (enable)? WL_PROXD_CMD_ENABLE: WL_PROXD_CMD_DISABLE; + subcmd_info.handler = NULL; + return dhd_rtt_common_set_handler(dhd, &subcmd_info, + WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); +} + +static int +dhd_rtt_start_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, bool start) +{ + ftm_subcmd_info_t subcmd_info; + subcmd_info.name = (start)? "start session" : "stop session"; + subcmd_info.cmdid = (start)? WL_PROXD_CMD_START_SESSION: WL_PROXD_CMD_STOP_SESSION; + subcmd_info.handler = NULL; + return dhd_rtt_common_set_handler(dhd, &subcmd_info, + WL_PROXD_METHOD_FTM, session_id); +} + +static int +dhd_rtt_delete_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id) +{ + ftm_subcmd_info_t subcmd_info; + subcmd_info.name = "delete session"; + subcmd_info.cmdid = WL_PROXD_CMD_DELETE_SESSION; + subcmd_info.handler = NULL; + return dhd_rtt_common_set_handler(dhd, &subcmd_info, + WL_PROXD_METHOD_FTM, session_id); +} + +static int +dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, + ftm_config_category_t catagory, void *ftm_configs, int ftm_cfg_cnt) +{ + ftm_subcmd_info_t subcmd_info; + wl_proxd_tlv_t *p_tlv; + /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ + wl_proxd_iov_t *p_proxd_iov; + uint16 proxd_iovsize = 0; + uint16 bufsize; + uint16 buf_space_left; + uint16 all_tlvsize; + int ret = BCME_OK; + + subcmd_info.name = "config"; + subcmd_info.cmdid = WL_PROXD_CMD_CONFIG; + + p_proxd_iov = rtt_alloc_getset_buf(WL_PROXD_METHOD_FTM, session_id, subcmd_info.cmdid, + FTM_IOC_BUFSZ, &proxd_iovsize); + + if (p_proxd_iov == NULL) { + DHD_ERROR(("%s : failed to allocate the iovar (size :%d)\n", + __FUNCTION__, FTM_IOC_BUFSZ)); + return BCME_NOMEM; + } + /* setup TLVs */ + bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */ + p_tlv = &p_proxd_iov->tlvs[0]; + /* TLV buffer starts with a full size, will decrement for each packed TLV */ + buf_space_left = bufsize; + if (catagory == FTM_CONFIG_CAT_OPTIONS) { + ret = rtt_handle_config_options(session_id, &p_tlv, &buf_space_left, + (ftm_config_options_info_t *)ftm_configs, ftm_cfg_cnt); + } else if (catagory == FTM_CONFIG_CAT_GENERAL) { + ret = rtt_handle_config_general(session_id, &p_tlv, &buf_space_left, + (ftm_config_param_info_t *)ftm_configs, ftm_cfg_cnt); + } + if (ret == BCME_OK) { + /* update the iov header, set len to include all TLVs + header */ + all_tlvsize = (bufsize - buf_space_left); + p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE); + ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, + all_tlvsize + WL_PROXD_IOV_HDR_SIZE, NULL, 0, TRUE); + if (ret != BCME_OK) { + DHD_ERROR(("%s : failed to set config\n", __FUNCTION__)); + } + } + /* clean up */ + kfree(p_proxd_iov); + return ret; +} + +chanspec_t +dhd_rtt_convert_to_chspec(wifi_channel_info_t channel) +{ + int bw; + chanspec_t chanspec = 0; + uint8 center_chan; + uint8 primary_chan; + /* set witdh to 20MHZ for 2.4G HZ */ + if (channel.center_freq >= 2400 && channel.center_freq <= 2500) { + channel.width = WIFI_CHAN_WIDTH_20; + } + switch (channel.width) { + case WIFI_CHAN_WIDTH_20: + bw = WL_CHANSPEC_BW_20; + primary_chan = wf_mhz2channel(channel.center_freq, 0); + chanspec = wf_channel2chspec(primary_chan, bw); + break; + case WIFI_CHAN_WIDTH_40: + bw = WL_CHANSPEC_BW_40; + primary_chan = wf_mhz2channel(channel.center_freq, 0); + chanspec = wf_channel2chspec(primary_chan, bw); + break; + case WIFI_CHAN_WIDTH_80: + bw = WL_CHANSPEC_BW_80; + primary_chan = wf_mhz2channel(channel.center_freq, 0); + center_chan = wf_mhz2channel(channel.center_freq0, 0); + chanspec = wf_chspec_80(center_chan, primary_chan); + break; + default: + DHD_ERROR(("doesn't support this bandwith : %d", channel.width)); + bw = -1; + break; + } + return chanspec; +} + +int +dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params) +{ + int err = BCME_OK; + int idx; + rtt_status_info_t *rtt_status; + NULL_CHECK(params, "params is NULL", err); + + NULL_CHECK(dhd, "dhd is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + if (!HAS_11MC_CAP(rtt_status->rtt_capa.proto)) { + DHD_ERROR(("doesn't support RTT \n")); + return BCME_ERROR; + } + if (rtt_status->status != RTT_STOPPED) { + DHD_ERROR(("rtt is already started\n")); + return BCME_BUSY; + } + DHD_RTT(("%s enter\n", __FUNCTION__)); + + memset(rtt_status->rtt_config.target_info, 0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); + rtt_status->rtt_config.rtt_target_cnt = params->rtt_target_cnt; + memcpy(rtt_status->rtt_config.target_info, + params->target_info, TARGET_INFO_SIZE(params->rtt_target_cnt)); + rtt_status->status = RTT_STARTED; + /* start to measure RTT from first device */ + /* find next target to trigger RTT */ + for (idx = rtt_status->cur_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { + /* skip the disabled device */ + if (rtt_status->rtt_config.target_info[idx].disable) { + continue; + } else { + /* set the idx to cur_idx */ + rtt_status->cur_idx = idx; + break; + } + } + if (idx < rtt_status->rtt_config.rtt_target_cnt) { + DHD_RTT(("rtt_status->cur_idx : %d\n", rtt_status->cur_idx)); + schedule_work(&rtt_status->work); + } + return err; +} + +int +dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt) +{ + int err = BCME_OK; + int i = 0, j = 0; + rtt_status_info_t *rtt_status; + + NULL_CHECK(dhd, "dhd is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + if (rtt_status->status == RTT_STOPPED) { + DHD_ERROR(("rtt is not started\n")); + return BCME_OK; + } + DHD_RTT(("%s enter\n", __FUNCTION__)); + mutex_lock(&rtt_status->rtt_mutex); + for (i = 0; i < mac_cnt; i++) { + for (j = 0; j < rtt_status->rtt_config.rtt_target_cnt; j++) { + if (!bcmp(&mac_list[i], &rtt_status->rtt_config.target_info[j].addr, + ETHER_ADDR_LEN)) { + rtt_status->rtt_config.target_info[j].disable = TRUE; + } + } + } + mutex_unlock(&rtt_status->rtt_mutex); + return err; +} + +/* custom tune function to have more accuracy */ +static int +dhd_rtt_custom_tune(dhd_pub_t *dhd, bool enable) +{ + int ret = BCME_OK; + uint32 ant_val; + rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd); + + /* Select Antenna */ + if (enable) { + /* read current Antenna value */ + ret = dhd_iovar(dhd, 0, "txchain", (char *)&ant_val, + sizeof(uint32), 0); + if (ret < 0) { + DHD_ERROR(("%s: failed to get txchain, ret=%d\n", + __FUNCTION__, ret)); + goto exit; + } + rtt_status->txchain = ltoh32(ant_val); + /* set 1 for tx chain */ + ant_val = 1; + } else { + /* restore the original value of tx chain */ + ant_val = rtt_status->txchain; + if (ant_val == 0) goto exit; + rtt_status->txchain = 0; + } + ant_val = htol32(ant_val); + ret = dhd_iovar(dhd, 0, "txchain", (char *)&ant_val, + sizeof(uint32), 1); + if (ret < 0) { + DHD_ERROR(("%s: failed to set txchain, ret=%d\n", __FUNCTION__, ret)); + } +#ifdef ENABLE_VHT_ACK + { + int16 vht = 1; + wl_proxd_params_iovar_t proxd_tune; + /* read the current tune params */ + memset(&proxd_tune, 0, sizeof(wl_proxd_params_iovar_t)); + ret = dhd_iovar(dhd, 0, "proxd_tune", (char *)&proxd_tune, + sizeof(wl_proxd_params_iovar_t), 0); + if (ret < 0) { + DHD_ERROR(("%s : failed to get proxd_tune %d\n", __FUNCTION__, ret)); + goto exit; + } + /* set VHT ACK in current tune param */ + proxd_tune.u.tof_tune.force_K = 0; + proxd_tune.u.tof_tune.vhtack = htol16(vht); + proxd_tune.method = htol16(PROXD_TOF_METHOD); + ret = dhd_iovar(dhd, 0, "proxd_tune", (char *)&proxd_tune, + sizeof(wl_proxd_params_iovar_t), 1); + if (ret < 0) { + DHD_ERROR(("%s : failed to set proxd_tune %d\n", __FUNCTION__, ret)); + } + } +#endif /* ENABLE_VHT_ACK */ +exit: + return ret; +} +static int +dhd_rtt_start(dhd_pub_t *dhd) +{ + int err = BCME_OK; + char eabuf[ETHER_ADDR_STR_LEN]; + char chanbuf[CHANSPEC_STR_LEN]; + int mpc = 0; + int ftm_cfg_cnt = 0; + int ftm_param_cnt = 0; + ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS]; + ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS]; + rtt_target_info_t *rtt_target; + rtt_status_info_t *rtt_status; + NULL_CHECK(dhd, "dhd is NULL", err); + + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + + if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) { + err = BCME_RANGE; + DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx)); + goto exit; + } + /* turn off mpc in case of non-associted */ + if (!dhd_is_associated(dhd, NULL, NULL)) { + err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); + if (err) { + DHD_ERROR(("%s : failed to set mpc\n", __FUNCTION__)); + goto exit; + } + rtt_status->mpc = 1; /* Either failure or complete, we need to enable mpc */ + } + + mutex_lock(&rtt_status->rtt_mutex); + /* Get a target information */ + rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; + mutex_unlock(&rtt_status->rtt_mutex); + DHD_RTT(("%s enter\n", __FUNCTION__)); + if (!RTT_IS_ENABLED(rtt_status)) { + /* enable ftm */ + err = dhd_rtt_ftm_enable(dhd, TRUE); + if (err) { + DHD_ERROR(("failed to enable FTM (%d)\n", err)); + goto exit; + } + /* VHT ACK for more accuracy */ + err = dhd_rtt_custom_tune(dhd, TRUE); + if (err < 0) { + DHD_ERROR(("failed to set rtt_custom_set (%d)\n", err)); + goto exit; + } + } + rtt_status->status = RTT_ENABLED; + + /* delete session of index default sesession */ + err = dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION); + if (err < 0 && err != BCME_NOTFOUND) { + DHD_ERROR(("failed to delete session of FTM (%d)\n", err)); + goto exit; + } + memset(ftm_configs, 0, sizeof(ftm_configs)); + memset(ftm_params, 0, sizeof(ftm_params)); + + /* configure the session 1 as initiator */ + ftm_configs[ftm_cfg_cnt].enable = TRUE; + ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_INITIATOR; + dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS, + ftm_configs, ftm_cfg_cnt); + /* target's mac address */ + if (!ETHER_ISNULLADDR(rtt_target->addr.octet)) { + ftm_params[ftm_param_cnt].mac_addr = rtt_target->addr; + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_PEER_MAC; + DHD_RTT((">\t target %s\n", bcm_ether_ntoa(&rtt_target->addr, eabuf))); + } + /* target's chanspec */ + if (rtt_target->chanspec) { + ftm_params[ftm_param_cnt].chanspec = htol32((uint32)rtt_target->chanspec); + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_CHANSPEC; + DHD_RTT((">\t chanspec : %s\n", wf_chspec_ntoa(rtt_target->chanspec, chanbuf))); + } + /* num-burst */ + if (rtt_target->num_burst) { + ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_burst); + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_NUM_BURST; + DHD_RTT((">\t num of burst : %d\n", rtt_target->num_burst)); + } + /* number of frame per burst */ + if (rtt_target->num_frames_per_burst == 0) { + rtt_target->num_frames_per_burst = + CHSPEC_IS20(rtt_target->chanspec) ? FTM_DEFAULT_CNT_20M : + CHSPEC_IS40(rtt_target->chanspec) ? FTM_DEFAULT_CNT_40M : + FTM_DEFAULT_CNT_80M; + } + ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_frames_per_burst); + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_NUM_FTM; + DHD_RTT((">\t number of frame per burst : %d\n", rtt_target->num_frames_per_burst)); + /* FTM retry count */ + if (rtt_target->num_retries_per_ftm) { + ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_retries_per_ftm); + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_RETRIES; + DHD_RTT((">\t retry count of FTM : %d\n", rtt_target->num_retries_per_ftm)); + } + /* FTM Request retry count */ + if (rtt_target->num_retries_per_ftmr) { + ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_retries_per_ftmr); + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_REQ_RETRIES; + DHD_RTT((">\t retry count of FTM Req : %d\n", rtt_target->num_retries_per_ftm)); + } + /* burst-period */ + if (rtt_target->interval) { + ftm_params[ftm_param_cnt].data_intvl.intvl = htol32(rtt_target->interval); /* ms */ + ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC; + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_PERIOD; + DHD_RTT((">\t burst period : %d ms\n", rtt_target->interval)); + } + /* burst-timeout */ + if (rtt_target->burst_timeout) { + ftm_params[ftm_param_cnt].data_intvl.intvl = + htol32(rtt_target->burst_timeout * FTM_BURST_TIMEOUT_UNIT); + ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MICRO_SEC; + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_TIMEOUT; + DHD_RTT((">\t burst timeout : %d us\n", + rtt_target->burst_timeout * WL_PROXD_TMU_MICRO_SEC)); + } + dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_GENERAL, + ftm_params, ftm_param_cnt); + + err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE); + if (err) { + DHD_ERROR(("failed to start session of FTM : error %d\n", err)); + } +exit: + if (err) { + rtt_status->status = RTT_STOPPED; + /* restore default value for custome tune */ + dhd_rtt_custom_tune(dhd, FALSE); + /* disable FTM */ + dhd_rtt_ftm_enable(dhd, FALSE); + if (rtt_status->mpc) { + /* enable mpc again in case of error */ + mpc = 1; + rtt_status->mpc = 0; + err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); + } + } + return err; +} + +int +dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn) +{ + int err = BCME_OK; + struct rtt_noti_callback *cb = NULL, *iter; + rtt_status_info_t *rtt_status; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(noti_fn, "noti_fn is NULL", err); + + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + spin_lock_bh(¬i_list_lock); + list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { + if (iter->noti_fn == noti_fn) { + goto exit; + } + } + cb = kmalloc(sizeof(struct rtt_noti_callback), GFP_ATOMIC); + if (!cb) { + err = -ENOMEM; + goto exit; + } + cb->noti_fn = noti_fn; + cb->ctx = ctx; + list_add(&cb->list, &rtt_status->noti_fn_list); +exit: + spin_unlock_bh(¬i_list_lock); + return err; +} + +int +dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn) +{ + int err = BCME_OK; + struct rtt_noti_callback *cb = NULL, *iter; + rtt_status_info_t *rtt_status; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(noti_fn, "noti_fn is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + spin_lock_bh(¬i_list_lock); + list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { + if (iter->noti_fn == noti_fn) { + cb = iter; + list_del(&cb->list); + break; + } + } + spin_unlock_bh(¬i_list_lock); + if (cb) { + kfree(cb); + } + return err; +} + +static wifi_rate_t +dhd_rtt_convert_rate_to_host(uint32 rspec) +{ + wifi_rate_t host_rate; + if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { + host_rate.preamble = 0; + } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { + host_rate.preamble = 2; + host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; + } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { + host_rate.preamble = 3; + host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; + host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; + } + host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1; + host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ + DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); + return host_rate; +} + + +static int +dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len) +{ + int err = BCME_OK; + char eabuf[ETHER_ADDR_STR_LEN]; + wl_proxd_rtt_result_t *p_data_info; + wl_proxd_result_flags_t flags; + wl_proxd_session_state_t session_state; + wl_proxd_status_t proxd_status; + struct timespec ts; + uint32 ratespec; + uint32 avg_dist; + wl_proxd_rtt_sample_t *p_sample; + wl_proxd_intvl_t rtt; + wl_proxd_intvl_t p_time; + + NULL_CHECK(rtt_report, "rtt_report is NULL", err); + NULL_CHECK(p_data, "p_data is NULL", err); + DHD_RTT(("%s enter\n", __FUNCTION__)); + p_data_info = (wl_proxd_rtt_result_t *) p_data; + /* unpack and format 'flags' for display */ + flags = ltoh16_ua(&p_data_info->flags); + + /* session state and status */ + session_state = ltoh16_ua(&p_data_info->state); + proxd_status = ltoh32_ua(&p_data_info->status); + DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n", + bcm_ether_ntoa((&(p_data_info->peer)), eabuf), + session_state, + ftm_session_state_value_to_logstr(session_state), + proxd_status, + ftm_status_value_to_logstr(proxd_status))); + + /* show avg_dist (1/256m units), burst_num */ + avg_dist = ltoh32_ua(&p_data_info->avg_dist); + if (avg_dist == 0xffffffff) { /* report 'failure' case */ + DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n", + ltoh16_ua(&p_data_info->burst_num), + p_data_info->num_valid_rtt)); /* in a session */ + avg_dist = FTM_INVALID; + } + else { + DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n", + avg_dist >> 8, /* 1/256m units */ + ((avg_dist & 0xff) * 625) >> 4, + ltoh16_ua(&p_data_info->burst_num), + p_data_info->num_valid_rtt, + p_data_info->num_ftm)); /* in a session */ + } + /* show 'avg_rtt' sample */ + p_sample = &p_data_info->avg_rtt; + DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d ratespec=0x%08x\n", + (int16) ltoh16_ua(&p_sample->rssi), + ltoh32_ua(&p_sample->rtt.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)), + ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10, + ltoh32_ua(&p_sample->ratespec))); + + /* set peer address */ + rtt_report->addr = p_data_info->peer; + /* burst num */ + rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num); + /* success num */ + rtt_report->success_num = p_data_info->num_valid_rtt; + /* actual number of FTM supported by peer */ + rtt_report->num_per_burst_peer = p_data_info->num_ftm; + /* status */ + rtt_report->status = ftm_get_statusmap_info(proxd_status, + &ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info)); + /* rssi */ + rtt_report->rssi = (int16)ltoh16_ua(&p_data_info->avg_rtt.rssi); + /* rx rate */ + ratespec = ltoh32_ua(&p_data_info->avg_rtt.ratespec); + rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec); + /* rtt_sd */ + rtt.tmu = ltoh16_ua(&p_data_info->avg_rtt.rtt.tmu); + rtt.intvl = ltoh32_ua(&p_data_info->avg_rtt.rtt.intvl); + rtt_report->rtt = FTM_INTVL2NSEC(&rtt) * 10; /* nano -> 0.1 nano */ + rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */ + + /* average distance */ + if (avg_dist != FTM_INVALID) { + rtt_report->distance = (avg_dist >> 8) * 100; /* meter -> cm */ + rtt_report->distance += (avg_dist & 0xff) * 100 / 256; + } else { + rtt_report->distance = FTM_INVALID; + } + /* time stamp */ + /* get the time elapsed from boot time */ + get_monotonic_boottime(&ts); + rtt_report->ts = (uint64)TIMESPEC_TO_US(ts); + + if (proxd_status == WL_PROXD_E_REMOTE_FAIL) { + /* retry time after failure */ + p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); + p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); + rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */ + DHD_RTT((">\tretry_after: %d%s\n", + ltoh32_ua(&p_data_info->u.retry_after.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu)))); + } else { + /* burst duration */ + p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); + p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); + rtt_report->burst_duration = FTM_INTVL2MSEC(&p_time); /* s -> ms */ + DHD_RTT((">\tburst_duration: %d%s\n", + ltoh32_ua(&p_data_info->u.burst_duration.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu)))); + } + return err; +} + +int +dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) +{ + int ret = BCME_OK; + int tlvs_len; + int idx; + uint16 version; + wl_proxd_event_t *p_event; + wl_proxd_event_type_t event_type; + wl_proxd_ftm_session_status_t session_status; + const ftm_strmap_entry_t *p_loginfo; + rtt_status_info_t *rtt_status; + rtt_target_info_t *rtt_target_info; + struct rtt_noti_callback *iter; + rtt_results_header_t *entry = NULL, *next = NULL, *rtt_results_header = NULL; + rtt_result_t *rtt_result, *next2; + gfp_t kflags; + bool is_new = TRUE; + + NULL_CHECK(dhd, "dhd is NULL", ret); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", ret); + + event_type = ntoh32_ua((void *)&event->event_type); + + if (event_type != WLC_E_PROXD) { + goto exit; + } + if (RTT_IS_STOPPED(rtt_status)) { + /* Ignore the Proxd event */ + goto exit; + } + p_event = (wl_proxd_event_t *) event_data; + version = ltoh16(p_event->version); + if (version < WL_PROXD_API_VERSION) { + DHD_ERROR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n", + version, WL_PROXD_API_VERSION)); + goto exit; + } + if (!in_atomic()) { + mutex_lock(&rtt_status->rtt_mutex); + } + event_type = (wl_proxd_event_type_t) ltoh16(p_event->type); + + kflags = in_softirq()? GFP_ATOMIC : GFP_KERNEL; + + DHD_RTT(("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x\n", + p_event->type, ntoh16(p_event->type), ltoh16(p_event->type))); + p_loginfo = ftm_get_event_type_loginfo(event_type); + if (p_loginfo == NULL) { + DHD_ERROR(("receive an invalid FTM event %d\n", event_type)); + goto exit; /* ignore this event */ + } + /* get TLVs len, skip over event header */ + tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs); + DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n", + p_loginfo->text, + version, + ltoh16(p_event->len), + ltoh16(p_event->method), + ltoh16(p_event->sid), + tlvs_len)); + rtt_target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; + /* find a rtt_report_header for this mac address */ + list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) { + if (!memcmp(&entry->peer_mac, &event->addr, ETHER_ADDR_LEN)) { + /* found a rtt_report_header for peer_mac in the list */ + is_new = FALSE; + rtt_results_header = entry; + break; + } + } + + switch (event_type) { + case WL_PROXD_EVENT_SESSION_CREATE: + DHD_RTT(("WL_PROXD_EVENT_SESSION_CREATE\n")); + break; + case WL_PROXD_EVENT_SESSION_START: + DHD_RTT(("WL_PROXD_EVENT_SESSION_START\n")); + break; + case WL_PROXD_EVENT_BURST_START: + DHD_RTT(("WL_PROXD_EVENT_BURST_START\n")); + break; + case WL_PROXD_EVENT_BURST_END: + DHD_RTT(("WL_PROXD_EVENT_BURST_END\n")); + if (is_new) { + /* allocate new header for rtt_results */ + rtt_results_header = kzalloc(sizeof(rtt_results_header_t), GFP_KERNEL); + if (!rtt_results_header) { + if (!in_atomic()) { + mutex_unlock(&rtt_status->rtt_mutex); + } + ret = -ENOMEM; + goto exit; + } + /* Initialize the head of list for rtt result */ + INIT_LIST_HEAD(&rtt_results_header->result_list); + rtt_results_header->peer_mac = event->addr; + list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache); + } + if (tlvs_len > 0) { + /* allocate rtt_results for new results */ + rtt_result = kzalloc(sizeof(rtt_result_t), kflags); + if (!rtt_result) { + if (!in_atomic()) { + mutex_unlock(&rtt_status->rtt_mutex); + } + ret = -ENOMEM; + goto exit; + } + /* unpack TLVs and invokes the cbfn to print the event content TLVs */ + ret = bcm_unpack_xtlv_buf((void *) &(rtt_result->report), + (uint8 *)&p_event->tlvs[0], tlvs_len, + BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); + if (ret != BCME_OK) { + DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", + __FUNCTION__)); + goto exit; + } + /* fill out the results from the configuration param */ + rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst; + rtt_result->report.type = RTT_TWO_WAY; + DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num)); + rtt_result->report_len = RTT_REPORT_SIZE; + + list_add_tail(&rtt_result->list, &rtt_results_header->result_list); + rtt_results_header->result_cnt++; + rtt_results_header->result_tot_len += rtt_result->report_len; + } + break; + case WL_PROXD_EVENT_SESSION_END: + DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n")); + if (tlvs_len > 0) { + /* unpack TLVs and invokes the cbfn to print the event content TLVs */ + ret = bcm_unpack_xtlv_buf((void *) &session_status, + (uint8 *)&p_event->tlvs[0], tlvs_len, + BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); + if (ret != BCME_OK) { + DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", + __FUNCTION__)); + goto exit; + } + } + /* find next target to trigger RTT */ + for (idx = (rtt_status->cur_idx + 1); + idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { + /* skip the disabled device */ + if (rtt_status->rtt_config.target_info[idx].disable) { + continue; + } else { + /* set the idx to cur_idx */ + rtt_status->cur_idx = idx; + break; + } + } + if (idx < rtt_status->rtt_config.rtt_target_cnt) { + /* restart to measure RTT from next device */ + schedule_work(&rtt_status->work); + } else { + DHD_RTT(("RTT_STOPPED\n")); + rtt_status->status = RTT_STOPPED; + /* to turn on mpc mode */ + schedule_work(&rtt_status->work); + /* notify the completed information to others */ + list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { + iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache); + } + /* remove the rtt results in cache */ + if (!list_empty(&rtt_status->rtt_results_cache)) { + /* Iterate rtt_results_header list */ + list_for_each_entry_safe(entry, next, + &rtt_status->rtt_results_cache, list) { + list_del(&entry->list); + /* Iterate rtt_result list */ + list_for_each_entry_safe(rtt_result, next2, + &entry->result_list, list) { + list_del(&rtt_result->list); + kfree(rtt_result); + } + kfree(entry); + } + } + + /* reinitialize the HEAD */ + INIT_LIST_HEAD(&rtt_status->rtt_results_cache); + /* clear information for rtt_config */ + rtt_status->rtt_config.rtt_target_cnt = 0; + memset(rtt_status->rtt_config.target_info, 0, + TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); + rtt_status->cur_idx = 0; + } + break; + case WL_PROXD_EVENT_SESSION_RESTART: + DHD_RTT(("WL_PROXD_EVENT_SESSION_RESTART\n")); + break; + case WL_PROXD_EVENT_BURST_RESCHED: + DHD_RTT(("WL_PROXD_EVENT_BURST_RESCHED\n")); + break; + case WL_PROXD_EVENT_SESSION_DESTROY: + DHD_RTT(("WL_PROXD_EVENT_SESSION_DESTROY\n")); + break; + case WL_PROXD_EVENT_FTM_FRAME: + DHD_RTT(("WL_PROXD_EVENT_FTM_FRAME\n")); + break; + case WL_PROXD_EVENT_DELAY: + DHD_RTT(("WL_PROXD_EVENT_DELAY\n")); + break; + case WL_PROXD_EVENT_VS_INITIATOR_RPT: + DHD_RTT(("WL_PROXD_EVENT_VS_INITIATOR_RPT\n ")); + break; + case WL_PROXD_EVENT_RANGING: + DHD_RTT(("WL_PROXD_EVENT_RANGING\n")); + break; + + default: + DHD_ERROR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type)); + break; + } + if (!in_atomic()) { + mutex_unlock(&rtt_status->rtt_mutex); + } +exit: + return ret; +} + +static void +dhd_rtt_work(struct work_struct *work) +{ + rtt_status_info_t *rtt_status; + dhd_pub_t *dhd; + rtt_status = container_of(work, rtt_status_info_t, work); + if (rtt_status == NULL) { + DHD_ERROR(("%s : rtt_status is NULL\n", __FUNCTION__)); + return; + } + dhd = rtt_status->dhd; + if (dhd == NULL) { + DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); + return; + } + (void) dhd_rtt_start(dhd); +} + +int +dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa) +{ + rtt_status_info_t *rtt_status; + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + NULL_CHECK(capa, "capa is NULL", err); + bzero(capa, sizeof(rtt_capabilities_t)); + switch (rtt_status->rtt_capa.proto) { + case RTT_CAP_ONE_WAY: + capa->rtt_one_sided_supported = 1; + break; + case RTT_CAP_FTM_WAY: + capa->rtt_ftm_supported = 1; + break; + } + + switch (rtt_status->rtt_capa.feature) { + case RTT_FEATURE_LCI: + capa->lci_support = 1; + break; + case RTT_FEATURE_LCR: + capa->lcr_support = 1; + break; + case RTT_FEATURE_PREAMBLE: + capa->preamble_support = 1; + break; + case RTT_FEATURE_BW: + capa->bw_support = 1; + break; + } + /* bit mask */ + capa->preamble_support = rtt_status->rtt_capa.preamble; + capa->bw_support = rtt_status->rtt_capa.bw; + + return err; +} + +int +dhd_rtt_init(dhd_pub_t *dhd) +{ + int err = BCME_OK, ret; + int32 up = 1; + int32 version; + rtt_status_info_t *rtt_status; + NULL_CHECK(dhd, "dhd is NULL", err); + if (dhd->rtt_state) { + return err; + } + dhd->rtt_state = kzalloc(sizeof(rtt_status_info_t), GFP_KERNEL); + if (dhd->rtt_state == NULL) { + err = BCME_NOMEM; + DHD_ERROR(("%s : failed to create rtt_state\n", __FUNCTION__)); + return err; + } + bzero(dhd->rtt_state, sizeof(rtt_status_info_t)); + rtt_status = GET_RTTSTATE(dhd); + rtt_status->rtt_config.target_info = + kzalloc(TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT), GFP_KERNEL); + if (rtt_status->rtt_config.target_info == NULL) { + DHD_ERROR(("%s failed to allocate the target info for %d\n", + __FUNCTION__, RTT_MAX_TARGET_CNT)); + err = BCME_NOMEM; + goto exit; + } + rtt_status->dhd = dhd; + /* need to do WLC_UP */ + dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(int32), TRUE, 0); + + ret = dhd_rtt_get_version(dhd, &version); + if (ret == BCME_OK && (version == WL_PROXD_API_VERSION)) { + DHD_ERROR(("%s : FTM is supported\n", __FUNCTION__)); + /* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */ + rtt_status->rtt_capa.proto |= RTT_CAP_FTM_WAY; + + /* indicate to set tx rate */ + rtt_status->rtt_capa.feature |= RTT_FEATURE_PREAMBLE; + rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_VHT; + rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_HT; + + /* indicate to set bandwith */ + rtt_status->rtt_capa.feature |= RTT_FEATURE_BW; + rtt_status->rtt_capa.bw |= RTT_BW_20; + rtt_status->rtt_capa.bw |= RTT_BW_40; + rtt_status->rtt_capa.bw |= RTT_BW_80; + } else { + if ((ret != BCME_OK) || (version == 0)) { + DHD_ERROR(("%s : FTM is not supported\n", __FUNCTION__)); + } else { + DHD_ERROR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n", + __FUNCTION__, WL_PROXD_API_VERSION, version)); + } + } + mutex_init(&rtt_status->rtt_mutex); + INIT_LIST_HEAD(&rtt_status->noti_fn_list); + INIT_LIST_HEAD(&rtt_status->rtt_results_cache); + INIT_WORK(&rtt_status->work, dhd_rtt_work); +exit: + if (err < 0) { + kfree(rtt_status->rtt_config.target_info); + kfree(dhd->rtt_state); + } + return err; +} + +int +dhd_rtt_deinit(dhd_pub_t *dhd) +{ + int err = BCME_OK; + rtt_status_info_t *rtt_status; + rtt_results_header_t *rtt_header, *next; + rtt_result_t *rtt_result, *next2; + struct rtt_noti_callback *iter, *iter2; + NULL_CHECK(dhd, "dhd is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + rtt_status->status = RTT_STOPPED; + /* clear evt callback list */ + if (!list_empty(&rtt_status->noti_fn_list)) { + list_for_each_entry_safe(iter, iter2, &rtt_status->noti_fn_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + /* remove the rtt results */ + if (!list_empty(&rtt_status->rtt_results_cache)) { + list_for_each_entry_safe(rtt_header, next, &rtt_status->rtt_results_cache, list) { + list_del(&rtt_header->list); + list_for_each_entry_safe(rtt_result, next2, + &rtt_header->result_list, list) { + list_del(&rtt_result->list); + kfree(rtt_result); + } + kfree(rtt_header); + } + } + kfree(rtt_status->rtt_config.target_info); + kfree(dhd->rtt_state); + dhd->rtt_state = NULL; + return err; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h new file mode 100644 index 000000000000..308f657391a5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h @@ -0,0 +1,284 @@ +/* + * Header file of Broadcom Dongle Host Driver (DHD) + * Copyright (C) 1999-2014, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_rtt.h 423669 2014-07-01 13:01:56Z $ + */ +#ifndef __DHD_RTT_H__ +#define __DHD_RTT_H__ + +#include "dngl_stats.h" + +#define RTT_MAX_TARGET_CNT 50 +#define RTT_MAX_FRAME_CNT 25 +#define RTT_MAX_RETRY_CNT 10 +#define DEFAULT_FTM_CNT 6 +#define DEFAULT_RETRY_CNT 6 +#define TARGET_INFO_SIZE(count) (sizeof(rtt_target_info_t) * count) + +#define TARGET_TYPE(target) (target->type) + +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +/* DSSS, CCK and 802.11n rates in [500kbps] units */ +#define WL_MAXRATE 108 /* in 500kbps units */ +#define WL_RATE_1M 2 /* in 500kbps units */ +#define WL_RATE_2M 4 /* in 500kbps units */ +#define WL_RATE_5M5 11 /* in 500kbps units */ +#define WL_RATE_11M 22 /* in 500kbps units */ +#define WL_RATE_6M 12 /* in 500kbps units */ +#define WL_RATE_9M 18 /* in 500kbps units */ +#define WL_RATE_12M 24 /* in 500kbps units */ +#define WL_RATE_18M 36 /* in 500kbps units */ +#define WL_RATE_24M 48 /* in 500kbps units */ +#define WL_RATE_36M 72 /* in 500kbps units */ +#define WL_RATE_48M 96 /* in 500kbps units */ +#define WL_RATE_54M 108 /* in 500kbps units */ + + +enum rtt_role { + RTT_INITIATOR = 0, + RTT_TARGET = 1 +}; +enum rtt_status { + RTT_STOPPED = 0, + RTT_STARTED = 1, + RTT_ENABLED = 2 +}; +typedef int64_t wifi_timestamp; /* In microseconds (us) */ +typedef int64_t wifi_timespan; +typedef int32 wifi_rssi; + +typedef enum { + RTT_INVALID, + RTT_ONE_WAY, + RTT_TWO_WAY, + RTT_AUTO +} rtt_type_t; + +typedef enum { + RTT_PEER_STA, + RTT_PEER_AP, + RTT_PEER_P2P, + RTT_PEER_NAN, + RTT_PEER_INVALID +} rtt_peer_type_t; + +typedef enum rtt_reason { + RTT_REASON_SUCCESS, + RTT_REASON_FAILURE, + RTT_REASON_FAIL_NO_RSP, + RTT_REASON_FAIL_INVALID_TS, /* Invalid timestamp */ + RTT_REASON_FAIL_PROTOCOL, /* 11mc protocol failed */ + RTT_REASON_FAIL_REJECTED, + RTT_REASON_FAIL_NOT_SCHEDULED_YET, + RTT_REASON_FAIL_SCHEDULE, /* schedule failed */ + RTT_REASON_FAIL_TM_TIMEOUT, + RTT_REASON_FAIL_AP_ON_DIFF_CHANNEL, + RTT_REASON_FAIL_NO_CAPABILITY, + RTT_REASON_FAIL_BUSY_TRY_LATER, + RTT_REASON_ABORTED +} rtt_reason_t; + +enum { + RTT_CAP_ONE_WAY = BIT(0), + /* IEEE802.11mc */ + RTT_CAP_FTM_WAY = BIT(1) +}; + +enum { + RTT_FEATURE_LCI = BIT(0), + RTT_FEATURE_LCR = BIT(1), + RTT_FEATURE_PREAMBLE = BIT(2), + RTT_FEATURE_BW = BIT(3) +}; + +enum { + RTT_PREAMBLE_LEGACY = BIT(0), + RTT_PREAMBLE_HT = BIT(1), + RTT_PREAMBLE_VHT = BIT(2) +}; + + +enum { + RTT_BW_5 = BIT(0), + RTT_BW_10 = BIT(1), + RTT_BW_20 = BIT(2), + RTT_BW_40 = BIT(3), + RTT_BW_80 = BIT(4), + RTT_BW_160 = BIT(5) +}; +#define FTM_MAX_NUM_BURST_EXP 14 +#define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) +#define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) +#define HAS_RTT_CAP(cap) (HAS_ONEWAY_CAP(cap) || HAS_11MC_CAP(cap)) + +typedef struct wifi_channel_info { + wifi_channel_width_t width; + wifi_channel center_freq; /* primary 20 MHz channel */ + wifi_channel center_freq0; /* center freq (MHz) first segment */ + wifi_channel center_freq1; /* center freq (MHz) second segment valid for 80 + 80 */ +} wifi_channel_info_t; + +typedef struct wifi_rate { + uint32 preamble :3; /* 0: OFDM, 1: CCK, 2 : HT, 3: VHT, 4..7 reserved */ + uint32 nss :2; /* 1 : 1x1, 2: 2x2, 3: 3x3, 4: 4x4 */ + uint32 bw :3; /* 0: 20Mhz, 1: 40Mhz, 2: 80Mhz, 3: 160Mhz */ + /* OFDM/CCK rate code would be as per IEEE std in the unit of 0.5 mb + * HT/VHT it would be mcs index + */ + uint32 rateMcsIdx :8; + uint32 reserved :16; /* reserved */ + uint32 bitrate; /* unit of 100 Kbps */ +} wifi_rate_t; + +typedef struct rtt_target_info { + struct ether_addr addr; + rtt_type_t type; /* rtt_type */ + rtt_peer_type_t peer; /* peer type */ + wifi_channel_info_t channel; /* channel information */ + chanspec_t chanspec; /* chanspec for channel */ + bool disable; /* disable for RTT measurement */ + uint32 interval; /* interval of RTT measurement (unit ms) when continuous = true */ + uint16 num_burst; /* total number of RTT bursts when multi_burst = 1 */ + uint32 num_frames_per_burst; + /* num of frames in each RTT burst + * for single side, measurement result num = frame number + * for 2 side RTT, measurement result num = frame number - 1 + */ + uint32 num_retries_per_ftm; /* retry time for RTT measurment frame */ + /* following fields are only valid for 2 side RTT */ + uint32 num_retries_per_ftmr; + uint8 LCI_request; + uint8 LCR_request; + uint32 burst_timeout; + uint8 preamble; /* 0 - Legacy, 1 - HT, 2 - VHT */ + uint8 bw; /* 5, 10, 20, 40, 80, 160 */ +} rtt_target_info_t; + + +typedef struct rtt_report { + struct ether_addr addr; + unsigned int burst_num; /* # of burst inside a multi-burst request */ + unsigned int ftm_num; /* total RTT measurement frames */ + unsigned int success_num; /* total successful RTT measurement frames */ + uint8 num_per_burst_peer; /* max number of FTM number per burst the peer support */ + rtt_reason_t status; /* raging status */ + /* in s, 11mc only, only for RTT_REASON_FAIL_BUSY_TRY_LATER, 1- 31s */ + uint8 retry_after_duration; + rtt_type_t type; /* rtt type */ + wifi_rssi rssi; /* average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB */ + wifi_rssi rssi_spread; /* rssi spread in 0.5 db steps e.g. 5 implies 2.5 spread */ + wifi_rate_t tx_rate; /* tx rate */ + wifi_rate_t rx_rate; /* rx rate */ + wifi_timespan rtt; /* round trip time in 0.1 nanoseconds */ + wifi_timespan rtt_sd; /* rtt standard deviation in 0.1 nanoseconds */ + wifi_timespan rtt_spread; /* difference between max and min rtt times recorded */ + int distance; /* distance in cm (optional) */ + int distance_sd; /* standard deviation in cm (optional) */ + int distance_spread; /* difference between max and min distance recorded (optional) */ + wifi_timestamp ts; /* time of the measurement (in microseconds since boot) */ + int burst_duration; /* in ms, how long the FW time is to fininish one burst measurement */ + bcm_tlv_t *LCI; /* LCI Report */ + bcm_tlv_t *LCR; /* Location Civic Report */ +} rtt_report_t; +#define RTT_REPORT_SIZE (sizeof(rtt_report_t)) + +/* rtt_results_header to maintain rtt result list per mac address */ +typedef struct rtt_results_header { + struct ether_addr peer_mac; + uint32 result_cnt; + uint32 result_tot_len; /* sum of report_len of rtt_result */ + struct list_head list; + struct list_head result_list; +} rtt_results_header_t; + +/* rtt_result to link all of rtt_report */ +typedef struct rtt_result { + struct list_head list; + struct rtt_report report; + int32 report_len; /* total length of rtt_report */ +} rtt_result_t; + +/* RTT Capabilities */ +typedef struct rtt_capabilities { + uint8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */ + uint8 rtt_ftm_supported; /* if ftm rtt data collection is supported */ + uint8 lci_support; /* location configuration information */ + uint8 lcr_support; /* Civic Location */ + uint8 preamble_support; /* bit mask indicate what preamble is supported */ + uint8 bw_support; /* bit mask indicate what BW is supported */ +} rtt_capabilities_t; + +typedef struct rtt_config_params { + int8 rtt_target_cnt; + rtt_target_info_t *target_info; +} rtt_config_params_t; + +typedef void (*dhd_rtt_compl_noti_fn)(void *ctx, void *rtt_data); +/* Linux wrapper to call common dhd_rtt_set_cfg */ +int +dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf); + +int +dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt); + +int +dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, + dhd_rtt_compl_noti_fn noti_fn); + +int +dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn); + +int +dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa); + +/* export to upper layer */ +chanspec_t +dhd_rtt_convert_to_chspec(wifi_channel_info_t channel); + +int +dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params); + +int +dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt); + + +int +dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn); + +int +dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn); + +int +dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); + +int +dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa); + +int +dhd_rtt_init(dhd_pub_t *dhd); + +int +dhd_rtt_deinit(dhd_pub_t *dhd); +#endif /* __DHD_RTT_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c new file mode 100644 index 000000000000..14f9d57f8b39 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c @@ -0,0 +1,8586 @@ +/* + * DHD Bus Module for SDIO + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_sdio.c 701287 2017-05-24 10:33:19Z $ + */ + +#include +#include +#include + +#ifdef BCMEMBEDIMAGE +#include BCMEMBEDIMAGE +#endif /* BCMEMBEDIMAGE */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef PROP_TXSTATUS +#include +#endif +#ifdef DHDTCPACK_SUPPRESS +#include +#endif /* DHDTCPACK_SUPPRESS */ + +bool dhd_mp_halting(dhd_pub_t *dhdp); +extern void bcmsdh_waitfor_iodrain(void *sdh); +extern void bcmsdh_reject_ioreqs(void *sdh, bool reject); +extern bool bcmsdh_fatal_error(void *sdh); + +#ifndef DHDSDIO_MEM_DUMP_FNAME +#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" +#endif + +#define QLEN (1024) /* bulk rx and tx queue lengths */ +#define FCHI (QLEN - 10) +#define FCLOW (FCHI / 2) +#define PRIOMASK 7 + +#define TXRETRIES 2 /* # of retries for tx frames */ +#define READ_FRM_CNT_RETRIES 3 +#ifndef DHD_RXBOUND +#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ +#endif + +#ifndef DHD_TXBOUND +#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ +#endif + +#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ + +#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ +#define MAX_NVRAMBUF_SIZE (6 * 1024) /* max nvram buf size */ +#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */ + +#ifndef DHD_FIRSTREAD +#define DHD_FIRSTREAD 32 +#endif +#if !ISPOWEROF2(DHD_FIRSTREAD) +#error DHD_FIRSTREAD is not a power of 2! +#endif + +/* Total length of frame header for dongle protocol */ +#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) +#define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN) +#define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE + +#ifdef SDTEST +#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) +#else +#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) +#endif + +/* Space for header read, limit for data packets */ +#ifndef MAX_HDR_READ +#define MAX_HDR_READ 32 +#endif +#if !ISPOWEROF2(MAX_HDR_READ) +#error MAX_HDR_READ is not a power of 2! +#endif + +#define MAX_RX_DATASZ 2048 + +/* Maximum milliseconds to wait for F2 to come up */ +#define DHD_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). + */ +#if (PMU_MAX_TRANSITION_DLY <= 1000000) +#undef PMU_MAX_TRANSITION_DLY +#define PMU_MAX_TRANSITION_DLY 1000000 +#endif + +/* hooks for limiting threshold custom tx num in rx processing */ +#define DEFAULT_TXINRX_THRES 0 +#ifndef CUSTOM_TXINRX_THRES +#define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES +#endif + +/* Value for ChipClockCSR during initial setup */ +#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) +#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) + +/* Flags for SDH calls */ +#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) + +/* Packet free applicable unconditionally for sdio and sdspi. Conditional if + * bufpool was present for gspi bus. + */ +#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ + PKTFREE(bus->dhd->osh, pkt, FALSE); +DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); + + +/* Device console log buffer state */ +#define CONSOLE_LINE_MAX 192 +#define CONSOLE_BUFFER_MAX 2024 +typedef struct dhd_console { + uint count; /* Poll interval msec counter */ + uint log_addr; /* Log struct address (fixed) */ + hnd_log_t log; /* Log struct (host copy) */ + uint bufsize; /* Size of log buffer */ + uint8 *buf; /* Log buffer (host copy) */ + uint last; /* Last buffer read index */ +} dhd_console_t; + +#define REMAP_ENAB(bus) ((bus)->remap) +#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) +#define KSO_ENAB(bus) ((bus)->kso) +#define SR_ENAB(bus) ((bus)->_srenab) +#define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto)) +#define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618) +#define MIN_RSRC_SR 0x3 +#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) +#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) +#define RCTL_MACPHY_DISABLE_MASK (1 << 26) +#define RCTL_LOGIC_DISABLE_MASK (1 << 27) + +#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) +#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ +#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ +#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ +#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) +#define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2) +#define OVERFLOW_BLKSZ512_WM 96 +#define OVERFLOW_BLKSZ512_MES 80 + +#define CC_PMUCC3 (0x3) +/* Private data for SDIO bus interaction */ +typedef struct dhd_bus { + dhd_pub_t *dhd; + + bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ + si_t *sih; /* Handle for SI calls */ + char *vars; /* Variables (from CIS and/or other) */ + uint varsz; /* Size of variables buffer */ + uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ + + sdpcmd_regs_t *regs; /* Registers for SDIO core */ + uint sdpcmrev; /* SDIO core revision */ + uint armrev; /* CPU core revision */ + uint ramrev; /* SOCRAM core revision */ + uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ + uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ + uint32 srmemsize; /* Size of SRMEM */ + + uint32 bus; /* gSPI or SDIO bus */ + uint32 bus_num; /* bus number */ + uint32 slot_num; /* slot ID */ + uint32 hostintmask; /* Copy of Host Interrupt Mask */ + uint32 intstatus; /* Intstatus bits (events) pending */ + bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ + bool fcstate; /* State of dongle flow-control */ + + uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ + char *fw_path; /* module_param: path to firmware image */ + char *nv_path; /* module_param: path to nvram vars file */ + const char *nvram_params; /* user specified nvram params. */ + + uint blocksize; /* Block size of SDIO transfers */ + uint roundup; /* Max roundup limit */ + + struct pktq txq; /* Queue length used for flow-control */ + uint8 flowcontrol; /* per prio flow control bitmask */ + uint8 tx_seq; /* Transmit sequence number (next) */ + uint8 tx_max; /* Maximum transmit sequence allowed */ + + uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; + uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ + uint16 nextlen; /* Next Read Len from last header */ + uint8 rx_seq; /* Receive sequence number (expected) */ + bool rxskip; /* Skip receive (awaiting NAK ACK) */ + + void *glomd; /* Packet containing glomming descriptor */ + void *glom; /* Packet chain for glommed superframe */ + uint glomerr; /* Glom packet read errors */ + + uint8 *rxbuf; /* Buffer for receiving control packets */ + uint rxblen; /* Allocated length of rxbuf */ + uint8 *rxctl; /* Aligned pointer into rxbuf */ + uint8 *databuf; /* Buffer for receiving big glom packet */ + uint8 *dataptr; /* Aligned pointer into databuf */ + uint rxlen; /* Length of valid data in buffer */ + + uint8 sdpcm_ver; /* Bus protocol reported by dongle */ + + bool intr; /* Use interrupts */ + bool poll; /* Use polling */ + bool ipend; /* Device interrupt is pending */ + bool intdis; /* Interrupts disabled by isr */ + 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 DHD_DEBUG + dhd_console_t console; /* Console output polling support */ + uint console_addr; /* Console address from shared struct */ +#endif /* DHD_DEBUG */ + + uint regfails; /* Count of R_REG/W_REG failures */ + + uint clkstate; /* State of sd and backplane clock(s) */ + bool activity; /* Activity flag for clock down */ + int32 idletime; /* Control for activity timeout */ + int32 idlecount; /* Activity timeout counter */ + int32 idleclock; /* How to set bus driver when idle */ + int32 sd_divisor; /* Speed control to bus driver */ + int32 sd_mode; /* Mode control to bus driver */ + int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ + bool use_rxchain; /* If dhd should use PKT chains */ + bool sleeping; /* Is SDIO bus sleeping? */ + wait_queue_head_t bus_sleep; + uint rxflow_mode; /* Rx flow control mode */ + bool rxflow; /* Is rx flow control on */ + uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ + 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; + int32 txinrx_thres; /* num of in-queued pkts */ + int32 dotxinrx; /* tx first in dhdsdio_readframes */ +#ifdef SDTEST + /* external loopback */ + bool ext_loop; + uint8 loopid; + + /* pktgen configuration */ + uint pktgen_freq; /* Ticks between bursts */ + uint pktgen_count; /* Packets to send each burst */ + uint pktgen_print; /* Bursts between count displays */ + uint pktgen_total; /* Stop after this many */ + uint pktgen_minlen; /* Minimum packet data len */ + uint pktgen_maxlen; /* Maximum packet data len */ + uint pktgen_mode; /* Configured mode: tx, rx, or echo */ + uint pktgen_stop; /* Number of tx failures causing stop */ + + /* active pktgen fields */ + uint pktgen_tick; /* Tick counter for bursts */ + uint pktgen_ptick; /* Burst counter for printing */ + uint pktgen_sent; /* Number of test packets generated */ + uint pktgen_rcvd; /* Number of test packets received */ + uint pktgen_prev_time; /* Time at which previous stats where printed */ + uint pktgen_prev_sent; /* Number of test packets generated when + * previous stats were printed + */ + uint pktgen_prev_rcvd; /* Number of test packets received when + * previous stats were printed + */ + uint pktgen_fail; /* Number of failed send attempts */ + uint16 pktgen_len; /* Length of next packet to send */ +#define PKTGEN_RCV_IDLE (0) +#define PKTGEN_RCV_ONGOING (1) + uint16 pktgen_rcv_state; /* receive state */ + uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ +#endif /* SDTEST */ + + /* 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 */ +#ifdef DHDENABLE_TAILPAD + uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */ + uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */ +#endif /* DHDENABLE_TAILPAD */ + uint8 *ctrl_frame_buf; + uint32 ctrl_frame_len; + bool ctrl_frame_stat; + uint32 rxint_mode; /* rx interrupt mode */ + bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram + * Available with socram rev 16 + * Remap region not DMA-able + */ + bool kso; + bool _slpauto; + bool _oobwakeup; + bool _srenab; + bool readframes; + bool reqbussleep; + uint32 resetinstr; + uint32 dongle_ram_base; + + void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */ + uint32 txglom_cnt; /* Number of pkts in the glom array */ + uint32 txglom_total_len; /* Total length of pkts in glom array */ + bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled */ + uint32 txglomsize; /* Glom size limitation */ +#ifdef DHDENABLE_TAILPAD + void *pad_pkt; +#endif /* DHDENABLE_TAILPAD */ +} dhd_bus_t; + +/* clkstate */ +#define CLK_NONE 0 +#define CLK_SDONLY 1 +#define CLK_PENDING 2 /* Not used yet */ +#define CLK_AVAIL 3 + +#define DHD_NOPMU(dhd) (FALSE) + +#ifdef DHD_DEBUG +static int qcount[NUMPRIO]; +static int tx_packets[NUMPRIO]; +#endif /* DHD_DEBUG */ + +/* Deferred transmit */ +const uint dhd_deferred_tx = 1; + +extern uint dhd_watchdog_ms; + +extern void dhd_os_wd_timer(void *bus, uint wdtick); + +/* Tx/Rx bounds */ +uint dhd_txbound; +uint dhd_rxbound; +uint dhd_txminmax = DHD_TXMINMAX; + +/* override the RAM size if possible */ +#define DONGLE_MIN_RAMSIZE (128 *1024) +int dhd_dongle_ramsize; + +uint dhd_doflow = TRUE; +uint dhd_dpcpoll = FALSE; + +module_param(dhd_doflow, uint, 0644); +module_param(dhd_dpcpoll, uint, 0644); + +static bool dhd_alignctl; + +static bool sd1idle; + +static bool retrydata; +#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) + +static uint watermark = 8; +static uint mesbusyctrl = 0; +static const uint firstread = DHD_FIRSTREAD; + +/* Retry count for register access failures */ +static const uint retry_limit = 2; + +/* Force even SD lengths (some host controllers mess up on odd bytes) */ +static bool forcealign; + +#define ALIGNMENT 4 + +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) +extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); +#endif + +#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) +#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD +#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ +#define PKTALIGN(osh, p, len, align) \ + do { \ + uintptr datalign; \ + datalign = (uintptr)PKTDATA((osh), (p)); \ + datalign = ROUNDUP(datalign, (align)) - datalign; \ + ASSERT(datalign < (align)); \ + ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ + if (datalign) \ + PKTPULL((osh), (p), (uint)datalign); \ + PKTSETLEN((osh), (p), (len)); \ + } while (0) + +/* Limit on rounding up frames */ +static const uint max_roundup = 512; + +/* Try doing readahead */ +static bool dhd_readahead; + +/* To check if there's window offered */ +#define DATAOK(bus) \ + (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ + (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) + +/* To check if there's window offered for ctrl frame */ +#define TXCTLOK(bus) \ + (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ + (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) + +/* Number of pkts available in dongle for data RX */ +#define DATABUFCNT(bus) \ + ((uint8)(bus->tx_max - bus->tx_seq) - 1) + +/* Macros to get register read/write status */ +/* NOTE: these assume a local dhdsdio_bus_t *bus! */ +#define R_SDREG(regvar, regaddr, retryvar) \ +do { \ + retryvar = 0; \ + do { \ + regvar = R_REG(bus->dhd->osh, regaddr); \ + } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ + if (retryvar) { \ + bus->regfails += (retryvar-1); \ + if (retryvar > retry_limit) { \ + DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \ + __FUNCTION__, __LINE__)); \ + regvar = 0; \ + } \ + } \ +} while (0) + +#define W_SDREG(regval, regaddr, retryvar) \ +do { \ + retryvar = 0; \ + do { \ + W_REG(bus->dhd->osh, regaddr, regval); \ + } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ + if (retryvar) { \ + bus->regfails += (retryvar-1); \ + if (retryvar > retry_limit) \ + DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \ + __FUNCTION__, __LINE__)); \ + } \ +} while (0) + +#define BUS_WAKE(bus) \ + do { \ + bus->idlecount = 0; \ + if ((bus)->sleeping) \ + dhdsdio_bussleep((bus), FALSE); \ + } while (0); + +/* + * pktavail interrupts from dongle to host can be managed in 3 different ways + * whenever there is a packet available in dongle to transmit to host. + * + * Mode 0: Dongle writes the software host mailbox and host is interrupted. + * Mode 1: (sdiod core rev >= 4) + * Device sets a new bit in the intstatus whenever there is a packet + * available in fifo. Host can't clear this specific status bit until all the + * packets are read from the FIFO. No need to ack dongle intstatus. + * Mode 2: (sdiod core rev >= 4) + * Device sets a bit in the intstatus, and host acks this by writing + * one to this bit. Dongle won't generate anymore packet interrupts + * until host reads all the packets from the dongle and reads a zero to + * figure that there are no more packets. No need to disable host ints. + * Need to ack the intstatus. + */ + +#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ +#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ +#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ + + +#define FRAME_AVAIL_MASK(bus) \ + ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) + +#define DHD_BUS SDIO_BUS + +#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) + +#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) + +#define GSPI_PR55150_BAILOUT + +#ifdef SDTEST +static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); +static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count); +#endif + +static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); +#ifdef DHD_DEBUG +static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); +#endif /* DHD_DEBUG */ + +#if defined(DHD_FW_COREDUMP) +static int dhdsdio_mem_dump(dhd_bus_t *bus); +#endif /* DHD_FW_COREDUMP */ +static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap); +static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); + +static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); +static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); +static void dhdsdio_disconnect(void *ptr); +static bool dhdsdio_chipmatch(uint16 chipid); +static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, + void * regsva, uint16 devid); +static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); +static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); +static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, + bool reset_flag); + +static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size); +static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, + void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); +static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, + void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry); +static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt); +static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, + int prev_chain_total_len, bool last_chained_pkt, + int *pad_pkt_len, void **new_pkt); +static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt); + +static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); +static int _dhdsdio_download_firmware(dhd_bus_t *bus); + +static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); +static int dhdsdio_download_nvram(dhd_bus_t *bus); +#ifdef BCMEMBEDIMAGE +static int dhdsdio_download_code_array(dhd_bus_t *bus); +#endif +static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep); +static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok); +static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus); + +#ifdef WLMEDIA_HTSF +#include +extern uint32 dhd_get_htsf(void *dhd, int ifidx); +#endif /* WLMEDIA_HTSF */ + +static void +dhdsdio_tune_fifoparam(struct dhd_bus *bus) +{ + int err; + uint8 devctl, wm, mes; + + if (bus->sih->buscorerev >= 15) { + /* See .ppt in PR for these recommended values */ + if (bus->blocksize == 512) { + wm = OVERFLOW_BLKSZ512_WM; + mes = OVERFLOW_BLKSZ512_MES; + } else { + mes = bus->blocksize/4; + wm = bus->blocksize/4; + } + + watermark = wm; + mesbusyctrl = mes; + } else { + DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n", + bus->sih->buscorerev)); + return; + } + + /* Update watermark */ + if (wm > 0) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err); + + devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl |= SBSDIO_DEVCTL_F2WM_ENAB; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } + + /* Update MES */ + if (mes > 0) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, + (mes | SBSDIO_MESBUSYCTRL_ENAB), &err); + } + + DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n", + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err), + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err), + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err))); +} + +static void +dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size) +{ + int32 min_size = DONGLE_MIN_RAMSIZE; + /* Restrict the ramsize to user specified limit */ + DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", + dhd_dongle_ramsize, min_size)); + if ((dhd_dongle_ramsize > min_size) && + (dhd_dongle_ramsize < (int32)bus->orig_ramsize)) + bus->ramsize = dhd_dongle_ramsize; +} + +static int +dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) +{ + int err = 0; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, + (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); + if (!err) + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, + (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); + if (!err) + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, + (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); + return err; +} + + +#ifdef USE_OOB_GPIO1 +static int +dhdsdio_oobwakeup_init(dhd_bus_t *bus) +{ + uint32 val, addr, data; + + bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP); + + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + + /* Set device for gpio1 wakeup */ + bcmsdh_reg_write(bus->sdh, addr, 4, 2); + val = bcmsdh_reg_read(bus->sdh, data, 4); + val |= CC_CHIPCTRL2_GPIO1_WAKEUP; + bcmsdh_reg_write(bus->sdh, data, 4, val); + + bus->_oobwakeup = TRUE; + + return 0; +} +#endif /* USE_OOB_GPIO1 */ + +/* + * Query if FW is in SR mode + */ +static bool +dhdsdio_sr_cap(dhd_bus_t *bus) +{ + bool cap = FALSE; + uint32 core_capext, addr, data; + + if (bus->sih->chip == BCM43430_CHIP_ID) { + /* check if fw initialized sr engine */ + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, sr_control1); + if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0) + cap = TRUE; + + return cap; + } + if (bus->sih->chip == BCM4324_CHIP_ID) { + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + bcmsdh_reg_write(bus->sdh, addr, 4, 3); + core_capext = bcmsdh_reg_read(bus->sdh, data, 4); + } else if (bus->sih->chip == BCM4330_CHIP_ID) { + core_capext = FALSE; + } else if ((bus->sih->chip == BCM4335_CHIP_ID) || + (bus->sih->chip == BCM4339_CHIP_ID) || + (bus->sih->chip == BCM43349_CHIP_ID) || + (bus->sih->chip == BCM4345_CHIP_ID) || + (bus->sih->chip == BCM4354_CHIP_ID) || + (bus->sih->chip == BCM4356_CHIP_ID) || + (bus->sih->chip == BCM4358_CHIP_ID) || + (BCM4349_CHIP(bus->sih->chip)) || + (bus->sih->chip == BCM4350_CHIP_ID)) { + core_capext = TRUE; + } else { + core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); + core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK); + } + if (!(core_capext)) + return FALSE; + + if (bus->sih->chip == BCM4324_CHIP_ID) { + /* FIX: Should change to query SR control register instead */ + cap = TRUE; + } else if ((bus->sih->chip == BCM4335_CHIP_ID) || + (bus->sih->chip == BCM4339_CHIP_ID) || + (bus->sih->chip == BCM43349_CHIP_ID) || + (bus->sih->chip == BCM4345_CHIP_ID) || + (bus->sih->chip == BCM4354_CHIP_ID) || + (bus->sih->chip == BCM4356_CHIP_ID) || + (bus->sih->chip == BCM4358_CHIP_ID) || + (bus->sih->chip == BCM4350_CHIP_ID)) { + uint32 enabval = 0; + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); + enabval = bcmsdh_reg_read(bus->sdh, data, 4); + + if ((bus->sih->chip == BCM4350_CHIP_ID) || + (bus->sih->chip == BCM4345_CHIP_ID) || + (bus->sih->chip == BCM4354_CHIP_ID) || + (bus->sih->chip == BCM4356_CHIP_ID) || + (bus->sih->chip == BCM4358_CHIP_ID)) + enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE; + + if (enabval) + cap = TRUE; + } else { + data = bcmsdh_reg_read(bus->sdh, + SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4); + if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) + cap = TRUE; + } + + return cap; +} + +static int +dhdsdio_srwar_init(dhd_bus_t *bus) +{ + bcmsdh_gpio_init(bus->sdh); + +#ifdef USE_OOB_GPIO1 + dhdsdio_oobwakeup_init(bus); +#endif + + + return 0; +} + +static int +dhdsdio_sr_init(dhd_bus_t *bus) +{ + uint8 val; + int err = 0; + + if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) + dhdsdio_srwar_init(bus); + + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); + val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, + 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); + +#ifdef USE_CMD14 + /* Add CMD14 Support */ + dhdsdio_devcap_set(bus, + (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT)); +#endif /* USE_CMD14 */ + + dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err); + + bus->_slpauto = dhd_slpauto ? TRUE : FALSE; + + bus->_srenab = TRUE; + + return 0; +} + +/* + * FIX: Be sure KSO bit is enabled + * Currently, it's defaulting to 0 which should be 1. + */ +static int +dhdsdio_clk_kso_init(dhd_bus_t *bus) +{ + uint8 val; + int err = 0; + + /* set flag */ + bus->kso = TRUE; + + /* + * Enable KeepSdioOn (KSO) bit for normal operation + * Default is 0 (4334A0) so set it. Fixed in B0. + */ + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL); + if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { + val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); + if (err) + DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err)); + } + + return 0; +} + +#define KSO_DBG(x) +#define KSO_WAIT_US 50 +#define KSO_WAIT_MS 1 +#define KSO_SLEEP_RETRY_COUNT 20 +#define ERROR_BCME_NODEVICE_MAX 1 + +#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) +static int +dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) +{ + uint8 wr_val = 0, rd_val, cmp_val, bmask; + int err = 0; + int try_cnt = 0; + + KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); + + wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); + + if (on) { + cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; + bmask = cmp_val; + + OSL_SLEEP(3); + } else { + /* Put device to sleep, turn off KSO */ + cmp_val = 0; + bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; + } + + do { + rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); + if (((rd_val & bmask) == cmp_val) && !err) + break; + + KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); + + if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) { + OSL_SLEEP(KSO_WAIT_MS); + } else + OSL_DELAY(KSO_WAIT_US); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); + } while (try_cnt++ < MAX_KSO_ATTEMPTS); + + + if (try_cnt > 2) + KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", + __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); + + if (try_cnt > MAX_KSO_ATTEMPTS) { + DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", + __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); + } + return err; +} + +static int +dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) +{ + int err = 0; + + if (on == FALSE) { + + BUS_WAKE(bus); + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__, + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err))); + dhdsdio_clk_kso_enab(bus, FALSE); + } else { + DHD_ERROR(("%s: KSO enable\n", __FUNCTION__)); + + /* Make sure we have SD bus access */ + if (bus->clkstate == CLK_NONE) { + DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__)); + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } + + dhdsdio_clk_kso_enab(bus, TRUE); + + DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__, + dhdsdio_sleepcsr_get(bus))); + } + + bus->kso = on; + BCM_REFERENCE(err); + + return 0; +} + +static uint8 +dhdsdio_sleepcsr_get(dhd_bus_t *bus) +{ + int err = 0; + uint8 val = 0; + + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); + if (err) + DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err)); + + return val; +} + +uint8 +dhdsdio_devcap_get(dhd_bus_t *bus) +{ + return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL); +} + +static int +dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap) +{ + int err = 0; + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err); + if (err) + DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err)); + + return 0; +} + +static int +dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) +{ + int err = 0, retry; + uint8 val; + + retry = 0; + if (on == TRUE) { + /* Enter Sleep */ + + /* Be sure we request clk before going to sleep + * so we can wake-up with clk request already set + * else device can go back to sleep immediately + */ + if (!SLPAUTO_ENAB(bus)) + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + else { + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if ((val & SBSDIO_CSR_MASK) == 0) { + DHD_ERROR(("%s: No clock before enter sleep:0x%x\n", + __FUNCTION__, val)); + + /* Reset clock request */ + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + SBSDIO_ALP_AVAIL_REQ, &err); + DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__, + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err))); + } + } + + DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__, + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err))); +#ifdef USE_CMD14 + err = bcmsdh_sleep(bus->sdh, TRUE); +#else + err = dhdsdio_clk_kso_enab(bus, FALSE); + if (OOB_WAKEUP_ENAB(bus)) + { + err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ + } +#endif /* USE_CMD14 */ + } else { + /* Exit Sleep */ + /* Make sure we have SD bus access */ + if (bus->clkstate == CLK_NONE) { + DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__)); + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } + + if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), + GPIO_DEV_SRSTATE_TIMEOUT); + + if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { + DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n")); + } + } +#ifdef USE_CMD14 + err = bcmsdh_sleep(bus->sdh, FALSE); + if (SLPAUTO_ENAB(bus) && (err != 0)) { + OSL_DELAY(10000); + DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__)); + + /* Toggle sleep to resync with host and device */ + err = bcmsdh_sleep(bus->sdh, TRUE); + OSL_DELAY(10000); + err = bcmsdh_sleep(bus->sdh, FALSE); + + if (err) { + OSL_DELAY(10000); + DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__)); + + /* Toggle sleep to resync with host and device */ + err = bcmsdh_sleep(bus->sdh, TRUE); + OSL_DELAY(10000); + err = bcmsdh_sleep(bus->sdh, FALSE); + if (err) { + DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__)); + DHD_ERROR(("%s: FATAL: Device non-response!\n", + __FUNCTION__)); + err = 0; + } + } + } +#else + if (OOB_WAKEUP_ENAB(bus)) + { + err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ + } + do { + err = dhdsdio_clk_kso_enab(bus, TRUE); + if (err) + OSL_SLEEP(10); + } while ((err != 0) && (++retry < 3)); + + if (err != 0) { + DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry)); + err = 0; /* continue anyway */ + } +#endif /* !USE_CMD14 */ + + if (err == 0) { + uint8 csr; + + /* Wait for device ready during transition to wake-up */ + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + (((csr = dhdsdio_sleepcsr_get(bus)) & + SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != + (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); + + DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr)); + + if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) { + DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n", + __FUNCTION__, csr)); + err = BCME_NODEVICE; + } + + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != + (SBSDIO_HT_AVAIL)), (10000)); + + DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr)); + if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) { + DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n", + __FUNCTION__, csr)); + err = BCME_NODEVICE; + } + } + } + + /* Update if successful */ + if (err == 0) + bus->kso = on ? FALSE : TRUE; + else { + DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n", + __FUNCTION__, bus->kso, on, err)); + if (!on && retry > 2) + bus->kso = FALSE; + } + + return err; +} + +/* Turn backplane clock on or off */ +static int +dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) +{ +#define HT_AVAIL_ERROR_MAX 10 + static int ht_avail_error = 0; + int err; + uint8 clkctl, clkreq, devctl; + bcmsdh_info_t *sdh; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + clkctl = 0; + sdh = bus->sdh; + + + if (!KSO_ENAB(bus)) + return BCME_OK; + + if (SLPAUTO_ENAB(bus)) { + bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); + return BCME_OK; + } + + if (on) { + /* Request HT Avail */ + clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; + + + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); + if (err) { + ht_avail_error++; + if (ht_avail_error < HT_AVAIL_ERROR_MAX) { + DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + else if (ht_avail_error == HT_AVAIL_ERROR_MAX) { +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + "%s ht_avail_error = %d\n", __func__, ht_avail_error); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + dhd_os_send_hang_message(bus->dhd); + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ + return BCME_ERROR; + } else { + ht_avail_error = 0; + } + + + /* Check current status */ + clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (err) { + DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err)); + return BCME_ERROR; + } + +#if !defined(OOB_INTR_ONLY) + /* Go to pending and await interrupt if appropriate */ + if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { + /* Allow only clock-available interrupt */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + if (err) { + DHD_ERROR(("%s: Devctl access error setting CA: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + + devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + DHD_INFO(("CLKCTL: set PENDING\n")); + bus->clkstate = CLK_PENDING; + return BCME_OK; + } else +#endif /* !defined (OOB_INTR_ONLY) */ + { + if (bus->clkstate == CLK_PENDING) { + /* Cancel CA-only interrupt filter */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } + } + + /* Otherwise, wait here (polling) for HT Avail */ + if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err)), + !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); + } + if (err) { + DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); + return BCME_ERROR; + } + if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { + DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n", + __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl)); + return BCME_ERROR; + } + + /* Mark clock available */ + bus->clkstate = CLK_AVAIL; + DHD_INFO(("CLKCTL: turned ON\n")); + +#if defined(DHD_DEBUG) + if (bus->alp_only == TRUE) { +#if !defined(BCMLXSDMMC) + if (!SBSDIO_ALPONLY(clkctl)) { + DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__)); + } +#endif /* !defined(BCMLXSDMMC) */ + } else { + if (SBSDIO_ALPONLY(clkctl)) { + DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__)); + } + } +#endif /* defined (DHD_DEBUG) */ + + bus->activity = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ + } else { + clkreq = 0; + + if (bus->clkstate == CLK_PENDING) { + /* Cancel CA-only interrupt filter */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } + + bus->clkstate = CLK_SDONLY; + if (!SR_ENAB(bus)) { + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); + DHD_INFO(("CLKCTL: turned OFF\n")); + if (err) { + DHD_ERROR(("%s: Failed access turning clock off: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } + } + return BCME_OK; +} + +/* Change idle/active SD state */ +static int +dhdsdio_sdclk(dhd_bus_t *bus, bool on) +{ + int err; + int32 iovalue; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (on) { + if (bus->idleclock == DHD_IDLE_STOP) { + /* Turn on clock and restore mode */ + iovalue = 1; + err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error enabling sd_clock: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + + iovalue = bus->sd_mode; + err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error changing sd_mode: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } else if (bus->idleclock != DHD_IDLE_ACTIVE) { + /* Restore clock speed */ + iovalue = bus->sd_divisor; + err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error restoring sd_divisor: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } + bus->clkstate = CLK_SDONLY; + } else { + /* Stop or slow the SD clock itself */ + if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { + DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n", + __FUNCTION__, bus->sd_divisor, bus->sd_mode)); + return BCME_ERROR; + } + if (bus->idleclock == DHD_IDLE_STOP) { + if (sd1idle) { + /* Change to SD1 mode and turn off clock */ + iovalue = 1; + err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error changing sd_clock: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } + + iovalue = 0; + err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error disabling sd_clock: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } else if (bus->idleclock != DHD_IDLE_ACTIVE) { + /* Set divisor to idle value */ + iovalue = bus->idleclock; + err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error changing sd_divisor: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } + bus->clkstate = CLK_NONE; + } + + return BCME_OK; +} + +/* Transition SD and backplane clock readiness */ +static int +dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) +{ + int ret = BCME_OK; +#ifdef DHD_DEBUG + uint oldstate = bus->clkstate; +#endif /* DHD_DEBUG */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Early exit if we're already there */ + if (bus->clkstate == target) { + if (target == CLK_AVAIL) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + bus->activity = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ + } + return ret; + } + + switch (target) { + case CLK_AVAIL: + /* Make sure SD clock is available */ + if (bus->clkstate == CLK_NONE) + dhdsdio_sdclk(bus, TRUE); + /* Now request HT Avail on the backplane */ + ret = dhdsdio_htclk(bus, TRUE, pendok); + if (ret == BCME_OK) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + bus->activity = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ + } + break; + + case CLK_SDONLY: + /* Remove HT request, or bring up SD clock */ + if (bus->clkstate == CLK_NONE) + ret = dhdsdio_sdclk(bus, TRUE); + else if (bus->clkstate == CLK_AVAIL) + ret = dhdsdio_htclk(bus, FALSE, FALSE); + else + DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", + bus->clkstate, target)); + if (ret == BCME_OK) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + } + break; + + case CLK_NONE: + /* Make sure to remove HT request */ + if (bus->clkstate == CLK_AVAIL) + ret = dhdsdio_htclk(bus, FALSE, FALSE); + /* Now remove the SD clock */ + ret = dhdsdio_sdclk(bus, FALSE); +#ifdef DHD_DEBUG + if (dhd_console_ms == 0) +#endif /* DHD_DEBUG */ + if (bus->poll == 0) + dhd_os_wd_timer(bus->dhd, 0); + break; + } +#ifdef DHD_DEBUG + DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); +#endif /* DHD_DEBUG */ + + return ret; +} + +static int +dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) +{ + int err = 0; + bcmsdh_info_t *sdh = bus->sdh; + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + + DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", + (sleep ? "SLEEP" : "WAKE"), + (bus->sleeping ? "SLEEP" : "WAKE"))); + + if (bus->dhd->hang_was_sent) + return BCME_ERROR; + + /* Done if we're already in the requested state */ + if (sleep == bus->sleeping) + return BCME_OK; + + /* 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 BCME_BUSY; + + + if (!SLPAUTO_ENAB(bus)) { + /* Disable SDIO interrupts (no longer interested) */ + bcmsdh_intr_disable(bus->sdh); + + /* Make sure the controller has the bus up */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Tell device to start using OOB wakeup */ + W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); + + /* Turn off our contribution to the HT clock request */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); + + /* Isolate the bus */ + if (bus->sih->chip != BCM4329_CHIP_ID && + bus->sih->chip != BCM4319_CHIP_ID) { + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, + SBSDIO_DEVCTL_PADS_ISO, NULL); + } + } else { + /* Leave interrupts enabled since device can exit sleep and + * interrupt host + */ + err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */); + } + + /* Change state */ + bus->sleeping = TRUE; + wake_up(&bus->bus_sleep); + } else { + /* Waking up: bus power up is ok, set local state */ + + if (!SLPAUTO_ENAB(bus)) { + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err); + + /* Force pad isolation off if possible (in case power never toggled) */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); + + + /* Make sure the controller has the bus up */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Send misc interrupt to indicate OOB not needed */ + W_SDREG(0, ®s->tosbmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); + + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); + + /* Make sure we have SD bus access */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + + /* Enable interrupts again */ + if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { + bus->intdis = FALSE; + bcmsdh_intr_enable(bus->sdh); + } + } else { + err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */); + } + + if (err == 0) { + /* Change state */ + bus->sleeping = FALSE; + } + } + + return err; +} + + +#if defined(OOB_INTR_ONLY) +void +dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) +{ +#if defined(HW_OOB) + bcmsdh_enable_hw_oob_intr(bus->sdh, enable); +#else + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (enable == TRUE) { + + /* Tell device to start using OOB wakeup */ + W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); + + } else { + /* Send misc interrupt to indicate OOB not needed */ + W_SDREG(0, ®s->tosbmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); + } + + /* Turn off our contribution to the HT clock request */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); +#endif /* !defined(HW_OOB) */ +} +#endif + +int +dhd_bus_txdata(struct dhd_bus *bus, void *pkt) +{ + int ret = BCME_ERROR; + osl_t *osh; + uint datalen, prec; +#if defined(DHD_TX_DUMP) + uint8 *dump_data; + uint16 protocol; +#endif /* DHD_TX_DUMP */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + osh = bus->dhd->osh; + datalen = PKTLEN(osh, pkt); + +#ifdef SDTEST + /* Push the test header if doing loopback */ + if (bus->ext_loop) { + uint8* data; + PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); + data = PKTDATA(osh, pkt); + *data++ = SDPCM_TEST_ECHOREQ; + *data++ = (uint8)bus->loopid++; + *data++ = (datalen >> 0); + *data++ = (datalen >> 8); + datalen += SDPCM_TEST_HDRLEN; + } +#else /* SDTEST */ + BCM_REFERENCE(datalen); +#endif /* SDTEST */ + +#if defined(DHD_TX_DUMP) + dump_data = PKTDATA(osh, pkt); + dump_data += 4; /* skip 4 bytes header */ + protocol = (dump_data[12] << 8) | dump_data[13]; + + if (protocol == ETHER_TYPE_802_1X) { + DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n", + dump_data[14], dump_data[15], dump_data[30])); + } +#endif /* DHD_TX_DUMP */ + +#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP) + { + int i; + DHD_ERROR(("TX DUMP\n")); + + for (i = 0; i < (datalen - 4); i++) { + DHD_ERROR(("%02X ", dump_data[i])); + if ((i & 15) == 15) + printk("\n"); + } + DHD_ERROR(("\n")); + } +#endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */ + + prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); + + /* Check for existing queue, current flow-control, pending event, or pending clock */ + if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || + (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || + (bus->clkstate != CLK_AVAIL)) { + bool deq_ret; + int pkq_len; + + DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq))); + bus->fcqueued++; + + /* Priority based enq */ + dhd_os_sdlock_txq(bus->dhd); + deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec); + dhd_os_sdunlock_txq(bus->dhd); + + if (!deq_ret) { +#ifdef PROP_TXSTATUS + if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0) +#endif /* PROP_TXSTATUS */ + { +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + dhd_txcomplete(bus->dhd, pkt, FALSE); + PKTFREE(osh, pkt, TRUE); + } + ret = BCME_NORESOURCE; + } else + ret = BCME_OK; + + dhd_os_sdlock_txq(bus->dhd); + pkq_len = pktq_len(&bus->txq); + dhd_os_sdunlock_txq(bus->dhd); + if (pkq_len >= FCHI) { + bool wlfc_enabled = FALSE; +#ifdef PROP_TXSTATUS + wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) != + WLFC_UNSUPPORTED); +#endif + if (!wlfc_enabled && dhd_doflow) { + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); + } + } + +#ifdef DHD_DEBUG + dhd_os_sdlock_txq(bus->dhd); + if (pktq_plen(&bus->txq, prec) > qcount[prec]) + qcount[prec] = pktq_plen(&bus->txq, prec); + dhd_os_sdunlock_txq(bus->dhd); +#endif + + /* Schedule DPC if needed to send queued packet(s) */ + if (dhd_deferred_tx && !bus->dpc_sched) { + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + } + } else { + int chan = SDPCM_DATA_CHANNEL; + +#ifdef SDTEST + chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL); +#endif + /* Lock: we're about to use shared data/code (and SDIO) */ + dhd_os_sdlock(bus->dhd); + + /* Otherwise, send it now */ + BUS_WAKE(bus); + /* Make sure back plane ht clk is on, no pending allowed */ + dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); + + ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE); + + if (ret != BCME_OK) + bus->dhd->tx_errors++; + else + bus->dhd->dstats.tx_bytes += datalen; + + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + } + + return ret; +} + +/* align packet data pointer and packet length to n-byte boundary, process packet headers, + * a new packet may be allocated if there is not enough head and/or tail from for padding. + * the caller is responsible for updating the glom size in the head packet (when glom is + * used) + * + * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter + * is taken in tx glom mode only + * + * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment + * padding, NULL if not needed, the caller is responsible for freeing the new packet + * + * return: positive value - length of the packet, including head and tail padding + * negative value - errors + */ +static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, + int prev_chain_total_len, bool last_chained_pkt, + int *pad_pkt_len, void **new_pkt) +{ + osl_t *osh; + uint8 *frame; + int pkt_len; + int modulo; + int head_padding; + int tail_padding = 0; + uint32 swheader; + uint32 swhdr_offset; + bool alloc_new_pkt = FALSE; + uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; + + *new_pkt = NULL; + osh = bus->dhd->osh; + +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + + /* Add space for the SDPCM hardware/software headers */ + PKTPUSH(osh, pkt, sdpcm_hdrlen); + ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); + + frame = (uint8*)PKTDATA(osh, pkt); + pkt_len = (uint16)PKTLEN(osh, pkt); + +#ifdef WLMEDIA_HTSF + frame = (uint8*)PKTDATA(osh, pkt); + if (PKTLEN(osh, pkt) >= 100) { + htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12); + if (htsf_ts->magic == HTSFMAGIC) { + htsf_ts->c20 = get_cycles(); + htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); + } + } +#endif /* WLMEDIA_HTSF */ +#ifdef DHD_DEBUG + if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) + tx_packets[PKTPRIO(pkt)]++; +#endif /* DHD_DEBUG */ + + /* align the data pointer, allocate a new packet if there is not enough space (new + * packet data pointer will be aligned thus no padding will be needed) + */ + head_padding = (ulong)frame % DHD_SDALIGN; + if (PKTHEADROOM(osh, pkt) < head_padding) { + head_padding = 0; + alloc_new_pkt = TRUE; + } else { + uint cur_chain_total_len; + int chain_tail_padding = 0; + + /* All packets need to be aligned by DHD_SDALIGN */ + modulo = (pkt_len + head_padding) % DHD_SDALIGN; + tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; + + /* Total pkt chain length needs to be aligned by block size, + * unless it is a single pkt chain with total length less than one block size, + * which we prefer sending by byte mode. + * + * Do the chain alignment here if + * 1. This is the last pkt of the chain of multiple pkts or a single pkt. + * 2-1. This chain is of multiple pkts, or + * 2-2. This is a single pkt whose size is longer than one block size. + */ + cur_chain_total_len = prev_chain_total_len + + (head_padding + pkt_len + tail_padding); + if (last_chained_pkt && bus->blocksize != 0 && + (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { + modulo = cur_chain_total_len % bus->blocksize; + chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; + } + +#ifdef DHDENABLE_TAILPAD + if (PKTTAILROOM(osh, pkt) < tail_padding) { + /* We don't have tail room to align by DHD_SDALIGN */ + alloc_new_pkt = TRUE; + bus->tx_tailpad_pktget++; + } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) { + /* We have tail room for tail_padding of this pkt itself, but not for + * total pkt chain alignment by block size. + * Use the padding packet to avoid memory copy if applicable, + * otherwise, just allocate a new pkt. + */ + if (bus->pad_pkt) { + *pad_pkt_len = chain_tail_padding; + bus->tx_tailpad_chain++; + } else { + alloc_new_pkt = TRUE; + bus->tx_tailpad_pktget++; + } + } else + /* This last pkt's tailroom is sufficient to hold both tail_padding + * of the pkt itself and chain_tail_padding of total pkt chain + */ +#endif /* DHDENABLE_TAILPAD */ + tail_padding += chain_tail_padding; + } + + DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n", + __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len)); + + if (alloc_new_pkt) { + void *tmp_pkt; + int newpkt_size; + int cur_total_len; + + ASSERT(*pad_pkt_len == 0); + + DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__)); + + /* head pointer is aligned now, no padding needed */ + head_padding = 0; + + /* update the tail padding as it depends on the head padding, since a new packet is + * allocated, the head padding is non longer needed and packet length is chagned + */ + + cur_total_len = prev_chain_total_len + pkt_len; + if (last_chained_pkt && bus->blocksize != 0 && + (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { + modulo = cur_total_len % bus->blocksize; + tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; + } + else { + modulo = pkt_len % DHD_SDALIGN; + tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; + } + + newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN; + bus->dhd->tx_realloc++; + tmp_pkt = PKTGET(osh, newpkt_size, TRUE); + if (tmp_pkt == NULL) { + DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size)); + return BCME_NOMEM; + } + PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN); + bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt)); + *new_pkt = tmp_pkt; + pkt = tmp_pkt; + } + + if (head_padding) + PKTPUSH(osh, pkt, head_padding); + + frame = (uint8*)PKTDATA(osh, pkt); + bzero(frame, head_padding + sdpcm_hdrlen); + pkt_len = (uint16)PKTLEN(osh, pkt); + + /* the header has the followming format + * 4-byte HW frame tag: length, ~length (for glom this is the total length) + * + * 8-byte HW extesion flags (glom mode only) as the following: + * 2-byte packet length, excluding HW tag and padding + * 2-byte frame channel and frame flags (e.g. next frame following) + * 2-byte header length + * 2-byte tail padding size + * + * 8-byte SW frame tags as the following + * 4-byte flags: host tx seq, channel, data offset + * 4-byte flags: TBD + */ + + swhdr_offset = SDPCM_FRAMETAG_LEN; + + /* hardware frame tag: + * + * in tx-glom mode, dongle only checks the hardware frame tag in the first + * packet and sees it as the total lenght of the glom (including tail padding), + * for each packet in the glom, the packet length needs to be updated, (see + * below PKTSETLEN) + * + * in non tx-glom mode, PKTLEN still need to include tail padding as to be + * referred to in sdioh_request_buffer(). The tail length will be excluded in + * dhdsdio_txpkt_postprocess(). + */ + *(uint16*)frame = (uint16)htol16(pkt_len); + *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len); + pkt_len += tail_padding; + + /* hardware extesion flags */ + if (bus->txglom_enable) { + uint32 hwheader1; + uint32 hwheader2; + + swhdr_offset += SDPCM_HWEXT_LEN; + hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) | + (last_chained_pkt << 24); + hwheader2 = (tail_padding) << 16; + htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); + htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); + } + PKTSETLEN((osh), (pkt), (pkt_len)); + + /* software frame tags */ + swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) + | (txseq % SDPCM_SEQUENCE_WRAP) | + (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); + htol32_ua_store(swheader, frame + swhdr_offset); + htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader)); + + return pkt_len; +} + +static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt) +{ + osl_t *osh; + uint8 *frame; + int data_offset; + int tail_padding; + int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0); + + (void)osh; + osh = bus->dhd->osh; + + /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */ + frame = (uint8*)PKTDATA(osh, pkt); + + DHD_INFO(("%s PKTLEN before postprocess %d", + __FUNCTION__, PKTLEN(osh, pkt))); + + /* PKTLEN still includes tail_padding, so exclude it. + * We shall have head_padding + original pkt_len for PKTLEN afterwards. + */ + if (bus->txglom_enable) { + /* txglom pkts have tail_padding length in HW ext header */ + tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16; + PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding); + DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n", + tail_padding, PKTLEN(osh, pkt))); + } else { + /* non-txglom pkts have head_padding + original pkt length in HW frame tag. + * We cannot refer to this field for txglom pkts as the first pkt of the chain will + * have the field for the total length of the chain. + */ + PKTSETLEN(osh, pkt, *(uint16*)frame); + DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n", + *(uint16*)frame, PKTLEN(osh, pkt))); + } + + data_offset = ltoh32_ua(frame + swhdr_offset); + data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; + /* Get rid of sdpcm header + head_padding */ + PKTPULL(osh, pkt, data_offset); + + DHD_INFO(("%s data_offset %d, PKTLEN %d\n", + __FUNCTION__, data_offset, PKTLEN(osh, pkt))); + + return BCME_OK; +} + +static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt) +{ + int i; + int ret = 0; + osl_t *osh; + bcmsdh_info_t *sdh; + void *pkt = NULL; + void *pkt_chain; + int total_len = 0; + void *head_pkt = NULL; + void *prev_pkt = NULL; + int pad_pkt_len = 0; + int new_pkt_num = 0; + void *new_pkts[MAX_TX_PKTCHAIN_CNT]; + bool wlfc_enabled = FALSE; + + if (bus->dhd->dongle_reset) + return BCME_NOTREADY; + + sdh = bus->sdh; + osh = bus->dhd->osh; + /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */ + new_pkts[0] = NULL; + + for (i = 0; i < num_pkt; i++) { + int pkt_len; + bool last_pkt; + void *new_pkt = NULL; + + pkt = pkts[i]; + ASSERT(pkt); + last_pkt = (i == num_pkt - 1); + pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i, + total_len, last_pkt, &pad_pkt_len, &new_pkt); + if (pkt_len <= 0) + goto done; + if (new_pkt) { + pkt = new_pkt; + new_pkts[new_pkt_num++] = new_pkt; + } + total_len += pkt_len; + + PKTSETNEXT(osh, pkt, NULL); + /* insert the packet into the list */ + head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt); + prev_pkt = pkt; + + } + + /* Update the HW frame tag (total length) in the first pkt of the glom */ + if (bus->txglom_enable) { + uint8 *frame; + + total_len += pad_pkt_len; + frame = (uint8*)PKTDATA(osh, head_pkt); + *(uint16*)frame = (uint16)htol16(total_len); + *(((uint16*)frame) + 1) = (uint16)htol16(~total_len); + + } + +#ifdef DHDENABLE_TAILPAD + /* if a padding packet if needed, insert it to the end of the link list */ + if (pad_pkt_len) { + PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len); + PKTSETNEXT(osh, pkt, bus->pad_pkt); + } +#endif /* DHDENABLE_TAILPAD */ + + /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet + * parameter is not NULL, for non packet chian we pass NULL pkt pointer + * so it will take the aligned length and buffer pointer. + */ + pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL; + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES); + if (ret == BCME_OK) + bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP; + + /* if a padding packet was needed, remove it from the link list as it not a data pkt */ + if (pad_pkt_len && pkt) + PKTSETNEXT(osh, pkt, NULL); + +done: + pkt = head_pkt; + while (pkt) { + void *pkt_next = PKTNEXT(osh, pkt); + PKTSETNEXT(osh, pkt, NULL); + dhdsdio_txpkt_postprocess(bus, pkt); + pkt = pkt_next; + } + + /* new packets might be allocated due to insufficient room for padding, but we + * still have to indicate the original packets to upper layer + */ + for (i = 0; i < num_pkt; i++) { + pkt = pkts[i]; + wlfc_enabled = FALSE; +#ifdef PROP_TXSTATUS + if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) { + wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) != + WLFC_UNSUPPORTED); + } +#endif /* PROP_TXSTATUS */ + if (!wlfc_enabled) { + PKTSETNEXT(osh, pkt, NULL); + dhd_txcomplete(bus->dhd, pkt, ret != 0); + if (free_pkt) + PKTFREE(osh, pkt, TRUE); + } + } + + for (i = 0; i < new_pkt_num; i++) + PKTFREE(osh, new_pkts[i], TRUE); + + return ret; +} + +static uint +dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) +{ + uint cnt = 0; + uint8 tx_prec_map; + uint16 txpktqlen = 0; + uint32 intstatus = 0; + uint retries = 0; + osl_t *osh; + uint datalen = 0; + dhd_pub_t *dhd = bus->dhd; + sdpcmd_regs_t *regs = bus->regs; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + return BCME_NODEVICE; + } + + osh = dhd->osh; + tx_prec_map = ~bus->flowcontrol; + for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) { + int i; + int num_pkt = 1; + void *pkts[MAX_TX_PKTCHAIN_CNT]; + int prec_out; + + dhd_os_sdlock_txq(bus->dhd); + if (bus->txglom_enable) { + num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize); + num_pkt = MIN(num_pkt, ARRAYSIZE(pkts)); + } + num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map)); + for (i = 0; i < num_pkt; i++) { + pkts[i] = pktq_mdeq(&bus->txq, ~bus->flowcontrol, &prec_out); + if (!pkts[i]) { + DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n", + __FUNCTION__)); + ASSERT(0); + break; + } + PKTORPHAN(pkts[i]); + datalen += PKTLEN(osh, pkts[i]); + } + dhd_os_sdunlock_txq(bus->dhd); + + if (i == 0) + break; + if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK) + dhd->tx_errors++; + else + dhd->dstats.tx_bytes += datalen; + cnt += i; + + /* In poll mode, need to check for other events */ + if (!bus->intr && cnt) + { + /* Check device status, signal pending interrupt */ + R_SDREG(intstatus, ®s->intstatus, retries); + bus->f2txdata++; + if (bcmsdh_regfail(bus->sdh)) + break; + if (intstatus & bus->hostintmask) + bus->ipend = TRUE; + } + + } + + dhd_os_sdlock_txq(bus->dhd); + txpktqlen = pktq_len(&bus->txq); + dhd_os_sdunlock_txq(bus->dhd); + + /* Do flow-control if needed */ + if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) { + bool wlfc_enabled = FALSE; +#ifdef PROP_TXSTATUS + wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED); +#endif + if (!wlfc_enabled && dhd_doflow && dhd->txoff) { + dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); + } + } + + return cnt; +} + +static void +dhdsdio_sendpendctl(dhd_bus_t *bus) +{ + bcmsdh_info_t *sdh = bus->sdh; + int ret; + uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; + + if (bus->txglom_enable) + frame_seq += SDPCM_HWEXT_LEN; + + if (*frame_seq != bus->tx_seq) { + DHD_INFO(("%s IOCTL frame seq lag detected!" + " frm_seq:%d != bus->tx_seq:%d, corrected\n", + __FUNCTION__, *frame_seq, bus->tx_seq)); + *frame_seq = bus->tx_seq; + } + + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, + NULL, NULL, NULL, 1); + if (ret == BCME_OK) + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + + bus->ctrl_frame_stat = FALSE; + dhd_wait_event_wakeup(bus->dhd); +} + +int +dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) +{ + static int err_nodevice = 0; + uint8 *frame; + uint16 len; + uint32 swheader; + bcmsdh_info_t *sdh = bus->sdh; + uint8 doff = 0; + int ret = -1; + uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) + return -EIO; + + /* 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) */ + if (dhd_alignctl) { + if ((doff = ((uintptr)frame % DHD_SDALIGN))) { + frame -= doff; + len += doff; + msglen += doff; + bzero(frame, doff + sdpcm_hdrlen); + } + ASSERT(doff < DHD_SDALIGN); + } + doff += sdpcm_hdrlen; + + /* Round send length to next SDIO block */ + if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { + uint16 pad = bus->blocksize - (len % bus->blocksize); + if ((pad <= bus->roundup) && (pad < bus->blocksize)) + len += pad; + } else if (len % DHD_SDALIGN) { + len += DHD_SDALIGN - (len % DHD_SDALIGN); + } + + /* Satisfy length-alignment requirements */ + if (forcealign && (len & (ALIGNMENT - 1))) + len = ROUNDUP(len, ALIGNMENT); + + ASSERT(ISALIGNED((uintptr)frame, 2)); + + + /* Need to lock here to protect txseq and SDIO tx calls */ + dhd_os_sdlock(bus->dhd); + + BUS_WAKE(bus); + + /* Make sure backplane clock is on */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ + *(uint16*)frame = htol16((uint16)msglen); + *(((uint16*)frame) + 1) = htol16(~msglen); + + if (bus->txglom_enable) { + uint32 hwheader1, hwheader2; + /* 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); + htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); + htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + + SDPCM_HWEXT_LEN + sizeof(swheader)); + + hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24); + hwheader2 = (len - (msglen)) << 16; + htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); + htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); + + *(uint16*)frame = htol16(len); + *(((uint16*)frame) + 1) = htol16(~(len)); + } else { + /* 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); + htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); + htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); + } + if (!TXCTLOK(bus)) { + DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", + __FUNCTION__, bus->tx_max, bus->tx_seq)); + bus->ctrl_frame_stat = TRUE; + /* Send from dpc */ + bus->ctrl_frame_buf = frame; + bus->ctrl_frame_len = len; + + if (!bus->dpc_sched) { + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + } + if (bus->ctrl_frame_stat) { + dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); + } + + if (bus->ctrl_frame_stat == FALSE) { + DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); + ret = 0; + } else { + bus->dhd->txcnt_timeout++; + if (!bus->dhd->hang_was_sent) { + DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", + __FUNCTION__, bus->dhd->txcnt_timeout)); + } + ret = -1; + bus->ctrl_frame_stat = FALSE; + goto done; + } + } + + bus->dhd->txcnt_timeout = 0; + bus->ctrl_frame_stat = TRUE; + + if (ret == -1) { +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_CTL_ON()) { + prhex("Tx Frame", frame, len); + } else if (DHD_HDRS_ON()) { + prhex("TxHdr", frame, MIN(len, 16)); + } +#endif + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + frame, len, NULL, NULL, NULL, TXRETRIES); + if (ret == BCME_OK) + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + } + bus->ctrl_frame_stat = FALSE; + +done: + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + + if (ret) + bus->dhd->tx_ctlerrs++; + else + bus->dhd->tx_ctlpkts++; + + if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) + return -ETIMEDOUT; + + if (ret == BCME_NODEVICE) + err_nodevice++; + else + err_nodevice = 0; + + return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0; +} + +int +dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) +{ + int timeleft; + uint rxlen = 0; + bool pending; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) + return -EIO; + + /* Wait until control frame is available */ + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); + + dhd_os_sdlock(bus->dhd); + rxlen = bus->rxlen; + bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); + bus->rxlen = 0; + dhd_os_sdunlock(bus->dhd); + + if (rxlen) { + DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", + __FUNCTION__, rxlen, msglen)); + } else if (timeleft == 0) { +#ifdef DHD_DEBUG + uint32 status, retry = 0; + R_SDREG(status, &bus->regs->intstatus, retry); + DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n", + __FUNCTION__, status)); +#else + DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); +#endif /* DHD_DEBUG */ + dhd_os_sdlock(bus->dhd); + dhdsdio_checkdied(bus, NULL, 0); + dhd_os_sdunlock(bus->dhd); + } else if (pending == TRUE) { + /* signal pending */ + DHD_ERROR(("%s: signal pending\n", __FUNCTION__)); + return -EINTR; + + } else { + DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); + dhd_os_sdlock(bus->dhd); + dhdsdio_checkdied(bus, NULL, 0); + dhd_os_sdunlock(bus->dhd); + } + if (timeleft == 0) { + if (rxlen == 0) + bus->dhd->rxcnt_timeout++; + DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__, + bus->dhd->rxcnt_timeout, rxlen)); + } + else + bus->dhd->rxcnt_timeout = 0; + + if (rxlen) + bus->dhd->rx_ctlpkts++; + else + bus->dhd->rx_ctlerrs++; + + if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) + return -ETIMEDOUT; + + if (bus->dhd->dongle_trap_occured) + return -EREMOTEIO; + + return rxlen ? (int)rxlen : -EIO; +} + +/* IOVar table */ +enum { + IOV_INTR = 1, + IOV_POLLRATE, + IOV_SDREG, + IOV_SBREG, + IOV_SDCIS, + IOV_MEMBYTES, + IOV_RAMSIZE, + IOV_RAMSTART, +#ifdef DHD_DEBUG + IOV_CHECKDIED, + IOV_SERIALCONS, +#endif /* DHD_DEBUG */ + IOV_SET_DOWNLOAD_STATE, + IOV_SOCRAM_STATE, + IOV_FORCEEVEN, + IOV_SDIOD_DRIVE, + IOV_READAHEAD, + IOV_SDRXCHAIN, + IOV_ALIGNCTL, + IOV_SDALIGN, + IOV_DEVRESET, + IOV_CPU, +#if defined(USE_SDIOFIFO_IOVAR) + IOV_WATERMARK, + IOV_MESBUSYCTRL, +#endif /* USE_SDIOFIFO_IOVAR */ +#ifdef SDTEST + IOV_PKTGEN, + IOV_EXTLOOP, +#endif /* SDTEST */ + IOV_SPROM, + IOV_TXBOUND, + IOV_RXBOUND, + IOV_TXMINMAX, + IOV_IDLETIME, + IOV_IDLECLOCK, + IOV_SD1IDLE, + IOV_SLEEP, + IOV_DONGLEISOLATION, + IOV_KSO, + IOV_DEVSLEEP, + IOV_DEVCAP, + IOV_VARS, +#ifdef SOFTAP + IOV_FWPATH, +#endif + IOV_TXGLOMSIZE, + IOV_TXGLOMMODE, + IOV_HANGREPORT, + IOV_TXINRX_THRES +}; + +const bcm_iovar_t dhdsdio_iovars[] = { + {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, + {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 }, + {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 }, + {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, + {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, + {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, + {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, + {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 }, + {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 }, + {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, + {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, + {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, + {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, + {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, + {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 }, + {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, + {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, + {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, +#ifdef DHD_DEBUG + {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, + {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, + {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, + {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, + {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, + {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, +#ifdef DHD_DEBUG + {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, + {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 }, +#endif /* DHD_DEBUG */ +#endif /* DHD_DEBUG */ +#ifdef SDTEST + {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, + {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, +#endif /* SDTEST */ +#if defined(USE_SDIOFIFO_IOVAR) + {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 }, + {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 }, +#endif /* USE_SDIOFIFO_IOVAR */ + {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 }, + {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, + {"kso", IOV_KSO, 0, IOVT_UINT32, 0 }, + {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 }, +#ifdef SOFTAP + {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, +#endif + {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 }, + {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 }, + {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +static void +dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) +{ + uint q1, q2; + + if (!div) { + bcm_bprintf(strbuf, "%s N/A", desc); + } else { + q1 = num / div; + q2 = (100 * (num - (q1 * div))) / div; + bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); + } +} + +void +dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + dhd_bus_t *bus = dhdp->bus; + + bcm_bprintf(strbuf, "Bus SDIO structure:\n"); + bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", + bus->hostintmask, bus->intstatus, bus->sdpcm_ver); + bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n", + bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, + bus->rxlen, bus->rx_seq); + bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n", + bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); + bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n", + bus->pollrate, bus->pollcnt, bus->regfails); + + bcm_bprintf(strbuf, "\nAdditional counters:\n"); +#ifdef DHDENABLE_TAILPAD + bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n", + bus->tx_tailpad_chain, bus->tx_tailpad_pktget); +#endif /* DHDENABLE_TAILPAD */ + bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n", + bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, + bus->rxc_errors); + bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n", + bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); + bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n", + bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); + bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n", + bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); + bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n", + (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, + bus->f2txdata, bus->f1regdata); + { + dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, + (bus->f2rxhdrs + bus->f2rxdata)); + dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); + dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, + (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); + dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); + bcm_bprintf(strbuf, "\n"); + + dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), + bus->dhd->rx_packets); + dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes); + bcm_bprintf(strbuf, "\n"); + + dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata); + dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata); + dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets, + (bus->f2txdata + bus->f1regdata)); + dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount); + bcm_bprintf(strbuf, "\n"); + + dhd_dump_pct(strbuf, "Total: pkts/f2rw", + (bus->dhd->tx_packets + bus->dhd->rx_packets), + (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); + dhd_dump_pct(strbuf, ", pkts/f1sd", + (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata); + dhd_dump_pct(strbuf, ", pkts/sd", + (bus->dhd->tx_packets + bus->dhd->rx_packets), + (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); + dhd_dump_pct(strbuf, ", pkts/int", + (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount); + bcm_bprintf(strbuf, "\n\n"); + } + +#ifdef SDTEST + if (bus->pktgen_count) { + bcm_bprintf(strbuf, "pktgen config and count:\n"); + bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n", + bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, + bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); + bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n", + bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); + } +#endif /* SDTEST */ +#ifdef DHD_DEBUG + bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", + bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); + bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup); +#endif /* DHD_DEBUG */ + bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", + bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); +} + +void +dhd_bus_clearcounts(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; + + bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; + bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; + bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; +#ifdef DHDENABLE_TAILPAD + bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0; +#endif /* DHDENABLE_TAILPAD */ + bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; + bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; + bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; +} + +#ifdef SDTEST +static int +dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg) +{ + dhd_pktgen_t pktgen; + + pktgen.version = DHD_PKTGEN_VERSION; + pktgen.freq = bus->pktgen_freq; + pktgen.count = bus->pktgen_count; + pktgen.print = bus->pktgen_print; + pktgen.total = bus->pktgen_total; + pktgen.minlen = bus->pktgen_minlen; + pktgen.maxlen = bus->pktgen_maxlen; + pktgen.numsent = bus->pktgen_sent; + pktgen.numrcvd = bus->pktgen_rcvd; + pktgen.numfail = bus->pktgen_fail; + pktgen.mode = bus->pktgen_mode; + pktgen.stop = bus->pktgen_stop; + + bcopy(&pktgen, arg, sizeof(pktgen)); + + return 0; +} + +static int +dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) +{ + dhd_pktgen_t pktgen; + uint oldcnt, oldmode; + + bcopy(arg, &pktgen, sizeof(pktgen)); + if (pktgen.version != DHD_PKTGEN_VERSION) + return BCME_BADARG; + + oldcnt = bus->pktgen_count; + oldmode = bus->pktgen_mode; + + bus->pktgen_freq = pktgen.freq; + bus->pktgen_count = pktgen.count; + bus->pktgen_print = pktgen.print; + bus->pktgen_total = pktgen.total; + bus->pktgen_minlen = pktgen.minlen; + bus->pktgen_maxlen = pktgen.maxlen; + bus->pktgen_mode = pktgen.mode; + bus->pktgen_stop = pktgen.stop; + + bus->pktgen_tick = bus->pktgen_ptick = 0; + bus->pktgen_prev_time = jiffies; + bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen); + bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen); + + /* Clear counts for a new pktgen (mode change, or was stopped) */ + if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) { + bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0; + bus->pktgen_prev_rcvd = bus->pktgen_fail = 0; + } + + return 0; +} +#endif /* SDTEST */ + +static void +dhdsdio_devram_remap(dhd_bus_t *bus, bool val) +{ + uint8 enable, protect, remap; + + si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); + remap = val ? TRUE : FALSE; + si_socdevram(bus->sih, TRUE, &enable, &protect, &remap); +} + +static int +dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size) +{ + int bcmerror = 0; + uint32 sdaddr; + uint dsize; + + /* In remap mode, adjust address beyond socram and redirect + * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize + * is not backplane accessible + */ + if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) { + address -= bus->orig_ramsize; + address += SOCDEVRAM_BP_ADDR; + } + + /* 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 */ + if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { + DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); + goto xfer_done; + } + + /* Do the transfer(s) */ + while (size) { + DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n", + __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr, + (address & SBSDIO_SBWINDOW_MASK))); + if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) { + DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__)); + break; + } + + /* Adjust for next transfer (if any) */ + if ((size -= dsize)) { + data += dsize; + address += dsize; + if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { + DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); + break; + } + sdaddr = 0; + dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); + } + + } + +xfer_done: + /* Return the window to backplane enumeration space for core access */ + if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { + DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, + bcmsdh_cur_sbwad(bus->sdh))); + } + + return bcmerror; +} + +static int +dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) +{ + uint32 addr; + int rv, i; + uint32 shaddr = 0; + + if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus)) + bus->srmemsize = 0; + + shaddr = bus->dongle_ram_base + bus->ramsize - 4; + i = 0; + do { + /* Read last word in memory to determine address of sdpcm_shared structure */ + if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) + return rv; + + addr = ltoh32(addr); + + DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); + + /* + * Check if addr is valid. + * NVRAM length at the end of memory should have been overwritten. + */ + if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { + if ((bus->srmemsize > 0) && (i++ == 0)) { + shaddr -= bus->srmemsize; + } else { + DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", + __FUNCTION__, addr)); + return BCME_ERROR; + } + } else + break; + } while (i < 2); + + /* Read hndrte_shared structure */ + if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) + return rv; + + /* Endianness */ + sh->flags = ltoh32(sh->flags); + sh->trap_addr = ltoh32(sh->trap_addr); + sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); + sh->assert_file_addr = ltoh32(sh->assert_file_addr); + sh->assert_line = ltoh32(sh->assert_line); + sh->console_addr = ltoh32(sh->console_addr); + sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); + + if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) + return BCME_OK; + + if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { + DHD_ERROR(("%s: sdpcm_shared version %d in dhd " + "is different than sdpcm_shared version %d in dongle\n", + __FUNCTION__, SDPCM_SHARED_VERSION, + sh->flags & SDPCM_SHARED_VERSION_MASK)); + return BCME_ERROR; + } + + return BCME_OK; +} + +#define CONSOLE_LINE_MAX 192 + +#ifdef DHD_DEBUG +static int +dhdsdio_readconsole(dhd_bus_t *bus) +{ + dhd_console_t *c = &bus->console; + uint8 line[CONSOLE_LINE_MAX], ch; + uint32 n, idx, addr; + int rv; + + /* Don't do anything until FWREADY updates console address */ + if (bus->console_addr == 0) + return 0; + + if (!KSO_ENAB(bus)) + return 0; + + /* Read console log struct */ + addr = bus->console_addr + OFFSETOF(hnd_cons_t, log); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) + return rv; + + /* Allocate console buffer (one time only) */ + if (c->buf == NULL) { + c->bufsize = ltoh32(c->log.buf_size); + if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) + return BCME_NOMEM; + } + + idx = ltoh32(c->log.idx); + + /* Protect against corrupt value */ + if (idx > c->bufsize) + return BCME_ERROR; + + /* Skip reading the console buffer if the index pointer has not moved */ + if (idx == c->last) + return BCME_OK; + + /* Read the console buffer */ + addr = ltoh32(c->log.buf); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 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; + printf("CONSOLE: %s\n", line); +#ifdef LOG_INTO_TCPDUMP + dhd_sendup_log(bus->dhd, line, n); +#endif /* LOG_INTO_TCPDUMP */ + } + } +break2: + + return BCME_OK; +} +#endif /* DHD_DEBUG */ + +static int +dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) +{ + int bcmerror = 0; + uint msize = 512; + char *mbuffer = NULL; + char *console_buffer = NULL; + uint maxstrlen = 256; + char *str = NULL; + trap_t tr; + sdpcm_shared_t sdpcm_shared; + struct bcmstrbuf strbuf; + uint32 console_ptr, console_size, console_index; + uint8 line[CONSOLE_LINE_MAX], ch; + uint32 n, i, addr; + int rv; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (DHD_NOCHECKDIED_ON()) + return 0; + + if (data == NULL) { + /* + * Called after a rx ctrl timeout. "data" is NULL. + * allocate memory to trace the trap or assert. + */ + size = msize; + mbuffer = data = MALLOC(bus->dhd->osh, msize); + if (mbuffer == NULL) { + DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); + bcmerror = BCME_NOMEM; + goto done; + } + } + + if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { + DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); + bcmerror = BCME_NOMEM; + goto done; + } + + if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0) + goto done; + + bcm_binit(&strbuf, data, size); + + bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", + sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); + + if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { + /* NOTE: Misspelled assert is intentional - DO NOT FIX. + * (Avoids conflict with real asserts for programmatic parsing of output.) + */ + bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); + } + + if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) { + /* NOTE: Misspelled assert is intentional - DO NOT FIX. + * (Avoids conflict with real asserts for programmatic parsing of output.) + */ + bcm_bprintf(&strbuf, "No trap%s in dongle", + (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) + ?"/assrt" :""); + } else { + if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { + /* Download assert */ + bcm_bprintf(&strbuf, "Dongle assert"); + if (sdpcm_shared.assert_exp_addr != 0) { + str[0] = '\0'; + if ((bcmerror = dhdsdio_membytes(bus, FALSE, + sdpcm_shared.assert_exp_addr, + (uint8 *)str, maxstrlen)) < 0) + goto done; + + str[maxstrlen - 1] = '\0'; + bcm_bprintf(&strbuf, " expr \"%s\"", str); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + " expr \"%s\"", str); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + } + + if (sdpcm_shared.assert_file_addr != 0) { + str[0] = '\0'; + if ((bcmerror = dhdsdio_membytes(bus, FALSE, + sdpcm_shared.assert_file_addr, + (uint8 *)str, maxstrlen)) < 0) + goto done; + + str[maxstrlen - 1] = '\0'; + bcm_bprintf(&strbuf, " file \"%s\"", str); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + " file \"%s\"", str); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + } + + bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line); + } + + if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { + bus->dhd->dongle_trap_occured = TRUE; + if ((bcmerror = dhdsdio_membytes(bus, FALSE, + sdpcm_shared.trap_addr, + (uint8*)&tr, sizeof(trap_t))) < 0) + goto done; + + bcm_bprintf(&strbuf, + "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," + "lp 0x%x, rpc 0x%x Trap offset 0x%x, " + "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " + "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", + ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), + ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), + ltoh32(sdpcm_shared.trap_addr), + ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), + ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); + +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," + "lp 0x%x, rpc 0x%x Trap offset 0x%x, " + "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " + "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", + ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), + ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), + ltoh32(sdpcm_shared.trap_addr), + ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), + ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, + (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) + goto printbuf; + + addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.buf_size); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, + (uint8 *)&console_size, sizeof(console_size))) < 0) + goto printbuf; + + addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, + (uint8 *)&console_index, sizeof(console_index))) < 0) + goto printbuf; + + console_ptr = ltoh32(console_ptr); + console_size = ltoh32(console_size); + console_index = ltoh32(console_index); + + if (console_size > CONSOLE_BUFFER_MAX || + !(console_buffer = MALLOC(bus->dhd->osh, console_size))) + goto printbuf; + + if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, + (uint8 *)console_buffer, console_size)) < 0) + goto printbuf; + + for (i = 0, n = 0; i < console_size; i += n + 1) { + for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { + ch = console_buffer[(console_index + i + n) % console_size]; + if (ch == '\n') + break; + line[n] = ch; + } + + + if (n > 0) { + if (line[n - 1] == '\r') + n--; + line[n] = 0; + /* Don't use DHD_ERROR macro since we print + * a lot of information quickly. The macro + * will truncate a lot of the printfs + */ + + if (dhd_msg_level & DHD_ERROR_VAL) + printf("CONSOLE: %s\n", line); + } + } + } + } + +printbuf: + if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { + DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); + } + +#if defined(DHD_FW_COREDUMP) + if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { + /* Mem dump to a file on device */ + dhdsdio_mem_dump(bus); + /* In some cases, the host back trace could be relevant too. */ + WARN_ON(1); + } +#endif /* #if defined(DHD_FW_COREDUMP) */ + +done: + if (mbuffer) + MFREE(bus->dhd->osh, mbuffer, msize); + if (str) + MFREE(bus->dhd->osh, str, maxstrlen); + if (console_buffer) + MFREE(bus->dhd->osh, console_buffer, console_size); + + return bcmerror; +} + +#if defined(DHD_FW_COREDUMP) +static int +dhdsdio_mem_dump(dhd_bus_t *bus) +{ + int ret = 0; + int size; /* Full mem size */ + int start = bus->dongle_ram_base; /* Start address */ + int read_size = 0; /* Read size of each iteration */ + uint8 *buf = NULL, *databuf = NULL; + + /* Get full mem size */ + size = bus->ramsize; + buf = dhd_get_fwdump_buf(bus->dhd, size); + if (!buf) { + DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size)); + return -1; + } + + /* Read mem content */ + DHD_ERROR(("Dump dongle memory\n")); + databuf = buf; + while (size) + { + read_size = MIN(MEMBLOCK, size); + if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size))) + { + DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret)); + return -1; + } + /* Decrement size and increment start address */ + size -= read_size; + start += read_size; + databuf += read_size; + } + DHD_ERROR(("Done\n")); + + dhd_schedule_memdump(bus->dhd, buf, bus->ramsize); + /* buf, actually soc_ram free handled in dhd_{free,clear} */ + + + return 0; +} + +int +dhd_bus_mem_dump(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + return dhdsdio_mem_dump(bus); +} +#endif /* DHD_FW_COREDUMP */ + +int +dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) +{ + int bcmerror = BCME_OK; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Basic sanity checks */ + if (bus->dhd->up) { + bcmerror = BCME_NOTDOWN; + goto err; + } + if (!len) { + bcmerror = BCME_BUFTOOSHORT; + goto err; + } + + /* Free the old ones and replace with passed variables */ + if (bus->vars) + MFREE(bus->dhd->osh, bus->vars, bus->varsz); + + bus->vars = MALLOC(bus->dhd->osh, len); + bus->varsz = bus->vars ? len : 0; + if (bus->vars == NULL) { + bcmerror = BCME_NOMEM; + goto err; + } + + /* Copy the passed variables, which should include the terminating double-null */ + bcopy(arg, bus->vars, bus->varsz); +err: + return bcmerror; +} + +#ifdef DHD_DEBUG + +#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) +#define CC_CHIPCTRL_JTAG_SEL (1 << 3) +#define CC_CHIPCTRL_GPIO_SEL (0x3) +#define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28) + +static int +dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) +{ + int int_val; + uint32 addr, data, uart_enab = 0; + uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL; + uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL; + + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + *bcmerror = 0; + + bcmsdh_reg_write(bus->sdh, addr, 4, 1); + if (bcmsdh_regfail(bus->sdh)) { + *bcmerror = BCME_SDIO_ERROR; + return -1; + } + int_val = bcmsdh_reg_read(bus->sdh, data, 4); + if (bcmsdh_regfail(bus->sdh)) { + *bcmerror = BCME_SDIO_ERROR; + return -1; + } + if (bus->sih->chip == BCM4330_CHIP_ID) { + uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; + } + else if (bus->sih->chip == BCM4334_CHIP_ID || + bus->sih->chip == BCM43340_CHIP_ID || + bus->sih->chip == BCM43341_CHIP_ID || + bus->sih->chip == BCM43342_CHIP_ID || + 0) { + if (enable) { + /* Moved to PMU chipcontrol 1 from 4330 */ + int_val &= ~gpio_sel; + int_val |= jtag_sel; + } else { + int_val |= gpio_sel; + int_val &= ~jtag_sel; + } + uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334; + } + + if (!set) + return (int_val & uart_enab); + if (enable) + int_val |= uart_enab; + else + int_val &= ~uart_enab; + bcmsdh_reg_write(bus->sdh, data, 4, int_val); + if (bcmsdh_regfail(bus->sdh)) { + *bcmerror = BCME_SDIO_ERROR; + return -1; + } + if (bus->sih->chip == BCM4330_CHIP_ID) { + uint32 chipcontrol; + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); + chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); + chipcontrol &= ~jtag_sel; + if (enable) { + chipcontrol |= jtag_sel; + chipcontrol &= ~gpio_sel; + } + bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); + } + + return (int_val & uart_enab); +} +#endif + +static int +dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, + void *params, int plen, void *arg, int len, int val_size) +{ + int bcmerror = 0; + int32 int_val = 0; + bool bool_val = 0; + + DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", + __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) + goto exit; + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + + + /* Some ioctls use the bus */ + dhd_os_sdlock(bus->dhd); + + /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ + if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || + actionid == IOV_GVAL(IOV_DEVRESET))) { + bcmerror = BCME_NOTREADY; + goto exit; + } + + /* + * Special handling for keepSdioOn: New SDIO Wake-up Mechanism + */ + if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) { + dhdsdio_clk_kso_iovar(bus, bool_val); + goto exit; + } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { + { + dhdsdio_clk_devsleep_iovar(bus, bool_val); + if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { + DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n", + bus->dpc_sched)); + if (!bus->dpc_sched) { + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + } + } + } + goto exit; + } + + /* Handle sleep stuff before any clock mucking */ + if (vi->varid == IOV_SLEEP) { + if (IOV_ISSET(actionid)) { + bcmerror = dhdsdio_bussleep(bus, bool_val); + } else { + int_val = (int32)bus->sleeping; + bcopy(&int_val, arg, val_size); + } + goto exit; + } + + /* Request clock to allow SDIO accesses */ + if (!bus->dhd->dongle_reset) { + BUS_WAKE(bus); + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + } + + switch (actionid) { + case IOV_GVAL(IOV_INTR): + int_val = (int32)bus->intr; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_INTR): + bus->intr = bool_val; + bus->intdis = FALSE; + if (bus->dhd->up) { + if (bus->intr) { + DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); + bcmsdh_intr_enable(bus->sdh); + } else { + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + bcmsdh_intr_disable(bus->sdh); + } + } + break; + + case IOV_GVAL(IOV_POLLRATE): + int_val = (int32)bus->pollrate; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_POLLRATE): + bus->pollrate = (uint)int_val; + bus->poll = (bus->pollrate != 0); + break; + + case IOV_GVAL(IOV_IDLETIME): + int_val = bus->idletime; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_IDLETIME): + if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) { + bcmerror = BCME_BADARG; + } else { + bus->idletime = int_val; + } + break; + + case IOV_GVAL(IOV_IDLECLOCK): + int_val = (int32)bus->idleclock; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_IDLECLOCK): + bus->idleclock = int_val; + break; + + case IOV_GVAL(IOV_SD1IDLE): + int_val = (int32)sd1idle; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SD1IDLE): + sd1idle = bool_val; + break; + + + case IOV_SVAL(IOV_MEMBYTES): + case IOV_GVAL(IOV_MEMBYTES): + { + uint32 address; + uint size, dsize; + uint8 *data; + + bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); + + ASSERT(plen >= 2*sizeof(int)); + + address = (uint32)int_val; + bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); + size = (uint)int_val; + + /* Do some validation */ + dsize = set ? plen - (2 * sizeof(int)) : len; + if (dsize < size) { + DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", + __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); + bcmerror = BCME_BADARG; + break; + } + + DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, + (set ? "write" : "read"), size, address)); + + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* + * If address is start of RAM (i.e. a downloaded image), + * store the reset instruction to be written in 0 + */ + if (set && address == bus->dongle_ram_base) { + bus->resetinstr = *(((uint32*)params) + 2); + } + } else { + /* If we know about SOCRAM, check for a fit */ + if ((bus->orig_ramsize) && + ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) + { + uint8 enable, protect, remap; + si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); + if (!enable || protect) { + DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", + __FUNCTION__, bus->orig_ramsize, size, address)); + DHD_ERROR(("%s: socram enable %d, protect %d\n", + __FUNCTION__, enable, protect)); + bcmerror = BCME_BADARG; + break; + } + + if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { + uint32 devramsize = si_socdevram_size(bus->sih); + if ((address < SOCDEVRAM_ARM_ADDR) || + (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { + DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n", + __FUNCTION__, address, size)); + DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n", + __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize)); + bcmerror = BCME_BADARG; + break; + } + /* move it such that address is real now */ + address -= SOCDEVRAM_ARM_ADDR; + address += SOCDEVRAM_BP_ADDR; + DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", + __FUNCTION__, (set ? "write" : "read"), size, address)); + } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { + /* Can not access remap region while devram remap bit is set + * ROM content would be returned in this case + */ + DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n", + __FUNCTION__, address)); + bcmerror = BCME_ERROR; + break; + } + } + } + + /* Generate the actual data pointer */ + data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; + + /* Call to do the transfer */ + bcmerror = dhdsdio_membytes(bus, set, address, data, size); + + break; + } + + case IOV_GVAL(IOV_RAMSIZE): + int_val = (int32)bus->ramsize; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_RAMSTART): + int_val = (int32)bus->dongle_ram_base; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_SDIOD_DRIVE): + int_val = (int32)dhd_sdiod_drive_strength; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDIOD_DRIVE): + dhd_sdiod_drive_strength = int_val; + si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength); + break; + + case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): + bcmerror = dhdsdio_download_state(bus, bool_val); + break; + + case IOV_SVAL(IOV_SOCRAM_STATE): + bcmerror = dhdsdio_download_state(bus, bool_val); + break; + + case IOV_SVAL(IOV_VARS): + bcmerror = dhdsdio_downloadvars(bus, arg, len); + break; + + case IOV_GVAL(IOV_READAHEAD): + int_val = (int32)dhd_readahead; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_READAHEAD): + if (bool_val && !dhd_readahead) + bus->nextlen = 0; + dhd_readahead = bool_val; + break; + + case IOV_GVAL(IOV_SDRXCHAIN): + int_val = (int32)bus->use_rxchain; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDRXCHAIN): + if (bool_val && !bus->sd_rxchain) + bcmerror = BCME_UNSUPPORTED; + else + bus->use_rxchain = bool_val; + break; + case IOV_GVAL(IOV_ALIGNCTL): + int_val = (int32)dhd_alignctl; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_ALIGNCTL): + dhd_alignctl = bool_val; + break; + + case IOV_GVAL(IOV_SDALIGN): + int_val = DHD_SDALIGN; + bcopy(&int_val, arg, val_size); + break; + +#ifdef DHD_DEBUG + case IOV_GVAL(IOV_VARS): + if (bus->varsz < (uint)len) + bcopy(bus->vars, arg, bus->varsz); + else + bcmerror = BCME_BUFTOOSHORT; + break; +#endif /* DHD_DEBUG */ + +#ifdef DHD_DEBUG + case IOV_GVAL(IOV_SDREG): + { + sdreg_t *sd_ptr; + uint32 addr, size; + + sd_ptr = (sdreg_t *)params; + + addr = (uint32)((ulong)bus->regs + sd_ptr->offset); + size = sd_ptr->func; + int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); + if (bcmsdh_regfail(bus->sdh)) + bcmerror = BCME_SDIO_ERROR; + bcopy(&int_val, arg, sizeof(int32)); + break; + } + + case IOV_SVAL(IOV_SDREG): + { + sdreg_t *sd_ptr; + uint32 addr, size; + + sd_ptr = (sdreg_t *)params; + + addr = (uint32)((ulong)bus->regs + sd_ptr->offset); + size = sd_ptr->func; + bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value); + if (bcmsdh_regfail(bus->sdh)) + bcmerror = BCME_SDIO_ERROR; + break; + } + + /* Same as above, but offset is not backplane (not SDIO core) */ + case IOV_GVAL(IOV_SBREG): + { + sdreg_t sdreg; + uint32 addr, size; + + bcopy(params, &sdreg, sizeof(sdreg)); + + addr = SI_ENUM_BASE + sdreg.offset; + size = sdreg.func; + int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); + if (bcmsdh_regfail(bus->sdh)) + bcmerror = BCME_SDIO_ERROR; + bcopy(&int_val, arg, sizeof(int32)); + break; + } + + case IOV_SVAL(IOV_SBREG): + { + sdreg_t sdreg; + uint32 addr, size; + + bcopy(params, &sdreg, sizeof(sdreg)); + + addr = SI_ENUM_BASE + sdreg.offset; + size = sdreg.func; + bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value); + if (bcmsdh_regfail(bus->sdh)) + bcmerror = BCME_SDIO_ERROR; + break; + } + + case IOV_GVAL(IOV_SDCIS): + { + *(char *)arg = 0; + + bcmstrcat(arg, "\nFunc 0\n"); + bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); + bcmstrcat(arg, "\nFunc 1\n"); + bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); + bcmstrcat(arg, "\nFunc 2\n"); + bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); + break; + } + + case IOV_GVAL(IOV_FORCEEVEN): + int_val = (int32)forcealign; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_FORCEEVEN): + forcealign = bool_val; + break; + + case IOV_GVAL(IOV_TXBOUND): + int_val = (int32)dhd_txbound; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TXBOUND): + dhd_txbound = (uint)int_val; + break; + + case IOV_GVAL(IOV_RXBOUND): + int_val = (int32)dhd_rxbound; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RXBOUND): + dhd_rxbound = (uint)int_val; + break; + + case IOV_GVAL(IOV_TXMINMAX): + int_val = (int32)dhd_txminmax; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TXMINMAX): + dhd_txminmax = (uint)int_val; + break; + + case IOV_GVAL(IOV_SERIALCONS): + int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); + if (bcmerror != 0) + break; + + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SERIALCONS): + dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); + break; + + +#endif /* DHD_DEBUG */ + + +#ifdef SDTEST + case IOV_GVAL(IOV_EXTLOOP): + int_val = (int32)bus->ext_loop; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_EXTLOOP): + bus->ext_loop = bool_val; + break; + + case IOV_GVAL(IOV_PKTGEN): + bcmerror = dhdsdio_pktgen_get(bus, arg); + break; + + case IOV_SVAL(IOV_PKTGEN): + bcmerror = dhdsdio_pktgen_set(bus, arg); + break; +#endif /* SDTEST */ + +#if defined(USE_SDIOFIFO_IOVAR) + case IOV_GVAL(IOV_WATERMARK): + int_val = (int32)watermark; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_WATERMARK): + watermark = (uint)int_val; + watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark; + DHD_ERROR(("Setting watermark as 0x%x.\n", watermark)); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL); + break; + + case IOV_GVAL(IOV_MESBUSYCTRL): + int_val = (int32)mesbusyctrl; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MESBUSYCTRL): + mesbusyctrl = (uint)int_val; + mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) + ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; + DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl)); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, + ((uint8)mesbusyctrl | 0x80), NULL); + break; +#endif + + + case IOV_GVAL(IOV_DONGLEISOLATION): + int_val = bus->dhd->dongle_isolation; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DONGLEISOLATION): + bus->dhd->dongle_isolation = bool_val; + break; + + case IOV_SVAL(IOV_DEVRESET): + DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", + __FUNCTION__, bool_val, bus->dhd->dongle_reset, + bus->dhd->busstate)); + + ASSERT(bus->dhd->osh); + /* ASSERT(bus->cl_devid); */ + + dhd_bus_devreset(bus->dhd, (uint8)bool_val); + + break; + /* + * softap firmware is updated through module parameter or android private command + */ + + case IOV_GVAL(IOV_DEVRESET): + DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__)); + + /* Get its status */ + int_val = (bool) bus->dhd->dongle_reset; + bcopy(&int_val, arg, val_size); + + break; + + case IOV_GVAL(IOV_KSO): + int_val = dhdsdio_sleepcsr_get(bus); + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_DEVCAP): + int_val = dhdsdio_devcap_get(bus); + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DEVCAP): + dhdsdio_devcap_set(bus, (uint8) int_val); + break; + case IOV_GVAL(IOV_TXGLOMSIZE): + int_val = (int32)bus->txglomsize; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TXGLOMSIZE): + if (int_val > SDPCM_MAXGLOM_SIZE) { + bcmerror = BCME_ERROR; + } else { + bus->txglomsize = (uint)int_val; + } + break; + case IOV_SVAL(IOV_HANGREPORT): + bus->dhd->hang_report = bool_val; + DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report)); + break; + + case IOV_GVAL(IOV_HANGREPORT): + int_val = (int32)bus->dhd->hang_report; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_TXINRX_THRES): + int_val = bus->txinrx_thres; + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_TXINRX_THRES): + if (int_val < 0) { + bcmerror = BCME_BADARG; + } else { + bus->txinrx_thres = int_val; + } + break; + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } + +exit: + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + + return bcmerror; +} + +static int +dhdsdio_write_vars(dhd_bus_t *bus) +{ + int bcmerror = 0; + uint32 varsize, phys_size; + uint32 varaddr; + uint8 *vbuffer; + uint32 varsizew; +#ifdef DHD_DEBUG + uint8 *nvram_ularray; +#endif /* DHD_DEBUG */ + + /* 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; + + varaddr += bus->dongle_ram_base; + + if (bus->vars) { + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { + if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { + DHD_ERROR(("PR85623WAR in place\n")); + varsize += 4; + varaddr -= 4; + } + } + + vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); + if (!vbuffer) + return BCME_NOMEM; + + bzero(vbuffer, varsize); + bcopy(bus->vars, vbuffer, bus->varsz); + + /* Write the vars list */ + bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); +#ifdef DHD_DEBUG + /* Verify NVRAM bytes */ + DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); + nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); + if (!nvram_ularray) + return BCME_NOMEM; + + /* Upload image to verify downloaded contents. */ + memset(nvram_ularray, 0xaa, varsize); + + /* Read the vars list to temp buffer for comparison */ + bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", + __FUNCTION__, bcmerror, varsize, varaddr)); + } + /* Compare the org NVRAM with the one read from RAM */ + if (memcmp(vbuffer, nvram_ularray, varsize)) { + DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); + } else + DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", + __FUNCTION__)); + + MFREE(bus->dhd->osh, nvram_ularray, varsize); +#endif /* DHD_DEBUG */ + + MFREE(bus->dhd->osh, vbuffer, varsize); + } + + phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; + + phys_size += bus->dongle_ram_base; + + /* adjust to the user specified RAM */ + DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", + phys_size, bus->ramsize)); + DHD_INFO(("Vars are at %d, orig varsize is %d\n", + varaddr, varsize)); + varsize = ((phys_size - 4) - varaddr); + + /* + * Determine the length token: + * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. + */ + if (bcmerror) { + varsizew = 0; + } else { + varsizew = varsize / 4; + varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); + varsizew = htol32(varsizew); + } + + DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); + + /* Write the length token to the last word */ + bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4), + (uint8*)&varsizew, 4); + + return bcmerror; +} + +static int +dhdsdio_download_state(dhd_bus_t *bus, bool enter) +{ + uint retries; + int bcmerror = 0; + int foundcr4 = 0; + + if (!bus->sih) + return BCME_ERROR; + /* 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; + + if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && + !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + foundcr4 = 1; + } else { + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + } + + if (!foundcr4) { + si_core_disable(bus->sih, 0); + if (bcmsdh_regfail(bus->sdh)) { + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + si_core_reset(bus->sih, 0, 0); + if (bcmsdh_regfail(bus->sdh)) { + DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", + __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + + /* Disable remap for download */ + if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) + dhdsdio_devram_remap(bus, FALSE); + + if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID) { + /* Disabling Remap for SRAM_3 */ + si_socram_set_bankpda(bus->sih, 0x3, 0x0); + } + + /* Clear the top bit of memory */ + if (bus->ramsize) { + uint32 zeros = 0; + if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, + (uint8*)&zeros, 4) < 0) { + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + } + } else { + /* For CR4, + * Halt ARM + * Remove ARM reset + * Read RAM base address [0x18_0000] + * [next] Download firmware + * [done at else] Populate the reset vector + * [done at else] Remove ARM halt + */ + /* Halt ARM & remove reset */ + si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); + } + } else { + if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + if (!si_iscoreup(bus->sih)) { + DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + if ((bcmerror = dhdsdio_write_vars(bus))) { + DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); + goto fail; + } + + /* Enable remap before ARM reset but after vars. + * No backplane access in remap mode + */ + if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) + dhdsdio_devram_remap(bus, TRUE); + + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && + !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); + + + if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && + !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + } else { + /* cr4 has no socram, but tcm's */ + /* write vars */ + if ((bcmerror = dhdsdio_write_vars(bus))) { + DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); + goto fail; + } + + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && + !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); + + /* switch back to arm core again */ + if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + /* write address 0 with reset instruction */ + bcmerror = dhdsdio_membytes(bus, TRUE, 0, + (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); + + /* now remove reset and halt and continue to run CR4 */ + } + + si_core_reset(bus->sih, 0, 0); + if (bcmsdh_regfail(bus->sdh)) { + DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + + /* Allow HT Clock now that the ARM is running. */ + bus->alp_only = FALSE; + + bus->dhd->busstate = DHD_BUS_LOAD; + } + +fail: + /* Always return to SDIOD core */ + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) + si_setcore(bus->sih, SDIOD_CORE_ID, 0); + + return bcmerror; +} + +int +dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + dhd_bus_t *bus = dhdp->bus; + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + uint32 actionid; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(name); + ASSERT(len >= 0); + + /* Get MUST have return space */ + ASSERT(set || (arg && len)); + + /* Set does NOT take qualifiers */ + ASSERT(!set || (!params && !plen)); + + /* Look up var locally; if not found pass to host driver */ + if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) { + dhd_os_sdlock(bus->dhd); + + BUS_WAKE(bus); + + /* Turn on clock in case SD command needs backplane */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set); + + /* Check for bus configuration changes of interest */ + + /* If it was divisor change, read the new one */ + if (set && strcmp(name, "sd_divisor") == 0) { + if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, + &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { + bus->sd_divisor = -1; + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); + } else { + DHD_INFO(("%s: noted %s update, value now %d\n", + __FUNCTION__, name, bus->sd_divisor)); + } + } + /* If it was a mode change, read the new one */ + if (set && strcmp(name, "sd_mode") == 0) { + if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, + &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { + bus->sd_mode = -1; + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); + } else { + DHD_INFO(("%s: noted %s update, value now %d\n", + __FUNCTION__, name, bus->sd_mode)); + } + } + /* Similar check for blocksize change */ + if (set && strcmp(name, "sd_blocksize") == 0) { + int32 fnum = 2; + if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32), + &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { + bus->blocksize = 0; + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); + } else { + DHD_INFO(("%s: noted %s update, value now %d\n", + __FUNCTION__, "sd_blocksize", bus->blocksize)); + + dhdsdio_tune_fifoparam(bus); + } + } + bus->roundup = MIN(max_roundup, bus->blocksize); + + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + goto exit; + } + + DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, + name, (set ? "set" : "get"), len, plen)); + + /* set up 'params' pointer in case this is a set command so that + * the convenience int and bool code can be common to set and get + */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + /* all other types are integer sized */ + val_size = sizeof(int); + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); + +exit: + return bcmerror; +} + +void +dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) +{ + osl_t *osh; + uint32 local_hostintmask; + uint8 saveclk; + uint retries; + int err; + bool wlfc_enabled = FALSE; + + if (!bus->dhd) + return; + + osh = bus->dhd->osh; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + bcmsdh_waitlockfree(bus->sdh); + + if (enforce_mutex) + dhd_os_sdlock(bus->dhd); + + if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { + /* if Firmware already hangs disbale any interrupt */ + bus->dhd->busstate = DHD_BUS_DOWN; + bus->hostintmask = 0; + bcmsdh_intr_disable(bus->sdh); + } else { + + BUS_WAKE(bus); + + /* Change our idea of bus state */ + bus->dhd->busstate = DHD_BUS_DOWN; + + if (KSO_ENAB(bus)) { + + /* Enable clock for device interrupts */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Disable and clear interrupts at the chip level also */ + W_SDREG(0, &bus->regs->hostintmask, retries); + local_hostintmask = bus->hostintmask; + bus->hostintmask = 0; + + /* Force clocks on backplane to be sure F2 interrupt propagates */ + saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (!err) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); + } + if (err) { + DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", + __FUNCTION__, err)); + } + + /* Turn off the bus (F2), free any pending packets */ + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + bcmsdh_intr_disable(bus->sdh); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); + + /* Clear any pending interrupts now that F2 is disabled */ + W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); + } + + /* Turn off the backplane clock (only) */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } + +#ifdef PROP_TXSTATUS + wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED); +#endif + if (!wlfc_enabled) { +#ifdef DHDTCPACK_SUPPRESS + /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, + * when there is a newly coming packet from network stack. + */ + dhd_tcpack_info_tbl_clean(bus->dhd); +#endif /* DHDTCPACK_SUPPRESS */ + /* Clear the data packet queues */ + pktq_flush(osh, &bus->txq, TRUE, NULL, 0); + } + + /* Clear any held glomming stuff */ + if (bus->glomd) + PKTFREE(osh, bus->glomd, FALSE); + + if (bus->glom) + PKTFREE(osh, bus->glom, FALSE); + + bus->glom = bus->glomd = NULL; + + /* Clear rx control and wake any waiters */ + bus->rxlen = 0; + dhd_os_ioctl_resp_wake(bus->dhd); + + /* Reset some F2 state stuff */ + bus->rxskip = FALSE; + bus->tx_seq = bus->rx_seq = 0; + + bus->tx_max = 4; + + if (enforce_mutex) + dhd_os_sdunlock(bus->dhd); +} + +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD) +extern uint sd_txglom; +#endif +void +dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) +{ + /* can't enable host txglom by default, some platforms have no + * (or crappy) ADMA support and txglom will cause kernel assertions (e.g. + * panda board) + */ + dhd_bus_t *bus = dhdp->bus; +#ifdef BCMSDIOH_TXGLOM + uint32 rxglom; + int32 ret; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + +#ifdef BCMSDIOH_STD + if (enable) + enable = sd_txglom; +#endif /* BCMSDIOH_STD */ + + if (enable) { + rxglom = 1; + ret = dhd_iovar(dhdp, 0, "bus:rxglom", (char *)&rxglom, sizeof(rxglom), NULL, 0, + TRUE); + if (ret >= 0) + bus->txglom_enable = TRUE; + else { +#ifdef BCMSDIOH_STD + sd_txglom = 0; +#endif /* BCMSDIOH_STD */ + bus->txglom_enable = FALSE; + } + } else +#endif /* BCMSDIOH_TXGLOM */ + bus->txglom_enable = FALSE; +} + +int +dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) +{ + dhd_bus_t *bus = dhdp->bus; + dhd_timeout_t tmo; + uint retries = 0; + uint8 ready, enable; + int err, ret = 0; + uint8 saveclk; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(bus->dhd); + if (!bus->dhd) + return 0; + + if (enforce_mutex) + dhd_os_sdlock(bus->dhd); + + /* Make sure backplane clock is on, needed to generate F2 interrupt */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (bus->clkstate != CLK_AVAIL) { + DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate)); + ret = -1; + goto exit; + } + + + /* Force clocks on backplane to be sure F2 interrupt propagates */ + saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (!err) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); + } + if (err) { + DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); + ret = -1; + goto exit; + } + + /* Enable function 2 (frame transfers) */ + W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT), + &bus->regs->tosbmailboxdata, retries); + enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); + + /* Give the dongle some time to do its thing and set IOR2 */ + dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); + + ready = 0; + while (ready != enable && !dhd_timeout_expired(&tmo)) + ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); + + DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", + __FUNCTION__, enable, ready, tmo.elapsed)); + + + /* If F2 successfully enabled, set core and enable interrupts */ + if (ready == enable) { + /* Make sure we're talking to the core. */ + if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) + bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); + ASSERT(bus->regs != NULL); + + /* Set up the interrupt mask and enable interrupts */ + bus->hostintmask = HOSTINTMASK; + /* corerev 4 could use the newer interrupt logic to detect the frames */ + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && + (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { + bus->hostintmask &= ~I_HMB_FRAME_IND; + bus->hostintmask |= I_XMTDATA_AVAIL; + } + W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); + + if (bus->sih->buscorerev < 15) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, + (uint8)watermark, &err); + } + + /* Set bus state according to enable result */ + dhdp->busstate = DHD_BUS_DATA; + + /* bcmsdh_intr_unmask(bus->sdh); */ + + bus->intdis = FALSE; + if (bus->intr) { + DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); + bcmsdh_intr_enable(bus->sdh); + } else { + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + bcmsdh_intr_disable(bus->sdh); + } + + } + + + else { + /* Disable F2 again */ + enable = SDIO_FUNC_ENABLE_1; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); + } + + if (dhdsdio_sr_cap(bus)) { + dhdsdio_sr_init(bus); + /* Masking the chip active interrupt permanantly */ + bus->hostintmask &= ~I_CHIPACTIVE; + W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); + DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n", + __FUNCTION__, bus->hostintmask)); + } + else + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); + + /* If we didn't come up, turn off backplane clock */ + if (dhdp->busstate != DHD_BUS_DATA) + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + +exit: + if (enforce_mutex) + dhd_os_sdunlock(bus->dhd); + + return ret; +} + +static void +dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) +{ + bcmsdh_info_t *sdh = bus->sdh; + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + uint16 lastrbc; + uint8 hi, lo; + int err; + + DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__, + (abort ? "abort command, " : ""), (rtx ? ", send NAK" : ""))); + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + return; + } + + if (abort) { + bcmsdh_abort(sdh, SDIO_FUNC_2); + } + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); + if (err) { + DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__)); + goto fail; + } + bus->f1regdata++; + + /* Wait until the packet has been flushed (device/FIFO stable) */ + for (lastrbc = retries = 0xffff; retries > 0; retries--) { + hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); + lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err); + if (err) { + DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__)); + goto fail; + } + + bus->f1regdata += 2; + + if ((hi == 0) && (lo == 0)) + break; + + if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { + DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n", + __FUNCTION__, lastrbc, ((hi << 8) + lo))); + } + lastrbc = (hi << 8) + lo; + } + + if (!retries) { + DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc)); + } else { + DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries))); + } + + if (rtx) { + bus->rxrtx++; + W_SDREG(SMB_NAK, ®s->tosbmailbox, retries); + bus->f1regdata++; + if (retries <= retry_limit) { + bus->rxskip = TRUE; + } + } + + /* Clear partial in any case */ + bus->nextlen = 0; + +fail: + /* If we can't reach the device, signal failure */ + if (err || bcmsdh_regfail(sdh)) + bus->dhd->busstate = DHD_BUS_DOWN; +} + +static void +dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) +{ + bcmsdh_info_t *sdh = bus->sdh; + uint rdlen, pad; + + int sdret; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Control data already received in aligned rxctl */ + if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) + goto gotpkt; + + ASSERT(bus->rxbuf); + /* Set rxctl for frame (w/optional alignment) */ + bus->rxctl = bus->rxbuf; + if (dhd_alignctl) { + bus->rxctl += firstread; + if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) + bus->rxctl += (DHD_SDALIGN - pad); + bus->rxctl -= firstread; + } + ASSERT(bus->rxctl >= bus->rxbuf); + + /* Copy the already-read portion over */ + bcopy(hdr, bus->rxctl, firstread); + if (len <= firstread) + goto gotpkt; + + /* Copy the full data pkt in gSPI case and process ioctl. */ + if (bus->bus == SPI_BUS) { + bcopy(hdr, bus->rxctl, len); + goto gotpkt; + } + + /* Raise rdlen to next SDIO block to avoid tail command */ + rdlen = len - 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->dhd->maxctl)) + rdlen += pad; + } else if (rdlen % DHD_SDALIGN) { + rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); + } + + /* Satisfy length-alignment requirements */ + if (forcealign && (rdlen & (ALIGNMENT - 1))) + rdlen = ROUNDUP(rdlen, ALIGNMENT); + + /* Drop if the read is too big or it exceeds our maximum */ + if ((rdlen + firstread) > bus->dhd->maxctl) { + DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n", + __FUNCTION__, rdlen, bus->dhd->maxctl)); + bus->dhd->rx_errors++; + dhdsdio_rxfail(bus, FALSE, FALSE); + goto done; + } + + if ((len - doff) > bus->dhd->maxctl) { + DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", + __FUNCTION__, len, (len - doff), bus->dhd->maxctl)); + bus->dhd->rx_errors++; bus->rx_toolong++; + dhdsdio_rxfail(bus, FALSE, FALSE); + goto done; + } + + + /* Read remainder of frame body into the rxctl buffer */ + sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); + bus->f2rxdata++; + ASSERT(sdret != BCME_PENDING); + + /* Control frame failures need retransmission */ + if (sdret < 0) { + DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret)); + bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */ + dhdsdio_rxfail(bus, TRUE, TRUE); + goto done; + } + +gotpkt: + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_CTL_ON()) { + prhex("RxCtrl", bus->rxctl, len); + } +#endif + + /* Point to valid data and indicate its length */ + bus->rxctl += doff; + bus->rxlen = len - doff; + +done: + /* Awake any waiters */ + dhd_os_ioctl_resp_wake(bus->dhd); +} +int +dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, + void **pkt, uint32 *pkt_count); + +static uint8 +dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) +{ + uint16 dlen, totlen; + uint8 *dptr, num = 0; + + uint16 sublen, check; + void *pfirst, *plast, *pnext; + void * list_tail[DHD_MAX_IFS] = { NULL }; + void * list_head[DHD_MAX_IFS] = { NULL }; + uint8 idx; + osl_t *osh = bus->dhd->osh; + + int errcode; + uint8 chan, seq, doff, sfdoff; + uint8 txmax; + uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; + uint reorder_info_len; + + int ifidx = 0; + bool usechain = bus->use_rxchain; + + /* If packets, issue read(s) and send up packet chain */ + /* Return sequence numbers consumed? */ + + DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom)); + + /* If there's a descriptor, generate the packet chain */ + if (bus->glomd) { + dhd_os_sdlock_rxq(bus->dhd); + + pfirst = plast = pnext = NULL; + dlen = (uint16)PKTLEN(osh, bus->glomd); + dptr = PKTDATA(osh, bus->glomd); + if (!dlen || (dlen & 1)) { + DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n", + __FUNCTION__, dlen)); + dlen = 0; + } + + for (totlen = num = 0; dlen; num++) { + /* Get (and move past) next length */ + sublen = ltoh16_ua(dptr); + dlen -= sizeof(uint16); + dptr += sizeof(uint16); + if ((sublen < SDPCM_HDRLEN) || + ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { + DHD_ERROR(("%s: descriptor len %d bad: %d\n", + __FUNCTION__, num, sublen)); + pnext = NULL; + break; + } + if (sublen % DHD_SDALIGN) { + DHD_ERROR(("%s: sublen %d not a multiple of %d\n", + __FUNCTION__, sublen, DHD_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 */ + if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) { + DHD_ERROR(("%s: PKTGET failed, num %d len %d\n", + __FUNCTION__, num, sublen)); + break; + } + ASSERT(!PKTLINK(pnext)); + if (!pfirst) { + ASSERT(!plast); + pfirst = plast = pnext; + } else { + ASSERT(plast); + PKTSETNEXT(osh, plast, pnext); + plast = pnext; + } + + /* Adhere to start alignment requirements */ + PKTALIGN(osh, pnext, sublen, DHD_SDALIGN); + } + + /* If all allocations succeeded, save packet chain in bus structure */ + if (pnext) { + DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n", + __FUNCTION__, totlen, num)); + if (DHD_GLOM_ON() && bus->nextlen) { + if (totlen != bus->nextlen) { + DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d " + "rxseq %d\n", __FUNCTION__, bus->nextlen, + totlen, rxseq)); + } + } + bus->glom = pfirst; + pfirst = pnext = NULL; + } else { + if (pfirst) + PKTFREE(osh, pfirst, FALSE); + bus->glom = NULL; + num = 0; + } + + /* Done with descriptor packet */ + PKTFREE(osh, bus->glomd, FALSE); + bus->glomd = NULL; + bus->nextlen = 0; + + dhd_os_sdunlock_rxq(bus->dhd); + } + + /* Ok -- either we just generated a packet chain, or had one from before */ + if (bus->glom) { + if (DHD_GLOM_ON()) { + DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__)); + for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) { + DHD_GLOM((" %p: %p len 0x%04x (%d)\n", + pnext, (uint8*)PKTDATA(osh, pnext), + PKTLEN(osh, pnext), PKTLEN(osh, pnext))); + } + } + + pfirst = bus->glom; + dlen = (uint16)pkttotlen(osh, 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 = dhd_bcmsdh_recv_buf(bus, + bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, + F2SYNC, (uint8*)PKTDATA(osh, pfirst), + dlen, pfirst, NULL, NULL); + } else if (bus->dataptr) { + errcode = dhd_bcmsdh_recv_buf(bus, + bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, + F2SYNC, bus->dataptr, + dlen, NULL, NULL, NULL); + sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); + if (sublen != dlen) { + DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n", + __FUNCTION__, dlen, sublen)); + errcode = -1; + } + pnext = NULL; + } else { + DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen)); + errcode = -1; + } + bus->f2rxdata++; + ASSERT(errcode != BCME_PENDING); + + /* On failure, kill the superframe, allow a couple retries */ + if (errcode < 0) { + DHD_ERROR(("%s: glom read of %d bytes failed: %d\n", + __FUNCTION__, dlen, errcode)); + bus->dhd->rx_errors++; + + if (bus->glomerr++ < 3) { + dhdsdio_rxfail(bus, TRUE, TRUE); + } else { + bus->glomerr = 0; + dhdsdio_rxfail(bus, TRUE, FALSE); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(osh, bus->glom, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + bus->rxglomfail++; + bus->glom = NULL; + } + return 0; + } + +#ifdef DHD_DEBUG + if (DHD_GLOM_ON()) { + prhex("SUPERFRAME", PKTDATA(osh, pfirst), + MIN(PKTLEN(osh, pfirst), 48)); + } +#endif + + + /* Validate the superframe header */ + dptr = (uint8 *)PKTDATA(osh, pfirst); + sublen = ltoh16_ua(dptr); + check = ltoh16_ua(dptr + sizeof(uint16)); + + 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) { + DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n", + __FUNCTION__, 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 ((uint16)~(sublen^check)) { + DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n", + __FUNCTION__, sublen, check)); + errcode = -1; + } else if (ROUNDUP(sublen, bus->blocksize) != dlen) { + DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", + __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen)); + errcode = -1; + } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) { + DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__, + SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]))); + errcode = -1; + } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { + DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__)); + errcode = -1; + } else if ((doff < SDPCM_HDRLEN) || + (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) { + DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", + __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), + SDPCM_HDRLEN)); + errcode = -1; + } + + /* Check sequence number of superframe SW header */ + if (rxseq != seq) { + DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n", + __FUNCTION__, seq, rxseq)); + bus->rx_badseq++; + rxseq = seq; + } + + /* Check window for sanity */ + if ((uint8)(txmax - bus->tx_seq) > 0x70) { + DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + __FUNCTION__, txmax, bus->tx_seq)); + txmax = bus->tx_max; + } + bus->tx_max = txmax; + + /* Remove superframe header, remember offset */ + PKTPULL(osh, pfirst, doff); + sfdoff = doff; + + /* Validate all the subframe headers */ + for (num = 0, pnext = pfirst; pnext && !errcode; + num++, pnext = PKTNEXT(osh, pnext)) { + dptr = (uint8 *)PKTDATA(osh, pnext); + dlen = (uint16)PKTLEN(osh, pnext); + sublen = ltoh16_ua(dptr); + check = ltoh16_ua(dptr + sizeof(uint16)); + chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); + doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); +#ifdef DHD_DEBUG + if (DHD_GLOM_ON()) { + prhex("subframe", dptr, 32); + } +#endif + + if ((uint16)~(sublen^check)) { + DHD_ERROR(("%s (subframe %d): HW hdr error: " + "len/check 0x%04x/0x%04x\n", + __FUNCTION__, num, sublen, check)); + errcode = -1; + } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { + DHD_ERROR(("%s (subframe %d): length mismatch: " + "len 0x%04x, expect 0x%04x\n", + __FUNCTION__, num, sublen, dlen)); + errcode = -1; + } else if ((chan != SDPCM_DATA_CHANNEL) && + (chan != SDPCM_EVENT_CHANNEL)) { + DHD_ERROR(("%s (subframe %d): bad channel %d\n", + __FUNCTION__, num, chan)); + errcode = -1; + } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { + DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n", + __FUNCTION__, 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 */ + PKTPUSH(osh, pfirst, sfdoff); + dhdsdio_rxfail(bus, TRUE, TRUE); + } else { + bus->glomerr = 0; + dhdsdio_rxfail(bus, TRUE, FALSE); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(osh, bus->glom, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + bus->rxglomfail++; + bus->glom = NULL; + } + bus->nextlen = 0; + return 0; + } + + /* Basic SD framing looks ok - process each packet (header) */ + bus->glom = NULL; + plast = NULL; + + dhd_os_sdlock_rxq(bus->dhd); + for (num = 0; pfirst; rxseq++, pfirst = pnext) { + pnext = PKTNEXT(osh, pfirst); + PKTSETNEXT(osh, pfirst, NULL); + + dptr = (uint8 *)PKTDATA(osh, pfirst); + sublen = ltoh16_ua(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]); + + DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", + __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst), + PKTLEN(osh, pfirst), sublen, chan, seq)); + + ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); + + if (rxseq != seq) { + DHD_GLOM(("%s: rx_seq %d, expected %d\n", + __FUNCTION__, seq, rxseq)); + bus->rx_badseq++; + rxseq = seq; + } + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_DATA_ON()) { + prhex("Rx Subframe Data", dptr, dlen); + } +#endif + + PKTSETLEN(osh, pfirst, sublen); + PKTPULL(osh, pfirst, doff); + + reorder_info_len = sizeof(reorder_info_buf); + + if (PKTLEN(osh, pfirst) == 0) { + PKTFREE(bus->dhd->osh, pfirst, FALSE); + continue; + } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, + &reorder_info_len) != 0) { + DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); + bus->dhd->rx_errors++; + PKTFREE(osh, pfirst, FALSE); + continue; + } + if (reorder_info_len) { + uint32 free_buf_count; + void *ppfirst; + + ppfirst = pfirst; + /* Reordering info from the firmware */ + dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, + reorder_info_len, &ppfirst, &free_buf_count); + + if (free_buf_count == 0) { + continue; + } + else { + void *temp; + + /* go to the end of the chain and attach the pnext there */ + temp = ppfirst; + while (PKTNEXT(osh, temp) != NULL) { + temp = PKTNEXT(osh, temp); + } + pfirst = temp; + if (list_tail[ifidx] == NULL) + list_head[ifidx] = ppfirst; + else + PKTSETNEXT(osh, list_tail[ifidx], ppfirst); + list_tail[ifidx] = pfirst; + } + + num += (uint8)free_buf_count; + } + else { + /* this packet will go up, link back into chain and count it */ + + if (list_tail[ifidx] == NULL) { + list_head[ifidx] = list_tail[ifidx] = pfirst; + } + else { + PKTSETNEXT(osh, list_tail[ifidx], pfirst); + list_tail[ifidx] = pfirst; + } + num++; + } +#ifdef DHD_DEBUG + if (DHD_GLOM_ON()) { + DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n", + __FUNCTION__, num, pfirst, + PKTDATA(osh, pfirst), PKTLEN(osh, pfirst), + PKTNEXT(osh, pfirst), PKTLINK(pfirst))); + prhex("", (uint8 *)PKTDATA(osh, pfirst), + MIN(PKTLEN(osh, pfirst), 32)); + } +#endif /* DHD_DEBUG */ + } + dhd_os_sdunlock_rxq(bus->dhd); + + for (idx = 0; idx < DHD_MAX_IFS; idx++) { + if (list_head[idx]) { + void *temp; + uint8 cnt = 0; + temp = list_head[idx]; + do { + temp = PKTNEXT(osh, temp); + cnt++; + } while (temp); + if (cnt) { + dhd_os_sdunlock(bus->dhd); + dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); + dhd_os_sdlock(bus->dhd); + } + } + } + bus->rxglomframes++; + bus->rxglompkts += num; + } + return num; +} + + +/* Return TRUE if there may be more frames to read */ +static uint +dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) +{ + osl_t *osh = bus->dhd->osh; + bcmsdh_info_t *sdh = bus->sdh; + + uint16 len, check; /* Extracted hardware header fields */ + uint8 chan, seq, doff; /* Extracted software header fields */ + uint8 fcbits; /* Extracted fcbits from software header */ + uint8 delta; + + void *pkt; /* Packet for event or data frames */ + uint16 pad; /* Number of pad bytes to read */ + uint16 rdlen; /* Total number of bytes to read */ + uint8 rxseq; /* Next sequence number to expect */ + uint rxleft = 0; /* Remaining number of frames allowed */ + int sdret; /* Return code from bcmsdh calls */ + uint8 txmax; /* Maximum tx sequence offered */ + bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ + uint8 *rxbuf; + int ifidx = 0; + uint rxcount = 0; /* Total frames read */ + uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; + uint reorder_info_len; + uint pkt_count; + +#if defined(DHD_DEBUG) || defined(SDTEST) + bool sdtest = FALSE; /* To limit message spew from test mode */ +#endif + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + bus->readframes = TRUE; + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: KSO off\n", __FUNCTION__)); + bus->readframes = FALSE; + return 0; + } + + ASSERT(maxframes); + +#ifdef SDTEST + /* Allow pktgen to override maxframes */ + if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { + maxframes = bus->pktgen_count; + sdtest = TRUE; + } +#endif + + /* Not finished unless we encounter no more frames indication */ + *finished = FALSE; + + + for (rxseq = bus->rx_seq, rxleft = maxframes; + !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; + rxseq++, rxleft--) { +#ifdef DHDTCPACK_SUP_DBG + if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) { + if (bus->dotxinrx == FALSE) + DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n", + __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode)); + } +#ifdef DEBUG_COUNTER + else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) { + tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++; + } +#endif /* DEBUG_COUNTER */ +#endif /* DHDTCPACK_SUP_DBG */ + /* tx more to improve rx performance */ + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { + dhdsdio_sendpendctl(bus); + } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) && + !bus->fcstate && DATAOK(bus) && + (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) { + dhdsdio_sendfromq(bus, dhd_txbound); +#ifdef DHDTCPACK_SUPPRESS + /* In TCPACK_SUP_DELAYTX mode, do txinrx only if + * 1. Any DATA packet to TX + * 2. TCPACK to TCPDATA PSH packets. + * in bus txq. + */ + bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ? + FALSE : TRUE; +#endif + } + + /* Handle glomming separately */ + if (bus->glom || bus->glomd) { + uint8 cnt; + DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n", + __FUNCTION__, bus->glomd, bus->glom)); + cnt = dhdsdio_rxglom(bus, rxseq); + DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt)); + rxseq += cnt - 1; + rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; + continue; + } + + /* Try doing single read if we can */ + if (dhd_readahead && bus->nextlen) { + uint16 nextlen = bus->nextlen; + bus->nextlen = 0; + + if (bus->bus == SPI_BUS) { + rdlen = len = nextlen; + } + else { + rdlen = len = nextlen << 4; + + /* 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 + firstread) < MAX_RX_DATASZ)) + rdlen += pad; + } else if (rdlen % DHD_SDALIGN) { + rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); + } + } + + /* We use bus->rxctl buffer in WinXP for initial control pkt receives. + * Later we use buffer-poll for data as well as control packets. + * This is required because dhd receives full frame in gSPI unlike SDIO. + * After the frame is received we have to distinguish whether it is data + * or non-data frame. + */ + /* Allocate a packet buffer */ + dhd_os_sdlock_rxq(bus->dhd); + if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) { + if (bus->bus == SPI_BUS) { + bus->usebufpool = FALSE; + bus->rxctl = bus->rxbuf; + if (dhd_alignctl) { + bus->rxctl += firstread; + if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) + bus->rxctl += (DHD_SDALIGN - pad); + bus->rxctl -= firstread; + } + ASSERT(bus->rxctl >= bus->rxbuf); + rxbuf = bus->rxctl; + /* Read the entire frame */ + sdret = dhd_bcmsdh_recv_buf(bus, + bcmsdh_cur_sbwad(sdh), + SDIO_FUNC_2, + F2SYNC, rxbuf, rdlen, + NULL, NULL, NULL); + bus->f2rxdata++; + ASSERT(sdret != BCME_PENDING); + + + /* Control frame failures need retransmission */ + if (sdret < 0) { + DHD_ERROR(("%s: read %d control bytes failed: %d\n", + __FUNCTION__, rdlen, sdret)); + /* dhd.rx_ctlerrs is higher level */ + bus->rxc_errors++; + dhd_os_sdunlock_rxq(bus->dhd); + dhdsdio_rxfail(bus, TRUE, + (bus->bus == SPI_BUS) ? FALSE : TRUE); + continue; + } + } else { + /* Give up on data, request rtx of events */ + DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d " + "expected rxseq %d\n", + __FUNCTION__, len, rdlen, rxseq)); + /* Just go try again w/normal header read */ + dhd_os_sdunlock_rxq(bus->dhd); + continue; + } + } else { + if (bus->bus == SPI_BUS) + bus->usebufpool = TRUE; + + ASSERT(!PKTLINK(pkt)); + PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); + rxbuf = (uint8 *)PKTDATA(osh, pkt); + /* Read the entire frame */ + sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), + SDIO_FUNC_2, + F2SYNC, rxbuf, rdlen, + pkt, NULL, NULL); + bus->f2rxdata++; + ASSERT(sdret != BCME_PENDING); + + if (sdret < 0) { + DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n", + __FUNCTION__, rdlen, sdret)); + PKTFREE(bus->dhd->osh, pkt, FALSE); + bus->dhd->rx_errors++; + dhd_os_sdunlock_rxq(bus->dhd); + /* Force retry w/normal header read. Don't attempt NAK for + * gSPI + */ + dhdsdio_rxfail(bus, TRUE, + (bus->bus == SPI_BUS) ? FALSE : TRUE); + continue; + } + } + dhd_os_sdunlock_rxq(bus->dhd); + + /* Now check the header */ + bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN); + + /* Extract hardware header fields */ + len = ltoh16_ua(bus->rxhdr); + check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); + + /* All zeros means readahead info was bad */ + if (!(len|check)) { + DHD_INFO(("%s (nextlen): read zeros in HW header???\n", + __FUNCTION__)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + GSPI_PR55150_BAILOUT; + continue; + } + + /* Validate check bytes */ + if ((uint16)~(len^check)) { + DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check" + " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen, + len, check)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + bus->rx_badhdr++; + dhdsdio_rxfail(bus, FALSE, FALSE); + GSPI_PR55150_BAILOUT; + continue; + } + + /* Validate frame length */ + if (len < SDPCM_HDRLEN) { + DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n", + __FUNCTION__, len)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + GSPI_PR55150_BAILOUT; + continue; + } + + /* 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) */ + DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; " + "expected rxseq %d\n", + __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE); + GSPI_PR55150_BAILOUT; + 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) { + DHD_INFO(("%s (nextlen): got frame w/nextlen too large" + " (%d), seq %d\n", __FUNCTION__, bus->nextlen, + seq)); + bus->nextlen = 0; + } + + bus->dhd->rx_readahead_cnt ++; + /* Handle Flow Control */ + fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); + + delta = 0; + if (~bus->flowcontrol & fcbits) { + bus->fc_xoff++; + delta = 1; + } + if (bus->flowcontrol & ~fcbits) { + bus->fc_xon++; + delta = 1; + } + + if (delta) { + bus->fc_rcvd++; + bus->flowcontrol = fcbits; + } + + /* Check and update sequence number */ + if (rxseq != seq) { + DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n", + __FUNCTION__, seq, rxseq)); + bus->rx_badseq++; + rxseq = seq; + } + + /* Check window for sanity */ + if ((uint8)(txmax - bus->tx_seq) > 0x70) { + DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + __FUNCTION__, txmax, bus->tx_seq)); + txmax = bus->tx_max; + } + bus->tx_max = txmax; + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_DATA_ON()) { + prhex("Rx Data", rxbuf, len); + } else if (DHD_HDRS_ON()) { + prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); + } +#endif + + if (chan == SDPCM_CONTROL_CHANNEL) { + if (bus->bus == SPI_BUS) { + dhdsdio_read_control(bus, rxbuf, len, doff); + if (bus->usebufpool) { + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(bus->dhd->osh, pkt, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + } + continue; + } else { + DHD_ERROR(("%s (nextlen): readahead on control" + " packet %d?\n", __FUNCTION__, seq)); + /* Force retry w/normal header read */ + bus->nextlen = 0; + dhdsdio_rxfail(bus, FALSE, TRUE); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + continue; + } + } + + if ((bus->bus == SPI_BUS) && !bus->usebufpool) { + DHD_ERROR(("Received %d bytes on %d channel. Running out of " + "rx pktbuf's or not yet malloced.\n", len, chan)); + continue; + } + + /* Validate data offset */ + if ((doff < SDPCM_HDRLEN) || (doff > len)) { + DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n", + __FUNCTION__, doff, len, SDPCM_HDRLEN)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + ASSERT(0); + dhdsdio_rxfail(bus, FALSE, FALSE); + continue; + } + + /* All done with this one -- now deliver the packet */ + goto deliver; + } + /* gSPI frames should not be handled in fractions */ + if (bus->bus == SPI_BUS) { + break; + } + + /* Read frame header (hardware and software) */ + sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + bus->rxhdr, firstread, NULL, NULL, NULL); + bus->f2rxhdrs++; + ASSERT(sdret != BCME_PENDING); + + if (sdret < 0) { + DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret)); + bus->rx_hdrfail++; + dhdsdio_rxfail(bus, TRUE, TRUE); + continue; + } + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() || DHD_HDRS_ON()) { + prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); + } +#endif + + /* Extract hardware header fields */ + len = ltoh16_ua(bus->rxhdr); + check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); + + /* All zeros means no more frames */ + if (!(len|check)) { + *finished = TRUE; + break; + } + + /* Validate check bytes */ + if ((uint16)~(len^check)) { + DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n", + __FUNCTION__, len, check)); + bus->rx_badhdr++; + dhdsdio_rxfail(bus, FALSE, FALSE); + continue; + } + + /* Validate frame length */ + if (len < SDPCM_HDRLEN) { + DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, 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)) { + DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n", + __FUNCTION__, doff, len, SDPCM_HDRLEN, seq)); + bus->rx_badhdr++; + ASSERT(0); + dhdsdio_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) { + DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n", + __FUNCTION__, bus->nextlen, seq)); + bus->nextlen = 0; + } + + /* Handle Flow Control */ + fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); + + delta = 0; + if (~bus->flowcontrol & fcbits) { + bus->fc_xoff++; + delta = 1; + } + if (bus->flowcontrol & ~fcbits) { + bus->fc_xon++; + delta = 1; + } + + if (delta) { + bus->fc_rcvd++; + bus->flowcontrol = fcbits; + } + + /* Check and update sequence number */ + if (rxseq != seq) { + DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq)); + bus->rx_badseq++; + rxseq = seq; + } + + /* Check window for sanity */ + if ((uint8)(txmax - bus->tx_seq) > 0x70) { + DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + __FUNCTION__, txmax, bus->tx_seq)); + txmax = bus->tx_max; + } + bus->tx_max = txmax; + + /* Call a separate function for control frames */ + if (chan == SDPCM_CONTROL_CHANNEL) { + dhdsdio_read_control(bus, bus->rxhdr, len, doff); + continue; + } + + ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) || + (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL)); + + /* Length to read */ + rdlen = (len > firstread) ? (len - 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 + firstread) < MAX_RX_DATASZ)) + rdlen += pad; + } else if (rdlen % DHD_SDALIGN) { + rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); + } + + /* Satisfy length-alignment requirements */ + if (forcealign && (rdlen & (ALIGNMENT - 1))) + rdlen = ROUNDUP(rdlen, ALIGNMENT); + + if ((rdlen + firstread) > MAX_RX_DATASZ) { + /* Too long -- skip this frame */ + DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen)); + bus->dhd->rx_errors++; bus->rx_toolong++; + dhdsdio_rxfail(bus, FALSE, FALSE); + continue; + } + + dhd_os_sdlock_rxq(bus->dhd); + if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) { + /* Give up on data, request rtx of events */ + DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n", + __FUNCTION__, rdlen, chan)); + bus->dhd->rx_dropped++; + dhd_os_sdunlock_rxq(bus->dhd); + dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan)); + continue; + } + dhd_os_sdunlock_rxq(bus->dhd); + + ASSERT(!PKTLINK(pkt)); + + /* Leave room for what we already read, and align remainder */ + ASSERT(firstread < (PKTLEN(osh, pkt))); + PKTPULL(osh, pkt, firstread); + PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); + + /* Read the remaining frame data */ + sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); + bus->f2rxdata++; + ASSERT(sdret != BCME_PENDING); + + if (sdret < 0) { + DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen, + ((chan == SDPCM_EVENT_CHANNEL) ? "event" : + ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(bus->dhd->osh, pkt, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + bus->dhd->rx_errors++; + dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan)); + continue; + } + + /* Copy the already-read portion */ + PKTPUSH(osh, pkt, firstread); + bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread); + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_DATA_ON()) { + prhex("Rx Data", PKTDATA(osh, pkt), len); + } +#endif + +deliver: + /* Save superframe descriptor and allocate packet frame */ + if (chan == SDPCM_GLOM_CHANNEL) { + if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { + DHD_GLOM(("%s: got glom descriptor, %d bytes:\n", + __FUNCTION__, len)); +#ifdef DHD_DEBUG + if (DHD_GLOM_ON()) { + prhex("Glom Data", PKTDATA(osh, pkt), len); + } +#endif + PKTSETLEN(osh, pkt, len); + ASSERT(doff == SDPCM_HDRLEN); + PKTPULL(osh, pkt, SDPCM_HDRLEN); + bus->glomd = pkt; + } else { + DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__)); + dhdsdio_rxfail(bus, FALSE, FALSE); + } + continue; + } + + /* Fill in packet len and prio, deliver upward */ + PKTSETLEN(osh, pkt, len); + PKTPULL(osh, pkt, doff); + +#ifdef SDTEST + /* Test channel packets are processed separately */ + if (chan == SDPCM_TEST_CHANNEL) { + dhdsdio_testrcv(bus, pkt, seq); + continue; + } +#endif /* SDTEST */ + + if (PKTLEN(osh, pkt) == 0) { + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(bus->dhd->osh, pkt, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + continue; + } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf, + &reorder_info_len) != 0) { + DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(bus->dhd->osh, pkt, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + bus->dhd->rx_errors++; + continue; + } + if (reorder_info_len) { + /* Reordering info from the firmware */ + dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len, + &pkt, &pkt_count); + if (pkt_count == 0) + continue; + } + else + pkt_count = 1; + + /* Unlock during rx call */ + dhd_os_sdunlock(bus->dhd); + dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); + dhd_os_sdlock(bus->dhd); + } + rxcount = maxframes - rxleft; +#ifdef DHD_DEBUG + /* Message if we hit the limit */ + if (!rxleft && !sdtest) + DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes)); + else +#endif /* DHD_DEBUG */ + DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount)); + /* Back off rxseq if awaiting rtx, update rx_seq */ + if (bus->rxskip) + rxseq--; + bus->rx_seq = rxseq; + + if (bus->reqbussleep) + { + dhdsdio_bussleep(bus, TRUE); + bus->reqbussleep = FALSE; + } + bus->readframes = FALSE; + + return rxcount; +} + +static uint32 +dhdsdio_hostmail(dhd_bus_t *bus) +{ + sdpcmd_regs_t *regs = bus->regs; + uint32 intstatus = 0; + uint32 hmb_data; + uint8 fcbits; + uint retries = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Read mailbox data and ack that we did so */ + R_SDREG(hmb_data, ®s->tohostmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries); + bus->f1regdata += 2; + + /* Dongle recomposed rx frames, accept them again */ + if (hmb_data & HMB_DATA_NAKHANDLED) { + DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq)); + if (!bus->rxskip) { + DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__)); + } + bus->rxskip = FALSE; + intstatus |= FRAME_AVAIL_MASK(bus); + } + + /* + * 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) + DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n", + bus->sdpcm_ver, SDPCM_PROT_VERSION)); + else + DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver)); + /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && + (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { + uint32 val; + + val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); + val &= ~CC_XMTDATAAVAIL_MODE; + val |= CC_XMTDATAAVAIL_CTRL; + W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); + + val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); + } + +#ifdef DHD_DEBUG + /* Retrieve console state address now that firmware should have updated it */ + { + sdpcm_shared_t shared; + if (dhdsdio_readshared(bus, &shared) == 0) + bus->console_addr = shared.console_addr; + } +#endif /* DHD_DEBUG */ + } + + /* + * Flow Control has been moved into the RX headers and this out of band + * method isn't used any more. Leave this here for possibly 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; + } + + /* At least print a message if FW halted */ + if (hmb_data & HMB_DATA_FWHALT) { + DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n")); + dhdsdio_checkdied(bus, NULL, 0); + bus->dhd->busstate = DHD_BUS_DOWN; + } + + /* Shouldn't be any others */ + if (hmb_data & ~(HMB_DATA_DEVREADY | + HMB_DATA_FWHALT | + HMB_DATA_NAKHANDLED | + HMB_DATA_FC | + HMB_DATA_FWREADY | + HMB_DATA_FCDATA_MASK | + HMB_DATA_VERSION_MASK)) { + DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data)); + } + + return intstatus; +} + +static bool +dhdsdio_dpc(dhd_bus_t *bus) +{ + bcmsdh_info_t *sdh = bus->sdh; + sdpcmd_regs_t *regs = bus->regs; + uint32 intstatus, newstatus = 0; + uint retries = 0; + uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */ + uint txlimit = dhd_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 */ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + dhd_os_sdlock(bus->dhd); + + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); + bus->intstatus = 0; + dhd_os_sdunlock(bus->dhd); + return 0; + } + + /* Start with leftover status bits */ + intstatus = bus->intstatus; + + if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + goto exit; + } + + /* If waiting for HTAVAIL, check status */ + if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) { + int err; + uint8 clkctl, devctl = 0; + +#ifdef DHD_DEBUG + /* Check for inconsistent device control */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + if (err) { + DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err)); + bus->dhd->busstate = DHD_BUS_DOWN; + } else { + ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); + } +#endif /* DHD_DEBUG */ + + /* Read CSR, if clock on switch to AVAIL, else ignore */ + clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (err) { + DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err)); + bus->dhd->busstate = DHD_BUS_DOWN; + } + + DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl)); + + if (SBSDIO_HTAV(clkctl)) { + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + if (err) { + DHD_ERROR(("%s: error reading DEVCTL: %d\n", + __FUNCTION__, err)); + bus->dhd->busstate = DHD_BUS_DOWN; + } + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + if (err) { + DHD_ERROR(("%s: error writing DEVCTL: %d\n", + __FUNCTION__, err)); + bus->dhd->busstate = DHD_BUS_DOWN; + } + bus->clkstate = CLK_AVAIL; + } else { + goto clkwait; + } + } + + BUS_WAKE(bus); + + /* Make sure backplane clock is on */ + dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); + if (bus->clkstate != CLK_AVAIL) + goto clkwait; + + /* Pending interrupt indicates new device status */ + if (bus->ipend) { + bus->ipend = FALSE; + R_SDREG(newstatus, ®s->intstatus, retries); + bus->f1regdata++; + if (bcmsdh_regfail(bus->sdh)) + newstatus = 0; + newstatus &= bus->hostintmask; + bus->fcstate = !!(newstatus & I_HMB_FC_STATE); + if (newstatus) { + bus->f1regdata++; + if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && + (newstatus == I_XMTDATA_AVAIL)) { + } + else + W_SDREG(newstatus, ®s->intstatus, retries); + } + } + + /* 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_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries); + R_SDREG(newstatus, ®s->intstatus, retries); + bus->f1regdata += 2; + bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); + intstatus |= (newstatus & bus->hostintmask); + } + + /* Just being here means nothing more to do for chipactive */ + if (intstatus & I_CHIPACTIVE) { + /* ASSERT(bus->clkstate == CLK_AVAIL); */ + intstatus &= ~I_CHIPACTIVE; + } + + /* Handle host mailbox indication */ + if (intstatus & I_HMB_HOST_INT) { + intstatus &= ~I_HMB_HOST_INT; + intstatus |= dhdsdio_hostmail(bus); + } + + /* Generally don't ask for these, can get CRC errors... */ + if (intstatus & I_WR_OOSYNC) { + DHD_ERROR(("Dongle reports WR_OOSYNC\n")); + intstatus &= ~I_WR_OOSYNC; + } + + if (intstatus & I_RD_OOSYNC) { + DHD_ERROR(("Dongle reports RD_OOSYNC\n")); + intstatus &= ~I_RD_OOSYNC; + } + + if (intstatus & I_SBINT) { + DHD_ERROR(("Dongle reports SBINT\n")); + intstatus &= ~I_SBINT; + } + + /* Would be active due to wake-wlan in gSPI */ + if (intstatus & I_CHIPACTIVE) { + DHD_INFO(("Dongle reports CHIPACTIVE\n")); + intstatus &= ~I_CHIPACTIVE; + } + + if (intstatus & I_HMB_FC_STATE) { + DHD_INFO(("Dongle reports HMB_FC_STATE\n")); + intstatus &= ~I_HMB_FC_STATE; + } + + /* Ignore frame indications if rxskip is set */ + if (bus->rxskip) { + intstatus &= ~FRAME_AVAIL_MASK(bus); + } + + /* On frame indication, read available frames */ + if (PKT_AVAILABLE(bus, intstatus)) { + framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); + if (rxdone || bus->rxskip) + intstatus &= ~FRAME_AVAIL_MASK(bus); + rxlimit -= MIN(framecnt, rxlimit); + } + + /* Keep still-pending events for next scheduling */ + bus->intstatus = intstatus; + +clkwait: + /* Re-enable interrupts to detect new device events (mailbox, rx frame) + * or clock availability. (Allows tx loop to check ipend if desired.) + * (Unless register access seems hosed, as we may not be able to ACK...) + */ + if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) { + DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", + __FUNCTION__, rxdone, framecnt)); + bus->intdis = FALSE; +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(bus->sdh, TRUE); +#endif /* defined(OOB_INTR_ONLY) */ + bcmsdh_intr_enable(sdh); + } + +#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) + /* In case of SW-OOB(using edge trigger), + * Check interrupt status in the dongle again after enable irq on the host. + * and rechedule dpc if interrupt is pended in the dongle. + * There is a chance to miss OOB interrupt while irq is disabled on the host. + * No need to do this with HW-OOB(level trigger) + */ + R_SDREG(newstatus, ®s->intstatus, retries); + if (bcmsdh_regfail(bus->sdh)) + newstatus = 0; + if (newstatus & bus->hostintmask) { + bus->ipend = TRUE; + resched = TRUE; + } +#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ + +#ifdef PROP_TXSTATUS + dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE); +#endif + + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) + dhdsdio_sendpendctl(bus); + + /* Send queued frames (limit 1 if rx may still be pending) */ + else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && + pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { + framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax); + framecnt = dhdsdio_sendfromq(bus, framecnt); + txlimit -= framecnt; + } + /* Resched the DPC if ctrl cmd is pending on bus credit */ + if (bus->ctrl_frame_stat) + resched = TRUE; + + /* 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->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { + if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & + SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { + /* Bus failed because of KSO */ + DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__)); + bus->kso = FALSE; + } else { + DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n", + __FUNCTION__)); + bus->dhd->busstate = DHD_BUS_DOWN; + bus->intstatus = 0; + } + } else if (bus->clkstate == CLK_PENDING) { + /* Awaiting I_CHIPACTIVE; don't resched */ + } else if (bus->intstatus || bus->ipend || + (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || + PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ + resched = TRUE; + } + + bus->dpc_sched = resched; + + /* If we're done for now, turn off clock request. */ + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + } + +exit: + + if (!resched && dhd_dpcpoll) { + if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) + resched = TRUE; + } + + dhd_os_sdunlock(bus->dhd); + return resched; +} + +bool +dhd_bus_dpc(struct dhd_bus *bus) +{ + bool resched; + + /* Call the DPC directly. */ + DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); + resched = dhdsdio_dpc(bus); + + return resched; +} + +void +dhdsdio_isr(void *arg) +{ + dhd_bus_t *bus = (dhd_bus_t*)arg; + bcmsdh_info_t *sdh; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!bus) { + DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); + return; + } + sdh = bus->sdh; + + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + return; + } + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Count the interrupt call */ + bus->intrcount++; + bus->ipend = TRUE; + + /* Shouldn't get this interrupt if we're sleeping? */ + if (!SLPAUTO_ENAB(bus)) { + if (bus->sleeping) { + DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n")); + return; + } else if (!KSO_ENAB(bus)) { + DHD_ERROR(("ISR in devsleep 1\n")); + } + } + + /* Disable additional interrupts (is this needed now)? */ + if (bus->intr) { + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + } else { + DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n")); + } + + bcmsdh_intr_disable(sdh); + bus->intdis = TRUE; + +#if defined(SDIO_ISR_THREAD) + DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); + DHD_OS_WAKE_LOCK(bus->dhd); + dhdsdio_dpc(bus); + DHD_OS_WAKE_UNLOCK(bus->dhd); +#else + + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + +#endif /* defined(SDIO_ISR_THREAD) */ + +} + +#ifdef SDTEST +static void +dhdsdio_pktgen_init(dhd_bus_t *bus) +{ + /* Default to specified length, or full range */ + if (dhd_pktgen_len) { + bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN); + bus->pktgen_minlen = bus->pktgen_maxlen; + } else { + bus->pktgen_maxlen = MAX_PKTGEN_LEN; + bus->pktgen_minlen = 0; + } + bus->pktgen_len = (uint16)bus->pktgen_minlen; + + /* Default to per-watchdog burst with 10s print time */ + bus->pktgen_freq = 1; + bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0; + bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; + + /* Default to echo mode */ + bus->pktgen_mode = DHD_PKTGEN_ECHO; + bus->pktgen_stop = 1; +} + +static void +dhdsdio_pktgen(dhd_bus_t *bus) +{ + void *pkt; + uint8 *data; + uint pktcount; + uint fillbyte; + osl_t *osh = bus->dhd->osh; + uint16 len; + ulong time_lapse; + uint sent_pkts; + uint rcvd_pkts; + + /* Display current count if appropriate */ + if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { + bus->pktgen_ptick = 0; + printf("%s: send attempts %d, rcvd %d, errors %d\n", + __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); + + /* Print throughput stats only for constant length packet runs */ + if (bus->pktgen_minlen == bus->pktgen_maxlen) { + time_lapse = jiffies - bus->pktgen_prev_time; + bus->pktgen_prev_time = jiffies; + sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent; + bus->pktgen_prev_sent = bus->pktgen_sent; + rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd; + bus->pktgen_prev_rcvd = bus->pktgen_rcvd; + + printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n", + __FUNCTION__, + (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8, + (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8); + } + } + + /* For recv mode, just make sure dongle has started sending */ + if (bus->pktgen_mode == DHD_PKTGEN_RECV) { + if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { + bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; + dhdsdio_sdtest_set(bus, bus->pktgen_total); + } + return; + } + + /* Otherwise, generate or request the specified number of packets */ + for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) { + /* Stop if total has been reached */ + if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) { + bus->pktgen_count = 0; + break; + } + + /* Allocate an appropriate-sized packet */ + if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { + len = SDPCM_TEST_PKT_CNT_FLD_LEN; + } else { + len = bus->pktgen_len; + } + if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), + TRUE))) {; + DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); + break; + } + PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); + data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; + + /* Write test header cmd and extra based on mode */ + switch (bus->pktgen_mode) { + case DHD_PKTGEN_ECHO: + *data++ = SDPCM_TEST_ECHOREQ; + *data++ = (uint8)bus->pktgen_sent; + break; + + case DHD_PKTGEN_SEND: + *data++ = SDPCM_TEST_DISCARD; + *data++ = (uint8)bus->pktgen_sent; + break; + + case DHD_PKTGEN_RXBURST: + *data++ = SDPCM_TEST_BURST; + *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */ + break; + + default: + DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode)); + PKTFREE(osh, pkt, TRUE); + bus->pktgen_count = 0; + return; + } + + /* Write test header length field */ + *data++ = (bus->pktgen_len >> 0); + *data++ = (bus->pktgen_len >> 8); + + /* Write frame count in a 4 byte field adjucent to SDPCM test header for + * burst mode + */ + if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { + *data++ = (uint8)(bus->pktgen_count >> 0); + *data++ = (uint8)(bus->pktgen_count >> 8); + *data++ = (uint8)(bus->pktgen_count >> 16); + *data++ = (uint8)(bus->pktgen_count >> 24); + } else { + + /* Then fill in the remainder -- N/A for burst */ + for (fillbyte = 0; fillbyte < len; fillbyte++) + *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); + } + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_DATA_ON()) { + data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; + prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN); + } +#endif + + /* Send it */ + if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) { + bus->pktgen_fail++; + if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) + bus->pktgen_count = 0; + } + bus->pktgen_sent++; + + /* Bump length if not fixed, wrap at max */ + if (++bus->pktgen_len > bus->pktgen_maxlen) + bus->pktgen_len = (uint16)bus->pktgen_minlen; + + /* Special case for burst mode: just send one request! */ + if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) + break; + } +} + +static void +dhdsdio_sdtest_set(dhd_bus_t *bus, uint count) +{ + void *pkt; + uint8 *data; + osl_t *osh = bus->dhd->osh; + + /* Allocate the packet */ + if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + + SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) { + DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); + return; + } + PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + + SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN); + data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; + + /* Fill in the test header */ + *data++ = SDPCM_TEST_SEND; + *data++ = (count > 0)?TRUE:FALSE; + *data++ = (bus->pktgen_maxlen >> 0); + *data++ = (bus->pktgen_maxlen >> 8); + *data++ = (uint8)(count >> 0); + *data++ = (uint8)(count >> 8); + *data++ = (uint8)(count >> 16); + *data++ = (uint8)(count >> 24); + + /* Send it */ + if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) + bus->pktgen_fail++; +} + + +static void +dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) +{ + osl_t *osh = bus->dhd->osh; + uint8 *data; + uint pktlen; + + uint8 cmd; + uint8 extra; + uint16 len; + uint16 offset; + + /* Check for min length */ + if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) { + DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen)); + PKTFREE(osh, pkt, FALSE); + return; + } + + /* Extract header fields */ + data = PKTDATA(osh, pkt); + cmd = *data++; + extra = *data++; + len = *data++; len += *data++ << 8; + DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len)); + /* Check length for relevant commands */ + if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { + if (pktlen != len + SDPCM_TEST_HDRLEN) { + DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d" + " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); + PKTFREE(osh, pkt, FALSE); + return; + } + } + + /* Process as per command */ + switch (cmd) { + case SDPCM_TEST_ECHOREQ: + /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ + *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; + if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) { + bus->pktgen_sent++; + } else { + bus->pktgen_fail++; + PKTFREE(osh, pkt, FALSE); + } + bus->pktgen_rcvd++; + break; + + case SDPCM_TEST_ECHORSP: + if (bus->ext_loop) { + PKTFREE(osh, pkt, FALSE); + bus->pktgen_rcvd++; + break; + } + + for (offset = 0; offset < len; offset++, data++) { + if (*data != SDPCM_TEST_FILL(offset, extra)) { + DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: " + "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n", + offset, len, SDPCM_TEST_FILL(offset, extra), *data)); + break; + } + } + PKTFREE(osh, pkt, FALSE); + bus->pktgen_rcvd++; + break; + + case SDPCM_TEST_DISCARD: + { + int i = 0; + uint8 *prn = data; + uint8 testval = extra; + for (i = 0; i < len; i++) { + if (*prn != testval) { + DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", + i, bus->pktgen_rcvd_rcvsession, testval, *prn)); + prn++; testval++; + } + } + } + PKTFREE(osh, pkt, FALSE); + bus->pktgen_rcvd++; + break; + + case SDPCM_TEST_BURST: + case SDPCM_TEST_SEND: + default: + DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d" + " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); + PKTFREE(osh, pkt, FALSE); + break; + } + + /* For recv mode, stop at limit (and tell dongle to stop sending) */ + if (bus->pktgen_mode == DHD_PKTGEN_RECV) { + if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { + bus->pktgen_rcvd_rcvsession++; + + if (bus->pktgen_total && + (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { + bus->pktgen_count = 0; + DHD_ERROR(("Pktgen:rcv test complete!\n")); + bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; + dhdsdio_sdtest_set(bus, FALSE); + bus->pktgen_rcvd_rcvsession = 0; + } + } + } +} +#endif /* SDTEST */ + +int dhd_bus_oob_intr_register(dhd_pub_t *dhdp) +{ + int err = 0; + +#if defined(OOB_INTR_ONLY) + err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus); +#endif + return err; +} + +void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp) +{ +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_unregister(dhdp->bus->sdh); +#endif +} + +void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable) +{ +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(dhdp->bus->sdh, enable); +#endif +} + +void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub) +{ + bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh); +} + +void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub) +{ + bcmsdh_dev_relax(dhdpub->bus->sdh); +} + +bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub) +{ + bool enabled = FALSE; + + enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh); + return enabled; +} + +extern bool +dhd_bus_watchdog(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus; + + DHD_TIMER(("%s: Enter\n", __FUNCTION__)); + + bus = dhdp->bus; + + if (bus->dhd->dongle_reset) + return FALSE; + + if (bus->dhd->hang_was_sent) { + dhd_os_wd_timer(bus->dhd, 0); + return FALSE; + } + + /* Ignore the timer if simulating bus down */ + if (!SLPAUTO_ENAB(bus) && bus->sleeping) + return FALSE; + + if (dhdp->busstate == DHD_BUS_DOWN) + return FALSE; + + dhd_os_sdlock(bus->dhd); + + /* Poll period: check device if appropriate. */ + if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) { + uint32 intstatus = 0; + + /* Reset poll tick */ + bus->polltick = 0; + + /* Check device if no interrupts */ + if (!bus->intr || (bus->intrcount == bus->lastintrs)) { + + if (!bus->dpc_sched) { + uint8 devpend; + devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, + SDIOD_CCCR_INTPEND, 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; + if (bus->intr) { + bcmsdh_intr_disable(bus->sdh); + } + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + } + } + + /* Update interrupt tracking */ + bus->lastintrs = bus->intrcount; + } + +#ifdef DHD_DEBUG + /* Poll for console output periodically */ + if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { + bus->console.count += dhd_watchdog_ms; + if (bus->console.count >= dhd_console_ms) { + bus->console.count -= dhd_console_ms; + /* Make sure backplane clock is on */ + if (SLPAUTO_ENAB(bus)) + dhdsdio_bussleep(bus, FALSE); + else + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (dhdsdio_readconsole(bus) < 0) + dhd_console_ms = 0; /* On error, stop trying */ + } + } +#endif /* DHD_DEBUG */ + +#ifdef SDTEST + /* Generate packets if configured */ + if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { + /* Make sure backplane clock is on */ + if (SLPAUTO_ENAB(bus)) + dhdsdio_bussleep(bus, FALSE); + else + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + bus->pktgen_tick = 0; + dhdsdio_pktgen(bus); + } +#endif + + /* On idle timeout clear activity flag and/or turn off clock */ +#ifdef DHD_USE_IDLECOUNT + if (bus->activity) + bus->activity = FALSE; + else { + bus->idlecount++; + + if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) { + DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); + if (SLPAUTO_ENAB(bus)) { + if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) + dhd_os_wd_timer(bus->dhd, 0); + } else + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + + bus->idlecount = 0; + } + } +#else + if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { + if (++bus->idlecount >= bus->idletime) { + bus->idlecount = 0; + if (bus->activity) { + bus->activity = FALSE; + if (SLPAUTO_ENAB(bus)) { + if (!bus->readframes) + dhdsdio_bussleep(bus, TRUE); + else + bus->reqbussleep = TRUE; + } + else + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + } + } + } +#endif /* DHD_USE_IDLECOUNT */ + + dhd_os_sdunlock(bus->dhd); + + return bus->ipend; +} + +#ifdef DHD_DEBUG +extern int +dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) +{ + dhd_bus_t *bus = dhdp->bus; + uint32 addr, val; + int rv; + void *pkt; + + /* Address could be zero if CONSOLE := 0 in dongle Makefile */ + if (bus->console_addr == 0) + return BCME_UNSUPPORTED; + + /* Exclusive bus access */ + dhd_os_sdlock(bus->dhd); + + /* Don't allow input if dongle is in reset */ + if (bus->dhd->dongle_reset) { + dhd_os_sdunlock(bus->dhd); + return BCME_NOTREADY; + } + + /* Request clock to allow SDIO accesses */ + BUS_WAKE(bus); + /* No pend allowed since txpkt is called later, ht clk has to be on */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Zero cbuf_index */ + addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx); + val = htol32(0); + if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) + goto done; + + /* Write message into cbuf */ + addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf); + if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) + goto done; + + /* Write length into vcons_in */ + addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in); + val = htol32(msglen); + if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) + goto done; + + /* Bump dongle by sending an empty packet on the event channel. + * sdpcm_sendup (RX) checks for virtual console input. + */ + if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) + rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE); + +done: + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + + return rv; +} +#endif /* DHD_DEBUG */ + +#ifdef DHD_DEBUG +static void +dhd_dump_cis(uint fn, uint8 *cis) +{ + uint byte, tag, tdata; + DHD_INFO(("Function %d CIS:\n", fn)); + + for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { + if ((byte % 16) == 0) + DHD_INFO((" ")); + DHD_INFO(("%02x ", cis[byte])); + if ((byte % 16) == 15) + DHD_INFO(("\n")); + if (!tdata--) { + tag = cis[byte]; + if (tag == 0xff) + break; + else if (!tag) + tdata = 0; + else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) + tdata = cis[byte + 1] + 1; + else + DHD_INFO(("]")); + } + } + if ((byte % 16) != 15) + DHD_INFO(("\n")); +} +#endif /* DHD_DEBUG */ + +static bool +dhdsdio_chipmatch(uint16 chipid) +{ + if (chipid == BCM4325_CHIP_ID) + return TRUE; + if (chipid == BCM4329_CHIP_ID) + return TRUE; + if (chipid == BCM4315_CHIP_ID) + return TRUE; + if (chipid == BCM4319_CHIP_ID) + return TRUE; + if (chipid == BCM4336_CHIP_ID) + return TRUE; + if (chipid == BCM4330_CHIP_ID) + return TRUE; + if (chipid == BCM43237_CHIP_ID) + return TRUE; + if (chipid == BCM43362_CHIP_ID) + return TRUE; + if (chipid == BCM4314_CHIP_ID) + return TRUE; + if (chipid == BCM43242_CHIP_ID) + return TRUE; + if (chipid == BCM43340_CHIP_ID) + return TRUE; + if (chipid == BCM43341_CHIP_ID) + return TRUE; + if (chipid == BCM43143_CHIP_ID) + return TRUE; + if (chipid == BCM43342_CHIP_ID) + return TRUE; + if (chipid == BCM4334_CHIP_ID) + return TRUE; + if (chipid == BCM43239_CHIP_ID) + return TRUE; + if (chipid == BCM4324_CHIP_ID) + return TRUE; + if (chipid == BCM4335_CHIP_ID) + return TRUE; + if (chipid == BCM4339_CHIP_ID) + return TRUE; + if (chipid == BCM43349_CHIP_ID) + return TRUE; + if (chipid == BCM4345_CHIP_ID) + return TRUE; + if (chipid == BCM4350_CHIP_ID) + return TRUE; + if (chipid == BCM4354_CHIP_ID) + return TRUE; + if (chipid == BCM4356_CHIP_ID) + return TRUE; + if (chipid == BCM4358_CHIP_ID) + return TRUE; + if (chipid == BCM43430_CHIP_ID) + return TRUE; + if (BCM4349_CHIP(chipid)) + return TRUE; + return FALSE; +} + +static void * +dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, + uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) +{ + int ret; + dhd_bus_t *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. + */ + dhd_txbound = DHD_TXBOUND; + dhd_rxbound = DHD_RXBOUND; + dhd_alignctl = TRUE; + sd1idle = TRUE; + dhd_readahead = TRUE; + retrydata = FALSE; + dhd_doflow = FALSE; + dhd_dongle_ramsize = 0; + dhd_txminmax = DHD_TXMINMAX; + + forcealign = TRUE; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid)); + + /* We make assumptions about address window mappings */ + ASSERT((uintptr)regsva == SI_ENUM_BASE); + + /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start + * means early parse could fail, so here we should get either an ID + * we recognize OR (-1) indicating we must request power first. + */ + /* Check the Vendor ID */ + switch (venid) { + case 0x0000: + case VENDOR_BROADCOM: + break; + default: + DHD_ERROR(("%s: unknown vendor: 0x%04x\n", + __FUNCTION__, venid)); + goto forcereturn; + } + + /* Check the Device ID and make sure it's one that we support */ + switch (devid) { + case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */ + case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */ + case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */ + DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__)); + break; + case BCM4329_D11N_ID: /* 4329 802.11n dualband device */ + case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */ + case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */ + case 0x4329: + DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__)); + break; + case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */ + case BCM4315_D11G_ID: /* 4315 802.11g id */ + case BCM4315_D11A_ID: /* 4315 802.11a id */ + DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__)); + break; + case BCM4319_D11N_ID: /* 4319 802.11n id */ + case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ + case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ + DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__)); + break; + case 0: + DHD_INFO(("%s: allow device id 0, will check chip internals\n", + __FUNCTION__)); + break; + + default: + DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", + __FUNCTION__, venid, devid)); + goto forcereturn; + } + + if (osh == NULL) { + DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__)); + goto forcereturn; + } + + /* Allocate private bus interface state */ + if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { + DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); + goto fail; + } + bzero(bus, sizeof(dhd_bus_t)); + bus->sdh = sdh; + bus->cl_devid = (uint16)devid; + bus->bus = DHD_BUS; + bus->bus_num = bus_no; + bus->slot_num = slot; + 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 (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { + DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__)); + goto fail; + } + + /* Attach to the dhd/OS/network interface */ + if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) { + DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); + goto fail; + } + + /* Allocate buffers */ + if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { + DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__)); + goto fail; + } + + if (!(dhdsdio_probe_init(bus, osh, sdh))) { + DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__)); + goto fail; + } + + if (bus->intr) { + /* Register interrupt callback, but mask it (not operational yet). */ + DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__)); + bcmsdh_intr_disable(sdh); + if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { + DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n", + __FUNCTION__, ret)); + goto fail; + } + DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__)); + } else { + DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n", + __FUNCTION__)); + } + + DHD_INFO(("%s: completed!!\n", __FUNCTION__)); + + /* if firmware path present try to download and bring up bus */ + bus->dhd->hang_report = TRUE; + if (dhd_download_fw_on_driverload) { + if ((ret = dhd_bus_start(bus->dhd)) != 0) { + DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); + goto fail; + } + } + /* Ok, have the per-port tell the stack we're open for business */ + if (dhd_register_if(bus->dhd, 0, TRUE) != 0) { + DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); + goto fail; + } + + + + init_waitqueue_head(&bus->bus_sleep); + + return bus; + +fail: + dhdsdio_release(bus, osh); + +forcereturn: + + return NULL; +} + +static bool +dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, + uint16 devid) +{ + int err = 0; + uint8 clkctl = 0; + + bus->alp_only = TRUE; + bus->sih = NULL; + + /* Return the window to backplane enumeration space for core access */ + if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) { + DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__)); + } + +#if defined(DHD_DEBUG) + DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n", + bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4))); +#endif + + + /* Force PLL off until si_attach() programs PLL control regs */ + + + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err); + if (!err) + clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + + if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) { + DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", + err, DHD_INIT_CLKCTL1, clkctl)); + goto fail; + } + +#ifdef DHD_DEBUG + if (DHD_INFO_ON()) { + uint fn, numfn; + uint8 *cis[SDIOD_MAX_IOFUNCS]; + int err = 0; + + numfn = bcmsdh_query_iofnum(sdh); + ASSERT(numfn <= SDIOD_MAX_IOFUNCS); + + /* Make sure ALP is available before trying to read CIS */ + SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, NULL)), + !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY); + + /* Now request ALP be put on the bus */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + DHD_INIT_CLKCTL2, &err); + OSL_DELAY(65); + + for (fn = 0; fn <= numfn; fn++) { + if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { + DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn)); + break; + } + bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); + + if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) { + DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err)); + MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); + break; + } + dhd_dump_cis(fn, cis[fn]); + } + + while (fn-- > 0) { + ASSERT(cis[fn]); + MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); + } + + if (err) { + DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n")); + goto fail; + } + } +#endif /* DHD_DEBUG */ + + /* si_attach() will provide an SI handle and scan the backplane */ + if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, + &bus->vars, &bus->varsz))) { + DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); + goto fail; + } + +#ifdef DHD_DEBUG + DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n", + bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg)); +#endif /* DHD_DEBUG */ + + + bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); + + if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { + DHD_ERROR(("%s: unsupported chip: 0x%04x\n", + __FUNCTION__, bus->sih->chip)); + goto fail; + } + + if (bus->sih->buscorerev >= 12) + dhdsdio_clk_kso_init(bus); + else + bus->kso = TRUE; + + if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) { + } + + si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); + + + /* Get info on the ARM and SOCRAM cores... */ + if (!DHD_NOPMU(bus)) { + if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || + (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || + (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { + bus->armrev = si_corerev(bus->sih); + } else { + DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); + goto fail; + } + + if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { + DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); + goto fail; + } + } else { + /* cr4 has a different way to find the RAM size from TCM's */ + if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { + DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); + goto fail; + } + /* also populate base address */ + switch ((uint16)bus->sih->chip) { + case BCM4335_CHIP_ID: + case BCM4339_CHIP_ID: + case BCM43349_CHIP_ID: + bus->dongle_ram_base = CR4_4335_RAM_BASE; + break; + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM4356_CHIP_ID: + case BCM4358_CHIP_ID: + bus->dongle_ram_base = CR4_4350_RAM_BASE; + break; + case BCM4360_CHIP_ID: + bus->dongle_ram_base = CR4_4360_RAM_BASE; + break; + case BCM4345_CHIP_ID: + bus->dongle_ram_base = CR4_4345_RAM_BASE; + break; + case BCM4349_CHIP_GRPID: + bus->dongle_ram_base = CR4_4349_RAM_BASE; + break; + default: + bus->dongle_ram_base = 0; + DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", + __FUNCTION__, bus->dongle_ram_base)); + } + } + bus->ramsize = bus->orig_ramsize; + if (dhd_dongle_ramsize) + dhd_dongle_setramsize(bus, dhd_dongle_ramsize); + + DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", + bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); + + bus->srmemsize = si_socram_srmem_size(bus->sih); + } + + /* ...but normally deal with the SDPCMDEV core */ + if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) && + !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) { + DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__)); + goto fail; + } + bus->sdpcmrev = si_corerev(bus->sih); + + /* Set core control so an SDIO reset does a backplane reset */ + OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); + bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; + + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && + (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) + { + uint32 val; + + val = R_REG(osh, &bus->regs->corecontrol); + val &= ~CC_XMTDATAAVAIL_MODE; + val |= CC_XMTDATAAVAIL_CTRL; + W_REG(osh, &bus->regs->corecontrol, val); + } + + + pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); + + /* Locate an appropriately-aligned portion of hdrbuf */ + bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); + + /* Set the poll and/or interrupt flags */ + bus->intr = (bool)dhd_intr; + if ((bus->poll = (bool)dhd_poll)) + bus->pollrate = 1; + + /* Setting default Glom size */ + bus->txglomsize = SDPCM_DEFGLOM_SIZE; + + return TRUE; + +fail: + if (bus->sih != NULL) { + si_detach(bus->sih); + bus->sih = NULL; + } + return FALSE; +} + +static bool +dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->maxctl) { + bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; + if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) { + DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", + __FUNCTION__, bus->rxblen)); + goto fail; + } + } + /* Allocate buffer to receive glomed packet */ + if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { + DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", + __FUNCTION__, MAX_DATA_BUF)); + /* release rxbuf which was already located as above */ + if (!bus->rxblen) + DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen); + goto fail; + } + + /* Align the buffer */ + if ((uintptr)bus->databuf % DHD_SDALIGN) + bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN)); + else + bus->dataptr = bus->databuf; + + return TRUE; + +fail: + return FALSE; +} + +static bool +dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) +{ + int32 fnum; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + bus->_srenab = FALSE; + +#ifdef SDTEST + dhdsdio_pktgen_init(bus); +#endif /* SDTEST */ + + /* Disable F2 to clear any intermediate frame state on the dongle */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); + + bus->dhd->busstate = DHD_BUS_DOWN; + bus->sleeping = FALSE; + bus->rxflow = FALSE; + bus->prev_rxlim_hit = 0; + + /* Done with backplane-dependent accesses, can drop clock... */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + + /* ...and initialize clock/power states */ + bus->clkstate = CLK_SDONLY; + bus->idletime = (int32)dhd_idletime; + bus->idleclock = DHD_IDLE_ACTIVE; + + /* Query the SD clock speed */ + if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, + &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor")); + bus->sd_divisor = -1; + } else { + DHD_INFO(("%s: Initial value for %s is %d\n", + __FUNCTION__, "sd_divisor", bus->sd_divisor)); + } + + /* Query the SD bus mode */ + if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, + &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode")); + bus->sd_mode = -1; + } else { + DHD_INFO(("%s: Initial value for %s is %d\n", + __FUNCTION__, "sd_mode", bus->sd_mode)); + } + + /* Query the F2 block size, set roundup accordingly */ + fnum = 2; + if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32), + &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { + bus->blocksize = 0; + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); + } else { + DHD_INFO(("%s: Initial value for %s is %d\n", + __FUNCTION__, "sd_blocksize", bus->blocksize)); + + dhdsdio_tune_fifoparam(bus); + } + bus->roundup = MIN(max_roundup, bus->blocksize); + +#ifdef DHDENABLE_TAILPAD + if (bus->pad_pkt) + PKTFREE(osh, bus->pad_pkt, FALSE); + bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE); + if (bus->pad_pkt == NULL) + DHD_ERROR(("failed to allocate padding packet\n")); + else { + int alignment_offset = 0; + uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt); + if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN))) + PKTPUSH(osh, bus->pad_pkt, alignment_offset); + PKTSETNEXT(osh, bus->pad_pkt, NULL); + } +#endif /* DHDENABLE_TAILPAD */ + + /* Query if bus module supports packet chaining, default to use if supported */ + if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, + &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) { + bus->sd_rxchain = FALSE; + } else { + DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n", + __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support"))); + } + bus->use_rxchain = (bool)bus->sd_rxchain; + bus->txinrx_thres = CUSTOM_TXINRX_THRES; + /* TX first in dhdsdio_readframes() */ + bus->dotxinrx = TRUE; + + return TRUE; +} + +int +dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, + char *pfw_path, char *pnv_path) +{ + int ret; + + bus->fw_path = pfw_path; + bus->nv_path = pnv_path; + + ret = dhdsdio_download_firmware(bus, osh, bus->sdh); + + + return ret; +} + +static int +dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) +{ + int ret; + +#if defined(SUPPORT_MULTIPLE_REVISION) + if (concate_revision(bus, bus->fw_path, bus->nv_path) != 0) { + DHD_ERROR(("%s: fail to concatnate revison \n", + __FUNCTION__)); + return BCME_BADARG; + } +#endif /* SUPPORT_MULTIPLE_REVISION */ + + DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n", + __FUNCTION__, bus->fw_path, bus->nv_path)); + DHD_OS_WAKE_LOCK(bus->dhd); + + /* Download the firmware */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + ret = _dhdsdio_download_firmware(bus); + + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + + DHD_OS_WAKE_UNLOCK(bus->dhd); + return ret; +} + +/* Detach and free everything */ +static void +dhdsdio_release(dhd_bus_t *bus, osl_t *osh) +{ + bool dongle_isolation = FALSE; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus) { + ASSERT(osh); + + if (bus->dhd) { + dongle_isolation = bus->dhd->dongle_isolation; + dhd_detach(bus->dhd); + } + + /* De-register interrupt handler */ + bcmsdh_intr_disable(bus->sdh); + bcmsdh_intr_dereg(bus->sdh); + + if (bus->dhd) { + dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); + dhd_free(bus->dhd); + bus->dhd = NULL; + } + + dhdsdio_release_malloc(bus, osh); + +#ifdef DHD_DEBUG + if (bus->console.buf != NULL) + MFREE(osh, bus->console.buf, bus->console.bufsize); +#endif + +#ifdef DHDENABLE_TAILPAD + if (bus->pad_pkt) + PKTFREE(osh, bus->pad_pkt, FALSE); +#endif /* DHDENABLE_TAILPAD */ + + MFREE(osh, bus, sizeof(dhd_bus_t)); + } + + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); +} + +static void +dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd && bus->dhd->dongle_reset) + return; + + if (bus->rxbuf) { +#ifndef CONFIG_DHD_USE_STATIC_BUF + MFREE(osh, bus->rxbuf, bus->rxblen); +#endif + bus->rxctl = bus->rxbuf = NULL; + bus->rxlen = 0; + } + + if (bus->databuf) { +#ifndef CONFIG_DHD_USE_STATIC_BUF + MFREE(osh, bus->databuf, MAX_DATA_BUF); +#endif + bus->databuf = NULL; + } + + if (bus->vars && bus->varsz) { + MFREE(osh, bus->vars, bus->varsz); + bus->vars = NULL; + } + +} + + +static void +dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) +{ + DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, + bus->dhd, bus->dhd->dongle_reset)); + + if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) + return; + + if (bus->sih) { +#if !defined(BCMLXSDMMC) + if (bus->dhd) { + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + } + if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) + si_watchdog(bus->sih, 4); +#endif /* !defined(BCMLXSDMMC) */ + if (bus->dhd) { + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + } + si_detach(bus->sih); + bus->sih = NULL; + if (bus->vars && bus->varsz) + MFREE(osh, bus->vars, bus->varsz); + bus->vars = NULL; + } + + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); +} + +static void +dhdsdio_disconnect(void *ptr) +{ + dhd_bus_t *bus = (dhd_bus_t *)ptr; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + + + if (bus) { + ASSERT(bus->dhd); + dhdsdio_release(bus, bus->dhd->osh); + } + + + + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); +} + +static int +dhdsdio_suspend(void *context) +{ + int ret = 0; + + dhd_bus_t *bus = (dhd_bus_t*)context; + int wait_time = 0; + if (bus->idletime > 0) { + wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms); + } + + ret = dhd_os_check_wakelock(bus->dhd); + if ((!ret) && (bus->dhd->up)) { + if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) { + if (!bus->sleeping) { + return 1; + } + } + } + return ret; +} + +static int +dhdsdio_resume(void *context) +{ +#if defined(OOB_INTR_ONLY) + dhd_bus_t *bus = (dhd_bus_t*)context; + + if (dhd_os_check_if_up(bus->dhd)) + bcmsdh_oob_intr_set(bus->sdh, TRUE); +#endif + return 0; +} + + +/* Register/Unregister functions are called by the main DHD entry + * point (e.g. module insertion) to link with the bus driver, in + * order to look for or await the device. + */ + +static bcmsdh_driver_t dhd_sdio = { + dhdsdio_probe, + dhdsdio_disconnect, + dhdsdio_suspend, + dhdsdio_resume +}; + +int +dhd_bus_register(void) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + return bcmsdh_register(&dhd_sdio); +} + +void +dhd_bus_unregister(void) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + bcmsdh_unregister(); +} + +#if defined(BCMLXSDMMC) +/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ +int dhd_bus_reg_sdio_notify(void* semaphore) +{ + return bcmsdh_reg_sdio_notify(semaphore); +} + +void dhd_bus_unreg_sdio_notify(void) +{ + bcmsdh_unreg_sdio_notify(); +} +#endif /* defined(BCMLXSDMMC) */ + +#ifdef BCMEMBEDIMAGE +static int +dhdsdio_download_code_array(struct dhd_bus *bus) +{ + int bcmerror = -1; + int offset = 0; + unsigned char *ularray = NULL; + + DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__)); + + /* Download image */ + while ((offset + MEMBLOCK) < sizeof(dlarray)) { + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)dlarray)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + + bcmerror = dhdsdio_membytes(bus, TRUE, offset, + (uint8 *) (dlarray + offset), MEMBLOCK); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + + offset += MEMBLOCK; + } + + if (offset < sizeof(dlarray)) { + bcmerror = dhdsdio_membytes(bus, TRUE, offset, + (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); + goto err; + } + } + +#ifdef DHD_DEBUG + /* Upload and compare the downloaded code */ + { + ularray = MALLOC(bus->dhd->osh, bus->ramsize); + /* Upload image to verify downloaded contents. */ + offset = 0; + memset(ularray, 0xaa, bus->ramsize); + while ((offset + MEMBLOCK) < sizeof(dlarray)) { + bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + + offset += MEMBLOCK; + } + + if (offset < sizeof(dlarray)) { + bcmerror = dhdsdio_membytes(bus, FALSE, offset, + ularray + offset, sizeof(dlarray) - offset); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); + goto err; + } + } + + if (memcmp(dlarray, ularray, sizeof(dlarray))) { + DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", + __FUNCTION__, dlimagename, dlimagever, dlimagedate)); + goto err; + } else + DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", + __FUNCTION__, dlimagename, dlimagever, dlimagedate)); + + } +#endif /* DHD_DEBUG */ + +err: + if (ularray) + MFREE(bus->dhd->osh, ularray, bus->ramsize); + return bcmerror; +} +#endif /* BCMEMBEDIMAGE */ + +static int +dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) +{ + int bcmerror = -1; + int offset = 0; + int len; + void *image = NULL; + uint8 *memblock = NULL, *memptr; + + DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); + + image = dhd_os_open_image(pfw_path); + if (image == NULL) + goto err; + + memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); + if (memblock == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); + goto err; + } + if ((uint32)(uintptr)memblock % DHD_SDALIGN) + memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); + + /* Download image */ + while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { + if (len < 0) { + DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); + bcmerror = BCME_ERROR; + goto err; + } + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)memptr)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + + bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + + offset += MEMBLOCK; + } + +err: + if (memblock) + MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); + + if (image) + dhd_os_close_image(image); + + return bcmerror; +} + +/* + EXAMPLE: nvram_array + nvram_arry format: + name=value + Use carriage return at the end of each assignment, and an empty string with + carriage return at the end of array. + + For example: + unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"}; + Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx. + + Search "EXAMPLE: nvram_array" to see how the array is activated. +*/ + +void +dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params) +{ + bus->nvram_params = nvram_params; +} + +static int +dhdsdio_download_nvram(struct dhd_bus *bus) +{ + int bcmerror = -1; + uint len; + void * image = NULL; + char * memblock = NULL; + char *bufp; + char *pnv_path; + bool nvram_file_exists; + + pnv_path = bus->nv_path; + + nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); + if (!nvram_file_exists && (bus->nvram_params == NULL)) + return (0); + + if (nvram_file_exists) { + image = dhd_os_open_image(pnv_path); + if (image == NULL) + goto err; + } + + memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); + if (memblock == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", + __FUNCTION__, MAX_NVRAMBUF_SIZE)); + goto err; + } + + /* Download variables */ + if (nvram_file_exists) { + len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); + } + else { + len = strlen(bus->nvram_params); + ASSERT(len <= MAX_NVRAMBUF_SIZE); + memcpy(memblock, bus->nvram_params, len); + } + if (len > 0 && len < MAX_NVRAMBUF_SIZE) { + bufp = (char *)memblock; + bufp[len] = 0; + len = process_nvram_vars(bufp, len); + if (len % 4) { + len += 4 - (len % 4); + } + bufp += len; + *bufp++ = 0; + if (len) + bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1); + if (bcmerror) { + DHD_ERROR(("%s: error downloading vars: %d\n", + __FUNCTION__, bcmerror)); + } + } + else { + DHD_ERROR(("%s: error reading nvram file: %d\n", + __FUNCTION__, len)); + bcmerror = BCME_SDIO_ERROR; + } + +err: + if (memblock) + MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); + + if (image) + dhd_os_close_image(image); + + return bcmerror; +} + +static int +_dhdsdio_download_firmware(struct dhd_bus *bus) +{ + int bcmerror = -1; + + bool embed = FALSE; /* download embedded firmware */ + bool dlok = FALSE; /* download firmware succeeded */ + + /* Out immediately if no image to download */ + if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { +#ifdef BCMEMBEDIMAGE + embed = TRUE; +#else + return 0; +#endif + } + + /* Keep arm in reset */ + if (dhdsdio_download_state(bus, TRUE)) { + DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); + goto err; + } + + /* External image takes precedence if specified */ + if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { + if (dhdsdio_download_code_file(bus, bus->fw_path)) { + DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); +#ifdef BCMEMBEDIMAGE + embed = TRUE; +#else + goto err; +#endif + } + else { + embed = FALSE; + dlok = TRUE; + } + } + +#ifdef BCMEMBEDIMAGE + if (embed) { + if (dhdsdio_download_code_array(bus)) { + DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); + goto err; + } + else { + dlok = TRUE; + } + } +#else + BCM_REFERENCE(embed); +#endif + if (!dlok) { + DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); + goto err; + } + + /* EXAMPLE: nvram_array */ + /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ + /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ + + /* External nvram takes precedence if specified */ + if (dhdsdio_download_nvram(bus)) { + DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); + goto err; + } + + /* Take arm out of reset */ + if (dhdsdio_download_state(bus, FALSE)) { + DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); + goto err; + } + + bcmerror = 0; + +err: + return bcmerror; +} + +static int +dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, + void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) +{ + int status; + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + return BCME_NODEVICE; + } + + status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle); + + return status; +} + +static int +dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, + void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry) +{ + int ret; + int i = 0; + int retries = 0; + bcmsdh_info_t *sdh; + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + return BCME_NODEVICE; + } + + sdh = bus->sdh; + do { + ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, + pkt, complete, handle); + + bus->f2txdata++; + ASSERT(ret != BCME_PENDING); + + if (ret == BCME_NODEVICE) { + DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); + } else if (ret < 0) { + /* On failure, abort the command and terminate the frame */ + DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n", + __FUNCTION__, ret)); + bus->tx_sderrs++; + bus->f1regdata++; + bus->dhd->tx_errors++; + bcmsdh_abort(sdh, SDIO_FUNC_2); + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, NULL); + for (i = 0; i < READ_FRM_CNT_RETRIES; i++) { + uint8 hi, lo; + hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI, + NULL); + lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO, + NULL); + bus->f1regdata += 2; + if ((hi == 0) && (lo == 0)) + break; + } + } + } while ((ret < 0) && retrydata && ++retries < max_retry); + + return ret; +} + +uint +dhd_bus_chip(struct dhd_bus *bus) +{ + ASSERT(bus->sih != NULL); + return bus->sih->chip; +} + +uint +dhd_bus_chiprev(struct dhd_bus *bus) +{ + ASSERT(bus); + ASSERT(bus->sih != NULL); + return bus->sih->chiprev; +} + +void * +dhd_bus_pub(struct dhd_bus *bus) +{ + return bus->dhd; +} + +void * +dhd_bus_sih(struct dhd_bus *bus) +{ + return (void *)bus->sih; +} + +void * +dhd_bus_txq(struct dhd_bus *bus) +{ + return &bus->txq; +} + +uint +dhd_bus_hdrlen(struct dhd_bus *bus) +{ + return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; +} + +void +dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val) +{ + bus->dotxinrx = val; +} + +int +dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) +{ + int bcmerror = 0; + dhd_bus_t *bus; + + bus = dhdp->bus; + + if (flag == TRUE) { + if (!bus->dhd->dongle_reset) { + dhd_os_sdlock(dhdp); + dhd_os_wd_timer(dhdp, 0); +#if !defined(IGNORE_ETH0_DOWN) + /* Force flow control as protection when stop come before ifconfig_down */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); +#endif /* !defined(IGNORE_ETH0_DOWN) */ + /* Expect app to have torn down any connection before calling */ + /* Stop the bus, disable F2 */ + dhd_bus_stop(bus, FALSE); + +#if defined(OOB_INTR_ONLY) + /* Clean up any pending IRQ */ + dhd_enable_oob_intr(bus, FALSE); + bcmsdh_oob_intr_set(bus->sdh, FALSE); + bcmsdh_oob_intr_unregister(bus->sdh); +#endif + + /* Clean tx/rx buffer pointers, detach from the dongle */ + dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); + + bus->dhd->dongle_reset = TRUE; + bus->dhd->up = FALSE; + dhd_txglom_enable(dhdp, FALSE); + dhd_os_sdunlock(dhdp); + + DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); + /* App can now remove power from device */ + } else + bcmerror = BCME_SDIO_ERROR; + } else { + /* App must have restored power to device before calling */ + + DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) { + /* Turn on WLAN */ + dhd_os_sdlock(dhdp); + /* Reset SD client */ + bcmsdh_reset(bus->sdh); + + /* Attempt to re-attach & download */ + if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh, + (uint32 *)SI_ENUM_BASE, + bus->cl_devid)) { + /* Attempt to download binary to the dongle */ + if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) && + dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) { + + /* Re-init bus, enable F2 transfer */ + bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); + if (bcmerror == BCME_OK) { +#if defined(OOB_INTR_ONLY) + dhd_enable_oob_intr(bus, TRUE); + bcmsdh_oob_intr_register(bus->sdh, + dhdsdio_isr, bus); + bcmsdh_oob_intr_set(bus->sdh, TRUE); +#endif + + bus->dhd->dongle_reset = FALSE; + bus->dhd->up = TRUE; + +#if !defined(IGNORE_ETH0_DOWN) + /* Restore flow control */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); +#endif + dhd_os_wd_timer(dhdp, dhd_watchdog_ms); + + DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); + } else { + dhd_bus_stop(bus, FALSE); + dhdsdio_release_dongle(bus, bus->dhd->osh, + TRUE, FALSE); + } + } else + bcmerror = BCME_SDIO_ERROR; + } else + bcmerror = BCME_SDIO_ERROR; + + dhd_os_sdunlock(dhdp); + } else { + bcmerror = BCME_SDIO_ERROR; + DHD_INFO(("%s called when dongle is not in reset\n", + __FUNCTION__)); + DHD_INFO(("Will call dhd_bus_start instead\n")); + dhd_bus_resume(dhdp, 1); + if ((bcmerror = dhd_bus_start(dhdp)) != 0) + DHD_ERROR(("%s: dhd_bus_start fail with %d\n", + __FUNCTION__, bcmerror)); + } + } + return bcmerror; +} + +int dhd_bus_suspend(dhd_pub_t *dhdpub) +{ + return bcmsdh_stop(dhdpub->bus->sdh); +} + +int dhd_bus_resume(dhd_pub_t *dhdpub, int stage) +{ + return bcmsdh_start(dhdpub->bus->sdh, stage); +} + +/* Get Chip ID version */ +uint dhd_bus_chip_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + + return bus->sih->chip; +} + +/* Get Chip Rev ID version */ +uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + + return bus->sih->chiprev; +} + +/* Get Chip Pkg ID version */ +uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + + return bus->sih->chippkg; +} + +int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num) +{ + *bus_type = bus->bus; + *bus_num = bus->bus_num; + *slot_num = bus->slot_num; + return 0; +} + +int +dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) +{ + dhd_bus_t *bus; + + bus = dhdp->bus; + return dhdsdio_membytes(bus, set, address, data, size); +} +#if defined(SUPPORT_MULTIPLE_REVISION) +/* Just print chip revision for BCM4330 */ +static int +concate_revision_bcm4330(dhd_bus_t *bus) +{ + uint chipver; + chipver = bus->sih->chiprev; + + if (chipver == 3) + DHD_ERROR(("---- CHIP bcm4330 B1 ----\n")); + else if (chipver == 4) + DHD_ERROR(("---- CHIP bcm4330 B2 ----\n")); + else + DHD_ERROR(("----- Invalid chip version -----\n")); + return 0; +} + +static int +concate_revision_bcm4334(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ +#define REV_ID_ADDR 0x1E008F90 +#define BCM4334_B1_UNIQUE 0x30312E36 + + uint chipver; + uint32 unique_id; + uint8 data[4]; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[10] = "_4334"; +#else + char chipver_tag[4] = ""; +#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ + + DHD_TRACE(("%s: BCM4334 Multiple Revision Check\n", __FUNCTION__)); + if (bus->sih->chip != BCM4334_CHIP_ID) { + DHD_ERROR(("%s:Chip is not BCM4334\n", __FUNCTION__)); + return -1; + } + chipver = bus->sih->chiprev; + if (chipver == 0x2) { + dhdsdio_membytes(bus, FALSE, REV_ID_ADDR, data, 4); + unique_id = load32_ua(data); + if (unique_id == BCM4334_B1_UNIQUE) + chipver = 0x01; + } + DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); + if (chipver == 1) { + DHD_ERROR(("----- CHIP bcm4334_B0 -----\n")); + strcat(chipver_tag, "_b0"); + } else if (chipver == 2) { + DHD_ERROR(("----- CHIP bcm4334_B1 -----\n")); + strcat(chipver_tag, "_b1"); + } else if (chipver == 3) { + DHD_ERROR(("----- CHIP bcm4334_B2 -----\n")); + strcat(chipver_tag, "_b2"); + } + else { + DHD_ERROR(("----- Invalid chip version -----\n")); + return -1; + } + + strcat(fw_path, chipver_tag); +#if defined(SUPPORT_MULTIPLE_CHIPS) + strcat(nv_path, chipver_tag); +#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ + +#undef REV_ID_ADDR +#undef BCM4334_B1_UNIQUE + return 0; +} + +static int +concate_revision_bcm4335(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + + uint chipver; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[10] = "_4335"; +#else + char chipver_tag[4] = {0, }; +#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ + + DHD_TRACE(("%s: BCM4335 Multiple Revision Check\n", __FUNCTION__)); + if (bus->sih->chip != BCM4335_CHIP_ID) { + DHD_ERROR(("%s:Chip is not BCM4335\n", __FUNCTION__)); + return -1; + } + chipver = bus->sih->chiprev; + DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); + if (chipver == 0x0) { + DHD_ERROR(("----- CHIP bcm4335_A0 -----\n")); + strcat(chipver_tag, "_a0"); + } else if (chipver == 0x1) { + DHD_ERROR(("----- CHIP bcm4335_B0 -----\n")); +#if defined(SUPPORT_MULTIPLE_CHIPS) + strcat(chipver_tag, "_b0"); +#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ + } + + strcat(fw_path, chipver_tag); + strcat(nv_path, chipver_tag); + return 0; +} + +static int +concate_revision_bcm4339(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + + uint chipver; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[10] = "_4339"; +#else + char chipver_tag[4] = {0, }; +#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ + + DHD_TRACE(("%s: BCM4339 Multiple Revision Check\n", __FUNCTION__)); + if (bus->sih->chip != BCM4339_CHIP_ID) { + DHD_ERROR(("%s:Chip is not BCM4339\n", __FUNCTION__)); + return -1; + } + chipver = bus->sih->chiprev; + DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); + if (chipver == 0x1) { + DHD_ERROR(("----- CHIP bcm4339_A0 -----\n")); + strcat(chipver_tag, "_a0"); + } else { + DHD_ERROR(("----- CHIP bcm4339 unknown revision %d -----\n", + chipver)); + } + + strcat(fw_path, chipver_tag); + strcat(nv_path, chipver_tag); + return 0; +} + +static int +concate_revision_bcm43349(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + uint chipver; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[10] = "_43349"; +#else + char chipver_tag[4] = {0, }; +#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ + + DHD_TRACE(("%s: BCM43349 Multiple Revision Check\n", __FUNCTION__)); + if (bus->sih->chip != BCM43349_CHIP_ID) { + DHD_ERROR(("%s:Chip is not BCM43349\n", __FUNCTION__)); + return -1; + } + chipver = bus->sih->chiprev; + DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); + if (chipver == 0x1) { + DHD_ERROR(("----- CHIP bcm43349_A0 -----\n")); + strcat(chipver_tag, "_a0"); + } else { + DHD_ERROR(("----- CHIP bcm43349 unknown revision %d -----\n", chipver)); + } + + strcat(fw_path, chipver_tag); + strcat(nv_path, chipver_tag); + return 0; +} + +static int concate_revision_bcm43241(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + uint32 chip_id, chip_ver; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[10] = "_43241"; +#else + char chipver_tag[4] = {0, }; +#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ + + DHD_TRACE(("%s: BCM43241 Multiple Revision Check\n", __FUNCTION__)); + + chip_id = bus->sih->chip; + chip_ver = bus->sih->chiprev; + + if (chip_ver == 2) { + DHD_ERROR(("----- CHIP bcm43241_B0 -----\n")); + strcat(chipver_tag, "_b0"); + } else if (chip_ver == 5) { + DHD_ERROR(("----- CHIP bcm43241_B4 -----\n")); + strcat(chipver_tag, "_b4"); + } else { + DHD_ERROR(("----- Invalid chip version -----\n")); + return -1; + } + + strcat(fw_path, chipver_tag); + strcat(nv_path, chipver_tag); + return 0; +} + +static int concate_revision_bcm4350(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + uint32 chip_id, chip_ver; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[10] = {0, }; +#else + char chipver_tag[4] = {0, }; +#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */ + chip_id = bus->sih->chip; + chip_ver = bus->sih->chiprev; + +#if defined(SUPPORT_MULTIPLE_CHIPS) + if (chip_ver == 3) + strcat(chipver_tag, "_4354"); + else + strcat(chipver_tag, "_4350"); +#endif + + if (chip_ver == 3) { + DHD_ERROR(("----- CHIP 4354 A0 -----\n")); + strcat(chipver_tag, "_a0"); + } else { + DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); + } + + strcat(fw_path, chipver_tag); + strcat(nv_path, chipver_tag); + return 0; +} + +static int concate_revision_bcm4354(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + uint32 chip_id, chip_ver; +#if defined(SUPPORT_MULTIPLE_CHIPS) + char chipver_tag[10] = "_4354"; +#else + char chipver_tag[4] = {0, }; +#endif /* SUPPORT_MULTIPLE_CHIPS */ + + chip_id = bus->sih->chip; + chip_ver = bus->sih->chiprev; + if (chip_ver == 1) { + DHD_ERROR(("----- CHIP 4354 A1 -----\n")); + strcat(chipver_tag, "_a1"); + } else { + DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver)); + } + + strcat(fw_path, chipver_tag); + strcat(nv_path, chipver_tag); + + return 0; +} + +int +concate_revision(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + int res = 0; + + if (!bus || !bus->sih) { + DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__)); + return -1; + } + + + switch (bus->sih->chip) { + case BCM4330_CHIP_ID: + res = concate_revision_bcm4330(bus); + break; + case BCM4334_CHIP_ID: + res = concate_revision_bcm4334(bus, fw_path, nv_path); + break; + case BCM4335_CHIP_ID: + res = concate_revision_bcm4335(bus, fw_path, nv_path); + + break; + case BCM4339_CHIP_ID: + res = concate_revision_bcm4339(bus, fw_path, nv_path); + break; + case BCM43349_CHIP_ID: + res = concate_revision_bcm43349(bus, fw_path, nv_path); + break; + case BCM4324_CHIP_ID: + res = concate_revision_bcm43241(bus, fw_path, nv_path); + break; + case BCM4350_CHIP_ID: + res = concate_revision_bcm4350(bus, fw_path, nv_path); + break; + case BCM4354_CHIP_ID: + res = concate_revision_bcm4354(bus, fw_path, nv_path); + break; + + default: + DHD_ERROR(("REVISION SPECIFIC feature is not required\n")); + return res; + } + + if (res == 0) { + } + return res; +} +#endif /* SUPPORT_MULTIPLE_REVISION */ + + +void +dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path) +{ + bus->fw_path = pfw_path; + bus->nv_path = pnv_path; +} + +int +dhd_enableOOB(dhd_pub_t *dhd, bool sleep) +{ + dhd_bus_t *bus = dhd->bus; + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + + if (sleep) { + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + /* Tell device to start using OOB wakeup */ + W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); + if (retries > retry_limit) { + DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); + return BCME_BUSY; + } + /* Turn off our contribution to the HT clock request */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } else { + /* Make sure the controller has the bus up */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Send misc interrupt to indicate OOB not needed */ + W_SDREG(0, ®s->tosbmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); + + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); + + /* Make sure we have SD bus access */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } + return BCME_OK; +} + +void +dhd_bus_pktq_flush(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + bool wlfc_enabled = FALSE; + +#ifdef PROP_TXSTATUS + wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED); +#endif + if (!wlfc_enabled) { +#ifdef DHDTCPACK_SUPPRESS + /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, + * when there is a newly coming packet from network stack. + */ + dhd_tcpack_info_tbl_clean(bus->dhd); +#endif /* DHDTCPACK_SUPPRESS */ + /* Clear the data packet queues */ + pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0); + } +} + +#ifdef BCMSDIO +int +dhd_sr_config(dhd_pub_t *dhd, bool on) +{ + dhd_bus_t *bus = dhd->bus; + + if (!bus->_srenab) + return -1; + + return dhdsdio_clk_devsleep_iovar(bus, on); +} + +uint16 +dhd_get_chipid(dhd_pub_t *dhd) +{ + dhd_bus_t *bus = dhd->bus; + + if (bus && bus->sih) + return (uint16)bus->sih->chip; + else + return 0; +} +#endif /* BCMSDIO */ + +#ifdef DEBUGGER +uint32 dhd_sdio_reg_read(void *h, uint32 addr) +{ + uint32 rval; + struct dhd_bus *bus = (struct dhd_bus *) h; + + dhd_os_sdlock(bus->dhd); + + BUS_WAKE(bus); + + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + rval = bcmsdh_reg_read(bus->sdh, addr, 4); + + dhd_os_sdunlock(bus->dhd); + + return rval; +} + +void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val) +{ + struct dhd_bus *bus = (struct dhd_bus *) h; + + dhd_os_sdlock(bus->dhd); + + BUS_WAKE(bus); + + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + bcmsdh_reg_write(bus->sdh, addr, 4, val); + + dhd_os_sdunlock(bus->dhd); +} +#endif /* DEBUGGER */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.c new file mode 100644 index 000000000000..de106110b05d --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Author: Daisuke Niwa daisuke.x.niwa@sonymobile.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +/* miscTA items */ +typedef enum somc_nv_item { + SOMC_TA_TXPWR_2_4G = 0, + SOMC_TA_TXPWR_5G_LOW, + SOMC_TA_TXPWR_5G_MID, + SOMC_TA_TXPWR_5G_HIGH, + SOMC_TA_TXPWR_CO1_2_4G, + SOMC_TA_TXPWR_CO1_5G_LOW, + SOMC_TA_TXPWR_CO1_5G_MID, + SOMC_TA_TXPWR_CO1_5G_HIGH, +} somc_nv_item_t; + +/* Paths to miscTA import files */ +static const char *somc_ta_paths[] = { + "/data/etc/wlan_txpower_2_4g", + "/data/etc/wlan_txpower_5g_low", + "/data/etc/wlan_txpower_5g_mid", + "/data/etc/wlan_txpower_5g_high", + "/data/etc/wlan_txpower_co1_2_4g", + "/data/etc/wlan_txpower_co1_5g_low", + "/data/etc/wlan_txpower_co1_5g_mid", + "/data/etc/wlan_txpower_co1_5g_high", +}; + +#define SOMC_NV_IS_5G(i) (i % 4 == 0 ? 0 : 1) +#define SOMC_NV_GET_CHAIN(i) (i < SOMC_TA_TXPWR_CO1_2_4G ? 0 : 1) + +#define SOMC_MAX_TABUF_SIZE 128 +#define SOMC_TXPWR_BUF_SIZE 7 + +/* Keys used in calibration file for tx power */ +#define SOMC_CKEY_TXPWR_2_4G_11B "cckbw202gpo" +#define SOMC_CKEY_TXPWR_2_4G_11A "dot11agofdmhrbw202gpo" +#define SOMC_CKEY_TXPWR_2_4G_11A_2 "ofdmlrbw202gpo" +#define SOMC_CKEY_TXPWR_2_4G_11N "mcsbw202gpo" +#define SOMC_CKEY_TXPWR_5G_LOW_11A "mcsbw205glpo" +#define SOMC_CKEY_TXPWR_5G_LOW_11N "mcsbw405glpo" +#define SOMC_CKEY_TXPWR_5G_LOW_11AC "mcsbw805glpo" +#define SOMC_CKEY_TXPWR_5G_MID_11A "mcsbw205gmpo" +#define SOMC_CKEY_TXPWR_5G_MID_11N "mcsbw405gmpo" +#define SOMC_CKEY_TXPWR_5G_MID_11AC "mcsbw805gmpo" +#define SOMC_CKEY_TXPWR_5G_HIGH_11A "mcsbw205ghpo" +#define SOMC_CKEY_TXPWR_5G_HIGH_11N "mcsbw405ghpo" +#define SOMC_CKEY_TXPWR_5G_HIGH_11AC "mcsbw805ghpo" + +#define SOMC_TXPWR_MAX 127 +#define SOMC_TXPWR_5G 0x20 + +typedef struct { + char *key; /* Key for tx power (see the definitions above) */ + int len; /* Length of a unit of PPR (not incl. "0x") */ + int offset; /* Offset to PPR */ +} somc_ppr_item_t; + +/* List of ppr item handled by somc_txpower_calibrate() */ +static const somc_ppr_item_t somc_ppr_items[] = { + { SOMC_CKEY_TXPWR_2_4G_11B, 4, 0}, + { SOMC_CKEY_TXPWR_2_4G_11A, 4, 0}, + { SOMC_CKEY_TXPWR_2_4G_11A_2, 4, 2}, + { SOMC_CKEY_TXPWR_2_4G_11N, 8, 0}, + { SOMC_CKEY_TXPWR_5G_LOW_11A, 8, 0}, + { SOMC_CKEY_TXPWR_5G_LOW_11N, 8, 0}, + { SOMC_CKEY_TXPWR_5G_LOW_11AC, 8, 0}, + { SOMC_CKEY_TXPWR_5G_MID_11A, 8, 0}, + { SOMC_CKEY_TXPWR_5G_MID_11N, 8, 0}, + { SOMC_CKEY_TXPWR_5G_MID_11AC, 8, 0}, + { SOMC_CKEY_TXPWR_5G_HIGH_11A, 8, 0}, + { SOMC_CKEY_TXPWR_5G_HIGH_11N, 8, 0}, + { SOMC_CKEY_TXPWR_5G_HIGH_11AC, 8, 0}, +}; + +/* {2.4GHz: {chain0, chain1}, 5GHz: {chain0, chain1}} */ +static int somc_txpower_min_deltas[2][2] = {{0, 0},{0, 0}}; + +static int +somc_txpower_get_min_delta(int band5g, int chain) +{ + int min_delta = somc_txpower_min_deltas[band5g][chain]; + return (min_delta == INT_MAX) ? 0 : min_delta; +} + +static void +somc_txpower_update_min_delta(const int *delta, int num, int band5g, int chain) +{ + int *min_delta = &somc_txpower_min_deltas[band5g][chain]; + while (num > 0) { + num--; + if (band5g && (num == 0)) /* ignore 11b delta value for 5GHz */ + continue; + if (!band5g && (num > 2)) /* ignore 11n-40/11ac delta values for 2.4GHz */ + continue; + *min_delta = MIN(*min_delta, delta[num]); + } +} + +static int +somc_read_file(const char *path, unsigned char *buf, int buf_len) +{ + int ret = -1; + int len; + struct file *fp = NULL; + + if (!path || !buf) + goto err; + + fp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(fp)) { + DHD_ERROR(("%s: file open error: %s\n", __FUNCTION__, path)); + if (PTR_ERR(fp) == -ENOENT) { + DHD_ERROR(("%s: file does not exist: %s\n", __FUNCTION__, path)); + ret = -2; + } + fp = NULL; + goto err; + } + + len = dhd_os_get_image_block(buf, buf_len, (void *)fp); + if (len <= 0 || buf_len <= len) { + DHD_ERROR(("%s: file read error: %s\n", __FUNCTION__, path)); + goto err; + } + buf[len] = '\0'; + + ret = 0; +err: + if (fp) + filp_close(fp, NULL); + return ret; +} + +static int +somc_read_ta(somc_nv_item_t item, unsigned char *buf, int buf_len) +{ + char ta_buf[SOMC_MAX_TABUF_SIZE] = {0}; + int *d, ret; + + ret = somc_read_file(somc_ta_paths[item], ta_buf, sizeof(ta_buf)); + if (ret != 0) + return ret; + + switch (item) { + case SOMC_TA_TXPWR_2_4G: + case SOMC_TA_TXPWR_5G_LOW: + case SOMC_TA_TXPWR_5G_MID: + case SOMC_TA_TXPWR_5G_HIGH: + case SOMC_TA_TXPWR_CO1_2_4G: + case SOMC_TA_TXPWR_CO1_5G_LOW: + case SOMC_TA_TXPWR_CO1_5G_MID: + case SOMC_TA_TXPWR_CO1_5G_HIGH: + if (buf_len < SOMC_TXPWR_BUF_SIZE) + return -1; + d = (int *)buf; + if (sscanf(ta_buf, "%d:%d:%d:%d:%d:%d:%d", + &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6]) != 7) { + DHD_ERROR(("%s: tx power parse error: %s\n", + __FUNCTION__, somc_ta_paths[item])); + return -1; + } + + printk("%s: tx power in miscTA(%s),\n 11b:11a:11n(20MHz):11n(40MHz):" + "11ac(20MHz):11ac(40MHz):11ac(80MHz)=,\n %d:%d:%d:%d:%d:%d:%d\n", + __FUNCTION__, somc_ta_paths[item], + d[0], d[1], d[2], d[3], d[4], d[5], d[6]); + break; + default: + return -1; + } + + return 0; +} + +static int +somc_txpower_apply_delta(const unsigned char *key, int len, int offset, + int delta, unsigned char *nvram, int nvram_len) +{ + unsigned char *end = nvram + nvram_len - 1; + unsigned char *k, *v, *t; + unsigned int power_h, power_l; + int i, j, v_len = len * 2 + 5; /* e.g. "0x5555,0x1111" (= 4 * 2 + 5) */ + const unsigned char *fmt; + + if (!key || !nvram || offset >= len || (len != 4 && len != 8)) + return -1; + + fmt = (len == 4) ? "0x%04x,0x%04x" : "0x%08x,0x%08x"; + + /* look up key in nvram */ + if ((k = strnstr(nvram, key, nvram_len)) == NULL) { + DHD_ERROR(("%s: key not found: %s\n", __FUNCTION__, key)); + return -1; + } + + /* extract value */ + v = k + strlen(key); + if (v > end || *v != '=') { + DHD_ERROR(("%s: value parse error: %s\n", __FUNCTION__, key)); + return -1; + } + v += 1; + + if (v > end || (t = strnchr(v, end - v + 1, '\n')) == NULL || + t - v != v_len) { + DHD_ERROR(("%s: value parse error: %s\n", __FUNCTION__, key)); + return -1; + } + + /* extract each values */ + if (sscanf(v, fmt, &power_l, &power_h) != 2) { + DHD_ERROR(("%s: power offset values parse error: %s\n", __FUNCTION__, key)); + return -1; + } + + /* convert unit since nvram uses 1/2dB step, miscTA uses 1/100dB step */ + if (delta < 0 && delta % 50 != 0) + delta = delta / 50 - 1; + else + delta = delta / 50; + + for (i = 0, j = len - offset; i < j; i++) { + int val, sft = i * 4; + /* combine low and high 4 bits into a value(8bit) */ + val = ((power_l >> sft) & 0xf) | (((power_h >> sft) & 0xf) << 4); + /* apply delta */ + val -= delta; + val = (val > 0xff) ? 0xff : (val < 0x00) ? 0x00 : val; + /* separate power to low and high again */ + power_l &= ~(0xf << sft); + power_l |= (val & 0x0f) << sft; + power_h &= ~(0xf << sft); + power_h |= ((val & 0xf0) >> 4) << sft; + } + + snprintf(v, v_len + 1, fmt, power_l, power_h); + v[v_len] = '\n'; + + return 0; +} + +int somc_txpower_calibrate(char *nvram, int nvram_len) +{ + int v[4][SOMC_TXPWR_BUF_SIZE]; /* tx power offset(s) */ + int i, j, ta_num, delta[sizeof(somc_ppr_items) / sizeof(somc_ppr_items[0])]; + +#ifdef SOMC_MIMO + ta_num = SOMC_TA_TXPWR_CO1_5G_HIGH + 1; +#else + ta_num = SOMC_TA_TXPWR_5G_HIGH + 1; +#endif + /* initialize minimum delta (used for tx power trim) */ + for (i = 0; i < 4; i++) { + for (j = 0; j < SOMC_TXPWR_BUF_SIZE; j++) { + v[i][j] = INT_MAX; + } + } + + /* initialize minimum delta (used for tx power back-off) */ + somc_txpower_min_deltas[0][0 /* chain0 */] = INT_MAX; + somc_txpower_min_deltas[1][0 /* chain0 */] = INT_MAX; + somc_txpower_min_deltas[0][1 /* chain1 */] = INT_MAX; + somc_txpower_min_deltas[1][1 /* chain1 */] = INT_MAX; + + for (i = 0; i < ta_num; i++) { + int ret; + int tv[SOMC_TXPWR_BUF_SIZE] = {0}; + + /* no need to update delta if miscTA doesn't exist(ret == 2) */ + ret = somc_read_ta(i, (char *)tv, sizeof(tv)); + if (ret == 0) { + somc_txpower_update_min_delta(tv, SOMC_TXPWR_BUF_SIZE, + SOMC_NV_IS_5G(i), SOMC_NV_GET_CHAIN(i)); + /* select minimum delta between chain0 and chain1 */ + for (j = 0; j < SOMC_TXPWR_BUF_SIZE; j++) + v[i % 4][j] = MIN(v[i % 4][j], tv[j]); + } else if (ret != -2) + return BCME_OK; + } + + /* construct delta data structure for 2.4GHz + * TA value "v[0]" consists of the following format. + * {11b}:{11a}:{11n-20} + */ + delta[0] = v[0][0]; /* {11b} */ + delta[1] = v[0][1]; /* {11a} */ + delta[2] = v[0][1]; /* {11a} */ + delta[3] = v[0][2]; /* {11n-20} */ + + /* construct delta data structure for 5GHz(low/mid/high) + * TA values "v[1],v[2],v[3]" consist of the following format. + * {11b}:{11a}:{11n-20}:{11n-40}:{11ac-20}:{11ac-40}:{11ac-80} + */ + for (i = 1; i < 4; i++) { + /* minimum delta between {11a}, {11n-20}, {11ac-20} for 20MHz */ + delta[i * 3 + 1] = MIN(MIN(v[i][1], v[i][2]), v[i][4]); + /* minimum delta between {11n-40}, {11ac-40} for 40MHz */ + delta[i * 3 + 2] = MIN(v[i][3], v[i][5]); + /* {11ac-80} for 80MHz */ + delta[i * 3 + 3] = v[i][6]; + } + + /* Apply delta (tx power trim) */ + for (i = 0; i < sizeof(somc_ppr_items) / sizeof(somc_ppr_items[0]); i++) { + if (delta[i] == INT_MAX) + continue; + if (somc_txpower_apply_delta(somc_ppr_items[i].key, somc_ppr_items[i].len, + somc_ppr_items[i].offset, delta[i], nvram, nvram_len) != 0) + return BCME_ERROR; + } + + return BCME_OK; +} + +int somc_update_qtxpower(char *buf, char band, int chain) +{ + int in_qdbm, power; + int delta = somc_txpower_get_min_delta((band & SOMC_TXPWR_5G) != 0, chain); + + in_qdbm = *buf; + + if (in_qdbm < 0 || SOMC_TXPWR_MAX < in_qdbm) + return -1; + + /* convert unit for calculation since 'delta' uses 1/100dB step */ + power = in_qdbm + delta / (100 / 4); + if (power > 0) { + power = (power > SOMC_TXPWR_MAX) ? SOMC_TXPWR_MAX : power; + } else { + power = 0; + } + *buf = (char)power; + + printk("%s: Set max tx power: %d qdBm (delta=%d)\n", + __FUNCTION__, power, delta); + + return 0; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.h new file mode 100644 index 000000000000..4c83517241a2 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Author: Daisuke Niwa daisuke.x.niwa@sonymobile.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#ifndef __DHD_SOMC_CUSTOM_H__ +#define __DHD_SOMC_CUSTOM_H__ + +extern int somc_txpower_calibrate(char *nvram, int nvram_len); +extern int somc_update_qtxpower(char *buf, char band, int chain); + +#endif /* __DHD_SOMC_CUSTOM_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.c new file mode 100644 index 000000000000..2b1d27311095 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.c @@ -0,0 +1,4109 @@ +/* + * DHD PROP_TXSTATUS Module. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_wlfc.c 701287 2017-05-24 10:33:19Z $ + * + */ + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#ifdef PROP_TXSTATUS +#include +#include +#endif +#include + + +/* + * wlfc naming and lock rules: + * + * 1. Private functions name like _dhd_wlfc_XXX, declared as static and avoid wlfc lock operation. + * 2. Public functions name like dhd_wlfc_XXX, use wlfc lock if needed. + * 3. Non-Proptxstatus module call public functions only and avoid wlfc lock operation. + * + */ + + +#ifdef PROP_TXSTATUS + +#define DHD_WLFC_QMON_COMPLETE(entry) + +#define LIMIT_BORROW + + +static uint16 +_dhd_wlfc_adjusted_seq(void* p, uint8 current_seq) +{ + uint16 seq; + + if (!p) { + return 0xffff; + } + + seq = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + if (seq < current_seq) { + /* wrap around */ + seq += 256; + } + + return seq; +} + +static void +_dhd_wlfc_prec_enque(struct pktq *pq, int prec, void* p, bool qHead, + uint8 current_seq, bool reOrder) +{ + struct pktq_prec *q; + uint16 seq, seq2; + void *p2, *p2_prev; + + if (!p) + return; + + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + PKTSETLINK(p, NULL); + if (q->head == NULL) { + /* empty queue */ + q->head = p; + q->tail = p; + } else { + if (reOrder && (prec & 1)) { + seq = _dhd_wlfc_adjusted_seq(p, current_seq); + p2 = qHead ? q->head : q->tail; + seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); + + if ((qHead &&((seq+1) > seq2)) || (!qHead && ((seq2+1) > seq))) { + /* need reorder */ + p2 = q->head; + p2_prev = NULL; + seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); + + while (seq > seq2) { + p2_prev = p2; + p2 = PKTLINK(p2); + if (!p2) { + break; + } + seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); + } + + if (p2_prev == NULL) { + /* insert head */ + PKTSETLINK(p, q->head); + q->head = p; + } else if (p2 == NULL) { + /* insert tail */ + PKTSETLINK(p2_prev, p); + q->tail = p; + } else { + /* insert after p2_prev */ + PKTSETLINK(p, PKTLINK(p2_prev)); + PKTSETLINK(p2_prev, p); + } + goto exit; + } + } + + if (qHead) { + PKTSETLINK(p, q->head); + q->head = p; + } else { + PKTSETLINK(q->tail, p); + q->tail = p; + } + } + +exit: + + q->len++; + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; +} + +/* Create a place to store all packet pointers submitted to the firmware until + a status comes back, suppress or otherwise. + + hang-er: noun, a contrivance on which things are hung, as a hook. +*/ +static void* +_dhd_wlfc_hanger_create(osl_t *osh, int max_items) +{ + int i; + wlfc_hanger_t* hanger; + + /* allow only up to a specific size for now */ + ASSERT(max_items == WLFC_HANGER_MAXITEMS); + + if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) + return NULL; + + memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); + hanger->max_items = max_items; + + for (i = 0; i < hanger->max_items; i++) { + hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } + return hanger; +} + +static int +_dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) +{ + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h) { + MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); + return BCME_OK; + } + return BCME_BADARG; +} + +static uint16 +_dhd_wlfc_hanger_get_free_slot(void* hanger) +{ + uint32 i; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h) { + i = h->slot_pos + 1; + if (i == h->max_items) { + i = 0; + } + while (i != h->slot_pos) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { + h->slot_pos = i; + return (uint16)i; + } + i++; + if (i == h->max_items) + i = 0; + } + h->failed_slotfind++; + } + return WLFC_HANGER_MAXITEMS; +} + +static int +_dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + *gen = 0xff; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + + if (h) { + if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || + (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { + *gen = h->items[slot_id].gen; + } + else { + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +_dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { + if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { + h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; + h->items[slot_id].pkt = pkt; + h->items[slot_id].pkt_state = 0; + h->items[slot_id].pkt_txstatus = 0; + h->pushed++; + } + else { + h->failed_to_push++; + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +_dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, bool remove_from_hanger) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + + if (h) { + if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { + *pktout = h->items[slot_id].pkt; + if (remove_from_hanger) { + h->items[slot_id].state = + WLFC_HANGER_ITEM_STATE_FREE; + h->items[slot_id].pkt = NULL; + h->items[slot_id].gen = 0xff; + h->items[slot_id].identifier = 0; + h->popped++; + } + } + else { + h->failed_to_pop++; + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +_dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + if (h) { + h->items[slot_id].gen = gen; + if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { + h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; + } + else + rc = BCME_BADARG; + } + else + rc = BCME_BADARG; + + return rc; +} + +/* remove reference of specific packet in hanger */ +static bool +_dhd_wlfc_hanger_remove_reference(wlfc_hanger_t* h, void* pkt) +{ + int i; + + if (!h || !pkt) { + return FALSE; + } + + for (i = 0; i < h->max_items; i++) { + if (pkt == h->items[i].pkt) { + if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) || + (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + h->items[i].pkt = NULL; + h->items[i].gen = 0xff; + h->items[i].identifier = 0; + } + return TRUE; + } + } + + return FALSE; +} + + +static int +_dhd_wlfc_enque_afq(athost_wl_status_info_t* ctx, void *p) +{ + wlfc_mac_descriptor_t* entry; + uint16 entry_idx = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + uint8 prec = DHD_PKTTAG_FIFO(PKTTAG(p)); + + if (entry_idx < WLFC_MAC_DESC_TABLE_SIZE) + entry = &ctx->destination_entries.nodes[entry_idx]; + else if (entry_idx < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) + entry = &ctx->destination_entries.interfaces[entry_idx - WLFC_MAC_DESC_TABLE_SIZE]; + else + entry = &ctx->destination_entries.other; + + pktq_penq(&entry->afq, prec, p); + + return BCME_OK; +} + +static int +_dhd_wlfc_deque_afq(athost_wl_status_info_t* ctx, uint16 hslot, uint8 hcnt, uint8 prec, + void **pktout) +{ + wlfc_mac_descriptor_t *entry; + struct pktq *pq; + struct pktq_prec *q; + void *p, *b; + + if (!ctx) { + DHD_ERROR(("%s: ctx(%p), pktout(%p)\n", __FUNCTION__, ctx, pktout)); + return BCME_BADARG; + } + + if (pktout) { + *pktout = NULL; + } + + ASSERT(hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM + 1)); + + if (hslot < WLFC_MAC_DESC_TABLE_SIZE) + entry = &ctx->destination_entries.nodes[hslot]; + else if (hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) + entry = &ctx->destination_entries.interfaces[hslot - WLFC_MAC_DESC_TABLE_SIZE]; + else + entry = &ctx->destination_entries.other; + + pq = &entry->afq; + + ASSERT(prec < pq->num_prec); + + q = &pq->q[prec]; + + b = NULL; + p = q->head; + + while (p && (hcnt != WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))))) + { + b = p; + p = PKTLINK(p); + } + + if (p == NULL) { + /* none is matched */ + if (b) { + DHD_ERROR(("%s: can't find matching seq(%d)\n", __FUNCTION__, hcnt)); + } else { + DHD_ERROR(("%s: queue is empty\n", __FUNCTION__)); + } + + return BCME_ERROR; + } + + if (!b) { + /* head packet is matched */ + if ((q->head = PKTLINK(p)) == NULL) { + q->tail = NULL; + } + } else { + /* middle packet is matched */ + DHD_INFO(("%s: out of order, seq(%d), head_seq(%d)\n", __FUNCTION__, hcnt, + WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(q->head))))); + ctx->stats.ooo_pkts[prec]++; + PKTSETLINK(b, PKTLINK(p)); + if (PKTLINK(p) == NULL) { + q->tail = b; + } + } + + q->len--; + pq->len--; + + PKTSETLINK(p, NULL); + + if (pktout) { + *pktout = p; + } + + return BCME_OK; +} + +static int +_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void** packet, bool tim_signal, + uint8 tim_bmp, uint8 mac_handle, uint32 htodtag, uint16 htodseq, bool skip_wlfc_hdr) +{ + uint32 wl_pktinfo = 0; + uint8* wlh; + uint8 dataOffset = 0; + uint8 fillers; + uint8 tim_signal_len = 0; + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + + struct bdc_header *h; + void *p = *packet; + + if (skip_wlfc_hdr) + goto push_bdc_hdr; + + if (tim_signal) { + tim_signal_len = TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; + } + + /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ + dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + TLV_HDR_LEN + tim_signal_len; + if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { + dataOffset += WLFC_CTL_VALUE_LEN_SEQ; + } + + fillers = ROUNDUP(dataOffset, 4) - dataOffset; + dataOffset += fillers; + + PKTPUSH(ctx->osh, p, dataOffset); + wlh = (uint8*) PKTDATA(ctx->osh, p); + + wl_pktinfo = htol32(htodtag); + + wlh[TLV_TAG_OFF] = WLFC_CTL_TYPE_PKTTAG; + wlh[TLV_LEN_OFF] = WLFC_CTL_VALUE_LEN_PKTTAG; + memcpy(&wlh[TLV_HDR_LEN], &wl_pktinfo, sizeof(uint32)); + + if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { + uint16 wl_seqinfo = htol16(htodseq); + wlh[TLV_LEN_OFF] += WLFC_CTL_VALUE_LEN_SEQ; + memcpy(&wlh[TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PKTTAG], &wl_seqinfo, + WLFC_CTL_VALUE_LEN_SEQ); + } + + if (tim_signal_len) { + wlh[dataOffset - fillers - tim_signal_len ] = + WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; + wlh[dataOffset - fillers - tim_signal_len + 1] = + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; + wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; + wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; + } + if (fillers) + memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); + +push_bdc_hdr: + + PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); + h = (struct bdc_header *)PKTDATA(ctx->osh, p); + h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); + if (PKTSUMNEEDED(p)) + h->flags |= BDC_FLAG_SUM_NEEDED; + + + h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); + h->flags2 = 0; + h->dataOffset = dataOffset >> 2; + BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); + *packet = p; + return BCME_OK; +} + +static int +_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) +{ + struct bdc_header *h; + + if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { + DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); + return BCME_ERROR; + } + h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); + + /* pull BDC header */ + PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); + + if (PKTLEN(ctx->osh, pktbuf) < (uint)(h->dataOffset << 2)) { + DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); + return BCME_ERROR; + } + + /* pull wl-header */ + PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); + return BCME_OK; +} + +static wlfc_mac_descriptor_t* +_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) +{ + int i; + wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; + uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); + uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); + wlfc_mac_descriptor_t* entry = DHD_PKTTAG_ENTRY(PKTTAG(p)); + int iftype = ctx->destination_entries.interfaces[ifid].iftype; + + /* saved one exists, return it */ + if (entry) + return entry; + + /* Multicast destination, STA and P2P clients get the interface entry. + * STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations + * have their own entry. + */ + if ((DHD_IF_ROLE_STA(iftype) || ETHER_ISMULTI(dstn)) && + (ctx->destination_entries.interfaces[ifid].occupied)) { + entry = &ctx->destination_entries.interfaces[ifid]; + } + + if (entry && ETHER_ISMULTI(dstn)) { + DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); + return entry; + } + + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (table[i].occupied) { + if (table[i].interface_id == ifid) { + if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) { + entry = &table[i]; + break; + } + } + } + } + + if (entry == NULL) + entry = &ctx->destination_entries.other; + + DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); + + return entry; +} + +static int +_dhd_wlfc_prec_drop(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ) +{ + athost_wl_status_info_t* ctx; + void *pout = NULL; + + ASSERT(dhdp && p); + ASSERT(prec >= 0 && prec <= WLFC_PSQ_PREC_COUNT); + + ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; + + if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { + /* suppressed queue, need pop from hanger */ + _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG + (PKTTAG(p))), &pout, TRUE); + ASSERT(p == pout); + } + + if (!(prec & 1)) { +#ifdef DHDTCPACK_SUPPRESS + /* pkt in delayed q, so fake push BDC header for + * dhd_tcpack_check_xmit() and dhd_txcomplete(). + */ + _dhd_wlfc_pushheader(ctx, &p, FALSE, 0, 0, 0, 0, TRUE); + + /* This packet is about to be freed, so remove it from tcp_ack_info_tbl + * This must be one of... + * 1. A pkt already in delayQ is evicted by another pkt with higher precedence + * in _dhd_wlfc_prec_enq_with_drop() + * 2. A pkt could not be enqueued to delayQ because it is full, + * in _dhd_wlfc_enque_delayq(). + * 3. A pkt could not be enqueued to delayQ because it is full, + * in _dhd_wlfc_rollback_packet_toq(). + */ + if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" + " Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + } + + if (bPktInQ) { + ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; + ctx->pkt_cnt_per_ac[prec>>1]--; + } + + ctx->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(p))][DHD_PKTTAG_FIFO(PKTTAG(p))]--; + ctx->stats.pktout++; + ctx->stats.drop_pkts[prec]++; + + dhd_txcomplete(dhdp, p, FALSE); + PKTFREE(ctx->osh, p, TRUE); + + return 0; +} + +static bool +_dhd_wlfc_prec_enq_with_drop(dhd_pub_t *dhdp, struct pktq *pq, void *pkt, int prec, bool qHead, + uint8 current_seq) +{ + void *p = NULL; + int eprec = -1; /* precedence to evict from */ + athost_wl_status_info_t* ctx; + + ASSERT(dhdp && pq && pkt); + ASSERT(prec >= 0 && prec < pq->num_prec); + + ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; + + /* Fast case, precedence queue is not full and we are also not + * exceeding total queue length + */ + if (!pktq_pfull(pq, prec) && !pktq_full(pq)) { + goto exit; + } + + /* Determine precedence from which to evict packet, if any */ + if (pktq_pfull(pq, prec)) + eprec = prec; + else if (pktq_full(pq)) { + p = pktq_peek_tail(pq, &eprec); + if (!p) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return FALSE; + } + if ((eprec > prec) || (eprec < 0)) { + if (!pktq_pempty(pq, prec)) { + eprec = prec; + } else { + return FALSE; + } + } + } + + /* Evict if needed */ + if (eprec >= 0) { + /* Detect queueing to unconfigured precedence */ + ASSERT(!pktq_pempty(pq, eprec)); + /* Evict all fragmented frames */ + dhd_prec_drop_pkts(dhdp, pq, eprec, _dhd_wlfc_prec_drop); + } + +exit: + /* Enqueue */ + _dhd_wlfc_prec_enque(pq, prec, pkt, qHead, current_seq, + WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)); + ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(pkt))][prec>>1]++; + ctx->pkt_cnt_per_ac[prec>>1]++; + + return TRUE; +} + + +static int +_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, + void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) +{ + /* + put the packet back to the head of queue + + - suppressed packet goes back to suppress sub-queue + - pull out the header, if new or delayed packet + + Note: hslot is used only when header removal is done. + */ + wlfc_mac_descriptor_t* entry; + int rc = BCME_OK; + int prec, fifo_id; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + prec = DHD_PKTTAG_FIFO(PKTTAG(p)); + fifo_id = prec << 1; + if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) + fifo_id += 1; + if (entry != NULL) { + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the firmware (for pspoll etc.) + */ + if ((prec != AC_COUNT) && !DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) + entry->requested_credit++; + + if (pkt_type == eWLFC_PKTTYPE_DELAYED) { + /* decrement sequence count */ + WLFC_DECR_SEQCOUNT(entry, prec); + /* remove header first */ + rc = _dhd_wlfc_pullheader(ctx, p); + if (rc != BCME_OK) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + goto exit; + } + } + + if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, fifo_id, TRUE, + WLFC_SEQCOUNT(entry, fifo_id>>1)) + == FALSE) { + /* enque failed */ + DHD_ERROR(("Error: %s():%d, fifo_id(%d)\n", + __FUNCTION__, __LINE__, fifo_id)); + rc = BCME_ERROR; + } + } else { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + rc = BCME_ERROR; + } +exit: + if (rc != BCME_OK) { + ctx->stats.rollback_failed++; + _dhd_wlfc_prec_drop(ctx->dhdp, fifo_id, p, FALSE); + } + else + ctx->stats.rollback++; + + return rc; +} + +static bool +_dhd_wlfc_allow_fc(athost_wl_status_info_t* ctx, uint8 ifid) +{ + int prec, ac_traffic = WLFC_NO_TRAFFIC; + + for (prec = 0; prec < AC_COUNT; prec++) { + if (ctx->pkt_cnt_in_drv[ifid][prec] > 0) { + if (ac_traffic == WLFC_NO_TRAFFIC) + ac_traffic = prec + 1; + else if (ac_traffic != (prec + 1)) + ac_traffic = WLFC_MULTI_TRAFFIC; + } + } + + if (ac_traffic >= 1 && ac_traffic <= AC_COUNT) { + /* single AC (BE/BK/VI/VO) in queue */ + if (ctx->allow_fc) { + return TRUE; + } else { + uint32 delta; + uint32 curr_t = OSL_SYSUPTIME(); + + if (ctx->fc_defer_timestamp == 0) { + /* first signle ac scenario */ + ctx->fc_defer_timestamp = curr_t; + return FALSE; + } + + /* single AC duration, this handles wrap around, e.g. 1 - ~0 = 2. */ + delta = curr_t - ctx->fc_defer_timestamp; + if (delta >= WLFC_FC_DEFER_PERIOD_MS) { + ctx->allow_fc = TRUE; + } + } + } else { + /* multiple ACs or BCMC in queue */ + ctx->allow_fc = FALSE; + ctx->fc_defer_timestamp = 0; + } + + return ctx->allow_fc; +} + +static void +_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) +{ + dhd_pub_t *dhdp; + + ASSERT(ctx); + + dhdp = (dhd_pub_t *)ctx->dhdp; + ASSERT(dhdp); + + if (dhdp->skip_fc && dhdp->skip_fc()) + return; + + if ((ctx->hostif_flow_state[if_id] == OFF) && !_dhd_wlfc_allow_fc(ctx, if_id)) + return; + + if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { + /* start traffic */ + ctx->hostif_flow_state[if_id] = OFF; + /* + WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", + pq->len, if_id, __FUNCTION__)); + */ + WLFC_DBGMESG(("F")); + + dhd_txflowcontrol(dhdp, if_id, OFF); + + ctx->toggle_host_if = 0; + } + + if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { + /* stop traffic */ + ctx->hostif_flow_state[if_id] = ON; + /* + WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", + pq->len, if_id, __FUNCTION__)); + */ + WLFC_DBGMESG(("N")); + + dhd_txflowcontrol(dhdp, if_id, ON); + + ctx->host_ifidx = if_id; + ctx->toggle_host_if = 1; + } + + return; +} + +static int +_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + uint8 ta_bmp) +{ + int rc = BCME_OK; + void* p = NULL; + int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 16; + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + + if (dhdp->proptxstatus_txoff) { + rc = BCME_NORESOURCE; + return rc; + } + + /* allocate a dummy packet */ + p = PKTGET(ctx->osh, dummylen, TRUE); + if (p) { + PKTPULL(ctx->osh, p, dummylen); + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); + _dhd_wlfc_pushheader(ctx, &p, TRUE, ta_bmp, entry->mac_handle, 0, 0, FALSE); + DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); + DHD_PKTTAG_WLFCPKT_SET(PKTTAG(p), 1); +#ifdef PROP_TXSTATUS_DEBUG + ctx->stats.signal_only_pkts_sent++; +#endif + +#if defined(BCMPCIE) + rc = dhd_bus_txdata(dhdp->bus, p, ctx->host_ifidx); +#else + rc = dhd_bus_txdata(dhdp->bus, p); +#endif + if (rc != BCME_OK) { + _dhd_wlfc_pullheader(ctx, p); + PKTFREE(ctx->osh, p, TRUE); + } + } + else { + DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", + __FUNCTION__, dummylen)); + rc = BCME_NOMEM; + } + return rc; +} + +/* Return TRUE if traffic availability changed */ +static bool +_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + int prec) +{ + bool rc = FALSE; + + if (entry->state == WLFC_STATE_CLOSE) { + if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && + (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { + + if (entry->traffic_pending_bmp & NBITVAL(prec)) { + rc = TRUE; + entry->traffic_pending_bmp = + entry->traffic_pending_bmp & ~ NBITVAL(prec); + } + } + else { + if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { + rc = TRUE; + entry->traffic_pending_bmp = + entry->traffic_pending_bmp | NBITVAL(prec); + } + } + } + if (rc) { + /* request a TIM update to firmware at the next piggyback opportunity */ + if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { + entry->send_tim_signal = 1; + _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); + entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; + entry->send_tim_signal = 0; + } + else { + rc = FALSE; + } + } + return rc; +} + +static int +_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) +{ + wlfc_mac_descriptor_t* entry; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + if (entry == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_NOTFOUND; + } + /* + - suppressed packets go to sub_queue[2*prec + 1] AND + - delayed packets go to sub_queue[2*prec + 0] to ensure + order of delivery. + */ + if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, ((prec << 1) + 1), FALSE, + WLFC_SEQCOUNT(entry, prec)) + == FALSE) { + ctx->stats.delayq_full_error++; + /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ + WLFC_DBGMESG(("s")); + return BCME_ERROR; + } + + /* A packet has been pushed, update traffic availability bitmap, if applicable */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); + return BCME_OK; +} + +static int +_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, + wlfc_mac_descriptor_t* entry, void** packet, int header_needed, uint32* slot) +{ + int rc = BCME_OK; + int hslot = WLFC_HANGER_MAXITEMS; + bool send_tim_update = FALSE; + uint32 htod = 0; + uint16 htodseq = 0; + uint8 free_ctr, flags = 0; + int gen = 0xff; + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + void * p = *packet; + + *slot = hslot; + + if (entry == NULL) { + entry = _dhd_wlfc_find_table_entry(ctx, p); + } + + if (entry == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_ERROR; + } + + if (entry->send_tim_signal) { + send_tim_update = TRUE; + entry->send_tim_signal = 0; + entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; + } + + if (header_needed) { + if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { + hslot = (uint)(entry - &ctx->destination_entries.nodes[0]); + } else { + hslot = _dhd_wlfc_hanger_get_free_slot(ctx->hanger); + } + gen = entry->generation; + free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); + } else { + if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { + htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(p)); + } + + hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + + if (WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)) { + gen = entry->generation; + } else if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { + gen = WL_TXSTATUS_GET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + } else { + _dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); + } + + free_ctr = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + /* remove old header */ + _dhd_wlfc_pullheader(ctx, p); + } + + if (hslot >= WLFC_HANGER_MAXITEMS) { + DHD_ERROR(("Error: %s():no hanger slot available\n", __FUNCTION__)); + return BCME_ERROR; + } + + flags = WLFC_PKTFLAG_PKTFROMHOST; + if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { + /* + Indicate that this packet is being sent in response to an + explicit request from the firmware side. + */ + flags |= WLFC_PKTFLAG_PKT_REQUESTED; + } + if (pkt_is_dhcp(ctx->osh, p)) { + flags |= WLFC_PKTFLAG_PKT_FORCELOWRATE; + } + + WL_TXSTATUS_SET_FREERUNCTR(htod, free_ctr); + WL_TXSTATUS_SET_HSLOT(htod, hslot); + WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); + WL_TXSTATUS_SET_FLAGS(htod, flags); + WL_TXSTATUS_SET_GENERATION(htod, gen); + DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); + + rc = _dhd_wlfc_pushheader(ctx, &p, send_tim_update, + entry->traffic_lastreported_bmp, entry->mac_handle, htod, htodseq, FALSE); + if (rc == BCME_OK) { + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); + + if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && header_needed) { + /* + a new header was created for this packet. + push to hanger slot and scrub q. Since bus + send succeeded, increment seq number as well. + */ + rc = _dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); + if (rc == BCME_OK) { +#ifdef PROP_TXSTATUS_DEBUG + ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = + OSL_SYSUPTIME(); +#endif + } else { + DHD_ERROR(("%s() hanger_pushpkt() failed, rc: %d\n", + __FUNCTION__, rc)); + } + } + + if ((rc == BCME_OK) && header_needed) { + /* increment free running sequence count */ + WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); + } + } + *slot = hslot; + *packet = p; + return rc; +} + +static int +_dhd_wlfc_is_destination_open(athost_wl_status_info_t* ctx, + wlfc_mac_descriptor_t* entry, int prec) +{ + if (entry->interface_id >= WLFC_MAX_IFNUM) { + ASSERT(&ctx->destination_entries.other == entry); + return 1; + } + if (ctx->destination_entries.interfaces[entry->interface_id].iftype == + WLC_E_IF_ROLE_P2P_GO) { + /* - destination interface is of type p2p GO. + For a p2pGO interface, if the destination is OPEN but the interface is + CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is + destination-specific-credit left send packets. This is because the + firmware storing the destination-specific-requested packet in queue. + */ + if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && + (entry->requested_packet == 0)) { + return 0; + } + } + /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ + if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && + (entry->requested_packet == 0)) || + (!(entry->ac_bitmap & (1 << prec)))) { + return 0; + } + + return 1; +} + +static void* +_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, int prec, + uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out, + bool only_no_credit) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + wlfc_mac_descriptor_t* entry; + int total_entries; + void* p = NULL; + int i; + + *entry_out = NULL; + /* most cases a packet will count against FIFO credit */ + *ac_credit_spent = ((prec == AC_COUNT) && !ctx->bcmc_credit_supported) ? 0 : 1; + + /* search all entries, include nodes as well as interfaces */ + if (only_no_credit) { + total_entries = ctx->requested_entry_count; + } else { + total_entries = ctx->active_entry_count; + } + + for (i = 0; i < total_entries; i++) { + if (only_no_credit) { + entry = ctx->requested_entry[i]; + } else { + entry = ctx->active_entry_head; + /* move head to ensure fair round-robin */ + ctx->active_entry_head = ctx->active_entry_head->next; + } + ASSERT(entry); + + if (entry->occupied && _dhd_wlfc_is_destination_open(ctx, entry, prec) && + (entry->transit_count < WL_TXSTATUS_FREERUNCTR_MASK) && + !(WLFC_GET_REORDERSUPP(dhdp->wlfc_mode) && entry->suppressed)) { + if (entry->state == WLFC_STATE_CLOSE) { + *ac_credit_spent = 0; + } + + /* higher precedence will be picked up first, + * i.e. suppressed packets before delayed ones + */ + p = pktq_pdeq(&entry->psq, PSQ_SUP_IDX(prec)); + *needs_hdr = 0; + if (p == NULL) { + if (entry->suppressed == TRUE) { + /* skip this entry */ + continue; + } + /* De-Q from delay Q */ + p = pktq_pdeq(&entry->psq, PSQ_DLY_IDX(prec)); + *needs_hdr = 1; + } + + if (p != NULL) { + /* did the packet come from suppress sub-queue? */ + if (entry->requested_credit > 0) { + entry->requested_credit--; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_sent_packets++; +#endif + } else if (entry->requested_packet > 0) { + entry->requested_packet--; + DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); + } + + *entry_out = entry; + ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec]--; + ctx->pkt_cnt_per_ac[prec]--; + _dhd_wlfc_flow_control_check(ctx, &entry->psq, + DHD_PKTTAG_IF(PKTTAG(p))); + /* + A packet has been picked up, update traffic + availability bitmap, if applicable + */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + return p; + } + } + } + return NULL; +} + +static int +_dhd_wlfc_enque_delayq(athost_wl_status_info_t* ctx, void* pktbuf, int prec) +{ + wlfc_mac_descriptor_t* entry; + + if (pktbuf != NULL) { + entry = _dhd_wlfc_find_table_entry(ctx, pktbuf); + if (entry == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_ERROR; + } + + /* + - suppressed packets go to sub_queue[2*prec + 1] AND + - delayed packets go to sub_queue[2*prec + 0] to ensure + order of delivery. + */ + if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, pktbuf, (prec << 1), + FALSE, WLFC_SEQCOUNT(entry, prec)) + == FALSE) { + WLFC_DBGMESG(("D")); + ctx->stats.delayq_full_error++; + return BCME_ERROR; + } + + + /* + A packet has been pushed, update traffic availability bitmap, + if applicable + */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + } + + return BCME_OK; +} + +static bool _dhd_wlfc_ifpkt_fn(void* p, void *p_ifid) +{ + if (!p || !p_ifid) + return FALSE; + + return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (*((uint8 *)p_ifid) == DHD_PKTTAG_IF(PKTTAG(p)))); +} + +static bool _dhd_wlfc_entrypkt_fn(void* p, void *entry) +{ + if (!p || !entry) + return FALSE; + + return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (entry == DHD_PKTTAG_ENTRY(PKTTAG(p)))); +} + +static void +_dhd_wlfc_return_implied_credit(athost_wl_status_info_t* wlfc, void* pkt) +{ + dhd_pub_t *dhdp; + + if (!wlfc || !pkt) { + return; + } + + dhdp = (dhd_pub_t *)(wlfc->dhdp); + if (dhdp && (dhdp->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) && + DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { + int lender, credit_returned = 0; + uint8 fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pkt)); + + /* Note that borrower is fifo_id */ + /* Return credits to highest priority lender first */ + for (lender = AC_COUNT; lender >= 0; lender--) { + if (wlfc->credits_borrowed[fifo_id][lender] > 0) { + wlfc->FIFO_credit[lender]++; + wlfc->credits_borrowed[fifo_id][lender]--; + credit_returned = 1; + break; + } + } + + if (!credit_returned) { + wlfc->FIFO_credit[fifo_id]++; + } + } +} + +static void +_dhd_wlfc_hanger_free_pkt(athost_wl_status_info_t* wlfc, uint32 slot_id, uint8 pkt_state, + int pkt_txstatus) +{ + wlfc_hanger_t* hanger; + wlfc_hanger_item_t* item; + + if (!wlfc) + return; + + hanger = (wlfc_hanger_t*)wlfc->hanger; + if (!hanger) + return; + + if (slot_id == WLFC_HANGER_MAXITEMS) + return; + + item = &hanger->items[slot_id]; + item->pkt_state |= pkt_state; + if (pkt_txstatus != -1) { + item->pkt_txstatus = pkt_txstatus; + } + + if (item->pkt) { + if ((item->pkt_state & WLFC_HANGER_PKT_STATE_TXCOMPLETE) && + (item->pkt_state & (WLFC_HANGER_PKT_STATE_TXSTATUS | + WLFC_HANGER_PKT_STATE_CLEANUP))) { + void *p = NULL; + void *pkt = item->pkt; + uint8 old_state = item->state; + int ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, slot_id, &p, TRUE); + BCM_REFERENCE(ret); + BCM_REFERENCE(pkt); + ASSERT((ret == BCME_OK) && p && (pkt == p)); + + /* free packet */ + if (!(item->pkt_state & WLFC_HANGER_PKT_STATE_TXSTATUS)) { + /* cleanup case */ + wlfc_mac_descriptor_t *entry = _dhd_wlfc_find_table_entry(wlfc, p); + + ASSERT(entry); + if (entry->transit_count) + entry->transit_count--; + if (entry->suppr_transit_count) { + entry->suppr_transit_count--; + if (!entry->suppr_transit_count) + entry->suppressed = FALSE; + } + _dhd_wlfc_return_implied_credit(wlfc, p); + wlfc->stats.cleanup_fw_cnt++; + /* slot not freeable yet */ + item->state = old_state; + } + + wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(p))] + [DHD_PKTTAG_FIFO(PKTTAG(p))]--; + wlfc->stats.pktout++; + dhd_txcomplete((dhd_pub_t *)wlfc->dhdp, p, item->pkt_txstatus); + PKTFREE(wlfc->osh, p, TRUE); + } + } else { + if (item->pkt_state & WLFC_HANGER_PKT_STATE_TXSTATUS) { + /* free slot */ + if (item->state == WLFC_HANGER_ITEM_STATE_FREE) + DHD_ERROR(("Error: %s():%d get multi TXSTATUS for one packet???\n", + __FUNCTION__, __LINE__)); + item->state = WLFC_HANGER_ITEM_STATE_FREE; + } + } +} + +static void +_dhd_wlfc_pktq_flush(athost_wl_status_info_t* ctx, struct pktq *pq, + bool dir, f_processpkt_t fn, void *arg, q_type_t q_type) +{ + int prec; + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + + ASSERT(dhdp); + + /* Optimize flush, if pktq len = 0, just return. + * pktq len of 0 means pktq's prec q's are all empty. + */ + if (pq->len == 0) { + return; + } + + + for (prec = 0; prec < pq->num_prec; prec++) { + struct pktq_prec *q; + void *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 = PKTLINK(p); + else + PKTSETLINK(prev, PKTLINK(p)); + if (q_type == Q_TYPE_PSQ) { + if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { + _dhd_wlfc_hanger_remove_reference(ctx->hanger, p); + } + ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; + ctx->pkt_cnt_per_ac[prec>>1]--; + ctx->stats.cleanup_psq_cnt++; + if (!(prec & 1)) { + /* pkt in delayed q, so fake push BDC header for + * dhd_tcpack_check_xmit() and dhd_txcomplete(). + */ + _dhd_wlfc_pushheader(ctx, &p, FALSE, 0, 0, + 0, 0, TRUE); +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" + " Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(dhdp, + TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + } + } else if (q_type == Q_TYPE_AFQ) { + wlfc_mac_descriptor_t* entry = + _dhd_wlfc_find_table_entry(ctx, p); + if (entry->transit_count) + entry->transit_count--; + if (entry->suppr_transit_count) { + entry->suppr_transit_count--; + if (!entry->suppr_transit_count) + entry->suppressed = FALSE; + } + _dhd_wlfc_return_implied_credit(ctx, p); + ctx->stats.cleanup_fw_cnt++; + } + PKTSETLINK(p, NULL); + if (dir) { + ctx->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; + ctx->stats.pktout++; + dhd_txcomplete(dhdp, p, FALSE); + } + PKTFREE(ctx->osh, p, dir); + + q->len--; + pq->len--; + p = (head ? q->head : PKTLINK(prev)); + } else { + prev = p; + p = PKTLINK(p); + } + } + + if (q->head == NULL) { + ASSERT(q->len == 0); + q->tail = NULL; + } + + } + + if (fn == NULL) + ASSERT(pq->len == 0); +} + +static void* +_dhd_wlfc_pktq_pdeq_with_fn(struct pktq *pq, int prec, f_processpkt_t fn, void *arg) +{ + struct pktq_prec *q; + void *p, *prev = NULL; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + p = q->head; + + while (p) { + if (fn == NULL || (*fn)(p, arg)) { + break; + } else { + prev = p; + p = PKTLINK(p); + } + } + if (p == NULL) + return NULL; + + if (prev == NULL) { + if ((q->head = PKTLINK(p)) == NULL) { + q->tail = NULL; + } + } else { + PKTSETLINK(prev, PKTLINK(p)); + if (q->tail == p) { + q->tail = prev; + } + } + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +static void +_dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + int prec; + void *pkt = NULL, *head = NULL, *tail = NULL; + struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; + wlfc_mac_descriptor_t* entry; + + dhd_os_sdlock_txq(dhd); + for (prec = 0; prec < txq->num_prec; prec++) { + while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(dhd, pkt) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(dhd, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + if (!head) { + head = pkt; + } + if (tail) { + PKTSETLINK(tail, pkt); + } + tail = pkt; + } + } + dhd_os_sdunlock_txq(dhd); + + + while ((pkt = head)) { + head = PKTLINK(pkt); + PKTSETLINK(pkt, NULL); + entry = _dhd_wlfc_find_table_entry(wlfc, pkt); + + if (!WLFC_GET_AFQ(dhd->wlfc_mode) && + !_dhd_wlfc_hanger_remove_reference(h, pkt)) { + DHD_ERROR(("%s: can't find pkt(%p) in hanger, free it anyway\n", + __FUNCTION__, pkt)); + } + if (entry->transit_count) + entry->transit_count--; + if (entry->suppr_transit_count) { + entry->suppr_transit_count--; + if (!entry->suppr_transit_count) + entry->suppressed = FALSE; + } + _dhd_wlfc_return_implied_credit(wlfc, pkt); + wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pkt))][DHD_PKTTAG_FIFO(PKTTAG(pkt))]--; + wlfc->stats.pktout++; + wlfc->stats.cleanup_txq_cnt++; + dhd_txcomplete(dhd, pkt, FALSE); + PKTFREE(wlfc->osh, pkt, TRUE); + } +} + +void +_dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + int i; + int total_entries; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; + + wlfc->stats.cleanup_txq_cnt = 0; + wlfc->stats.cleanup_psq_cnt = 0; + wlfc->stats.cleanup_fw_cnt = 0; + /* + * flush sequence shoulde be txq -> psq -> hanger/afq, hanger has to be last one + */ + /* flush bus->txq */ + _dhd_wlfc_cleanup_txq(dhd, fn, arg); + + + /* flush psq, search all entries, include nodes as well as interfaces */ + total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); + table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; + + for (i = 0; i < total_entries; i++) { + if (table[i].occupied) { + /* release packets held in PSQ (both delayed and suppressed) */ + if (table[i].psq.len) { + WLFC_DBGMESG(("%s(): PSQ[%d].len = %d\n", + __FUNCTION__, i, table[i].psq.len)); + _dhd_wlfc_pktq_flush(wlfc, &table[i].psq, TRUE, + fn, arg, Q_TYPE_PSQ); + } + + /* free packets held in AFQ */ + if (WLFC_GET_AFQ(dhd->wlfc_mode) && (table[i].afq.len)) { + _dhd_wlfc_pktq_flush(wlfc, &table[i].afq, TRUE, + fn, arg, Q_TYPE_AFQ); + } + + if ((fn == NULL) && (&table[i] != &wlfc->destination_entries.other)) { + table[i].occupied = 0; + if (table[i].transit_count || table[i].suppr_transit_count) { + DHD_ERROR(("%s: table[%d] transit(%d), suppr_tansit(%d)\n", + __FUNCTION__, i, + table[i].transit_count, + table[i].suppr_transit_count)); + } + } + } + } + + /* + . flush remained pkt in hanger queue, not in bus->txq nor psq. + . the remained pkt was successfully downloaded to dongle already. + . hanger slot state cannot be set to free until receive txstatus update. + */ + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + for (i = 0; i < h->max_items; i++) { + if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) || + (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { + if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { + _dhd_wlfc_hanger_free_pkt(wlfc, i, + WLFC_HANGER_PKT_STATE_CLEANUP, FALSE); + } + } + } + } + + return; +} + +static int +_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + uint8 action, uint8 ifid, uint8 iftype, uint8* ea, + f_processpkt_t fn, void *arg) +{ + int rc = BCME_OK; + + + if ((action == eWLFC_MAC_ENTRY_ACTION_ADD) || (action == eWLFC_MAC_ENTRY_ACTION_UPDATE)) { + entry->occupied = 1; + entry->state = WLFC_STATE_OPEN; + entry->requested_credit = 0; + entry->interface_id = ifid; + entry->iftype = iftype; + entry->ac_bitmap = 0xff; /* update this when handling APSD */ + /* for an interface entry we may not care about the MAC address */ + if (ea != NULL) + memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); + + if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { + entry->suppressed = FALSE; + entry->transit_count = 0; + entry->suppr_transit_count = 0; + } + + if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { + dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); + pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); + if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { + pktq_init(&entry->afq, WLFC_AFQ_PREC_COUNT, WLFC_PSQ_LEN); + } + + if (entry->next == NULL) { + /* not linked to anywhere, add to tail */ + if (ctx->active_entry_head) { + entry->prev = ctx->active_entry_head->prev; + ctx->active_entry_head->prev->next = entry; + ctx->active_entry_head->prev = entry; + entry->next = ctx->active_entry_head; + + } else { + ASSERT(ctx->active_entry_count == 0); + entry->prev = entry->next = entry; + ctx->active_entry_head = entry; + } + ctx->active_entry_count++; + } else { + DHD_ERROR(("%s():%d, entry(%d)\n", __FUNCTION__, __LINE__, + (int)(entry - &ctx->destination_entries.nodes[0]))); + } + } + } else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { + /* When the entry is deleted, the packets that are queued in the entry must be + cleanup. The cleanup action should be before the occupied is set as 0. + */ + _dhd_wlfc_cleanup(ctx->dhdp, fn, arg); + _dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid); + + entry->occupied = 0; + entry->state = WLFC_STATE_CLOSE; + memset(&entry->ea[0], 0, ETHER_ADDR_LEN); + + if (entry->next) { + /* not floating, remove from Q */ + if (ctx->active_entry_count <= 1) { + /* last item */ + ctx->active_entry_head = NULL; + ctx->active_entry_count = 0; + } else { + entry->prev->next = entry->next; + entry->next->prev = entry->prev; + if (entry == ctx->active_entry_head) { + ctx->active_entry_head = entry->next; + } + ctx->active_entry_count--; + } + entry->next = entry->prev = NULL; + } else { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + } + } + return rc; +} + +#ifdef LIMIT_BORROW +static int +_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, int highest_lender_ac, int borrower_ac, + bool bBorrowAll) +{ + int lender_ac, borrow_limit = 0; + int rc = -1; + + if (ctx == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return -1; + } + + /* Borrow from lowest priority available AC (including BC/MC credits) */ + for (lender_ac = 0; lender_ac <= highest_lender_ac; lender_ac++) { + if (!bBorrowAll) { + borrow_limit = ctx->Init_FIFO_credit[lender_ac]/WLFC_BORROW_LIMIT_RATIO; + } else { + borrow_limit = 0; + } + + if (ctx->FIFO_credit[lender_ac] > borrow_limit) { + ctx->credits_borrowed[borrower_ac][lender_ac]++; + ctx->FIFO_credit[lender_ac]--; + rc = lender_ac; + break; + } + } + + return rc; +} + +static int _dhd_wlfc_return_credit(athost_wl_status_info_t* ctx, int lender_ac, int borrower_ac) +{ + if ((ctx == NULL) || (lender_ac < 0) || (lender_ac > AC_COUNT) || + (borrower_ac < 0) || (borrower_ac > AC_COUNT)) { + DHD_ERROR(("Error: %s():%d, ctx(%p), lender_ac(%d), borrower_ac(%d)\n", + __FUNCTION__, __LINE__, ctx, lender_ac, borrower_ac)); + + return BCME_BADARG; + } + + ctx->credits_borrowed[borrower_ac][lender_ac]--; + ctx->FIFO_credit[lender_ac]++; + + return BCME_OK; +} +#endif /* LIMIT_BORROW */ + +static int +_dhd_wlfc_interface_entry_update(void* state, + uint8 action, uint8 ifid, uint8 iftype, uint8* ea) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + wlfc_mac_descriptor_t* entry; + + if (ifid >= WLFC_MAX_IFNUM) + return BCME_BADARG; + + entry = &ctx->destination_entries.interfaces[ifid]; + + return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea, + _dhd_wlfc_ifpkt_fn, &ifid); +} + +static int +_dhd_wlfc_BCMCCredit_support_update(void* state) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + + ctx->bcmc_credit_supported = TRUE; + return BCME_OK; +} + +static int +_dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + int i; + + for (i = 0; i <= 4; i++) { + if (ctx->Init_FIFO_credit[i] != ctx->FIFO_credit[i]) { + DHD_ERROR(("%s: credit[i] is not returned, (%d %d)\n", + __FUNCTION__, ctx->Init_FIFO_credit[i], ctx->FIFO_credit[i])); + } + } + + /* update the AC FIFO credit map */ + ctx->FIFO_credit[0] += (credits[0] - ctx->Init_FIFO_credit[0]); + ctx->FIFO_credit[1] += (credits[1] - ctx->Init_FIFO_credit[1]); + ctx->FIFO_credit[2] += (credits[2] - ctx->Init_FIFO_credit[2]); + ctx->FIFO_credit[3] += (credits[3] - ctx->Init_FIFO_credit[3]); + ctx->FIFO_credit[4] += (credits[4] - ctx->Init_FIFO_credit[4]); + + ctx->Init_FIFO_credit[0] = credits[0]; + ctx->Init_FIFO_credit[1] = credits[1]; + ctx->Init_FIFO_credit[2] = credits[2]; + ctx->Init_FIFO_credit[3] = credits[3]; + ctx->Init_FIFO_credit[4] = credits[4]; + + /* credit for ATIM FIFO is not used yet. */ + ctx->Init_FIFO_credit[5] = ctx->FIFO_credit[5] = 0; + + return BCME_OK; +} + +static int +_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, + dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) +{ + uint32 hslot; + int rc; + dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); + + /* + if ac_fifo_credit_spent = 0 + + This packet will not count against the FIFO credit. + To ensure the txstatus corresponding to this packet + does not provide an implied credit (default behavior) + mark the packet accordingly. + + if ac_fifo_credit_spent = 1 + + This is a normal packet and it counts against the FIFO + credit count. + */ + DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); + rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, &commit_info->p, + commit_info->needs_hdr, &hslot); + + if (rc == BCME_OK) { + rc = fcommit(commit_ctx, commit_info->p); + if (rc == BCME_OK) { + uint8 gen = WL_TXSTATUS_GET_GENERATION( + DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))); + ctx->stats.pkt2bus++; + if (commit_info->ac_fifo_credit_spent || (ac == AC_COUNT)) { + ctx->stats.send_pkts[ac]++; + WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); + } + + if (gen != commit_info->mac_entry->generation) { + /* will be suppressed back by design */ + if (!commit_info->mac_entry->suppressed) { + commit_info->mac_entry->suppressed = TRUE; + } + commit_info->mac_entry->suppr_transit_count++; + } + commit_info->mac_entry->transit_count++; + } else if (commit_info->needs_hdr) { + if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { + void *pout = NULL; + /* pop hanger for delayed packet */ + _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT( + DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))), &pout, TRUE); + ASSERT(commit_info->p == pout); + } + } + } else { + ctx->stats.generic_error++; + } + + if (rc != BCME_OK) { + /* + pretx pkt process or bus commit has failed, rollback. + - remove wl-header for a delayed packet + - save wl-header header for suppressed packets + - reset credit check flag + */ + _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, commit_info->pkt_type, hslot); + DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), 0); + } + + return rc; +} + +static uint8 +_dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) +{ + wlfc_mac_descriptor_t* table = + ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; + uint8 table_index; + + if (ea != NULL) { + for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { + if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && + table[table_index].occupied) + return table_index; + } + } + return WLFC_MAC_DESC_ID_INVALID; +} + +static int +_dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, void** p_mac) +{ + uint8 status_flag; + uint32 status; + int ret = BCME_OK; + int remove_from_hanger = 1; + void* pktbuf = NULL; + uint8 fifo_id = 0, gen = 0, count = 0, hcnt; + uint16 hslot; + wlfc_mac_descriptor_t* entry = NULL; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + uint16 seq = 0, seq_fromfw = 0, seq_num = 0; + + memcpy(&status, pkt_info, sizeof(uint32)); + status_flag = WL_TXSTATUS_GET_FLAGS(status); + hcnt = WL_TXSTATUS_GET_FREERUNCTR(status); + hslot = WL_TXSTATUS_GET_HSLOT(status); + fifo_id = WL_TXSTATUS_GET_FIFO(status); + gen = WL_TXSTATUS_GET_GENERATION(status); + + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { + memcpy(&seq, pkt_info + WLFC_CTL_VALUE_LEN_TXSTATUS, WLFC_CTL_VALUE_LEN_SEQ); + seq_fromfw = WL_SEQ_GET_FROMFW(seq); + seq_num = WL_SEQ_GET_NUM(seq); + } + + wlfc->stats.txstatus_in += len; + + if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { + wlfc->stats.pkt_freed += len; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_DISCARD_NOACK) { + wlfc->stats.pkt_freed += len; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { + wlfc->stats.d11_suppress += len; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { + wlfc->stats.wl_suppress += len; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { + wlfc->stats.wlc_tossed_pkts += len; + } + + if (dhd->proptxstatus_txstatus_ignore) { + if (!remove_from_hanger) { + DHD_ERROR(("suppress txstatus: %d\n", status_flag)); + } + return BCME_OK; + } + + while (count < len) { + if (WLFC_GET_AFQ(dhd->wlfc_mode)) { + ret = _dhd_wlfc_deque_afq(wlfc, hslot, hcnt, fifo_id, &pktbuf); + } else { + ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, hslot, &pktbuf, FALSE); + if (!pktbuf) { + _dhd_wlfc_hanger_free_pkt(wlfc, hslot, + WLFC_HANGER_PKT_STATE_TXSTATUS, -1); + goto cont; + } + } + + if ((ret != BCME_OK) || !pktbuf) { + goto cont; + } + + /* set fifo_id to correct value because not all FW does that */ + fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + + if (!remove_from_hanger) { + /* this packet was suppressed */ + if (!entry->suppressed || (entry->generation != gen)) { + if (!entry->suppressed) { + entry->suppr_transit_count = entry->transit_count; + if (p_mac) { + *p_mac = entry; + } + } else { + DHD_ERROR(("gen(%d), entry->generation(%d)\n", + gen, entry->generation)); + } + entry->suppressed = TRUE; + + } + entry->generation = gen; + } + +#ifdef PROP_TXSTATUS_DEBUG + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) + { + uint32 new_t = OSL_SYSUPTIME(); + uint32 old_t; + uint32 delta; + old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[hslot].push_time; + + + wlfc->stats.latency_sample_count++; + if (new_t > old_t) + delta = new_t - old_t; + else + delta = 0xffffffff + new_t - old_t; + wlfc->stats.total_status_latency += delta; + wlfc->stats.latency_most_recent = delta; + + wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; + if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) + wlfc->stats.idx_delta = 0; + } +#endif /* PROP_TXSTATUS_DEBUG */ + + /* pick up the implicit credit from this packet */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { + _dhd_wlfc_return_implied_credit(wlfc, pktbuf); + } else { + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the destination entry (for pspoll etc.) + */ + if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) + entry->requested_credit++; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_acks++; +#endif + } + + if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || + (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { + /* save generation bit inside packet */ + WL_TXSTATUS_SET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(pktbuf)), gen); + + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { + WL_SEQ_SET_FROMDRV(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_fromfw); + WL_SEQ_SET_NUM(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_num); + } + + ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); + if (ret != BCME_OK) { + /* delay q is full, drop this packet */ + DHD_WLFC_QMON_COMPLETE(entry); + _dhd_wlfc_prec_drop(dhd, (fifo_id << 1) + 1, pktbuf, FALSE); + } else { + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + /* Mark suppressed to avoid a double free + during wlfc cleanup + */ + _dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, hslot, gen); + } + } + } else { + + DHD_WLFC_QMON_COMPLETE(entry); + + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + _dhd_wlfc_hanger_free_pkt(wlfc, hslot, + WLFC_HANGER_PKT_STATE_TXSTATUS, TRUE); + } else { + dhd_txcomplete(dhd, pktbuf, TRUE); + wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pktbuf))] + [DHD_PKTTAG_FIFO(PKTTAG(pktbuf))]--; + wlfc->stats.pktout++; + /* free the packet */ + PKTFREE(wlfc->osh, pktbuf, TRUE); + } + } + /* pkt back from firmware side */ + if (entry->transit_count) + entry->transit_count--; + if (entry->suppr_transit_count) { + entry->suppr_transit_count--; + if (!entry->suppr_transit_count) + entry->suppressed = FALSE; + } + +cont: + hcnt = (hcnt + 1) & WL_TXSTATUS_FREERUNCTR_MASK; + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + hslot = (hslot + 1) & WL_TXSTATUS_HSLOT_MASK; + } + + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode) && seq_fromfw) { + seq_num = (seq_num + 1) & WL_SEQ_NUM_MASK; + } + + count++; + } + return BCME_OK; +} + +static int +_dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) +{ + int i; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { +#ifdef PROP_TXSTATUS_DEBUG + wlfc->stats.fifo_credits_back[i] += credits[i]; +#endif + + /* update FIFO credits */ + if (dhd->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) + { + int lender; /* Note that borrower is i */ + + /* Return credits to highest priority lender first */ + for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { + if (wlfc->credits_borrowed[i][lender] > 0) { + if (credits[i] >= wlfc->credits_borrowed[i][lender]) { + credits[i] -= + (uint8)wlfc->credits_borrowed[i][lender]; + wlfc->FIFO_credit[lender] += + wlfc->credits_borrowed[i][lender]; + wlfc->credits_borrowed[i][lender] = 0; + } + else { + wlfc->credits_borrowed[i][lender] -= credits[i]; + wlfc->FIFO_credit[lender] += credits[i]; + credits[i] = 0; + } + } + } + + /* If we have more credits left over, these must belong to the AC */ + if (credits[i] > 0) { + wlfc->FIFO_credit[i] += credits[i]; + } + + if (wlfc->FIFO_credit[i] > wlfc->Init_FIFO_credit[i]) { + wlfc->FIFO_credit[i] = wlfc->Init_FIFO_credit[i]; + } + } + } + + return BCME_OK; +} + +static void +_dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* entry; + int prec; + void *pkt = NULL, *head = NULL, *tail = NULL; + struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); + uint8 results[WLFC_CTL_VALUE_LEN_TXSTATUS+WLFC_CTL_VALUE_LEN_SEQ]; + uint8 credits[WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK] = {0}; + uint32 htod = 0; + uint16 htodseq = 0; + bool bCreditUpdate = FALSE; + + dhd_os_sdlock_txq(dhd); + for (prec = 0; prec < txq->num_prec; prec++) { + while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { + if (!head) { + head = pkt; + } + if (tail) { + PKTSETLINK(tail, pkt); + } + tail = pkt; + } + } + dhd_os_sdunlock_txq(dhd); + + while ((pkt = head)) { + head = PKTLINK(pkt); + PKTSETLINK(pkt, NULL); + + entry = _dhd_wlfc_find_table_entry(wlfc, pkt); + + /* fake a suppression txstatus */ + htod = DHD_PKTTAG_H2DTAG(PKTTAG(pkt)); + WL_TXSTATUS_SET_FLAGS(htod, WLFC_CTL_PKTFLAG_WLSUPPRESS); + WL_TXSTATUS_SET_GENERATION(htod, entry->generation); + memcpy(results, &htod, WLFC_CTL_VALUE_LEN_TXSTATUS); + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { + htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(pkt)); + if (WL_SEQ_GET_FROMDRV(htodseq)) { + WL_SEQ_SET_FROMFW(htodseq, 1); + WL_SEQ_SET_FROMDRV(htodseq, 0); + } + memcpy(results + WLFC_CTL_VALUE_LEN_TXSTATUS, &htodseq, + WLFC_CTL_VALUE_LEN_SEQ); + } + if (WLFC_GET_AFQ(dhd->wlfc_mode)) { + _dhd_wlfc_enque_afq(wlfc, pkt); + } + _dhd_wlfc_compressed_txstatus_update(dhd, results, 1, NULL); + + /* fake a fifo credit back */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { + credits[DHD_PKTTAG_FIFO(PKTTAG(pkt))]++; + bCreditUpdate = TRUE; + } + } + + if (bCreditUpdate) { + _dhd_wlfc_fifocreditback_indicate(dhd, credits); + } +} + + +static int +_dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) +{ + uint32 timestamp; + + (void)dhd; + + bcopy(&value[2], ×tamp, sizeof(uint32)); + DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp)); + return BCME_OK; +} + +static int +_dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) +{ + (void)dhd; + (void)rssi; + return BCME_OK; +} + +static void +_dhd_wlfc_add_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) +{ + int i; + + if (!wlfc || !entry) { + return; + } + + for (i = 0; i < wlfc->requested_entry_count; i++) { + if (entry == wlfc->requested_entry[i]) { + break; + } + } + + if (i == wlfc->requested_entry_count) { + /* no match entry found */ + ASSERT(wlfc->requested_entry_count <= (WLFC_MAC_DESC_TABLE_SIZE-1)); + wlfc->requested_entry[wlfc->requested_entry_count++] = entry; + } +} + +static void +_dhd_wlfc_remove_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) +{ + int i; + + if (!wlfc || !entry) { + return; + } + + for (i = 0; i < wlfc->requested_entry_count; i++) { + if (entry == wlfc->requested_entry[i]) { + break; + } + } + + if (i < wlfc->requested_entry_count) { + /* found */ + ASSERT(wlfc->requested_entry_count > 0); + wlfc->requested_entry_count--; + if (i != wlfc->requested_entry_count) { + wlfc->requested_entry[i] = + wlfc->requested_entry[wlfc->requested_entry_count]; + } + wlfc->requested_entry[wlfc->requested_entry_count] = NULL; + } +} + +static int +_dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + int rc; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + uint8 existing_index; + uint8 table_index; + uint8 ifid; + uint8* ea; + + WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", + __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], + ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), + WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); + + table = wlfc->destination_entries.nodes; + table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); + ifid = value[1]; + ea = &value[2]; + + _dhd_wlfc_remove_requested_entry(wlfc, &table[table_index]); + if (type == WLFC_CTL_TYPE_MACDESC_ADD) { + existing_index = _dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); + if ((existing_index != WLFC_MAC_DESC_ID_INVALID) && + (existing_index != table_index) && table[existing_index].occupied) { + /* + there is an existing different entry, free the old one + and move it to new index if necessary. + */ + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[existing_index], + eWLFC_MAC_ENTRY_ACTION_DEL, table[existing_index].interface_id, + table[existing_index].iftype, NULL, _dhd_wlfc_entrypkt_fn, + &table[existing_index]); + } + + if (!table[table_index].occupied) { + /* this new MAC entry does not exist, create one */ + table[table_index].mac_handle = value[0]; + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], + eWLFC_MAC_ENTRY_ACTION_ADD, ifid, + wlfc->destination_entries.interfaces[ifid].iftype, + ea, NULL, NULL); + } else { + /* the space should have been empty, but it's not */ + wlfc->stats.mac_update_failed++; + } + } + + if (type == WLFC_CTL_TYPE_MACDESC_DEL) { + if (table[table_index].occupied) { + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], + eWLFC_MAC_ENTRY_ACTION_DEL, ifid, + wlfc->destination_entries.interfaces[ifid].iftype, + ea, _dhd_wlfc_entrypkt_fn, &table[table_index]); + } else { + /* the space should have been occupied, but it's not */ + wlfc->stats.mac_update_failed++; + } + } + BCM_REFERENCE(rc); + return BCME_OK; +} + +static int +_dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + /* Handle PS on/off indication */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle = value[0]; + int i; + + table = wlfc->destination_entries.nodes; + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + if (type == WLFC_CTL_TYPE_MAC_OPEN) { + desc->state = WLFC_STATE_OPEN; + desc->ac_bitmap = 0xff; + DHD_WLFC_CTRINC_MAC_OPEN(desc); + desc->requested_credit = 0; + desc->requested_packet = 0; + _dhd_wlfc_remove_requested_entry(wlfc, desc); + } + else { + desc->state = WLFC_STATE_CLOSE; + DHD_WLFC_CTRINC_MAC_CLOSE(desc); + /* + Indicate to firmware if there is any traffic pending. + */ + for (i = 0; i < AC_COUNT; i++) { + _dhd_wlfc_traffic_pending_check(wlfc, desc, i); + } + } + } + else { + wlfc->stats.psmode_update_failed++; + } + return BCME_OK; +} + +static int +_dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + /* Handle PS on/off indication */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + uint8 if_id = value[0]; + + if (if_id < WLFC_MAX_IFNUM) { + table = wlfc->destination_entries.interfaces; + if (table[if_id].occupied) { + if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { + table[if_id].state = WLFC_STATE_OPEN; + /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ + } + else { + table[if_id].state = WLFC_STATE_CLOSE; + /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ + } + return BCME_OK; + } + } + wlfc->stats.interface_update_failed++; + + return BCME_OK; +} + +static int +_dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle; + uint8 credit; + + table = wlfc->destination_entries.nodes; + mac_handle = value[1]; + credit = value[0]; + + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + desc->requested_credit = credit; + + desc->ac_bitmap = value[2] & (~(1<stats.credit_request_failed++; + } + return BCME_OK; +} + +static int +_dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle; + uint8 packet_count; + + table = wlfc->destination_entries.nodes; + mac_handle = value[1]; + packet_count = value[0]; + + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + desc->requested_packet = packet_count; + + desc->ac_bitmap = value[2] & (~(1<stats.packet_request_failed++; + } + return BCME_OK; +} + +static void +_dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) +{ + if (info_len) { + /* Check copy length to avoid buffer overrun. In case of length exceeding + * WLHOST_REORDERDATA_TOTLEN, return failure instead sending incomplete result + * of length WLHOST_REORDERDATA_TOTLEN + */ + if ((info_buf) && (len <= WLHOST_REORDERDATA_TOTLEN)) { + bcopy(val, info_buf, len); + *info_len = len; + } + else + *info_len = 0; + } +} + +/* + * public functions + */ + +bool dhd_wlfc_is_supported(dhd_pub_t *dhd) +{ + bool rc = TRUE; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return FALSE; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + rc = FALSE; + } + + dhd_os_wlfc_unblock(dhd); + + return rc; +} + +int dhd_wlfc_enable(dhd_pub_t *dhd) +{ + int i, rc = BCME_OK; + athost_wl_status_info_t* wlfc; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_enabled || dhd->wlfc_state) { + rc = BCME_OK; + goto exit; + } + + /* allocate space to track txstatus propagated from firmware */ + dhd->wlfc_state = DHD_OS_PREALLOC(dhd, DHD_PREALLOC_DHD_WLFC_INFO, + sizeof(athost_wl_status_info_t)); + if (dhd->wlfc_state == NULL) { + rc = BCME_NOMEM; + goto exit; + } + + /* initialize state space */ + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + memset(wlfc, 0, sizeof(athost_wl_status_info_t)); + + /* remember osh & dhdp */ + wlfc->osh = dhd->osh; + wlfc->dhdp = dhd; + + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + wlfc->hanger = _dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); + if (wlfc->hanger == NULL) { + DHD_OS_PREFREE(dhd, dhd->wlfc_state, + sizeof(athost_wl_status_info_t)); + dhd->wlfc_state = NULL; + rc = BCME_NOMEM; + goto exit; + } + } + + dhd->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; + /* default to check rx pkt */ + if (dhd->op_mode & DHD_FLAG_IBSS_MODE) { + dhd->wlfc_rxpkt_chk = FALSE; + } else { + dhd->wlfc_rxpkt_chk = TRUE; + } + + + /* initialize all interfaces to accept traffic */ + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + wlfc->hostif_flow_state[i] = OFF; + } + + _dhd_wlfc_mac_entry_update(wlfc, &wlfc->destination_entries.other, + eWLFC_MAC_ENTRY_ACTION_ADD, 0xff, 0, NULL, NULL, NULL); + + wlfc->allow_credit_borrow = 0; + wlfc->single_ac = 0; + wlfc->single_ac_timestamp = 0; + + +exit: + dhd_os_wlfc_unblock(dhd); + + return rc; +} +#ifdef SUPPORT_P2P_GO_PS +int +dhd_wlfc_suspend(dhd_pub_t *dhd) +{ + uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ + uint32 tlv = 0; + int ret; + + DHD_TRACE(("%s: masking wlfc events\n", __FUNCTION__)); + if (!dhd->wlfc_enabled) + return -1; + + ret = dhd_iovar(dhd, 0, "tlv", NULL, 0, + (char *)iovbuf, sizeof(iovbuf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); + return -1; + } + tlv = iovbuf[0]; + if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == 0) + return 0; + tlv &= ~(WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); + + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", + __FUNCTION__, tlv)); + return -1; + } + + return 0; +} + +int +dhd_wlfc_resume(dhd_pub_t *dhd) +{ + uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ + uint32 tlv = 0; + int ret; + + DHD_TRACE(("%s: unmasking wlfc events\n", __FUNCTION__)); + if (!dhd->wlfc_enabled) + return -1; + + ret = dhd_iovar(dhd, 0, "tlv", NULL, 0, + (char *)iovbuf, sizeof(iovbuf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); + return -1; + } + tlv = iovbuf[0]; + if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == + (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) + return 0; + tlv |= (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); + + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", + __FUNCTION__, tlv)); + return -1; + } + + return 0; +} +#endif /* SUPPORT_P2P_GO_PS */ + +int +dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, + uint *reorder_info_len) +{ + uint8 type, len; + uint8* value; + uint8* tmpbuf; + uint16 remainder = (uint16)tlv_hdr_len; + uint16 processed = 0; + athost_wl_status_info_t* wlfc = NULL; + void* entry; + + if ((dhd == NULL) || (pktbuf == NULL)) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (dhd->proptxstatus_mode != WLFC_ONLY_AMPDU_HOSTREORDER) { + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + } + + tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); + + if (remainder) { + while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { + type = tmpbuf[processed]; + if (type == WLFC_CTL_TYPE_FILLER) { + remainder -= 1; + processed += 1; + continue; + } + + len = tmpbuf[processed + 1]; + value = &tmpbuf[processed + 2]; + + if (remainder < (2 + len)) + break; + + remainder -= 2 + len; + processed += 2 + len; + entry = NULL; + + DHD_INFO(("%s():%d type %d remainder %d processed %d\n", + __FUNCTION__, __LINE__, type, remainder, processed)); + + if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) + _dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, + reorder_info_len); + + if (wlfc == NULL) { + ASSERT(dhd->proptxstatus_mode == WLFC_ONLY_AMPDU_HOSTREORDER); + + if (type != WLFC_CTL_TYPE_HOST_REORDER_RXPKTS && + type != WLFC_CTL_TYPE_TRANS_ID) + DHD_INFO(("%s():%d dhd->wlfc_state is NULL yet!" + " type %d remainder %d processed %d\n", + __FUNCTION__, __LINE__, type, remainder, processed)); + continue; + } + + if (type == WLFC_CTL_TYPE_TXSTATUS) { + _dhd_wlfc_compressed_txstatus_update(dhd, value, 1, &entry); + } + else if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) { + uint8 compcnt_offset = WLFC_CTL_VALUE_LEN_TXSTATUS; + + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { + compcnt_offset += WLFC_CTL_VALUE_LEN_SEQ; + } + _dhd_wlfc_compressed_txstatus_update(dhd, value, + value[compcnt_offset], &entry); + } + else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) + _dhd_wlfc_fifocreditback_indicate(dhd, value); + + else if (type == WLFC_CTL_TYPE_RSSI) + _dhd_wlfc_rssi_indicate(dhd, value); + + else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) + _dhd_wlfc_credit_request(dhd, value); + + else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) + _dhd_wlfc_packet_request(dhd, value); + + else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || + (type == WLFC_CTL_TYPE_MAC_CLOSE)) + _dhd_wlfc_psmode_update(dhd, value, type); + + else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || + (type == WLFC_CTL_TYPE_MACDESC_DEL)) + _dhd_wlfc_mac_table_update(dhd, value, type); + + else if (type == WLFC_CTL_TYPE_TRANS_ID) + _dhd_wlfc_dbg_senum_check(dhd, value); + + else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || + (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { + _dhd_wlfc_interface_update(dhd, value, type); + } + + if (entry && WLFC_GET_REORDERSUPP(dhd->wlfc_mode)) { + /* suppress all packets for this mac entry from bus->txq */ + _dhd_wlfc_suppress_txq(dhd, _dhd_wlfc_entrypkt_fn, entry); + } + } + if (remainder != 0 && wlfc) { + /* trouble..., something is not right */ + wlfc->stats.tlv_parse_failed++; + } + } + + if (wlfc) + wlfc->stats.dhd_hdrpulls++; + + dhd_os_wlfc_unblock(dhd); + return BCME_OK; +} + +int +dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf, + bool need_toggle_host_if) +{ + int ac, single_ac = 0, rc = BCME_OK; + dhd_wlfc_commit_info_t commit_info; + athost_wl_status_info_t* ctx; + int bus_retry_count = 0; + + uint8 tx_map = 0; /* packets (send + in queue), Bitmask for 4 ACs + BC/MC */ + uint8 rx_map = 0; /* received packets, Bitmask for 4 ACs + BC/MC */ + uint8 packets_map = 0; /* packets in queue, Bitmask for 4 ACs + BC/MC */ + bool no_credit = FALSE; + + int lender; + + if ((dhdp == NULL) || (fcommit == NULL)) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + if (pktbuf) { + DHD_PKTTAG_WLFCPKT_SET(PKTTAG(pktbuf), 0); + } + rc = WLFC_UNSUPPORTED; + goto exit2; + } + + ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; + + + if (dhdp->proptxstatus_module_ignore) { + if (pktbuf) { + uint32 htod = 0; + WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); + _dhd_wlfc_pushheader(ctx, &pktbuf, FALSE, 0, 0, htod, 0, FALSE); + if (fcommit(commit_ctx, pktbuf)) + PKTFREE(ctx->osh, pktbuf, TRUE); + rc = BCME_OK; + } + goto exit; + } + + memset(&commit_info, 0, sizeof(commit_info)); + + /* + Commit packets for regular AC traffic. Higher priority first. + First, use up FIFO credits available to each AC. Based on distribution + and credits left, borrow from other ACs as applicable + + -NOTE: + If the bus between the host and firmware is overwhelmed by the + traffic from host, it is possible that higher priority traffic + starves the lower priority queue. If that occurs often, we may + have to employ weighted round-robin or ucode scheme to avoid + low priority packet starvation. + */ + + if (pktbuf) { + DHD_PKTTAG_WLFCPKT_SET(PKTTAG(pktbuf), 1); + ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + /* en-queue the packets to respective queue. */ + rc = _dhd_wlfc_enque_delayq(ctx, pktbuf, ac); + if (rc) { + _dhd_wlfc_prec_drop(ctx->dhdp, (ac << 1), pktbuf, FALSE); + } else { + ctx->stats.pktin++; + ctx->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pktbuf))][ac]++; + } + } + + for (ac = AC_COUNT; ac >= 0; ac--) { + if (dhdp->wlfc_rxpkt_chk) { + /* check rx packet */ + uint32 curr_t = OSL_SYSUPTIME(), delta; + + delta = curr_t - ctx->rx_timestamp[ac]; + if (delta < WLFC_RX_DETECTION_THRESHOLD_MS) { + rx_map |= (1 << ac); + } + } + + if (ctx->pkt_cnt_per_ac[ac] == 0) { + continue; + } + tx_map |= (1 << ac); + single_ac = ac + 1; + while (FALSE == dhdp->proptxstatus_txoff) { + /* packets from delayQ with less priority are fresh and + * they'd need header and have no MAC entry + */ + no_credit = (ctx->FIFO_credit[ac] < 1); + if (dhdp->proptxstatus_credit_ignore || + ((ac == AC_COUNT) && !ctx->bcmc_credit_supported)) { + no_credit = FALSE; + } + + lender = -1; +#ifdef LIMIT_BORROW + if (no_credit && (ac < AC_COUNT) && (tx_map >= rx_map)) { + /* try borrow from lower priority */ + lender = _dhd_wlfc_borrow_credit(ctx, ac - 1, ac, FALSE); + if (lender != -1) { + no_credit = FALSE; + } + } +#endif + commit_info.needs_hdr = 1; + commit_info.mac_entry = NULL; + commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, + &(commit_info.ac_fifo_credit_spent), + &(commit_info.needs_hdr), + &(commit_info.mac_entry), + no_credit); + commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : + eWLFC_PKTTYPE_SUPPRESSED; + + if (commit_info.p == NULL) { +#ifdef LIMIT_BORROW + if (lender != -1) { + _dhd_wlfc_return_credit(ctx, lender, ac); + } +#endif + break; + } + + if (!dhdp->proptxstatus_credit_ignore && (lender == -1)) { + ASSERT(ctx->FIFO_credit[ac] >= commit_info.ac_fifo_credit_spent); + } + /* here we can ensure have credit or no credit needed */ + rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, fcommit, + commit_ctx); + + /* Bus commits may fail (e.g. flow control); abort after retries */ + if (rc == BCME_OK) { + if (commit_info.ac_fifo_credit_spent && (lender == -1)) { + ctx->FIFO_credit[ac]--; + } +#ifdef LIMIT_BORROW + else if (!commit_info.ac_fifo_credit_spent && (lender != -1)) { + _dhd_wlfc_return_credit(ctx, lender, ac); + } +#endif + } else { +#ifdef LIMIT_BORROW + if (lender != -1) { + _dhd_wlfc_return_credit(ctx, lender, ac); + } +#endif + bus_retry_count++; + if (bus_retry_count >= BUS_RETRIES) { + DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); + goto exit; + } + } + } + + if (ctx->pkt_cnt_per_ac[ac]) { + packets_map |= (1 << ac); + } + } + + if ((tx_map == 0) || dhdp->proptxstatus_credit_ignore) { + /* nothing send out or remain in queue */ + rc = BCME_OK; + goto exit; + } + + if (((tx_map & (tx_map - 1)) == 0) && (tx_map >= rx_map)) { + /* only one tx ac exist and no higher rx ac */ + if ((single_ac == ctx->single_ac) && ctx->allow_credit_borrow) { + ac = single_ac - 1; + } else { + uint32 delta; + uint32 curr_t = OSL_SYSUPTIME(); + + if (single_ac != ctx->single_ac) { + /* new single ac traffic (first single ac or different single ac) */ + ctx->allow_credit_borrow = 0; + ctx->single_ac_timestamp = curr_t; + ctx->single_ac = (uint8)single_ac; + rc = BCME_OK; + goto exit; + } + /* same ac traffic, check if it lasts enough time */ + delta = curr_t - ctx->single_ac_timestamp; + + if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { + /* wait enough time, can borrow now */ + ctx->allow_credit_borrow = 1; + ac = single_ac - 1; + } else { + rc = BCME_OK; + goto exit; + } + } + } else { + /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ + ctx->allow_credit_borrow = 0; + ctx->single_ac_timestamp = 0; + ctx->single_ac = 0; + rc = BCME_OK; + goto exit; + } + + if (packets_map == 0) { + /* nothing to send, skip borrow */ + rc = BCME_OK; + goto exit; + } + + /* At this point, borrow all credits only for ac */ + while (FALSE == dhdp->proptxstatus_txoff) { +#ifdef LIMIT_BORROW + if ((lender = _dhd_wlfc_borrow_credit(ctx, AC_COUNT, ac, TRUE)) == -1) { + break; + } +#endif + commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, + &(commit_info.ac_fifo_credit_spent), + &(commit_info.needs_hdr), + &(commit_info.mac_entry), + FALSE); + if (commit_info.p == NULL) { + /* before borrow only one ac exists and now this only ac is empty */ +#ifdef LIMIT_BORROW + _dhd_wlfc_return_credit(ctx, lender, ac); +#endif + break; + } + + commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : + eWLFC_PKTTYPE_SUPPRESSED; + + rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, + fcommit, commit_ctx); + + /* Bus commits may fail (e.g. flow control); abort after retries */ + if (rc == BCME_OK) { + + if (commit_info.ac_fifo_credit_spent) { +#ifndef LIMIT_BORROW + ctx->FIFO_credit[ac]--; +#endif + } else { +#ifdef LIMIT_BORROW + _dhd_wlfc_return_credit(ctx, lender, ac); +#endif + } + } else { +#ifdef LIMIT_BORROW + _dhd_wlfc_return_credit(ctx, lender, ac); +#endif + bus_retry_count++; + if (bus_retry_count >= BUS_RETRIES) { + DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); + goto exit; + } + } + } + +exit: + if (need_toggle_host_if && ctx->toggle_host_if) { + ctx->toggle_host_if = 0; + } + +exit2: + dhd_os_wlfc_unblock(dhdp); + return rc; +} + +int +dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) +{ + athost_wl_status_info_t* wlfc; + void* pout = NULL; + int rtn = BCME_OK; + if ((dhd == NULL) || (txp == NULL)) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + rtn = WLFC_UNSUPPORTED; + goto EXIT; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { +#ifdef PROP_TXSTATUS_DEBUG + wlfc->stats.signal_only_pkts_freed++; +#endif + /* is this a signal-only packet? */ + _dhd_wlfc_pullheader(wlfc, txp); + PKTFREE(wlfc->osh, txp, TRUE); + goto EXIT; + } + + if (!success || dhd->proptxstatus_txstatus_ignore) { + wlfc_mac_descriptor_t *entry = _dhd_wlfc_find_table_entry(wlfc, txp); + + WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", + __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + _dhd_wlfc_hanger_poppkt(wlfc->hanger, WL_TXSTATUS_GET_HSLOT( + DHD_PKTTAG_H2DTAG(PKTTAG(txp))), &pout, TRUE); + ASSERT(txp == pout); + } + + /* indicate failure and free the packet */ + dhd_txcomplete(dhd, txp, success); + + /* return the credit, if necessary */ + _dhd_wlfc_return_implied_credit(wlfc, txp); + + if (entry->transit_count) + entry->transit_count--; + if (entry->suppr_transit_count) { + entry->suppr_transit_count--; + if (!entry->suppr_transit_count) + entry->suppressed = FALSE; + } + wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(txp))][DHD_PKTTAG_FIFO(PKTTAG(txp))]--; + wlfc->stats.pktout++; + PKTFREE(wlfc->osh, txp, TRUE); + } else { + /* bus confirmed pkt went to firmware side */ + if (WLFC_GET_AFQ(dhd->wlfc_mode)) { + _dhd_wlfc_enque_afq(wlfc, txp); + } else { + int hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(txp))); + _dhd_wlfc_hanger_free_pkt(wlfc, hslot, + WLFC_HANGER_PKT_STATE_TXCOMPLETE, -1); + } + } + +EXIT: + dhd_os_wlfc_unblock(dhd); + return rtn; +} + +int +dhd_wlfc_init(dhd_pub_t *dhd) +{ + char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */ + /* enable all signals & indicate host proptxstatus logic is active */ + uint32 tlv, mode, fw_caps; + int ret = 0; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + if (dhd->wlfc_enabled) { + DHD_ERROR(("%s():%d, Already enabled!\n", __FUNCTION__, __LINE__)); + dhd_os_wlfc_unblock(dhd); + return BCME_OK; + } + dhd->wlfc_enabled = TRUE; + dhd_os_wlfc_unblock(dhd); + + tlv = WLFC_FLAGS_RSSI_SIGNALS | + WLFC_FLAGS_XONXOFF_SIGNALS | + WLFC_FLAGS_CREDIT_STATUS_SIGNALS | + WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | + WLFC_FLAGS_HOST_RXRERODER_ACTIVE; + + + /* + try to enable/disable signaling by sending "tlv" iovar. if that fails, + fallback to no flow control? Print a message for now. + */ + + /* enable proptxtstatus signaling by default */ + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, + sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); + } + else { + /* + Leaving the message for now, it should be removed after a while; once + the tlv situation is stable. + */ + DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", + dhd->wlfc_enabled?"enabled":"disabled", tlv)); + } + + /* query caps */ + ret = dhd_iovar(dhd, 0, "wlfc_mode", (char *)&mode, sizeof(mode), + iovbuf, sizeof(iovbuf), FALSE); + + if (ret >= 0) { + fw_caps = *((uint32 *)iovbuf); + mode = 0; + DHD_ERROR(("%s: query wlfc_mode succeed, fw_caps=0x%x\n", __FUNCTION__, fw_caps)); + + if (WLFC_IS_OLD_DEF(fw_caps)) { + /* enable proptxtstatus v2 by default */ + mode = WLFC_MODE_AFQ; + } else { + WLFC_SET_AFQ(mode, WLFC_GET_AFQ(fw_caps)); + WLFC_SET_REUSESEQ(mode, WLFC_GET_REUSESEQ(fw_caps)); + WLFC_SET_REORDERSUPP(mode, WLFC_GET_REORDERSUPP(fw_caps)); + } + ret = dhd_iovar(dhd, 0, "wlfc_mode", (char *)&mode, + sizeof(mode), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: failed to set wlfc mode, ret = %d\n", __FUNCTION__, ret)); + } + } + + dhd_os_wlfc_block(dhd); + + dhd->wlfc_mode = 0; + if (ret >= 0) { + if (WLFC_IS_OLD_DEF(mode)) { + WLFC_SET_AFQ(dhd->wlfc_mode, (mode == WLFC_MODE_AFQ)); + } else { + dhd->wlfc_mode = mode; + } + } + DHD_ERROR(("dhd_wlfc_init(): wlfc_mode=0x%x, ret=%d\n", dhd->wlfc_mode, ret)); + + dhd_os_wlfc_unblock(dhd); + + if (dhd->plat_init) + dhd->plat_init((void *)dhd); + + return BCME_OK; +} + +int +dhd_wlfc_hostreorder_init(dhd_pub_t *dhd) +{ + /* enable only ampdu hostreorder here */ + uint32 tlv; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + DHD_TRACE(("%s():%d Enter\n", __FUNCTION__, __LINE__)); + + tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; + + /* enable proptxtstatus signaling by default */ + if (dhd_iovar(dhd, 0, "tlv", (char *)&tlv, + sizeof(tlv), NULL, 0, TRUE) < 0) { + DHD_ERROR(("%s(): failed to enable/disable bdcv2 tlv signaling\n", + __FUNCTION__)); + } + else { + /* + Leaving the message for now, it should be removed after a while; once + the tlv situation is stable. + */ + DHD_ERROR(("%s(): successful bdcv2 tlv signaling, %d\n", + __FUNCTION__, tlv)); + } + + dhd_os_wlfc_block(dhd); + dhd->proptxstatus_mode = WLFC_ONLY_AMPDU_HOSTREORDER; + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int +dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + _dhd_wlfc_cleanup_txq(dhd, fn, arg); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +/* release all packet resources */ +int +dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + _dhd_wlfc_cleanup(dhd, fn, arg); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int +dhd_wlfc_deinit(dhd_pub_t *dhd) +{ + char iovbuf[32]; /* Room for "ampdu_hostreorder" or "tlv" + '\0' + parameter */ + /* cleanup all psq related resources */ + athost_wl_status_info_t* wlfc; + uint32 tlv = 0; + uint32 hostreorder = 0; + int ret = BCME_OK; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + if (!dhd->wlfc_enabled) { + DHD_ERROR(("%s():%d, Already disabled!\n", __FUNCTION__, __LINE__)); + dhd_os_wlfc_unblock(dhd); + return BCME_OK; + } + dhd->wlfc_enabled = FALSE; + dhd_os_wlfc_unblock(dhd); + + /* query ampdu hostreorder */ + ret = dhd_iovar(dhd, 0, "ampdu_hostreorder", NULL, 0, + (char *)iovbuf, sizeof(iovbuf), FALSE); + if (ret == BCME_OK) + hostreorder = *((uint32 *)iovbuf); + else { + hostreorder = 0; + DHD_ERROR(("%s():%d, ampdu_hostreorder get failed Err = %d\n", + __FUNCTION__, __LINE__, ret)); + } + + if (hostreorder) { + tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; + DHD_ERROR(("%s():%d, maintain HOST RXRERODER flag in tvl\n", + __FUNCTION__, __LINE__)); + } + + /* Disable proptxtstatus signaling for deinit */ + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + + if (ret == BCME_OK) { + /* + Leaving the message for now, it should be removed after a while; once + the tlv situation is stable. + */ + DHD_ERROR(("%s():%d successfully %s bdcv2 tlv signaling, %d\n", + __FUNCTION__, __LINE__, + dhd->wlfc_enabled?"enabled":"disabled", tlv)); + } else + DHD_ERROR(("%s():%d failed to enable/disable bdcv2 tlv signaling Err = %d\n", + __FUNCTION__, __LINE__, ret)); + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + +#ifdef PROP_TXSTATUS_DEBUG + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) + { + int i; + wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; + for (i = 0; i < h->max_items; i++) { + if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { + WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", + __FUNCTION__, i, h->items[i].pkt, + DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); + } + } + } +#endif + + _dhd_wlfc_cleanup(dhd, NULL, NULL); + + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + /* delete hanger */ + _dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); + } + + + /* free top structure */ + DHD_OS_PREFREE(dhd, dhd->wlfc_state, + sizeof(athost_wl_status_info_t)); + dhd->wlfc_state = NULL; + dhd->proptxstatus_mode = hostreorder ? + WLFC_ONLY_AMPDU_HOSTREORDER : WLFC_FCMODE_NONE; + + dhd_os_wlfc_unblock(dhd); + + if (dhd->plat_deinit) + dhd->plat_deinit((void *)dhd); + return BCME_OK; +} + +int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea) +{ + int rc; + + if (dhdp == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhdp); + return WLFC_UNSUPPORTED; + } + + rc = _dhd_wlfc_interface_entry_update(dhdp->wlfc_state, action, ifid, iftype, ea); + + dhd_os_wlfc_unblock(dhdp); + return rc; +} + +int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data) +{ + int rc; + + if (dhdp == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhdp); + return WLFC_UNSUPPORTED; + } + + rc = _dhd_wlfc_FIFOcreditmap_update(dhdp->wlfc_state, event_data); + + dhd_os_wlfc_unblock(dhdp); + + return rc; +} + +int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp) +{ + int rc; + + if (dhdp == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhdp); + return WLFC_UNSUPPORTED; + } + + rc = _dhd_wlfc_BCMCCredit_support_update(dhdp->wlfc_state); + + dhd_os_wlfc_unblock(dhdp); + return rc; +} + +int +dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + int i; + uint8* ea; + athost_wl_status_info_t* wlfc; + wlfc_hanger_t* h; + wlfc_mac_descriptor_t* mac_table; + wlfc_mac_descriptor_t* interfaces; + char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; + + if (!dhdp || !strbuf) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhdp); + return WLFC_UNSUPPORTED; + } + + wlfc = (athost_wl_status_info_t*)dhdp->wlfc_state; + + h = (wlfc_hanger_t*)wlfc->hanger; + if (h == NULL) { + bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); + } + + mac_table = wlfc->destination_entries.nodes; + interfaces = wlfc->destination_entries.interfaces; + bcm_bprintf(strbuf, "---- wlfc stats ----\n"); + + if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { + h = (wlfc_hanger_t*)wlfc->hanger; + if (h == NULL) { + bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); + } else { + bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," + "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", + h->pushed, + h->popped, + h->failed_to_push, + h->failed_to_pop, + h->failed_slotfind, + (h->pushed - h->popped)); + } + } + + bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " + "(dq_full,rollback_fail) = (%d,%d,%d,%d), (%d,%d)\n", + wlfc->stats.tlv_parse_failed, + wlfc->stats.credit_request_failed, + wlfc->stats.mac_update_failed, + wlfc->stats.psmode_update_failed, + wlfc->stats.delayq_full_error, + wlfc->stats.rollback_failed); + + bcm_bprintf(strbuf, "PKTS (init_credit,credit,sent,drop_d,drop_s,outoforder) " + "(AC0[%d,%d,%d,%d,%d,%d],AC1[%d,%d,%d,%d,%d,%d],AC2[%d,%d,%d,%d,%d,%d]," + "AC3[%d,%d,%d,%d,%d,%d],BC_MC[%d,%d,%d,%d,%d,%d])\n", + wlfc->Init_FIFO_credit[0], wlfc->FIFO_credit[0], wlfc->stats.send_pkts[0], + wlfc->stats.drop_pkts[0], wlfc->stats.drop_pkts[1], wlfc->stats.ooo_pkts[0], + wlfc->Init_FIFO_credit[1], wlfc->FIFO_credit[1], wlfc->stats.send_pkts[1], + wlfc->stats.drop_pkts[2], wlfc->stats.drop_pkts[3], wlfc->stats.ooo_pkts[1], + wlfc->Init_FIFO_credit[2], wlfc->FIFO_credit[2], wlfc->stats.send_pkts[2], + wlfc->stats.drop_pkts[4], wlfc->stats.drop_pkts[5], wlfc->stats.ooo_pkts[2], + wlfc->Init_FIFO_credit[3], wlfc->FIFO_credit[3], wlfc->stats.send_pkts[3], + wlfc->stats.drop_pkts[6], wlfc->stats.drop_pkts[7], wlfc->stats.ooo_pkts[3], + wlfc->Init_FIFO_credit[4], wlfc->FIFO_credit[4], wlfc->stats.send_pkts[4], + wlfc->stats.drop_pkts[8], wlfc->stats.drop_pkts[9], wlfc->stats.ooo_pkts[4]); + + bcm_bprintf(strbuf, "\n"); + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (interfaces[i].occupied) { + char* iftype_desc; + + if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) + iftype_desc = "hostif_flow_state[i] == OFF) + ? " OFF":" ON")); + + bcm_bprintf(strbuf, "INTERFACE[%d].PSQ(len,state,credit),(trans,supp_trans)" + "= (%d,%s,%d),(%d,%d)\n", + i, + interfaces[i].psq.len, + ((interfaces[i].state == + WLFC_STATE_OPEN) ? "OPEN":"CLOSE"), + interfaces[i].requested_credit, + interfaces[i].transit_count, interfaces[i].suppr_transit_count); + + bcm_bprintf(strbuf, "INTERFACE[%d].PSQ" + "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," + "(delay3,sup3,afq3),(delay4,sup4,afq4) = (%d,%d,%d)," + "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", + i, + interfaces[i].psq.q[0].len, + interfaces[i].psq.q[1].len, + interfaces[i].afq.q[0].len, + interfaces[i].psq.q[2].len, + interfaces[i].psq.q[3].len, + interfaces[i].afq.q[1].len, + interfaces[i].psq.q[4].len, + interfaces[i].psq.q[5].len, + interfaces[i].afq.q[2].len, + interfaces[i].psq.q[6].len, + interfaces[i].psq.q[7].len, + interfaces[i].afq.q[3].len, + interfaces[i].psq.q[8].len, + interfaces[i].psq.q[9].len, + interfaces[i].afq.q[4].len); + } + } + + bcm_bprintf(strbuf, "\n"); + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (mac_table[i].occupied) { + ea = mac_table[i].ea; + bcm_bprintf(strbuf, "MAC_table[%d].ea = " + "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], + mac_table[i].interface_id); + + bcm_bprintf(strbuf, "MAC_table[%d].PSQ(len,state,credit),(trans,supp_trans)" + "= (%d,%s,%d),(%d,%d)\n", + i, + mac_table[i].psq.len, + ((mac_table[i].state == + WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), + mac_table[i].requested_credit, + mac_table[i].transit_count, mac_table[i].suppr_transit_count); +#ifdef PROP_TXSTATUS_DEBUG + bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", + i, mac_table[i].opened_ct, mac_table[i].closed_ct); +#endif + bcm_bprintf(strbuf, "MAC_table[%d].PSQ" + "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," + "(delay3,sup3,afq3),(delay4,sup4,afq4) =(%d,%d,%d)," + "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", + i, + mac_table[i].psq.q[0].len, + mac_table[i].psq.q[1].len, + mac_table[i].afq.q[0].len, + mac_table[i].psq.q[2].len, + mac_table[i].psq.q[3].len, + mac_table[i].afq.q[1].len, + mac_table[i].psq.q[4].len, + mac_table[i].psq.q[5].len, + mac_table[i].afq.q[2].len, + mac_table[i].psq.q[6].len, + mac_table[i].psq.q[7].len, + mac_table[i].afq.q[3].len, + mac_table[i].psq.q[8].len, + mac_table[i].psq.q[9].len, + mac_table[i].afq.q[4].len); + + } + } + +#ifdef PROP_TXSTATUS_DEBUG + { + int avg; + int moving_avg = 0; + int moving_samples; + + if (wlfc->stats.latency_sample_count) { + moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); + + for (i = 0; i < moving_samples; i++) + moving_avg += wlfc->stats.deltas[i]; + moving_avg /= moving_samples; + + avg = (100 * wlfc->stats.total_status_latency) / + wlfc->stats.latency_sample_count; + bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " + "(%d.%d, %03d, %03d)\n", + moving_samples, avg/100, (avg - (avg/100)*100), + wlfc->stats.latency_most_recent, + moving_avg); + } + } + + bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " + "back = (%d,%d,%d,%d,%d,%d)\n", + wlfc->stats.fifo_credits_sent[0], + wlfc->stats.fifo_credits_sent[1], + wlfc->stats.fifo_credits_sent[2], + wlfc->stats.fifo_credits_sent[3], + wlfc->stats.fifo_credits_sent[4], + wlfc->stats.fifo_credits_sent[5], + + wlfc->stats.fifo_credits_back[0], + wlfc->stats.fifo_credits_back[1], + wlfc->stats.fifo_credits_back[2], + wlfc->stats.fifo_credits_back[3], + wlfc->stats.fifo_credits_back[4], + wlfc->stats.fifo_credits_back[5]); + { + uint32 fifo_cr_sent = 0; + uint32 fifo_cr_acked = 0; + uint32 request_cr_sent = 0; + uint32 request_cr_ack = 0; + uint32 bc_mc_cr_ack = 0; + + for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { + fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; + } + + for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { + fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; + } + + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (wlfc->destination_entries.nodes[i].occupied) { + request_cr_sent += + wlfc->destination_entries.nodes[i].dstncredit_sent_packets; + } + } + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (wlfc->destination_entries.interfaces[i].occupied) { + request_cr_sent += + wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; + } + } + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (wlfc->destination_entries.nodes[i].occupied) { + request_cr_ack += + wlfc->destination_entries.nodes[i].dstncredit_acks; + } + } + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (wlfc->destination_entries.interfaces[i].occupied) { + request_cr_ack += + wlfc->destination_entries.interfaces[i].dstncredit_acks; + } + } + bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," + "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", + fifo_cr_sent, fifo_cr_acked, + request_cr_sent, request_cr_ack, + wlfc->destination_entries.other.dstncredit_acks, + bc_mc_cr_ack, + wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); + } +#endif /* PROP_TXSTATUS_DEBUG */ + bcm_bprintf(strbuf, "\n"); + bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull,out),(dropped,hdr_only,wlc_tossed)" + "(freed,free_err,rollback)) = " + "((%d,%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", + wlfc->stats.pktin, + wlfc->stats.pkt2bus, + wlfc->stats.txstatus_in, + wlfc->stats.dhd_hdrpulls, + wlfc->stats.pktout, + + wlfc->stats.pktdropped, + wlfc->stats.wlfc_header_only_pkt, + wlfc->stats.wlc_tossed_pkts, + + wlfc->stats.pkt_freed, + wlfc->stats.pkt_free_err, wlfc->stats.rollback); + + bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " + "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", + wlfc->stats.d11_suppress, + wlfc->stats.wl_suppress, + wlfc->stats.bad_suppress, + + wlfc->stats.psq_d11sup_enq, + wlfc->stats.psq_wlsup_enq, + wlfc->stats.psq_hostq_enq, + wlfc->stats.mac_handle_notfound, + + wlfc->stats.psq_d11sup_retx, + wlfc->stats.psq_wlsup_retx, + wlfc->stats.psq_hostq_retx); + + bcm_bprintf(strbuf, "wlfc- cleanup(txq,psq,fw) = (%d,%d,%d)\n", + wlfc->stats.cleanup_txq_cnt, + wlfc->stats.cleanup_psq_cnt, + wlfc->stats.cleanup_fw_cnt); + + bcm_bprintf(strbuf, "wlfc- generic error: %d\n", wlfc->stats.generic_error); + + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + bcm_bprintf(strbuf, "wlfc- if[%d], pkt_cnt_in_q/AC[0-4] = (%d,%d,%d,%d,%d)\n", i, + wlfc->pkt_cnt_in_q[i][0], + wlfc->pkt_cnt_in_q[i][1], + wlfc->pkt_cnt_in_q[i][2], + wlfc->pkt_cnt_in_q[i][3], + wlfc->pkt_cnt_in_q[i][4]); + } + bcm_bprintf(strbuf, "\n"); + + dhd_os_wlfc_unblock(dhdp); + return BCME_OK; +} + +int dhd_wlfc_clear_counts(dhd_pub_t *dhd) +{ + athost_wl_status_info_t* wlfc; + wlfc_hanger_t* hanger; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + + memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); + + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + hanger = (wlfc_hanger_t*)wlfc->hanger; + + hanger->pushed = 0; + hanger->popped = 0; + hanger->failed_slotfind = 0; + hanger->failed_to_pop = 0; + hanger->failed_to_push = 0; + } + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->wlfc_enabled; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->wlfc_state ? dhd->proptxstatus_mode : 0; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val) +{ + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (dhd->wlfc_state) { + dhd->proptxstatus_mode = val & 0xff; + } + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf) +{ + athost_wl_status_info_t* wlfc; + bool rc = FALSE; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return FALSE; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return FALSE; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + + if (PKTLEN(wlfc->osh, pktbuf) == 0) { + wlfc->stats.wlfc_header_only_pkt++; + rc = TRUE; + } + + dhd_os_wlfc_unblock(dhd); + + return rc; +} + +int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock) +{ + if (dhdp == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + if (bAcquireLock) { + dhd_os_wlfc_block(dhdp); + } + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE) || + dhdp->proptxstatus_module_ignore) { + if (bAcquireLock) { + dhd_os_wlfc_unblock(dhdp); + } + return WLFC_UNSUPPORTED; + } + + if (state != dhdp->proptxstatus_txoff) { + dhdp->proptxstatus_txoff = state; + } + + if (bAcquireLock) { + dhd_os_wlfc_unblock(dhdp); + } + + return BCME_OK; +} + +int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio) +{ + athost_wl_status_info_t* wlfc; + int rx_path_ac = -1; + + if ((dhd == NULL) || (prio >= NUMPRIO)) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_rxpkt_chk) { + dhd_os_wlfc_unblock(dhd); + return BCME_OK; + } + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + + rx_path_ac = prio2fifo[prio]; + wlfc->rx_timestamp[rx_path_ac] = OSL_SYSUPTIME(); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->proptxstatus_module_ignore; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val) +{ + uint32 tlv = 0; + bool bChanged = FALSE; + + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if ((bool)val != dhd->proptxstatus_module_ignore) { + dhd->proptxstatus_module_ignore = (val != 0); + /* force txstatus_ignore sync with proptxstatus_module_ignore */ + dhd->proptxstatus_txstatus_ignore = dhd->proptxstatus_module_ignore; + if (FALSE == dhd->proptxstatus_module_ignore) { + tlv = WLFC_FLAGS_RSSI_SIGNALS | + WLFC_FLAGS_XONXOFF_SIGNALS | + WLFC_FLAGS_CREDIT_STATUS_SIGNALS | + WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE; + } + /* always enable host reorder */ + tlv |= WLFC_FLAGS_HOST_RXRERODER_ACTIVE; + bChanged = TRUE; + } + + dhd_os_wlfc_unblock(dhd); + + if (bChanged) { + /* select enable proptxtstatus signaling */ + if (dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE) < 0) { + DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", + __FUNCTION__, tlv)); + } + else { + DHD_ERROR(("%s: successfully set bdcv2 tlv signaling to 0x%x\n", + __FUNCTION__, tlv)); + } + } + return BCME_OK; +} + +int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->proptxstatus_credit_ignore; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val) +{ + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + dhd->proptxstatus_credit_ignore = (val != 0); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->proptxstatus_txstatus_ignore; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val) +{ + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + dhd->proptxstatus_txstatus_ignore = (val != 0); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->wlfc_rxpkt_chk; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val) +{ + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + dhd->wlfc_rxpkt_chk = (val != 0); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} +#endif /* PROP_TXSTATUS */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.h new file mode 100644 index 000000000000..a7658ede2b52 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.h @@ -0,0 +1,517 @@ +/* +* Copyright (C) 1999-2017, Broadcom Corporation +* +* Unless you and Broadcom execute a separate written software license +* agreement governing use of this software, this software is licensed to you +* under the terms of the GNU General Public License version 2 (the "GPL"), +* available at http://www.broadcom.com/licenses/GPLv2.php, with the +* following added to such license: +* +* As a special exception, the copyright holders of this software give you +* permission to link this software with independent modules, and to copy and +* distribute the resulting executable under terms of your choice, provided that +* you also meet, for each linked independent module, the terms and conditions of +* the license of that module. An independent module is a module which is not +* derived from this software. The special exception does not apply to any +* modifications of the software. +* +* Notwithstanding the above, under no circumstances may you combine this +* software in any way with any other Broadcom software provided under a license +* other than the GPL, without Broadcom's express prior written consent. +* $Id: dhd_wlfc.h 501046 2014-09-06 01:25:16Z $ +* +*/ +#ifndef __wlfc_host_driver_definitions_h__ +#define __wlfc_host_driver_definitions_h__ + + +/* #define OOO_DEBUG */ + +#define WLFC_UNSUPPORTED -9999 + +#define WLFC_NO_TRAFFIC -1 +#define WLFC_MULTI_TRAFFIC 0 + +#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ + +/* 16 bits will provide an absolute max of 65536 slots */ +#define WLFC_HANGER_MAXITEMS 3072 + +#define WLFC_HANGER_ITEM_STATE_FREE 1 +#define WLFC_HANGER_ITEM_STATE_INUSE 2 +#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 + +#define WLFC_HANGER_PKT_STATE_TXSTATUS 1 +#define WLFC_HANGER_PKT_STATE_TXCOMPLETE 2 +#define WLFC_HANGER_PKT_STATE_CLEANUP 4 + +typedef enum { + Q_TYPE_PSQ, + Q_TYPE_AFQ +} q_type_t; + +typedef enum ewlfc_packet_state { + eWLFC_PKTTYPE_NEW, + eWLFC_PKTTYPE_DELAYED, + eWLFC_PKTTYPE_SUPPRESSED, + eWLFC_PKTTYPE_MAX +} ewlfc_packet_state_t; + +typedef enum ewlfc_mac_entry_action { + eWLFC_MAC_ENTRY_ACTION_ADD, + eWLFC_MAC_ENTRY_ACTION_DEL, + eWLFC_MAC_ENTRY_ACTION_UPDATE, + eWLFC_MAC_ENTRY_ACTION_MAX +} ewlfc_mac_entry_action_t; + +typedef struct wlfc_hanger_item { + uint8 state; + uint8 gen; + uint8 pkt_state; + uint8 pkt_txstatus; + uint32 identifier; + void* pkt; +#ifdef PROP_TXSTATUS_DEBUG + uint32 push_time; +#endif + struct wlfc_hanger_item *next; +} wlfc_hanger_item_t; + +typedef struct wlfc_hanger { + int max_items; + uint32 pushed; + uint32 popped; + uint32 failed_to_push; + uint32 failed_to_pop; + uint32 failed_slotfind; + uint32 slot_pos; + wlfc_hanger_item_t items[1]; +} wlfc_hanger_t; + +#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ + sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) + +#define WLFC_STATE_OPEN 1 +#define WLFC_STATE_CLOSE 2 + +#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ +#define WLFC_AFQ_PREC_COUNT (AC_COUNT + 1) + +#define WLFC_PSQ_LEN 2048 + +#define WLFC_FLOWCONTROL_HIWATER (2048 - 256) +#define WLFC_FLOWCONTROL_LOWATER 256 + +#define WLFC_LOG_BUF_SIZE (1024*1024) + +typedef struct wlfc_mac_descriptor { + uint8 occupied; + uint8 interface_id; + uint8 iftype; + uint8 state; + uint8 ac_bitmap; /* for APSD */ + uint8 requested_credit; + uint8 requested_packet; + uint8 ea[ETHER_ADDR_LEN]; + /* + maintain (MAC,AC) based seq count for + packets going to the device. As well as bc/mc. + */ + uint8 seq[AC_COUNT + 1]; + uint8 generation; + struct pktq psq; + /* packets at firmware */ + struct pktq afq; + /* The AC pending bitmap that was reported to the fw at last change */ + uint8 traffic_lastreported_bmp; + /* The new AC pending bitmap */ + uint8 traffic_pending_bmp; + /* 1= send on next opportunity */ + uint8 send_tim_signal; + uint8 mac_handle; + /* Number of packets at dongle for this entry. */ + int transit_count; + /* Numbe of suppression to wait before evict from delayQ */ + int suppr_transit_count; + /* flag. TRUE when in suppress state */ + uint8 suppressed; + + +#ifdef PROP_TXSTATUS_DEBUG + uint32 dstncredit_sent_packets; + uint32 dstncredit_acks; + uint32 opened_ct; + uint32 closed_ct; +#endif + struct wlfc_mac_descriptor* prev; + struct wlfc_mac_descriptor* next; +} wlfc_mac_descriptor_t; + +typedef struct dhd_wlfc_commit_info { + uint8 needs_hdr; + uint8 ac_fifo_credit_spent; + ewlfc_packet_state_t pkt_type; + wlfc_mac_descriptor_t* mac_entry; + void* p; +} dhd_wlfc_commit_info_t; + +#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ + entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) + +#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ +#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] + +typedef struct athost_wl_stat_counters { + uint32 pktin; + uint32 pktout; + uint32 pkt2bus; + uint32 pktdropped; + uint32 tlv_parse_failed; + uint32 rollback; + uint32 rollback_failed; + uint32 delayq_full_error; + uint32 credit_request_failed; + uint32 packet_request_failed; + uint32 mac_update_failed; + uint32 psmode_update_failed; + uint32 interface_update_failed; + uint32 wlfc_header_only_pkt; + uint32 txstatus_in; + uint32 d11_suppress; + uint32 wl_suppress; + uint32 bad_suppress; + uint32 pkt_freed; + uint32 pkt_free_err; + uint32 psq_wlsup_retx; + uint32 psq_wlsup_enq; + uint32 psq_d11sup_retx; + uint32 psq_d11sup_enq; + uint32 psq_hostq_retx; + uint32 psq_hostq_enq; + uint32 mac_handle_notfound; + uint32 wlc_tossed_pkts; + uint32 dhd_hdrpulls; + uint32 generic_error; + /* an extra one for bc/mc traffic */ + uint32 send_pkts[AC_COUNT + 1]; + uint32 drop_pkts[WLFC_PSQ_PREC_COUNT]; + uint32 ooo_pkts[AC_COUNT + 1]; +#ifdef PROP_TXSTATUS_DEBUG + /* all pkt2bus -> txstatus latency accumulated */ + uint32 latency_sample_count; + uint32 total_status_latency; + uint32 latency_most_recent; + int idx_delta; + uint32 deltas[10]; + uint32 fifo_credits_sent[6]; + uint32 fifo_credits_back[6]; + uint32 dropped_qfull[6]; + uint32 signal_only_pkts_sent; + uint32 signal_only_pkts_freed; +#endif + uint32 cleanup_txq_cnt; + uint32 cleanup_psq_cnt; + uint32 cleanup_fw_cnt; +} athost_wl_stat_counters_t; + +#ifdef PROP_TXSTATUS_DEBUG +#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ + (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) +#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ + (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) +#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ + (ctx)->stats.dropped_qfull[(ac)]++;} while (0) +#else +#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) +#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) +#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) +#endif + +#define WLFC_FCMODE_NONE 0 +#define WLFC_FCMODE_IMPLIED_CREDIT 1 +#define WLFC_FCMODE_EXPLICIT_CREDIT 2 +#define WLFC_ONLY_AMPDU_HOSTREORDER 3 + +/* Reserved credits ratio when borrowed by hihger priority */ +#define WLFC_BORROW_LIMIT_RATIO 4 + +/* How long to defer borrowing in milliseconds */ +#define WLFC_BORROW_DEFER_PERIOD_MS 100 + +/* How long to defer flow control in milliseconds */ +#define WLFC_FC_DEFER_PERIOD_MS 200 + +/* How long to detect occurance per AC in miliseconds */ +#define WLFC_RX_DETECTION_THRESHOLD_MS 100 + +/* Mask to represent available ACs (note: BC/MC is ignored */ +#define WLFC_AC_MASK 0xF + +typedef struct athost_wl_status_info { + uint8 last_seqid_to_wlc; + + /* OSL handle */ + osl_t* osh; + /* dhd pub */ + void* dhdp; + + /* stats */ + athost_wl_stat_counters_t stats; + + int Init_FIFO_credit[AC_COUNT + 2]; + + /* the additional ones are for bc/mc and ATIM FIFO */ + int FIFO_credit[AC_COUNT + 2]; + + /* Credit borrow counts for each FIFO from each of the other FIFOs */ + int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; + + /* packet hanger and MAC->handle lookup table */ + void* hanger; + struct { + /* table for individual nodes */ + wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; + /* table for interfaces */ + wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; + /* OS may send packets to unknown (unassociated) destinations */ + /* A place holder for bc/mc and packets to unknown destinations */ + wlfc_mac_descriptor_t other; + } destination_entries; + + wlfc_mac_descriptor_t *active_entry_head; + int active_entry_count; + + wlfc_mac_descriptor_t* requested_entry[WLFC_MAC_DESC_TABLE_SIZE]; + int requested_entry_count; + + /* pkt counts for each interface and ac */ + int pkt_cnt_in_q[WLFC_MAX_IFNUM][AC_COUNT+1]; + int pkt_cnt_per_ac[AC_COUNT+1]; + int pkt_cnt_in_drv[WLFC_MAX_IFNUM][AC_COUNT+1]; + uint8 allow_fc; + uint32 fc_defer_timestamp; + uint32 rx_timestamp[AC_COUNT+1]; + /* ON/OFF state for flow control to the host network interface */ + uint8 hostif_flow_state[WLFC_MAX_IFNUM]; + uint8 host_ifidx; + /* to flow control an OS interface */ + uint8 toggle_host_if; + + /* To borrow credits */ + uint8 allow_credit_borrow; + + /* ac number for the first single ac traffic */ + uint8 single_ac; + + /* Timestamp for the first single ac traffic */ + uint32 single_ac_timestamp; + + bool bcmc_credit_supported; + +} athost_wl_status_info_t; + +/* Please be mindful that total pkttag space is 32 octets only */ +typedef struct dhd_pkttag { + /* + b[15] - 1 = wlfc packet + b[14:13] - encryption exemption + b[12 ] - 1 = event channel + b[11 ] - 1 = this packet was sent in response to one time packet request, + do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. + b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] + b[9 ] - 1 = packet is host->firmware (transmit direction) + - 0 = packet received from firmware (firmware->host) + b[8 ] - 1 = packet was sent due to credit_request (pspoll), + packet does not count against FIFO credit. + - 0 = normal transaction, packet counts against FIFO credit + b[7 ] - 1 = AP, 0 = STA + b[6:4] - AC FIFO number + b[3:0] - interface index + */ + uint16 if_flags; + /* destination MAC address for this packet so that not every + module needs to open the packet to find this + */ + uint8 dstn_ether[ETHER_ADDR_LEN]; + /* + This 32-bit goes from host to device for every packet. + */ + uint32 htod_tag; + + /* + This 16-bit is original seq number for every suppress packet. + */ + uint16 htod_seq; + + /* + This address is mac entry for every packet. + */ + void* entry; + /* bus specific stuff */ + union { + struct { + void* stuff; + uint32 thing1; + uint32 thing2; + } sd; + struct { + void* bus; + void* urb; + } usb; + } bus_specific; +} dhd_pkttag_t; + +#define DHD_PKTTAG_WLFCPKT_MASK 0x1 +#define DHD_PKTTAG_WLFCPKT_SHIFT 15 +#define DHD_PKTTAG_WLFCPKT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_WLFCPKT_MASK << DHD_PKTTAG_WLFCPKT_SHIFT)) | \ + (((value) & DHD_PKTTAG_WLFCPKT_MASK) << DHD_PKTTAG_WLFCPKT_SHIFT) +#define DHD_PKTTAG_WLFCPKT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_WLFCPKT_SHIFT) & DHD_PKTTAG_WLFCPKT_MASK) + +#define DHD_PKTTAG_EXEMPT_MASK 0x3 +#define DHD_PKTTAG_EXEMPT_SHIFT 13 +#define DHD_PKTTAG_EXEMPT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_EXEMPT_MASK << DHD_PKTTAG_EXEMPT_SHIFT)) | \ + (((value) & DHD_PKTTAG_EXEMPT_MASK) << DHD_PKTTAG_EXEMPT_SHIFT) +#define DHD_PKTTAG_EXEMPT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_EXEMPT_SHIFT) & DHD_PKTTAG_EXEMPT_MASK) + +#define DHD_PKTTAG_EVENT_MASK 0x1 +#define DHD_PKTTAG_EVENT_SHIFT 12 +#define DHD_PKTTAG_SETEVENT(tag, event) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_EVENT_MASK << DHD_PKTTAG_EVENT_SHIFT)) | \ + (((event) & DHD_PKTTAG_EVENT_MASK) << DHD_PKTTAG_EVENT_SHIFT) +#define DHD_PKTTAG_EVENT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_EVENT_SHIFT) & DHD_PKTTAG_EVENT_MASK) + +#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 +#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 +#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ + (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) +#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) + +#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 +#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 +#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ + (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) +#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) + +#define DHD_PKTTAG_PKTDIR_MASK 0x1 +#define DHD_PKTTAG_PKTDIR_SHIFT 9 +#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ + (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) +#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) + +#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 +#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 +#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ + (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) +#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) + +#define DHD_PKTTAG_IFTYPE_MASK 0x1 +#define DHD_PKTTAG_IFTYPE_SHIFT 7 +#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ + (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) +#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) + +#define DHD_PKTTAG_FIFO_MASK 0x7 +#define DHD_PKTTAG_FIFO_SHIFT 4 +#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ + (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) +#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) + +#define DHD_PKTTAG_IF_MASK 0xf +#define DHD_PKTTAG_IF_SHIFT 0 +#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_IF_MASK << DHD_PKTTAG_IF_SHIFT)) | \ + (((if) & DHD_PKTTAG_IF_MASK) << DHD_PKTTAG_IF_SHIFT) +#define DHD_PKTTAG_IF(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_IF_SHIFT) & DHD_PKTTAG_IF_MASK) + +#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ + (dstn_MAC_ea), ETHER_ADDR_LEN) +#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether + +#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) +#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) + +#define DHD_PKTTAG_SET_H2DSEQ(tag, seq) ((dhd_pkttag_t*)(tag))->htod_seq = (seq) +#define DHD_PKTTAG_H2DSEQ(tag) (((dhd_pkttag_t*)(tag))->htod_seq) + +#define DHD_PKTTAG_SET_ENTRY(tag, entry) ((dhd_pkttag_t*)(tag))->entry = (entry) +#define DHD_PKTTAG_ENTRY(tag) (((dhd_pkttag_t*)(tag))->entry) + +#define PSQ_SUP_IDX(x) (x * 2 + 1) +#define PSQ_DLY_IDX(x) (x * 2) + +typedef int (*f_commitpkt_t)(void* ctx, void* p); +typedef bool (*f_processpkt_t)(void* p, void* arg); + +#ifdef PROP_TXSTATUS_DEBUG +#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) +#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) +#else +#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) +#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) +#endif + +/* public functions */ +int dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, + uchar *reorder_info_buf, uint *reorder_info_len); +int dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, + void* commit_ctx, void *pktbuf, bool need_toggle_host_if); +int dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); +int dhd_wlfc_init(dhd_pub_t *dhd); +#ifdef SUPPORT_P2P_GO_PS +int dhd_wlfc_suspend(dhd_pub_t *dhd); +int dhd_wlfc_resume(dhd_pub_t *dhd); +#endif /* SUPPORT_P2P_GO_PS */ +int dhd_wlfc_hostreorder_init(dhd_pub_t *dhd); +int dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg); +int dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void* arg); +int dhd_wlfc_deinit(dhd_pub_t *dhd); +int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea); +int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data); +int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp); +int dhd_wlfc_enable(dhd_pub_t *dhdp); +int dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +int dhd_wlfc_clear_counts(dhd_pub_t *dhd); +int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val); +int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val); +bool dhd_wlfc_is_supported(dhd_pub_t *dhd); +bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf); +int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock); +int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio); + +int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val); +int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val); +int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val); + +int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val); +#endif /* __wlfc_host_driver_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dngl_stats.h b/drivers/net/wireless/bcmdhd_bcm4356/dngl_stats.h new file mode 100644 index 000000000000..496d86fe4de0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dngl_stats.h @@ -0,0 +1,271 @@ +/* + * Common stats definitions for clients of dongle + * ports + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dngl_stats.h 596029 2015-10-29 11:23:38Z $ + */ + +#ifndef _dngl_stats_h_ +#define _dngl_stats_h_ + +typedef struct { + 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 */ +} dngl_stats_t; + +#ifdef LINKSTAT_SUPPORT +typedef int wifi_radio; +typedef int wifi_channel; +typedef int wifi_rssi; + +typedef enum wifi_channel_width { + WIFI_CHAN_WIDTH_20 = 0, + WIFI_CHAN_WIDTH_40 = 1, + WIFI_CHAN_WIDTH_80 = 2, + WIFI_CHAN_WIDTH_160 = 3, + WIFI_CHAN_WIDTH_80P80 = 4, + WIFI_CHAN_WIDTH_5 = 5, + WIFI_CHAN_WIDTH_10 = 6, + WIFI_CHAN_WIDTH_INVALID = -1 +} wifi_channel_width_t; + +typedef enum { + WIFI_DISCONNECTED = 0, + WIFI_AUTHENTICATING = 1, + WIFI_ASSOCIATING = 2, + WIFI_ASSOCIATED = 3, + WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ + WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ +} wifi_connection_state; + +typedef enum { + WIFI_ROAMING_IDLE = 0, + WIFI_ROAMING_ACTIVE = 1 +} wifi_roam_state; + +typedef enum { + WIFI_INTERFACE_STA = 0, + WIFI_INTERFACE_SOFTAP = 1, + WIFI_INTERFACE_IBSS = 2, + WIFI_INTERFACE_P2P_CLIENT = 3, + WIFI_INTERFACE_P2P_GO = 4, + WIFI_INTERFACE_NAN = 5, + WIFI_INTERFACE_MESH = 6 +} wifi_interface_mode; + +/* set for QOS association */ +#define WIFI_CAPABILITY_QOS 0x00000001 +/* set for protected association (802.11 beacon frame control protected bit set) */ +#define WIFI_CAPABILITY_PROTECTED 0x00000002 +/* set if 802.11 Extended Capabilities element interworking bit is set */ +#define WIFI_CAPABILITY_INTERWORKING 0x00000004 +/* set for HS20 association */ +#define WIFI_CAPABILITY_HS20 0x00000008 +/* set is 802.11 Extended Capabilities element UTF-8 SSID bit is set */ +#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 +/* set is 802.11 Country Element is present */ +#define WIFI_CAPABILITY_COUNTRY 0x00000020 + +typedef struct { + wifi_interface_mode mode; /* interface mode */ + u8 mac_addr[6]; /* interface mac address (self) */ + wifi_connection_state state; /* connection state (valid for STA, CLI only) */ + wifi_roam_state roaming; /* roaming state */ + u32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ + u8 ssid[33]; /* null terminated SSID */ + u8 bssid[6]; /* bssid */ + u8 ap_country_str[3]; /* country string advertised by AP */ + u8 country_str[3]; /* country string for this association */ +} wifi_interface_info; + +typedef wifi_interface_info *wifi_interface_handle; + +/* channel information */ +typedef struct { + wifi_channel_width_t width; /* channel width (20, 40, 80, 80+80, 160) */ + wifi_channel center_freq; /* primary 20 MHz channel */ + wifi_channel center_freq0; /* center frequency (MHz) first segment */ + wifi_channel center_freq1; /* center frequency (MHz) second segment */ +} wifi_channel_info; + +/* wifi rate */ +typedef struct { + u32 preamble :3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ + u32 nss :2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ + u32 bw :3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ + u32 rateMcsIdx :8; /* OFDM/CCK rate code would be as per + * ieee std in the units of 0.5mbps + */ + /* HT/VHT it would be mcs index */ + u32 reserved :16; /* reserved */ + u32 bitrate; /* units of 100 Kbps */ +} wifi_rate; + +/* channel statistics */ +typedef struct { + wifi_channel_info channel; /* channel */ + u32 on_time; /* msecs the radio is awake + * (32 bits number accruing over time) + */ + u32 cca_busy_time; /* msecs the CCA register is + * busy (32 bits number accruing over time) + */ +} wifi_channel_stat; + +/* radio statistics */ +typedef struct { + wifi_radio radio; /* wifi radio (if multiple radio supported) */ + /* all msecs in 32 bits number accruing over time */ + u32 on_time; /* msecs the radio is awake */ + u32 tx_time; /* msecs the radio is transmitting */ + u32 rx_time; /* msecs the radio is in active receive */ + u32 on_time_scan; /* msecs the radio is awake due to all scan */ + u32 on_time_nbd; /* msecs the radio is awake due to NAN */ + u32 on_time_gscan; /* msecs the radio is awake due to Gscan */ + u32 on_time_roam_scan; /* msecs the radio is awake due to roam scan */ + u32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan */ + u32 on_time_hs20; /* msecs the radio is awake due to + * HS2.0 scans and GAS exchange + */ + u32 num_channels; /* number of channels */ + wifi_channel_stat channels[]; /* channel statistics */ +} wifi_radio_stat; + +/* per rate statistics */ +typedef struct { + wifi_rate rate; /* rate information */ + u32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ + u32 rx_mpdu; /* number of received data pkts */ + u32 mpdu_lost; /* number of data packet losses (no ACK) */ + u32 retries; /* total number of data pkt retries */ + u32 retries_short; /* number of short data pkt retries */ + u32 retries_long; /* number of long data pkt retries */ +} wifi_rate_stat; + +/* access categories */ +typedef enum { + WIFI_AC_VO = 0, + WIFI_AC_VI = 1, + WIFI_AC_BE = 2, + WIFI_AC_BK = 3, + WIFI_AC_MAX = 4 +} wifi_traffic_ac; + +/* wifi peer type */ +typedef enum +{ + WIFI_PEER_STA, + WIFI_PEER_AP, + WIFI_PEER_P2P_GO, + WIFI_PEER_P2P_CLIENT, + WIFI_PEER_NAN, + WIFI_PEER_TDLS, + WIFI_PEER_INVALID +} wifi_peer_type; + +/* per peer statistics */ +typedef struct { + wifi_peer_type type; /* peer type (AP, TDLS, GO etc.) */ + u8 peer_mac_address[6]; /* mac address */ + u32 capabilities; /* peer WIFI_CAPABILITY_XXX */ + u32 num_rate; /* number of rates */ + wifi_rate_stat rate_stats[]; /* per rate statistics, number of entries = num_rate */ +} wifi_peer_info; + +/* per access category statistics */ +typedef struct { + wifi_traffic_ac ac; /* access category (VI, VO, BE, BK) */ + u32 tx_mpdu; /* number of successfully transmitted + * unicast data pkts (ACK rcvd) + */ + u32 rx_mpdu; /* number of received unicast mpdus */ + u32 tx_mcast; /* number of successfully transmitted + * multicast data packets + */ + /* STA case: implies ACK received from AP + * for the unicast packet in which mcast pkt was sent + */ + u32 rx_mcast; /* number of received multicast data packets */ + u32 rx_ampdu; /* number of received unicast a-mpdus */ + u32 tx_ampdu; /* number of transmitted unicast a-mpdus */ + u32 mpdu_lost; /* number of data pkt losses (no ACK) */ + u32 retries; /* total number of data pkt retries */ + u32 retries_short; /* number of short data pkt retries */ + u32 retries_long; /* number of long data pkt retries */ + u32 contention_time_min; /* data pkt min contention time (usecs) */ + u32 contention_time_max; /* data pkt max contention time (usecs) */ + u32 contention_time_avg; /* data pkt avg contention time (usecs) */ + u32 contention_num_samples; /* num of data pkts used for contention statistics */ +} wifi_wmm_ac_stat; + +/* interface statistics */ +typedef struct { + wifi_interface_handle iface; /* wifi interface */ + wifi_interface_info info; /* current state of the interface */ + u32 beacon_rx; /* access point beacon received count + * from connected AP + */ + u64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT) + * The average_tsf_offset field is used so as to calculate + * the typical beacon contention time on the channel as well + * may be used to debug beacon synchronization and related + * power consumption issue + */ + u32 leaky_ap_detected; /* indicate that this AP typically leaks packets beyond + * the driver guard time. + */ + u32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after + * frame with PM bit set was ACK'ed by AP + */ + u32 leaky_ap_guard_time; /* guard time currently in force (when implementing IEEE + * power management based on frame control PM bit), How long + * driver waits before shutting down the radio and after + * receiving an ACK for a data frame with PM bit set) + */ + u32 mgmt_rx; /* access point mgmt frames received count + * from connected AP (including Beacon) + */ + u32 mgmt_action_rx; /* action frames received count */ + u32 mgmt_action_tx; /* action frames transmit count */ + wifi_rssi rssi_mgmt; /* access Point Beacon and + * Management frames RSSI (averaged) + */ + wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) + * from connected AP + */ + wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) + * from connected AP + */ + wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ + u32 num_peers; /* number of peers */ + wifi_peer_info peer_info[]; /* per peer statistics */ +} wifi_iface_stat; +#endif /* LINKSTAT_SUPPORT */ +#endif /* _dngl_stats_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd_bcm4356/dngl_wlhdr.h new file mode 100644 index 000000000000..6050aec62acf --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/dngl_wlhdr.h @@ -0,0 +1,40 @@ +/* + * Dongle WL Header definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dngl_wlhdr.h 464743 2014-03-25 21:04:32Z $ + */ + +#ifndef _dngl_wlhdr_h_ +#define _dngl_wlhdr_h_ + +typedef struct wl_header { + uint8 type; /* Header type */ + uint8 version; /* Header version */ + int8 rssi; /* RSSI */ + uint8 pad; /* Unused */ +} wl_header_t; + +#define WL_HEADER_LEN sizeof(wl_header_t) +#define WL_HEADER_TYPE 0 +#define WL_HEADER_VER 1 +#endif /* _dngl_wlhdr_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/hnd_pktpool.c b/drivers/net/wireless/bcmdhd_bcm4356/hnd_pktpool.c new file mode 100644 index 000000000000..a1b4b16a4cde --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/hnd_pktpool.c @@ -0,0 +1,751 @@ +/* + * HND generic packet pool operation primitives + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: $ + */ + +#include +#include +#include +#include + +/* Registry size is one larger than max pools, as slot #0 is reserved */ +#define PKTPOOLREG_RSVD_ID (0U) +#define PKTPOOLREG_RSVD_PTR (POOLPTR(0xdeaddead)) +#define PKTPOOLREG_FREE_PTR (POOLPTR(NULL)) + +#define PKTPOOL_REGISTRY_SET(id, pp) (pktpool_registry_set((id), (pp))) +#define PKTPOOL_REGISTRY_CMP(id, pp) (pktpool_registry_cmp((id), (pp))) + +/* Tag a registry entry as free for use */ +#define PKTPOOL_REGISTRY_CLR(id) \ + PKTPOOL_REGISTRY_SET((id), PKTPOOLREG_FREE_PTR) +#define PKTPOOL_REGISTRY_ISCLR(id) \ + (PKTPOOL_REGISTRY_CMP((id), PKTPOOLREG_FREE_PTR)) + +/* Tag registry entry 0 as reserved */ +#define PKTPOOL_REGISTRY_RSV() \ + PKTPOOL_REGISTRY_SET(PKTPOOLREG_RSVD_ID, PKTPOOLREG_RSVD_PTR) +#define PKTPOOL_REGISTRY_ISRSVD() \ + (PKTPOOL_REGISTRY_CMP(PKTPOOLREG_RSVD_ID, PKTPOOLREG_RSVD_PTR)) + +/* Walk all un-reserved entries in registry */ +#define PKTPOOL_REGISTRY_FOREACH(id) \ + for ((id) = 1U; (id) <= pktpools_max; (id)++) + +uint32 pktpools_max = 0U; /* maximum number of pools that may be initialized */ +pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; /* Pktpool registry */ + +/* Register/Deregister a pktpool with registry during pktpool_init/deinit */ +static int pktpool_register(pktpool_t * poolptr); +static int pktpool_deregister(pktpool_t * poolptr); + +/** accessor functions required when ROMming this file, forced into RAM */ +static void +BCMRAMFN(pktpool_registry_set)(int id, pktpool_t *pp) +{ + pktpools_registry[id] = pp; +} + +static bool +BCMRAMFN(pktpool_registry_cmp)(int id, pktpool_t *pp) +{ + return pktpools_registry[id] == pp; +} + +int /* Construct a pool registry to serve a maximum of total_pools */ +pktpool_attach(osl_t *osh, uint32 total_pools) +{ + uint32 poolid; + + if (pktpools_max != 0U) { + return BCME_ERROR; + } + + ASSERT(total_pools <= PKTPOOL_MAXIMUM_ID); + + /* Initialize registry: reserve slot#0 and tag others as free */ + PKTPOOL_REGISTRY_RSV(); /* reserve slot#0 */ + + PKTPOOL_REGISTRY_FOREACH(poolid) { /* tag all unreserved entries as free */ + PKTPOOL_REGISTRY_CLR(poolid); + } + + pktpools_max = total_pools; + + return (int)pktpools_max; +} + +int /* Destruct the pool registry. Ascertain all pools were first de-inited */ +pktpool_dettach(osl_t *osh) +{ + uint32 poolid; + + if (pktpools_max == 0U) { + return BCME_OK; + } + + /* Ascertain that no pools are still registered */ + ASSERT(PKTPOOL_REGISTRY_ISRSVD()); /* assert reserved slot */ + + PKTPOOL_REGISTRY_FOREACH(poolid) { /* ascertain all others are free */ + ASSERT(PKTPOOL_REGISTRY_ISCLR(poolid)); + } + + pktpools_max = 0U; /* restore boot state */ + + return BCME_OK; +} + +static int /* Register a pool in a free slot; return the registry slot index */ +pktpool_register(pktpool_t * poolptr) +{ + uint32 poolid; + + if (pktpools_max == 0U) { + return PKTPOOL_INVALID_ID; /* registry has not yet been constructed */ + } + + ASSERT(pktpools_max != 0U); + + /* find an empty slot in pktpools_registry */ + PKTPOOL_REGISTRY_FOREACH(poolid) { + if (PKTPOOL_REGISTRY_ISCLR(poolid)) { + PKTPOOL_REGISTRY_SET(poolid, POOLPTR(poolptr)); /* register pool */ + return (int)poolid; /* return pool ID */ + } + } /* FOREACH */ + + return PKTPOOL_INVALID_ID; /* error: registry is full */ +} + +static int /* Deregister a pktpool, given the pool pointer; tag slot as free */ +pktpool_deregister(pktpool_t * poolptr) +{ + uint32 poolid; + + ASSERT(POOLPTR(poolptr) != POOLPTR(NULL)); + + poolid = POOLID(poolptr); + ASSERT(poolid <= pktpools_max); + + /* Asertain that a previously registered poolptr is being de-registered */ + if (PKTPOOL_REGISTRY_CMP(poolid, POOLPTR(poolptr))) { + PKTPOOL_REGISTRY_CLR(poolid); /* mark as free */ + } else { + ASSERT(0); + return BCME_ERROR; /* mismatch in registry */ + } + + return BCME_OK; +} + + +/* + * pktpool_init: + * User provides a pktpool_t sturcture and specifies the number of packets to + * be pre-filled into the pool (pplen). The size of all packets in a pool must + * be the same and is specified by plen. + * pktpool_init first attempts to register the pool and fetch a unique poolid. + * If registration fails, it is considered an BCME_ERR, caused by either the + * registry was not pre-created (pktpool_attach) or the registry is full. + * If registration succeeds, then the requested number of packets will be filled + * into the pool as part of initialization. In the event that there is no + * available memory to service the request, then BCME_NOMEM will be returned + * along with the count of how many packets were successfully allocated. + * In dongle builds, prior to memory reclaimation, one should limit the number + * of packets to be allocated during pktpool_init and fill the pool up after + * reclaim stage. + */ +int +pktpool_init(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx, uint8 type) +{ + int i, err = BCME_OK; + int pktplen; + uint8 pktp_id; + + ASSERT(pktp != NULL); + ASSERT(osh != NULL); + ASSERT(pplen != NULL); + + pktplen = *pplen; + + bzero(pktp, sizeof(pktpool_t)); + + /* assign a unique pktpool id */ + if ((pktp_id = (uint8) pktpool_register(pktp)) == PKTPOOL_INVALID_ID) { + return BCME_ERROR; + } + POOLSETID(pktp, pktp_id); + + pktp->inited = TRUE; + pktp->istx = istx ? TRUE : FALSE; + pktp->plen = (uint16)plen; + pktp->type = type; + + pktp->maxlen = PKTPOOL_LEN_MAX; + pktplen = LIMIT_TO_MAX(pktplen, pktp->maxlen); + + for (i = 0; i < pktplen; i++) { + void *p; + p = PKTGET(osh, plen, TRUE); + + if (p == NULL) { + /* Not able to allocate all requested pkts + * so just return what was actually allocated + * We can add to the pool later + */ + if (pktp->freelist == NULL) /* pktpool free list is empty */ + err = BCME_NOMEM; + + goto exit; + } + + PKTSETPOOL(osh, p, TRUE, pktp); /* Tag packet with pool ID */ + + PKTSETFREELIST(p, pktp->freelist); /* insert p at head of free list */ + pktp->freelist = p; + + pktp->avail++; + +#ifdef BCMDBG_POOL + pktp->dbg_q[pktp->dbg_qlen++].p = p; +#endif + } + +exit: + pktp->len = pktp->avail; + + *pplen = pktp->len; + return err; +} + +/* + * pktpool_deinit: + * Prior to freeing a pktpool, all packets must be first freed into the pktpool. + * Upon pktpool_deinit, all packets in the free pool will be freed to the heap. + * An assert is in place to ensure that there are no packets still lingering + * around. Packets freed to a pool after the deinit will cause a memory + * corruption as the pktpool_t structure no longer exists. + */ +int +pktpool_deinit(osl_t *osh, pktpool_t *pktp) +{ + uint16 freed = 0; + + ASSERT(osh != NULL); + ASSERT(pktp != NULL); + +#ifdef BCMDBG_POOL + { + int i; + for (i = 0; i <= pktp->len; i++) { + pktp->dbg_q[i].p = NULL; + } + } +#endif + + while (pktp->freelist != NULL) { + void * p = pktp->freelist; + + pktp->freelist = PKTFREELIST(p); /* unlink head packet from free list */ + PKTSETFREELIST(p, NULL); + + PKTSETPOOL(osh, p, FALSE, NULL); /* clear pool ID tag in pkt */ + + PKTFREE(osh, p, pktp->istx); /* free the packet */ + + freed++; + ASSERT(freed <= pktp->len); + } + + pktp->avail -= freed; + ASSERT(pktp->avail == 0); + + pktp->len -= freed; + + pktpool_deregister(pktp); /* release previously acquired unique pool id */ + POOLSETID(pktp, PKTPOOL_INVALID_ID); + + pktp->inited = FALSE; + + /* Are there still pending pkts? */ + ASSERT(pktp->len == 0); + + return 0; +} + +int +pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal) +{ + void *p; + int err = 0; + int len, psize, maxlen; + + ASSERT(pktp->plen != 0); + + maxlen = pktp->maxlen; + psize = minimal ? (maxlen >> 2) : maxlen; + for (len = (int)pktp->len; len < psize; len++) { + + p = PKTGET(osh, pktp->len, TRUE); + + if (p == NULL) { + err = BCME_NOMEM; + break; + } + + if (pktpool_add(pktp, p) != BCME_OK) { + PKTFREE(osh, p, FALSE); + err = BCME_ERROR; + break; + } + } + + return err; +} + +static void * +pktpool_deq(pktpool_t *pktp) +{ + void *p; + + if (pktp->avail == 0) + return NULL; + + ASSERT(pktp->freelist != NULL); + + p = pktp->freelist; /* dequeue packet from head of pktpool free list */ + pktp->freelist = PKTFREELIST(p); /* free list points to next packet */ + PKTSETFREELIST(p, NULL); + + pktp->avail--; + + return p; +} + +static void +pktpool_enq(pktpool_t *pktp, void *p) +{ + ASSERT(p != NULL); + + PKTSETFREELIST(p, pktp->freelist); /* insert at head of pktpool free list */ + pktp->freelist = p; /* free list points to newly inserted packet */ + + pktp->avail++; + ASSERT(pktp->avail <= pktp->len); +} + +/* utility for registering host addr fill function called from pciedev */ +int +/* BCMATTACHFN */ +(pktpool_hostaddr_fill_register)(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) +{ + + ASSERT(cb != NULL); + + ASSERT(pktp->cbext.cb == NULL); + pktp->cbext.cb = cb; + pktp->cbext.arg = arg; + return 0; +} + +int +pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) +{ + + ASSERT(cb != NULL); + + ASSERT(pktp->rxcplidfn.cb == NULL); + pktp->rxcplidfn.cb = cb; + pktp->rxcplidfn.arg = arg; + return 0; +} +/* Callback functions for split rx modes */ +/* when evr host posts rxbuffer, invike dma_rxfill from pciedev layer */ +void +pktpool_invoke_dmarxfill(pktpool_t *pktp) +{ + ASSERT(pktp->dmarxfill.cb); + ASSERT(pktp->dmarxfill.arg); + + if (pktp->dmarxfill.cb) + pktp->dmarxfill.cb(pktp, pktp->dmarxfill.arg); +} +int +pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg) +{ + + ASSERT(cb != NULL); + + pktp->dmarxfill.cb = cb; + pktp->dmarxfill.arg = arg; + + return 0; +} +/* No BCMATTACHFN as it is used in xdc_enable_ep which is not an attach function */ +int +pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) +{ + int i; + + ASSERT(cb != NULL); + + i = pktp->cbcnt; + if (i == PKTPOOL_CB_MAX) + return BCME_ERROR; + + ASSERT(pktp->cbs[i].cb == NULL); + pktp->cbs[i].cb = cb; + pktp->cbs[i].arg = arg; + pktp->cbcnt++; + + return 0; +} + +int +pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) +{ + int i; + + ASSERT(cb != NULL); + + i = pktp->ecbcnt; + if (i == PKTPOOL_CB_MAX) + return BCME_ERROR; + + ASSERT(pktp->ecbs[i].cb == NULL); + pktp->ecbs[i].cb = cb; + pktp->ecbs[i].arg = arg; + pktp->ecbcnt++; + + return 0; +} + +static int +pktpool_empty_notify(pktpool_t *pktp) +{ + int i; + + pktp->empty = TRUE; + for (i = 0; i < pktp->ecbcnt; i++) { + ASSERT(pktp->ecbs[i].cb != NULL); + pktp->ecbs[i].cb(pktp, pktp->ecbs[i].arg); + } + pktp->empty = FALSE; + + return 0; +} + +#ifdef BCMDBG_POOL +int +pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) +{ + int i; + + ASSERT(cb); + + i = pktp->dbg_cbcnt; + if (i == PKTPOOL_CB_MAX) + return BCME_ERROR; + + ASSERT(pktp->dbg_cbs[i].cb == NULL); + pktp->dbg_cbs[i].cb = cb; + pktp->dbg_cbs[i].arg = arg; + pktp->dbg_cbcnt++; + + return 0; +} + +int pktpool_dbg_notify(pktpool_t *pktp); + +int +pktpool_dbg_notify(pktpool_t *pktp) +{ + int i; + + for (i = 0; i < pktp->dbg_cbcnt; i++) { + ASSERT(pktp->dbg_cbs[i].cb); + pktp->dbg_cbs[i].cb(pktp, pktp->dbg_cbs[i].arg); + } + + return 0; +} + +int +pktpool_dbg_dump(pktpool_t *pktp) +{ + int i; + + printf("pool len=%d maxlen=%d\n", pktp->dbg_qlen, pktp->maxlen); + for (i = 0; i < pktp->dbg_qlen; i++) { + ASSERT(pktp->dbg_q[i].p); + printf("%d, p: 0x%x dur:%lu us state:%d\n", i, + pktp->dbg_q[i].p, pktp->dbg_q[i].dur/100, PKTPOOLSTATE(pktp->dbg_q[i].p)); + } + + return 0; +} + +int +pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats) +{ + int i; + int state; + + bzero(stats, sizeof(pktpool_stats_t)); + for (i = 0; i < pktp->dbg_qlen; i++) { + ASSERT(pktp->dbg_q[i].p != NULL); + + state = PKTPOOLSTATE(pktp->dbg_q[i].p); + switch (state) { + case POOL_TXENQ: + stats->enq++; break; + case POOL_TXDH: + stats->txdh++; break; + case POOL_TXD11: + stats->txd11++; break; + case POOL_RXDH: + stats->rxdh++; break; + case POOL_RXD11: + stats->rxd11++; break; + case POOL_RXFILL: + stats->rxfill++; break; + case POOL_IDLE: + stats->idle++; break; + } + } + + return 0; +} + +int +pktpool_start_trigger(pktpool_t *pktp, void *p) +{ + uint32 cycles, i; + + if (!PKTPOOL(OSH_NULL, p)) + return 0; + + OSL_GETCYCLES(cycles); + + for (i = 0; i < pktp->dbg_qlen; i++) { + ASSERT(pktp->dbg_q[i].p != NULL); + + if (pktp->dbg_q[i].p == p) { + pktp->dbg_q[i].cycles = cycles; + break; + } + } + + return 0; +} + +int pktpool_stop_trigger(pktpool_t *pktp, void *p); +int +pktpool_stop_trigger(pktpool_t *pktp, void *p) +{ + uint32 cycles, i; + + if (!PKTPOOL(OSH_NULL, p)) + return 0; + + OSL_GETCYCLES(cycles); + + for (i = 0; i < pktp->dbg_qlen; i++) { + ASSERT(pktp->dbg_q[i].p != NULL); + + if (pktp->dbg_q[i].p == p) { + if (pktp->dbg_q[i].cycles == 0) + break; + + if (cycles >= pktp->dbg_q[i].cycles) + pktp->dbg_q[i].dur = cycles - pktp->dbg_q[i].cycles; + else + pktp->dbg_q[i].dur = + (((uint32)-1) - pktp->dbg_q[i].cycles) + cycles + 1; + + pktp->dbg_q[i].cycles = 0; + break; + } + } + + return 0; +} +#endif /* BCMDBG_POOL */ + +int +pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp) +{ + ASSERT(pktp); + pktp->availcb_excl = NULL; + return 0; +} + +int +pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb) +{ + int i; + + ASSERT(pktp); + ASSERT(pktp->availcb_excl == NULL); + for (i = 0; i < pktp->cbcnt; i++) { + if (cb == pktp->cbs[i].cb) { + pktp->availcb_excl = &pktp->cbs[i]; + break; + } + } + + if (pktp->availcb_excl == NULL) + return BCME_ERROR; + else + return 0; +} + +static int +pktpool_avail_notify(pktpool_t *pktp) +{ + int i, k, idx; + int avail; + + ASSERT(pktp); + if (pktp->availcb_excl != NULL) { + pktp->availcb_excl->cb(pktp, pktp->availcb_excl->arg); + return 0; + } + + k = pktp->cbcnt - 1; + for (i = 0; i < pktp->cbcnt; i++) { + avail = pktp->avail; + + if (avail) { + if (pktp->cbtoggle) + idx = i; + else + idx = k--; + + ASSERT(pktp->cbs[idx].cb != NULL); + pktp->cbs[idx].cb(pktp, pktp->cbs[idx].arg); + } + } + + /* Alternate between filling from head or tail + */ + pktp->cbtoggle ^= 1; + + return 0; +} + +void * +pktpool_get(pktpool_t *pktp) +{ + void *p; + + p = pktpool_deq(pktp); + + if (p == NULL) { + /* Notify and try to reclaim tx pkts */ + if (pktp->ecbcnt) + pktpool_empty_notify(pktp); + + p = pktpool_deq(pktp); + if (p == NULL) + return NULL; + } + + return p; +} + +void +pktpool_free(pktpool_t *pktp, void *p) +{ + ASSERT(p != NULL); +#ifdef BCMDBG_POOL + /* pktpool_stop_trigger(pktp, p); */ +#endif + + pktpool_enq(pktp, p); + + if (pktp->emptycb_disable) + return; + + if (pktp->cbcnt) { + if (pktp->empty == FALSE) + pktpool_avail_notify(pktp); + } +} + +int +pktpool_add(pktpool_t *pktp, void *p) +{ + ASSERT(p != NULL); + + if (pktp->len == pktp->maxlen) + return BCME_RANGE; + + /* pkts in pool have same length */ + ASSERT(pktp->plen == PKTLEN(OSH_NULL, p)); + PKTSETPOOL(OSH_NULL, p, TRUE, pktp); + + pktp->len++; + pktpool_enq(pktp, p); + +#ifdef BCMDBG_POOL + pktp->dbg_q[pktp->dbg_qlen++].p = p; +#endif + + return 0; +} + +/* Force pktpool_setmaxlen () into RAM as it uses a constant + * (PKTPOOL_LEN_MAX) that may be changed post tapeout for ROM-based chips. + */ +int +BCMRAMFN(pktpool_setmaxlen)(pktpool_t *pktp, uint16 maxlen) +{ + if (maxlen > PKTPOOL_LEN_MAX) + maxlen = PKTPOOL_LEN_MAX; + + /* if pool is already beyond maxlen, then just cap it + * since we currently do not reduce the pool len + * already allocated + */ + pktp->maxlen = (pktp->len > maxlen) ? pktp->len : maxlen; + + return pktp->maxlen; +} + +void +pktpool_emptycb_disable(pktpool_t *pktp, bool disable) +{ + ASSERT(pktp); + + pktp->emptycb_disable = disable; +} + +bool +pktpool_emptycb_disabled(pktpool_t *pktp) +{ + ASSERT(pktp); + return pktp->emptycb_disable; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/hnd_pktq.c b/drivers/net/wireless/bcmdhd_bcm4356/hnd_pktq.c new file mode 100644 index 000000000000..e4ce75b1363e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/hnd_pktq.c @@ -0,0 +1,602 @@ +/* + * HND generic pktq operation primitives + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: $ + */ + +#include +#include +#include +#include + +/* + * osl multiple-precedence packet queue + * hi_prec is always >= the number of the highest non-empty precedence + */ +void * BCMFASTPATH +pktq_penq(struct pktq *pq, int prec, void *p) +{ + struct pktq_prec *q; + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + if (q->head) + PKTSETLINK(q->tail, p); + else + q->head = p; + + q->tail = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + return p; +} + +void * BCMFASTPATH +pktq_penq_head(struct pktq *pq, int prec, void *p) +{ + struct pktq_prec *q; + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + if (q->head == NULL) + q->tail = p; + + PKTSETLINK(p, q->head); + q->head = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + return p; +} + +/* + * Append spktq 'list' to the tail of pktq 'pq' + */ +void BCMFASTPATH +pktq_append(struct pktq *pq, int prec, struct spktq *list) +{ + struct pktq_prec *q; + struct pktq_prec *list_q; + + list_q = &list->q[0]; + + /* empty list check */ + if (list_q->head == NULL) + return; + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(list_q->tail) == NULL); /* terminated list */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + if (q->head) + PKTSETLINK(q->tail, list_q->head); + else + q->head = list_q->head; + + q->tail = list_q->tail; + q->len += list_q->len; + pq->len += list_q->len; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + list_q->head = NULL; + list_q->tail = NULL; + list_q->len = 0; + list->len = 0; +} + +/* + * Prepend spktq 'list' to the head of pktq 'pq' + */ +void BCMFASTPATH +pktq_prepend(struct pktq *pq, int prec, struct spktq *list) +{ + struct pktq_prec *q; + struct pktq_prec *list_q; + + list_q = &list->q[0]; + + /* empty list check */ + if (list_q->head == NULL) + return; + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(list_q->tail) == NULL); /* terminated list */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + /* set the tail packet of list to point at the former pq head */ + PKTSETLINK(list_q->tail, q->head); + /* the new q head is the head of list */ + q->head = list_q->head; + + /* If the q tail was non-null, then it stays as is. + * If the q tail was null, it is now the tail of list + */ + if (q->tail == NULL) { + q->tail = list_q->tail; + } + + q->len += list_q->len; + pq->len += list_q->len; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + list_q->head = NULL; + list_q->tail = NULL; + list_q->len = 0; + list->len = 0; +} + +void * BCMFASTPATH +pktq_pdeq(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if (prev_p == NULL) + return NULL; + + if ((p = PKTLINK(prev_p)) == NULL) + return NULL; + + q->len--; + + pq->len--; + + PKTSETLINK(prev_p, PKTLINK(p)); + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg) +{ + struct pktq_prec *q; + void *p, *prev = NULL; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + p = q->head; + + while (p) { + if (fn == NULL || (*fn)(p, arg)) { + break; + } else { + prev = p; + p = PKTLINK(p); + } + } + if (p == NULL) + return NULL; + + if (prev == NULL) { + if ((q->head = PKTLINK(p)) == NULL) { + q->tail = NULL; + } + } else { + PKTSETLINK(prev, PKTLINK(p)); + if (q->tail == p) { + q->tail = prev; + } + } + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_pdeq_tail(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + void *p, *prev; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + for (prev = NULL; p != q->tail; p = PKTLINK(p)) + prev = p; + + if (prev) + PKTSETLINK(prev, NULL); + else + q->head = NULL; + + q->tail = prev; + q->len--; + + pq->len--; + + return p; +} + +void +pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) +{ + struct pktq_prec *q; + void *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 = PKTLINK(p); + else + PKTSETLINK(prev, PKTLINK(p)); + PKTSETLINK(p, NULL); + PKTFREE(osh, p, dir); + q->len--; + pq->len--; + p = (head ? q->head : PKTLINK(prev)); + } else { + prev = p; + p = PKTLINK(p); + } + } + + if (q->head == NULL) { + ASSERT(q->len == 0); + q->tail = NULL; + } +} + +bool BCMFASTPATH +pktq_pdel(struct pktq *pq, void *pktbuf, int prec) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + /* Should this just assert pktbuf? */ + if (!pktbuf) + return FALSE; + + q = &pq->q[prec]; + + if (q->head == pktbuf) { + if ((q->head = PKTLINK(pktbuf)) == NULL) + q->tail = NULL; + } else { + for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) + ; + if (p == NULL) + return FALSE; + + PKTSETLINK(p, PKTLINK(pktbuf)); + if (q->tail == pktbuf) + q->tail = p; + } + + q->len--; + pq->len--; + PKTSETLINK(pktbuf, NULL); + return TRUE; +} + +void +pktq_init(struct pktq *pq, int num_prec, int max_len) +{ + int prec; + + ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); + + /* pq is variable size; only zero out what's requested */ + bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); + + pq->num_prec = (uint16)num_prec; + + pq->max = (uint16)max_len; + + for (prec = 0; prec < num_prec; prec++) + pq->q[prec].max = pq->max; +} + +void +pktq_set_max_plen(struct pktq *pq, int prec, int max_len) +{ + ASSERT(prec >= 0 && prec < pq->num_prec); + + if (prec < pq->num_prec) + pq->q[prec].max = (uint16)max_len; +} + +void * BCMFASTPATH +pktq_deq(struct pktq *pq, int *prec_out) +{ + struct pktq_prec *q; + void *p; + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + pq->len--; + + if (prec_out) + *prec_out = prec; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_deq_tail(struct pktq *pq, int *prec_out) +{ + struct pktq_prec *q; + void *p, *prev; + int prec; + + if (pq->len == 0) + return NULL; + + for (prec = 0; prec < pq->hi_prec; prec++) + if (pq->q[prec].head) + break; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + for (prev = NULL; p != q->tail; p = PKTLINK(p)) + prev = p; + + if (prev) + PKTSETLINK(prev, NULL); + else + q->head = NULL; + + q->tail = prev; + q->len--; + + pq->len--; + + if (prec_out) + *prec_out = prec; + + PKTSETLINK(p, NULL); + + return p; +} + +void * +pktq_peek(struct pktq *pq, int *prec_out) +{ + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + if (prec_out) + *prec_out = prec; + + return (pq->q[prec].head); +} + +void * +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); +} + +void +pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) +{ + int prec; + + /* Optimize flush, if pktq len = 0, just return. + * pktq len of 0 means pktq's prec q's are all empty. + */ + if (pq->len == 0) { + return; + } + + for (prec = 0; prec < pq->num_prec; prec++) + pktq_pflush(osh, pq, prec, dir, fn, arg); + if (fn == NULL) + ASSERT(pq->len == 0); +} + +/* Return sum of lengths of a specific set of precedences */ +int +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; +} + +/* Priority peek from a specific set of precedences */ +void * BCMFASTPATH +pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) +{ + struct pktq_prec *q; + void *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]; + + if ((p = q->head) == NULL) + return NULL; + + if (prec_out) + *prec_out = prec; + + return p; +} +/* Priority dequeue from a specific set of precedences */ +void * BCMFASTPATH +pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) +{ + struct pktq_prec *q; + void *p; + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) + if (prec-- == 0) + return NULL; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + if (prec_out) + *prec_out = prec; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/hndpmu.c b/drivers/net/wireless/bcmdhd_bcm4356/hndpmu.c new file mode 100644 index 000000000000..95656347d148 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/hndpmu.c @@ -0,0 +1,274 @@ +/* + * Misc utility routines for accessing PMU corerev specific features + * of the SiliconBackplane-based Broadcom chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hndpmu.c 475037 2014-05-02 23:55:49Z $ + */ + + +/* + * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs. + * However, in the context of this file the baseband ('BB') PLL/FLL is referred to. + * + * Throughout this code, the prefixes 'pmu0_', 'pmu1_' and 'pmu2_' are used. + * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012) + * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports + * fractional frequency generation. pmu2_ does not support fractional frequency generation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PMU_ERROR(args) + +#define PMU_MSG(args) + +/* To check in verbose debugging messages not intended + * to be on except on private builds. + */ +#define PMU_NONE(args) + +/** contains resource bit positions for a specific chip */ +struct rsc_per_chip_s { + uint8 ht_avail; + uint8 macphy_clkavail; + uint8 ht_start; + uint8 otp_pu; +}; + +typedef struct rsc_per_chip_s rsc_per_chip_t; + + +/* SDIO Pad drive strength to select value mappings. + * The last strength value in each table must be 0 (the tri-state value). + */ +typedef struct { + uint8 strength; /* Pad Drive Strength in mA */ + uint8 sel; /* Chip-specific select value */ +} sdiod_drive_str_t; + +/* SDIO Drive Strength to sel value table for PMU Rev 1 */ +static const sdiod_drive_str_t 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 sdiod_drive_str_t 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 sdiod_drive_str_t sdiod_drive_strength_tab3[] = { + {32, 0x7}, + {26, 0x6}, + {22, 0x5}, + {16, 0x4}, + {12, 0x3}, + {8, 0x2}, + {4, 0x1}, + {0, 0x0} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { + {32, 0x6}, + {26, 0x7}, + {22, 0x4}, + {16, 0x5}, + {12, 0x2}, + {8, 0x3}, + {4, 0x0}, + {0, 0x1} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ + +/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { + {6, 0x7}, + {5, 0x6}, + {4, 0x5}, + {3, 0x4}, + {2, 0x2}, + {1, 0x1}, + {0, 0x0} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ + +/** SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { + {3, 0x3}, + {2, 0x2}, + {1, 0x1}, + {0, 0x0} }; + + +/** + * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel + * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture + * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has + * been written '1'. + */ +#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 + +static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = { + /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */ + {16, 0x7}, + {12, 0x5}, + {8, 0x3}, + {4, 0x1} }; /* note: 43143 does not support tristate */ + +#else + +static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = { + /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */ + {8, 0x7}, + {6, 0x5}, + {4, 0x3}, + {2, 0x1} }; /* note: 43143 does not support tristate */ + +#endif /* BCM_SDIO_VDDIO */ + +#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) + +/** + * Balance between stable SDIO operation and power consumption is achieved using this function. + * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this + * function should read the VDDIO itself to select the correct table. For now it has been solved + * with the 'BCM_SDIO_VDDIO' preprocessor constant. + * + * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if + * hardware supports this), if no hw support drive strength is not programmed. + */ +void +si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) +{ + sdiod_drive_str_t *str_tab = NULL; + uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */ + uint32 str_shift = 0; + uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */ + uint32 str_ovr_pmuval = 0; /* position of bit within this register */ + + if (!(sih->cccaps & CC_CAP_PMU)) { + return; + } + + switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { + case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): + str_tab = (sdiod_drive_str_t *)&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): + case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): + if (sih->pmurev == 8) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; + } + else if (sih->pmurev == 11) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; + } + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; + str_mask = 0x00001800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): +#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 + if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; + } +#else + if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; + } +#endif /* BCM_SDIO_VDDIO */ + str_mask = 0x00000007; + str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; + break; + default: + PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", + bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); + break; + } + + if (str_tab != NULL) { + uint32 cc_data_temp; + int i; + + /* Pick the lowest available drive strength equal or greater than the + * requested strength. Drive strength of 0 requests tri-state. + */ + for (i = 0; drivestrength < str_tab[i].strength; i++) + ; + + if (i > 0 && drivestrength > str_tab[i].strength) + i--; + + W_REG(osh, PMUREG(sih, chipcontrol_addr), PMU_CHIPCTL1); + cc_data_temp = R_REG(osh, PMUREG(sih, chipcontrol_data)); + cc_data_temp &= ~str_mask; + cc_data_temp |= str_tab[i].sel << str_shift; + W_REG(osh, PMUREG(sih, chipcontrol_data), cc_data_temp); + if (str_ovr_pmuval) { /* enables the selected drive strength */ + W_REG(osh, PMUREG(sih, chipcontrol_addr), str_ovr_pmuctl); + OR_REG(osh, PMUREG(sih, chipcontrol_data), str_ovr_pmuval); + } + PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", + drivestrength, str_tab[i].strength)); + } +} /* si_sdiod_drive_strength_init */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/Makefile b/drivers/net/wireless/bcmdhd_bcm4356/include/Makefile new file mode 100644 index 000000000000..40224e8dc232 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/Makefile @@ -0,0 +1,71 @@ +#!/bin/bash +# +# Copyright (C) 1999-2017, Broadcom Corporation +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to you +# under the terms of the GNU General Public License version 2 (the "GPL"), +# available at http://www.broadcom.com/licenses/GPLv2.php, with the +# following added to such license: +# +# As a special exception, the copyright holders of this software give you +# permission to link this software with independent modules, and to copy and +# distribute the resulting executable under terms of your choice, provided that +# you also meet, for each linked independent module, the terms and conditions of +# the license of that module. An independent module is a module which is not +# derived from this software. The special exception does not apply to any +# modifications of the software. +# +# Notwithstanding the above, under no circumstances may you combine this +# software in any way with any other Broadcom software provided under a license +# other than the GPL, without Broadcom's express prior written consent. +# +# This script serves following purpose: +# +# 1. It generates native version information by querying +# automerger maintained database to see where src/include +# came from +# 2. For select components, as listed in compvers.sh +# it generates component version files +# +# $Id: Makefile 528443 2015-01-22 09:29:18Z $ +# + +export SRCBASE:=.. + +TARGETS := epivers.h + +ifdef VERBOSE +export VERBOSE +endif + +all release: epivers compvers + +# Generate epivers.h for native branch url +epivers: + bash epivers.sh + +# Generate component versions based on component url +compvers: + @if [ -s "compvers.sh" ]; then \ + echo "Generating component versions, if any"; \ + bash compvers.sh; \ + else \ + echo "Skipping component version generation"; \ + fi + +# Generate epivers.h for native branch version +clean_compvers: + @if [ -s "compvers.sh" ]; then \ + echo "bash compvers.sh clean"; \ + bash compvers.sh clean; \ + else \ + echo "Skipping component version clean"; \ + fi + +clean: + rm -f $(TARGETS) *.prev + +clean_all: clean clean_compvers + +.PHONY: all release clean epivers compvers clean_compvers diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/aidmp.h b/drivers/net/wireless/bcmdhd_bcm4356/include/aidmp.h new file mode 100644 index 000000000000..8314d110e2e6 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/aidmp.h @@ -0,0 +1,387 @@ +/* + * Broadcom AMBA Interconnect definitions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: aidmp.h 511882 2014-10-31 06:08:29Z $ + */ + +#ifndef _AIDMP_H +#define _AIDMP_H + +/* Manufacturer Ids */ +#define MFGID_ARM 0x43b +#define MFGID_BRCM 0x4bf +#define MFGID_MIPS 0x4a7 + +/* Component Classes */ +#define CC_SIM 0 +#define CC_EROM 1 +#define CC_CORESIGHT 9 +#define CC_VERIF 0xb +#define CC_OPTIMO 0xd +#define CC_GEN 0xe +#define CC_PRIMECELL 0xf + +/* 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 +#define ER_SZ_MAX 4096 /* 4KB */ + +/* 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 MasterPortDesc */ +#define MPD_MUI_MASK 0x0000ff00 +#define MPD_MUI_SHIFT 8 +#define MPD_MP_MASK 0x000000f0 +#define MPD_MP_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 + + +#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) + +typedef volatile struct _aidmp { + uint32 oobselina30; /* 0x000 */ + uint32 oobselina74; /* 0x004 */ + uint32 PAD[6]; + uint32 oobselinb30; /* 0x020 */ + uint32 oobselinb74; /* 0x024 */ + uint32 PAD[6]; + uint32 oobselinc30; /* 0x040 */ + uint32 oobselinc74; /* 0x044 */ + uint32 PAD[6]; + uint32 oobselind30; /* 0x060 */ + uint32 oobselind74; /* 0x064 */ + uint32 PAD[38]; + uint32 oobselouta30; /* 0x100 */ + uint32 oobselouta74; /* 0x104 */ + uint32 PAD[6]; + uint32 oobseloutb30; /* 0x120 */ + uint32 oobseloutb74; /* 0x124 */ + uint32 PAD[6]; + uint32 oobseloutc30; /* 0x140 */ + uint32 oobseloutc74; /* 0x144 */ + uint32 PAD[6]; + uint32 oobseloutd30; /* 0x160 */ + uint32 oobseloutd74; /* 0x164 */ + uint32 PAD[38]; + uint32 oobsynca; /* 0x200 */ + uint32 oobseloutaen; /* 0x204 */ + uint32 PAD[6]; + uint32 oobsyncb; /* 0x220 */ + uint32 oobseloutben; /* 0x224 */ + uint32 PAD[6]; + uint32 oobsyncc; /* 0x240 */ + uint32 oobseloutcen; /* 0x244 */ + uint32 PAD[6]; + uint32 oobsyncd; /* 0x260 */ + uint32 oobseloutden; /* 0x264 */ + uint32 PAD[38]; + uint32 oobaextwidth; /* 0x300 */ + uint32 oobainwidth; /* 0x304 */ + uint32 oobaoutwidth; /* 0x308 */ + uint32 PAD[5]; + uint32 oobbextwidth; /* 0x320 */ + uint32 oobbinwidth; /* 0x324 */ + uint32 oobboutwidth; /* 0x328 */ + uint32 PAD[5]; + uint32 oobcextwidth; /* 0x340 */ + uint32 oobcinwidth; /* 0x344 */ + uint32 oobcoutwidth; /* 0x348 */ + uint32 PAD[5]; + uint32 oobdextwidth; /* 0x360 */ + uint32 oobdinwidth; /* 0x364 */ + uint32 oobdoutwidth; /* 0x368 */ + uint32 PAD[37]; + uint32 ioctrlset; /* 0x400 */ + uint32 ioctrlclear; /* 0x404 */ + uint32 ioctrl; /* 0x408 */ + uint32 PAD[61]; + uint32 iostatus; /* 0x500 */ + uint32 PAD[127]; + uint32 ioctrlwidth; /* 0x700 */ + uint32 iostatuswidth; /* 0x704 */ + uint32 PAD[62]; + uint32 resetctrl; /* 0x800 */ + uint32 resetstatus; /* 0x804 */ + uint32 resetreadid; /* 0x808 */ + uint32 resetwriteid; /* 0x80c */ + uint32 PAD[60]; + uint32 errlogctrl; /* 0x900 */ + uint32 errlogdone; /* 0x904 */ + uint32 errlogstatus; /* 0x908 */ + uint32 errlogaddrlo; /* 0x90c */ + uint32 errlogaddrhi; /* 0x910 */ + uint32 errlogid; /* 0x914 */ + uint32 errloguser; /* 0x918 */ + uint32 errlogflags; /* 0x91c */ + uint32 PAD[56]; + uint32 intstatus; /* 0xa00 */ + uint32 PAD[255]; + uint32 config; /* 0xe00 */ + uint32 PAD[63]; + uint32 itcr; /* 0xf00 */ + uint32 PAD[3]; + uint32 itipooba; /* 0xf10 */ + uint32 itipoobb; /* 0xf14 */ + uint32 itipoobc; /* 0xf18 */ + uint32 itipoobd; /* 0xf1c */ + uint32 PAD[4]; + uint32 itipoobaout; /* 0xf30 */ + uint32 itipoobbout; /* 0xf34 */ + uint32 itipoobcout; /* 0xf38 */ + uint32 itipoobdout; /* 0xf3c */ + uint32 PAD[4]; + uint32 itopooba; /* 0xf50 */ + uint32 itopoobb; /* 0xf54 */ + uint32 itopoobc; /* 0xf58 */ + uint32 itopoobd; /* 0xf5c */ + uint32 PAD[4]; + uint32 itopoobain; /* 0xf70 */ + uint32 itopoobbin; /* 0xf74 */ + uint32 itopoobcin; /* 0xf78 */ + uint32 itopoobdin; /* 0xf7c */ + uint32 PAD[4]; + uint32 itopreset; /* 0xf90 */ + uint32 PAD[15]; + uint32 peripherialid4; /* 0xfd0 */ + uint32 peripherialid5; /* 0xfd4 */ + uint32 peripherialid6; /* 0xfd8 */ + uint32 peripherialid7; /* 0xfdc */ + uint32 peripherialid0; /* 0xfe0 */ + uint32 peripherialid1; /* 0xfe4 */ + uint32 peripherialid2; /* 0xfe8 */ + uint32 peripherialid3; /* 0xfec */ + uint32 componentid0; /* 0xff0 */ + uint32 componentid1; /* 0xff4 */ + uint32 componentid2; /* 0xff8 */ + uint32 componentid3; /* 0xffc */ +} aidmp_t; + +#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ + +/* Out-of-band Router registers */ +#define OOB_BUSCONFIG 0x020 +#define OOB_STATUSA 0x100 +#define OOB_STATUSB 0x104 +#define OOB_STATUSC 0x108 +#define OOB_STATUSD 0x10c +#define OOB_ENABLEA0 0x200 +#define OOB_ENABLEA1 0x204 +#define OOB_ENABLEA2 0x208 +#define OOB_ENABLEA3 0x20c +#define OOB_ENABLEB0 0x280 +#define OOB_ENABLEB1 0x284 +#define OOB_ENABLEB2 0x288 +#define OOB_ENABLEB3 0x28c +#define OOB_ENABLEC0 0x300 +#define OOB_ENABLEC1 0x304 +#define OOB_ENABLEC2 0x308 +#define OOB_ENABLEC3 0x30c +#define OOB_ENABLED0 0x380 +#define OOB_ENABLED1 0x384 +#define OOB_ENABLED2 0x388 +#define OOB_ENABLED3 0x38c +#define OOB_ITCR 0xf00 +#define OOB_ITIPOOBA 0xf10 +#define OOB_ITIPOOBB 0xf14 +#define OOB_ITIPOOBC 0xf18 +#define OOB_ITIPOOBD 0xf1c +#define OOB_ITOPOOBA 0xf30 +#define OOB_ITOPOOBB 0xf34 +#define OOB_ITOPOOBC 0xf38 +#define OOB_ITOPOOBD 0xf3c + +/* DMP wrapper registers */ +#define AI_OOBSELINA30 0x000 +#define AI_OOBSELINA74 0x004 +#define AI_OOBSELINB30 0x020 +#define AI_OOBSELINB74 0x024 +#define AI_OOBSELINC30 0x040 +#define AI_OOBSELINC74 0x044 +#define AI_OOBSELIND30 0x060 +#define AI_OOBSELIND74 0x064 +#define AI_OOBSELOUTA30 0x100 +#define AI_OOBSELOUTA74 0x104 +#define AI_OOBSELOUTB30 0x120 +#define AI_OOBSELOUTB74 0x124 +#define AI_OOBSELOUTC30 0x140 +#define AI_OOBSELOUTC74 0x144 +#define AI_OOBSELOUTD30 0x160 +#define AI_OOBSELOUTD74 0x164 +#define AI_OOBSYNCA 0x200 +#define AI_OOBSELOUTAEN 0x204 +#define AI_OOBSYNCB 0x220 +#define AI_OOBSELOUTBEN 0x224 +#define AI_OOBSYNCC 0x240 +#define AI_OOBSELOUTCEN 0x244 +#define AI_OOBSYNCD 0x260 +#define AI_OOBSELOUTDEN 0x264 +#define AI_OOBAEXTWIDTH 0x300 +#define AI_OOBAINWIDTH 0x304 +#define AI_OOBAOUTWIDTH 0x308 +#define AI_OOBBEXTWIDTH 0x320 +#define AI_OOBBINWIDTH 0x324 +#define AI_OOBBOUTWIDTH 0x328 +#define AI_OOBCEXTWIDTH 0x340 +#define AI_OOBCINWIDTH 0x344 +#define AI_OOBCOUTWIDTH 0x348 +#define AI_OOBDEXTWIDTH 0x360 +#define AI_OOBDINWIDTH 0x364 +#define AI_OOBDOUTWIDTH 0x368 + + +#define AI_IOCTRLSET 0x400 +#define AI_IOCTRLCLEAR 0x404 +#define AI_IOCTRL 0x408 +#define AI_IOSTATUS 0x500 +#define AI_RESETCTRL 0x800 +#define AI_RESETSTATUS 0x804 + +#define AI_IOCTRLWIDTH 0x700 +#define AI_IOSTATUSWIDTH 0x704 + +#define AI_RESETREADID 0x808 +#define AI_RESETWRITEID 0x80c +#define AI_ERRLOGCTRL 0xa00 +#define AI_ERRLOGDONE 0xa04 +#define AI_ERRLOGSTATUS 0xa08 +#define AI_ERRLOGADDRLO 0xa0c +#define AI_ERRLOGADDRHI 0xa10 +#define AI_ERRLOGID 0xa14 +#define AI_ERRLOGUSER 0xa18 +#define AI_ERRLOGFLAGS 0xa1c +#define AI_INTSTATUS 0xa00 +#define AI_CONFIG 0xe00 +#define AI_ITCR 0xf00 +#define AI_ITIPOOBA 0xf10 +#define AI_ITIPOOBB 0xf14 +#define AI_ITIPOOBC 0xf18 +#define AI_ITIPOOBD 0xf1c +#define AI_ITIPOOBAOUT 0xf30 +#define AI_ITIPOOBBOUT 0xf34 +#define AI_ITIPOOBCOUT 0xf38 +#define AI_ITIPOOBDOUT 0xf3c +#define AI_ITOPOOBA 0xf50 +#define AI_ITOPOOBB 0xf54 +#define AI_ITOPOOBC 0xf58 +#define AI_ITOPOOBD 0xf5c +#define AI_ITOPOOBAIN 0xf70 +#define AI_ITOPOOBBIN 0xf74 +#define AI_ITOPOOBCIN 0xf78 +#define AI_ITOPOOBDIN 0xf7c +#define AI_ITOPRESET 0xf90 +#define AI_PERIPHERIALID4 0xfd0 +#define AI_PERIPHERIALID5 0xfd4 +#define AI_PERIPHERIALID6 0xfd8 +#define AI_PERIPHERIALID7 0xfdc +#define AI_PERIPHERIALID0 0xfe0 +#define AI_PERIPHERIALID1 0xfe4 +#define AI_PERIPHERIALID2 0xfe8 +#define AI_PERIPHERIALID3 0xfec +#define AI_COMPONENTID0 0xff0 +#define AI_COMPONENTID1 0xff4 +#define AI_COMPONENTID2 0xff8 +#define AI_COMPONENTID3 0xffc + +/* resetctrl */ +#define AIRC_RESET 1 + +/* config */ +#define AICFG_OOB 0x00000020 +#define AICFG_IOS 0x00000010 +#define AICFG_IOC 0x00000008 +#define AICFG_TO 0x00000004 +#define AICFG_ERRL 0x00000002 +#define AICFG_RST 0x00000001 + +/* bit defines for AI_OOBSELOUTB74 reg */ +#define OOB_SEL_OUTEN_B_5 15 +#define OOB_SEL_OUTEN_B_6 23 + +/* AI_OOBSEL for A/B/C/D, 0-7 */ +#define AI_OOBSEL_MASK 0x1F +#define AI_OOBSEL_0_SHIFT 0 +#define AI_OOBSEL_1_SHIFT 8 +#define AI_OOBSEL_2_SHIFT 16 +#define AI_OOBSEL_3_SHIFT 24 +#define AI_OOBSEL_4_SHIFT 0 +#define AI_OOBSEL_5_SHIFT 8 +#define AI_OOBSEL_6_SHIFT 16 +#define AI_OOBSEL_7_SHIFT 24 + +#endif /* _AIDMP_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcm_cfg.h new file mode 100644 index 000000000000..7c6e70f449ef --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcm_cfg.h @@ -0,0 +1,29 @@ +/* + * BCM common config options + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcm_cfg.h 351867 2012-08-21 18:46:16Z $ + */ + +#ifndef _bcm_cfg_h_ +#define _bcm_cfg_h_ +#endif /* _bcm_cfg_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcm_mpool_pub.h new file mode 100644 index 000000000000..b05ba3704aeb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcm_mpool_pub.h @@ -0,0 +1,361 @@ +/* + * Memory pools library, Public interface + * + * API Overview + * + * This package provides a memory allocation subsystem based on pools of + * homogenous objects. + * + * Instrumentation is available for reporting memory utilization both + * on a per-data-structure basis and system wide. + * + * There are two main types defined in this API. + * + * pool manager: A singleton object that acts as a factory for + * pool allocators. It also is used for global + * instrumentation, such as reporting all blocks + * in use across all data structures. The pool manager + * creates and provides individual memory pools + * upon request to application code. + * + * memory pool: An object for allocating homogenous memory blocks. + * + * Global identifiers in this module use the following prefixes: + * bcm_mpm_* Memory pool manager + * bcm_mp_* Memory pool + * + * There are two main types of memory pools: + * + * prealloc: The contiguous memory block of objects can either be supplied + * by the client or malloc'ed by the memory manager. The objects are + * allocated out of a block of memory and freed back to the block. + * + * heap: The memory pool allocator uses the heap (malloc/free) for memory. + * In this case, the pool allocator is just providing statistics + * and instrumentation on top of the heap, without modifying the heap + * allocation implementation. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcm_mpool_pub.h 407097 2013-06-11 18:43:16Z $ + */ + +#ifndef _BCM_MPOOL_PUB_H +#define _BCM_MPOOL_PUB_H 1 + +#include /* needed for uint16 */ + + +/* +************************************************************************** +* +* Type definitions, handles +* +************************************************************************** +*/ + +/* Forward declaration of OSL handle. */ +struct osl_info; + +/* Forward declaration of string buffer. */ +struct bcmstrbuf; + +/* + * Opaque type definition for the pool manager handle. This object is used for global + * memory pool operations such as obtaining a new pool, deleting a pool, iterating and + * instrumentation/debugging. + */ +struct bcm_mpm_mgr; +typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h; + +/* + * Opaque type definition for an instance of a pool. This handle is used for allocating + * and freeing memory through the pool, as well as management/instrumentation on this + * specific pool. + */ +struct bcm_mp_pool; +typedef struct bcm_mp_pool *bcm_mp_pool_h; + + +/* + * To make instrumentation more readable, every memory + * pool must have a readable name. Pool names are up to + * 8 bytes including '\0' termination. (7 printable characters.) + */ +#define BCM_MP_NAMELEN 8 + + +/* + * Type definition for pool statistics. + */ +typedef struct bcm_mp_stats { + char name[BCM_MP_NAMELEN]; /* Name of this pool. */ + unsigned int objsz; /* Object size allocated in this pool */ + uint16 nobj; /* Total number of objects in this pool */ + uint16 num_alloc; /* Number of objects currently allocated */ + uint16 high_water; /* Max number of allocated objects. */ + uint16 failed_alloc; /* Failed allocations. */ +} bcm_mp_stats_t; + + +/* +************************************************************************** +* +* API Routines on the pool manager. +* +************************************************************************** +*/ + +/* + * bcm_mpm_init() - initialize the whole memory pool system. + * + * Parameters: + * osh: INPUT Operating system handle. Needed for heap memory allocation. + * max_pools: INPUT Maximum number of mempools supported. + * mgr: OUTPUT The handle is written with the new pools manager object/handle. + * + * Returns: + * BCME_OK Object initialized successfully. May be used. + * BCME_NOMEM Initialization failed due to no memory. Object must not be used. + */ +int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp); + + +/* + * bcm_mpm_deinit() - de-initialize the whole memory pool system. + * + * Parameters: + * mgr: INPUT Pointer to pool manager handle. + * + * Returns: + * BCME_OK Memory pool manager successfully de-initialized. + * other Indicated error occured during de-initialization. + */ +int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); + +/* + * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The + * pool uses a contiguous block of pre-alloced + * memory. The memory block may either be provided + * by the client or dynamically allocated by the + * pool manager. + * + * Parameters: + * mgr: INPUT The handle to the pool manager + * obj_sz: INPUT Size of objects that will be allocated by the new pool + * Must be >= sizeof(void *). + * nobj: INPUT Maximum number of concurrently existing objects to support + * memstart INPUT Pointer to the memory to use, or NULL to malloc() + * memsize INPUT Number of bytes referenced from memstart (for error checking). + * Must be 0 if 'memstart' is NULL. + * poolname INPUT For instrumentation, the name of the pool + * newp: OUTPUT The handle for the new pool, if creation is successful + * + * Returns: + * BCME_OK Pool created ok. + * other Pool not created due to indicated error. newpoolp set to NULL. + * + * + */ +int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, + unsigned int obj_sz, + int nobj, + void *memstart, + unsigned int memsize, + const char poolname[BCM_MP_NAMELEN], + bcm_mp_pool_h *newp); + + +/* + * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after + * all memory objects have been freed back to the pool. + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * pool: INPUT The handle of the pool to delete + * + * Returns: + * BCME_OK Pool deleted ok. + * other Pool not deleted due to indicated error. + * + */ +int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); + +/* + * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory + * pool allocator uses the heap (malloc/free) for memory. + * In this case, the pool allocator is just providing + * statistics and instrumentation on top of the heap, + * without modifying the heap allocation implementation. + * + * Parameters: + * mgr: INPUT The handle to the pool manager + * obj_sz: INPUT Size of objects that will be allocated by the new pool + * poolname INPUT For instrumentation, the name of the pool + * newp: OUTPUT The handle for the new pool, if creation is successful + * + * Returns: + * BCME_OK Pool created ok. + * other Pool not created due to indicated error. newpoolp set to NULL. + * + * + */ +int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, + const char poolname[BCM_MP_NAMELEN], + bcm_mp_pool_h *newp); + + +/* + * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after + * all memory objects have been freed back to the pool. + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * pool: INPUT The handle of the pool to delete + * + * Returns: + * BCME_OK Pool deleted ok. + * other Pool not deleted due to indicated error. + * + */ +int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); + + +/* + * bcm_mpm_stats() - Return stats for all pools + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * stats: OUTPUT Array of pool statistics. + * nentries: MOD Max elements in 'stats' array on INPUT. Actual number + * of array elements copied to 'stats' on OUTPUT. + * + * Returns: + * BCME_OK Ok + * other Error getting stats. + * + */ +int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries); + + +/* + * bcm_mpm_dump() - Display statistics on all pools + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * b: OUTPUT Output buffer. + * + * Returns: + * BCME_OK Ok + * other Error during dump. + * + */ +int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b); + + +/* + * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to + * compensate for alignment requirements of the objects. + * This function provides the padded object size. If clients + * pre-allocate a memory slab for a memory pool, the + * padded object size should be used by the client to allocate + * the memory slab (in order to provide sufficent space for + * the maximum number of objects). + * + * Parameters: + * mgr: INPUT The handle to the pools manager. + * obj_sz: INPUT Input object size. + * padded_obj_sz: OUTPUT Padded object size. + * + * Returns: + * BCME_OK Ok + * BCME_BADARG Bad arguments. + * + */ +int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz); + + +/* +*************************************************************************** +* +* API Routines on a specific pool. +* +*************************************************************************** +*/ + + +/* + * bcm_mp_alloc() - Allocate a memory pool object. + * + * Parameters: + * pool: INPUT The handle to the pool. + * + * Returns: + * A pointer to the new object. NULL on error. + * + */ +void* bcm_mp_alloc(bcm_mp_pool_h pool); + +/* + * bcm_mp_free() - Free a memory pool object. + * + * Parameters: + * pool: INPUT The handle to the pool. + * objp: INPUT A pointer to the object to free. + * + * Returns: + * BCME_OK Ok + * other Error during free. + * + */ +int bcm_mp_free(bcm_mp_pool_h pool, void *objp); + +/* + * bcm_mp_stats() - Return stats for this pool + * + * Parameters: + * pool: INPUT The handle to the pool + * stats: OUTPUT Pool statistics + * + * Returns: + * BCME_OK Ok + * other Error getting statistics. + * + */ +int bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats); + + +/* + * bcm_mp_dump() - Dump a pool + * + * Parameters: + * pool: INPUT The handle to the pool + * b OUTPUT Output buffer + * + * Returns: + * BCME_OK Ok + * other Error during dump. + * + */ +int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b); + + +#endif /* _BCM_MPOOL_PUB_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmcdc.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmcdc.h new file mode 100644 index 000000000000..c93b6f619b20 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmcdc.h @@ -0,0 +1,132 @@ +/* + * CDC network driver ioctl/indication encoding + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmcdc.h 318308 2012-03-02 02:23:42Z $ + */ +#ifndef _bcmcdc_h_ +#define _bcmcdc_h_ +#include + +typedef struct cdc_ioctl { + uint32 cmd; /* ioctl command value */ + uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */ + uint32 flags; /* flag defns given below */ + uint32 status; /* status code returned from the device */ +} cdc_ioctl_t; + +/* Max valid buffer size that can be sent to the dongle */ +#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN + +/* len field is divided into input and output buffer lengths */ +#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */ + /* excluding IOCTL header */ +#define CDCL_IOC_OUTLEN_SHIFT 0 +#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */ +#define CDCL_IOC_INLEN_SHIFT 16 + +/* CDC flag definitions */ +#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */ +#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */ +#define CDCF_IOC_OVL_IDX_MASK 0x3c /* overlay region index mask */ +#define CDCF_IOC_OVL_RSV 0x40 /* 1=reserve this overlay region */ +#define CDCF_IOC_OVL 0x80 /* 1=this ioctl corresponds to an overlay */ +#define CDCF_IOC_ACTION_MASK 0xfe /* SET/GET, OVL_IDX, OVL_RSV, OVL mask */ +#define CDCF_IOC_ACTION_SHIFT 1 /* SET/GET, OVL_IDX, OVL_RSV, OVL shift */ +#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */ +#define CDCF_IOC_IF_SHIFT 12 +#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */ +#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */ + +#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) +#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) + +#define CDC_GET_IF_IDX(hdr) \ + ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) +#define CDC_SET_IF_IDX(hdr, idx) \ + ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) + +/* + * BDC header + * + * The BDC header is used on data packets to convey priority across USB. + */ + +struct bdc_header { + uint8 flags; /* Flags */ + uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 USB flow control info */ + uint8 flags2; + uint8 dataOffset; /* Offset from end of BDC header to packet data, in + * 4-byte words. Leaves room for optional headers. + */ +}; + +#define BDC_HEADER_LEN 4 + +/* flags field bitmap */ +#define BDC_FLAG_80211_PKT 0x01 /* Packet is in 802.11 format (dongle -> host) */ +#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */ +#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums: host->device */ +#define BDC_FLAG_EVENT_MSG 0x08 /* Payload contains an event msg: device->host */ +#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ +#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ + +/* priority field bitmap */ +#define BDC_PRIORITY_MASK 0x07 +#define BDC_PRIORITY_FC_MASK 0xf0 /* flow control info mask */ +#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */ + +/* flags2 field bitmap */ +#define BDC_FLAG2_IF_MASK 0x0f /* interface index (host <-> dongle) */ +#define BDC_FLAG2_IF_SHIFT 0 +#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */ + /* FLOW CONTROL info only */ + +/* version numbers */ +#define BDC_PROTO_VER_1 1 /* Old Protocol version */ +#define BDC_PROTO_VER 2 /* Protocol version */ + +/* flags2.if field access macros */ +#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))) + +#define BDC_FLAG2_PAD_MASK 0xf0 +#define BDC_FLAG_PAD_MASK 0x03 +#define BDC_FLAG2_PAD_SHIFT 2 +#define BDC_FLAG_PAD_SHIFT 0 +#define BDC_FLAG2_PAD_IDX 0x3c +#define BDC_FLAG_PAD_IDX 0x03 +#define BDC_GET_PAD_LEN(hdr) \ + ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ + ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) +#define BDC_SET_PAD_LEN(hdr, idx) \ + ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ + (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ + ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ + (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) + +#endif /* _bcmcdc_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmdefs.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmdefs.h new file mode 100644 index 000000000000..b444cb1c3fc5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmdefs.h @@ -0,0 +1,399 @@ +/* + * Misc system wide definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmdefs.h 516456 2014-11-19 21:00:05Z $ + */ + +#ifndef _bcmdefs_h_ +#define _bcmdefs_h_ + +/* + * One doesn't need to include this file explicitly, gets included automatically if + * typedefs.h is included. + */ + +/* Use BCM_REFERENCE to suppress warnings about intentionally-unused function + * arguments or local variables. + */ +#define BCM_REFERENCE(data) ((void)(data)) + +/* Allow for suppressing unused variable warnings. */ +#ifdef __GNUC__ +#define UNUSED_VAR __attribute__ ((unused)) +#else +#define UNUSED_VAR +#endif + +/* Compile-time assert can be used in place of ASSERT if the expression evaluates + * to a constant at compile time. + */ +#define STATIC_ASSERT(expr) { \ + /* Make sure the expression is constant. */ \ + typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \ + /* Make sure the expression is true. */ \ + typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \ +} + +/* Reclaiming text and data : + * The following macros specify special linker sections that can be reclaimed + * after a system is considered 'up'. + * BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN, + * as in most cases, the attach function calls the detach function to clean up on error). + */ + +#define bcmreclaimed 0 +#define _data _data +#define _fn _fn +#define BCMPREATTACHDATA(_data) _data +#define BCMPREATTACHFN(_fn) _fn +#define _data _data +#define _fn _fn +#define _fn _fn +#define BCMNMIATTACHFN(_fn) _fn +#define BCMNMIATTACHDATA(_data) _data +#define CONST const + +#undef BCM47XX_CA9 + +#ifndef BCMFASTPATH +#define BCMFASTPATH +#define BCMFASTPATH_HOST +#endif /* BCMFASTPATH */ + + +/* Use the BCMRAMFN() macro to tag functions in source that must be included in RAM (excluded from + * ROM). This should eliminate the need to manually specify these functions in the ROM config file. + * It should only be used in special cases where the function must be in RAM for *all* ROM-based + * chips. + */ + #define BCMRAMFN(_fn) _fn + +#define STATIC static + +/* Bus types */ +#define SI_BUS 0 /* SOC Interconnect */ +#define PCI_BUS 1 /* PCI target */ +#define PCMCIA_BUS 2 /* PCMCIA target */ +#define SDIO_BUS 3 /* SDIO target */ +#define JTAG_BUS 4 /* JTAG */ +#define USB_BUS 5 /* USB (does not support R/W REG) */ +#define SPI_BUS 6 /* gSPI target */ +#define RPC_BUS 7 /* RPC target */ + +/* Allows size optimization for single-bus image */ +#ifdef BCMBUSTYPE +#define BUSTYPE(bus) (BCMBUSTYPE) +#else +#define BUSTYPE(bus) (bus) +#endif + +/* Allows size optimization for single-backplane image */ +#ifdef BCMCHIPTYPE +#define CHIPTYPE(bus) (BCMCHIPTYPE) +#else +#define CHIPTYPE(bus) (bus) +#endif + + +/* Allows size optimization for SPROM support */ +#if defined(BCMSPROMBUS) +#define SPROMBUS (BCMSPROMBUS) +#elif defined(SI_PCMCIA_SROM) +#define SPROMBUS (PCMCIA_BUS) +#else +#define SPROMBUS (PCI_BUS) +#endif + +/* Allows size optimization for single-chip image */ +#ifdef BCMCHIPID +#define CHIPID(chip) (BCMCHIPID) +#else +#define CHIPID(chip) (chip) +#endif + +#ifdef BCMCHIPREV +#define CHIPREV(rev) (BCMCHIPREV) +#else +#define CHIPREV(rev) (rev) +#endif + +/* Defines for DMA Address Width - Shared between OSL and HNDDMA */ +#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ +#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */ +#define DMADDR_MASK_26 0xFC000000 /* Address maks for 26-bits */ +#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */ + +#define DMADDRWIDTH_26 26 /* 26-bit addressing capability */ +#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */ +#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */ +#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */ +#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */ + +typedef struct { + uint32 loaddr; + uint32 hiaddr; +} dma64addr_t; + +#define PHYSADDR64HI(_pa) ((_pa).hiaddr) +#define PHYSADDR64HISET(_pa, _val) \ + do { \ + (_pa).hiaddr = (_val); \ + } while (0) +#define PHYSADDR64LO(_pa) ((_pa).loaddr) +#define PHYSADDR64LOSET(_pa, _val) \ + do { \ + (_pa).loaddr = (_val); \ + } while (0) + +#define PHYSADDR64ADD(_pa, _hi0, _lo0, _hi1, _lo1) \ + do { \ + uint32 _lo = (uint32)(_lo0); \ + (_pa).loaddr = _lo + (uint32)(_lo1); \ + (_pa).hiaddr = (uint32)(_hi0) + (uint32)(_hi1) + \ + (((_pa).loaddr < _lo)? 1 : 0); \ + } while (0) +#define PHYSADDR64ADD64BITDATA(_pa, _paorg, _hi, _lo) \ + PHYSADDR64ADD((_pa), (_paorg).hiaddr, (_paorg).loaddr, (_hi), (_lo)) +#define PHYSADDR64ADDOFFSET(_pa, _paorg, _offset) \ + PHYSADDR64ADD((_pa), (_paorg).hiaddr, (_paorg).loaddr, 0, (_offset)) +#define PHYSADDR64ROUNDUP(_pa, _paorg, _align) \ + do { \ + PHYSADDR64ADDOFFSET(_pa, _paorg, (uint32)((_align) - 1)); \ + (_pa).loaddr = ((_pa).loaddr / (_align)) * (_align); \ + } while (0) + +#define PHYSADDR64SUB(_pa, _hi0, _lo0, _hi1, _lo1) \ + do { \ + uint32 _lo = (uint32)(_lo0); \ + (_pa).loaddr = _lo - (uint32)(_lo1); \ + (_pa).hiaddr = (uint32)(_hi0) - (uint32)(_hi1) - \ + (((_pa).loaddr > _lo)? 1 : 0); \ + } while (0) +#define PHYSADDR64SUB64BITDATA(_pa, _paorg, _hi, _lo) \ + PHYSADDR64SUB((_pa), (_paorg).hiaddr, (_paorg).loaddr, (_hi), (_lo)) +#define PHYSADDR64SUBOFFSET(_pa, _paorg, _offset) \ + PHYSADDR64SUB((_pa), (_paorg).hiaddr, (_paorg).loaddr, 0, (_offset)) + +#ifdef BCMDMA64OSL +typedef dma64addr_t dmaaddr_t; +#define PHYSADDRHI(_pa) PHYSADDR64HI(_pa) +#define PHYSADDRHISET(_pa, _val) PHYSADDR64HISET(_pa, _val) +#define PHYSADDRLO(_pa) PHYSADDR64LO(_pa) +#define PHYSADDRLOSET(_pa, _val) PHYSADDR64LOSET(_pa, _val) +#define PHYSADDRADD(_pa, _hi0, _lo0, _hi1, _lo1) \ + PHYSADDR64ADD(_pa, _hi0, _lo0, _hi1, _lo1) +#define PHYSADDRADD64BITDATA(_pa, _paorg, _hi, _lo) \ + PHYSADDR64ADD64BITDATA(_pa, _paorg, _hi, _lo) +#define PHYSADDRADDOFFSET(_pa, _paorg, _offset) \ + PHYSADDR64ADDOFFSET(_pa, _paorg, _offset) +#define PHYSADDRROUNDUP(_pa, _paorg, _align) \ + PHYSADDR64ROUNDUP(_pa, _paorg, _align) +#define PHYSADDRSUB(_pa, _hi0, _lo0, _hi1, _lo1) \ + PHYSADDR64SUB(_pa, _hi0, _lo0, _hi1, _lo1) +#define PHYSADDRSUB64BITDATA(_pa, _paorg, _hi, _lo) \ + PHYSADDR64SUB64BITDATA(_pa, _paorg, _hi, _lo) +#define PHYSADDRSUBOFFSET(_pa, _paorg, _offset) \ + PHYSADDR64SUBOFFSET(_pa, _paorg, _offset) +#else +typedef unsigned long dmaaddr_t; +#define PHYSADDRHI(_pa) (0) +#define PHYSADDRHISET(_pa, _val) +#define PHYSADDRLO(_pa) ((_pa)) +#define PHYSADDRLOSET(_pa, _val) \ + do { \ + (_pa) = (_val); \ + } while (0) +#define PHYSADDRADD(_pa, _hi0, _lo0, _hi1, _lo1) \ + do { \ + (_pa) = (uint32)(_lo0) + (uint32)(_lo1); \ + } while (0) +#define PHYSADDRADDOFFSET(_pa, _paorg, _offset) \ + do { \ + (_pa) = (uint32)(_paorg) + (uint32)(_offset); \ + } while (0) +#define PHYSADDRADD64BITDATA(_pa, _paorg, _hi, _lo) \ + do { \ + (_pa) = (uint32)(_paorg) + (uint32)(_lo); \ + } while (0) +#define PHYSADDRROUNDUP(_pa, _paorg, _align) \ + do { \ + (_pa) = (((_paorg) + ((_align) - 1)) / (_align)) * (_align); \ + } while (0) +#define PHYSADDRSUB(_pa, _hi0, _lo0, _hi1, _lo1) \ + do { \ + (_pa) = (uint32)(_lo0) - (uint32)(_lo1); \ + } while (0) +#define PHYSADDRSUB64BITDATA(_pa, _paorg, _hi, _lo) \ + do { \ + (_pa) = (uint32)(_paorg) - (uint32)(_lo); \ + } while (0) +#define PHYSADDRSUBOFFSET(_pa, _paorg, _offset) \ + do { \ + (_pa) = (uint32)(_paorg) - (uint32)(_offset); \ + } while (0) +#endif /* BCMDMA64OSL */ +#define PHYSADDRISZERO(_pa) (PHYSADDRLO(_pa) == 0 && PHYSADDRHI(_pa) == 0) + +/* One physical DMA segment */ +typedef struct { + dmaaddr_t addr; + uint32 length; +} hnddma_seg_t; + +#define MAX_DMA_SEGS 8 + + +typedef struct { + void *oshdmah; /* Opaque handle for OSL to store its information */ + uint origsize; /* Size of the virtual packet */ + uint nsegs; + hnddma_seg_t segs[MAX_DMA_SEGS]; +} hnddma_seg_map_t; + + +/* 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 (hnddma.c). + */ + +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) +/* add 40 bytes to allow for extra RPC header and info */ +#define BCMEXTRAHDROOM 260 +#else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ +#define BCMEXTRAHDROOM 204 +#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ + +/* Packet alignment for most efficient SDIO (can change based on platform) */ +#ifndef SDALIGN +#define SDALIGN 32 +#endif + +/* Headroom required for dongle-to-host communication. Packets allocated + * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should + * leave this much room in front for low-level message headers which may + * be needed to get across the dongle bus to the host. (These messages + * don't go over the network, so room for the full WL header above would + * be a waste.). +*/ +#define BCMDONGLEHDRSZ 12 +#define BCMDONGLEPADSZ 16 + +#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) + + +#if defined(NO_BCMDBG_ASSERT) +# undef BCMDBG_ASSERT +# undef BCMASSERT_LOG +#endif + +#if defined(BCMASSERT_LOG) +#define BCMASSERT_SUPPORT +#endif + +/* 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 BCMSMALL to remove misc features for memory-constrained environments */ +#ifdef BCMSMALL +#undef BCMSPACE +#define bcmspace FALSE /* if (bcmspace) code is discarded */ +#else +#define BCMSPACE +#define bcmspace TRUE /* if (bcmspace) code is retained */ +#endif + +/* Max. nvram variable table size */ +#ifndef MAXSZ_NVRAM_VARS +#define MAXSZ_NVRAM_VARS 4096 +#endif + + + +/* WL_ENAB_RUNTIME_CHECK may be set based upon the #define below (for ROM builds). It may also + * be defined via makefiles (e.g. ROM auto abandon unoptimized compiles). + */ + + +#ifdef BCMLFRAG /* BCMLFRAG support enab macros */ + extern bool _bcmlfrag; + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCMLFRAG_ENAB() (_bcmlfrag) + #elif defined(BCMLFRAG_DISABLED) + #define BCMLFRAG_ENAB() (0) + #else + #define BCMLFRAG_ENAB() (1) + #endif +#else + #define BCMLFRAG_ENAB() (0) +#endif /* BCMLFRAG_ENAB */ +#ifdef BCMSPLITRX /* BCMLFRAG support enab macros */ + extern bool _bcmsplitrx; + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCMSPLITRX_ENAB() (_bcmsplitrx) + #elif defined(BCMSPLITRX_DISABLED) + #define BCMSPLITRX_ENAB() (0) + #else + #define BCMSPLITRX_ENAB() (1) + #endif +#else + #define BCMSPLITRX_ENAB() (0) +#endif /* BCMSPLITRX */ +#ifdef BCM_SPLITBUF + extern bool _bcmsplitbuf; + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCM_SPLITBUF_ENAB() (_bcmsplitbuf) + #elif defined(BCM_SPLITBUF_DISABLED) + #define BCM_SPLITBUF_ENAB() (0) + #else + #define BCM_SPLITBUF_ENAB() (1) + #endif +#else + #define BCM_SPLITBUF_ENAB() (0) +#endif /* BCM_SPLITBUF */ +/* Max size for reclaimable NVRAM array */ +#ifdef DL_NVRAM +#define NVRAM_ARRAY_MAXSIZE DL_NVRAM +#else +#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS +#endif /* DL_NVRAM */ + +extern uint32 gFWID; + + +#endif /* _bcmdefs_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmdevs.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmdevs.h new file mode 100644 index 000000000000..126086eeba2b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmdevs.h @@ -0,0 +1,731 @@ +/* + * Broadcom device-specific manifest constants. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmdevs.h 484136 2014-06-12 04:36:10Z $ + */ + +#ifndef _BCMDEVS_H +#define _BCMDEVS_H + +/* PCI vendor IDs */ +#define VENDOR_EPIGRAM 0xfeda +#define VENDOR_BROADCOM 0x14e4 +#define VENDOR_3COM 0x10b7 +#define VENDOR_NETGEAR 0x1385 +#define VENDOR_DIAMOND 0x1092 +#define VENDOR_INTEL 0x8086 +#define VENDOR_DELL 0x1028 +#define VENDOR_HP 0x103c +#define VENDOR_HP_COMPAQ 0x0e11 +#define VENDOR_APPLE 0x106b +#define VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */ +#define VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */ +#define VENDOR_TI 0x104c /* Texas Instruments */ +#define VENDOR_RICOH 0x1180 /* Ricoh */ +#define VENDOR_JMICRON 0x197b + + +/* PCMCIA vendor IDs */ +#define VENDOR_BROADCOM_PCMCIA 0x02d0 + +/* SDIO vendor IDs */ +#define VENDOR_BROADCOM_SDIO 0x00BF + +/* DONGLE VID/PIDs */ +#define BCM_DNGL_VID 0x0a5c +#define BCM_DNGL_BL_PID_4328 0xbd12 +#define BCM_DNGL_BL_PID_4322 0xbd13 +#define BCM_DNGL_BL_PID_4319 0xbd16 +#define BCM_DNGL_BL_PID_43236 0xbd17 +#define BCM_DNGL_BL_PID_4332 0xbd18 +#define BCM_DNGL_BL_PID_4330 0xbd19 +#define BCM_DNGL_BL_PID_4334 0xbd1a +#define BCM_DNGL_BL_PID_43239 0xbd1b +#define BCM_DNGL_BL_PID_4324 0xbd1c +#define BCM_DNGL_BL_PID_4360 0xbd1d +#define BCM_DNGL_BL_PID_43143 0xbd1e +#define BCM_DNGL_BL_PID_43242 0xbd1f +#define BCM_DNGL_BL_PID_43342 0xbd21 +#define BCM_DNGL_BL_PID_4335 0xbd20 +#define BCM_DNGL_BL_PID_43341 0xbd22 +#define BCM_DNGL_BL_PID_4350 0xbd23 +#define BCM_DNGL_BL_PID_4345 0xbd24 +#define BCM_DNGL_BL_PID_4349 0xbd25 +#define BCM_DNGL_BL_PID_4354 0xbd26 +#define BCM_DNGL_BL_PID_43569 0xbd27 +#define BCM_DNGL_BL_PID_43909 0xbd28 + +#define BCM_DNGL_BDC_PID 0x0bdc +#define BCM_DNGL_JTAG_PID 0x4a44 + +/* HW USB BLOCK [CPULESS USB] PIDs */ +#define BCM_HWUSB_PID_43239 43239 + +/* PCI Device IDs */ +#define BCM4210_DEVICE_ID 0x1072 /* never used */ +#define BCM4230_DEVICE_ID 0x1086 /* never used */ +#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */ +#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */ +#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */ +#define BCM4211_DEVICE_ID 0x4211 +#define BCM4231_DEVICE_ID 0x4231 +#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */ +#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */ +#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */ +#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */ +#define BCM4328_D11DUAL_ID 0x4314 /* 4328/4312 802.11a/g id */ +#define BCM4328_D11G_ID 0x4315 /* 4328/4312 802.11g id */ +#define BCM4328_D11A_ID 0x4316 /* 4328/4312 802.11a id */ +#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */ +#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */ +#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */ +#define BCM4325_D11DUAL_ID 0x431b /* 4325 802.11a/g id */ +#define BCM4325_D11G_ID 0x431c /* 4325 802.11g id */ +#define BCM4325_D11A_ID 0x431d /* 4325 802.11a id */ +#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */ +#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */ +#define BCM4306_UART_ID 0x4322 /* 4306 uart */ +#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */ +#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */ +#define BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G_ID; INF w/loose binding war */ +#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */ +#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Ghz band id */ +#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */ +#define BCM4322_D11N_ID 0x432b /* 4322 802.11n dualband device */ +#define BCM4322_D11N2G_ID 0x432c /* 4322 802.11n 2.4GHz device */ +#define BCM4322_D11N5G_ID 0x432d /* 4322 802.11n 5GHz device */ +#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */ +#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ +#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ +#define BCM4315_D11DUAL_ID 0x4334 /* 4315 802.11a/g id */ +#define BCM4315_D11G_ID 0x4335 /* 4315 802.11g id */ +#define BCM4315_D11A_ID 0x4336 /* 4315 802.11a id */ +#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 BCM43231_D11N2G_ID 0x4340 /* 43231 802.11n 2.4GHz device */ +#define BCM43221_D11N2G_ID 0x4341 /* 43221 802.11n 2.4GHz device */ +#define BCM43222_D11N_ID 0x4350 /* 43222 802.11n dualband device */ +#define BCM43222_D11N2G_ID 0x4351 /* 43222 802.11n 2.4GHz device */ +#define BCM43222_D11N5G_ID 0x4352 /* 43222 802.11n 5GHz device */ +#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ +#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */ +#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband device */ +#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ +#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ +#define BCM43236_D11N5G_ID 0x4348 /* 43236 802.11n 5GHz device */ +#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ +#define BCM43421_D11N_ID 0xA99D /* 43421 802.11n dualband device */ +#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ +#define BCM4330_D11N_ID 0x4360 /* 4330 802.11n dualband device */ +#define BCM4330_D11N2G_ID 0x4361 /* 4330 802.11n 2.4G device */ +#define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */ +#define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */ +#define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */ +#define BCM6362_D11N2G_ID 0x433f /* 6362 802.11n 2.4Ghz band id */ +#define BCM6362_D11N5G_ID 0x434f /* 6362 802.11n 5Ghz band id */ +#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */ +#define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */ +#define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */ +#define BCM43237_D11N_ID 0x4355 /* 43237 802.11n dualband device */ +#define BCM43237_D11N5G_ID 0x4356 /* 43237 802.11n 5GHz device */ +#define BCM43227_D11N2G_ID 0x4358 /* 43228 802.11n 2.4GHz device */ +#define BCM43228_D11N_ID 0x4359 /* 43228 802.11n DualBand device */ +#define BCM43228_D11N5G_ID 0x435a /* 43228 802.11n 5GHz device */ +#define BCM43362_D11N_ID 0x4363 /* 43362 802.11n 2.4GHz device */ +#define BCM43239_D11N_ID 0x4370 /* 43239 802.11n dualband device */ +#define BCM4324_D11N_ID 0x4374 /* 4324 802.11n dualband device */ +#define BCM43217_D11N2G_ID 0x43a9 /* 43217 802.11n 2.4GHz device */ +#define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */ +#define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */ +#define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */ +#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ +#define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */ +#define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */ +#define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */ +#define BCM43342_D11N_ID 0x4383 /* 43342 802.11n dualband device */ +#define BCM43342_D11N2G_ID 0x4384 /* 43342 802.11n 2.4G device */ +#define BCM43342_D11N5G_ID 0x4385 /* 43342 802.11n 5G device */ +#define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */ +#define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */ +#define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */ +#define BCM4360_D11AC_ID 0x43a0 +#define BCM4360_D11AC2G_ID 0x43a1 +#define BCM4360_D11AC5G_ID 0x43a2 +#define BCM4345_D11AC_ID 0x43ab /* 4345 802.11ac dualband device */ +#define BCM4345_D11AC2G_ID 0x43ac /* 4345 802.11ac 2.4G device */ +#define BCM4345_D11AC5G_ID 0x43ad /* 4345 802.11ac 5G device */ +#define BCM4335_D11AC_ID 0x43ae +#define BCM4335_D11AC2G_ID 0x43af +#define BCM4335_D11AC5G_ID 0x43b0 +#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ +#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ +#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ +#define BCM43602_D11AC_ID 0x43ba /* ac dualband PCI devid SPROM programmed */ +#define BCM43602_D11AC2G_ID 0x43bb /* 43602 802.11ac 2.4G device */ +#define BCM43602_D11AC5G_ID 0x43bc /* 43602 802.11ac 5G device */ +#define BCM4349_D11AC_ID 0x4349 /* 4349 802.11ac dualband device */ +#define BCM4349_D11AC2G_ID 0x43dd /* 4349 802.11ac 2.4G device */ +#define BCM4349_D11AC5G_ID 0x43de /* 4349 802.11ac 5G device */ +#define BCM4355_D11AC_ID 0x43d3 /* 4355 802.11ac dualband device */ +#define BCM4355_D11AC2G_ID 0x43d4 /* 4355 802.11ac 2.4G device */ +#define BCM4355_D11AC5G_ID 0x43d5 /* 4355 802.11ac 5G device */ +#define BCM4359_D11AC_ID 0x43d6 /* 4359 802.11ac dualband device */ +#define BCM4359_D11AC2G_ID 0x43d7 /* 4359 802.11ac 2.4G device */ +#define BCM4359_D11AC5G_ID 0x43d8 /* 4359 802.11ac 5G device */ + +/* PCI Subsystem ID */ +#define BCM943228HMB_SSID_VEN1 0x0607 +#define BCM94313HMGBL_SSID_VEN1 0x0608 +#define BCM94313HMG_SSID_VEN1 0x0609 +#define BCM943142HM_SSID_VEN1 0x0611 + +#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ + +#define BCM43242_D11N_ID 0x4367 /* 43242 802.11n dualband device */ +#define BCM43242_D11N2G_ID 0x4368 /* 43242 802.11n 2.4G device */ +#define BCM43242_D11N5G_ID 0x4369 /* 43242 802.11n 5G device */ + +#define BCM4350_D11AC_ID 0x43a3 +#define BCM4350_D11AC2G_ID 0x43a4 +#define BCM4350_D11AC5G_ID 0x43a5 + +#define BCM43556_D11AC_ID 0x43b7 +#define BCM43556_D11AC2G_ID 0x43b8 +#define BCM43556_D11AC5G_ID 0x43b9 + +#define BCM43558_D11AC_ID 0x43c0 +#define BCM43558_D11AC2G_ID 0x43c1 +#define BCM43558_D11AC5G_ID 0x43c2 + +#define BCM43566_D11AC_ID 0x43d3 +#define BCM43566_D11AC2G_ID 0x43d4 +#define BCM43566_D11AC5G_ID 0x43d5 + +#define BCM43568_D11AC_ID 0x43d6 +#define BCM43568_D11AC2G_ID 0x43d7 +#define BCM43568_D11AC5G_ID 0x43d8 + +#define BCM43569_D11AC_ID 0x43d9 +#define BCM43569_D11AC2G_ID 0x43da +#define BCM43569_D11AC5G_ID 0x43db + +#define BCM43570_D11AC_ID 0x43d9 +#define BCM43570_D11AC2G_ID 0x43da +#define BCM43570_D11AC5G_ID 0x43db + +#define BCM4354_D11AC_ID 0x43df /* 4354 802.11ac dualband device */ +#define BCM4354_D11AC2G_ID 0x43e0 /* 4354 802.11ac 2.4G device */ +#define BCM4354_D11AC5G_ID 0x43e1 /* 4354 802.11ac 5G device */ +#define BCM43430_D11N2G_ID 0x43e2 /* 43430 802.11n 2.4G device */ + + +#define BCM43349_D11N_ID 0x43e6 /* 43349 802.11n dualband id */ +#define BCM43349_D11N2G_ID 0x43e7 /* 43349 802.11n 2.4Ghz band id */ +#define BCM43349_D11N5G_ID 0x43e8 /* 43349 802.11n 5Ghz band id */ + +#define BCM4358_D11AC_ID 0x43e9 /* 4358 802.11ac dualband device */ +#define BCM4358_D11AC2G_ID 0x43ea /* 4358 802.11ac 2.4G device */ +#define BCM4358_D11AC5G_ID 0x43eb /* 4358 802.11ac 5G device */ + +#define BCM4356_D11AC_ID 0x43ec /* 4356 802.11ac dualband device */ +#define BCM4356_D11AC2G_ID 0x43ed /* 4356 802.11ac 2.4G device */ +#define BCM4356_D11AC5G_ID 0x43ee /* 4356 802.11ac 5G device */ + +#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */ +#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */ +#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */ +#define BCM_JTAGM_ID 0x43f1 /* BCM jtagm device id */ +#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */ +#define BCM_SDIOH_ID 0x43f3 /* BCM sdio host id */ +#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */ +#define SPIH_FPGA_ID 0x43f5 /* PCI SPI Host Controller FPGA */ +#define BCM_SPIH_ID 0x43f6 /* Synopsis SPI Host Controller */ +#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */ +#define BCM_JTAGM2_ID 0x43f9 /* BCM alternate jtagm device id */ +#define SDHCI_FPGA_ID 0x43fa /* Standard SDIO Host Controller FPGA */ +#define BCM4402_ENET_ID 0x4402 /* 4402 enet */ +#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */ +#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */ +#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */ +#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */ +#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */ +#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */ +#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */ +#define BCM47XX_AUDIO_ID 0x4711 /* 47xx audio codec */ +#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */ +#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */ +#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */ +#define BCM47XX_GMAC_ID 0x4715 /* 47xx Unimac based GbE */ +#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */ +#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */ +#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */ +#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */ +#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */ +#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */ +#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */ +#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */ +#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */ +#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */ +#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */ +#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */ +#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */ +#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */ +#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */ +#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */ +#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */ +#define JINVANI_SDIOH_ID 0x4743 /* Jinvani SDIO Gold Host */ +#define BCM27XX_SDIOH_ID 0x2702 /* BCM27xx Standard SDIO Host */ +#define PCIXX21_FLASHMEDIA_ID 0x803b /* TI PCI xx21 Standard Host Controller */ +#define PCIXX21_SDIOH_ID 0x803c /* TI PCI xx21 Standard Host Controller */ +#define R5C822_SDIOH_ID 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */ +#define JMICRON_SDIOH_ID 0x2381 /* JMicron Standard SDIO Host Controller */ + +/* Chip IDs */ +#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */ +#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */ +#define BCM43111_CHIP_ID 43111 /* 43111 chipcommon chipid (OTP chipid) */ +#define BCM43112_CHIP_ID 43112 /* 43112 chipcommon chipid (OTP chipid) */ +#define BCM4312_CHIP_ID 0x4312 /* 4312 chipcommon chipid */ +#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ +#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP chipid) */ +#define BCM4315_CHIP_ID 0x4315 /* 4315 chip id */ +#define BCM4318_CHIP_ID 0x4318 /* 4318 chipcommon chipid */ +#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ +#define BCM4320_CHIP_ID 0x4320 /* 4320 chipcommon chipid */ +#define BCM4321_CHIP_ID 0x4321 /* 4321 chipcommon chipid */ +#define BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP chipid) */ +#define BCM4322_CHIP_ID 0x4322 /* 4322 chipcommon chipid */ +#define BCM43221_CHIP_ID 43221 /* 43221 chipcommon chipid (OTP chipid) */ +#define BCM43222_CHIP_ID 43222 /* 43222 chipcommon chipid */ +#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ +#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ +#define BCM43227_CHIP_ID 43227 /* 43227 chipcommon chipid */ +#define BCM43228_CHIP_ID 43228 /* 43228 chipcommon chipid */ +#define BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */ +#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (OTP chipid) */ +#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */ +#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ +#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ +#define BCM43237_CHIP_ID 43237 /* 43237 chipcommon chipid */ +#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ +#define BCM43239_CHIP_ID 43239 /* 43239 chipcommon chipid */ +#define BCM43420_CHIP_ID 43420 /* 43222 chipcommon chipid (OTP, RBBU) */ +#define BCM43421_CHIP_ID 43421 /* 43224 chipcommon chipid (OTP, RBBU) */ +#define BCM43428_CHIP_ID 43428 /* 43228 chipcommon chipid (OTP, RBBU) */ +#define BCM43431_CHIP_ID 43431 /* 4331 chipcommon chipid (OTP, RBBU) */ +#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ +#define BCM4325_CHIP_ID 0x4325 /* 4325 chip id */ +#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */ +#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ +#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ +#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ +#define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */ +#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ +#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ +#define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */ +#define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */ +#define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */ +#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */ +#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */ +#define BCM43243_CHIP_ID 43243 /* 43243 chipcommon chipid */ +#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */ +#define BCM4335_CHIP_ID 0x4335 /* 4335 chipcommon chipid */ +#define BCM4339_CHIP_ID 0x4339 /* 4339 chipcommon chipid */ +#define BCM43349_CHIP_ID 43349 /* 43349(0xA955) chipcommon chipid */ +#define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */ +#define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */ +#define BCM43526_CHIP_ID 0xAA06 +#define BCM43340_CHIP_ID 43340 /* 43340 chipcommon chipid */ +#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */ +#define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */ +#define BCM4350_CHIP_ID 0x4350 /* 4350 chipcommon chipid */ +#define BCM4354_CHIP_ID 0x4354 /* 4354 chipcommon chipid */ +#define BCM4356_CHIP_ID 0x4356 /* 4356 chipcommon chipid */ +#define BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */ +#define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */ +#define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */ +#define BCM43567_CHIP_ID 0xAA2F /* 43567 chipcommon chipid */ +#define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */ +#define BCM43569_CHIP_ID 0xAA31 /* 43569 chipcommon chipid */ +#define BCM43570_CHIP_ID 0xAA32 /* 43570 chipcommon chipid */ +#define BCM4358_CHIP_ID 0x4358 /* 4358 chipcommon chipid */ +#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \ + (CHIPID(chipid) == BCM4354_CHIP_ID) || \ + (CHIPID(chipid) == BCM4356_CHIP_ID) || \ + (CHIPID(chipid) == BCM43556_CHIP_ID) || \ + (CHIPID(chipid) == BCM43558_CHIP_ID) || \ + (CHIPID(chipid) == BCM43566_CHIP_ID) || \ + (CHIPID(chipid) == BCM43567_CHIP_ID) || \ + (CHIPID(chipid) == BCM43568_CHIP_ID) || \ + (CHIPID(chipid) == BCM43569_CHIP_ID) || \ + (CHIPID(chipid) == BCM43570_CHIP_ID) || \ + (CHIPID(chipid) == BCM4358_CHIP_ID)) /* 4350 variations */ +#define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */ +#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */ +#define BCM4349_CHIP_ID 0x4349 /* 4349 chipcommon chipid */ +#define BCM4355_CHIP_ID 0x4355 /* 4355 chipcommon chipid */ +#define BCM4359_CHIP_ID 0x4359 /* 4359 chipcommon chipid */ +#define BCM4349_CHIP(chipid) ((CHIPID(chipid) == BCM4349_CHIP_ID) || \ + (CHIPID(chipid) == BCM4355_CHIP_ID) || \ + (CHIPID(chipid) == BCM4359_CHIP_ID)) +#define BCM4349_CHIP_GRPID BCM4349_CHIP_ID: \ + case BCM4355_CHIP_ID: \ + case BCM4359_CHIP_ID + +#define BCM43602_CHIP_ID 0xaa52 /* 43602 chipcommon chipid */ +#define BCM43462_CHIP_ID 0xa9c6 /* 43462 chipcommon chipid */ + +#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */ +#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */ +#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */ +#define BCM4706_CHIP_ID 0x5300 /* 4706 chipcommon chipid */ +#define BCM4707_CHIP_ID 53010 /* 4707 chipcommon chipid */ +#define BCM53018_CHIP_ID 53018 /* 53018 chipcommon chipid */ +#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || ((chipid) == BCM53018_CHIP_ID)) +#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */ +#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */ +#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) */ +#define BCM4749_CHIP_ID 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */ +#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */ +#define BCM5350_CHIP_ID 0x5350 /* 5350 chipcommon chipid */ +#define BCM5352_CHIP_ID 0x5352 /* 5352 chipcommon chipid */ +#define BCM5354_CHIP_ID 0x5354 /* 5354 chipcommon chipid */ +#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */ +#define BCM5356_CHIP_ID 0x5356 /* 5356 chipcommon chipid */ +#define BCM5357_CHIP_ID 0x5357 /* 5357 chipcommon chipid */ +#define BCM53572_CHIP_ID 53572 /* 53572 chipcommon chipid */ + +/* Package IDs */ +#define BCM4303_PKG_ID 2 /* 4303 package id */ +#define BCM4309_PKG_ID 1 /* 4309 package id */ +#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */ +#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */ +#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */ +#define BCM4328USBD11G_PKG_ID 2 /* 4328 802.11g USB package id */ +#define BCM4328USBDUAL_PKG_ID 3 /* 4328 802.11a/g USB package id */ +#define BCM4328SDIOD11G_PKG_ID 4 /* 4328 802.11g SDIO package id */ +#define BCM4328SDIODUAL_PKG_ID 5 /* 4328 802.11a/g SDIO package id */ +#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */ +#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */ +#define BCM5354E_PKG_ID 1 /* 5354E package id */ +#define BCM4716_PKG_ID 8 /* 4716 package id */ +#define BCM4717_PKG_ID 9 /* 4717 package id */ +#define BCM4718_PKG_ID 10 /* 4718 package id */ +#define BCM5356_PKG_NONMODE 1 /* 5356 package without nmode suppport */ +#define BCM5358U_PKG_ID 8 /* 5358U package id */ +#define BCM5358_PKG_ID 9 /* 5358 package id */ +#define BCM47186_PKG_ID 10 /* 47186 package id */ +#define BCM5357_PKG_ID 11 /* 5357 package id */ +#define BCM5356U_PKG_ID 12 /* 5356U package id */ +#define BCM53572_PKG_ID 8 /* 53572 package id */ +#define BCM5357C0_PKG_ID 8 /* 5357c0 package id (the same as 53572) */ +#define BCM47188_PKG_ID 9 /* 47188 package id */ +#define BCM5358C0_PKG_ID 0xa /* 5358c0 package id */ +#define BCM5356C0_PKG_ID 0xb /* 5356c0 package id */ +#define BCM4331TT_PKG_ID 8 /* 4331 12x12 package id */ +#define BCM4331TN_PKG_ID 9 /* 4331 12x9 package id */ +#define BCM4331TNA0_PKG_ID 0xb /* 4331 12x9 package id */ +#define BCM4706L_PKG_ID 1 /* 4706L package id */ + +#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */ +#define HDLSIM_PKG_ID 14 /* HDL simulator package id */ +#define HWSIM_PKG_ID 15 /* Hardware simulator package id */ +#define BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */ +#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ +#define BCM4336_WLBGA_PKG_ID 0x8 +#define BCM4330_WLBGA_PKG_ID 0x0 +#define BCM4314PCIE_ARM_PKG_ID (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */ +#define BCM4314SDIO_PKG_ID (8 | 1) /* 4314 QFN SDIO package id */ +#define BCM4314PCIE_PKG_ID (8 | 2) /* 4314 QFN PCI (ARM-less) package id */ +#define BCM4314SDIO_ARM_PKG_ID (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */ +#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) /* 4314 FpBGA SDIO package id */ +#define BCM4314DEV_PKG_ID (8 | 6) /* 4314 Developement package id */ + +#define BCM4707_PKG_ID 1 /* 4707 package id */ +#define BCM4708_PKG_ID 2 /* 4708 package id */ +#define BCM4709_PKG_ID 0 /* 4709 package id */ + +#define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */ +#define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */ + +#define BCM4335_WLCSP_PKG_ID (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */ +#define BCM4335_FCBGA_PKG_ID (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */ +#define BCM4335_WLBGA_PKG_ID (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */ +#define BCM4335_FCBGAD_PKG_ID (0x3) /* FCBGA Debug Debug/Dev All if's. */ +#define BCM4335_PKG_MASK (0x3) + +/* boardflags */ +#define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */ +#define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */ +#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */ +#define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio 13 radio disable indication, UNUSED */ +#define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */ +#define BFL_DIS_256QAM 0x00000008 +#define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */ +#define BFL_TSSIAVG 0x00000010 /* TSSI averaging for ACPHY chips */ +#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */ +#define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */ +#define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */ +#define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */ +#define BFL_LTECOEX 0x00000200 /* LTE Coex enabled */ +#define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ +#define BFL_FEM 0x00000800 /* Board supports the Front End Module */ +#define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ +#define BFL_HGPA 0x00002000 /* Board has a high gain PA */ +#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */ +#define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */ +#define BFL_NOPA 0x00010000 /* Board has no PA */ +#define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */ +#define BFL_PAREF 0x00040000 /* Board uses the PARef LDO */ +#define BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */ +#define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */ +#define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */ +#define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */ +#define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */ +#define BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */ +#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */ +#define BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */ +#define BFL_FASTPWR 0x08000000 +#define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */ +#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ +#define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */ +#define BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ +#define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */ +#define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field + * when this flag is set + */ +#define BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */ + +/* boardflags2 */ +#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */ +#define BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ +#define BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */ +#define BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */ +#define BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */ +#define BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */ +#define BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */ +#define BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */ +#define BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace + * BFL2_BTC3WIRE + */ +#define BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */ +#define BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */ +#define BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */ +#define BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */ +#define BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ +#define BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */ +#define BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */ +#define BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */ +#define BFL2_DAC_SPUR_IMPROVEMENT 0x00008000 /* Reducing DAC Spurs */ +#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */ +#define BFL2_REDUCED_PA_TURNONTIME 0x00010000 /* Flag to reduce PA turn on Time */ +#define BFL2_IPALVLSHIFT_3P3 0x00020000 +#define BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */ +#define BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */ + /* Most drivers will turn it off without this flag */ + /* to save power. */ + +#define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */ +#define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */ +#define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */ +#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */ +#define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value + * than programmed. The exact delta is decided by + * driver per chip/boardtype. This can be used + * when tempsense qualification happens after shipment + */ +#define BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */ +#define BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */ +#define BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save */ + /* ucode control of eLNA during Tx */ +#define BFL2_4313_RADIOREG 0x10000000 + /* board rework */ +#define BFL2_DYNAMIC_VMID 0x10000000 /* enable dynamic Vmid in idle TSSI CAL for 4331 */ + +#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ +#define BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */ +#define BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */ +#define BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */ + +/* SROM 11 - 11ac boardflag definitions */ +#define BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */ +#define BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */ +#define BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ +#define BFL_SROM11_EPA_TURNON_TIME 0x00018000 /* 2 bits for different PA turn on times */ +#define BFL_SROM11_EPA_TURNON_TIME_SHIFT 15 +#define BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ +#define BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ +#define BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ +#define BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */ +#define BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */ +#define BFL2_SROM11_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ + +/* boardflags3 */ +#define BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */ +#define BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */ +#define BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */ +#define BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */ +#define BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */ +#define BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */ +#define BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */ +#define BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */ +#define BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */ +#define BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */ +#define BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */ +#define BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */ +#define BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */ +#define BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */ +#define BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */ +#define BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */ +#define BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */ +#define BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */ +#define BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */ +#define BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */ +/* acphy, to use backed off gaintbl for lte-coex */ +#define BFL3_LTECOEX_GAINTBL_EN 0x00060000 +/* acphy, to use backed off gaintbl for lte-coex */ +#define BFL3_LTECOEX_GAINTBL_EN_SHIFT 17 +#define BFL3_5G_SPUR_WAR 0x00080000 /* acphy, enable spur WAR in 5G band */ +#define BFL3_1X1_RSDB_ANT 0x01000000 /* to find if 2-ant RSDB board or 1-ant RSDB board */ +#define BFL3_1X1_RSDB_ANT_SHIFT 24 + +/* acphy: lpmode2g and lpmode_5g related boardflags */ +#define BFL3_ACPHY_LPMODE_2G 0x00300000 /* bits 20:21 for lpmode_2g choice */ +#define BFL3_ACPHY_LPMODE_2G_SHIFT 20 + +#define BFL3_ACPHY_LPMODE_5G 0x00C00000 /* bits 22:23 for lpmode_5g choice */ +#define BFL3_ACPHY_LPMODE_5G_SHIFT 22 + +#define BFL3_EXT_LPO_ISCLOCK 0x02000000 /* External LPO is clock, not x-tal */ +#define BFL3_FORCE_INT_LPO_SEL 0x04000000 /* Force internal lpo */ +#define BFL3_FORCE_EXT_LPO_SEL 0x08000000 /* Force external lpo */ + +#define BFL3_EN_BRCM_IMPBF 0x10000000 /* acphy, Allow BRCM Implicit TxBF */ +#define BFL3_AVVMID_FROM_NVRAM 0x40000000 /* Read Av Vmid from NVRAM */ +#define BFL3_VLIN_EN_FROM_NVRAM 0x80000000 /* Read Vlin En from NVRAM */ + +#define BFL3_AVVMID_FROM_NVRAM_SHIFT 30 /* Read Av Vmid from NVRAM */ +#define BFL3_VLIN_EN_FROM_NVRAM_SHIFT 31 /* Enable Vlin from NVRAM */ + + +/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */ +#define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ +#define BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */ +#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */ +#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */ +#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */ +#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */ +#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */ +#define BOARD_GPIO_12 0x1000 /* gpio 12 */ +#define BOARD_GPIO_13 0x2000 /* gpio 13 */ +#define BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */ +#define BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */ +#define BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */ +#define BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */ +#define BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */ +#define BOARD_GPIO_2_WLAN_PWR 0x04 /* throttle WLAN power on X29C board */ +#define BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */ +#define BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */ + +#define GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */ +#define GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */ +#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */ +#define GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */ +#define GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */ +#define GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */ +#define GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */ + +#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ +#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ +#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal power-up */ +#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL power-down */ + +/* power control defines */ +#define PLL_DELAY 150 /* us pll on delay */ +#define FREF_DELAY 200 /* us fref change delay */ +#define MIN_SLOW_CLK 32 /* us Slow clock period */ +#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ + + +/* 43341 Boards */ +#define BCM943341WLABGS_SSID 0x062d + +/* 43342 Boards */ +#define BCM943342FCAGBI_SSID 0x0641 + +/* 43602 Boards, unclear yet what boards will be created. */ +#define BCM943602RSVD1_SSID 0x06a5 +#define BCM943602RSVD2_SSID 0x06a6 +#define BCM943602X87 0X0133 +#define BCM943602X238 0X0132 + +/* # of GPIO pins */ +#define GPIO_NUMPINS 32 + +/* These values are used by dhd host driver. */ +#define RDL_RAM_BASE_4319 0x60000000 +#define RDL_RAM_BASE_4329 0x60000000 +#define RDL_RAM_SIZE_4319 0x48000 +#define RDL_RAM_SIZE_4329 0x48000 +#define RDL_RAM_SIZE_43236 0x70000 +#define RDL_RAM_BASE_43236 0x60000000 +#define RDL_RAM_SIZE_4328 0x60000 +#define RDL_RAM_BASE_4328 0x80000000 +#define RDL_RAM_SIZE_4322 0x60000 +#define RDL_RAM_BASE_4322 0x60000000 +#define RDL_RAM_SIZE_4360 0xA0000 +#define RDL_RAM_BASE_4360 0x60000000 +#define RDL_RAM_SIZE_43242 0x90000 +#define RDL_RAM_BASE_43242 0x60000000 +#define RDL_RAM_SIZE_43143 0x70000 +#define RDL_RAM_BASE_43143 0x60000000 +#define RDL_RAM_SIZE_4350 0xC0000 +#define RDL_RAM_BASE_4350 0x180800 + +/* generic defs for nvram "muxenab" bits +* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options. +*/ +#define MUXENAB_UART 0x00000001 +#define MUXENAB_GPIO 0x00000002 +#define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */ +#define MUXENAB_JTAG 0x00000008 +#define MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */ +#define MUXENAB_I2S_EN 0x00000020 +#define MUXENAB_I2S_MASTER 0x00000040 +#define MUXENAB_I2S_FULL 0x00000080 +#define MUXENAB_SFLASH 0x00000100 +#define MUXENAB_RFSWCTRL0 0x00000200 +#define MUXENAB_RFSWCTRL1 0x00000400 +#define MUXENAB_RFSWCTRL2 0x00000800 +#define MUXENAB_SECI 0x00001000 +#define MUXENAB_BT_LEGACY 0x00002000 +#define MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */ + +/* Boot flags */ +#define FLASH_KERNEL_NFLASH 0x00000001 +#define FLASH_BOOT_NFLASH 0x00000002 + +#endif /* _BCMDEVS_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmendian.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmendian.h new file mode 100644 index 000000000000..970989e38f6b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmendian.h @@ -0,0 +1,329 @@ +/* + * Byte order utilities + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmendian.h 402715 2013-05-16 18:50:09Z $ + * + * This file by default provides proper behavior on little-endian architectures. + * On big-endian architectures, IL_BIGENDIAN should be defined. + */ + +#ifndef _BCMENDIAN_H_ +#define _BCMENDIAN_H_ + +#include + +/* Reverse the bytes in a 16-bit value */ +#define BCMSWAP16(val) \ + ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ + (((uint16)(val) & (uint16)0xff00U) >> 8))) + +/* Reverse the bytes in a 32-bit value */ +#define BCMSWAP32(val) \ + ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ + (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ + (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ + (((uint32)(val) & (uint32)0xff000000U) >> 24))) + +/* Reverse the two 16-bit halves of a 32-bit value */ +#define BCMSWAP32BY16(val) \ + ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ + (((uint32)(val) & (uint32)0xffff0000U) >> 16))) + +/* Reverse the bytes in a 64-bit value */ +#define BCMSWAP64(val) \ + ((uint64)((((uint64)(val) & 0x00000000000000ffULL) << 56) | \ + (((uint64)(val) & 0x000000000000ff00ULL) << 40) | \ + (((uint64)(val) & 0x0000000000ff0000ULL) << 24) | \ + (((uint64)(val) & 0x00000000ff000000ULL) << 8) | \ + (((uint64)(val) & 0x000000ff00000000ULL) >> 8) | \ + (((uint64)(val) & 0x0000ff0000000000ULL) >> 24) | \ + (((uint64)(val) & 0x00ff000000000000ULL) >> 40) | \ + (((uint64)(val) & 0xff00000000000000ULL) >> 56))) + +/* Reverse the two 32-bit halves of a 64-bit value */ +#define BCMSWAP64BY32(val) \ + ((uint64)((((uint64)(val) & 0x00000000ffffffffULL) << 32) | \ + (((uint64)(val) & 0xffffffff00000000ULL) >> 32))) + + +/* Byte swapping macros + * Host <=> Network (Big Endian) for 16- and 32-bit values + * Host <=> Little-Endian for 16- and 32-bit values + */ +#ifndef hton16 +#define HTON16(i) BCMSWAP16(i) +#define hton16(i) bcmswap16(i) +#define HTON32(i) BCMSWAP32(i) +#define hton32(i) bcmswap32(i) +#define NTOH16(i) BCMSWAP16(i) +#define ntoh16(i) bcmswap16(i) +#define NTOH32(i) BCMSWAP32(i) +#define ntoh32(i) bcmswap32(i) +#define LTOH16(i) (i) +#define ltoh16(i) (i) +#define LTOH32(i) (i) +#define ltoh32(i) (i) +#define HTOL16(i) (i) +#define htol16(i) (i) +#define HTOL32(i) (i) +#define htol32(i) (i) +#define HTOL64(i) (i) +#define htol64(i) (i) +#endif /* hton16 */ + +#define ltoh16_buf(buf, i) +#define htol16_buf(buf, i) + +/* Unaligned loads and stores in host byte order */ +#define load32_ua(a) ltoh32_ua(a) +#define store32_ua(a, v) htol32_ua_store(v, a) +#define load16_ua(a) ltoh16_ua(a) +#define store16_ua(a, v) htol16_ua_store(v, a) + +#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) +#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) +#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) +#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) + +#define ltoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#define ntoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#ifdef __GNUC__ + +/* GNU macro versions avoid referencing the argument multiple times, while also + * avoiding the -fno-inline used in ROM builds. + */ + +#define bcmswap16(val) ({ \ + uint16 _val = (val); \ + BCMSWAP16(_val); \ +}) + +#define bcmswap32(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32(_val); \ +}) + +#define bcmswap64(val) ({ \ + uint64 _val = (val); \ + BCMSWAP64(_val); \ +}) + +#define bcmswap32by16(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32BY16(_val); \ +}) + +#define bcmswap16_buf(buf, len) ({ \ + uint16 *_buf = (uint16 *)(buf); \ + uint _wds = (len) / 2; \ + while (_wds--) { \ + *_buf = bcmswap16(*_buf); \ + _buf++; \ + } \ +}) + +#define htol16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = _val >> 8; \ +}) + +#define htol32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = (_val >> 8) & 0xff; \ + _bytes[2] = (_val >> 16) & 0xff; \ + _bytes[3] = _val >> 24; \ +}) + +#define hton16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 8; \ + _bytes[1] = _val & 0xff; \ +}) + +#define hton32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 24; \ + _bytes[1] = (_val >> 16) & 0xff; \ + _bytes[2] = (_val >> 8) & 0xff; \ + _bytes[3] = _val & 0xff; \ +}) + +#define ltoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH16_UA(_bytes); \ +}) + +#define ltoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH32_UA(_bytes); \ +}) + +#define ntoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH16_UA(_bytes); \ +}) + +#define ntoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH32_UA(_bytes); \ +}) + +#else /* !__GNUC__ */ + +/* Inline versions avoid referencing the argument multiple times */ +static INLINE uint16 +bcmswap16(uint16 val) +{ + return BCMSWAP16(val); +} + +static INLINE uint32 +bcmswap32(uint32 val) +{ + return BCMSWAP32(val); +} + +static INLINE uint64 +bcmswap64(uint64 val) +{ + return BCMSWAP64(val); +} + +static INLINE uint32 +bcmswap32by16(uint32 val) +{ + return BCMSWAP32BY16(val); +} + +/* Reverse pairs of bytes in a buffer (not for high-performance use) */ +/* buf - start of buffer of shorts to swap */ +/* len - byte length of buffer */ +static INLINE void +bcmswap16_buf(uint16 *buf, uint len) +{ + len = len / 2; + + while (len--) { + *buf = bcmswap16(*buf); + buf++; + } +} + +/* + * Store 16-bit value to unaligned little-endian byte array. + */ +static INLINE void +htol16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[0] = val & 0xff; + bytes[1] = val >> 8; +} + +/* + * Store 32-bit value to unaligned little-endian byte array. + */ +static INLINE void +htol32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[0] = val & 0xff; + bytes[1] = (val >> 8) & 0xff; + bytes[2] = (val >> 16) & 0xff; + bytes[3] = val >> 24; +} + +/* + * Store 16-bit value to unaligned network-(big-)endian byte array. + */ +static INLINE void +hton16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[0] = val >> 8; + bytes[1] = val & 0xff; +} + +/* + * Store 32-bit value to unaligned network-(big-)endian byte array. + */ +static INLINE void +hton32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[0] = val >> 24; + bytes[1] = (val >> 16) & 0xff; + bytes[2] = (val >> 8) & 0xff; + bytes[3] = val & 0xff; +} + +/* + * Load 16-bit value from unaligned little-endian byte array. + */ +static INLINE uint16 +ltoh16_ua(const void *bytes) +{ + return _LTOH16_UA((const uint8 *)bytes); +} + +/* + * Load 32-bit value from unaligned little-endian byte array. + */ +static INLINE uint32 +ltoh32_ua(const void *bytes) +{ + return _LTOH32_UA((const uint8 *)bytes); +} + +/* + * Load 16-bit value from unaligned big-(network-)endian byte array. + */ +static INLINE uint16 +ntoh16_ua(const void *bytes) +{ + return _NTOH16_UA((const uint8 *)bytes); +} + +/* + * Load 32-bit value from unaligned big-(network-)endian byte array. + */ +static INLINE uint32 +ntoh32_ua(const void *bytes) +{ + return _NTOH32_UA((const uint8 *)bytes); +} + +#endif /* !__GNUC__ */ +#endif /* !_BCMENDIAN_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmmsgbuf.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmmsgbuf.h new file mode 100644 index 000000000000..45ed9a3d846a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmmsgbuf.h @@ -0,0 +1,749 @@ +/* + * MSGBUF network driver ioctl/indication encoding + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmmsgbuf.h 542258 2015-03-19 07:55:03Z $ + */ +#ifndef _bcmmsgbuf_h_ +#define _bcmmsgbuf_h_ +#include +#include +#include + +#define MSGBUF_MAX_MSG_SIZE ETHER_MAX_LEN + +#define D2H_EPOCH_MODULO 253 /* sequence number wrap */ +#define D2H_EPOCH_INIT_VAL (D2H_EPOCH_MODULO + 1) + +#define H2DRING_TXPOST_ITEMSIZE 48 +#define H2DRING_RXPOST_ITEMSIZE 32 +#define H2DRING_CTRL_SUB_ITEMSIZE 40 +#define D2HRING_TXCMPLT_ITEMSIZE 16 +#define D2HRING_RXCMPLT_ITEMSIZE 32 +#define D2HRING_CTRL_CMPLT_ITEMSIZE 24 + +#define H2DRING_TXPOST_MAX_ITEM 512 +#define H2DRING_RXPOST_MAX_ITEM 256 +#define H2DRING_CTRL_SUB_MAX_ITEM 128 +#define D2HRING_TXCMPLT_MAX_ITEM 1024 +#define D2HRING_RXCMPLT_MAX_ITEM 256 +#define D2HRING_CTRL_CMPLT_MAX_ITEM 128 +enum { + DNGL_TO_HOST_MSGBUF, + HOST_TO_DNGL_MSGBUF +}; + +enum { + HOST_TO_DNGL_TXP_DATA, + HOST_TO_DNGL_RXP_DATA, + HOST_TO_DNGL_CTRL, + DNGL_TO_HOST_DATA, + DNGL_TO_HOST_CTRL +}; + +#define MESSAGE_PAYLOAD(a) (a & MSG_TYPE_INTERNAL_USE_START) ? TRUE : FALSE + +#ifdef PCIE_API_REV1 + +#define BCMMSGBUF_DUMMY_REF(a, b) do {BCM_REFERENCE((a));BCM_REFERENCE((b));} while (0) + +#define BCMMSGBUF_API_IFIDX(a) 0 +#define BCMMSGBUF_API_SEQNUM(a) 0 +#define BCMMSGBUF_IOCTL_XTID(a) 0 +#define BCMMSGBUF_IOCTL_PKTID(a) ((a)->cmd_id) + +#define BCMMSGBUF_SET_API_IFIDX(a, b) BCMMSGBUF_DUMMY_REF(a, b) +#define BCMMSGBUF_SET_API_SEQNUM(a, b) BCMMSGBUF_DUMMY_REF(a, b) +#define BCMMSGBUF_IOCTL_SET_PKTID(a, b) (BCMMSGBUF_IOCTL_PKTID(a) = (b)) +#define BCMMSGBUF_IOCTL_SET_XTID(a, b) BCMMSGBUF_DUMMY_REF(a, b) + +#else /* PCIE_API_REV1 */ + +#define BCMMSGBUF_API_IFIDX(a) ((a)->if_id) +#define BCMMSGBUF_IOCTL_PKTID(a) ((a)->pkt_id) +#define BCMMSGBUF_API_SEQNUM(a) ((a)->u.seq.seq_no) +#define BCMMSGBUF_IOCTL_XTID(a) ((a)->xt_id) + +#define BCMMSGBUF_SET_API_IFIDX(a, b) (BCMMSGBUF_API_IFIDX((a)) = (b)) +#define BCMMSGBUF_SET_API_SEQNUM(a, b) (BCMMSGBUF_API_SEQNUM((a)) = (b)) +#define BCMMSGBUF_IOCTL_SET_PKTID(a, b) (BCMMSGBUF_IOCTL_PKTID((a)) = (b)) +#define BCMMSGBUF_IOCTL_SET_XTID(a, b) (BCMMSGBUF_IOCTL_XTID((a)) = (b)) + +#endif /* PCIE_API_REV1 */ + +/* utility data structures */ +union addr64 { + struct { + uint32 low; + uint32 high; + }; + struct { + uint32 low_addr; + uint32 high_addr; + }; + uint64 u64; +} DECLSPEC_ALIGN(8); + +typedef union addr64 addr64_t; + +/* IOCTL req Hdr */ +/* cmn Msg Hdr */ +typedef struct cmn_msg_hdr { + /* message type */ + uint8 msg_type; + /* interface index this is valid for */ + uint8 if_id; + /* flags */ + uint8 flags; + /* sequence number */ + uint8 epoch; + /* packet Identifier for the associated host buffer */ + uint32 request_id; +} cmn_msg_hdr_t; + +/* message type */ +typedef enum bcmpcie_msgtype { + MSG_TYPE_GEN_STATUS = 0x1, + MSG_TYPE_RING_STATUS = 0x2, + MSG_TYPE_FLOW_RING_CREATE = 0x3, + MSG_TYPE_FLOW_RING_CREATE_CMPLT = 0x4, + MSG_TYPE_FLOW_RING_DELETE = 0x5, + MSG_TYPE_FLOW_RING_DELETE_CMPLT = 0x6, + MSG_TYPE_FLOW_RING_FLUSH = 0x7, + MSG_TYPE_FLOW_RING_FLUSH_CMPLT = 0x8, + MSG_TYPE_IOCTLPTR_REQ = 0x9, + MSG_TYPE_IOCTLPTR_REQ_ACK = 0xA, + MSG_TYPE_IOCTLRESP_BUF_POST = 0xB, + MSG_TYPE_IOCTL_CMPLT = 0xC, + MSG_TYPE_EVENT_BUF_POST = 0xD, + MSG_TYPE_WL_EVENT = 0xE, + MSG_TYPE_TX_POST = 0xF, + MSG_TYPE_TX_STATUS = 0x10, + MSG_TYPE_RXBUF_POST = 0x11, + MSG_TYPE_RX_CMPLT = 0x12, + MSG_TYPE_LPBK_DMAXFER = 0x13, + MSG_TYPE_LPBK_DMAXFER_CMPLT = 0x14, + MSG_TYPE_API_MAX_RSVD = 0x3F +} bcmpcie_msg_type_t; + +typedef enum bcmpcie_msgtype_int { + MSG_TYPE_INTERNAL_USE_START = 0x40, + MSG_TYPE_EVENT_PYLD = 0x41, + MSG_TYPE_IOCT_PYLD = 0x42, + MSG_TYPE_RX_PYLD = 0x43, + MSG_TYPE_HOST_FETCH = 0x44, + MSG_TYPE_LPBK_DMAXFER_PYLD = 0x45, + MSG_TYPE_TXMETADATA_PYLD = 0x46, + MSG_TYPE_HOSTDMA_PTRS = 0x47 +} bcmpcie_msgtype_int_t; + +typedef enum bcmpcie_msgtype_u { + MSG_TYPE_TX_BATCH_POST = 0x80, + MSG_TYPE_IOCTL_REQ = 0x81, + MSG_TYPE_HOST_EVNT = 0x82, + MSG_TYPE_LOOPBACK = 0x83 +} bcmpcie_msgtype_u_t; + + +/* if_id */ +#define BCMPCIE_CMNHDR_IFIDX_PHYINTF_SHFT 5 +#define BCMPCIE_CMNHDR_IFIDX_PHYINTF_MAX 0x7 +#define BCMPCIE_CMNHDR_IFIDX_PHYINTF_MASK \ + (BCMPCIE_CMNHDR_IFIDX_PHYINTF_MAX << BCMPCIE_CMNHDR_IFIDX_PHYINTF_SHFT) +#define BCMPCIE_CMNHDR_IFIDX_VIRTINTF_SHFT 0 +#define BCMPCIE_CMNHDR_IFIDX_VIRTINTF_MAX 0x1F +#define BCMPCIE_CMNHDR_IFIDX_VIRTINTF_MASK \ + (BCMPCIE_CMNHDR_IFIDX_PHYINTF_MAX << BCMPCIE_CMNHDR_IFIDX_PHYINTF_SHFT) + +/* flags */ +#define BCMPCIE_CMNHDR_FLAGS_DMA_R_IDX 0x1 +#define BCMPCIE_CMNHDR_FLAGS_DMA_R_IDX_INTR 0x2 +#define BCMPCIE_CMNHDR_FLAGS_PHASE_BIT 0x80 + + +/* IOCTL request message */ +typedef struct ioctl_req_msg { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + + /* ioctl command type */ + uint32 cmd; + /* ioctl transaction ID, to pair with a ioctl response */ + uint16 trans_id; + /* input arguments buffer len */ + uint16 input_buf_len; + /* expected output len */ + uint16 output_buf_len; + /* to aling the host address on 8 byte boundary */ + uint16 rsvd[3]; + /* always aling on 8 byte boundary */ + addr64_t host_input_buf_addr; + /* rsvd */ + uint32 rsvd1[2]; +} ioctl_req_msg_t; + +/* buffer post messages for device to use to return IOCTL responses, Events */ +typedef struct ioctl_resp_evt_buf_post_msg { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* length of the host buffer supplied */ + uint16 host_buf_len; + /* to aling the host address on 8 byte boundary */ + uint16 reserved[3]; + /* always aling on 8 byte boundary */ + addr64_t host_buf_addr; + uint32 rsvd[4]; +} ioctl_resp_evt_buf_post_msg_t; + + +typedef struct pcie_dma_xfer_params { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + + /* always aling on 8 byte boundary */ + addr64_t host_input_buf_addr; + + /* always aling on 8 byte boundary */ + addr64_t host_ouput_buf_addr; + + /* length of transfer */ + uint32 xfer_len; + /* delay before doing the src txfer */ + uint32 srcdelay; + /* delay before doing the dest txfer */ + uint32 destdelay; + uint32 rsvd; +} pcie_dma_xfer_params_t; + +/* Complete msgbuf hdr for flow ring update from host to dongle */ +typedef struct tx_flowring_create_request { + cmn_msg_hdr_t msg; + uint8 da[ETHER_ADDR_LEN]; + uint8 sa[ETHER_ADDR_LEN]; + uint8 tid; + uint8 if_flags; + uint16 flow_ring_id; + uint8 tc; + uint8 priority; + uint16 int_vector; + uint16 max_items; + uint16 len_item; + addr64_t flow_ring_ptr; +} tx_flowring_create_request_t; + +typedef struct tx_flowring_delete_request { + cmn_msg_hdr_t msg; + uint16 flow_ring_id; + uint16 reason; + uint32 rsvd[7]; +} tx_flowring_delete_request_t; + +typedef struct tx_flowring_flush_request { + cmn_msg_hdr_t msg; + uint16 flow_ring_id; + uint16 reason; + uint32 rsvd[7]; +} tx_flowring_flush_request_t; + +typedef union ctrl_submit_item { + ioctl_req_msg_t ioctl_req; + ioctl_resp_evt_buf_post_msg_t resp_buf_post; + pcie_dma_xfer_params_t dma_xfer; + tx_flowring_create_request_t flow_create; + tx_flowring_delete_request_t flow_delete; + tx_flowring_flush_request_t flow_flush; + unsigned char check[H2DRING_CTRL_SUB_ITEMSIZE]; +} ctrl_submit_item_t; + +/* Control Completion messages (20 bytes) */ +typedef struct compl_msg_hdr { + /* status for the completion */ + int16 status; + /* submisison flow ring id which generated this status */ + uint16 flow_ring_id; +} compl_msg_hdr_t; + +/* XOR checksum or a magic number to audit DMA done */ +typedef uint32 dma_done_t; + +/* completion header status codes */ +#define BCMPCIE_SUCCESS 0 +#define BCMPCIE_NOTFOUND 1 +#define BCMPCIE_NOMEM 2 +#define BCMPCIE_BADOPTION 3 +#define BCMPCIE_RING_IN_USE 4 +#define BCMPCIE_RING_ID_INVALID 5 +#define BCMPCIE_PKT_FLUSH 6 +#define BCMPCIE_NO_EVENT_BUF 7 +#define BCMPCIE_NO_RX_BUF 8 +#define BCMPCIE_NO_IOCTLRESP_BUF 9 +#define BCMPCIE_MAX_IOCTLRESP_BUF 10 +#define BCMPCIE_MAX_EVENT_BUF 11 + +/* IOCTL completion response */ +typedef struct ioctl_compl_resp_msg { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* completion message header */ + compl_msg_hdr_t compl_hdr; + /* response buffer len where a host buffer is involved */ + uint16 resp_len; + /* transaction id to pair with a request */ + uint16 trans_id; + /* cmd id */ + uint32 cmd; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} ioctl_comp_resp_msg_t; + +/* IOCTL request acknowledgement */ +typedef struct ioctl_req_ack_msg { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* completion message header */ + compl_msg_hdr_t compl_hdr; + /* cmd id */ + uint32 cmd; + uint32 rsvd[1]; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} ioctl_req_ack_msg_t; + +/* WL event message: send from device to host */ +typedef struct wlevent_req_msg { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* completion message header */ + compl_msg_hdr_t compl_hdr; + /* event data len valid with the event buffer */ + uint16 event_data_len; + /* sequence number */ + uint16 seqnum; + /* rsvd */ + uint32 rsvd; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} wlevent_req_msg_t; + +/* dma xfer complete message */ +typedef struct pcie_dmaxfer_cmplt { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* completion message header */ + compl_msg_hdr_t compl_hdr; + uint32 rsvd[2]; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} pcie_dmaxfer_cmplt_t; + +/* general status message */ +typedef struct pcie_gen_status { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* completion message header */ + compl_msg_hdr_t compl_hdr; + uint32 rsvd[2]; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} pcie_gen_status_t; + +/* ring status message */ +typedef struct pcie_ring_status { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* completion message header */ + compl_msg_hdr_t compl_hdr; + /* message which firmware couldn't decode */ + uint16 write_idx; + uint16 rsvd[3]; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} pcie_ring_status_t; + +typedef struct tx_flowring_create_response { + cmn_msg_hdr_t msg; + compl_msg_hdr_t cmplt; + uint32 rsvd[2]; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} tx_flowring_create_response_t; +typedef struct tx_flowring_delete_response { + cmn_msg_hdr_t msg; + compl_msg_hdr_t cmplt; + uint32 rsvd[2]; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} tx_flowring_delete_response_t; + +typedef struct tx_flowring_flush_response { + cmn_msg_hdr_t msg; + compl_msg_hdr_t cmplt; + uint32 rsvd[2]; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} tx_flowring_flush_response_t; + +/* Common layout of all d2h control messages */ +typedef struct ctrl_compl_msg { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* completion message header */ + compl_msg_hdr_t compl_hdr; + uint32 rsvd[2]; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} ctrl_compl_msg_t; + +typedef union ctrl_completion_item { + ioctl_comp_resp_msg_t ioctl_resp; + wlevent_req_msg_t event; + ioctl_req_ack_msg_t ioct_ack; + pcie_dmaxfer_cmplt_t pcie_xfer_cmplt; + pcie_gen_status_t pcie_gen_status; + pcie_ring_status_t pcie_ring_status; + tx_flowring_create_response_t txfl_create_resp; + tx_flowring_delete_response_t txfl_delete_resp; + tx_flowring_flush_response_t txfl_flush_resp; + ctrl_compl_msg_t ctrl_compl; + unsigned char check[D2HRING_CTRL_CMPLT_ITEMSIZE]; +} ctrl_completion_item_t; + +/* H2D Rxpost ring work items */ +typedef struct host_rxbuf_post { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* provided meta data buffer len */ + uint16 metadata_buf_len; + /* provided data buffer len to receive data */ + uint16 data_buf_len; + /* alignment to make the host buffers start on 8 byte boundary */ + uint32 rsvd; + /* provided meta data buffer */ + addr64_t metadata_buf_addr; + /* provided data buffer to receive data */ + addr64_t data_buf_addr; +} host_rxbuf_post_t; + +typedef union rxbuf_submit_item { + host_rxbuf_post_t rxpost; + unsigned char check[H2DRING_RXPOST_ITEMSIZE]; +} rxbuf_submit_item_t; + + +/* D2H Rxcompletion ring work items */ +typedef struct host_rxbuf_cmpl { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* completion message header */ + compl_msg_hdr_t compl_hdr; + /* filled up meta data len */ + uint16 metadata_len; + /* filled up buffer len to receive data */ + uint16 data_len; + /* offset in the host rx buffer where the data starts */ + uint16 data_offset; + /* offset in the host rx buffer where the data starts */ + uint16 flags; + /* rx status */ + uint32 rx_status_0; + uint32 rx_status_1; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; +} host_rxbuf_cmpl_t; + +typedef union rxbuf_complete_item { + host_rxbuf_cmpl_t rxcmpl; + unsigned char check[D2HRING_RXCMPLT_ITEMSIZE]; +} rxbuf_complete_item_t; + + +typedef struct host_txbuf_post { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* eth header */ + uint8 txhdr[ETHER_HDR_LEN]; + /* flags */ + uint8 flags; + /* number of segments */ + uint8 seg_cnt; + + /* provided meta data buffer for txstatus */ + addr64_t metadata_buf_addr; + /* provided data buffer to receive data */ + addr64_t data_buf_addr; + /* provided meta data buffer len */ + uint16 metadata_buf_len; + /* provided data buffer len to receive data */ + uint16 data_len; + uint32 flag2; +} host_txbuf_post_t; + +#define BCMPCIE_PKT_FLAGS_FRAME_802_3 0x01 +#define BCMPCIE_PKT_FLAGS_FRAME_802_11 0x02 + +#define BCMPCIE_PKT_FLAGS_FRAME_EXEMPT_MASK 0x03 /* Exempt uses 2 bits */ +#define BCMPCIE_PKT_FLAGS_FRAME_EXEMPT_SHIFT 0x02 /* needs to be shifted past other bits */ + + +#define BCMPCIE_PKT_FLAGS_PRIO_SHIFT 5 +#define BCMPCIE_PKT_FLAGS_PRIO_MASK (7 << BCMPCIE_PKT_FLAGS_PRIO_SHIFT) + +/* These are added to fix up teh compile issues */ +#define BCMPCIE_TXPOST_FLAGS_FRAME_802_3 BCMPCIE_PKT_FLAGS_FRAME_802_3 +#define BCMPCIE_TXPOST_FLAGS_FRAME_802_11 BCMPCIE_PKT_FLAGS_FRAME_802_11 +#define BCMPCIE_TXPOST_FLAGS_PRIO_SHIFT BCMPCIE_PKT_FLAGS_PRIO_SHIFT +#define BCMPCIE_TXPOST_FLAGS_PRIO_MASK BCMPCIE_PKT_FLAGS_PRIO_MASK + +#define BCMPCIE_PKT_FLAGS2_FORCELOWRATE_MASK 0x01 +#define BCMPCIE_PKT_FLAGS2_FORCELOWRATE_SHIFT 0 + +/* H2D Txpost ring work items */ +typedef union txbuf_submit_item { + host_txbuf_post_t txpost; + unsigned char check[H2DRING_TXPOST_ITEMSIZE]; +} txbuf_submit_item_t; + +/* D2H Txcompletion ring work items */ +typedef struct host_txbuf_cmpl { + /* common message header */ + cmn_msg_hdr_t cmn_hdr; + /* completion message header */ + compl_msg_hdr_t compl_hdr; + union { + struct { + /* provided meta data len */ + uint16 metadata_len; + /* WLAN side txstatus */ + uint16 tx_status; + }; + /* XOR checksum or a magic number to audit DMA done */ + dma_done_t marker; + }; +} host_txbuf_cmpl_t; + +typedef union txbuf_complete_item { + host_txbuf_cmpl_t txcmpl; + unsigned char check[D2HRING_TXCMPLT_ITEMSIZE]; +} txbuf_complete_item_t; + +#define BCMPCIE_D2H_METADATA_HDRLEN 4 +#define BCMPCIE_D2H_METADATA_MINLEN (BCMPCIE_D2H_METADATA_HDRLEN + 4) + +/* ret buf struct */ +typedef struct ret_buf_ptr { + uint32 low_addr; + uint32 high_addr; +} ret_buf_t; + +#ifdef PCIE_API_REV1 +/* ioctl specific hdr */ +typedef struct ioctl_hdr { + uint16 cmd; + uint16 retbuf_len; + uint32 cmd_id; +} ioctl_hdr_t; +typedef struct ioctlptr_hdr { + uint16 cmd; + uint16 retbuf_len; + uint16 buflen; + uint16 rsvd; + uint32 cmd_id; +} ioctlptr_hdr_t; +#else /* PCIE_API_REV1 */ +typedef struct ioctl_req_hdr { + uint32 pkt_id; /* Packet ID */ + uint32 cmd; /* IOCTL ID */ + uint16 retbuf_len; + uint16 buflen; + uint16 xt_id; /* transaction ID */ + uint16 rsvd[1]; +} ioctl_req_hdr_t; +#endif /* PCIE_API_REV1 */ + + +/* Complete msgbuf hdr for ioctl from host to dongle */ +typedef struct ioct_reqst_hdr { + cmn_msg_hdr_t msg; +#ifdef PCIE_API_REV1 + ioctl_hdr_t ioct_hdr; +#else + ioctl_req_hdr_t ioct_hdr; +#endif + ret_buf_t ret_buf; +} ioct_reqst_hdr_t; +typedef struct ioctptr_reqst_hdr { + cmn_msg_hdr_t msg; +#ifdef PCIE_API_REV1 + ioctlptr_hdr_t ioct_hdr; +#else + ioctl_req_hdr_t ioct_hdr; +#endif + ret_buf_t ret_buf; + ret_buf_t ioct_buf; +} ioctptr_reqst_hdr_t; + +/* ioctl response header */ +typedef struct ioct_resp_hdr { + cmn_msg_hdr_t msg; +#ifdef PCIE_API_REV1 + uint32 cmd_id; +#else + uint32 pkt_id; +#endif + uint32 status; + uint32 ret_len; + uint32 inline_data; +#ifdef PCIE_API_REV1 +#else + uint16 xt_id; /* transaction ID */ + uint16 rsvd[1]; +#endif +} ioct_resp_hdr_t; + +/* ioct resp header used in dongle */ +/* ret buf hdr will be stripped off inside dongle itself */ +typedef struct msgbuf_ioctl_resp { + ioct_resp_hdr_t ioct_hdr; + ret_buf_t ret_buf; /* ret buf pointers */ +} msgbuf_ioct_resp_t; + +/* WL evet hdr info */ +typedef struct wl_event_hdr { + cmn_msg_hdr_t msg; + uint16 event; + uint8 flags; + uint8 rsvd; + uint16 retbuf_len; + uint16 rsvd1; + uint32 rxbufid; +} wl_event_hdr_t; + +#define TXDESCR_FLOWID_PCIELPBK_1 0xFF +#define TXDESCR_FLOWID_PCIELPBK_2 0xFE + +typedef struct txbatch_lenptr_tup { + uint32 pktid; + uint16 pktlen; + uint16 rsvd; + ret_buf_t ret_buf; /* ret buf pointers */ +} txbatch_lenptr_tup_t; + +typedef struct txbatch_cmn_msghdr { + cmn_msg_hdr_t msg; + uint8 priority; + uint8 hdrlen; + uint8 pktcnt; + uint8 flowid; + uint8 txhdr[ETHER_HDR_LEN]; + uint16 rsvd; +} txbatch_cmn_msghdr_t; + +typedef struct txbatch_msghdr { + txbatch_cmn_msghdr_t txcmn; + txbatch_lenptr_tup_t tx_tup[0]; /* Based on packet count */ +} txbatch_msghdr_t; + +/* TX desc posting header */ +typedef struct tx_lenptr_tup { + uint16 pktlen; + uint16 rsvd; + ret_buf_t ret_buf; /* ret buf pointers */ +} tx_lenptr_tup_t; + +typedef struct txdescr_cmn_msghdr { + cmn_msg_hdr_t msg; + uint8 priority; + uint8 hdrlen; + uint8 descrcnt; + uint8 flowid; + uint32 pktid; +} txdescr_cmn_msghdr_t; + +typedef struct txdescr_msghdr { + txdescr_cmn_msghdr_t txcmn; + uint8 txhdr[ETHER_HDR_LEN]; + uint16 rsvd; + tx_lenptr_tup_t tx_tup[0]; /* Based on descriptor count */ +} txdescr_msghdr_t; + +/* Tx status header info */ +typedef struct txstatus_hdr { + cmn_msg_hdr_t msg; + uint32 pktid; +} txstatus_hdr_t; +/* RX bufid-len-ptr tuple */ +typedef struct rx_lenptr_tup { + uint32 rxbufid; + uint16 len; + uint16 rsvd2; + ret_buf_t ret_buf; /* ret buf pointers */ +} rx_lenptr_tup_t; +/* Rx descr Post hdr info */ +typedef struct rxdesc_msghdr { + cmn_msg_hdr_t msg; + uint16 rsvd0; + uint8 rsvd1; + uint8 descnt; + rx_lenptr_tup_t rx_tup[0]; +} rxdesc_msghdr_t; + +/* RX complete tuples */ +typedef struct rxcmplt_tup { + uint16 retbuf_len; + uint16 data_offset; + uint32 rxstatus0; + uint32 rxstatus1; + uint32 rxbufid; +} rxcmplt_tup_t; +/* RX complete messge hdr */ +typedef struct rxcmplt_hdr { + cmn_msg_hdr_t msg; + uint16 rsvd0; + uint16 rxcmpltcnt; + rxcmplt_tup_t rx_tup[0]; +} rxcmplt_hdr_t; +typedef struct hostevent_hdr { + cmn_msg_hdr_t msg; + uint32 evnt_pyld; +} hostevent_hdr_t; + +typedef struct dma_xfer_params { + uint32 src_physaddr_hi; + uint32 src_physaddr_lo; + uint32 dest_physaddr_hi; + uint32 dest_physaddr_lo; + uint32 len; + uint32 srcdelay; + uint32 destdelay; +} dma_xfer_params_t; + +enum { + HOST_EVENT_CONS_CMD = 1 +}; + +/* defines for flags */ +#define MSGBUF_IOC_ACTION_MASK 0x1 + +#endif /* _bcmmsgbuf_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmnvram.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmnvram.h new file mode 100644 index 000000000000..3fbc303bd528 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmnvram.h @@ -0,0 +1,272 @@ +/* + * NVRAM variable manipulation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmnvram.h 428512 2013-10-09 02:12:11Z $ + */ + +#ifndef _bcmnvram_h_ +#define _bcmnvram_h_ + +#ifndef _LANGUAGE_ASSEMBLY + +#include +#include + +struct nvram_header { + uint32 magic; + uint32 len; + uint32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ + uint32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ + uint32 config_ncdl; /* ncdl values for memc */ +}; + +struct nvram_tuple { + char *name; + char *value; + struct nvram_tuple *next; +}; + +/* + * Get default value for an NVRAM variable + */ +extern char *nvram_default_get(const char *name); +/* + * validate/restore all per-interface related variables + */ +extern void nvram_validate_all(char *prefix, bool restore); + +/* + * restore specific per-interface variable + */ +extern void nvram_restore_var(char *prefix, char *name); + +/* + * Initialize NVRAM access. May be unnecessary or undefined on certain + * platforms. + */ +extern int nvram_init(void *sih); +extern int nvram_deinit(void *sih); + + +/* + * Append a chunk of nvram variables to the global list + */ +extern int nvram_append(void *si, char *vars, uint varsz); + +extern void nvram_get_global_vars(char **varlst, uint *varsz); + + +/* + * Check for reset button press for restoring factory defaults. + */ +extern int nvram_reset(void *sih); + +/* + * Disable NVRAM access. May be unnecessary or undefined on certain + * platforms. + */ +extern void nvram_exit(void *sih); + +/* + * Get the value of an NVRAM variable. The pointer returned may be + * invalid after a set. + * @param name name of variable to get + * @return value of variable or NULL if undefined + */ +extern char * nvram_get(const char *name); + +/* + * Read the reset GPIO value from the nvram and set the GPIO + * as input + */ +extern int nvram_resetgpio_init(void *sih); + +/* + * Get the value of an NVRAM variable. + * @param name name of variable to get + * @return value of variable or NUL if undefined + */ +static INLINE char * +nvram_safe_get(const char *name) +{ + char *p = nvram_get(name); + return p ? p : ""; +} + +/* + * Match an NVRAM variable. + * @param name name of variable to match + * @param match value to compare against value of variable + * @return TRUE if variable is defined and its value is string equal + * to match or FALSE otherwise + */ +static INLINE int +nvram_match(const char *name, const char *match) +{ + const char *value = nvram_get(name); + return (value && !strcmp(value, match)); +} + +/* + * Inversely match an NVRAM variable. + * @param name name of variable to match + * @param match value to compare against value of variable + * @return TRUE if variable is defined and its value is not string + * equal to invmatch or FALSE otherwise + */ +static INLINE int +nvram_invmatch(const char *name, const char *invmatch) +{ + const char *value = nvram_get(name); + return (value && strcmp(value, invmatch)); +} + +/* + * Set the value of an NVRAM variable. The name and value strings are + * copied into private storage. Pointers to previously set values + * may become invalid. The new value may be immediately + * retrieved but will not be permanently stored until a commit. + * @param name name of variable to set + * @param value value of variable + * @return 0 on success and errno on failure + */ +extern int nvram_set(const char *name, const char *value); + +/* + * Unset an NVRAM variable. Pointers to previously set values + * remain valid until a set. + * @param name name of variable to unset + * @return 0 on success and errno on failure + * NOTE: use nvram_commit to commit this change to flash. + */ +extern int nvram_unset(const char *name); + +/* + * Commit NVRAM variables to permanent storage. All pointers to values + * may be invalid after a commit. + * NVRAM values are undefined after a commit. + * @param nvram_corrupt true to corrupt nvram, false otherwise. + * @return 0 on success and errno on failure + */ +extern int nvram_commit_internal(bool nvram_corrupt); + +/* + * Commit NVRAM variables to permanent storage. All pointers to values + * may be invalid after a commit. + * NVRAM values are undefined after a commit. + * @return 0 on success and errno on failure + */ +extern int nvram_commit(void); + +/* + * Get all NVRAM variables (format name=value\0 ... \0\0). + * @param buf buffer to store variables + * @param count size of buffer in bytes + * @return 0 on success and errno on failure + */ +extern int nvram_getall(char *nvram_buf, int count); + +/* + * returns the crc value of the nvram + * @param nvh nvram header pointer + */ +uint8 nvram_calc_crc(struct nvram_header * nvh); + +extern int nvram_space; +#endif /* _LANGUAGE_ASSEMBLY */ + +/* The NVRAM version number stored as an NVRAM variable */ +#define NVRAM_SOFTWARE_VERSION "1" + +#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */ +#define NVRAM_CLEAR_MAGIC 0x0 +#define NVRAM_INVALID_MAGIC 0xFFFFFFFF +#define NVRAM_VERSION 1 +#define NVRAM_HEADER_SIZE 20 +/* This definition is for precommit staging, and will be removed */ +#define NVRAM_SPACE 0x8000 +/* For CFE builds this gets passed in thru the makefile */ +#ifndef MAX_NVRAM_SPACE +#define MAX_NVRAM_SPACE 0x10000 +#endif +#define DEF_NVRAM_SPACE 0x8000 +#define ROM_ENVRAM_SPACE 0x1000 +#define NVRAM_LZMA_MAGIC 0x4c5a4d41 /* 'LZMA' */ + +#define NVRAM_MAX_VALUE_LEN 255 +#define NVRAM_MAX_PARAM_LEN 64 + +#define NVRAM_CRC_START_POSITION 9 /* magic, len, crc8 to be skipped */ +#define NVRAM_CRC_VER_MASK 0xffffff00 /* for crc_ver_init */ + +/* Offsets to embedded nvram area */ +#define NVRAM_START_COMPRESSED 0x400 +#define NVRAM_START 0x1000 + +#define BCM_JUMBO_NVRAM_DELIMIT '\n' +#define BCM_JUMBO_START "Broadcom Jumbo Nvram file" + + +#if (defined(FAILSAFE_UPGRADE) || defined(CONFIG_FAILSAFE_UPGRADE) || \ + defined(__CONFIG_FAILSAFE_UPGRADE_SUPPORT__)) +#define IMAGE_SIZE "image_size" +#define BOOTPARTITION "bootpartition" +#define IMAGE_BOOT BOOTPARTITION +#define PARTIALBOOTS "partialboots" +#define MAXPARTIALBOOTS "maxpartialboots" +#define IMAGE_1ST_FLASH_TRX "flash0.trx" +#define IMAGE_1ST_FLASH_OS "flash0.os" +#define IMAGE_2ND_FLASH_TRX "flash0.trx2" +#define IMAGE_2ND_FLASH_OS "flash0.os2" +#define IMAGE_FIRST_OFFSET "image_first_offset" +#define IMAGE_SECOND_OFFSET "image_second_offset" +#define LINUX_FIRST "linux" +#define LINUX_SECOND "linux2" +#endif + +#if (defined(DUAL_IMAGE) || defined(CONFIG_DUAL_IMAGE) || \ + defined(__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__)) +/* Shared by all: CFE, Linux Kernel, and Ap */ +#define IMAGE_BOOT "image_boot" +#define BOOTPARTITION IMAGE_BOOT +/* CFE variables */ +#define IMAGE_1ST_FLASH_TRX "flash0.trx" +#define IMAGE_1ST_FLASH_OS "flash0.os" +#define IMAGE_2ND_FLASH_TRX "flash0.trx2" +#define IMAGE_2ND_FLASH_OS "flash0.os2" +#define IMAGE_SIZE "image_size" + +/* CFE and Linux Kernel shared variables */ +#define IMAGE_FIRST_OFFSET "image_first_offset" +#define IMAGE_SECOND_OFFSET "image_second_offset" + +/* Linux application variables */ +#define LINUX_FIRST "linux" +#define LINUX_SECOND "linux2" +#define POLICY_TOGGLE "toggle" +#define LINUX_PART_TO_FLASH "linux_to_flash" +#define LINUX_FLASH_POLICY "linux_flash_policy" + +#endif /* defined(DUAL_IMAGE||CONFIG_DUAL_IMAGE)||__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__ */ + +#endif /* _bcmnvram_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcie.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcie.h new file mode 100644 index 000000000000..55a763d6793f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcie.h @@ -0,0 +1,227 @@ +/* + * Broadcom PCIE + * Software-specific definitions shared between device and host side + * Explains the shared area between host and dongle + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmpcie.h 627710 2016-03-28 07:09:41Z $ + */ + +#ifndef _bcmpcie_h_ +#define _bcmpcie_h_ + +#include + +#define ADDR_64(x) (x.addr) +#define HIGH_ADDR_32(x) ((uint32) (((sh_addr_t) x).high_addr)) +#define LOW_ADDR_32(x) ((uint32) (((sh_addr_t) x).low_addr)) + +typedef struct { + uint32 low_addr; + uint32 high_addr; +} sh_addr_t; + + + +#ifdef BCMPCIE_SUPPORT_TX_PUSH_RING +#define BCMPCIE_PUSH_TX_RING 1 +#else +#define BCMPCIE_PUSH_TX_RING 0 +#endif /* BCMPCIE_SUPPORT_TX_PUSH_RING */ + +/* May be overridden by 43xxxxx-roml.mk */ +#if !defined(BCMPCIE_MAX_TX_FLOWS) +#define BCMPCIE_MAX_TX_FLOWS 40 +#endif /* ! BCMPCIE_MAX_TX_FLOWS */ + +#define PCIE_SHARED_VERSION 0x00005 +#define PCIE_SHARED_VERSION_MASK 0x000FF +#define PCIE_SHARED_ASSERT_BUILT 0x00100 +#define PCIE_SHARED_ASSERT 0x00200 +#define PCIE_SHARED_TRAP 0x00400 +#define PCIE_SHARED_IN_BRPT 0x00800 +#define PCIE_SHARED_SET_BRPT 0x01000 +#define PCIE_SHARED_PENDING_BRPT 0x02000 +#define PCIE_SHARED_TXPUSH_SPRT 0x04000 +#define PCIE_SHARED_EVT_SEQNUM 0x08000 +#define PCIE_SHARED_DMA_INDEX 0x10000 + +/* D2H M2M DMA Complete Sync mechanism: Modulo-253-SeqNum or XORCSUM */ +#define PCIE_SHARED_D2H_SYNC_SEQNUM 0x20000 +#define PCIE_SHARED_D2H_SYNC_XORCSUM 0x40000 +#define PCIE_SHARED_D2H_SYNC_MODE_MASK \ + (PCIE_SHARED_D2H_SYNC_SEQNUM | PCIE_SHARED_D2H_SYNC_XORCSUM) + +#define BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT 0 +#define BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT 1 +#define BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE 2 +#define BCMPCIE_D2H_MSGRING_TX_COMPLETE 3 +#define BCMPCIE_D2H_MSGRING_RX_COMPLETE 4 +#define BCMPCIE_COMMON_MSGRING_MAX_ID 4 + +/* Added only for single tx ring */ +#define BCMPCIE_H2D_TXFLOWRINGID 5 + +#define BCMPCIE_H2D_COMMON_MSGRINGS 2 +#define BCMPCIE_D2H_COMMON_MSGRINGS 3 +#define BCMPCIE_COMMON_MSGRINGS 5 + +enum h2dring_idx { + BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT_IDX = 0, + BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT_IDX = 1, + BCMPCIE_H2D_MSGRING_TXFLOW_IDX_START = 2 +}; + +enum d2hring_idx { + BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE_IDX = 0, + BCMPCIE_D2H_MSGRING_TX_COMPLETE_IDX = 1, + BCMPCIE_D2H_MSGRING_RX_COMPLETE_IDX = 2 +}; + +typedef struct ring_mem { + uint16 idx; + uint8 type; + uint8 rsvd; + uint16 max_item; + uint16 len_items; + sh_addr_t base_addr; +} ring_mem_t; + +#define RINGSTATE_INITED 1 + +typedef struct ring_state { + uint8 idx; + uint8 state; + uint16 r_offset; + uint16 w_offset; + uint16 e_offset; +} ring_state_t; + + + +typedef struct ring_info { + /* locations in the TCM where the ringmem is and ringstate are defined */ + uint32 ringmem_ptr; /* ring mem location in TCM */ + uint32 h2d_w_idx_ptr; + + uint32 h2d_r_idx_ptr; + uint32 d2h_w_idx_ptr; + + uint32 d2h_r_idx_ptr; + /* host locations where the DMA of read/write indices are */ + sh_addr_t h2d_w_idx_hostaddr; + sh_addr_t h2d_r_idx_hostaddr; + sh_addr_t d2h_w_idx_hostaddr; + sh_addr_t d2h_r_idx_hostaddr; + uint16 max_sub_queues; + uint16 rsvd; +} ring_info_t; + +typedef struct { + /* shared area version captured at flags 7:0 */ + uint32 flags; + + uint32 trap_addr; + uint32 assert_exp_addr; + uint32 assert_file_addr; + uint32 assert_line; + uint32 console_addr; /* Address of hnd_cons_t */ + + uint32 msgtrace_addr; + + uint32 fwid; + + /* Used for debug/flow control */ + uint16 total_lfrag_pkt_cnt; + uint16 max_host_rxbufs; /* rsvd in spec */ + + uint32 dma_rxoffset; /* rsvd in spec */ + + /* these will be used for sleep request/ack, d3 req/ack */ + uint32 h2d_mb_data_ptr; + uint32 d2h_mb_data_ptr; + + /* information pertinent to host IPC/msgbuf channels */ + /* location in the TCM memory which has the ring_info */ + uint32 rings_info_ptr; + + /* block of host memory for the scratch buffer */ + uint32 host_dma_scratch_buffer_len; + sh_addr_t host_dma_scratch_buffer; + + /* block of host memory for the dongle to push the status into */ + uint32 device_rings_stsblk_len; + sh_addr_t device_rings_stsblk; +#ifdef BCM_BUZZZ + uint32 buzzz; /* BUZZZ state format strings and trace buffer */ +#endif +} pciedev_shared_t; + + +/* H2D mail box Data */ +#define H2D_HOST_D3_INFORM 0x00000001 +#define H2D_HOST_DS_ACK 0x00000002 +#define H2D_HOST_CONS_INT 0x80000000 /* h2d int for console cmds */ + +#define H2D_HOST_D0_INFORM_IN_USE 0x00000008 +#define H2D_HOST_D0_INFORM 0x00000010 + +/* D2H mail box Data */ +#define D2H_DEV_D3_ACK 0x00000001 +#define D2H_DEV_DS_ENTER_REQ 0x00000002 +#define D2H_DEV_DS_EXIT_NOTE 0x00000004 +#define D2H_DEV_FWHALT 0x10000000 +#define D2H_DEV_MB_MASK (D2H_DEV_D3_ACK | D2H_DEV_DS_ENTER_REQ | \ + D2H_DEV_DS_EXIT_NOTE | D2H_DEV_FWHALT) +#define D2H_DEV_MB_INVALIDATED(x) ((!x) || (x & ~D2H_DEV_MB_MASK)) + + +extern pciedev_shared_t pciedev_shared; +#define NEXTTXP(i, d) ((((i)+1) >= (d)) ? 0 : ((i)+1)) +#define NTXPACTIVE(r, w, d) (((r) <= (w)) ? ((w)-(r)) : ((d)-(r)+(w))) +#define NTXPAVAIL(r, w, d) (((d) - NTXPACTIVE((r), (w), (d))) > 1) + +/* Function can be used to notify host of FW halt */ +#define READ_AVAIL_SPACE(w, r, d) \ + ((w >= r) ? (w - r) : (d - r)) + +#define WRT_PEND(x) ((x)->wr_pending) +#define DNGL_RING_WPTR(msgbuf) (*((msgbuf)->tcm_rs_w_ptr)) +#define BCMMSGBUF_RING_SET_W_PTR(msgbuf, a) (DNGL_RING_WPTR(msgbuf) = (a)) + +#define DNGL_RING_RPTR(msgbuf) (*((msgbuf)->tcm_rs_r_ptr)) +#define BCMMSGBUF_RING_SET_R_PTR(msgbuf, a) (DNGL_RING_RPTR(msgbuf) = (a)) + +#define RING_READ_PTR(x) ((x)->ringstate->r_offset) +#define RING_WRITE_PTR(x) ((x)->ringstate->w_offset) +#define RING_START_PTR(x) ((x)->ringmem->base_addr.low_addr) +#define RING_MAX_ITEM(x) ((x)->ringmem->max_item) +#define RING_LEN_ITEMS(x) ((x)->ringmem->len_items) +#define HOST_RING_BASE(x) ((x)->ring_base.va) +#define HOST_RING_END(x) ((uint8 *)HOST_RING_BASE((x)) + \ + ((RING_MAX_ITEM((x))-1)*RING_LEN_ITEMS((x)))) + +#define WRITE_SPACE_AVAIL_CONTINUOUS(r, w, d) ((w >= r) ? (d - w) : (r - w)) +#define WRITE_SPACE_AVAIL(r, w, d) (d - (NTXPACTIVE(r, w, d)) - 1) +#define CHECK_WRITE_SPACE(r, w, d) \ + MIN(WRITE_SPACE_AVAIL(r, w, d), WRITE_SPACE_AVAIL_CONTINUOUS(r, w, d)) + +#endif /* _bcmpcie_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcispi.h new file mode 100644 index 000000000000..d4781abb982a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcispi.h @@ -0,0 +1,181 @@ +/* + * Broadcom PCI-SPI Host Controller Register Definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmpcispi.h 241182 2011-02-17 21:50:03Z $ + */ +#ifndef _BCM_PCI_SPI_H +#define _BCM_PCI_SPI_H + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif /* PAD */ + + +typedef volatile struct { + uint32 spih_ctrl; /* 0x00 SPI Control Register */ + uint32 spih_stat; /* 0x04 SPI Status Register */ + uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ + uint32 spih_ext; /* 0x0C SPI Extension Register */ + uint32 PAD[4]; /* 0x10-0x1F PADDING */ + + uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ + uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ + uint32 PAD[6]; /* 0x28-0x3F PADDING */ + + uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ + uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ + /* 1=Active High) */ + uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ + uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ + uint32 PAD[4]; /* 0x50-0x5F PADDING */ + + uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ + uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ + uint32 PAD[1]; /* 0x68 PADDING */ + uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ + uint32 PAD[4]; /* 0x70-0x7F PADDING */ + uint32 PAD[8]; /* 0x80-0x9F PADDING */ + uint32 PAD[8]; /* 0xA0-0xBF PADDING */ + uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ + uint32 spih_pll_status; /* 0xC4 PLL Status Register */ + uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ + uint32 spih_clk_count; /* 0xCC External Clock Count Register */ + +} spih_regs_t; + +typedef volatile struct { + uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ + uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ + + uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ + uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ + uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ + uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ + uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ + uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ + uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ + uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ + uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ + uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ + uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ + uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ + uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ + uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ + uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ + uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ + uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ + uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ + uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ + uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ + uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ + uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ + uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ + uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ + uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ + uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ + + uint32 PAD[5]; /* 0x16C-0x17F PADDING */ + + uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ + uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ + uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ + uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ + uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ + uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ + uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ + uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ + uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ + uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ + uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ + uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ + uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ + uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ + uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ + uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ + uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ + uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ + uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ + uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ + uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ + uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ + uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ + uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ + uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ + uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ + + uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ + uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ + uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ +} spih_pciregs_t; + +/* + * PCI Core interrupt enable and status bit definitions. + */ + +/* PCI Core ICR Register bit definitions */ +#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ +#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ +#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ +#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ +#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ +#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ + + +/* PCI Core ISR Register bit definitions */ +#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ +#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ +#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ +#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ +#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ + + +/* Registers on the Wishbone bus */ +#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ +#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ +#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ + +/* GPIO Bit definitions */ +#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ +#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ +#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ + +/* SPI Status Register Bit definitions */ +#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ +#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ +#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ +#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ +#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ +#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ + +#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ + +#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ +#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ + +/* Spin bit loop bound check */ +#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ + +#endif /* _BCM_PCI_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmperf.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmperf.h new file mode 100644 index 000000000000..84c232f8a059 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmperf.h @@ -0,0 +1,36 @@ +/* + * Performance counters software interface. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmperf.h 241182 2011-02-17 21:50:03Z $ + */ +/* essai */ +#ifndef _BCMPERF_H_ +#define _BCMPERF_H_ +/* get cache hits and misses */ +#define BCMPERF_ENABLE_INSTRCOUNT() +#define BCMPERF_ENABLE_ICACHE_MISS() +#define BCMPERF_ENABLE_ICACHE_HIT() +#define BCMPERF_GETICACHE_MISS(x) ((x) = 0) +#define BCMPERF_GETICACHE_HIT(x) ((x) = 0) +#define BCMPERF_GETINSTRCOUNT(x) ((x) = 0) +#endif /* _BCMPERF_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdbus.h new file mode 100644 index 000000000000..4d4634ba6585 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdbus.h @@ -0,0 +1,143 @@ +/* + * Definitions for API from sdio common code (bcmsdh) to individual + * host controller drivers. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdbus.h 408158 2013-06-17 22:15:35Z $ + */ + +#ifndef _sdio_api_h_ +#define _sdio_api_h_ + + +#define SDIOH_API_RC_SUCCESS (0x00) +#define SDIOH_API_RC_FAIL (0x01) +#define SDIOH_API_SUCCESS(status) (status == 0) + +#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 */ + +#define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */ +#define SDIOH_CMD_TYPE_APPEND 1 /* Append command */ +#define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */ + +#define SDIOH_DATA_PIO 0 /* PIO mode */ +#define SDIOH_DATA_DMA 1 /* DMA mode */ + +/* Max number of glommed pkts */ +#ifdef CUSTOM_MAX_TXGLOM_SIZE +#define SDPCM_MAXGLOM_SIZE CUSTOM_MAX_TXGLOM_SIZE +#else +#define SDPCM_MAXGLOM_SIZE 40 +#endif /* CUSTOM_MAX_TXGLOM_SIZE */ + +#define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ +#define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ + +#ifdef CUSTOM_DEF_TXGLOM_SIZE +#define SDPCM_DEFGLOM_SIZE CUSTOM_DEF_TXGLOM_SIZE +#else +#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE +#endif /* CUSTOM_DEF_TXGLOM_SIZE */ + +#if SDPCM_DEFGLOM_SIZE > SDPCM_MAXGLOM_SIZE +#warning "SDPCM_DEFGLOM_SIZE cannot be higher than SDPCM_MAXGLOM_SIZE!!" +#undef SDPCM_DEFGLOM_SIZE +#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE +#endif + +typedef int SDIOH_API_RC; + +/* SDio Host structure */ +typedef struct sdioh_info sdioh_info_t; + +/* callback function, taking one arg */ +typedef void (*sdioh_cb_fn_t)(void *); + +extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); +extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); + +/* query whether SD interrupt is enabled or not */ +extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff); + +/* enable or disable SD interrupt */ +extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); + +#if defined(DHD_DEBUG) +extern bool sdioh_interrupt_pending(sdioh_info_t *si); +#endif + +/* read or write one byte using cmd52 */ +extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte); + +/* read or write 2/4 bytes using cmd53 */ +extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *si, uint cmd_type, uint rw, uint fnc, + uint addr, uint32 *word, uint nbyte); + +/* read or write any buffer using cmd53 */ +extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc, + uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer, + void *pkt); + +/* get cis data */ +extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); + +extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); +extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); + +/* query number of io functions */ +extern uint sdioh_query_iofnum(sdioh_info_t *si); + +/* handle iovars */ +extern int sdioh_iovar_op(sdioh_info_t *si, const char *name, + void *params, int plen, void *arg, int len, bool set); + +/* Issue abort to the specified function and clear controller as needed */ +extern int sdioh_abort(sdioh_info_t *si, uint fnc); + +/* Start and Stop SDIO without re-enumerating the SD card. */ +extern int sdioh_start(sdioh_info_t *si, int stage); +extern int sdioh_stop(sdioh_info_t *si); + +/* Wait system lock free */ +extern int sdioh_waitlockfree(sdioh_info_t *si); + +/* Reset and re-initialize the device */ +extern int sdioh_sdio_reset(sdioh_info_t *si); + + + +#if defined(BCMSDIOH_STD) + #define SDIOH_SLEEP_ENABLED +#endif +extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab); + +/* GPIO support */ +extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd); +extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio); +extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio); +extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab); + +#endif /* _sdio_api_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh.h new file mode 100644 index 000000000000..4ff425e350c8 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh.h @@ -0,0 +1,252 @@ +/* + * SDIO host client driver interface of Broadcom HNBU + * export functions to client drivers + * abstract OS and BUS specific details of SDIO + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh.h 450676 2014-01-22 22:45:13Z $ + */ + +/** + * @file bcmsdh.h + */ + +#ifndef _bcmsdh_h_ +#define _bcmsdh_h_ + +#define BCMSDH_ERROR_VAL 0x0001 /* Error */ +#define BCMSDH_INFO_VAL 0x0002 /* Info */ +extern const uint bcmsdh_msglevel; + +#define BCMSDH_ERROR(x) +#define BCMSDH_INFO(x) + +#if defined(BCMSDIO) && (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || \ + defined(BCMSDIOH_SPI)) +#define BCMSDH_ADAPTER +#endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */ + +/* forward declarations */ +typedef struct bcmsdh_info bcmsdh_info_t; +typedef void (*bcmsdh_cb_fn_t)(void *); + +extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva); +/** + * BCMSDH API context + */ +struct bcmsdh_info +{ + bool init_success; /* underlying driver successfully attached */ + void *sdioh; /* handler for sdioh */ + uint32 vendevid; /* Target Vendor and Device ID on SD bus */ + osl_t *osh; + bool regfail; /* Save status of last reg_read/reg_write call */ + uint32 sbwad; /* Save backplane window address */ + void *os_cxt; /* Pointer to per-OS private data */ +}; + +/* Detach - freeup resources allocated in attach */ +extern int bcmsdh_detach(osl_t *osh, void *sdh); + +/* Query if SD device interrupts are enabled */ +extern bool bcmsdh_intr_query(void *sdh); + +/* Enable/disable SD interrupt */ +extern int bcmsdh_intr_enable(void *sdh); +extern int bcmsdh_intr_disable(void *sdh); + +/* Register/deregister device interrupt handler. */ +extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); +extern int bcmsdh_intr_dereg(void *sdh); +/* Enable/disable SD card interrupt forward */ +extern void bcmsdh_intr_forward(void *sdh, bool pass); + +#if defined(DHD_DEBUG) +/* Query pending interrupt status from the host controller */ +extern bool bcmsdh_intr_pending(void *sdh); +#endif + +/* Register a callback to be called if and when bcmsdh detects + * device removal. No-op in the case of non-removable/hardwired devices. + */ +extern int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); + +/* 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 uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err); +extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err); + +/* Read/Write 4bytes from/to cfg space */ +extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err); +extern void bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err); + +/* Read CIS content for specified function. + * fn: function whose CIS is being requested (0 is common CIS) + * cis: pointer to memory location to place results + * length: number of bytes to read + * Internally, this routine uses the values from the cis base regs (0x9-0xB) + * to form an SDIO-space address to read the data from. + */ +extern int bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length); + +/* 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 uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size); +extern uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data); + +/* set sb address window */ +extern int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set); + +/* Indicate if last reg read/write failed */ +extern bool bcmsdh_regfail(void *sdh); + +/* 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. + */ +typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting); +extern int bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, void *pkt, + bcmsdh_cmplt_fn_t complete_fn, void *handle); +extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, void *pkt, + bcmsdh_cmplt_fn_t complete_fn, void *handle); + +extern void bcmsdh_glom_post(void *sdh, uint8 *frame, void *pkt, uint len); +extern void bcmsdh_glom_clear(void *sdh); +extern uint bcmsdh_set_mode(void *sdh, uint mode); +extern bool bcmsdh_glom_enabled(void); +/* Flags bits */ +#define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */ +#define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */ +#define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */ +#define SDIO_BYTE_MODE 0x8 /* Byte mode request(non-block mode) */ + +/* Pending (non-error) return code */ +#define BCME_PENDING 1 + +/* 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 bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes); + +/* Issue an abort to the specified function */ +extern int bcmsdh_abort(void *sdh, uint fn); + +/* Start SDIO Host Controller communication */ +extern int bcmsdh_start(void *sdh, int stage); + +/* Stop SDIO Host Controller communication */ +extern int bcmsdh_stop(void *sdh); + +/* Wait system lock free */ +extern int bcmsdh_waitlockfree(void *sdh); + +/* Returns the "Device ID" of target device on the SDIO bus. */ +extern int bcmsdh_query_device(void *sdh); + +/* Returns the number of IO functions reported by the device */ +extern uint bcmsdh_query_iofnum(void *sdh); + +/* Miscellaneous knob tweaker. */ +extern int bcmsdh_iovar_op(void *sdh, const char *name, + void *params, int plen, void *arg, int len, bool set); + +/* Reset and reinitialize the device */ +extern int bcmsdh_reset(bcmsdh_info_t *sdh); + +/* helper functions */ + +/* callback functions */ +typedef struct { + /* probe the device */ + void *(*probe)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot, + uint16 func, uint bustype, void * regsva, osl_t * osh, + void * param); + /* remove the device */ + void (*remove)(void *context); + /* can we suspend now */ + int (*suspend)(void *context); + /* resume from suspend */ + int (*resume)(void *context); +} bcmsdh_driver_t; + +/* platform specific/high level functions */ +extern int bcmsdh_register(bcmsdh_driver_t *driver); +extern void bcmsdh_unregister(void); +extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device); +extern void bcmsdh_device_remove(void * sdh); + +extern int bcmsdh_reg_sdio_notify(void* semaphore); +extern void bcmsdh_unreg_sdio_notify(void); + +#if defined(OOB_INTR_ONLY) +extern int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, + void* oob_irq_handler_context); +extern void bcmsdh_oob_intr_unregister(bcmsdh_info_t *sdh); +extern void bcmsdh_oob_intr_set(bcmsdh_info_t *sdh, bool enable); +#endif +extern void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *sdh); +extern void bcmsdh_dev_relax(bcmsdh_info_t *sdh); +extern bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *sdh); + +int bcmsdh_suspend(bcmsdh_info_t *bcmsdh); +int bcmsdh_resume(bcmsdh_info_t *bcmsdh); + +/* Function to pass device-status bits to DHD. */ +extern uint32 bcmsdh_get_dstatus(void *sdh); + +/* Function to return current window addr */ +extern uint32 bcmsdh_cur_sbwad(void *sdh); + +/* Function to pass chipid and rev to lower layers for controlling pr's */ +extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); + + +extern int bcmsdh_sleep(void *sdh, bool enab); + +/* GPIO support */ +extern int bcmsdh_gpio_init(void *sd); +extern bool bcmsdh_gpioin(void *sd, uint32 gpio); +extern int bcmsdh_gpioouten(void *sd, uint32 gpio); +extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); + +#endif /* _bcmsdh_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh_sdmmc.h new file mode 100644 index 000000000000..b4578468cbab --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh_sdmmc.h @@ -0,0 +1,117 @@ +/* + * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh_sdmmc.h 496576 2014-08-13 15:04:56Z $ + */ + +#ifndef __BCMSDH_SDMMC_H__ +#define __BCMSDH_SDMMC_H__ + +#define sd_err(x) +#define sd_trace(x) +#define sd_info(x) +#define sd_debug(x) +#define sd_data(x) +#define sd_ctrl(x) + + +#define sd_sync_dma(sd, read, nbytes) +#define sd_init_dma(sd) +#define sd_ack_intr(sd) +#define sd_wakeup(sd); + +#define sd_log(x) + +#define SDIOH_ASSERT(exp) \ + do { if (!(exp)) \ + printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ + } while (0) + +#define BLOCK_SIZE_4318 64 +#define BLOCK_SIZE_4328 512 + +/* internal return code */ +#define SUCCESS 0 +#define ERROR 1 + +/* private bus modes */ +#define SDIOH_MODE_SD4 2 +#define CLIENT_INTR 0x100 /* Get rid of this! */ +#define SDIOH_SDMMC_MAX_SG_ENTRIES (SDPCM_MAXGLOM_SIZE+2) + +struct sdioh_info { + osl_t *osh; /* osh handler */ + void *bcmsdh; /* upper layer handle */ + bool client_intr_enabled; /* interrupt connnected flag */ + bool intr_handler_valid; /* client driver interrupt handler valid */ + sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ + void *intr_handler_arg; /* argument to call interrupt handler */ + uint16 intmask; /* Current active interrupts */ + + int intrcount; /* Client interrupts */ + bool sd_use_dma; /* DMA on CMD53 */ + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + /* Must be on for sd_multiblock to be effective */ + bool use_client_ints; /* If this is false, make sure to restore */ + int sd_mode; /* SD1/SD4/SPI */ + int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ + uint8 num_funcs; /* Supported funcs on client */ + uint32 com_cis_ptr; + uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; + bool use_rxchain; + struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; + struct sdio_func fake_func0; + struct sdio_func *func[SDIOD_MAX_IOFUNCS]; + +}; + +/************************************************************ + * Internal interfaces: per-port references into bcmsdh_sdmmc.c + */ + +/* Global message bits */ +extern uint sd_msglevel; + +/* OS-independent interrupt handler */ +extern bool check_client_intr(sdioh_info_t *sd); + +/* Core interrupt enable/disable of device interrupts */ +extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); +extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); + + +/************************************************************** + * Internal interfaces: bcmsdh_sdmmc.c references to per-port code + */ + +/* Register mapping routines */ +extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size); +extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size); + +/* Interrupt (de)registration routines */ +extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); +extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd); + +extern sdioh_info_t *sdioh_attach(osl_t *osh, struct sdio_func *func); +extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); +#endif /* __BCMSDH_SDMMC_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdpcm.h new file mode 100644 index 000000000000..535961916075 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdpcm.h @@ -0,0 +1,278 @@ +/* + * Broadcom SDIO/PCMCIA + * Software-specific definitions shared between device and host side + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdpcm.h 472405 2014-04-23 23:46:55Z $ + */ + +#ifndef _bcmsdpcm_h_ +#define _bcmsdpcm_h_ + +/* + * Software allocation of To SB Mailbox resources + */ + +/* intstatus bits */ +#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */ +#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */ +#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */ +#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */ + +#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) + +/* tosbmailbox bits corresponding to intstatus bits */ +#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ +#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ +#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ +#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ +#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */ + +/* tosbmailboxdata */ +#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */ +#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */ + +/* + * Software allocation of To Host Mailbox resources + */ + +/* intstatus bits */ +#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */ +#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */ +#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */ +#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */ + +#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT) + +/* tohostmailbox bits corresponding to intstatus bits */ +#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */ +#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */ +#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ +#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ +#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */ + +/* tohostmailboxdata */ +#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */ +#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */ +#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */ +#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */ +#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */ + +#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */ +#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ + +#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */ +#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ + +/* + * Software-defined protocol header + */ + +/* Current protocol version */ +#define SDPCM_PROT_VERSION 4 + +/* SW frame header */ +#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ +#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ + +#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ +#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ +#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ + +#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ +#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ +#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ + +/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ +#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ +#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ +#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ +#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) (((uint8 *)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) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) +#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ +#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) +#define SDPCM_VERSION_OFFSET 6 /* Version # */ +#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) +#define SDPCM_UNUSED_OFFSET 7 /* Spare */ +#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) + +#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ + +/* logical channel numbers */ +#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response 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 (superframes) */ +#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ +#define SDPCM_MAX_CHANNEL 15 + +#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ + +#define SDPCM_FLAG_RESVD0 0x01 +#define SDPCM_FLAG_RESVD1 0x02 +#define SDPCM_FLAG_GSPI_TXENAB 0x04 +#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ + +/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ +#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) + +#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80) + +/* For TEST_CHANNEL packets, define another 4-byte header */ +#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2); + * Semantics of Ext byte depend on command. + * Len is current or requested frame length, not + * including test header; sent little-endian. + */ +#define SDPCM_TEST_PKT_CNT_FLD_LEN 4 /* Packet count filed legth */ +#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ +#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ +#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ +#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count + * (Backward compatabilty) Set frame count in a + * 4 byte filed adjacent to the HDR + */ +#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off + * Set frame count in a 4 byte filed adjacent to + * the HDR + */ + +/* Handy macro for filling in datagen packets with a pattern */ +#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) + +/* + * Software counters (first part matches hardware counters) + */ + +typedef volatile struct { + uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ + uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ + uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ + uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ + uint32 abort; /* AbortCount, SDIO: aborts */ + uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ + uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ + uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ + uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ + uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ + uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ + uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ + uint32 rxdescuflo; /* receive descriptor underflows */ + uint32 rxfifooflo; /* receive fifo overflows */ + uint32 txfifouflo; /* transmit fifo underflows */ + uint32 runt; /* runt (too short) frames recv'd from bus */ + uint32 badlen; /* frame's rxh len does not match its hw tag len */ + uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ + uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ + uint32 rxfcrc; /* frame rx header indicates crc error */ + uint32 rxfwoos; /* frame rx header indicates write out of sync */ + uint32 rxfwft; /* frame rx header indicates write frame termination */ + uint32 rxfabort; /* frame rx header indicates frame aborted */ + uint32 woosint; /* write out of sync interrupt */ + uint32 roosint; /* read out of sync interrupt */ + uint32 rftermint; /* read frame terminate interrupt */ + uint32 wftermint; /* write frame terminate interrupt */ +} sdpcmd_cnt_t; + +/* + * Register Access Macros + */ + +#define SDIODREV_IS(var, val) ((var) == (val)) +#define SDIODREV_GE(var, val) ((var) >= (val)) +#define SDIODREV_GT(var, val) ((var) > (val)) +#define SDIODREV_LT(var, val) ((var) < (val)) +#define SDIODREV_LE(var, val) ((var) <= (val)) + +#define SDIODDMAREG32(h, dir, chnl) \ + ((dir) == DMA_TX ? \ + (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ + (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv)) + +#define SDIODDMAREG64(h, dir, chnl) \ + ((dir) == DMA_TX ? \ + (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ + (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv)) + +#define SDIODDMAREG(h, dir, chnl) \ + (SDIODREV_LT((h)->corerev, 1) ? \ + SDIODDMAREG32((h), (dir), (chnl)) : \ + SDIODDMAREG64((h), (dir), (chnl))) + +#define PCMDDMAREG(h, dir, chnl) \ + ((dir) == DMA_TX ? \ + (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \ + (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv)) + +#define SDPCMDMAREG(h, dir, chnl, coreid) \ + ((coreid) == SDIOD_CORE_ID ? \ + SDIODDMAREG(h, dir, chnl) : \ + PCMDDMAREG(h, dir, chnl)) + +#define SDIODFIFOREG(h, corerev) \ + (SDIODREV_LT((corerev), 1) ? \ + ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \ + ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo))) + +#define PCMDFIFOREG(h) \ + ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo)) + +#define SDPCMFIFOREG(h, coreid, corerev) \ + ((coreid) == SDIOD_CORE_ID ? \ + SDIODFIFOREG(h, corerev) : \ + PCMDFIFOREG(h)) + +/* + * Shared structure between dongle and the host. + * The structure contains pointers to trap or assert information. + */ +#define SDPCM_SHARED_VERSION 0x0001 +#define SDPCM_SHARED_VERSION_MASK 0x00FF +#define SDPCM_SHARED_ASSERT_BUILT 0x0100 +#define SDPCM_SHARED_ASSERT 0x0200 +#define SDPCM_SHARED_TRAP 0x0400 +#define SDPCM_SHARED_IN_BRPT 0x0800 +#define SDPCM_SHARED_SET_BRPT 0x1000 +#define SDPCM_SHARED_PENDING_BRPT 0x2000 + +typedef struct { + uint32 flags; + uint32 trap_addr; + uint32 assert_exp_addr; + uint32 assert_file_addr; + uint32 assert_line; + uint32 console_addr; /* Address of hnd_cons_t */ + uint32 msgtrace_addr; + uint32 fwid; +} sdpcm_shared_t; + +extern sdpcm_shared_t sdpcm_shared; + +#endif /* _bcmsdpcm_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdspi.h new file mode 100644 index 000000000000..1fc1fd4eef6b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdspi.h @@ -0,0 +1,135 @@ +/* + * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdspi.h 294363 2011-11-06 23:02:20Z $ + */ +#ifndef _BCM_SD_SPI_H +#define _BCM_SD_SPI_H + +/* global msglevel for debug messages - bitvals come from sdiovar.h */ + +#define sd_err(x) +#define sd_trace(x) +#define sd_info(x) +#define sd_debug(x) +#define sd_data(x) +#define sd_ctrl(x) + +#define sd_log(x) + +#define SDIOH_ASSERT(exp) \ + do { if (!(exp)) \ + printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ + } while (0) + +#define BLOCK_SIZE_4318 64 +#define BLOCK_SIZE_4328 512 + +/* internal return code */ +#define SUCCESS 0 +#undef ERROR +#define ERROR 1 + +/* private bus modes */ +#define SDIOH_MODE_SPI 0 + +#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ +#define USE_MULTIBLOCK 0x4 + +struct sdioh_info { + uint cfg_bar; /* pci cfg address for bar */ + uint32 caps; /* cached value of capabilities reg */ + uint bar0; /* BAR0 for PCI Device */ + osl_t *osh; /* osh handler */ + void *controller; /* Pointer to SPI Controller's private data struct */ + + uint lockcount; /* nest count of sdspi_lock() calls */ + bool client_intr_enabled; /* interrupt connnected flag */ + bool intr_handler_valid; /* client driver interrupt handler valid */ + sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ + void *intr_handler_arg; /* argument to call interrupt handler */ + bool initialized; /* card initialized */ + uint32 target_dev; /* Target device ID */ + uint32 intmask; /* Current active interrupts */ + void *sdos_info; /* Pointer to per-OS private data */ + + uint32 controller_type; /* Host controller type */ + uint8 version; /* Host Controller Spec Compliance Version */ + uint irq; /* Client irq */ + uint32 intrcount; /* Client interrupts */ + uint32 local_intrcount; /* Controller interrupts */ + bool host_init_done; /* Controller initted */ + bool card_init_done; /* Client SDIO interface initted */ + bool polled_mode; /* polling for command completion */ + + bool sd_use_dma; /* DMA on CMD53 */ + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + /* Must be on for sd_multiblock to be effective */ + bool use_client_ints; /* If this is false, make sure to restore */ + bool got_hcint; /* Host Controller interrupt. */ + /* polling hack in wl_linux.c:wl_timer() */ + int adapter_slot; /* Maybe dealing with multiple slots/controllers */ + int sd_mode; /* SD1/SD4/SPI */ + int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ + uint32 data_xfer_count; /* Current register transfer size */ + uint32 cmd53_wr_data; /* Used to pass CMD53 write data */ + uint32 card_response; /* Used to pass back response status byte */ + uint32 card_rsp_data; /* Used to pass back response data word */ + uint16 card_rca; /* Current Address */ + uint8 num_funcs; /* Supported funcs on client */ + uint32 com_cis_ptr; + uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; + void *dma_buf; + ulong dma_phys; + int r_cnt; /* rx count */ + int t_cnt; /* tx_count */ +}; + +/************************************************************ + * Internal interfaces: per-port references into bcmsdspi.c + */ + +/* Global message bits */ +extern uint sd_msglevel; + +/************************************************************** + * Internal interfaces: bcmsdspi.c references to per-port code + */ + +/* Register mapping routines */ +extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); +extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); + +/* Interrupt (de)registration routines */ +extern int spi_register_irq(sdioh_info_t *sd, uint irq); +extern void spi_free_irq(uint irq, sdioh_info_t *sd); + +/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ +extern void spi_lock(sdioh_info_t *sd); +extern void spi_unlock(sdioh_info_t *sd); + +/* Allocate/init/free per-OS private data */ +extern int spi_osinit(sdioh_info_t *sd); +extern void spi_osfree(sdioh_info_t *sd); + +#endif /* _BCM_SD_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdstd.h new file mode 100644 index 000000000000..ef55d436b588 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdstd.h @@ -0,0 +1,282 @@ +/* + * 'Standard' SDIO HOST CONTROLLER driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdstd.h 455390 2014-02-13 22:14:56Z $ + */ +#ifndef _BCM_SD_STD_H +#define _BCM_SD_STD_H + +/* global msglevel for debug messages - bitvals come from sdiovar.h */ +#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) +#define sd_trace(x) +#define sd_info(x) +#define sd_debug(x) +#define sd_data(x) +#define sd_ctrl(x) +#define sd_dma(x) + +#define sd_sync_dma(sd, read, nbytes) +#define sd_init_dma(sd) +#define sd_ack_intr(sd) +#define sd_wakeup(sd); +/* Allocate/init/free per-OS private data */ +extern int sdstd_osinit(sdioh_info_t *sd); +extern void sdstd_osfree(sdioh_info_t *sd); + +#define sd_log(x) + +#define SDIOH_ASSERT(exp) \ + do { if (!(exp)) \ + printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ + } while (0) + +#define BLOCK_SIZE_4318 64 +#define BLOCK_SIZE_4328 512 + +/* internal return code */ +#define SUCCESS 0 +#define ERROR 1 + +/* private bus modes */ +#define SDIOH_MODE_SPI 0 +#define SDIOH_MODE_SD1 1 +#define SDIOH_MODE_SD4 2 + +#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */ +#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */ + +#define SDIOH_TYPE_ARASAN_HDK 1 +#define SDIOH_TYPE_BCM27XX 2 +#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */ +#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */ +#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */ + +/* For linux, allow yielding for dongle */ +#define BCMSDYIELD + +/* Expected card status value for CMD7 */ +#define SDIOH_CMD7_EXP_STATUS 0x00001E00 + +#define RETRIES_LARGE 100000 +#define sdstd_os_yield(sd) do {} while (0) +#define RETRIES_SMALL 100 + + +#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ +#define USE_MULTIBLOCK 0x4 + +#define USE_FIFO 0x8 /* Fifo vs non-fifo */ + +#define CLIENT_INTR 0x100 /* Get rid of this! */ + +#define HC_INTR_RETUNING 0x1000 + + +#ifdef BCMSDIOH_TXGLOM +/* Total glom pkt can not exceed 64K + * need one more slot for glom padding packet + */ +#define SDIOH_MAXGLOM_SIZE (40+1) + +typedef struct glom_buf { + uint32 count; /* Total number of pkts queued */ + void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */ + ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */ + uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */ +} glom_buf_t; +#endif + +struct sdioh_info { + uint cfg_bar; /* pci cfg address for bar */ + uint32 caps; /* cached value of capabilities reg */ + uint32 curr_caps; /* max current capabilities reg */ + + osl_t *osh; /* osh handler */ + volatile char *mem_space; /* pci device memory va */ + uint lockcount; /* nest count of sdstd_lock() calls */ + bool client_intr_enabled; /* interrupt connnected flag */ + bool intr_handler_valid; /* client driver interrupt handler valid */ + sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ + void *intr_handler_arg; /* argument to call interrupt handler */ + bool initialized; /* card initialized */ + uint target_dev; /* Target device ID */ + uint16 intmask; /* Current active interrupts */ + void *sdos_info; /* Pointer to per-OS private data */ + void *bcmsdh; /* handler to upper layer stack (bcmsdh) */ + + uint32 controller_type; /* Host controller type */ + uint8 version; /* Host Controller Spec Compliance Version */ + uint irq; /* Client irq */ + int intrcount; /* Client interrupts */ + int local_intrcount; /* Controller interrupts */ + bool host_init_done; /* Controller initted */ + bool card_init_done; /* Client SDIO interface initted */ + bool polled_mode; /* polling for command completion */ + + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + /* Must be on for sd_multiblock to be effective */ + bool use_client_ints; /* If this is false, make sure to restore */ + /* polling hack in wl_linux.c:wl_timer() */ + int adapter_slot; /* Maybe dealing with multiple slots/controllers */ + int sd_mode; /* SD1/SD4/SPI */ + int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ + uint32 data_xfer_count; /* Current transfer */ + uint16 card_rca; /* Current Address */ + int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */ + uint8 num_funcs; /* Supported funcs on client */ + uint32 com_cis_ptr; + uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; + void *dma_buf; /* DMA Buffer virtual address */ + ulong dma_phys; /* DMA Buffer physical address */ + void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */ + ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */ + + /* adjustments needed to make the dma align properly */ + void *dma_start_buf; + ulong dma_start_phys; + uint alloced_dma_size; + void *adma2_dscr_start_buf; + ulong adma2_dscr_start_phys; + uint alloced_adma2_dscr_size; + + int r_cnt; /* rx count */ + int t_cnt; /* tx_count */ + bool got_hcint; /* local interrupt flag */ + uint16 last_intrstatus; /* to cache intrstatus */ + int host_UHSISupported; /* whether UHSI is supported for HC. */ + int card_UHSI_voltage_Supported; /* whether UHSI is supported for + * Card in terms of Voltage [1.8 or 3.3]. + */ + int global_UHSI_Supp; /* type of UHSI support in both host and card. + * HOST_SDR_UNSUPP: capabilities not supported/matched + * HOST_SDR_12_25: SDR12 and SDR25 supported + * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd + */ + volatile int sd3_dat_state; /* data transfer state used for retuning check */ + volatile int sd3_tun_state; /* tuning state used for retuning check */ + bool sd3_tuning_reqd; /* tuning requirement parameter */ + uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ +#ifdef BCMSDIOH_TXGLOM + glom_buf_t glom_info; /* pkt information used for glomming */ + uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ +#endif +}; + +#define DMA_MODE_NONE 0 +#define DMA_MODE_SDMA 1 +#define DMA_MODE_ADMA1 2 +#define DMA_MODE_ADMA2 3 +#define DMA_MODE_ADMA2_64 4 +#define DMA_MODE_AUTO -1 + +#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) + +/* States for Tuning and corr data */ +#define TUNING_IDLE 0 +#define TUNING_START 1 +#define TUNING_START_AFTER_DAT 2 +#define TUNING_ONGOING 3 + +#define DATA_TRANSFER_IDLE 0 +#define DATA_TRANSFER_ONGOING 1 + +#define CHECK_TUNING_PRE_DATA 1 +#define CHECK_TUNING_POST_DATA 2 + + +#ifdef DHD_DEBUG +#define SD_DHD_DISABLE_PERIODIC_TUNING 0x01 +#define SD_DHD_ENABLE_PERIODIC_TUNING 0x00 +#endif + + +/************************************************************ + * Internal interfaces: per-port references into bcmsdstd.c + */ + +/* Global message bits */ +extern uint sd_msglevel; + +/* OS-independent interrupt handler */ +extern bool check_client_intr(sdioh_info_t *sd); + +/* Core interrupt enable/disable of device interrupts */ +extern void sdstd_devintr_on(sdioh_info_t *sd); +extern void sdstd_devintr_off(sdioh_info_t *sd); + +/* Enable/disable interrupts for local controller events */ +extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err); +extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err); + +/* Wait for specified interrupt and error bits to be set */ +extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err); + + +/************************************************************** + * Internal interfaces: bcmsdstd.c references to per-port code + */ + +/* Register mapping routines */ +extern uint32 *sdstd_reg_map(osl_t *osh, ulong addr, int size); +extern void sdstd_reg_unmap(osl_t *osh, ulong addr, int size); + +/* Interrupt (de)registration routines */ +extern int sdstd_register_irq(sdioh_info_t *sd, uint irq); +extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); + +/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ +extern void sdstd_lock(sdioh_info_t *sd); +extern void sdstd_unlock(sdioh_info_t *sd); +extern void sdstd_waitlockfree(sdioh_info_t *sd); + +/* OS-specific wrappers for safe concurrent register access */ +extern void sdstd_os_lock_irqsave(sdioh_info_t *sd, ulong* flags); +extern void sdstd_os_unlock_irqrestore(sdioh_info_t *sd, ulong* flags); + +/* OS-specific wait-for-interrupt-or-status */ +extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits); + +/* used by bcmsdstd_linux [implemented in sdstd] */ +extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd); +extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); +extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); +extern void sdstd_3_check_and_do_tuning(sdioh_info_t *sd, int tuning_param); +extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); +extern int sdstd_3_get_tune_state(sdioh_info_t *sd); +extern int sdstd_3_get_data_state(sdioh_info_t *sd); +extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); +extern void sdstd_3_set_data_state(sdioh_info_t *sd, int state); +extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); +extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); +extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode); + +/* used by sdstd [implemented in bcmsdstd_linux/ndis] */ +extern void sdstd_3_start_tuning(sdioh_info_t *sd); +extern void sdstd_3_osinit_tuning(sdioh_info_t *sd); +extern void sdstd_3_osclean_tuning(sdioh_info_t *sd); + +extern void sdstd_enable_disable_periodic_timer(sdioh_info_t * sd, uint val); + +extern sdioh_info_t *sdioh_attach(osl_t *osh, void *bar0, uint irq); +extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); +#endif /* _BCM_SD_STD_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmspi.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmspi.h new file mode 100644 index 000000000000..193dc8e0c9ca --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmspi.h @@ -0,0 +1,40 @@ +/* + * Broadcom SPI Low-Level Hardware Driver API + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmspi.h 241182 2011-02-17 21:50:03Z $ + */ +#ifndef _BCM_SPI_H +#define _BCM_SPI_H + +extern void spi_devintr_off(sdioh_info_t *sd); +extern void spi_devintr_on(sdioh_info_t *sd); +extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); +extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); +extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); +extern bool spi_hw_attach(sdioh_info_t *sd); +extern bool spi_hw_detach(sdioh_info_t *sd); +extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); +extern void spi_spinbits(sdioh_info_t *sd); +extern void spi_waitbits(sdioh_info_t *sd, bool yield); + +#endif /* _BCM_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmspibrcm.h new file mode 100644 index 000000000000..c81e6049ae03 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmspibrcm.h @@ -0,0 +1,162 @@ +/* + * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmspibrcm.h 373331 2012-12-07 04:46:22Z $ + */ +#ifndef _BCM_SPI_BRCM_H +#define _BCM_SPI_BRCM_H + +#ifndef SPI_MAX_IOFUNCS +/* Maximum number of I/O funcs */ +#define SPI_MAX_IOFUNCS 4 +#endif +/* global msglevel for debug messages - bitvals come from sdiovar.h */ + +#if defined(DHD_DEBUG) +#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) +#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) +#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) +#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0) +#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) +#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0) +#else +#define sd_err(x) +#define sd_trace(x) +#define sd_info(x) +#define sd_debug(x) +#define sd_data(x) +#define sd_ctrl(x) +#endif + +#define sd_log(x) + +#define SDIOH_ASSERT(exp) \ + do { if (!(exp)) \ + printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ + } while (0) + +#define BLOCK_SIZE_F1 64 +#define BLOCK_SIZE_F2 2048 +#define BLOCK_SIZE_F3 2048 + +/* internal return code */ +#define SUCCESS 0 +#undef ERROR +#define ERROR 1 +#define ERROR_UF 2 +#define ERROR_OF 3 + +/* private bus modes */ +#define SDIOH_MODE_SPI 0 + +#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ +#define USE_MULTIBLOCK 0x4 + +struct sdioh_info { + uint cfg_bar; /* pci cfg address for bar */ + uint32 caps; /* cached value of capabilities reg */ + void *bar0; /* BAR0 for PCI Device */ + osl_t *osh; /* osh handler */ + void *controller; /* Pointer to SPI Controller's private data struct */ + uint lockcount; /* nest count of spi_lock() calls */ + bool client_intr_enabled; /* interrupt connnected flag */ + bool intr_handler_valid; /* client driver interrupt handler valid */ + sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ + void *intr_handler_arg; /* argument to call interrupt handler */ + bool initialized; /* card initialized */ + uint32 target_dev; /* Target device ID */ + uint32 intmask; /* Current active interrupts */ + void *sdos_info; /* Pointer to per-OS private data */ + uint32 controller_type; /* Host controller type */ + uint8 version; /* Host Controller Spec Compliance Version */ + uint irq; /* Client irq */ + uint32 intrcount; /* Client interrupts */ + uint32 local_intrcount; /* Controller interrupts */ + bool host_init_done; /* Controller initted */ + bool card_init_done; /* Client SDIO interface initted */ + bool polled_mode; /* polling for command completion */ + + bool sd_use_dma; /* DMA on CMD53 */ + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + /* Must be on for sd_multiblock to be effective */ + bool use_client_ints; /* If this is false, make sure to restore */ + /* polling hack in wl_linux.c:wl_timer() */ + int adapter_slot; /* Maybe dealing with multiple slots/controllers */ + int sd_mode; /* SD1/SD4/SPI */ + int client_block_size[SPI_MAX_IOFUNCS]; /* Blocksize */ + uint32 data_xfer_count; /* Current transfer */ + uint16 card_rca; /* Current Address */ + uint8 num_funcs; /* Supported funcs on client */ + uint32 card_dstatus; /* 32bit device status */ + uint32 com_cis_ptr; + uint32 func_cis_ptr[SPI_MAX_IOFUNCS]; + void *dma_buf; + ulong dma_phys; + int r_cnt; /* rx count */ + int t_cnt; /* tx_count */ + uint32 wordlen; /* host processor 16/32bits */ + uint32 prev_fun; + uint32 chip; + uint32 chiprev; + bool resp_delay_all; + bool dwordmode; + bool resp_delay_new; + + struct spierrstats_t spierrstats; +}; + +/************************************************************ + * Internal interfaces: per-port references into bcmspibrcm.c + */ + +/* Global message bits */ +extern uint sd_msglevel; + +/************************************************************** + * Internal interfaces: bcmspibrcm.c references to per-port code + */ + +/* Interrupt (de)registration routines */ +extern int spi_register_irq(sdioh_info_t *sd, uint irq); +extern void spi_free_irq(uint irq, sdioh_info_t *sd); + +/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ +extern void spi_lock(sdioh_info_t *sd); +extern void spi_unlock(sdioh_info_t *sd); + +/* Allocate/init/free per-OS private data */ +extern int spi_osinit(sdioh_info_t *sd); +extern void spi_osfree(sdioh_info_t *sd); + +#define SPI_RW_FLAG_M BITFIELD_MASK(1) /* Bit [31] - R/W Command Bit */ +#define SPI_RW_FLAG_S 31 +#define SPI_ACCESS_M BITFIELD_MASK(1) /* Bit [30] - Fixed/Incr Access */ +#define SPI_ACCESS_S 30 +#define SPI_FUNCTION_M BITFIELD_MASK(2) /* Bit [29:28] - Function Number */ +#define SPI_FUNCTION_S 28 +#define SPI_REG_ADDR_M BITFIELD_MASK(17) /* Bit [27:11] - Address */ +#define SPI_REG_ADDR_S 11 +#define SPI_LEN_M BITFIELD_MASK(11) /* Bit [10:0] - Packet length */ +#define SPI_LEN_S 0 + +#endif /* _BCM_SPI_BRCM_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_fmt.h new file mode 100644 index 000000000000..bfb8f1dea0ff --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_fmt.h @@ -0,0 +1,633 @@ +/* + * SROM format definition. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsrom_fmt.h 473704 2014-04-29 15:49:57Z $ + */ + +#ifndef _bcmsrom_fmt_h_ +#define _bcmsrom_fmt_h_ + +#define SROM_MAXREV 11 /* max revisiton supported by driver */ + +/* Maximum srom: 12 Kilobits == 1536 bytes */ +#define SROM_MAX 1536 +#define SROM_MAXW 384 +#define VARS_MAX 4096 + +/* PCI fields */ +#define PCI_F0DEVID 48 + + +#define SROM_WORDS 64 + +#define SROM3_SWRGN_OFF 28 /* s/w region offset in words */ + +#define SROM_SSID 2 +#define SROM_SVID 3 + +#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_ET0 39 +#define SROM_MACMID_ET0 40 +#define SROM_MACLO_ET0 41 +#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 SROM2_ENETPHY 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 accomodate + * MIMO features. It assumes up to two PCIE functions and 440 bytes + * of useable srom i.e. the useable 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_AA2G_MASK 0x00ff +#define SROM4_AA2G_SHIFT 0 +#define SROM4_AA5G_MASK 0xff00 +#define SROM4_AA5G_SHIFT 8 + +#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 + +/* Fields in the ITT_MAXP and 5GLH_MAXP words */ +#define B2G_MAXP_MASK 0xff +#define B2G_ITT_SHIFT 8 +#define B5G_MAXP_MASK 0xff +#define B5G_ITT_SHIFT 8 +#define B5GH_MAXP_MASK 0xff +#define B5GL_MAXP_SHIFT 8 + +/* 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_SIGN 64 + +#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 + +#define SROM8_EXTLNAGAIN 93 + +/* Temperature delta for PHY calibration */ +#define SROM8_PHYCAL_TEMPDELTA 94 + +/* Measured power 1 & 2, 0-13 bits at offset 95, MSB 2 bits are unused for now. */ +#define SROM8_MPWR_1_AND_2 95 + + +/* 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) + +#define SROM8_CRCREV 219 + +/* 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 +#define SROM8_RXGAINERR_2G 205 +#define SROM8_RXGAINERR_5GL 206 +#define SROM8_RXGAINERR_5GM 207 +#define SROM8_RXGAINERR_5GH 208 +#define SROM8_RXGAINERR_5GU 209 +#define SROM8_SUBBAND_PPR 210 +#define SROM8_PCIEINGRESS_WAR 211 +#define SROM9_SAR 212 + +#define SROM8_NOISELVL_2G 213 +#define SROM8_NOISELVL_5GL 214 +#define SROM8_NOISELVL_5GM 215 +#define SROM8_NOISELVL_5GH 216 +#define SROM8_NOISELVL_5GU 217 +#define SROM8_NOISECALOFFSET 218 + +#define SROM9_REV_CRC 219 + +#define SROM10_CCKPWROFFSET 218 +#define SROM10_SIGN 219 +#define SROM10_SWCTRLMAP_2G 220 +#define SROM10_CRCREV 229 + +#define SROM10_WORDS 230 +#define SROM10_SIGNATURE SROM4_SIGNATURE + + +/* SROM REV 11 */ +#define SROM11_BREV 65 + +#define SROM11_BFL0 66 +#define SROM11_BFL1 67 +#define SROM11_BFL2 68 +#define SROM11_BFL3 69 +#define SROM11_BFL4 70 +#define SROM11_BFL5 71 + +#define SROM11_MACHI 72 +#define SROM11_MACMID 73 +#define SROM11_MACLO 74 + +#define SROM11_CCODE 75 +#define SROM11_REGREV 76 + +#define SROM11_LEDBH10 77 +#define SROM11_LEDBH32 78 + +#define SROM11_LEDDC 79 + +#define SROM11_AA 80 + +#define SROM11_AGBG10 81 +#define SROM11_AGBG2A0 82 +#define SROM11_AGA21 83 + +#define SROM11_TXRXC 84 + +#define SROM11_FEM_CFG1 85 +#define SROM11_FEM_CFG2 86 + +/* Masks and offsets for FEM_CFG */ +#define SROM11_FEMCTRL_MASK 0xf800 +#define SROM11_FEMCTRL_SHIFT 11 +#define SROM11_PAPDCAP_MASK 0x0400 +#define SROM11_PAPDCAP_SHIFT 10 +#define SROM11_TWORANGETSSI_MASK 0x0200 +#define SROM11_TWORANGETSSI_SHIFT 9 +#define SROM11_PDGAIN_MASK 0x01f0 +#define SROM11_PDGAIN_SHIFT 4 +#define SROM11_EPAGAIN_MASK 0x000e +#define SROM11_EPAGAIN_SHIFT 1 +#define SROM11_TSSIPOSSLOPE_MASK 0x0001 +#define SROM11_TSSIPOSSLOPE_SHIFT 0 +#define SROM11_GAINCTRLSPH_MASK 0xf800 +#define SROM11_GAINCTRLSPH_SHIFT 11 + +#define SROM11_THERMAL 87 +#define SROM11_MPWR_RAWTS 88 +#define SROM11_TS_SLP_OPT_CORRX 89 +#define SROM11_XTAL_FREQ 90 +#define SROM11_5GB0_4080_W0_A1 91 +#define SROM11_PHYCAL_TEMPDELTA 92 +#define SROM11_MPWR_1_AND_2 93 +#define SROM11_5GB0_4080_W1_A1 94 +#define SROM11_TSSIFLOOR_2G 95 +#define SROM11_TSSIFLOOR_5GL 96 +#define SROM11_TSSIFLOOR_5GM 97 +#define SROM11_TSSIFLOOR_5GH 98 +#define SROM11_TSSIFLOOR_5GU 99 + +/* Masks and offsets for Terrmal parameters */ +#define SROM11_TEMPS_PERIOD_MASK 0xf0 +#define SROM11_TEMPS_PERIOD_SHIFT 4 +#define SROM11_TEMPS_HYSTERESIS_MASK 0x0f +#define SROM11_TEMPS_HYSTERESIS_SHIFT 0 +#define SROM11_TEMPCORRX_MASK 0xfc +#define SROM11_TEMPCORRX_SHIFT 2 +#define SROM11_TEMPSENSE_OPTION_MASK 0x3 +#define SROM11_TEMPSENSE_OPTION_SHIFT 0 + +#define SROM11_PDOFF_2G_40M_A0_MASK 0x000f +#define SROM11_PDOFF_2G_40M_A0_SHIFT 0 +#define SROM11_PDOFF_2G_40M_A1_MASK 0x00f0 +#define SROM11_PDOFF_2G_40M_A1_SHIFT 4 +#define SROM11_PDOFF_2G_40M_A2_MASK 0x0f00 +#define SROM11_PDOFF_2G_40M_A2_SHIFT 8 +#define SROM11_PDOFF_2G_40M_VALID_MASK 0x8000 +#define SROM11_PDOFF_2G_40M_VALID_SHIFT 15 + +#define SROM11_PDOFF_2G_40M 100 +#define SROM11_PDOFF_40M_A0 101 +#define SROM11_PDOFF_40M_A1 102 +#define SROM11_PDOFF_40M_A2 103 +#define SROM11_5GB0_4080_W2_A1 103 +#define SROM11_PDOFF_80M_A0 104 +#define SROM11_PDOFF_80M_A1 105 +#define SROM11_PDOFF_80M_A2 106 +#define SROM11_5GB1_4080_W0_A1 106 + +#define SROM11_SUBBAND5GVER 107 + +/* Per-path fields and offset */ +#define MAX_PATH_SROM_11 3 +#define SROM11_PATH0 108 +#define SROM11_PATH1 128 +#define SROM11_PATH2 148 + +#define SROM11_2G_MAXP 0 +#define SROM11_5GB1_4080_PA 0 +#define SROM11_2G_PA 1 +#define SROM11_5GB2_4080_PA 2 +#define SROM11_RXGAINS1 4 +#define SROM11_RXGAINS 5 +#define SROM11_5GB3_4080_PA 5 +#define SROM11_5GB1B0_MAXP 6 +#define SROM11_5GB3B2_MAXP 7 +#define SROM11_5GB0_PA 8 +#define SROM11_5GB1_PA 11 +#define SROM11_5GB2_PA 14 +#define SROM11_5GB3_PA 17 + +/* Masks and offsets for rxgains */ +#define SROM11_RXGAINS5GTRELNABYPA_MASK 0x8000 +#define SROM11_RXGAINS5GTRELNABYPA_SHIFT 15 +#define SROM11_RXGAINS5GTRISOA_MASK 0x7800 +#define SROM11_RXGAINS5GTRISOA_SHIFT 11 +#define SROM11_RXGAINS5GELNAGAINA_MASK 0x0700 +#define SROM11_RXGAINS5GELNAGAINA_SHIFT 8 +#define SROM11_RXGAINS2GTRELNABYPA_MASK 0x0080 +#define SROM11_RXGAINS2GTRELNABYPA_SHIFT 7 +#define SROM11_RXGAINS2GTRISOA_MASK 0x0078 +#define SROM11_RXGAINS2GTRISOA_SHIFT 3 +#define SROM11_RXGAINS2GELNAGAINA_MASK 0x0007 +#define SROM11_RXGAINS2GELNAGAINA_SHIFT 0 +#define SROM11_RXGAINS5GHTRELNABYPA_MASK 0x8000 +#define SROM11_RXGAINS5GHTRELNABYPA_SHIFT 15 +#define SROM11_RXGAINS5GHTRISOA_MASK 0x7800 +#define SROM11_RXGAINS5GHTRISOA_SHIFT 11 +#define SROM11_RXGAINS5GHELNAGAINA_MASK 0x0700 +#define SROM11_RXGAINS5GHELNAGAINA_SHIFT 8 +#define SROM11_RXGAINS5GMTRELNABYPA_MASK 0x0080 +#define SROM11_RXGAINS5GMTRELNABYPA_SHIFT 7 +#define SROM11_RXGAINS5GMTRISOA_MASK 0x0078 +#define SROM11_RXGAINS5GMTRISOA_SHIFT 3 +#define SROM11_RXGAINS5GMELNAGAINA_MASK 0x0007 +#define SROM11_RXGAINS5GMELNAGAINA_SHIFT 0 + +/* Power per rate */ +#define SROM11_CCKBW202GPO 168 +#define SROM11_CCKBW20UL2GPO 169 +#define SROM11_MCSBW202GPO 170 +#define SROM11_MCSBW202GPO_1 171 +#define SROM11_MCSBW402GPO 172 +#define SROM11_MCSBW402GPO_1 173 +#define SROM11_DOT11AGOFDMHRBW202GPO 174 +#define SROM11_OFDMLRBW202GPO 175 + +#define SROM11_MCSBW205GLPO 176 +#define SROM11_MCSBW205GLPO_1 177 +#define SROM11_MCSBW405GLPO 178 +#define SROM11_MCSBW405GLPO_1 179 +#define SROM11_MCSBW805GLPO 180 +#define SROM11_MCSBW805GLPO_1 181 +#define SROM11_RPCAL_2G 182 +#define SROM11_RPCAL_5GL 183 +#define SROM11_MCSBW205GMPO 184 +#define SROM11_MCSBW205GMPO_1 185 +#define SROM11_MCSBW405GMPO 186 +#define SROM11_MCSBW405GMPO_1 187 +#define SROM11_MCSBW805GMPO 188 +#define SROM11_MCSBW805GMPO_1 189 +#define SROM11_RPCAL_5GM 190 +#define SROM11_RPCAL_5GH 191 +#define SROM11_MCSBW205GHPO 192 +#define SROM11_MCSBW205GHPO_1 193 +#define SROM11_MCSBW405GHPO 194 +#define SROM11_MCSBW405GHPO_1 195 +#define SROM11_MCSBW805GHPO 196 +#define SROM11_MCSBW805GHPO_1 197 +#define SROM11_RPCAL_5GU 198 +#define SROM11_PDOFF_2G_CCK 199 +#define SROM11_MCSLR5GLPO 200 +#define SROM11_MCSLR5GMPO 201 +#define SROM11_MCSLR5GHPO 202 + +#define SROM11_SB20IN40HRPO 203 +#define SROM11_SB20IN80AND160HR5GLPO 204 +#define SROM11_SB40AND80HR5GLPO 205 +#define SROM11_SB20IN80AND160HR5GMPO 206 +#define SROM11_SB40AND80HR5GMPO 207 +#define SROM11_SB20IN80AND160HR5GHPO 208 +#define SROM11_SB40AND80HR5GHPO 209 +#define SROM11_SB20IN40LRPO 210 +#define SROM11_SB20IN80AND160LR5GLPO 211 +#define SROM11_SB40AND80LR5GLPO 212 +#define SROM11_TXIDXCAP2G 212 +#define SROM11_SB20IN80AND160LR5GMPO 213 +#define SROM11_SB40AND80LR5GMPO 214 +#define SROM11_TXIDXCAP5G 214 +#define SROM11_SB20IN80AND160LR5GHPO 215 +#define SROM11_SB40AND80LR5GHPO 216 + +#define SROM11_DOT11AGDUPHRPO 217 +#define SROM11_DOT11AGDUPLRPO 218 + +/* MISC */ +#define SROM11_PCIEINGRESS_WAR 220 +#define SROM11_SAR 221 + +#define SROM11_NOISELVL_2G 222 +#define SROM11_NOISELVL_5GL 223 +#define SROM11_NOISELVL_5GM 224 +#define SROM11_NOISELVL_5GH 225 +#define SROM11_NOISELVL_5GU 226 + +#define SROM11_RXGAINERR_2G 227 +#define SROM11_RXGAINERR_5GL 228 +#define SROM11_RXGAINERR_5GM 229 +#define SROM11_RXGAINERR_5GH 230 +#define SROM11_RXGAINERR_5GU 231 + +#define SROM11_SIGN 64 +#define SROM11_CRCREV 233 + +#define SROM11_WORDS 234 +#define SROM11_SIGNATURE 0x0634 + +typedef struct { + uint8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */ + uint8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */ + uint8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */ + uint8 triso; /* TR switch isolation */ + uint8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */ +} srom_fem_t; + +#endif /* _bcmsrom_fmt_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_tbl.h new file mode 100644 index 000000000000..4f84428eec0c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_tbl.h @@ -0,0 +1,1029 @@ +/* + * Table that encodes the srom formats for PCI/PCIe NICs. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsrom_tbl.h 471127 2014-04-17 23:24:23Z $ + */ + +#ifndef _bcmsrom_tbl_h_ +#define _bcmsrom_tbl_h_ + +#include "sbpcmcia.h" +#include "wlioctl.h" +#include + +typedef struct { + const char *name; + uint32 revmask; + uint32 flags; + uint16 off; + uint16 mask; +} sromvar_t; + +#define SRFL_MORE 1 /* value continues as described by the next entry */ +#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 */ +#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */ +#define SRFL_ARRAY 0x100 /* value is in an array. All elements EXCEPT FOR THE LAST + * ONE in the array should have this flag set. + */ + + +#define SROM_DEVID_PCIE 48 + +/* Assumptions: + * - Ethernet address spans across 3 consective 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 sromvar_t pci_sromvars[] = { +#if defined(CABLECPE) + {"devid", 0xffffff00, SRFL_PRHEX, PCI_F0DEVID, 0xffff}, +#elif defined(BCMPCIEDEV) && defined(BCMPCIEDEV_ENABLED) + {"devid", 0xffffff00, SRFL_PRHEX, SROM_DEVID_PCIE, 0xffff}, +#else + {"devid", 0xffffff00, SRFL_PRHEX|SRFL_NOVAR, PCI_F0DEVID, 0xffff}, +#endif + {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK}, + {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, + {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, + {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, + {"boardflags", 0x00000004, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM_BFL2, 0xffff}, + {"boardflags", 0x00000008, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM3_BFL2, 0xffff}, + {"boardflags", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL0, 0xffff}, + {"", 0, 0, SROM4_BFL1, 0xffff}, + {"boardflags", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL0, 0xffff}, + {"", 0, 0, SROM5_BFL1, 0xffff}, + {"boardflags", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL0, 0xffff}, + {"", 0, 0, SROM8_BFL1, 0xffff}, + {"boardflags2", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL2, 0xffff}, + {"", 0, 0, SROM4_BFL3, 0xffff}, + {"boardflags2", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL2, 0xffff}, + {"", 0, 0, SROM5_BFL3, 0xffff}, + {"boardflags2", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL2, 0xffff}, + {"", 0, 0, SROM8_BFL3, 0xffff}, + {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, + {"subvid", 0xfffffffc, SRFL_PRHEX, SROM_SVID, 0xffff}, + {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, + {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff}, + {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff}, + {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff}, + {"boardnum", 0x00000700, 0, SROM8_MACLO, 0xffff}, + {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, + {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, + {"regrev", 0x00000010, 0, SROM4_REGREV, 0x00ff}, + {"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff}, + {"regrev", 0x00000700, 0, SROM8_REGREV, 0x00ff}, + {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff}, + {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, + {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff}, + {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, + {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff}, + {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, + {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff}, + {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, + {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff}, + {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, + {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff}, + {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, + {"ledbh0", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, + {"ledbh1", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, + {"ledbh2", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, + {"ledbh3", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, + {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, + {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, + {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, + {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff}, + {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff}, + {"pa0b0", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, + {"pa0b1", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, + {"pa0b2", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, + {"pa0itssit", 0x00000700, 0, SROM8_W0_ITTMAXP, 0xff00}, + {"pa0maxpwr", 0x00000700, 0, SROM8_W0_ITTMAXP, 0x00ff}, + {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff}, + {"opo", 0x00000700, 0, SROM8_2G_OFDMPO, 0x00ff}, + {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, + {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff}, + {"aa2g", 0x00000700, 0, SROM8_AA, 0x00ff}, + {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, + {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, + {"aa5g", 0x00000700, 0, SROM8_AA, 0xff00}, + {"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff}, + {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00}, + {"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff}, + {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00}, + {"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff}, + {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00}, + {"ag0", 0x00000700, 0, SROM8_AG10, 0x00ff}, + {"ag1", 0x00000700, 0, SROM8_AG10, 0xff00}, + {"ag2", 0x00000700, 0, SROM8_AG32, 0x00ff}, + {"ag3", 0x00000700, 0, SROM8_AG32, 0xff00}, + {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, + {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, + {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, + {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, + {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, + {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, + {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, + {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, + {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, + {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00}, + {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, + {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, + {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff}, + {"pa1b0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, + {"pa1b1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, + {"pa1b2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, + {"pa1lob0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, + {"pa1lob1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, + {"pa1lob2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, + {"pa1hib0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, + {"pa1hib1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, + {"pa1hib2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, + {"pa1itssit", 0x00000700, 0, SROM8_W1_ITTMAXP, 0xff00}, + {"pa1maxpwr", 0x00000700, 0, SROM8_W1_ITTMAXP, 0x00ff}, + {"pa1lomaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0xff00}, + {"pa1himaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, + {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, + {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, + {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, + {"bxa2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x1800}, + {"rssisav2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x0700}, + {"rssismc2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x000f}, + {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, + {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, + {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, + {"bxa5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x1800}, + {"rssisav5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x0700}, + {"rssismc5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x000f}, + {"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff}, + {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00}, + {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff}, + {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00}, + {"tri2g", 0x00000700, 0, SROM8_TRI52G, 0x00ff}, + {"tri5g", 0x00000700, 0, SROM8_TRI52G, 0xff00}, + {"tri5gl", 0x00000700, 0, SROM8_TRI5GHL, 0x00ff}, + {"tri5gh", 0x00000700, 0, SROM8_TRI5GHL, 0xff00}, + {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, + {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, + {"rxpo2g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, + {"rxpo5g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, + {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK}, + {"txchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, + {"tssipos2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK}, + {"extpagain2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK}, + {"pdetrange2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK}, + {"triso2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, + {"antswctl2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK}, + {"tssipos5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK}, + {"extpagain5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK}, + {"pdetrange5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK}, + {"triso5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, + {"antswctl5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK}, + {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff}, + {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, + {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff}, + {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, + {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff}, + {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, + {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff}, + {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, + {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff}, + {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, + {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff}, + {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, + {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff}, + {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, + {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff}, + {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, + + {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, + {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, + {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, + {"ccode", 0x00000700, SRFL_CCODE, SROM8_CCODE, 0xffff}, + {"macaddr", 0x00000700, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, + {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, + {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, + {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, + {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff}, + {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff}, + {"leddc", 0x00000700, SRFL_NOFFS|SRFL_LEDDC, SROM8_LEDDC, 0xffff}, + {"leddc", 0x000000e0, SRFL_NOFFS|SRFL_LEDDC, SROM5_LEDDC, 0xffff}, + {"leddc", 0x00000010, SRFL_NOFFS|SRFL_LEDDC, SROM4_LEDDC, 0xffff}, + {"leddc", 0x00000008, SRFL_NOFFS|SRFL_LEDDC, SROM3_LEDDC, 0xffff}, + + {"tempthresh", 0x00000700, 0, SROM8_THERMAL, 0xff00}, + {"tempoffset", 0x00000700, 0, SROM8_THERMAL, 0x00ff}, + {"rawtempsense", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff}, + {"measpower", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00}, + {"tempsense_slope", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff}, + {"tempcorrx", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00}, + {"tempsense_option", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300}, + {"freqoffset_corr", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f}, + {"iqcal_swp_dis", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010}, + {"hw_iqcal_en", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020}, + {"elna2g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0x00ff}, + {"elna5g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0xff00}, + {"phycal_tempdelta", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff}, + {"temps_period", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x0f00}, + {"temps_hysteresis", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0xf000}, + {"measpower1", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x007f}, + {"measpower2", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x3f80}, + + {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, + {"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, + {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, + {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, + {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, + {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, + {"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, + {"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, + {"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, + {"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, + {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, + {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, + {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, + {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, + {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, + {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, + {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, + {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, + {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, + {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, + {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, + {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, + {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, + {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, + {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, + {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, + {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, + {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, + {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, + {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, + {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, + {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, + {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, + {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, + {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, + {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, + {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, + {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, + {"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff}, + {"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff}, + {"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff}, + {"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff}, + {"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff}, + {"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff}, + {"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff}, + {"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff}, + {"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff}, + {"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff}, + {"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff}, + {"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff}, + {"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff}, + {"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff}, + {"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff}, + {"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff}, + {"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff}, + {"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff}, + {"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff}, + {"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff}, + {"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff}, + {"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff}, + {"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff}, + {"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff}, + {"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff}, + {"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff}, + {"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff}, + {"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff}, + {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff}, + {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff}, + {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff}, + {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, + {"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff}, + {"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff}, + {"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff}, + {"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, + + /* power per rate from sromrev 9 */ + {"cckbw202gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20, 0xffff}, + {"cckbw20ul2gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, + {"legofdmbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, + {"legofdmbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, + {"legofdmbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, + {"legofdmbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, + {"mcsbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw402gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, + {"mcsbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw405glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, + {"mcsbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw405gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, + {"mcsbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw405ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, + {"mcs32po", 0x00000600, 0, SROM9_PO_MCS32, 0xffff}, + {"legofdm40duppo", 0x00000600, 0, SROM9_PO_LOFDM40DUP, 0xffff}, + {"pcieingress_war", 0x00000700, 0, SROM8_PCIEINGRESS_WAR, 0xf}, + {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f}, + {"rxgainerr2ga1", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x07c0}, + {"rxgainerr2ga2", 0x00000700, 0, SROM8_RXGAINERR_2G, 0xf800}, + {"rxgainerr5gla0", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x003f}, + {"rxgainerr5gla1", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x07c0}, + {"rxgainerr5gla2", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0xf800}, + {"rxgainerr5gma0", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x003f}, + {"rxgainerr5gma1", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x07c0}, + {"rxgainerr5gma2", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0xf800}, + {"rxgainerr5gha0", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x003f}, + {"rxgainerr5gha1", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x07c0}, + {"rxgainerr5gha2", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0xf800}, + {"rxgainerr5gua0", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x003f}, + {"rxgainerr5gua1", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x07c0}, + {"rxgainerr5gua2", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0xf800}, + {"sar2g", 0x00000600, 0, SROM9_SAR, 0x00ff}, + {"sar5g", 0x00000600, 0, SROM9_SAR, 0xff00}, + {"noiselvl2ga0", 0x00000700, 0, SROM8_NOISELVL_2G, 0x001f}, + {"noiselvl2ga1", 0x00000700, 0, SROM8_NOISELVL_2G, 0x03e0}, + {"noiselvl2ga2", 0x00000700, 0, SROM8_NOISELVL_2G, 0x7c00}, + {"noiselvl5gla0", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x001f}, + {"noiselvl5gla1", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x03e0}, + {"noiselvl5gla2", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x7c00}, + {"noiselvl5gma0", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x001f}, + {"noiselvl5gma1", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x03e0}, + {"noiselvl5gma2", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x7c00}, + {"noiselvl5gha0", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x001f}, + {"noiselvl5gha1", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x03e0}, + {"noiselvl5gha2", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x7c00}, + {"noiselvl5gua0", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x001f}, + {"noiselvl5gua1", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x03e0}, + {"noiselvl5gua2", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x7c00}, + {"noisecaloffset", 0x00000300, 0, SROM8_NOISECALOFFSET, 0x00ff}, + {"noisecaloffset5g", 0x00000300, 0, SROM8_NOISECALOFFSET, 0xff00}, + {"subband5gver", 0x00000700, 0, SROM8_SUBBAND_PPR, 0x7}, + + {"cckPwrOffset", 0x00000400, 0, SROM10_CCKPWROFFSET, 0xffff}, + /* swctrlmap_2g array, note that the last element doesn't have SRFL_ARRAY flag set */ + {"swctrlmap_2g", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 1, 0xffff}, + {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 2, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 3, 0xffff}, + {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 4, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 5, 0xffff}, + {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 6, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 7, 0xffff}, + {"", 0x00000400, SRFL_PRHEX, SROM10_SWCTRLMAP_2G + 8, 0xffff}, + + /* sromrev 11 */ + {"boardflags3", 0xfffff800, SRFL_PRHEX|SRFL_MORE, SROM11_BFL4, 0xffff}, + {"", 0, 0, SROM11_BFL5, 0xffff}, + {"boardnum", 0xfffff800, 0, SROM11_MACLO, 0xffff}, + {"macaddr", 0xfffff800, SRFL_ETHADDR, SROM11_MACHI, 0xffff}, + {"ccode", 0xfffff800, SRFL_CCODE, SROM11_CCODE, 0xffff}, + {"regrev", 0xfffff800, 0, SROM11_REGREV, 0x00ff}, + {"ledbh0", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0x00ff}, + {"ledbh1", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0xff00}, + {"ledbh2", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0x00ff}, + {"ledbh3", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0xff00}, + {"leddc", 0xfffff800, SRFL_NOFFS|SRFL_LEDDC, SROM11_LEDDC, 0xffff}, + {"aa2g", 0xfffff800, 0, SROM11_AA, 0x00ff}, + {"aa5g", 0xfffff800, 0, SROM11_AA, 0xff00}, + {"agbg0", 0xfffff800, 0, SROM11_AGBG10, 0xff00}, + {"agbg1", 0xfffff800, 0, SROM11_AGBG10, 0x00ff}, + {"agbg2", 0xfffff800, 0, SROM11_AGBG2A0, 0xff00}, + {"aga0", 0xfffff800, 0, SROM11_AGBG2A0, 0x00ff}, + {"aga1", 0xfffff800, 0, SROM11_AGA21, 0xff00}, + {"aga2", 0xfffff800, 0, SROM11_AGA21, 0x00ff}, + {"txchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_SWITCH_MASK}, + + {"tssiposslope2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0001}, + {"epagain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x000e}, + {"pdgain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x01f0}, + {"tworangetssi2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0200}, + {"papdcap2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0400}, + {"femctrl", 0xfffff800, 0, SROM11_FEM_CFG1, 0xf800}, + + {"tssiposslope5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0001}, + {"epagain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x000e}, + {"pdgain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x01f0}, + {"tworangetssi5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0200}, + {"papdcap5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0400}, + {"gainctrlsph", 0xfffff800, 0, SROM11_FEM_CFG2, 0xf800}, + + {"tempthresh", 0xfffff800, 0, SROM11_THERMAL, 0xff00}, + {"tempoffset", 0xfffff800, 0, SROM11_THERMAL, 0x00ff}, + {"rawtempsense", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0x01ff}, + {"measpower", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0xfe00}, + {"tempsense_slope", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x00ff}, + {"tempcorrx", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0xfc00}, + {"tempsense_option", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x0300}, + {"xtalfreq", 0xfffff800, 0, SROM11_XTAL_FREQ, 0xffff}, + /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #1 */ + {"pa5gbw4080a1", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W0_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W1_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W2_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_4080_W0_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_4080_PA + 2, 0xffff}, + {"phycal_tempdelta", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x00ff}, + {"temps_period", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x0f00}, + {"temps_hysteresis", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0xf000}, + {"measpower1", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x007f}, + {"measpower2", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x3f80}, + {"tssifloor2g", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_2G, 0x03ff}, + {"tssifloor5g", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GL, 0x03ff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GM, 0x03ff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GH, 0x03ff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_5GU, 0x03ff}, + {"pdoffset2g40ma0", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x000f}, + {"pdoffset2g40ma1", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x00f0}, + {"pdoffset2g40ma2", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x0f00}, + {"pdoffset2g40mvalid", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x8000}, + {"pdoffset40ma0", 0xfffff800, 0, SROM11_PDOFF_40M_A0, 0xffff}, + {"pdoffset40ma1", 0xfffff800, 0, SROM11_PDOFF_40M_A1, 0xffff}, + {"pdoffset40ma2", 0xfffff800, 0, SROM11_PDOFF_40M_A2, 0xffff}, + {"pdoffset80ma0", 0xfffff800, 0, SROM11_PDOFF_80M_A0, 0xffff}, + {"pdoffset80ma1", 0xfffff800, 0, SROM11_PDOFF_80M_A1, 0xffff}, + {"pdoffset80ma2", 0xfffff800, 0, SROM11_PDOFF_80M_A2, 0xffff}, + + {"subband5gver", 0xfffff800, SRFL_PRHEX, SROM11_SUBBAND5GVER, 0xffff}, + {"paparambwver", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0xf000}, + /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #0 */ + {"pa5gbw4080a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 +SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, + /* Special PA Params for 4335 5G Band, 40 MHz BW */ + {"pa5gbw40a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_5GB3_PA + 2, 0xffff}, + /* Special PA Params for 4335 5G Band, 80 MHz BW */ + {"pa5gbw80a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, + /* Special PA Params for 4335 2G Band, CCK */ + {"pa2gccka0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_2G_PA + 2, 0xffff}, + + /* power per rate */ + {"cckbw202gpo", 0xfffff800, 0, SROM11_CCKBW202GPO, 0xffff}, + {"cckbw20ul2gpo", 0xfffff800, 0, SROM11_CCKBW20UL2GPO, 0xffff}, + {"mcsbw202gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW202GPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW202GPO_1, 0xffff}, + {"mcsbw402gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW402GPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW402GPO_1, 0xffff}, + {"dot11agofdmhrbw202gpo", 0xfffff800, 0, SROM11_DOT11AGOFDMHRBW202GPO, 0xffff}, + {"ofdmlrbw202gpo", 0xfffff800, 0, SROM11_OFDMLRBW202GPO, 0xffff}, + {"mcsbw205glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GLPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW205GLPO_1, 0xffff}, + {"mcsbw405glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GLPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW405GLPO_1, 0xffff}, + {"mcsbw805glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GLPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW805GLPO_1, 0xffff}, + {"mcsbw205gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GMPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW205GMPO_1, 0xffff}, + {"mcsbw405gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GMPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW405GMPO_1, 0xffff}, + {"mcsbw805gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GMPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW805GMPO_1, 0xffff}, + {"mcsbw205ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GHPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW205GHPO_1, 0xffff}, + {"mcsbw405ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GHPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW405GHPO_1, 0xffff}, + {"mcsbw805ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GHPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW805GHPO_1, 0xffff}, + {"mcslr5glpo", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0x0fff}, + {"mcslr5gmpo", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0xffff}, + {"mcslr5ghpo", 0xfffff800, 0, SROM11_MCSLR5GHPO, 0xffff}, + {"sb20in40hrpo", 0xfffff800, 0, SROM11_SB20IN40HRPO, 0xffff}, + {"sb20in80and160hr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GLPO, 0xffff}, + {"sb40and80hr5glpo", 0xfffff800, 0, SROM11_SB40AND80HR5GLPO, 0xffff}, + {"sb20in80and160hr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GMPO, 0xffff}, + {"sb40and80hr5gmpo", 0xfffff800, 0, SROM11_SB40AND80HR5GMPO, 0xffff}, + {"sb20in80and160hr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GHPO, 0xffff}, + {"sb40and80hr5ghpo", 0xfffff800, 0, SROM11_SB40AND80HR5GHPO, 0xffff}, + {"sb20in40lrpo", 0xfffff800, 0, SROM11_SB20IN40LRPO, 0xffff}, + {"sb20in80and160lr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GLPO, 0xffff}, + {"sb40and80lr5glpo", 0xfffff800, 0, SROM11_SB40AND80LR5GLPO, 0xffff}, + {"sb20in80and160lr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GMPO, 0xffff}, + {"sb40and80lr5gmpo", 0xfffff800, 0, SROM11_SB40AND80LR5GMPO, 0xffff}, + {"sb20in80and160lr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GHPO, 0xffff}, + {"sb40and80lr5ghpo", 0xfffff800, 0, SROM11_SB40AND80LR5GHPO, 0xffff}, + {"dot11agduphrpo", 0xfffff800, 0, SROM11_DOT11AGDUPHRPO, 0xffff}, + {"dot11agduplrpo", 0xfffff800, 0, SROM11_DOT11AGDUPLRPO, 0xffff}, + + /* Misc */ + {"sar2g", 0xfffff800, 0, SROM11_SAR, 0x00ff}, + {"sar5g", 0xfffff800, 0, SROM11_SAR, 0xff00}, + + {"noiselvl2ga0", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x001f}, + {"noiselvl2ga1", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x03e0}, + {"noiselvl2ga2", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x7c00}, + {"noiselvl5ga0", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x001f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x001f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x001f}, + {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x001f}, + {"noiselvl5ga1", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x03e0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x03e0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x03e0}, + {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x03e0}, + {"noiselvl5ga2", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x7c00}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x7c00}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x7c00}, + {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x7c00}, + + {"rxgainerr2ga0", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x003f}, + {"rxgainerr2ga1", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x07c0}, + {"rxgainerr2ga2", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0xf800}, + {"rxgainerr5ga0", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x003f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x003f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x003f}, + {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x003f}, + {"rxgainerr5ga1", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x07c0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x07c0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x07c0}, + {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x07c0}, + {"rxgainerr5ga2", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0xf800}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0xf800}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0xf800}, + {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0xf800}, + {"rpcal2g", 0xfffff800, 0, SROM11_RPCAL_2G, 0xffff}, + {"rpcal5gb0", 0xfffff800, 0, SROM11_RPCAL_5GL, 0xffff}, + {"rpcal5gb1", 0xfffff800, 0, SROM11_RPCAL_5GM, 0xffff}, + {"rpcal5gb2", 0xfffff800, 0, SROM11_RPCAL_5GH, 0xffff}, + {"rpcal5gb3", 0xfffff800, 0, SROM11_RPCAL_5GU, 0xffff}, + {"txidxcap2g", 0xfffff800, 0, SROM11_TXIDXCAP2G, 0x0ff0}, + {"txidxcap5g", 0xfffff800, 0, SROM11_TXIDXCAP5G, 0x0ff0}, + {"pdoffsetcckma0", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x000f}, + {"pdoffsetcckma1", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x00f0}, + {"pdoffsetcckma2", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x0f00}, + {NULL, 0, 0, 0, 0} +}; + +static const sromvar_t perpath_pci_sromvars[] = { + {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff}, + {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, + {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, + {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, + {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, + {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff}, + {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff}, + {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, + {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, + {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, + {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, + {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, + {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff}, + {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff}, + {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff}, + {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, + {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff}, + {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff}, + {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff}, + {"maxp2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0x00ff}, + {"itt2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, + {"pa2gw1a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, + {"pa2gw2a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, + {"maxp5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0x00ff}, + {"maxp5gha", 0x00000700, 0, SROM8_5GLH_MAXP, 0x00ff}, + {"maxp5gla", 0x00000700, 0, SROM8_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, + {"pa5gw1a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, + {"pa5gw2a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, + {"pa5glw0a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, + {"pa5glw1a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff}, + {"pa5glw2a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff}, + {"pa5ghw0a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, + {"pa5ghw1a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff}, + {"pa5ghw2a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff}, + + /* sromrev 11 */ + {"maxp2ga", 0xfffff800, 0, SROM11_2G_MAXP, 0x00ff}, + {"pa2ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_2G_PA + 2, 0xffff}, + {"rxgains5gmelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0007}, + {"rxgains5gmtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0078}, + {"rxgains5gmtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0080}, + {"rxgains5ghelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0700}, + {"rxgains5ghtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x7800}, + {"rxgains5ghtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x8000}, + {"rxgains2gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0007}, + {"rxgains2gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x0078}, + {"rxgains2gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x0080}, + {"rxgains5gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0700}, + {"rxgains5gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x7800}, + {"rxgains5gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x8000}, + {"maxp5ga", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0x00ff}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0xff00}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB3B2_MAXP, 0x00ff}, + {"", 0xfffff800, 0, SROM11_5GB3B2_MAXP, 0xff00}, + {"pa5ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_5GB3_PA + 2, 0xffff}, + + {NULL, 0, 0, 0, 0} +}; + +#if !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) +#define PHY_TYPE_HT 7 /* HT-Phy value */ +#define PHY_TYPE_N 4 /* N-Phy value */ +#define PHY_TYPE_LP 5 /* LP-Phy value */ +#endif /* !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) */ +#if !defined(PHY_TYPE_AC) +#define PHY_TYPE_AC 11 /* AC-Phy value */ +#endif /* !defined(PHY_TYPE_AC) */ +#if !defined(PHY_TYPE_NULL) +#define PHY_TYPE_NULL 0xf /* Invalid Phy value */ +#endif /* !defined(PHY_TYPE_NULL) */ + +typedef struct { + uint16 phy_type; + uint16 bandrange; + uint16 chain; + const char *vars; +} pavars_t; + +static const pavars_t pavars[] = { + /* HTPHY */ + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 2, "pa2gw0a2 pa2gw1a2 pa2gw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 2, "pa5glw0a2 pa5glw1a2 pa5glw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 2, "pa5gw0a2 pa5gw1a2 pa5gw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 2, "pa5ghw0a2 pa5ghw1a2 pa5ghw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 0, "pa5gw0a3 pa5gw1a3 pa5gw2a3"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 1, "pa5glw0a3 pa5glw1a3 pa5glw2a3"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 2, "pa5ghw0a3 pa5ghw1a3 pa5ghw2a3"}, + /* NPHY */ + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, + /* LPPHY */ + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_2G, 0, "pa0b0 pa0b1 pa0b2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GL, 0, "pa1lob0 pa1lob1 pa1lob2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GM, 0, "pa1b0 pa1b1 pa1b2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GH, 0, "pa1hib0 pa1hib1 pa1hib2"}, + /* ACPHY */ + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5ga2"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +/* pavars table when paparambwver is 1 */ +static const pavars_t pavars_bwver_1[] = { + /* ACPHY */ + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gccka0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga2"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5gbw40a0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw80a0"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +/* pavars table when paparambwver is 2 */ +static const pavars_t pavars_bwver_2[] = { + /* ACPHY */ + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw4080a0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 3, "pa5gbw4080a1"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +typedef struct { + uint16 phy_type; + uint16 bandrange; + const char *vars; +} povars_t; + +static const povars_t povars[] = { + /* NPHY */ + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, "mcs2gpo0 mcs2gpo1 mcs2gpo2 mcs2gpo3 " + "mcs2gpo4 mcs2gpo5 mcs2gpo6 mcs2gpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, "mcs5glpo0 mcs5glpo1 mcs5glpo2 mcs5glpo3 " + "mcs5glpo4 mcs5glpo5 mcs5glpo6 mcs5glpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, "mcs5gpo0 mcs5gpo1 mcs5gpo2 mcs5gpo3 " + "mcs5gpo4 mcs5gpo5 mcs5gpo6 mcs5gpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, "mcs5ghpo0 mcs5ghpo1 mcs5ghpo2 mcs5ghpo3 " + "mcs5ghpo4 mcs5ghpo5 mcs5ghpo6 mcs5ghpo7"}, + {PHY_TYPE_NULL, 0, ""} +}; + +typedef struct { + uint8 tag; /* Broadcom subtag name */ + uint32 revmask; /* Supported cis_sromrev */ + uint8 len; /* Length field of the tuple, note that it includes the + * subtag name (1 byte): 1 + tuple content length + */ + const char *params; +} cis_tuple_t; + +#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */ +#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */ +#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */ +#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */ + +static const cis_tuple_t cis_hnbuvars[] = { + {OTP_RAW1, 0xffffffff, 0, ""}, /* special case */ + {OTP_VERS_1, 0xffffffff, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */ + {OTP_MANFID, 0xffffffff, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */ + /* Unified OTP: tupple to embed USB manfid inside SDIO CIS */ + {HNBU_UMANFID, 0xffffffff, 8, "8usbmanfid"}, + {HNBU_SROMREV, 0xffffffff, 2, "1sromrev"}, + /* NOTE: subdevid is also written to boardtype. + * Need to write HNBU_BOARDTYPE to change it if it is different. + */ + {HNBU_CHIPID, 0xffffffff, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"}, + {HNBU_BOARDREV, 0xffffffff, 3, "2boardrev"}, + {HNBU_PAPARMS, 0xffffffff, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"}, + {HNBU_AA, 0xffffffff, 3, "1aa2g 1aa5g"}, + {HNBU_AA, 0xffffffff, 3, "1aa0 1aa1"}, /* backward compatibility */ + {HNBU_AG, 0xffffffff, 5, "1ag0 1ag1 1ag2 1ag3"}, + {HNBU_BOARDFLAGS, 0xffffffff, 21, "4boardflags 4boardflags2 4boardflags3 " + "4boardflags4 4boardflags5 "}, + {HNBU_LEDS, 0xffffffff, 17, "1ledbh0 1ledbh1 1ledbh2 1ledbh3 1ledbh4 1ledbh5 " + "1ledbh6 1ledbh7 1ledbh8 1ledbh9 1ledbh10 1ledbh11 1ledbh12 1ledbh13 1ledbh14 1ledbh15"}, + {HNBU_CCODE, 0xffffffff, 4, "2ccode 1cctl"}, + {HNBU_CCKPO, 0xffffffff, 3, "2cckpo"}, + {HNBU_OFDMPO, 0xffffffff, 5, "4ofdmpo"}, + {HNBU_PAPARMS5G, 0xffffffff, 23, "2pa1b0 2pa1b1 2pa1b2 2pa1lob0 2pa1lob1 2pa1lob2 " + "2pa1hib0 2pa1hib1 2pa1hib2 1pa1itssit " + "1pa1maxpwr 1pa1lomaxpwr 1pa1himaxpwr"}, + {HNBU_RDLID, 0xffffffff, 3, "2rdlid"}, + {HNBU_RSSISMBXA2G, 0xffffffff, 3, "0rssismf2g 0rssismc2g " + "0rssisav2g 0bxa2g"}, /* special case */ + {HNBU_RSSISMBXA5G, 0xffffffff, 3, "0rssismf5g 0rssismc5g " + "0rssisav5g 0bxa5g"}, /* special case */ + {HNBU_XTALFREQ, 0xffffffff, 5, "4xtalfreq"}, + {HNBU_TRI2G, 0xffffffff, 2, "1tri2g"}, + {HNBU_TRI5G, 0xffffffff, 4, "1tri5gl 1tri5g 1tri5gh"}, + {HNBU_RXPO2G, 0xffffffff, 2, "1rxpo2g"}, + {HNBU_RXPO5G, 0xffffffff, 2, "1rxpo5g"}, + {HNBU_BOARDNUM, 0xffffffff, 3, "2boardnum"}, + {HNBU_MACADDR, 0xffffffff, 7, "6macaddr"}, /* special case */ + {HNBU_RDLSN, 0xffffffff, 3, "2rdlsn"}, + {HNBU_BOARDTYPE, 0xffffffff, 3, "2boardtype"}, + {HNBU_LEDDC, 0xffffffff, 3, "2leddc"}, + {HNBU_RDLRNDIS, 0xffffffff, 2, "1rdlndis"}, + {HNBU_CHAINSWITCH, 0xffffffff, 5, "1txchain 1rxchain 2antswitch"}, + {HNBU_REGREV, 0xffffffff, 2, "1regrev"}, + {HNBU_FEM, 0x000007fe, 5, "0antswctl2g 0triso2g 0pdetrange2g 0extpagain2g " + "0tssipos2g 0antswctl5g 0triso5g 0pdetrange5g 0extpagain5g 0tssipos5g"}, /* special case */ + {HNBU_PAPARMS_C0, 0x000007fe, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 " + "2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 2pa5gw1a0 2pa5gw2a0 " + "2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 2pa5ghw1a0 2pa5ghw2a0"}, + {HNBU_PAPARMS_C1, 0x000007fe, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 " + "2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 2pa5gw1a1 2pa5gw2a1 " + "2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 2pa5ghw1a1 2pa5ghw2a1"}, + {HNBU_PO_CCKOFDM, 0xffffffff, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo " + "4ofdm5ghpo"}, + {HNBU_PO_MCS2G, 0xffffffff, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 " + "2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"}, + {HNBU_PO_MCS5GM, 0xffffffff, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 " + "2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"}, + {HNBU_PO_MCS5GLH, 0xffffffff, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 " + "2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 " + "2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 " + "2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"}, + {HNBU_CCKFILTTYPE, 0xffffffff, 2, "1cckdigfilttype"}, + {HNBU_PO_CDD, 0xffffffff, 3, "2cddpo"}, + {HNBU_PO_STBC, 0xffffffff, 3, "2stbcpo"}, + {HNBU_PO_40M, 0xffffffff, 3, "2bw40po"}, + {HNBU_PO_40MDUP, 0xffffffff, 3, "2bwduppo"}, + {HNBU_RDLRWU, 0xffffffff, 2, "1rdlrwu"}, + {HNBU_WPS, 0xffffffff, 3, "1wpsgpio 1wpsled"}, + {HNBU_USBFS, 0xffffffff, 2, "1usbfs"}, + {HNBU_ELNA2G, 0xffffffff, 2, "1elna2g"}, + {HNBU_ELNA5G, 0xffffffff, 2, "1elna5g"}, + {HNBU_CUSTOM1, 0xffffffff, 5, "4customvar1"}, + {OTP_RAW, 0xffffffff, 0, ""}, /* special case */ + {HNBU_OFDMPO5G, 0xffffffff, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"}, + {HNBU_USBEPNUM, 0xffffffff, 3, "2usbepnum"}, + {HNBU_CCKBW202GPO, 0xffffffff, 7, "2cckbw202gpo 2cckbw20ul2gpo 2cckbw20in802gpo"}, + {HNBU_LEGOFDMBW202GPO, 0xffffffff, 9, "4legofdmbw202gpo 4legofdmbw20ul2gpo"}, + {HNBU_LEGOFDMBW205GPO, 0xffffffff, 25, "4legofdmbw205glpo 4legofdmbw20ul5glpo " + "4legofdmbw205gmpo 4legofdmbw20ul5gmpo 4legofdmbw205ghpo 4legofdmbw20ul5ghpo"}, + {HNBU_MCS2GPO, 0xffffffff, 17, "4mcsbw202gpo 4mcsbw20ul2gpo 4mcsbw402gpo 4mcsbw802gpo"}, + {HNBU_MCS5GLPO, 0xffffffff, 13, "4mcsbw205glpo 4mcsbw20ul5glpo 4mcsbw405glpo"}, + {HNBU_MCS5GMPO, 0xffffffff, 13, "4mcsbw205gmpo 4mcsbw20ul5gmpo 4mcsbw405gmpo"}, + {HNBU_MCS5GHPO, 0xffffffff, 13, "4mcsbw205ghpo 4mcsbw20ul5ghpo 4mcsbw405ghpo"}, + {HNBU_MCS32PO, 0xffffffff, 3, "2mcs32po"}, + {HNBU_LEG40DUPPO, 0xffffffff, 3, "2legofdm40duppo"}, + {HNBU_TEMPTHRESH, 0xffffffff, 7, "1tempthresh 0temps_period 0temps_hysteresis " + "1tempoffset 1tempsense_slope 0tempcorrx 0tempsense_option " + "1phycal_tempdelta"}, /* special case */ + {HNBU_MUXENAB, 0xffffffff, 2, "1muxenab"}, + {HNBU_FEM_CFG, 0xfffff800, 5, "0femctrl 0papdcap2g 0tworangetssi2g 0pdgain2g " + "0epagain2g 0tssiposslope2g 0gainctrlsph 0papdcap5g 0tworangetssi5g 0pdgain5g 0epagain5g " + "0tssiposslope5g"}, /* special case */ + {HNBU_ACPA_C0, 0xfffff800, 39, "2subband5gver 2maxp2ga0 2*3pa2ga0 " + "1*4maxp5ga0 2*12pa5ga0"}, + {HNBU_ACPA_C1, 0xfffff800, 37, "2maxp2ga1 2*3pa2ga1 1*4maxp5ga1 2*12pa5ga1"}, + {HNBU_ACPA_C2, 0xfffff800, 37, "2maxp2ga2 2*3pa2ga2 1*4maxp5ga2 2*12pa5ga2"}, + {HNBU_MEAS_PWR, 0xfffff800, 5, "1measpower 1measpower1 1measpower2 2rawtempsense"}, + {HNBU_PDOFF, 0xfffff800, 13, "2pdoffset40ma0 2pdoffset40ma1 2pdoffset40ma2 " + "2pdoffset80ma0 2pdoffset80ma1 2pdoffset80ma2"}, + {HNBU_ACPPR_2GPO, 0xfffff800, 13, "2dot11agofdmhrbw202gpo 2ofdmlrbw202gpo " + "2sb20in40dot11agofdm2gpo 2sb20in80dot11agofdm2gpo 2sb20in40ofdmlrbw202gpo " + "2sb20in80ofdmlrbw202gpo"}, + {HNBU_ACPPR_5GPO, 0xfffff800, 59, "4mcsbw805glpo 4mcsbw1605glpo 4mcsbw805gmpo " + "4mcsbw1605gmpo 4mcsbw805ghpo 4mcsbw1605ghpo 2mcslr5glpo 2mcslr5gmpo 2mcslr5ghpo " + "4mcsbw80p805glpo 4mcsbw80p805gmpo 4mcsbw80p805ghpo 4mcsbw80p805gx1po 2mcslr5gx1po " + "2mcslr5g80p80po 4mcsbw805gx1po 4mcsbw1605gx1po"}, + {HNBU_MCS5Gx1PO, 0xfffff800, 9, "4mcsbw205gx1po 4mcsbw405gx1po"}, + {HNBU_ACPPR_SBPO, 0xfffff800, 49, "2sb20in40hrpo 2sb20in80and160hr5glpo " + "2sb40and80hr5glpo 2sb20in80and160hr5gmpo 2sb40and80hr5gmpo 2sb20in80and160hr5ghpo " + "2sb40and80hr5ghpo 2sb20in40lrpo 2sb20in80and160lr5glpo 2sb40and80lr5glpo " + "2sb20in80and160lr5gmpo 2sb40and80lr5gmpo 2sb20in80and160lr5ghpo 2sb40and80lr5ghpo " + "4dot11agduphrpo 4dot11agduplrpo 2sb20in40and80hrpo 2sb20in40and80lrpo " + "2sb20in80and160hr5gx1po 2sb20in80and160lr5gx1po 2sb40and80hr5gx1po 2sb40and80lr5gx1po " + }, + {HNBU_ACPPR_SB8080_PO, 0xfffff800, 23, "2sb2040and80in80p80hr5glpo " + "2sb2040and80in80p80lr5glpo 2sb2040and80in80p80hr5gmpo " + "2sb2040and80in80p80lr5gmpo 2sb2040and80in80p80hr5ghpo 2sb2040and80in80p80lr5ghpo " + "2sb2040and80in80p80hr5gx1po 2sb2040and80in80p80lr5gx1po 2sb20in80p80hr5gpo " + "2sb20in80p80lr5gpo 2dot11agduppo"}, + {HNBU_NOISELVL, 0xfffff800, 16, "1noiselvl2ga0 1noiselvl2ga1 1noiselvl2ga2 " + "1*4noiselvl5ga0 1*4noiselvl5ga1 1*4noiselvl5ga2"}, + {HNBU_RXGAIN_ERR, 0xfffff800, 16, "1rxgainerr2ga0 1rxgainerr2ga1 1rxgainerr2ga2 " + "1*4rxgainerr5ga0 1*4rxgainerr5ga1 1*4rxgainerr5ga2"}, + {HNBU_AGBGA, 0xfffff800, 7, "1agbg0 1agbg1 1agbg2 1aga0 1aga1 1aga2"}, + {HNBU_USBDESC_COMPOSITE, 0xffffffff, 3, "2usbdesc_composite"}, + {HNBU_UUID, 0xffffffff, 17, "16uuid"}, + {HNBU_WOWLGPIO, 0xffffffff, 2, "1wowl_gpio"}, + {HNBU_ACRXGAINS_C0, 0xfffff800, 5, "0rxgains5gtrelnabypa0 0rxgains5gtrisoa0 " + "0rxgains5gelnagaina0 0rxgains2gtrelnabypa0 0rxgains2gtrisoa0 0rxgains2gelnagaina0 " + "0rxgains5ghtrelnabypa0 0rxgains5ghtrisoa0 0rxgains5ghelnagaina0 0rxgains5gmtrelnabypa0 " + "0rxgains5gmtrisoa0 0rxgains5gmelnagaina0"}, /* special case */ + {HNBU_ACRXGAINS_C1, 0xfffff800, 5, "0rxgains5gtrelnabypa1 0rxgains5gtrisoa1 " + "0rxgains5gelnagaina1 0rxgains2gtrelnabypa1 0rxgains2gtrisoa1 0rxgains2gelnagaina1 " + "0rxgains5ghtrelnabypa1 0rxgains5ghtrisoa1 0rxgains5ghelnagaina1 0rxgains5gmtrelnabypa1 " + "0rxgains5gmtrisoa1 0rxgains5gmelnagaina1"}, /* special case */ + {HNBU_ACRXGAINS_C2, 0xfffff800, 5, "0rxgains5gtrelnabypa2 0rxgains5gtrisoa2 " + "0rxgains5gelnagaina2 0rxgains2gtrelnabypa2 0rxgains2gtrisoa2 0rxgains2gelnagaina2 " + "0rxgains5ghtrelnabypa2 0rxgains5ghtrisoa2 0rxgains5ghelnagaina2 0rxgains5gmtrelnabypa2 " + "0rxgains5gmtrisoa2 0rxgains5gmelnagaina2"}, /* special case */ + {HNBU_TXDUTY, 0xfffff800, 9, "2tx_duty_cycle_ofdm_40_5g " + "2tx_duty_cycle_thresh_40_5g 2tx_duty_cycle_ofdm_80_5g 2tx_duty_cycle_thresh_80_5g"}, + {HNBU_PDOFF_2G, 0xfffff800, 3, "0pdoffset2g40ma0 0pdoffset2g40ma1 " + "0pdoffset2g40ma2 0pdoffset2g40mvalid"}, + {HNBU_ACPA_CCK, 0xfffff800, 7, "2*3pa2gccka0"}, + {HNBU_ACPA_40, 0xfffff800, 25, "2*12pa5gbw40a0"}, + {HNBU_ACPA_80, 0xfffff800, 25, "2*12pa5gbw80a0"}, + {HNBU_ACPA_4080, 0xfffff800, 49, "2*12pa5gbw4080a0 2*12pa5gbw4080a1"}, + {HNBU_SUBBAND5GVER, 0xfffff800, 3, "2subband5gver"}, + {HNBU_PAPARAMBWVER, 0xfffff800, 2, "1paparambwver"}, + {0xFF, 0xffffffff, 0, ""} +}; + +#endif /* _bcmsrom_tbl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/bcmutils.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmutils.h new file mode 100644 index 000000000000..a3ba46436161 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmutils.h @@ -0,0 +1,1174 @@ +/* + * Misc useful os-independent macros and functions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmutils.h 504037 2014-09-22 19:03:15Z $ + */ + +#ifndef _bcmutils_h_ +#define _bcmutils_h_ + +#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) +#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) +#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef PKTQ_LOG +#include +#endif + +/* ctype replacement */ +#define _BCM_U 0x01 /* upper */ +#define _BCM_L 0x02 /* lower */ +#define _BCM_D 0x04 /* digit */ +#define _BCM_C 0x08 /* cntrl */ +#define _BCM_P 0x10 /* punct */ +#define _BCM_S 0x20 /* white space (space/lf/tab) */ +#define _BCM_X 0x40 /* hex digit */ +#define _BCM_SP 0x80 /* hard space (0x20) */ + +extern const unsigned char bcm_ctype[]; +#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) + +#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) +#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) +#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) +#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) +#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) +#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) +#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) +#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) +#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) +#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) +#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) +#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) + +#define CIRCULAR_ARRAY_FULL(rd_idx, wr_idx, max) ((wr_idx + 1)%max == rd_idx) + +/* Buffer structure for collecting string-formatted data +* using bcm_bprintf() API. +* Use bcm_binit() to initialize before use +*/ + +struct bcmstrbuf { + char *buf; /* pointer to current position in origbuf */ + unsigned int size; /* current (residual) size in bytes */ + char *origbuf; /* unmodified pointer to orignal buffer */ + unsigned int origsize; /* unmodified orignal buffer size in bytes */ +}; + +/* ** driver-only section ** */ +#ifdef BCMDRIVER +#include +#include +#include + +#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */ + +/* + * 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. + */ +#ifndef SPINWAIT_POLL_PERIOD +#define SPINWAIT_POLL_PERIOD 10 +#endif + +#define SPINWAIT(exp, us) { \ + uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1); \ + while ((exp) && (countdown >= SPINWAIT_POLL_PERIOD)) { \ + OSL_DELAY(SPINWAIT_POLL_PERIOD); \ + countdown -= SPINWAIT_POLL_PERIOD; \ + } \ +} + +/* forward definition of ether_addr structure used by some function prototypes */ + +struct ether_addr; + +extern int ether_isbcast(const void *ea); +extern int ether_isnulladdr(const void *ea); + +#define BCM_MAC_RXCPL_IDX_BITS 12 +#define BCM_MAX_RXCPL_IDX_INVALID 0 +#define BCM_MAC_RXCPL_IFIDX_BITS 3 +#define BCM_MAC_RXCPL_DOT11_BITS 1 +#define BCM_MAX_RXCPL_IFIDX ((1 << BCM_MAC_RXCPL_IFIDX_BITS) - 1) +#define BCM_MAC_RXCPL_FLAG_BITS 4 +#define BCM_RXCPL_FLAGS_IN_TRANSIT 0x1 +#define BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST 0x2 +#define BCM_RXCPL_FLAGS_RXCPLVALID 0x4 +#define BCM_RXCPL_FLAGS_RSVD 0x8 + +#define BCM_RXCPL_SET_IN_TRANSIT(a) ((a)->rxcpl_id.flags |= BCM_RXCPL_FLAGS_IN_TRANSIT) +#define BCM_RXCPL_CLR_IN_TRANSIT(a) ((a)->rxcpl_id.flags &= ~BCM_RXCPL_FLAGS_IN_TRANSIT) +#define BCM_RXCPL_IN_TRANSIT(a) ((a)->rxcpl_id.flags & BCM_RXCPL_FLAGS_IN_TRANSIT) + +#define BCM_RXCPL_SET_FRST_IN_FLUSH(a) ((a)->rxcpl_id.flags |= BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST) +#define BCM_RXCPL_CLR_FRST_IN_FLUSH(a) ((a)->rxcpl_id.flags &= ~BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST) +#define BCM_RXCPL_FRST_IN_FLUSH(a) ((a)->rxcpl_id.flags & BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST) + +#define BCM_RXCPL_SET_VALID_INFO(a) ((a)->rxcpl_id.flags |= BCM_RXCPL_FLAGS_RXCPLVALID) +#define BCM_RXCPL_CLR_VALID_INFO(a) ((a)->rxcpl_id.flags &= ~BCM_RXCPL_FLAGS_RXCPLVALID) +#define BCM_RXCPL_VALID_INFO(a) (((a)->rxcpl_id.flags & BCM_RXCPL_FLAGS_RXCPLVALID) ? TRUE : FALSE) + + +struct reorder_rxcpl_id_list { + uint16 head; + uint16 tail; + uint32 cnt; +}; + +typedef struct rxcpl_id { + uint32 idx : BCM_MAC_RXCPL_IDX_BITS; + uint32 next_idx : BCM_MAC_RXCPL_IDX_BITS; + uint32 ifidx : BCM_MAC_RXCPL_IFIDX_BITS; + uint32 dot11 : BCM_MAC_RXCPL_DOT11_BITS; + uint32 flags : BCM_MAC_RXCPL_FLAG_BITS; +} rxcpl_idx_id_t; + +typedef struct rxcpl_data_len { + uint32 metadata_len_w : 6; + uint32 dataoffset: 10; + uint32 datalen : 16; +} rxcpl_data_len_t; + +typedef struct rxcpl_info { + rxcpl_idx_id_t rxcpl_id; + uint32 host_pktref; + union { + rxcpl_data_len_t rxcpl_len; + struct rxcpl_info *free_next; + }; +} rxcpl_info_t; + +/* rx completion list */ +typedef struct bcm_rxcplid_list { + uint32 max; + uint32 avail; + rxcpl_info_t *rxcpl_ptr; + rxcpl_info_t *free_list; +} bcm_rxcplid_list_t; + +extern bool bcm_alloc_rxcplid_list(osl_t *osh, uint32 max); +extern rxcpl_info_t * bcm_alloc_rxcplinfo(void); +extern void bcm_free_rxcplinfo(rxcpl_info_t *ptr); +extern void bcm_chain_rxcplid(uint16 first, uint16 next); +extern rxcpl_info_t *bcm_id2rxcplinfo(uint16 id); +extern uint16 bcm_rxcplinfo2id(rxcpl_info_t *ptr); +extern rxcpl_info_t *bcm_rxcpllist_end(rxcpl_info_t *ptr, uint32 *count); + +/* externs */ +/* packet */ +extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); +extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); +extern uint pkttotlen(osl_t *osh, void *p); +extern void *pktlast(osl_t *osh, void *p); +extern uint pktsegcnt(osl_t *osh, void *p); +extern uint pktsegcnt_war(osl_t *osh, void *p); +extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset); +extern void *pktoffset(osl_t *osh, void *p, uint offset); + +/* Get priority from a packet and pass it back in scb (or equiv) */ +#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */ +#define PKTPRIO_VLAN 0x200 /* VLAN prio found */ +#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ +#define PKTPRIO_DSCP 0x800 /* DSCP prio found */ + +/* DSCP type definitions (RFC4594) */ +/* AF1x: High-Throughput Data (RFC2597) */ +#define DSCP_AF11 0x0A +#define DSCP_AF12 0x0C +#define DSCP_AF13 0x0E +/* AF2x: Low-Latency Data (RFC2597) */ +#define DSCP_AF21 0x12 +#define DSCP_AF22 0x14 +#define DSCP_AF23 0x16 +/* AF3x: Multimedia Streaming (RFC2597) */ +#define DSCP_AF31 0x1A +#define DSCP_AF32 0x1C +#define DSCP_AF33 0x1E +/* EF: Telephony (RFC3246) */ +#define DSCP_EF 0x2E + +extern uint pktsetprio(void *pkt, bool update_vtag); +extern bool pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp); + +/* string */ +extern int bcm_atoi(const char *s); +extern ulong bcm_strtoul(const char *cp, char **endp, uint base); +extern char *bcmstrstr(const char *haystack, const char *needle); +extern char *bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len); +extern char *bcmstrcat(char *dest, const char *src); +extern char *bcmstrncat(char *dest, const char *src, uint size); +extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); +char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); +int bcmstricmp(const char *s1, const char *s2); +int bcmstrnicmp(const char* s1, const char* s2, int cnt); + + +/* ethernet address */ +extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); +extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); + +/* ip address */ +struct ipv4_addr; +extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); +extern char *bcm_ipv6_ntoa(void *ipv6, char *buf); +extern int bcm_atoipv4(const char *p, struct ipv4_addr *ip); + +/* delay */ +extern void bcm_mdelay(uint ms); +/* variable access */ +#define NVRAM_RECLAIM_CHECK(name) + +extern char *getvar(char *vars, const char *name); +extern int getintvar(char *vars, const char *name); +extern int getintvararray(char *vars, const char *name, int index); +extern int getintvararraysize(char *vars, const char *name); +extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); +#define bcm_perf_enable() +#define bcmstats(fmt) +#define bcmlog(fmt, a1, a2) +#define bcmdumplog(buf, size) *buf = '\0' +#define bcmdumplogent(buf, idx) -1 + +#define TSF_TICKS_PER_MS 1000 +#define TS_ENTER 0xdeadbeef /* Timestamp profiling enter */ +#define TS_EXIT 0xbeefcafe /* Timestamp profiling exit */ + +#define bcmtslog(tstamp, fmt, a1, a2) +#define bcmprinttslogs() +#define bcmprinttstamp(us) +#define bcmdumptslog(buf, size) + +extern char *bcm_nvram_vars(uint *length); +extern int bcm_nvram_cache(void *sih); + +/* Support for sharing code across in-driver iovar implementations. + * The intent is that a driver use this structure to map iovar names + * to its (private) iovar identifiers, and the lookup function to + * find the entry. Macros are provided to map ids and get/set actions + * into a single number space for a switch statement. + */ + +/* iovar structure */ +typedef struct bcm_iovar { + const char *name; /* name for lookup and display */ + uint16 varid; /* id for switch */ + uint16 flags; /* driver-specific flag bits */ + uint16 type; /* base type of argument */ + uint16 minlen; /* min length for buffer vars */ +} bcm_iovar_t; + +/* varid definitions are per-driver, may use these get/set bits */ + +/* IOVar action bits for id mapping */ +#define IOV_GET 0 /* Get an iovar */ +#define IOV_SET 1 /* Set an iovar */ + +/* Varid to actionid mapping */ +#define IOV_GVAL(id) ((id) * 2) +#define IOV_SVAL(id) ((id) * 2 + IOV_SET) +#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) +#define IOV_ID(actionid) (actionid >> 1) + +/* flags are per-driver based on driver attributes */ + +extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); +extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); +#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ + defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) +extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); +#endif +#endif /* BCMDRIVER */ + +/* Base type definitions */ +#define IOVT_VOID 0 /* no value (implictly set only) */ +#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */ +#define IOVT_INT8 2 /* integer values are range-checked */ +#define IOVT_UINT8 3 /* unsigned int 8 bits */ +#define IOVT_INT16 4 /* int 16 bits */ +#define IOVT_UINT16 5 /* unsigned int 16 bits */ +#define IOVT_INT32 6 /* int 32 bits */ +#define IOVT_UINT32 7 /* unsigned int 32 bits */ +#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */ +#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) + +/* Initializer for IOV type strings */ +#define BCM_IOV_TYPE_INIT { \ + "void", \ + "bool", \ + "int8", \ + "uint8", \ + "int16", \ + "uint16", \ + "int32", \ + "uint32", \ + "buffer", \ + "" } + +#define BCM_IOVT_IS_INT(type) (\ + (type == IOVT_BOOL) || \ + (type == IOVT_INT8) || \ + (type == IOVT_UINT8) || \ + (type == IOVT_INT16) || \ + (type == IOVT_UINT16) || \ + (type == IOVT_INT32) || \ + (type == IOVT_UINT32)) + +/* ** driver/apps-shared section ** */ + +#define BCME_STRLEN 64 /* Max string length for BCM errors */ +#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) + + +/* + * error codes could be added but the defined ones shouldn't be changed/deleted + * these error codes are exposed to the user code + * when ever a new error code is added to this list + * please update errorstring table with the related error string and + * update osl files with os specific errorcode map +*/ + +#define BCME_OK 0 /* Success */ +#define BCME_ERROR -1 /* Error generic */ +#define BCME_BADARG -2 /* Bad Argument */ +#define BCME_BADOPTION -3 /* Bad option */ +#define BCME_NOTUP -4 /* Not up */ +#define BCME_NOTDOWN -5 /* Not down */ +#define BCME_NOTAP -6 /* Not AP */ +#define BCME_NOTSTA -7 /* Not STA */ +#define BCME_BADKEYIDX -8 /* BAD Key Index */ +#define BCME_RADIOOFF -9 /* Radio Off */ +#define BCME_NOTBANDLOCKED -10 /* Not band locked */ +#define BCME_NOCLK -11 /* No Clock */ +#define BCME_BADRATESET -12 /* BAD Rate valueset */ +#define BCME_BADBAND -13 /* BAD Band */ +#define BCME_BUFTOOSHORT -14 /* Buffer too short */ +#define BCME_BUFTOOLONG -15 /* Buffer too long */ +#define BCME_BUSY -16 /* Busy */ +#define BCME_NOTASSOCIATED -17 /* Not Associated */ +#define BCME_BADSSIDLEN -18 /* Bad SSID len */ +#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ +#define BCME_BADCHAN -20 /* Bad Channel */ +#define BCME_BADADDR -21 /* Bad Address */ +#define BCME_NORESOURCE -22 /* Not Enough Resources */ +#define BCME_UNSUPPORTED -23 /* Unsupported */ +#define BCME_BADLEN -24 /* Bad length */ +#define BCME_NOTREADY -25 /* Not Ready */ +#define BCME_EPERM -26 /* Not Permitted */ +#define BCME_NOMEM -27 /* No Memory */ +#define BCME_ASSOCIATED -28 /* Associated */ +#define BCME_RANGE -29 /* Not In Range */ +#define BCME_NOTFOUND -30 /* Not Found */ +#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ +#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ +#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ +#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ +#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ +#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ +#define BCME_VERSION -37 /* Incorrect version */ +#define BCME_TXFAIL -38 /* TX failure */ +#define BCME_RXFAIL -39 /* RX failure */ +#define BCME_NODEVICE -40 /* Device not present */ +#define BCME_NMODE_DISABLED -41 /* NMODE disabled */ +#define BCME_NONRESIDENT -42 /* access to nonresident overlay */ +#define BCME_SCANREJECT -43 /* reject scan request */ +#define BCME_USAGE_ERROR -44 /* WLCMD usage error */ +#define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */ +#define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */ +#define BCME_DISABLED -47 /* Disabled in this build */ +#define BCME_DECERR -48 /* Decrypt error */ +#define BCME_ENCERR -49 /* Encrypt error */ +#define BCME_MICERR -50 /* Integrity/MIC error */ +#define BCME_REPLAY -51 /* Replay */ +#define BCME_IE_NOTFOUND -52 /* IE not found */ +#define BCME_LAST BCME_IE_NOTFOUND + +#define BCME_NOTENABLED BCME_DISABLED + +/* These are collection of BCME Error strings */ +#define BCMERRSTRINGTABLE { \ + "OK", \ + "Undefined error", \ + "Bad Argument", \ + "Bad Option", \ + "Not up", \ + "Not down", \ + "Not AP", \ + "Not STA", \ + "Bad Key Index", \ + "Radio Off", \ + "Not band locked", \ + "No clock", \ + "Bad Rate valueset", \ + "Bad Band", \ + "Buffer too short", \ + "Buffer too long", \ + "Busy", \ + "Not Associated", \ + "Bad SSID len", \ + "Out of Range Channel", \ + "Bad Channel", \ + "Bad Address", \ + "Not Enough Resources", \ + "Unsupported", \ + "Bad length", \ + "Not Ready", \ + "Not Permitted", \ + "No Memory", \ + "Associated", \ + "Not In Range", \ + "Not Found", \ + "WME Not Enabled", \ + "TSPEC Not Found", \ + "ACM Not Supported", \ + "Not WME Association", \ + "SDIO Bus Error", \ + "Dongle Not Accessible", \ + "Incorrect version", \ + "TX Failure", \ + "RX Failure", \ + "Device Not Present", \ + "NMODE Disabled", \ + "Nonresident overlay access", \ + "Scan Rejected", \ + "WLCMD usage error", \ + "WLCMD ioctl error", \ + "RWL serial port error", \ + "Disabled", \ + "Decrypt error", \ + "Encrypt error", \ + "MIC error", \ + "Replay", \ + "IE not found", \ +} + +#ifndef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) +#endif /* ABS */ + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* MIN */ + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif /* MAX */ + +/* limit to [min, max] */ +#ifndef LIMIT_TO_RANGE +#define LIMIT_TO_RANGE(x, min, max) \ + ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) +#endif /* LIMIT_TO_RANGE */ + +/* limit to max */ +#ifndef LIMIT_TO_MAX +#define LIMIT_TO_MAX(x, max) \ + (((x) > (max) ? (max) : (x))) +#endif /* LIMIT_TO_MAX */ + +/* limit to min */ +#ifndef LIMIT_TO_MIN +#define LIMIT_TO_MIN(x, min) \ + (((x) < (min) ? (min) : (x))) +#endif /* LIMIT_TO_MIN */ + +#define DELTA(curr, prev) ((curr) > (prev) ? ((curr) - (prev)) : \ + (0xffffffff - (prev) + (curr) + 1)) +#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) +#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#define ROUNDDN(p, align) ((p) & ~((align) - 1)) +#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) +#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ + & ~((boundary) - 1)) +#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ + & ~((boundary) - 1)) +#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) +#define VALID_MASK(mask) !((mask) & ((mask) + 1)) + +#ifndef OFFSETOF +#ifdef __ARMCC_VERSION +/* + * The ARM RVCT compiler complains when using OFFSETOF where a constant + * expression is expected, such as an initializer for a static object. + * offsetof from the runtime library doesn't have that problem. + */ +#include +#define OFFSETOF(type, member) offsetof(type, member) +#else +# if ((__GNUC__ >= 4) && (__GNUC_MINOR__ >= 8)) +/* GCC 4.8+ complains when using our OFFSETOF macro in array length declarations. */ +# define OFFSETOF(type, member) __builtin_offsetof(type, member) +# else +# define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) +# endif /* GCC 4.8 or newer */ +#endif /* __ARMCC_VERSION */ +#endif /* OFFSETOF */ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) +#endif + +#ifndef ARRAYLAST /* returns pointer to last array element */ +#define ARRAYLAST(a) (&a[ARRAYSIZE(a)-1]) +#endif + +/* Reference a function; used to prevent a static function from being optimized out */ +extern void *_bcmutils_dummy_fn; +#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) + +/* bit map related macros */ +#ifndef setbit +#ifndef NBBY /* the BSD family defines NBBY */ +#define NBBY 8 /* 8 bits per byte */ +#endif /* #ifndef NBBY */ +#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS +extern void setbit(void *array, uint bit); +extern void clrbit(void *array, uint bit); +extern bool isset(const void *array, uint bit); +extern bool isclr(const void *array, uint bit); +#else +#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) +#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) +#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) +#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) +#endif +#endif /* setbit */ +extern void set_bitrange(void *array, uint start, uint end, uint maxbit); + +#define isbitset(a, i) (((a) & (1 << (i))) != 0) + +#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) + +extern void bcm_bitprint32(const uint32 u32); + +/* + * ---------------------------------------------------------------------------- + * Multiword map of 2bits, nibbles + * setbit2 setbit4 (void *ptr, uint32 ix, uint32 val) + * getbit2 getbit4 (void *ptr, uint32 ix) + * ---------------------------------------------------------------------------- + */ + +#define DECLARE_MAP_API(NB, RSH, LSH, OFF, MSK) \ +static INLINE void setbit##NB(void *ptr, uint32 ix, uint32 val) \ +{ \ + uint32 *addr = (uint32 *)ptr; \ + uint32 *a = addr + (ix >> RSH); /* (ix / 2^RSH) */ \ + uint32 pos = (ix & OFF) << LSH; /* (ix % 2^RSH) * 2^LSH */ \ + uint32 mask = (MSK << pos); \ + uint32 tmp = *a & ~mask; \ + *a = tmp | (val << pos); \ +} \ +static INLINE uint32 getbit##NB(void *ptr, uint32 ix) \ +{ \ + uint32 *addr = (uint32 *)ptr; \ + uint32 *a = addr + (ix >> RSH); \ + uint32 pos = (ix & OFF) << LSH; \ + return ((*a >> pos) & MSK); \ +} + +DECLARE_MAP_API(2, 4, 1, 15U, 0x0003) /* setbit2() and getbit2() */ +DECLARE_MAP_API(4, 3, 2, 7U, 0x000F) /* setbit4() and getbit4() */ +DECLARE_MAP_API(8, 2, 3, 3U, 0x00FF) /* setbit8() and getbit8() */ + +/* 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 MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 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)) + +/* modulo add/sub - assumes x, y E [0, bound - 1] */ +#define MODADD(x, y, bound) \ + MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) +#define MODSUB(x, y, bound) \ + MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) + +/* module 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)) + +/* crc defines */ +#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */ +#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */ +#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */ +#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */ +#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */ +#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */ + +/* use for direct output of MAC address in printf etc */ +#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" +#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ + ((struct ether_addr *) (ea))->octet[1], \ + ((struct ether_addr *) (ea))->octet[2], \ + ((struct ether_addr *) (ea))->octet[3], \ + ((struct ether_addr *) (ea))->octet[4], \ + ((struct ether_addr *) (ea))->octet[5] + +#define ETHER_TO_MACF(ea) (ea).octet[0], \ + (ea).octet[1], \ + (ea).octet[2], \ + (ea).octet[3], \ + (ea).octet[4], \ + (ea).octet[5] +#if !defined(SIMPLE_MAC_PRINT) +#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] +#else +#define MACDBG "%02x:%02x:%02x" +#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] +#endif /* SIMPLE_MAC_PRINT */ + +/* bcm_format_flags() bit description structure */ +typedef struct bcm_bit_desc { + uint32 bit; + const char* name; +} bcm_bit_desc_t; + +/* bcm_format_field */ +typedef struct bcm_bit_desc_ex { + uint32 mask; + const bcm_bit_desc_t *bitfield; +} bcm_bit_desc_ex_t; + +/* buffer length for ethernet address from bcm_ether_ntoa() */ +#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */ + +static INLINE uint32 /* 32bit word aligned xor-32 */ +bcm_compute_xor32(volatile uint32 *u32, int num_u32) +{ + int i; + uint32 xor32 = 0; + for (i = 0; i < num_u32; i++) + xor32 ^= *(u32 + i); + return xor32; +} + +/* crypto utility function */ +/* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */ +static INLINE void +xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) +{ + if ( +#ifdef __i386__ + 1 || +#endif + (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { + /* ARM CM3 rel time: 1229 (727 if alignment check could be omitted) */ + /* x86 supports unaligned. This version runs 6x-9x faster on x86. */ + ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; + ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; + ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; + ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; + } else { + /* ARM CM3 rel time: 4668 (4191 if alignment check could be omitted) */ + int k; + for (k = 0; k < 16; k++) + dst[k] = src1[k] ^ src2[k]; + } +} + +/* externs */ +/* crc */ +extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); +extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); +extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); + +/* format/print */ +#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ + defined(WLMSG_ASSOC) +/* print out the value a field has: fields may have 1-32 bits and may hold any value */ +extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len); +/* print out which bits in flags are set */ +extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); +#endif + +extern int bcm_format_hex(char *str, const void *bytes, int len); + +extern const char *bcm_crypto_algo_name(uint algo); +extern char *bcm_chipname(uint chipid, char *buf, uint len); +extern char *bcm_brev_str(uint32 brev, char *buf); +extern void printbig(char *buf); +extern void prhex(const char *msg, uchar *buf, uint len); + +/* IE parsing */ + +/* tag_ID/length/value_buffer tuple */ +typedef struct bcm_tlv { + uint8 id; + uint8 len; + uint8 data[1]; +} bcm_tlv_t; + +/* bcm tlv w/ 16 bit id/len */ +typedef struct bcm_xtlv { + uint16 id; + uint16 len; + uint8 data[1]; +} bcm_xtlv_t; + +/* descriptor of xtlv data src or dst */ +typedef struct { + uint16 type; + uint16 len; + void *ptr; /* ptr to memory location */ +} xtlv_desc_t; + +/* set a var from xtlv buffer */ +typedef int +(bcm_set_var_from_tlv_cbfn_t)(void *ctx, void **tlv_buf, uint16 type, uint16 len); + +struct bcm_tlvbuf { + uint16 size; + uint8 *head; /* point to head of buffer */ + uint8 *buf; /* current position of buffer */ + /* followed by the allocated buffer */ +}; + +#define BCM_TLV_MAX_DATA_SIZE (255) +#define BCM_XTLV_MAX_DATA_SIZE (65535) +#define BCM_TLV_HDR_SIZE (OFFSETOF(bcm_tlv_t, data)) + +#define BCM_XTLV_HDR_SIZE (OFFSETOF(bcm_xtlv_t, data)) +#define BCM_XTLV_LEN(elt) ltoh16_ua(&(elt->len)) +#define BCM_XTLV_ID(elt) ltoh16_ua(&(elt->id)) +#define BCM_XTLV_SIZE(elt) (BCM_XTLV_HDR_SIZE + BCM_XTLV_LEN(elt)) + +/* Check that bcm_tlv_t fits into the given buflen */ +#define bcm_valid_tlv(elt, buflen) (\ + ((int)(buflen) >= (int)BCM_TLV_HDR_SIZE) && \ + ((int)(buflen) >= (int)(BCM_TLV_HDR_SIZE + (elt)->len))) + +#define bcm_valid_xtlv(elt, buflen) (\ + ((int)(buflen) >= (int)BCM_XTLV_HDR_SIZE) && \ + ((int)(buflen) >= (int)BCM_XTLV_SIZE(elt))) + +extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); +extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); +extern bcm_tlv_t *bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen); + +extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); + +extern bcm_tlv_t *bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, + int type_len); + +extern uint8 *bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst); +extern uint8 *bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, + int dst_maxlen); + +extern uint8 *bcm_copy_tlv(const void *src, uint8 *dst); +extern uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen); + +/* xtlv */ +extern bcm_xtlv_t *bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen); +extern struct bcm_tlvbuf *bcm_xtlv_buf_alloc(void *osh, uint16 len); +extern void bcm_xtlv_buf_free(void *osh, struct bcm_tlvbuf *tbuf); +extern uint16 bcm_xtlv_buf_len(struct bcm_tlvbuf *tbuf); +extern uint16 bcm_xtlv_buf_rlen(struct bcm_tlvbuf *tbuf); +extern uint8 *bcm_xtlv_buf(struct bcm_tlvbuf *tbuf); +extern uint8 *bcm_xtlv_head(struct bcm_tlvbuf *tbuf); +extern int bcm_xtlv_put_data(struct bcm_tlvbuf *tbuf, uint16 type, const void *data, uint16 dlen); +extern int bcm_xtlv_put_8(struct bcm_tlvbuf *tbuf, uint16 type, const int8 data); +extern int bcm_xtlv_put_16(struct bcm_tlvbuf *tbuf, uint16 type, const int16 data); +extern int bcm_xtlv_put_32(struct bcm_tlvbuf *tbuf, uint16 type, const int32 data); +extern int bcm_unpack_xtlv_entry(void **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst); +extern int bcm_skip_xtlv(void **tlv_buf); +extern int bcm_pack_xtlv_entry(void **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src); +extern int bcm_unpack_xtlv_buf(void *ctx, + void *tlv_buf, uint16 buflen, bcm_set_var_from_tlv_cbfn_t *cbfn); +extern int +bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items); +extern int +bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items); +extern int +bcm_pack_xtlv_entry_from_hex_string(void **tlv_buf, uint16 *buflen, uint16 type, char *hex); + +/* bcmerror */ +extern const char *bcmerrorstr(int bcmerror); + +/* multi-bool data type: set of bools, mbool is true if any is set */ +typedef uint32 mbool; +#define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */ +#define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */ +#define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */ +#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) + +/* generic datastruct to help dump routines */ +struct fielddesc { + const char *nameandfmt; + uint32 offset; + uint32 len; +}; + +extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); +extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); + +extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); +extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); +extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); + +typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); +extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, + char *buf, uint32 bufsize); +extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); + +extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); + +/* power conversion */ +extern uint16 bcm_qdbm_to_mw(uint8 qdbm); +extern uint8 bcm_mw_to_qdbm(uint16 mw); +extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); + +unsigned int process_nvram_vars(char *varbuf, unsigned int len); + +/* calculate a * b + c */ +extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c); +/* calculate a / b */ +extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b); + + +/* Public domain bit twiddling hacks/utilities: Sean Eron Anderson */ + +/* Table driven count set bits. */ +static const uint8 /* Table only for use by bcm_cntsetbits */ +_CSBTBL[256] = +{ +# define B2(n) n, n + 1, n + 1, n + 2 +# define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2) +# define B6(n) B4(n), B4(n + 1), B4(n + 1), B4(n + 2) + B6(0), B6(0 + 1), B6(0 + 1), B6(0 + 2) +}; + +static INLINE uint32 /* Uses table _CSBTBL for fast counting of 1's in a u32 */ +bcm_cntsetbits(const uint32 u32) +{ + /* function local scope declaration of const _CSBTBL[] */ + const uint8 * p = (const uint8 *)&u32; + return (_CSBTBL[p[0]] + _CSBTBL[p[1]] + _CSBTBL[p[2]] + _CSBTBL[p[3]]); +} + + +static INLINE int /* C equivalent count of leading 0's in a u32 */ +C_bcm_count_leading_zeros(uint32 u32) +{ + int shifts = 0; + while (u32) { + shifts++; u32 >>= 1; + } + return (32U - shifts); +} + +#ifdef BCMDRIVER +/* + * Assembly instructions: Count Leading Zeros + * "clz" : MIPS, ARM + * "cntlzw" : PowerPC + * "BSF" : x86 + * "lzcnt" : AMD, SPARC + */ + +#if defined(__arm__) + +#if defined(__ARM_ARCH_7M__) /* Cortex M3 */ +#define __USE_ASM_CLZ__ +#endif /* __ARM_ARCH_7M__ */ + +#if defined(__ARM_ARCH_7R__) /* Cortex R4 */ +#define __USE_ASM_CLZ__ +#endif /* __ARM_ARCH_7R__ */ + +#endif /* __arm__ */ + +static INLINE int +bcm_count_leading_zeros(uint32 u32) +{ +#if defined(__USE_ASM_CLZ__) + int zeros; + __asm__ volatile("clz %0, %1 \n" : "=r" (zeros) : "r" (u32)); + return zeros; +#else /* C equivalent */ + return C_bcm_count_leading_zeros(u32); +#endif /* C equivalent */ +} + +/* INTERFACE: Multiword bitmap based small id allocator. */ +struct bcm_mwbmap; /* forward declaration for use as an opaque mwbmap handle */ + +#define BCM_MWBMAP_INVALID_HDL ((struct bcm_mwbmap *)NULL) +#define BCM_MWBMAP_INVALID_IDX ((uint32)(~0U)) + +/* Incarnate a multiword bitmap based small index allocator */ +extern struct bcm_mwbmap * bcm_mwbmap_init(osl_t * osh, uint32 items_max); + +/* Free up the multiword bitmap index allocator */ +extern void bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl); + +/* Allocate a unique small index using a multiword bitmap index allocator */ +extern uint32 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl); + +/* Force an index at a specified position to be in use */ +extern void bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); + +/* Free a previously allocated index back into the multiword bitmap allocator */ +extern void bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); + +/* Fetch the toal number of free indices in the multiword bitmap allocator */ +extern uint32 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl); + +/* Determine whether an index is inuse or free */ +extern bool bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); + +/* Debug dump a multiword bitmap allocator */ +extern void bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl); + +extern void bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl); +/* End - Multiword bitmap based small Id allocator. */ + + +/* INTERFACE: Simple unique 16bit Id Allocator using a stack implementation. */ + +#define ID16_INVALID ((uint16)(~0)) + +/* + * Construct a 16bit id allocator, managing 16bit ids in the range: + * [start_val16 .. start_val16+total_ids) + * Note: start_val16 is inclusive. + * Returns an opaque handle to the 16bit id allocator. + */ +extern void * id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16); +extern void * id16_map_fini(osl_t *osh, void * id16_map_hndl); +extern void id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16); + +/* Allocate a unique 16bit id */ +extern uint16 id16_map_alloc(void * id16_map_hndl); + +/* Free a 16bit id value into the id16 allocator */ +extern void id16_map_free(void * id16_map_hndl, uint16 val16); + +/* Get the number of failures encountered during id allocation. */ +extern uint32 id16_map_failures(void * id16_map_hndl); + +/* Audit the 16bit id allocator state. */ +extern bool id16_map_audit(void * id16_map_hndl); +/* End - Simple 16bit Id Allocator. */ + +#endif /* BCMDRIVER */ + +extern void bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b); + +void bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset); +void bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset); + +/* calculate checksum for ip header, tcp / udp header / data */ +uint16 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum); + +#ifndef _dll_t_ +#define _dll_t_ +/* + * ----------------------------------------------------------------------------- + * Double Linked List Macros + * ----------------------------------------------------------------------------- + * + * All dll operations must be performed on a pre-initialized node. + * Inserting an uninitialized node into a list effectively initialized it. + * + * When a node is deleted from a list, you may initialize it to avoid corruption + * incurred by double deletion. You may skip initialization if the node is + * immediately inserted into another list. + * + * By placing a dll_t element at the start of a struct, you may cast a dll_t * + * to the struct or vice versa. + * + * Example of declaring an initializing someList and inserting nodeA, nodeB + * + * typedef struct item { + * dll_t node; + * int someData; + * } Item_t; + * Item_t nodeA, nodeB, nodeC; + * nodeA.someData = 11111, nodeB.someData = 22222, nodeC.someData = 33333; + * + * dll_t someList; + * dll_init(&someList); + * + * dll_append(&someList, (dll_t *) &nodeA); + * dll_prepend(&someList, &nodeB.node); + * dll_insert((dll_t *)&nodeC, &nodeA.node); + * + * dll_delete((dll_t *) &nodeB); + * + * Example of a for loop to walk someList of node_p + * + * extern void mydisplay(Item_t * item_p); + * + * dll_t * item_p, * next_p; + * for (item_p = dll_head_p(&someList); ! dll_end(&someList, item_p); + * item_p = next_p) + * { + * next_p = dll_next_p(item_p); + * ... use item_p at will, including removing it from list ... + * mydisplay((PItem_t)item_p); + * } + * + * ----------------------------------------------------------------------------- + */ +typedef struct dll { + struct dll * next_p; + struct dll * prev_p; +} dll_t; + +static INLINE void +dll_init(dll_t *node_p) +{ + node_p->next_p = node_p; + node_p->prev_p = node_p; +} +/* dll macros returing a pointer to dll_t */ + +static INLINE dll_t * +dll_head_p(dll_t *list_p) +{ + return list_p->next_p; +} + + +static INLINE dll_t * +dll_tail_p(dll_t *list_p) +{ + return (list_p)->prev_p; +} + + +static INLINE dll_t * +dll_next_p(dll_t *node_p) +{ + return (node_p)->next_p; +} + + +static INLINE dll_t * +dll_prev_p(dll_t *node_p) +{ + return (node_p)->prev_p; +} + + +static INLINE bool +dll_empty(dll_t *list_p) +{ + return ((list_p)->next_p == (list_p)); +} + + +static INLINE bool +dll_end(dll_t *list_p, dll_t * node_p) +{ + return (list_p == node_p); +} + + +/* inserts the node new_p "after" the node at_p */ +static INLINE void +dll_insert(dll_t *new_p, dll_t * at_p) +{ + new_p->next_p = at_p->next_p; + new_p->prev_p = at_p; + at_p->next_p = new_p; + (new_p->next_p)->prev_p = new_p; +} + +static INLINE void +dll_append(dll_t *list_p, dll_t *node_p) +{ + dll_insert(node_p, dll_tail_p(list_p)); +} + +static INLINE void +dll_prepend(dll_t *list_p, dll_t *node_p) +{ + dll_insert(node_p, list_p); +} + + +/* deletes a node from any list that it "may" be in, if at all. */ +static INLINE void +dll_delete(dll_t *node_p) +{ + node_p->prev_p->next_p = node_p->next_p; + node_p->next_p->prev_p = node_p->prev_p; +} +#endif /* ! defined(_dll_t_) */ + +/* Elements managed in a double linked list */ + +typedef struct dll_pool { + dll_t free_list; + uint16 free_count; + uint16 elems_max; + uint16 elem_size; + dll_t elements[1]; +} dll_pool_t; + +dll_pool_t * dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size); +void * dll_pool_alloc(dll_pool_t * dll_pool_p); +void dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p); +void dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p); +typedef void (* dll_elem_dump)(void * elem_p); +void dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size); + +#ifdef __cplusplus + } +#endif + +/* #define DEBUG_COUNTER */ +#ifdef DEBUG_COUNTER +#define CNTR_TBL_MAX 10 +typedef struct _counter_tbl_t { + char name[16]; /* name of this counter table */ + uint32 prev_log_print; /* Internal use. Timestamp of the previous log print */ + uint log_print_interval; /* Desired interval to print logs in ms */ + uint needed_cnt; /* How many counters need to be used */ + uint32 cnt[CNTR_TBL_MAX]; /* Counting entries to increase at desired places */ + bool enabled; /* Whether to enable printing log */ +} counter_tbl_t; + + +void counter_printlog(counter_tbl_t *ctr_tbl); +#endif /* DEBUG_COUNTER */ + +#endif /* _bcmutils_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd_bcm4356/include/brcm_nl80211.h new file mode 100644 index 000000000000..d68668bb99e1 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/brcm_nl80211.h @@ -0,0 +1,64 @@ +/* + * Definitions for nl80211 vendor command/event access to host driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: brcm_nl80211.h 595011 2015-10-26 05:41:56Z $ + * + */ + +#ifndef _brcm_nl80211_h_ +#define _brcm_nl80211_h_ + +#define OUI_BRCM 0x001018 + +enum wl_vendor_subcmd { + BRCM_VENDOR_SCMD_UNSPEC, + BRCM_VENDOR_SCMD_PRIV_STR, + BRCM_VENDOR_SCMD_BCM_STR +}; + +struct bcm_nlmsg_hdr { + uint cmd; /* common ioctl definition */ + uint len; /* expected return buffer length */ + uint offset; /* user buffer offset */ + uint set; /* get or set request optional */ + uint magic; /* magic number for verification */ +}; + +enum bcmnl_attrs { + BCM_NLATTR_UNSPEC, + + BCM_NLATTR_LEN, + BCM_NLATTR_DATA, + + __BCM_NLATTR_AFTER_LAST, + BCM_NLATTR_MAX = __BCM_NLATTR_AFTER_LAST - 1 +}; + +struct nl_prv_data { + int err; /* return result */ + void *data; /* ioctl return buffer pointer */ + uint len; /* ioctl return buffer length */ + struct bcm_nlmsg_hdr *nlioc; /* bcm_nlmsg_hdr header pointer */ +}; + +#endif /* _brcm_nl80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/dbus.h b/drivers/net/wireless/bcmdhd_bcm4356/include/dbus.h new file mode 100644 index 000000000000..933e8f0e9d2e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/dbus.h @@ -0,0 +1,582 @@ +/* + * Dongle BUS interface Abstraction layer + * target serial buses like USB, SDIO, SPI, etc. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dbus.h 496883 2014-08-14 22:59:09Z $ + */ + +#ifndef __DBUS_H__ +#define __DBUS_H__ + +#include "typedefs.h" + +#define DBUSTRACE(args) +#define DBUSERR(args) +#define DBUSINFO(args) +#define DBUSDBGLOCK(args) + +enum { + DBUS_OK = 0, + DBUS_ERR = -200, + DBUS_ERR_TIMEOUT, + DBUS_ERR_DISCONNECT, + DBUS_ERR_NODEVICE, + DBUS_ERR_UNSUPPORTED, + DBUS_ERR_PENDING, + DBUS_ERR_NOMEM, + DBUS_ERR_TXFAIL, + DBUS_ERR_TXTIMEOUT, + DBUS_ERR_TXDROP, + DBUS_ERR_RXFAIL, + DBUS_ERR_RXDROP, + DBUS_ERR_TXCTLFAIL, + DBUS_ERR_RXCTLFAIL, + DBUS_ERR_REG_PARAM, + DBUS_STATUS_CANCELLED, + DBUS_ERR_NVRAM, + DBUS_JUMBO_NOMATCH, + DBUS_JUMBO_BAD_FORMAT, + DBUS_NVRAM_NONTXT +}; + +#define BCM_OTP_SIZE_43236 84 /* number of 16 bit values */ +#define BCM_OTP_SW_RGN_43236 24 /* start offset of SW config region */ +#define BCM_OTP_ADDR_43236 0x18000800 /* address of otp base */ + +#define ERR_CBMASK_TXFAIL 0x00000001 +#define ERR_CBMASK_RXFAIL 0x00000002 +#define ERR_CBMASK_ALL 0xFFFFFFFF + +#define DBUS_CBCTL_WRITE 0 +#define DBUS_CBCTL_READ 1 +#if defined(INTR_EP_ENABLE) +#define DBUS_CBINTR_POLL 2 +#endif /* defined(INTR_EP_ENABLE) */ + +#define DBUS_TX_RETRY_LIMIT 3 /* retries for failed txirb */ +#define DBUS_TX_TIMEOUT_INTERVAL 250 /* timeout for txirb complete, in ms */ + +#define DBUS_BUFFER_SIZE_TX 32000 +#define DBUS_BUFFER_SIZE_RX 24000 + +#define DBUS_BUFFER_SIZE_TX_NOAGG 2048 +#define DBUS_BUFFER_SIZE_RX_NOAGG 2048 + +/* DBUS types */ +enum { + DBUS_USB, + DBUS_SDIO, + DBUS_SPI, + DBUS_UNKNOWN +}; + +enum dbus_state { + DBUS_STATE_DL_PENDING, + DBUS_STATE_DL_DONE, + DBUS_STATE_UP, + DBUS_STATE_DOWN, + DBUS_STATE_PNP_FWDL, + DBUS_STATE_DISCONNECT, + DBUS_STATE_SLEEP +}; + +enum dbus_pnp_state { + DBUS_PNP_DISCONNECT, + DBUS_PNP_SLEEP, + DBUS_PNP_RESUME +}; + +enum dbus_file { + DBUS_FIRMWARE, + DBUS_NVFILE +}; + +typedef enum _DEVICE_SPEED { + INVALID_SPEED = -1, + LOW_SPEED = 1, /* USB 1.1: 1.5 Mbps */ + FULL_SPEED, /* USB 1.1: 12 Mbps */ + HIGH_SPEED, /* USB 2.0: 480 Mbps */ + SUPER_SPEED, /* USB 3.0: 4.8 Gbps */ +} DEVICE_SPEED; + +typedef struct { + int bustype; + int vid; + int pid; + int devid; + int chiprev; /* chip revsion number */ + int mtu; + int nchan; /* Data Channels */ + int has_2nd_bulk_in_ep; +} dbus_attrib_t; + +/* FIX: Account for errors related to DBUS; + * Let upper layer account for packets/bytes + */ +typedef struct { + uint32 rx_errors; + uint32 tx_errors; + uint32 rx_dropped; + uint32 tx_dropped; +} dbus_stats_t; + +/* + * Configurable BUS parameters + */ +enum { + DBUS_CONFIG_ID_RXCTL_DEFERRES = 1, + DBUS_CONFIG_ID_TXRXQUEUE +}; +typedef struct { + uint32 config_id; + union { + bool rxctl_deferrespok; + struct { + int maxrxq; + int rxbufsize; + int maxtxq; + int txbufsize; + } txrxqueue; + }; +} dbus_config_t; + +/* + * External Download Info + */ +typedef struct dbus_extdl { + uint8 *fw; + int fwlen; + uint8 *vars; + int varslen; +} dbus_extdl_t; + +struct dbus_callbacks; +struct exec_parms; + +typedef void *(*probe_cb_t)(void *arg, const char *desc, uint32 bustype, uint32 hdrlen); +typedef void (*disconnect_cb_t)(void *arg); +typedef void *(*exec_cb_t)(struct exec_parms *args); + +/* Client callbacks registered during dbus_attach() */ +typedef struct dbus_callbacks { + void (*send_complete)(void *cbarg, void *info, int status); + void (*recv_buf)(void *cbarg, uint8 *buf, int len); + void (*recv_pkt)(void *cbarg, void *pkt); + void (*txflowcontrol)(void *cbarg, bool onoff); + void (*errhandler)(void *cbarg, int err); + void (*ctl_complete)(void *cbarg, int type, int status); + void (*state_change)(void *cbarg, int state); + void *(*pktget)(void *cbarg, uint len, bool send); + void (*pktfree)(void *cbarg, void *p, bool send); +} dbus_callbacks_t; + +struct dbus_pub; +struct bcmstrbuf; +struct dbus_irb; +struct dbus_irb_rx; +struct dbus_irb_tx; +struct dbus_intf_callbacks; + +typedef struct { + void* (*attach)(struct dbus_pub *pub, void *cbarg, struct dbus_intf_callbacks *cbs); + void (*detach)(struct dbus_pub *pub, void *bus); + + int (*up)(void *bus); + int (*down)(void *bus); + int (*send_irb)(void *bus, struct dbus_irb_tx *txirb); + int (*recv_irb)(void *bus, struct dbus_irb_rx *rxirb); + int (*cancel_irb)(void *bus, struct dbus_irb_tx *txirb); + int (*send_ctl)(void *bus, uint8 *buf, int len); + int (*recv_ctl)(void *bus, uint8 *buf, int len); + int (*get_stats)(void *bus, dbus_stats_t *stats); + int (*get_attrib)(void *bus, dbus_attrib_t *attrib); + + int (*pnp)(void *bus, int evnt); + int (*remove)(void *bus); + int (*resume)(void *bus); + int (*suspend)(void *bus); + int (*stop)(void *bus); + int (*reset)(void *bus); + + /* Access to bus buffers directly */ + void *(*pktget)(void *bus, int len); + void (*pktfree)(void *bus, void *pkt); + + int (*iovar_op)(void *bus, const char *name, void *params, int plen, void *arg, int len, + bool set); + void (*dump)(void *bus, struct bcmstrbuf *strbuf); + int (*set_config)(void *bus, dbus_config_t *config); + int (*get_config)(void *bus, dbus_config_t *config); + + bool (*device_exists)(void *bus); + bool (*dlneeded)(void *bus); + int (*dlstart)(void *bus, uint8 *fw, int len); + int (*dlrun)(void *bus); + bool (*recv_needed)(void *bus); + + void *(*exec_rxlock)(void *bus, exec_cb_t func, struct exec_parms *args); + void *(*exec_txlock)(void *bus, exec_cb_t func, struct exec_parms *args); + + int (*tx_timer_init)(void *bus); + int (*tx_timer_start)(void *bus, uint timeout); + int (*tx_timer_stop)(void *bus); + + int (*sched_dpc)(void *bus); + int (*lock)(void *bus); + int (*unlock)(void *bus); + int (*sched_probe_cb)(void *bus); + + int (*shutdown)(void *bus); + + int (*recv_stop)(void *bus); + int (*recv_resume)(void *bus); + + int (*recv_irb_from_ep)(void *bus, struct dbus_irb_rx *rxirb, uint ep_idx); + + int (*readreg)(void *bus, uint32 regaddr, int datalen, uint32 *value); + + /* Add from the bottom */ +} dbus_intf_t; + +typedef struct dbus_pub { + struct osl_info *osh; + dbus_stats_t stats; + dbus_attrib_t attrib; + enum dbus_state busstate; + DEVICE_SPEED device_speed; + int ntxq, nrxq, rxsize; + void *bus; + struct shared_info *sh; + void *dev_info; +} dbus_pub_t; + +#define BUS_INFO(bus, type) (((type *) bus)->pub->bus) + +#define ALIGNED_LOCAL_VARIABLE(var, align) \ + uint8 buffer[SDALIGN+64]; \ + uint8 *var = (uint8 *)(((uintptr)&buffer[0]) & ~(align-1)) + align; + +/* + * Public Bus Function Interface + */ + +/* + * FIX: Is there better way to pass OS/Host handles to DBUS but still + * maintain common interface for all OS?? + * Under NDIS, param1 needs to be MiniportHandle + * For NDIS60, param2 is WdfDevice + * Under Linux, param1 and param2 are NULL; + */ +extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, + void *param1, void *param2); +extern int dbus_deregister(void); + +extern dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq, int ntxq, + void *cbarg, dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh); +extern void dbus_detach(dbus_pub_t *pub); + +extern int dbus_up(dbus_pub_t *pub); +extern int dbus_down(dbus_pub_t *pub); +extern int dbus_stop(dbus_pub_t *pub); +extern int dbus_shutdown(dbus_pub_t *pub); +extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on); + +extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); +extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info); +extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); +extern int dbus_send_ctl(dbus_pub_t *pub, uint8 *buf, int len); +extern int dbus_recv_ctl(dbus_pub_t *pub, uint8 *buf, int len); +extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); +extern int dbus_poll_intr(dbus_pub_t *pub); +extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats); +extern int dbus_get_attrib(dbus_pub_t *pub, dbus_attrib_t *attrib); +extern int dbus_get_device_speed(dbus_pub_t *pub); +extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config); +extern int dbus_get_config(dbus_pub_t *pub, dbus_config_t *config); +extern void * dbus_get_devinfo(dbus_pub_t *pub); + +extern void *dbus_pktget(dbus_pub_t *pub, int len); +extern void dbus_pktfree(dbus_pub_t *pub, void* pkt); + +extern int dbus_set_errmask(dbus_pub_t *pub, uint32 mask); +extern int dbus_pnp_sleep(dbus_pub_t *pub); +extern int dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload); +extern int dbus_pnp_disconnect(dbus_pub_t *pub); + +extern int dbus_iovar_op(dbus_pub_t *pub, const char *name, + void *params, int plen, void *arg, int len, bool set); + +extern void *dhd_dbus_txq(const dbus_pub_t *pub); +extern uint dhd_dbus_hdrlen(const dbus_pub_t *pub); + +/* + * Private Common Bus Interface + */ + +/* IO Request Block (IRB) */ +typedef struct dbus_irb { + struct dbus_irb *next; /* it's casted from dbus_irb_tx or dbus_irb_rx struct */ +} dbus_irb_t; + +typedef struct dbus_irb_rx { + struct dbus_irb irb; /* Must be first */ + uint8 *buf; + int buf_len; + int actual_len; + void *pkt; + void *info; + void *arg; +} dbus_irb_rx_t; + +typedef struct dbus_irb_tx { + struct dbus_irb irb; /* Must be first */ + uint8 *buf; + int len; + void *pkt; + int retry_count; + void *info; + void *arg; + void *send_buf; /* linear bufffer for LINUX when aggreagtion is enabled */ +} dbus_irb_tx_t; + +/* DBUS interface callbacks are different from user callbacks + * so, internally, different info can be passed to upper layer + */ +typedef struct dbus_intf_callbacks { + void (*send_irb_timeout)(void *cbarg, dbus_irb_tx_t *txirb); + void (*send_irb_complete)(void *cbarg, dbus_irb_tx_t *txirb, int status); + void (*recv_irb_complete)(void *cbarg, dbus_irb_rx_t *rxirb, int status); + void (*errhandler)(void *cbarg, int err); + void (*ctl_complete)(void *cbarg, int type, int status); + void (*state_change)(void *cbarg, int state); + bool (*isr)(void *cbarg, bool *wantdpc); + bool (*dpc)(void *cbarg, bool bounded); + void (*watchdog)(void *cbarg); + void *(*pktget)(void *cbarg, uint len, bool send); + void (*pktfree)(void *cbarg, void *p, bool send); + struct dbus_irb* (*getirb)(void *cbarg, bool send); + void (*rxerr_indicate)(void *cbarg, bool on); +} dbus_intf_callbacks_t; + +/* + * Porting: To support new bus, port these functions below + */ + +/* + * Bus specific Interface + * Implemented by dbus_usb.c/dbus_sdio.c + */ +extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, + dbus_intf_t **intf, void *param1, void *param2); +extern int dbus_bus_deregister(void); +extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp); + +/* + * Bus-specific and OS-specific Interface + * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c + */ +extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, + void *prarg, dbus_intf_t **intf, void *param1, void *param2); +extern int dbus_bus_osl_deregister(void); + +/* + * Bus-specific, OS-specific, HW-specific Interface + * Mainly for SDIO Host HW controller + */ +extern int dbus_bus_osl_hw_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, + void *prarg, dbus_intf_t **intf); +extern int dbus_bus_osl_hw_deregister(void); + +extern uint usbdev_bulkin_eps(void); +#if defined(BCM_REQUEST_FW) +extern void *dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, + uint16 boardtype, uint16 boardrev); +extern void dbus_release_fw_nvfile(void *firmware); +#endif /* #if defined(BCM_REQUEST_FW) */ + + +#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) + /* Backward compatibility */ + typedef unsigned int gfp_t; + + #define dma_pool pci_pool + #define dma_pool_create(name, dev, size, align, alloc) \ + pci_pool_create(name, dev, size, align, alloc, GFP_DMA | GFP_ATOMIC) + #define dma_pool_destroy(pool) pci_pool_destroy(pool) + #define dma_pool_alloc(pool, flags, handle) pci_pool_alloc(pool, flags, handle) + #define dma_pool_free(pool, vaddr, addr) pci_pool_free(pool, vaddr, addr) + + #define dma_map_single(dev, addr, size, dir) pci_map_single(dev, addr, size, dir) + #define dma_unmap_single(dev, hnd, size, dir) pci_unmap_single(dev, hnd, size, dir) + #define DMA_FROM_DEVICE PCI_DMA_FROMDEVICE + #define DMA_TO_DEVICE PCI_DMA_TODEVICE +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ + +/* Availability of these functions varies (when present, they have two arguments) */ +#ifndef hc32_to_cpu + #define hc32_to_cpu(x) le32_to_cpu(x) + #define cpu_to_hc32(x) cpu_to_le32(x) + typedef unsigned int __hc32; +#else + #error Two-argument functions needed +#endif + +/* Private USB opcode base */ +#define EHCI_FASTPATH 0x31 +#define EHCI_SET_EP_BYPASS EHCI_FASTPATH +#define EHCI_SET_BYPASS_CB (EHCI_FASTPATH + 1) +#define EHCI_SET_BYPASS_DEV (EHCI_FASTPATH + 2) +#define EHCI_DUMP_STATE (EHCI_FASTPATH + 3) +#define EHCI_SET_BYPASS_POOL (EHCI_FASTPATH + 4) +#define EHCI_CLR_EP_BYPASS (EHCI_FASTPATH + 5) + +/* + * EHCI QTD structure (hardware and extension) + * NOTE that is does not need to (and does not) match its kernel counterpart + */ +#define EHCI_QTD_NBUFFERS 5 +#define EHCI_QTD_ALIGN 32 +#define EHCI_BULK_PACKET_SIZE 512 +#define EHCI_QTD_XACTERR_MAX 32 + +struct ehci_qtd { + /* Hardware map */ + volatile uint32_t qtd_next; + volatile uint32_t qtd_altnext; + volatile uint32_t qtd_status; +#define EHCI_QTD_GET_BYTES(x) (((x)>>16) & 0x7fff) +#define EHCI_QTD_IOC 0x00008000 +#define EHCI_QTD_GET_CERR(x) (((x)>>10) & 0x3) +#define EHCI_QTD_SET_CERR(x) ((x) << 10) +#define EHCI_QTD_GET_PID(x) (((x)>>8) & 0x3) +#define EHCI_QTD_SET_PID(x) ((x) << 8) +#define EHCI_QTD_ACTIVE 0x80 +#define EHCI_QTD_HALTED 0x40 +#define EHCI_QTD_BUFERR 0x20 +#define EHCI_QTD_BABBLE 0x10 +#define EHCI_QTD_XACTERR 0x08 +#define EHCI_QTD_MISSEDMICRO 0x04 + volatile uint32_t qtd_buffer[EHCI_QTD_NBUFFERS]; + volatile uint32_t qtd_buffer_hi[EHCI_QTD_NBUFFERS]; + + /* Implementation extension */ + dma_addr_t qtd_self; /* own hardware address */ + struct ehci_qtd *obj_next; /* software link to the next QTD */ + void *rpc; /* pointer to the rpc buffer */ + size_t length; /* length of the data in the buffer */ + void *buff; /* pointer to the reassembly buffer */ + int xacterrs; /* retry counter for qtd xact error */ +} __attribute__ ((aligned(EHCI_QTD_ALIGN))); + +#define EHCI_NULL __constant_cpu_to_le32(1) /* HW null pointer shall be odd */ + +#define SHORT_READ_Q(token) (EHCI_QTD_GET_BYTES(token) != 0 && EHCI_QTD_GET_PID(token) == 1) + +/* Queue Head */ +/* NOTE This structure is slightly different from the one in the kernel; but needs to stay + * compatible + */ +struct ehci_qh { + /* Hardware map */ + volatile uint32_t qh_link; + volatile uint32_t qh_endp; + volatile uint32_t qh_endphub; + volatile uint32_t qh_curqtd; + + /* QTD overlay */ + volatile uint32_t ow_next; + volatile uint32_t ow_altnext; + volatile uint32_t ow_status; + volatile uint32_t ow_buffer [EHCI_QTD_NBUFFERS]; + volatile uint32_t ow_buffer_hi [EHCI_QTD_NBUFFERS]; + + /* Extension (should match the kernel layout) */ + dma_addr_t unused0; + void *unused1; + struct list_head unused2; + struct ehci_qtd *dummy; + struct ehci_qh *unused3; + + struct ehci_hcd *unused4; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + struct kref unused5; + unsigned unused6; + + uint8_t unused7; + + /* periodic schedule info */ + uint8_t unused8; + uint8_t unused9; + uint8_t unused10; + uint16_t unused11; + uint16_t unused12; + uint16_t unused13; + struct usb_device *unused14; +#else + unsigned unused5; + + u8 unused6; + + /* periodic schedule info */ + u8 unused7; + u8 unused8; + u8 unused9; + unsigned short unused10; + unsigned short unused11; +#define NO_FRAME ((unsigned short)~0) +#ifdef EHCI_QUIRK_FIX + struct usb_device *unused12; +#endif /* EHCI_QUIRK_FIX */ +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ + struct ehci_qtd *first_qtd; + /* Link to the first QTD; this is an optimized equivalent of the qtd_list field */ + /* NOTE that ehci_qh in ehci.h shall reserve this word */ +} __attribute__ ((aligned(EHCI_QTD_ALIGN))); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +/* The corresponding structure in the kernel is used to get the QH */ +struct hcd_dev { /* usb_device.hcpriv points to this */ + struct list_head unused0; + struct list_head unused1; + + /* array of QH pointers */ + void *ep[32]; +}; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ + +int optimize_qtd_fill_with_rpc(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *rpc, + int token, int len); +int optimize_qtd_fill_with_data(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *data, + int token, int len); +int optimize_submit_async(struct ehci_qtd *qtd, int epn); +void inline optimize_ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma); +struct ehci_qtd *optimize_ehci_qtd_alloc(gfp_t flags); +void optimize_ehci_qtd_free(struct ehci_qtd *qtd); +void optimize_submit_rx_request(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd_in, void *buf); +#endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ + +void dbus_flowctrl_tx(void *dbi, bool on); +#endif /* __DBUS_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd_bcm4356/include/devctrl_if/wlioctl_defs.h new file mode 100644 index 000000000000..444166042572 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/devctrl_if/wlioctl_defs.h @@ -0,0 +1,2110 @@ +/* + * Custom OID/ioctl definitions for + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wlioctl_defs.h 403826 2013-05-22 16:40:55Z $ + */ + + +#ifndef wlioctl_defs_h +#define wlioctl_defs_h + + + +/* All builds use the new 11ac ratespec/chanspec */ +#undef D11AC_IOTYPES +#define D11AC_IOTYPES + +/* WL_RSPEC defines for rate information */ +#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */ +#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */ +#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */ +#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */ +#define WL_RSPEC_TXEXP_MASK 0x00000300 +#define WL_RSPEC_TXEXP_SHIFT 8 +#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ +#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ +#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ +#define WL_RSPEC_TXBF 0x00200000 /* bit indicates TXBF mode */ +#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ +#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ +#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ +#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */ +#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override both rate & mode */ + +/* WL_RSPEC_ENCODING field defs */ +#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */ +#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */ +#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */ + +/* WL_RSPEC_BW field defs */ +#define WL_RSPEC_BW_UNSPECIFIED 0 +#define WL_RSPEC_BW_20MHZ 0x00010000 +#define WL_RSPEC_BW_40MHZ 0x00020000 +#define WL_RSPEC_BW_80MHZ 0x00030000 +#define WL_RSPEC_BW_160MHZ 0x00040000 + +/* Legacy defines for the nrate iovar */ +#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ +#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ +#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ +#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */ +#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ +#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ +#define OLD_NRATE_SGI 0x00800000 /* sgi mode */ +#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ + +#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */ +#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */ +#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */ +#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */ + +#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ + +#define GET_PRO_PRIETARY_11N_MCS_NSS(mcs) (1 + ((mcs) - 85) / 8) + +#define GET_11N_MCS_NSS(mcs) ((mcs) < 32 ? (1 + ((mcs) / 8)) \ + : ((mcs) == 32 ? 1 : GET_PRO_PRIETARY_11N_MCS_NSS(mcs))) + +#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ +#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ + +#define IBSS_MED 15 /* Mediom in-bss congestion percentage */ +#define IBSS_HI 25 /* Hi in-bss congestion percentage */ +#define OBSS_MED 12 +#define OBSS_HI 25 +#define INTERFER_MED 5 +#define INTERFER_HI 10 + +#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */ +#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */ +#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */ +#define CCA_FLAGS_PREFER_1_6_11 0x10 +#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */ + +#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */ +#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */ +#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */ +#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */ +#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */ + +#define WL_STA_AID(a) ((a) &~ 0xc000) + +/* Flags for sta_info_t indicating properties of STA */ +#define WL_STA_BRCM 0x00000001 /* Running a Broadcom driver */ +#define WL_STA_WME 0x00000002 /* WMM association */ +#define WL_STA_NONERP 0x00000004 /* No ERP */ +#define WL_STA_AUTHE 0x00000008 /* Authenticated */ +#define WL_STA_ASSOC 0x00000010 /* Associated */ +#define WL_STA_AUTHO 0x00000020 /* Authorized */ +#define WL_STA_WDS 0x00000040 /* Wireless Distribution System */ +#define WL_STA_WDS_LINKUP 0x00000080 /* WDS traffic/probes flowing properly */ +#define WL_STA_PS 0x00000100 /* STA is in power save mode from AP's viewpoint */ +#define WL_STA_APSD_BE 0x00000200 /* APSD delv/trigger for AC_BE is default enabled */ +#define WL_STA_APSD_BK 0x00000400 /* APSD delv/trigger for AC_BK is default enabled */ +#define WL_STA_APSD_VI 0x00000800 /* APSD delv/trigger for AC_VI is default enabled */ +#define WL_STA_APSD_VO 0x00001000 /* APSD delv/trigger for AC_VO is default enabled */ +#define WL_STA_N_CAP 0x00002000 /* STA 802.11n capable */ +#define WL_STA_SCBSTATS 0x00004000 /* Per STA debug stats */ +#define WL_STA_AMPDU_CAP 0x00008000 /* STA AMPDU capable */ +#define WL_STA_AMSDU_CAP 0x00010000 /* STA AMSDU capable */ +#define WL_STA_MIMO_PS 0x00020000 /* mimo ps mode is enabled */ +#define WL_STA_MIMO_RTS 0x00040000 /* send rts in mimo ps mode */ +#define WL_STA_RIFS_CAP 0x00080000 /* rifs enabled */ +#define WL_STA_VHT_CAP 0x00100000 /* STA VHT(11ac) capable */ +#define WL_STA_WPS 0x00200000 /* WPS state */ + +#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ + +/* STA HT cap fields */ +#define WL_STA_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ +#define WL_STA_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ +#define WL_STA_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ +#define WL_STA_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ +#define WL_STA_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ +#define WL_STA_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ +#define WL_STA_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ +#define WL_STA_CAP_GF 0x0010 /* Greenfield preamble support */ +#define WL_STA_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ +#define WL_STA_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ +#define WL_STA_CAP_TX_STBC 0x0080 /* Tx STBC support */ +#define WL_STA_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ +#define WL_STA_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ +#define WL_STA_CAP_DELAYED_BA 0x0400 /* delayed BA support */ +#define WL_STA_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ +#define WL_STA_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ +#define WL_STA_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ +#define WL_STA_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ +#define WL_STA_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ + +#define WL_STA_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ +#define WL_STA_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ +#define WL_STA_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ +#define WL_STA_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ + +/* scb vht flags */ +#define WL_STA_VHT_LDPCCAP 0x0001 +#define WL_STA_SGI80 0x0002 +#define WL_STA_SGI160 0x0004 +#define WL_STA_VHT_TX_STBCCAP 0x0008 +#define WL_STA_VHT_RX_STBCCAP 0x0010 +#define WL_STA_SU_BEAMFORMER 0x0020 +#define WL_STA_SU_BEAMFORMEE 0x0040 +#define WL_STA_MU_BEAMFORMER 0x0080 +#define WL_STA_MU_BEAMFORMEE 0x0100 +#define WL_STA_VHT_TXOP_PS 0x0200 +#define WL_STA_HTC_VHT_CAP 0x0400 + +/* Values for TX Filter override mode */ +#define WLC_TXFILTER_OVERRIDE_DISABLED 0 +#define WLC_TXFILTER_OVERRIDE_ENABLED 1 + +#define WL_IOCTL_ACTION_GET 0x0 +#define WL_IOCTL_ACTION_SET 0x1 +#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e +#define WL_IOCTL_ACTION_OVL_RSV 0x20 +#define WL_IOCTL_ACTION_OVL 0x40 +#define WL_IOCTL_ACTION_MASK 0x7e +#define WL_IOCTL_ACTION_OVL_SHIFT 1 + +#define WL_BSSTYPE_INFRA 1 +#define WL_BSSTYPE_INDEP 0 +#define WL_BSSTYPE_ANY 2 + +/* Bitmask for scan_type */ +#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ +#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ +#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ +#define WL_SCANFLAGS_OFFCHAN 0x08 /* allow scanning/reporting off-channel APs */ +#define WL_SCANFLAGS_HOTSPOT 0x10 /* automatic ANQP to hotspot APs */ +#define WL_SCANFLAGS_SWTCHAN 0x20 /* Force channel switch for differerent bandwidth */ + +/* wl_iscan_results status values */ +#define WL_SCAN_RESULTS_SUCCESS 0 +#define WL_SCAN_RESULTS_PARTIAL 1 +#define WL_SCAN_RESULTS_PENDING 2 +#define WL_SCAN_RESULTS_ABORTED 3 +#define WL_SCAN_RESULTS_NO_MEM 4 + +#define SCANOL_ENABLED (1 << 0) +#define SCANOL_BCAST_SSID (1 << 1) +#define SCANOL_NOTIFY_BCAST_SSID (1 << 2) +#define SCANOL_RESULTS_PER_CYCLE (1 << 3) + +/* scan times in milliseconds */ +#define SCANOL_HOME_TIME 45 /* for home channel processing */ +#define SCANOL_ASSOC_TIME 20 /* dwell on a channel while associated */ +#define SCANOL_UNASSOC_TIME 40 /* dwell on a channel while unassociated */ +#define SCANOL_PASSIVE_TIME 110 /* listen on a channelfor passive scan */ +#define SCANOL_AWAY_LIMIT 100 /* max time to be away from home channel */ +#define SCANOL_IDLE_REST_TIME 40 +#define SCANOL_IDLE_REST_MULTIPLIER 0 +#define SCANOL_ACTIVE_REST_TIME 20 +#define SCANOL_ACTIVE_REST_MULTIPLIER 0 +#define SCANOL_CYCLE_IDLE_REST_TIME 300000 /* Idle Rest Time between Scan Cycle (msec) */ +#define SCANOL_CYCLE_IDLE_REST_MULTIPLIER 0 /* Idle Rest Time Multiplier */ +#define SCANOL_CYCLE_ACTIVE_REST_TIME 200 +#define SCANOL_CYCLE_ACTIVE_REST_MULTIPLIER 0 +#define SCANOL_MAX_REST_TIME 3600000 /* max rest time between scan cycle (msec) */ +#define SCANOL_CYCLE_DEFAULT 0 /* default for Max Scan Cycle, 0 = forever */ +#define SCANOL_CYCLE_MAX 864000 /* Max Scan Cycle */ + /* 10 sec/scan cycle => 100 days */ +#define SCANOL_NPROBES 2 /* for Active scan; send n probes on each channel */ +#define SCANOL_NPROBES_MAX 5 /* for Active scan; send n probes on each channel */ +#define SCANOL_SCAN_START_DLY 10 /* delay start of offload scan (sec) */ +#define SCANOL_SCAN_START_DLY_MAX 240 /* delay start of offload scan (sec) */ +#define SCANOL_MULTIPLIER_MAX 10 /* Max Multiplier */ +#define SCANOL_UNASSOC_TIME_MAX 100 /* max dwell on a channel while unassociated */ +#define SCANOL_PASSIVE_TIME_MAX 500 /* max listen on a channel for passive scan */ +#define SCANOL_SSID_MAX 16 /* max supported preferred SSID */ + +/* masks for channel and ssid count */ +#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff +#define WL_SCAN_PARAMS_NSSID_SHIFT 16 + +#define WL_SCAN_ACTION_START 1 +#define WL_SCAN_ACTION_CONTINUE 2 +#define WL_SCAN_ACTION_ABORT 3 + + +#define ANTENNA_NUM_1 1 /* total number of antennas to be used */ +#define ANTENNA_NUM_2 2 +#define ANTENNA_NUM_3 3 +#define ANTENNA_NUM_4 4 + +#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 */ + +/* interference source detection and identification mode */ +#define ITFR_MODE_DISABLE 0 /* disable feature */ +#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */ +#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */ + +/* bit definitions for flags in interference source report */ +#define ITFR_INTERFERENCED 1 /* interference detected */ +#define ITFR_HOME_CHANNEL 2 /* home channel has interference */ +#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */ + +#define WL_NUM_RPI_BINS 8 +#define WL_RM_TYPE_BASIC 1 +#define WL_RM_TYPE_CCA 2 +#define WL_RM_TYPE_RPI 3 +#define WL_RM_TYPE_ABORT -1 /* ABORT any in-progress RM request */ + +#define WL_RM_FLAG_PARALLEL (1<<0) + +#define WL_RM_FLAG_LATE (1<<1) +#define WL_RM_FLAG_INCAPABLE (1<<2) +#define WL_RM_FLAG_REFUSED (1<<3) + +/* flags */ +#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ + +#define WLC_CIS_DEFAULT 0 /* built-in default */ +#define WLC_CIS_SROM 1 /* source is sprom */ +#define WLC_CIS_OTP 2 /* source is otp */ + +/* PCL - Power Control Loop */ +/* current gain setting is replaced by user input */ +#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ +#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ +/* current gain setting is maintained */ +#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ + +#define PLC_CMD_FAILOVER 1 +#define PLC_CMD_MAC_COST 2 +#define PLC_CMD_LINK_COST 3 +#define PLC_CMD_NODE_LIST 4 + +#define NODE_TYPE_UNKNOWN 0 /* Unknown link */ +#define NODE_TYPE_WIFI_ONLY 1 /* Pure Wireless STA node */ +#define NODE_TYPE_PLC_ONLY 2 /* Pure PLC only node */ +#define NODE_TYPE_WIFI_PLC 3 /* WiFi PLC capable node */ + +/* defines used by poweridx iovar - it controls power in a-band */ +/* current gain setting is maintained */ +#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ +#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ +#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ +#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ +/* value >= 0 causes + * - input to be set to that value + * - PCL to be off + */ + +#define BCM_MAC_STATUS_INDICATION (0x40010200L) + +/* Values for TX Filter override mode */ +#define WLC_TXFILTER_OVERRIDE_DISABLED 0 +#define WLC_TXFILTER_OVERRIDE_ENABLED 1 + +/* magic pattern used for mismatch driver and wl */ +#define WL_TXFIFO_SZ_MAGIC 0xa5a5 + +/* check this magic number */ +#define WLC_IOCTL_MAGIC 0x14e46c77 + + +/* bss_info_cap_t flags */ +#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */ +#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */ +#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info received on channel (vs offchannel) */ +#define WL_BSS_FLAGS_HS20 0x08 /* hotspot 2.0 capable */ +#define WL_BSS_FLAGS_RSSI_INVALID 0x10 /* BSS contains invalid RSSI */ +#define WL_BSS_FLAGS_RSSI_INACCURATE 0x20 /* BSS contains inaccurate RSSI */ +#define WL_BSS_FLAGS_SNR_INVALID 0x40 /* BSS contains invalid SNR */ +#define WL_BSS_FLAGS_NF_INVALID 0x80 /* BSS contains invalid noise floor */ + +/* bssinfo flag for nbss_cap */ +#define VHT_BI_SGI_80MHZ 0x00000100 +#define VHT_BI_80MHZ 0x00000200 +#define VHT_BI_160MHZ 0x00000400 +#define VHT_BI_8080MHZ 0x00000800 + +/* reference to wl_ioctl_t struct used by usermode driver */ +#define ioctl_subtype set /* subtype param */ +#define ioctl_pid used /* pid param */ +#define ioctl_status needed /* status param */ + + +/* 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_OCB_MSDU 5 +#define CRYPTO_ALGO_AES_OCB_MPDU 6 +#if !defined(BCMCCX) && !defined(BCMEXTCCX) +#define CRYPTO_ALGO_NALG 7 +#else +#define CRYPTO_ALGO_CKIP 7 +#define CRYPTO_ALGO_CKIP_MMH 8 +#define CRYPTO_ALGO_WEP_MMH 9 +#define CRYPTO_ALGO_NALG 10 +#endif /* !BCMCCX && !BCMEXTCCX */ + +#define CRYPTO_ALGO_SMS4 11 +#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ +#define CRYPTO_ALGO_BIP 13 /* 802.11w BIP (aes cmac) */ + +#define CRYPTO_ALGO_AES_GCM 14 /* 128 bit GCM */ +#define CRYPTO_ALGO_AES_CCM256 15 /* 256 bit CCM */ +#define CRYPTO_ALGO_AES_GCM256 16 /* 256 bit GCM */ +#define CRYPTO_ALGO_BIP_CMAC256 17 /* 256 bit BIP CMAC */ +#define CRYPTO_ALGO_BIP_GMAC 18 /* 128 bit BIP GMAC */ +#define CRYPTO_ALGO_BIP_GMAC256 19 /* 256 bit BIP GMAC */ + +#define CRYPTO_ALGO_NONE CRYPTO_ALGO_OFF + +#define WSEC_GEN_MIC_ERROR 0x0001 +#define WSEC_GEN_REPLAY 0x0002 +#define WSEC_GEN_ICV_ERROR 0x0004 +#define WSEC_GEN_MFP_ACT_ERROR 0x0008 +#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 +#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 + +#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ +#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ +#if defined(BCMCCX) || defined(BCMEXTCCX) +#define WL_CKIP_KP (1 << 4) /* CMIC */ +#define WL_CKIP_MMH (1 << 5) /* CKIP */ +#else +#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ +#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ +#endif /* BCMCCX || BCMEXTCCX */ +#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ + +/* wireless security bitvec */ +#define WEP_ENABLED 0x0001 +#define TKIP_ENABLED 0x0002 +#define AES_ENABLED 0x0004 +#define WSEC_SWFLAG 0x0008 +#ifdef BCMCCX +#define CKIP_KP_ENABLED 0x0010 +#define CKIP_MIC_ENABLED 0x0020 +#endif /* BCMCCX */ +#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */ +#ifdef BCMWAPI_WPI +#define SMS4_ENABLED 0x0100 +#endif /* BCMWAPI_WPI */ + +/* wsec macros for operating on the above definitions */ +#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) +#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) +#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) + +#ifdef BCMCCX +#define WSEC_CKIP_KP_ENABLED(wsec) ((wsec) & CKIP_KP_ENABLED) +#define WSEC_CKIP_MIC_ENABLED(wsec) ((wsec) & CKIP_MIC_ENABLED) +#define WSEC_CKIP_ENABLED(wsec) ((wsec) & (CKIP_KP_ENABLED|CKIP_MIC_ENABLED)) + +#ifdef BCMWAPI_WPI +#define WSEC_ENABLED(wsec) \ + ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | \ + CKIP_MIC_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define WSEC_ENABLED(wsec) \ + ((wsec) & \ + (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | CKIP_MIC_ENABLED)) +#endif /* BCMWAPI_WPI */ +#else /* defined BCMCCX */ +#ifdef BCMWAPI_WPI +#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) +#endif /* BCMWAPI_WPI */ +#endif /* BCMCCX */ +#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) +#ifdef BCMWAPI_WAI +#define WSEC_SMS4_ENABLED(wsec) ((wsec) & SMS4_ENABLED) +#endif /* BCMWAPI_WAI */ + +#define MFP_CAPABLE 0x0200 +#define MFP_REQUIRED 0x0400 +#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ + +/* 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 */ +#if defined(BCMCCX) || defined(BCMEXTCCX) +#define WPA_AUTH_CCKM 0x0008 /* CCKM */ +#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ +#endif /* BCMCCX || BCMEXTCCX */ +/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ +#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ +#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ +#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */ +#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */ +#if defined(BCMWAPI_WAI) || defined(BCMWAPI_WPI) +#define WPA_AUTH_WAPI 0x0400 +#define WAPI_AUTH_NONE WPA_AUTH_NONE /* none (IBSS) */ +#define WAPI_AUTH_UNSPECIFIED 0x0400 /* over AS */ +#define WAPI_AUTH_PSK 0x0800 /* Pre-shared key */ +#endif /* BCMWAPI_WAI || BCMWAPI_WPI */ +#define WPA2_AUTH_MFP 0x1000 +#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */ +#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */ +#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ + +/* pmkid */ +#define MAXPMKID 16 + +#ifdef SROM12 +#define WLC_IOCTL_MAXLEN 10000 /* max length ioctl buffer required */ +#else +#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ +#endif /* SROM12 */ + +#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ +#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ +#if defined(LCNCONF) || defined(LCN40CONF) +#define WLC_SAMPLECOLLECT_MAXLEN 1024 /* Max Sample Collect buffer */ +#else +#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ +#endif +#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192 + +/* common ioctl definitions */ +#define WLC_GET_MAGIC 0 +#define WLC_GET_VERSION 1 +#define WLC_UP 2 +#define WLC_DOWN 3 +#define WLC_GET_LOOP 4 +#define WLC_SET_LOOP 5 +#define WLC_DUMP 6 +#define WLC_GET_MSGLEVEL 7 +#define WLC_SET_MSGLEVEL 8 +#define WLC_GET_PROMISC 9 +#define WLC_SET_PROMISC 10 +/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */ +#define WLC_GET_RATE 12 +#define WLC_GET_MAX_RATE 13 +#define WLC_GET_INSTANCE 14 +/* #define WLC_GET_FRAG 15 */ /* no longer supported */ +/* #define WLC_SET_FRAG 16 */ /* no longer supported */ +/* #define WLC_GET_RTS 17 */ /* no longer supported */ +/* #define WLC_SET_RTS 18 */ /* no longer supported */ +#define WLC_GET_INFRA 19 +#define WLC_SET_INFRA 20 +#define WLC_GET_AUTH 21 +#define WLC_SET_AUTH 22 +#define WLC_GET_BSSID 23 +#define WLC_SET_BSSID 24 +#define WLC_GET_SSID 25 +#define WLC_SET_SSID 26 +#define WLC_RESTART 27 +#define WLC_TERMINATED 28 +/* #define WLC_DUMP_SCB 28 */ /* no longer supported */ +#define WLC_GET_CHANNEL 29 +#define WLC_SET_CHANNEL 30 +#define WLC_GET_SRL 31 +#define WLC_SET_SRL 32 +#define WLC_GET_LRL 33 +#define WLC_SET_LRL 34 +#define WLC_GET_PLCPHDR 35 +#define WLC_SET_PLCPHDR 36 +#define WLC_GET_RADIO 37 +#define WLC_SET_RADIO 38 +#define WLC_GET_PHYTYPE 39 +#define WLC_DUMP_RATE 40 +#define WLC_SET_RATE_PARAMS 41 +#define WLC_GET_FIXRATE 42 +#define WLC_SET_FIXRATE 43 +/* #define WLC_GET_WEP 42 */ /* no longer supported */ +/* #define WLC_SET_WEP 43 */ /* no longer supported */ +#define WLC_GET_KEY 44 +#define WLC_SET_KEY 45 +#define WLC_GET_REGULATORY 46 +#define WLC_SET_REGULATORY 47 +#define WLC_GET_PASSIVE_SCAN 48 +#define WLC_SET_PASSIVE_SCAN 49 +#define WLC_SCAN 50 +#define WLC_SCAN_RESULTS 51 +#define WLC_DISASSOC 52 +#define WLC_REASSOC 53 +#define WLC_GET_ROAM_TRIGGER 54 +#define WLC_SET_ROAM_TRIGGER 55 +#define WLC_GET_ROAM_DELTA 56 +#define WLC_SET_ROAM_DELTA 57 +#define WLC_GET_ROAM_SCAN_PERIOD 58 +#define WLC_SET_ROAM_SCAN_PERIOD 59 +#define WLC_EVM 60 /* diag */ +#define WLC_GET_TXANT 61 +#define WLC_SET_TXANT 62 +#define WLC_GET_ANTDIV 63 +#define WLC_SET_ANTDIV 64 +/* #define WLC_GET_TXPWR 65 */ /* no longer supported */ +/* #define WLC_SET_TXPWR 66 */ /* no longer supported */ +#define WLC_GET_CLOSED 67 +#define WLC_SET_CLOSED 68 +#define WLC_GET_MACLIST 69 +#define WLC_SET_MACLIST 70 +#define WLC_GET_RATESET 71 +#define WLC_SET_RATESET 72 +/* #define WLC_GET_LOCALE 73 */ /* no longer supported */ +#define WLC_LONGTRAIN 74 +#define WLC_GET_BCNPRD 75 +#define WLC_SET_BCNPRD 76 +#define WLC_GET_DTIMPRD 77 +#define WLC_SET_DTIMPRD 78 +#define WLC_GET_SROM 79 +#define WLC_SET_SROM 80 +#define WLC_GET_WEP_RESTRICT 81 +#define WLC_SET_WEP_RESTRICT 82 +#define WLC_GET_COUNTRY 83 +#define WLC_SET_COUNTRY 84 +#define WLC_GET_PM 85 +#define WLC_SET_PM 86 +#define WLC_GET_WAKE 87 +#define WLC_SET_WAKE 88 +/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */ +#define WLC_GET_FORCELINK 90 /* ndis only */ +#define WLC_SET_FORCELINK 91 /* ndis only */ +#define WLC_FREQ_ACCURACY 92 /* diag */ +#define WLC_CARRIER_SUPPRESS 93 /* diag */ +#define WLC_GET_PHYREG 94 +#define WLC_SET_PHYREG 95 +#define WLC_GET_RADIOREG 96 +#define WLC_SET_RADIOREG 97 +#define WLC_GET_REVINFO 98 +#define WLC_GET_UCANTDIV 99 +#define WLC_SET_UCANTDIV 100 +#define WLC_R_REG 101 +#define WLC_W_REG 102 +/* #define WLC_DIAG_LOOPBACK 103 old tray diag */ +/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */ +#define WLC_GET_MACMODE 105 +#define WLC_SET_MACMODE 106 +#define WLC_GET_MONITOR 107 +#define WLC_SET_MONITOR 108 +#define WLC_GET_GMODE 109 +#define WLC_SET_GMODE 110 +#define WLC_GET_LEGACY_ERP 111 +#define WLC_SET_LEGACY_ERP 112 +#define WLC_GET_RX_ANT 113 +#define WLC_GET_CURR_RATESET 114 /* current rateset */ +#define WLC_GET_SCANSUPPRESS 115 +#define WLC_SET_SCANSUPPRESS 116 +#define WLC_GET_AP 117 +#define WLC_SET_AP 118 +#define WLC_GET_EAP_RESTRICT 119 +#define WLC_SET_EAP_RESTRICT 120 +#define WLC_SCB_AUTHORIZE 121 +#define WLC_SCB_DEAUTHORIZE 122 +#define WLC_GET_WDSLIST 123 +#define WLC_SET_WDSLIST 124 +#define WLC_GET_ATIM 125 +#define WLC_SET_ATIM 126 +#define WLC_GET_RSSI 127 +#define WLC_GET_PHYANTDIV 128 +#define WLC_SET_PHYANTDIV 129 +#define WLC_AP_RX_ONLY 130 +#define WLC_GET_TX_PATH_PWR 131 +#define WLC_SET_TX_PATH_PWR 132 +#define WLC_GET_WSEC 133 +#define WLC_SET_WSEC 134 +#define WLC_GET_PHY_NOISE 135 +#define WLC_GET_BSS_INFO 136 +#define WLC_GET_PKTCNTS 137 +#define WLC_GET_LAZYWDS 138 +#define WLC_SET_LAZYWDS 139 +#define WLC_GET_BANDLIST 140 + +#define WLC_GET_BAND 141 +#define WLC_SET_BAND 142 +#define WLC_SCB_DEAUTHENTICATE 143 +#define WLC_GET_SHORTSLOT 144 +#define WLC_GET_SHORTSLOT_OVERRIDE 145 +#define WLC_SET_SHORTSLOT_OVERRIDE 146 +#define WLC_GET_SHORTSLOT_RESTRICT 147 +#define WLC_SET_SHORTSLOT_RESTRICT 148 +#define WLC_GET_GMODE_PROTECTION 149 +#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 +#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 +#define WLC_UPGRADE 152 +/* #define WLC_GET_MRATE 153 */ /* no longer supported */ +/* #define WLC_SET_MRATE 154 */ /* no longer supported */ +#define WLC_GET_IGNORE_BCNS 155 +#define WLC_SET_IGNORE_BCNS 156 +#define WLC_GET_SCB_TIMEOUT 157 +#define WLC_SET_SCB_TIMEOUT 158 +#define WLC_GET_ASSOCLIST 159 +#define WLC_GET_CLK 160 +#define WLC_SET_CLK 161 +#define WLC_GET_UP 162 +#define WLC_OUT 163 +#define WLC_GET_WPA_AUTH 164 +#define WLC_SET_WPA_AUTH 165 +#define WLC_GET_UCFLAGS 166 +#define WLC_SET_UCFLAGS 167 +#define WLC_GET_PWRIDX 168 +#define WLC_SET_PWRIDX 169 +#define WLC_GET_TSSI 170 +#define WLC_GET_SUP_RATESET_OVERRIDE 171 +#define WLC_SET_SUP_RATESET_OVERRIDE 172 +/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */ +/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */ +/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */ +/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */ +/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */ +#define WLC_GET_PROTECTION_CONTROL 178 +#define WLC_SET_PROTECTION_CONTROL 179 +#define WLC_GET_PHYLIST 180 +#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */ +#define WLC_DECRYPT_STATUS 182 /* ndis only */ +#define WLC_GET_KEY_SEQ 183 +#define WLC_GET_SCAN_CHANNEL_TIME 184 +#define WLC_SET_SCAN_CHANNEL_TIME 185 +#define WLC_GET_SCAN_UNASSOC_TIME 186 +#define WLC_SET_SCAN_UNASSOC_TIME 187 +#define WLC_GET_SCAN_HOME_TIME 188 +#define WLC_SET_SCAN_HOME_TIME 189 +#define WLC_GET_SCAN_NPROBES 190 +#define WLC_SET_SCAN_NPROBES 191 +#define WLC_GET_PRB_RESP_TIMEOUT 192 +#define WLC_SET_PRB_RESP_TIMEOUT 193 +#define WLC_GET_ATTEN 194 +#define WLC_SET_ATTEN 195 +#define WLC_GET_SHMEM 196 /* diag */ +#define WLC_SET_SHMEM 197 /* diag */ +/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */ +/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */ +#define WLC_SET_WSEC_TEST 200 +#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 +#define WLC_TKIP_COUNTERMEASURES 202 +#define WLC_GET_PIOMODE 203 +#define WLC_SET_PIOMODE 204 +#define WLC_SET_ASSOC_PREFER 205 +#define WLC_GET_ASSOC_PREFER 206 +#define WLC_SET_ROAM_PREFER 207 +#define WLC_GET_ROAM_PREFER 208 +#define WLC_SET_LED 209 +#define WLC_GET_LED 210 +#define WLC_GET_INTERFERENCE_MODE 211 +#define WLC_SET_INTERFERENCE_MODE 212 +#define WLC_GET_CHANNEL_QA 213 +#define WLC_START_CHANNEL_QA 214 +#define WLC_GET_CHANNEL_SEL 215 +#define WLC_START_CHANNEL_SEL 216 +#define WLC_GET_VALID_CHANNELS 217 +#define WLC_GET_FAKEFRAG 218 +#define WLC_SET_FAKEFRAG 219 +#define WLC_GET_PWROUT_PERCENTAGE 220 +#define WLC_SET_PWROUT_PERCENTAGE 221 +#define WLC_SET_BAD_FRAME_PREEMPT 222 +#define WLC_GET_BAD_FRAME_PREEMPT 223 +#define WLC_SET_LEAP_LIST 224 +#define WLC_GET_LEAP_LIST 225 +#define WLC_GET_CWMIN 226 +#define WLC_SET_CWMIN 227 +#define WLC_GET_CWMAX 228 +#define WLC_SET_CWMAX 229 +#define WLC_GET_WET 230 +#define WLC_SET_WET 231 +#define WLC_GET_PUB 232 +/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */ +/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */ +#define WLC_GET_KEY_PRIMARY 235 +#define WLC_SET_KEY_PRIMARY 236 + + +/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */ +#define WLC_GET_ACI_ARGS 238 +#define WLC_SET_ACI_ARGS 239 +#define WLC_UNSET_CALLBACK 240 +#define WLC_SET_CALLBACK 241 +#define WLC_GET_RADAR 242 +#define WLC_SET_RADAR 243 +#define WLC_SET_SPECT_MANAGMENT 244 +#define WLC_GET_SPECT_MANAGMENT 245 +#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ +#define WLC_WDS_GET_WPA_SUP 247 +#define WLC_SET_CS_SCAN_TIMER 248 +#define WLC_GET_CS_SCAN_TIMER 249 +#define WLC_MEASURE_REQUEST 250 +#define WLC_INIT 251 +#define WLC_SEND_QUIET 252 +#define WLC_KEEPALIVE 253 +#define WLC_SEND_PWR_CONSTRAINT 254 +#define WLC_UPGRADE_STATUS 255 +#define WLC_CURRENT_PWR 256 +#define WLC_GET_SCAN_PASSIVE_TIME 257 +#define WLC_SET_SCAN_PASSIVE_TIME 258 +#define WLC_LEGACY_LINK_BEHAVIOR 259 +#define WLC_GET_CHANNELS_IN_COUNTRY 260 +#define WLC_GET_COUNTRY_LIST 261 +#define WLC_GET_VAR 262 /* get value of named variable */ +#define WLC_SET_VAR 263 /* set named variable to value */ +#define WLC_NVRAM_GET 264 /* deprecated */ +#define WLC_NVRAM_SET 265 +#define WLC_NVRAM_DUMP 266 +#define WLC_REBOOT 267 +#define WLC_SET_WSEC_PMK 268 +#define WLC_GET_AUTH_MODE 269 +#define WLC_SET_AUTH_MODE 270 +#define WLC_GET_WAKEENTRY 271 +#define WLC_SET_WAKEENTRY 272 +#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ +#define WLC_NVOTPW 274 +#define WLC_OTPW 275 +#define WLC_IOV_BLOCK_GET 276 +#define WLC_IOV_MODULES_GET 277 +#define WLC_SOFT_RESET 278 +#define WLC_GET_ALLOW_MODE 279 +#define WLC_SET_ALLOW_MODE 280 +#define WLC_GET_DESIRED_BSSID 281 +#define WLC_SET_DESIRED_BSSID 282 +#define WLC_DISASSOC_MYAP 283 +#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */ +#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */ +#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */ +#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */ +#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */ +#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */ +#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */ +#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */ +#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */ +#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */ +#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */ +#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */ +#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */ +#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */ +#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */ +#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */ +#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */ +#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */ +#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */ +#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */ +#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */ +#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */ +#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */ +#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */ +/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */ +#define WLC_GET_CMD 309 +/* #define WLC_LAST 310 */ /* Never used - can be reused */ +#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */ +#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */ +/* #define WLC_GET_WAI_RESTRICT 313 */ /* for WAPI, deprecated use iovar instead */ +/* #define WLC_SET_WAI_RESTRICT 314 */ /* for WAPI, deprecated use iovar instead */ +/* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */ +#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ +#define WLC_GET_NAT_STATE 317 +#define WLC_GET_TXBF_RATESET 318 +#define WLC_SET_TXBF_RATESET 319 +#define WLC_SCAN_CQ 320 +#define WLC_GET_RSSI_QDB 321 /* qdB portion of the RSSI */ +#define WLC_DUMP_RATESET 322 +#define WLC_ECHO 323 +#define WLC_LAST 324 +#ifndef EPICTRL_COOKIE +#define EPICTRL_COOKIE 0xABADCEDE +#endif + +/* vx wlc ioctl's offset */ +#define CMN_IOCTL_OFF 0x180 + +/* + * custom OID support + * + * 0xFF - implementation specific OID + * 0xE4 - first byte of Broadcom PCI vendor ID + * 0x14 - second byte of Broadcom PCI vendor ID + * 0xXX - the custom OID number + */ + +/* begin 0x1f values beyond the start of the ET driver range. */ +#define WL_OID_BASE 0xFFE41420 + +/* NDIS overrides */ +#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) +#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) +#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) +#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) +#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) +#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) +#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) + +/* EXT_STA Dongle suuport */ +#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) +#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) +#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) +#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) +#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) +#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) +#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) +#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) +#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) +#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) +#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) +#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) +#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) +#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) +#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) + +/* NAT filter driver support */ +#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG) +#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE) + +#define WL_DECRYPT_STATUS_SUCCESS 1 +#define WL_DECRYPT_STATUS_FAILURE 2 +#define WL_DECRYPT_STATUS_UNKNOWN 3 + +/* allows user-mode app to poll the status of USB image upgrade */ +#define WLC_UPGRADE_SUCCESS 0 +#define WLC_UPGRADE_PENDING 1 + +/* WLC_GET_AUTH, WLC_SET_AUTH values */ +#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ +#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ +#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ + +/* a large TX Power as an init value to factor out of MIN() calculations, + * keep low enough to fit in an int8, units are .25 dBm + */ +#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ + +/* "diag" iovar argument and error code */ +#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */ +#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */ +#define WL_DIAG_MEMORY 3 /* d11 memory test */ +#define WL_DIAG_LED 4 /* LED test */ +#define WL_DIAG_REG 5 /* d11/phy register test */ +#define WL_DIAG_SROM 6 /* srom read/crc test */ +#define WL_DIAG_DMA 7 /* DMA test */ +#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */ + +#define WL_DIAGERR_SUCCESS 0 +#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */ +#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */ +#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */ +#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */ +#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */ +#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */ +#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */ +#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */ +#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */ +#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */ + +#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */ +#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */ + +/* band types */ +#define WLC_BAND_AUTO 0 /* auto-select */ +#define WLC_BAND_5G 1 /* 5 Ghz */ +#define WLC_BAND_2G 2 /* 2.4 Ghz */ +#define WLC_BAND_ALL 3 /* all bands */ + +/* band range returned by band_range iovar */ +#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 + +#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4 +#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5 +#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6 +#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7 +#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8 + +#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 +#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 +#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 +#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 + +#ifdef SROM12 +#define WL_CHAN_FREQ_RANGE_5G_BAND4 5 +#define WL_CHAN_FREQ_RANGE_2G_40 6 +#define WL_CHAN_FREQ_RANGE_5G_BAND0_40 7 +#define WL_CHAN_FREQ_RANGE_5G_BAND1_40 8 +#define WL_CHAN_FREQ_RANGE_5G_BAND2_40 9 +#define WL_CHAN_FREQ_RANGE_5G_BAND3_40 10 +#define WL_CHAN_FREQ_RANGE_5G_BAND4_40 11 +#define WL_CHAN_FREQ_RANGE_5G_BAND0_80 12 +#define WL_CHAN_FREQ_RANGE_5G_BAND1_80 13 +#define WL_CHAN_FREQ_RANGE_5G_BAND2_80 14 +#define WL_CHAN_FREQ_RANGE_5G_BAND3_80 15 +#define WL_CHAN_FREQ_RANGE_5G_BAND4_80 16 + +#define WL_CHAN_FREQ_RANGE_5G_4BAND 17 +#define WL_CHAN_FREQ_RANGE_5G_5BAND 18 +#define WL_CHAN_FREQ_RANGE_5G_5BAND_40 19 +#define WL_CHAN_FREQ_RANGE_5G_5BAND_80 20 +#else +#define WL_CHAN_FREQ_RANGE_5G_4BAND 5 +#endif /* SROM12 */ +/* MAC list modes */ +#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */ +#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */ +#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */ + +/* + * 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 + +/* values for PLCPHdr_override */ +#define WLC_PLCP_AUTO -1 +#define WLC_PLCP_SHORT 0 +#define WLC_PLCP_LONG 1 + +/* values for g_protection_override and n_protection_override */ +#define WLC_PROTECTION_AUTO -1 +#define WLC_PROTECTION_OFF 0 +#define WLC_PROTECTION_ON 1 +#define WLC_PROTECTION_MMHDR_ONLY 2 +#define WLC_PROTECTION_CTS_ONLY 3 + +/* values for g_protection_control and n_protection_control */ +#define WLC_PROTECTION_CTL_OFF 0 +#define WLC_PROTECTION_CTL_LOCAL 1 +#define WLC_PROTECTION_CTL_OVERLAP 2 + +/* values for n_protection */ +#define WLC_N_PROTECTION_OFF 0 +#define WLC_N_PROTECTION_OPTIONAL 1 +#define WLC_N_PROTECTION_20IN40 2 +#define WLC_N_PROTECTION_MIXEDMODE 3 + +/* values for n_preamble_type */ +#define WLC_N_PREAMBLE_MIXEDMODE 0 +#define WLC_N_PREAMBLE_GF 1 +#define WLC_N_PREAMBLE_GF_BRCM 2 + +/* values for band specific 40MHz capabilities (deprecated) */ +#define WLC_N_BW_20ALL 0 +#define WLC_N_BW_40ALL 1 +#define WLC_N_BW_20IN2G_40IN5G 2 + +#define WLC_BW_20MHZ_BIT (1<<0) +#define WLC_BW_40MHZ_BIT (1<<1) +#define WLC_BW_80MHZ_BIT (1<<2) +#define WLC_BW_160MHZ_BIT (1<<3) + +/* Bandwidth capabilities */ +#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_160MHZ (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ + WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_UNRESTRICTED 0xFF + +#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) +#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) +#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) +#define WL_BW_CAP_160MHZ(bw_cap)(((bw_cap) & WLC_BW_160MHZ_BIT) ? TRUE : FALSE) + +/* values to force tx/rx chain */ +#define WLC_N_TXRX_CHAIN0 0 +#define WLC_N_TXRX_CHAIN1 1 + +/* bitflags for SGI support (sgi_rx iovar) */ +#define WLC_N_SGI_20 0x01 +#define WLC_N_SGI_40 0x02 +#define WLC_VHT_SGI_80 0x04 + +/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ +#define WLC_SGI_ALL 0x02 + +#define LISTEN_INTERVAL 10 +/* interference mitigation options */ +#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ +#define INTERFERE_NONE 0 /* off */ +#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */ +#define WLAN_MANUAL 2 /* ACI: no auto detection */ +#define WLAN_AUTO 3 /* ACI: auto detect */ +#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ +#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ + +/* interfernece mode bit-masks (ACPHY) */ +#define ACPHY_ACI_GLITCHBASED_DESENSE 1 /* bit 0 */ +#define ACPHY_ACI_HWACI_PKTGAINLMT 2 /* bit 1 */ +#define ACPHY_ACI_W2NB_PKTGAINLMT 4 /* bit 2 */ +#define ACPHY_ACI_PREEMPTION 8 /* bit 3 */ +#define ACPHY_HWACI_MITIGATION 16 /* bit 4 */ +#define ACPHY_ACI_MAX_MODE 31 + +/* AP environment */ +#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ +#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ +#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ +#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ + +#define TRIGGER_NOW 0 +#define TRIGGER_CRS 0x01 +#define TRIGGER_CRSDEASSERT 0x02 +#define TRIGGER_GOODFCS 0x04 +#define TRIGGER_BADFCS 0x08 +#define TRIGGER_BADPLCP 0x10 +#define TRIGGER_CRSGLITCH 0x20 + +#define WL_SAMPLEDATA_HEADER_TYPE 1 +#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ +#define WL_SAMPLEDATA_TYPE 2 +#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ +#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ + +/* WL_OTA START */ +#define WL_OTA_ARG_PARSE_BLK_SIZE 1200 +#define WL_OTA_TEST_MAX_NUM_RATE 30 +#define WL_OTA_TEST_MAX_NUM_SEQ 100 + +#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */ + +/* radar iovar SET defines */ +#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */ +#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */ +#define WL_RADAR_SIMULATED 2 /* force radar detector to declare + * detection once + */ +#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */ +#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 */ + +#ifndef WL_RSSI_ANT_MAX +#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ +#elif WL_RSSI_ANT_MAX != 4 +#error "WL_RSSI_ANT_MAX does not match" +#endif + +/* dfs_status iovar-related defines */ + +/* cac - channel availability check, + * ism - in-service monitoring + * csa - channel switching announcement + */ + +/* cac state values */ +#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */ +#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */ +#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */ +#define WL_DFS_CACSTATE_CSA 3 /* csa */ +#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */ +#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */ +#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */ +#define WL_DFS_CACSTATES 7 /* this many states exist */ + +/* Defines used with channel_bandwidth for curpower */ +#define WL_BW_20MHZ 0 +#define WL_BW_40MHZ 1 +#define WL_BW_80MHZ 2 +#define WL_BW_160MHZ 3 +#define WL_BW_8080MHZ 4 + +/* tx_power_t.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 +#define WL_TX_POWER_F_HT 0x10 +#define WL_TX_POWER_F_VHT 0x20 +#define WL_TX_POWER_F_OPENLOOP 0x40 + +/* Message levels */ +#define WL_ERROR_VAL 0x00000001 +#define WL_TRACE_VAL 0x00000002 +#define WL_PRHDRS_VAL 0x00000004 +#define WL_PRPKT_VAL 0x00000008 +#define WL_INFORM_VAL 0x00000010 +#define WL_TMP_VAL 0x00000020 +#define WL_OID_VAL 0x00000040 +#define WL_RATE_VAL 0x00000080 +#define WL_ASSOC_VAL 0x00000100 +#define WL_PRUSR_VAL 0x00000200 +#define WL_PS_VAL 0x00000400 +#define WL_TXPWR_VAL 0x00000800 /* retired in TOT on 6/10/2009 */ +#define WL_MODE_SWITCH_VAL 0x00000800 /* Using retired TXPWR val */ +#define WL_PORT_VAL 0x00001000 +#define WL_DUAL_VAL 0x00002000 +#define WL_WSEC_VAL 0x00004000 +#define WL_WSEC_DUMP_VAL 0x00008000 +#define WL_LOG_VAL 0x00010000 +#define WL_NRSSI_VAL 0x00020000 /* retired in TOT on 6/10/2009 */ +#define WL_LOFT_VAL 0x00040000 /* retired in TOT on 6/10/2009 */ +#define WL_REGULATORY_VAL 0x00080000 +#define WL_TAF_VAL 0x00100000 +#define WL_RADAR_VAL 0x00200000 /* retired in TOT on 6/10/2009 */ +#define WL_MPC_VAL 0x00400000 +#define WL_APSTA_VAL 0x00800000 +#define WL_DFS_VAL 0x01000000 +#define WL_BA_VAL 0x02000000 /* retired in TOT on 6/14/2010 */ +#define WL_ACI_VAL 0x04000000 +#define WL_PRMAC_VAL 0x04000000 +#define WL_MBSS_VAL 0x04000000 +#define WL_CAC_VAL 0x08000000 +#define WL_AMSDU_VAL 0x10000000 +#define WL_AMPDU_VAL 0x20000000 +#define WL_FFPLD_VAL 0x40000000 + +/* wl_msg_level is full. For new bits take the next one and AND with + * wl_msg_level2 in wl_dbg.h + */ +#define WL_DPT_VAL 0x00000001 +#define WL_SCAN_VAL 0x00000002 +#define WL_WOWL_VAL 0x00000004 +#define WL_COEX_VAL 0x00000008 +#define WL_RTDC_VAL 0x00000010 +#define WL_PROTO_VAL 0x00000020 +#define WL_BTA_VAL 0x00000040 +#define WL_CHANINT_VAL 0x00000080 +#define WL_WMF_VAL 0x00000100 +#define WL_P2P_VAL 0x00000200 +#define WL_ITFR_VAL 0x00000400 +#define WL_MCHAN_VAL 0x00000800 +#define WL_TDLS_VAL 0x00001000 +#define WL_MCNX_VAL 0x00002000 +#define WL_PROT_VAL 0x00004000 +#define WL_PSTA_VAL 0x00008000 +#define WL_TSO_VAL 0x00010000 +#define WL_TRF_MGMT_VAL 0x00020000 +#define WL_LPC_VAL 0x00040000 +#define WL_L2FILTER_VAL 0x00080000 +#define WL_TXBF_VAL 0x00100000 +#define WL_P2PO_VAL 0x00200000 +#define WL_TBTT_VAL 0x00400000 +#define WL_MQ_VAL 0x01000000 + +/* This level is currently used in Phoenix2 only */ +#define WL_SRSCAN_VAL 0x02000000 + +#define WL_WNM_VAL 0x04000000 +#define WL_PWRSEL_VAL 0x10000000 +#define WL_NET_DETECT_VAL 0x20000000 +#define WL_PCIE_VAL 0x40000000 + +/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier + * rather than a message-type of its own + */ +#define WL_TIMESTAMP_VAL 0x80000000 + +/* max # of leds supported by GPIO (gpio pin# == led index#) */ +#define WL_LED_NUMGPIO 32 /* gpio 0-31 */ + +/* led per-pin behaviors */ +#define WL_LED_OFF 0 /* always off */ +#define WL_LED_ON 1 /* always on */ +#define WL_LED_ACTIVITY 2 /* activity */ +#define WL_LED_RADIO 3 /* radio enabled */ +#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */ +#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */ +#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */ +#define WL_LED_WI1 7 +#define WL_LED_WI2 8 +#define WL_LED_WI3 9 +#define WL_LED_ASSOC 10 /* associated state indicator */ +#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */ +#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */ +#define WL_LED_WI4 13 +#define WL_LED_WI5 14 +#define WL_LED_BLINKSLOW 15 /* blink slow */ +#define WL_LED_BLINKMED 16 /* blink med */ +#define WL_LED_BLINKFAST 17 /* blink fast */ +#define WL_LED_BLINKCUSTOM 18 /* blink custom */ +#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */ +#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ + /* keep on for 300 sec */ +#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ +#define WL_LED_WI6 22 +#define WL_LED_WI7 23 +#define WL_LED_WI8 24 +#define WL_LED_NUMBEHAVIOR 25 + +/* led behavior numeric value format */ +#define WL_LED_BEH_MASK 0x7f /* behavior mask */ +#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */ + +/* number of bytes needed to define a proper bit mask for MAC event reporting */ +#define BCMIO_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#define BCMIO_NBBY 8 +#define WL_EVENTING_MASK_LEN 16 + + +/* join preference types */ +#define WL_JOIN_PREF_RSSI 1 /* by RSSI */ +#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */ +#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */ +#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */ +#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */ + +/* band preference */ +#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */ + +/* any multicast cipher suite */ +#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" + +/* 802.11h measurement types */ +#define WLC_MEASURE_TPC 1 +#define WLC_MEASURE_CHANNEL_BASIC 2 +#define WLC_MEASURE_CHANNEL_CCA 3 +#define WLC_MEASURE_CHANNEL_RPI 4 + +/* regulatory enforcement levels */ +#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */ +#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */ +#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */ +#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */ +/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE + * adoption is done regardless of capability spectrum_management + */ +#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */ + +#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */ +#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */ +#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */ +#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */ +#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */ +#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */ +#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */ + +/* BTC mode used by "btc_mode" iovar */ +#define WL_BTC_DISABLE 0 /* disable BT coexistence */ +#define WL_BTC_FULLTDM 1 /* full TDM COEX */ +#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ +#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ +#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ +#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ +#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ +#define WL_BTC_DEFAULT 8 /* set the default mode for the device */ +#define WL_INF_BTC_DISABLE 0 +#define WL_INF_BTC_ENABLE 1 +#define WL_INF_BTC_AUTO 3 + +/* BTC wire used by "btc_wire" iovar */ +#define WL_BTC_DEFWIRE 0 /* use default wire setting */ +#define WL_BTC_2WIRE 2 /* use 2-wire BTC */ +#define WL_BTC_3WIRE 3 /* use 3-wire BTC */ +#define WL_BTC_4WIRE 4 /* use 4-wire BTC */ + +/* BTC flags: BTC configuration that can be set by host */ +#define WL_BTC_FLAG_PREMPT (1 << 0) +#define WL_BTC_FLAG_BT_DEF (1 << 1) +#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2) +#define WL_BTC_FLAG_SIM_RSP (1 << 3) +#define WL_BTC_FLAG_PS_PROTECT (1 << 4) +#define WL_BTC_FLAG_SIM_TX_LP (1 << 5) +#define WL_BTC_FLAG_ECI (1 << 6) +#define WL_BTC_FLAG_LIGHT (1 << 7) +#define WL_BTC_FLAG_PARALLEL (1 << 8) + +/* maximum channels returned by the get valid channels iovar */ +#define WL_NUMCHANNELS 64 + +/* max number of chanspecs (used by the iovar to calc. buf space) */ +#ifdef WL11AC_80P80 +#define WL_NUMCHANSPECS 206 +#else +#define WL_NUMCHANSPECS 110 +#endif + + +/* WDS link local endpoint WPA role */ +#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */ +#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ +#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ + +/* Base offset values */ +#define WL_PKT_FILTER_BASE_PKT 0 +#define WL_PKT_FILTER_BASE_END 1 +#define WL_PKT_FILTER_BASE_D11_H 2 /* May be removed */ +#define WL_PKT_FILTER_BASE_D11_D 3 /* May be removed */ +#define WL_PKT_FILTER_BASE_ETH_H 4 +#define WL_PKT_FILTER_BASE_ETH_D 5 +#define WL_PKT_FILTER_BASE_ARP_H 6 +#define WL_PKT_FILTER_BASE_ARP_D 7 /* May be removed */ +#define WL_PKT_FILTER_BASE_IP4_H 8 +#define WL_PKT_FILTER_BASE_IP4_D 9 +#define WL_PKT_FILTER_BASE_IP6_H 10 +#define WL_PKT_FILTER_BASE_IP6_D 11 +#define WL_PKT_FILTER_BASE_TCP_H 12 +#define WL_PKT_FILTER_BASE_TCP_D 13 /* May be removed */ +#define WL_PKT_FILTER_BASE_UDP_H 14 +#define WL_PKT_FILTER_BASE_UDP_D 15 +#define WL_PKT_FILTER_BASE_IP6_P 16 +#define WL_PKT_FILTER_BASE_COUNT 17 /* May be removed */ + +/* String mapping for bases that may be used by applications or debug */ +#define WL_PKT_FILTER_BASE_NAMES \ + { "START", WL_PKT_FILTER_BASE_PKT }, \ + { "END", WL_PKT_FILTER_BASE_END }, \ + { "ETH_H", WL_PKT_FILTER_BASE_ETH_H }, \ + { "ETH_D", WL_PKT_FILTER_BASE_ETH_D }, \ + { "D11_H", WL_PKT_FILTER_BASE_D11_H }, \ + { "D11_D", WL_PKT_FILTER_BASE_D11_D }, \ + { "ARP_H", WL_PKT_FILTER_BASE_ARP_H }, \ + { "IP4_H", WL_PKT_FILTER_BASE_IP4_H }, \ + { "IP4_D", WL_PKT_FILTER_BASE_IP4_D }, \ + { "IP6_H", WL_PKT_FILTER_BASE_IP6_H }, \ + { "IP6_D", WL_PKT_FILTER_BASE_IP6_D }, \ + { "IP6_P", WL_PKT_FILTER_BASE_IP6_P }, \ + { "TCP_H", WL_PKT_FILTER_BASE_TCP_H }, \ + { "TCP_D", WL_PKT_FILTER_BASE_TCP_D }, \ + { "UDP_H", WL_PKT_FILTER_BASE_UDP_H }, \ + { "UDP_D", WL_PKT_FILTER_BASE_UDP_D } + +/* Flags for a pattern list element */ +#define WL_PKT_FILTER_MFLAG_NEG 0x0001 + +/* + * Packet engine interface + */ + +#define WL_PKTENG_PER_TX_START 0x01 +#define WL_PKTENG_PER_TX_STOP 0x02 +#define WL_PKTENG_PER_RX_START 0x04 +#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 +#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 +#define WL_PKTENG_PER_RX_STOP 0x08 +#define WL_PKTENG_PER_MASK 0xff + +#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ + +#define WL_PKTENG_MAXPKTSZ 16384 /* max pktsz limit for pkteng */ + +#define NUM_80211b_RATES 4 +#define NUM_80211ag_RATES 8 +#define NUM_80211n_RATES 32 +#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) + +/* + * WOWL capability/override settings + */ +#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */ +#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */ +#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */ +#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */ +#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */ +#define WL_WOWL_TST (1 << 5) /* Wakeup after test */ +#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */ +#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */ +#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */ +#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */ +#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */ +#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */ +#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */ +#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */ +#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */ +#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */ +#define WL_WOWL_SCANOL (1 << 16) /* If the bit is set, scan offload is enabled */ +#define WL_WOWL_TCPKEEP_TIME (1 << 17) /* Wakeup on tcpkeep alive timeout */ +#define WL_WOWL_MDNS_CONFLICT (1 << 18) /* Wakeup on mDNS Conflict Resolution */ +#define WL_WOWL_MDNS_SERVICE (1 << 19) /* Wakeup on mDNS Service Connect */ +#define WL_WOWL_TCPKEEP_DATA (1 << 20) /* tcp keepalive got data */ +#define WL_WOWL_FW_HALT (1 << 21) /* Firmware died in wowl mode */ +#define WL_WOWL_ENAB_HWRADIO (1 << 22) /* Enable detection of radio button changes */ +#define WL_WOWL_MIC_FAIL (1 << 23) /* Offloads detected MIC failure(s) */ +#define WL_WOWL_UNASSOC (1 << 24) /* Wakeup in Unassociated state (Net/Magic Pattern) */ +#define WL_WOWL_SECURE (1 << 25) /* Wakeup if received matched secured pattern */ +#define WL_WOWL_LINKDOWN (1 << 31) /* Link Down indication in WoWL mode */ + +#define WL_WOWL_TCPKEEP (1 << 20) /* temp copy to satisfy automerger */ +#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ + +#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ +#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ + +#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ +#define MAGIC_PKT_NUM_MAC_ADDRS 16 + + +/* Overlap BSS Scan parameters default, minimum, maximum */ +#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */ +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */ +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */ +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */ +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */ +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */ +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */ + +#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */ + +#define WL_COEX_INFO_MASK 0x07 +#define WL_COEX_INFO_REQ 0x01 +#define WL_COEX_40MHZ_INTOLERANT 0x02 +#define WL_COEX_WIDTH20 0x04 + +#define WLC_RSSI_INVALID 0 /* invalid RSSI value */ + +#define MAX_RSSI_LEVELS 8 + +/* **** EXTLOG **** */ +#define EXTLOG_CUR_VER 0x0100 + +#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ + +/* log modules (bitmap) */ +#define LOG_MODULE_COMMON 0x0001 +#define LOG_MODULE_ASSOC 0x0002 +#define LOG_MODULE_EVENT 0x0004 +#define LOG_MODULE_MAX 3 /* Update when adding module */ + +/* log levels */ +#define WL_LOG_LEVEL_DISABLE 0 +#define WL_LOG_LEVEL_ERR 1 +#define WL_LOG_LEVEL_WARN 2 +#define WL_LOG_LEVEL_INFO 3 +#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */ + +/* flag */ +#define LOG_FLAG_EVENT 1 + +/* log arg_type */ +#define LOG_ARGTYPE_NULL 0 +#define LOG_ARGTYPE_STR 1 /* %s */ +#define LOG_ARGTYPE_INT 2 /* %d */ +#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */ +#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */ + +/* 802.11 Mgmt Packet flags */ +#define VNDR_IE_BEACON_FLAG 0x1 +#define VNDR_IE_PRBRSP_FLAG 0x2 +#define VNDR_IE_ASSOCRSP_FLAG 0x4 +#define VNDR_IE_AUTHRSP_FLAG 0x8 +#define VNDR_IE_PRBREQ_FLAG 0x10 +#define VNDR_IE_ASSOCREQ_FLAG 0x20 +#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ +#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ + +#if defined(WLP2P) +/* P2P Action Frames flags (spec ordered) */ +#define VNDR_IE_GONREQ_FLAG 0x001000 +#define VNDR_IE_GONRSP_FLAG 0x002000 +#define VNDR_IE_GONCFM_FLAG 0x004000 +#define VNDR_IE_INVREQ_FLAG 0x008000 +#define VNDR_IE_INVRSP_FLAG 0x010000 +#define VNDR_IE_DISREQ_FLAG 0x020000 +#define VNDR_IE_DISRSP_FLAG 0x040000 +#define VNDR_IE_PRDREQ_FLAG 0x080000 +#define VNDR_IE_PRDRSP_FLAG 0x100000 + +#define VNDR_IE_P2PAF_SHIFT 12 +#endif /* WLP2P */ + +/* channel interference measurement (chanim) related defines */ + +/* chanim mode */ +#define CHANIM_DISABLE 0 /* disabled */ +#define CHANIM_DETECT 1 /* detection only */ +#define CHANIM_EXT 2 /* external state machine */ +#define CHANIM_ACT 3 /* full internal state machine, detect + act */ +#define CHANIM_MODE_MAX 4 + +/* define for apcs reason code */ +#define APCS_INIT 0 +#define APCS_IOCTL 1 +#define APCS_CHANIM 2 +#define APCS_CSTIMER 3 +#define APCS_BTA 4 +#define APCS_TXDLY 5 +#define APCS_NONACSD 6 +#define APCS_DFS_REENTRY 7 +#define APCS_TXFAIL 8 +#define APCS_MAX 9 + +/* number of ACS record entries */ +#define CHANIM_ACS_RECORD 10 + +/* CHANIM */ +#define CCASTATS_TXDUR 0 +#define CCASTATS_INBSS 1 +#define CCASTATS_OBSS 2 +#define CCASTATS_NOCTG 3 +#define CCASTATS_NOPKT 4 +#define CCASTATS_DOZE 5 +#define CCASTATS_TXOP 6 +#define CCASTATS_GDTXDUR 7 +#define CCASTATS_BDTXDUR 8 +#define CCASTATS_MAX 9 + +#define WL_CHANIM_COUNT_ALL 0xff +#define WL_CHANIM_COUNT_ONE 0x1 + +/* ap tpc modes */ +#define AP_TPC_OFF 0 +#define AP_TPC_BSS_PWR 1 /* BSS power control */ +#define AP_TPC_AP_PWR 2 /* AP power control */ +#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ +#define AP_TPC_MAX_LINK_MARGIN 127 + +/* ap tpc modes */ +#define AP_TPC_OFF 0 +#define AP_TPC_BSS_PWR 1 /* BSS power control */ +#define AP_TPC_AP_PWR 2 /* AP power control */ +#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ +#define AP_TPC_MAX_LINK_MARGIN 127 + +/* state */ +#define WL_P2P_DISC_ST_SCAN 0 +#define WL_P2P_DISC_ST_LISTEN 1 +#define WL_P2P_DISC_ST_SEARCH 2 + +/* i/f type */ +#define WL_P2P_IF_CLIENT 0 +#define WL_P2P_IF_GO 1 +#define WL_P2P_IF_DYNBCN_GO 2 +#define WL_P2P_IF_DEV 3 + +/* count */ +#define WL_P2P_SCHED_RSVD 0 +#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */ + +#define WL_P2P_SCHED_FIXED_LEN 3 + +/* schedule type */ +#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */ +#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */ + +/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */ +#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */ +#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */ +/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ +#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */ +/* schedule option - WL_P2P_SCHED_TYPE_XXX */ +#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */ + +/* schedule option - WL_P2P_SCHED_TYPE_ABS */ +#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */ +#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */ +/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ +#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with + * start being an offset of the 'current' TSF + */ + +/* feature flags */ +#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */ +#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe + * requests + */ +#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */ + +/* 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 + +/* Proxy STA modes */ +#define PSTA_MODE_DISABLED 0 +#define PSTA_MODE_PROXY 1 +#define PSTA_MODE_REPEATER 2 + +/* op code in nat_cfg */ +#define NAT_OP_ENABLE 1 /* enable NAT on given interface */ +#define NAT_OP_DISABLE 2 /* disable NAT on given interface */ +#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */ + +/* NAT state */ +#define NAT_STATE_ENABLED 1 /* NAT is enabled */ +#define NAT_STATE_DISABLED 2 /* NAT is disabled */ + +#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */ +#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */ +#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */ +#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */ + +/* D0 Coalescing */ +#define IPV4_ARP_FILTER 0x0001 +#define IPV4_NETBT_FILTER 0x0002 +#define IPV4_LLMNR_FILTER 0x0004 +#define IPV4_SSDP_FILTER 0x0008 +#define IPV4_WSD_FILTER 0x0010 +#define IPV6_NETBT_FILTER 0x0200 +#define IPV6_LLMNR_FILTER 0x0400 +#define IPV6_SSDP_FILTER 0x0800 +#define IPV6_WSD_FILTER 0x1000 + +/* Network Offload Engine */ +#define NWOE_OL_ENABLE 0x00000001 + +/* + * Traffic management structures/defines. + */ + +/* Traffic management bandwidth parameters */ +#define TRF_MGMT_MAX_PRIORITIES 3 + +#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ +#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Don't shape traffic */ +#define TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC 0x0008 /* Manage traffic over our local subnet */ +#define TRF_MGMT_FLAG_FILTER_ON_MACADDR 0x0010 /* filter on MAC address */ +#define TRF_MGMT_FLAG_NO_RX 0x0020 /* do not apply fiters to rx packets */ + +#define TRF_FILTER_MAC_ADDR 0x0001 /* L2 filter use dst mac address for filtering */ +#define TRF_FILTER_IP_ADDR 0x0002 /* L3 filter use ip ddress for filtering */ +#define TRF_FILTER_L4 0x0004 /* L4 filter use tcp/udp for filtering */ +#define TRF_FILTER_DWM 0x0008 /* L3 filter use DSCP for filtering */ +#define TRF_FILTER_FAVORED 0x0010 /* Tag the packet FAVORED */ + +/* WNM/NPS subfeatures mask */ +#define WL_WNM_BSSTRANS 0x00000001 +#define WL_WNM_PROXYARP 0x00000002 +#define WL_WNM_MAXIDLE 0x00000004 +#define WL_WNM_TIMBC 0x00000008 +#define WL_WNM_TFS 0x00000010 +#define WL_WNM_SLEEP 0x00000020 +#define WL_WNM_DMS 0x00000040 +#define WL_WNM_FMS 0x00000080 +#define WL_WNM_NOTIF 0x00000100 +#define WL_WNM_MAX 0x00000200 + +#ifndef ETHER_MAX_DATA +#define ETHER_MAX_DATA 1500 +#endif /* ETHER_MAX_DATA */ + +/* Different discovery modes for dpt */ +#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */ +#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */ +#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */ + +/* different path selection values */ +#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */ +#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */ +#define DPT_PATHSEL_APPATH 2 /* always use AP path */ + +/* different ops for deny list */ +#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */ +#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */ + +/* different ops for manual end point */ +#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ +#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ +#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ + +/* flags to indicate DPT status */ +#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */ +#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */ +#define DPT_STATUS_FAILED 0x04 /* DPT link failed */ + +#ifdef WLTDLS +/* different ops for manual end point */ +#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ +#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ +#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ +#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ +#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ +#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ +#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ +#define TDLS_MANUAL_EP_WFD_TPQ 8 /* WiFi-Display Tunneled Probe reQuest */ + +/* modes */ +#define TDLS_WFD_IE_TX 0 +#define TDLS_WFD_IE_RX 1 +#define TDLS_WFD_PROBE_IE_TX 2 +#define TDLS_WFD_PROBE_IE_RX 3 +#endif /* WLTDLS */ + +/* define for flag */ +#define TSPEC_PENDING 0 /* TSPEC pending */ +#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ +#define TSPEC_REJECTED 2 /* TSPEC rejected */ +#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ +#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ + +#ifdef BCMCCX +/* "wlan_reason" iovar interface */ +#define WL_WLAN_ASSOC_REASON_NORMAL_NETWORK 0 /* normal WLAN network setup */ +#define WL_WLAN_ASSOC_REASON_ROAM_FROM_CELLULAR_NETWORK 1 /* roam from Cellular network */ +#define WL_WLAN_ASSOC_REASON_ROAM_FROM_LAN 2 /* roam from LAN */ +#define WL_WLAN_ASSOC_REASON_MAX 2 /* largest value allowed */ +#endif /* BCMCCX */ + +/* Software feature flag defines used by wlfeatureflag */ +#ifdef WLAFTERBURNER +#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ +#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ +#endif /* WLAFTERBURNER */ +#define WL_SWFL_NOHWRADIO 0x0004 +#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ +#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ + +#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ + +#define CSA_BROADCAST_ACTION_FRAME 0 /* csa broadcast action frame */ +#define CSA_UNICAST_ACTION_FRAME 1 /* csa unicast action frame */ + +/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER. + * + * (-100 < value < 0) value is used directly as a roaming trigger in dBm + * (0 <= value) value specifies a logical roaming trigger level from + * the list below + * + * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never + * the logical roam trigger value. + */ +#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */ +#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */ +#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */ +#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */ +#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */ + +#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */ + +/* Preferred Network Offload (PNO, formerly PFN) defines */ +#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ + +#define SORT_CRITERIA_BIT 0 +#define AUTO_NET_SWITCH_BIT 1 +#define ENABLE_BKGRD_SCAN_BIT 2 +#define IMMEDIATE_SCAN_BIT 3 +#define AUTO_CONNECT_BIT 4 +#define ENABLE_BD_SCAN_BIT 5 +#define ENABLE_ADAPTSCAN_BIT 6 +#define IMMEDIATE_EVENT_BIT 8 +#define SUPPRESS_SSID_BIT 9 +#define ENABLE_NET_OFFLOAD_BIT 10 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_BIT 11 +#define BESTN_BSSID_ONLY_BIT 12 + +#define SORT_CRITERIA_MASK 0x0001 +#define AUTO_NET_SWITCH_MASK 0x0002 +#define ENABLE_BKGRD_SCAN_MASK 0x0004 +#define IMMEDIATE_SCAN_MASK 0x0008 +#define AUTO_CONNECT_MASK 0x0010 + +#define ENABLE_BD_SCAN_MASK 0x0020 +#define ENABLE_ADAPTSCAN_MASK 0x00c0 +#define IMMEDIATE_EVENT_MASK 0x0100 +#define SUPPRESS_SSID_MASK 0x0200 +#define ENABLE_NET_OFFLOAD_MASK 0x0400 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_MASK 0x0800 +#define BESTN_BSSID_ONLY_MASK 0x1000 + +#define PFN_VERSION 2 +#define PFN_SCANRESULT_VERSION 1 +#define MAX_PFN_LIST_COUNT 16 + +#define PFN_COMPLETE 1 +#define PFN_INCOMPLETE 0 + +#define DEFAULT_BESTN 2 +#define DEFAULT_MSCAN 0 +#define DEFAULT_REPEAT 10 +#define DEFAULT_EXP 2 + +#define PFN_PARTIAL_SCAN_BIT 0 +#define PFN_PARTIAL_SCAN_MASK 1 + +#define WL_PFN_SUPPRESSFOUND_MASK 0x08 +#define WL_PFN_SUPPRESSLOST_MASK 0x10 +#define WL_PFN_SSID_A_BAND_TRIG 0x20 +#define WL_PFN_SSID_BG_BAND_TRIG 0x40 +#define WL_PFN_RSSI_MASK 0xff00 +#define WL_PFN_RSSI_SHIFT 8 + +#define WL_PFN_REPORT_ALLNET 0 +#define WL_PFN_REPORT_SSIDNET 1 +#define WL_PFN_REPORT_BSSIDNET 2 + +#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ +#define WL_PFN_CFG_FLAGS_HISTORY_OFF 0x00000002 /* Scan history suppressed */ + +#define WL_PFN_HIDDEN_BIT 2 +#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ +#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ +#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ +#define WL_PFN_HIDDEN_MASK 0x4 +#define MAX_SSID_WHITELIST_NUM 4 +#define MAX_BSSID_PREF_LIST_NUM 32 +#define MAX_BSSID_BLACKLIST_NUM 32 + +#ifndef BESTN_MAX +#define BESTN_MAX 8 +#endif + +#ifndef MSCAN_MAX +#define MSCAN_MAX 32 +#endif + +/* TCP Checksum Offload error injection for testing */ +#define TOE_ERRTEST_TX_CSUM 0x00000001 +#define TOE_ERRTEST_RX_CSUM 0x00000002 +#define TOE_ERRTEST_RX_CSUM2 0x00000004 + +/* ARP Offload feature flags for arp_ol iovar */ +#define ARP_OL_AGENT 0x00000001 +#define ARP_OL_SNOOP 0x00000002 +#define ARP_OL_HOST_AUTO_REPLY 0x00000004 +#define ARP_OL_PEER_AUTO_REPLY 0x00000008 + +/* ARP Offload error injection */ +#define ARP_ERRTEST_REPLY_PEER 0x1 +#define ARP_ERRTEST_REPLY_HOST 0x2 + +#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ +#define ND_MULTIHOMING_MAX 10 /* Maximum local host IP addresses */ +#define ND_REQUEST_MAX 5 /* Max set of offload params */ + + +/* AOAC wake event flag */ +#define WAKE_EVENT_NLO_DISCOVERY_BIT 1 +#define WAKE_EVENT_AP_ASSOCIATION_LOST_BIT 2 +#define WAKE_EVENT_GTK_HANDSHAKE_ERROR_BIT 4 +#define WAKE_EVENT_4WAY_HANDSHAKE_REQUEST_BIT 8 + + +#define MAX_NUM_WOL_PATTERN 22 /* LOGO requirements min 22 */ + + +/* Packet filter operation mode */ +/* True: 1; False: 0 */ +#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 +/* Enable and disable pkt_filter as a whole */ +#define PKT_FILTER_MODE_DISABLE 2 +/* Cache first matched rx pkt(be queried by host later) */ +#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 +/* If pkt_filter is enabled and no filter is set, don't forward anything */ +#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 + +#ifdef DONGLEOVERLAYS +#define OVERLAY_IDX_MASK 0x000000ff +#define OVERLAY_IDX_SHIFT 0 +#define OVERLAY_FLAGS_MASK 0xffffff00 +#define OVERLAY_FLAGS_SHIFT 8 +/* overlay written to device memory immediately after loading the base image */ +#define OVERLAY_FLAG_POSTLOAD 0x100 +/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */ +#define OVERLAY_FLAG_DEFER_DL 0x200 +/* overlay downloaded prior to the host going to sleep */ +#define OVERLAY_FLAG_PRESLEEP 0x400 +#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 +#endif /* DONGLEOVERLAYS */ + +/* reuse two number in the sc/rc space */ +#define SMFS_CODE_MALFORMED 0xFFFE +#define SMFS_CODE_IGNORED 0xFFFD + +/* RFAWARE def */ +#define BCM_ACTION_RFAWARE 0x77 +#define BCM_ACTION_RFAWARE_DCS 0x01 + +/* DCS reason code define */ +#define BCM_DCS_IOVAR 0x1 +#define BCM_DCS_UNKNOWN 0xFF + + +#ifdef PROP_TXSTATUS +/* Bit definitions for tlv iovar */ +/* + * enable RSSI signals: + * WLFC_CTL_TYPE_RSSI + */ +#define WLFC_FLAGS_RSSI_SIGNALS 0x0001 + +/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals: + * + * WLFC_CTL_TYPE_MAC_OPEN + * WLFC_CTL_TYPE_MAC_CLOSE + * + * WLFC_CTL_TYPE_INTERFACE_OPEN + * WLFC_CTL_TYPE_INTERFACE_CLOSE + * + * WLFC_CTL_TYPE_MACDESC_ADD + * WLFC_CTL_TYPE_MACDESC_DEL + * + */ +#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002 + +/* enable (status, fifo_credit, mac_credit) signals + * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT + * WLFC_CTL_TYPE_TXSTATUS + * WLFC_CTL_TYPE_FIFO_CREDITBACK + */ +#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 + +#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 +#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 +#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 +#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040 +#define WLFC_FLAGS_PKT_STAMP_SIGNALS 0x0080 + +#endif /* PROP_TXSTATUS */ + +#define WL_TIMBC_STATUS_AP_UNKNOWN 255 /* AP status for internal use only */ + +#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ +#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ +#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ + +/* Definitions for Reliable Multicast */ +#define WL_RELMCAST_MAX_CLIENT 32 +#define WL_RELMCAST_FLAG_INBLACKLIST 1 +#define WL_RELMCAST_FLAG_ACTIVEACKER 2 +#define WL_RELMCAST_FLAG_RELMCAST 4 + +/* structures for proximity detection device role */ +#define WL_PROXD_MODE_DISABLE 0 +#define WL_PROXD_MODE_NEUTRAL 1 +#define WL_PROXD_MODE_INITIATOR 2 +#define WL_PROXD_MODE_TARGET 3 +#define WL_PROXD_RANDOM_WAKEUP 0x8000 + + +#ifdef NET_DETECT +#define NET_DETECT_MAX_WAKE_DATA_SIZE 2048 +#define NET_DETECT_MAX_PROFILES 16 +#define NET_DETECT_MAX_CHANNELS 50 +#endif /* NET_DETECT */ + + +/* 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) +#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */ + +#define WL_SPURAVOID_OFF 0 +#define WL_SPURAVOID_ON1 1 +#define WL_SPURAVOID_ON2 2 + + +#define WL_4335_SPURAVOID_ON1 1 +#define WL_4335_SPURAVOID_ON2 2 +#define WL_4335_SPURAVOID_ON3 3 +#define WL_4335_SPURAVOID_ON4 4 +#define WL_4335_SPURAVOID_ON5 5 +#define WL_4335_SPURAVOID_ON6 6 +#define WL_4335_SPURAVOID_ON7 7 +#define WL_4335_SPURAVOID_ON8 8 +#define WL_4335_SPURAVOID_ON9 9 + +/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ +#define WL_TXPWR_OVERRIDE (1U<<31) +#define WL_TXPWR_NEG (1U<<30) + + +/* 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_LCN40 10 +#define WLC_PHY_TYPE_AC 11 +#define WLC_PHY_TYPE_NULL 0xf + +/* Values for PM */ +#define PM_OFF 0 +#define PM_MAX 1 +#define PM_FAST 2 +#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */ + +#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ + +/* fbt_cap: FBT assoc / reassoc modes. */ +#define WLC_FBT_CAP_DRV_4WAY_AND_REASSOC 1 /* Driver 4-way handshake & reassoc (WLFBT). */ + +/* monitor_promisc_level bits */ +#define WL_MONPROMISC_PROMISC 0x0001 +#define WL_MONPROMISC_CTRL 0x0002 +#define WL_MONPROMISC_FCS 0x0004 + +/* TCP Checksum Offload defines */ +#define TOE_TX_CSUM_OL 0x00000001 +#define TOE_RX_CSUM_OL 0x00000002 + +/* Wi-Fi Display Services (WFDS) */ +#define WL_P2P_SOCIAL_CHANNELS_MAX WL_NUMCHANNELS +#define MAX_WFDS_SEEK_SVC 4 /* Max # of wfds services to seek */ +#define MAX_WFDS_ADVERT_SVC 4 /* Max # of wfds services to advertise */ +#define MAX_WFDS_SVC_NAME_LEN 200 /* maximum service_name length */ +#define MAX_WFDS_ADV_SVC_INFO_LEN 65000 /* maximum adv service_info length */ +#define P2P_WFDS_HASH_LEN 6 /* Length of a WFDS service hash */ +#define MAX_WFDS_SEEK_SVC_INFO_LEN 255 /* maximum seek service_info req length */ +#define MAX_WFDS_SEEK_SVC_NAME_LEN 200 /* maximum service_name length */ + +/* ap_isolate bitmaps */ +#define AP_ISOLATE_DISABLED 0x0 +#define AP_ISOLATE_SENDUP_ALL 0x01 +#define AP_ISOLATE_SENDUP_MCAST 0x02 + +#endif /* wlioctl_defs_h */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/dhdioctl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/dhdioctl.h new file mode 100644 index 000000000000..766ffbf7fcb7 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/dhdioctl.h @@ -0,0 +1,136 @@ +/* + * Definitions for ioctls to access DHD iovars. + * Based on wlioctl.h (for Broadcom 802.11abg driver). + * (Moves towards generic ioctls for BCM drivers/iovars.) + * + * Definitions subject to change without notice. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhdioctl.h 518127 2014-11-28 08:44:47Z $ + */ + +#ifndef _dhdioctl_h_ +#define _dhdioctl_h_ + +#include + + +/* require default structure packing */ +#define BWL_DEFAULT_PACKING +#include + + +/* Linux network driver ioctl encoding */ +typedef struct dhd_ioctl { + uint cmd; /* common ioctl definition */ + void *buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + bool set; /* get or set request (optional) */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ + uint driver; /* to identify target driver */ +} dhd_ioctl_t; + +/* Underlying BUS definition */ +enum { + BUS_TYPE_USB = 0, /* for USB dongles */ + BUS_TYPE_SDIO, /* for SDIO dongles */ + BUS_TYPE_PCIE /* for PCIE dongles */ +}; + +/* per-driver magic numbers */ +#define DHD_IOCTL_MAGIC 0x00444944 + +/* bump this number if you change the ioctl interface */ +#define DHD_IOCTL_VERSION 1 + +#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ +#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ + +/* common ioctl definitions */ +#define DHD_GET_MAGIC 0 +#define DHD_GET_VERSION 1 +#define DHD_GET_VAR 2 +#define DHD_SET_VAR 3 + +/* message levels */ +#define DHD_ERROR_VAL 0x0001 +#define DHD_TRACE_VAL 0x0002 +#define DHD_INFO_VAL 0x0004 +#define DHD_DATA_VAL 0x0008 +#define DHD_CTL_VAL 0x0010 +#define DHD_TIMER_VAL 0x0020 +#define DHD_HDRS_VAL 0x0040 +#define DHD_BYTES_VAL 0x0080 +#define DHD_INTR_VAL 0x0100 +#define DHD_LOG_VAL 0x0200 +#define DHD_GLOM_VAL 0x0400 +#define DHD_EVENT_VAL 0x0800 +#define DHD_BTA_VAL 0x1000 +#define DHD_ISCAN_VAL 0x2000 +#define DHD_ARPOE_VAL 0x4000 +#define DHD_REORDER_VAL 0x8000 +#define DHD_WL_VAL 0x10000 +#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */ +#define DHD_WL_VAL2 0x40000 +#define DHD_PNO_VAL 0x80000 +#define DHD_RTT_VAL 0x100000 + +#ifdef SDTEST +/* For pktgen iovar */ +typedef struct dhd_pktgen { + uint version; /* To allow structure change tracking */ + uint freq; /* Max ticks between tx/rx attempts */ + uint count; /* Test packets to send/rcv each attempt */ + uint print; /* Print counts every attempts */ + uint total; /* Total packets (or bursts) */ + uint minlen; /* Minimum length of packets to send */ + uint maxlen; /* Maximum length of packets to send */ + uint numsent; /* Count of test packets sent */ + uint numrcvd; /* Count of test packets received */ + uint numfail; /* Count of test send failures */ + uint mode; /* Test mode (type of test packets) */ + uint stop; /* Stop after this many tx failures */ +} dhd_pktgen_t; + +/* Version in case structure changes */ +#define DHD_PKTGEN_VERSION 2 + +/* Type of test packets to use */ +#define DHD_PKTGEN_ECHO 1 /* Send echo requests */ +#define DHD_PKTGEN_SEND 2 /* Send discard packets */ +#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */ +#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ +#endif /* SDTEST */ + +/* Enter idle immediately (no timeout) */ +#define DHD_IDLE_IMMEDIATE (-1) + +/* Values for idleclock iovar: other values are the sd_divisor to use when idle */ +#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */ +#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */ + + +/* require default structure packing */ +#include + +#endif /* _dhdioctl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h b/drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h new file mode 100644 index 000000000000..c21e4efb943f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 $ + * +*/ + +#ifndef _epivers_h_ +#define _epivers_h_ + +#define EPI_MAJOR_VERSION 1 + +#define EPI_MINOR_VERSION 71 + +#define EPI_RC_NUMBER 25 + +#define EPI_INCREMENTAL_NUMBER 0 + +#define EPI_BUILD_NUMBER 0 + +#define EPI_VERSION 1, 71, 25, 0 + +#define EPI_VERSION_NUM 0x01471900 + +#define EPI_VERSION_DEV 1.71.25 + +/* Driver Version String, ASCII, 32 chars max */ +#define EPI_VERSION_STR "1.71.25 (r)" + +#endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_armtrap.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_armtrap.h new file mode 100644 index 000000000000..c6186b156272 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_armtrap.h @@ -0,0 +1,88 @@ +/* + * HND arm trap handling. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hnd_armtrap.h 470663 2014-04-16 00:24:43Z $ + */ + +#ifndef _hnd_armtrap_h_ +#define _hnd_armtrap_h_ + + +/* ARM trap handling */ + +/* Trap types defined by ARM (see arminc.h) */ + +/* Trap locations in lo memory */ +#define TRAP_STRIDE 4 +#define FIRST_TRAP TR_RST +#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) + +#if defined(__ARM_ARCH_4T__) +#define MAX_TRAP_TYPE (TR_FIQ + 1) +#elif defined(__ARM_ARCH_7M__) +#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) +#endif /* __ARM_ARCH_7M__ */ + +/* The trap structure is defined here as offsets for assembly */ +#define TR_TYPE 0x00 +#define TR_EPC 0x04 +#define TR_CPSR 0x08 +#define TR_SPSR 0x0c +#define TR_REGS 0x10 +#define TR_REG(n) (TR_REGS + (n) * 4) +#define TR_SP TR_REG(13) +#define TR_LR TR_REG(14) +#define TR_PC TR_REG(15) + +#define TRAP_T_SIZE 80 + +#ifndef _LANGUAGE_ASSEMBLY + +#include + +typedef struct _trap_struct { + uint32 type; + uint32 epc; + uint32 cpsr; + uint32 spsr; + uint32 r0; /* a1 */ + uint32 r1; /* a2 */ + uint32 r2; /* a3 */ + uint32 r3; /* a4 */ + uint32 r4; /* v1 */ + uint32 r5; /* v2 */ + uint32 r6; /* v3 */ + uint32 r7; /* v4 */ + uint32 r8; /* v5 */ + uint32 r9; /* sb/v6 */ + uint32 r10; /* sl/v7 */ + uint32 r11; /* fp/v8 */ + uint32 r12; /* ip */ + uint32 r13; /* sp */ + uint32 r14; /* lr */ + uint32 pc; /* r15 */ +} trap_t; + +#endif /* !_LANGUAGE_ASSEMBLY */ + +#endif /* _hnd_armtrap_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_cons.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_cons.h new file mode 100644 index 000000000000..d9c0cb335e64 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_cons.h @@ -0,0 +1,77 @@ +/* + * Console support for RTE - for host use only. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hnd_cons.h 473343 2014-04-29 01:45:22Z $ + */ +#ifndef _hnd_cons_h_ +#define _hnd_cons_h_ + +#include +#include + +#define CBUF_LEN (128) + +#define LOG_BUF_LEN 1024 + +#ifdef BOOTLOADER_CONSOLE_OUTPUT +#undef RWL_MAX_DATA_LEN +#undef CBUF_LEN +#undef LOG_BUF_LEN +#define RWL_MAX_DATA_LEN (4 * 1024 + 8) +#define CBUF_LEN (RWL_MAX_DATA_LEN + 64) +#define LOG_BUF_LEN (16 * 1024) +#endif + +typedef struct { + uint32 buf; /* Can't be pointer on (64-bit) hosts */ + uint buf_size; + uint idx; + uint out_idx; /* output index */ +} hnd_log_t; + +typedef struct { + /* 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. + */ + volatile uint vcons_in; + volatile 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. + */ + hnd_log_t log; + + /* 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]; +} hnd_cons_t; + +#endif /* _hnd_cons_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktpool.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktpool.h new file mode 100644 index 000000000000..4100b3eeb4d1 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktpool.h @@ -0,0 +1,204 @@ +/* + * HND generic packet pool operation primitives + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: $ + */ + +#ifndef _hnd_pktpool_h_ +#define _hnd_pktpool_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef BCMPKTPOOL +#define POOL_ENAB(pool) ((pool) && (pool)->inited) +#define SHARED_POOL (pktpool_shared) +#else /* BCMPKTPOOL */ +#define POOL_ENAB(bus) 0 +#define SHARED_POOL ((struct pktpool *)NULL) +#endif /* BCMPKTPOOL */ + +#ifdef BCMFRAGPOOL +#define SHARED_FRAG_POOL (pktpool_shared_lfrag) +#endif +#define SHARED_RXFRAG_POOL (pktpool_shared_rxlfrag) + + +#ifndef PKTPOOL_LEN_MAX +#define PKTPOOL_LEN_MAX 40 +#endif /* PKTPOOL_LEN_MAX */ +#define PKTPOOL_CB_MAX 3 + +/* forward declaration */ +struct pktpool; + +typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); +typedef struct { + pktpool_cb_t cb; + void *arg; +} pktpool_cbinfo_t; +/* call back fn extension to populate host address in pool pkt */ +typedef int (*pktpool_cb_extn_t)(struct pktpool *pool, void *arg1, void* pkt, bool arg2); +typedef struct { + pktpool_cb_extn_t cb; + void *arg; +} pktpool_cbextn_info_t; + + +#ifdef BCMDBG_POOL +/* pkt pool debug states */ +#define POOL_IDLE 0 +#define POOL_RXFILL 1 +#define POOL_RXDH 2 +#define POOL_RXD11 3 +#define POOL_TXDH 4 +#define POOL_TXD11 5 +#define POOL_AMPDU 6 +#define POOL_TXENQ 7 + +typedef struct { + void *p; + uint32 cycles; + uint32 dur; +} pktpool_dbg_t; + +typedef struct { + uint8 txdh; /* tx to host */ + uint8 txd11; /* tx to d11 */ + uint8 enq; /* waiting in q */ + uint8 rxdh; /* rx from host */ + uint8 rxd11; /* rx from d11 */ + uint8 rxfill; /* dma_rxfill */ + uint8 idle; /* avail in pool */ +} pktpool_stats_t; +#endif /* BCMDBG_POOL */ + +typedef struct pktpool { + bool inited; /* pktpool_init was successful */ + uint8 type; /* type of lbuf: basic, frag, etc */ + uint8 id; /* pktpool ID: index in registry */ + bool istx; /* direction: transmit or receive data path */ + + void * freelist; /* free list: see PKTNEXTFREE(), PKTSETNEXTFREE() */ + uint16 avail; /* number of packets in pool's free list */ + uint16 len; /* number of packets managed by pool */ + uint16 maxlen; /* maximum size of pool <= PKTPOOL_LEN_MAX */ + uint16 plen; /* size of pkt buffer, excluding lbuf|lbuf_frag */ + + bool empty; + uint8 cbtoggle; + uint8 cbcnt; + uint8 ecbcnt; + bool emptycb_disable; + pktpool_cbinfo_t *availcb_excl; + pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; + pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; + pktpool_cbextn_info_t cbext; + pktpool_cbextn_info_t rxcplidfn; +#ifdef BCMDBG_POOL + uint8 dbg_cbcnt; + pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; + uint16 dbg_qlen; + pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; +#endif + pktpool_cbinfo_t dmarxfill; +} pktpool_t; + +extern pktpool_t *pktpool_shared; +#ifdef BCMFRAGPOOL +extern pktpool_t *pktpool_shared_lfrag; +#endif +extern pktpool_t *pktpool_shared_rxlfrag; + +/* Incarnate a pktpool registry. On success returns total_pools. */ +extern int pktpool_attach(osl_t *osh, uint32 total_pools); +extern int pktpool_dettach(osl_t *osh); /* Relinquish registry */ + +extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx, uint8 type); +extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); +extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); +extern void* pktpool_get(pktpool_t *pktp); +extern void pktpool_free(pktpool_t *pktp, void *p); +extern int pktpool_add(pktpool_t *pktp, void *p); +extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); +extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); +extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); +extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); +extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); +extern bool pktpool_emptycb_disabled(pktpool_t *pktp); +extern int pktpool_hostaddr_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg1); +extern int pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg); +extern void pktpool_invoke_dmarxfill(pktpool_t *pktp); +extern int pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg); + +#define POOLPTR(pp) ((pktpool_t *)(pp)) +#define POOLID(pp) (POOLPTR(pp)->id) + +#define POOLSETID(pp, ppid) (POOLPTR(pp)->id = (ppid)) + +#define pktpool_len(pp) (POOLPTR(pp)->len) +#define pktpool_avail(pp) (POOLPTR(pp)->avail) +#define pktpool_plen(pp) (POOLPTR(pp)->plen) +#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) + + +/* + * ---------------------------------------------------------------------------- + * A pool ID is assigned with a pkt pool during pool initialization. This is + * done by maintaining a registry of all initialized pools, and the registry + * index at which the pool is registered is used as the pool's unique ID. + * ID 0 is reserved and is used to signify an invalid pool ID. + * All packets henceforth allocated from a pool will be tagged with the pool's + * unique ID. Packets allocated from the heap will use the reserved ID = 0. + * Packets with non-zero pool id signify that they were allocated from a pool. + * A maximum of 15 pools are supported, allowing a 4bit pool ID to be used + * in place of a 32bit pool pointer in each packet. + * ---------------------------------------------------------------------------- + */ +#define PKTPOOL_INVALID_ID (0) +#define PKTPOOL_MAXIMUM_ID (15) + +/* Registry of pktpool(s) */ +extern pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; + +/* Pool ID to/from Pool Pointer converters */ +#define PKTPOOL_ID2PTR(id) (pktpools_registry[id]) +#define PKTPOOL_PTR2ID(pp) (POOLID(pp)) + + +#ifdef BCMDBG_POOL +extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_start_trigger(pktpool_t *pktp, void *p); +extern int pktpool_dbg_dump(pktpool_t *pktp); +extern int pktpool_dbg_notify(pktpool_t *pktp); +extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); +#endif /* BCMDBG_POOL */ + +#ifdef __cplusplus + } +#endif + +#endif /* _hnd_pktpool_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktq.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktq.h new file mode 100644 index 000000000000..3854843652af --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktq.h @@ -0,0 +1,186 @@ +/* + * HND generic pktq operation primitives + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: $ + */ + +#ifndef _hnd_pktq_h_ +#define _hnd_pktq_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* osl multi-precedence packet queue */ +#define PKTQ_LEN_MAX 0xFFFF /* Max uint16 65535 packets */ +#ifndef PKTQ_LEN_DEFAULT +#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ +#endif +#ifndef PKTQ_MAX_PREC +#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ +#endif + +typedef struct pktq_prec { + void *head; /* first packet to dequeue */ + void *tail; /* last packet to dequeue */ + uint16 len; /* number of queued packets */ + uint16 max; /* maximum number of queued packets */ +} pktq_prec_t; + +#ifdef PKTQ_LOG +typedef struct { + uint32 requested; /* packets requested to be stored */ + uint32 stored; /* packets stored */ + uint32 saved; /* packets saved, + because a lowest priority queue has given away one packet + */ + uint32 selfsaved; /* packets saved, + because an older packet from the same queue has been dropped + */ + uint32 full_dropped; /* packets dropped, + because pktq is full with higher precedence packets + */ + uint32 dropped; /* packets dropped because pktq per that precedence is full */ + uint32 sacrificed; /* packets dropped, + in order to save one from a queue of a highest priority + */ + uint32 busy; /* packets droped because of hardware/transmission error */ + uint32 retry; /* packets re-sent because they were not received */ + uint32 ps_retry; /* packets retried again prior to moving power save mode */ + uint32 suppress; /* packets which were suppressed and not transmitted */ + uint32 retry_drop; /* packets finally dropped after retry limit */ + uint32 max_avail; /* the high-water mark of the queue capacity for packets - + goes to zero as queue fills + */ + uint32 max_used; /* the high-water mark of the queue utilisation for packets - + increases with use ('inverse' of max_avail) + */ + uint32 queue_capacity; /* the maximum capacity of the queue */ + uint32 rtsfail; /* count of rts attempts that failed to receive cts */ + uint32 acked; /* count of packets sent (acked) successfully */ + uint32 txrate_succ; /* running total of phy rate of packets sent successfully */ + uint32 txrate_main; /* running totoal of primary phy rate of all packets */ + uint32 throughput; /* actual data transferred successfully */ + uint32 airtime; /* cumulative total medium access delay in useconds */ + uint32 _logtime; /* timestamp of last counter clear */ +} pktq_counters_t; + +typedef struct { + uint32 _prec_log; + pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */ +} pktq_log_t; +#endif /* PKTQ_LOG */ + + +#define PKTQ_COMMON \ + uint16 num_prec; /* number of precedences in use */ \ + uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ \ + uint16 max; /* total max packets */ \ + uint16 len; /* total number of packets */ + +/* multi-priority pkt queue */ +struct pktq { + PKTQ_COMMON + /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ + struct pktq_prec q[PKTQ_MAX_PREC]; +#ifdef PKTQ_LOG + pktq_log_t* pktqlog; +#endif +}; + +/* simple, non-priority pkt queue */ +struct spktq { + PKTQ_COMMON + /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ + struct pktq_prec q[1]; +}; + +#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) + +/* fn(pkt, arg). return true if pkt belongs to if */ +typedef bool (*ifpkt_cb_t)(void*, int); + +/* operations on a specific precedence in packet queue */ + +#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) +#define pktq_pmax(pq, prec) ((pq)->q[prec].max) +#define pktq_plen(pq, prec) ((pq)->q[prec].len) +#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) +#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) +#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) + +#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) +#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) + +extern void pktq_append(struct pktq *pq, int prec, struct spktq *list); +extern void pktq_prepend(struct pktq *pq, int prec, struct spktq *list); + +extern void *pktq_penq(struct pktq *pq, int prec, void *p); +extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); +extern void *pktq_pdeq(struct pktq *pq, int prec); +extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); +extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg); +extern void *pktq_pdeq_tail(struct pktq *pq, int prec); +/* Empty the queue at particular precedence level */ +extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, + ifpkt_cb_t fn, int arg); +/* Remove a specified packet from its queue */ +extern bool pktq_pdel(struct pktq *pq, void *p, int prec); + +/* operations on a set of precedences in packet queue */ + +extern int pktq_mlen(struct pktq *pq, uint prec_bmp); +extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); +extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); + +/* operations on packet queue as a whole */ + +#define pktq_len(pq) ((int)(pq)->len) +#define pktq_max(pq) ((int)(pq)->max) +#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) +#define pktq_full(pq) ((pq)->len >= (pq)->max) +#define pktq_empty(pq) ((pq)->len == 0) + +/* operations for single precedence queues */ +#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) +#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) +#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) +#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) +#define pktqflush(osh, pq) pktq_flush(osh, ((struct pktq *)(void *)pq), TRUE, NULL, 0) +#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) + +extern void pktq_init(struct pktq *pq, int num_prec, int max_len); +extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); + +/* prec_out may be NULL if caller is not interested in return value */ +extern void *pktq_deq(struct pktq *pq, int *prec_out); +extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); +extern void *pktq_peek(struct pktq *pq, int *prec_out); +extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); +extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); + +#ifdef __cplusplus + } +#endif + +#endif /* _hnd_pktq_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/hndpmu.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hndpmu.h new file mode 100644 index 000000000000..763befeffd21 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/hndpmu.h @@ -0,0 +1,41 @@ +/* + * HND SiliconBackplane PMU support. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hndpmu.h 471127 2014-04-17 23:24:23Z $ + */ + +#ifndef _hndpmu_h_ +#define _hndpmu_h_ + +#include +#include +#include + + +extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on, uint32* min_res_mask); +extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength); + +extern void si_pmu_minresmask_htavail_set(si_t *sih, osl_t *osh, bool set_clear); +extern void si_pmu_slow_clk_reinit(si_t *sih, osl_t *osh); + +#endif /* _hndpmu_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/hndsoc.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hndsoc.h new file mode 100644 index 000000000000..d6254e62e026 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/hndsoc.h @@ -0,0 +1,286 @@ +/* + * Broadcom HND chip & on-chip-interconnect-related definitions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hndsoc.h 473238 2014-04-28 19:14:56Z $ + */ + +#ifndef _HNDSOC_H +#define _HNDSOC_H + +/* Include the soci specific files */ +#include +#include + +/* + * SOC Interconnect Address Map. + * All regions may not exist on all chips. + */ +#define SI_SDRAM_BASE 0x00000000 /* Physical SDRAM */ +#define SI_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */ +#define SI_PCI_MEM_SZ (64 * 1024 * 1024) +#define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */ +#define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ +#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */ + +#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ + +#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ +#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ + +#ifndef SI_MAXCORES +#define SI_MAXCORES 32 /* NorthStar has more cores */ +#endif /* SI_MAXCORES */ + +#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ +#define SI_FASTRAM_SWAPPED 0x19800000 + +#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */ +#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */ +#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */ +#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */ +#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */ +#define SI_FLASH_WINDOW 0x01000000 /* Flash XIP Window */ + +#define SI_NS_NANDFLASH 0x1c000000 /* NorthStar NAND flash base */ +#define SI_NS_NORFLASH 0x1e000000 /* NorthStar NOR flash base */ +#define SI_NS_ROM 0xfffd0000 /* NorthStar ROM */ +#define SI_NS_FLASH_WINDOW 0x02000000 /* Flash XIP Window */ + +#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */ +#define SI_ARMCR4_ROM 0x000f0000 /* ARM Cortex-R4 ROM */ +#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */ +#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */ +#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */ +#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */ + +#define SI_SFLASH 0x14000000 +#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */ +#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */ +#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ +#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 + * (2 ZettaBytes), low 32 bits + */ +#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 + * (2 ZettaBytes), high 32 bits + */ +/* 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 ACPHY_CORE_ID 0x83b /* Dot11 ACPHY */ +#define PCIE2_CORE_ID 0x83c /* pci express Gen2 core */ +#define USB30D_CORE_ID 0x83d /* usb 3.0 device core */ +#define ARMCR4_CORE_ID 0x83e /* ARM CR4 CPU */ +#define GCI_CORE_ID 0x840 /* GCI Core */ +#define M2MDMA_CORE_ID 0x844 /* memory to memory dma */ +#define APB_BRIDGE_CORE_ID 0x135 /* APB bridge core ID */ +#define AXI_CORE_ID 0x301 /* AXI/GPV core ID */ +#define EROM_CORE_ID 0x366 /* EROM core ID */ +#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 + */ + +#define CC_4706_CORE_ID 0x500 /* chipcommon core */ +#define NS_PCIEG2_CORE_ID 0x501 /* PCIE Gen 2 core */ +#define NS_DMA_CORE_ID 0x502 /* DMA core */ +#define NS_SDIO3_CORE_ID 0x503 /* SDIO3 core */ +#define NS_USB20_CORE_ID 0x504 /* USB2.0 core */ +#define NS_USB30_CORE_ID 0x505 /* USB3.0 core */ +#define NS_A9JTAG_CORE_ID 0x506 /* ARM Cortex A9 JTAG core */ +#define NS_DDR23_CORE_ID 0x507 /* Denali DDR2/DDR3 memory controller */ +#define NS_ROM_CORE_ID 0x508 /* ROM core */ +#define NS_NAND_CORE_ID 0x509 /* NAND flash controller core */ +#define NS_QSPI_CORE_ID 0x50a /* SPI flash controller core */ +#define NS_CCB_CORE_ID 0x50b /* ChipcommonB core */ +#define SOCRAM_4706_CORE_ID 0x50e /* internal memory core */ +#define NS_SOCRAM_CORE_ID SOCRAM_4706_CORE_ID +#define ARMCA9_CORE_ID 0x510 /* ARM Cortex A9 core (ihost) */ +#define NS_IHOST_CORE_ID ARMCA9_CORE_ID /* ARM Cortex A9 core (ihost) */ +#define GMAC_COMMON_4706_CORE_ID 0x5dc /* Gigabit MAC core */ +#define GMAC_4706_CORE_ID 0x52d /* Gigabit MAC core */ +#define AMEMC_CORE_ID 0x52e /* DDR1/2 memory controller core */ +#define ALTA_CORE_ID 0x534 /* I2S core */ +#define DDR23_PHY_CORE_ID 0x5dd + +#define SI_PCI1_MEM 0x40000000 /* Host Mode sb2pcitranslation0 (64 MB) */ +#define SI_PCI1_CFG 0x44000000 /* Host Mode sb2pcitranslation1 (64 MB) */ +#define SI_PCIE1_DMA_H32 0xc0000000 /* PCIE Client Mode sb2pcitranslation2 + * (2 ZettaBytes), high 32 bits + */ +#define CC_4706B0_CORE_REV 0x8000001f /* chipcommon core */ +#define SOCRAM_4706B0_CORE_REV 0x80000005 /* internal memory core */ +#define GMAC_4706B0_CORE_REV 0x80000000 /* Gigabit MAC core */ +#define NS_PCIEG2_CORE_REV_B0 0x7 /* NS-B0 PCIE Gen 2 core rev */ + +/* There are TWO constants on all HND chips: SI_ENUM_BASE above, + * and chipcommon being the first core: + */ +#define SI_CC_IDX 0 +/* SOC Interconnect types (aka chip types) */ +#define SOCI_SB 0 +#define SOCI_AI 1 +#define SOCI_UBUS 2 +#define SOCI_NAI 3 + +/* 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 + +/* Norstar core status flags */ +#define SISF_NS_BOOTDEV_MASK 0x0003 /* ROM core */ +#define SISF_NS_BOOTDEV_NOR 0x0000 /* ROM core */ +#define SISF_NS_BOOTDEV_NAND 0x0001 /* ROM core */ +#define SISF_NS_BOOTDEV_ROM 0x0002 /* ROM core */ +#define SISF_NS_BOOTDEV_OFFLOAD 0x0003 /* ROM core */ +#define SISF_NS_SKUVEC_MASK 0x000c /* ROM core */ + +/* 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 */ +#define SI_PWR_CTL_ST 0x1e8 /* For memory clock gating */ + +/* 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_HQCLKREQ 0x00000040 /* HQ Clock Required */ +#define CCS_USBCLKREQ 0x00000100 /* USB Clock Req */ +#define CCS_SECICLKREQ 0x00000100 /* SECI Clock Req */ +#define CCS_ARMFASTCLOCKREQ 0x00000100 /* ARM CR4 fast clock request */ +#define CCS_AVBCLKREQ 0x00000400 /* AVB Clock enable request */ +#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: Backplane is running on ALP clock */ +#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */ +#define CCS_ARMFASTCLOCKSTATUS 0x01000000 /* Fast CPU clock is running */ +#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ +#define CCS_ERSRC_STS_SHIFT 24 + +#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */ +#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */ + +/* 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 */ + +/* A boot/binary may have an embedded block that describes its size */ +#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */ +#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */ +#define BISZ_MAGIC_IDX 0 /* Word 0: magic */ +#define BISZ_TXTST_IDX 1 /* 1: text start */ +#define BISZ_TXTEND_IDX 2 /* 2: text end */ +#define BISZ_DATAST_IDX 3 /* 3: data start */ +#define BISZ_DATAEND_IDX 4 /* 4: data end */ +#define BISZ_BSSST_IDX 5 /* 5: bss start */ +#define BISZ_BSSEND_IDX 6 /* 6: bss end */ +#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */ + +/* Boot/Kernel related defintion and functions */ +#define SOC_BOOTDEV_ROM 0x00000001 +#define SOC_BOOTDEV_PFLASH 0x00000002 +#define SOC_BOOTDEV_SFLASH 0x00000004 +#define SOC_BOOTDEV_NANDFLASH 0x00000008 + +#define SOC_KNLDEV_NORFLASH 0x00000002 +#define SOC_KNLDEV_NANDFLASH 0x00000004 + +#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) +int soc_boot_dev(void *sih); +int soc_knl_dev(void *sih); +#endif /* !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) */ + +#endif /* _HNDSOC_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h new file mode 100644 index 000000000000..59129cf8015b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h @@ -0,0 +1,986 @@ +/* + * Linux OS Independent Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: linux_osl.h 676007 2016-12-20 02:31:31Z $ + */ + +#ifndef _linux_osl_h_ +#define _linux_osl_h_ + +#include +#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) + +/* Linux Kernel: File Operations: start */ +extern void * osl_os_open_image(char * filename); +extern int osl_os_get_image_block(char * buf, int len, void * image); +extern void osl_os_close_image(void * image); +extern int osl_os_image_size(void *image); +/* Linux Kernel: File Operations: end */ + +#ifdef BCMDRIVER + +/* OSL initialization */ +#ifdef SHARED_OSL_CMN +extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag, void **osh_cmn); +#else +extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); +#endif /* SHARED_OSL_CMN */ + +extern void osl_detach(osl_t *osh); +extern int osl_static_mem_init(osl_t *osh, void *adapter); +extern int osl_static_mem_deinit(osl_t *osh, void *adapter); +extern void osl_set_bus_handle(osl_t *osh, void *bus_handle); +extern void* osl_get_bus_handle(osl_t *osh); + +/* Global ASSERT type */ +extern uint32 g_assert_type; + +/* ASSERT */ +#if defined(BCMASSERT_LOG) + #define ASSERT(exp) \ + do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) +extern void osl_assert(const char *exp, const char *file, int line); +#else + #ifdef __GNUC__ + #define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) + #if GCC_VERSION > 30100 + #define ASSERT(exp) do {} while (0) + #else + /* ASSERT could cause segmentation fault on GCC3.1, use empty instead */ + #define ASSERT(exp) + #endif /* GCC_VERSION > 30100 */ + #endif /* __GNUC__ */ +#endif + +/* bcm_prefetch_32B */ +static inline void bcm_prefetch_32B(const uint8 *addr, const int cachelines_32B) +{ +} + +/* microsecond delay */ +#define OSL_DELAY(usec) osl_delay(usec) +extern void osl_delay(uint usec); + +#define OSL_SLEEP(ms) osl_sleep(ms) +extern void osl_sleep(uint ms); + +#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ + osl_pcmcia_read_attr((osh), (offset), (buf), (size)) +#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ + osl_pcmcia_write_attr((osh), (offset), (buf), (size)) +extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); +extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size); + +/* PCI configuration space access macros */ +#define OSL_PCI_READ_CONFIG(osh, offset, size) \ + osl_pci_read_config((osh), (offset), (size)) +#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ + osl_pci_write_config((osh), (offset), (size), (val)) +extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); +extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); + +/* PCI device bus # and slot # */ +#define OSL_PCI_BUS(osh) osl_pci_bus(osh) +#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) +#define OSL_PCIE_DOMAIN(osh) osl_pcie_domain(osh) +#define OSL_PCIE_BUS(osh) osl_pcie_bus(osh) +extern uint osl_pci_bus(osl_t *osh); +extern uint osl_pci_slot(osl_t *osh); +extern uint osl_pcie_domain(osl_t *osh); +extern uint osl_pcie_bus(osl_t *osh); +extern struct pci_dev *osl_pci_device(osl_t *osh); + + +/* Pkttag flag should be part of public information */ +typedef struct { + bool pkttag; + bool mmbus; /* Bus supports memory-mapped register accesses */ + pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ + void *tx_ctx; /* Context to the callback function */ + void *unused[3]; +} osl_pubinfo_t; + +extern void osl_flag_set(osl_t *osh, uint32 mask); +extern bool osl_is_flag_set(osl_t *osh, uint32 mask); + +#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ + do { \ + ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ + ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ + } while (0) + + +/* host/bus architecture-specific byte swap */ +#define BUS_SWAP32(v) (v) + #define MALLOC(osh, size) osl_malloc((osh), (size)) + #define MALLOCZ(osh, size) osl_mallocz((osh), (size)) + #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) + #define MALLOCED(osh) osl_malloced((osh)) + #define MEMORY_LEFTOVER(osh) osl_check_memleak(osh) + extern void *osl_malloc(osl_t *osh, uint size); + extern void *osl_mallocz(osl_t *osh, uint size); + extern void osl_mfree(osl_t *osh, void *addr, uint size); + extern uint osl_malloced(osl_t *osh); + extern uint osl_check_memleak(osl_t *osh); + + +#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) +extern uint osl_malloc_failed(osl_t *osh); + +/* allocate/free shared (dma-able) consistent memory */ +#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() +#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ + osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) +#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ + osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) + +#define DMA_ALLOC_CONSISTENT_FORCE32(osh, size, align, tot, pap, dmah) \ + osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) +#define DMA_FREE_CONSISTENT_FORCE32(osh, va, size, pa, dmah) \ + osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) + +extern uint osl_dma_consistent_align(void); +extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, + uint *tot, dmaaddr_t *pap); +extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa); + +/* map/unmap direction */ +#define DMA_TX 1 /* TX direction for DMA */ +#define DMA_RX 2 /* RX direction for DMA */ + +/* map/unmap shared (dma-able) memory */ +#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ + osl_dma_unmap((osh), (pa), (size), (direction)) +extern dmaaddr_t osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, + hnddma_seg_map_t *txp_dmah); +extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); + +/* API for DMA addressing capability */ +#define OSL_DMADDRWIDTH(osh, addrwidth) ({BCM_REFERENCE(osh); BCM_REFERENCE(addrwidth);}) + +/* API for CPU relax */ +extern void osl_cpu_relax(void); +#define OSL_CPU_RELAX() osl_cpu_relax() + +#if (defined(USE_KMALLOC_FOR_FLOW_RING) && defined(__ARM_ARCH_7A__)) || \ + defined(CONFIG_ARCH_MSM8994) + extern void osl_cache_flush(void *va, uint size); + extern void osl_cache_inv(void *va, uint size); + extern void osl_prefetch(const void *ptr); + #define OSL_CACHE_FLUSH(va, len) osl_cache_flush((void *) va, len) + #define OSL_CACHE_INV(va, len) osl_cache_inv((void *) va, len) + #define OSL_PREFETCH(ptr) osl_prefetch(ptr) +#ifdef __ARM_ARCH_7A__ + extern int osl_arch_is_coherent(void); + #define OSL_ARCH_IS_COHERENT() osl_arch_is_coherent() +#else + #define OSL_ARCH_IS_COHERENT() NULL +#endif /* __ARM_ARCH_7A__ */ +#else + #define OSL_CACHE_FLUSH(va, len) BCM_REFERENCE(va) + #define OSL_CACHE_INV(va, len) BCM_REFERENCE(va) + #define OSL_PREFETCH(ptr) BCM_REFERENCE(ptr) + + #define OSL_ARCH_IS_COHERENT() NULL +#endif + +/* register access macros */ +#if defined(BCMSDIO) + #include + #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(osl_get_bus_handle(osh), \ + (uintptr)(r), sizeof(*(r)), (v))) + #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(osl_get_bus_handle(osh), \ + (uintptr)(r), sizeof(*(r)))) +#endif + + +#if defined(BCMSDIO) + #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ + mmap_op else bus_op + #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ + mmap_op : bus_op +#else + #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) + #define SELECT_BUS_READ(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) +#endif + +#define OSL_ERROR(bcmerror) osl_error(bcmerror) +extern int osl_error(int bcmerror); + +/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ +#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ + +#define OSH_NULL NULL + +/* + * BINOSL selects the slightly slower function-call-based binary compatible osl. + * Macros expand to calls to functions defined in linux_osl.c . + */ +#include /* use current 2.4.x calling conventions */ +#include /* for vsn/printf's */ +#include /* for mem*, str* */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) +#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) +#else +#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ +#define printf(fmt, args...) printk(fmt , ## args) +#include /* for vsn/printf's */ +#include /* for mem*, str* */ +/* bcopy's: Linux kernel doesn't provide these (anymore) */ +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) +#define bzero(b, len) memset((b), '\0', (len)) + +/* register access macros */ + +#ifdef CONFIG_64BIT +/* readq is defined only for 64 bit platform */ +#define R_REG(osh, r) (\ + SELECT_BUS_READ(osh, \ + ({ \ + __typeof(*(r)) __osl_v = 0; \ + switch (sizeof(*(r))) { \ + case sizeof(uint8): __osl_v = \ + readb((volatile uint8*)(r)); break; \ + case sizeof(uint16): __osl_v = \ + readw((volatile uint16*)(r)); break; \ + case sizeof(uint32): __osl_v = \ + readl((volatile uint32*)(r)); break; \ + case sizeof(uint64): __osl_v = \ + readq((volatile uint64*)(r)); break; \ + } \ + __osl_v; \ + }), \ + OSL_READ_REG(osh, r)) \ +) +#else /* !CONFIG_64BIT */ +#define R_REG(osh, r) (\ + SELECT_BUS_READ(osh, \ + ({ \ + __typeof(*(r)) __osl_v = 0; \ + switch (sizeof(*(r))) { \ + case sizeof(uint8): __osl_v = \ + readb((volatile uint8*)(r)); break; \ + case sizeof(uint16): __osl_v = \ + readw((volatile uint16*)(r)); break; \ + case sizeof(uint32): __osl_v = \ + readl((volatile uint32*)(r)); break; \ + } \ + __osl_v; \ + }), \ + OSL_READ_REG(osh, r)) \ +) +#endif /* CONFIG_64BIT */ + +#ifdef CONFIG_64BIT +/* writeq is defined only for 64 bit platform */ +#define W_REG(osh, r, v) do { \ + SELECT_BUS_WRITE(osh, \ + switch (sizeof(*(r))) { \ + case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ + case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ + case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ + case sizeof(uint64): writeq((uint64)(v), (volatile uint64*)(r)); break; \ + }, \ + (OSL_WRITE_REG(osh, r, v))); \ + } while (0) +#else /* !CONFIG_64BIT */ +#define W_REG(osh, r, v) do { \ + SELECT_BUS_WRITE(osh, \ + switch (sizeof(*(r))) { \ + case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ + case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ + case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ + }, \ + (OSL_WRITE_REG(osh, r, v))); \ + } while (0) +#endif /* CONFIG_64BIT */ + +#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) +#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) + +/* bcopy, bcmp, and bzero functions */ +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) +#define bzero(b, len) memset((b), '\0', (len)) + +/* uncached/cached virtual address */ +#define OSL_UNCACHED(va) ((void *)va) +#define OSL_CACHED(va) ((void *)va) + +#define OSL_PREF_RANGE_LD(va, sz) BCM_REFERENCE(va) +#define OSL_PREF_RANGE_ST(va, sz) BCM_REFERENCE(va) + +/* get processor cycle count */ +#if defined(__i386__) +#define OSL_GETCYCLES(x) rdtscl((x)) +#else +#define OSL_GETCYCLES(x) ((x) = 0) +#endif + +/* dereference an address that may cause a bus exception */ +#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) + +/* map/unmap physical to virtual I/O */ +#if !defined(CONFIG_MMC_MSM7X00A) +#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) +#else +#define REG_MAP(pa, size) (void *)(0) +#endif /* !defined(CONFIG_MMC_MSM7X00A */ +#define REG_UNMAP(va) iounmap((va)) + +/* shared (dma-able) memory access macros */ +#define R_SM(r) *(r) +#define W_SM(r, v) (*(r) = (v)) +#define BZERO_SM(r, len) memset((r), '\0', (len)) + +/* Because the non BINOSL implemenation of the PKT OSL routines are macros (for + * performance reasons), we need the Linux headers. + */ +#include /* use current 2.4.x calling conventions */ + +/* packet primitives */ +#define PKTGET(osh, len, send) osl_pktget((osh), (len)) +#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) +#define PKTLIST_DUMP(osh, buf) BCM_REFERENCE(osh) +#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) +#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) +#ifdef CONFIG_DHD_USE_STATIC_BUF +#define PREALLOC_FREE_MAGIC 0xFEDC +#define PREALLOC_USED_MAGIC 0xFCDE +#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) +#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) +#else +#define PKTGET_STATIC PKTGET +#define PKTFREE_STATIC PKTFREE +#endif /* CONFIG_DHD_USE_STATIC_BUF */ +#if defined(BCMPCIE) && defined(CONFIG_DHD_USE_STATIC_BUF) && \ + defined(DHD_USE_STATIC_IOCTLBUF) +#define PKTINVALIDATE_STATIC(osh, skb) osl_pktinvalidate_static((osh), (skb)) +#endif /* BCMPCIE && CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTL_BUF */ +#define PKTDATA(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->data);}) +#define PKTLEN(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->len);}) +#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) +#define PKTEXPHEADROOM(osh, skb, b) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_realloc_headroom((struct sk_buff*)(skb), (b)); \ + }) +#define PKTTAILROOM(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_tailroom((struct sk_buff*)(skb)); \ + }) +#define PKTPADTAILROOM(osh, skb, padlen) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_pad((struct sk_buff*)(skb), (padlen)); \ + }) +#define PKTNEXT(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->next);}) +#define PKTSETNEXT(osh, skb, x) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)); \ + }) +#define PKTSETLEN(osh, skb, len) \ + ({ \ + BCM_REFERENCE(osh); \ + __skb_trim((struct sk_buff*)(skb), (len)); \ + }) +#define PKTPUSH(osh, skb, bytes) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_push((struct sk_buff*)(skb), (bytes)); \ + }) +#define PKTPULL(osh, skb, bytes) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_pull((struct sk_buff*)(skb), (bytes)); \ + }) +#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) +#define PKTSETPOOL(osh, skb, x, y) BCM_REFERENCE(osh) +#define PKTPOOL(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) +#define PKTFREELIST(skb) PKTLINK(skb) +#define PKTSETFREELIST(skb, x) PKTSETLINK((skb), (x)) +#define PKTPTR(skb) (skb) +#define PKTID(skb) ({BCM_REFERENCE(skb); 0;}) +#define PKTSETID(skb, id) ({BCM_REFERENCE(skb); BCM_REFERENCE(id);}) +#define PKTSHRINK(osh, m) ({BCM_REFERENCE(osh); m;}) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) +#define PKTORPHAN(skb) skb_orphan(skb) +#else +#define PKTORPHAN(skb) ({BCM_REFERENCE(skb); 0;}) +#endif /* LINUX VERSION >= 3.6 */ + + + +#ifdef CTFPOOL +#define CTFPOOL_REFILL_THRESH 3 +typedef struct ctfpool { + void *head; + spinlock_t lock; + uint max_obj; + uint curr_obj; + uint obj_size; + uint refills; + uint fast_allocs; + uint fast_frees; + uint slow_allocs; +} ctfpool_t; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define FASTBUF (1 << 0) +#define PKTSETFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->pktc_flags) |= FASTBUF); \ + }) +#define PKTCLRFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->pktc_flags) &= (~FASTBUF)); \ + }) +#define PKTISFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->pktc_flags) & FASTBUF); \ + }) +#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->pktc_flags) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#define FASTBUF (1 << 16) +#define PKTSETFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF); \ + }) +#define PKTCLRFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)); \ + }) +#define PKTISFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->mac_len) & FASTBUF); \ + }) +#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) +#else +#define FASTBUF (1 << 0) +#define PKTSETFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->__unused) |= FASTBUF); \ + }) +#define PKTCLRFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)); \ + }) +#define PKTISFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->__unused) & FASTBUF); \ + }) +#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) +#endif /* 2.6.22 */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->ctfpool) +#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->ctfpool)->head) +#else +#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) +#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) +#endif + +extern void *osl_ctfpool_add(osl_t *osh); +extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); +extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); +extern void osl_ctfpool_cleanup(osl_t *osh); +extern void osl_ctfpool_stats(osl_t *osh, void *b); +#else /* CTFPOOL */ +#define PKTSETFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTISFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) +#endif /* CTFPOOL */ + +#define PKTSETCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTISCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) + +#ifdef HNDCTF + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define SKIPCT (1 << 2) +#define CHAINED (1 << 3) +#define PKTSETSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags |= SKIPCT); \ + }) +#define PKTCLRSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags &= (~SKIPCT)); \ + }) +#define PKTSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags & SKIPCT); \ + }) +#define PKTSETCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags |= CHAINED); \ + }) +#define PKTCLRCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags &= (~CHAINED)); \ + }) +#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->pktc_flags & CHAINED) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#define SKIPCT (1 << 18) +#define CHAINED (1 << 19) +#define PKTSETSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len |= SKIPCT); \ + }) +#define PKTCLRSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)); \ + }) +#define PKTSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len & SKIPCT); \ + }) +#define PKTSETCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len |= CHAINED); \ + }) +#define PKTCLRCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len &= (~CHAINED)); \ + }) +#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->mac_len & CHAINED) +#else /* 2.6.22 */ +#define SKIPCT (1 << 2) +#define CHAINED (1 << 3) +#define PKTSETSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused |= SKIPCT); \ + }) +#define PKTCLRSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)); \ + }) +#define PKTSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused & SKIPCT); \ + }) +#define PKTSETCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused |= CHAINED); \ + }) +#define PKTCLRCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused &= (~CHAINED)); \ + }) +#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->__unused & CHAINED) +#endif /* 2.6.22 */ +typedef struct ctf_mark { + uint32 value; +} ctf_mark_t; +#define CTF_MARK(m) (m.value) +#else /* HNDCTF */ +#define PKTSETSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define CTF_MARK(m) ({BCM_REFERENCE(m); 0;}) +#endif /* HNDCTF */ + +#if defined(BCM_GMAC3) + +/** pktalloced accounting in devices using GMAC Bulk Forwarding to DHD */ + +/* Account for packets delivered to downstream forwarder by GMAC interface. */ +extern void osl_pkt_tofwder(osl_t *osh, void *skbs, int skb_cnt); +#define PKTTOFWDER(osh, skbs, skb_cnt) \ + osl_pkt_tofwder(((osl_t *)osh), (void *)(skbs), (skb_cnt)) + +/* Account for packets received from downstream forwarder. */ +extern void osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt); +#define PKTFRMFWDER(osh, skbs, skb_cnt) \ + osl_pkt_frmfwder(((osl_t *)osh), (void *)(skbs), (skb_cnt)) + + +/** GMAC Forwarded packet tagging for reduced cache flush/invalidate. + * In FWDERBUF tagged packet, only FWDER_PKTMAPSZ amount of data would have + * been accessed in the GMAC forwarder. This may be used to limit the number of + * cachelines that need to be flushed or invalidated. + * Packets sent to the DHD from a GMAC forwarder will be tagged w/ FWDERBUF. + * DHD may clear the FWDERBUF tag, if more than FWDER_PKTMAPSZ was accessed. + * Likewise, a debug print of a packet payload in say the ethernet driver needs + * to be accompanied with a clear of the FWDERBUF tag. + */ + +/** Forwarded packets, have a HWRXOFF sized rx header (etc.h) */ +#define FWDER_HWRXOFF (30) + +/** Maximum amount of a pktadat that a downstream forwarder (GMAC) may have + * read into the L1 cache (not dirty). This may be used in reduced cache ops. + * + * Max 56: ET HWRXOFF[30] + BRCMHdr[4] + EtherHdr[14] + VlanHdr[4] + IP[4] + */ +#define FWDER_PKTMAPSZ (FWDER_HWRXOFF + 4 + 14 + 4 + 4) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + +#define FWDERBUF (1 << 4) +#define PKTSETFWDERBUF(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags |= FWDERBUF); \ + }) +#define PKTCLRFWDERBUF(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags &= (~FWDERBUF)); \ + }) +#define PKTISFWDERBUF(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags & FWDERBUF); \ + }) + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + +#define FWDERBUF (1 << 20) +#define PKTSETFWDERBUF(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len |= FWDERBUF); \ + }) +#define PKTCLRFWDERBUF(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len &= (~FWDERBUF)); \ + }) +#define PKTISFWDERBUF(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len & FWDERBUF); \ + }) + +#else /* 2.6.22 */ + +#define FWDERBUF (1 << 4) +#define PKTSETFWDERBUF(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused |= FWDERBUF); \ + }) +#define PKTCLRFWDERBUF(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused &= (~FWDERBUF)); \ + }) +#define PKTISFWDERBUF(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused & FWDERBUF); \ + }) + +#endif /* 2.6.22 */ + +#else /* ! BCM_GMAC3 */ + +#define PKTSETFWDERBUF(osh, skb) ({ BCM_REFERENCE(osh); BCM_REFERENCE(skb); }) +#define PKTCLRFWDERBUF(osh, skb) ({ BCM_REFERENCE(osh); BCM_REFERENCE(skb); }) +#define PKTISFWDERBUF(osh, skb) ({ BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) + +#endif /* ! BCM_GMAC3 */ + + +#ifdef HNDCTF +/* For broadstream iqos */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define TOBR (1 << 5) +#define PKTSETTOBR(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags |= TOBR); \ + }) +#define PKTCLRTOBR(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags &= (~TOBR)); \ + }) +#define PKTISTOBR(skb) (((struct sk_buff*)(skb))->pktc_flags & TOBR) +#define PKTSETCTFIPCTXIF(skb, ifp) (((struct sk_buff*)(skb))->ctf_ipc_txif = ifp) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) +#define PKTSETCTFIPCTXIF(skb, ifp) ({BCM_REFERENCE(skb); BCM_REFERENCE(ifp);}) +#else /* 2.6.22 */ +#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) +#define PKTSETCTFIPCTXIF(skb, ifp) ({BCM_REFERENCE(skb); BCM_REFERENCE(ifp);}) +#endif /* 2.6.22 */ +#else /* HNDCTF */ +#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) +#endif /* HNDCTF */ + + +#ifdef BCMFA +#ifdef BCMFA_HW_HASH +#define PKTSETFAHIDX(skb, idx) (((struct sk_buff*)(skb))->napt_idx = idx) +#else +#define PKTSETFAHIDX(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) +#endif /* BCMFA_SW_HASH */ +#define PKTGETFAHIDX(skb) (((struct sk_buff*)(skb))->napt_idx) +#define PKTSETFADEV(skb, imp) (((struct sk_buff*)(skb))->dev = imp) +#define PKTSETRXDEV(skb) (((struct sk_buff*)(skb))->rxdev = ((struct sk_buff*)(skb))->dev) + +#define AUX_TCP_FIN_RST (1 << 0) +#define AUX_FREED (1 << 1) +#define PKTSETFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_TCP_FIN_RST) +#define PKTCLRFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_TCP_FIN_RST)) +#define PKTISFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_TCP_FIN_RST) +#define PKTSETFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_FREED) +#define PKTCLRFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_FREED)) +#define PKTISFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_FREED) +#define PKTISFABRIDGED(skb) PKTISFAAUX(skb) +#else +#define PKTISFAAUX(skb) ({BCM_REFERENCE(skb); FALSE;}) +#define PKTISFABRIDGED(skb) ({BCM_REFERENCE(skb); FALSE;}) +#define PKTISFAFREED(skb) ({BCM_REFERENCE(skb); FALSE;}) + +#define PKTCLRFAAUX(skb) BCM_REFERENCE(skb) +#define PKTSETFAFREED(skb) BCM_REFERENCE(skb) +#define PKTCLRFAFREED(skb) BCM_REFERENCE(skb) +#endif /* BCMFA */ + +extern void osl_pktfree(osl_t *osh, void *skb, bool send); +extern void *osl_pktget_static(osl_t *osh, uint len); +extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); +extern void osl_pktclone(osl_t *osh, void **pkt); +#if defined(BCMPCIE) && defined(CONFIG_DHD_USE_STATIC_BUF) && \ + defined(DHD_USE_STATIC_IOCTLBUF) +extern void osl_pktinvalidate_static(osl_t *osh, void *p); +#endif /* BCMPCIE && CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_IOCTL_BUF */ + +extern void *osl_pkt_frmnative(osl_t *osh, void *skb); +extern void *osl_pktget(osl_t *osh, uint len); +extern void *osl_pktdup(osl_t *osh, void *skb); +extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); +#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), (struct sk_buff*)(skb)) +#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_t *)(osh), (pkt)) + +#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) +#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) +#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) +#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) +#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW) +#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \ + ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) +/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ +#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) + +#ifdef CONFIG_NF_CONNTRACK_MARK +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define PKTMARK(p) (((struct sk_buff *)(p))->mark) +#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->mark = (m) +#else /* !2.6.0 */ +#define PKTMARK(p) (((struct sk_buff *)(p))->nfmark) +#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->nfmark = (m) +#endif /* 2.6.0 */ +#else /* CONFIG_NF_CONNTRACK_MARK */ +#define PKTMARK(p) 0 +#define PKTSETMARK(p, m) +#endif /* CONFIG_NF_CONNTRACK_MARK */ + +#define PKTALLOCED(osh) osl_pktalloced(osh) +extern uint osl_pktalloced(osl_t *osh); + +#define OSL_RAND() osl_rand() +extern uint32 osl_rand(void); + +#define DMA_MAP(osh, va, size, direction, p, dmah) \ + osl_dma_map((osh), (va), (size), (direction), (p), (dmah)) + +#ifdef PKTC +/* Use 8 bytes of skb tstamp field to store below info */ +struct chain_node { + struct sk_buff *link; + unsigned int flags:3, pkts:9, bytes:20; +}; + +#define CHAIN_NODE(skb) ((struct chain_node*)(((struct sk_buff*)skb)->pktc_cb)) + +#define PKTCSETATTR(s, f, p, b) ({CHAIN_NODE(s)->flags = (f); CHAIN_NODE(s)->pkts = (p); \ + CHAIN_NODE(s)->bytes = (b);}) +#define PKTCCLRATTR(s) ({CHAIN_NODE(s)->flags = CHAIN_NODE(s)->pkts = \ + CHAIN_NODE(s)->bytes = 0;}) +#define PKTCGETATTR(s) (CHAIN_NODE(s)->flags << 29 | CHAIN_NODE(s)->pkts << 20 | \ + CHAIN_NODE(s)->bytes) +#define PKTCCNT(skb) (CHAIN_NODE(skb)->pkts) +#define PKTCLEN(skb) (CHAIN_NODE(skb)->bytes) +#define PKTCGETFLAGS(skb) (CHAIN_NODE(skb)->flags) +#define PKTCSETFLAGS(skb, f) (CHAIN_NODE(skb)->flags = (f)) +#define PKTCCLRFLAGS(skb) (CHAIN_NODE(skb)->flags = 0) +#define PKTCFLAGS(skb) (CHAIN_NODE(skb)->flags) +#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c)) +#define PKTCINCRCNT(skb) (CHAIN_NODE(skb)->pkts++) +#define PKTCADDCNT(skb, c) (CHAIN_NODE(skb)->pkts += (c)) +#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l)) +#define PKTCADDLEN(skb, l) (CHAIN_NODE(skb)->bytes += (l)) +#define PKTCSETFLAG(skb, fb) (CHAIN_NODE(skb)->flags |= (fb)) +#define PKTCCLRFLAG(skb, fb) (CHAIN_NODE(skb)->flags &= ~(fb)) +#define PKTCLINK(skb) (CHAIN_NODE(skb)->link) +#define PKTSETCLINK(skb, x) (CHAIN_NODE(skb)->link = (struct sk_buff*)(x)) +#define FOREACH_CHAINED_PKT(skb, nskb) \ + for (; (skb) != NULL; (skb) = (nskb)) \ + if ((nskb) = (PKTISCHAINED(skb) ? PKTCLINK(skb) : NULL), \ + PKTSETCLINK((skb), NULL), 1) +#define PKTCFREE(osh, skb, send) \ +do { \ + void *nskb; \ + ASSERT((skb) != NULL); \ + FOREACH_CHAINED_PKT((skb), nskb) { \ + PKTCLRCHAINED((osh), (skb)); \ + PKTCCLRFLAGS((skb)); \ + PKTFREE((osh), (skb), (send)); \ + } \ +} while (0) +#define PKTCENQTAIL(h, t, p) \ +do { \ + if ((t) == NULL) { \ + (h) = (t) = (p); \ + } else { \ + PKTSETCLINK((t), (p)); \ + (t) = (p); \ + } \ +} while (0) +#endif /* PKTC */ + +#else /* ! BCMDRIVER */ + + +/* ASSERT */ + #define ASSERT(exp) do {} while (0) + +/* MALLOC and MFREE */ +#define MALLOC(o, l) malloc(l) +#define MFREE(o, p, l) free(p) +#include + +/* str* and mem* functions */ +#include + +/* *printf functions */ +#include + +/* bcopy, bcmp, and bzero */ +extern void bcopy(const void *src, void *dst, size_t len); +extern int bcmp(const void *b1, const void *b2, size_t len); +extern void bzero(void *b, size_t len); +#endif /* ! BCMDRIVER */ + +typedef struct sec_cma_info { + struct sec_mem_elem *sec_alloc_list; + struct sec_mem_elem *sec_alloc_list_tail; +} sec_cma_info_t; + +#ifdef BCM_SECURE_DMA + +#define SECURE_DMA_MAP(osh, va, size, direction, p, dmah, pcma, offset) \ + osl_sec_dma_map((osh), (va), (size), (direction), (p), (dmah), (pcma), (offset)) +#define SECURE_DMA_DD_MAP(osh, va, size, direction, p, dmah) \ + osl_sec_dma_dd_map((osh), (va), (size), (direction), (p), (dmah)) +#define SECURE_DMA_MAP_TXMETA(osh, va, size, direction, p, dmah, pcma) \ + osl_sec_dma_map_txmeta((osh), (va), (size), (direction), (p), (dmah), (pcma)) +#define SECURE_DMA_UNMAP(osh, pa, size, direction, p, dmah, pcma, offset) \ + osl_sec_dma_unmap((osh), (pa), (size), (direction), (p), (dmah), (pcma), (offset)) +#define SECURE_DMA_UNMAP_ALL(osh, pcma) \ +osl_sec_dma_unmap_all((osh), (pcma)) + +#if defined(__ARM_ARCH_7A__) +#define ACP_WAR_ENAB() 0 +#define ACP_WIN_LIMIT 0 +#define arch_is_coherent() 0 + +#define CMA_BUFSIZE_4K 4096 +#define CMA_BUFSIZE_2K 2048 +#define CMA_BUFSIZE_512 512 + +#define CMA_BUFNUM 9216 /* packet id num 8192+1024 */ +#define SEC_CMA_COHERENT_BLK 0x8000 /* 32768 */ +#define SEC_CMA_COHERENT_MAX 32 +#define CMA_DMA_DESC_MEMBLOCK (SEC_CMA_COHERENT_BLK * SEC_CMA_COHERENT_MAX) +#define CMA_DMA_DATA_MEMBLOCK (CMA_BUFSIZE_4K*CMA_BUFNUM) +#define CMA_MEMBLOCK (CMA_DMA_DESC_MEMBLOCK + CMA_DMA_DATA_MEMBLOCK) +#define CONT_ARMREGION 0x02 /* Region CMA */ +#else +#define CONT_MIPREGION 0x00 /* To access the MIPs mem, Not yet... */ +#endif /* !defined __ARM_ARCH_7A__ */ + +#define SEC_DMA_ALIGN (1<<16) +typedef struct sec_mem_elem { + size_t size; + int direction; + phys_addr_t pa_cma; /* physical address */ + void *va; /* virtual address of driver pkt */ + dma_addr_t dma_handle; /* bus address assign by linux */ + void *vac; /* virtual address of cma buffer */ + struct sec_mem_elem *next; +} sec_mem_elem_t; + +extern dma_addr_t osl_sec_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, + hnddma_seg_map_t *dmah, void *ptr_cma_info, uint offset); +extern dma_addr_t osl_sec_dma_dd_map(osl_t *osh, void *va, uint size, int direction, void *p, + hnddma_seg_map_t *dmah); +extern dma_addr_t osl_sec_dma_map_txmeta(osl_t *osh, void *va, uint size, + int direction, void *p, hnddma_seg_map_t *dmah, void *ptr_cma_info); +extern void osl_sec_dma_unmap(osl_t *osh, dma_addr_t dma_handle, uint size, int direction, + void *p, hnddma_seg_map_t *map, void *ptr_cma_info, uint offset); +extern void osl_sec_dma_unmap_all(osl_t *osh, void *ptr_cma_info); + +#endif /* BCM_SECURE_DMA */ +#endif /* _linux_osl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/linuxver.h b/drivers/net/wireless/bcmdhd_bcm4356/include/linuxver.h new file mode 100644 index 000000000000..93934953aff2 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/linuxver.h @@ -0,0 +1,748 @@ +/* + * Linux-specific abstractions to gain some independence from linux kernel versions. + * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: linuxver.h 431983 2013-10-25 06:53:27Z $ + */ + +#ifndef _linuxver_h_ +#define _linuxver_h_ + +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +#include +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) +#include +#else +#include +#endif +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) +#include +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) +/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */ +#ifdef __UNDEF_NO_VERSION__ +#undef __NO_VERSION__ +#else +#define __NO_VERSION__ +#endif +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) +#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i") +#define module_param_string(_name_, _string_, _size_, _perm_) \ + MODULE_PARM(_string_, "c" __MODULE_STRING(_size_)) +#endif + +/* linux/malloc.h is deprecated, use linux/slab.h instead. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)) +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +#include +#else +#include +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) +#undef IP_TOS +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) */ +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)) +#include +#else +#include +#ifndef work_struct +#define work_struct tq_struct +#endif +#ifndef INIT_WORK +#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data)) +#endif +#ifndef schedule_work +#define schedule_work(_work) schedule_task((_work)) +#endif +#ifndef flush_scheduled_work +#define flush_scheduled_work() flush_scheduled_tasks() +#endif +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define DAEMONIZE(a) do { \ + allow_signal(SIGKILL); \ + allow_signal(SIGTERM); \ + } while (0) +#elif ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))) +#define DAEMONIZE(a) daemonize(a); \ + allow_signal(SIGKILL); \ + allow_signal(SIGTERM); +#else /* Linux 2.4 (w/o preemption patch) */ +#define RAISE_RX_SOFTIRQ() \ + cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) +#define DAEMONIZE(a) daemonize(); \ + do { if (a) \ + strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ + } while (0); +#endif /* LINUX_VERSION_CODE */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) +#else +#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) +#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ + (RHEL_MAJOR == 5)) +/* Exclude RHEL 5 */ +typedef void (*work_func_t)(void *work); +#endif +#endif /* >= 2.6.20 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +/* Some distributions have their own 2.6.x compatibility layers */ +#ifndef IRQ_NONE +typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) +#endif +#else +typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#define IRQF_SHARED SA_SHIRQ +#endif /* < 2.6.18 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) +#ifdef CONFIG_NET_RADIO +#define CONFIG_WIRELESS_EXT +#endif +#endif /* < 2.6.17 */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) +#include +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) +#include +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +#include +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) +#include +#endif +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ + + +#ifndef __exit +#define __exit +#endif +#ifndef __devexit +#define __devexit +#endif +#ifndef __devinit +# if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) +# define __devinit __init +# else +/* All devices are hotpluggable since linux 3.8.0 */ +# define __devinit +# endif +#endif /* !__devinit */ +#ifndef __devinitdata +#define __devinitdata +#endif +#ifndef __devexit_p +#define __devexit_p(x) x +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) + +#define pci_get_drvdata(dev) (dev)->sysdata +#define pci_set_drvdata(dev, value) (dev)->sysdata = (value) + +/* + * New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration + */ + +struct pci_device_id { + unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ + unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ + unsigned long driver_data; /* Data private to the driver */ +}; + +struct pci_driver { + struct list_head node; + char *name; + const struct pci_device_id *id_table; /* NULL if wants all devices */ + int (*probe)(struct pci_dev *dev, + const struct pci_device_id *id); /* New device inserted */ + void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug + * capable driver) + */ + void (*suspend)(struct pci_dev *dev); /* Device suspended */ + void (*resume)(struct pci_dev *dev); /* Device woken up */ +}; + +#define MODULE_DEVICE_TABLE(type, name) +#define PCI_ANY_ID (~0) + +/* compatpci.c */ +#define pci_module_init pci_register_driver +extern int pci_register_driver(struct pci_driver *drv); +extern void pci_unregister_driver(struct pci_driver *drv); + +#endif /* PCI registration */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) +#define pci_module_init pci_register_driver +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) +#ifdef MODULE +#define module_init(x) int init_module(void) { return x(); } +#define module_exit(x) void cleanup_module(void) { x(); } +#else +#define module_init(x) __initcall(x); +#define module_exit(x) __exitcall(x); +#endif +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) +#define WL_USE_NETDEV_OPS +#else +#undef WL_USE_NETDEV_OPS +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL) +#define WL_CONFIG_RFKILL +#else +#undef WL_CONFIG_RFKILL +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13)) +#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44)) +#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23)) +#define pci_enable_device(dev) do { } while (0) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)) +#define net_device device +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42)) + +/* + * DMA mapping + * + * See linux/Documentation/DMA-mapping.txt + */ + +#ifndef PCI_DMA_TODEVICE +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 +#endif + +typedef u32 dma_addr_t; + +/* Pure 2^n version of get_order */ +static inline int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC | GFP_DMA; + + ret = (void *)__get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} +static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, get_order(size)); +} +#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) +#define pci_unmap_single(cookie, address, size, dir) + +#endif /* DMA mapping */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)) + +#define dev_kfree_skb_any(a) dev_kfree_skb(a) +#define netif_down(dev) do { (dev)->start = 0; } while (0) + +/* pcmcia-cs provides its own netdevice compatibility layer */ +#ifndef _COMPAT_NETDEVICE_H + +/* + * SoftNet + * + * For pre-softnet kernels we need to tell the upper layer not to + * re-enter start_xmit() while we are in there. However softnet + * guarantees not to enter while we are in there so there is no need + * to do the netif_stop_queue() dance unless the transmit queue really + * gets stuck. This should also improve performance according to tests + * done by Aman Singla. + */ + +#define dev_kfree_skb_irq(a) dev_kfree_skb(a) +#define netif_wake_queue(dev) \ + do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0) +#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy) + +static inline void netif_start_queue(struct net_device *dev) +{ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; +} + +#define netif_queue_stopped(dev) (dev)->tbusy +#define netif_running(dev) (dev)->start + +#endif /* _COMPAT_NETDEVICE_H */ + +#define netif_device_attach(dev) netif_start_queue(dev) +#define netif_device_detach(dev) netif_stop_queue(dev) + +/* 2.4.x renamed bottom halves to tasklets */ +#define tasklet_struct tq_struct +static inline void tasklet_schedule(struct tasklet_struct *tasklet) +{ + queue_task(tasklet, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static inline void tasklet_init(struct tasklet_struct *tasklet, + void (*func)(unsigned long), + unsigned long data) +{ + tasklet->next = NULL; + tasklet->sync = 0; + tasklet->routine = (void (*)(void *))func; + tasklet->data = (void *)data; +} +#define tasklet_kill(tasklet) { do {} while (0); } + +/* 2.4.x introduced del_timer_sync() */ +#define del_timer_sync(timer) del_timer(timer) + +#else + +#define netif_down(dev) + +#endif /* SoftNet */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)) + +/* + * Emit code to initialise a tq_struct's routine and data pointers + */ +#define PREPARE_TQUEUE(_tq, _routine, _data) \ + do { \ + (_tq)->routine = _routine; \ + (_tq)->data = _data; \ + } while (0) + +/* + * Emit code to initialise all of a tq_struct + */ +#define INIT_TQUEUE(_tq, _routine, _data) \ + do { \ + INIT_LIST_HEAD(&(_tq)->list); \ + (_tq)->sync = 0; \ + PREPARE_TQUEUE((_tq), (_routine), (_data)); \ + } while (0) + +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) */ + +/* Power management related macro & routines */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) +#define PCI_SAVE_STATE(a, b) pci_save_state(a) +#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) +#else +#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) +#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) +static inline int +pci_save_state(struct pci_dev *dev, u32 *buffer) +{ + int i; + if (buffer) { + for (i = 0; i < 16; i++) + pci_read_config_dword(dev, i * 4, &buffer[i]); + } + return 0; +} + +static inline int +pci_restore_state(struct pci_dev *dev, u32 *buffer) +{ + int i; + + if (buffer) { + for (i = 0; i < 16; i++) + pci_write_config_dword(dev, i * 4, buffer[i]); + } + /* + * otherwise, write the context information we know from bootup. + * This works around a problem where warm-booting from Windows + * combined with a D3(hot)->D0 transition causes PCI config + * header data to be forgotten. + */ + else { + for (i = 0; i < 6; i ++) + pci_write_config_dword(dev, + PCI_BASE_ADDRESS_0 + (i * 4), + pci_resource_start(dev, i)); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + return 0; +} +#endif /* PCI power management */ + +/* Old cp0 access macros deprecated in 2.4.19 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19)) +#define read_c0_count() read_32bit_cp0_register(CP0_COUNT) +#endif + +/* Module refcount handled internally in 2.6.x */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) +#ifndef SET_MODULE_OWNER +#define SET_MODULE_OWNER(dev) do {} while (0) +#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define OLD_MOD_INC_USE_COUNT do {} while (0) +#define OLD_MOD_DEC_USE_COUNT do {} while (0) +#endif +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ +#ifndef SET_MODULE_OWNER +#define SET_MODULE_OWNER(dev) do {} while (0) +#endif +#ifndef MOD_INC_USE_COUNT +#define MOD_INC_USE_COUNT do {} while (0) +#endif +#ifndef MOD_DEC_USE_COUNT +#define MOD_DEC_USE_COUNT do {} while (0) +#endif +#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ + +#ifndef SET_NETDEV_DEV +#define SET_NETDEV_DEV(net, pdev) do {} while (0) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)) +#ifndef HAVE_FREE_NETDEV +#define free_netdev(dev) kfree(dev) +#endif +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +/* struct packet_type redefined in 2.6.x */ +#define af_packet_priv data +#endif + +/* suspend args */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) +#define DRV_SUSPEND_STATE_TYPE pm_message_t +#else +#define DRV_SUSPEND_STATE_TYPE uint32 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +#define CHECKSUM_HW CHECKSUM_PARTIAL +#endif + +typedef struct { + void *parent; /* some external entity that the thread supposed to work for */ + char *proc_name; + struct task_struct *p_task; + long thr_pid; + int prio; /* priority */ + struct semaphore sema; + int terminated; + struct completion completed; + spinlock_t spinlock; + int up_cnt; +} tsk_ctl_t; + + +/* requires tsk_ctl_t tsk argument, the caller's priv data is passed in owner ptr */ +/* note this macro assumes there may be only one context waiting on thread's completion */ +#ifdef DHD_DEBUG +#define DBG_THR(x) printk x +#else +#define DBG_THR(x) +#endif + +static inline bool binary_sema_down(tsk_ctl_t *tsk) +{ + if (down_interruptible(&tsk->sema) == 0) { + unsigned long flags = 0; + spin_lock_irqsave(&tsk->spinlock, flags); + if (tsk->up_cnt == 1) + tsk->up_cnt--; + else { + DBG_THR(("dhd_dpc_thread: Unexpected up_cnt %d\n", tsk->up_cnt)); + } + spin_unlock_irqrestore(&tsk->spinlock, flags); + return false; + } else + return true; +} + +static inline bool binary_sema_up(tsk_ctl_t *tsk) +{ + bool sem_up = false; + unsigned long flags = 0; + + spin_lock_irqsave(&tsk->spinlock, flags); + if (tsk->up_cnt == 0) { + tsk->up_cnt++; + sem_up = true; + } else if (tsk->up_cnt == 1) { + /* dhd_sched_dpc: dpc is alread up! */ + } else + DBG_THR(("dhd_sched_dpc: unexpected up cnt %d!\n", tsk->up_cnt)); + + spin_unlock_irqrestore(&tsk->spinlock, flags); + + if (sem_up) + up(&tsk->sema); + + return sem_up; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) +#else +#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) +#endif + +#define PROC_START(thread_func, owner, tsk_ctl, flags, name) \ +{ \ + sema_init(&((tsk_ctl)->sema), 0); \ + init_completion(&((tsk_ctl)->completed)); \ + (tsk_ctl)->parent = owner; \ + (tsk_ctl)->proc_name = name; \ + (tsk_ctl)->terminated = FALSE; \ + (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ + (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ + spin_lock_init(&((tsk_ctl)->spinlock)); \ + DBG_THR(("%s(): thread:%s:%lx started\n", __FUNCTION__, \ + (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ +} + +#define PROC_STOP(tsk_ctl) \ +{ \ + (tsk_ctl)->terminated = TRUE; \ + smp_wmb(); \ + up(&((tsk_ctl)->sema)); \ + wait_for_completion(&((tsk_ctl)->completed)); \ + DBG_THR(("%s(): thread:%s:%lx terminated OK\n", __FUNCTION__, \ + (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ + (tsk_ctl)->thr_pid = -1; \ +} + +/* ----------------------- */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) +#define KILL_PROC(nr, sig) \ +{ \ +struct task_struct *tsk; \ +struct pid *pid; \ +pid = find_get_pid((pid_t)nr); \ +tsk = pid_task(pid, PIDTYPE_PID); \ +if (tsk) send_sig(sig, tsk, 1); \ +} +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(2, 6, 30)) +#define KILL_PROC(pid, sig) \ +{ \ + struct task_struct *tsk; \ + tsk = find_task_by_vpid(pid); \ + if (tsk) send_sig(sig, tsk, 1); \ +} +#else +#define KILL_PROC(pid, sig) \ +{ \ + kill_proc(pid, sig, 1); \ +} +#endif +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#include +#include +#else +#include + +#define __wait_event_interruptible_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ + __ret; \ +}) + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ + +/* +For < 2.6.24, wl creates its own netdev but doesn't +align the priv area like the genuine alloc_netdev(). +Since netdev_priv() always gives us the aligned address, it will +not match our unaligned address for < 2.6.24 +*/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) +#define DEV_PRIV(dev) (dev->priv) +#else +#define DEV_PRIV(dev) netdev_priv(dev) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +#define WL_ISR(i, d, p) wl_isr((i), (d)) +#else +#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) +#endif /* < 2.6.20 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +#define netdev_priv(dev) dev->priv +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) +#define CAN_SLEEP() ((!in_atomic() && !irqs_disabled())) +#else +#define CAN_SLEEP() (FALSE) +#endif + +#define KMALLOC_FLAG (CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define RANDOM32 prandom_u32 +#else +#define RANDOM32 random32 +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define SRANDOM32(entropy) prandom_seed(entropy) +#else +#define SRANDOM32(entropy) srandom32(entropy) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ + +/* + * Overide latest kfifo functions with + * older version to work on older kernels + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) && !defined(WL_COMPAT_WIRELESS) +#define kfifo_in_spinlocked(a, b, c, d) kfifo_put(a, (u8 *)b, c) +#define kfifo_out_spinlocked(a, b, c, d) kfifo_get(a, (u8 *)b, c) +#define kfifo_esize(a) 1 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)) && !defined(WL_COMPAT_WIRELESS) +#define kfifo_in_spinlocked(a, b, c, d) kfifo_in_locked(a, b, c, d) +#define kfifo_out_spinlocked(a, b, c, d) kfifo_out_locked(a, b, c, d) +#define kfifo_esize(a) 1 +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ + +#endif /* _linuxver_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/miniopt.h b/drivers/net/wireless/bcmdhd_bcm4356/include/miniopt.h new file mode 100644 index 000000000000..3726cbab81b1 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/miniopt.h @@ -0,0 +1,79 @@ +/* + * Command line options parser. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: miniopt.h 484281 2014-06-12 22:42:26Z $ + */ + + +#ifndef MINI_OPT_H +#define MINI_OPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---- Include Files ---------------------------------------------------- */ + + +/* ---- Constants and Types ---------------------------------------------- */ + +#define MINIOPT_MAXKEY 128 /* Max options */ +typedef struct miniopt { + + /* These are persistent after miniopt_init() */ + const char* name; /* name for prompt in error strings */ + const char* flags; /* option chars that take no args */ + bool longflags; /* long options may be flags */ + bool opt_end; /* at end of options (passed a "--") */ + + /* These are per-call to miniopt() */ + + int consumed; /* number of argv entries cosumed in + * the most recent call to miniopt() + */ + bool positional; + bool good_int; /* 'val' member is the result of a sucessful + * strtol conversion of the option value + */ + char opt; + char key[MINIOPT_MAXKEY]; + char* valstr; /* positional param, or value for the option, + * or null if the option had + * no accompanying value + */ + uint uval; /* strtol translation of valstr */ + int val; /* strtol translation of valstr */ +} miniopt_t; + +void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); +int miniopt(miniopt_t *t, char **argv); + + +/* ---- Variable Externs ------------------------------------------------- */ +/* ---- Function Prototypes ---------------------------------------------- */ + + +#ifdef __cplusplus + } +#endif + +#endif /* MINI_OPT_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/msgtrace.h b/drivers/net/wireless/bcmdhd_bcm4356/include/msgtrace.h new file mode 100644 index 000000000000..3d54bff2f08b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/msgtrace.h @@ -0,0 +1,78 @@ +/* + * Trace messages sent over HBUS + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: msgtrace.h 439681 2013-11-27 15:39:50Z $ + */ + +#ifndef _MSGTRACE_H +#define _MSGTRACE_H + +#ifndef _TYPEDEFS_H_ +#include +#endif + + +/* This marks the start of a packed structure section. */ +#include +/* for osl_t */ +#include +#define MSGTRACE_VERSION 1 + +/* Message trace header */ +typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { + uint8 version; + uint8 trace_type; +#define MSGTRACE_HDR_TYPE_MSG 0 +#define MSGTRACE_HDR_TYPE_LOG 1 + uint16 len; /* Len of the trace */ + uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost + * because of DMA error or a bus reset (ex: SDIO Func2) + */ + /* Msgtrace type only */ + uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */ + uint32 discarded_printf; /* Number of discarded printf because of trace overflow */ +} BWL_POST_PACKED_STRUCT msgtrace_hdr_t; + +#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t) + +/* The hbus driver generates traces when sending a trace message. This causes endless traces. + * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put. + * This prevents endless traces but generates hasardous lost of traces only in bus device code. + * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing + * hbus error traces. hbus error trace should not generates endless traces. + */ +extern bool msgtrace_hbus_trace; + +typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, + uint16 hdrlen, uint8 *buf, uint16 buflen); +extern void msgtrace_start(void); +extern void msgtrace_stop(void); +extern int msgtrace_sent(void); +extern void msgtrace_put(char *buf, int count); +extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send); +extern bool msgtrace_event_enabled(void); + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _MSGTRACE_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/osl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/osl.h new file mode 100644 index 000000000000..f4bbbcad4841 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/osl.h @@ -0,0 +1,149 @@ +/* + * OS Abstraction Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: osl.h 542258 2015-03-19 07:55:03Z $ + */ + +#ifndef _osl_h_ +#define _osl_h_ + +#include + +#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ + +/* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ +typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); + +/* Drivers use REGOPSSET() to register register read/write funcitons */ +typedef unsigned int (*osl_rreg_fn_t)(void *ctx, volatile void *reg, unsigned int size); +typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, unsigned int size); + + + +#include + +#ifndef PKTDBG_TRACE +#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) +#endif + +#define PKTCTFMAP(osh, p) BCM_REFERENCE(osh) + +/* -------------------------------------------------------------------------- +** Register manipulation macros. +*/ + +#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) + +#ifndef AND_REG +#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) +#endif /* !AND_REG */ + +#ifndef OR_REG +#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) +#endif /* !OR_REG */ + +#if !defined(OSL_SYSUPTIME) +#define OSL_SYSUPTIME() (0) +#define OSL_SYSUPTIME_SUPPORT FALSE +#else +#define OSL_SYSUPTIME_SUPPORT TRUE +#endif /* OSL_SYSUPTIME */ + +#if !defined(PKTC) && !defined(PKTC_DONGLE) +#define PKTCGETATTR(skb) (0) +#define PKTCSETATTR(skb, f, p, b) BCM_REFERENCE(skb) +#define PKTCCLRATTR(skb) BCM_REFERENCE(skb) +#define PKTCCNT(skb) (1) +#define PKTCLEN(skb) PKTLEN(NULL, skb) +#define PKTCGETFLAGS(skb) (0) +#define PKTCSETFLAGS(skb, f) BCM_REFERENCE(skb) +#define PKTCCLRFLAGS(skb) BCM_REFERENCE(skb) +#define PKTCFLAGS(skb) (0) +#define PKTCSETCNT(skb, c) BCM_REFERENCE(skb) +#define PKTCINCRCNT(skb) BCM_REFERENCE(skb) +#define PKTCADDCNT(skb, c) BCM_REFERENCE(skb) +#define PKTCSETLEN(skb, l) BCM_REFERENCE(skb) +#define PKTCADDLEN(skb, l) BCM_REFERENCE(skb) +#define PKTCSETFLAG(skb, fb) BCM_REFERENCE(skb) +#define PKTCCLRFLAG(skb, fb) BCM_REFERENCE(skb) +#define PKTCLINK(skb) NULL +#define PKTSETCLINK(skb, x) BCM_REFERENCE(skb) +#define FOREACH_CHAINED_PKT(skb, nskb) \ + for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) +#define PKTCFREE PKTFREE +#define PKTCENQTAIL(h, t, p) \ +do { \ + if ((t) == NULL) { \ + (h) = (t) = (p); \ + } \ +} while (0) +#endif /* !linux || !PKTC */ + +#if !defined(HNDCTF) && !defined(PKTC_TX_DONGLE) +#define PKTSETCHAINED(osh, skb) BCM_REFERENCE(osh) +#define PKTCLRCHAINED(osh, skb) BCM_REFERENCE(osh) +#define PKTISCHAINED(skb) FALSE +#endif + +/* Lbuf with fraglist */ +#define PKTFRAGPKTID(osh, lb) (0) +#define PKTSETFRAGPKTID(osh, lb, id) BCM_REFERENCE(osh) +#define PKTFRAGTOTNUM(osh, lb) (0) +#define PKTSETFRAGTOTNUM(osh, lb, tot) BCM_REFERENCE(osh) +#define PKTFRAGTOTLEN(osh, lb) (0) +#define PKTSETFRAGTOTLEN(osh, lb, len) BCM_REFERENCE(osh) +#define PKTIFINDEX(osh, lb) (0) +#define PKTSETIFINDEX(osh, lb, idx) BCM_REFERENCE(osh) +#define PKTGETLF(osh, len, send, lbuf_type) (0) + +/* in rx path, reuse totlen as used len */ +#define PKTFRAGUSEDLEN(osh, lb) (0) +#define PKTSETFRAGUSEDLEN(osh, lb, len) BCM_REFERENCE(osh) + +#define PKTFRAGLEN(osh, lb, ix) (0) +#define PKTSETFRAGLEN(osh, lb, ix, len) BCM_REFERENCE(osh) +#define PKTFRAGDATA_LO(osh, lb, ix) (0) +#define PKTSETFRAGDATA_LO(osh, lb, ix, addr) BCM_REFERENCE(osh) +#define PKTFRAGDATA_HI(osh, lb, ix) (0) +#define PKTSETFRAGDATA_HI(osh, lb, ix, addr) BCM_REFERENCE(osh) + +/* RX FRAG */ +#define PKTISRXFRAG(osh, lb) (0) +#define PKTSETRXFRAG(osh, lb) BCM_REFERENCE(osh) +#define PKTRESETRXFRAG(osh, lb) BCM_REFERENCE(osh) + +/* TX FRAG */ +#define PKTISTXFRAG(osh, lb) (0) +#define PKTSETTXFRAG(osh, lb) BCM_REFERENCE(osh) + +/* Need Rx completion used for AMPDU reordering */ +#define PKTNEEDRXCPL(osh, lb) (TRUE) +#define PKTSETNORXCPL(osh, lb) BCM_REFERENCE(osh) +#define PKTRESETNORXCPL(osh, lb) BCM_REFERENCE(osh) + +#define PKTISFRAG(osh, lb) (0) +#define PKTFRAGISCHAINED(osh, i) (0) +/* TRIM Tail bytes from lfrag */ +#define PKTFRAG_TRIM_TAILBYTES(osh, p, len) PKTSETLEN(osh, p, PKTLEN(osh, p) - len) + +#endif /* _osl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/osl_decl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/osl_decl.h new file mode 100644 index 000000000000..04f44a5fea93 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/osl_decl.h @@ -0,0 +1,34 @@ +/* + * osl forward declarations + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id$ + */ + +#ifndef _osl_decl_h_ +#define _osl_decl_h_ + +/* osl handle type forward declaration */ +typedef struct osl_info osl_t; +typedef struct osl_dmainfo osldma_t; +extern unsigned int lmtest; /* low memory test */ +#endif diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_end.h b/drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_end.h new file mode 100644 index 000000000000..d4fde86ec6c4 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_end.h @@ -0,0 +1,59 @@ +/* + * Declare directives for structure packing. No padding will be provided + * between the members of packed structures, and therefore, there is no + * guarantee that structure members will be aligned. + * + * Declaring packed structures is compiler specific. In order to handle all + * cases, packed structures should be delared as: + * + * #include + * + * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { + * some_struct_members; + * } BWL_POST_PACKED_STRUCT foobar_t; + * + * #include + * + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: packed_section_end.h 437241 2013-11-18 07:39:24Z $ + */ + + +/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h + * and undefined in packed_section_end.h. If it is NOT defined at this + * point, then there is a missing include of packed_section_start.h. + */ +#ifdef BWL_PACKED_SECTION + #undef BWL_PACKED_SECTION +#else + #error "BWL_PACKED_SECTION is NOT defined!" +#endif + + + + +/* Compiler-specific directives for structure packing are declared in + * packed_section_start.h. This marks the end of the structure packing section, + * so, undef them here. + */ +#undef BWL_PRE_PACKED_STRUCT +#undef BWL_POST_PACKED_STRUCT diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_start.h b/drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_start.h new file mode 100644 index 000000000000..e77fe1477ecf --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_start.h @@ -0,0 +1,63 @@ +/* + * Declare directives for structure packing. No padding will be provided + * between the members of packed structures, and therefore, there is no + * guarantee that structure members will be aligned. + * + * Declaring packed structures is compiler specific. In order to handle all + * cases, packed structures should be delared as: + * + * #include + * + * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { + * some_struct_members; + * } BWL_POST_PACKED_STRUCT foobar_t; + * + * #include + * + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: packed_section_start.h 437241 2013-11-18 07:39:24Z $ + */ + + +/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h + * and undefined in packed_section_end.h. If it is already defined at this + * point, then there is a missing include of packed_section_end.h. + */ +#ifdef BWL_PACKED_SECTION + #error "BWL_PACKED_SECTION is already defined!" +#else + #define BWL_PACKED_SECTION +#endif + + + + +/* Declare compiler-specific directives for structure packing. */ +#if defined(__GNUC__) || defined(__lint) + #define BWL_PRE_PACKED_STRUCT + #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) +#elif defined(__CC_ARM) + #define BWL_PRE_PACKED_STRUCT __packed + #define BWL_POST_PACKED_STRUCT +#else + #error "Unknown compiler!" +#endif diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/pcicfg.h b/drivers/net/wireless/bcmdhd_bcm4356/include/pcicfg.h new file mode 100644 index 000000000000..5fae554da755 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/pcicfg.h @@ -0,0 +1,260 @@ +/* + * pcicfg.h: PCI configuration constants and structures. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: pcicfg.h 506084 2014-10-02 15:34:59Z $ + */ + +#ifndef _h_pcicfg_ +#define _h_pcicfg_ + + +/* pci config status reg has a bit to indicate that capability ptr is present */ + +#define PCI_CAPPTR_PRESENT 0x0010 + +/* A structure for the config registers is nice, but in most + * systems the config space is not memory mapped, so we need + * field offsetts. :-( + */ +#define PCI_CFG_VID 0 +#define PCI_CFG_DID 2 +#define PCI_CFG_CMD 4 +#define PCI_CFG_STAT 6 +#define PCI_CFG_REV 8 +#define PCI_CFG_PROGIF 9 +#define PCI_CFG_SUBCL 0xa +#define PCI_CFG_BASECL 0xb +#define PCI_CFG_CLSZ 0xc +#define PCI_CFG_LATTIM 0xd +#define PCI_CFG_HDR 0xe +#define PCI_CFG_BIST 0xf +#define PCI_CFG_BAR0 0x10 +#define PCI_CFG_BAR1 0x14 +#define PCI_CFG_BAR2 0x18 +#define PCI_CFG_BAR3 0x1c +#define PCI_CFG_BAR4 0x20 +#define PCI_CFG_BAR5 0x24 +#define PCI_CFG_CIS 0x28 +#define PCI_CFG_SVID 0x2c +#define PCI_CFG_SSID 0x2e +#define PCI_CFG_ROMBAR 0x30 +#define PCI_CFG_CAPPTR 0x34 +#define PCI_CFG_INT 0x3c +#define PCI_CFG_PIN 0x3d +#define PCI_CFG_MINGNT 0x3e +#define PCI_CFG_MAXLAT 0x3f +#define PCI_CFG_DEVCTRL 0xd8 + + +/* PCI CAPABILITY DEFINES */ +#define PCI_CAP_POWERMGMTCAP_ID 0x01 +#define PCI_CAP_MSICAP_ID 0x05 +#define PCI_CAP_VENDSPEC_ID 0x09 +#define PCI_CAP_PCIECAP_ID 0x10 + +/* Data structure to define the Message Signalled Interrupt facility + * Valid for PCI and PCIE configurations + */ +typedef struct _pciconfig_cap_msi { + uint8 capID; + uint8 nextptr; + uint16 msgctrl; + uint32 msgaddr; +} pciconfig_cap_msi; +#define MSI_ENABLE 0x1 /* bit 0 of msgctrl */ + +/* Data structure to define the Power managment facility + * Valid for PCI and PCIE configurations + */ +typedef struct _pciconfig_cap_pwrmgmt { + uint8 capID; + uint8 nextptr; + uint16 pme_cap; + uint16 pme_sts_ctrl; + uint8 pme_bridge_ext; + uint8 data; +} pciconfig_cap_pwrmgmt; + +#define PME_CAP_PM_STATES (0x1f << 27) /* Bits 31:27 states that can generate PME */ +#define PME_CSR_OFFSET 0x4 /* 4-bytes offset */ +#define PME_CSR_PME_EN (1 << 8) /* Bit 8 Enable generating of PME */ +#define PME_CSR_PME_STAT (1 << 15) /* Bit 15 PME got asserted */ + +/* Data structure to define the PCIE capability */ +typedef struct _pciconfig_cap_pcie { + uint8 capID; + uint8 nextptr; + uint16 pcie_cap; + uint32 dev_cap; + uint16 dev_ctrl; + uint16 dev_status; + uint32 link_cap; + uint16 link_ctrl; + uint16 link_status; + uint32 slot_cap; + uint16 slot_ctrl; + uint16 slot_status; + uint16 root_ctrl; + uint16 root_cap; + uint32 root_status; +} pciconfig_cap_pcie; + +/* PCIE Enhanced CAPABILITY DEFINES */ +#define PCIE_EXTCFG_OFFSET 0x100 +#define PCIE_ADVERRREP_CAPID 0x0001 +#define PCIE_VC_CAPID 0x0002 +#define PCIE_DEVSNUM_CAPID 0x0003 +#define PCIE_PWRBUDGET_CAPID 0x0004 + +/* PCIE Extended configuration */ +#define PCIE_ADV_CORR_ERR_MASK 0x114 +#define CORR_ERR_RE (1 << 0) /* Receiver */ +#define CORR_ERR_BT (1 << 6) /* Bad TLP */ +#define CORR_ERR_BD (1 << 7) /* Bad DLLP */ +#define CORR_ERR_RR (1 << 8) /* REPLAY_NUM rollover */ +#define CORR_ERR_RT (1 << 12) /* Reply timer timeout */ +#define ALL_CORR_ERRORS (CORR_ERR_RE | CORR_ERR_BT | CORR_ERR_BD | \ + CORR_ERR_RR | CORR_ERR_RT) + +/* PCIE Root Control Register bits (Host mode only) */ +#define PCIE_RC_CORR_SERR_EN 0x0001 +#define PCIE_RC_NONFATAL_SERR_EN 0x0002 +#define PCIE_RC_FATAL_SERR_EN 0x0004 +#define PCIE_RC_PME_INT_EN 0x0008 +#define PCIE_RC_CRS_EN 0x0010 + +/* PCIE Root Capability Register bits (Host mode only) */ +#define PCIE_RC_CRS_VISIBILITY 0x0001 + +/* Header to define the PCIE specific capabilities in the extended config space */ +typedef struct _pcie_enhanced_caphdr { + uint16 capID; + uint16 cap_ver : 4; + uint16 next_ptr : 12; +} pcie_enhanced_caphdr; + + +#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */ +#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */ +#define PCI_SPROM_CONTROL 0x88 /* sprom property control */ +#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */ +#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */ +#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */ +#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */ +#define PCI_BACKPLANE_ADDR 0xa0 /* address an arbitrary location on the system backplane */ +#define PCI_BACKPLANE_DATA 0xa4 /* data at the location specified by above address */ +#define PCI_CLK_CTL_ST 0xa8 /* pci config space clock control/status (>=rev14) */ +#define PCI_BAR0_WIN2 0xac /* backplane addres space accessed by second 4KB of BAR0 */ +#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */ +#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */ +#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */ +#define PCI_LINK_CTRL 0xbc /* PCI link control register */ +#define PCI_DEV_STAT_CTRL2 0xd4 /* PCI device status control 2 register */ +#define PCIE_LTR_MAX_SNOOP 0x1b4 /* PCIE LTRMaxSnoopLatency */ +#define PCI_L1SS_CTRL 0x248 /* The L1 PM Substates Control register */ +#define PCI_L1SS_CTRL2 0x24c /* The L1 PM Substates Control 2 register */ + +/* Private Registers */ +#define PCI_STAT_CTRL 0xa80 +#define PCI_L0_EVENTCNT 0xa84 +#define PCI_L0_STATETMR 0xa88 +#define PCI_L1_EVENTCNT 0xa8c +#define PCI_L1_STATETMR 0xa90 +#define PCI_L1_1_EVENTCNT 0xa94 +#define PCI_L1_1_STATETMR 0xa98 +#define PCI_L1_2_EVENTCNT 0xa9c +#define PCI_L1_2_STATETMR 0xaa0 +#define PCI_L2_EVENTCNT 0xaa4 +#define PCI_L2_STATETMR 0xaa8 + +#define PCI_PMCR_REFUP 0x1814 /* Trefup time */ +#define PCI_PMCR_REFUP_EXT 0x1818 /* Trefup extend Max */ +#define PCI_TPOWER_SCALE_MASK 0x3 +#define PCI_TPOWER_SCALE_SHIFT 3 /* 0:1 is scale and 2 is rsvd */ + + +#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) /* bar0 + 2K accesses sprom shadow (in pci core) */ +#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */ +#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */ +#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) /* pci core SB registers are at the end of the + * 8KB window, so their address is the "regular" + * address plus 4K + */ +/* + * PCIE GEN2 changed some of the above locations for + * Bar0WrapperBase, SecondaryBAR0Window and SecondaryBAR0WrapperBase + * BAR0 maps 32K of register space +*/ +#define PCIE2_BAR0_WIN2 0x70 /* backplane addres space accessed by second 4KB of BAR0 */ +#define PCIE2_BAR0_CORE2_WIN 0x74 /* backplane addres space accessed by second 4KB of BAR0 */ +#define PCIE2_BAR0_CORE2_WIN2 0x78 /* backplane addres space accessed by second 4KB of BAR0 */ + +#define PCI_BAR0_WINSZ (16 * 1024) /* bar0 window size Match with corerev 13 */ +/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ +#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) /* bar0 + 8K accesses pci/pcie core registers */ +#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) /* bar0 + 12K accesses chipc core registers */ +#define PCI_16KBB0_WINSZ (16 * 1024) /* bar0 window size */ + + +/* Header types */ +#define PCI_HEADER_MULTI 0x80 +#define PCI_HEADER_MASK 0x7f +typedef enum { + PCI_HEADER_NORMAL, + PCI_HEADER_BRIDGE, + PCI_HEADER_CARDBUS +} pci_header_types; + +#define PCI_CONFIG_SPACE_SIZE 256 + +#define DWORD_ALIGN(x) (x & ~(0x03)) +#define BYTE_POS(x) (x & 0x3) +#define WORD_POS(x) (x & 0x1) + +#define BYTE_SHIFT(x) (8 * BYTE_POS(x)) +#define WORD_SHIFT(x) (16 * WORD_POS(x)) + +#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF) +#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF) + +#define read_pci_cfg_byte(a) \ + (BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff) + +#define read_pci_cfg_word(a) \ + (WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff) + +#define write_pci_cfg_byte(a, val) do { \ + uint32 tmpval; \ + tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \ + val << BYTE_POS(a); \ + OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \ + } while (0) + +#define write_pci_cfg_word(a, val) do { \ + uint32 tmpval; \ + tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \ + val << WORD_POS(a); \ + OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \ + } while (0) + +#endif /* _h_pcicfg_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/pcie_core.h b/drivers/net/wireless/bcmdhd_bcm4356/include/pcie_core.h new file mode 100644 index 000000000000..68ffac32dcae --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/pcie_core.h @@ -0,0 +1,642 @@ +/* + * BCM43XX PCIE core hardware definitions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: pcie_core.h 483003 2014-06-05 19:57:46Z $ + */ +#ifndef _PCIE_CORE_H +#define _PCIE_CORE_H + +#include +#include + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif + +/* PCIE Enumeration space offsets */ +#define PCIE_CORE_CONFIG_OFFSET 0x0 +#define PCIE_FUNC0_CONFIG_OFFSET 0x400 +#define PCIE_FUNC1_CONFIG_OFFSET 0x500 +#define PCIE_FUNC2_CONFIG_OFFSET 0x600 +#define PCIE_FUNC3_CONFIG_OFFSET 0x700 +#define PCIE_SPROM_SHADOW_OFFSET 0x800 +#define PCIE_SBCONFIG_OFFSET 0xE00 + + +#define PCIEDEV_MAX_DMAS 4 + +/* PCIE Bar0 Address Mapping. Each function maps 16KB config space */ +#define PCIE_DEV_BAR0_SIZE 0x4000 +#define PCIE_BAR0_WINMAPCORE_OFFSET 0x0 +#define PCIE_BAR0_EXTSPROM_OFFSET 0x1000 +#define PCIE_BAR0_PCIECORE_OFFSET 0x2000 +#define PCIE_BAR0_CCCOREREG_OFFSET 0x3000 + +/* different register spaces to access thr'u pcie indirect access */ +#define PCIE_CONFIGREGS 1 /* Access to config space */ +#define PCIE_PCIEREGS 2 /* Access to pcie registers */ + +/* dma regs to control the flow between host2dev and dev2host */ +typedef struct pcie_devdmaregs { + dma64regs_t tx; + uint32 PAD[2]; + dma64regs_t rx; + uint32 PAD[2]; +} pcie_devdmaregs_t; + +#define PCIE_DB_HOST2DEV_0 0x1 +#define PCIE_DB_HOST2DEV_1 0x2 +#define PCIE_DB_DEV2HOST_0 0x3 +#define PCIE_DB_DEV2HOST_1 0x4 + +/* door bell register sets */ +typedef struct pcie_doorbell { + uint32 host2dev_0; + uint32 host2dev_1; + uint32 dev2host_0; + uint32 dev2host_1; +} pcie_doorbell_t; + +/* SB side: PCIE core and host control registers */ +typedef struct sbpcieregs { + uint32 control; /* host mode only */ + uint32 iocstatus; /* PCIE2: iostatus */ + uint32 PAD[1]; + uint32 biststatus; /* bist Status: 0x00C */ + uint32 gpiosel; /* PCIE gpio sel: 0x010 */ + uint32 gpioouten; /* PCIE gpio outen: 0x14 */ + uint32 PAD[2]; + uint32 intstatus; /* Interrupt status: 0x20 */ + uint32 intmask; /* Interrupt mask: 0x24 */ + uint32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */ + uint32 obffcontrol; /* PCIE2: 0x2C */ + uint32 obffintstatus; /* PCIE2: 0x30 */ + uint32 obffdatastatus; /* PCIE2: 0x34 */ + uint32 PAD[2]; + uint32 errlog; /* PCIE2: 0x40 */ + uint32 errlogaddr; /* PCIE2: 0x44 */ + uint32 mailboxint; /* PCIE2: 0x48 */ + uint32 mailboxintmsk; /* PCIE2: 0x4c */ + uint32 ltrspacing; /* PCIE2: 0x50 */ + uint32 ltrhysteresiscnt; /* PCIE2: 0x54 */ + uint32 PAD[42]; + + uint32 sbtopcie0; /* sb to pcie translation 0: 0x100 */ + uint32 sbtopcie1; /* sb to pcie translation 1: 0x104 */ + uint32 sbtopcie2; /* sb to pcie translation 2: 0x108 */ + uint32 PAD[5]; + + /* pcie core supports in direct access to config space */ + uint32 configaddr; /* pcie config space access: Address field: 0x120 */ + uint32 configdata; /* pcie config space access: Data field: 0x124 */ + union { + struct { + /* mdio access to serdes */ + uint32 mdiocontrol; /* controls the mdio access: 0x128 */ + uint32 mdiodata; /* Data to the mdio access: 0x12c */ + /* pcie protocol phy/dllp/tlp register indirect access mechanism */ + uint32 pcieindaddr; /* indirect access to the internal register: 0x130 */ + uint32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */ + uint32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */ + uint32 PAD[177]; + } pcie1; + struct { + /* mdio access to serdes */ + uint32 mdiocontrol; /* controls the mdio access: 0x128 */ + uint32 mdiowrdata; /* write data to mdio 0x12C */ + uint32 mdiorddata; /* read data to mdio 0x130 */ + uint32 PAD[3]; /* 0x134-0x138-0x13c */ + /* door bell registers available from gen2 rev5 onwards */ + pcie_doorbell_t dbls[PCIEDEV_MAX_DMAS]; /* 0x140 - 0x17F */ + uint32 dataintf; /* 0x180 */ + uint32 PAD[1]; /* 0x184 */ + uint32 d2h_intrlazy_0; /* 0x188 */ + uint32 h2d_intrlazy_0; /* 0x18c */ + uint32 h2d_intstat_0; /* 0x190 */ + uint32 h2d_intmask_0; /* 0x194 */ + uint32 d2h_intstat_0; /* 0x198 */ + uint32 d2h_intmask_0; /* 0x19c */ + uint32 ltr_state; /* 0x1A0 */ + uint32 pwr_int_status; /* 0x1A4 */ + uint32 pwr_int_mask; /* 0x1A8 */ + uint32 PAD[21]; /* 0x1AC - 0x200 */ + pcie_devdmaregs_t h2d0_dmaregs; /* 0x200 - 0x23c */ + pcie_devdmaregs_t d2h0_dmaregs; /* 0x240 - 0x27c */ + pcie_devdmaregs_t h2d1_dmaregs; /* 0x280 - 0x2bc */ + pcie_devdmaregs_t d2h1_dmaregs; /* 0x2c0 - 0x2fc */ + pcie_devdmaregs_t h2d2_dmaregs; /* 0x300 - 0x33c */ + pcie_devdmaregs_t d2h2_dmaregs; /* 0x340 - 0x37c */ + pcie_devdmaregs_t h2d3_dmaregs; /* 0x380 - 0x3bc */ + pcie_devdmaregs_t d2h3_dmaregs; /* 0x3c0 - 0x3fc */ + } pcie2; + } u; + uint32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */ + uint16 sprom[64]; /* SPROM shadow Area */ +} sbpcieregs_t; + +/* PCI control */ +#define PCIE_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */ +#define PCIE_RST 0x02 /* Value driven out to pin */ +#define PCIE_SPERST 0x04 /* SurvivePeRst */ +#define PCIE_DISABLE_L1CLK_GATING 0x10 +#define PCIE_DLYPERST 0x100 /* Delay PeRst to CoE Core */ +#define PCIE_DISSPROMLD 0x200 /* DisableSpromLoadOnPerst */ +#define PCIE_WakeModeL2 0x1000 /* Wake on L2 */ + +#define PCIE_CFGADDR 0x120 /* offsetof(configaddr) */ +#define PCIE_CFGDATA 0x124 /* offsetof(configdata) */ + +/* Interrupt status/mask */ +#define PCIE_INTA 0x01 /* PCIE INTA message is received */ +#define PCIE_INTB 0x02 /* PCIE INTB message is received */ +#define PCIE_INTFATAL 0x04 /* PCIE INTFATAL message is received */ +#define PCIE_INTNFATAL 0x08 /* PCIE INTNONFATAL message is received */ +#define PCIE_INTCORR 0x10 /* PCIE INTCORR message is received */ +#define PCIE_INTPME 0x20 /* PCIE INTPME message is received */ +#define PCIE_PERST 0x40 /* PCIE Reset Interrupt */ + +#define PCIE_INT_MB_FN0_0 0x0100 /* PCIE to SB Mailbox int Fn0.0 is received */ +#define PCIE_INT_MB_FN0_1 0x0200 /* PCIE to SB Mailbox int Fn0.1 is received */ +#define PCIE_INT_MB_FN1_0 0x0400 /* PCIE to SB Mailbox int Fn1.0 is received */ +#define PCIE_INT_MB_FN1_1 0x0800 /* PCIE to SB Mailbox int Fn1.1 is received */ +#define PCIE_INT_MB_FN2_0 0x1000 /* PCIE to SB Mailbox int Fn2.0 is received */ +#define PCIE_INT_MB_FN2_1 0x2000 /* PCIE to SB Mailbox int Fn2.1 is received */ +#define PCIE_INT_MB_FN3_0 0x4000 /* PCIE to SB Mailbox int Fn3.0 is received */ +#define PCIE_INT_MB_FN3_1 0x8000 /* PCIE to SB Mailbox int Fn3.1 is received */ + +/* PCIE MailboxInt/MailboxIntMask register */ +#define PCIE_MB_TOSB_FN0_0 0x0001 /* write to assert PCIEtoSB Mailbox interrupt */ +#define PCIE_MB_TOSB_FN0_1 0x0002 +#define PCIE_MB_TOSB_FN1_0 0x0004 +#define PCIE_MB_TOSB_FN1_1 0x0008 +#define PCIE_MB_TOSB_FN2_0 0x0010 +#define PCIE_MB_TOSB_FN2_1 0x0020 +#define PCIE_MB_TOSB_FN3_0 0x0040 +#define PCIE_MB_TOSB_FN3_1 0x0080 +#define PCIE_MB_TOPCIE_FN0_0 0x0100 /* int status/mask for SBtoPCIE Mailbox interrupts */ +#define PCIE_MB_TOPCIE_FN0_1 0x0200 +#define PCIE_MB_TOPCIE_FN1_0 0x0400 +#define PCIE_MB_TOPCIE_FN1_1 0x0800 +#define PCIE_MB_TOPCIE_FN2_0 0x1000 +#define PCIE_MB_TOPCIE_FN2_1 0x2000 +#define PCIE_MB_TOPCIE_FN3_0 0x4000 +#define PCIE_MB_TOPCIE_FN3_1 0x8000 +#define PCIE_MB_TOPCIE_D2H0_DB0 0x10000 +#define PCIE_MB_TOPCIE_D2H0_DB1 0x20000 +#define PCIE_MB_TOPCIE_D2H1_DB0 0x40000 +#define PCIE_MB_TOPCIE_D2H1_DB1 0x80000 +#define PCIE_MB_TOPCIE_D2H2_DB0 0x100000 +#define PCIE_MB_TOPCIE_D2H2_DB1 0x200000 +#define PCIE_MB_TOPCIE_D2H3_DB0 0x400000 +#define PCIE_MB_TOPCIE_D2H3_DB1 0x800000 + +#define PCIE_MB_D2H_MB_MASK \ + (PCIE_MB_TOPCIE_D2H0_DB0 | PCIE_MB_TOPCIE_D2H0_DB1 | \ + PCIE_MB_TOPCIE_D2H1_DB1 | PCIE_MB_TOPCIE_D2H1_DB1 | \ + PCIE_MB_TOPCIE_D2H2_DB1 | PCIE_MB_TOPCIE_D2H2_DB1 | \ + PCIE_MB_TOPCIE_D2H3_DB1 | PCIE_MB_TOPCIE_D2H3_DB1) + +/* SB to PCIE translation masks */ +#define SBTOPCIE0_MASK 0xfc000000 +#define SBTOPCIE1_MASK 0xfc000000 +#define SBTOPCIE2_MASK 0xc0000000 + +/* Access type bits (0:1) */ +#define SBTOPCIE_MEM 0 +#define SBTOPCIE_IO 1 +#define SBTOPCIE_CFG0 2 +#define SBTOPCIE_CFG1 3 + +/* Prefetch enable bit 2 */ +#define SBTOPCIE_PF 4 + +/* Write Burst enable for memory write bit 3 */ +#define SBTOPCIE_WR_BURST 8 + +/* config access */ +#define CONFIGADDR_FUNC_MASK 0x7000 +#define CONFIGADDR_FUNC_SHF 12 +#define CONFIGADDR_REG_MASK 0x0FFF +#define CONFIGADDR_REG_SHF 0 + +#define PCIE_CONFIG_INDADDR(f, r) ((((f) & CONFIGADDR_FUNC_MASK) << CONFIGADDR_FUNC_SHF) | \ + (((r) & CONFIGADDR_REG_MASK) << CONFIGADDR_REG_SHF)) + +/* PCIE protocol regs Indirect Address */ +#define PCIEADDR_PROT_MASK 0x300 +#define PCIEADDR_PROT_SHF 8 +#define PCIEADDR_PL_TLP 0 +#define PCIEADDR_PL_DLLP 1 +#define PCIEADDR_PL_PLP 2 + +/* PCIE protocol PHY diagnostic registers */ +#define PCIE_PLP_MODEREG 0x200 /* Mode */ +#define PCIE_PLP_STATUSREG 0x204 /* Status */ +#define PCIE_PLP_LTSSMCTRLREG 0x208 /* LTSSM control */ +#define PCIE_PLP_LTLINKNUMREG 0x20c /* Link Training Link number */ +#define PCIE_PLP_LTLANENUMREG 0x210 /* Link Training Lane number */ +#define PCIE_PLP_LTNFTSREG 0x214 /* Link Training N_FTS */ +#define PCIE_PLP_ATTNREG 0x218 /* Attention */ +#define PCIE_PLP_ATTNMASKREG 0x21C /* Attention Mask */ +#define PCIE_PLP_RXERRCTR 0x220 /* Rx Error */ +#define PCIE_PLP_RXFRMERRCTR 0x224 /* Rx Framing Error */ +#define PCIE_PLP_RXERRTHRESHREG 0x228 /* Rx Error threshold */ +#define PCIE_PLP_TESTCTRLREG 0x22C /* Test Control reg */ +#define PCIE_PLP_SERDESCTRLOVRDREG 0x230 /* SERDES Control Override */ +#define PCIE_PLP_TIMINGOVRDREG 0x234 /* Timing param override */ +#define PCIE_PLP_RXTXSMDIAGREG 0x238 /* RXTX State Machine Diag */ +#define PCIE_PLP_LTSSMDIAGREG 0x23C /* LTSSM State Machine Diag */ + +/* PCIE protocol DLLP diagnostic registers */ +#define PCIE_DLLP_LCREG 0x100 /* Link Control */ +#define PCIE_DLLP_LSREG 0x104 /* Link Status */ +#define PCIE_DLLP_LAREG 0x108 /* Link Attention */ +#define PCIE_DLLP_LAMASKREG 0x10C /* Link Attention Mask */ +#define PCIE_DLLP_NEXTTXSEQNUMREG 0x110 /* Next Tx Seq Num */ +#define PCIE_DLLP_ACKEDTXSEQNUMREG 0x114 /* Acked Tx Seq Num */ +#define PCIE_DLLP_PURGEDTXSEQNUMREG 0x118 /* Purged Tx Seq Num */ +#define PCIE_DLLP_RXSEQNUMREG 0x11C /* Rx Sequence Number */ +#define PCIE_DLLP_LRREG 0x120 /* Link Replay */ +#define PCIE_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */ +#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */ +#define PCIE_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */ +#define PCIE_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */ +#define PCIE_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */ +#define PCIE_DLLP_RTRRWREG 0x138 /* Retry buffer Read/Write */ +#define PCIE_DLLP_ECTHRESHREG 0x13C /* Error Count Threshold */ +#define PCIE_DLLP_TLPERRCTRREG 0x140 /* TLP Error Counter */ +#define PCIE_DLLP_ERRCTRREG 0x144 /* Error Counter */ +#define PCIE_DLLP_NAKRXCTRREG 0x148 /* NAK Received Counter */ +#define PCIE_DLLP_TESTREG 0x14C /* Test */ +#define PCIE_DLLP_PKTBIST 0x150 /* Packet BIST */ +#define PCIE_DLLP_PCIE11 0x154 /* DLLP PCIE 1.1 reg */ + +#define PCIE_DLLP_LSREG_LINKUP (1 << 16) + +/* PCIE protocol TLP diagnostic registers */ +#define PCIE_TLP_CONFIGREG 0x000 /* Configuration */ +#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */ +#define PCIE_TLP_WRDMAUPPER 0x010 /* Write DMA Upper Address */ +#define PCIE_TLP_WRDMALOWER 0x014 /* Write DMA Lower Address */ +#define PCIE_TLP_WRDMAREQ_LBEREG 0x018 /* Write DMA Len/ByteEn Req */ +#define PCIE_TLP_RDDMAUPPER 0x01C /* Read DMA Upper Address */ +#define PCIE_TLP_RDDMALOWER 0x020 /* Read DMA Lower Address */ +#define PCIE_TLP_RDDMALENREG 0x024 /* Read DMA Len Req */ +#define PCIE_TLP_MSIDMAUPPER 0x028 /* MSI DMA Upper Address */ +#define PCIE_TLP_MSIDMALOWER 0x02C /* MSI DMA Lower Address */ +#define PCIE_TLP_MSIDMALENREG 0x030 /* MSI DMA Len Req */ +#define PCIE_TLP_SLVREQLENREG 0x034 /* Slave Request Len */ +#define PCIE_TLP_FCINPUTSREQ 0x038 /* Flow Control Inputs */ +#define PCIE_TLP_TXSMGRSREQ 0x03C /* Tx StateMachine and Gated Req */ +#define PCIE_TLP_ADRACKCNTARBLEN 0x040 /* Address Ack XferCnt and ARB Len */ +#define PCIE_TLP_DMACPLHDR0 0x044 /* DMA Completion Hdr 0 */ +#define PCIE_TLP_DMACPLHDR1 0x048 /* DMA Completion Hdr 1 */ +#define PCIE_TLP_DMACPLHDR2 0x04C /* DMA Completion Hdr 2 */ +#define PCIE_TLP_DMACPLMISC0 0x050 /* DMA Completion Misc0 */ +#define PCIE_TLP_DMACPLMISC1 0x054 /* DMA Completion Misc1 */ +#define PCIE_TLP_DMACPLMISC2 0x058 /* DMA Completion Misc2 */ +#define PCIE_TLP_SPTCTRLLEN 0x05C /* Split Controller Req len */ +#define PCIE_TLP_SPTCTRLMSIC0 0x060 /* Split Controller Misc 0 */ +#define PCIE_TLP_SPTCTRLMSIC1 0x064 /* Split Controller Misc 1 */ +#define PCIE_TLP_BUSDEVFUNC 0x068 /* Bus/Device/Func */ +#define PCIE_TLP_RESETCTR 0x06C /* Reset Counter */ +#define PCIE_TLP_RTRYBUF 0x070 /* Retry Buffer value */ +#define PCIE_TLP_TGTDEBUG1 0x074 /* Target Debug Reg1 */ +#define PCIE_TLP_TGTDEBUG2 0x078 /* Target Debug Reg2 */ +#define PCIE_TLP_TGTDEBUG3 0x07C /* Target Debug Reg3 */ +#define PCIE_TLP_TGTDEBUG4 0x080 /* Target Debug Reg4 */ + +/* PCIE2 MDIO register offsets */ +#define PCIE2_MDIO_CONTROL 0x128 +#define PCIE2_MDIO_WR_DATA 0x12C +#define PCIE2_MDIO_RD_DATA 0x130 + + +/* 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 /* Tranaction complete */ + +/* MDIO Data */ +#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */ +#define MDIODATA_TA 0x00020000 /* Turnaround */ +#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift (rev < 10) */ +#define MDIODATA_REGADDR_MASK_OLD 0x003c0000 /* Regaddr Mask (rev < 10) */ +#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift (rev < 10) */ +#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000 /* Physmedia devaddr Mask (rev < 10) */ +#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 */ +#define MDIODATA_WRITE 0x10000000 /* write Transaction */ +#define MDIODATA_READ 0x20000000 /* Read Transaction */ +#define MDIODATA_START 0x40000000 /* start of Transaction */ + +#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */ +#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */ + +/* MDIO control/wrData/rdData register defines for PCIE Gen 2 */ +#define MDIOCTL2_DIVISOR_MASK 0x7f /* clock to be used on MDIO */ +#define MDIOCTL2_DIVISOR_VAL 0x2 +#define MDIOCTL2_REGADDR_SHF 8 /* Regaddr shift */ +#define MDIOCTL2_REGADDR_MASK 0x00FFFF00 /* Regaddr Mask */ +#define MDIOCTL2_DEVADDR_SHF 24 /* Physmedia devaddr shift */ +#define MDIOCTL2_DEVADDR_MASK 0x0f000000 /* Physmedia devaddr Mask */ +#define MDIOCTL2_SLAVE_BYPASS 0x10000000 /* IP slave bypass */ +#define MDIOCTL2_READ 0x20000000 /* IP slave bypass */ + +#define MDIODATA2_DONE 0x80000000 /* rd/wr transaction done */ +#define MDIODATA2_MASK 0x7FFFFFFF /* rd/wr transaction data */ +#define MDIODATA2_DEVADDR_SHF 4 /* Physmedia devaddr shift */ + + +/* MDIO devices (SERDES modules) + * unlike old pcie cores (rev < 10), rev10 pcie serde organizes registers into a few blocks. + * two layers mapping (blockidx, register offset) is required + */ +#define MDIO_DEV_IEEE0 0x000 +#define MDIO_DEV_IEEE1 0x001 +#define MDIO_DEV_BLK0 0x800 +#define MDIO_DEV_BLK1 0x801 +#define MDIO_DEV_BLK2 0x802 +#define MDIO_DEV_BLK3 0x803 +#define MDIO_DEV_BLK4 0x804 +#define MDIO_DEV_TXPLL 0x808 /* TXPLL register block idx */ +#define MDIO_DEV_TXCTRL0 0x820 +#define MDIO_DEV_SERDESID 0x831 +#define MDIO_DEV_RXCTRL0 0x840 + + +/* XgxsBlk1_A Register Offsets */ +#define BLK1_PWR_MGMT0 0x16 +#define BLK1_PWR_MGMT1 0x17 +#define BLK1_PWR_MGMT2 0x18 +#define BLK1_PWR_MGMT3 0x19 +#define BLK1_PWR_MGMT4 0x1A + +/* 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 */ + +/* Power management threshold */ +#define PCIE_L0THRESHOLDTIME_MASK 0xFF00 /* bits 0 - 7 */ +#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 */ + +/* 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_OFFSET_REV8 52 /* word 52 for srom rev 8 */ +#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */ +#define SRSH_BD_OFFSET 6 /* word 6 */ +#define SRSH_AUTOINIT_OFFSET 18 /* auto initialization enable */ + +/* Linkcontrol reg offset in PCIE Cap */ +#define PCIE_CAP_LINKCTRL_OFFSET 16 /* linkctrl 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_LINKSPEED_MASK 0xF0000 /* bits 0 - 3 of high word */ +#define PCIE_LINKSPEED_SHIFT 16 /* PCIE_LINKSPEED_SHIFT */ + +/* Devcontrol reg offset in PCIE Cap */ +#define PCIE_CAP_DEVCTRL_OFFSET 8 /* devctrl offset in pcie cap */ +#define PCIE_CAP_DEVCTRL_MRRS_MASK 0x7000 /* Max read request size mask */ +#define PCIE_CAP_DEVCTRL_MRRS_SHIFT 12 /* Max read request size shift */ +#define PCIE_CAP_DEVCTRL_MRRS_128B 0 /* 128 Byte */ +#define PCIE_CAP_DEVCTRL_MRRS_256B 1 /* 256 Byte */ +#define PCIE_CAP_DEVCTRL_MRRS_512B 2 /* 512 Byte */ +#define PCIE_CAP_DEVCTRL_MRRS_1024B 3 /* 1024 Byte */ +#define PCIE_CAP_DEVCTRL_MPS_MASK 0x00e0 /* Max payload size mask */ +#define PCIE_CAP_DEVCTRL_MPS_SHIFT 5 /* Max payload size shift */ +#define PCIE_CAP_DEVCTRL_MPS_128B 0 /* 128 Byte */ +#define PCIE_CAP_DEVCTRL_MPS_256B 1 /* 256 Byte */ +#define PCIE_CAP_DEVCTRL_MPS_512B 2 /* 512 Byte */ +#define PCIE_CAP_DEVCTRL_MPS_1024B 3 /* 1024 Byte */ + +#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 */ + +#define PCIE_ASPM_L11_ENAB 8 /* ASPM L1.1 in PML1_sub_control2 */ +#define PCIE_ASPM_L12_ENAB 4 /* ASPM L1.2 in PML1_sub_control2 */ + +/* Devcontrol2 reg offset in PCIE Cap */ +#define PCIE_CAP_DEVCTRL2_OFFSET 0x28 /* devctrl2 offset in pcie cap */ +#define PCIE_CAP_DEVCTRL2_LTR_ENAB_MASK 0x400 /* Latency Tolerance Reporting Enable */ +#define PCIE_CAP_DEVCTRL2_OBFF_ENAB_SHIFT 13 /* Enable OBFF mechanism, select signaling method */ +#define PCIE_CAP_DEVCTRL2_OBFF_ENAB_MASK 0x6000 /* Enable OBFF mechanism, select signaling method */ + +/* LTR registers in PCIE Cap */ +#define PCIE_LTR0_REG_OFFSET 0x844 /* ltr0_reg offset in pcie cap */ +#define PCIE_LTR1_REG_OFFSET 0x848 /* ltr1_reg offset in pcie cap */ +#define PCIE_LTR2_REG_OFFSET 0x84c /* ltr2_reg offset in pcie cap */ +#define PCIE_LTR0_REG_DEFAULT_60 0x883c883c /* active latency default to 60usec */ +#define PCIE_LTR0_REG_DEFAULT_150 0x88968896 /* active latency default to 150usec */ +#define PCIE_LTR1_REG_DEFAULT 0x88648864 /* idle latency default to 100usec */ +#define PCIE_LTR2_REG_DEFAULT 0x90039003 /* sleep latency default to 3msec */ + +/* Status reg PCIE_PLP_STATUSREG */ +#define PCIE_PLP_POLARITYINV_STAT 0x10 + + +/* PCIE BRCM Vendor CAP REVID reg bits */ +#define BRCMCAP_PCIEREV_CT_MASK 0xF00 +#define BRCMCAP_PCIEREV_CT_SHIFT 8 +#define BRCMCAP_PCIEREV_REVID_MASK 0xFF +#define BRCMCAP_PCIEREV_REVID_SHIFT 0 + +#define PCIE_REVREG_CT_PCIE1 0 +#define PCIE_REVREG_CT_PCIE2 1 + +/* PCIE GEN2 specific defines */ +/* PCIE BRCM Vendor Cap offsets w.r.t to vendor cap ptr */ +#define PCIE2R0_BRCMCAP_REVID_OFFSET 4 +#define PCIE2R0_BRCMCAP_BAR0_WIN0_WRAP_OFFSET 8 +#define PCIE2R0_BRCMCAP_BAR0_WIN2_OFFSET 12 +#define PCIE2R0_BRCMCAP_BAR0_WIN2_WRAP_OFFSET 16 +#define PCIE2R0_BRCMCAP_BAR0_WIN_OFFSET 20 +#define PCIE2R0_BRCMCAP_BAR1_WIN_OFFSET 24 +#define PCIE2R0_BRCMCAP_SPROM_CTRL_OFFSET 28 +#define PCIE2R0_BRCMCAP_BAR2_WIN_OFFSET 32 +#define PCIE2R0_BRCMCAP_INTSTATUS_OFFSET 36 +#define PCIE2R0_BRCMCAP_INTMASK_OFFSET 40 +#define PCIE2R0_BRCMCAP_PCIE2SB_MB_OFFSET 44 +#define PCIE2R0_BRCMCAP_BPADDR_OFFSET 48 +#define PCIE2R0_BRCMCAP_BPDATA_OFFSET 52 +#define PCIE2R0_BRCMCAP_CLKCTLSTS_OFFSET 56 + +/* definition of configuration space registers of PCIe gen2 + * http://hwnbu-twiki.sj.broadcom.com/twiki/pub/Mwgroup/CurrentPcieGen2ProgramGuide/pcie_ep.htm + */ +#define PCIECFGREG_STATUS_CMD 0x4 +#define PCIECFGREG_PM_CSR 0x4C +#define PCIECFGREG_MSI_CAP 0x58 +#define PCIECFGREG_MSI_ADDR_L 0x5C +#define PCIECFGREG_MSI_ADDR_H 0x60 +#define PCIECFGREG_MSI_DATA 0x64 +#define PCIECFGREG_LINK_STATUS_CTRL 0xBC +#define PCIECFGREG_LINK_STATUS_CTRL2 0xDC +#define PCIECFGREG_RBAR_CTRL 0x228 +#define PCIECFGREG_PML1_SUB_CTRL1 0x248 +#define PCIECFGREG_REG_BAR2_CONFIG 0x4E0 +#define PCIECFGREG_REG_BAR3_CONFIG 0x4F4 +#define PCIECFGREG_PDL_CTRL1 0x1004 +#define PCIECFGREG_PDL_IDDQ 0x1814 +#define PCIECFGREG_REG_PHY_CTL7 0x181c + +/* PCIECFGREG_PML1_SUB_CTRL1 Bit Definition */ +#define PCI_PM_L1_2_ENA_MASK 0x00000001 /* PCI-PM L1.2 Enabled */ +#define PCI_PM_L1_1_ENA_MASK 0x00000002 /* PCI-PM L1.1 Enabled */ +#define ASPM_L1_2_ENA_MASK 0x00000004 /* ASPM L1.2 Enabled */ +#define ASPM_L1_1_ENA_MASK 0x00000008 /* ASPM L1.1 Enabled */ + +/* PCIe gen2 mailbox interrupt masks */ +#define I_MB 0x3 +#define I_BIT0 0x1 +#define I_BIT1 0x2 + +/* PCIE gen2 config regs */ +#define PCIIntstatus 0x090 +#define PCIIntmask 0x094 +#define PCISBMbx 0x98 + +/* enumeration Core regs */ +#define PCIH2D_MailBox 0x140 +#define PCIH2D_DB1 0x144 +#define PCID2H_MailBox 0x148 +#define PCIMailBoxInt 0x48 +#define PCIMailBoxMask 0x4C + +#define I_F0_B0 (0x1 << 8) /* Mail box interrupt Function 0 interrupt, bit 0 */ +#define I_F0_B1 (0x1 << 9) /* Mail box interrupt Function 0 interrupt, bit 1 */ + +#define PCIECFGREG_DEVCONTROL 0xB4 + +/* SROM hardware region */ +#define SROM_OFFSET_BAR1_CTRL 52 + +#define BAR1_ENC_SIZE_MASK 0x000e +#define BAR1_ENC_SIZE_SHIFT 1 + +#define BAR1_ENC_SIZE_1M 0 +#define BAR1_ENC_SIZE_2M 1 +#define BAR1_ENC_SIZE_4M 2 + +#define PCIEGEN2_CAP_DEVSTSCTRL2_OFFSET 0xD4 +#define PCIEGEN2_CAP_DEVSTSCTRL2_LTRENAB 0x400 + +/* + * Latency Tolerance Reporting (LTR) states + * Active has the least tolerant latency requirement + * Sleep is most tolerant + */ +#define LTR_ACTIVE 2 +#define LTR_ACTIVE_IDLE 1 +#define LTR_SLEEP 0 +#define LTR_FINAL_MASK 0x300 +#define LTR_FINAL_SHIFT 8 + +/* pwrinstatus, pwrintmask regs */ +#define PCIEGEN2_PWRINT_D0_STATE_SHIFT 0 +#define PCIEGEN2_PWRINT_D1_STATE_SHIFT 1 +#define PCIEGEN2_PWRINT_D2_STATE_SHIFT 2 +#define PCIEGEN2_PWRINT_D3_STATE_SHIFT 3 +#define PCIEGEN2_PWRINT_L0_LINK_SHIFT 4 +#define PCIEGEN2_PWRINT_L0s_LINK_SHIFT 5 +#define PCIEGEN2_PWRINT_L1_LINK_SHIFT 6 +#define PCIEGEN2_PWRINT_L2_L3_LINK_SHIFT 7 +#define PCIEGEN2_PWRINT_OBFF_CHANGE_SHIFT 8 + +#define PCIEGEN2_PWRINT_D0_STATE_MASK (1 << PCIEGEN2_PWRINT_D0_STATE_SHIFT) +#define PCIEGEN2_PWRINT_D1_STATE_MASK (1 << PCIEGEN2_PWRINT_D1_STATE_SHIFT) +#define PCIEGEN2_PWRINT_D2_STATE_MASK (1 << PCIEGEN2_PWRINT_D2_STATE_SHIFT) +#define PCIEGEN2_PWRINT_D3_STATE_MASK (1 << PCIEGEN2_PWRINT_D3_STATE_SHIFT) +#define PCIEGEN2_PWRINT_L0_LINK_MASK (1 << PCIEGEN2_PWRINT_L0_LINK_SHIFT) +#define PCIEGEN2_PWRINT_L0s_LINK_MASK (1 << PCIEGEN2_PWRINT_L0s_LINK_SHIFT) +#define PCIEGEN2_PWRINT_L1_LINK_MASK (1 << PCIEGEN2_PWRINT_L1_LINK_SHIFT) +#define PCIEGEN2_PWRINT_L2_L3_LINK_MASK (1 << PCIEGEN2_PWRINT_L2_L3_LINK_SHIFT) +#define PCIEGEN2_PWRINT_OBFF_CHANGE_MASK (1 << PCIEGEN2_PWRINT_OBFF_CHANGE_SHIFT) + +/* sbtopcie mail box */ +#define SBTOPCIE_MB_FUNC0_SHIFT 8 +#define SBTOPCIE_MB_FUNC1_SHIFT 10 +#define SBTOPCIE_MB_FUNC2_SHIFT 12 +#define SBTOPCIE_MB_FUNC3_SHIFT 14 + +/* pcieiocstatus */ +#define PCIEGEN2_IOC_D0_STATE_SHIFT 8 +#define PCIEGEN2_IOC_D1_STATE_SHIFT 9 +#define PCIEGEN2_IOC_D2_STATE_SHIFT 10 +#define PCIEGEN2_IOC_D3_STATE_SHIFT 11 +#define PCIEGEN2_IOC_L0_LINK_SHIFT 12 +#define PCIEGEN2_IOC_L1_LINK_SHIFT 13 +#define PCIEGEN2_IOC_L1L2_LINK_SHIFT 14 +#define PCIEGEN2_IOC_L2_L3_LINK_SHIFT 15 + +#define PCIEGEN2_IOC_D0_STATE_MASK (1 << PCIEGEN2_IOC_D0_STATE_SHIFT) +#define PCIEGEN2_IOC_D1_STATE_MASK (1 << PCIEGEN2_IOC_D1_STATE_SHIF) +#define PCIEGEN2_IOC_D2_STATE_MASK (1 << PCIEGEN2_IOC_D2_STATE_SHIF) +#define PCIEGEN2_IOC_D3_STATE_MASK (1 << PCIEGEN2_IOC_D3_STATE_SHIF) +#define PCIEGEN2_IOC_L0_LINK_MASK (1 << PCIEGEN2_IOC_L0_LINK_SHIF) +#define PCIEGEN2_IOC_L1_LINK_MASK (1 << PCIEGEN2_IOC_L1_LINK_SHIF) +#define PCIEGEN2_IOC_L1L2_LINK_MASK (1 << PCIEGEN2_IOC_L1L2_LINK_SHIFT) +#define PCIEGEN2_IOC_L2_L3_LINK_MASK (1 << PCIEGEN2_IOC_L2_L3_LINK_SHIFT) + +/* stat_ctrl */ +#define PCIE_STAT_CTRL_RESET 0x1 +#define PCIE_STAT_CTRL_ENABLE 0x2 +#define PCIE_STAT_CTRL_INTENABLE 0x4 +#define PCIE_STAT_CTRL_INTSTATUS 0x8 + +#ifdef BCMDRIVER +void pcie_watchdog_reset(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs); +#endif /* BCMDRIVER */ + +#endif /* _PCIE_CORE_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11.h new file mode 100644 index 000000000000..b446a6dd2617 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11.h @@ -0,0 +1,3853 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental types and constants relating to 802.11 + * + * $Id: 802.11.h 495738 2014-08-08 03:36:17Z $ + */ + +#ifndef _802_11_H_ +#define _802_11_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +#ifndef _NET_ETHERNET_H_ +#include +#endif + +#include + +/* This marks the start of a packed structure section. */ +#include + + +#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */ + +/* Generic 802.11 frame constants */ +#define DOT11_A3_HDR_LEN 24 /* d11 header length with A3 */ +#define DOT11_A4_HDR_LEN 30 /* d11 header length with A4 */ +#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN /* MAC header length */ +#define DOT11_FCS_LEN 4 /* d11 FCS length */ +#define DOT11_ICV_LEN 4 /* d11 ICV length */ +#define DOT11_ICV_AES_LEN 8 /* d11 ICV/AES length */ +#define DOT11_QOS_LEN 2 /* d11 QoS length */ +#define DOT11_HTC_LEN 4 /* d11 HT Control field length */ + +#define DOT11_KEY_INDEX_SHIFT 6 /* d11 key index shift */ +#define DOT11_IV_LEN 4 /* d11 IV length */ +#define DOT11_IV_TKIP_LEN 8 /* d11 IV TKIP length */ +#define DOT11_IV_AES_OCB_LEN 4 /* d11 IV/AES/OCB length */ +#define DOT11_IV_AES_CCM_LEN 8 /* d11 IV/AES/CCM length */ +#define DOT11_IV_MAX_LEN 8 /* maximum iv len for any encryption */ + +/* Includes MIC */ +#define DOT11_MAX_MPDU_BODY_LEN 2304 /* max MPDU body length */ +/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */ +#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ + DOT11_QOS_LEN + \ + DOT11_IV_AES_CCM_LEN + \ + DOT11_MAX_MPDU_BODY_LEN + \ + DOT11_ICV_LEN + \ + DOT11_FCS_LEN) /* d11 max MPDU length */ + +#define DOT11_MAX_SSID_LEN 32 /* d11 max ssid length */ + +/* dot11RTSThreshold */ +#define DOT11_DEFAULT_RTS_LEN 2347 /* d11 default RTS length */ +#define DOT11_MAX_RTS_LEN 2347 /* d11 max RTS length */ + +/* dot11FragmentationThreshold */ +#define DOT11_MIN_FRAG_LEN 256 /* d11 min fragmentation length */ +#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength + * of the attached PHY + */ +#define DOT11_DEFAULT_FRAG_LEN 2346 /* d11 default fragmentation length */ + +/* dot11BeaconPeriod */ +#define DOT11_MIN_BEACON_PERIOD 1 /* d11 min beacon period */ +#define DOT11_MAX_BEACON_PERIOD 0xFFFF /* d11 max beacon period */ + +/* dot11DTIMPeriod */ +#define DOT11_MIN_DTIM_PERIOD 1 /* d11 min DTIM period */ +#define DOT11_MAX_DTIM_PERIOD 0xFF /* d11 max DTIM period */ + +/** 802.2 LLC/SNAP header used by 802.11 per 802.1H */ +#define DOT11_LLC_SNAP_HDR_LEN 8 /* d11 LLC/SNAP header length */ +#define DOT11_OUI_LEN 3 /* d11 OUI length */ +BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 type; /* ethertype */ +} BWL_POST_PACKED_STRUCT; + +/* RFC1042 header used by 802.11 per 802.1H */ +#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) /* RCF1042 header length */ + +/* Generic 802.11 MAC header */ +/** + * N.B.: This struct reflects the full 4 address 802.11 MAC header. + * The fields are defined such that the shorter 1, 2, and 3 + * address headers just use the first k fields. + */ +BWL_PRE_PACKED_STRUCT struct dot11_header { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr a1; /* address 1 */ + struct ether_addr a2; /* address 2 */ + struct ether_addr a3; /* address 3 */ + uint16 seq; /* sequence control */ + struct ether_addr a4; /* address 4 */ +} BWL_POST_PACKED_STRUCT; + +/* Control frames */ + +BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr ta; /* transmitter address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_RTS_LEN 16 /* d11 RTS frame length */ + +BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_CTS_LEN 10 /* d11 CTS frame length */ + +BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACK_LEN 10 /* d11 ACK frame length */ + +BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { + uint16 fc; /* frame control */ + uint16 durid; /* AID */ + struct ether_addr bssid; /* receiver address, STA in AP */ + struct ether_addr ta; /* transmitter address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_PS_POLL_LEN 16 /* d11 PS poll frame length */ + +BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr bssid; /* transmitter address, STA in AP */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */ + +/** + * RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling + * category+OUI+vendor specific content ( this can be variable) + */ +BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1040]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; + +/** generic vendor specific action frame with variable length */ +BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; + +#define DOT11_ACTION_VS_HDR_LEN 6 + +#define BCM_ACTION_OUI_BYTE0 0x00 +#define BCM_ACTION_OUI_BYTE1 0x90 +#define BCM_ACTION_OUI_BYTE2 0x4c + +/* BA/BAR Control parameters */ +#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */ +#define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */ +#define DOT11_BA_CTL_POLICY_MASK 0x0001 /* ack policy mask */ + +#define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */ +#define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */ + +#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */ +#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */ + +#define DOT11_BA_CTL_TID_MASK 0xF000 /* tid mask */ +#define DOT11_BA_CTL_TID_SHIFT 12 /* tid shift */ + +/** control frame header (BA/BAR) */ +BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr ta; /* transmitter address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */ + +/** BAR frame payload */ +BWL_PRE_PACKED_STRUCT struct dot11_bar { + uint16 bar_control; /* BAR Control */ + uint16 seqnum; /* Starting Sequence control */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_BAR_LEN 4 /* BAR frame payload length */ + +#define DOT11_BA_BITMAP_LEN 128 /* bitmap length */ +#define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */ +/** BA frame payload */ +BWL_PRE_PACKED_STRUCT struct dot11_ba { + uint16 ba_control; /* BA Control */ + uint16 seqnum; /* Starting Sequence control */ + uint8 bitmap[DOT11_BA_BITMAP_LEN]; /* Block Ack Bitmap */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_BA_LEN 4 /* BA frame payload len (wo bitmap) */ + +/** Management frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_management_header { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr da; /* receiver address */ + struct ether_addr sa; /* transmitter address */ + struct ether_addr bssid; /* BSS ID */ + uint16 seq; /* sequence control */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_MGMT_HDR_LEN 24 /* d11 management header length */ + +/* Management frame payloads */ + +BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { + uint32 timestamp[2]; + uint16 beacon_interval; + uint16 capability; +} BWL_POST_PACKED_STRUCT; +#define DOT11_BCN_PRB_LEN 12 /* 802.11 beacon/probe frame fixed length */ +#define DOT11_BCN_PRB_FIXED_LEN 12 /* 802.11 beacon/probe frame fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_auth { + uint16 alg; /* algorithm */ + uint16 seq; /* sequence control */ + uint16 status; /* status code */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge IE */ + +BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { + uint16 capability; /* capability information */ + uint16 listen; /* listen interval */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_ASSOC_REQ_FIXED_LEN 4 /* length of assoc frame without info elts */ + +BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { + uint16 capability; /* capability information */ + uint16 listen; /* listen interval */ + struct ether_addr ap; /* Current AP address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_REASSOC_REQ_FIXED_LEN 10 /* length of assoc frame without info elts */ + +BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { + uint16 capability; /* capability information */ + uint16 status; /* status code */ + uint16 aid; /* association ID */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_ASSOC_RESP_FIXED_LEN 6 /* length of assoc resp frame without info elts */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_measure { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { + uint8 category; + uint8 action; + uint8 ch_width; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { + uint8 category; + uint8 action; + uint8 control; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { + uint8 category; + uint8 action; + uint16 id; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { + uint8 category; + uint8 action; + uint8 mode; +} BWL_POST_PACKED_STRUCT; + +#define SM_PWRSAVE_ENABLE 1 +#define SM_PWRSAVE_MODE 2 + +/* ************* 802.11h related definitions. ************* */ +BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { + uint8 id; + uint8 len; + uint8 power; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_power_cnst dot11_power_cnst_t; + +BWL_PRE_PACKED_STRUCT struct dot11_power_cap { + int8 min; + int8 max; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_power_cap dot11_power_cap_t; + +BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { + uint8 id; + uint8 len; + uint8 tx_pwr; + uint8 margin; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tpc_rep dot11_tpc_rep_t; +#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */ + +BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { + uint8 id; + uint8 len; + uint8 first_channel; + uint8 num_channels; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_supp_channels dot11_supp_channels_t; + +/** + * Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband + * offset for 40MHz operation. The possible 3 values are: + * 1 = above control channel + * 3 = below control channel + * 0 = no extension channel + */ +BWL_PRE_PACKED_STRUCT struct dot11_extch { + uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ + uint8 len; /* IE length */ + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extch dot11_extch_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; + uint8 type; /* type indicates what follows */ + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; + +#define BRCM_EXTCH_IE_LEN 5 +#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ +#define DOT11_EXTCH_IE_LEN 1 +#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ +#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ +#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ +#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { + uint8 category; + uint8 action; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACTION_FRMHDR_LEN 2 + +/** CSA IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { + uint8 id; /* id DOT11_MNG_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 mode; /* mode 0 or 1 */ + uint8 channel; /* channel switch to */ + uint8 count; /* number of beacons before switching */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch dot11_chan_switch_ie_t; + +#define DOT11_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ +/* CSA mode - 802.11h-2003 $7.3.2.20 */ +#define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */ +#define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { + uint8 category; + uint8 action; + dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */ + dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */ +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_csa_body { + uint8 mode; /* mode 0 or 1 */ + uint8 reg; /* regulatory class */ + uint8 channel; /* channel switch to */ + uint8 count; /* number of beacons before switching */ +} BWL_POST_PACKED_STRUCT; + +/** 11n Extended Channel Switch IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { + uint8 id; /* id DOT11_MNG_EXT_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + struct dot11_csa_body b; /* body of the ie */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ext_csa dot11_ext_csa_ie_t; +#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { + uint8 category; + uint8 action; + dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { + uint8 category; + uint8 action; + struct dot11_csa_body b; /* body of the ie */ +} BWL_POST_PACKED_STRUCT; + +/** Wide Bandwidth Channel Switch IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 channel_width; /* new channel width */ + uint8 center_frequency_segment_0; /* center frequency segment 0 */ + uint8 center_frequency_segment_1; /* center frequency segment 1 */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; + +#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ + +/** Channel Switch Wrapper IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; + +/** VHT Transmit Power Envelope IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 transmit_power_info; + uint8 local_max_transmit_power_20; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; + +/* vht transmit power envelope IE length depends on channel width */ +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_40MHZ 1 +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_80MHZ 2 +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_160MHZ 3 + +BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { + uint8 id; + uint8 len; + uint8 info; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_coex dot11_obss_coex_t; +#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */ + +#define DOT11_OBSS_COEX_INFO_REQ 0x01 +#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 +#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 + +BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { + uint8 id; + uint8 len; + uint8 regclass; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; +#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */ + +BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { + uint8 id; + uint8 len; + uint8 cap[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extcap_ie dot11_extcap_ie_t; + +#define DOT11_EXTCAP_LEN_MAX 8 + +#define DOT11_EXTCAP_LEN_COEX 1 +#define DOT11_EXTCAP_LEN_BT 3 +#define DOT11_EXTCAP_LEN_IW 4 +#define DOT11_EXTCAP_LEN_SI 6 + +#define DOT11_EXTCAP_LEN_TDLS 5 +#define DOT11_11AC_EXTCAP_LEN_TDLS 8 + +#define DOT11_EXTCAP_LEN_FMS 2 +#define DOT11_EXTCAP_LEN_PROXY_ARP 2 +#define DOT11_EXTCAP_LEN_TFS 3 +#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 +#define DOT11_EXTCAP_LEN_TIMBC 3 +#define DOT11_EXTCAP_LEN_BSSTRANS 3 +#define DOT11_EXTCAP_LEN_DMS 4 +#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 +#define DOT11_EXTCAP_LEN_TDLS_WBW 8 +#define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8 + +BWL_PRE_PACKED_STRUCT struct dot11_extcap { + uint8 extcap[DOT11_EXTCAP_LEN_MAX]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extcap dot11_extcap_t; + +/* TDLS Capabilities */ +#define DOT11_TDLS_CAP_TDLS 37 /* TDLS support */ +#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ +#define DOT11_TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ +#define DOT11_TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ +#define DOT11_TDLS_CAP_PROH 38 /* TDLS prohibited */ +#define DOT11_TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ +#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 /* TDLS Wider Band-Width */ + +#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ + +/* 802.11h/802.11k Measurement Request/Report IEs */ +/* Measurement Type field */ +#define DOT11_MEASURE_TYPE_BASIC 0 /* d11 measurement basic type */ +#define DOT11_MEASURE_TYPE_CCA 1 /* d11 measurement CCA type */ +#define DOT11_MEASURE_TYPE_RPI 2 /* d11 measurement RPI type */ +#define DOT11_MEASURE_TYPE_CHLOAD 3 /* d11 measurement Channel Load type */ +#define DOT11_MEASURE_TYPE_NOISE 4 /* d11 measurement Noise Histogram type */ +#define DOT11_MEASURE_TYPE_BEACON 5 /* d11 measurement Beacon type */ +#define DOT11_MEASURE_TYPE_FRAME 6 /* d11 measurement Frame type */ +#define DOT11_MEASURE_TYPE_STAT 7 /* d11 measurement STA Statistics type */ +#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ +#define DOT11_MEASURE_TYPE_TXSTREAM 9 /* d11 measurement TX Stream type */ +#define DOT11_MEASURE_TYPE_PAUSE 255 /* d11 measurement pause type */ + +/* Measurement Request Modes */ +#define DOT11_MEASURE_MODE_PARALLEL (1<<0) /* d11 measurement parallel */ +#define DOT11_MEASURE_MODE_ENABLE (1<<1) /* d11 measurement enable */ +#define DOT11_MEASURE_MODE_REQUEST (1<<2) /* d11 measurement request */ +#define DOT11_MEASURE_MODE_REPORT (1<<3) /* d11 measurement report */ +#define DOT11_MEASURE_MODE_DUR (1<<4) /* d11 measurement dur mandatory */ +/* Measurement Report Modes */ +#define DOT11_MEASURE_MODE_LATE (1<<0) /* d11 measurement late */ +#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) /* d11 measurement incapable */ +#define DOT11_MEASURE_MODE_REFUSED (1<<2) /* d11 measurement refuse */ +/* Basic Measurement Map bits */ +#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) /* d11 measurement basic map BSS */ +#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) /* d11 measurement map OFDM */ +#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) /* d11 measurement map unknown */ +#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) /* d11 measurement map radar */ +#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) /* d11 measurement map unmeasuremnt */ + +BWL_PRE_PACKED_STRUCT struct dot11_meas_req { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 channel; + uint8 start_time[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_req dot11_meas_req_t; +#define DOT11_MNG_IE_MREQ_LEN 14 /* d11 measurement request IE length */ +/* length of Measure Request IE data not including variable len */ +#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 /* d11 measurement request IE fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + BWL_PRE_PACKED_STRUCT union + { + BWL_PRE_PACKED_STRUCT struct { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; + } BWL_POST_PACKED_STRUCT basic; + uint8 data[1]; + } BWL_POST_PACKED_STRUCT rep; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_rep dot11_meas_rep_t; + +/* length of Measure Report IE data not including variable len */ +#define DOT11_MNG_IE_MREP_FIXED_LEN 3 /* d11 measurement response IE fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; +#define DOT11_MEASURE_BASIC_REP_LEN 12 /* d11 measurement basic report length */ + +BWL_PRE_PACKED_STRUCT struct dot11_quiet { + uint8 id; + uint8 len; + uint8 count; /* TBTTs until beacon interval in quiet starts */ + uint8 period; /* Beacon intervals between periodic quiet periods ? */ + uint16 duration; /* Length of quiet period, in TU's */ + uint16 offset; /* TU's offset from TBTT in Count field */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_quiet dot11_quiet_t; + +BWL_PRE_PACKED_STRUCT struct chan_map_tuple { + uint8 channel; + uint8 map; +} BWL_POST_PACKED_STRUCT; +typedef struct chan_map_tuple chan_map_tuple_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { + uint8 id; + uint8 len; + uint8 eaddr[ETHER_ADDR_LEN]; + uint8 interval; + chan_map_tuple_t map[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; + +/* WME Elements */ +#define WME_OUI "\x00\x50\xf2" /* WME OUI */ +#define WME_OUI_LEN 3 +#define WME_OUI_TYPE 2 /* WME type */ +#define WME_TYPE 2 /* WME type, deprecated */ +#define WME_SUBTYPE_IE 0 /* Information Element */ +#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ +#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ +#define WME_VER 1 /* WME version */ + +/* WME Access Category Indices (ACIs) */ +#define AC_BE 0 /* Best Effort */ +#define AC_BK 1 /* Background */ +#define AC_VI 2 /* Video */ +#define AC_VO 3 /* Voice */ +#define AC_COUNT 4 /* number of ACs */ + +typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */ + +#define AC_BITMAP_NONE 0x0 /* No ACs */ +#define AC_BITMAP_ALL 0xf /* All ACs */ +#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) +#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) +#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) + +/** WME Information Element (IE) */ +BWL_PRE_PACKED_STRUCT struct wme_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_ie wme_ie_t; +#define WME_IE_LEN 7 /* WME IE length */ + +BWL_PRE_PACKED_STRUCT struct edcf_acparam { + uint8 ACI; + uint8 ECW; + uint16 TXOP; /* stored in network order (ls octet first) */ +} BWL_POST_PACKED_STRUCT; +typedef struct edcf_acparam edcf_acparam_t; + +/** WME Parameter Element (PE) */ +BWL_PRE_PACKED_STRUCT struct wme_param_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_param_ie wme_param_ie_t; +#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ + +/* QoS Info field for IE as sent from AP */ +#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ +#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ +#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ +#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ + +/* QoS Info field for IE as sent from STA */ +#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ +#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ +#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ +#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ +#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ +#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ +#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ +#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ +#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ +#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ +#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ +#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ + +/* ACI */ +#define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */ +#define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */ +#define EDCF_AIFSN_MASK 0x0f /* AIFSN mask */ +#define EDCF_ACM_MASK 0x10 /* ACM mask */ +#define EDCF_ACI_MASK 0x60 /* ACI mask */ +#define EDCF_ACI_SHIFT 5 /* ACI shift */ +#define EDCF_AIFSN_SHIFT 12 /* 4 MSB(0xFFF) in ifs_ctl for AC idx */ + +/* ECW */ +#define EDCF_ECW_MIN 0 /* cwmin/cwmax exponent minimum value */ +#define EDCF_ECW_MAX 15 /* cwmin/cwmax exponent maximum value */ +#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) +#define EDCF_ECWMIN_MASK 0x0f /* cwmin exponent form mask */ +#define EDCF_ECWMAX_MASK 0xf0 /* cwmax exponent form mask */ +#define EDCF_ECWMAX_SHIFT 4 /* cwmax exponent form shift */ + +/* TXOP */ +#define EDCF_TXOP_MIN 0 /* TXOP minimum value */ +#define EDCF_TXOP_MAX 65535 /* TXOP maximum value */ +#define EDCF_TXOP2USEC(txop) ((txop) << 5) + +/* Default BE ACI value for non-WME connection STA */ +#define NON_EDCF_AC_BE_ACI_STA 0x02 + +/* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */ +#define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */ +#define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */ +#define EDCF_AC_BE_TXOP_STA 0x0000 /* STA TXOP value for best effort AC */ +#define EDCF_AC_BK_ACI_STA 0x27 /* STA ACI value for background AC */ +#define EDCF_AC_BK_ECW_STA 0xA4 /* STA ECW value for background AC */ +#define EDCF_AC_BK_TXOP_STA 0x0000 /* STA TXOP value for background AC */ +#define EDCF_AC_VI_ACI_STA 0x42 /* STA ACI value for video AC */ +#define EDCF_AC_VI_ECW_STA 0x43 /* STA ECW value for video AC */ +#define EDCF_AC_VI_TXOP_STA 0x005e /* STA TXOP value for video AC */ +#define EDCF_AC_VO_ACI_STA 0x62 /* STA ACI value for audio AC */ +#define EDCF_AC_VO_ECW_STA 0x32 /* STA ECW value for audio AC */ +#define EDCF_AC_VO_TXOP_STA 0x002f /* STA TXOP value for audio AC */ + +/* Default EDCF parameters that AP uses; WMM draft Table 14 */ +#define EDCF_AC_BE_ACI_AP 0x03 /* AP ACI value for best effort AC */ +#define EDCF_AC_BE_ECW_AP 0x64 /* AP ECW value for best effort AC */ +#define EDCF_AC_BE_TXOP_AP 0x0000 /* AP TXOP value for best effort AC */ +#define EDCF_AC_BK_ACI_AP 0x27 /* AP ACI value for background AC */ +#define EDCF_AC_BK_ECW_AP 0xA4 /* AP ECW value for background AC */ +#define EDCF_AC_BK_TXOP_AP 0x0000 /* AP TXOP value for background AC */ +#define EDCF_AC_VI_ACI_AP 0x41 /* AP ACI value for video AC */ +#define EDCF_AC_VI_ECW_AP 0x43 /* AP ECW value for video AC */ +#define EDCF_AC_VI_TXOP_AP 0x005e /* AP TXOP value for video AC */ +#define EDCF_AC_VO_ACI_AP 0x61 /* AP ACI value for audio AC */ +#define EDCF_AC_VO_ECW_AP 0x32 /* AP ECW value for audio AC */ +#define EDCF_AC_VO_TXOP_AP 0x002f /* AP TXOP value for audio AC */ + +/** EDCA Parameter IE */ +BWL_PRE_PACKED_STRUCT struct edca_param_ie { + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} BWL_POST_PACKED_STRUCT; +typedef struct edca_param_ie edca_param_ie_t; +#define EDCA_PARAM_IE_LEN 18 /* EDCA Parameter IE length */ + +/** QoS Capability IE */ +BWL_PRE_PACKED_STRUCT struct qos_cap_ie { + uint8 qosinfo; +} BWL_POST_PACKED_STRUCT; +typedef struct qos_cap_ie qos_cap_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { + uint8 id; /* 11, DOT11_MNG_QBSS_LOAD_ID */ + uint8 length; + uint16 station_count; /* total number of STAs associated */ + uint8 channel_utilization; /* % of time, normalized to 255, QAP sensed medium busy */ + uint16 aac; /* available admission capacity */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; +#define BSS_LOAD_IE_SIZE 7 /* BSS load IE size */ + +#define WLC_QBSS_LOAD_CHAN_FREE_MAX 0xff /* max for channel free score */ + +/* nom_msdu_size */ +#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */ +#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */ + +/* surplus_bandwidth */ +/* Represented as 3 bits of integer, binary point, 13 bits fraction */ +#define INTEGER_SHIFT 13 /* integer shift */ +#define FRACTION_MASK 0x1FFF /* fraction mask */ + +/** Management Notification Frame */ +BWL_PRE_PACKED_STRUCT struct dot11_management_notification { + uint8 category; /* DOT11_ACTION_NOTIFICATION */ + uint8 action; + uint8 token; + uint8 status; + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */ + +/** Timeout Interval IE */ +BWL_PRE_PACKED_STRUCT struct ti_ie { + uint8 ti_type; + uint32 ti_val; +} BWL_POST_PACKED_STRUCT; +typedef struct ti_ie ti_ie_t; +#define TI_TYPE_REASSOC_DEADLINE 1 +#define TI_TYPE_KEY_LIFETIME 2 + +/* WME Action Codes */ +#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ +#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ +#define WME_DELTS_REQUEST 2 /* WME DELTS request */ + +/* WME Setup Response Status Codes */ +#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ +#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ +#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ + +/* Macro to take a pointer to a beacon or probe response + * body and return the char* pointer to the SSID info element + */ +#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) + +/* Authentication frame payload constants */ +#define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */ +#define DOT11_SHARED_KEY 1 /* d11 shared authentication */ +#define DOT11_FAST_BSS 2 /* d11 fast bss authentication */ +#define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */ + +/* Frame control macros */ +#define FC_PVER_MASK 0x3 /* PVER mask */ +#define FC_PVER_SHIFT 0 /* PVER shift */ +#define FC_TYPE_MASK 0xC /* type mask */ +#define FC_TYPE_SHIFT 2 /* type shift */ +#define FC_SUBTYPE_MASK 0xF0 /* subtype mask */ +#define FC_SUBTYPE_SHIFT 4 /* subtype shift */ +#define FC_TODS 0x100 /* to DS */ +#define FC_TODS_SHIFT 8 /* to DS shift */ +#define FC_FROMDS 0x200 /* from DS */ +#define FC_FROMDS_SHIFT 9 /* from DS shift */ +#define FC_MOREFRAG 0x400 /* more frag. */ +#define FC_MOREFRAG_SHIFT 10 /* more frag. shift */ +#define FC_RETRY 0x800 /* retry */ +#define FC_RETRY_SHIFT 11 /* retry shift */ +#define FC_PM 0x1000 /* PM */ +#define FC_PM_SHIFT 12 /* PM shift */ +#define FC_MOREDATA 0x2000 /* more data */ +#define FC_MOREDATA_SHIFT 13 /* more data shift */ +#define FC_WEP 0x4000 /* WEP */ +#define FC_WEP_SHIFT 14 /* WEP shift */ +#define FC_ORDER 0x8000 /* order */ +#define FC_ORDER_SHIFT 15 /* order shift */ + +/* sequence control macros */ +#define SEQNUM_SHIFT 4 /* seq. number shift */ +#define SEQNUM_MAX 0x1000 /* max seqnum + 1 */ +#define FRAGNUM_MASK 0xF /* frag. number mask */ + +/* Frame Control type/subtype defs */ + +/* FC Types */ +#define FC_TYPE_MNG 0 /* management type */ +#define FC_TYPE_CTL 1 /* control type */ +#define FC_TYPE_DATA 2 /* data type */ + +/* Management Subtypes */ +#define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */ +#define FC_SUBTYPE_ASSOC_RESP 1 /* assoc. response */ +#define FC_SUBTYPE_REASSOC_REQ 2 /* reassoc. request */ +#define FC_SUBTYPE_REASSOC_RESP 3 /* reassoc. response */ +#define FC_SUBTYPE_PROBE_REQ 4 /* probe request */ +#define FC_SUBTYPE_PROBE_RESP 5 /* probe response */ +#define FC_SUBTYPE_BEACON 8 /* beacon */ +#define FC_SUBTYPE_ATIM 9 /* ATIM */ +#define FC_SUBTYPE_DISASSOC 10 /* disassoc. */ +#define FC_SUBTYPE_AUTH 11 /* authentication */ +#define FC_SUBTYPE_DEAUTH 12 /* de-authentication */ +#define FC_SUBTYPE_ACTION 13 /* action */ +#define FC_SUBTYPE_ACTION_NOACK 14 /* action no-ack */ + +/* Control Subtypes */ +#define FC_SUBTYPE_CTL_WRAPPER 7 /* Control Wrapper */ +#define FC_SUBTYPE_BLOCKACK_REQ 8 /* Block Ack Req */ +#define FC_SUBTYPE_BLOCKACK 9 /* Block Ack */ +#define FC_SUBTYPE_PS_POLL 10 /* PS poll */ +#define FC_SUBTYPE_RTS 11 /* RTS */ +#define FC_SUBTYPE_CTS 12 /* CTS */ +#define FC_SUBTYPE_ACK 13 /* ACK */ +#define FC_SUBTYPE_CF_END 14 /* CF-END */ +#define FC_SUBTYPE_CF_END_ACK 15 /* CF-END ACK */ + +/* Data Subtypes */ +#define FC_SUBTYPE_DATA 0 /* Data */ +#define FC_SUBTYPE_DATA_CF_ACK 1 /* Data + CF-ACK */ +#define FC_SUBTYPE_DATA_CF_POLL 2 /* Data + CF-Poll */ +#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 /* Data + CF-Ack + CF-Poll */ +#define FC_SUBTYPE_NULL 4 /* Null */ +#define FC_SUBTYPE_CF_ACK 5 /* CF-Ack */ +#define FC_SUBTYPE_CF_POLL 6 /* CF-Poll */ +#define FC_SUBTYPE_CF_ACK_POLL 7 /* CF-Ack + CF-Poll */ +#define FC_SUBTYPE_QOS_DATA 8 /* QoS Data */ +#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 /* QoS Data + CF-Ack */ +#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 /* QoS Data + CF-Poll */ +#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 /* QoS Data + CF-Ack + CF-Poll */ +#define FC_SUBTYPE_QOS_NULL 12 /* QoS Null */ +#define FC_SUBTYPE_QOS_CF_POLL 14 /* QoS CF-Poll */ +#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 /* QoS CF-Ack + CF-Poll */ + +/* Data Subtype Groups */ +#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) +#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) +#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) +#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) +#define FC_SUBTYPE_ANY_PSPOLL(s) (((s) & 10) != 0) + +/* Type/Subtype Combos */ +#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */ + +#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) /* FC kind */ + +#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) /* Subtype from FC */ +#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) /* Type from FC */ + +#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) /* assoc. request */ +#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) /* assoc. response */ +#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) /* reassoc. request */ +#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) /* reassoc. response */ +#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) /* probe request */ +#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) /* probe response */ +#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) /* beacon */ +#define FC_ATIM FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ATIM) /* ATIM */ +#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) /* disassoc */ +#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) /* authentication */ +#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) /* deauthentication */ +#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) /* action */ +#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) /* action no-ack */ + +#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) /* Control Wrapper */ +#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) /* Block Ack Req */ +#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) /* Block Ack */ +#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) /* PS poll */ +#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) /* RTS */ +#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) /* CTS */ +#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) /* ACK */ +#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) /* CF-END */ +#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) /* CF-END ACK */ + +#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) /* data */ +#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) /* null data */ +#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) /* data CF ACK */ +#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) /* QoS data */ +#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) /* QoS null */ + +/* QoS Control Field */ + +/* 802.1D Priority */ +#define QOS_PRIO_SHIFT 0 /* QoS priority shift */ +#define QOS_PRIO_MASK 0x0007 /* QoS priority mask */ +#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) /* QoS priority */ + +/* Traffic Identifier */ +#define QOS_TID_SHIFT 0 /* QoS TID shift */ +#define QOS_TID_MASK 0x000f /* QoS TID mask */ +#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) /* QoS TID */ + +/* End of Service Period (U-APSD) */ +#define QOS_EOSP_SHIFT 4 /* QoS End of Service Period shift */ +#define QOS_EOSP_MASK 0x0010 /* QoS End of Service Period mask */ +#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) /* Qos EOSP */ + +/* Ack Policy */ +#define QOS_ACK_NORMAL_ACK 0 /* Normal Ack */ +#define QOS_ACK_NO_ACK 1 /* No Ack (eg mcast) */ +#define QOS_ACK_NO_EXP_ACK 2 /* No Explicit Ack */ +#define QOS_ACK_BLOCK_ACK 3 /* Block Ack */ +#define QOS_ACK_SHIFT 5 /* QoS ACK shift */ +#define QOS_ACK_MASK 0x0060 /* QoS ACK mask */ +#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) /* QoS ACK */ + +/* A-MSDU flag */ +#define QOS_AMSDU_SHIFT 7 /* AMSDU shift */ +#define QOS_AMSDU_MASK 0x0080 /* AMSDU mask */ + +/* Management Frames */ + +/* Management Frame Constants */ + +/* Fixed fields */ +#define DOT11_MNG_AUTH_ALGO_LEN 2 /* d11 management auth. algo. length */ +#define DOT11_MNG_AUTH_SEQ_LEN 2 /* d11 management auth. seq. length */ +#define DOT11_MNG_BEACON_INT_LEN 2 /* d11 management beacon interval length */ +#define DOT11_MNG_CAP_LEN 2 /* d11 management cap. length */ +#define DOT11_MNG_AP_ADDR_LEN 6 /* d11 management AP address length */ +#define DOT11_MNG_LISTEN_INT_LEN 2 /* d11 management listen interval length */ +#define DOT11_MNG_REASON_LEN 2 /* d11 management reason length */ +#define DOT11_MNG_AID_LEN 2 /* d11 management AID length */ +#define DOT11_MNG_STATUS_LEN 2 /* d11 management status length */ +#define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */ + +/* DUR/ID field in assoc resp is 0xc000 | AID */ +#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ + +/* Reason Codes */ +#define DOT11_RC_RESERVED 0 /* d11 RC reserved */ +#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */ +#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */ +#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station + * is leaving (or has left) IBSS or ESS + */ +#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */ +#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle + * all currently associated stations + */ +#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from + * nonauthenticated station + */ +#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from + * nonassociated station + */ +#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is + * leaving (or has left) BSS + */ +#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is not + * authenticated with responding station + */ +#define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */ +#define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */ +/* 12 is unused */ + +/* 32-39 are QSTA specific reasons added in 11e */ +#define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */ +#define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */ +#define DOT11_RC_EXCESSIVE_FRAMES 34 /* excessive number of frames need ack */ +#define DOT11_RC_TX_OUTSIDE_TXOP 35 /* transmitting outside the limits of txop */ +#define DOT11_RC_LEAVING_QBSS 36 /* QSTA is leaving the QBSS (or restting) */ +#define DOT11_RC_BAD_MECHANISM 37 /* does not want to use the mechanism */ +#define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */ +#define DOT11_RC_TIMEOUT 39 /* timeout */ + +#define DOT11_RC_MAX 23 /* Reason codes > 23 are reserved */ + +#define DOT11_RC_TDLS_PEER_UNREACH 25 +#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 + +/* Status Codes */ +#define DOT11_SC_SUCCESS 0 /* Successful */ +#define DOT11_SC_FAILURE 1 /* Unspecified failure */ +#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but alternative */ + /* schedule provided */ +#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */ +#define DOT11_SC_TDLS_SEC_DISABLED 5 /* TDLS Security disabled */ +#define DOT11_SC_LIFETIME_REJ 6 /* Unacceptable lifetime */ +#define DOT11_SC_NOT_SAME_BSS 7 /* Not in same BSS */ +#define DOT11_SC_CAP_MISMATCH 10 /* Cannot support all requested + * capabilities in the Capability + * Information field + */ +#define DOT11_SC_REASSOC_FAIL 11 /* Reassociation denied due to inability + * to confirm that association exists + */ +#define DOT11_SC_ASSOC_FAIL 12 /* Association denied due to reason + * outside the scope of this standard + */ +#define DOT11_SC_AUTH_MISMATCH 13 /* Responding station does not support + * the specified authentication + * algorithm + */ +#define DOT11_SC_AUTH_SEQ 14 /* Received an Authentication frame + * with authentication transaction + * sequence number out of expected + * sequence + */ +#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of + * challenge failure + */ +#define DOT11_SC_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout + * waiting for next frame in sequence + */ +#define DOT11_SC_ASSOC_BUSY_FAIL 17 /* Association denied because AP is + * unable to handle additional + * associated stations + */ +#define DOT11_SC_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting + * station not supporting all of the + * data rates in the BSSBasicRateSet + * parameter + */ +#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting + * station not supporting the Short + * Preamble option + */ +#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting + * station not supporting the PBCC + * Modulation option + */ +#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting + * station not supporting the Channel + * Agility option + */ +#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum + * Management capability is required. + */ +#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info + * in the Power Cap element is + * unacceptable. + */ +#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info + * in the Supported Channel element is + * unacceptable + */ +#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting + * station not supporting the Short Slot + * Time option + */ +#define DOT11_SC_ASSOC_DSSSOFDM_REQUIRED 26 /* Association denied because requesting station + * does not support the DSSS-OFDM option + */ +#define DOT11_SC_ASSOC_HT_REQUIRED 27 /* Association denied because the requesting + * station does not support HT features + */ +#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 /* Association denied due to AP + * being unable to reach the R0 Key Holder + */ +#define DOT11_SC_ASSOC_TRY_LATER 30 /* Association denied temporarily, try again later + */ +#define DOT11_SC_ASSOC_MFP_VIOLATION 31 /* Association denied due to Robust Management + * frame policy violation + */ + +#define DOT11_SC_DECLINED 37 /* request declined */ +#define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ +#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */ +#define DOT11_SC_INVALID_AKMP 43 /* Association denied due to invalid AKMP */ +#define DOT11_SC_INVALID_RSNIE_CAP 45 /* invalid RSN IE capabilities */ +#define DOT11_SC_DLS_NOT_ALLOWED 48 /* DLS is not allowed in the BSS by policy */ +#define DOT11_SC_INVALID_PMKID 53 /* Association denied due to invalid PMKID */ +#define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */ +#define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */ + +#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 /* ad proto not supported */ +#define DOT11_SC_NO_OUTSTAND_REQ 60 /* no outstanding req */ +#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 /* no response from server */ +#define DOT11_SC_TIMEOUT 62 /* timeout */ +#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 /* query rsp too large */ +#define DOT11_SC_SERVER_UNREACHABLE 65 /* server unreachable */ + +#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ +#define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */ +#define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */ +#define DOT11_SC_ASSOC_VHT_REQUIRED 104 /* Association denied because the requesting + * station does not support VHT features. + */ + +#define DOT11_SC_TRANSMIT_FAILURE 79 /* transmission failure */ + +/* Info Elts, length of INFORMATION portion of Info Elts */ +#define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ +#define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */ + +/* TIM Info element has 3 bytes fixed info in INFORMATION field, + * followed by 1 to 251 bytes of Partial Virtual Bitmap + */ +#define DOT11_MNG_TIM_FIXED_LEN 3 /* d11 management TIM fixed length */ +#define DOT11_MNG_TIM_DTIM_COUNT 0 /* d11 management DTIM count */ +#define DOT11_MNG_TIM_DTIM_PERIOD 1 /* d11 management DTIM period */ +#define DOT11_MNG_TIM_BITMAP_CTL 2 /* d11 management TIM BITMAP control */ +#define DOT11_MNG_TIM_PVB 3 /* d11 management TIM PVB */ + +/* TLV defines */ +#define TLV_TAG_OFF 0 /* tag offset */ +#define TLV_LEN_OFF 1 /* length offset */ +#define TLV_HDR_LEN 2 /* header length */ +#define TLV_BODY_OFF 2 /* body offset */ +#define TLV_BODY_LEN_MAX 255 /* max body length */ + +/* Management Frame Information Element IDs */ +#define DOT11_MNG_SSID_ID 0 /* d11 management SSID id */ +#define DOT11_MNG_RATES_ID 1 /* d11 management rates id */ +#define DOT11_MNG_FH_PARMS_ID 2 /* d11 management FH parameter id */ +#define DOT11_MNG_DS_PARMS_ID 3 /* d11 management DS parameter id */ +#define DOT11_MNG_CF_PARMS_ID 4 /* d11 management CF parameter id */ +#define DOT11_MNG_TIM_ID 5 /* d11 management TIM id */ +#define DOT11_MNG_IBSS_PARMS_ID 6 /* d11 management IBSS parameter id */ +#define DOT11_MNG_COUNTRY_ID 7 /* d11 management country id */ +#define DOT11_MNG_HOPPING_PARMS_ID 8 /* d11 management hopping parameter id */ +#define DOT11_MNG_HOPPING_TABLE_ID 9 /* d11 management hopping table id */ +#define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */ +#define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */ +#define DOT11_MNG_EDCA_PARAM_ID 12 /* 11E EDCA Parameter id */ +#define DOT11_MNG_TSPEC_ID 13 /* d11 management TSPEC id */ +#define DOT11_MNG_TCLAS_ID 14 /* d11 management TCLAS id */ +#define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */ +#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */ +#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */ +#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */ +#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */ +#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */ +#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement */ +#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ +#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */ +#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */ +#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */ +#define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */ +#define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */ +#define DOT11_MNG_TCLAS_PROC_ID 44 /* d11 management TCLAS processing id */ +#define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */ +#define DOT11_MNG_QOS_CAP_ID 46 /* 11E QoS Capability id */ +#define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */ +#define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */ +#define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */ +#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */ +#define DOT11_MNG_NEIGHBOR_REP_ID 52 /* 11k & 11v Neighbor report id */ +#define DOT11_MNG_RCPI_ID 53 /* 11k RCPI */ +#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */ +#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */ +#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */ +#define DOT11_MNG_RDE_ID 57 /* 11r RIC Data Element id */ +#define DOT11_MNG_REGCLASS_ID 59 /* d11 management regulatory class id */ +#define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */ +#define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */ +#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */ +#define DOT11_MNG_BSS_AVR_ACCESS_DELAY_ID 63 /* 11k bss average access delay */ +#define DOT11_MNG_ANTENNA_ID 64 /* 11k antenna id */ +#define DOT11_MNG_RSNI_ID 65 /* 11k RSNI id */ +#define DOT11_MNG_MEASUREMENT_PILOT_TX_ID 66 /* 11k measurement pilot tx info id */ +#define DOT11_MNG_BSS_AVAL_ADMISSION_CAP_ID 67 /* 11k bss aval admission cap id */ +#define DOT11_MNG_BSS_AC_ACCESS_DELAY_ID 68 /* 11k bss AC access delay id */ +#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ +#define DOT11_MNG_TIME_ADVERTISE_ID 69 /* 11p time advertisement */ +#define DOT11_MNG_RRM_CAP_ID 70 /* 11k radio measurement capability */ +#define DOT11_MNG_MULTIPLE_BSSID_ID 71 /* 11k multiple BSSID id */ +#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 /* d11 mgmt OBSS Coexistence INFO */ +#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 /* d11 mgmt OBSS Intolerant Channel list */ +#define DOT11_MNG_HT_OBSS_ID 74 /* d11 mgmt OBSS HT info */ +#define DOT11_MNG_MMIE_ID 76 /* d11 mgmt MIC IE */ +#define DOT11_MNG_FMS_DESCR_ID 86 /* 11v FMS descriptor */ +#define DOT11_MNG_FMS_REQ_ID 87 /* 11v FMS request id */ +#define DOT11_MNG_FMS_RESP_ID 88 /* 11v FMS response id */ +#define DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID 90 /* 11v bss max idle id */ +#define DOT11_MNG_TFS_REQUEST_ID 91 /* 11v tfs request id */ +#define DOT11_MNG_TFS_RESPONSE_ID 92 /* 11v tfs response id */ +#define DOT11_MNG_WNM_SLEEP_MODE_ID 93 /* 11v wnm-sleep mode id */ +#define DOT11_MNG_TIMBC_REQ_ID 94 /* 11v TIM broadcast request id */ +#define DOT11_MNG_TIMBC_RESP_ID 95 /* 11v TIM broadcast response id */ +#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */ +#define DOT11_MNG_TIME_ZONE_ID 98 /* 11v time zone */ +#define DOT11_MNG_DMS_REQUEST_ID 99 /* 11v dms request id */ +#define DOT11_MNG_DMS_RESPONSE_ID 100 /* 11v dms response id */ +#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */ +#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */ +#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */ +#define DOT11_MNG_PTI_CONTROL_ID 105 /* 11z TDLS PTI Control IE */ +#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 /* 11z TDLS PU Buffer Status IE */ +#define DOT11_MNG_INTERWORKING_ID 107 /* 11u interworking */ +#define DOT11_MNG_ADVERTISEMENT_ID 108 /* 11u advertisement protocol */ +#define DOT11_MNG_EXP_BW_REQ_ID 109 /* 11u expedited bandwith request */ +#define DOT11_MNG_QOS_MAP_ID 110 /* 11u QoS map set */ +#define DOT11_MNG_ROAM_CONSORT_ID 111 /* 11u roaming consortium */ +#define DOT11_MNG_EMERGCY_ALERT_ID 112 /* 11u emergency alert identifier */ +#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */ +#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */ +#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */ +#define DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID 194 /* Wide BW Channel Switch IE */ +#define DOT11_MNG_VHT_TRANSMIT_POWER_ENVELOPE_ID 195 /* VHT transmit Power Envelope IE */ +#define DOT11_MNG_CHANNEL_SWITCH_WRAPPER_ID 196 /* Channel Switch Wrapper IE */ +#define DOT11_MNG_AID_ID 197 /* Association ID IE */ +#define DOT11_MNG_OPER_MODE_NOTIF_ID 199 /* d11 mgmt VHT oper mode notif */ + + +#define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */ +#define DOT11_MNG_PROPR_ID 221 +/* should start using this one instead of above two */ +#define DOT11_MNG_VS_ID 221 /* d11 management Vendor Specific IE */ + +/* Rate Defines */ + +/* Valid rates for the Supported Rates and Extended Supported Rates IEs. + * Encoding is the rate in 500kbps units, rouding up for fractional values. + * 802.11-2012, section 6.5.5.2, DATA_RATE parameter enumerates all the values. + * The rate values cover DSSS, HR/DSSS, ERP, and OFDM phy rates. + * The defines below do not cover the rates specific to 10MHz, {3, 4.5, 27}, + * and 5MHz, {1.5, 2.25, 3, 4.5, 13.5}, which are not supported by Broadcom devices. + */ + +#define DOT11_RATE_1M 2 /* 1 Mbps in 500kbps units */ +#define DOT11_RATE_2M 4 /* 2 Mbps in 500kbps units */ +#define DOT11_RATE_5M5 11 /* 5.5 Mbps in 500kbps units */ +#define DOT11_RATE_11M 22 /* 11 Mbps in 500kbps units */ +#define DOT11_RATE_6M 12 /* 6 Mbps in 500kbps units */ +#define DOT11_RATE_9M 18 /* 9 Mbps in 500kbps units */ +#define DOT11_RATE_12M 24 /* 12 Mbps in 500kbps units */ +#define DOT11_RATE_18M 36 /* 18 Mbps in 500kbps units */ +#define DOT11_RATE_24M 48 /* 24 Mbps in 500kbps units */ +#define DOT11_RATE_36M 72 /* 36 Mbps in 500kbps units */ +#define DOT11_RATE_48M 96 /* 48 Mbps in 500kbps units */ +#define DOT11_RATE_54M 108 /* 54 Mbps in 500kbps units */ +#define DOT11_RATE_MAX 108 /* highest rate (54 Mbps) in 500kbps units */ + +/* Supported Rates and Extended Supported Rates IEs + * The supported rates octets are defined a the MSB indicatin a Basic Rate + * and bits 0-6 as the rate value + */ +#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ +#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ + +/* BSS Membership Selector parameters + * 802.11-2012 and 802.11ac_D4.0 sec 8.4.2.3 + * These selector values are advertised in Supported Rates and Extended Supported Rates IEs + * in the supported rates list with the Basic rate bit set. + * Constants below include the basic bit. + */ +#define DOT11_BSS_MEMBERSHIP_HT 0xFF /* Basic 0x80 + 127, HT Required to join */ +#define DOT11_BSS_MEMBERSHIP_VHT 0xFE /* Basic 0x80 + 126, VHT Required to join */ + +/* ERP info element bit values */ +#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ +#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present + *in the BSS + */ +#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for + *ERP-OFDM frames + */ +#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, + * 1 == not allowed + */ +/* TS Delay element offset & size */ +#define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */ +#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ + +/* Capability Information Field */ +#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */ +#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */ +#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */ +#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */ +#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */ +#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */ +#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ +#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ +#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ +#define DOT11_CAP_QOS 0x0200 /* d11 cap. qos */ +#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ +#define DOT11_CAP_APSD 0x0800 /* d11 cap. apsd */ +#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ +#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ +#define DOT11_CAP_DELAY_BA 0x4000 /* d11 cap. delayed block ack */ +#define DOT11_CAP_IMMEDIATE_BA 0x8000 /* d11 cap. immediate block ack */ + +/* Extended capabilities IE bitfields */ +/* 20/40 BSS Coexistence Management support bit position */ +#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 +/* Extended Channel Switching support bit position */ +#define DOT11_EXT_CAP_EXT_CHAN_SWITCHING 2 +/* scheduled PSMP support bit position */ +#define DOT11_EXT_CAP_SPSMP 6 +/* Flexible Multicast Service */ +#define DOT11_EXT_CAP_FMS 11 +/* proxy ARP service support bit position */ +#define DOT11_EXT_CAP_PROXY_ARP 12 +/* Traffic Filter Service */ +#define DOT11_EXT_CAP_TFS 16 +/* WNM-Sleep Mode */ +#define DOT11_EXT_CAP_WNM_SLEEP 17 +/* TIM Broadcast service */ +#define DOT11_EXT_CAP_TIMBC 18 +/* BSS Transition Management support bit position */ +#define DOT11_EXT_CAP_BSSTRANS_MGMT 19 +/* Direct Multicast Service */ +#define DOT11_EXT_CAP_DMS 26 +/* Interworking support bit position */ +#define DOT11_EXT_CAP_IW 31 +/* QoS map support bit position */ +#define DOT11_EXT_CAP_QOS_MAP 32 +/* service Interval granularity bit position and mask */ +#define DOT11_EXT_CAP_SI 41 +#define DOT11_EXT_CAP_SI_MASK 0x0E +/* WNM notification */ +#define DOT11_EXT_CAP_WNM_NOTIF 46 +/* Operating mode notification - VHT (11ac D3.0 - 8.4.2.29) */ +#define DOT11_EXT_CAP_OPER_MODE_NOTIF 62 + +/* VHT Operating mode bit fields - (11ac D3.0 - 8.4.1.50) */ +#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 +#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 +#define DOT11_OPER_MODE_RXNSS_SHIFT 4 +#define DOT11_OPER_MODE_RXNSS_MASK 0x70 +#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 +#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 + +#define DOT11_OPER_MODE(type, nss, chanw) (\ + ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ + DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ + (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ + ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ + DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) + +#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ + (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ + >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) +#define DOT11_OPER_MODE_RXNSS(mode) \ + ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ + >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) +#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ + (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ + >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) + +#define DOT11_OPER_MODE_20MHZ 0 +#define DOT11_OPER_MODE_40MHZ 1 +#define DOT11_OPER_MODE_80MHZ 2 +#define DOT11_OPER_MODE_160MHZ 3 +#define DOT11_OPER_MODE_8080MHZ 3 + +#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ) + +/* Operating mode information element 802.11ac D3.0 - 8.4.2.168 */ +BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { + uint8 mode; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; + +#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 + +/* Extended Capability Information Field */ +#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 /* 20/40 BSS Coexistence Management support */ + +/* + * Action Frame Constants + */ +#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action field */ +#define DOT11_ACTION_CAT_OFF 0 /* category offset */ +#define DOT11_ACTION_ACT_OFF 1 /* action offset */ + +/* Action Category field (sec 8.4.1.11) */ +#define DOT11_ACTION_CAT_ERR_MASK 0x80 /* category error mask */ +#define DOT11_ACTION_CAT_MASK 0x7F /* category mask */ +#define DOT11_ACTION_CAT_SPECT_MNG 0 /* category spectrum management */ +#define DOT11_ACTION_CAT_QOS 1 /* category QoS */ +#define DOT11_ACTION_CAT_DLS 2 /* category DLS */ +#define DOT11_ACTION_CAT_BLOCKACK 3 /* category block ack */ +#define DOT11_ACTION_CAT_PUBLIC 4 /* category public */ +#define DOT11_ACTION_CAT_RRM 5 /* category radio measurements */ +#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */ +#define DOT11_ACTION_CAT_HT 7 /* category for HT */ +#define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */ +#define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */ +#define DOT11_ACTION_CAT_WNM 10 /* category for WNM */ +#define DOT11_ACTION_CAT_UWNM 11 /* category for Unprotected WNM */ +#define DOT11_ACTION_NOTIFICATION 17 +#define DOT11_ACTION_CAT_VHT 21 /* VHT action */ +#define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */ +#define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */ + +/* Spectrum Management Action IDs (sec 7.4.1) */ +#define DOT11_SM_ACTION_M_REQ 0 /* d11 action measurement request */ +#define DOT11_SM_ACTION_M_REP 1 /* d11 action measurement response */ +#define DOT11_SM_ACTION_TPC_REQ 2 /* d11 action TPC request */ +#define DOT11_SM_ACTION_TPC_REP 3 /* d11 action TPC response */ +#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ +#define DOT11_SM_ACTION_EXT_CSA 5 /* d11 extened CSA for 11n */ + +/* QoS action ids */ +#define DOT11_QOS_ACTION_ADDTS_REQ 0 /* d11 action ADDTS request */ +#define DOT11_QOS_ACTION_ADDTS_RESP 1 /* d11 action ADDTS response */ +#define DOT11_QOS_ACTION_DELTS 2 /* d11 action DELTS */ +#define DOT11_QOS_ACTION_SCHEDULE 3 /* d11 action schedule */ +#define DOT11_QOS_ACTION_QOS_MAP 4 /* d11 action QOS map */ + +/* HT action ids */ +#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ +#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ + +/* Public action ids */ +#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 /* 20/40 Coexistence Management action id */ +#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ +#define DOT11_PUB_ACTION_GAS_CB_REQ 12 /* GAS Comeback Request */ + +/* Block Ack action types */ +#define DOT11_BA_ACTION_ADDBA_REQ 0 /* ADDBA Req action frame type */ +#define DOT11_BA_ACTION_ADDBA_RESP 1 /* ADDBA Resp action frame type */ +#define DOT11_BA_ACTION_DELBA 2 /* DELBA action frame type */ + +/* ADDBA action parameters */ +#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 /* AMSDU supported under BA */ +#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 /* policy mask(ack vs delayed) */ +#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 /* policy shift */ +#define DOT11_ADDBA_PARAM_TID_MASK 0x003c /* tid mask */ +#define DOT11_ADDBA_PARAM_TID_SHIFT 2 /* tid shift */ +#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 /* buffer size mask */ +#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 /* buffer size shift */ + +#define DOT11_ADDBA_POLICY_DELAYED 0 /* delayed BA policy */ +#define DOT11_ADDBA_POLICY_IMMEDIATE 1 /* immediate BA policy */ + +/* Fast Transition action types */ +#define DOT11_FT_ACTION_FT_RESERVED 0 +#define DOT11_FT_ACTION_FT_REQ 1 /* FBT request - for over-the-DS FBT */ +#define DOT11_FT_ACTION_FT_RES 2 /* FBT response - for over-the-DS FBT */ +#define DOT11_FT_ACTION_FT_CON 3 /* FBT confirm - for OTDS with RRP */ +#define DOT11_FT_ACTION_FT_ACK 4 /* FBT ack */ + +/* DLS action types */ +#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */ +#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */ +#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */ + +/* Wireless Network Management (WNM) action types */ +#define DOT11_WNM_ACTION_EVENT_REQ 0 +#define DOT11_WNM_ACTION_EVENT_REP 1 +#define DOT11_WNM_ACTION_DIAG_REQ 2 +#define DOT11_WNM_ACTION_DIAG_REP 3 +#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 +#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 +#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6 +#define DOT11_WNM_ACTION_BSSTRANS_REQ 7 +#define DOT11_WNM_ACTION_BSSTRANS_RESP 8 +#define DOT11_WNM_ACTION_FMS_REQ 9 +#define DOT11_WNM_ACTION_FMS_RESP 10 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 +#define DOT11_WNM_ACTION_TFS_REQ 13 +#define DOT11_WNM_ACTION_TFS_RESP 14 +#define DOT11_WNM_ACTION_TFS_NOTIFY_REQ 15 +#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 +#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 +#define DOT11_WNM_ACTION_TIMBC_REQ 18 +#define DOT11_WNM_ACTION_TIMBC_RESP 19 +#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 +#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 +#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 +#define DOT11_WNM_ACTION_DMS_REQ 23 +#define DOT11_WNM_ACTION_DMS_RESP 24 +#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 +#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 +#define DOT11_WNM_ACTION_NOTFCTN_RESP 27 +#define DOT11_WNM_ACTION_TFS_NOTIFY_RESP 28 + +/* Unprotected Wireless Network Management (WNM) action types */ +#define DOT11_UWNM_ACTION_TIM 0 +#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 + +#define DOT11_MNG_COUNTRY_ID_LEN 3 + +/* VHT category action types - 802.11ac D3.0 - 8.5.23.1 */ +#define DOT11_VHT_ACTION_CBF 0 /* Compressed Beamforming */ +#define DOT11_VHT_ACTION_GID_MGMT 1 /* Group ID Management */ +#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 /* Operating mode notif'n */ + +/** DLS Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dls_req { + uint8 category; /* category of action frame (2) */ + uint8 action; /* DLS action: req (0) */ + struct ether_addr da; /* destination address */ + struct ether_addr sa; /* source address */ + uint16 cap; /* capability */ + uint16 timeout; /* timeout value */ + uint8 data[1]; /* IE:support rate, extend support rate, HT cap */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dls_req dot11_dls_req_t; +#define DOT11_DLS_REQ_LEN 18 /* Fixed length */ + +/** DLS response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { + uint8 category; /* category of action frame (2) */ + uint8 action; /* DLS action: req (0) */ + uint16 status; /* status code field */ + struct ether_addr da; /* destination address */ + struct ether_addr sa; /* source address */ + uint8 data[1]; /* optional: capability, rate ... */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dls_resp dot11_dls_resp_t; +#define DOT11_DLS_RESP_LEN 16 /* Fixed length */ + + +/* ************* 802.11v related definitions. ************* */ + +/** BSS Management Transition Query frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_query (6) */ + uint8 token; /* dialog token */ + uint8 reason; /* transition query reason */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_query dot11_bsstrans_query_t; +#define DOT11_BSSTRANS_QUERY_LEN 4 /* Fixed length */ + +/** BSS Management Transition Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_req (7) */ + uint8 token; /* dialog token */ + uint8 reqmode; /* transition request mode */ + uint16 disassoc_tmr; /* disassociation timer */ + uint8 validity_intrvl; /* validity interval */ + uint8 data[1]; /* optional: BSS term duration, ... */ + /* ...session info URL, candidate list */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_req dot11_bsstrans_req_t; +#define DOT11_BSSTRANS_REQ_LEN 7 /* Fixed length */ + +/* BSS Mgmt Transition Request Mode Field - 802.11v */ +#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01 +#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02 +#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04 +#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08 +#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10 + +/** BSS Management transition response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_resp (8) */ + uint8 token; /* dialog token */ + uint8 status; /* transition status */ + uint8 term_delay; /* validity interval */ + uint8 data[1]; /* optional: BSSID target, candidate list */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t; +#define DOT11_BSSTRANS_RESP_LEN 5 /* Fixed length */ + +/* BSS Mgmt Transition Response Status Field */ +#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0 +#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8 + + +/** BSS Max Idle Period element */ +BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { + uint8 id; /* 90, DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID */ + uint8 len; + uint16 max_idle_period; /* in unit of 1000 TUs */ + uint8 idle_opt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; +#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 /* bss max idle period IE size */ +#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 /* BSS max idle option */ + +/** TIM Broadcast request element */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { + uint8 id; /* 94, DOT11_MNG_TIMBC_REQ_ID */ + uint8 len; + uint8 interval; /* in unit of beacon interval */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; +#define DOT11_TIMBC_REQ_IE_LEN 1 /* Fixed length */ + +/** TIM Broadcast request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: DOT11_WNM_ACTION_TIMBC_REQ(18) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* TIM broadcast request element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req dot11_timbc_req_t; +#define DOT11_TIMBC_REQ_LEN 3 /* Fixed length */ + +/** TIM Broadcast response element */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { + uint8 id; /* 95, DOT11_MNG_TIM_BROADCAST_RESP_ID */ + uint8 len; + uint8 status; /* status of add request */ + uint8 interval; /* in unit of beacon interval */ + int32 offset; /* in unit of ms */ + uint16 high_rate; /* in unit of 0.5 Mb/s */ + uint16 low_rate; /* in unit of 0.5 Mb/s */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; +#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 /* Deny. Fixed length */ +#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 /* Accept. Fixed length */ + +#define DOT11_TIMBC_STATUS_ACCEPT 0 +#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 +#define DOT11_TIMBC_STATUS_DENY 2 +#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 +#define DOT11_TIMBC_STATUS_RESERVED 4 + +/** TIM Broadcast request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* action: DOT11_WNM_ACTION_TIMBC_RESP(19) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* TIM broadcast response element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp dot11_timbc_resp_t; +#define DOT11_TIMBC_RESP_LEN 3 /* Fixed length */ + +/** TIM element */ +BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { + uint8 id; /* 5, DOT11_MNG_TIM_ID */ + uint8 len; /* 4 - 255 */ + uint8 dtim_count; /* DTIM decrementing counter */ + uint8 dtim_period; /* DTIM period */ + uint8 bitmap_control; /* AID 0 + bitmap offset */ + uint8 pvb[1]; /* Partial Virtual Bitmap, variable length */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tim_ie dot11_tim_ie_t; +#define DOT11_TIM_IE_FIXED_LEN 3 /* Fixed length, without id and len */ +#define DOT11_TIM_IE_FIXED_TOTAL_LEN 5 /* Fixed length, with id and len */ + +/** TIM Broadcast frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc { + uint8 category; /* category of action frame (11) */ + uint8 action; /* action: TIM (0) */ + uint8 check_beacon; /* need to check-beacon */ + uint8 tsf[8]; /* Time Synchronization Function */ + dot11_tim_ie_t tim_ie; /* TIM element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc dot11_timbc_t; +#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) +#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) /* Fixed length */ +#define DOT11_TIMBC_LEN 11 /* Fixed length */ + +/** TCLAS frame classifier type */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { + uint8 type; + uint8 mask; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; +#define DOT11_TCLAS_FC_HDR_LEN 2 /* Fixed length */ + +#define DOT11_TCLAS_MASK_0 0x1 +#define DOT11_TCLAS_MASK_1 0x2 +#define DOT11_TCLAS_MASK_2 0x4 +#define DOT11_TCLAS_MASK_3 0x8 +#define DOT11_TCLAS_MASK_4 0x10 +#define DOT11_TCLAS_MASK_5 0x20 +#define DOT11_TCLAS_MASK_6 0x40 +#define DOT11_TCLAS_MASK_7 0x80 + +#define DOT11_TCLAS_FC_0_ETH 0 +#define DOT11_TCLAS_FC_1_IP 1 +#define DOT11_TCLAS_FC_2_8021Q 2 +#define DOT11_TCLAS_FC_3_OFFSET 3 +#define DOT11_TCLAS_FC_4_IP_HIGHER 4 +#define DOT11_TCLAS_FC_5_8021D 5 + +/** TCLAS frame classifier type 0 parameters for Ethernet */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { + uint8 type; + uint8 mask; + uint8 sa[ETHER_ADDR_LEN]; + uint8 da[ETHER_ADDR_LEN]; + uint16 eth_type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; +#define DOT11_TCLAS_FC_0_ETH_LEN 16 + +/** TCLAS frame classifier type 1 parameters for IPV4 */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { + uint8 type; + uint8 mask; + uint8 version; + uint32 src_ip; + uint32 dst_ip; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 protocol; + uint8 reserved; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; +#define DOT11_TCLAS_FC_1_IPV4_LEN 18 + +/** TCLAS frame classifier type 2 parameters for 802.1Q */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { + uint8 type; + uint8 mask; + uint16 tci; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; +#define DOT11_TCLAS_FC_2_8021Q_LEN 4 + +/** TCLAS frame classifier type 3 parameters for filter offset */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { + uint8 type; + uint8 mask; + uint16 offset; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; +#define DOT11_TCLAS_FC_3_FILTER_LEN 4 + +/** TCLAS frame classifier type 4 parameters for IPV4 is the same as TCLAS type 1 */ +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; +#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN + +/** TCLAS frame classifier type 4 parameters for IPV6 */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { + uint8 type; + uint8 mask; + uint8 version; + uint8 saddr[16]; + uint8 daddr[16]; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 nexthdr; + uint8 flow_lbl[3]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; +#define DOT11_TCLAS_FC_4_IPV6_LEN 44 + +/** TCLAS frame classifier type 5 parameters for 802.1D */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { + uint8 type; + uint8 mask; + uint8 pcp; + uint8 cfi; + uint16 vid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; +#define DOT11_TCLAS_FC_5_8021D_LEN 6 + +/** TCLAS frame classifier type parameters */ +BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { + uint8 data[1]; + dot11_tclas_fc_hdr_t hdr; + dot11_tclas_fc_0_eth_t t0_eth; + dot11_tclas_fc_1_ipv4_t t1_ipv4; + dot11_tclas_fc_2_8021q_t t2_8021q; + dot11_tclas_fc_3_filter_t t3_filter; + dot11_tclas_fc_4_ipv4_t t4_ipv4; + dot11_tclas_fc_4_ipv6_t t4_ipv6; + dot11_tclas_fc_5_8021d_t t5_8021d; +} BWL_POST_PACKED_STRUCT; +typedef union dot11_tclas_fc dot11_tclas_fc_t; + +#define DOT11_TCLAS_FC_MIN_LEN 4 /* Classifier Type 2 has the min size */ +#define DOT11_TCLAS_FC_MAX_LEN 254 + +/** TCLAS element */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { + uint8 id; /* 14, DOT11_MNG_TCLAS_ID */ + uint8 len; + uint8 user_priority; + dot11_tclas_fc_t fc; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_ie dot11_tclas_ie_t; +#define DOT11_TCLAS_IE_LEN 3 /* Fixed length, include id and len */ + +/** TCLAS processing element */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { + uint8 id; /* 44, DOT11_MNG_TCLAS_PROC_ID */ + uint8 len; + uint8 process; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; +#define DOT11_TCLAS_PROC_IE_LEN 3 /* Fixed length, include id and len */ + +#define DOT11_TCLAS_PROC_MATCHALL 0 /* All high level element need to match */ +#define DOT11_TCLAS_PROC_MATCHONE 1 /* One high level element need to match */ +#define DOT11_TCLAS_PROC_NONMATCH 2 /* Non match to any high level element */ + + +/* TSPEC element defined in 802.11 std section 8.4.2.32 - Not supported */ +#define DOT11_TSPEC_IE_LEN 57 /* Fixed length */ + +/** TFS request element */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { + uint8 id; /* 91, DOT11_MNG_TFS_REQUEST_ID */ + uint8 len; + uint8 tfs_id; + uint8 actcode; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; +#define DOT11_TFS_REQ_IE_LEN 2 /* Fixed length, without id and len */ + +/** TFS request action codes (bitfield) */ +#define DOT11_TFS_ACTCODE_DELETE 1 +#define DOT11_TFS_ACTCODE_NOTIFY 2 + +/** TFS request subelement IDs */ +#define DOT11_TFS_REQ_TFS_SE_ID 1 +#define DOT11_TFS_REQ_VENDOR_SE_ID 221 + +/** TFS subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { + uint8 sub_id; + uint8 len; + uint8 data[1]; /* TCLAS element(s) + optional TCLAS proc */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_se dot11_tfs_se_t; + + +/** TFS response element */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { + uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ + uint8 len; + uint8 tfs_id; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; +#define DOT11_TFS_RESP_IE_LEN 1 /* Fixed length, without id and len */ + +/** TFS response subelement IDs (same subelments, but different IDs than in TFS request */ +#define DOT11_TFS_RESP_TFS_STATUS_SE_ID 1 +#define DOT11_TFS_RESP_TFS_SE_ID 2 +#define DOT11_TFS_RESP_VENDOR_SE_ID 221 + +/** TFS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { + uint8 sub_id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ + uint8 len; + uint8 resp_st; + uint8 data[1]; /* Potential dot11_tfs_se_t included */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; +#define DOT11_TFS_STATUS_SE_LEN 1 /* Fixed length, without id and len */ + +/* Following Definition should be merged to FMS_TFS macro below */ +/* TFS Response status code. Identical to FMS Element status, without N/A */ +#define DOT11_TFS_STATUS_ACCEPT 0 +#define DOT11_TFS_STATUS_DENY_FORMAT 1 +#define DOT11_TFS_STATUS_DENY_RESOURCE 2 +#define DOT11_TFS_STATUS_DENY_POLICY 4 +#define DOT11_TFS_STATUS_DENY_UNSPECIFIED 5 +#define DOT11_TFS_STATUS_ALTPREF_POLICY 7 +#define DOT11_TFS_STATUS_ALTPREF_TCLAS_UNSUPP 14 + +/* FMS Element Status and TFS Response Status Definition */ +#define DOT11_FMS_TFS_STATUS_ACCEPT 0 +#define DOT11_FMS_TFS_STATUS_DENY_FORMAT 1 +#define DOT11_FMS_TFS_STATUS_DENY_RESOURCE 2 +#define DOT11_FMS_TFS_STATUS_DENY_MULTIPLE_DI 3 +#define DOT11_FMS_TFS_STATUS_DENY_POLICY 4 +#define DOT11_FMS_TFS_STATUS_DENY_UNSPECIFIED 5 +#define DOT11_FMS_TFS_STATUS_ALT_DIFF_DI 6 +#define DOT11_FMS_TFS_STATUS_ALT_POLICY 7 +#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_DI 8 +#define DOT11_FMS_TFS_STATUS_ALT_MCRATE 9 +#define DOT11_FMS_TFS_STATUS_TERM_POLICY 10 +#define DOT11_FMS_TFS_STATUS_TERM_RESOURCE 11 +#define DOT11_FMS_TFS_STATUS_TERM_HIGHER_PRIO 12 +#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_MDI 13 +#define DOT11_FMS_TFS_STATUS_ALT_TCLAS_UNSUPP 14 + +/** TFS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS request (13) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req dot11_tfs_req_t; +#define DOT11_TFS_REQ_LEN 3 /* Fixed length */ + +/** TFS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS request (14) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp dot11_tfs_resp_t; +#define DOT11_TFS_RESP_LEN 3 /* Fixed length */ + +/** TFS Management Notify frame request header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS notify request (15) */ + uint8 tfs_id_cnt; /* TFS IDs count */ + uint8 tfs_id[1]; /* Array of TFS IDs */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify_req dot11_tfs_notify_req_t; +#define DOT11_TFS_NOTIFY_REQ_LEN 3 /* Fixed length */ + +/** TFS Management Notify frame response header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS notify response (28) */ + uint8 tfs_id_cnt; /* TFS IDs count */ + uint8 tfs_id[1]; /* Array of TFS IDs */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify_resp dot11_tfs_notify_resp_t; +#define DOT11_TFS_NOTIFY_RESP_LEN 3 /* Fixed length */ + + +/** WNM-Sleep Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: wnm-sleep request (16) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; +#define DOT11_WNM_SLEEP_REQ_LEN 3 /* Fixed length */ + +/** WNM-Sleep Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: wnm-sleep request (17) */ + uint8 token; /* dialog token */ + uint16 key_len; /* key data length */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; +#define DOT11_WNM_SLEEP_RESP_LEN 5 /* Fixed length */ + +#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 +#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { + uint8 sub_id; + uint8 len; + uint16 key_info; + uint8 key_length; + uint8 rsc[8]; + uint8 key[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 /* without sub_id, len, and key */ +#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 /* without sub_id and len */ + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { + uint8 sub_id; + uint8 len; + uint16 key_id; + uint8 pn[6]; + uint8 key[16]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 /* Fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { + uint8 id; /* 93, DOT11_MNG_WNM_SLEEP_MODE_ID */ + uint8 len; + uint8 act_type; + uint8 resp_status; + uint16 interval; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; +#define DOT11_WNM_SLEEP_IE_LEN 4 /* Fixed length */ + +#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 +#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 + +#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 +#define DOT11_WNM_SLEEP_RESP_UPDATE 1 +#define DOT11_WNM_SLEEP_RESP_DENY 2 +#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 +#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 +#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 +#define DOT11_WNM_SLEEP_RESP_LAST 6 + +/** DMS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: dms request (23) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req dot11_dms_req_t; +#define DOT11_DMS_REQ_LEN 3 /* Fixed length */ + +/** DMS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: dms request (24) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp dot11_dms_resp_t; +#define DOT11_DMS_RESP_LEN 3 /* Fixed length */ + +/** DMS request element */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { + uint8 id; /* 99, DOT11_MNG_DMS_REQUEST_ID */ + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; +#define DOT11_DMS_REQ_IE_LEN 2 /* Fixed length */ + +/** DMS response element */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { + uint8 id; /* 100, DOT11_MNG_DMS_RESPONSE_ID */ + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; +#define DOT11_DMS_RESP_IE_LEN 2 /* Fixed length */ + +/** DMS request descriptor */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { + uint8 dms_id; + uint8 len; + uint8 type; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; +#define DOT11_DMS_REQ_DESC_LEN 3 /* Fixed length */ + +#define DOT11_DMS_REQ_TYPE_ADD 0 +#define DOT11_DMS_REQ_TYPE_REMOVE 1 +#define DOT11_DMS_REQ_TYPE_CHANGE 2 + +/** DMS response status */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { + uint8 dms_id; + uint8 len; + uint8 type; + uint16 lsc; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; +#define DOT11_DMS_RESP_STATUS_LEN 5 /* Fixed length */ + +#define DOT11_DMS_RESP_TYPE_ACCEPT 0 +#define DOT11_DMS_RESP_TYPE_DENY 1 +#define DOT11_DMS_RESP_TYPE_TERM 2 + +#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF + +/** FMS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: fms request (9) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_req dot11_fms_req_t; +#define DOT11_FMS_REQ_LEN 3 /* Fixed length */ + +/** FMS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: fms request (10) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_resp dot11_fms_resp_t; +#define DOT11_FMS_RESP_LEN 3 /* Fixed length */ + +/** FMS Descriptor element */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_desc { + uint8 id; + uint8 len; + uint8 num_fms_cnt; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_desc dot11_fms_desc_t; +#define DOT11_FMS_DESC_LEN 1 /* Fixed length */ + +#define DOT11_FMS_CNTR_MAX 0x8 +#define DOT11_FMS_CNTR_ID_MASK 0x7 +#define DOT11_FMS_CNTR_ID_SHIFT 0x0 +#define DOT11_FMS_CNTR_COUNT_MASK 0xf1 +#define DOT11_FMS_CNTR_SHIFT 0x3 + +/** FMS request element */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_req_ie { + uint8 id; + uint8 len; + uint8 fms_token; /* token used to identify fms stream set */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_req_ie dot11_fms_req_ie_t; +#define DOT11_FMS_REQ_IE_FIX_LEN 1 /* Fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_rate_id_field { + uint8 mask; + uint8 mcs_idx; + uint16 rate; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rate_id_field dot11_rate_id_field_t; +#define DOT11_RATE_ID_FIELD_MCS_SEL_MASK 0x7 +#define DOT11_RATE_ID_FIELD_MCS_SEL_OFFSET 0 +#define DOT11_RATE_ID_FIELD_RATETYPE_MASK 0x18 +#define DOT11_RATE_ID_FIELD_RATETYPE_OFFSET 3 +#define DOT11_RATE_ID_FIELD_LEN sizeof(dot11_rate_id_field_t) + +/** FMS request subelements */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_se { + uint8 sub_id; + uint8 len; + uint8 interval; + uint8 max_interval; + dot11_rate_id_field_t rate; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_se dot11_fms_se_t; +#define DOT11_FMS_REQ_SE_LEN 6 /* Fixed length */ + +#define DOT11_FMS_REQ_SE_ID_FMS 1 /* FMS subelement */ +#define DOT11_FMS_REQ_SE_ID_VS 221 /* Vendor Specific subelement */ + +/** FMS response element */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_resp_ie { + uint8 id; + uint8 len; + uint8 fms_token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_resp_ie dot11_fms_resp_ie_t; +#define DOT11_FMS_RESP_IE_FIX_LEN 1 /* Fixed length */ + +/* FMS status subelements */ +#define DOT11_FMS_STATUS_SE_ID_FMS 1 /* FMS Status */ +#define DOT11_FMS_STATUS_SE_ID_TCLAS 2 /* TCLAS Status */ +#define DOT11_FMS_STATUS_SE_ID_VS 221 /* Vendor Specific subelement */ + +/** FMS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_status_se { + uint8 sub_id; + uint8 len; + uint8 status; + uint8 interval; + uint8 max_interval; + uint8 fmsid; + uint8 counter; + dot11_rate_id_field_t rate; + uint8 mcast_addr[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_status_se dot11_fms_status_se_t; +#define DOT11_FMS_STATUS_SE_LEN 15 /* Fixed length */ + +/** TCLAS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_status_se { + uint8 sub_id; + uint8 len; + uint8 fmsid; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_status_se dot11_tclas_status_se_t; +#define DOT11_TCLAS_STATUS_SE_LEN 1 /* Fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_addba_req { + uint8 category; /* category of action frame (3) */ + uint8 action; /* action: addba req */ + uint8 token; /* identifier */ + uint16 addba_param_set; /* parameter set */ + uint16 timeout; /* timeout in seconds */ + uint16 start_seqnum; /* starting sequence number */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_req dot11_addba_req_t; +#define DOT11_ADDBA_REQ_LEN 9 /* length of addba req frame */ + +BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { + uint8 category; /* category of action frame (3) */ + uint8 action; /* action: addba resp */ + uint8 token; /* identifier */ + uint16 status; /* status of add request */ + uint16 addba_param_set; /* negotiated parameter set */ + uint16 timeout; /* negotiated timeout in seconds */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_resp dot11_addba_resp_t; +#define DOT11_ADDBA_RESP_LEN 9 /* length of addba resp frame */ + +/* DELBA action parameters */ +#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 /* initiator mask */ +#define DOT11_DELBA_PARAM_INIT_SHIFT 11 /* initiator shift */ +#define DOT11_DELBA_PARAM_TID_MASK 0xf000 /* tid mask */ +#define DOT11_DELBA_PARAM_TID_SHIFT 12 /* tid shift */ + +BWL_PRE_PACKED_STRUCT struct dot11_delba { + uint8 category; /* category of action frame (3) */ + uint8 action; /* action: addba req */ + uint16 delba_param_set; /* paarmeter set */ + uint16 reason; /* reason for dellba */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_delba dot11_delba_t; +#define DOT11_DELBA_LEN 6 /* length of delba frame */ + +/* SA Query action field value */ +#define SA_QUERY_REQUEST 0 +#define SA_QUERY_RESPONSE 1 + +/* ************* 802.11r related definitions. ************* */ + +/** Over-the-DS Fast Transition Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_ft_req { + uint8 category; /* category of action frame (6) */ + uint8 action; /* action: ft req */ + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_req dot11_ft_req_t; +#define DOT11_FT_REQ_FIXED_LEN 14 + +/** Over-the-DS Fast Transition Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_ft_res { + uint8 category; /* category of action frame (6) */ + uint8 action; /* action: ft resp */ + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint16 status; /* status code */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_res dot11_ft_res_t; +#define DOT11_FT_RES_FIXED_LEN 16 + +/** RDE RIC Data Element. */ +BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { + uint8 id; /* 11r, DOT11_MNG_RDE_ID */ + uint8 length; + uint8 rde_id; /* RDE identifier. */ + uint8 rd_count; /* Resource Descriptor Count. */ + uint16 status; /* Status Code. */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rde_ie dot11_rde_ie_t; + +/* 11r - Size of the RDE (RIC Data Element) IE, including TLV header. */ +#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) + + +/* ************* 802.11k related definitions. ************* */ + +/* Radio measurements enabled capability ie */ +#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ +#define RCPI_IE_LEN 1 +#define RSNI_IE_LEN 1 +BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { + uint8 cap[DOT11_RRM_CAP_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; + +/* Bitmap definitions for cap ie */ +#define DOT11_RRM_CAP_LINK 0 +#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 +#define DOT11_RRM_CAP_PARALLEL 2 +#define DOT11_RRM_CAP_REPEATED 3 +#define DOT11_RRM_CAP_BCN_PASSIVE 4 +#define DOT11_RRM_CAP_BCN_ACTIVE 5 +#define DOT11_RRM_CAP_BCN_TABLE 6 +#define DOT11_RRM_CAP_BCN_REP_COND 7 +#define DOT11_RRM_CAP_FM 8 +#define DOT11_RRM_CAP_CLM 9 +#define DOT11_RRM_CAP_NHM 10 +#define DOT11_RRM_CAP_SM 11 +#define DOT11_RRM_CAP_LCIM 12 +#define DOT11_RRM_CAP_LCIA 13 +#define DOT11_RRM_CAP_TSCM 14 +#define DOT11_RRM_CAP_TTSCM 15 +#define DOT11_RRM_CAP_AP_CHANREP 16 +#define DOT11_RRM_CAP_RMMIB 17 +/* bit18-bit26, not used for RRM_IOVAR */ +#define DOT11_RRM_CAP_MPTI 27 +#define DOT11_RRM_CAP_NBRTSFO 28 +#define DOT11_RRM_CAP_RCPI 29 +#define DOT11_RRM_CAP_RSNI 30 +#define DOT11_RRM_CAP_BSSAAD 31 +#define DOT11_RRM_CAP_BSSAAC 32 +#define DOT11_RRM_CAP_AI 33 + +/* Operating Class (formerly "Regulatory Class") definitions */ +#define DOT11_OP_CLASS_NONE 255 + +BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { + uint8 id; + uint8 len; + uint8 reg; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct do11_ap_chrep dot11_ap_chrep_t; + +/* Radio Measurements action ids */ +#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ +#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */ +#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */ +#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */ +#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */ +#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */ + +/** Generic radio measurement action frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_rm_action { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_action dot11_rm_action_t; +#define DOT11_RM_ACTION_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + uint16 reps; /* no. of repetitions */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq dot11_rmreq_t; +#define DOT11_RMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_ie dot11_rm_ie_t; +#define DOT11_RM_IE_LEN 5 + +/* Definitions for "mode" bits in rm req */ +#define DOT11_RMREQ_MODE_PARALLEL 1 +#define DOT11_RMREQ_MODE_ENABLE 2 +#define DOT11_RMREQ_MODE_REQUEST 4 +#define DOT11_RMREQ_MODE_REPORT 8 +#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */ + +/* Definitions for "mode" bits in rm rep */ +#define DOT11_RMREP_MODE_LATE 1 +#define DOT11_RMREP_MODE_INCAPABLE 2 +#define DOT11_RMREP_MODE_REFUSED 4 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 bcn_mode; + struct ether_addr bssid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; +#define DOT11_RMREQ_BCN_LEN 18 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 frame_info; + uint8 rcpi; + uint8 rsni; + struct ether_addr bssid; + uint8 antenna_id; + uint32 parent_tsf; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; +#define DOT11_RMREP_BCN_LEN 26 + +/* Beacon request measurement mode */ +#define DOT11_RMREQ_BCN_PASSIVE 0 +#define DOT11_RMREQ_BCN_ACTIVE 1 +#define DOT11_RMREQ_BCN_TABLE 2 + +/* Sub-element IDs for Beacon Request */ +#define DOT11_RMREQ_BCN_SSID_ID 0 +#define DOT11_RMREQ_BCN_REPINFO_ID 1 +#define DOT11_RMREQ_BCN_REPDET_ID 2 +#define DOT11_RMREQ_BCN_REQUEST_ID 10 +#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID + +/* Reporting Detail element definition */ +#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ +#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */ +#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */ + +/* Sub-element IDs for Beacon Report */ +#define DOT11_RMREP_BCN_FRM_BODY 1 + +/* Sub-element IDs for Frame Report */ +#define DOT11_RMREP_FRAME_COUNT_REPORT 1 + +/** Channel load request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; +#define DOT11_RMREQ_CHANLOAD_LEN 11 + +/** Channel load report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 channel_load; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; +#define DOT11_RMREP_CHANLOAD_LEN 13 + +/** Noise histogram request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; +#define DOT11_RMREQ_NOISE_LEN 11 + +/** Noise histogram report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 antid; + uint8 anpi; + uint8 ipi0_dens; + uint8 ipi1_dens; + uint8 ipi2_dens; + uint8 ipi3_dens; + uint8 ipi4_dens; + uint8 ipi5_dens; + uint8 ipi6_dens; + uint8 ipi7_dens; + uint8 ipi8_dens; + uint8 ipi9_dens; + uint8 ipi10_dens; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; +#define DOT11_RMREP_NOISE_LEN 25 + +/** Frame request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 req_type; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; +#define DOT11_RMREQ_FRAME_LEN 18 + +/** Frame report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; +#define DOT11_RMREP_FRAME_LEN 12 + +/** Frame report entry */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { + struct ether_addr ta; + struct ether_addr bssid; + uint8 phy_type; + uint8 avg_rcpi; + uint8 last_rsni; + uint8 last_rcpi; + uint8 ant_id; + uint16 frame_cnt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; +#define DOT11_RMREP_FRMENTRY_LEN 19 + +/** STA statistics request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + struct ether_addr peer; + uint16 interval; + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; +#define DOT11_RMREQ_STAT_LEN 16 + +/** STA statistics report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; + +/** Transmit stream/category measurement request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 interval; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 bin0_range; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; + +/** Transmit stream/category measurement report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { + uint32 starttime[2]; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 reason; + uint32 txmsdu_cnt; + uint32 msdu_discarded_cnt; + uint32 msdufailed_cnt; + uint32 msduretry_cnt; + uint32 cfpolls_lost_cnt; + uint32 avrqueue_delay; + uint32 avrtx_delay; + uint8 bin0_range; + uint32 bin0; + uint32 bin1; + uint32 bin2; + uint32 bin3; + uint32 bin4; + uint32 bin5; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; + +/** Measurement pause request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 pause_time; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; + + +/* Neighbor Report subelements ID (11k & 11v) */ +#define DOT11_NGBR_TSF_INFO_SE_ID 1 +#define DOT11_NGBR_CCS_SE_ID 2 +#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3 +#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4 +#define DOT11_NGBR_BEARING_SE_ID 5 + +/** Neighbor Report, BSS Transition Candidate Preference subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se { + uint8 sub_id; + uint8 len; + uint8 preference; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t; +#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1 + +/** Neighbor Report, BSS Termination Duration subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se { + uint8 sub_id; + uint8 len; + uint8 tsf[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t; +#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10 + +/* Neighbor Report BSSID Information Field */ +#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002 +#define DOT11_NGBR_BI_REACHABILTY 0x0003 +#define DOT11_NGBR_BI_SEC 0x0004 +#define DOT11_NGBR_BI_KEY_SCOPE 0x0008 +#define DOT11_NGBR_BI_CAP 0x03f0 +#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010 +#define DOT11_NGBR_BI_CAP_QOS 0x0020 +#define DOT11_NGBR_BI_CAP_APSD 0x0040 +#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080 +#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100 +#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200 +#define DOT11_NGBR_BI_MOBILITY 0x0400 +#define DOT11_NGBR_BI_HT 0x0800 + +/** Neighbor Report element (11k & 11v) */ +BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; /* Operating class */ + uint8 channel; + uint8 phytype; + uint8 data[1]; /* Variable size subelements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; +#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13 + + +/* MLME Enumerations */ +#define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ +#define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */ +#define DOT11_BSSTYPE_ANY 2 /* d11 any BSS type */ +#define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */ +#define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */ + +/** Link Measurement */ +BWL_PRE_PACKED_STRUCT struct dot11_lmreq { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + uint8 txpwr; /* Transmit Power Used */ + uint8 maxtxpwr; /* Max Transmit Power */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmreq dot11_lmreq_t; +#define DOT11_LMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_lmrep { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + dot11_tpc_rep_t tpc; /* TPC element */ + uint8 rxant; /* Receive Antenna ID */ + uint8 txant; /* Transmit Antenna ID */ + uint8 rcpi; /* RCPI */ + uint8 rsni; /* RSNI */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmrep dot11_lmrep_t; +#define DOT11_LMREP_LEN 11 + +/* 802.11 BRCM "Compromise" Pre N constants */ +#define PREN_PREAMBLE 24 /* green field preamble time */ +#define PREN_MM_EXT 12 /* extra mixed mode preamble time */ +#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ + +/* 802.11N PHY constants */ +#define RIFS_11N_TIME 2 /* NPHY RIFS time */ + +/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3 + * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 + */ +/* HT-SIG1 */ +#define HT_SIG1_MCS_MASK 0x00007F +#define HT_SIG1_CBW 0x000080 +#define HT_SIG1_HT_LENGTH 0xFFFF00 + +/* HT-SIG2 */ +#define HT_SIG2_SMOOTHING 0x000001 +#define HT_SIG2_NOT_SOUNDING 0x000002 +#define HT_SIG2_RESERVED 0x000004 +#define HT_SIG2_AGGREGATION 0x000008 +#define HT_SIG2_STBC_MASK 0x000030 +#define HT_SIG2_STBC_SHIFT 4 +#define HT_SIG2_FEC_CODING 0x000040 +#define HT_SIG2_SHORT_GI 0x000080 +#define HT_SIG2_ESS_MASK 0x000300 +#define HT_SIG2_ESS_SHIFT 8 +#define HT_SIG2_CRC 0x03FC00 +#define HT_SIG2_TAIL 0x1C0000 + +/* HT Timing-related parameters (802.11-2012, sec 20.3.6) */ +#define HT_T_LEG_PREAMBLE 16 +#define HT_T_L_SIG 4 +#define HT_T_SIG 8 +#define HT_T_LTF1 4 +#define HT_T_GF_LTF1 8 +#define HT_T_LTFs 4 +#define HT_T_STF 4 +#define HT_T_GF_STF 8 +#define HT_T_SYML 4 + +#define HT_N_SERVICE 16 /* bits in SERVICE field */ +#define HT_N_TAIL 6 /* tail bits per BCC encoder */ + +/* 802.11 A PHY constants */ +#define APHY_SLOT_TIME 9 /* APHY slot time */ +#define APHY_SIFS_TIME 16 /* APHY SIFS time */ +#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ +#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ +#define APHY_SIGNAL_TIME 4 /* APHY signal time */ +#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ +#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ +#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ +#define APHY_CWMIN 15 /* APHY cwmin */ + +/* 802.11 B PHY constants */ +#define BPHY_SLOT_TIME 20 /* BPHY slot time */ +#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ +#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ +#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ +#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ +#define BPHY_CWMIN 31 /* BPHY cwmin */ + +/* 802.11 G constants */ +#define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */ + +#define PHY_CWMAX 1023 /* PHY cwmax */ + +#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ + +/* 802.11 VHT constants */ + +typedef int vht_group_id_t; + +/* for VHT-A1 */ +/* SIG-A1 reserved bits */ +#define VHT_SIGA1_CONST_MASK 0x800004 + +#define VHT_SIGA1_BW_MASK 0x000003 +#define VHT_SIGA1_20MHZ_VAL 0x000000 +#define VHT_SIGA1_40MHZ_VAL 0x000001 +#define VHT_SIGA1_80MHZ_VAL 0x000002 +#define VHT_SIGA1_160MHZ_VAL 0x000003 + +#define VHT_SIGA1_STBC 0x000008 + +#define VHT_SIGA1_GID_MASK 0x0003f0 +#define VHT_SIGA1_GID_SHIFT 4 +#define VHT_SIGA1_GID_TO_AP 0x00 +#define VHT_SIGA1_GID_NOT_TO_AP 0x3f +#define VHT_SIGA1_GID_MAX_GID 0x3f + +#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 +#define VHT_SIGA1_NSTS_SHIFT 10 + +#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 +#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 + +#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 + +/* for VHT-A2 */ +#define VHT_SIGA2_GI_NONE 0x000000 +#define VHT_SIGA2_GI_SHORT 0x000001 +#define VHT_SIGA2_GI_W_MOD10 0x000002 +#define VHT_SIGA2_CODING_LDPC 0x000004 +#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 +#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 +#define VHT_SIGA2_MCS_SHIFT 4 + +#define VHT_SIGA2_B9_RESERVED 0x000200 +#define VHT_SIGA2_TAIL_MASK 0xfc0000 +#define VHT_SIGA2_TAIL_VALUE 0x000000 + +/* VHT Timing-related parameters (802.11ac D4.0, sec 22.3.6) */ +#define VHT_T_LEG_PREAMBLE 16 +#define VHT_T_L_SIG 4 +#define VHT_T_SIG_A 8 +#define VHT_T_LTF 4 +#define VHT_T_STF 4 +#define VHT_T_SIG_B 4 +#define VHT_T_SYML 4 + +#define VHT_N_SERVICE 16 /* bits in SERVICE field */ +#define VHT_N_TAIL 6 /* tail bits per BCC encoder */ + + +/** dot11Counters Table - 802.11 spec., Annex D */ +typedef struct d11cnt { + uint32 txfrag; /* dot11TransmittedFragmentCount */ + uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ + uint32 txfail; /* dot11FailedCount */ + uint32 txretry; /* dot11RetryCount */ + uint32 txretrie; /* dot11MultipleRetryCount */ + uint32 rxdup; /* dot11FrameduplicateCount */ + uint32 txrts; /* dot11RTSSuccessCount */ + uint32 txnocts; /* dot11RTSFailureCount */ + uint32 txnoack; /* dot11ACKFailureCount */ + uint32 rxfrag; /* dot11ReceivedFragmentCount */ + uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ + uint32 rxcrc; /* dot11FCSErrorCount */ + uint32 txfrmsnt; /* dot11TransmittedFrameCount */ + uint32 rxundec; /* dot11WEPUndecryptableCount */ +} d11cnt_t; + +#define BRCM_PROP_OUI "\x00\x90\x4C" + + +/* Action frame type for RWL */ +#define RWL_WIFI_DEFAULT 0 +#define RWL_WIFI_FIND_MY_PEER 9 /* Used while finding server */ +#define RWL_WIFI_FOUND_PEER 10 /* Server response to the client */ +#define RWL_ACTION_WIFI_FRAG_TYPE 85 /* Fragment indicator for receiver */ + +#define PROXD_AF_TYPE 11 /* Wifi proximity action frame type */ +#define BRCM_RELMACST_AF_TYPE 12 /* RMC action frame type */ + + +/* brcm syscap_ie cap */ +#define BRCM_SYSCAP_WET_TUNNEL 0x0100 /* Device with WET_TUNNEL support */ + +#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ + +/** BRCM info element */ +BWL_PRE_PACKED_STRUCT struct brcm_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; + uint8 ver; /* type/ver of this IE */ + uint8 assoc; /* # of assoc STAs */ + uint8 flags; /* misc flags */ + uint8 flags1; /* misc flags */ + uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ +} BWL_POST_PACKED_STRUCT; +typedef struct brcm_ie brcm_ie_t; +#define BRCM_IE_LEN 11 /* BRCM IE length */ +#define BRCM_IE_VER 2 /* BRCM IE version */ +#define BRCM_IE_LEGACY_AES_VER 1 /* BRCM IE legacy AES version */ + +/* brcm_ie flags */ +#define BRF_ABCAP 0x1 /* afterburner is obsolete, defined for backward compat */ +#define BRF_ABRQRD 0x2 /* afterburner is obsolete, defined for backward compat */ +#define BRF_LZWDS 0x4 /* lazy wds enabled */ +#define BRF_BLOCKACK 0x8 /* BlockACK capable */ +#define BRF_ABCOUNTER_MASK 0xf0 /* afterburner is obsolete, defined for backward compat */ +#define BRF_PROP_11N_MCS 0x10 /* re-use afterburner bit */ + +#define GET_BRF_PROP_11N_MCS(brcm_ie) \ + (!((brcm_ie)->flags & BRF_ABCAP) && ((brcm_ie)->flags & BRF_PROP_11N_MCS)) + +/* brcm_ie flags1 */ +#define BRF1_AMSDU 0x1 /* A-MSDU capable */ +#define BRF1_WMEPS 0x4 /* AP is capable of handling WME + PS w/o APSD */ +#define BRF1_PSOFIX 0x8 /* AP has fixed PS mode out-of-order packets */ +#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ +#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ +#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ +#define BRF1_DWDS 0x80 /* DWDS capable */ + +/** Vendor IE structure */ +BWL_PRE_PACKED_STRUCT struct vndr_ie { + uchar id; + uchar len; + uchar oui [3]; + uchar data [1]; /* Variable size data */ +} BWL_POST_PACKED_STRUCT; +typedef struct vndr_ie vndr_ie_t; + +#define VNDR_IE_HDR_LEN 2 /* id + len field */ +#define VNDR_IE_MIN_LEN 3 /* size of the oui field */ +#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) + +#define VNDR_IE_MAX_LEN 255 /* vendor IE max length, without ID and len */ + +/** BRCM PROP DEVICE PRIMARY MAC ADDRESS IE */ +BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { + uchar id; + uchar len; + uchar oui[3]; + uint8 type; /* type indicates what follows */ + struct ether_addr ea; /* Device Primary MAC Adrress */ +} BWL_POST_PACKED_STRUCT; +typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; + +#define MEMBER_OF_BRCM_PROP_IE_LEN 10 /* IE max length */ +#define MEMBER_OF_BRCM_PROP_IE_HDRLEN (sizeof(member_of_brcm_prop_ie_t)) +#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 + +/** BRCM Reliable Multicast IE */ +BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; /* type indicates what follows */ + struct ether_addr ea; /* The ack sender's MAC Adrress */ + struct ether_addr mcast_ea; /* The multicast MAC address */ + uint8 updtmo; /* time interval(second) for client to send null packet to report its rssi */ +} BWL_POST_PACKED_STRUCT; +typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; + +/* IE length */ +/* BRCM_PROP_IE_LEN = sizeof(relmcast_brcm_prop_ie_t)-((sizeof (id) + sizeof (len)))? */ +#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-(2*sizeof(uint8))) + +#define RELMCAST_BRCM_PROP_IE_TYPE 55 + +/* ************* HT definitions. ************* */ +#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ +#define MAX_MCS_NUM (128) /* max mcs number = 128 */ + +BWL_PRE_PACKED_STRUCT struct ht_cap_ie { + uint16 cap; + uint8 params; + uint8 supp_mcs[MCSSET_LEN]; + uint16 ext_htcap; + uint32 txbf_cap; + uint8 as_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_cap_ie ht_cap_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { + uint8 id; + uint8 len; + ht_cap_ie_t ht_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; + +/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ +/* the capability IE is primarily used to convey this nodes abilities */ +BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; + uint8 type; /* type indicates what follows */ + ht_cap_ie_t cap_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; + +#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ +#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */ +#define HT_CAP_IE_TYPE 51 + +#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ +#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ +#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ +#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ +#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ +#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ +#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ +#define HT_CAP_GF 0x0010 /* Greenfield preamble support */ +#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ +#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ +#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */ +#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ +#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ +#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */ +#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ + +#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ +#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ +#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ +#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ + +#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ +#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ +#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ +#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ + + +#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 +#define HT_CAP_TXBF_CAP_NDP_RX 0x8 +#define HT_CAP_TXBF_CAP_NDP_TX 0x10 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 +#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 +#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 + +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 + +#define HT_CAP_TXBF_FB_TYPE_NONE 0 +#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 +#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 +#define HT_CAP_TXBF_FB_TYPE_BOTH 3 + +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400 +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15 + +#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ +#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ +/* Max AMSDU len - per spec */ +#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) + +#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */ +#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */ + +#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ +#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ +#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ + +/* HT/AMPDU specific define */ +#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */ +#define AMPDU_DENSITY_NONE 0 /* No density requirement */ +#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */ +#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */ +#define AMPDU_DENSITY_1_US 3 /* 1 us density */ +#define AMPDU_DENSITY_2_US 4 /* 2 us density */ +#define AMPDU_DENSITY_4_US 5 /* 4 us density */ +#define AMPDU_DENSITY_8_US 6 /* 8 us density */ +#define AMPDU_DENSITY_16_US 7 /* 16 us density */ +#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */ +#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */ +#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */ +#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */ + +/* AMPDU RX factors for VHT rates */ +#define AMPDU_RX_FACTOR_128K 4 /* max rcv ampdu len (128kb) */ +#define AMPDU_RX_FACTOR_256K 5 /* max rcv ampdu len (256kb) */ +#define AMPDU_RX_FACTOR_512K 6 /* max rcv ampdu len (512kb) */ +#define AMPDU_RX_FACTOR_1024K 7 /* max rcv ampdu len (1024kb) */ + +#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ +#define AMPDU_RX_FACTOR_BASE_PWR 13 /* ampdu factor base for rx len in power of 2 */ + +#define AMPDU_DELIMITER_LEN 4 /* length of ampdu delimiter */ +#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */ + +#define HT_CAP_EXT_PCO 0x0001 +#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 +#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 +#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 +#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 +#define HT_CAP_EXT_HTC 0x0400 +#define HT_CAP_EXT_RD_RESP 0x0800 + +/** 'ht_add' is called 'HT Operation' information element in the 802.11 standard */ +BWL_PRE_PACKED_STRUCT struct ht_add_ie { + uint8 ctl_ch; /* control channel number */ + uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ + uint16 opmode; /* operation mode */ + uint16 misc_bits; /* misc bits */ + uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ +} BWL_POST_PACKED_STRUCT; +typedef struct ht_add_ie ht_add_ie_t; + +/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ +/* the additional IE is primarily used to convey the current BSS configuration */ +BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; + uint8 type; /* indicates what follows */ + ht_add_ie_t add_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_add_ie ht_prop_add_ie_t; + +#define HT_ADD_IE_LEN 22 +#define HT_ADD_IE_TYPE 52 + +/* byte1 defn's */ +#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ +#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */ + +/* opmode defn's */ +#define HT_OPMODE_MASK 0x0003 /* protection mode mask */ +#define HT_OPMODE_SHIFT 0 /* protection mode shift */ +#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */ +#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ +#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ +#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ +#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ +#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ +#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ + +/* misc_bites defn's */ +#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ +#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ +#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */ +#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ +#define HT_PCO_ACTIVE 0x0400 /* PCO active */ +#define HT_PCO_PHASE 0x0800 /* PCO phase */ +#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */ + +/* Tx Burst Limits */ +#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ +#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ + +/* Macros for opmode */ +#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + >> HT_OPMODE_SHIFT) +#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_MIXED) /* mixed mode present */ +#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_HT20IN40) /* 20MHz HT present */ +#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_OPTIONAL) /* Optional protection present */ +#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ + HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */ +#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ + == HT_OPMODE_NONGF) /* non-GF present */ +#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ + == DOT11N_TXBURST) /* Tx Burst present */ +#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ + == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ + +BWL_PRE_PACKED_STRUCT struct obss_params { + uint16 passive_dwell; + uint16 active_dwell; + uint16 bss_widthscan_interval; + uint16 passive_total; + uint16 active_total; + uint16 chanwidth_transition_dly; + uint16 activity_threshold; +} BWL_POST_PACKED_STRUCT; +typedef struct obss_params obss_params_t; + +BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { + uint8 id; + uint8 len; + obss_params_t obss_params; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_ie dot11_obss_ie_t; +#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */ + +/* HT control field */ +#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */ +#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */ +#define HT_CTRL_LA_MAI_SHIFT 2 +#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */ +#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */ +#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */ +#define HT_CTRL_LA_MFSI_SHIFT 6 +#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */ +#define HT_CTRL_LA_MFB_ASELC_SH 9 +#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */ +#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */ +#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */ +#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */ +#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */ +#define HT_CTRL_CSI_STEER_SHIFT 22 +#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */ +#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */ +#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */ +#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */ +#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */ +#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */ +#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */ + +/* ************* VHT definitions. ************* */ + +/** + * VHT Capabilites IE (sec 8.4.2.160) + */ + +BWL_PRE_PACKED_STRUCT struct vht_cap_ie { + uint32 vht_cap_info; + /* supported MCS set - 64 bit field */ + uint16 rx_mcs_map; + uint16 rx_max_rate; + uint16 tx_mcs_map; + uint16 tx_max_rate; +} BWL_POST_PACKED_STRUCT; +typedef struct vht_cap_ie vht_cap_ie_t; + +/* 4B cap_info + 8B supp_mcs */ +#define VHT_CAP_IE_LEN 12 + +/* VHT Capabilities Info field - 32bit - in VHT Cap IE */ +#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 +#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c +#define VHT_CAP_INFO_LDPC 0x00000010 +#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 +#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 +#define VHT_CAP_INFO_TX_STBC 0x00000080 +#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 +#define VHT_CAP_INFO_RX_STBC_SHIFT 8 +#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 +#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 +#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 +#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 +#define VHT_CAP_INFO_TXOPPS 0x00200000 +#define VHT_CAP_INFO_HTCVHT 0x00400000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 +#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 +#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 + +/* VHT Supported MCS Set - 64-bit - in VHT Cap IE */ +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_MCS_MAP_0_7 0 +#define VHT_CAP_MCS_MAP_0_8 1 +#define VHT_CAP_MCS_MAP_0_9 2 +#define VHT_CAP_MCS_MAP_NONE 3 +#define VHT_CAP_MCS_MAP_S 2 /* num bits for 1-stream */ +#define VHT_CAP_MCS_MAP_M 0x3 /* mask for 1-stream */ +/* assumes VHT_CAP_MCS_MAP_NONE is 3 and 2 bits are used for encoding */ +#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff +/* mcsmap with MCS0-9 for Nss = 3 */ +#define VHT_CAP_MCS_MAP_0_9_NSS3 \ + ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) + +#define VHT_CAP_MCS_MAP_NSS_MAX 8 + +/* get mcsmap with given mcs for given nss streams */ +#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ + do { \ + int i; \ + for (i = 1; i <= nss; i++) { \ + VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ + } \ + } while (0) + +/* Map the mcs code to mcs bit map */ +#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ + ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? 0xff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_8) ? 0x1ff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_9) ? 0x3ff : 0) + +/* Map the mcs bit map to mcs code */ +#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ + ((mcs_map == 0xff) ? VHT_CAP_MCS_MAP_0_7 : \ + (mcs_map == 0x1ff) ? VHT_CAP_MCS_MAP_0_8 : \ + (mcs_map == 0x3ff) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) + +/** VHT Capabilities Supported Channel Width */ +typedef enum vht_cap_chan_width { + VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, + VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, + VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 +} vht_cap_chan_width_t; + +/** VHT Capabilities Supported max MPDU LEN (sec 8.4.2.160.2) */ +typedef enum vht_cap_max_mpdu_len { + VHT_CAP_MPDU_MAX_4K = 0x00, + VHT_CAP_MPDU_MAX_8K = 0x01, + VHT_CAP_MPDU_MAX_11K = 0x02 +} vht_cap_max_mpdu_len_t; + +/* Maximum MPDU Length byte counts for the VHT Capabilities advertised limits */ +#define VHT_MPDU_LIMIT_4K 3895 +#define VHT_MPDU_LIMIT_8K 7991 +#define VHT_MPDU_LIMIT_11K 11454 + + +/** + * VHT Operation IE (sec 8.4.2.161) + */ + +BWL_PRE_PACKED_STRUCT struct vht_op_ie { + uint8 chan_width; + uint8 chan1; + uint8 chan2; + uint16 supp_mcs; /* same def as above in vht cap */ +} BWL_POST_PACKED_STRUCT; +typedef struct vht_op_ie vht_op_ie_t; + +/* 3B VHT Op info + 2B Basic MCS */ +#define VHT_OP_IE_LEN 5 + +typedef enum vht_op_chan_width { + VHT_OP_CHAN_WIDTH_20_40 = 0, + VHT_OP_CHAN_WIDTH_80 = 1, + VHT_OP_CHAN_WIDTH_160 = 2, + VHT_OP_CHAN_WIDTH_80_80 = 3 +} vht_op_chan_width_t; + +/* AID length */ +#define AID_IE_LEN 2 +/** + * BRCM vht features IE header + * The header if the fixed part of the IE + * On the 5GHz band this is the entire IE, + * on 2.4GHz the VHT IEs as defined in the 802.11ac + * specification follows + * + * + * VHT features rates bitmap. + * Bit0: 5G MCS 0-9 BW 160MHz + * Bit1: 5G MCS 0-9 support BW 80MHz + * Bit2: 5G MCS 0-9 support BW 20MHz + * Bit3: 2.4G MCS 0-9 support BW 20MHz + * Bits:4-7 Reserved for future use + * + */ +#define VHT_FEATURES_IE_TYPE 0x4 +BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { + uint8 oui[3]; + uint8 type; /* type of this IE = 4 */ + uint8 rate_mask; /* VHT rate mask */ +} BWL_POST_PACKED_STRUCT; +typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; + +/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ +#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) +#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ + (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) +#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ + do { \ + (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ + (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ + } while (0) +#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ + (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) + + +/* ************* WPA definitions. ************* */ +#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ +#define WPA_OUI_LEN 3 /* WPA OUI length */ +#define WPA_OUI_TYPE 1 +#define WPA_VERSION 1 /* WPA version */ +#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ +#define WPA2_OUI_LEN 3 /* WPA2 OUI length */ +#define WPA2_VERSION 1 /* WPA2 version */ +#define WPA2_VERSION_LEN 2 /* WAP2 version length */ + +/* ************* WPS definitions. ************* */ +#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */ +#define WPS_OUI_LEN 3 /* WPS OUI length */ +#define WPS_OUI_TYPE 4 + +/* ************* WFA definitions. ************* */ + +#ifdef P2P_IE_OVRD +#define WFA_OUI MAC_OUI +#else +#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */ +#endif /* P2P_IE_OVRD */ +#define WFA_OUI_LEN 3 /* WFA OUI length */ +#ifdef P2P_IE_OVRD +#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P +#else +#define WFA_OUI_TYPE_TPC 8 +#define WFA_OUI_TYPE_P2P 9 +#endif + +#define WFA_OUI_TYPE_TPC 8 +#ifdef WLTDLS +#define WFA_OUI_TYPE_TPQ 4 /* WFD Tunneled Probe ReQuest */ +#define WFA_OUI_TYPE_TPS 5 /* WFD Tunneled Probe ReSponse */ +#define WFA_OUI_TYPE_WFD 10 +#endif /* WTDLS */ +#define WFA_OUI_TYPE_HS20 0x10 +#define WFA_OUI_TYPE_OSEN 0x12 +#define WFA_OUI_TYPE_NAN 0x13 + +/* RSN authenticated key managment suite */ +#define RSN_AKM_NONE 0 /* None (IBSS) */ +#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ +#define RSN_AKM_PSK 2 /* Pre-shared Key */ +#define RSN_AKM_FBT_1X 3 /* Fast Bss transition using 802.1X */ +#define RSN_AKM_FBT_PSK 4 /* Fast Bss transition using Pre-shared Key */ +#define RSN_AKM_MFP_1X 5 /* SHA256 key derivation, using 802.1X */ +#define RSN_AKM_MFP_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ +#define RSN_AKM_TPK 7 /* TPK(TDLS Peer Key) handshake */ + +/* OSEN authenticated key managment suite */ +#define OSEN_AKM_UNSPECIFIED RSN_AKM_UNSPECIFIED /* Over 802.1x */ + +/* Key related defines */ +#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */ +#define DOT11_MAX_IGTK_KEYS 2 +#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */ +#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */ +#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */ +#define DOT11_WPA_KEY_RSC_LEN 8 /* WPA RSC key len */ + +#define WEP1_KEY_SIZE 5 /* max size of any WEP key */ +#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */ +#define WEP128_KEY_SIZE 13 /* max size of any WEP key */ +#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */ +#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */ +#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */ +#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */ +#define TKIP_KEY_SIZE 32 /* size of any TKIP key, includs MIC keys */ +#define TKIP_TK_SIZE 16 +#define TKIP_MIC_KEY_SIZE 8 +#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */ +#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */ +#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX /* offset to Supplicant MIC RX key */ +#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX /* offset to Supplicant MIC TX key */ +#define AES_KEY_SIZE 16 /* size of AES key */ +#define AES_MIC_SIZE 8 /* size of AES MIC */ +#define BIP_KEY_SIZE 16 /* size of BIP key */ +#define BIP_MIC_SIZE 8 /* sizeof BIP MIC */ + +#define AES_GCM_MIC_SIZE 16 /* size of MIC for 128-bit GCM - .11adD9 */ + +#define AES256_KEY_SIZE 32 /* size of AES 256 key - .11acD5 */ +#define AES256_MIC_SIZE 16 /* size of MIC for 256 bit keys, incl BIP */ + +/* WCN */ +#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ +#define WCN_TYPE 4 /* WCN type */ + +#ifdef BCMWAPI_WPI +#define SMS4_KEY_LEN 16 +#define SMS4_WPI_CBC_MAC_LEN 16 +#endif + +/* 802.11r protocol definitions */ + +/** Mobility Domain IE */ +BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { + uint8 id; + uint8 len; + uint16 mdid; /* Mobility Domain Id */ + uint8 cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_mdid_ie dot11_mdid_ie_t; + +#define FBT_MDID_CAP_OVERDS 0x01 /* Fast Bss transition over the DS support */ +#define FBT_MDID_CAP_RRP 0x02 /* Resource request protocol support */ + +/** Fast Bss Transition IE */ +BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { + uint8 id; + uint8 len; + uint16 mic_control; /* Mic Control */ + uint8 mic[16]; + uint8 anonce[32]; + uint8 snonce[32]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_ie dot11_ft_ie_t; + +#define TIE_TYPE_RESERVED 0 +#define TIE_TYPE_REASSOC_DEADLINE 1 +#define TIE_TYPE_KEY_LIEFTIME 2 +#define TIE_TYPE_ASSOC_COMEBACK 3 +BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { + uint8 id; + uint8 len; + uint8 type; /* timeout interval type */ + uint32 value; /* timeout interval value */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timeout_ie dot11_timeout_ie_t; + +/** GTK ie */ +BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { + uint8 id; + uint8 len; + uint16 key_info; + uint8 key_len; + uint8 rsc[8]; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_gtk_ie dot11_gtk_ie_t; + +/** Management MIC ie */ +BWL_PRE_PACKED_STRUCT struct mmic_ie { + uint8 id; /* IE ID: DOT11_MNG_MMIE_ID */ + uint8 len; /* IE length */ + uint16 key_id; /* key id */ + uint8 ipn[6]; /* ipn */ + uint8 mic[16]; /* mic */ +} BWL_POST_PACKED_STRUCT; +typedef struct mmic_ie mmic_ie_t; + +#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" +#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" + +#ifdef BCMWAPI_WAI +#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */ +#define WAPI_VERSION 1 /* WAPI version */ +#define WAPI_VERSION_LEN 2 /* WAPI version length */ +#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */ +#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */ +#endif /* BCMWAPI_WAI */ + +/* ************* WMM Parameter definitions. ************* */ +#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */ +#define WMM_OUI_LEN 3 /* WMM OUI length */ +#define WMM_OUI_TYPE 2 /* WMM OUT type */ +#define WMM_VERSION 1 +#define WMM_VERSION_LEN 1 + +/* WMM OUI subtype */ +#define WMM_OUI_SUBTYPE_PARAMETER 1 +#define WMM_PARAMETER_IE_LEN 24 + +/** Link Identifier Element */ +BWL_PRE_PACKED_STRUCT struct link_id_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + struct ether_addr tdls_init_mac; + struct ether_addr tdls_resp_mac; +} BWL_POST_PACKED_STRUCT; +typedef struct link_id_ie link_id_ie_t; +#define TDLS_LINK_ID_IE_LEN 18 + +/** Link Wakeup Schedule Element */ +BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { + uint8 id; + uint8 len; + uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */ + uint32 interval; /* in ms bwtween the start of 2 Awake Windows */ + uint32 awake_win_slots; /* in backof slots, duration of Awake Window */ + uint32 max_wake_win; /* in ms, max duration of Awake Window */ + uint16 idle_cnt; /* number of consecutive Awake Windows */ +} BWL_POST_PACKED_STRUCT; +typedef struct wakeup_sch_ie wakeup_sch_ie_t; +#define TDLS_WAKEUP_SCH_IE_LEN 18 + +/** Channel Switch Timing Element */ +BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { + uint8 id; + uint8 len; + uint16 switch_time; /* in ms, time to switch channels */ + uint16 switch_timeout; /* in ms */ +} BWL_POST_PACKED_STRUCT; +typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; +#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 + +/** PTI Control Element */ +BWL_PRE_PACKED_STRUCT struct pti_control_ie { + uint8 id; + uint8 len; + uint8 tid; + uint16 seq_control; +} BWL_POST_PACKED_STRUCT; +typedef struct pti_control_ie pti_control_ie_t; +#define TDLS_PTI_CONTROL_IE_LEN 3 + +/** PU Buffer Status Element */ +BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { + uint8 id; + uint8 len; + uint8 status; +} BWL_POST_PACKED_STRUCT; +typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; +#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 +#define TDLS_PU_BUFFER_STATUS_AC_BK 1 +#define TDLS_PU_BUFFER_STATUS_AC_BE 2 +#define TDLS_PU_BUFFER_STATUS_AC_VI 4 +#define TDLS_PU_BUFFER_STATUS_AC_VO 8 + +/* TDLS Action Field Values */ +#define TDLS_SETUP_REQ 0 +#define TDLS_SETUP_RESP 1 +#define TDLS_SETUP_CONFIRM 2 +#define TDLS_TEARDOWN 3 +#define TDLS_PEER_TRAFFIC_IND 4 +#define TDLS_CHANNEL_SWITCH_REQ 5 +#define TDLS_CHANNEL_SWITCH_RESP 6 +#define TDLS_PEER_PSM_REQ 7 +#define TDLS_PEER_PSM_RESP 8 +#define TDLS_PEER_TRAFFIC_RESP 9 +#define TDLS_DISCOVERY_REQ 10 + +/* 802.11z TDLS Public Action Frame action field */ +#define TDLS_DISCOVERY_RESP 14 + +/* 802.11u GAS action frames */ +#define GAS_REQUEST_ACTION_FRAME 10 +#define GAS_RESPONSE_ACTION_FRAME 11 +#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 +#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 + +/* 802.11u interworking access network options */ +#define IW_ANT_MASK 0x0f +#define IW_INTERNET_MASK 0x10 +#define IW_ASRA_MASK 0x20 +#define IW_ESR_MASK 0x40 +#define IW_UESA_MASK 0x80 + +/* 802.11u interworking access network type */ +#define IW_ANT_PRIVATE_NETWORK 0 +#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 +#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 +#define IW_ANT_FREE_PUBLIC_NETWORK 3 +#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 +#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 +#define IW_ANT_TEST_NETWORK 14 +#define IW_ANT_WILDCARD_NETWORK 15 + +/* 802.11u advertisement protocol */ +#define ADVP_ANQP_PROTOCOL_ID 0 + +/* 802.11u advertisement protocol masks */ +#define ADVP_QRL_MASK 0x7f +#define ADVP_PAME_BI_MASK 0x80 + +/* 802.11u advertisement protocol values */ +#define ADVP_QRL_REQUEST 0x00 +#define ADVP_QRL_RESPONSE 0x7f +#define ADVP_PAME_BI_DEPENDENT 0x00 +#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK + +/* 802.11u ANQP information ID */ +#define ANQP_ID_QUERY_LIST 256 +#define ANQP_ID_CAPABILITY_LIST 257 +#define ANQP_ID_VENUE_NAME_INFO 258 +#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 +#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 +#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 +#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 +#define ANQP_ID_NAI_REALM_LIST 263 +#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 +#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 +#define ANQP_ID_AP_CIVIC_LOCATION 266 +#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 +#define ANQP_ID_DOMAIN_NAME_LIST 268 +#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 +#define ANQP_ID_EMERGENCY_NAI 271 +#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 + +/* 802.11u ANQP OUI */ +#define ANQP_OUI_SUBTYPE 9 + +/* 802.11u venue name */ +#define VENUE_LANGUAGE_CODE_SIZE 3 +#define VENUE_NAME_SIZE 255 + +/* 802.11u venue groups */ +#define VENUE_UNSPECIFIED 0 +#define VENUE_ASSEMBLY 1 +#define VENUE_BUSINESS 2 +#define VENUE_EDUCATIONAL 3 +#define VENUE_FACTORY 4 +#define VENUE_INSTITUTIONAL 5 +#define VENUE_MERCANTILE 6 +#define VENUE_RESIDENTIAL 7 +#define VENUE_STORAGE 8 +#define VENUE_UTILITY 9 +#define VENUE_VEHICULAR 10 +#define VENUE_OUTDOOR 11 + +/* 802.11u network authentication type indicator */ +#define NATI_UNSPECIFIED -1 +#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 +#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 +#define NATI_HTTP_HTTPS_REDIRECTION 2 +#define NATI_DNS_REDIRECTION 3 + +/* 802.11u IP address type availability - IPv6 */ +#define IPA_IPV6_SHIFT 0 +#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) +#define IPA_IPV6_NOT_AVAILABLE 0x00 +#define IPA_IPV6_AVAILABLE 0x01 +#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 + +/* 802.11u IP address type availability - IPv4 */ +#define IPA_IPV4_SHIFT 2 +#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) +#define IPA_IPV4_NOT_AVAILABLE 0x00 +#define IPA_IPV4_PUBLIC 0x01 +#define IPA_IPV4_PORT_RESTRICT 0x02 +#define IPA_IPV4_SINGLE_NAT 0x03 +#define IPA_IPV4_DOUBLE_NAT 0x04 +#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 +#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 +#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 + +/* 802.11u NAI realm encoding */ +#define REALM_ENCODING_RFC4282 0 +#define REALM_ENCODING_UTF8 1 + +/* 802.11u IANA EAP method type numbers */ +#define REALM_EAP_TLS 13 +#define REALM_EAP_LEAP 17 +#define REALM_EAP_SIM 18 +#define REALM_EAP_TTLS 21 +#define REALM_EAP_AKA 23 +#define REALM_EAP_PEAP 25 +#define REALM_EAP_FAST 43 +#define REALM_EAP_PSK 47 +#define REALM_EAP_AKAP 50 +#define REALM_EAP_EXPANDED 254 + +/* 802.11u authentication ID */ +#define REALM_EXPANDED_EAP 1 +#define REALM_NON_EAP_INNER_AUTHENTICATION 2 +#define REALM_INNER_AUTHENTICATION_EAP 3 +#define REALM_EXPANDED_INNER_EAP 4 +#define REALM_CREDENTIAL 5 +#define REALM_TUNNELED_EAP_CREDENTIAL 6 +#define REALM_VENDOR_SPECIFIC_EAP 221 + +/* 802.11u non-EAP inner authentication type */ +#define REALM_RESERVED_AUTH 0 +#define REALM_PAP 1 +#define REALM_CHAP 2 +#define REALM_MSCHAP 3 +#define REALM_MSCHAPV2 4 + +/* 802.11u credential type */ +#define REALM_SIM 1 +#define REALM_USIM 2 +#define REALM_NFC 3 +#define REALM_HARDWARE_TOKEN 4 +#define REALM_SOFTOKEN 5 +#define REALM_CERTIFICATE 6 +#define REALM_USERNAME_PASSWORD 7 +#define REALM_SERVER_SIDE 8 +#define REALM_RESERVED_CRED 9 +#define REALM_VENDOR_SPECIFIC_CRED 10 + +/* 802.11u 3GPP PLMN */ +#define G3PP_GUD_VERSION 0 +#define G3PP_PLMN_LIST_IE 0 + +/** hotspot2.0 indication element (vendor specific) */ +BWL_PRE_PACKED_STRUCT struct hs20_ie { + uint8 oui[3]; + uint8 type; + uint8 config; +} BWL_POST_PACKED_STRUCT; +typedef struct hs20_ie hs20_ie_t; +#define HS20_IE_LEN 5 /* HS20 IE length */ + +/** IEEE 802.11 Annex E */ +typedef enum { + DOT11_2GHZ_20MHZ_CLASS_12 = 81, /* Ch 1-11 */ + DOT11_5GHZ_20MHZ_CLASS_1 = 115, /* Ch 36-48 */ + DOT11_5GHZ_20MHZ_CLASS_2_DFS = 118, /* Ch 52-64 */ + DOT11_5GHZ_20MHZ_CLASS_3 = 124, /* Ch 149-161 */ + DOT11_5GHZ_20MHZ_CLASS_4_DFS = 121, /* Ch 100-140 */ + DOT11_5GHZ_20MHZ_CLASS_5 = 125, /* Ch 149-165 */ + DOT11_5GHZ_40MHZ_CLASS_22 = 116, /* Ch 36-44, lower */ + DOT11_5GHZ_40MHZ_CLASS_23_DFS = 119, /* Ch 52-60, lower */ + DOT11_5GHZ_40MHZ_CLASS_24_DFS = 122, /* Ch 100-132, lower */ + DOT11_5GHZ_40MHZ_CLASS_25 = 126, /* Ch 149-157, lower */ + DOT11_5GHZ_40MHZ_CLASS_27 = 117, /* Ch 40-48, upper */ + DOT11_5GHZ_40MHZ_CLASS_28_DFS = 120, /* Ch 56-64, upper */ + DOT11_5GHZ_40MHZ_CLASS_29_DFS = 123, /* Ch 104-136, upper */ + DOT11_5GHZ_40MHZ_CLASS_30 = 127, /* Ch 153-161, upper */ + DOT11_2GHZ_40MHZ_CLASS_32 = 83, /* Ch 1-7, lower */ + DOT11_2GHZ_40MHZ_CLASS_33 = 84, /* Ch 5-11, upper */ +} dot11_op_class_t; + +/* QoS map */ +#define QOS_MAP_FIXED_LENGTH (8 * 2) /* DSCP ranges fixed with 8 entries */ + +#define BCM_AIBSS_IE_TYPE 56 + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11_bta.h new file mode 100644 index 000000000000..9de5616ab024 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11_bta.h @@ -0,0 +1,45 @@ +/* + * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: 802.11_bta.h 382882 2013-02-04 23:24:31Z $ +*/ + +#ifndef _802_11_BTA_H_ +#define _802_11_BTA_H_ + +#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58" + +/* BT-AMP 802.11 PAL Protocols */ +#define BTA_PROT_L2CAP 1 +#define BTA_PROT_ACTIVITY_REPORT 2 +#define BTA_PROT_SECURITY 3 +#define BTA_PROT_LINK_SUPERVISION_REQUEST 4 +#define BTA_PROT_LINK_SUPERVISION_REPLY 5 + +/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */ +#define BTA_TYPE_ID_MAC_ADDRESS 1 +#define BTA_TYPE_ID_PREFERRED_CHANNELS 2 +#define BTA_TYPE_ID_CONNECTED_CHANNELS 3 +#define BTA_TYPE_ID_CAPABILITIES 4 +#define BTA_TYPE_ID_VERSION 5 +#endif /* _802_11_bta_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11e.h new file mode 100644 index 000000000000..ded6b7612415 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11e.h @@ -0,0 +1,138 @@ +/* + * 802.11e protocol header file + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: 802.11e.h 382883 2013-02-04 23:26:09Z $ + */ + +#ifndef _802_11e_H_ +#define _802_11e_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + + +/* WME Traffic Specification (TSPEC) element */ +#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ +#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ + +#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ +#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ +#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ +#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ + +BWL_PRE_PACKED_STRUCT struct tsinfo { + uint8 octets[3]; +} BWL_POST_PACKED_STRUCT; + +typedef struct tsinfo tsinfo_t; + +/* 802.11e TSPEC IE */ +typedef BWL_PRE_PACKED_STRUCT struct tspec { + uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ + uint8 type; /* WME_TYPE */ + uint8 subtype; /* WME_SUBTYPE_TSPEC */ + uint8 version; /* WME_VERSION */ + tsinfo_t tsinfo; /* TS Info bit field */ + uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ + uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ + uint32 min_srv_interval; /* Minimum Service Interval (us) */ + uint32 max_srv_interval; /* Maximum Service Interval (us) */ + uint32 inactivity_interval; /* Inactivity Interval (us) */ + uint32 suspension_interval; /* Suspension Interval (us) */ + uint32 srv_start_time; /* Service Start Time (us) */ + uint32 min_data_rate; /* Minimum Data Rate (bps) */ + uint32 mean_data_rate; /* Mean Data Rate (bps) */ + uint32 peak_data_rate; /* Peak Data Rate (bps) */ + uint32 max_burst_size; /* Maximum Burst Size (bytes) */ + uint32 delay_bound; /* Delay Bound (us) */ + uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ + uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ + uint16 medium_time; /* Medium Time (32 us/s periods) */ +} BWL_POST_PACKED_STRUCT tspec_t; + +#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ + +/* ts_info */ +/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ +#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ +#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ +#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ +#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ +#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ +#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ +#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ +#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ +#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ +#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ +#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ +#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ +/* TS info. user priority mask */ +#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) + +/* Macro to get/set bit(s) field in TSINFO */ +#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) +#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ + TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) +#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) +#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ + TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) + +#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ + ((id) << TS_INFO_TID_SHIFT)) +#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ + ((prio) << TS_INFO_USER_PRIO_SHIFT)) + +/* 802.11e QBSS Load IE */ +#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ +#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ + +#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */ + /* DEFVAL dot11ADDTSResponseTimeout = 1s */ + +/* 802.11e ADDTS status code */ +#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ +#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ +#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ +#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ +#ifdef BCMCCX +#define CCX_STATUS_ASSOC_DENIED_UNKNOWN 0xc8 /* unspecified QoS related failure */ +#define CCX_STATUS_ASSOC_DENIED_AP_POLICY 0xc9 /* TSPEC refused due to AP policy */ +#define CCX_STATUS_ASSOC_DENIED_NO_BW 0xca /* Assoc denied due to AP insufficient BW */ +#define CCX_STATUS_ASSOC_DENIED_BAD_PARAM 0xcb /* one or more TSPEC with invalid parameter */ +#endif /* BCMCCX */ + +/* 802.11e DELTS status code */ +#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ +#define DOT11E_STATUS_END_TS 37 /* END TS */ +#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ +#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ + + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11e_CAC_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.1d.h new file mode 100644 index 000000000000..efb390bfc09e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.1d.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental types and constants relating to 802.1D + * + * $Id: 802.1d.h 382882 2013-02-04 23:24:31Z $ + */ + +#ifndef _802_1_D_ +#define _802_1_D_ + +/* 802.1D priority defines */ +#define PRIO_8021D_NONE 2 /* None = - */ +#define PRIO_8021D_BK 1 /* BK - Background */ +#define PRIO_8021D_BE 0 /* BE - Best-effort */ +#define PRIO_8021D_EE 3 /* EE - Excellent-effort */ +#define PRIO_8021D_CL 4 /* CL - Controlled Load */ +#define PRIO_8021D_VI 5 /* Vi - Video */ +#define PRIO_8021D_VO 6 /* Vo - Voice */ +#define PRIO_8021D_NC 7 /* NC - Network Control */ +#define MAXPRIO 7 /* 0-7 */ +#define NUMPRIO (MAXPRIO + 1) + +#define ALLPRIO -1 /* All prioirty */ + +/* Converts prio to precedence since the numerical value of + * PRIO_8021D_BE and PRIO_8021D_NONE are swapped. + */ +#define PRIO2PREC(prio) \ + (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) + +#endif /* _802_1_D__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.3.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.3.h new file mode 100644 index 000000000000..dc1626aa667a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.3.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental constants relating to 802.3 + * + * $Id: 802.3.h 417943 2013-08-13 07:54:04Z $ + */ + +#ifndef _802_3_h_ +#define _802_3_h_ + +/* This marks the start of a packed structure section. */ +#include + +#define SNAP_HDR_LEN 6 /* 802.3 SNAP header length */ +#define DOT3_OUI_LEN 3 /* 802.3 oui length */ + +BWL_PRE_PACKED_STRUCT struct dot3_mac_llc_snap_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ + uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ + uint16 length; /* frame length incl header */ + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[DOT3_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 type; /* ethertype */ +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include + +#endif /* #ifndef _802_3_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmdhcp.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmdhcp.h new file mode 100644 index 000000000000..1e4bff7d9ed0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmdhcp.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental constants relating to DHCP Protocol + * + * $Id: bcmdhcp.h 528443 2015-01-22 09:29:18Z $ + */ + +#ifndef _bcmdhcp_h_ +#define _bcmdhcp_h_ + +/* DHCP params */ +#define DHCP_TYPE_OFFSET 0 /* DHCP type (request|reply) offset */ +#define DHCP_TID_OFFSET 4 /* DHCP transition id offset */ +#define DHCP_FLAGS_OFFSET 10 /* DHCP flags offset */ +#define DHCP_CIADDR_OFFSET 12 /* DHCP client IP address offset */ +#define DHCP_YIADDR_OFFSET 16 /* DHCP your IP address offset */ +#define DHCP_GIADDR_OFFSET 24 /* DHCP relay agent IP address offset */ +#define DHCP_CHADDR_OFFSET 28 /* DHCP client h/w address offset */ +#define DHCP_OPT_OFFSET 236 /* DHCP options offset */ + +#define DHCP_OPT_MSGTYPE 53 /* DHCP message type */ +#define DHCP_OPT_MSGTYPE_REQ 3 +#define DHCP_OPT_MSGTYPE_ACK 5 /* DHCP message type - ACK */ + +#define DHCP_OPT_CODE_OFFSET 0 /* Option identifier */ +#define DHCP_OPT_LEN_OFFSET 1 /* Option data length */ +#define DHCP_OPT_DATA_OFFSET 2 /* Option data */ + +#define DHCP_OPT_CODE_CLIENTID 61 /* Option identifier */ + +#define DHCP_TYPE_REQUEST 1 /* DHCP request (discover|request) */ +#define DHCP_TYPE_REPLY 2 /* DHCP reply (offset|ack) */ + +#define DHCP_PORT_SERVER 67 /* DHCP server UDP port */ +#define DHCP_PORT_CLIENT 68 /* DHCP client UDP port */ + +#define DHCP_FLAG_BCAST 0x8000 /* DHCP broadcast flag */ + +#define DHCP_FLAGS_LEN 2 /* DHCP flags field length */ + +#define DHCP6_TYPE_SOLICIT 1 /* DHCP6 solicit */ +#define DHCP6_TYPE_ADVERTISE 2 /* DHCP6 advertise */ +#define DHCP6_TYPE_REQUEST 3 /* DHCP6 request */ +#define DHCP6_TYPE_CONFIRM 4 /* DHCP6 confirm */ +#define DHCP6_TYPE_RENEW 5 /* DHCP6 renew */ +#define DHCP6_TYPE_REBIND 6 /* DHCP6 rebind */ +#define DHCP6_TYPE_REPLY 7 /* DHCP6 reply */ +#define DHCP6_TYPE_RELEASE 8 /* DHCP6 release */ +#define DHCP6_TYPE_DECLINE 9 /* DHCP6 decline */ +#define DHCP6_TYPE_RECONFIGURE 10 /* DHCP6 reconfigure */ +#define DHCP6_TYPE_INFOREQ 11 /* DHCP6 information request */ +#define DHCP6_TYPE_RELAYFWD 12 /* DHCP6 relay forward */ +#define DHCP6_TYPE_RELAYREPLY 13 /* DHCP6 relay reply */ + +#define DHCP6_TYPE_OFFSET 0 /* DHCP6 type offset */ + +#define DHCP6_MSG_OPT_OFFSET 4 /* Offset of options in client server messages */ +#define DHCP6_RELAY_OPT_OFFSET 34 /* Offset of options in relay messages */ + +#define DHCP6_OPT_CODE_OFFSET 0 /* Option identifier */ +#define DHCP6_OPT_LEN_OFFSET 2 /* Option data length */ +#define DHCP6_OPT_DATA_OFFSET 4 /* Option data */ + +#define DHCP6_OPT_CODE_CLIENTID 1 /* DHCP6 CLIENTID option */ +#define DHCP6_OPT_CODE_SERVERID 2 /* DHCP6 SERVERID option */ + +#define DHCP6_PORT_SERVER 547 /* DHCP6 server UDP port */ +#define DHCP6_PORT_CLIENT 546 /* DHCP6 client UDP port */ + +#endif /* #ifndef _bcmdhcp_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmeth.h new file mode 100644 index 000000000000..2657d2fdf5ab --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmeth.h @@ -0,0 +1,112 @@ +/* + * Broadcom Ethernettype protocol definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmeth.h 445746 2013-12-30 12:57:26Z $ + */ + +/* + * Broadcom Ethernet protocol defines + */ + +#ifndef _BCMETH_H_ +#define _BCMETH_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +/* ETHER_TYPE_BRCM is defined in ethernet.h */ + +/* + * Following the 2byte BRCM ether_type is a 16bit BRCM subtype field + * in one of two formats: (only subtypes 32768-65535 are in use now) + * + * subtypes 0-32767: + * 8 bit subtype (0-127) + * 8 bit length in bytes (0-255) + * + * subtypes 32768-65535: + * 16 bit big-endian subtype + * 16 bit big-endian length in bytes (0-65535) + * + * length is the number of additional bytes beyond the 4 or 6 byte header + * + * Reserved values: + * 0 reserved + * 5-15 reserved for iLine protocol assignments + * 17-126 reserved, assignable + * 127 reserved + * 32768 reserved + * 32769-65534 reserved, assignable + * 65535 reserved + */ + +/* + * While adding the subtypes and their specific processing code make sure + * bcmeth_bcm_hdr_t is the first data structure in the user specific data structure definition + */ + +#define BCMILCP_SUBTYPE_RATE 1 +#define BCMILCP_SUBTYPE_LINK 2 +#define BCMILCP_SUBTYPE_CSA 3 +#define BCMILCP_SUBTYPE_LARQ 4 +#define BCMILCP_SUBTYPE_VENDOR 5 +#define BCMILCP_SUBTYPE_FLH 17 + +#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 +#define BCMILCP_SUBTYPE_CERT 32770 +#define BCMILCP_SUBTYPE_SES 32771 + + +#define BCMILCP_BCM_SUBTYPE_RESERVED 0 +#define BCMILCP_BCM_SUBTYPE_EVENT 1 +#define BCMILCP_BCM_SUBTYPE_SES 2 +/* + * The EAPOL type is not used anymore. Instead EAPOL messages are now embedded + * within BCMILCP_BCM_SUBTYPE_EVENT type messages + */ +/* #define BCMILCP_BCM_SUBTYPE_EAPOL 3 */ +#define BCMILCP_BCM_SUBTYPE_DPT 4 + +#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 +#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 + +/* These fields are stored in network order */ +typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr +{ + uint16 subtype; /* Vendor specific..32769 */ + uint16 length; + uint8 version; /* Version is 0 */ + uint8 oui[3]; /* Broadcom OUI */ + /* user specific Data */ + uint16 usr_subtype; +} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; + + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _BCMETH_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmevent.h new file mode 100644 index 000000000000..c0894a097cb9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmevent.h @@ -0,0 +1,529 @@ +/* + * Broadcom Event protocol definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Dependencies: proto/bcmeth.h + * + * $Id: bcmevent.h 642286 2016-06-08 05:57:20Z $ + * + */ + +/* + * Broadcom Ethernet Events protocol defines + * + */ + +#ifndef _BCMEVENT_H_ +#define _BCMEVENT_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif +/* #include -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */ +#include + +/* This marks the start of a packed structure section. */ +#include + +#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */ +#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */ + +/* flags */ +#define WLC_EVENT_MSG_LINK 0x01 /* link is up */ +#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */ +#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ +#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */ +#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */ + +/* these fields are stored in network order */ + +/* version 1 */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; + uint16 flags; /* see flags below */ + uint32 event_type; /* Message (see below) */ + uint32 status; /* Status code (see below) */ + uint32 reason; /* Reason code (if applicable) */ + uint32 auth_type; /* WLC_E_AUTH */ + uint32 datalen; /* data buf */ + struct ether_addr addr; /* Station address (if applicable) */ + char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ +} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; + +/* the current version */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; + uint16 flags; /* see flags below */ + uint32 event_type; /* Message (see below) */ + uint32 status; /* Status code (see below) */ + uint32 reason; /* Reason code (if applicable) */ + uint32 auth_type; /* WLC_E_AUTH */ + uint32 datalen; /* data buf */ + struct ether_addr addr; /* Station address (if applicable) */ + char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ + uint8 ifidx; /* destination OS i/f index */ + uint8 bsscfgidx; /* source bsscfg index */ +} BWL_POST_PACKED_STRUCT wl_event_msg_t; + +/* used by driver msgs */ +typedef BWL_PRE_PACKED_STRUCT struct bcm_event { + struct ether_header eth; + bcmeth_hdr_t bcm_hdr; + wl_event_msg_t event; + /* data portion follows */ +} BWL_POST_PACKED_STRUCT bcm_event_t; + +#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) + +/* Event messages */ +#define WLC_E_SET_SSID 0 /* indicates status of set SSID */ +#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */ +#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */ +#define WLC_E_AUTH 3 /* 802.11 AUTH request */ +#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */ +#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */ +#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */ +#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */ +#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */ +#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */ +#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */ +#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */ +#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */ +#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */ +#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */ +#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */ +#define WLC_E_LINK 16 /* generic link indication */ +#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */ +#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */ +#define WLC_E_ROAM 19 /* roam attempt occurred: indicate status & reason */ +#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */ +#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */ +#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */ +#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */ +#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */ +#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */ +#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */ +#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */ +#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */ +#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */ +#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */ +#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */ +#define WLC_E_ROAM_PREP 32 /* before attempting to roam */ +#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */ +#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */ +#define WLC_E_RESET_COMPLETE 35 +#define WLC_E_JOIN_START 36 +#define WLC_E_ROAM_START 37 +#define WLC_E_ASSOC_START 38 +#define WLC_E_IBSS_ASSOC 39 +#define WLC_E_RADIO 40 +#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */ +#define WLC_E_PROBREQ_MSG 44 /* probe request received */ +#define WLC_E_SCAN_CONFIRM_IND 45 +#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */ +#define WLC_E_COUNTRY_CODE_CHANGED 47 +#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */ +#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */ +#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */ +#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ +#define WLC_E_TRACE 52 +#define WLC_E_IF 54 /* I/F change (for dongle host notification) */ +#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */ +#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */ +#define WLC_E_PFN_BEST_BATCHING 57 /* PFN best network batching event */ +#define WLC_E_EXTLOG_MSG 58 +#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */ +#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ +#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */ +#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */ +#define WLC_E_CHANNEL_ADOPTED 63 +#define WLC_E_AP_STARTED 64 /* AP started */ +#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */ +#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */ +#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */ +#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */ +#define WLC_E_ESCAN_RESULT 69 /* escan result event */ +#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */ +#define WLC_E_PROBRESP_MSG 71 /* probe response received */ +#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */ +#define WLC_E_DCS_REQUEST 73 +#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */ +#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH + * wl_event_rx_frame_data_t header + */ +#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */ +#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */ +#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */ +#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */ +#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */ +#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */ +#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */ +/* PFN BSSID network found event, conflict/share with WLC_E_PFN_SCAN_NONE */ +#define WLC_E_PFN_BSSID_NET_FOUND 82 +#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */ +/* PFN BSSID network lost event, conflict/share with WLC_E_PFN_SCAN_ALLGONE */ +#define WLC_E_PFN_BSSID_NET_LOST 83 +#define WLC_E_GTK_PLUMBED 84 +#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */ +#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */ +#define WLC_E_ASSOC_REQ_IE 87 +#define WLC_E_ASSOC_RESP_IE 88 +#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ +#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */ +#define WLC_E_AUTH_REQ 91 /* authentication request received */ +#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected/disconnected peer */ +#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */ +#define WLC_E_NATIVE 94 /* port-specific event and payload (e.g. NDIS) */ +#define WLC_E_PKTDELAY_IND 95 /* event for tx pkt delay suddently jump */ +#define WLC_E_PSTA_PRIMARY_INTF_IND 99 /* psta primary interface indication */ +#define WLC_E_NAN 100 /* NAN event */ +#define WLC_E_BEACON_FRAME_RX 101 +#define WLC_E_SERVICE_FOUND 102 /* desired service found */ +#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ +#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ +#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ +#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ +#define WLC_E_WNM_STA_SLEEP 107 /* WNM event to notify STA enter sleep mode */ +#define WLC_E_TXFAIL_THRESH 108 /* Indication of MAC tx failures (exhaustion of + * 802.11 retries) exceeding threshold(s) + */ +#define WLC_E_PROXD 109 /* Proximity Detection event */ +#define WLC_E_IBSS_COALESCE 110 /* IBSS Coalescing */ +#define WLC_E_AIBSS_TXFAIL 110 /* TXFAIL event for AIBSS, re using event 110 */ +#define WLC_E_BSS_LOAD 114 /* Inform host of beacon bss load */ +#define WLC_E_CSA_START_IND 121 +#define WLC_E_CSA_DONE_IND 122 +#define WLC_E_CSA_FAILURE_IND 123 +#define WLC_E_CCA_CHAN_QUAL 124 /* CCA based channel quality report */ +#define WLC_E_BSSID 125 /* to report change in BSSID while roaming */ +#define WLC_E_TX_STAT_ERROR 126 /* tx error indication */ +#define WLC_E_BCMC_CREDIT_SUPPORT 127 /* credit check for BCMC supported */ +#define WLC_E_BT_WIFI_HANDOVER_REQ 130 /* Handover Request Initiated */ +#define WLC_E_SPW_TXINHIBIT 131 /* Southpaw TxInhibit notification */ +#define WLC_E_FBT_AUTH_REQ_IND 132 /* FBT Authentication Request Indication */ +#define WLC_E_RSSI_LQM 133 /* Enhancement addition for WLC_E_RSSI */ +#define WLC_E_PFN_GSCAN_FULL_RESULT 134 /* Full probe/beacon (IEs etc) results */ +#define WLC_E_PFN_SWC 135 /* Significant change in rssi of bssids being tracked */ +#define WLC_E_PFN_SCAN_COMPLETE 138 /* PFN completed scan of network list */ +#define WLC_E_RMC_EVENT 139 /* RMC event */ +#define WLC_E_PFN_SSID_EXT 142 /* SSID EXT event */ +#define WLC_E_LAST 143 /* highest val + 1 for range checking */ + +#if (WLC_E_LAST > 143) +#error "WLC_E_LAST: Invalid value for last event; must be <= 140." +#endif /* WLC_E_LAST */ + +/* define an API for getting the string name of an event */ +extern const char *bcmevent_get_name(uint event_type); + +/* validate if the event is proper and if valid copy event header to event */ +extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, + void *out_event); + + + +/* Event status codes */ +#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */ +#define WLC_E_STATUS_FAIL 1 /* operation failed */ +#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */ +#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */ +#define WLC_E_STATUS_ABORT 4 /* operation was aborted */ +#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */ +#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */ +#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */ +#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */ +#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */ +#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */ +#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */ +#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */ +#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */ +#ifdef BCMCCX +#define WLC_E_STATUS_CCXFASTRM 14 /* scan aborted due to CCX fast roam */ +#endif /* BCMCCX */ +#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */ +#define WLC_E_STATUS_ERROR 16 /* request failed due to error */ +#define WLC_E_STATUS_INVALID 0xff /* Invalid status code to init variables. */ + + +/* roam reason codes */ +#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */ +#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */ +#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ +#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ +#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ + +#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ +#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ +#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ +#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ +#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ +#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ +/* retained for precommit auto-merging errors; remove once all branches are synced */ +#define WLC_E_REASON_REQUESTED_ROAM 11 +#define WLC_E_REASON_BSSTRANS_REQ 11 /* roamed due to BSS Transition request by AP */ + +/* prune reason codes */ +#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ +#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ +#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ +#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ +#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ +#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ +#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ +#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ +#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ +#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ +#ifdef BCMCCX +#define WLC_E_PRUNE_CCXFAST_PREVAP 11 /* CCX FAST ROAM: prune previous AP */ +#endif /* def BCMCCX */ +#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ +#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ +#ifdef BCMCCX +#define WLC_E_PRUNE_CCXFAST_DROAM 14 /* CCX FAST ROAM: prune unqualified AP */ +#endif /* def BCMCCX */ +#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ +#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ +#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ +#ifdef BCMCCX +#define WLC_E_PRUNE_AP_BLOCKED 18 /* prune blocked AP */ +#define WLC_E_PRUNE_NO_DIAG_SUPPORT 19 /* prune due to diagnostic mode not supported */ +#endif /* BCMCCX */ + +/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */ +#define WLC_E_SUP_OTHER 0 /* Other reason */ +#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */ +#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */ +#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */ +#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */ +#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */ +#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */ +#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */ +#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */ +#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */ +#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */ +#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */ +#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */ +#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */ +#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */ +#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */ + +/* Event data for events that include frames received over the air */ +/* WLC_E_PROBRESP_MSG + * WLC_E_P2P_PROBREQ_MSG + * WLC_E_ACTION_FRAME_RX + */ +typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { + uint16 version; + uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */ + int32 rssi; + uint32 mactime; + uint32 rate; +} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; + +#define BCM_RX_FRAME_DATA_VERSION 1 + +/* WLC_E_IF event data */ +typedef struct wl_event_data_if { + uint8 ifidx; /* RTE virtual device index (for dongle) */ + uint8 opcode; /* see I/F opcode */ + uint8 reserved; /* bit mask (WLC_E_IF_FLAGS_XXX ) */ + uint8 bssidx; /* bsscfg index */ + uint8 role; /* see I/F role */ +} wl_event_data_if_t; + +/* opcode in WLC_E_IF event */ +#define WLC_E_IF_ADD 1 /* bsscfg add */ +#define WLC_E_IF_DEL 2 /* bsscfg delete */ +#define WLC_E_IF_CHANGE 3 /* bsscfg role change */ + +/* I/F role code in WLC_E_IF event */ +#define WLC_E_IF_ROLE_STA 0 /* Infra STA */ +#define WLC_E_IF_ROLE_AP 1 /* Access Point */ +#define WLC_E_IF_ROLE_WDS 2 /* WDS link */ +#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ +#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ + +/* WLC_E_RSSI event data */ +typedef struct wl_event_data_rssi { + int32 rssi; + int32 snr; + int32 noise; +} wl_event_data_rssi_t; + +/* WLC_E_IF flag */ +#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 /* no host I/F creation needed */ + +/* Reason codes for LINK */ +#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */ +#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */ +#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */ +#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */ + +/* reason codes for WLC_E_OVERLAY_REQ event */ +#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */ +#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */ + +/* reason codes for WLC_E_TDLS_PEER_EVENT event */ +#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */ +#define WLC_E_TDLS_PEER_CONNECTED 1 +#define WLC_E_TDLS_PEER_DISCONNECTED 2 + +/* reason codes for WLC_E_RMC_EVENT event */ +#define WLC_E_REASON_RMC_NONE 0 +#define WLC_E_REASON_RMC_AR_LOST 1 +#define WLC_E_REASON_RMC_AR_NO_ACK 2 + +#ifdef WLTDLS +/* TDLS Action Category code */ +#define TDLS_AF_CATEGORY 12 +/* Wi-Fi Display (WFD) Vendor Specific Category */ +/* used for WFD Tunneled Probe Request and Response */ +#define TDLS_VENDOR_SPECIFIC 127 +/* TDLS Action Field Values */ +#define TDLS_ACTION_SETUP_REQ 0 +#define TDLS_ACTION_SETUP_RESP 1 +#define TDLS_ACTION_SETUP_CONFIRM 2 +#define TDLS_ACTION_TEARDOWN 3 +#define WLAN_TDLS_SET_PROBE_WFD_IE 11 +#define WLAN_TDLS_SET_SETUP_WFD_IE 12 +#endif + + +/* GAS event data */ +typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { + uint16 channel; /* channel of GAS protocol */ + uint8 dialog_token; /* GAS dialog token */ + uint8 fragment_id; /* fragment id */ + uint16 status_code; /* status code on GAS completion */ + uint16 data_len; /* length of data to follow */ + uint8 data[1]; /* variable length specified by data_len */ +} BWL_POST_PACKED_STRUCT wl_event_gas_t; + +/* service discovery TLV */ +typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { + uint16 length; /* length of response_data */ + uint8 protocol; /* service protocol type */ + uint8 transaction_id; /* service transaction id */ + uint8 status_code; /* status code */ + uint8 data[1]; /* response data */ +} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; + +/* service discovery event data */ +typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { + uint16 channel; /* channel */ + uint8 count; /* number of tlvs */ + wl_sd_tlv_t tlv[1]; /* service discovery TLV */ +} BWL_POST_PACKED_STRUCT wl_event_sd_t; + +/* Reason codes for WLC_E_PROXD */ +#define WLC_E_PROXD_FOUND 1 /* Found a proximity device */ +#define WLC_E_PROXD_GONE 2 /* Lost a proximity device */ +#define WLC_E_PROXD_START 3 /* used by: target */ +#define WLC_E_PROXD_STOP 4 /* used by: target */ +#define WLC_E_PROXD_COMPLETED 5 /* used by: initiator completed */ +#define WLC_E_PROXD_ERROR 6 /* used by both initiator and target */ +#define WLC_E_PROXD_COLLECT_START 7 /* used by: target & initiator */ +#define WLC_E_PROXD_COLLECT_STOP 8 /* used by: target */ +#define WLC_E_PROXD_COLLECT_COMPLETED 9 /* used by: initiator completed */ +#define WLC_E_PROXD_COLLECT_ERROR 10 /* used by both initiator and target */ +#define WLC_E_PROXD_NAN_EVENT 11 /* used by both initiator and target */ + +/* proxd_event data */ +typedef struct ftm_sample { + uint32 value; /* RTT in ns */ + int8 rssi; /* RSSI */ +} ftm_sample_t; + +typedef BWL_PRE_PACKED_STRUCT struct proxd_event_data { + uint16 ver; /* version */ + uint16 mode; /* mode: target/initiator */ + uint16 method; /* method: rssi/TOF/AOA */ + uint8 err_code; /* error classification */ + uint8 TOF_type; /* one way or two way TOF */ + uint8 OFDM_frame_type; /* legacy or VHT */ + uint8 bandwidth; /* Bandwidth is 20, 40,80, MHZ */ + struct ether_addr peer_mac; /* (e.g for tgt:initiator's */ + uint32 distance; /* dst to tgt, units meter */ + uint32 meanrtt; /* mean delta */ + uint32 modertt; /* Mode delta */ + uint32 medianrtt; /* median RTT */ + uint32 sdrtt; /* Standard deviation of RTT */ + int gdcalcresult; /* Software or Hardware Kind of redundant, but if */ + /* frame type is VHT, then we should do it by hardware */ + int16 avg_rssi; /* avg rssi accroos the ftm frames */ + int16 validfrmcnt; /* Firmware's valid frame counts */ + char *peer_router_info; /* Peer router information if available in TLV, */ + /* We will add this field later */ + int32 var1; /* average of group delay */ + int32 var2; /* average of threshold crossing */ + int32 var3; /* difference between group delay and threshold crossing */ + /* raw Fine Time Measurements (ftm) data */ + uint16 ftm_unit; /* ftm cnt resolution in picoseconds , 6250ps - default */ + uint16 ftm_cnt; /* num of rtd measurments/length in the ftm buffer */ + ftm_sample_t ftm_buff[1]; /* 1 ... ftm_cnt */ +} BWL_POST_PACKED_STRUCT wl_proxd_event_data_t; + + +/* Video Traffic Interference Monitor Event */ +#define INTFER_EVENT_VERSION 1 +#define INTFER_STREAM_TYPE_NONTCP 1 +#define INTFER_STREAM_TYPE_TCP 2 +#define WLINTFER_STATS_NSMPLS 4 +typedef struct wl_intfer_event { + uint16 version; /* version */ + uint16 status; /* status */ + uint8 txfail_histo[WLINTFER_STATS_NSMPLS]; /* txfail histo */ +} wl_intfer_event_t; + +/* WLC_E_PSTA_PRIMARY_INTF_IND event data */ +typedef struct wl_psta_primary_intf_event { + struct ether_addr prim_ea; /* primary intf ether addr */ +} wl_psta_primary_intf_event_t; + + +/* ********** NAN protocol events/subevents ********** */ +#define NAN_EVENT_BUFFER_SIZE 512 /* max size */ +/* nan application events to the host driver */ +enum nan_app_events { + WL_NAN_EVENT_START = 1, /* NAN cluster started */ + WL_NAN_EVENT_JOIN = 2, /* Joined to a NAN cluster */ + WL_NAN_EVENT_ROLE = 3, /* Role or State changed */ + WL_NAN_EVENT_SCAN_COMPLETE = 4, + WL_NAN_EVENT_DISCOVERY_RESULT = 5, + WL_NAN_EVENT_REPLIED = 6, + WL_NAN_EVENT_TERMINATED = 7, /* the instance ID will be present in the ev data */ + WL_NAN_EVENT_RECEIVE = 8, + WL_NAN_EVENT_STATUS_CHG = 9, /* generated on any change in nan_mac status */ + WL_NAN_EVENT_MERGE = 10, /* Merged to a NAN cluster */ + WL_NAN_EVENT_STOP = 11, /* NAN stopped */ + WL_NAN_EVENT_P2P = 12, /* NAN P2P EVENT */ + WL_NAN_EVENT_INVALID = 13, /* delimiter for max value */ +}; +#define IS_NAN_EVT_ON(var, evt) ((var & (1 << (evt-1))) != 0) +/* ******************* end of NAN section *************** */ + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _BCMEVENT_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmip.h new file mode 100644 index 000000000000..85ce02e580b7 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmip.h @@ -0,0 +1,245 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental constants relating to IP Protocol + * + * $Id: bcmip.h 458522 2014-02-27 02:26:15Z $ + */ + +#ifndef _bcmip_h_ +#define _bcmip_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + + +/* IPV4 and IPV6 common */ +#define IP_VER_OFFSET 0x0 /* offset to version field */ +#define IP_VER_MASK 0xf0 /* version mask */ +#define IP_VER_SHIFT 4 /* version shift */ +#define IP_VER_4 4 /* version number for IPV4 */ +#define IP_VER_6 6 /* version number for IPV6 */ + +#define IP_VER(ip_body) \ + ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) + +#define IP_PROT_ICMP 0x1 /* ICMP protocol */ +#define IP_PROT_IGMP 0x2 /* IGMP protocol */ +#define IP_PROT_TCP 0x6 /* TCP protocol */ +#define IP_PROT_UDP 0x11 /* UDP protocol type */ +#define IP_PROT_ICMP6 0x3a /* ICMPv6 protocol type */ + +/* IPV4 field offsets */ +#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ +#define IPV4_TOS_OFFSET 1 /* type of service offset */ +#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ +#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ +#define IPV4_PROT_OFFSET 9 /* protocol type offset */ +#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ +#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ +#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ +#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ +#define IPV4_MIN_HEADER_LEN 20 /* Minimum size for an IP header (no options) */ + +/* IPV4 field decodes */ +#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ +#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ + +#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ +#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) + +#define IPV4_ADDR_LEN 4 /* IPV4 address length */ + +#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ + ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) + +#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ + ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) + +#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ +#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ + +#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) + +#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ +#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ + +#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ +#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ +#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ + +#define IPV4_TOS_ROUTINE 0 +#define IPV4_TOS_PRIORITY 1 +#define IPV4_TOS_IMMEDIATE 2 +#define IPV4_TOS_FLASH 3 +#define IPV4_TOS_FLASHOVERRIDE 4 +#define IPV4_TOS_CRITICAL 5 +#define IPV4_TOS_INETWORK_CTRL 6 +#define IPV4_TOS_NETWORK_CTRL 7 + +#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) + +#define IPV4_FRAG_RESV 0x8000 /* Reserved */ +#define IPV4_FRAG_DONT 0x4000 /* Don't fragment */ +#define IPV4_FRAG_MORE 0x2000 /* More fragments */ +#define IPV4_FRAG_OFFSET_MASK 0x1fff /* Fragment offset */ + +#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ + +/* IPV4 packet formats */ +BWL_PRE_PACKED_STRUCT struct ipv4_addr { + uint8 addr[IPV4_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct ipv4_hdr { + uint8 version_ihl; /* Version and Internet Header Length */ + uint8 tos; /* Type Of Service */ + uint16 tot_len; /* Number of bytes in packet (max 65535) */ + uint16 id; + uint16 frag; /* 3 flag bits and fragment offset */ + uint8 ttl; /* Time To Live */ + uint8 prot; /* Protocol */ + uint16 hdr_chksum; /* IP header checksum */ + uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ + uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ +} BWL_POST_PACKED_STRUCT; + +/* IPV6 field offsets */ +#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ +#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ +#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ +#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ +#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ + +/* IPV6 field decodes */ +#define IPV6_TRAFFIC_CLASS(ipv6_body) \ + (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ + ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) + +#define IPV6_FLOW_LABEL(ipv6_body) \ + (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ + (((uint8 *)(ipv6_body))[2] << 8) | \ + (((uint8 *)(ipv6_body))[3])) + +#define IPV6_PAYLOAD_LEN(ipv6_body) \ + ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ + ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) + +#define IPV6_NEXT_HDR(ipv6_body) \ + (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) + +#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) + +#define IPV6_ADDR_LEN 16 /* IPV6 address length */ + +/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ +#define IP_TOS46(ip_body) \ + (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ + IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) + +#define IP_DSCP46(ip_body) (IP_TOS46(ip_body) >> IPV4_TOS_DSCP_SHIFT); + +/* IPV4 or IPV6 Protocol Classifier or 0 */ +#define IP_PROT46(ip_body) \ + (IP_VER(ip_body) == IP_VER_4 ? IPV4_PROT(ip_body) : \ + IP_VER(ip_body) == IP_VER_6 ? IPV6_PROT(ip_body) : 0) + +/* IPV6 extension headers (options) */ +#define IPV6_EXTHDR_HOP 0 +#define IPV6_EXTHDR_ROUTING 43 +#define IPV6_EXTHDR_FRAGMENT 44 +#define IPV6_EXTHDR_AUTH 51 +#define IPV6_EXTHDR_NONE 59 +#define IPV6_EXTHDR_DEST 60 + +#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ + ((prot) == IPV6_EXTHDR_ROUTING) || \ + ((prot) == IPV6_EXTHDR_FRAGMENT) || \ + ((prot) == IPV6_EXTHDR_AUTH) || \ + ((prot) == IPV6_EXTHDR_NONE) || \ + ((prot) == IPV6_EXTHDR_DEST)) + +#define IPV6_MIN_HLEN 40 + +#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) + +BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { + uint8 nexthdr; + uint8 hdrlen; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { + uint8 nexthdr; + uint8 rsvd; + uint16 frag_off; + uint32 ident; +} BWL_POST_PACKED_STRUCT; + +static INLINE int32 +ipv6_exthdr_len(uint8 *h, uint8 *proto) +{ + uint16 len = 0, hlen; + struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; + + while (IPV6_EXTHDR(eh->nexthdr)) { + if (eh->nexthdr == IPV6_EXTHDR_NONE) + return -1; + else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) + hlen = 8; + else if (eh->nexthdr == IPV6_EXTHDR_AUTH) + hlen = (eh->hdrlen + 2) << 2; + else + hlen = IPV6_EXTHDR_LEN(eh); + + len += hlen; + eh = (struct ipv6_exthdr *)(h + len); + } + + *proto = eh->nexthdr; + return len; +} + +#define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000) + +#define IPV4_MCAST_TO_ETHER_MCAST(ipv4, ether) \ +{ \ + ether[0] = 0x01; \ + ether[1] = 0x00; \ + ether[2] = 0x5E; \ + ether[3] = (ipv4 & 0x7f0000) >> 16; \ + ether[4] = (ipv4 & 0xff00) >> 8; \ + ether[5] = (ipv4 & 0xff); \ +} + +/* This marks the end of a packed structure section. */ +#include + +#define IPV4_ADDR_STR "%d.%d.%d.%d" +#define IPV4_ADDR_TO_STR(addr) ((uint32)addr & 0xff000000) >> 24, \ + ((uint32)addr & 0x00ff0000) >> 16, \ + ((uint32)addr & 0x0000ff00) >> 8, \ + ((uint32)addr & 0x000000ff) + +#endif /* _bcmip_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmipv6.h new file mode 100644 index 000000000000..ee65aab4ae2b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmipv6.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental constants relating to Neighbor Discovery Protocol + * + * $Id: bcmipv6.h 439574 2013-11-27 06:37:37Z $ + */ + +#ifndef _bcmipv6_h_ +#define _bcmipv6_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +/* Extension headers */ +#define IPV6_EXT_HOP 0 +#define IPV6_EXT_ROUTE 43 +#define IPV6_EXT_FRAG 44 +#define IPV6_EXT_DEST 60 +#define IPV6_EXT_ESEC 50 +#define IPV6_EXT_AUTH 51 + +/* Minimum size (extension header "word" length) */ +#define IPV6_EXT_WORD 8 + +/* Offsets for most extension headers */ +#define IPV6_EXT_NEXTHDR 0 +#define IPV6_EXT_HDRLEN 1 + +/* Constants specific to fragmentation header */ +#define IPV6_FRAG_MORE_MASK 0x0001 +#define IPV6_FRAG_MORE_SHIFT 0 +#define IPV6_FRAG_OFFS_MASK 0xfff8 +#define IPV6_FRAG_OFFS_SHIFT 3 + +/* For icmpv6 */ +#define ICMPV6_HEADER_TYPE 0x3A +#define ICMPV6_PKT_TYPE_RA 134 +#define ICMPV6_PKT_TYPE_NS 135 +#define ICMPV6_PKT_TYPE_NA 136 + +#define ICMPV6_ND_OPT_TYPE_TARGET_MAC 2 +#define ICMPV6_ND_OPT_TYPE_SRC_MAC 1 + +#define ICMPV6_ND_OPT_LEN_LINKADDR 1 + +#define ICMPV6_ND_OPT_LEN_LINKADDR 1 + +#define IPV6_VERSION 6 +#define IPV6_HOP_LIMIT 255 + +#define IPV6_ADDR_NULL(a) ((a[0] | a[1] | a[2] | a[3] | a[4] | \ + a[5] | a[6] | a[7] | a[8] | a[9] | \ + a[10] | a[11] | a[12] | a[13] | \ + a[14] | a[15]) == 0) + +#define IPV6_ADDR_LOCAL(a) (((a[0] == 0xfe) && (a[1] & 0x80))? TRUE: FALSE) + +/* IPV6 address */ +BWL_PRE_PACKED_STRUCT struct ipv6_addr { + uint8 addr[16]; +} BWL_POST_PACKED_STRUCT; + + +/* ICMPV6 Header */ +BWL_PRE_PACKED_STRUCT struct icmp6_hdr { + uint8 icmp6_type; + uint8 icmp6_code; + uint16 icmp6_cksum; + BWL_PRE_PACKED_STRUCT union { + uint32 reserved; + BWL_PRE_PACKED_STRUCT struct nd_advt { + uint32 reserved1:5, + override:1, + solicited:1, + router:1, + reserved2:24; + } BWL_POST_PACKED_STRUCT nd_advt; + } BWL_POST_PACKED_STRUCT opt; +} BWL_POST_PACKED_STRUCT; + +/* Ipv6 Header Format */ +BWL_PRE_PACKED_STRUCT struct ipv6_hdr { + uint8 priority:4, + version:4; + uint8 flow_lbl[3]; + uint16 payload_len; + uint8 nexthdr; + uint8 hop_limit; + struct ipv6_addr saddr; + struct ipv6_addr daddr; +} BWL_POST_PACKED_STRUCT; + +/* Neighbor Advertisement/Solicitation Packet Structure */ +BWL_PRE_PACKED_STRUCT struct nd_msg { + struct icmp6_hdr icmph; + struct ipv6_addr target; +} BWL_POST_PACKED_STRUCT; + + +/* Neighibor Solicitation/Advertisement Optional Structure */ +BWL_PRE_PACKED_STRUCT struct nd_msg_opt { + uint8 type; + uint8 len; + uint8 mac_addr[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; + +/* Ipv6 Fragmentation Header */ +BWL_PRE_PACKED_STRUCT struct ipv6_frag { + uint8 nexthdr; + uint8 reserved; + uint16 frag_offset; + uint32 ident; +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include + +static const struct ipv6_addr all_node_ipv6_maddr = { + { 0xff, 0x2, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1 + }}; + +#define IPV6_ISMULTI(a) (a[0] == 0xff) + +#define IPV6_MCAST_TO_ETHER_MCAST(ipv6, ether) \ +{ \ + ether[0] = 0x33; \ + ether[1] = 0x33; \ + ether[2] = ipv6[12]; \ + ether[3] = ipv6[13]; \ + ether[4] = ipv6[14]; \ + ether[5] = ipv6[15]; \ +} + +#endif /* !defined(_bcmipv6_h_) */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmtcp.h new file mode 100644 index 000000000000..a024ea8a401f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmtcp.h @@ -0,0 +1,90 @@ +/* + * Fundamental constants relating to TCP Protocol + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmtcp.h 458522 2014-02-27 02:26:15Z $ + */ + +#ifndef _bcmtcp_h_ +#define _bcmtcp_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + + +#define TCP_SRC_PORT_OFFSET 0 /* TCP source port offset */ +#define TCP_DEST_PORT_OFFSET 2 /* TCP dest port offset */ +#define TCP_SEQ_NUM_OFFSET 4 /* TCP sequence number offset */ +#define TCP_ACK_NUM_OFFSET 8 /* TCP acknowledgement number offset */ +#define TCP_HLEN_OFFSET 12 /* HLEN and reserved bits offset */ +#define TCP_FLAGS_OFFSET 13 /* FLAGS and reserved bits offset */ +#define TCP_CHKSUM_OFFSET 16 /* TCP body checksum offset */ + +#define TCP_PORT_LEN 2 /* TCP port field length */ + +/* 8bit TCP flag field */ +#define TCP_FLAG_URG 0x20 +#define TCP_FLAG_ACK 0x10 +#define TCP_FLAG_PSH 0x08 +#define TCP_FLAG_RST 0x04 +#define TCP_FLAG_SYN 0x02 +#define TCP_FLAG_FIN 0x01 + +#define TCP_HLEN_MASK 0xf000 +#define TCP_HLEN_SHIFT 12 + +/* These fields are stored in network order */ +BWL_PRE_PACKED_STRUCT struct bcmtcp_hdr +{ + uint16 src_port; /* Source Port Address */ + uint16 dst_port; /* Destination Port Address */ + uint32 seq_num; /* TCP Sequence Number */ + uint32 ack_num; /* TCP Sequence Number */ + uint16 hdrlen_rsvd_flags; /* Header length, reserved bits and flags */ + uint16 tcpwin; /* TCP window */ + uint16 chksum; /* Segment checksum with pseudoheader */ + uint16 urg_ptr; /* Points to seq-num of byte following urg data */ +} BWL_POST_PACKED_STRUCT; + +#define TCP_MIN_HEADER_LEN 20 + +#define TCP_HDRLEN_MASK 0xf0 +#define TCP_HDRLEN_SHIFT 4 +#define TCP_HDRLEN(hdrlen) (((hdrlen) & TCP_HDRLEN_MASK) >> TCP_HDRLEN_SHIFT) + +#define TCP_FLAGS_MASK 0x1f +#define TCP_FLAGS(hdrlen) ((hdrlen) & TCP_FLAGS_MASK) + +/* This marks the end of a packed structure section. */ +#include + +/* To address round up by 32bit. */ +#define IS_TCPSEQ_GE(a, b) ((a - b) < NBITVAL(31)) /* a >= b */ +#define IS_TCPSEQ_LE(a, b) ((b - a) < NBITVAL(31)) /* a =< b */ +#define IS_TCPSEQ_GT(a, b) !IS_TCPSEQ_LE(a, b) /* a > b */ +#define IS_TCPSEQ_LT(a, b) !IS_TCPSEQ_GE(a, b) /* a < b */ + +#endif /* #ifndef _bcmtcp_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmudp.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmudp.h new file mode 100644 index 000000000000..09b71f2d2cac --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmudp.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental constants relating to UDP Protocol + * + * $Id: bcmudp.h 528443 2015-01-22 09:29:18Z $ + */ + +#ifndef _bcmudp_h_ +#define _bcmudp_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + + +/* UDP header */ +#define UDP_DEST_PORT_OFFSET 2 /* UDP dest port offset */ +#define UDP_LEN_OFFSET 4 /* UDP length offset */ +#define UDP_CHKSUM_OFFSET 6 /* UDP body checksum offset */ + +#define UDP_HDR_LEN 8 /* UDP header length */ +#define UDP_PORT_LEN 2 /* UDP port length */ + +/* These fields are stored in network order */ +BWL_PRE_PACKED_STRUCT struct bcmudp_hdr +{ + uint16 src_port; /* Source Port Address */ + uint16 dst_port; /* Destination Port Address */ + uint16 len; /* Number of bytes in datagram including header */ + uint16 chksum; /* entire datagram checksum with pseudoheader */ +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include + +#endif /* #ifndef _bcmudp_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bt_amp_hci.h new file mode 100644 index 000000000000..f1ea2909971c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bt_amp_hci.h @@ -0,0 +1,441 @@ +/* + * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bt_amp_hci.h 382882 2013-02-04 23:24:31Z $ +*/ + +#ifndef _bt_amp_hci_h +#define _bt_amp_hci_h + +/* This marks the start of a packed structure section. */ +#include + + +/* AMP HCI CMD packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd { + uint16 opcode; + uint8 plen; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT amp_hci_cmd_t; + +#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms) +#define HCI_CMD_DATA_SIZE 255 + +/* AMP HCI CMD opcode layout */ +#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF)) +#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F)) +#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF) + +/* AMP HCI command opcodes */ +#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001) +#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002) +#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003) +#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009) +#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A) +#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B) +#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035) +#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036) +#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037) +#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038) +#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039) +#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A) +#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B) +#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C) +#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067) +#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069) +#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A) +#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B) +#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003) +#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015) +#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016) +#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036) +#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037) +#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F) +#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061) +#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062) +#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063) +#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064) +#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065) +#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001) +#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002) +#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005) +#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A) + +/* AMP HCI command parameters */ +typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms { + uint8 plh; + uint8 offset[2]; /* length so far */ + uint8 max_remote[2]; +} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms { + uint8 plh; + uint8 offset[2]; + uint8 len[2]; + uint8 frag[1]; +} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms { + uint8 plh; + uint8 key_length; + uint8 key_type; + uint8 key[1]; +} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms { + uint8 plh; + uint8 reason; +} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms { + uint8 plh; + uint8 txflow[16]; + uint8 rxflow[16]; +} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec { + uint8 id; + uint8 service_type; + uint8 max_sdu[2]; + uint8 sdu_ia_time[4]; + uint8 access_latency[4]; + uint8 flush_timeout[4]; +} BWL_POST_PACKED_STRUCT ext_flow_spec_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms { + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms { + uint8 llh[2]; + uint8 txflow[16]; + uint8 rxflow[16]; +} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct plh_pad { + uint8 plh; + uint8 pad; +} BWL_POST_PACKED_STRUCT plh_pad_t; + +typedef BWL_PRE_PACKED_STRUCT union hci_handle { + uint16 bredr; + plh_pad_t amp; +} BWL_POST_PACKED_STRUCT hci_handle_t; + +typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms { + hci_handle_t handle; + uint8 timeout[2]; +} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms { + uint8 llh[2]; + uint8 befto[4]; +} BWL_POST_PACKED_STRUCT befto_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms { + uint8 plh; + uint8 srm; +} BWL_POST_PACKED_STRUCT srm_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms { + uint8 ld_aware; + uint8 ld[2]; + uint8 ld_opts; + uint8 l_opts; +} BWL_POST_PACKED_STRUCT ld_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms { + uint8 llh[2]; + uint8 packet_type; +} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t; + +/* Generic AMP extended flow spec service types */ +#define EFS_SVCTYPE_NO_TRAFFIC 0 +#define EFS_SVCTYPE_BEST_EFFORT 1 +#define EFS_SVCTYPE_GUARANTEED 2 + +/* AMP HCI event packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event { + uint8 ecode; + uint8 plen; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT amp_hci_event_t; + +#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms) + +/* AMP HCI event codes */ +#define HCI_Command_Complete 0x0E +#define HCI_Command_Status 0x0F +#define HCI_Flush_Occurred 0x11 +#define HCI_Enhanced_Flush_Complete 0x39 +#define HCI_Physical_Link_Complete 0x40 +#define HCI_Channel_Select 0x41 +#define HCI_Disconnect_Physical_Link_Complete 0x42 +#define HCI_Logical_Link_Complete 0x45 +#define HCI_Disconnect_Logical_Link_Complete 0x46 +#define HCI_Flow_Spec_Modify_Complete 0x47 +#define HCI_Number_of_Completed_Data_Blocks 0x48 +#define HCI_Short_Range_Mode_Change_Complete 0x4C +#define HCI_Status_Change_Event 0x4D +#define HCI_Vendor_Specific 0xFF + +/* AMP HCI event mask bit positions */ +#define HCI_Physical_Link_Complete_Event_Mask 0x0001 +#define HCI_Channel_Select_Event_Mask 0x0002 +#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004 +#define HCI_Logical_Link_Complete_Event_Mask 0x0020 +#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040 +#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080 +#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100 +#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000 +#define HCI_Status_Change_Event_Mask 0x2000 +#define HCI_All_Event_Mask 0x31e7 +/* AMP HCI event parameters */ +typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms { + uint8 status; + uint8 cmdpkts; + uint16 opcode; +} BWL_POST_PACKED_STRUCT cmd_status_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms { + uint8 cmdpkts; + uint16 opcode; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT cmd_complete_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms { + uint16 handle; +} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms { + uint8 status; + uint8 plh; +} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms { + uint8 status; + uint8 plh; + uint16 len; + uint8 frag[1]; +} BWL_POST_PACKED_STRUCT read_local_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms { + uint8 status; + uint8 AMP_status; + uint32 bandwidth; + uint32 gbandwidth; + uint32 latency; + uint32 PDU_size; + uint8 ctrl_type; + uint16 PAL_cap; + uint16 AMP_ASSOC_len; + uint32 max_flush_timeout; + uint32 be_flush_timeout; +} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms { + uint8 status; + uint16 llh; + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms { + uint8 status; + uint16 llh; + uint8 reason; +} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms { + uint8 status; + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms { + uint8 status; + uint16 llh; +} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms { + uint8 status; + uint8 plh; +} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms { + uint8 status; + uint8 plh; + uint8 reason; +} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms { + uint8 status; + hci_handle_t handle; + uint16 timeout; +} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms { + uint8 status; + uint16 timeout; +} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms { + uint8 status; + uint16 ACL_pkt_len; + uint16 data_block_len; + uint16 data_block_num; +} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct data_blocks { + uint16 handle; + uint16 pkts; + uint16 blocks; +} BWL_POST_PACKED_STRUCT data_blocks_t; + +typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms { + uint16 num_blocks; + uint8 num_handles; + data_blocks_t completed[1]; +} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms { + uint8 status; + uint32 befto; +} BWL_POST_PACKED_STRUCT befto_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms { + uint8 status; + uint8 plh; + uint8 srm; +} BWL_POST_PACKED_STRUCT srm_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms { + uint8 status; + uint8 llh[2]; + uint16 counter; +} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms { + uint8 status; + uint8 llh[2]; +} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms { + uint8 status; + hci_handle_t handle; + uint8 link_quality; +} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms { + uint8 status; + uint8 ld_aware; + uint8 ld[2]; + uint8 ld_opts; + uint8 l_opts; +} BWL_POST_PACKED_STRUCT ld_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms { + uint16 handle; +} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms { + uint8 len; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms { + uint8 status; + uint8 hci_version; + uint16 hci_revision; + uint8 pal_version; + uint16 mfg_name; + uint16 pal_subversion; +} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t; + +#define MAX_SUPPORTED_CMD_BYTE 64 +typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms { + uint8 status; + uint8 cmd[MAX_SUPPORTED_CMD_BYTE]; +} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms { + uint8 status; + uint8 amp_status; +} BWL_POST_PACKED_STRUCT status_change_evt_parms_t; + +/* AMP HCI error codes */ +#define HCI_SUCCESS 0x00 +#define HCI_ERR_ILLEGAL_COMMAND 0x01 +#define HCI_ERR_NO_CONNECTION 0x02 +#define HCI_ERR_MEMORY_FULL 0x07 +#define HCI_ERR_CONNECTION_TIMEOUT 0x08 +#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 +#define HCI_ERR_CONNECTION_EXISTS 0x0B +#define HCI_ERR_CONNECTION_DISALLOWED 0x0C +#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10 +#define HCI_ERR_UNSUPPORTED_VALUE 0x11 +#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 +#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16 +#define HCI_ERR_UNSPECIFIED 0x1F +#define HCI_ERR_UNIT_KEY_USED 0x26 +#define HCI_ERR_QOS_REJECTED 0x2D +#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 +#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39 +#define HCI_ERR_CHANNEL_MOVE 0xFF + +/* AMP HCI ACL Data packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data { + uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */ + uint16 dlen; /* data total length */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t; + +#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data) + +#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14) +#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12) + +#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff) +#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12) + +/* AMP Activity Report packet formats */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report { + uint8 ScheduleKnown; + uint8 NumReports; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t; + +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple { + uint32 StartTime; + uint32 Duration; + uint32 Periodicity; +} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t; + +#define HCI_AR_SCHEDULE_KNOWN 0x01 + + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _bt_amp_hci_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/eapol.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/eapol.h new file mode 100644 index 000000000000..8fd84ee348e7 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/eapol.h @@ -0,0 +1,212 @@ +/* + * 802.1x EAPOL definitions + * + * See + * IEEE Std 802.1X-2001 + * IEEE 802.1X RADIUS Usage Guidelines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: eapol.h 528443 2015-01-22 09:29:18Z $ + */ + +#ifndef _eapol_h_ +#define _eapol_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +#include + +/* EAPOL for 802.3/Ethernet */ +typedef BWL_PRE_PACKED_STRUCT struct { + struct ether_header eth; /* 802.3/Ethernet header */ + unsigned char version; /* EAPOL protocol version */ + unsigned char type; /* EAPOL type */ + unsigned short length; /* Length of body */ + unsigned char body[1]; /* Body (optional) */ +} BWL_POST_PACKED_STRUCT eapol_header_t; + +#define EAPOL_HEADER_LEN 18 + +typedef struct { + unsigned char version; /* EAPOL protocol version */ + unsigned char type; /* EAPOL type */ + unsigned short length; /* Length of body */ +} eapol_hdr_t; + +#define EAPOL_HDR_LEN 4 + +/* EAPOL version */ +#define WPA2_EAPOL_VERSION 2 +#define WPA_EAPOL_VERSION 1 +#define LEAP_EAPOL_VERSION 1 +#define SES_EAPOL_VERSION 1 + +/* EAPOL types */ +#define EAP_PACKET 0 +#define EAPOL_START 1 +#define EAPOL_LOGOFF 2 +#define EAPOL_KEY 3 +#define EAPOL_ASF 4 + +/* EAPOL-Key types */ +#define EAPOL_RC4_KEY 1 +#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ +#define EAPOL_WPA_KEY 254 /* WPA */ + +/* RC4 EAPOL-Key header field sizes */ +#define EAPOL_KEY_REPLAY_LEN 8 +#define EAPOL_KEY_IV_LEN 16 +#define EAPOL_KEY_SIG_LEN 16 + +/* RC4 EAPOL-Key */ +typedef BWL_PRE_PACKED_STRUCT struct { + unsigned char type; /* Key Descriptor Type */ + unsigned short length; /* Key Length (unaligned) */ + unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ + unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ + unsigned char index; /* Key Flags & Index */ + unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ + unsigned char key[1]; /* Key (optional) */ +} BWL_POST_PACKED_STRUCT eapol_key_header_t; + +#define EAPOL_KEY_HEADER_LEN 44 + +/* RC4 EAPOL-Key flags */ +#define EAPOL_KEY_FLAGS_MASK 0x80 +#define EAPOL_KEY_BROADCAST 0 +#define EAPOL_KEY_UNICAST 0x80 + +/* RC4 EAPOL-Key index */ +#define EAPOL_KEY_INDEX_MASK 0x7f + +/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ +#define EAPOL_WPA_KEY_REPLAY_LEN 8 +#define EAPOL_WPA_KEY_NONCE_LEN 32 +#define EAPOL_WPA_KEY_IV_LEN 16 +#define EAPOL_WPA_KEY_RSC_LEN 8 +#define EAPOL_WPA_KEY_ID_LEN 8 +#define EAPOL_WPA_KEY_MIC_LEN 16 +#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) +#define EAPOL_WPA_MAX_KEY_SIZE 32 + +/* WPA EAPOL-Key */ +typedef BWL_PRE_PACKED_STRUCT struct { + unsigned char type; /* Key Descriptor Type */ + unsigned short key_info; /* Key Information (unaligned) */ + unsigned short key_len; /* Key Length (unaligned) */ + unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ + unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ + unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ + unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ + unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ + unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ + unsigned short data_len; /* Key Data Length */ + unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ +} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t; + +#define EAPOL_WPA_KEY_LEN 95 + +/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ +#define WPA_KEY_DESC_OSEN 0x0 +#define WPA_KEY_DESC_V1 0x01 +#define WPA_KEY_DESC_V2 0x02 +#define WPA_KEY_DESC_V3 0x03 +#define WPA_KEY_PAIRWISE 0x08 +#define WPA_KEY_INSTALL 0x40 +#define WPA_KEY_ACK 0x80 +#define WPA_KEY_MIC 0x100 +#define WPA_KEY_SECURE 0x200 +#define WPA_KEY_ERROR 0x400 +#define WPA_KEY_REQ 0x800 + +#define WPA_KEY_DESC_V2_OR_V3 WPA_KEY_DESC_V2 + +/* WPA-only KEY KEY_INFO bits */ +#define WPA_KEY_INDEX_0 0x00 +#define WPA_KEY_INDEX_1 0x10 +#define WPA_KEY_INDEX_2 0x20 +#define WPA_KEY_INDEX_3 0x30 +#define WPA_KEY_INDEX_MASK 0x30 +#define WPA_KEY_INDEX_SHIFT 0x04 + +/* 802.11i/WPA2-only KEY KEY_INFO bits */ +#define WPA_KEY_ENCRYPTED_DATA 0x1000 + +/* Key Data encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 type; + uint8 length; + uint8 oui[3]; + uint8 subtype; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; + +#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 + +#define WPA2_KEY_DATA_SUBTYPE_GTK 1 +#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 +#define WPA2_KEY_DATA_SUBTYPE_MAC 3 +#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 +#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 + +/* GTK encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 flags; + uint8 reserved; + uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; + +#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 + +#define WPA2_GTK_INDEX_MASK 0x03 +#define WPA2_GTK_INDEX_SHIFT 0x00 + +#define WPA2_GTK_TRANSMIT 0x04 + +/* IGTK encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 key_id; + uint8 ipn[6]; + uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; + +#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8 + +/* STAKey encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 reserved[2]; + uint8 mac[ETHER_ADDR_LEN]; + uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t; + +#define WPA2_KEY_DATA_PAD 0xdd + + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _eapol_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/ethernet.h new file mode 100644 index 000000000000..54d363b49608 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/ethernet.h @@ -0,0 +1,228 @@ +/* + * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: ethernet.h 473238 2014-04-28 19:14:56Z $ + */ + +#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ +#define _NET_ETHERNET_H_ + +#ifndef _TYPEDEFS_H_ +#include "typedefs.h" +#endif + +/* This marks the start of a packed structure section. */ +#include + + +/* + * The number of bytes in an ethernet (MAC) address. + */ +#define ETHER_ADDR_LEN 6 + +/* + * The number of bytes in the type field. + */ +#define ETHER_TYPE_LEN 2 + +/* + * The number of bytes in the trailing CRC field. + */ +#define ETHER_CRC_LEN 4 + +/* + * The length of the combined header. + */ +#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) + +/* + * The minimum packet length. + */ +#define ETHER_MIN_LEN 64 + +/* + * The minimum packet user data length. + */ +#define ETHER_MIN_DATA 46 + +/* + * The maximum packet length. + */ +#define ETHER_MAX_LEN 1518 + +/* + * The maximum packet user data length. + */ +#define ETHER_MAX_DATA 1500 + +/* ether types */ +#define ETHER_TYPE_MIN 0x0600 /* Anything less than MIN is a length */ +#define ETHER_TYPE_IP 0x0800 /* IP */ +#define ETHER_TYPE_ARP 0x0806 /* ARP */ +#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */ +#define ETHER_TYPE_IPV6 0x86dd /* IPv6 */ +#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */ +#define ETHER_TYPE_802_1X 0x888e /* 802.1x */ +#ifdef PLC +#define ETHER_TYPE_88E1 0x88e1 /* GIGLE */ +#define ETHER_TYPE_8912 0x8912 /* GIGLE */ +#define ETHER_TYPE_GIGLED 0xffff /* GIGLE */ +#endif /* PLC */ +#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */ +#define ETHER_TYPE_WAI 0x88b4 /* WAI */ +#define ETHER_TYPE_89_0D 0x890d /* 89-0d frame for TDLS */ + +#define ETHER_TYPE_PPP_SES 0x8864 /* PPPoE Session */ + +#define ETHER_TYPE_IAPP_L2_UPDATE 0x6 /* IAPP L2 update frame */ + +/* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */ +#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */ + +/* ether header */ +#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) /* dest address offset */ +#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) /* src address offset */ +#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) /* ether type offset */ + +/* + * A macro to validate a length with + */ +#define ETHER_IS_VALID_LEN(foo) \ + ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ + ((uint8 *)ea)[0] = 0x01; \ + ((uint8 *)ea)[1] = 0x00; \ + ((uint8 *)ea)[2] = 0x5e; \ + ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ + ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ + ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ +} + +#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ +/* + * Structure of a 10Mb/s Ethernet header. + */ +BWL_PRE_PACKED_STRUCT struct ether_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 ether_type; +} BWL_POST_PACKED_STRUCT; + +/* + * Structure of a 48-bit Ethernet address. + */ +BWL_PRE_PACKED_STRUCT struct ether_addr { + uint8 octet[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; +#endif /* !__INCif_etherh Quick and ugly hack for VxWorks */ + +/* + * Takes a pointer, set, test, clear, toggle locally admininistered + * address bit in the 48-bit Ethernet address. + */ +#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) +#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) +#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) +#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) + +/* Takes a pointer, marks unicast address bit in the MAC address */ +#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) + +/* + * Takes a pointer, returns true if a 48-bit multicast address + * (including broadcast, since it is all ones) + */ +#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) + + +/* compare two ethernet addresses - assumes the pointers can be referenced as shorts */ +#define eacmp(a, b) ((((const uint16 *)(a))[0] ^ ((const uint16 *)(b))[0]) | \ + (((const uint16 *)(a))[1] ^ ((const uint16 *)(b))[1]) | \ + (((const uint16 *)(a))[2] ^ ((const uint16 *)(b))[2])) + +#define ether_cmp(a, b) eacmp(a, b) + +/* copy an ethernet address - assumes the pointers can be referenced as shorts */ +#define eacopy(s, d) \ +do { \ + ((uint16 *)(d))[0] = ((const uint16 *)(s))[0]; \ + ((uint16 *)(d))[1] = ((const uint16 *)(s))[1]; \ + ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \ +} while (0) + +#define ether_copy(s, d) eacopy(s, d) + +/* Copy an ethernet address in reverse order */ +#define ether_rcopy(s, d) \ +do { \ + ((uint16 *)(d))[2] = ((uint16 *)(s))[2]; \ + ((uint16 *)(d))[1] = ((uint16 *)(s))[1]; \ + ((uint16 *)(d))[0] = ((uint16 *)(s))[0]; \ +} while (0) + +/* Copy 14B ethernet header: 32bit aligned source and destination. */ +#define ehcopy32(s, d) \ +do { \ + ((uint32 *)(d))[0] = ((const uint32 *)(s))[0]; \ + ((uint32 *)(d))[1] = ((const uint32 *)(s))[1]; \ + ((uint32 *)(d))[2] = ((const uint32 *)(s))[2]; \ + ((uint16 *)(d))[6] = ((const uint16 *)(s))[6]; \ +} while (0) + + +static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; +static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; +static const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; + +#define ETHER_ISBCAST(ea) ((((const uint8 *)(ea))[0] & \ + ((const uint8 *)(ea))[1] & \ + ((const uint8 *)(ea))[2] & \ + ((const uint8 *)(ea))[3] & \ + ((const uint8 *)(ea))[4] & \ + ((const uint8 *)(ea))[5]) == 0xff) +#define ETHER_ISNULLADDR(ea) ((((const uint8 *)(ea))[0] | \ + ((const uint8 *)(ea))[1] | \ + ((const uint8 *)(ea))[2] | \ + ((const uint8 *)(ea))[3] | \ + ((const uint8 *)(ea))[4] | \ + ((const uint8 *)(ea))[5]) == 0) + +#define ETHER_ISNULLDEST(da) ((((const uint16 *)(da))[0] | \ + ((const uint16 *)(da))[1] | \ + ((const uint16 *)(da))[2]) == 0) +#define ETHER_ISNULLSRC(sa) ETHER_ISNULLDEST(sa) + +#define ETHER_MOVE_HDR(d, s) \ +do { \ + struct ether_header t; \ + t = *(struct ether_header *)(s); \ + *(struct ether_header *)(d) = t; \ +} while (0) + +#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0) + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _NET_ETHERNET_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/nan.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/nan.h new file mode 100644 index 000000000000..40b5058320d3 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/nan.h @@ -0,0 +1,238 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental types and constants relating to WFA NAN + * (Neighbor Awareness Networking) + * + * $Id$ + */ +#ifndef _NAN_H_ +#define _NAN_H_ + +#include +#include + + +/* This marks the start of a packed structure section. */ +#include + +/* WiFi NAN OUI values */ +#define NAN_OUI WFA_OUI /* WiFi OUI */ +/* For oui_type field identifying the type and version of the NAN IE. */ +#define NAN_OUI_TYPE 0x13 /* Type/Version */ +/* IEEE 802.11 vendor specific information element. (Same as P2P_IE_ID.) */ +#define NAN_IE_ID 0xdd + +/* Same as P2P_PUB_AF_CATEGORY and DOT11_ACTION_CAT_PUBLIC */ +#define NAN_PUB_AF_CATEGORY 0x04 +/* IEEE 802.11 Public Action Frame Vendor Specific. (Same as P2P_PUB_AF_ACTION.) */ +#define NAN_PUB_AF_ACTION 0x09 +/* Number of octents in hash of service name. (Same as P2P_WFDS_HASH_LEN.) */ +#define NAN_SVC_HASH_LEN 6 +/* Size of fixed length part of nan_pub_act_frame_t before attributes. */ +#define NAN_PUB_ACT_FRAME_FIXED_LEN 6 +/* Number of octents in master rank value. */ +#define NAN_MASTER_RANK_LEN 8 +/* NAN public action frame header size */ +#define NAN_PUB_ACT_FRAME_HDR_SIZE (OFFSETOF(nan_pub_act_frame_t, data)) +/* NAN network ID */ +#define NAN_NETWORK_ID "\x51\x6F\x9A\x01\x00\x00" +/* Service Control Type length */ +#define NAN_SVC_CONTROL_TYPE_LEN 2 + +/* Attribute TLV header size */ +#define NAN_ATTR_ID_OFF 0 +#define NAN_ATTR_LEN_OFF 1 +#define NAN_ATTR_DATA_OFF 3 + +#define NAN_ATTR_ID_LEN 1 /* ID field length */ +#define NAN_ATTR_LEN_LEN 2 /* Length field length */ +#define NAN_ATTR_HDR_LEN 3 /* ID + 2-byte length field */ + +/* Vendor-specific public action frame for NAN */ +typedef BWL_PRE_PACKED_STRUCT struct nan_pub_act_frame_s { + /* NAN_PUB_AF_CATEGORY 0x04 */ + uint8 category_id; + /* NAN_PUB_AF_ACTION 0x09 */ + uint8 action_field; + /* NAN_OUI 0x50-6F-9A */ + uint8 oui[DOT11_OUI_LEN]; + /* NAN_OUI_TYPE 0x13 */ + uint8 oui_type; + /* One or more NAN Attributes follow */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT nan_pub_act_frame_t; + +/* NAN attributes as defined in the nan spec */ +enum { + NAN_ATTR_MASTER_IND = 0, + NAN_ATTR_CLUSTER = 1, + NAN_ATTR_SVC_ID_LIST = 2, + NAN_ATTR_SVC_DESCRIPTOR = 3, + NAN_ATTR_CONN_CAP = 4, + NAN_ATTR_INFRA = 5, + NAN_ATTR_P2P = 6, + NAN_ATTR_IBSS = 7, + NAN_ATTR_MESH = 8, + NAN_ATTR_FURTHER_NAN_SD = 9, + NAN_ATTR_FURTHER_AVAIL = 10, + NAN_ATTR_COUNTRY_CODE = 11, + NAN_ATTR_RANGING = 12, + NAN_ATTR_VENDOR_SPECIFIC = 221 +}; + +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ie_s { + uint8 id; /* IE ID: NAN_IE_ID 0xDD */ + uint8 len; /* IE length */ + uint8 oui[DOT11_OUI_LEN]; /* NAN_OUI 50:6F:9A */ + uint8 oui_type; /* NAN_OUI_TYPE 0x13 */ + uint8 attr[1]; /* var len attributes */ +} BWL_POST_PACKED_STRUCT wifi_nan_ie_t; + +#define NAN_IE_HDR_SIZE (OFFSETOF(wifi_nan_ie_t, attr)) + +/* master indication record */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_master_ind_attr_s { + uint8 id; + uint16 len; + uint8 master_preference; + uint8 random_factor; +} BWL_POST_PACKED_STRUCT wifi_nan_master_ind_attr_t; + +/* cluster attr record */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_cluster_attr_s { + uint8 id; + uint16 len; + uint8 amr[NAN_MASTER_RANK_LEN]; + uint8 hop_count; + /* Anchor Master Beacon Transmission Time */ + uint32 ambtt; +} BWL_POST_PACKED_STRUCT wifi_nan_cluster_attr_t; + +/* container for service ID records */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_id_attr_s { + uint8 id; + uint16 len; + uint8 svcid[NAN_SVC_HASH_LEN]; /* 6*len of srvc IDs */ +} BWL_POST_PACKED_STRUCT wifi_nan_svc_id_attr_t; + +/* service_control bitmap for wifi_nan_svc_descriptor_attr_t below */ +#define NAN_SC_PUBLISH 0x0 +#define NAN_SC_SUBSCRIBE 0x1 +#define NAN_SC_FOLLOWUP 0x2 +/* Set to 1 if a Matching Filter field is included in descriptors. */ +#define NAN_SC_MATCHING_FILTER_PRESENT 0x8 +/* Set to 1 if a Service Response Filter field is included in descriptors. */ +#define NAN_SC_SR_FILTER_PRESENT 0x10 +/* Set to 1 if a Service Info field is included in descriptors. */ +#define NAN_SC_SVC_INFO_PRESENT 0x20 +/* range is close proximity only */ +#define NAN_SC_RANGE_LIMITED 0x40 + +/* Service descriptor */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_descriptor_attr_s { + /* Attribute ID - 0x03. */ + uint8 id; + /* Length of the following fields in the attribute */ + uint16 len; + /* Hash of the Service Name */ + uint8 svc_hash[NAN_SVC_HASH_LEN]; + /* Publish or subscribe instance id */ + uint8 instance_id; + /* Requestor Instance ID */ + uint8 requestor_id; + /* Service Control Bitmask. Also determines what data follows. */ + uint8 svc_control; + /* Optional fields follow */ +} BWL_POST_PACKED_STRUCT wifi_nan_svc_descriptor_attr_t; + +/* IBSS attribute */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ibss_attr_s { + /* Attribute ID - 0x07. */ + uint8 id; + /* Length of the following fields in the attribute */ + uint16 len; + /* BSSID of the ibss */ + struct ether_addr bssid; + /* + map control:, bits: + [0-3]: Id for associated further avail map attribute + [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved + [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf? + [7] : reserved + */ + uint8 map_ctrl; + /* avail. intervals bitmap, var len */ + uint8 avail_bmp[1]; +} BWL_POST_PACKED_STRUCT wifi_nan_ibss_attr_t; + +/* Further Availability MAP attr */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_favail_attr_s { + /* Attribute ID - 0x0A. */ + uint8 id; + /* Length of the following fields in the attribute */ + uint16 len; + /* MAP id: val [0..15], values[16-255] reserved */ + uint8 map_id; + /* availibility entry, var len */ + uint8 avil_entry[1]; +} BWL_POST_PACKED_STRUCT wifi_nan_favail_attr_t; + +/* Further Availability MAP attr */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_s { + /* + entry control + [0-1]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; + [2:7] reserved + */ + uint8 entry_ctrl; + /* operating class: freq band etc IEEE 802.11 */ + uint8 opclass; + /* channel number */ + uint8 chan; + uint8 map_id; + /* avail bmp, var len */ + uint8 avail_bmp[1]; +} BWL_POST_PACKED_STRUCT wifi_nan_avail_entry_t; + +/* Map control Field */ +#define NAN_MAPCTRL_IDMASK 0x7 +#define NAN_MAPCTRL_DURSHIFT 3 +#define NAN_MAPCTRL_REPEAT 0x40 + +#define NAN_VENDOR_TYPE_RTT 0 +#define NAN_VENDOR_TYPE_P2P 1 + +/* Vendor Specific Attribute */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_vendor_attr_s { + uint8 id; /* 0xDD */ + uint16 len; /* IE length */ + uint8 oui[DOT11_OUI_LEN]; /* 00-90-4C */ + uint8 type; /* attribute type */ + uint8 attr[1]; /* var len attributes */ +} BWL_POST_PACKED_STRUCT wifi_nan_vendor_attr_t; + +#define NAN_VENDOR_HDR_SIZE (OFFSETOF(wifi_nan_vendor_attr_t, attr)) + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _NAN_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/p2p.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/p2p.h new file mode 100644 index 000000000000..487603240fb3 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/p2p.h @@ -0,0 +1,710 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) + * + * $Id: p2p.h 457033 2014-02-20 19:39:45Z $ + */ + +#ifndef _P2P_H_ +#define _P2P_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif +#include +#include + +/* This marks the start of a packed structure section. */ +#include + + +/* WiFi P2P OUI values */ +#define P2P_OUI WFA_OUI /* WiFi P2P OUI */ +#define P2P_VER WFA_OUI_TYPE_P2P /* P2P version: 9=WiFi P2P v1.0 */ + +#define P2P_IE_ID 0xdd /* P2P IE element ID */ + +/* WiFi P2P IE */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { + uint8 id; /* IE ID: 0xDD */ + uint8 len; /* IE length */ + uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ + uint8 oui_type; /* Identifies P2P version: P2P_VER */ + uint8 subelts[1]; /* variable length subelements */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_ie wifi_p2p_ie_t; + +#define P2P_IE_FIXED_LEN 6 + +#define P2P_ATTR_ID_OFF 0 +#define P2P_ATTR_LEN_OFF 1 +#define P2P_ATTR_DATA_OFF 3 + +#define P2P_ATTR_ID_LEN 1 /* ID filed length */ +#define P2P_ATTR_LEN_LEN 2 /* length field length */ +#define P2P_ATTR_HDR_LEN 3 /* ID + 2-byte length field spec 1.02 */ + +#define P2P_WFDS_HASH_LEN 6 +#define P2P_WFDS_MAX_SVC_NAME_LEN 32 + +/* P2P IE Subelement IDs from WiFi P2P Technical Spec 1.00 */ +#define P2P_SEID_STATUS 0 /* Status */ +#define P2P_SEID_MINOR_RC 1 /* Minor Reason Code */ +#define P2P_SEID_P2P_INFO 2 /* P2P Capability (capabilities info) */ +#define P2P_SEID_DEV_ID 3 /* P2P Device ID */ +#define P2P_SEID_INTENT 4 /* Group Owner Intent */ +#define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */ +#define P2P_SEID_CHANNEL 6 /* Listen channel */ +#define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */ +#define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */ +#define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */ +#define P2P_SEID_P2P_MGBTY 10 /* P2P Manageability */ +#define P2P_SEID_CHAN_LIST 11 /* Channel List */ +#define P2P_SEID_ABSENCE 12 /* Notice of Absence */ +#define P2P_SEID_DEV_INFO 13 /* Device Info */ +#define P2P_SEID_GROUP_INFO 14 /* Group Info */ +#define P2P_SEID_GROUP_ID 15 /* Group ID */ +#define P2P_SEID_P2P_IF 16 /* P2P Interface */ +#define P2P_SEID_OP_CHANNEL 17 /* Operating Channel */ +#define P2P_SEID_INVITE_FLAGS 18 /* Invitation Flags */ +#define P2P_SEID_SERVICE_HASH 21 /* Service hash */ +#define P2P_SEID_SESSION 22 /* Session information */ +#define P2P_SEID_CONNECT_CAP 23 /* Connection capability */ +#define P2P_SEID_ADVERTISE_ID 24 /* Advertisement ID */ +#define P2P_SEID_ADVERTISE_SERVICE 25 /* Advertised service */ +#define P2P_SEID_SESSION_ID 26 /* Session ID */ +#define P2P_SEID_FEATURE_CAP 27 /* Feature capability */ +#define P2P_SEID_PERSISTENT_GROUP 28 /* Persistent group */ +#define P2P_SEID_SESSION_INFO_RESP 29 /* Session Information Response */ +#define P2P_SEID_VNDR 221 /* Vendor-specific subelement */ + +#define P2P_SE_VS_ID_SERVICES 0x1b + + +/* WiFi P2P IE subelement: P2P Capability (capabilities info) */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { + uint8 eltId; /* SE ID: P2P_SEID_P2P_INFO */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 dev; /* Device Capability Bitmap */ + uint8 group; /* Group Capability Bitmap */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; + +/* P2P Capability subelement's Device Capability Bitmap bit values */ +#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 /* Service Discovery */ +#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 /* Client Discoverability */ +#define P2P_CAPSE_DEV_CONCURRENT 0x4 /* Concurrent Operation */ +#define P2P_CAPSE_DEV_INFRA_MAN 0x8 /* P2P Infrastructure Managed */ +#define P2P_CAPSE_DEV_LIMIT 0x10 /* P2P Device Limit */ +#define P2P_CAPSE_INVITE_PROC 0x20 /* P2P Invitation Procedure */ + +/* P2P Capability subelement's Group Capability Bitmap bit values */ +#define P2P_CAPSE_GRP_OWNER 0x1 /* P2P Group Owner */ +#define P2P_CAPSE_PERSIST_GRP 0x2 /* Persistent P2P Group */ +#define P2P_CAPSE_GRP_LIMIT 0x4 /* P2P Group Limit */ +#define P2P_CAPSE_GRP_INTRA_BSS 0x8 /* Intra-BSS Distribution */ +#define P2P_CAPSE_GRP_X_CONNECT 0x10 /* Cross Connection */ +#define P2P_CAPSE_GRP_PERSISTENT 0x20 /* Persistent Reconnect */ +#define P2P_CAPSE_GRP_FORMATION 0x40 /* Group Formation */ + + +/* WiFi P2P IE subelement: Group Owner Intent */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { + uint8 eltId; /* SE ID: P2P_SEID_INTENT */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 intent; /* Intent Value 0...15 (0=legacy 15=master only) */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; + +/* WiFi P2P IE subelement: Configuration Timeout */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { + uint8 eltId; /* SE ID: P2P_SEID_CFG_TIMEOUT */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 go_tmo; /* GO config timeout in units of 10 ms */ + uint8 client_tmo; /* Client config timeout in units of 10 ms */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; + +/* WiFi P2P IE subelement: Listen Channel */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_listen_channel_se_s { + uint8 eltId; /* SE ID: P2P_SEID_CHANNEL */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 country[3]; /* Country String */ + uint8 op_class; /* Operating Class */ + uint8 channel; /* Channel */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_listen_channel_se_s wifi_p2p_listen_channel_se_t; + +/* WiFi P2P IE subelement: P2P Group BSSID */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_bssid_se_s { + uint8 eltId; /* SE ID: P2P_SEID_GRP_BSSID */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P group bssid */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; + +/* WiFi P2P IE subelement: P2P Group ID */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { + uint8 eltId; /* SE ID: P2P_SEID_GROUP_ID */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P device address */ + uint8 ssid[1]; /* ssid. device id. variable length */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; + +/* WiFi P2P IE subelement: P2P Interface */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { + uint8 eltId; /* SE ID: P2P_SEID_P2P_IF */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P device address */ + uint8 ifaddrs; /* P2P Interface Address count */ + uint8 ifaddr[1][6]; /* P2P Interface Address list */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; + +/* WiFi P2P IE subelement: Status */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { + uint8 eltId; /* SE ID: P2P_SEID_STATUS */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 status; /* Status Code: P2P_STATSE_* */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; + +/* Status subelement Status Code definitions */ +#define P2P_STATSE_SUCCESS 0 + /* Success */ +#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 + /* Failed, information currently unavailable */ +#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL + /* Old name for above in P2P spec 1.08 and older */ +#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 + /* Failed, incompatible parameters */ +#define P2P_STATSE_FAIL_LIMIT_REACHED 3 + /* Failed, limit reached */ +#define P2P_STATSE_FAIL_INVALID_PARAMS 4 + /* Failed, invalid parameters */ +#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 + /* Failed, unable to accomodate request */ +#define P2P_STATSE_FAIL_PROTO_ERROR 6 + /* Failed, previous protocol error or disruptive behaviour */ +#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 + /* Failed, no common channels */ +#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 + /* Failed, unknown P2P Group */ +#define P2P_STATSE_FAIL_INTENT 9 + /* Failed, both peers indicated Intent 15 in GO Negotiation */ +#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 + /* Failed, incompatible provisioning method */ +#define P2P_STATSE_FAIL_USER_REJECT 11 + /* Failed, rejected by user */ +#define P2P_STATSE_SUCCESS_USER_ACCEPT 12 + /* Success, accepted by user */ + +/* WiFi P2P IE attribute: Extended Listen Timing */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { + uint8 eltId; /* ID: P2P_SEID_EXT_TIMING */ + uint8 len[2]; /* length not including eltId, len fields */ + uint8 avail[2]; /* availibility period */ + uint8 interval[2]; /* availibility interval */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; + +#define P2P_EXT_MIN 10 /* minimum 10ms */ + +/* WiFi P2P IE subelement: Intended P2P Interface Address */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { + uint8 eltId; /* SE ID: P2P_SEID_INTINTADDR */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* intended P2P interface MAC address */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; + +/* WiFi P2P IE subelement: Channel */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { + uint8 eltId; /* SE ID: P2P_SEID_STATUS */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 band; /* Regulatory Class (band) */ + uint8 channel; /* Channel */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; + + +/* Channel Entry structure within the Channel List SE */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { + uint8 band; /* Regulatory Class (band) */ + uint8 num_channels; /* # of channels in the channel list */ + uint8 channels[WL_NUMCHANNELS]; /* Channel List */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; +#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 + +/* WiFi P2P IE subelement: Channel List */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { + uint8 eltId; /* SE ID: P2P_SEID_CHAN_LIST */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 country[3]; /* Country String */ + uint8 num_entries; /* # of channel entries */ + wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; + /* Channel Entry List */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; + +/* WiFi Primary Device Type structure */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_pri_devtype_s { + uint16 cat_id; /* Category ID */ + uint8 OUI[3]; /* WFA OUI: 0x0050F2 */ + uint8 oui_type; /* WPS_OUI_TYPE */ + uint16 sub_cat_id; /* Sub Category ID */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_pri_devtype_s wifi_p2p_pri_devtype_t; + +/* WiFi P2P Device Info Sub Element Primary Device Type Sub Category + * maximum values for each category + */ +#define P2P_DISE_SUBCATEGORY_MINVAL 1 +#define P2P_DISE_CATEGORY_COMPUTER 1 +#define P2P_DISE_SUBCATEGORY_COMPUTER_MAXVAL 8 +#define P2P_DISE_CATEGORY_INPUT_DEVICE 2 +#define P2P_DISE_SUBCATEGORY_INPUT_DEVICE_MAXVAL 9 +#define P2P_DISE_CATEGORY_PRINTER 3 +#define P2P_DISE_SUBCATEGORY_PRINTER_MAXVAL 5 +#define P2P_DISE_CATEGORY_CAMERA 4 +#define P2P_DISE_SUBCATEGORY_CAMERA_MAXVAL 4 +#define P2P_DISE_CATEGORY_STORAGE 5 +#define P2P_DISE_SUBCATEGORY_STORAGE_MAXVAL 1 +#define P2P_DISE_CATEGORY_NETWORK_INFRA 6 +#define P2P_DISE_SUBCATEGORY_NETWORK_INFRA_MAXVAL 4 +#define P2P_DISE_CATEGORY_DISPLAY 7 +#define P2P_DISE_SUBCATEGORY_DISPLAY_MAXVAL 4 +#define P2P_DISE_CATEGORY_MULTIMEDIA 8 +#define P2P_DISE_SUBCATEGORY_MULTIMEDIA_MAXVAL 6 +#define P2P_DISE_CATEGORY_GAMING 9 +#define P2P_DISE_SUBCATEGORY_GAMING_MAXVAL 5 +#define P2P_DISE_CATEGORY_TELEPHONE 10 +#define P2P_DISE_SUBCATEGORY_TELEPHONE_MAXVAL 5 +#define P2P_DISE_CATEGORY_AUDIO 11 +#define P2P_DISE_SUBCATEGORY_AUDIO_MAXVAL 6 + +/* WiFi P2P IE's Device Info subelement */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { + uint8 eltId; /* SE ID: P2P_SEID_DEVINFO */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P Device MAC address */ + uint16 wps_cfg_meths; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ + uint8 pri_devtype[8]; /* Primary Device Type */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; + +#define P2P_DEV_TYPE_LEN 8 + +/* WiFi P2P IE's Group Info subelement Client Info Descriptor */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { + uint8 len; + uint8 devaddr[ETHER_ADDR_LEN]; /* P2P Device Address */ + uint8 ifaddr[ETHER_ADDR_LEN]; /* P2P Interface Address */ + uint8 devcap; /* Device Capability */ + uint8 cfg_meths[2]; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ + uint8 pridt[P2P_DEV_TYPE_LEN]; /* Primary Device Type */ + uint8 secdts; /* Number of Secondary Device Types */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; + +/* WiFi P2P IE's Device ID subelement */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { + uint8 eltId; + uint8 len[2]; + struct ether_addr addr; /* P2P Device MAC address */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; + +/* WiFi P2P IE subelement: P2P Manageability */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { + uint8 eltId; /* SE ID: P2P_SEID_P2P_MGBTY */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mg_bitmap; /* manageability bitmap */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; +/* mg_bitmap field bit values */ +#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 /* AP supports Managed P2P Device */ + +/* WiFi P2P IE subelement: Group Info */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { + uint8 eltId; /* SE ID: P2P_SEID_GROUP_INFO */ + uint8 len[2]; /* SE length not including eltId, len fields */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; + +/* WiFi IE subelement: Operating Channel */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_op_channel_se_s { + uint8 eltId; /* SE ID: P2P_SEID_OP_CHANNEL */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 country[3]; /* Country String */ + uint8 op_class; /* Operating Class */ + uint8 channel; /* Channel */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_op_channel_se_s wifi_p2p_op_channel_se_t; + +/* WiFi IE subelement: INVITATION FLAGS */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_invite_flags_se_s { + uint8 eltId; /* SE ID: P2P_SEID_INVITE_FLAGS */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 flags; /* Flags */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_invite_flags_se_s wifi_p2p_invite_flags_se_t; + +/* WiFi P2P IE subelement: Service Hash */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_serv_hash_se_s { + uint8 eltId; /* SE ID: P2P_SEID_SERVICE_HASH */ + uint8 len[2]; /* SE length not including eltId, len fields + * in multiple of 6 Bytes + */ + uint8 hash[1]; /* Variable length - SHA256 hash of + * service names (can be more than one hashes) + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_serv_hash_se_s wifi_p2p_serv_hash_se_t; + +/* WiFi P2P IE subelement: Service Instance Data */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_serv_inst_data_se_s { + uint8 eltId; /* SE ID: P2P_SEID_SESSION */ + uint8 len[2]; /* SE length not including eltId, len */ + uint8 ssn_info[1]; /* Variable length - Session information as specified by + * the service layer, type matches serv. name + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_serv_inst_data_se_s wifi_p2p_serv_inst_data_se_t; + + +/* WiFi P2P IE subelement: Connection capability */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_conn_cap_data_se_s { + uint8 eltId; /* SE ID: P2P_SEID_CONNECT_CAP */ + uint8 len[2]; /* SE length not including eltId, len */ + uint8 conn_cap; /* 1byte capability as specified by the + * service layer, valid bitmask/values + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_conn_cap_data_se_s wifi_p2p_conn_cap_data_se_t; + + +/* WiFi P2P IE subelement: Advertisement ID */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_advt_id_se_s { + uint8 eltId; /* SE ID: P2P_SEID_ADVERTISE_ID */ + uint8 len[2]; /* SE length not including eltId, len fixed 4 Bytes */ + uint8 advt_id[4]; /* 4byte Advertisement ID of the peer device sent in + * PROV Disc in Network byte order + */ + uint8 advt_mac[6]; /* P2P device address of the service advertiser */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_advt_id_se_s wifi_p2p_advt_id_se_t; + + +/* WiFi P2P IE subelement: Advertise Service Hash */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_adv_serv_info_s { + uint8 advt_id[4]; /* SE Advertise ID for the service */ + uint16 nw_cfg_method; /* SE Network Config method for the service */ + uint8 serv_name_len; /* SE length of the service name */ + uint8 serv_name[1]; /* Variable length service name field */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_adv_serv_info_s wifi_p2p_adv_serv_info_t; + + +/* WiFi P2P IE subelement: Advertise Service Hash */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_advt_serv_se_s { + uint8 eltId; /* SE ID: P2P_SEID_ADVERTISE_SERVICE */ + uint8 len[2]; /* SE length not including eltId, len fields mutiple len of + * wifi_p2p_adv_serv_info_t entries + */ + wifi_p2p_adv_serv_info_t p_advt_serv_info[1]; /* Variable length + of multiple instances + of the advertise service info + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_advt_serv_se_s wifi_p2p_advt_serv_se_t; + + +/* WiFi P2P IE subelement: Session ID */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_ssn_id_se_s { + uint8 eltId; /* SE ID: P2P_SEID_SESSION_ID */ + uint8 len[2]; /* SE length not including eltId, len fixed 4 Bytes */ + uint8 ssn_id[4]; /* 4byte Session ID of the peer device sent in + * PROV Disc in Network byte order + */ + uint8 ssn_mac[6]; /* P2P device address of the seeker - session mac */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_ssn_id_se_s wifi_p2p_ssn_id_se_t; + + +#define P2P_ADVT_SERV_SE_FIXED_LEN 3 /* Includes only the element ID and len */ +#define P2P_ADVT_SERV_INFO_FIXED_LEN 7 /* Per ADV Service Instance advt_id + + * nw_config_method + serv_name_len + */ + +/* WiFi P2P Action Frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { + uint8 category; /* P2P_AF_CATEGORY */ + uint8 OUI[3]; /* OUI - P2P_OUI */ + uint8 type; /* OUI Type - P2P_VER */ + uint8 subtype; /* OUI Subtype - P2P_AF_* */ + uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ + uint8 elts[1]; /* Variable length information elements. Max size = + * ACTION_FRAME_SIZE - sizeof(this structure) - 1 + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; +#define P2P_AF_CATEGORY 0x7f + +#define P2P_AF_FIXED_LEN 7 + +/* WiFi P2P Action Frame OUI Subtypes */ +#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ +#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ +#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ +#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ + + +/* WiFi P2P Public Action Frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { + uint8 category; /* P2P_PUB_AF_CATEGORY */ + uint8 action; /* P2P_PUB_AF_ACTION */ + uint8 oui[3]; /* P2P_OUI */ + uint8 oui_type; /* OUI type - P2P_VER */ + uint8 subtype; /* OUI subtype - P2P_TYPE_* */ + uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ + uint8 elts[1]; /* Variable length information elements. Max size = + * ACTION_FRAME_SIZE - sizeof(this structure) - 1 + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; +#define P2P_PUB_AF_FIXED_LEN 8 +#define P2P_PUB_AF_CATEGORY 0x04 +#define P2P_PUB_AF_ACTION 0x09 + +/* WiFi P2P Public Action Frame OUI Subtypes */ +#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ +#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ +#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ +#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ +#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ +#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ +#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ +#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ +#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ +#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ + +/* TODO: Stop using these obsolete aliases for P2P_PAF_GON_* */ +#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ +#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP +#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF + +/* WiFi P2P IE subelement: Notice of Absence */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { + uint8 cnt_type; /* Count/Type */ + uint32 duration; /* Duration */ + uint32 interval; /* Interval */ + uint32 start; /* Start Time */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { + uint8 eltId; /* Subelement ID */ + uint8 len[2]; /* Length */ + uint8 index; /* Index */ + uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ + wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; + +#define P2P_NOA_SE_FIXED_LEN 5 + +#define P2P_NOA_SE_MAX_DESC 2 /* max NoA descriptors in presence request */ + +/* cnt_type field values */ +#define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */ +#define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */ +#define P2P_NOA_DESC_TYPE_PREFERRED 1 /* preferred values */ +#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 /* acceptable limits */ + +/* ctw_ops_parms field values */ +#define P2P_NOA_CTW_MASK 0x7f +#define P2P_NOA_OPS_MASK 0x80 +#define P2P_NOA_OPS_SHIFT 7 + +#define P2P_CTW_MIN 10 /* minimum 10TU */ + +/* + * P2P Service Discovery related + */ +#define P2PSD_ACTION_CATEGORY 0x04 + /* Public action frame */ +#define P2PSD_ACTION_ID_GAS_IREQ 0x0a + /* Action value for GAS Initial Request AF */ +#define P2PSD_ACTION_ID_GAS_IRESP 0x0b + /* Action value for GAS Initial Response AF */ +#define P2PSD_ACTION_ID_GAS_CREQ 0x0c + /* Action value for GAS Comback Request AF */ +#define P2PSD_ACTION_ID_GAS_CRESP 0x0d + /* Action value for GAS Comback Response AF */ +#define P2PSD_AD_EID 0x6c + /* Advertisement Protocol IE ID */ +#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 + /* Query Response Length Limit 7 bits plus PAME-BI 1 bit */ +#define P2PSD_ADP_PROTO_ID 0x00 + /* Advertisement Protocol ID. Always 0 for P2P SD */ +#define P2PSD_GAS_OUI P2P_OUI + /* WFA OUI */ +#define P2PSD_GAS_OUI_SUBTYPE P2P_VER + /* OUI Subtype for GAS IE */ +#define P2PSD_GAS_NQP_INFOID 0xDDDD + /* NQP Query Info ID: 56797 */ +#define P2PSD_GAS_COMEBACKDEALY 0x00 + /* Not used in the Native GAS protocol */ + +/* Service Protocol Type */ +typedef enum p2psd_svc_protype { + SVC_RPOTYPE_ALL = 0, + SVC_RPOTYPE_BONJOUR = 1, + SVC_RPOTYPE_UPNP = 2, + SVC_RPOTYPE_WSD = 3, + SVC_RPOTYPE_WFDS = 11, + SVC_RPOTYPE_VENDOR = 255 +} p2psd_svc_protype_t; + +/* Service Discovery response status code */ +typedef enum { + P2PSD_RESP_STATUS_SUCCESS = 0, + P2PSD_RESP_STATUS_PROTYPE_NA = 1, + P2PSD_RESP_STATUS_DATA_NA = 2, + P2PSD_RESP_STATUS_BAD_REQUEST = 3 +} p2psd_resp_status_t; + +/* Advertisement Protocol IE tuple field */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { + uint8 llm_pamebi; /* Query Response Length Limit bit 0-6, set to 0 plus + * Pre-Associated Message Exchange BSSID Independent bit 7, set to 0 + */ + uint8 adp_id; /* Advertisement Protocol ID: 0 for NQP Native Query Protocol */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; + +/* Advertisement Protocol IE */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { + uint8 id; /* IE ID: 0x6c - 108 */ + uint8 len; /* IE length */ + wifi_p2psd_adp_tpl_t adp_tpl; /* Advertisement Protocol Tuple field. Only one + * tuple is defined for P2P Service Discovery + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; + +/* NQP Vendor-specific Content */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { + uint8 oui_subtype; /* OUI Subtype: 0x09 */ + uint16 svc_updi; /* Service Update Indicator */ + uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request, + * wifi_p2psd_qresp_tlv_t type for service response + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; + +/* Service Request TLV */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { + uint16 len; /* Length: 5 plus size of Query Data */ + uint8 svc_prot; /* Service Protocol Type */ + uint8 svc_tscid; /* Service Transaction ID */ + uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; + +/* Query Request Frame, defined in generic format, instead of NQP specific */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { + uint16 info_id; /* Info ID: 0xDDDD */ + uint16 len; /* Length of service request TLV, 5 plus the size of request data */ + uint8 oui[3]; /* WFA OUI: 0x0050F2 */ + uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */ + +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; + +/* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qreq_len; /* Query Request Length */ + uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; + +/* Service Response TLV */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { + uint16 len; /* Length: 5 plus size of Query Data */ + uint8 svc_prot; /* Service Protocol Type */ + uint8 svc_tscid; /* Service Transaction ID */ + uint8 status; /* Value defined in Table 57 of P2P spec. */ + uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; + +/* Query Response Frame, defined in generic format, instead of NQP specific */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { + uint16 info_id; /* Info ID: 0xDDDD */ + uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */ + uint8 oui[3]; /* WFA OUI: 0x0050F2 */ + uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */ + +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; + +/* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { + uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ + uint16 cb_delay; /* GAS Comeback Delay */ + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qresp_len; /* Query Response Length */ + uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; + +/* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { + uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ + uint8 fragment_id; /* Fragmentation ID */ + uint16 cb_delay; /* GAS Comeback Delay */ + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qresp_len; /* Query Response Length */ + uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; + +/* Wi-Fi GAS Public Action Frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { + uint8 category; /* 0x04 Public Action Frame */ + uint8 action; /* 0x6c Advertisement Protocol */ + uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ + uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t + * or wifi_p2psd_gas_iresp_frame_t format + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _P2P_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/sdspi.h new file mode 100644 index 000000000000..35e8180d67dd --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/sdspi.h @@ -0,0 +1,75 @@ +/* + * SD-SPI Protocol Standard + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sdspi.h 382882 2013-02-04 23:24:31Z $ + */ +#ifndef _SD_SPI_H +#define _SD_SPI_H + +#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ +#define SPI_START_S 31 +#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ +#define SPI_DIR_S 30 +#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ +#define SPI_CMD_INDEX_S 24 +#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ +#define SPI_RW_S 23 +#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ +#define SPI_FUNC_S 20 +#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ +#define SPI_RAW_S 19 +#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ +#define SPI_STUFF_S 18 +#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ +#define SPI_BLKMODE_S 19 +#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ +#define SPI_OPCODE_S 18 +#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ +#define SPI_ADDR_S 1 +#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ +#define SPI_STUFF0_S 0 + +#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ +#define SPI_RSP_START_S 7 +#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ +#define SPI_RSP_PARAM_ERR_S 6 +#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ +#define SPI_RSP_RFU5_S 5 +#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ +#define SPI_RSP_FUNC_ERR_S 4 +#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ +#define SPI_RSP_CRC_ERR_S 3 +#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ +#define SPI_RSP_ILL_CMD_S 2 +#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ +#define SPI_RSP_RFU1_S 1 +#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ +#define SPI_RSP_IDLE_S 0 + +/* SD-SPI Protocol Definitions */ +#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ +#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ +#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ +#define SDSPI_START_BIT_MASK 0x80 + +#endif /* _SD_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/vlan.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/vlan.h new file mode 100644 index 000000000000..fc6e13b6cd48 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/vlan.h @@ -0,0 +1,95 @@ +/* + * 802.1Q VLAN protocol definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: vlan.h 382883 2013-02-04 23:26:09Z $ + */ + +#ifndef _vlan_h_ +#define _vlan_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +#ifndef VLAN_VID_MASK +#define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */ +#endif + +#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */ +#define VLAN_PRI_SHIFT 13 /* user priority */ + +#define VLAN_PRI_MASK 7 /* 3 bits of priority */ + +#define VLAN_TPID_OFFSET 12 /* offset of tag protocol id field */ +#define VLAN_TCI_OFFSET 14 /* offset of tag ctrl info field */ + +#define VLAN_TAG_LEN 4 +#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */ + +#define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */ + +struct vlan_header { + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ +}; + +struct ethervlan_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ + uint16 ether_type; +}; + +struct dot3_mac_llc_snapvlan_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ + uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ + uint16 length; /* frame length incl header */ + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[3]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ + uint16 ether_type; /* ethertype */ +}; + +#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) + + +/* This marks the end of a packed structure section. */ +#include + +#define ETHERVLAN_MOVE_HDR(d, s) \ +do { \ + struct ethervlan_header t; \ + t = *(struct ethervlan_header *)(s); \ + *(struct ethervlan_header *)(d) = t; \ +} while (0) + +#endif /* _vlan_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/wpa.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/wpa.h new file mode 100644 index 000000000000..aed733d24f0b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/wpa.h @@ -0,0 +1,217 @@ +/* + * Fundamental types and constants relating to WPA + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wpa.h 492853 2014-07-23 17:20:34Z $ + */ + +#ifndef _proto_wpa_h_ +#define _proto_wpa_h_ + +#include +#include + + +/* This marks the start of a packed structure section. */ +#include + +/* Reason Codes */ + +/* 13 through 23 taken from IEEE Std 802.11i-2004 */ +#define DOT11_RC_INVALID_WPA_IE 13 /* Invalid info. element */ +#define DOT11_RC_MIC_FAILURE 14 /* Michael failure */ +#define DOT11_RC_4WH_TIMEOUT 15 /* 4-way handshake timeout */ +#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 /* Group key update timeout */ +#define DOT11_RC_WPA_IE_MISMATCH 17 /* WPA IE in 4-way handshake differs from + * (re-)assoc. request/probe response + */ +#define DOT11_RC_INVALID_MC_CIPHER 18 /* Invalid multicast cipher */ +#define DOT11_RC_INVALID_UC_CIPHER 19 /* Invalid unicast cipher */ +#define DOT11_RC_INVALID_AKMP 20 /* Invalid authenticated key management protocol */ +#define DOT11_RC_BAD_WPA_VERSION 21 /* Unsupported WPA version */ +#define DOT11_RC_INVALID_WPA_CAP 22 /* Invalid WPA IE capabilities */ +#define DOT11_RC_8021X_AUTH_FAIL 23 /* 802.1X authentication failure */ + +#define WPA2_PMKID_LEN 16 + +/* WPA IE fixed portion */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint8 tag; /* TAG */ + uint8 length; /* TAG length */ + uint8 oui[3]; /* IE OUI */ + uint8 oui_type; /* OUI type */ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT version; /* IE version */ +} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; +#define WPA_IE_OUITYPE_LEN 4 +#define WPA_IE_FIXED_LEN 8 +#define WPA_IE_TAG_FIXED_LEN 6 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 tag; /* TAG */ + uint8 length; /* TAG length */ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT version; /* IE version */ +} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; +#define WPA_RSN_IE_FIXED_LEN 4 +#define WPA_RSN_IE_TAG_FIXED_LEN 2 +typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; + +#define WFA_OSEN_IE_FIXED_LEN 6 + +/* WPA suite/multicast suite */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint8 oui[3]; + uint8 type; +} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; +#define WPA_SUITE_LEN 4 + +/* WPA unicast suite list/key management suite list */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT count; + wpa_suite_t list[1]; +} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; +#define WPA_IE_SUITE_COUNT_LEN 2 +typedef BWL_PRE_PACKED_STRUCT struct +{ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT count; + wpa_pmkid_t list[1]; +} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; + +/* WPA cipher suites */ +#define WPA_CIPHER_NONE 0 /* None */ +#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */ +#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */ +#define WPA_CIPHER_AES_OCB 3 /* AES (OCB) */ +#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */ +#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */ +#define WPA_CIPHER_BIP 6 /* WEP (104-bit) */ +#define WPA_CIPHER_TPK 7 /* Group addressed traffic not allowed */ +#ifdef BCMCCX +#define WPA_CIPHER_CKIP 8 /* KP with no MIC */ +#define WPA_CIPHER_CKIP_MMH 9 /* KP with MIC ("CKIP/MMH", "CKIP+CMIC") */ +#define WPA_CIPHER_WEP_MMH 10 /* MIC with no KP ("WEP/MMH", "CMIC") */ + +#define IS_CCX_CIPHER(cipher) ((cipher) == WPA_CIPHER_CKIP || \ + (cipher) == WPA_CIPHER_CKIP_MMH || \ + (cipher) == WPA_CIPHER_WEP_MMH) +#endif + +#ifdef BCMWAPI_WAI +#define WAPI_CIPHER_NONE WPA_CIPHER_NONE +#define WAPI_CIPHER_SMS4 11 + +#define WAPI_CSE_WPI_SMS4 1 +#endif /* BCMWAPI_WAI */ + +#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ + (cipher) == WPA_CIPHER_WEP_40 || \ + (cipher) == WPA_CIPHER_WEP_104 || \ + (cipher) == WPA_CIPHER_TKIP || \ + (cipher) == WPA_CIPHER_AES_OCB || \ + (cipher) == WPA_CIPHER_AES_CCM || \ + (cipher) == WPA_CIPHER_TPK) + +#ifdef BCMWAPI_WAI +#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ + (cipher) == WAPI_CSE_WPI_SMS4) + +/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */ +#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ + WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) + +#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ + WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) +#endif /* BCMWAPI_WAI */ + +/* WPA TKIP countermeasures parameters */ +#define WPA_TKIP_CM_DETECT 60 /* multiple MIC failure window (seconds) */ +#define WPA_TKIP_CM_BLOCK 60 /* countermeasures active window (seconds) */ + +/* RSN IE defines */ +#define RSN_CAP_LEN 2 /* Length of RSN capabilities field (2 octets) */ + +/* RSN Capabilities defined in 802.11i */ +#define RSN_CAP_PREAUTH 0x0001 +#define RSN_CAP_NOPAIRWISE 0x0002 +#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C +#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 +#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 +#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 +#define RSN_CAP_1_REPLAY_CNTR 0 +#define RSN_CAP_2_REPLAY_CNTRS 1 +#define RSN_CAP_4_REPLAY_CNTRS 2 +#define RSN_CAP_16_REPLAY_CNTRS 3 +#define RSN_CAP_MFPR 0x0040 +#define RSN_CAP_MFPC 0x0080 +#define RSN_CAP_SPPC 0x0400 +#define RSN_CAP_SPPR 0x0800 + +/* WPA capabilities defined in 802.11i */ +#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS +#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS +#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT +#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK + +/* WPA capabilities defined in 802.11zD9.0 */ +#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) /* bit 9 */ + +/* WPA Specific defines */ +#define WPA_CAP_LEN RSN_CAP_LEN /* Length of RSN capabilities in RSN IE (2 octets) */ +#define WPA_PMKID_CNT_LEN 2 /* Length of RSN PMKID count (2 octests) */ + +#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH + +#define WPA2_PMKID_COUNT_LEN 2 +#define RSN_GROUPMANAGE_CIPHER_LEN 4 + +#ifdef BCMWAPI_WAI +#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH + +/* Other WAI definition */ +#define WAPI_WAI_REQUEST 0x00F1 +#define WAPI_UNICAST_REKEY 0x00F2 +#define WAPI_STA_AGING 0x00F3 +#define WAPI_MUTIL_REKEY 0x00F4 +#define WAPI_STA_STATS 0x00F5 + +#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */ +#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */ +#endif /* BCMWAPI_WAI */ + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _proto_wpa_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/proto/wps.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/wps.h new file mode 100644 index 000000000000..ce78daeb6b0c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/wps.h @@ -0,0 +1,386 @@ +/* + * WPS IE definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id$ + */ + +#ifndef _WPS_ +#define _WPS_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Data Element Definitions */ +#define WPS_ID_AP_CHANNEL 0x1001 +#define WPS_ID_ASSOC_STATE 0x1002 +#define WPS_ID_AUTH_TYPE 0x1003 +#define WPS_ID_AUTH_TYPE_FLAGS 0x1004 +#define WPS_ID_AUTHENTICATOR 0x1005 +#define WPS_ID_CONFIG_METHODS 0x1008 +#define WPS_ID_CONFIG_ERROR 0x1009 +#define WPS_ID_CONF_URL4 0x100A +#define WPS_ID_CONF_URL6 0x100B +#define WPS_ID_CONN_TYPE 0x100C +#define WPS_ID_CONN_TYPE_FLAGS 0x100D +#define WPS_ID_CREDENTIAL 0x100E +#define WPS_ID_DEVICE_NAME 0x1011 +#define WPS_ID_DEVICE_PWD_ID 0x1012 +#define WPS_ID_E_HASH1 0x1014 +#define WPS_ID_E_HASH2 0x1015 +#define WPS_ID_E_SNONCE1 0x1016 +#define WPS_ID_E_SNONCE2 0x1017 +#define WPS_ID_ENCR_SETTINGS 0x1018 +#define WPS_ID_ENCR_TYPE 0x100F +#define WPS_ID_ENCR_TYPE_FLAGS 0x1010 +#define WPS_ID_ENROLLEE_NONCE 0x101A +#define WPS_ID_FEATURE_ID 0x101B +#define WPS_ID_IDENTITY 0x101C +#define WPS_ID_IDENTITY_PROOF 0x101D +#define WPS_ID_KEY_WRAP_AUTH 0x101E +#define WPS_ID_KEY_IDENTIFIER 0x101F +#define WPS_ID_MAC_ADDR 0x1020 +#define WPS_ID_MANUFACTURER 0x1021 +#define WPS_ID_MSG_TYPE 0x1022 +#define WPS_ID_MODEL_NAME 0x1023 +#define WPS_ID_MODEL_NUMBER 0x1024 +#define WPS_ID_NW_INDEX 0x1026 +#define WPS_ID_NW_KEY 0x1027 +#define WPS_ID_NW_KEY_INDEX 0x1028 +#define WPS_ID_NEW_DEVICE_NAME 0x1029 +#define WPS_ID_NEW_PWD 0x102A +#define WPS_ID_OOB_DEV_PWD 0x102C +#define WPS_ID_OS_VERSION 0x102D +#define WPS_ID_POWER_LEVEL 0x102F +#define WPS_ID_PSK_CURRENT 0x1030 +#define WPS_ID_PSK_MAX 0x1031 +#define WPS_ID_PUBLIC_KEY 0x1032 +#define WPS_ID_RADIO_ENABLED 0x1033 +#define WPS_ID_REBOOT 0x1034 +#define WPS_ID_REGISTRAR_CURRENT 0x1035 +#define WPS_ID_REGISTRAR_ESTBLSHD 0x1036 +#define WPS_ID_REGISTRAR_LIST 0x1037 +#define WPS_ID_REGISTRAR_MAX 0x1038 +#define WPS_ID_REGISTRAR_NONCE 0x1039 +#define WPS_ID_REQ_TYPE 0x103A +#define WPS_ID_RESP_TYPE 0x103B +#define WPS_ID_RF_BAND 0x103C +#define WPS_ID_R_HASH1 0x103D +#define WPS_ID_R_HASH2 0x103E +#define WPS_ID_R_SNONCE1 0x103F +#define WPS_ID_R_SNONCE2 0x1040 +#define WPS_ID_SEL_REGISTRAR 0x1041 +#define WPS_ID_SERIAL_NUM 0x1042 +#define WPS_ID_SC_STATE 0x1044 +#define WPS_ID_SSID 0x1045 +#define WPS_ID_TOT_NETWORKS 0x1046 +#define WPS_ID_UUID_E 0x1047 +#define WPS_ID_UUID_R 0x1048 +#define WPS_ID_VENDOR_EXT 0x1049 +#define WPS_ID_VERSION 0x104A +#define WPS_ID_X509_CERT_REQ 0x104B +#define WPS_ID_X509_CERT 0x104C +#define WPS_ID_EAP_IDENTITY 0x104D +#define WPS_ID_MSG_COUNTER 0x104E +#define WPS_ID_PUBKEY_HASH 0x104F +#define WPS_ID_REKEY_KEY 0x1050 +#define WPS_ID_KEY_LIFETIME 0x1051 +#define WPS_ID_PERM_CFG_METHODS 0x1052 +#define WPS_ID_SEL_REG_CFG_METHODS 0x1053 +#define WPS_ID_PRIM_DEV_TYPE 0x1054 +#define WPS_ID_SEC_DEV_TYPE_LIST 0x1055 +#define WPS_ID_PORTABLE_DEVICE 0x1056 +#define WPS_ID_AP_SETUP_LOCKED 0x1057 +#define WPS_ID_APP_LIST 0x1058 +#define WPS_ID_EAP_TYPE 0x1059 +#define WPS_ID_INIT_VECTOR 0x1060 +#define WPS_ID_KEY_PROVIDED_AUTO 0x1061 +#define WPS_ID_8021X_ENABLED 0x1062 +#define WPS_ID_WEP_TRANSMIT_KEY 0x1064 +#define WPS_ID_REQ_DEV_TYPE 0x106A + +/* WSC 2.0, WFA Vendor Extension Subelements */ +#define WFA_VENDOR_EXT_ID "\x00\x37\x2A" +#define WPS_WFA_SUBID_VERSION2 0x00 +#define WPS_WFA_SUBID_AUTHORIZED_MACS 0x01 +#define WPS_WFA_SUBID_NW_KEY_SHAREABLE 0x02 +#define WPS_WFA_SUBID_REQ_TO_ENROLL 0x03 +#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME 0x04 +#define WPS_WFA_SUBID_REG_CFG_METHODS 0x05 + + +/* WCN-NET Windows Rally Vertical Pairing Vendor Extensions */ +#define MS_VENDOR_EXT_ID "\x00\x01\x37" +#define WPS_MS_ID_VPI 0x1001 /* Vertical Pairing Identifier TLV */ +#define WPS_MS_ID_TRANSPORT_UUID 0x1002 /* Transport UUID TLV */ + +/* Vertical Pairing Identifier TLV Definitions */ +#define WPS_MS_VPI_TRANSPORT_NONE 0x00 /* None */ +#define WPS_MS_VPI_TRANSPORT_DPWS 0x01 /* Devices Profile for Web Services */ +#define WPS_MS_VPI_TRANSPORT_UPNP 0x02 /* uPnP */ +#define WPS_MS_VPI_TRANSPORT_SDNWS 0x03 /* Secure Devices Profile for Web Services */ +#define WPS_MS_VPI_NO_PROFILE_REQ 0x00 /* Wi-Fi profile not requested. + * Not supported in Windows 7 + */ +#define WPS_MS_VPI_PROFILE_REQ 0x01 /* Wi-Fi profile requested. */ + +/* sizes of the fixed size elements */ +#define WPS_ID_AP_CHANNEL_S 2 +#define WPS_ID_ASSOC_STATE_S 2 +#define WPS_ID_AUTH_TYPE_S 2 +#define WPS_ID_AUTH_TYPE_FLAGS_S 2 +#define WPS_ID_AUTHENTICATOR_S 8 +#define WPS_ID_CONFIG_METHODS_S 2 +#define WPS_ID_CONFIG_ERROR_S 2 +#define WPS_ID_CONN_TYPE_S 1 +#define WPS_ID_CONN_TYPE_FLAGS_S 1 +#define WPS_ID_DEVICE_PWD_ID_S 2 +#define WPS_ID_ENCR_TYPE_S 2 +#define WPS_ID_ENCR_TYPE_FLAGS_S 2 +#define WPS_ID_FEATURE_ID_S 4 +#define WPS_ID_MAC_ADDR_S 6 +#define WPS_ID_MSG_TYPE_S 1 +#define WPS_ID_SC_STATE_S 1 +#define WPS_ID_RF_BAND_S 1 +#define WPS_ID_OS_VERSION_S 4 +#define WPS_ID_VERSION_S 1 +#define WPS_ID_SEL_REGISTRAR_S 1 +#define WPS_ID_SEL_REG_CFG_METHODS_S 2 +#define WPS_ID_REQ_TYPE_S 1 +#define WPS_ID_RESP_TYPE_S 1 +#define WPS_ID_AP_SETUP_LOCKED_S 1 + +/* WSC 2.0, WFA Vendor Extension Subelements */ +#define WPS_WFA_SUBID_VERSION2_S 1 +#define WPS_WFA_SUBID_NW_KEY_SHAREABLE_S 1 +#define WPS_WFA_SUBID_REQ_TO_ENROLL_S 1 +#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME_S 1 +#define WPS_WFA_SUBID_REG_CFG_METHODS_S 2 + +/* Association states */ +#define WPS_ASSOC_NOT_ASSOCIATED 0 +#define WPS_ASSOC_CONN_SUCCESS 1 +#define WPS_ASSOC_CONFIG_FAIL 2 +#define WPS_ASSOC_ASSOC_FAIL 3 +#define WPS_ASSOC_IP_FAIL 4 + +/* Authentication types */ +#define WPS_AUTHTYPE_OPEN 0x0001 +#define WPS_AUTHTYPE_WPAPSK 0x0002 /* Deprecated in WSC 2.0 */ +#define WPS_AUTHTYPE_SHARED 0x0004 /* Deprecated in WSC 2.0 */ +#define WPS_AUTHTYPE_WPA 0x0008 /* Deprecated in WSC 2.0 */ +#define WPS_AUTHTYPE_WPA2 0x0010 +#define WPS_AUTHTYPE_WPA2PSK 0x0020 + +/* Config methods */ +#define WPS_CONFMET_USBA 0x0001 /* Deprecated in WSC 2.0 */ +#define WPS_CONFMET_ETHERNET 0x0002 /* Deprecated in WSC 2.0 */ +#define WPS_CONFMET_LABEL 0x0004 +#define WPS_CONFMET_DISPLAY 0x0008 +#define WPS_CONFMET_EXT_NFC_TOK 0x0010 +#define WPS_CONFMET_INT_NFC_TOK 0x0020 +#define WPS_CONFMET_NFC_INTF 0x0040 +#define WPS_CONFMET_PBC 0x0080 +#define WPS_CONFMET_KEYPAD 0x0100 +/* WSC 2.0 */ +#define WPS_CONFMET_VIRT_PBC 0x0280 +#define WPS_CONFMET_PHY_PBC 0x0480 +#define WPS_CONFMET_VIRT_DISPLAY 0x2008 +#define WPS_CONFMET_PHY_DISPLAY 0x4008 + +/* WPS error messages */ +#define WPS_ERROR_NO_ERROR 0 +#define WPS_ERROR_OOB_INT_READ_ERR 1 +#define WPS_ERROR_DECRYPT_CRC_FAIL 2 +#define WPS_ERROR_CHAN24_NOT_SUPP 3 +#define WPS_ERROR_CHAN50_NOT_SUPP 4 +#define WPS_ERROR_SIGNAL_WEAK 5 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_NW_AUTH_FAIL 6 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_NW_ASSOC_FAIL 7 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_NO_DHCP_RESP 8 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_FAILED_DHCP_CONF 9 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_IP_ADDR_CONFLICT 10 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_FAIL_CONN_REGISTRAR 11 +#define WPS_ERROR_MULTI_PBC_DETECTED 12 +#define WPS_ERROR_ROGUE_SUSPECTED 13 +#define WPS_ERROR_DEVICE_BUSY 14 +#define WPS_ERROR_SETUP_LOCKED 15 +#define WPS_ERROR_MSG_TIMEOUT 16 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_REG_SESSION_TIMEOUT 17 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_DEV_PWD_AUTH_FAIL 18 +#define WPS_ERROR_60GHZ_NOT_SUPPORT 19 +#define WPS_ERROR_PKH_MISMATCH 20 /* Public Key Hash Mismatch */ + +/* Connection types */ +#define WPS_CONNTYPE_ESS 0x01 +#define WPS_CONNTYPE_IBSS 0x02 + +/* Device password ID */ +#define WPS_DEVICEPWDID_DEFAULT 0x0000 +#define WPS_DEVICEPWDID_USER_SPEC 0x0001 +#define WPS_DEVICEPWDID_MACHINE_SPEC 0x0002 +#define WPS_DEVICEPWDID_REKEY 0x0003 +#define WPS_DEVICEPWDID_PUSH_BTN 0x0004 +#define WPS_DEVICEPWDID_REG_SPEC 0x0005 +#define WPS_DEVICEPWDID_IBSS 0x0006 +#define WPS_DEVICEPWDID_NFC_CHO 0x0007 /* NFC-Connection-Handover */ +#define WPS_DEVICEPWDID_WFDS 0x0008 /* Wi-Fi Direct Services Specification */ + +/* Encryption type */ +#define WPS_ENCRTYPE_NONE 0x0001 +#define WPS_ENCRTYPE_WEP 0x0002 /* Deprecated in WSC 2.0 */ +#define WPS_ENCRTYPE_TKIP 0x0004 /* Deprecated in version 2.0. TKIP can only + * be advertised on the AP when Mixed Mode + * is enabled (Encryption Type is 0x000c). + */ +#define WPS_ENCRTYPE_AES 0x0008 + + +/* WPS Message Types */ +#define WPS_ID_BEACON 0x01 +#define WPS_ID_PROBE_REQ 0x02 +#define WPS_ID_PROBE_RESP 0x03 +#define WPS_ID_MESSAGE_M1 0x04 +#define WPS_ID_MESSAGE_M2 0x05 +#define WPS_ID_MESSAGE_M2D 0x06 +#define WPS_ID_MESSAGE_M3 0x07 +#define WPS_ID_MESSAGE_M4 0x08 +#define WPS_ID_MESSAGE_M5 0x09 +#define WPS_ID_MESSAGE_M6 0x0A +#define WPS_ID_MESSAGE_M7 0x0B +#define WPS_ID_MESSAGE_M8 0x0C +#define WPS_ID_MESSAGE_ACK 0x0D +#define WPS_ID_MESSAGE_NACK 0x0E +#define WPS_ID_MESSAGE_DONE 0x0F + +/* WSP private ID for local use */ +#define WPS_PRIVATE_ID_IDENTITY (WPS_ID_MESSAGE_DONE + 1) +#define WPS_PRIVATE_ID_WPS_START (WPS_ID_MESSAGE_DONE + 2) +#define WPS_PRIVATE_ID_FAILURE (WPS_ID_MESSAGE_DONE + 3) +#define WPS_PRIVATE_ID_FRAG (WPS_ID_MESSAGE_DONE + 4) +#define WPS_PRIVATE_ID_FRAG_ACK (WPS_ID_MESSAGE_DONE + 5) +#define WPS_PRIVATE_ID_EAPOL_START (WPS_ID_MESSAGE_DONE + 6) + + +/* Device Type categories for primary and secondary device types */ +#define WPS_DEVICE_TYPE_CAT_COMPUTER 1 +#define WPS_DEVICE_TYPE_CAT_INPUT_DEVICE 2 +#define WPS_DEVICE_TYPE_CAT_PRINTER 3 +#define WPS_DEVICE_TYPE_CAT_CAMERA 4 +#define WPS_DEVICE_TYPE_CAT_STORAGE 5 +#define WPS_DEVICE_TYPE_CAT_NW_INFRA 6 +#define WPS_DEVICE_TYPE_CAT_DISPLAYS 7 +#define WPS_DEVICE_TYPE_CAT_MM_DEVICES 8 +#define WPS_DEVICE_TYPE_CAT_GAME_DEVICES 9 +#define WPS_DEVICE_TYPE_CAT_TELEPHONE 10 +#define WPS_DEVICE_TYPE_CAT_AUDIO_DEVICES 11 /* WSC 2.0 */ + +/* Device Type sub categories for primary and secondary device types */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_PC 1 +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_SERVER 2 +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MEDIA_CTR 3 +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_UM_PC 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NOTEBOOK 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_DESKTOP 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MID 7 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NETBOOK 8 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_Keyboard 1 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_MOUSE 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_JOYSTICK 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_TRACKBALL 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_GAM_CTRL 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_REMOTE 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_TOUCHSCREEN 7 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_BIO_READER 8 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_BAR_READER 9 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_PRINTER 1 +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_SCANNER 2 +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_FAX 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_COPIER 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_ALLINONE 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_DGTL_STILL 1 +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_VIDEO_CAM 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_WEB_CAM 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_SECU_CAM 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_STOR_NAS 1 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_AP 1 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_ROUTER 2 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_SWITCH 3 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_GATEWAY 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_NW_BRIDGE 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_TV 1 +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PIC_FRAME 2 +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PROJECTOR 3 +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_MONITOR 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_MM_DAR 1 +#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVR 2 +#define WPS_DEVICE_TYPE_SUB_CAT_MM_MCX 3 +#define WPS_DEVICE_TYPE_SUB_CAT_MM_STB 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_MM_MS_ME 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVP 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX 1 +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX_360 2 +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PS 3 +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_GC 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PGD 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_WM 1 +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PSM 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PDM 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SSM 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SDM 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_TUNER 1 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_SPEAKERS 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_PMP 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HEADSET 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HPHONE 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_MPHONE 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HTS 7 /* WSC 2.0 */ + + +/* Device request/response type */ +#define WPS_MSGTYPE_ENROLLEE_INFO_ONLY 0x00 +#define WPS_MSGTYPE_ENROLLEE_OPEN_8021X 0x01 +#define WPS_MSGTYPE_REGISTRAR 0x02 +#define WPS_MSGTYPE_AP_WLAN_MGR 0x03 + +/* RF Band */ +#define WPS_RFBAND_24GHZ 0x01 +#define WPS_RFBAND_50GHZ 0x02 + +/* Simple Config state */ +#define WPS_SCSTATE_UNCONFIGURED 0x01 +#define WPS_SCSTATE_CONFIGURED 0x02 +#define WPS_SCSTATE_OFF 11 + +/* WPS Vendor extension key */ +#define WPS_OUI_HEADER_LEN 2 +#define WPS_OUI_HEADER_SIZE 4 +#define WPS_OUI_FIXED_HEADER_OFF 16 +#define WPS_WFA_SUBID_V2_OFF 3 +#define WPS_WFA_V2_OFF 5 + +#ifdef __cplusplus +} +#endif + +#endif /* _WPS_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sbchipc.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbchipc.h new file mode 100644 index 000000000000..7205468019ab --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sbchipc.h @@ -0,0 +1,3646 @@ +/* + * SiliconBackplane Chipcommon core hardware definitions. + * + * The chipcommon core provides chip identification, SB control, + * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, + * GPIO interface, extbus, and support for serial and parallel flashes. + * + * $Id: sbchipc.h 474281 2014-04-30 18:24:55Z $ + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + */ + +#ifndef _SBCHIPC_H +#define _SBCHIPC_H + +#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif /* PAD */ + +/** + * In chipcommon rev 49 the pmu registers have been moved from chipc to the pmu core if the + * 'AOBPresent' bit of 'CoreCapabilitiesExt' is set. If this field is set, the traditional chipc to + * [pmu|gci|sreng] register interface is deprecated and removed. These register blocks would instead + * be assigned their respective chipc-specific address space and connected to the Always On + * Backplane via the APB interface. + */ +typedef volatile struct { + uint32 PAD[384]; + uint32 pmucontrol; /* 0x600 */ + uint32 pmucapabilities; + uint32 pmustatus; + uint32 res_state; + uint32 res_pending; + uint32 pmutimer; + uint32 min_res_mask; + uint32 max_res_mask; + uint32 res_table_sel; + uint32 res_dep_mask; + uint32 res_updn_timer; + uint32 res_timer; + uint32 clkstretch; + uint32 pmuwatchdog; + uint32 gpiosel; /* 0x638, rev >= 1 */ + uint32 gpioenable; /* 0x63c, rev >= 1 */ + uint32 res_req_timer_sel; + uint32 res_req_timer; + uint32 res_req_mask; + uint32 PAD; + uint32 chipcontrol_addr; /* 0x650 */ + uint32 chipcontrol_data; /* 0x654 */ + uint32 regcontrol_addr; + uint32 regcontrol_data; + uint32 pllcontrol_addr; + uint32 pllcontrol_data; + uint32 pmustrapopt; /* 0x668, corerev >= 28 */ + uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ + uint32 retention_ctl; /* 0x670 */ + uint32 PAD[3]; + uint32 retention_grpidx; /* 0x680 */ + uint32 retention_grpctl; /* 0x684 */ + uint32 PAD[20]; + uint32 pmucontrol_ext; /* 0x6d8 */ + uint32 slowclkperiod; /* 0x6dc */ + uint32 PAD[8]; + uint32 pmuintmask0; /* 0x700 */ + uint32 pmuintmask1; /* 0x704 */ + uint32 PAD[14]; + uint32 pmuintstatus; /* 0x740 */ +} pmuregs_t; + +typedef struct eci_prerev35 { + uint32 eci_output; + uint32 eci_control; + uint32 eci_inputlo; + uint32 eci_inputmi; + uint32 eci_inputhi; + uint32 eci_inputintpolaritylo; + uint32 eci_inputintpolaritymi; + uint32 eci_inputintpolarityhi; + uint32 eci_intmasklo; + uint32 eci_intmaskmi; + uint32 eci_intmaskhi; + uint32 eci_eventlo; + uint32 eci_eventmi; + uint32 eci_eventhi; + uint32 eci_eventmasklo; + uint32 eci_eventmaskmi; + uint32 eci_eventmaskhi; + uint32 PAD[3]; +} eci_prerev35_t; + +typedef struct eci_rev35 { + uint32 eci_outputlo; + uint32 eci_outputhi; + uint32 eci_controllo; + uint32 eci_controlhi; + uint32 eci_inputlo; + uint32 eci_inputhi; + uint32 eci_inputintpolaritylo; + uint32 eci_inputintpolarityhi; + uint32 eci_intmasklo; + uint32 eci_intmaskhi; + uint32 eci_eventlo; + uint32 eci_eventhi; + uint32 eci_eventmasklo; + uint32 eci_eventmaskhi; + uint32 eci_auxtx; + uint32 eci_auxrx; + uint32 eci_datatag; + uint32 eci_uartescvalue; + uint32 eci_autobaudctr; + uint32 eci_uartfifolevel; +} eci_rev35_t; + +typedef struct flash_config { + uint32 PAD[19]; + /* Flash struct configuration registers (0x18c) for BCM4706 (corerev = 31) */ + uint32 flashstrconfig; +} flash_config_t; + +typedef volatile struct { + uint32 chipid; /* 0x0 */ + uint32 capabilities; + uint32 corecontrol; /* corerev >= 1 */ + uint32 bist; + + /* OTP */ + uint32 otpstatus; /* 0x10, corerev >= 10 */ + uint32 otpcontrol; + uint32 otpprog; + uint32 otplayout; /* corerev >= 23 */ + + /* Interrupt control */ + uint32 intstatus; /* 0x20 */ + uint32 intmask; + + /* Chip specific regs */ + uint32 chipcontrol; /* 0x28, rev >= 11 */ + uint32 chipstatus; /* 0x2c, rev >= 11 */ + + /* Jtag Master */ + uint32 jtagcmd; /* 0x30, rev >= 10 */ + uint32 jtagir; + uint32 jtagdr; + uint32 jtagctrl; + + /* serial flash interface registers */ + uint32 flashcontrol; /* 0x40 */ + uint32 flashaddress; + uint32 flashdata; + uint32 otplayoutextension; /* rev >= 35 */ + + /* Silicon backplane configuration broadcast control */ + uint32 broadcastaddress; /* 0x50 */ + uint32 broadcastdata; + + /* gpio - cleared only by power-on-reset */ + uint32 gpiopullup; /* 0x58, corerev >= 20 */ + uint32 gpiopulldown; /* 0x5c, corerev >= 20 */ + uint32 gpioin; /* 0x60 */ + uint32 gpioout; /* 0x64 */ + uint32 gpioouten; /* 0x68 */ + uint32 gpiocontrol; /* 0x6C */ + uint32 gpiointpolarity; /* 0x70 */ + uint32 gpiointmask; /* 0x74 */ + + /* GPIO events corerev >= 11 */ + uint32 gpioevent; + uint32 gpioeventintmask; + + /* Watchdog timer */ + uint32 watchdog; /* 0x80 */ + + /* GPIO events corerev >= 11 */ + uint32 gpioeventintpolarity; + + /* GPIO based LED powersave registers corerev >= 16 */ + uint32 gpiotimerval; /* 0x88 */ + uint32 gpiotimeroutmask; + + /* clock control */ + uint32 clockcontrol_n; /* 0x90 */ + uint32 clockcontrol_sb; /* aka m0 */ + uint32 clockcontrol_pci; /* aka m1 */ + uint32 clockcontrol_m2; /* mii/uart/mipsref */ + uint32 clockcontrol_m3; /* cpu */ + uint32 clkdiv; /* corerev >= 3 */ + uint32 gpiodebugsel; /* corerev >= 28 */ + uint32 capabilities_ext; /* 0xac */ + + /* pll delay registers (corerev >= 4) */ + uint32 pll_on_delay; /* 0xb0 */ + uint32 fref_sel_delay; + uint32 slow_clk_ctl; /* 5 < corerev < 10 */ + uint32 PAD; + + /* Instaclock registers (corerev >= 10) */ + uint32 system_clk_ctl; /* 0xc0 */ + uint32 clkstatestretch; + uint32 PAD[2]; + + /* Indirect backplane access (corerev >= 22) */ + uint32 bp_addrlow; /* 0xd0 */ + uint32 bp_addrhigh; + uint32 bp_data; + uint32 PAD; + uint32 bp_indaccess; + /* SPI registers, corerev >= 37 */ + uint32 gsioctrl; + uint32 gsioaddress; + uint32 gsiodata; + + /* More clock dividers (corerev >= 32) */ + uint32 clkdiv2; + /* FAB ID (corerev >= 40) */ + uint32 otpcontrol1; + uint32 fabid; /* 0xf8 */ + + /* In AI chips, pointer to erom */ + uint32 eromptr; /* 0xfc */ + + /* ExtBus control registers (corerev >= 3) */ + uint32 pcmcia_config; /* 0x100 */ + uint32 pcmcia_memwait; + uint32 pcmcia_attrwait; + uint32 pcmcia_iowait; + uint32 ide_config; + uint32 ide_memwait; + uint32 ide_attrwait; + uint32 ide_iowait; + uint32 prog_config; + uint32 prog_waitcount; + uint32 flash_config; + uint32 flash_waitcount; + uint32 SECI_config; /* 0x130 SECI configuration */ + uint32 SECI_status; + uint32 SECI_statusmask; + uint32 SECI_rxnibchanged; + + uint32 PAD[20]; + + /* SROM interface (corerev >= 32) */ + uint32 sromcontrol; /* 0x190 */ + uint32 sromaddress; + uint32 sromdata; + uint32 PAD[1]; /* 0x19C */ + /* NAND flash registers for BCM4706 (corerev = 31) */ + uint32 nflashctrl; /* 0x1a0 */ + uint32 nflashconf; + uint32 nflashcoladdr; + uint32 nflashrowaddr; + uint32 nflashdata; + uint32 nflashwaitcnt0; /* 0x1b4 */ + uint32 PAD[2]; + + uint32 seci_uart_data; /* 0x1C0 */ + uint32 seci_uart_bauddiv; + uint32 seci_uart_fcr; + uint32 seci_uart_lcr; + uint32 seci_uart_mcr; + uint32 seci_uart_lsr; + uint32 seci_uart_msr; + uint32 seci_uart_baudadj; + /* Clock control and hardware workarounds (corerev >= 20) */ + uint32 clk_ctl_st; /* 0x1e0 */ + uint32 hw_war; + uint32 PAD[70]; + + /* UARTs */ + uint8 uart0data; /* 0x300 */ + uint8 uart0imr; + uint8 uart0fcr; + uint8 uart0lcr; + uint8 uart0mcr; + uint8 uart0lsr; + uint8 uart0msr; + uint8 uart0scratch; + uint8 PAD[248]; /* corerev >= 1 */ + + uint8 uart1data; /* 0x400 */ + uint8 uart1imr; + uint8 uart1fcr; + uint8 uart1lcr; + uint8 uart1mcr; + uint8 uart1lsr; + uint8 uart1msr; + uint8 uart1scratch; /* 0x407 */ + uint32 PAD[62]; + + /* save/restore, corerev >= 48 */ + uint32 sr_capability; /* 0x500 */ + uint32 sr_control0; /* 0x504 */ + uint32 sr_control1; /* 0x508 */ + uint32 gpio_control; /* 0x50C */ + uint32 PAD[60]; + + /* PMU registers (corerev >= 20) */ + /* Note: all timers driven by ILP clock are updated asynchronously to HT/ALP. + * The CPU must read them twice, compare, and retry if different. + */ + uint32 pmucontrol; /* 0x600 */ + uint32 pmucapabilities; + uint32 pmustatus; + uint32 res_state; + uint32 res_pending; + uint32 pmutimer; + uint32 min_res_mask; + uint32 max_res_mask; + uint32 res_table_sel; + uint32 res_dep_mask; + uint32 res_updn_timer; + uint32 res_timer; + uint32 clkstretch; + uint32 pmuwatchdog; + uint32 gpiosel; /* 0x638, rev >= 1 */ + uint32 gpioenable; /* 0x63c, rev >= 1 */ + uint32 res_req_timer_sel; + uint32 res_req_timer; + uint32 res_req_mask; + uint32 PAD; + uint32 chipcontrol_addr; /* 0x650 */ + uint32 chipcontrol_data; /* 0x654 */ + uint32 regcontrol_addr; + uint32 regcontrol_data; + uint32 pllcontrol_addr; + uint32 pllcontrol_data; + uint32 pmustrapopt; /* 0x668, corerev >= 28 */ + uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ + uint32 retention_ctl; /* 0x670 */ + uint32 PAD[3]; + uint32 retention_grpidx; /* 0x680 */ + uint32 retention_grpctl; /* 0x684 */ + uint32 PAD[20]; + uint32 pmucontrol_ext; /* 0x6d8 */ + uint32 slowclkperiod; /* 0x6dc */ + uint32 PAD[8]; + uint32 pmuintmask0; /* 0x700 */ + uint32 pmuintmask1; /* 0x704 */ + uint32 PAD[14]; + uint32 pmuintstatus; /* 0x740 */ + uint32 PAD[47]; + uint16 sromotp[512]; /* 0x800 */ +#ifdef NFLASH_SUPPORT + /* Nand flash MLC controller registers (corerev >= 38) */ + uint32 nand_revision; /* 0xC00 */ + uint32 nand_cmd_start; + uint32 nand_cmd_addr_x; + uint32 nand_cmd_addr; + uint32 nand_cmd_end_addr; + uint32 nand_cs_nand_select; + uint32 nand_cs_nand_xor; + uint32 PAD; + uint32 nand_spare_rd0; + uint32 nand_spare_rd4; + uint32 nand_spare_rd8; + uint32 nand_spare_rd12; + uint32 nand_spare_wr0; + uint32 nand_spare_wr4; + uint32 nand_spare_wr8; + uint32 nand_spare_wr12; + uint32 nand_acc_control; + uint32 PAD; + uint32 nand_config; + uint32 PAD; + uint32 nand_timing_1; + uint32 nand_timing_2; + uint32 nand_semaphore; + uint32 PAD; + uint32 nand_devid; + uint32 nand_devid_x; + uint32 nand_block_lock_status; + uint32 nand_intfc_status; + uint32 nand_ecc_corr_addr_x; + uint32 nand_ecc_corr_addr; + uint32 nand_ecc_unc_addr_x; + uint32 nand_ecc_unc_addr; + uint32 nand_read_error_count; + uint32 nand_corr_stat_threshold; + uint32 PAD[2]; + uint32 nand_read_addr_x; + uint32 nand_read_addr; + uint32 nand_page_program_addr_x; + uint32 nand_page_program_addr; + uint32 nand_copy_back_addr_x; + uint32 nand_copy_back_addr; + uint32 nand_block_erase_addr_x; + uint32 nand_block_erase_addr; + uint32 nand_inv_read_addr_x; + uint32 nand_inv_read_addr; + uint32 PAD[2]; + uint32 nand_blk_wr_protect; + uint32 PAD[3]; + uint32 nand_acc_control_cs1; + uint32 nand_config_cs1; + uint32 nand_timing_1_cs1; + uint32 nand_timing_2_cs1; + uint32 PAD[20]; + uint32 nand_spare_rd16; + uint32 nand_spare_rd20; + uint32 nand_spare_rd24; + uint32 nand_spare_rd28; + uint32 nand_cache_addr; + uint32 nand_cache_data; + uint32 nand_ctrl_config; + uint32 nand_ctrl_status; +#endif /* NFLASH_SUPPORT */ + uint32 gci_corecaps0; /* GCI starting at 0xC00 */ + uint32 gci_corecaps1; + uint32 gci_corecaps2; + uint32 gci_corectrl; + uint32 gci_corestat; /* 0xC10 */ + uint32 gci_intstat; /* 0xC14 */ + uint32 gci_intmask; /* 0xC18 */ + uint32 gci_wakemask; /* 0xC1C */ + uint32 gci_levelintstat; /* 0xC20 */ + uint32 gci_eventintstat; /* 0xC24 */ + uint32 PAD[6]; + uint32 gci_indirect_addr; /* 0xC40 */ + uint32 gci_gpioctl; /* 0xC44 */ + uint32 gci_gpiostatus; + uint32 gci_gpiomask; /* 0xC4C */ + uint32 PAD; + uint32 gci_miscctl; /* 0xC54 */ + uint32 gci_gpiointmask; + uint32 gci_gpiowakemask; + uint32 gci_input[32]; /* C60 */ + uint32 gci_event[32]; /* CE0 */ + uint32 gci_output[4]; /* D60 */ + uint32 gci_control_0; /* 0xD70 */ + uint32 gci_control_1; /* 0xD74 */ + uint32 gci_intpolreg; /* 0xD78 */ + uint32 gci_levelintmask; /* 0xD7C */ + uint32 gci_eventintmask; /* 0xD80 */ + uint32 PAD[3]; + uint32 gci_inbandlevelintmask; /* 0xD90 */ + uint32 gci_inbandeventintmask; /* 0xD94 */ + uint32 PAD[2]; + uint32 gci_seciauxtx; /* 0xDA0 */ + uint32 gci_seciauxrx; /* 0xDA4 */ + uint32 gci_secitx_datatag; /* 0xDA8 */ + uint32 gci_secirx_datatag; /* 0xDAC */ + uint32 gci_secitx_datamask; /* 0xDB0 */ + uint32 gci_seciusef0tx_reg; /* 0xDB4 */ + uint32 gci_secif0tx_offset; /* 0xDB8 */ + uint32 gci_secif0rx_offset; /* 0xDBC */ + uint32 gci_secif1tx_offset; /* 0xDC0 */ + uint32 gci_rxfifo_common_ctrl; /* 0xDC4 */ + uint32 gci_rxfifoctrl; /* 0xDC8 */ + uint32 gci_uartreadid; /* DCC */ + uint32 gci_uartescval; /* DD0 */ + uint32 PAD; + uint32 gci_secififolevel; /* DD8 */ + uint32 gci_seciuartdata; /* DDC */ + uint32 gci_secibauddiv; /* DE0 */ + uint32 gci_secifcr; /* DE4 */ + uint32 gci_secilcr; /* DE8 */ + uint32 gci_secimcr; /* DEC */ + uint32 gci_secilsr; /* DF0 */ + uint32 gci_secimsr; /* DF4 */ + uint32 gci_baudadj; /* DF8 */ + uint32 PAD; + uint32 gci_chipctrl; /* 0xE00 */ + uint32 gci_chipsts; /* 0xE04 */ + uint32 gci_gpioout; /* 0xE08 */ + uint32 gci_gpioout_read; /* 0xE0C */ + uint32 gci_mpwaketx; /* 0xE10 */ + uint32 gci_mpwakedetect; /* 0xE14 */ + uint32 gci_seciin_ctrl; /* 0xE18 */ + uint32 gci_seciout_ctrl; /* 0xE1C */ + uint32 gci_seciin_auxfifo_en; /* 0xE20 */ + uint32 gci_seciout_txen_txbr; /* 0xE24 */ + uint32 gci_seciin_rxbrstatus; /* 0xE28 */ + uint32 gci_seciin_rxerrstatus; /* 0xE2C */ + uint32 gci_seciin_fcstatus; /* 0xE30 */ + uint32 gci_seciout_txstatus; /* 0xE34 */ + uint32 gci_seciout_txbrstatus; /* 0xE38 */ +} chipcregs_t; + +#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ + + +#define CC_CHIPID 0 +#define CC_CAPABILITIES 4 +#define CC_CHIPST 0x2c +#define CC_EROMPTR 0xfc + +#define CC_OTPST 0x10 +#define CC_INTSTATUS 0x20 +#define CC_INTMASK 0x24 +#define CC_JTAGCMD 0x30 +#define CC_JTAGIR 0x34 +#define CC_JTAGDR 0x38 +#define CC_JTAGCTRL 0x3c +#define CC_GPIOPU 0x58 +#define CC_GPIOPD 0x5c +#define CC_GPIOIN 0x60 +#define CC_GPIOOUT 0x64 +#define CC_GPIOOUTEN 0x68 +#define CC_GPIOCTRL 0x6c +#define CC_GPIOPOL 0x70 +#define CC_GPIOINTM 0x74 +#define CC_GPIOEVENT 0x78 +#define CC_GPIOEVENTMASK 0x7c +#define CC_WATCHDOG 0x80 +#define CC_GPIOEVENTPOL 0x84 +#define CC_CLKC_N 0x90 +#define CC_CLKC_M0 0x94 +#define CC_CLKC_M1 0x98 +#define CC_CLKC_M2 0x9c +#define CC_CLKC_M3 0xa0 +#define CC_CLKDIV 0xa4 +#define CC_SYS_CLK_CTL 0xc0 +#define CC_CLK_CTL_ST SI_CLK_CTL_ST +#define PMU_CTL 0x600 +#define PMU_CAP 0x604 +#define PMU_ST 0x608 +#define PMU_RES_STATE 0x60c +#define PMU_RES_PENDING 0x610 +#define PMU_TIMER 0x614 +#define PMU_MIN_RES_MASK 0x618 +#define PMU_MAX_RES_MASK 0x61c +#define CC_CHIPCTL_ADDR 0x650 +#define CC_CHIPCTL_DATA 0x654 +#define PMU_REG_CONTROL_ADDR 0x658 +#define PMU_REG_CONTROL_DATA 0x65C +#define PMU_PLL_CONTROL_ADDR 0x660 +#define PMU_PLL_CONTROL_DATA 0x664 +#define CC_SROM_CTRL 0x190 +#define CC_SROM_OTP 0x800 /* SROM/OTP address space */ +#define CC_GCI_INDIRECT_ADDR_REG 0xC40 +#define CC_GCI_CHIP_CTRL_REG 0xE00 +#define CC_GCI_CC_OFFSET_2 2 +#define CC_GCI_CC_OFFSET_5 5 +#define CC_SWD_CTRL 0x380 +#define CC_SWD_REQACK 0x384 +#define CC_SWD_DATA 0x388 + + +#define CHIPCTRLREG0 0x0 +#define CHIPCTRLREG1 0x1 +#define CHIPCTRLREG2 0x2 +#define CHIPCTRLREG3 0x3 +#define CHIPCTRLREG4 0x4 +#define CHIPCTRLREG5 0x5 +#define CHIPCTRLREG6 0x6 +#define REGCTRLREG4 0x4 +#define REGCTRLREG5 0x5 +#define REGCTRLREG6 0x6 +#define MINRESMASKREG 0x618 +#define MAXRESMASKREG 0x61c +#define CHIPCTRLADDR 0x650 +#define CHIPCTRLDATA 0x654 +#define RSRCTABLEADDR 0x620 +#define PMU_RES_DEP_MASK 0x624 +#define RSRCUPDWNTIME 0x628 +#define PMUREG_RESREQ_MASK 0x68c +#define EXT_LPO_AVAIL 0x100 +#define LPO_SEL (1 << 0) +#define CC_EXT_LPO_PU 0x200000 +#define GC_EXT_LPO_PU 0x2 +#define CC_INT_LPO_PU 0x100000 +#define GC_INT_LPO_PU 0x1 +#define EXT_LPO_SEL 0x8 +#define INT_LPO_SEL 0x4 +#define ENABLE_FINE_CBUCK_CTRL (1 << 30) +#define REGCTRL5_PWM_AUTO_CTRL_MASK 0x007e0000 +#define REGCTRL5_PWM_AUTO_CTRL_SHIFT 17 +#define REGCTRL6_PWM_AUTO_CTRL_MASK 0x3fff0000 +#define REGCTRL6_PWM_AUTO_CTRL_SHIFT 16 + +#ifdef SR_DEBUG +#define SUBCORE_POWER_ON 0x0001 +#define PHY_POWER_ON 0x0010 +#define VDDM_POWER_ON 0x0100 +#define MEMLPLDO_POWER_ON 0x1000 +#define SUBCORE_POWER_ON_CHK 0x00040000 +#define PHY_POWER_ON_CHK 0x00080000 +#define VDDM_POWER_ON_CHK 0x00100000 +#define MEMLPLDO_POWER_ON_CHK 0x00200000 +#endif /* SR_DEBUG */ + +#ifdef NFLASH_SUPPORT +/* NAND flash support */ +#define CC_NAND_REVISION 0xC00 +#define CC_NAND_CMD_START 0xC04 +#define CC_NAND_CMD_ADDR 0xC0C +#define CC_NAND_SPARE_RD_0 0xC20 +#define CC_NAND_SPARE_RD_4 0xC24 +#define CC_NAND_SPARE_RD_8 0xC28 +#define CC_NAND_SPARE_RD_C 0xC2C +#define CC_NAND_CONFIG 0xC48 +#define CC_NAND_DEVID 0xC60 +#define CC_NAND_DEVID_EXT 0xC64 +#define CC_NAND_INTFC_STATUS 0xC6C +#endif /* NFLASH_SUPPORT */ + +/* 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 */ +#define CC_CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */ +#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_ECI 0x20000000 /* ECI Present, rev >= 21 */ +#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */ +#define CC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */ + +#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ +#define CC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */ + +/* capabilities extension */ +#define CC_CAP_EXT_SECI_PRESENT 0x00000001 /* SECI present */ +#define CC_CAP_EXT_GSIO_PRESENT 0x00000002 /* GSIO present */ +#define CC_CAP_EXT_GCI_PRESENT 0x00000004 /* GCI present */ +#define CC_CAP_EXT_AOB_PRESENT 0x00000040 /* AOB present */ + +/* WL Channel Info to BT via GCI - bits 40 - 47 */ +#define GCI_WL_CHN_INFO_MASK (0xFF00) +/* PLL type */ +#define PLL_NONE 0x00000000 +#define PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */ +#define PLL_TYPE2 0x00020000 /* 48MHz, 4 dividers */ +#define PLL_TYPE3 0x00030000 /* 25MHz, 2 dividers */ +#define PLL_TYPE4 0x00008000 /* 48MHz, 4 dividers */ +#define PLL_TYPE5 0x00018000 /* 25MHz, 4 dividers */ +#define PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */ +#define PLL_TYPE7 0x00038000 /* 25MHz, 4 dividers */ + +/* ILP clock */ +#define ILP_CLOCK 32000 + +/* ALP clock on pre-PMU chips */ +#define ALP_CLOCK 20000000 + +#ifdef CFG_SIM +#define NS_ALP_CLOCK 84922 +#define NS_SLOW_ALP_CLOCK 84922 +#define NS_CPU_CLOCK 534500 +#define NS_SLOW_CPU_CLOCK 534500 +#define NS_SI_CLOCK 271750 +#define NS_SLOW_SI_CLOCK 271750 +#define NS_FAST_MEM_CLOCK 271750 +#define NS_MEM_CLOCK 271750 +#define NS_SLOW_MEM_CLOCK 271750 +#else +#define NS_ALP_CLOCK 125000000 +#define NS_SLOW_ALP_CLOCK 100000000 +#define NS_CPU_CLOCK 1000000000 +#define NS_SLOW_CPU_CLOCK 800000000 +#define NS_SI_CLOCK 250000000 +#define NS_SLOW_SI_CLOCK 200000000 +#define NS_FAST_MEM_CLOCK 800000000 +#define NS_MEM_CLOCK 533000000 +#define NS_SLOW_MEM_CLOCK 400000000 +#endif /* CFG_SIM */ + +/* HT clock */ +#define HT_CLOCK 80000000 + +/* corecontrol */ +#define CC_UARTCLKO 0x00000001 /* Drive UART with internal clock */ +#define CC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ +#define CC_ASYNCGPIO 0x00000004 /* 1=generate GPIO interrupt without backplane clock */ +#define CC_UARTCLKEN 0x00000008 /* enable UART Clock (corerev > = 21 */ + +/* 4321 chipcontrol */ +#define CHIPCTRL_4321A0_DEFAULT 0x3a4 +#define CHIPCTRL_4321A1_DEFAULT 0x0a4 +#define CHIPCTRL_4321_PLL_DOWN 0x800000 /* serdes PLL down override */ + +/* Fields in the otpstatus register in rev >= 21 */ +#define OTPS_OL_MASK 0x000000ff +#define OTPS_OL_MFG 0x00000001 /* manuf row is locked */ +#define OTPS_OL_OR1 0x00000002 /* otp redundancy row 1 is locked */ +#define OTPS_OL_OR2 0x00000004 /* otp redundancy row 2 is locked */ +#define OTPS_OL_GU 0x00000008 /* general use region is locked */ +#define OTPS_GUP_MASK 0x00000f00 +#define OTPS_GUP_SHIFT 8 +#define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */ +#define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */ +#define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */ +#define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */ +#define OTPS_READY 0x00001000 +#define OTPS_RV(x) (1 << (16 + (x))) /* redundancy entry valid */ +#define OTPS_RV_MASK 0x0fff0000 +#define OTPS_PROGOK 0x40000000 + +/* Fields in the otpcontrol register in rev >= 21 */ +#define OTPC_PROGSEL 0x00000001 +#define OTPC_PCOUNT_MASK 0x0000000e +#define OTPC_PCOUNT_SHIFT 1 +#define OTPC_VSEL_MASK 0x000000f0 +#define OTPC_VSEL_SHIFT 4 +#define OTPC_TMM_MASK 0x00000700 +#define OTPC_TMM_SHIFT 8 +#define OTPC_ODM 0x00000800 +#define OTPC_PROGEN 0x80000000 + +/* Fields in the 40nm otpcontrol register in rev >= 40 */ +#define OTPC_40NM_PROGSEL_SHIFT 0 +#define OTPC_40NM_PCOUNT_SHIFT 1 +#define OTPC_40NM_PCOUNT_WR 0xA +#define OTPC_40NM_PCOUNT_V1X 0xB +#define OTPC_40NM_REGCSEL_SHIFT 5 +#define OTPC_40NM_REGCSEL_DEF 0x4 +#define OTPC_40NM_PROGIN_SHIFT 8 +#define OTPC_40NM_R2X_SHIFT 10 +#define OTPC_40NM_ODM_SHIFT 11 +#define OTPC_40NM_DF_SHIFT 15 +#define OTPC_40NM_VSEL_SHIFT 16 +#define OTPC_40NM_VSEL_WR 0xA +#define OTPC_40NM_VSEL_V1X 0xA +#define OTPC_40NM_VSEL_R1X 0x5 +#define OTPC_40NM_COFAIL_SHIFT 30 + +#define OTPC1_CPCSEL_SHIFT 0 +#define OTPC1_CPCSEL_DEF 6 +#define OTPC1_TM_SHIFT 8 +#define OTPC1_TM_WR 0x84 +#define OTPC1_TM_V1X 0x84 +#define OTPC1_TM_R1X 0x4 +#define OTPC1_CLK_EN_MASK 0x00020000 +#define OTPC1_CLK_DIV_MASK 0x00FC0000 + +/* Fields in otpprog in rev >= 21 and HND OTP */ +#define OTPP_COL_MASK 0x000000ff +#define OTPP_COL_SHIFT 0 +#define OTPP_ROW_MASK 0x0000ff00 +#define OTPP_ROW_MASK9 0x0001ff00 /* for ccrev >= 49 */ +#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 /* HND OTP */ + +/* Fields in otplayout register */ +#define OTPL_HWRGN_OFF_MASK 0x00000FFF +#define OTPL_HWRGN_OFF_SHIFT 0 +#define OTPL_WRAP_REVID_MASK 0x00F80000 +#define OTPL_WRAP_REVID_SHIFT 19 +#define OTPL_WRAP_TYPE_MASK 0x00070000 +#define OTPL_WRAP_TYPE_SHIFT 16 +#define OTPL_WRAP_TYPE_65NM 0 +#define OTPL_WRAP_TYPE_40NM 1 +#define OTPL_ROW_SIZE_MASK 0x0000F000 +#define OTPL_ROW_SIZE_SHIFT 12 + +/* otplayout reg corerev >= 36 */ +#define OTP_CISFORMAT_NEW 0x80000000 + +/* 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 + +/* Opcodes for OTPP_OC field (40NM) */ +#define OTPPOC_READ_40NM 0 +#define OTPPOC_PROG_ENABLE_40NM 1 +#define OTPPOC_PROG_DISABLE_40NM 2 +#define OTPPOC_VERIFY_40NM 3 +#define OTPPOC_WORD_VERIFY_1_40NM 4 +#define OTPPOC_ROW_LOCK_40NM 5 +#define OTPPOC_STBY_40NM 6 +#define OTPPOC_WAKEUP_40NM 7 +#define OTPPOC_WORD_VERIFY_0_40NM 8 +#define OTPPOC_PRESCN_TEST_40NM 9 +#define OTPPOC_BIT_PROG_40NM 10 +#define OTPPOC_WORDPROG_40NM 11 +#define OTPPOC_BURNIN_40NM 12 +#define OTPPOC_AUTORELOAD_40NM 13 +#define OTPPOC_OVST_READ_40NM 14 +#define OTPPOC_OVST_PROG_40NM 15 + +/* Fields in otplayoutextension */ +#define OTPLAYOUTEXT_FUSE_MASK 0x3FF + + +/* Jtagm characteristics that appeared at a given corerev */ +#define JTAGM_CREV_OLD 10 /* Old command set, 16bit max IR */ +#define JTAGM_CREV_IRP 22 /* Able to do pause-ir */ +#define JTAGM_CREV_RTI 28 /* Able to do return-to-idle */ + +/* jtagcmd */ +#define JCMD_START 0x80000000 +#define JCMD_BUSY 0x80000000 +#define JCMD_STATE_MASK 0x60000000 +#define JCMD_STATE_TLR 0x00000000 /* Test-logic-reset */ +#define JCMD_STATE_PIR 0x20000000 /* Pause IR */ +#define JCMD_STATE_PDR 0x40000000 /* Pause DR */ +#define JCMD_STATE_RTI 0x60000000 /* Run-test-idle */ +#define JCMD0_ACC_MASK 0x0000f000 +#define JCMD0_ACC_IRDR 0x00000000 +#define JCMD0_ACC_DR 0x00001000 +#define JCMD0_ACC_IR 0x00002000 +#define JCMD0_ACC_RESET 0x00003000 +#define JCMD0_ACC_IRPDR 0x00004000 +#define JCMD0_ACC_PDR 0x00005000 +#define JCMD0_IRW_MASK 0x00000f00 +#define JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */ +#define JCMD_ACC_IRDR 0x00000000 +#define JCMD_ACC_DR 0x00010000 +#define JCMD_ACC_IR 0x00020000 +#define JCMD_ACC_RESET 0x00030000 +#define JCMD_ACC_IRPDR 0x00040000 +#define JCMD_ACC_PDR 0x00050000 +#define JCMD_ACC_PIR 0x00060000 +#define JCMD_ACC_IRDR_I 0x00070000 /* rev 28: return to run-test-idle */ +#define JCMD_ACC_DR_I 0x00080000 /* rev 28: return to run-test-idle */ +#define JCMD_IRW_MASK 0x00001f00 +#define JCMD_IRW_SHIFT 8 +#define JCMD_DRW_MASK 0x0000003f + +/* jtagctrl */ +#define JCTRL_FORCE_CLK 4 /* Force clock */ +#define JCTRL_EXT_EN 2 /* Enable external targets */ +#define JCTRL_EN 1 /* Enable Jtag master */ + +#define JCTRL_TAPSEL_BIT 0x00000008 /* JtagMasterCtrl tap_sel bit */ + +/* Fields in clkdiv */ +#define CLKD_SFLASH 0x0f000000 +#define CLKD_SFLASH_SHIFT 24 +#define CLKD_OTP 0x000f0000 +#define CLKD_OTP_SHIFT 16 +#define CLKD_JTAG 0x00000f00 +#define CLKD_JTAG_SHIFT 8 +#define CLKD_UART 0x000000ff + +#define CLKD2_SROM 0x00000003 + +/* intstatus/intmask */ +#define CI_GPIO 0x00000001 /* gpio intr */ +#define CI_EI 0x00000002 /* extif intr (corerev >= 3) */ +#define CI_TEMP 0x00000004 /* temp. ctrl intr (corerev >= 15) */ +#define CI_SIRQ 0x00000008 /* serial IRQ intr (corerev >= 15) */ +#define CI_ECI 0x00000010 /* eci intr (corerev >= 21) */ +#define CI_PMU 0x00000020 /* pmu intr (corerev >= 21) */ +#define CI_UART 0x00000040 /* uart intr (corerev >= 21) */ +#define CI_WDRESET 0x80000000 /* watchdog reset occurred */ + +/* slow_clk_ctl */ +#define SCC_SS_MASK 0x00000007 /* slow clock source mask */ +#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */ +#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */ +#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */ +#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ +#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, + * 0: LPO is enabled + */ +#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, + * 0: power logic control + */ +#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors + * PLL clock disable requests from core + */ +#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't + * disable crystal when appropriate + */ +#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ +#define SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ +#define SCC_CD_SHIFT 16 + +/* system_clk_ctl */ +#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */ +#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */ +#define SYCC_FP 0x00000004 /* ForcePLLOn */ +#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */ +#define SYCC_HR 0x00000010 /* Force HT */ +#define SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ +#define SYCC_CD_SHIFT 16 + +/* Indirect backplane access */ +#define BPIA_BYTEEN 0x0000000f +#define BPIA_SZ1 0x00000001 +#define BPIA_SZ2 0x00000003 +#define BPIA_SZ4 0x00000007 +#define BPIA_SZ8 0x0000000f +#define BPIA_WRITE 0x00000100 +#define BPIA_START 0x00000200 +#define BPIA_BUSY 0x00000200 +#define BPIA_ERROR 0x00000400 + +/* pcmcia/prog/flash_config */ +#define CF_EN 0x00000001 /* enable */ +#define CF_EM_MASK 0x0000000e /* mode */ +#define CF_EM_SHIFT 1 +#define CF_EM_FLASH 0 /* flash/asynchronous mode */ +#define CF_EM_SYNC 2 /* synchronous mode */ +#define CF_EM_PCMCIA 4 /* pcmcia mode */ +#define CF_DS 0x00000010 /* destsize: 0=8bit, 1=16bit */ +#define CF_BS 0x00000020 /* byteswap */ +#define CF_CD_MASK 0x000000c0 /* clock divider */ +#define CF_CD_SHIFT 6 +#define CF_CD_DIV2 0x00000000 /* backplane/2 */ +#define CF_CD_DIV3 0x00000040 /* backplane/3 */ +#define CF_CD_DIV4 0x00000080 /* backplane/4 */ +#define CF_CE 0x00000100 /* clock enable */ +#define CF_SB 0x00000200 /* size/bytestrobe (synch only) */ + +/* pcmcia_memwait */ +#define PM_W0_MASK 0x0000003f /* waitcount0 */ +#define PM_W1_MASK 0x00001f00 /* waitcount1 */ +#define PM_W1_SHIFT 8 +#define PM_W2_MASK 0x001f0000 /* waitcount2 */ +#define PM_W2_SHIFT 16 +#define PM_W3_MASK 0x1f000000 /* waitcount3 */ +#define PM_W3_SHIFT 24 + +/* pcmcia_attrwait */ +#define PA_W0_MASK 0x0000003f /* waitcount0 */ +#define PA_W1_MASK 0x00001f00 /* waitcount1 */ +#define PA_W1_SHIFT 8 +#define PA_W2_MASK 0x001f0000 /* waitcount2 */ +#define PA_W2_SHIFT 16 +#define PA_W3_MASK 0x1f000000 /* waitcount3 */ +#define PA_W3_SHIFT 24 + +/* pcmcia_iowait */ +#define PI_W0_MASK 0x0000003f /* waitcount0 */ +#define PI_W1_MASK 0x00001f00 /* waitcount1 */ +#define PI_W1_SHIFT 8 +#define PI_W2_MASK 0x001f0000 /* waitcount2 */ +#define PI_W2_SHIFT 16 +#define PI_W3_MASK 0x1f000000 /* waitcount3 */ +#define PI_W3_SHIFT 24 + +/* prog_waitcount */ +#define PW_W0_MASK 0x0000001f /* waitcount0 */ +#define PW_W1_MASK 0x00001f00 /* waitcount1 */ +#define PW_W1_SHIFT 8 +#define PW_W2_MASK 0x001f0000 /* waitcount2 */ +#define PW_W2_SHIFT 16 +#define PW_W3_MASK 0x1f000000 /* waitcount3 */ +#define PW_W3_SHIFT 24 + +#define PW_W0 0x0000000c +#define PW_W1 0x00000a00 +#define PW_W2 0x00020000 +#define PW_W3 0x01000000 + +/* flash_waitcount */ +#define FW_W0_MASK 0x0000003f /* waitcount0 */ +#define FW_W1_MASK 0x00001f00 /* waitcount1 */ +#define FW_W1_SHIFT 8 +#define FW_W2_MASK 0x001f0000 /* waitcount2 */ +#define FW_W2_SHIFT 16 +#define FW_W3_MASK 0x1f000000 /* waitcount3 */ +#define FW_W3_SHIFT 24 + +/* 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_OTPPRESENT 0x00000020 +#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 + +/* Fields in pmucontrol */ +#define PCTL_ILP_DIV_MASK 0xffff0000 +#define PCTL_ILP_DIV_SHIFT 16 +#define PCTL_LQ_REQ_EN 0x00008000 +#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 + +/* Retention Control */ +#define PMU_RCTL_CLK_DIV_SHIFT 0 +#define PMU_RCTL_CHAIN_LEN_SHIFT 12 +#define PMU_RCTL_MACPHY_DISABLE_SHIFT 26 +#define PMU_RCTL_MACPHY_DISABLE_MASK (1 << 26) +#define PMU_RCTL_LOGIC_DISABLE_SHIFT 27 +#define PMU_RCTL_LOGIC_DISABLE_MASK (1 << 27) +#define PMU_RCTL_MEMSLP_LOG_SHIFT 28 +#define PMU_RCTL_MEMSLP_LOG_MASK (1 << 28) +#define PMU_RCTL_MEMRETSLP_LOG_SHIFT 29 +#define PMU_RCTL_MEMRETSLP_LOG_MASK (1 << 29) + +/* Retention Group Control */ +#define PMU_RCTLGRP_CHAIN_LEN_SHIFT 0 +#define PMU_RCTLGRP_RMODE_ENABLE_SHIFT 14 +#define PMU_RCTLGRP_RMODE_ENABLE_MASK (1 << 14) +#define PMU_RCTLGRP_DFT_ENABLE_SHIFT 15 +#define PMU_RCTLGRP_DFT_ENABLE_MASK (1 << 15) +#define PMU_RCTLGRP_NSRST_DISABLE_SHIFT 16 +#define PMU_RCTLGRP_NSRST_DISABLE_MASK (1 << 16) +/* Retention Group Control special for 4334 */ +#define PMU4334_RCTLGRP_CHAIN_LEN_GRP0 338 +#define PMU4334_RCTLGRP_CHAIN_LEN_GRP1 315 +/* Retention Group Control special for 43341 */ +#define PMU43341_RCTLGRP_CHAIN_LEN_GRP0 366 +#define PMU43341_RCTLGRP_CHAIN_LEN_GRP1 330 + +/* Fields in clkstretch */ +#define CSTRETCH_HT 0xffff0000 +#define CSTRETCH_ALP 0x0000ffff + +/* gpiotimerval */ +#define GPIO_ONTIME_SHIFT 16 + +/* clockcontrol_n */ +#define CN_N1_MASK 0x3f /* n1 control */ +#define CN_N2_MASK 0x3f00 /* n2 control */ +#define CN_N2_SHIFT 8 +#define CN_PLLC_MASK 0xf0000 /* pll control */ +#define CN_PLLC_SHIFT 16 + +/* clockcontrol_sb/pci/uart */ +#define CC_M1_MASK 0x3f /* m1 control */ +#define CC_M2_MASK 0x3f00 /* m2 control */ +#define CC_M2_SHIFT 8 +#define CC_M3_MASK 0x3f0000 /* m3 control */ +#define CC_M3_SHIFT 16 +#define CC_MC_MASK 0x1f000000 /* mux control */ +#define CC_MC_SHIFT 24 + +/* N3M Clock control magic field values */ +#define CC_F6_2 0x02 /* A factor of 2 in */ +#define CC_F6_3 0x03 /* 6-bit fields like */ +#define CC_F6_4 0x05 /* N1, M1 or M3 */ +#define CC_F6_5 0x09 +#define CC_F6_6 0x11 +#define CC_F6_7 0x21 + +#define CC_F5_BIAS 5 /* 5-bit fields get this added */ + +#define CC_MC_BYPASS 0x08 +#define CC_MC_M1 0x04 +#define CC_MC_M1M2 0x02 +#define CC_MC_M1M2M3 0x01 +#define CC_MC_M1M3 0x11 + +/* Type 2 Clock control magic field values */ +#define CC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ +#define CC_T2M2_BIAS 3 /* m2 bias */ + +#define CC_T2MC_M1BYP 1 +#define CC_T2MC_M2BYP 2 +#define CC_T2MC_M3BYP 4 + +/* Type 6 Clock control magic field values */ +#define CC_T6_MMASK 1 /* bits of interest in m */ +#define CC_T6_M0 120000000 /* sb clock for m = 0 */ +#define CC_T6_M1 100000000 /* sb clock for m = 1 */ +#define SB2MIPS_T6(sb) (2 * (sb)) + +/* Common clock base */ +#define CC_CLOCK_BASE1 24000000 /* Half the clock freq */ +#define CC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLLs */ + +/* Clock control values for 200MHz in 5350 */ +#define CLKC_5350_N 0x0311 +#define CLKC_5350_M 0x04020009 + +/* Flash types in the chipcommon capabilities register */ +#define FLASH_NONE 0x000 /* No flash */ +#define SFLASH_ST 0x100 /* ST serial flash */ +#define SFLASH_AT 0x200 /* Atmel serial flash */ +#define NFLASH 0x300 +#define PFLASH 0x700 /* Parallel flash */ +#define QSPIFLASH_ST 0x800 +#define QSPIFLASH_AT 0x900 + +/* Bits in the ExtBus config registers */ +#define CC_CFG_EN 0x0001 /* Enable */ +#define CC_CFG_EM_MASK 0x000e /* Extif Mode */ +#define CC_CFG_EM_ASYNC 0x0000 /* Async/Parallel flash */ +#define CC_CFG_EM_SYNC 0x0002 /* Synchronous */ +#define CC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */ +#define CC_CFG_EM_IDE 0x0006 /* IDE */ +#define CC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */ +#define CC_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */ +#define CC_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */ +#define CC_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */ +#define CC_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */ + +/* ExtBus address space */ +#define CC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */ +#define CC_EB_PCMCIA_MEM 0x1a000000 /* PCMCIA 0 memory base address */ +#define CC_EB_PCMCIA_IO 0x1a200000 /* PCMCIA 0 I/O base address */ +#define CC_EB_PCMCIA_CFG 0x1a400000 /* PCMCIA 0 config base address */ +#define CC_EB_IDE 0x1a800000 /* IDE memory base */ +#define CC_EB_PCMCIA1_MEM 0x1a800000 /* PCMCIA 1 memory base address */ +#define CC_EB_PCMCIA1_IO 0x1aa00000 /* PCMCIA 1 I/O base address */ +#define CC_EB_PCMCIA1_CFG 0x1ac00000 /* PCMCIA 1 config base address */ +#define CC_EB_PROGIF 0x1b000000 /* ProgIF Async/Sync base address */ + + +/* Start/busy bit in flashcontrol */ +#define SFLASH_OPCODE 0x000000ff +#define SFLASH_ACTION 0x00000700 +#define SFLASH_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */ +#define SFLASH_START 0x80000000 +#define SFLASH_BUSY SFLASH_START + +/* flashcontrol action codes */ +#define SFLASH_ACT_OPONLY 0x0000 /* Issue opcode only */ +#define SFLASH_ACT_OP1D 0x0100 /* opcode + 1 data byte */ +#define SFLASH_ACT_OP3A 0x0200 /* opcode + 3 addr bytes */ +#define SFLASH_ACT_OP3A1D 0x0300 /* opcode + 3 addr & 1 data bytes */ +#define SFLASH_ACT_OP3A4D 0x0400 /* opcode + 3 addr & 4 data bytes */ +#define SFLASH_ACT_OP3A4X4D 0x0500 /* opcode + 3 addr, 4 don't care & 4 data bytes */ +#define SFLASH_ACT_OP3A1X4D 0x0700 /* opcode + 3 addr, 1 don't care & 4 data bytes */ + +/* flashcontrol action+opcodes for ST flashes */ +#define SFLASH_ST_WREN 0x0006 /* Write Enable */ +#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */ +#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */ +#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */ +#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */ +#define SFLASH_ST_PP 0x0302 /* Page Program */ +#define SFLASH_ST_SE 0x02d8 /* Sector Erase */ +#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */ +#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */ +#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */ +#define SFLASH_ST_CSA 0x1000 /* Keep chip select asserted */ +#define SFLASH_ST_SSE 0x0220 /* Sub-sector Erase */ + +#define SFLASH_MXIC_RDID 0x0390 /* Read Manufacture ID */ +#define SFLASH_MXIC_MFID 0xc2 /* MXIC Manufacture ID */ + +/* Status register bits for ST flashes */ +#define SFLASH_ST_WIP 0x01 /* Write In Progress */ +#define SFLASH_ST_WEL 0x02 /* Write Enable Latch */ +#define SFLASH_ST_BP_MASK 0x1c /* Block Protect */ +#define SFLASH_ST_BP_SHIFT 2 +#define SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */ + +/* flashcontrol action+opcodes for Atmel flashes */ +#define SFLASH_AT_READ 0x07e8 +#define SFLASH_AT_PAGE_READ 0x07d2 +#define SFLASH_AT_BUF1_READ +#define SFLASH_AT_BUF2_READ +#define SFLASH_AT_STATUS 0x01d7 +#define SFLASH_AT_BUF1_WRITE 0x0384 +#define SFLASH_AT_BUF2_WRITE 0x0387 +#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 +#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 +#define SFLASH_AT_BUF1_PROGRAM 0x0288 +#define SFLASH_AT_BUF2_PROGRAM 0x0289 +#define SFLASH_AT_PAGE_ERASE 0x0281 +#define SFLASH_AT_BLOCK_ERASE 0x0250 +#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 +#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 +#define SFLASH_AT_BUF1_LOAD 0x0253 +#define SFLASH_AT_BUF2_LOAD 0x0255 +#define SFLASH_AT_BUF1_COMPARE 0x0260 +#define SFLASH_AT_BUF2_COMPARE 0x0261 +#define SFLASH_AT_BUF1_REPROGRAM 0x0258 +#define SFLASH_AT_BUF2_REPROGRAM 0x0259 + +/* Status register bits for Atmel flashes */ +#define SFLASH_AT_READY 0x80 +#define SFLASH_AT_MISMATCH 0x40 +#define SFLASH_AT_ID_MASK 0x38 +#define SFLASH_AT_ID_SHIFT 3 + +/* SPI register bits, corerev >= 37 */ +#define GSIO_START 0x80000000 +#define GSIO_BUSY GSIO_START + +/* + * These are the UART port assignments, expressed as offsets from the base + * register. These assignments should hold for any serial port based on + * a 8250, 16450, or 16550(A). + */ + +#define UART_RX 0 /* In: Receive buffer (DLAB=0) */ +#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ +#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ +#define UART_IER 1 /* In/Out: Interrupt Enable Register (DLAB=0) */ +#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */ +#define UART_IIR 2 /* In: Interrupt Identity Register */ +#define UART_FCR 2 /* Out: FIFO Control Register */ +#define UART_LCR 3 /* Out: Line Control Register */ +#define UART_MCR 4 /* Out: Modem Control Register */ +#define UART_LSR 5 /* In: Line Status Register */ +#define UART_MSR 6 /* In: Modem Status Register */ +#define UART_SCR 7 /* I/O: Scratch Register */ +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ +#define UART_LCR_WLEN8 0x03 /* Word length: 8 bits */ +#define UART_MCR_OUT2 0x08 /* MCR GPIO out 2 */ +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ +#define UART_LSR_RX_FIFO 0x80 /* Receive FIFO error */ +#define UART_LSR_TDHR 0x40 /* Data-hold-register empty */ +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ +#define UART_LSR_BREAK 0x10 /* Break interrupt */ +#define UART_LSR_FRAMING 0x08 /* Framing error */ +#define UART_LSR_PARITY 0x04 /* Parity error */ +#define UART_LSR_OVERRUN 0x02 /* Overrun error */ +#define UART_LSR_RXRDY 0x01 /* Receiver ready */ +#define UART_FCR_FIFO_ENABLE 1 /* FIFO control register bit controlling FIFO enable/disable */ + +/* Interrupt Identity Register (IIR) bits */ +#define UART_IIR_FIFO_MASK 0xc0 /* IIR FIFO disable/enabled mask */ +#define UART_IIR_INT_MASK 0xf /* IIR interrupt ID source */ +#define UART_IIR_MDM_CHG 0x0 /* Modem status changed */ +#define UART_IIR_NOINT 0x1 /* No interrupt pending */ +#define UART_IIR_THRE 0x2 /* THR empty */ +#define UART_IIR_RCVD_DATA 0x4 /* Received data available */ +#define UART_IIR_RCVR_STATUS 0x6 /* Receiver status */ +#define UART_IIR_CHAR_TIME 0xc /* Character time */ + +/* Interrupt Enable Register (IER) bits */ +#define UART_IER_PTIME 128 /* Programmable THRE Interrupt Mode Enable */ +#define UART_IER_EDSSI 8 /* enable modem status interrupt */ +#define UART_IER_ELSI 4 /* enable receiver line status interrupt */ +#define UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */ +#define UART_IER_ERBFI 1 /* enable data available interrupt */ + +/* pmustatus */ +#define PST_SLOW_WR_PENDING 0x0400 +#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 + +/* 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 + +/* PMU Resource Request Timer registers */ +/* This is based on PmuRev0 */ +#define PRRT_TIME_MASK 0x03ff +#define PRRT_INTEN 0x0400 +#define PRRT_REQ_ACTIVE 0x0800 +#define PRRT_ALP_REQ 0x1000 +#define PRRT_HT_REQ 0x2000 +#define PRRT_HQ_REQ 0x4000 + +/* bit 0 of the PMU interrupt vector is asserted if this mask is enabled */ +#define RSRC_INTR_MASK_TIMER_INT_0 1 + +/* PMU resource bit position */ +#define PMURES_BIT(bit) (1 << (bit)) + +/* PMU resource number limit */ +#define PMURES_MAX_RESNUM 30 + +/* PMU chip control0 register */ +#define PMU_CHIPCTL0 0 +#define PMU43143_CC0_SDIO_DRSTR_OVR (1 << 31) /* sdio drive strength override enable */ + +/* clock req types */ +#define PMU_CC1_CLKREQ_TYPE_SHIFT 19 +#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT) + +#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0 +#define CLKREQ_TYPE_CONFIG_PUSHPULL 1 + +/* PMU chip control1 register */ +#define PMU_CHIPCTL1 1 +#define PMU_CC1_RXC_DLL_BYPASS 0x00010000 +#define PMU_CC1_ENABLE_BBPLL_PWR_DOWN 0x00000010 + +#define PMU_CC1_IF_TYPE_MASK 0x00000030 +#define PMU_CC1_IF_TYPE_RMII 0x00000000 +#define PMU_CC1_IF_TYPE_MII 0x00000010 +#define PMU_CC1_IF_TYPE_RGMII 0x00000020 + +#define PMU_CC1_SW_TYPE_MASK 0x000000c0 +#define PMU_CC1_SW_TYPE_EPHY 0x00000000 +#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040 +#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 +#define PMU_CC1_SW_TYPE_RGMII 0x000000c0 + +/* PMU chip control2 register */ +#define PMU_CHIPCTL2 2 +#define PMU_CC2_FORCE_SUBCORE_PWR_SWITCH_ON (1 << 18) +#define PMU_CC2_FORCE_PHY_PWR_SWITCH_ON (1 << 19) +#define PMU_CC2_FORCE_VDDM_PWR_SWITCH_ON (1 << 20) +#define PMU_CC2_FORCE_MEMLPLDO_PWR_SWITCH_ON (1 << 21) + +/* PMU chip control3 register */ +#define PMU_CHIPCTL3 3 +#define PMU_CC3_ENABLE_SDIO_WAKEUP_SHIFT 19 +#define PMU_CC3_ENABLE_RF_SHIFT 22 +#define PMU_CC3_RF_DISABLE_IVALUE_SHIFT 23 + +/* PMU chip control5 register */ +#define PMU_CHIPCTL5 5 + +/* PMU chip control6 register */ +#define PMU_CHIPCTL6 6 +#define PMU_CC6_ENABLE_CLKREQ_WAKEUP (1 << 4) +#define PMU_CC6_ENABLE_PMU_WAKEUP_ALP (1 << 6) + +/* PMU chip control7 register */ +#define PMU_CHIPCTL7 7 +#define PMU_CC7_ENABLE_L2REFCLKPAD_PWRDWN (1 << 25) +#define PMU_CC7_ENABLE_MDIO_RESET_WAR (1 << 27) + + +/* 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 */ +/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */ +#define PMU0_PLL0_PLLCTL0 0 +#define PMU0_PLL0_PC0_PDIV_MASK 1 +#define PMU0_PLL0_PC0_PDIV_FREQ 25000 +#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038 +#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3 +#define PMU0_PLL0_PC0_DIV_ARM_BASE 8 + +/* PC0_DIV_ARM for PLLOUT_ARM */ +#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0 +#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1 +#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2 +#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */ +#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4 +#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5 +#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6 +#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7 + +/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */ +#define PMU0_PLL0_PLLCTL1 1 +#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000 +#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28 +#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00 +#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8 +#define PMU0_PLL0_PC1_STOP_MOD 0x00000040 + +/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */ +#define PMU0_PLL0_PLLCTL2 2 +#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf +#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4 + +/* pllcontrol registers */ +/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ +#define PMU1_PLL0_PLLCTL0 0 +#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 +#define PMU1_PLL0_PC0_P1DIV_SHIFT 20 +#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 +#define PMU1_PLL0_PC0_P2DIV_SHIFT 24 + +/* mdiv */ +#define PMU1_PLL0_PLLCTL1 1 +#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff +#define PMU1_PLL0_PC1_M1DIV_SHIFT 0 +#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 +#define PMU1_PLL0_PC1_M2DIV_SHIFT 8 +#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 +#define PMU1_PLL0_PC1_M3DIV_SHIFT 16 +#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 +#define PMU1_PLL0_PC1_M4DIV_SHIFT 24 +#define PMU1_PLL0_PC1_M4DIV_BY_9 9 +#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12 +#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24 +#define PMU1_PLL0_PC1_M4DIV_BY_60 0x3C + +#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 +#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) +#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) + +/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ +#define PMU1_PLL0_PLLCTL2 2 +#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff +#define PMU1_PLL0_PC2_M5DIV_SHIFT 0 +#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc +#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12 +#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24 +#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 +#define PMU1_PLL0_PC2_M6DIV_SHIFT 8 +#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12 +#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24 +#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 +#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 +#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 +#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */ +#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 +#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 + +/* ndiv_frac */ +#define PMU1_PLL0_PLLCTL3 3 +#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff +#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 + +/* pll_ctrl */ +#define PMU1_PLL0_PLLCTL4 4 + +/* pll_ctrl, vco_rng, clkdrive_ch */ +#define PMU1_PLL0_PLLCTL5 5 +#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 +#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 + +#define PMU1_PLL0_PLLCTL6 6 +#define PMU1_PLL0_PLLCTL7 7 + +#define PMU1_PLL0_PLLCTL8 8 +#define PMU1_PLLCTL8_OPENLOOP_MASK 0x2 + +/* PMU rev 2 control words */ +#define PMU2_PHY_PLL_PLLCTL 4 +#define PMU2_SI_PLL_PLLCTL 10 + +/* PMU rev 2 */ +/* pllcontrol registers */ +/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ +#define PMU2_PLL_PLLCTL0 0 +#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 +#define PMU2_PLL_PC0_P1DIV_SHIFT 20 +#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 +#define PMU2_PLL_PC0_P2DIV_SHIFT 24 + +/* mdiv */ +#define PMU2_PLL_PLLCTL1 1 +#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff +#define PMU2_PLL_PC1_M1DIV_SHIFT 0 +#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 +#define PMU2_PLL_PC1_M2DIV_SHIFT 8 +#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 +#define PMU2_PLL_PC1_M3DIV_SHIFT 16 +#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000 +#define PMU2_PLL_PC1_M4DIV_SHIFT 24 + +/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ +#define PMU2_PLL_PLLCTL2 2 +#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff +#define PMU2_PLL_PC2_M5DIV_SHIFT 0 +#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 +#define PMU2_PLL_PC2_M6DIV_SHIFT 8 +#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 +#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 +#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 +#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20 + +/* ndiv_frac */ +#define PMU2_PLL_PLLCTL3 3 +#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff +#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 + +/* pll_ctrl */ +#define PMU2_PLL_PLLCTL4 4 + +/* pll_ctrl, vco_rng, clkdrive_ch */ +#define PMU2_PLL_PLLCTL5 5 +#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 +#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 +#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 +#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 +#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 +#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 +#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 +#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 +#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 +#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 +#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 +#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 + +/* PMU rev 5 (& 6) */ +#define PMU5_PLL_P1P2_OFF 0 +#define PMU5_PLL_P1_MASK 0x0f000000 +#define PMU5_PLL_P1_SHIFT 24 +#define PMU5_PLL_P2_MASK 0x00f00000 +#define PMU5_PLL_P2_SHIFT 20 +#define PMU5_PLL_M14_OFF 1 +#define PMU5_PLL_MDIV_MASK 0x000000ff +#define PMU5_PLL_MDIV_WIDTH 8 +#define PMU5_PLL_NM5_OFF 2 +#define PMU5_PLL_NDIV_MASK 0xfff00000 +#define PMU5_PLL_NDIV_SHIFT 20 +#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000 +#define PMU5_PLL_NDIV_MODE_SHIFT 17 +#define PMU5_PLL_FMAB_OFF 3 +#define PMU5_PLL_MRAT_MASK 0xf0000000 +#define PMU5_PLL_MRAT_SHIFT 28 +#define PMU5_PLL_ABRAT_MASK 0x08000000 +#define PMU5_PLL_ABRAT_SHIFT 27 +#define PMU5_PLL_FDIV_MASK 0x07ffffff +#define PMU5_PLL_PLLCTL_OFF 4 +#define PMU5_PLL_PCHI_OFF 5 +#define PMU5_PLL_PCHI_MASK 0x0000003f + +/* pmu XtalFreqRatio */ +#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF +#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 +#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 + +/* Divider allocation in 4716/47162/5356/5357 */ +#define PMU5_MAINPLL_CPU 1 +#define PMU5_MAINPLL_MEM 2 +#define PMU5_MAINPLL_SI 3 + +/* 4706 PMU */ +#define PMU4706_MAINPLL_PLL0 0 +#define PMU6_4706_PROCPLL_OFF 4 /* The CPU PLL */ +#define PMU6_4706_PROC_P2DIV_MASK 0x000f0000 +#define PMU6_4706_PROC_P2DIV_SHIFT 16 +#define PMU6_4706_PROC_P1DIV_MASK 0x0000f000 +#define PMU6_4706_PROC_P1DIV_SHIFT 12 +#define PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 +#define PMU6_4706_PROC_NDIV_INT_SHIFT 3 +#define PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 +#define PMU6_4706_PROC_NDIV_MODE_SHIFT 0 + +#define PMU7_PLL_PLLCTL7 7 +#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000 +#define PMU7_PLL_CTL7_M4DIV_SHIFT 24 +#define PMU7_PLL_CTL7_M4DIV_BY_6 6 +#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc +#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18 +#define PMU7_PLL_PLLCTL8 8 +#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff +#define PMU7_PLL_CTL8_M5DIV_SHIFT 0 +#define PMU7_PLL_CTL8_M5DIV_BY_8 8 +#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc +#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18 +#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00 +#define PMU7_PLL_CTL8_M6DIV_SHIFT 8 +#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc +#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18 +#define PMU7_PLL_PLLCTL11 11 +#define PMU7_PLL_PLLCTL11_MASK 0xffffff00 +#define PMU7_PLL_PLLCTL11_VAL 0x22222200 + +/* PMU rev 15 */ +#define PMU15_PLL_PLLCTL0 0 +#define PMU15_PLL_PC0_CLKSEL_MASK 0x00000003 +#define PMU15_PLL_PC0_CLKSEL_SHIFT 0 +#define PMU15_PLL_PC0_FREQTGT_MASK 0x003FFFFC +#define PMU15_PLL_PC0_FREQTGT_SHIFT 2 +#define PMU15_PLL_PC0_PRESCALE_MASK 0x00C00000 +#define PMU15_PLL_PC0_PRESCALE_SHIFT 22 +#define PMU15_PLL_PC0_KPCTRL_MASK 0x07000000 +#define PMU15_PLL_PC0_KPCTRL_SHIFT 24 +#define PMU15_PLL_PC0_FCNTCTRL_MASK 0x38000000 +#define PMU15_PLL_PC0_FCNTCTRL_SHIFT 27 +#define PMU15_PLL_PC0_FDCMODE_MASK 0x40000000 +#define PMU15_PLL_PC0_FDCMODE_SHIFT 30 +#define PMU15_PLL_PC0_CTRLBIAS_MASK 0x80000000 +#define PMU15_PLL_PC0_CTRLBIAS_SHIFT 31 + +#define PMU15_PLL_PLLCTL1 1 +#define PMU15_PLL_PC1_BIAS_CTLM_MASK 0x00000060 +#define PMU15_PLL_PC1_BIAS_CTLM_SHIFT 5 +#define PMU15_PLL_PC1_BIAS_CTLM_RST_MASK 0x00000040 +#define PMU15_PLL_PC1_BIAS_CTLM_RST_SHIFT 6 +#define PMU15_PLL_PC1_BIAS_SS_DIVR_MASK 0x0001FF80 +#define PMU15_PLL_PC1_BIAS_SS_DIVR_SHIFT 7 +#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_MASK 0x03FE0000 +#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_SHIFT 17 +#define PMU15_PLL_PC1_BIAS_INTG_BW_MASK 0x0C000000 +#define PMU15_PLL_PC1_BIAS_INTG_BW_SHIFT 26 +#define PMU15_PLL_PC1_BIAS_INTG_BYP_MASK 0x10000000 +#define PMU15_PLL_PC1_BIAS_INTG_BYP_SHIFT 28 +#define PMU15_PLL_PC1_OPENLP_EN_MASK 0x40000000 +#define PMU15_PLL_PC1_OPENLP_EN_SHIFT 30 + +#define PMU15_PLL_PLLCTL2 2 +#define PMU15_PLL_PC2_CTEN_MASK 0x00000001 +#define PMU15_PLL_PC2_CTEN_SHIFT 0 + +#define PMU15_PLL_PLLCTL3 3 +#define PMU15_PLL_PC3_DITHER_EN_MASK 0x00000001 +#define PMU15_PLL_PC3_DITHER_EN_SHIFT 0 +#define PMU15_PLL_PC3_DCOCTLSP_MASK 0xFE000000 +#define PMU15_PLL_PC3_DCOCTLSP_SHIFT 25 +#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_MASK 0x01 +#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_SHIFT 0 +#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_MASK 0x02 +#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_SHIFT 1 +#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_MASK 0x04 +#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_SHIFT 2 +#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_MASK 0x18 +#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_SHIFT 3 +#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_MASK 0x60 +#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_SHIFT 5 +#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV1 0 +#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV2 1 +#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV3 2 +#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV5 3 + +#define PMU15_PLL_PLLCTL4 4 +#define PMU15_PLL_PC4_FLLCLK1_DIV_MASK 0x00000007 +#define PMU15_PLL_PC4_FLLCLK1_DIV_SHIFT 0 +#define PMU15_PLL_PC4_FLLCLK2_DIV_MASK 0x00000038 +#define PMU15_PLL_PC4_FLLCLK2_DIV_SHIFT 3 +#define PMU15_PLL_PC4_FLLCLK3_DIV_MASK 0x000001C0 +#define PMU15_PLL_PC4_FLLCLK3_DIV_SHIFT 6 +#define PMU15_PLL_PC4_DBGMODE_MASK 0x00000E00 +#define PMU15_PLL_PC4_DBGMODE_SHIFT 9 +#define PMU15_PLL_PC4_FLL480_CTLSP_LK_MASK 0x00001000 +#define PMU15_PLL_PC4_FLL480_CTLSP_LK_SHIFT 12 +#define PMU15_PLL_PC4_FLL480_CTLSP_MASK 0x000FE000 +#define PMU15_PLL_PC4_FLL480_CTLSP_SHIFT 13 +#define PMU15_PLL_PC4_DINPOL_MASK 0x00100000 +#define PMU15_PLL_PC4_DINPOL_SHIFT 20 +#define PMU15_PLL_PC4_CLKOUT_PD_MASK 0x00200000 +#define PMU15_PLL_PC4_CLKOUT_PD_SHIFT 21 +#define PMU15_PLL_PC4_CLKDIV2_PD_MASK 0x00400000 +#define PMU15_PLL_PC4_CLKDIV2_PD_SHIFT 22 +#define PMU15_PLL_PC4_CLKDIV4_PD_MASK 0x00800000 +#define PMU15_PLL_PC4_CLKDIV4_PD_SHIFT 23 +#define PMU15_PLL_PC4_CLKDIV8_PD_MASK 0x01000000 +#define PMU15_PLL_PC4_CLKDIV8_PD_SHIFT 24 +#define PMU15_PLL_PC4_CLKDIV16_PD_MASK 0x02000000 +#define PMU15_PLL_PC4_CLKDIV16_PD_SHIFT 25 +#define PMU15_PLL_PC4_TEST_EN_MASK 0x04000000 +#define PMU15_PLL_PC4_TEST_EN_SHIFT 26 + +#define PMU15_PLL_PLLCTL5 5 +#define PMU15_PLL_PC5_FREQTGT_MASK 0x000FFFFF +#define PMU15_PLL_PC5_FREQTGT_SHIFT 0 +#define PMU15_PLL_PC5_DCOCTLSP_MASK 0x07F00000 +#define PMU15_PLL_PC5_DCOCTLSP_SHIFT 20 +#define PMU15_PLL_PC5_PRESCALE_MASK 0x18000000 +#define PMU15_PLL_PC5_PRESCALE_SHIFT 27 + +#define PMU15_PLL_PLLCTL6 6 +#define PMU15_PLL_PC6_FREQTGT_MASK 0x000FFFFF +#define PMU15_PLL_PC6_FREQTGT_SHIFT 0 +#define PMU15_PLL_PC6_DCOCTLSP_MASK 0x07F00000 +#define PMU15_PLL_PC6_DCOCTLSP_SHIFT 20 +#define PMU15_PLL_PC6_PRESCALE_MASK 0x18000000 +#define PMU15_PLL_PC6_PRESCALE_SHIFT 27 + +#define PMU15_FREQTGT_480_DEFAULT 0x19AB1 +#define PMU15_FREQTGT_492_DEFAULT 0x1A4F5 +#define PMU15_ARM_96MHZ 96000000 /* 96 Mhz */ +#define PMU15_ARM_98MHZ 98400000 /* 98.4 Mhz */ +#define PMU15_ARM_97MHZ 97000000 /* 97 Mhz */ + + +#define PMU17_PLLCTL2_NDIVTYPE_MASK 0x00000070 +#define PMU17_PLLCTL2_NDIVTYPE_SHIFT 4 + +#define PMU17_PLLCTL2_NDIV_MODE_INT 0 +#define PMU17_PLLCTL2_NDIV_MODE_INT1B8 1 +#define PMU17_PLLCTL2_NDIV_MODE_MASH111 2 +#define PMU17_PLLCTL2_NDIV_MODE_MASH111B8 3 + +#define PMU17_PLLCTL0_BBPLL_PWRDWN 0 +#define PMU17_PLLCTL0_BBPLL_DRST 3 +#define PMU17_PLLCTL0_BBPLL_DISBL_CLK 8 + +/* PLL usage in 4716/47162 */ +#define PMU4716_MAINPLL_PLL0 12 + +/* PLL usage in 4335 */ +#define PMU4335_PLL0_PC2_P1DIV_MASK 0x000f0000 +#define PMU4335_PLL0_PC2_P1DIV_SHIFT 16 +#define PMU4335_PLL0_PC2_NDIV_INT_MASK 0xff800000 +#define PMU4335_PLL0_PC2_NDIV_INT_SHIFT 23 +#define PMU4335_PLL0_PC1_MDIV2_MASK 0x0000ff00 +#define PMU4335_PLL0_PC1_MDIV2_SHIFT 8 + + +/* PLL usage in 5356/5357 */ +#define PMU5356_MAINPLL_PLL0 0 +#define PMU5357_MAINPLL_PLL0 0 + +/* 4716/47162 resources */ +#define RES4716_PROC_PLL_ON 0x00000040 +#define RES4716_PROC_HT_AVAIL 0x00000080 + +/* 4716/4717/4718 Chip specific ChipControl register bits */ +#define CCTRL_471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared w/ pflash */ + +/* 5357 Chip specific ChipControl register bits */ +/* 2nd - 32-bit reg */ +#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000 /* I2S pins enable */ +#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000 /* I2C/SPI pins enable */ + +/* 5354 resources */ +#define RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */ +#define RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */ +#define RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */ +#define RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ +#define RES5354_ILP_REQUEST 4 /* 0x00010 */ +#define RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */ +#define RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */ +#define RES5354_ROM_SWITCH 7 /* 0x00080 */ +#define RES5354_PA_REF_LDO 8 /* 0x00100 */ +#define RES5354_RADIO_LDO 9 /* 0x00200 */ +#define RES5354_AFE_LDO 10 /* 0x00400 */ +#define RES5354_PLL_LDO 11 /* 0x00800 */ +#define RES5354_BG_FILTBYP 12 /* 0x01000 */ +#define RES5354_TX_FILTBYP 13 /* 0x02000 */ +#define RES5354_RX_FILTBYP 14 /* 0x04000 */ +#define RES5354_XTAL_PU 15 /* 0x08000 */ +#define RES5354_XTAL_EN 16 /* 0x10000 */ +#define RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */ +#define RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */ +#define RES5354_BB_PLL_PU 19 /* 0x80000 */ + +/* 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 CCTRL5357_NFLASH (1<<16) /* Nandflash in ChipControl 1, bit 16 */ + +/* 43217 Chip specific ChipControl register bits */ +#define CCTRL43217_EXTPA_C0 (1<<13) /* core0 extPA in ChipControl 1, bit 13 */ +#define CCTRL43217_EXTPA_C1 (1<<8) /* core1 extPA in ChipControl 1, bit 8 */ + +/* 43228 Chip specific ChipControl register bits */ +#define CCTRL43228_EXTPA_C0 (1<<14) /* core1 extPA in ChipControl 1, bit 14 */ +#define CCTRL43228_EXTPA_C1 (1<<9) /* core0 extPA in ChipControl 1, bit 1 */ + +/* 4328 resources */ +#define RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */ +#define RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */ +#define RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */ +#define RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ +#define RES4328_ILP_REQUEST 4 /* 0x00010 */ +#define RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */ +#define RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */ +#define RES4328_ROM_SWITCH 7 /* 0x00080 */ +#define RES4328_PA_REF_LDO 8 /* 0x00100 */ +#define RES4328_RADIO_LDO 9 /* 0x00200 */ +#define RES4328_AFE_LDO 10 /* 0x00400 */ +#define RES4328_PLL_LDO 11 /* 0x00800 */ +#define RES4328_BG_FILTBYP 12 /* 0x01000 */ +#define RES4328_TX_FILTBYP 13 /* 0x02000 */ +#define RES4328_RX_FILTBYP 14 /* 0x04000 */ +#define RES4328_XTAL_PU 15 /* 0x08000 */ +#define RES4328_XTAL_EN 16 /* 0x10000 */ +#define RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */ +#define RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */ +#define RES4328_BB_PLL_PU 19 /* 0x80000 */ + +/* 4325 A0/A1 resources */ +#define RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */ +#define RES4325_CBUCK_BURST 1 /* 0x00000002 */ +#define RES4325_CBUCK_PWM 2 /* 0x00000004 */ +#define RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */ +#define RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */ +#define RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */ +#define RES4325_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4325_ABUCK_BURST 7 /* 0x00000080 */ +#define RES4325_ABUCK_PWM 8 /* 0x00000100 */ +#define RES4325_LNLDO1_PU 9 /* 0x00000200 */ +#define RES4325_OTP_PU 10 /* 0x00000400 */ +#define RES4325_LNLDO3_PU 11 /* 0x00000800 */ +#define RES4325_LNLDO4_PU 12 /* 0x00001000 */ +#define RES4325_XTAL_PU 13 /* 0x00002000 */ +#define RES4325_ALP_AVAIL 14 /* 0x00004000 */ +#define RES4325_RX_PWRSW_PU 15 /* 0x00008000 */ +#define RES4325_TX_PWRSW_PU 16 /* 0x00010000 */ +#define RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define RES4325_HT_AVAIL 21 /* 0x00200000 */ + +/* 4325 B0/C0 resources */ +#define RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */ +#define RES4325B0_CBUCK_BURST 2 /* 0x00000004 */ +#define RES4325B0_CBUCK_PWM 3 /* 0x00000008 */ +#define RES4325B0_CLDO_PU 4 /* 0x00000010 */ + +/* 4325 C1 resources */ +#define RES4325C1_LNLDO2_PU 12 /* 0x00001000 */ + +/* 4325 chip-specific ChipStatus register bits */ +#define CST4325_SPROM_OTP_SEL_MASK 0x00000003 +#define CST4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ +#define CST4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ +#define CST4325_OTP_SEL 2 /* OTP is powered up, no SPROM */ +#define CST4325_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ +#define CST4325_SDIO_USB_MODE_MASK 0x00000004 +#define CST4325_SDIO_USB_MODE_SHIFT 2 +#define CST4325_RCAL_VALID_MASK 0x00000008 +#define CST4325_RCAL_VALID_SHIFT 3 +#define CST4325_RCAL_VALUE_MASK 0x000001f0 +#define CST4325_RCAL_VALUE_SHIFT 4 +#define CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */ +#define CST4325_PMUTOP_2B_SHIFT 9 + +#define RES4329_RESERVED0 0 /* 0x00000001 */ +#define RES4329_CBUCK_LPOM 1 /* 0x00000002 */ +#define RES4329_CBUCK_BURST 2 /* 0x00000004 */ +#define RES4329_CBUCK_PWM 3 /* 0x00000008 */ +#define RES4329_CLDO_PU 4 /* 0x00000010 */ +#define RES4329_PALDO_PU 5 /* 0x00000020 */ +#define RES4329_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4329_RESERVED7 7 /* 0x00000080 */ +#define RES4329_RESERVED8 8 /* 0x00000100 */ +#define RES4329_LNLDO1_PU 9 /* 0x00000200 */ +#define RES4329_OTP_PU 10 /* 0x00000400 */ +#define RES4329_RESERVED11 11 /* 0x00000800 */ +#define RES4329_LNLDO2_PU 12 /* 0x00001000 */ +#define RES4329_XTAL_PU 13 /* 0x00002000 */ +#define RES4329_ALP_AVAIL 14 /* 0x00004000 */ +#define RES4329_RX_PWRSW_PU 15 /* 0x00008000 */ +#define RES4329_TX_PWRSW_PU 16 /* 0x00010000 */ +#define RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define RES4329_HT_AVAIL 21 /* 0x00200000 */ + +#define CST4329_SPROM_OTP_SEL_MASK 0x00000003 +#define CST4329_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ +#define CST4329_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ +#define CST4329_OTP_SEL 2 /* OTP is powered up, no SPROM */ +#define CST4329_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ +#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 +#define CST4329_SPI_SDIO_MODE_SHIFT 2 + +/* 4312 chip-specific ChipStatus register bits */ +#define CST4312_SPROM_OTP_SEL_MASK 0x00000003 +#define CST4312_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ +#define CST4312_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ +#define CST4312_OTP_SEL 2 /* OTP is powered up, no SPROM */ +#define CST4312_OTP_BAD 3 /* OTP is broken, SPROM is present */ + +/* 4312 resources (all PMU chips with little memory constraint) */ +#define RES4312_SWITCHER_BURST 0 /* 0x00000001 */ +#define RES4312_SWITCHER_PWM 1 /* 0x00000002 */ +#define RES4312_PA_REF_LDO 2 /* 0x00000004 */ +#define RES4312_CORE_LDO_BURST 3 /* 0x00000008 */ +#define RES4312_CORE_LDO_PWM 4 /* 0x00000010 */ +#define RES4312_RADIO_LDO 5 /* 0x00000020 */ +#define RES4312_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4312_BG_FILTBYP 7 /* 0x00000080 */ +#define RES4312_TX_FILTBYP 8 /* 0x00000100 */ +#define RES4312_RX_FILTBYP 9 /* 0x00000200 */ +#define RES4312_XTAL_PU 10 /* 0x00000400 */ +#define RES4312_ALP_AVAIL 11 /* 0x00000800 */ +#define RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */ +#define RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */ +#define RES4312_HT_AVAIL 14 /* 0x00004000 */ + +/* 4322 resources */ +#define RES4322_RF_LDO 0 +#define RES4322_ILP_REQUEST 1 +#define RES4322_XTAL_PU 2 +#define RES4322_ALP_AVAIL 3 +#define RES4322_SI_PLL_ON 4 +#define RES4322_HT_SI_AVAIL 5 +#define RES4322_PHY_PLL_ON 6 +#define RES4322_HT_PHY_AVAIL 7 +#define RES4322_OTP_PU 8 + +/* 4322 chip-specific ChipStatus register bits */ +#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020 +#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0 +#define CST4322_SPROM_OTP_SEL_SHIFT 6 +#define CST4322_NO_SPROM_OTP 0 /* no OTP, no SPROM */ +#define CST4322_SPROM_PRESENT 1 /* SPROM is present */ +#define CST4322_OTP_PRESENT 2 /* OTP is present */ +#define CST4322_PCI_OR_USB 0x00000100 +#define CST4322_BOOT_MASK 0x00000600 +#define CST4322_BOOT_SHIFT 9 +#define CST4322_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ +#define CST4322_BOOT_FROM_ROM 1 /* boot from ROM */ +#define CST4322_BOOT_FROM_FLASH 2 /* boot from FLASH */ +#define CST4322_BOOT_FROM_INVALID 3 +#define CST4322_ILP_DIV_EN 0x00000800 +#define CST4322_FLASH_TYPE_MASK 0x00001000 +#define CST4322_FLASH_TYPE_SHIFT 12 +#define CST4322_FLASH_TYPE_SHIFT_ST 0 /* ST serial FLASH */ +#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1 /* ATMEL flash */ +#define CST4322_ARM_TAP_SEL 0x00002000 +#define CST4322_RES_INIT_MODE_MASK 0x0000c000 +#define CST4322_RES_INIT_MODE_SHIFT 14 +#define CST4322_RES_INIT_MODE_ILPAVAIL 0 /* resinitmode: ILP available */ +#define CST4322_RES_INIT_MODE_ILPREQ 1 /* resinitmode: ILP request */ +#define CST4322_RES_INIT_MODE_ALPAVAIL 2 /* resinitmode: ALP available */ +#define CST4322_RES_INIT_MODE_HTAVAIL 3 /* resinitmode: HT available */ +#define CST4322_PCIPLLCLK_GATING 0x00010000 +#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 +#define CST4322_PCI_CARDBUS_MODE 0x00040000 + +/* 43224 chip-specific ChipControl register bits */ +#define CCTRL43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */ +#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */ +#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */ + +/* 43236 resources */ +#define RES43236_REGULATOR 0 +#define RES43236_ILP_REQUEST 1 +#define RES43236_XTAL_PU 2 +#define RES43236_ALP_AVAIL 3 +#define RES43236_SI_PLL_ON 4 +#define RES43236_HT_SI_AVAIL 5 + +/* 43236 chip-specific ChipControl register bits */ +#define CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */ +#define CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ +#define CCTRL43236_EXT_LNA (1<<2) /* 0 disable */ +#define CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ +#define CCTRL43236_GSIO (1<<4) /* 0 disable */ + +/* 43236 Chip specific ChipStatus register bits */ +#define CST43236_SFLASH_MASK 0x00000040 +#define CST43236_OTP_SEL_MASK 0x00000080 +#define CST43236_OTP_SEL_SHIFT 7 +#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 + +/* 43237 resources */ +#define RES43237_REGULATOR 0 +#define RES43237_ILP_REQUEST 1 +#define RES43237_XTAL_PU 2 +#define RES43237_ALP_AVAIL 3 +#define RES43237_SI_PLL_ON 4 +#define RES43237_HT_SI_AVAIL 5 + +/* 43237 chip-specific ChipControl register bits */ +#define CCTRL43237_BT_COEXIST (1<<0) /* 0 disable */ +#define CCTRL43237_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ +#define CCTRL43237_EXT_LNA (1<<2) /* 0 disable */ +#define CCTRL43237_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ +#define CCTRL43237_GSIO (1<<4) /* 0 disable */ + +/* 43237 Chip specific ChipStatus register bits */ +#define CST43237_SFLASH_MASK 0x00000040 +#define CST43237_OTP_SEL_MASK 0x00000080 +#define CST43237_OTP_SEL_SHIFT 7 +#define CST43237_HSIC_MASK 0x00000100 /* USB/HSIC */ +#define CST43237_BP_CLK 0x00000200 /* 120/96Mbps */ +#define CST43237_BOOT_MASK 0x00001800 +#define CST43237_BOOT_SHIFT 11 +#define CST43237_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ +#define CST43237_BOOT_FROM_ROM 1 /* boot from ROM */ +#define CST43237_BOOT_FROM_FLASH 2 /* boot from FLASH */ +#define CST43237_BOOT_FROM_INVALID 3 + +/* 43239 resources */ +#define RES43239_OTP_PU 9 +#define RES43239_MACPHY_CLKAVAIL 23 +#define RES43239_HT_AVAIL 24 + +/* 43239 Chip specific ChipStatus register bits */ +#define CST43239_SPROM_MASK 0x00000002 +#define CST43239_SFLASH_MASK 0x00000004 +#define CST43239_RES_INIT_MODE_SHIFT 7 +#define CST43239_RES_INIT_MODE_MASK 0x000001f0 +#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) /* SDIO || gSPI */ +#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15)) /* USB || USBDA */ +#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) /* SDIO */ +#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) /* gSPI */ + +/* 4324 resources */ +/* 43242 use same PMU as 4324 */ +#define RES4324_LPLDO_PU 0 +#define RES4324_RESET_PULLDN_DIS 1 +#define RES4324_PMU_BG_PU 2 +#define RES4324_HSIC_LDO_PU 3 +#define RES4324_CBUCK_LPOM_PU 4 +#define RES4324_CBUCK_PFM_PU 5 +#define RES4324_CLDO_PU 6 +#define RES4324_LPLDO2_LVM 7 +#define RES4324_LNLDO1_PU 8 +#define RES4324_LNLDO2_PU 9 +#define RES4324_LDO3P3_PU 10 +#define RES4324_OTP_PU 11 +#define RES4324_XTAL_PU 12 +#define RES4324_BBPLL_PU 13 +#define RES4324_LQ_AVAIL 14 +#define RES4324_WL_CORE_READY 17 +#define RES4324_ILP_REQ 18 +#define RES4324_ALP_AVAIL 19 +#define RES4324_PALDO_PU 20 +#define RES4324_RADIO_PU 21 +#define RES4324_SR_CLK_STABLE 22 +#define RES4324_SR_SAVE_RESTORE 23 +#define RES4324_SR_PHY_PWRSW 24 +#define RES4324_SR_PHY_PIC 25 +#define RES4324_SR_SUBCORE_PWRSW 26 +#define RES4324_SR_SUBCORE_PIC 27 +#define RES4324_SR_MEM_PM0 28 +#define RES4324_HT_AVAIL 29 +#define RES4324_MACPHY_CLKAVAIL 30 + +/* 4324 Chip specific ChipStatus register bits */ +#define CST4324_SPROM_MASK 0x00000080 +#define CST4324_SFLASH_MASK 0x00400000 +#define CST4324_RES_INIT_MODE_SHIFT 10 +#define CST4324_RES_INIT_MODE_MASK 0x00000c00 +#define CST4324_CHIPMODE_MASK 0x7 +#define CST4324_CHIPMODE_SDIOD(cs) ((~(cs)) & (1 << 2)) /* SDIO || gSPI */ +#define CST4324_CHIPMODE_USB20D(cs) (((cs) & CST4324_CHIPMODE_MASK) == 0x6) /* USB || USBDA */ + +/* 43242 Chip specific ChipStatus register bits */ +#define CST43242_SFLASH_MASK 0x00000008 +#define CST43242_SR_HALT (1<<25) +#define CST43242_SR_CHIP_STATUS_2 27 /* bit 27 */ + +/* 4331 resources */ +#define RES4331_REGULATOR 0 +#define RES4331_ILP_REQUEST 1 +#define RES4331_XTAL_PU 2 +#define RES4331_ALP_AVAIL 3 +#define RES4331_SI_PLL_ON 4 +#define RES4331_HT_SI_AVAIL 5 + +/* 4331 chip-specific ChipControl register bits */ +#define CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */ +#define CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ +#define CCTRL4331_EXT_LNA_G (1<<2) /* 0 disable */ +#define CCTRL4331_SPROM_GPIO13_15 (1<<3) /* sprom/gpio13-15 mux */ +#define CCTRL4331_EXTPA_EN (1<<4) /* 0 ext pa disable, 1 ext pa enabled */ +#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) /* set drive out GPIO_CLK on sprom_cs pin */ +#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) /* use sprom_cs pin as PCIE mdio interface */ +#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) /* aband extpa will be at gpio2/5 and sprom_dout */ +#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) /* override core control on pipe_AuxClkEnable */ +#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) /* override core control on pipe_AuxPowerDown */ +#define CCTRL4331_PCIE_AUXCLKEN (1<<10) /* pcie_auxclkenable */ +#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) /* pcie_pipe_pllpowerdown */ +#define CCTRL4331_EXTPA_EN2 (1<<12) /* 0 ext pa disable, 1 ext pa enabled */ +#define CCTRL4331_EXT_LNA_A (1<<13) /* 0 disable */ +#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */ +#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */ +#define CCTRL4331_EXTPA_ANA_EN (1<<24) /* 0 ext pa disable, 1 ext pa enabled */ + +/* 4331 Chip specific ChipStatus register bits */ +#define CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */ +#define CST4331_SPROM_OTP_SEL_MASK 0x00000006 +#define CST4331_SPROM_OTP_SEL_SHIFT 1 +#define CST4331_SPROM_PRESENT 0x00000002 +#define CST4331_OTP_PRESENT 0x00000004 +#define CST4331_LDO_RF 0x00000008 +#define CST4331_LDO_PAR 0x00000010 + +/* 4315 resource */ +#define RES4315_CBUCK_LPOM 1 /* 0x00000002 */ +#define RES4315_CBUCK_BURST 2 /* 0x00000004 */ +#define RES4315_CBUCK_PWM 3 /* 0x00000008 */ +#define RES4315_CLDO_PU 4 /* 0x00000010 */ +#define RES4315_PALDO_PU 5 /* 0x00000020 */ +#define RES4315_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4315_LNLDO1_PU 9 /* 0x00000200 */ +#define RES4315_OTP_PU 10 /* 0x00000400 */ +#define RES4315_LNLDO2_PU 12 /* 0x00001000 */ +#define RES4315_XTAL_PU 13 /* 0x00002000 */ +#define RES4315_ALP_AVAIL 14 /* 0x00004000 */ +#define RES4315_RX_PWRSW_PU 15 /* 0x00008000 */ +#define RES4315_TX_PWRSW_PU 16 /* 0x00010000 */ +#define RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define RES4315_HT_AVAIL 21 /* 0x00200000 */ + +/* 4315 chip-specific ChipStatus register bits */ +#define CST4315_SPROM_OTP_SEL_MASK 0x00000003 /* gpio [7:6], SDIO CIS selection */ +#define CST4315_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ +#define CST4315_SPROM_SEL 0x00000001 /* use SPROM, OTP is powered up */ +#define CST4315_OTP_SEL 0x00000002 /* use OTP, OTP is powered up */ +#define CST4315_OTP_PWRDN 0x00000003 /* use SPROM, OTP is powered down */ +#define CST4315_SDIO_MODE 0x00000004 /* gpio [8], sdio/usb mode */ +#define CST4315_RCAL_VALID 0x00000008 +#define CST4315_RCAL_VALUE_MASK 0x000001f0 +#define CST4315_RCAL_VALUE_SHIFT 4 +#define CST4315_PALDO_EXTPNP 0x00000200 /* PALDO is configured with external PNP */ +#define CST4315_CBUCK_MODE_MASK 0x00000c00 +#define CST4315_CBUCK_MODE_BURST 0x00000400 +#define CST4315_CBUCK_MODE_LPBURST 0x00000c00 + +/* 4319 resources */ +#define RES4319_CBUCK_LPOM 1 /* 0x00000002 */ +#define RES4319_CBUCK_BURST 2 /* 0x00000004 */ +#define RES4319_CBUCK_PWM 3 /* 0x00000008 */ +#define RES4319_CLDO_PU 4 /* 0x00000010 */ +#define RES4319_PALDO_PU 5 /* 0x00000020 */ +#define RES4319_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4319_LNLDO1_PU 9 /* 0x00000200 */ +#define RES4319_OTP_PU 10 /* 0x00000400 */ +#define RES4319_LNLDO2_PU 12 /* 0x00001000 */ +#define RES4319_XTAL_PU 13 /* 0x00002000 */ +#define RES4319_ALP_AVAIL 14 /* 0x00004000 */ +#define RES4319_RX_PWRSW_PU 15 /* 0x00008000 */ +#define RES4319_TX_PWRSW_PU 16 /* 0x00010000 */ +#define RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define RES4319_HT_AVAIL 21 /* 0x00200000 */ + +/* 4319 chip-specific ChipStatus register bits */ +#define CST4319_SPI_CPULESSUSB 0x00000001 +#define CST4319_SPI_CLK_POL 0x00000002 +#define CST4319_SPI_CLK_PH 0x00000008 +#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 /* gpio [7:6], SDIO CIS selection */ +#define CST4319_SPROM_OTP_SEL_SHIFT 6 +#define CST4319_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ +#define CST4319_SPROM_SEL 0x00000040 /* use SPROM, OTP is powered up */ +#define CST4319_OTP_SEL 0x00000080 /* use OTP, OTP is powered up */ +#define CST4319_OTP_PWRDN 0x000000c0 /* use SPROM, OTP is powered down */ +#define CST4319_SDIO_USB_MODE 0x00000100 /* gpio [8], sdio/usb mode */ +#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 +#define CST4319_PALDO_EXTPNP 0x00010000 /* PALDO is configured with external PNP */ +#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 + +#define PMU1_PLL0_CHIPCTL0 0 +#define PMU1_PLL0_CHIPCTL1 1 +#define PMU1_PLL0_CHIPCTL2 2 +#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000 +#define CCTL_4319USB_XTAL_SEL_SHIFT 19 +#define CCTL_4319USB_48MHZ_PLL_SEL 1 +#define CCTL_4319USB_24MHZ_PLL_SEL 2 + +/* PMU resources for 4336 */ +#define RES4336_CBUCK_LPOM 0 +#define RES4336_CBUCK_BURST 1 +#define RES4336_CBUCK_LP_PWM 2 +#define RES4336_CBUCK_PWM 3 +#define RES4336_CLDO_PU 4 +#define RES4336_DIS_INT_RESET_PD 5 +#define RES4336_ILP_REQUEST 6 +#define RES4336_LNLDO_PU 7 +#define RES4336_LDO3P3_PU 8 +#define RES4336_OTP_PU 9 +#define RES4336_XTAL_PU 10 +#define RES4336_ALP_AVAIL 11 +#define RES4336_RADIO_PU 12 +#define RES4336_BG_PU 13 +#define RES4336_VREG1p4_PU_PU 14 +#define RES4336_AFE_PWRSW_PU 15 +#define RES4336_RX_PWRSW_PU 16 +#define RES4336_TX_PWRSW_PU 17 +#define RES4336_BB_PWRSW_PU 18 +#define RES4336_SYNTH_PWRSW_PU 19 +#define RES4336_MISC_PWRSW_PU 20 +#define RES4336_LOGEN_PWRSW_PU 21 +#define RES4336_BBPLL_PWRSW_PU 22 +#define RES4336_MACPHY_CLKAVAIL 23 +#define RES4336_HT_AVAIL 24 +#define RES4336_RSVD 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 + +/* 4336 Chip specific PMU ChipControl register bits */ +#define PCTL_4336_SERIAL_ENAB (1 << 24) + +/* 4330 resources */ +#define RES4330_CBUCK_LPOM 0 +#define RES4330_CBUCK_BURST 1 +#define RES4330_CBUCK_LP_PWM 2 +#define RES4330_CBUCK_PWM 3 +#define RES4330_CLDO_PU 4 +#define RES4330_DIS_INT_RESET_PD 5 +#define RES4330_ILP_REQUEST 6 +#define RES4330_LNLDO_PU 7 +#define RES4330_LDO3P3_PU 8 +#define RES4330_OTP_PU 9 +#define RES4330_XTAL_PU 10 +#define RES4330_ALP_AVAIL 11 +#define RES4330_RADIO_PU 12 +#define RES4330_BG_PU 13 +#define RES4330_VREG1p4_PU_PU 14 +#define RES4330_AFE_PWRSW_PU 15 +#define RES4330_RX_PWRSW_PU 16 +#define RES4330_TX_PWRSW_PU 17 +#define RES4330_BB_PWRSW_PU 18 +#define RES4330_SYNTH_PWRSW_PU 19 +#define RES4330_MISC_PWRSW_PU 20 +#define RES4330_LOGEN_PWRSW_PU 21 +#define RES4330_BBPLL_PWRSW_PU 22 +#define RES4330_MACPHY_CLKAVAIL 23 +#define RES4330_HT_AVAIL 24 +#define RES4330_5gRX_PWRSW_PU 25 +#define RES4330_5gTX_PWRSW_PU 26 +#define RES4330_5g_LOGEN_PWRSW_PU 27 + +/* 4330 chip-specific ChipStatus register bits */ +#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */ +#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */ +#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) /* SDIO */ +#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) /* gSPI */ +#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) /* USB packet-oriented */ +#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) /* USB Direct Access */ +#define CST4330_OTP_PRESENT 0x00000010 +#define CST4330_LPO_AUTODET_EN 0x00000020 +#define CST4330_ARMREMAP_0 0x00000040 +#define CST4330_SPROM_PRESENT 0x00000080 /* takes priority over OTP if both set */ +#define CST4330_ILPDIV_EN 0x00000100 +#define CST4330_LPO_SEL 0x00000200 +#define CST4330_RES_INIT_MODE_SHIFT 10 +#define CST4330_RES_INIT_MODE_MASK 0x00000c00 +#define CST4330_CBUCK_MODE_SHIFT 12 +#define CST4330_CBUCK_MODE_MASK 0x00003000 +#define CST4330_CBUCK_POWER_OK 0x00004000 +#define CST4330_BB_PLL_LOCKED 0x00008000 +#define SOCDEVRAM_BP_ADDR 0x1E000000 +#define SOCDEVRAM_ARM_ADDR 0x00800000 + +/* 4330 Chip specific PMU ChipControl register bits */ +#define PCTL_4330_SERIAL_ENAB (1 << 24) + +/* 4330 Chip specific ChipControl register bits */ +#define CCTRL_4330_GPIO_SEL 0x00000001 /* 1=select GPIOs to be muxed out */ +#define CCTRL_4330_ERCX_SEL 0x00000002 /* 1=select ERCX BT coex to be muxed out */ +#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004 /* SDIO: 1=configure GPIO0 for host wake */ +#define CCTRL_4330_JTAG_DISABLE 0x00000008 /* 1=disable JTAG interface on mux'd pins */ + +#define PMU_VREG0_ADDR 0 +#define PMU_VREG0_DISABLE_PULLD_BT_SHIFT 2 +#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 3 + +#define PMU_VREG4_ADDR 4 + +#define PMU_VREG4_CLDO_PWM_SHIFT 4 +#define PMU_VREG4_CLDO_PWM_MASK 0x7 + +#define PMU_VREG4_LPLDO1_SHIFT 15 +#define PMU_VREG4_LPLDO1_MASK 0x7 +#define PMU_VREG4_LPLDO1_1p20V 0 +#define PMU_VREG4_LPLDO1_1p15V 1 +#define PMU_VREG4_LPLDO1_1p10V 2 +#define PMU_VREG4_LPLDO1_1p25V 3 +#define PMU_VREG4_LPLDO1_1p05V 4 +#define PMU_VREG4_LPLDO1_1p00V 5 +#define PMU_VREG4_LPLDO1_0p95V 6 +#define PMU_VREG4_LPLDO1_0p90V 7 + +/* 4350/4345 VREG4 settings */ +#define PMU4350_VREG4_LPLDO1_1p10V 0 +#define PMU4350_VREG4_LPLDO1_1p15V 1 +#define PMU4350_VREG4_LPLDO1_1p21V 2 +#define PMU4350_VREG4_LPLDO1_1p24V 3 +#define PMU4350_VREG4_LPLDO1_0p90V 4 +#define PMU4350_VREG4_LPLDO1_0p96V 5 +#define PMU4350_VREG4_LPLDO1_1p01V 6 +#define PMU4350_VREG4_LPLDO1_1p04V 7 + +#define PMU_VREG4_LPLDO2_LVM_SHIFT 18 +#define PMU_VREG4_LPLDO2_LVM_MASK 0x7 +#define PMU_VREG4_LPLDO2_HVM_SHIFT 21 +#define PMU_VREG4_LPLDO2_HVM_MASK 0x7 +#define PMU_VREG4_LPLDO2_LVM_HVM_MASK 0x3f +#define PMU_VREG4_LPLDO2_1p00V 0 +#define PMU_VREG4_LPLDO2_1p15V 1 +#define PMU_VREG4_LPLDO2_1p20V 2 +#define PMU_VREG4_LPLDO2_1p10V 3 +#define PMU_VREG4_LPLDO2_0p90V 4 /* 4 - 7 is 0.90V */ + +#define PMU_VREG4_HSICLDO_BYPASS_SHIFT 27 +#define PMU_VREG4_HSICLDO_BYPASS_MASK 0x1 + +#define PMU_VREG5_ADDR 5 +#define PMU_VREG5_HSICAVDD_PD_SHIFT 6 +#define PMU_VREG5_HSICAVDD_PD_MASK 0x1 +#define PMU_VREG5_HSICDVDD_PD_SHIFT 11 +#define PMU_VREG5_HSICDVDD_PD_MASK 0x1 + +/* 4334 resources */ +#define RES4334_LPLDO_PU 0 +#define RES4334_RESET_PULLDN_DIS 1 +#define RES4334_PMU_BG_PU 2 +#define RES4334_HSIC_LDO_PU 3 +#define RES4334_CBUCK_LPOM_PU 4 +#define RES4334_CBUCK_PFM_PU 5 +#define RES4334_CLDO_PU 6 +#define RES4334_LPLDO2_LVM 7 +#define RES4334_LNLDO_PU 8 +#define RES4334_LDO3P3_PU 9 +#define RES4334_OTP_PU 10 +#define RES4334_XTAL_PU 11 +#define RES4334_WL_PWRSW_PU 12 +#define RES4334_LQ_AVAIL 13 +#define RES4334_LOGIC_RET 14 +#define RES4334_MEM_SLEEP 15 +#define RES4334_MACPHY_RET 16 +#define RES4334_WL_CORE_READY 17 +#define RES4334_ILP_REQ 18 +#define RES4334_ALP_AVAIL 19 +#define RES4334_MISC_PWRSW_PU 20 +#define RES4334_SYNTH_PWRSW_PU 21 +#define RES4334_RX_PWRSW_PU 22 +#define RES4334_RADIO_PU 23 +#define RES4334_WL_PMU_PU 24 +#define RES4334_VCO_LDO_PU 25 +#define RES4334_AFE_LDO_PU 26 +#define RES4334_RX_LDO_PU 27 +#define RES4334_TX_LDO_PU 28 +#define RES4334_HT_AVAIL 29 +#define RES4334_MACPHY_CLK_AVAIL 30 + +/* 4334 chip-specific ChipStatus register bits */ +#define CST4334_CHIPMODE_MASK 7 +#define CST4334_SDIO_MODE 0x00000000 +#define CST4334_SPI_MODE 0x00000004 +#define CST4334_HSIC_MODE 0x00000006 +#define CST4334_BLUSB_MODE 0x00000007 +#define CST4334_CHIPMODE_HSIC(cs) (((cs) & CST4334_CHIPMODE_MASK) == CST4334_HSIC_MODE) +#define CST4334_OTP_PRESENT 0x00000010 +#define CST4334_LPO_AUTODET_EN 0x00000020 +#define CST4334_ARMREMAP_0 0x00000040 +#define CST4334_SPROM_PRESENT 0x00000080 +#define CST4334_ILPDIV_EN_MASK 0x00000100 +#define CST4334_ILPDIV_EN_SHIFT 8 +#define CST4334_LPO_SEL_MASK 0x00000200 +#define CST4334_LPO_SEL_SHIFT 9 +#define CST4334_RES_INIT_MODE_MASK 0x00000C00 +#define CST4334_RES_INIT_MODE_SHIFT 10 + +/* 4334 Chip specific PMU ChipControl register bits */ +#define PCTL_4334_GPIO3_ENAB (1 << 3) + +/* 4334 Chip control */ +#define CCTRL4334_PMU_WAKEUP_GPIO1 (1 << 0) +#define CCTRL4334_PMU_WAKEUP_HSIC (1 << 1) +#define CCTRL4334_PMU_WAKEUP_AOS (1 << 2) +#define CCTRL4334_HSIC_WAKE_MODE (1 << 3) +#define CCTRL4334_HSIC_INBAND_GPIO1 (1 << 4) +#define CCTRL4334_HSIC_LDO_PU (1 << 23) + +/* 4334 Chip control 3 */ +#define CCTRL4334_BLOCK_EXTRNL_WAKE (1 << 4) +#define CCTRL4334_SAVERESTORE_FIX (1 << 5) + +/* 43341 Chip control 3 */ +#define CCTRL43341_BLOCK_EXTRNL_WAKE (1 << 13) +#define CCTRL43341_SAVERESTORE_FIX (1 << 14) +#define CCTRL43341_BT_ISO_SEL (1 << 16) + +/* 4334 Chip specific ChipControl1 register bits */ +#define CCTRL1_4334_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ +#define CCTRL1_4334_ERCX_SEL (1 << 1) /* 1=select ERCX BT coex to be muxed out */ +#define CCTRL1_4334_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ +#define CCTRL1_4334_JTAG_DISABLE (1 << 3) /* 1=disable JTAG interface on mux'd pins */ +#define CCTRL1_4334_UART_ON_4_5 (1 << 28) /* 1=UART_TX/UART_RX muxed on GPIO_4/5 (4334B0/1) */ + +/* 4324 Chip specific ChipControl1 register bits */ +#define CCTRL1_4324_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ +#define CCTRL1_4324_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ + +/* 43143 chip-specific ChipStatus register bits based on Confluence documentation */ +/* register contains strap values sampled during POR */ +#define CST43143_REMAP_TO_ROM (3 << 0) /* 00=Boot SRAM, 01=Boot ROM, 10=Boot SFLASH */ +#define CST43143_SDIO_EN (1 << 2) /* 0 = USB Enab, SDIO pins are GPIO or I2S */ +#define CST43143_SDIO_ISO (1 << 3) /* 1 = SDIO isolated */ +#define CST43143_USB_CPU_LESS (1 << 4) /* 1 = CPULess mode Enabled */ +#define CST43143_CBUCK_MODE (3 << 6) /* Indicates what controller mode CBUCK is in */ +#define CST43143_POK_CBUCK (1 << 8) /* 1 = 1.2V CBUCK voltage ready */ +#define CST43143_PMU_OVRSPIKE (1 << 9) +#define CST43143_PMU_OVRTEMP (0xF << 10) +#define CST43143_SR_FLL_CAL_DONE (1 << 14) +#define CST43143_USB_PLL_LOCKDET (1 << 15) +#define CST43143_PMU_PLL_LOCKDET (1 << 16) +#define CST43143_CHIPMODE_SDIOD(cs) (((cs) & CST43143_SDIO_EN) != 0) /* SDIO */ + +/* 43143 Chip specific ChipControl register bits */ +/* 00: SECI is disabled (JATG functional), 01: 2 wire, 10: 4 wire */ +#define CCTRL_43143_SECI (1<<0) +#define CCTRL_43143_BT_LEGACY (1<<1) +#define CCTRL_43143_I2S_MODE (1<<2) /* 0: SDIO enabled */ +#define CCTRL_43143_I2S_MASTER (1<<3) /* 0: I2S MCLK input disabled */ +#define CCTRL_43143_I2S_FULL (1<<4) /* 0: I2S SDIN and SPDIF_TX inputs disabled */ +#define CCTRL_43143_GSIO (1<<5) /* 0: sFlash enabled */ +#define CCTRL_43143_RF_SWCTRL_MASK (7<<6) /* 0: disabled */ +#define CCTRL_43143_RF_SWCTRL_0 (1<<6) +#define CCTRL_43143_RF_SWCTRL_1 (2<<6) +#define CCTRL_43143_RF_SWCTRL_2 (4<<6) +#define CCTRL_43143_RF_XSWCTRL (1<<9) /* 0: UART enabled */ +#define CCTRL_43143_HOST_WAKE0 (1<<11) /* 1: SDIO separate interrupt output from GPIO4 */ +#define CCTRL_43143_HOST_WAKE1 (1<<12) /* 1: SDIO separate interrupt output from GPIO16 */ + +/* 43143 resources, based on pmu_params.xls V1.19 */ +#define RES43143_EXT_SWITCHER_PWM 0 /* 0x00001 */ +#define RES43143_XTAL_PU 1 /* 0x00002 */ +#define RES43143_ILP_REQUEST 2 /* 0x00004 */ +#define RES43143_ALP_AVAIL 3 /* 0x00008 */ +#define RES43143_WL_CORE_READY 4 /* 0x00010 */ +#define RES43143_BBPLL_PWRSW_PU 5 /* 0x00020 */ +#define RES43143_HT_AVAIL 6 /* 0x00040 */ +#define RES43143_RADIO_PU 7 /* 0x00080 */ +#define RES43143_MACPHY_CLK_AVAIL 8 /* 0x00100 */ +#define RES43143_OTP_PU 9 /* 0x00200 */ +#define RES43143_LQ_AVAIL 10 /* 0x00400 */ + +#define PMU43143_XTAL_CORE_SIZE_MASK 0x3F + +/* 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 + +/* 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 */ +#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */ + +/* PMU respources for 4314 */ +#define RES4314_LPLDO_PU 0 +#define RES4314_PMU_SLEEP_DIS 1 +#define RES4314_PMU_BG_PU 2 +#define RES4314_CBUCK_LPOM_PU 3 +#define RES4314_CBUCK_PFM_PU 4 +#define RES4314_CLDO_PU 5 +#define RES4314_LPLDO2_LVM 6 +#define RES4314_WL_PMU_PU 7 +#define RES4314_LNLDO_PU 8 +#define RES4314_LDO3P3_PU 9 +#define RES4314_OTP_PU 10 +#define RES4314_XTAL_PU 11 +#define RES4314_WL_PWRSW_PU 12 +#define RES4314_LQ_AVAIL 13 +#define RES4314_LOGIC_RET 14 +#define RES4314_MEM_SLEEP 15 +#define RES4314_MACPHY_RET 16 +#define RES4314_WL_CORE_READY 17 +#define RES4314_ILP_REQ 18 +#define RES4314_ALP_AVAIL 19 +#define RES4314_MISC_PWRSW_PU 20 +#define RES4314_SYNTH_PWRSW_PU 21 +#define RES4314_RX_PWRSW_PU 22 +#define RES4314_RADIO_PU 23 +#define RES4314_VCO_LDO_PU 24 +#define RES4314_AFE_LDO_PU 25 +#define RES4314_RX_LDO_PU 26 +#define RES4314_TX_LDO_PU 27 +#define RES4314_HT_AVAIL 28 +#define RES4314_MACPHY_CLK_AVAIL 29 + +/* 4314 chip-specific ChipStatus register bits */ +#define CST4314_OTP_ENABLED 0x00200000 + +/* 43228 resources */ +#define RES43228_NOT_USED 0 +#define RES43228_ILP_REQUEST 1 +#define RES43228_XTAL_PU 2 +#define RES43228_ALP_AVAIL 3 +#define RES43228_PLL_EN 4 +#define RES43228_HT_PHY_AVAIL 5 + +/* 43228 chipstatus reg bits */ +#define CST43228_ILP_DIV_EN 0x1 +#define CST43228_OTP_PRESENT 0x2 +#define CST43228_SERDES_REFCLK_PADSEL 0x4 +#define CST43228_SDIO_MODE 0x8 +#define CST43228_SDIO_OTP_PRESENT 0x10 +#define CST43228_SDIO_RESET 0x20 + +/* 4706 chipstatus reg bits */ +#define CST4706_PKG_OPTION (1<<0) /* 0: full-featured package 1: low-cost package */ +#define CST4706_SFLASH_PRESENT (1<<1) /* 0: parallel, 1: serial flash is present */ +#define CST4706_SFLASH_TYPE (1<<2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */ +#define CST4706_MIPS_BENDIAN (1<<3) /* 0: little, 1: big endian */ +#define CST4706_PCIE1_DISABLE (1<<5) /* PCIE1 enable strap pin */ + +/* 4706 flashstrconfig reg bits */ +#define FLSTRCF4706_MASK 0x000000ff +#define FLSTRCF4706_SF1 0x00000001 /* 2nd serial flash present */ +#define FLSTRCF4706_PF1 0x00000002 /* 2nd parallel flash present */ +#define FLSTRCF4706_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */ +#define FLSTRCF4706_NF1 0x00000008 /* 2nd NAND flash present */ +#define FLSTRCF4706_1ST_MADDR_SEG_MASK 0x000000f0 /* Valid value mask */ +#define FLSTRCF4706_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */ + +/* 4360 Chip specific ChipControl register bits */ +#define CCTRL4360_I2C_MODE (1 << 0) +#define CCTRL4360_UART_MODE (1 << 1) +#define CCTRL4360_SECI_MODE (1 << 2) +#define CCTRL4360_BTSWCTRL_MODE (1 << 3) +#define CCTRL4360_DISCRETE_FEMCTRL_MODE (1 << 4) +#define CCTRL4360_DIGITAL_PACTRL_MODE (1 << 5) +#define CCTRL4360_BTSWCTRL_AND_DIGPA_PRESENT (1 << 6) +#define CCTRL4360_EXTRA_GPIO_MODE (1 << 7) +#define CCTRL4360_EXTRA_FEMCTRL_MODE (1 << 8) +#define CCTRL4360_BT_LGCY_MODE (1 << 9) +#define CCTRL4360_CORE2FEMCTRL4_ON (1 << 21) +#define CCTRL4360_SECI_ON_GPIO01 (1 << 24) + +/* 4360 Chip specific Regulator Control register bits */ +#define RCTRL4360_RFLDO_PWR_DOWN (1 << 1) + +/* 4360 PMU resources and chip status bits */ +#define RES4360_REGULATOR 0 +#define RES4360_ILP_AVAIL 1 +#define RES4360_ILP_REQ 2 +#define RES4360_XTAL_LDO_PU 3 +#define RES4360_XTAL_PU 4 +#define RES4360_ALP_AVAIL 5 +#define RES4360_BBPLLPWRSW_PU 6 +#define RES4360_HT_AVAIL 7 +#define RES4360_OTP_PU 8 + +#define CST4360_XTAL_40MZ 0x00000001 +#define CST4360_SFLASH 0x00000002 +#define CST4360_SPROM_PRESENT 0x00000004 +#define CST4360_SFLASH_TYPE 0x00000004 +#define CST4360_OTP_ENABLED 0x00000008 +#define CST4360_REMAP_ROM 0x00000010 +#define CST4360_RSRC_INIT_MODE_MASK 0x00000060 +#define CST4360_RSRC_INIT_MODE_SHIFT 5 +#define CST4360_ILP_DIVEN 0x00000080 +#define CST4360_MODE_USB 0x00000100 +#define CST4360_SPROM_SIZE_MASK 0x00000600 +#define CST4360_SPROM_SIZE_SHIFT 9 +#define CST4360_BBPLL_LOCK 0x00000800 +#define CST4360_AVBBPLL_LOCK 0x00001000 +#define CST4360_USBBBPLL_LOCK 0x00002000 +#define CST4360_RSRC_INIT_MODE(cs) ((cs & CST4360_RSRC_INIT_MODE_MASK) >> \ + CST4360_RSRC_INIT_MODE_SHIFT) + +#define CCTRL_4360_UART_SEL 0x2 +#define CST4360_RSRC_INIT_MODE(cs) ((cs & CST4360_RSRC_INIT_MODE_MASK) >> \ + CST4360_RSRC_INIT_MODE_SHIFT) + + +/* 43602 PMU resources based on pmu_params.xls version v0.95 */ +#define RES43602_LPLDO_PU 0 +#define RES43602_REGULATOR 1 +#define RES43602_PMU_SLEEP 2 +#define RES43602_RSVD_3 3 +#define RES43602_XTALLDO_PU 4 +#define RES43602_SERDES_PU 5 +#define RES43602_BBPLL_PWRSW_PU 6 +#define RES43602_SR_CLK_START 7 +#define RES43602_SR_PHY_PWRSW 8 +#define RES43602_SR_SUBCORE_PWRSW 9 +#define RES43602_XTAL_PU 10 +#define RES43602_PERST_OVR 11 +#define RES43602_SR_CLK_STABLE 12 +#define RES43602_SR_SAVE_RESTORE 13 +#define RES43602_SR_SLEEP 14 +#define RES43602_LQ_START 15 +#define RES43602_LQ_AVAIL 16 +#define RES43602_WL_CORE_RDY 17 +#define RES43602_ILP_REQ 18 +#define RES43602_ALP_AVAIL 19 +#define RES43602_RADIO_PU 20 +#define RES43602_RFLDO_PU 21 +#define RES43602_HT_START 22 +#define RES43602_HT_AVAIL 23 +#define RES43602_MACPHY_CLKAVAIL 24 +#define RES43602_PARLDO_PU 25 +#define RES43602_RSVD_26 26 + +/* 43602 chip status bits */ +#define CST43602_SPROM_PRESENT (1<<1) +#define CST43602_SPROM_SIZE (1<<10) /* 0 = 16K, 1 = 4K */ +#define CST43602_BBPLL_LOCK (1<<11) +#define CST43602_RF_LDO_OUT_OK (1<<15) /* RF LDO output OK */ + +#define PMU43602_CC1_GPIO12_OVRD (1<<28) /* GPIO12 override */ + +#define PMU43602_CC2_PCIE_CLKREQ_L_WAKE_EN (1<<1) /* creates gated_pcie_wake, pmu_wakeup logic */ +#define PMU43602_CC2_PCIE_PERST_L_WAKE_EN (1<<2) /* creates gated_pcie_wake, pmu_wakeup logic */ +#define PMU43602_CC2_ENABLE_L2REFCLKPAD_PWRDWN (1<<3) +#define PMU43602_CC2_PMU_WAKE_ALP_AVAIL_EN (1<<5) /* enable pmu_wakeup to request for ALP_AVAIL */ +#define PMU43602_CC2_PERST_L_EXTEND_EN (1<<9) /* extend perst_l until rsc PERST_OVR comes up */ +#define PMU43602_CC2_FORCE_EXT_LPO (1<<19) /* 1=ext LPO clock is the final LPO clock */ +#define PMU43602_CC2_XTAL32_SEL (1<<30) /* 0=ext_clock, 1=xtal */ + +#define CC_SR1_43602_SR_ASM_ADDR (0x0) + +/* PLL CTL register values for open loop, used during S/R operation */ +#define PMU43602_PLL_CTL6_VAL 0x68000528 +#define PMU43602_PLL_CTL7_VAL 0x6 + +#define PMU43602_CC3_ARMCR4_DBG_CLK (1 << 29) + +/* 4349 related */ +#define RES4349_LPLDO_PU 0 +#define RES4349_BG_PU 1 +#define RES4349_PMU_SLEEP 2 +#define RES4349_PALDO3P3_PU 3 +#define RES4349_CBUCK_LPOM_PU 4 +#define RES4349_CBUCK_PFM_PU 5 +#define RES4349_COLD_START_WAIT 6 +#define RES4349_RSVD_7 7 +#define RES4349_LNLDO_PU 8 +#define RES4349_XTALLDO_PU 9 +#define RES4349_LDO3P3_PU 10 +#define RES4349_OTP_PU 11 +#define RES4349_XTAL_PU 12 +#define RES4349_SR_CLK_START 13 +#define RES4349_LQ_AVAIL 14 +#define RES4349_LQ_START 15 +#define RES4349_PERST_OVR 16 +#define RES4349_WL_CORE_RDY 17 +#define RES4349_ILP_REQ 18 +#define RES4349_ALP_AVAIL 19 +#define RES4349_MINI_PMU 20 +#define RES4349_RADIO_PU 21 +#define RES4349_SR_CLK_STABLE 22 +#define RES4349_SR_SAVE_RESTORE 23 +#define RES4349_SR_PHY_PWRSW 24 +#define RES4349_SR_VDDM_PWRSW 25 +#define RES4349_SR_SUBCORE_PWRSW 26 +#define RES4349_SR_SLEEP 27 +#define RES4349_HT_START 28 +#define RES4349_HT_AVAIL 29 +#define RES4349_MACPHY_CLKAVAIL 30 + +#define CR4_4349_RAM_BASE (0x180000) +#define CC4_4349_SR_ASM_ADDR (0x48) + +#define CST4349_CHIPMODE_SDIOD(cs) (((cs) & (1 << 6)) != 0) /* SDIO */ +#define CST4349_CHIPMODE_PCIE(cs) (((cs) & (1 << 7)) != 0) /* PCIE */ + +#define CST4349_SPROM_PRESENT 0x00000010 + + +/* 43430 PMU resources based on pmu_params.xls */ +#define RES43430_LPLDO_PU 0 +#define RES43430_BG_PU 1 +#define RES43430_PMU_SLEEP 2 +#define RES43430_RSVD_3 3 +#define RES43430_CBUCK_LPOM_PU 4 +#define RES43430_CBUCK_PFM_PU 5 +#define RES43430_COLD_START_WAIT 6 +#define RES43430_RSVD_7 7 +#define RES43430_LNLDO_PU 8 +#define RES43430_RSVD_9 9 +#define RES43430_LDO3P3_PU 10 +#define RES43430_OTP_PU 11 +#define RES43430_XTAL_PU 12 +#define RES43430_SR_CLK_START 13 +#define RES43430_LQ_AVAIL 14 +#define RES43430_LQ_START 15 +#define RES43430_RSVD_16 16 +#define RES43430_WL_CORE_RDY 17 +#define RES43430_ILP_REQ 18 +#define RES43430_ALP_AVAIL 19 +#define RES43430_MINI_PMU 20 +#define RES43430_RADIO_PU 21 +#define RES43430_SR_CLK_STABLE 22 +#define RES43430_SR_SAVE_RESTORE 23 +#define RES43430_SR_PHY_PWRSW 24 +#define RES43430_SR_VDDM_PWRSW 25 +#define RES43430_SR_SUBCORE_PWRSW 26 +#define RES43430_SR_SLEEP 27 +#define RES43430_HT_START 28 +#define RES43430_HT_AVAIL 29 +#define RES43430_MACPHY_CLK_AVAIL 30 + +/* 43430 chip status bits */ +#define CST43430_SDIO_MODE 0x00000001 +#define CST43430_GSPI_MODE 0x00000002 +#define CST43430_RSRC_INIT_MODE_0 0x00000080 +#define CST43430_RSRC_INIT_MODE_1 0x00000100 +#define CST43430_SEL0_SDIO 0x00000200 +#define CST43430_SEL1_SDIO 0x00000400 +#define CST43430_SEL2_SDIO 0x00000800 +#define CST43430_BBPLL_LOCKED 0x00001000 +#define CST43430_DBG_INST_DETECT 0x00004000 +#define CST43430_CLB2WL_BT_READY 0x00020000 +#define CST43430_JTAG_MODE 0x00100000 +#define CST43430_HOST_IFACE 0x00400000 +#define CST43430_TRIM_EN 0x00800000 +#define CST43430_DIN_PACKAGE_OPTION 0x10000000 + +/* defines to detect active host interface in use */ +#define CHIP_HOSTIF_PCIEMODE 0x1 +#define CHIP_HOSTIF_USBMODE 0x2 +#define CHIP_HOSTIF_SDIOMODE 0x4 +#define CHIP_HOSTIF_PCIE(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_PCIEMODE) +#define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_USBMODE) +#define CHIP_HOSTIF_SDIO(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_SDIOMODE) + +/* 4335 resources */ +#define RES4335_LPLDO_PO 0 +#define RES4335_PMU_BG_PU 1 +#define RES4335_PMU_SLEEP 2 +#define RES4335_RSVD_3 3 +#define RES4335_CBUCK_LPOM_PU 4 +#define RES4335_CBUCK_PFM_PU 5 +#define RES4335_RSVD_6 6 +#define RES4335_RSVD_7 7 +#define RES4335_LNLDO_PU 8 +#define RES4335_XTALLDO_PU 9 +#define RES4335_LDO3P3_PU 10 +#define RES4335_OTP_PU 11 +#define RES4335_XTAL_PU 12 +#define RES4335_SR_CLK_START 13 +#define RES4335_LQ_AVAIL 14 +#define RES4335_LQ_START 15 +#define RES4335_RSVD_16 16 +#define RES4335_WL_CORE_RDY 17 +#define RES4335_ILP_REQ 18 +#define RES4335_ALP_AVAIL 19 +#define RES4335_MINI_PMU 20 +#define RES4335_RADIO_PU 21 +#define RES4335_SR_CLK_STABLE 22 +#define RES4335_SR_SAVE_RESTORE 23 +#define RES4335_SR_PHY_PWRSW 24 +#define RES4335_SR_VDDM_PWRSW 25 +#define RES4335_SR_SUBCORE_PWRSW 26 +#define RES4335_SR_SLEEP 27 +#define RES4335_HT_START 28 +#define RES4335_HT_AVAIL 29 +#define RES4335_MACPHY_CLKAVAIL 30 + +/* 4335 Chip specific ChipStatus register bits */ +#define CST4335_SPROM_MASK 0x00000020 +#define CST4335_SFLASH_MASK 0x00000040 +#define CST4335_RES_INIT_MODE_SHIFT 7 +#define CST4335_RES_INIT_MODE_MASK 0x00000180 +#define CST4335_CHIPMODE_MASK 0xF +#define CST4335_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ +#define CST4335_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ +#define CST4335_CHIPMODE_USB20D(cs) (((cs) & (1 << 2)) != 0) /* HSIC || USBDA */ +#define CST4335_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ + +/* 4335 Chip specific ChipControl1 register bits */ +#define CCTRL1_4335_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ +#define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ + +/* 4335 Chip specific ChipControl2 register bits */ +#define CCTRL2_4335_AOSBLOCK (1 << 30) +#define CCTRL2_4335_PMUWAKE (1 << 31) +#define PATCHTBL_SIZE (0x800) +#define CR4_4335_RAM_BASE (0x180000) +#define CR4_4345_RAM_BASE (0x1b0000) +#define CR4_4349_RAM_BASE (0x180000) +#define CR4_4350_RAM_BASE (0x180000) +#define CR4_4360_RAM_BASE (0x0) +#define CR4_43602_RAM_BASE (0x180000) + +/* 4335 chip OTP present & OTP select bits. */ +#define SPROM4335_OTP_SELECT 0x00000010 +#define SPROM4335_OTP_PRESENT 0x00000020 + +/* 4335 GCI specific bits. */ +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 +#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 + +/* SFLASH clkdev specific bits. */ +#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 +#define CC4335_SFLASH_CLKDIV_SHIFT 25 + +/* 4335 OTP bits for SFLASH. */ +#define CC4335_SROM_OTP_SFLASH 40 +#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 +#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 +#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C +#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 + + +/* 4335 chip OTP present & OTP select bits. */ +#define SPROM4335_OTP_SELECT 0x00000010 +#define SPROM4335_OTP_PRESENT 0x00000020 + +/* 4335 GCI specific bits. */ +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 +#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 + +/* SFLASH clkdev specific bits. */ +#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 +#define CC4335_SFLASH_CLKDIV_SHIFT 25 + +/* 4335 OTP bits for SFLASH. */ +#define CC4335_SROM_OTP_SFLASH 40 +#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 +#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 +#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C +#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 + +/* 4335 resources--END */ + +/* 4345 Chip specific ChipStatus register bits */ +#define CST4345_SPROM_MASK 0x00000020 +#define CST4345_SFLASH_MASK 0x00000040 +#define CST4345_RES_INIT_MODE_SHIFT 7 +#define CST4345_RES_INIT_MODE_MASK 0x00000180 +#define CST4345_CHIPMODE_MASK 0x4000F +#define CST4345_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ +#define CST4345_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ +#define CST4345_CHIPMODE_HSIC(cs) (((cs) & (1 << 2)) != 0) /* HSIC */ +#define CST4345_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ +#define CST4345_CHIPMODE_USB20D(cs) (((cs) & (1 << 18)) != 0) /* USBDA */ + +/* 4350 Chipcommon ChipStatus bits */ +#define CST4350_SDIO_MODE 0x00000001 +#define CST4350_HSIC20D_MODE 0x00000002 +#define CST4350_BP_ON_HSIC_CLK 0x00000004 +#define CST4350_PCIE_MODE 0x00000008 +#define CST4350_USB20D_MODE 0x00000010 +#define CST4350_USB30D_MODE 0x00000020 +#define CST4350_SPROM_PRESENT 0x00000040 +#define CST4350_RSRC_INIT_MODE_0 0x00000080 +#define CST4350_RSRC_INIT_MODE_1 0x00000100 +#define CST4350_SEL0_SDIO 0x00000200 +#define CST4350_SEL1_SDIO 0x00000400 +#define CST4350_SDIO_PAD_MODE 0x00000800 +#define CST4350_BBPLL_LOCKED 0x00001000 +#define CST4350_USBPLL_LOCKED 0x00002000 +#define CST4350_LINE_STATE 0x0000C000 +#define CST4350_SERDES_PIPE_PLLLOCK 0x00010000 +#define CST4350_BT_READY 0x00020000 +#define CST4350_SFLASH_PRESENT 0x00040000 +#define CST4350_CPULESS_ENABLE 0x00080000 +#define CST4350_STRAP_HOST_IFC_1 0x00100000 +#define CST4350_STRAP_HOST_IFC_2 0x00200000 +#define CST4350_STRAP_HOST_IFC_3 0x00400000 +#define CST4350_RAW_SPROM_PRESENT 0x00800000 +#define CST4350_APP_CLK_SWITCH_SEL_RDBACK 0x01000000 +#define CST4350_RAW_RSRC_INIT_MODE_0 0x02000000 +#define CST4350_SDIO_PAD_VDDIO 0x04000000 +#define CST4350_GSPI_MODE 0x08000000 +#define CST4350_PACKAGE_OPTION 0xF0000000 +#define CST4350_PACKAGE_SHIFT 28 + +/* package option for 4350 */ +#define CST4350_PACKAGE_WLCSP 0x0 +#define CST4350_PACKAGE_PCIE 0x1 +#define CST4350_PACKAGE_WLBGA 0x2 +#define CST4350_PACKAGE_DBG 0x3 +#define CST4350_PACKAGE_USB 0x4 +#define CST4350_PACKAGE_USB_HSIC 0x4 + +#define CST4350_PKG_MODE(cs) ((cs & CST4350_PACKAGE_OPTION) >> CST4350_PACKAGE_SHIFT) + +#define CST4350_PKG_WLCSP(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLCSP)) +#define CST4350_PKG_PCIE(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_PCIE)) +#define CST4350_PKG_WLBGA(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLBGA)) +#define CST4350_PKG_USB(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB)) +#define CST4350_PKG_USB_HSIC(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB_HSIC)) + +/* 4350C0 USB PACKAGE using raw_sprom_present to indicate 40mHz xtal */ +#define CST4350_PKG_USB_40M(cs) (cs & CST4350_RAW_SPROM_PRESENT) + +#define CST4350_CHIPMODE_SDIOD(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_SDIOD)) +#define CST4350_CHIPMODE_USB20D(cs) ((CST4350_IFC_MODE(cs)) == (CST4350_IFC_MODE_USB20D)) +#define CST4350_CHIPMODE_HSIC20D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC20D)) +#define CST4350_CHIPMODE_HSIC30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC30D)) +#define CST4350_CHIPMODE_USB30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D)) +#define CST4350_CHIPMODE_USB30D_WL(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D_WL)) +#define CST4350_CHIPMODE_PCIE(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_PCIE)) + +/* strap_host_ifc strap value */ +#define CST4350_HOST_IFC_MASK 0x00700000 +#define CST4350_HOST_IFC_SHIFT 20 + +/* host_ifc raw mode */ +#define CST4350_IFC_MODE_SDIOD 0x0 +#define CST4350_IFC_MODE_HSIC20D 0x1 +#define CST4350_IFC_MODE_HSIC30D 0x2 +#define CST4350_IFC_MODE_PCIE 0x3 +#define CST4350_IFC_MODE_USB20D 0x4 +#define CST4350_IFC_MODE_USB30D 0x5 +#define CST4350_IFC_MODE_USB30D_WL 0x6 +#define CST4350_IFC_MODE_USB30D_BT 0x7 + +#define CST4350_IFC_MODE(cs) ((cs & CST4350_HOST_IFC_MASK) >> CST4350_HOST_IFC_SHIFT) + +/* 4350 PMU resources */ +#define RES4350_LPLDO_PU 0 +#define RES4350_PMU_BG_PU 1 +#define RES4350_PMU_SLEEP 2 +#define RES4350_RSVD_3 3 +#define RES4350_CBUCK_LPOM_PU 4 +#define RES4350_CBUCK_PFM_PU 5 +#define RES4350_COLD_START_WAIT 6 +#define RES4350_RSVD_7 7 +#define RES4350_LNLDO_PU 8 +#define RES4350_XTALLDO_PU 9 +#define RES4350_LDO3P3_PU 10 +#define RES4350_OTP_PU 11 +#define RES4350_XTAL_PU 12 +#define RES4350_SR_CLK_START 13 +#define RES4350_LQ_AVAIL 14 +#define RES4350_LQ_START 15 +#define RES4350_PERST_OVR 16 +#define RES4350_WL_CORE_RDY 17 +#define RES4350_ILP_REQ 18 +#define RES4350_ALP_AVAIL 19 +#define RES4350_MINI_PMU 20 +#define RES4350_RADIO_PU 21 +#define RES4350_SR_CLK_STABLE 22 +#define RES4350_SR_SAVE_RESTORE 23 +#define RES4350_SR_PHY_PWRSW 24 +#define RES4350_SR_VDDM_PWRSW 25 +#define RES4350_SR_SUBCORE_PWRSW 26 +#define RES4350_SR_SLEEP 27 +#define RES4350_HT_START 28 +#define RES4350_HT_AVAIL 29 +#define RES4350_MACPHY_CLKAVAIL 30 + +#define MUXENAB4350_UART_MASK (0x0000000f) +#define MUXENAB4350_UART_SHIFT 0 +#define MUXENAB4350_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ +#define MUXENAB4350_HOSTWAKE_SHIFT 4 + + +/* 4350 GCI function sel values */ +#define CC4350_FNSEL_HWDEF (0) +#define CC4350_FNSEL_SAMEASPIN (1) +#define CC4350_FNSEL_UART (2) +#define CC4350_FNSEL_SFLASH (3) +#define CC4350_FNSEL_SPROM (4) +#define CC4350_FNSEL_I2C (5) +#define CC4350_FNSEL_MISC0 (6) +#define CC4350_FNSEL_GCI (7) +#define CC4350_FNSEL_MISC1 (8) +#define CC4350_FNSEL_MISC2 (9) +#define CC4350_FNSEL_PWDOG (10) +#define CC4350_FNSEL_IND (12) +#define CC4350_FNSEL_PDN (13) +#define CC4350_FNSEL_PUP (14) +#define CC4350_FNSEL_TRISTATE (15) +#define CC4350C_FNSEL_UART (3) + + +/* 4350 GPIO */ +#define CC4350_PIN_GPIO_00 (0) +#define CC4350_PIN_GPIO_01 (1) +#define CC4350_PIN_GPIO_02 (2) +#define CC4350_PIN_GPIO_03 (3) +#define CC4350_PIN_GPIO_04 (4) +#define CC4350_PIN_GPIO_05 (5) +#define CC4350_PIN_GPIO_06 (6) +#define CC4350_PIN_GPIO_07 (7) +#define CC4350_PIN_GPIO_08 (8) +#define CC4350_PIN_GPIO_09 (9) +#define CC4350_PIN_GPIO_10 (10) +#define CC4350_PIN_GPIO_11 (11) +#define CC4350_PIN_GPIO_12 (12) +#define CC4350_PIN_GPIO_13 (13) +#define CC4350_PIN_GPIO_14 (14) +#define CC4350_PIN_GPIO_15 (15) + +#define CC4350_RSVD_16_SHIFT 16 + +#define CC2_4350_PHY_PWRSW_UPTIME_MASK (0xf << 0) +#define CC2_4350_PHY_PWRSW_UPTIME_SHIFT (0) +#define CC2_4350_VDDM_PWRSW_UPDELAY_MASK (0xf << 4) +#define CC2_4350_VDDM_PWRSW_UPDELAY_SHIFT (4) +#define CC2_4350_VDDM_PWRSW_UPTIME_MASK (0xf << 8) +#define CC2_4350_VDDM_PWRSW_UPTIME_SHIFT (8) +#define CC2_4350_SBC_PWRSW_DNDELAY_MASK (0x3 << 12) +#define CC2_4350_SBC_PWRSW_DNDELAY_SHIFT (12) +#define CC2_4350_PHY_PWRSW_DNDELAY_MASK (0x3 << 14) +#define CC2_4350_PHY_PWRSW_DNDELAY_SHIFT (14) +#define CC2_4350_VDDM_PWRSW_DNDELAY_MASK (0x3 << 16) +#define CC2_4350_VDDM_PWRSW_DNDELAY_SHIFT (16) +#define CC2_4350_VDDM_PWRSW_EN_MASK (1 << 20) +#define CC2_4350_VDDM_PWRSW_EN_SHIFT (20) +#define CC2_4350_MEMLPLDO_PWRSW_EN_MASK (1 << 21) +#define CC2_4350_MEMLPLDO_PWRSW_EN_SHIFT (21) +#define CC2_4350_SDIO_AOS_WAKEUP_MASK (1 << 24) +#define CC2_4350_SDIO_AOS_WAKEUP_SHIFT (24) + +/* Applies to 4335/4350/4345 */ +#define CC3_SR_CLK_SR_MEM_MASK (1 << 0) +#define CC3_SR_CLK_SR_MEM_SHIFT (0) +#define CC3_SR_BIT1_TBD_MASK (1 << 1) +#define CC3_SR_BIT1_TBD_SHIFT (1) +#define CC3_SR_ENGINE_ENABLE_MASK (1 << 2) +#define CC3_SR_ENGINE_ENABLE_SHIFT (2) +#define CC3_SR_BIT3_TBD_MASK (1 << 3) +#define CC3_SR_BIT3_TBD_SHIFT (3) +#define CC3_SR_MINDIV_FAST_CLK_MASK (0xF << 4) +#define CC3_SR_MINDIV_FAST_CLK_SHIFT (4) +#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_MASK (1 << 8) +#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_SHIFT (8) +#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_MASK (1 << 9) +#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_SHIFT (9) +#define CC3_SR_R23_SR_RISE_EDGE_TRIG_MASK (1 << 10) +#define CC3_SR_R23_SR_RISE_EDGE_TRIG_SHIFT (10) +#define CC3_SR_R23_SR_FALL_EDGE_TRIG_MASK (1 << 11) +#define CC3_SR_R23_SR_FALL_EDGE_TRIG_SHIFT (11) +#define CC3_SR_NUM_CLK_HIGH_MASK (0x7 << 12) +#define CC3_SR_NUM_CLK_HIGH_SHIFT (12) +#define CC3_SR_BIT15_TBD_MASK (1 << 15) +#define CC3_SR_BIT15_TBD_SHIFT (15) +#define CC3_SR_PHY_FUNC_PIC_MASK (1 << 16) +#define CC3_SR_PHY_FUNC_PIC_SHIFT (16) +#define CC3_SR_BIT17_19_TBD_MASK (0x7 << 17) +#define CC3_SR_BIT17_19_TBD_SHIFT (17) +#define CC3_SR_CHIP_TRIGGER_1_MASK (1 << 20) +#define CC3_SR_CHIP_TRIGGER_1_SHIFT (20) +#define CC3_SR_CHIP_TRIGGER_2_MASK (1 << 21) +#define CC3_SR_CHIP_TRIGGER_2_SHIFT (21) +#define CC3_SR_CHIP_TRIGGER_3_MASK (1 << 22) +#define CC3_SR_CHIP_TRIGGER_3_SHIFT (22) +#define CC3_SR_CHIP_TRIGGER_4_MASK (1 << 23) +#define CC3_SR_CHIP_TRIGGER_4_SHIFT (23) +#define CC3_SR_ALLOW_SBC_FUNC_PIC_MASK (1 << 24) +#define CC3_SR_ALLOW_SBC_FUNC_PIC_SHIFT (24) +#define CC3_SR_BIT25_26_TBD_MASK (0x3 << 25) +#define CC3_SR_BIT25_26_TBD_SHIFT (25) +#define CC3_SR_ALLOW_SBC_STBY_MASK (1 << 27) +#define CC3_SR_ALLOW_SBC_STBY_SHIFT (27) +#define CC3_SR_GPIO_MUX_MASK (0xF << 28) +#define CC3_SR_GPIO_MUX_SHIFT (28) + +/* Applies to 4335/4350/4345 */ +#define CC4_SR_INIT_ADDR_MASK (0x3FF0000) +#define CC4_4350_SR_ASM_ADDR (0x30) +#define CC4_4350_C0_SR_ASM_ADDR (0x0) +#define CC4_4335_SR_ASM_ADDR (0x48) +#define CC4_4345_SR_ASM_ADDR (0x48) +#define CC4_SR_INIT_ADDR_SHIFT (16) + +#define CC4_4350_EN_SR_CLK_ALP_MASK (1 << 30) +#define CC4_4350_EN_SR_CLK_ALP_SHIFT (30) +#define CC4_4350_EN_SR_CLK_HT_MASK (1 << 31) +#define CC4_4350_EN_SR_CLK_HT_SHIFT (31) + +#define VREG4_4350_MEMLPDO_PU_MASK (1 << 31) +#define VREG4_4350_MEMLPDO_PU_SHIFT 31 + +#define VREG6_4350_SR_EXT_CLKDIR_MASK (1 << 20) +#define VREG6_4350_SR_EXT_CLKDIR_SHIFT 20 +#define VREG6_4350_SR_EXT_CLKDIV_MASK (0x3 << 21) +#define VREG6_4350_SR_EXT_CLKDIV_SHIFT 21 +#define VREG6_4350_SR_EXT_CLKEN_MASK (1 << 23) +#define VREG6_4350_SR_EXT_CLKEN_SHIFT 23 + +#define CC5_4350_PMU_EN_ASSERT_MASK (1 << 13) +#define CC5_4350_PMU_EN_ASSERT_SHIFT (13) + +#define CC6_4350_PCIE_CLKREQ_WAKEUP_MASK (1 << 4) +#define CC6_4350_PCIE_CLKREQ_WAKEUP_SHIFT (4) +#define CC6_4350_PMU_WAKEUP_ALPAVAIL_MASK (1 << 6) +#define CC6_4350_PMU_WAKEUP_ALPAVAIL_SHIFT (6) +#define CC6_4350_PMU_EN_EXT_PERST_MASK (1 << 17) +#define CC6_4350_PMU_EN_EXT_PERST_SHIFT (17) +#define CC6_4350_PMU_EN_WAKEUP_MASK (1 << 18) +#define CC6_4350_PMU_EN_WAKEUP_SHIFT (18) + +#define CC7_4350_PMU_EN_ASSERT_L2_MASK (1 << 26) +#define CC7_4350_PMU_EN_ASSERT_L2_SHIFT (26) +#define CC7_4350_PMU_EN_MDIO_MASK (1 << 27) +#define CC7_4350_PMU_EN_MDIO_SHIFT (27) + +#define CC6_4345_PMU_EN_PERST_DEASSERT_MASK (1 << 13) +#define CC6_4345_PMU_EN_PERST_DEASSERT_SHIF (13) +#define CC6_4345_PMU_EN_L2_DEASSERT_MASK (1 << 14) +#define CC6_4345_PMU_EN_L2_DEASSERT_SHIF (14) +#define CC6_4345_PMU_EN_ASSERT_L2_MASK (1 << 15) +#define CC6_4345_PMU_EN_ASSERT_L2_SHIFT (15) +#define CC6_4345_PMU_EN_MDIO_MASK (1 << 24) +#define CC6_4345_PMU_EN_MDIO_SHIFT (24) + +/* GCI chipcontrol register indices */ +#define CC_GCI_CHIPCTRL_00 (0) +#define CC_GCI_CHIPCTRL_01 (1) +#define CC_GCI_CHIPCTRL_02 (2) +#define CC_GCI_CHIPCTRL_03 (3) +#define CC_GCI_CHIPCTRL_04 (4) +#define CC_GCI_CHIPCTRL_05 (5) +#define CC_GCI_CHIPCTRL_06 (6) +#define CC_GCI_CHIPCTRL_07 (7) +#define CC_GCI_CHIPCTRL_08 (8) +#define CC_GCI_XTAL_BUFSTRG_NFC (0xff << 12) + +#define CC_GCI_06_JTAG_SEL_SHIFT 4 +#define CC_GCI_06_JTAG_SEL_MASK (1 << 4) + +#define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) + +/* 4345 PMU resources */ +#define RES4345_LPLDO_PU 0 +#define RES4345_PMU_BG_PU 1 +#define RES4345_PMU_SLEEP 2 +#define RES4345_HSICLDO_PU 3 +#define RES4345_CBUCK_LPOM_PU 4 +#define RES4345_CBUCK_PFM_PU 5 +#define RES4345_COLD_START_WAIT 6 +#define RES4345_RSVD_7 7 +#define RES4345_LNLDO_PU 8 +#define RES4345_XTALLDO_PU 9 +#define RES4345_LDO3P3_PU 10 +#define RES4345_OTP_PU 11 +#define RES4345_XTAL_PU 12 +#define RES4345_SR_CLK_START 13 +#define RES4345_LQ_AVAIL 14 +#define RES4345_LQ_START 15 +#define RES4345_PERST_OVR 16 +#define RES4345_WL_CORE_RDY 17 +#define RES4345_ILP_REQ 18 +#define RES4345_ALP_AVAIL 19 +#define RES4345_MINI_PMU 20 +#define RES4345_RADIO_PU 21 +#define RES4345_SR_CLK_STABLE 22 +#define RES4345_SR_SAVE_RESTORE 23 +#define RES4345_SR_PHY_PWRSW 24 +#define RES4345_SR_VDDM_PWRSW 25 +#define RES4345_SR_SUBCORE_PWRSW 26 +#define RES4345_SR_SLEEP 27 +#define RES4345_HT_START 28 +#define RES4345_HT_AVAIL 29 +#define RES4345_MACPHY_CLK_AVAIL 30 + +/* 4335 pins +* note: only the values set as default/used are added here. +*/ +#define CC4335_PIN_GPIO_00 (0) +#define CC4335_PIN_GPIO_01 (1) +#define CC4335_PIN_GPIO_02 (2) +#define CC4335_PIN_GPIO_03 (3) +#define CC4335_PIN_GPIO_04 (4) +#define CC4335_PIN_GPIO_05 (5) +#define CC4335_PIN_GPIO_06 (6) +#define CC4335_PIN_GPIO_07 (7) +#define CC4335_PIN_GPIO_08 (8) +#define CC4335_PIN_GPIO_09 (9) +#define CC4335_PIN_GPIO_10 (10) +#define CC4335_PIN_GPIO_11 (11) +#define CC4335_PIN_GPIO_12 (12) +#define CC4335_PIN_GPIO_13 (13) +#define CC4335_PIN_GPIO_14 (14) +#define CC4335_PIN_GPIO_15 (15) +#define CC4335_PIN_SDIO_CLK (16) +#define CC4335_PIN_SDIO_CMD (17) +#define CC4335_PIN_SDIO_DATA0 (18) +#define CC4335_PIN_SDIO_DATA1 (19) +#define CC4335_PIN_SDIO_DATA2 (20) +#define CC4335_PIN_SDIO_DATA3 (21) +#define CC4335_PIN_RF_SW_CTRL_6 (22) +#define CC4335_PIN_RF_SW_CTRL_7 (23) +#define CC4335_PIN_RF_SW_CTRL_8 (24) +#define CC4335_PIN_RF_SW_CTRL_9 (25) +/* Last GPIO Pad */ +#define CC4335_PIN_GPIO_LAST (31) + +/* 4335 GCI function sel values +*/ +#define CC4335_FNSEL_HWDEF (0) +#define CC4335_FNSEL_SAMEASPIN (1) +#define CC4335_FNSEL_GPIO0 (2) +#define CC4335_FNSEL_GPIO1 (3) +#define CC4335_FNSEL_GCI0 (4) +#define CC4335_FNSEL_GCI1 (5) +#define CC4335_FNSEL_UART (6) +#define CC4335_FNSEL_SFLASH (7) +#define CC4335_FNSEL_SPROM (8) +#define CC4335_FNSEL_MISC0 (9) +#define CC4335_FNSEL_MISC1 (10) +#define CC4335_FNSEL_MISC2 (11) +#define CC4335_FNSEL_IND (12) +#define CC4335_FNSEL_PDN (13) +#define CC4335_FNSEL_PUP (14) +#define CC4335_FNSEL_TRI (15) + +/* GCI Core Control Reg */ +#define GCI_CORECTRL_SR_MASK (1 << 0) /* SECI block Reset */ +#define GCI_CORECTRL_RSL_MASK (1 << 1) /* ResetSECILogic */ +#define GCI_CORECTRL_ES_MASK (1 << 2) /* EnableSECI */ +#define GCI_CORECTRL_FSL_MASK (1 << 3) /* Force SECI Out Low */ +#define GCI_CORECTRL_SOM_MASK (7 << 4) /* SECI Op Mode */ +#define GCI_CORECTRL_US_MASK (1 << 7) /* Update SECI */ +#define GCI_CORECTRL_BOS_MASK (1 << 8) /* Break On Sleep */ + +/* 4345 pins +* note: only the values set as default/used are added here. +*/ +#define CC4345_PIN_GPIO_00 (0) +#define CC4345_PIN_GPIO_01 (1) +#define CC4345_PIN_GPIO_02 (2) +#define CC4345_PIN_GPIO_03 (3) +#define CC4345_PIN_GPIO_04 (4) +#define CC4345_PIN_GPIO_05 (5) +#define CC4345_PIN_GPIO_06 (6) +#define CC4345_PIN_GPIO_07 (7) +#define CC4345_PIN_GPIO_08 (8) +#define CC4345_PIN_GPIO_09 (9) +#define CC4345_PIN_GPIO_10 (10) +#define CC4345_PIN_GPIO_11 (11) +#define CC4345_PIN_GPIO_12 (12) +#define CC4345_PIN_GPIO_13 (13) +#define CC4345_PIN_GPIO_14 (14) +#define CC4345_PIN_GPIO_15 (15) +#define CC4345_PIN_GPIO_16 (16) +#define CC4345_PIN_SDIO_CLK (17) +#define CC4345_PIN_SDIO_CMD (18) +#define CC4345_PIN_SDIO_DATA0 (19) +#define CC4345_PIN_SDIO_DATA1 (20) +#define CC4345_PIN_SDIO_DATA2 (21) +#define CC4345_PIN_SDIO_DATA3 (22) +#define CC4345_PIN_RF_SW_CTRL_0 (23) +#define CC4345_PIN_RF_SW_CTRL_1 (24) +#define CC4345_PIN_RF_SW_CTRL_2 (25) +#define CC4345_PIN_RF_SW_CTRL_3 (26) +#define CC4345_PIN_RF_SW_CTRL_4 (27) +#define CC4345_PIN_RF_SW_CTRL_5 (28) +#define CC4345_PIN_RF_SW_CTRL_6 (29) +#define CC4345_PIN_RF_SW_CTRL_7 (30) +#define CC4345_PIN_RF_SW_CTRL_8 (31) +#define CC4345_PIN_RF_SW_CTRL_9 (32) + +/* 4345 GCI function sel values +*/ +#define CC4345_FNSEL_HWDEF (0) +#define CC4345_FNSEL_SAMEASPIN (1) +#define CC4345_FNSEL_GPIO0 (2) +#define CC4345_FNSEL_GPIO1 (3) +#define CC4345_FNSEL_GCI0 (4) +#define CC4345_FNSEL_GCI1 (5) +#define CC4345_FNSEL_UART (6) +#define CC4345_FNSEL_SFLASH (7) +#define CC4345_FNSEL_SPROM (8) +#define CC4345_FNSEL_MISC0 (9) +#define CC4345_FNSEL_MISC1 (10) +#define CC4345_FNSEL_MISC2 (11) +#define CC4345_FNSEL_IND (12) +#define CC4345_FNSEL_PDN (13) +#define CC4345_FNSEL_PUP (14) +#define CC4345_FNSEL_TRI (15) + +#define MUXENAB4345_UART_MASK (0x0000000f) +#define MUXENAB4345_UART_SHIFT 0 +#define MUXENAB4345_HOSTWAKE_MASK (0x000000f0) +#define MUXENAB4345_HOSTWAKE_SHIFT 4 + +/* 4349 Group (4349, 4355, 4359) GCI AVS function sel values */ +#define CC4349_GRP_GCI_AVS_CTRL_MASK (0xffe00000) +#define CC4349_GRP_GCI_AVS_CTRL_SHIFT (21) +#define CC4349_GRP_GCI_AVS_CTRL_ENAB (1 << 5) + +/* 4345 GCI AVS function sel values */ +#define CC4345_GCI_AVS_CTRL_MASK (0xfc) +#define CC4345_GCI_AVS_CTRL_SHIFT (2) +#define CC4345_GCI_AVS_CTRL_ENAB (1 << 5) + +/* GCI GPIO for function sel GCI-0/GCI-1 */ +#define CC_GCI_GPIO_0 (0) +#define CC_GCI_GPIO_1 (1) +#define CC_GCI_GPIO_2 (2) +#define CC_GCI_GPIO_3 (3) +#define CC_GCI_GPIO_4 (4) +#define CC_GCI_GPIO_5 (5) +#define CC_GCI_GPIO_6 (6) +#define CC_GCI_GPIO_7 (7) +#define CC_GCI_GPIO_8 (8) +#define CC_GCI_GPIO_9 (9) +#define CC_GCI_GPIO_10 (10) +#define CC_GCI_GPIO_11 (11) +#define CC_GCI_GPIO_12 (12) +#define CC_GCI_GPIO_13 (13) +#define CC_GCI_GPIO_14 (14) +#define CC_GCI_GPIO_15 (15) + + +/* indicates Invalid GPIO, e.g. when PAD GPIO doesn't map to GCI GPIO */ +#define CC_GCI_GPIO_INVALID 0xFF + +/* find the 4 bit mask given the bit position */ +#define GCIMASK(pos) (((uint32)0xF) << pos) +/* get the value which can be used to directly OR with chipcontrol reg */ +#define GCIPOSVAL(val, pos) ((((uint32)val) << pos) & GCIMASK(pos)) +/* Extract nibble from a given position */ +#define GCIGETNBL(val, pos) ((val >> pos) & 0xF) + + +/* find the 8 bit mask given the bit position */ +#define GCIMASK_8B(pos) (((uint32)0xFF) << pos) +/* get the value which can be used to directly OR with chipcontrol reg */ +#define GCIPOSVAL_8B(val, pos) ((((uint32)val) << pos) & GCIMASK_8B(pos)) +/* Extract nibble from a given position */ +#define GCIGETNBL_8B(val, pos) ((val >> pos) & 0xFF) + +/* find the 4 bit mask given the bit position */ +#define GCIMASK_4B(pos) (((uint32)0xF) << pos) +/* get the value which can be used to directly OR with chipcontrol reg */ +#define GCIPOSVAL_4B(val, pos) ((((uint32)val) << pos) & GCIMASK_4B(pos)) +/* Extract nibble from a given position */ +#define GCIGETNBL_4B(val, pos) ((val >> pos) & 0xF) + + +/* 4335 GCI Intstatus(Mask)/WakeMask Register bits. */ +#define GCI_INTSTATUS_RBI (1 << 0) /* Rx Break Interrupt */ +#define GCI_INTSTATUS_UB (1 << 1) /* UART Break Interrupt */ +#define GCI_INTSTATUS_SPE (1 << 2) /* SECI Parity Error Interrupt */ +#define GCI_INTSTATUS_SFE (1 << 3) /* SECI Framing Error Interrupt */ +#define GCI_INTSTATUS_SRITI (1 << 9) /* SECI Rx Idle Timer Interrupt */ +#define GCI_INTSTATUS_STFF (1 << 10) /* SECI Tx FIFO Full Interrupt */ +#define GCI_INTSTATUS_STFAE (1 << 11) /* SECI Tx FIFO Almost Empty Intr */ +#define GCI_INTSTATUS_SRFAF (1 << 12) /* SECI Rx FIFO Almost Full */ +#define GCI_INTSTATUS_SRFNE (1 << 14) /* SECI Rx FIFO Not Empty */ +#define GCI_INTSTATUS_SRFOF (1 << 15) /* SECI Rx FIFO Not Empty Timeout */ +#define GCI_INTSTATUS_GPIOINT (1 << 25) /* GCIGpioInt */ +#define GCI_INTSTATUS_GPIOWAKE (1 << 26) /* GCIGpioWake */ + +/* 4335 GCI IntMask Register bits. */ +#define GCI_INTMASK_RBI (1 << 0) /* Rx Break Interrupt */ +#define GCI_INTMASK_UB (1 << 1) /* UART Break Interrupt */ +#define GCI_INTMASK_SPE (1 << 2) /* SECI Parity Error Interrupt */ +#define GCI_INTMASK_SFE (1 << 3) /* SECI Framing Error Interrupt */ +#define GCI_INTMASK_SRITI (1 << 9) /* SECI Rx Idle Timer Interrupt */ +#define GCI_INTMASK_STFF (1 << 10) /* SECI Tx FIFO Full Interrupt */ +#define GCI_INTMASK_STFAE (1 << 11) /* SECI Tx FIFO Almost Empty Intr */ +#define GCI_INTMASK_SRFAF (1 << 12) /* SECI Rx FIFO Almost Full */ +#define GCI_INTMASK_SRFNE (1 << 14) /* SECI Rx FIFO Not Empty */ +#define GCI_INTMASK_SRFOF (1 << 15) /* SECI Rx FIFO Not Empty Timeout */ +#define GCI_INTMASK_GPIOINT (1 << 25) /* GCIGpioInt */ +#define GCI_INTMASK_GPIOWAKE (1 << 26) /* GCIGpioWake */ + +/* 4335 GCI WakeMask Register bits. */ +#define GCI_WAKEMASK_RBI (1 << 0) /* Rx Break Interrupt */ +#define GCI_WAKEMASK_UB (1 << 1) /* UART Break Interrupt */ +#define GCI_WAKEMASK_SPE (1 << 2) /* SECI Parity Error Interrupt */ +#define GCI_WAKEMASK_SFE (1 << 3) /* SECI Framing Error Interrupt */ +#define GCI_WAKE_SRITI (1 << 9) /* SECI Rx Idle Timer Interrupt */ +#define GCI_WAKEMASK_STFF (1 << 10) /* SECI Tx FIFO Full Interrupt */ +#define GCI_WAKEMASK_STFAE (1 << 11) /* SECI Tx FIFO Almost Empty Intr */ +#define GCI_WAKEMASK_SRFAF (1 << 12) /* SECI Rx FIFO Almost Full */ +#define GCI_WAKEMASK_SRFNE (1 << 14) /* SECI Rx FIFO Not Empty */ +#define GCI_WAKEMASK_SRFOF (1 << 15) /* SECI Rx FIFO Not Empty Timeout */ +#define GCI_WAKEMASK_GPIOINT (1 << 25) /* GCIGpioInt */ +#define GCI_WAKEMASK_GPIOWAKE (1 << 26) /* GCIGpioWake */ + +#define GCI_WAKE_ON_GCI_GPIO1 1 +#define GCI_WAKE_ON_GCI_GPIO2 2 +#define GCI_WAKE_ON_GCI_GPIO3 3 +#define GCI_WAKE_ON_GCI_GPIO4 4 +#define GCI_WAKE_ON_GCI_GPIO5 5 +#define GCI_WAKE_ON_GCI_GPIO6 6 +#define GCI_WAKE_ON_GCI_GPIO7 7 +#define GCI_WAKE_ON_GCI_GPIO8 8 +#define GCI_WAKE_ON_GCI_SECI_IN 9 + +/* 4335 MUX options. each nibble belongs to a setting. Non-zero value specifies a logic +* for now only UART for bootloader. +*/ +#define MUXENAB4335_UART_MASK (0x0000000f) + +#define MUXENAB4335_UART_SHIFT 0 +#define MUXENAB4335_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ +#define MUXENAB4335_HOSTWAKE_SHIFT 4 +#define MUXENAB4335_GETIX(val, name) \ + ((((val) & MUXENAB4335_ ## name ## _MASK) >> MUXENAB4335_ ## name ## _SHIFT) - 1) + +/* +* Maximum delay for the PMU state transition in us. +* This is an upper bound intended for spinwaits etc. +*/ +#define PMU_MAX_TRANSITION_DLY 15000 + +/* PMU resource up transition time in ILP cycles */ +#define PMURES_UP_TRANSITION 2 + + +/* SECI configuration */ +#define SECI_MODE_UART 0x0 +#define SECI_MODE_SECI 0x1 +#define SECI_MODE_LEGACY_3WIRE_BT 0x2 +#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3 +#define SECI_MODE_HALF_SECI 0x4 + +#define SECI_RESET (1 << 0) +#define SECI_RESET_BAR_UART (1 << 1) +#define SECI_ENAB_SECI_ECI (1 << 2) +#define SECI_ENAB_SECIOUT_DIS (1 << 3) +#define SECI_MODE_MASK 0x7 +#define SECI_MODE_SHIFT 4 /* (bits 5, 6, 7) */ +#define SECI_UPD_SECI (1 << 7) + +#define SECI_SLIP_ESC_CHAR 0xDB +#define SECI_SIGNOFF_0 SECI_SLIP_ESC_CHAR +#define SECI_SIGNOFF_1 0 +#define SECI_REFRESH_REQ 0xDA + +/* seci clk_ctl_st bits */ +#define CLKCTL_STS_SECI_CLK_REQ (1 << 8) +#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24) + +#define SECI_UART_MSR_CTS_STATE (1 << 0) +#define SECI_UART_MSR_RTS_STATE (1 << 1) +#define SECI_UART_SECI_IN_STATE (1 << 2) +#define SECI_UART_SECI_IN2_STATE (1 << 3) + +/* GCI RX FIFO Control Register */ +#define GCI_RXF_LVL_MASK (0xFF << 0) +#define GCI_RXF_TIMEOUT_MASK (0xFF << 8) + +/* GCI UART Registers' Bit definitions */ +/* Seci Fifo Level Register */ +#define SECI_TXF_LVL_MASK (0x3F << 8) +#define TXF_AE_LVL_DEFAULT 0x4 +#define SECI_RXF_LVL_FC_MASK (0x3F << 16) + +/* SeciUARTFCR Bit definitions */ +#define SECI_UART_FCR_RFR (1 << 0) +#define SECI_UART_FCR_TFR (1 << 1) +#define SECI_UART_FCR_SR (1 << 2) +#define SECI_UART_FCR_THP (1 << 3) +#define SECI_UART_FCR_AB (1 << 4) +#define SECI_UART_FCR_ATOE (1 << 5) +#define SECI_UART_FCR_ARTSOE (1 << 6) +#define SECI_UART_FCR_ABV (1 << 7) +#define SECI_UART_FCR_ALM (1 << 8) + +/* SECI UART LCR register bits */ +#define SECI_UART_LCR_STOP_BITS (1 << 0) /* 0 - 1bit, 1 - 2bits */ +#define SECI_UART_LCR_PARITY_EN (1 << 1) +#define SECI_UART_LCR_PARITY (1 << 2) /* 0 - odd, 1 - even */ +#define SECI_UART_LCR_RX_EN (1 << 3) +#define SECI_UART_LCR_LBRK_CTRL (1 << 4) /* 1 => SECI_OUT held low */ +#define SECI_UART_LCR_TXO_EN (1 << 5) +#define SECI_UART_LCR_RTSO_EN (1 << 6) +#define SECI_UART_LCR_SLIPMODE_EN (1 << 7) +#define SECI_UART_LCR_RXCRC_CHK (1 << 8) +#define SECI_UART_LCR_TXCRC_INV (1 << 9) +#define SECI_UART_LCR_TXCRC_LSBF (1 << 10) +#define SECI_UART_LCR_TXCRC_EN (1 << 11) +#define SECI_UART_LCR_RXSYNC_EN (1 << 12) + +#define SECI_UART_MCR_TX_EN (1 << 0) +#define SECI_UART_MCR_PRTS (1 << 1) +#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2) +#define SECI_UART_MCR_HIGHRATE_EN (1 << 3) +#define SECI_UART_MCR_LOOPBK_EN (1 << 4) +#define SECI_UART_MCR_AUTO_RTS (1 << 5) +#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6) +#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7) +#define SECI_UART_MCR_XONOFF_RPT (1 << 9) + +/* SeciUARTLSR Bit Mask */ +#define SECI_UART_LSR_RXOVR_MASK (1 << 0) +#define SECI_UART_LSR_RFF_MASK (1 << 1) +#define SECI_UART_LSR_TFNE_MASK (1 << 2) +#define SECI_UART_LSR_TI_MASK (1 << 3) +#define SECI_UART_LSR_TPR_MASK (1 << 4) +#define SECI_UART_LSR_TXHALT_MASK (1 << 5) + +/* SeciUARTMSR Bit Mask */ +#define SECI_UART_MSR_CTSS_MASK (1 << 0) +#define SECI_UART_MSR_RTSS_MASK (1 << 1) +#define SECI_UART_MSR_SIS_MASK (1 << 2) +#define SECI_UART_MSR_SIS2_MASK (1 << 3) + +/* SeciUARTData Bits */ +#define SECI_UART_DATA_RF_NOT_EMPTY_BIT (1 << 12) +#define SECI_UART_DATA_RF_FULL_BIT (1 << 13) +#define SECI_UART_DATA_RF_OVRFLOW_BIT (1 << 14) +#define SECI_UART_DATA_FIFO_PTR_MASK 0xFF +#define SECI_UART_DATA_RF_RD_PTR_SHIFT 16 +#define SECI_UART_DATA_RF_WR_PTR_SHIFT 24 + +/* LTECX: ltecxmux */ +#define LTECX_EXTRACT_MUX(val, idx) (getbit4(&(val), (idx))) + +/* LTECX: ltecxmux MODE */ +#define LTECX_MUX_MODE_IDX 0 +#define LTECX_MUX_MODE_WCI2 0x0 +#define LTECX_MUX_MODE_GPIO 0x1 + + +/* LTECX GPIO Information Index */ +#define LTECX_NVRAM_FSYNC_IDX 0 +#define LTECX_NVRAM_LTERX_IDX 1 +#define LTECX_NVRAM_LTETX_IDX 2 +#define LTECX_NVRAM_WLPRIO_IDX 3 + +/* LTECX WCI2 Information Index */ +#define LTECX_NVRAM_WCI2IN_IDX 0 +#define LTECX_NVRAM_WCI2OUT_IDX 1 + +/* LTECX: Macros to get GPIO/FNSEL/GCIGPIO */ +#define LTECX_EXTRACT_PADNUM(val, idx) (getbit8(&(val), (idx))) +#define LTECX_EXTRACT_FNSEL(val, idx) (getbit4(&(val), (idx))) +#define LTECX_EXTRACT_GCIGPIO(val, idx) (getbit4(&(val), (idx))) + +/* WLAN channel numbers - used from wifi.h */ + +/* WLAN BW */ +#define ECI_BW_20 0x0 +#define ECI_BW_25 0x1 +#define ECI_BW_30 0x2 +#define ECI_BW_35 0x3 +#define ECI_BW_40 0x4 +#define ECI_BW_45 0x5 +#define ECI_BW_50 0x6 +#define ECI_BW_ALL 0x7 + +/* WLAN - number of antenna */ +#define WLAN_NUM_ANT1 TXANT_0 +#define WLAN_NUM_ANT2 TXANT_1 + +/* otpctrl1 0xF4 */ +#define OTPC_FORCE_PWR_OFF 0x02000000 +/* chipcommon s/r registers introduced with cc rev >= 48 */ +#define CC_SR_CTL0_ENABLE_MASK 0x1 +#define CC_SR_CTL0_ENABLE_SHIFT 0 +#define CC_SR_CTL0_EN_SR_ENG_CLK_SHIFT 1 /* sr_clk to sr_memory enable */ +#define CC_SR_CTL0_RSRC_TRIGGER_SHIFT 2 /* Rising edge resource trigger 0 to sr_engine */ +#define CC_SR_CTL0_MIN_DIV_SHIFT 6 /* Min division value for fast clk in sr_engine */ +#define CC_SR_CTL0_EN_SBC_STBY_SHIFT 16 /* Allow Subcore mem StandBy? */ +#define CC_SR_CTL0_EN_SR_ALP_CLK_MASK_SHIFT 18 +#define CC_SR_CTL0_EN_SR_HT_CLK_SHIFT 19 +#define CC_SR_CTL0_ALLOW_PIC_SHIFT 20 /* Allow pic to separate power domains */ +#define CC_SR_CTL0_MAX_SR_LQ_CLK_CNT_SHIFT 25 +#define CC_SR_CTL0_EN_MEM_DISABLE_FOR_SLEEP 30 + +#define CC_SR_CTL1_SR_INIT_MASK 0x3FF +#define CC_SR_CTL1_SR_INIT_SHIFT 0 + +#define ECI_INLO_PKTDUR_MASK 0x000000f0 /* [7:4] - 4 bits */ +#define ECI_INLO_PKTDUR_SHIFT 4 + +/* gci chip control bits */ +#define GCI_GPIO_CHIPCTRL_ENAB_IN_BIT 0 +#define GCI_GPIO_CHIPCTRL_ENAB_OP_BIT 1 +#define GCI_GPIO_CHIPCTRL_INVERT_BIT 2 +#define GCI_GPIO_CHIPCTRL_PULLUP_BIT 3 +#define GCI_GPIO_CHIPCTRL_PULLDN_BIT 4 +#define GCI_GPIO_CHIPCTRL_ENAB_BTSIG_BIT 5 +#define GCI_GPIO_CHIPCTRL_ENAB_OD_OP_BIT 6 +#define GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT 7 + +/* gci GPIO input status bits */ +#define GCI_GPIO_STS_VALUE_BIT 0 +#define GCI_GPIO_STS_POS_EDGE_BIT 1 +#define GCI_GPIO_STS_NEG_EDGE_BIT 2 +#define GCI_GPIO_STS_FAST_EDGE_BIT 3 +#define GCI_GPIO_STS_CLEAR 0xF + +#define GCI_GPIO_STS_VALUE (1 << GCI_GPIO_STS_VALUE_BIT) + +#endif /* _SBCHIPC_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sbconfig.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbconfig.h new file mode 100644 index 000000000000..d2e60152abef --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sbconfig.h @@ -0,0 +1,282 @@ +/* + * Broadcom SiliconBackplane hardware register definitions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbconfig.h 456346 2014-02-18 16:48:52Z $ + */ + +#ifndef _SBCONFIG_H +#define _SBCONFIG_H + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif + +/* enumeration in SB is based on the premise that cores are contiguos in the + * enumeration space. + */ +#define SB_BUS_SIZE 0x10000 /* Each bus gets 64Kbytes for cores */ +#define SB_BUS_BASE(b) (SI_ENUM_BASE + (b) * SB_BUS_SIZE) +#define SB_BUS_MAXCORES (SB_BUS_SIZE / SI_CORE_SIZE) /* Max cores per bus */ + +/* + * Sonics Configuration Space Registers. + */ +#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */ +#define SBCONFIGSIZE 256 /* sizeof (sbconfig_t) */ + +#define SBIPSFLAG 0x08 +#define SBTPSFLAG 0x18 +#define SBTMERRLOGA 0x48 /* sonics >= 2.3 */ +#define SBTMERRLOG 0x50 /* sonics >= 2.3 */ +#define SBADMATCH3 0x60 +#define SBADMATCH2 0x68 +#define SBADMATCH1 0x70 +#define SBIMSTATE 0x90 +#define SBINTVEC 0x94 +#define SBTMSTATELOW 0x98 +#define SBTMSTATEHIGH 0x9c +#define SBBWA0 0xa0 +#define SBIMCONFIGLOW 0xa8 +#define SBIMCONFIGHIGH 0xac +#define SBADMATCH0 0xb0 +#define SBTMCONFIGLOW 0xb8 +#define SBTMCONFIGHIGH 0xbc +#define SBBCONFIG 0xc0 +#define SBBSTATE 0xc8 +#define SBACTCNFG 0xd8 +#define SBFLAGST 0xe8 +#define SBIDLOW 0xf8 +#define SBIDHIGH 0xfc + +/* All the previous registers are above SBCONFIGOFF, but with Sonics 2.3, we have + * a few registers *below* that line. I think it would be very confusing to try + * and change the value of SBCONFIGOFF, so I'm definig them as absolute offsets here, + */ + +#define SBIMERRLOGA 0xea8 +#define SBIMERRLOG 0xeb0 +#define SBTMPORTCONNID0 0xed8 +#define SBTMPORTLOCK0 0xef8 + +#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) + +typedef volatile struct _sbconfig { + uint32 PAD[2]; + uint32 sbipsflag; /* initiator port ocp slave flag */ + uint32 PAD[3]; + uint32 sbtpsflag; /* target port ocp slave flag */ + uint32 PAD[11]; + uint32 sbtmerrloga; /* (sonics >= 2.3) */ + uint32 PAD; + uint32 sbtmerrlog; /* (sonics >= 2.3) */ + uint32 PAD[3]; + uint32 sbadmatch3; /* address match3 */ + uint32 PAD; + uint32 sbadmatch2; /* address match2 */ + uint32 PAD; + uint32 sbadmatch1; /* address match1 */ + uint32 PAD[7]; + uint32 sbimstate; /* initiator agent state */ + uint32 sbintvec; /* interrupt mask */ + uint32 sbtmstatelow; /* target state */ + uint32 sbtmstatehigh; /* target state */ + uint32 sbbwa0; /* bandwidth allocation table0 */ + uint32 PAD; + uint32 sbimconfiglow; /* initiator configuration */ + uint32 sbimconfighigh; /* initiator configuration */ + uint32 sbadmatch0; /* address match0 */ + uint32 PAD; + uint32 sbtmconfiglow; /* target configuration */ + uint32 sbtmconfighigh; /* target configuration */ + uint32 sbbconfig; /* broadcast configuration */ + uint32 PAD; + uint32 sbbstate; /* broadcast state */ + uint32 PAD[3]; + uint32 sbactcnfg; /* activate configuration */ + uint32 PAD[3]; + uint32 sbflagst; /* current sbflags */ + uint32 PAD[3]; + uint32 sbidlow; /* identification */ + uint32 sbidhigh; /* identification */ +} sbconfig_t; + +#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ + +/* sbipsflag */ +#define SBIPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */ +#define SBIPS_INT1_SHIFT 0 +#define SBIPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */ +#define SBIPS_INT2_SHIFT 8 +#define SBIPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */ +#define SBIPS_INT3_SHIFT 16 +#define SBIPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */ +#define SBIPS_INT4_SHIFT 24 + +/* sbtpsflag */ +#define SBTPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */ +#define SBTPS_F0EN0 0x40 /* interrupt is always sent on the backplane */ + +/* sbtmerrlog */ +#define SBTMEL_CM 0x00000007 /* command */ +#define SBTMEL_CI 0x0000ff00 /* connection id */ +#define SBTMEL_EC 0x0f000000 /* error code */ +#define SBTMEL_ME 0x80000000 /* multiple error */ + +/* sbimstate */ +#define SBIM_PC 0xf /* pipecount */ +#define SBIM_AP_MASK 0x30 /* arbitration policy */ +#define SBIM_AP_BOTH 0x00 /* use both timeslaces and token */ +#define SBIM_AP_TS 0x10 /* use timesliaces only */ +#define SBIM_AP_TK 0x20 /* use token only */ +#define SBIM_AP_RSV 0x30 /* reserved */ +#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 */ +#define SBTML_RESET 0x0001 /* reset */ +#define SBTML_REJ_MASK 0x0006 /* reject field */ +#define SBTML_REJ 0x0002 /* reject */ +#define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */ + +#define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */ + +/* sbtmstatehigh */ +#define SBTMH_SERR 0x0001 /* serror */ +#define SBTMH_INT 0x0002 /* interrupt */ +#define SBTMH_BUSY 0x0004 /* busy */ +#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ + +#define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */ + +/* sbbwa0 */ +#define SBBWA_TAB0_MASK 0xffff /* lookup table 0 */ +#define SBBWA_TAB1_MASK 0xffff /* lookup table 1 */ +#define SBBWA_TAB1_SHIFT 16 + +/* sbimconfiglow */ +#define SBIMCL_STO_MASK 0x7 /* service timeout */ +#define SBIMCL_RTO_MASK 0x70 /* request timeout */ +#define SBIMCL_RTO_SHIFT 4 +#define SBIMCL_CID_MASK 0xff0000 /* connection id */ +#define SBIMCL_CID_SHIFT 16 + +/* sbimconfighigh */ +#define SBIMCH_IEM_MASK 0xc /* inband error mode */ +#define SBIMCH_TEM_MASK 0x30 /* timeout error mode */ +#define SBIMCH_TEM_SHIFT 4 +#define SBIMCH_BEM_MASK 0xc0 /* bus error mode */ +#define SBIMCH_BEM_SHIFT 6 + +/* sbadmatch0 */ +#define SBAM_TYPE_MASK 0x3 /* address type */ +#define SBAM_AD64 0x4 /* reserved */ +#define SBAM_ADINT0_MASK 0xf8 /* type0 size */ +#define SBAM_ADINT0_SHIFT 3 +#define SBAM_ADINT1_MASK 0x1f8 /* type1 size */ +#define SBAM_ADINT1_SHIFT 3 +#define SBAM_ADINT2_MASK 0x1f8 /* type2 size */ +#define SBAM_ADINT2_SHIFT 3 +#define SBAM_ADEN 0x400 /* enable */ +#define SBAM_ADNEG 0x800 /* negative decode */ +#define SBAM_BASE0_MASK 0xffffff00 /* type0 base address */ +#define SBAM_BASE0_SHIFT 8 +#define SBAM_BASE1_MASK 0xfffff000 /* type1 base address for the core */ +#define SBAM_BASE1_SHIFT 12 +#define SBAM_BASE2_MASK 0xffff0000 /* type2 base address for the core */ +#define SBAM_BASE2_SHIFT 16 + +/* sbtmconfiglow */ +#define SBTMCL_CD_MASK 0xff /* clock divide */ +#define SBTMCL_CO_MASK 0xf800 /* clock offset */ +#define SBTMCL_CO_SHIFT 11 +#define SBTMCL_IF_MASK 0xfc0000 /* interrupt flags */ +#define SBTMCL_IF_SHIFT 18 +#define SBTMCL_IM_MASK 0x3000000 /* interrupt mode */ +#define SBTMCL_IM_SHIFT 24 + +/* sbtmconfighigh */ +#define SBTMCH_BM_MASK 0x3 /* busy mode */ +#define SBTMCH_RM_MASK 0x3 /* retry mode */ +#define SBTMCH_RM_SHIFT 2 +#define SBTMCH_SM_MASK 0x30 /* stop mode */ +#define SBTMCH_SM_SHIFT 4 +#define SBTMCH_EM_MASK 0x300 /* sb error mode */ +#define SBTMCH_EM_SHIFT 8 +#define SBTMCH_IM_MASK 0xc00 /* int mode */ +#define SBTMCH_IM_SHIFT 10 + +/* sbbconfig */ +#define SBBC_LAT_MASK 0x3 /* sb latency */ +#define SBBC_MAX0_MASK 0xf0000 /* maxccntr0 */ +#define SBBC_MAX0_SHIFT 16 +#define SBBC_MAX1_MASK 0xf00000 /* maxccntr1 */ +#define SBBC_MAX1_SHIFT 20 + +/* sbbstate */ +#define SBBS_SRD 0x1 /* st reg disable */ +#define SBBS_HRD 0x2 /* hold reg disable */ + +/* sbidlow */ +#define SBIDL_CS_MASK 0x3 /* config space */ +#define SBIDL_AR_MASK 0x38 /* # address ranges supported */ +#define SBIDL_AR_SHIFT 3 +#define SBIDL_SYNCH 0x40 /* sync */ +#define SBIDL_INIT 0x80 /* initiator */ +#define SBIDL_MINLAT_MASK 0xf00 /* minimum backplane latency */ +#define SBIDL_MINLAT_SHIFT 8 +#define SBIDL_MAXLAT 0xf000 /* maximum backplane latency */ +#define SBIDL_MAXLAT_SHIFT 12 +#define SBIDL_FIRST 0x10000 /* this initiator is first */ +#define SBIDL_CW_MASK 0xc0000 /* cycle counter width */ +#define SBIDL_CW_SHIFT 18 +#define SBIDL_TP_MASK 0xf00000 /* target ports */ +#define SBIDL_TP_SHIFT 20 +#define SBIDL_IP_MASK 0xf000000 /* initiator ports */ +#define SBIDL_IP_SHIFT 24 +#define SBIDL_RV_MASK 0xf0000000 /* sonics backplane revision code */ +#define SBIDL_RV_SHIFT 28 +#define SBIDL_RV_2_2 0x00000000 /* version 2.2 or earlier */ +#define SBIDL_RV_2_3 0x10000000 /* version 2.3 */ + +/* 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 + +#define SB_COMMIT 0xfd8 /* update buffered registers value */ + +/* vendor codes */ +#define SB_VEND_BCM 0x4243 /* Broadcom's SB vendor code */ + +#endif /* _SBCONFIG_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sbhnddma.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbhnddma.h new file mode 100644 index 000000000000..401fbbbd48dc --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sbhnddma.h @@ -0,0 +1,417 @@ +/* + * Generic Broadcom Home Networking Division (HND) DMA engine HW interface + * This supports the following chips: BCM42xx, 44xx, 47xx . + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbhnddma.h 452424 2014-01-30 09:43:39Z $ + */ + +#ifndef _sbhnddma_h_ +#define _sbhnddma_h_ + +/* 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 */ + +/* dma registers per channel(xmt or rcv) */ +typedef volatile struct { + uint32 control; /* enable, et al */ + uint32 addr; /* descriptor ring base address (4K aligned) */ + uint32 ptr; /* last descriptor posted to chip */ + uint32 status; /* current active descriptor, et al */ +} dma32regs_t; + +typedef volatile struct { + dma32regs_t xmt; /* dma tx channel */ + dma32regs_t rcv; /* dma rx channel */ +} dma32regp_t; + +typedef volatile struct { /* diag access */ + uint32 fifoaddr; /* diag address */ + uint32 fifodatalow; /* low 32bits of data */ + uint32 fifodatahigh; /* high 32bits of data */ + uint32 pad; /* reserved */ +} dma32diag_t; + +/* + * DMA Descriptor + * Descriptors are only read by the hardware, never written back. + */ +typedef volatile struct { + uint32 ctrl; /* misc control bits & bufcount */ + uint32 addr; /* data buffer address */ +} dma32dd_t; + +/* + * Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page. + */ +#define D32RINGALIGN_BITS 12 +#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS) +#define D32RINGALIGN (1 << D32RINGALIGN_BITS) + +#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) + +/* transmit channel control */ +#define XC_XE ((uint32)1 << 0) /* transmit enable */ +#define XC_SE ((uint32)1 << 1) /* transmit suspend request */ +#define XC_LE ((uint32)1 << 2) /* loopback enable */ +#define XC_FL ((uint32)1 << 4) /* flush request */ +#define XC_MR_MASK 0x000001C0 /* Multiple outstanding reads */ +#define XC_MR_SHIFT 6 +#define XC_PD ((uint32)1 << 11) /* parity check disable */ +#define XC_AE ((uint32)3 << 16) /* address extension bits */ +#define XC_AE_SHIFT 16 +#define XC_BL_MASK 0x001C0000 /* BurstLen bits */ +#define XC_BL_SHIFT 18 +#define XC_PC_MASK 0x00E00000 /* Prefetch control */ +#define XC_PC_SHIFT 21 +#define XC_PT_MASK 0x03000000 /* Prefetch threshold */ +#define XC_PT_SHIFT 24 + +/* Multiple outstanding reads */ +#define DMA_MR_1 0 +#define DMA_MR_2 1 +#define DMA_MR_4 2 +#define DMA_MR_8 3 +#define DMA_MR_12 4 +#define DMA_MR_16 5 +#define DMA_MR_20 6 +#define DMA_MR_32 7 + +/* DMA Burst Length in bytes */ +#define DMA_BL_16 0 +#define DMA_BL_32 1 +#define DMA_BL_64 2 +#define DMA_BL_128 3 +#define DMA_BL_256 4 +#define DMA_BL_512 5 +#define DMA_BL_1024 6 + +/* Prefetch control */ +#define DMA_PC_0 0 +#define DMA_PC_4 1 +#define DMA_PC_8 2 +#define DMA_PC_16 3 +/* others: reserved */ + +/* Prefetch threshold */ +#define DMA_PT_1 0 +#define DMA_PT_2 1 +#define DMA_PT_4 2 +#define DMA_PT_8 3 + +/* transmit descriptor table pointer */ +#define XP_LD_MASK 0xfff /* last valid descriptor */ + +/* transmit channel status */ +#define XS_CD_MASK 0x0fff /* current descriptor pointer */ +#define XS_XS_MASK 0xf000 /* transmit state */ +#define XS_XS_SHIFT 12 +#define XS_XS_DISABLED 0x0000 /* disabled */ +#define XS_XS_ACTIVE 0x1000 /* active */ +#define XS_XS_IDLE 0x2000 /* idle wait */ +#define XS_XS_STOPPED 0x3000 /* stopped */ +#define XS_XS_SUSP 0x4000 /* suspend pending */ +#define XS_XE_MASK 0xf0000 /* transmit errors */ +#define XS_XE_SHIFT 16 +#define XS_XE_NOERR 0x00000 /* no error */ +#define XS_XE_DPE 0x10000 /* descriptor protocol error */ +#define XS_XE_DFU 0x20000 /* data fifo underrun */ +#define XS_XE_BEBR 0x30000 /* bus error on buffer read */ +#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */ +#define XS_AD_MASK 0xfff00000 /* active descriptor */ +#define XS_AD_SHIFT 20 + +/* receive channel control */ +#define RC_RE ((uint32)1 << 0) /* receive enable */ +#define RC_RO_MASK 0xfe /* receive frame offset */ +#define RC_RO_SHIFT 1 +#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */ +#define RC_SH ((uint32)1 << 9) /* separate rx header descriptor enable */ +#define RC_OC ((uint32)1 << 10) /* overflow continue */ +#define RC_PD ((uint32)1 << 11) /* parity check disable */ +#define RC_AE ((uint32)3 << 16) /* address extension bits */ +#define RC_AE_SHIFT 16 +#define RC_BL_MASK 0x001C0000 /* BurstLen bits */ +#define RC_BL_SHIFT 18 +#define RC_PC_MASK 0x00E00000 /* Prefetch control */ +#define RC_PC_SHIFT 21 +#define RC_PT_MASK 0x03000000 /* Prefetch threshold */ +#define RC_PT_SHIFT 24 + +/* receive descriptor table pointer */ +#define RP_LD_MASK 0xfff /* last valid descriptor */ + +/* receive channel status */ +#define RS_CD_MASK 0x0fff /* current descriptor pointer */ +#define RS_RS_MASK 0xf000 /* receive state */ +#define RS_RS_SHIFT 12 +#define RS_RS_DISABLED 0x0000 /* disabled */ +#define RS_RS_ACTIVE 0x1000 /* active */ +#define RS_RS_IDLE 0x2000 /* idle wait */ +#define RS_RS_STOPPED 0x3000 /* reserved */ +#define RS_RE_MASK 0xf0000 /* receive errors */ +#define RS_RE_SHIFT 16 +#define RS_RE_NOERR 0x00000 /* no error */ +#define RS_RE_DPE 0x10000 /* descriptor protocol error */ +#define RS_RE_DFO 0x20000 /* data fifo overflow */ +#define RS_RE_BEBW 0x30000 /* bus error on buffer write */ +#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */ +#define RS_AD_MASK 0xfff00000 /* active descriptor */ +#define RS_AD_SHIFT 20 + +/* fifoaddr */ +#define FA_OFF_MASK 0xffff /* offset */ +#define FA_SEL_MASK 0xf0000 /* select */ +#define FA_SEL_SHIFT 16 +#define FA_SEL_XDD 0x00000 /* transmit dma data */ +#define FA_SEL_XDP 0x10000 /* transmit dma pointers */ +#define FA_SEL_RDD 0x40000 /* receive dma data */ +#define FA_SEL_RDP 0x50000 /* receive dma pointers */ +#define FA_SEL_XFD 0x80000 /* transmit fifo data */ +#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */ +#define FA_SEL_RFD 0xc0000 /* receive fifo data */ +#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */ +#define FA_SEL_RSD 0xe0000 /* receive frame status data */ +#define FA_SEL_RSP 0xf0000 /* receive frame status pointers */ + +/* descriptor control flags */ +#define CTRL_BC_MASK 0x00001fff /* buffer byte count, real data len must <= 4KB */ +#define CTRL_AE ((uint32)3 << 16) /* address extension bits */ +#define CTRL_AE_SHIFT 16 +#define CTRL_PARITY ((uint32)3 << 18) /* parity bit */ +#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */ +#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */ +#define CTRL_EOF ((uint32)1 << 30) /* end of frame */ +#define CTRL_SOF ((uint32)1 << 31) /* start of frame */ + +/* control flags in the range [27:20] are core-specific and not defined here */ +#define CTRL_CORE_MASK 0x0ff00000 + +/* 64 bits addressing */ + +/* dma registers per channel(xmt or rcv) */ +typedef volatile struct { + uint32 control; /* enable, et al */ + uint32 ptr; /* last descriptor posted to chip */ + uint32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */ + uint32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */ + uint32 status0; /* current descriptor, xmt state */ + uint32 status1; /* active descriptor, xmt error */ +} dma64regs_t; + +typedef volatile struct { + dma64regs_t tx; /* dma64 tx channel */ + dma64regs_t rx; /* dma64 rx channel */ +} dma64regp_t; + +typedef volatile struct { /* diag access */ + uint32 fifoaddr; /* diag address */ + uint32 fifodatalow; /* low 32bits of data */ + uint32 fifodatahigh; /* high 32bits of data */ + uint32 pad; /* reserved */ +} dma64diag_t; + +/* + * DMA Descriptor + * Descriptors are only read by the hardware, never written back. + */ +typedef volatile struct { + uint32 ctrl1; /* misc control bits */ + uint32 ctrl2; /* buffer count and address extension */ + uint32 addrlow; /* memory address of the date buffer, bits 31:0 */ + uint32 addrhigh; /* memory address of the date buffer, bits 63:32 */ +} dma64dd_t; + +/* + * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss. + */ +#define D64RINGALIGN_BITS 13 +#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) +#define D64RINGBOUNDARY (1 << D64RINGALIGN_BITS) + +#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) + +/* for cores with large descriptor ring support, descriptor ring size can be up to 4096 */ +#define D64MAXDD_LARGE ((1 << 16) / sizeof (dma64dd_t)) + +/* for cores with large descriptor ring support (4k descriptors), descriptor ring cannot cross + * 64K boundary + */ +#define D64RINGBOUNDARY_LARGE (1 << 16) + +/* + * Default DMA Burstlen values for USBRev >= 12 and SDIORev >= 11. + * When this field contains the value N, the burst length is 2**(N + 4) bytes. + */ +#define D64_DEF_USBBURSTLEN 2 +#define D64_DEF_SDIOBURSTLEN 1 + + +#ifndef D64_USBBURSTLEN +#define D64_USBBURSTLEN DMA_BL_64 +#endif +#ifndef D64_SDIOBURSTLEN +#define D64_SDIOBURSTLEN DMA_BL_32 +#endif + +/* 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_MR_MASK 0x000001C0 /* Multiple outstanding reads */ +#define D64_XC_MR_SHIFT 6 +#define D64_XC_PD 0x00000800 /* parity check disable */ +#define D64_XC_AE 0x00030000 /* address extension bits */ +#define D64_XC_AE_SHIFT 16 +#define D64_XC_BL_MASK 0x001C0000 /* BurstLen bits */ +#define D64_XC_BL_SHIFT 18 +#define D64_XC_PC_MASK 0x00E00000 /* Prefetch control */ +#define D64_XC_PC_SHIFT 21 +#define D64_XC_PT_MASK 0x03000000 /* Prefetch threshold */ +#define D64_XC_PT_SHIFT 24 + +/* transmit descriptor table pointer */ +#define D64_XP_LD_MASK 0x00001fff /* last valid descriptor */ + +/* transmit channel status */ +#define D64_XS0_CD_MASK (di->d64_xs0_cd_mask) /* 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 (di->d64_xs1_ad_mask) /* 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 */ +#define D64_RC_RE 0x00000001 /* receive enable */ +#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */ +#define D64_RC_RO_SHIFT 1 +#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */ +#define D64_RC_SH 0x00000200 /* separate rx header descriptor enable */ +#define D64_RC_SHIFT 9 /* separate rx header descriptor enable */ +#define D64_RC_OC 0x00000400 /* overflow continue */ +#define D64_RC_PD 0x00000800 /* parity check disable */ +#define D64_RC_GE 0x00004000 /* Glom enable */ +#define D64_RC_AE 0x00030000 /* address extension bits */ +#define D64_RC_AE_SHIFT 16 +#define D64_RC_BL_MASK 0x001C0000 /* BurstLen bits */ +#define D64_RC_BL_SHIFT 18 +#define D64_RC_PC_MASK 0x00E00000 /* Prefetch control */ +#define D64_RC_PC_SHIFT 21 +#define D64_RC_PT_MASK 0x03000000 /* Prefetch threshold */ +#define D64_RC_PT_SHIFT 24 + +/* flags for dma controller */ +#define DMA_CTRL_PEN (1 << 0) /* partity enable */ +#define DMA_CTRL_ROC (1 << 1) /* rx overflow continue */ +#define DMA_CTRL_RXMULTI (1 << 2) /* allow rx scatter to multiple descriptors */ +#define DMA_CTRL_UNFRAMED (1 << 3) /* Unframed Rx/Tx data */ +#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) +#define DMA_CTRL_DMA_AVOIDANCE_WAR (1 << 5) /* DMA avoidance WAR for 4331 */ +#define DMA_CTRL_RXSINGLE (1 << 6) /* always single buffer */ +#define DMA_CTRL_SDIO_RXGLOM (1 << 7) /* DMA Rx glome is enabled */ + +/* receive descriptor table pointer */ +#define D64_RP_LD_MASK 0x00001fff /* last valid descriptor */ + +/* receive channel status */ +#define D64_RS0_CD_MASK (di->d64_rs0_cd_mask) /* 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_NOTPCIE ((uint32)1 << 18) /* buirst size control */ +#define D64_CTRL1_EOT ((uint32)1 << 28) /* end of descriptor table */ +#define D64_CTRL1_IOC ((uint32)1 << 29) /* interrupt on completion */ +#define D64_CTRL1_EOF ((uint32)1 << 30) /* end of frame */ +#define D64_CTRL1_SOF ((uint32)1 << 31) /* start of frame */ + +/* descriptor control flags 2 */ +#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count. real data len must <= 16KB */ +#define D64_CTRL2_AE 0x00030000 /* address extension bits */ +#define D64_CTRL2_AE_SHIFT 16 +#define D64_CTRL2_PARITY 0x00040000 /* parity bit */ + +/* 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, d11corerev >= 22 */ +#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */ + +/* receive frame status */ +typedef volatile struct { + uint16 len; + uint16 flags; +} dma_rxh_t; + +#endif /* _sbhnddma_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbpcmcia.h new file mode 100644 index 000000000000..b48ef3bd974f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sbpcmcia.h @@ -0,0 +1,131 @@ +/* + * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbpcmcia.h 516206 2014-11-19 05:21:45Z $ + */ + +#ifndef _SBPCMCIA_H +#define _SBPCMCIA_H + +/* All the addresses that are offsets in attribute space are divided + * by two to account for the fact that odd bytes are invalid in + * attribute space and our read/write routines make the space appear + * as if they didn't exist. Still we want to show the original numbers + * as documented in the hnd_pcmcia core manual. + */ + +/* PCMCIA Function Configuration Registers */ +#define PCMCIA_FCR (0x700 / 2) + +#define FCR0_OFF 0 +#define FCR1_OFF (0x40 / 2) +#define FCR2_OFF (0x80 / 2) +#define FCR3_OFF (0xc0 / 2) + +#define PCMCIA_FCR0 (0x700 / 2) +#define PCMCIA_FCR1 (0x740 / 2) +#define PCMCIA_FCR2 (0x780 / 2) +#define PCMCIA_FCR3 (0x7c0 / 2) + +/* Standard PCMCIA FCR registers */ + +#define PCMCIA_COR 0 + +#define COR_RST 0x80 +#define COR_LEV 0x40 +#define COR_IRQEN 0x04 +#define COR_BLREN 0x01 +#define COR_FUNEN 0x01 + + +#define PCICIA_FCSR (2 / 2) +#define PCICIA_PRR (4 / 2) +#define PCICIA_SCR (6 / 2) +#define PCICIA_ESR (8 / 2) + + +#define PCM_MEMOFF 0x0000 +#define F0_MEMOFF 0x1000 +#define F1_MEMOFF 0x2000 +#define F2_MEMOFF 0x3000 +#define F3_MEMOFF 0x4000 + +/* Memory base in the function fcr's */ +#define MEM_ADDR0 (0x728 / 2) +#define MEM_ADDR1 (0x72a / 2) +#define MEM_ADDR2 (0x72c / 2) + +/* PCMCIA base plus Srom access in fcr0: */ +#define PCMCIA_ADDR0 (0x072e / 2) +#define PCMCIA_ADDR1 (0x0730 / 2) +#define PCMCIA_ADDR2 (0x0732 / 2) + +#define MEM_SEG (0x0734 / 2) +#define SROM_CS (0x0736 / 2) +#define SROM_DATAL (0x0738 / 2) +#define SROM_DATAH (0x073a / 2) +#define SROM_ADDRL (0x073c / 2) +#define SROM_ADDRH (0x073e / 2) +#define SROM_INFO2 (0x0772 / 2) /* Corerev >= 2 && <= 5 */ +#define SROM_INFO (0x07be / 2) /* Corerev >= 6 */ + +/* Values for srom_cs: */ +#define SROM_IDLE 0 +#define SROM_WRITE 1 +#define SROM_READ 2 +#define SROM_WEN 4 +#define SROM_WDS 7 +#define SROM_DONE 8 + +/* Fields in srom_info: */ +#define SRI_SZ_MASK 0x03 +#define SRI_BLANK 0x04 +#define SRI_OTP 0x80 + + +/* Standard tuples we know about */ + +#define CISTPL_NULL 0x00 +#define CISTPL_END 0xff /* End of the CIS tuple chain */ + + +#define CISTPL_BRCM_HNBU 0x80 + + +#define HNBU_BOARDREV 0x02 /* One byte board revision */ + + +#define HNBU_BOARDTYPE 0x1b /* 2 bytes; boardtype */ + + +#define HNBU_HNBUCIS 0x1d /* what follows is proprietary HNBU CIS format */ + + +/* sbtmstatelow */ +#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */ +#define SBTML_INT_EN 0x20000 /* enable sb interrupt */ + +/* sbtmstatehigh */ +#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */ + +#endif /* _SBPCMCIA_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sbsdio.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbsdio.h new file mode 100644 index 000000000000..56e5f14fe34f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sbsdio.h @@ -0,0 +1,186 @@ +/* + * SDIO device core hardware definitions. + * sdio is a portion of the pcmcia core in core rev 3 - rev 8 + * + * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbsdio.h 383835 2013-02-07 23:32:39Z $ + */ + +#ifndef _SBSDIO_H +#define _SBSDIO_H + +#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */ + +/* function 1 miscellaneous registers */ +#define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */ +#define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */ +#define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */ +#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */ +#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */ +#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */ +#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */ +#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */ +#define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */ +#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */ + +/* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */ +#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */ +#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */ +#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */ +#define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */ +#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */ +#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */ +#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */ +#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */ +#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */ +#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */ +#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D /* MesBusyCtl at 0x1001D (rev 11) */ + +#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ +#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ + +/* Sdio Core Rev 12 */ +#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E +#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1 +#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0 +#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2 +#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1 +#define SBSDIO_FUNC1_SLEEPCSR 0x1001F +#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1 +#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0 +#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1 +#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2 +#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1 + +/* SBSDIO_SPROM_CS */ +#define SBSDIO_SPROM_IDLE 0 +#define SBSDIO_SPROM_WRITE 1 +#define SBSDIO_SPROM_READ 2 +#define SBSDIO_SPROM_WEN 4 +#define SBSDIO_SPROM_WDS 7 +#define SBSDIO_SPROM_DONE 8 + +/* SBSDIO_SPROM_INFO */ +#define SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */ +#define SROM_BLANK 0x04 /* depreciated in corerev 6 */ +#define SROM_OTP 0x80 /* OTP present */ + +/* SBSDIO_CHIP_CTRL */ +#define SBSDIO_CHIP_CTRL_XTAL 0x01 /* or'd with onchip xtal_pu, + * 1: power on oscillator + * (for 4318 only) + */ +/* SBSDIO_WATERMARK */ +#define SBSDIO_WATERMARK_MASK 0x7f /* number of words - 1 for sd device + * to wait before sending data to host + */ + +/* SBSDIO_MESBUSYCTRL */ +/* When RX FIFO has less entries than this & MBE is set + * => busy signal is asserted between data blocks. +*/ +#define SBSDIO_MESBUSYCTRL_MASK 0x7f +#define SBSDIO_MESBUSYCTRL_ENAB 0x80 /* Enable busy capability for MES access */ + +/* SBSDIO_DEVICE_CTL */ +#define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when + * receiving CMD53 + */ +#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is + * synchronous to the sdio clock + */ +#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host + * except the chipActive (rev 8) + */ +#define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put + * external pads in tri-state; requires + * sdio bus power cycle to clear (rev 9) + */ +#define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ +#define SBSDIO_DEVCTL_F2WM_ENAB 0x10 /* Enable F2 Watermark */ +#define SBSDIO_DEVCTL_NONDAT_PADS_ISO 0x20 /* Isolate sdio clk and cmd (non-data) */ + +/* SBSDIO_FUNC1_CHIPCLKCSR */ +#define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */ +#define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */ +#define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */ +#define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */ +#define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */ +#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */ +#define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */ +#define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */ +/* In rev8, actual avail bits followed original docs */ +#define SBSDIO_Rev8_HT_AVAIL 0x40 +#define SBSDIO_Rev8_ALP_AVAIL 0x80 +#define SBSDIO_CSR_MASK 0x1F + +#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))) + +/* SBSDIO_FUNC1_SDIOPULLUP */ +#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */ +#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */ +#define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */ +#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */ +#define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */ + +/* function 1 OCP space */ +#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */ +#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 +#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */ + +/* some duplication with sbsdpcmdev.h here */ +/* 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 */ +#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ + +/* direct(mapped) cis space */ +#define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ +#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */ +#define SBSDIO_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP CIS */ + +#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */ + +#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple, + * link bytes + */ + +/* indirect cis access (in sprom) */ +#define SBSDIO_SPROM_CIS_OFFSET 0x8 /* 8 control bytes first, CIS starts from + * 8th byte + */ + +#define SBSDIO_BYTEMODE_DATALEN_MAX 64 /* sdio byte mode: maximum length of one + * data comamnd + */ + +#define SBSDIO_CORE_ADDR_MASK 0x1FFFF /* sdio core function one address mask */ + +#endif /* _SBSDIO_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbsdpcmdev.h new file mode 100644 index 000000000000..f24d0a3c4e76 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sbsdpcmdev.h @@ -0,0 +1,295 @@ +/* + * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific + * device core support + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbsdpcmdev.h 416730 2013-08-06 09:33:19Z $ + */ + +#ifndef _sbsdpcmdev_h_ +#define _sbsdpcmdev_h_ + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif /* PAD */ + + +typedef volatile struct { + dma64regs_t xmt; /* dma tx */ + uint32 PAD[2]; + dma64regs_t rcv; /* dma rx */ + uint32 PAD[2]; +} dma64p_t; + +/* dma64 sdiod corerev >= 1 */ +typedef volatile struct { + dma64p_t dma64regs[2]; + dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */ + uint32 PAD[92]; +} sdiodma64_t; + +/* dma32 sdiod corerev == 0 */ +typedef volatile struct { + dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ + dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */ + uint32 PAD[108]; +} sdiodma32_t; + +/* dma32 regs for pcmcia core */ +typedef volatile struct { + dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */ + dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */ + uint32 PAD[116]; +} pcmdma32_t; + +/* core registers */ +typedef volatile struct { + uint32 corecontrol; /* CoreControl, 0x000, rev8 */ + uint32 corestatus; /* CoreStatus, 0x004, rev8 */ + uint32 PAD[1]; + uint32 biststatus; /* BistStatus, 0x00c, rev8 */ + + /* PCMCIA access */ + uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */ + uint16 PAD[1]; + uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */ + uint16 PAD[1]; + uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */ + uint16 PAD[1]; + uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */ + uint16 PAD[1]; + + /* interrupt */ + uint32 intstatus; /* IntStatus, 0x020, rev8 */ + uint32 hostintmask; /* IntHostMask, 0x024, rev8 */ + uint32 intmask; /* IntSbMask, 0x028, rev8 */ + uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */ + uint32 sbintmask; /* SBIntMask, 0x030, rev8 */ + uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */ + uint32 PAD[2]; + uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */ + uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */ + uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */ + uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */ + + /* synchronized access to registers in SDIO clock domain */ + uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */ + uint32 PAD[3]; + + /* PCMCIA frame control */ + uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ + uint8 PAD[3]; + uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ + uint8 PAD[155]; + + /* interrupt batching control */ + uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */ + uint32 PAD[3]; + + /* counters */ + uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */ + uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */ + uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */ + uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */ + uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */ + uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */ + uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */ + uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */ + uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */ + uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */ + uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */ + uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */ + uint32 PAD[40]; + uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */ + uint32 PAD[7]; + + /* DMA engines */ + volatile union { + pcmdma32_t pcm32; + sdiodma32_t sdiod32; + sdiodma64_t sdiod64; + } dma; + + /* SDIO/PCMCIA CIS region */ + char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */ + + /* PCMCIA function control registers */ + char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */ + uint16 PAD[55]; + + /* PCMCIA backplane access */ + uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */ + uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */ + uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */ + uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */ + uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */ + uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */ + uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */ + uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */ + uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */ + uint16 PAD[31]; + + /* sprom "size" & "blank" info */ + uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */ + uint32 PAD[464]; + + /* Sonics SiliconBackplane registers */ + sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */ +} sdpcmd_regs_t; + +/* corecontrol */ +#define CC_CISRDY (1 << 0) /* CIS Ready */ +#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ +#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ +#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ +#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */ +#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */ + +/* corestatus */ +#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */ +#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */ +#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */ + +#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */ +#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */ +#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */ +#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */ + +/* 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 transitioned 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) /* DMA Errors */ +#define I_DMA (I_RI | I_XI | I_ERRORS) + +/* sbintstatus */ +#define I_SB_SERR (1 << 8) /* Backplane SError (write) */ +#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */ +#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */ + +/* sdioaccess */ +#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */ +#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */ +#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */ +#define SDA_WRITE 0x01000000 /* Write bit */ +#define SDA_READ 0x00000000 /* Write bit cleared for Read */ +#define SDA_BUSY 0x80000000 /* Busy bit */ + +/* sdioaccess-accessible register address spaces */ +#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */ +#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */ +#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */ +#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */ + +/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */ +#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */ +#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */ +#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */ +#define SDA_DEVICECONTROL 0x009 /* DeviceControl */ +#define SDA_SBADDRLOW 0x00a /* SbAddrLow */ +#define SDA_SBADDRMID 0x00b /* SbAddrMid */ +#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */ +#define SDA_FRAMECTRL 0x00d /* FrameCtrl */ +#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */ +#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */ +#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */ +#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */ +#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */ +#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */ + +/* SDA_F2WATERMARK */ +#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */ + +/* SDA_SBADDRLOW */ +#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */ + +/* SDA_SBADDRMID */ +#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */ + +/* SDA_SBADDRHIGH */ +#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */ + +/* 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) /* HW reports CRC error for write out of sync */ +#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */ + +/* pcmciaframectrl */ +#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */ +#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */ + +/* intrcvlazy */ +#define IRL_TO_MASK 0x00ffffff /* timeout */ +#define IRL_FC_MASK 0xff000000 /* frame count */ +#define IRL_FC_SHIFT 24 /* frame count */ + +/* rx header */ +typedef volatile struct { + uint16 len; + uint16 flags; +} sdpcmd_rxh_t; + +/* rx header flags */ +#define RXF_CRC 0x0001 /* CRC error detected */ +#define RXF_WOOS 0x0002 /* write frame out of sync */ +#define RXF_WF_TERM 0x0004 /* write frame terminated */ +#define RXF_ABORT 0x0008 /* write frame aborted */ +#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */ + +/* HW frame tag */ +#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ + +#define SDPCM_HWEXT_LEN 8 + +#endif /* _sbsdpcmdev_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sbsocram.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbsocram.h new file mode 100644 index 000000000000..900c001eea4a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sbsocram.h @@ -0,0 +1,200 @@ +/* + * BCM47XX Sonics SiliconBackplane embedded ram core + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbsocram.h 481602 2014-05-29 22:43:34Z $ + */ + +#ifndef _SBSOCRAM_H +#define _SBSOCRAM_H + +#ifndef _LANGUAGE_ASSEMBLY + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif /* PAD */ + +/* Memcsocram core registers */ +typedef volatile struct sbsocramregs { + uint32 coreinfo; + uint32 bwalloc; + uint32 extracoreinfo; + uint32 biststat; + uint32 bankidx; + uint32 standbyctrl; + + uint32 errlogstatus; /* rev 6 */ + uint32 errlogaddr; /* rev 6 */ + /* used for patching rev 3 & 5 */ + uint32 cambankidx; + uint32 cambankstandbyctrl; + uint32 cambankpatchctrl; + uint32 cambankpatchtblbaseaddr; + uint32 cambankcmdreg; + uint32 cambankdatareg; + uint32 cambankmaskreg; + uint32 PAD[1]; + uint32 bankinfo; /* corev 8 */ + uint32 bankpda; + uint32 PAD[14]; + uint32 extmemconfig; + uint32 extmemparitycsr; + uint32 extmemparityerrdata; + uint32 extmemparityerrcnt; + uint32 extmemwrctrlandsize; + uint32 PAD[84]; + uint32 workaround; + uint32 pwrctl; /* corerev >= 2 */ + uint32 PAD[133]; + uint32 sr_control; /* corerev >= 15 */ + uint32 sr_status; /* corerev >= 15 */ + uint32 sr_address; /* corerev >= 15 */ + uint32 sr_data; /* corerev >= 15 */ +} sbsocramregs_t; + +#endif /* _LANGUAGE_ASSEMBLY */ + +/* Register offsets */ +#define SR_COREINFO 0x00 +#define SR_BWALLOC 0x04 +#define SR_BISTSTAT 0x0c +#define SR_BANKINDEX 0x10 +#define SR_BANKSTBYCTL 0x14 +#define SR_PWRCTL 0x1e8 + +/* Coreinfo register */ +#define SRCI_PT_MASK 0x00070000 /* corerev >= 6; port type[18:16] */ +#define SRCI_PT_SHIFT 16 +/* port types : SRCI_PT__ */ +#define SRCI_PT_OCP_OCP 0 +#define SRCI_PT_AXI_OCP 1 +#define SRCI_PT_ARM7AHB_OCP 2 +#define SRCI_PT_CM3AHB_OCP 3 +#define SRCI_PT_AXI_AXI 4 +#define SRCI_PT_AHB_AXI 5 +/* corerev >= 3 */ +#define SRCI_LSS_MASK 0x00f00000 +#define SRCI_LSS_SHIFT 20 +#define SRCI_LRS_MASK 0x0f000000 +#define SRCI_LRS_SHIFT 24 + +/* In corerev 0, the memory size is 2 to the power of the + * base plus 16 plus to the contents of the memsize field plus 1. + */ +#define SRCI_MS0_MASK 0xf +#define SR_MS0_BASE 16 + +/* + * In corerev 1 the bank size is 2 ^ the bank size field plus 14, + * the memory size is number of banks times bank size. + * The same applies to rom size. + */ +#define SRCI_ROMNB_MASK 0xf000 +#define SRCI_ROMNB_SHIFT 12 +#define SRCI_ROMBSZ_MASK 0xf00 +#define SRCI_ROMBSZ_SHIFT 8 +#define SRCI_SRNB_MASK 0xf0 +#define SRCI_SRNB_SHIFT 4 +#define SRCI_SRBSZ_MASK 0xf +#define SRCI_SRBSZ_SHIFT 0 + +#define SR_BSZ_BASE 14 + +/* Standby control register */ +#define SRSC_SBYOVR_MASK 0x80000000 +#define SRSC_SBYOVR_SHIFT 31 +#define SRSC_SBYOVRVAL_MASK 0x60000000 +#define SRSC_SBYOVRVAL_SHIFT 29 +#define SRSC_SBYEN_MASK 0x01000000 /* rev >= 3 */ +#define SRSC_SBYEN_SHIFT 24 + +/* Power control register */ +#define SRPC_PMU_STBYDIS_MASK 0x00000010 /* rev >= 3 */ +#define SRPC_PMU_STBYDIS_SHIFT 4 +#define SRPC_STBYOVRVAL_MASK 0x00000008 +#define SRPC_STBYOVRVAL_SHIFT 3 +#define SRPC_STBYOVR_MASK 0x00000007 +#define SRPC_STBYOVR_SHIFT 0 + +/* Extra core capability register */ +#define SRECC_NUM_BANKS_MASK 0x000000F0 +#define SRECC_NUM_BANKS_SHIFT 4 +#define SRECC_BANKSIZE_MASK 0x0000000F +#define SRECC_BANKSIZE_SHIFT 0 + +#define SRECC_BANKSIZE(value) (1 << (value)) + +/* CAM bank patch control */ +#define SRCBPC_PATCHENABLE 0x80000000 + +#define SRP_ADDRESS 0x0001FFFC +#define SRP_VALID 0x8000 + +/* CAM bank command reg */ +#define SRCMD_WRITE 0x00020000 +#define SRCMD_READ 0x00010000 +#define SRCMD_DONE 0x80000000 + +#define SRCMD_DONE_DLY 1000 + +/* bankidx and bankinfo reg defines corerev >= 8 */ +#define SOCRAM_BANKINFO_SZMASK 0x7f +#define SOCRAM_BANKIDX_ROM_MASK 0x100 + +#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 +/* socram bankinfo memtype */ +#define SOCRAM_MEMTYPE_RAM 0 +#define SOCRAM_MEMTYPE_R0M 1 +#define SOCRAM_MEMTYPE_DEVRAM 2 + +#define SOCRAM_BANKINFO_REG 0x40 +#define SOCRAM_BANKIDX_REG 0x10 +#define SOCRAM_BANKINFO_STDBY_MASK 0x400 +#define SOCRAM_BANKINFO_STDBY_TIMER 0x800 + +/* bankinfo rev >= 10 */ +#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13 +#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000 +#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14 +#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000 +#define SOCRAM_BANKINFO_SLPSUPP_SHIFT 15 +#define SOCRAM_BANKINFO_SLPSUPP_MASK 0x8000 +#define SOCRAM_BANKINFO_RETNTRAM_SHIFT 16 +#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 +#define SOCRAM_BANKINFO_PDASZ_SHIFT 17 +#define SOCRAM_BANKINFO_PDASZ_MASK 0x003E0000 +#define SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT 24 +#define SOCRAM_BANKINFO_DEVRAMREMAP_MASK 0x01000000 + +/* extracoreinfo register */ +#define SOCRAM_DEVRAMBANK_MASK 0xF000 +#define SOCRAM_DEVRAMBANK_SHIFT 12 + +/* bank info to calculate bank size */ +#define SOCRAM_BANKINFO_SZBASE 8192 +#define SOCRAM_BANKSIZE_SHIFT 13 /* SOCRAM_BANKINFO_SZBASE */ + + +#endif /* _SBSOCRAM_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sdio.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sdio.h new file mode 100644 index 000000000000..8bebba9d2981 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sdio.h @@ -0,0 +1,622 @@ +/* + * SDIO spec header file + * Protocol and standard (common) device definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sdio.h 416730 2013-08-06 09:33:19Z $ + */ + +#ifndef _SDIO_H +#define _SDIO_H + +#ifdef BCMSDIO + +/* CCCR structure for function 0 */ +typedef volatile struct { + uint8 cccr_sdio_rev; /* RO, cccr and sdio revision */ + uint8 sd_rev; /* RO, sd spec revision */ + uint8 io_en; /* I/O enable */ + uint8 io_rdy; /* I/O ready reg */ + uint8 intr_ctl; /* Master and per function interrupt enable control */ + uint8 intr_status; /* RO, interrupt pending status */ + uint8 io_abort; /* read/write abort or reset all functions */ + uint8 bus_inter; /* bus interface control */ + uint8 capability; /* RO, card capability */ + + uint8 cis_base_low; /* 0x9 RO, common CIS base address, LSB */ + uint8 cis_base_mid; + uint8 cis_base_high; /* 0xB RO, common CIS base address, MSB */ + + /* suspend/resume registers */ + uint8 bus_suspend; /* 0xC */ + uint8 func_select; /* 0xD */ + uint8 exec_flag; /* 0xE */ + uint8 ready_flag; /* 0xF */ + + uint8 fn0_blk_size[2]; /* 0x10(LSB), 0x11(MSB) */ + + uint8 power_control; /* 0x12 (SDIO version 1.10) */ + + uint8 speed_control; /* 0x13 */ +} sdio_regs_t; + +/* SDIO Device CCCR offsets */ +#define SDIOD_CCCR_REV 0x00 +#define SDIOD_CCCR_SDREV 0x01 +#define SDIOD_CCCR_IOEN 0x02 +#define SDIOD_CCCR_IORDY 0x03 +#define SDIOD_CCCR_INTEN 0x04 +#define SDIOD_CCCR_INTPEND 0x05 +#define SDIOD_CCCR_IOABORT 0x06 +#define SDIOD_CCCR_BICTRL 0x07 +#define SDIOD_CCCR_CAPABLITIES 0x08 +#define SDIOD_CCCR_CISPTR_0 0x09 +#define SDIOD_CCCR_CISPTR_1 0x0A +#define SDIOD_CCCR_CISPTR_2 0x0B +#define SDIOD_CCCR_BUSSUSP 0x0C +#define SDIOD_CCCR_FUNCSEL 0x0D +#define SDIOD_CCCR_EXECFLAGS 0x0E +#define SDIOD_CCCR_RDYFLAGS 0x0F +#define SDIOD_CCCR_BLKSIZE_0 0x10 +#define SDIOD_CCCR_BLKSIZE_1 0x11 +#define SDIOD_CCCR_POWER_CONTROL 0x12 +#define SDIOD_CCCR_SPEED_CONTROL 0x13 +#define SDIOD_CCCR_UHSI_SUPPORT 0x14 +#define SDIOD_CCCR_DRIVER_STRENGTH 0x15 +#define SDIOD_CCCR_INTR_EXTN 0x16 + +/* Broadcom extensions (corerev >= 1) */ +#define SDIOD_CCCR_BRCM_CARDCAP 0xf0 +#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02 +#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04 +#define SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08 +#define SDIOD_CCCR_BRCM_CARDCTL 0xf1 +#define SDIOD_CCCR_BRCM_SEPINT 0xf2 + +/* cccr_sdio_rev */ +#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */ +#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */ +#define SDIO_SPEC_VERSION_3_0 0x40 /* SDIO spec version 3.0 */ + +/* sd_rev */ +#define SD_REV_PHY_MASK 0x0f /* SD format version number */ + +/* io_en */ +#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */ +#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */ + +/* io_rdys */ +#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */ +#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */ + +/* intr_ctl */ +#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */ +#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */ +#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */ + +/* intr_status */ +#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */ +#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */ + +/* io_abort */ +#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */ +#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */ + +/* bus_inter */ +#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */ +#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */ +#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */ +#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */ +#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */ +#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */ + +/* capability */ +#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */ +#define SDIO_CAP_LSC 0x40 /* low speed card */ +#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */ +#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */ +#define SDIO_CAP_SBS 0x08 /* support suspend/resume */ +#define SDIO_CAP_SRW 0x04 /* support read wait */ +#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */ +#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */ + +/* power_control */ +#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */ +#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */ + +/* speed_control (control device entry into high-speed clocking mode) */ +#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */ +#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */ +#define SDIO_SPEED_UHSI_DDR50 0x08 + +/* for setting bus speed in card: 0x13h */ +#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3) +#define SDIO_BUS_SPEED_UHSISEL_S 1 + +/* for getting bus speed cap in card: 0x14h */ +#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3) +#define SDIO_BUS_SPEED_UHSICAP_S 0 + +/* for getting driver type CAP in card: 0x15h */ +#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3) +#define SDIO_BUS_DRVR_TYPE_CAP_S 0 + +/* for setting driver type selection in card: 0x15h */ +#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2) +#define SDIO_BUS_DRVR_TYPE_SEL_S 4 + +/* for getting async int support in card: 0x16h */ +#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1) +#define SDIO_BUS_ASYNCINT_CAP_S 0 + +/* for setting async int selection in card: 0x16h */ +#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1) +#define SDIO_BUS_ASYNCINT_SEL_S 1 + +/* brcm sepint */ +#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */ +#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */ +#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */ + +/* FBR structure for function 1-7, FBR addresses and register offsets */ +typedef volatile struct { + uint8 devctr; /* device interface, CSA control */ + uint8 ext_dev; /* extended standard I/O device type code */ + uint8 pwr_sel; /* power selection support */ + uint8 PAD[6]; /* reserved */ + + uint8 cis_low; /* CIS LSB */ + uint8 cis_mid; + uint8 cis_high; /* CIS MSB */ + uint8 csa_low; /* code storage area, LSB */ + uint8 csa_mid; + uint8 csa_high; /* code storage area, MSB */ + uint8 csa_dat_win; /* data access window to function */ + + uint8 fnx_blk_size[2]; /* block size, little endian */ +} sdio_fbr_t; + +/* Maximum number of I/O funcs */ +#define SDIOD_MAX_FUNCS 8 +#define SDIOD_MAX_IOFUNCS 7 + +/* SDIO Device FBR Start Address */ +#define SDIOD_FBR_STARTADDR 0x100 + +/* SDIO Device FBR Size */ +#define SDIOD_FBR_SIZE 0x100 + +/* Macro to calculate FBR register base */ +#define SDIOD_FBR_BASE(n) ((n) * 0x100) + +/* Function register offsets */ +#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */ +#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */ +#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */ + +/* SDIO Function CIS ptr offset */ +#define SDIOD_FBR_CISPTR_0 0x09 +#define SDIOD_FBR_CISPTR_1 0x0A +#define SDIOD_FBR_CISPTR_2 0x0B + +/* Code Storage Area pointer */ +#define SDIOD_FBR_CSA_ADDR_0 0x0C +#define SDIOD_FBR_CSA_ADDR_1 0x0D +#define SDIOD_FBR_CSA_ADDR_2 0x0E +#define SDIOD_FBR_CSA_DATA 0x0F + +/* SDIO Function I/O Block Size */ +#define SDIOD_FBR_BLKSIZE_0 0x10 +#define SDIOD_FBR_BLKSIZE_1 0x11 + +/* devctr */ +#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */ +#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */ +#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */ +/* interface codes */ +#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */ +#define SDIOD_DIC_UART 1 +#define SDIOD_DIC_BLUETOOTH_A 2 +#define SDIOD_DIC_BLUETOOTH_B 3 +#define SDIOD_DIC_GPS 4 +#define SDIOD_DIC_CAMERA 5 +#define SDIOD_DIC_PHS 6 +#define SDIOD_DIC_WLAN 7 +#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */ + +/* pwr_sel */ +#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */ +#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */ + +/* misc defines */ +#define SDIO_FUNC_0 0 +#define SDIO_FUNC_1 1 +#define SDIO_FUNC_2 2 +#define SDIO_FUNC_3 3 +#define SDIO_FUNC_4 4 +#define SDIO_FUNC_5 5 +#define SDIO_FUNC_6 6 +#define SDIO_FUNC_7 7 + +#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */ +#define SD_CARD_TYPE_IO 1 /* IO only card */ +#define SD_CARD_TYPE_MEMORY 2 /* memory only card */ +#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */ + +#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */ +#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */ + +/* Card registers: status bit position */ +#define CARDREG_STATUS_BIT_OUTOFRANGE 31 +#define CARDREG_STATUS_BIT_COMCRCERROR 23 +#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22 +#define CARDREG_STATUS_BIT_ERROR 19 +#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12 +#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11 +#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10 +#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9 +#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4 + + + +#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */ +#define SD_CMD_SEND_OPCOND 1 +#define SD_CMD_MMC_SET_RCA 3 +#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */ +#define SD_CMD_SELECT_DESELECT_CARD 7 +#define SD_CMD_SEND_CSD 9 +#define SD_CMD_SEND_CID 10 +#define SD_CMD_STOP_TRANSMISSION 12 +#define SD_CMD_SEND_STATUS 13 +#define SD_CMD_GO_INACTIVE_STATE 15 +#define SD_CMD_SET_BLOCKLEN 16 +#define SD_CMD_READ_SINGLE_BLOCK 17 +#define SD_CMD_READ_MULTIPLE_BLOCK 18 +#define SD_CMD_WRITE_BLOCK 24 +#define SD_CMD_WRITE_MULTIPLE_BLOCK 25 +#define SD_CMD_PROGRAM_CSD 27 +#define SD_CMD_SET_WRITE_PROT 28 +#define SD_CMD_CLR_WRITE_PROT 29 +#define SD_CMD_SEND_WRITE_PROT 30 +#define SD_CMD_ERASE_WR_BLK_START 32 +#define SD_CMD_ERASE_WR_BLK_END 33 +#define SD_CMD_ERASE 38 +#define SD_CMD_LOCK_UNLOCK 42 +#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */ +#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */ +#define SD_CMD_APP_CMD 55 +#define SD_CMD_GEN_CMD 56 +#define SD_CMD_READ_OCR 58 +#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */ +#define SD_ACMD_SD_STATUS 13 +#define SD_ACMD_SEND_NUM_WR_BLOCKS 22 +#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23 +#define SD_ACMD_SD_SEND_OP_COND 41 +#define SD_ACMD_SET_CLR_CARD_DETECT 42 +#define SD_ACMD_SEND_SCR 51 + +/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */ +#define SD_IO_OP_READ 0 /* Read_Write: Read */ +#define SD_IO_OP_WRITE 1 /* Read_Write: Write */ +#define SD_IO_RW_NORMAL 0 /* no RAW */ +#define SD_IO_RW_RAW 1 /* RAW */ +#define SD_IO_BYTE_MODE 0 /* Byte Mode */ +#define SD_IO_BLOCK_MODE 1 /* BlockMode */ +#define SD_IO_FIXED_ADDRESS 0 /* fix Address */ +#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */ + +/* build SD_CMD_IO_RW_DIRECT Argument */ +#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \ + ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \ + (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF)) + +/* build SD_CMD_IO_RW_EXTENDED Argument */ +#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \ + ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \ + (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF)) + +/* SDIO response parameters */ +#define SD_RSP_NO_NONE 0 +#define SD_RSP_NO_1 1 +#define SD_RSP_NO_2 2 +#define SD_RSP_NO_3 3 +#define SD_RSP_NO_4 4 +#define SD_RSP_NO_5 5 +#define SD_RSP_NO_6 6 + + /* Modified R6 response (to CMD3) */ +#define SD_RSP_MR6_COM_CRC_ERROR 0x8000 +#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000 +#define SD_RSP_MR6_ERROR 0x2000 + + /* Modified R1 in R4 Response (to CMD5) */ +#define SD_RSP_MR1_SBIT 0x80 +#define SD_RSP_MR1_PARAMETER_ERROR 0x40 +#define SD_RSP_MR1_RFU5 0x20 +#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10 +#define SD_RSP_MR1_COM_CRC_ERROR 0x08 +#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04 +#define SD_RSP_MR1_RFU1 0x02 +#define SD_RSP_MR1_IDLE_STATE 0x01 + + /* R5 response (to CMD52 and CMD53) */ +#define SD_RSP_R5_COM_CRC_ERROR 0x80 +#define SD_RSP_R5_ILLEGAL_COMMAND 0x40 +#define SD_RSP_R5_IO_CURRENTSTATE1 0x20 +#define SD_RSP_R5_IO_CURRENTSTATE0 0x10 +#define SD_RSP_R5_ERROR 0x08 +#define SD_RSP_R5_RFU 0x04 +#define SD_RSP_R5_FUNC_NUM_ERROR 0x02 +#define SD_RSP_R5_OUT_OF_RANGE 0x01 + +#define SD_RSP_R5_ERRBITS 0xCB + + +/* ------------------------------------------------ + * SDIO Commands and responses + * + * I/O only commands are: + * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53 + * ------------------------------------------------ + */ + +/* SDIO Commands */ +#define SDIOH_CMD_0 0 +#define SDIOH_CMD_3 3 +#define SDIOH_CMD_5 5 +#define SDIOH_CMD_7 7 +#define SDIOH_CMD_11 11 +#define SDIOH_CMD_14 14 +#define SDIOH_CMD_15 15 +#define SDIOH_CMD_19 19 +#define SDIOH_CMD_52 52 +#define SDIOH_CMD_53 53 +#define SDIOH_CMD_59 59 + +/* SDIO Command Responses */ +#define SDIOH_RSP_NONE 0 +#define SDIOH_RSP_R1 1 +#define SDIOH_RSP_R2 2 +#define SDIOH_RSP_R3 3 +#define SDIOH_RSP_R4 4 +#define SDIOH_RSP_R5 5 +#define SDIOH_RSP_R6 6 + +/* + * SDIO Response Error flags + */ +#define SDIOH_RSP5_ERROR_FLAGS 0xCB + +/* ------------------------------------------------ + * SDIO Command structures. I/O only commands are: + * + * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53 + * ------------------------------------------------ + */ + +#define CMD5_OCR_M BITFIELD_MASK(24) +#define CMD5_OCR_S 0 + +#define CMD5_S18R_M BITFIELD_MASK(1) +#define CMD5_S18R_S 24 + +#define CMD7_RCA_M BITFIELD_MASK(16) +#define CMD7_RCA_S 16 + +#define CMD14_RCA_M BITFIELD_MASK(16) +#define CMD14_RCA_S 16 +#define CMD14_SLEEP_M BITFIELD_MASK(1) +#define CMD14_SLEEP_S 15 + +#define CMD_15_RCA_M BITFIELD_MASK(16) +#define CMD_15_RCA_S 16 + +#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52 + */ +#define CMD52_DATA_S 0 +#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ +#define CMD52_REG_ADDR_S 9 +#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */ +#define CMD52_RAW_S 27 +#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ +#define CMD52_FUNCTION_S 28 +#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ +#define CMD52_RW_FLAG_S 31 + + +#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */ +#define CMD53_BYTE_BLK_CNT_S 0 +#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ +#define CMD53_REG_ADDR_S 9 +#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */ +#define CMD53_OP_CODE_S 26 +#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */ +#define CMD53_BLK_MODE_S 27 +#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ +#define CMD53_FUNCTION_S 28 +#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ +#define CMD53_RW_FLAG_S 31 + +/* ------------------------------------------------------ + * SDIO Command Response structures for SD1 and SD4 modes + * ----------------------------------------------------- + */ +#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */ +#define RSP4_IO_OCR_S 0 + +#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */ +#define RSP4_S18A_S 24 + +#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */ +#define RSP4_STUFF_S 24 +#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */ +#define RSP4_MEM_PRESENT_S 27 +#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */ +#define RSP4_NUM_FUNCS_S 28 +#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */ +#define RSP4_CARD_READY_S 31 + +#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0] + */ +#define RSP6_STATUS_S 0 +#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */ +#define RSP6_IO_RCA_S 16 + +#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */ +#define RSP1_AKE_SEQ_ERROR_S 3 +#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ +#define RSP1_APP_CMD_S 5 +#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */ +#define RSP1_READY_FOR_DATA_S 8 +#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card + * when Cmd was received + */ +#define RSP1_CURR_STATE_S 9 +#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */ +#define RSP1_EARSE_RESET_S 13 +#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */ +#define RSP1_CARD_ECC_DISABLE_S 14 +#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */ +#define RSP1_WP_ERASE_SKIP_S 15 +#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits + * of CSD + */ +#define RSP1_CID_CSD_OVERW_S 16 +#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */ +#define RSP1_ERROR_S 19 +#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */ +#define RSP1_CC_ERROR_S 20 +#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed + * to correct data + */ +#define RSP1_CARD_ECC_FAILED_S 21 +#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */ +#define RSP1_ILLEGAL_CMD_S 22 +#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed + */ +#define RSP1_COM_CRC_ERROR_S 23 +#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */ +#define RSP1_LOCK_UNLOCK_FAIL_S 24 +#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */ +#define RSP1_CARD_LOCKED_S 25 +#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program + * write-protected blocks + */ +#define RSP1_WP_VIOLATION_S 26 +#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */ +#define RSP1_ERASE_PARAM_S 27 +#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */ +#define RSP1_ERASE_SEQ_ERR_S 28 +#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */ +#define RSP1_BLK_LEN_ERR_S 29 +#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */ +#define RSP1_ADDR_ERR_S 30 +#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */ +#define RSP1_OUT_OF_RANGE_S 31 + + +#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */ +#define RSP5_DATA_S 0 +#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */ +#define RSP5_FLAGS_S 8 +#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */ +#define RSP5_STUFF_S 16 + +/* ---------------------------------------------- + * SDIO Command Response structures for SPI mode + * ---------------------------------------------- + */ +#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */ +#define SPIRSP4_IO_OCR_S 0 +#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */ +#define SPIRSP4_STUFF_S 16 +#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */ +#define SPIRSP4_MEM_PRESENT_S 19 +#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */ +#define SPIRSP4_NUM_FUNCS_S 20 +#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */ +#define SPIRSP4_CARD_READY_S 23 +#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */ +#define SPIRSP4_IDLE_STATE_S 24 +#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ +#define SPIRSP4_ILLEGAL_CMD_S 26 +#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ +#define SPIRSP4_COM_CRC_ERROR_S 27 +#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error + */ +#define SPIRSP4_FUNC_NUM_ERROR_S 28 +#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ +#define SPIRSP4_PARAM_ERROR_S 30 +#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ +#define SPIRSP4_START_BIT_S 31 + +#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */ +#define SPIRSP5_DATA_S 16 +#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */ +#define SPIRSP5_IDLE_STATE_S 24 +#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ +#define SPIRSP5_ILLEGAL_CMD_S 26 +#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ +#define SPIRSP5_COM_CRC_ERROR_S 27 +#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error + */ +#define SPIRSP5_FUNC_NUM_ERROR_S 28 +#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ +#define SPIRSP5_PARAM_ERROR_S 30 +#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ +#define SPIRSP5_START_BIT_S 31 + +/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */ +#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error + */ +#define RSP6STAT_AKE_SEQ_ERROR_S 3 +#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ +#define RSP6STAT_APP_CMD_S 5 +#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data + * (buff empty) + */ +#define RSP6STAT_READY_FOR_DATA_S 8 +#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at + * Cmd reception + */ +#define RSP6STAT_CURR_STATE_S 9 +#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19 + */ +#define RSP6STAT_ERROR_S 13 +#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for + * card state Bit 22 + */ +#define RSP6STAT_ILLEGAL_CMD_S 14 +#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command + * failed Bit 23 + */ +#define RSP6STAT_COM_CRC_ERROR_S 15 + +#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ +#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE + +/* command issue options */ +#define CMD_OPTION_DEFAULT 0 +#define CMD_OPTION_TUNING 1 + +#endif /* def BCMSDIO */ +#endif /* _SDIO_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sdioh.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sdioh.h new file mode 100644 index 000000000000..62a5c4cc3179 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sdioh.h @@ -0,0 +1,445 @@ +/* + * SDIO Host Controller Spec header file + * Register map and definitions for the Standard Host Controller + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sdioh.h 345499 2012-07-18 06:59:05Z $ + */ + +#ifndef _SDIOH_H +#define _SDIOH_H + +#define SD_SysAddr 0x000 +#define SD_BlockSize 0x004 +#define SD_BlockCount 0x006 +#define SD_Arg0 0x008 +#define SD_Arg1 0x00A +#define SD_TransferMode 0x00C +#define SD_Command 0x00E +#define SD_Response0 0x010 +#define SD_Response1 0x012 +#define SD_Response2 0x014 +#define SD_Response3 0x016 +#define SD_Response4 0x018 +#define SD_Response5 0x01A +#define SD_Response6 0x01C +#define SD_Response7 0x01E +#define SD_BufferDataPort0 0x020 +#define SD_BufferDataPort1 0x022 +#define SD_PresentState 0x024 +#define SD_HostCntrl 0x028 +#define SD_PwrCntrl 0x029 +#define SD_BlockGapCntrl 0x02A +#define SD_WakeupCntrl 0x02B +#define SD_ClockCntrl 0x02C +#define SD_TimeoutCntrl 0x02E +#define SD_SoftwareReset 0x02F +#define SD_IntrStatus 0x030 +#define SD_ErrorIntrStatus 0x032 +#define SD_IntrStatusEnable 0x034 +#define SD_ErrorIntrStatusEnable 0x036 +#define SD_IntrSignalEnable 0x038 +#define SD_ErrorIntrSignalEnable 0x03A +#define SD_CMD12ErrorStatus 0x03C +#define SD_Capabilities 0x040 +#define SD_Capabilities3 0x044 +#define SD_MaxCurCap 0x048 +#define SD_MaxCurCap_Reserved 0x04C +#define SD_ADMA_ErrStatus 0x054 +#define SD_ADMA_SysAddr 0x58 +#define SD_SlotInterruptStatus 0x0FC +#define SD_HostControllerVersion 0x0FE +#define SD_GPIO_Reg 0x100 +#define SD_GPIO_OE 0x104 +#define SD_GPIO_Enable 0x108 + +/* SD specific registers in PCI config space */ +#define SD_SlotInfo 0x40 + +/* HC 3.0 specific registers and offsets */ +#define SD3_HostCntrl2 0x03E +/* preset regsstart and count */ +#define SD3_PresetValStart 0x060 +#define SD3_PresetValCount 8 +/* preset-indiv regs */ +#define SD3_PresetVal_init 0x060 +#define SD3_PresetVal_default 0x062 +#define SD3_PresetVal_HS 0x064 +#define SD3_PresetVal_SDR12 0x066 +#define SD3_PresetVal_SDR25 0x068 +#define SD3_PresetVal_SDR50 0x06a +#define SD3_PresetVal_SDR104 0x06c +#define SD3_PresetVal_DDR50 0x06e +/* SDIO3.0 Revx specific Registers */ +#define SD3_Tuning_Info_Register 0x0EC +#define SD3_WL_BT_reset_register 0x0F0 + + +/* preset value indices */ +#define SD3_PRESETVAL_INITIAL_IX 0 +#define SD3_PRESETVAL_DESPEED_IX 1 +#define SD3_PRESETVAL_HISPEED_IX 2 +#define SD3_PRESETVAL_SDR12_IX 3 +#define SD3_PRESETVAL_SDR25_IX 4 +#define SD3_PRESETVAL_SDR50_IX 5 +#define SD3_PRESETVAL_SDR104_IX 6 +#define SD3_PRESETVAL_DDR50_IX 7 + +/* SD_Capabilities reg (0x040) */ +#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6) +#define CAP_TO_CLKFREQ_S 0 +#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1) +#define CAP_TO_CLKUNIT_S 7 +/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2 + bits are reserved. going ahead with 8 bits, as it is req for 3.0 +*/ +#define CAP_BASECLK_M BITFIELD_MASK(8) +#define CAP_BASECLK_S 8 +#define CAP_MAXBLOCK_M BITFIELD_MASK(2) +#define CAP_MAXBLOCK_S 16 +#define CAP_ADMA2_M BITFIELD_MASK(1) +#define CAP_ADMA2_S 19 +#define CAP_ADMA1_M BITFIELD_MASK(1) +#define CAP_ADMA1_S 20 +#define CAP_HIGHSPEED_M BITFIELD_MASK(1) +#define CAP_HIGHSPEED_S 21 +#define CAP_DMA_M BITFIELD_MASK(1) +#define CAP_DMA_S 22 +#define CAP_SUSPEND_M BITFIELD_MASK(1) +#define CAP_SUSPEND_S 23 +#define CAP_VOLT_3_3_M BITFIELD_MASK(1) +#define CAP_VOLT_3_3_S 24 +#define CAP_VOLT_3_0_M BITFIELD_MASK(1) +#define CAP_VOLT_3_0_S 25 +#define CAP_VOLT_1_8_M BITFIELD_MASK(1) +#define CAP_VOLT_1_8_S 26 +#define CAP_64BIT_HOST_M BITFIELD_MASK(1) +#define CAP_64BIT_HOST_S 28 + +#define SDIO_OCR_READ_FAIL (2) + + +#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1) +#define CAP_ASYNCINT_SUP_S 29 + +#define CAP_SLOTTYPE_M BITFIELD_MASK(2) +#define CAP_SLOTTYPE_S 30 + +#define CAP3_MSBits_OFFSET (32) +/* note: following are caps MSB32 bits. + So the bits start from 0, instead of 32. that is why + CAP3_MSBits_OFFSET is subtracted. +*/ +#define CAP3_SDR50_SUP_M BITFIELD_MASK(1) +#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET) + +#define CAP3_SDR104_SUP_M BITFIELD_MASK(1) +#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET) + +#define CAP3_DDR50_SUP_M BITFIELD_MASK(1) +#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET) + +/* for knowing the clk caps in a single read */ +#define CAP3_30CLKCAP_M BITFIELD_MASK(3) +#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET) + +#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1) +#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET) + +#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1) +#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET) + +#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1) +#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET) + +#define CAP3_RETUNING_TC_M BITFIELD_MASK(4) +#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET) + +#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1) +#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET) + +#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2) +#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET) + +#define CAP3_CLK_MULT_M BITFIELD_MASK(8) +#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET) + +#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2) +#define PRESET_DRIVR_SELECT_S 14 + +#define PRESET_CLK_DIV_M BITFIELD_MASK(10) +#define PRESET_CLK_DIV_S 0 + +/* SD_MaxCurCap reg (0x048) */ +#define CAP_CURR_3_3_M BITFIELD_MASK(8) +#define CAP_CURR_3_3_S 0 +#define CAP_CURR_3_0_M BITFIELD_MASK(8) +#define CAP_CURR_3_0_S 8 +#define CAP_CURR_1_8_M BITFIELD_MASK(8) +#define CAP_CURR_1_8_S 16 + +/* SD_SysAddr: Offset 0x0000, Size 4 bytes */ + +/* SD_BlockSize: Offset 0x004, Size 2 bytes */ +#define BLKSZ_BLKSZ_M BITFIELD_MASK(12) +#define BLKSZ_BLKSZ_S 0 +#define BLKSZ_BNDRY_M BITFIELD_MASK(3) +#define BLKSZ_BNDRY_S 12 + +/* SD_BlockCount: Offset 0x006, size 2 bytes */ + +/* SD_Arg0: Offset 0x008, size = 4 bytes */ +/* SD_TransferMode Offset 0x00C, size = 2 bytes */ +#define XFER_DMA_ENABLE_M BITFIELD_MASK(1) +#define XFER_DMA_ENABLE_S 0 +#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1) +#define XFER_BLK_COUNT_EN_S 1 +#define XFER_CMD_12_EN_M BITFIELD_MASK(1) +#define XFER_CMD_12_EN_S 2 +#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1) +#define XFER_DATA_DIRECTION_S 4 +#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1) +#define XFER_MULTI_BLOCK_S 5 + +/* SD_Command: Offset 0x00E, size = 2 bytes */ +/* resp_type field */ +#define RESP_TYPE_NONE 0 +#define RESP_TYPE_136 1 +#define RESP_TYPE_48 2 +#define RESP_TYPE_48_BUSY 3 +/* type field */ +#define CMD_TYPE_NORMAL 0 +#define CMD_TYPE_SUSPEND 1 +#define CMD_TYPE_RESUME 2 +#define CMD_TYPE_ABORT 3 + +#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */ +#define CMD_RESP_TYPE_S 0 +#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */ +#define CMD_CRC_EN_S 3 +#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */ +#define CMD_INDEX_EN_S 4 +#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */ +#define CMD_DATA_EN_S 5 +#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc + */ +#define CMD_TYPE_S 6 +#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */ +#define CMD_INDEX_S 8 + +/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */ +/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */ +/* SD_PresentState : Offset 0x024, size = 4 bytes */ +#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */ +#define PRES_CMD_INHIBIT_S 0 +#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */ +#define PRES_DAT_INHIBIT_S 1 +#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */ +#define PRES_DAT_BUSY_S 2 +#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */ +#define PRES_PRESENT_RSVD_S 3 +#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */ +#define PRES_WRITE_ACTIVE_S 8 +#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */ +#define PRES_READ_ACTIVE_S 9 +#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */ +#define PRES_WRITE_DATA_RDY_S 10 +#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */ +#define PRES_READ_DATA_RDY_S 11 +#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */ +#define PRES_CARD_PRESENT_S 16 +#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */ +#define PRES_CARD_STABLE_S 17 +#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */ +#define PRES_CARD_PRESENT_RAW_S 18 +#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */ +#define PRES_WRITE_ENABLED_S 19 +#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */ +#define PRES_DAT_SIGNAL_S 20 +#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */ +#define PRES_CMD_SIGNAL_S 24 + +/* SD_HostCntrl: Offset 0x028, size = 1 bytes */ +#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */ +#define HOST_LED_S 0 +#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */ +#define HOST_DATA_WIDTH_S 1 +#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */ +#define HOST_DMA_SEL_S 3 +#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */ +#define HOST_HI_SPEED_EN_S 2 + +/* Host Control2: */ +#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */ + +#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */ + +#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */ + +#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */ + +#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */ +#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */ + +#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */ + +#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */ +#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */ + +#define HOST_CONTR_VER_2 (1) +#define HOST_CONTR_VER_3 (2) + +/* misc defines */ +#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */ +#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */ + +/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */ +#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */ +#define PWR_BUS_EN_S 0 +#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */ +#define PWR_VOLTS_S 1 + +/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */ +#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */ +#define SW_RESET_ALL_S 0 +#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */ +#define SW_RESET_CMD_S 1 +#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */ +#define SW_RESET_DAT_S 2 + +/* SD_IntrStatus: Offset 0x030, size = 2 bytes */ +/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */ +#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */ +#define INTSTAT_CMD_COMPLETE_S 0 +#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1) +#define INTSTAT_XFER_COMPLETE_S 1 +#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1) +#define INTSTAT_BLOCK_GAP_EVENT_S 2 +#define INTSTAT_DMA_INT_M BITFIELD_MASK(1) +#define INTSTAT_DMA_INT_S 3 +#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1) +#define INTSTAT_BUF_WRITE_READY_S 4 +#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1) +#define INTSTAT_BUF_READ_READY_S 5 +#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1) +#define INTSTAT_CARD_INSERTION_S 6 +#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1) +#define INTSTAT_CARD_REMOVAL_S 7 +#define INTSTAT_CARD_INT_M BITFIELD_MASK(1) +#define INTSTAT_CARD_INT_S 8 +#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */ +#define INTSTAT_RETUNING_INT_S 12 +#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */ +#define INTSTAT_ERROR_INT_S 15 + +/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */ +/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */ +#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1) +#define ERRINT_CMD_TIMEOUT_S 0 +#define ERRINT_CMD_CRC_M BITFIELD_MASK(1) +#define ERRINT_CMD_CRC_S 1 +#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1) +#define ERRINT_CMD_ENDBIT_S 2 +#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1) +#define ERRINT_CMD_INDEX_S 3 +#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1) +#define ERRINT_DATA_TIMEOUT_S 4 +#define ERRINT_DATA_CRC_M BITFIELD_MASK(1) +#define ERRINT_DATA_CRC_S 5 +#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1) +#define ERRINT_DATA_ENDBIT_S 6 +#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1) +#define ERRINT_CURRENT_LIMIT_S 7 +#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1) +#define ERRINT_AUTO_CMD12_S 8 +#define ERRINT_VENDOR_M BITFIELD_MASK(4) +#define ERRINT_VENDOR_S 12 +#define ERRINT_ADMA_M BITFIELD_MASK(1) +#define ERRINT_ADMA_S 9 + +/* Also provide definitions in "normal" form to allow combined masks */ +#define ERRINT_CMD_TIMEOUT_BIT 0x0001 +#define ERRINT_CMD_CRC_BIT 0x0002 +#define ERRINT_CMD_ENDBIT_BIT 0x0004 +#define ERRINT_CMD_INDEX_BIT 0x0008 +#define ERRINT_DATA_TIMEOUT_BIT 0x0010 +#define ERRINT_DATA_CRC_BIT 0x0020 +#define ERRINT_DATA_ENDBIT_BIT 0x0040 +#define ERRINT_CURRENT_LIMIT_BIT 0x0080 +#define ERRINT_AUTO_CMD12_BIT 0x0100 +#define ERRINT_ADMA_BIT 0x0200 + +/* Masks to select CMD vs. DATA errors */ +#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\ + ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT) +#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\ + ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT) +#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS) + +/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */ +/* SD_ClockCntrl : Offset 0x02C , size = bytes */ +/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */ +/* SD_IntrStatus : Offset 0x030 , size = bytes */ +/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */ +/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */ +/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */ +/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */ +/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */ +/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */ +/* SD_Capabilities : Offset 0x040 , size = bytes */ +/* SD_MaxCurCap : Offset 0x048 , size = bytes */ +/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */ +/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */ +/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */ + +/* SDIO Host Control Register DMA Mode Definitions */ +#define SDIOH_SDMA_MODE 0 +#define SDIOH_ADMA1_MODE 1 +#define SDIOH_ADMA2_MODE 2 +#define SDIOH_ADMA2_64_MODE 3 + +#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ +#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ +#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ +#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ +#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ +#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ +#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ +#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ + +/* ADMA2 Descriptor Table Entry for 32-bit Address */ +typedef struct adma2_dscr_32b { + uint32 len_attr; + uint32 phys_addr; +} adma2_dscr_32b_t; + +/* ADMA1 Descriptor Table Entry */ +typedef struct adma1_dscr { + uint32 phys_addr_attr; +} adma1_dscr_t; + +#endif /* _SDIOH_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/sdiovar.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sdiovar.h new file mode 100644 index 000000000000..326b32d8dfb0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/sdiovar.h @@ -0,0 +1,58 @@ +/* + * Structure used by apps whose drivers access SDIO drivers. + * Pulled out separately so dhdu and wlu can both use it. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sdiovar.h 241182 2011-02-17 21:50:03Z $ + */ + +#ifndef _sdiovar_h_ +#define _sdiovar_h_ + +#include + +/* require default structure packing */ +#define BWL_DEFAULT_PACKING +#include + +typedef struct sdreg { + int func; + int offset; + int value; +} sdreg_t; + +/* Common msglevel constants */ +#define SDH_ERROR_VAL 0x0001 /* Error */ +#define SDH_TRACE_VAL 0x0002 /* Trace */ +#define SDH_INFO_VAL 0x0004 /* Info */ +#define SDH_DEBUG_VAL 0x0008 /* Debug */ +#define SDH_DATA_VAL 0x0010 /* Data */ +#define SDH_CTRL_VAL 0x0020 /* Control Regs */ +#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ +#define SDH_DMA_VAL 0x0080 /* DMA */ + +#define NUM_PREV_TRANSACTIONS 16 + + +#include + +#endif /* _sdiovar_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/siutils.h b/drivers/net/wireless/bcmdhd_bcm4356/include/siutils.h new file mode 100644 index 000000000000..4603169ec1b9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/siutils.h @@ -0,0 +1,589 @@ +/* + * Misc utility routines for accessing the SOC Interconnects + * of Broadcom HNBU chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: siutils.h 481602 2014-05-29 22:43:34Z $ + */ + +#ifndef _siutils_h_ +#define _siutils_h_ + +#ifdef SR_DEBUG +#include "wlioctl.h" +#endif /* SR_DEBUG */ + + +/* + * Data structure to export all chip specific common variables + * public (read-only) portion of siutils handle returned by si_attach()/si_kattach() + */ +struct si_pub { + uint socitype; /* SOCI_SB, SOCI_AI */ + + uint bustype; /* SI_BUS, PCI_BUS */ + 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 */ + uint32 cccaps; /* chip common capabilities */ + uint32 cccaps_ext; /* chip common capabilities extension */ + int pmurev; /* pmu core rev */ + uint32 pmucaps; /* pmu capabilities */ + uint boardtype; /* board type */ + uint boardrev; /* board rev */ + 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 */ + uint32 chipst; /* chip status */ + bool issim; /* chip is in simulation or emulation */ + uint socirev; /* SOC interconnect rev */ + bool pci_pr32414; + +}; + +/* for HIGH_ONLY driver, the si_t must be writable to allow states sync from BMAC to HIGH driver + * for monolithic driver, it is readonly to prevent accident change + */ +typedef const struct si_pub si_t; + +/* + * 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. + */ +#define SI_OSH NULL /* Use for si_kattach when no osh is available */ + +#define BADIDX (SI_MAXCORES + 1) + +/* 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 /* wireless interface is down */ +#define SI_PCIUP 3 /* wireless interface is up */ + +#ifdef SR_DEBUG +#define PMU_RES 31 +#endif /* SR_DEBUG */ + +#define ISSIM_ENAB(sih) FALSE + +/* PMU clock/power control */ +#if defined(BCMPMUCTL) +#define PMUCTL_ENAB(sih) (BCMPMUCTL) +#else +#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU) +#endif + +#define AOB_ENAB(sih) ((sih)->ccrev >= 35 ? \ + ((sih)->cccaps_ext & CC_CAP_EXT_AOB_PRESENT) : 0) + +/* chipcommon clock/power control (exclusive with PMU's) */ +#if defined(BCMPMUCTL) && BCMPMUCTL +#define CCCTL_ENAB(sih) (0) +#define CCPLL_ENAB(sih) (0) +#else +#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL) +#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK) +#endif + +typedef void (*gpio_handler_t)(uint32 stat, void *arg); +typedef void (*gci_gpio_handler_t)(uint32 stat, void *arg); +/* External BT Coex enable mask */ +#define CC_BTCOEX_EN_MASK 0x01 +/* External PA enable mask */ +#define GPIO_CTRL_EPA_EN_MASK 0x40 +/* WL/BT control enable mask */ +#define GPIO_CTRL_5_6_EN_MASK 0x60 +#define GPIO_CTRL_7_6_EN_MASK 0xC0 +#define GPIO_OUT_7_EN_MASK 0x80 + + +/* CR4 specific defines used by the host driver */ +#define SI_CR4_CAP (0x04) +#define SI_CR4_BANKIDX (0x40) +#define SI_CR4_BANKINFO (0x44) +#define SI_CR4_BANKPDA (0x4C) + +#define ARMCR4_TCBBNB_MASK 0xf0 +#define ARMCR4_TCBBNB_SHIFT 4 +#define ARMCR4_TCBANB_MASK 0xf +#define ARMCR4_TCBANB_SHIFT 0 + +#define SICF_CPUHALT (0x0020) +#define ARMCR4_BSZ_MASK 0x3f +#define ARMCR4_BSZ_MULT 8192 + +#include +/* === exported functions === */ +extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, + void *sdh, char **vars, uint *varsz); +extern si_t *si_kattach(osl_t *osh); +extern void si_detach(si_t *sih); +extern bool si_pci_war16165(si_t *sih); +extern void * +si_d11_switch_addrbase(si_t *sih, uint coreunit); +extern uint si_corelist(si_t *sih, uint coreid[]); +extern uint si_coreid(si_t *sih); +extern uint si_flag(si_t *sih); +extern uint si_flag_alt(si_t *sih); +extern uint si_intflag(si_t *sih); +extern uint si_coreidx(si_t *sih); +extern uint si_coreunit(si_t *sih); +extern uint si_corevendor(si_t *sih); +extern uint si_corerev(si_t *sih); +extern void *si_osh(si_t *sih); +extern void si_setosh(si_t *sih, osl_t *osh); +extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); +extern uint si_pmu_corereg(si_t *sih, uint32 idx, uint regoff, uint mask, uint val); +extern uint32 *si_corereg_addr(si_t *sih, uint coreidx, uint regoff); +extern void *si_coreregs(si_t *sih); +extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); +extern uint si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val); +extern void *si_wrapperregs(si_t *sih); +extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); +extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); +extern bool si_iscoreup(si_t *sih); +extern uint si_numcoreunits(si_t *sih, uint coreid); +extern uint si_numd11coreunits(si_t *sih); +extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); +extern void *si_setcoreidx(si_t *sih, uint coreidx); +extern void *si_setcore(si_t *sih, uint coreid, uint coreunit); +extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); +extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); +extern int si_numaddrspaces(si_t *sih); +extern uint32 si_addrspace(si_t *sih, uint asidx); +extern uint32 si_addrspacesize(si_t *sih, uint asidx); +extern void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); +extern int si_corebist(si_t *sih); +extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); +extern void si_core_disable(si_t *sih, uint32 bits); +extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); +extern uint si_chip_hostif(si_t *sih); +extern bool si_read_pmu_autopll(si_t *sih); +extern uint32 si_clock(si_t *sih); +extern uint32 si_alp_clock(si_t *sih); /* returns [Hz] units */ +extern uint32 si_ilp_clock(si_t *sih); /* returns [Hz] units */ +extern void si_pci_setup(si_t *sih, uint coremask); +extern void si_pcmcia_init(si_t *sih); +extern void si_setint(si_t *sih, int siflag); +extern bool si_backplane64(si_t *sih); +extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, + void *intrsenabled_fn, void *intr_arg); +extern void si_deregister_intr_callback(si_t *sih); +extern void si_clkctl_init(si_t *sih); +extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); +extern bool si_clkctl_cc(si_t *sih, uint mode); +extern int si_clkctl_xtal(si_t *sih, uint what, bool on); +extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); +extern void si_btcgpiowar(si_t *sih); +extern bool si_deviceremoved(si_t *sih); +extern uint32 si_socram_size(si_t *sih); +extern uint32 si_socdevram_size(si_t *sih); +extern uint32 si_socram_srmem_size(si_t *sih); +extern void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda); +extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect, uint8 *remap); +extern bool si_socdevram_pkg(si_t *sih); +extern bool si_socdevram_remap_isenb(si_t *sih); +extern uint32 si_socdevram_remap_size(si_t *sih); + +extern void si_watchdog(si_t *sih, uint ticks); +extern void si_watchdog_ms(si_t *sih, uint32 ms); +extern uint32 si_watchdog_msticks(void); +extern void *si_gpiosetcore(si_t *sih); +extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioin(si_t *sih); +extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); +extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); +extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); +extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); +extern uint32 si_gpio_int_enable(si_t *sih, bool enable); +extern void si_gci_uart_init(si_t *sih, osl_t *osh, uint8 seci_mode); +extern void si_gci_enable_gpio(si_t *sih, uint8 gpio, uint32 mask, uint32 value); +extern uint8 si_gci_host_wake_gpio_init(si_t *sih); +extern void si_gci_host_wake_gpio_enable(si_t *sih, uint8 gpio, bool state); + +/* GPIO event handlers */ +extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg); +extern void si_gpio_handler_unregister(si_t *sih, void* gpioh); +extern void si_gpio_handler_process(si_t *sih); + +/* GCI interrupt handlers */ +extern void si_gci_handler_process(si_t *sih); + +/* GCI GPIO event handlers */ +extern void *si_gci_gpioint_handler_register(si_t *sih, uint8 gpio, uint8 sts, + gci_gpio_handler_t cb, void *arg); +extern void si_gci_gpioint_handler_unregister(si_t *sih, void* gci_i); +extern uint8 si_gci_gpio_status(si_t *sih, uint8 gci_gpio, uint8 mask, uint8 value); + +/* Wake-on-wireless-LAN (WOWL) */ +extern bool si_pci_pmecap(si_t *sih); +extern bool si_pci_fastpmecap(struct osl_info *osh); +extern bool si_pci_pmestat(si_t *sih); +extern void si_pci_pmeclr(si_t *sih); +extern void si_pci_pmeen(si_t *sih); +extern void si_pci_pmestatclr(si_t *sih); +extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); +extern uint si_pcie_writereg(void *sih, uint addrtype, uint offset, uint val); + + +#ifdef BCMSDIO +extern void si_sdio_init(si_t *sih); +#endif + +extern uint16 si_d11_devid(si_t *sih); +extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, + uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); + +#define si_eci(sih) 0 +static INLINE void * si_eci_init(si_t *sih) {return NULL;} +#define si_eci_notify_bt(sih, type, val) (0) +#define si_seci(sih) 0 +#define si_seci_upd(sih, a) do {} while (0) +static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} +static INLINE void * si_gci_init(si_t *sih) {return NULL;} +#define si_seci_down(sih) do {} while (0) +#define si_gci(sih) 0 + +/* OTP status */ +extern bool si_is_otp_disabled(si_t *sih); +extern bool si_is_otp_powered(si_t *sih); +extern void si_otp_power(si_t *sih, bool on, uint32* min_res_mask); + +/* SPROM availability */ +extern bool si_is_sprom_available(si_t *sih); +extern bool si_is_sprom_enabled(si_t *sih); +extern void si_sprom_enable(si_t *sih, bool enable); + +/* OTP/SROM CIS stuff */ +extern int si_cis_source(si_t *sih); +#define CIS_DEFAULT 0 +#define CIS_SROM 1 +#define CIS_OTP 2 + +/* Fab-id information */ +#define DEFAULT_FAB 0x0 /* Original/first fab used for this chip */ +#define CSM_FAB7 0x1 /* CSM Fab7 chip */ +#define TSMC_FAB12 0x2 /* TSMC Fab12/Fab14 chip */ +#define SMIC_FAB4 0x3 /* SMIC Fab4 chip */ + +extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw); +extern uint16 si_fabid(si_t *sih); +extern uint16 si_chipid(si_t *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 si_devpath(si_t *sih, char *path, int size); +extern int si_devpath_pcie(si_t *sih, char *path, int size); +/* Read variable with prepending the devpath to the name */ +extern char *si_getdevpathvar(si_t *sih, const char *name); +extern int si_getdevpathintvar(si_t *sih, const char *name); +extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const char *name); + + +extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); +extern uint8 si_pcieltrenable(si_t *sih, uint32 mask, uint32 val); +extern uint8 si_pcieobffenable(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcieltr_reg(si_t *sih, uint32 reg, uint32 mask, uint32 val); +extern uint32 si_pcieltrspacing_reg(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcieltrhysteresiscnt_reg(si_t *sih, uint32 mask, uint32 val); +extern void si_pcie_set_error_injection(si_t *sih, uint32 mode); +extern void si_pcie_set_L1substate(si_t *sih, uint32 substate); +extern uint32 si_pcie_get_L1substate(si_t *sih); +extern void si_war42780_clkreq(si_t *sih, bool clkreq); +extern void si_pci_down(si_t *sih); +extern void si_pci_up(si_t *sih); +extern void si_pci_sleep(si_t *sih); +extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); +extern void si_pcie_power_save_enable(si_t *sih, bool enable); +extern void si_pcie_extendL1timer(si_t *sih, bool extend); +extern int si_pci_fixcfg(si_t *sih); +extern void si_chippkg_set(si_t *sih, uint); + +extern void si_chipcontrl_btshd0_4331(si_t *sih, bool on); +extern void si_chipcontrl_restore(si_t *sih, uint32 val); +extern uint32 si_chipcontrl_read(si_t *sih); +extern void si_chipcontrl_epa4331(si_t *sih, bool on); +extern void si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl); +extern void si_chipcontrl_srom4360(si_t *sih, bool on); +/* Enable BT-COEX & Ex-PA for 4313 */ +extern void si_epa_4313war(si_t *sih); +extern void si_btc_enable_chipcontrol(si_t *sih); +/* BT/WL selection for 4313 bt combo >= P250 boards */ +extern void si_btcombo_p250_4313_war(si_t *sih); +extern void si_btcombo_43228_war(si_t *sih); +extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); +extern void si_pmu_synth_pwrsw_4313_war(si_t *sih); +extern uint si_pll_reset(si_t *sih); +/* === debug routines === */ + +extern bool si_taclear(si_t *sih, bool details); + + +#if defined(BCMDBG_PHYDUMP) +extern void si_dumpregs(si_t *sih, struct bcmstrbuf *b); +#endif + +extern uint32 si_ccreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); +extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); +#ifdef SR_DEBUG +extern void si_dump_pmu(si_t *sih, void *pmu_var); +extern void si_pmu_keep_on(si_t *sih, int32 int_val); +extern uint32 si_pmu_keep_on_get(si_t *sih); +extern uint32 si_power_island_set(si_t *sih, uint32 int_val); +extern uint32 si_power_island_get(si_t *sih); +#endif /* SR_DEBUG */ +extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); +extern void si_pcie_set_request_size(si_t *sih, uint16 size); +extern uint16 si_pcie_get_request_size(si_t *sih); +extern void si_pcie_set_maxpayload_size(si_t *sih, uint16 size); +extern uint16 si_pcie_get_maxpayload_size(si_t *sih); +extern uint16 si_pcie_get_ssid(si_t *sih); +extern uint32 si_pcie_get_bar0(si_t *sih); +extern int si_pcie_configspace_cache(si_t *sih); +extern int si_pcie_configspace_restore(si_t *sih); +extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); + +char *si_getnvramflvar(si_t *sih, const char *name); + + +extern uint32 si_tcm_size(si_t *sih); +extern bool si_has_flops(si_t *sih); + +extern int si_set_sromctl(si_t *sih, uint32 value); +extern uint32 si_get_sromctl(si_t *sih); + +extern uint32 si_gci_direct(si_t *sih, uint offset, uint32 mask, uint32 val); +extern uint32 si_gci_indirect(si_t *sih, uint regidx, uint offset, uint32 mask, uint32 val); +extern uint32 si_gci_output(si_t *sih, uint reg, uint32 mask, uint32 val); +extern uint32 si_gci_input(si_t *sih, uint reg); +extern uint32 si_gci_int_enable(si_t *sih, bool enable); +extern void si_gci_reset(si_t *sih); +#ifdef BCMLTECOEX +extern void si_gci_seci_init(si_t *sih); +extern void si_ercx_init(si_t *sih, uint32 ltecx_mux, uint32 ltecx_padnum, + uint32 ltecx_fnsel, uint32 ltecx_gcigpio); +extern void si_wci2_init(si_t *sih, uint8 baudrate, uint32 ltecx_mux, uint32 ltecx_padnum, + uint32 ltecx_fnsel, uint32 ltecx_gcigpio); +#endif /* BCMLTECOEX */ +extern void si_gci_set_functionsel(si_t *sih, uint32 pin, uint8 fnsel); +extern uint32 si_gci_get_functionsel(si_t *sih, uint32 pin); +extern void si_gci_clear_functionsel(si_t *sih, uint8 fnsel); +extern uint8 si_gci_get_chipctrlreg_idx(uint32 pin, uint32 *regidx, uint32 *pos); +extern uint32 si_gci_chipcontrol(si_t *sih, uint reg, uint32 mask, uint32 val); +extern uint32 si_gci_chipstatus(si_t *sih, uint reg); +extern uint16 si_cc_get_reg16(uint32 reg_offs); +extern uint32 si_cc_get_reg32(uint32 reg_offs); +extern uint32 si_cc_set_reg32(uint32 reg_offs, uint32 val); +extern uint32 si_gci_preinit_upd_indirect(uint32 regidx, uint32 setval, uint32 mask); +extern uint8 si_enable_device_wake(si_t *sih, uint8 *wake_status, uint8 *cur_status); +extern void si_swdenable(si_t *sih, uint32 swdflag); + +#define CHIPCTRLREG1 0x1 +#define CHIPCTRLREG2 0x2 +#define CHIPCTRLREG3 0x3 +#define CHIPCTRLREG4 0x4 +#define CHIPCTRLREG5 0x5 +#define MINRESMASKREG 0x618 +#define MAXRESMASKREG 0x61c +#define CHIPCTRLADDR 0x650 +#define CHIPCTRLDATA 0x654 +#define RSRCTABLEADDR 0x620 +#define RSRCUPDWNTIME 0x628 +#define PMUREG_RESREQ_MASK 0x68c + +void si_update_masks(si_t *sih); +void si_force_islanding(si_t *sih, bool enable); +extern uint32 si_pmu_res_req_timer_clr(si_t *sih); +extern void si_pmu_rfldo(si_t *sih, bool on); +extern void si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 spert_val); +extern uint32 si_pcie_set_ctrlreg(si_t *sih, uint32 sperst_mask, uint32 spert_val); +extern void si_pcie_ltr_war(si_t *sih); +extern void si_pcie_hw_LTR_war(si_t *sih); +extern void si_pcie_hw_L1SS_war(si_t *sih); +extern void si_pciedev_crwlpciegen2(si_t *sih); +extern void si_pcie_prep_D3(si_t *sih, bool enter_D3); +extern void si_pciedev_reg_pm_clk_period(si_t *sih); + +#ifdef WLRSDB +extern void si_d11rsdb_core_disable(si_t *sih, uint32 bits); +extern void si_d11rsdb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); +#endif + + +/* Macro to enable clock gating changes in different cores */ +#define MEM_CLK_GATE_BIT 5 +#define GCI_CLK_GATE_BIT 18 + +#define USBAPP_CLK_BIT 0 +#define PCIE_CLK_BIT 3 +#define ARMCR4_DBG_CLK_BIT 4 +#define SAMPLE_SYNC_CLK_BIT 17 +#define PCIE_TL_CLK_BIT 18 +#define HQ_REQ_BIT 24 +#define PLL_DIV2_BIT_START 9 +#define PLL_DIV2_MASK (0x37 << PLL_DIV2_BIT_START) +#define PLL_DIV2_DIS_OP (0x37 << PLL_DIV2_BIT_START) + +#define PMUREG(si, member) \ + (AOB_ENAB(si) ? \ + si_corereg_addr(si, si_findcoreidx(si, PMU_CORE_ID, 0), \ + OFFSETOF(pmuregs_t, member)): \ + si_corereg_addr(si, SI_CC_IDX, OFFSETOF(chipcregs_t, member))) + +#define pmu_corereg(si, cc_idx, member, mask, val) \ + (AOB_ENAB(si) ? \ + si_pmu_corereg(si, si_findcoreidx(sih, PMU_CORE_ID, 0), \ + OFFSETOF(pmuregs_t, member), mask, val): \ + si_pmu_corereg(si, cc_idx, OFFSETOF(chipcregs_t, member), mask, val)) + +/* GCI Macros */ +#define ALLONES_32 0xFFFFFFFF +#define GCI_CCTL_SECIRST_OFFSET 0 /* SeciReset */ +#define GCI_CCTL_RSTSL_OFFSET 1 /* ResetSeciLogic */ +#define GCI_CCTL_SECIEN_OFFSET 2 /* EnableSeci */ +#define GCI_CCTL_FSL_OFFSET 3 /* ForceSeciOutLow */ +#define GCI_CCTL_SMODE_OFFSET 4 /* SeciOpMode, 6:4 */ +#define GCI_CCTL_US_OFFSET 7 /* UpdateSeci */ +#define GCI_CCTL_BRKONSLP_OFFSET 8 /* BreakOnSleep */ +#define GCI_CCTL_SILOWTOUT_OFFSET 9 /* SeciInLowTimeout, 10:9 */ +#define GCI_CCTL_RSTOCC_OFFSET 11 /* ResetOffChipCoex */ +#define GCI_CCTL_ARESEND_OFFSET 12 /* AutoBTSigResend */ +#define GCI_CCTL_FGCR_OFFSET 16 /* ForceGciClkReq */ +#define GCI_CCTL_FHCRO_OFFSET 17 /* ForceHWClockReqOff */ +#define GCI_CCTL_FREGCLK_OFFSET 18 /* ForceRegClk */ +#define GCI_CCTL_FSECICLK_OFFSET 19 /* ForceSeciClk */ +#define GCI_CCTL_FGCA_OFFSET 20 /* ForceGciClkAvail */ +#define GCI_CCTL_FGCAV_OFFSET 21 /* ForceGciClkAvailValue */ +#define GCI_CCTL_SCS_OFFSET 24 /* SeciClkStretch, 31:24 */ + +#define GCI_MODE_UART 0x0 +#define GCI_MODE_SECI 0x1 +#define GCI_MODE_BTSIG 0x2 +#define GCI_MODE_GPIO 0x3 +#define GCI_MODE_MASK 0x7 + +#define GCI_CCTL_LOWTOUT_DIS 0x0 +#define GCI_CCTL_LOWTOUT_10BIT 0x1 +#define GCI_CCTL_LOWTOUT_20BIT 0x2 +#define GCI_CCTL_LOWTOUT_30BIT 0x3 +#define GCI_CCTL_LOWTOUT_MASK 0x3 + +#define GCI_CCTL_SCS_DEF 0x19 +#define GCI_CCTL_SCS_MASK 0xFF + +#define GCI_SECIIN_MODE_OFFSET 0 +#define GCI_SECIIN_GCIGPIO_OFFSET 4 +#define GCI_SECIIN_RXID2IP_OFFSET 8 + +#define GCI_SECIOUT_MODE_OFFSET 0 +#define GCI_SECIOUT_GCIGPIO_OFFSET 4 +#define GCI_SECIOUT_SECIINRELATED_OFFSET 16 + +#define GCI_SECIAUX_RXENABLE_OFFSET 0 +#define GCI_SECIFIFO_RXENABLE_OFFSET 16 + +#define GCI_SECITX_ENABLE_OFFSET 0 + +#define GCI_GPIOCTL_INEN_OFFSET 0 +#define GCI_GPIOCTL_OUTEN_OFFSET 1 +#define GCI_GPIOCTL_PDN_OFFSET 4 + +#define GCI_GPIOIDX_OFFSET 16 + +#define GCI_LTECX_SECI_ID 0 /* SECI port for LTECX */ + +/* To access per GCI bit registers */ +#define GCI_REG_WIDTH 32 + +/* GCI bit positions */ +/* GCI [127:000] = WLAN [127:0] */ +#define GCI_WLAN_IP_ID 0 +#define GCI_WLAN_BEGIN 0 +#define GCI_WLAN_PRIO_POS (GCI_WLAN_BEGIN + 4) + +/* GCI [639:512] = LTE [127:0] */ +#define GCI_LTE_IP_ID 4 +#define GCI_LTE_BEGIN 512 +#define GCI_LTE_FRAMESYNC_POS (GCI_LTE_BEGIN + 0) +#define GCI_LTE_RX_POS (GCI_LTE_BEGIN + 1) +#define GCI_LTE_TX_POS (GCI_LTE_BEGIN + 2) +#define GCI_LTE_AUXRXDVALID_POS (GCI_LTE_BEGIN + 56) + +/* Reg Index corresponding to ECI bit no x of ECI space */ +#define GCI_REGIDX(x) ((x)/GCI_REG_WIDTH) +/* Bit offset of ECI bit no x in 32-bit words */ +#define GCI_BITOFFSET(x) ((x)%GCI_REG_WIDTH) + +/* End - GCI Macros */ + +#ifdef REROUTE_OOBINT +#define CC_OOB 0x0 +#define M2MDMA_OOB 0x1 +#define PMU_OOB 0x2 +#define D11_OOB 0x3 +#define SDIOD_OOB 0x4 +#define PMU_OOB_BIT (0x10 | PMU_OOB) +#endif /* REROUTE_OOBINT */ + + +#endif /* _siutils_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/spid.h b/drivers/net/wireless/bcmdhd_bcm4356/include/spid.h new file mode 100644 index 000000000000..b5d7b675748d --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/spid.h @@ -0,0 +1,165 @@ +/* + * SPI device spec header file + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: spid.h 358377 2012-09-23 11:30:22Z $ + */ + +#ifndef _SPI_H +#define _SPI_H + +/* + * Brcm SPI Device Register Map. + * + */ + +typedef volatile struct { + uint8 config; /* 0x00, len, endian, clock, speed, polarity, wakeup */ + uint8 response_delay; /* 0x01, read response delay in bytes (corerev < 3) */ + uint8 status_enable; /* 0x02, status-enable, intr with status, response_delay + * function selection, command/data error check + */ + uint8 reset_bp; /* 0x03, reset on wlan/bt backplane reset (corerev >= 1) */ + uint16 intr_reg; /* 0x04, Intr status register */ + uint16 intr_en_reg; /* 0x06, Intr mask register */ + uint32 status_reg; /* 0x08, RO, Status bits of last spi transfer */ + uint16 f1_info_reg; /* 0x0c, RO, enabled, ready for data transfer, blocksize */ + uint16 f2_info_reg; /* 0x0e, RO, enabled, ready for data transfer, blocksize */ + uint16 f3_info_reg; /* 0x10, RO, enabled, ready for data transfer, blocksize */ + uint32 test_read; /* 0x14, RO 0xfeedbead signature */ + uint32 test_rw; /* 0x18, RW */ + uint8 resp_delay_f0; /* 0x1c, read resp delay bytes for F0 (corerev >= 3) */ + uint8 resp_delay_f1; /* 0x1d, read resp delay bytes for F1 (corerev >= 3) */ + uint8 resp_delay_f2; /* 0x1e, read resp delay bytes for F2 (corerev >= 3) */ + uint8 resp_delay_f3; /* 0x1f, read resp delay bytes for F3 (corerev >= 3) */ +} spi_regs_t; + +/* SPI device register offsets */ +#define SPID_CONFIG 0x00 +#define SPID_RESPONSE_DELAY 0x01 +#define SPID_STATUS_ENABLE 0x02 +#define SPID_RESET_BP 0x03 /* (corerev >= 1) */ +#define SPID_INTR_REG 0x04 /* 16 bits - Interrupt status */ +#define SPID_INTR_EN_REG 0x06 /* 16 bits - Interrupt mask */ +#define SPID_STATUS_REG 0x08 /* 32 bits */ +#define SPID_F1_INFO_REG 0x0C /* 16 bits */ +#define SPID_F2_INFO_REG 0x0E /* 16 bits */ +#define SPID_F3_INFO_REG 0x10 /* 16 bits */ +#define SPID_TEST_READ 0x14 /* 32 bits */ +#define SPID_TEST_RW 0x18 /* 32 bits */ +#define SPID_RESP_DELAY_F0 0x1c /* 8 bits (corerev >= 3) */ +#define SPID_RESP_DELAY_F1 0x1d /* 8 bits (corerev >= 3) */ +#define SPID_RESP_DELAY_F2 0x1e /* 8 bits (corerev >= 3) */ +#define SPID_RESP_DELAY_F3 0x1f /* 8 bits (corerev >= 3) */ + +/* Bit masks for SPID_CONFIG device register */ +#define WORD_LENGTH_32 0x1 /* 0/1 16/32 bit word length */ +#define ENDIAN_BIG 0x2 /* 0/1 Little/Big Endian */ +#define CLOCK_PHASE 0x4 /* 0/1 clock phase delay */ +#define CLOCK_POLARITY 0x8 /* 0/1 Idle state clock polarity is low/high */ +#define HIGH_SPEED_MODE 0x10 /* 1/0 High Speed mode / Normal mode */ +#define INTR_POLARITY 0x20 /* 1/0 Interrupt active polarity is high/low */ +#define WAKE_UP 0x80 /* 0/1 Wake-up command from Host to WLAN */ + +/* Bit mask for SPID_RESPONSE_DELAY device register */ +#define RESPONSE_DELAY_MASK 0xFF /* Configurable rd response delay in multiples of 8 bits */ + +/* Bit mask for SPID_STATUS_ENABLE device register */ +#define STATUS_ENABLE 0x1 /* 1/0 Status sent/not sent to host after read/write */ +#define INTR_WITH_STATUS 0x2 /* 0/1 Do-not / do-interrupt if status is sent */ +#define RESP_DELAY_ALL 0x4 /* Applicability of resp delay to F1 or all func's read */ +#define DWORD_PKT_LEN_EN 0x8 /* Packet len denoted in dwords instead of bytes */ +#define CMD_ERR_CHK_EN 0x20 /* Command error check enable */ +#define DATA_ERR_CHK_EN 0x40 /* Data error check enable */ + +/* Bit mask for SPID_RESET_BP device register */ +#define RESET_ON_WLAN_BP_RESET 0x4 /* enable reset for WLAN backplane */ +#define RESET_ON_BT_BP_RESET 0x8 /* enable reset for BT backplane */ +#define RESET_SPI 0x80 /* reset the above enabled logic */ + +/* Bit mask for SPID_INTR_REG device register */ +#define DATA_UNAVAILABLE 0x0001 /* Requested data not available; Clear by writing a "1" */ +#define F2_F3_FIFO_RD_UNDERFLOW 0x0002 +#define F2_F3_FIFO_WR_OVERFLOW 0x0004 +#define COMMAND_ERROR 0x0008 /* Cleared by writing 1 */ +#define DATA_ERROR 0x0010 /* Cleared by writing 1 */ +#define F2_PACKET_AVAILABLE 0x0020 +#define F3_PACKET_AVAILABLE 0x0040 +#define F1_OVERFLOW 0x0080 /* Due to last write. Bkplane has pending write requests */ +#define MISC_INTR0 0x0100 +#define MISC_INTR1 0x0200 +#define MISC_INTR2 0x0400 +#define MISC_INTR3 0x0800 +#define MISC_INTR4 0x1000 +#define F1_INTR 0x2000 +#define F2_INTR 0x4000 +#define F3_INTR 0x8000 + +/* Bit mask for 32bit SPID_STATUS_REG device register */ +#define STATUS_DATA_NOT_AVAILABLE 0x00000001 +#define STATUS_UNDERFLOW 0x00000002 +#define STATUS_OVERFLOW 0x00000004 +#define STATUS_F2_INTR 0x00000008 +#define STATUS_F3_INTR 0x00000010 +#define STATUS_F2_RX_READY 0x00000020 +#define STATUS_F3_RX_READY 0x00000040 +#define STATUS_HOST_CMD_DATA_ERR 0x00000080 +#define STATUS_F2_PKT_AVAILABLE 0x00000100 +#define STATUS_F2_PKT_LEN_MASK 0x000FFE00 +#define STATUS_F2_PKT_LEN_SHIFT 9 +#define STATUS_F3_PKT_AVAILABLE 0x00100000 +#define STATUS_F3_PKT_LEN_MASK 0xFFE00000 +#define STATUS_F3_PKT_LEN_SHIFT 21 + +/* Bit mask for 16 bits SPID_F1_INFO_REG device register */ +#define F1_ENABLED 0x0001 +#define F1_RDY_FOR_DATA_TRANSFER 0x0002 +#define F1_MAX_PKT_SIZE 0x01FC + +/* Bit mask for 16 bits SPID_F2_INFO_REG device register */ +#define F2_ENABLED 0x0001 +#define F2_RDY_FOR_DATA_TRANSFER 0x0002 +#define F2_MAX_PKT_SIZE 0x3FFC + +/* Bit mask for 16 bits SPID_F3_INFO_REG device register */ +#define F3_ENABLED 0x0001 +#define F3_RDY_FOR_DATA_TRANSFER 0x0002 +#define F3_MAX_PKT_SIZE 0x3FFC + +/* Bit mask for 32 bits SPID_TEST_READ device register read in 16bit LE mode */ +#define TEST_RO_DATA_32BIT_LE 0xFEEDBEAD + +/* Maximum number of I/O funcs */ +#define SPI_MAX_IOFUNCS 4 + +#define SPI_MAX_PKT_LEN (2048*4) + +/* Misc defines */ +#define SPI_FUNC_0 0 +#define SPI_FUNC_1 1 +#define SPI_FUNC_2 2 +#define SPI_FUNC_3 3 + +#define WAIT_F2RXFIFORDY 100 +#define WAIT_F2RXFIFORDY_DELAY 20 + +#endif /* _SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/trxhdr.h b/drivers/net/wireless/bcmdhd_bcm4356/include/trxhdr.h new file mode 100644 index 000000000000..5ea40e739e31 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/trxhdr.h @@ -0,0 +1,92 @@ +/* + * TRX image file header format. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: trxhdr.h 349211 2012-08-07 09:45:24Z $ + */ + +#ifndef _TRX_HDR_H +#define _TRX_HDR_H + +#include + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ +#define TRX_MAX_LEN 0x3B0000 /* Max length */ +#define TRX_NO_HEADER 1 /* Do not write TRX header */ +#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ +#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ +#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ +#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ +#define TRX_BOOTLOADER 0x40 /* the image is a bootloader */ + +#define TRX_V1 1 +#define TRX_V1_MAX_OFFSETS 3 /* V1: Max number of individual files */ + +#ifndef BCMTRXV2 +#define TRX_VERSION TRX_V1 /* Version 1 */ +#define TRX_MAX_OFFSET TRX_V1_MAX_OFFSETS +#endif + +/* BMAC Host driver/application like bcmdl need to support both Ver 1 as well as + * Ver 2 of trx header. To make it generic, trx_header is structure is modified + * as below where size of "offsets" field will vary as per the TRX version. + * Currently, BMAC host driver and bcmdl are modified to support TRXV2 as well. + * To make sure, other applications like "dhdl" which are yet to be enhanced to support + * TRXV2 are not broken, new macro and structure defintion take effect only when BCMTRXV2 + * is defined. + */ +struct trx_header { + uint32 magic; /* "HDR0" */ + uint32 len; /* Length of file including header */ + uint32 crc32; /* 32-bit CRC from flag_version to end of file */ + uint32 flag_version; /* 0:15 flags, 16:31 version */ +#ifndef BCMTRXV2 + uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ +#else + uint32 offsets[1]; /* Offsets of partitions from start of header */ +#endif +}; + +#ifdef BCMTRXV2 +#define TRX_VERSION TRX_V2 /* Version 2 */ +#define TRX_MAX_OFFSET TRX_V2_MAX_OFFSETS + +#define TRX_V2 2 +/* V2: Max number of individual files + * To support SDR signature + Config data region + */ +#define TRX_V2_MAX_OFFSETS 5 +#define SIZEOF_TRXHDR_V1 (sizeof(struct trx_header)+(TRX_V1_MAX_OFFSETS-1)*sizeof(uint32)) +#define SIZEOF_TRXHDR_V2 (sizeof(struct trx_header)+(TRX_V2_MAX_OFFSETS-1)*sizeof(uint32)) +#define TRX_VER(trx) (trx->flag_version>>16) +#define ISTRX_V1(trx) (TRX_VER(trx) == TRX_V1) +#define ISTRX_V2(trx) (TRX_VER(trx) == TRX_V2) +/* For V2, return size of V2 size: others, return V1 size */ +#define SIZEOF_TRX(trx) (ISTRX_V2(trx) ? SIZEOF_TRXHDR_V2: SIZEOF_TRXHDR_V1) +#else +#define SIZEOF_TRX(trx) (sizeof(struct trx_header)) +#endif /* BCMTRXV2 */ + +/* Compatibility */ +typedef struct trx_header TRXHDR, *PTRXHDR; + +#endif /* _TRX_HDR_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/typedefs.h b/drivers/net/wireless/bcmdhd_bcm4356/include/typedefs.h new file mode 100644 index 000000000000..a0ea58926161 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/typedefs.h @@ -0,0 +1,339 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: typedefs.h 484281 2014-06-12 22:42:26Z $ + */ + +#ifndef _TYPEDEFS_H_ +#define _TYPEDEFS_H_ + +#ifdef SITE_TYPEDEFS + +/* + * Define SITE_TYPEDEFS in the compile to include a site-specific + * typedef file "site_typedefs.h". + * + * If SITE_TYPEDEFS is not defined, then the code section below makes + * inferences about the compile environment based on defined symbols and + * possibly compiler pragmas. + * + * Following these two sections is the Default Typedefs section. + * This section is only processed if USE_TYPEDEF_DEFAULTS is + * defined. This section has a default set of typedefs and a few + * preprocessor symbols (TRUE, FALSE, NULL, ...). + */ + +#include "site_typedefs.h" + +#else + +/* + * Infer the compile environment based on preprocessor symbols and pragmas. + * Override type definitions as needed, and include configuration-dependent + * header files to define types. + */ + +#ifdef __cplusplus + +#define TYPEDEF_BOOL +#ifndef FALSE +#define FALSE false +#endif +#ifndef TRUE +#define TRUE true +#endif + +#else /* ! __cplusplus */ + + +#endif /* ! __cplusplus */ + +#if defined(__LP64__) +#define TYPEDEF_UINTPTR +typedef unsigned long long int uintptr; +#endif + + + + + +#if defined(_NEED_SIZE_T_) +typedef long unsigned int size_t; +#endif + + + + + +#if defined(__sparc__) +#define TYPEDEF_ULONG +#endif + +/* + * If this is either a Linux hybrid build or the per-port code of a hybrid build + * then use the Linux header files to get some of the typedefs. Otherwise, define + * them entirely in this file. We can't always define the types because we get + * a duplicate typedef error; there is no way to "undefine" a typedef. + * We know when it's per-port code because each file defines LINUX_PORT at the top. + */ +#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) +#define TYPEDEF_UINT +#ifndef TARGETENV_android +#define TYPEDEF_USHORT +#define TYPEDEF_ULONG +#endif /* TARGETENV_android */ +#ifdef __KERNEL__ +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) +#define TYPEDEF_BOOL +#endif /* >= 2.6.19 */ +/* special detection for 2.6.18-128.7.1.0.1.el5 */ +#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) +#include +#ifdef noinline_for_stack +#define TYPEDEF_BOOL +#endif +#endif /* == 2.6.18 */ +#endif /* __KERNEL__ */ +#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ + + +/* Do not support the (u)int64 types with strict ansi for GNU C */ +#if defined(__GNUC__) && defined(__STRICT_ANSI__) +#define TYPEDEF_INT64 +#define TYPEDEF_UINT64 +#endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */ + +/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode + * for signed or unsigned + */ +#if defined(__ICL) + +#define TYPEDEF_INT64 + +#if defined(__STDC__) +#define TYPEDEF_UINT64 +#endif + +#endif /* __ICL */ + +#if !defined(__DJGPP__) + +/* pick up ushort & uint from standard types.h */ +#if defined(__KERNEL__) + +/* See note above */ +#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) +#include /* sys/types.h and linux/types.h are oil and water */ +#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ + +#else + +#include + +#endif /* linux && __KERNEL__ */ + +#endif + + +/* use the default typedefs in the next section of this file */ +#define USE_TYPEDEF_DEFAULTS + +#endif /* SITE_TYPEDEFS */ + + +/* + * Default Typedefs + */ + +#ifdef USE_TYPEDEF_DEFAULTS +#undef USE_TYPEDEF_DEFAULTS + +#ifndef TYPEDEF_BOOL +typedef /* @abstract@ */ unsigned char bool; +#endif /* endif TYPEDEF_BOOL */ + +/* define uchar, ushort, uint, ulong */ + +#ifndef TYPEDEF_UCHAR +typedef unsigned char uchar; +#endif + +#ifndef TYPEDEF_USHORT +typedef unsigned short ushort; +#endif + +#ifndef TYPEDEF_UINT +typedef unsigned int uint; +#endif + +#ifndef TYPEDEF_ULONG +typedef unsigned long ulong; +#endif + +/* define [u]int8/16/32/64, uintptr */ + +#ifndef TYPEDEF_UINT8 +typedef unsigned char uint8; +#endif + +#ifndef TYPEDEF_UINT16 +typedef unsigned short uint16; +#endif + +#ifndef TYPEDEF_UINT32 +typedef unsigned int uint32; +#endif + +#ifndef TYPEDEF_UINT64 +typedef unsigned long long uint64; +#endif + +#ifndef TYPEDEF_UINTPTR +typedef unsigned int uintptr; +#endif + +#ifndef TYPEDEF_INT8 +typedef signed char int8; +#endif + +#ifndef TYPEDEF_INT16 +typedef signed short int16; +#endif + +#ifndef TYPEDEF_INT32 +typedef signed int int32; +#endif + +#ifndef TYPEDEF_INT64 +typedef signed long long int64; +#endif + +/* define float32/64, float_t */ + +#ifndef TYPEDEF_FLOAT32 +typedef float float32; +#endif + +#ifndef TYPEDEF_FLOAT64 +typedef double float64; +#endif + +/* + * abstracted floating point type allows for compile time selection of + * single or double precision arithmetic. Compiling with -DFLOAT32 + * selects single precision; the default is double precision. + */ + +#ifndef TYPEDEF_FLOAT_T + +#if defined(FLOAT32) +typedef float32 float_t; +#else /* default to double precision floating point */ +typedef float64 float_t; +#endif + +#endif /* TYPEDEF_FLOAT_T */ + +/* define macro values */ + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 /* TRUE */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef OFF +#define OFF 0 +#endif + +#ifndef ON +#define ON 1 /* ON = 1 */ +#endif + +#define AUTO (-1) /* Auto = -1 */ + +/* define PTRSZ, INLINE */ + +#ifndef PTRSZ +#define PTRSZ sizeof(char*) +#endif + + +/* Detect compiler type. */ +#if defined(__GNUC__) || defined(__lint) + #define BWL_COMPILER_GNU +#elif defined(__CC_ARM) && __CC_ARM + #define BWL_COMPILER_ARMCC +#else + #error "Unknown compiler!" +#endif + + +#ifndef INLINE + #if defined(BWL_COMPILER_MICROSOFT) + #define INLINE __inline + #elif defined(BWL_COMPILER_GNU) + #define INLINE __inline__ + #elif defined(BWL_COMPILER_ARMCC) + #define INLINE __inline + #else + #define INLINE + #endif +#endif /* INLINE */ + +#undef TYPEDEF_BOOL +#undef TYPEDEF_UCHAR +#undef TYPEDEF_USHORT +#undef TYPEDEF_UINT +#undef TYPEDEF_ULONG +#undef TYPEDEF_UINT8 +#undef TYPEDEF_UINT16 +#undef TYPEDEF_UINT32 +#undef TYPEDEF_UINT64 +#undef TYPEDEF_UINTPTR +#undef TYPEDEF_INT8 +#undef TYPEDEF_INT16 +#undef TYPEDEF_INT32 +#undef TYPEDEF_INT64 +#undef TYPEDEF_FLOAT32 +#undef TYPEDEF_FLOAT64 +#undef TYPEDEF_FLOAT_T + +#endif /* USE_TYPEDEF_DEFAULTS */ + +/* Suppress unused parameter warning */ +#define UNUSED_PARAMETER(x) (void)(x) + +/* Avoid warning for discarded const or volatile qualifier in special cases (-Wcast-qual) */ +#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) + +/* + * Including the bcmdefs.h here, to make sure everyone including typedefs.h + * gets this automatically +*/ +#include +#endif /* _TYPEDEFS_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd_bcm4356/include/wlfc_proto.h new file mode 100644 index 000000000000..2a4b8fa5b17d --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/wlfc_proto.h @@ -0,0 +1,301 @@ +/* +* Copyright (C) 1999-2017, Broadcom Corporation +* +* Unless you and Broadcom execute a separate written software license +* agreement governing use of this software, this software is licensed to you +* under the terms of the GNU General Public License version 2 (the "GPL"), +* available at http://www.broadcom.com/licenses/GPLv2.php, with the +* following added to such license: +* +* As a special exception, the copyright holders of this software give you +* permission to link this software with independent modules, and to copy and +* distribute the resulting executable under terms of your choice, provided that +* you also meet, for each linked independent module, the terms and conditions of +* the license of that module. An independent module is a module which is not +* derived from this software. The special exception does not apply to any +* modifications of the software. +* +* Notwithstanding the above, under no circumstances may you combine this +* software in any way with any other Broadcom software provided under a license +* other than the GPL, without Broadcom's express prior written consent. +* $Id: wlfc_proto.h 499510 2014-08-28 23:40:47Z $ +* +*/ +#ifndef __wlfc_proto_definitions_h__ +#define __wlfc_proto_definitions_h__ + + /* Use TLV to convey WLFC information. + --------------------------------------------------------------------------- + | Type | Len | value | Description + --------------------------------------------------------------------------- + | 1 | 1 | (handle) | MAC OPEN + --------------------------------------------------------------------------- + | 2 | 1 | (handle) | MAC CLOSE + --------------------------------------------------------------------------- + | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn + --------------------------------------------------------------------------- + | 4 | 4+ | see pkttag comments | TXSTATUS + | | | TX status & timestamps | Present only when pkt timestamp is enabled + --------------------------------------------------------------------------- + | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] + --------------------------------------------------------------------------- + | 6 | 8 | (handle, ifid, MAC) | MAC ADD + --------------------------------------------------------------------------- + | 7 | 8 | (handle, ifid, MAC) | MAC DEL + --------------------------------------------------------------------------- + | 8 | 1 | (rssi) | RSSI - RSSI value for the packet. + --------------------------------------------------------------------------- + | 9 | 1 | (interface ID) | Interface OPEN + --------------------------------------------------------------------------- + | 10 | 1 | (interface ID) | Interface CLOSE + --------------------------------------------------------------------------- + | 11 | 8 | fifo credit returns map | FIFO credits back to the host + | | | | + | | | | -------------------------------------- + | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim | + | | | | -------------------------------------- + | | | | + --------------------------------------------------------------------------- + | 12 | 2 | MAC handle, | Host provides a bitmap of pending + | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn. + | | | | [host->firmware] + --------------------------------------------------------------------------- + | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific + | | | | MAC destination. + --------------------------------------------------------------------------- + | 15 | 12 | (pkttag, timestamps) | Send TX timestamp at reception from host + --------------------------------------------------------------------------- + | 16 | 12 | (pkttag, timestamps) | Send WLAN RX timestamp along with RX frame + --------------------------------------------------------------------------- + | 255 | N/A | N/A | FILLER - This is a special type + | | | | that has no length or value. + | | | | Typically used for padding. + --------------------------------------------------------------------------- + */ + +#define WLFC_CTL_TYPE_MAC_OPEN 1 +#define WLFC_CTL_TYPE_MAC_CLOSE 2 +#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3 +#define WLFC_CTL_TYPE_TXSTATUS 4 +#define WLFC_CTL_TYPE_PKTTAG 5 + +#define WLFC_CTL_TYPE_MACDESC_ADD 6 +#define WLFC_CTL_TYPE_MACDESC_DEL 7 +#define WLFC_CTL_TYPE_RSSI 8 + +#define WLFC_CTL_TYPE_INTERFACE_OPEN 9 +#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 + +#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11 + +#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12 +#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 +#define WLFC_CTL_TYPE_HOST_REORDER_RXPKTS 14 + + +#define WLFC_CTL_TYPE_TX_ENTRY_STAMP 15 +#define WLFC_CTL_TYPE_RX_STAMP 16 + +#define WLFC_CTL_TYPE_TRANS_ID 18 +#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 + +#define WLFC_CTL_TYPE_TID_OPEN 20 +#define WLFC_CTL_TYPE_TID_CLOSE 21 + + +#define WLFC_CTL_TYPE_FILLER 255 + +#define WLFC_CTL_VALUE_LEN_MACDESC 8 /* handle, interface, MAC */ + +#define WLFC_CTL_VALUE_LEN_MAC 1 /* MAC-handle */ +#define WLFC_CTL_VALUE_LEN_RSSI 1 + +#define WLFC_CTL_VALUE_LEN_INTERFACE 1 +#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2 + +#define WLFC_CTL_VALUE_LEN_TXSTATUS 4 +#define WLFC_CTL_VALUE_LEN_PKTTAG 4 + +#define WLFC_CTL_VALUE_LEN_SEQ 2 + +/* enough space to host all 4 ACs, bc/mc and atim fifo credit */ +#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6 + +#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ +#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ + + +#define WLFC_PKTFLAG_PKTFROMHOST 0x01 /* packet originated from hot side */ +#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 /* packet requsted by firmware side */ +#define WLFC_PKTFLAG_PKT_FORCELOWRATE 0x04 /* force low rate for this packet */ + +#define WL_TXSTATUS_STATUS_MASK 0xff /* allow 8 bits */ +#define WL_TXSTATUS_STATUS_SHIFT 24 + +#define WL_TXSTATUS_SET_STATUS(x, status) ((x) = \ + ((x) & ~(WL_TXSTATUS_STATUS_MASK << WL_TXSTATUS_STATUS_SHIFT)) | \ + (((status) & WL_TXSTATUS_STATUS_MASK) << WL_TXSTATUS_STATUS_SHIFT)) +#define WL_TXSTATUS_GET_STATUS(x) (((x) >> WL_TXSTATUS_STATUS_SHIFT) & \ + WL_TXSTATUS_STATUS_MASK) + +#define WL_TXSTATUS_GENERATION_MASK 1 /* allow 1 bit */ +#define WL_TXSTATUS_GENERATION_SHIFT 31 + +#define WL_TXSTATUS_SET_GENERATION(x, gen) ((x) = \ + ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ + (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT)) + +#define WL_TXSTATUS_GET_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ + WL_TXSTATUS_GENERATION_MASK) + +#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ +#define WL_TXSTATUS_FLAGS_SHIFT 27 + +#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ + ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ + (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT)) +#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \ + WL_TXSTATUS_FLAGS_MASK) + +#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ +#define WL_TXSTATUS_FIFO_SHIFT 24 + +#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ + ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ + (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) +#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) + +#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ +#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ + ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) +#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) + +#define WL_TXSTATUS_HSLOT_MASK 0xffff /* allow 16 bits */ +#define WL_TXSTATUS_HSLOT_SHIFT 8 + +#define WL_TXSTATUS_SET_HSLOT(x, hslot) ((x) = \ + ((x) & ~(WL_TXSTATUS_HSLOT_MASK << WL_TXSTATUS_HSLOT_SHIFT)) | \ + (((hslot) & WL_TXSTATUS_HSLOT_MASK) << WL_TXSTATUS_HSLOT_SHIFT)) +#define WL_TXSTATUS_GET_HSLOT(x) (((x) >> WL_TXSTATUS_HSLOT_SHIFT)& \ + WL_TXSTATUS_HSLOT_MASK) + +#define WL_TXSTATUS_FREERUNCTR_MASK 0xff /* allow 8 bits */ + +#define WL_TXSTATUS_SET_FREERUNCTR(x, ctr) ((x) = \ + ((x) & ~(WL_TXSTATUS_FREERUNCTR_MASK)) | \ + ((ctr) & WL_TXSTATUS_FREERUNCTR_MASK)) +#define WL_TXSTATUS_GET_FREERUNCTR(x) ((x)& WL_TXSTATUS_FREERUNCTR_MASK) + +#define WL_SEQ_FROMFW_MASK 0x1 /* allow 1 bit */ +#define WL_SEQ_FROMFW_SHIFT 13 +#define WL_SEQ_SET_FROMFW(x, val) ((x) = \ + ((x) & ~(WL_SEQ_FROMFW_MASK << WL_SEQ_FROMFW_SHIFT)) | \ + (((val) & WL_SEQ_FROMFW_MASK) << WL_SEQ_FROMFW_SHIFT)) +#define WL_SEQ_GET_FROMFW(x) (((x) >> WL_SEQ_FROMFW_SHIFT) & \ + WL_SEQ_FROMFW_MASK) + +#define WL_SEQ_FROMDRV_MASK 0x1 /* allow 1 bit */ +#define WL_SEQ_FROMDRV_SHIFT 12 +#define WL_SEQ_SET_FROMDRV(x, val) ((x) = \ + ((x) & ~(WL_SEQ_FROMDRV_MASK << WL_SEQ_FROMDRV_SHIFT)) | \ + (((val) & WL_SEQ_FROMDRV_MASK) << WL_SEQ_FROMDRV_SHIFT)) +#define WL_SEQ_GET_FROMDRV(x) (((x) >> WL_SEQ_FROMDRV_SHIFT) & \ + WL_SEQ_FROMDRV_MASK) + +#define WL_SEQ_NUM_MASK 0xfff /* allow 12 bit */ +#define WL_SEQ_NUM_SHIFT 0 +#define WL_SEQ_SET_NUM(x, val) ((x) = \ + ((x) & ~(WL_SEQ_NUM_MASK << WL_SEQ_NUM_SHIFT)) | \ + (((val) & WL_SEQ_NUM_MASK) << WL_SEQ_NUM_SHIFT)) +#define WL_SEQ_GET_NUM(x) (((x) >> WL_SEQ_NUM_SHIFT) & \ + WL_SEQ_NUM_MASK) + +/* 32 STA should be enough??, 6 bits; Must be power of 2 */ +#define WLFC_MAC_DESC_TABLE_SIZE 32 +#define WLFC_MAX_IFNUM 16 +#define WLFC_MAC_DESC_ID_INVALID 0xff + +/* b[7:5] -reuse guard, b[4:0] -value */ +#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f) + +#define WLFC_MAX_PENDING_DATALEN 120 + +/* host is free to discard the packet */ +#define WLFC_CTL_PKTFLAG_DISCARD 0 +/* D11 suppressed a packet */ +#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1 +/* WL firmware suppressed a packet because MAC is + already in PSMode (short time window) +*/ +#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2 +/* Firmware tossed this packet */ +#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3 +/* Firmware tossed after retries */ +#define WLFC_CTL_PKTFLAG_DISCARD_NOACK 4 + +#define WLFC_D11_STATUS_INTERPRET(txs) \ + (((txs)->status.suppr_ind != TX_STATUS_SUPR_NONE) ? \ + WLFC_CTL_PKTFLAG_D11SUPPRESS : \ + ((txs)->status.was_acked ? \ + WLFC_CTL_PKTFLAG_DISCARD : WLFC_CTL_PKTFLAG_DISCARD_NOACK)) + +#ifdef PROP_TXSTATUS_DEBUG +#define WLFC_DBGMESG(x) printf x +/* wlfc-breadcrumb */ +#define WLFC_BREADCRUMB(x) do {if ((x) == NULL) \ + {printf("WLFC: %s():%d:caller:%p\n", \ + __FUNCTION__, __LINE__, __builtin_return_address(0));}} while (0) +#define WLFC_PRINTMAC(banner, ea) do {printf("%s MAC: [%02x:%02x:%02x:%02x:%02x:%02x]\n", \ + banner, ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); } while (0) +#define WLFC_WHEREIS(s) printf("WLFC: at %s():%d, %s\n", __FUNCTION__, __LINE__, (s)) +#else +#define WLFC_DBGMESG(x) +#define WLFC_BREADCRUMB(x) +#define WLFC_PRINTMAC(banner, ea) +#define WLFC_WHEREIS(s) +#endif + +/* AMPDU host reorder packet flags */ +#define WLHOST_REORDERDATA_MAXFLOWS 256 +#define WLHOST_REORDERDATA_LEN 10 +#define WLHOST_REORDERDATA_TOTLEN (WLHOST_REORDERDATA_LEN + 1 + 1) /* +tag +len */ + +#define WLHOST_REORDERDATA_FLOWID_OFFSET 0 +#define WLHOST_REORDERDATA_MAXIDX_OFFSET 2 +#define WLHOST_REORDERDATA_FLAGS_OFFSET 4 +#define WLHOST_REORDERDATA_CURIDX_OFFSET 6 +#define WLHOST_REORDERDATA_EXPIDX_OFFSET 8 + +#define WLHOST_REORDERDATA_DEL_FLOW 0x01 +#define WLHOST_REORDERDATA_FLUSH_ALL 0x02 +#define WLHOST_REORDERDATA_CURIDX_VALID 0x04 +#define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 +#define WLHOST_REORDERDATA_NEW_HOLE 0x10 + +/* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ +#define WLFC_CTL_TRANS_ID_LEN 6 +#define WLFC_TYPE_TRANS_ID_LEN 6 + +#define WLFC_MODE_HANGER 1 /* use hanger */ +#define WLFC_MODE_AFQ 2 /* use afq */ +#define WLFC_IS_OLD_DEF(x) ((x & 1) || (x & 2)) + +#define WLFC_MODE_AFQ_SHIFT 2 /* afq bit */ +#define WLFC_SET_AFQ(x, val) ((x) = \ + ((x) & ~(1 << WLFC_MODE_AFQ_SHIFT)) | \ + (((val) & 1) << WLFC_MODE_AFQ_SHIFT)) +#define WLFC_GET_AFQ(x) (((x) >> WLFC_MODE_AFQ_SHIFT) & 1) + +#define WLFC_MODE_REUSESEQ_SHIFT 3 /* seq reuse bit */ +#define WLFC_SET_REUSESEQ(x, val) ((x) = \ + ((x) & ~(1 << WLFC_MODE_REUSESEQ_SHIFT)) | \ + (((val) & 1) << WLFC_MODE_REUSESEQ_SHIFT)) +#define WLFC_GET_REUSESEQ(x) (((x) >> WLFC_MODE_REUSESEQ_SHIFT) & 1) + +#define WLFC_MODE_REORDERSUPP_SHIFT 4 /* host reorder suppress pkt bit */ +#define WLFC_SET_REORDERSUPP(x, val) ((x) = \ + ((x) & ~(1 << WLFC_MODE_REORDERSUPP_SHIFT)) | \ + (((val) & 1) << WLFC_MODE_REORDERSUPP_SHIFT)) +#define WLFC_GET_REORDERSUPP(x) (((x) >> WLFC_MODE_REORDERSUPP_SHIFT) & 1) + +#endif /* __wlfc_proto_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/wlioctl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/wlioctl.h new file mode 100644 index 000000000000..aa71bca48928 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/wlioctl.h @@ -0,0 +1,6681 @@ +/* + * Custom OID/ioctl definitions for + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wlioctl.h 595011 2015-10-26 05:41:56Z $ + */ + +#ifndef _wlioctl_h_ +#define _wlioctl_h_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + + + + + + +#ifndef INTF_NAME_SIZ +#define INTF_NAME_SIZ 16 +#endif + +/* Used to send ioctls over the transport pipe */ +typedef struct remote_ioctl { + cdc_ioctl_t msg; + uint32 data_len; + char intf_name[INTF_NAME_SIZ]; +} rem_ioctl_t; +#define REMOTE_SIZE sizeof(rem_ioctl_t) + +typedef struct { + uint32 num; + chanspec_t list[1]; +} chanspec_list_t; + +/* DFS Forced param */ +typedef struct wl_dfs_forced_params { + chanspec_t chspec; + uint16 version; + chanspec_list_t chspec_list; +} wl_dfs_forced_t; + +#define DFS_PREFCHANLIST_VER 0x01 +#define WL_CHSPEC_LIST_FIXED_SIZE OFFSETOF(chanspec_list_t, list) +#define WL_DFS_FORCED_PARAMS_FIXED_SIZE \ + (WL_CHSPEC_LIST_FIXED_SIZE + OFFSETOF(wl_dfs_forced_t, chspec_list)) +#define WL_DFS_FORCED_PARAMS_MAX_SIZE \ + WL_DFS_FORCED_PARAMS_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(chanspec_t)) + +/* association decision information */ +typedef struct { + bool assoc_approved; /* (re)association approved */ + uint16 reject_reason; /* reason code for rejecting association */ + struct ether_addr da; + int64 sys_time; /* current system time */ +} assoc_decision_t; + +#define ACTION_FRAME_SIZE 1800 + +typedef struct wl_action_frame { + struct ether_addr da; + uint16 len; + uint32 packetId; + uint8 data[ACTION_FRAME_SIZE]; +} wl_action_frame_t; + +#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) + +typedef struct ssid_info +{ + uint8 ssid_len; /* the length of SSID */ + uint8 ssid[32]; /* SSID string */ +} ssid_info_t; + +typedef struct wl_af_params { + uint32 channel; + int32 dwell_time; + struct ether_addr BSSID; + wl_action_frame_t action_frame; +} wl_af_params_t; + +#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) + +#define MFP_TEST_FLAG_NORMAL 0 +#define MFP_TEST_FLAG_ANY_KEY 1 +typedef struct wl_sa_query { + uint32 flag; + uint8 action; + uint16 id; + struct ether_addr da; +} wl_sa_query_t; + + +/* require default structure packing */ +#define BWL_DEFAULT_PACKING +#include + + +/* Flags for OBSS IOVAR Parameters */ +#define WL_OBSS_DYN_BWSW_FLAG_ACTIVITY_PERIOD (0x01) +#define WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_PERIOD (0x02) +#define WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_INCR_PERIOD (0x04) +#define WL_OBSS_DYN_BWSW_FLAG_PSEUDO_SENSE_PERIOD (0x08) +#define WL_OBSS_DYN_BWSW_FLAG_RX_CRS_PERIOD (0x10) +#define WL_OBSS_DYN_BWSW_FLAG_DUR_THRESHOLD (0x20) +#define WL_OBSS_DYN_BWSW_FLAG_TXOP_PERIOD (0x40) + +/* OBSS IOVAR Version information */ +#define WL_PROT_OBSS_CONFIG_PARAMS_VERSION 1 +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 obss_bwsw_activity_cfm_count_cfg; /* configurable count in + * seconds before we confirm that OBSS is present and + * dynamically activate dynamic bwswitch. + */ + uint8 obss_bwsw_no_activity_cfm_count_cfg; /* configurable count in + * seconds before we confirm that OBSS is GONE and + * dynamically start pseudo upgrade. If in pseudo sense time, we + * will see OBSS, [means that, we false detected that OBSS-is-gone + * in watchdog] this count will be incremented in steps of + * obss_bwsw_no_activity_cfm_count_incr_cfg for confirming OBSS + * detection again. Note that, at present, max 30seconds is + * allowed like this. [OBSS_BWSW_NO_ACTIVITY_MAX_INCR_DEFAULT] + */ + uint8 obss_bwsw_no_activity_cfm_count_incr_cfg; /* see above + */ + uint16 obss_bwsw_pseudo_sense_count_cfg; /* number of msecs/cnt to be in + * pseudo state. This is used to sense/measure the stats from lq. + */ + uint8 obss_bwsw_rx_crs_threshold_cfg; /* RX CRS default threshold */ + uint8 obss_bwsw_dur_thres; /* OBSS dyn bwsw trigger/RX CRS Sec */ + uint8 obss_bwsw_txop_threshold_cfg; /* TXOP default threshold */ +} BWL_POST_PACKED_STRUCT wlc_prot_dynbwsw_config_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 version; /* version field */ + uint32 config_mask; + uint32 reset_mask; + wlc_prot_dynbwsw_config_t config_params; +} BWL_POST_PACKED_STRUCT obss_config_params_t; + + + +/* Legacy structure to help keep backward compatible wl tool and tray app */ + +#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ + +typedef struct wl_bss_info_107 { + uint32 version; /* version field */ + uint32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; /* # rates in this set */ + uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + uint8 channel; /* Channel no. */ + uint16 atim_window; /* units are Kusec */ + uint8 dtim_period; /* DTIM period */ + int16 RSSI; /* receive signal strength (in dBm) */ + int8 phy_noise; /* noise (in dBm) */ + uint32 ie_length; /* byte length of Information Elements */ + /* variable length Information Elements */ +} wl_bss_info_107_t; + +/* + * Per-BSS information structure. + */ + +#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */ + +/* BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in wl_scan_results_t) + */ +typedef struct wl_bss_info_108 { + uint32 version; /* version field */ + uint32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; /* # rates in this set */ + uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + chanspec_t chanspec; /* chanspec for bss */ + uint16 atim_window; /* units are Kusec */ + uint8 dtim_period; /* DTIM period */ + int16 RSSI; /* receive signal strength (in dBm) */ + int8 phy_noise; /* noise (in dBm) */ + + uint8 n_cap; /* BSS is 802.11N Capable */ + uint32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ + uint8 ctl_ch; /* 802.11N BSS control channel number */ + uint32 reserved32[1]; /* Reserved for expansion of BSS properties */ + uint8 flags; /* flags */ + uint8 reserved[3]; /* Reserved for expansion of BSS properties */ + uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + + uint16 ie_offset; /* offset at which IEs start, from beginning */ + uint32 ie_length; /* byte length of Information Elements */ + /* Add new fields here */ + /* variable length Information Elements */ +} wl_bss_info_108_t; + + +#define WL_BSS_INFO_VERSION 109 /* current version of wl_bss_info struct */ + +/* BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in wl_scan_results_t) + */ +typedef struct wl_bss_info { + uint32 version; /* version field */ + uint32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; /* # rates in this set */ + uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + chanspec_t chanspec; /* chanspec for bss */ + uint16 atim_window; /* units are Kusec */ + uint8 dtim_period; /* DTIM period */ + int16 RSSI; /* receive signal strength (in dBm) */ + int8 phy_noise; /* noise (in dBm) */ + + uint8 n_cap; /* BSS is 802.11N Capable */ + uint32 nbss_cap; /* 802.11N+AC BSS Capabilities */ + uint8 ctl_ch; /* 802.11N BSS control channel number */ + uint8 padding1[3]; /* explicit struct alignment padding */ + uint16 vht_rxmcsmap; /* VHT rx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ + uint16 vht_txmcsmap; /* VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ + uint8 flags; /* flags */ + uint8 vht_cap; /* BSS is vht capable */ + uint8 reserved[2]; /* Reserved for expansion of BSS properties */ + uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + + uint16 ie_offset; /* offset at which IEs start, from beginning */ + uint32 ie_length; /* byte length of Information Elements */ + int16 SNR; /* average SNR of during frame reception */ + /* Add new fields here */ + /* variable length Information Elements */ +} wl_bss_info_t; + +#define WL_GSCAN_BSS_INFO_VERSION 1 /* current version of wl_gscan_bss_info struct */ +#define WL_GSCAN_INFO_FIXED_FIELD_SIZE (sizeof(wl_gscan_bss_info_t) - sizeof(wl_bss_info_t)) + +typedef struct wl_gscan_bss_info { + uint32 timestamp[2]; + wl_bss_info_t info; + /* variable length Information Elements */ +} wl_gscan_bss_info_t; + + +typedef struct wl_bsscfg { + uint32 bsscfg_idx; + uint32 wsec; + uint32 WPA_auth; + uint32 wsec_index; + uint32 associated; + uint32 BSS; + uint32 phytest_on; + struct ether_addr prev_BSSID; + struct ether_addr BSSID; + uint32 targetbss_wpa2_flags; + uint32 assoc_type; + uint32 assoc_state; +} wl_bsscfg_t; + +typedef struct wl_if_add { + uint32 bsscfg_flags; + uint32 if_flags; + uint32 ap; + struct ether_addr mac_addr; +} wl_if_add_t; + +typedef struct wl_bss_config { + uint32 atim_window; + uint32 beacon_period; + uint32 chanspec; +} wl_bss_config_t; + +#define WL_BSS_USER_RADAR_CHAN_SELECT 0x1 /* User application will randomly select + * radar channel. + */ + +#define DLOAD_HANDLER_VER 1 /* Downloader version */ +#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ +#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ + +#define DL_CRC_NOT_INUSE 0x0001 + +/* generic download types & flags */ +enum { + DL_TYPE_UCODE = 1, + DL_TYPE_CLM = 2 +}; + +/* ucode type values */ +enum { + UCODE_FW, + INIT_VALS, + BS_INIT_VALS +}; + +struct wl_dload_data { + uint16 flag; + uint16 dload_type; + uint32 len; + uint32 crc; + uint8 data[1]; +}; +typedef struct wl_dload_data wl_dload_data_t; + +struct wl_ucode_info { + uint32 ucode_type; + uint32 num_chunks; + uint32 chunk_len; + uint32 chunk_num; + uint8 data_chunk[1]; +}; +typedef struct wl_ucode_info wl_ucode_info_t; + +struct wl_clm_dload_info { + uint32 ds_id; + uint32 clm_total_len; + uint32 num_chunks; + uint32 chunk_len; + uint32 chunk_offset; + uint8 data_chunk[1]; +}; +typedef struct wl_clm_dload_info wl_clm_dload_info_t; + + +typedef struct wlc_ssid { + uint32 SSID_len; + uchar SSID[DOT11_MAX_SSID_LEN]; +} wlc_ssid_t; + +typedef struct wlc_ssid_ext { + bool hidden; + uint16 flags; + uint8 SSID_len; + int8 rssi_thresh; + uchar SSID[DOT11_MAX_SSID_LEN]; +} wlc_ssid_ext_t; + + +#define MAX_PREFERRED_AP_NUM 5 +typedef struct wlc_fastssidinfo { + uint32 SSID_channel[MAX_PREFERRED_AP_NUM]; + wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM]; +} wlc_fastssidinfo_t; + +typedef BWL_PRE_PACKED_STRUCT struct wnm_url { + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT wnm_url_t; + +typedef struct chan_scandata { + uint8 txpower; + uint8 pad; + chanspec_t channel; /* Channel num, bw, ctrl_sb and band */ + uint32 channel_mintime; + uint32 channel_maxtime; +} chan_scandata_t; + +typedef enum wl_scan_type { + EXTDSCAN_FOREGROUND_SCAN, + EXTDSCAN_BACKGROUND_SCAN, + EXTDSCAN_FORCEDBACKGROUND_SCAN +} wl_scan_type_t; + +#define WLC_EXTDSCAN_MAX_SSID 5 + +typedef struct wl_extdscan_params { + int8 nprobes; /* 0, passive, otherwise active */ + int8 split_scan; /* split scan */ + int8 band; /* band */ + int8 pad; + wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /* ssid list */ + uint32 tx_rate; /* in 500ksec units */ + wl_scan_type_t scan_type; /* enum */ + int32 channel_num; + chan_scandata_t channel_list[1]; /* list of chandata structs */ +} wl_extdscan_params_t; + +#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) + +#define WL_SCAN_PARAMS_SSID_MAX 10 + +typedef struct wl_scan_params { + wlc_ssid_t ssid; /* default: {0, ""} */ + struct ether_addr bssid; /* default: bcast */ + int8 bss_type; /* default: any, + * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT + */ + uint8 scan_type; /* flags, 0 use default */ + int32 nprobes; /* -1 use default, number of probes per channel */ + int32 active_time; /* -1 use default, dwell time per channel for + * active scanning + */ + int32 passive_time; /* -1 use default, dwell time per channel + * for passive scanning + */ + int32 home_time; /* -1 use default, dwell time for the home channel + * between channel scans + */ + int32 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 wlc_ssid_t array that + * follows channel_list, aligned for int32 (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 + */ + uint16 channel_list[1]; /* list of chanspecs */ +} wl_scan_params_t; + +/* size of wl_scan_params not including variable length array */ +#define WL_SCAN_PARAMS_FIXED_SIZE 64 +#define WL_MAX_ROAMSCAN_DATSZ (WL_SCAN_PARAMS_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16))) + +#define ISCAN_REQ_VERSION 1 + +/* incremental scan struct */ +typedef struct wl_iscan_params { + uint32 version; + uint16 action; + uint16 scan_duration; + wl_scan_params_t params; +} wl_iscan_params_t; + +/* 3 fields + size of wl_scan_params, not including variable length array */ +#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) + +typedef struct wl_scan_results { + uint32 buflen; + uint32 version; + uint32 count; + wl_bss_info_t bss_info[1]; +} wl_scan_results_t; + +/* size of wl_scan_results not including variable length array */ +#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) + + +#define ESCAN_REQ_VERSION 1 + +typedef struct wl_escan_params { + uint32 version; + uint16 action; + uint16 sync_id; + wl_scan_params_t params; +} wl_escan_params_t; + +#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) + +typedef struct wl_escan_result { + uint32 buflen; + uint32 version; + uint16 sync_id; + uint16 bss_count; + wl_bss_info_t bss_info[1]; +} wl_escan_result_t; + +#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) + +typedef struct wl_gscan_result { + uint32 buflen; + uint32 version; + wl_gscan_bss_info_t bss_info[1]; +} wl_gscan_result_t; + +#define WL_GSCAN_RESULTS_FIXED_SIZE (sizeof(wl_gscan_result_t) - sizeof(wl_gscan_bss_info_t)) + +/* incremental scan results struct */ +typedef struct wl_iscan_results { + uint32 status; + wl_scan_results_t results; +} wl_iscan_results_t; + +/* size of wl_iscan_results not including variable length array */ +#define WL_ISCAN_RESULTS_FIXED_SIZE \ + (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) + +#define SCANOL_PARAMS_VERSION 1 + +typedef struct scanol_params { + uint32 version; + uint32 flags; /* offload scanning flags */ + int32 active_time; /* -1 use default, dwell time per channel for active scanning */ + int32 passive_time; /* -1 use default, dwell time per channel for passive scanning */ + int32 idle_rest_time; /* -1 use default, time idle between scan cycle */ + int32 idle_rest_time_multiplier; + int32 active_rest_time; + int32 active_rest_time_multiplier; + int32 scan_cycle_idle_rest_time; + int32 scan_cycle_idle_rest_multiplier; + int32 scan_cycle_active_rest_time; + int32 scan_cycle_active_rest_multiplier; + int32 max_rest_time; + int32 max_scan_cycles; + int32 nprobes; /* -1 use default, number of probes per channel */ + int32 scan_start_delay; + uint32 nchannels; + uint32 ssid_count; + wlc_ssid_t ssidlist[1]; +} scanol_params_t; + +typedef struct wl_probe_params { + wlc_ssid_t ssid; + struct ether_addr bssid; + struct ether_addr mac; +} wl_probe_params_t; + +#define WL_MAXRATES_IN_SET 16 /* max # of rates in a rateset */ +typedef struct wl_rateset { + uint32 count; /* # rates in this set */ + uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ +} wl_rateset_t; + +typedef struct wl_rateset_args { + uint32 count; /* # rates in this set */ + uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ + uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ + uint16 vht_mcs[VHT_CAP_MCS_MAP_NSS_MAX]; /* supported mcs index bit map per nss */ +} wl_rateset_args_t; + +#define TXBF_RATE_MCS_ALL 4 +#define TXBF_RATE_VHT_ALL 4 +#define TXBF_RATE_OFDM_ALL 8 + +typedef struct wl_txbf_rateset { + uint8 txbf_rate_mcs[TXBF_RATE_MCS_ALL]; /* one for each stream */ + uint8 txbf_rate_mcs_bcm[TXBF_RATE_MCS_ALL]; /* one for each stream */ + uint16 txbf_rate_vht[TXBF_RATE_VHT_ALL]; /* one for each stream */ + uint16 txbf_rate_vht_bcm[TXBF_RATE_VHT_ALL]; /* one for each stream */ + uint8 txbf_rate_ofdm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ + uint8 txbf_rate_ofdm_bcm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ + uint8 txbf_rate_ofdm_cnt; + uint8 txbf_rate_ofdm_cnt_bcm; +} wl_txbf_rateset_t; + +#define OFDM_RATE_MASK 0x0000007f +typedef uint8 ofdm_rates_t; + +typedef struct wl_rates_info { + wl_rateset_t rs_tgt; + uint32 phy_type; + int32 bandtype; + uint8 cck_only; + uint8 rate_mask; + uint8 mcsallow; + uint8 bw; + uint8 txstreams; +} wl_rates_info_t; + +/* uint32 list */ +typedef struct wl_uint32_list { + /* in - # of elements, out - # of entries */ + uint32 count; + /* variable length uint32 list */ + uint32 element[1]; +} wl_uint32_list_t; + +/* used for association with a specific BSSID and chanspec list */ +typedef struct wl_assoc_params { + struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */ + uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, + * otherwise count of chanspecs in chanspec_list + * AND paired bssids following chanspec_list + * also, chanspec_num has to be set to zero + * for bssid list to be used + */ + int32 chanspec_num; /* 0: all available channels, + * otherwise count of chanspecs in chanspec_list + */ + chanspec_t chanspec_list[1]; /* list of chanspecs */ +} wl_assoc_params_t; + +#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) + +/* used for reassociation/roam to a specific BSSID and channel */ +typedef wl_assoc_params_t wl_reassoc_params_t; +#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE + +/* used for association to a specific BSSID and channel */ +typedef wl_assoc_params_t wl_join_assoc_params_t; +#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE + +/* used for join with or without a specific bssid and channel list */ +typedef struct wl_join_params { + wlc_ssid_t ssid; + wl_assoc_params_t params; /* optional field, but it must include the fixed portion + * of the wl_assoc_params_t struct when it does present. + */ +} wl_join_params_t; + +typedef struct wlc_roam_exp_params { + int8 a_band_boost_threshold; + int8 a_band_penalty_threshold; + uint8 a_band_boost_factor; + uint8 a_band_penalty_factor; + uint8 cur_bssid_boost; + int8 alert_roam_trigger_threshold; + uint16 a_band_max_boost; +} wlc_roam_exp_params_t; + +#define ROAM_EXP_CFG_VERSION 1 +#define ROAM_EXP_ENABLE_FLAG (1 << 0) +#define ROAM_EXP_CFG_PRESENT (1 << 1) +typedef struct wl_roam_exp_cfg { + uint8 version; + uint8 flags; + uint16 reserved; + wlc_roam_exp_params_t params; +} wl_roam_exp_cfg_t; + +typedef struct wl_bssid_pref_list { + struct ether_addr bssid; + /* Add this to modify rssi */ + int8 rssi_factor; + int8 flags; +} wl_bssid_pref_list_t; + +#define BSSID_PREF_LIST_VERSION 1 +#define ROAM_EXP_CLEAR_BSSID_PREF (1 << 0) +typedef struct wl_bssid_pref_cfg { + uint8 version; + uint8 flags; + uint16 count; + wl_bssid_pref_list_t bssids[1]; +} wl_bssid_pref_cfg_t; + +#define SSID_WHITELIST_VERSION 1 +#define ROAM_EXP_CLEAR_SSID_WHITELIST (1 << 0) +/* Roam SSID whitelist, ssids in this list are ok to */ +/* be considered as targets to join when considering a roam */ +typedef struct wl_ssid_whitelist { + uint8 version; + uint8 flags; + uint8 ssid_count; + uint8 reserved; + wlc_ssid_t ssids[1]; +} wl_ssid_whitelist_t; + +#define ROAM_EXP_EVENT_VERSION 1 +typedef struct wl_roam_exp_event { + uint8 version; + uint8 flags; + uint16 reserved; + wlc_ssid_t cur_ssid; +} wl_roam_exp_event_t; + +#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \ + WL_ASSOC_PARAMS_FIXED_SIZE) +/* scan params for extended join */ +typedef struct wl_join_scan_params { + uint8 scan_type; /* 0 use default, active or passive scan */ + int32 nprobes; /* -1 use default, number of probes per channel */ + int32 active_time; /* -1 use default, dwell time per channel for + * active scanning + */ + int32 passive_time; /* -1 use default, dwell time per channel + * for passive scanning + */ + int32 home_time; /* -1 use default, dwell time for the home channel + * between channel scans + */ +} wl_join_scan_params_t; + +/* extended join params */ +typedef struct wl_extjoin_params { + wlc_ssid_t ssid; /* {0, ""}: wildcard scan */ + wl_join_scan_params_t scan; + wl_join_assoc_params_t assoc; /* optional field, but it must include the fixed portion + * of the wl_join_assoc_params_t struct when it does + * present. + */ +} wl_extjoin_params_t; +#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \ + WL_JOIN_ASSOC_PARAMS_FIXED_SIZE) + +#define ANT_SELCFG_MAX 4 /* max number of antenna configurations */ +#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ +typedef struct { + uint8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ + uint8 num_antcfg; /* number of available antenna configurations */ +} wlc_antselcfg_t; + +typedef struct { + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 timestamp; /* second timestamp */ +} cca_congest_t; + +typedef struct { + chanspec_t chanspec; /* Which channel? */ + uint8 num_secs; /* How many secs worth of data */ + cca_congest_t secs[1]; /* Data */ +} cca_congest_channel_req_t; + + +/* interference sources */ +enum interference_source { + ITFR_NONE = 0, /* interference */ + ITFR_PHONE, /* wireless phone */ + ITFR_VIDEO_CAMERA, /* wireless video camera */ + ITFR_MICROWAVE_OVEN, /* microwave oven */ + ITFR_BABY_MONITOR, /* wireless baby monitor */ + ITFR_BLUETOOTH, /* bluetooth */ + ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /* wireless camera or baby monitor */ + ITFR_BLUETOOTH_OR_BABY_MONITOR, /* bluetooth or baby monitor */ + ITFR_VIDEO_CAMERA_OR_PHONE, /* video camera or phone */ + ITFR_UNIDENTIFIED /* interference from unidentified source */ +}; + +/* structure for interference source report */ +typedef struct { + uint32 flags; /* flags. bit definitions below */ + uint32 source; /* last detected interference source */ + uint32 timestamp; /* second timestamp on interferenced flag change */ +} interference_source_rep_t; + +#define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ + +typedef struct wl_country { + char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in + * the Country IE + */ + int32 rev; /* revision specifier for ccode + * on set, -1 indicates unspecified. + * on get, rev >= 0 + */ + char ccode[WLC_CNTRY_BUF_SZ]; /* nul-terminated built-in country code. + * variable length, but fixed size in + * struct allows simple allocation for + * expected country strings <= 3 chars. + */ +} wl_country_t; + +typedef struct wl_channels_in_country { + uint32 buflen; + uint32 band; + char country_abbrev[WLC_CNTRY_BUF_SZ]; + uint32 count; + uint32 channel[1]; +} wl_channels_in_country_t; + +typedef struct wl_country_list { + uint32 buflen; + uint32 band_set; + uint32 band; + uint32 count; + char country_abbrev[1]; +} wl_country_list_t; + +typedef struct wl_rm_req_elt { + int8 type; + int8 flags; + chanspec_t chanspec; + uint32 token; /* token for this measurement */ + uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ + uint32 tsf_l; /* TSF low 32-bits */ + uint32 dur; /* TUs */ +} wl_rm_req_elt_t; + +typedef struct wl_rm_req { + uint32 token; /* overall measurement set token */ + uint32 count; /* number of measurement requests */ + void *cb; /* completion callback function: may be NULL */ + void *cb_arg; /* arg to completion callback function */ + wl_rm_req_elt_t req[1]; /* variable length block of requests */ +} wl_rm_req_t; +#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) + +typedef struct wl_rm_rep_elt { + int8 type; + int8 flags; + chanspec_t chanspec; + uint32 token; /* token for this measurement */ + uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ + uint32 tsf_l; /* TSF low 32-bits */ + uint32 dur; /* TUs */ + uint32 len; /* byte length of data block */ + uint8 data[1]; /* variable length data block */ +} wl_rm_rep_elt_t; +#define WL_RM_REP_ELT_FIXED_LEN 24 /* length excluding data block */ + +#define WL_RPI_REP_BIN_NUM 8 +typedef struct wl_rm_rpi_rep { + uint8 rpi[WL_RPI_REP_BIN_NUM]; + int8 rpi_max[WL_RPI_REP_BIN_NUM]; +} wl_rm_rpi_rep_t; + +typedef struct wl_rm_rep { + uint32 token; /* overall measurement set token */ + uint32 len; /* length of measurement report block */ + wl_rm_rep_elt_t rep[1]; /* variable length block of reports */ +} wl_rm_rep_t; +#define WL_RM_REP_FIXED_LEN 8 + +#ifdef BCMCCX + +#define LEAP_USER_MAX 32 +#define LEAP_DOMAIN_MAX 32 +#define LEAP_PASSWORD_MAX 32 + +typedef struct wl_leap_info { + wlc_ssid_t ssid; + uint8 user_len; + uchar user[LEAP_USER_MAX]; + uint8 password_len; + uchar password[LEAP_PASSWORD_MAX]; + uint8 domain_len; + uchar domain[LEAP_DOMAIN_MAX]; +} wl_leap_info_t; + +typedef struct wl_leap_list { + uint32 buflen; + uint32 version; + uint32 count; + wl_leap_info_t leap_info[1]; +} wl_leap_list_t; +#endif /* BCMCCX */ + +typedef enum sup_auth_status { + /* Basic supplicant authentication states */ + WLC_SUP_DISCONNECTED = 0, + WLC_SUP_CONNECTING, + WLC_SUP_IDREQUIRED, + WLC_SUP_AUTHENTICATING, + WLC_SUP_AUTHENTICATED, + WLC_SUP_KEYXCHANGE, + WLC_SUP_KEYED, + WLC_SUP_TIMEOUT, + WLC_SUP_LAST_BASIC_STATE, + + /* Extended supplicant authentication states */ + /* Waiting to receive handshake msg M1 */ + WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, + /* Preparing to send handshake msg M2 */ + WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, + /* Waiting to receive handshake msg M3 */ + WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, + WLC_SUP_KEYXCHANGE_PREP_M4, /* Preparing to send handshake msg M4 */ + WLC_SUP_KEYXCHANGE_WAIT_G1, /* Waiting to receive handshake msg G1 */ + WLC_SUP_KEYXCHANGE_PREP_G2 /* Preparing to send handshake msg G2 */ +} sup_auth_status_t; + +typedef struct wl_wsec_key { + uint32 index; /* key index */ + uint32 len; /* key length */ + uint8 data[DOT11_MAX_KEY_SIZE]; /* key data */ + uint32 pad_1[18]; + uint32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ + uint32 flags; /* misc flags */ + uint32 pad_2[2]; + int pad_3; + int iv_initialized; /* has IV been initialized already? */ + int pad_4; + /* Rx IV */ + struct { + uint32 hi; /* upper 32 bits of IV */ + uint16 lo; /* lower 16 bits of IV */ + } rxiv; + uint32 pad_5[2]; + struct ether_addr ea; /* per station */ +} wl_wsec_key_t; + +#define WSEC_MIN_PSK_LEN 8 +#define WSEC_MAX_PSK_LEN 64 + +/* Flag for key material needing passhash'ing */ +#define WSEC_PASSPHRASE (1<<0) + +/* receptacle for WLC_SET_WSEC_PMK parameter */ +typedef struct { + ushort key_len; /* octets in key material */ + ushort flags; /* key handling qualification */ + uint8 key[WSEC_MAX_PSK_LEN]; /* PMK material */ +} wsec_pmk_t; + +typedef struct _pmkid { + struct ether_addr BSSID; + uint8 PMKID[WPA2_PMKID_LEN]; +} pmkid_t; + +typedef struct _pmkid_list { + uint32 npmkid; + pmkid_t pmkid[1]; +} pmkid_list_t; + +typedef struct _pmkid_cand { + struct ether_addr BSSID; + uint8 preauth; +} pmkid_cand_t; + +typedef struct _pmkid_cand_list { + uint32 npmkid_cand; + pmkid_cand_t pmkid_cand[1]; +} pmkid_cand_list_t; + +#define WL_STA_ANT_MAX 4 /* max possible rx antennas */ + +typedef struct wl_assoc_info { + uint32 req_len; + uint32 resp_len; + uint32 flags; + struct dot11_assoc_req req; + struct ether_addr reassoc_bssid; /* used in reassoc's */ + struct dot11_assoc_resp resp; +} wl_assoc_info_t; + +typedef struct wl_led_info { + uint32 index; /* led index */ + uint32 behavior; + uint8 activehi; +} wl_led_info_t; + + +/* srom read/write struct passed through ioctl */ +typedef struct { + uint byteoff; /* byte offset */ + uint nbytes; /* number of bytes */ + uint16 buf[1]; +} srom_rw_t; + +#define CISH_FLAG_PCIECIS (1 << 15) /* write CIS format bit for PCIe CIS */ +/* similar cis (srom or otp) struct [iovar: may not be aligned] */ +typedef struct { + uint16 source; /* cis source */ + uint16 flags; /* flags */ + uint32 byteoff; /* byte offset */ + uint32 nbytes; /* number of bytes */ + /* data follows here */ +} cis_rw_t; + +/* R_REG and W_REG struct passed through ioctl */ +typedef struct { + uint32 byteoff; /* byte offset of the field in d11regs_t */ + uint32 val; /* read/write value of the field */ + uint32 size; /* sizeof the field */ + uint band; /* band (optional) */ +} rw_reg_t; + +/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */ +/* PCL - Power Control Loop */ +typedef struct { + uint16 auto_ctrl; /* WL_ATTEN_XX */ + uint16 bb; /* Baseband attenuation */ + uint16 radio; /* Radio attenuation */ + uint16 txctl1; /* Radio TX_CTL1 value */ +} atten_t; + +/* Per-AC retry parameters */ +struct wme_tx_params_s { + uint8 short_retry; + uint8 short_fallback; + uint8 long_retry; + uint8 long_fallback; + uint16 max_rate; /* In units of 512 Kbps */ +}; + +typedef struct wme_tx_params_s wme_tx_params_t; + +#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) + +typedef struct wl_plc_nodelist { + uint32 count; /* Number of nodes */ + struct _node { + struct ether_addr ea; /* Node ether address */ + uint32 node_type; /* Node type */ + uint32 cost; /* PLC affinity */ + } node[1]; +} wl_plc_nodelist_t; + +typedef struct wl_plc_params { + uint32 cmd; /* Command */ + uint8 plc_failover; /* PLC failover control/status */ + struct ether_addr node_ea; /* Node ether address */ + uint32 cost; /* Link cost or mac cost */ +} wl_plc_params_t; + +/* Used to get specific link/ac parameters */ +typedef struct { + int32 ac; + uint8 val; + struct ether_addr ea; +} link_val_t; + + +#define WL_PM_MUTE_TX_VER 1 + +typedef struct wl_pm_mute_tx { + uint16 version; /* version */ + uint16 len; /* length */ + uint16 deadline; /* deadline timer (in milliseconds) */ + uint8 enable; /* set to 1 to enable mode; set to 0 to disable it */ +} wl_pm_mute_tx_t; + + +typedef struct { + uint16 ver; /* version of this struct */ + uint16 len; /* length in bytes of this structure */ + uint16 cap; /* sta's advertised capabilities */ + uint32 flags; /* flags defined below */ + uint32 idle; /* time since data pkt rx'd from sta */ + struct ether_addr ea; /* Station address */ + wl_rateset_t rateset; /* rateset in use */ + uint32 in; /* seconds elapsed since associated */ + uint32 listen_interval_inms; /* Min Listen interval in ms for this STA */ + uint32 tx_pkts; /* # of user packets transmitted (unicast) */ + uint32 tx_failures; /* # of user packets failed */ + uint32 rx_ucast_pkts; /* # of unicast packets received */ + uint32 rx_mcast_pkts; /* # of multicast packets received */ + uint32 tx_rate; /* Rate used by last tx frame */ + uint32 rx_rate; /* Rate of last successful rx frame */ + uint32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ + uint32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */ + uint32 tx_tot_pkts; /* # of user tx pkts (ucast + mcast) */ + uint32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */ + uint32 tx_mcast_pkts; /* # of mcast pkts txed */ + uint64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */ + uint64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */ + uint64 tx_ucast_bytes; /* data bytes txed (ucast) */ + uint64 tx_mcast_bytes; /* # data bytes txed (mcast) */ + uint64 rx_ucast_bytes; /* data bytes recvd (ucast) */ + uint64 rx_mcast_bytes; /* data bytes recvd (mcast) */ + int8 rssi[WL_STA_ANT_MAX]; /* average rssi per antenna + * of data frames + */ + int8 nf[WL_STA_ANT_MAX]; /* per antenna noise floor */ + uint16 aid; /* association ID */ + uint16 ht_capabilities; /* advertised ht caps */ + uint16 vht_flags; /* converted vht flags */ + uint32 tx_pkts_retried; /* # of frames where a retry was + * necessary + */ + uint32 tx_pkts_retry_exhausted; /* # of user frames where a retry + * was exhausted + */ + int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /* Per antenna RSSI of last + * received data frame. + */ + /* TX WLAN retry/failure statistics: + * Separated for host requested frames and WLAN locally generated frames. + * Include unicast frame only where the retries/failures can be counted. + */ + uint32 tx_pkts_total; /* # user frames sent successfully */ + uint32 tx_pkts_retries; /* # user frames retries */ + uint32 tx_pkts_fw_total; /* # FW generated sent successfully */ + uint32 tx_pkts_fw_retries; /* # retries for FW generated frames */ + uint32 tx_pkts_fw_retry_exhausted; /* # FW generated where a retry + * was exhausted + */ + uint32 rx_pkts_retried; /* # rx with retry bit set */ + uint32 tx_rate_fallback; /* lowest fallback TX rate */ +} sta_info_t; + +#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts) + +#define WL_STA_VER 4 + +#define WLC_NUMRATES 16 /* max # of rates in a rateset */ + +typedef struct wlc_rateset { + uint32 count; /* number of rates in rates[] */ + uint8 rates[WLC_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */ + uint8 htphy_membership; /* HT PHY Membership */ + uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ + uint16 vht_mcsmap; /* supported vht mcs nss bit map */ +} wlc_rateset_t; + +/* Used to get specific STA parameters */ +typedef struct { + uint32 val; + struct ether_addr ea; +} scb_val_t; + +/* Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */ +typedef struct { + uint32 code; + scb_val_t ioctl_args; +} authops_t; + +/* channel encoding */ +typedef struct channel_info { + int hw_channel; + int target_channel; + int scan_channel; +} channel_info_t; + +/* For ioctls that take a list of MAC addresses */ +typedef struct maclist { + uint count; /* number of MAC addresses */ + struct ether_addr ea[1]; /* variable length array of MAC addresses */ +} maclist_t; + +/* get pkt count struct passed through ioctl */ +typedef struct get_pktcnt { + uint rx_good_pkt; + uint rx_bad_pkt; + uint tx_good_pkt; + uint tx_bad_pkt; + uint rx_ocast_good_pkt; /* unicast packets destined for others */ +} get_pktcnt_t; + +/* NINTENDO2 */ +#define LQ_IDX_MIN 0 +#define LQ_IDX_MAX 1 +#define LQ_IDX_AVG 2 +#define LQ_IDX_SUM 2 +#define LQ_IDX_LAST 3 +#define LQ_STOP_MONITOR 0 +#define LQ_START_MONITOR 1 + +/* Get averages RSSI, Rx PHY rate and SNR values */ +typedef struct { + int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */ + int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */ + int isvalid; /* Flag indicating whether above data is valid */ +} wl_lq_t; /* Link Quality */ + +typedef enum wl_wakeup_reason_type { + LCD_ON = 1, + LCD_OFF, + DRC1_WAKE, + DRC2_WAKE, + REASON_LAST +} wl_wr_type_t; + +typedef struct { +/* Unique filter id */ + uint32 id; + +/* stores the reason for the last wake up */ + uint8 reason; +} wl_wr_t; + +/* Get MAC specific rate histogram command */ +typedef struct { + struct ether_addr ea; /* MAC Address */ + uint8 ac_cat; /* Access Category */ + uint8 num_pkts; /* Number of packet entries to be averaged */ +} wl_mac_ratehisto_cmd_t; /* MAC Specific Rate Histogram command */ + +/* Get MAC rate histogram response */ +typedef struct { + uint32 rate[DOT11_RATE_MAX + 1]; /* Rates */ + uint32 mcs[WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX]; /* MCS counts */ + uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /* VHT counts */ + uint32 tsf_timer[2][2]; /* Start and End time for 8bytes value */ +} wl_mac_ratehisto_res_t; /* MAC Specific Rate Histogram Response */ + +/* Linux network driver ioctl encoding */ +typedef struct wl_ioctl { + uint cmd; /* common ioctl definition */ + void *buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + uint8 set; /* 1=set IOCTL; 0=query IOCTL */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ +} wl_ioctl_t; + +#ifdef CONFIG_COMPAT +typedef struct compat_wl_ioctl { + uint cmd; /* common ioctl definition */ + uint32 buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + uint8 set; /* 1=set IOCTL; 0=query IOCTL */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ +} compat_wl_ioctl_t; +#endif /* CONFIG_COMPAT */ + +#define WL_NUM_RATES_CCK 4 /* 1, 2, 5.5, 11 Mbps */ +#define WL_NUM_RATES_OFDM 8 /* 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */ +#define WL_NUM_RATES_MCS_1STREAM 8 /* MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */ +#define WL_NUM_RATES_EXTRA_VHT 2 /* Additional VHT 11AC rates */ +#define WL_NUM_RATES_VHT 10 +#define WL_NUM_RATES_MCS32 1 + +/* + * Structure for passing hardware and software + * revision info up from the driver. + */ +typedef struct wlc_rev_info { + uint vendorid; /* PCI vendor id */ + uint deviceid; /* device id of chip */ + uint radiorev; /* radio revision */ + uint chiprev; /* chip revision */ + uint corerev; /* core revision */ + uint boardid; /* board identifier (usu. PCI sub-device id) */ + uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ + uint boardrev; /* board revision */ + uint driverrev; /* driver version */ + uint ucoderev; /* microcode version */ + uint bus; /* bus type */ + uint chipnum; /* chip number */ + uint phytype; /* phy type */ + uint phyrev; /* phy revision */ + uint anarev; /* anacore rev */ + uint chippkg; /* chip package info */ + uint nvramrev; /* nvram revision number */ +} wlc_rev_info_t; + +#define WL_REV_INFO_LEGACY_LENGTH 48 + +#define WL_BRAND_MAX 10 +typedef struct wl_instance_info { + uint instance; + char brand[WL_BRAND_MAX]; +} wl_instance_info_t; + +/* structure to change size of tx fifo */ +typedef struct wl_txfifo_sz { + uint16 magic; + uint16 fifo; + uint16 size; +} wl_txfifo_sz_t; + +/* Transfer info about an IOVar from the driver */ +/* Max supported IOV name size in bytes, + 1 for nul termination */ +#define WLC_IOV_NAME_LEN 30 +typedef struct wlc_iov_trx_s { + uint8 module; + uint8 type; + char name[WLC_IOV_NAME_LEN]; +} wlc_iov_trx_t; + +/* bump this number if you change the ioctl interface */ +#define WLC_IOCTL_VERSION 2 +#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1 + +#ifdef CONFIG_USBRNDIS_RETAIL +/* struct passed in for WLC_NDCONFIG_ITEM */ +typedef struct { + char *name; + void *param; +} ndconfig_item_t; +#endif + + +#define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[0] ... */ + +#define WL_PHY_PAVAR_VER 1 /* pavars version */ +#define WL_PHY_PAVARS2_NUM 3 /* a1, b0, b1 */ +typedef struct wl_pavars2 { + uint16 ver; /* version of this struct */ + uint16 len; /* len of this structure */ + uint16 inuse; /* driver return 1 for a1,b0,b1 in current band range */ + uint16 phy_type; /* phy type */ + uint16 bandrange; + uint16 chain; + uint16 inpa[WL_PHY_PAVARS2_NUM]; /* phy pavars for one band range */ +} wl_pavars2_t; + +typedef struct wl_po { + uint16 phy_type; /* Phy type */ + uint16 band; + uint16 cckpo; + uint32 ofdmpo; + uint16 mcspo[8]; +} wl_po_t; + +#define WL_NUM_RPCALVARS 5 /* number of rpcal vars */ + +typedef struct wl_rpcal { + uint16 value; + uint16 update; +} wl_rpcal_t; + +typedef struct wl_aci_args { + int enter_aci_thresh; /* Trigger level to start detecting ACI */ + int exit_aci_thresh; /* Trigger level to exit ACI mode */ + int usec_spin; /* microsecs to delay between rssi samples */ + int glitch_delay; /* interval between ACI scans when glitch count is consistently high */ + uint16 nphy_adcpwr_enter_thresh; /* ADC power to enter ACI mitigation mode */ + uint16 nphy_adcpwr_exit_thresh; /* ADC power to exit ACI mitigation mode */ + uint16 nphy_repeat_ctr; /* Number of tries per channel to compute power */ + uint16 nphy_num_samples; /* Number of samples to compute power on one channel */ + uint16 nphy_undetect_window_sz; /* num of undetects to exit ACI Mitigation mode */ + uint16 nphy_b_energy_lo_aci; /* low ACI power energy threshold for bphy */ + uint16 nphy_b_energy_md_aci; /* mid ACI power energy threshold for bphy */ + uint16 nphy_b_energy_hi_aci; /* high ACI power energy threshold for bphy */ + uint16 nphy_noise_noassoc_glitch_th_up; /* wl interference 4 */ + uint16 nphy_noise_noassoc_glitch_th_dn; + uint16 nphy_noise_assoc_glitch_th_up; + uint16 nphy_noise_assoc_glitch_th_dn; + uint16 nphy_noise_assoc_aci_glitch_th_up; + uint16 nphy_noise_assoc_aci_glitch_th_dn; + uint16 nphy_noise_assoc_enter_th; + uint16 nphy_noise_noassoc_enter_th; + uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; + uint16 nphy_noise_noassoc_crsidx_incr; + uint16 nphy_noise_assoc_crsidx_incr; + uint16 nphy_noise_crsidx_decr; +} wl_aci_args_t; + +#define WL_ACI_ARGS_LEGACY_LENGTH 16 /* bytes of pre NPHY aci args */ +#define WL_SAMPLECOLLECT_T_VERSION 2 /* version of wl_samplecollect_args_t struct */ +typedef struct wl_samplecollect_args { + /* version 0 fields */ + uint8 coll_us; + int cores; + /* add'l version 1 fields */ + uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */ + uint16 length; /* length of entire structure */ + int8 trigger; + uint16 timeout; + uint16 mode; + uint32 pre_dur; + uint32 post_dur; + uint8 gpio_sel; + uint8 downsamp; + uint8 be_deaf; + uint8 agc; /* loop from init gain and going down */ + uint8 filter; /* override high pass corners to lowest */ + /* add'l version 2 fields */ + uint8 trigger_state; + uint8 module_sel1; + uint8 module_sel2; + uint16 nsamps; + int bitStart; + uint32 gpioCapMask; +} wl_samplecollect_args_t; + +#define WL_SAMPLEDATA_T_VERSION 1 /* version of wl_samplecollect_args_t struct */ +/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */ +#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 + +typedef struct wl_sampledata { + uint16 version; /* structure version */ + uint16 size; /* size of structure */ + uint16 tag; /* Header/Data */ + uint16 length; /* data length */ + uint32 flag; /* bit def */ +} wl_sampledata_t; + + +/* WL_OTA START */ +/* OTA Test Status */ +enum { + WL_OTA_TEST_IDLE = 0, /* Default Idle state */ + WL_OTA_TEST_ACTIVE = 1, /* Test Running */ + WL_OTA_TEST_SUCCESS = 2, /* Successfully Finished Test */ + WL_OTA_TEST_FAIL = 3 /* Test Failed in the Middle */ +}; +/* OTA SYNC Status */ +enum { + WL_OTA_SYNC_IDLE = 0, /* Idle state */ + WL_OTA_SYNC_ACTIVE = 1, /* Waiting for Sync */ + WL_OTA_SYNC_FAIL = 2 /* Sync pkt not recieved */ +}; + +/* Various error states dut can get stuck during test */ +enum { + WL_OTA_SKIP_TEST_CAL_FAIL = 1, /* Phy calibration failed */ + WL_OTA_SKIP_TEST_SYNCH_FAIL = 2, /* Sync Packet not recieved */ + WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL = 3, /* Cmd flow file download failed */ + WL_OTA_SKIP_TEST_NO_TEST_FOUND = 4, /* No test found in Flow file */ + WL_OTA_SKIP_TEST_WL_NOT_UP = 5, /* WL UP failed */ + WL_OTA_SKIP_TEST_UNKNOWN_CALL /* Unintentional scheduling on ota test */ +}; + +/* Differentiator for ota_tx and ota_rx */ +enum { + WL_OTA_TEST_TX = 0, /* ota_tx */ + WL_OTA_TEST_RX = 1, /* ota_rx */ +}; + +/* Catch 3 modes of operation: 20Mhz, 40Mhz, 20 in 40 Mhz */ +enum { + WL_OTA_TEST_BW_20_IN_40MHZ = 0, /* 20 in 40 operation */ + WL_OTA_TEST_BW_20MHZ = 1, /* 20 Mhz operation */ + WL_OTA_TEST_BW_40MHZ = 2 /* full 40Mhz operation */ +}; +typedef struct ota_rate_info { + uint8 rate_cnt; /* Total number of rates */ + uint8 rate_val_mbps[WL_OTA_TEST_MAX_NUM_RATE]; /* array of rates from 1mbps to 130mbps */ + /* for legacy rates : ratein mbps * 2 */ + /* for HT rates : mcs index */ +} ota_rate_info_t; + +typedef struct ota_power_info { + int8 pwr_ctrl_on; /* power control on/off */ + int8 start_pwr; /* starting power/index */ + int8 delta_pwr; /* delta power/index */ + int8 end_pwr; /* end power/index */ +} ota_power_info_t; + +typedef struct ota_packetengine { + uint16 delay; /* Inter-packet delay */ + /* for ota_tx, delay is tx ifs in micro seconds */ + /* for ota_rx, delay is wait time in milliseconds */ + uint16 nframes; /* Number of frames */ + uint16 length; /* Packet length */ +} ota_packetengine_t; + +/* Test info vector */ +typedef struct wl_ota_test_args { + uint8 cur_test; /* test phase */ + uint8 chan; /* channel */ + uint8 bw; /* bandwidth */ + uint8 control_band; /* control band */ + uint8 stf_mode; /* stf mode */ + ota_rate_info_t rt_info; /* Rate info */ + ota_packetengine_t pkteng; /* packeteng info */ + uint8 txant; /* tx antenna */ + uint8 rxant; /* rx antenna */ + ota_power_info_t pwr_info; /* power sweep info */ + uint8 wait_for_sync; /* wait for sync or not */ +} wl_ota_test_args_t; + +typedef struct wl_ota_test_vector { + wl_ota_test_args_t test_arg[WL_OTA_TEST_MAX_NUM_SEQ]; /* Test argument struct */ + uint16 test_cnt; /* Total no of test */ + uint8 file_dwnld_valid; /* File successfully downloaded */ + uint8 sync_timeout; /* sync packet timeout */ + int8 sync_fail_action; /* sync fail action */ + struct ether_addr sync_mac; /* macaddress for sync pkt */ + struct ether_addr tx_mac; /* macaddress for tx */ + struct ether_addr rx_mac; /* macaddress for rx */ + int8 loop_test; /* dbg feature to loop the test */ +} wl_ota_test_vector_t; + + +/* struct copied back form dongle to host to query the status */ +typedef struct wl_ota_test_status { + int16 cur_test_cnt; /* test phase */ + int8 skip_test_reason; /* skip test reasoin */ + wl_ota_test_args_t test_arg; /* cur test arg details */ + uint16 test_cnt; /* total no of test downloaded */ + uint8 file_dwnld_valid; /* file successfully downloaded ? */ + uint8 sync_timeout; /* sync timeout */ + int8 sync_fail_action; /* sync fail action */ + struct ether_addr sync_mac; /* macaddress for sync pkt */ + struct ether_addr tx_mac; /* tx mac address */ + struct ether_addr rx_mac; /* rx mac address */ + uint8 test_stage; /* check the test status */ + int8 loop_test; /* Debug feature to puts test enfine in a loop */ + uint8 sync_status; /* sync status */ +} wl_ota_test_status_t; + +/* WL_OTA END */ + +/* wl_radar_args_t */ +typedef struct { + int npulses; /* required number of pulses at n * t_int */ + int ncontig; /* required number of pulses at t_int */ + int min_pw; /* minimum pulse width (20 MHz clocks) */ + int max_pw; /* maximum pulse width (20 MHz clocks) */ + uint16 thresh0; /* Radar detection, thresh 0 */ + uint16 thresh1; /* Radar detection, thresh 1 */ + uint16 blank; /* Radar detection, blank control */ + uint16 fmdemodcfg; /* Radar detection, fmdemod config */ + int npulses_lp; /* Radar detection, minimum long pulses */ + int min_pw_lp; /* Minimum pulsewidth for long pulses */ + int max_pw_lp; /* Maximum pulsewidth for long pulses */ + int min_fm_lp; /* Minimum fm for long pulses */ + int max_span_lp; /* Maximum deltat for long pulses */ + int min_deltat; /* Minimum spacing between pulses */ + int max_deltat; /* Maximum spacing between pulses */ + uint16 autocorr; /* Radar detection, autocorr on or off */ + uint16 st_level_time; /* Radar detection, start_timing level */ + uint16 t2_min; /* minimum clocks needed to remain in state 2 */ + uint32 version; /* version */ + uint32 fra_pulse_err; /* sample error margin for detecting French radar pulsed */ + int npulses_fra; /* Radar detection, minimum French pulses set */ + int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */ + int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */ + uint16 percal_mask; /* defines which period cal is masked from radar detection */ + int quant; /* quantization resolution to pulse positions */ + uint32 min_burst_intv_lp; /* minimum burst to burst interval for bin3 radar */ + uint32 max_burst_intv_lp; /* maximum burst to burst interval for bin3 radar */ + int nskip_rst_lp; /* number of skipped pulses before resetting lp buffer */ + int max_pw_tol; /* maximum tollerance allowed in detected pulse width for radar detection */ + uint16 feature_mask; /* 16-bit mask to specify enabled features */ +} wl_radar_args_t; + +#define WL_RADAR_ARGS_VERSION 2 + +typedef struct { + uint32 version; /* version */ + uint16 thresh0_20_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */ + uint16 thresh1_20_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */ + uint16 thresh0_40_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */ + uint16 thresh1_40_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */ + uint16 thresh0_80_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */ + uint16 thresh1_80_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */ + uint16 thresh0_20_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */ + uint16 thresh1_20_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */ + uint16 thresh0_40_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */ + uint16 thresh1_40_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */ + uint16 thresh0_80_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */ + uint16 thresh1_80_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */ +#ifdef WL11AC160 + uint16 thresh0_160_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */ + uint16 thresh1_160_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */ + uint16 thresh0_160_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */ + uint16 thresh1_160_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */ +#endif /* WL11AC160 */ +} wl_radar_thr_t; + +#define WL_RADAR_THR_VERSION 2 + +/* RSSI per antenna */ +typedef struct { + uint32 version; /* version field */ + uint32 count; /* number of valid antenna rssi */ + int8 rssi_ant[WL_RSSI_ANT_MAX]; /* rssi per antenna */ +} wl_rssi_ant_t; + +/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */ +typedef struct { + uint state; /* noted by WL_DFS_CACSTATE_XX. */ + uint duration; /* time spent in ms in state. */ + /* as dfs enters ISM state, it removes the operational channel from quiet channel + * list and notes the channel in channel_cleared. set to 0 if no channel is cleared + */ + chanspec_t chanspec_cleared; + /* chanspec cleared used to be a uint, add another to uint16 to maintain size */ + uint16 pad; +} wl_dfs_status_t; + +/* data structure used in 'radar_status' wl interface, which is use to query radar det status */ +typedef struct { + bool detected; + int count; + bool pretended; + uint32 radartype; + uint32 timenow; + uint32 timefromL; + int lp_csect_single; + int detected_pulse_index; + int nconsecq_pulses; + chanspec_t ch; + int pw[10]; + int intv[10]; + int fm[10]; +} wl_radar_status_t; + +#define NUM_PWRCTRL_RATES 12 + +typedef struct { + uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /* User set target */ + uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /* reg and local power limit */ + uint8 txpwr_local_max; /* local max according to the AP */ + uint8 txpwr_local_constraint; /* local constraint according to the AP */ + uint8 txpwr_chan_reg_max; /* Regulatory max for this channel */ + uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /* Latest target for 2.4 and 5 Ghz */ + uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ + uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /* On G phy, OFDM power offset */ + uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /* Max CCK power for this band (SROM) */ + uint8 txpwr_bphy_ofdm_max; /* Max OFDM power for this band (SROM) */ + uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /* Max power for A band (SROM) */ + int8 txpwr_antgain[2]; /* Ant gain for each band - from SROM */ + uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ +} tx_power_legacy_t; + +#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 + +typedef struct { + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint8 local_max; /* local max according to the AP */ + uint8 local_constraint; /* local constraint according to the AP */ + int8 antgain[2]; /* Ant gain for each band - from SROM */ + uint8 rf_cores; /* count of RF Cores being reported */ + uint8 est_Pout[4]; /* Latest tx power out estimate per RF + * chain without adjustment + */ + uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ + uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */ + uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */ + uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */ + uint8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */ +} tx_power_legacy2_t; + +/* TX Power index defines */ +#define WLC_NUM_RATES_CCK WL_NUM_RATES_CCK +#define WLC_NUM_RATES_OFDM WL_NUM_RATES_OFDM +#define WLC_NUM_RATES_MCS_1_STREAM WL_NUM_RATES_MCS_1STREAM +#define WLC_NUM_RATES_MCS_2_STREAM WL_NUM_RATES_MCS_1STREAM +#define WLC_NUM_RATES_MCS32 WL_NUM_RATES_MCS32 +#define WL_TX_POWER_CCK_NUM WL_NUM_RATES_CCK +#define WL_TX_POWER_OFDM_NUM WL_NUM_RATES_OFDM +#define WL_TX_POWER_MCS_1_STREAM_NUM WL_NUM_RATES_MCS_1STREAM +#define WL_TX_POWER_MCS_2_STREAM_NUM WL_NUM_RATES_MCS_1STREAM +#define WL_TX_POWER_MCS_32_NUM WL_NUM_RATES_MCS32 + +#define WL_NUM_2x2_ELEMENTS 4 +#define WL_NUM_3x3_ELEMENTS 6 + +typedef struct { + uint16 ver; /* version of this struct */ + uint16 len; /* length in bytes of this structure */ + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint32 buflen; /* ppr buffer length */ + uint8 pprbuf[1]; /* Latest target power buffer */ +} wl_txppr_t; + +#define WL_TXPPR_VERSION 1 +#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) +#define TX_POWER_T_VERSION 45 +/* number of ppr serialization buffers, it should be reg, board and target */ +#define WL_TXPPR_SER_BUF_NUM (3) + +typedef struct chanspec_txpwr_max { + chanspec_t chanspec; /* chanspec */ + uint8 txpwr_max; /* max txpwr in all the rates */ + uint8 padding; +} chanspec_txpwr_max_t; + +typedef struct wl_chanspec_txpwr_max { + uint16 ver; /* version of this struct */ + uint16 len; /* length in bytes of this structure */ + uint32 count; /* number of elements of (chanspec, txpwr_max) pair */ + chanspec_txpwr_max_t txpwr[1]; /* array of (chanspec, max_txpwr) pair */ +} wl_chanspec_txpwr_max_t; + +#define WL_CHANSPEC_TXPWR_MAX_VER 1 +#define WL_CHANSPEC_TXPWR_MAX_LEN (sizeof(wl_chanspec_txpwr_max_t)) + +typedef struct tx_inst_power { + uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ + uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ +} tx_inst_power_t; + +#define WL_NUM_TXCHAIN_MAX 4 +typedef struct wl_txchain_pwr_offsets { + int8 offset[WL_NUM_TXCHAIN_MAX]; /* quarter dBm signed offset for each chain */ +} wl_txchain_pwr_offsets_t; +/* maximum channels returned by the get valid channels iovar */ +#define WL_NUMCHANNELS 64 + +/* + * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, + * a one-byte length, and a variable length value. RSSI type tuple must be present + * in the array. + * + * Types are defined in "join preference types" section. + * + * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple + * and must be set to zero. + * + * Values are defined below. + * + * 1. RSSI - 2 octets + * offset 0: reserved + * offset 1: reserved + * + * 2. WPA - 2 + 12 * n octets (n is # tuples defined below) + * offset 0: reserved + * offset 1: # of tuples + * offset 2: tuple 1 + * offset 14: tuple 2 + * ... + * offset 2 + 12 * (n - 1) octets: tuple n + * + * struct wpa_cfg_tuple { + * uint8 akm[DOT11_OUI_LEN+1]; akm suite + * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite + * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite + * }; + * + * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY. + * + * 3. BAND - 2 octets + * offset 0: reserved + * offset 1: see "band preference" and "band types" + * + * 4. BAND RSSI - 2 octets + * offset 0: band types + * offset 1: +ve RSSI boost value in dB + */ + +struct tsinfo_arg { + uint8 octets[3]; +}; + +#define RATE_CCK_1MBPS 0 +#define RATE_CCK_2MBPS 1 +#define RATE_CCK_5_5MBPS 2 +#define RATE_CCK_11MBPS 3 + +#define RATE_LEGACY_OFDM_6MBPS 0 +#define RATE_LEGACY_OFDM_9MBPS 1 +#define RATE_LEGACY_OFDM_12MBPS 2 +#define RATE_LEGACY_OFDM_18MBPS 3 +#define RATE_LEGACY_OFDM_24MBPS 4 +#define RATE_LEGACY_OFDM_36MBPS 5 +#define RATE_LEGACY_OFDM_48MBPS 6 +#define RATE_LEGACY_OFDM_54MBPS 7 + +#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION 1 + +typedef struct wl_bsstrans_rssi { + int8 rssi_2g; /* RSSI in dbm for 2.4 G */ + int8 rssi_5g; /* RSSI in dbm for 5G, unused for cck */ +} wl_bsstrans_rssi_t; + +#define RSSI_RATE_MAP_MAX_STREAMS 4 /* max streams supported */ + +/* RSSI to rate mapping, all 20Mhz, no SGI */ +typedef struct wl_bsstrans_rssi_rate_map { + uint16 ver; + uint16 len; /* length of entire structure */ + wl_bsstrans_rssi_t cck[WL_NUM_RATES_CCK]; /* 2.4G only */ + wl_bsstrans_rssi_t ofdm[WL_NUM_RATES_OFDM]; /* 6 to 54mbps */ + wl_bsstrans_rssi_t phy_n[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_MCS_1STREAM]; /* MCS0-7 */ + wl_bsstrans_rssi_t phy_ac[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_VHT]; /* MCS0-9 */ +} wl_bsstrans_rssi_rate_map_t; + +#define WL_BSSTRANS_ROAMTHROTTLE_VERSION 1 + +/* Configure number of scans allowed per throttle period */ +typedef struct wl_bsstrans_roamthrottle { + uint16 ver; + uint16 period; + uint16 scans_allowed; +} wl_bsstrans_roamthrottle_t; + +#define NFIFO 6 /* # tx/rx fifopairs */ +#define NREINITREASONCOUNT 8 +#define REINITREASONIDX(_x) (((_x) < NREINITREASONCOUNT) ? (_x) : 0) + +#define WL_CNT_T_VERSION 10 /* current version of wl_cnt_t struct */ + +typedef struct { + uint16 version; /* see definition of WL_CNT_T_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txframe; /* tx data frames */ + uint32 txbyte; /* tx data bytes */ + uint32 txretrans; /* tx mac retransmits */ + uint32 txerror; /* tx data errors (derived: sum of others) */ + uint32 txctl; /* tx management frames */ + uint32 txprshort; /* tx short preamble frames */ + uint32 txserr; /* tx status errors */ + uint32 txnobuf; /* tx out of buffers errors */ + uint32 txnoassoc; /* tx discard because we're not associated */ + uint32 txrunt; /* tx runt frames */ + uint32 txchit; /* tx header cache hit (fastpath) */ + uint32 txcmiss; /* tx header cache miss (slowpath) */ + + /* transmit chip error counters */ + uint32 txuflo; /* tx fifo underflows */ + uint32 txphyerr; /* tx phy errors (indicated in tx status) */ + uint32 txphycrs; + + /* receive stat counters */ + uint32 rxframe; /* rx data frames */ + uint32 rxbyte; /* rx data bytes */ + uint32 rxerror; /* rx data errors (derived: sum of others) */ + uint32 rxctl; /* rx management frames */ + uint32 rxnobuf; /* rx out of buffers errors */ + uint32 rxnondata; /* rx non data frames in the data channel errors */ + uint32 rxbadds; /* rx bad DS errors */ + uint32 rxbadcm; /* rx bad control or management frames */ + uint32 rxfragerr; /* rx fragmentation errors */ + uint32 rxrunt; /* rx runt frames */ + uint32 rxgiant; /* rx giant frames */ + uint32 rxnoscb; /* rx no scb error */ + uint32 rxbadproto; /* rx invalid frames */ + uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ + uint32 rxbadda; /* rx frames tossed for invalid da */ + uint32 rxfilter; /* rx frames filtered out */ + + /* receive chip error counters */ + uint32 rxoflo; /* rx fifo overflow errors */ + uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ + + uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ + uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ + uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ + + /* misc counters */ + uint32 dmade; /* tx/rx dma descriptor errors */ + uint32 dmada; /* tx/rx dma data errors */ + uint32 dmape; /* tx/rx dma descriptor protocol errors */ + uint32 reset; /* reset count */ + uint32 tbtt; /* cnts the TBTT int's */ + uint32 txdmawar; + uint32 pkt_callback_reg_fail; /* callbacks register failure */ + + /* MAC counters: 32-bit version of d11.h's macstat_t */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txdnlfrm; /* Not used */ + uint32 txbcnfrm; /* beacons transmitted */ + uint32 txfunfl[6]; /* per-fifo tx underflows */ + uint32 rxtoolate; /* receive too late */ + uint32 txfbw; /* transmit at fallback bw (dynamic bw) */ + uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS + * or BCN) + */ + uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for + * driver enqueued frames + */ + uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ + uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ + uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not + * data/control/management + */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ + uint32 rxbadplcp; /* parity check of the PLCP header failed */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ + uint32 rxstrt; /* Number of received frames with a good PLCP + * (i.e. passing parity check) + */ + uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ + uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ + uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ + uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ + uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ + uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ + uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ + uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ + uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ + uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC + * (unlikely to see these) + */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from + * other BSS (WDS FRAME) + */ + uint32 rxbeaconobss; /* beacons received from other BSS */ + uint32 rxrsptmout; /* Number of response timeouts for transmitted frames + * expecting a response + */ + uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ + uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ + uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ + uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ + uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ + uint32 pmqovfl; /* Number of PMQ overflows */ + uint32 rxcgprqfrm; /* Number of received Probe requests that made it into + * the PRQ fifo + */ + uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ + uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did + * not get ACK + */ + uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ + uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ + * fifo because a probe response could not be sent out within + * the time limit defined in M_PRS_MAXTIME + */ + uint32 rxnack; /* obsolete */ + uint32 frmscons; /* obsolete */ + uint32 txnack; /* obsolete */ + uint32 rxback; /* blockack rxcnt */ + uint32 txback; /* blockack txcnt */ + + /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ + uint32 txfrag; /* dot11TransmittedFragmentCount */ + uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ + uint32 txfail; /* dot11FailedCount */ + uint32 txretry; /* dot11RetryCount */ + uint32 txretrie; /* dot11MultipleRetryCount */ + uint32 rxdup; /* dot11FrameduplicateCount */ + uint32 txrts; /* dot11RTSSuccessCount */ + uint32 txnocts; /* dot11RTSFailureCount */ + uint32 txnoack; /* dot11ACKFailureCount */ + uint32 rxfrag; /* dot11ReceivedFragmentCount */ + uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ + uint32 rxcrc; /* dot11FCSErrorCount */ + uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ + uint32 rxundec; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay; /* TKIPReplays */ + uint32 ccmpfmterr; /* CCMPFormatErrors */ + uint32 ccmpreplay; /* CCMPReplays */ + uint32 ccmpundec; /* CCMPDecryptErrors */ + uint32 fourwayfail; /* FourWayHandshakeFailures */ + uint32 wepundec; /* dot11WEPUndecryptableCount */ + uint32 wepicverr; /* dot11WEPICVErrorCount */ + uint32 decsuccess; /* DecryptSuccessCount */ + uint32 tkipicverr; /* TKIPICVErrorCount */ + uint32 wepexcluded; /* dot11WEPExcludedCount */ + + uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ + uint32 psmwds; /* Count PSM watchdogs */ + uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ + + /* MBSS counters, AP only */ + uint32 prq_entries_handled; /* PRQ entries read in */ + uint32 prq_undirected_entries; /* which were bcast bss & ssid */ + uint32 prq_bad_entries; /* which could not be translated to info */ + uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ + uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ + uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ + uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ + + /* per-rate receive stat counters */ + uint32 rx1mbps; /* packets rx at 1Mbps */ + uint32 rx2mbps; /* packets rx at 2Mbps */ + uint32 rx5mbps5; /* packets rx at 5.5Mbps */ + uint32 rx6mbps; /* packets rx at 6Mbps */ + uint32 rx9mbps; /* packets rx at 9Mbps */ + uint32 rx11mbps; /* packets rx at 11Mbps */ + uint32 rx12mbps; /* packets rx at 12Mbps */ + uint32 rx18mbps; /* packets rx at 18Mbps */ + uint32 rx24mbps; /* packets rx at 24Mbps */ + uint32 rx36mbps; /* packets rx at 36Mbps */ + uint32 rx48mbps; /* packets rx at 48Mbps */ + uint32 rx54mbps; /* packets rx at 54Mbps */ + uint32 rx108mbps; /* packets rx at 108mbps */ + uint32 rx162mbps; /* packets rx at 162mbps */ + uint32 rx216mbps; /* packets rx at 216 mbps */ + uint32 rx270mbps; /* packets rx at 270 mbps */ + uint32 rx324mbps; /* packets rx at 324 mbps */ + uint32 rx378mbps; /* packets rx at 378 mbps */ + uint32 rx432mbps; /* packets rx at 432 mbps */ + uint32 rx486mbps; /* packets rx at 486 mbps */ + uint32 rx540mbps; /* packets rx at 540 mbps */ + + /* pkteng rx frame stats */ + uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ + uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ + + uint32 rfdisable; /* count of radio disables */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 bphy_badplcp; + + uint32 txexptime; /* Tx frames suppressed due to timer expiration */ + + uint32 txmpdu_sgi; /* count for sgi transmit */ + uint32 rxmpdu_sgi; /* count for sgi received */ + uint32 txmpdu_stbc; /* count for stbc transmit */ + uint32 rxmpdu_stbc; /* count for stbc received */ + + uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay_mcst; /* TKIPReplays */ + uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ + uint32 ccmpreplay_mcst; /* CCMPReplays */ + uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ + uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ + uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ + uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ + uint32 decsuccess_mcst; /* DecryptSuccessCount */ + uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ + uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ + + uint32 dma_hang; /* count for dma hang */ + uint32 reinit; /* count for reinit */ + + uint32 pstatxucast; /* count of ucast frames xmitted on all psta assoc */ + uint32 pstatxnoassoc; /* count of txnoassoc frames xmitted on all psta assoc */ + uint32 pstarxucast; /* count of ucast frames received on all psta assoc */ + uint32 pstarxbcmc; /* count of bcmc frames received on all psta */ + uint32 pstatxbcmc; /* count of bcmc frames transmitted on all psta */ + + uint32 cso_passthrough; /* hw cso required but passthrough */ + uint32 cso_normal; /* hw cso hdr for normal process */ + uint32 chained; /* number of frames chained */ + uint32 chainedsz1; /* number of chain size 1 frames */ + uint32 unchained; /* number of frames not chained */ + uint32 maxchainsz; /* max chain size so far */ + uint32 currchainsz; /* current chain size */ + uint32 rxdrop20s; /* drop secondary cnt */ + uint32 pciereset; /* Secondary Bus Reset issued by driver */ + uint32 cfgrestore; /* configspace restore by driver */ + uint32 reinitreason[NREINITREASONCOUNT]; /* reinitreason counters; 0: Unknown reason */ + uint32 rxrtry; /* num of received packets with retry bit on */ +} wl_cnt_t; + +typedef struct { + uint16 version; /* see definition of WL_CNT_T_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txframe; /* tx data frames */ + uint32 txbyte; /* tx data bytes */ + uint32 txretrans; /* tx mac retransmits */ + uint32 txerror; /* tx data errors (derived: sum of others) */ + uint32 txctl; /* tx management frames */ + uint32 txprshort; /* tx short preamble frames */ + uint32 txserr; /* tx status errors */ + uint32 txnobuf; /* tx out of buffers errors */ + uint32 txnoassoc; /* tx discard because we're not associated */ + uint32 txrunt; /* tx runt frames */ + uint32 txchit; /* tx header cache hit (fastpath) */ + uint32 txcmiss; /* tx header cache miss (slowpath) */ + + /* transmit chip error counters */ + uint32 txuflo; /* tx fifo underflows */ + uint32 txphyerr; /* tx phy errors (indicated in tx status) */ + uint32 txphycrs; + + /* receive stat counters */ + uint32 rxframe; /* rx data frames */ + uint32 rxbyte; /* rx data bytes */ + uint32 rxerror; /* rx data errors (derived: sum of others) */ + uint32 rxctl; /* rx management frames */ + uint32 rxnobuf; /* rx out of buffers errors */ + uint32 rxnondata; /* rx non data frames in the data channel errors */ + uint32 rxbadds; /* rx bad DS errors */ + uint32 rxbadcm; /* rx bad control or management frames */ + uint32 rxfragerr; /* rx fragmentation errors */ + uint32 rxrunt; /* rx runt frames */ + uint32 rxgiant; /* rx giant frames */ + uint32 rxnoscb; /* rx no scb error */ + uint32 rxbadproto; /* rx invalid frames */ + uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ + uint32 rxbadda; /* rx frames tossed for invalid da */ + uint32 rxfilter; /* rx frames filtered out */ + + /* receive chip error counters */ + uint32 rxoflo; /* rx fifo overflow errors */ + uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ + + uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ + uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ + uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ + + /* misc counters */ + uint32 dmade; /* tx/rx dma descriptor errors */ + uint32 dmada; /* tx/rx dma data errors */ + uint32 dmape; /* tx/rx dma descriptor protocol errors */ + uint32 reset; /* reset count */ + uint32 tbtt; /* cnts the TBTT int's */ + uint32 txdmawar; + uint32 pkt_callback_reg_fail; /* callbacks register failure */ + + /* MAC counters: 32-bit version of d11.h's macstat_t */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txdnlfrm; /* Not used */ + uint32 txbcnfrm; /* beacons transmitted */ + uint32 txfunfl[6]; /* per-fifo tx underflows */ + uint32 rxtoolate; /* receive too late */ + uint32 txfbw; /* transmit at fallback bw (dynamic bw) */ + uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS + * or BCN) + */ + uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for + * driver enqueued frames + */ + uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ + uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ + uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not + * data/control/management + */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ + uint32 rxbadplcp; /* parity check of the PLCP header failed */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ + uint32 rxstrt; /* Number of received frames with a good PLCP + * (i.e. passing parity check) + */ + uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ + uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ + uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ + uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ + uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ + uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ + uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ + uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ + uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ + uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC + * (unlikely to see these) + */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from + * other BSS (WDS FRAME) + */ + uint32 rxbeaconobss; /* beacons received from other BSS */ + uint32 rxrsptmout; /* Number of response timeouts for transmitted frames + * expecting a response + */ + uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ + uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ + uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ + uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ + uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ + uint32 pmqovfl; /* Number of PMQ overflows */ + uint32 rxcgprqfrm; /* Number of received Probe requests that made it into + * the PRQ fifo + */ + uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ + uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did + * not get ACK + */ + uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ + uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ + * fifo because a probe response could not be sent out within + * the time limit defined in M_PRS_MAXTIME + */ + uint32 rxnack; + uint32 frmscons; + uint32 txnack; /* obsolete */ + uint32 rxback; /* blockack rxcnt */ + uint32 txback; /* blockack txcnt */ + + /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ + uint32 txfrag; /* dot11TransmittedFragmentCount */ + uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ + uint32 txfail; /* dot11FailedCount */ + uint32 txretry; /* dot11RetryCount */ + uint32 txretrie; /* dot11MultipleRetryCount */ + uint32 rxdup; /* dot11FrameduplicateCount */ + uint32 txrts; /* dot11RTSSuccessCount */ + uint32 txnocts; /* dot11RTSFailureCount */ + uint32 txnoack; /* dot11ACKFailureCount */ + uint32 rxfrag; /* dot11ReceivedFragmentCount */ + uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ + uint32 rxcrc; /* dot11FCSErrorCount */ + uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ + uint32 rxundec; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay; /* TKIPReplays */ + uint32 ccmpfmterr; /* CCMPFormatErrors */ + uint32 ccmpreplay; /* CCMPReplays */ + uint32 ccmpundec; /* CCMPDecryptErrors */ + uint32 fourwayfail; /* FourWayHandshakeFailures */ + uint32 wepundec; /* dot11WEPUndecryptableCount */ + uint32 wepicverr; /* dot11WEPICVErrorCount */ + uint32 decsuccess; /* DecryptSuccessCount */ + uint32 tkipicverr; /* TKIPICVErrorCount */ + uint32 wepexcluded; /* dot11WEPExcludedCount */ + + uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay_mcst; /* TKIPReplays */ + uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ + uint32 ccmpreplay_mcst; /* CCMPReplays */ + uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ + uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ + uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ + uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ + uint32 decsuccess_mcst; /* DecryptSuccessCount */ + uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ + uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ + + uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ + uint32 txexptime; /* Tx frames suppressed due to timer expiration */ + uint32 psmwds; /* Count PSM watchdogs */ + uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ + + /* MBSS counters, AP only */ + uint32 prq_entries_handled; /* PRQ entries read in */ + uint32 prq_undirected_entries; /* which were bcast bss & ssid */ + uint32 prq_bad_entries; /* which could not be translated to info */ + uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ + uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ + uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ + uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ + + /* per-rate receive stat counters */ + uint32 rx1mbps; /* packets rx at 1Mbps */ + uint32 rx2mbps; /* packets rx at 2Mbps */ + uint32 rx5mbps5; /* packets rx at 5.5Mbps */ + uint32 rx6mbps; /* packets rx at 6Mbps */ + uint32 rx9mbps; /* packets rx at 9Mbps */ + uint32 rx11mbps; /* packets rx at 11Mbps */ + uint32 rx12mbps; /* packets rx at 12Mbps */ + uint32 rx18mbps; /* packets rx at 18Mbps */ + uint32 rx24mbps; /* packets rx at 24Mbps */ + uint32 rx36mbps; /* packets rx at 36Mbps */ + uint32 rx48mbps; /* packets rx at 48Mbps */ + uint32 rx54mbps; /* packets rx at 54Mbps */ + uint32 rx108mbps; /* packets rx at 108mbps */ + uint32 rx162mbps; /* packets rx at 162mbps */ + uint32 rx216mbps; /* packets rx at 216 mbps */ + uint32 rx270mbps; /* packets rx at 270 mbps */ + uint32 rx324mbps; /* packets rx at 324 mbps */ + uint32 rx378mbps; /* packets rx at 378 mbps */ + uint32 rx432mbps; /* packets rx at 432 mbps */ + uint32 rx486mbps; /* packets rx at 486 mbps */ + uint32 rx540mbps; /* packets rx at 540 mbps */ + + /* pkteng rx frame stats */ + uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ + uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ + + uint32 rfdisable; /* count of radio disables */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 bphy_badplcp; + + uint32 txmpdu_sgi; /* count for sgi transmit */ + uint32 rxmpdu_sgi; /* count for sgi received */ + uint32 txmpdu_stbc; /* count for stbc transmit */ + uint32 rxmpdu_stbc; /* count for stbc received */ + + uint32 rxdrop20s; /* drop secondary cnt */ + +} wl_cnt_ver_six_t; + +#define WL_DELTA_STATS_T_VERSION 2 /* current version of wl_delta_stats_t struct */ + +typedef struct { + uint16 version; /* see definition of WL_DELTA_STATS_T_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txframe; /* tx data frames */ + uint32 txbyte; /* tx data bytes */ + uint32 txretrans; /* tx mac retransmits */ + uint32 txfail; /* tx failures */ + + /* receive stat counters */ + uint32 rxframe; /* rx data frames */ + uint32 rxbyte; /* rx data bytes */ + + /* per-rate receive stat counters */ + uint32 rx1mbps; /* packets rx at 1Mbps */ + uint32 rx2mbps; /* packets rx at 2Mbps */ + uint32 rx5mbps5; /* packets rx at 5.5Mbps */ + uint32 rx6mbps; /* packets rx at 6Mbps */ + uint32 rx9mbps; /* packets rx at 9Mbps */ + uint32 rx11mbps; /* packets rx at 11Mbps */ + uint32 rx12mbps; /* packets rx at 12Mbps */ + uint32 rx18mbps; /* packets rx at 18Mbps */ + uint32 rx24mbps; /* packets rx at 24Mbps */ + uint32 rx36mbps; /* packets rx at 36Mbps */ + uint32 rx48mbps; /* packets rx at 48Mbps */ + uint32 rx54mbps; /* packets rx at 54Mbps */ + uint32 rx108mbps; /* packets rx at 108mbps */ + uint32 rx162mbps; /* packets rx at 162mbps */ + uint32 rx216mbps; /* packets rx at 216 mbps */ + uint32 rx270mbps; /* packets rx at 270 mbps */ + uint32 rx324mbps; /* packets rx at 324 mbps */ + uint32 rx378mbps; /* packets rx at 378 mbps */ + uint32 rx432mbps; /* packets rx at 432 mbps */ + uint32 rx486mbps; /* packets rx at 486 mbps */ + uint32 rx540mbps; /* packets rx at 540 mbps */ + + /* phy stats */ + uint32 rxbadplcp; + uint32 rxcrsglitch; + uint32 bphy_rxcrsglitch; + uint32 bphy_badplcp; + +} wl_delta_stats_t; + + +typedef struct { + uint32 packets; + uint32 bytes; +} wl_traffic_stats_t; + +typedef struct { + uint16 version; /* see definition of WL_WME_CNT_VERSION */ + uint16 length; /* length of entire structure */ + + wl_traffic_stats_t tx[AC_COUNT]; /* Packets transmitted */ + wl_traffic_stats_t tx_failed[AC_COUNT]; /* Packets dropped or failed to transmit */ + wl_traffic_stats_t rx[AC_COUNT]; /* Packets received */ + wl_traffic_stats_t rx_failed[AC_COUNT]; /* Packets failed to receive */ + + wl_traffic_stats_t forward[AC_COUNT]; /* Packets forwarded by AP */ + + wl_traffic_stats_t tx_expired[AC_COUNT]; /* packets dropped due to lifetime expiry */ + +} wl_wme_cnt_t; + +struct wl_msglevel2 { + uint32 low; + uint32 high; +}; + +typedef struct wl_mkeep_alive_pkt { + uint16 version; /* Version for mkeep_alive */ + uint16 length; /* length of fixed parameters in the structure */ + uint32 period_msec; + uint16 len_bytes; + uint8 keep_alive_id; /* 0 - 3 for N = 4 */ + uint8 data[1]; +} wl_mkeep_alive_pkt_t; + +#define WL_MKEEP_ALIVE_VERSION 1 +#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) +#define WL_MKEEP_ALIVE_PRECISION 500 + +/* TCP Keep-Alive conn struct */ +typedef struct wl_mtcpkeep_alive_conn_pkt { + struct ether_addr saddr; /* src mac address */ + struct ether_addr daddr; /* dst mac address */ + struct ipv4_addr sipaddr; /* source IP addr */ + struct ipv4_addr dipaddr; /* dest IP addr */ + uint16 sport; /* src port */ + uint16 dport; /* dest port */ + uint32 seq; /* seq number */ + uint32 ack; /* ACK number */ + uint16 tcpwin; /* TCP window */ +} wl_mtcpkeep_alive_conn_pkt_t; + +/* TCP Keep-Alive interval struct */ +typedef struct wl_mtcpkeep_alive_timers_pkt { + uint16 interval; /* interval timer */ + uint16 retry_interval; /* retry_interval timer */ + uint16 retry_count; /* retry_count */ +} wl_mtcpkeep_alive_timers_pkt_t; + +typedef struct wake_info { + uint32 wake_reason; + uint32 wake_info_len; /* size of packet */ + uchar packet[1]; +} wake_info_t; + +typedef struct wake_pkt { + uint32 wake_pkt_len; /* size of packet */ + uchar packet[1]; +} wake_pkt_t; + + +#define WL_MTCPKEEP_ALIVE_VERSION 1 + +#ifdef WLBA + +#define WLC_BA_CNT_VERSION 1 /* current version of wlc_ba_cnt_t */ + +/* block ack related stats */ +typedef struct wlc_ba_cnt { + uint16 version; /* WLC_BA_CNT_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txpdu; /* pdus sent */ + uint32 txsdu; /* sdus sent */ + uint32 txfc; /* tx side flow controlled packets */ + uint32 txfci; /* tx side flow control initiated */ + uint32 txretrans; /* retransmitted pdus */ + uint32 txbatimer; /* ba resend due to timer */ + uint32 txdrop; /* dropped packets */ + uint32 txaddbareq; /* addba req sent */ + uint32 txaddbaresp; /* addba resp sent */ + uint32 txdelba; /* delba sent */ + uint32 txba; /* ba sent */ + uint32 txbar; /* bar sent */ + uint32 txpad[4]; /* future */ + + /* receive side counters */ + uint32 rxpdu; /* pdus recd */ + uint32 rxqed; /* pdus buffered before sending up */ + uint32 rxdup; /* duplicate pdus */ + uint32 rxnobuf; /* pdus discarded due to no buf */ + uint32 rxaddbareq; /* addba req recd */ + uint32 rxaddbaresp; /* addba resp recd */ + uint32 rxdelba; /* delba recd */ + uint32 rxba; /* ba recd */ + uint32 rxbar; /* bar recd */ + uint32 rxinvba; /* invalid ba recd */ + uint32 rxbaholes; /* ba recd with holes */ + uint32 rxunexp; /* unexpected packets */ + uint32 rxpad[4]; /* future */ +} wlc_ba_cnt_t; +#endif /* WLBA */ + +/* structure for per-tid ampdu control */ +struct ampdu_tid_control { + uint8 tid; /* tid */ + uint8 enable; /* enable/disable */ +}; + +/* struct for ampdu tx/rx aggregation control */ +struct ampdu_aggr { + int8 aggr_override; /* aggr overrided by dongle. Not to be set by host. */ + uint16 conf_TID_bmap; /* bitmap of TIDs to configure */ + uint16 enab_TID_bmap; /* enable/disable per TID */ +}; + +/* structure for identifying ea/tid for sending addba/delba */ +struct ampdu_ea_tid { + struct ether_addr ea; /* Station address */ + uint8 tid; /* tid */ + uint8 initiator; /* 0 is recipient, 1 is originator */ +}; +/* structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */ +struct ampdu_retry_tid { + uint8 tid; /* tid */ + uint8 retry; /* retry value */ +}; + +#define BDD_FNAME_LEN 32 /* Max length of friendly name */ +typedef struct bdd_fname { + uint8 len; /* length of friendly name */ + uchar name[BDD_FNAME_LEN]; /* friendly name */ +} bdd_fname_t; + +/* structure for addts arguments */ +/* For ioctls that take a list of TSPEC */ +struct tslist { + int count; /* number of tspecs */ + struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */ +}; + +#ifdef WLTDLS +/* structure for tdls iovars */ +typedef struct tdls_iovar { + struct ether_addr ea; /* Station address */ + uint8 mode; /* mode: depends on iovar */ + chanspec_t chanspec; + uint32 pad; /* future */ +} tdls_iovar_t; + +#define TDLS_WFD_IE_SIZE 512 +/* structure for tdls wfd ie */ +typedef struct tdls_wfd_ie_iovar { + struct ether_addr ea; /* Station address */ + uint8 mode; + uint16 length; + uint8 data[TDLS_WFD_IE_SIZE]; +} tdls_wfd_ie_iovar_t; +#endif /* WLTDLS */ + +/* structure for addts/delts arguments */ +typedef struct tspec_arg { + uint16 version; /* see definition of TSPEC_ARG_VERSION */ + uint16 length; /* length of entire structure */ + uint flag; /* bit field */ + /* TSPEC Arguments */ + struct tsinfo_arg tsinfo; /* TS Info bit field */ + uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ + uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ + uint min_srv_interval; /* Minimum Service Interval (us) */ + uint max_srv_interval; /* Maximum Service Interval (us) */ + uint inactivity_interval; /* Inactivity Interval (us) */ + uint suspension_interval; /* Suspension Interval (us) */ + uint srv_start_time; /* Service Start Time (us) */ + uint min_data_rate; /* Minimum Data Rate (bps) */ + uint mean_data_rate; /* Mean Data Rate (bps) */ + uint peak_data_rate; /* Peak Data Rate (bps) */ + uint max_burst_size; /* Maximum Burst Size (bytes) */ + uint delay_bound; /* Delay Bound (us) */ + uint min_phy_rate; /* Minimum PHY Rate (bps) */ + uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */ + uint16 medium_time; /* Medium Time (32 us/s periods) */ + uint8 dialog_token; /* dialog token */ +} tspec_arg_t; + +/* tspec arg for desired station */ +typedef struct tspec_per_sta_arg { + struct ether_addr ea; + struct tspec_arg ts; +} tspec_per_sta_arg_t; + +/* structure for max bandwidth for each access category */ +typedef struct wme_max_bandwidth { + uint32 ac[AC_COUNT]; /* max bandwidth for each access category */ +} wme_max_bandwidth_t; + +#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) + +/* current version of wl_tspec_arg_t struct */ +#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */ +#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */ +#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */ +#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */ + + +#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80 +#define WLC_WOWL_MAX_KEEPALIVE 2 + +/* Packet lifetime configuration per ac */ +typedef struct wl_lifetime { + uint32 ac; /* access class */ + uint32 lifetime; /* Packet lifetime value in ms */ +} wl_lifetime_t; + +/* Channel Switch Announcement param */ +typedef struct wl_chan_switch { + uint8 mode; /* value 0 or 1 */ + uint8 count; /* count # of beacons before switching */ + chanspec_t chspec; /* chanspec */ + uint8 reg; /* regulatory class */ + uint8 frame_type; /* csa frame type, unicast or broadcast */ +} wl_chan_switch_t; + +enum { + PFN_LIST_ORDER, + PFN_RSSI +}; + +enum { + DISABLE, + ENABLE +}; + +enum { + OFF_ADAPT, + SMART_ADAPT, + STRICT_ADAPT, + SLOW_ADAPT +}; + +#define SORT_CRITERIA_BIT 0 +#define AUTO_NET_SWITCH_BIT 1 +#define ENABLE_BKGRD_SCAN_BIT 2 +#define IMMEDIATE_SCAN_BIT 3 +#define AUTO_CONNECT_BIT 4 +#define ENABLE_BD_SCAN_BIT 5 +#define ENABLE_ADAPTSCAN_BIT 6 +#define IMMEDIATE_EVENT_BIT 8 +#define SUPPRESS_SSID_BIT 9 +#define ENABLE_NET_OFFLOAD_BIT 10 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_BIT 11 + +#define SORT_CRITERIA_MASK 0x0001 +#define AUTO_NET_SWITCH_MASK 0x0002 +#define ENABLE_BKGRD_SCAN_MASK 0x0004 +#define IMMEDIATE_SCAN_MASK 0x0008 +#define AUTO_CONNECT_MASK 0x0010 + +#define ENABLE_BD_SCAN_MASK 0x0020 +#define ENABLE_ADAPTSCAN_MASK 0x00c0 +#define IMMEDIATE_EVENT_MASK 0x0100 +#define SUPPRESS_SSID_MASK 0x0200 +#define ENABLE_NET_OFFLOAD_MASK 0x0400 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_MASK 0x0800 + +#define PFN_VERSION 2 +#define PFN_SCANRESULT_VERSION 1 +#define MAX_PFN_LIST_COUNT 16 + +#define PFN_COMPLETE 1 +#define PFN_INCOMPLETE 0 + +#define DEFAULT_BESTN 2 +#define DEFAULT_MSCAN 0 +#define DEFAULT_REPEAT 10 +#define DEFAULT_EXP 2 + +#define PFN_PARTIAL_SCAN_BIT 0 +#define PFN_PARTIAL_SCAN_MASK 1 + +#define PFN_SWC_RSSI_WINDOW_MAX 8 +#define PFN_SWC_MAX_NUM_APS 16 +#define PFN_HOTLIST_MAX_NUM_APS 64 + +#define MAX_EPNO_HIDDEN_SSID 8 +#define MAX_WHITELIST_SSID 2 + +/* PFN network info structure */ +typedef struct wl_pfn_subnet_info { + struct ether_addr BSSID; + uint8 channel; /* channel number only */ + uint8 SSID_len; + uint8 SSID[32]; +} wl_pfn_subnet_info_t; + +typedef struct wl_pfn_net_info { + wl_pfn_subnet_info_t pfnsubnet; + int16 RSSI; /* receive signal strength (in dBm) */ + uint16 timestamp; /* age in seconds */ +} wl_pfn_net_info_t; + +typedef struct wl_pfn_lnet_info { + wl_pfn_subnet_info_t pfnsubnet; /* BSSID + channel + SSID len + SSID */ + uint16 flags; /* partial scan, etc */ + int16 RSSI; /* receive signal strength (in dBm) */ + uint32 timestamp; /* age in miliseconds */ + uint16 rtt0; /* estimated distance to this AP in centimeters */ + uint16 rtt1; /* standard deviation of the distance to this AP in centimeters */ +} wl_pfn_lnet_info_t; + +typedef struct wl_pfn_lscanresults { + uint32 version; + uint32 status; + uint32 count; + wl_pfn_lnet_info_t netinfo[1]; +} wl_pfn_lscanresults_t; + +/* this is used to report on 1-* pfn scan results */ +typedef struct wl_pfn_scanresults { + uint32 version; + uint32 status; + uint32 count; + wl_pfn_net_info_t netinfo[1]; +} wl_pfn_scanresults_t; + +typedef struct wl_pfn_significant_net { + uint16 flags; + uint16 channel; + struct ether_addr BSSID; + int8 rssi[PFN_SWC_RSSI_WINDOW_MAX]; +} wl_pfn_significant_net_t; + +typedef struct wl_pfn_swc_results { + uint32 version; + uint32 pkt_count; + uint32 total_count; + wl_pfn_significant_net_t list[1]; +} wl_pfn_swc_results_t; + +/* used to report exactly one scan result */ +/* plus reports detailed scan info in bss_info */ +typedef struct wl_pfn_scanresult { + uint32 version; + uint32 status; + uint32 count; + wl_pfn_net_info_t netinfo; + wl_bss_info_t bss_info; +} wl_pfn_scanresult_t; + +/* PFN data structure */ +typedef struct wl_pfn_param { + int32 version; /* PNO parameters version */ + int32 scan_freq; /* Scan frequency */ + int32 lost_network_timeout; /* Timeout in sec. to declare + * discovered network as lost + */ + int16 flags; /* Bit field to control features + * of PFN such as sort criteria auto + * enable switch and background scan + */ + int16 rssi_margin; /* Margin to avoid jitter for choosing a + * PFN based on RSSI sort criteria + */ + uint8 bestn; /* number of best networks in each scan */ + uint8 mscan; /* number of scans recorded */ + uint8 repeat; /* Minimum number of scan intervals + *before scan frequency changes in adaptive scan + */ + uint8 exp; /* Exponent of 2 for maximum scan interval */ + int32 slow_freq; /* slow scan period */ +} wl_pfn_param_t; + +typedef struct wl_pfn_bssid { + struct ether_addr macaddr; + /* Bit4: suppress_lost, Bit3: suppress_found */ + uint16 flags; +} wl_pfn_bssid_t; + +typedef struct wl_pfn_significant_bssid { + struct ether_addr macaddr; + int8 rssi_low_threshold; + int8 rssi_high_threshold; +} wl_pfn_significant_bssid_t; + +#define WL_PFN_SUPPRESSFOUND_MASK 0x08 +#define WL_PFN_SUPPRESSLOST_MASK 0x10 +#define WL_PFN_RSSI_MASK 0xff00 +#define WL_PFN_RSSI_SHIFT 8 + +typedef struct wl_pfn_cfg { + uint32 reporttype; + int32 channel_num; + uint16 channel_list[WL_NUMCHANNELS]; + uint32 flags; +} wl_pfn_cfg_t; + +#define CH_BUCKET_REPORT_REGULAR 0 +#define CH_BUCKET_REPORT_FULL_RESULT 2 +#define CH_BUCKET_GSCAN 4 + +typedef struct wl_pfn_gscan_ch_bucket_cfg { + uint8 bucket_end_index; + uint8 bucket_freq_multiple; + uint8 flag; + uint8 reserved; + uint16 repeat; + uint16 max_freq_multiple; +} wl_pfn_gscan_ch_bucket_cfg_t; + +#define GSCAN_SEND_ALL_RESULTS_MASK (1 << 0) +#define GSCAN_CFG_FLAGS_ONLY_MASK (1 << 7) +#define WL_GSCAN_CFG_VERSION 2 +typedef struct wl_pfn_gscan_cfg { + uint16 version; + /* BIT0 1 = send probes/beacons to HOST + * BIT1 Reserved + * BIT2 Reserved + * Add any future flags here + * BIT7 1 = no other useful cfg sent + */ + uint8 flags; + /* Buffer filled threshold in % to generate an event */ + uint8 buffer_threshold; + /* No. of BSSIDs with "change" to generate an evt + * change - crosses rssi threshold/lost + */ + uint8 swc_nbssid_threshold; + /* Max=8 (for now) Size of rssi cache buffer */ + uint8 swc_rssi_window_size; + uint8 count_of_channel_buckets; + uint8 retry_threshold; + uint16 lost_ap_window; + wl_pfn_gscan_ch_bucket_cfg_t channel_bucket[1]; +} wl_pfn_gscan_cfg_t; + +#define WL_PFN_REPORT_ALLNET 0 +#define WL_PFN_REPORT_SSIDNET 1 +#define WL_PFN_REPORT_BSSIDNET 2 + +#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ +#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /* Remaining reserved for future use */ +#define WL_PFN_SSID_A_BAND_TRIG 0x20 +#define WL_PFN_SSID_BG_BAND_TRIG 0x40 +typedef struct wl_pfn { + wlc_ssid_t ssid; /* ssid name and its length */ + int32 flags; /* bit2: hidden */ + int32 infra; /* BSS Vs IBSS */ + int32 auth; /* Open Vs Closed */ + int32 wpa_auth; /* WPA type */ + int32 wsec; /* wsec value */ +} wl_pfn_t; + +typedef struct wl_pfn_list { + uint32 version; + uint32 enabled; + uint32 count; + wl_pfn_t pfn[1]; +} wl_pfn_list_t; + +#define PFN_SSID_EXT_VERSION 2 + +typedef struct wl_pfn_ext { + uint8 flags; + int8 rssi_thresh; /* RSSI threshold, track only if RSSI > threshold */ + uint16 wpa_auth; /* Match the wpa auth type defined in wlioctl_defs.h */ + uint8 ssid[DOT11_MAX_SSID_LEN]; + uint8 ssid_len; + uint8 pad; +} wl_pfn_ext_t; + +typedef struct wl_pfn_ext_list { + uint16 version; + uint16 count; + wl_pfn_ext_t pfn_ext[1]; +} wl_pfn_ext_list_t; + +#define WL_PFN_SSID_EXT_FOUND 0x1 +#define WL_PFN_SSID_EXT_LOST 0x2 +typedef struct wl_pfn_result_ssid { + uint8 flags; + int8 rssi; + /* channel number */ + uint16 channel; + /* Assume idx in order of cfg */ + uint16 index; + struct ether_addr bssid; +} wl_pfn_result_ssid_crc32_t; + +typedef struct wl_pfn_ssid_ext_result { + uint16 version; + uint16 count; + wl_pfn_result_ssid_crc32_t net[1]; +} wl_pfn_ssid_ext_result_t; + +#define PFN_EXT_AUTH_CODE_OPEN 1 /* open */ +#define PFN_EXT_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ +#define PFN_EXT_AUTH_CODE_EAPOL 4 /* any EAPOL */ + +#define WL_PFN_MAC_OUI_ONLY_MASK 1 +#define WL_PFN_SET_MAC_UNASSOC_MASK 2 +/* To configure pfn_macaddr */ +typedef struct wl_pfn_macaddr_cfg { + uint8 version; + uint8 flags; + struct ether_addr macaddr; +} wl_pfn_macaddr_cfg_t; +#define WL_PFN_MACADDR_CFG_VER 1 + +typedef BWL_PRE_PACKED_STRUCT struct pfn_olmsg_params_t { + wlc_ssid_t ssid; + uint32 cipher_type; + uint32 auth_type; + uint8 channels[4]; +} BWL_POST_PACKED_STRUCT pfn_olmsg_params; + +#define WL_PFN_HIDDEN_BIT 2 +#define WL_PFN_HIDDEN_MASK 0x4 + +#ifndef BESTN_MAX +#define BESTN_MAX 3 +#endif + +#ifndef MSCAN_MAX +#define MSCAN_MAX 90 +#endif + + +/* Service discovery */ +typedef struct { + uint8 transaction_id; /* Transaction id */ + uint8 protocol; /* Service protocol type */ + uint16 query_len; /* Length of query */ + uint16 response_len; /* Length of response */ + uint8 qrbuf[1]; +} wl_p2po_qr_t; + +typedef struct { + uint16 period; /* extended listen period */ + uint16 interval; /* extended listen interval */ +} wl_p2po_listen_t; + +/* GAS state machine tunable parameters. Structure field values of 0 means use the default. */ +typedef struct wl_gas_config { + uint16 max_retransmit; /* Max # of firmware/driver retransmits on no Ack + * from peer (on top of the ucode retries). + */ + uint16 response_timeout; /* Max time to wait for a GAS-level response + * after sending a packet. + */ + uint16 max_comeback_delay; /* Max GAS response comeback delay. + * Exceeding this fails the GAS exchange. + */ + uint16 max_retries; /* Max # of GAS state machine retries on failure + * of a GAS frame exchange. + */ +} wl_gas_config_t; + +/* P2P Find Offload parameters */ +typedef BWL_PRE_PACKED_STRUCT struct wl_p2po_find_config { + uint16 version; /* Version of this struct */ + uint16 length; /* sizeof(wl_p2po_find_config_t) */ + int32 search_home_time; /* P2P search state home time when concurrent + * connection exists. -1 for default. + */ + uint8 num_social_channels; + /* Number of social channels up to WL_P2P_SOCIAL_CHANNELS_MAX. + * 0 means use default social channels. + */ + uint8 flags; + uint16 social_channels[1]; /* Variable length array of social channels */ +} BWL_POST_PACKED_STRUCT wl_p2po_find_config_t; +#define WL_P2PO_FIND_CONFIG_VERSION 2 /* value for version field */ + +/* wl_p2po_find_config_t flags */ +#define P2PO_FIND_FLAG_SCAN_ALL_APS 0x01 /* Whether to scan for all APs in the p2po_find + * periodic scans of all channels. + * 0 means scan for only P2P devices. + * 1 means scan for P2P devices plus non-P2P APs. + */ + + +/* For adding a WFDS service to seek */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 seek_hdl; /* unique id chosen by host */ + uint8 addr[6]; /* Seek service from a specific device with this + * MAC address, all 1's for any device. + */ + uint8 service_hash[P2P_WFDS_HASH_LEN]; + uint8 service_name_len; + uint8 service_name[MAX_WFDS_SEEK_SVC_NAME_LEN]; + /* Service name to seek, not null terminated */ + uint8 service_info_req_len; + uint8 service_info_req[1]; /* Service info request, not null terminated. + * Variable length specified by service_info_req_len. + * Maximum length is MAX_WFDS_SEEK_SVC_INFO_LEN. + */ +} BWL_POST_PACKED_STRUCT wl_p2po_wfds_seek_add_t; + +/* For deleting a WFDS service to seek */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 seek_hdl; /* delete service specified by id */ +} BWL_POST_PACKED_STRUCT wl_p2po_wfds_seek_del_t; + + +/* For adding a WFDS service to advertise */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 advertise_hdl; /* unique id chosen by host */ + uint8 service_hash[P2P_WFDS_HASH_LEN]; + uint32 advertisement_id; + uint16 service_config_method; + uint8 service_name_len; + uint8 service_name[MAX_WFDS_SVC_NAME_LEN]; + /* Service name , not null terminated */ + uint8 service_status; + uint16 service_info_len; + uint8 service_info[1]; /* Service info, not null terminated. + * Variable length specified by service_info_len. + * Maximum length is MAX_WFDS_ADV_SVC_INFO_LEN. + */ +} BWL_POST_PACKED_STRUCT wl_p2po_wfds_advertise_add_t; + +/* For deleting a WFDS service to advertise */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 advertise_hdl; /* delete service specified by hdl */ +} BWL_POST_PACKED_STRUCT wl_p2po_wfds_advertise_del_t; + +/* P2P Offload discovery mode for the p2po_state iovar */ +typedef enum { + WL_P2PO_DISC_STOP, + WL_P2PO_DISC_LISTEN, + WL_P2PO_DISC_DISCOVERY +} disc_mode_t; + +/* ANQP offload */ + +#define ANQPO_MAX_QUERY_SIZE 256 +typedef struct { + uint16 max_retransmit; /* ~0 use default, max retransmit on no ACK from peer */ + uint16 response_timeout; /* ~0 use default, msec to wait for resp after tx packet */ + uint16 max_comeback_delay; /* ~0 use default, max comeback delay in resp else fail */ + uint16 max_retries; /* ~0 use default, max retries on failure */ + uint16 query_len; /* length of ANQP query */ + uint8 query_data[1]; /* ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */ +} wl_anqpo_set_t; + +typedef struct { + uint16 channel; /* channel of the peer */ + struct ether_addr addr; /* addr of the peer */ +} wl_anqpo_peer_t; + +#define ANQPO_MAX_PEER_LIST 64 +typedef struct { + uint16 count; /* number of peers in list */ + wl_anqpo_peer_t peer[1]; /* max ANQPO_MAX_PEER_LIST */ +} wl_anqpo_peer_list_t; + +#define ANQPO_MAX_IGNORE_SSID 64 +typedef struct { + bool is_clear; /* set to clear list (not used on GET) */ + uint16 count; /* number of SSID in list */ + wlc_ssid_t ssid[1]; /* max ANQPO_MAX_IGNORE_SSID */ +} wl_anqpo_ignore_ssid_list_t; + +#define ANQPO_MAX_IGNORE_BSSID 64 +typedef struct { + bool is_clear; /* set to clear list (not used on GET) */ + uint16 count; /* number of addr in list */ + struct ether_addr bssid[1]; /* max ANQPO_MAX_IGNORE_BSSID */ +} wl_anqpo_ignore_bssid_list_t; + + +struct toe_ol_stats_t { + /* Num of tx packets that don't need to be checksummed */ + uint32 tx_summed; + + /* Num of tx packets where checksum is filled by offload engine */ + uint32 tx_iph_fill; + uint32 tx_tcp_fill; + uint32 tx_udp_fill; + uint32 tx_icmp_fill; + + /* Num of rx packets where toe finds out if checksum is good or bad */ + uint32 rx_iph_good; + uint32 rx_iph_bad; + uint32 rx_tcp_good; + uint32 rx_tcp_bad; + uint32 rx_udp_good; + uint32 rx_udp_bad; + uint32 rx_icmp_good; + uint32 rx_icmp_bad; + + /* Num of tx packets in which csum error is injected */ + uint32 tx_tcp_errinj; + uint32 tx_udp_errinj; + uint32 tx_icmp_errinj; + + /* Num of rx packets in which csum error is injected */ + uint32 rx_tcp_errinj; + uint32 rx_udp_errinj; + uint32 rx_icmp_errinj; +}; + +/* Arp offload statistic counts */ +struct arp_ol_stats_t { + uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ + uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ + + uint32 arp_table_entries; /* ARP table entries */ + uint32 arp_table_overflow; /* ARP table additions skipped due to overflow */ + + uint32 host_request; /* ARP requests from host */ + uint32 host_reply; /* ARP replies from host */ + uint32 host_service; /* ARP requests from host serviced by ARP Agent */ + + uint32 peer_request; /* ARP requests received from network */ + uint32 peer_request_drop; /* ARP requests from network that were dropped */ + uint32 peer_reply; /* ARP replies received from network */ + uint32 peer_reply_drop; /* ARP replies from network that were dropped */ + uint32 peer_service; /* ARP request from host serviced by ARP Agent */ +}; + +/* NS offload statistic counts */ +struct nd_ol_stats_t { + uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ + uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ + uint32 peer_request; /* NS requests received from network */ + uint32 peer_request_drop; /* NS requests from network that were dropped */ + uint32 peer_reply_drop; /* NA replies from network that were dropped */ + uint32 peer_service; /* NS request from host serviced by firmware */ +}; + +/* + * Keep-alive packet offloading. + */ + +/* NAT keep-alive packets format: specifies the re-transmission period, the packet + * length, and packet contents. + */ +typedef struct wl_keep_alive_pkt { + uint32 period_msec; /* Retransmission period (0 to disable packet re-transmits) */ + uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */ + uint8 data[1]; /* Variable length packet to transmit. Contents should include + * entire ethernet packet (enet header, IP header, UDP header, + * and UDP payload) in network byte order. + */ +} wl_keep_alive_pkt_t; + +#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) + + +/* + * Dongle pattern matching filter. + */ + +/* Packet filter operation mode */ +/* True: 1; False: 0 */ +#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 +/* Enable and disable pkt_filter as a whole */ +#define PKT_FILTER_MODE_DISABLE 2 +/* Cache first matched rx pkt(be queried by host later) */ +#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 +/* If pkt_filter is enabled and no filter is set, don't forward anything */ +#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 + +#define MAX_WAKE_PACKET_CACHE_BYTES 128 /* Maximum cached wake packet */ + +#define MAX_WAKE_PACKET_BYTES (DOT11_A3_HDR_LEN + \ + DOT11_QOS_LEN + \ + sizeof(struct dot11_llc_snap_header) + \ + ETHER_MAX_DATA) + +typedef struct pm_wake_packet { + uint32 status; /* Is the wake reason a packet (if all the other field's valid) */ + uint32 pattern_id; /* Pattern ID that matched */ + uint32 original_packet_size; + uint32 saved_packet_size; + uchar packet[MAX_WAKE_PACKET_CACHE_BYTES]; +} pm_wake_packet_t; + +/* Packet filter types. Currently, only pattern matching is supported. */ +typedef enum wl_pkt_filter_type { + WL_PKT_FILTER_TYPE_PATTERN_MATCH=0, /* Pattern matching filter */ + WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH=1, /* Magic packet match */ + WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH=2, /* A pattern list (match all to match filter) */ + WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH=3, /* SECURE WOWL magic / net pattern match */ +} wl_pkt_filter_type_t; + +#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t + +/* String mapping for types that may be used by applications or debug */ +#define WL_PKT_FILTER_TYPE_NAMES \ + { "PATTERN", WL_PKT_FILTER_TYPE_PATTERN_MATCH }, \ + { "MAGIC", WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH }, \ + { "PATLIST", WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH } + +/* Secured WOWL packet was encrypted, need decrypted before check filter match */ +typedef struct wl_pkt_decrypter { + uint8* (*dec_cb)(void* dec_ctx, const void *sdu, int sending); + void* dec_ctx; +} wl_pkt_decrypter_t; + +/* 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. + */ +typedef struct wl_pkt_filter_pattern { + union { + uint32 offset; /* Offset within received packet to start pattern matching. + * Offset '0' is the first byte of the ethernet header. + */ + wl_pkt_decrypter_t* decrypt_ctx; /* Decrypt context */ + }; + uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ + uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts + * at offset 0. Pattern immediately follows mask. + */ +} wl_pkt_filter_pattern_t; + +/* A pattern list is a numerically specified list of modified pattern structures. */ +typedef struct wl_pkt_filter_pattern_listel { + uint16 rel_offs; /* Offset to begin match (relative to 'base' below) */ + uint16 base_offs; /* Base for offset (defined below) */ + uint16 size_bytes; /* Size of mask/pattern */ + uint16 match_flags; /* Addition flags controlling the match */ + uint8 mask_and_data[1]; /* Variable length mask followed by data, each size_bytes */ +} wl_pkt_filter_pattern_listel_t; + +typedef struct wl_pkt_filter_pattern_list { + uint8 list_cnt; /* Number of elements in the list */ + uint8 PAD1[1]; /* Reserved (possible version: reserved) */ + uint16 totsize; /* Total size of this pattern list (includes this struct) */ + wl_pkt_filter_pattern_listel_t patterns[1]; /* Variable number of list elements */ +} wl_pkt_filter_pattern_list_t; + +/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ +typedef struct wl_pkt_filter { + uint32 id; /* Unique filter id, specified by app. */ + uint32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ + uint32 negate_match; /* Negate the result of filter matches */ + union { /* Filter definitions */ + wl_pkt_filter_pattern_t pattern; /* Pattern matching filter */ + wl_pkt_filter_pattern_list_t patlist; /* List of patterns to match */ + } u; +} wl_pkt_filter_t; + +/* IOVAR "tcp_keep_set" parameter. Used to install tcp keep_alive stuff. */ +typedef struct wl_tcp_keep_set { + uint32 val1; + uint32 val2; +} wl_tcp_keep_set_t; + +#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) +#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) +#define WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_list_t, patterns) +#define WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN \ + OFFSETOF(wl_pkt_filter_pattern_listel_t, mask_and_data) + +/* IOVAR "pkt_filter_enable" parameter. */ +typedef struct wl_pkt_filter_enable { + uint32 id; /* Unique filter id */ + uint32 enable; /* Enable/disable bool */ +} wl_pkt_filter_enable_t; + +/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ +typedef struct wl_pkt_filter_list { + uint32 num; /* Number of installed packet filters */ + wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */ +} wl_pkt_filter_list_t; + +#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) + +/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ +typedef struct wl_pkt_filter_stats { + uint32 num_pkts_matched; /* # filter matches for specified filter id */ + uint32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */ + uint32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ +} wl_pkt_filter_stats_t; + +/* IOVAR "pkt_filter_ports" parameter. Configure TCP/UDP port filters. */ +typedef struct wl_pkt_filter_ports { + uint8 version; /* Be proper */ + uint8 reserved; /* Be really proper */ + uint16 count; /* Number of ports following */ + /* End of fixed data */ + uint16 ports[1]; /* Placeholder for ports[] */ +} wl_pkt_filter_ports_t; + +#define WL_PKT_FILTER_PORTS_FIXED_LEN OFFSETOF(wl_pkt_filter_ports_t, ports) + +#define WL_PKT_FILTER_PORTS_VERSION 0 +#define WL_PKT_FILTER_PORTS_MAX 128 + +#define RSN_KCK_LENGTH 16 +#define RSN_KEK_LENGTH 16 +#define RSN_REPLAY_LEN 8 +typedef struct _gtkrefresh { + uchar KCK[RSN_KCK_LENGTH]; + uchar KEK[RSN_KEK_LENGTH]; + uchar ReplayCounter[RSN_REPLAY_LEN]; +} gtk_keyinfo_t, *pgtk_keyinfo_t; + +/* Sequential Commands ioctl */ +typedef struct wl_seq_cmd_ioctl { + uint32 cmd; /* common ioctl definition */ + uint32 len; /* length of user buffer */ +} wl_seq_cmd_ioctl_t; + +#define WL_SEQ_CMD_ALIGN_BYTES 4 + +/* These are the set of get IOCTLs that should be allowed when using + * IOCTL sequence commands. These are issued implicitly by wl.exe each time + * it is invoked. We never want to buffer these, or else wl.exe will stop working. + */ +#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ + (((cmd) == WLC_GET_MAGIC) || \ + ((cmd) == WLC_GET_VERSION) || \ + ((cmd) == WLC_GET_AP) || \ + ((cmd) == WLC_GET_INSTANCE)) + +typedef struct wl_pkteng { + uint32 flags; + uint32 delay; /* Inter-packet delay */ + uint32 nframes; /* Number of frames */ + uint32 length; /* Packet length */ + uint8 seqno; /* Enable/disable sequence no. */ + struct ether_addr dest; /* Destination address */ + struct ether_addr src; /* Source address */ +} wl_pkteng_t; + +typedef struct wl_pkteng_stats { + uint32 lostfrmcnt; /* RX PER test: no of frames lost (skip seqno) */ + int32 rssi; /* RSSI */ + int32 snr; /* signal to noise ratio */ + uint16 rxpktcnt[NUM_80211_RATES+1]; + uint8 rssi_qdb; /* qdB portion of the computed rssi */ +} wl_pkteng_stats_t; + +typedef struct wl_txcal_params { + wl_pkteng_t pkteng; + uint8 gidx_start; + int8 gidx_step; + uint8 gidx_stop; +} wl_txcal_params_t; + + +typedef enum { + wowl_pattern_type_bitmap = 0, + wowl_pattern_type_arp, + wowl_pattern_type_na +} wowl_pattern_type_t; + +typedef struct wl_wowl_pattern { + uint32 masksize; /* Size of the mask in #of bytes */ + uint32 offset; /* Pattern byte offset in packet */ + uint32 patternoffset; /* Offset of start of pattern in the structure */ + uint32 patternsize; /* Size of the pattern itself in #of bytes */ + uint32 id; /* id */ + uint32 reasonsize; /* Size of the wakeup reason code */ + wowl_pattern_type_t type; /* Type of pattern */ + /* Mask follows the structure above */ + /* Pattern follows the mask is at 'patternoffset' from the start */ +} wl_wowl_pattern_t; + +typedef struct wl_wowl_pattern_list { + uint count; + wl_wowl_pattern_t pattern[1]; +} wl_wowl_pattern_list_t; + +typedef struct wl_wowl_wakeind { + uint8 pci_wakeind; /* Whether PCI PMECSR PMEStatus bit was set */ + uint32 ucode_wakeind; /* What wakeup-event indication was set by ucode */ +} wl_wowl_wakeind_t; + +typedef struct { + uint32 pktlen; /* size of packet */ + void *sdu; +} tcp_keepalive_wake_pkt_infop_t; + +/* per AC rate control related data structure */ +typedef struct wl_txrate_class { + uint8 init_rate; + uint8 min_rate; + uint8 max_rate; +} wl_txrate_class_t; + +/* structure for Overlap BSS scan arguments */ +typedef struct wl_obss_scan_arg { + int16 passive_dwell; + int16 active_dwell; + int16 bss_widthscan_interval; + int16 passive_total; + int16 active_total; + int16 chanwidth_transition_delay; + int16 activity_threshold; +} wl_obss_scan_arg_t; + +#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) + +/* RSSI event notification configuration. */ +typedef struct wl_rssi_event { + uint32 rate_limit_msec; /* # of events posted to application will be limited to + * one per specified period (0 to disable rate limit). + */ + uint8 num_rssi_levels; /* Number of entries in rssi_levels[] below */ + int8 rssi_levels[MAX_RSSI_LEVELS]; /* Variable number of RSSI levels. An event + * will be posted each time the RSSI of received + * beacons/packets crosses a level. + */ +} wl_rssi_event_t; + +#define RSSI_MONITOR_VERSION 1 +#define RSSI_MONITOR_STOP (1 << 0) +typedef struct wl_rssi_monitor_cfg { + uint8 version; + uint8 flags; + int8 max_rssi; + int8 min_rssi; +} wl_rssi_monitor_cfg_t; + +typedef struct wl_rssi_monitor_evt { + uint8 version; + int8 cur_rssi; + uint16 pad; +} wl_rssi_monitor_evt_t; + +typedef struct wl_action_obss_coex_req { + uint8 info; + uint8 num; + uint8 ch_list[1]; +} wl_action_obss_coex_req_t; + + +/* IOVar parameter block for small MAC address array with type indicator */ +#define WL_IOV_MAC_PARAM_LEN 4 + +#define WL_IOV_PKTQ_LOG_PRECS 16 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 num_addrs; + char addr_type[WL_IOV_MAC_PARAM_LEN]; + struct ether_addr ea[WL_IOV_MAC_PARAM_LEN]; +} BWL_POST_PACKED_STRUCT wl_iov_mac_params_t; + +/* This is extra info that follows wl_iov_mac_params_t */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 addr_info[WL_IOV_MAC_PARAM_LEN]; +} BWL_POST_PACKED_STRUCT wl_iov_mac_extra_params_t; + +/* Combined structure */ +typedef struct { + wl_iov_mac_params_t params; + wl_iov_mac_extra_params_t extra_params; +} wl_iov_mac_full_params_t; + +/* Parameter block for PKTQ_LOG statistics */ +#define PKTQ_LOG_COUNTERS_V4 \ + /* packets requested to be stored */ \ + uint32 requested; \ + /* packets stored */ \ + uint32 stored; \ + /* packets saved, because a lowest priority queue has given away one packet */ \ + uint32 saved; \ + /* packets saved, because an older packet from the same queue has been dropped */ \ + uint32 selfsaved; \ + /* packets dropped, because pktq is full with higher precedence packets */ \ + uint32 full_dropped; \ + /* packets dropped because pktq per that precedence is full */ \ + uint32 dropped; \ + /* packets dropped, in order to save one from a queue of a highest priority */ \ + uint32 sacrificed; \ + /* packets droped because of hardware/transmission error */ \ + uint32 busy; \ + /* packets re-sent because they were not received */ \ + uint32 retry; \ + /* packets retried again (ps pretend) prior to moving power save mode */ \ + uint32 ps_retry; \ + /* suppressed packet count */ \ + uint32 suppress; \ + /* packets finally dropped after retry limit */ \ + uint32 retry_drop; \ + /* the high-water mark of the queue capacity for packets - goes to zero as queue fills */ \ + uint32 max_avail; \ + /* the high-water mark of the queue utilisation for packets - ('inverse' of max_avail) */ \ + uint32 max_used; \ + /* the maximum capacity of the queue */ \ + uint32 queue_capacity; \ + /* count of rts attempts that failed to receive cts */ \ + uint32 rtsfail; \ + /* count of packets sent (acked) successfully */ \ + uint32 acked; \ + /* running total of phy rate of packets sent successfully */ \ + uint32 txrate_succ; \ + /* running total of phy 'main' rate */ \ + uint32 txrate_main; \ + /* actual data transferred successfully */ \ + uint32 throughput; \ + /* time difference since last pktq_stats */ \ + uint32 time_delta; + +typedef struct { + PKTQ_LOG_COUNTERS_V4 +} pktq_log_counters_v04_t; + +/* v5 is the same as V4 with extra parameter */ +typedef struct { + PKTQ_LOG_COUNTERS_V4 + /* cumulative time to transmit */ + uint32 airtime; +} pktq_log_counters_v05_t; + +typedef struct { + uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; + pktq_log_counters_v04_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; + uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; + uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; + char headings[1]; +} pktq_log_format_v04_t; + +typedef struct { + uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; + pktq_log_counters_v05_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; + uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; + uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; + char headings[1]; +} pktq_log_format_v05_t; + + +typedef struct { + uint32 version; + wl_iov_mac_params_t params; + union { + pktq_log_format_v04_t v04; + pktq_log_format_v05_t v05; + } pktq_log; +} wl_iov_pktq_log_t; + +/* PKTQ_LOG_AUTO, PKTQ_LOG_DEF_PREC flags introduced in v05, they are ignored by v04 */ +#define PKTQ_LOG_AUTO (1 << 31) +#define PKTQ_LOG_DEF_PREC (1 << 30) + +/* + * SCB_BS_DATA iovar definitions start. + */ +#define SCB_BS_DATA_STRUCT_VERSION 1 + +/* The actual counters maintained for each station */ +typedef BWL_PRE_PACKED_STRUCT struct { + /* The following counters are a subset of what pktq_stats provides per precedence. */ + uint32 retry; /* packets re-sent because they were not received */ + uint32 retry_drop; /* packets finally dropped after retry limit */ + uint32 rtsfail; /* count of rts attempts that failed to receive cts */ + uint32 acked; /* count of packets sent (acked) successfully */ + uint32 txrate_succ; /* running total of phy rate of packets sent successfully */ + uint32 txrate_main; /* running total of phy 'main' rate */ + uint32 throughput; /* actual data transferred successfully */ + uint32 time_delta; /* time difference since last pktq_stats */ + uint32 airtime; /* cumulative total medium access delay in useconds */ +} BWL_POST_PACKED_STRUCT iov_bs_data_counters_t; + +/* The structure for individual station information. */ +typedef BWL_PRE_PACKED_STRUCT struct { + struct ether_addr station_address; /* The station MAC address */ + uint16 station_flags; /* Bit mask of flags, for future use. */ + iov_bs_data_counters_t station_counters; /* The actual counter values */ +} BWL_POST_PACKED_STRUCT iov_bs_data_record_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 structure_version; /* Structure version number (for wl/wlu matching) */ + uint16 structure_count; /* Number of iov_bs_data_record_t records following */ + iov_bs_data_record_t structure_record[1]; /* 0 - structure_count records */ +} BWL_POST_PACKED_STRUCT iov_bs_data_struct_t; + +/* Bitmask of options that can be passed in to the iovar. */ +enum { + SCB_BS_DATA_FLAG_NO_RESET = (1<<0) /* Do not clear the counters after reading */ +}; +/* + * SCB_BS_DATA iovar definitions end. + */ + +typedef struct wlc_extlog_cfg { + int max_number; + uint16 module; /* bitmap */ + uint8 level; + uint8 flag; + uint16 version; +} wlc_extlog_cfg_t; + +typedef struct log_record { + uint32 time; + uint16 module; + uint16 id; + uint8 level; + uint8 sub_unit; + uint8 seq_num; + int32 arg; + char str[MAX_ARGSTR_LEN]; +} log_record_t; + +typedef struct wlc_extlog_req { + uint32 from_last; + uint32 num; +} wlc_extlog_req_t; + +typedef struct wlc_extlog_results { + uint16 version; + uint16 record_len; + uint32 num; + log_record_t logs[1]; +} wlc_extlog_results_t; + +typedef struct log_idstr { + uint16 id; + uint16 flag; + uint8 arg_type; + const char *fmt_str; +} log_idstr_t; + +#define FMTSTRF_USER 1 + +/* flat ID definitions + * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will + * affect backward compatibility with pre-existing apps + */ +typedef enum { + FMTSTR_DRIVER_UP_ID = 0, + FMTSTR_DRIVER_DOWN_ID = 1, + FMTSTR_SUSPEND_MAC_FAIL_ID = 2, + FMTSTR_NO_PROGRESS_ID = 3, + FMTSTR_RFDISABLE_ID = 4, + FMTSTR_REG_PRINT_ID = 5, + FMTSTR_EXPTIME_ID = 6, + FMTSTR_JOIN_START_ID = 7, + FMTSTR_JOIN_COMPLETE_ID = 8, + FMTSTR_NO_NETWORKS_ID = 9, + FMTSTR_SECURITY_MISMATCH_ID = 10, + FMTSTR_RATE_MISMATCH_ID = 11, + FMTSTR_AP_PRUNED_ID = 12, + FMTSTR_KEY_INSERTED_ID = 13, + FMTSTR_DEAUTH_ID = 14, + FMTSTR_DISASSOC_ID = 15, + FMTSTR_LINK_UP_ID = 16, + FMTSTR_LINK_DOWN_ID = 17, + FMTSTR_RADIO_HW_OFF_ID = 18, + FMTSTR_RADIO_HW_ON_ID = 19, + FMTSTR_EVENT_DESC_ID = 20, + FMTSTR_PNP_SET_POWER_ID = 21, + FMTSTR_RADIO_SW_OFF_ID = 22, + FMTSTR_RADIO_SW_ON_ID = 23, + FMTSTR_PWD_MISMATCH_ID = 24, + FMTSTR_FATAL_ERROR_ID = 25, + FMTSTR_AUTH_FAIL_ID = 26, + FMTSTR_ASSOC_FAIL_ID = 27, + FMTSTR_IBSS_FAIL_ID = 28, + FMTSTR_EXTAP_FAIL_ID = 29, + FMTSTR_MAX_ID +} log_fmtstr_id_t; + +#ifdef DONGLEOVERLAYS +typedef struct { + uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */ + uint32 offset; /* offset into overlay region to write code */ + uint32 len; /* overlay code len */ + /* overlay code follows this struct */ +} wl_ioctl_overlay_t; +#endif /* DONGLEOVERLAYS */ + +/* 11k Neighbor Report element */ +typedef struct nbr_element { + uint8 id; + uint8 len; + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; + uint8 channel; + uint8 phytype; + uint8 pad; +} nbr_element_t; + + +typedef enum event_msgs_ext_command { + EVENTMSGS_NONE = 0, + EVENTMSGS_SET_BIT = 1, + EVENTMSGS_RESET_BIT = 2, + EVENTMSGS_SET_MASK = 3 +} event_msgs_ext_command_t; + +#define EVENTMSGS_VER 1 +#define EVENTMSGS_EXT_STRUCT_SIZE OFFSETOF(eventmsgs_ext_t, mask[0]) + +/* len- for SET it would be mask size from the application to the firmware */ +/* for GET it would be actual firmware mask size */ +/* maxgetsize - is only used for GET. indicate max mask size that the */ +/* application can read from the firmware */ +typedef struct eventmsgs_ext +{ + uint8 ver; + uint8 command; + uint8 len; + uint8 maxgetsize; + uint8 mask[1]; +} eventmsgs_ext_t; + +typedef BWL_PRE_PACKED_STRUCT struct pcie_bus_tput_params { + /* no of host dma descriptors programmed by the firmware before a commit */ + uint16 max_dma_descriptors; + + uint16 host_buf_len; /* length of host buffer */ + dmaaddr_t host_buf_addr; /* physical address for bus_throughput_buf */ +} BWL_POST_PACKED_STRUCT pcie_bus_tput_params_t; +typedef BWL_PRE_PACKED_STRUCT struct pcie_bus_tput_stats { + uint16 time_taken; /* no of secs the test is run */ + uint16 nbytes_per_descriptor; /* no of bytes of data dma ed per descriptor */ + + /* no of desciptors fo which dma is sucessfully completed within the test time */ + uint32 count; +} BWL_POST_PACKED_STRUCT pcie_bus_tput_stats_t; + +#define MAX_ROAMOFFL_BSSID_NUM 100 + +typedef BWL_PRE_PACKED_STRUCT struct roamoffl_bssid_list { + int cnt; + struct ether_addr bssid[1]; +} BWL_POST_PACKED_STRUCT roamoffl_bssid_list_t; + +/* no default structure packing */ +#include + +typedef struct keepalives_max_idle { + uint16 keepalive_count; /* nmbr of keepalives per bss_max_idle period */ + uint8 mkeepalive_index; /* mkeepalive_index for keepalive frame to be used */ + uint8 PAD; /* to align next field */ + uint16 max_interval; /* seconds */ +} keepalives_max_idle_t; + +#define PM_IGNORE_BCMC_PROXY_ARP (1 << 0) +#define PM_IGNORE_BCMC_ALL_DMS_ACCEPTED (1 << 1) + +/* require strict packing */ +#include + +/* ##### Power Stats section ##### */ + +#define WL_PWRSTATS_VERSION 2 + +/* Input structure for pwrstats IOVAR */ +typedef BWL_PRE_PACKED_STRUCT struct wl_pwrstats_query { + uint16 length; /* Number of entries in type array. */ + uint16 type[1]; /* Types (tags) to retrieve. + * Length 0 (no types) means get all. + */ +} BWL_POST_PACKED_STRUCT wl_pwrstats_query_t; + +/* This structure is for version 2; version 1 will be deprecated in by FW */ +typedef BWL_PRE_PACKED_STRUCT struct wl_pwrstats { + uint16 version; /* Version = 2 is TLV format */ + uint16 length; /* Length of entire structure */ + uint8 data[1]; /* TLV data, a series of structures, + * each starting with type and length. + * + * Padded as necessary so each section + * starts on a 4-byte boundary. + * + * Both type and len are uint16, but the + * upper nibble of length is reserved so + * valid len values are 0-4095. + */ +} BWL_POST_PACKED_STRUCT wl_pwrstats_t; +#define WL_PWR_STATS_HDRLEN OFFSETOF(wl_pwrstats_t, data) + +/* Type values for the data section */ +#define WL_PWRSTATS_TYPE_PHY 0 /* struct wl_pwr_phy_stats */ +#define WL_PWRSTATS_TYPE_SCAN 1 /* struct wl_pwr_scan_stats */ +#define WL_PWRSTATS_TYPE_USB_HSIC 2 /* struct wl_pwr_usb_hsic_stats */ +#define WL_PWRSTATS_TYPE_PM_AWAKE 3 /* struct wl_pwr_pm_awake_stats */ +#define WL_PWRSTATS_TYPE_CONNECTION 4 /* struct wl_pwr_connect_stats; assoc and key-exch time */ +#define WL_PWRSTATS_TYPE_PCIE 6 /* struct wl_pwr_pcie_stats */ + +/* Bits for wake reasons */ +#define WLC_PMD_WAKE_SET 0x1 +#define WLC_PMD_PM_AWAKE_BCN 0x2 +#define WLC_PMD_BTA_ACTIVE 0x4 +#define WLC_PMD_SCAN_IN_PROGRESS 0x8 +#define WLC_PMD_RM_IN_PROGRESS 0x10 +#define WLC_PMD_AS_IN_PROGRESS 0x20 +#define WLC_PMD_PM_PEND 0x40 +#define WLC_PMD_PS_POLL 0x80 +#define WLC_PMD_CHK_UNALIGN_TBTT 0x100 +#define WLC_PMD_APSD_STA_UP 0x200 +#define WLC_PMD_TX_PEND_WAR 0x400 +#define WLC_PMD_GPTIMER_STAY_AWAKE 0x800 +#define WLC_PMD_PM2_RADIO_SOFF_PEND 0x2000 +#define WLC_PMD_NON_PRIM_STA_UP 0x4000 +#define WLC_PMD_AP_UP 0x8000 + +typedef BWL_PRE_PACKED_STRUCT struct wlc_pm_debug { + uint32 timestamp; /* timestamp in millisecond */ + uint32 reason; /* reason(s) for staying awake */ +} BWL_POST_PACKED_STRUCT wlc_pm_debug_t; + +/* Data sent as part of pwrstats IOVAR */ +typedef BWL_PRE_PACKED_STRUCT struct pm_awake_data { + uint32 curr_time; /* ms */ + uint32 hw_macc; /* HW maccontrol */ + uint32 sw_macc; /* SW maccontrol */ + uint32 pm_dur; /* Total sleep time in PM, usecs */ + uint32 mpc_dur; /* Total sleep time in MPC, usecs */ + + /* int32 drifts = remote - local; +ve drift => local-clk slow */ + int32 last_drift; /* Most recent TSF drift from beacon */ + int32 min_drift; /* Min TSF drift from beacon in magnitude */ + int32 max_drift; /* Max TSF drift from beacon in magnitude */ + + uint32 avg_drift; /* Avg TSF drift from beacon */ + + /* Wake history tracking */ + + /* pmstate array (type wlc_pm_debug_t) start offset */ + uint16 pm_state_offset; + /* pmstate number of array entries */ + uint16 pm_state_len; + + /* array (type uint32) start offset */ + uint16 pmd_event_wake_dur_offset; + /* pmd_event_wake_dur number of array entries */ + uint16 pmd_event_wake_dur_len; + + uint32 drift_cnt; /* Count of drift readings over which avg_drift was computed */ + uint8 pmwake_idx; /* for stepping through pm_state */ + uint8 pad[3]; + uint32 frts_time; /* Cumulative ms spent in frts since driver load */ + uint32 frts_end_cnt; /* No of times frts ended since driver load */ +} BWL_POST_PACKED_STRUCT pm_awake_data_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_pm_awake_stats { + uint16 type; /* WL_PWRSTATS_TYPE_PM_AWAKE */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + + pm_awake_data_t awake_data; +} BWL_POST_PACKED_STRUCT wl_pwr_pm_awake_stats_t; + +/* Original bus structure is for HSIC */ +typedef BWL_PRE_PACKED_STRUCT struct bus_metrics { + uint32 suspend_ct; /* suspend count */ + uint32 resume_ct; /* resume count */ + uint32 disconnect_ct; /* disconnect count */ + uint32 reconnect_ct; /* reconnect count */ + uint32 active_dur; /* msecs in bus, usecs for user */ + uint32 suspend_dur; /* msecs in bus, usecs for user */ + uint32 disconnect_dur; /* msecs in bus, usecs for user */ +} BWL_POST_PACKED_STRUCT bus_metrics_t; + +/* Bus interface info for USB/HSIC */ +typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_usb_hsic_stats { + uint16 type; /* WL_PWRSTATS_TYPE_USB_HSIC */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + + bus_metrics_t hsic; /* stats from hsic bus driver */ +} BWL_POST_PACKED_STRUCT wl_pwr_usb_hsic_stats_t; + +typedef BWL_PRE_PACKED_STRUCT struct pcie_bus_metrics { + uint32 d3_suspend_ct; /* suspend count */ + uint32 d0_resume_ct; /* resume count */ + uint32 perst_assrt_ct; /* PERST# assert count */ + uint32 perst_deassrt_ct; /* PERST# de-assert count */ + uint32 active_dur; /* msecs */ + uint32 d3_suspend_dur; /* msecs */ + uint32 perst_dur; /* msecs */ + uint32 l0_cnt; /* L0 entry count */ + uint32 l0_usecs; /* L0 duration in usecs */ + uint32 l1_cnt; /* L1 entry count */ + uint32 l1_usecs; /* L1 duration in usecs */ + uint32 l1_1_cnt; /* L1_1ss entry count */ + uint32 l1_1_usecs; /* L1_1ss duration in usecs */ + uint32 l1_2_cnt; /* L1_2ss entry count */ + uint32 l1_2_usecs; /* L1_2ss duration in usecs */ + uint32 l2_cnt; /* L2 entry count */ + uint32 l2_usecs; /* L2 duration in usecs */ +} BWL_POST_PACKED_STRUCT pcie_bus_metrics_t; + +/* Bus interface info for PCIE */ +typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_pcie_stats { + uint16 type; /* WL_PWRSTATS_TYPE_PCIE */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + pcie_bus_metrics_t pcie; /* stats from pcie bus driver */ +} BWL_POST_PACKED_STRUCT wl_pwr_pcie_stats_t; + +/* Scan information history per category */ +typedef BWL_PRE_PACKED_STRUCT struct scan_data { + uint32 count; /* Number of scans performed */ + uint32 dur; /* Total time (in us) used */ +} BWL_POST_PACKED_STRUCT scan_data_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_scan_stats { + uint16 type; /* WL_PWRSTATS_TYPE_SCAN */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + + /* Scan history */ + scan_data_t user_scans; /* User-requested scans: (i/e/p)scan */ + scan_data_t assoc_scans; /* Scans initiated by association requests */ + scan_data_t roam_scans; /* Scans initiated by the roam engine */ + scan_data_t pno_scans[8]; /* For future PNO bucketing (BSSID, SSID, etc) */ + scan_data_t other_scans; /* Scan engine usage not assigned to the above */ +} BWL_POST_PACKED_STRUCT wl_pwr_scan_stats_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_connect_stats { + uint16 type; /* WL_PWRSTATS_TYPE_SCAN */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + + /* Connection (Association + Key exchange) data */ + uint32 count; /* Number of connections performed */ + uint32 dur; /* Total time (in ms) used */ +} BWL_POST_PACKED_STRUCT wl_pwr_connect_stats_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_phy_stats { + uint16 type; /* WL_PWRSTATS_TYPE_PHY */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + uint32 tx_dur; /* TX Active duration in us */ + uint32 rx_dur; /* RX Active duration in us */ +} BWL_POST_PACKED_STRUCT wl_pwr_phy_stats_t; + + +/* ##### End of Power Stats section ##### */ + +/* IPV4 Arp offloads for ndis context */ +BWL_PRE_PACKED_STRUCT struct hostip_id { + struct ipv4_addr ipa; + uint8 id; +} BWL_POST_PACKED_STRUCT; + + +typedef BWL_PRE_PACKED_STRUCT struct wl_pfn_roam_thresh { + uint32 pfn_alert_thresh; /* time in ms */ + uint32 roam_alert_thresh; /* time in ms */ +} BWL_POST_PACKED_STRUCT wl_pfn_roam_thresh_t; + + +/* Reasons for wl_pmalert_t */ +#define PM_DUR_EXCEEDED (1<<0) +#define MPC_DUR_EXCEEDED (1<<1) +#define ROAM_ALERT_THRESH_EXCEEDED (1<<2) +#define PFN_ALERT_THRESH_EXCEEDED (1<<3) +#define CONST_AWAKE_DUR_ALERT (1<<4) +#define CONST_AWAKE_DUR_RECOVERY (1<<5) + +#define MIN_PM_ALERT_LEN 9 + +/* Data sent in EXCESS_PM_WAKE event */ +#define WL_PM_ALERT_VERSION 3 + +#define MAX_P2P_BSS_DTIM_PRD 4 + +/* This structure is for version 3; version 2 will be deprecated in by FW */ +typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert { + uint16 version; /* Version = 3 is TLV format */ + uint16 length; /* Length of entire structure */ + uint32 reasons; /* reason(s) for pm_alert */ + uint8 data[1]; /* TLV data, a series of structures, + * each starting with type and length. + * + * Padded as necessary so each section + * starts on a 4-byte boundary. + * + * Both type and len are uint16, but the + * upper nibble of length is reserved so + * valid len values are 0-4095. + */ +} BWL_POST_PACKED_STRUCT wl_pmalert_t; + +/* Type values for the data section */ +#define WL_PMALERT_FIXED 0 /* struct wl_pmalert_fixed_t, fixed fields */ +#define WL_PMALERT_PMSTATE 1 /* struct wl_pmalert_pmstate_t, variable */ +#define WL_PMALERT_EVENT_DUR 2 /* struct wl_pmalert_event_dur_t, variable */ +#define WL_PMALERT_UCODE_DBG 3 /* struct wl_pmalert_ucode_dbg_t, variable */ + +typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert_fixed { + uint16 type; /* WL_PMALERT_FIXED */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + uint32 prev_stats_time; /* msecs */ + uint32 curr_time; /* ms */ + uint32 prev_pm_dur; /* usecs */ + uint32 pm_dur; /* Total sleep time in PM, usecs */ + uint32 prev_mpc_dur; /* usecs */ + uint32 mpc_dur; /* Total sleep time in MPC, usecs */ + uint32 hw_macc; /* HW maccontrol */ + uint32 sw_macc; /* SW maccontrol */ + + /* int32 drifts = remote - local; +ve drift -> local-clk slow */ + int32 last_drift; /* Most recent TSF drift from beacon */ + int32 min_drift; /* Min TSF drift from beacon in magnitude */ + int32 max_drift; /* Max TSF drift from beacon in magnitude */ + + uint32 avg_drift; /* Avg TSF drift from beacon */ + uint32 drift_cnt; /* Count of drift readings over which avg_drift was computed */ + uint32 frts_time; /* Cumulative ms spent in frts since driver load */ + uint32 frts_end_cnt; /* No of times frts ended since driver load */ +} BWL_POST_PACKED_STRUCT wl_pmalert_fixed_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert_pmstate { + uint16 type; /* WL_PMALERT_PMSTATE */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + + uint8 pmwake_idx; /* for stepping through pm_state */ + uint8 pad[3]; + /* Array of pmstate; len of array is based on tlv len */ + wlc_pm_debug_t pmstate[1]; +} BWL_POST_PACKED_STRUCT wl_pmalert_pmstate_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert_event_dur { + uint16 type; /* WL_PMALERT_EVENT_DUR */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + + /* Array of event_dur, len of array is based on tlv len */ + uint32 event_dur[1]; +} BWL_POST_PACKED_STRUCT wl_pmalert_event_dur_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert_ucode_dbg { + uint16 type; /* WL_PMALERT_UCODE_DBG */ + uint16 len; /* Up to 4K-1, top 4 bits are reserved */ + uint32 macctrl; + uint16 m_p2p_hps; + uint32 psm_brc; + uint32 ifsstat; + uint16 m_p2p_bss_dtim_prd[MAX_P2P_BSS_DTIM_PRD]; + uint32 psmdebug[20]; + uint32 phydebug[20]; +} BWL_POST_PACKED_STRUCT wl_pmalert_ucode_dbg_t; + + +/* Structures and constants used for "vndr_ie" IOVar interface */ +#define VNDR_IE_CMD_LEN 4 /* length of the set command string: + * "add", "del" (+ NUL) + */ + +#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ + vndr_ie_t vndr_ie_data; /* vendor IE data */ +} BWL_POST_PACKED_STRUCT vndr_ie_info_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + int iecount; /* number of entries in the vndr_ie_list[] array */ + vndr_ie_info_t vndr_ie_list[1]; /* variable size list of vndr_ie_info_t structs */ +} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + char cmd[VNDR_IE_CMD_LEN]; /* vndr_ie IOVar set command : "add", "del" + NUL */ + vndr_ie_buf_t vndr_ie_buffer; /* buffer containing Vendor IE list information */ +} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; + +/* tag_ID/length/value_buffer tuple */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 id; + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT tlv_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ + tlv_t ie_data; /* IE data */ +} BWL_POST_PACKED_STRUCT ie_info_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + int iecount; /* number of entries in the ie_list[] array */ + ie_info_t ie_list[1]; /* variable size list of ie_info_t structs */ +} BWL_POST_PACKED_STRUCT ie_buf_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + char cmd[VNDR_IE_CMD_LEN]; /* ie IOVar set command : "add" + NUL */ + ie_buf_t ie_buffer; /* buffer containing IE list information */ +} BWL_POST_PACKED_STRUCT ie_setbuf_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ + uint8 id; /* IE type */ +} BWL_POST_PACKED_STRUCT ie_getbuf_t; + +/* structures used to define format of wps ie data from probe requests */ +/* passed up to applications via iovar "prbreq_wpsie" */ +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr { + struct ether_addr staAddr; + uint16 ieLen; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t; + +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { + sta_prbreq_wps_ie_hdr_t hdr; + uint8 ieData[1]; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; + +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { + uint32 totLen; + uint8 ieDataList[1]; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; + + +#ifdef WLMEDIA_TXFAILEVENT +typedef BWL_PRE_PACKED_STRUCT struct { + char dest[ETHER_ADDR_LEN]; /* destination MAC */ + uint8 prio; /* Packet Priority */ + uint8 flags; /* Flags */ + uint32 tsf_l; /* TSF timer low */ + uint32 tsf_h; /* TSF timer high */ + uint16 rates; /* Main Rates */ + uint16 txstatus; /* TX Status */ +} BWL_POST_PACKED_STRUCT txfailinfo_t; +#endif /* WLMEDIA_TXFAILEVENT */ + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint8 local_max; /* local max according to the AP */ + uint8 local_constraint; /* local constraint according to the AP */ + int8 antgain[2]; /* Ant gain for each band - from SROM */ + uint8 rf_cores; /* count of RF Cores being reported */ + uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ + uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain w/o adjustment */ + uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ + uint8 tx_power_max[4]; /* Maximum target power among all rates */ + uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ + int8 sar; /* SAR limit for display by wl executable */ + int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ + uint8 version; /* Version of the data format wlu <--> driver */ + uint8 display_core; /* Displayed curpower core */ + int8 target_offsets[4]; /* Target power offsets for current rate per core */ + uint32 last_tx_ratespec; /* Ratespec for last transmition */ + uint user_target; /* user limit */ + uint32 ppr_len; /* length of each ppr serialization buffer */ + int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; + uint8 pprdata[1]; /* ppr serialization buffer */ +} BWL_POST_PACKED_STRUCT tx_pwr_rpt_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + struct ipv4_addr ipv4_addr; + struct ether_addr nexthop; +} BWL_POST_PACKED_STRUCT ibss_route_entry_t; +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 num_entry; + ibss_route_entry_t route_entry[1]; +} BWL_POST_PACKED_STRUCT ibss_route_tbl_t; + +#define MAX_IBSS_ROUTE_TBL_ENTRY 64 + +#define TXPWR_TARGET_VERSION 0 +typedef BWL_PRE_PACKED_STRUCT struct { + int32 version; /* version number */ + chanspec_t chanspec; /* txpwr report for this channel */ + int8 txpwr[WL_STA_ANT_MAX]; /* Max tx target power, in qdb */ + uint8 rf_cores; /* count of RF Cores being reported */ +} BWL_POST_PACKED_STRUCT txpwr_target_max_t; + +#define BSS_PEER_INFO_PARAM_CUR_VER 0 +/* Input structure for IOV_BSS_PEER_INFO */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + struct ether_addr ea; /* peer MAC address */ +} BWL_POST_PACKED_STRUCT bss_peer_info_param_t; + +#define BSS_PEER_INFO_CUR_VER 0 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + struct ether_addr ea; + int32 rssi; + uint32 tx_rate; /* current tx rate */ + uint32 rx_rate; /* current rx rate */ + wl_rateset_t rateset; /* rateset in use */ + uint32 age; /* age in seconds */ +} BWL_POST_PACKED_STRUCT bss_peer_info_t; + +#define BSS_PEER_LIST_INFO_CUR_VER 0 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 bss_peer_info_len; /* length of bss_peer_info_t */ + uint32 count; /* number of peer info */ + bss_peer_info_t peer_info[1]; /* peer info */ +} BWL_POST_PACKED_STRUCT bss_peer_list_info_t; + +#define BSS_PEER_LIST_INFO_FIXED_LEN OFFSETOF(bss_peer_list_info_t, peer_info) + +#define AIBSS_BCN_FORCE_CONFIG_VER_0 0 + +/* structure used to configure AIBSS beacon force xmit */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 len; + uint32 initial_min_bcn_dur; /* dur in ms to check a bcn in bcn_flood period */ + uint32 min_bcn_dur; /* dur in ms to check a bcn after bcn_flood period */ + uint32 bcn_flood_dur; /* Initial bcn xmit period in ms */ +} BWL_POST_PACKED_STRUCT aibss_bcn_force_config_t; + +#define AIBSS_TXFAIL_CONFIG_VER_0 0 + +/* structure used to configure aibss tx fail event */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 len; + uint32 bcn_timeout; /* dur in seconds to receive 1 bcn */ + uint32 max_tx_retry; /* no of consecutive no acks to send txfail event */ +} BWL_POST_PACKED_STRUCT aibss_txfail_config_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_aibss_if { + uint16 version; + uint16 len; + uint32 flags; + struct ether_addr addr; + chanspec_t chspec; +} BWL_POST_PACKED_STRUCT wl_aibss_if_t; + +typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_entry { + struct ipv4_addr ip_addr; + struct ether_addr nexthop; +} BWL_POST_PACKED_STRUCT wlc_ipfo_route_entry_t; + +typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_tbl { + uint32 num_entry; + wlc_ipfo_route_entry_t route_entry[1]; +} BWL_POST_PACKED_STRUCT wlc_ipfo_route_tbl_t; + +#define WL_IPFO_ROUTE_TBL_FIXED_LEN 4 +#define WL_MAX_IPFO_ROUTE_TBL_ENTRY 64 + +/* no strict structure packing */ +#include + + /* Global ASSERT Logging */ +#define ASSERTLOG_CUR_VER 0x0100 +#define MAX_ASSRTSTR_LEN 64 + + typedef struct assert_record { + uint32 time; + uint8 seq_num; + char str[MAX_ASSRTSTR_LEN]; + } assert_record_t; + + typedef struct assertlog_results { + uint16 version; + uint16 record_len; + uint32 num; + assert_record_t logs[1]; + } assertlog_results_t; + +#define LOGRRC_FIX_LEN 8 +#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) + +#ifdef BCMWAPI_WAI +#define IV_LEN 16 + struct wapi_sta_msg_t + { + uint16 msg_type; + uint16 datalen; + uint8 vap_mac[6]; + uint8 reserve_data1[2]; + uint8 sta_mac[6]; + uint8 reserve_data2[2]; + uint8 gsn[IV_LEN]; + uint8 wie[256]; + }; +#endif /* BCMWAPI_WAI */ + + /* chanim acs record */ + typedef struct { + bool valid; + uint8 trigger; + chanspec_t selected_chspc; + int8 bgnoise; + uint32 glitch_cnt; + uint8 ccastats; + uint timestamp; + } chanim_acs_record_t; + + typedef struct { + chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; + uint8 count; + uint timestamp; + } wl_acs_record_t; + + typedef struct chanim_stats { + uint32 glitchcnt; /* normalized as per second count */ + uint32 badplcp; /* normalized as per second count */ + uint8 ccastats[CCASTATS_MAX]; /* normalized as 0-255 */ + int8 bgnoise; /* background noise level (in dBm) */ + chanspec_t chanspec; + uint32 timestamp; + uint32 bphy_glitchcnt; /* normalized as per second count */ + uint32 bphy_badplcp; /* normalized as per second count */ + uint8 chan_idle; /* normalized as 0~255 */ + } chanim_stats_t; + +#define WL_CHANIM_STATS_VERSION 2 + +typedef struct { + uint32 buflen; + uint32 version; + uint32 count; + chanim_stats_t stats[1]; +} wl_chanim_stats_t; + +#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats) + +/* Noise measurement metrics. */ +#define NOISE_MEASURE_KNOISE 0x1 + +/* scb probe parameter */ +typedef struct { + uint32 scb_timeout; + uint32 scb_activity_time; + uint32 scb_max_probe; +} wl_scb_probe_t; + +/* structure/defines for selective mgmt frame (smf) stats support */ + +#define SMFS_VERSION 1 +/* selected mgmt frame (smf) stats element */ +typedef struct wl_smfs_elem { + uint32 count; + uint16 code; /* SC or RC code */ +} wl_smfs_elem_t; + +typedef struct wl_smf_stats { + uint32 version; + uint16 length; /* reserved for future usage */ + uint8 type; + uint8 codetype; + uint32 ignored_cnt; + uint32 malformed_cnt; + uint32 count_total; /* count included the interested group */ + wl_smfs_elem_t elem[1]; +} wl_smf_stats_t; + +#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); + +enum { + SMFS_CODETYPE_SC, + SMFS_CODETYPE_RC +}; + +typedef enum smfs_type { + SMFS_TYPE_AUTH, + SMFS_TYPE_ASSOC, + SMFS_TYPE_REASSOC, + SMFS_TYPE_DISASSOC_TX, + SMFS_TYPE_DISASSOC_RX, + SMFS_TYPE_DEAUTH_TX, + SMFS_TYPE_DEAUTH_RX, + SMFS_TYPE_MAX +} smfs_type_t; + +#ifdef PHYMON + +#define PHYMON_VERSION 1 + +typedef struct wl_phycal_core_state { + /* Tx IQ/LO calibration coeffs */ + int16 tx_iqlocal_a; + int16 tx_iqlocal_b; + int8 tx_iqlocal_ci; + int8 tx_iqlocal_cq; + int8 tx_iqlocal_di; + int8 tx_iqlocal_dq; + int8 tx_iqlocal_ei; + int8 tx_iqlocal_eq; + int8 tx_iqlocal_fi; + int8 tx_iqlocal_fq; + + /* Rx IQ calibration coeffs */ + int16 rx_iqcal_a; + int16 rx_iqcal_b; + + uint8 tx_iqlocal_pwridx; /* Tx Power Index for Tx IQ/LO calibration */ + uint32 papd_epsilon_table[64]; /* PAPD epsilon table */ + int16 papd_epsilon_offset; /* PAPD epsilon offset */ + uint8 curr_tx_pwrindex; /* Tx power index */ + int8 idle_tssi; /* Idle TSSI */ + int8 est_tx_pwr; /* Estimated Tx Power (dB) */ + int8 est_rx_pwr; /* Estimated Rx Power (dB) from RSSI */ + uint16 rx_gaininfo; /* Rx gain applied on last Rx pkt */ + uint16 init_gaincode; /* initgain required for ACI */ + int8 estirr_tx; + int8 estirr_rx; + +} wl_phycal_core_state_t; + +typedef struct wl_phycal_state { + int version; + int8 num_phy_cores; /* number of cores */ + int8 curr_temperature; /* on-chip temperature sensor reading */ + chanspec_t chspec; /* channspec for this state */ + bool aci_state; /* ACI state: ON/OFF */ + uint16 crsminpower; /* crsminpower required for ACI */ + uint16 crsminpowerl; /* crsminpowerl required for ACI */ + uint16 crsminpoweru; /* crsminpoweru required for ACI */ + wl_phycal_core_state_t phycal_core[1]; +} wl_phycal_state_t; + +#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) +#endif /* PHYMON */ + +/* discovery state */ +typedef struct wl_p2p_disc_st { + uint8 state; /* see state */ + chanspec_t chspec; /* valid in listen state */ + uint16 dwell; /* valid in listen state, in ms */ +} wl_p2p_disc_st_t; + +/* scan request */ +typedef struct wl_p2p_scan { + uint8 type; /* 'S' for WLC_SCAN, 'E' for "escan" */ + uint8 reserved[3]; + /* scan or escan parms... */ +} wl_p2p_scan_t; + +/* i/f request */ +typedef struct wl_p2p_if { + struct ether_addr addr; + uint8 type; /* see i/f type */ + chanspec_t chspec; /* for p2p_ifadd GO */ +} wl_p2p_if_t; + +/* i/f query */ +typedef struct wl_p2p_ifq { + uint bsscfgidx; + char ifname[BCM_MSG_IFNAME_MAX]; +} wl_p2p_ifq_t; + +/* OppPS & CTWindow */ +typedef struct wl_p2p_ops { + uint8 ops; /* 0: disable 1: enable */ + uint8 ctw; /* >= 10 */ +} wl_p2p_ops_t; + +/* absence and presence request */ +typedef struct wl_p2p_sched_desc { + uint32 start; + uint32 interval; + uint32 duration; + uint32 count; /* see count */ +} wl_p2p_sched_desc_t; + +typedef struct wl_p2p_sched { + uint8 type; /* see schedule type */ + uint8 action; /* see schedule action */ + uint8 option; /* see schedule option */ + wl_p2p_sched_desc_t desc[1]; +} wl_p2p_sched_t; + +typedef struct wl_p2p_wfds_hash { + uint32 advt_id; + uint16 nw_cfg_method; + uint8 wfds_hash[6]; + uint8 name_len; + uint8 service_name[MAX_WFDS_SVC_NAME_LEN]; +} wl_p2p_wfds_hash_t; + +typedef struct wl_bcmdcs_data { + uint reason; + chanspec_t chspec; +} wl_bcmdcs_data_t; + + +/* NAT configuration */ +typedef struct { + uint32 ipaddr; /* interface ip address */ + uint32 ipaddr_mask; /* interface ip address mask */ + uint32 ipaddr_gateway; /* gateway ip address */ + uint8 mac_gateway[6]; /* gateway mac address */ + uint32 ipaddr_dns; /* DNS server ip address, valid only for public if */ + uint8 mac_dns[6]; /* DNS server mac address, valid only for public if */ + uint8 GUID[38]; /* interface GUID */ +} nat_if_info_t; + +typedef struct { + uint op; /* operation code */ + bool pub_if; /* set for public if, clear for private if */ + nat_if_info_t if_info; /* interface info */ +} nat_cfg_t; + +typedef struct { + int state; /* NAT state returned */ +} nat_state_t; + + +#define BTA_STATE_LOG_SZ 64 + +/* BTAMP Statemachine states */ +enum { + HCIReset = 1, + HCIReadLocalAMPInfo, + HCIReadLocalAMPASSOC, + HCIWriteRemoteAMPASSOC, + HCICreatePhysicalLink, + HCIAcceptPhysicalLinkRequest, + HCIDisconnectPhysicalLink, + HCICreateLogicalLink, + HCIAcceptLogicalLink, + HCIDisconnectLogicalLink, + HCILogicalLinkCancel, + HCIAmpStateChange, + HCIWriteLogicalLinkAcceptTimeout +}; + +typedef struct flush_txfifo { + uint32 txfifobmp; + uint32 hwtxfifoflush; + struct ether_addr ea; +} flush_txfifo_t; + +enum { + SPATIAL_MODE_2G_IDX = 0, + SPATIAL_MODE_5G_LOW_IDX, + SPATIAL_MODE_5G_MID_IDX, + SPATIAL_MODE_5G_HIGH_IDX, + SPATIAL_MODE_5G_UPPER_IDX, + SPATIAL_MODE_MAX_IDX +}; + +#define WLC_TXCORE_MAX 4 /* max number of txcore supports */ +#define WLC_SUBBAND_MAX 4 /* max number of sub-band supports */ +typedef struct { + uint8 band2g[WLC_TXCORE_MAX]; + uint8 band5g[WLC_SUBBAND_MAX][WLC_TXCORE_MAX]; +} sar_limit_t; + +#define WLC_TXCAL_CORE_MAX 2 /* max number of txcore supports for txcal */ +#define MAX_NUM_TXCAL_MEAS 128 + +typedef struct wl_txcal_meas { + uint8 tssi[WLC_TXCAL_CORE_MAX][MAX_NUM_TXCAL_MEAS]; + int16 pwr[WLC_TXCAL_CORE_MAX][MAX_NUM_TXCAL_MEAS]; + uint8 valid_cnt; +} wl_txcal_meas_t; + +typedef struct wl_txcal_power_tssi { + uint8 set_core; + uint8 channel; + int16 pwr_start[WLC_TXCAL_CORE_MAX]; + uint8 num_entries[WLC_TXCAL_CORE_MAX]; + uint8 tssi[WLC_TXCAL_CORE_MAX][MAX_NUM_TXCAL_MEAS]; + bool gen_tbl; +} wl_txcal_power_tssi_t; + +/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ +typedef struct wl_mempool_stats { + int num; /* Number of memory pools */ + bcm_mp_stats_t s[1]; /* Variable array of memory pool stats. */ +} wl_mempool_stats_t; + +typedef struct { + uint32 ipaddr; + uint32 ipaddr_netmask; + uint32 ipaddr_gateway; +} nwoe_ifconfig_t; + +/* Traffic management priority classes */ +typedef enum trf_mgmt_priority_class { + trf_mgmt_priority_low = 0, /* Maps to 802.1p BK */ + trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ + trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ + trf_mgmt_priority_nochange = 3, /* do not update the priority */ + trf_mgmt_priority_invalid = (trf_mgmt_priority_nochange + 1) +} trf_mgmt_priority_class_t; + +/* Traffic management configuration parameters */ +typedef struct trf_mgmt_config { + uint32 trf_mgmt_enabled; /* 0 - disabled, 1 - enabled */ + uint32 flags; /* See TRF_MGMT_FLAG_xxx defines */ + uint32 host_ip_addr; /* My IP address to determine subnet */ + uint32 host_subnet_mask; /* My subnet mask */ + uint32 downlink_bandwidth; /* In units of kbps */ + uint32 uplink_bandwidth; /* In units of kbps */ + uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed tx bandwidth */ + uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed rx bandwidth */ +} trf_mgmt_config_t; + +/* Traffic management filter */ +typedef struct trf_mgmt_filter { + struct ether_addr dst_ether_addr; /* His L2 address */ + uint32 dst_ip_addr; /* His IP address */ + uint16 dst_port; /* His L4 port */ + uint16 src_port; /* My L4 port */ + uint16 prot; /* L4 protocol (only TCP or UDP) */ + uint16 flags; /* TBD. For now, this must be zero. */ + trf_mgmt_priority_class_t priority; /* Priority for filtered packets */ + uint32 dscp; /* DSCP */ +} trf_mgmt_filter_t; + +/* Traffic management filter list (variable length) */ +typedef struct trf_mgmt_filter_list { + uint32 num_filters; + trf_mgmt_filter_t filter[1]; +} trf_mgmt_filter_list_t; + +/* Traffic management global info used for all queues */ +typedef struct trf_mgmt_global_info { + uint32 maximum_bytes_per_second; + uint32 maximum_bytes_per_sampling_period; + uint32 total_bytes_consumed_per_second; + uint32 total_bytes_consumed_per_sampling_period; + uint32 total_unused_bytes_per_sampling_period; +} trf_mgmt_global_info_t; + +/* Traffic management shaping info per priority queue */ +typedef struct trf_mgmt_shaping_info { + uint32 gauranteed_bandwidth_percentage; + uint32 guaranteed_bytes_per_second; + uint32 guaranteed_bytes_per_sampling_period; + uint32 num_bytes_produced_per_second; + uint32 num_bytes_consumed_per_second; + uint32 num_queued_packets; /* Number of packets in queue */ + uint32 num_queued_bytes; /* Number of bytes in queue */ +} trf_mgmt_shaping_info_t; + +/* Traffic management shaping info array */ +typedef struct trf_mgmt_shaping_info_array { + trf_mgmt_global_info_t tx_global_shaping_info; + trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; + trf_mgmt_global_info_t rx_global_shaping_info; + trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; +} trf_mgmt_shaping_info_array_t; + + +/* Traffic management statistical counters */ +typedef struct trf_mgmt_stats { + uint32 num_processed_packets; /* Number of packets processed */ + uint32 num_processed_bytes; /* Number of bytes processed */ + uint32 num_discarded_packets; /* Number of packets discarded from queue */ +} trf_mgmt_stats_t; + +/* Traffic management statisics array */ +typedef struct trf_mgmt_stats_array { + trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; + trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; +} trf_mgmt_stats_array_t; + +typedef struct powersel_params { + /* LPC Params exposed via IOVAR */ + int32 tp_ratio_thresh; /* Throughput ratio threshold */ + uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ + uint8 pwr_stab_thresh; /* Number of successes before power step down */ + uint8 pwr_sel_exp_time; /* Time lapse for expiry of database */ +} powersel_params_t; + +typedef struct lpc_params { + /* LPC Params exposed via IOVAR */ + uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ + uint8 pwr_stab_thresh; /* Number of successes before power step down */ + uint8 lpc_exp_time; /* Time lapse for expiry of database */ + uint8 pwrup_slow_step; /* Step size for slow step up */ + uint8 pwrup_fast_step; /* Step size for fast step up */ + uint8 pwrdn_slow_step; /* Step size for slow step down */ +} lpc_params_t; + +/* tx pkt delay statistics */ +#define SCB_RETRY_SHORT_DEF 7 /* Default Short retry Limit */ +#define WLPKTDLY_HIST_NBINS 16 /* number of bins used in the Delay histogram */ + +/* structure to store per-AC delay statistics */ +typedef struct scb_delay_stats { + uint32 txmpdu_lost; /* number of MPDUs lost */ + uint32 txmpdu_cnt[SCB_RETRY_SHORT_DEF]; /* retry times histogram */ + uint32 delay_sum[SCB_RETRY_SHORT_DEF]; /* cumulative packet latency */ + uint32 delay_min; /* minimum packet latency observed */ + uint32 delay_max; /* maximum packet latency observed */ + uint32 delay_avg; /* packet latency average */ + uint32 delay_hist[WLPKTDLY_HIST_NBINS]; /* delay histogram */ +} scb_delay_stats_t; + +/* structure for txdelay event */ +typedef struct txdelay_event { + uint8 status; + int rssi; + chanim_stats_t chanim_stats; + scb_delay_stats_t delay_stats[AC_COUNT]; +} txdelay_event_t; + +/* structure for txdelay parameters */ +typedef struct txdelay_params { + uint16 ratio; /* Avg Txdelay Delta */ + uint8 cnt; /* Sample cnt */ + uint8 period; /* Sample period */ + uint8 tune; /* Debug */ +} txdelay_params_t; + +enum { + WNM_SERVICE_DMS = 1, + WNM_SERVICE_FMS = 2, + WNM_SERVICE_TFS = 3 +}; + +/* Definitions for WNM/NPS TCLAS */ +typedef struct wl_tclas { + uint8 user_priority; + uint8 fc_len; + dot11_tclas_fc_t fc; +} wl_tclas_t; + +#define WL_TCLAS_FIXED_SIZE OFFSETOF(wl_tclas_t, fc) + +typedef struct wl_tclas_list { + uint32 num; + wl_tclas_t tclas[1]; +} wl_tclas_list_t; + +/* Definitions for WNM/NPS Traffic Filter Service */ +typedef struct wl_tfs_req { + uint8 tfs_id; + uint8 tfs_actcode; + uint8 tfs_subelem_id; + uint8 send; +} wl_tfs_req_t; + +typedef struct wl_tfs_filter { + uint8 status; /* Status returned by the AP */ + uint8 tclas_proc; /* TCLAS processing value (0:and, 1:or) */ + uint8 tclas_cnt; /* count of all wl_tclas_t in tclas array */ + uint8 tclas[1]; /* VLA of wl_tclas_t */ +} wl_tfs_filter_t; +#define WL_TFS_FILTER_FIXED_SIZE OFFSETOF(wl_tfs_filter_t, tclas) + +typedef struct wl_tfs_fset { + struct ether_addr ea; /* Address of AP/STA involved with this filter set */ + uint8 tfs_id; /* TFS ID field chosen by STA host */ + uint8 status; /* Internal status TFS_STATUS_xxx */ + uint8 actcode; /* Action code DOT11_TFS_ACTCODE_xxx */ + uint8 token; /* Token used in last request frame */ + uint8 notify; /* Notify frame sent/received because of this set */ + uint8 filter_cnt; /* count of all wl_tfs_filter_t in filter array */ + uint8 filter[1]; /* VLA of wl_tfs_filter_t */ +} wl_tfs_fset_t; +#define WL_TFS_FSET_FIXED_SIZE OFFSETOF(wl_tfs_fset_t, filter) + +enum { + TFS_STATUS_DISABLED = 0, /* TFS filter set disabled by user */ + TFS_STATUS_DISABLING = 1, /* Empty request just sent to AP */ + TFS_STATUS_VALIDATED = 2, /* Filter set validated by AP (but maybe not enabled!) */ + TFS_STATUS_VALIDATING = 3, /* Filter set just sent to AP */ + TFS_STATUS_NOT_ASSOC = 4, /* STA not associated */ + TFS_STATUS_NOT_SUPPORT = 5, /* TFS not supported by AP */ + TFS_STATUS_DENIED = 6, /* Filter set refused by AP (=> all sets are disabled!) */ +}; + +typedef struct wl_tfs_status { + uint8 fset_cnt; /* count of all wl_tfs_fset_t in fset array */ + wl_tfs_fset_t fset[1]; /* VLA of wl_tfs_fset_t */ +} wl_tfs_status_t; + +typedef struct wl_tfs_set { + uint8 send; /* Immediatly register registered sets on AP side */ + uint8 tfs_id; /* ID of a specific set (existing or new), or nul for all */ + uint8 actcode; /* Action code for this filter set */ + uint8 tclas_proc; /* TCLAS processing operator for this filter set */ +} wl_tfs_set_t; + +typedef struct wl_tfs_term { + uint8 del; /* Delete internal set once confirmation received */ + uint8 tfs_id; /* ID of a specific set (existing), or nul for all */ +} wl_tfs_term_t; + + +#define DMS_DEP_PROXY_ARP (1 << 0) + +/* Definitions for WNM/NPS Directed Multicast Service */ +enum { + DMS_STATUS_DISABLED = 0, /* DMS desc disabled by user */ + DMS_STATUS_ACCEPTED = 1, /* Request accepted by AP */ + DMS_STATUS_NOT_ASSOC = 2, /* STA not associated */ + DMS_STATUS_NOT_SUPPORT = 3, /* DMS not supported by AP */ + DMS_STATUS_DENIED = 4, /* Request denied by AP */ + DMS_STATUS_TERM = 5, /* Request terminated by AP */ + DMS_STATUS_REMOVING = 6, /* Remove request just sent */ + DMS_STATUS_ADDING = 7, /* Add request just sent */ + DMS_STATUS_ERROR = 8, /* Non compliant AP behvior */ + DMS_STATUS_IN_PROGRESS = 9, /* Request just sent */ + DMS_STATUS_REQ_MISMATCH = 10 /* Conditions for sending DMS req not met */ +}; + +typedef struct wl_dms_desc { + uint8 user_id; + uint8 status; + uint8 token; + uint8 dms_id; + uint8 tclas_proc; + uint8 mac_len; /* length of all ether_addr in data array, 0 if STA */ + uint8 tclas_len; /* length of all wl_tclas_t in data array */ + uint8 data[1]; /* VLA of 'ether_addr' and 'wl_tclas_t' (in this order ) */ +} wl_dms_desc_t; + +#define WL_DMS_DESC_FIXED_SIZE OFFSETOF(wl_dms_desc_t, data) + +typedef struct wl_dms_status { + uint32 cnt; + wl_dms_desc_t desc[1]; +} wl_dms_status_t; + +typedef struct wl_dms_set { + uint8 send; + uint8 user_id; + uint8 tclas_proc; +} wl_dms_set_t; + +typedef struct wl_dms_term { + uint8 del; + uint8 user_id; +} wl_dms_term_t; + +typedef struct wl_service_term { + uint8 service; + union { + wl_dms_term_t dms; + } u; +} wl_service_term_t; + +/* Definitions for WNM/NPS BSS Transistion */ +typedef struct wl_bsstrans_req { + uint16 tbtt; /* time of BSS to end of life, in unit of TBTT */ + uint16 dur; /* time of BSS to keep off, in unit of minute */ + uint8 reqmode; /* request mode of BSS transition request */ + uint8 unicast; /* request by unicast or by broadcast */ +} wl_bsstrans_req_t; + +enum { + BSSTRANS_RESP_AUTO = 0, /* Currently equivalent to ENABLE */ + BSSTRANS_RESP_DISABLE = 1, /* Never answer BSS Trans Req frames */ + BSSTRANS_RESP_ENABLE = 2, /* Always answer Req frames with preset data */ + BSSTRANS_RESP_WAIT = 3, /* Send ind, wait and/or send preset data (NOT IMPL) */ + BSSTRANS_RESP_IMMEDIATE = 4 /* After an ind, set data and send resp (NOT IMPL) */ +}; + +typedef struct wl_bsstrans_resp { + uint8 policy; + uint8 status; + uint8 delay; + struct ether_addr target; +} wl_bsstrans_resp_t; + +/* "wnm_bsstrans_policy" argument programs behavior after BSSTRANS Req reception. + * BSS-Transition feature is used by multiple programs such as NPS-PF, VE-PF, + * Band-steering, Hotspot 2.0 and customer requirements. Each PF and its test plan + * mandates different behavior on receiving BSS-transition request. To accomodate + * such divergent behaviors these policies have been created. + */ +enum { + WL_BSSTRANS_POLICY_ROAM_ALWAYS = 0, /* Roam (or disassociate) in all cases */ + WL_BSSTRANS_POLICY_ROAM_IF_MODE = 1, /* Roam only if requested by Request Mode field */ + WL_BSSTRANS_POLICY_ROAM_IF_PREF = 2, /* Roam only if Preferred BSS provided */ + WL_BSSTRANS_POLICY_WAIT = 3, /* Wait for deauth and send Accepted status */ + WL_BSSTRANS_POLICY_PRODUCT = 4, /* Policy for real product use cases (non-pf) */ +}; + +/* Definitions for WNM/NPS TIM Broadcast */ +typedef struct wl_timbc_offset { + int16 offset; /* offset in us */ + uint16 fix_intv; /* override interval sent from STA */ + uint16 rate_override; /* use rate override to send high rate TIM broadcast frame */ + uint8 tsf_present; /* show timestamp in TIM broadcast frame */ +} wl_timbc_offset_t; + +typedef struct wl_timbc_set { + uint8 interval; /* Interval in DTIM wished or required. */ + uint8 flags; /* Bitfield described below */ + uint16 rate_min; /* Minimum rate required for High/Low TIM frames. Optionnal */ + uint16 rate_max; /* Maximum rate required for High/Low TIM frames. Optionnal */ +} wl_timbc_set_t; + +enum { + WL_TIMBC_SET_TSF_REQUIRED = 1, /* Enable TIMBC only if TSF in TIM frames */ + WL_TIMBC_SET_NO_OVERRIDE = 2, /* ... if AP does not override interval */ + WL_TIMBC_SET_PROXY_ARP = 4, /* ... if AP support Proxy ARP */ + WL_TIMBC_SET_DMS_ACCEPTED = 8 /* ... if all DMS desc have been accepted */ +}; + +typedef struct wl_timbc_status { + uint8 status_sta; /* Status from internal state machine (check below) */ + uint8 status_ap; /* From AP response frame (check 8.4.2.86 from 802.11) */ + uint8 interval; + uint8 pad; + int32 offset; + uint16 rate_high; + uint16 rate_low; +} wl_timbc_status_t; + +enum { + WL_TIMBC_STATUS_DISABLE = 0, /* TIMBC disabled by user */ + WL_TIMBC_STATUS_REQ_MISMATCH = 1, /* AP settings do no match user requirements */ + WL_TIMBC_STATUS_NOT_ASSOC = 2, /* STA not associated */ + WL_TIMBC_STATUS_NOT_SUPPORT = 3, /* TIMBC not supported by AP */ + WL_TIMBC_STATUS_DENIED = 4, /* Req to disable TIMBC sent to AP */ + WL_TIMBC_STATUS_ENABLE = 5 /* TIMBC enabled */ +}; + +/* Definitions for PM2 Dynamic Fast Return To Sleep */ +typedef struct wl_pm2_sleep_ret_ext { + uint8 logic; /* DFRTS logic: see WL_DFRTS_LOGIC_* below */ + uint16 low_ms; /* Low FRTS timeout */ + uint16 high_ms; /* High FRTS timeout */ + uint16 rx_pkts_threshold; /* switching threshold: # rx pkts */ + uint16 tx_pkts_threshold; /* switching threshold: # tx pkts */ + uint16 txrx_pkts_threshold; /* switching threshold: # (tx+rx) pkts */ + uint32 rx_bytes_threshold; /* switching threshold: # rx bytes */ + uint32 tx_bytes_threshold; /* switching threshold: # tx bytes */ + uint32 txrx_bytes_threshold; /* switching threshold: # (tx+rx) bytes */ +} wl_pm2_sleep_ret_ext_t; + +#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ +#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ +#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ + +/* Values for the passive_on_restricted_mode iovar. When set to non-zero, this iovar + * disables automatic conversions of a channel from passively scanned to + * actively scanned. These values only have an effect for country codes such + * as XZ where some 5 GHz channels are defined to be passively scanned. + */ +#define WL_PASSACTCONV_DISABLE_NONE 0 /* Enable permanent and temporary conversions */ +#define WL_PASSACTCONV_DISABLE_ALL 1 /* Disable permanent and temporary conversions */ +#define WL_PASSACTCONV_DISABLE_PERM 2 /* Disable only permanent conversions */ + +/* Definitions for Reliable Multicast */ +#define WL_RMC_CNT_VERSION 1 +#define WL_RMC_TR_VERSION 1 +#define WL_RMC_MAX_CLIENT 32 +#define WL_RMC_FLAG_INBLACKLIST 1 +#define WL_RMC_FLAG_ACTIVEACKER 2 +#define WL_RMC_FLAG_RELMCAST 4 +#define WL_RMC_MAX_TABLE_ENTRY 4 + +#define WL_RMC_VER 1 +#define WL_RMC_INDEX_ACK_ALL 255 +#define WL_RMC_NUM_OF_MC_STREAMS 4 +#define WL_RMC_MAX_TRS_PER_GROUP 1 +#define WL_RMC_MAX_TRS_IN_ACKALL 1 +#define WL_RMC_ACK_MCAST0 0x02 +#define WL_RMC_ACK_MCAST_ALL 0x01 +#define WL_RMC_ACTF_TIME_MIN 300 /* time in ms */ +#define WL_RMC_ACTF_TIME_MAX 20000 /* time in ms */ +#define WL_RMC_MAX_NUM_TRS 32 /* maximun transmitters allowed */ +#define WL_RMC_ARTMO_MIN 350 /* time in ms */ +#define WL_RMC_ARTMO_MAX 40000 /* time in ms */ + +/* RMC events in action frames */ +enum rmc_opcodes { + RELMCAST_ENTRY_OP_DISABLE = 0, /* Disable multi-cast group */ + RELMCAST_ENTRY_OP_DELETE = 1, /* Delete multi-cast group */ + RELMCAST_ENTRY_OP_ENABLE = 2, /* Enable multi-cast group */ + RELMCAST_ENTRY_OP_ACK_ALL = 3 /* Enable ACK ALL bit in AMT */ +}; + +/* RMC operational modes */ +enum rmc_modes { + WL_RMC_MODE_RECEIVER = 0, /* Receiver mode by default */ + WL_RMC_MODE_TRANSMITTER = 1, /* Transmitter mode using wl ackreq */ + WL_RMC_MODE_INITIATOR = 2 /* Initiator mode using wl ackreq */ +}; + +/* Each RMC mcast client info */ +typedef struct wl_relmcast_client { + uint8 flag; /* status of client such as AR, R, or blacklisted */ + int16 rssi; /* rssi value of RMC client */ + struct ether_addr addr; /* mac address of RMC client */ +} wl_relmcast_client_t; + +/* RMC Counters */ +typedef struct wl_rmc_cnts { + uint16 version; /* see definition of WL_CNT_T_VERSION */ + uint16 length; /* length of entire structure */ + uint16 dupcnt; /* counter for duplicate rmc MPDU */ + uint16 ackreq_err; /* counter for wl ackreq error */ + uint16 af_tx_err; /* error count for action frame transmit */ + uint16 null_tx_err; /* error count for rmc null frame transmit */ + uint16 af_unicast_tx_err; /* error count for rmc unicast frame transmit */ + uint16 mc_no_amt_slot; /* No mcast AMT entry available */ + /* Unused. Keep for rom compatibility */ + uint16 mc_no_glb_slot; /* No mcast entry available in global table */ + uint16 mc_not_mirrored; /* mcast group is not mirrored */ + uint16 mc_existing_tr; /* mcast group is already taken by transmitter */ + uint16 mc_exist_in_amt; /* mcast group is already programmed in amt */ + /* Unused. Keep for rom compatibility */ + uint16 mc_not_exist_in_gbl; /* mcast group is not in global table */ + uint16 mc_not_exist_in_amt; /* mcast group is not in AMT table */ + uint16 mc_utilized; /* mcast addressed is already taken */ + uint16 mc_taken_other_tr; /* multi-cast addressed is already taken */ + uint32 rmc_rx_frames_mac; /* no of mc frames received from mac */ + uint32 rmc_tx_frames_mac; /* no of mc frames transmitted to mac */ + uint32 mc_null_ar_cnt; /* no. of times NULL AR is received */ + uint32 mc_ar_role_selected; /* no. of times took AR role */ + uint32 mc_ar_role_deleted; /* no. of times AR role cancelled */ + uint32 mc_noacktimer_expired; /* no. of times noack timer expired */ + uint16 mc_no_wl_clk; /* no wl clk detected when trying to access amt */ + uint16 mc_tr_cnt_exceeded; /* No of transmitters in the network exceeded */ +} wl_rmc_cnts_t; + +/* RMC Status */ +typedef struct wl_relmcast_st { + uint8 ver; /* version of RMC */ + uint8 num; /* number of clients detected by transmitter */ + wl_relmcast_client_t clients[WL_RMC_MAX_CLIENT]; + uint16 err; /* error status (used in infra) */ + uint16 actf_time; /* action frame time period */ +} wl_relmcast_status_t; + +/* Entry for each STA/node */ +typedef struct wl_rmc_entry { + /* operation on multi-cast entry such add, + * delete, ack-all + */ + int8 flag; + struct ether_addr addr; /* multi-cast group mac address */ +} wl_rmc_entry_t; + +/* RMC table */ +typedef struct wl_rmc_entry_table { + uint8 index; /* index to a particular mac entry in table */ + uint8 opcode; /* opcodes or operation on entry */ + wl_rmc_entry_t entry[WL_RMC_MAX_TABLE_ENTRY]; +} wl_rmc_entry_table_t; + +typedef struct wl_rmc_trans_elem { + struct ether_addr tr_mac; /* transmitter mac */ + struct ether_addr ar_mac; /* ar mac */ + uint16 artmo; /* AR timeout */ + uint8 amt_idx; /* amt table entry */ + uint16 flag; /* entry will be acked, not acked, programmed, full etc */ +} wl_rmc_trans_elem_t; + +/* RMC transmitters */ +typedef struct wl_rmc_trans_in_network { + uint8 ver; /* version of RMC */ + uint8 num_tr; /* number of transmitters in the network */ + wl_rmc_trans_elem_t trs[WL_RMC_MAX_NUM_TRS]; +} wl_rmc_trans_in_network_t; + +/* To update vendor specific ie for RMC */ +typedef struct wl_rmc_vsie { + uint8 oui[DOT11_OUI_LEN]; + uint16 payload; /* IE Data Payload */ +} wl_rmc_vsie_t; + + +/* structures & defines for proximity detection */ +enum proxd_method { + PROXD_UNDEFINED_METHOD = 0, + PROXD_RSSI_METHOD = 1, + PROXD_TOF_METHOD = 2 +}; + +/* structures for proximity detection device role */ +#define WL_PROXD_MODE_DISABLE 0 +#define WL_PROXD_MODE_NEUTRAL 1 +#define WL_PROXD_MODE_INITIATOR 2 +#define WL_PROXD_MODE_TARGET 3 + +#define WL_PROXD_ACTION_STOP 0 +#define WL_PROXD_ACTION_START 1 + +#define WL_PROXD_FLAG_TARGET_REPORT 0x1 +#define WL_PROXD_FLAG_REPORT_FAILURE 0x2 +#define WL_PROXD_FLAG_INITIATOR_REPORT 0x4 +#define WL_PROXD_FLAG_NOCHANSWT 0x8 +#define WL_PROXD_FLAG_NETRUAL 0x10 +#define WL_PROXD_FLAG_INITIATOR_RPTRTT 0x20 +#define WL_PROXD_FLAG_ONEWAY 0x40 +#define WL_PROXD_FLAG_SEQ_EN 0x80 + +#define WL_PROXD_RANDOM_WAKEUP 0x8000 + +typedef struct wl_proxd_iovar { + uint16 method; /* Proxmity Detection method */ + uint16 mode; /* Mode (neutral, initiator, target) */ +} wl_proxd_iovar_t; + +/* + * structures for proximity detection parameters + * consists of two parts, common and method specific params + * common params should be placed at the beginning + */ + +/* require strict packing */ +#include + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_common { + chanspec_t chanspec; /* channel spec */ + int16 tx_power; /* tx power of Proximity Detection(PD) frames (in dBm) */ + uint16 tx_rate; /* tx rate of PD rames (in 500kbps units) */ + uint16 timeout; /* timeout value */ + uint16 interval; /* interval between neighbor finding attempts (in TU) */ + uint16 duration; /* duration of neighbor finding attempts (in ms) */ +} BWL_POST_PACKED_STRUCT wl_proxd_params_common_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_rssi_method { + chanspec_t chanspec; /* chanspec for home channel */ + int16 tx_power; /* tx power of Proximity Detection frames (in dBm) */ + uint16 tx_rate; /* tx rate of PD frames, 500kbps units */ + uint16 timeout; /* state machine wait timeout of the frames (in ms) */ + uint16 interval; /* interval between neighbor finding attempts (in TU) */ + uint16 duration; /* duration of neighbor finding attempts (in ms) */ + /* method specific ones go after this line */ + int16 rssi_thresh; /* RSSI threshold (in dBm) */ + uint16 maxconvergtmo; /* max wait converge timeout (in ms) */ +} wl_proxd_params_rssi_method_t; + +#define Q1_NS 25 /* Q1 time units */ + +#define TOF_BW_NUM 3 /* number of bandwidth that the TOF can support */ +#define TOF_BW_SEQ_NUM (TOF_BW_NUM+2) /* number of total index */ +enum tof_bw_index { + TOF_BW_20MHZ_INDEX = 0, + TOF_BW_40MHZ_INDEX = 1, + TOF_BW_80MHZ_INDEX = 2, + TOF_BW_SEQTX_INDEX = 3, + TOF_BW_SEQRX_INDEX = 4 +}; + +#define BANDWIDTH_BASE 20 /* base value of bandwidth */ +#define TOF_BW_20MHZ (BANDWIDTH_BASE << TOF_BW_20MHZ_INDEX) +#define TOF_BW_40MHZ (BANDWIDTH_BASE << TOF_BW_40MHZ_INDEX) +#define TOF_BW_80MHZ (BANDWIDTH_BASE << TOF_BW_80MHZ_INDEX) +#define TOF_BW_10MHZ 10 + +#define NFFT_BASE 64 /* base size of fft */ +#define TOF_NFFT_20MHZ (NFFT_BASE << TOF_BW_20MHZ_INDEX) +#define TOF_NFFT_40MHZ (NFFT_BASE << TOF_BW_40MHZ_INDEX) +#define TOF_NFFT_80MHZ (NFFT_BASE << TOF_BW_80MHZ_INDEX) + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_method { + chanspec_t chanspec; /* chanspec for home channel */ + int16 tx_power; /* tx power of Proximity Detection(PD) frames (in dBm) */ + uint16 tx_rate; /* tx rate of PD rames (in 500kbps units) */ + uint16 timeout; /* state machine wait timeout of the frames (in ms) */ + uint16 interval; /* interval between neighbor finding attempts (in TU) */ + uint16 duration; /* duration of neighbor finding attempts (in ms) */ + /* specific for the method go after this line */ + struct ether_addr tgt_mac; /* target mac addr for TOF method */ + uint16 ftm_cnt; /* number of the frames txed by initiator */ + uint16 retry_cnt; /* number of retransmit attampts for ftm frames */ + int16 vht_rate; /* ht or vht rate */ + /* add more params required for other methods can be added here */ +} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_method_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_tune { + uint32 Ki; /* h/w delay K factor for initiator */ + uint32 Kt; /* h/w delay K factor for target */ + int16 vhtack; /* enable/disable VHT ACK */ + int16 N_log2[TOF_BW_SEQ_NUM]; /* simple threshold crossing */ + int16 w_offset[TOF_BW_NUM]; /* offset of threshold crossing window(per BW) */ + int16 w_len[TOF_BW_NUM]; /* length of threshold crossing window(per BW) */ + int32 maxDT; /* max time difference of T4/T1 or T3/T2 */ + int32 minDT; /* min time difference of T4/T1 or T3/T2 */ + uint8 totalfrmcnt; /* total count of transfered measurement frames */ + uint16 rsv_media; /* reserve media value for TOF */ + uint32 flags; /* flags */ + uint8 core; /* core to use for tx */ + uint8 force_K; /* set to force value of K */ + int16 N_scale[TOF_BW_SEQ_NUM]; /* simple threshold crossing */ + uint8 sw_adj; /* enable sw assisted timestamp adjustment */ + uint8 hw_adj; /* enable hw assisted timestamp adjustment */ + uint8 seq_en; /* enable ranging sequence */ + uint8 ftm_cnt[TOF_BW_SEQ_NUM]; /* number of ftm frames based on bandwidth */ +} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_tune_t; + +typedef struct wl_proxd_params_iovar { + uint16 method; /* Proxmity Detection method */ + union { + /* common params for pdsvc */ + wl_proxd_params_common_t cmn_params; /* common parameters */ + /* method specific */ + wl_proxd_params_rssi_method_t rssi_params; /* RSSI method parameters */ + wl_proxd_params_tof_method_t tof_params; /* TOF meothod parameters */ + /* tune parameters */ + wl_proxd_params_tof_tune_t tof_tune; /* TOF tune parameters */ + } u; /* Method specific optional parameters */ +} wl_proxd_params_iovar_t; + +#define PROXD_COLLECT_GET_STATUS 0 +#define PROXD_COLLECT_SET_STATUS 1 +#define PROXD_COLLECT_QUERY_HEADER 2 +#define PROXD_COLLECT_QUERY_DATA 3 +#define PROXD_COLLECT_QUERY_DEBUG 4 +#define PROXD_COLLECT_REMOTE_REQUEST 5 + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_query { + uint32 method; /* method */ + uint8 request; /* Query request. */ + uint8 status; /* 0 -- disable, 1 -- enable collection, */ + /* 2 -- enable collection & debug */ + uint16 index; /* The current frame index [0 to total_frames - 1]. */ + uint16 mode; /* Initiator or Target */ + bool busy; /* tof sm is busy */ + bool remote; /* Remote collect data */ +} BWL_POST_PACKED_STRUCT wl_proxd_collect_query_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_header { + uint16 total_frames; /* The totral frames for this collect. */ + uint16 nfft; /* nfft value */ + uint16 bandwidth; /* bandwidth */ + uint16 channel; /* channel number */ + uint32 chanspec; /* channel spec */ + uint32 fpfactor; /* avb timer value factor */ + uint16 fpfactor_shift; /* avb timer value shift bits */ + int32 distance; /* distance calculated by fw */ + uint32 meanrtt; /* mean of RTTs */ + uint32 modertt; /* mode of RTTs */ + uint32 medianrtt; /* median of RTTs */ + uint32 sdrtt; /* standard deviation of RTTs */ + uint32 clkdivisor; /* clock divisor */ + uint16 chipnum; /* chip type */ + uint8 chiprev; /* chip revision */ + uint8 phyver; /* phy version */ + struct ether_addr loaclMacAddr; /* local mac address */ + struct ether_addr remoteMacAddr; /* remote mac address */ + wl_proxd_params_tof_tune_t params; +} BWL_POST_PACKED_STRUCT wl_proxd_collect_header_t; + + +/* ********************** NAN wl interface struct types and defs ******************** */ + +#define WL_NAN_IOCTL_VERSION 0x1 +#define WL_P2P_NAN_IOCTL_VERSION 0x1 +#define P2P_NAN_IOC_BUFSZ 512 /* nan p2p ioctl buffer size */ +/* wl_nan_sub_cmd may also be used in dhd */ +typedef struct wl_nan_sub_cmd wl_nan_sub_cmd_t; +typedef int (cmd_handler_t)(void *wl, const wl_nan_sub_cmd_t *cmd, char **argv); +/* nan cmd list entry */ +struct wl_nan_sub_cmd { + char *name; + uint8 version; /* cmd version */ + uint16 id; /* id for the dongle f/w switch/case */ + uint16 type; /* base type of argument */ + cmd_handler_t *handler; /* cmd handler */ +}; +/* p2p nan cfg ioctls */ +enum wl_p2p_nan_cmds { + WL_P2P_NAN_CMD_ENABLE = 1, + WL_P2P_NAN_CMD_CONFIG = 2, + WL_P2P_NAN_CMD_DEL_CONFIG = 3 +}; +/* container for p2p nan iovtls & events */ +typedef BWL_PRE_PACKED_STRUCT struct wl_p2p_nan_ioc { + uint16 version; /* interface command or event version */ + uint16 id; /* p2p nan ioctl cmd ID */ + uint16 len; /* total length of data[] */ + uint8 data [1]; /* var len payload of bcm_xtlv_t type */ +} BWL_POST_PACKED_STRUCT wl_p2p_nan_ioc_t; + +/* container for nan iovtls & events */ +typedef BWL_PRE_PACKED_STRUCT struct wl_nan_ioc { + uint16 version; /* interface command or event version */ + uint16 id; /* nan ioctl cmd ID */ + uint16 len; /* total length of all tlv records in data[] */ + uint16 PAD; /* pad to be 32 bit aligment */ + uint8 data [1]; /* var len payload of bcm_xtlv_t type */ +} BWL_POST_PACKED_STRUCT wl_nan_ioc_t; + +typedef struct wl_nan_status { + uint8 inited; + uint8 joined; + uint8 role; + uint8 hop_count; + uint32 chspec; + uint8 amr[8]; /* Anchor Master Rank */ + uint32 cnt_pend_txfrm; /* pending TX frames */ + uint32 cnt_bcn_tx; /* TX disc/sync beacon count */ + uint32 cnt_bcn_rx; /* RX disc/sync beacon count */ + uint32 cnt_svc_disc_tx; /* TX svc disc frame count */ + uint32 cnt_svc_disc_rx; /* RX svc disc frame count */ + struct ether_addr cid; +} wl_nan_status_t; + +/* various params and ctl swithce for nan_debug instance */ +typedef struct nan_debug_params { + uint8 enabled; /* runtime debuging enabled */ + uint8 collect; /* enables debug svc sdf monitor mode */ + uint16 cmd; /* debug cmd to perform a debug action */ + uint32 msglevel; /* msg level if enabled */ + uint16 status; +} nan_debug_params_t; + + +/* nan passive scan params */ +#define NAN_SCAN_MAX_CHCNT 8 +typedef BWL_PRE_PACKED_STRUCT struct nan_scan_params { + uint16 scan_time; + uint16 home_time; + uint16 ms_intvl; /* interval between merge scan */ + uint16 ms_dur; /* duration of merge scan */ + uint16 chspec_num; + uint8 PAD[2]; /* pad to make 4 byte alignment */ + chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /* act. used 3, 5 rfu */ +} BWL_POST_PACKED_STRUCT nan_scan_params_t; + +enum wl_nan_role { + WL_NAN_ROLE_AUTO = 0, + WL_NAN_ROLE_NON_MASTER_NON_SYNC = 1, + WL_NAN_ROLE_NON_MASTER_SYNC = 2, + WL_NAN_ROLE_MASTER = 3, + WL_NAN_ROLE_ANCHOR_MASTER = 4 +}; +#define NAN_MASTER_RANK_LEN 8 +/* nan cmd IDs */ +enum wl_nan_cmds { + /* nan cfg /disc & dbg ioctls */ + WL_NAN_CMD_ENABLE = 1, + WL_NAN_CMD_ATTR = 2, + WL_NAN_CMD_NAN_JOIN = 3, + WL_NAN_CMD_LEAVE = 4, + WL_NAN_CMD_MERGE = 5, + WL_NAN_CMD_STATUS = 6, + /* discovery engine commands */ + WL_NAN_CMD_PUBLISH = 20, + WL_NAN_CMD_SUBSCRIBE = 21, + WL_NAN_CMD_CANCEL_PUBLISH = 22, + WL_NAN_CMD_CANCEL_SUBSCRIBE = 23, + WL_NAN_CMD_TRANSMIT = 24, + WL_NAN_CMD_CONNECTION = 25, + WL_NAN_CMD_SHOW = 26, + WL_NAN_CMD_STOP = 27, /* stop nan for a given cluster ID */ + /* nan debug iovars & cmds */ + WL_NAN_CMD_SCAN_PARAMS = 46, + WL_NAN_CMD_SCAN = 47, + WL_NAN_CMD_SCAN_RESULTS = 48, + WL_NAN_CMD_EVENT_MASK = 49, + WL_NAN_CMD_EVENT_CHECK = 50, + + WL_NAN_CMD_DEBUG = 60, + WL_NAN_CMD_TEST1 = 61, + WL_NAN_CMD_TEST2 = 62, + WL_NAN_CMD_TEST3 = 63 +}; + +/* + * tlv IDs uniquely identifies cmd parameters + * packed into wl_nan_ioc_t container + */ +enum wl_nan_cmd_xtlv_id { + /* 0x00 ~ 0xFF: standard TLV ID whose data format is the same as NAN attribute TLV */ + WL_NAN_XTLV_ZERO = 0, /* used as tlv buf end marker */ +#ifdef NAN_STD_TLV /* rfu, don't use yet */ + WL_NAN_XTLV_MASTER_IND = 1, /* == NAN_ATTR_MASTER_IND, */ + WL_NAN_XTLV_CLUSTER = 2, /* == NAN_ATTR_CLUSTER, */ + WL_NAN_XTLV_VENDOR = 221, /* == NAN_ATTR_VENDOR, */ +#endif + /* 0x02 ~ 0xFF: reserved. In case to use with the same data format as NAN attribute TLV */ + /* 0x100 ~ : private TLV ID defined just for NAN command */ + /* common types */ + WL_NAN_XTLV_BUFFER = 0x101, /* generic type, function depends on cmd context */ + WL_NAN_XTLV_MAC_ADDR = 0x102, /* used in various cmds */ + WL_NAN_XTLV_REASON = 0x103, + WL_NAN_XTLV_ENABLE = 0x104, + /* explicit types, primarily for discovery engine iovars */ + WL_NAN_XTLV_SVC_PARAMS = 0x120, /* Contains required params: wl_nan_disc_params_t */ + WL_NAN_XTLV_MATCH_RX = 0x121, /* Matching filter to evaluate on receive */ + WL_NAN_XTLV_MATCH_TX = 0x122, /* Matching filter to send */ + WL_NAN_XTLV_SVC_INFO = 0x123, /* Service specific info */ + WL_NAN_XTLV_SVC_NAME = 0x124, /* Optional UTF-8 service name, for debugging. */ + WL_NAN_XTLV_INSTANCE_ID = 0x125, /* Identifies unique publish or subscribe instance */ + WL_NAN_XTLV_PRIORITY = 0x126, /* used in transmit cmd context */ + WL_NAN_XTLV_REQUESTOR_ID = 0x127, /* Requestor instance ID */ + WL_NAN_XTLV_VNDR = 0x128, /* Vendor specific attribute */ + WL_NAN_XTLV_PEER_INSTANCE_ID = 0x131, /* Used to parse remote instance Id */ + /* explicit types, primarily for NAN MAC iovars */ + WL_NAN_XTLV_DW_LEN = 0x140, /* discovery win length */ + WL_NAN_XTLV_BCN_INTERVAL = 0x141, /* beacon interval, both sync and descovery bcns? */ + WL_NAN_XTLV_CLUSTER_ID = 0x142, + WL_NAN_XTLV_IF_ADDR = 0x143, + WL_NAN_XTLV_MC_ADDR = 0x144, + WL_NAN_XTLV_ROLE = 0x145, + WL_NAN_XTLV_START = 0x146, + + WL_NAN_XTLV_MASTER_PREF = 0x147, + WL_NAN_XTLV_DW_INTERVAL = 0x148, + WL_NAN_XTLV_PTBTT_OVERRIDE = 0x149, + /* nan status command xtlvs */ + WL_NAN_XTLV_MAC_INITED = 0x14a, + WL_NAN_XTLV_MAC_ENABLED = 0x14b, + WL_NAN_XTLV_MAC_CHANSPEC = 0x14c, + WL_NAN_XTLV_MAC_AMR = 0x14d, /* anchormaster rank u8 amr[8] */ + WL_NAN_XTLV_MAC_HOPCNT = 0x14e, + WL_NAN_XTLV_MAC_AMBTT = 0x14f, + WL_NAN_XTLV_MAC_TXRATE = 0x150, + WL_NAN_XTLV_MAC_STATUS = 0x151, /* xtlv payload is nan_status_t */ + WL_NAN_XTLV_NAN_SCANPARAMS = 0x152, /* payload is nan_scan_params_t */ + WL_NAN_XTLV_DEBUGPARAMS = 0x153, /* payload is nan_scan_params_t */ + WL_NAN_XTLV_SUBSCR_ID = 0x154, /* subscriber id */ + WL_NAN_XTLV_PUBLR_ID = 0x155, /* publisher id */ + WL_NAN_XTLV_EVENT_MASK = 0x156, + WL_NAN_XTLV_MERGE = 0x157 +}; + +/* Flag bits for Publish and Subscribe (wl_nan_disc_params_t flags) */ +#define WL_NAN_RANGE_LIMITED 0x0040 +/* Bits specific to Publish */ +/* Unsolicited transmissions */ +#define WL_NAN_PUB_UNSOLICIT 0x1000 +/* Solicited transmissions */ +#define WL_NAN_PUB_SOLICIT 0x2000 +#define WL_NAN_PUB_BOTH 0x3000 +/* Set for broadcast solicited transmission + * Do not set for unicast solicited transmission + */ +#define WL_NAN_PUB_BCAST 0x4000 +/* Generate event on each solicited transmission */ +#define WL_NAN_PUB_EVENT 0x8000 +/* Used for one-time solicited Publish functions to indicate transmision occurred */ +#define WL_NAN_PUB_SOLICIT_PENDING 0x10000 +/* Follow-up frames */ +#define WL_NAN_FOLLOWUP 0x20000 +/* Bits specific to Subscribe */ +/* Active subscribe mode (Leave unset for passive) */ +#define WL_NAN_SUB_ACTIVE 0x1000 + +/* Special values for time to live (ttl) parameter */ +#define WL_NAN_TTL_UNTIL_CANCEL 0xFFFFFFFF +/* Publish - runs until first transmission + * Subscribe - runs until first DiscoveryResult event + */ +#define WL_NAN_TTL_FIRST 0 + +/* The service hash (service id) is exactly this many bytes. */ +#define WL_NAN_SVC_HASH_LEN 6 + +/* Instance ID type (unique identifier) */ +typedef uint8 wl_nan_instance_id_t; + +/* Mandatory parameters for publish/subscribe iovars - NAN_TLV_SVC_PARAMS */ +typedef struct wl_nan_disc_params_s { + /* Periodicity of unsolicited/query transmissions, in DWs */ + uint32 period; + /* Time to live in DWs */ + uint32 ttl; + /* Flag bits */ + uint32 flags; + /* Publish or subscribe service id, i.e. hash of the service name */ + uint8 svc_hash[WL_NAN_SVC_HASH_LEN]; + /* pad to make 4 byte alignment, can be used for something else in the future */ + uint8 PAD; + /* Publish or subscribe id */ + wl_nan_instance_id_t instance_id; +} wl_nan_disc_params_t; + +/* +* desovery interface event structures * +*/ + +/* NAN Ranging */ + +/* Bit defines for global flags */ +#define WL_NAN_RANGING_ENABLE 1 /* enable RTT */ +#define WL_NAN_RANGING_RANGED 2 /* Report to host if ranged as target */ +typedef struct nan_ranging_config { + uint32 chanspec; /* Ranging chanspec */ + uint16 timeslot; /* NAN RTT start time slot 1-511 */ + uint16 duration; /* NAN RTT duration in ms */ + struct ether_addr allow_mac; /* peer initiated ranging: the allowed peer mac + * address, a unicast (for one peer) or + * a broadcast for all. Setting it to all zeros + * means responding to none,same as not setting + * the flag bit NAN_RANGING_RESPOND + */ + uint16 flags; +} wl_nan_ranging_config_t; + +/* list of peers for self initiated ranging */ +/* Bit defines for per peer flags */ +#define WL_NAN_RANGING_REPORT (1<<0) /* Enable reporting range to target */ +typedef struct nan_ranging_peer { + uint32 chanspec; /* desired chanspec for this peer */ + uint32 abitmap; /* available bitmap */ + struct ether_addr ea; /* peer MAC address */ + uint8 frmcnt; /* frame count */ + uint8 retrycnt; /* retry count */ + uint16 flags; /* per peer flags, report or not */ +} wl_nan_ranging_peer_t; +typedef struct nan_ranging_list { + uint8 count; /* number of MAC addresses */ + uint8 num_peers_done; /* host set to 0, when read, shows number of peers + * completed, success or fail + */ + uint8 num_dws; /* time period to do the ranging, specified in dws */ + uint8 reserve; /* reserved field */ + wl_nan_ranging_peer_t rp[1]; /* variable length array of peers */ +} wl_nan_ranging_list_t; + +/* ranging results, a list for self initiated ranging and one for peer initiated ranging */ +/* There will be one structure for each peer */ +#define WL_NAN_RANGING_STATUS_SUCCESS 1 +#define WL_NAN_RANGING_STATUS_FAIL 2 +#define WL_NAN_RANGING_STATUS_TIMEOUT 3 +#define WL_NAN_RANGING_STATUS_ABORT 4 /* with partial results if sounding count > 0 */ +typedef struct nan_ranging_result { + uint8 status; /* 1: Success, 2: Fail 3: Timeout 4: Aborted */ + uint8 sounding_count; /* number of measurements completed (0 = failure) */ + struct ether_addr ea; /* initiator MAC address */ + uint32 chanspec; /* Chanspec where the ranging was done */ + uint32 timestamp; /* 32bits of the TSF timestamp ranging was completed at */ + uint32 distance; /* mean distance in meters expressed as Q4 number. + * Only valid when sounding_count > 0. Examples: + * 0x08 = 0.5m + * 0x10 = 1m + * 0x18 = 1.5m + * set to 0xffffffff to indicate invalid number + */ + int32 rtt_var; /* standard deviation in 10th of ns of RTTs measured. + * Only valid when sounding_count > 0 + */ + struct ether_addr tgtea; /* target MAC address */ +} wl_nan_ranging_result_t; +typedef struct nan_ranging_event_data { + uint8 mode; /* 1: Result of host initiated ranging */ + /* 2: Result of peer initiated ranging */ + uint8 reserved; + uint8 success_count; /* number of peers completed successfully */ + uint8 count; /* number of peers in the list */ + wl_nan_ranging_result_t rr[1]; /* variable array of ranging peers */ +} wl_nan_ranging_event_data_t; + +#define WL_P2P_NAN_CONFIG_VERSION 1 + +typedef struct p2p_nan_config { + uint16 version; /* wl_p2p_nan_config_t structure version */ + uint16 len; /* total length */ + uint8 map_ctrl; /* Map control information */ + uint8 dev_role; /* Device role: Table 5-18: dev_role is 1 octet */ + uint16 ie_len; /* variable ie len */ + struct ether_addr mac; /* Mac address based on device role */ + uint32 avail_bmap; /* availability interval bitmap */ + uint8 ie[1]; /* hex ie data */ +} wl_p2p_nan_config_t; + +/* ********************* end of NAN section ******************************** */ + + +#define RSSI_THRESHOLD_SIZE 16 +#define MAX_IMP_RESP_SIZE 256 + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_rssi_bias { + int32 version; /* version */ + int32 threshold[RSSI_THRESHOLD_SIZE]; /* threshold */ + int32 peak_offset; /* peak offset */ + int32 bias; /* rssi bias */ + int32 gd_delta; /* GD - GD_ADJ */ + int32 imp_resp[MAX_IMP_RESP_SIZE]; /* (Hi*Hi)+(Hr*Hr) */ +} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_rssi_bias_avg { + int32 avg_threshold[RSSI_THRESHOLD_SIZE]; /* avg threshold */ + int32 avg_peak_offset; /* avg peak offset */ + int32 avg_rssi; /* avg rssi */ + int32 avg_bias; /* avg bias */ +} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_avg_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_info { + uint16 type; /* type: 0 channel table, 1 channel smoothing table, 2 and 3 seq */ + uint16 index; /* The current frame index, from 1 to total_frames. */ + uint16 tof_cmd; /* M_TOF_CMD */ + uint16 tof_rsp; /* M_TOF_RSP */ + uint16 tof_avb_rxl; /* M_TOF_AVB_RX_L */ + uint16 tof_avb_rxh; /* M_TOF_AVB_RX_H */ + uint16 tof_avb_txl; /* M_TOF_AVB_TX_L */ + uint16 tof_avb_txh; /* M_TOF_AVB_TX_H */ + uint16 tof_id; /* M_TOF_ID */ + uint8 tof_frame_type; + uint8 tof_frame_bw; + int8 tof_rssi; + int32 tof_cfo; + int32 gd_adj_ns; /* gound delay */ + int32 gd_h_adj_ns; /* group delay + threshold crossing */ +#ifdef RSSI_REFINE + wl_proxd_rssi_bias_t rssi_bias; /* RSSI refinement info */ +#endif + int16 nfft; /* number of samples stored in H */ + +} BWL_POST_PACKED_STRUCT wl_proxd_collect_info_t; + +#define k_tof_collect_H_pad 1 +#define k_tof_collect_H_size (256+16+k_tof_collect_H_pad) +#define k_tof_collect_Hraw_size (2*k_tof_collect_H_size) +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_data { + wl_proxd_collect_info_t info; + uint32 H[k_tof_collect_H_size]; /* raw data read from phy used to adjust timestamps */ + +} BWL_POST_PACKED_STRUCT wl_proxd_collect_data_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_debug_data { + uint8 count; /* number of packets */ + uint8 stage; /* state machone stage */ + uint8 received; /* received or txed */ + uint8 paket_type; /* packet type */ + uint8 category; /* category field */ + uint8 action; /* action field */ + uint8 token; /* token number */ + uint8 follow_token; /* following token number */ + uint16 index; /* index of the packet */ + uint16 tof_cmd; /* M_TOF_CMD */ + uint16 tof_rsp; /* M_TOF_RSP */ + uint16 tof_avb_rxl; /* M_TOF_AVB_RX_L */ + uint16 tof_avb_rxh; /* M_TOF_AVB_RX_H */ + uint16 tof_avb_txl; /* M_TOF_AVB_TX_L */ + uint16 tof_avb_txh; /* M_TOF_AVB_TX_H */ + uint16 tof_id; /* M_TOF_ID */ + uint16 tof_status0; /* M_TOF_STATUS_0 */ + uint16 tof_status2; /* M_TOF_STATUS_2 */ + uint16 tof_chsm0; /* M_TOF_CHNSM_0 */ + uint16 tof_phyctl0; /* M_TOF_PHYCTL0 */ + uint16 tof_phyctl1; /* M_TOF_PHYCTL1 */ + uint16 tof_phyctl2; /* M_TOF_PHYCTL2 */ + uint16 tof_lsig; /* M_TOF_LSIG */ + uint16 tof_vhta0; /* M_TOF_VHTA0 */ + uint16 tof_vhta1; /* M_TOF_VHTA1 */ + uint16 tof_vhta2; /* M_TOF_VHTA2 */ + uint16 tof_vhtb0; /* M_TOF_VHTB0 */ + uint16 tof_vhtb1; /* M_TOF_VHTB1 */ + uint16 tof_apmductl; /* M_TOF_AMPDU_CTL */ + uint16 tof_apmdudlim; /* M_TOF_AMPDU_DLIM */ + uint16 tof_apmdulen; /* M_TOF_AMPDU_LEN */ +} BWL_POST_PACKED_STRUCT wl_proxd_debug_data_t; + +/* version of the wl_wsec_info structure */ +#define WL_WSEC_INFO_VERSION 0x01 + +/* start enum value for BSS properties */ +#define WL_WSEC_INFO_BSS_BASE 0x0100 + +/* size of len and type fields of wl_wsec_info_tlv_t struct */ +#define WL_WSEC_INFO_TLV_HDR_LEN OFFSETOF(wl_wsec_info_tlv_t, data) + +/* Allowed wl_wsec_info properties; not all of them may be supported. */ +typedef enum { + WL_WSEC_INFO_NONE = 0, + WL_WSEC_INFO_MAX_KEYS = 1, + WL_WSEC_INFO_NUM_KEYS = 2, + WL_WSEC_INFO_NUM_HW_KEYS = 3, + WL_WSEC_INFO_MAX_KEY_IDX = 4, + WL_WSEC_INFO_NUM_REPLAY_CNTRS = 5, + WL_WSEC_INFO_SUPPORTED_ALGOS = 6, + WL_WSEC_INFO_MAX_KEY_LEN = 7, + WL_WSEC_INFO_FLAGS = 8, + /* add global/per-wlc properties above */ + WL_WSEC_INFO_BSS_FLAGS = (WL_WSEC_INFO_BSS_BASE + 1), + WL_WSEC_INFO_BSS_WSEC = (WL_WSEC_INFO_BSS_BASE + 2), + WL_WSEC_INFO_BSS_TX_KEY_ID = (WL_WSEC_INFO_BSS_BASE + 3), + WL_WSEC_INFO_BSS_ALGO = (WL_WSEC_INFO_BSS_BASE + 4), + WL_WSEC_INFO_BSS_KEY_LEN = (WL_WSEC_INFO_BSS_BASE + 5), + /* add per-BSS properties above */ + WL_WSEC_INFO_MAX = 0xffff +} wl_wsec_info_type_t; + +/* tlv used to return wl_wsec_info properties */ +typedef struct { + uint16 type; + uint16 len; /* data length */ + uint8 data[1]; /* data follows */ +} wl_wsec_info_tlv_t; + +/* input/output data type for wsec_info iovar */ +typedef struct wl_wsec_info { + uint8 version; /* structure version */ + uint8 pad[2]; + uint8 num_tlvs; + wl_wsec_info_tlv_t tlvs[1]; /* tlv data follows */ +} wl_wsec_info_t; + +/* no default structure packing */ +#include + +enum rssi_reason { + RSSI_REASON_UNKNOW = 0, + RSSI_REASON_LOWRSSI = 1, + RSSI_REASON_NSYC = 2, + RSSI_REASON_TIMEOUT = 3 +}; + +enum tof_reason { + TOF_REASON_OK = 0, + TOF_REASON_REQEND = 1, + TOF_REASON_TIMEOUT = 2, + TOF_REASON_NOACK = 3, + TOF_REASON_INVALIDAVB = 4, + TOF_REASON_INITIAL = 5, + TOF_REASON_ABORT = 6 +}; + +enum rssi_state { + RSSI_STATE_POLL = 0, + RSSI_STATE_TPAIRING = 1, + RSSI_STATE_IPAIRING = 2, + RSSI_STATE_THANDSHAKE = 3, + RSSI_STATE_IHANDSHAKE = 4, + RSSI_STATE_CONFIRMED = 5, + RSSI_STATE_PIPELINE = 6, + RSSI_STATE_NEGMODE = 7, + RSSI_STATE_MONITOR = 8, + RSSI_STATE_LAST = 9 +}; + +enum tof_state { + TOF_STATE_IDLE = 0, + TOF_STATE_IWAITM = 1, + TOF_STATE_TWAITM = 2, + TOF_STATE_ILEGACY = 3, + TOF_STATE_IWAITCL = 4, + TOF_STATE_TWAITCL = 5, + TOF_STATE_ICONFIRM = 6, + TOF_STATE_IREPORT = 7 +}; + +enum tof_mode_type { + TOF_LEGACY_UNKNOWN = 0, + TOF_LEGACY_AP = 1, + TOF_NONLEGACY_AP = 2 +}; + +enum tof_way_type { + TOF_TYPE_ONE_WAY = 0, + TOF_TYPE_TWO_WAY = 1, + TOF_TYPE_REPORT = 2 +}; + +enum tof_rate_type { + TOF_FRAME_RATE_VHT = 0, + TOF_FRAME_RATE_LEGACY = 1 +}; + +#define TOF_ADJ_TYPE_NUM 4 /* number of assisted timestamp adjustment */ +enum tof_adj_mode { + TOF_ADJ_SOFTWARE = 0, + TOF_ADJ_HARDWARE = 1, + TOF_ADJ_SEQ = 2, + TOF_ADJ_NONE = 3 +}; + +#define FRAME_TYPE_NUM 4 /* number of frame type */ +enum frame_type { + FRAME_TYPE_CCK = 0, + FRAME_TYPE_OFDM = 1, + FRAME_TYPE_11N = 2, + FRAME_TYPE_11AC = 3 +}; + +typedef struct wl_proxd_status_iovar { + uint16 method; /* method */ + uint8 mode; /* mode */ + uint8 peermode; /* peer mode */ + uint8 state; /* state */ + uint8 reason; /* reason code */ + uint32 distance; /* distance */ + uint32 txcnt; /* tx pkt counter */ + uint32 rxcnt; /* rx pkt counter */ + struct ether_addr peer; /* peer mac address */ + int8 avg_rssi; /* average rssi */ + int8 hi_rssi; /* highest rssi */ + int8 low_rssi; /* lowest rssi */ + uint32 dbgstatus; /* debug status */ + uint16 frame_type_cnt[FRAME_TYPE_NUM]; /* frame types */ + uint8 adj_type_cnt[TOF_ADJ_TYPE_NUM]; /* adj types HW/SW */ +} wl_proxd_status_iovar_t; + +#ifdef NET_DETECT +typedef struct net_detect_adapter_features { + bool wowl_enabled; + bool net_detect_enabled; + bool nlo_enabled; +} net_detect_adapter_features_t; + +typedef enum net_detect_bss_type { + nd_bss_any = 0, + nd_ibss, + nd_ess +} net_detect_bss_type_t; + +typedef struct net_detect_profile { + wlc_ssid_t ssid; + net_detect_bss_type_t bss_type; /* Ignore for now since Phase 1 is only for ESS */ + uint32 cipher_type; /* DOT11_CIPHER_ALGORITHM enumeration values */ + uint32 auth_type; /* DOT11_AUTH_ALGORITHM enumeration values */ +} net_detect_profile_t; + +typedef struct net_detect_profile_list { + uint32 num_nd_profiles; + net_detect_profile_t nd_profile[0]; +} net_detect_profile_list_t; + +typedef struct net_detect_config { + bool nd_enabled; + uint32 scan_interval; + uint32 wait_period; + bool wake_if_connected; + bool wake_if_disconnected; + net_detect_profile_list_t nd_profile_list; +} net_detect_config_t; + +typedef enum net_detect_wake_reason { + nd_reason_unknown, + nd_net_detected, + nd_wowl_event, + nd_ucode_error +} net_detect_wake_reason_t; + +typedef struct net_detect_wake_data { + net_detect_wake_reason_t nd_wake_reason; + uint32 nd_wake_date_length; + uint8 nd_wake_data[0]; /* Wake data (currently unused) */ +} net_detect_wake_data_t; + +#endif /* NET_DETECT */ + +typedef struct bcnreq { + uint8 bcn_mode; + int dur; + int channel; + struct ether_addr da; + uint16 random_int; + wlc_ssid_t ssid; + uint16 reps; +} bcnreq_t; + +typedef struct rrmreq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + uint16 reps; +} rrmreq_t; + +typedef struct framereq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + struct ether_addr ta; + uint16 reps; +} framereq_t; + +typedef struct statreq { + struct ether_addr da; + struct ether_addr peer; + uint16 random_int; + uint16 dur; + uint8 group_id; + uint16 reps; +} statreq_t; + +#define WL_RRM_RPT_VER 0 +#define WL_RRM_RPT_MAX_PAYLOAD 64 +#define WL_RRM_RPT_MIN_PAYLOAD 7 +#define WL_RRM_RPT_FALG_ERR 0 +#define WL_RRM_RPT_FALG_OK 1 +typedef struct { + uint16 ver; /* version */ + struct ether_addr addr; /* STA MAC addr */ + uint32 timestamp; /* timestamp of the report */ + uint16 flag; /* flag */ + uint16 len; /* length of payload data */ + unsigned char data[WL_RRM_RPT_MAX_PAYLOAD]; +} statrpt_t; + +typedef struct wlc_l2keepalive_ol_params { + uint8 flags; + uint8 prio; + uint16 period_ms; +} wlc_l2keepalive_ol_params_t; + +typedef struct wlc_dwds_config { + uint32 enable; + uint32 mode; /* STA/AP interface */ + struct ether_addr ea; +} wlc_dwds_config_t; + +typedef struct wl_el_set_params_s { + uint8 set; /* Set number */ + uint32 size; /* Size to make/expand */ +} wl_el_set_params_t; + +typedef struct wl_el_tag_params_s { + uint16 tag; + uint8 set; + uint8 flags; +} wl_el_tag_params_t; + +/* Video Traffic Interference Monitor config */ +#define INTFER_VERSION 1 +typedef struct wl_intfer_params { + uint16 version; /* version */ + uint8 period; /* sample period */ + uint8 cnt; /* sample cnt */ + uint8 txfail_thresh; /* non-TCP txfail threshold */ + uint8 tcptxfail_thresh; /* tcptxfail threshold */ +} wl_intfer_params_t; + +typedef struct wl_staprio_cfg { + struct ether_addr ea; /* mac addr */ + uint8 prio; /* scb priority */ +} wl_staprio_cfg_t; + +typedef enum wl_stamon_cfg_cmd_type { + STAMON_CFG_CMD_DEL = 0, + STAMON_CFG_CMD_ADD = 1 +} wl_stamon_cfg_cmd_type_t; + +typedef struct wlc_stamon_sta_config { + wl_stamon_cfg_cmd_type_t cmd; /* 0 - delete, 1 - add */ + struct ether_addr ea; +} wlc_stamon_sta_config_t; + +#ifdef SR_DEBUG +typedef struct /* pmu_reg */{ + uint32 pmu_control; + uint32 pmu_capabilities; + uint32 pmu_status; + uint32 res_state; + uint32 res_pending; + uint32 pmu_timer1; + uint32 min_res_mask; + uint32 max_res_mask; + uint32 pmu_chipcontrol1[4]; + uint32 pmu_regcontrol[5]; + uint32 pmu_pllcontrol[5]; + uint32 pmu_rsrc_up_down_timer[31]; + uint32 rsrc_dep_mask[31]; +} pmu_reg_t; +#endif /* pmu_reg */ + +typedef struct wl_taf_define { + struct ether_addr ea; /* STA MAC or 0xFF... */ + uint16 version; /* version */ + uint32 sch; /* method index */ + uint32 prio; /* priority */ + uint32 misc; /* used for return value */ + char text[1]; /* used to pass and return ascii text */ +} wl_taf_define_t; + +/* Received Beacons lengths information */ +#define WL_LAST_BCNS_INFO_FIXED_LEN OFFSETOF(wlc_bcn_len_hist_t, bcnlen_ring) +typedef struct wlc_bcn_len_hist { + uint16 ver; /* version field */ + uint16 cur_index; /* current pointed index in ring buffer */ + uint32 max_bcnlen; /* Max beacon length received */ + uint32 min_bcnlen; /* Min beacon length received */ + uint32 ringbuff_len; /* Length of the ring buffer 'bcnlen_ring' */ + uint32 bcnlen_ring[1]; /* ring buffer storing received beacon lengths */ +} wlc_bcn_len_hist_t; + +/* WDS net interface types */ +#define WL_WDSIFTYPE_NONE 0x0 /* The interface type is neither WDS nor DWDS. */ +#define WL_WDSIFTYPE_WDS 0x1 /* The interface is WDS type. */ +#define WL_WDSIFTYPE_DWDS 0x2 /* The interface is DWDS type. */ + +typedef struct wl_bssload_static { + bool is_static; + uint16 sta_count; + uint8 chan_util; + uint16 aac; +} wl_bssload_static_t; + + +/* LTE coex info */ +/* Analogue of HCI Set MWS Signaling cmd */ +typedef struct { + uint16 mws_rx_assert_offset; + uint16 mws_rx_assert_jitter; + uint16 mws_rx_deassert_offset; + uint16 mws_rx_deassert_jitter; + uint16 mws_tx_assert_offset; + uint16 mws_tx_assert_jitter; + uint16 mws_tx_deassert_offset; + uint16 mws_tx_deassert_jitter; + uint16 mws_pattern_assert_offset; + uint16 mws_pattern_assert_jitter; + uint16 mws_inact_dur_assert_offset; + uint16 mws_inact_dur_assert_jitter; + uint16 mws_scan_freq_assert_offset; + uint16 mws_scan_freq_assert_jitter; + uint16 mws_prio_assert_offset_req; +} wci2_config_t; + +/* Analogue of HCI MWS Channel Params */ +typedef struct { + uint16 mws_rx_center_freq; /* MHz */ + uint16 mws_tx_center_freq; + uint16 mws_rx_channel_bw; /* KHz */ + uint16 mws_tx_channel_bw; + uint8 mws_channel_en; + uint8 mws_channel_type; /* Don't care for WLAN? */ +} mws_params_t; + +/* MWS wci2 message */ +typedef struct { + uint8 mws_wci2_data; /* BT-SIG msg */ + uint16 mws_wci2_interval; /* Interval in us */ + uint16 mws_wci2_repeat; /* No of msgs to send */ +} mws_wci2_msg_t; + +typedef struct { + uint32 config; /* MODE: AUTO (-1), Disable (0), Enable (1) */ + uint32 status; /* Current state: Disabled (0), Enabled (1) */ +} wl_config_t; + +#define WLC_RSDB_MODE_AUTO_MASK 0x80 +#define WLC_RSDB_EXTRACT_MODE(val) ((int8)((val) & (~(WLC_RSDB_MODE_AUTO_MASK)))) + +#define WL_IF_STATS_T_VERSION 1 /* current version of wl_if_stats structure */ + +/* per interface counters */ +typedef struct wl_if_stats { + uint16 version; /* version of the structure */ + uint16 length; /* length of the entire structure */ + uint32 PAD; /* padding */ + + /* transmit stat counters */ + uint64 txframe; /* tx data frames */ + uint64 txbyte; /* tx data bytes */ + uint64 txerror; /* tx data errors (derived: sum of others) */ + uint64 txnobuf; /* tx out of buffer errors */ + uint64 txrunt; /* tx runt frames */ + uint64 txfail; /* tx failed frames */ + uint64 txretry; /* tx retry frames */ + uint64 txretrie; /* tx multiple retry frames */ + uint64 txfrmsnt; /* tx sent frames */ + uint64 txmulti; /* tx mulitcast sent frames */ + uint64 txfrag; /* tx fragments sent */ + + /* receive stat counters */ + uint64 rxframe; /* rx data frames */ + uint64 rxbyte; /* rx data bytes */ + uint64 rxerror; /* rx data errors (derived: sum of others) */ + uint64 rxnobuf; /* rx out of buffer errors */ + uint64 rxrunt; /* rx runt frames */ + uint64 rxfragerr; /* rx fragment errors */ + uint64 rxmulti; /* rx multicast frames */ + + uint64 txexptime; /* DATA Tx frames suppressed due to timer expiration */ + uint64 txrts; /* RTS/CTS succeeeded count */ + uint64 txnocts; /* RTS/CTS faled count */ +} +wl_if_stats_t; + +typedef struct wl_band { + uint16 bandtype; /* WL_BAND_2G, WL_BAND_5G */ + uint16 bandunit; /* bandstate[] index */ + uint16 phytype; /* phytype */ + uint16 phyrev; +} +wl_band_t; + +#define WL_WLC_VERSION_T_VERSION 1 /* current version of wlc_version structure */ + +/* wlc interface version */ +typedef struct wl_wlc_version { + uint16 version; /* version of the structure */ + uint16 length; /* length of the entire structure */ + + /* epi version numbers */ + uint16 epi_ver_major; /* epi major version number */ + uint16 epi_ver_minor; /* epi minor version number */ + uint16 epi_rc_num; /* epi RC number */ + uint16 epi_incr_num; /* epi increment number */ + + /* wlc interface version numbers */ + uint16 wlc_ver_major; /* wlc interface major version number */ + uint16 wlc_ver_minor; /* wlc interface minor version number */ +} +wl_wlc_version_t; + +/* Version of WLC interface to be returned as a part of wl_wlc_version structure. + * For the discussion related to versions update policy refer to + * http://hwnbu-twiki.broadcom.com/bin/view/Mwgroup/WlShimAbstractionLayer + * For now the policy is to increment WLC_VERSION_MAJOR each time + * there is a change that involves both WLC layer and per-port layer. + * WLC_VERSION_MINOR is currently not in use. + */ +#define WLC_VERSION_MAJOR 3 +#define WLC_VERSION_MINOR 0 + + +/* require strict packing */ +#include +#define WL_PROXD_API_VERSION 0x0300 /* version 3.0 */ + +/* proximity detection methods */ +enum { + WL_PROXD_METHOD_NONE = 0, + WL_PROXD_METHOD_RSVD1 = 1, /* backward compatibility - RSSI, not supported */ + WL_PROXD_METHOD_TOF = 2, /* 11v+BCM proprietary */ + WL_PROXD_METHOD_RSVD2 = 3, /* 11v only - if needed */ + WL_PROXD_METHOD_FTM = 4, /* IEEE rev mc/2014 */ + WL_PROXD_METHOD_MAX +}; +typedef int16 wl_proxd_method_t; + +/* global and method configuration flags */ +enum { + WL_PROXD_FLAG_NONE = 0x00000000, + WL_PROXD_FLAG_RX_ENABLED = 0x00000001, /* respond to requests */ + WL_PROXD_FLAG_RX_RANGE_REQ = 0x00000002, /* 11mc range requests enabled */ + WL_PROXD_FLAG_TX_LCI = 0x00000004, /* transmit location, if available */ + WL_PROXD_FLAG_TX_CIVIC = 0x00000008, /* tx civic loc, if available */ + WL_PROXD_FLAG_RX_AUTO_BURST = 0x00000010, /* respond to requests w/o host action */ + WL_PROXD_FLAG_TX_AUTO_BURST = 0x00000020, /* continue requests w/o host action */ + WL_PROXD_FLAG_ALL = 0xffffffff +}; +typedef uint32 wl_proxd_flags_t; + +/* session flags */ +enum { + WL_PROXD_SESSION_FLAG_NONE = 0x00000000, /* no flags */ + WL_PROXD_SESSION_FLAG_INITIATOR = 0x00000001, /* local device is initiator */ + WL_PROXD_SESSION_FLAG_TARGET = 0x00000002, /* local device is target */ + WL_PROXD_SESSION_FLAG_ONE_WAY = 0x00000004, /* (initiated) 1-way rtt */ + WL_PROXD_SESSION_FLAG_AUTO_BURST = 0x00000008, /* created w/ rx_auto_burst */ + WL_PROXD_SESSION_FLAG_PERSIST = 0x00000010, /* good until cancelled */ + WL_PROXD_SESSION_FLAG_RTT_DETAIL = 0x00000020, /* rtt detail in results */ + WL_PROXD_SESSION_FLAG_TOF_COMPAT = 0x00000040, /* TOF compatibility - TBD */ + WL_PROXD_SESSION_FLAG_AOA = 0x00000080, /* AOA along w/ RTT */ + WL_PROXD_SESSION_FLAG_RX_AUTO_BURST = 0x00000100, /* Same as proxd flags above */ + WL_PROXD_SESSION_FLAG_TX_AUTO_BURST = 0x00000200, /* Same as proxd flags above */ + WL_PROXD_SESSION_FLAG_NAN_BSS = 0x00000400, /* Use NAN BSS, if applicable */ + WL_PROXD_SESSION_FLAG_TS1 = 0x00000800, /* e.g. FTM1 - cap or rx */ + WL_PROXD_SESSION_FLAG_REPORT_FAILURE = 0x00002000, /* report failure to target */ + WL_PROXD_SESSION_FLAG_INITIATOR_RPT = 0x00004000, /* report distance to target */ + WL_PROXD_SESSION_FLAG_NOCHANSWT = 0x00008000, /* No channel switching */ + WL_PROXD_SESSION_FLAG_NETRUAL = 0x00010000, /* netrual mode */ + WL_PROXD_SESSION_FLAG_SEQ_EN = 0x00020000, /* Toast */ + WL_PROXD_SESSION_FLAG_NO_PARAM_OVRD = 0x00040000, /* no param override from target */ + WL_PROXD_SESSION_FLAG_ASAP = 0x00080000, /* ASAP session */ + WL_PROXD_SESSION_FLAG_REQ_LCI = 0x00100000, /* transmit LCI req */ + WL_PROXD_SESSION_FLAG_REQ_CIV = 0x00200000, /* transmit civic loc req */ + WL_PROXD_SESSION_FLAG_COLLECT = 0x80000000, /* debug - collect */ + WL_PROXD_SESSION_FLAG_ALL = 0xffffffff +}; +typedef uint32 wl_proxd_session_flags_t; + +/* time units - mc supports up to 0.1ns resolution */ +enum { + WL_PROXD_TMU_TU = 0, /* 1024us */ + WL_PROXD_TMU_SEC = 1, + WL_PROXD_TMU_MILLI_SEC = 2, + WL_PROXD_TMU_MICRO_SEC = 3, + WL_PROXD_TMU_NANO_SEC = 4, + WL_PROXD_TMU_PICO_SEC = 5 +}; +typedef int16 wl_proxd_tmu_t; + +/* time interval e.g. 10ns */ +typedef struct wl_proxd_intvl { + uint32 intvl; + wl_proxd_tmu_t tmu; + uint8 pad[2]; +} wl_proxd_intvl_t; + +/* commands that can apply to proxd, method or a session */ +enum { + WL_PROXD_CMD_NONE = 0, + WL_PROXD_CMD_GET_VERSION = 1, + WL_PROXD_CMD_ENABLE = 2, + WL_PROXD_CMD_DISABLE = 3, + WL_PROXD_CMD_CONFIG = 4, + WL_PROXD_CMD_START_SESSION = 5, + WL_PROXD_CMD_BURST_REQUEST = 6, + WL_PROXD_CMD_STOP_SESSION = 7, + WL_PROXD_CMD_DELETE_SESSION = 8, + WL_PROXD_CMD_GET_RESULT = 9, + WL_PROXD_CMD_GET_INFO = 10, + WL_PROXD_CMD_GET_STATUS = 11, + WL_PROXD_CMD_GET_SESSIONS = 12, + WL_PROXD_CMD_GET_COUNTERS = 13, + WL_PROXD_CMD_CLEAR_COUNTERS = 14, + WL_PROXD_CMD_COLLECT = 15, + WL_PROXD_CMD_TUNE = 16, + WL_PROXD_CMD_DUMP = 17, + WL_PROXD_CMD_START_RANGING = 18, + WL_PROXD_CMD_STOP_RANGING = 19, + WL_PROXD_CMD_GET_RANGING_INFO = 20, + WL_PROXD_CMD_MAX +}; +typedef int16 wl_proxd_cmd_t; + +/* session ids: + * id 0 is reserved + * ids 1..0x7fff - allocated by host/app + * 0x8000-0xffff - allocated by firmware, used for auto/rx + */ +enum { + WL_PROXD_SESSION_ID_GLOBAL = 0 +}; + +#define WL_PROXD_SID_HOST_MAX 0x7fff +#define WL_PROXD_SID_HOST_ALLOC(_sid) ((_sid) > 0 && (_sid) <= WL_PROXD_SID_HOST_MAX) + +/* maximum number sessions that can be allocated, may be less if tunable */ +#define WL_PROXD_MAX_SESSIONS 16 + +typedef uint16 wl_proxd_session_id_t; + +/* status - TBD BCME_ vs proxd status - range reserved for BCME_ */ +enum { + WL_PROXD_E_INCOMPLETE = -1044, + WL_PROXD_E_OVERRIDDEN = -1043, + WL_PROXD_E_ASAP_FAILED = -1042, + WL_PROXD_E_NOTSTARTED = -1041, + WL_PROXD_E_INVALIDAVB = -1040, + WL_PROXD_E_INCAPABLE = -1039, + WL_PROXD_E_MISMATCH = -1038, + WL_PROXD_E_DUP_SESSION = -1037, + WL_PROXD_E_REMOTE_FAIL = -1036, + WL_PROXD_E_REMOTE_INCAPABLE = -1035, + WL_PROXD_E_SCHED_FAIL = -1034, + WL_PROXD_E_PROTO = -1033, + WL_PROXD_E_EXPIRED = -1032, + WL_PROXD_E_TIMEOUT = -1031, + WL_PROXD_E_NOACK = -1030, + WL_PROXD_E_DEFERRED = -1029, + WL_PROXD_E_INVALID_SID = -1028, + WL_PROXD_E_REMOTE_CANCEL = -1027, + WL_PROXD_E_CANCELED = -1026, /* local */ + WL_PROXD_E_INVALID_SESSION = -1025, + WL_PROXD_E_BAD_STATE = -1024, + WL_PROXD_E_ERROR = -1, + WL_PROXD_E_OK = 0 +}; +typedef int32 wl_proxd_status_t; + +/* session states */ +enum { + WL_PROXD_SESSION_STATE_NONE = 0, + WL_PROXD_SESSION_STATE_CREATED = 1, + WL_PROXD_SESSION_STATE_CONFIGURED = 2, + WL_PROXD_SESSION_STATE_STARTED = 3, + WL_PROXD_SESSION_STATE_DELAY = 4, + WL_PROXD_SESSION_STATE_USER_WAIT = 5, + WL_PROXD_SESSION_STATE_SCHED_WAIT = 6, + WL_PROXD_SESSION_STATE_BURST = 7, + WL_PROXD_SESSION_STATE_STOPPING = 8, + WL_PROXD_SESSION_STATE_ENDED = 9, + WL_PROXD_SESSION_STATE_DESTROYING = -1 +}; +typedef int16 wl_proxd_session_state_t; + +/* RTT sample flags */ +enum { + WL_PROXD_RTT_SAMPLE_NONE = 0x00, + WL_PROXD_RTT_SAMPLE_DISCARD = 0x01 +}; +typedef uint8 wl_proxd_rtt_sample_flags_t; + +typedef struct wl_proxd_rtt_sample { + uint8 id; /* id for the sample - non-zero */ + wl_proxd_rtt_sample_flags_t flags; + int16 rssi; + wl_proxd_intvl_t rtt; /* round trip time */ + uint32 ratespec; +} wl_proxd_rtt_sample_t; + +/* result flags */ +enum { + WL_PRXOD_RESULT_FLAG_NONE = 0x0000, + WL_PROXD_RESULT_FLAG_NLOS = 0x0001, /* LOS - if available */ + WL_PROXD_RESULT_FLAG_LOS = 0x0002, /* NLOS - if available */ + WL_PROXD_RESULT_FLAG_FATAL = 0x0004, /* Fatal error during burst */ + WL_PROXD_RESULT_FLAG_ALL = 0xffff +}; +typedef int16 wl_proxd_result_flags_t; + +/* rtt measurement result */ +typedef struct wl_proxd_rtt_result { + wl_proxd_session_id_t sid; + wl_proxd_result_flags_t flags; + wl_proxd_status_t status; + struct ether_addr peer; + wl_proxd_session_state_t state; /* current state */ + union { + wl_proxd_intvl_t retry_after; /* hint for errors */ + wl_proxd_intvl_t burst_duration; /* burst duration */ + } u; + wl_proxd_rtt_sample_t avg_rtt; + uint32 avg_dist; /* 1/256m units */ + uint16 sd_rtt; /* RTT standard deviation */ + uint8 num_valid_rtt; /* valid rtt cnt */ + uint8 num_ftm; /* actual num of ftm cnt */ + uint16 burst_num; /* in a session */ + uint16 num_rtt; /* 0 if no detail */ + wl_proxd_rtt_sample_t rtt[1]; /* variable */ +} wl_proxd_rtt_result_t; + +/* aoa measurement result */ +typedef struct wl_proxd_aoa_result { + wl_proxd_session_id_t sid; + wl_proxd_result_flags_t flags; + wl_proxd_status_t status; + struct ether_addr peer; + wl_proxd_session_state_t state; + uint16 burst_num; + uint8 pad[2]; + /* wl_proxd_aoa_sample_t sample_avg; TBD */ +} BWL_POST_PACKED_STRUCT wl_proxd_aoa_result_t; + +/* global stats */ +typedef struct wl_proxd_counters { + uint32 tx; /* tx frame count */ + uint32 rx; /* rx frame count */ + uint32 burst; /* total number of burst */ + uint32 sessions; /* total number of sessions */ + uint32 max_sessions; /* max concurrency */ + uint32 sched_fail; /* scheduling failures */ + uint32 timeouts; /* timeouts */ + uint32 protoerr; /* protocol errors */ + uint32 noack; /* tx w/o ack */ + uint32 txfail; /* any tx falure */ + uint32 lci_req_tx; /* tx LCI requests */ + uint32 lci_req_rx; /* rx LCI requests */ + uint32 lci_rep_tx; /* tx LCI reports */ + uint32 lci_rep_rx; /* rx LCI reports */ + uint32 civic_req_tx; /* tx civic requests */ + uint32 civic_req_rx; /* rx civic requests */ + uint32 civic_rep_tx; /* tx civic reports */ + uint32 civic_rep_rx; /* rx civic reports */ + uint32 rctx; /* ranging contexts created */ + uint32 rctx_done; /* count of ranging done */ +} wl_proxd_counters_t; + +typedef struct wl_proxd_counters wl_proxd_session_counters_t; + +enum { + WL_PROXD_CAP_NONE = 0x0000, + WL_PROXD_CAP_ALL = 0xffff +}; +typedef int16 wl_proxd_caps_t; + +/* method capabilities */ +enum { + WL_PROXD_FTM_CAP_NONE = 0x0000, + WL_PROXD_FTM_CAP_FTM1 = 0x0001 +}; +typedef uint16 wl_proxd_ftm_caps_t; + +typedef struct BWL_PRE_PACKED_STRUCT wl_proxd_tlv_id_list { + uint16 num_ids; + uint16 ids[1]; +} BWL_POST_PACKED_STRUCT wl_proxd_tlv_id_list_t; + +typedef struct wl_proxd_session_id_list { + uint16 num_ids; + wl_proxd_session_id_t ids[1]; +} wl_proxd_session_id_list_t; + +/* tlvs returned for get_info on ftm method + * configuration: + * proxd flags + * event mask + * debug mask + * session defaults (session tlvs) + * status tlv - not supported for ftm method + * info tlv + */ +typedef struct wl_proxd_ftm_info { + wl_proxd_ftm_caps_t caps; + uint16 max_sessions; + uint16 num_sessions; + uint16 rx_max_burst; +} wl_proxd_ftm_info_t; + +/* tlvs returned for get_info on session + * session config (tlvs) + * session info tlv + */ +typedef struct wl_proxd_ftm_session_info { + uint16 sid; + uint8 bss_index; + uint8 pad; + struct ether_addr bssid; + wl_proxd_session_state_t state; + wl_proxd_status_t status; + uint16 burst_num; +} wl_proxd_ftm_session_info_t; + +typedef struct wl_proxd_ftm_session_status { + uint16 sid; + wl_proxd_session_state_t state; + wl_proxd_status_t status; + uint16 burst_num; +} wl_proxd_ftm_session_status_t; + +/* rrm range request */ +typedef struct wl_proxd_range_req { + uint16 num_repeat; + uint16 init_delay_range; /* in TUs */ + uint8 pad; + uint8 num_nbr; /* number of (possible) neighbors */ + nbr_element_t nbr[1]; +} wl_proxd_range_req_t; + +#define WL_PROXD_LCI_LAT_OFF 0 +#define WL_PROXD_LCI_LONG_OFF 5 +#define WL_PROXD_LCI_ALT_OFF 10 + +#define WL_PROXD_LCI_GET_LAT(_lci, _lat, _lat_err) { \ + unsigned _off = WL_PROXD_LCI_LAT_OFF; \ + _lat_err = (_lci)->data[(_off)] & 0x3f; \ + _lat = (_lci)->data[(_off)+1]; \ + _lat |= (_lci)->data[(_off)+2] << 8; \ + _lat |= (_lci)->data[_(_off)+3] << 16; \ + _lat |= (_lci)->data[(_off)+4] << 24; \ + _lat <<= 2; \ + _lat |= (_lci)->data[(_off)] >> 6; \ +} + +#define WL_PROXD_LCI_GET_LONG(_lci, _lcilong, _long_err) { \ + unsigned _off = WL_PROXD_LCI_LONG_OFF; \ + _long_err = (_lci)->data[(_off)] & 0x3f; \ + _lcilong = (_lci)->data[(_off)+1]; \ + _lcilong |= (_lci)->data[(_off)+2] << 8; \ + _lcilong |= (_lci)->data[_(_off)+3] << 16; \ + _lcilong |= (_lci)->data[(_off)+4] << 24; \ + __lcilong <<= 2; \ + _lcilong |= (_lci)->data[(_off)] >> 6; \ +} + +#define WL_PROXD_LCI_GET_ALT(_lci, _alt_type, _alt, _alt_err) { \ + unsigned _off = WL_PROXD_LCI_ALT_OFF; \ + _alt_type = (_lci)->data[_off] & 0x0f; \ + _alt_err = (_lci)->data[(_off)] >> 4; \ + _alt_err |= ((_lci)->data[(_off)+1] & 0x03) << 4; \ + _alt = (_lci)->data[(_off)+2]; \ + _alt |= (_lci)->data[(_off)+3] << 8; \ + _alt |= (_lci)->data[_(_off)+4] << 16; \ + _alt <<= 6; \ + _alt |= (_lci)->data[(_off) + 1] >> 2; \ +} + +#define WL_PROXD_LCI_VERSION(_lci) ((_lci)->data[15] >> 6) + +/* availability. advertising mechanism bss specific */ +/* availablity flags */ +enum { + WL_PROXD_AVAIL_NONE = 0, + WL_PROXD_AVAIL_NAN_PUBLISHED = 0x0001, + WL_PROXD_AVAIL_SCHEDULED = 0x0002 /* scheduled by proxd */ +}; +typedef int16 wl_proxd_avail_flags_t; + +/* time reference */ +enum { + WL_PROXD_TREF_NONE = 0, + WL_PROXD_TREF_DEV_TSF = 1, + WL_PROXD_TREF_NAN_DW = 2, + WL_PROXD_TREF_TBTT = 3, + WL_PROXD_TREF_MAX /* last entry */ +}; +typedef int16 wl_proxd_time_ref_t; + +/* proxd channel-time slot */ +typedef struct { + wl_proxd_intvl_t start; /* from ref */ + wl_proxd_intvl_t duration; /* from start */ + uint32 chanspec; +} wl_proxd_time_slot_t; + +/* availability. advertising mechanism bss specific */ +typedef struct wl_proxd_avail { + wl_proxd_avail_flags_t flags; /* for query only */ + wl_proxd_time_ref_t time_ref; + uint16 max_slots; /* for query only */ + uint16 num_slots; + wl_proxd_time_slot_t slots[1]; +} wl_proxd_avail_t; + +/* collect support TBD */ + +/* debugging */ +enum { + WL_PROXD_DEBUG_NONE = 0x00000000, + WL_PROXD_DEBUG_LOG = 0x00000001, + WL_PROXD_DEBUG_IOV = 0x00000002, + WL_PROXD_DEBUG_EVENT = 0x00000004, + WL_PROXD_DEBUG_SESSION = 0x00000008, + WL_PROXD_DEBUG_PROTO = 0x00000010, + WL_PROXD_DEBUG_SCHED = 0x00000020, + WL_PROXD_DEBUG_RANGING = 0x00000040, + WL_PROXD_DEBUG_ALL = 0xffffffff +}; +typedef uint32 wl_proxd_debug_mask_t; + +/* tlv IDs - data length 4 bytes unless overridden by type, alignment 32 bits */ +enum { + WL_PROXD_TLV_ID_NONE = 0, + WL_PROXD_TLV_ID_METHOD = 1, + WL_PROXD_TLV_ID_FLAGS = 2, + WL_PROXD_TLV_ID_CHANSPEC = 3, /* note: uint32 */ + WL_PROXD_TLV_ID_TX_POWER = 4, + WL_PROXD_TLV_ID_RATESPEC = 5, + WL_PROXD_TLV_ID_BURST_DURATION = 6, /* intvl - length of burst */ + WL_PROXD_TLV_ID_BURST_PERIOD = 7, /* intvl - between bursts */ + WL_PROXD_TLV_ID_BURST_FTM_SEP = 8, /* intvl - between FTMs */ + WL_PROXD_TLV_ID_BURST_NUM_FTM = 9, /* uint16 - per burst */ + WL_PROXD_TLV_ID_NUM_BURST = 10, /* uint16 */ + WL_PROXD_TLV_ID_FTM_RETRIES = 11, /* uint16 at FTM level */ + WL_PROXD_TLV_ID_BSS_INDEX = 12, /* uint8 */ + WL_PROXD_TLV_ID_BSSID = 13, + WL_PROXD_TLV_ID_INIT_DELAY = 14, /* intvl - optional, non-standalone only */ + WL_PROXD_TLV_ID_BURST_TIMEOUT = 15, /* expect response within - intvl */ + WL_PROXD_TLV_ID_EVENT_MASK = 16, /* interested events - in/out */ + WL_PROXD_TLV_ID_FLAGS_MASK = 17, /* interested flags - in only */ + WL_PROXD_TLV_ID_PEER_MAC = 18, /* mac address of peer */ + WL_PROXD_TLV_ID_FTM_REQ = 19, /* dot11_ftm_req */ + WL_PROXD_TLV_ID_LCI_REQ = 20, + WL_PROXD_TLV_ID_LCI = 21, + WL_PROXD_TLV_ID_CIVIC_REQ = 22, + WL_PROXD_TLV_ID_CIVIC = 23, + WL_PROXD_TLV_ID_AVAIL = 24, + WL_PROXD_TLV_ID_SESSION_FLAGS = 25, + WL_PROXD_TLV_ID_SESSION_FLAGS_MASK = 26, /* in only */ + WL_PROXD_TLV_ID_RX_MAX_BURST = 27, /* uint16 - limit bursts per session */ + WL_PROXD_TLV_ID_RANGING_INFO = 28, /* ranging info */ + WL_PROXD_TLV_ID_RANGING_FLAGS = 29, /* uint16 */ + WL_PROXD_TLV_ID_RANGING_FLAGS_MASK = 30, /* uint16, in only */ + /* 31 - 34 reserved for other feature */ + WL_PROXD_TLV_ID_FTM_REQ_RETRIES = 35, /* uint16 FTM request retries */ + + /* output - 512 + x */ + WL_PROXD_TLV_ID_STATUS = 512, + WL_PROXD_TLV_ID_COUNTERS = 513, + WL_PROXD_TLV_ID_INFO = 514, + WL_PROXD_TLV_ID_RTT_RESULT = 515, + WL_PROXD_TLV_ID_AOA_RESULT = 516, + WL_PROXD_TLV_ID_SESSION_INFO = 517, + WL_PROXD_TLV_ID_SESSION_STATUS = 518, + WL_PROXD_TLV_ID_SESSION_ID_LIST = 519, + + /* debug tlvs can be added starting 1024 */ + WL_PROXD_TLV_ID_DEBUG_MASK = 1024, + WL_PROXD_TLV_ID_COLLECT = 1025, /* output only */ + WL_PROXD_TLV_ID_STRBUF = 1026, + + WL_PROXD_TLV_ID_MAX +}; + +typedef struct wl_proxd_tlv { + uint16 id; + uint16 len; + uint8 data[1]; +} wl_proxd_tlv_t; + +/* proxd iovar - applies to proxd, method or session */ +typedef struct wl_proxd_iov { + uint16 version; + uint16 len; + wl_proxd_cmd_t cmd; + wl_proxd_method_t method; + wl_proxd_session_id_t sid; + uint8 pad[2]; + wl_proxd_tlv_t tlvs[1]; /* variable */ +} wl_proxd_iov_t; + +#define WL_PROXD_IOV_HDR_SIZE OFFSETOF(wl_proxd_iov_t, tlvs) + +/* The following event definitions may move to bcmevent.h, but sharing proxd types + * across needs more invasive changes unrelated to proxd + */ +enum { + WL_PROXD_EVENT_NONE = 0, /* not an event, reserved */ + WL_PROXD_EVENT_SESSION_CREATE = 1, + WL_PROXD_EVENT_SESSION_START = 2, + WL_PROXD_EVENT_FTM_REQ = 3, + WL_PROXD_EVENT_BURST_START = 4, + WL_PROXD_EVENT_BURST_END = 5, + WL_PROXD_EVENT_SESSION_END = 6, + WL_PROXD_EVENT_SESSION_RESTART = 7, + WL_PROXD_EVENT_BURST_RESCHED = 8, /* burst rescheduled - e.g. partial TSF */ + WL_PROXD_EVENT_SESSION_DESTROY = 9, + WL_PROXD_EVENT_RANGE_REQ = 10, + WL_PROXD_EVENT_FTM_FRAME = 11, + WL_PROXD_EVENT_DELAY = 12, + WL_PROXD_EVENT_VS_INITIATOR_RPT = 13, /* (target) rx initiator-report */ + WL_PROXD_EVENT_RANGING = 14, + + WL_PROXD_EVENT_MAX +}; +typedef int16 wl_proxd_event_type_t; + +/* proxd event mask - upto 32 events for now */ +typedef uint32 wl_proxd_event_mask_t; + +#define WL_PROXD_EVENT_MASK_ALL 0xfffffffe +#define WL_PROXD_EVENT_MASK_EVENT(_event_type) (1 << (_event_type)) +#define WL_PROXD_EVENT_ENABLED(_mask, _event_type) (\ + ((_mask) & WL_PROXD_EVENT_MASK_EVENT(_event_type)) != 0) + +/* proxd event - applies to proxd, method or session */ +typedef struct wl_proxd_event { + uint16 version; + uint16 len; + wl_proxd_event_type_t type; + wl_proxd_method_t method; + wl_proxd_session_id_t sid; + uint8 pad[2]; + wl_proxd_tlv_t tlvs[1]; /* variable */ +} wl_proxd_event_t; + +enum { + WL_PROXD_RANGING_STATE_NONE = 0, + WL_PROXD_RANGING_STATE_NOTSTARTED = 1, + WL_PROXD_RANGING_STATE_INPROGRESS = 2, + WL_PROXD_RANGING_STATE_DONE = 3 +}; +typedef int16 wl_proxd_ranging_state_t; + +/* proxd ranging flags */ +enum { + WL_PROXD_RANGING_FLAG_NONE = 0x0000, /* no flags */ + WL_PROXD_RANGING_FLAG_DEL_SESSIONS_ON_STOP = 0x0001, + WL_PROXD_RANGING_FLAG_ALL = 0xffff +}; +typedef uint16 wl_proxd_ranging_flags_t; + +struct wl_proxd_ranging_info { + wl_proxd_status_t status; + wl_proxd_ranging_state_t state; + wl_proxd_ranging_flags_t flags; + uint16 num_sids; + uint16 num_done; +}; +typedef struct wl_proxd_ranging_info wl_proxd_ranging_info_t; + +/* end proxd definitions */ +/* Data returned by the bssload_report iovar. + * This is also the WLC_E_BSS_LOAD event data. + */ +typedef BWL_PRE_PACKED_STRUCT struct wl_bssload { + uint16 sta_count; /* station count */ + uint16 aac; /* available admission capacity */ + uint8 chan_util; /* channel utilization */ +} BWL_POST_PACKED_STRUCT wl_bssload_t; + +/* Maximum number of configurable BSS Load levels. The number of BSS Load + * ranges is always 1 more than the number of configured levels. eg. if + * 3 levels of 10, 20, 30 are configured then this defines 4 load ranges: + * 0-10, 11-20, 21-30, 31-255. A WLC_E_BSS_LOAD event is generated each time + * the utilization level crosses into another range, subject to the rate limit. + */ +#define MAX_BSSLOAD_LEVELS 8 +#define MAX_BSSLOAD_RANGES (MAX_BSSLOAD_LEVELS + 1) + +/* BSS Load event notification configuration. */ +typedef struct wl_bssload_cfg { + uint32 rate_limit_msec; /* # of events posted to application will be limited to + * one per specified period (0 to disable rate limit). + */ + uint8 num_util_levels; /* Number of entries in util_levels[] below */ + uint8 util_levels[MAX_BSSLOAD_LEVELS]; + /* Variable number of BSS Load utilization levels in + * low to high order. An event will be posted each time + * a received beacon's BSS Load IE channel utilization + * value crosses a level. + */ +} wl_bssload_cfg_t; + +/* Multiple roaming profile suport */ +#define WL_MAX_ROAM_PROF_BRACKETS 4 + +#define WL_MAX_ROAM_PROF_VER 0 + +#define WL_ROAM_PROF_NONE (0 << 0) +#define WL_ROAM_PROF_LAZY (1 << 0) +#define WL_ROAM_PROF_NO_CI (1 << 1) +#define WL_ROAM_PROF_SUSPEND (1 << 2) +#define WL_ROAM_PROF_SYNC_DTIM (1 << 6) +#define WL_ROAM_PROF_DEFAULT (1 << 7) /* backward compatible single default profile */ + +typedef struct wl_roam_prof { + int8 roam_flags; /* bit flags */ + int8 roam_trigger; /* RSSI trigger level per profile/RSSI bracket */ + int8 rssi_lower; + int8 roam_delta; + int8 rssi_boost_thresh; /* Min RSSI to qualify for RSSI boost */ + int8 rssi_boost_delta; /* RSSI boost for AP in the other band */ + uint16 nfscan; /* nuber of full scan to start with */ + uint16 fullscan_period; + uint16 init_scan_period; + uint16 backoff_multiplier; + uint16 max_scan_period; +} wl_roam_prof_t; + +typedef struct wl_roam_prof_band { + uint32 band; /* Must be just one band */ + uint16 ver; /* version of this struct */ + uint16 len; /* length in bytes of this structure */ + wl_roam_prof_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS]; +} wl_roam_prof_band_t; + +/* Data structures for Interface Create/Remove */ + +#define WL_INTERFACE_CREATE_VER (0) + +/* + * The flags filed of the wl_interface_create is designed to be + * a Bit Mask. As of now only Bit 0 and Bit 1 are used as mentioned below. + * The rest of the bits can be used, incase we have to provide + * more information to the dongle + */ + +/* + * Bit 0 of flags field is used to inform whether the interface requested to + * be created is STA or AP. + * 0 - Create a STA interface + * 1 - Create an AP interface + */ +#define WL_INTERFACE_CREATE_STA (0 << 0) +#define WL_INTERFACE_CREATE_AP (1 << 0) + +/* + * Bit 1 of flags field is used to inform whether MAC is present in the + * data structure or not. + * 0 - Ignore mac_addr field + * 1 - Use the mac_addr field + */ +#define WL_INTERFACE_MAC_DONT_USE (0 << 1) +#define WL_INTERFACE_MAC_USE (1 << 1) + +typedef struct wl_interface_create { + uint16 ver; /* version of this struct */ + uint32 flags; /* flags that defines the operation */ + struct ether_addr mac_addr; /* Optional Mac address */ +} wl_interface_create_t; + +typedef struct wl_interface_info { + uint16 ver; /* version of this struct */ + struct ether_addr mac_addr; /* MAC address of the interface */ + char ifname[BCM_MSG_IFNAME_MAX]; /* name of interface */ + uint8 bsscfgidx; /* source bsscfg index */ +} wl_interface_info_t; + +/* no default structure packing */ +#include + +#endif /* _wlioctl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/linux_osl.c b/drivers/net/wireless/bcmdhd_bcm4356/linux_osl.c new file mode 100644 index 000000000000..1145a5b10ed8 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/linux_osl.c @@ -0,0 +1,1815 @@ +/* + * Linux OS Independent Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: linux_osl.c 614089 2016-01-21 02:43:09Z $ + */ + +#define LINUX_PORT + +#include +#include +#include +#include + + +#include + +#include +#include +#include +#include + + + +#ifdef BCM_SECURE_DMA +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__ARM_ARCH_7A__) +#include +#include +#endif +#include +#endif /* BCM_SECURE_DMA */ + +#include + + +#define PCI_CFG_RETRY 10 + +#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ +#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ +#define DUMPBUFSZ 1024 + +#ifdef CONFIG_DHD_USE_STATIC_BUF +#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) +#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1) +#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2) +#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4) +#else +#define DHD_SKB_HDRSIZE 336 +#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) +#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) +#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) +#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ + +#define STATIC_BUF_MAX_NUM 16 +#define STATIC_BUF_SIZE (PAGE_SIZE*2) +#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) + +typedef struct bcm_static_buf { + spinlock_t static_lock; + unsigned char *buf_ptr; + unsigned char buf_use[STATIC_BUF_MAX_NUM]; +} bcm_static_buf_t; + +static bcm_static_buf_t *bcm_static_buf = 0; + +#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) +#define STATIC_PKT_4PAGE_NUM 0 +#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE +#elif defined(ENHANCED_STATIC_BUF) +#define STATIC_PKT_4PAGE_NUM 1 +#define DHD_SKB_MAX_BUFSIZE DHD_SKB_4PAGE_BUFSIZE +#else +#define STATIC_PKT_4PAGE_NUM 0 +#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE +#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ + +#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) +#define STATIC_PKT_1PAGE_NUM 0 +#define STATIC_PKT_2PAGE_NUM 64 +#else +#define STATIC_PKT_1PAGE_NUM 8 +#define STATIC_PKT_2PAGE_NUM 8 +#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ + +#define STATIC_PKT_1_2PAGE_NUM \ + ((STATIC_PKT_1PAGE_NUM) + (STATIC_PKT_2PAGE_NUM)) +#define STATIC_PKT_MAX_NUM \ + ((STATIC_PKT_1_2PAGE_NUM) + (STATIC_PKT_4PAGE_NUM)) + +typedef struct bcm_static_pkt { +#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) + struct sk_buff *skb_8k[STATIC_PKT_2PAGE_NUM]; + unsigned char pkt_invalid[STATIC_PKT_2PAGE_NUM]; + spinlock_t osl_pkt_lock; + uint32 last_allocated_index; +#else + struct sk_buff *skb_4k[STATIC_PKT_1PAGE_NUM]; + struct sk_buff *skb_8k[STATIC_PKT_2PAGE_NUM]; +#ifdef ENHANCED_STATIC_BUF + struct sk_buff *skb_16k; +#endif /* ENHANCED_STATIC_BUF */ + struct semaphore osl_pkt_sem; +#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ + unsigned char pkt_use[STATIC_PKT_MAX_NUM]; +} bcm_static_pkt_t; + +static bcm_static_pkt_t *bcm_static_skb = 0; + +void* wifi_platform_prealloc(void *adapter, int section, unsigned long size); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + +typedef struct bcm_mem_link { + struct bcm_mem_link *prev; + struct bcm_mem_link *next; + uint size; + int line; + void *osh; + char file[BCM_MEM_FILENAME_LEN]; +} bcm_mem_link_t; + +struct osl_cmn_info { + atomic_t malloced; + atomic_t pktalloced; /* Number of allocated packet buffers */ + spinlock_t dbgmem_lock; + bcm_mem_link_t *dbgmem_list; + spinlock_t pktalloc_lock; + atomic_t refcount; /* Number of references to this shared structure. */ +}; +typedef struct osl_cmn_info osl_cmn_t; + +struct osl_info { + osl_pubinfo_t pub; +#ifdef CTFPOOL + ctfpool_t *ctfpool; +#endif /* CTFPOOL */ + uint magic; + void *pdev; + uint failed; + uint bustype; + osl_cmn_t *cmn; /* Common OSL related data shred between two OSH's */ + + void *bus_handle; + uint32 flags; /* If specific cases to be handled in the OSL */ +}; + +#define OSL_PKTTAG_CLEAR(p) \ +do { \ + struct sk_buff *s = (struct sk_buff *)(p); \ + ASSERT(OSL_PKTTAG_SZ == 32); \ + *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ + *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ + *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ + *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ +} while (0) + +/* PCMCIA attribute space access macros */ + +/* Global ASSERT type flag */ +uint32 g_assert_type = 0; +module_param(g_assert_type, int, 0); + +static int16 linuxbcmerrormap[] = +{ 0, /* 0 */ + -EINVAL, /* BCME_ERROR */ + -EINVAL, /* BCME_BADARG */ + -EINVAL, /* BCME_BADOPTION */ + -EINVAL, /* BCME_NOTUP */ + -EINVAL, /* BCME_NOTDOWN */ + -EINVAL, /* BCME_NOTAP */ + -EINVAL, /* BCME_NOTSTA */ + -EINVAL, /* BCME_BADKEYIDX */ + -EINVAL, /* BCME_RADIOOFF */ + -EINVAL, /* BCME_NOTBANDLOCKED */ + -EINVAL, /* BCME_NOCLK */ + -EINVAL, /* BCME_BADRATESET */ + -EINVAL, /* BCME_BADBAND */ + -E2BIG, /* BCME_BUFTOOSHORT */ + -E2BIG, /* BCME_BUFTOOLONG */ + -EBUSY, /* BCME_BUSY */ + -EINVAL, /* BCME_NOTASSOCIATED */ + -EINVAL, /* BCME_BADSSIDLEN */ + -EINVAL, /* BCME_OUTOFRANGECHAN */ + -EINVAL, /* BCME_BADCHAN */ + -EFAULT, /* BCME_BADADDR */ + -ENOMEM, /* BCME_NORESOURCE */ + -EOPNOTSUPP, /* BCME_UNSUPPORTED */ + -EMSGSIZE, /* BCME_BADLENGTH */ + -EINVAL, /* BCME_NOTREADY */ + -EPERM, /* BCME_EPERM */ + -ENOMEM, /* BCME_NOMEM */ + -EINVAL, /* BCME_ASSOCIATED */ + -ERANGE, /* BCME_RANGE */ + -EINVAL, /* BCME_NOTFOUND */ + -EINVAL, /* BCME_WME_NOT_ENABLED */ + -EINVAL, /* BCME_TSPEC_NOTFOUND */ + -EINVAL, /* BCME_ACM_NOTSUPPORTED */ + -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ + -EIO, /* BCME_SDIO_ERROR */ + -ENODEV, /* BCME_DONGLE_DOWN */ + -EINVAL, /* BCME_VERSION */ + -EIO, /* BCME_TXFAIL */ + -EIO, /* BCME_RXFAIL */ + -ENODEV, /* BCME_NODEVICE */ + -EINVAL, /* BCME_NMODE_DISABLED */ + -ENODATA, /* BCME_NONRESIDENT */ + -EINVAL, /* BCME_SCANREJECT */ + -EINVAL, /* BCME_USAGE_ERROR */ + -EIO, /* BCME_IOCTL_ERROR */ + -EIO, /* BCME_SERIAL_PORT_ERR */ + -EOPNOTSUPP, /* BCME_DISABLED, BCME_NOTENABLED */ + -EIO, /* BCME_DECERR */ + -EIO, /* BCME_ENCERR */ + -EIO, /* BCME_MICERR */ + -ERANGE, /* BCME_REPLAY */ + -EINVAL, /* BCME_IE_NOTFOUND */ + +/* When an new error code is added to bcmutils.h, add os + * specific error translation here as well + */ +/* check if BCME_LAST changed since the last time this function was updated */ +#if BCME_LAST != -52 +#error "You need to add a OS error translation in the linuxbcmerrormap \ + for new error code defined in bcmutils.h" +#endif +}; +uint lmtest = FALSE; + +/* translate bcmerrors into linux errors */ +int +osl_error(int bcmerror) +{ + if (bcmerror > 0) + bcmerror = 0; + else if (bcmerror < BCME_LAST) + bcmerror = BCME_ERROR; + + /* Array bounds covered by ASSERT in osl_attach */ + return linuxbcmerrormap[-bcmerror]; +} +#ifdef SHARED_OSL_CMN +osl_t * +osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn) +{ +#else +osl_t * +osl_attach(void *pdev, uint bustype, bool pkttag) +{ + void **osl_cmn = NULL; +#endif /* SHARED_OSL_CMN */ + osl_t *osh; + gfp_t flags; + + flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; + if (!(osh = kmalloc(sizeof(osl_t), flags))) + return osh; + + ASSERT(osh); + + bzero(osh, sizeof(osl_t)); + + if (osl_cmn == NULL || *osl_cmn == NULL) { + if (!(osh->cmn = kmalloc(sizeof(osl_cmn_t), flags))) { + kfree(osh); + return NULL; + } + bzero(osh->cmn, sizeof(osl_cmn_t)); + if (osl_cmn) + *osl_cmn = osh->cmn; + atomic_set(&osh->cmn->malloced, 0); + osh->cmn->dbgmem_list = NULL; + spin_lock_init(&(osh->cmn->dbgmem_lock)); + + spin_lock_init(&(osh->cmn->pktalloc_lock)); + + } else { + osh->cmn = *osl_cmn; + } + atomic_add(1, &osh->cmn->refcount); + + /* Check that error map has the right number of entries in it */ + ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); + + osh->failed = 0; + osh->pdev = pdev; + osh->pub.pkttag = pkttag; + osh->bustype = bustype; + osh->magic = OS_HANDLE_MAGIC; + + switch (bustype) { + case PCI_BUS: + case SI_BUS: + case PCMCIA_BUS: + osh->pub.mmbus = TRUE; + break; + case JTAG_BUS: + case SDIO_BUS: + case USB_BUS: + case SPI_BUS: + case RPC_BUS: + osh->pub.mmbus = FALSE; + break; + default: + ASSERT(FALSE); + break; + } + + + + return osh; +} + +int osl_static_mem_init(osl_t *osh, void *adapter) +{ +#ifdef CONFIG_DHD_USE_STATIC_BUF + if (!bcm_static_buf && adapter) { + if (!(bcm_static_buf = (bcm_static_buf_t *)wifi_platform_prealloc(adapter, + 3, STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) { + printk("can not alloc static buf!\n"); + bcm_static_skb = NULL; + ASSERT(osh->magic == OS_HANDLE_MAGIC); + return -ENOMEM; + } + else + printk("alloc static buf at %p!\n", bcm_static_buf); + + + spin_lock_init(&bcm_static_buf->static_lock); + + bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; + } + +#if defined(BCMPCIE) && !defined(DHD_USE_STATIC_IOCTLBUF) + return 0; +#else + if (!bcm_static_skb && adapter) { + int i; + void *skb_buff_ptr = 0; + bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); + skb_buff_ptr = wifi_platform_prealloc(adapter, 4, 0); + if (!skb_buff_ptr) { + printk("cannot alloc static buf!\n"); + bcm_static_buf = NULL; + bcm_static_skb = NULL; + ASSERT(osh->magic == OS_HANDLE_MAGIC); + return -ENOMEM; + } + + bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * + (STATIC_PKT_MAX_NUM)); + for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { + bcm_static_skb->pkt_use[i] = 0; +#ifdef BCMPCIE + bcm_static_skb->pkt_invalid[i] = 0; +#endif /* BCMPCIE */ + } + +#ifdef BCMPCIE + spin_lock_init(&bcm_static_skb->osl_pkt_lock); + bcm_static_skb->last_allocated_index = 0; +#else + sema_init(&bcm_static_skb->osl_pkt_sem, 1); +#endif /* BCMPCIE */ + } +#endif /* BCMPCIE && !DHD_USE_STATIC_IOCTLBUF */ +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + + return 0; +} + +void osl_set_bus_handle(osl_t *osh, void *bus_handle) +{ + osh->bus_handle = bus_handle; +} + +void* osl_get_bus_handle(osl_t *osh) +{ + return osh->bus_handle; +} + +void +osl_detach(osl_t *osh) +{ + if (osh == NULL) + return; + + ASSERT(osh->magic == OS_HANDLE_MAGIC); + atomic_sub(1, &osh->cmn->refcount); + if (atomic_read(&osh->cmn->refcount) == 0) { + kfree(osh->cmn); + } + kfree(osh); +} + +int osl_static_mem_deinit(osl_t *osh, void *adapter) +{ +#ifdef CONFIG_DHD_USE_STATIC_BUF + if (bcm_static_buf) { + bcm_static_buf = 0; + } + if (bcm_static_skb) { + bcm_static_skb = 0; + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + return 0; +} + +static struct sk_buff *osl_alloc_skb(osl_t *osh, unsigned int len) +{ + struct sk_buff *skb; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) + gfp_t flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; +#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_ZONE_DMA) + flags |= GFP_ATOMIC; +#endif + skb = __dev_alloc_skb(len, flags); +#else + skb = dev_alloc_skb(len); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) */ + return skb; +} + +#ifdef CTFPOOL + +#ifdef CTFPOOL_SPINLOCK +#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_irqsave(&(ctfpool)->lock, flags) +#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_irqrestore(&(ctfpool)->lock, flags) +#else +#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_bh(&(ctfpool)->lock) +#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_bh(&(ctfpool)->lock) +#endif /* CTFPOOL_SPINLOCK */ +/* + * Allocate and add an object to packet pool. + */ +void * +osl_ctfpool_add(osl_t *osh) +{ + struct sk_buff *skb; +#ifdef CTFPOOL_SPINLOCK + unsigned long flags; +#endif /* CTFPOOL_SPINLOCK */ + + if ((osh == NULL) || (osh->ctfpool == NULL)) + return NULL; + + CTFPOOL_LOCK(osh->ctfpool, flags); + ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj); + + /* No need to allocate more objects */ + if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) { + CTFPOOL_UNLOCK(osh->ctfpool, flags); + return NULL; + } + + /* Allocate a new skb and add it to the ctfpool */ + skb = osl_alloc_skb(osh, osh->ctfpool->obj_size); + if (skb == NULL) { + printf("%s: skb alloc of len %d failed\n", __FUNCTION__, + osh->ctfpool->obj_size); + CTFPOOL_UNLOCK(osh->ctfpool, flags); + return NULL; + } + + /* Add to ctfpool */ + skb->next = (struct sk_buff *)osh->ctfpool->head; + osh->ctfpool->head = skb; + osh->ctfpool->fast_frees++; + osh->ctfpool->curr_obj++; + + /* Hijack a skb member to store ptr to ctfpool */ + CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool; + + /* Use bit flag to indicate skb from fast ctfpool */ + PKTFAST(osh, skb) = FASTBUF; + + CTFPOOL_UNLOCK(osh->ctfpool, flags); + + return skb; +} + +/* + * Add new objects to the pool. + */ +void +osl_ctfpool_replenish(osl_t *osh, uint thresh) +{ + if ((osh == NULL) || (osh->ctfpool == NULL)) + return; + + /* Do nothing if no refills are required */ + while ((osh->ctfpool->refills > 0) && (thresh--)) { + osl_ctfpool_add(osh); + osh->ctfpool->refills--; + } +} + +/* + * Initialize the packet pool with specified number of objects. + */ +int32 +osl_ctfpool_init(osl_t *osh, uint numobj, uint size) +{ + gfp_t flags; + + flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; + osh->ctfpool = kzalloc(sizeof(ctfpool_t), flags); + ASSERT(osh->ctfpool); + + osh->ctfpool->max_obj = numobj; + osh->ctfpool->obj_size = size; + + spin_lock_init(&osh->ctfpool->lock); + + while (numobj--) { + if (!osl_ctfpool_add(osh)) + return -1; + osh->ctfpool->fast_frees--; + } + + return 0; +} + +/* + * Cleanup the packet pool objects. + */ +void +osl_ctfpool_cleanup(osl_t *osh) +{ + struct sk_buff *skb, *nskb; +#ifdef CTFPOOL_SPINLOCK + unsigned long flags; +#endif /* CTFPOOL_SPINLOCK */ + + if ((osh == NULL) || (osh->ctfpool == NULL)) + return; + + CTFPOOL_LOCK(osh->ctfpool, flags); + + skb = osh->ctfpool->head; + + while (skb != NULL) { + nskb = skb->next; + dev_kfree_skb(skb); + skb = nskb; + osh->ctfpool->curr_obj--; + } + + ASSERT(osh->ctfpool->curr_obj == 0); + osh->ctfpool->head = NULL; + CTFPOOL_UNLOCK(osh->ctfpool, flags); + + kfree(osh->ctfpool); + osh->ctfpool = NULL; +} + +void +osl_ctfpool_stats(osl_t *osh, void *b) +{ + struct bcmstrbuf *bb; + + if ((osh == NULL) || (osh->ctfpool == NULL)) + return; + +#ifdef CONFIG_DHD_USE_STATIC_BUF + if (bcm_static_buf) { + bcm_static_buf = 0; + } + if (bcm_static_skb) { + bcm_static_skb = 0; + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + + bb = b; + + ASSERT((osh != NULL) && (bb != NULL)); + + bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n", + osh->ctfpool->max_obj, osh->ctfpool->obj_size, + osh->ctfpool->curr_obj, osh->ctfpool->refills); + bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n", + osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees, + osh->ctfpool->slow_allocs); +} + +static inline struct sk_buff * +osl_pktfastget(osl_t *osh, uint len) +{ + struct sk_buff *skb; +#ifdef CTFPOOL_SPINLOCK + unsigned long flags; +#endif /* CTFPOOL_SPINLOCK */ + + /* Try to do fast allocate. Return null if ctfpool is not in use + * or if there are no items in the ctfpool. + */ + if (osh->ctfpool == NULL) + return NULL; + + CTFPOOL_LOCK(osh->ctfpool, flags); + if (osh->ctfpool->head == NULL) { + ASSERT(osh->ctfpool->curr_obj == 0); + osh->ctfpool->slow_allocs++; + CTFPOOL_UNLOCK(osh->ctfpool, flags); + return NULL; + } + + if (len > osh->ctfpool->obj_size) { + CTFPOOL_UNLOCK(osh->ctfpool, flags); + return NULL; + } + + ASSERT(len <= osh->ctfpool->obj_size); + + /* Get an object from ctfpool */ + skb = (struct sk_buff *)osh->ctfpool->head; + osh->ctfpool->head = (void *)skb->next; + + osh->ctfpool->fast_allocs++; + osh->ctfpool->curr_obj--; + ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head); + CTFPOOL_UNLOCK(osh->ctfpool, flags); + + /* Init skb struct */ + skb->next = skb->prev = NULL; +#if defined(__ARM_ARCH_7A__) + skb->data = skb->head + NET_SKB_PAD; + skb->tail = skb->head + NET_SKB_PAD; +#else + skb->data = skb->head + 16; + skb->tail = skb->head + 16; +#endif /* __ARM_ARCH_7A__ */ + skb->len = 0; + skb->cloned = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) + skb->list = NULL; +#endif + atomic_set(&skb->users, 1); + + PKTSETCLINK(skb, NULL); + PKTCCLRATTR(skb); + PKTFAST(osh, skb) &= ~(CTFBUF | SKIPCT | CHAINED); + + return skb; +} +#endif /* CTFPOOL */ + +#if defined(BCM_GMAC3) +/* Account for a packet delivered to downstream forwarder. + * Decrement a GMAC forwarder interface's pktalloced count. + */ +void BCMFASTPATH +osl_pkt_tofwder(osl_t *osh, void *skbs, int skb_cnt) +{ + + atomic_sub(skb_cnt, &osh->cmn->pktalloced); +} + +/* Account for a downstream forwarder delivered packet to a WL/DHD driver. + * Increment a GMAC forwarder interface's pktalloced count. + */ +void BCMFASTPATH +osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt) +{ + + + atomic_add(skb_cnt, &osh->cmn->pktalloced); +} + +#endif /* BCM_GMAC3 */ + +/* Convert a driver packet to native(OS) packet + * In the process, packettag is zeroed out before sending up + * IP code depends on skb->cb to be setup correctly with various options + * In our case, that means it should be 0 + */ +struct sk_buff * BCMFASTPATH +osl_pkt_tonative(osl_t *osh, void *pkt) +{ + struct sk_buff *nskb; + + if (osh->pub.pkttag) + OSL_PKTTAG_CLEAR(pkt); + + /* Decrement the packet counter */ + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { + atomic_sub(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced); + + } + return (struct sk_buff *)pkt; +} + +/* Convert a native(OS) packet to driver packet. + * In the process, native packet is destroyed, there is no copying + * Also, a packettag is zeroed out + */ +void * BCMFASTPATH +osl_pkt_frmnative(osl_t *osh, void *pkt) +{ + struct sk_buff *nskb; + + if (osh->pub.pkttag) + OSL_PKTTAG_CLEAR(pkt); + + /* Increment the packet counter */ + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { + atomic_add(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced); + + } + return (void *)pkt; +} + +/* Return a new packet. zero out pkttag */ +void * BCMFASTPATH +osl_pktget(osl_t *osh, uint len) +{ + struct sk_buff *skb; + uchar num = 0; + if (lmtest != FALSE) { + get_random_bytes(&num, sizeof(uchar)); + if ((num + 1) <= (256 * lmtest / 100)) + return NULL; + } + +#ifdef CTFPOOL + /* Allocate from local pool */ + skb = osl_pktfastget(osh, len); + if ((skb != NULL) || ((skb = osl_alloc_skb(osh, len)) != NULL)) { +#else /* CTFPOOL */ + if ((skb = osl_alloc_skb(osh, len))) { +#endif /* CTFPOOL */ + skb->tail += len; + skb->len += len; + skb->priority = 0; + + atomic_inc(&osh->cmn->pktalloced); + } + + return ((void*) skb); +} + +#ifdef CTFPOOL +static inline void +osl_pktfastfree(osl_t *osh, struct sk_buff *skb) +{ + ctfpool_t *ctfpool; +#ifdef CTFPOOL_SPINLOCK + unsigned long flags; +#endif /* CTFPOOL_SPINLOCK */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) + skb->tstamp.tv.sec = 0; +#else + skb->stamp.tv_sec = 0; +#endif + + /* We only need to init the fields that we change */ + skb->dev = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + skb->dst = NULL; +#endif + OSL_PKTTAG_CLEAR(skb); + skb->ip_summed = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + skb_orphan(skb); +#else + skb->destructor = NULL; +#endif + + ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); + ASSERT(ctfpool != NULL); + + /* Add object to the ctfpool */ + CTFPOOL_LOCK(ctfpool, flags); + skb->next = (struct sk_buff *)ctfpool->head; + ctfpool->head = (void *)skb; + + ctfpool->fast_frees++; + ctfpool->curr_obj++; + + ASSERT(ctfpool->curr_obj <= ctfpool->max_obj); + CTFPOOL_UNLOCK(ctfpool, flags); +} +#endif /* CTFPOOL */ + +/* Free the driver packet. Free the tag if present */ +void BCMFASTPATH +osl_pktfree(osl_t *osh, void *p, bool send) +{ + struct sk_buff *skb, *nskb; + if (osh == NULL) + return; + + skb = (struct sk_buff*) p; + + if (send && osh->pub.tx_fn) + osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); + + PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE); + +#ifdef CONFIG_DHD_USE_STATIC_BUF + if (skb && (skb->mac_len == PREALLOC_USED_MAGIC)) { + printk("%s: pkt %p is from static pool\n", + __FUNCTION__, p); + + dump_stack(); + return; + } + + if (skb && (skb->mac_len == PREALLOC_FREE_MAGIC)) { + printk("%s: pkt %p is from static pool and not in used\n", + __FUNCTION__, p); + dump_stack(); + return; + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + + /* perversion: we use skb->next to chain multi-skb packets */ + while (skb) { + nskb = skb->next; + skb->next = NULL; + + + +#ifdef CTFPOOL + if (PKTISFAST(osh, skb)) { + if (atomic_read(&skb->users) == 1) + smp_rmb(); + else if (!atomic_dec_and_test(&skb->users)) + goto next_skb; + osl_pktfastfree(osh, skb); + } else +#endif + { + dev_kfree_skb_any(skb); + } +#ifdef CTFPOOL +next_skb: +#endif + atomic_dec(&osh->cmn->pktalloced); + skb = nskb; + } +} + +#ifdef CONFIG_DHD_USE_STATIC_BUF +void* +osl_pktget_static(osl_t *osh, uint len) +{ + int i = 0; + struct sk_buff *skb; +#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) + unsigned long flags; +#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ + void *p; + + if (!bcm_static_skb) + return osl_pktget(osh, len); + + if (len > DHD_SKB_MAX_BUFSIZE) { + printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len); + p = osl_pktget(osh, len); + return p; + } + +#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) + spin_lock_irqsave(&bcm_static_skb->osl_pkt_lock, flags); + + if (len <= DHD_SKB_2PAGE_BUFSIZE) { + uint32 index; + for (i = 0; i < STATIC_PKT_2PAGE_NUM; i++) { + index = bcm_static_skb->last_allocated_index % STATIC_PKT_2PAGE_NUM; + bcm_static_skb->last_allocated_index++; + if (bcm_static_skb->skb_8k[index] && + bcm_static_skb->pkt_use[index] == 0 && + bcm_static_skb->pkt_invalid[index] == 0) { + break; + } + } + + if ((i != STATIC_PKT_2PAGE_NUM) && + (index >= 0) && (index < STATIC_PKT_2PAGE_NUM)) { + bcm_static_skb->pkt_use[index] = 1; + skb = bcm_static_skb->skb_8k[index]; + skb->data = skb->head + NET_SKB_PAD; + skb->cloned = 0; + skb->priority = 0; +#ifdef NET_SKBUFF_DATA_USES_OFFSET + skb_set_tail_pointer(skb, len); +#else + skb->tail = skb->data + len; +#endif /* NET_SKBUFF_DATA_USES_OFFSET */ + skb->len = len; + skb->mac_len = PREALLOC_USED_MAGIC; + spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); + return skb; + } + } + + spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); + printk("%s: all static pkt in use!\n", __FUNCTION__); + return NULL; +#else + down(&bcm_static_skb->osl_pkt_sem); + + if (len <= DHD_SKB_1PAGE_BUFSIZE) { + for (i = 0; i < STATIC_PKT_1PAGE_NUM; i++) { + if (bcm_static_skb->skb_4k[i] && + bcm_static_skb->pkt_use[i] == 0) { + break; + } + } + + if (i != STATIC_PKT_1PAGE_NUM) { + bcm_static_skb->pkt_use[i] = 1; + + skb = bcm_static_skb->skb_4k[i]; +#ifdef NET_SKBUFF_DATA_USES_OFFSET + skb_set_tail_pointer(skb, len); +#else + skb->tail = skb->data + len; +#endif /* NET_SKBUFF_DATA_USES_OFFSET */ + skb->len = len; + + up(&bcm_static_skb->osl_pkt_sem); + return skb; + } + } + + if (len <= DHD_SKB_2PAGE_BUFSIZE) { + for (i = STATIC_PKT_1PAGE_NUM; i < STATIC_PKT_1_2PAGE_NUM; i++) { + if (bcm_static_skb->skb_8k[i - STATIC_PKT_1PAGE_NUM] && + bcm_static_skb->pkt_use[i] == 0) { + break; + } + } + + if ((i >= STATIC_PKT_1PAGE_NUM) && (i < STATIC_PKT_1_2PAGE_NUM)) { + bcm_static_skb->pkt_use[i] = 1; + skb = bcm_static_skb->skb_8k[i - STATIC_PKT_1PAGE_NUM]; +#ifdef NET_SKBUFF_DATA_USES_OFFSET + skb_set_tail_pointer(skb, len); +#else + skb->tail = skb->data + len; +#endif /* NET_SKBUFF_DATA_USES_OFFSET */ + skb->len = len; + + up(&bcm_static_skb->osl_pkt_sem); + return skb; + } + } + +#if defined(ENHANCED_STATIC_BUF) + if (bcm_static_skb->skb_16k && + bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] == 0) { + bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] = 1; + + skb = bcm_static_skb->skb_16k; +#ifdef NET_SKBUFF_DATA_USES_OFFSET + skb_set_tail_pointer(skb, len); +#else + skb->tail = skb->data + len; +#endif /* NET_SKBUFF_DATA_USES_OFFSET */ + skb->len = len; + + up(&bcm_static_skb->osl_pkt_sem); + return skb; + } +#endif /* ENHANCED_STATIC_BUF */ + up(&bcm_static_skb->osl_pkt_sem); +#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ + + p = osl_pktget(osh, len); + return p; +} + +void +osl_pktfree_static(osl_t *osh, void *p, bool send) +{ + int i; +#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) + struct sk_buff *skb = p; + unsigned long flags; +#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ + + if (!p) { + return; + } + + if (!bcm_static_skb) { + osl_pktfree(osh, p, send); + return; + } + +#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) + spin_lock_irqsave(&bcm_static_skb->osl_pkt_lock, flags); + + for (i = 0; i < STATIC_PKT_2PAGE_NUM; i++) { + if (p == bcm_static_skb->skb_8k[i]) { + if (bcm_static_skb->pkt_invalid[i] != 0) { + printk("%s: static pkt idx %d(%p) is invalid\n", + __FUNCTION__, i, p); + } else if (bcm_static_skb->pkt_use[i] == 0) { + printk("%s: static pkt idx %d(%p) is double free\n", + __FUNCTION__, i, p); + } else { + bcm_static_skb->pkt_use[i] = 0; + } + + if (skb->mac_len != PREALLOC_USED_MAGIC) { + printk("%s: static pkt idx %d(%p) is not in used\n", + __FUNCTION__, i, p); + } + + skb->mac_len = PREALLOC_FREE_MAGIC; + spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); + return; + } + } + + spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); + printk("%s: packet %p does not exist in the pool\n", __FUNCTION__, p); +#else + down(&bcm_static_skb->osl_pkt_sem); + + for (i = 0; i < STATIC_PKT_1PAGE_NUM; i++) { + if (p == bcm_static_skb->skb_4k[i]) { + if (bcm_static_skb->pkt_use[i] == 0) + printk("[WLAN] %s: double free! %d p %p\n", __FUNCTION__, i, p); + bcm_static_skb->pkt_use[i] = 0; + up(&bcm_static_skb->osl_pkt_sem); + return; + } + } + + for (i = STATIC_PKT_1PAGE_NUM; i < STATIC_PKT_1_2PAGE_NUM; i++) { + if (p == bcm_static_skb->skb_8k[i - STATIC_PKT_1PAGE_NUM]) { + if (bcm_static_skb->pkt_use[i] == 0) + printk("[WLAN] %s: double free! %d p %p\n", __FUNCTION__, i, p); + bcm_static_skb->pkt_use[i] = 0; + up(&bcm_static_skb->osl_pkt_sem); + return; + } + } +#ifdef ENHANCED_STATIC_BUF + if (p == bcm_static_skb->skb_16k) { + bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] = 0; + up(&bcm_static_skb->osl_pkt_sem); + return; + } +#endif /* ENHANCED_STATIC_BUF */ + up(&bcm_static_skb->osl_pkt_sem); + osl_pktfree(osh, p, send); +#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ +} + +#if defined(BCMPCIE) && defined(DHD_USE_STATIC_IOCTLBUF) +void +osl_pktinvalidate_static(osl_t *osh, void *p) +{ + int i; + unsigned long flags; + + if (!bcm_static_skb) { + return; + } + + spin_lock_irqsave(&bcm_static_skb->osl_pkt_lock, flags); + for (i = 0; i < STATIC_PKT_2PAGE_NUM; i++) { + if (p == bcm_static_skb->skb_8k[i]) { + bcm_static_skb->pkt_invalid[i] = 1; + bcm_static_skb->pkt_use[i] = 1; + break; + } + } + + if (i == STATIC_PKT_2PAGE_NUM) { + printk("%s: pkt=%p isn't static pkt pool\n", __FUNCTION__, p); + } + spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); +} +#endif /* BCMPCIE && DHD_USE_STATIC_IOCTLBUF */ +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + +uint32 +osl_pci_read_config(osl_t *osh, uint offset, uint size) +{ + uint val = 0; + uint retry = PCI_CFG_RETRY; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + /* only 4byte access supported */ + ASSERT(size == 4); + + do { + pci_read_config_dword(osh->pdev, offset, &val); + if (val != 0xffffffff) + break; + } while (retry--); + + + return (val); +} + +void +osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) +{ + uint retry = PCI_CFG_RETRY; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + /* only 4byte access supported */ + ASSERT(size == 4); + + do { + pci_write_config_dword(osh->pdev, offset, val); + if (offset != PCI_BAR0_WIN) + break; + if (osl_pci_read_config(osh, offset, size) == val) + break; + } while (retry--); + +} + +/* return bus # for the pci device pointed by osh->pdev */ +uint +osl_pci_bus(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + +#if defined(__ARM_ARCH_7A__) && LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35) + return pci_domain_nr(((struct pci_dev *)osh->pdev)->bus); +#else + return ((struct pci_dev *)osh->pdev)->bus->number; +#endif +} + +/* return slot # for the pci device pointed by osh->pdev */ +uint +osl_pci_slot(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + +#if defined(__ARM_ARCH_7A__) && LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35) + return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn) + 1; +#else + return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); +#endif +} + +/* return domain # for the pci device pointed by osh->pdev */ +uint +osl_pcie_domain(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + + return pci_domain_nr(((struct pci_dev *)osh->pdev)->bus); +} + +/* return bus # for the pci device pointed by osh->pdev */ +uint +osl_pcie_bus(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + + return ((struct pci_dev *)osh->pdev)->bus->number; +} + +/* return the pci device pointed by osh->pdev */ +struct pci_dev * +osl_pci_device(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + + return osh->pdev; +} + +static void +osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) +{ +} + +void +osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size) +{ + osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE); +} + +void +osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) +{ + osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); +} + +void * +osl_malloc(osl_t *osh, uint size) +{ + void *addr; + gfp_t flags; + + /* only ASSERT if osh is defined */ + if (osh) + ASSERT(osh->magic == OS_HANDLE_MAGIC); +#ifdef CONFIG_DHD_USE_STATIC_BUF + if (bcm_static_buf) + { + unsigned long irq_flags; + int i = 0; + if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE)) + { + spin_lock_irqsave(&bcm_static_buf->static_lock, irq_flags); + + for (i = 0; i < STATIC_BUF_MAX_NUM; i++) + { + if (bcm_static_buf->buf_use[i] == 0) + break; + } + + if (i == STATIC_BUF_MAX_NUM) + { + spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); + printk("all static buff in use!\n"); + goto original; + } + + bcm_static_buf->buf_use[i] = 1; + spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); + + bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size); + if (osh) + atomic_add(size, &osh->cmn->malloced); + + return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i)); + } + } +original: +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + + flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; + if ((addr = kmalloc(size, flags)) == NULL) { + if (osh) + osh->failed++; + return (NULL); + } + if (osh && osh->cmn) + atomic_add(size, &osh->cmn->malloced); + + return (addr); +} + +void * +osl_mallocz(osl_t *osh, uint size) +{ + void *ptr; + + ptr = osl_malloc(osh, size); + + if (ptr != NULL) { + bzero(ptr, size); + } + + return ptr; +} + +void +osl_mfree(osl_t *osh, void *addr, uint size) +{ +#ifdef CONFIG_DHD_USE_STATIC_BUF + unsigned long flags; + + if (bcm_static_buf) + { + if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr + <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN))) + { + int buf_idx = 0; + + buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE; + + spin_lock_irqsave(&bcm_static_buf->static_lock, flags); + bcm_static_buf->buf_use[buf_idx] = 0; + spin_unlock_irqrestore(&bcm_static_buf->static_lock, flags); + + if (osh && osh->cmn) { + ASSERT(osh->magic == OS_HANDLE_MAGIC); + atomic_sub(size, &osh->cmn->malloced); + } + return; + } + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + if (osh && osh->cmn) { + ASSERT(osh->magic == OS_HANDLE_MAGIC); + + ASSERT(size <= osl_malloced(osh)); + + atomic_sub(size, &osh->cmn->malloced); + } + kfree(addr); +} + +uint +osl_check_memleak(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + if (atomic_read(&osh->cmn->refcount) == 1) + return (atomic_read(&osh->cmn->malloced)); + else + return 0; +} + +uint +osl_malloced(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + return (atomic_read(&osh->cmn->malloced)); +} + +uint +osl_malloc_failed(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + return (osh->failed); +} + + +uint +osl_dma_consistent_align(void) +{ + return (PAGE_SIZE); +} + +void* +osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, dmaaddr_t *pap) +{ + void *va; + uint16 align = (1 << align_bits); + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) + size += align; + *alloced = size; + +#if defined(USE_KMALLOC_FOR_FLOW_RING) && defined(__ARM_ARCH_7A__) + va = kmalloc(size, GFP_ATOMIC | __GFP_ZERO); + if (va) + *pap = (ulong)__virt_to_phys((ulong)va); +#else + { + dma_addr_t pap_lin; + struct pci_dev *hwdev = osh->pdev; +#ifdef PCIE_TX_DEFERRAL + va = dma_alloc_coherent(&hwdev->dev, size, &pap_lin, GFP_KERNEL); +#else + va = dma_alloc_coherent(&hwdev->dev, size, &pap_lin, GFP_ATOMIC); +#endif + *pap = (dmaaddr_t)pap_lin; + } +#endif + + return va; +} + +void +osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + +#if defined(USE_KMALLOC_FOR_FLOW_RING) && defined(__ARM_ARCH_7A__) + kfree(va); +#else + pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); +#endif +} + +dmaaddr_t BCMFASTPATH +osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah) +{ + int dir; + dmaaddr_t ret_addr; + dma_addr_t map_addr; + int ret; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + +#if defined(__ARM_ARCH_7A__) && defined(BCMDMASGLISTOSL) + if (dmah != NULL) { + int32 nsegs, i, totsegs = 0, totlen = 0; + struct scatterlist *sg, _sg[MAX_DMA_SEGS * 2]; + struct sk_buff *skb; + for (skb = (struct sk_buff *)p; skb != NULL; skb = PKTNEXT(osh, skb)) { + sg = &_sg[totsegs]; + if (skb_is_nonlinear(skb)) { + nsegs = skb_to_sgvec(skb, sg, 0, PKTLEN(osh, skb)); + ASSERT((nsegs > 0) && (totsegs + nsegs <= MAX_DMA_SEGS)); + pci_map_sg(osh->pdev, sg, nsegs, dir); + } else { + nsegs = 1; + ASSERT(totsegs + nsegs <= MAX_DMA_SEGS); + sg->page_link = 0; + sg_set_buf(sg, PKTDATA(osh, skb), PKTLEN(osh, skb)); + pci_map_single(osh->pdev, PKTDATA(osh, skb), PKTLEN(osh, skb), dir); + } + totsegs += nsegs; + totlen += PKTLEN(osh, skb); + } + dmah->nsegs = totsegs; + dmah->origsize = totlen; + for (i = 0, sg = _sg; i < totsegs; i++, sg++) { + dmah->segs[i].addr = sg_phys(sg); + dmah->segs[i].length = sg->length; + } + return dmah->segs[0].addr; + } +#endif /* __ARM_ARCH_7A__ && BCMDMASGLISTOSL */ + + + map_addr = pci_map_single(osh->pdev, va, size, dir); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + ret = pci_dma_mapping_error(osh->pdev, map_addr); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 5)) + ret = pci_dma_mapping_error(map_addr); +#else + ret = 0; +#endif + if (ret) { + printk("%s: Failed to map memory\n", __FUNCTION__); + PHYSADDRLOSET(ret_addr, 0); + PHYSADDRHISET(ret_addr, 0); + } else { + PHYSADDRLOSET(ret_addr, map_addr & 0xffffffff); + PHYSADDRHISET(ret_addr, (map_addr >> 32) & 0xffffffff); + } + + return ret_addr; +} + +void BCMFASTPATH +osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) +{ + int dir; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + pci_unmap_single(osh->pdev, (uint32)pa, size, dir); +} + +/* OSL function for CPU relax */ +inline void BCMFASTPATH +osl_cpu_relax(void) +{ + cpu_relax(); +} + + +#if defined(USE_KMALLOC_FOR_FLOW_RING) && defined(__ARM_ARCH_7A__) || \ + defined(CONFIG_ARCH_MSM8994) + +#include + +/* + * Note that its gauranteed that the Ring is cache line aligned, but + * the messages are not. And we see that __dma_inv_range in + * arch/arm64/mm/cache.S invalidates only if the request size is + * cache line aligned. If not, it will Clean and invalidate. + * So we'll better invalidate the whole ring. + * + * Also, the latest Kernel versions invoke cache maintenance operations + * from arch/arm64/mm/dma-mapping.c, __swiotlb_sync_single_for_device + * Only if is_device_dma_coherent returns 0. Since we don't have BSP + * source, assuming that its the case, since we pass NULL for the dev ptr + */ +inline void BCMFASTPATH +osl_cache_flush(void *va, uint size) +{ + /* + * using long for address arithmatic is OK, in linux + * 32 bit its 4 bytes and 64 bit its 8 bytes + */ + unsigned long end_cache_line_start; + unsigned long end_addr; + unsigned long next_cache_line_start; + + end_addr = (unsigned long)va + size; + + /* Start address beyond the cache line we plan to operate */ + end_cache_line_start = (end_addr & ~(L1_CACHE_BYTES - 1)); + next_cache_line_start = end_cache_line_start + L1_CACHE_BYTES; + + /* Align the start address to cache line boundary */ + va = (void *)((unsigned long)va & ~(L1_CACHE_BYTES - 1)); + + /* Ensure that size is also aligned and extends partial line to full */ + size = next_cache_line_start - (unsigned long)va; + + +#ifdef CONFIG_ARM64 + /* + * virt_to_dma is not present in arm64/include/dma-mapping.h + * So have to convert the va to pa first and then get the dma addr + * of the same. + */ + { + phys_addr_t pa; + dma_addr_t dma_addr; + pa = virt_to_phys(va); + dma_addr = phys_to_dma(NULL, pa); + if (size > 0) + dma_sync_single_for_device(OSH_NULL, dma_addr, size, DMA_TX); + } +#else + if (size > 0) + dma_sync_single_for_device(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_TX); +#endif /* !CONFIG_ARM64 */ +} + +inline void BCMFASTPATH +osl_cache_inv(void *va, uint size) +{ + /* + * using long for address arithmatic is OK, in linux + * 32 bit its 4 bytes and 64 bit its 8 bytes + */ + unsigned long end_cache_line_start; + unsigned long end_addr; + unsigned long next_cache_line_start; + + end_addr = (unsigned long)va + size; + + /* Start address beyond the cache line we plan to operate */ + end_cache_line_start = (end_addr & ~(L1_CACHE_BYTES - 1)); + next_cache_line_start = end_cache_line_start + L1_CACHE_BYTES; + + /* Align the start address to cache line boundary */ + va = (void *)((unsigned long)va & ~(L1_CACHE_BYTES - 1)); + + /* Ensure that size is also aligned and extends partial line to full */ + size = next_cache_line_start - (unsigned long)va; + +#ifdef CONFIG_ARM64 + /* + * virt_to_dma is not present in arm64/include/dma-mapping.h + * So have to convert the va to pa first and then get the dma addr + * of the same. + */ + { + phys_addr_t pa; + dma_addr_t dma_addr; + pa = virt_to_phys(va); + dma_addr = phys_to_dma(NULL, pa); + dma_sync_single_for_cpu(OSH_NULL, dma_addr, size, DMA_RX); + } +#else + dma_sync_single_for_cpu(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_RX); +#endif /* !CONFIG_ARM64 */ + +} + +inline void osl_prefetch(const void *ptr) +{ + /* PLD instruction is not applicable in ARM 64. We don't care for now */ +#ifndef CONFIG_ARM64 + __asm__ __volatile__("pld\t%0" :: "o"(*(char *)ptr) : "cc"); +#endif /* !CONFIG_ARM64 */ +} + +int osl_arch_is_coherent(void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) + return 0; +#else + return arch_is_coherent(); +#endif +} +#endif + +#if defined(BCMASSERT_LOG) +void +osl_assert(const char *exp, const char *file, int line) +{ + char tempbuf[256]; + const char *basename; + + basename = strrchr(file, '/'); + /* skip the '/' */ + if (basename) + basename++; + + if (!basename) + basename = file; + +#ifdef BCMASSERT_LOG + snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", + exp, basename, line); + printk("%s", tempbuf); +#endif /* BCMASSERT_LOG */ + + +} +#endif + +void +osl_delay(uint usec) +{ + uint d; + + while (usec > 0) { + d = MIN(usec, 1000); + udelay(d); + usec -= d; + } +} + +void +osl_sleep(uint ms) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + if (ms < 20) + usleep_range(ms*1000, ms*1000 + 1000); + else +#endif + msleep(ms); +} + + + +/* Clone a packet. + * The pkttag contents are NOT cloned. + */ +void * +osl_pktdup(osl_t *osh, void *skb) +{ + void * p; + + ASSERT(!PKTISCHAINED(skb)); + + /* clear the CTFBUF flag if set and map the rest of the buffer + * before cloning. + */ + PKTCTFMAP(osh, skb); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + if ((p = pskb_copy((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) +#else + if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) +#endif + return NULL; + +#ifdef CTFPOOL + if (PKTISFAST(osh, skb)) { + ctfpool_t *ctfpool; + + /* if the buffer allocated from ctfpool is cloned then + * we can't be sure when it will be freed. since there + * is a chance that we will be losing a buffer + * from our pool, we increment the refill count for the + * object to be alloced later. + */ + ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); + ASSERT(ctfpool != NULL); + PKTCLRFAST(osh, p); + PKTCLRFAST(osh, skb); + ctfpool->refills++; + } +#endif /* CTFPOOL */ + + /* Clear PKTC context */ + PKTSETCLINK(p, NULL); + PKTCCLRFLAGS(p); + PKTCSETCNT(p, 1); + PKTCSETLEN(p, PKTLEN(osh, skb)); + + /* skb_clone copies skb->cb.. we don't want that */ + if (osh->pub.pkttag) + OSL_PKTTAG_CLEAR(p); + + /* Increment the packet counter */ + atomic_inc(&osh->cmn->pktalloced); + return (p); +} + + + +/* + * OSLREGOPS specifies the use of osl_XXX routines to be used for register access + */ + +/* + * BINOSL selects the slightly slower function-call-based binary compatible osl. + */ + +uint +osl_pktalloced(osl_t *osh) +{ + if (atomic_read(&osh->cmn->refcount) == 1) + return (atomic_read(&osh->cmn->pktalloced)); + else + return 0; +} + +uint32 +osl_rand(void) +{ + uint32 rand; + + get_random_bytes(&rand, sizeof(rand)); + + return rand; +} + +/* Linux Kernel: File Operations: start */ +void * +osl_os_open_image(char *filename) +{ + struct file *fp; + + fp = filp_open(filename, O_RDONLY, 0); + /* + * 2.6.11 (FC4) supports filp_open() but later revs don't? + * Alternative: + * fp = open_namei(AT_FDCWD, filename, O_RD, 0); + * ??? + */ + if (IS_ERR(fp)) + fp = NULL; + + return fp; +} + +int +osl_os_get_image_block(char *buf, int len, void *image) +{ + struct file *fp = (struct file *)image; + int rdlen; + + if (!image) + return 0; + + rdlen = kernel_read(fp, fp->f_pos, buf, len); + if (rdlen > 0) + fp->f_pos += rdlen; + + return rdlen; +} + +void +osl_os_close_image(void *image) +{ + if (image) + filp_close((struct file *)image, NULL); +} + +int +osl_os_image_size(void *image) +{ + int len = 0, curroffset; + + if (image) { + /* store the current offset */ + curroffset = generic_file_llseek(image, 0, 1); + /* goto end of file to get length */ + len = generic_file_llseek(image, 0, 2); + /* restore back the offset */ + generic_file_llseek(image, curroffset, 0); + } + return len; +} + +/* Linux Kernel: File Operations: end */ + + +/* APIs to set/get specific quirks in OSL layer */ +void +osl_flag_set(osl_t *osh, uint32 mask) +{ + osh->flags |= mask; +} + +bool +osl_is_flag_set(osl_t *osh, uint32 mask) +{ + return (osh->flags & mask); +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/pcie_core.c b/drivers/net/wireless/bcmdhd_bcm4356/pcie_core.c new file mode 100644 index 000000000000..b085f161715f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/pcie_core.c @@ -0,0 +1,88 @@ +/** @file pcie_core.c + * + * Contains PCIe related functions that are shared between different driver models (e.g. firmware + * builds, DHD builds, BMAC builds), in order to avoid code duplication. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: pcie_core.c 444841 2013-12-21 04:32:29Z $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie_core.h" + +/* local prototypes */ + +/* local variables */ + +/* function definitions */ + +#ifdef BCMDRIVER + +void pcie_watchdog_reset(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs) +{ + uint32 val, i, lsc; + uint16 cfg_offset[] = {PCIECFGREG_STATUS_CMD, PCIECFGREG_PM_CSR, + PCIECFGREG_MSI_CAP, PCIECFGREG_MSI_ADDR_L, + PCIECFGREG_MSI_ADDR_H, PCIECFGREG_MSI_DATA, + PCIECFGREG_LINK_STATUS_CTRL2, PCIECFGREG_RBAR_CTRL, + PCIECFGREG_PML1_SUB_CTRL1, PCIECFGREG_REG_BAR2_CONFIG, + PCIECFGREG_REG_BAR3_CONFIG}; + sbpcieregs_t *pcie = NULL; + uint32 origidx = si_coreidx(sih); + + /* Switch to PCIE2 core */ + pcie = (sbpcieregs_t *)si_setcore(sih, PCIE2_CORE_ID, 0); + BCM_REFERENCE(pcie); + ASSERT(pcie != NULL); + + /* Disable/restore ASPM Control to protect the watchdog reset */ + W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); + lsc = R_REG(osh, &sbpcieregs->configdata); + val = lsc & (~PCIE_ASPM_ENAB); + W_REG(osh, &sbpcieregs->configdata, val); + + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, 4); + OSL_DELAY(100000); + + W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); + W_REG(osh, &sbpcieregs->configdata, lsc); + + /* Write configuration registers back to the shadow registers + * cause shadow registers are cleared out after watchdog reset. + */ + for (i = 0; i < ARRAYSIZE(cfg_offset); i++) { + W_REG(osh, &sbpcieregs->configaddr, cfg_offset[i]); + val = R_REG(osh, &sbpcieregs->configdata); + W_REG(osh, &sbpcieregs->configdata, val); + } + si_setcoreidx(sih, origidx); +} + +#endif /* BCMDRIVER */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/sbutils.c b/drivers/net/wireless/bcmdhd_bcm4356/sbutils.c new file mode 100644 index 000000000000..473f8dcc6c92 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/sbutils.c @@ -0,0 +1,1105 @@ +/* + * Misc utility routines for accessing chip-specific features + * of the SiliconBackplane-based Broadcom chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbutils.c 467150 2014-04-02 17:30:43Z $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "siutils_priv.h" + + +/* local prototypes */ +static uint _sb_coreidx(si_info_t *sii, uint32 sba); +static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, + uint ncores); +static uint32 _sb_coresba(si_info_t *sii); +static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); +#define SET_SBREG(sii, r, mask, val) \ + W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) +#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) + +/* sonicsrev */ +#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) +#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT) + +#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr)) +#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v)) +#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v))) +#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v))) + +static uint32 +sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) +{ + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint8 tmp; + uint32 val, intr_val = 0; + + + /* + * compact flash only has 11 bits address, while we needs 12 bits address. + * MEM_SEG will be OR'd with other 11 bits address in hardware, + * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). + * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special + */ + if (PCMCIA(sii)) { + INTR_OFF(sii, intr_val); + tmp = 1; + OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); + sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ + } + + val = R_REG(sii->osh, sbr); + + if (PCMCIA(sii)) { + tmp = 0; + OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); + INTR_RESTORE(sii, intr_val); + } + + return (val); +} + +static void +sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) +{ + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint8 tmp; + volatile uint32 dummy; + uint32 intr_val = 0; + + + /* + * compact flash only has 11 bits address, while we needs 12 bits address. + * MEM_SEG will be OR'd with other 11 bits address in hardware, + * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). + * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special + */ + if (PCMCIA(sii)) { + INTR_OFF(sii, intr_val); + tmp = 1; + OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); + sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ + } + + if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { + dummy = R_REG(sii->osh, sbr); + BCM_REFERENCE(dummy); + W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); + dummy = R_REG(sii->osh, sbr); + BCM_REFERENCE(dummy); + W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); + } else + W_REG(sii->osh, sbr, v); + + if (PCMCIA(sii)) { + tmp = 0; + OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); + INTR_RESTORE(sii, intr_val); + } +} + +uint +sb_coreid(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); +} + +uint +sb_intflag(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + void *corereg; + sbconfig_t *sb; + uint origidx, intflag, intr_val = 0; + + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + corereg = si_setcore(sih, CC_CORE_ID, 0); + ASSERT(corereg != NULL); + sb = REGS2SB(corereg); + intflag = R_SBREG(sii, &sb->sbflagst); + sb_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); + + return intflag; +} + +uint +sb_flag(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK; +} + +void +sb_setint(si_t *sih, int siflag) +{ + si_info_t *sii; + sbconfig_t *sb; + uint32 vec; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + if (siflag == -1) + vec = 0; + else + vec = 1 << siflag; + W_SBREG(sii, &sb->sbintvec, vec); +} + +/* return core index of the core with address 'sba' */ +static uint +_sb_coreidx(si_info_t *sii, uint32 sba) +{ + uint i; + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + for (i = 0; i < sii->numcores; i ++) + if (sba == cores_info->coresba[i]) + return i; + return BADIDX; +} + +/* return core address of the current core */ +static uint32 +_sb_coresba(si_info_t *sii) +{ + uint32 sbaddr; + + + switch (BUSTYPE(sii->pub.bustype)) { + case SI_BUS: { + sbconfig_t *sb = REGS2SB(sii->curmap); + sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0)); + break; + } + + case PCI_BUS: + sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + break; + + case PCMCIA_BUS: { + uint8 tmp = 0; + OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); + sbaddr = (uint32)tmp << 12; + OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); + sbaddr |= (uint32)tmp << 16; + OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); + sbaddr |= (uint32)tmp << 24; + break; + } + +#ifdef BCMSDIO + case SPI_BUS: + case SDIO_BUS: + sbaddr = (uint32)(uintptr)sii->curmap; + break; +#endif + + + default: + sbaddr = BADCOREADDR; + break; + } + + return sbaddr; +} + +uint +sb_corevendor(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); +} + +uint +sb_corerev(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + uint sbidh; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + sbidh = R_SBREG(sii, &sb->sbidhigh); + + return (SBCOREREV(sbidh)); +} + +/* set core-specific control flags */ +void +sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii; + sbconfig_t *sb; + uint32 w; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + ASSERT((val & ~mask) == 0); + + /* mask and set */ + w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | + (val << SBTML_SICF_SHIFT); + W_SBREG(sii, &sb->sbtmstatelow, w); +} + +/* set/clear core-specific control flags */ +uint32 +sb_core_cflags(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii; + sbconfig_t *sb; + uint32 w; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + ASSERT((val & ~mask) == 0); + + /* mask and set */ + if (mask || val) { + w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | + (val << SBTML_SICF_SHIFT); + W_SBREG(sii, &sb->sbtmstatelow, w); + } + + /* return the new value + * for write operation, the following readback ensures the completion of write opration. + */ + return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT); +} + +/* set/clear core-specific status flags */ +uint32 +sb_core_sflags(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii; + sbconfig_t *sb; + uint32 w; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + ASSERT((val & ~mask) == 0); + ASSERT((mask & ~SISF_CORE_BITS) == 0); + + /* mask and set */ + if (mask || val) { + w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) | + (val << SBTMH_SISF_SHIFT); + W_SBREG(sii, &sb->sbtmstatehigh, w); + } + + /* return the new value */ + return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT); +} + +bool +sb_iscoreup(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + return ((R_SBREG(sii, &sb->sbtmstatelow) & + (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == + (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); +} + +/* + * 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 fidleing with interrupts or core switches are needed. + * + * Also, when using pci/pcie, we can optimize away the core switching for pci registers + * and (on newer pci cores) chipcommon registers. + */ +uint +sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) +{ + uint origidx = 0; + uint32 *r = NULL; + uint w; + uint intr_val = 0; + bool fast = FALSE; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + ASSERT(GOODIDX(coreidx)); + ASSERT(regoff < SI_CORE_SIZE); + ASSERT((val & ~mask) == 0); + + if (coreidx >= SI_MAXCORES) + return 0; + + if (BUSTYPE(sii->pub.bustype) == SI_BUS) { + /* If internal bus, we can always get at everything */ + fast = TRUE; + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + + fast = TRUE; + r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (uint32 *)((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 = si_coreidx(&sii->pub); + + /* switch core */ + r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff); + } + ASSERT(r != NULL); + + /* mask and set */ + if (mask || val) { + if (regoff >= SBCONFIGOFF) { + w = (R_SBREG(sii, r) & ~mask) | val; + W_SBREG(sii, r, w); + } else { + w = (R_REG(sii->osh, r) & ~mask) | val; + W_REG(sii->osh, r, w); + } + } + + /* readback */ + if (regoff >= SBCONFIGOFF) + w = R_SBREG(sii, r); + else { + if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) && + (coreidx == SI_CC_IDX) && + (regoff == OFFSETOF(chipcregs_t, watchdog))) { + w = val; + } else + w = R_REG(sii->osh, r); + } + + if (!fast) { + /* restore core index */ + if (origidx != coreidx) + sb_setcoreidx(&sii->pub, origidx); + + INTR_RESTORE(sii, intr_val); + } + + return (w); +} + +/* + * If there is no need for fiddling with interrupts or core switches (typically silicon + * back plane registers, pci registers and chipcommon registers), this function + * returns the register offset on this core to a mapped address. This address can + * be used for W_REG/R_REG directly. + * + * For accessing registers that would need a core switch, this function will return + * NULL. + */ +uint32 * +sb_corereg_addr(si_t *sih, uint coreidx, uint regoff) +{ + uint32 *r = NULL; + bool fast = FALSE; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + ASSERT(GOODIDX(coreidx)); + ASSERT(regoff < SI_CORE_SIZE); + + if (coreidx >= SI_MAXCORES) + return 0; + + if (BUSTYPE(sii->pub.bustype) == SI_BUS) { + /* If internal bus, we can always get at everything */ + fast = TRUE; + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + + fast = TRUE; + r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (uint32 *)((char *)sii->curmap + + ((regoff >= SBCONFIGOFF) ? + PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + + regoff); + } + } + + if (!fast) + return 0; + + return (r); +} + +/* Scan the enumeration space to find all cores starting from the given + * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' + * is the default core address at chip POR time and 'regs' is the virtual + * address that the default core is mapped at. 'ncores' is the number of + * cores expected on bus 'sbba'. It returns the total number of cores + * starting from bus 'sbba', inclusive. + */ +#define SB_MAXBUSES 2 +static uint +_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores) +{ + uint next; + uint ncc = 0; + uint i; + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + if (bus >= SB_MAXBUSES) { + SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus)); + return 0; + } + SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores)); + + /* Scan all cores on the bus starting from core 0. + * Core addresses must be contiguous on each bus. + */ + for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { + cores_info->coresba[next] = sbba + (i * SI_CORE_SIZE); + + /* keep and reuse the initial register mapping */ + if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (cores_info->coresba[next] == sba)) { + SI_VMSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next)); + cores_info->regs[next] = regs; + } + + /* change core to 'next' and read its coreid */ + sii->curmap = _sb_setcoreidx(sii, next); + sii->curidx = next; + + cores_info->coreid[next] = sb_coreid(&sii->pub); + + /* core specific processing... */ + /* chipc provides # cores */ + if (cores_info->coreid[next] == CC_CORE_ID) { + chipcregs_t *cc = (chipcregs_t *)sii->curmap; + uint32 ccrev = sb_corerev(&sii->pub); + + /* determine numcores - this is the total # cores in the chip */ + if (((ccrev == 4) || (ccrev >= 6))) { + ASSERT(cc); + numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> + CID_CC_SHIFT; + } else { + /* Older chips */ + uint chip = CHIPID(sii->pub.chip); + + if (chip == BCM4306_CHIP_ID) /* < 4306c0 */ + numcores = 6; + else if (chip == BCM4704_CHIP_ID) + numcores = 9; + else if (chip == BCM5365_CHIP_ID) + numcores = 7; + else { + SI_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", + chip)); + ASSERT(0); + numcores = 1; + } + } + SI_VMSG(("_sb_scan: there are %u cores in the chip %s\n", numcores, + sii->pub.issim ? "QT" : "")); + } + /* scan bridged SB(s) and add results to the end of the list */ + else if (cores_info->coreid[next] == OCP_CORE_ID) { + sbconfig_t *sb = REGS2SB(sii->curmap); + uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); + uint nsbcc; + + sii->numcores = next + 1; + + if ((nsbba & 0xfff00000) != SI_ENUM_BASE) + continue; + nsbba &= 0xfffff000; + if (_sb_coreidx(sii, nsbba) != BADIDX) + continue; + + nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16; + nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc); + if (sbba == SI_ENUM_BASE) + numcores -= nsbcc; + ncc += nsbcc; + } + } + + SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba)); + + sii->numcores = i + ncc; + return sii->numcores; +} + +/* scan the sb enumerated space to identify all cores */ +void +sb_scan(si_t *sih, void *regs, uint devid) +{ + uint32 origsba; + sbconfig_t *sb; + si_info_t *sii = SI_INFO(sih); + + sb = REGS2SB(sii->curmap); + + sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; + + /* Save the current core info and validate it later till we know + * for sure what is good and what is bad. + */ + origsba = _sb_coresba(sii); + + /* scan all SB(s) starting from SI_ENUM_BASE */ + sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1); +} + +/* + * 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 * +sb_setcoreidx(si_t *sih, uint coreidx) +{ + si_info_t *sii = SI_INFO(sih); + + if (coreidx >= sii->numcores) + return (NULL); + + /* + * If the user has provided an interrupt mask enabled function, + * then assert interrupts are disabled before switching the core. + */ + ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); + + sii->curmap = _sb_setcoreidx(sii, coreidx); + sii->curidx = coreidx; + + return (sii->curmap); +} + +/* This function changes the logical "focus" to the indicated core. + * Return the current core's virtual address. + */ +static void * +_sb_setcoreidx(si_info_t *sii, uint coreidx) +{ + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint32 sbaddr = cores_info->coresba[coreidx]; + void *regs; + + switch (BUSTYPE(sii->pub.bustype)) { + case SI_BUS: + /* map new one */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + regs = cores_info->regs[coreidx]; + break; + + case PCI_BUS: + /* point bar0 window */ + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr); + regs = sii->curmap; + break; + + case PCMCIA_BUS: { + uint8 tmp = (sbaddr >> 12) & 0x0f; + OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); + tmp = (sbaddr >> 16) & 0xff; + OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); + tmp = (sbaddr >> 24) & 0xff; + OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); + regs = sii->curmap; + break; + } +#ifdef BCMSDIO + case SPI_BUS: + case SDIO_BUS: + /* map new one */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = (void *)(uintptr)sbaddr; + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + regs = cores_info->regs[coreidx]; + break; +#endif /* BCMSDIO */ + + + default: + ASSERT(0); + regs = NULL; + break; + } + + return regs; +} + +/* Return the address of sbadmatch0/1/2/3 register */ +static volatile uint32 * +sb_admatch(si_info_t *sii, uint asidx) +{ + sbconfig_t *sb; + volatile uint32 *addrm; + + sb = REGS2SB(sii->curmap); + + switch (asidx) { + case 0: + addrm = &sb->sbadmatch0; + break; + + case 1: + addrm = &sb->sbadmatch1; + break; + + case 2: + addrm = &sb->sbadmatch2; + break; + + case 3: + addrm = &sb->sbadmatch3; + break; + + default: + SI_ERROR(("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx)); + return 0; + } + + return (addrm); +} + +/* Return the number of address spaces in current core */ +int +sb_numaddrspaces(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + /* + 1 because of enumeration space */ + return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1; +} + +/* Return the address of the nth address space in the current core */ +uint32 +sb_addrspace(si_t *sih, uint asidx) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + + return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx)))); +} + +/* Return the size of the nth address space in the current core */ +uint32 +sb_addrspacesize(si_t *sih, uint asidx) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + + return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx)))); +} + + +/* do buffered registers update */ +void +sb_commit(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + + origidx = sii->curidx; + ASSERT(GOODIDX(origidx)); + + INTR_OFF(sii, intr_val); + + /* switch over to chipcommon core if there is one, else use pci */ + if (sii->pub.ccrev != NOREV) { + chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + ASSERT(ccregs != NULL); + + /* do the buffer registers update */ + W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT); + W_REG(sii->osh, &ccregs->broadcastdata, 0x0); + } else + ASSERT(0); + + /* restore core index */ + sb_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); +} + +void +sb_core_disable(si_t *sih, uint32 bits) +{ + si_info_t *sii; + volatile uint32 dummy; + sbconfig_t *sb; + + sii = SI_INFO(sih); + + ASSERT(GOODREGS(sii->curmap)); + sb = REGS2SB(sii->curmap); + + /* if core is already in reset, just return */ + if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET) + return; + + /* if clocks are not enabled, put into reset and return */ + if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0) + goto disable; + + /* set target reject and spin until busy is clear (preserve core-specific bits) */ + OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000); + if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY) + SI_ERROR(("%s: target state still busy\n", __FUNCTION__)); + + if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) { + OR_SBREG(sii, &sb->sbimstate, SBIM_RJ); + dummy = R_SBREG(sii, &sb->sbimstate); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000); + } + + /* set reset and reject while enabling the clocks */ + W_SBREG(sii, &sb->sbtmstatelow, + (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | + SBTML_REJ | SBTML_RESET)); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(10); + + /* don't forget to clear the initiator reject bit */ + if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) + AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ); + +disable: + /* leave reset and reject asserted */ + W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET)); + OSL_DELAY(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 +sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) +{ + si_info_t *sii; + sbconfig_t *sb; + volatile uint32 dummy; + + sii = SI_INFO(sih); + ASSERT(GOODREGS(sii->curmap)); + sb = REGS2SB(sii->curmap); + + /* + * Must do the disable sequence first to work for arbitrary current core state. + */ + sb_core_disable(sih, (bits | resetbits)); + + /* + * Now do the initialization sequence. + */ + + /* set reset while enabling the clock and forcing them on throughout the core */ + W_SBREG(sii, &sb->sbtmstatelow, + (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | + SBTML_RESET)); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + + if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) { + W_SBREG(sii, &sb->sbtmstatehigh, 0); + } + if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) { + AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); + } + + /* clear reset and allow it to propagate throughout the core */ + W_SBREG(sii, &sb->sbtmstatelow, + ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + + /* leave clock enabled */ + W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(1); +} + +/* + * Set the initiator timeout for the "master core". + * The master core is defined to be the core in control + * of the chip and so it issues accesses to non-memory + * locations (Because of dma *any* core can access memeory). + * + * The routine uses the bus to decide who is the master: + * SI_BUS => mips + * JTAG_BUS => chipc + * PCI_BUS => pci or pcie + * PCMCIA_BUS => pcmcia + * SDIO_BUS => pcmcia + * + * This routine exists so callers can disable initiator + * timeouts so accesses to very slow devices like otp + * won't cause an abort. The routine allows arbitrary + * settings of the service and request timeouts, though. + * + * Returns the timeout state before changing it or -1 + * on error. + */ + +#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK) + +uint32 +sb_set_initiator_to(si_t *sih, uint32 to, uint idx) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + uint32 tmp, ret = 0xffffffff; + sbconfig_t *sb; + + + if ((to & ~TO_MASK) != 0) + return ret; + + /* Figure out the master core */ + if (idx == BADIDX) { + switch (BUSTYPE(sii->pub.bustype)) { + case PCI_BUS: + idx = sii->pub.buscoreidx; + break; + case JTAG_BUS: + idx = SI_CC_IDX; + break; + case PCMCIA_BUS: +#ifdef BCMSDIO + case SDIO_BUS: +#endif + idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0); + break; + case SI_BUS: + idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0); + break; + default: + ASSERT(0); + } + if (idx == BADIDX) + return ret; + } + + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + sb = REGS2SB(sb_setcoreidx(sih, idx)); + + tmp = R_SBREG(sii, &sb->sbimconfiglow); + ret = tmp & TO_MASK; + W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to); + + sb_commit(sih); + sb_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); + return ret; +} + +uint32 +sb_base(uint32 admatch) +{ + uint32 base; + uint type; + + type = admatch & SBAM_TYPE_MASK; + ASSERT(type < 3); + + base = 0; + + if (type == 0) { + base = admatch & SBAM_BASE0_MASK; + } else if (type == 1) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + base = admatch & SBAM_BASE1_MASK; + } else if (type == 2) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + base = admatch & SBAM_BASE2_MASK; + } + + return (base); +} + +uint32 +sb_size(uint32 admatch) +{ + uint32 size; + uint type; + + type = admatch & SBAM_TYPE_MASK; + ASSERT(type < 3); + + size = 0; + + if (type == 0) { + size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); + } else if (type == 1) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1); + } else if (type == 2) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1); + } + + return (size); +} + +#if defined(BCMDBG_PHYDUMP) +/* print interesting sbconfig registers */ +void +sb_dumpregs(si_t *sih, struct bcmstrbuf *b) +{ + sbconfig_t *sb; + uint origidx, i, intr_val = 0; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + origidx = sii->curidx; + + INTR_OFF(sii, intr_val); + + for (i = 0; i < sii->numcores; i++) { + sb = REGS2SB(sb_setcoreidx(sih, i)); + + bcm_bprintf(b, "core 0x%x: \n", cores_info->coreid[i]); + + if (sii->pub.socirev > SONICS_2_2) + bcm_bprintf(b, "sbimerrlog 0x%x sbimerrloga 0x%x\n", + sb_corereg(sih, si_coreidx(&sii->pub), SBIMERRLOG, 0, 0), + sb_corereg(sih, si_coreidx(&sii->pub), SBIMERRLOGA, 0, 0)); + + bcm_bprintf(b, "sbtmstatelow 0x%x sbtmstatehigh 0x%x sbidhigh 0x%x " + "sbimstate 0x%x\n sbimconfiglow 0x%x sbimconfighigh 0x%x\n", + R_SBREG(sii, &sb->sbtmstatelow), R_SBREG(sii, &sb->sbtmstatehigh), + R_SBREG(sii, &sb->sbidhigh), R_SBREG(sii, &sb->sbimstate), + R_SBREG(sii, &sb->sbimconfiglow), R_SBREG(sii, &sb->sbimconfighigh)); + } + + sb_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); +} +#endif diff --git a/drivers/net/wireless/bcmdhd_bcm4356/siutils.c b/drivers/net/wireless/bcmdhd_bcm4356/siutils.c new file mode 100644 index 000000000000..6ae7c4c323d2 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/siutils.c @@ -0,0 +1,3047 @@ +/* + * Misc utility routines for accessing chip-specific features + * of the SiliconBackplane-based Broadcom chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: siutils.c 506728 2014-10-07 07:22:45Z $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef BCMSDIO +#include +#include +#include +#include +#include +#include +#endif /* BCMSDIO */ +#include + +#ifdef BCM_SDRBL +#include +#endif /* BCM_SDRBL */ +#ifdef HNDGCI +#include +#endif /* HNDGCI */ + +#include "siutils_priv.h" + +/** + * A set of PMU registers is clocked in the ILP domain, which has an implication on register write + * behavior: if such a register is written, it takes multiple ILP clocks for the PMU block to absorb + * the write. During that time the 'SlowWritePending' bit in the PMUStatus register is set. + */ +#define PMUREGS_ILP_SENSITIVE(regoff) \ + ((regoff) == OFFSETOF(pmuregs_t, pmutimer) || \ + (regoff) == OFFSETOF(pmuregs_t, pmuwatchdog) || \ + (regoff) == OFFSETOF(pmuregs_t, res_req_timer)) + +#define CHIPCREGS_ILP_SENSITIVE(regoff) \ + ((regoff) == OFFSETOF(chipcregs_t, pmutimer) || \ + (regoff) == OFFSETOF(chipcregs_t, pmuwatchdog) || \ + (regoff) == OFFSETOF(chipcregs_t, res_req_timer)) + +/* local prototypes */ +static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, + uint bustype, void *sdh, char **vars, uint *varsz); +static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); +static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, + uint *origidx, void *regs); + + +static bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff); + +#ifdef BCMLTECOEX +static void si_config_gcigpio(si_t *sih, uint32 gci_pos, uint8 gcigpio, + uint8 gpioctl_mask, uint8 gpioctl_val); +#endif /* BCMLTECOEX */ + + + +/* global variable to indicate reservation/release of gpio's */ +static uint32 si_gpioreservation = 0; + +/* global flag to prevent shared resources from being initialized multiple times in si_attach() */ +#ifdef SR_DEBUG +static const uint32 si_power_island_test_array[] = { + 0x0000, 0x0001, 0x0010, 0x0011, + 0x0100, 0x0101, 0x0110, 0x0111, + 0x1000, 0x1001, 0x1010, 0x1011, + 0x1100, 0x1101, 0x1110, 0x1111 +}; +#endif /* SR_DEBUG */ + +int do_4360_pcie2_war = 0; + +/* global kernel resource */ +static si_info_t ksii; +static si_cores_info_t ksii_cores_info; + +/** + * Allocate an si handle. This function may be called multiple times. + * + * devid - pci device id (used to determine chip#) + * osh - opaque OS handle + * regs - virtual address of initial core registers + * bustype - pci/pcmcia/sb/sdio/etc + * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this + * function set 'vars' to NULL, making dereferencing of this parameter undesired. + * varsz - pointer to int to return the size of the vars + */ +si_t * +si_attach(uint devid, osl_t *osh, void *regs, + uint bustype, void *sdh, char **vars, uint *varsz) +{ + si_info_t *sii; + si_cores_info_t *cores_info; + /* alloc si_info_t */ + if ((sii = MALLOCZ(osh, sizeof (si_info_t))) == NULL) { + SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); + return (NULL); + } + + /* alloc si_cores_info_t */ + if ((cores_info = (si_cores_info_t *)MALLOCZ(osh, sizeof (si_cores_info_t))) == NULL) { + SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); + MFREE(osh, sii, sizeof(si_info_t)); + return (NULL); + } + sii->cores_info = cores_info; + + if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { + MFREE(osh, sii, sizeof(si_info_t)); + MFREE(osh, cores_info, sizeof(si_cores_info_t)); + return (NULL); + } + sii->vars = vars ? *vars : NULL; + sii->varsz = varsz ? *varsz : 0; + + return (si_t *)sii; +} + + +static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */ + +/** generic kernel variant of si_attach() */ +si_t * +si_kattach(osl_t *osh) +{ + static bool ksii_attached = FALSE; + si_cores_info_t *cores_info; + + if (!ksii_attached) { + void *regs = NULL; + regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); + cores_info = (si_cores_info_t *)&ksii_cores_info; + ksii.cores_info = cores_info; + + ASSERT(osh); + if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, + SI_BUS, NULL, + osh != SI_OSH ? &(ksii.vars) : NULL, + osh != SI_OSH ? &(ksii.varsz) : NULL) == NULL) { + SI_ERROR(("si_kattach: si_doattach failed\n")); + REG_UNMAP(regs); + return NULL; + } + REG_UNMAP(regs); + + /* save ticks normalized to ms for si_watchdog_ms() */ + if (PMUCTL_ENAB(&ksii.pub)) { + /* based on 32KHz ILP clock */ + wd_msticks = 32; + } else { + wd_msticks = ALP_CLOCK / 1000; + } + + ksii_attached = TRUE; + SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n", + ksii.pub.ccrev, wd_msticks)); + } + + return &ksii.pub; +} + + +static bool +si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) +{ + /* need to set memseg flag for CF card first before any sb registers access */ + if (BUSTYPE(bustype) == PCMCIA_BUS) + sii->memseg = TRUE; + + +#if defined(BCMSDIO) + if (BUSTYPE(bustype) == SDIO_BUS) { + int err; + uint8 clkset; + + /* Try forcing SDIO core to do ALPAvail request only */ + clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); + if (!err) { + uint8 clkval; + + /* If register supported, wait for ALPAvail and then force ALP */ + clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); + if ((clkval & ~SBSDIO_AVBITS) == clkset) { + SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), + PMU_MAX_TRANSITION_DLY); + if (!SBSDIO_ALPAV(clkval)) { + SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", + clkval)); + return FALSE; + } + clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + clkset, &err); + OSL_DELAY(65); + } + } + + /* Also, disable the extra SDIO pull-ups */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); + } + +#endif /* BCMSDIO && BCMDONGLEHOST */ + + return TRUE; +} + +static bool +si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, + uint *origidx, void *regs) +{ + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + bool pci, pcie, pcie_gen2 = FALSE; + uint i; + uint pciidx, pcieidx, pcirev, pcierev; + + cc = si_setcoreidx(&sii->pub, SI_CC_IDX); + ASSERT((uintptr)cc); + + /* get chipcommon rev */ + sii->pub.ccrev = (int)si_corerev(&sii->pub); + + /* get chipcommon chipstatus */ + if (sii->pub.ccrev >= 11) + sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); + + /* get chipcommon capabilites */ + sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); + /* get chipcommon extended capabilities */ + + if (sii->pub.ccrev >= 35) + sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); + + /* get pmu rev and caps */ + if (sii->pub.cccaps & CC_CAP_PMU) { + if (AOB_ENAB(&sii->pub)) { + uint pmucoreidx; + pmuregs_t *pmu; + pmucoreidx = si_findcoreidx(&sii->pub, PMU_CORE_ID, 0); + pmu = si_setcoreidx(&sii->pub, pmucoreidx); + sii->pub.pmucaps = R_REG(sii->osh, &pmu->pmucapabilities); + si_setcoreidx(&sii->pub, SI_CC_IDX); + } else + sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); + + sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; + } + + SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", + sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, + sii->pub.pmucaps)); + + /* figure out bus/orignal core idx */ + sii->pub.buscoretype = NODEV_CORE_ID; + sii->pub.buscorerev = (uint)NOREV; + sii->pub.buscoreidx = BADIDX; + + pci = pcie = FALSE; + pcirev = pcierev = (uint)NOREV; + pciidx = pcieidx = BADIDX; + + for (i = 0; i < sii->numcores; i++) { + uint cid, crev; + + si_setcoreidx(&sii->pub, i); + cid = si_coreid(&sii->pub); + crev = si_corerev(&sii->pub); + + /* Display cores found */ + SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", + i, cid, crev, cores_info->coresba[i], cores_info->regs[i])); + + if (BUSTYPE(bustype) == SI_BUS) { + /* now look at the chipstatus register to figure the pacakge */ + /* for SDIO but downloaded on PCIE dev */ + if (cid == PCIE2_CORE_ID) { + if ((CHIPID(sii->pub.chip) == BCM43602_CHIP_ID) || + ((CHIPID(sii->pub.chip) == BCM4345_CHIP_ID) && + CST4345_CHIPMODE_PCIE(sii->pub.chipst))) { + pcieidx = i; + pcierev = crev; + pcie = TRUE; + pcie_gen2 = TRUE; + } + } + + } + else if (BUSTYPE(bustype) == PCI_BUS) { + if (cid == PCI_CORE_ID) { + pciidx = i; + pcirev = crev; + pci = TRUE; + } else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) { + pcieidx = i; + pcierev = crev; + pcie = TRUE; + if (cid == PCIE2_CORE_ID) + pcie_gen2 = TRUE; + } + } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && + (cid == PCMCIA_CORE_ID)) { + sii->pub.buscorerev = crev; + sii->pub.buscoretype = cid; + sii->pub.buscoreidx = i; + } +#ifdef BCMSDIO + else if (((BUSTYPE(bustype) == SDIO_BUS) || + (BUSTYPE(bustype) == SPI_BUS)) && + ((cid == PCMCIA_CORE_ID) || + (cid == SDIOD_CORE_ID))) { + sii->pub.buscorerev = crev; + sii->pub.buscoretype = cid; + sii->pub.buscoreidx = i; + } +#endif /* BCMSDIO */ + + /* find the core idx before entering this func. */ + if ((savewin && (savewin == cores_info->coresba[i])) || + (regs == cores_info->regs[i])) + *origidx = i; + } + + +#if defined(PCIE_FULL_DONGLE) + if (pcie) { + if (pcie_gen2) + sii->pub.buscoretype = PCIE2_CORE_ID; + else + sii->pub.buscoretype = PCIE_CORE_ID; + sii->pub.buscorerev = pcierev; + sii->pub.buscoreidx = pcieidx; + } + BCM_REFERENCE(pci); + BCM_REFERENCE(pcirev); + BCM_REFERENCE(pciidx); +#else + if (pci) { + sii->pub.buscoretype = PCI_CORE_ID; + sii->pub.buscorerev = pcirev; + sii->pub.buscoreidx = pciidx; + } else if (pcie) { + if (pcie_gen2) + sii->pub.buscoretype = PCIE2_CORE_ID; + else + sii->pub.buscoretype = PCIE_CORE_ID; + sii->pub.buscorerev = pcierev; + sii->pub.buscoreidx = pcieidx; + } +#endif /* defined(PCIE_FULL_DONGLE) */ + + SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, + sii->pub.buscorerev)); + + if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && + (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3)) + OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); + + +#if defined(BCMSDIO) + /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was + * already running. + */ + if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { + if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || + si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) + si_core_disable(&sii->pub, 0); + } +#endif /* BCMSDIO && BCMDONGLEHOST */ + + /* return to the original core */ + si_setcoreidx(&sii->pub, *origidx); + + return TRUE; +} + + + + +uint16 +si_chipid(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + + return (sii->chipnew) ? sii->chipnew : sih->chip; +} + +static void +si_chipid_fixup(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + + ASSERT(sii->chipnew == 0); + switch (sih->chip) { + case BCM43570_CHIP_ID: + case BCM4358_CHIP_ID: + sii->chipnew = sih->chip; /* save it */ + sii->pub.chip = BCM43569_CHIP_ID; /* chip class */ + break; + case BCM4356_CHIP_ID: + sii->chipnew = sih->chip; /* save it */ + sii->pub.chip = BCM4354_CHIP_ID; /* chip class */ + break; + default: + ASSERT(0); + break; + } +} + +/** + * Allocate an si handle. This function may be called multiple times. + * + * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this + * function set 'vars' to NULL. + */ +static si_info_t * +si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, + uint bustype, void *sdh, char **vars, uint *varsz) +{ + struct si_pub *sih = &sii->pub; + uint32 w, savewin; + chipcregs_t *cc; + char *pvars = NULL; + uint origidx; +#if !defined(_CFEZ_) || defined(CFG_WL) +#endif + + ASSERT(GOODREGS(regs)); + + savewin = 0; + + sih->buscoreidx = BADIDX; + + sii->curmap = regs; + sii->sdh = sdh; + sii->osh = osh; + + + /* check to see if we are a si core mimic'ing a pci core */ + if ((bustype == PCI_BUS) && + (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(uint32)) == 0xffffffff)) { + SI_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SI " + "devid:0x%x\n", __FUNCTION__, devid)); + bustype = SI_BUS; + } + + /* find Chipcommon address */ + if (bustype == PCI_BUS) { + savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) + savewin = SI_ENUM_BASE; + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); + if (!regs) + return NULL; + cc = (chipcregs_t *)regs; +#ifdef BCMSDIO + } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { + cc = (chipcregs_t *)sii->curmap; +#endif + } else { + cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); + } + + sih->bustype = bustype; + if (bustype != BUSTYPE(bustype)) { + SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", + bustype, BUSTYPE(bustype))); + return NULL; + } + + /* bus/core/clk setup for register access */ + if (!si_buscore_prep(sii, bustype, devid, sdh)) { + SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); + 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. + */ + if (!cc) { + SI_ERROR(("%s: chipcommon register space is null \n", __FUNCTION__)); + return NULL; + } +#ifdef COSTOMER_HW4 +#ifdef CONFIG_MACH_UNIVERSAL5433 + /* old revision check */ + if (!check_rev()) { + /* abnormal link status */ + if (!check_pcie_link_status()) { + printk("%s : PCIE LINK is abnormal status\n", __FUNCTION__); + return NULL; + } + } +#endif /* CONFIG_MACH_UNIVERSAL5433 */ +#endif + w = R_REG(osh, &cc->chipid); + if ((w & 0xfffff) == 148277) w -= 65532; + sih->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; + + if ((sih->chip == BCM4358_CHIP_ID) || + (sih->chip == BCM43570_CHIP_ID) || + (sih->chip == BCM4358_CHIP_ID)) { + si_chipid_fixup(sih); + } + + if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && + (sih->chippkg != BCM4329_289PIN_PKG_ID)) { + sih->chippkg = BCM4329_182PIN_PKG_ID; + } + sih->issim = IS_SIM(sih->chippkg); + + /* scan for cores */ + if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { + SI_MSG(("Found chip type SB (0x%08x)\n", w)); + sb_scan(&sii->pub, regs, devid); + } else if ((CHIPTYPE(sii->pub.socitype) == SOCI_AI) || + (CHIPTYPE(sii->pub.socitype) == SOCI_NAI)) { + if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) + SI_MSG(("Found chip type AI (0x%08x)\n", w)); + else + SI_MSG(("Found chip type NAI (0x%08x)\n", w)); + /* pass chipc address instead of original core base */ + ai_scan(&sii->pub, (void *)(uintptr)cc, devid); + } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { + SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip)); + /* pass chipc address instead of original core base */ + ub_scan(&sii->pub, (void *)(uintptr)cc, devid); + } else { + SI_ERROR(("Found chip of unknown type (0x%08x)\n", w)); + return NULL; + } + /* no cores found, bail out */ + if (sii->numcores == 0) { + SI_ERROR(("si_doattach: could not find any cores\n")); + return NULL; + } + /* bus/core/clk setup */ + origidx = SI_CC_IDX; + if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { + SI_ERROR(("si_doattach: si_buscore_setup failed\n")); + goto exit; + } + +#if !defined(_CFEZ_) || defined(CFG_WL) + if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) + >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | + CST4322_SPROM_PRESENT))) { + SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__)); + return NULL; + } + + /* assume current core is CC */ + if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || + CHIPID(sih->chip) == BCM43235_CHIP_ID || + CHIPID(sih->chip) == BCM43234_CHIP_ID || + CHIPID(sih->chip) == BCM43238_CHIP_ID) && + (CHIPREV(sii->pub.chiprev) <= 2))) { + + if ((cc->chipstatus & CST43236_BP_CLK) != 0) { + uint clkdiv; + clkdiv = R_REG(osh, &cc->clkdiv); + /* otp_clk_div is even number, 120/14 < 9mhz */ + clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); + W_REG(osh, &cc->clkdiv, clkdiv); + SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv)); + } + OSL_DELAY(10); + } + + if (bustype == PCI_BUS) { + + } +#endif +#ifdef BCM_SDRBL + /* 4360 rom bootloader in PCIE case, if the SDR is enabled, But preotection is + * not turned on, then we want to hold arm in reset. + * Bottomline: In sdrenable case, we allow arm to boot only when protection is + * turned on. + */ + if (CHIP_HOSTIF_PCIE(&(sii->pub))) { + uint32 sflags = si_arm_sflags(&(sii->pub)); + + /* If SDR is enabled but protection is not turned on + * then we want to force arm to WFI. + */ + if ((sflags & (SISF_SDRENABLE | SISF_TCMPROT)) == SISF_SDRENABLE) { + disable_arm_irq(); + while (1) { + hnd_cpu_wait(sih); + } + } + } +#endif /* BCM_SDRBL */ + + pvars = NULL; + BCM_REFERENCE(pvars); + + + + if (sii->pub.ccrev >= 20) { + uint32 gpiopullup = 0, gpiopulldown = 0; + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + ASSERT(cc != NULL); + + /* 4314/43142 has pin muxing, don't clear gpio bits */ + if ((CHIPID(sih->chip) == BCM4314_CHIP_ID) || + (CHIPID(sih->chip) == BCM43142_CHIP_ID)) { + gpiopullup |= 0x402e0; + gpiopulldown |= 0x20500; + } + + W_REG(osh, &cc->gpiopullup, gpiopullup); + W_REG(osh, &cc->gpiopulldown, gpiopulldown); + si_setcoreidx(sih, origidx); + } + + + /* clear any previous epidiag-induced target abort */ + ASSERT(!si_taclear(sih, FALSE)); + + +#ifdef BOOTLOADER_CONSOLE_OUTPUT + /* Enable console prints */ + si_muxenab(sii, 3); +#endif + + return (sii); + +exit: + + return NULL; +} + +/** may be called with core in reset */ +void +si_detach(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint idx; + + + if (BUSTYPE(sih->bustype) == SI_BUS) + for (idx = 0; idx < SI_MAXCORES; idx++) + if (cores_info->regs[idx]) { + REG_UNMAP(cores_info->regs[idx]); + cores_info->regs[idx] = NULL; + } + + +#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) + if (cores_info != &ksii_cores_info) +#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ + MFREE(sii->osh, cores_info, sizeof(si_cores_info_t)); + +#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) + if (sii != &ksii) +#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ + MFREE(sii->osh, sii, sizeof(si_info_t)); +} + +void * +si_osh(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + return sii->osh; +} + +void +si_setosh(si_t *sih, osl_t *osh) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + if (sii->osh != NULL) { + SI_ERROR(("osh is already set....\n")); + ASSERT(!sii->osh); + } + sii->osh = osh; +} + +/** register driver interrupt disabling and restoring callback functions */ +void +si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, + void *intrsenabled_fn, void *intr_arg) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + sii->intr_arg = intr_arg; + sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn; + sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn; + sii->intrsenabled_fn = (si_intrsenabled_t)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 = cores_info->coreid[sii->curidx]; +} + +void +si_deregister_intr_callback(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + sii->intrsoff_fn = NULL; + sii->intrsrestore_fn = NULL; + sii->intrsenabled_fn = NULL; +} + +uint +si_intflag(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_intflag(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return R_REG(sii->osh, ((uint32 *)(uintptr) + (sii->oob_router + OOB_STATUSA))); + else { + ASSERT(0); + return 0; + } +} + +uint +si_flag(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_flag(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_flag(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_flag(sih); + else { + ASSERT(0); + return 0; + } +} + +uint +si_flag_alt(si_t *sih) +{ + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_flag_alt(sih); + else { + ASSERT(0); + return 0; + } +} + +void +si_setint(si_t *sih, int siflag) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + sb_setint(sih, siflag); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_setint(sih, siflag); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_setint(sih, siflag); + else + ASSERT(0); +} + +uint +si_coreid(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + return cores_info->coreid[sii->curidx]; +} + +uint +si_coreidx(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + return sii->curidx; +} + +void * +si_d11_switch_addrbase(si_t *sih, uint coreunit) +{ + return si_setcore(sih, D11_CORE_ID, coreunit); +} + +/** return the core-type instantiation # of the current core */ +uint +si_coreunit(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint idx; + uint coreid; + uint coreunit; + uint i; + + coreunit = 0; + + idx = sii->curidx; + + ASSERT(GOODREGS(sii->curmap)); + coreid = si_coreid(sih); + + /* count the cores of our type */ + for (i = 0; i < idx; i++) + if (cores_info->coreid[i] == coreid) + coreunit++; + + return (coreunit); +} + +uint +si_corevendor(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_corevendor(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_corevendor(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_corevendor(sih); + else { + ASSERT(0); + return 0; + } +} + +bool +si_backplane64(si_t *sih) +{ + return ((sih->cccaps & CC_CAP_BKPLN64) != 0); +} + +uint +si_corerev(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_corerev(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_corerev(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_corerev(sih); + else { + ASSERT(0); + return 0; + } +} + + +/* return index of coreid or BADIDX if not found */ +uint +si_findcoreidx(si_t *sih, uint coreid, uint coreunit) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint found; + uint i; + + + found = 0; + + for (i = 0; i < sii->numcores; i++) + if (cores_info->coreid[i] == coreid) { + if (found == coreunit) + return (i); + found++; + } + + return (BADIDX); +} + +/** return total coreunit of coreid or zero if not found */ +uint +si_numcoreunits(si_t *sih, uint coreid) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint found = 0; + uint i; + + for (i = 0; i < sii->numcores; i++) { + if (cores_info->coreid[i] == coreid) { + found++; + } + } + + return found; +} + +/** return total D11 coreunits */ +uint +BCMRAMFN(si_numd11coreunits)(si_t *sih) +{ + uint found = 0; + + found = si_numcoreunits(sih, D11_CORE_ID); + +#if defined(WLRSDB) && defined(WLRSDB_DISABLED) + /* If RSDB functionality is compiled out, + * then ignore any D11 cores beyond the first + * Used in norsdb dongle build variants for rsdb chip. + */ + found = 1; +#endif /* defined(WLRSDB) && !defined(WLRSDB_DISABLED) */ + + return found; +} + +/** return list of found cores */ +uint +si_corelist(si_t *sih, uint coreid[]) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + bcopy((uchar*)cores_info->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); + return (sii->numcores); +} + +/** return current wrapper mapping */ +void * +si_wrapperregs(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + ASSERT(GOODREGS(sii->curwrap)); + + return (sii->curwrap); +} + +/** return current register mapping */ +void * +si_coreregs(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + ASSERT(GOODREGS(sii->curmap)); + + return (sii->curmap); +} + +/** + * 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 * +si_setcore(si_t *sih, uint coreid, uint coreunit) +{ + uint idx; + + idx = si_findcoreidx(sih, coreid, coreunit); + if (!GOODIDX(idx)) + return (NULL); + + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_setcoreidx(sih, idx); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_setcoreidx(sih, idx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_setcoreidx(sih, idx); + else { + ASSERT(0); + return NULL; + } +} + +void * +si_setcoreidx(si_t *sih, uint coreidx) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_setcoreidx(sih, coreidx); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_setcoreidx(sih, coreidx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_setcoreidx(sih, coreidx); + else { + ASSERT(0); + return NULL; + } +} + +/** Turn off interrupt as required by sb_setcore, before switch core */ +void * +si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) +{ + void *cc; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + 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 (void *)CCREGS_FAST(sii); + else if (coreid == sih->buscoretype) + return (void *)PCIEREGS(sii); + } + INTR_OFF(sii, *intr_val); + *origidx = sii->curidx; + cc = si_setcore(sih, coreid, 0); + ASSERT(cc != NULL); + + return cc; +} + +/* restore coreidx and restore interrupt */ +void +si_restore_core(si_t *sih, uint coreid, uint intr_val) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) + return; + + si_setcoreidx(sih, coreid); + INTR_RESTORE(sii, intr_val); +} + +int +si_numaddrspaces(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_numaddrspaces(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_numaddrspaces(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_numaddrspaces(sih); + else { + ASSERT(0); + return 0; + } +} + +uint32 +si_addrspace(si_t *sih, uint asidx) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_addrspace(sih, asidx); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_addrspace(sih, asidx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_addrspace(sih, asidx); + else { + ASSERT(0); + return 0; + } +} + +uint32 +si_addrspacesize(si_t *sih, uint asidx) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_addrspacesize(sih, asidx); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_addrspacesize(sih, asidx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_addrspacesize(sih, asidx); + else { + ASSERT(0); + return 0; + } +} + +void +si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) +{ + /* Only supported for SOCI_AI */ + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_coreaddrspaceX(sih, asidx, addr, size); + else + *size = 0; +} + +uint32 +si_core_cflags(si_t *sih, uint32 mask, uint32 val) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_core_cflags(sih, mask, val); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_core_cflags(sih, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_core_cflags(sih, mask, val); + else { + ASSERT(0); + return 0; + } +} + +void +si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + sb_core_cflags_wo(sih, mask, val); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_core_cflags_wo(sih, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_core_cflags_wo(sih, mask, val); + else + ASSERT(0); +} + +uint32 +si_core_sflags(si_t *sih, uint32 mask, uint32 val) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_core_sflags(sih, mask, val); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_core_sflags(sih, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_core_sflags(sih, mask, val); + else { + ASSERT(0); + return 0; + } +} + +bool +si_iscoreup(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_iscoreup(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_iscoreup(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_iscoreup(sih); + else { + ASSERT(0); + return FALSE; + } +} + +uint +si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) +{ + /* only for AI back plane chips */ + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return (ai_wrap_reg(sih, offset, mask, val)); + return 0; +} + +uint +si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_corereg(sih, coreidx, regoff, mask, val); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_corereg(sih, coreidx, regoff, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_corereg(sih, coreidx, regoff, mask, val); + else { + ASSERT(0); + return 0; + } +} + +/** ILP sensitive register access needs special treatment to avoid backplane stalls */ +bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff) +{ + if (idx == SI_CC_IDX) { + if (CHIPCREGS_ILP_SENSITIVE(regoff)) + return TRUE; + } else if (PMUREGS_ILP_SENSITIVE(regoff)) { + return TRUE; + } + + return FALSE; +} + +/** 'idx' should refer either to the chipcommon core or the PMU core */ +uint +si_pmu_corereg(si_t *sih, uint32 idx, uint regoff, uint mask, uint val) +{ + int pmustatus_offset; + + /* prevent backplane stall on double write to 'ILP domain' registers in the PMU */ + if (mask != 0 && sih->pmurev >= 22 && + si_pmu_is_ilp_sensitive(idx, regoff)) { + pmustatus_offset = AOB_ENAB(sih) ? OFFSETOF(pmuregs_t, pmustatus) : + OFFSETOF(chipcregs_t, pmustatus); + + while (si_corereg(sih, idx, pmustatus_offset, 0, 0) & PST_SLOW_WR_PENDING) + {}; + } + + return si_corereg(sih, idx, regoff, mask, val); +} + +/* + * If there is no need for fiddling with interrupts or core switches (typically silicon + * back plane registers, pci registers and chipcommon registers), this function + * returns the register offset on this core to a mapped address. This address can + * be used for W_REG/R_REG directly. + * + * For accessing registers that would need a core switch, this function will return + * NULL. + */ +uint32 * +si_corereg_addr(si_t *sih, uint coreidx, uint regoff) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_corereg_addr(sih, coreidx, regoff); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_corereg_addr(sih, coreidx, regoff); + else { + return 0; + } +} + +void +si_core_disable(si_t *sih, uint32 bits) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + sb_core_disable(sih, bits); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_core_disable(sih, bits); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_core_disable(sih, bits); +} + +void +si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + sb_core_reset(sih, bits, resetbits); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_core_reset(sih, bits, resetbits); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_core_reset(sih, bits, resetbits); +} + +/** Run bist on current core. Caller needs to take care of core-specific bist hazards */ +int +si_corebist(si_t *sih) +{ + uint32 cflags; + int result = 0; + + /* Read core control flags */ + cflags = si_core_cflags(sih, 0, 0); + + /* Set bist & fgc */ + si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); + + /* Wait for bist done */ + SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); + + if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) + result = BCME_ERROR; + + /* Reset core control flags */ + si_core_cflags(sih, 0xffff, cflags); + + return result; +} + +static uint32 +factor6(uint32 x) +{ + switch (x) { + case CC_F6_2: return 2; + case CC_F6_3: return 3; + case CC_F6_4: return 4; + case CC_F6_5: return 5; + case CC_F6_6: return 6; + case CC_F6_7: return 7; + default: return 0; + } +} + +/** calculate the speed the SI would run at given a set of clockcontrol values */ +uint32 +si_clock_rate(uint32 pll_type, uint32 n, uint32 m) +{ + uint32 n1, n2, clock, m1, m2, m3, mc; + + n1 = n & CN_N1_MASK; + n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; + + if (pll_type == PLL_TYPE6) { + if (m & CC_T6_MMASK) + return CC_T6_M1; + else + return CC_T6_M0; + } else if ((pll_type == PLL_TYPE1) || + (pll_type == PLL_TYPE3) || + (pll_type == PLL_TYPE4) || + (pll_type == PLL_TYPE7)) { + n1 = factor6(n1); + n2 += CC_F5_BIAS; + } else if (pll_type == PLL_TYPE2) { + n1 += CC_T2_BIAS; + n2 += CC_T2_BIAS; + ASSERT((n1 >= 2) && (n1 <= 7)); + ASSERT((n2 >= 5) && (n2 <= 23)); + } else if (pll_type == PLL_TYPE5) { + return (100000000); + } else + ASSERT(0); + /* PLL types 3 and 7 use BASE2 (25Mhz) */ + if ((pll_type == PLL_TYPE3) || + (pll_type == PLL_TYPE7)) { + clock = CC_CLOCK_BASE2 * n1 * n2; + } else + clock = CC_CLOCK_BASE1 * n1 * n2; + + if (clock == 0) + return 0; + + m1 = m & CC_M1_MASK; + m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; + m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; + mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; + + if ((pll_type == PLL_TYPE1) || + (pll_type == PLL_TYPE3) || + (pll_type == PLL_TYPE4) || + (pll_type == PLL_TYPE7)) { + m1 = factor6(m1); + if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) + m2 += CC_F5_BIAS; + else + m2 = factor6(m2); + m3 = factor6(m3); + + switch (mc) { + case CC_MC_BYPASS: return (clock); + case CC_MC_M1: return (clock / m1); + case CC_MC_M1M2: return (clock / (m1 * m2)); + case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3)); + case CC_MC_M1M3: return (clock / (m1 * m3)); + default: return (0); + } + } else { + ASSERT(pll_type == PLL_TYPE2); + + m1 += CC_T2_BIAS; + m2 += CC_T2M2_BIAS; + m3 += CC_T2_BIAS; + ASSERT((m1 >= 2) && (m1 <= 7)); + ASSERT((m2 >= 3) && (m2 <= 10)); + ASSERT((m3 >= 2) && (m3 <= 7)); + + if ((mc & CC_T2MC_M1BYP) == 0) + clock /= m1; + if ((mc & CC_T2MC_M2BYP) == 0) + clock /= m2; + if ((mc & CC_T2MC_M3BYP) == 0) + clock /= m3; + + return (clock); + } +} + +/** + * Some chips could have multiple host interfaces, however only one will be active. + * For a given chip. Depending pkgopt and cc_chipst return the active host interface. + */ +uint +si_chip_hostif(si_t *sih) +{ + uint hosti = 0; + + switch (CHIPID(sih->chip)) { + + case BCM43602_CHIP_ID: + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + case BCM4360_CHIP_ID: + /* chippkg bit-0 == 0 is PCIE only pkgs + * chippkg bit-0 == 1 has both PCIE and USB cores enabled + */ + if ((sih->chippkg & 0x1) && (sih->chipst & CST4360_MODE_USB)) + hosti = CHIP_HOSTIF_USBMODE; + else + hosti = CHIP_HOSTIF_PCIEMODE; + + break; + + case BCM4335_CHIP_ID: + /* TBD: like in 4360, do we need to check pkg? */ + if (CST4335_CHIPMODE_USB20D(sih->chipst)) + hosti = CHIP_HOSTIF_USBMODE; + else if (CST4335_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + case BCM4345_CHIP_ID: + if (CST4345_CHIPMODE_USB20D(sih->chipst) || CST4345_CHIPMODE_HSIC(sih->chipst)) + hosti = CHIP_HOSTIF_USBMODE; + else if (CST4345_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else if (CST4345_CHIPMODE_PCIE(sih->chipst)) + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + case BCM4349_CHIP_GRPID: + if (CST4349_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else if (CST4349_CHIPMODE_PCIE(sih->chipst)) + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM4356_CHIP_ID: + case BCM43556_CHIP_ID: + case BCM43558_CHIP_ID: + case BCM43566_CHIP_ID: + case BCM43568_CHIP_ID: + case BCM43569_CHIP_ID: + case BCM43570_CHIP_ID: + case BCM4358_CHIP_ID: + if (CST4350_CHIPMODE_USB20D(sih->chipst) || + CST4350_CHIPMODE_HSIC20D(sih->chipst) || + CST4350_CHIPMODE_USB30D(sih->chipst) || + CST4350_CHIPMODE_USB30D_WL(sih->chipst) || + CST4350_CHIPMODE_HSIC30D(sih->chipst)) + hosti = CHIP_HOSTIF_USBMODE; + else if (CST4350_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else if (CST4350_CHIPMODE_PCIE(sih->chipst)) + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + default: + break; + } + + return hosti; +} + + +/** set chip watchdog reset timer to fire in 'ticks' */ +void +si_watchdog(si_t *sih, uint ticks) +{ + uint nb, maxt; + + if (PMUCTL_ENAB(sih)) { + +#if !defined(_CFEZ_) || defined(CFG_WL) + if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && + (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); + si_setcore(sih, USB20D_CORE_ID, 0); + si_core_disable(sih, 1); + si_setcore(sih, CC_CORE_ID, 0); + } +#endif + + nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); + /* The mips compiler uses the sllv instruction, + * so we specially handle the 32-bit case. + */ + if (nb == 32) + maxt = 0xffffffff; + else + maxt = ((1 << nb) - 1); + + if (ticks == 1) + ticks = 2; + else if (ticks > maxt) + ticks = maxt; + + pmu_corereg(sih, SI_CC_IDX, pmuwatchdog, ~0, ticks); + } else { + maxt = (1 << 28) - 1; + if (ticks > maxt) + ticks = maxt; + + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); + } +} + +/** trigger watchdog reset after ms milliseconds */ +void +si_watchdog_ms(si_t *sih, uint32 ms) +{ + si_watchdog(sih, wd_msticks * ms); +} + +uint32 si_watchdog_msticks(void) +{ + return wd_msticks; +} + +bool +si_taclear(si_t *sih, bool details) +{ + return FALSE; +} + + + +/** return the slow clock source - LPO, XTAL, or PCI */ +static uint +si_slowclk_src(si_info_t *sii) +{ + chipcregs_t *cc; + + ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); + + if (sii->pub.ccrev < 6) { + if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && + (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) & + PCI_CFG_GPIO_SCS)) + return (SCC_SS_PCI); + else + return (SCC_SS_XTAL); + } else if (sii->pub.ccrev < 10) { + cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); + ASSERT(cc); + return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); + } else /* Insta-clock */ + return (SCC_SS_XTAL); +} + +/** return the ILP (slowclock) min or max frequency */ +static uint +si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) +{ + uint32 slowclk; + uint div; + + ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); + + /* shouldn't be here unless we've established the chip has dynamic clk control */ + ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); + + slowclk = si_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(sii->osh, &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 + ASSERT(0); + } else { + /* Chipc rev 10 is InstaClock */ + div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; + div = 4 * (div + 1); + return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); + } + return (0); +} + +static void +si_clkctl_setdelay(si_info_t *sii, void *chipcregs) +{ + chipcregs_t *cc = (chipcregs_t *)chipcregs; + 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 = si_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 = si_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(sii->osh, &cc->pll_on_delay, pll_on_delay); + W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); +} + +/** initialize power control delay registers */ +void +si_clkctl_init(si_t *sih) +{ + si_info_t *sii; + uint origidx = 0; + chipcregs_t *cc; + bool fast; + + if (!CCCTL_ENAB(sih)) + return; + + sii = SI_INFO(sih); + fast = SI_FAST(sii); + if (!fast) { + origidx = sii->curidx; + if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) + return; + } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) + return; + ASSERT(cc != NULL); + + /* set all Instaclk chip ILP to 1 MHz */ + if (sih->ccrev >= 10) + SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, + (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); + + si_clkctl_setdelay(sii, (void *)(uintptr)cc); + + OSL_DELAY(20000); + + if (!fast) + si_setcoreidx(sih, origidx); +} + + +/** change logical "focus" to the gpio core for optimized access */ +void * +si_gpiosetcore(si_t *sih) +{ + return (si_setcoreidx(sih, SI_CC_IDX)); +} + +/** + * mask & set gpiocontrol bits. + * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin. + * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated + * to some chip-specific purpose. + */ +uint32 +si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + regoff = 0; + + /* gpios could be shared on router platforms + * ignore reservation if it's high priority (e.g., test apps) + */ + if ((priority != GPIO_HI_PRIORITY) && + (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpiocontrol); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/** mask&set gpio output enable bits */ +uint32 +si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + regoff = 0; + + /* gpios could be shared on router platforms + * ignore reservation if it's high priority (e.g., test apps) + */ + if ((priority != GPIO_HI_PRIORITY) && + (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpioouten); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/** mask&set gpio output bits */ +uint32 +si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + regoff = 0; + + /* gpios could be shared on router platforms + * ignore reservation if it's high priority (e.g., test apps) + */ + if ((priority != GPIO_HI_PRIORITY) && + (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpioout); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/** reserve one gpio */ +uint32 +si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) +{ + /* only cores on SI_BUS share GPIO's and only applcation users need to + * reserve/release GPIO + */ + if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { + ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); + return 0xffffffff; + } + /* make sure only one bit is set */ + if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { + ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); + return 0xffffffff; + } + + /* already reserved */ + if (si_gpioreservation & gpio_bitmask) + return 0xffffffff; + /* set reservation */ + si_gpioreservation |= gpio_bitmask; + + return si_gpioreservation; +} + +/** + * release one gpio. + * + * releasing the gpio doesn't change the current value on the GPIO last write value + * persists till someone overwrites it. + */ +uint32 +si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) +{ + /* only cores on SI_BUS share GPIO's and only applcation users need to + * reserve/release GPIO + */ + if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { + ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); + return 0xffffffff; + } + /* make sure only one bit is set */ + if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { + ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); + return 0xffffffff; + } + + /* already released */ + if (!(si_gpioreservation & gpio_bitmask)) + return 0xffffffff; + + /* clear reservation */ + si_gpioreservation &= ~gpio_bitmask; + + return si_gpioreservation; +} + +/* return the current gpioin register value */ +uint32 +si_gpioin(si_t *sih) +{ + uint regoff; + + regoff = OFFSETOF(chipcregs_t, gpioin); + return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0)); +} + +/* mask&set gpio interrupt polarity bits */ +uint32 +si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + /* gpios could be shared on router platforms */ + if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpiointpolarity); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/* mask&set gpio interrupt mask bits */ +uint32 +si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + /* gpios could be shared on router platforms */ + if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpiointmask); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/* assign the gpio to an led */ +uint32 +si_gpioled(si_t *sih, uint32 mask, uint32 val) +{ + if (sih->ccrev < 16) + return 0xffffffff; + + /* gpio led powersave reg */ + return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); +} + +/* mask&set gpio timer val */ +uint32 +si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) +{ + if (sih->ccrev < 16) + return 0xffffffff; + + return (si_corereg(sih, SI_CC_IDX, + OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); +} + +uint32 +si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) +{ + uint offs; + + if (sih->ccrev < 20) + return 0xffffffff; + + offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); + return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); +} + +uint32 +si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) +{ + uint offs; + + if (sih->ccrev < 11) + return 0xffffffff; + + if (regtype == GPIO_REGEVT) + offs = OFFSETOF(chipcregs_t, gpioevent); + else if (regtype == GPIO_REGEVT_INTMSK) + offs = OFFSETOF(chipcregs_t, gpioeventintmask); + else if (regtype == GPIO_REGEVT_INTPOL) + offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); + else + return 0xffffffff; + + return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); +} + +void * +si_gpio_handler_register(si_t *sih, uint32 event, + bool level, gpio_handler_t cb, void *arg) +{ + si_info_t *sii = SI_INFO(sih); + gpioh_item_t *gi; + + ASSERT(event); + ASSERT(cb != NULL); + + if (sih->ccrev < 11) + return NULL; + + if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL) + return NULL; + + bzero(gi, sizeof(gpioh_item_t)); + gi->event = event; + gi->handler = cb; + gi->arg = arg; + gi->level = level; + + gi->next = sii->gpioh_head; + sii->gpioh_head = gi; + + return (void *)(gi); +} + +void +si_gpio_handler_unregister(si_t *sih, void *gpioh) +{ + si_info_t *sii = SI_INFO(sih); + gpioh_item_t *p, *n; + + if (sih->ccrev < 11) + return; + + ASSERT(sii->gpioh_head != NULL); + if ((void*)sii->gpioh_head == gpioh) { + sii->gpioh_head = sii->gpioh_head->next; + MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); + return; + } else { + p = sii->gpioh_head; + n = p->next; + while (n) { + if ((void*)n == gpioh) { + p->next = n->next; + MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); + return; + } + p = n; + n = n->next; + } + } + + ASSERT(0); /* Not found in list */ +} + +void +si_gpio_handler_process(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + gpioh_item_t *h; + uint32 level = si_gpioin(sih); + uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0); + uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); + uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0); + + for (h = sii->gpioh_head; h != NULL; h = h->next) { + if (h->handler) { + uint32 status = (h->level ? level : edge) & h->event; + uint32 polarity = (h->level ? levelp : edgep) & h->event; + + /* polarity bitval is opposite of status bitval */ + if ((h->level && (status ^ polarity)) || (!h->level && status)) + h->handler(status, h->arg); + } + } + + si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ +} + +uint32 +si_gpio_int_enable(si_t *sih, bool enable) +{ + uint offs; + + if (sih->ccrev < 11) + return 0xffffffff; + + offs = OFFSETOF(chipcregs_t, intmask); + return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); +} + + +/** Return the size of the specified SOCRAM bank */ +static uint +socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) +{ + uint banksize, bankinfo; + uint bankidx = idx | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + + ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); + + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); + return banksize; +} + +void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 16) { + W_REG(sii->osh, ®s->bankidx, bankidx); + W_REG(sii->osh, ®s->bankpda, bankpda); + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); +} + +void +si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect, uint8 *remap) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + if (!set) + *enable = *protect = *remap = 0; + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 10) { + uint32 extcinfo; + uint8 nb; + uint8 i; + uint32 bankidx, bankinfo; + + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); + for (i = 0; i < nb; i++) { + bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + if (set) { + bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; + bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; + bankinfo &= ~SOCRAM_BANKINFO_DEVRAMREMAP_MASK; + if (*enable) { + bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); + if (*protect) + bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); + if ((corerev >= 16) && *remap) + bankinfo |= + (1 << SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT); + } + W_REG(sii->osh, ®s->bankinfo, bankinfo); + } + else if (i == 0) { + if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { + *enable = 1; + if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) + *protect = 1; + if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) + *remap = 1; + } + } + } + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); +} + +bool +si_socdevram_remap_isenb(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + sbsocramregs_t *regs; + bool wasup, remap = FALSE; + uint corerev; + uint32 extcinfo; + uint8 nb; + uint8 i; + uint32 bankidx, bankinfo; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 16) { + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); + for (i = 0; i < nb; i++) { + bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { + remap = TRUE; + break; + } + } + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + return remap; +} + +bool +si_socdevram_pkg(si_t *sih) +{ + if (si_socdevram_size(sih) > 0) + return TRUE; + else + return FALSE; +} + +uint32 +si_socdevram_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + uint32 memsize = 0; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 10) { + uint32 extcinfo; + uint8 nb; + uint8 i; + + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); + for (i = 0; i < nb; i++) + memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + +uint32 +si_socdevram_remap_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + uint32 memsize = 0, banksz; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + uint32 extcinfo; + uint8 nb; + uint8 i; + uint32 bankidx, bankinfo; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 16) { + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); + + /* + * FIX: A0 Issue: Max addressable is 512KB, instead 640KB + * Only four banks are accessible to ARM + */ + if ((corerev == 16) && (nb == 5)) + nb = 4; + + for (i = 0; i < nb; i++) { + bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { + banksz = socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); + memsize += banksz; + } else { + /* Account only consecutive banks for now */ + break; + } + } + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + +/** Return the RAM size of the SOCRAM core */ +uint32 +si_socram_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + + sbsocramregs_t *regs; + bool wasup; + uint corerev; + uint32 coreinfo; + uint memsize = 0; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + corerev = si_corerev(sih); + coreinfo = R_REG(sii->osh, ®s->coreinfo); + + /* Calculate size from coreinfo based on rev */ + if (corerev == 0) + memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); + else if (corerev < 3) { + memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); + memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + } else if ((corerev <= 7) || (corerev == 12)) { + uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + uint bsz = (coreinfo & SRCI_SRBSZ_MASK); + uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; + if (lss != 0) + nb --; + memsize = nb * (1 << (bsz + SR_BSZ_BASE)); + if (lss != 0) + memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); + } else { + uint8 i; + uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + for (i = 0; i < nb; i++) + memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + + +/** Return the TCM-RAM size of the ARMCR4 core. */ +uint32 +si_tcm_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + uint8 *regs; + bool wasup; + uint32 corecap; + uint memsize = 0; + uint32 nab = 0; + uint32 nbb = 0; + uint32 totb = 0; + uint32 bxinfo = 0; + uint32 idx = 0; + uint32 *arm_cap_reg; + uint32 *arm_bidx; + uint32 *arm_binfo; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to CR4 core */ + if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0))) + goto done; + + /* Get info for determining size. If in reset, come out of reset, + * but remain in halt + */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT); + + arm_cap_reg = (uint32 *)(regs + SI_CR4_CAP); + corecap = R_REG(sii->osh, arm_cap_reg); + + nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; + nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; + totb = nab + nbb; + + arm_bidx = (uint32 *)(regs + SI_CR4_BANKIDX); + arm_binfo = (uint32 *)(regs + SI_CR4_BANKINFO); + for (idx = 0; idx < totb; idx++) { + W_REG(sii->osh, arm_bidx, idx); + + bxinfo = R_REG(sii->osh, arm_binfo); + memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + +bool +si_has_flops(si_t *sih) +{ + uint origidx, cr4_rev; + + /* Find out CR4 core revision */ + origidx = si_coreidx(sih); + if (si_setcore(sih, ARMCR4_CORE_ID, 0)) { + cr4_rev = si_corerev(sih); + si_setcoreidx(sih, origidx); + + if (cr4_rev == 1 || cr4_rev >= 3) + return TRUE; + } + return FALSE; +} + +uint32 +si_socram_srmem_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + + sbsocramregs_t *regs; + bool wasup; + uint corerev; + uint32 coreinfo; + uint memsize = 0; + + if ((CHIPID(sih->chip) == BCM4334_CHIP_ID) && (CHIPREV(sih->chiprev) < 2)) { + return (32 * 1024); + } + + if (CHIPID(sih->chip) == BCM43430_CHIP_ID) { + return (64 * 1024); + } + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + corerev = si_corerev(sih); + coreinfo = R_REG(sii->osh, ®s->coreinfo); + + /* Calculate size from coreinfo based on rev */ + if (corerev >= 16) { + uint8 i; + uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + for (i = 0; i < nb; i++) { + W_REG(sii->osh, ®s->bankidx, i); + if (R_REG(sii->osh, ®s->bankinfo) & SOCRAM_BANKINFO_RETNTRAM_MASK) + memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); + } + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + + +#if !defined(_CFEZ_) || defined(CFG_WL) +void +si_btcgpiowar(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + chipcregs_t *cc; + + /* Make sure that there is ChipCommon core present && + * UART_TX is strapped to 1 + */ + if (!(sih->cccaps & CC_CAP_UARTGPIO)) + return; + + /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */ + INTR_OFF(sii, intr_val); + + origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + ASSERT(cc != NULL); + + W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04); + + /* restore the original index */ + si_setcoreidx(sih, origidx); + + INTR_RESTORE(sii, intr_val); +} + +void +si_chipcontrl_btshd0_4331(si_t *sih, bool on) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + chipcregs_t *cc; + uint origidx; + uint32 val; + uint intr_val = 0; + + INTR_OFF(sii, intr_val); + + origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + val = R_REG(sii->osh, &cc->chipcontrol); + + /* bt_shd0 controls are same for 4331 chiprevs 0 and 1, packages 12x9 and 12x12 */ + if (on) { + /* Enable bt_shd0 on gpio4: */ + val |= (CCTRL4331_BT_SHD0_ON_GPIO4); + W_REG(sii->osh, &cc->chipcontrol, val); + } else { + val &= ~(CCTRL4331_BT_SHD0_ON_GPIO4); + W_REG(sii->osh, &cc->chipcontrol, val); + } + + /* restore the original index */ + si_setcoreidx(sih, origidx); + + INTR_RESTORE(sii, intr_val); +} + +void +si_chipcontrl_restore(si_t *sih, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + W_REG(sii->osh, &cc->chipcontrol, val); + si_setcoreidx(sih, origidx); +} + +uint32 +si_chipcontrl_read(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + uint32 val; + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + val = R_REG(sii->osh, &cc->chipcontrol); + si_setcoreidx(sih, origidx); + return val; +} + +void +si_chipcontrl_epa4331(si_t *sih, bool on) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + uint32 val; + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + val = R_REG(sii->osh, &cc->chipcontrol); + + if (on) { + if (sih->chippkg == 9 || sih->chippkg == 0xb) { + val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); + /* Ext PA Controls for 4331 12x9 Package */ + W_REG(sii->osh, &cc->chipcontrol, val); + } else { + /* Ext PA Controls for 4331 12x12 Package */ + if (sih->chiprev > 0) { + W_REG(sii->osh, &cc->chipcontrol, val | + (CCTRL4331_EXTPA_EN) | (CCTRL4331_EXTPA_EN2)); + } else { + W_REG(sii->osh, &cc->chipcontrol, val | (CCTRL4331_EXTPA_EN)); + } + } + } else { + val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_EN2 | CCTRL4331_EXTPA_ON_GPIO2_5); + W_REG(sii->osh, &cc->chipcontrol, val); + } + + si_setcoreidx(sih, origidx); +} + +/** switch muxed pins, on: SROM, off: FEMCTRL. Called for a family of ac chips, not just 4360. */ +void +si_chipcontrl_srom4360(si_t *sih, bool on) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + uint32 val; + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + val = R_REG(sii->osh, &cc->chipcontrol); + + if (on) { + val &= ~(CCTRL4360_SECI_MODE | + CCTRL4360_BTSWCTRL_MODE | + CCTRL4360_EXTRA_FEMCTRL_MODE | + CCTRL4360_BT_LGCY_MODE | + CCTRL4360_CORE2FEMCTRL4_ON); + + W_REG(sii->osh, &cc->chipcontrol, val); + } else { + } + + si_setcoreidx(sih, origidx); +} + +void +si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl) +{ + si_info_t *sii; + chipcregs_t *cc; + uint origidx; + uint32 val; + bool sel_chip; + + sel_chip = (CHIPID(sih->chip) == BCM4331_CHIP_ID) || + (CHIPID(sih->chip) == BCM43431_CHIP_ID); + sel_chip &= ((sih->chippkg == 9 || sih->chippkg == 0xb)); + + if (!sel_chip) + return; + + sii = SI_INFO(sih); + origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + val = R_REG(sii->osh, &cc->chipcontrol); + + if (enter_wowl) { + val |= CCTRL4331_EXTPA_EN; + W_REG(sii->osh, &cc->chipcontrol, val); + } else { + val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); + W_REG(sii->osh, &cc->chipcontrol, val); + } + si_setcoreidx(sih, origidx); +} +#endif + +uint +si_pll_reset(si_t *sih) +{ + uint err = 0; + + return (err); +} + +/** Enable BT-COEX & Ex-PA for 4313 */ +void +si_epa_4313war(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + /* EPA Fix */ + W_REG(sii->osh, &cc->gpiocontrol, + R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); + + si_setcoreidx(sih, origidx); +} + +void +si_clk_pmu_htavail_set(si_t *sih, bool set_clear) +{ +} + +/** Re-enable synth_pwrsw resource in min_res_mask for 4313 */ +void +si_pmu_synth_pwrsw_4313_war(si_t *sih) +{ +} + +/** WL/BT control for 4313 btcombo boards >= P250 */ +void +si_btcombo_p250_4313_war(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + W_REG(sii->osh, &cc->gpiocontrol, + R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_5_6_EN_MASK); + + W_REG(sii->osh, &cc->gpioouten, + R_REG(sii->osh, &cc->gpioouten) | GPIO_CTRL_5_6_EN_MASK); + + si_setcoreidx(sih, origidx); +} +void +si_btc_enable_chipcontrol(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + /* BT fix */ + W_REG(sii->osh, &cc->chipcontrol, + R_REG(sii->osh, &cc->chipcontrol) | CC_BTCOEX_EN_MASK); + + si_setcoreidx(sih, origidx); +} +void +si_btcombo_43228_war(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + W_REG(sii->osh, &cc->gpioouten, GPIO_CTRL_7_6_EN_MASK); + W_REG(sii->osh, &cc->gpioout, GPIO_OUT_7_EN_MASK); + + si_setcoreidx(sih, origidx); +} + +/** check if the device is removed */ +bool +si_deviceremoved(si_t *sih) +{ + uint32 w; + + switch (BUSTYPE(sih->bustype)) { + case PCI_BUS: + ASSERT(SI_INFO(sih)->osh != NULL); + w = OSL_PCI_READ_CONFIG(SI_INFO(sih)->osh, PCI_CFG_VID, sizeof(uint32)); + if ((w & 0xFFFF) != VENDOR_BROADCOM) + return TRUE; + break; + } + return FALSE; +} + +bool +si_is_sprom_available(si_t *sih) +{ + if (sih->ccrev >= 31) { + si_info_t *sii; + uint origidx; + chipcregs_t *cc; + uint32 sromctrl; + + if ((sih->cccaps & CC_CAP_SROM) == 0) + return FALSE; + + sii = SI_INFO(sih); + origidx = sii->curidx; + cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT(cc); + sromctrl = R_REG(sii->osh, &cc->sromcontrol); + si_setcoreidx(sih, origidx); + return (sromctrl & SRC_PRESENT); + } + + switch (CHIPID(sih->chip)) { + case BCM4312_CHIP_ID: + return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL); + case BCM4325_CHIP_ID: + return (sih->chipst & CST4325_SPROM_SEL) != 0; + case BCM4322_CHIP_ID: case BCM43221_CHIP_ID: case BCM43231_CHIP_ID: + case BCM43222_CHIP_ID: case BCM43111_CHIP_ID: case BCM43112_CHIP_ID: + case BCM4342_CHIP_ID: { + uint32 spromotp; + spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >> + CST4322_SPROM_OTP_SEL_SHIFT; + return (spromotp & CST4322_SPROM_PRESENT) != 0; + } + case BCM4329_CHIP_ID: + return (sih->chipst & CST4329_SPROM_SEL) != 0; + case BCM4315_CHIP_ID: + return (sih->chipst & CST4315_SPROM_SEL) != 0; + case BCM4319_CHIP_ID: + return (sih->chipst & CST4319_SPROM_SEL) != 0; + case BCM4336_CHIP_ID: + case BCM43362_CHIP_ID: + return (sih->chipst & CST4336_SPROM_PRESENT) != 0; + case BCM4330_CHIP_ID: + return (sih->chipst & CST4330_SPROM_PRESENT) != 0; + case BCM4313_CHIP_ID: + return (sih->chipst & CST4313_SPROM_PRESENT) != 0; + case BCM4331_CHIP_ID: + case BCM43431_CHIP_ID: + return (sih->chipst & CST4331_SPROM_PRESENT) != 0; + case BCM43239_CHIP_ID: + return ((sih->chipst & CST43239_SPROM_MASK) && + !(sih->chipst & CST43239_SFLASH_MASK)); + case BCM4324_CHIP_ID: + case BCM43242_CHIP_ID: + return ((sih->chipst & CST4324_SPROM_MASK) && + !(sih->chipst & CST4324_SFLASH_MASK)); + case BCM4335_CHIP_ID: + case BCM4345_CHIP_ID: + return ((sih->chipst & CST4335_SPROM_MASK) && + !(sih->chipst & CST4335_SFLASH_MASK)); + case BCM4349_CHIP_GRPID: + return (sih->chipst & CST4349_SPROM_PRESENT) != 0; + break; + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM4356_CHIP_ID: + case BCM43556_CHIP_ID: + case BCM43558_CHIP_ID: + case BCM43566_CHIP_ID: + case BCM43568_CHIP_ID: + case BCM43569_CHIP_ID: + case BCM43570_CHIP_ID: + case BCM4358_CHIP_ID: + return (sih->chipst & CST4350_SPROM_PRESENT) != 0; + case BCM43602_CHIP_ID: + return (sih->chipst & CST43602_SPROM_PRESENT) != 0; + case BCM43131_CHIP_ID: + case BCM43217_CHIP_ID: + case BCM43227_CHIP_ID: + case BCM43228_CHIP_ID: + case BCM43428_CHIP_ID: + return (sih->chipst & CST43228_OTP_PRESENT) != CST43228_OTP_PRESENT; + default: + return TRUE; + } +} + + +uint32 si_get_sromctl(si_t *sih) +{ + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + uint32 sromctl; + osl_t *osh = si_osh(sih); + + cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT((uintptr)cc); + + sromctl = R_REG(osh, &cc->sromcontrol); + + /* return to the original core */ + si_setcoreidx(sih, origidx); + return sromctl; +} + +int si_set_sromctl(si_t *sih, uint32 value) +{ + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + osl_t *osh = si_osh(sih); + + cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT((uintptr)cc); + + /* get chipcommon rev */ + if (si_corerev(sih) < 32) + return BCME_UNSUPPORTED; + + W_REG(osh, &cc->sromcontrol, value); + + /* return to the original core */ + si_setcoreidx(sih, origidx); + return BCME_OK; + +} + +uint +si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val) +{ + uint origidx, intr_val = 0; + uint ret_val; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + origidx = si_coreidx(sih); + + INTR_OFF(sii, intr_val); + si_setcoreidx(sih, coreidx); + + ret_val = si_wrapperreg(sih, offset, mask, val); + + /* return to the original core */ + si_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); + return ret_val; +} + + +/* cleanup the timer from the host when ARM is been halted + * without a chance for ARM cleanup its resources + * If left not cleanup, Intr from a software timer can still + * request HT clk when ARM is halted. + */ +uint32 +si_pmu_res_req_timer_clr(si_t *sih) +{ + uint32 mask; + + mask = PRRT_REQ_ACTIVE | PRRT_INTEN | PRRT_HT_REQ; + if (CHIPID(sih->chip) != BCM4328_CHIP_ID) + mask <<= 14; + /* clear mask bits */ + pmu_corereg(sih, SI_CC_IDX, res_req_timer, mask, 0); + /* readback to ensure write completes */ + return pmu_corereg(sih, SI_CC_IDX, res_req_timer, 0, 0); +} + +/** turn on/off rfldo */ +void +si_pmu_rfldo(si_t *sih, bool on) +{ +} + + +#ifdef SURVIVE_PERST_ENAB +static uint32 +si_pcie_survive_perst(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + + if (!PCIE(sii)) + return (0); + + return pcie_survive_perst(sii->pch, mask, val); +} + +static void +si_watchdog_reset(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + uint32 i; + + /* issue a watchdog reset */ + pmu_corereg(sih, SI_CC_IDX, pmuwatchdog, 2, 2); + /* do busy wait for 20ms */ + for (i = 0; i < 2000; i++) { + OSL_DELAY(10); + } +} +#endif /* SURVIVE_PERST_ENAB */ + +void +si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 sperst_val) +{ +#ifdef SURVIVE_PERST_ENAB + if (BUSTYPE(sih->bustype) != PCI_BUS) + return; + + if ((CHIPID(sih->chip) != BCM4360_CHIP_ID && CHIPID(sih->chip) != BCM4352_CHIP_ID) || + (CHIPREV(sih->chiprev) >= 4)) + return; + + if (reset) { + si_info_t *sii = SI_INFO(sih); + uint32 bar0win, bar0win_after; + + /* save the bar0win */ + bar0win = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + + si_watchdog_reset(sih); + + bar0win_after = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + if (bar0win_after != bar0win) { + SI_ERROR(("%s: bar0win before %08x, bar0win after %08x\n", + __FUNCTION__, bar0win, bar0win_after)); + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32), bar0win); + } + } + if (sperst_mask) { + /* enable survive perst */ + si_pcie_survive_perst(sih, sperst_mask, sperst_val); + } +#endif /* SURVIVE_PERST_ENAB */ +} + +void +si_pcie_ltr_war(si_t *sih) +{ +} + +void +si_pcie_hw_LTR_war(si_t *sih) +{ +} + +void +si_pciedev_reg_pm_clk_period(si_t *sih) +{ +} + +void +si_pciedev_crwlpciegen2(si_t *sih) +{ +} + +void +si_pcie_prep_D3(si_t *sih, bool enter_D3) +{ +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/siutils_priv.h b/drivers/net/wireless/bcmdhd_bcm4356/siutils_priv.h new file mode 100644 index 000000000000..3941db8895c7 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/siutils_priv.h @@ -0,0 +1,283 @@ +/* + * Include file private to the SOC Interconnect support files. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: siutils_priv.h 474902 2014-05-02 18:31:33Z $ + */ + +#ifndef _siutils_priv_h_ +#define _siutils_priv_h_ + +#define SI_ERROR(args) + +#define SI_MSG(args) + +#ifdef BCMDBG_SI +#define SI_VMSG(args) printf args +#else +#define SI_VMSG(args) +#endif + +#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) + +typedef uint32 (*si_intrsoff_t)(void *intr_arg); +typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg); +typedef bool (*si_intrsenabled_t)(void *intr_arg); + +typedef struct gpioh_item { + void *arg; + bool level; + gpio_handler_t handler; + uint32 event; + struct gpioh_item *next; +} gpioh_item_t; + + +#define SI_GPIO_MAX 16 + +typedef struct gci_gpio_item { + void *arg; + uint8 gci_gpio; + uint8 status; + gci_gpio_handler_t handler; + struct gci_gpio_item *next; +} gci_gpio_item_t; + + +typedef struct si_cores_info { + void *regs[SI_MAXCORES]; /* other regs va */ + + uint coreid[SI_MAXCORES]; /* id of each core */ + uint32 coresba[SI_MAXCORES]; /* backplane address of each core */ + void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */ + uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */ + uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */ + uint32 coresba2_size[SI_MAXCORES]; /* second address space size */ + + void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ + uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ + + uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */ + uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */ +} si_cores_info_t; + +/* misc si info needed by some of the routines */ +typedef struct si_info { + struct si_pub pub; /* back plane public state (must be first field) */ + + void *osh; /* osl os handle */ + void *sdh; /* bcmsdh handle */ + + uint dev_coreid; /* the core provides driver functions */ + void *intr_arg; /* interrupt callback function arg */ + si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ + si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ + si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ + + void *pch; /* PCI/E core handle */ + + gpioh_item_t *gpioh_head; /* GPIO event handlers list */ + + bool memseg; /* flag to toggle MEM_SEG register */ + + char *vars; + uint varsz; + + void *curmap; /* current regs va */ + + uint curidx; /* current core index */ + uint numcores; /* # discovered cores */ + + void *curwrap; /* current wrapper va */ + + uint32 oob_router; /* oob router registers for axi */ + + void *cores_info; + gci_gpio_item_t *gci_gpio_head; /* gci gpio interrupts head */ + uint chipnew; /* new chip number */ +} si_info_t; + + +#define SI_INFO(sih) ((si_info_t *)(uintptr)sih) + +#define GOODCOREADDR(x, b) (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ + ISALIGNED((x), SI_CORE_SIZE)) +#define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE)) +#define BADCOREADDR 0 +#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES) +#define NOREV -1 /* Invalid rev */ + +#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ + ((si)->pub.buscoretype == PCI_CORE_ID)) + +#define PCIE_GEN1(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ + ((si)->pub.buscoretype == PCIE_CORE_ID)) + +#define PCIE_GEN2(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ + ((si)->pub.buscoretype == PCIE2_CORE_ID)) + +#define PCIE(si) (PCIE_GEN1(si) || PCIE_GEN2(si)) + +#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE)) + +/* Newer chips can access PCI/PCIE and CC core without requiring to change + * PCI BAR0 WIN + */ +#define SI_FAST(si) (PCIE(si) || (PCI(si) && ((si)->pub.buscorerev >= 13))) + +#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET)) +#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET)) + +/* + * 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 && (cores_info)->coreid[(si)->curidx] == (si)->dev_coreid) { \ + intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); } +#define INTR_RESTORE(si, intr_val) \ + if ((si)->intrsrestore_fn && (cores_info)->coreid[(si)->curidx] == (si)->dev_coreid) { \ + (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } + +/* 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 */ + +/* Force fast clock for 4360b0 */ +#define PCI_FORCEHT(si) \ + (((PCIE_GEN1(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \ + ((PCI(si) || PCIE_GEN1(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \ + (PCIE_GEN1(si) && (si->pub.chip == BCM4716_CHIP_ID)) || \ + (PCIE_GEN1(si) && (si->pub.chip == BCM4748_CHIP_ID))) + +/* GPIO Based LED powersave defines */ +#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ +#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ + +#ifndef DEFAULT_GPIOTIMERVAL +#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) +#endif + +/* Silicon Backplane externs */ +extern void sb_scan(si_t *sih, void *regs, uint devid); +extern uint sb_coreid(si_t *sih); +extern uint sb_intflag(si_t *sih); +extern uint sb_flag(si_t *sih); +extern void sb_setint(si_t *sih, int siflag); +extern uint sb_corevendor(si_t *sih); +extern uint sb_corerev(si_t *sih); +extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); +extern uint32 *sb_corereg_addr(si_t *sih, uint coreidx, uint regoff); +extern bool sb_iscoreup(si_t *sih); +extern void *sb_setcoreidx(si_t *sih, uint coreidx); +extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val); +extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); +extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val); +extern void sb_commit(si_t *sih); +extern uint32 sb_base(uint32 admatch); +extern uint32 sb_size(uint32 admatch); +extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); +extern void sb_core_disable(si_t *sih, uint32 bits); +extern uint32 sb_addrspace(si_t *sih, uint asidx); +extern uint32 sb_addrspacesize(si_t *sih, uint asidx); +extern int sb_numaddrspaces(si_t *sih); + +extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); + +extern bool sb_taclear(si_t *sih, bool details); + +#if defined(BCMDBG_PHYDUMP) +extern void sb_dumpregs(si_t *sih, struct bcmstrbuf *b); +#endif + +/* Wake-on-wireless-LAN (WOWL) */ +extern bool sb_pci_pmecap(si_t *sih); +struct osl_info; +extern bool sb_pci_fastpmecap(struct osl_info *osh); +extern bool sb_pci_pmeclr(si_t *sih); +extern void sb_pci_pmeen(si_t *sih); +extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset); + +/* AMBA Interconnect exported externs */ +extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, + void *sdh, char **vars, uint *varsz); +extern si_t *ai_kattach(osl_t *osh); +extern void ai_scan(si_t *sih, void *regs, uint devid); + +extern uint ai_flag(si_t *sih); +extern uint ai_flag_alt(si_t *sih); +extern void ai_setint(si_t *sih, int siflag); +extern uint ai_coreidx(si_t *sih); +extern uint ai_corevendor(si_t *sih); +extern uint ai_corerev(si_t *sih); +extern uint32 *ai_corereg_addr(si_t *sih, uint coreidx, uint regoff); +extern bool ai_iscoreup(si_t *sih); +extern void *ai_setcoreidx(si_t *sih, uint coreidx); +extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val); +extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); +extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val); +extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); +extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits); +extern void ai_d11rsdb_core_reset(si_t *sih, uint32 bits, + uint32 resetbits, void *p, void *s); +extern void ai_core_disable(si_t *sih, uint32 bits); +extern void ai_d11rsdb_core_disable(const si_info_t *sii, uint32 bits, + aidmp_t *pmacai, aidmp_t *smacai); +extern int ai_numaddrspaces(si_t *sih); +extern uint32 ai_addrspace(si_t *sih, uint asidx); +extern uint32 ai_addrspacesize(si_t *sih, uint asidx); +extern void ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); +extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val); + +#if defined(BCMDBG_PHYDUMP) +extern void ai_dumpregs(si_t *sih, struct bcmstrbuf *b); +#endif + + +#define ub_scan(a, b, c) do {} while (0) +#define ub_flag(a) (0) +#define ub_setint(a, b) do {} while (0) +#define ub_coreidx(a) (0) +#define ub_corevendor(a) (0) +#define ub_corerev(a) (0) +#define ub_iscoreup(a) (0) +#define ub_setcoreidx(a, b) (0) +#define ub_core_cflags(a, b, c) (0) +#define ub_core_cflags_wo(a, b, c) do {} while (0) +#define ub_core_sflags(a, b, c) (0) +#define ub_corereg(a, b, c, d, e) (0) +#define ub_core_reset(a, b, c) do {} while (0) +#define ub_core_disable(a, b) do {} while (0) +#define ub_numaddrspaces(a) (0) +#define ub_addrspace(a, b) (0) +#define ub_addrspacesize(a, b) (0) +#define ub_view(a, b) do {} while (0) +#define ub_dumpregs(a, b) do {} while (0) + +#endif /* _siutils_priv_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/uamp_api.h b/drivers/net/wireless/bcmdhd_bcm4356/uamp_api.h new file mode 100644 index 000000000000..bffadb2ea658 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/uamp_api.h @@ -0,0 +1,178 @@ +/* + * Name: uamp_api.h + * + * Description: Universal AMP API + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: uamp_api.h 467328 2014-04-03 01:23:40Z $ + * + */ + + +#ifndef UAMP_API_H +#define UAMP_API_H + + +#include "typedefs.h" + + +/***************************************************************************** +** Constant and Type Definitions +****************************************************************************** +*/ + +#define BT_API + +/* Types. */ +typedef bool BOOLEAN; +typedef uint8 UINT8; +typedef uint16 UINT16; + + +/* UAMP identifiers */ +#define UAMP_ID_1 1 +#define UAMP_ID_2 2 +typedef UINT8 tUAMP_ID; + +/* UAMP event ids (used by UAMP_CBACK) */ +#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */ +#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */ +#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */ +typedef UINT8 tUAMP_EVT; + + +/* UAMP Channels */ +#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */ +#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */ +#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */ +typedef UINT8 tUAMP_CH; + +/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */ +typedef union { + tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */ +} tUAMP_EVT_DATA; + + +/***************************************************************************** +** +** Function: UAMP_CBACK +** +** Description: Callback for events. Register callback using UAMP_Init. +** +** Parameters amp_id: AMP device identifier that generated the event +** amp_evt: event id +** p_amp_evt_data: pointer to event-specific data +** +****************************************************************************** +*/ +typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data); + +/***************************************************************************** +** external function declarations +****************************************************************************** +*/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** +** Function: UAMP_Init +** +** Description: Initialize UAMP driver +** +** Parameters p_cback: Callback function for UAMP event notification +** +****************************************************************************** +*/ +BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback); + + +/***************************************************************************** +** +** Function: UAMP_Open +** +** Description: Open connection to local AMP device. +** +** Parameters app_id: Application specific AMP identifer. This value +** will be included in AMP messages sent to the +** BTU task, to identify source of the message +** +****************************************************************************** +*/ +BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id); + +/***************************************************************************** +** +** Function: UAMP_Close +** +** Description: Close connection to local AMP device. +** +** Parameters app_id: Application specific AMP identifer. +** +****************************************************************************** +*/ +BT_API void UAMP_Close(tUAMP_ID amp_id); + + +/***************************************************************************** +** +** Function: UAMP_Write +** +** Description: Send buffer to AMP device. Frees GKI buffer when done. +** +** +** Parameters: app_id: AMP identifer. +** p_buf: pointer to buffer to write +** num_bytes: number of bytes to write +** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD +** +** Returns: number of bytes written +** +****************************************************************************** +*/ +BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel); + +/***************************************************************************** +** +** Function: UAMP_Read +** +** Description: Read incoming data from AMP. Call after receiving a +** UAMP_EVT_RX_READY callback event. +** +** Parameters: app_id: AMP identifer. +** p_buf: pointer to buffer for holding incoming AMP data +** buf_size: size of p_buf +** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT +** +** Returns: number of bytes read +** +****************************************************************************** +*/ +BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel); + +#ifdef __cplusplus +} +#endif + +#endif /* UAMP_API_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c new file mode 100644 index 000000000000..a9a1196dc5a5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c @@ -0,0 +1,3190 @@ +/* + * Linux cfg80211 driver - Android related functions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_android.c 701287 2017-05-24 10:33:19Z $ + */ + +#include +#include +#include +#ifdef CONFIG_COMPAT +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef PNO_SUPPORT +#include +#endif +#ifdef BCMSDIO +#include +#endif +#ifdef WL_CFG80211 +#include +#endif + +/* + * Android private command strings, PLEASE define new private commands here + * so they can be updated easily in the future (if needed) + */ + +#define CMD_START "START" +#define CMD_STOP "STOP" +#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" +#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" +#define CMD_RSSI "RSSI" +#define CMD_LINKSPEED "LINKSPEED" +#ifdef PKT_FILTER_SUPPORT +#define CMD_RXFILTER_START "RXFILTER-START" +#define CMD_RXFILTER_STOP "RXFILTER-STOP" +#define CMD_RXFILTER_ADD "RXFILTER-ADD" +#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" +#endif /* PKT_FILTER_SUPPORT */ +#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" +#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" +#define CMD_BTCOEXMODE "BTCOEXMODE" +#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" +#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" +#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" +#define CMD_SETFWPATH "SETFWPATH" +#define CMD_SETBAND "SETBAND" +#define CMD_GETBAND "GETBAND" +#define CMD_COUNTRY "COUNTRY" +#define CMD_P2P_SET_NOA "P2P_SET_NOA" +#if !defined WL_ENABLE_P2P_IF +#define CMD_P2P_GET_NOA "P2P_GET_NOA" +#endif /* WL_ENABLE_P2P_IF */ +#define CMD_P2P_SD_OFFLOAD "P2P_SD_" +#define CMD_P2P_SET_PS "P2P_SET_PS" +#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" +#define CMD_SETROAMMODE "SETROAMMODE" +#define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA" +#define CMD_MIRACAST "MIRACAST" +#define CMD_NAN "NAN_" + +#if defined(WL_SUPPORT_AUTO_CHANNEL) +#define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS" +#endif /* WL_SUPPORT_AUTO_CHANNEL */ + + +#define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */ +#define CMD_CHANSPEC "CHANSPEC" +#define CMD_DATARATE "DATARATE" +#define CMD_ASSOC_CLIENTS "ASSOCLIST" +#define CMD_SET_CSA "SETCSA" + +#define CMD_KEEP_ALIVE "KEEPALIVE" + +#ifdef BCMCCX +/* CCX Private Commands */ +#define CMD_GETCCKM_RN "get cckm_rn" +#define CMD_SETCCKM_KRK "set cckm_krk" +#define CMD_GET_ASSOC_RES_IES "get assoc_res_ies" +#endif + +#ifdef PNO_SUPPORT +#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" +#define CMD_PNOSETUP_SET "PNOSETUP " +#define CMD_PNOENABLE_SET "PNOFORCE" +#define CMD_PNODEBUG_SET "PNODEBUG" +#define CMD_WLS_BATCHING "WLS_BATCHING" +#endif /* PNO_SUPPORT */ + +#define CMD_OKC_SET_PMK "SET_PMK" +#define CMD_OKC_ENABLE "OKC_ENABLE" + +#define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER" + +#ifdef WLFBT +#define CMD_GET_FTKEY "GET_FTKEY" +#endif + +#ifdef WLAIBSS +#define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT" +#define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO" +#define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL" +#define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE" +#define CMD_SETIBSSAMPDU "SETIBSSAMPDU" +#define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE" +#endif /* WLAIBSS */ + +#define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD" +#define CMD_ROAM_OFFLOAD_APLIST "SETROAMOFFLAPLIST" +#define CMD_GET_LINK_STATUS "GETLINKSTATUS" + + +#ifdef SET_RPS_CPUS +#define CMD_RPSMODE "RPSMODE" +#endif /* SET_RPS_CPUS */ + +/* related with CMD_GET_LINK_STATUS */ +#define WL_ANDROID_LINK_VHT 0x01 +#define WL_ANDROID_LINK_MIMO 0x02 +#define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04 +#define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08 + +/* miracast related definition */ +#define MIRACAST_MODE_OFF 0 +#define MIRACAST_MODE_SOURCE 1 +#define MIRACAST_MODE_SINK 2 + +#ifndef MIRACAST_AMPDU_SIZE +#define MIRACAST_AMPDU_SIZE 8 +#endif + +#ifndef MIRACAST_MCHAN_ALGO +#define MIRACAST_MCHAN_ALGO 1 +#endif + +#ifndef MIRACAST_MCHAN_BW +#define MIRACAST_MCHAN_BW 25 +#endif + +#ifdef CHANGE_SCAN_TIME +static int miracast_scan_time[3][2] = { + { WLC_GET_SCAN_CHANNEL_TIME, 20 }, + { WLC_GET_SCAN_UNASSOC_TIME, 20 }, + { WLC_GET_SCAN_PASSIVE_TIME, 40 } + }; +#endif + +#ifdef CONNECTION_STATISTICS +#define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS" + +struct connection_stats { + u32 txframe; + u32 txbyte; + u32 txerror; + u32 rxframe; + u32 rxbyte; + u32 txfail; + u32 txretry; + u32 txretrie; + u32 txrts; + u32 txnocts; + u32 txexptime; + u32 txrate; + u8 chan_idle; +}; +#endif /* CONNECTION_STATISTICS */ + +static LIST_HEAD(miracast_resume_list); +static u8 miracast_cur_mode; + +struct io_cfg { + s8 *iovar; + s32 param; + u32 ioctl; + void *arg; + u32 len; + struct list_head list; +}; + +typedef struct _android_wifi_priv_cmd { + char *buf; + int used_len; + int total_len; +} android_wifi_priv_cmd; + +#ifdef CONFIG_COMPAT +typedef struct _compat_android_wifi_priv_cmd { + compat_caddr_t buf; + int used_len; + int total_len; +} compat_android_wifi_priv_cmd; +#endif /* CONFIG_COMPAT */ + +#if defined(BCMFW_ROAM_ENABLE) +#define CMD_SET_ROAMPREF "SET_ROAMPREF" + +#define MAX_NUM_SUITES 10 +#define WIDTH_AKM_SUITE 8 +#define JOIN_PREF_RSSI_LEN 0x02 +#define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */ +#define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */ +#define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */ +#define JOIN_PREF_MAX_WPA_TUPLES 16 +#define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \ + (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES)) +#endif /* BCMFW_ROAM_ENABLE */ + +#ifdef WL_GENL +static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info); +static int wl_genl_init(void); +static int wl_genl_deinit(void); + +extern struct net init_net; +/* attribute policy: defines which attribute has which type (e.g int, char * etc) + * possible values defined in net/netlink.h + */ +static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = { + [BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING }, + [BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY }, +}; + +#define WL_GENL_VER 1 +/* family definition */ +static struct genl_family wl_genl_family = { + .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */ + .hdrsize = 0, + .name = "bcm-genl", /* Netlink I/F for Android */ + .version = WL_GENL_VER, /* Version Number */ + .maxattr = BCM_GENL_ATTR_MAX, +}; + +/* commands: mapping between the command enumeration and the actual function */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) +struct genl_ops wl_genl_ops[] = { + { + .cmd = BCM_GENL_CMD_MSG, + .flags = 0, + .policy = wl_genl_policy, + .doit = wl_genl_handle_msg, + .dumpit = NULL, + }, +}; +#else +struct genl_ops wl_genl_ops = { + .cmd = BCM_GENL_CMD_MSG, + .flags = 0, + .policy = wl_genl_policy, + .doit = wl_genl_handle_msg, + .dumpit = NULL, + +}; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) +static struct genl_multicast_group wl_genl_mcast[] = { + { .name = "bcm-genl-mcast", }, +}; +#else +static struct genl_multicast_group wl_genl_mcast = { + .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */ + .name = "bcm-genl-mcast", +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */ +#endif /* WL_GENL */ + +/** + * Extern function declarations (TODO: move them to dhd_linux.h) + */ +int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); +int dhd_dev_init_ioctl(struct net_device *dev); +#ifdef WL_CFG80211 +int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); +int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command); +#else +int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) +{ return 0; } +int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) +{ return 0; } +int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) +{ return 0; } +int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) +{ return 0; } +#endif /* WK_CFG80211 */ + + +#ifdef ENABLE_4335BT_WAR +extern int bcm_bt_lock(int cookie); +extern void bcm_bt_unlock(int cookie); +static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ +#endif /* ENABLE_4335BT_WAR */ + +extern bool ap_fw_loaded; +#if defined(CUSTOMER_HW2) +extern char iface_name[IFNAMSIZ]; +#endif + +/** + * Local (static) functions and variables + */ + +/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first + * time (only) in dhd_open, subsequential wifi on will be handled by + * wl_android_wifi_on + */ +static int g_wifi_on = TRUE; + +/** + * Local (static) function definitions + */ +static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) +{ + int link_speed; + int bytes_written; + int error; + + error = wldev_get_link_speed(net, &link_speed); + if (error) + return -1; + + /* Convert Kbps to Android Mbps */ + link_speed = link_speed / 1000; + bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); + DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); + return bytes_written; +} + +static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) +{ + wlc_ssid_t ssid = {0}; + int bytes_written = 0; + int error = 0; + scb_val_t scbval; + char *delim = NULL; + + + delim = strchr(command, ' '); + /* For Ap mode rssi command would be + * driver rssi + * for STA/GC mode + * driver rssi + */ + if (delim) { + /* Ap/GO mode + * driver rssi + */ + DHD_TRACE(("%s: cmd:%s\n", __FUNCTION__, delim)); + /* skip space from delim after finding char */ + delim++; + if (!(bcm_ether_atoe((delim), &scbval.ea))) { + + DHD_ERROR(("%s:address err\n", __FUNCTION__)); + return -1; + } + scbval.val = htod32(0); + DHD_TRACE(("%s: address:"MACDBG, __FUNCTION__, MAC2STRDBG(scbval.ea.octet))); + } + else { + memset(&scbval, 0, sizeof(scb_val_t)); + } + + error = wldev_get_rssi(net, &scbval); + if (error) + return -1; + + error = wldev_get_ssid(net, &ssid); + if (error) + return -1; + if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { + DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); + } else if (total_len <= ssid.SSID_len) { + return -ENOMEM; + } else { + memcpy(command, ssid.SSID, ssid.SSID_len); + bytes_written = ssid.SSID_len; + } + if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1)) + return -ENOMEM; + + bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written, + " rssi %d", scbval.val); + command[bytes_written] = '\0'; + + DHD_TRACE(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); + return bytes_written; +} + +static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) +{ + int suspend_flag; + int ret_now; + int ret = 0; + + suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; + + if (suspend_flag != 0) + suspend_flag = 1; + ret_now = net_os_set_suspend_disable(dev, suspend_flag); + + if (ret_now != suspend_flag) { + if (!(ret = net_os_set_suspend(dev, ret_now, 1))) + DHD_INFO(("%s: Suspend Flag %d -> %d\n", + __FUNCTION__, ret_now, suspend_flag)); + else + DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); + } + return ret; +} + +static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) +{ + int ret = 0; + +#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) + int suspend_flag; + + suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; + if (suspend_flag != 0) + suspend_flag = 1; + + if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) + DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag)); + else + DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); +#endif + + return ret; +} + +int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len) +{ + uint8 mode[4]; + int error = 0; + int bytes_written = 0; + + error = wldev_get_mode(dev, mode); + if (error) + return -1; + + DHD_INFO(("%s: mode:%s\n", __FUNCTION__, mode)); + bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode); + DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command)); + return bytes_written; + +} + +extern chanspec_t +wl_chspec_driver_to_host(chanspec_t chanspec); +int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int bytes_written = 0; + int chsp = {0}; + uint16 band = 0; + uint16 bw = 0; + uint16 channel = 0; + u32 sb = 0; + chanspec_t chanspec; + + /* command is + * driver chanspec + */ + error = wldev_iovar_getint(dev, "chanspec", &chsp); + if (error) + return -1; + + chanspec = wl_chspec_driver_to_host(chsp); + DHD_INFO(("%s:return value of chanspec:%x\n", __FUNCTION__, chanspec)); + + channel = chanspec & WL_CHANSPEC_CHAN_MASK; + band = chanspec & WL_CHANSPEC_BAND_MASK; + bw = chanspec & WL_CHANSPEC_BW_MASK; + + DHD_INFO(("%s:channel:%d band:%d bandwidth:%d\n", __FUNCTION__, channel, band, bw)); + + if (bw == WL_CHANSPEC_BW_80) + bw = WL_CH_BANDWIDTH_80MHZ; + else if (bw == WL_CHANSPEC_BW_40) + bw = WL_CH_BANDWIDTH_40MHZ; + else if (bw == WL_CHANSPEC_BW_20) + bw = WL_CH_BANDWIDTH_20MHZ; + else + bw = WL_CH_BANDWIDTH_20MHZ; + + if (bw == WL_CH_BANDWIDTH_40MHZ) { + if (CHSPEC_SB_UPPER(chanspec)) { + channel += CH_10MHZ_APART; + } else { + channel -= CH_10MHZ_APART; + } + } + else if (bw == WL_CH_BANDWIDTH_80MHZ) { + sb = chanspec & WL_CHANSPEC_CTL_SB_MASK; + if (sb == WL_CHANSPEC_CTL_SB_LL) { + channel -= (CH_10MHZ_APART + CH_20MHZ_APART); + } else if (sb == WL_CHANSPEC_CTL_SB_LU) { + channel -= CH_10MHZ_APART; + } else if (sb == WL_CHANSPEC_CTL_SB_UL) { + channel += CH_10MHZ_APART; + } else { + /* WL_CHANSPEC_CTL_SB_UU */ + channel += (CH_10MHZ_APART + CH_20MHZ_APART); + } + } + bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC, + channel, band == WL_CHANSPEC_BAND_5G ? "5G":"2G", bw); + + DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command)); + return bytes_written; + +} + +/* returns current datarate datarate returned from firmware are in 500kbps */ +int wl_android_get_datarate(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int datarate = 0; + int bytes_written = 0; + + error = wldev_get_datarate(dev, &datarate); + if (error) + return -1; + + DHD_INFO(("%s:datarate:%d\n", __FUNCTION__, datarate)); + + bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2)); + return bytes_written; +} +int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int bytes_written = 0; + uint i; + char mac_buf[MAX_NUM_OF_ASSOCLIST * + sizeof(struct ether_addr) + sizeof(uint)] = {0}; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; + + DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); + + assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST); + + error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf)); + if (error) + return -1; + + assoc_maclist->count = dtoh32(assoc_maclist->count); + bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:", + CMD_ASSOC_CLIENTS, assoc_maclist->count); + + for (i = 0; i < assoc_maclist->count; i++) { + bytes_written += snprintf(command + bytes_written, total_len, " " MACDBG, + MAC2STRDBG(assoc_maclist->ea[i].octet)); + } + return bytes_written; + +} +extern chanspec_t +wl_chspec_host_to_driver(chanspec_t chanspec); +static int wl_android_set_csa(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + char smbuf[WLC_IOCTL_SMLEN]; + wl_chan_switch_t csa_arg; + char buf[32]; + u32 chnsp = 0; + int err = 0; + + DHD_INFO(("%s: command:%s\n", __FUNCTION__, command)); + + command = (command + strlen(CMD_SET_CSA)); + /* Order is mode, count channel */ + if (!*++command) { + DHD_ERROR(("%s:error missing arguments\n", __FUNCTION__)); + return -1; + } + csa_arg.mode = bcm_atoi(command); + if (csa_arg.mode != 0 && csa_arg.mode != 1) { + DHD_ERROR(("Invalid mode\n")); + return -1; + } if (!*++command) { + DHD_ERROR(("%s:error missing count\n", __FUNCTION__)); + return -1; + } + command++; + csa_arg.count = bcm_atoi(command); + if (!*++command) { + DHD_ERROR(("%s:error missing channel\n", __FUNCTION__)); + return -1; + } + csa_arg.reg = 0; + csa_arg.chspec = 0; + command += 2; + if (sizeof(buf) > strlen(command)) + bcm_strncpy_s(buf, sizeof(buf), command, strlen(command)); + else { + DHD_ERROR(("%s:command is not valid\n", __FUNCTION__)); + return -1; + } + chnsp = wf_chspec_aton(buf); + if (chnsp == 0) { + DHD_ERROR(("%s:chsp is not correct\n", __FUNCTION__)); + return -1; + } + chnsp = wl_chspec_host_to_driver(chnsp); + csa_arg.chspec = chnsp; + + if (chnsp & WL_CHANSPEC_BAND_5G) { + u32 chanspec = chnsp; + err = wldev_iovar_getint(dev, "per_chan_info", &chanspec); + if (!err) { + if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) { + DHD_ERROR(("Channel is radar sensitive\n")); + return -1; + } + if (chanspec == 0) { + DHD_ERROR(("Invalid hw channel\n")); + return -1; + } + } else { + DHD_ERROR(("does not support per_chan_info\n")); + return -1; + } + DHD_INFO(("non radar sensitivity\n")); + } + error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg), + smbuf, sizeof(smbuf), NULL); + if (error) { + DHD_ERROR(("%s:set csa failed:%d\n", __FUNCTION__, error)); + return -1; + } + return 0; +} +static int wl_android_get_band(struct net_device *dev, char *command, int total_len) +{ + uint band; + int bytes_written; + int error; + + error = wldev_get_band(dev, &band); + if (error) + return -1; + bytes_written = snprintf(command, total_len, "Band %d", band); + return bytes_written; +} + + +#ifdef PNO_SUPPORT +#define PNO_PARAM_SIZE 50 +#define VALUE_SIZE 50 +#define LIMIT_STR_FMT ("%50s %50s") +static int +wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) +{ + int err = BCME_OK; + uint i, tokens; + char *pos, *pos2, *token, *token2, *delim; + char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1]; + struct dhd_pno_batch_params batch_params; + DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + if (total_len < strlen(CMD_WLS_BATCHING)) { + DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); + err = BCME_ERROR; + goto exit; + } + pos = command + strlen(CMD_WLS_BATCHING) + 1; + memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params)); + + if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) { + pos += strlen(PNO_BATCHING_SET) + 1; + while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) { + memset(param, 0, sizeof(param)); + memset(value, 0, sizeof(value)); + if (token == NULL || !*token) + break; + if (*token == '\0') + continue; + delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER); + if (delim != NULL) + *delim = ' '; + + tokens = sscanf(token, LIMIT_STR_FMT, param, value); + if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) { + batch_params.scan_fr = simple_strtol(value, NULL, 0); + DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr)); + } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) { + batch_params.bestn = simple_strtol(value, NULL, 0); + DHD_PNO(("bestn : %d\n", batch_params.bestn)); + } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) { + batch_params.mscan = simple_strtol(value, NULL, 0); + DHD_PNO(("mscan : %d\n", batch_params.mscan)); + } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) { + i = 0; + pos2 = value; + tokens = sscanf(value, "<%s>", value); + if (tokens != 1) { + err = BCME_ERROR; + DHD_ERROR(("%s : invalid format for channel" + " <> params\n", __FUNCTION__)); + goto exit; + } + while ((token2 = strsep(&pos2, + PNO_PARAM_CHANNEL_DELIMETER)) != NULL) { + if (token2 == NULL || !*token2) + break; + if (*token2 == '\0') + continue; + if (*token2 == 'A' || *token2 == 'B') { + batch_params.band = (*token2 == 'A')? + WLC_BAND_5G : WLC_BAND_2G; + DHD_PNO(("band : %s\n", + (*token2 == 'A')? "A" : "B")); + } else { + if ((batch_params.nchan >= WL_NUMCHANNELS) || + (i >= WL_NUMCHANNELS)) { + DHD_ERROR(("Too many nchan %d\n", + batch_params.nchan)); + err = BCME_BUFTOOSHORT; + goto exit; + } + batch_params.chan_list[i++] = + simple_strtol(token2, NULL, 0); + batch_params.nchan++; + DHD_PNO(("channel :%d\n", + batch_params.chan_list[i-1])); + } + } + } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) { + batch_params.rtt = simple_strtol(value, NULL, 0); + DHD_PNO(("rtt : %d\n", batch_params.rtt)); + } else { + DHD_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param)); + err = BCME_ERROR; + goto exit; + } + } + err = dhd_dev_pno_set_for_batch(dev, &batch_params); + if (err < 0) { + DHD_ERROR(("failed to configure batch scan\n")); + } else { + memset(command, 0, total_len); + err = sprintf(command, "%d", err); + } + } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) { + err = dhd_dev_pno_get_for_batch(dev, command, total_len); + if (err < 0) { + DHD_ERROR(("failed to getting batching results\n")); + } else { + err = strlen(command); + } + } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) { + err = dhd_dev_pno_stop_for_batch(dev); + if (err < 0) { + DHD_ERROR(("failed to stop batching scan\n")); + } else { + memset(command, 0, total_len); + err = sprintf(command, "OK"); + } + } else { + DHD_ERROR(("%s : unknown command\n", __FUNCTION__)); + err = BCME_ERROR; + goto exit; + } +exit: + return err; +} +#ifndef WL_SCHED_SCAN +static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) +{ + wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; + int res = -1; + int nssid = 0; + cmd_tlv_t *cmd_tlv_temp; + char *str_ptr; + int tlv_size_left; + int pno_time = 0; + int pno_repeat = 0; + int pno_freq_expo_max = 0; + +#ifdef PNO_SET_DEBUG + int i; + char pno_in_example[] = { + 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', + 'S', '1', '2', '0', + 'S', + 0x05, + 'd', 'l', 'i', 'n', 'k', + 'S', + 0x04, + 'G', 'O', 'O', 'G', + 'T', + '0', 'B', + 'R', + '2', + 'M', + '2', + 0x00 + }; +#endif /* PNO_SET_DEBUG */ + DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + + if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { + DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); + goto exit_proc; + } +#ifdef PNO_SET_DEBUG + memcpy(command, pno_in_example, sizeof(pno_in_example)); + total_len = sizeof(pno_in_example); +#endif + str_ptr = command + strlen(CMD_PNOSETUP_SET); + tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); + + cmd_tlv_temp = (cmd_tlv_t *)str_ptr; + memset(ssids_local, 0, sizeof(ssids_local)); + + if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && + (cmd_tlv_temp->version == PNO_TLV_VERSION) && + (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) { + + str_ptr += sizeof(cmd_tlv_t); + tlv_size_left -= sizeof(cmd_tlv_t); + + if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local, + MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { + DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); + goto exit_proc; + } else { + if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { + DHD_ERROR(("%s scan duration corrupted field size %d\n", + __FUNCTION__, tlv_size_left)); + goto exit_proc; + } + str_ptr++; + pno_time = simple_strtoul(str_ptr, &str_ptr, 16); + DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); + + if (str_ptr[0] != 0) { + if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { + DHD_ERROR(("%s pno repeat : corrupted field\n", + __FUNCTION__)); + goto exit_proc; + } + str_ptr++; + pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); + DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); + if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { + DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", + __FUNCTION__)); + goto exit_proc; + } + str_ptr++; + pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); + DHD_PNO(("%s: pno_freq_expo_max=%d\n", + __FUNCTION__, pno_freq_expo_max)); + } + } + } else { + DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); + goto exit_proc; + } + + res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat, + pno_freq_expo_max, NULL, 0); +exit_proc: + return res; +} +#endif /* !WL_SCHED_SCAN */ +#endif /* PNO_SUPPORT */ + +static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) +{ + int ret; + int bytes_written = 0; + + ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command); + if (ret) + return 0; + bytes_written = sizeof(struct ether_addr); + return bytes_written; +} + +#ifdef BCMCCX +static int wl_android_get_cckm_rn(struct net_device *dev, char *command) +{ + int error, rn; + + WL_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name)); + + error = wldev_iovar_getint(dev, "cckm_rn", &rn); + if (unlikely(error)) { + WL_ERR(("wl_android_get_cckm_rn error (%d)\n", error)); + return -1; + } + memcpy(command, &rn, sizeof(int)); + + return sizeof(int); +} + +static int wl_android_set_cckm_krk(struct net_device *dev, char *command) +{ + int error; + unsigned char key[16]; + static char iovar_buf[WLC_IOCTL_MEDLEN]; + + WL_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name)); + + memset(iovar_buf, 0, sizeof(iovar_buf)); + memcpy(key, command+strlen("set cckm_krk")+1, 16); + + error = wldev_iovar_setbuf(dev, "cckm_krk", key, sizeof(key), + iovar_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(error)) + { + WL_ERR((" cckm_krk set error (%d)\n", error)); + return -1; + } + return 0; +} + +static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command) +{ + int error; + u8 buf[WL_ASSOC_INFO_MAX]; + wl_assoc_info_t assoc_info; + u32 resp_ies_len = 0; + int bytes_written = 0; + + WL_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name)); + + error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf, WL_ASSOC_INFO_MAX, NULL); + if (unlikely(error)) { + WL_ERR(("could not get assoc info (%d)\n", error)); + return -1; + } + + memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t)); + assoc_info.req_len = htod32(assoc_info.req_len); + assoc_info.resp_len = htod32(assoc_info.resp_len); + assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.resp_len) { + resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + } + + /* first 4 bytes are ie len */ + memcpy(command, &resp_ies_len, sizeof(u32)); + bytes_written = sizeof(u32); + + /* get the association resp IE's if there are any */ + if (resp_ies_len) { + error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0, + buf, WL_ASSOC_INFO_MAX, NULL); + if (unlikely(error)) { + WL_ERR(("could not get assoc resp_ies (%d)\n", error)); + return -1; + } + + memcpy(command+sizeof(u32), buf, resp_ies_len); + bytes_written += resp_ies_len; + } + return bytes_written; +} + +#endif /* BCMCCX */ + +int +wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist) +{ + int i, j, match; + int ret = 0; + char mac_buf[MAX_NUM_OF_ASSOCLIST * + sizeof(struct ether_addr) + sizeof(uint)] = {0}; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; + + /* set filtering mode */ + if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode))) != 0) { + DHD_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret)); + return ret; + } + if (macmode != MACLIST_MODE_DISABLED) { + /* set the MAC filter list */ + if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist, + sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) { + DHD_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret)); + return ret; + } + /* get the current list of associated STAs */ + assoc_maclist->count = MAX_NUM_OF_ASSOCLIST; + if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, + sizeof(mac_buf))) != 0) { + DHD_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret)); + return ret; + } + /* do we have any STA associated? */ + if (assoc_maclist->count) { + /* iterate each associated STA */ + for (i = 0; i < assoc_maclist->count; i++) { + match = 0; + /* compare with each entry */ + for (j = 0; j < maclist->count; j++) { + DHD_INFO(("%s : associated="MACDBG " list="MACDBG "\n", + __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet), + MAC2STRDBG(maclist->ea[j].octet))); + if (memcmp(assoc_maclist->ea[i].octet, + maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) { + match = 1; + break; + } + } + /* do conditional deauth */ + /* "if not in the allow list" or "if in the deny list" */ + if ((macmode == MACLIST_MODE_ALLOW && !match) || + (macmode == MACLIST_MODE_DENY && match)) { + scb_val_t scbval; + + scbval.val = htod32(1); + memcpy(&scbval.ea, &assoc_maclist->ea[i], + ETHER_ADDR_LEN); + if ((ret = wldev_ioctl_set(dev, + WLC_SCB_DEAUTHENTICATE_FOR_REASON, + &scbval, sizeof(scb_val_t))) != 0) + DHD_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n", + __FUNCTION__, ret)); + } + } + } + } + return ret; +} + +/* + * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2 + * + */ +static int +wl_android_set_mac_address_filter(struct net_device *dev, const char* str) +{ + int i; + int ret = 0; + int macnum = 0; + int macmode = MACLIST_MODE_DISABLED; + struct maclist *list; + char eabuf[ETHER_ADDR_STR_LEN]; + + /* string should look like below (macmode/macnum/maclist) */ + /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */ + + /* get the MAC filter mode */ + macmode = bcm_atoi(strsep((char**)&str, " ")); + + if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) { + DHD_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode)); + return -1; + } + + macnum = bcm_atoi(strsep((char**)&str, " ")); + if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { + DHD_ERROR(("%s : invalid number of MAC address entries %d\n", + __FUNCTION__, macnum)); + return -1; + } + /* allocate memory for the MAC list */ + list = (struct maclist*)kmalloc(sizeof(int) + + sizeof(struct ether_addr) * macnum, GFP_KERNEL); + if (!list) { + DHD_ERROR(("%s : failed to allocate memory\n", __FUNCTION__)); + return -1; + } + /* prepare the MAC list */ + list->count = htod32(macnum); + bzero((char *)eabuf, ETHER_ADDR_STR_LEN); + for (i = 0; i < list->count; i++) { + strncpy(eabuf, strsep((char**)&str, " "), ETHER_ADDR_STR_LEN - 1); + if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) { + DHD_ERROR(("%s : mac parsing err index=%d, addr=%s\n", + __FUNCTION__, i, eabuf)); + list->count--; + break; + } + DHD_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf)); + } + /* set the list */ + if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0) + DHD_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); + + kfree(list); + + return 0; +} + +/** + * Global function definitions (declared in wl_android.h) + */ + +int wl_android_wifi_on(struct net_device *dev) +{ + int ret = 0; +#ifdef CONFIG_MACH_UNIVERSAL5433 + int retry; + /* Do not retry old revision Helsinki Prime */ + if (!check_rev()) { + retry = 1; + } else { + retry = POWERUP_MAX_RETRY; + } +#else + int retry = POWERUP_MAX_RETRY; +#endif /* CONFIG_MACH_UNIVERSAL5433 */ + + DHD_ERROR(("%s in\n", __FUNCTION__)); + if (!dev) { + DHD_ERROR(("%s: dev is null\n", __FUNCTION__)); + return -EINVAL; + } + + dhd_net_if_lock(dev); + if (!g_wifi_on) { + do { + dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY); +#ifdef BCMSDIO + ret = dhd_net_bus_resume(dev, 0); +#endif /* BCMSDIO */ +#ifdef BCMPCIE + ret = dhd_net_bus_devreset(dev, FALSE); +#endif /* BCMPCIE */ + if (ret == 0) + break; + DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n", + retry)); +#ifdef BCMPCIE + dhd_net_bus_devreset(dev, TRUE); +#endif /* BCMPCIE */ + dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); + } while (retry-- > 0); + if (ret != 0) { + DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n")); + goto exit; + } +#ifdef BCMSDIO + ret = dhd_net_bus_devreset(dev, FALSE); + dhd_net_bus_resume(dev, 1); +#endif /* BCMSDIO */ + +#ifndef BCMPCIE + if (!ret) { + if (dhd_dev_init_ioctl(dev) < 0) + ret = -EFAULT; + } +#endif /* !BCMPCIE */ + g_wifi_on = TRUE; + } + +exit: + dhd_net_if_unlock(dev); + + return ret; +} + +int wl_android_wifi_off(struct net_device *dev) +{ + int ret = 0; + + DHD_ERROR(("%s in\n", __FUNCTION__)); + if (!dev) { + DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); + return -EINVAL; + } + + dhd_net_if_lock(dev); + if (g_wifi_on) { +#if defined(BCMSDIO) || defined(BCMPCIE) + ret = dhd_net_bus_devreset(dev, TRUE); +#ifdef BCMSDIO + dhd_net_bus_suspend(dev); +#endif /* BCMSDIO */ +#endif /* BCMSDIO || BCMPCIE */ + dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); + g_wifi_on = FALSE; + } + dhd_net_if_unlock(dev); + + return ret; +} + +static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len) +{ + if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN) + return -1; + return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1); +} + +#ifdef CONNECTION_STATISTICS +static int +wl_chanim_stats(struct net_device *dev, u8 *chan_idle) +{ + int err; + wl_chanim_stats_t *list; + /* Parameter _and_ returned buffer of chanim_stats. */ + wl_chanim_stats_t param; + u8 result[WLC_IOCTL_SMLEN]; + chanim_stats_t *stats; + + memset(¶m, 0, sizeof(param)); + + param.buflen = htod32(sizeof(wl_chanim_stats_t)); + param.count = htod32(WL_CHANIM_COUNT_ONE); + + if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)¶m, sizeof(wl_chanim_stats_t), + (char*)result, sizeof(result), 0)) < 0) { + WL_ERR(("Failed to get chanim results %d \n", err)); + return err; + } + + list = (wl_chanim_stats_t*)result; + + list->buflen = dtoh32(list->buflen); + list->version = dtoh32(list->version); + list->count = dtoh32(list->count); + + if (list->buflen == 0) { + list->version = 0; + list->count = 0; + } else if (list->version != WL_CHANIM_STATS_VERSION) { + WL_ERR(("Sorry, firmware has wl_chanim_stats version %d " + "but driver supports only version %d.\n", + list->version, WL_CHANIM_STATS_VERSION)); + list->buflen = 0; + list->count = 0; + } + + stats = list->stats; + stats->glitchcnt = dtoh32(stats->glitchcnt); + stats->badplcp = dtoh32(stats->badplcp); + stats->chanspec = dtoh16(stats->chanspec); + stats->timestamp = dtoh32(stats->timestamp); + stats->chan_idle = dtoh32(stats->chan_idle); + + WL_INFORM(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n", + stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle, + stats->timestamp)); + + *chan_idle = stats->chan_idle; + + return (err); +} + +static int +wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len) +{ + wl_cnt_t* cnt = NULL; +#ifndef DISABLE_IF_COUNTERS + wl_if_stats_t* if_stats = NULL; +#endif /* DISABLE_IF_COUNTERS */ + + int link_speed = 0; + struct connection_stats *output; + unsigned int bufsize = 0; + int bytes_written = -1; + int ret = 0; + + WL_INFORM(("%s: enter Get Connection Stats\n", __FUNCTION__)); + + if (total_len <= 0) { + WL_ERR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len)); + goto error; + } + + bufsize = total_len; + if (bufsize < sizeof(struct connection_stats)) { + WL_ERR(("%s: not enough buffer size, provided=%u, requires=%zu\n", + __FUNCTION__, bufsize, + sizeof(struct connection_stats))); + goto error; + } + + output = (struct connection_stats *)command; + +#ifndef DISABLE_IF_COUNTERS + if ((if_stats = kmalloc(sizeof(*if_stats), GFP_KERNEL)) == NULL) { + WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); + goto error; + } + + ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0, + (char *)if_stats, sizeof(*if_stats), NULL); + if (ret) { + WL_ERR(("%s: if_counters not supported ret=%d\n", + __FUNCTION__, ret)); + + /* In case if_stats IOVAR is not supported, get information from counters. */ +#endif /* DISABLE_IF_COUNTERS */ + if ((cnt = kmalloc(sizeof(*cnt), GFP_KERNEL)) == NULL) { + WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); + goto error; + } + memset(cnt, 0, sizeof(*cnt)); + + ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, + (char *)cnt, sizeof(wl_cnt_t), NULL); + if (ret) { + WL_ERR(("%s: wldev_iovar_getbuf() failed, ret=%d\n", + __FUNCTION__, ret)); + goto error; + } + + if (dtoh16(cnt->version) > WL_CNT_T_VERSION) { + WL_ERR(("%s: incorrect version of wl_cnt_t, expected=%u got=%u\n", + __FUNCTION__, WL_CNT_T_VERSION, cnt->version)); + goto error; + } + + output->txframe = dtoh32(cnt->txframe); + output->txbyte = dtoh32(cnt->txbyte); + output->txerror = dtoh32(cnt->txerror); + output->rxframe = dtoh32(cnt->rxframe); + output->rxbyte = dtoh32(cnt->rxbyte); + output->txfail = dtoh32(cnt->txfail); + output->txretry = dtoh32(cnt->txretry); + output->txretrie = dtoh32(cnt->txretrie); + output->txrts = dtoh32(cnt->txrts); + output->txnocts = dtoh32(cnt->txnocts); + output->txexptime = dtoh32(cnt->txexptime); +#ifndef DISABLE_IF_COUNTERS + } else { + /* Populate from if_stats. */ + if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) { + WL_ERR(("%s: incorrect version of wl_if_stats_t, expected=%u got=%u\n", + __FUNCTION__, WL_IF_STATS_T_VERSION, if_stats->version)); + goto error; + } + + output->txframe = (uint32)dtoh64(if_stats->txframe); + output->txbyte = (uint32)dtoh64(if_stats->txbyte); + output->txerror = (uint32)dtoh64(if_stats->txerror); + output->rxframe = (uint32)dtoh64(if_stats->rxframe); + output->rxbyte = (uint32)dtoh64(if_stats->rxbyte); + output->txfail = (uint32)dtoh64(if_stats->txfail); + output->txretry = (uint32)dtoh64(if_stats->txretry); + output->txretrie = (uint32)dtoh64(if_stats->txretrie); + if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) { + output->txexptime = (uint32)dtoh64(if_stats->txexptime); + output->txrts = (uint32)dtoh64(if_stats->txrts); + output->txnocts = (uint32)dtoh64(if_stats->txnocts); + } else { + output->txexptime = 0; + output->txrts = 0; + output->txnocts = 0; + } + } +#endif /* DISABLE_IF_COUNTERS */ + + /* link_speed is in kbps */ + ret = wldev_get_link_speed(dev, &link_speed); + if (ret || link_speed < 0) { + WL_ERR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n", + __FUNCTION__, ret, link_speed)); + goto error; + } + output->txrate = link_speed; + + /* Channel idle ratio. */ + if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) { + output->chan_idle = 0; + }; + + bytes_written = sizeof(struct connection_stats); + +error: +#ifndef DISABLE_IF_COUNTERS + if (if_stats) { + kfree(if_stats); + } +#endif /* DISABLE_IF_COUNTERS */ + if (cnt) { + kfree(cnt); + } + + return bytes_written; +} +#endif /* CONNECTION_STATISTICS */ + +static int +wl_android_set_pmk(struct net_device *dev, char *command, int total_len) +{ + uchar pmk[33]; + int error = 0; + char smbuf[WLC_IOCTL_SMLEN]; +#ifdef OKC_DEBUG + int i = 0; +#endif + + bzero(pmk, sizeof(pmk)); + memcpy((char *)pmk, command + strlen("SET_PMK "), 32); + error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL); + if (error) { + DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error)); + } +#ifdef OKC_DEBUG + DHD_ERROR(("PMK is ")); + for (i = 0; i < 32; i++) + DHD_ERROR(("%02X ", pmk[i])); + + DHD_ERROR(("\n")); +#endif + return error; +} + +static int +wl_android_okc_enable(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + char okc_enable = 0; + + okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0'; + error = wldev_iovar_setint(dev, "okc_enable", okc_enable); + if (error) { + DHD_ERROR(("Failed to %s OKC, error = %d\n", + okc_enable ? "enable" : "disable", error)); + } + + wldev_iovar_setint(dev, "ccx_enable", 0); + + return error; +} + + + +int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int mode = 0; + + if (sscanf(command, "%*s %d", &mode) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + error = wldev_iovar_setint(dev, "roam_off", mode); + if (error) { + DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n", + __FUNCTION__, mode, error)); + return -1; + } + else + DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n", + __FUNCTION__, mode, error)); + return 0; +} + +int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len) +{ + char ie_buf[VNDR_IE_MAX_LEN]; + char *ioctl_buf = NULL; + char hex[] = "XX"; + char *pcmd = NULL; + int ielen = 0, datalen = 0, idx = 0, tot_len = 0; + vndr_ie_setbuf_t *vndr_ie = NULL; + s32 iecount; + uint32 pktflag; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + s32 err = BCME_OK; + + /* Check the VSIE (Vendor Specific IE) which was added. + * If exist then send IOVAR to delete it + */ + if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) { + return -EINVAL; + } + + pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1; + for (idx = 0; idx < DOT11_OUI_LEN; idx++) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16); + } + pcmd++; + while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16); + datalen++; + } + tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1); + vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags); + if (!vndr_ie) { + WL_ERR(("IE memory alloc failed\n")); + return -ENOMEM; + } + /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ + strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1); + vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Set the IE count - the buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32)); + + /* Set packet flag to indicate that BEACON's will contain this IE */ + pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG); + memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, + sizeof(u32)); + /* Set the IE ID */ + vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID; + + memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf, + DOT11_OUI_LEN); + memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, + &ie_buf[DOT11_OUI_LEN], datalen); + + ielen = DOT11_OUI_LEN + datalen; + vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen; + + ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + if (vndr_ie) { + kfree(vndr_ie); + } + return -ENOMEM; + } + memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */ + err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + + + if (err != BCME_OK) { + err = -EINVAL; + if (vndr_ie) { + kfree(vndr_ie); + } + } + else { + /* do NOT free 'vndr_ie' for the next process */ + wl_cfg80211_ibss_vsie_set_buffer(vndr_ie, tot_len); + } + + if (ioctl_buf) { + kfree(ioctl_buf); + } + + return err; +} + +#if defined(BCMFW_ROAM_ENABLE) +static int +wl_android_set_roampref(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + char smbuf[WLC_IOCTL_SMLEN]; + uint8 buf[MAX_BUF_SIZE]; + uint8 *pref = buf; + char *pcmd; + int num_ucipher_suites = 0; + int num_akm_suites = 0; + wpa_suite_t ucipher_suites[MAX_NUM_SUITES]; + wpa_suite_t akm_suites[MAX_NUM_SUITES]; + int num_tuples = 0; + int total_bytes = 0; + int total_len_left; + int i, j; + char hex[] = "XX"; + + pcmd = command + strlen(CMD_SET_ROAMPREF) + 1; + total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1; + + num_akm_suites = simple_strtoul(pcmd, NULL, 16); + if (num_akm_suites > MAX_NUM_SUITES) { + DHD_ERROR(("too many AKM suites = %d\n", num_akm_suites)); + return -1; + } + + /* Increment for number of AKM suites field + space */ + pcmd += 3; + total_len_left -= 3; + + /* check to make sure pcmd does not overrun */ + if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE)) + return -1; + + memset(buf, 0, sizeof(buf)); + memset(akm_suites, 0, sizeof(akm_suites)); + memset(ucipher_suites, 0, sizeof(ucipher_suites)); + + /* Save the AKM suites passed in the command */ + for (i = 0; i < num_akm_suites; i++) { + /* Store the MSB first, as required by join_pref */ + for (j = 0; j < 4; j++) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + buf[j] = (uint8)simple_strtoul(hex, NULL, 16); + } + memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32)); + } + + total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); + num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); + /* Increment for number of cipher suites field + space */ + pcmd += 3; + total_len_left -= 3; + + if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE)) + return -1; + + /* Save the cipher suites passed in the command */ + for (i = 0; i < num_ucipher_suites; i++) { + /* Store the MSB first, as required by join_pref */ + for (j = 0; j < 4; j++) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + buf[j] = (uint8)simple_strtoul(hex, NULL, 16); + } + memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32)); + } + + /* Join preference for RSSI + * Type : 1 byte (0x01) + * Length : 1 byte (0x02) + * Value : 2 bytes (reserved) + */ + *pref++ = WL_JOIN_PREF_RSSI; + *pref++ = JOIN_PREF_RSSI_LEN; + *pref++ = 0; + *pref++ = 0; + + /* Join preference for WPA + * Type : 1 byte (0x02) + * Length : 1 byte (not used) + * Value : (variable length) + * reserved: 1 byte + * count : 1 byte (no of tuples) + * Tuple1 : 12 bytes + * akm[4] + * ucipher[4] + * mcipher[4] + * Tuple2 : 12 bytes + * Tuplen : 12 bytes + */ + num_tuples = num_akm_suites * num_ucipher_suites; + if (num_tuples != 0) { + if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) { + *pref++ = WL_JOIN_PREF_WPA; + *pref++ = 0; + *pref++ = 0; + *pref++ = (uint8)num_tuples; + total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + + (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples); + } else { + DHD_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__)); + return -1; + } + } else { + /* No WPA config, configure only RSSI preference */ + total_bytes = JOIN_PREF_RSSI_SIZE; + } + + /* akm-ucipher-mcipher tuples in the format required for join_pref */ + for (i = 0; i < num_ucipher_suites; i++) { + for (j = 0; j < num_akm_suites; j++) { + memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN); + pref += WPA_SUITE_LEN; + memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN); + pref += WPA_SUITE_LEN; + /* Set to 0 to match any available multicast cipher */ + memset(pref, 0, WPA_SUITE_LEN); + pref += WPA_SUITE_LEN; + } + } + + prhex("join pref", (uint8 *)buf, total_bytes); + error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL); + if (error) { + DHD_ERROR(("Failed to set join_pref, error = %d\n", error)); + } + return error; +} +#endif /* defined(BCMFW_ROAM_ENABLE */ + +static int +wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config) +{ + struct io_cfg *resume_cfg; + s32 ret; + + resume_cfg = kzalloc(sizeof(struct io_cfg), GFP_KERNEL); + if (!resume_cfg) + return -ENOMEM; + + if (config->iovar) { + ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param); + if (ret) { + DHD_ERROR(("%s: Failed to get current %s value\n", + __FUNCTION__, config->iovar)); + goto error; + } + + ret = wldev_iovar_setint(dev, config->iovar, config->param); + if (ret) { + DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, + config->iovar, config->param)); + goto error; + } + + resume_cfg->iovar = config->iovar; + } else { + resume_cfg->arg = kzalloc(config->len, GFP_KERNEL); + if (!resume_cfg->arg) { + ret = -ENOMEM; + goto error; + } + ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len); + if (ret) { + DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__, + config->ioctl)); + goto error; + } + ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len); + if (ret) { + DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, + config->iovar, config->param)); + goto error; + } + if (config->ioctl + 1 == WLC_SET_PM) + wl_cfg80211_update_power_mode(dev); + resume_cfg->ioctl = config->ioctl; + resume_cfg->len = config->len; + } + + list_add(&resume_cfg->list, head); + + return 0; +error: + kfree(resume_cfg->arg); + kfree(resume_cfg); + return ret; +} + +static void +wl_android_iolist_resume(struct net_device *dev, struct list_head *head) +{ + struct io_cfg *config; + struct list_head *cur, *q; + s32 ret = 0; + + list_for_each_safe(cur, q, head) { + config = list_entry(cur, struct io_cfg, list); + if (config->iovar) { + if (!ret) + ret = wldev_iovar_setint(dev, config->iovar, + config->param); + } else { + if (!ret) + ret = wldev_ioctl_set(dev, config->ioctl + 1, + config->arg, config->len); + if (config->ioctl + 1 == WLC_SET_PM) + wl_cfg80211_update_power_mode(dev); + kfree(config->arg); + } + list_del(cur); + kfree(config); + } +} + +static int +wl_android_set_miracast(struct net_device *dev, char *command, int total_len) +{ + int mode, val = 0; + int ret = 0; + struct io_cfg config; +#ifdef CHANGE_SCAN_TIME + int i; +#endif + + if (sscanf(command, "%*s %d", &mode) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + DHD_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode)); + + if (miracast_cur_mode == mode) { + return 0; + } + + wl_android_iolist_resume(dev, &miracast_resume_list); + miracast_cur_mode = MIRACAST_MODE_OFF; + + switch (mode) { + case MIRACAST_MODE_SOURCE: + /* setting mchan_algo to platform specific value */ + config.iovar = "mchan_algo"; + + ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int)); + if (!ret && val > 100) { + config.param = 0; + DHD_ERROR(("%s: Connected station's beacon interval: " + "%d and set mchan_algo to %d \n", + __FUNCTION__, val, config.param)); + } else { + config.param = MIRACAST_MCHAN_ALGO; + } + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) { + goto resume; + } + + /* setting mchan_bw to platform specific value */ + config.iovar = "mchan_bw"; + config.param = MIRACAST_MCHAN_BW; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) { + goto resume; + } + + /* setting apmdu to platform specific value */ + config.iovar = "ampdu_mpdu"; + config.param = MIRACAST_AMPDU_SIZE; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) { + goto resume; + } + /* FALLTROUGH */ + /* Source mode shares most configurations with sink mode. + * Fall through here to avoid code duplication + */ + case MIRACAST_MODE_SINK: + /* disable internal roaming */ + config.iovar = "roam_off"; + config.param = 1; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) { + goto resume; + } + + /* tunr off pm */ + ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val)); + if (ret) { + goto resume; + } + + if (val != PM_OFF) { + val = PM_OFF; + config.iovar = NULL; + config.ioctl = WLC_GET_PM; + config.arg = &val; + config.len = sizeof(int); + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) { + goto resume; + } + } + +#ifdef CHANGE_SCAN_TIME + for (i = 0; i < sizeof(miracast_scan_time) / sizeof(miracast_scan_time[0]); i++) { + config.iovar = NULL; + config.ioctl = miracast_scan_time[i][0]; + config.arg = &miracast_scan_time[i][1]; + config.len = sizeof(int); + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) { + goto resume; + } + } +#endif + + break; + case MIRACAST_MODE_OFF: + default: + break; + } + miracast_cur_mode = mode; + + return 0; + +resume: + DHD_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret)); + wl_android_iolist_resume(dev, &miracast_resume_list); + return ret; +} + +#define NETLINK_OXYGEN 30 +#define AIBSS_BEACON_TIMEOUT 10 + +static struct sock *nl_sk = NULL; + +static void wl_netlink_recv(struct sk_buff *skb) +{ + WL_ERR(("netlink_recv called\n")); +} + +static int wl_netlink_init(void) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct netlink_kernel_cfg cfg = { + .input = wl_netlink_recv, + }; +#endif + + if (nl_sk != NULL) { + WL_ERR(("nl_sk already exist\n")); + return BCME_ERROR; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, + 0, wl_netlink_recv, NULL, THIS_MODULE); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg); +#else + nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg); +#endif + + if (nl_sk == NULL) { + WL_ERR(("nl_sk is not ready\n")); + return BCME_ERROR; + } + + return BCME_OK; +} + +static void wl_netlink_deinit(void) +{ + if (nl_sk) { + netlink_kernel_release(nl_sk); + nl_sk = NULL; + } +} + +s32 +wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size) +{ + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh = NULL; + int ret = -1; + + if (nl_sk == NULL) { + WL_ERR(("nl_sk was not initialized\n")); + goto nlmsg_failure; + } + + skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC); + if (skb == NULL) { + WL_ERR(("failed to allocate memory\n")); + goto nlmsg_failure; + } + + nlh = nlmsg_put(skb, 0, 0, 0, size, 0); + if (nlh == NULL) { + WL_ERR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n", + skb_tailroom(skb), nlmsg_total_size(size))); + dev_kfree_skb(skb); + goto nlmsg_failure; + } + + memcpy(nlmsg_data(nlh), data, size); + nlh->nlmsg_seq = seq; + nlh->nlmsg_type = type; + + /* netlink_unicast() takes ownership of the skb and frees it itself. */ + ret = netlink_unicast(nl_sk, skb, pid, 0); + WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret)); + +nlmsg_failure: + return ret; +} + +#ifdef WLAIBSS +static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len) +{ + int err = 0; + int retry = 0; + int pid = 0; + aibss_txfail_config_t txfail_config = {0, 0, 0, 0}; + char smbuf[WLC_IOCTL_SMLEN]; + + if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) { + WL_ERR(("Failed to get Parameter from : %s\n", command)); + return -1; + } + + /* set pid, and if the event was happened, let's send a notification through netlink */ + wl_cfg80211_set_txfail_pid(pid); + + /* If retry value is 0, it disables the functionality for TX Fail. */ + if (retry > 0) { + txfail_config.max_tx_retry = retry; + txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */ + } + txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0; + txfail_config.len = sizeof(txfail_config); + + err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config, + sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL); + WL_DBG(("retry=%d, pid=%d, err=%d\n", retry, pid, err)); + + return ((err == 0)?total_len:err); +} + +static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command, + int total_len, bool bAll) +{ + int error; + int bytes_written = 0; + void *buf = NULL; + bss_peer_list_info_t peer_list_info; + bss_peer_info_t *peer_info; + int i; + bool found = false; + struct ether_addr mac_ea; + + WL_DBG(("get ibss peer info(%s)\n", bAll?"true":"false")); + + if (!bAll) { + if (sscanf (command, "GETIBSSPEERINFO %02x:%02x:%02x:%02x:%02x:%02x", + (unsigned int *)&mac_ea.octet[0], (unsigned int *)&mac_ea.octet[1], + (unsigned int *)&mac_ea.octet[2], (unsigned int *)&mac_ea.octet[3], + (unsigned int *)&mac_ea.octet[4], (unsigned int *)&mac_ea.octet[5]) != 6) { + WL_DBG(("invalid MAC address\n")); + return -1; + } + } + + if ((buf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL)) == NULL) { + WL_ERR(("kmalloc failed\n")); + return -1; + } + + error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL); + if (unlikely(error)) { + WL_ERR(("could not get ibss peer info (%d)\n", error)); + kfree(buf); + return -1; + } + + memcpy(&peer_list_info, buf, sizeof(peer_list_info)); + peer_list_info.version = htod16(peer_list_info.version); + peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len); + peer_list_info.count = htod32(peer_list_info.count); + + WL_DBG(("ver:%d, len:%d, count:%d\n", peer_list_info.version, + peer_list_info.bss_peer_info_len, peer_list_info.count)); + + if (peer_list_info.count > 0) { + if (bAll) + bytes_written += sprintf(&command[bytes_written], "%u ", + peer_list_info.count); + + peer_info = (bss_peer_info_t *) ((void *)buf + BSS_PEER_LIST_INFO_FIXED_LEN); + + + for (i = 0; i < peer_list_info.count; i++) { + + WL_DBG(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi, + peer_info->tx_rate, peer_info->rx_rate)); + + if (!bAll && + memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) { + found = true; + } + + if (bAll || found) { + bytes_written += sprintf(&command[bytes_written], MACF, + ETHER_TO_MACF(peer_info->ea)); + bytes_written += sprintf(&command[bytes_written], " %u %d ", + peer_info->tx_rate/1000, peer_info->rssi); + } + + if (found) + break; + + peer_info = (bss_peer_info_t *)((void *)peer_info+sizeof(bss_peer_info_t)); + } + } + else { + WL_ERR(("could not get ibss peer info : no item\n")); + } + bytes_written += sprintf(&command[bytes_written], "%s", "\0"); + + WL_DBG(("command(%u):%s\n", total_len, command)); + WL_DBG(("bytes_written:%d\n", bytes_written)); + + kfree(buf); + return bytes_written; +} + +int wl_android_set_ibss_routetable(struct net_device *dev, char *command, int total_len) +{ + + char *pcmd = command; + char *str = NULL; + + ibss_route_tbl_t *route_tbl = NULL; + char *ioctl_buf = NULL; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + s32 err = BCME_OK; + uint32 route_tbl_len; + uint32 entries; + char *endptr; + uint32 i = 0; + struct ipv4_addr dipaddr; + struct ether_addr ea; + + route_tbl_len = sizeof(ibss_route_tbl_t) + + (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t); + route_tbl = (ibss_route_tbl_t *)kzalloc(route_tbl_len, kflags); + if (!route_tbl) { + WL_ERR(("Route TBL alloc failed\n")); + return -ENOMEM; + } + ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + if (route_tbl) { + kfree(route_tbl); + } + return -ENOMEM; + } + memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); + + /* drop command */ + str = bcmstrtok(&pcmd, " ", NULL); + + /* get count */ + str = bcmstrtok(&pcmd, " ", NULL); + if (!str) { + WL_ERR(("Invalid number parameter %s\n", str)); + err = -EINVAL; + goto exit; + } + entries = bcm_strtoul(str, &endptr, 0); + if (*endptr != '\0') { + WL_ERR(("Invalid number parameter %s\n", str)); + err = -EINVAL; + goto exit; + } + WL_INFORM(("Routing table count:%d\n", entries)); + route_tbl->num_entry = entries; + + for (i = 0; i < entries; i++) { + str = bcmstrtok(&pcmd, " ", NULL); + if (!str || !bcm_atoipv4(str, &dipaddr)) { + WL_ERR(("Invalid ip string %s\n", str)); + err = -EINVAL; + goto exit; + } + + + str = bcmstrtok(&pcmd, " ", NULL); + if (!str || !bcm_ether_atoe(str, &ea)) { + WL_ERR(("Invalid ethernet string %s\n", str)); + err = -EINVAL; + goto exit; + } + bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN); + bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN); + } + + route_tbl_len = sizeof(ibss_route_tbl_t) + + ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t)); + err = wldev_iovar_setbuf(dev, "ibss_route_tbl", + route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (err != BCME_OK) { + WL_ERR(("Fail to set iovar %d\n", err)); + err = -EINVAL; + } + +exit: + if (route_tbl) + kfree(route_tbl); + if (ioctl_buf) + kfree(ioctl_buf); + return err; + +} + +int +wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len) +{ + char *pcmd = command; + char *str = NULL, *endptr = NULL; + struct ampdu_aggr aggr; + char smbuf[WLC_IOCTL_SMLEN]; + int idx; + int err = 0; + int wme_AC2PRIO[AC_COUNT][2] = { + {PRIO_8021D_VO, PRIO_8021D_NC}, /* AC_VO - 3 */ + {PRIO_8021D_CL, PRIO_8021D_VI}, /* AC_VI - 2 */ + {PRIO_8021D_BK, PRIO_8021D_NONE}, /* AC_BK - 1 */ + {PRIO_8021D_BE, PRIO_8021D_EE}}; /* AC_BE - 0 */ + + WL_DBG(("set ibss ampdu:%s\n", command)); + + memset(&aggr, 0, sizeof(aggr)); + /* Cofigure all priorities */ + aggr.conf_TID_bmap = NBITMASK(NUMPRIO); + + /* acquire parameters */ + /* drop command */ + str = bcmstrtok(&pcmd, " ", NULL); + + for (idx = 0; idx < AC_COUNT; idx++) { + bool on; + str = bcmstrtok(&pcmd, " ", NULL); + if (!str) { + WL_ERR(("Invalid parameter : %s\n", pcmd)); + return -EINVAL; + } + on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE; + if (*endptr != '\0') { + WL_ERR(("Invalid number format %s\n", str)); + return -EINVAL; + } + if (on) { + setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]); + setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]); + } + } + + err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr, + sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL); + + return ((err == 0) ? total_len : err); +} + +int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len) +{ + char *pcmd = command; + char *str = NULL; + int txchain, rxchain; + int err = 0; + + WL_DBG(("set ibss antenna:%s\n", command)); + + /* acquire parameters */ + /* drop command */ + str = bcmstrtok(&pcmd, " ", NULL); + + /* TX chain */ + str = bcmstrtok(&pcmd, " ", NULL); + if (!str) { + WL_ERR(("Invalid parameter : %s\n", pcmd)); + return -EINVAL; + } + txchain = bcm_atoi(str); + + /* RX chain */ + str = bcmstrtok(&pcmd, " ", NULL); + if (!str) { + WL_ERR(("Invalid parameter : %s\n", pcmd)); + return -EINVAL; + } + rxchain = bcm_atoi(str); + + err = wldev_iovar_setint(dev, "txchain", txchain); + if (err != 0) + return err; + err = wldev_iovar_setint(dev, "rxchain", rxchain); + return ((err == 0)?total_len:err); +} +#endif /* WLAIBSS */ + +int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len) +{ + wl_mkeep_alive_pkt_t mkeep_alive_pkt; + int ret; + uint period_msec = 0; + char *buf; + + if (extra == NULL) + { + DHD_ERROR(("%s: extra is NULL\n", __FUNCTION__)); + return -1; + } + if (sscanf(extra, "%d", &period_msec) != 1) + { + DHD_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__)); + return -EINVAL; + } + DHD_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec)); + + memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); + + mkeep_alive_pkt.period_msec = period_msec; + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + + /* Setup keep alive zero for null packet generation */ + mkeep_alive_pkt.keep_alive_id = 0; + mkeep_alive_pkt.len_bytes = 0; + buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + if (!buf) { + DHD_ERROR(("%s: buffer alloc failed\n", __FUNCTION__)); + return BCME_NOMEM; + } + + ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt, + WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL); + if (ret < 0) + DHD_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret)); + else + DHD_TRACE(("%s:keep_alive set ok\n", __FUNCTION__)); + kfree(buf); + return ret; +} + + +static const char * +get_string_by_separator(char *result, int result_len, const char *src, char separator) +{ + char *end = result + result_len - 1; + while ((result != end) && (*src != separator) && (*src)) { + *result++ = *src++; + } + *result = 0; + if (*src == separator) + ++src; + return src; +} + +int +wl_android_set_roam_offload_bssid_list(struct net_device *dev, const char *cmd) +{ + char sbuf[32]; + int i, cnt, size, err, ioctl_buf_len; + roamoffl_bssid_list_t *bssid_list; + const char *str = cmd; + char *ioctl_buf; + + str = get_string_by_separator(sbuf, 32, str, ','); + cnt = bcm_atoi(sbuf); + cnt = MIN(cnt, MAX_ROAMOFFL_BSSID_NUM); + size = sizeof(int) + sizeof(struct ether_addr) * cnt; + WL_ERR(("ROAM OFFLOAD BSSID LIST %d BSSIDs, size %d\n", cnt, size)); + bssid_list = kmalloc(size, GFP_KERNEL); + if (bssid_list == NULL) { + WL_ERR(("%s: memory alloc for bssid list(%d) failed\n", + __FUNCTION__, size)); + return -ENOMEM; + } + ioctl_buf_len = size + 64; + ioctl_buf = kmalloc(ioctl_buf_len, GFP_KERNEL); + if (ioctl_buf == NULL) { + WL_ERR(("%s: memory alloc for ioctl_buf(%d) failed\n", + __FUNCTION__, ioctl_buf_len)); + kfree(bssid_list); + return -ENOMEM; + } + + for (i = 0; i < cnt; i++) { + str = get_string_by_separator(sbuf, 32, str, ','); + if (bcm_ether_atoe(sbuf, &bssid_list->bssid[i]) == 0) { + DHD_ERROR(("%s: Invalid station MAC Address!!!\n", __FUNCTION__)); + kfree(bssid_list); + kfree(ioctl_buf); + return -1; + } + } + + bssid_list->cnt = cnt; + err = wldev_iovar_setbuf(dev, "roamoffl_bssid_list", + bssid_list, size, ioctl_buf, ioctl_buf_len, NULL); + kfree(bssid_list); + kfree(ioctl_buf); + + return err; +} + + +static int wl_android_get_link_status(struct net_device *dev, char *command, + int total_len) +{ + int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map; + uint32 rspec; + uint encode, rate, txexp; + struct wl_bss_info *bi; + int datalen = sizeof(uint32) + sizeof(wl_bss_info_t); + char buf[datalen]; + + memset(buf, 0, datalen); + /* get BSS information */ + *(u32 *) buf = htod32(datalen); + error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen); + if (unlikely(error)) { + WL_ERR(("Could not get bss info %d\n", error)); + return -1; + } + + bi = (struct wl_bss_info *) (buf + sizeof(uint32)); + + for (i = 0; i < ETHER_ADDR_LEN; i++) { + if (bi->BSSID.octet[i] > 0) { + break; + } + } + + if (i == ETHER_ADDR_LEN) { + WL_DBG(("No BSSID\n")); + return -1; + } + + /* check VHT capability at beacon */ + if (bi->vht_cap) { + if (CHSPEC_IS5G(bi->chanspec)) { + result |= WL_ANDROID_LINK_AP_VHT_SUPPORT; + } + } + + /* get a rspec (radio spectrum) rate */ + error = wldev_iovar_getint(dev, "nrate", &rspec); + if (unlikely(error) || rspec == 0) { + WL_ERR(("get link status error (%d)\n", error)); + return -1; + } + + encode = (rspec & WL_RSPEC_ENCODING_MASK); + rate = (rspec & WL_RSPEC_RATE_MASK); + txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT; + + switch (encode) { + case WL_RSPEC_ENCODE_HT: + /* check Rx MCS Map for HT */ + for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) { + int8 bitmap = 0xFF; + if (i == MAX_STREAMS_SUPPORTED-1) { + bitmap = 0x7F; + } + if (bi->basic_mcs[i] & bitmap) { + nss++; + } + } + break; + case WL_RSPEC_ENCODE_VHT: + /* check Rx MCS Map for VHT */ + for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) { + mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap)); + if (mcs_map != VHT_CAP_MCS_MAP_NONE) { + nss++; + } + } + break; + } + + /* check MIMO capability with nss in beacon */ + if (nss > 1) { + result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT; + } + + single_stream = (encode == WL_RSPEC_ENCODE_RATE) || + ((encode == WL_RSPEC_ENCODE_HT) && rate < 8) || + ((encode == WL_RSPEC_ENCODE_VHT) && + ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1); + + if (txexp == 0) { + if ((rspec & WL_RSPEC_STBC) && single_stream) { + stf = OLD_NRATE_STF_STBC; + } else { + stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM; + } + } else if (txexp == 1 && single_stream) { + stf = OLD_NRATE_STF_CDD; + } + + /* check 11ac (VHT) */ + if (encode == WL_RSPEC_ENCODE_VHT) { + if (CHSPEC_IS5G(bi->chanspec)) { + result |= WL_ANDROID_LINK_VHT; + } + } + + /* check MIMO */ + if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) { + switch (stf) { + case OLD_NRATE_STF_SISO: + break; + case OLD_NRATE_STF_CDD: + case OLD_NRATE_STF_STBC: + result |= WL_ANDROID_LINK_MIMO; + break; + case OLD_NRATE_STF_SDM: + if (!single_stream) { + result |= WL_ANDROID_LINK_MIMO; + } + break; + } + } + + WL_DBG(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n", + __FUNCTION__, result, stf, single_stream, nss)); + + bytes_written = sprintf(command, "%s %d", CMD_GET_LINK_STATUS, result); + + return bytes_written; +} + +#ifdef SET_RPS_CPUS +static int +wl_android_set_rps_cpus(struct net_device *dev, char *command, int total_len) +{ + int error, enable; + + enable = command[strlen(CMD_RPSMODE) + 1] - '0'; + error = dhd_rps_cpus_enable(dev, enable); + + return error; +} +#endif /* SET_RPS_CPUS */ + +int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) +{ +#define PRIVATE_COMMAND_MAX_LEN 8192 +#define PRIVATE_COMMAND_DEF_LEN 4096 + int ret = 0; + char *command = NULL; + int bytes_written = 0; + android_wifi_priv_cmd priv_cmd; + int buf_size = 0; + + net_os_wake_lock(net); + + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto exit; + } + + if (!ifr->ifr_data) { + ret = -EINVAL; + goto exit; + } + +#ifdef CONFIG_COMPAT + if (is_compat_task()) { + compat_android_wifi_priv_cmd compat_priv_cmd; + if (copy_from_user(&compat_priv_cmd, ifr->ifr_data, + sizeof(compat_android_wifi_priv_cmd))) { + ret = -EFAULT; + goto exit; + + } + priv_cmd.buf = compat_ptr(compat_priv_cmd.buf); + priv_cmd.used_len = compat_priv_cmd.used_len; + priv_cmd.total_len = compat_priv_cmd.total_len; + } else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) { + ret = -EFAULT; + goto exit; + } + } + if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) { + DHD_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__, + priv_cmd.total_len)); + ret = -EINVAL; + goto exit; + } + + buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN); + command = kmalloc((buf_size + 1), GFP_KERNEL); + + if (!command) + { + DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__)); + ret = -ENOMEM; + goto exit; + } + if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { + ret = -EFAULT; + goto exit; + } + command[priv_cmd.total_len] = '\0'; + + DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); + + if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { + DHD_INFO(("%s, Received regular START command\n", __FUNCTION__)); + bytes_written = wl_android_wifi_on(net); + } + else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) { + bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len); + } + + if (!g_wifi_on) { + DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n", + __FUNCTION__, command, ifr->ifr_name)); + ret = 0; + goto exit; + } + + if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) { + bytes_written = wl_android_wifi_off(net); + } + else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { + /* TBD: SCAN-ACTIVE */ + } + else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) { + /* TBD: SCAN-PASSIVE */ + } + else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) { + bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { + bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len); + } +#ifdef PKT_FILTER_SUPPORT + else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) { + bytes_written = net_os_enable_packet_filter(net, 1); + } + else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) { + bytes_written = net_os_enable_packet_filter(net, 0); + } + else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) { + int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; + bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num); + } + else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) { + int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; + bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); + } +#endif /* PKT_FILTER_SUPPORT */ + else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { + /* TBD: BTCOEXSCAN-START */ + } + else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) { + /* TBD: BTCOEXSCAN-STOP */ + } + else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { +#ifdef WL_CFG80211 + void *dhdp = wl_cfg80211_get_dhdp(); + bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command); +#else +#ifdef PKT_FILTER_SUPPORT + uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; + + if (mode == 1) + net_os_enable_packet_filter(net, 0); /* DHCP starts */ + else + net_os_enable_packet_filter(net, 1); /* DHCP ends */ +#endif /* PKT_FILTER_SUPPORT */ +#endif /* WL_CFG80211 */ + } + else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { + bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { + bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { + uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; +#ifdef WL_HOST_BAND_MGMT + s32 ret = 0; + if ((ret = wl_cfg80211_set_band(net, band)) < 0) { + if (ret == BCME_UNSUPPORTED) { + /* If roam_var is unsupported, fallback to the original method */ + WL_ERR(("WL_HOST_BAND_MGMT defined, " + "but roam_band iovar unsupported in the firmware\n")); + } else { + bytes_written = -1; + goto exit; + } + } + if ((band == WLC_BAND_AUTO) || (ret == BCME_UNSUPPORTED)) + bytes_written = wldev_set_band(net, band); +#else + bytes_written = wldev_set_band(net, band); +#endif /* WL_HOST_BAND_MGMT */ + } + else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { + bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); + } +#ifdef WL_CFG80211 +#ifndef CUSTOMER_SET_COUNTRY + /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ + else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { + char *country_code = command + strlen(CMD_COUNTRY) + 1; +#ifdef CUSTOMER_HW5 + /* Customer_hw5 want to keep connections */ + bytes_written = wldev_set_country(net, country_code, true, false); +#else + bytes_written = wldev_set_country(net, country_code, true, true); +#endif + } +#endif /* CUSTOMER_SET_COUNTRY */ +#endif /* WL_CFG80211 */ + else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) { + bytes_written = wl_android_set_csa(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) { + bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) { + bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) { + bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) { + bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len); + } + + +#ifdef PNO_SUPPORT + else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { + bytes_written = dhd_dev_pno_stop_for_ssid(net); + } +#ifndef WL_SCHED_SCAN + else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { + bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len); + } +#endif /* !WL_SCHED_SCAN */ + else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { + int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; + bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net); + } + else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) { + bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len); + } +#endif /* PNO_SUPPORT */ + else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { + bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) { + int skip = strlen(CMD_P2P_SET_NOA) + 1; + bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, + priv_cmd.total_len - skip); + } +#if !defined WL_ENABLE_P2P_IF + else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { + bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); + } +#endif /* WL_ENABLE_P2P_IF */ + else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { + int skip = strlen(CMD_P2P_SET_PS) + 1; + bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, + priv_cmd.total_len - skip); + } +#ifdef WL_CFG80211 + else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE, + strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) { + int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3; + bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, + priv_cmd.total_len - skip, *(command + skip - 2) - '0'); + } +#ifdef WLFBT + else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) { + wl_cfg80211_get_fbt_key(command); + bytes_written = FBT_KEYLEN; + } +#endif /* WLFBT */ +#endif /* WL_CFG80211 */ + else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) + bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) + bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); +#ifdef BCMCCX + else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) { + bytes_written = wl_android_get_cckm_rn(net, command); + } + else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) { + bytes_written = wl_android_set_cckm_krk(net, command); + } + else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) { + bytes_written = wl_android_get_assoc_res_ies(net, command); + } +#endif /* BCMCCX */ +#if defined(WL_SUPPORT_AUTO_CHANNEL) + else if (strnicmp(command, CMD_GET_BEST_CHANNELS, + strlen(CMD_GET_BEST_CHANNELS)) == 0) { + bytes_written = wl_cfg80211_get_best_channels(net, command, + priv_cmd.total_len); + } +#endif /* WL_SUPPORT_AUTO_CHANNEL */ + else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) { + int skip = strlen(CMD_HAPD_MAC_FILTER) + 1; + wl_android_set_mac_address_filter(net, (const char*)command+skip); + } + else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0) + bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len); +#if defined(BCMFW_ROAM_ENABLE) + else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) { + bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len); + } +#endif /* BCMFW_ROAM_ENABLE */ + else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) + bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0) + bytes_written = wl_android_set_ibss_beacon_ouidata(net, + command, priv_cmd.total_len); +#ifdef WLAIBSS + else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT, + strlen(CMD_SETIBSSTXFAILEVENT)) == 0) + bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL, + strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0) + bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, + TRUE); + else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO, + strlen(CMD_GET_IBSS_PEER_INFO)) == 0) + bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, + FALSE); + else if (strnicmp(command, CMD_SETIBSSROUTETABLE, + strlen(CMD_SETIBSSROUTETABLE)) == 0) + bytes_written = wl_android_set_ibss_routetable(net, command, + priv_cmd.total_len); + else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0) + bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0) + bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len); +#endif /* WLAIBSS */ + else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) { + int skip = strlen(CMD_KEEP_ALIVE) + 1; + bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip); + } + else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) { + int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0'; + bytes_written = wl_cfg80211_enable_roam_offload(net, enable); + } + else if (strnicmp(command, CMD_ROAM_OFFLOAD_APLIST, strlen(CMD_ROAM_OFFLOAD_APLIST)) == 0) { + bytes_written = wl_android_set_roam_offload_bssid_list(net, + command + strlen(CMD_ROAM_OFFLOAD_APLIST) + 1); + } +#ifdef SET_RPS_CPUS + else if (strnicmp(command, CMD_RPSMODE, strlen(CMD_RPSMODE)) == 0) { + bytes_written = wl_android_set_rps_cpus(net, command, priv_cmd.total_len); + } +#endif /* SET_RPS_CPUS */ + else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) { + bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len); + } +#ifdef CONNECTION_STATISTICS + else if (strnicmp(command, CMD_GET_CONNECTION_STATS, + strlen(CMD_GET_CONNECTION_STATS)) == 0) { + bytes_written = wl_android_get_connection_stats(net, command, + priv_cmd.total_len); + } +#endif + else { + DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); + bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); + } + + if (bytes_written >= 0) { + if ((bytes_written == 0) && (priv_cmd.total_len > 0)) + command[0] = '\0'; + if (bytes_written >= priv_cmd.total_len) { + DHD_ERROR(("%s: err. bytes_written:%d >= buf_size:%d \n", + __FUNCTION__, bytes_written, buf_size)); + ret = BCME_BUFTOOSHORT; + goto exit; + } + bytes_written++; + priv_cmd.used_len = bytes_written; + if (copy_to_user(priv_cmd.buf, command, bytes_written)) { + DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); + ret = -EFAULT; + } + } + else { + ret = bytes_written; + } + +exit: + net_os_wake_unlock(net); + kfree(command); + return ret; +} + +int wl_android_init(void) +{ + int ret = 0; + +#ifdef ENABLE_INSMOD_NO_FW_LOAD + dhd_download_fw_on_driverload = FALSE; +#endif /* ENABLE_INSMOD_NO_FW_LOAD */ +#if defined(CUSTOMER_HW2) + if (!iface_name[0]) { + memset(iface_name, 0, IFNAMSIZ); + bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); + } +#endif + +#ifdef WL_GENL + wl_genl_init(); +#endif + wl_netlink_init(); + + return ret; +} + +int wl_android_exit(void) +{ + int ret = 0; + struct io_cfg *cur, *q; + +#ifdef WL_GENL + wl_genl_deinit(); +#endif /* WL_GENL */ + wl_netlink_deinit(); + + list_for_each_entry_safe(cur, q, &miracast_resume_list, list) { + list_del(&cur->list); + kfree(cur); + } + + return ret; +} + +void wl_android_post_init(void) +{ + +#ifdef ENABLE_4335BT_WAR + bcm_bt_unlock(lock_cookie_wifi); + printk("%s: btlock released\n", __FUNCTION__); +#endif /* ENABLE_4335BT_WAR */ + + if (!dhd_download_fw_on_driverload) + g_wifi_on = FALSE; +} + +#ifdef WL_GENL +/* Generic Netlink Initializaiton */ +static int wl_genl_init(void) +{ + int ret; + + WL_DBG(("GEN Netlink Init\n\n")); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) + /* register new family */ + ret = genl_register_family(&wl_genl_family); + if (ret != 0) + goto failure; + + /* register functions (commands) of the new family */ + ret = genl_register_ops(&wl_genl_family, &wl_genl_ops); + if (ret != 0) { + WL_ERR(("register ops failed: %i\n", ret)); + genl_unregister_family(&wl_genl_family); + goto failure; + } + + ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast); +#else + ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */ + if (ret != 0) { + WL_ERR(("register mc_group failed: %i\n", ret)); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) + genl_unregister_ops(&wl_genl_family, &wl_genl_ops); +#endif + genl_unregister_family(&wl_genl_family); + goto failure; + } + + return 0; + +failure: + WL_ERR(("Registering Netlink failed!!\n")); + return -1; +} + +/* Generic netlink deinit */ +static int wl_genl_deinit(void) +{ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) + if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0) + WL_ERR(("Unregister wl_genl_ops failed\n")); +#endif + if (genl_unregister_family(&wl_genl_family) < 0) + WL_ERR(("Unregister wl_genl_ops failed\n")); + + return 0; +} + +s32 wl_event_to_bcm_event(u16 event_type) +{ + u16 event = -1; + + switch (event_type) { + case WLC_E_SERVICE_FOUND: + event = BCM_E_SVC_FOUND; + break; + case WLC_E_P2PO_ADD_DEVICE: + event = BCM_E_DEV_FOUND; + break; + case WLC_E_P2PO_DEL_DEVICE: + event = BCM_E_DEV_LOST; + break; + /* Above events are supported from BCM Supp ver 47 Onwards */ +#ifdef BT_WIFI_HANDOVER + case WLC_E_BT_WIFI_HANDOVER_REQ: + event = BCM_E_DEV_BT_WIFI_HO_REQ; + break; +#endif /* BT_WIFI_HANDOVER */ + + default: + WL_ERR(("Event not supported\n")); + } + + return event; +} + +s32 +wl_genl_send_msg( + struct net_device *ndev, + u32 event_type, + u8 *buf, + u16 len, + u8 *subhdr, + u16 subhdr_len) +{ + int ret = 0; + struct sk_buff *skb = NULL; + void *msg; + u32 attr_type = 0; + bcm_event_hdr_t *hdr = NULL; + int mcast = 1; /* By default sent as mutlicast type */ + int pid = 0; + u8 *ptr = NULL, *p = NULL; + u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + + WL_DBG(("Enter \n")); + + /* Decide between STRING event and Data event */ + if (event_type == 0) + attr_type = BCM_GENL_ATTR_STRING; + else + attr_type = BCM_GENL_ATTR_MSG; + + skb = genlmsg_new(NLMSG_GOODSIZE, kflags); + if (skb == NULL) { + ret = -ENOMEM; + goto out; + } + + msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG); + if (msg == NULL) { + ret = -ENOMEM; + goto out; + } + + + if (attr_type == BCM_GENL_ATTR_STRING) { + /* Add a BCM_GENL_MSG attribute. Since it is specified as a string. + * make sure it is null terminated + */ + if (subhdr || subhdr_len) { + WL_ERR(("No sub hdr support for the ATTR STRING type \n")); + ret = -EINVAL; + goto out; + } + + ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf); + if (ret != 0) { + WL_ERR(("nla_put_string failed\n")); + goto out; + } + } else { + /* ATTR_MSG */ + + /* Create a single buffer for all */ + p = ptr = kzalloc(tot_len, kflags); + if (!ptr) { + ret = -ENOMEM; + WL_ERR(("ENOMEM!!\n")); + goto out; + } + + /* Include the bcm event header */ + hdr = (bcm_event_hdr_t *)ptr; + hdr->event_type = wl_event_to_bcm_event(event_type); + hdr->len = len + subhdr_len; + ptr += sizeof(bcm_event_hdr_t); + + /* Copy subhdr (if any) */ + if (subhdr && subhdr_len) { + memcpy(ptr, subhdr, subhdr_len); + ptr += subhdr_len; + } + + /* Copy the data */ + if (buf && len) { + memcpy(ptr, buf, len); + } + + ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p); + if (ret != 0) { + WL_ERR(("nla_put_string failed\n")); + goto out; + } + } + + if (mcast) { + int err = 0; + /* finalize the message */ + genlmsg_end(skb, msg); + /* NETLINK_CB(skb).dst_group = 1; */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) + if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0) +#else + if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0) +#endif + WL_ERR(("genlmsg_multicast for attr(%d) failed. Error:%d \n", + attr_type, err)); + else + WL_DBG(("Multicast msg sent successfully. attr_type:%d len:%d \n", + attr_type, tot_len)); + } else { + NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */ + + /* finalize the message */ + genlmsg_end(skb, msg); + + /* send the message back */ + if (genlmsg_unicast(&init_net, skb, pid) < 0) + WL_ERR(("genlmsg_unicast failed\n")); + } + +out: + if (p) + kfree(p); + if (ret) + nlmsg_free(skb); + + return ret; +} + +static s32 +wl_genl_handle_msg( + struct sk_buff *skb, + struct genl_info *info) +{ + struct nlattr *na; + u8 *data = NULL; + + WL_DBG(("Enter \n")); + + if (info == NULL) { + return -EINVAL; + } + + na = info->attrs[BCM_GENL_ATTR_MSG]; + if (!na) { + WL_ERR(("nlattribute NULL\n")); + return -EINVAL; + } + + data = (char *)nla_data(na); + if (!data) { + WL_ERR(("Invalid data\n")); + return -EINVAL; + } else { + /* Handle the data */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || defined(WL_COMPAT_WIRELESS) + WL_DBG(("%s: Data received from pid (%d) \n", __func__, + info->snd_pid)); +#else + WL_DBG(("%s: Data received from pid (%d) \n", __func__, + info->snd_portid)); +#endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */ + } + + return 0; +} +#endif /* WL_GENL */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_android.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.h new file mode 100644 index 000000000000..cb6ca2403eb9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.h @@ -0,0 +1,120 @@ +/* + * Linux cfg80211 driver - Android related functions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_android.h 513437 2014-11-06 12:09:29Z $ + */ + +#include +#include +#include + +/* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL + * automatically + */ +#if defined(BT_WIFI_HANDOVER) +#define WL_GENL +#endif + + +#ifdef WL_GENL +#include +#endif + +/** + * Android platform dependent functions, feel free to add Android specific functions here + * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd + * or cfg, define them as static in wl_android.c + */ + +/** + * wl_android_init will be called from module init function (dhd_module_init now), similarly + * wl_android_exit will be called from module exit function (dhd_module_cleanup now) + */ +int wl_android_init(void); +int wl_android_exit(void); +void wl_android_post_init(void); +int wl_android_wifi_on(struct net_device *dev); +int wl_android_wifi_off(struct net_device *dev); +int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); + +#ifdef WL_GENL +typedef struct bcm_event_hdr { + u16 event_type; + u16 len; +} bcm_event_hdr_t; + +/* attributes (variables): the index in this enum is used as a reference for the type, + * userspace application has to indicate the corresponding type + * the policy is used for security considerations + */ +enum { + BCM_GENL_ATTR_UNSPEC, + BCM_GENL_ATTR_STRING, + BCM_GENL_ATTR_MSG, + __BCM_GENL_ATTR_MAX +}; +#define BCM_GENL_ATTR_MAX (__BCM_GENL_ATTR_MAX - 1) + +/* commands: enumeration of all commands (functions), + * used by userspace application to identify command to be ececuted + */ +enum { + BCM_GENL_CMD_UNSPEC, + BCM_GENL_CMD_MSG, + __BCM_GENL_CMD_MAX +}; +#define BCM_GENL_CMD_MAX (__BCM_GENL_CMD_MAX - 1) + +/* Enum values used by the BCM supplicant to identify the events */ +enum { + BCM_E_UNSPEC, + BCM_E_SVC_FOUND, + BCM_E_DEV_FOUND, + BCM_E_DEV_LOST, + BCM_E_DEV_BT_WIFI_HO_REQ, + BCM_E_MAX +}; + +s32 wl_genl_send_msg(struct net_device *ndev, u32 event_type, + u8 *string, u16 len, u8 *hdr, u16 hdrlen); +#endif /* WL_GENL */ +s32 wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size); + +/* hostap mac mode */ +#define MACLIST_MODE_DISABLED 0 +#define MACLIST_MODE_DENY 1 +#define MACLIST_MODE_ALLOW 2 + +/* max number of assoc list */ +#define MAX_NUM_OF_ASSOCLIST 64 +/* Bandwidth */ +#define WL_CH_BANDWIDTH_20MHZ 20 +#define WL_CH_BANDWIDTH_40MHZ 40 +#define WL_CH_BANDWIDTH_80MHZ 80 + +/* max number of mac filter list + * restrict max number to 10 as maximum cmd string size is 255 + */ +#define MAX_NUM_MAC_FILT 10 + +int wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist); diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c new file mode 100644 index 000000000000..d1546bbfcbd0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -0,0 +1,14387 @@ +/* + * Linux cfg80211 driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.c 704356 2017-06-13 08:36:52Z $ + */ +/* */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef PNO_SUPPORT +#include +#endif /* PNO_SUPPORT */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef PROP_TXSTATUS +#include +#endif + +#ifdef WL11U +#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) +#error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \ + according to Kernel version and is supported only in Android-JB +#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ +#endif /* WL11U */ + +#ifdef BCMWAPI_WPI +/* these items should evetually go into wireless.h of the linux system headfile dir */ +#ifndef IW_ENCODE_ALG_SM4 +#define IW_ENCODE_ALG_SM4 0x20 +#endif + +#ifndef IW_AUTH_WAPI_ENABLED +#define IW_AUTH_WAPI_ENABLED 0x20 +#endif + +#ifndef IW_AUTH_WAPI_VERSION_1 +#define IW_AUTH_WAPI_VERSION_1 0x00000008 +#endif + +#ifndef IW_AUTH_CIPHER_SMS4 +#define IW_AUTH_CIPHER_SMS4 0x00000020 +#endif + +#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK +#define IW_AUTH_KEY_MGMT_WAPI_PSK 4 +#endif + +#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT +#define IW_AUTH_KEY_MGMT_WAPI_CERT 8 +#endif +#endif /* BCMWAPI_WPI */ + +#ifdef BCMWAPI_WPI +#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) +#endif /* BCMWAPI_WPI */ + +static struct device *cfg80211_parent_dev = NULL; +/* g_bcm_cfg should be static. Do not change */ +static struct bcm_cfg80211 *g_bcm_cfg = NULL; +u32 wl_dbg_level = WL_DBG_ERR; + +#ifdef WLAIBSS_MCHAN +#define IBSS_IF_NAME "ibss%d" +#endif /* WLAIBSS_MCHAN */ + +#ifdef VSDB +/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */ +#define DEFAULT_SLEEP_TIME_VSDB 120 +#define OFF_CHAN_TIME_THRESHOLD_MS 200 +#define AF_RETRY_DELAY_TIME 40 + +/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */ +#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \ + do { \ + if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \ + wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \ + OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \ + } \ + } while (0) +#else /* VSDB */ +/* if not VSDB, do nothing */ +#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) +#endif /* VSDB */ + +#ifdef WL_CFG80211_SYNC_GON +#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) \ + (wl_get_drv_status_all(cfg, SENDING_ACT_FRM) || \ + wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) +#else +#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) wl_get_drv_status_all(cfg, SENDING_ACT_FRM) +#endif /* WL_CFG80211_SYNC_GON */ +#define WL_IS_P2P_DEV_EVENT(e) ((e->emsg.ifidx == 0) && \ + (e->emsg.bsscfgidx == P2PAPI_BSSCFG_DEVICE)) + +#define COEX_DHCP + +#define WLAN_EID_SSID 0 +#define CH_MIN_5G_CHANNEL 34 +#define CH_MIN_2G_CHANNEL 1 + +#ifdef WLAIBSS +enum abiss_event_type { + AIBSS_EVENT_TXFAIL +}; +#endif + +enum rmc_event_type { + RMC_EVENT_NONE, + RMC_EVENT_LEADER_CHECK_FAIL +}; + +/* This is to override regulatory domains defined in cfg80211 module (reg.c) + * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN + * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165). + * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels. + * All the chnages in world regulatory domain are to be done here. + */ +static const struct ieee80211_regdomain brcm_regdom = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + /* IEEE 802.11b/g, channels 1..11 */ + REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), + /* If any */ + /* IEEE 802.11 channel 14 - Only JP enables + * this and for 802.11b only + */ + REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), + /* IEEE 802.11a, channel 36..64 */ + REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), + /* IEEE 802.11a, channel 100..165 */ + REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) +/* + * Possible interface combinations supported by driver + * + * ADHOC Mode - #ADHOC <= 1 on channels = 1 + * SoftAP Mode - #AP <= 1 on channels = 1 + * STA + P2P Mode - #STA <= 2, #{P2P-GO, P2P-client} <= 1, #P2P-device <= 1 + * on channels = 2 + */ +static const struct ieee80211_iface_limit common_if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, + { + /* + * During P2P-GO removal, P2P-GO is first changed to STA and later only + * removed. So setting maximum possible number of STA interfaces according + * to kernel version. + * + * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x) + * linux-3.8 and above - max:2 (wlan0 + group removal of p2p-wlan0-x) + */ +#ifdef WL_ENABLE_P2P_IF + .max = 3, +#else + .max = 2, +#endif /* WL_ENABLE_P2P_IF */ + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +#if defined(WL_CFG80211_P2P_DEV_IF) + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +#endif /* WL_CFG80211_P2P_DEV_IF */ + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC), + }, +}; +#ifdef BCM4330_CHIP +#define NUM_DIFF_CHANNELS 1 +#else +#define NUM_DIFF_CHANNELS 2 +#endif +static const struct ieee80211_iface_combination +common_iface_combinations[] = { + { + .num_different_channels = NUM_DIFF_CHANNELS, + .max_interfaces = 4, + .limits = common_if_limits, + .n_limits = ARRAY_SIZE(common_if_limits), + }, +}; +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ + +/* Data Element Definitions */ +#define WPS_ID_CONFIG_METHODS 0x1008 +#define WPS_ID_REQ_TYPE 0x103A +#define WPS_ID_DEVICE_NAME 0x1011 +#define WPS_ID_VERSION 0x104A +#define WPS_ID_DEVICE_PWD_ID 0x1012 +#define WPS_ID_REQ_DEV_TYPE 0x106A +#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053 +#define WPS_ID_PRIM_DEV_TYPE 0x1054 + +/* Device Password ID */ +#define DEV_PW_DEFAULT 0x0000 +#define DEV_PW_USER_SPECIFIED 0x0001, +#define DEV_PW_MACHINE_SPECIFIED 0x0002 +#define DEV_PW_REKEY 0x0003 +#define DEV_PW_PUSHBUTTON 0x0004 +#define DEV_PW_REGISTRAR_SPECIFIED 0x0005 + +/* Config Methods */ +#define WPS_CONFIG_USBA 0x0001 +#define WPS_CONFIG_ETHERNET 0x0002 +#define WPS_CONFIG_LABEL 0x0004 +#define WPS_CONFIG_DISPLAY 0x0008 +#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010 +#define WPS_CONFIG_INT_NFC_TOKEN 0x0020 +#define WPS_CONFIG_NFC_INTERFACE 0x0040 +#define WPS_CONFIG_PUSHBUTTON 0x0080 +#define WPS_CONFIG_KEYPAD 0x0100 +#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280 +#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480 +#define WPS_CONFIG_VIRT_DISPLAY 0x2008 +#define WPS_CONFIG_PHY_DISPLAY 0x4008 + +#ifdef BCMCCX +#ifndef WLAN_AKM_SUITE_CCKM +#define WLAN_AKM_SUITE_CCKM 0x00409600 +#endif +#define DOT11_LEAP_AUTH 0x80 /* LEAP auth frame paylod constants */ +#endif /* BCMCCX */ + +#ifdef MFP +#define WL_AKM_SUITE_MFP_1X 0x000FAC05 +#define WL_AKM_SUITE_MFP_PSK 0x000FAC06 +#define WL_MFP_CAPABLE 0x1 +#define WL_MFP_REQUIRED 0x2 +#endif /* MFP */ + +#ifndef IBSS_COALESCE_ALLOWED +#define IBSS_COALESCE_ALLOWED 0 +#endif + +#ifndef IBSS_INITIAL_SCAN_ALLOWED +#define IBSS_INITIAL_SCAN_ALLOWED 0 +#endif + +#define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */ +/* + * cfg80211_ops api/callback list + */ +static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, + const struct ether_addr *sa, const struct ether_addr *bssid, + u8 **pheader, u32 *body_len, u8 *pbody); +static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request, + struct cfg80211_ssid *this_ssid); +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); +#else +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request); +#endif /* WL_CFG80211_P2P_DEV_IF */ +static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); +#ifdef WLAIBSS_MCHAN +static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name); +static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev); +#endif /* WLAIBSS_MCHAN */ +static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params); +static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev); +static s32 wl_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, u8 *mac, + struct station_info *sinfo); +static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, bool enabled, + s32 timeout); +static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code); +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 mbm); +#else +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, s32 dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, s32 *dbm); +#else +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ +static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_idx, bool unicast, bool multicast); +static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + struct key_params *params); +static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr); +static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + void *cookie, void (*callback) (void *cookie, + struct key_params *params)); +static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx); +static s32 wl_cfg80211_resume(struct wiphy *wiphy); +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) +static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + bcm_struct_cfgdev *cfgdev, u64 cookie); +static s32 wl_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *ndev, u8* mac_addr); +static s32 wl_cfg80211_change_station(struct wiphy *wiphy, + struct net_device *dev, u8 *mac, struct station_parameters *params); +#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) +static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); +#else +static s32 wl_cfg80211_suspend(struct wiphy *wiphy); +#endif +static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa); +static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa); +static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, + struct net_device *dev); +static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg); +#if defined(WL_ABORT_SCAN) +static void wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *dev); +#endif /* WL_ABORT_SCAN */ +static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, + struct net_device *ndev, bool aborted, bool fw_abort); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) +#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) +static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, + u32 peer_capability, const u8 *data, size_t len); +#else +static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data, + size_t len); +#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ +static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, enum nl80211_tdls_operation oper); +#endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */ +#ifdef WL_SCHED_SCAN +static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev); +#endif +#if defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) +bcm_struct_cfgdev* +wl_cfg80211_create_iface(struct wiphy *wiphy, enum nl80211_iftype + iface_type, u8 *mac_addr, const char *name); +s32 +wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev); +#endif /* defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) */ +chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec); + +/* + * event & event Q handlers for cfg80211 interfaces + */ +static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg); +static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg); +static s32 wl_event_handler(void *data); +static void wl_init_eq(struct bcm_cfg80211 *cfg); +static void wl_flush_eq(struct bcm_cfg80211 *cfg); +static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg); +static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags); +static void wl_init_eq_lock(struct bcm_cfg80211 *cfg); +static void wl_init_event_handler(struct bcm_cfg80211 *cfg); +static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg); +static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type, + const wl_event_msg_t *msg, void *data); +static void wl_put_event(struct wl_event_q *e); +static void wl_wakeup_event(struct bcm_cfg80211 *cfg); +static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data, bool completed); +static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#ifdef BT_WIFI_HANDOVER +static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +#endif /* BT_WIFI_HANDOVER */ +#ifdef WL_SCHED_SCAN +static s32 +wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +#endif /* WL_SCHED_SCAN */ +#ifdef PNO_SUPPORT +static s32 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* PNO_SUPPORT */ +#ifdef GSCAN_SUPPORT +static s32 wl_notify_gscan_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* GSCAN_SUPPORT */ +static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, + enum wl_status state, bool set); + +#ifdef WLTDLS +static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* WLTDLS */ +/* + * register/deregister parent device + */ +static void wl_cfg80211_clear_parent_dev(void); + +/* + * ioctl utilites + */ + +/* + * cfg80211 set_wiphy_params utilities + */ +static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); +static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold); +static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); + +/* + * cfg profile utilities + */ +static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data, s32 item); +static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item); +static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev); + +/* + * cfg80211 connect utilites + */ +static s32 wl_set_wpa_version(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_auth_type(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_set_cipher(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_key_mgmt(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_set_sharedkey(struct net_device *dev, + struct cfg80211_connect_params *sme); +#ifdef BCMWAPI_WPI +static s32 wl_set_set_wapi_ie(struct net_device *dev, + struct cfg80211_connect_params *sme); +#endif +static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev); +static void wl_ch_to_chanspec(int ch, + struct wl_join_params *join_params, size_t *join_params_size); + +/* + * information element utilities + */ +static void wl_rst_ie(struct bcm_cfg80211 *cfg); +static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v); +static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam); +static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size); +static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size); +static u32 wl_get_ielen(struct bcm_cfg80211 *cfg); +#ifdef MFP +static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa); +#endif + +#ifdef WL11U +bcm_tlv_t * +wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); +static s32 +wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, + uint8 ie_id, uint8 *data, uint8 data_len); +#endif /* WL11U */ + +static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data); +static void wl_free_wdev(struct bcm_cfg80211 *cfg); + +static s32 wl_inform_bss(struct bcm_cfg80211 *cfg); +static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam); +static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam); +static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); +s32 wl_cfg80211_channel_to_freq(u32 channel); + + +static void wl_cfg80211_work_handler(struct work_struct *work); +static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, + struct key_params *params); +/* + * key indianess swap utilities + */ +static void swap_key_from_BE(struct wl_wsec_key *key); +static void swap_key_to_BE(struct wl_wsec_key *key); + +/* + * bcm_cfg80211 memory init/deinit utilities + */ +static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg); +static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg); + +static void wl_delay(u32 ms); + +/* + * ibss mode utilities + */ +static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev); +static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg); + +/* + * link up/down , default configuration utilities + */ +static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg); +static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg); +static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); +static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, + struct net_device *ndev); +static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); +static void wl_link_up(struct bcm_cfg80211 *cfg); +static void wl_link_down(struct bcm_cfg80211 *cfg); +static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype); +static void wl_init_conf(struct wl_conf *conf); +static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info, + struct net_device* ndev); + +int wl_cfg80211_get_ioctl_version(void); + +/* + * find most significant bit set + */ +static __used u32 wl_find_msb(u16 bit16); + +/* + * rfkill support + */ +static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup); +static int wl_rfkill_set(void *data, bool blocked); +#ifdef DEBUGFS_CFG80211 +static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg); +static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg); +#endif + +static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel, + int nprobes, int *out_params_size); +static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role); + +#ifdef WL_CFG80211_ACL +/* ACL */ +static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, + const struct cfg80211_acl_data *acl); +#endif /* WL_CFG80211_ACL */ + +/* + * Some external functions, TODO: move them to dhd_linux.h + */ +int dhd_add_monitor(char *name, struct net_device **new_ndev); +int dhd_del_monitor(struct net_device *ndev); +int dhd_monitor_init(void *dhd_pub); +int dhd_monitor_uninit(void); +int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); + + +static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const struct ether_addr *bssid); + +static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ, + WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ }; + +#define RETURN_EIO_IF_NOT_UP(wlpriv) \ +do { \ + struct net_device *checkSysUpNDev = bcmcfg_to_prmry_ndev(wlpriv); \ + if (unlikely(!wl_get_drv_status(wlpriv, READY, checkSysUpNDev))) { \ + WL_INFORM(("device is not ready\n")); \ + return -EIO; \ + } \ +} while (0) + +#ifdef RSSI_OFFSET +static s32 wl_rssi_offset(s32 rssi) +{ + rssi += RSSI_OFFSET; + if (rssi > 0) + rssi = 0; + return rssi; +} +#else +#define wl_rssi_offset(x) x +#endif + +#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ + (akm) == RSN_AKM_UNSPECIFIED || \ + (akm) == RSN_AKM_PSK) + + +extern int dhd_wait_pend8021x(struct net_device *dev); +#ifdef PROP_TXSTATUS_VSDB +extern int disable_proptx; +#endif /* PROP_TXSTATUS_VSDB */ + +extern int passive_channel_skip; + +static s32 +wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, +const wl_event_msg_t *e, void *data); +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \ + 0))) +struct chan_info { + int freq; + int chan_type; +}; +#endif + + +#if (WL_DBG_LEVEL > 0) +#define WL_DBG_ESTR_MAX 50 +static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { + "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND", + "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC", + "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END", + "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM", + "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH", + "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND", + "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", + "PFN_NET_LOST", + "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", + "IBSS_ASSOC", + "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT", + "PROBREQ_MSG", + "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", + "EXCEEDED_MEDIUM_TIME", "ICV_ERROR", + "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE", + "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE", + "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG", + "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND", + "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED", + "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT", + "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE", + "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP", + "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE" +}; +#endif /* WL_DBG_LEVEL */ + +#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(DOT11_RATE_1M, 0), + RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_6M, 0), + RATETAB_ENT(DOT11_RATE_9M, 0), + RATETAB_ENT(DOT11_RATE_12M, 0), + RATETAB_ENT(DOT11_RATE_18M, 0), + RATETAB_ENT(DOT11_RATE_24M, 0), + RATETAB_ENT(DOT11_RATE_36M, 0), + RATETAB_ENT(DOT11_RATE_48M, 0), + RATETAB_ENT(DOT11_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(144, 0), + CHAN5G(149, 0), CHAN5G(153, 0), + CHAN5G(157, 0), CHAN5G(161, 0), + CHAN5G(165, 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 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, +#ifdef BCMWAPI_WPI + WLAN_CIPHER_SUITE_SMS4, +#endif +#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK) + WLAN_CIPHER_SUITE_PMK, +#endif +}; + +#ifdef WL_SUPPORT_ACS +/* + * The firmware code required for this feature to work is currently under + * BCMINTERNAL flag. In future if this is to enabled we need to bring the + * required firmware code out of the BCMINTERNAL flag. + */ +struct wl_dump_survey { + u32 obss; + u32 ibss; + u32 no_ctg; + u32 no_pckt; + u32 tx; + u32 idle; +}; +#endif /* WL_SUPPORT_ACS */ + + +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) +static int maxrxpktglom = 0; +#endif + +/* IOCtl version read from targeted driver */ +static int ioctl_version; +#ifdef DEBUGFS_CFG80211 +#define S_SUBLOGLEVEL 20 +static const struct { + u32 log_level; + char *sublogname; +} sublogname_map[] = { + {WL_DBG_ERR, "ERR"}, + {WL_DBG_INFO, "INFO"}, + {WL_DBG_DBG, "DBG"}, + {WL_DBG_SCAN, "SCAN"}, + {WL_DBG_TRACE, "TRACE"}, + {WL_DBG_P2P_ACTION, "P2PACTION"} +}; +#endif + + +static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg, bool add_remove, + enum wl_handler_del_type type) +{ + if (cfg == NULL) + return; + + if (cfg->pm_enable_work_on) { + if (add_remove) { + schedule_delayed_work(&cfg->pm_enable_work, + msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); + } else { + cancel_delayed_work_sync(&cfg->pm_enable_work); + switch (type) { + case WL_HANDLER_MAINTAIN: + schedule_delayed_work(&cfg->pm_enable_work, + msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); + break; + case WL_HANDLER_PEND: + schedule_delayed_work(&cfg->pm_enable_work, + msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT*2)); + break; + case WL_HANDLER_DEL: + default: + cfg->pm_enable_work_on = false; + break; + } + } + } +} + +/* Return a new chanspec given a legacy chanspec + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_from_legacy(chanspec_t legacy_chspec) +{ + chanspec_t chspec; + + /* get the channel number */ + chspec = LCHSPEC_CHANNEL(legacy_chspec); + + /* convert the band */ + if (LCHSPEC_IS2G(legacy_chspec)) { + chspec |= WL_CHANSPEC_BAND_2G; + } else { + chspec |= WL_CHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (LCHSPEC_IS20(legacy_chspec)) { + chspec |= WL_CHANSPEC_BW_20; + } else { + chspec |= WL_CHANSPEC_BW_40; + if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { + chspec |= WL_CHANSPEC_CTL_SB_L; + } else { + chspec |= WL_CHANSPEC_CTL_SB_U; + } + } + + if (wf_chspec_malformed(chspec)) { + WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", + chspec)); + return INVCHANSPEC; + } + + return chspec; +} + +/* Return a legacy chanspec given a new chanspec + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_to_legacy(chanspec_t chspec) +{ + chanspec_t lchspec; + + if (wf_chspec_malformed(chspec)) { + WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", + chspec)); + return INVCHANSPEC; + } + + /* get the channel number */ + lchspec = CHSPEC_CHANNEL(chspec); + + /* convert the band */ + if (CHSPEC_IS2G(chspec)) { + lchspec |= WL_LCHANSPEC_BAND_2G; + } else { + lchspec |= WL_LCHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (CHSPEC_IS20(chspec)) { + lchspec |= WL_LCHANSPEC_BW_20; + lchspec |= WL_LCHANSPEC_CTL_SB_NONE; + } else if (CHSPEC_IS40(chspec)) { + lchspec |= WL_LCHANSPEC_BW_40; + if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { + lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; + } else { + lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; + } + } else { + /* cannot express the bandwidth */ + char chanbuf[CHANSPEC_STR_LEN]; + WL_ERR(( + "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " + "to pre-11ac format\n", + wf_chspec_ntoa(chspec, chanbuf), chspec)); + return INVCHANSPEC; + } + + return lchspec; +} + +/* given a chanspec value, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +chanspec_t +wl_chspec_host_to_driver(chanspec_t chanspec) +{ + if (ioctl_version == 1) { + chanspec = wl_chspec_to_legacy(chanspec); + if (chanspec == INVCHANSPEC) { + return chanspec; + } + } + chanspec = htodchanspec(chanspec); + + return chanspec; +} + +/* given a channel value, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +chanspec_t +wl_ch_host_to_driver(u16 channel) +{ + + chanspec_t chanspec; + + chanspec = channel & WL_CHANSPEC_CHAN_MASK; + + if (channel <= 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; + + return wl_chspec_host_to_driver(chanspec); +} + +/* given a chanspec value from the driver, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +chanspec_t +wl_chspec_driver_to_host(chanspec_t chanspec) +{ + chanspec = dtohchanspec(chanspec); + if (ioctl_version == 1) { + chanspec = wl_chspec_from_legacy(chanspec); + } + + return chanspec; +} + +/* + * convert ASCII string to MAC address (colon-delimited format) + * eg: 00:11:22:33:44:55 + */ +int +wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n) +{ + char *c = NULL; + int count = 0; + + memset(n, 0, ETHER_ADDR_LEN); + for (;;) { + n->octet[count++] = (uint8)simple_strtoul(a, &c, 16); + if (!*c++ || count == ETHER_ADDR_LEN) + break; + a = c; + } + return (count == ETHER_ADDR_LEN); +} + +/* convert hex string buffer to binary */ +int +wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str) +{ + int count, slen; + int hvalue; + char tmp[3] = {0}; + char *ptr = str, *endp = NULL; + + if (!data || !str || !dlen) { + WL_DBG((" passed buffer is empty \n")); + return 0; + } + + slen = strlen(str); + if (dlen * 2 < slen) { + WL_DBG((" destination buffer too short \n")); + return 0; + } + + if (slen % 2) { + WL_DBG((" source buffer is of odd length \n")); + return 0; + } + + for (count = 0; count < slen; count += 2) { + memcpy(tmp, ptr, 2); + hvalue = simple_strtol(tmp, &endp, 16); + if (*endp != '\0') { + WL_DBG((" non hexadecimal character encountered \n")); + return 0; + } + *data++ = (unsigned char)hvalue; + ptr += 2; + } + + return (slen / 2); +} + +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes +wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_AP_VLAN] = { + /* copy AP */ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, +#if defined(WL_CFG80211_P2P_DEV_IF) + [NL80211_IFTYPE_P2P_DEVICE] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, +#endif /* WL_CFG80211_P2P_DEV_IF */ +}; + +static void swap_key_from_BE(struct wl_wsec_key *key) +{ + key->index = htod32(key->index); + key->len = htod32(key->len); + key->algo = htod32(key->algo); + key->flags = htod32(key->flags); + key->rxiv.hi = htod32(key->rxiv.hi); + key->rxiv.lo = htod16(key->rxiv.lo); + key->iv_initialized = htod32(key->iv_initialized); +} + +static void swap_key_to_BE(struct wl_wsec_key *key) +{ + key->index = dtoh32(key->index); + key->len = dtoh32(key->len); + key->algo = dtoh32(key->algo); + key->flags = dtoh32(key->flags); + key->rxiv.hi = dtoh32(key->rxiv.hi); + key->rxiv.lo = dtoh16(key->rxiv.lo); + key->iv_initialized = dtoh32(key->iv_initialized); +} + +/* Dump the contents of the encoded wps ie buffer and get pbc value */ +static void +wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) +{ + #define WPS_IE_FIXED_LEN 6 + u16 len; + u8 *subel = NULL; + u16 subelt_id; + u16 subelt_len; + u16 val; + u8 *valptr = (uint8*) &val; + if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) { + WL_ERR(("invalid argument : NULL\n")); + return; + } + len = (u16)wps_ie[TLV_LEN_OFF]; + + if (len > wps_ie_len) { + WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len)); + return; + } + WL_DBG(("wps_ie len=%d\n", len)); + len -= 4; /* for the WPS IE's OUI, oui_type fields */ + subel = wps_ie + WPS_IE_FIXED_LEN; + while (len >= 4) { /* must have attr id, attr len fields */ + valptr[0] = *subel++; + valptr[1] = *subel++; + subelt_id = HTON16(val); + + valptr[0] = *subel++; + valptr[1] = *subel++; + subelt_len = HTON16(val); + + len -= 4; /* for the attr id, attr len fields */ + + if (len < subelt_len) { + WL_ERR(("not enough data, len %d, subelt_len %d\n", len, + subelt_len)); + break; + } + len -= subelt_len; /* for the remaining fields in this attribute */ + + WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n", + subel, subelt_id, subelt_len)); + + if (subelt_id == WPS_ID_VERSION) { + WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel)); + } else if (subelt_id == WPS_ID_REQ_TYPE) { + WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel)); + } else if (subelt_id == WPS_ID_CONFIG_METHODS) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val))); + } else if (subelt_id == WPS_ID_DEVICE_NAME) { + char devname[100]; + int namelen = MIN(subelt_len, (sizeof(devname) - 1)); + + if (namelen) { + memcpy(devname, subel, namelen); + devname[namelen] = '\0'; + /* Printing len as rx'ed in the IE */ + WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n", + devname, subelt_len)); + } + } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val))); + *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false; + } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val))); + valptr[0] = *(subel + 6); + valptr[1] = *(subel + 7); + WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val))); + } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val))); + valptr[0] = *(subel + 6); + valptr[1] = *(subel + 7); + WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val))); + } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS" + ": cat=%u\n", HTON16(val))); + } else { + WL_DBG((" unknown attr 0x%x\n", subelt_id)); + } + + subel += subelt_len; + } +} + +s32 wl_set_tx_power(struct net_device *dev, + enum nl80211_tx_power_setting type, s32 dbm) +{ + s32 err = 0; + s32 disable = 0; + s32 txpwrqdbm; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + /* Make sure radio is off or on as far as software is concerned */ + disable = WL_RADIO_SW_DISABLE << 16; + disable = htod32(disable); + err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); + return err; + } + + if (dbm > 0xffff) + dbm = 0xffff; + txpwrqdbm = dbm * 4; +#ifdef SUPPORT_WL_TXPOWER + if (type == NL80211_TX_POWER_AUTOMATIC) + txpwrqdbm = 127; + else + txpwrqdbm |= WL_TXPWR_OVERRIDE; +#endif /* SUPPORT_WL_TXPOWER */ + err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm, + sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, + &cfg->ioctl_buf_sync); + if (unlikely(err)) + WL_ERR(("qtxpower error (%d)\n", err)); + else + WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm)); + + return err; +} + +s32 wl_get_tx_power(struct net_device *dev, s32 *dbm) +{ + s32 err = 0; + s32 txpwrdbm; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower", + NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + memcpy(&txpwrdbm, cfg->ioctl_buf, sizeof(txpwrdbm)); + txpwrdbm = dtoh32(txpwrdbm); + *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4; + + WL_INFORM(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm)); + + return err; +} + +static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) +{ + chanspec_t chspec; + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + struct ether_addr bssid; + struct wl_bss_info *bss = NULL; + char *buf; + + memset(&bssid, 0, sizeof(bssid)); + if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) { + /* STA interface is not associated. So start the new interface on a temp + * channel . Later proper channel will be applied by the above framework + * via set_channel (cfg80211 API). + */ + WL_DBG(("Not associated. Return a temp channel. \n")); + return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); + } + + buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!buf) { + WL_ERR(("buf alloc failed. use temp channel\n")); + return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); + } + + *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX); + if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf, + WL_EXTRA_BUF_MAX))) { + WL_ERR(("Failed to get associated bss info, use temp channel \n")); + chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); + } + else { + bss = (wl_bss_info_t *) (buf + 4); + chspec = bss->chanspec; + + WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec)); + } + kfree(buf); + return chspec; +} + +static bcm_struct_cfgdev * +wl_cfg80211_add_monitor_if(char *name) +{ +#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) + WL_INFORM(("wl_cfg80211_add_monitor_if: No more support monitor interface\n")); + return ERR_PTR(-EOPNOTSUPP); +#else + struct net_device* ndev = NULL; + + dhd_add_monitor(name, &ndev); + WL_INFORM(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); + return ndev_to_cfgdev(ndev); +#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */ +} + +static bcm_struct_cfgdev * +wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, +#if defined(WL_CFG80211_P2P_DEV_IF) + const char *name, +#else + char *name, +#endif /* WL_CFG80211_P2P_DEV_IF */ + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + s32 err; + s32 timeout = -1; + s32 wlif_type = -1; + s32 mode = 0; + s32 val = 0; + s32 dhd_mode = 0; + chanspec_t chspec; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *primary_ndev; + struct net_device *new_ndev; + struct ether_addr primary_mac; +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + s32 up = 1; + dhd_pub_t *dhd; + bool enabled; +#endif +#endif /* PROP_TXSTATUS_VSDB */ + + if (!cfg) + return ERR_PTR(-EINVAL); + +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + dhd = (dhd_pub_t *)(cfg->pub); +#endif +#endif /* PROP_TXSTATUS_VSDB */ + + /* Use primary I/F for sending cmds down to firmware */ + primary_ndev = bcmcfg_to_prmry_ndev(cfg); + + if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) { + WL_ERR(("device is not ready\n")); + return ERR_PTR(-ENODEV); + } + + WL_DBG(("if name: %s, type: %d\n", name, type)); + switch (type) { + case NL80211_IFTYPE_ADHOC: +#ifdef WLAIBSS_MCHAN + return bcm_cfg80211_add_ibss_if(wiphy, (char *)name); +#endif /* WLAIBSS_MCHAN */ + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + WL_ERR(("Unsupported interface type\n")); + mode = WL_MODE_IBSS; + return NULL; + case NL80211_IFTYPE_MONITOR: + return wl_cfg80211_add_monitor_if((char *)name); +#if defined(WL_CFG80211_P2P_DEV_IF) + case NL80211_IFTYPE_P2P_DEVICE: + return wl_cfgp2p_add_p2p_disc_if(cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ + case NL80211_IFTYPE_STATION: +#ifdef DUAL_STA +#ifdef WLAIBSS_MCHAN + if (cfg->ibss_cfgdev) { + WL_ERR(("AIBSS is already operational. " + " AIBSS & DUALSTA can't be used together \n")); + return NULL; + } +#endif /* WLAIBSS_MCHAN */ + if (!name) { + WL_ERR(("Interface name not provided \n")); + return NULL; + } + return wl_cfg80211_create_iface(cfg->wdev->wiphy, + NL80211_IFTYPE_STATION, NULL, name); +#endif /* DUAL_STA */ + case NL80211_IFTYPE_P2P_CLIENT: + wlif_type = WL_P2P_IF_CLIENT; + mode = WL_MODE_BSS; + break; + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP: + wlif_type = WL_P2P_IF_GO; + mode = WL_MODE_AP; + break; + default: + WL_ERR(("Unsupported interface type\n")); + return NULL; + break; + } + + if (!name) { + WL_ERR(("name is NULL\n")); + return NULL; + } + if (cfg->p2p_supported && (wlif_type != -1)) { + ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */ + +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + if (!dhd) + return ERR_PTR(-ENODEV); +#endif +#endif /* PROP_TXSTATUS_VSDB */ + if (!cfg->p2p) + return ERR_PTR(-ENODEV); + + if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { + p2p_on(cfg) = true; + wl_cfgp2p_set_firm_p2p(cfg); + wl_cfgp2p_init_discovery(cfg); + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &cfg->p2p->dev_addr, &cfg->p2p->int_addr); + } + + memset(cfg->p2p->vir_ifname, 0, IFNAMSIZ); + strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1); + + wl_cfg80211_scan_abort(cfg); +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + if (!cfg->wlfc_on && !disable_proptx) { + dhd_wlfc_get_enable(dhd, &enabled); + if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) { + dhd_wlfc_init(dhd); + err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32)); + if (err < 0) + WL_ERR(("WLC_UP return err:%d\n", err)); + } + cfg->wlfc_on = true; + } +#endif +#endif /* PROP_TXSTATUS_VSDB */ + + /* In concurrency case, STA may be already associated in a particular channel. + * so retrieve the current channel of primary interface and then start the virtual + * interface on that. + */ + chspec = wl_cfg80211_get_shared_freq(wiphy); + + /* For P2P mode, use P2P-specific driver features to create the + * bss: "cfg p2p_ifadd" + */ + wl_set_p2p_status(cfg, IF_ADDING); + memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); + if (wlif_type == WL_P2P_IF_GO) + wldev_iovar_setint(primary_ndev, "mpc", 0); + err = wl_cfgp2p_ifadd(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec); + if (unlikely(err)) { + wl_clr_p2p_status(cfg, IF_ADDING); + WL_ERR((" virtual iface add failed (%d) \n", err)); + return ERR_PTR(-ENOMEM); + } + + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + (wl_get_p2p_status(cfg, IF_ADDING) == false), + msecs_to_jiffies(MAX_WAIT_TIME)); + + if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) { + struct wireless_dev *vwdev; + int pm_mode = PM_ENABLE; + wl_if_event_info *event = &cfg->if_event_info; + + /* IF_ADD event has come back, we can proceed to to register + * the new interface now, use the interface name provided by caller (thus + * ignore the one from wlc) + */ + strncpy(cfg->if_event_info.name, name, IFNAMSIZ - 1); + new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname, + event->mac, event->bssidx); + if (new_ndev == NULL) + goto fail; + + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = new_ndev; + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = event->bssidx; + vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); + if (unlikely(!vwdev)) { + WL_ERR(("Could not allocate wireless device\n")); + goto fail; + } + vwdev->wiphy = cfg->wdev->wiphy; + WL_INFORM(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname)); + vwdev->iftype = type; + vwdev->netdev = new_ndev; + new_ndev->ieee80211_ptr = vwdev; + SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy)); + wl_set_drv_status(cfg, READY, new_ndev); + cfg->p2p->vif_created = true; + wl_set_mode_by_netdev(cfg, new_ndev, mode); + + if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) { + wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev); + goto fail; + } + wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode); + val = 1; + /* Disable firmware roaming for P2P interface */ + wldev_iovar_setint(new_ndev, "roam_off", val); + + if (mode != WL_MODE_AP) + wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1); + + WL_ERR((" virtual interface(%s) is " + "created net attach done\n", cfg->p2p->vir_ifname)); + if (mode == WL_MODE_AP) + wl_set_drv_status(cfg, CONNECTED, new_ndev); + if (type == NL80211_IFTYPE_P2P_CLIENT) + dhd_mode = DHD_FLAG_P2P_GC_MODE; + else if (type == NL80211_IFTYPE_P2P_GO) + dhd_mode = DHD_FLAG_P2P_GO_MODE; + DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode)); + /* reinitialize completion to clear previous count */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) + INIT_COMPLETION(cfg->iface_disable); +#else + init_completion(&cfg->iface_disable); +#endif + return ndev_to_cfgdev(new_ndev); + } else { + wl_clr_p2p_status(cfg, IF_ADDING); + WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname)); + + WL_ERR(("left timeout : %d\n", timeout)); + WL_ERR(("IF_ADDING status : %d\n", wl_get_p2p_status(cfg, IF_ADDING))); + WL_ERR(("event valid : %d\n", cfg->if_event_info.valid)); + + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + wl_set_p2p_status(cfg, IF_DELETING); + + err = wl_cfgp2p_ifdel(cfg, &cfg->p2p->int_addr); + if (err == BCME_OK) { + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + (wl_get_p2p_status(cfg, IF_DELETING) == false), + msecs_to_jiffies(MAX_WAIT_TIME)); + if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) && + cfg->if_event_info.valid) { + WL_ERR(("IFDEL operation done\n")); + } else { + WL_ERR(("IFDEL didn't complete properly\n")); + err = BCME_ERROR; + } + } + if (err != BCME_OK) { + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + + WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n", + err, ndev->name)); + #ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(((dhd_pub_t *)(cfg->pub))->crash_reason, + "p2p_ifdel failed, error %d, sent HANG event to %s\n", + err, ndev->name); + #endif /* CONFIG_BCM_WLAN_RAMDUMP */ + net_os_send_hang_message(ndev); + } + + memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ); + cfg->p2p->vif_created = false; +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + dhd_wlfc_get_enable(dhd, &enabled); + if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) { + dhd_wlfc_deinit(dhd); + cfg->wlfc_on = false; + } +#endif +#endif /* PROP_TXSTATUS_VSDB */ + } + } + +fail: + if (wlif_type == WL_P2P_IF_GO) + wldev_iovar_setint(primary_ndev, "mpc", 1); + return ERR_PTR(-ENODEV); +} + +static s32 +wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) +{ + struct net_device *dev = NULL; + struct ether_addr p2p_mac; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 timeout = -1; + s32 ret = 0; + s32 index = -1; +#ifdef CUSTOM_SET_CPUCORE + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif /* CUSTOM_SET_CPUCORE */ + WL_DBG(("Enter\n")); + +#ifdef CUSTOM_SET_CPUCORE + dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE; + if (!(dhd->chan_isvht80)) + dhd_set_cpucore(dhd, FALSE); +#endif /* CUSTOM_SET_CPUCORE */ +#if defined(WL_CFG80211_P2P_DEV_IF) + if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { + return wl_cfgp2p_del_p2p_disc_if(cfgdev, cfg); + } +#endif /* WL_CFG80211_P2P_DEV_IF */ + dev = cfgdev_to_wlc_ndev(cfgdev, cfg); + +#ifdef WLAIBSS_MCHAN + if (cfgdev == cfg->ibss_cfgdev) + return bcm_cfg80211_del_ibss_if(wiphy, cfgdev); +#endif /* WLAIBSS_MCHAN */ + +#ifdef DUAL_STA + if (cfgdev == cfg->bss_cfgdev) + return wl_cfg80211_del_iface(wiphy, cfgdev); +#endif /* DUAL_STA */ + + if (wl_cfgp2p_find_idx(cfg, dev, &index) != BCME_OK) { + WL_ERR(("Find p2p index from ndev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (cfg->p2p_supported) { + memcpy(p2p_mac.octet, cfg->p2p->int_addr.octet, ETHER_ADDR_LEN); + + /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases + */ + WL_DBG(("P2P: GO_NEG_PHASE status cleared ")); + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + if (cfg->p2p->vif_created) { + if (wl_get_drv_status(cfg, SCANNING, dev)) { + wl_notify_escan_complete(cfg, dev, true, true); + } + wldev_iovar_setint(dev, "mpc", 1); + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + + /* for GC */ + if (wl_get_drv_status(cfg, DISCONNECTING, dev) && + (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)) { + WL_ERR(("Wait for Link Down event for GC !\n")); + wait_for_completion_timeout + (&cfg->iface_disable, msecs_to_jiffies(500)); + } + + memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); + wl_set_p2p_status(cfg, IF_DELETING); + DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg)); + + /* for GO */ + if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); + /* disable interface before bsscfg free */ + ret = wl_cfgp2p_ifdisable(cfg, &p2p_mac); + /* if fw doesn't support "ifdis", + do not wait for link down of ap mode + */ + if (ret == 0) { + WL_ERR(("Wait for Link Down event for GO !!!\n")); + wait_for_completion_timeout(&cfg->iface_disable, + msecs_to_jiffies(500)); + } else if (ret != BCME_UNSUPPORTED) { + msleep(300); + } + } + wl_cfgp2p_clear_management_ie(cfg, index); + + if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) + wldev_iovar_setint(dev, "buf_key_b4_m4", 0); + + /* delete interface after link down */ + ret = wl_cfgp2p_ifdel(cfg, &p2p_mac); + + if (ret != BCME_OK) { + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + + WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n", + ret, ndev->name)); + #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID) + #ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(((dhd_pub_t *)(cfg->pub))->crash_reason, + ("p2p_ifdel failed, error %d, sent HANG event to %s\n", + ret, ndev->name); + #endif /* CONFIG_BCM_WLAN_RAMDUMP */ + net_os_send_hang_message(ndev); + #endif + } else { + /* Wait for IF_DEL operation to be finished */ + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + (wl_get_p2p_status(cfg, IF_DELETING) == false), + msecs_to_jiffies(MAX_WAIT_TIME)); + if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) && + cfg->if_event_info.valid) { + + WL_DBG(("IFDEL operation done\n")); + wl_cfg80211_handle_ifdel(cfg, &cfg->if_event_info, dev); + } else { + WL_ERR(("IFDEL didn't complete properly\n")); + } + } + + ret = dhd_del_monitor(dev); + if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL((dhd_pub_t *)(cfg->pub)); + } + } + } + return ret; +} + +static s32 +wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + s32 ap = 0; + s32 infra = 0; + s32 ibss = 0; + s32 wlif_type; + s32 mode = 0; + s32 err = BCME_OK; + chanspec_t chspec; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + + WL_DBG(("Enter type %d\n", type)); + switch (type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + ap = 1; + WL_ERR(("type (%d) : currently we do not support this type\n", + type)); + break; + case NL80211_IFTYPE_ADHOC: + mode = WL_MODE_IBSS; + ibss = 1; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + mode = WL_MODE_BSS; + infra = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + mode = WL_MODE_AP; + ap = 1; + break; + default: + return -EINVAL; + } + if (!dhd) + return -EINVAL; + if (ap) { + wl_set_mode_by_netdev(cfg, ndev, mode); + if (cfg->p2p_supported && cfg->p2p->vif_created) { + WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", cfg->p2p->vif_created, + p2p_on(cfg))); + wldev_iovar_setint(ndev, "mpc", 0); + wl_notify_escan_complete(cfg, ndev, true, true); + + /* In concurrency case, STA may be already associated in a particular + * channel. so retrieve the current channel of primary interface and + * then start the virtual interface on that. + */ + chspec = wl_cfg80211_get_shared_freq(wiphy); + + wlif_type = WL_P2P_IF_GO; + WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", + ndev->name, ap, infra, type)); + wl_set_p2p_status(cfg, IF_CHANGING); + wl_clr_p2p_status(cfg, IF_CHANGED); + wl_cfgp2p_ifchange(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec); + wait_event_interruptible_timeout(cfg->netif_change_event, + (wl_get_p2p_status(cfg, IF_CHANGED) == true), + msecs_to_jiffies(MAX_WAIT_TIME)); + wl_set_mode_by_netdev(cfg, ndev, mode); + dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE; + dhd->op_mode |= DHD_FLAG_P2P_GO_MODE; + wl_clr_p2p_status(cfg, IF_CHANGING); + wl_clr_p2p_status(cfg, IF_CHANGED); + if (mode == WL_MODE_AP) + wl_set_drv_status(cfg, CONNECTED, ndev); + } else if (ndev == bcmcfg_to_prmry_ndev(cfg) && + !wl_get_drv_status(cfg, AP_CREATED, ndev)) { + wl_set_drv_status(cfg, AP_CREATING, ndev); + if (!cfg->ap_info && + !(cfg->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) { + WL_ERR(("struct ap_saved_ie allocation failed\n")); + return -ENOMEM; + } + } else { + WL_ERR(("Cannot change the interface for GO or SOFTAP\n")); + return -EINVAL; + } + } else { + WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA")); + } + + if (ibss) { + infra = 0; + wl_set_mode_by_netdev(cfg, ndev, mode); + err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(s32)); + if (err < 0) { + WL_ERR(("SET Adhoc error %d\n", err)); + return -EINVAL; + } + } + + ndev->ieee80211_ptr->iftype = type; + return 0; +} + +s32 +wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx) +{ + bool ifadd_expected = FALSE; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd") + * redirect the IF_ADD event to ifchange as it is not a real "new" interface + */ + if (wl_get_p2p_status(cfg, IF_CHANGING)) + return wl_cfg80211_notify_ifchange(ifidx, name, mac, bssidx); + + /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */ + if (wl_get_p2p_status(cfg, IF_ADDING)) { + ifadd_expected = TRUE; + wl_clr_p2p_status(cfg, IF_ADDING); + } else if (cfg->bss_pending_op) { + ifadd_expected = TRUE; + cfg->bss_pending_op = FALSE; + } + + if (ifadd_expected) { + wl_if_event_info *if_event_info = &cfg->if_event_info; + + if_event_info->valid = TRUE; + if_event_info->ifidx = ifidx; + if_event_info->bssidx = bssidx; + strncpy(if_event_info->name, name, IFNAMSIZ); + if_event_info->name[IFNAMSIZ] = '\0'; + if (mac) + memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN); + wake_up_interruptible(&cfg->netif_change_event); + return BCME_OK; + } + + return BCME_ERROR; +} + +s32 +wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx) +{ + bool ifdel_expected = FALSE; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + wl_if_event_info *if_event_info = &cfg->if_event_info; + + if (wl_get_p2p_status(cfg, IF_DELETING)) { + ifdel_expected = TRUE; + wl_clr_p2p_status(cfg, IF_DELETING); + } else if (cfg->bss_pending_op) { + ifdel_expected = TRUE; + cfg->bss_pending_op = FALSE; + } + + if (ifdel_expected) { + if_event_info->valid = TRUE; + if_event_info->ifidx = ifidx; + if_event_info->bssidx = bssidx; + wake_up_interruptible(&cfg->netif_change_event); + return BCME_OK; + } + + return BCME_ERROR; +} + +s32 +wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (wl_get_p2p_status(cfg, IF_CHANGING)) { + wl_set_p2p_status(cfg, IF_CHANGED); + wake_up_interruptible(&cfg->netif_change_event); + return BCME_OK; + } + + return BCME_ERROR; +} + +static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info, + struct net_device* ndev) +{ + s32 type = -1; + s32 bssidx = -1; +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + bool enabled; +#endif +#endif /* PROP_TXSTATUS_VSDB */ + + bssidx = if_event_info->bssidx; + if (bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION)) { + WL_ERR(("got IF_DEL for if %d, not owned by cfg driver\n", bssidx)); + return BCME_ERROR; + } + + if (p2p_is_on(cfg) && cfg->p2p->vif_created) { + + if (cfg->scan_request && (cfg->escan_info.ndev == ndev)) { + /* Abort any pending scan requests */ + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + WL_DBG(("ESCAN COMPLETED\n")); + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, false); + } + + memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ); + if (wl_cfgp2p_find_type(cfg, bssidx, &type) != BCME_OK) { + WL_ERR(("Find p2p type from bssidx(%d) failed\n", bssidx)); + return BCME_ERROR; + } + wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, type)); + wl_to_p2p_bss_ndev(cfg, type) = NULL; + wl_to_p2p_bss_bssidx(cfg, type) = WL_INVALID; + cfg->p2p->vif_created = false; + +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + dhd_wlfc_get_enable(dhd, &enabled); + if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) { + dhd_wlfc_deinit(dhd); + cfg->wlfc_on = false; + } +#endif +#endif /* PROP_TXSTATUS_VSDB */ + } + + wl_cfg80211_remove_if(cfg, if_event_info->ifidx, ndev); + return BCME_OK; +} + +/* Find listen channel */ +static s32 wl_find_listen_channel(struct bcm_cfg80211 *cfg, + const u8 *ie, u32 ie_len) +{ + wifi_p2p_ie_t *p2p_ie; + u8 *end, *pos; + s32 listen_channel; + + pos = (u8 *)ie; + p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len); + + if (p2p_ie == NULL) + return 0; + + pos = p2p_ie->subelts; + end = p2p_ie->subelts + (p2p_ie->len - 4); + + CFGP2P_DBG((" found p2p ie ! lenth %d \n", + p2p_ie->len)); + + while (pos < end) { + uint16 attr_len; + if (pos + 2 >= end) { + CFGP2P_DBG((" -- Invalid P2P attribute")); + return 0; + } + attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0])); + + if (pos + 3 + attr_len > end) { + CFGP2P_DBG(("P2P: Attribute underflow " + "(len=%u left=%d)", + attr_len, (int) (end - pos - 3))); + return 0; + } + + /* if Listen Channel att id is 6 and the vailue is valid, + * return the listen channel + */ + if (pos[0] == 6) { + /* listen channel subel length format + * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num) + */ + listen_channel = pos[1 + 2 + 3 + 1]; + + if (listen_channel == SOCIAL_CHAN_1 || + listen_channel == SOCIAL_CHAN_2 || + listen_channel == SOCIAL_CHAN_3) { + CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel)); + return listen_channel; + } + } + pos += 3 + attr_len; + } + return 0; +} + +static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) +{ + u32 n_ssids; + u32 n_channels; + u16 channel; + chanspec_t chanspec; + s32 i = 0, j = 0, offset; + char *ptr; + wlc_ssid_t ssid; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + params->bss_type = DOT11_BSSTYPE_ANY; + params->scan_type = 0; + params->nprobes = -1; + params->active_time = -1; + params->passive_time = -1; + params->home_time = -1; + params->channel_num = 0; + memset(¶ms->ssid, 0, sizeof(wlc_ssid_t)); + + WL_SCAN(("Preparing Scan request\n")); + WL_SCAN(("nprobes=%d\n", params->nprobes)); + WL_SCAN(("active_time=%d\n", params->active_time)); + WL_SCAN(("passive_time=%d\n", params->passive_time)); + WL_SCAN(("home_time=%d\n", params->home_time)); + WL_SCAN(("scan_type=%d\n", params->scan_type)); + + params->nprobes = htod32(params->nprobes); + params->active_time = htod32(params->active_time); + params->passive_time = htod32(params->passive_time); + params->home_time = htod32(params->home_time); + + /* if request is null just exit so it will be all channel broadcast scan */ + if (!request) + return; + + n_ssids = request->n_ssids; + n_channels = request->n_channels; + + /* Copy channel array if applicable */ + WL_SCAN(("### List of channelspecs to scan ###\n")); + if (n_channels > 0) { + for (i = 0; i < n_channels; i++) { + chanspec = 0; + channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); + /* SKIP DFS channels for Secondary interface */ + if ((cfg->escan_info.ndev != bcmcfg_to_prmry_ndev(cfg)) && + (request->channels[i]->flags & +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) +#else + (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR))) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */ + continue; + + if (request->channels[i]->band == IEEE80211_BAND_2GHZ) { +#ifdef WL_HOST_BAND_MGMT + if (cfg->curr_band == WLC_BAND_5G) { + WL_DBG(("In 5G only mode, omit 2G channel:%d\n", channel)); + continue; + } +#endif /* WL_HOST_BAND_MGMT */ + chanspec |= WL_CHANSPEC_BAND_2G; + } else { +#ifdef WL_HOST_BAND_MGMT + if (cfg->curr_band == WLC_BAND_2G) { + WL_DBG(("In 2G only mode, omit 5G channel:%d\n", channel)); + continue; + } +#endif /* WL_HOST_BAND_MGMT */ + chanspec |= WL_CHANSPEC_BAND_5G; + } + + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + params->channel_list[j] = channel; + params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK; + params->channel_list[j] |= chanspec; + WL_SCAN(("Chan : %d, Channel spec: %x \n", + channel, params->channel_list[j])); + params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]); + j++; + } + } else { + WL_SCAN(("Scanning all channels\n")); + } + n_channels = j; + /* Copy ssid array if applicable */ + WL_SCAN(("### List of SSIDs to scan ###\n")); + if (n_ssids > 0) { + offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); + offset = roundup(offset, sizeof(u32)); + ptr = (char*)params + offset; + for (i = 0; i < n_ssids; i++) { + memset(&ssid, 0, sizeof(wlc_ssid_t)); + ssid.SSID_len = MIN(request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN); + memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); + if (!ssid.SSID_len) + WL_SCAN(("%d: Broadcast scan\n", i)); + else + WL_SCAN(("%d: scan for %s size =%d\n", i, + ssid.SSID, ssid.SSID_len)); + memcpy(ptr, &ssid, sizeof(wlc_ssid_t)); + ptr += sizeof(wlc_ssid_t); + } + } else { + WL_SCAN(("Broadcast scan\n")); + } + /* Adding mask to channel numbers */ + params->channel_num = + htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | + (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); + + if (n_channels == 1) { + params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS); + } +} + +static s32 +wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) +{ + wl_uint32_list_t *list; + s32 err = BCME_OK; + if (valid_chan_list == NULL || size <= 0) + return -ENOMEM; + + memset(valid_chan_list, 0, size); + list = (wl_uint32_list_t *)(void *) valid_chan_list; + list->count = htod32(WL_NUMCHANNELS); + err = wldev_ioctl_get(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size); + if (err != 0) { + WL_ERR(("get channels failed with %d\n", err)); + } + + return err; +} + +#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) +#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40 +bool g_first_broadcast_scan = TRUE; +#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ + +static s32 +wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, + struct cfg80211_scan_request *request, uint16 action) +{ + s32 err = BCME_OK; + u32 n_channels; + u32 n_ssids; + s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); + wl_escan_params_t *params = NULL; + u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS)]; + u32 num_chans = 0; + s32 channel; + s32 n_valid_chan; + s32 search_state = WL_P2P_DISC_ST_SCAN; + u32 i, j, n_nodfs = 0; + u16 *default_chan_list = NULL; + wl_uint32_list_t *list; + struct net_device *dev = NULL; +#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) + bool is_first_init_2g_scan = false; +#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ + p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN; + + WL_DBG(("Enter \n")); + + /* scan request can come with empty request : perform all default scan */ + if (!cfg) { + err = -EINVAL; + goto exit; + } + if (!cfg->p2p_supported || !p2p_scan(cfg)) { + /* LEGACY SCAN TRIGGER */ + WL_SCAN((" LEGACY E-SCAN START\n")); + +#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) + if (!request) { + err = -EINVAL; + goto exit; + } + if (ndev == bcmcfg_to_prmry_ndev(cfg) && g_first_broadcast_scan == true) { +#ifdef USE_INITIAL_2G_SCAN + struct ieee80211_channel tmp_channel_list[CH_MAX_2G_CHANNEL]; + /* allow one 5G channel to add previous connected channel in 5G */ + bool allow_one_5g_channel = TRUE; + j = 0; + for (i = 0; i < request->n_channels; i++) { + int tmp_chan = ieee80211_frequency_to_channel + (request->channels[i]->center_freq); + if (tmp_chan > CH_MAX_2G_CHANNEL) { + if (allow_one_5g_channel) + allow_one_5g_channel = FALSE; + else + continue; + } + if (j > CH_MAX_2G_CHANNEL) { + WL_ERR(("Index %d exceeds max 2.4GHz channels %d" + " and previous 5G connected channel\n", + j, CH_MAX_2G_CHANNEL)); + break; + } + bcopy(request->channels[i], &tmp_channel_list[j], + sizeof(struct ieee80211_channel)); + WL_SCAN(("channel of request->channels[%d]=%d\n", i, tmp_chan)); + j++; + } + if ((j > 0) && (j <= CH_MAX_2G_CHANNEL)) { + for (i = 0; i < j; i++) + bcopy(&tmp_channel_list[i], request->channels[i], + sizeof(struct ieee80211_channel)); + + request->n_channels = j; + is_first_init_2g_scan = true; + } + else + WL_ERR(("Invalid number of 2.4GHz channels %d\n", j)); + + WL_SCAN(("request->n_channels=%d\n", request->n_channels)); +#else /* USE_INITIAL_SHORT_DWELL_TIME */ + is_first_init_2g_scan = true; +#endif /* USE_INITIAL_2G_SCAN */ + g_first_broadcast_scan = false; + } +#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ + + /* if scan request is not empty parse scan request paramters */ + if (request != NULL) { + n_channels = request->n_channels; + n_ssids = request->n_ssids; + if (n_channels % 2) + /* If n_channels is odd, add a padd of u16 */ + params_size += sizeof(u16) * (n_channels + 1); + else + params_size += sizeof(u16) * n_channels; + + /* Allocate space for populating ssids in wl_escan_params_t struct */ + params_size += sizeof(struct wlc_ssid) * n_ssids; + } + params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); + if (params == NULL) { + err = -ENOMEM; + goto exit; + } + wl_scan_prep(¶ms->params, request); + +#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) + /* Override active_time to reduce scan time if it's first bradcast scan. */ + if (is_first_init_2g_scan) + params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; +#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ + + params->version = htod32(ESCAN_REQ_VERSION); + params->action = htod16(action); + wl_escan_set_sync_id(params->sync_id, cfg); + wl_escan_set_type(cfg, WL_SCANTYPE_LEGACY); + if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { + WL_ERR(("ioctl buffer length not sufficient\n")); + kfree(params); + err = -ENOMEM; + goto exit; + } + err = wldev_iovar_setbuf(ndev, "escan", params, params_size, + cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(err)) { + if (err == BCME_EPERM) + /* Scan Not permitted at this point of time */ + WL_DBG((" Escan not permitted at this time (%d)\n", err)); + else + WL_ERR((" Escan set error (%d)\n", err)); + } + kfree(params); + } + else if (p2p_is_on(cfg) && p2p_scan(cfg)) { + /* P2P SCAN TRIGGER */ + s32 _freq = 0; + n_nodfs = 0; + if (request && request->n_channels) { + num_chans = request->n_channels; + WL_SCAN((" chann number : %d\n", num_chans)); + default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), + GFP_KERNEL); + if (default_chan_list == NULL) { + WL_ERR(("channel list allocation failed \n")); + err = -ENOMEM; + goto exit; + } + if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { + list = (wl_uint32_list_t *) chan_buf; + n_valid_chan = dtoh32(list->count); + if (n_valid_chan > WL_NUMCHANNELS) { + WL_ERR(("wrong n_valid_chan:%d\n", n_valid_chan)); + kfree(default_chan_list); + err = -EINVAL; + goto exit; + } + + for (i = 0; i < num_chans; i++) + { +#ifdef WL_HOST_BAND_MGMT + int channel_band = 0; +#endif /* WL_HOST_BAND_MGMT */ + _freq = request->channels[i]->center_freq; + channel = ieee80211_frequency_to_channel(_freq); +#ifdef WL_HOST_BAND_MGMT + channel_band = (channel > CH_MAX_2G_CHANNEL) ? + WLC_BAND_5G : WLC_BAND_2G; + if ((cfg->curr_band != WLC_BAND_AUTO) && + (cfg->curr_band != channel_band) && + !IS_P2P_SOCIAL_CHANNEL(channel)) + continue; +#endif /* WL_HOST_BAND_MGMT */ + + /* ignore DFS channels */ + if (request->channels[i]->flags & +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + (IEEE80211_CHAN_NO_IR + | IEEE80211_CHAN_RADAR)) +#else + (IEEE80211_CHAN_RADAR +#ifdef CUSTOMER_HW5 + | 0)) +#else + | IEEE80211_CHAN_PASSIVE_SCAN)) +#endif /* CUSTOMER_HW5 */ +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ + continue; + + for (j = 0; j < n_valid_chan; j++) { + /* allows only supported channel on + * current reguatory + */ + if (n_nodfs >= num_chans) { + break; + } + if (channel == (dtoh32(list->element[j]))) { + default_chan_list[n_nodfs++] = + channel; + } + } + + } + } + if (num_chans == SOCIAL_CHAN_CNT && ( + (default_chan_list[0] == SOCIAL_CHAN_1) && + (default_chan_list[1] == SOCIAL_CHAN_2) && + (default_chan_list[2] == SOCIAL_CHAN_3))) { + /* SOCIAL CHANNELS 1, 6, 11 */ + search_state = WL_P2P_DISC_ST_SEARCH; + p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; + WL_INFORM(("P2P SEARCH PHASE START \n")); + } else if ((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) && + (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) { + /* If you are already a GO, then do SEARCH only */ + WL_INFORM(("Already a GO. Do SEARCH Only")); + search_state = WL_P2P_DISC_ST_SEARCH; + num_chans = n_nodfs; + p2p_scan_purpose = P2P_SCAN_NORMAL; + + } else if (num_chans == 1) { + p2p_scan_purpose = P2P_SCAN_CONNECT_TRY; + } else if (num_chans == SOCIAL_CHAN_CNT + 1) { + /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by + * the supplicant + */ + p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; + } else { + WL_INFORM(("P2P SCAN STATE START \n")); + num_chans = n_nodfs; + p2p_scan_purpose = P2P_SCAN_NORMAL; + } + } else { + err = -EINVAL; + goto exit; + } + err = wl_cfgp2p_escan(cfg, ndev, cfg->active_scan, num_chans, default_chan_list, + search_state, action, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE), NULL, + p2p_scan_purpose); + + if (!err) + cfg->p2p->search_state = search_state; + + kfree(default_chan_list); + } +exit: + if (unlikely(err)) { + /* Don't print Error incase of Scan suppress */ + if ((err == BCME_EPERM) && cfg->scan_suppressed) + WL_DBG(("Escan failed: Scan Suppressed \n")); + else + WL_ERR(("error (%d)\n", err)); + } + return err; +} + + +static s32 +wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) +{ + s32 err = BCME_OK; + s32 passive_scan; + s32 passive_scan_time; + s32 passive_scan_time_org = 0; + wl_scan_results_t *results; + WL_SCAN(("Enter \n")); + mutex_lock(&cfg->usr_sync); + + results = wl_escan_get_buf(cfg, FALSE); + results->version = 0; + results->count = 0; + results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; + + cfg->escan_info.ndev = ndev; + cfg->escan_info.wiphy = wiphy; + cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING; + passive_scan = cfg->active_scan ? 0 : 1; + err = wldev_ioctl_set(ndev, WLC_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan)); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + goto exit; + } + + if (passive_channel_skip) { + + err = wldev_ioctl_get(ndev, WLC_GET_SCAN_PASSIVE_TIME, + &passive_scan_time_org, sizeof(passive_scan_time_org)); + if (unlikely(err)) { + WL_ERR(("== error (%d)\n", err)); + goto exit; + } + + WL_SCAN(("PASSIVE SCAN time : %d \n", passive_scan_time_org)); + + passive_scan_time = 0; + err = wldev_ioctl_set(ndev, WLC_SET_SCAN_PASSIVE_TIME, + &passive_scan_time, sizeof(passive_scan_time)); + if (unlikely(err)) { + WL_ERR(("== error (%d)\n", err)); + goto exit; + } + + WL_SCAN(("PASSIVE SCAN SKIPED!! (passive_channel_skip:%d) \n", + passive_channel_skip)); + } + + err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START); + + if (passive_channel_skip) { + err = wldev_ioctl_set(ndev, WLC_SET_SCAN_PASSIVE_TIME, + &passive_scan_time_org, sizeof(passive_scan_time_org)); + if (unlikely(err)) { + WL_ERR(("== error (%d)\n", err)); + goto exit; + } + + WL_SCAN(("PASSIVE SCAN RECOVERED!! (passive_scan_time_org:%d) \n", + passive_scan_time_org)); + } + +exit: + mutex_unlock(&cfg->usr_sync); + return err; +} + +static s32 +__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request, + struct cfg80211_ssid *this_ssid) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct cfg80211_ssid *ssids; + struct ether_addr primary_mac; + bool p2p_ssid; +#ifdef WL11U + bcm_tlv_t *interworking_ie; +#endif + s32 err = 0; + s32 bssidx = -1; + s32 i; + + unsigned long flags; + static s32 busy_count = 0; +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + struct net_device *remain_on_channel_ndev = NULL; +#endif + + dhd_pub_t *dhd; + + dhd = (dhd_pub_t *)(cfg->pub); + /* + * Hostapd triggers scan before starting automatic channel selection + * also Dump stats IOVAR scans each channel hence returning from here. + */ + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { +#ifdef WL_SUPPORT_ACS + WL_INFORM(("Scan Command at SoftAP mode\n")); + return 0; +#else + WL_ERR(("Invalid Scan Command at SoftAP mode\n")); + return -EINVAL; +#endif /* WL_SUPPORT_ACS */ + } + + ndev = ndev_to_wlc_ndev(ndev, cfg); + + if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) { + WL_ERR(("Sending Action Frames. Try it again.\n")); + return -EAGAIN; + } + + WL_DBG(("Enter wiphy (%p)\n", wiphy)); + if (wl_get_drv_status_all(cfg, SCANNING)) { + if (cfg->scan_request == NULL) { + wl_clr_drv_status_all(cfg, SCANNING); + WL_DBG(("<<<<<<<<<<>>>>>>>>>>\n")); + } else { + WL_ERR(("Scanning already\n")); + return -EAGAIN; + } + } + if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) { + WL_ERR(("Scanning being aborted\n")); + return -EAGAIN; + } + if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { + WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); + return -EOPNOTSUPP; + } +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg); + if (remain_on_channel_ndev) { + WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n")); + wl_notify_escan_complete(cfg, remain_on_channel_ndev, true, true); + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + + + /* Arm scan timeout timer */ + mod_timer(&cfg->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); + if (request) { /* scan bss */ + ssids = request->ssids; + p2p_ssid = false; + for (i = 0; i < request->n_ssids; i++) { + if (ssids[i].ssid_len && + IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { + p2p_ssid = true; + break; + } + } + if (p2p_ssid) { + if (cfg->p2p_supported) { + /* p2p scan trigger */ + if (p2p_on(cfg) == false) { + /* p2p on at the first time */ + p2p_on(cfg) = true; + wl_cfgp2p_set_firm_p2p(cfg); + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &cfg->p2p->dev_addr, &cfg->p2p->int_addr); + } + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); + p2p_scan(cfg) = true; + } + } else { + /* legacy scan trigger + * So, we have to disable p2p discovery if p2p discovery is on + */ + if (cfg->p2p_supported) { + p2p_scan(cfg) = false; + /* If Netdevice is not equals to primary and p2p is on + * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. + */ + + if (p2p_scan(cfg) == false) { + if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { + err = wl_cfgp2p_discover_enable_search(cfg, + false); + if (unlikely(err)) { + goto scan_out; + } + + } + } + } + if (!cfg->p2p_supported || !p2p_scan(cfg)) { + + if (wl_cfgp2p_find_idx(cfg, ndev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from ndev(%p) failed\n", + ndev)); + err = BCME_ERROR; + goto scan_out; + } +#ifdef WL11U + if ((interworking_ie = wl_cfg80211_find_interworking_ie( + (u8 *)request->ie, request->ie_len)) != NULL) { + err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, + VNDR_IE_CUSTOM_FLAG, interworking_ie->id, + interworking_ie->data, interworking_ie->len); + + if (unlikely(err)) { + goto scan_out; + } + } else if (cfg->iw_ie_len != 0) { + /* we have to clear IW IE and disable gratuitous APR */ + wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, + VNDR_IE_CUSTOM_FLAG, + DOT11_MNG_INTERWORKING_ID, + 0, 0); + + wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, + bssidx); + cfg->wl11u = FALSE; + /* we don't care about error */ + } +#endif /* WL11U */ + err = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, + VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, + request->ie_len); + + if (unlikely(err)) { + goto scan_out; + } + + } + } + } else { /* scan in ibss */ + ssids = this_ssid; + } + + if (request && !p2p_scan(cfg)) { + WL_TRACE_HW4(("START SCAN\n")); + } + + cfg->scan_request = request; + wl_set_drv_status(cfg, SCANNING, ndev); + + if (cfg->p2p_supported) { + if (p2p_on(cfg) && p2p_scan(cfg)) { + + /* find my listen channel */ + cfg->afx_hdl->my_listen_chan = + wl_find_listen_channel(cfg, request->ie, + request->ie_len); + err = wl_cfgp2p_enable_discovery(cfg, ndev, + request->ie, request->ie_len); + + if (unlikely(err)) { + goto scan_out; + } + } + } + err = wl_do_escan(cfg, wiphy, ndev, request); + if (likely(!err)) + goto scan_success; + else + goto scan_out; + +scan_success: + busy_count = 0; + + return 0; + +scan_out: + if (err == BCME_BUSY || err == BCME_NOTREADY) { + WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY)); + err = -EBUSY; + } + +#define SCAN_EBUSY_RETRY_LIMIT 10 + if (err == -EBUSY) { + if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) { + struct ether_addr bssid; + s32 ret = 0; + busy_count = 0; + WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n", + wl_get_drv_status(cfg, SCANNING, ndev), + wl_get_drv_status(cfg, SCAN_ABORTING, ndev), + wl_get_drv_status(cfg, CONNECTING, ndev), + wl_get_drv_status(cfg, CONNECTED, ndev), + wl_get_drv_status(cfg, DISCONNECTING, ndev), + wl_get_drv_status(cfg, AP_CREATING, ndev), + wl_get_drv_status(cfg, AP_CREATED, ndev), + wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev), + wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev))); + + bzero(&bssid, sizeof(bssid)); + if ((ret = wldev_ioctl_get(ndev, WLC_GET_BSSID, + &bssid, ETHER_ADDR_LEN)) == 0) + WL_ERR(("FW is connected with " MACDBG "/n", + MAC2STRDBG(bssid.octet))); + else + WL_ERR(("GET BSSID failed with %d\n", ret)); + + wl_cfg80211_scan_abort(cfg); + + } + } else { + busy_count = 0; + } + + wl_clr_drv_status(cfg, SCANNING, ndev); + if (timer_pending(&cfg->scan_timeout)) + del_timer_sync(&cfg->scan_timeout); + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + cfg->scan_request = NULL; + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + return err; +} + +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +#else +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) +#endif /* WL_CFG80211_P2P_DEV_IF */ +{ + s32 err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); +#if defined(WL_CFG80211_P2P_DEV_IF) + struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ + + WL_DBG(("Enter \n")); + RETURN_EIO_IF_NOT_UP(cfg); + + + err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); + if (unlikely(err)) { + if ((err == BCME_EPERM) && cfg->scan_suppressed) + WL_DBG(("scan not permitted at this time (%d)\n", err)); + else + WL_ERR(("scan error (%d)\n", err)); + return err; + } + + return err; +} + +static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) +{ + s32 err = 0; + + err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) +{ + s32 err = 0; + + err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) +{ + s32 err = 0; + u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); + + retry = htod32(retry); + err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry)); + if (unlikely(err)) { + WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); + return err; + } + return err; +} + +static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; + + RETURN_EIO_IF_NOT_UP(cfg); + WL_DBG(("Enter\n")); + if (changed & WIPHY_PARAM_RTS_THRESHOLD && + (cfg->conf->rts_threshold != wiphy->rts_threshold)) { + cfg->conf->rts_threshold = wiphy->rts_threshold; + err = wl_set_rts(ndev, cfg->conf->rts_threshold); + if (err != BCME_OK) + return err; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD && + (cfg->conf->frag_threshold != wiphy->frag_threshold)) { + cfg->conf->frag_threshold = wiphy->frag_threshold; + err = wl_set_frag(ndev, cfg->conf->frag_threshold); + if (err != BCME_OK) + return err; + } + if (changed & WIPHY_PARAM_RETRY_LONG && + (cfg->conf->retry_long != wiphy->retry_long)) { + cfg->conf->retry_long = wiphy->retry_long; + err = wl_set_retry(ndev, cfg->conf->retry_long, true); + if (err != BCME_OK) + return err; + } + if (changed & WIPHY_PARAM_RETRY_SHORT && + (cfg->conf->retry_short != wiphy->retry_short)) { + cfg->conf->retry_short = wiphy->retry_short; + err = wl_set_retry(ndev, cfg->conf->retry_short, false); + if (err != BCME_OK) { + return err; + } + } + + return err; +} +static chanspec_t +channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + u8 *buf = NULL; + wl_uint32_list_t *list; + int err = BCME_OK; + chanspec_t c = 0, ret_c = 0; + int bw = 0, tmp_bw = 0; + int i; + u32 tmp_c; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; +#define LOCAL_BUF_SIZE 1024 + buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags); + if (!buf) { + WL_ERR(("buf memory alloc failed\n")); + goto exit; + } + + err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, + 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync); + if (err != BCME_OK) { + WL_ERR(("get chanspecs failed with %d\n", err)); + goto exit; + } + + list = (wl_uint32_list_t *)(void *)buf; + for (i = 0; i < dtoh32(list->count); i++) { + c = dtoh32(list->element[i]); + if (channel <= CH_MAX_2G_CHANNEL) { + if (!CHSPEC_IS20(c)) + continue; + if (channel == CHSPEC_CHANNEL(c)) { + ret_c = c; + bw = 20; + goto exit; + } + } + tmp_c = wf_chspec_ctlchan(c); + tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT]; + if (tmp_c != channel) + continue; + + if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) { + bw = tmp_bw; + ret_c = c; + if (bw == bw_cap) + goto exit; + } + } +exit: + if (buf) + kfree(buf); +#undef LOCAL_BUF_SIZE + WL_INFORM(("return chanspec %x %d\n", ret_c, bw)); + return ret_c; +} + +void +wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (cfg != NULL && ibss_vsie != NULL) { + if (cfg->ibss_vsie != NULL) { + kfree(cfg->ibss_vsie); + } + cfg->ibss_vsie = ibss_vsie; + cfg->ibss_vsie_len = ibss_vsie_len; + } +} + +static void +wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg) +{ + /* free & initiralize VSIE (Vendor Specific IE) */ + if (cfg->ibss_vsie != NULL) { + kfree(cfg->ibss_vsie); + cfg->ibss_vsie = NULL; + cfg->ibss_vsie_len = 0; + } +} + +s32 +wl_cfg80211_ibss_vsie_delete(struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + char *ioctl_buf = NULL; + s32 ret = BCME_OK; + + if (cfg != NULL && cfg->ibss_vsie != NULL) { + ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + return -ENOMEM; + } + + /* change the command from "add" to "del" */ + strncpy(cfg->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1); + cfg->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + ret = wldev_iovar_setbuf(dev, "ie", + cfg->ibss_vsie, cfg->ibss_vsie_len, + ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + WL_ERR(("ret=%d\n", ret)); + + if (ret == BCME_OK) { + /* free & initiralize VSIE */ + kfree(cfg->ibss_vsie); + cfg->ibss_vsie = NULL; + cfg->ibss_vsie_len = 0; + } + + if (ioctl_buf) { + kfree(ioctl_buf); + } + } + + return ret; +} + +#ifdef WLAIBSS_MCHAN +static bcm_struct_cfgdev* +bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct wireless_dev* wdev = NULL; + struct net_device *new_ndev = NULL; + struct net_device *primary_ndev = NULL; + s32 timeout; + wl_aibss_if_t aibss_if; + wl_if_event_info *event = NULL; + + if (cfg->ibss_cfgdev != NULL) { + WL_ERR(("IBSS interface %s already exists\n", name)); + return NULL; + } + + WL_ERR(("Try to create IBSS interface %s\n", name)); + primary_ndev = bcmcfg_to_prmry_ndev(cfg); + /* generate a new MAC address for the IBSS interface */ + get_primary_mac(cfg, &cfg->ibss_if_addr); + cfg->ibss_if_addr.octet[4] ^= 0x40; + memset(&aibss_if, sizeof(aibss_if), 0); + memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr)); + aibss_if.chspec = 0; + aibss_if.len = sizeof(aibss_if); + + cfg->bss_pending_op = TRUE; + memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); + err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if, + sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); + if (err) { + WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err)); + goto fail; + } + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); + if (timeout <= 0 || cfg->bss_pending_op) + goto fail; + + event = &cfg->if_event_info; + strncpy(event->name, name, IFNAMSIZ - 1); + /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control + * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux + * and will be freed by dhd_detach unless it gets unregistered before that. The + * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will + * be freed by wl_dealloc_netinfo + */ + new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name, + event->mac, event->bssidx); + if (new_ndev == NULL) + goto fail; + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (wdev == NULL) + goto fail; + wdev->wiphy = wiphy; + wdev->iftype = NL80211_IFTYPE_ADHOC; + wdev->netdev = new_ndev; + new_ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy)); + + /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if + * needs to be modified to take one parameter (bool need_rtnl_lock) + */ + ASSERT_RTNL(); + if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) + goto fail; + + wl_alloc_netinfo(cfg, new_ndev, wdev, WL_MODE_IBSS, PM_ENABLE); + cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev); + WL_ERR(("IBSS interface %s created\n", new_ndev->name)); + return cfg->ibss_cfgdev; + +fail: + WL_ERR(("failed to create IBSS interface %s \n", name)); + cfg->bss_pending_op = FALSE; + if (new_ndev) + wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev); + if (wdev) + kfree(wdev); + return NULL; +} + +static s32 +bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = NULL; + struct net_device *primary_ndev = NULL; + s32 timeout; + + if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet)) + return -EINVAL; + ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev); + primary_ndev = bcmcfg_to_prmry_ndev(cfg); + + cfg->bss_pending_op = TRUE; + memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); + err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr, + sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); + if (err) { + WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err)); + goto fail; + } + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); + if (timeout <= 0 || cfg->bss_pending_op) { + WL_ERR(("timeout in waiting IF_DEL event\n")); + goto fail; + } + + wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev); + cfg->ibss_cfgdev = NULL; + return 0; + +fail: + cfg->bss_pending_op = FALSE; + return -1; +} +#endif /* WLAIBSS_MCHAN */ + +s32 +wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, + struct net_device *ndev, s32 bsscfg_idx, + enum nl80211_iftype iface_type, s32 del, u8 *addr) +{ + wl_interface_create_t iface; + s32 ret; + wl_interface_info_t *info; + + bzero(&iface, sizeof(wl_interface_create_t)); + + iface.ver = WL_INTERFACE_CREATE_VER; + + if (iface_type == NL80211_IFTYPE_AP) + iface.flags = WL_INTERFACE_CREATE_AP; + else + iface.flags = WL_INTERFACE_CREATE_STA; + + if (del) { + ret = wldev_iovar_setbuf(ndev, "interface_remove", + NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + } else { + if (addr) { + memcpy(&iface.mac_addr.octet, addr, ETH_ALEN); + iface.flags |= WL_INTERFACE_MAC_USE; + } + ret = wldev_iovar_getbuf(ndev, "interface_create", + &iface, sizeof(wl_interface_create_t), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (ret == 0) { + /* success */ + info = (wl_interface_info_t *)cfg->ioctl_buf; + WL_DBG(("wl interface create success!! bssidx:%d \n", + info->bsscfgidx)); + ret = info->bsscfgidx; + } + } + + if (ret < 0) + WL_ERR(("Interface %s failed!! ret %d\n", + del ? "remove" : "create", ret)); + + return ret; +} + +#if defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) +s32 +wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg, + struct net_device *ndev, s32 bsscfg_idx, + enum nl80211_iftype iface_type, s32 del, u8 *addr) +{ + s32 ret = BCME_OK; + s32 val = 0; + + struct { + s32 cfg; + s32 val; + struct ether_addr ea; + } bss_setbuf; + + WL_INFORM(("iface_type:%d del:%d \n", iface_type, del)); + + bzero(&bss_setbuf, sizeof(bss_setbuf)); + + /* AP=3, STA=2, up=1, down=0, val=-1 */ + if (del) { + val = -1; + } else if (iface_type == NL80211_IFTYPE_AP) { + /* AP Interface */ + WL_DBG(("Adding AP Interface \n")); + val = 3; + } else if (iface_type == NL80211_IFTYPE_STATION) { + WL_DBG(("Adding STA Interface \n")); + val = 2; + } else { + WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", iface_type)); + return -EINVAL; + } + + bss_setbuf.cfg = htod32(bsscfg_idx); + bss_setbuf.val = htod32(val); + + if (addr) { + memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN); + } + + ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (ret != 0) + WL_ERR(("'bss %d' failed with %d\n", val, ret)); + + return ret; +} + +/* Create a Generic Network Interface and initialize it depending up on + * the interface type + */ +bcm_struct_cfgdev* +wl_cfg80211_create_iface(struct wiphy *wiphy, + enum nl80211_iftype iface_type, + u8 *mac_addr, const char *name) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *new_ndev = NULL; + struct net_device *primary_ndev = NULL; + s32 ret = BCME_OK; + s32 bsscfg_idx = 1; + u32 timeout; + wl_if_event_info *event = NULL; + struct wireless_dev *wdev = NULL; + u8 addr[ETH_ALEN]; + + WL_DBG(("Enter\n")); + + if (!name) { + WL_ERR(("Interface name not provided\n")); + return NULL; + } + + primary_ndev = bcmcfg_to_prmry_ndev(cfg); + + if (likely(!mac_addr)) { + /* Use primary MAC with the locally administered bit for the Secondary STA I/F */ + memcpy(addr, primary_ndev->dev_addr, ETH_ALEN); + addr[0] |= 0x02; + } else { + /* Use the application provided mac address (if any) */ + memcpy(addr, mac_addr, ETH_ALEN); + } + + if ((iface_type != NL80211_IFTYPE_STATION) && (iface_type != NL80211_IFTYPE_AP)) { + WL_ERR(("IFACE type:%d not supported. STA " + "or AP IFACE is only supported\n", iface_type)); + return NULL; + } + + cfg->bss_pending_op = TRUE; + memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); + + /* De-initialize the p2p discovery interface, if operational */ + if (p2p_is_on(cfg)) { + WL_DBG(("Disabling P2P Discovery Interface \n")); +#ifdef WL_CFG80211_P2P_DEV_IF + ret = wl_cfg80211_scan_stop(bcmcfg_to_p2p_wdev(cfg)); +#else + ret = wl_cfg80211_scan_stop(cfg->p2p_net); +#endif + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret)); + } + + wl_cfgp2p_disable_discovery(cfg); + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; + p2p_on(cfg) = false; + } + + /* + * Intialize the firmware I/F. + */ + ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx, + NL80211_IFTYPE_STATION, 0, addr); + if (ret == BCME_UNSUPPORTED) { + /* Use bssidx 1 by default */ + if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev, + bsscfg_idx, iface_type, 0, addr)) < 0) { + return NULL; + } + } else if (ret < 0) { + WL_ERR(("Interface create failed!! ret:%d \n", ret)); + goto fail; + } else { + /* Success */ + bsscfg_idx = ret; + } + + /* + * Wait till the firmware send a confirmation event back. + */ + WL_DBG(("Wait for the FW I/F Event\n")); + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); + if (timeout <= 0 || cfg->bss_pending_op) { + WL_ERR(("ADD_IF event, didn't come. Return \n")); + goto fail; + } + + /* + * Since FW operation is successful,we can go ahead with the + * the host interface creation. + */ + event = &cfg->if_event_info; + strncpy(event->name, name, IFNAMSIZ - 1); + new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, + event->name, addr, event->bssidx); + if (!new_ndev) { + WL_ERR(("I/F allocation failed! \n")); + goto fail; + } else + WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n", + event->ifidx, event->bssidx)); + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (!wdev) { + WL_ERR(("wireless_dev alloc failed! \n")); + goto fail; + } + + wdev->wiphy = wiphy; + wdev->iftype = iface_type; + new_ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy)); + + /* RTNL lock must have been acquired. */ + ASSERT_RTNL(); + + /* Set the locally administed mac addr, if not applied already */ + if (memcmp(addr, event->mac, ETH_ALEN) != 0) { + ret = wldev_iovar_setbuf_bsscfg(primary_ndev, "cur_etheraddr", addr, ETH_ALEN, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, event->bssidx, &cfg->ioctl_buf_sync); + if (unlikely(ret)) { + WL_ERR(("set cur_etheraddr Error (%d)\n", ret)); + goto fail; + } + memcpy(new_ndev->dev_addr, addr, ETH_ALEN); + } + + if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) { + WL_ERR(("IFACE register failed \n")); + goto fail; + } + + /* Initialize with the station mode params */ + wl_alloc_netinfo(cfg, new_ndev, wdev, + (iface_type == NL80211_IFTYPE_STATION) ? + WL_MODE_BSS : WL_MODE_AP, PM_ENABLE); + cfg->bss_cfgdev = ndev_to_cfgdev(new_ndev); + cfg->cfgdev_bssidx = event->bssidx; + + WL_DBG(("Host Network Interface for Secondary I/F created")); + + return cfg->bss_cfgdev; + +fail: + cfg->bss_pending_op = FALSE; + if (new_ndev) + wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev); + if (wdev) + kfree(wdev); + + return NULL; +} + +s32 +wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = NULL; + struct net_device *primary_ndev = NULL; + s32 ret = BCME_OK; + s32 bsscfg_idx = 1; + u32 timeout; + u32 ifidx; + enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION; + + WL_DBG(("Enter\n")); + + if (!cfg->bss_cfgdev) + return 0; + + /* If any scan is going on, abort it */ + if (wl_get_drv_status_all(cfg, SCANNING)) { + WL_DBG(("Scan in progress. Aborting the scan!\n")); + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); + } + + ndev = (struct net_device *)cfgdev_to_ndev(cfg->bss_cfgdev); + primary_ndev = bcmcfg_to_prmry_ndev(cfg); + + cfg->bss_pending_op = TRUE; + memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); + + /* Delete the firmware interface */ + ret = wl_cfg80211_interface_ops(cfg, ndev, cfg->cfgdev_bssidx, + NL80211_IFTYPE_STATION, 1, NULL); + if (ret == BCME_UNSUPPORTED) { + if ((ret = wl_cfg80211_add_del_bss(cfg, ndev, + bsscfg_idx, iface_type, true, NULL)) < 0) { + WL_ERR(("DEL bss failed ret:%d \n", ret)); + return ret; + } + } else if (ret < 0) { + WL_ERR(("Interface DEL failed ret:%d \n", ret)); + return ret; + } + + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); + if (timeout <= 0 || cfg->bss_pending_op) { + WL_ERR(("timeout in waiting IF_DEL event\n")); + } + ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev); + wl_cfg80211_remove_if(cfg, ifidx, ndev); + cfg->bss_cfgdev = NULL; + cfg->cfgdev_bssidx = -1; + cfg->bss_pending_op = FALSE; + + WL_DBG(("IF_DEL Done.\n")); + + return ret; +} +#endif /* defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) */ + +static s32 +wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct cfg80211_bss *bss; + struct ieee80211_channel *chan; + struct wl_join_params join_params; + int scan_suppress; + struct cfg80211_ssid ssid; + s32 scan_retry = 0; + s32 err = 0; + size_t join_params_size; + chanspec_t chanspec = 0; + u32 param[2] = {0, 0}; + u32 bw_cap = 0; +#if defined(WLAIBSS) && defined(WLAIBSS_PS) + s32 atim = 10; +#endif /* WLAIBSS & WLAIBSS_PS */ + + WL_TRACE(("In\n")); + RETURN_EIO_IF_NOT_UP(cfg); + WL_INFORM(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid))); + if (!params->ssid || params->ssid_len <= 0 || + params->ssid_len > DOT11_MAX_SSID_LEN) { + WL_ERR(("Invalid parameter\n")); + return -EINVAL; + } +#if defined(WL_CFG80211_P2P_DEV_IF) + chan = params->chandef.chan; +#else + chan = params->channel; +#endif /* WL_CFG80211_P2P_DEV_IF */ + if (chan) + cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); + if (wl_get_drv_status(cfg, CONNECTED, dev)) { + struct wlc_ssid *ssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID); + u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID); + u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN); + if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) && + (memcmp(params->ssid, ssid->SSID, ssid->SSID_len) == 0) && + (*channel == cfg->channel))) { + WL_ERR(("Connection already existed to " MACDBG "\n", + MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID)))); + return -EISCONN; + } + WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n", + ssid->SSID, MAC2STRDBG(bssid))); + } + + /* remove the VSIE */ + wl_cfg80211_ibss_vsie_delete(dev); + + bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); + if (!bss) { + if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) { + memcpy(ssid.ssid, params->ssid, params->ssid_len); + ssid.ssid_len = params->ssid_len; + do { + if (unlikely + (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == + -EBUSY)) { + wl_delay(150); + } else { + break; + } + } while (++scan_retry < WL_SCAN_RETRY_MAX); + + /* rtnl lock code is removed here. don't see why rtnl lock + * needs to be released. + */ + + /* wait 4 secons till scan done.... */ + schedule_timeout_interruptible(msecs_to_jiffies(4000)); + + bss = cfg80211_get_ibss(wiphy, NULL, + params->ssid, params->ssid_len); + } + } + if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) || + ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid && + !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) { + cfg->ibss_starter = false; + WL_DBG(("Found IBSS\n")); + } else { + cfg->ibss_starter = true; + } + if (chan) { + if (chan->band == IEEE80211_BAND_5GHZ) + param[0] = WLC_BAND_5G; + else if (chan->band == IEEE80211_BAND_2GHZ) + param[0] = WLC_BAND_2G; + err = wldev_iovar_getint(dev, "bw_cap", param); + if (unlikely(err)) { + WL_ERR(("Get bw_cap Failed (%d)\n", err)); + return err; + } + bw_cap = param[0]; + chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap); + } + /* + * Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ + memset(&join_params, 0, sizeof(join_params)); + memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, + params->ssid_len); + join_params.ssid.SSID_len = htod32(params->ssid_len); + if (params->bssid) { + memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN); + err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid, + ETHER_ADDR_LEN); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + } else + memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); + wldev_iovar_setint(dev, "ibss_coalesce_allowed", IBSS_COALESCE_ALLOWED); + + if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { + scan_suppress = TRUE; + /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */ + err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS, + &scan_suppress, sizeof(int)); + if (unlikely(err)) { + WL_ERR(("Scan Suppress Setting Failed (%d)\n", err)); + return err; + } + } + + join_params.params.chanspec_list[0] = chanspec; + join_params.params.chanspec_num = 1; + wldev_iovar_setint(dev, "chanspec", chanspec); + join_params_size = sizeof(join_params); + + /* Disable Authentication, IBSS will add key if it required */ + wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED); + wldev_iovar_setint(dev, "wsec", 0); + +#ifdef WLAIBSS + /* Enable custom ibss features */ + err = wldev_iovar_setint(dev, "aibss", TRUE); + + if (unlikely(err)) { + WL_ERR(("Enable custom IBSS mode failed (%d)\n", err)); + return err; + } +#ifdef WLAIBSS_PS + err = wldev_ioctl_set(dev, WLC_SET_ATIM, &atim, sizeof(int)); + if (unlikely(err)) { + WL_ERR(("Enable custom IBSS ATIM mode failed (%d)\n", err)); + return err; + } +#endif /* WLAIBSS_PS */ +#endif /* WLAIBSS */ + + err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, + join_params_size); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + + if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { + scan_suppress = FALSE; + /* Reset the SCAN SUPPRESS Flag */ + err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS, + &scan_suppress, sizeof(int)); + if (unlikely(err)) { + WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err)); + return err; + } + } + wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); + wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN); +#ifdef WLAIBSS + cfg->aibss_txfail_seq = 0; /* initialize the sequence */ +#endif /* WLAIBSS */ + cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */ + return err; +} + +static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + scb_val_t scbval; + u8 *curbssid; + + RETURN_EIO_IF_NOT_UP(cfg); + wl_link_down(cfg); + + WL_ERR(("Leave IBSS\n")); + curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); + wl_set_drv_status(cfg, DISCONNECTING, dev); + scbval.val = 0; + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); + if (unlikely(err)) { + wl_clr_drv_status(cfg, DISCONNECTING, dev); + WL_ERR(("error(%d)\n", err)); + return err; + } + + /* remove the VSIE */ + wl_cfg80211_ibss_vsie_delete(dev); + + return err; +} + +#ifdef MFP +static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa) +{ + u16 suite_count; + wpa_suite_mcast_t *mcast; + wpa_suite_ucast_t *ucast; + u16 len; + wpa_suite_auth_key_mgmt_t *mgmt; + + if (!wpa2ie) + return -1; + + len = wpa2ie->len; + mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; + if ((len -= WPA_SUITE_LEN) <= 0) + return BCME_BADLEN; + ucast = (wpa_suite_ucast_t *)&mcast[1]; + suite_count = ltoh16_ua(&ucast->count); + if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || + (len -= (WPA_IE_SUITE_COUNT_LEN + + (WPA_SUITE_LEN * suite_count))) <= 0) + return BCME_BADLEN; + + mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; + suite_count = ltoh16_ua(&mgmt->count); + + if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || + (len -= (WPA_IE_SUITE_COUNT_LEN + + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { + capa[0] = *(u8 *)&mgmt->list[suite_count]; + capa[1] = *((u8 *)&mgmt->list[suite_count] + 1); + } else + return BCME_BADLEN; + + return 0; +} +#endif /* MFP */ + +static s32 +wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + s32 val = 0; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) + val = WPA_AUTH_PSK | +#ifdef BCMCCX + WPA_AUTH_CCKM | +#endif + WPA_AUTH_UNSPECIFIED; + else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) + val = WPA2_AUTH_PSK| +#ifdef BCMCCX + WPA2_AUTH_CCKM | +#endif + WPA2_AUTH_UNSPECIFIED; + else + val = WPA_AUTH_DISABLED; + + if (is_wps_conn(sme)) + val = WPA_AUTH_DISABLED; + +#ifdef BCMWAPI_WPI + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { + WL_DBG((" * wl_set_wpa_version, set wpa_auth" + " to WPA_AUTH_WAPI 0x400")); + val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED; + } +#endif + WL_DBG(("setting wpa_auth to 0x%0x\n", val)); + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); + if (unlikely(err)) { + WL_ERR(("set wpa_auth failed (%d)\n", err)); + return err; + } + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + sec->wpa_versions = sme->crypto.wpa_versions; + return err; +} + +#ifdef BCMWAPI_WPI +static s32 +wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + WL_DBG((" %s \n", __FUNCTION__)); + + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { + err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", sme->ie, sme->ie_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + if (unlikely(err)) { + WL_ERR(("===> set_wapi_ie Error (%d)\n", err)); + return err; + } + } else + WL_DBG((" * skip \n")); + return err; +} +#endif /* BCMWAPI_WPI */ + +static s32 +wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + s32 val = 0; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + val = WL_AUTH_OPEN_SYSTEM; + WL_DBG(("open system\n")); + break; + case NL80211_AUTHTYPE_SHARED_KEY: + val = WL_AUTH_SHARED_KEY; + WL_DBG(("shared key\n")); + break; + case NL80211_AUTHTYPE_AUTOMATIC: + val = WL_AUTH_OPEN_SHARED; + WL_DBG(("automatic\n")); + break; +#ifdef BCMCCX + case NL80211_AUTHTYPE_NETWORK_EAP: + WL_DBG(("network eap\n")); + val = DOT11_LEAP_AUTH; + break; +#endif + default: + val = 2; + WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); + break; + } + + err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); + if (unlikely(err)) { + WL_ERR(("set auth failed (%d)\n", err)); + return err; + } + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + sec->auth_type = sme->auth_type; + return err; +} + +static s32 +wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + s32 pval = 0; + s32 gval = 0; + s32 err = 0; + s32 wsec_val = 0; +#ifdef MFP + s32 mfp = 0; + bcm_tlv_t *wpa2_ie; + u8 rsn_cap[2]; +#endif /* MFP */ + +#ifdef BCMWAPI_WPI + s32 val = 0; +#endif + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + 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: + case WLAN_CIPHER_SUITE_AES_CMAC: + pval = AES_ENABLED; + break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + val = SMS4_ENABLED; + pval = SMS4_ENABLED; + break; +#endif + 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; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + val = SMS4_ENABLED; + gval = SMS4_ENABLED; + break; +#endif + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } + + WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); + + if (is_wps_conn(sme)) { + if (sme->privacy) + err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + else + /* WPS-2.0 allows no security */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); + } else { +#ifdef BCMWAPI_WPI + if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) { + WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED")); + err = wldev_iovar_setint_bsscfg(dev, "wsec", val, bssidx); + } else { +#endif + WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); + wsec_val = pval | gval; + +#ifdef MFP + if (pval == AES_ENABLED) { + if (((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, + DOT11_MNG_RSN_ID)) != NULL) && + (wl_cfg80211_get_rsn_capa(wpa2_ie, rsn_cap) == 0)) { + + if (rsn_cap[0] & RSN_CAP_MFPC) { + /* MFP Capability advertised by supplicant. Check + * whether MFP is supported in the firmware + */ + if ((err = wldev_iovar_getint_bsscfg(dev, + "mfp", &mfp, bssidx)) < 0) { + WL_ERR(("Get MFP failed! " + "Check MFP support in FW \n")); + return -1; + } + + if ((sme->crypto.n_akm_suites == 1) && + ((sme->crypto.akm_suites[0] == + WL_AKM_SUITE_MFP_PSK) || + (sme->crypto.akm_suites[0] == + WL_AKM_SUITE_MFP_1X))) { + wsec_val |= MFP_SHA256; + } else if (sme->crypto.n_akm_suites > 1) { + WL_ERR(("Multiple AKM Specified \n")); + return -EINVAL; + } + + wsec_val |= MFP_CAPABLE; + if (rsn_cap[0] & RSN_CAP_MFPR) + wsec_val |= MFP_REQUIRED; + + if (rsn_cap[0] & RSN_CAP_MFPR) + mfp = WL_MFP_REQUIRED; + else + mfp = WL_MFP_CAPABLE; + err = wldev_iovar_setint_bsscfg(dev, "mfp", + mfp, bssidx); + } + } + } +#endif /* MFP */ + WL_DBG((" Set WSEC to fW 0x%x \n", wsec_val)); + err = wldev_iovar_setint_bsscfg(dev, "wsec", + wsec_val, bssidx); +#ifdef BCMWAPI_WPI + } +#endif + } + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; + sec->cipher_group = sme->crypto.cipher_group; + + return err; +} + +static s32 +wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + s32 val = 0; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + if (sme->crypto.n_akm_suites) { + err = wldev_iovar_getint(dev, "wpa_auth", &val); + if (unlikely(err)) { + WL_ERR(("could not get wpa_auth (%d)\n", err)); + return err; + } + if (val & (WPA_AUTH_PSK | +#ifdef BCMCCX + WPA_AUTH_CCKM | +#endif + 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; +#ifdef BCMCCX + case WLAN_AKM_SUITE_CCKM: + val = WPA_AUTH_CCKM; + break; +#endif + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } else if (val & (WPA2_AUTH_PSK | +#ifdef BCMCCX + WPA2_AUTH_CCKM | +#endif + WPA2_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA2_AUTH_UNSPECIFIED; + break; +#ifdef MFP + case WL_AKM_SUITE_MFP_1X: + val = WPA2_AUTH_UNSPECIFIED; + break; + case WL_AKM_SUITE_MFP_PSK: + val = WPA2_AUTH_PSK; + break; +#endif + case WLAN_AKM_SUITE_PSK: + val = WPA2_AUTH_PSK; + break; +#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X) + case WLAN_AKM_SUITE_FT_8021X: + val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; + break; +#endif +#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK) + case WLAN_AKM_SUITE_FT_PSK: + val = WPA2_AUTH_PSK | WPA2_AUTH_FT; + break; +#endif +#ifdef BCMCCX + case WLAN_AKM_SUITE_CCKM: + val = WPA2_AUTH_CCKM; + break; +#endif + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } +#ifdef BCMWAPI_WPI + else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_WAPI_CERT: + val = WAPI_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_WAPI_PSK: + val = WAPI_AUTH_PSK; + break; + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } +#endif + WL_DBG(("setting wpa_auth to %d\n", val)); + + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); + if (unlikely(err)) { + WL_ERR(("could not set wpa_auth (%d)\n", err)); + return err; + } + } + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + sec->wpa_auth = sme->crypto.akm_suites[0]; + + return err; +} + +static s32 +wl_set_set_sharedkey(struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + struct wl_wsec_key key; + s32 val; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + WL_DBG(("key len (%d)\n", sme->key_len)); + if (sme->key_len) { + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", + sec->wpa_versions, sec->cipher_pairwise)); + if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | +#ifdef BCMWAPI_WPI + NL80211_WPA_VERSION_2 | NL80211_WAPI_VERSION_1)) && +#else + NL80211_WPA_VERSION_2)) && +#endif + (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | +#ifdef BCMWAPI_WPI + WLAN_CIPHER_SUITE_WEP104 | WLAN_CIPHER_SUITE_SMS4))) +#else + WLAN_CIPHER_SUITE_WEP104))) +#endif + { + memset(&key, 0, sizeof(key)); + key.len = (u32) sme->key_len; + key.index = (u32) sme->key_idx; + if (unlikely(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 = WL_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; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + break; +#endif + default: + WL_ERR(("Invalid algorithm (%d)\n", + sme->crypto.ciphers_pairwise[0])); + return -EINVAL; + } + /* Set the new key/index */ + WL_DBG(("key length (%d) key index (%d) algo (%d)\n", + key.len, key.index, key.algo)); + WL_DBG(("key \"%s\"\n", key.data)); + swap_key_from_BE(&key); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { + WL_DBG(("set auth_type to shared key\n")); + val = WL_AUTH_SHARED_KEY; /* shared key */ + err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); + if (unlikely(err)) { + WL_ERR(("set auth failed (%d)\n", err)); + return err; + } + } + } + } + return err; +} + +#if defined(ESCAN_RESULT_PATCH) +static u8 connect_req_bssid[6]; +static u8 broad_bssid[6]; +#endif /* ESCAN_RESULT_PATCH */ + + + +#if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX) +static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd) +{ + u32 chanspec = 0; + bool isvht80 = 0; + + if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK) + chanspec = wl_chspec_driver_to_host(chanspec); + + isvht80 = chanspec & WL_CHANSPEC_BW_80; + WL_INFO(("%s: chanspec(%x:%d)\n", __FUNCTION__, chanspec, isvht80)); + + return isvht80; +} +#endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */ + +static s32 +wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct ieee80211_channel *chan = sme->channel; + wl_extjoin_params_t *ext_join_params; + struct wl_join_params join_params; + size_t join_params_size; +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + s32 roam_trigger[2] = {0, 0}; +#endif /* ROAM_AP_ENV_DETECTION */ + s32 err = 0; + wpa_ie_fixed_t *wpa_ie; + bcm_tlv_t *wpa2_ie; + u8* wpaie = 0; + u32 wpaie_len = 0; + u32 chan_cnt = 0; + struct ether_addr bssid; + s32 bssidx; + int ret; + int wait_cnt; + + WL_DBG(("In\n")); + + if (unlikely(!sme->ssid)) { + WL_ERR(("Invalid ssid\n")); + return -EOPNOTSUPP; + } + + if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) { + WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n", + sme->ssid, sme->ssid_len)); + return -EINVAL; + } + + WL_DBG(("SME IE : len=%zu\n", sme->ie_len)); + if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) { + prhex(NULL, sme->ie, sme->ie_len); + } + + RETURN_EIO_IF_NOT_UP(cfg); + + /* + * Cancel ongoing scan to sync up with sme state machine of cfg80211. + */ +#if !defined(ESCAN_RESULT_PATCH) + if (cfg->scan_request) { + wl_notify_escan_complete(cfg, dev, true, true); + } +#endif +#ifdef WL_SCHED_SCAN + if (cfg->sched_scan_req) { + wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg)); + } +#endif +#if defined(ESCAN_RESULT_PATCH) + if (sme->bssid) + memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); + else + bzero(connect_req_bssid, ETHER_ADDR_LEN); + bzero(broad_bssid, ETHER_ADDR_LEN); +#endif +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) + maxrxpktglom = 0; +#endif + bzero(&bssid, sizeof(bssid)); + if (!wl_get_drv_status(cfg, CONNECTED, dev)&& + (ret = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) == 0) { + if (!ETHER_ISNULLADDR(&bssid)) { + scb_val_t scbval; + wl_set_drv_status(cfg, DISCONNECTING, dev); + scbval.val = DOT11_RC_DISASSOC_LEAVING; + memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + + WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n", + MAC2STRDBG(bssid.octet))); + err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); + if (unlikely(err)) { + wl_clr_drv_status(cfg, DISCONNECTING, dev); + WL_ERR(("error (%d)\n", err)); + return err; + } + wait_cnt = 500/10; + while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) { + WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", + wait_cnt)); + wait_cnt--; + OSL_SLEEP(10); + } + } else + WL_DBG(("Currently not associated!\n")); + } else { + /* if status is DISCONNECTING, wait for disconnection terminated max 500 ms */ + wait_cnt = 500/10; + while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) { + WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt)); + wait_cnt--; + OSL_SLEEP(10); + } + } + + /* Clean BSSID */ + bzero(&bssid, sizeof(bssid)); + if (!wl_get_drv_status(cfg, DISCONNECTING, dev)) + wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID); + + if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) { + /* we only allow to connect using virtual interface in case of P2P */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); + } else if (dev == bcmcfg_to_prmry_ndev(cfg)) { + /* find the RSN_IE */ + if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE is found\n")); + } + /* find the WPA_IE */ + if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, + sme->ie_len)) != NULL) { + WL_DBG((" WPA IE is found\n")); + } + if (wpa_ie != NULL || wpa2_ie != NULL) { + wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; + wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; + wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; + err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("wpaie set error (%d)\n", err)); + return err; + } + } else { + err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("wpaie set error (%d)\n", err)); + return err; + } + } + + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len); + if (unlikely(err)) { + return err; + } + } +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + if (dhd->roam_env_detection) { + bool is_roamtrig_reset = TRUE; + bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection", + AP_ENV_DETECT_NOT_USED) == BCME_OK); + if (is_roamtrig_reset && is_roam_env_ok) { + roam_trigger[0] = WL_AUTO_ROAM_TRIGGER; + roam_trigger[1] = WLC_BAND_ALL; + err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger)); + if (unlikely(err)) { + WL_ERR((" failed to restore roam_trigger for auto env" + " detection\n")); + } + } + } +#endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */ + if (chan) { + cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); + chan_cnt = 1; + WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel, + chan->center_freq, chan_cnt)); + } else + cfg->channel = 0; +#ifdef BCMWAPI_WPI + WL_DBG(("1. enable wapi auth\n")); + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { + WL_DBG(("2. set wapi ie \n")); + err = wl_set_set_wapi_ie(dev, sme); + if (unlikely(err)) + return err; + } else + WL_DBG(("2. Not wapi ie \n")); +#endif + WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); + WL_DBG(("3. set wapi version \n")); + err = wl_set_wpa_version(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid wpa_version\n")); + return err; + } +#ifdef BCMWAPI_WPI + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) + WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n")); + else { + WL_DBG(("4. wl_set_auth_type\n")); +#endif + err = wl_set_auth_type(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid auth type\n")); + return err; + } +#ifdef BCMWAPI_WPI + } +#endif + + err = wl_set_set_cipher(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid ciper\n")); + return err; + } + + err = wl_set_key_mgmt(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid key mgmt\n")); + return err; + } + + err = wl_set_set_sharedkey(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid shared key\n")); + return err; + } + + /* + * Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ + join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + + chan_cnt * sizeof(chanspec_t); + ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL); + if (ext_join_params == NULL) { + err = -ENOMEM; + wl_clr_drv_status(cfg, CONNECTING, dev); + goto exit; + } + ext_join_params->ssid.SSID_len = MIN(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); + memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); + wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID); + ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); + /* increate dwell time to receive probe response or detect Beacon + * from target AP at a noisy air only during connect command + */ + ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1; + ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1; + /* Set up join scan parameters */ + ext_join_params->scan.scan_type = -1; + ext_join_params->scan.nprobes = chan_cnt ? + (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1; + ext_join_params->scan.home_time = -1; + + if (sme->bssid) + memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN); + else + memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN); + ext_join_params->assoc.chanspec_num = chan_cnt; + if (chan_cnt) { + u16 channel, band, bw, ctl_sb; + chanspec_t chspec; + channel = cfg->channel; + band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G + : WL_CHANSPEC_BAND_5G; + bw = WL_CHANSPEC_BW_20; + ctl_sb = WL_CHANSPEC_CTL_SB_NONE; + chspec = (channel | band | bw | ctl_sb); + ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + ext_join_params->assoc.chanspec_list[0] |= chspec; + ext_join_params->assoc.chanspec_list[0] = + wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); + } + ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); + if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { + WL_INFORM(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID, + ext_join_params->ssid.SSID_len)); + } + wl_set_drv_status(cfg, CONNECTING, dev); + + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + kfree(ext_join_params); + return BCME_ERROR; + } + err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + WL_ERR(("Connectting with" MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n", + MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), cfg->channel, + ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len)); + + kfree(ext_join_params); + if (err) { + wl_clr_drv_status(cfg, CONNECTING, dev); + if (err == BCME_UNSUPPORTED) { + WL_DBG(("join iovar is not supported\n")); + goto set_ssid; + } else { + WL_ERR(("error (%d)\n", err)); + goto exit; + } + } else + goto exit; + +set_ssid: + memset(&join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params.ssid); + + join_params.ssid.SSID_len = MIN(sizeof(join_params.ssid.SSID), sme->ssid_len); + memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); + join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); + wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); + if (sme->bssid) + memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); + else + memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); + + wl_ch_to_chanspec(cfg->channel, &join_params, &join_params_size); + WL_DBG(("join_param_size %zu\n", join_params_size)); + + if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { + WL_INFORM(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, + join_params.ssid.SSID_len)); + } + wl_set_drv_status(cfg, CONNECTING, dev); + err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, join_params_size); + if (err) { + WL_ERR(("error (%d)\n", err)); + wl_clr_drv_status(cfg, CONNECTING, dev); + } +exit: + return err; +} + +static s32 +wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + scb_val_t scbval; + bool act = false; + s32 err = 0; + u8 *curbssid; +#ifdef CUSTOM_SET_CPUCORE + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif /* CUSTOM_SET_CPUCORE */ + WL_ERR(("Reason %d\n", reason_code)); + RETURN_EIO_IF_NOT_UP(cfg); + act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT); + curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); +#ifdef ESCAN_RESULT_PATCH + if (wl_get_drv_status(cfg, CONNECTING, dev) && curbssid && + (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0)) { + WL_ERR(("Disconnecting from connecting device: " MACDBG "\n", + MAC2STRDBG(curbssid))); + act = true; + } +#endif /* ESCAN_RESULT_PATCH */ + if (act) { + /* + * Cancel ongoing scan to sync up with sme state machine of cfg80211. + */ +#if !defined(ESCAN_RESULT_PATCH) + /* Let scan aborted by F/W */ + if (cfg->scan_request) { + wl_notify_escan_complete(cfg, dev, true, true); + } +#endif /* ESCAN_RESULT_PATCH */ + wl_set_drv_status(cfg, DISCONNECTING, dev); + scbval.val = reason_code; + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); + if (unlikely(err)) { + wl_clr_drv_status(cfg, DISCONNECTING, dev); + WL_ERR(("error (%d)\n", err)); + return err; + } + } +#ifdef CUSTOM_SET_CPUCORE + /* set default cpucore */ + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + dhd->chan_isvht80 &= ~DHD_FLAG_STA_MODE; + if (!(dhd->chan_isvht80)) + dhd_set_cpucore(dhd, FALSE); + } +#endif /* CUSTOM_SET_CPUCORE */ + + return err; +} + +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 mbm) +#else +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, s32 dbm) +#endif /* WL_CFG80211_P2P_DEV_IF */ +{ + + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; +#if defined(WL_CFG80211_P2P_DEV_IF) + s32 dbm = MBM_TO_DBM(mbm); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \ + defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES) + dbm = MBM_TO_DBM(dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ + + RETURN_EIO_IF_NOT_UP(cfg); + switch (type) { + case NL80211_TX_POWER_AUTOMATIC: + break; + case NL80211_TX_POWER_LIMITED: + if (dbm < 0) { + WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n")); + return -EINVAL; + } + break; + case NL80211_TX_POWER_FIXED: + if (dbm < 0) { + WL_ERR(("TX_POWER_FIXED - dbm is negative..\n")); + return -EINVAL; + } + break; + } + + err = wl_set_tx_power(ndev, type, dbm); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + cfg->conf->tx_power = dbm; + + return err; +} + +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, s32 *dbm) +#else +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +#endif /* WL_CFG80211_P2P_DEV_IF */ +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; + + RETURN_EIO_IF_NOT_UP(cfg); + err = wl_get_tx_power(ndev, dbm); + if (unlikely(err)) + WL_ERR(("error (%d)\n", err)); + + return err; +} + +static s32 +wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool unicast, bool multicast) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + u32 index; + s32 wsec; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + WL_DBG(("key index (%d)\n", key_idx)); + RETURN_EIO_IF_NOT_UP(cfg); + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); + if (unlikely(err)) { + WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); + return err; + } + if (wsec == WEP_ENABLED) { + /* Just select a new current key */ + index = (u32) key_idx; + index = htod32(index); + err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index, + sizeof(index)); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + } + } + return err; +} + +static s32 +wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, struct key_params *params) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct wl_wsec_key key; + s32 err = 0; + s32 bssidx; + s32 mode = wl_get_mode_by_netdev(cfg, dev); + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + memset(&key, 0, sizeof(key)); + key.index = (u32) key_idx; + + if (!ETHER_ISMULTI(mac_addr)) + memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); + key.len = (u32) params->key_len; + + /* check for key index change */ + if (key.len == 0) { + /* key delete */ + swap_key_from_BE(&key); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("key delete error (%d)\n", err)); + return err; + } + } else { + if (key.len > sizeof(key.data)) { + WL_ERR(("Invalid key length (%d)\n", key.len)); + return -EINVAL; + } + WL_DBG(("Setting the key index %d\n", key.index)); + memcpy(key.data, params->key, key.len); + + if ((mode == WL_MODE_BSS) && + (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_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + break; + case WLAN_CIPHER_SUITE_TKIP: + key.algo = CRYPTO_ALGO_TKIP; + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + case WLAN_CIPHER_SUITE_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); + break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); + break; +#endif + default: + WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); + return -EINVAL; + } + swap_key_from_BE(&key); + /* need to guarantee EAPOL 4/4 send out before set key */ + dhd_wait_pend8021x(dev); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + } + return err; +} + +int +wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable) +{ + int err; + wl_eventmsg_buf_t ev_buf; + + if (dev != bcmcfg_to_prmry_ndev(g_bcm_cfg)) { + /* roam offload is only for the primary device */ + return -1; + } + err = wldev_iovar_setint(dev, "roam_offload", enable); + if (err) + return err; + + bzero(&ev_buf, sizeof(wl_eventmsg_buf_t)); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable); + err = wl_cfg80211_apply_eventbuffer(dev, g_bcm_cfg, &ev_buf); + if (!err) { + g_bcm_cfg->roam_offload = enable; + } + return err; +} + +static s32 +wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + struct wl_wsec_key key; + s32 val = 0; + s32 wsec = 0; + s32 err = 0; + u8 keybuf[8]; + s32 bssidx = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 mode = wl_get_mode_by_netdev(cfg, dev); + WL_DBG(("key index (%d)\n", key_idx)); + RETURN_EIO_IF_NOT_UP(cfg); + + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + if (mac_addr && + ((params->cipher != WLAN_CIPHER_SUITE_WEP40) && + (params->cipher != WLAN_CIPHER_SUITE_WEP104))) { + wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); + goto exit; + } + memset(&key, 0, sizeof(key)); + + key.len = (u32) params->key_len; + key.index = (u32) key_idx; + + if (unlikely(key.len > sizeof(key.data))) { + WL_ERR(("Too long key length (%u)\n", key.len)); + return -EINVAL; + } + memcpy(key.data, params->key, key.len); + + key.flags = WL_PRIMARY_KEY; + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + val = WEP_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + val = WEP_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + break; + case WLAN_CIPHER_SUITE_TKIP: + key.algo = CRYPTO_ALGO_TKIP; + val = TKIP_ENABLED; + /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ + if (mode == WL_MODE_BSS) { + bcopy(&key.data[24], keybuf, sizeof(keybuf)); + bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); + bcopy(keybuf, &key.data[16], sizeof(keybuf)); + } + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key.algo = CRYPTO_ALGO_AES_CCM; + val = AES_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + case WLAN_CIPHER_SUITE_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + val = AES_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); + break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); + val = SMS4_ENABLED; + break; +#endif /* BCMWAPI_WPI */ +#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK) + case WLAN_CIPHER_SUITE_PMK: { + int j; + wsec_pmk_t pmk; + char keystring[WSEC_MAX_PSK_LEN + 1]; + char* charptr = keystring; + uint len; + struct wl_security *sec; + + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + if (sec->wpa_auth == WLAN_AKM_SUITE_8021X) { + err = wldev_iovar_setbuf(dev, "okc_info_pmk", params->key, + WSEC_MAX_PSK_LEN / 2, keystring, sizeof(keystring), NULL); + if (err) { + /* could fail in case that 'okc' is not supported */ + WL_INFORM(("Setting 'okc_info_pmk' failed, err=%d\n", err)); + } + } + /* copy the raw hex key to the appropriate format */ + for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { + sprintf(charptr, "%02x", params->key[j]); + charptr += 2; + } + len = strlen(keystring); + pmk.key_len = htod16(len); + bcopy(keystring, pmk.key, len); + pmk.flags = htod16(WSEC_PASSPHRASE); + + err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); + if (err) + return err; + } break; +#endif /* WLFBT && WLAN_CIPHER_SUITE_PMK */ + default: + WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); + return -EINVAL; + } + + /* Set the new key/index */ + if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) { + WL_ERR(("IBSS KEY setted\n")); + wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE); + } + swap_key_from_BE(&key); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, + WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + +exit: + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); + if (unlikely(err)) { + WL_ERR(("get wsec error (%d)\n", err)); + return err; + } + + wsec |= val; + err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); + if (unlikely(err)) { + WL_ERR(("set wsec error (%d)\n", err)); + return err; + } + + return err; +} + +static s32 +wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr) +{ + struct wl_wsec_key key; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + WL_DBG(("Enter\n")); + +#ifndef IEEE80211W + if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) + return -EINVAL; +#endif + + RETURN_EIO_IF_NOT_UP(cfg); + memset(&key, 0, sizeof(key)); + + key.flags = WL_PRIMARY_KEY; + key.algo = CRYPTO_ALGO_OFF; + key.index = (u32) key_idx; + + WL_DBG(("key index (%d)\n", key_idx)); + /* Set the new key/index */ + swap_key_from_BE(&key); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, + WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + if (err == -EINVAL) { + if (key.index >= DOT11_MAX_DEFAULT_KEYS) { + /* we ignore this key index in this case */ + WL_DBG(("invalid key index (%d)\n", key_idx)); + } + } else { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + } + return err; + } + return err; +} + +static s32 +wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback) (void *cookie, struct key_params * params)) +{ + struct key_params params; + struct wl_wsec_key key; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct wl_security *sec; + s32 wsec; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + WL_DBG(("key index (%d)\n", key_idx)); + RETURN_EIO_IF_NOT_UP(cfg); + memset(&key, 0, sizeof(key)); + key.index = key_idx; + swap_key_to_BE(&key); + memset(¶ms, 0, sizeof(params)); + params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); + memcpy(params.key, key.data, params.key_len); + + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); + if (unlikely(err)) { + WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); + return err; + } + switch (WSEC_ENABLED(wsec)) { + case WEP_ENABLED: + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { + params.cipher = WLAN_CIPHER_SUITE_WEP40; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { + params.cipher = WLAN_CIPHER_SUITE_WEP104; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + } + break; + case TKIP_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_TKIP; + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case AES_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); + break; +#endif + default: + WL_ERR(("Invalid algo (0x%x)\n", wsec)); + return -EINVAL; + } + + callback(cookie, ¶ms); + return err; +} + +static s32 +wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx) +{ +#ifdef MFP + return 0; +#else + WL_INFORM(("Not supported\n")); + return -EOPNOTSUPP; +#endif /* MFP */ +} + +static s32 +wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + scb_val_t scb_val; + s32 rssi; + s32 rate; + s32 err = 0; + sta_info_t *sta; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS) + s8 eabuf[ETHER_ADDR_STR_LEN]; +#endif + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + RETURN_EIO_IF_NOT_UP(cfg); + if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { + err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, + ETHER_ADDR_LEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); + if (err < 0) { + WL_ERR(("GET STA INFO failed, %d\n", err)); + return err; + } + sinfo->filled = STATION_INFO_INACTIVE_TIME; + sta = (sta_info_t *)cfg->ioctl_buf; + sta->len = dtoh16(sta->len); + sta->cap = dtoh16(sta->cap); + sta->flags = dtoh32(sta->flags); + sta->idle = dtoh32(sta->idle); + sta->in = dtoh32(sta->in); + sinfo->inactive_time = sta->idle * 1000; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS) + if (sta->flags & WL_STA_ASSOC) { + sinfo->filled |= STATION_INFO_CONNECTED_TIME; + sinfo->connected_time = sta->in; + } + WL_INFORM(("STA %s : idle time : %d sec, connected time :%d ms\n", + bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time, + sta->idle * 1000)); +#endif + } else if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS || + wl_get_mode_by_netdev(cfg, dev) == WL_MODE_IBSS) { + get_pktcnt_t pktcnt; + u8 *curmacp; + + if (cfg->roam_offload) { + struct ether_addr bssid; + memset(&bssid, 0, sizeof(bssid)); + err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); + if (err) { + WL_ERR(("Failed to get current BSSID\n")); + } else { + if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) { + /* roaming is detected */ + err = wl_cfg80211_delayed_roam(cfg, dev, &bssid); + if (err) + WL_ERR(("Failed to handle the delayed roam, " + "err=%d", err)); + mac = (u8 *)bssid.octet; + } + } + } + if (!wl_get_drv_status(cfg, CONNECTED, dev) || + (dhd_is_associated(dhd, NULL, &err) == FALSE)) { + WL_ERR(("NOT assoc\n")); + if (err == -ERESTARTSYS) + return err; + err = -ENODEV; + return err; + } + curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID); + if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { + WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n", + MAC2STRDBG(mac), MAC2STRDBG(curmacp))); + } + + /* Report the current tx rate */ + rate = 0; + err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate)); + if (err) { + WL_ERR(("Could not get rate (%d)\n", err)); + } else { +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) + int rxpktglom; +#endif + rate = dtoh32(rate); + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = rate * 5; + WL_DBG(("Rate %d Mbps\n", (rate / 2))); +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) + rxpktglom = ((rate/2) > 150) ? 20 : 10; + + if (maxrxpktglom != rxpktglom) { + maxrxpktglom = rxpktglom; + WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2), + maxrxpktglom)); + err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom", + (char*)&maxrxpktglom, 4, cfg->ioctl_buf, + WLC_IOCTL_MAXLEN, NULL); + if (err < 0) { + WL_ERR(("set bus:maxtxpktglom failed, %d\n", err)); + } + } +#endif + } + + memset(&scb_val, 0, sizeof(scb_val)); + scb_val.val = 0; + err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val, + sizeof(scb_val_t)); + if (err) { + WL_ERR(("Could not get rssi (%d)\n", err)); + goto get_station_err; + } + rssi = wl_rssi_offset(dtoh32(scb_val.val)); + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = rssi; + WL_DBG(("RSSI %d dBm\n", rssi)); + memset(&pktcnt, 0, sizeof(pktcnt)); + err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt, + sizeof(pktcnt)); + if (!err) { + sinfo->filled |= (STATION_INFO_RX_PACKETS | + STATION_INFO_RX_DROP_MISC | + STATION_INFO_TX_PACKETS | + STATION_INFO_TX_FAILED); + sinfo->rx_packets = pktcnt.rx_good_pkt; + sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt; + sinfo->tx_packets = pktcnt.tx_good_pkt; + sinfo->tx_failed = pktcnt.tx_bad_pkt; + } +get_station_err: + if (err && (err != -ERESTARTSYS)) { + /* Disconnect due to zero BSSID or error to get RSSI */ + WL_ERR(("force cfg80211_disconnected: %d\n", err)); + wl_clr_drv_status(cfg, CONNECTED, dev); + cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL); + wl_link_down(cfg); + } + } + else { + WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev))); + } + + return err; +} + +static s32 +wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, s32 timeout) +{ + s32 pm; + s32 err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev); + + RETURN_EIO_IF_NOT_UP(cfg); + WL_DBG(("Enter\n")); + if (cfg->p2p_net == dev || _net_info == NULL || cfg->vsdb_mode || + !wl_get_drv_status(cfg, CONNECTED, dev)) { + return err; + } + + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_PEND); + + pm = enabled ? PM_FAST : PM_OFF; + if (_net_info->pm_block) { + WL_ERR(("%s:Do not enable the power save for pm_block %d\n", + dev->name, _net_info->pm_block)); + pm = PM_OFF; + } + pm = htod32(pm); + WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled"))); + err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); + if (unlikely(err)) { + if (err == -ENODEV) + WL_DBG(("net_device is not ready yet\n")); + else + WL_ERR(("error (%d)\n", err)); + return err; + } + wl_cfg80211_update_power_mode(dev); + return err; +} + +void wl_cfg80211_update_power_mode(struct net_device *dev) +{ + int err, pm = -1; + + err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm)); + if (err) + WL_ERR(("%s:error (%d)\n", __FUNCTION__, err)); + else if (pm != -1 && dev->ieee80211_ptr) + dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true; +} + +static __used u32 wl_find_msb(u16 bit16) +{ + u32 ret = 0; + + if (bit16 & 0xff00) { + ret += 8; + bit16 >>= 8; + } + + if (bit16 & 0xf0) { + ret += 4; + bit16 >>= 4; + } + + if (bit16 & 0xc) { + ret += 2; + bit16 >>= 2; + } + + if (bit16 & 2) + ret += bit16 & 2; + else if (bit16) + ret += bit16; + + return ret; +} + +static s32 wl_cfg80211_resume(struct wiphy *wiphy) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; + + if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) { + WL_INFORM(("device is not ready\n")); + return 0; + } + + return err; +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) +static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) +#else +static s32 wl_cfg80211_suspend(struct wiphy *wiphy) +#endif +{ +#ifdef DHD_CLEAR_ON_SUSPEND + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_info *iter, *next; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + unsigned long flags; + if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) { + WL_INFORM(("device is not ready : status (%d)\n", + (int)cfg->status)); + return 0; + } + for_each_ndev(cfg, iter, next) + wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + if (cfg->scan_request) { + cfg80211_scan_done(cfg->scan_request, true); + cfg->scan_request = NULL; + } + for_each_ndev(cfg, iter, next) { + wl_clr_drv_status(cfg, SCANNING, iter->ndev); + wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev); + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + for_each_ndev(cfg, iter, next) { + if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) { + wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false); + } + } +#endif /* DHD_CLEAR_ON_SUSPEND */ + return 0; +} + +static s32 +wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, + s32 err) +{ + int i, j; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); + + if (!pmk_list) { + printk("pmk_list is NULL\n"); + return -EINVAL; + } + /* pmk list is supported only for STA interface i.e. primary interface + * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init + */ + if (primary_dev != dev) { + WL_INFORM(("Not supporting Flushing pmklist on virtual" + " interfaces than primary interface\n")); + return err; + } + + WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid)); + for (i = 0; i < pmk_list->pmkids.npmkid; i++) { + WL_DBG(("PMKID[%d]: %pM =\n", i, + &pmk_list->pmkids.pmkid[i].BSSID)); + for (j = 0; j < WPA2_PMKID_LEN; j++) { + WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j])); + } + } + if (likely(!err)) { + err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, + sizeof(*pmk_list), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + } + + return err; +} + +static s32 +wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + int i; + + if (pmksa == NULL) { + WL_ERR(("pmksa is null\n")); + return -EINVAL; + } + + RETURN_EIO_IF_NOT_UP(cfg); + for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++) + if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN)) + break; + if (i < WL_NUM_PMKIDS_MAX) { + memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, + ETHER_ADDR_LEN); + memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, + WPA2_PMKID_LEN); + if (i == cfg->pmk_list->pmkids.npmkid) + cfg->pmk_list->pmkids.npmkid++; + } else { + err = -EINVAL; + } + WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", + &cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].BSSID)); + for (i = 0; i < WPA2_PMKID_LEN; i++) { + WL_DBG(("%02x\n", + cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1]. + PMKID[i])); + } + + err = wl_update_pmklist(dev, cfg->pmk_list, err); + + return err; +} + +static s32 +wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct _pmkid_list pmkid = {0}; + s32 err = 0; + int i; + + if (pmksa == NULL) { + WL_ERR(("pmksa is null\n")); + return -EINVAL; + } + + RETURN_EIO_IF_NOT_UP(cfg); + memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); + memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); + + WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", + &pmkid.pmkid[0].BSSID)); + for (i = 0; i < WPA2_PMKID_LEN; i++) { + WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i])); + } + + for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++) + if (!memcmp + (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN)) + break; + + if ((cfg->pmk_list->pmkids.npmkid > 0) && + (i < cfg->pmk_list->pmkids.npmkid)) { + memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t)); + for (; i < (cfg->pmk_list->pmkids.npmkid - 1); i++) { + memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, + &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID, + ETHER_ADDR_LEN); + memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, + &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID, + WPA2_PMKID_LEN); + } + cfg->pmk_list->pmkids.npmkid--; + } else { + err = -EINVAL; + } + + err = wl_update_pmklist(dev, cfg->pmk_list, err); + + return err; + +} + +static s32 +wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + RETURN_EIO_IF_NOT_UP(cfg); + memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list)); + err = wl_update_pmklist(dev, cfg->pmk_list, err); + return err; + +} + +static wl_scan_params_t * +wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) +{ + wl_scan_params_t *params; + int params_size; + int num_chans; + + *out_params_size = 0; + + /* Our scan params only need space for 1 channel and 0 ssids */ + params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); + params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); + if (params == NULL) { + WL_ERR(("mem alloc failed (%d bytes)\n", params_size)); + return params; + } + memset(params, 0, params_size); + params->nprobes = nprobes; + + num_chans = (channel == 0) ? 0 : 1; + + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + params->bss_type = DOT11_BSSTYPE_ANY; + params->scan_type = DOT11_SCANTYPE_ACTIVE; + params->nprobes = htod32(1); + params->active_time = htod32(-1); + params->passive_time = htod32(-1); + params->home_time = htod32(10); + if (channel == -1) + params->channel_list[0] = htodchanspec(channel); + else + params->channel_list[0] = wl_ch_host_to_driver(channel); + + /* Our scan params have 1 channel and 0 ssids */ + params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | + (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); + + *out_params_size = params_size; /* rtn size to the caller */ + return params; +} + +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel *channel, unsigned int duration, u64 *cookie) +#else +static s32 +wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel * channel, + enum nl80211_channel_type channel_type, + unsigned int duration, u64 *cookie) +#endif /* WL_CFG80211_P2P_DEV_IF */ +{ + s32 target_channel; + u32 id; + s32 err = BCME_OK; + struct ether_addr primary_mac; + struct net_device *ndev = NULL; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n", + ieee80211_frequency_to_channel(channel->center_freq), + duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO")); + + if (!cfg->p2p) { + WL_ERR(("cfg->p2p is not initialized\n")); + err = BCME_ERROR; + goto exit; + } + +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (wl_get_drv_status_all(cfg, SCANNING)) { + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); + } +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + + target_channel = ieee80211_frequency_to_channel(channel->center_freq); + memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel)); +#if defined(WL_ENABLE_P2P_IF) + cfg->remain_on_chan_type = channel_type; +#endif /* WL_ENABLE_P2P_IF */ + id = ++cfg->last_roc_id; + if (id == 0) + id = ++cfg->last_roc_id; + *cookie = id; + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (wl_get_drv_status(cfg, SCANNING, ndev)) { + struct timer_list *_timer; + WL_DBG(("scan is running. go to fake listen state\n")); + + wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); + + if (timer_pending(&cfg->p2p->listen_timer)) { + WL_DBG(("cancel current listen timer \n")); + del_timer_sync(&cfg->p2p->listen_timer); + } + + _timer = &cfg->p2p->listen_timer; + wl_clr_p2p_status(cfg, LISTEN_EXPIRED); + + INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0); + + err = BCME_OK; + goto exit; + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +#ifdef WL_CFG80211_SYNC_GON + if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { + /* do not enter listen mode again if we are in listen mode already for next af. + * remain on channel completion will be returned by waiting next af completion. + */ +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); +#else + wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + goto exit; + } +#endif /* WL_CFG80211_SYNC_GON */ + if (cfg->p2p && !cfg->p2p->on) { + /* In case of p2p_listen command, supplicant send remain_on_channel + * without turning on P2P + */ + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr, &cfg->p2p->int_addr); + p2p_on(cfg) = true; + } + + if (p2p_is_on(cfg)) { + err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0); + if (unlikely(err)) { + goto exit; + } +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + err = wl_cfgp2p_discover_listen(cfg, target_channel, duration); + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (err == BCME_OK) { + wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); + } else { + /* if failed, firmware may be internal scanning state. + * so other scan request shall not abort it + */ + wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant + * and expire timer will send a completion to the upper layer + */ + err = BCME_OK; + } + +exit: + if (err == BCME_OK) { + WL_INFORM(("Success\n")); +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_ready_on_channel(cfgdev, *cookie, channel, + duration, GFP_KERNEL); +#else + cfg80211_ready_on_channel(cfgdev, *cookie, channel, + channel_type, duration, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ + } else { + WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); + } + return err; +} + +static s32 +wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + bcm_struct_cfgdev *cfgdev, u64 cookie) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + + + RETURN_EIO_IF_NOT_UP(cfg); +#if defined(WL_CFG80211_P2P_DEV_IF) + if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { + WL_DBG((" enter ) on P2P dedicated discover interface\n")); + } +#else + WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex)); +#endif /* WL_CFG80211_P2P_DEV_IF */ + + + if (cfg->last_roc_id == cookie) { + wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + } else { + WL_ERR(("%s : ignore, request cookie(%llu) is not matched. (cur : %llu)\n", + __FUNCTION__, cookie, cfg->last_roc_id)); + } + + return err; +} + +static void +wl_cfg80211_afx_handler(struct work_struct *work) +{ + struct afx_hdl *afx_instance; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + s32 ret = BCME_OK; + + afx_instance = container_of(work, struct afx_hdl, work); + if (afx_instance != NULL && cfg->afx_hdl->is_active) { + if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) { + ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan, + (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */ + } else { + ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev, + cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan, + NULL); + } + if (unlikely(ret != BCME_OK)) { + WL_ERR(("ERROR occurred! returned value is (%d)\n", ret)); + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) + complete(&cfg->act_frm_scan); + } + } +} + +static s32 +wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev) +{ + u32 max_retry = WL_CHANNEL_SYNC_RETRY; + + if (dev == NULL) + return -1; + + WL_DBG((" enter ) \n")); + + wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev); + cfg->afx_hdl->is_active = TRUE; + + /* Loop to wait until we find a peer's channel or the + * pending action frame tx is cancelled. + */ + while ((cfg->afx_hdl->retry < max_retry) && + (cfg->afx_hdl->peer_chan == WL_INVALID)) { + cfg->afx_hdl->is_listen = FALSE; + wl_set_drv_status(cfg, SCANNING, dev); + WL_DBG(("Scheduling the action frame for sending.. retry %d\n", + cfg->afx_hdl->retry)); + /* search peer on peer's listen channel */ + schedule_work(&cfg->afx_hdl->work); + wait_for_completion_timeout(&cfg->act_frm_scan, + msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); + + if ((cfg->afx_hdl->peer_chan != WL_INVALID) || + !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) + break; + + if (cfg->afx_hdl->my_listen_chan) { + WL_DBG(("Scheduling Listen peer in my listen channel = %d\n", + cfg->afx_hdl->my_listen_chan)); + /* listen on my listen channel */ + cfg->afx_hdl->is_listen = TRUE; + schedule_work(&cfg->afx_hdl->work); + wait_for_completion_timeout(&cfg->act_frm_scan, + msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); + } + if ((cfg->afx_hdl->peer_chan != WL_INVALID) || + !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) + break; + + cfg->afx_hdl->retry++; + + WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg); + } + + cfg->afx_hdl->is_active = FALSE; + + wl_clr_drv_status(cfg, SCANNING, dev); + wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev); + + return (cfg->afx_hdl->peer_chan); +} + +struct p2p_config_af_params { + s32 max_tx_retry; /* max tx retry count if tx no ack */ + /* To make sure to send successfully action frame, we have to turn off mpc + * 0: off, 1: on, (-1): do nothing + */ + s32 mpc_onoff; +#ifdef WL_CFG80211_SYNC_GON + bool extra_listen; +#endif + bool search_channel; /* 1: search peer's channel to send af */ +}; + +static s32 +wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, + wl_action_frame_t *action_frame, wl_af_params_t *af_params, + struct p2p_config_af_params *config_af_params) +{ + s32 err = BCME_OK; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + wifi_p2p_pub_act_frame_t *act_frm = + (wifi_p2p_pub_act_frame_t *) (action_frame->data); + + /* initialize default value */ +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = true; +#endif + config_af_params->search_channel = false; + config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; + config_af_params->mpc_onoff = -1; + cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; + + switch (act_frm->subtype) { + case P2P_PAF_GON_REQ: { + WL_DBG(("P2P: GO_NEG_PHASE status set \n")); + wl_set_p2p_status(cfg, GO_NEG_PHASE); + + config_af_params->mpc_onoff = 0; + config_af_params->search_channel = true; + cfg->next_af_subtype = act_frm->subtype + 1; + + /* increase dwell time to wait for RESP frame */ + af_params->dwell_time = WL_MED_DWELL_TIME; + + break; + } + case P2P_PAF_GON_RSP: { + cfg->next_af_subtype = act_frm->subtype + 1; + /* increase dwell time to wait for CONF frame */ + af_params->dwell_time = WL_MED_DWELL_TIME + 100; + break; + } + case P2P_PAF_GON_CONF: { + /* If we reached till GO Neg confirmation reset the filter */ + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + + /* turn on mpc again if go nego is done */ + config_af_params->mpc_onoff = 1; + + /* minimize dwell time */ + af_params->dwell_time = WL_MIN_DWELL_TIME; + +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + } + case P2P_PAF_INVITE_REQ: { + config_af_params->search_channel = true; + cfg->next_af_subtype = act_frm->subtype + 1; + + /* increase dwell time */ + af_params->dwell_time = WL_MED_DWELL_TIME; + break; + } + case P2P_PAF_INVITE_RSP: + /* minimize dwell time */ + af_params->dwell_time = WL_MIN_DWELL_TIME; +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + case P2P_PAF_DEVDIS_REQ: { + if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0], + action_frame->len)) { + config_af_params->search_channel = true; + } + + cfg->next_af_subtype = act_frm->subtype + 1; + /* maximize dwell time to wait for RESP frame */ + af_params->dwell_time = WL_LONG_DWELL_TIME; + break; + } + case P2P_PAF_DEVDIS_RSP: + /* minimize dwell time */ + af_params->dwell_time = WL_MIN_DWELL_TIME; +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + case P2P_PAF_PROVDIS_REQ: { + if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0], + action_frame->len)) { + config_af_params->search_channel = true; + } + + config_af_params->mpc_onoff = 0; + cfg->next_af_subtype = act_frm->subtype + 1; + /* increase dwell time to wait for RESP frame */ + af_params->dwell_time = WL_MED_DWELL_TIME; + break; + } + case P2P_PAF_PROVDIS_RSP: { + cfg->next_af_subtype = P2P_PAF_GON_REQ; + af_params->dwell_time = WL_MIN_DWELL_TIME; +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + } + default: + WL_DBG(("Unknown p2p pub act frame subtype: %d\n", + act_frm->subtype)); + err = BCME_BADARG; + } + return err; +} + +#ifdef WL11U +static bool +wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params, + void *frame, u16 frame_len) +{ + struct wl_scan_results *bss_list; + struct wl_bss_info *bi = NULL; + bool result = false; + s32 i; + chanspec_t chanspec; + + /* If DFS channel is 52~148, check to block it or not */ + if (af_params && + (af_params->channel >= 52 && af_params->channel <= 148)) { + if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) { + bss_list = cfg->bss_list; + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + chanspec = wl_chspec_driver_to_host(bi->chanspec); + if (CHSPEC_IS5G(chanspec) && + ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec)) + == af_params->channel)) { + result = true; /* do not block the action frame */ + break; + } + } + } + } + else { + result = true; + } + + WL_DBG(("result=%s", result?"true":"false")); + return result; +} +#endif /* WL11U */ + + +static bool +wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, + bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params, + wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) +{ +#ifdef WL11U + struct net_device *ndev = NULL; +#endif /* WL11U */ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + bool ack = false; + u8 category, action; + s32 tx_retry; + struct p2p_config_af_params config_af_params; +#ifdef VSDB + ulong off_chan_started_jiffies = 0; +#endif + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + + + /* Add the default dwell time + * Dwell time to stay off-channel to wait for a response action frame + * after transmitting an GO Negotiation action frame + */ + af_params->dwell_time = WL_DWELL_TIME; + +#ifdef WL11U +#if defined(WL_CFG80211_P2P_DEV_IF) + ndev = dev; +#else + ndev = ndev_to_cfgdev(cfgdev); +#endif /* WL_CFG80211_P2P_DEV_IF */ +#endif /* WL11U */ + + category = action_frame->data[DOT11_ACTION_CAT_OFF]; + action = action_frame->data[DOT11_ACTION_ACT_OFF]; + + /* initialize variables */ + tx_retry = 0; + cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; + config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY; + config_af_params.mpc_onoff = -1; + config_af_params.search_channel = false; +#ifdef WL_CFG80211_SYNC_GON + config_af_params.extra_listen = false; +#endif + + /* config parameters */ + /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */ + if (category == DOT11_ACTION_CAT_PUBLIC) { + if ((action == P2P_PUB_AF_ACTION) && + (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) { + /* p2p public action frame process */ + if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy, + action_frame, af_params, &config_af_params)) { + WL_DBG(("Unknown subtype.\n")); + } + + } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) { + /* service discovery process */ + if (action == P2PSD_ACTION_ID_GAS_IREQ || + action == P2PSD_ACTION_ID_GAS_CREQ) { + /* configure service discovery query frame */ + + config_af_params.search_channel = true; + + /* save next af suptype to cancel remained dwell time */ + cfg->next_af_subtype = action + 1; + + af_params->dwell_time = WL_MED_DWELL_TIME; + } else if (action == P2PSD_ACTION_ID_GAS_IRESP || + action == P2PSD_ACTION_ID_GAS_CRESP) { + /* configure service discovery response frame */ + af_params->dwell_time = WL_MIN_DWELL_TIME; + } else { + WL_DBG(("Unknown action type: %d\n", action)); + } + } else { + WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n", + category, action, action_frame_len)); + } + } else if (category == P2P_AF_CATEGORY) { + /* do not configure anything. it will be sent with a default configuration */ + } else { + WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n", + category, action)); + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { + wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev); + return false; + } + } + + /* To make sure to send successfully action frame, we have to turn off mpc */ + if (config_af_params.mpc_onoff == 0) { + wldev_iovar_setint(dev, "mpc", 0); + } + + /* validate channel and p2p ies */ + if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) && + wl_to_p2p_bss_saved_ie(cfg, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { + config_af_params.search_channel = true; + } else { + config_af_params.search_channel = false; + } +#ifdef WL11U + if (ndev == bcmcfg_to_prmry_ndev(cfg)) + config_af_params.search_channel = false; +#endif /* WL11U */ + +#ifdef VSDB + /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ + if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { + OSL_SLEEP(50); + } +#endif + + /* if scan is ongoing, abort current scan. */ + if (wl_get_drv_status_all(cfg, SCANNING)) { + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); + } + + /* Abort P2P listen */ + if (discover_cfgdev(cfgdev, cfg)) { + if (cfg->p2p_supported && cfg->p2p) { + wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + } + } + +#ifdef WL11U + /* handling DFS channel exceptions */ + if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) { + return false; /* the action frame was blocked */ + } +#endif /* WL11U */ + + /* set status and destination address before sending af */ + if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { + /* set this status to cancel the remained dwell time in rx process */ + wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev); + } + wl_set_drv_status(cfg, SENDING_ACT_FRM, dev); + memcpy(cfg->afx_hdl->tx_dst_addr.octet, + af_params->action_frame.da.octet, + sizeof(cfg->afx_hdl->tx_dst_addr.octet)); + + /* save af_params for rx process */ + cfg->afx_hdl->pending_tx_act_frm = af_params; + + if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) { + WL_DBG(("Set GAS action frame config.\n")); + config_af_params.search_channel = false; + config_af_params.max_tx_retry = 1; + } + + /* search peer's channel */ + if (config_af_params.search_channel) { + /* initialize afx_hdl */ + if (wl_cfgp2p_find_idx(cfg, dev, &cfg->afx_hdl->bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + goto exit; + } + cfg->afx_hdl->dev = dev; + cfg->afx_hdl->retry = 0; + cfg->afx_hdl->peer_chan = WL_INVALID; + + if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) { + WL_ERR(("couldn't find peer's channel.\n")); + wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, + af_params->channel); + goto exit; + } + + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + /* + * Abort scan even for VSDB scenarios. Scan gets aborted in firmware + * but after the check of piggyback algorithm. + * To take care of current piggback algo, lets abort the scan here itself. + */ + wl_notify_escan_complete(cfg, dev, true, true); + /* Suspend P2P discovery's search-listen to prevent it from + * starting a scan or changing the channel. + */ + wl_cfgp2p_discover_enable_search(cfg, false); + + /* update channel */ + af_params->channel = cfg->afx_hdl->peer_chan; + } + +#ifdef VSDB + off_chan_started_jiffies = jiffies; +#endif /* VSDB */ + + wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel); + + wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true); + + /* Now send a tx action frame */ + ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true; + + /* if failed, retry it. tx_retry_max value is configure by .... */ + while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) { +#ifdef VSDB + if (af_params->channel) { + if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) > + OFF_CHAN_TIME_THRESHOLD_MS) { + WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg); + off_chan_started_jiffies = jiffies; + } else + OSL_SLEEP(AF_RETRY_DELAY_TIME); + } +#endif /* VSDB */ + ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? + false : true; + } + + if (ack == false) { + WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry)); + } + WL_DBG(("Complete to send action frame\n")); +exit: + /* Clear SENDING_ACT_FRM after all sending af is done */ + wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev); + +#ifdef WL_CFG80211_SYNC_GON + /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. + * if we coundn't get the next action response frame and dongle does not keep + * the dwell time, go to listen state again to get next action response frame. + */ + if (ack && config_af_params.extra_listen && + wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) && + cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) { + s32 extar_listen_time; + + extar_listen_time = af_params->dwell_time - + jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies); + + if (extar_listen_time > 50) { + wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev); + WL_DBG(("Wait more time! actual af time:%d," + "calculated extar listen:%d\n", + af_params->dwell_time, extar_listen_time)); + if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel, + extar_listen_time + 100) == BCME_OK) { + wait_for_completion_timeout(&cfg->wait_next_af, + msecs_to_jiffies(extar_listen_time + 100 + 300)); + } + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev); + } + } +#endif /* WL_CFG80211_SYNC_GON */ + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev); + + if (cfg->afx_hdl->pending_tx_act_frm) + cfg->afx_hdl->pending_tx_act_frm = NULL; + + WL_INFORM(("-- sending Action Frame is %s, listen chan: %d\n", + (ack) ? "Succeeded!!":"Failed!!", cfg->afx_hdl->my_listen_chan)); + + + /* if all done, turn mpc on again */ + if (config_af_params.mpc_onoff == 1) { + wldev_iovar_setint(dev, "mpc", 1); + } + + return ack; +} + +#define MAX_NUM_OF_ASSOCIATED_DEV 64 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +static s32 +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +#else +static s32 +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel *channel, bool offchan, +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0)) + enum nl80211_channel_type channel_type, + bool channel_type_valid, +#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */ + unsigned int wait, const u8* buf, size_t len, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) + bool no_cck, +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS) + bool dont_wait_for_ack, +#endif + u64 *cookie) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ +{ + wl_action_frame_t *action_frame; + wl_af_params_t *af_params; + scb_val_t scb_val; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + struct ieee80211_channel *channel = params->chan; + const u8 *buf = params->buf; + size_t len = params->len; +#endif + const struct ieee80211_mgmt *mgmt; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *dev = NULL; + s32 err = BCME_OK; + s32 bssidx = 0; + u32 id; + bool ack = false; + s8 eabuf[ETHER_ADDR_STR_LEN]; + + WL_DBG(("Enter \n")); + + if (len > ACTION_FRAME_SIZE) { + WL_ERR(("bad length:%zu\n", len)); + return BCME_BADLEN; + } + + dev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (!dev) { + WL_ERR(("dev is NULL\n")); + return -EINVAL; + } + + /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */ + if (discover_cfgdev(cfgdev, cfg)) { + if (!cfg->p2p_supported || !cfg->p2p) { + WL_ERR(("P2P doesn't setup completed yet\n")); + return -EINVAL; + } + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + } + else { + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + } + + WL_DBG(("TX target bssidx=%d\n", bssidx)); + + if (p2p_is_on(cfg)) { + /* Suspend P2P discovery search-listen to prevent it from changing the + * channel. + */ + if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) { + WL_ERR(("Can not disable discovery mode\n")); + return -EFAULT; + } + } + *cookie = 0; + id = cfg->send_action_id++; + if (id == 0) + id = cfg->send_action_id++; + *cookie = id; + mgmt = (const struct ieee80211_mgmt *)buf; + if (ieee80211_is_mgmt(mgmt->frame_control)) { + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + s32 ie_len = len - ie_offset; + if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); + cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); + goto exit; + } else if (ieee80211_is_disassoc(mgmt->frame_control) || + ieee80211_is_deauth(mgmt->frame_control)) { + char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * + sizeof(struct ether_addr) + sizeof(uint)] = {0}; + int num_associated = 0; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; + if (!bcmp((const uint8 *)BSSID_BROADCAST, + (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) { + assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; + err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, + assoc_maclist, sizeof(mac_buf)); + if (err < 0) + WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); + else + num_associated = assoc_maclist->count; + } + memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); + scb_val.val = mgmt->u.disassoc.reason_code; + err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t)); + if (err < 0) + WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err)); + WL_ERR(("Disconnect STA : %s scb_val.val %d\n", + bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), + scb_val.val)); + + if (num_associated > 0 && ETHER_ISBCAST(mgmt->da)) + wl_delay(400); + + cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); + goto exit; + + } else if (ieee80211_is_action(mgmt->frame_control)) { + /* Abort the dwell time of any previous off-channel + * action frame that may be still in effect. Sending + * off-channel action frames relies on the driver's + * scan engine. If a previous off-channel action frame + * tx is still in progress (including the dwell time), + * then this new action frame will not be sent out. + */ +/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary. + * And previous off-channel action frame must be ended before new af tx. + */ +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_notify_escan_complete(cfg, dev, true, true); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + } + + } else { + WL_ERR(("Driver only allows MGMT packet type\n")); + goto exit; + } + + af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); + + if (af_params == NULL) + { + WL_ERR(("unable to allocate frame\n")); + return -ENOMEM; + } + + action_frame = &af_params->action_frame; + + /* Add the packet Id */ + action_frame->packetId = *cookie; + WL_DBG(("action frame %d\n", action_frame->packetId)); + /* Add BSSID */ + memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); + memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN); + + /* Add the length exepted for 802.11 header */ + action_frame->len = len - DOT11_MGMT_HDR_LEN; + WL_DBG(("action_frame->len: %d\n", action_frame->len)); + + /* Add the channel */ + af_params->channel = + ieee80211_frequency_to_channel(channel->center_freq); + /* Save listen_chan for searching common channel */ + cfg->afx_hdl->peer_listen_chan = af_params->channel; + WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan)); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + af_params->dwell_time = params->wait; +#else + af_params->dwell_time = wait; +#endif + + memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); + + ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params, + action_frame, action_frame->len, bssidx); + cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL); + + kfree(af_params); +exit: + return err; +} + + +static void +wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + u16 frame_type, bool reg) +{ + + WL_DBG(("frame_type: %x, reg: %d\n", frame_type, reg)); + + if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) + return; + + return; +} + + +static s32 +wl_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + s32 err = 0; + s32 ap_isolate = 0; +#ifdef PCIE_FULL_DONGLE + s32 ifidx = DHD_BAD_IF; +#endif +#if defined(SUPPORT_HOSTAPD_BGN_MODE) + s32 gmode = -1, nmode = -1; + s32 gmode_prev = -1, nmode_prev = -1; +#endif /* SUPPORT_HOSTAPD_BGN_MODE */ +#if defined(PCIE_FULL_DONGLE) || defined(SUPPORT_HOSTAPD_BGN_MODE) + dhd_pub_t *dhd; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd = (dhd_pub_t *)(cfg->pub); +#if defined(WL_ENABLE_P2P_IF) + if (cfg->p2p_net == dev) + dev = bcmcfg_to_prmry_ndev(cfg); +#endif +#endif /* PCIE_FULL_DONGLE || SUPPORT_HOSTAPD_BGN_MODE */ + + if (params->use_cts_prot >= 0) { + } + + if (params->use_short_preamble >= 0) { + } + + if (params->use_short_slot_time >= 0) { + } + + if (params->basic_rates) { +#if defined(SUPPORT_HOSTAPD_BGN_MODE) + switch ((int)(params->basic_rates[params->basic_rates_len -1])) { + case 22: /* B only , rate 11 */ + gmode = 0; + nmode = 0; + break; + case 108: /* G only , rate 54 */ + gmode = 2; + nmode = 0; + break; + default: + gmode = -1; + nmode = -1; + break; + } +#endif /* SUPPORT_HOSTAPD_BGN_MODE */ + } + + if (params->ap_isolate >= 0) { + ap_isolate = params->ap_isolate; +#ifdef PCIE_FULL_DONGLE + ifidx = dhd_net2idx(dhd->info, dev); + + if (ifidx != DHD_BAD_IF) { + err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate); + } else { + WL_ERR(("Failed to set ap_isolate\n")); + } +#else + err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate); + if (unlikely(err)) + { + WL_ERR(("set ap_isolate Error (%d)\n", err)); + } +#endif /* PCIE_FULL_DONGLE */ + } + + if (params->ht_opmode >= 0) { +#if defined(SUPPORT_HOSTAPD_BGN_MODE) + nmode = 1; + gmode = 1; + } else { + nmode = 0; +#endif /* SUPPORT_HOSTAPD_BGN_MODE */ + } + +#if defined(SUPPORT_HOSTAPD_BGN_MODE) + err = wldev_iovar_getint(dev, "nmode", &nmode_prev); + if (unlikely(err)) { + WL_ERR(("error reading nmode (%d)\n", err)); + } + if (nmode == nmode_prev) { + nmode = -1; + } + err = wldev_ioctl_get(dev, WLC_GET_GMODE, &gmode_prev, sizeof(gmode_prev)); + if (unlikely(err)) { + WL_ERR(("error reading gmode (%d)\n", err)); + } + if (gmode == gmode_prev) { + gmode = -1; + } + + if (((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) == DHD_FLAG_HOSTAP_MODE) && + ((gmode > -1) || (nmode > -1))) { + s32 val = 0; + + err = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32)); + if (unlikely(err)) + WL_ERR(("WLC_DOWN command failed:[%d]\n", err)); + + if (nmode > -1) { + err = wldev_iovar_setint(dev, "nmode", nmode); + if (unlikely(err)) + WL_ERR(("nmode command failed:mode[%d]:err[%d]\n", nmode, err)); + } + + if (gmode > -1) { + err = wldev_ioctl_set(dev, WLC_SET_GMODE, &gmode, sizeof(s32)); + if (unlikely(err)) + WL_ERR(("WLC_SET_GMODE command failed:mode[%d]:err[%d]\n", + gmode, err)); + } + + val = 0; + err = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32)); + if (unlikely(err)) + WL_ERR(("WLC_UP command failed:err[%d]\n", err)); + + } +#endif /* SUPPORT_HOSTAPD_BGN_MODE */ + + return err; +} + +static s32 +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS)) +wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + struct cfg80211_chan_def chandef) +#else +wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */ +{ + s32 _chan; + chanspec_t chspec = 0; + chanspec_t fw_chspec = 0; + u32 bw = WL_CHANSPEC_BW_20; + + s32 err = BCME_OK; + s32 bw_cap = 0; + struct { + u32 band; + u32 bw_cap; + } param = {0, 0}; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); +#ifdef CUSTOM_SET_CPUCORE + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif /* CUSTOM_SET_CPUCORE */ + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS)) + enum nl80211_channel_type channel_type = NL80211_CHAN_HT20; +#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */ + + dev = ndev_to_wlc_ndev(dev, cfg); + _chan = ieee80211_frequency_to_channel(chan->center_freq); + WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", + dev->ifindex, channel_type, _chan)); + +#if defined(CUSTOMER_HW5) +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_COMPAT_WIRELESS)) + WL_ERR(("chan_width = %d\n", chandef.width)); + switch (chandef.width) { + case NL80211_CHAN_WIDTH_40: + bw = WL_CHANSPEC_BW_40; + break; + case NL80211_CHAN_WIDTH_80: + bw = WL_CHANSPEC_BW_80; + break; + case NL80211_CHAN_WIDTH_80P80: + bw = WL_CHANSPEC_BW_8080; + break; + case NL80211_CHAN_WIDTH_160: + bw = WL_CHANSPEC_BW_160; + break; + default: + bw = WL_CHANSPEC_BW_20; + break; + } + goto set_channel; +#endif /* ((LINUX_VERSION >= VERSION(3, 8, 0) && !WL_COMPAT_WIRELESS) */ +#endif + + if (chan->band == IEEE80211_BAND_5GHZ) { + param.band = WLC_BAND_5G; + err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), + cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); + if (err) { + if (err != BCME_UNSUPPORTED) { + WL_ERR(("bw_cap failed, %d\n", err)); + return err; + } else { + err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); + if (err) { + WL_ERR(("error get mimo_bw_cap (%d)\n", err)); + } + if (bw_cap != WLC_N_BW_20ALL) + bw = WL_CHANSPEC_BW_40; + } + } else { + if (WL_BW_CAP_80MHZ(cfg->ioctl_buf[0])) + bw = WL_CHANSPEC_BW_80; + else if (WL_BW_CAP_40MHZ(cfg->ioctl_buf[0])) + bw = WL_CHANSPEC_BW_40; + else + bw = WL_CHANSPEC_BW_20; + + } + + } else if (chan->band == IEEE80211_BAND_2GHZ) + bw = WL_CHANSPEC_BW_20; +set_channel: + chspec = wf_channel2chspec(_chan, bw); + if (wf_chspec_valid(chspec)) { + fw_chspec = wl_chspec_host_to_driver(chspec); + if (fw_chspec != INVCHANSPEC) { + if ((err = wldev_iovar_setint(dev, "chanspec", + fw_chspec)) == BCME_BADCHAN) { + if (bw == WL_CHANSPEC_BW_80) + goto change_bw; + err = wldev_ioctl_set(dev, WLC_SET_CHANNEL, + &_chan, sizeof(_chan)); + if (err < 0) { + WL_ERR(("WLC_SET_CHANNEL error %d" + "chip may not be supporting this channel\n", err)); + } + } else if (err) { + WL_ERR(("failed to set chanspec error %d\n", err)); + } + } else { + WL_ERR(("failed to convert host chanspec to fw chanspec\n")); + err = BCME_ERROR; + } + } else { +change_bw: + if (bw == WL_CHANSPEC_BW_80) + bw = WL_CHANSPEC_BW_40; + else if (bw == WL_CHANSPEC_BW_40) + bw = WL_CHANSPEC_BW_20; + else + bw = 0; + if (bw) + goto set_channel; + WL_ERR(("Invalid chanspec 0x%x\n", chspec)); + err = BCME_ERROR; + } +#ifdef CUSTOM_SET_CPUCORE + if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) { + WL_DBG(("SoftAP mode do not need to set cpucore\n")); + } else if ((dev == wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) && + (chspec & WL_CHANSPEC_BW_80)) { + /* If GO is vht80 */ + dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE; + dhd_set_cpucore(dhd, TRUE); + } +#endif /* CUSTOM_SET_CPUCORE */ + return err; +} + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +struct net_device * +wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg) +{ + struct net_info *_net_info, *next; + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (_net_info->ndev && + test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state)) + return _net_info->ndev; + } + return NULL; +} +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +static s32 +wl_validate_opensecurity(struct net_device *dev, s32 bssidx) +{ + s32 err = BCME_OK; + + /* set auth */ + err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx); + if (err < 0) { + WL_ERR(("auth error %d\n", err)); + return BCME_ERROR; + } + /* set wsec */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); + if (err < 0) { + WL_ERR(("wsec error %d\n", err)); + return BCME_ERROR; + } + + /* set upper-layer auth */ + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WPA_AUTH_NONE, bssidx); + if (err < 0) { + WL_ERR(("wpa_auth error %d\n", err)); + return BCME_ERROR; + } + + return 0; +} + +static s32 +wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) +{ + s32 len = 0; + s32 err = BCME_OK; + u16 auth = 0; /* d11 open authentication */ + u32 wsec; + u32 pval = 0; + u32 gval = 0; + u32 wpa_auth = 0; + wpa_suite_mcast_t *mcast; + wpa_suite_ucast_t *ucast; + wpa_suite_auth_key_mgmt_t *mgmt; + wpa_pmkid_list_t *pmkid; + int cnt = 0; +#ifdef MFP + int mfp = 0; + struct bcm_cfg80211 *cfg = g_bcm_cfg; +#endif /* MFP */ + + u16 suite_count; + u8 rsn_cap[2]; + u32 wme_bss_disable; + + if (wpa2ie == NULL) + goto exit; + + WL_DBG(("Enter \n")); + len = wpa2ie->len - WPA2_VERSION_LEN; + /* check the mcast cipher */ + mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; + switch (mcast->type) { + case WPA_CIPHER_NONE: + gval = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + gval = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + gval = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + gval = AES_ENABLED; + break; +#ifdef BCMWAPI_WPI + case WAPI_CIPHER_SMS4: + gval = SMS4_ENABLED; + break; +#endif + default: + WL_ERR(("No Security Info\n")); + break; + } + if ((len -= WPA_SUITE_LEN) <= 0) + return BCME_BADLEN; + + /* check the unicast cipher */ + ucast = (wpa_suite_ucast_t *)&mcast[1]; + suite_count = ltoh16_ua(&ucast->count); + switch (ucast->list[0].type) { + case WPA_CIPHER_NONE: + pval = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + pval = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + pval = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + pval = AES_ENABLED; + break; +#ifdef BCMWAPI_WPI + case WAPI_CIPHER_SMS4: + pval = SMS4_ENABLED; + break; +#endif + default: + WL_ERR(("No Security Info\n")); + } + if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0) + return BCME_BADLEN; + + /* FOR WPS , set SEC_OW_ENABLED */ + wsec = (pval | gval | SES_OW_ENABLED); + /* check the AKM */ + mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; + suite_count = cnt = ltoh16_ua(&mgmt->count); + while (cnt--) { + switch (mgmt->list[cnt].type) { + case RSN_AKM_NONE: + wpa_auth = WPA_AUTH_NONE; + break; + case RSN_AKM_UNSPECIFIED: + wpa_auth = WPA2_AUTH_UNSPECIFIED; + break; + case RSN_AKM_PSK: + wpa_auth = WPA2_AUTH_PSK; + break; +#ifdef MFP + case RSN_AKM_MFP_PSK: + wpa_auth |= WPA2_AUTH_PSK; + wsec |= MFP_SHA256; + break; + case RSN_AKM_MFP_1X: + wpa_auth |= WPA2_AUTH_UNSPECIFIED; + wsec |= MFP_SHA256; + break; +#endif /* MFP */ + default: + WL_ERR(("No Key Mgmt Info\n")); + } + } + + if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { + rsn_cap[0] = *(u8 *)&mgmt->list[suite_count]; + rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1); + + if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) { + wme_bss_disable = 0; + } else { + wme_bss_disable = 1; + } + +#ifdef MFP + if (rsn_cap[0] & RSN_CAP_MFPR) { + WL_DBG(("MFP Required \n")); + mfp = WL_MFP_REQUIRED; + } else if (rsn_cap[0] & RSN_CAP_MFPC) { + WL_DBG(("MFP Capable \n")); + mfp = WL_MFP_CAPABLE; + } +#endif /* MFP */ + + /* set wme_bss_disable to sync RSN Capabilities */ + err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx); + if (err < 0) { + WL_ERR(("wme_bss_disable error %d\n", err)); + return BCME_ERROR; + } + } else { + WL_DBG(("There is no RSN Capabilities. remained len %d\n", len)); + } + + if ((len -= RSN_CAP_LEN) >= WPA2_PMKID_COUNT_LEN) { + pmkid = (wpa_pmkid_list_t *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN); + cnt = ltoh16_ua(&pmkid->count); + if (cnt != 0) { + WL_ERR(("AP has non-zero PMKID count. Wrong!\n")); + return BCME_ERROR; + } + /* since PMKID cnt is known to be 0 for AP, */ + /* so don't bother to send down this info to firmware */ + } + +#ifdef MFP + if ((len -= WPA2_PMKID_COUNT_LEN) >= RSN_GROUPMANAGE_CIPHER_LEN) { + err = wldev_iovar_setbuf_bsscfg(dev, "bip", + (void *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN), + RSN_GROUPMANAGE_CIPHER_LEN, + cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync); + if (err < 0) { + WL_ERR(("bip set error %d\n", err)); + return BCME_ERROR; + } + } +#endif + + /* set auth */ + err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); + if (err < 0) { + WL_ERR(("auth error %d\n", err)); + return BCME_ERROR; + } + /* set wsec */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); + if (err < 0) { + WL_ERR(("wsec error %d\n", err)); + return BCME_ERROR; + } + +#ifdef MFP + if (mfp) { + /* This needs to go after wsec otherwise the wsec command will + * overwrite the values set by MFP + */ + if ((err = wldev_iovar_setint_bsscfg(dev, "mfp", mfp, bssidx)) < 0) { + WL_ERR(("MFP Setting failed. ret = %d \n", err)); + return err; + } + } +#endif /* MFP */ + + /* set upper-layer auth */ + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); + if (err < 0) { + WL_ERR(("wpa_auth error %d\n", err)); + return BCME_ERROR; + } +exit: + return 0; +} + +static s32 +wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) +{ + wpa_suite_mcast_t *mcast; + wpa_suite_ucast_t *ucast; + wpa_suite_auth_key_mgmt_t *mgmt; + u16 auth = 0; /* d11 open authentication */ + u16 count; + s32 err = BCME_OK; + s32 len = 0; + u32 i; + u32 wsec; + u32 pval = 0; + u32 gval = 0; + u32 wpa_auth = 0; + u32 tmp = 0; + + if (wpaie == NULL) + goto exit; + WL_DBG(("Enter \n")); + len = wpaie->length; /* value length */ + len -= WPA_IE_TAG_FIXED_LEN; + /* check for multicast cipher suite */ + if (len < WPA_SUITE_LEN) { + WL_INFORM(("no multicast cipher suite\n")); + goto exit; + } + + /* pick up multicast cipher */ + mcast = (wpa_suite_mcast_t *)&wpaie[1]; + len -= WPA_SUITE_LEN; + if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) { + if (IS_WPA_CIPHER(mcast->type)) { + tmp = 0; + switch (mcast->type) { + case WPA_CIPHER_NONE: + tmp = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + tmp = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + tmp = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + tmp = AES_ENABLED; + break; + default: + WL_ERR(("No Security Info\n")); + } + gval |= tmp; + } + } + /* Check for unicast suite(s) */ + if (len < WPA_IE_SUITE_COUNT_LEN) { + WL_INFORM(("no unicast suite\n")); + goto exit; + } + /* walk thru unicast cipher list and pick up what we recognize */ + ucast = (wpa_suite_ucast_t *)&mcast[1]; + count = ltoh16_ua(&ucast->count); + len -= WPA_IE_SUITE_COUNT_LEN; + for (i = 0; i < count && len >= WPA_SUITE_LEN; + i++, len -= WPA_SUITE_LEN) { + if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { + if (IS_WPA_CIPHER(ucast->list[i].type)) { + tmp = 0; + switch (ucast->list[i].type) { + case WPA_CIPHER_NONE: + tmp = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + tmp = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + tmp = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + tmp = AES_ENABLED; + break; + default: + WL_ERR(("No Security Info\n")); + } + pval |= tmp; + } + } + } + len -= (count - i) * WPA_SUITE_LEN; + /* Check for auth key management suite(s) */ + if (len < WPA_IE_SUITE_COUNT_LEN) { + WL_INFORM((" no auth key mgmt suite\n")); + goto exit; + } + /* walk thru auth management suite list and pick up what we recognize */ + mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count]; + count = ltoh16_ua(&mgmt->count); + len -= WPA_IE_SUITE_COUNT_LEN; + for (i = 0; i < count && len >= WPA_SUITE_LEN; + i++, len -= WPA_SUITE_LEN) { + if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { + if (IS_WPA_AKM(mgmt->list[i].type)) { + tmp = 0; + switch (mgmt->list[i].type) { + case RSN_AKM_NONE: + tmp = WPA_AUTH_NONE; + break; + case RSN_AKM_UNSPECIFIED: + tmp = WPA_AUTH_UNSPECIFIED; + break; + case RSN_AKM_PSK: + tmp = WPA_AUTH_PSK; + break; + default: + WL_ERR(("No Key Mgmt Info\n")); + } + wpa_auth |= tmp; + } + } + + } + /* FOR WPS , set SEC_OW_ENABLED */ + wsec = (pval | gval | SES_OW_ENABLED); + /* set auth */ + err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); + if (err < 0) { + WL_ERR(("auth error %d\n", err)); + return BCME_ERROR; + } + /* set wsec */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); + if (err < 0) { + WL_ERR(("wsec error %d\n", err)); + return BCME_ERROR; + } + /* set upper-layer auth */ + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); + if (err < 0) { + WL_ERR(("wpa_auth error %d\n", err)); + return BCME_ERROR; + } +exit: + return 0; +} + + +static s32 +wl_cfg80211_bcn_validate_sec( + struct net_device *dev, + struct parsed_ies *ies, + u32 dev_role, + s32 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) { + /* For P2P GO, the sec type is WPA2-PSK */ + WL_DBG(("P2P GO: validating wpa2_ie")); + if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0) + return BCME_ERROR; + + } else if (dev_role == NL80211_IFTYPE_AP) { + + WL_DBG(("SoftAP: validating security")); + /* If wpa2_ie or wpa_ie is present validate it */ + + if ((ies->wpa2_ie || ies->wpa_ie) && + ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || + wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) { + cfg->ap_info->security_mode = false; + return BCME_ERROR; + } + + cfg->ap_info->security_mode = true; + if (cfg->ap_info->rsn_ie) { + kfree(cfg->ap_info->rsn_ie); + cfg->ap_info->rsn_ie = NULL; + } + if (cfg->ap_info->wpa_ie) { + kfree(cfg->ap_info->wpa_ie); + cfg->ap_info->wpa_ie = NULL; + } + if (cfg->ap_info->wps_ie) { + kfree(cfg->ap_info->wps_ie); + cfg->ap_info->wps_ie = NULL; + } + if (ies->wpa_ie != NULL) { + /* WPAIE */ + cfg->ap_info->rsn_ie = NULL; + cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, + ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else if (ies->wpa2_ie != NULL) { + /* RSNIE */ + cfg->ap_info->wpa_ie = NULL; + cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, + ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } + if (!ies->wpa2_ie && !ies->wpa_ie) { + wl_validate_opensecurity(dev, bssidx); + cfg->ap_info->security_mode = false; + } + + if (ies->wps_ie) { + cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); + } + } + + return 0; + +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) +static s32 wl_cfg80211_bcn_set_params( + struct cfg80211_ap_settings *info, + struct net_device *dev, + u32 dev_role, s32 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + s32 err = BCME_OK; + + WL_DBG(("interval (%d) \ndtim_period (%d) \n", + info->beacon_interval, info->dtim_period)); + + if (info->beacon_interval) { + if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD, + &info->beacon_interval, sizeof(s32))) < 0) { + WL_ERR(("Beacon Interval Set Error, %d\n", err)); + return err; + } + } + + if (info->dtim_period) { + if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD, + &info->dtim_period, sizeof(s32))) < 0) { + WL_ERR(("DTIM Interval Set Error, %d\n", err)); + return err; + } + } + + if ((info->ssid) && (info->ssid_len > 0) && + (info->ssid_len <= DOT11_MAX_SSID_LEN)) { + WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len)); + if (dev_role == NL80211_IFTYPE_AP) { + /* Store the hostapd SSID */ + memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); + memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len); + cfg->hostapd_ssid.SSID_len = info->ssid_len; + + } else { + /* P2P GO */ + memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); + memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len); + cfg->p2p->ssid.SSID_len = info->ssid_len; + } + } + + if (info->hidden_ssid) { + if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) + WL_ERR(("failed to set hidden : %d\n", err)); + WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid)); + } + + return err; +} +#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */ + +static s32 +wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies) +{ + s32 err = BCME_OK; + + memset(ies, 0, sizeof(struct parsed_ies)); + + /* find the WPSIE */ + if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) { + WL_DBG(("WPSIE in beacon \n")); + ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; + } else { + WL_ERR(("No WPSIE in beacon \n")); + } + + /* find the RSN_IE */ + if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE found\n")); + ies->wpa2_ie_len = ies->wpa2_ie->len; + } + + /* find the WPA_IE */ + if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) { + WL_DBG((" WPA found\n")); + ies->wpa_ie_len = ies->wpa_ie->length; + } + + return err; + +} + +static s32 +wl_cfg80211_bcn_bringup_ap( + struct net_device *dev, + struct parsed_ies *ies, + u32 dev_role, s32 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_join_params join_params; + bool is_bssup = false; + s32 infra = 1; + s32 join_params_size = 0; + s32 ap = 1; +#ifdef DISABLE_11H_SOFTAP + s32 spect = 0; +#endif /* DISABLE_11H_SOFTAP */ + s32 err = BCME_OK; + + WL_DBG(("Enter dev_role: %d\n", dev_role)); + + /* Common code for SoftAP and P2P GO */ + wldev_iovar_setint(dev, "mpc", 0); + + if (dev_role == NL80211_IFTYPE_P2P_GO) { + is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); + if (!is_bssup && (ies->wpa2_ie != NULL)) { + + err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32)); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + goto exit; + } + + err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid, + sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &cfg->ioctl_buf_sync); + if (err < 0) { + WL_ERR(("GO SSID setting error %d\n", err)); + goto exit; + } + + /* Do abort scan before creating GO */ + wl_cfg80211_scan_abort(cfg); + + if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) { + WL_ERR(("GO Bring up error %d\n", err)); + goto exit; + } + } else + WL_DBG(("Bss is already up\n")); + } else if ((dev_role == NL80211_IFTYPE_AP) && + (wl_get_drv_status(cfg, AP_CREATING, dev))) { + /* Device role SoftAP */ + err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32)); + if (err < 0) { + WL_ERR(("WLC_DOWN error %d\n", err)); + goto exit; + } + err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32)); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + goto exit; + } + if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) < 0) { + WL_ERR(("setting AP mode failed %d \n", err)); + goto exit; + } +#ifdef DISABLE_11H_SOFTAP + err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, + &spect, sizeof(s32)); + if (err < 0) { + WL_ERR(("SET SPECT_MANAGMENT error %d\n", err)); + goto exit; + } +#endif /* DISABLE_11H_SOFTAP */ + + err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32)); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + goto exit; + } + + memset(&join_params, 0, sizeof(join_params)); + /* join parameters starts with ssid */ + join_params_size = sizeof(join_params.ssid); + join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len, + DOT11_MAX_SSID_LEN); + memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID, + join_params.ssid.SSID_len); + join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); + + /* create softap */ + if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, + join_params_size)) == 0) { + WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID)); + wl_clr_drv_status(cfg, AP_CREATING, dev); + wl_set_drv_status(cfg, AP_CREATED, dev); + } + } + + +exit: + return err; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) +s32 +wl_cfg80211_parse_ap_ies( + struct net_device *dev, + struct cfg80211_beacon_data *info, + struct parsed_ies *ies) +{ + struct parsed_ies prb_ies; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + u8 *vndr = NULL; + u32 vndr_ie_len = 0; + s32 err = BCME_OK; + + /* Parse Beacon IEs */ + if (wl_cfg80211_parse_ies((u8 *)info->tail, + info->tail_len, ies) < 0) { + WL_ERR(("Beacon get IEs failed \n")); + err = -EINVAL; + goto fail; + } + + vndr = (u8 *)info->proberesp_ies; + vndr_ie_len = info->proberesp_ies_len; + + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { + /* SoftAP mode */ + struct ieee80211_mgmt *mgmt; + mgmt = (struct ieee80211_mgmt *)info->probe_resp; + if (mgmt != NULL) { + vndr = (u8 *)&mgmt->u.probe_resp.variable; + vndr_ie_len = info->probe_resp_len - + offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + } + } + + /* Parse Probe Response IEs */ + if (wl_cfg80211_parse_ies(vndr, vndr_ie_len, &prb_ies) < 0) { + WL_ERR(("PROBE RESP get IEs failed \n")); + err = -EINVAL; + } + +fail: + + return err; +} + +s32 +wl_cfg80211_set_ies( + struct net_device *dev, + struct cfg80211_beacon_data *info, + s32 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + u8 *vndr = NULL; + u32 vndr_ie_len = 0; + s32 err = BCME_OK; + + /* Set Beacon IEs to FW */ + if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_BEACON_FLAG, (u8 *)info->tail, + info->tail_len)) < 0) { + WL_ERR(("Set Beacon IE Failed \n")); + } else { + WL_DBG(("Applied Vndr IEs for Beacon \n")); + } + + vndr = (u8 *)info->proberesp_ies; + vndr_ie_len = info->proberesp_ies_len; + + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { + /* SoftAP mode */ + struct ieee80211_mgmt *mgmt; + mgmt = (struct ieee80211_mgmt *)info->probe_resp; + if (mgmt != NULL) { + vndr = (u8 *)&mgmt->u.probe_resp.variable; + vndr_ie_len = info->probe_resp_len - + offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + } + } + + /* Set Probe Response IEs to FW */ + if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) { + WL_ERR(("Set Probe Resp IE Failed \n")); + } else { + WL_DBG(("Applied Vndr IEs for Probe Resp \n")); + } + + return err; +} +#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */ + +static s32 wl_cfg80211_hostapd_sec( + struct net_device *dev, + struct parsed_ies *ies, + s32 bssidx) +{ + bool update_bss = 0; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + + if (ies->wps_ie) { + if (cfg->ap_info->wps_ie && + memcmp(cfg->ap_info->wps_ie, ies->wps_ie, ies->wps_ie_len)) { + WL_DBG((" WPS IE is changed\n")); + kfree(cfg->ap_info->wps_ie); + cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); + } else if (cfg->ap_info->wps_ie == NULL) { + WL_DBG((" WPS IE is added\n")); + cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); + } + + if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) { + if (!cfg->ap_info->security_mode) { + /* change from open mode to security mode */ + update_bss = true; + if (ies->wpa_ie != NULL) { + cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, + ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else { + cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, + ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } + } else if (cfg->ap_info->wpa_ie) { + /* change from WPA2 mode to WPA mode */ + if (ies->wpa_ie != NULL) { + update_bss = true; + kfree(cfg->ap_info->rsn_ie); + cfg->ap_info->rsn_ie = NULL; + cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, + ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else if (memcmp(cfg->ap_info->rsn_ie, + ies->wpa2_ie, ies->wpa2_ie->len + + WPA_RSN_IE_TAG_FIXED_LEN)) { + update_bss = true; + kfree(cfg->ap_info->rsn_ie); + cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, + ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + cfg->ap_info->wpa_ie = NULL; + } + } + if (update_bss) { + cfg->ap_info->security_mode = true; + wl_cfgp2p_bss(cfg, dev, bssidx, 0); + if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || + wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) { + return BCME_ERROR; + } + wl_cfgp2p_bss(cfg, dev, bssidx, 1); + } + } + } else { + WL_ERR(("No WPSIE in beacon \n")); + } + return 0; +} + +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) +static s32 +wl_cfg80211_del_station( + struct wiphy *wiphy, + struct net_device *ndev, + u8* mac_addr) +{ + struct net_device *dev; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + scb_val_t scb_val; + s8 eabuf[ETHER_ADDR_STR_LEN]; + int err; + char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * + sizeof(struct ether_addr) + sizeof(uint)] = {0}; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; + int num_associated = 0; + + WL_DBG(("Entry\n")); + if (mac_addr == NULL) { + WL_DBG(("mac_addr is NULL ignore it\n")); + return 0; + } + + dev = ndev_to_wlc_ndev(ndev, cfg); + + if (p2p_is_on(cfg)) { + /* Suspend P2P discovery search-listen to prevent it from changing the + * channel. + */ + if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) { + WL_ERR(("Can not disable discovery mode\n")); + return -EFAULT; + } + } + + assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; + err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST, + assoc_maclist, sizeof(mac_buf)); + if (err < 0) + WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); + else + num_associated = assoc_maclist->count; + + memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN); + scb_val.val = DOT11_RC_DEAUTH_LEAVING; + err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t)); + if (err < 0) + WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err)); + WL_ERR(("Disconnect STA : %s scb_val.val %d\n", + bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf), + scb_val.val)); + + if (num_associated > 0 && ETHER_ISBCAST(mac_addr)) + wl_delay(400); + + return 0; +} + +static s32 +wl_cfg80211_change_station( + struct wiphy *wiphy, + struct net_device *dev, + u8 *mac, + struct station_parameters *params) +{ + int err; + + WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x " + "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac), + params->sta_flags_mask, params->sta_flags_set, dev->name)); + + /* Processing only authorize/de-authorize flag for now */ + if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) { + WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n")); + return -ENOTSUPP; + } + + if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) { + err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN); + if (err) + WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err)); + return err; + } + + err = wldev_ioctl_set(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN); + if (err) + WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err)); + return err; +} +#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) +static s32 +wl_cfg80211_start_ap( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *info) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = BCME_OK; + struct parsed_ies ies; + s32 bssidx = 0; + u32 dev_role = 0; + + WL_DBG(("Enter \n")); + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + WL_DBG(("Start AP req on primary iface: Softap\n")); + dev_role = NL80211_IFTYPE_AP; + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == cfg->p2p_net) { + /* Group Add request on p2p0 */ + WL_DBG(("Start AP req on P2P iface: GO\n")); + dev = bcmcfg_to_prmry_ndev(cfg); + dev_role = NL80211_IFTYPE_P2P_GO; + } +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (p2p_is_on(cfg) && + (bssidx == wl_to_p2p_bss_bssidx(cfg, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + WL_DBG(("Start AP req on P2P connection iface\n")); + } + + if (!check_dev_role_integrity(cfg, dev_role)) + goto fail; + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS)) + if ((err = wl_cfg80211_set_channel(wiphy, dev, + dev->ieee80211_ptr->preset_chandef.chan, + dev->ieee80211_ptr->preset_chandef) < 0)) { + WL_ERR(("Set channel failed \n")); + goto fail; + } +#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */ + + if ((err = wl_cfg80211_bcn_set_params(info, dev, + dev_role, bssidx)) < 0) { + WL_ERR(("Beacon params set failed \n")); + goto fail; + } + + /* Parse IEs */ + if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) { + WL_ERR(("Set IEs failed \n")); + goto fail; + } + + if ((wl_cfg80211_bcn_validate_sec(dev, &ies, + dev_role, bssidx)) < 0) + { + WL_ERR(("Beacon set security failed \n")); + goto fail; + } + + if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, + dev_role, bssidx)) < 0) { + WL_ERR(("Beacon bring up AP/GO failed \n")); + goto fail; + } + + WL_DBG(("** AP/GO Created **\n")); + +#ifdef WL_CFG80211_ACL + /* Enfoce Admission Control. */ + if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) { + WL_ERR(("Set ACL failed\n")); + } +#endif /* WL_CFG80211_ACL */ + + /* Set IEs to FW */ + if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0) + WL_ERR(("Set IEs failed \n")); + + /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ + if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) { + bool pbc = 0; + wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); + if (pbc) { + WL_DBG(("set WLC_E_PROBREQ_MSG\n")); + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + } + } + +fail: + if (err) { + WL_ERR(("ADD/SET beacon failed\n")); + wldev_iovar_setint(dev, "mpc", 1); + } + + return err; +} + +static s32 +wl_cfg80211_stop_ap( + struct wiphy *wiphy, + struct net_device *dev) +{ + int err = 0; + u32 dev_role = 0; + int infra = 0; + int ap = 0; + s32 bssidx = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + WL_DBG(("Enter \n")); + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + dev_role = NL80211_IFTYPE_AP; + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == cfg->p2p_net) { + /* Group Add request on p2p0 */ + dev = bcmcfg_to_prmry_ndev(cfg); + dev_role = NL80211_IFTYPE_P2P_GO; + } +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (p2p_is_on(cfg) && + (bssidx == wl_to_p2p_bss_bssidx(cfg, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + } + + if (!check_dev_role_integrity(cfg, dev_role)) + goto exit; + + if (dev_role == NL80211_IFTYPE_AP) { + /* SoftAp on primary Interface. + * Shut down AP and turn on MPC + */ + if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) < 0) { + WL_ERR(("setting AP mode failed %d \n", err)); + err = -ENOTSUPP; + goto exit; + } + err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32)); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + err = -ENOTSUPP; + goto exit; + } + + err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32)); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + err = -EINVAL; + goto exit; + } + + wl_clr_drv_status(cfg, AP_CREATED, dev); + /* Turn on the MPC */ + wldev_iovar_setint(dev, "mpc", 1); + if (cfg->ap_info) { + kfree(cfg->ap_info->wpa_ie); + kfree(cfg->ap_info->rsn_ie); + kfree(cfg->ap_info->wps_ie); + kfree(cfg->ap_info); + cfg->ap_info = NULL; + } + } else { + WL_DBG(("Stopping P2P GO \n")); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub), + DHD_EVENT_TIMEOUT_MS*3); + DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub)); + } + +exit: + return err; +} + +static s32 +wl_cfg80211_change_beacon( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *info) +{ + s32 err = BCME_OK; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct parsed_ies ies; + u32 dev_role = 0; + s32 bssidx = 0; + bool pbc = 0; + + WL_DBG(("Enter \n")); + + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + dev_role = NL80211_IFTYPE_AP; + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == cfg->p2p_net) { + /* Group Add request on p2p0 */ + dev = bcmcfg_to_prmry_ndev(cfg); + dev_role = NL80211_IFTYPE_P2P_GO; + } +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (p2p_is_on(cfg) && + (bssidx == wl_to_p2p_bss_bssidx(cfg, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + } + + if (!check_dev_role_integrity(cfg, dev_role)) + goto fail; + + if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) { + WL_ERR(("P2P already down status!\n")); + err = BCME_ERROR; + goto fail; + } + + /* Parse IEs */ + if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) { + WL_ERR(("Parse IEs failed \n")); + goto fail; + } + + /* Set IEs to FW */ + if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) { + WL_ERR(("Set IEs failed \n")); + goto fail; + } + + if (dev_role == NL80211_IFTYPE_AP) { + if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { + WL_ERR(("Hostapd update sec failed \n")); + err = -EINVAL; + goto fail; + } + /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ + if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) { + wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); + WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc)); + if (pbc) + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + else + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); + } + } + +fail: + return err; +} +#else +static s32 +wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + s32 err = BCME_OK; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 ie_offset = 0; + s32 bssidx = 0; + u32 dev_role = NL80211_IFTYPE_AP; + struct parsed_ies ies; + bcm_tlv_t *ssid_ie; + bool pbc = 0; + WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", + info->interval, info->dtim_period, info->head_len, info->tail_len)); + + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + dev_role = NL80211_IFTYPE_AP; + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == cfg->p2p_net) { + /* Group Add request on p2p0 */ + dev = bcmcfg_to_prmry_ndev(cfg); + dev_role = NL80211_IFTYPE_P2P_GO; + } +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (p2p_is_on(cfg) && + (bssidx == wl_to_p2p_bss_bssidx(cfg, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + } + + if (!check_dev_role_integrity(cfg, dev_role)) + goto fail; + + if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) { + WL_ERR(("P2P already down status!\n")); + err = BCME_ERROR; + goto fail; + } + + ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + /* find the SSID */ + if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], + info->head_len - ie_offset, + DOT11_MNG_SSID_ID)) != NULL) { + if (dev_role == NL80211_IFTYPE_AP) { + /* Store the hostapd SSID */ + memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); + cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN); + memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data, + cfg->hostapd_ssid.SSID_len); + } else { + /* P2P GO */ + memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); + cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN); + memcpy(cfg->p2p->ssid.SSID, ssid_ie->data, + cfg->p2p->ssid.SSID_len); + } + } + + if (wl_cfg80211_parse_ies((u8 *)info->tail, + info->tail_len, &ies) < 0) { + WL_ERR(("Beacon get IEs failed \n")); + err = -EINVAL; + goto fail; + } + + if (wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_BEACON_FLAG, (u8 *)info->tail, + info->tail_len) < 0) { + WL_ERR(("Beacon set IEs failed \n")); + goto fail; + } else { + WL_DBG(("Applied Vndr IEs for Beacon \n")); + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + if (wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies, + info->proberesp_ies_len) < 0) { + WL_ERR(("ProbeRsp set IEs failed \n")); + goto fail; + } else { + WL_DBG(("Applied Vndr IEs for ProbeRsp \n")); + } +#endif + + if (!wl_cfgp2p_bss_isup(dev, bssidx) && + (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx) < 0)) + { + WL_ERR(("Beacon set security failed \n")); + goto fail; + } + + /* Set BI and DTIM period */ + if (info->interval) { + if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD, + &info->interval, sizeof(s32))) < 0) { + WL_ERR(("Beacon Interval Set Error, %d\n", err)); + return err; + } + } + if (info->dtim_period) { + if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD, + &info->dtim_period, sizeof(s32))) < 0) { + WL_ERR(("DTIM Interval Set Error, %d\n", err)); + return err; + } + } + + if (wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx) < 0) { + WL_ERR(("Beacon bring up AP/GO failed \n")); + goto fail; + } + + if (wl_get_drv_status(cfg, AP_CREATED, dev)) { + /* Soft AP already running. Update changed params */ + if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { + WL_ERR(("Hostapd update sec failed \n")); + err = -EINVAL; + goto fail; + } + } + + /* Enable Probe Req filter */ + if (((dev_role == NL80211_IFTYPE_P2P_GO) || + (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) { + wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); + if (pbc) + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + } + + WL_DBG(("** ADD/SET beacon done **\n")); + +fail: + if (err) { + WL_ERR(("ADD/SET beacon failed\n")); + wldev_iovar_setint(dev, "mpc", 1); + } + return err; + +} +#endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */ + +#ifdef WL_SCHED_SCAN +#define PNO_TIME 30 +#define PNO_REPEAT 4 +#define PNO_FREQ_EXPO_MAX 2 +static bool +is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count) +{ + int i; + + if (!ssid || !ssid_list) + return FALSE; + + for (i = 0; i < count; i++) { + if (ssid->ssid_len == ssid_list[i].ssid_len) { + if (strncmp(ssid->ssid, ssid_list[i].ssid, ssid->ssid_len) == 0) + return TRUE; + } + } + return FALSE; +} + +static int +wl_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *request) +{ + ushort pno_time = PNO_TIME; + int pno_repeat = PNO_REPEAT; + int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; + wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct cfg80211_ssid *ssid = NULL; + struct cfg80211_ssid *hidden_ssid_list = NULL; + int ssid_cnt = 0; + int i; + int ret = 0; + + WL_DBG(("Enter \n")); + WL_ERR((">>> SCHED SCAN START\n")); + WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n", + request->n_match_sets, request->n_ssids)); + WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n", + request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max)); + + + if (!request || !request->n_ssids || !request->n_match_sets) { + WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids)); + return -EINVAL; + } + + memset(&ssids_local, 0, sizeof(ssids_local)); + + if (request->n_ssids > 0) + hidden_ssid_list = request->ssids; + + for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) { + ssid = &request->match_sets[i].ssid; + /* No need to include null ssid */ + if (ssid->ssid_len) { + ssids_local[ssid_cnt].SSID_len = MIN(ssid->ssid_len, + DOT11_MAX_SSID_LEN); + memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid, + ssids_local[ssid_cnt].SSID_len); + if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) { + ssids_local[ssid_cnt].hidden = TRUE; + WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid)); + } else { + ssids_local[ssid_cnt].hidden = FALSE; + WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid->ssid)); + } + if (request->match_sets[i].rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) { + ssids_local[ssid_cnt].rssi_thresh = + (int8)request->match_sets[i].rssi_thold; + } + ssid_cnt++; + } + } + + if (ssid_cnt) { + if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, ssid_cnt, pno_time, + pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) { + WL_ERR(("PNO setup failed!! ret=%d \n", ret)); + return -EINVAL; + } + cfg->sched_scan_req = request; + } else { + return -EINVAL; + } + + return 0; +} + +static int +wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + WL_DBG(("Enter \n")); + WL_PNO((">>> SCHED SCAN STOP\n")); + + if (dhd_dev_pno_stop_for_ssid(dev) < 0) + WL_ERR(("PNO Stop for SSID failed")); + + if (cfg->scan_request && cfg->sched_scan_running) { + WL_PNO((">>> Sched scan running. Aborting it..\n")); + wl_notify_escan_complete(cfg, dev, true, true); + } + + cfg->sched_scan_req = NULL; + cfg->sched_scan_running = FALSE; + + return 0; +} +#endif /* WL_SCHED_SCAN */ + +#ifdef WL_SUPPORT_ACS +/* + * Currently the dump_obss IOVAR is returning string as output so we need to + * parse the output buffer in an unoptimized way. Going forward if we get the + * IOVAR output in binary format this method can be optimized + */ +static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey) +{ + int i; + char *token; + char delim[] = " \n"; + + token = strsep(&buf, delim); + while (token != NULL) { + if (!strcmp(token, "OBSS")) { + for (i = 0; i < OBSS_TOKEN_IDX; i++) + token = strsep(&buf, delim); + survey->obss = simple_strtoul(token, NULL, 10); + } + + if (!strcmp(token, "IBSS")) { + for (i = 0; i < IBSS_TOKEN_IDX; i++) + token = strsep(&buf, delim); + survey->ibss = simple_strtoul(token, NULL, 10); + } + + if (!strcmp(token, "TXDur")) { + for (i = 0; i < TX_TOKEN_IDX; i++) + token = strsep(&buf, delim); + survey->tx = simple_strtoul(token, NULL, 10); + } + + if (!strcmp(token, "Category")) { + for (i = 0; i < CTG_TOKEN_IDX; i++) + token = strsep(&buf, delim); + survey->no_ctg = simple_strtoul(token, NULL, 10); + } + + if (!strcmp(token, "Packet")) { + for (i = 0; i < PKT_TOKEN_IDX; i++) + token = strsep(&buf, delim); + survey->no_pckt = simple_strtoul(token, NULL, 10); + } + + if (!strcmp(token, "Opp(time):")) { + for (i = 0; i < IDLE_TOKEN_IDX; i++) + token = strsep(&buf, delim); + survey->idle = simple_strtoul(token, NULL, 10); + } + + token = strsep(&buf, delim); + } + + return 0; +} + +static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req, + struct wl_dump_survey *survey) +{ + cca_stats_n_flags *results; + char *buf; + int retry, err; + + buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL); + if (unlikely(!buf)) { + WL_ERR(("%s: buf alloc failed\n", __func__)); + return -ENOMEM; + } + + retry = IOCTL_RETRY_COUNT; + while (retry--) { + err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req), + buf, WLC_IOCTL_MAXLEN, NULL); + if (err >= 0) { + break; + } + WL_DBG(("attempt = %d, err = %d, \n", + (IOCTL_RETRY_COUNT - retry), err)); + } + + if (retry <= 0) { + WL_ERR(("failure, dump_obss IOVAR failed\n")); + err = -BCME_ERROR; + goto exit; + } + + results = (cca_stats_n_flags *)(buf); + wl_parse_dump_obss(results->buf, survey); + kfree(buf); + + return 0; +exit: + kfree(buf); + return err; +} + +static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, + int idx, struct survey_info *info) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct wl_dump_survey *survey; + struct ieee80211_supported_band *band; + struct ieee80211_channel*chan; + cca_msrmnt_query req; + int val, err, noise, retry; + + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { + return -ENOENT; + } + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + if (band && idx >= band->n_channels) { + idx -= band->n_channels; + band = NULL; + } + + if (!band || idx >= band->n_channels) { + /* Move to 5G band */ + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (idx >= band->n_channels) { + return -ENOENT; + } + } + + chan = &band->channels[idx]; + /* Setting current channel to the requested channel */ + if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan, + NL80211_CHAN_HT20) < 0)) { + WL_ERR(("Set channel failed \n")); + } + + if (!idx) { + /* Disable mpc */ + val = 0; + err = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, + sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, + &cfg->ioctl_buf_sync); + if (err < 0) { + WL_ERR(("set 'mpc' failed, error = %d\n", err)); + } + + /* Set interface up, explicitly. */ + val = 1; + err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val); + if (err < 0) { + WL_ERR(("set interface up failed, error = %d\n", err)); + } + } + + /* Get noise value */ + retry = IOCTL_RETRY_COUNT; + while (retry--) { + noise = 0; + err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise, + sizeof(noise)); + if (err >= 0) { + break; + } + WL_DBG(("attempt = %d, err = %d, \n", + (IOCTL_RETRY_COUNT - retry), err)); + } + + if (retry <= 0) { + WL_ERR(("Get Phy Noise failed, error = %d\n", err)); + noise = CHAN_NOISE_DUMMY; + } + + survey = (struct wl_dump_survey *) kzalloc(sizeof(struct wl_dump_survey), + GFP_KERNEL); + if (unlikely(!survey)) { + WL_ERR(("%s: alloc failed\n", __func__)); + return -ENOMEM; + } + + /* Start Measurement for obss stats on current channel */ + req.msrmnt_query = 0; + req.time_req = ACS_MSRMNT_DELAY; + if ((err = wl_dump_obss(ndev, req, survey)) < 0) { + goto exit; + } + + /* + * Wait for the meaurement to complete, adding a buffer value of 10 to take + * into consideration any delay in IOVAR completion + */ + msleep(ACS_MSRMNT_DELAY + 10); + + /* Issue IOVAR to collect measurement results */ + req.msrmnt_query = 1; + if ((err = wl_dump_obss(ndev, req, survey)) < 0) { + goto exit; + } + + info->channel = chan; + info->noise = noise; + info->channel_time = ACS_MSRMNT_DELAY; + info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle; + info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg + + survey->no_pckt; + info->channel_time_tx = survey->tx; + info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME | + SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX | + SURVEY_INFO_CHANNEL_TIME_TX; + kfree(survey); + + return 0; +exit: + kfree(survey); + return err; +} +#endif /* WL_SUPPORT_ACS */ + +static struct cfg80211_ops wl_cfg80211_ops = { + .add_virtual_intf = wl_cfg80211_add_virtual_iface, + .del_virtual_intf = wl_cfg80211_del_virtual_iface, + .change_virtual_intf = wl_cfg80211_change_virtual_iface, +#if defined(WL_CFG80211_P2P_DEV_IF) + .start_p2p_device = wl_cfgp2p_start_p2p_device, + .stop_p2p_device = wl_cfgp2p_stop_p2p_device, +#endif /* WL_CFG80211_P2P_DEV_IF */ + .scan = wl_cfg80211_scan, + .set_wiphy_params = wl_cfg80211_set_wiphy_params, + .join_ibss = wl_cfg80211_join_ibss, + .leave_ibss = wl_cfg80211_leave_ibss, + .get_station = wl_cfg80211_get_station, + .set_tx_power = wl_cfg80211_set_tx_power, + .get_tx_power = wl_cfg80211_get_tx_power, + .add_key = wl_cfg80211_add_key, + .del_key = wl_cfg80211_del_key, + .get_key = wl_cfg80211_get_key, + .set_default_key = wl_cfg80211_config_default_key, + .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key, + .set_power_mgmt = wl_cfg80211_set_power_mgmt, + .connect = wl_cfg80211_connect, + .disconnect = wl_cfg80211_disconnect, + .suspend = wl_cfg80211_suspend, + .resume = wl_cfg80211_resume, + .set_pmksa = wl_cfg80211_set_pmksa, + .del_pmksa = wl_cfg80211_del_pmksa, + .flush_pmksa = wl_cfg80211_flush_pmksa, + .remain_on_channel = wl_cfg80211_remain_on_channel, + .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel, + .mgmt_tx = wl_cfg80211_mgmt_tx, + .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, + .change_bss = wl_cfg80211_change_bss, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS) + .set_channel = wl_cfg80211_set_channel, +#endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS) + .set_beacon = wl_cfg80211_add_set_beacon, + .add_beacon = wl_cfg80211_add_set_beacon, +#else + .change_beacon = wl_cfg80211_change_beacon, + .start_ap = wl_cfg80211_start_ap, + .stop_ap = wl_cfg80211_stop_ap, +#endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */ +#ifdef WL_SCHED_SCAN + .sched_scan_start = wl_cfg80211_sched_scan_start, + .sched_scan_stop = wl_cfg80211_sched_scan_stop, +#endif /* WL_SCHED_SCAN */ +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) + .del_station = wl_cfg80211_del_station, + .change_station = wl_cfg80211_change_station, + .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, +#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) + .tdls_mgmt = wl_cfg80211_tdls_mgmt, + .tdls_oper = wl_cfg80211_tdls_oper, +#endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */ +#ifdef WL_SUPPORT_ACS + .dump_survey = wl_cfg80211_dump_survey, +#endif /* WL_SUPPORT_ACS */ +#ifdef WL_CFG80211_ACL + .set_mac_acl = wl_cfg80211_set_mac_acl, +#endif /* WL_CFG80211_ACL */ +#if defined(WL_ABORT_SCAN) + .abort_scan = wl_cfg80211_abort_scan, +#endif /* WL_ABORT_SCAN */ + +}; + +s32 wl_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; + case WL_MODE_AP: + return NL80211_IFTYPE_AP; + default: + return NL80211_IFTYPE_UNSPECIFIED; + } + + return err; +} + + +#ifdef CONFIG_PM +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static const struct wiphy_wowlan_support brcm_wowlan_support = { + .flags = WIPHY_WOWLAN_ANY, +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ +#endif /* CONFIG_PM */ + +static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context) +{ + s32 err = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS)) + dhd_pub_t *dhd = (dhd_pub_t *)context; + BCM_REFERENCE(dhd); + + if (!dhd) { + WL_ERR(("DHD is NULL!!")); + err = -ENODEV; + return err; + } +#endif + + wdev->wiphy = + wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211)); + if (unlikely(!wdev->wiphy)) { + WL_ERR(("Couldn not allocate wiphy device\n")); + err = -ENOMEM; + return err; + } + set_wiphy_dev(wdev->wiphy, sdiofunc_dev); + wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; + /* Report how many SSIDs Driver can support per Scan request */ + wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; + wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; +#ifdef WL_SCHED_SCAN + wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; + wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; + wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; +#endif /* WL_SCHED_SCAN */ + wdev->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC) +#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_MONITOR) +#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) +#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_P2P_DEVICE) +#endif /* WL_CFG80211_P2P_DEV_IF */ + | BIT(NL80211_IFTYPE_AP); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) + WL_DBG(("Setting interface combinations for common mode\n")); + wdev->wiphy->iface_combinations = common_iface_combinations; + wdev->wiphy->n_iface_combinations = + ARRAY_SIZE(common_iface_combinations); +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ + + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + + 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->max_remain_on_channel_duration = 5000; + wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes; +#ifndef WL_POWERSAVE_DISABLED + wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; +#else + wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; +#endif /* !WL_POWERSAVE_DISABLED */ + wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | + WIPHY_FLAG_4ADDR_AP | +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS) + WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | +#endif + WIPHY_FLAG_4ADDR_STATION; +#if (defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && ((LINUX_VERSION_CODE >= \ + KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)) + /* Please use supplicant ver >= 76 if FW_ROAM is enabled + * If driver advertises FW_ROAM, older supplicant wouldn't + * send the BSSID & Freq in the connect req command. This + * will delay the ASSOC as the FW need to do a full scan + * before attempting to connect. Supplicant >=76 has patch + * to allow bssid & freq to be sent down to driver even if + * FW ROAM is advertised. + */ + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS) + wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_OFFCHAN_TX; +#endif +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 4, 0)) + /* From 3.4 kernel ownards AP_SME flag can be advertised + * to remove the patch from supplicant + */ + wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; + +#ifdef WL_CFG80211_ACL + /* Configure ACL capabilities. */ + wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS)) + /* Supplicant distinguish between the SoftAP mode and other + * modes (e.g. P2P, WPS, HS2.0) when it builds the probe + * response frame from Supplicant MR1 and Kernel 3.4.0 or + * later version. To add Vendor specific IE into the + * probe response frame in case of SoftAP mode, + * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable. + */ + if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) { + wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + wdev->wiphy->probe_resp_offload = 0; + } +#endif +#endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */ + + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; +#endif + +#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF) + /* + * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the + * disconnection of connected network before suspend. So a dummy wowlan + * filter is configured for kernels linux-3.8 and above. + */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + wdev->wiphy->wowlan = &brcm_wowlan_support; +#else + wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 10) */ +#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */ + + WL_DBG(("Registering custom regulatory)\n")); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; +#else + wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; +#endif + wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) + WL_DBG(("Registering Vendor80211)\n")); + err = wl_cfgvendor_attach(wdev->wiphy); + if (unlikely(err < 0)) { + WL_ERR(("Couldn not attach vendor commands (%d)\n", err)); + } +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ + + /* Now we can register wiphy with cfg80211 module */ + err = wiphy_register(wdev->wiphy); + if (unlikely(err < 0)) { + WL_ERR(("Couldn not register wiphy device (%d)\n", err)); + wiphy_free(wdev->wiphy); + } + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS) + wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS; +#endif + + return err; +} + +static void wl_free_wdev(struct bcm_cfg80211 *cfg) +{ + struct wireless_dev *wdev = cfg->wdev; + struct wiphy *wiphy; + if (!wdev) { + WL_ERR(("wdev is invalid\n")); + return; + } + wiphy = wdev->wiphy; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) + wl_cfgvendor_detach(wdev->wiphy); +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ + + wiphy_unregister(wdev->wiphy); + wdev->wiphy->dev.parent = NULL; + + wl_delete_all_netinfo(cfg); + wiphy_free(wiphy); + /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg", + * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! + */ +} + +static s32 wl_inform_bss(struct bcm_cfg80211 *cfg) +{ + struct wl_scan_results *bss_list; + struct wl_bss_info *bi = NULL; /* must be initialized */ + s32 err = 0; + s32 i; + + bss_list = cfg->bss_list; + WL_DBG(("scanned AP count (%d)\n", bss_list->count)); + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + err = wl_inform_single_bss(cfg, bi, false); + if (unlikely(err)) + break; + } + return err; +} + +static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam) +{ + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct ieee80211_mgmt *mgmt; + struct ieee80211_channel *channel; + struct ieee80211_supported_band *band; + struct wl_cfg80211_bss_info *notif_bss_info; + struct wl_scan_req *sr = wl_to_sr(cfg); + struct beacon_proberesp *beacon_proberesp; + struct cfg80211_bss *cbss = NULL; + s32 mgmt_type; + s32 signal; + u32 freq; + s32 err = 0; + gfp_t aflags; + + if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { + WL_DBG(("Beacon is larger than buffer. Discarding\n")); + return err; + } + aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) + - sizeof(u8) + WL_BSS_INFO_MAX, aflags); + if (unlikely(!notif_bss_info)) { + WL_ERR(("notif_bss_info alloc failed\n")); + return -ENOMEM; + } + mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; + notif_bss_info->channel = + wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); + + if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (!band) { + WL_ERR(("No valid band")); + kfree(notif_bss_info); + return -EINVAL; + } + notif_bss_info->rssi = wl_rssi_offset(dtoh16(bi->RSSI)); + memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); + mgmt_type = cfg->active_scan ? + IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; + if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type); + } + beacon_proberesp = cfg->active_scan ? + (struct beacon_proberesp *)&mgmt->u.probe_resp : + (struct beacon_proberesp *)&mgmt->u.beacon; + beacon_proberesp->timestamp = 0; + beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); + beacon_proberesp->capab_info = cpu_to_le16(bi->capability); + wl_rst_ie(cfg); + wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, roam); + wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length); + wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX - + offsetof(struct wl_cfg80211_bss_info, frame_buf)); + notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, + u.beacon.variable) + wl_get_ielen(cfg); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) + freq = ieee80211_channel_to_frequency(notif_bss_info->channel); + (void)band->band; +#else + freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); +#endif + if (freq == 0) { + WL_ERR(("Invalid channel, fail to chcnage channel to freq\n")); + kfree(notif_bss_info); + return -EINVAL; + } + channel = ieee80211_get_channel(wiphy, freq); + if (unlikely(!channel)) { + WL_ERR(("ieee80211_get_channel error\n")); + kfree(notif_bss_info); + return -EINVAL; + } + WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM" + "mgmt_type %d frame_len %d\n", bi->SSID, + notif_bss_info->rssi, notif_bss_info->channel, + mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type, + notif_bss_info->frame_len)); + + signal = notif_bss_info->rssi * 100; + if (!mgmt->u.probe_resp.timestamp) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) + struct timespec ts; + get_monotonic_boottime(&ts); + mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) + + ts.tv_nsec / 1000; +#else + struct timeval tv; + do_gettimeofday(&tv); + mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000) + + tv.tv_usec; +#endif + } + + + cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, + le16_to_cpu(notif_bss_info->frame_len), signal, aflags); + if (unlikely(!cbss)) { + WL_ERR(("cfg80211_inform_bss_frame error\n")); + kfree(notif_bss_info); + return -EINVAL; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + cfg80211_put_bss(wiphy, cbss); +#else + cfg80211_put_bss(cbss); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ + kfree(notif_bss_info); + return err; +} + +static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev) +{ + u32 event = ntoh32(e->event_type); + u32 status = ntoh32(e->status); + u16 flags = ntoh16(e->flags); + + WL_DBG(("event %d, status %d flags %x\n", event, status, flags)); + if (event == WLC_E_SET_SSID) { + if (status == WLC_E_STATUS_SUCCESS) { + if (!wl_is_ibssmode(cfg, ndev)) + return true; + } + } else if (event == WLC_E_LINK) { + if (flags & WLC_EVENT_MSG_LINK) + return true; + } + + WL_DBG(("wl_is_linkup false\n")); + return false; +} + +static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e) +{ + u32 event = ntoh32(e->event_type); + u16 flags = ntoh16(e->flags); + + if (event == WLC_E_DEAUTH_IND || + event == WLC_E_DISASSOC_IND || + event == WLC_E_DISASSOC || + event == WLC_E_DEAUTH) { +#if (WL_DBG_LEVEL > 0) + WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); +#endif /* (WL_DBG_LEVEL > 0) */ + return true; + } else if (event == WLC_E_LINK) { + if (!(flags & WLC_EVENT_MSG_LINK)) { +#if (WL_DBG_LEVEL > 0) + WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); +#endif /* (WL_DBG_LEVEL > 0) */ + return true; + } + } + + return false; +} + +static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e) +{ + u32 event = ntoh32(e->event_type); + u32 status = ntoh32(e->status); + + if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) + return true; + if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) + return true; + + return false; +} + +/* The mainline kernel >= 3.2.0 has support for indicating new/del station + * to AP/P2P GO via events. If this change is backported to kernel for which + * this driver is being built, then define WL_CFG80211_STA_EVENT. You + * should use this new/del sta event mechanism for BRCM supplicant >= 22. + */ +static s32 +wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + u32 event = ntoh32(e->event_type); + u32 reason = ntoh32(e->reason); + u32 len = ntoh32(e->datalen); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) \ + && !defined(WL_COMPAT_WIRELESS) + bool isfree = false; + u8 *mgmt_frame; + u8 bsscfgidx = e->bsscfgidx; + s32 freq; + s32 channel; + u8 *body = NULL; + u16 fc = 0; + + struct ieee80211_supported_band *band; + struct ether_addr da; + struct ether_addr bssid; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + channel_info_t ci; +#else + struct station_info sinfo; +#endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ + + WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason)); + /* if link down, bsscfg is disabled. */ + if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS && + wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) { + wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false); + WL_INFORM(("AP mode link down !! \n")); + complete(&cfg->iface_disable); + return 0; + } + + if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) { + WL_ERR(("event %s(%d) status %d reason %d\n", + bcmevent_get_name(event), event, ntoh32(e->status), reason)); + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) \ + && !defined(WL_COMPAT_WIRELESS) + WL_DBG(("Enter \n")); + if (!len && (event == WLC_E_DEAUTH)) { + len = 2; /* reason code field */ + data = &reason; + } + if (len) { + body = kzalloc(len, GFP_KERNEL); + + if (body == NULL) { + WL_ERR(("wl_notify_connect_status: Failed to allocate body\n")); + return WL_INVALID; + } + } + memset(&bssid, 0, ETHER_ADDR_LEN); + WL_DBG(("Enter event %d ndev %p\n", event, ndev)); + if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) { + kfree(body); + return WL_INVALID; + } + if (len) + memcpy(body, data, len); + + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); + memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); + memset(&bssid, 0, sizeof(bssid)); + err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); + switch (event) { + case WLC_E_ASSOC_IND: + fc = FC_ASSOC_REQ; + break; + case WLC_E_REASSOC_IND: + fc = FC_REASSOC_REQ; + break; + case WLC_E_DISASSOC_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH: + fc = FC_DISASSOC; + break; + default: + fc = 0; + goto exit; + } + memset(&ci, 0, sizeof(ci)); + if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) { + kfree(body); + return err; + } + + channel = dtoh32(ci.hw_channel); + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (!band) { + WL_ERR(("No valid band")); + if (body) + kfree(body); + return -EINVAL; + } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) + freq = ieee80211_channel_to_frequency(channel); + (void)band->band; +#else + freq = ieee80211_channel_to_frequency(channel, band->band); +#endif + + err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, + &mgmt_frame, &len, body); + if (err < 0) + goto exit; + isfree = true; + + if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ + defined(WL_COMPAT_WIRELESS) + cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); +#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ + } else if (event == WLC_E_DISASSOC_IND) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ + defined(WL_COMPAT_WIRELESS) + cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); +#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ + } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ + defined(WL_COMPAT_WIRELESS) + cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); +#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ + } + +exit: + if (isfree) + kfree(mgmt_frame); + if (body) + kfree(body); +#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ + sinfo.filled = 0; + if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && + reason == DOT11_SC_SUCCESS) { + sinfo.filled = STATION_INFO_ASSOC_REQ_IES; + if (!data) { + WL_ERR(("No IEs present in ASSOC/REASSOC_IND")); + return -EINVAL; + } + sinfo.assoc_req_ies = data; + sinfo.assoc_req_ies_len = len; + cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); + } else if (event == WLC_E_DISASSOC_IND) { + cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); + } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { + cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); + } +#endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ + return err; +} + +static s32 +wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e) +{ + u32 reason = ntoh32(e->reason); + u32 event = ntoh32(e->event_type); + struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); + WL_DBG(("event type : %d, reason : %d\n", event, reason)); + if (sec) { + switch (event) { + case WLC_E_ASSOC: + case WLC_E_AUTH: + sec->auth_assoc_res_status = reason; + default: + break; + } + } else + WL_ERR(("sec is NULL\n")); + return 0; +} + +static s32 +wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + u32 event = ntoh32(e->event_type); + u16 flags = ntoh16(e->flags); + u32 status = ntoh32(e->status); + bool active; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + struct ieee80211_channel *channel = NULL; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + u32 chanspec, chan; + u32 freq, band; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */ + + if (event == WLC_E_JOIN) { + WL_DBG(("joined in IBSS network\n")); + } + if (event == WLC_E_START) { + WL_DBG(("started IBSS network\n")); + } + if (event == WLC_E_JOIN || event == WLC_E_START || + (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec); + if (unlikely(err)) { + WL_ERR(("Could not get chanspec %d\n", err)); + return err; + } + chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec)); + band = (chan <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + freq = ieee80211_channel_to_frequency(chan, band); + channel = ieee80211_get_channel(wiphy, freq); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */ + if (wl_get_drv_status(cfg, CONNECTED, ndev)) { + /* ROAM or Redundant */ + u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) { + WL_DBG(("IBSS connected event from same BSSID(" + MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid))); + return err; + } + WL_INFORM(("IBSS BSSID is changed from " MACDBG " to " MACDBG "\n", + MAC2STRDBG(cur_bssid), MAC2STRDBG((u8 *)&e->addr))); + wl_get_assoc_ies(cfg, ndev); + wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + wl_update_bss_info(cfg, ndev, false); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + cfg80211_ibss_joined(ndev, (s8 *)&e->addr, channel, GFP_KERNEL); +#else + cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); +#endif + } + else { + /* New connection */ + WL_INFORM(("IBSS connected to " MACDBG "\n", MAC2STRDBG((u8 *)&e->addr))); + wl_link_up(cfg); + wl_get_assoc_ies(cfg, ndev); + wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + wl_update_bss_info(cfg, ndev, false); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + cfg80211_ibss_joined(ndev, (s8 *)&e->addr, channel, GFP_KERNEL); +#else + cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); +#endif + wl_set_drv_status(cfg, CONNECTED, ndev); + active = true; + wl_update_prof(cfg, ndev, NULL, (void *)&active, WL_PROF_ACT); + } + } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) || + event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) { + wl_clr_drv_status(cfg, CONNECTED, ndev); + wl_link_down(cfg); + wl_init_prof(cfg, ndev); + } + else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) { + WL_DBG(("no action - join fail (IBSS mode)\n")); + } + else { + WL_DBG(("no action (IBSS mode)\n")); +} + return err; +} + +static s32 +wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + bool act; + struct net_device *ndev = NULL; + s32 err = 0; + u32 event = ntoh32(e->event_type); + +#ifdef DHD_ENABLE_DISC_TIME_LOG + struct timeval tv_now; + do_gettimeofday(&tv_now); +#endif /* DHD_ENABLE_DISC_TIME_LOG */ + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { + err = wl_notify_connect_status_ap(cfg, ndev, e, data); + } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS) { + err = wl_notify_connect_status_ibss(cfg, ndev, e, data); + } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) { + WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", + ntoh32(e->event_type), ntoh32(e->status), ndev)); + if (event == WLC_E_ASSOC || event == WLC_E_AUTH) { + wl_get_auth_assoc_status(cfg, ndev, e); + return 0; + } + if (wl_is_linkup(cfg, e, ndev)) { + wl_link_up(cfg); + act = true; + if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) { + printk("wl_bss_connect_done succeeded with " MACDBG "\n", + MAC2STRDBG((u8*)(&e->addr))); + wl_bss_connect_done(cfg, ndev, e, data, true); + WL_DBG(("joined in BSS network \"%s\"\n", + ((struct wlc_ssid *) + wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID)); + } + wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); + wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + + } else if (wl_is_linkdown(cfg, e)) { + + if (cfg->scan_request) + wl_notify_escan_complete(cfg, ndev, true, true); + if (wl_get_drv_status(cfg, CONNECTED, ndev)) { + scb_val_t scbval; + u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + s32 reason = 0; + if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) + reason = ntoh32(e->reason); + /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ + reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; + +#ifdef DHD_ENABLE_DISC_TIME_LOG + printk("KERN_ERR [Log]%s: current time=%lu\n", __FUNCTION__, + (unsigned long int) tv_now.tv_sec*1000000+tv_now.tv_usec); +#endif /* DHD_ENABLE_DISC_TIME_LOG */ + printk("link down if %s may call cfg80211_disconnected. " + "event : %d, reason=%d from " MACDBG "\n", + ndev->name, event, ntoh32(e->reason), + MAC2STRDBG((u8*)(&e->addr))); + if (!cfg->roam_offload && + memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) { + WL_ERR(("BSSID of event is not the connected BSSID" + "(ignore it) cur: " MACDBG " event: " MACDBG"\n", + MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr)))); + return 0; + } + wl_clr_drv_status(cfg, CONNECTED, ndev); + if (! wl_get_drv_status(cfg, DISCONNECTING, ndev)) { + /* To make sure disconnect, explictly send dissassoc + * for BSSID 00:00:00:00:00:00 issue + */ + scbval.val = WLAN_REASON_DEAUTH_LEAVING; + + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); + if (err < 0) { + WL_ERR(("WLC_DISASSOC error %d\n", err)); + err = 0; + } + cfg80211_disconnected(ndev, reason, NULL, 0, GFP_KERNEL); + wl_link_down(cfg); + wl_init_prof(cfg, ndev); + } + } + else if (wl_get_drv_status(cfg, CONNECTING, ndev)) { + printk("link down, during connecting\n"); +#ifdef ESCAN_RESULT_PATCH + if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) || + (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) || + (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0)) + /* In case this event comes while associating another AP */ +#endif /* ESCAN_RESULT_PATCH */ + wl_bss_connect_done(cfg, ndev, e, data, false); + } + wl_clr_drv_status(cfg, DISCONNECTING, ndev); + + /* if link down, bsscfg is diabled */ + if (ndev != bcmcfg_to_prmry_ndev(cfg)) + complete(&cfg->iface_disable); + + } else if (wl_is_nonetwork(cfg, e)) { + printk("connect failed event=%d e->status %d e->reason %d \n", + event, (int)ntoh32(e->status), (int)ntoh32(e->reason)); + /* Clean up any pending scan request */ + if (cfg->scan_request) + wl_notify_escan_complete(cfg, ndev, true, true); + if (wl_get_drv_status(cfg, CONNECTING, ndev)) + wl_bss_connect_done(cfg, ndev, e, data, false); + } else { + WL_DBG(("%s nothing\n", __FUNCTION__)); + } + } + else { + WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev))); + } + return err; +} + +void wl_cfg80211_set_rmc_pid(int pid) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + if (pid > 0) + cfg->rmc_event_pid = pid; + WL_DBG(("set pid for rmc event : pid=%d\n", pid)); +} + +#ifdef WLAIBSS +void wl_cfg80211_set_txfail_pid(int pid) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + if (pid > 0) + cfg->aibss_txfail_pid = pid; + WL_DBG(("set pid for aibss fail event : pid=%d\n", pid)); +} + +static s32 +wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + u32 evt = ntoh32(e->event_type); + int ret = -1; + + if (cfg->aibss_txfail_pid != 0) { + ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL, + cfg->aibss_txfail_seq++, (void *)&e->addr, ETHER_ADDR_LEN); + } + + WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n", + evt, cfg->aibss_txfail_pid, ret, ETHERP_TO_MACF(&e->addr))); + return ret; +} +#endif /* WLAIBSS */ + +static s32 +wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + u32 evt = ntoh32(e->event_type); + u32 reason = ntoh32(e->reason); + int ret = -1; + + switch (reason) { + case WLC_E_REASON_RMC_AR_LOST: + case WLC_E_REASON_RMC_AR_NO_ACK: + if (cfg->rmc_event_pid != 0) { + ret = wl_netlink_send_msg(cfg->rmc_event_pid, + RMC_EVENT_LEADER_CHECK_FAIL, + cfg->rmc_event_seq++, NULL, 0); + } + break; + default: + break; + } + WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret)); + return ret; +} + +static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ +#if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT) + u32 datalen = be32_to_cpu(e->datalen); + struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + + if (datalen) { + wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data; + if (evt_data->version == RSSI_MONITOR_VERSION) { + dhd_rssi_monitor_evt_t monitor_data; + monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION; + monitor_data.cur_rssi = evt_data->cur_rssi; + memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN); + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_RSSI_MONITOR_EVENT, + &monitor_data, sizeof(monitor_data)); + } else { + WL_ERR(("Version mismatch %d, expected %d", evt_data->version, + RSSI_MONITOR_VERSION)); + } + } +#endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */ + return BCME_OK; +} + +static s32 +wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + bool act; + struct net_device *ndev = NULL; + s32 err = 0; + u32 event = be32_to_cpu(e->event_type); + u32 status = be32_to_cpu(e->status); + WL_DBG(("Enter \n")); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) { + wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false); + cfg->disable_roam_event = TRUE; + } + + if ((cfg->disable_roam_event) && (event == WLC_E_ROAM)) + return err; + + if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) { + if (wl_get_drv_status(cfg, CONNECTED, ndev)) + wl_bss_roaming_done(cfg, ndev, e, data); + else + wl_bss_connect_done(cfg, ndev, e, data, true); + act = true; + wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); + wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + } + return err; +} + +static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + wl_assoc_info_t assoc_info; + struct wl_connect_info *conn_info = wl_to_conn(cfg); + s32 err = 0; + + WL_DBG(("Enter \n")); + err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); + if (unlikely(err)) { + WL_ERR(("could not get assoc info (%d)\n", err)); + return err; + } + memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t)); + assoc_info.req_len = htod32(assoc_info.req_len); + assoc_info.resp_len = htod32(assoc_info.resp_len); + assoc_info.flags = htod32(assoc_info.flags); + if (conn_info->req_ie_len) { + conn_info->req_ie_len = 0; + bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); + } + if (conn_info->resp_ie_len) { + conn_info->resp_ie_len = 0; + bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); + } + if (assoc_info.req_len) { + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); + if (unlikely(err)) { + WL_ERR(("could not get assoc req (%d)\n", err)); + return err; + } + conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); + if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { + conn_info->req_ie_len -= ETHER_ADDR_LEN; + } + if (conn_info->req_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); + else { + WL_ERR(("IE size %d above max %d size \n", + conn_info->req_ie_len, MAX_REQ_LINE)); + return err; + } + } else { + conn_info->req_ie_len = 0; + } + if (assoc_info.resp_len) { + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); + if (unlikely(err)) { + WL_ERR(("could not get assoc resp (%d)\n", err)); + return err; + } + conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); + if (conn_info->resp_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); + else { + WL_ERR(("IE size %d above max %d size \n", + conn_info->resp_ie_len, MAX_REQ_LINE)); + return err; + } + } else { + conn_info->resp_ie_len = 0; + } + WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, + conn_info->resp_ie_len)); + + return err; +} + +static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, + size_t *join_params_size) +{ + chanspec_t chanspec = 0; + if (ch != 0) { + join_params->params.chanspec_num = 1; + join_params->params.chanspec_list[0] = ch; + + if (join_params->params.chanspec_list[0] <= 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 += WL_ASSOC_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(chanspec_t); + + join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + join_params->params.chanspec_list[0] |= chanspec; + join_params->params.chanspec_list[0] = + wl_chspec_host_to_driver(join_params->params.chanspec_list[0]); + + join_params->params.chanspec_num = + htod32(join_params->params.chanspec_num); + WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n", + join_params->params.chanspec_list[0], + join_params->params.chanspec_num)); + } +} + +static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam) +{ + struct cfg80211_bss *bss; + struct wl_bss_info *bi; + struct wlc_ssid *ssid; + struct bcm_tlv *tim; + s32 beacon_interval; + s32 dtim_period; + size_t ie_len; + u8 *ie; + u8 *curbssid; + s32 err = 0; + struct wiphy *wiphy; + u32 channel; + struct ieee80211_channel *cur_channel; + u32 freq, band; + char *buf; + + wiphy = bcmcfg_to_wiphy(cfg); + + ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID); + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + + mutex_lock(&cfg->usr_sync); + buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_ATOMIC); + if (!buf) { + WL_ERR(("buffer alloc failed.\n")); + return BCME_NOMEM; + } + + *(u32 *) buf = htod32(WL_EXTRA_BUF_MAX); + err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, + buf, WL_EXTRA_BUF_MAX); + if (unlikely(err)) { + WL_ERR(("Could not get bss info %d\n", err)); + goto update_bss_info_out; + } + bi = (struct wl_bss_info *)(buf + 4); + channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); + wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) + freq = ieee80211_channel_to_frequency(channel); +#else + band = (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + freq = ieee80211_channel_to_frequency(channel, band); +#endif + cur_channel = ieee80211_get_channel(wiphy, freq); + + bss = cfg80211_get_bss(wiphy, cur_channel, curbssid, + ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + + if (!bss) { + WL_DBG(("Could not find the AP\n")); + if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) { + WL_ERR(("Bssid doesn't match\n")); + err = -EIO; + goto update_bss_info_out; + } + err = wl_inform_single_bss(cfg, bi, roam); + if (unlikely(err)) + goto update_bss_info_out; + + ie = ((u8 *)bi) + bi->ie_offset; + ie_len = bi->ie_length; + beacon_interval = cpu_to_le16(bi->beacon_period); + } else { + WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); +#if defined(WL_CFG80211_P2P_DEV_IF) + ie = (u8 *)bss->ies->data; + ie_len = bss->ies->len; +#else + ie = bss->information_elements; + ie_len = bss->len_information_elements; +#endif /* WL_CFG80211_P2P_DEV_IF */ + beacon_interval = bss->beacon_interval; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + cfg80211_put_bss(wiphy, bss); +#else + cfg80211_put_bss(bss); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ + } + + tim = bcm_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. + */ + dtim_period = 0; + err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD, + &dtim_period, sizeof(dtim_period)); + if (unlikely(err)) { + WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); + goto update_bss_info_out; + } + } + + wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT); + wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); + +update_bss_info_out: + if (unlikely(err)) { + WL_ERR(("Failed with error %d\n", err)); + } + + kfree(buf); + mutex_unlock(&cfg->usr_sync); + return err; +} + +static s32 +wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + struct wl_connect_info *conn_info = wl_to_conn(cfg); + s32 err = 0; + u8 *curbssid; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct ieee80211_supported_band *band; + struct ieee80211_channel *notify_channel = NULL; + u32 *channel; + u32 freq; +#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */ + +#ifdef WLFBT + uint32 data_len = 0; + if (data) + data_len = ntoh32(e->datalen); +#endif /* WLFBT */ + + wl_get_assoc_ies(cfg, ndev); + wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + wl_update_bss_info(cfg, ndev, true); + wl_update_pmklist(ndev, cfg->pmk_list, err); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) + /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */ + channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN); + 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); +#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */ +#ifdef WLFBT + /* back up the given FBT key for the further supplicant request, + * currently not checking the FBT is enabled for current BSS in DHD, + * because the supplicant decides to take it or not. + */ + if (data && (data_len == FBT_KEYLEN)) { + memcpy(cfg->fbt_key, data, FBT_KEYLEN); + } +#endif /* WLFBT */ + printk("wl_bss_roaming_done succeeded to " MACDBG "\n", + MAC2STRDBG((u8*)(&e->addr))); + + cfg80211_roamed(ndev, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) + notify_channel, +#endif + curbssid, + conn_info->req_ie, conn_info->req_ie_len, + conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); + WL_DBG(("Report roaming result\n")); + + wl_set_drv_status(cfg, CONNECTED, ndev); + + return err; +} + +static s32 +wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data, bool completed) +{ + struct wl_connect_info *conn_info = wl_to_conn(cfg); + struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); +#if (defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)) || \ + defined(CUSTOM_SET_CPUCORE) + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif /* (ROAM_ENABLE && ROAM_AP_ENV_DETECTION) || CUSTOM_SET_CPUCORE */ + s32 err = 0; + u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + if (!sec) { + WL_ERR(("sec is NULL\n")); + return -ENODEV; + } + WL_DBG((" enter\n")); +#ifdef ESCAN_RESULT_PATCH + if (wl_get_drv_status(cfg, CONNECTED, ndev)) { + if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) { + WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n", + ntoh32(e->event_type), ntoh32(e->status))); + return err; + } + } + if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 && + memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) { + WL_DBG(("copy bssid\n")); + memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); + } + +#else + if (cfg->scan_request) { + wl_notify_escan_complete(cfg, ndev, true, true); + } +#endif /* ESCAN_RESULT_PATCH */ + if (wl_get_drv_status(cfg, CONNECTING, ndev)) { + wl_cfg80211_scan_abort(cfg); + wl_clr_drv_status(cfg, CONNECTING, ndev); + if (completed) { + wl_get_assoc_ies(cfg, ndev); + wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + wl_update_bss_info(cfg, ndev, false); + wl_update_pmklist(ndev, cfg->pmk_list, err); + wl_set_drv_status(cfg, CONNECTED, ndev); +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + if (dhd->roam_env_detection) + wldev_iovar_setint(ndev, "roam_env_detection", + AP_ENV_INDETERMINATE); +#endif /* ROAM_AP_ENV_DETECTION */ + if (ndev != bcmcfg_to_prmry_ndev(cfg)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + init_completion(&cfg->iface_disable); +#else + /* reinitialize completion to clear previous count */ + INIT_COMPLETION(cfg->iface_disable); +#endif + } +#ifdef CUSTOM_SET_CPUCORE + if (wl_get_chan_isvht80(ndev, dhd)) { + if (ndev == bcmcfg_to_prmry_ndev(cfg)) + dhd->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */ + else if (ndev == wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) + dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */ + dhd_set_cpucore(dhd, TRUE); + } +#endif /* CUSTOM_SET_CPUCORE */ + + } + cfg80211_connect_result(ndev, + curbssid, + conn_info->req_ie, + conn_info->req_ie_len, + conn_info->resp_ie, + conn_info->resp_ie_len, + completed ? WLAN_STATUS_SUCCESS : + (sec->auth_assoc_res_status) ? + sec->auth_assoc_res_status : + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + if (completed) + WL_INFORM(("Report connect result - connection succeeded\n")); + else + WL_ERR(("Report connect result - connection failed\n")); + } +#ifdef CONFIG_TCPACK_FASTTX + if (wl_get_chan_isvht80(ndev, dhd)) + wldev_iovar_setint(ndev, "tcpack_fast_tx", 0); + else + wldev_iovar_setint(ndev, "tcpack_fast_tx", 1); +#endif /* CONFIG_TCPACK_FASTTX */ + + return err; +} + +static s32 +wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct net_device *ndev = NULL; + u16 flags = ntoh16(e->flags); + enum nl80211_key_type key_type; + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + mutex_lock(&cfg->usr_sync); + if (flags & WLC_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); + mutex_unlock(&cfg->usr_sync); + + return 0; +} + +#ifdef BT_WIFI_HANDOVER +static s32 +wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct net_device *ndev = NULL; + u32 event = ntoh32(e->event_type); + u32 datalen = ntoh32(e->datalen); + s32 err; + + WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen)); + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0); + + return err; +} +#endif /* BT_WIFI_HANDOVER */ + +#ifdef PNO_SUPPORT +static s32 +wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct net_device *ndev = NULL; +#ifdef GSCAN_SUPPORT + void *ptr; + int send_evt_bytes = 0; + u32 event = be32_to_cpu(e->event_type); + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); +#endif /* GSCAN_SUPPORT */ + + WL_ERR((">>> PNO Event\n")); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + +#ifdef GSCAN_SUPPORT + ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes); + if (ptr) { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes); + kfree(ptr); + } + if (!dhd_dev_is_legacy_pno_enabled(ndev)) + return 0; +#endif /* GSCAN_SUPPORT */ + +#ifndef WL_SCHED_SCAN + mutex_lock(&cfg->usr_sync); + /* TODO: Use cfg80211_sched_scan_results(wiphy); */ + cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + mutex_unlock(&cfg->usr_sync); +#else + /* If cfg80211 scheduled scan is supported, report the pno results via sched + * scan results + */ + wl_notify_sched_scan_results(cfg, ndev, e, data); +#endif /* WL_SCHED_SCAN */ + return 0; +} +#endif /* PNO_SUPPORT */ + +#ifdef GSCAN_SUPPORT +static s32 +wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + u32 event = be32_to_cpu(e->event_type); + void *ptr; + int send_evt_bytes = 0; + int batch_event_result_dummy = 0; + struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + u32 len = ntoh32(e->datalen); + + switch (event) { + case WLC_E_PFN_SWC: + ptr = dhd_dev_swc_scan_event(ndev, data, &send_evt_bytes); + if (send_evt_bytes) { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_GSCAN_SIGNIFICANT_EVENT, ptr, send_evt_bytes); + kfree(ptr); + } + break; + case WLC_E_PFN_BEST_BATCHING: + err = dhd_dev_retrieve_batch_scan(ndev); + if (err < 0) { + WL_ERR(("Batch retrieval already in progress %d\n", err)); + } else { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_GSCAN_BATCH_SCAN_EVENT, + &batch_event_result_dummy, sizeof(int)); + } + break; + case WLC_E_PFN_SCAN_COMPLETE: + batch_event_result_dummy = WIFI_SCAN_COMPLETE; + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_SCAN_COMPLETE_EVENT, + &batch_event_result_dummy, sizeof(int)); + break; + case WLC_E_PFN_BSSID_NET_FOUND: + ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes, + HOTLIST_FOUND); + if (ptr) { + wl_cfgvendor_send_hotlist_event(wiphy, ndev, + ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT); + dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_FOUND); + } else { + err = -ENOMEM; + } + break; + case WLC_E_PFN_BSSID_NET_LOST: + /* WLC_E_PFN_BSSID_NET_LOST is conflict shared with WLC_E_PFN_SCAN_ALLGONE + * We currently do not use WLC_E_PFN_SCAN_ALLGONE, so if we get it, ignore + */ + if (len) { + ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes, + HOTLIST_LOST); + if (ptr) { + wl_cfgvendor_send_hotlist_event(wiphy, ndev, + ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT); + dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_LOST); + } else { + err = -ENOMEM; + } + } else { + err = -EINVAL; + } + break; + case WLC_E_PFN_GSCAN_FULL_RESULT: + ptr = dhd_dev_process_full_gscan_result(ndev, data, &send_evt_bytes); + if (ptr) { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes); + kfree(ptr); + } else { + err = -ENOMEM; + } + break; + case WLC_E_PFN_SSID_EXT: + ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes); + if (ptr) { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes); + kfree(ptr); + } else { + err = -ENOMEM; + } + break; + default: + WL_ERR(("Unknown event %d\n", event)); + break; + } + return err; +} +#endif /* GSCAN_SUPPORT */ + +static s32 +wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct channel_info channel_inform; + struct wl_scan_results *bss_list; + struct net_device *ndev = NULL; + u32 len = WL_SCAN_BUF_MAX; + s32 err = 0; + unsigned long flags; + + WL_DBG(("Enter \n")); + if (!wl_get_drv_status(cfg, SCANNING, ndev)) { + WL_ERR(("scan is not ready \n")); + return err; + } + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + mutex_lock(&cfg->usr_sync); + wl_clr_drv_status(cfg, SCANNING, ndev); + memset(&channel_inform, 0, sizeof(channel_inform)); + err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &channel_inform, + sizeof(channel_inform)); + if (unlikely(err)) { + WL_ERR(("scan busy (%d)\n", err)); + goto scan_done_out; + } + channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); + if (unlikely(channel_inform.scan_channel)) { + + WL_DBG(("channel_inform.scan_channel (%d)\n", + channel_inform.scan_channel)); + } + cfg->bss_list = cfg->scan_results; + bss_list = cfg->bss_list; + memset(bss_list, 0, len); + bss_list->buflen = htod32(len); + err = wldev_ioctl_get(ndev, WLC_SCAN_RESULTS, bss_list, len); + if (unlikely(err) && unlikely(!cfg->scan_suppressed)) { + WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); + err = -EINVAL; + goto scan_done_out; + } + bss_list->buflen = dtoh32(bss_list->buflen); + bss_list->version = dtoh32(bss_list->version); + bss_list->count = dtoh32(bss_list->count); + + err = wl_inform_bss(cfg); + +scan_done_out: + del_timer_sync(&cfg->scan_timeout); + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + if (cfg->scan_request) { + cfg80211_scan_done(cfg->scan_request, false); + cfg->scan_request = NULL; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + WL_DBG(("cfg80211_scan_done\n")); + mutex_unlock(&cfg->usr_sync); + return err; +} + +static s32 +wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, + const struct ether_addr *sa, const struct ether_addr *bssid, + u8 **pheader, u32 *body_len, u8 *pbody) +{ + struct dot11_management_header *hdr; + u32 totlen = 0; + s32 err = 0; + u8 *offset; + u32 prebody_len = *body_len; + switch (fc) { + case FC_ASSOC_REQ: + /* capability , listen interval */ + totlen = DOT11_ASSOC_REQ_FIXED_LEN; + *body_len += DOT11_ASSOC_REQ_FIXED_LEN; + break; + + case FC_REASSOC_REQ: + /* capability, listen inteval, ap address */ + totlen = DOT11_REASSOC_REQ_FIXED_LEN; + *body_len += DOT11_REASSOC_REQ_FIXED_LEN; + break; + } + totlen += DOT11_MGMT_HDR_LEN + prebody_len; + *pheader = kzalloc(totlen, GFP_KERNEL); + if (*pheader == NULL) { + WL_ERR(("memory alloc failed \n")); + return -ENOMEM; + } + hdr = (struct dot11_management_header *) (*pheader); + hdr->fc = htol16(fc); + hdr->durid = 0; + hdr->seq = 0; + offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len); + bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN); + bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN); + bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN); + if ((pbody != NULL) && prebody_len) + bcopy((const char*)pbody, offset, prebody_len); + *body_len = totlen; + return err; +} + + +void +wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + if (timer_pending(&cfg->p2p->listen_timer)) { + del_timer_sync(&cfg->p2p->listen_timer); + } + if (cfg->afx_hdl != NULL) { + if (cfg->afx_hdl->dev != NULL) { + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev); + } + cfg->afx_hdl->peer_chan = WL_INVALID; + } + complete(&cfg->act_frm_scan); + WL_DBG(("*** Wake UP ** Working afx searching is cleared\n")); + } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) { + if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) || + wl_get_p2p_status(cfg, ACTION_TX_NOACK))) + wl_set_p2p_status(cfg, ACTION_TX_COMPLETED); + + WL_DBG(("*** Wake UP ** abort actframe iovar\n")); + /* if channel is not zero, "actfame" uses off channel scan. + * So abort scan for off channel completion. + */ + if (cfg->af_sent_channel) + wl_cfg80211_scan_abort(cfg); + } +#ifdef WL_CFG80211_SYNC_GON + else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { + WL_DBG(("*** Wake UP ** abort listen for next af frame\n")); + /* So abort scan to cancel listen */ + wl_cfg80211_scan_abort(cfg); + } +#endif /* WL_CFG80211_SYNC_GON */ +} + + +int wl_cfg80211_get_ioctl_version(void) +{ + return ioctl_version; +} + +static s32 +wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct ieee80211_supported_band *band; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct ether_addr da; + struct ether_addr bssid; + bool isfree = false; + s32 err = 0; + s32 freq; + struct net_device *ndev = NULL; + wifi_p2p_pub_act_frame_t *act_frm = NULL; + wifi_p2p_action_frame_t *p2p_act_frm = NULL; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; + wl_event_rx_frame_data_t *rxframe = + (wl_event_rx_frame_data_t*)data; + u32 event = ntoh32(e->event_type); + u8 *mgmt_frame; + u8 bsscfgidx = e->bsscfgidx; + u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); + u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); + bool retval; + + memset(&bssid, 0, ETHER_ADDR_LEN); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (!band) { + WL_ERR(("No valid band")); + return -EINVAL; + } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) + freq = ieee80211_channel_to_frequency(channel); + (void)band->band; +#else + freq = ieee80211_channel_to_frequency(channel, band->band); +#endif + if (event == WLC_E_ACTION_FRAME_RX) { + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); + + err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); + if (err < 0) + WL_ERR(("WLC_GET_BSSID error %d\n", err)); + memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); + err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, + &mgmt_frame, &mgmt_frame_len, + (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); + if (err < 0) { + WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n", + mgmt_frame_len, channel, freq)); + goto exit; + } + isfree = true; + if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + act_frm = (wifi_p2p_pub_act_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + p2p_act_frm = (wifi_p2p_action_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + (void) p2p_act_frm; + } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) { + if (cfg->next_af_subtype == sd_act_frm->action) { + WL_DBG(("We got a right next frame of SD!(%d)\n", + sd_act_frm->action)); + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); + + /* Stop waiting for next AF. */ + wl_stop_wait_next_action_frame(cfg, ndev); + } + } + (void) sd_act_frm; +#ifdef WLTDLS + } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) { + WL_DBG((" TDLS Action Frame Received type = %d \n", + mgmt_frame[DOT11_MGMT_HDR_LEN + 1])); + + if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) { + cfg->tdls_mgmt_frame = mgmt_frame; + cfg->tdls_mgmt_frame_len = mgmt_frame_len; + cfg->tdls_mgmt_freq = freq; + return 0; + } + + } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_VENDOR_SPECIFIC) { + WL_DBG((" TDLS Vendor Specific Received type \n")); +#endif + } else { + + if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { + u8 action = 0; + if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) { + WL_DBG(("Recived action is not public action frame\n")); + } else if (cfg->next_af_subtype == action) { + WL_DBG(("Recived action is the waiting action(%d)\n", + action)); + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); + + /* Stop waiting for next AF. */ + wl_stop_wait_next_action_frame(cfg, ndev); + } + } + } + + if (act_frm) { + + if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) { + if (cfg->next_af_subtype == act_frm->subtype) { + WL_DBG(("We got a right next frame!(%d)\n", + act_frm->subtype)); + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); + + if (cfg->next_af_subtype == P2P_PAF_GON_CONF) { + OSL_SLEEP(20); + } + + /* Stop waiting for next AF. */ + wl_stop_wait_next_action_frame(cfg, ndev); + } + } + } + + wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel); + /* + * After complete GO Negotiation, roll back to mpc mode + */ + if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || + (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { + wldev_iovar_setint(ndev, "mpc", 1); + } + if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + } + } else if (event == WLC_E_PROBREQ_MSG) { + + /* Handle probe reqs frame + * WPS-AP certification 4.2.13 + */ + struct parsed_ies prbreq_ies; + u32 prbreq_ie_len = 0; + bool pbc = 0; + + WL_DBG((" Event WLC_E_PROBREQ_MSG received\n")); + mgmt_frame = (u8 *)(data); + mgmt_frame_len = ntoh32(e->datalen); + + prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN; + + /* Parse prob_req IEs */ + if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN], + prbreq_ie_len, &prbreq_ies) < 0) { + WL_ERR(("Prob req get IEs failed\n")); + return 0; + } + if (prbreq_ies.wps_ie != NULL) { + wl_validate_wps_ie((char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc); + WL_DBG((" wps_ie exist pbc = %d\n", pbc)); + /* if pbc method, send prob_req mgmt frame to upper layer */ + if (!pbc) + return 0; + } else + return 0; + } else { + mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); + + /* wpa supplicant use probe request event for restarting another GON Req. + * but it makes GON Req repetition. + * so if src addr of prb req is same as my target device, + * do not send probe request event during sending action frame. + */ + if (event == WLC_E_P2P_PROBREQ_MSG) { + WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ? + "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG")); + + + /* Filter any P2P probe reqs arriving during the + * GO-NEG Phase + */ + if (cfg->p2p && + wl_get_p2p_status(cfg, GO_NEG_PHASE)) { + WL_DBG(("Filtering P2P probe_req while " + "being in GO-Neg state\n")); + return 0; + } + } + } + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + retval = cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ + defined(WL_COMPAT_WIRELESS) + retval = cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); +#else + retval = cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); +#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ + + WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d) retval (%d)\n", + mgmt_frame_len, ntoh32(e->datalen), channel, freq, retval)); +exit: + if (isfree) + kfree(mgmt_frame); + return 0; +} + +#ifdef WL_SCHED_SCAN +/* If target scan is not reliable, set the below define to "1" to do a + * full escan + */ +#define FULL_ESCAN_ON_PFN_NET_FOUND 0 +static s32 +wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + wl_pfn_net_info_t *netinfo, *pnetinfo; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + int err = 0; + struct cfg80211_scan_request *request = NULL; + struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; + struct ieee80211_channel *channel = NULL; + int channel_req = 0; + int band = 0; + struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; + int n_pfn_results = pfn_result->count; + + WL_DBG(("Enter\n")); + + if ((e->event_type == WLC_E_PFN_NET_LOST) || !data) { + WL_PNO(("Do Nothing %d\n", e->event_type)); + return 0; + } + if (pfn_result->version != PFN_SCANRESULT_VERSION) { + WL_ERR(("Incorrect version %d, expected %d\n", pfn_result->version, + PFN_SCANRESULT_VERSION)); + return 0; + } + WL_PNO((">>> PFN NET FOUND event. count:%d \n", n_pfn_results)); + if (n_pfn_results > 0) { + int i; + + if (n_pfn_results > MAX_PFN_LIST_COUNT) + n_pfn_results = MAX_PFN_LIST_COUNT; + pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) + - sizeof(wl_pfn_net_info_t)); + + memset(&ssid, 0x00, sizeof(ssid)); + + request = kzalloc(sizeof(*request) + + sizeof(*request->channels) * n_pfn_results, + GFP_KERNEL); + channel = (struct ieee80211_channel *)kzalloc( + (sizeof(struct ieee80211_channel) * n_pfn_results), + GFP_KERNEL); + if (!request || !channel) { + WL_ERR(("No memory")); + err = -ENOMEM; + goto out_err; + } + + request->wiphy = wiphy; + + for (i = 0; i < n_pfn_results; i++) { + netinfo = &pnetinfo[i]; + if (!netinfo) { + WL_ERR(("Invalid netinfo ptr. index:%d", i)); + err = -EINVAL; + goto out_err; + } + WL_PNO((">>> SSID:%s Channel:%d \n", + netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel)); + /* PFN result doesn't have all the info which are required by the supplicant + * (For e.g IEs) Do a target Escan so that sched scan results are reported + * via wl_inform_single_bss in the required format. Escan does require the + * scan request in the form of cfg80211_scan_request. For timebeing, create + * cfg80211_scan_request one out of the received PNO event. + */ + ssid[i].ssid_len = MIN(netinfo->pfnsubnet.SSID_len, DOT11_MAX_SSID_LEN); + memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, ssid[i].ssid_len); + request->n_ssids++; + + channel_req = netinfo->pfnsubnet.channel; + band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ + : NL80211_BAND_5GHZ; + channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); + channel[i].band = band; + channel[i].flags |= IEEE80211_CHAN_NO_HT40; + request->channels[i] = &channel[i]; + request->n_channels++; + } + + /* assign parsed ssid array */ + if (request->n_ssids) + request->ssids = &ssid[0]; + + if (wl_get_drv_status_all(cfg, SCANNING)) { + /* Abort any on-going scan */ + wl_notify_escan_complete(cfg, ndev, true, true); + } + + if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { + WL_PNO((">>> P2P discovery was ON. Disabling it\n")); + err = wl_cfgp2p_discover_enable_search(cfg, false); + if (unlikely(err)) { + wl_clr_drv_status(cfg, SCANNING, ndev); + goto out_err; + } + p2p_scan(cfg) = false; + } + + wl_set_drv_status(cfg, SCANNING, ndev); +#if FULL_ESCAN_ON_PFN_NET_FOUND + WL_PNO((">>> Doing Full ESCAN on PNO event\n")); + err = wl_do_escan(cfg, wiphy, ndev, NULL); +#else + WL_PNO((">>> Doing targeted ESCAN on PNO event\n")); + err = wl_do_escan(cfg, wiphy, ndev, request); +#endif + if (err) { + wl_clr_drv_status(cfg, SCANNING, ndev); + goto out_err; + } + cfg->sched_scan_running = TRUE; + } + else { + WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); + } +out_err: + if (request) + kfree(request); + if (channel) + kfree(channel); + return err; +} +#endif /* WL_SCHED_SCAN */ + +static void wl_init_conf(struct wl_conf *conf) +{ + WL_DBG(("Enter \n")); + 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 wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + unsigned long flags; + struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); + + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + memset(profile, 0, sizeof(struct wl_profile)); + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); +} + +static void wl_init_event_handler(struct bcm_cfg80211 *cfg) +{ + memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler)); + + cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; + cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; + cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; + cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; + cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; + cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; + cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; + cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; + cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; + cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_START] = wl_notify_connect_status; +#ifdef PNO_SUPPORT + cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; +#endif /* PNO_SUPPORT */ +#ifdef GSCAN_SUPPORT + cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event; +#endif /* GSCAN_SUPPORT */ + cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event; +#ifdef WLTDLS + cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler; +#endif /* WLTDLS */ + cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status; +#ifdef WLAIBSS + cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail; +#endif /* WLAIBSS */ +#ifdef BT_WIFI_HANDOVER + cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req; +#endif + cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status; + cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind; +} + +#if defined(STATIC_WL_PRIV_STRUCT) +static void +wl_init_escan_result_buf(struct bcm_cfg80211 *cfg) +{ + cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub, + DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE); + bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE); +} + +static void +wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg) +{ + cfg->escan_info.escan_buf = NULL; + +} +#endif /* STATIC_WL_PRIV_STRUCT */ + +static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg) +{ + WL_DBG(("Enter \n")); + cfg->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); + if (unlikely(!cfg->scan_results)) { + WL_ERR(("Scan results alloc failed\n")); + goto init_priv_mem_out; + } + cfg->conf = (void *)kzalloc(sizeof(*cfg->conf), GFP_KERNEL); + if (unlikely(!cfg->conf)) { + WL_ERR(("wl_conf alloc failed\n")); + goto init_priv_mem_out; + } + cfg->scan_req_int = + (void *)kzalloc(sizeof(*cfg->scan_req_int), GFP_KERNEL); + if (unlikely(!cfg->scan_req_int)) { + WL_ERR(("Scan req alloc failed\n")); + goto init_priv_mem_out; + } + cfg->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); + if (unlikely(!cfg->ioctl_buf)) { + WL_ERR(("Ioctl buf alloc failed\n")); + goto init_priv_mem_out; + } + cfg->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); + if (unlikely(!cfg->escan_ioctl_buf)) { + WL_ERR(("Ioctl buf alloc failed\n")); + goto init_priv_mem_out; + } + cfg->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (unlikely(!cfg->extra_buf)) { + WL_ERR(("Extra buf alloc failed\n")); + goto init_priv_mem_out; + } + cfg->pmk_list = (void *)kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL); + if (unlikely(!cfg->pmk_list)) { + WL_ERR(("pmk list alloc failed\n")); + goto init_priv_mem_out; + } + cfg->sta_info = (void *)kzalloc(sizeof(*cfg->sta_info), GFP_KERNEL); + if (unlikely(!cfg->sta_info)) { + WL_ERR(("sta info alloc failed\n")); + goto init_priv_mem_out; + } + +#if defined(STATIC_WL_PRIV_STRUCT) + cfg->conn_info = (void *)kzalloc(sizeof(*cfg->conn_info), GFP_KERNEL); + if (unlikely(!cfg->conn_info)) { + WL_ERR(("cfg->conn_info alloc failed\n")); + goto init_priv_mem_out; + } + cfg->ie = (void *)kzalloc(sizeof(*cfg->ie), GFP_KERNEL); + if (unlikely(!cfg->ie)) { + WL_ERR(("cfg->ie alloc failed\n")); + goto init_priv_mem_out; + } + wl_init_escan_result_buf(cfg); +#endif /* STATIC_WL_PRIV_STRUCT */ + cfg->afx_hdl = (void *)kzalloc(sizeof(*cfg->afx_hdl), GFP_KERNEL); + if (unlikely(!cfg->afx_hdl)) { + WL_ERR(("afx hdl alloc failed\n")); + goto init_priv_mem_out; + } else { + init_completion(&cfg->act_frm_scan); + init_completion(&cfg->wait_next_af); + + INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler); + } + return 0; + +init_priv_mem_out: + wl_deinit_priv_mem(cfg); + + return -ENOMEM; +} + +static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg) +{ + kfree(cfg->scan_results); + cfg->scan_results = NULL; + kfree(cfg->conf); + cfg->conf = NULL; + kfree(cfg->scan_req_int); + cfg->scan_req_int = NULL; + kfree(cfg->ioctl_buf); + cfg->ioctl_buf = NULL; + kfree(cfg->escan_ioctl_buf); + cfg->escan_ioctl_buf = NULL; + kfree(cfg->extra_buf); + cfg->extra_buf = NULL; + kfree(cfg->pmk_list); + cfg->pmk_list = NULL; + kfree(cfg->sta_info); + cfg->sta_info = NULL; +#if defined(STATIC_WL_PRIV_STRUCT) + kfree(cfg->conn_info); + cfg->conn_info = NULL; + kfree(cfg->ie); + cfg->ie = NULL; + wl_deinit_escan_result_buf(cfg); +#endif /* STATIC_WL_PRIV_STRUCT */ + if (cfg->afx_hdl) { + cancel_work_sync(&cfg->afx_hdl->work); + kfree(cfg->afx_hdl); + cfg->afx_hdl = NULL; + } + + if (cfg->ap_info) { + kfree(cfg->ap_info->wpa_ie); + kfree(cfg->ap_info->rsn_ie); + kfree(cfg->ap_info->wps_ie); + kfree(cfg->ap_info); + cfg->ap_info = NULL; + } +#ifdef WLTDLS + if (cfg->tdls_mgmt_frame) { + kfree(cfg->tdls_mgmt_frame); + cfg->tdls_mgmt_frame = NULL; + } +#endif /* WLTDLS */ +} + +static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg) +{ + int ret = 0; + WL_DBG(("Enter \n")); + + /* Do not use DHD in cfg driver */ + cfg->event_tsk.thr_pid = -1; + + PROC_START(wl_event_handler, cfg, &cfg->event_tsk, 0, "wl_event_handler"); + if (cfg->event_tsk.thr_pid < 0) + ret = -ENOMEM; + return ret; +} + +static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg) +{ + if (cfg->event_tsk.thr_pid >= 0) + PROC_STOP(&cfg->event_tsk); +} + +void wl_reinit_event_handler(void) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (cfg) { + wl_flush_eq(cfg); + } +} + +static void wl_scan_timeout(unsigned long data) +{ + wl_event_msg_t msg; + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; + + if (!(cfg->scan_request)) { + WL_ERR(("timer expired but no scan request\n")); + return; + } + bzero(&msg, sizeof(wl_event_msg_t)); + WL_ERR(("timer expired\n")); + msg.event_type = hton32(WLC_E_ESCAN_RESULT); + msg.status = hton32(WLC_E_STATUS_TIMEOUT); + msg.reason = 0xFFFFFFFF; + wl_cfg80211_event(bcmcfg_to_prmry_ndev(cfg), &msg, NULL); +} + +static s32 +wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, + unsigned long state, + void *ndev) +{ + struct net_device *dev = ndev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + WL_DBG(("Enter \n")); + + if (!wdev || !cfg || dev == bcmcfg_to_prmry_ndev(cfg)) + return NOTIFY_DONE; + + switch (state) { + case NETDEV_DOWN: + { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) + int max_wait_timeout = 2; + int max_wait_count = 100; + int refcnt = 0; + unsigned long limit = jiffies + max_wait_timeout * HZ; + while (work_pending(&wdev->cleanup_work)) { + if (refcnt%5 == 0) { + WL_ERR(("[NETDEV_DOWN] wait for " + "complete of cleanup_work" + " (%d th)\n", refcnt)); + } + if (!time_before(jiffies, limit)) { + WL_ERR(("[NETDEV_DOWN] cleanup_work" + " of CFG80211 is not" + " completed in %d sec\n", + max_wait_timeout)); + break; + } + if (refcnt >= max_wait_count) { + WL_ERR(("[NETDEV_DOWN] cleanup_work" + " of CFG80211 is not" + " completed in %d loop\n", + max_wait_count)); + break; + } + set_current_state(TASK_INTERRUPTIBLE); + (void)schedule_timeout(100); + set_current_state(TASK_RUNNING); + refcnt++; + } +#endif /* LINUX_VERSION < VERSION(3, 14, 0) */ + break; + } + + case NETDEV_UNREGISTER: + /* after calling list_del_rcu(&wdev->list) */ + wl_dealloc_netinfo(cfg, ndev); + break; + case NETDEV_GOING_DOWN: + /* At NETDEV_DOWN state, wdev_cleanup_work work will be called. + * In front of door, the function checks + * whether current scan is working or not. + * If the scanning is still working, wdev_cleanup_work call WARN_ON and + * make the scan done forcibly. + */ + if (wl_get_drv_status(cfg, SCANNING, dev)) + wl_notify_escan_complete(cfg, dev, true, true); + break; + } + return NOTIFY_DONE; +} +static struct notifier_block wl_cfg80211_netdev_notifier = { + .notifier_call = wl_cfg80211_netdev_notifier_call, +}; +/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be + * created in kernel notifier link list (with 'next' pointing to itself) + */ +static bool wl_cfg80211_netdev_notifier_registered = FALSE; + +static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg) +{ + wl_scan_params_t *params = NULL; + s32 params_size = 0; + s32 err = BCME_OK; + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + if (!in_atomic()) { + /* Our scan params only need space for 1 channel and 0 ssids */ + params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); + if (params == NULL) { + WL_ERR(("scan params allocation failed \n")); + err = -ENOMEM; + } else { + /* Do a scan abort to stop the driver's scan engine */ + err = wldev_ioctl_set(dev, WLC_SCAN, params, params_size); + if (err < 0) { + WL_ERR(("scan abort failed \n")); + } + kfree(params); + } + } +} + +#if defined(WL_ABORT_SCAN) +static void wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + if (cfg == NULL) { + WL_ERR(("Parsing parameter failed\n")); + return; + } + wl_cfg80211_scan_abort(cfg); +} +#endif /* WL_ABORT_SCAN */ + +static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, + struct net_device *ndev, + bool aborted, bool fw_abort) +{ + s32 err = BCME_OK; + unsigned long flags; + struct net_device *dev; + + WL_DBG(("Enter \n")); + if (!ndev) { + WL_ERR(("ndev is null\n")); + err = BCME_ERROR; + return err; + } + + if (cfg->escan_info.ndev != ndev) { + WL_ERR(("ndev is different %p %p\n", cfg->escan_info.ndev, ndev)); + err = BCME_ERROR; + return err; + } + + if (cfg->scan_request) { + dev = bcmcfg_to_prmry_ndev(cfg); +#if defined(WL_ENABLE_P2P_IF) + if (cfg->scan_request->dev != cfg->p2p_net) + dev = cfg->scan_request->dev; +#endif /* WL_ENABLE_P2P_IF */ + } + else { + WL_DBG(("cfg->scan_request is NULL may be internal scan." + "doing scan_abort for ndev %p primary %p", + ndev, bcmcfg_to_prmry_ndev(cfg))); + dev = ndev; + } + if (fw_abort && !in_atomic()) + wl_cfg80211_scan_abort(cfg); + if (timer_pending(&cfg->scan_timeout)) + del_timer_sync(&cfg->scan_timeout); +#if defined(ESCAN_RESULT_PATCH) + if (likely(cfg->scan_request)) { + cfg->bss_list = wl_escan_get_buf(cfg, aborted); + wl_inform_bss(cfg); + } +#endif /* ESCAN_RESULT_PATCH */ + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); +#ifdef WL_SCHED_SCAN + if (cfg->sched_scan_req && !cfg->scan_request) { + WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n")); + if (!aborted) + cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy); + cfg->sched_scan_running = FALSE; + cfg->sched_scan_req = NULL; + } +#endif /* WL_SCHED_SCAN */ + if (likely(cfg->scan_request)) { + cfg80211_scan_done(cfg->scan_request, aborted); + cfg->scan_request = NULL; + } + if (p2p_is_on(cfg)) + wl_clr_p2p_status(cfg, SCANNING); + wl_clr_drv_status(cfg, SCANNING, dev); + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + return err; +} + +#ifdef ESCAN_BUF_OVERFLOW_MGMT +static void +wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate) +{ + int idx; + for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) { + int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1; + if (bss->RSSI < candidate[idx].RSSI) { + if (len) + memcpy(&candidate[idx + 1], &candidate[idx], + sizeof(removal_element_t) * len); + candidate[idx].RSSI = bss->RSSI; + candidate[idx].length = bss->length; + memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN); + return; + } + } +} + +static void +wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate, + wl_bss_info_t *bi) +{ + int idx1, idx2; + int total_delete_len = 0; + for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) { + int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; + wl_bss_info_t *bss = NULL; + if (candidate[idx1].RSSI >= bi->RSSI) + continue; + for (idx2 = 0; idx2 < list->count; idx2++) { + bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) : + list->bss_info; + if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) && + candidate[idx1].RSSI == bss->RSSI && + candidate[idx1].length == dtoh32(bss->length)) { + u32 delete_len = dtoh32(bss->length); + WL_DBG(("delete scan info of " MACDBG " to add new AP\n", + MAC2STRDBG(bss->BSSID.octet))); + if (idx2 < list->count -1) { + memmove((u8 *)bss, (u8 *)bss + delete_len, + list->buflen - cur_len - delete_len); + } + list->buflen -= delete_len; + list->count--; + total_delete_len += delete_len; + /* if delete_len is greater than or equal to result length */ + if (total_delete_len >= bi->length) { + return; + } + break; + } + cur_len += dtoh32(bss->length); + } + } +} +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + +static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 err = BCME_OK; + s32 status = ntoh32(e->status); + wl_bss_info_t *bi; + wl_escan_result_t *escan_result; + wl_bss_info_t *bss = NULL; + wl_scan_results_t *list; + wifi_p2p_ie_t * p2p_ie; + struct net_device *ndev = NULL; + u32 bi_length; + u32 i; + u8 *p2p_dev_addr = NULL; + + WL_DBG((" enter event type : %d, status : %d \n", + ntoh32(e->event_type), ntoh32(e->status))); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + mutex_lock(&cfg->usr_sync); + /* P2P SCAN is coming from primary interface */ + if (wl_get_p2p_status(cfg, SCANNING)) { + if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) + ndev = cfg->afx_hdl->dev; + else + ndev = cfg->escan_info.ndev; + + } + if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) { + WL_ERR(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n", + ndev, wl_get_drv_status(cfg, SCANNING, ndev), + ntoh32(e->event_type), ntoh32(e->status))); + goto exit; + } + escan_result = (wl_escan_result_t *)data; + + if (status == WLC_E_STATUS_PARTIAL) { + WL_INFORM(("WLC_E_STATUS_PARTIAL \n")); + if (!escan_result) { + WL_ERR(("Invalid escan result (NULL pointer)\n")); + goto exit; + } + if (dtoh16(escan_result->bss_count) != 1) { + WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); + goto exit; + } + bi = escan_result->bss_info; + if (!bi) { + WL_ERR(("Invalid escan bss info (NULL pointer)\n")); + goto exit; + } + bi_length = dtoh32(bi->length); + if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { + WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); + goto exit; + } + if (wl_escan_check_sync_id(status, escan_result->sync_id, + cfg->escan_info.cur_sync_id) < 0) + goto exit; + + if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { + if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { + WL_DBG(("Ignoring IBSS result\n")); + goto exit; + } + } + + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); + if (p2p_dev_addr && !memcmp(p2p_dev_addr, + cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) { + s32 channel = wf_chspec_ctlchan( + wl_chspec_driver_to_host(bi->chanspec)); + + if ((channel > MAXCHANNEL) || (channel <= 0)) + channel = WL_INVALID; + else + WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found," + " channel : %d\n", + MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet), + channel)); + + wl_clr_p2p_status(cfg, SCANNING); + cfg->afx_hdl->peer_chan = channel; + complete(&cfg->act_frm_scan); + goto exit; + } + + } else { + int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; +#ifdef ESCAN_BUF_OVERFLOW_MGMT + removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT]; + int remove_lower_rssi = FALSE; + + bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT); +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + + list = wl_escan_get_buf(cfg, FALSE); + if (scan_req_match(cfg)) { +#ifdef WL_HOST_BAND_MGMT + s32 channel = 0; + s32 channel_band = 0; + chanspec_t chspec; +#endif /* WL_HOST_BAND_MGMT */ + /* p2p scan && allow only probe response */ + if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) && + (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) + goto exit; + if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, + bi->ie_length)) == NULL) { + WL_ERR(("Couldn't find P2PIE in probe" + " response/beacon\n")); + goto exit; + } +#ifdef WL_HOST_BAND_MGMT + chspec = wl_chspec_driver_to_host(bi->chanspec); + channel = wf_chspec_ctlchan(chspec); + channel_band = CHSPEC2WLC_BAND(chspec); + + if ((cfg->curr_band == WLC_BAND_5G) && + (channel_band == WLC_BAND_2G)) { + /* Avoid sending the GO results in band conflict */ + if (wl_cfgp2p_retreive_p2pattrib(p2p_ie, + P2P_SEID_GROUP_ID) != NULL) + goto exit; + } +#endif /* WL_HOST_BAND_MGMT */ + } +#ifdef ESCAN_BUF_OVERFLOW_MGMT + if (bi_length > ESCAN_BUF_SIZE - list->buflen) + remove_lower_rssi = TRUE; +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + + for (i = 0; i < list->count; i++) { + bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) + : list->bss_info; +#ifdef ESCAN_BUF_OVERFLOW_MGMT + WL_TRACE(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n", + bss->SSID, MAC2STRDBG(bss->BSSID.octet), + i, bss->RSSI, list->count)); + + if (remove_lower_rssi) + wl_cfg80211_find_removal_candidate(bss, candidate); +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + + if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && + (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec)) + == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) && + bi->SSID_len == bss->SSID_len && + !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { + + /* do not allow beacon data to update + *the data recd from a probe response + */ + if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) && + (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) + goto exit; + + WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d" + " flags 0x%x, new: RSSI %d flags 0x%x\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), i, + bss->RSSI, bss->flags, bi->RSSI, bi->flags)); + + if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == + (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) { + /* preserve max RSSI if the measurements are + * both on-channel or both off-channel + */ + WL_SCAN(("%s("MACDBG"), same onchan" + ", RSSI: prev %d new %d\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + bss->RSSI, bi->RSSI)); + bi->RSSI = MAX(bss->RSSI, bi->RSSI); + } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && + (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { + /* preserve the on-channel rssi measurement + * if the new measurement is off channel + */ + WL_SCAN(("%s("MACDBG"), prev onchan" + ", RSSI: prev %d new %d\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + bss->RSSI, bi->RSSI)); + bi->RSSI = bss->RSSI; + bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; + } + if (dtoh32(bss->length) != bi_length) { + u32 prev_len = dtoh32(bss->length); + + WL_SCAN(("bss info replacement" + " is occured(bcast:%d->probresp%d)\n", + bss->ie_length, bi->ie_length)); + WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + prev_len, bi_length)); + + if (list->buflen - prev_len + bi_length + > ESCAN_BUF_SIZE) { + WL_ERR(("Buffer is too small: keep the" + " previous result of this AP\n")); + /* Only update RSSI */ + bss->RSSI = bi->RSSI; + bss->flags |= (bi->flags + & WL_BSS_FLAGS_RSSI_ONCHANNEL); + goto exit; + } + + if (i < list->count - 1) { + /* memory copy required by this case only */ + memmove((u8 *)bss + bi_length, + (u8 *)bss + prev_len, + list->buflen - cur_len - prev_len); + } + list->buflen -= prev_len; + list->buflen += bi_length; + } + list->version = dtoh32(bi->version); + memcpy((u8 *)bss, (u8 *)bi, bi_length); + goto exit; + } + cur_len += dtoh32(bss->length); + } + if (bi_length > ESCAN_BUF_SIZE - list->buflen) { +#ifdef ESCAN_BUF_OVERFLOW_MGMT + wl_cfg80211_remove_lowRSSI_info(list, candidate, bi); + if (bi_length > ESCAN_BUF_SIZE - list->buflen) { + WL_DBG(("RSSI(" MACDBG ") is too low(%d) to add Buffer\n", + MAC2STRDBG(bi->BSSID.octet), bi->RSSI)); + goto exit; + } +#else + WL_ERR(("Buffer is too small: ignoring\n")); + goto exit; +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + } + + memcpy(&(((char *)list)[list->buflen]), bi, bi_length); + list->version = dtoh32(bi->version); + list->buflen += bi_length; + list->count++; + + /* + * !Broadcast && number of ssid = 1 && number of channels =1 + * means specific scan to association + */ + if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) { + WL_ERR(("P2P assoc scan fast aborted.\n")); + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false, true); + goto exit; + } + } + + } + else if (status == WLC_E_STATUS_SUCCESS) { + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id, + escan_result->sync_id); + + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + WL_INFORM(("ACTION FRAME SCAN DONE\n")); + wl_clr_p2p_status(cfg, SCANNING); + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + if (cfg->afx_hdl->peer_chan == WL_INVALID) + complete(&cfg->act_frm_scan); + } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { + WL_INFORM(("ESCAN COMPLETED\n")); + cfg->bss_list = wl_escan_get_buf(cfg, FALSE); + if (!scan_req_match(cfg)) { + WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n", + cfg->bss_list->count)); + } + wl_inform_bss(cfg); + wl_notify_escan_complete(cfg, ndev, false, false); + } + wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); + } +#ifdef GSCAN_SUPPORT + else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN)) { + if (status == WLC_E_STATUS_NEWSCAN) { + WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); + WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, + escan_result->bss_count)); + } +#else + else if (status == WLC_E_STATUS_ABORT) { +#endif /* GSCAN_SUPPORT */ + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_print_sync_id(status, escan_result->sync_id, + cfg->escan_info.cur_sync_id); + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + WL_INFORM(("ACTION FRAME SCAN DONE\n")); + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + wl_clr_p2p_status(cfg, SCANNING); + if (cfg->afx_hdl->peer_chan == WL_INVALID) + complete(&cfg->act_frm_scan); + } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { + WL_INFORM(("ESCAN ABORTED\n")); + cfg->bss_list = wl_escan_get_buf(cfg, TRUE); + if (!scan_req_match(cfg)) { + WL_TRACE_HW4(("SCAN ABORTED: scanned AP count=%d\n", + cfg->bss_list->count)); + } + wl_inform_bss(cfg); + wl_notify_escan_complete(cfg, ndev, true, false); + } + wl_escan_increment_sync_id(cfg, SCAN_BUF_CNT); + } else if (status == WLC_E_STATUS_NEWSCAN) { + WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); + WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, + escan_result->bss_count)); + } else if (status == WLC_E_STATUS_TIMEOUT) { + WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request)); + WL_ERR(("reason[0x%x]\n", e->reason)); + if (e->reason == 0xFFFFFFFF) { + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); + } + } else { + WL_ERR(("unexpected Escan Event %d : abort\n", status)); + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_print_sync_id(status, escan_result->sync_id, + cfg->escan_info.cur_sync_id); + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + WL_INFORM(("ACTION FRAME SCAN DONE\n")); + wl_clr_p2p_status(cfg, SCANNING); + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + if (cfg->afx_hdl->peer_chan == WL_INVALID) + complete(&cfg->act_frm_scan); + } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { + cfg->bss_list = wl_escan_get_buf(cfg, TRUE); + if (!scan_req_match(cfg)) { + WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): " + "scanned AP count=%d\n", + cfg->bss_list->count)); + } + wl_inform_bss(cfg); + wl_notify_escan_complete(cfg, ndev, true, false); + } + wl_escan_increment_sync_id(cfg, 2); + } +exit: + mutex_unlock(&cfg->usr_sync); + return err; +} + +static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable) +{ + u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED); + struct net_info *iter, *next; + int err; + + if (!cfg->roamoff_on_concurrent) + return; + if (enable && connected_cnt > 1) { + for_each_ndev(cfg, iter, next) { + /* Save the current roam setting */ + if ((err = wldev_iovar_getint(iter->ndev, "roam_off", + (s32 *)&iter->roam_off)) != BCME_OK) { + WL_ERR(("%s:Failed to get current roam setting err %d\n", + iter->ndev->name, err)); + continue; + } + if ((err = wldev_iovar_setint(iter->ndev, "roam_off", 1)) != BCME_OK) { + WL_ERR((" %s:failed to set roam_off : %d\n", + iter->ndev->name, err)); + } + } + } + else if (!enable) { + for_each_ndev(cfg, iter, next) { + if (iter->roam_off != WL_INVALID) { + if ((err = wldev_iovar_setint(iter->ndev, "roam_off", + iter->roam_off)) == BCME_OK) + iter->roam_off = WL_INVALID; + else { + WL_ERR((" %s:failed to set roam_off : %d\n", + iter->ndev->name, err)); + } + } + } + } + return; +} + +static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg) +{ + struct net_info *iter, *next; + u32 ctl_chan = 0; + u32 chanspec = 0; + u32 pre_ctl_chan = 0; + u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED); + cfg->vsdb_mode = false; + + if (connected_cnt <= 1) { + return; + } + for_each_ndev(cfg, iter, next) { + chanspec = 0; + ctl_chan = 0; + if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) { + if (wldev_iovar_getint(iter->ndev, "chanspec", + (s32 *)&chanspec) == BCME_OK) { + chanspec = wl_chspec_driver_to_host(chanspec); + ctl_chan = wf_chspec_ctlchan(chanspec); + wl_update_prof(cfg, iter->ndev, NULL, + &ctl_chan, WL_PROF_CHAN); + } + if (!cfg->vsdb_mode) { + if (!pre_ctl_chan && ctl_chan) + pre_ctl_chan = ctl_chan; + else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) { + cfg->vsdb_mode = true; + } + } + } + } + WL_ERR(("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel")); + return; +} + + +static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, + enum wl_status state, bool set) +{ + s32 pm = PM_FAST; + s32 err = BCME_OK; + u32 mode; + u32 chan = 0; + struct net_info *iter, *next; + struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); + WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n", + state, set, _net_info->pm_restore, _net_info->ndev->name)); + + if (state != WL_STATUS_CONNECTED) + return 0; + mode = wl_get_mode_by_netdev(cfg, _net_info->ndev); + if (set) { + wl_cfg80211_concurrent_roam(cfg, 1); + + if (mode == WL_MODE_AP) { + + if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false)) + WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); + } + wl_cfg80211_determine_vsdb_mode(cfg); + if (cfg->vsdb_mode || _net_info->pm_block) { + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_MAINTAIN); + /* save PM_FAST in _net_info to restore this + * if _net_info->pm_block is false + */ + if (!_net_info->pm_block && (mode == WL_MODE_BSS)) { + _net_info->pm = PM_FAST; + _net_info->pm_restore = true; + } + pm = PM_OFF; + for_each_ndev(cfg, iter, next) { + if (iter->pm_restore) + continue; + /* Save the current power mode */ + err = wldev_ioctl_get(iter->ndev, WLC_GET_PM, &iter->pm, + sizeof(iter->pm)); + WL_DBG(("%s:power save %s\n", iter->ndev->name, + iter->pm ? "enabled" : "disabled")); + if (!err && iter->pm) { + iter->pm_restore = true; + } + + } + for_each_ndev(cfg, iter, next) { + if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev)) + continue; + if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM, &pm, + sizeof(pm))) != 0) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); + wl_cfg80211_update_power_mode(iter->ndev); + } + } + } else { + /* add PM Enable timer to go to power save mode + * if supplicant control pm mode, it will be cleared or + * updated by wl_cfg80211_set_power_mgmt() if not - for static IP & HW4 P2P, + * PM will be configured when timer expired + */ + + /* + * before calling pm_enable_timer, we need to set PM -1 for all ndev + */ + pm = PM_OFF; + if (!_net_info->pm_block) { + for_each_ndev(cfg, iter, next) { + if (iter->pm_restore) + continue; + /* Save the current power mode */ + err = wldev_ioctl_get(iter->ndev, WLC_GET_PM, &iter->pm, + sizeof(iter->pm)); + WL_DBG(("%s:power save %s\n", iter->ndev->name, + iter->pm ? "enabled" : "disabled")); + if (!err && iter->pm) { + iter->pm_restore = true; + } + } + } + for_each_ndev(cfg, iter, next) { + if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev)) + continue; + if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM, &pm, + sizeof(pm))) != 0) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); + } + } + + if (cfg->pm_enable_work_on) { + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + } + + cfg->pm_enable_work_on = true; + wl_add_remove_pm_enable_work(cfg, TRUE, WL_HANDLER_NOTUSE); + } +#if defined(WLTDLS) +#if defined(DISABLE_TDLS_IN_P2P) + if (cfg->vsdb_mode || p2p_is_on(cfg)) +#else + if (cfg->vsdb_mode) +#endif /* defined(DISABLE_TDLS_IN_P2P) */ + { + + err = wldev_iovar_setint(primary_dev, "tdls_enable", 0); + } +#endif /* defined(WLTDLS) */ + + } + else { /* clear */ + chan = 0; + /* clear chan information when the net device is disconnected */ + wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); + wl_cfg80211_determine_vsdb_mode(cfg); + for_each_ndev(cfg, iter, next) { + if (iter->pm_restore && iter->pm) { + WL_DBG(("%s:restoring power save %s\n", + iter->ndev->name, (iter->pm ? "enabled" : "disabled"))); + err = wldev_ioctl_set(iter->ndev, + WLC_SET_PM, &iter->pm, sizeof(iter->pm)); + if (unlikely(err)) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error(%d)\n", iter->ndev->name, err)); + break; + } + iter->pm_restore = 0; + wl_cfg80211_update_power_mode(iter->ndev); + } + } + wl_cfg80211_concurrent_roam(cfg, 0); +#if defined(WLTDLS) + if (!cfg->vsdb_mode) { + err = wldev_iovar_setint(primary_dev, "tdls_enable", 1); + } +#endif /* defined(WLTDLS) */ + + + } + return err; +} +static s32 wl_init_scan(struct bcm_cfg80211 *cfg) +{ + int err = 0; + + cfg->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_init_sync_id(cfg); + + /* Init scan_timeout timer */ + init_timer(&cfg->scan_timeout); + cfg->scan_timeout.data = (unsigned long) cfg; + cfg->scan_timeout.function = wl_scan_timeout; + + return err; +} + +static s32 wl_init_priv(struct bcm_cfg80211 *cfg) +{ + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; + + cfg->scan_request = NULL; + cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); + cfg->roam_on = false; + cfg->active_scan = true; + cfg->rf_blocked = false; + cfg->vsdb_mode = false; +#if defined(BCMSDIO) + cfg->wlfc_on = false; +#endif + cfg->roamoff_on_concurrent = true; + cfg->disable_roam_event = false; + /* register interested state */ + set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state); + spin_lock_init(&cfg->cfgdrv_lock); + mutex_init(&cfg->ioctl_buf_sync); + init_waitqueue_head(&cfg->netif_change_event); + init_completion(&cfg->send_af_done); + init_completion(&cfg->iface_disable); + wl_init_eq(cfg); + err = wl_init_priv_mem(cfg); + if (err) + return err; + if (wl_create_event_handler(cfg)) + return -ENOMEM; + wl_init_event_handler(cfg); + mutex_init(&cfg->usr_sync); + mutex_init(&cfg->event_sync); + err = wl_init_scan(cfg); + if (err) + return err; + wl_init_conf(cfg->conf); + wl_init_prof(cfg, ndev); + wl_link_down(cfg); + DNGL_FUNC(dhd_cfg80211_init, (cfg)); + + return err; +} + +static void wl_deinit_priv(struct bcm_cfg80211 *cfg) +{ + DNGL_FUNC(dhd_cfg80211_deinit, (cfg)); + wl_destroy_event_handler(cfg); + wl_flush_eq(cfg); + wl_link_down(cfg); + del_timer_sync(&cfg->scan_timeout); + wl_deinit_priv_mem(cfg); + if (wl_cfg80211_netdev_notifier_registered) { + wl_cfg80211_netdev_notifier_registered = FALSE; + unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); + } +} + + +#if defined(WL_ENABLE_P2P_IF) +static s32 wl_cfg80211_attach_p2p(void) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + WL_TRACE(("Enter \n")); + + if (wl_cfgp2p_register_ndev(cfg) < 0) { + WL_ERR(("P2P attach failed. \n")); + return -ENODEV; + } + + + return 0; +} +#endif + +#if defined(WL_ENABLE_P2P_IF) +static s32 wl_cfg80211_detach_p2p(void) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wireless_dev *wdev; + + WL_DBG(("Enter \n")); + if (!cfg) { + WL_ERR(("Invalid Ptr\n")); + return -EINVAL; + } else + wdev = cfg->p2p_wdev; + + if (!wdev) { + WL_ERR(("Invalid Ptr\n")); + return -EINVAL; + } + + wl_cfgp2p_unregister_ndev(cfg); + + cfg->p2p_wdev = NULL; + cfg->p2p_net = NULL; + WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev)); + kfree(wdev); + + return 0; +} +#endif + +s32 wl_cfg80211_attach_post(struct net_device *ndev) +{ + struct bcm_cfg80211 * cfg = NULL; + s32 err = 0; + s32 ret = 0; + WL_TRACE(("In\n")); + if (unlikely(!ndev)) { + WL_ERR(("ndev is invaild\n")); + return -ENODEV; + } + cfg = g_bcm_cfg; + if (unlikely(!cfg)) { + WL_ERR(("cfg is invaild\n")); + return -EINVAL; + } + if (!wl_get_drv_status(cfg, READY, ndev)) { + if (cfg->wdev) { + ret = wl_cfgp2p_supported(cfg, ndev); + if (ret > 0) { +#if !defined(WL_ENABLE_P2P_IF) + cfg->wdev->wiphy->interface_modes |= + (BIT(NL80211_IFTYPE_P2P_CLIENT)| + BIT(NL80211_IFTYPE_P2P_GO)); +#endif /* !WL_ENABLE_P2P_IF */ + if ((err = wl_cfgp2p_init_priv(cfg)) != 0) + goto fail; + +#if defined(WL_ENABLE_P2P_IF) + if (cfg->p2p_net) { + /* Update MAC addr for p2p0 interface here. */ + memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); + cfg->p2p_net->dev_addr[0] |= 0x02; + WL_ERR(("%s: p2p_dev_addr="MACDBG "\n", + cfg->p2p_net->name, + MAC2STRDBG(cfg->p2p_net->dev_addr))); + } else { + WL_ERR(("p2p_net not yet populated." + " Couldn't update the MAC Address for p2p0 \n")); + return -ENODEV; + } +#endif /* WL_ENABLE_P2P_IF */ + cfg->p2p_supported = true; + } else if (ret == 0) { + if ((err = wl_cfgp2p_init_priv(cfg)) != 0) + goto fail; + } else { + /* SDIO bus timeout */ + err = -ENODEV; + goto fail; + } + } + } + wl_set_drv_status(cfg, READY, ndev); +fail: + return err; +} + +s32 wl_cfg80211_attach(struct net_device *ndev, void *context) +{ + struct wireless_dev *wdev; + struct bcm_cfg80211 *cfg; + s32 err = 0; + struct device *dev; + + WL_TRACE(("In\n")); + if (!ndev) { + WL_ERR(("ndev is invaild\n")); + return -ENODEV; + } + WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev())); + dev = wl_cfg80211_get_parent_dev(); + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return -ENOMEM; + } + err = wl_setup_wiphy(wdev, dev, context); + if (unlikely(err)) { + kfree(wdev); + return -ENOMEM; + } + wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); + cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy); + cfg->wdev = wdev; + cfg->pub = context; + INIT_LIST_HEAD(&cfg->net_list); + ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); + wdev->netdev = ndev; + cfg->state_notifier = wl_notifier_change_state; + err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE); + if (err) { + WL_ERR(("Failed to alloc net_info (%d)\n", err)); + goto cfg80211_attach_out; + } + err = wl_init_priv(cfg); + if (err) { + WL_ERR(("Failed to init iwm_priv (%d)\n", err)); + goto cfg80211_attach_out; + } + + err = wl_setup_rfkill(cfg, TRUE); + if (err) { + WL_ERR(("Failed to setup rfkill %d\n", err)); + goto cfg80211_attach_out; + } +#ifdef DEBUGFS_CFG80211 + err = wl_setup_debugfs(cfg); + if (err) { + WL_ERR(("Failed to setup debugfs %d\n", err)); + goto cfg80211_attach_out; + } +#endif + if (!wl_cfg80211_netdev_notifier_registered) { + wl_cfg80211_netdev_notifier_registered = TRUE; + err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); + if (err) { + wl_cfg80211_netdev_notifier_registered = FALSE; + WL_ERR(("Failed to register notifierl %d\n", err)); + goto cfg80211_attach_out; + } + } +#if defined(COEX_DHCP) + cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev); + if (!cfg->btcoex_info) + goto cfg80211_attach_out; +#endif + + g_bcm_cfg = cfg; + +#if defined(WL_ENABLE_P2P_IF) + err = wl_cfg80211_attach_p2p(); + if (err) + goto cfg80211_attach_out; +#endif + + return err; + +cfg80211_attach_out: + wl_setup_rfkill(cfg, FALSE); + wl_free_wdev(cfg); + return err; +} + +void wl_cfg80211_detach(void *para) +{ + struct bcm_cfg80211 *cfg; + + (void)para; + cfg = g_bcm_cfg; + + WL_TRACE(("In\n")); + + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + +#if defined(COEX_DHCP) + wl_cfg80211_btcoex_deinit(); + cfg->btcoex_info = NULL; +#endif + + wl_setup_rfkill(cfg, FALSE); +#ifdef DEBUGFS_CFG80211 + wl_free_debugfs(cfg); +#endif + if (cfg->p2p_supported) { + if (timer_pending(&cfg->p2p->listen_timer)) + del_timer_sync(&cfg->p2p->listen_timer); + wl_cfgp2p_deinit_priv(cfg); + } + + if (timer_pending(&cfg->scan_timeout)) + del_timer_sync(&cfg->scan_timeout); + +#if defined(WL_CFG80211_P2P_DEV_IF) + wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_ENABLE_P2P_IF) + wl_cfg80211_detach_p2p(); +#endif + + wl_cfg80211_ibss_vsie_free(cfg); + wl_deinit_priv(cfg); + g_bcm_cfg = NULL; + wl_cfg80211_clear_parent_dev(); + wl_free_wdev(cfg); + /* PLEASE do NOT call any function after wl_free_wdev, the driver's private + * structure "cfg", which is the private part of wiphy, has been freed in + * wl_free_wdev !!!!!!!!!!! + */ +} + +static void wl_wakeup_event(struct bcm_cfg80211 *cfg) +{ + if (cfg->event_tsk.thr_pid >= 0) { + up(&cfg->event_tsk.sema); + } +} + + +static s32 wl_event_handler(void *data) +{ + struct bcm_cfg80211 *cfg = NULL; + struct wl_event_q *e; + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + bcm_struct_cfgdev *cfgdev = NULL; + + cfg = (struct bcm_cfg80211 *)tsk->parent; + + WL_ERR(("tsk Enter, tsk = 0x%p\n", tsk)); + + while (down_interruptible (&tsk->sema) == 0) { + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } + while ((e = wl_deq_event(cfg))) { + WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx)); + /* All P2P device address related events comes on primary interface since + * there is no corresponding bsscfg for P2P interface. Map it to p2p0 + * interface. + */ +#if defined(WL_CFG80211_P2P_DEV_IF) + if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_wdev)) { + cfgdev = bcmcfg_to_p2p_wdev(cfg); + } else { + struct net_device *ndev = NULL; + + ndev = dhd_idx2net((struct dhd_pub *)(cfg->pub), e->emsg.ifidx); + if (ndev) + cfgdev = ndev_to_wdev(ndev); + } +#elif defined(WL_ENABLE_P2P_IF) + if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_net)) { + cfgdev = cfg->p2p_net; + } else { + cfgdev = dhd_idx2net((struct dhd_pub *)(cfg->pub), + e->emsg.ifidx); + } +#endif /* WL_CFG80211_P2P_DEV_IF */ + + if (!cfgdev) { +#if defined(WL_CFG80211_P2P_DEV_IF) + cfgdev = bcmcfg_to_prmry_wdev(cfg); +#elif defined(WL_ENABLE_P2P_IF) + cfgdev = bcmcfg_to_prmry_ndev(cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ + } + if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) { + dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub); + if (dhd->busstate == DHD_BUS_DOWN) { + WL_ERR((": BUS is DOWN.\n")); + } else + cfg->evt_handler[e->etype](cfg, cfgdev, &e->emsg, e->edata); + } else { + WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); + } + wl_put_event(e); + DHD_EVENT_WAKE_UNLOCK(cfg->pub); + } + } + WL_ERR(("was terminated\n")); + complete_and_exit(&tsk->completed, 0); + return 0; +} + +void +wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) +{ + u32 event_type = ntoh32(e->event_type); + struct bcm_cfg80211 *cfg = g_bcm_cfg; + +#if (WL_DBG_LEVEL > 0) + s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? + wl_dbg_estr[event_type] : (s8 *) "Unknown"; + WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); +#endif /* (WL_DBG_LEVEL > 0) */ + if (cfg->event_tsk.thr_pid == -1) { + WL_ERR(("Event handler is not created\n")); + return; + } + + if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) { + WL_ERR(("during IF change, ignore event %d\n", event_type)); + return; + } + + if (ndev != bcmcfg_to_prmry_ndev(cfg) && cfg->p2p_supported) { + if ((cfg->bss_cfgdev) && + (ndev == cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg))) { + /* Event is corresponding to the secondary STA interface */ + WL_DBG(("DualSta event (%d), proceed to enqueue it \n", event_type)); + } else if (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) && +#if defined(WL_ENABLE_P2P_IF) + (ndev != (cfg->p2p_net ? cfg->p2p_net : + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE))) && +#else + (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE)) && +#endif /* WL_ENABLE_P2P_IF */ + TRUE) { + WL_ERR(("ignore event %d, not interested\n", event_type)); + return; + } + } + + if (event_type == WLC_E_PFN_NET_FOUND) { + WL_DBG((" PNOEVENT: PNO_NET_FOUND\n")); + } + else if (event_type == WLC_E_PFN_NET_LOST) { + WL_DBG((" PNOEVENT: PNO_NET_LOST\n")); + } + + DHD_EVENT_WAKE_LOCK(cfg->pub); + if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) { + wl_wakeup_event(cfg); + } else { + DHD_EVENT_WAKE_UNLOCK(cfg->pub); + } +} + +static void wl_init_eq(struct bcm_cfg80211 *cfg) +{ + wl_init_eq_lock(cfg); + INIT_LIST_HEAD(&cfg->eq_list); +} + +static void wl_flush_eq(struct bcm_cfg80211 *cfg) +{ + struct wl_event_q *e; + unsigned long flags; + + flags = wl_lock_eq(cfg); + while (!list_empty(&cfg->eq_list)) { + e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list); + list_del(&e->eq_list); + kfree(e); + } + wl_unlock_eq(cfg, flags); +} + +/* +* retrieve first queued event from head +*/ + +static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg) +{ + struct wl_event_q *e = NULL; + unsigned long flags; + + flags = wl_lock_eq(cfg); + if (likely(!list_empty(&cfg->eq_list))) { + e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list); + list_del(&e->eq_list); + } + wl_unlock_eq(cfg, flags); + + return e; +} + +/* + * push event to tail of the queue + */ + +static s32 +wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event, + const wl_event_msg_t *msg, void *data) +{ + struct wl_event_q *e; + s32 err = 0; + uint32 evtq_size; + uint32 data_len; + unsigned long flags; + gfp_t aflags; + + data_len = 0; + if (data) + data_len = ntoh32(msg->datalen); + evtq_size = sizeof(struct wl_event_q) + data_len; + aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + e = kzalloc(evtq_size, aflags); + if (unlikely(!e)) { + WL_ERR(("event alloc failed\n")); + return -ENOMEM; + } + e->etype = event; + memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); + if (data) + memcpy(e->edata, data, data_len); + flags = wl_lock_eq(cfg); + list_add_tail(&e->eq_list, &cfg->eq_list); + wl_unlock_eq(cfg, flags); + + return err; +} + +static void wl_put_event(struct wl_event_q *e) +{ + kfree(e); +} + +static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype) +{ + s32 infra = 0; + s32 err = 0; + s32 mode = 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: + mode = WL_MODE_IBSS; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + mode = WL_MODE_BSS; + infra = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + mode = WL_MODE_AP; + infra = 1; + break; + default: + err = -EINVAL; + WL_ERR(("invalid type (%d)\n", iftype)); + return err; + } + infra = htod32(infra); + err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); + return err; + } + + wl_set_mode_by_netdev(cfg, ndev, mode); + + return 0; +} + +void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set) +{ + if (!ev || (event > WLC_E_LAST)) + return; + + if (ev->num < MAX_EVENT_BUF_NUM) { + ev->event[ev->num].type = event; + ev->event[ev->num].set = set; + ev->num++; + } else { + WL_ERR(("evenbuffer doesn't support > %u events. Update" + " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM)); + ASSERT(0); + } +} + +s32 wl_cfg80211_apply_eventbuffer( + struct net_device *ndev, + struct bcm_cfg80211 *cfg, + wl_eventmsg_buf_t *ev) +{ + char eventmask[WL_EVENTING_MASK_LEN]; + int i, ret = 0; + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + if (!ev || (!ev->num)) + return -EINVAL; + + mutex_lock(&cfg->event_sync); + + /* Read event_msgs mask */ + ret = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL); + if (unlikely(ret)) { + WL_ERR(("Get event_msgs error (%d)\n", ret)); + goto exit; + } + memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); + + /* apply the set bits */ + for (i = 0; i < ev->num; i++) { + if (ev->event[i].set) + setbit(eventmask, ev->event[i].type); + else + clrbit(eventmask, ev->event[i].type); + } + + /* Write updated Event mask */ + ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf, + sizeof(iovbuf), NULL); + if (unlikely(ret)) { + WL_ERR(("Set event_msgs error (%d)\n", ret)); + } + +exit: + mutex_unlock(&cfg->event_sync); + return ret; +} + +s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) +{ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + s8 eventmask[WL_EVENTING_MASK_LEN]; + s32 err = 0; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (!ndev || !cfg) + return -ENODEV; + + mutex_lock(&cfg->event_sync); + + /* Setup event_msgs */ + err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL); + if (unlikely(err)) { + WL_ERR(("Get event_msgs error (%d)\n", err)); + goto eventmsg_out; + } + memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); + if (add) { + setbit(eventmask, event); + } else { + clrbit(eventmask, event); + } + err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, + sizeof(iovbuf), NULL); + if (unlikely(err)) { + WL_ERR(("Set event_msgs error (%d)\n", err)); + goto eventmsg_out; + } + +eventmsg_out: + mutex_unlock(&cfg->event_sync); + return err; +} + +static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) +{ + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + struct ieee80211_channel *band_chan_arr = NULL; + wl_uint32_list_t *list; + u32 i, j, index, n_2g, n_5g, band, channel, array_size; + u32 *n_cnt = NULL; + chanspec_t c = 0; + s32 err = BCME_OK; + bool update; + bool ht40_allowed; + u8 *pbuf = NULL; + bool dfs_radar_disabled = FALSE; + +#define LOCAL_BUF_LEN 1024 + pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); + + if (pbuf == NULL) { + WL_ERR(("failed to allocate local buf\n")); + return -ENOMEM; + } + + err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, + 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync); + if (err != 0) { + WL_ERR(("get chanspecs failed with %d\n", err)); + kfree(pbuf); + return err; + } +#undef LOCAL_BUF_LEN + + list = (wl_uint32_list_t *)(void *)pbuf; + band = array_size = n_2g = n_5g = 0; + for (i = 0; i < dtoh32(list->count); i++) { + index = 0; + update = false; + ht40_allowed = false; + c = (chanspec_t)dtoh32(list->element[i]); + c = wl_chspec_driver_to_host(c); + channel = wf_chspec_ctlchan(c); + + if (!CHSPEC_IS40(c) && ! CHSPEC_IS20(c)) { + WL_DBG(("HT80/160/80p80 center channel : %d\n", channel)); + continue; + } + if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) && + (channel <= CH_MAX_2G_CHANNEL)) { + band_chan_arr = __wl_2ghz_channels; + array_size = ARRAYSIZE(__wl_2ghz_channels); + n_cnt = &n_2g; + band = IEEE80211_BAND_2GHZ; + ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; + } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) { + band_chan_arr = __wl_5ghz_a_channels; + array_size = ARRAYSIZE(__wl_5ghz_a_channels); + n_cnt = &n_5g; + band = IEEE80211_BAND_5GHZ; + ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; + } else { + WL_ERR(("Invalid channel Sepc. 0x%x.\n", c)); + continue; + } + if (!ht40_allowed && CHSPEC_IS40(c)) + continue; + for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { + if (band_chan_arr[j].hw_value == channel) { + update = true; + break; + } + } + if (update) + index = j; + else + index = *n_cnt; + if (index < array_size) { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) + band_chan_arr[index].center_freq = + ieee80211_channel_to_frequency(channel); +#else + band_chan_arr[index].center_freq = + ieee80211_channel_to_frequency(channel, band); +#endif + band_chan_arr[index].hw_value = channel; + band_chan_arr[index].beacon_found = false; + + if (CHSPEC_IS40(c) && ht40_allowed) { + /* assuming the order is HT20, HT40 Upper, + * HT40 lower from chanspecs + */ + u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; + if (CHSPEC_SB_UPPER(c)) { + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags &= + ~IEEE80211_CHAN_NO_HT40; + band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; + } else { + /* It should be one of + * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS + */ + band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags |= + IEEE80211_CHAN_NO_HT40MINUS; + } + } else { + band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; + if (!dfs_radar_disabled) { + if (band == IEEE80211_BAND_2GHZ) + channel |= WL_CHANSPEC_BAND_2G; + else + channel |= WL_CHANSPEC_BAND_5G; + channel |= WL_CHANSPEC_BW_20; + channel = wl_chspec_host_to_driver(channel); + err = wldev_iovar_getint(dev, "per_chan_info", &channel); + if (!err) { + if (channel & WL_CHAN_RADAR) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + band_chan_arr[index].flags |= + (IEEE80211_CHAN_RADAR + | IEEE80211_CHAN_NO_IBSS); +#else + band_chan_arr[index].flags |= + IEEE80211_CHAN_RADAR; +#endif + } + + if (channel & WL_CHAN_PASSIVE) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + band_chan_arr[index].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; +#else + band_chan_arr[index].flags |= + IEEE80211_CHAN_NO_IR; +#endif + } else if (err == BCME_UNSUPPORTED) { + dfs_radar_disabled = TRUE; + WL_ERR(("does not support per_chan_info\n")); + } + } + } + if (!update) + (*n_cnt)++; + } + + } + __wl_band_2ghz.n_channels = n_2g; + __wl_band_5ghz_a.n_channels = n_5g; + kfree(pbuf); + return err; +} + +s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) +{ + struct wiphy *wiphy; + struct net_device *dev; + u32 bandlist[3]; + u32 nband = 0; + u32 i = 0; + s32 err = 0; + s32 index = 0; + s32 nmode = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) + u32 j = 0; + s32 vhtmode = 0; + s32 txstreams = 0; + s32 rxstreams = 0; + s32 ldpc_cap = 0; + s32 stbc_rx = 0; + s32 stbc_tx = 0; + s32 txbf_bfe_cap = 0; + s32 txbf_bfr_cap = 0; +#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ + bool rollback_lock = false; + s32 bw_cap = 0; + s32 cur_band = -1; + struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, }; + + if (cfg == NULL) { + cfg = g_bcm_cfg; + mutex_lock(&cfg->usr_sync); + rollback_lock = true; + } + dev = bcmcfg_to_prmry_ndev(cfg); + + memset(bandlist, 0, sizeof(bandlist)); + err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist, + sizeof(bandlist)); + if (unlikely(err)) { + WL_ERR(("error read bandlist (%d)\n", err)); + goto end_bands; + } + err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, + sizeof(s32)); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + goto end_bands; + } + + err = wldev_iovar_getint(dev, "nmode", &nmode); + if (unlikely(err)) { + WL_ERR(("error reading nmode (%d)\n", err)); + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) + err = wldev_iovar_getint(dev, "vhtmode", &vhtmode); + if (unlikely(err)) { + WL_ERR(("error reading vhtmode (%d)\n", err)); + } + + if (vhtmode) { + err = wldev_iovar_getint(dev, "txstreams", &txstreams); + if (unlikely(err)) { + WL_ERR(("error reading txstreams (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "rxstreams", &rxstreams); + if (unlikely(err)) { + WL_ERR(("error reading rxstreams (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap); + if (unlikely(err)) { + WL_ERR(("error reading ldpc_cap (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx); + if (unlikely(err)) { + WL_ERR(("error reading stbc_rx (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx); + if (unlikely(err)) { + WL_ERR(("error reading stbc_tx (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap); + if (unlikely(err)) { + WL_ERR(("error reading txbf_bfe_cap (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap); + if (unlikely(err)) { + WL_ERR(("error reading txbf_bfr_cap (%d)\n", err)); + } + } +#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ + + /* For nmode and vhtmode check bw cap */ + if (nmode || +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) + vhtmode || +#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ + 0) { + err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); + if (unlikely(err)) { + WL_ERR(("error get mimo_bw_cap (%d)\n", err)); + } + } + + err = wl_construct_reginfo(cfg, bw_cap); + if (err) { + WL_ERR(("wl_construct_reginfo() fails err=%d\n", err)); + if (err != BCME_UNSUPPORTED) + goto end_bands; + err = 0; + } + wiphy = bcmcfg_to_wiphy(cfg); + nband = bandlist[0]; + + for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { + index = -1; + if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) { + bands[IEEE80211_BAND_5GHZ] = + &__wl_band_5ghz_a; + index = IEEE80211_BAND_5GHZ; + if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G)) + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) + /* VHT capabilities. */ + if (vhtmode) { + /* Supported */ + bands[index]->vht_cap.vht_supported = TRUE; + + for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) { + /* TX stream rates. */ + if (j <= txstreams) { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, + bands[index]->vht_cap.vht_mcs.tx_mcs_map); + } else { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, + bands[index]->vht_cap.vht_mcs.tx_mcs_map); + } + + /* RX stream rates. */ + if (j <= rxstreams) { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, + bands[index]->vht_cap.vht_mcs.rx_mcs_map); + } else { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, + bands[index]->vht_cap.vht_mcs.rx_mcs_map); + } + } + + + /* Capabilities */ + /* 80 MHz is mandatory */ + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SHORT_GI_80; + + if (WL_BW_CAP_160MHZ(bw_cap)) { + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SHORT_GI_160; + } + + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + + if (ldpc_cap) + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_RXLDPC; + + if (stbc_tx) + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_TXSTBC; + + if (stbc_rx) + bands[index]->vht_cap.cap |= + (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT); + + if (txbf_bfe_cap) + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + + if (txbf_bfr_cap) { + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + } + + if (txbf_bfe_cap || txbf_bfr_cap) { + bands[index]->vht_cap.cap |= + (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT); + bands[index]->vht_cap.cap |= + ((txstreams - 1) << + VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT); + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; + } + + /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */ + bands[index]->vht_cap.cap |= + (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT); + WL_INFORM(("%s band[%d] vht_enab=%d vht_cap=%08x " + "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n", + __FUNCTION__, index, + bands[index]->vht_cap.vht_supported, + bands[index]->vht_cap.cap, + bands[index]->vht_cap.vht_mcs.rx_mcs_map, + bands[index]->vht_cap.vht_mcs.tx_mcs_map)); + } +#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ + } + else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { + bands[IEEE80211_BAND_2GHZ] = + &__wl_band_2ghz; + index = IEEE80211_BAND_2GHZ; + if (bw_cap == WLC_N_BW_40ALL) + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + } + + if ((index >= 0) && nmode) { + bands[index]->ht_cap.cap |= + (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); + bands[index]->ht_cap.ht_supported = TRUE; + bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + /* An HT shall support all EQM rates for one spatial stream */ + bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; + } + + } + + wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; + wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; + + /* check if any bands populated otherwise makes 2Ghz as default */ + if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL && + wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) { + /* Setup 2Ghz band as default */ + wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + } + + if (notify) + wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); + + end_bands: + if (rollback_lock) + mutex_unlock(&cfg->usr_sync); + return err; +} + +static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) +{ + s32 err = 0; +#ifdef WL_HOST_BAND_MGMT + s32 ret = 0; +#endif /* WL_HOST_BAND_MGMT */ + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + struct wireless_dev *wdev = ndev->ieee80211_ptr; + + WL_DBG(("In\n")); + + err = dhd_config_dongle(cfg); + if (unlikely(err)) + return err; + + err = wl_config_ifmode(cfg, ndev, wdev->iftype); + if (unlikely(err && err != -EINPROGRESS)) { + WL_ERR(("wl_config_ifmode failed\n")); + if (err == -1) { + WL_ERR(("return error %d\n", err)); + return err; + } + } + err = wl_update_wiphybands(cfg, true); + if (unlikely(err)) { + WL_ERR(("wl_update_wiphybands failed\n")); + if (err == -1) { + WL_ERR(("return error %d\n", err)); + return err; + } + } + + err = dhd_monitor_init(cfg->pub); + +#ifdef WL_HOST_BAND_MGMT + /* By default the curr_band is initialized to BAND_AUTO */ + if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) { + if (ret == BCME_UNSUPPORTED) { + /* Don't fail the initialization, lets just + * fall back to the original method + */ + WL_ERR(("WL_HOST_BAND_MGMT defined, " + "but roam_band iovar not supported \n")); + } else { + WL_ERR(("roam_band failed. ret=%d", ret)); + err = -1; + } + } +#endif /* WL_HOST_BAND_MGMT */ + INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler); + wl_set_drv_status(cfg, READY, ndev); + return err; +} + +static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) +{ + s32 err = 0; + unsigned long flags; + struct net_info *iter, *next; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); +#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF) + struct net_device *p2p_net = cfg->p2p_net; +#endif + u32 bssidx = 0; +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif +#endif /* PROP_TXSTATUS_VSDB */ + WL_DBG(("In\n")); + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + + + if (cfg->p2p_supported) { + wl_clr_p2p_status(cfg, GO_NEG_PHASE); +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + if (cfg->p2p->vif_created) { + bool enabled = false; + dhd_wlfc_get_enable(dhd, &enabled); + if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) { + dhd_wlfc_deinit(dhd); + cfg->wlfc_on = false; + } + } +#endif +#endif /* PROP_TXSTATUS_VSDB */ + } + + + /* If primary BSS is operational (for e.g SoftAP), bring it down */ + if (!(wl_cfgp2p_find_idx(cfg, ndev, &bssidx)) && + wl_cfgp2p_bss_isup(ndev, bssidx)) { + if (wl_cfgp2p_bss(cfg, ndev, bssidx, 0) < 0) + WL_ERR(("BSS down failed \n")); + } + + /* Check if cfg80211 interface is already down */ + if (!wl_get_drv_status(cfg, READY, ndev)) + return err; /* it is even not ready */ + for_each_ndev(cfg, iter, next) + wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); + + + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + if (cfg->scan_request) { + cfg80211_scan_done(cfg->scan_request, true); + cfg->scan_request = NULL; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + for_each_ndev(cfg, iter, next) { + wl_clr_drv_status(cfg, READY, iter->ndev); + wl_clr_drv_status(cfg, SCANNING, iter->ndev); + wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev); + wl_clr_drv_status(cfg, CONNECTING, iter->ndev); + wl_clr_drv_status(cfg, CONNECTED, iter->ndev); + wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev); + wl_clr_drv_status(cfg, AP_CREATED, iter->ndev); + wl_clr_drv_status(cfg, AP_CREATING, iter->ndev); + } + bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype = + NL80211_IFTYPE_STATION; +#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF) + if (p2p_net) + dev_close(p2p_net); +#endif + wl_flush_eq(cfg); + wl_link_down(cfg); + if (cfg->p2p_supported) + wl_cfgp2p_down(cfg); + if (cfg->ap_info) { + kfree(cfg->ap_info->wpa_ie); + kfree(cfg->ap_info->rsn_ie); + kfree(cfg->ap_info->wps_ie); + kfree(cfg->ap_info); + cfg->ap_info = NULL; + } + dhd_monitor_uninit(); +#ifdef WLAIBSS_MCHAN + bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev); +#endif /* WLAIBSS_MCHAN */ + +#if defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF) + /* Clean up if not removed already */ + if (cfg->bss_cfgdev) + wl_cfg80211_del_iface(cfg->wdev->wiphy, cfg->bss_cfgdev); +#endif /* defined (DUAL_STA) || defined (DUAL_STA_STATIC_IF) */ + + DNGL_FUNC(dhd_cfg80211_down, (cfg)); + + return err; +} + +s32 wl_cfg80211_up(void *para) +{ + struct bcm_cfg80211 *cfg; + s32 err = 0; + int val = 1; + dhd_pub_t *dhd; + + (void)para; + WL_DBG(("In\n")); + cfg = g_bcm_cfg; + + if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val, + sizeof(int)) < 0)) { + WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err)); + return err; + } + val = dtoh32(val); + if (val != WLC_IOCTL_VERSION && val != 1) { + WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n", + val, WLC_IOCTL_VERSION)); + return BCME_VERSION; + } + ioctl_version = val; + WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version)); + + mutex_lock(&cfg->usr_sync); + dhd = (dhd_pub_t *)(cfg->pub); + if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { + err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg)); + if (unlikely(err)) + return err; + } + err = __wl_cfg80211_up(cfg); + if (unlikely(err)) + WL_ERR(("__wl_cfg80211_up failed\n")); + mutex_unlock(&cfg->usr_sync); + +#ifdef WLAIBSS_MCHAN + bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME); +#endif /* WLAIBSS_MCHAN */ + +#ifdef DUAL_STA_STATIC_IF +#ifdef DUAL_STA +#error "Both DUAL_STA and DUAL_STA_STATIC_IF can't be enabled together" +#endif + /* Static Interface support is currently supported only for STA only builds (without P2P) */ + wl_cfg80211_create_iface(cfg->wdev->wiphy, NL80211_IFTYPE_STATION, NULL, "wlan%d"); +#endif /* DUAL_STA_STATIC_IF */ + + return err; +} + +/* Private Event to Supplicant with indication that chip hangs */ +int wl_cfg80211_hang(struct net_device *dev, u16 reason) +{ + struct bcm_cfg80211 *cfg; + cfg = g_bcm_cfg; + + WL_ERR(("In : chip crash eventing\n")); + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL); + if (cfg != NULL) { + wl_link_down(cfg); + } + return 0; +} + +s32 wl_cfg80211_down(void *para) +{ + struct bcm_cfg80211 *cfg; + s32 err = 0; + + (void)para; + WL_DBG(("In\n")); + cfg = g_bcm_cfg; + mutex_lock(&cfg->usr_sync); + err = __wl_cfg80211_down(cfg); + mutex_unlock(&cfg->usr_sync); + + return err; +} + +static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item) +{ + unsigned long flags; + void *rptr = NULL; + struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); + + if (!profile) + return NULL; + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + switch (item) { + case WL_PROF_SEC: + rptr = &profile->sec; + break; + case WL_PROF_ACT: + rptr = &profile->active; + break; + case WL_PROF_BSSID: + rptr = profile->bssid; + break; + case WL_PROF_SSID: + rptr = &profile->ssid; + break; + case WL_PROF_CHAN: + rptr = &profile->channel; + break; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + if (!rptr) + WL_ERR(("invalid item (%d)\n", item)); + return rptr; +} + +static s32 +wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data, s32 item) +{ + s32 err = 0; + struct wlc_ssid *ssid; + unsigned long flags; + struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); + + if (!profile) + return WL_INVALID; + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + switch (item) { + case WL_PROF_SSID: + ssid = (wlc_ssid_t *) data; + memset(profile->ssid.SSID, 0, + sizeof(profile->ssid.SSID)); + profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN); + memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len); + break; + case WL_PROF_BSSID: + if (data) + memcpy(profile->bssid, data, ETHER_ADDR_LEN); + else + memset(profile->bssid, 0, ETHER_ADDR_LEN); + break; + case WL_PROF_SEC: + memcpy(&profile->sec, data, sizeof(profile->sec)); + break; + case WL_PROF_ACT: + profile->active = *(bool *)data; + break; + case WL_PROF_BEACONINT: + profile->beacon_interval = *(u16 *)data; + break; + case WL_PROF_DTIMPERIOD: + profile->dtim_period = *(u8 *)data; + break; + case WL_PROF_CHAN: + profile->channel = *(u32*)data; + break; + default: + err = -EOPNOTSUPP; + break; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + if (err == -EOPNOTSUPP) + WL_ERR(("unsupported item (%d)\n", item)); + + return err; +} + +void wl_cfg80211_dbg_level(u32 level) +{ + /* + * prohibit to change debug level + * by insmod parameter. + * eventually debug level will be configured + * in compile time by using CONFIG_XXX + */ + /* wl_dbg_level = level; */ +} + +static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS; +} + +static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg) +{ + return cfg->ibss_starter; +} + +static void wl_rst_ie(struct bcm_cfg80211 *cfg) +{ + struct wl_ie *ie = wl_to_ie(cfg); + + ie->offset = 0; +} + +static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v) +{ + struct wl_ie *ie = wl_to_ie(cfg); + s32 err = 0; + + if (unlikely(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; +} + +static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam) +{ + u8 *ssidie; + int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); + int32 remaining_ie_buf_len, available_buffer_len; + ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); + /* ERROR out if + * 1. No ssid IE is FOUND or + * 2. New ssid length is > what was allocated for existing ssid (as + * we do not want to overwrite the rest of the IEs) or + * 3. If in case of erroneous buffer input where ssid length doesnt match the space + * allocated to it. + */ + if (!ssidie) { + return; + } + available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream); + remaining_ie_buf_len = available_buffer_len - (int)ssidie[1]; + if ((ssid_len > ssidie[1]) || + (ssidie[1] > available_buffer_len)) { + return; + } + + if (ssidie[1] != ssid_len) { + if (ssidie[1]) { + WL_ERR(("%s: Wrong SSID len: %d != %d\n", + __FUNCTION__, ssidie[1], bi->SSID_len)); + } + if (roam) { + WL_ERR(("Changing the SSID Info.\n")); + memmove(ssidie + ssid_len + 2, + (ssidie + 2) + ssidie[1], + remaining_ie_buf_len); + memcpy(ssidie + 2, bi->SSID, ssid_len); + *ie_size = *ie_size + ssid_len - ssidie[1]; + ssidie[1] = ssid_len; + } + return; + } + if (*(ssidie + 2) == '\0') + memcpy(ssidie + 2, bi->SSID, ssid_len); + return; +} + +static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size) +{ + struct wl_ie *ie = wl_to_ie(cfg); + s32 err = 0; + + if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { + WL_ERR(("ei_stream crosses buffer boundary\n")); + return -ENOSPC; + } + memcpy(&ie->buf[ie->offset], ie_stream, ie_size); + ie->offset += ie_size; + + return err; +} + +static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size) +{ + struct wl_ie *ie = wl_to_ie(cfg); + s32 err = 0; + + if (unlikely(ie->offset > dst_size)) { + WL_ERR(("dst_size is not enough\n")); + return -ENOSPC; + } + memcpy(dst, &ie->buf[0], ie->offset); + + return err; +} + +static u32 wl_get_ielen(struct bcm_cfg80211 *cfg) +{ + struct wl_ie *ie = wl_to_ie(cfg); + + return ie->offset; +} + +static void wl_link_up(struct bcm_cfg80211 *cfg) +{ + cfg->link_up = true; +} + +static void wl_link_down(struct bcm_cfg80211 *cfg) +{ + struct wl_connect_info *conn_info = wl_to_conn(cfg); + + WL_DBG(("In\n")); + cfg->link_up = false; + conn_info->req_ie_len = 0; + conn_info->resp_ie_len = 0; +} + +static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg) +{ + unsigned long flags; + + spin_lock_irqsave(&cfg->eq_lock, flags); + return flags; +} + +static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags) +{ + spin_unlock_irqrestore(&cfg->eq_lock, flags); +} + +static void wl_init_eq_lock(struct bcm_cfg80211 *cfg) +{ + spin_lock_init(&cfg->eq_lock); +} + +static void wl_delay(u32 ms) +{ + if (in_atomic() || (ms < jiffies_to_msecs(1))) { + OSL_DELAY(ms*1000); + } else { + OSL_SLEEP(ms); + } +} + +s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct ether_addr p2pif_addr; + struct ether_addr primary_mac; + if (!cfg->p2p) + return -1; + if (!p2p_is_on(cfg)) { + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); + } else { + memcpy(p2pdev_addr->octet, + cfg->p2p->dev_addr.octet, ETHER_ADDR_LEN); + } + + + return 0; +} +s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) +{ + struct bcm_cfg80211 *cfg; + + cfg = g_bcm_cfg; + + return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len); +} + +s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) +{ + struct bcm_cfg80211 *cfg; + cfg = g_bcm_cfg; + + return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len); +} + +s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) +{ + struct bcm_cfg80211 *cfg; + cfg = g_bcm_cfg; + + return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len); +} + +s32 wl_cfg80211_channel_to_freq(u32 channel) +{ + int freq = 0; + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) + freq = ieee80211_channel_to_frequency(channel); +#else + { + u16 band = 0; + if (channel <= CH_MAX_2G_CHANNEL) + band = IEEE80211_BAND_2GHZ; + else + band = IEEE80211_BAND_5GHZ; + freq = ieee80211_channel_to_frequency(channel, band); + } +#endif + return freq; +} + + +#ifdef WLTDLS +static s32 +wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) { + + struct net_device *ndev = NULL; + u32 reason = ntoh32(e->reason); + s8 *msg = NULL; + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + switch (reason) { + case WLC_E_TDLS_PEER_DISCOVERED : + msg = " TDLS PEER DISCOVERD "; + break; + case WLC_E_TDLS_PEER_CONNECTED : +#ifdef PCIE_FULL_DONGLE + dhd_tdls_update_peer_info(ndev, TRUE, (uint8 *)&e->addr.octet[0]); +#endif /* PCIE_FULL_DONGLE */ + if (cfg->tdls_mgmt_frame) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0, + cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, + 0, GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ + defined(WL_COMPAT_WIRELESS) + cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0, + cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, + GFP_ATOMIC); +#else + cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, + cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, + GFP_ATOMIC); +#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */ + } + msg = " TDLS PEER CONNECTED "; + break; + case WLC_E_TDLS_PEER_DISCONNECTED : +#ifdef PCIE_FULL_DONGLE + dhd_tdls_update_peer_info(ndev, FALSE, (uint8 *)&e->addr.octet[0]); +#endif /* PCIE_FULL_DONGLE */ + if (cfg->tdls_mgmt_frame) { + kfree(cfg->tdls_mgmt_frame); + cfg->tdls_mgmt_frame = NULL; + cfg->tdls_mgmt_freq = 0; + } + msg = "TDLS PEER DISCONNECTED "; + break; + } + if (msg) { + WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((u8*)(&e->addr)), + (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary")); + } + return 0; + +} +#endif /* WLTDLS */ + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) +static s32 +#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) +wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, + u32 peer_capability, const u8 *data, size_t len) +#else +wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data, + size_t len) +#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ +{ + s32 ret = 0; +#ifdef WLTDLS + struct bcm_cfg80211 *cfg; + tdls_wfd_ie_iovar_t info; + memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t)); + cfg = g_bcm_cfg; + +#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) + /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10 + * and that cuases build error + */ + BCM_REFERENCE(peer_capability); +#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ + + switch (action_code) { + /* We need to set TDLS Wifi Display IE to firmware + * using tdls_wfd_ie iovar + */ + case WLAN_TDLS_SET_PROBE_WFD_IE: + info.mode = TDLS_WFD_PROBE_IE_TX; + memcpy(&info.data, data, len); + info.length = len; + break; + case WLAN_TDLS_SET_SETUP_WFD_IE: + info.mode = TDLS_WFD_IE_TX; + memcpy(&info.data, data, len); + info.length = len; + break; + default: + WL_ERR(("Unsupported action code : %d\n", action_code)); + goto out; + } + + ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (ret) { + WL_ERR(("tdls_wfd_ie error %d\n", ret)); + } +out: +#endif /* WLTDLS */ + return ret; +} + +static s32 +wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, enum nl80211_tdls_operation oper) +{ + s32 ret = 0; +#ifdef WLTDLS + struct bcm_cfg80211 *cfg; + tdls_iovar_t info; + cfg = g_bcm_cfg; + memset(&info, 0, sizeof(tdls_iovar_t)); + if (peer) { + memcpy(&info.ea, peer, ETHER_ADDR_LEN); + } else { + return -1; + } + switch (oper) { + case NL80211_TDLS_DISCOVERY_REQ: + /* turn on TDLS */ + ret = dhd_tdls_enable(dev, true, false, NULL); + if (ret < 0) + return ret; + /* If the discovery request is broadcast then we need to set + * info.mode to Tunneled Probe Request + */ + if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) { + info.mode = TDLS_MANUAL_EP_WFD_TPQ; + } + else { + info.mode = TDLS_MANUAL_EP_DISCOVERY; + } + break; + case NL80211_TDLS_SETUP: + /* auto mode on */ + ret = dhd_tdls_enable(dev, true, true, (struct ether_addr *)peer); + if (ret < 0) + return ret; + break; + case NL80211_TDLS_TEARDOWN: + info.mode = TDLS_MANUAL_EP_DELETE; + /* auto mode off */ + ret = dhd_tdls_enable(dev, true, false, (struct ether_addr *)peer); + if (ret < 0) + return ret; + break; + default: + WL_ERR(("Unsupported operation : %d\n", oper)); + goto out; + } + if (info.mode) { + ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (ret) { + WL_ERR(("tdls_endpoint error %d\n", ret)); + } + } +out: +#endif /* WLTDLS */ + return ret; +} +#endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */ + +s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, + enum wl_management_type type) +{ + struct bcm_cfg80211 *cfg; + struct net_device *ndev = NULL; + struct ether_addr primary_mac; + s32 ret = 0; + s32 bssidx = 0; + s32 pktflag = 0; + cfg = g_bcm_cfg; + + if (wl_get_drv_status(cfg, AP_CREATING, net)) { + /* Vendor IEs should be set to FW + * after SoftAP interface is brought up + */ + goto exit; + } else if (wl_get_drv_status(cfg, AP_CREATED, net)) { + ndev = net; + bssidx = 0; + } else if (cfg->p2p) { + net = ndev_to_wlc_ndev(net, cfg); + if (!cfg->p2p->on) { + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr, + &cfg->p2p->int_addr); + /* In case of p2p_listen command, supplicant send remain_on_channel + * without turning on P2P + */ + + p2p_on(cfg) = true; + ret = wl_cfgp2p_enable_discovery(cfg, net, NULL, 0); + + if (unlikely(ret)) { + goto exit; + } + } + if (net != bcmcfg_to_prmry_ndev(cfg)) { + if (wl_get_mode_by_netdev(cfg, net) == WL_MODE_AP) { + ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION); + } + } else { + ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + } + } + if (ndev != NULL) { + switch (type) { + case WL_BEACON: + pktflag = VNDR_IE_BEACON_FLAG; + break; + case WL_PROBE_RESP: + pktflag = VNDR_IE_PRBRSP_FLAG; + break; + case WL_ASSOC_RESP: + pktflag = VNDR_IE_ASSOCRSP_FLAG; + break; + } + if (pktflag) + ret = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, pktflag, buf, len); + } +exit: + return ret; +} + +#ifdef WL_SUPPORT_AUTO_CHANNEL +static s32 +wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev) +{ + u32 val = 0; + s32 ret = BCME_ERROR; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + /* Disable mpc, to avoid automatic interface down. */ + val = 0; + + ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, + sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, + &cfg->ioctl_buf_sync); + if (ret < 0) { + WL_ERR(("set 'mpc' failed, error = %d\n", ret)); + goto done; + } + + /* Set interface up, explicitly. */ + val = 1; + + ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val)); + if (ret < 0) { + WL_ERR(("set interface up failed, error = %d\n", ret)); + goto done; + } + + /* Stop all scan explicitly, till auto channel selection complete. */ + wl_set_drv_status(cfg, SCANNING, ndev); + if (cfg->escan_info.ndev == NULL) { + ret = BCME_OK; + goto done; + } + ret = wl_notify_escan_complete(cfg, ndev, true, true); + if (ret < 0) { + WL_ERR(("set scan abort failed, error = %d\n", ret)); + goto done; + } + +done: + return ret; +} + +static bool +wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec) +{ + bool valid = false; + char chanbuf[CHANSPEC_STR_LEN]; + + if (ioctl_version != 1) { + if ((chanspec = wl_chspec_to_legacy(chanspec)) == INVCHANSPEC) { + return valid; + } + } + + /* channel 1 to 14 */ + if ((chanspec >= 0x2b01) && (chanspec <= 0x2b0e)) { + valid = true; + } + /* channel 36 to 48 */ + else if ((chanspec >= 0x1b24) && (chanspec <= 0x1b30)) { + valid = true; + } + /* channel 149 to 161 */ + else if ((chanspec >= 0x1b95) && (chanspec <= 0x1ba1)) { + valid = true; + } + else { + valid = false; + WL_INFORM(("invalid P2P chanspec, chanspec = %s\n", + wf_chspec_ntoa_ex(chanspec, chanbuf))); + } + + return valid; +} + +static s32 +wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen) +{ + s32 ret = BCME_ERROR; + struct bcm_cfg80211 *cfg = NULL; + chanspec_t chanspec = 0; + + cfg = g_bcm_cfg; + + /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */ + chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 | + WL_CHANSPEC_CTL_SB_NONE); + chanspec = wl_chspec_host_to_driver(chanspec); + + ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, + sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync); + if (ret < 0) { + WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); + } + + return ret; +} + +static s32 +wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen) +{ + u32 channel = 0; + s32 ret = BCME_ERROR; + s32 i = 0; + s32 j = 0; + struct bcm_cfg80211 *cfg = NULL; + wl_uint32_list_t *list = NULL; + chanspec_t chanspec = 0; + + cfg = g_bcm_cfg; + + /* Restrict channels to 5GHz, 20MHz BW, no SB. */ + chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 | + WL_CHANSPEC_CTL_SB_NONE); + chanspec = wl_chspec_host_to_driver(chanspec); + + ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, + sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync); + if (ret < 0) { + WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); + goto done; + } + + list = (wl_uint32_list_t *)buf; + /* Skip DFS and inavlid P2P channel. */ + for (i = 0, j = 0; i < dtoh32(list->count); i++) { + chanspec = (chanspec_t) dtoh32(list->element[i]); + channel = CHSPEC_CHANNEL(chanspec); + + ret = wldev_iovar_getint(ndev, "per_chan_info", &channel); + if (ret < 0) { + WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret)); + goto done; + } + + if (CHANNEL_IS_RADAR(channel) || + !(wl_cfg80211_valid_chanspec_p2p(chanspec))) { + continue; + } else { + list->element[j] = list->element[i]; + } + + j++; + } + + list->count = j; + +done: + return ret; +} + +static s32 +wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen, + int *channel) +{ + s32 ret = BCME_ERROR; + int chosen = 0; + int retry = 0; + + /* Start auto channel selection scan. */ + ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, buf, buflen); + if (ret < 0) { + WL_ERR(("can't start auto channel scan, error = %d\n", ret)); + *channel = 0; + goto done; + } + + /* Wait for auto channel selection, worst case possible delay is 5250ms. */ + retry = CHAN_SEL_RETRY_COUNT; + + while (retry--) { + OSL_SLEEP(CHAN_SEL_IOCTL_DELAY); + chosen = 0; + ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); + if ((ret == 0) && (dtoh32(chosen) != 0)) { + *channel = (u16)(chosen & 0x00FF); + WL_INFORM(("selected channel = %d\n", *channel)); + break; + } + WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n", + (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen))); + } + + if (retry <= 0) { + WL_ERR(("failure, auto channel selection timed out\n")); + *channel = 0; + ret = BCME_ERROR; + } + +done: + return ret; +} + +static s32 +wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev) +{ + u32 val = 0; + s32 ret = BCME_ERROR; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + /* Clear scan stop driver status. */ + wl_clr_drv_status(cfg, SCANNING, ndev); + + /* Enable mpc back to 1, irrespective of initial state. */ + val = 1; + + ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, + sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, + &cfg->ioctl_buf_sync); + if (ret < 0) { + WL_ERR(("set 'mpc' failed, error = %d\n", ret)); + } + + return ret; +} + +s32 +wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len) +{ + int channel = 0; + s32 ret = BCME_ERROR; + u8 *buf = NULL; + char *pos = cmd; + struct bcm_cfg80211 *cfg = NULL; + struct net_device *ndev = NULL; + + memset(cmd, 0, total_len); + + buf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL); + if (buf == NULL) { + WL_ERR(("failed to allocate chanspec buffer\n")); + return -ENOMEM; + } + + /* + * Always use primary interface, irrespective of interface on which + * command came. + */ + cfg = g_bcm_cfg; + ndev = bcmcfg_to_prmry_ndev(cfg); + + /* + * Make sure that FW and driver are in right state to do auto channel + * selection scan. + */ + ret = wl_cfg80211_set_auto_channel_scan_state(ndev); + if (ret < 0) { + WL_ERR(("can't set auto channel scan state, error = %d\n", ret)); + goto done; + } + + /* Best channel selection in 2.4GHz band. */ + ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); + if (ret < 0) { + WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret)); + goto done; + } + + ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, + &channel); + if (ret < 0) { + WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret)); + goto done; + } + + if (CHANNEL_IS_2G(channel)) { + channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); + } else { + WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel)); + channel = 0; + } + + sprintf(pos, "%04d ", channel); + pos += 5; + + /* Best channel selection in 5GHz band. */ + ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); + if (ret < 0) { + WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret)); + goto done; + } + + ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, + &channel); + if (ret < 0) { + WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret)); + goto done; + } + + if (CHANNEL_IS_5G(channel)) { + channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); + } else { + WL_ERR(("invalid 5GHz channel, channel = %d\n", channel)); + channel = 0; + } + + sprintf(pos, "%04d ", channel); + pos += 5; + + /* Set overall best channel same as 5GHz best channel. */ + sprintf(pos, "%04d ", channel); + pos += 5; + +done: + if (NULL != buf) { + kfree(buf); + } + + /* Restore FW and driver back to normal state. */ + ret = wl_cfg80211_restore_auto_channel_scan_state(ndev); + if (ret < 0) { + WL_ERR(("can't restore auto channel scan state, error = %d\n", ret)); + } + + return (pos - cmd); +} +#endif /* WL_SUPPORT_AUTO_CHANNEL */ + +static const struct rfkill_ops wl_rfkill_ops = { + .set_block = wl_rfkill_set +}; + +static int wl_rfkill_set(void *data, bool blocked) +{ + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; + + WL_DBG(("Enter \n")); + WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked")); + + if (!cfg) + return -EINVAL; + + cfg->rf_blocked = blocked; + + return 0; +} + +static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup) +{ + s32 err = 0; + + WL_DBG(("Enter \n")); + if (!cfg) + return -EINVAL; + if (setup) { + cfg->rfkill = rfkill_alloc("brcmfmac-wifi", + wl_cfg80211_get_parent_dev(), + RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg); + + if (!cfg->rfkill) { + err = -ENOMEM; + goto err_out; + } + + err = rfkill_register(cfg->rfkill); + + if (err) + rfkill_destroy(cfg->rfkill); + } else { + if (!cfg->rfkill) { + err = -ENOMEM; + goto err_out; + } + + rfkill_unregister(cfg->rfkill); + rfkill_destroy(cfg->rfkill); + } + +err_out: + return err; +} + +#ifdef DEBUGFS_CFG80211 +/** +* Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level +* to turn on SCAN and DBG log. +* To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level +* To see current setting of debug level, +* cat /sys/kernel/debug/dhd/debug_level +*/ +static ssize_t +wl_debuglevel_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL]; + char *params, *token, *colon; + uint i, tokens, log_on = 0; + memset(tbuf, 0, sizeof(tbuf)); + memset(sublog, 0, sizeof(sublog)); + if (copy_from_user(&tbuf, userbuf, min_t(size_t, (sizeof(tbuf) - 1), count))) + return -EFAULT; + + params = &tbuf[0]; + colon = strchr(params, '\n'); + if (colon != NULL) + *colon = '\0'; + while ((token = strsep(¶ms, " ")) != NULL) { + memset(sublog, 0, sizeof(sublog)); + if (token == NULL || !*token) + break; + if (*token == '\0') + continue; + colon = strchr(token, ':'); + if (colon != NULL) { + *colon = ' '; + } + tokens = sscanf(token, "%s %u", sublog, &log_on); + if (colon != NULL) + *colon = ':'; + + if (tokens == 2) { + for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { + if (!strncmp(sublog, sublogname_map[i].sublogname, + strlen(sublogname_map[i].sublogname))) { + if (log_on) + wl_dbg_level |= + (sublogname_map[i].log_level); + else + wl_dbg_level &= + ~(sublogname_map[i].log_level); + } + } + } else + WL_ERR(("%s: can't parse '%s' as a " + "SUBMODULE:LEVEL (%d tokens)\n", + tbuf, token, tokens)); + + + } + return count; +} + +static ssize_t +wl_debuglevel_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + char *param; + char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)]; + uint i; + memset(tbuf, 0, sizeof(tbuf)); + param = &tbuf[0]; + for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { + param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ", + sublogname_map[i].sublogname, + (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0); + } + *param = '\n'; + return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0])); + +} +static const struct file_operations fops_debuglevel = { + .open = NULL, + .write = wl_debuglevel_write, + .read = wl_debuglevel_read, + .owner = THIS_MODULE, + .llseek = NULL, +}; + +static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg) +{ + s32 err = 0; + struct dentry *_dentry; + if (!cfg) + return -EINVAL; + cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!cfg->debugfs || IS_ERR(cfg->debugfs)) { + if (cfg->debugfs == ERR_PTR(-ENODEV)) + WL_ERR(("Debugfs is not enabled on this kernel\n")); + else + WL_ERR(("Can not create debugfs directory\n")); + cfg->debugfs = NULL; + goto exit; + + } + _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR, + cfg->debugfs, cfg, &fops_debuglevel); + if (!_dentry || IS_ERR(_dentry)) { + WL_ERR(("failed to create debug_level debug file\n")); + wl_free_debugfs(cfg); + } +exit: + return err; +} +static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg) +{ + if (!cfg) + return -EINVAL; + if (cfg->debugfs) + debugfs_remove_recursive(cfg->debugfs); + cfg->debugfs = NULL; + return 0; +} +#endif /* DEBUGFS_CFG80211 */ + +struct device *wl_cfg80211_get_parent_dev(void) +{ + return cfg80211_parent_dev; +} + +void wl_cfg80211_set_parent_dev(void *dev) +{ + cfg80211_parent_dev = dev; +} + +static void wl_cfg80211_clear_parent_dev(void) +{ + cfg80211_parent_dev = NULL; +} + +void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac) +{ + wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr", NULL, + 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync); + memcpy(mac->octet, cfg->ioctl_buf, ETHER_ADDR_LEN); +} +static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + if (((dev_role == NL80211_IFTYPE_AP) && + !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) || + ((dev_role == NL80211_IFTYPE_P2P_GO) && + !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE))) + { + WL_ERR(("device role select failed\n")); + return false; + } + return true; +} + +int wl_cfg80211_do_driver_init(struct net_device *net) +{ + struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net); + + if (!cfg || !cfg->wdev) + return -EINVAL; + + if (dhd_do_driver_init(cfg->wdev->netdev) < 0) + return -1; + + return 0; +} + +void wl_cfg80211_enable_trace(bool set, u32 level) +{ + if (set) + wl_dbg_level = level & WL_DBG_LEVEL; + else + wl_dbg_level |= (WL_DBG_LEVEL & level); +} +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) +static s32 +wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + bcm_struct_cfgdev *cfgdev, u64 cookie) +{ + /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION + * is passed with CMD_FRAME. This callback is supposed to cancel + * the OFFCHANNEL Wait. Since we are already taking care of that + * with the tx_mgmt logic, do nothing here. + */ + + return 0; +} +#endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */ + +#ifdef WL11U +bcm_tlv_t * +wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) { + return (bcm_tlv_t *)ie; + } + return NULL; +} + + +static s32 +wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, + uint8 ie_id, uint8 *data, uint8 data_len) +{ + s32 err = BCME_OK; + s32 buf_len; + s32 iecount; + ie_setbuf_t *ie_setbuf; + + if (ie_id != DOT11_MNG_INTERWORKING_ID) + return BCME_UNSUPPORTED; + + /* access network options (1 octet) is the mandatory field */ + if (!data || data_len == 0 || data_len > IW_IES_MAX_BUF_LEN) { + WL_ERR(("wrong interworking IE (len=%d)\n", data_len)); + return BCME_BADARG; + } + + /* Validate the pktflag parameter */ + if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | + VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | + VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| + VNDR_IE_CUSTOM_FLAG))) { + WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag)); + return -1; + } + + /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ + pktflag = htod32(pktflag); + + buf_len = sizeof(ie_setbuf_t) + data_len - 1; + ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); + + if (!ie_setbuf) { + WL_ERR(("Error allocating buffer for IE\n")); + return -ENOMEM; + } + + if (cfg->iw_ie_len == data_len && !memcmp(cfg->iw_ie, data, data_len)) { + WL_ERR(("Previous IW IE is equals to current IE\n")); + err = BCME_OK; + goto exit; + } + + strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); + ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); + memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); + + /* Now, add the IE to the buffer */ + ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; + + /* if already set with previous values, delete it first */ + if (cfg->iw_ie_len != 0) { + WL_DBG(("Different IW_IE was already set. clear first\n")); + + ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; + + err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + if (err != BCME_OK) + goto exit; + } + + ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; + memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); + + err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + if (err == BCME_OK) { + memcpy(cfg->iw_ie, data, data_len); + cfg->iw_ie_len = data_len; + cfg->wl11u = TRUE; + + err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); + } + +exit: + if (ie_setbuf) + kfree(ie_setbuf); + return err; +} +#endif /* WL11U */ + +#ifdef WL_HOST_BAND_MGMT +s32 +wl_cfg80211_set_band(struct net_device *ndev, int band) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + int ret = 0; + char ioctl_buf[50]; + + if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) { + WL_ERR(("Invalid band\n")); + return -EINVAL; + } + + if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band, + sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) { + WL_ERR(("seting roam_band failed code=%d\n", ret)); + return ret; + } + + WL_DBG(("Setting band to %d\n", band)); + cfg->curr_band = band; + + return 0; +} +#endif /* WL_HOST_BAND_MGMT */ + + +int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev) +{ + struct bcm_cfg80211 *cfg = NULL; + struct net_device *ndev = NULL; + unsigned long flags; + int clear_flag = 0; + int ret = 0; + + WL_TRACE(("Enter\n")); + + cfg = g_bcm_cfg; + if (!cfg) + return -EINVAL; + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); +#ifdef WL_CFG80211_P2P_DEV_IF + if (cfg->scan_request && cfg->scan_request->wdev == cfgdev) { +#else + if (cfg->scan_request && cfg->scan_request->dev == cfgdev) { +#endif + cfg80211_scan_done(cfg->scan_request, true); + cfg->scan_request = NULL; + clear_flag = 1; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + if (clear_flag) + wl_clr_drv_status(cfg, SCANNING, ndev); + + return ret; +} + +bool wl_cfg80211_is_vsdb_mode(void) +{ + return (g_bcm_cfg && g_bcm_cfg->vsdb_mode); +} + +void* wl_cfg80211_get_dhdp() +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + return cfg->pub; +} + +bool wl_cfg80211_is_p2p_active(void) +{ + return (g_bcm_cfg && g_bcm_cfg->p2p); +} + +static void wl_cfg80211_work_handler(struct work_struct * work) +{ + struct bcm_cfg80211 *cfg = NULL; + struct net_info *iter, *next; + s32 err = BCME_OK; + s32 pm = PM_FAST; + + cfg = container_of(work, struct bcm_cfg80211, pm_enable_work.work); + WL_DBG(("Enter \n")); + if (cfg->pm_enable_work_on) { + cfg->pm_enable_work_on = false; + for_each_ndev(cfg, iter, next) { + if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) || + (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS)) + continue; + if (iter->ndev) { + if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM, + &pm, sizeof(pm))) != 0) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); + } else + wl_cfg80211_update_power_mode(iter->ndev); + } + } + } +} + +u8 +wl_get_action_category(void *frame, u32 frame_len) +{ + u8 category; + u8 *ptr = (u8 *)frame; + if (frame == NULL) + return DOT11_ACTION_CAT_ERR_MASK; + if (frame_len < DOT11_ACTION_HDR_LEN) + return DOT11_ACTION_CAT_ERR_MASK; + category = ptr[DOT11_ACTION_CAT_OFF]; + WL_INFORM(("Action Category: %d\n", category)); + return category; +} + +int +wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action) +{ + u8 *ptr = (u8 *)frame; + if (frame == NULL || ret_action == NULL) + return BCME_ERROR; + if (frame_len < DOT11_ACTION_HDR_LEN) + return BCME_ERROR; + if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len)) + return BCME_ERROR; + *ret_action = ptr[DOT11_ACTION_ACT_OFF]; + WL_INFORM(("Public Action : %d\n", *ret_action)); + return BCME_OK; +} + +#ifdef WLFBT +void +wl_cfg80211_get_fbt_key(uint8 *key) +{ + memcpy(key, g_bcm_cfg->fbt_key, FBT_KEYLEN); +} +#endif /* WLFBT */ + +static int +wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const struct ether_addr *bssid) +{ + s32 err; + wl_event_msg_t e; + + bzero(&e, sizeof(e)); + e.event_type = cpu_to_be32(WLC_E_BSSID); + memcpy(&e.addr, bssid, ETHER_ADDR_LEN); + /* trigger the roam event handler */ + err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL); + + return err; +} + +#ifdef WL_CFG80211_ACL +static int +wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, + const struct cfg80211_acl_data *acl) +{ + int i; + int ret = 0; + int macnum = 0; + int macmode = MACLIST_MODE_DISABLED; + struct maclist *list; + + /* get the MAC filter mode */ + if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) { + macmode = MACLIST_MODE_ALLOW; + } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED && + acl->n_acl_entries) { + macmode = MACLIST_MODE_DENY; + } + + /* if acl == NULL, macmode is still disabled.. */ + if (macmode == MACLIST_MODE_DISABLED) { + if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0) + WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); + + return ret; + } + + macnum = acl->n_acl_entries; + if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { + WL_ERR(("%s : invalid number of MAC address entries %d\n", + __FUNCTION__, macnum)); + return -1; + } + + /* allocate memory for the MAC list */ + list = (struct maclist*)kmalloc(sizeof(int) + + sizeof(struct ether_addr) * macnum, GFP_KERNEL); + if (!list) { + WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__)); + return -1; + } + + /* prepare the MAC list */ + list->count = htod32(macnum); + for (i = 0; i < macnum; i++) { + memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN); + } + /* set the list */ + if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0) + WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); + + kfree(list); + + return ret; +} +#endif /* WL_CFG80211_ACL */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) +int wl_chspec_chandef(chanspec_t chanspec, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +struct cfg80211_chan_def *chandef, +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ + \ + 0))) +struct chan_info *chaninfo, +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */ +struct wiphy *wiphy) +{ + uint16 freq = 0; + int chan_type; + int channel = 0; + + if (!chandef) { + return -1; + } + channel = CHSPEC_CHANNEL(chanspec); + + switch (CHSPEC_BW(chanspec)) { + case WL_CHANSPEC_BW_20: + chan_type = NL80211_CHAN_HT20; + break; + case WL_CHANSPEC_BW_40: + { + if (CHSPEC_SB_UPPER(chanspec)) { + channel += CH_10MHZ_APART; + } else { + channel -= CH_10MHZ_APART; + } + } + chan_type = NL80211_CHAN_HT40PLUS; + break; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) + case WL_CHANSPEC_BW_80: + case WL_CHANSPEC_BW_8080: + { + uint16 sb = CHSPEC_CTL_SB(chanspec); + + if (sb == WL_CHANSPEC_CTL_SB_LL) { + channel -= (CH_10MHZ_APART + CH_20MHZ_APART); + } else if (sb == WL_CHANSPEC_CTL_SB_LU) { + channel -= CH_10MHZ_APART; + } else if (sb == WL_CHANSPEC_CTL_SB_UL) { + channel += CH_10MHZ_APART; + } else { + /* WL_CHANSPEC_CTL_SB_UU */ + channel += (CH_10MHZ_APART + CH_20MHZ_APART); + } + } + + chan_type = NL80211_CHAN_WIDTH_80P80; + break; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ + default: + chan_type = NL80211_CHAN_HT20; + break; + + } + + if (CHSPEC_IS5G(chanspec)) + freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ); + else + freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) + cfg80211_chandef_create(chandef, ieee80211_get_channel(wiphy, freq), chan_type); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ + \ + 0))) + chaninfo->freq = freq; + chaninfo->chan_type = chan_type; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ + return 0; +} + +void +wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) + struct cfg80211_chan_def chandef; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ + \ + 0))) + struct chan_info chaninfo; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ + + if (!wiphy) { + printk("wiphy is null\n"); + return; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) + if (wl_chspec_chandef(chanspec, &chandef, wiphy)) { +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ + \ + 0))) + if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) { +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ + + WL_ERR(("%s:chspec_chandef failed\n", __FUNCTION__)); + return; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) + cfg80211_ch_switch_notify(dev, &chandef); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ + \ + 0))) + cfg80211_ch_switch_notify(dev, chan_info.freq, chan_info.chan_type); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ + return; +} + +static s32 +wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, +const wl_event_msg_t *e, void *data) +{ + int error = 0; + int chsp = 0; + struct net_device *ndev = NULL; + struct wiphy *wiphy = NULL; + chanspec_t chanspec; + + WL_ERR(("%s\n", __FUNCTION__)); + if (e->status) + return -1; + if (cfgdev) { + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + wiphy = bcmcfg_to_wiphy(cfg); + error = wldev_iovar_getint(ndev, "chanspec", &chsp); + if (error) + return -1; + chanspec = wl_chspec_driver_to_host(chsp); + wl_cfg80211_ch_switch_notify(ndev, chanspec, wiphy); + } else { + WL_ERR(("%s:cfgdev is null\n", __FUNCTION__)); + return -1; + } + + + return 0; +} +#else +static s32 +wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, +const wl_event_msg_t *e, void *data) +{ + WL_ERR(("%s:Not sup for kernel < 3.5\n", __FUNCTION__)); + return 0; +} +#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h new file mode 100644 index 000000000000..326700e4b5ff --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h @@ -0,0 +1,1040 @@ +/* + * Linux cfg80211 driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.h 633622 2016-04-24 11:50:51Z $ + */ + +/** + * Older Linux versions support the 'iw' interface, more recent ones the 'cfg80211' interface. + */ + +#ifndef _wl_cfg80211_h_ +#define _wl_cfg80211_h_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct wl_conf; +struct wl_iface; +struct bcm_cfg80211; +struct wl_security; +struct wl_ibss; + + +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh64(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) + +#define WL_DBG_NONE 0 +#define WL_DBG_P2P_ACTION (1 << 5) +#define WL_DBG_TRACE (1 << 4) +#define WL_DBG_SCAN (1 << 3) +#define WL_DBG_DBG (1 << 2) +#define WL_DBG_INFO (1 << 1) +#define WL_DBG_ERR (1 << 0) + +/* 0 invalidates all debug messages. default is 1 */ +#define WL_DBG_LEVEL 0xFF + +#define CFG80211_ERROR_TEXT "CFG80211-ERROR) " + +#define MAX_WAIT_TIME 1500 +#define DNGL_FUNC(func, parameters) func parameters; + +#define PM_BLOCK 1 +#define PM_ENABLE 0 + +#if defined(DHD_DEBUG) +#define WL_ERR(args) \ +do { \ + if (wl_dbg_level & WL_DBG_ERR) { \ + printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ + printk args; \ + } \ +} while (0) +#else /* defined(DHD_DEBUG) */ +#define WL_ERR(args) \ +do { \ + if ((wl_dbg_level & WL_DBG_ERR) && net_ratelimit()) { \ + printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ + printk args; \ + } \ +} while (0) +#endif /* defined(DHD_DEBUG) */ + +#ifdef WL_INFORM +#undef WL_INFORM +#endif + +#define WL_INFORM(args) \ +do { \ + if (wl_dbg_level & WL_DBG_INFO) { \ + printk(KERN_INFO "CFG80211-INFO) %s : ", __func__); \ + printk args; \ + } \ +} while (0) + + +#ifdef WL_SCAN +#undef WL_SCAN +#endif +#define WL_SCAN(args) \ +do { \ + if (wl_dbg_level & WL_DBG_SCAN) { \ + printk(KERN_INFO "CFG80211-SCAN) %s :", __func__); \ + printk args; \ + } \ +} while (0) +#ifdef WL_TRACE +#undef WL_TRACE +#endif +#define WL_TRACE(args) \ +do { \ + if (wl_dbg_level & WL_DBG_TRACE) { \ + printk(KERN_INFO "CFG80211-TRACE) %s :", __func__); \ + printk args; \ + } \ +} while (0) +#ifdef WL_TRACE_HW4 +#undef WL_TRACE_HW4 +#endif +#define WL_TRACE_HW4 WL_TRACE +#if (WL_DBG_LEVEL > 0) +#define WL_DBG(args) \ +do { \ + if (wl_dbg_level & WL_DBG_DBG) { \ + printk(KERN_DEBUG "CFG80211-DEBUG) %s :", __func__); \ + printk args; \ + } \ +} while (0) +#else /* !(WL_DBG_LEVEL > 0) */ +#define WL_DBG(args) +#endif /* (WL_DBG_LEVEL > 0) */ +#define WL_PNO(x) +#define WL_SD(x) + + +#define WL_SCAN_RETRY_MAX 3 +#define WL_NUM_PMKIDS_MAX MAXPMKID +#define WL_SCAN_BUF_MAX (1024 * 8) +#define WL_TLV_INFO_MAX 1500 +#define WL_SCAN_IE_LEN_MAX 2048 +#define WL_BSS_INFO_MAX 2048 +#define WL_ASSOC_INFO_MAX 512 +#define WL_IOCTL_LEN_MAX 2048 +#define WL_EXTRA_BUF_MAX 2048 +#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) +#define WL_AP_MAX 256 +#define WL_FILE_NAME_MAX 256 +#define WL_DWELL_TIME 200 +#define WL_MED_DWELL_TIME 400 +#define WL_MIN_DWELL_TIME 100 +#define WL_LONG_DWELL_TIME 1000 +#define IFACE_MAX_CNT 2 +#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 +#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 +#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 +#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 +#define WL_AF_TX_MAX_RETRY 5 + +#define WL_AF_SEARCH_TIME_MAX 450 +#define WL_AF_TX_EXTRA_TIME_MAX 200 + +#define WL_SCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */ +#define WL_CHANNEL_SYNC_RETRY 5 +#define WL_INVALID -1 + +/* Bring down SCB Timeout to 20secs from 60secs default */ +#ifndef WL_SCB_TIMEOUT +#define WL_SCB_TIMEOUT 20 +#endif + +/* SCAN_SUPPRESS timer values in ms */ +#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */ +#define WL_SCAN_SUPPRESS_RETRY 3000 + +#define WL_PM_ENABLE_TIMEOUT 10000 + +#ifdef WLAIBSS +/* Custom AIBSS beacon parameters */ +#define AIBSS_INITIAL_MIN_BCN_DUR 500 +#define AIBSS_MIN_BCN_DUR 5000 +#define AIBSS_BCN_FLOOD_DUR 5000 +#endif /* WLAIBSS */ + +/* driver status */ +enum wl_status { + WL_STATUS_READY = 0, + WL_STATUS_SCANNING, + WL_STATUS_SCAN_ABORTING, + WL_STATUS_CONNECTING, + WL_STATUS_CONNECTED, + WL_STATUS_DISCONNECTING, + WL_STATUS_AP_CREATING, + WL_STATUS_AP_CREATED, + /* whole sending action frame procedure: + * includes a) 'finding common channel' for public action request frame + * and b) 'sending af via 'actframe' iovar' + */ + WL_STATUS_SENDING_ACT_FRM, + /* find a peer to go to a common channel before sending public action req frame */ + WL_STATUS_FINDING_COMMON_CHANNEL, + /* waiting for next af to sync time of supplicant. + * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN + */ + WL_STATUS_WAITING_NEXT_ACT_FRM, +#ifdef WL_CFG80211_SYNC_GON + /* go to listen state to wait for next af after SENDING_ACT_FRM */ + WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN, +#endif /* WL_CFG80211_SYNC_GON */ + /* it will be set when upper layer requests listen and succeed in setting listen mode. + * if set, other scan request can abort current listen state + */ + WL_STATUS_REMAINING_ON_CHANNEL, +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + /* it's fake listen state to keep current scan state. + * it will be set when upper layer requests listen but scan is running. then just run + * a expire timer without actual listen state. + * if set, other scan request does not need to abort scan. + */ + WL_STATUS_FAKE_REMAINING_ON_CHANNEL +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ +}; + +/* wi-fi mode */ +enum wl_mode { + WL_MODE_BSS, + WL_MODE_IBSS, + WL_MODE_AP +}; + +/* driver profile list */ +enum wl_prof_list { + WL_PROF_MODE, + WL_PROF_SSID, + WL_PROF_SEC, + WL_PROF_IBSS, + WL_PROF_BAND, + WL_PROF_CHAN, + WL_PROF_BSSID, + WL_PROF_ACT, + WL_PROF_BEACONINT, + WL_PROF_DTIMPERIOD +}; + +/* donlge escan state */ +enum wl_escan_state { + WL_ESCAN_STATE_IDLE, + WL_ESCAN_STATE_SCANING +}; +/* fw downloading status */ +enum wl_fw_status { + WL_FW_LOADING_DONE, + WL_NVRAM_LOADING_DONE +}; + +enum wl_management_type { + WL_BEACON = 0x1, + WL_PROBE_RESP = 0x2, + WL_ASSOC_RESP = 0x4 +}; + +enum wl_handler_del_type { + WL_HANDLER_NOTUSE, + WL_HANDLER_DEL, + WL_HANDLER_MAINTAIN, + WL_HANDLER_PEND +}; + +/* beacon / probe_response */ +struct beacon_proberesp { + __le64 timestamp; + __le16 beacon_int; + __le16 capab_info; + u8 variable[0]; +} __attribute__ ((packed)); + +/* driver configuration */ +struct wl_conf { + u32 frag_threshold; + u32 rts_threshold; + u32 retry_short; + u32 retry_long; + s32 tx_power; + struct ieee80211_channel channel; +}; + +typedef s32(*EVENT_HANDLER) (struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); + +/* bss inform structure for cfg80211 interface */ +struct wl_cfg80211_bss_info { + u16 band; + u16 channel; + s16 rssi; + u16 frame_len; + u8 frame_buf[1]; +}; + +/* basic structure of scan request */ +struct wl_scan_req { + struct wlc_ssid ssid; +}; + +/* basic structure of information element */ +struct wl_ie { + u16 offset; + u8 buf[WL_TLV_INFO_MAX]; +}; + +/* event queue for cfg80211 main event */ +struct wl_event_q { + struct list_head eq_list; + u32 etype; + wl_event_msg_t emsg; + s8 edata[1]; +}; + +/* security information with currently associated ap */ +struct wl_security { + u32 wpa_versions; + u32 auth_type; + u32 cipher_pairwise; + u32 cipher_group; + u32 wpa_auth; + u32 auth_assoc_res_status; +}; + +/* ibss information for currently joined ibss network */ +struct wl_ibss { + u8 beacon_interval; /* in millisecond */ + u8 atim; /* in millisecond */ + s8 join_only; + u8 band; + u8 channel; +}; + +/* cfg driver profile */ +struct wl_profile { + u32 mode; + s32 band; + u32 channel; + struct wlc_ssid ssid; + struct wl_security sec; + struct wl_ibss ibss; + u8 bssid[ETHER_ADDR_LEN]; + u16 beacon_interval; + u8 dtim_period; + bool active; +}; + +struct net_info { + struct net_device *ndev; + struct wireless_dev *wdev; + struct wl_profile profile; + s32 mode; + s32 roam_off; + unsigned long sme_state; + bool pm_restore; + bool pm_block; + s32 pm; + struct list_head list; /* list of all net_info structure */ +}; + +/* association inform */ +#define MAX_REQ_LINE 1024 +struct wl_connect_info { + u8 req_ie[MAX_REQ_LINE]; + s32 req_ie_len; + u8 resp_ie[MAX_REQ_LINE]; + s32 resp_ie_len; +}; + +/* firmware /nvram downloading controller */ +struct wl_fw_ctrl { + const struct firmware *fw_entry; + unsigned long status; + u32 ptr; + s8 fw_name[WL_FILE_NAME_MAX]; + s8 nvram_name[WL_FILE_NAME_MAX]; +}; + +/* assoc ie length */ +struct wl_assoc_ielen { + u32 req_len; + u32 resp_len; +}; + +/* wpa2 pmk list */ +struct wl_pmk_list { + pmkid_list_t pmkids; + pmkid_t foo[MAXPMKID - 1]; +}; + + +#define ESCAN_BUF_SIZE (64 * 1024) + +struct escan_info { + u32 escan_state; +#if defined(STATIC_WL_PRIV_STRUCT) +#ifndef CONFIG_DHD_USE_STATIC_BUF +#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + u8 *escan_buf; +#else + u8 escan_buf[ESCAN_BUF_SIZE]; +#endif /* STATIC_WL_PRIV_STRUCT */ + struct wiphy *wiphy; + struct net_device *ndev; +}; + +#ifdef ESCAN_BUF_OVERFLOW_MGMT +#define BUF_OVERFLOW_MGMT_COUNT 3 +typedef struct { + int RSSI; + int length; + struct ether_addr BSSID; +} removal_element_t; +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + +struct ap_info { +/* Structure to hold WPS, WPA IEs for a AP */ + u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN]; + u8 beacon_ie[VNDR_IES_MAX_BUF_LEN]; + u8 assoc_res_ie[VNDR_IES_MAX_BUF_LEN]; + u32 probe_res_ie_len; + u32 beacon_ie_len; + u32 assoc_res_ie_len; + u8 *wpa_ie; + u8 *rsn_ie; + u8 *wps_ie; + bool security_mode; +}; + +struct sta_info { + /* Structure to hold WPS IE for a STA */ + u8 probe_req_ie[VNDR_IES_BUF_LEN]; + u8 assoc_req_ie[VNDR_IES_BUF_LEN]; + u32 probe_req_ie_len; + u32 assoc_req_ie_len; +}; + +struct afx_hdl { + wl_af_params_t *pending_tx_act_frm; + struct ether_addr tx_dst_addr; + struct net_device *dev; + struct work_struct work; + u32 bssidx; + u32 retry; + s32 peer_chan; + s32 peer_listen_chan; /* search channel: configured by upper layer */ + s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */ + bool is_listen; + bool ack_recv; + bool is_active; +}; + +struct parsed_ies { + wpa_ie_fixed_t *wps_ie; + u32 wps_ie_len; + wpa_ie_fixed_t *wpa_ie; + u32 wpa_ie_len; + bcm_tlv_t *wpa2_ie; + u32 wpa2_ie_len; +}; + + +#ifdef WL11U +/* Max length of Interworking element */ +#define IW_IES_MAX_BUF_LEN 9 +#endif +#ifdef WLFBT +#define FBT_KEYLEN 32 +#endif +#define MAX_EVENT_BUF_NUM 16 +typedef struct wl_eventmsg_buf { + u16 num; + struct { + u16 type; + bool set; + } event [MAX_EVENT_BUF_NUM]; +} wl_eventmsg_buf_t; + +typedef struct wl_if_event_info { + bool valid; + int ifidx; + int bssidx; + uint8 mac[ETHER_ADDR_LEN]; + char name[IFNAMSIZ+1]; +} wl_if_event_info; + +/* private data of cfg80211 interface */ +struct bcm_cfg80211 { + struct wireless_dev *wdev; /* representing cfg cfg80211 device */ + + struct wireless_dev *p2p_wdev; /* representing cfg cfg80211 device for P2P */ + struct net_device *p2p_net; /* reference to p2p0 interface */ + + struct wl_conf *conf; + struct cfg80211_scan_request *scan_request; /* scan request object */ + EVENT_HANDLER evt_handler[WLC_E_LAST]; + struct list_head eq_list; /* used for event queue */ + struct list_head net_list; /* used for struct net_info */ + spinlock_t eq_lock; /* for event queue synchronization */ + spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ + struct completion act_frm_scan; + struct completion iface_disable; + struct completion wait_next_af; + struct mutex usr_sync; /* maily for up/down synchronization */ + struct wl_scan_results *bss_list; + struct wl_scan_results *scan_results; + + /* scan request object for internal purpose */ + struct wl_scan_req *scan_req_int; + /* information element object for internal purpose */ +#if defined(STATIC_WL_PRIV_STRUCT) + struct wl_ie *ie; +#else + struct wl_ie ie; +#endif + + /* association information container */ +#if defined(STATIC_WL_PRIV_STRUCT) + struct wl_connect_info *conn_info; +#else + struct wl_connect_info conn_info; +#endif +#ifdef DEBUGFS_CFG80211 + struct dentry *debugfs; +#endif /* DEBUGFS_CFG80211 */ + struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ + tsk_ctl_t event_tsk; /* task of main event handler thread */ + void *pub; + u32 iface_cnt; + u32 channel; /* current channel */ + u32 af_sent_channel; /* channel action frame is sent */ + /* next af subtype to cancel the remained dwell time in rx process */ + u8 next_af_subtype; +#ifdef WL_CFG80211_SYNC_GON + ulong af_tx_sent_jiffies; +#endif /* WL_CFG80211_SYNC_GON */ + struct escan_info escan_info; /* escan information */ + bool active_scan; /* current scan mode */ + bool ibss_starter; /* indicates this sta is ibss starter */ + bool link_up; /* link/connection up flag */ + + /* indicate whether chip to support power save mode */ + bool pwr_save; + bool roam_on; /* on/off switch for self-roaming */ + bool scan_tried; /* indicates if first scan attempted */ +#if defined(BCMSDIO) || defined(BCMPCIE) + bool wlfc_on; +#endif + bool vsdb_mode; + bool roamoff_on_concurrent; + u8 *ioctl_buf; /* ioctl buffer */ + struct mutex ioctl_buf_sync; + u8 *escan_ioctl_buf; + u8 *extra_buf; /* maily to grab assoc information */ + struct dentry *debugfsdir; + struct rfkill *rfkill; + bool rf_blocked; + struct ieee80211_channel remain_on_chan; + enum nl80211_channel_type remain_on_chan_type; + u64 send_action_id; + u64 last_roc_id; + wait_queue_head_t netif_change_event; + wl_if_event_info if_event_info; + struct completion send_af_done; + struct afx_hdl *afx_hdl; + struct ap_info *ap_info; + struct sta_info *sta_info; + struct p2p_info *p2p; + bool p2p_supported; + void *btcoex_info; + struct timer_list scan_timeout; /* Timer for catch scan event timeout */ + s32(*state_notifier) (struct bcm_cfg80211 *cfg, + struct net_info *_net_info, enum wl_status state, bool set); + unsigned long interrested_state; + wlc_ssid_t hostapd_ssid; +#ifdef WL11U + bool wl11u; + u8 iw_ie[IW_IES_MAX_BUF_LEN]; + u32 iw_ie_len; +#endif /* WL11U */ + bool sched_scan_running; /* scheduled scan req status */ +#ifdef WL_SCHED_SCAN + struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ +#endif /* WL_SCHED_SCAN */ +#ifdef WL_HOST_BAND_MGMT + u8 curr_band; +#endif /* WL_HOST_BAND_MGMT */ + bool scan_suppressed; + struct timer_list scan_supp_timer; + struct work_struct wlan_work; + struct mutex event_sync; /* maily for up/down synchronization */ + bool disable_roam_event; + bool pm_enable_work_on; + struct delayed_work pm_enable_work; + vndr_ie_setbuf_t *ibss_vsie; /* keep the VSIE for IBSS */ + int ibss_vsie_len; +#ifdef WLAIBSS + u32 aibss_txfail_pid; + u32 aibss_txfail_seq; +#endif /* WLAIBSS */ + u32 rmc_event_pid; + u32 rmc_event_seq; +#ifdef WLAIBSS_MCHAN + struct ether_addr ibss_if_addr; + bcm_struct_cfgdev *ibss_cfgdev; /* For AIBSS */ +#endif /* WLAIBSS_MCHAN */ + bcm_struct_cfgdev *bss_cfgdev; /* For DUAL STA/STA+AP */ + s32 cfgdev_bssidx; + bool bss_pending_op; /* indicate where there is a pending IF operation */ +#ifdef WLFBT + uint8 fbt_key[FBT_KEYLEN]; +#endif + int roam_offload; + bool nan_enable; + bool nan_running; +#ifdef WLTDLS + u8 *tdls_mgmt_frame; + u32 tdls_mgmt_frame_len; + s32 tdls_mgmt_freq; +#endif /* WLTDLS */ + bool need_wait_afrx; +}; + + +static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) +{ + return bss = bss ? + (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; +} +static inline s32 +wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev, + struct wireless_dev * wdev, s32 mode, bool pm_block) +{ + struct net_info *_net_info; + s32 err = 0; + if (cfg->iface_cnt == IFACE_MAX_CNT) + return -ENOMEM; + _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL); + if (!_net_info) + err = -ENOMEM; + else { + _net_info->mode = mode; + _net_info->ndev = ndev; + _net_info->wdev = wdev; + _net_info->pm_restore = 0; + _net_info->pm = 0; + _net_info->pm_block = pm_block; + _net_info->roam_off = WL_INVALID; + cfg->iface_cnt++; + list_add(&_net_info->list, &cfg->net_list); + } + return err; +} +static inline void +wl_dealloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) { + list_del(&_net_info->list); + cfg->iface_cnt--; + kfree(_net_info); + } + } + +} +static inline void +wl_delete_all_netinfo(struct bcm_cfg80211 *cfg) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + list_del(&_net_info->list); + if (_net_info->wdev) + kfree(_net_info->wdev); + kfree(_net_info); + } + cfg->iface_cnt = 0; +} +static inline u32 +wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status) + +{ + struct net_info *_net_info, *next; + u32 cnt = 0; + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (_net_info->ndev && + test_bit(status, &_net_info->sme_state)) + cnt++; + } + return cnt; +} +static inline void +wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op) +{ + struct net_info *_net_info, *next; + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + switch (op) { + case 1: + return; /* set all status is not allowed */ + case 2: + clear_bit(status, &_net_info->sme_state); + if (cfg->state_notifier && + test_bit(status, &(cfg->interrested_state))) + cfg->state_notifier(cfg, _net_info, status, false); + break; + case 4: + return; /* change all status is not allowed */ + default: + return; /* unknown operation */ + } + } +} +static inline void +wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, + struct net_device *ndev, u32 op) +{ + + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) { + switch (op) { + case 1: + set_bit(status, &_net_info->sme_state); + if (cfg->state_notifier && + test_bit(status, &(cfg->interrested_state))) + cfg->state_notifier(cfg, _net_info, status, true); + break; + case 2: + clear_bit(status, &_net_info->sme_state); + if (cfg->state_notifier && + test_bit(status, &(cfg->interrested_state))) + cfg->state_notifier(cfg, _net_info, status, false); + break; + case 4: + change_bit(status, &_net_info->sme_state); + break; + } + } + + } + +} + +static inline u32 +wl_get_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, + struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return test_bit(status, &_net_info->sme_state); + } + return 0; +} + +static inline s32 +wl_get_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return _net_info->mode; + } + return -1; +} + + +static inline void +wl_set_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev, + s32 mode) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + _net_info->mode = mode; + } +} +static inline struct wl_profile * +wl_get_profile_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return &_net_info->profile; + } + return NULL; +} +static inline struct net_info * +wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return _net_info; + } + return NULL; +} +#define bcmcfg_to_wiphy(cfg) (cfg->wdev->wiphy) +#define bcmcfg_to_prmry_ndev(cfg) (cfg->wdev->netdev) +#define bcmcfg_to_prmry_wdev(cfg) (cfg->wdev) +#define bcmcfg_to_p2p_wdev(cfg) (cfg->p2p_wdev) +#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) +#define ndev_to_wdev(ndev) (ndev->ieee80211_ptr) +#define wdev_to_ndev(wdev) (wdev->netdev) + +#if defined(WL_ENABLE_P2P_IF) +#define ndev_to_wlc_ndev(ndev, cfg) ((ndev == cfg->p2p_net) ? \ + bcmcfg_to_prmry_ndev(cfg) : ndev) +#else +#define ndev_to_wlc_ndev(ndev, cfg) (ndev) +#endif /* WL_ENABLE_P2P_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define wdev_to_wlc_ndev(wdev, cfg) \ + ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) ? \ + bcmcfg_to_prmry_ndev(cfg) : wdev_to_ndev(wdev)) +#define cfgdev_to_wlc_ndev(cfgdev, cfg) wdev_to_wlc_ndev(cfgdev, cfg) +#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_wdev(cfg) +#elif defined(WL_ENABLE_P2P_IF) +#define cfgdev_to_wlc_ndev(cfgdev, cfg) ndev_to_wlc_ndev(cfgdev, cfg) +#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_ndev(cfg) +#else +#define cfgdev_to_wlc_ndev(cfgdev, cfg) (cfgdev) +#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) (cfgdev) +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define ndev_to_cfgdev(ndev) ndev_to_wdev(ndev) +#define cfgdev_to_ndev(cfgdev) cfgdev ? (cfgdev->netdev) : NULL +#define discover_cfgdev(cfgdev, cfg) (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) +#else +#define ndev_to_cfgdev(ndev) (ndev) +#define cfgdev_to_ndev(cfgdev) (cfgdev) +#define discover_cfgdev(cfgdev, cfg) (cfgdev == cfg->p2p_net) +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \ + (cfg->scan_request->wdev == cfg->p2p_wdev)) ? true : false) +#elif defined(WL_ENABLE_P2P_IF) +#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \ + (cfg->scan_request->dev == cfg->p2p_net)) ? true : false) +#else +#define scan_req_match(cfg) (((cfg) && p2p_is_on(cfg) && p2p_scan(cfg)) ? \ + true : false) +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#define wl_to_sr(w) (w->scan_req_int) +#if defined(STATIC_WL_PRIV_STRUCT) +#define wl_to_ie(w) (w->ie) +#define wl_to_conn(w) (w->conn_info) +#else +#define wl_to_ie(w) (&w->ie) +#define wl_to_conn(w) (&w->conn_info) +#endif +#define wiphy_from_scan(w) (w->escan_info.wiphy) +#define wl_get_drv_status_all(cfg, stat) \ + (wl_get_status_all(cfg, WL_STATUS_ ## stat)) +#define wl_get_drv_status(cfg, stat, ndev) \ + (wl_get_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev)) +#define wl_set_drv_status(cfg, stat, ndev) \ + (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 1)) +#define wl_clr_drv_status(cfg, stat, ndev) \ + (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 2)) +#define wl_clr_drv_status_all(cfg, stat) \ + (wl_set_status_all(cfg, WL_STATUS_ ## stat, 2)) +#define wl_chg_drv_status(cfg, stat, ndev) \ + (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 4)) + +#define for_each_bss(list, bss, __i) \ + for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) + +#define for_each_ndev(cfg, iter, next) \ + list_for_each_entry_safe(iter, next, &cfg->net_list, list) + + +/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0. + * In addtion to that, wpa_version is WPA_VERSION_1 + */ +#define is_wps_conn(_sme) \ + ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \ + (!_sme->crypto.n_ciphers_pairwise) && \ + (!_sme->crypto.cipher_group)) +extern s32 wl_cfg80211_attach(struct net_device *ndev, void *context); +extern s32 wl_cfg80211_attach_post(struct net_device *ndev); +extern void wl_cfg80211_detach(void *para); + +extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, + void *data); +void wl_cfg80211_set_parent_dev(void *dev); +struct device *wl_cfg80211_get_parent_dev(void); + +extern s32 wl_cfg80211_up(void *para); +extern s32 wl_cfg80211_down(void *para); +extern s32 wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx); +extern s32 wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx); +extern s32 wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx); +extern struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, + uint8 *mac, uint8 bssidx); +extern int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev); +extern int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev); +extern int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev); +extern bool wl_cfg80211_is_vsdb_mode(void); +extern void* wl_cfg80211_get_dhdp(void); +extern bool wl_cfg80211_is_p2p_active(void); +extern void wl_cfg80211_dbg_level(u32 level); +extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); +extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len); +extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); +extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, + enum wl_management_type type); +extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); + +/* btcoex functions */ +void* wl_cfg80211_btcoex_init(struct net_device *ndev); +void wl_cfg80211_btcoex_deinit(void); + + +#ifdef WL_SUPPORT_AUTO_CHANNEL +#define CHANSPEC_BUF_SIZE 1024 +#define CHAN_SEL_IOCTL_DELAY 300 +#define CHAN_SEL_RETRY_COUNT 15 +#define CHANNEL_IS_RADAR(channel) (((channel & WL_CHAN_RADAR) || \ + (channel & WL_CHAN_PASSIVE)) ? true : false) +#define CHANNEL_IS_2G(channel) (((channel >= 1) && (channel <= 14)) ? \ + true : false) +#define CHANNEL_IS_5G(channel) (((channel >= 36) && (channel <= 165)) ? \ + true : false) +extern s32 wl_cfg80211_get_best_channels(struct net_device *dev, char* command, + int total_len); +#endif /* WL_SUPPORT_AUTO_CHANNEL */ + +extern int wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n); +extern int wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str); +extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); +extern s32 wl_mode_to_nl80211_iftype(s32 mode); +int wl_cfg80211_do_driver_init(struct net_device *net); +void wl_cfg80211_enable_trace(bool set, u32 level); +extern s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify); +extern s32 wl_cfg80211_if_is_group_owner(void); +extern chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec); +extern chanspec_t wl_ch_host_to_driver(u16 channel); +extern s32 wl_set_tx_power(struct net_device *dev, + enum nl80211_tx_power_setting type, s32 dbm); +extern s32 wl_get_tx_power(struct net_device *dev, s32 *dbm); +extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); +extern void wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev); +#ifdef WL_HOST_BAND_MGMT +extern s32 wl_cfg80211_set_band(struct net_device *ndev, int band); +#endif /* WL_HOST_BAND_MGMT */ +extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set); +extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, + struct bcm_cfg80211 *cfg, wl_eventmsg_buf_t *ev); +extern void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac); +extern void wl_cfg80211_update_power_mode(struct net_device *dev); +extern void wl_reinit_event_handler(void); + +#define SCAN_BUF_CNT 2 +#define SCAN_BUF_NEXT 1 +#define WL_SCANTYPE_LEGACY 0x1 +#define WL_SCANTYPE_P2P 0x2 +#define wl_escan_set_sync_id(a, b) ((a) = htod16(0x1234)) +#define wl_escan_set_type(a, b) +#define wl_escan_get_buf(a, b) ((wl_scan_results_t *) (a)->escan_info.escan_buf) +#define wl_escan_check_sync_id(a, b, c) 0 +#define wl_escan_print_sync_id(a, b, c) +#define wl_escan_increment_sync_id(a, b) +#define wl_escan_init_sync_id(a) +extern void wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len); +extern s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev); +#ifdef WLAIBSS +extern void wl_cfg80211_set_txfail_pid(int pid); +#endif /* WLAIBSS */ +extern void wl_cfg80211_set_rmc_pid(int pid); + +#ifdef WLFBT +extern void wl_cfg80211_get_fbt_key(uint8 *key); +#endif + +/* Action frame specific functions */ +extern u8 wl_get_action_category(void *frame, u32 frame_len); +extern int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action); + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +struct net_device *wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +#ifdef WL_SUPPORT_ACS +#define ACS_MSRMNT_DELAY 1000 /* dump_obss delay in ms */ +#define IOCTL_RETRY_COUNT 5 +#define CHAN_NOISE_DUMMY -80 +#define OBSS_TOKEN_IDX 15 +#define IBSS_TOKEN_IDX 15 +#define TX_TOKEN_IDX 14 +#define CTG_TOKEN_IDX 13 +#define PKT_TOKEN_IDX 15 +#define IDLE_TOKEN_IDX 12 +#endif /* WL_SUPPORT_ACS */ + +extern int wl_cfg80211_get_ioctl_version(void); +extern int wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable); + + +#ifdef WL_CFG80211_P2P_DEV_IF +extern void wl_cfg80211_del_p2p_wdev(void); +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#define RETURN_EIO_IF_NOT_UP(wlpriv) \ +do { \ + struct net_device *checkSysUpNDev = bcmcfg_to_prmry_ndev(wlpriv); \ + if (unlikely(!wl_get_drv_status(wlpriv, READY, checkSysUpNDev))) { \ + WL_INFORM(("device is not ready\n")); \ + return -EIO; \ + } \ +} while (0) + +#endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg_btcoex.c new file mode 100644 index 000000000000..1706c4a82033 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg_btcoex.c @@ -0,0 +1,554 @@ +/* + * Linux cfg80211 driver - Dongle Host Driver (DHD) related + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg_btcoex.c 701287 2017-05-24 10:33:19Z $ + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PKT_FILTER_SUPPORT +extern uint dhd_pkt_filter_enable; +extern uint dhd_master_mode; +extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); +#endif + +struct btcoex_info { + struct timer_list timer; + u32 timer_ms; + u32 timer_on; + u32 ts_dhcp_start; /* ms ts ecord time stats */ + u32 ts_dhcp_ok; /* ms ts ecord time stats */ + bool dhcp_done; /* flag, indicates that host done with + * dhcp before t1/t2 expiration + */ + s32 bt_state; + struct work_struct work; + struct net_device *dev; +}; + +static struct btcoex_info *btcoex_info_loc = NULL; + +/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ + +/* use New SCO/eSCO smart YG suppression */ +#define BT_DHCP_eSCO_FIX +/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ +#define BT_DHCP_USE_FLAGS +/* T1 start SCO/ESCo priority suppression */ +#define BT_DHCP_OPPR_WIN_TIME 2500 +/* T2 turn off SCO/SCO supperesion is (timeout) */ +#define BT_DHCP_FLAG_FORCE_TIME 5500 + +enum wl_cfg80211_btcoex_status { + BT_DHCP_IDLE, + BT_DHCP_START, + BT_DHCP_OPPR_WIN, + BT_DHCP_FLAG_FORCE_TIMEOUT +}; + +/* + * get named driver variable to uint register value and return error indication + * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) + */ +static int +dev_wlc_intvar_get_reg(struct net_device *dev, char *name, + uint reg, int *retval) +{ + union { + char buf[WLC_IOCTL_SMLEN]; + int val; + } var; + int error; + + memset(&var, 0, sizeof(var)); + error = bcm_mkiovar(name, (char *)(®), sizeof(reg), + (char *)(&var), sizeof(var.buf)); + if (error == 0) { + return BCME_BUFTOOSHORT; + } + error = wldev_ioctl_get(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf)); + + *retval = dtoh32(var.val); + return (error); +} + +static int +dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) +{ + char ioctlbuf_local[WLC_IOCTL_SMLEN]; + int ret; + + memset(ioctlbuf_local, 0, sizeof(ioctlbuf_local)); + ret = bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); + + if (ret == 0) + return BCME_BUFTOOSHORT; + + return (wldev_ioctl_set(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local))); +} +/* +get named driver variable to uint register value and return error indication +calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) +*/ +static int +dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) +{ + char reg_addr[8]; + + memset(reg_addr, 0, sizeof(reg_addr)); + memcpy((char *)®_addr[0], (char *)addr, 4); + memcpy((char *)®_addr[4], (char *)val, 4); + + return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); +} + +static bool btcoex_is_sco_active(struct net_device *dev) +{ + int ioc_res = 0; + bool res = FALSE; + int sco_id_cnt = 0; + int param27; + int i; + + for (i = 0; i < 12; i++) { + + ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); + + WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27)); + + if (ioc_res < 0) { + WL_ERR(("ioc read btc params error\n")); + break; + } + + if ((param27 & 0x6) == 2) { /* count both sco & esco */ + sco_id_cnt++; + } + + if (sco_id_cnt > 2) { + WL_TRACE(("sco/esco detected, pkt id_cnt:%d samples:%d\n", + sco_id_cnt, i)); + res = TRUE; + break; + } + + OSL_SLEEP(5); + } + + return res; +} + +#if defined(BT_DHCP_eSCO_FIX) +/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ +static int set_btc_esco_params(struct net_device *dev, bool trump_sco) +{ + static bool saved_status = FALSE; + + char buf_reg50va_dhcp_on[8] = + { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; + char buf_reg51va_dhcp_on[8] = + { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg64va_dhcp_on[8] = + { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg65va_dhcp_on[8] = + { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg71va_dhcp_on[8] = + { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + uint32 regaddr; + static uint32 saved_reg50; + static uint32 saved_reg51; + static uint32 saved_reg64; + static uint32 saved_reg65; + static uint32 saved_reg71; + + if (trump_sco) { + /* this should reduce eSCO agressive retransmit + * w/o breaking it + */ + + /* 1st save current */ + WL_TRACE(("Do new SCO/eSCO coex algo {save &" + "override}\n")); + if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { + saved_status = TRUE; + WL_TRACE(("saved bt_params[50,51,64,65,71]:" + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + saved_reg50, saved_reg51, + saved_reg64, saved_reg65, saved_reg71)); + } else { + WL_ERR((":%s: save btc_params failed\n", + __FUNCTION__)); + saved_status = FALSE; + return -1; + } + + WL_TRACE(("override with [50,51,64,65,71]:" + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + *(u32 *)(buf_reg50va_dhcp_on+4), + *(u32 *)(buf_reg51va_dhcp_on+4), + *(u32 *)(buf_reg64va_dhcp_on+4), + *(u32 *)(buf_reg65va_dhcp_on+4), + *(u32 *)(buf_reg71va_dhcp_on+4))); + + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg50va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg51va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg64va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg65va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg71va_dhcp_on[0], 8); + + saved_status = TRUE; + } else if (saved_status) { + /* restore previously saved bt params */ + WL_TRACE(("Do new SCO/eSCO coex algo {save &" + "override}\n")); + + regaddr = 50; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg50); + regaddr = 51; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg51); + regaddr = 64; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg64); + regaddr = 65; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg65); + regaddr = 71; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg71); + + WL_TRACE(("restore bt_params[50,51,64,65,71]:" + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + saved_reg50, saved_reg51, saved_reg64, + saved_reg65, saved_reg71)); + + saved_status = FALSE; + } else { + WL_ERR((":%s att to restore not saved BTCOEX params\n", + __FUNCTION__)); + return -1; + } + return 0; +} +#endif /* BT_DHCP_eSCO_FIX */ + +static void +wl_cfg80211_bt_setflag(struct net_device *dev, bool set) +{ +#if defined(BT_DHCP_USE_FLAGS) + char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; + char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; +#endif + + +#if defined(BT_DHCP_eSCO_FIX) + /* set = 1, save & turn on 0 - off & restore prev settings */ + set_btc_esco_params(dev, set); +#endif + +#if defined(BT_DHCP_USE_FLAGS) + WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); + if (set == TRUE) + /* Forcing bt_flag7 */ + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_dhcp_on[0], + sizeof(buf_flag7_dhcp_on)); + else + /* Restoring default bt flag7 */ + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_default[0], + sizeof(buf_flag7_default)); +#endif +} + +static void wl_cfg80211_bt_timerfunc(ulong data) +{ + struct btcoex_info *bt_local = (struct btcoex_info *)data; + WL_TRACE(("Enter\n")); + bt_local->timer_on = 0; + schedule_work(&bt_local->work); +} + +static void wl_cfg80211_bt_handler(struct work_struct *work) +{ + struct btcoex_info *btcx_inf; + + btcx_inf = container_of(work, struct btcoex_info, work); + + if (btcx_inf->timer_on) { + btcx_inf->timer_on = 0; + del_timer_sync(&btcx_inf->timer); + } + + switch (btcx_inf->bt_state) { + case BT_DHCP_START: + /* DHCP started + * provide OPPORTUNITY window to get DHCP address + */ + WL_TRACE(("bt_dhcp stm: started \n")); + + btcx_inf->bt_state = BT_DHCP_OPPR_WIN; + mod_timer(&btcx_inf->timer, + jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); + btcx_inf->timer_on = 1; + break; + + case BT_DHCP_OPPR_WIN: + if (btcx_inf->dhcp_done) { + WL_TRACE(("DHCP Done before T1 expiration\n")); + goto btc_coex_idle; + } + + /* DHCP is not over yet, start lowering BT priority + * enforce btc_params + flags if necessary + */ + WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME)); + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); + btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; + mod_timer(&btcx_inf->timer, + jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); + btcx_inf->timer_on = 1; + break; + + case BT_DHCP_FLAG_FORCE_TIMEOUT: + if (btcx_inf->dhcp_done) { + WL_TRACE(("DHCP Done before T2 expiration\n")); + } else { + /* Noo dhcp during T1+T2, restore BT priority */ + WL_TRACE(("DHCP wait interval T2:%d msec expired\n", + BT_DHCP_FLAG_FORCE_TIME)); + } + + /* Restoring default bt priority */ + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); +btc_coex_idle: + btcx_inf->bt_state = BT_DHCP_IDLE; + btcx_inf->timer_on = 0; + break; + + default: + WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state)); + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); + btcx_inf->bt_state = BT_DHCP_IDLE; + btcx_inf->timer_on = 0; + break; + } + + net_os_wake_unlock(btcx_inf->dev); +} + +void* wl_cfg80211_btcoex_init(struct net_device *ndev) +{ + struct btcoex_info *btco_inf = NULL; + + btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); + if (!btco_inf) + return NULL; + + btco_inf->bt_state = BT_DHCP_IDLE; + btco_inf->ts_dhcp_start = 0; + btco_inf->ts_dhcp_ok = 0; + /* Set up timer for BT */ + btco_inf->timer_ms = 10; + init_timer(&btco_inf->timer); + btco_inf->timer.data = (ulong)btco_inf; + btco_inf->timer.function = wl_cfg80211_bt_timerfunc; + + btco_inf->dev = ndev; + + INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); + + btcoex_info_loc = btco_inf; + return btco_inf; +} + +void wl_cfg80211_btcoex_deinit() +{ + if (!btcoex_info_loc) + return; + + if (btcoex_info_loc->timer_on) { + btcoex_info_loc->timer_on = 0; + del_timer_sync(&btcoex_info_loc->timer); + } + + cancel_work_sync(&btcoex_info_loc->work); + + kfree(btcoex_info_loc); +} + +int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command) +{ + + struct btcoex_info *btco_inf = btcoex_info_loc; + char powermode_val = 0; + char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; + char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; + char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; + + uint32 regaddr; + static uint32 saved_reg66; + static uint32 saved_reg41; + static uint32 saved_reg68; + static bool saved_status = FALSE; + + char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; + + /* Figure out powermode 1 or o command */ + strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); + + if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { + WL_TRACE_HW4(("DHCP session starts\n")); + + +#ifdef PKT_FILTER_SUPPORT + dhd->dhcp_in_progress = 1; + + if (dhd->early_suspended) { + WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n")); + dhd_enable_packet_filter(0, dhd); + } +#endif + + /* Retrieve and saved orig regs value */ + if ((saved_status == FALSE) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { + saved_status = TRUE; + WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", + saved_reg66, saved_reg41, saved_reg68)); + + /* Disable PM mode during dhpc session */ + + /* Disable PM mode during dhpc session */ + /* Start BT timer only for SCO connection */ + if (btcoex_is_sco_active(dev)) { + /* btc_params 66 */ + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg66va_dhcp_on[0], + sizeof(buf_reg66va_dhcp_on)); + /* btc_params 41 0x33 */ + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg41va_dhcp_on[0], + sizeof(buf_reg41va_dhcp_on)); + /* btc_params 68 0x190 */ + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg68va_dhcp_on[0], + sizeof(buf_reg68va_dhcp_on)); + saved_status = TRUE; + + btco_inf->bt_state = BT_DHCP_START; + btco_inf->timer_on = 1; + mod_timer(&btco_inf->timer, btco_inf->timer.expires); + WL_TRACE(("enable BT DHCP Timer\n")); + } + } + else if (saved_status == TRUE) { + WL_ERR(("was called w/o DHCP OFF. Continue\n")); + } + } + else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { + + + +#ifdef PKT_FILTER_SUPPORT + dhd->dhcp_in_progress = 0; + WL_TRACE_HW4(("DHCP is complete \n")); + + /* Enable packet filtering */ + if (dhd->early_suspended) { + WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); + dhd_enable_packet_filter(1, dhd); + } +#endif /* PKT_FILTER_SUPPORT */ + + /* Restoring PM mode */ + + /* Stop any bt timer because DHCP session is done */ + WL_TRACE(("disable BT DHCP Timer\n")); + if (btco_inf->timer_on) { + btco_inf->timer_on = 0; + del_timer_sync(&btco_inf->timer); + + if (btco_inf->bt_state != BT_DHCP_IDLE) { + /* need to restore original btc flags & extra btc params */ + WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state)); + /* wake up btcoex thread to restore btlags+params */ + schedule_work(&btco_inf->work); + } + } + + /* Restoring btc_flag paramter anyway */ + if (saved_status == TRUE) + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); + + /* Restore original values */ + if (saved_status == TRUE) { + regaddr = 66; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg66); + regaddr = 41; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg41); + regaddr = 68; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg68); + + WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", + saved_reg66, saved_reg41, saved_reg68)); + } + saved_status = FALSE; + + } + else { + WL_ERR(("Unkwown yet power setting, ignored\n")); + } + + snprintf(command, 3, "OK"); + + return (strlen("OK")); +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.c new file mode 100644 index 000000000000..ae2466d8cd74 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.c @@ -0,0 +1,2060 @@ +/* + * Neighbor Awareness Networking + * + * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgnan.c 487532 2014-06-26 05:09:36Z $ + */ + +/** + * @file + * @brief + * NAN (Neighbor Awareness Networking) is to provide a low-power mechanism + * that will run in the background to make the devices neighbor aware. NAN + * enables mobile devices to efficiently discover devices and services in + * their proximity. The purpose of NAN is only to discover device and its + * services. Then it is handed over to post NAN discovery and connection + * is established using the actual service data channel (e.g., WLAN + * infrastructure, P2P, IBSS, etc.) + */ + + +#include +#include +#include +#include + +#include +#include +#include + +#ifdef WL_NAN_DEBUG +static u8 g_nan_debug = true; +#else +static u8 g_nan_debug = false; +#endif /* WL_NAN_DEBUG */ + +static nan_cmd_t nan_cmds [] = { + { "NAN_START", wl_cfgnan_start_handler }, + { "NAN_STOP", wl_cfgnan_stop_handler }, + { "NAN_SUPPORT", wl_cfgnan_support_handler }, + { "NAN_STATUS", wl_cfgnan_status_handler }, + { "NAN_PUBLISH", wl_cfgnan_pub_handler }, + { "NAN_SUBSCRIBE", wl_cfgnan_sub_handler }, + { "NAN_CANCEL_PUBLISH", wl_cfgnan_cancel_pub_handler }, + { "NAN_CANCEL_SUBSCRIBE", wl_cfgnan_cancel_sub_handler }, + { "NAN_TRANSMIT", wl_cfgnan_transmit_handler }, + { "NAN_SET_CONFIG", wl_cfgnan_set_config_handler }, + { "NAN_GET_CONFIG", NULL }, + { "NAN_RTT_CONFIG", wl_cfgnan_rtt_config_handler }, + { "NAN_RTT_FIND", wl_cfgnan_rtt_find_handler }, + { "NAN_DEBUG", wl_cfgnan_debug_handler }, +#ifdef NAN_P2P_CONFIG + { "NAN_ADD_CONF", wl_cfgnan_p2p_ie_add_handler }, + { "NAN_ENABLE_CONF", wl_cfgnan_p2p_ie_enable_handler }, + { "NAN_DEL_CONF", wl_cfgnan_p2p_ie_del_handler }, +#endif /* NAN_P2P_CONFIG */ + { NULL, NULL }, +}; + +static nan_config_attr_t nan_config_attrs [] = { + { "ATTR_MASTER", WL_NAN_XTLV_MASTER_PREF }, + { "ATTR_ID", WL_NAN_XTLV_CLUSTER_ID }, + { "ATTR_ADDR", WL_NAN_XTLV_IF_ADDR }, + { "ATTR_ROLE", WL_NAN_XTLV_ROLE }, + { "ATTR_BCN_INT", WL_NAN_XTLV_BCN_INTERVAL }, + { "ATTR_CHAN", WL_NAN_XTLV_MAC_CHANSPEC }, + { "ATTR_TX_RATE", WL_NAN_XTLV_MAC_TXRATE }, + { "ATTR_DW_LEN", WL_NAN_XTLV_DW_LEN }, + { {0}, 0 } +}; + +static char nan_event_str[][NAN_EVENT_STR_MAX_LEN] = { + "NAN-INVALID", + "NAN-STARTED", + "NAN-JOINED", + "NAN-ROLE-CHANGE", + "NAN-SCAN-COMPLETE", + "NAN-SDF-RX", + "NAN-REPLIED", + "NAN-TERMINATED", + "NAN-FOLLOWUP-RX", + "NAN-STATUS-CHANGE", + "NAN-MERGED", + "NAN-STOPPED" + "NAN-INVALID", +#ifdef NAN_P2P_CONFIG + "NAN-P2P-RX", +#endif /* NAN_P2P_CONFIG */ +}; + +static char nan_event_name[][NAN_EVENT_NAME_MAX_LEN] = { + "WL_NAN_EVENT_INVALID", + "WL_NAN_EVENT_START", + "WL_NAN_EVENT_JOIN", + "WL_NAN_EVENT_ROLE", + "WL_NAN_EVENT_SCAN_COMPLETE", + "WL_NAN_EVENT_DISCOVERY_RESULT", + "WL_NAN_EVENT_REPLIED", + "WL_NAN_EVENT_TERMINATED", + "WL_NAN_EVENT_RECEIVE", + "WL_NAN_EVENT_STATUS_CHG", + "WL_NAN_EVENT_MERGE", + "WL_NAN_EVENT_STOP", +#ifdef NAN_P2P_CONFIG + "WL_NAN_EVENT_P2P", +#endif /* NAN_P2P_CONFIG */ + "WL_NAN_EVENT_INVALID" +}; + +int +wl_cfgnan_set_vars_cbfn(void *ctx, void **tlv_buf, uint16 type, uint16 len) +{ + wl_nan_tlv_data_t *ndata = ((wl_nan_tlv_data_t *)(ctx)); + bcm_xtlv_t *ptlv; + struct ether_addr mac; + int ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint8 uv8; + char buf[64]; + + WL_DBG((" enter, xtlv_type: 0x%x \n", type)); + + switch (type) { + case WL_NAN_XTLV_ENABLE: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_ENABLE, + sizeof(uv8), &ndata->enabled); + break; + case WL_NAN_XTLV_MASTER_PREF: + /* + * master role and preference mac has them as two u8's, + * + * masterpref: val & 0x0ff + * rnd_factor: val >> 8 + */ + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MASTER_PREF, + sizeof(uint16), &ndata->master_pref); + break; + case WL_NAN_XTLV_IF_ADDR: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_IF_ADDR, + ETHER_ADDR_LEN, &mac); + memcpy(&ndata->mac_addr, &mac, ETHER_ADDR_LEN); + break; + case WL_NAN_XTLV_CLUSTER_ID: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_CLUSTER_ID, + ETHER_ADDR_LEN, &mac); + memcpy(&ndata->clus_id, &mac, ETHER_ADDR_LEN); + break; + case WL_NAN_XTLV_ROLE: + /* nan device role, master, master-sync nosync etc */ + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_ROLE, 4, + &ndata->dev_role); + break; + case WL_NAN_XTLV_MAC_CHANSPEC: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_CHANSPEC, + sizeof(chanspec_t), &ndata->chanspec); + if (wf_chspec_valid(ndata->chanspec)) { + wf_chspec_ntoa(ndata->chanspec, buf); + WL_DBG((" chanspec: %s 0x%x \n", buf, ndata->chanspec)); + } else { + WL_DBG((" chanspec: 0x%x is not valid \n", ndata->chanspec)); + } + break; + case WL_NAN_XTLV_MAC_AMR: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_AMR, + NAN_MASTER_RANK_LEN, buf); + memcpy(ndata->amr, buf, NAN_MASTER_RANK_LEN); + break; + case WL_NAN_XTLV_MAC_AMBTT: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_AMBTT, + sizeof(uint32), &ndata->ambtt); + break; + case WL_NAN_XTLV_MAC_HOPCNT: + ret = bcm_unpack_xtlv_entry(tlv_buf, + WL_NAN_XTLV_MAC_HOPCNT, sizeof(uint8), &ndata->hop_count); + break; + case WL_NAN_XTLV_INSTANCE_ID: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_INSTANCE_ID, + sizeof(wl_nan_instance_id_t), &ndata->inst_id); + break; + case WL_NAN_XTLV_SVC_NAME: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_SVC_NAME, + WL_NAN_SVC_HASH_LEN, ndata->svc_name); + break; + case WL_NAN_XTLV_SVC_PARAMS: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_SVC_PARAMS, + sizeof(wl_nan_disc_params_t), &ndata->params); + break; + case WL_NAN_XTLV_MAC_STATUS: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_STATUS, + sizeof(wl_nan_status_t), &ndata->nstatus); + break; + case WL_NAN_XTLV_PUBLR_ID: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_PUBLR_ID, + sizeof(uint8), &ndata->pub_id); + break; + case WL_NAN_XTLV_SUBSCR_ID: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_SUBSCR_ID, + sizeof(uint8), &ndata->sub_id); + break; + case WL_NAN_XTLV_MAC_ADDR: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_MAC_ADDR, + ETHER_ADDR_LEN, &mac); + memcpy(&ndata->mac_addr, &mac, ETHER_ADDR_LEN); + break; + case WL_NAN_XTLV_VNDR: + ptlv = *tlv_buf; + ndata->vend_info.dlen = BCM_XTLV_LEN(ptlv); + ndata->vend_info.data = kzalloc(ndata->vend_info.dlen, kflags); + if (!ndata->vend_info.data) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + if (ndata->vend_info.data && ndata->vend_info.dlen) { + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_VNDR, + ndata->vend_info.dlen, ndata->vend_info.data); + } + break; + case WL_NAN_XTLV_SVC_INFO: + ptlv = *tlv_buf; + ndata->svc_info.dlen = BCM_XTLV_LEN(ptlv); + ndata->svc_info.data = kzalloc(ndata->svc_info.dlen, kflags); + if (!ndata->svc_info.data) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + if (ndata->svc_info.data && ndata->svc_info.dlen) { + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_SVC_INFO, + ndata->svc_info.dlen, ndata->svc_info.data); + } + break; + case WL_NAN_XTLV_PEER_INSTANCE_ID: + ret = bcm_unpack_xtlv_entry(tlv_buf, + WL_NAN_XTLV_PEER_INSTANCE_ID, sizeof(wl_nan_instance_id_t), + &ndata->peer_inst_id); + break; + case WL_NAN_XTLV_NAN_SCANPARAMS: + ret = bcm_unpack_xtlv_entry(tlv_buf, WL_NAN_XTLV_NAN_SCANPARAMS, + sizeof(nan_scan_params_t), &ndata->scan_params); + break; + case WL_NAN_XTLV_ZERO: + /* don't parse empty space in the buffer */ + ret = BCME_ERROR; + break; + + default: + /* skip current tlv, if we don't have a handler */ + ret = bcm_skip_xtlv(tlv_buf); + break; + } + +fail: + return ret; +} + +int +wl_cfgnan_enable_events(struct net_device *ndev, struct bcm_cfg80211 *cfg) +{ + wl_nan_ioc_t *nanioc = NULL; + void *pxtlv; + u32 event_mask = 0; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + ret = wl_add_remove_eventmsg(ndev, WLC_E_NAN, true); + if (unlikely(ret)) { + WL_ERR((" nan event enable failed, error = %d \n", ret)); + goto fail; + } + if (g_nan_debug) { + /* enable all nan events */ + event_mask = NAN_EVENT_MASK_ALL; + } else { + /* enable only selected nan events to avoid unnecessary host wake up */ + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_START); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_JOIN); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_DISCOVERY_RESULT); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_RECEIVE); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_TERMINATED); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_STOP); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_CLEAR_BIT); +#ifdef NAN_P2P_CONFIG + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_P2P); +#endif /* NAN_P2P_CONFIG */ + event_mask = htod32(event_mask); + } + + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_EVENT_MASK); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_EVENT_MASK, + sizeof(uint32), &event_mask); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan event selective enable failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan event selective enable successful \n")); + } + + ret = wl_add_remove_eventmsg(ndev, WLC_E_PROXD, true); + if (unlikely(ret)) { + WL_ERR((" proxd event enable failed, error = %d \n", ret)); + goto fail; + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_enable_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + void *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + uint8 val; + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan 1 + * + * wpa_cli: DRIVER NAN_ENABLE + */ + + /* nan enable */ + val = 1; + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_ENABLE); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE, + sizeof(uint8), &val); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan enable failed, error = %d \n", ret)); + goto fail; + } else { + cfg->nan_enable = true; + WL_DBG((" nan enable successful \n")); + } + + /* enable nan events */ + ret = wl_cfgnan_enable_events(ndev, cfg); + if (unlikely(ret)) { + goto fail; + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_start_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + struct ether_addr cluster_id = ether_null; + void *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + uint8 val; + + if (cfg->nan_enable != true) { + ret = wl_cfgnan_enable_handler(ndev, cfg, cmd, cmd_data); + if (unlikely(ret)) { + goto fail; + } + } + + /* + * command to test + * + * wl: wl nan join -start + * + * wpa_cli: DRIVER NAN_START + */ + + /* nan join */ + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + val = 1; + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_NAN_JOIN); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, + ETHER_ADDR_LEN, &cluster_id); + if (unlikely(ret)) { + goto fail; + } + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_START, + sizeof(uint8), &val); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan join failed, error = %d \n", ret)); + goto fail; + } + + WL_DBG((" nan join successful \n")); + cfg->nan_running = true; + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_stop_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + struct ether_addr cluster_id = ether_null; + void *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + uint8 nan_enable = FALSE; + + /* + * command to test + * + * wl: wl nan stop + * wl nan 0 + * + * wpa_cli: DRIVER NAN_STOP + */ + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + if (cfg->nan_running == true) { + /* nan stop */ + + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_STOP); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, + ETHER_ADDR_LEN, &cluster_id); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan stop failed, error = %d \n", ret)); + goto fail; + } else { + cfg->nan_running = false; + WL_DBG((" nan stop successful \n")); + } + } + + /* nan disable */ + if (cfg->nan_enable == true) { + memset(nanioc, 0, nanioc_size); + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_ENABLE); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE, + sizeof(uint8), &nan_enable); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan disable failed, error = %d \n", ret)); + goto fail; + } else { + cfg->nan_enable = false; + WL_DBG((" nan disable successful \n")); + } + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_support_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + void *pxtlv; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan + * + * wpa_cli: DRIVER NAN_SUPPORT + */ + + /* nan support */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_ENABLE); + pxtlv = nanioc->data; + nanioc->len = htod16(BCM_XTLV_HDR_SIZE + 1); + nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); + ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); + if (unlikely(ret)) { + WL_ERR((" nan is not supported, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan is supported \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_status_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + wl_nan_ioc_t *ioc_ret = NULL; + void *pxtlv; + char *ptr = cmd; + wl_nan_tlv_data_t tlv_data; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan status + * + * wpa_cli: DRIVER NAN_STATUS + */ + + /* nan status */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_STATUS); + pxtlv = nanioc->data; + nanioc->len = NAN_IOCTL_BUF_SIZE; + nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); + ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan status failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan status successful \n")); + } + + /* unpack the tlvs */ + memset(&tlv_data, 0, sizeof(tlv_data)); + ioc_ret = (wl_nan_ioc_t *)cfg->ioctl_buf; + if (g_nan_debug) { + prhex(" nanioc->data: ", (uint8 *)ioc_ret->data, ioc_ret->len); + } + bcm_unpack_xtlv_buf(&tlv_data, ioc_ret->data, ioc_ret->len, + wl_cfgnan_set_vars_cbfn); + + ptr += sprintf(ptr, ROLE_PREFIX"%d", tlv_data.dev_role); + ptr += sprintf(ptr, " " AMR_PREFIX); + ptr += bcm_format_hex(ptr, tlv_data.amr, NAN_MASTER_RANK_LEN); + ptr += sprintf(ptr, " " CLUS_ID_PREFIX MACF, ETHER_TO_MACF(tlv_data.clus_id)); + ptr += sprintf(ptr, " " AMBTT_PREFIX"0x%x", tlv_data.ambtt); + ptr += sprintf(ptr, " " HOP_COUNT_PREFIX"%d", tlv_data.hop_count); + + /* nan scan param */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_SCAN_PARAMS); + pxtlv = nanioc->data; + nanioc->len = NAN_IOCTL_BUF_SIZE; + nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); + ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan scan params failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan scan params successful \n")); + } + + /* unpack the tlvs */ + memset(&tlv_data, 0, sizeof(tlv_data)); + ioc_ret = (wl_nan_ioc_t *)cfg->ioctl_buf; + ASSERT(ioc_ret != NULL); + if (g_nan_debug) { + prhex(" nanioc->data: ", (uint8 *)ioc_ret->data, ioc_ret->len); + } + bcm_unpack_xtlv_buf(&tlv_data, ioc_ret->data, ioc_ret->len, + wl_cfgnan_set_vars_cbfn); + + ptr += sprintf(ptr, " " SCAN_PERIOD_PREFIX"%d", + tlv_data.scan_params.ms_dur); + ptr += sprintf(ptr, " " SCAN_INTERVAL_PREFIX"%d", + tlv_data.scan_params.ms_intvl*512); + + WL_DBG((" formatted string for userspace: %s, len: %zu \n", + cmd, strlen(cmd))); + +fail: + if (nanioc) { + kfree(nanioc); + } + if (tlv_data.svc_info.data) { + kfree(tlv_data.svc_info.data); + tlv_data.svc_info.data = NULL; + tlv_data.svc_info.dlen = 0; + } + if (tlv_data.vend_info.data) { + kfree(tlv_data.vend_info.data); + tlv_data.vend_info.data = NULL; + tlv_data.vend_info.dlen = 0; + } + + return ret; +} + + +#ifdef NAN_P2P_CONFIG + +static void +wl_p2p_nan_ioctl_make_header(wl_p2p_nan_ioc_t *p2p_nanioc, uint16 cmd_id, uint16 len) +{ + p2p_nanioc->version = htod16(WL_P2P_NAN_IOCTL_VERSION); + p2p_nanioc->id = cmd_id; + p2p_nanioc->len = htod16(len); +} + +static int +wl_p2p_nan_do_get_ioctl(struct net_device *ndev, struct bcm_cfg80211 *cfg, + wl_p2p_nan_ioc_t *p2p_nanioc, uint16 alloc_size) +{ + wl_p2p_nan_ioc_t *iocresp = NULL; + int res; + uint8 *val; + /* send getbuf p2p nan iovar */ + res = wldev_iovar_getbuf(ndev, "p2p_nan", p2p_nanioc, alloc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + + if (res == BCME_OK) { + iocresp = (wl_p2p_nan_ioc_t *)cfg->ioctl_buf; + if (iocresp == NULL) { + res = BCME_ERROR; + return res; + } + switch (iocresp->id) { + case WL_P2P_NAN_CMD_ENABLE: + val = iocresp->data; + WL_ERR(("wl p2p_nan status is %s\n", + *val == 1? "Enabled":"Disabled")); + break; + case WL_P2P_NAN_CMD_CONFIG: { + wl_p2p_nan_config_t *p_p2p_nan_cfg = + (wl_p2p_nan_config_t *)iocresp->data; + WL_ERR(("wl p2p nan ie len = %u\n", p_p2p_nan_cfg->ie_len)); + prhex("P2P IE", p_p2p_nan_cfg->ie, p_p2p_nan_cfg->ie_len); + } + break; + default: + WL_ERR(("Unknown command %d\n", iocresp->id)); + break; + } + } + return res; +} + + +int wl_cfgnan_p2p_ie_enable_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char* buf, nan_cmd_data_t *cmd_data) { + int res = BCME_OK; + wl_p2p_nan_ioc_t *p2p_nanioc; + uint16 alloc_size = OFFSETOF(wl_p2p_nan_ioc_t, data) + P2P_NAN_IOC_BUFSZ; + void *pdata = NULL; + uint8 val; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + p2p_nanioc = kzalloc(alloc_size, kflags); + if (p2p_nanioc == NULL) { + WL_ERR((" memory allocation failed \n")); + return BCME_NOMEM; + } + + wl_p2p_nan_ioctl_make_header(p2p_nanioc, WL_P2P_NAN_CMD_ENABLE, sizeof(uint8)); + + if (cmd_data->p2p_info.data == NULL) { /* get */ + res = wl_p2p_nan_do_get_ioctl(ndev, cfg, p2p_nanioc, alloc_size); + } else { /* set */ + + val = (uint8) cmd_data->p2p_info.data[0]; + pdata = p2p_nanioc->data; + memcpy(pdata, &val, sizeof(uint8)); + res = wldev_iovar_setbuf(ndev, "p2p_nan", p2p_nanioc, + alloc_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + } + + kfree(p2p_nanioc); + return res; +} +int wl_cfgnan_p2p_ie_add_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) { + int res = BCME_OK; + int ie_len, data_len; + wl_p2p_nan_ioc_t *p2p_nanioc; + uint16 alloc_size = OFFSETOF(wl_p2p_nan_ioc_t, data) + cmd_data->p2p_info.dlen; + wl_p2p_nan_config_t *p_p2p_nan_cfg; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + p2p_nanioc = kzalloc(alloc_size, kflags); + if (p2p_nanioc == NULL) + return BCME_NOMEM; + cmd_data->p2p_info.dlen /= 2; /* Number of hex values will be half of ascii */ + wl_p2p_nan_ioctl_make_header(p2p_nanioc, WL_P2P_NAN_CMD_CONFIG, P2P_NAN_IOC_BUFSZ); + + if (cmd_data->p2p_info.data == NULL) { /* get */ + wl_p2p_nan_do_get_ioctl(ndev, cfg, p2p_nanioc, alloc_size); + } else { + ie_len = cmd_data->p2p_info.dlen; + data_len = OFFSETOF(wl_p2p_nan_config_t, ie) + ie_len; + + p_p2p_nan_cfg = (wl_p2p_nan_config_t *)p2p_nanioc->data; + p_p2p_nan_cfg->version = WL_P2P_NAN_CONFIG_VERSION; + p_p2p_nan_cfg->len = data_len; + p_p2p_nan_cfg->ie_len = ie_len; + + if (!wl_cfg80211_hex_str_to_bin + (p_p2p_nan_cfg->ie, (int)p_p2p_nan_cfg->ie_len, (uchar*)cmd_data->p2p_info.data)) { + res = BCME_BADARG; + goto fail; + } + p2p_nanioc->len = htod16(data_len); + + res = wldev_iovar_setbuf(ndev, "p2p_nan", p2p_nanioc, alloc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + } +fail: + kfree(p2p_nanioc); + return res; +} +int wl_cfgnan_p2p_ie_del_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + int res = BCME_OK; + wl_p2p_nan_ioc_t *p2p_nanioc; + uint16 alloc_size = OFFSETOF(wl_p2p_nan_ioc_t, data); + + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + p2p_nanioc = kzalloc(alloc_size, kflags); + if (p2p_nanioc == NULL) { + WL_ERR((" Memory is not enough\n")); + return BCME_NOMEM; + } + wl_p2p_nan_ioctl_make_header(p2p_nanioc, WL_P2P_NAN_CMD_DEL_CONFIG, 0); + res = wldev_iovar_setbuf(ndev, "p2p_nan", p2p_nanioc, alloc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + return res; +} + +#endif /* NAN_P2P_CONFIG */ + +int +wl_cfgnan_pub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + struct bcm_tlvbuf *tbuf = NULL; + wl_nan_disc_params_t params; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 tbuf_size = BCM_XTLV_HDR_SIZE + sizeof(params); + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + void *pxtlv; + u16 start, end; + + /* + * proceed only if mandatory arguments are present - publisher id, + * service hash + */ + if ((!cmd_data->pub_id) || (!cmd_data->svc_hash.data) || + (!cmd_data->svc_hash.dlen)) { + WL_ERR((" mandatory arguments are not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + tbuf = bcm_xtlv_buf_alloc(NULL, tbuf_size); + if (!tbuf) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + + /* + * command to test + * + * wl: wl nan publish 10 NAN123 -info + * DRIVER NAN_PUBLISH PUB_ID=10 SVC_HASH=NAN123 + * SVC_INFO= PUB_PR=1 PUB_INT=0xffffffff + */ + + /* nan publish */ + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_PUBLISH); + pxtlv = nanioc->data; + + /* disovery parameters */ + if (cmd_data->pub_pr) { + params.period = cmd_data->pub_pr; + } else { + params.period = 1; + } + if (cmd_data->pub_int) { + params.ttl = cmd_data->pub_int; + } else { + params.ttl = WL_NAN_TTL_UNTIL_CANCEL; + } + params.flags = 0; + if (cmd_data->flags & WL_NAN_PUB_UNSOLICIT) { + params.flags |= WL_NAN_PUB_UNSOLICIT; + WL_DBG((" nan publish type - unsolicited\n")); + } + if (cmd_data->flags & WL_NAN_PUB_SOLICIT) { + params.flags |= WL_NAN_PUB_SOLICIT; + WL_DBG((" nan publish type - solicited\n")); + } + if (!params.flags) { + params.flags = WL_NAN_PUB_BOTH; /* default. */ + } + params.instance_id = (wl_nan_instance_id_t)cmd_data->pub_id; + memcpy((char *)params.svc_hash, cmd_data->svc_hash.data, + cmd_data->svc_hash.dlen); + ret = bcm_pack_xtlv_entry(&pxtlv, + &end, WL_NAN_XTLV_SVC_PARAMS, sizeof(wl_nan_disc_params_t), ¶ms); + if (unlikely(ret)) { + goto fail; + } + if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { + WL_DBG((" optional svc_info present, pack it \n")); + ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv, + &end, WL_NAN_XTLV_SVC_INFO, cmd_data->svc_info.data); + if (unlikely(ret)) { + goto fail; + } + } + + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan publish failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan publish successful \n")); + } + +fail: + if (tbuf) { + bcm_xtlv_buf_free(NULL, tbuf); + } + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_sub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + struct bcm_tlvbuf *tbuf = NULL; + wl_nan_disc_params_t params; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + /* + * proceed only if mandatory arguments are present - subscriber id, + * service hash + */ + if ((!cmd_data->sub_id) || (!cmd_data->svc_hash.data) || + (!cmd_data->svc_hash.dlen)) { + WL_ERR((" mandatory arguments are not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + tbuf = bcm_xtlv_buf_alloc(NULL, BCM_XTLV_HDR_SIZE + sizeof(params)); + if (!tbuf) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + + /* + * command to test + * + * wl: wl nan subscribe 10 NAN123 + * + * wpa_cli: DRIVER NAN_SUBSCRIBE SUB_ID=10 SVC_HASH=NAN123 + */ + + /* nan subscribe */ + params.period = 1; + params.ttl = WL_NAN_TTL_UNTIL_CANCEL; + params.flags = 0; + if (cmd_data->flags & WL_NAN_SUB_ACTIVE) { + params.flags = WL_NAN_SUB_ACTIVE; + WL_DBG((" nan subscribe type - Active\n")); + } + params.instance_id = (wl_nan_instance_id_t)cmd_data->sub_id; + memcpy((char *)params.svc_hash, cmd_data->svc_hash.data, + cmd_data->svc_hash.dlen); + bcm_xtlv_put_data(tbuf, WL_NAN_XTLV_SVC_PARAMS, ¶ms, sizeof(params)); + + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_SUBSCRIBE); + nanioc->len = htod16(bcm_xtlv_buf_len(tbuf)); + bcopy(bcm_xtlv_head(tbuf), nanioc->data, bcm_xtlv_buf_len(tbuf)); + nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(tbuf); + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan subscribe failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan subscribe successful \n")); + } + +fail: + if (tbuf) { + bcm_xtlv_buf_free(NULL, tbuf); + } + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_cancel_pub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + struct bcm_tlvbuf *tbuf = NULL; + wl_nan_disc_params_t params; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + /* proceed only if mandatory argument is present - publisher id */ + if (!cmd_data->pub_id) { + WL_ERR((" mandatory argument is not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + tbuf = bcm_xtlv_buf_alloc(NULL, BCM_XTLV_HDR_SIZE + sizeof(params)); + if (!tbuf) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + + /* + * command to test + * + * wl: wl nan cancel_publish 10 + * + * wpa_cli: DRIVER NAN_CANCEL_PUBLISH PUB_ID=10 + */ + + bcm_xtlv_put_data(tbuf, WL_NAN_XTLV_INSTANCE_ID, &cmd_data->pub_id, + sizeof(wl_nan_instance_id_t)); + + /* nan cancel publish */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_CANCEL_PUBLISH); + nanioc->len = htod16(bcm_xtlv_buf_len(tbuf)); + bcopy(bcm_xtlv_head(tbuf), nanioc->data, bcm_xtlv_buf_len(tbuf)); + nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(tbuf); + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan cancel publish failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan cancel publish successful \n")); + } + +fail: + if (tbuf) { + bcm_xtlv_buf_free(NULL, tbuf); + } + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_cancel_sub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + struct bcm_tlvbuf *tbuf = NULL; + wl_nan_disc_params_t params; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + /* proceed only if mandatory argument is present - subscriber id */ + if (!cmd_data->sub_id) { + WL_ERR((" mandatory argument is not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + tbuf = bcm_xtlv_buf_alloc(NULL, BCM_XTLV_HDR_SIZE + sizeof(params)); + if (!tbuf) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + + /* + * command to test + * + * wl: wl nan cancel_subscribe 10 + * + * wpa_cli: DRIVER NAN_CANCEL_SUBSCRIBE PUB_ID=10 + */ + + bcm_xtlv_put_data(tbuf, WL_NAN_XTLV_INSTANCE_ID, &cmd_data->sub_id, + sizeof(wl_nan_instance_id_t)); + + /* nan cancel subscribe */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_CANCEL_SUBSCRIBE); + nanioc->len = htod16(bcm_xtlv_buf_len(tbuf)); + bcopy(bcm_xtlv_head(tbuf), nanioc->data, bcm_xtlv_buf_len(tbuf)); + nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(tbuf); + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan cancel subscribe failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan cancel subscribe successful \n")); + } + +fail: + if (tbuf) { + bcm_xtlv_buf_free(NULL, tbuf); + } + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_transmit_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + void *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + /* + * proceed only if mandatory arguments are present - subscriber id, + * publisher id, mac address + */ + if ((!cmd_data->local_id) || (!cmd_data->remote_id) || + ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) { + WL_ERR((" mandatory arguments are not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan trasnmit -info + * + * wpa_cli: DRIVER NAN_TRANSMIT SUB_ID= PUB_ID= + * MAC_ADDR= SVC_INFO= + */ + + /* nan transmit */ + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_TRANSMIT); + pxtlv = nanioc->data; + + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_INSTANCE_ID, + sizeof(wl_nan_instance_id_t), &cmd_data->local_id); + if (unlikely(ret)) { + goto fail; + } + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_REQUESTOR_ID, + sizeof(wl_nan_instance_id_t), &cmd_data->remote_id); + if (unlikely(ret)) { + goto fail; + } + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_ADDR, + ETHER_ADDR_LEN, &cmd_data->mac_addr.octet); + if (unlikely(ret)) { + goto fail; + } + if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { + WL_DBG((" optional svc_info present, pack it \n")); + ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv, + &end, WL_NAN_XTLV_SVC_INFO, cmd_data->svc_info.data); + if (unlikely(ret)) { + goto fail; + } + } + + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan transmit failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan transmit successful \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_set_config_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + void *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + if (cfg->nan_running == true) { + WL_ERR((" Stop nan (NAN_STOP) before issuing NAN_CONFIG command\n")); + return BCME_ERROR; + } + + if (cfg->nan_enable != true) { + ret = wl_cfgnan_enable_handler(ndev, cfg, cmd, cmd_data); + if (unlikely(ret)) { + goto fail; + } + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan (wl nan role 1) + * + * wpa_cli: DRIVER NAN_CONFIG_SET ATTR= ... + * + * wpa_cli: DRIVER NAN_SET_CONFIG ATTR=ATTR_ROLE ROLE=1 + */ + + /* nan set config */ + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_ATTR); + pxtlv = nanioc->data; + + switch (cmd_data->attr.type) { + case WL_NAN_XTLV_ROLE: + WL_DBG((" set nan ROLE = %#x\n", cmd_data->role)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ROLE, + sizeof(u32), &cmd_data->role); + break; + case WL_NAN_XTLV_MASTER_PREF: + WL_DBG((" set nan MASTER PREF = %#x\n", cmd_data->master_pref)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MASTER_PREF, + sizeof(u16), &cmd_data->master_pref); + break; + case WL_NAN_XTLV_DW_LEN: + WL_DBG((" set nan DW LEN = %#x\n", cmd_data->dw_len)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_DW_LEN, + sizeof(u16), &cmd_data->dw_len); + break; + case WL_NAN_XTLV_CLUSTER_ID: + WL_DBG((" set nan CLUSTER ID ")); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, + sizeof(cmd_data->clus_id), &cmd_data->clus_id); + break; + case WL_NAN_XTLV_IF_ADDR: + WL_DBG((" set nan IFADDR ")); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_IF_ADDR, + sizeof(cmd_data->if_addr), &cmd_data->if_addr); + break; + case WL_NAN_XTLV_MAC_CHANSPEC: + WL_DBG((" set nan CHANSPEC = %#x\n", cmd_data->chanspec)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_CHANSPEC, + sizeof(cmd_data->chanspec), &cmd_data->chanspec); + break; + case WL_NAN_XTLV_BCN_INTERVAL: + WL_DBG((" set nan BCN_INTERVAL = %#x\n", cmd_data->beacon_int)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_BCN_INTERVAL, + sizeof(cmd_data->beacon_int), &cmd_data->beacon_int); + break; + case WL_NAN_XTLV_MAC_TXRATE: + default: + ret = -EINVAL; + break; + } + if (unlikely(ret)) { + WL_ERR((" unsupported attribute, attr = %s (%d) \n", + cmd_data->attr.name, cmd_data->attr.type)); + goto fail; + } + + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan set config failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan set config successful \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_rtt_config_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ranging_config_t rtt_config; + s32 ret = BCME_OK; + + /* proceed only if mandatory argument is present - channel */ + if (!cmd_data->chanspec) { + WL_ERR((" mandatory argument is not present \n")); + return -EINVAL; + } + + /* + * command to test + * + * wl: wl proxd_nancfg 44/80 128 32 ff:ff:ff:ff:ff:ff 1 + * + * wpa_cli: DRIVER NAN_RTT_CONFIG CHAN=44/80 + */ + + memset(&rtt_config, 0, sizeof(wl_nan_ranging_config_t)); + rtt_config.chanspec = cmd_data->chanspec; + rtt_config.timeslot = 128; + rtt_config.duration = 32; + memcpy(&rtt_config.allow_mac, ðer_bcast, ETHER_ADDR_LEN); + rtt_config.flags = 1; + + ret = wldev_iovar_setbuf(ndev, "proxd_nancfg", &rtt_config, + sizeof(wl_nan_ranging_config_t), cfg->ioctl_buf, + WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan rtt config failed, error = %d \n", ret)); + } else { + WL_DBG((" nan rtt config successful \n")); + } + + return ret; +} + +int +wl_cfgnan_rtt_find_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + void *iovbuf; + wl_nan_ranging_list_t *rtt_list; + s32 iovbuf_size = NAN_RTT_IOVAR_BUF_SIZE; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + /* + * proceed only if mandatory arguments are present - channel, bitmap, + * mac address + */ + if ((!cmd_data->chanspec) || (!cmd_data->bmap) || + ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) { + WL_ERR((" mandatory arguments are not present \n")); + return -EINVAL; + } + + iovbuf = kzalloc(iovbuf_size, kflags); + if (!iovbuf) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl proxd_nanfind 1 44/80 0x300 5 6 1 + * + * wpa_cli: DRIVER NAN_RTT_FIND MAC_ADDR= CHAN=44/80 BMAP=0x300 + * + */ + rtt_list = (wl_nan_ranging_list_t *)iovbuf; + rtt_list->count = 1; + rtt_list->num_peers_done = 0; + rtt_list->num_dws = 1; + rtt_list->rp[0].chanspec = cmd_data->chanspec; + memcpy(&rtt_list->rp[0].ea, &cmd_data->mac_addr, + sizeof(struct ether_addr)); + rtt_list->rp[0].abitmap = cmd_data->bmap; + rtt_list->rp[0].frmcnt = 5; + rtt_list->rp[0].retrycnt = 6; + rtt_list->rp[0].flags = 1; + + iovbuf_size = sizeof(wl_nan_ranging_list_t) + + sizeof(wl_nan_ranging_peer_t); + ret = wldev_iovar_setbuf(ndev, "proxd_nanfind", iovbuf, + iovbuf_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan rtt find failed, error = %d \n", ret)); + } else { + WL_DBG((" nan rtt find successful \n")); + } + + if (iovbuf) { + kfree(iovbuf); + } + + return ret; +} + +int +wl_cfgnan_debug_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + /* + * command to test + * + * wpa_cli: DRIVER NAN_DEBUG DEBUG=1 + * + */ + + g_nan_debug = cmd_data->debug_flag; + + /* reconfigure nan events */ + return wl_cfgnan_enable_events(ndev, cfg); +} + +static int wl_cfgnan_config_attr(char *buf, nan_config_attr_t *attr) +{ + s32 ret = BCME_OK; + nan_config_attr_t *nanc = NULL; + + /* only one attribute at a time */ + for (nanc = &nan_config_attrs[0]; strlen(nanc->name) != 0; nanc++) { + if (!strncmp(nanc->name, buf, strlen(nanc->name))) { + strncpy((char *)attr->name, buf, strlen(nanc->name)); + attr->type = nanc->type; + ret = strlen(nanc->name); + break; + } + } + + return ret; +} + +static int wl_cfgnan_parse_args(char *buf, nan_cmd_data_t *cmd_data) +{ + s32 ret = BCME_OK; + char *token = buf; + char delim[] = " "; + + while ((buf != NULL) && (token != NULL)) { + if (!strncmp(buf, PUB_ID_PREFIX, strlen(PUB_ID_PREFIX))) { + buf += strlen(PUB_ID_PREFIX); + token = strsep(&buf, delim); + cmd_data->pub_id = simple_strtoul(token, NULL, 10); + cmd_data->local_id ? (cmd_data->remote_id = cmd_data->pub_id) : + (cmd_data->local_id = cmd_data->pub_id); + if (NAN_INVALID_ID(cmd_data->pub_id)) { + WL_ERR((" invalid publisher id, pub_id = %d \n", + cmd_data->pub_id)); + ret = -EINVAL; + goto fail; + } +#ifdef NAN_P2P_CONFIG + } else if (!strncmp(buf, P2P_IE_PREFIX, strlen(P2P_IE_PREFIX))) { + buf += strlen(P2P_IE_PREFIX); + token = strsep(&buf, delim); + cmd_data->p2p_info.data = token; + cmd_data->p2p_info.dlen = strlen(token); + } else if (!strncmp(buf, IE_EN_PREFIX, strlen(IE_EN_PREFIX))) { + buf += strlen(IE_EN_PREFIX); + token = strsep(&buf, delim); + cmd_data->p2p_info.data = token; + cmd_data->p2p_info.dlen = strlen(token); +#endif /* NAN_P2P_CONFIG */ + } else if (!strncmp(buf, SUB_ID_PREFIX, strlen(SUB_ID_PREFIX))) { + buf += strlen(SUB_ID_PREFIX); + token = strsep(&buf, delim); + cmd_data->sub_id = simple_strtoul(token, NULL, 10); + cmd_data->local_id ? (cmd_data->remote_id = cmd_data->sub_id) : + (cmd_data->local_id = cmd_data->sub_id); + if (NAN_INVALID_ID(cmd_data->sub_id)) { + WL_ERR((" invalid subscriber id, sub_id = %d \n", + cmd_data->sub_id)); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, MAC_ADDR_PREFIX, strlen(MAC_ADDR_PREFIX))) { + buf += strlen(MAC_ADDR_PREFIX); + token = strsep(&buf, delim); + if (!wl_cfg80211_ether_atoe(token, &cmd_data->mac_addr)) { + WL_ERR((" invalid mac address, mac_addr = "MACDBG "\n", + MAC2STRDBG(cmd_data->mac_addr.octet))); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, SVC_HASH_PREFIX, strlen(SVC_HASH_PREFIX))) { + buf += strlen(SVC_HASH_PREFIX); + token = strsep(&buf, delim); + cmd_data->svc_hash.data = token; + cmd_data->svc_hash.dlen = WL_NAN_SVC_HASH_LEN; + } else if (!strncmp(buf, SVC_INFO_PREFIX, strlen(SVC_INFO_PREFIX))) { + buf += strlen(SVC_INFO_PREFIX); + token = strsep(&buf, delim); + cmd_data->svc_info.data = token; + cmd_data->svc_info.dlen = strlen(token); + } else if (!strncmp(buf, CHAN_PREFIX, strlen(CHAN_PREFIX))) { + buf += strlen(CHAN_PREFIX); + token = strsep(&buf, delim); + cmd_data->chanspec = wf_chspec_aton(token); + cmd_data->chanspec = wl_chspec_host_to_driver(cmd_data->chanspec); + if (NAN_INVALID_CHANSPEC(cmd_data->chanspec)) { + WL_ERR((" invalid chanspec, chanspec = 0x%04x \n", + cmd_data->chanspec)); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, BITMAP_PREFIX, strlen(BITMAP_PREFIX))) { + buf += strlen(BITMAP_PREFIX); + token = strsep(&buf, delim); + cmd_data->bmap = simple_strtoul(token, NULL, 16); + } else if (!strncmp(buf, ATTR_PREFIX, strlen(ATTR_PREFIX))) { + buf += strlen(ATTR_PREFIX); + token = strsep(&buf, delim); + if (!wl_cfgnan_config_attr(token, &cmd_data->attr)) { + WL_ERR((" invalid attribute, attr = %s \n", + cmd_data->attr.name)); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, ROLE_PREFIX, strlen(ROLE_PREFIX))) { + buf += strlen(ROLE_PREFIX); + token = strsep(&buf, delim); + cmd_data->role = simple_strtoul(token, NULL, 10); + if (NAN_INVALID_ROLE(cmd_data->role)) { + WL_ERR((" invalid role, role = %d \n", cmd_data->role)); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, MASTER_PREF_PREFIX, + strlen(MASTER_PREF_PREFIX))) { + buf += strlen(MASTER_PREF_PREFIX); + token = strsep(&buf, delim); + cmd_data->master_pref = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, CLUS_ID_PREFIX, strlen(CLUS_ID_PREFIX))) { + buf += strlen(CLUS_ID_PREFIX); + token = strsep(&buf, delim); + if (!wl_cfg80211_ether_atoe(token, &cmd_data->clus_id)) { + WL_ERR((" invalid cluster id, CLUS_ID = "MACDBG "\n", + MAC2STRDBG(cmd_data->clus_id.octet))); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, IF_ADDR_PREFIX, strlen(IF_ADDR_PREFIX))) { + buf += strlen(IF_ADDR_PREFIX); + token = strsep(&buf, delim); + if (!wl_cfg80211_ether_atoe(token, &cmd_data->if_addr)) { + WL_ERR((" invalid cluster id, IF_ADDR = "MACDBG "\n", + MAC2STRDBG(cmd_data->if_addr.octet))); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, BCN_INTERVAL_PREFIX, + strlen(BCN_INTERVAL_PREFIX))) { + buf += strlen(BCN_INTERVAL_PREFIX); + token = strsep(&buf, delim); + cmd_data->beacon_int = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, PUB_PR_PREFIX, strlen(PUB_PR_PREFIX))) { + buf += strlen(PUB_PR_PREFIX); + token = strsep(&buf, delim); + cmd_data->pub_pr = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, PUB_INT_PREFIX, strlen(PUB_INT_PREFIX))) { + buf += strlen(PUB_INT_PREFIX); + token = strsep(&buf, delim); + cmd_data->pub_int = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, DW_LEN_PREFIX, strlen(DW_LEN_PREFIX))) { + buf += strlen(DW_LEN_PREFIX); + token = strsep(&buf, delim); + cmd_data->dw_len = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, DEBUG_PREFIX, strlen(DEBUG_PREFIX))) { + buf += strlen(DEBUG_PREFIX); + token = strsep(&buf, delim); + cmd_data->debug_flag = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, ACTIVE_OPTION, strlen(ACTIVE_OPTION))) { + buf += strlen(ACTIVE_OPTION); + token = strsep(&buf, delim); + cmd_data->flags |= WL_NAN_SUB_ACTIVE; + } else if (!strncmp(buf, SOLICITED_OPTION, strlen(SOLICITED_OPTION))) { + buf += strlen(SOLICITED_OPTION); + token = strsep(&buf, delim); + cmd_data->flags |= WL_NAN_PUB_SOLICIT; + } else if (!strncmp(buf, UNSOLICITED_OPTION, strlen(UNSOLICITED_OPTION))) { + buf += strlen(UNSOLICITED_OPTION); + token = strsep(&buf, delim); + cmd_data->flags |= WL_NAN_PUB_UNSOLICIT; + } else { + WL_ERR((" unknown token, token = %s, buf = %s \n", token, buf)); + ret = -EINVAL; + goto fail; + } + } + +fail: + return ret; +} + +int +wl_cfgnan_cmd_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, + char *cmd, int cmd_len) +{ + nan_cmd_data_t cmd_data; + u8 *buf = cmd; + u8 *cmd_name = NULL; + nan_cmd_t *nanc = NULL; + int buf_len = 0; + int ret = BCME_OK; + + cmd_name = strsep((char **)&buf, " "); + if (buf) { + buf_len = strlen(buf); + } + + WL_DBG((" cmd_name: %s, buf_len: %d, buf: %s \n", cmd_name, buf_len, buf)); + + memset(&cmd_data, 0, sizeof(nan_cmd_data_t)); + ret = wl_cfgnan_parse_args(buf, &cmd_data); + if (unlikely(ret)) { + WL_ERR((" argument parsing failed with error (%d), buf = %s \n", + ret, buf)); + goto fail; + } + + for (nanc = nan_cmds; nanc->name; nanc++) { + if (strncmp(nanc->name, cmd_name, strlen(nanc->name)) == 0) { + ret = (*nanc->func)(ndev, cfg, cmd, &cmd_data); + if (ret < BCME_OK) { + WL_ERR((" command (%s) failed with error (%d) \n", + cmd_name, ret)); + } + } + } + +fail: + return ret; +} + +s32 +wl_cfgnan_notify_proxd_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data) +{ + s32 ret = BCME_OK; + wl_nan_ranging_event_data_t *rdata; + s32 status; + u16 data_len; + s32 event_type; + s32 event_num; + u8 *buf = NULL; + u32 buf_len; + u8 *ptr; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + s32 i; + + if (!event || !data) { + WL_ERR((" event data is NULL \n")); + return -EINVAL; + } + + status = ntoh32(event->reason); + event_type = ntoh32(event->event_type); + event_num = ntoh32(event->reason); + data_len = ntoh32(event->datalen); + + WL_DBG((" proxd event: type: %d num: %d len: %d \n", + event_type, event_num, data_len)); + + if (NAN_INVALID_PROXD_EVENT(event_num)) { + WL_ERR((" unsupported event, num: %d \n", event_num)); + return -EINVAL; + } + + if (g_nan_debug) { + WL_DBG((" event name: WLC_E_PROXD_NAN_EVENT \n")); + WL_DBG((" event data: \n")); + prhex(NULL, data, data_len); + } + + if (data_len < sizeof(wl_nan_ranging_event_data_t)) { + WL_ERR((" wrong data len \n")); + return -EINVAL; + } + + rdata = (wl_nan_ranging_event_data_t *)data; + + WL_DBG((" proxd event: count:%d success_count:%d mode:%d \n", + rdata->count, rdata->success_count, rdata->mode)); + + if (g_nan_debug) { + prhex(" event data: ", data, data_len); + } + + buf_len = NAN_IOCTL_BUF_SIZE; + buf = kzalloc(buf_len, kflags); + if (!buf) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + for (i = 0; i < rdata->count; i++) { + if (&rdata->rr[i] == NULL) { + ret = -EINVAL; + goto fail; + } + + ptr = buf; + WL_DBG((" ranging data for mac:"MACDBG" \n", + MAC2STRDBG(rdata->rr[i].ea.octet))); + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " MAC_ADDR_PREFIX MACF + " "STATUS_PREFIX"%s", EVENT_RTT_STATUS_STR, + ETHER_TO_MACF(rdata->rr[i].ea), (rdata->rr[i].status == 1) ? + "success" : "fail"); + + if (rdata->rr[i].status == 1) { + /* add tsf and distance only if status is success */ + ptr += sprintf(ptr, " "TIMESTAMP_PREFIX"0x%x " + DISTANCE_PREFIX"%d.%04d", rdata->rr[i].timestamp, + rdata->rr[i].distance >> 4, + ((rdata->rr[i].distance & 0x0f) * 625)); + } + +#ifdef WL_GENL + /* send the preformatted string to the upper layer as event */ + WL_DBG((" formatted string for userspace: %s, len: %zu \n", + buf, strlen(buf))); + wl_genl_send_msg(bcmcfg_to_prmry_ndev(cfg), 0, buf, strlen(buf), 0, 0); +#endif /* WL_GENL */ + } + +fail: + if (buf) { + kfree(buf); + } + + return ret; +} + +s32 +wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data) +{ + s32 ret = BCME_OK; + u16 data_len; + u32 event_num; + s32 event_type; + nan_event_hdr_t nan_hdr; + wl_nan_tlv_data_t tlv_data; + u8 *buf = NULL; + u32 buf_len; + u8 *ptr; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + if (!event || !data) { + WL_ERR((" event data is NULL \n")); + return -EINVAL; + } + + event_type = ntoh32(event->event_type); + event_num = ntoh32(event->reason); + data_len = ntoh32(event->datalen); + memset(&nan_hdr, 0, sizeof(nan_event_hdr_t)); + nan_hdr.event_subtype = event_num; + + WL_DBG((" nan event: type: %d num: %d len: %d \n", + event_type, event_num, data_len)); + + if (NAN_INVALID_EVENT(event_num)) { + WL_ERR((" unsupported event, num: %d \n", event_num)); + return -EINVAL; + } + + if (g_nan_debug) { + WL_DBG((" event name: %s \n", nan_event_name[event_num])); + WL_DBG((" event data: \n")); + prhex(NULL, data, data_len); + } + + /* unpack the tlvs */ + memset(&tlv_data, 0, sizeof(wl_nan_tlv_data_t)); + bcm_unpack_xtlv_buf(&tlv_data, data, data_len, + wl_cfgnan_set_vars_cbfn); + + /* + * send as preformatted hex string + * + * EVENT_NAN + */ + + buf_len = NAN_IOCTL_BUF_SIZE; + buf = ptr = kzalloc(buf_len, kflags); + if (!buf) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + + switch (event_num) { + case WL_NAN_EVENT_START: + case WL_NAN_EVENT_JOIN: + case WL_NAN_EVENT_STOP: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, + nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; + case WL_NAN_EVENT_ROLE: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s "ROLE_PREFIX "%d " + CLUS_ID_PREFIX MACF, nan_event_str[event_num], + tlv_data.nstatus.role, ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; + case WL_NAN_EVENT_DISCOVERY_RESULT: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " + SUB_ID_PREFIX"%d " MAC_ADDR_PREFIX MACF, + nan_event_str[event_num], tlv_data.pub_id, tlv_data.sub_id, + ETHER_TO_MACF(tlv_data.mac_addr)); + if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) { + WL_DBG((" service info present \n")); + if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) { + WL_ERR((" service info length = %d\n", + tlv_data.svc_info.dlen)); + WL_ERR((" insufficent buffer to copy service info \n")); + ret = -EOVERFLOW; + goto fail; + } + ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX); + ptr += bcm_format_hex(ptr, tlv_data.svc_info.data, + tlv_data.svc_info.dlen); + } else { + WL_DBG((" service info not present \n")); + } + + if (tlv_data.vend_info.data && tlv_data.vend_info.dlen) { + struct ether_addr *ea; + u8 *temp_data = tlv_data.vend_info.data; + uint32 bitmap; + u16 dlen = tlv_data.vend_info.dlen; + chanspec_t chanspec; + uint8 mapcontrol; + uint8 proto; + + WL_DBG((" vendor info present \n")); + if ((*temp_data != NAN_ATTR_VENDOR_SPECIFIC) || + (dlen < NAN_VENDOR_HDR_SIZE)) { + WL_ERR((" error in vendor info attribute \n")); + ret = -EINVAL; + goto fail; + } else { + WL_DBG((" vendor info not present \n")); + } + + if (*(temp_data + 6) == NAN_VENDOR_TYPE_RTT) { + temp_data += NAN_VENDOR_HDR_SIZE; + ea = (struct ether_addr *)temp_data; + temp_data += ETHER_ADDR_LEN; + mapcontrol = *temp_data++; + proto = *temp_data++; + bitmap = *(uint32 *)temp_data; + temp_data += 4; + chanspec = *(chanspec_t *)temp_data; + ptr += sprintf(ptr, " "BITMAP_PREFIX"0x%x "CHAN_PREFIX"%d/%s", + bitmap, wf_chspec_ctlchan(chanspec), + wf_chspec_to_bw_str(chanspec)); + WL_DBG((" bitmap: 0x%x channel: %d bandwidth: %s \n", bitmap, + wf_chspec_ctlchan(chanspec), + wf_chspec_to_bw_str(chanspec))); + } + } + break; + case WL_NAN_EVENT_REPLIED: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " + MAC_ADDR_PREFIX MACF, nan_event_str[event_num], + tlv_data.pub_id, ETHER_TO_MACF(tlv_data.mac_addr)); + break; + case WL_NAN_EVENT_TERMINATED: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d ", + nan_event_str[event_num], tlv_data.pub_id); + break; + case WL_NAN_EVENT_RECEIVE: + ptr += sprintf(buf, + SUPP_EVENT_PREFIX"%s " INSTANCE_ID_PREFIX"%d " + REMOTE_INSTANCE_ID_PREFIX"%d " MAC_ADDR_PREFIX MACF, + nan_event_str[event_num], tlv_data.inst_id, + tlv_data.peer_inst_id, ETHER_TO_MACF(tlv_data.mac_addr)); + if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) { + WL_DBG((" service info present \n")); + if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) { + WL_ERR((" service info length = %d\n", + tlv_data.svc_info.dlen)); + WL_ERR((" insufficent buffer to copy service info \n")); + ret = -EOVERFLOW; + goto fail; + } + ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX); + ptr += bcm_format_hex(ptr, tlv_data.svc_info.data, + tlv_data.svc_info.dlen); + } else { + WL_DBG((" service info not present \n")); + } + break; + case WL_NAN_EVENT_SCAN_COMPLETE: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, + nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; + case WL_NAN_EVENT_STATUS_CHG: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, + nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; + case WL_NAN_EVENT_MERGE: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, + nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; +#ifdef NAN_P2P_CONFIG + case WL_NAN_EVENT_P2P: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " + MAC_ADDR_PREFIX MACF, nan_event_str[event_num], + ETHER_TO_MACF(tlv_data.mac_addr)); + if (tlv_data.vend_info.data && tlv_data.vend_info.dlen) { + u8 *data = tlv_data.vend_info.data; + u16 dlen = tlv_data.vend_info.dlen; + + WL_DBG((" vendor info present %d dlen = %d\n", + *(data + 6), (dlen - (NAN_VENDOR_HDR_SIZE+1)))); + if ((*data != NAN_ATTR_VENDOR_SPECIFIC) || + (dlen < NAN_VENDOR_HDR_SIZE)) { + WL_ERR((" error in vendor info attribute \n")); + ret = -EINVAL; + goto fail; + } else { + WL_DBG((" vendor info present \n")); + } + + if (*(data + 6) == NAN_VENDOR_TYPE_P2P) { + data += NAN_VENDOR_HDR_SIZE; + ptr += sprintf(ptr, " %s", P2P_IE_PREFIX); + ptr += bcm_format_hex(ptr, data, (dlen - (NAN_VENDOR_HDR_SIZE))); + } + } + break; +#endif /* NAN_P2P_CONFIG */ + default: + WL_ERR((" unknown event \n")); + break; + } + +#ifdef WL_GENL + /* send the preformatted string to the upper layer as event */ + WL_DBG((" formatted string for userspace: %s, len: %zu \n", + buf, strlen(buf))); + wl_genl_send_msg(bcmcfg_to_prmry_ndev(cfg), 0, buf, strlen(buf), 0, 0); +#endif /* WL_GENL */ + +fail: + if (buf) { + kfree(buf); + } + if (tlv_data.svc_info.data) { + kfree(tlv_data.svc_info.data); + tlv_data.svc_info.data = NULL; + tlv_data.svc_info.dlen = 0; + } + if (tlv_data.vend_info.data) { + kfree(tlv_data.vend_info.data); + tlv_data.vend_info.data = NULL; + tlv_data.vend_info.dlen = 0; + } + + return ret; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.h new file mode 100644 index 000000000000..71de5d68b1ed --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.h @@ -0,0 +1,207 @@ +/* + * Neighbor Awareness Networking + * + * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgnan.h 487532 2014-06-26 05:09:36Z $ + */ + +#ifndef _wl_cfgnan_h_ +#define _wl_cfgnan_h_ + +#define NAN_IOCTL_BUF_SIZE 512 +#define NAN_EVENT_STR_MAX_LEN 30 +#define NAN_EVENT_NAME_MAX_LEN 40 +#define NAN_CONFIG_ATTR_MAX_LEN 24 +#define NAN_RTT_IOVAR_BUF_SIZE 1024 +#define WL_NAN_EVENT_CLEAR_BIT 32 +#define NAN_EVENT_MASK_ALL 0x7fffffff + +#define NAN_INVALID_ID(id) ((id > 255) ? true : false) +#define NAN_INVALID_ROLE(role) ((role > WL_NAN_ROLE_ANCHOR_MASTER) ? true : false) +#define NAN_INVALID_CHANSPEC(chanspec) ((chanspec == INVCHANSPEC) || \ + (chanspec == 0) ? true : false) +#define NAN_INVALID_EVENT(num) (((num < WL_NAN_EVENT_START) || \ + (num >= WL_NAN_EVENT_INVALID)) ? true : false) +#define NAN_INVALID_PROXD_EVENT(num) ((num != WLC_E_PROXD_NAN_EVENT) ? \ + true : false) +#define NAN_EVENT_BIT(event) (1U << (event - WL_NAN_EVENT_START)) + +#define SUPP_EVENT_PREFIX "CTRL-EVENT-" +#define EVENT_RTT_STATUS_STR "NAN-RTT-STATUS" + +#define TIMESTAMP_PREFIX "TSF=" /* timestamp */ +#define AMR_PREFIX "AMR=" /* anchor master rank */ +#define DISTANCE_PREFIX "DIST=" /* distance */ +#define ATTR_PREFIX "ATTR=" /* attribute */ +#define ROLE_PREFIX "ROLE=" /* role */ +#define CHAN_PREFIX "CHAN=" /* channel */ +#define BITMAP_PREFIX "BMAP=" /* bitmap */ +#define DEBUG_PREFIX "DEBUG=" /* debug enable/disable flag */ +#define DW_LEN_PREFIX "DW_LEN=" /* discovery window length */ +#define DW_INT_PREFIX "DW_INT=" /* discovery window interval */ +#define STATUS_PREFIX "STATUS=" /* status */ +#define PUB_ID_PREFIX "PUB_ID=" /* publisher id */ +#define SUB_ID_PREFIX "SUB_ID=" /* subscriber id */ +#define INSTANCE_ID_PREFIX "LOCAL_ID=" /* Instance id */ +#define REMOTE_INSTANCE_ID_PREFIX "PEER_ID=" /* Peer id */ + +#ifdef NAN_P2P_CONFIG +#define P2P_IE_PREFIX "P2P_IE=" /* p2p ie id */ +#define IE_EN_PREFIX "ENBLE_IE=" /* enable p2p ie */ +#endif +#define PUB_PR_PREFIX "PUB_PR=" /* publish period */ +#define PUB_INT_PREFIX "PUB_INT=" /* publish interval (ttl) */ +#define CLUS_ID_PREFIX "CLUS_ID=" /* cluster id */ +#define IF_ADDR_PREFIX "IF_ADDR=" /* IF address */ +#define MAC_ADDR_PREFIX "MAC_ADDR=" /* mac address */ +#define SVC_HASH_PREFIX "SVC_HASH=" /* service hash */ +#define SVC_INFO_PREFIX "SVC_INFO=" /* service information */ +#define HOP_COUNT_PREFIX "HOP_COUNT=" /* hop count */ +#define MASTER_PREF_PREFIX "MASTER_PREF=" /* master preference */ +#define ACTIVE_OPTION "ACTIVE" /* Active Subscribe. */ +#define SOLICITED_OPTION "SOLICITED" /* Solicited Publish. */ +#define UNSOLICITED_OPTION "UNSOLICITED" /* Unsolicited Publish. */ +/* anchor master beacon transmission time */ +#define AMBTT_PREFIX "AMBTT=" +/* passive scan period for cluster merge */ +#define SCAN_PERIOD_PREFIX "SCAN_PERIOD=" +/* passive scan interval for cluster merge */ +#define SCAN_INTERVAL_PREFIX "SCAN_INTERVAL=" +#define BCN_INTERVAL_PREFIX "BCN_INTERVAL=" + +typedef struct nan_str_data { + u8 *data; + u32 dlen; +} nan_str_data_t; + +typedef struct nan_config_attr { + char name[NAN_CONFIG_ATTR_MAX_LEN]; /* attribute name */ + u16 type; /* attribute xtlv type */ +} nan_config_attr_t; + +typedef struct nan_cmd_data { + nan_config_attr_t attr; /* set config attributes */ + nan_str_data_t svc_hash; /* service hash */ + nan_str_data_t svc_info; /* service information */ + nan_str_data_t p2p_info; /* p2p information */ + struct ether_addr mac_addr; /* mac address */ + struct ether_addr clus_id; /* cluster id */ + struct ether_addr if_addr; /* if addr */ + u32 beacon_int; /* beacon interval */ + u32 pub_int; /* publish interval (ttl) */ + u32 pub_pr; /* publish period */ + u32 bmap; /* bitmap */ + u32 role; /* role */ + u16 pub_id; /* publisher id */ + u16 sub_id; /* subscriber id */ + u16 local_id; /* Local id */ + u16 remote_id; /* Remote id */ + uint32 flags; /* Flag bits */ + u16 dw_len; /* discovery window length */ + u16 master_pref; /* master preference */ + chanspec_t chanspec; /* channel */ + u8 debug_flag; /* debug enable/disable flag */ +} nan_cmd_data_t; + +typedef int (nan_func_t)(struct net_device *ndev, struct bcm_cfg80211 *cfg, + char *cmd, nan_cmd_data_t *cmd_data); + +typedef struct nan_cmd { + const char *name; /* command name */ + nan_func_t *func; /* command hadler */ +} nan_cmd_t; + +typedef struct nan_event_hdr { + u16 event_subtype; + u32 flags; /* future use */ +} nan_event_hdr_t; + +typedef struct wl_nan_tlv_data { + wl_nan_status_t nstatus; /* status data */ + wl_nan_disc_params_t params; /* discovery parameters */ + struct ether_addr mac_addr; /* peer mac address */ + struct ether_addr clus_id; /* cluster id */ + nan_str_data_t svc_info; /* service info */ + nan_str_data_t vend_info; /* vendor info */ + /* anchor master beacon transmission time */ + u32 ambtt; + u32 dev_role; /* device role */ + u16 inst_id; /* instance id */ + u16 peer_inst_id; /* Peer instance id */ + u16 pub_id; /* publisher id */ + u16 sub_id; /* subscriber id */ + u16 master_pref; /* master preference */ + chanspec_t chanspec; /* channel */ + u8 amr[NAN_MASTER_RANK_LEN]; /* anchor master role */ + u8 svc_name[WL_NAN_SVC_HASH_LEN]; /* service name */ + u8 hop_count; /* hop count */ + u8 enabled; /* nan status flag */ + nan_scan_params_t scan_params; /* scan_param */ +} wl_nan_tlv_data_t; + +extern int wl_cfgnan_set_vars_cbfn(void *ctx, void **tlv_buf, + uint16 type, uint16 len); +extern int wl_cfgnan_enable_events(struct net_device *ndev, + struct bcm_cfg80211 *cfg); +extern int wl_cfgnan_start_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_stop_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_support_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_status_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_pub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_p2p_ie_add_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_p2p_ie_enable_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_p2p_ie_del_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); + +extern int wl_cfgnan_sub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_cancel_pub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_cancel_sub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_transmit_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_set_config_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_rtt_config_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_rtt_find_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_debug_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_cmd_handler(struct net_device *dev, + struct bcm_cfg80211 *cfg, char *cmd, int cmd_len); +extern s32 wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +extern s32 wl_cfgnan_notify_proxd_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); + +#endif /* _wl_cfgnan_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c new file mode 100644 index 000000000000..5465913c99fa --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c @@ -0,0 +1,2742 @@ +/* + * Linux cfgp2p driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgp2p.c 701287 2017-05-24 10:33:19Z $ + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +static s8 scanparambuf[WLC_IOCTL_SMLEN]; +static s8 g_mgmt_ie_buf[2048]; +static bool +wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); + +static u32 +wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag, + s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd); +static s32 wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, + struct wireless_dev *wdev, bool notify); + + +#if defined(WL_ENABLE_P2P_IF) +static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); +static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); +static int wl_cfgp2p_if_open(struct net_device *net); +static int wl_cfgp2p_if_stop(struct net_device *net); + +static const struct net_device_ops wl_cfgp2p_if_ops = { + .ndo_open = wl_cfgp2p_if_open, + .ndo_stop = wl_cfgp2p_if_stop, + .ndo_do_ioctl = wl_cfgp2p_do_ioctl, + .ndo_start_xmit = wl_cfgp2p_start_xmit, +}; +#endif /* WL_ENABLE_P2P_IF */ + + +bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + + if (frame == NULL) + return false; + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1) + return false; + + if (pact_frm->category == P2P_PUB_AF_CATEGORY && + pact_frm->action == P2P_PUB_AF_ACTION && + pact_frm->oui_type == P2P_VER && + memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) { + return true; + } + + return false; +} + +bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) +{ + wifi_p2p_action_frame_t *act_frm; + + if (frame == NULL) + return false; + act_frm = (wifi_p2p_action_frame_t *)frame; + if (frame_len < sizeof(wifi_p2p_action_frame_t) -1) + return false; + + if (act_frm->category == P2P_AF_CATEGORY && + act_frm->type == P2P_VER && + memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) { + return true; + } + + return false; +} + +#define GAS_RESP_LEN 2 +#define DOUBLE_TLV_BODY_OFF 4 +#define GAS_RESP_OFFSET 4 +#define GAS_CRESP_OFFSET 5 + +bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len) +{ + bcm_tlv_t *ie = (bcm_tlv_t *)data; + u8 *frame = NULL; + u16 id, flen; + + /* Skipped first ANQP Element, if frame has anqp elemnt */ + ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID); + + if (ie == NULL) + return false; + + frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN; + id = ((u16) (((frame)[1] << 8) | (frame)[0])); + flen = ((u16) (((frame)[3] << 8) | (frame)[2])); + + /* If the contents match the OUI and the type */ + if (flen >= WFA_OUI_LEN + 1 && + id == P2PSD_GAS_NQP_INFOID && + !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) && + subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) { + return true; + } + + return false; +} + +bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) +{ + + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; + + if (frame == NULL) + return false; + + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; + if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)) + return false; + if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) + return false; + + if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) + return true; + else + return false; +} + +bool wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len) +{ + + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; + + if (frame == NULL) + return false; + + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; + if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)) + return false; + if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) + return false; + + if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ) + return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, + (u8 *)sd_act_frm->query_data, + frame_len); + else + return false; +} + +void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + wifi_p2p_action_frame_t *act_frm; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; + if (!frame || frame_len <= 2) + return; + + if (wl_cfgp2p_is_pub_action(frame, frame_len)) { + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + switch (pact_frm->subtype) { + case P2P_PAF_GON_REQ: + CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_GON_RSP: + CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_GON_CONF: + CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_INVITE_REQ: + CFGP2P_ACTION(("%s P2P Invitation Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_INVITE_RSP: + CFGP2P_ACTION(("%s P2P Invitation Response Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_DEVDIS_REQ: + CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_DEVDIS_RSP: + CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_PROVDIS_REQ: + CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_PROVDIS_RSP: + CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + default: + CFGP2P_ACTION(("%s Unknown P2P Public Action Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + + } + + } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) { + act_frm = (wifi_p2p_action_frame_t *)frame; + switch (act_frm->subtype) { + case P2P_AF_NOTICE_OF_ABSENCE: + CFGP2P_ACTION(("%s P2P Notice of Absence Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_AF_PRESENCE_REQ: + CFGP2P_ACTION(("%s P2P Presence Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_AF_PRESENCE_RSP: + CFGP2P_ACTION(("%s P2P Presence Response Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_AF_GO_DISC_REQ: + CFGP2P_ACTION(("%s P2P Discoverability Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + default: + CFGP2P_ACTION(("%s Unknown P2P Action Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + } + + } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; + switch (sd_act_frm->action) { + case P2PSD_ACTION_ID_GAS_IREQ: + CFGP2P_ACTION(("%s P2P GAS Initial Request," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + break; + case P2PSD_ACTION_ID_GAS_IRESP: + CFGP2P_ACTION(("%s P2P GAS Initial Response," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + break; + case P2PSD_ACTION_ID_GAS_CREQ: + CFGP2P_ACTION(("%s P2P GAS Comback Request," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + break; + case P2PSD_ACTION_ID_GAS_CRESP: + CFGP2P_ACTION(("%s P2P GAS Comback Response," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + break; + default: + CFGP2P_ACTION(("%s Unknown P2P GAS Frame," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + } + + + } +} + +/* + * Initialize variables related to P2P + * + */ +s32 +wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg) +{ + if (!(cfg->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) { + CFGP2P_ERR(("struct p2p_info allocation failed\n")); + return -ENOMEM; + } +#define INIT_IE(IE_TYPE, BSS_TYPE) \ + do { \ + memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ + sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ + wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ + } while (0); + + INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE); + INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE); + INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE); + INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE); + INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE); + INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION); +#undef INIT_IE + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg); + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0; + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = NULL; + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = 0; + return BCME_OK; + +} +/* + * Deinitialize variables related to P2P + * + */ +void +wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg) +{ + CFGP2P_DBG(("In\n")); + if (cfg->p2p) { + kfree(cfg->p2p); + cfg->p2p = NULL; + } + cfg->p2p_supported = 0; +} +/* + * Set P2P functions into firmware + */ +s32 +wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg) +{ + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } }; + s32 ret = BCME_OK; + s32 val = 0; + /* Do we have to check whether APSTA is enabled or not ? */ + ret = wldev_iovar_getint(ndev, "apsta", &val); + if (ret < 0) { + CFGP2P_ERR(("get apsta error %d\n", ret)); + return ret; + } + if (val == 0) { + val = 1; + ret = wldev_ioctl_set(ndev, WLC_DOWN, &val, sizeof(s32)); + if (ret < 0) { + CFGP2P_ERR(("WLC_DOWN error %d\n", ret)); + return ret; + } + wldev_iovar_setint(ndev, "apsta", val); + ret = wldev_ioctl_set(ndev, WLC_UP, &val, sizeof(s32)); + if (ret < 0) { + CFGP2P_ERR(("WLC_UP error %d\n", ret)); + return ret; + } + } + + /* In case of COB type, firmware has default mac address + * After Initializing firmware, we have to set current mac address to + * firmware for P2P device address + */ + ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr, + sizeof(null_eth_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &cfg->ioctl_buf_sync); + if (ret && ret != BCME_UNSUPPORTED) { + CFGP2P_ERR(("failed to update device address ret %d\n", ret)); + } + return ret; +} + +/* Create a new P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to create + * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT + * @chspec : chspec to use if creating a GO BSS. + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, + chanspec_t chspec) +{ + wl_p2p_if_t ifreq; + s32 err; + u32 scb_timeout = WL_SCB_TIMEOUT; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + + ifreq.type = if_type; + ifreq.chspec = chspec; + memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); + + CFGP2P_DBG(("---cfg p2p_ifadd "MACDBG" %s %u\n", + MAC2STRDBG(ifreq.addr.octet), + (if_type == WL_P2P_IF_GO) ? "go" : "client", + (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); + + err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (unlikely(err < 0)) + printk("'cfg p2p_ifadd' error %d\n", err); + else if (if_type == WL_P2P_IF_GO) { + err = wldev_ioctl_set(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32)); + if (unlikely(err < 0)) + printk("'cfg scb_timeout' error %d\n", err); + } + return err; +} + +/* Disable a P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to disable + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac) +{ + s32 ret; + struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); + + CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdis "MACDBG"\n", + netdev->ifindex, MAC2STRDBG(mac->octet))); + ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(ret < 0)) { + printk("'cfg p2p_ifdis' error %d\n", ret); + } + return ret; +} + +/* Delete a P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to delete + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac) +{ + s32 ret; + struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); + + CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdel "MACDBG"\n", + netdev->ifindex, MAC2STRDBG(mac->octet))); + ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(ret < 0)) { + printk("'cfg p2p_ifdel' error %d\n", ret); + } + return ret; +} + +/* Change a P2P Role. + * Parameters: + * @mac : MAC address of the BSS to change a role + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, + chanspec_t chspec) +{ + wl_p2p_if_t ifreq; + s32 err; + u32 scb_timeout = WL_SCB_TIMEOUT; + + struct net_device *netdev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); + + ifreq.type = if_type; + ifreq.chspec = chspec; + memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); + + CFGP2P_INFO(("---cfg p2p_ifchange "MACDBG" %s %u" + " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet), + (if_type == WL_P2P_IF_GO) ? "go" : "client", + (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT, + ifreq.chspec)); + + err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (unlikely(err < 0)) { + printk("'cfg p2p_ifupd' error %d\n", err); + } else if (if_type == WL_P2P_IF_GO) { + err = wldev_ioctl_set(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32)); + if (unlikely(err < 0)) + printk("'cfg scb_timeout' error %d\n", err); + } + return err; +} + + +/* Get the index of a created P2P BSS. + * Parameters: + * @mac : MAC address of the created BSS + * @index : output: index of created BSS + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index) +{ + s32 ret; + u8 getbuf[64]; + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + + CFGP2P_INFO(("---cfg p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet))); + + ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, + sizeof(getbuf), wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY), NULL); + + if (ret == 0) { + memcpy(index, getbuf, sizeof(s32)); + CFGP2P_INFO(("---cfg p2p_if ==> %d\n", *index)); + } + + return ret; +} + +static s32 +wl_cfgp2p_set_discovery(struct bcm_cfg80211 *cfg, s32 on) +{ + s32 ret = BCME_OK; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + CFGP2P_DBG(("enter\n")); + + ret = wldev_iovar_setint(ndev, "p2p_disc", on); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret)); + } + + return ret; +} + +/* Set the WL driver's P2P mode. + * Parameters : + * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}. + * @channel : the channel to listen + * @listen_ms : the time (milli seconds) to wait + * @bssidx : bss index for BSSCFG + * Returns 0 if success + */ + +s32 +wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, u32 channel, u16 listen_ms, int bssidx) +{ + wl_p2p_disc_st_t discovery_mode; + s32 ret; + struct net_device *dev; + CFGP2P_DBG(("enter\n")); + + if (unlikely(bssidx == WL_INVALID)) { + CFGP2P_ERR((" %d index out of range\n", bssidx)); + return -1; + } + + dev = wl_cfgp2p_find_ndev(cfg, bssidx); + if (unlikely(dev == NULL)) { + CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx)); + return BCME_NOTFOUND; + } + + + + /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */ + discovery_mode.state = mode; + discovery_mode.chspec = wl_ch_host_to_driver(channel); + discovery_mode.dwell = listen_ms; + ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode, + sizeof(discovery_mode), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &cfg->ioctl_buf_sync); + + return ret; +} + +/* Get the index of the P2P Discovery BSS */ +static s32 +wl_cfgp2p_get_disc_idx(struct bcm_cfg80211 *cfg, s32 *index) +{ + s32 ret; + struct net_device *dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); + + ret = wldev_iovar_getint(dev, "p2p_dev", index); + CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret)); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("'p2p_dev' error %d\n", ret)); + return ret; + } + return ret; +} + +s32 +wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg) +{ + + s32 index = 0; + s32 ret = BCME_OK; + + CFGP2P_DBG(("enter\n")); + + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0) { + CFGP2P_ERR(("do nothing, already initialized\n")); + return ret; + } + + ret = wl_cfgp2p_set_discovery(cfg, 1); + if (ret < 0) { + CFGP2P_ERR(("set discover error\n")); + return ret; + } + /* Enable P2P Discovery in the WL Driver */ + ret = wl_cfgp2p_get_disc_idx(cfg, &index); + + if (ret < 0) { + return ret; + } + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = index; + + /* Set the initial discovery state to SCAN */ + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + + if (unlikely(ret != 0)) { + CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); + wl_cfgp2p_set_discovery(cfg, 0); + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; + return 0; + } + return ret; +} + +/* Deinitialize P2P Discovery + * Parameters : + * @cfg : wl_private data + * Returns 0 if succes + */ +static s32 +wl_cfgp2p_deinit_discovery(struct bcm_cfg80211 *cfg) +{ + s32 ret = BCME_OK; + CFGP2P_DBG(("enter\n")); + + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) <= 0) { + CFGP2P_ERR(("do nothing, not initialized\n")); + return -1; + } + /* Set the discovery state to SCAN */ + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */ + ret = wl_cfgp2p_set_discovery(cfg, 0); + + /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver + * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery + * BSS. + */ + + /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we + * have no discovery BSS. + */ + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = WL_INVALID; + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; + + return ret; + +} +/* Enable P2P Discovery + * Parameters: + * @cfg : wl_private data + * @ie : probe request ie (WPS IE + P2P IE) + * @ie_len : probe request ie length + * Returns 0 if success. + */ +s32 +wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, + const u8 *ie, u32 ie_len) +{ + s32 ret = BCME_OK; + s32 bssidx; + + if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { + CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n")); + goto set_ie; + } + + wl_set_p2p_status(cfg, DISCOVERY_ON); + + CFGP2P_DBG(("enter\n")); + + ret = wl_cfgp2p_init_discovery(cfg); + if (unlikely(ret < 0)) { + CFGP2P_ERR((" init discovery error %d\n", ret)); + goto exit; + } + /* Set wsec to any non-zero value in the discovery bsscfg to ensure our + * P2P probe responses have the privacy bit set in the 802.11 WPA IE. + * Some peer devices may not initiate WPS with us if this bit is not set. + */ + ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), + "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + if (unlikely(ret < 0)) { + CFGP2P_ERR((" wsec error %d\n", ret)); + } +set_ie: + if (ie_len) { + if (bcmcfg_to_prmry_ndev(cfg) == dev) { + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + } else if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + ret = wl_cfgp2p_set_management_ie(cfg, dev, + bssidx, + VNDR_IE_PRBREQ_FLAG, ie, ie_len); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("set probreq ie occurs error %d\n", ret)); + goto exit; + } + } +exit: + return ret; +} + +/* Disable P2P Discovery + * Parameters: + * @cfg : wl_private_data + * Returns 0 if success. + */ +s32 +wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg) +{ + s32 ret = BCME_OK; + CFGP2P_DBG((" enter\n")); + wl_clr_p2p_status(cfg, DISCOVERY_ON); + + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) == 0) { + CFGP2P_ERR((" do nothing, not initialized\n")); + goto exit; + } + + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + + if (unlikely(ret < 0)) { + + CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); + } + /* Do a scan abort to stop the driver's scan engine in case it is still + * waiting out an action frame tx dwell time. + */ + wl_clr_p2p_status(cfg, DISCOVERY_ON); + ret = wl_cfgp2p_deinit_discovery(cfg); + +exit: + return ret; +} + +s32 +wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, + u32 num_chans, u16 *channels, + s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, + p2p_scan_purpose_t p2p_scan_purpose) +{ + s32 ret = BCME_OK; + s32 memsize; + s32 eparams_size; + u32 i; + s8 *memblk; + wl_p2p_scan_t *p2p_params; + wl_escan_params_t *eparams; + wlc_ssid_t ssid; + /* Scan parameters */ +#define P2PAPI_SCAN_NPROBES 1 +#define P2PAPI_SCAN_DWELL_TIME_MS 80 +#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 +#define P2PAPI_SCAN_HOME_TIME_MS 60 +#define P2PAPI_SCAN_NPROBS_TIME_MS 30 +#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 + + struct net_device *pri_dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); + /* Allocate scan params which need space for 3 channels and 0 ssids */ + eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + + OFFSETOF(wl_escan_params_t, params)) + + num_chans * sizeof(eparams->params.channel_list[0]); + + memsize = sizeof(wl_p2p_scan_t) + eparams_size; + memblk = scanparambuf; + if (memsize > sizeof(scanparambuf)) { + CFGP2P_ERR((" scanpar buf too small (%u > %zu)\n", + memsize, sizeof(scanparambuf))); + return -1; + } + memset(memblk, 0, memsize); + memset(cfg->ioctl_buf, 0, WLC_IOCTL_MAXLEN); + if (search_state == WL_P2P_DISC_ST_SEARCH) { + /* + * If we in SEARCH STATE, we don't need to set SSID explictly + * because dongle use P2P WILDCARD internally by default + */ + wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx); + /* use null ssid */ + ssid.SSID_len = 0; + memset(&ssid.SSID, 0, sizeof(ssid.SSID)); + } else if (search_state == WL_P2P_DISC_ST_SCAN) { + /* SCAN STATE 802.11 SCAN + * WFD Supplicant has p2p_find command with (type=progressive, type= full) + * So if P2P_find command with type=progressive, + * we have to set ssid to P2P WILDCARD because + * we just do broadcast scan unless setting SSID + */ + wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); + /* use wild card ssid */ + ssid.SSID_len = WL_P2P_WILDCARD_SSID_LEN; + memset(&ssid.SSID, 0, sizeof(ssid.SSID)); + memcpy(&ssid.SSID, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN); + } else { + CFGP2P_ERR((" invalid search state %d\n", search_state)); + return -1; + } + + + /* Fill in the P2P scan structure at the start of the iovar param block */ + p2p_params = (wl_p2p_scan_t*) memblk; + p2p_params->type = 'E'; + /* Fill in the Scan structure that follows the P2P scan structure */ + eparams = (wl_escan_params_t*) (p2p_params + 1); + eparams->params.bss_type = DOT11_BSSTYPE_ANY; + if (active) + eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE; + else + eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE; + + if (tx_dst_addr == NULL) + memcpy(&eparams->params.bssid, ðer_bcast, ETHER_ADDR_LEN); + else + memcpy(&eparams->params.bssid, tx_dst_addr, ETHER_ADDR_LEN); + + if (ssid.SSID_len) + memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); + + eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); + + switch (p2p_scan_purpose) { + case P2P_SCAN_SOCIAL_CHANNEL: + eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); + break; + case P2P_SCAN_AFX_PEER_NORMAL: + case P2P_SCAN_AFX_PEER_REDUCED: + eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); + break; + case P2P_SCAN_CONNECT_TRY: + eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + break; + default : + if (wl_get_drv_status_all(cfg, CONNECTED)) + eparams->params.active_time = -1; + else + eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); + break; + } + + if (p2p_scan_purpose == P2P_SCAN_CONNECT_TRY) + eparams->params.nprobes = htod32(eparams->params.active_time / + WL_SCAN_JOIN_PROBE_INTERVAL_MS); + else + eparams->params.nprobes = htod32((eparams->params.active_time / + P2PAPI_SCAN_NPROBS_TIME_MS)); + + + if (eparams->params.nprobes <= 0) + eparams->params.nprobes = 1; + CFGP2P_DBG(("nprobes # %d, active_time %d\n", + eparams->params.nprobes, eparams->params.active_time)); + eparams->params.passive_time = htod32(-1); + eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | + (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); + + for (i = 0; i < num_chans; i++) { + eparams->params.channel_list[i] = wl_ch_host_to_driver(channels[i]); + } + eparams->version = htod32(ESCAN_REQ_VERSION); + eparams->action = htod16(action); + wl_escan_set_sync_id(eparams->sync_id, cfg); + wl_escan_set_type(cfg, WL_SCANTYPE_P2P); + CFGP2P_INFO(("SCAN CHANNELS : ")); + + for (i = 0; i < num_chans; i++) { + if (i == 0) CFGP2P_INFO(("%d", channels[i])); + else CFGP2P_INFO((",%d", channels[i])); + } + + CFGP2P_INFO(("\n")); + + ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan", + memblk, memsize, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (ret == BCME_OK) + wl_set_p2p_status(cfg, SCANNING); + return ret; +} + +/* search function to reach at common channel to send action frame + * Parameters: + * @cfg : wl_private data + * @ndev : net device for bssidx + * @bssidx : bssidx for BSS + * Returns 0 if success. + */ +s32 +wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, + s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr) +{ + s32 ret = 0; + u32 chan_cnt = 0; + u16 *default_chan_list = NULL; + p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_AFX_PEER_NORMAL; + if (!p2p_is_on(cfg) || ndev == NULL || bssidx == WL_INVALID) + return -BCME_ERROR; + WL_TRACE_HW4((" Enter\n")); + if (bssidx == wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY)) + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + if (channel) + chan_cnt = AF_PEER_SEARCH_CNT; + else + chan_cnt = SOCIAL_CHAN_CNT; + default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL); + if (default_chan_list == NULL) { + CFGP2P_ERR(("channel list allocation failed \n")); + ret = -ENOMEM; + goto exit; + } + if (channel) { + u32 i; + /* insert same channel to the chan_list */ + for (i = 0; i < chan_cnt; i++) { + default_chan_list[i] = channel; + } + } else { + default_chan_list[0] = SOCIAL_CHAN_1; + default_chan_list[1] = SOCIAL_CHAN_2; + default_chan_list[2] = SOCIAL_CHAN_3; + } + ret = wl_cfgp2p_escan(cfg, ndev, true, chan_cnt, + default_chan_list, WL_P2P_DISC_ST_SEARCH, + WL_SCAN_ACTION_START, bssidx, NULL, p2p_scan_purpose); + kfree(default_chan_list); +exit: + return ret; +} + +/* Check whether pointed-to IE looks like WPA. */ +#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) +/* Check whether pointed-to IE looks like WPS. */ +#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) +/* Check whether the given IE looks like WFA P2P IE. */ +#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) +/* Check whether the given IE looks like WFA WFDisplay IE. */ +#ifndef WFA_OUI_TYPE_WFD +#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ +#endif +#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) + +static s32 +wl_cfgp2p_parse_vndr_ies(u8 *parse, u32 len, + struct parsed_vndr_ies *vndr_ies) +{ + s32 err = BCME_OK; + vndr_ie_t *vndrie; + bcm_tlv_t *ie; + struct parsed_vndr_ie_info *parsed_info; + u32 count = 0; + s32 remained_len; + + remained_len = (s32)len; + memset(vndr_ies, 0, sizeof(*vndr_ies)); + + WL_INFORM(("---> len %d\n", len)); + ie = (bcm_tlv_t *) parse; + if (!bcm_valid_tlv(ie, remained_len)) + ie = NULL; + while (ie) { + if (count >= MAX_VNDR_IE_NUMBER) + break; + if (ie->id == DOT11_MNG_VS_ID) { + vndrie = (vndr_ie_t *) ie; + /* len should be bigger than OUI length + one data length at least */ + if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) { + CFGP2P_ERR(("%s: invalid vndr ie. length is too small %d\n", + __FUNCTION__, vndrie->len)); + goto end; + } + /* if wpa or wme ie, do not add ie */ + if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) && + ((vndrie->data[0] == WPA_OUI_TYPE) || + (vndrie->data[0] == WME_OUI_TYPE))) { + CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n")); + goto end; + } + + parsed_info = &vndr_ies->ie_info[count++]; + + /* save vndr ie information */ + parsed_info->ie_ptr = (char *)vndrie; + parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN); + memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t)); + + vndr_ies->count = count; + + CFGP2P_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x \n", + parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1], + parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0])); + } +end: + ie = bcm_next_tlv(ie, &remained_len); + } + return err; +} + + +/* Delete and Set a management vndr ie to firmware + * Parameters: + * @cfg : wl_private data + * @ndev : net device for bssidx + * @bssidx : bssidx for BSS + * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, + * VNDR_IE_ASSOCREQ_FLAG) + * @ie : VNDR IE (such as P2P IE , WPS IE) + * @ie_len : VNDR IE Length + * Returns 0 if success. + */ + +s32 +wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, + s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) +{ + s32 ret = BCME_OK; + u8 *curr_ie_buf = NULL; + u8 *mgmt_ie_buf = NULL; + u32 mgmt_ie_buf_len = 0; + u32 *mgmt_ie_len = 0; + u32 del_add_ie_buf_len = 0; + u32 total_ie_buf_len = 0; + u32 parsed_ie_buf_len = 0; + struct parsed_vndr_ies old_vndr_ies; + struct parsed_vndr_ies new_vndr_ies; + s32 i; + u8 *ptr; + s32 type = -1; + s32 remained_buf_len; +#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie) +#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie_len) + memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf)); + curr_ie_buf = g_mgmt_ie_buf; + CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag)); + +#ifdef DUAL_STA + if ((cfg->p2p != NULL) && ((bssidx == 0) || (bssidx != cfg->cfgdev_bssidx))) { +#else + if (cfg->p2p != NULL) { +#endif + if (wl_cfgp2p_find_type(cfg, bssidx, &type)) { + CFGP2P_ERR(("cannot find type from bssidx : %d\n", bssidx)); + return BCME_ERROR; + } + + switch (pktflag) { + case VNDR_IE_PRBREQ_FLAG : + mgmt_ie_buf = IE_TYPE(probe_req, type); + mgmt_ie_len = &IE_TYPE_LEN(probe_req, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, type)); + break; + case VNDR_IE_PRBRSP_FLAG : + mgmt_ie_buf = IE_TYPE(probe_res, type); + mgmt_ie_len = &IE_TYPE_LEN(probe_res, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, type)); + break; + case VNDR_IE_ASSOCREQ_FLAG : + mgmt_ie_buf = IE_TYPE(assoc_req, type); + mgmt_ie_len = &IE_TYPE_LEN(assoc_req, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, type)); + break; + case VNDR_IE_ASSOCRSP_FLAG : + mgmt_ie_buf = IE_TYPE(assoc_res, type); + mgmt_ie_len = &IE_TYPE_LEN(assoc_res, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, type)); + break; + case VNDR_IE_BEACON_FLAG : + mgmt_ie_buf = IE_TYPE(beacon, type); + mgmt_ie_len = &IE_TYPE_LEN(beacon, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, type)); + break; + default: + mgmt_ie_buf = NULL; + mgmt_ie_len = NULL; + CFGP2P_ERR(("not suitable type\n")); + return BCME_ERROR; + } + } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { + if (cfg->ap_info == NULL) { + CFGP2P_ERR(("hostapd ap_info null ptr refrence while setting IE\n")); + return BCME_ERROR; + + } + switch (pktflag) { + case VNDR_IE_PRBRSP_FLAG : + mgmt_ie_buf = cfg->ap_info->probe_res_ie; + mgmt_ie_len = &cfg->ap_info->probe_res_ie_len; + mgmt_ie_buf_len = sizeof(cfg->ap_info->probe_res_ie); + break; + case VNDR_IE_BEACON_FLAG : + mgmt_ie_buf = cfg->ap_info->beacon_ie; + mgmt_ie_len = &cfg->ap_info->beacon_ie_len; + mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie); + break; + case VNDR_IE_ASSOCRSP_FLAG : + /* WPS-AP WSC2.0 assoc res includes wps_ie */ + mgmt_ie_buf = cfg->ap_info->assoc_res_ie; + mgmt_ie_len = &cfg->ap_info->assoc_res_ie_len; + mgmt_ie_buf_len = sizeof(cfg->ap_info->assoc_res_ie); + break; + default: + mgmt_ie_buf = NULL; + mgmt_ie_len = NULL; + CFGP2P_ERR(("not suitable type\n")); + return BCME_ERROR; + } + bssidx = 0; + } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) { + switch (pktflag) { + case VNDR_IE_PRBREQ_FLAG : + mgmt_ie_buf = cfg->sta_info->probe_req_ie; + mgmt_ie_len = &cfg->sta_info->probe_req_ie_len; + mgmt_ie_buf_len = sizeof(cfg->sta_info->probe_req_ie); + break; + case VNDR_IE_ASSOCREQ_FLAG : + mgmt_ie_buf = cfg->sta_info->assoc_req_ie; + mgmt_ie_len = &cfg->sta_info->assoc_req_ie_len; + mgmt_ie_buf_len = sizeof(cfg->sta_info->assoc_req_ie); + break; + default: + mgmt_ie_buf = NULL; + mgmt_ie_len = NULL; + CFGP2P_ERR(("not suitable type\n")); + return BCME_ERROR; + } + bssidx = 0; + } else { + CFGP2P_ERR(("not suitable type\n")); + return BCME_ERROR; + } + + if (vndr_ie_len > mgmt_ie_buf_len) { + CFGP2P_ERR(("extra IE size too big\n")); + ret = -ENOMEM; + } else { + /* parse and save new vndr_ie in curr_ie_buff before comparing it */ + if (vndr_ie && vndr_ie_len && curr_ie_buf) { + ptr = curr_ie_buf; + + wl_cfgp2p_parse_vndr_ies((u8*)vndr_ie, + vndr_ie_len, &new_vndr_ies); + + for (i = 0; i < new_vndr_ies.count; i++) { + struct parsed_vndr_ie_info *vndrie_info = + &new_vndr_ies.ie_info[i]; + + memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr, + vndrie_info->ie_len); + parsed_ie_buf_len += vndrie_info->ie_len; + } + } + + if (mgmt_ie_buf != NULL) { + if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && + (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { + CFGP2P_INFO(("Previous mgmt IE is equals to current IE")); + goto exit; + } + + /* parse old vndr_ie */ + wl_cfgp2p_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, + &old_vndr_ies); + + /* make a command to delete old ie */ + for (i = 0; i < old_vndr_ies.count; i++) { + struct parsed_vndr_ie_info *vndrie_info = + &old_vndr_ies.ie_info[i]; + + CFGP2P_INFO(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", + vndrie_info->vndrie.id, vndrie_info->vndrie.len, + vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2])); + + del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, + pktflag, vndrie_info->vndrie.oui, + vndrie_info->vndrie.id, + vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, + vndrie_info->ie_len - VNDR_IE_FIXED_LEN, + "del"); + + curr_ie_buf += del_add_ie_buf_len; + total_ie_buf_len += del_add_ie_buf_len; + } + } + + *mgmt_ie_len = 0; + /* Add if there is any extra IE */ + if (mgmt_ie_buf && parsed_ie_buf_len) { + ptr = mgmt_ie_buf; + + remained_buf_len = mgmt_ie_buf_len; + + /* make a command to add new ie */ + for (i = 0; i < new_vndr_ies.count; i++) { + struct parsed_vndr_ie_info *vndrie_info = + &new_vndr_ies.ie_info[i]; + + CFGP2P_INFO(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n", + vndrie_info->vndrie.id, vndrie_info->vndrie.len, + vndrie_info->ie_len - 2, + vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2])); + + del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, + pktflag, vndrie_info->vndrie.oui, + vndrie_info->vndrie.id, + vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, + vndrie_info->ie_len - VNDR_IE_FIXED_LEN, + "add"); + + /* verify remained buf size before copy data */ + if (remained_buf_len >= vndrie_info->ie_len) { + remained_buf_len -= vndrie_info->ie_len; + } else { + CFGP2P_ERR(("no space in mgmt_ie_buf: pktflag = %d, " + "found vndr ies # = %d(cur %d), remained len %d, " + "cur mgmt_ie_len %d, new ie len = %d\n", + pktflag, new_vndr_ies.count, i, remained_buf_len, + *mgmt_ie_len, vndrie_info->ie_len)); + break; + } + + /* save the parsed IE in cfg struct */ + memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, + vndrie_info->ie_len); + *mgmt_ie_len += vndrie_info->ie_len; + + curr_ie_buf += del_add_ie_buf_len; + total_ie_buf_len += del_add_ie_buf_len; + } + } + if (total_ie_buf_len) { + ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, + total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &cfg->ioctl_buf_sync); + if (ret) + CFGP2P_ERR(("vndr ie set error : %d\n", ret)); + } + } +#undef IE_TYPE +#undef IE_TYPE_LEN +exit: + return ret; +} + +/* Clear the manament IE buffer of BSSCFG + * Parameters: + * @cfg : wl_private data + * @bssidx : bssidx for BSS + * + * Returns 0 if success. + */ +s32 +wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx) +{ + + s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, + VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG}; + s32 index = -1; + s32 type = -1; + struct net_device *ndev = wl_cfgp2p_find_ndev(cfg, bssidx); +#define INIT_IE(IE_TYPE, BSS_TYPE) \ + do { \ + memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ + sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ + wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ + } while (0); + + if (bssidx < 0 || ndev == NULL) { + CFGP2P_ERR(("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev")); + return BCME_BADARG; + } + + if (wl_cfgp2p_find_type(cfg, bssidx, &type)) { + CFGP2P_ERR(("invalid argument\n")); + return BCME_BADARG; + } + for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) { + /* clean up vndr ies in dongle */ + wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, vndrie_flag[index], NULL, 0); + } + INIT_IE(probe_req, type); + INIT_IE(probe_res, type); + INIT_IE(assoc_req, type); + INIT_IE(assoc_res, type); + INIT_IE(beacon, type); + return BCME_OK; +} + + +/* Is any of the tlvs the expected entry? If + * not update the tlvs buffer pointer/length. + */ +static bool +wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type) +{ + /* If the contents match the OUI and the type */ + if (ie[TLV_LEN_OFF] >= oui_len + 1 && + !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && + type == ie[TLV_BODY_OFF + oui_len]) { + return TRUE; + } + + if (tlvs == NULL) + return FALSE; + /* point to the next ie */ + ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; + /* calculate the length of the rest of the buffer */ + *tlvs_len -= (int)(ie - *tlvs); + /* update the pointer to the start of the buffer */ + *tlvs = ie; + + return FALSE; +} + +wpa_ie_fixed_t * +wl_cfgp2p_find_wpaie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) { + return (wpa_ie_fixed_t *)ie; + } + } + return NULL; +} + +wpa_ie_fixed_t * +wl_cfgp2p_find_wpsie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) { + return (wpa_ie_fixed_t *)ie; + } + } + return NULL; +} + +wifi_p2p_ie_t * +wl_cfgp2p_find_p2pie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) { + return (wifi_p2p_ie_t *)ie; + } + } + return NULL; +} + +wifi_wfd_ie_t * +wl_cfgp2p_find_wfdie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) { + return (wifi_wfd_ie_t *)ie; + } + } + return NULL; +} +static u32 +wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag, + s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd) +{ + vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */ + s32 iecount; + u32 data_offset; + + /* Validate the pktflag parameter */ + if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | + VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | + VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) { + CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag)); + return -1; + } + + /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ + strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1); + hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Set the IE count - the buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32)); + + /* Copy packet flags that indicate which packets will contain this IE */ + pktflag = htod32(pktflag); + memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, + sizeof(u32)); + + /* Add the IE ID to the buffer */ + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; + + /* Add the IE length to the buffer */ + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = + (uint8) VNDR_IE_MIN_LEN + datalen; + + /* Add the IE OUI to the buffer */ + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0]; + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1]; + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2]; + + /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */ + memcpy(iebuf, &hdr, sizeof(hdr) - 1); + + /* Copy the IE data to the IE buffer */ + data_offset = + (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] - + (u8*)&hdr; + memcpy(iebuf + data_offset, data, datalen); + return data_offset + datalen; + +} + +/* + * Search the bssidx based on dev argument + * Parameters: + * @cfg : wl_private data + * @ndev : net device to search bssidx + * @bssidx : output arg to store bssidx of the bsscfg of firmware. + * Returns error + */ +s32 +wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *bssidx) +{ + u32 i; + if (ndev == NULL || bssidx == NULL) { + CFGP2P_ERR((" argument is invalid\n")); + return BCME_BADARG; + } + if (!cfg->p2p_supported) { + *bssidx = P2PAPI_BSSCFG_PRIMARY; + return BCME_OK; + } + /* we cannot find the bssidx of DISCOVERY BSS + * because the ndev is same with ndev of PRIMARY BSS. + */ + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + if (ndev == wl_to_p2p_bss_ndev(cfg, i)) { + *bssidx = wl_to_p2p_bss_bssidx(cfg, i); + return BCME_OK; + } + } + +#ifdef DUAL_STA + if (cfg->bss_cfgdev && (cfg->bss_cfgdev == ndev_to_cfgdev(ndev))) { + CFGP2P_INFO(("cfgdev is present, return the bssidx")); + *bssidx = cfg->cfgdev_bssidx; + return BCME_OK; + } +#endif + + return BCME_BADARG; + +} +struct net_device * +wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx) +{ + u32 i; + struct net_device *ndev = NULL; + if (bssidx < 0) { + CFGP2P_ERR((" bsscfg idx is invalid\n")); + goto exit; + } + + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) { + ndev = wl_to_p2p_bss_ndev(cfg, i); + break; + } + } + +exit: + return ndev; +} +/* + * Search the driver array idx based on bssidx argument + * Parameters: + * @cfg : wl_private data + * @bssidx : bssidx which indicate bsscfg->idx of firmware. + * @type : output arg to store array idx of p2p->bss. + * Returns error + */ + +s32 +wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type) +{ + u32 i; + if (bssidx < 0 || type == NULL) { + CFGP2P_ERR((" argument is invalid\n")); + goto exit; + } + + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) { + *type = i; + return BCME_OK; + } + } + +#ifdef DUAL_STA + if (bssidx == cfg->cfgdev_bssidx) { + CFGP2P_DBG(("bssidx matching with the virtual I/F \n")); + *type = 1; + return BCME_OK; + } +#endif + +exit: + return BCME_BADARG; +} + +/* + * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE + */ +s32 +wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 ret = BCME_OK; + struct net_device *ndev = NULL; + + if (!cfg || !cfg->p2p) + return BCME_ERROR; + + CFGP2P_DBG((" Enter\n")); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + + if (wl_get_p2p_status(cfg, LISTEN_EXPIRED) == 0) { + wl_set_p2p_status(cfg, LISTEN_EXPIRED); + if (timer_pending(&cfg->p2p->listen_timer)) { + del_timer_sync(&cfg->p2p->listen_timer); + } + + if (cfg->afx_hdl->is_listen == TRUE && + wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + WL_DBG(("Listen DONE for action frame\n")); + complete(&cfg->act_frm_scan); + } +#ifdef WL_CFG80211_SYNC_GON + else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, ndev); + WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n", + jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies))); + + if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); + + complete(&cfg->wait_next_af); + } +#endif /* WL_CFG80211_SYNC_GON */ + +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL)) { +#else + if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL) || + wl_get_drv_status_all(cfg, FAKE_REMAINING_ON_CHANNEL)) { +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + WL_DBG(("Listen DONE for ramain on channel expired\n")); + wl_clr_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_clr_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + if (ndev && (ndev->ieee80211_ptr != NULL)) { +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_remain_on_channel_expired(bcmcfg_to_p2p_wdev(cfg), + cfg->last_roc_id, &cfg->remain_on_chan, GFP_KERNEL); +#else + cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id, + &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ + } + } + if (wl_add_remove_eventmsg(bcmcfg_to_prmry_ndev(cfg), + WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) { + CFGP2P_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); + } + } else + wl_clr_p2p_status(cfg, LISTEN_EXPIRED); + + return ret; + +} + +/* + * Timer expire callback function for LISTEN + * We can't report cfg80211_remain_on_channel_expired from Timer ISR context, + * so lets do it from thread context. + */ +void +wl_cfgp2p_listen_expired(unsigned long data) +{ + wl_event_msg_t msg; + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *) data; + CFGP2P_DBG((" Enter\n")); + bzero(&msg, sizeof(wl_event_msg_t)); + msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); +#if defined(WL_ENABLE_P2P_IF) + wl_cfg80211_event(cfg->p2p_net ? cfg->p2p_net : + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, NULL); +#else + wl_cfg80211_event(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, + NULL); +#endif /* WL_ENABLE_P2P_IF */ +} +/* + * Routine for cancelling the P2P LISTEN + */ +static s32 +wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, + struct wireless_dev *wdev, bool notify) +{ + WL_DBG(("Enter \n")); + /* Irrespective of whether timer is running or not, reset + * the LISTEN state. + */ + if (timer_pending(&cfg->p2p->listen_timer)) { + del_timer_sync(&cfg->p2p->listen_timer); + if (notify) { +#if defined(WL_CFG80211_P2P_DEV_IF) + if (wdev) + cfg80211_remain_on_channel_expired(bcmcfg_to_p2p_wdev(cfg), + cfg->last_roc_id, &cfg->remain_on_chan, GFP_KERNEL); +#else + if (ndev && ndev->ieee80211_ptr) + cfg80211_remain_on_channel_expired(ndev, cfg->last_roc_id, + &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ + } + } + return 0; +} +/* + * Do a P2P Listen on the given channel for the given duration. + * A listen consists of sitting idle and responding to P2P probe requests + * with a P2P probe response. + * + * This fn assumes dongle p2p device discovery is already enabled. + * Parameters : + * @cfg : wl_private data + * @channel : channel to listen + * @duration_ms : the time (milli seconds) to wait + */ +s32 +wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms) +{ +#define EXTRA_DELAY_TIME 100 + s32 ret = BCME_OK; + struct timer_list *_timer; + s32 extra_delay; + struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); + + CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms)); + if (unlikely(wl_get_p2p_status(cfg, DISCOVERY_ON) == 0)) { + + CFGP2P_ERR((" Discovery is not set, so we have noting to do\n")); + + ret = BCME_NOTREADY; + goto exit; + } + if (timer_pending(&cfg->p2p->listen_timer)) { + CFGP2P_DBG(("previous LISTEN is not completed yet\n")); + goto exit; + + } +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + else + wl_clr_p2p_status(cfg, LISTEN_EXPIRED); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) { + CFGP2P_ERR((" failed to set WLC_E_P2P_PROPREQ_MSG\n")); + } + + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + _timer = &cfg->p2p->listen_timer; + + /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , + * otherwise we will wait up to duration_ms + 100ms + duration / 10 + */ + if (ret == BCME_OK) { + extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10); + } else { + /* if failed to set listen, it doesn't need to wait whole duration. */ + duration_ms = 100 + duration_ms / 20; + extra_delay = 0; + } + + INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_clr_p2p_status(cfg, LISTEN_EXPIRED); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +#undef EXTRA_DELAY_TIME +exit: + return ret; +} + + +s32 +wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable) +{ + s32 ret = BCME_OK; + CFGP2P_DBG((" Enter\n")); + if (!wl_get_p2p_status(cfg, DISCOVERY_ON)) { + + CFGP2P_DBG((" do nothing, discovery is off\n")); + return ret; + } + if (wl_get_p2p_status(cfg, SEARCH_ENABLED) == enable) { + CFGP2P_DBG(("already : %d\n", enable)); + return ret; + } + + wl_chg_p2p_status(cfg, SEARCH_ENABLED); + /* When disabling Search, reset the WL driver's p2p discovery state to + * WL_P2P_DISC_ST_SCAN. + */ + if (!enable) { + wl_clr_p2p_status(cfg, SCANNING); + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + } + + return ret; +} + +/* + * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE + */ +s32 +wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 ret = BCME_OK; + u32 event_type = ntoh32(e->event_type); + u32 status = ntoh32(e->status); + struct net_device *ndev = NULL; + CFGP2P_DBG((" Enter\n")); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) { + if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { + + CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); + if (status == WLC_E_STATUS_SUCCESS) { + wl_set_p2p_status(cfg, ACTION_TX_COMPLETED); + CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n")); + if (!cfg->need_wait_afrx && cfg->af_sent_channel) { + CFGP2P_DBG(("no need to wait next AF.\n")); + wl_stop_wait_next_action_frame(cfg, ndev); + } + } + else if (!wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { + wl_set_p2p_status(cfg, ACTION_TX_NOACK); + CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); + wl_stop_wait_next_action_frame(cfg, ndev); + } + } else { + CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," + "status : %d\n", status)); + + if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) + complete(&cfg->send_af_done); + } + } + return ret; +} +/* Send an action frame immediately without doing channel synchronization. + * + * This function does not wait for a completion event before returning. + * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action + * frame is transmitted. + * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an + * 802.11 ack has been received for the sent action frame. + */ +s32 +wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, + wl_af_params_t *af_params, s32 bssidx) +{ + s32 ret = BCME_OK; + s32 evt_ret = BCME_OK; + s32 timeout = 0; + wl_eventmsg_buf_t buf; + + + CFGP2P_INFO(("\n")); + CFGP2P_INFO(("channel : %u , dwell time : %u\n", + af_params->channel, af_params->dwell_time)); + + wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED); + wl_clr_p2p_status(cfg, ACTION_TX_NOACK); + + bzero(&buf, sizeof(wl_eventmsg_buf_t)); + wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true); + wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true); + if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) + return evt_ret; + + cfg->af_sent_channel = af_params->channel; +#ifdef WL_CFG80211_SYNC_GON + cfg->af_tx_sent_jiffies = jiffies; +#endif /* WL_CFG80211_SYNC_GON */ + + ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + if (ret < 0) { + CFGP2P_ERR((" sending action frame is failed\n")); + goto exit; + } + + timeout = wait_for_completion_timeout(&cfg->send_af_done, + msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX)); + + if (timeout >= 0 && wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { + CFGP2P_INFO(("tx action frame operation is completed\n")); + ret = BCME_OK; + } else if (ETHER_ISBCAST(&cfg->afx_hdl->tx_dst_addr)) { + CFGP2P_INFO(("bcast tx action frame operation is completed\n")); + ret = BCME_OK; + } else { + ret = BCME_ERROR; + CFGP2P_INFO(("tx action frame operation is failed\n")); + } + /* clear status bit for action tx */ + wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED); + wl_clr_p2p_status(cfg, ACTION_TX_NOACK); + +exit: + CFGP2P_INFO((" via act frame iovar : status = %d\n", ret)); + + bzero(&buf, sizeof(wl_eventmsg_buf_t)); + wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false); + wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false); + if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) { + WL_ERR(("TX frame events revert back failed \n")); + return evt_ret; + } + + return ret; +} + +/* Generate our P2P Device Address and P2P Interface Address from our primary + * MAC address. + */ +void +wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, + struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr) +{ + memset(out_dev_addr, 0, sizeof(*out_dev_addr)); + memset(out_int_addr, 0, sizeof(*out_int_addr)); + + /* Generate the P2P Device Address. This consists of the device's + * primary MAC address with the locally administered bit set. + */ + memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr)); + out_dev_addr->octet[0] |= 0x02; + + /* Generate the P2P Interface Address. If the discovery and connection + * BSSCFGs need to simultaneously co-exist, then this address must be + * different from the P2P Device Address. + */ + memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr)); + out_int_addr->octet[4] ^= 0x80; + +} + +/* P2P IF Address change to Virtual Interface MAC Address */ +void +wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id) +{ + wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf; + u16 len = ie->len; + u8 *subel; + u8 subelt_id; + u16 subelt_len; + CFGP2P_DBG((" Enter\n")); + + /* Point subel to the P2P IE's subelt field. + * Subtract the preceding fields (id, len, OUI, oui_type) from the length. + */ + subel = ie->subelts; + len -= 4; /* exclude OUI + OUI_TYPE */ + + while (len >= 3) { + /* attribute id */ + subelt_id = *subel; + subel += 1; + len -= 1; + + /* 2-byte little endian */ + subelt_len = *subel++; + subelt_len |= *subel++ << 8; + + len -= 2; + len -= subelt_len; /* for the remaining subelt fields */ + + if (subelt_id == element_id) { + if (subelt_id == P2P_SEID_INTINTADDR) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n")); + } else if (subelt_id == P2P_SEID_DEV_ID) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("Device ID ATTR FOUND\n")); + } else if (subelt_id == P2P_SEID_DEV_INFO) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("Device INFO ATTR FOUND\n")); + } else if (subelt_id == P2P_SEID_GROUP_ID) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("GROUP ID ATTR FOUND\n")); + } return; + } else { + CFGP2P_DBG(("OTHER id : %d\n", subelt_id)); + } + subel += subelt_len; + } +} +/* + * Check if a BSS is up. + * This is a common implementation called by most OSL implementations of + * p2posl_bss_isup(). DO NOT call this function directly from the + * common code -- call p2posl_bss_isup() instead to allow the OSL to + * override the common implementation if necessary. + */ +bool +wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) +{ + s32 result, val; + bool isup = false; + s8 getbuf[64]; + + /* Check if the BSS is up */ + *(int*)getbuf = -1; + result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, + sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL); + if (result != 0) { + CFGP2P_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result)); + CFGP2P_ERR(("NOTE: this ioctl error is normal " + "when the BSS has not been created yet.\n")); + } else { + val = *(int*)getbuf; + val = dtoh32(val); + CFGP2P_INFO(("---cfg bss -C %d ==> %d\n", bsscfg_idx, val)); + isup = (val ? TRUE : FALSE); + } + return isup; +} + + +/* Bring up or down a BSS */ +s32 +wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up) +{ + s32 ret = BCME_OK; + s32 val = up ? 1 : 0; + + struct { + s32 cfg; + s32 val; + } bss_setbuf; + + bss_setbuf.cfg = htod32(bsscfg_idx); + bss_setbuf.val = htod32(val); + CFGP2P_INFO(("---cfg bss -C %d %s\n", bsscfg_idx, up ? "up" : "down")); + ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (ret != 0) { + CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret)); + } + + return ret; +} + +/* Check if 'p2p' is supported in the driver */ +s32 +wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + s32 ret = BCME_OK; + s32 p2p_supported = 0; + ret = wldev_iovar_getint(ndev, "p2p", + &p2p_supported); + if (ret < 0) { + if (ret == BCME_UNSUPPORTED) { + CFGP2P_INFO(("p2p is unsupported\n")); + return 0; + } else { + CFGP2P_ERR(("cfg p2p error %d\n", ret)); + return ret; + } + } + if (p2p_supported == 1) { + CFGP2P_INFO(("p2p is supported\n")); + } else { + CFGP2P_INFO(("p2p is unsupported\n")); + p2p_supported = 0; + } + return p2p_supported; +} +/* Cleanup P2P resources */ +s32 +wl_cfgp2p_down(struct bcm_cfg80211 *cfg) +{ + struct net_device *ndev = NULL; + struct wireless_dev *wdev = NULL; + s32 i = 0, index = -1; + +#if defined(WL_CFG80211_P2P_DEV_IF) + wdev = bcmcfg_to_p2p_wdev(cfg); + ndev = bcmcfg_to_prmry_ndev(cfg); +#elif defined(WL_ENABLE_P2P_IF) + ndev = cfg->p2p_net ? cfg->p2p_net : bcmcfg_to_prmry_ndev(cfg); + wdev = ndev_to_wdev(ndev); +#endif /* WL_CFG80211_P2P_DEV_IF */ + + wl_cfgp2p_cancel_listen(cfg, ndev, wdev, TRUE); + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + index = wl_to_p2p_bss_bssidx(cfg, i); + if (index != WL_INVALID) + wl_cfgp2p_clear_management_ie(cfg, index); + } + wl_cfgp2p_deinit_priv(cfg); + return 0; +} +s32 +wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len) +{ + s32 ret = -1; + int count, start, duration; + wl_p2p_sched_t dongle_noa; + + CFGP2P_DBG((" Enter\n")); + + memset(&dongle_noa, 0, sizeof(dongle_noa)); + + if (cfg->p2p && cfg->p2p->vif_created) { + + cfg->p2p->noa.desc[0].start = 0; + + sscanf(buf, "%10d %10d %10d", &count, &start, &duration); + CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n", + count, start, duration)); + if (count != -1) + cfg->p2p->noa.desc[0].count = count; + + /* supplicant gives interval as start */ + if (start != -1) + cfg->p2p->noa.desc[0].interval = start; + + if (duration != -1) + cfg->p2p->noa.desc[0].duration = duration; + + if (cfg->p2p->noa.desc[0].count != 255 && cfg->p2p->noa.desc[0].count != 0) { + cfg->p2p->noa.desc[0].start = 200; + dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS; + dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF; + dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; + } + else if (cfg->p2p->noa.desc[0].count == 0) { + cfg->p2p->noa.desc[0].start = 0; + dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; + dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; + dongle_noa.action = WL_P2P_SCHED_ACTION_RESET; + } + else { + /* Continuous NoA interval. */ + dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; + dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; + if ((cfg->p2p->noa.desc[0].interval == 102) || + (cfg->p2p->noa.desc[0].interval == 100)) { + cfg->p2p->noa.desc[0].start = 100 - + cfg->p2p->noa.desc[0].duration; + dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT; + } + else { + dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; + } + } + /* Put the noa descriptor in dongle format for dongle */ + dongle_noa.desc[0].count = htod32(cfg->p2p->noa.desc[0].count); + if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) { + dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start); + dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration); + } + else { + dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start*1000); + dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration*1000); + } + dongle_noa.desc[0].interval = htod32(cfg->p2p->noa.desc[0].interval*1000); + + ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION), + "p2p_noa", &dongle_noa, sizeof(dongle_noa), cfg->ioctl_buf, + WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (ret < 0) { + CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret)); + } + } + else { + CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n")); + } + return ret; +} +s32 +wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int buf_len) +{ + + wifi_p2p_noa_desc_t *noa_desc; + int len = 0, i; + char _buf[200]; + + CFGP2P_DBG((" Enter\n")); + buf[0] = '\0'; + if (cfg->p2p && cfg->p2p->vif_created) { + if (cfg->p2p->noa.desc[0].count || cfg->p2p->ops.ops) { + _buf[0] = 1; /* noa index */ + _buf[1] = (cfg->p2p->ops.ops ? 0x80: 0) | + (cfg->p2p->ops.ctw & 0x7f); /* ops + ctw */ + len += 2; + if (cfg->p2p->noa.desc[0].count) { + noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len]; + noa_desc->cnt_type = cfg->p2p->noa.desc[0].count; + noa_desc->duration = cfg->p2p->noa.desc[0].duration; + noa_desc->interval = cfg->p2p->noa.desc[0].interval; + noa_desc->start = cfg->p2p->noa.desc[0].start; + len += sizeof(wifi_p2p_noa_desc_t); + } + if (buf_len <= len * 2) { + CFGP2P_ERR(("ERROR: buf_len %d in not enough for" + "returning noa in string format\n", buf_len)); + return -1; + } + /* We have to convert the buffer data into ASCII strings */ + for (i = 0; i < len; i++) { + snprintf(buf, 3, "%02x", _buf[i]); + buf += 2; + } + buf[i*2] = '\0'; + } + } + else { + CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n")); + return -1; + } + return len * 2; +} +s32 +wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len) +{ + int ps, ctw; + int ret = -1; + s32 legacy_ps; + struct net_device *dev; + + CFGP2P_DBG((" Enter\n")); + if (cfg->p2p && cfg->p2p->vif_created) { + sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw); + CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw)); + dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); + if (ctw != -1) { + cfg->p2p->ops.ctw = ctw; + ret = 0; + } + if (ps != -1) { + cfg->p2p->ops.ops = ps; + ret = wldev_iovar_setbuf(dev, + "p2p_ops", &cfg->p2p->ops, sizeof(cfg->p2p->ops), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (ret < 0) { + CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret)); + } + } + + if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) { + ret = wldev_ioctl_set(dev, + WLC_SET_PM, &legacy_ps, sizeof(legacy_ps)); + if (unlikely(ret)) + CFGP2P_ERR(("error (%d)\n", ret)); + wl_cfg80211_update_power_mode(dev); + } + else + CFGP2P_ERR(("ilegal setting\n")); + } + else { + CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n")); + ret = -1; + } + return ret; +} + +u8 * +wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) +{ + wifi_p2p_ie_t *ie = NULL; + u16 len = 0; + u8 *subel; + u8 subelt_id; + u16 subelt_len; + + if (!buf) { + WL_ERR(("P2P IE not present")); + return 0; + } + + ie = (wifi_p2p_ie_t*) buf; + len = ie->len; + + /* Point subel to the P2P IE's subelt field. + * Subtract the preceding fields (id, len, OUI, oui_type) from the length. + */ + subel = ie->subelts; + len -= 4; /* exclude OUI + OUI_TYPE */ + + while (len >= 3) { + /* attribute id */ + subelt_id = *subel; + subel += 1; + len -= 1; + + /* 2-byte little endian */ + subelt_len = *subel++; + subelt_len |= *subel++ << 8; + + len -= 2; + len -= subelt_len; /* for the remaining subelt fields */ + + if (subelt_id == element_id) { + /* This will point to start of subelement attrib after + * attribute id & len + */ + return subel; + } + + /* Go to next subelement */ + subel += subelt_len; + } + + /* Not Found */ + return NULL; +} + +#define P2P_GROUP_CAPAB_GO_BIT 0x01 + +u8* +wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib) +{ + bcm_tlv_t *ie; + u8* pAttrib; + + CFGP2P_INFO(("Starting parsing parse %p attrib %d remaining len %d ", parse, attrib, len)); + while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len) == TRUE) { + /* Have the P2p ie. Now check for attribute */ + if ((pAttrib = wl_cfgp2p_retreive_p2pattrib(parse, attrib)) != NULL) { + CFGP2P_INFO(("P2P attribute %d was found at parse %p", + attrib, parse)); + return pAttrib; + } + else { + parse += (ie->len + TLV_HDR_LEN); + len -= (ie->len + TLV_HDR_LEN); + CFGP2P_INFO(("P2P Attribute %d not found Moving parse" + " to %p len to %d", attrib, parse, len)); + } + } + else { + /* It was not p2p IE. parse will get updated automatically to next TLV */ + CFGP2P_INFO(("IT was NOT P2P IE parse %p len %d", parse, len)); + } + } + CFGP2P_ERR(("P2P attribute %d was NOT found", attrib)); + return NULL; +} + +u8 * +wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) +{ + u8 *capability = NULL; + bool p2p_go = 0; + u8 *ptr = NULL; + + if ((capability = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, + bi->ie_length, P2P_SEID_P2P_INFO)) == NULL) { + WL_ERR(("P2P Capability attribute not found")); + return NULL; + } + + /* Check Group capability for Group Owner bit */ + p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT; + if (!p2p_go) { + return bi->BSSID.octet; + } + + /* In probe responses, DEVICE INFO attribute will be present */ + if (!(ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, + bi->ie_length, P2P_SEID_DEV_INFO))) { + /* If DEVICE_INFO is not found, this might be a beacon frame. + * check for DEVICE_ID in the beacon frame. + */ + ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, + bi->ie_length, P2P_SEID_DEV_ID); + } + + if (!ptr) + WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE ")); + + return ptr; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +static void +wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) +{ + snprintf(info->driver, sizeof(info->driver), "p2p"); + snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0)); +} + +struct ethtool_ops cfgp2p_ethtool_ops = { + .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + +#if defined(WL_ENABLE_P2P_IF) +s32 +wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg) +{ + int ret = 0; + struct net_device* net = NULL; + struct wireless_dev *wdev = NULL; + uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; + + if (cfg->p2p_net) { + CFGP2P_ERR(("p2p_net defined already.\n")); + return -EINVAL; + } + + /* Allocate etherdev, including space for private structure */ + if (!(net = alloc_etherdev(sizeof(struct bcm_cfg80211 *)))) { + CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); + return -ENODEV; + } + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + free_netdev(net); + return -ENOMEM; + } + + strncpy(net->name, "p2p%d", sizeof(net->name) - 1); + net->name[IFNAMSIZ - 1] = '\0'; + + /* Copy the reference to bcm_cfg80211 */ + memcpy((void *)netdev_priv(net), &cfg, sizeof(struct bcm_cfg80211 *)); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + ASSERT(!net->open); + net->do_ioctl = wl_cfgp2p_do_ioctl; + net->hard_start_xmit = wl_cfgp2p_start_xmit; + net->open = wl_cfgp2p_if_open; + net->stop = wl_cfgp2p_if_stop; +#else + ASSERT(!net->netdev_ops); + net->netdev_ops = &wl_cfgp2p_if_ops; +#endif + + /* Register with a dummy MAC addr */ + memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); + + wdev->wiphy = cfg->wdev->wiphy; + + wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); + + net->ieee80211_ptr = wdev; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + net->ethtool_ops = &cfgp2p_ethtool_ops; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + + SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy)); + + /* Associate p2p0 network interface with new wdev */ + wdev->netdev = net; + + ret = register_netdev(net); + if (ret) { + CFGP2P_ERR((" register_netdevice failed (%d)\n", ret)); + free_netdev(net); + kfree(wdev); + return -ENODEV; + } + + /* store p2p net ptr for further reference. Note that iflist won't have this + * entry as there corresponding firmware interface is a "Hidden" interface. + */ + cfg->p2p_wdev = wdev; + cfg->p2p_net = net; + + printk("%s: P2P Interface Registered\n", net->name); + + return ret; +} + +s32 +wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg) +{ + + if (!cfg || !cfg->p2p_net) { + CFGP2P_ERR(("Invalid Ptr\n")); + return -EINVAL; + } + + unregister_netdev(cfg->p2p_net); + free_netdev(cfg->p2p_net); + + return 0; +} + +static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + + if (skb) + { + CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n", + ndev->name)); + dev_kfree_skb_any(skb); + } + + return 0; +} + +static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd) +{ + int ret = 0; + struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + + /* There is no ifidx corresponding to p2p0 in our firmware. So we should + * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs. + * For Android PRIV CMD handling map it to primary I/F + */ + if (cmd == SIOCDEVPRIVATE+1) { + ret = wl_android_priv_cmd(ndev, ifr, cmd); + + } else { + CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n", + __FUNCTION__, cmd)); + return -1; + } + + return ret; +} +#endif + +#if defined(WL_ENABLE_P2P_IF) +static int wl_cfgp2p_if_open(struct net_device *net) +{ + struct wireless_dev *wdev = net->ieee80211_ptr; + + if (!wdev || !wl_cfg80211_is_p2p_active()) + return -EINVAL; + WL_TRACE(("Enter\n")); +#if !defined(WL_IFACE_COMB_NUM_CHANNELS) + /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, + * do it here. This will make sure that in concurrent mode, supplicant + * is not dependent on a particular order of interface initialization. + * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N + * -iwlan0. + */ + wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO)); +#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ + wl_cfg80211_do_driver_init(net); + + return 0; +} + +static int wl_cfgp2p_if_stop(struct net_device *net) +{ + struct wireless_dev *wdev = net->ieee80211_ptr; + if (!wdev) + return -EINVAL; + + wl_cfg80211_scan_stop(net); + +#if !defined(WL_IFACE_COMB_NUM_CHANNELS) + wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) + & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| + BIT(NL80211_IFTYPE_P2P_GO))); +#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ + return 0; +} +#endif + +#if defined(WL_ENABLE_P2P_IF) +bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops) +{ + return (if_ops == &wl_cfgp2p_if_ops); +} +#endif /* WL_ENABLE_P2P_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +struct wireless_dev * +wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg) +{ + struct wireless_dev *wdev = NULL; + struct ether_addr primary_mac; + + if (!cfg || !cfg->p2p_supported) + return ERR_PTR(-EINVAL); + + WL_TRACE(("Enter\n")); + + if (cfg->p2p_wdev) { + CFGP2P_ERR(("p2p_wdev defined already.\n")); +#if defined(CUSTOMER_HW5) + wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); + CFGP2P_ERR(("p2p_wdev deleted.\n")); +#else + return ERR_PTR(-ENFILE); +#endif + } + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return ERR_PTR(-ENOMEM); + } + + memset(&primary_mac, 0, sizeof(primary_mac)); + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &cfg->p2p->dev_addr, &cfg->p2p->int_addr); + + wdev->wiphy = cfg->wdev->wiphy; + wdev->iftype = NL80211_IFTYPE_P2P_DEVICE; + memcpy(wdev->address, &cfg->p2p->dev_addr, ETHER_ADDR_LEN); + + + /* store p2p wdev ptr for further reference. */ + cfg->p2p_wdev = wdev; + + CFGP2P_ERR(("P2P interface registered\n")); + + return wdev; +} + +int +wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + if (!cfg) + return -EINVAL; + + WL_TRACE(("Enter\n")); + + ret = wl_cfgp2p_set_firm_p2p(cfg); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("Set P2P in firmware failed, ret=%d\n", ret)); + goto exit; + } + + ret = wl_cfgp2p_enable_discovery(cfg, bcmcfg_to_prmry_ndev(cfg), NULL, 0); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P enable discovery failed, ret=%d\n", ret)); + goto exit; + } + + p2p_on(cfg) = true; + + CFGP2P_DBG(("P2P interface started\n")); + +exit: + return ret; +} + +void +wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + if (!cfg) + return; + + WL_TRACE(("Enter\n")); + + ret = wl_cfg80211_scan_stop(wdev); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret)); + } + + if (!cfg->p2p) + return; + + ret = wl_cfgp2p_disable_discovery(cfg); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret)); + } + + p2p_on(cfg) = false; + + CFGP2P_DBG(("P2P interface stopped\n")); + + return; +} + +int +wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg) +{ + bool rollback_lock = false; + + if (!wdev) + return -EINVAL; + + + WL_TRACE(("Enter\n")); + + if (!rtnl_is_locked()) { + rtnl_lock(); + rollback_lock = true; + } + + cfg80211_unregister_wdev(wdev); + + if (rollback_lock) + rtnl_unlock(); + + kfree(wdev); + + if (cfg) + cfg->p2p_wdev = NULL; + + CFGP2P_ERR(("P2P interface unregistered\n")); + + return 0; +} +#endif /* WL_CFG80211_P2P_DEV_IF */ + +void +wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + int status = 0; + + if (!frame || (frame_len < (sizeof(*pact_frm) + WL_P2P_AF_STATUS_OFFSET - 1))) { + return; + } + + if (wl_cfgp2p_is_pub_action(frame, frame_len)) { + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + if (pact_frm->subtype == P2P_PAF_GON_RSP && tx) { + CFGP2P_ACTION(("Check TX P2P Group Owner Negotiation Rsp Frame status\n")); + status = pact_frm->elts[WL_P2P_AF_STATUS_OFFSET]; + if (status) { + cfg->need_wait_afrx = false; + return; + } + } + } + + cfg->need_wait_afrx = true; + return; +} + +int +wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request) +{ + if (request && (request->n_ssids == 1) && + (request->n_channels == 1) && + IS_P2P_SSID(request->ssids[0].ssid, WL_P2P_WILDCARD_SSID_LEN) && + (request->ssids[0].ssid_len > WL_P2P_WILDCARD_SSID_LEN)) { + return true; + } + return false; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.h new file mode 100644 index 000000000000..327b75f574cd --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.h @@ -0,0 +1,422 @@ +/* + * Linux cfgp2p driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgp2p.h 528497 2015-01-22 10:58:38Z $ + */ +#ifndef _wl_cfgp2p_h_ +#define _wl_cfgp2p_h_ +#include +#include + +struct bcm_cfg80211; +extern u32 wl_dbg_level; + +typedef struct wifi_p2p_ie wifi_wfd_ie_t; +/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not + * confuse this with a bsscfg index. This value is an index into the + * saved_ie[] array of structures which in turn contains a bsscfg index field. + */ +typedef enum { + P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ + P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ + P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ + P2PAPI_BSSCFG_MAX +} p2p_bsscfg_type_t; + +typedef enum { + P2P_SCAN_PURPOSE_MIN, + P2P_SCAN_SOCIAL_CHANNEL, /* scan for social channel */ + P2P_SCAN_AFX_PEER_NORMAL, /* scan for action frame search */ + P2P_SCAN_AFX_PEER_REDUCED, /* scan for action frame search with short time */ + P2P_SCAN_DURING_CONNECTED, /* scan during connected status */ + P2P_SCAN_CONNECT_TRY, /* scan for connecting */ + P2P_SCAN_NORMAL, /* scan during not-connected status */ + P2P_SCAN_PURPOSE_MAX +} p2p_scan_purpose_t; + +/* vendor ies max buffer length for probe response or beacon */ +#define VNDR_IES_MAX_BUF_LEN 1400 +/* normal vendor ies buffer length */ +#define VNDR_IES_BUF_LEN 512 + +/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */ +struct p2p_saved_ie { + u8 p2p_probe_req_ie[VNDR_IES_BUF_LEN]; + u8 p2p_probe_res_ie[VNDR_IES_MAX_BUF_LEN]; + u8 p2p_assoc_req_ie[VNDR_IES_BUF_LEN]; + u8 p2p_assoc_res_ie[VNDR_IES_BUF_LEN]; + u8 p2p_beacon_ie[VNDR_IES_MAX_BUF_LEN]; + u32 p2p_probe_req_ie_len; + u32 p2p_probe_res_ie_len; + u32 p2p_assoc_req_ie_len; + u32 p2p_assoc_res_ie_len; + u32 p2p_beacon_ie_len; +}; + +struct p2p_bss { + s32 bssidx; + struct net_device *dev; + struct p2p_saved_ie saved_ie; + void *private_data; +}; + +struct p2p_info { + bool on; /* p2p on/off switch */ + bool scan; + int16 search_state; + bool vif_created; + s8 vir_ifname[IFNAMSIZ]; + unsigned long status; + struct ether_addr dev_addr; + struct ether_addr int_addr; + struct p2p_bss bss[P2PAPI_BSSCFG_MAX]; + struct timer_list listen_timer; + wl_p2p_sched_t noa; + wl_p2p_ops_t ops; + wlc_ssid_t ssid; +}; + +#define MAX_VNDR_IE_NUMBER 5 + +struct parsed_vndr_ie_info { + char *ie_ptr; + u32 ie_len; /* total length including id & length field */ + vndr_ie_t vndrie; +}; + +struct parsed_vndr_ies { + u32 count; + struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; +}; + +/* dongle status */ +enum wl_cfgp2p_status { + WLP2P_STATUS_DISCOVERY_ON = 0, + WLP2P_STATUS_SEARCH_ENABLED, + WLP2P_STATUS_IF_ADDING, + WLP2P_STATUS_IF_DELETING, + WLP2P_STATUS_IF_CHANGING, + WLP2P_STATUS_IF_CHANGED, + WLP2P_STATUS_LISTEN_EXPIRED, + WLP2P_STATUS_ACTION_TX_COMPLETED, + WLP2P_STATUS_ACTION_TX_NOACK, + WLP2P_STATUS_SCANNING, + WLP2P_STATUS_GO_NEG_PHASE, + WLP2P_STATUS_DISC_IN_PROGRESS +}; + + +#define wl_to_p2p_bss_ndev(cfg, type) ((cfg)->p2p->bss[type].dev) +#define wl_to_p2p_bss_bssidx(cfg, type) ((cfg)->p2p->bss[type].bssidx) +#define wl_to_p2p_bss_saved_ie(cfg, type) ((cfg)->p2p->bss[type].saved_ie) +#define wl_to_p2p_bss_private(cfg, type) ((cfg)->p2p->bss[type].private_data) +#define wl_to_p2p_bss(cfg, type) ((cfg)->p2p->bss[type]) +#define wl_get_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ + test_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) +#define wl_set_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ + set_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) +#define wl_clr_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ + clear_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) +#define wl_chg_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ + change_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) +#define p2p_on(cfg) ((cfg)->p2p->on) +#define p2p_scan(cfg) ((cfg)->p2p->scan) +#define p2p_is_on(cfg) ((cfg)->p2p && (cfg)->p2p->on) + +/* dword align allocation */ +#define WLC_IOCTL_MAXLEN 8192 + +#define CFGP2P_ERROR_TEXT "CFGP2P-ERROR) " + + +#define CFGP2P_ERR(args) \ + do { \ + if (wl_dbg_level & WL_DBG_ERR) { \ + printk(KERN_INFO CFGP2P_ERROR_TEXT "%s : ", __func__); \ + printk args; \ + } \ + } while (0) +#define CFGP2P_INFO(args) \ + do { \ + if (wl_dbg_level & WL_DBG_INFO) { \ + printk(KERN_INFO "CFGP2P-INFO) %s : ", __func__); \ + printk args; \ + } \ + } while (0) +#define CFGP2P_DBG(args) \ + do { \ + if (wl_dbg_level & WL_DBG_DBG) { \ + printk(KERN_DEBUG "CFGP2P-DEBUG) %s :", __func__); \ + printk args; \ + } \ + } while (0) + +#define CFGP2P_ACTION(args) \ + do { \ + if (wl_dbg_level & WL_DBG_P2P_ACTION) { \ + printk(KERN_DEBUG "CFGP2P-ACTION) %s :", __func__); \ + printk args; \ + } \ + } while (0) +#define INIT_TIMER(timer, func, duration, extra_delay) \ + do { \ + init_timer(timer); \ + timer->function = func; \ + timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ + timer->data = (unsigned long) cfg; \ + add_timer(timer); \ + } while (0); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_CFG80211_P2P_DEV_IF) +#define WL_CFG80211_P2P_DEV_IF + +#ifdef WL_ENABLE_P2P_IF +#undef WL_ENABLE_P2P_IF +#endif + +#ifdef WL_SUPPORT_BACKPORTED_KPATCHES +#undef WL_SUPPORT_BACKPORTED_KPATCHES +#endif +#else +#ifdef WLP2P +#ifndef WL_ENABLE_P2P_IF +/* Enable P2P network Interface if P2P support is enabled */ +#define WL_ENABLE_P2P_IF +#endif /* WL_ENABLE_P2P_IF */ +#endif /* WLP2P */ +#endif /* (LINUX_VERSION >= VERSION(3, 8, 0)) */ + +#ifndef WL_CFG80211_P2P_DEV_IF +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#if defined(WL_ENABLE_P2P_IF) && (defined(WL_CFG80211_P2P_DEV_IF) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))) +#error Disable 'WL_ENABLE_P2P_IF', if 'WL_CFG80211_P2P_DEV_IF' is enabled \ + or kernel version is 3.8.0 or above +#endif /* WL_ENABLE_P2P_IF && (WL_CFG80211_P2P_DEV_IF || (LINUX_VERSION >= VERSION(3, 8, 0))) */ + +#if !defined(WLP2P) && (defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)) +#error WLP2P not defined +#endif /* !WLP2P && (WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF) */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define bcm_struct_cfgdev struct wireless_dev +#else +#define bcm_struct_cfgdev struct net_device +#endif /* WL_CFG80211_P2P_DEV_IF */ + +extern void +wl_cfgp2p_listen_expired(unsigned long data); +extern bool +wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len); +extern bool +wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len); +extern void +wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel); +extern s32 +wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg); +extern void +wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg); +extern s32 +wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg); +extern s32 +wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, + u32 channel, u16 listen_ms, int bssidx); +extern s32 +wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, + chanspec_t chspec); +extern s32 +wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac); +extern s32 +wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac); +extern s32 +wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, chanspec_t chspec); + +extern s32 +wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index); + +extern s32 +wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg); +extern s32 +wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *ie, + u32 ie_len); +extern s32 +wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg); +extern s32 +wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, u32 num_chans, + u16 *channels, + s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, + p2p_scan_purpose_t p2p_scan_purpose); + +extern s32 +wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, + s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr); + +extern wpa_ie_fixed_t * +wl_cfgp2p_find_wpaie(u8 *parse, u32 len); + +extern wpa_ie_fixed_t * +wl_cfgp2p_find_wpsie(u8 *parse, u32 len); + +extern wifi_p2p_ie_t * +wl_cfgp2p_find_p2pie(u8 *parse, u32 len); + +extern wifi_wfd_ie_t * +wl_cfgp2p_find_wfdie(u8 *parse, u32 len); +extern s32 +wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, + s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len); +extern s32 +wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx); + +extern s32 +wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *index); +extern struct net_device * +wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx); +extern s32 +wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type); + + +extern s32 +wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +extern s32 +wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms); + +extern s32 +wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable); + +extern s32 +wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); + +extern s32 +wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, + wl_af_params_t *af_params, s32 bssidx); + +extern void +wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr, + struct ether_addr *out_int_addr); + +extern void +wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); +extern bool +wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); + +extern s32 +wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up); + + +extern s32 +wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev); + +extern s32 +wl_cfgp2p_down(struct bcm_cfg80211 *cfg); + +extern s32 +wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); + +extern s32 +wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); + +extern s32 +wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); + +extern u8 * +wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id); + +extern u8* +wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib); + +extern u8 * +wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length); + +extern s32 +wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg); + +extern s32 +wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg); + +extern bool +wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops); + +#if defined(WL_CFG80211_P2P_DEV_IF) +extern struct wireless_dev * +wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg); + +extern int +wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); + +extern void +wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); + +extern int +wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ + +extern void +wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx); + +extern int +wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request); + +/* WiFi Direct */ +#define SOCIAL_CHAN_1 1 +#define SOCIAL_CHAN_2 6 +#define SOCIAL_CHAN_3 11 +#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ + (channel == SOCIAL_CHAN_2) || \ + (channel == SOCIAL_CHAN_3)) +#define SOCIAL_CHAN_CNT 3 +#define AF_PEER_SEARCH_CNT 2 +#define WL_P2P_WILDCARD_SSID "DIRECT-" +#define WL_P2P_WILDCARD_SSID_LEN 7 +#define WL_P2P_INTERFACE_PREFIX "p2p" +#define WL_P2P_TEMP_CHAN 11 +#define WL_P2P_AF_STATUS_OFFSET 9 + +/* If the provision discovery is for JOIN operations, + * or the device discoverablity frame is destined to GO + * then we need not do an internal scan to find GO. + */ +#define IS_ACTPUB_WITHOUT_GROUP_ID(p2p_ie, len) \ + (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL) + +#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ + ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ + (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) + +#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \ + ((subtype == P2P_PAF_GON_CONF) || \ + (subtype == P2P_PAF_INVITE_RSP) || \ + (subtype == P2P_PAF_PROVDIS_RSP))) +#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) +#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \ + (len == WL_P2P_WILDCARD_SSID_LEN)) +#endif /* _wl_cfgp2p_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c new file mode 100644 index 000000000000..2422df453b46 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c @@ -0,0 +1,2304 @@ +/* + * Linux cfg80211 Vendor Extension Code + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgvendor.c 455257 2014-02-20 08:10:24Z $ +*/ + +/* + * New vendor interface additon to nl80211/cfg80211 to allow vendors + * to implement proprietary features over the cfg80211 stack. +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef PNO_SUPPORT +#include +#endif /* PNO_SUPPORT */ +#ifdef RTT_SUPPORT +#include +#endif /* RTT_SUPPORT */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef PROP_TXSTATUS +#include +#endif +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) +/* + * This API is to be used for asynchronous vendor events. This + * shouldn't be used in response to a vendor command from its + * do_it handler context (instead wl_cfgvendor_send_cmd_reply should + * be used). + */ +int wl_cfgvendor_send_async_event(struct wiphy *wiphy, + struct net_device *dev, int event_id, const void *data, int len) +{ + u16 kflags; + struct sk_buff *skb; + + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags); + if (!skb) { + WL_ERR(("skb alloc failed")); + return -ENOMEM; + } + + /* Push the data to the skb */ + nla_put_nohdr(skb, len, data); + + cfg80211_vendor_event(skb, kflags); + + return 0; +} + +static int +wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy, + struct net_device *dev, const void *data, int len) +{ + struct sk_buff *skb; + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + return -ENOMEM; + } + + /* Push the data to the skb */ + nla_put_nohdr(skb, len, data); + + return cfg80211_vendor_cmd_reply(skb); +} + +static int wl_cfgvendor_get_feature_set(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int reply; + + reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg)); + + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + &reply, sizeof(int)); + + if (unlikely(err)) + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + + return err; +} + +static int wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct sk_buff *skb; + int *reply; + int num, mem_needed, i; + + reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), &num); + + if (!reply) { + WL_ERR(("Could not get feature list matrix\n")); + err = -EINVAL; + return err; + } + + mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * num) + + ATTRIBUTE_U32_LEN; + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + err = -ENOMEM; + goto exit; + } + + nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, num); + for (i = 0; i < num; i++) { + nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply[i]); + } + + err = cfg80211_vendor_cmd_reply(skb); + + if (unlikely(err)) + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); +exit: + kfree(reply); + return err; +} + +static int +wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + uint8 random_mac_oui[DOT11_OUI_LEN]; + + type = nla_type(data); + + if (type == ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI) { + memcpy(random_mac_oui, nla_data(data), DOT11_OUI_LEN); + + err = dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg), random_mac_oui); + + if (unlikely(err)) + WL_ERR(("Bad OUI, could not set:%d \n", err)); + + } else { + err = -1; + } + + return err; +} + +static int wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; +#ifdef CUSTOM_FORCE_NODFS_FLAG + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + u32 nodfs; + + type = nla_type(data); + if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) { + nodfs = nla_get_u32(data); + err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs); + } else { + err = -1; + } +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + return err; +} + +#ifdef GSCAN_SUPPORT +int +wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, + struct net_device *dev, void *data, int len, wl_vendor_event_t event) +{ + u16 kflags; + const void *ptr; + struct sk_buff *skb; + int malloc_len, total, iter_cnt_to_send, cnt; + gscan_results_cache_t *cache = (gscan_results_cache_t *)data; + + total = len/sizeof(wifi_gscan_result_t); + while (total > 0) { + malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD; + if (malloc_len > NLMSG_DEFAULT_SIZE) { + malloc_len = NLMSG_DEFAULT_SIZE; + } + iter_cnt_to_send = + (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t); + total = total - iter_cnt_to_send; + + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags); + if (!skb) { + WL_ERR(("skb alloc failed")); + return -ENOMEM; + } + + while (cache && iter_cnt_to_send) { + ptr = (const void *) &cache->results[cache->tot_consumed]; + + if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) { + cnt = iter_cnt_to_send; + } else { + cnt = (cache->tot_count - cache->tot_consumed); + } + + iter_cnt_to_send -= cnt; + cache->tot_consumed += cnt; + /* Push the data to the skb */ + nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr); + if (cache->tot_consumed == cache->tot_count) { + cache = cache->next; + } + + } + + cfg80211_vendor_event(skb, kflags); + } + + return 0; +} + +static int +wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pno_gscan_capabilities_t *reply = NULL; + uint32 reply_len = 0; + + + reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GET_CAPABILITIES, NULL, &reply_len); + if (!reply) { + WL_ERR(("Could not get capabilities\n")); + err = -EINVAL; + return err; + } + + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + reply, reply_len); + + if (unlikely(err)) { + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + } + + kfree(reply); + return err; +} + +static int +wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0, type, band; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + uint16 *reply = NULL; + uint32 reply_len = 0, num_channels, mem_needed; + struct sk_buff *skb; + + type = nla_type(data); + + if (type == GSCAN_ATTRIBUTE_BAND) { + band = nla_get_u32(data); + } else { + return -EINVAL; + } + + reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len); + + if (!reply) { + WL_ERR(("Could not get channel list\n")); + err = -EINVAL; + return err; + } + num_channels = reply_len/ sizeof(uint32); + mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2); + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + err = -ENOMEM; + goto exit; + } + + nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels); + nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply); + + err = cfg80211_vendor_cmd_reply(skb); + + if (unlikely(err)) { + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + } +exit: + kfree(reply); + return err; +} + +static int +wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_results_cache_t *results, *iter; + uint32 reply_len, complete = 1; + int32 mem_needed, num_results_iter; + wifi_gscan_result_t *ptr; + uint16 num_scan_ids, num_results; + struct sk_buff *skb; + struct nlattr *scan_hdr, *complete_flag; + + err = dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg)); + if (err != BCME_OK) + return -EBUSY; + + err = dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); + if (err != BCME_OK) { + WL_ERR(("Can't obtain lock to access batch results %d\n", err)); + return -EBUSY; + } + results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len); + + if (!results) { + WL_ERR(("No results to send %d\n", err)); + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + results, 0); + + if (unlikely(err)) + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); + return err; + } + num_scan_ids = reply_len & 0xFFFF; + num_results = (reply_len & 0xFFFF0000) >> 16; + mem_needed = (num_results * sizeof(wifi_gscan_result_t)) + + (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) + + VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN; + + if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) { + mem_needed = (int32)NLMSG_DEFAULT_SIZE; + } + + WL_TRACE(("complete %d mem_needed %d max_mem %d\n", complete, mem_needed, + (int)NLMSG_DEFAULT_SIZE)); + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); + return -ENOMEM; + } + iter = results; + complete_flag = nla_reserve(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, + sizeof(complete)); + mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD); + + while (iter) { + num_results_iter = (mem_needed - (int32)GSCAN_BATCH_RESULT_HDR_LEN); + num_results_iter /= ((int32)sizeof(wifi_gscan_result_t)); + if (num_results_iter <= 0 || + ((iter->tot_count - iter->tot_consumed) > num_results_iter)) { + break; + } + scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS); + /* no more room? we are done then (for now) */ + if (scan_hdr == NULL) { + complete = 0; + break; + } + nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id); + nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag); + num_results_iter = iter->tot_count - iter->tot_consumed; + + nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter); + if (num_results_iter) { + ptr = &iter->results[iter->tot_consumed]; + iter->tot_consumed += num_results_iter; + nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, + num_results_iter * sizeof(wifi_gscan_result_t), ptr); + } + nla_nest_end(skb, scan_hdr); + mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN + + (num_results_iter * sizeof(wifi_gscan_result_t)); + iter = iter->next; + } + /* Returns TRUE if all result consumed */ + complete = dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg)); + memcpy(nla_data(complete_flag), &complete, sizeof(complete)); + dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); + return cfg80211_vendor_cmd_reply(skb); +} + +static int +wl_cfgvendor_initiate_gscan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type, tmp = len; + int run = 0xFF; + int flush = 0; + const struct nlattr *iter; + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE) + run = nla_get_u32(iter); + else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE) + flush = nla_get_u32(iter); + } + + if (run != 0xFF) { + err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush); + + if (unlikely(err)) { + WL_ERR(("Could not run gscan:%d \n", err)); + } + return err; + } else { + return -EINVAL; + } + + +} + +static int +wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + bool real_time = FALSE; + + type = nla_type(data); + + if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) { + real_time = nla_get_u32(data); + + err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time); + + if (unlikely(err)) { + WL_ERR(("Could not run gscan:%d \n", err)); + } + + } else { + err = -EINVAL; + } + + return err; +} + +static int +wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev, + gscan_scan_params_t *scan_param, int num) +{ + struct dhd_pno_gscan_channel_bucket *ch_bucket; + int k = 0; + int type, err = 0, rem; + const struct nlattr *cur, *next; + + nla_for_each_nested(cur, prev, rem) { + type = nla_type(cur); + ch_bucket = scan_param->channel_bucket; + + switch (type) { + case GSCAN_ATTRIBUTE_BUCKET_ID: + break; + case GSCAN_ATTRIBUTE_BUCKET_PERIOD: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + + ch_bucket[num].bucket_freq_multiple = + nla_get_u32(cur)/1000; + break; + case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].num_channels = + nla_get_u32(cur); + if (ch_bucket[num].num_channels > + GSCAN_MAX_CHANNELS_IN_BUCKET) { + WL_ERR(("channel range:%d,bucket:%d\n", + ch_bucket[num].num_channels, + num)); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_BUCKET_CHANNELS: + nla_for_each_nested(next, cur, rem) { + if (k >= + GSCAN_MAX_CHANNELS_IN_BUCKET) { + break; + } + if (nla_len(next) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].chan_list[k] = + nla_get_u32(next); + k++; + } + break; + case GSCAN_ATTRIBUTE_BUCKETS_BAND: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].band = (uint16) + nla_get_u32(cur); + break; + case GSCAN_ATTRIBUTE_REPORT_EVENTS: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].report_flag = (uint8) + nla_get_u32(cur); + break; + case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].repeat = (uint16) + nla_get_u32(cur); + break; + case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].bucket_max_multiple = + nla_get_u32(cur)/1000; + break; + default: + WL_ERR(("bucket attribute type error %d\n", + type)); + err = -EINVAL; + goto exit; + } + } + +exit: + return err; +} + + +static int +wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_scan_params_t *scan_param; + int j = 0; + int type, tmp; + const struct nlattr *iter; + + scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL); + if (!scan_param) { + WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n")); + err = -EINVAL; + return err; + + } + + scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC; + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + + if (j >= GSCAN_MAX_CH_BUCKETS) { + break; + } + + switch (type) { + case GSCAN_ATTRIBUTE_BASE_PERIOD: + if (nla_len(iter) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + scan_param->scan_fr = nla_get_u32(iter)/1000; + break; + case GSCAN_ATTRIBUTE_NUM_BUCKETS: + if (nla_len(iter) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + scan_param->nchannel_buckets = nla_get_u32(iter); + if (scan_param->nchannel_buckets >= + GSCAN_MAX_CH_BUCKETS) { + WL_ERR(("ncha_buck out of range %d\n", + scan_param->nchannel_buckets)); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_CH_BUCKET_1: + case GSCAN_ATTRIBUTE_CH_BUCKET_2: + case GSCAN_ATTRIBUTE_CH_BUCKET_3: + case GSCAN_ATTRIBUTE_CH_BUCKET_4: + case GSCAN_ATTRIBUTE_CH_BUCKET_5: + case GSCAN_ATTRIBUTE_CH_BUCKET_6: + case GSCAN_ATTRIBUTE_CH_BUCKET_7: + err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j); + if (err < 0) { + WL_ERR(("set_scan_cfg_buck error:%d\n", err)); + goto exit; + } + j++; + break; + default: + WL_ERR(("Unknown type %d\n", type)); + err = -EINVAL; + goto exit; + } + } + + err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_SCAN_CFG_ID, scan_param, 0); + + if (err < 0) { + WL_ERR(("Could not set GSCAN scan cfg\n")); + err = -EINVAL; + } + +exit: + kfree(scan_param); + return err; + +} + +static int +wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_hotlist_scan_params_t *hotlist_params; + int tmp, tmp1, tmp2, type, j = 0, dummy; + const struct nlattr *outer, *inner = NULL, *iter; + uint8 flush = 0; + struct bssid_t *pbssid; + + if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) { + WL_ERR(("buffer length :%d wrong - bail out.\n", len)); + return -EINVAL; + } + hotlist_params = kzalloc(sizeof(*hotlist_params) + + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)), + GFP_KERNEL); + + if (!hotlist_params) { + WL_ERR(("Cannot Malloc memory.\n")); + return -ENOMEM; + } + + hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT; + + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS: + pbssid = hotlist_params->bssid; + nla_for_each_nested(outer, iter, tmp) { + nla_for_each_nested(inner, outer, tmp1) { + type = nla_type(inner); + + switch (type) { + case GSCAN_ATTRIBUTE_BSSID: + if (nla_len(inner) != sizeof(pbssid[j].macaddr)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + memcpy(&(pbssid[j].macaddr), + nla_data(inner), + sizeof(pbssid[j].macaddr)); + break; + case GSCAN_ATTRIBUTE_RSSI_LOW: + if (nla_len(inner) != sizeof(uint8)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + pbssid[j].rssi_reporting_threshold = + (int8)nla_get_u8(inner); + break; + case GSCAN_ATTRIBUTE_RSSI_HIGH: + if (nla_len(inner) != sizeof(uint8)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + dummy = (int8)nla_get_u8(inner); + break; + default: + WL_ERR(("ATTR unknown %d\n", type)); + err = -EINVAL; + goto exit; + } + } + if (++j >= PFN_SWC_MAX_NUM_APS) { + WL_ERR(("cap hotlist max:%d\n", j)); + break; + } + } + hotlist_params->nbssid = j; + break; + case GSCAN_ATTRIBUTE_HOTLIST_FLUSH: + if (nla_len(iter) != sizeof(uint8)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + flush = nla_get_u8(iter); + break; + case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: + if (nla_len(iter) != sizeof(uint32)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter); + break; + default: + WL_ERR(("Unknown type %d\n", type)); + err = -EINVAL; + goto exit; + } + } + + if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) { + WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err)); + err = -EINVAL; + goto exit; + } +exit: + kfree(hotlist_params); + return err; +} + +static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_epno_params_t *epno_params; + int tmp, tmp1, tmp2, type, num = 0; + const struct nlattr *outer, *inner, *iter; + uint8 flush = 0, i = 0; + uint16 num_visible_ssid = 0; + + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_EPNO_SSID_LIST: + nla_for_each_nested(outer, iter, tmp) { + epno_params = (dhd_epno_params_t *) + dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GET_EPNO_SSID_ELEM, NULL, &num); + if (!epno_params) { + WL_ERR(("Failed to get SSID LIST buffer\n")); + err = -ENOMEM; + goto exit; + } + i++; + nla_for_each_nested(inner, outer, tmp1) { + type = nla_type(inner); + + switch (type) { + case GSCAN_ATTRIBUTE_EPNO_SSID: + memcpy(epno_params->ssid, + nla_data(inner), + DOT11_MAX_SSID_LEN); + break; + case GSCAN_ATTRIBUTE_EPNO_SSID_LEN: + len = nla_get_u8(inner); + if (len < DOT11_MAX_SSID_LEN) { + epno_params->ssid_len = len; + } else { + WL_ERR(("SSID toolong %d\n", + len)); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_EPNO_RSSI: + epno_params->rssi_thresh = + (int8) nla_get_u32(inner); + break; + case GSCAN_ATTRIBUTE_EPNO_FLAGS: + epno_params->flags = + nla_get_u8(inner); + if (!(epno_params->flags & + DHD_PNO_USE_SSID)) + num_visible_ssid++; + break; + case GSCAN_ATTRIBUTE_EPNO_AUTH: + epno_params->auth = + nla_get_u8(inner); + break; + } + } + } + break; + case GSCAN_ATTRIBUTE_EPNO_SSID_NUM: + num = nla_get_u8(iter); + break; + case GSCAN_ATTRIBUTE_EPNO_FLUSH: + flush = nla_get_u8(iter); + dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_EPNO_CFG_ID, NULL, flush); + break; + default: + WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); + err = -EINVAL; + goto exit; + } + + } + if (i != num) { + WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__, + num, i)); + err = -EINVAL; + } +exit: + /* Flush all configs if error condition */ + flush = (err < 0) ? TRUE: FALSE; + dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_EPNO_CFG_ID, &num_visible_ssid, flush); + return err; +} + +static int +wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0, tmp, type; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_batch_params_t batch_param; + const struct nlattr *iter; + + batch_param.mscan = batch_param.bestn = 0; + batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET; + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + + switch (type) { + case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN: + batch_param.bestn = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE: + batch_param.mscan = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_REPORT_THRESHOLD: + batch_param.buffer_threshold = nla_get_u32(iter); + break; + default: + WL_ERR(("Unknown type %d\n", type)); + break; + } + } + + if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_BATCH_SCAN_CFG_ID, + &batch_param, 0) < 0) { + WL_ERR(("Could not set batch cfg\n")); + err = -EINVAL; + return err; + } + + return err; +} + +static int +wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_swc_params_t *significant_params; + int tmp, tmp1, tmp2, type, j = 0; + const struct nlattr *outer, *inner, *iter; + uint8 flush = 0; + wl_pfn_significant_bssid_t *bssid; + uint16 num_bssid = 0; + uint16 max_buf_size = sizeof(gscan_swc_params_t) + + sizeof(wl_pfn_significant_bssid_t) * (PFN_SWC_MAX_NUM_APS - 1); + + significant_params = kzalloc(max_buf_size, GFP_KERNEL); + if (!significant_params) { + WL_ERR(("Cannot Malloc mem size:%d\n", max_buf_size)); + return BCME_NOMEM; + } + + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + + switch (type) { + case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH: + flush = nla_get_u8(iter); + break; + case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE: + significant_params->rssi_window = nla_get_u16(iter); + break; + case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: + significant_params->lost_ap_window = nla_get_u16(iter); + break; + case GSCAN_ATTRIBUTE_MIN_BREACHING: + significant_params->swc_threshold = nla_get_u16(iter); + break; + case GSCAN_ATTRIBUTE_NUM_BSSID: + num_bssid = nla_get_u16(iter); + if (num_bssid > PFN_SWC_MAX_NUM_APS) { + WL_ERR(("ovar max SWC bssids:%d\n", + num_bssid)); + err = BCME_BADARG; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS: + if (num_bssid == 0) { + WL_ERR(("num_bssid : 0\n")); + err = BCME_BADARG; + goto exit; + } + bssid = significant_params->bssid_elem_list; + nla_for_each_nested(outer, iter, tmp) { + if (j >= num_bssid) { + j++; + break; + } + nla_for_each_nested(inner, outer, tmp1) { + switch (nla_type(inner)) { + case GSCAN_ATTRIBUTE_BSSID: + memcpy(&(bssid[j].macaddr), + nla_data(inner), + ETHER_ADDR_LEN); + break; + case GSCAN_ATTRIBUTE_RSSI_HIGH: + bssid[j].rssi_high_threshold + = (int8) nla_get_u8(inner); + break; + case GSCAN_ATTRIBUTE_RSSI_LOW: + bssid[j].rssi_low_threshold + = (int8) nla_get_u8(inner); + break; + default: + WL_ERR(("ATTR unknown %d\n", + type)); + break; + } + } + j++; + } + break; + default: + WL_ERR(("Unknown type %d\n", type)); + break; + } + } + if (j != num_bssid) { + WL_ERR(("swc bssids count:%d not matched to num_bssid:%d\n", + j, num_bssid)); + err = BCME_BADARG; + goto exit; + } + significant_params->nbssid = j; + + if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, + significant_params, flush) < 0) { + WL_ERR(("Could not set GSCAN significant cfg\n")); + err = BCME_ERROR; + goto exit; + } +exit: + kfree(significant_params); + return err; +} + +static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = -EINVAL; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + uint32 lazy_roam_enable_flag; + + type = nla_type(data); + + if (type == GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE) { + lazy_roam_enable_flag = nla_get_u32(data); + + err = dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg), + lazy_roam_enable_flag); + + if (unlikely(err)) + WL_ERR(("Could not enable lazy roam:%d \n", err)); + + } + return err; +} + +static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0, tmp, type; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + wlc_roam_exp_params_t roam_param; + const struct nlattr *iter; + + memset(&roam_param, 0, sizeof(roam_param)); + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + + switch (type) { + case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD: + roam_param.a_band_boost_threshold = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD: + roam_param.a_band_penalty_threshold = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR: + roam_param.a_band_boost_factor = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR: + roam_param.a_band_penalty_factor = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST: + roam_param.a_band_max_boost = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS: + roam_param.cur_bssid_boost = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER: + roam_param.alert_roam_trigger_threshold = nla_get_u32(iter); + break; + } + } + + if (dhd_dev_set_lazy_roam_cfg(bcmcfg_to_prmry_ndev(cfg), &roam_param) < 0) { + WL_ERR(("Could not set batch cfg\n")); + err = -EINVAL; + } + return err; +} + +/* small helper function */ +static wl_bssid_pref_cfg_t * +create_bssid_pref_cfg(uint32 num) +{ + uint32 mem_needed; + wl_bssid_pref_cfg_t *bssid_pref; + + mem_needed = sizeof(wl_bssid_pref_cfg_t); + if (num) + mem_needed += (num - 1) * sizeof(wl_bssid_pref_list_t); + bssid_pref = (wl_bssid_pref_cfg_t *) kmalloc(mem_needed, GFP_KERNEL); + return bssid_pref; +} + +static int +wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + wl_bssid_pref_cfg_t *bssid_pref = NULL; + wl_bssid_pref_list_t *bssids; + int tmp, tmp1, tmp2, type; + const struct nlattr *outer, *inner, *iter; + uint32 flush = 0, i = 0, num = 0; + + /* Assumption: NUM attribute must come first */ + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_NUM_BSSID: + num = nla_get_u32(iter); + if (num > MAX_BSSID_PREF_LIST_NUM) { + WL_ERR(("Too many Preferred BSSIDs!\n")); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH: + flush = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_BSSID_PREF_LIST: + if (!num) + return -EINVAL; + if ((bssid_pref = create_bssid_pref_cfg(num)) == NULL) { + WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__)); + err = -ENOMEM; + goto exit; + } + bssid_pref->count = num; + bssids = bssid_pref->bssids; + nla_for_each_nested(outer, iter, tmp) { + if (i >= num) { + WL_ERR(("CFGs don't seem right!\n")); + err = -EINVAL; + goto exit; + } + nla_for_each_nested(inner, outer, tmp1) { + type = nla_type(inner); + switch (type) { + case GSCAN_ATTRIBUTE_BSSID_PREF: + memcpy(&(bssids[i].bssid), + nla_data(inner), ETHER_ADDR_LEN); + /* not used for now */ + bssids[i].flags = 0; + break; + case GSCAN_ATTRIBUTE_RSSI_MODIFIER: + bssids[i].rssi_factor = + (int8) nla_get_u32(inner); + break; + } + } + i++; + } + break; + default: + WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); + break; + } + } + + if (!bssid_pref) { + /* What if only flush is desired? */ + if (flush) { + if ((bssid_pref = create_bssid_pref_cfg(0)) == NULL) { + WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__)); + err = -ENOMEM; + goto exit; + } + bssid_pref->count = 0; + } else { + err = -EINVAL; + goto exit; + } + } + err = dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg), + bssid_pref, flush); +exit: + kfree(bssid_pref); + return err; +} + + +static int +wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + maclist_t *blacklist = NULL; + int err = 0; + int type, tmp; + const struct nlattr *iter; + uint32 mem_needed = 0, flush = 0, i = 0, num = 0; + + /* Assumption: NUM attribute must come first */ + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_NUM_BSSID: + num = nla_get_u32(iter); + if (num > MAX_BSSID_BLACKLIST_NUM) { + WL_ERR(("Too many Blacklist BSSIDs!\n")); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH: + flush = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_BLACKLIST_BSSID: + if (num) { + if (!blacklist) { + mem_needed = sizeof(maclist_t) + + sizeof(struct ether_addr) * (num - 1); + blacklist = (maclist_t *) + kmalloc(mem_needed, GFP_KERNEL); + if (!blacklist) { + WL_ERR(("%s: Can't malloc %d bytes\n", + __FUNCTION__, mem_needed)); + err = -ENOMEM; + goto exit; + } + blacklist->count = num; + } + if (i >= num) { + WL_ERR(("CFGs don't seem right!\n")); + err = -EINVAL; + goto exit; + } + memcpy(&(blacklist->ea[i]), + nla_data(iter), ETHER_ADDR_LEN); + i++; + } + break; + default: + WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); + break; + } + } + err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg), + blacklist, mem_needed, flush); +exit: + kfree(blacklist); + return err; +} + +static int +wl_cfgvendor_set_ssid_whitelist(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + wl_ssid_whitelist_t *ssid_whitelist = NULL; + wlc_ssid_t *ssid_elem; + int tmp, tmp2, mem_needed = 0, type; + const struct nlattr *inner, *iter; + uint32 flush = 0, i = 0, num = 0; + + /* Assumption: NUM attribute must come first */ + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_NUM_WL_SSID: + num = nla_get_u32(iter); + if (num > MAX_SSID_WHITELIST_NUM) { + WL_ERR(("Too many WL SSIDs!\n")); + err = -EINVAL; + goto exit; + } + mem_needed = sizeof(wl_ssid_whitelist_t); + if (num) + mem_needed += (num - 1) * sizeof(ssid_info_t); + ssid_whitelist = (wl_ssid_whitelist_t *) + kzalloc(mem_needed, GFP_KERNEL); + if (ssid_whitelist == NULL) { + WL_ERR(("%s: Can't malloc %d bytes\n", + __FUNCTION__, mem_needed)); + err = -ENOMEM; + goto exit; + } + ssid_whitelist->ssid_count = num; + break; + case GSCAN_ATTRIBUTE_WL_SSID_FLUSH: + flush = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM: + if (!num || !ssid_whitelist) { + WL_ERR(("num ssid is not set!\n")); + return -EINVAL; + } + if (i >= num) { + WL_ERR(("CFGs don't seem right!\n")); + err = -EINVAL; + goto exit; + } + ssid_elem = &ssid_whitelist->ssids[i]; + nla_for_each_nested(inner, iter, tmp) { + type = nla_type(inner); + switch (type) { + case GSCAN_ATTRIBUTE_WHITELIST_SSID: + memcpy(ssid_elem->SSID, + nla_data(inner), + DOT11_MAX_SSID_LEN); + break; + case GSCAN_ATTRIBUTE_WL_SSID_LEN: + ssid_elem->SSID_len = (uint8) + nla_get_u32(inner); + break; + } + } + i++; + break; + default: + WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); + break; + } + } + + err = dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg), + ssid_whitelist, mem_needed, flush); +exit: + kfree(ssid_whitelist); + return err; +} +#endif /* GSCAN_SUPPORT */ + +static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0, tmp, type, start = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int8 max_rssi = 0, min_rssi = 0; + const struct nlattr *iter; + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + switch (type) { + case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI: + max_rssi = (int8) nla_get_u32(iter); + break; + case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI: + min_rssi = (int8) nla_get_u32(iter); + break; + case RSSI_MONITOR_ATTRIBUTE_START: + start = nla_get_u32(iter); + } + } + + if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg), + start, max_rssi, min_rssi) < 0) { + WL_ERR(("Could not set rssi monitor cfg\n")); + err = -EINVAL; + } + return err; +} + +#ifdef RTT_SUPPORT +void +wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data) +{ + struct wireless_dev *wdev = (struct wireless_dev *)ctx; + struct wiphy *wiphy; + struct sk_buff *skb; + uint32 complete = 0; + gfp_t kflags; + rtt_result_t *rtt_result; + rtt_results_header_t *rtt_header; + struct list_head *rtt_cache_list; + struct nlattr *rtt_nl_hdr; + wiphy = wdev->wiphy; + + WL_DBG(("In\n")); + /* Push the data to the skb */ + if (!rtt_data) { + WL_ERR(("rtt_data is NULL\n")); + goto exit; + } + rtt_cache_list = (struct list_head *)rtt_data; + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + list_for_each_entry(rtt_header, rtt_cache_list, list) { + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_event_alloc(wiphy, rtt_header->result_tot_len + 100, + GOOGLE_RTT_COMPLETE_EVENT, kflags); + if (!skb) { + WL_ERR(("skb alloc failed")); + goto exit; + } + if (list_is_last(&rtt_header->list, rtt_cache_list)) { + complete = 1; + } + nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, complete); + rtt_nl_hdr = nla_nest_start(skb, RTT_ATTRIBUTE_RESULTS_PER_TARGET); + if (!rtt_nl_hdr) { + WL_ERR(("rtt_nl_hdr is NULL\n")); + break; + } + nla_put(skb, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN, &rtt_header->peer_mac); + nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_CNT, rtt_header->result_cnt); + list_for_each_entry(rtt_result, &rtt_header->result_list, list) { + nla_put(skb, RTT_ATTRIBUTE_RESULT, + rtt_result->report_len, &rtt_result->report); + } + nla_nest_end(skb, rtt_nl_hdr); + cfg80211_vendor_event(skb, kflags); + } +exit: + return; +} + +static int +wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) { + int err = 0, rem, rem1, rem2, type; + int target_cnt; + rtt_config_params_t rtt_param; + rtt_target_info_t* rtt_target = NULL; + const struct nlattr *iter, *iter1, *iter2; + int8 eabuf[ETHER_ADDR_STR_LEN]; + int8 chanbuf[CHANSPEC_STR_LEN]; + int32 feature_set = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + rtt_capabilities_t capability; + feature_set = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg)); + + WL_DBG(("In\n")); + err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt); + if (err < 0) { + WL_ERR(("failed to register rtt_noti_callback\n")); + goto exit; + } + err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability); + if (err < 0) { + WL_ERR(("failed to get the capability\n")); + goto exit; + } + memset(&rtt_param, 0, sizeof(rtt_param)); + if (len <= 0) { + WL_ERR(("Length of the nlattr is not valid len : %d\n", len)); + err = BCME_ERROR; + goto exit; + } + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case RTT_ATTRIBUTE_TARGET_CNT: + target_cnt = nla_get_u8(iter); + if ((target_cnt <= 0) || (target_cnt > RTT_MAX_TARGET_CNT)) { + WL_ERR(("target_cnt is not valid : %d\n", + target_cnt)); + err = BCME_RANGE; + goto exit; + } + rtt_param.rtt_target_cnt = target_cnt; + rtt_param.target_info = kzalloc(TARGET_INFO_SIZE(target_cnt), GFP_KERNEL); + if (rtt_param.target_info == NULL) { + WL_ERR(("failed to allocate target info for (%d)\n", target_cnt)); + err = BCME_NOMEM; + goto exit; + } + break; + case RTT_ATTRIBUTE_TARGET_INFO: + /* Added this variable for safe check to avoid crash + * incase the caller did not respect the order + */ + if (rtt_param.target_info == NULL) { + WL_ERR(("rtt_target_info is NULL\n")); + err = BCME_NOMEM; + goto exit; + } + rtt_target = rtt_param.target_info; + nla_for_each_nested(iter1, iter, rem1) { + nla_for_each_nested(iter2, iter1, rem2) { + type = nla_type(iter2); + switch (type) { + case RTT_ATTRIBUTE_TARGET_MAC: + memcpy(&rtt_target->addr, nla_data(iter2), + ETHER_ADDR_LEN); + break; + case RTT_ATTRIBUTE_TARGET_TYPE: + rtt_target->type = nla_get_u8(iter2); + if (rtt_target->type == RTT_INVALID || + (rtt_target->type == RTT_ONE_WAY && + !capability.rtt_one_sided_supported)) { + WL_ERR(("doesn't support RTT type" + " : %d\n", + rtt_target->type)); + err = -EINVAL; + goto exit; + } + break; + case RTT_ATTRIBUTE_TARGET_PEER: + rtt_target->peer = nla_get_u8(iter2); + break; + case RTT_ATTRIBUTE_TARGET_CHAN: + memcpy(&rtt_target->channel, nla_data(iter2), + sizeof(rtt_target->channel)); + break; + case RTT_ATTRIBUTE_TARGET_INTERVAL: + rtt_target->interval = nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_NUM_BURST: + rtt_target->num_burst = nla_get_u32(iter2); + if (!(rtt_target->num_burst == 1 || + ISPOWEROF2(rtt_target->num_burst))) { + WL_ERR(("%d value must be power of 2" + " or 1\n", + rtt_target->num_burst)); + err = -EINVAL; + goto exit; + } + break; + case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST: + rtt_target->num_frames_per_burst = + nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM: + rtt_target->num_retries_per_ftm = + nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR: + rtt_target->num_retries_per_ftmr = + nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_LCI: + rtt_target->LCI_request = nla_get_u8(iter2); + break; + case RTT_ATTRIBUTE_TARGET_LCR: + rtt_target->LCI_request = nla_get_u8(iter2); + break; + case RTT_ATTRIBUTE_TARGET_BURST_TIMEOUT: + rtt_target->burst_timeout = nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_BW: + rtt_target->bw = nla_get_u8(iter2); + } + } + /* convert to chanspec value */ + rtt_target->chanspec = + dhd_rtt_convert_to_chspec(rtt_target->channel); + if (rtt_target->chanspec == 0) { + WL_ERR(("Channel is not valid \n")); + err = -EINVAL; + goto exit; + } + WL_INFORM(("Target addr %s, Channel : %s for RTT \n", + bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, + eabuf), + wf_chspec_ntoa(rtt_target->chanspec, chanbuf))); + rtt_target++; + } + break; + } + } + WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt)); + if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) { + WL_ERR(("Could not set RTT configuration\n")); + err = -EINVAL; + } +exit: + /* free the target info list */ + if (rtt_param.target_info) { + kfree(rtt_param.target_info); + rtt_param.target_info = NULL; + } + return err; +} + +static int +wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) +{ + int err = 0, rem, type, target_cnt = 0; + int target_cnt_chk = 0; + const struct nlattr *iter; + struct ether_addr *mac_list = NULL, *mac_addr = NULL; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + if (len <= 0) { + WL_ERR(("Length of nlattr is not valid len : %d\n", len)); + err = -EINVAL; + goto exit; + } + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case RTT_ATTRIBUTE_TARGET_CNT: + if (mac_list != NULL) { + WL_ERR(("mac_list is not NULL\n")); + err = -EINVAL; + goto exit; + } + target_cnt = nla_get_u8(iter); + if ((target_cnt > 0) && (target_cnt < RTT_MAX_TARGET_CNT)) { + mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN, + GFP_KERNEL); + if (mac_list == NULL) { + WL_ERR(("failed to allocate mem for mac list\n")); + err = -EINVAL; + goto exit; + } + mac_addr = &mac_list[0]; + } else { + /* cancel the current whole RTT process */ + goto cancel; + } + break; + case RTT_ATTRIBUTE_TARGET_MAC: + if (mac_addr) { + memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN); + target_cnt_chk++; + if (target_cnt_chk > target_cnt) { + WL_ERR(("over target count\n")); + err = -EINVAL; + goto exit; + } + break; + } else { + WL_ERR(("mac_list is NULL\n")); + err = -EINVAL; + goto exit; + } + } + } +cancel: + if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) { + WL_ERR(("Could not cancel RTT configuration\n")); + err = -EINVAL; + } + +exit: + if (mac_list) { + kfree(mac_list); + } + return err; +} +static int +wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + rtt_capabilities_t capability; + + err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability); + if (unlikely(err)) { + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + goto exit; + } + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + &capability, sizeof(capability)); + + if (unlikely(err)) { + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + } +exit: + return err; +} + +#endif /* RTT_SUPPORT */ + +#if defined(KEEP_ALIVE) +static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) +{ + /* max size of IP packet for keep alive */ + const int MKEEP_ALIVE_IP_PKT_MAX = 256; + + int ret = BCME_OK, rem, type; + u8 mkeep_alive_id = 0; + u8 *ip_pkt = NULL; + u16 ip_pkt_len = 0; + u8 src_mac[ETHER_ADDR_LEN]; + u8 dst_mac[ETHER_ADDR_LEN]; + u32 period_msec = 0; + const struct nlattr *iter; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhd_pub = cfg->pub; + gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case MKEEP_ALIVE_ATTRIBUTE_ID: + mkeep_alive_id = nla_get_u8(iter); + break; + case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN: + ip_pkt_len = nla_get_u16(iter); + if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) { + ret = BCME_BADARG; + goto exit; + } + break; + case MKEEP_ALIVE_ATTRIBUTE_IP_PKT: + ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags); + if (ip_pkt == NULL) { + ret = BCME_NOMEM; + WL_ERR(("Failed to allocate mem for ip packet\n")); + goto exit; + } + memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len); + break; + case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR: + memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN); + break; + case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR: + memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN); + break; + case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC: + period_msec = nla_get_u32(iter); + break; + default: + WL_ERR(("Unknown type: %d\n", type)); + ret = BCME_BADARG; + goto exit; + } + } + + ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac, + dst_mac, period_msec); + if (ret < 0) { + WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret)); + } + +exit: + if (ip_pkt) { + kfree(ip_pkt); + } + + return ret; +} + +static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) +{ + int ret = BCME_OK, rem, type; + u8 mkeep_alive_id = 0; + const struct nlattr *iter; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhd_pub = cfg->pub; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case MKEEP_ALIVE_ATTRIBUTE_ID: + mkeep_alive_id = nla_get_u8(iter); + break; + default: + WL_ERR(("Unknown type: %d\n", type)); + ret = BCME_BADARG; + break; + } + } + + ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id); + if (ret < 0) { + WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret)); + } + + return ret; +} +#endif /* defined(KEEP_ALIVE) */ + +static int +wl_cfgvendor_priv_string_handler(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int err = 0; + int data_len = 0; + + WL_TRACE(("%s: Enter \n", __func__)); + + bzero(cfg->ioctl_buf, WLC_IOCTL_MAXLEN); + + if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) { + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + data_len = strlen(cfg->ioctl_buf); + } + + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + cfg->ioctl_buf, data_len+1); + if (unlikely(err)) + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + else + WL_INFORM(("Vendor Command reply sent successfully!\n")); + + return err; +} + +#ifdef LINKSTAT_SUPPORT +#define NUM_RATE 32 +#define NUM_PEER 1 +#define NUM_CHAN 11 +static int +wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + char *iovar_buf = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int err = 0; + wifi_iface_stat *iface; + wifi_radio_stat *radio; + wl_wme_cnt_t *wl_wme_cnt; + wl_cnt_t *wl_cnt; + char *output; + int radstat_buflen = sizeof(wifi_radio_stat) + NUM_CHAN * sizeof(wifi_channel_stat); + int iface_buflen = sizeof(wifi_iface_stat) + NUM_PEER * sizeof(wifi_peer_info); + int ratestat_buflen = NUM_RATE * sizeof(wifi_rate_stat); + scb_val_t scbval; + + WL_TRACE(("%s: Enter \n", __FUNCTION__)); + + RETURN_EIO_IF_NOT_UP(cfg); + + bzero(&scbval, sizeof(scb_val_t)); + + iovar_buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL); + if (unlikely(!iovar_buf)) { + WL_ERR(("%s: link stats buf alloc fails\n", __FUNCTION__)); + return -ENOMEM; + } + + ASSERT((radstat_buflen + iface_buflen + ratestat_buflen) <= + (sizeof(char) * WLC_IOCTL_MAXLEN)); + + output = iovar_buf; + radio = (wifi_radio_stat *)output; + + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("%s: ioctl error(%d) for radiostat - size = %zu\n", + __FUNCTION__, err, sizeof(wifi_radio_stat))); + goto exit; + } + memcpy(output, cfg->ioctl_buf, sizeof(wifi_radio_stat)); + + radio->num_channels = NUM_CHAN; + output += radstat_buflen; + + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "wme_counters", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("%s: ioctl error(%d) for wme_counters\n", __FUNCTION__, err)); + goto exit; + } + wl_wme_cnt = (wl_wme_cnt_t *)cfg->ioctl_buf; + iface = (wifi_iface_stat *)output; + + iface->ac[WIFI_AC_VO].ac = WIFI_AC_VO; + iface->ac[WIFI_AC_VO].tx_mpdu = wl_wme_cnt->tx[AC_VO].packets; + iface->ac[WIFI_AC_VO].rx_mpdu = wl_wme_cnt->rx[AC_VO].packets; + iface->ac[WIFI_AC_VO].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VO].packets; + + iface->ac[WIFI_AC_VI].ac = WIFI_AC_VI; + iface->ac[WIFI_AC_VI].tx_mpdu = wl_wme_cnt->tx[AC_VI].packets; + iface->ac[WIFI_AC_VI].rx_mpdu = wl_wme_cnt->rx[AC_VI].packets; + iface->ac[WIFI_AC_VI].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VI].packets; + + iface->ac[WIFI_AC_BE].ac = WIFI_AC_BE; + iface->ac[WIFI_AC_BE].tx_mpdu = wl_wme_cnt->tx[AC_BE].packets; + iface->ac[WIFI_AC_BE].rx_mpdu = wl_wme_cnt->rx[AC_BE].packets; + iface->ac[WIFI_AC_BE].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BE].packets; + + iface->ac[WIFI_AC_BK].ac = WIFI_AC_BK; + iface->ac[WIFI_AC_BK].tx_mpdu = wl_wme_cnt->tx[AC_BK].packets; + iface->ac[WIFI_AC_BK].rx_mpdu = wl_wme_cnt->rx[AC_BK].packets; + iface->ac[WIFI_AC_BK].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BK].packets; + + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("%s: ioctl error(%d) for counters - size = %zu\n", + __FUNCTION__, err, sizeof(wl_cnt_t))); + goto exit; + } + wl_cnt = (wl_cnt_t *)cfg->ioctl_buf; + iface->ac[WIFI_AC_BE].retries = wl_cnt->txretry; + iface->beacon_rx = wl_cnt->rxbeaconmbss; + + err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval); + if (unlikely(err)) { + WL_ERR(("%s: get_rssi error(%d)\n", __FUNCTION__, err)); + goto exit; + } + iface->rssi_mgmt = scbval.val; + + iface->num_peers = NUM_PEER; + iface->peer_info->num_rate = NUM_RATE; + + output = (char *)iface + iface_buflen; + + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("%s: ioctl error(%d) for ratestat - size = %d\n", + __FUNCTION__, err, ratestat_buflen)); + goto exit; + } + memcpy(output, cfg->ioctl_buf, ratestat_buflen); + + if (unlikely(radio->num_channels != NUM_CHAN)) { + WL_ERR(("%s: error! num_channels corrupted. value=%d \n", + __FUNCTION__, (int)radio->num_channels)); + goto exit; + } + + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + iovar_buf, radstat_buflen + iface_buflen + ratestat_buflen); + if (unlikely(err)) { + WL_ERR(("%s: Vendor Command reply failed ret:%d \n", __FUNCTION__, err)); + } + +exit: + + if (iovar_buf) { + kfree(iovar_buf); + } + return err; +} +#endif /* LINKSTAT_SUPPORT */ + +static int wl_cfgvendor_set_country(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = BCME_ERROR, rem, type; + char country_code[WLC_CNTRY_BUF_SZ] = {0}; + const struct nlattr *iter; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case ANDR_WIFI_ATTRIBUTE_COUNTRY: + memcpy(country_code, nla_data(iter), + MIN(nla_len(iter), WLC_CNTRY_BUF_SZ)); + break; + default: + WL_ERR(("Unknown type: %d\n", type)); + return err; + } + } + + err = wldev_set_country(wdev->netdev, country_code, true, true); + if (err < 0) { + WL_ERR(("Set country failed ret:%d\n", err)); + } + + return err; +} + +static const struct wiphy_vendor_command wl_vendor_cmds [] = { + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_PRIV_STR + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_priv_string_handler + }, +#ifdef GSCAN_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_get_capabilities + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_scan_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_batch_scan_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_initiate_gscan + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_enable_full_scan_result + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_HOTLIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_hotlist_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_significant_change_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_get_batch_results + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_get_channel_list + }, +#endif /* GSCAN_SUPPORT */ +#ifdef KEEP_ALIVE + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_start_mkeep_alive + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_stop_mkeep_alive + }, +#endif /* KEEP_ALIVE */ +#ifdef RTT_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_SET_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_set_config + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_CANCEL_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_cancel_config + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_GETCAPABILITY + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_get_capability + }, +#endif /* RTT_SUPPORT */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_get_feature_set + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_get_feature_set_matrix + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_RANDOM_MAC_OUI + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_rand_mac_oui + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_NODFS_CHANNELS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_nodfs_flag + + }, +#ifdef LINKSTAT_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = LSTATS_SUBCMD_GET_INFO + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_lstats_get_info + }, +#endif /* LINKSTAT_SUPPORT */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_SET_COUNTRY + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_country + }, +#ifdef GSCAN_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_epno_cfg + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_ssid_whitelist + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_lazy_roam_cfg + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_enable_lazy_roam + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_BSSID_PREF + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_bssid_pref + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_bssid_blacklist + }, +#endif /* GSCAN_SUPPORT */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_rssi_monitor + } +}; + +static const struct nl80211_vendor_cmd_info wl_vendor_events [] = { + { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC }, + { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR }, +#ifdef GSCAN_SUPPORT + { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT }, + { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT }, + { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT }, + { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT }, +#endif /* GSCAN_SUPPORT */ + { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT }, +#ifdef GSCAN_SUPPORT + { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT }, + { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT }, + { OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT }, +#endif /* GSCAN_SUPPORT */ + { OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT }, + { OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT }, +#ifdef GSCAN_SUPPORT + { OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT }, +#endif /* GSCAN_SUPPORT */ + { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT }, +#ifdef KEEP_ALIVE + { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT }, +#endif /* KEEP_ALIVE */ +}; + +int wl_cfgvendor_attach(struct wiphy *wiphy) +{ + + WL_INFORM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n", + NL80211_CMD_VENDOR)); + + wiphy->vendor_commands = wl_vendor_cmds; + wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds); + wiphy->vendor_events = wl_vendor_events; + wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events); + + return 0; +} + +int wl_cfgvendor_detach(struct wiphy *wiphy) +{ + WL_INFORM(("Vendor: Unregister BRCM cfg80211 vendor interface \n")); + + wiphy->vendor_commands = NULL; + wiphy->vendor_events = NULL; + wiphy->n_vendor_commands = 0; + wiphy->n_vendor_events = 0; + + return 0; +} +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.h new file mode 100644 index 000000000000..e6f7ce882ff0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.h @@ -0,0 +1,353 @@ +/* + * Linux cfg80211 Vendor Extension Code + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgvendor.h 455257 2014-02-20 08:10:24Z $ + */ + + +#ifndef _wl_cfgvendor_h_ +#define _wl_cfgvendor_h_ + +#define OUI_BRCM 0x001018 +#define OUI_GOOGLE 0x001A11 +#define BRCM_VENDOR_SUBCMD_PRIV_STR 1 +#define ATTRIBUTE_U32_LEN (NLA_HDRLEN + 4) +#define VENDOR_ID_OVERHEAD ATTRIBUTE_U32_LEN +#define VENDOR_SUBCMD_OVERHEAD ATTRIBUTE_U32_LEN +#define VENDOR_DATA_OVERHEAD (NLA_HDRLEN) + +#define SCAN_RESULTS_COMPLETE_FLAG_LEN ATTRIBUTE_U32_LEN +#define SCAN_INDEX_HDR_LEN (NLA_HDRLEN) +#define SCAN_ID_HDR_LEN ATTRIBUTE_U32_LEN +#define SCAN_FLAGS_HDR_LEN ATTRIBUTE_U32_LEN +#define GSCAN_NUM_RESULTS_HDR_LEN ATTRIBUTE_U32_LEN +#define GSCAN_RESULTS_HDR_LEN (NLA_HDRLEN) +#define GSCAN_BATCH_RESULT_HDR_LEN (SCAN_INDEX_HDR_LEN + \ + SCAN_ID_HDR_LEN + \ + SCAN_FLAGS_HDR_LEN + \ + GSCAN_NUM_RESULTS_HDR_LEN + \ + GSCAN_RESULTS_HDR_LEN) + +#define VENDOR_REPLY_OVERHEAD (VENDOR_ID_OVERHEAD + \ + VENDOR_SUBCMD_OVERHEAD + \ + VENDOR_DATA_OVERHEAD) +typedef enum { + /* don't use 0 as a valid subcommand */ + VENDOR_NL80211_SUBCMD_UNSPECIFIED, + + /* define all vendor startup commands between 0x0 and 0x0FFF */ + VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001, + VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF, + + /* define all GScan related commands between 0x1000 and 0x10FF */ + ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000, + ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF, + + /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */ + ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100, + ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF, + + /* define all RTT related commands between 0x1100 and 0x11FF */ + ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100, + ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF, + + ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200, + ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF, + + ANDROID_NL80211_SUBCMD_TDLS_RANGE_START = 0x1300, + ANDROID_NL80211_SUBCMD_TDLS_RANGE_END = 0x13FF, + + /* define all wifi calling related commands between 0x1600 and 0x16FF */ + ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600, + ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF, + + /* This is reserved for future usage */ +} ANDROID_VENDOR_SUB_COMMAND; + +enum andr_vendor_subcmd { + GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START, + GSCAN_SUBCMD_SET_CONFIG, + GSCAN_SUBCMD_SET_SCAN_CONFIG, + GSCAN_SUBCMD_ENABLE_GSCAN, + GSCAN_SUBCMD_GET_SCAN_RESULTS, + GSCAN_SUBCMD_SCAN_RESULTS, + GSCAN_SUBCMD_SET_HOTLIST, + GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, + GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, + GSCAN_SUBCMD_GET_CHANNEL_LIST, + /* ANDR_WIFI_XXX although not related to gscan are defined here */ + ANDR_WIFI_SUBCMD_GET_FEATURE_SET, + ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, + ANDR_WIFI_RANDOM_MAC_OUI, + ANDR_WIFI_NODFS_CHANNELS, + ANDR_WIFI_SET_COUNTRY, + GSCAN_SUBCMD_SET_EPNO_SSID, + WIFI_SUBCMD_SET_SSID_WHITELIST, + WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS, + WIFI_SUBCMD_ENABLE_LAZY_ROAM, + WIFI_SUBCMD_SET_BSSID_PREF, + WIFI_SUBCMD_SET_BSSID_BLACKLIST, + GSCAN_SUBCMD_ANQPO_CONFIG, + WIFI_SUBCMD_SET_RSSI_MONITOR, + RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, + RTT_SUBCMD_CANCEL_CONFIG, + RTT_SUBCMD_GETCAPABILITY, + + LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START, + WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START, + WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE, + + /* Add more sub commands here */ + VENDOR_SUBCMD_MAX +}; + + +enum gscan_attributes { + GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, + GSCAN_ATTRIBUTE_BASE_PERIOD, + GSCAN_ATTRIBUTE_BUCKETS_BAND, + GSCAN_ATTRIBUTE_BUCKET_ID, + GSCAN_ATTRIBUTE_BUCKET_PERIOD, + GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, + GSCAN_ATTRIBUTE_BUCKET_CHANNELS, + GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, + GSCAN_ATTRIBUTE_REPORT_THRESHOLD, + GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, + GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND, + + GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, + GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, + GSCAN_ATTRIBUTE_FLUSH_FEATURE, + GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS, + GSCAN_ATTRIBUTE_REPORT_EVENTS, + /* remaining reserved for additional attributes */ + GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, + GSCAN_ATTRIBUTE_FLUSH_RESULTS, + GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ + GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ + GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ + GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ + GSCAN_ATTRIBUTE_NUM_CHANNELS, + GSCAN_ATTRIBUTE_CHANNEL_LIST, + + /* remaining reserved for additional attributes */ + + GSCAN_ATTRIBUTE_SSID = 40, + GSCAN_ATTRIBUTE_BSSID, + GSCAN_ATTRIBUTE_CHANNEL, + GSCAN_ATTRIBUTE_RSSI, + GSCAN_ATTRIBUTE_TIMESTAMP, + GSCAN_ATTRIBUTE_RTT, + GSCAN_ATTRIBUTE_RTTSD, + + /* remaining reserved for additional attributes */ + + GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, + GSCAN_ATTRIBUTE_RSSI_LOW, + GSCAN_ATTRIBUTE_RSSI_HIGH, + GSCAN_ATTRIBUTE_HOSTLIST_BSSID_ELEM, + GSCAN_ATTRIBUTE_HOTLIST_FLUSH, + + /* remaining reserved for additional attributes */ + GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, + GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, + GSCAN_ATTRIBUTE_MIN_BREACHING, + GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, + GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, + /* EPNO */ + GSCAN_ATTRIBUTE_EPNO_SSID_LIST = 70, + GSCAN_ATTRIBUTE_EPNO_SSID, + GSCAN_ATTRIBUTE_EPNO_SSID_LEN, + GSCAN_ATTRIBUTE_EPNO_RSSI, + GSCAN_ATTRIBUTE_EPNO_FLAGS, + GSCAN_ATTRIBUTE_EPNO_AUTH, + GSCAN_ATTRIBUTE_EPNO_SSID_NUM, + GSCAN_ATTRIBUTE_EPNO_FLUSH, + + /* Roam SSID Whitelist and BSSID pref */ + GSCAN_ATTRIBUTE_WHITELIST_SSID = 80, + GSCAN_ATTRIBUTE_NUM_WL_SSID, + GSCAN_ATTRIBUTE_WL_SSID_LEN, + GSCAN_ATTRIBUTE_WL_SSID_FLUSH, + GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM, + GSCAN_ATTRIBUTE_NUM_BSSID, + GSCAN_ATTRIBUTE_BSSID_PREF_LIST, + GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH, + GSCAN_ATTRIBUTE_BSSID_PREF, + GSCAN_ATTRIBUTE_RSSI_MODIFIER, + + + /* Roam cfg */ + GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD = 90, + GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD, + GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR, + GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR, + GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST, + GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS, + GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER, + GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE, + + /* BSSID blacklist */ + GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH = 100, + GSCAN_ATTRIBUTE_BLACKLIST_BSSID, + + GSCAN_ATTRIBUTE_ANQPO_HS_LIST = 110, + GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, + GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, + GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, + GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID, + GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, + + /* Adaptive scan attributes */ + GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 120, + GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD, + + GSCAN_ATTRIBUTE_MAX +}; + +enum gscan_bucket_attributes { + GSCAN_ATTRIBUTE_CH_BUCKET_1, + GSCAN_ATTRIBUTE_CH_BUCKET_2, + GSCAN_ATTRIBUTE_CH_BUCKET_3, + GSCAN_ATTRIBUTE_CH_BUCKET_4, + GSCAN_ATTRIBUTE_CH_BUCKET_5, + GSCAN_ATTRIBUTE_CH_BUCKET_6, + GSCAN_ATTRIBUTE_CH_BUCKET_7 +}; + +enum gscan_ch_attributes { + GSCAN_ATTRIBUTE_CH_ID_1, + GSCAN_ATTRIBUTE_CH_ID_2, + GSCAN_ATTRIBUTE_CH_ID_3, + GSCAN_ATTRIBUTE_CH_ID_4, + GSCAN_ATTRIBUTE_CH_ID_5, + GSCAN_ATTRIBUTE_CH_ID_6, + GSCAN_ATTRIBUTE_CH_ID_7 +}; + +enum rtt_attributes { + RTT_ATTRIBUTE_TARGET_CNT, + RTT_ATTRIBUTE_TARGET_INFO, + RTT_ATTRIBUTE_TARGET_MAC, + RTT_ATTRIBUTE_TARGET_TYPE, + RTT_ATTRIBUTE_TARGET_PEER, + RTT_ATTRIBUTE_TARGET_CHAN, + RTT_ATTRIBUTE_TARGET_INTERVAL, + RTT_ATTRIBUTE_TARGET_NUM_BURST, + RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, + RTT_ATTRIBUTE_TARGET_LCI, + RTT_ATTRIBUTE_TARGET_LCR, + RTT_ATTRIBUTE_TARGET_BURST_TIMEOUT, + RTT_ATTRIBUTE_TARGET_PREAMBLE, + RTT_ATTRIBUTE_TARGET_BW, + RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, + RTT_ATTRIBUTE_RESULTS_PER_TARGET, + RTT_ATTRIBUTE_RESULT_CNT, + RTT_ATTRIBUTE_RESULT +}; + +enum mkeep_alive_attributes { + MKEEP_ALIVE_ATTRIBUTE_ID, + MKEEP_ALIVE_ATTRIBUTE_IP_PKT, + MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, + MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, + MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, + MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC +}; + +enum wifi_rssi_monitor_attr { + RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, + RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, + RSSI_MONITOR_ATTRIBUTE_START +}; + +typedef enum wl_vendor_event { + BRCM_VENDOR_EVENT_UNSPEC, + BRCM_VENDOR_EVENT_PRIV_STR, + GOOGLE_GSCAN_SIGNIFICANT_EVENT, + GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT, + GOOGLE_GSCAN_BATCH_SCAN_EVENT, + GOOGLE_SCAN_FULL_RESULTS_EVENT, + GOOGLE_RTT_COMPLETE_EVENT, + GOOGLE_SCAN_COMPLETE_EVENT, + GOOGLE_GSCAN_GEOFENCE_LOST_EVENT, + GOOGLE_SCAN_EPNO_EVENT, + GOOGLE_DEBUG_RING_EVENT, + GOOGLE_FW_DUMP_EVENT, + GOOGLE_PNO_HOTSPOT_FOUND_EVENT, + GOOGLE_RSSI_MONITOR_EVENT, + GOOGLE_MKEEP_ALIVE_EVENT +} wl_vendor_event_t; + +enum andr_wifi_attr { + ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, + ANDR_WIFI_ATTRIBUTE_FEATURE_SET, + ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI, + ANDR_WIFI_ATTRIBUTE_NODFS_SET, + ANDR_WIFI_ATTRIBUTE_COUNTRY +}; + +typedef enum wl_vendor_gscan_attribute { + ATTR_START_GSCAN, + ATTR_STOP_GSCAN, + ATTR_SET_SCAN_BATCH_CFG_ID, /* set batch scan params */ + ATTR_SET_SCAN_GEOFENCE_CFG_ID, /* set list of bssids to track */ + ATTR_SET_SCAN_SIGNIFICANT_CFG_ID, /* set list of bssids, rssi threshold etc.. */ + ATTR_SET_SCAN_CFG_ID, /* set common scan config params here */ + ATTR_GET_GSCAN_CAPABILITIES_ID, + + /* Add more sub commands here */ + ATTR_GSCAN_MAX +} wl_vendor_gscan_attribute_t; + +typedef enum gscan_batch_attribute { + ATTR_GSCAN_BATCH_BESTN, + ATTR_GSCAN_BATCH_MSCAN, + ATTR_GSCAN_BATCH_BUFFER_THRESHOLD +} gscan_batch_attribute_t; + +typedef enum gscan_geofence_attribute { + ATTR_GSCAN_NUM_HOTLIST_BSSID, + ATTR_GSCAN_HOTLIST_BSSID +} gscan_geofence_attribute_t; + +typedef enum gscan_complete_event { + WIFI_SCAN_BUFFER_FULL, + WIFI_SCAN_COMPLETE +} gscan_complete_event_t; + +/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */ +#define BRCM_VENDOR_SCMD_CAPA "cap" + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) +extern int wl_cfgvendor_attach(struct wiphy *wiphy); +extern int wl_cfgvendor_detach(struct wiphy *wiphy); +extern int wl_cfgvendor_send_async_event(struct wiphy *wiphy, + struct net_device *dev, int event_id, const void *data, int len); +extern int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, + struct net_device *dev, void *data, int len, wl_vendor_event_t event); +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ + +#endif /* _wl_cfgvendor_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_dbg.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_dbg.h new file mode 100644 index 000000000000..3691db18f4bb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_dbg.h @@ -0,0 +1,206 @@ +/* + * Minimal debug/trace/assert driver definitions for + * Broadcom 802.11 Networking Adapter. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_dbg.h 472390 2014-04-23 23:32:01Z $ + */ + + +#ifndef _wl_dbg_h_ +#define _wl_dbg_h_ + +/* wl_msg_level is a bit vector with defs in wlioctl.h */ +extern uint32 wl_msg_level; +extern uint32 wl_msg_level2; + +#define WL_TIMESTAMP() + +#define WL_PRINT(args) do { WL_TIMESTAMP(); printf args; } while (0) + +#if defined(EVENT_LOG_COMPILE) && defined(WLMSG_SRSCAN) +#define _WL_SRSCAN(fmt, ...) EVENT_LOG(EVENT_LOG_TAG_SRSCAN, fmt, ##__VA_ARGS__) +#define WL_SRSCAN(args) _WL_SRSCAN args +#else +#define WL_SRSCAN(args) +#endif + +#if defined(BCMCONDITIONAL_LOGGING) + +/* Ideally this should be some include file that vendors can include to conditionalize logging */ + +/* DBGONLY() macro to reduce ifdefs in code for statements that are only needed when + * BCMDBG is defined. + */ +#define DBGONLY(x) + +/* To disable a message completely ... until you need it again */ +#define WL_NONE(args) +#define WL_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args);} while (0) +#define WL_TRACE(args) +#define WL_PRHDRS_MSG(args) +#define WL_PRHDRS(i, p, f, t, r, l) +#define WL_PRPKT(m, b, n) +#define WL_INFORM(args) +#define WL_TMP(args) +#define WL_OID(args) +#define WL_RATE(args) do {if (wl_msg_level & WL_RATE_VAL) WL_PRINT(args);} while (0) +#define WL_ASSOC(args) do {if (wl_msg_level & WL_ASSOC_VAL) WL_PRINT(args);} while (0) +#define WL_PRUSR(m, b, n) +#define WL_PS(args) do {if (wl_msg_level & WL_PS_VAL) WL_PRINT(args);} while (0) + +#define WL_PORT(args) +#define WL_DUAL(args) +#define WL_REGULATORY(args) do {if (wl_msg_level & WL_REGULATORY_VAL) WL_PRINT(args);} while (0) + +#define WL_MPC(args) +#define WL_APSTA(args) +#define WL_APSTA_BCN(args) +#define WL_APSTA_TX(args) +#define WL_APSTA_TSF(args) +#define WL_APSTA_BSSID(args) +#define WL_BA(args) +#define WL_MBSS(args) +#define WL_PROTO(args) + +#define WL_CAC(args) do {if (wl_msg_level & WL_CAC_VAL) WL_PRINT(args);} while (0) +#define WL_AMSDU(args) +#define WL_AMPDU(args) +#define WL_FFPLD(args) +#define WL_MCHAN(args) + +#define WL_DFS(args) +#define WL_WOWL(args) +#define WL_DPT(args) +#define WL_ASSOC_OR_DPT(args) +#define WL_SCAN(args) do {if (wl_msg_level2 & WL_SCAN_VAL) WL_PRINT(args);} while (0) +#define WL_COEX(args) +#define WL_RTDC(w, s, i, j) +#define WL_RTDC2(w, s, i, j) +#define WL_CHANINT(args) +#define WL_BTA(args) +#define WL_P2P(args) +#define WL_ITFR(args) +#define WL_TDLS(args) +#define WL_MCNX(args) +#define WL_PROT(args) +#define WL_PSTA(args) +#define WL_TRF_MGMT(args) +#define WL_L2FILTER(args) +#define WL_MQ(args) +#define WL_TXBF(args) +#define WL_P2PO(args) +#define WL_NET_DETECT(args) +#define WL_ROAM(args) +#define WL_WNM(args) + + +#define WL_AMPDU_UPDN(args) +#define WL_AMPDU_RX(args) +#define WL_AMPDU_ERR(args) +#define WL_AMPDU_TX(args) +#define WL_AMPDU_CTL(args) +#define WL_AMPDU_HW(args) +#define WL_AMPDU_HWTXS(args) +#define WL_AMPDU_HWDBG(args) +#define WL_AMPDU_STAT(args) +#define WL_AMPDU_ERR_ON() 0 +#define WL_AMPDU_HW_ON() 0 +#define WL_AMPDU_HWTXS_ON() 0 + +#define WL_APSTA_UPDN(args) +#define WL_APSTA_RX(args) +#define WL_WSEC(args) +#define WL_WSEC_DUMP(args) +#define WL_PCIE(args) +#define WL_CHANLOG(w, s, i, j) + +#define WL_ERROR_ON() (wl_msg_level & WL_ERROR_VAL) +#define WL_TRACE_ON() 0 +#define WL_PRHDRS_ON() 0 +#define WL_PRPKT_ON() 0 +#define WL_INFORM_ON() 0 +#define WL_TMP_ON() 0 +#define WL_OID_ON() 0 +#define WL_RATE_ON() (wl_msg_level & WL_RATE_VAL) +#define WL_ASSOC_ON() (wl_msg_level & WL_ASSOC_VAL) +#define WL_PRUSR_ON() 0 +#define WL_PS_ON() (wl_msg_level & WL_PS_VAL) +#define WL_PORT_ON() 0 +#define WL_WSEC_ON() 0 +#define WL_WSEC_DUMP_ON() 0 +#define WL_MPC_ON() 0 +#define WL_REGULATORY_ON() (wl_msg_level & WL_REGULATORY_VAL) +#define WL_APSTA_ON() 0 +#define WL_DFS_ON() 0 +#define WL_MBSS_ON() 0 +#define WL_CAC_ON() (wl_msg_level & WL_CAC_VAL) +#define WL_AMPDU_ON() 0 +#define WL_DPT_ON() 0 +#define WL_WOWL_ON() 0 +#define WL_SCAN_ON() (wl_msg_level2 & WL_SCAN_VAL) +#define WL_BTA_ON() 0 +#define WL_P2P_ON() 0 +#define WL_ITFR_ON() 0 +#define WL_MCHAN_ON() 0 +#define WL_TDLS_ON() 0 +#define WL_MCNX_ON() 0 +#define WL_PROT_ON() 0 +#define WL_PSTA_ON() 0 +#define WL_TRF_MGMT_ON() 0 +#define WL_LPC_ON() 0 +#define WL_L2FILTER_ON() 0 +#define WL_TXBF_ON() 0 +#define WL_P2PO_ON() 0 +#define WL_CHANLOG_ON() 0 +#define WL_NET_DETECT_ON() 0 +#define WL_WNM_ON() 0 +#define WL_PCIE_ON() 0 + +#else /* !BCMDBG */ + +/* DBGONLY() macro to reduce ifdefs in code for statements that are only needed when + * BCMDBG is defined. + */ +#define DBGONLY(x) + +/* To disable a message completely ... until you need it again */ +#define WL_NONE(args) + +#define WL_ERROR(args) +#define WL_TRACE(args) +#define WL_APSTA_UPDN(args) +#define WL_APSTA_RX(args) +#ifdef WLMSG_WSEC +#define WL_WSEC(args) WL_PRINT(args) +#define WL_WSEC_DUMP(args) WL_PRINT(args) +#else +#define WL_WSEC(args) +#define WL_WSEC_DUMP(args) +#endif +#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0) +#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL) +#endif + +extern uint32 wl_msg_level; +extern uint32 wl_msg_level2; +#endif /* _wl_dbg_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_linux_mon.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_linux_mon.c new file mode 100644 index 000000000000..aa745a913777 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_linux_mon.c @@ -0,0 +1,403 @@ +/* + * Broadcom Dongle Host Driver (DHD), Linux monitor network interface + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_linux_mon.c 467328 2014-04-03 01:23:40Z $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef enum monitor_states +{ + MONITOR_STATE_DEINIT = 0x0, + MONITOR_STATE_INIT = 0x1, + MONITOR_STATE_INTERFACE_ADDED = 0x2, + MONITOR_STATE_INTERFACE_DELETED = 0x4 +} monitor_states_t; +int dhd_add_monitor(char *name, struct net_device **new_ndev); +extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); +int dhd_del_monitor(struct net_device *ndev); +int dhd_monitor_init(void *dhd_pub); +int dhd_monitor_uninit(void); + +/** + * Local declarations and defintions (not exposed) + */ +#ifndef DHD_MAX_IFS +#define DHD_MAX_IFS 16 +#endif +#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__) +#define MON_TRACE MON_PRINT + +typedef struct monitor_interface { + int radiotap_enabled; + struct net_device* real_ndev; /* The real interface that the monitor is on */ + struct net_device* mon_ndev; +} monitor_interface; + +typedef struct dhd_linux_monitor { + void *dhd_pub; + monitor_states_t monitor_state; + monitor_interface mon_if[DHD_MAX_IFS]; + struct mutex lock; /* lock to protect mon_if */ +} dhd_linux_monitor_t; + +static dhd_linux_monitor_t g_monitor; + +static struct net_device* lookup_real_netdev(char *name); +static monitor_interface* ndev_to_monif(struct net_device *ndev); +static int dhd_mon_if_open(struct net_device *ndev); +static int dhd_mon_if_stop(struct net_device *ndev); +static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev); +static void dhd_mon_if_set_multicast_list(struct net_device *ndev); +static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr); + +static const struct net_device_ops dhd_mon_if_ops = { + .ndo_open = dhd_mon_if_open, + .ndo_stop = dhd_mon_if_stop, + .ndo_start_xmit = dhd_mon_if_subif_start_xmit, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + .ndo_set_rx_mode = dhd_mon_if_set_multicast_list, +#else + .ndo_set_multicast_list = dhd_mon_if_set_multicast_list, +#endif + .ndo_set_mac_address = dhd_mon_if_change_mac, +}; + +/** + * Local static function defintions + */ + +/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0" + * "p2p-eth0-0" is a match for "mon.p2p-eth0-0") + */ +static struct net_device* lookup_real_netdev(char *name) +{ + struct net_device *ndev_found = NULL; + + int i; + int len = 0; + int last_name_len = 0; + struct net_device *ndev; + + /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0", + * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon + * iface would be mon-p2p0-0. + */ + for (i = 0; i < DHD_MAX_IFS; i++) { + ndev = dhd_idx2net(g_monitor.dhd_pub, i); + + /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it + * it matches, then this netdev is the corresponding real_netdev. + */ + if (ndev && strstr(ndev->name, "p2p-p2p0")) { + len = strlen("p2p"); + } else { + /* if p2p- is not present, then the IFNAMSIZ have reached and name + * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x + */ + len = 0; + } + if (ndev && strstr(name, (ndev->name + len))) { + if (strlen(ndev->name) > last_name_len) { + ndev_found = ndev; + last_name_len = strlen(ndev->name); + } + } + } + + return ndev_found; +} + +static monitor_interface* ndev_to_monif(struct net_device *ndev) +{ + int i; + + for (i = 0; i < DHD_MAX_IFS; i++) { + if (g_monitor.mon_if[i].mon_ndev == ndev) + return &g_monitor.mon_if[i]; + } + + return NULL; +} + +static int dhd_mon_if_open(struct net_device *ndev) +{ + int ret = 0; + + MON_PRINT("enter\n"); + return ret; +} + +static int dhd_mon_if_stop(struct net_device *ndev) +{ + int ret = 0; + + MON_PRINT("enter\n"); + return ret; +} + +static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int ret = 0; + int rtap_len; + int qos_len = 0; + int dot11_hdr_len = 24; + int snap_len = 6; + unsigned char *pdata; + unsigned short frame_ctl; + unsigned char src_mac_addr[6]; + unsigned char dst_mac_addr[6]; + struct ieee80211_hdr *dot11_hdr; + struct ieee80211_radiotap_header *rtap_hdr; + monitor_interface* mon_if; + + MON_PRINT("enter\n"); + + mon_if = ndev_to_monif(ndev); + if (mon_if == NULL || mon_if->real_ndev == NULL) { + MON_PRINT(" cannot find matched net dev, skip the packet\n"); + goto fail; + } + + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) + goto fail; + + rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; + if (unlikely(rtap_hdr->it_version)) + goto fail; + + rtap_len = ieee80211_get_radiotap_len(skb->data); + if (unlikely(skb->len < rtap_len)) + goto fail; + + MON_PRINT("radiotap len (should be 14): %d\n", rtap_len); + + /* Skip the ratio tap header */ + skb_pull(skb, rtap_len); + + dot11_hdr = (struct ieee80211_hdr *)skb->data; + frame_ctl = le16_to_cpu(dot11_hdr->frame_control); + /* Check if the QoS bit is set */ + if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { + /* Check if this ia a Wireless Distribution System (WDS) frame + * which has 4 MAC addresses + */ + if (dot11_hdr->frame_control & 0x0080) + qos_len = 2; + if ((dot11_hdr->frame_control & 0x0300) == 0x0300) + dot11_hdr_len += 6; + + memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); + memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); + + /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for + * for two MAC addresses + */ + skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); + pdata = (unsigned char*)skb->data; + memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); + memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); + PKTSETPRIO(skb, 0); + + MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); + + /* Use the real net device to transmit the packet */ + ret = dhd_start_xmit(skb, mon_if->real_ndev); + + return ret; + } +fail: + dev_kfree_skb(skb); + return 0; +} + +static void dhd_mon_if_set_multicast_list(struct net_device *ndev) +{ + monitor_interface* mon_if; + + mon_if = ndev_to_monif(ndev); + if (mon_if == NULL || mon_if->real_ndev == NULL) { + MON_PRINT(" cannot find matched net dev, skip the packet\n"); + } else { + MON_PRINT("enter, if name: %s, matched if name %s\n", + ndev->name, mon_if->real_ndev->name); + } +} + +static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) +{ + int ret = 0; + monitor_interface* mon_if; + + mon_if = ndev_to_monif(ndev); + if (mon_if == NULL || mon_if->real_ndev == NULL) { + MON_PRINT(" cannot find matched net dev, skip the packet\n"); + } else { + MON_PRINT("enter, if name: %s, matched if name %s\n", + ndev->name, mon_if->real_ndev->name); + } + return ret; +} + +/** + * Global function definitions (declared in dhd_linux_mon.h) + */ + +int dhd_add_monitor(char *name, struct net_device **new_ndev) +{ + int i; + int idx = -1; + int ret = 0; + struct net_device* ndev = NULL; + dhd_linux_monitor_t **dhd_mon; + + mutex_lock(&g_monitor.lock); + + MON_TRACE("enter, if name: %s\n", name); + if (!name || !new_ndev) { + MON_PRINT("invalid parameters\n"); + ret = -EINVAL; + goto out; + } + + /* + * Find a vacancy + */ + for (i = 0; i < DHD_MAX_IFS; i++) + if (g_monitor.mon_if[i].mon_ndev == NULL) { + idx = i; + break; + } + if (idx == -1) { + MON_PRINT("exceeds maximum interfaces\n"); + ret = -EFAULT; + goto out; + } + + ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*)); + if (!ndev) { + MON_PRINT("failed to allocate memory\n"); + ret = -ENOMEM; + goto out; + } + + ndev->type = ARPHRD_IEEE80211_RADIOTAP; + strncpy(ndev->name, name, IFNAMSIZ); + ndev->name[IFNAMSIZ - 1] = 0; + ndev->netdev_ops = &dhd_mon_if_ops; + + ret = register_netdevice(ndev); + if (ret) { + MON_PRINT(" register_netdevice failed (%d)\n", ret); + goto out; + } + + *new_ndev = ndev; + g_monitor.mon_if[idx].radiotap_enabled = TRUE; + g_monitor.mon_if[idx].mon_ndev = ndev; + g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name); + dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev); + *dhd_mon = &g_monitor; + g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED; + MON_PRINT("net device returned: 0x%p\n", ndev); + MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name); + +out: + if (ret && ndev) + free_netdev(ndev); + + mutex_unlock(&g_monitor.lock); + return ret; + +} + +int dhd_del_monitor(struct net_device *ndev) +{ + int i; + if (!ndev) + return -EINVAL; + mutex_lock(&g_monitor.lock); + for (i = 0; i < DHD_MAX_IFS; i++) { + if (g_monitor.mon_if[i].mon_ndev == ndev || + g_monitor.mon_if[i].real_ndev == ndev) { + + g_monitor.mon_if[i].real_ndev = NULL; + unregister_netdevice(g_monitor.mon_if[i].mon_ndev); + free_netdev(g_monitor.mon_if[i].mon_ndev); + g_monitor.mon_if[i].mon_ndev = NULL; + g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED; + break; + } + } + + if (g_monitor.monitor_state != MONITOR_STATE_INTERFACE_DELETED) + MON_PRINT("IF not found in monitor array, is this a monitor IF? 0x%p\n", ndev); + mutex_unlock(&g_monitor.lock); + + return 0; +} + +int dhd_monitor_init(void *dhd_pub) +{ + if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) { + g_monitor.dhd_pub = dhd_pub; + mutex_init(&g_monitor.lock); + g_monitor.monitor_state = MONITOR_STATE_INIT; + } + return 0; +} + +int dhd_monitor_uninit(void) +{ + int i; + struct net_device *ndev; + mutex_lock(&g_monitor.lock); + if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) { + for (i = 0; i < DHD_MAX_IFS; i++) { + ndev = g_monitor.mon_if[i].mon_ndev; + if (ndev) { + unregister_netdevice(ndev); + free_netdev(ndev); + g_monitor.mon_if[i].real_ndev = NULL; + g_monitor.mon_if[i].mon_ndev = NULL; + } + } + g_monitor.monitor_state = MONITOR_STATE_DEINIT; + } + mutex_unlock(&g_monitor.lock); + return 0; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_roam.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_roam.c new file mode 100644 index 000000000000..c937007d84e5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_roam.c @@ -0,0 +1,306 @@ +/* + * Linux roam cache + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_roam.c 467328 2014-04-03 01:23:40Z $ + */ + + +#include +#include +#include +#include +#include +#ifdef WL_CFG80211 +#include +#endif +#include + +#define MAX_ROAM_CACHE 100 +#define MAX_CHANNEL_LIST 20 +#define MAX_SSID_BUFSIZE 36 + +#define ROAMSCAN_MODE_NORMAL 0 +#define ROAMSCAN_MODE_WES 1 + +typedef struct { + chanspec_t chanspec; + int ssid_len; + char ssid[MAX_SSID_BUFSIZE]; +} roam_channel_cache; + +typedef struct { + int n; + chanspec_t channels[MAX_CHANNEL_LIST]; +} channel_list_t; + +static int n_roam_cache = 0; +static int roam_band = WLC_BAND_AUTO; +static roam_channel_cache roam_cache[MAX_ROAM_CACHE]; +static uint band2G, band5G, band_bw; + +void init_roam(int ioctl_ver) +{ +#ifdef D11AC_IOTYPES + if (ioctl_ver == 1) { + /* legacy chanspec */ + band2G = WL_LCHANSPEC_BAND_2G; + band5G = WL_LCHANSPEC_BAND_5G; + band_bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE; + } else { + band2G = WL_CHANSPEC_BAND_2G; + band5G = WL_CHANSPEC_BAND_5G; + band_bw = WL_CHANSPEC_BW_20; + } +#else + band2G = WL_CHANSPEC_BAND_2G; + band5G = WL_CHANSPEC_BAND_5G; + band_bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; +#endif /* D11AC_IOTYPES */ + + n_roam_cache = 0; + roam_band = WLC_BAND_AUTO; +} + + +void set_roam_band(int band) +{ + roam_band = band; +} + +void reset_roam_cache(void) +{ + + n_roam_cache = 0; +} + +void add_roam_cache(wl_bss_info_t *bi) +{ + int i; + uint8 channel; + char chanbuf[CHANSPEC_STR_LEN]; + + + if (n_roam_cache >= MAX_ROAM_CACHE) + return; + + for (i = 0; i < n_roam_cache; i++) { + if ((roam_cache[i].ssid_len == bi->SSID_len) && + (roam_cache[i].chanspec == bi->chanspec) && + (memcmp(roam_cache[i].ssid, bi->SSID, bi->SSID_len) == 0)) { + /* identical one found, just return */ + return; + } + } + + roam_cache[n_roam_cache].ssid_len = bi->SSID_len; + channel = wf_chspec_ctlchan(bi->chanspec); + WL_DBG(("CHSPEC = %s, CTL %d\n", wf_chspec_ntoa_ex(bi->chanspec, chanbuf), channel)); + roam_cache[n_roam_cache].chanspec = + (channel <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw | channel; + memcpy(roam_cache[n_roam_cache].ssid, bi->SSID, bi->SSID_len); + + n_roam_cache++; +} + +static bool is_duplicated_channel(const chanspec_t *channels, int n_channels, chanspec_t new) +{ + int i; + + for (i = 0; i < n_channels; i++) { + if (channels[i] == new) + return TRUE; + } + + return FALSE; +} + +int get_roam_channel_list(int target_chan, + chanspec_t *channels, const wlc_ssid_t *ssid, int ioctl_ver) +{ + int i, n = 1; + char chanbuf[CHANSPEC_STR_LEN]; + + /* first index is filled with the given target channel */ + channels[0] = (target_chan & WL_CHANSPEC_CHAN_MASK) | + (target_chan <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw; + + WL_DBG((" %s: %03d 0x%04X\n", __FUNCTION__, target_chan, channels[0])); + + + for (i = 0; i < n_roam_cache; i++) { + chanspec_t ch = roam_cache[i].chanspec; + bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch); + bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch); + bool band_match = ((roam_band == WLC_BAND_AUTO) || + ((roam_band == WLC_BAND_2G) && is_2G) || + ((roam_band == WLC_BAND_5G) && is_5G)); + + ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw; + if ((roam_cache[i].ssid_len == ssid->SSID_len) && + band_match && !is_duplicated_channel(channels, n, ch) && + (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) { + /* match found, add it */ + WL_DBG(("%s: Chanspec = %s\n", __FUNCTION__, + wf_chspec_ntoa_ex(ch, chanbuf))); + channels[n++] = ch; + } + } + + return n; +} + + +void print_roam_cache(void) +{ + int i; + + WL_DBG((" %d cache\n", n_roam_cache)); + + for (i = 0; i < n_roam_cache; i++) { + roam_cache[i].ssid[roam_cache[i].ssid_len] = 0; + WL_DBG(("0x%02X %02d %s\n", roam_cache[i].chanspec, + roam_cache[i].ssid_len, roam_cache[i].ssid)); + } +} + +static void add_roamcache_channel(channel_list_t *channels, chanspec_t ch) +{ + int i; + + if (channels->n >= MAX_CHANNEL_LIST) /* buffer full */ + return; + + for (i = 0; i < channels->n; i++) { + if (channels->channels[i] == ch) /* already in the list */ + return; + } + + channels->channels[i] = ch; + channels->n++; + + WL_DBG((" RCC: %02d 0x%04X\n", + ch & WL_CHANSPEC_CHAN_MASK, ch)); +} + +void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver) +{ + int error, i, prev_channels; + channel_list_t channel_list; + char iobuf[WLC_IOCTL_SMLEN]; + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + wlc_ssid_t ssid; + + + if (!wl_get_drv_status(cfg, CONNECTED, dev)) { + WL_DBG(("Not associated\n")); + return; + } + + /* need to read out the current cache list + as the firmware may change dynamically + */ + error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0, + (void *)&channel_list, sizeof(channel_list), NULL); + + WL_DBG(("%d AP, %d cache item(s), err=%d\n", n_roam_cache, channel_list.n, error)); + + error = wldev_get_ssid(dev, &ssid); + if (error) { + WL_ERR(("Failed to get SSID, err=%d\n", error)); + return; + } + + prev_channels = channel_list.n; + for (i = 0; i < n_roam_cache; i++) { + chanspec_t ch = roam_cache[i].chanspec; + bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch); + bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch); + bool band_match = ((roam_band == WLC_BAND_AUTO) || + ((roam_band == WLC_BAND_2G) && is_2G) || + ((roam_band == WLC_BAND_5G) && is_5G)); + + if ((roam_cache[i].ssid_len == ssid.SSID_len) && + band_match && (memcmp(roam_cache[i].ssid, ssid.SSID, ssid.SSID_len) == 0)) { + /* match found, add it */ + ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw; + add_roamcache_channel(&channel_list, ch); + } + } + if (prev_channels != channel_list.n) { + /* channel list updated */ + error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list, + sizeof(channel_list), iobuf, sizeof(iobuf), NULL); + if (error) { + WL_ERR(("Failed to update roamscan channels, error = %d\n", error)); + } + } +} + +void wl_update_roamscan_cache_by_band(struct net_device *dev, int band) +{ + int i, error, ioctl_ver, wes_mode; + channel_list_t chanlist_before, chanlist_after; + char iobuf[WLC_IOCTL_SMLEN]; + + roam_band = band; + if (band == WLC_BAND_AUTO) + return; + + error = wldev_iovar_getint(dev, "roamscan_mode", &wes_mode); + if (error) { + WL_ERR(("Failed to get roamscan mode, error = %d\n", error)); + return; + } + /* in case of WES mode, then skip the update */ + if (wes_mode) + return; + + error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0, + (void *)&chanlist_before, sizeof(channel_list_t), NULL); + if (error) { + WL_ERR(("Failed to get roamscan channels, error = %d\n", error)); + return; + } + ioctl_ver = wl_cfg80211_get_ioctl_version(); + chanlist_after.n = 0; + /* filtering by the given band */ + for (i = 0; i < chanlist_before.n; i++) { + chanspec_t chspec = chanlist_before.channels[i]; + bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(chspec) : CHSPEC_IS2G(chspec); + bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(chspec) : CHSPEC_IS5G(chspec); + bool band_match = ((band == WLC_BAND_2G) && is_2G) || + ((band == WLC_BAND_5G) && is_5G); + if (band_match) { + chanlist_after.channels[chanlist_after.n++] = chspec; + } + } + + if (chanlist_before.n == chanlist_after.n) + return; + + error = wldev_iovar_setbuf(dev, "roamscan_channels", &chanlist_after, + sizeof(channel_list_t), iobuf, sizeof(iobuf), NULL); + if (error) { + WL_ERR(("Failed to update roamscan channels, error = %d\n", error)); + } +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c new file mode 100644 index 000000000000..0f12c77bb29f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c @@ -0,0 +1,516 @@ +/* + * Common function shared by Linux WEXT, cfg80211 and p2p drivers + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wldev_common.c 701287 2017-05-24 10:33:19Z $ + */ + +#include +#include +#include +#include + +#include +#include + +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) + +#define WLDEV_ERROR(args) \ + do { \ + printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__); \ + printk args; \ + } while (0) + +extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd); + +static s32 wldev_ioctl( + struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) +{ + s32 ret = 0; + struct wl_ioctl ioc; + + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + ioc.set = set; + + ret = dhd_ioctl_entry_local(dev, &ioc, cmd); + + return ret; +} + +/* +SET commands : +cast buffer to non-const and call the GET function +*/ + +s32 wldev_ioctl_set( + struct net_device *dev, u32 cmd, const void *arg, u32 len) +{ + +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + return wldev_ioctl(dev, cmd, (void *)arg, len, 1); +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +} + + +s32 wldev_ioctl_get( + struct net_device *dev, u32 cmd, void *arg, u32 len) +{ + return wldev_ioctl(dev, cmd, (void *)arg, len, 0); +} + +/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be + * taken care of in dhd_ioctl_entry. Internal use only, not exposed to + * wl_iw, wl_cfg80211 and wl_cfgp2p + */ +static s32 wldev_mkiovar( + s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, u32 buflen) +{ + s32 iolen = 0; + + iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen); + return iolen; +} + +s32 wldev_iovar_getbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) +{ + s32 ret = 0; + if (buf_sync) { + mutex_lock(buf_sync); + } + + if (buf && (buflen > 0)) { + /* initialize the response buffer */ + memset(buf, 0, buflen); + } else { + ret = BCME_BADARG; + goto exit; + } + + ret = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); + + if (!ret) { + ret = BCME_BUFTOOSHORT; + goto exit; + } + ret = wldev_ioctl_get(dev, WLC_GET_VAR, buf, buflen); + +exit: + if (buf_sync) + mutex_unlock(buf_sync); + return ret; +} + + +s32 wldev_iovar_setbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) +{ + s32 ret = 0; + s32 iovar_len; + if (buf_sync) { + mutex_lock(buf_sync); + } + if (buf && (buflen > 0)) { + /* initialize the response buffer */ + memset(buf, 0, buflen); + } else { + ret = BCME_BADARG; + goto exit; + } + iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); + if (iovar_len > 0) + ret = wldev_ioctl_set(dev, WLC_SET_VAR, buf, iovar_len); + else + ret = BCME_BUFTOOSHORT; + +exit: + if (buf_sync) + mutex_unlock(buf_sync); + return ret; +} + +s32 wldev_iovar_setint( + struct net_device *dev, s8 *iovar, s32 val) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + + val = htod32(val); + memset(iovar_buf, 0, sizeof(iovar_buf)); + return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf, + sizeof(iovar_buf), NULL); +} + + +s32 wldev_iovar_getint( + struct net_device *dev, s8 *iovar, s32 *pval) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + s32 err; + + memset(iovar_buf, 0, sizeof(iovar_buf)); + err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf, + sizeof(iovar_buf), NULL); + if (err == 0) + { + memcpy(pval, iovar_buf, sizeof(*pval)); + *pval = dtoh32(*pval); + } + return err; +} + +/** Format a bsscfg indexed iovar buffer. The bsscfg index will be + * taken care of in dhd_ioctl_entry. Internal use only, not exposed to + * wl_iw, wl_cfg80211 and wl_cfgp2p + */ +s32 wldev_mkiovar_bsscfg( + const s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, s32 buflen, s32 bssidx) +{ + const s8 *prefix = "bsscfg:"; + s8 *p; + u32 prefixlen; + u32 namelen; + u32 iolen; + + /* initialize buffer */ + if (!iovar_buf || buflen == 0) + return BCME_BADARG; + memset(iovar_buf, 0, buflen); + + if (bssidx == 0) { + return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen, + (s8 *) iovar_buf, buflen); + } + + prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ + namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */ + iolen = prefixlen + namelen + sizeof(u32) + paramlen; + + if (buflen < 0 || iolen > (u32)buflen) + { + WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__)); + return BCME_BUFTOOSHORT; + } + + p = (s8 *)iovar_buf; + + /* copy prefix, no null */ + memcpy(p, prefix, prefixlen); + p += prefixlen; + + /* copy iovar name including null */ + memcpy(p, iovar_name, namelen); + p += namelen; + + /* bss config index as first param */ + bssidx = htod32(bssidx); + memcpy(p, &bssidx, sizeof(u32)); + p += sizeof(u32); + + /* parameter buffer follows */ + if (paramlen) + memcpy(p, param, paramlen); + + return iolen; + +} + +s32 wldev_iovar_getbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) +{ + s32 ret = 0; + if (buf_sync) { + mutex_lock(buf_sync); + } + + wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); + ret = wldev_ioctl_get(dev, WLC_GET_VAR, buf, buflen); + if (buf_sync) { + mutex_unlock(buf_sync); + } + return ret; + +} + +s32 wldev_iovar_setbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) +{ + s32 ret = 0; + s32 iovar_len; + if (buf_sync) { + mutex_lock(buf_sync); + } + iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); + if (iovar_len > 0) + ret = wldev_ioctl_set(dev, WLC_SET_VAR, buf, iovar_len); + else { + ret = BCME_BUFTOOSHORT; + } + + if (buf_sync) { + mutex_unlock(buf_sync); + } + return ret; +} + +s32 wldev_iovar_setint_bsscfg( + struct net_device *dev, s8 *iovar, s32 val, s32 bssidx) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + + val = htod32(val); + + return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, + sizeof(iovar_buf), bssidx, NULL); +} + + +s32 wldev_iovar_getint_bsscfg( + struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + s32 err; + + memset(iovar_buf, 0, sizeof(iovar_buf)); + err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf, + sizeof(iovar_buf), bssidx, NULL); + if (err == 0) + { + memcpy(pval, iovar_buf, sizeof(*pval)); + *pval = dtoh32(*pval); + } + return err; +} + +int wldev_get_link_speed( + struct net_device *dev, int *plink_speed) +{ + int error; + + if (!plink_speed) + return -ENOMEM; + *plink_speed = 0; + error = wldev_ioctl_get(dev, WLC_GET_RATE, plink_speed, sizeof(int)); + if (unlikely(error)) + return error; + + /* Convert internal 500Kbps to Kbps */ + *plink_speed *= 500; + return error; +} + +int wldev_get_rssi( + struct net_device *dev, scb_val_t *scb_val) +{ + int error; + + if (!scb_val) + return -ENOMEM; + + memset(scb_val, 0, sizeof(scb_val_t)); + error = wldev_ioctl_get(dev, WLC_GET_RSSI, scb_val, sizeof(scb_val_t)); + if (unlikely(error)) + return error; + + return error; +} + +int wldev_get_ssid( + struct net_device *dev, wlc_ssid_t *pssid) +{ + int error; + + if (!pssid) + return -ENOMEM; + memset(pssid, 0, sizeof(wlc_ssid_t)); + error = wldev_ioctl_get(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t)); + if (unlikely(error)) + return error; + pssid->SSID_len = dtoh32(pssid->SSID_len); + return error; +} + +int wldev_get_band( + struct net_device *dev, uint *pband) +{ + int error; + + *pband = 0; + error = wldev_ioctl_get(dev, WLC_GET_BAND, pband, sizeof(uint)); + return error; +} + +int wldev_set_band( + struct net_device *dev, uint band) +{ + int error = -1; + + if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { + error = wldev_ioctl_set(dev, WLC_SET_BAND, &band, sizeof(band)); + if (!error) + dhd_bus_band_set(dev, band); + } + return error; +} + +int wldev_get_datarate(struct net_device *dev, int *datarate) +{ + int error = 0; + + error = wldev_ioctl_get(dev, WLC_GET_RATE, datarate, sizeof(int)); + if (error) { + return -1; + } else { + *datarate = dtoh32(*datarate); + } + + return error; +} + +extern chanspec_t +wl_chspec_driver_to_host(chanspec_t chanspec); +#define WL_EXTRA_BUF_MAX 2048 +int wldev_get_mode( + struct net_device *dev, uint8 *cap) +{ + int error = 0; + int chanspec = 0; + uint16 band = 0; + uint16 bandwidth = 0; + wl_bss_info_t *bss = NULL; + char* buf = NULL; + + buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!buf) { + WLDEV_ERROR(("%s:NOMEM\n", __FUNCTION__)); + return -ENOMEM; + } + + *(u32*) buf = htod32(WL_EXTRA_BUF_MAX); + error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void*)buf, WL_EXTRA_BUF_MAX); + if (error) { + WLDEV_ERROR(("%s:failed:%d\n", __FUNCTION__, error)); + kfree(buf); + buf = NULL; + return error; + } + bss = (struct wl_bss_info *)(buf + 4); + chanspec = wl_chspec_driver_to_host(bss->chanspec); + + band = chanspec & WL_CHANSPEC_BAND_MASK; + bandwidth = chanspec & WL_CHANSPEC_BW_MASK; + + if (band == WL_CHANSPEC_BAND_2G) { + if (bss->n_cap) + strcpy(cap, "n"); + else + strcpy(cap, "bg"); + } else if (band == WL_CHANSPEC_BAND_5G) { + if (bandwidth == WL_CHANSPEC_BW_80) + strcpy(cap, "ac"); + else if ((bandwidth == WL_CHANSPEC_BW_40) || (bandwidth == WL_CHANSPEC_BW_20)) { + if ((bss->nbss_cap & 0xf00) && (bss->n_cap)) + strcpy(cap, "n|ac"); + else if (bss->n_cap) + strcpy(cap, "n"); + else if (bss->vht_cap) + strcpy(cap, "ac"); + else + strcpy(cap, "a"); + } else { + WLDEV_ERROR(("%s:Mode get failed\n", __FUNCTION__)); + error = BCME_ERROR; + } + + } + kfree(buf); + buf = NULL; + return error; +} +int wldev_set_country( + struct net_device *dev, char *country_code, bool notify, bool user_enforced) +{ + int error = -1; + wl_country_t cspec = {{0}, 0, {0}}; + scb_val_t scbval; + char smbuf[WLC_IOCTL_SMLEN]; + + if (!country_code) + return error; + + bzero(&scbval, sizeof(scb_val_t)); + error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL); + if (error < 0) { + WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error)); + return error; + } + + if ((error < 0) || + (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { + + if (user_enforced) { + bzero(&scbval, sizeof(scb_val_t)); + error = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); + if (error < 0) { + WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", + __FUNCTION__, error)); + return error; + } + } + + cspec.rev = -1; + memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); + memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); + dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec); + error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), + smbuf, sizeof(smbuf), NULL); + if (error < 0) { + WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", + __FUNCTION__, country_code, cspec.ccode, cspec.rev)); + return error; + } + dhd_bus_country_set(dev, &cspec, notify); + WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", + __FUNCTION__, country_code, cspec.ccode, cspec.rev)); + } + return 0; +} diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.h b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.h new file mode 100644 index 000000000000..bf15bd40efc5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.h @@ -0,0 +1,124 @@ +/* + * Common function shared by Linux WEXT, cfg80211 and p2p drivers + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wldev_common.h 701287 2017-05-24 10:33:19Z $ + */ +#ifndef __WLDEV_COMMON_H__ +#define __WLDEV_COMMON_H__ + +#include + +/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or + * netdev_ops->ndo_do_ioctl in new kernels) + * @dev: the net_device handle + */ +s32 wldev_ioctl_get( + struct net_device *dev, u32 cmd, void *arg, u32 len); + +s32 wldev_ioctl_set( + struct net_device *dev, u32 cmd, const void *arg, u32 len); + +/** Retrieve named IOVARs, this function calls wl_dev_ioctl with + * WLC_GET_VAR IOCTL code + */ +s32 wldev_iovar_getbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); + +/** Set named IOVARs, this function calls wl_dev_ioctl with + * WLC_SET_VAR IOCTL code + */ +s32 wldev_iovar_setbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); + +s32 wldev_iovar_setint( + struct net_device *dev, s8 *iovar, s32 val); + +s32 wldev_iovar_getint( + struct net_device *dev, s8 *iovar, s32 *pval); + +/** The following function can be implemented if there is a need for bsscfg + * indexed IOVARs + */ + +s32 wldev_mkiovar_bsscfg( + const s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, s32 buflen, s32 bssidx); + +/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with + * WLC_GET_VAR IOCTL code + */ +s32 wldev_iovar_getbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, + void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); + +/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with + * WLC_SET_VAR IOCTL code + */ +s32 wldev_iovar_setbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, + void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); + +s32 wldev_iovar_getint_bsscfg( + struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx); + +s32 wldev_iovar_setint_bsscfg( + struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); + +extern int dhd_net_set_fw_path(struct net_device *dev, char *fw); +extern int dhd_net_bus_suspend(struct net_device *dev); +extern int dhd_net_bus_resume(struct net_device *dev, uint8 stage); +extern int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, + unsigned long delay_msec); +extern void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, + wl_country_t *cspec); +extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify); +extern void dhd_bus_band_set(struct net_device *dev, uint band); +extern int wldev_set_country(struct net_device *dev, char *country_code, bool notify, + bool user_enforced); +extern int net_os_wake_lock(struct net_device *dev); +extern int net_os_wake_unlock(struct net_device *dev); +extern int net_os_wake_lock_timeout(struct net_device *dev); +extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); +extern int net_os_set_dtim_skip(struct net_device *dev, int val); +extern int net_os_set_suspend_disable(struct net_device *dev, int val); +extern int net_os_set_suspend(struct net_device *dev, int val, int force); +extern int wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, + int max, int *bytes_left); + +/* Get the link speed from dongle, speed is in kpbs */ +int wldev_get_link_speed(struct net_device *dev, int *plink_speed); + +int wldev_get_rssi(struct net_device *dev, scb_val_t *prssi); + +int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid); + +int wldev_get_band(struct net_device *dev, uint *pband); + +int wldev_get_mode(struct net_device *dev, uint8 *pband); +int wldev_get_datarate(struct net_device *dev, int *datarate); +int wldev_set_band(struct net_device *dev, uint band); + + +#endif /* __WLDEV_COMMON_H__ */ -- GitLab From 15e77c3807f863181ec55749b0a21d5c11c843b9 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Thu, 21 Dec 2017 23:28:33 +0300 Subject: [PATCH 186/528] drivers: wireless: bcm4356: Update to 1.71.26 * Sony package version: 32.1.D.0.442 [Xperia Z5 (501SO)] Signed-off-by: Andrey Cherepkov (cherry picked from commit 25f4aa7444e2283ae1c3023df80d83aa16221995) --- .../net/wireless/bcmdhd_bcm4356/bcmevent.c | 3 +- .../net/wireless/bcmdhd_bcm4356/dhd_linux.c | 15 +- drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c | 271 +++--------------- drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h | 31 +- drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c | 34 ++- .../wireless/bcmdhd_bcm4356/include/epivers.h | 10 +- .../net/wireless/bcmdhd_bcm4356/wl_cfg80211.c | 64 +++-- .../net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c | 7 +- .../wireless/bcmdhd_bcm4356/wl_cfgvendor.c | 115 -------- 9 files changed, 129 insertions(+), 421 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c index 82f2af8eb11d..58fa662e840b 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmevent.c 696772 2017-04-28 04:41:32Z $ + * $Id: bcmevent.c 718504 2017-08-31 02:38:08Z $ */ #include @@ -158,7 +158,6 @@ static const bcmevent_name_str_t bcmevent_names[] = { BCMEVENT_NAME(WLC_E_TXFAIL_THRESH), #ifdef GSCAN_SUPPORT BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT), - BCMEVENT_NAME(WLC_E_PFN_SWC), #endif /* GSCAN_SUPPORT */ #ifdef WLBSSLOAD_REPORT BCMEVENT_NAME(WLC_E_BSS_LOAD), diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c index eeada222b3e5..98f96354f6a9 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c @@ -23,7 +23,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 701287 2017-05-24 10:33:19Z $ + * $Id: dhd_linux.c 718504 2017-08-31 02:38:08Z $ */ #include @@ -6128,7 +6128,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef GSCAN_SUPPORT setbit(eventmask_msg->mask, WLC_E_PFN_GSCAN_FULL_RESULT); setbit(eventmask_msg->mask, WLC_E_PFN_SCAN_COMPLETE); - setbit(eventmask_msg->mask, WLC_E_PFN_SWC); setbit(eventmask_msg->mask, WLC_E_PFN_SSID_EXT); #endif /* GSCAN_SUPPORT */ #ifdef BT_WIFI_HANDOVER @@ -8226,14 +8225,6 @@ int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time_f return (dhd_pno_enable_full_scan_result(&dhd->pub, real_time_flag)); } -/* Linux wrapper to call common dhd_handle_swc_evt */ -void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_handle_swc_evt(&dhd->pub, data, send_evt_bytes)); -} - /* Linux wrapper to call common dhd_handle_hotlist_scan_evt */ void * dhd_dev_hotlist_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes, hotlist_type_t type) @@ -8245,11 +8236,11 @@ void * dhd_dev_hotlist_scan_event(struct net_device *dev, /* Linux wrapper to call common dhd_process_full_gscan_result */ void * dhd_dev_process_full_gscan_result(struct net_device *dev, -const void *data, int *send_evt_bytes) + const void *data, uint32 len, int *send_evt_bytes) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_process_full_gscan_result(&dhd->pub, data, send_evt_bytes)); + return (dhd_process_full_gscan_result(&dhd->pub, data, len, send_evt_bytes)); } void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c index 0c7ada8d66a6..a76ab6ade80e 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c @@ -47,6 +47,7 @@ #ifdef GSCAN_SUPPORT #include #endif /* GSCAN_SUPPORT */ +#include #ifdef __BIG_ENDIAN #include @@ -90,6 +91,11 @@ #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") #define TIME_MIN_DIFF 5 +#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) +#define EVENT_MAX_NETCNT \ + ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_t)) \ + / sizeof(wl_pfn_net_info_t) + 1) + static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state); #ifdef GSCAN_SUPPORT @@ -959,32 +965,6 @@ exit: return err; } -#ifdef GSCAN_SUPPORT -static int -_dhd_pno_add_significant_bssid(dhd_pub_t *dhd, - wl_pfn_significant_bssid_t *p_pfn_significant_bssid, int nbssid) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - - if (!nbssid) { - err = BCME_ERROR; - goto exit; - } - - NULL_CHECK(p_pfn_significant_bssid, "bssid list is NULL", err); - - err = dhd_iovar(dhd, 0, "pfn_add_swc_bssid", (char *)p_pfn_significant_bssid, - sizeof(wl_pfn_significant_bssid_t) * nbssid, NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_significant_bssid %d\n", __FUNCTION__, err)); - goto exit; - } -exit: - return err; -} -#endif /* GSCAN_SUPPORT */ - int dhd_pno_stop_for_ssid(dhd_pub_t *dhd) { @@ -1623,19 +1603,6 @@ static void dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params, _params->params_gscan.nbssid_hotlist = 0; DHD_PNO(("Flush Hotlist Config\n")); } - if (flags & GSCAN_FLUSH_SIGNIFICANT_CFG) { - dhd_pno_significant_bssid_t *iter, *next; - - if (_params->params_gscan.nbssid_significant_change > 0) { - list_for_each_entry_safe(iter, next, - &_params->params_gscan.significant_bssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - _params->params_gscan.nbssid_significant_change = 0; - DHD_PNO(("Flush Significant Change Config\n")); - } if (flags & GSCAN_FLUSH_EPNO_CFG) { dhd_epno_params_t *iter, *next; @@ -1781,8 +1748,10 @@ dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX; ptr->max_scan_reporting_threshold = 100; - ptr->max_hotlist_aps = PFN_HOTLIST_MAX_NUM_APS; - ptr->max_significant_wifi_change_aps = PFN_SWC_MAX_NUM_APS; + ptr->max_hotlist_bssids = PFN_HOTLIST_MAX_NUM_APS; + ptr->max_hotlist_ssids = 0; + ptr->max_significant_wifi_change_aps = 0; + ptr->max_bssid_history_entries = 0; ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; ptr->max_white_list_ssid = MAX_WHITELIST_SSID; @@ -1951,61 +1920,6 @@ dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, _params->params_gscan.lost_ap_window = ptr->lost_ap_window; } break; - case DHD_PNO_SIGNIFICANT_SCAN_CFG_ID: - { - gscan_swc_params_t *ptr = (gscan_swc_params_t *)buf; - dhd_pno_significant_bssid_t *_pno_significant_change_bssid; - wl_pfn_significant_bssid_t *significant_bssid_ptr; - - if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, - GSCAN_FLUSH_SIGNIFICANT_CFG); - } - - if (!ptr->nbssid) - break; - - if (!_params->params_gscan.nbssid_significant_change) - INIT_LIST_HEAD(&_params->params_gscan.significant_bssid_list); - - if ((_params->params_gscan.nbssid_significant_change + - ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { - DHD_ERROR(("Excessive number of SWC APs programmed %d\n", - (_params->params_gscan.nbssid_significant_change + - ptr->nbssid))); - err = BCME_RANGE; - goto exit; - } - - for (i = 0, significant_bssid_ptr = ptr->bssid_elem_list; - i < ptr->nbssid; i++, significant_bssid_ptr++) { - _pno_significant_change_bssid = - kzalloc(sizeof(dhd_pno_significant_bssid_t), - GFP_KERNEL); - - if (!_pno_significant_change_bssid) { - DHD_ERROR(("SWC bssidptr is NULL, cannot kalloc %zd bytes", - sizeof(dhd_pno_significant_bssid_t))); - err = BCME_NOMEM; - goto exit; - } - memcpy(&_pno_significant_change_bssid->BSSID, - &significant_bssid_ptr->macaddr, ETHER_ADDR_LEN); - _pno_significant_change_bssid->rssi_low_threshold = - significant_bssid_ptr->rssi_low_threshold; - _pno_significant_change_bssid->rssi_high_threshold = - significant_bssid_ptr->rssi_high_threshold; - list_add_tail(&_pno_significant_change_bssid->list, - &_params->params_gscan.significant_bssid_list); - } - - _params->params_gscan.swc_nbssid_threshold = ptr->swc_threshold; - _params->params_gscan.swc_rssi_window_size = ptr->rssi_window; - _params->params_gscan.lost_ap_window = ptr->lost_ap_window; - _params->params_gscan.nbssid_significant_change += ptr->nbssid; - - } - break; case DHD_PNO_SCAN_CFG_ID: { int i, k; @@ -2119,7 +2033,6 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL; wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL; - wl_pfn_significant_bssid_t *p_pfn_significant_bssid = NULL; wl_pfn_bssid_t *p_pfn_bssid = NULL; wlc_ssid_ext_t *pssid_list = NULL; dhd_pno_params_t *params_legacy; @@ -2197,7 +2110,7 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); - pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOC(dhd->osh, gscan_param_size); + pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size); if (!pfn_gscan_cfg_t) { DHD_ERROR(("%s: failed to malloc memory of size %d\n", @@ -2212,15 +2125,7 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) } else { pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; } - if (gscan_params->nbssid_significant_change) { - pfn_gscan_cfg_t->swc_nbssid_threshold = gscan_params->swc_nbssid_threshold; - pfn_gscan_cfg_t->swc_rssi_window_size = gscan_params->swc_rssi_window_size; - pfn_gscan_cfg_t->lost_ap_window = gscan_params->lost_ap_window; - } else { - pfn_gscan_cfg_t->swc_nbssid_threshold = 0; - pfn_gscan_cfg_t->swc_rssi_window_size = 0; - pfn_gscan_cfg_t->lost_ap_window = 0; - } + pfn_gscan_cfg_t->flags = (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw; @@ -2257,37 +2162,6 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) __FUNCTION__, err)); goto exit; } - if (gscan_params->nbssid_significant_change) { - dhd_pno_significant_bssid_t *iter, *next; - - p_pfn_significant_bssid = kzalloc(sizeof(wl_pfn_significant_bssid_t) * - gscan_params->nbssid_significant_change, GFP_KERNEL); - if (p_pfn_significant_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate memory %zd\n", - __FUNCTION__, - sizeof(wl_pfn_significant_bssid_t) * - gscan_params->nbssid_significant_change)); - err = BCME_NOMEM; - goto exit; - } - i = 0; - /* convert dhd_pno_significant_bssid_t to wl_pfn_significant_bssid_t */ - list_for_each_entry_safe(iter, next, &gscan_params->significant_bssid_list, list) { - p_pfn_significant_bssid[i].rssi_low_threshold = iter->rssi_low_threshold; - p_pfn_significant_bssid[i].rssi_high_threshold = iter->rssi_high_threshold; - memcpy(&p_pfn_significant_bssid[i].macaddr, &iter->BSSID, ETHER_ADDR_LEN); - i++; - } - DHD_PNO(("nbssid_significant_change %d \n", - gscan_params->nbssid_significant_change)); - err = _dhd_pno_add_significant_bssid(dhd, p_pfn_significant_bssid, - gscan_params->nbssid_significant_change); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_add_significant_bssid(err :%d)\n", - __FUNCTION__, err)); - goto exit; - } - } if (gscan_params->nbssid_hotlist) { struct dhd_pno_bssid *iter, *next; @@ -2348,7 +2222,6 @@ exit: } } kfree(pssid_list); - kfree(p_pfn_significant_bssid); kfree(p_pfn_bssid); if (pfn_gscan_cfg_t) { MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size); @@ -2358,7 +2231,6 @@ exit: (tot_num_buckets * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); } return err; - } static wl_pfn_gscan_ch_bucket_cfg_t * @@ -3588,87 +3460,6 @@ dhd_retreive_batch_scan_results(dhd_pub_t *dhd) return err; } -/* Handle Significant WiFi Change (SWC) event from FW - * Send event to HAL when all results arrive from FW - */ -void * -dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes) -{ - void *ptr = NULL; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - struct dhd_pno_swc_evt_param *params; - wl_pfn_swc_results_t *results = (wl_pfn_swc_results_t *)event_data; - wl_pfn_significant_net_t *change_array; - int i; - - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - params = &(gscan_params->param_significant); - - if (!results->total_count) { - *send_evt_bytes = 0; - return ptr; - } - - if (!params->results_rxed_so_far) { - if (!params->change_array) { - params->change_array = (wl_pfn_significant_net_t *) - kmalloc(sizeof(wl_pfn_significant_net_t) * results->total_count, - GFP_KERNEL); - - if (!params->change_array) { - DHD_ERROR(("%s Cannot Malloc %zd bytes!!\n", __FUNCTION__, - sizeof(wl_pfn_significant_net_t) * results->total_count)); - *send_evt_bytes = 0; - return ptr; - } - } else { - DHD_ERROR(("RX'ed WLC_E_PFN_SWC evt from FW, previous evt not complete!!")); - *send_evt_bytes = 0; - return ptr; - } - - } - - DHD_PNO(("%s: pkt_count %d total_count %d\n", __FUNCTION__, - results->pkt_count, results->total_count)); - - for (i = 0; i < results->pkt_count; i++) { - DHD_PNO(("\t %02x:%02x:%02x:%02x:%02x:%02x\n", - results->list[i].BSSID.octet[0], - results->list[i].BSSID.octet[1], - results->list[i].BSSID.octet[2], - results->list[i].BSSID.octet[3], - results->list[i].BSSID.octet[4], - results->list[i].BSSID.octet[5])); - } - - change_array = ¶ms->change_array[params->results_rxed_so_far]; - if ((params->results_rxed_so_far + results->pkt_count) <= results->total_count) { - memcpy(change_array, results->list, - sizeof(wl_pfn_significant_net_t) * results->pkt_count); - params->results_rxed_so_far += results->pkt_count; - } else { - /* In case of spurious event or invalid data send hang event */ - dhd_os_send_hang_message(dhd); - } - - if (params->results_rxed_so_far == results->total_count) { - params->results_rxed_so_far = 0; - *send_evt_bytes = sizeof(wl_pfn_significant_net_t) * results->total_count; - /* Pack up change buffer to send up and reset - * results_rxed_so_far, after its done. - */ - ptr = (void *) params->change_array; - /* expecting the callee to free this mem chunk */ - params->change_array = NULL; - } else { - *send_evt_bytes = 0; - } - - return ptr; -} - void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) { @@ -3699,7 +3490,7 @@ dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) } void * -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size) { wl_bss_info_t *bi = NULL; wl_gscan_result_t *gscan_result; @@ -3708,6 +3499,8 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) uint8 channel; uint32 mem_needed; struct timespec ts; + u32 bi_ie_length = 0; + u32 bi_ie_offset = 0; *size = 0; @@ -3717,6 +3510,14 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); goto exit; } + if ((len < sizeof(*gscan_result)) || + (len < dtoh32(gscan_result->buflen)) || + (dtoh32(gscan_result->buflen) > + (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { + DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__, + dtoh32(gscan_result->buflen))); + goto exit; + } if (!gscan_result->bss_info) { DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); goto exit; @@ -3728,12 +3529,19 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } + bi_ie_offset = dtoh32(bi->ie_offset); + bi_ie_length = dtoh32(bi->ie_length); + if ((bi_ie_offset + bi_ie_length) > bi_length) { + DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n", + __FUNCTION__, bi_ie_length, bi_ie_offset)); + goto exit; + } if (bi->SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", bi->SSID_len)); - bi->SSID_len = DOT11_MAX_SSID_LEN; + DHD_ERROR(("%s: Invalid SSID length:%u\n", __FUNCTION__, bi->SSID_len)); + goto exit; } - mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi->ie_length; + mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi_ie_length; result = kmalloc(mem_needed, GFP_KERNEL); if (!result) { @@ -3755,9 +3563,9 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) result->ts = (uint64) TIMESPEC_TO_US(ts); result->beacon_period = dtoh16(bi->beacon_period); result->capability = dtoh16(bi->capability); - result->ie_length = dtoh32(bi->ie_length); + result->ie_length = bi_ie_length; memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN); - memcpy(result->ie_data, ((uint8 *)bi + bi->ie_offset), bi->ie_length); + memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length); *size = mem_needed; exit: return result; @@ -3821,6 +3629,12 @@ dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int wl_pfn_net_info_t *net; if (pfn_result->version != PFN_SCANRESULT_VERSION) { + /* Check if count of pfn results is corrupted */ + if (pfn_result->count > EVENT_MAX_NETCNT) { + DHD_ERROR(("%s event %d: pfn results count %d" + "exceeds the max limit\n", __FUNCTION__, event, pfn_result->count)); + return NULL; + } DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, pfn_result->version, PFN_SCANRESULT_VERSION)); return NULL; @@ -3875,7 +3689,8 @@ void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *s gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - if (!results->count) { + if (!results->count || (results->count > EVENT_MAX_NETCNT)) { + DHD_ERROR(("%s: wrong result count:%d\n", __FUNCTION__, results->count)); *send_evt_bytes = 0; return ptr; } diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h index 2f48e5fc55e5..dc99441fa47a 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h @@ -354,8 +354,10 @@ typedef struct dhd_pno_gscan_capabilities { int max_ap_cache_per_scan; int max_rssi_sample_size; int max_scan_reporting_threshold; - int max_hotlist_aps; + int max_hotlist_bssids; + int max_hotlist_ssids; int max_significant_wifi_change_aps; + int max_bssid_history_entries; int max_epno_ssid_crc32; int max_epno_hidden_ssid; int max_white_list_ssid; @@ -417,26 +419,6 @@ typedef struct gscan_hotlist_scan_params { struct bssid_t bssid[1]; /* n bssids to follow */ } gscan_hotlist_scan_params_t; -/* SWC (Significant WiFi Change) params */ -typedef struct gscan_swc_params { - /* Rssi averaging window size */ - uint8 rssi_window; - /* Number of scans that the AP has to be absent before - * being declared LOST - */ - uint8 lost_ap_window; - /* if x Aps have a significant change generate an event. */ - uint8 swc_threshold; - uint8 nbssid; - wl_pfn_significant_bssid_t bssid_elem_list[1]; -} gscan_swc_params_t; - -typedef struct dhd_pno_significant_bssid { - struct ether_addr BSSID; - int8 rssi_low_threshold; - int8 rssi_high_threshold; - struct list_head list; -} dhd_pno_significant_bssid_t; #endif /* GSCAN_SUPPORT */ typedef union dhd_pno_params { struct dhd_pno_legacy_params params_legacy; @@ -497,13 +479,11 @@ int dhd_dev_pno_lock_access_batch_results(struct net_device *dev); void dhd_dev_pno_unlock_access_batch_results(struct net_device *dev); extern int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush); extern int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time); -extern void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, - int *send_evt_bytes); int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes, hotlist_type_t type); void * dhd_dev_process_full_gscan_result(struct net_device *dev, - const void *data, int *send_evt_bytes); + const void *data, uint32 len, int *send_evt_bytes); extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); @@ -545,11 +525,10 @@ extern int dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush); extern int dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag); extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *buf); extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); -extern void *dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes); extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, hotlist_type_t type); extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, - int *send_evt_bytes); + uint32 len, int *send_evt_bytes); extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c index c307875acb1f..21af524e1419 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c @@ -1601,19 +1601,37 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) gfp_t kflags; bool is_new = TRUE; + DHD_RTT(("Enter %s \n", __FUNCTION__)); NULL_CHECK(dhd, "dhd is NULL", ret); + +#ifdef WL_CFG80211 rtt_status = GET_RTTSTATE(dhd); NULL_CHECK(rtt_status, "rtt_status is NULL", ret); - event_type = ntoh32_ua((void *)&event->event_type); - - if (event_type != WLC_E_PROXD) { - goto exit; - } if (RTT_IS_STOPPED(rtt_status)) { /* Ignore the Proxd event */ + DHD_RTT((" event handler rtt is stopped \n")); goto exit; } +#endif /* WL_CFG80211 */ + if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) { + DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__, + ntoh32_ua((void *)&event->datalen))); + ret = -EINVAL; + goto exit; + } + event_type = ntoh32_ua((void *)&event->event_type); + if (event_type != WLC_E_PROXD) { + DHD_ERROR((" failed event \n")); + ret = -EINVAL; + goto exit; + } + + if (!event_data) { + DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); + ret = -EINVAL; + goto exit; + } p_event = (wl_proxd_event_t *) event_data; version = ltoh16(p_event->version); if (version < WL_PROXD_API_VERSION) { @@ -1633,9 +1651,15 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) p_loginfo = ftm_get_event_type_loginfo(event_type); if (p_loginfo == NULL) { DHD_ERROR(("receive an invalid FTM event %d\n", event_type)); + ret = -EINVAL; goto exit; /* ignore this event */ } /* get TLVs len, skip over event header */ + if (ltoh16(p_event->len) < OFFSETOF(wl_proxd_event_t, tlvs)) { + DHD_ERROR(("invalid FTM event length:%d\n", ltoh16(p_event->len))); + ret = -EINVAL; + goto exit; + } tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs); DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n", p_loginfo->text, diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h b/drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h index c21e4efb943f..8624621913d9 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h @@ -30,19 +30,19 @@ #define EPI_MINOR_VERSION 71 -#define EPI_RC_NUMBER 25 +#define EPI_RC_NUMBER 26 #define EPI_INCREMENTAL_NUMBER 0 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 71, 25, 0 +#define EPI_VERSION 1, 71, 26, 0 -#define EPI_VERSION_NUM 0x01471900 +#define EPI_VERSION_NUM 0x01471a00 -#define EPI_VERSION_DEV 1.71.25 +#define EPI_VERSION_DEV 1.71.26 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.71.25 (r)" +#define EPI_VERSION_STR "1.71.26 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c index d1546bbfcbd0..4b6ddbed17cb 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 704356 2017-06-13 08:36:52Z $ + * $Id: wl_cfg80211.c 718504 2017-08-31 02:38:08Z $ */ /* */ #include @@ -9853,14 +9853,6 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, u32 len = ntoh32(e->datalen); switch (event) { - case WLC_E_PFN_SWC: - ptr = dhd_dev_swc_scan_event(ndev, data, &send_evt_bytes); - if (send_evt_bytes) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_GSCAN_SIGNIFICANT_EVENT, ptr, send_evt_bytes); - kfree(ptr); - } - break; case WLC_E_PFN_BEST_BATCHING: err = dhd_dev_retrieve_batch_scan(ndev); if (err < 0) { @@ -9907,7 +9899,7 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } break; case WLC_E_PFN_GSCAN_FULL_RESULT: - ptr = dhd_dev_process_full_gscan_result(ndev, data, &send_evt_bytes); + ptr = dhd_dev_process_full_gscan_result(ndev, data, len, &send_evt_bytes); if (ptr) { wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes); @@ -10098,15 +10090,26 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wifi_p2p_pub_act_frame_t *act_frm = NULL; wifi_p2p_action_frame_t *p2p_act_frm = NULL; wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; - wl_event_rx_frame_data_t *rxframe = - (wl_event_rx_frame_data_t*)data; - u32 event = ntoh32(e->event_type); + wl_event_rx_frame_data_t *rxframe; + u32 event; u8 *mgmt_frame; - u8 bsscfgidx = e->bsscfgidx; - u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); - u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); + u8 bsscfgidx; + u32 mgmt_frame_len; + u16 channel; bool retval; - + if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) { + WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen))); + return -EINVAL; + } + mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); + event = ntoh32(e->event_type); + bsscfgidx = e->bsscfgidx; + rxframe = (wl_event_rx_frame_data_t *)data; + if (!rxframe) { + WL_ERR(("rxframe: NULL\n")); + return -EINVAL; + } + channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK); memset(&bssid, 0, ETHER_ADDR_LEN); ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); @@ -10243,7 +10246,10 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_DBG((" Event WLC_E_PROBREQ_MSG received\n")); mgmt_frame = (u8 *)(data); mgmt_frame_len = ntoh32(e->datalen); - + if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) { + WL_ERR(("wrong datalen:%d\n", mgmt_frame_len)); + return -EINVAL; + } prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN; /* Parse prob_req IEs */ @@ -10484,7 +10490,6 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event; @@ -10968,6 +10973,11 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("Invalid escan result (NULL pointer)\n")); goto exit; } + if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) || + (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) { + WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen))); + goto exit; + } if (dtoh16(escan_result->bss_count) != 1) { WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); goto exit; @@ -12927,7 +12937,7 @@ static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *i { u8 *ssidie; int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); - int32 remaining_ie_buf_len, available_buffer_len; + int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len; ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); /* ERROR out if * 1. No ssid IE is FOUND or @@ -12941,24 +12951,28 @@ static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *i } available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream); remaining_ie_buf_len = available_buffer_len - (int)ssidie[1]; - if ((ssid_len > ssidie[1]) || - (ssidie[1] > available_buffer_len)) { + unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size); + if (ssidie[1] > available_buffer_len) { + WL_ERR(("%s: skip wl_update_hidden_ap_ie : overflow\n", __FUNCTION__)); return; } if (ssidie[1] != ssid_len) { if (ssidie[1]) { - WL_ERR(("%s: Wrong SSID len: %d != %d\n", + WL_INFORM(("%s: Wrong SSID len: %d != %d\n", __FUNCTION__, ssidie[1], bi->SSID_len)); } - if (roam) { - WL_ERR(("Changing the SSID Info.\n")); + if ((roam && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) { + WL_INFORM(("Changing the SSID Info.\n")); memmove(ssidie + ssid_len + 2, (ssidie + 2) + ssidie[1], remaining_ie_buf_len); memcpy(ssidie + 2, bi->SSID, ssid_len); *ie_size = *ie_size + ssid_len - ssidie[1]; ssidie[1] = ssid_len; + } else if (ssid_len < ssidie[1]) { + WL_ERR(("%s: Invalid SSID len: %d < %d\n", + __FUNCTION__, ssidie[1], bi->SSID_len)); } return; } diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c index 5465913c99fa..ff6e8a2045ad 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfgp2p.c 701287 2017-05-24 10:33:19Z $ + * $Id: wl_cfgp2p.c 711632 2017-07-19 04:24:04Z $ * */ #include @@ -2321,8 +2321,9 @@ wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib) return pAttrib; } else { - parse += (ie->len + TLV_HDR_LEN); - len -= (ie->len + TLV_HDR_LEN); + /* move to next IE */ + len -= (u32)((u8 *)ie + TLV_HDR_LEN + ie->len - parse); + parse = (uint8 *)ie + TLV_HDR_LEN + ie->len; CFGP2P_INFO(("P2P Attribute %d not found Moving parse" " to %p len to %d", attrib, parse, len)); } diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c index 2422df453b46..e88fd7289459 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c @@ -956,113 +956,6 @@ wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy, return err; } -static int -wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_swc_params_t *significant_params; - int tmp, tmp1, tmp2, type, j = 0; - const struct nlattr *outer, *inner, *iter; - uint8 flush = 0; - wl_pfn_significant_bssid_t *bssid; - uint16 num_bssid = 0; - uint16 max_buf_size = sizeof(gscan_swc_params_t) + - sizeof(wl_pfn_significant_bssid_t) * (PFN_SWC_MAX_NUM_APS - 1); - - significant_params = kzalloc(max_buf_size, GFP_KERNEL); - if (!significant_params) { - WL_ERR(("Cannot Malloc mem size:%d\n", max_buf_size)); - return BCME_NOMEM; - } - - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - - switch (type) { - case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH: - flush = nla_get_u8(iter); - break; - case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE: - significant_params->rssi_window = nla_get_u16(iter); - break; - case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: - significant_params->lost_ap_window = nla_get_u16(iter); - break; - case GSCAN_ATTRIBUTE_MIN_BREACHING: - significant_params->swc_threshold = nla_get_u16(iter); - break; - case GSCAN_ATTRIBUTE_NUM_BSSID: - num_bssid = nla_get_u16(iter); - if (num_bssid > PFN_SWC_MAX_NUM_APS) { - WL_ERR(("ovar max SWC bssids:%d\n", - num_bssid)); - err = BCME_BADARG; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS: - if (num_bssid == 0) { - WL_ERR(("num_bssid : 0\n")); - err = BCME_BADARG; - goto exit; - } - bssid = significant_params->bssid_elem_list; - nla_for_each_nested(outer, iter, tmp) { - if (j >= num_bssid) { - j++; - break; - } - nla_for_each_nested(inner, outer, tmp1) { - switch (nla_type(inner)) { - case GSCAN_ATTRIBUTE_BSSID: - memcpy(&(bssid[j].macaddr), - nla_data(inner), - ETHER_ADDR_LEN); - break; - case GSCAN_ATTRIBUTE_RSSI_HIGH: - bssid[j].rssi_high_threshold - = (int8) nla_get_u8(inner); - break; - case GSCAN_ATTRIBUTE_RSSI_LOW: - bssid[j].rssi_low_threshold - = (int8) nla_get_u8(inner); - break; - default: - WL_ERR(("ATTR unknown %d\n", - type)); - break; - } - } - j++; - } - break; - default: - WL_ERR(("Unknown type %d\n", type)); - break; - } - } - if (j != num_bssid) { - WL_ERR(("swc bssids count:%d not matched to num_bssid:%d\n", - j, num_bssid)); - err = BCME_BADARG; - goto exit; - } - significant_params->nbssid = j; - - if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, - significant_params, flush) < 0) { - WL_ERR(("Could not set GSCAN significant cfg\n")); - err = BCME_ERROR; - goto exit; - } -exit: - kfree(significant_params); - return err; -} - static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { @@ -2065,14 +1958,6 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = { .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = wl_cfgvendor_hotlist_cfg }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_significant_change_cfg - }, { { .vendor_id = OUI_GOOGLE, -- GitLab From 51b7b8edc1033f2f5768dd169602a07cf56ee251 Mon Sep 17 00:00:00 2001 From: zachariasmaladroit Date: Mon, 2 Oct 2017 01:30:41 +0200 Subject: [PATCH 187/528] drivers: wireless: bcm4356: Fix direct references to HZ inspired by work from humberos, kudos ! Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit 1a6b7bb38f343133037b961e5744d46baf059942) --- drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c | 6 +++--- drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c index 98f96354f6a9..cb35906c0567 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c @@ -7356,7 +7356,7 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); #endif DHD_PERIM_UNLOCK(pub); @@ -7387,7 +7387,7 @@ dhd_os_d3ack_wait(dhd_pub_t *pub, uint *condition, bool *pending) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); #endif DHD_PERIM_UNLOCK(pub); @@ -7765,7 +7765,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); #else - int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; + int timeout = IOCTL_RESP_TIMEOUT * msecs_to_jiffies(1); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ dhd_os_sdunlock(dhd); diff --git a/drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h index 59129cf8015b..3ce18fa61bf7 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h @@ -243,7 +243,7 @@ extern int osl_error(int bcmerror); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) #define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) #else -#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#define OSL_SYSUPTIME() ((uint32)jiffies * msecs_to_jiffies(1)) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ #define printf(fmt, args...) printk(fmt , ## args) #include /* for vsn/printf's */ -- GitLab From 0829544e45eeed7c7b686d027b8274b153ac31a9 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 24 Oct 2017 13:30:13 +0300 Subject: [PATCH 188/528] drivers: wireless: bcm4356: fix warning: initialization from incompatible pointer type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/bcmdhd/wl_cfg80211.c:7459:17: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types] .del_station = wl_cfg80211_del_station, ^~~~~~~~~~~~~~~~~~~~~~~ drivers/net/wireless/bcmdhd/wl_cfg80211.c:7459:17: note: (near initialization for ‘wl_cfg80211_ops.del_station’) Fix warning due to patch: 1d2389ba93 ("cfg80211: Convert del_station() callback to use a param struct") Signed-off-by: Andrey Cherepkov (cherry picked from commit 3c6455554377ae715d3d4e81f83ad4cc9bea54a2) --- drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c index 4b6ddbed17cb..b5554c59770f 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -377,8 +377,9 @@ static s32 wl_cfg80211_resume(struct wiphy *wiphy); 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); -static s32 wl_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *ndev, u8* mac_addr); +static s32 wl_cfg80211_del_station( + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params); static s32 wl_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ @@ -7543,9 +7544,8 @@ static s32 wl_cfg80211_hostapd_sec( 2, 0)) static s32 wl_cfg80211_del_station( - struct wiphy *wiphy, - struct net_device *ndev, - u8* mac_addr) + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params) { struct net_device *dev; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -7557,6 +7557,8 @@ wl_cfg80211_del_station( struct maclist *assoc_maclist = (struct maclist *)mac_buf; int num_associated = 0; + const u8 *mac_addr = params->mac; + WL_DBG(("Entry\n")); if (mac_addr == NULL) { WL_DBG(("mac_addr is NULL ignore it\n")); -- GitLab From b10f5498f8a1adbb38ce581d92f358578e4edbcd Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 25 Apr 2018 18:30:04 -0700 Subject: [PATCH 189/528] drivers: wireless: bcm4356: Fix tautological comparison warning When BCMBUSTYPE is undefined (which it is), BUSTYPE is just whatever is passed to it so this statement is never true. Fixes the following GCC 7.3.0 warning: self-comparison always evaluates to false [-Wtautological-compare] Signed-off-by: Nathan Chancellor Signed-off-by: Andrey Cherepkov (cherry picked from commit 71974c3e708abad571f689dd7e7635bf8ab61534) --- drivers/net/wireless/bcmdhd_bcm4356/siutils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/siutils.c b/drivers/net/wireless/bcmdhd_bcm4356/siutils.c index 6ae7c4c323d2..7cbec7608757 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/siutils.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/siutils.c @@ -495,11 +495,13 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, } sih->bustype = bustype; +#ifdef BCMBUSTYPE if (bustype != BUSTYPE(bustype)) { SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); return NULL; } +#endif /* bus/core/clk setup for register access */ if (!si_buscore_prep(sii, bustype, devid, sdh)) { -- GitLab From 453ea4541601f7f35e6c29311af4d748133574bd Mon Sep 17 00:00:00 2001 From: Insun Song Date: Mon, 3 Aug 2015 16:41:42 -0700 Subject: [PATCH 190/528] drivers: wireless: bcm4356: fix for watch dog issue in wifi connect test bug => 22666437 fix for watchdog issue in fast switching APs. preventing numerous escan result which trigger watchdog. Change-Id: I835401008a644290df947e4bab1cedbd1599f6e6 Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit 17585d8a15fadc664dbe8219f218405c9065c61f) --- drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c index b5554c59770f..70a1d22f9047 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -11213,16 +11213,7 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); } -#ifdef GSCAN_SUPPORT - else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN)) { - if (status == WLC_E_STATUS_NEWSCAN) { - WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, - escan_result->bss_count)); - } -#else else if (status == WLC_E_STATUS_ABORT) { -#endif /* GSCAN_SUPPORT */ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; wl_escan_print_sync_id(status, escan_result->sync_id, cfg->escan_info.cur_sync_id); -- GitLab From 01d4ed45f9d409b47e4722d38041e6a22c95df1b Mon Sep 17 00:00:00 2001 From: Ashwin Date: Fri, 16 Oct 2015 15:53:47 -0700 Subject: [PATCH 191/528] drivers: wireless: bcm4356: add a NULL check Check if the gscan result buffer was succesfully allocated Bug: 24469238 Change-Id: I1e896faed42ce53bc36ada449cc4e1c975830159 Signed-off-by: Ashwin Signed-off-by: Andrey Cherepkov (cherry picked from commit 6ee18470501f2544a4aa30c392d30a230a6d576d) --- drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c index a76ab6ade80e..838fe5d2898c 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c @@ -2591,6 +2591,12 @@ _dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) } plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + if (!plbestnet) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, + PNO_BESTNET_LEN)); + err = BCME_NOMEM; + goto exit; + } mutex_lock(&_pno_state->pno_mutex); -- GitLab From 76c449d241d88ebf86170cad9228eb99f199481f Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Sat, 5 Mar 2016 19:51:40 -0800 Subject: [PATCH 192/528] drivers: wireless: bcm4356: Fix CONFIG_HZ dependency in wifi driver. Sleep for HZ jiffies, not 100. bug 27419732 Change-Id: I9717f2b539a7fe2e2ba2cd6c3fd231f987ec38a4 Signed-off-by: Andrey Cherepkov (cherry picked from commit fa8a74b56f973164ea99fd49ffeb05e1e2af196a) --- drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c index 70a1d22f9047..3883facbe883 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -10739,7 +10739,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } set_current_state(TASK_INTERRUPTIBLE); - (void)schedule_timeout(100); + (void)schedule_timeout(HZ); set_current_state(TASK_RUNNING); refcnt++; } -- GitLab From 39613fdef5cf7b1e58ef2149bb76775d5b0d2bc3 Mon Sep 17 00:00:00 2001 From: Mir Ali Date: Mon, 20 Jun 2016 15:23:42 +0530 Subject: [PATCH 193/528] drivers: wireless: bcm4356: Check to avoid sending Disassoc in unassociated state The change is meant to send a Disassoc request only in the connected state thereby handling the case of a erroneous Diassoc from firmware BUG=28336924 Signed-off-by: Mir Ali Signed-off-by: Andrey Cherepkov (cherry picked from commit 6e51867e23ecdaa9c427d3ca9d9d17e570af7aae) --- drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c index 0f12c77bb29f..b4aa5063a279 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c @@ -31,6 +31,7 @@ #include #include +#include #define htod32(i) (i) #define htod16(i) (i) @@ -473,6 +474,9 @@ int wldev_set_country( wl_country_t cspec = {{0}, 0, {0}}; scb_val_t scbval; char smbuf[WLC_IOCTL_SMLEN]; + struct wireless_dev *wdev = ndev_to_wdev(dev); + struct wiphy *wiphy = wdev->wiphy; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); if (!country_code) return error; @@ -487,7 +491,7 @@ int wldev_set_country( if ((error < 0) || (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { - if (user_enforced) { + if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) { bzero(&scbval, sizeof(scb_val_t)); error = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); if (error < 0) { -- GitLab From 57481a12e6a568f64e2ca690b9b049a020526592 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Thu, 14 Jul 2016 14:49:48 -0700 Subject: [PATCH 194/528] drivers: wireless: bcm4356: add boundary check while getting channel spec [PORT][angler] Adding check for chanspec-list count. If count is over than maximum, then cancel current process and immediately return. This will also prevent kernel panic once caused by watchdog timeout. bug=29863589 Change-Id: Ib2de9d71ca39c3fd97a7d684db9925940904e404 Signed-off-by: Insun Song Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit 06bfe1bb7a48c8b0fe0eeffef4a8a7da95fe01cf) --- drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c index 3883facbe883..055358835358 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -12187,6 +12187,13 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) #undef LOCAL_BUF_LEN list = (wl_uint32_list_t *)(void *)pbuf; + + if ((list) && (dtoh32(list->count) > htod32(WL_NUMCHANSPECS))) { + WL_ERR(("Invalid channel list : %d\n", dtoh32(list->count))); + kfree(pbuf); + return INVCHANSPEC; + } + band = array_size = n_2g = n_5g = 0; for (i = 0; i < dtoh32(list->count); i++) { index = 0; -- GitLab From e2f23e0df0cb2b5e07893ff005f01a46a1fc6758 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Tue, 25 Oct 2016 13:33:18 -0700 Subject: [PATCH 195/528] drivers: wireless: bcm4356: fix buffer overrun in private command path buffer overrun case found when length parameter manipulated. 1. if input parameter buffer length is less than 4k, then allocate 4k by default. It help to get enough margin for output string overwritten. 2. added additional length check not to override user space allocated buffer size. bug=29000183 Change-Id: I0c15d764c1648920f0214ec47ada689ca44ebfba Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit 948a40a933c062cb7d20421388a00a67bdf7b605) --- .../net/wireless/bcmdhd_bcm4356/wl_android.c | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c index a9a1196dc5a5..9148ea7883ca 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c @@ -398,18 +398,22 @@ static int wl_android_get_rssi(struct net_device *net, char *command, int total_ return -1; if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); - } else if (total_len <= ssid.SSID_len) { - return -ENOMEM; } else { - memcpy(command, ssid.SSID, ssid.SSID_len); - bytes_written = ssid.SSID_len; + if (total_len > ssid.SSID_len) { + memcpy(command, ssid.SSID, ssid.SSID_len); + bytes_written = ssid.SSID_len; + } else { + return BCME_ERROR; + } } - if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1)) - return -ENOMEM; - bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written, + if ((total_len - bytes_written) >= (strlen(" rssi -XXX") + 1)) { + bytes_written += snprintf(&command[bytes_written], total_len - bytes_written, " rssi %d", scbval.val); - command[bytes_written] = '\0'; + command[bytes_written] = '\0'; + } else { + return BCME_ERROR; + } DHD_TRACE(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); return bytes_written; @@ -2574,13 +2578,17 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) } } if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) { - DHD_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__, - priv_cmd.total_len)); + DHD_ERROR(("%s: buf length invalid:%d \n", __FUNCTION__, priv_cmd.total_len)); ret = -EINVAL; goto exit; } - buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN); + if (priv_cmd.total_len < PRIVATE_COMMAND_DEF_LEN) { + buf_size = PRIVATE_COMMAND_DEF_LEN; + } else { + buf_size = priv_cmd.total_len; + } + command = kmalloc((buf_size + 1), GFP_KERNEL); if (!command) @@ -2857,19 +2865,22 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) #endif else { DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); - bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); + snprintf(command, 5, "FAIL"); + bytes_written = strlen("FAIL"); } if (bytes_written >= 0) { - if ((bytes_written == 0) && (priv_cmd.total_len > 0)) + if ((bytes_written == 0) && (priv_cmd.total_len > 0)) { command[0] = '\0'; + } if (bytes_written >= priv_cmd.total_len) { - DHD_ERROR(("%s: err. bytes_written:%d >= buf_size:%d \n", - __FUNCTION__, bytes_written, buf_size)); + DHD_ERROR(("%s: not enough for output. bytes_written:%d >= total_len:%d \n", + __FUNCTION__, bytes_written, priv_cmd.total_len)); ret = BCME_BUFTOOSHORT; goto exit; + } else { + bytes_written++; } - bytes_written++; priv_cmd.used_len = bytes_written; if (copy_to_user(priv_cmd.buf, command, bytes_written)) { DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); @@ -2882,7 +2893,10 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) exit: net_os_wake_unlock(net); - kfree(command); + if (command) { + kfree(command); + } + return ret; } -- GitLab From 9109f8ad3700694a09ca1201cd023856332638e2 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Tue, 31 Jan 2017 16:18:40 -0800 Subject: [PATCH 196/528] drivers: wireless: bcm4356: fix buffer overrun in wl_android_set_roampref added boundary check not to override allocated buffer. Specially when user input corrupted or manipulated. Bug: 34469904 Change-Id: Id6196da10111517696eda5f186b1e2dd19f66085 Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit 6ec91040c55fbfdc957950b8b51f88b738a96a1c) --- drivers/net/wireless/bcmdhd_bcm4356/wl_android.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c index 9148ea7883ca..e58496de3b4e 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c @@ -1625,6 +1625,10 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); + if (num_ucipher_suites > MAX_NUM_SUITES) { + DHD_ERROR(("too many UCIPHER suites = %d\n", num_ucipher_suites)); + return -1; + } /* Increment for number of cipher suites field + space */ pcmd += 3; total_len_left -= 3; -- GitLab From 3febd85eda9192e02657e2724b4fcd456a3e4619 Mon Sep 17 00:00:00 2001 From: Joe Maples Date: Mon, 1 May 2017 09:47:29 -0500 Subject: [PATCH 197/528] drivers: wireless: bcm4356: We get it, negative 30 is invalid Stop log spam when return value is -30 Signed-off-by: Joe Maples Signed-off-by: Andrey Cherepkov (cherry picked from commit 7438b4f9f662c5cefd99cd450f4f0650b1b32c8e) --- drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c index b8bfca228627..0cf348324f65 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c @@ -1649,7 +1649,7 @@ wl_host_event_get_data(void *pktdata, uint pktlen, void *evt) int ret; ret = is_wlc_event_frame(pktdata, pktlen, 0, evt); - if (ret != BCME_OK) { + if (ret != BCME_OK && ret != -30) { DHD_ERROR(("%s: Invalid event frame, err = %d\n", __FUNCTION__, ret)); } -- GitLab From 28f3d8894bdb14283fb91036ec8ee695a6fdc890 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Wed, 3 May 2017 16:20:41 -0700 Subject: [PATCH 198/528] drivers: wireless: bcm4356: adding boundary check in wl_cfg80211_mgmt_tx added boundary check for user-input parameter not to corrupt kernel memmory. Bug: 35195787 Change-Id: Ia497feae5f502c9a650e50a39fd0620fa976d908 Signed-off-by: Insun Song Signed-off-by: Joe Maples Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit 41a56a0d5f96c9718e48d0339c2399fa762a3e67) --- drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c index 055358835358..4fa1cd072647 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -6294,7 +6294,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, WL_DBG(("Enter \n")); - if (len > ACTION_FRAME_SIZE) { + if (len > (ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN)) { WL_ERR(("bad length:%zu\n", len)); return BCME_BADLEN; } -- GitLab From 4a6e03ba3b1b876b2ed5c82d3ebcbc0d7eae4cc5 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Fri, 19 May 2017 17:34:10 -0700 Subject: [PATCH 199/528] drivers: wireless: bcm4356: fix RTT report of providing wrong information adding exception handling for RX rate/bitrate translation in RTT report. The missing error check resulted in wrong interpretation and it caused legacy HAL layer crash. Bug:37505450 Change-Id: I088e20d882b76afd8c8ba5db0390de4df57fd7ea Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit 1bd2ba22a9c02ca9bf9e3bb1860fcf56e31312d7) --- drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c | 33 +++++++++++++++---- drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h | 8 +++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c index 21af524e1419..205afce98852 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c @@ -448,7 +448,7 @@ rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) int rate_rspec2rate(uint32 rspec) { - int rate = -1; + int rate = 0; if (RSPEC_ISLEGACY(rspec)) { rate = 500 * (rspec & WL_RSPEC_RATE_MASK); @@ -474,7 +474,7 @@ rate_rspec2rate(uint32 rspec) ASSERT(0); } - return (rate == 0) ? -1 : rate; + return rate; } char resp_buf[WLC_IOCTL_SMLEN]; @@ -1453,17 +1453,38 @@ static wifi_rate_t dhd_rtt_convert_rate_to_host(uint32 rspec) { wifi_rate_t host_rate; - if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { + uint32 bandwidth; + memset(&host_rate, 0, sizeof(wifi_rate_t)); + if (RSPEC_ISLEGACY(rspec)) { host_rate.preamble = 0; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { + } else if (RSPEC_ISHT(rspec)) { host_rate.preamble = 2; host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { + } else if (RSPEC_ISVHT(rspec)) { host_rate.preamble = 3; host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; } - host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1; + + bandwidth = RSPEC_BW(rspec); + switch (bandwidth) { + case WL_RSPEC_BW_20MHZ: + host_rate.bw = RTT_RATE_20M; + break; + case WL_RSPEC_BW_40MHZ: + host_rate.bw = RTT_RATE_40M; + break; + case WL_RSPEC_BW_80MHZ: + host_rate.bw = RTT_RATE_80M; + break; + case WL_RSPEC_BW_160MHZ: + host_rate.bw = RTT_RATE_160M; + break; + default: + host_rate.bw = RTT_RATE_20M; + break; + } + host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); return host_rate; diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h index 308f657391a5..08216dbc8d08 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h @@ -128,6 +128,14 @@ enum { RTT_BW_80 = BIT(4), RTT_BW_160 = BIT(5) }; + +enum rtt_rate_bw { + RTT_RATE_20M, + RTT_RATE_40M, + RTT_RATE_80M, + RTT_RATE_160M +}; + #define FTM_MAX_NUM_BURST_EXP 14 #define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) #define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) -- GitLab From 9c95469fa4141be98f3c59e956e7622a6f5ac57f Mon Sep 17 00:00:00 2001 From: Gautam Date: Fri, 28 Jul 2017 01:32:39 +0200 Subject: [PATCH 200/528] drivers: wireless: bcm4356: Disable debug trace event WLC_E_TRACE [PORT] WLC_E_TRACE event is not required when device goes to suspend. This event is for debugging purpose and can be enabled back using wlutil command. BUG:24270601 Change-Id: Ic28cf5c0f88c831537c5e6c0b6b727c33de281b1 Signed-off-by: Gautam apply to both bcmdhd for kitakami Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit a73698f1ec14644e126ac70eddc570753f16fe16) --- drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c index cb35906c0567..555ce640adf8 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c @@ -6097,7 +6097,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLAIBSS setbit(eventmask, WLC_E_AIBSS_TXFAIL); #endif /* WLAIBSS */ +#ifdef SHOW_LOGTRACE setbit(eventmask, WLC_E_TRACE); +#else + clrbit(eventmask, WLC_E_TRACE); +#endif /* SHOW_LOGTRACE */ setbit(eventmask, WLC_E_CSA_COMPLETE_IND); /* Write updated Event mask */ ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, NULL, 0, TRUE); -- GitLab From 89f56bbe493af2b964f3b7c3d7ec648e7726effa Mon Sep 17 00:00:00 2001 From: Insun Song Date: Wed, 3 Jan 2018 13:57:12 -0800 Subject: [PATCH 201/528] drivers: wireless: bcm4356: fix integer overflow in wl_get_assoc_ies integer overflow case found where signed integer variable converted to unsigned one without proper bounds checking. Then this would result in kernel memory corruption by OOB write. CVE-2017-13292 Bug: 70722061 Change-Id: Idb1aa16ae1bae9c3f601e6688cd263fa95a93bdf Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit be628d76ca067276a797ae49a5ed2548755b1c6b) --- .../net/wireless/bcmdhd_bcm4356/wl_cfg80211.c | 76 ++++++++++++------- .../net/wireless/bcmdhd_bcm4356/wl_cfg80211.h | 6 +- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c index 4fa1cd072647..eb08e1b359d3 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -9398,6 +9398,32 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.req_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.req_len > 0) && + (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0)))) { + err = BCME_BADLEN; + goto exit; + } + if (assoc_info.resp_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.resp_len > 0) && + (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -9406,48 +9432,42 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) conn_info->resp_ie_len = 0; bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); } + if (assoc_info.req_len) { - err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - return err; + goto exit; } - conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); + conn_info->req_ie_len = assoc_info.req_len - + sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - if (conn_info->req_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->req_ie_len, MAX_REQ_LINE)); - return err; - } - } else { - conn_info->req_ie_len = 0; + memcpy(conn_info->req_ie, cfg->extra_buf, + conn_info->req_ie_len); } + if (assoc_info.resp_len) { - err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - return err; - } - conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); - if (conn_info->resp_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->resp_ie_len, MAX_REQ_LINE)); - return err; + goto exit; } - } else { - conn_info->resp_ie_len = 0; + conn_info->resp_ie_len = + assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + memcpy(conn_info->resp_ie, cfg->extra_buf, + conn_info->resp_ie_len); } - WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, - conn_info->resp_ie_len)); +exit: + if (err) { + WL_ERR(("err:%d assoc-req:%u,resp:%u conn-req:%u,resp:%u\n", + err, assoc_info.req_len, assoc_info.resp_len, + conn_info->req_ie_len, conn_info->resp_ie_len)); + } return err; } diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h index 326700e4b5ff..f1dfe77b95ef 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h @@ -373,12 +373,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024 +#define MAX_REQ_LINE 1024u struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - s32 req_ie_len; + u32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - s32 resp_ie_len; + u32 resp_ie_len; }; /* firmware /nvram downloading controller */ -- GitLab From e6c4ddd30d4c476f361fd0a5c1968419b48089ca Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Thu, 9 Nov 2017 22:47:37 +0300 Subject: [PATCH 202/528] drivers/net/wireless: Import BCM43455, version 1.141.67.28 * Sony package version: 32.4.A.1.54 * Required for Sony Xperia Z5 Compact Signed-off-by: Andrey Cherepkov (cherry picked from commit 9e990a9c4b60ab486473362312b8afbd364cd55b) --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/bcmdhd_bcm43455/Kconfig | 85 + drivers/net/wireless/bcmdhd_bcm43455/Makefile | 402 + .../net/wireless/bcmdhd_bcm43455/Makefile.bcm | 361 + .../net/wireless/bcmdhd_bcm43455/Makefile.kk | 308 + .../net/wireless/bcmdhd_bcm43455/Makefile.lp | 352 + .../net/wireless/bcmdhd_bcm43455/aiutils.c | 1004 ++ .../net/wireless/bcmdhd_bcm43455/bcmevent.c | 295 + drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c | 705 + .../wireless/bcmdhd_bcm43455/bcmsdh_linux.c | 466 + .../wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c | 1456 ++ .../bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c | 390 + .../wireless/bcmdhd_bcm43455/bcmsdspi_linux.c | 249 + .../net/wireless/bcmdhd_bcm43455/bcmspibrcm.c | 1810 +++ .../net/wireless/bcmdhd_bcm43455/bcmutils.c | 3092 ++++ .../bcmdhd_bcm43455/bcmwifi_channels.c | 1246 ++ .../bcmdhd_bcm43455/bcmwifi_channels.h | 516 + .../wireless/bcmdhd_bcm43455/bcmwifi_rates.h | 458 + .../net/wireless/bcmdhd_bcm43455/bcmxtlv.c | 410 + drivers/net/wireless/bcmdhd_bcm43455/dhd.h | 1007 ++ .../net/wireless/bcmdhd_bcm43455/dhd_bta.c | 328 + .../net/wireless/bcmdhd_bcm43455/dhd_bta.h | 39 + .../net/wireless/bcmdhd_bcm43455/dhd_bus.h | 158 + .../net/wireless/bcmdhd_bcm43455/dhd_cdc.c | 795 + .../wireless/bcmdhd_bcm43455/dhd_cfg80211.c | 301 + .../wireless/bcmdhd_bcm43455/dhd_cfg80211.h | 59 + .../net/wireless/bcmdhd_bcm43455/dhd_common.c | 2354 +++ .../bcmdhd_bcm43455/dhd_custom_gpio.c | 588 + .../net/wireless/bcmdhd_bcm43455/dhd_dbg.h | 126 + drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c | 953 ++ drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h | 71 + .../net/wireless/bcmdhd_bcm43455/dhd_linux.c | 8412 ++++++++++ .../net/wireless/bcmdhd_bcm43455/dhd_linux.h | 74 + .../bcmdhd_bcm43455/dhd_linux_platdev.c | 760 + .../bcmdhd_bcm43455/dhd_linux_sched.c | 48 + .../wireless/bcmdhd_bcm43455/dhd_linux_wq.c | 316 + .../wireless/bcmdhd_bcm43455/dhd_linux_wq.h | 64 + .../net/wireless/bcmdhd_bcm43455/dhd_pno.c | 4158 +++++ .../net/wireless/bcmdhd_bcm43455/dhd_pno.h | 583 + .../net/wireless/bcmdhd_bcm43455/dhd_proto.h | 115 + .../net/wireless/bcmdhd_bcm43455/dhd_rtt.c | 1906 +++ .../net/wireless/bcmdhd_bcm43455/dhd_rtt.h | 284 + .../net/wireless/bcmdhd_bcm43455/dhd_sdio.c | 8334 ++++++++++ .../bcmdhd_bcm43455/dhd_somc_custom.c | 352 + .../bcmdhd_bcm43455/dhd_somc_custom.h | 18 + .../net/wireless/bcmdhd_bcm43455/dhd_wlfc.c | 4046 +++++ .../net/wireless/bcmdhd_bcm43455/dhd_wlfc.h | 513 + .../net/wireless/bcmdhd_bcm43455/dngl_stats.h | 309 + .../net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h | 40 + drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c | 282 + .../wireless/bcmdhd_bcm43455/include/Makefile | 71 + .../wireless/bcmdhd_bcm43455/include/aidmp.h | 386 + .../bcmdhd_bcm43455/include/bcm_cfg.h | 29 + .../bcmdhd_bcm43455/include/bcm_mpool_pub.h | 361 + .../wireless/bcmdhd_bcm43455/include/bcmcdc.h | 132 + .../bcmdhd_bcm43455/include/bcmdefs.h | 348 + .../bcmdhd_bcm43455/include/bcmdevs.h | 689 + .../bcmdhd_bcm43455/include/bcmendian.h | 329 + .../bcmdhd_bcm43455/include/bcmnvram.h | 272 + .../bcmdhd_bcm43455/include/bcmpcispi.h | 181 + .../bcmdhd_bcm43455/include/bcmperf.h | 36 + .../bcmdhd_bcm43455/include/bcmsdbus.h | 143 + .../wireless/bcmdhd_bcm43455/include/bcmsdh.h | 251 + .../bcmdhd_bcm43455/include/bcmsdh_sdmmc.h | 117 + .../bcmdhd_bcm43455/include/bcmsdpcm.h | 281 + .../bcmdhd_bcm43455/include/bcmsdspi.h | 135 + .../bcmdhd_bcm43455/include/bcmsdstd.h | 282 + .../wireless/bcmdhd_bcm43455/include/bcmspi.h | 40 + .../bcmdhd_bcm43455/include/bcmspibrcm.h | 162 + .../bcmdhd_bcm43455/include/bcmsrom_fmt.h | 633 + .../bcmdhd_bcm43455/include/bcmsrom_tbl.h | 1014 ++ .../bcmdhd_bcm43455/include/bcmutils.h | 1238 ++ .../bcmdhd_bcm43455/include/brcm_nl80211.h | 64 + .../wireless/bcmdhd_bcm43455/include/dbus.h | 582 + .../include/devctrl_if/wlioctl_defs.h | 2030 +++ .../bcmdhd_bcm43455/include/dhdioctl.h | 136 + .../bcmdhd_bcm43455/include/epivers.h | 48 + .../wireless/bcmdhd_bcm43455/include/hndpmu.h | 36 + .../bcmdhd_bcm43455/include/hndrte_armtrap.h | 88 + .../bcmdhd_bcm43455/include/hndrte_cons.h | 69 + .../wireless/bcmdhd_bcm43455/include/hndsoc.h | 282 + .../bcmdhd_bcm43455/include/linux_osl.h | 688 + .../bcmdhd_bcm43455/include/linuxver.h | 748 + .../bcmdhd_bcm43455/include/miniopt.h | 77 + .../bcmdhd_bcm43455/include/msgtrace.h | 77 + .../wireless/bcmdhd_bcm43455/include/osl.h | 142 + .../include/packed_section_end.h | 59 + .../include/packed_section_start.h | 63 + .../wireless/bcmdhd_bcm43455/include/pcicfg.h | 101 + .../bcmdhd_bcm43455/include/proto/802.11.h | 3814 +++++ .../include/proto/802.11_bta.h | 45 + .../bcmdhd_bcm43455/include/proto/802.11e.h | 138 + .../bcmdhd_bcm43455/include/proto/802.1d.h | 50 + .../bcmdhd_bcm43455/include/proto/802.3.h | 52 + .../bcmdhd_bcm43455/include/proto/bcmeth.h | 113 + .../bcmdhd_bcm43455/include/proto/bcmevent.h | 538 + .../bcmdhd_bcm43455/include/proto/bcmip.h | 231 + .../bcmdhd_bcm43455/include/proto/bcmipv6.h | 159 + .../bcmdhd_bcm43455/include/proto/bcmtcp.h | 90 + .../include/proto/bt_amp_hci.h | 441 + .../bcmdhd_bcm43455/include/proto/dnglevent.h | 98 + .../bcmdhd_bcm43455/include/proto/eapol.h | 211 + .../bcmdhd_bcm43455/include/proto/ethernet.h | 220 + .../bcmdhd_bcm43455/include/proto/nan.h | 237 + .../bcmdhd_bcm43455/include/proto/p2p.h | 608 + .../bcmdhd_bcm43455/include/proto/sdspi.h | 75 + .../bcmdhd_bcm43455/include/proto/vlan.h | 95 + .../bcmdhd_bcm43455/include/proto/wpa.h | 214 + .../bcmdhd_bcm43455/include/proto/wps.h | 379 + .../bcmdhd_bcm43455/include/sbchipc.h | 3304 ++++ .../bcmdhd_bcm43455/include/sbconfig.h | 282 + .../bcmdhd_bcm43455/include/sbhnddma.h | 416 + .../bcmdhd_bcm43455/include/sbpcmcia.h | 113 + .../wireless/bcmdhd_bcm43455/include/sbsdio.h | 186 + .../bcmdhd_bcm43455/include/sbsdpcmdev.h | 295 + .../bcmdhd_bcm43455/include/sbsocram.h | 200 + .../wireless/bcmdhd_bcm43455/include/sdio.h | 619 + .../wireless/bcmdhd_bcm43455/include/sdioh.h | 445 + .../bcmdhd_bcm43455/include/sdiovar.h | 58 + .../bcmdhd_bcm43455/include/siutils.h | 440 + .../wireless/bcmdhd_bcm43455/include/spid.h | 165 + .../wireless/bcmdhd_bcm43455/include/trxhdr.h | 92 + .../bcmdhd_bcm43455/include/typedefs.h | 344 + .../bcmdhd_bcm43455/include/wlfc_proto.h | 304 + .../bcmdhd_bcm43455/include/wlioctl.h | 5858 +++++++ .../net/wireless/bcmdhd_bcm43455/linux_osl.c | 1352 ++ .../net/wireless/bcmdhd_bcm43455/sbutils.c | 1063 ++ .../net/wireless/bcmdhd_bcm43455/siutils.c | 2839 ++++ .../wireless/bcmdhd_bcm43455/siutils_priv.h | 272 + .../net/wireless/bcmdhd_bcm43455/uamp_api.h | 176 + .../net/wireless/bcmdhd_bcm43455/wl_android.c | 2340 +++ .../net/wireless/bcmdhd_bcm43455/wl_android.h | 72 + .../wireless/bcmdhd_bcm43455/wl_cfg80211.c | 13198 ++++++++++++++++ .../wireless/bcmdhd_bcm43455/wl_cfg80211.h | 1016 ++ .../wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c | 551 + .../net/wireless/bcmdhd_bcm43455/wl_cfgnan.c | 1856 +++ .../net/wireless/bcmdhd_bcm43455/wl_cfgnan.h | 189 + .../net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c | 2725 ++++ .../net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h | 416 + .../wireless/bcmdhd_bcm43455/wl_cfgvendor.c | 2455 +++ .../wireless/bcmdhd_bcm43455/wl_cfgvendor.h | 359 + drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h | 67 + .../wireless/bcmdhd_bcm43455/wl_linux_mon.c | 403 + .../net/wireless/bcmdhd_bcm43455/wl_roam.c | 304 + .../wireless/bcmdhd_bcm43455/wldev_common.c | 421 + .../wireless/bcmdhd_bcm43455/wldev_common.h | 120 + 147 files changed, 116543 insertions(+) create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/Kconfig create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/Makefile create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/Makefile.bcm create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/Makefile.kk create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/Makefile.lp create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/aiutils.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/Makefile create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/osl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/spid.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/sbutils.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/siutils.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_android.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_android.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index be053439b566..2de6d6bc0f14 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -357,6 +357,7 @@ 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/bcmdhd_bcm43455/Kconfig" source "drivers/net/wireless/bcmdhd_bcm4356/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/ipw2x00/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index d5ddd8daab74..8a5615248bc7 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/ obj-$(CONFIG_SOMC_WIFI_CONTROL) += somcwifictrl/ +obj-$(CONFIG_BCMDHD_BCM43455) += bcmdhd_bcm43455/ obj-$(CONFIG_BCMDHD_BCM4356) += bcmdhd_bcm4356/ obj-$(CONFIG_BRCMFMAC) += brcm80211/ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig new file mode 100644 index 000000000000..37e9a097bd72 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig @@ -0,0 +1,85 @@ +menuconfig BCMDHD_BCM43455 + tristate "Broadcom wireless cards support" + +if BCMDHD_BCM43455 + +config BCMDHD + tristate "Broadcom 43xx wireless cards support" + depends on MMC && CFG80211 + ---help--- + This module adds support for wireless adapters based on + Broadcom 43xx chipset. + This driver uses the kernel's cfg80211 subsystem. + If you choose to build a module, it'll be called dhd. Say M if + unsure. + +choice + prompt "Select Broadcom wireless card" + depends on BCMDHD + default BCM43455 + +config BCM4339 + bool "Broadcom 4339 wireless card support" + depends on BCMDHD + ---help--- + This module adds support for wireless adapters based on + Broadcom 4339 chipset. + +config BCM4354 + bool "Broadcom 4354 wireless card support" + depends on BCMDHD + ---help--- + This module adds support for wireless adapters based on + Broadcom 4354 chipset. + +config BCM43455 + bool "Broadcom 43455 wireless cards support" + depends on BCMDHD + ---help--- + This module adds support for wireless adapters based on + Broadcom 43455 chipset. + +endchoice + +config BCMDHD_FW_PATH + depends on BCMDHD + string "Firmware path" + default "/system/etc/firmware/fw_bcmdhd.bin" + ---help--- + Path to the firmware file. + +config BCMDHD_NVRAM_PATH + depends on BCMDHD + string "NVRAM path" + default "/system/etc/wifi/bcmdhd.cal" + ---help--- + Path to the calibration file. + +config DHD_USE_STATIC_BUF + bool "Enable memory preallocation" + depends on BCMDHD + default n + ---help--- + Use memory preallocated in platform + +config BCMDHD_HW_OOB + depends on BCMDHD + bool "Use H/W OOB to the Host Wakeup" + default y + ---help--- + Use H/W OOB to the Host Wakeup + +config DHD_USE_SCHED_SCAN + bool "Use CFG80211 sched scan" + depends on BCMDHD && CFG80211 + default n + ---help--- + Use CFG80211 sched scan + +config BROADCOM_WIFI_RESERVED_MEM + bool "BROADCOM Reserved memory for wifi device" + depends on BCMDHD + ---help--- + This is a configuration for broadcom WLAN driver. + +endif diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Makefile b/drivers/net/wireless/bcmdhd_bcm43455/Makefile new file mode 100644 index 000000000000..7470e87cd211 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile @@ -0,0 +1,402 @@ +# bcmdhd + +##################### +# SDIO Basic feature +##################### +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ + -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ + -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ + -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ + -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ + -DCONFIG_DTS + +#################### +# Common feature +#################### +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 +# For Kernel ver > 3.6 or Kernel Patch required +DHDCFLAGS += -DWL_SUPPORT_CHAN_BW + +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# DPC priority +#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# idle count +DHDCFLAGS += -DDHD_USE_IDLECOUNT + +# custom specific value define +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# set keep alive period +ifneq ($(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING),) +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=$(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING) +else +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 +endif +# set roam setting values +DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 +DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +# SKB TAILPAD to avoid out of boundary memory access +DHDCFLAGS += -DDHDENABLE_TAILPAD + +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS + +DHDCFLAGS += -DSUPPORT_P2P_GO_PS + +# Disable TXBF sending +DHDCFLAGS += -DDISABLE_TXBFR + +DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + +# Disable to delay link down event +DHDCFLAGS += -DDISABLE_BCN_DLY + +############################## +# Android Platform Definition +############################## +BCM_SRC_DIR := ./ + +########### +# Lollipop +########### +DHDCFLAGS += -DWL_ENABLE_P2P_IF +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS +# To support p2p private command on kernel 3.8 or above +DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT + +ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD +endif + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +ifneq ($(CONFIG_BCM4339),) +# To support GSCAN +#DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o +endif + +ifneq ($(CONFIG_BCM43455),) +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o +endif + +ifneq ($(CONFIG_BCM4354),) +# To support RTT +DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +#DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o +endif + + +######################### +# Chip dependent feature +######################### +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DSDIO_CRC_ERROR_FIX + +# tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DREPEAT_READFRAME + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +# DRIVER_TYPE = y +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # for 4339 only currently - need test for 4354, 43455 + DHDCFLAGS += -DDHD_LOSSLESS_ROAMING + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM43455),) + DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM43455),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + + # Radio_stat v2 - data structure is updated + DHDCFLAGS += -DLINKSTAT_V2 + +# DHDCFLAGS += -DWL_ABORT_SCAN +endif + +# Read custom mac address function +DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE + +# Default Beacon timeout +ifneq ($(CONFIG_SOMC_WLAN_BCN_TIMEOUT),) + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=$(CONFIG_SOMC_WLAN_BCN_TIMEOUT) +else + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=3 +endif + +# The number of the maximum devices which phone can associate +DHDCFLAGS += -DSOMC_MAX_ASSOC_NUM=10 + +# Default Listen Interval in Beacons +ifneq ($(CONFIG_SOMC_WLAN_LISTEN_INTERVAL),) + DHDCFLAGS += -DCUSTOM_LISTEN_INTERVAL=$(CONFIG_SOMC_WLAN_LISTEN_INTERVAL) +endif + +# WAPI +DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI + +# Set the number of probe requests per channel +ifneq ($(CONFIG_SOMC_WLAN_SCAN_NPROBES),) + DHDCFLAGS += -DSOMC_WLAN_SCAN_NPROBES=$(CONFIG_SOMC_WLAN_SCAN_NPROBES) +endif + +# Set default nvram path +ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) + DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" +endif + +# Change scan time +ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) + DHDCFLAGS += -DCHANGE_SCAN_TIME +endif + +#EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +MODNAME := wlan + +DHDOFILES := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o \ + dhd_linux_wq.o aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o \ + hndpmu.o linux_osl.o sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o \ + dhd_somc_custom.o + +DHDOFILES += $(ANDROID_OFILES) + +# Module information used by KBuild framework +obj-$(CONFIG_BCMDHD_BCM43455) += $(MODNAME).o + +$(MODNAME)-objs := $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Makefile.bcm b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.bcm new file mode 100644 index 000000000000..92de6bba75b4 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.bcm @@ -0,0 +1,361 @@ +# bcmdhd + +##################### +# SDIO Basic feature +##################### +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ + -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ + -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ + -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ + -DEMBEDDED_PLATFORM -DPNO_SUPPORT + +#################### +# Common feature +#################### +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 + +# For Kernel ver > 3.6 or Kernel Patch required +DHDCFLAGS += -DWL_SUPPORT_CHAN_BW + +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# DPC priority +#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# idle count +DHDCFLAGS += -DDHD_USE_IDLECOUNT + +# custom specific value define +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# set keep alive period +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 +# set roam setting values +DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 +DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +# SKB TAILPAD to avoid out of boundary memory access +DHDCFLAGS += -DDHDENABLE_TAILPAD + +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS + +DHDCFLAGS += -DSUPPORT_P2P_GO_PS + +# Disable TXBF sending +DHDCFLAGS += -DDISABLE_TXBFR + +DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + + +############################## +# Android Platform Definition +############################## + +############################### +# Android M +############################### +DHDCFLAGS += -DWL_ENABLE_P2P_IF + +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS +# To support p2p private command on kernel 3.8 or above +DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +ifneq ($(CONFIG_BCM4339),) +# To support GSCAN +#DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o +endif + +ifneq ($(CONFIG_BCM43455),) +# To support RTT +DHDCFLAGS += -DRTT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT +# To support ePNO +DHDCFLAGS += -DEPNO_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support Rssi Monitor +DHDCFLAGS += -DRSSI_MONITOR_SUPPORT +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT +# To support ANQPO - GSCAN must be supported +DHDCFLAGS += -DANQPO_SUPPORT + + + +# Extra file list for Android M, SOMC +ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o bcmxtlv.o +endif + +ifneq ($(CONFIG_BCM4354),) +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Android M +ANDROID_OFILES := wl_cfgvendor.o +endif + + + + +######################### +# Chip dependent feature +######################### +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DSDIO_CRC_ERROR_FIX + +# tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DREPEAT_READFRAME + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +# DRIVER_TYPE = y +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # for 4339 only currently - need test for 4354, 43455 + DHDCFLAGS += -DDHD_LOSSLESS_ROAMING + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM43455),) + DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM43455),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + + # Radio_stat v2 - data structure is updated + DHDCFLAGS += -DLINKSTAT_V2 + +# DHDCFLAGS += -DWL_ABORT_SCAN +endif + +#EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o dhd_linux_wq.o aiutils.o \ + bcmevent.o bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o \ + sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o wl_android.o wl_cfg80211.o \ + wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o + +DHDOFILES += $(ANDROID_OFILES) + +obj-$(CONFIG_BCMDHD) += bcmdhd.o +bcmdhd-objs += $(DHDOFILES) + diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Makefile.kk b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.kk new file mode 100644 index 000000000000..a90c3ebe0938 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.kk @@ -0,0 +1,308 @@ +# bcmdhd + +##################### +# SDIO Basic feature +##################### +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ + -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ + -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ + -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ + -DEMBEDDED_PLATFORM -DPNO_SUPPORT + +#################### +# Common feature +#################### +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 + +# For Kernel ver > 3.6 or Kernel Patch required +DHDCFLAGS += -DWL_SUPPORT_CHAN_BW + +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# DPC priority +#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# idle count +DHDCFLAGS += -DDHD_USE_IDLECOUNT + +# custom specific value define +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# set keep alive period +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 +# set roam setting values +DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 +DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +# SKB TAILPAD to avoid out of boundary memory access +DHDCFLAGS += -DDHDENABLE_TAILPAD + +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS + +DHDCFLAGS += -DSUPPORT_P2P_GO_PS + +# Disable TXBF sending +DHDCFLAGS += -DDISABLE_TXBFR + +DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + + +############################## +# Android Platform Definition +############################## + +## Andrioid KitKat ## + +DHDCFLAGS += -DWL_ENABLE_P2P_IF +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS +# To support p2p private command on kernel 3.8 or above +DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT + + + + +######################### +# Chip dependent feature +######################### +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DSDIO_CRC_ERROR_FIX + +# tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DREPEAT_READFRAME + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +# DRIVER_TYPE = y +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # for 4339 only currently - need test for 4354, 43455 + DHDCFLAGS += -DDHD_LOSSLESS_ROAMING + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM43455),) + DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM43455),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + + # Radio_stat v2 - data structure is updated + DHDCFLAGS += -DLINKSTAT_V2 + +# DHDCFLAGS += -DWL_ABORT_SCAN +endif + +#EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o dhd_linux_wq.o aiutils.o \ + bcmevent.o bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o \ + sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o wl_android.o wl_cfg80211.o \ + wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o + +DHDOFILES += $(ANDROID_OFILES) + +obj-$(CONFIG_BCMDHD) += bcmdhd.o +bcmdhd-objs += $(DHDOFILES) + diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Makefile.lp b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.lp new file mode 100644 index 000000000000..8e9ef4d2d1f4 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.lp @@ -0,0 +1,352 @@ +# bcmdhd + +##################### +# SDIO Basic feature +##################### +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ + -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ + -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ + -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ + -DEMBEDDED_PLATFORM -DPNO_SUPPORT + +#################### +# Common feature +#################### +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 + +# For Kernel ver > 3.6 or Kernel Patch required +DHDCFLAGS += -DWL_SUPPORT_CHAN_BW + +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# DPC priority +#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# idle count +DHDCFLAGS += -DDHD_USE_IDLECOUNT + +# custom specific value define +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# set keep alive period +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 +# set roam setting values +DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 +DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +# SKB TAILPAD to avoid out of boundary memory access +DHDCFLAGS += -DDHDENABLE_TAILPAD + +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS + +DHDCFLAGS += -DSUPPORT_P2P_GO_PS + +# Disable TXBF sending +DHDCFLAGS += -DDISABLE_TXBFR + +DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + + +############################## +# Android Platform Definition +############################## + +########### +# Lollipop +########### +DHDCFLAGS += -DWL_ENABLE_P2P_IF +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS +# To support p2p private command on kernel 3.8 or above +DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +ifneq ($(CONFIG_BCM4339),) +# To support GSCAN +#DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o +endif + +ifneq ($(CONFIG_BCM43455),) +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o +endif + +ifneq ($(CONFIG_BCM4354),) +# To support RTT +DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +#DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o +endif + + + + +######################### +# Chip dependent feature +######################### +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DSDIO_CRC_ERROR_FIX + +# tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DREPEAT_READFRAME + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +# DRIVER_TYPE = y +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # for 4339 only currently - need test for 4354, 43455 + DHDCFLAGS += -DDHD_LOSSLESS_ROAMING + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM43455),) + DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM43455),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + + # Radio_stat v2 - data structure is updated + DHDCFLAGS += -DLINKSTAT_V2 + +# DHDCFLAGS += -DWL_ABORT_SCAN +endif + +#EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o dhd_linux_wq.o aiutils.o \ + bcmevent.o bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o \ + sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o wl_android.o wl_cfg80211.o \ + wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o + +DHDOFILES += $(ANDROID_OFILES) + +obj-$(CONFIG_BCMDHD) += bcmdhd.o +bcmdhd-objs += $(DHDOFILES) + diff --git a/drivers/net/wireless/bcmdhd_bcm43455/aiutils.c b/drivers/net/wireless/bcmdhd_bcm43455/aiutils.c new file mode 100644 index 000000000000..54a0376747c5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/aiutils.c @@ -0,0 +1,1004 @@ +/* + * Misc utility routines for accessing chip-specific features + * of the SiliconBackplane-based Broadcom chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: aiutils.c 432226 2013-10-26 04:34:36Z $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "siutils_priv.h" + +#define BCM47162_DMP() (0) +#define BCM5357_DMP() (0) +#define BCM4707_DMP() (0) +#define remap_coreid(sih, coreid) (coreid) +#define remap_corerev(sih, corerev) (corerev) + +/* EROM parsing */ + +static uint32 +get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) +{ + uint32 ent; + uint inv = 0, nom = 0; + + while (TRUE) { + ent = R_REG(si_osh(sih), *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++; + } + + SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); + if (inv + nom) { + SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); + } + return ent; +} + +static uint32 +get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, + uint32 *sizel, uint32 *sizeh) +{ + uint32 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); + + SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", + sp, ad, st, *sizeh, *sizel, *addrh, *addrl)); + + return asd; +} + +static void +ai_hwfixup(si_info_t *sii) +{ +} + + +/* parse the enumeration rom to identify all cores */ +void +ai_scan(si_t *sih, void *regs, uint devid) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + chipcregs_t *cc = (chipcregs_t *)regs; + uint32 erombase, *eromptr, *eromlim; + + erombase = R_REG(sii->osh, &cc->eromptr); + + switch (BUSTYPE(sih->bustype)) { + case SI_BUS: + eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); + break; + + case PCI_BUS: + /* Set wrappers address */ + sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); + + /* Now point the window at the erom */ + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); + eromptr = regs; + break; + + case SPI_BUS: + case SDIO_BUS: + eromptr = (uint32 *)(uintptr)erombase; + break; + + case PCMCIA_BUS: + default: + SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype)); + ASSERT(0); + return; + } + eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); + + SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", + regs, erombase, eromptr, eromlim)); + while (eromptr < eromlim) { + uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; + uint32 mpd, asd, addrl, addrh, sizel, sizeh; + 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)) { + SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); + ai_hwfixup(sii); + return; + } + + cib = get_erom_ent(sih, &eromptr, 0, 0); + + if ((cib & ER_TAG) != ER_CI) { + SI_ERROR(("CIA not followed by CIB\n")); + 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; + +#ifdef BCMDBG_SI + SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " + "nsw = %d, nmp = %d & nsp = %d\n", + mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp)); +#else + BCM_REFERENCE(crev); +#endif + + 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; + } + } + if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID) + continue; + } + + idx = sii->numcores; + + cores_info->cia[idx] = cia; + cores_info->cib[idx] = cib; + cores_info->coreid[idx] = remap_coreid(sih, cid); + + for (i = 0; i < nmp; i++) { + mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); + if ((mpd & ER_TAG) != ER_MP) { + SI_ERROR(("Not enough MP entries for component 0x%x\n", cid)); + goto error; + } + SI_VMSG((" Master port %d, mp: %d id: %d\n", i, + (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, + (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); + } + + /* 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) { + do { + /* 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 (br == TRUE) { + break; + } + else if ((addrh != 0) || (sizeh != 0) || + (sizel != SI_CORE_SIZE)) { + SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 =" + "0x%x\n", addrh, sizeh, sizel)); + SI_ERROR(("First Slave ASD for" + "core 0x%04x malformed " + "(0x%08x)\n", cid, asd)); + goto error; + } + } + } while (1); + } + cores_info->coresba[idx] = addrl; + cores_info->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)) { + cores_info->coresba2[idx] = addrl; + cores_info->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); + + if (asd == 0) + break; + j++; + } while (1); + if (j == 0) { + SI_ERROR((" SP %d has no address descriptors\n", i)); + 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) { + SI_ERROR(("Missing descriptor for MW %d\n", i)); + goto error; + } + if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { + SI_ERROR(("Master wrapper %d is not 4KB\n", i)); + goto error; + } + if (i == 0) + cores_info->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) { + SI_ERROR(("Missing descriptor for SW %d\n", i)); + goto error; + } + if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { + SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); + goto error; + } + if ((nmw == 0) && (i == 0)) + cores_info->wrapba[idx] = addrl; + } + + + /* Don't record bridges */ + if (br) + continue; + + /* Done with core */ + sii->numcores++; + } + + SI_ERROR(("Reached end of erom without finding END")); + +error: + sii->numcores = 0; + return; +} + +/* This function changes the logical "focus" to the indicated core. + * Return the current core's virtual address. + */ +void * +ai_setcoreidx(si_t *sih, uint coreidx) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint32 addr, wrap; + void *regs; + + if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) + return (NULL); + + addr = cores_info->coresba[coreidx]; + wrap = cores_info->wrapba[coreidx]; + + /* + * If the user has provided an interrupt mask enabled function, + * then assert interrupts are disabled before switching the core. + */ + ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); + + switch (BUSTYPE(sih->bustype)) { + case SI_BUS: + /* map new one */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + sii->curmap = regs = cores_info->regs[coreidx]; + if (!cores_info->wrappers[coreidx] && (wrap != 0)) { + cores_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->wrappers[coreidx])); + } + sii->curwrap = cores_info->wrappers[coreidx]; + break; + + case PCI_BUS: + /* point bar0 window */ + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); + regs = sii->curmap; + /* point bar0 2nd 4KB window to the primary wrapper */ + if (PCIE_GEN2(sii)) + OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap); + else + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); + break; + + case SPI_BUS: + case SDIO_BUS: + sii->curmap = regs = (void *)((uintptr)addr); + sii->curwrap = (void *)((uintptr)wrap); + break; + + case PCMCIA_BUS: + default: + ASSERT(0); + regs = NULL; + break; + } + + sii->curmap = regs; + sii->curidx = coreidx; + + return regs; +} + + +void +ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + chipcregs_t *cc = NULL; + uint32 erombase, *eromptr, *eromlim; + uint i, j, cidx; + uint32 cia, cib, nmp, nsp; + uint32 asd, addrl, addrh, sizel, sizeh; + + for (i = 0; i < sii->numcores; i++) { + if (cores_info->coreid[i] == CC_CORE_ID) { + cc = (chipcregs_t *)cores_info->regs[i]; + break; + } + } + if (cc == NULL) + goto error; + + erombase = R_REG(sii->osh, &cc->eromptr); + eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); + eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); + + cidx = sii->curidx; + cia = cores_info->cia[cidx]; + cib = cores_info->cib[cidx]; + + nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; + nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; + + /* scan for cores */ + while (eromptr < eromlim) { + if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && + (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { + break; + } + } + + /* skip master ports */ + for (i = 0; i < nmp; i++) + get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); + + /* Skip ASDs in port 0 */ + 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); + } + + j = 1; + do { + asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, + &sizel, &sizeh); + 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); + if (asd == 0) + break; + + if (!asidx--) { + *addr = addrl; + *size = sizel; + return; + } + j++; + } while (1); + + if (j == 0) { + SI_ERROR((" SP %d has no address descriptors\n", i)); + break; + } + } + +error: + *size = 0; + return; +} + +/* Return the number of address spaces in current core */ +int +ai_numaddrspaces(si_t *sih) +{ + return 2; +} + +/* Return the address of the nth address space in the current core */ +uint32 +ai_addrspace(si_t *sih, uint asidx) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint cidx; + + cidx = sii->curidx; + + if (asidx == 0) + return cores_info->coresba[cidx]; + else if (asidx == 1) + return cores_info->coresba2[cidx]; + else { + SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", + __FUNCTION__, asidx)); + return 0; + } +} + +/* Return the size of the nth address space in the current core */ +uint32 +ai_addrspacesize(si_t *sih, uint asidx) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint cidx; + + cidx = sii->curidx; + + if (asidx == 0) + return cores_info->coresba_size[cidx]; + else if (asidx == 1) + return cores_info->coresba2_size[cidx]; + else { + SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", + __FUNCTION__, asidx)); + return 0; + } +} + +uint +ai_flag(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); + return sii->curidx; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); + return sii->curidx; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", + __FUNCTION__)); + return sii->curidx; + } + ai = sii->curwrap; + + return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); +} + +uint +ai_flag_alt(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); + return sii->curidx; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); + return sii->curidx; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", + __FUNCTION__)); + return sii->curidx; + } + ai = sii->curwrap; + + return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK); +} + +void +ai_setint(si_t *sih, int siflag) +{ +} + +uint +ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + uint32 *map = (uint32 *) sii->curwrap; + + if (mask || val) { + uint32 w = R_REG(sii->osh, map+(offset/4)); + w &= ~mask; + w |= val; + W_REG(sii->osh, map+(offset/4), w); + } + + return (R_REG(sii->osh, map+(offset/4))); +} + +uint +ai_corevendor(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint32 cia; + + cia = cores_info->cia[sii->curidx]; + return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); +} + +uint +ai_corerev(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint32 cib; + + + cib = cores_info->cib[sii->curidx]; + return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); +} + +bool +ai_iscoreup(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + + ai = sii->curwrap; + + return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && + ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); +} + +/* + * 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(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) +{ + uint origidx = 0; + uint32 *r = NULL; + uint w; + uint intr_val = 0; + bool fast = FALSE; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + + ASSERT(GOODIDX(coreidx)); + ASSERT(regoff < SI_CORE_SIZE); + ASSERT((val & ~mask) == 0); + + if (coreidx >= SI_MAXCORES) + return 0; + + if (BUSTYPE(sih->bustype) == SI_BUS) { + /* If internal bus, we can always get at everything */ + fast = TRUE; + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + } else if (BUSTYPE(sih->bustype) == PCI_BUS) { + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + + fast = TRUE; + r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (uint32 *)((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 = si_coreidx(&sii->pub); + + /* switch core */ + r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); + } + ASSERT(r != NULL); + + /* mask and set */ + if (mask || val) { + w = (R_REG(sii->osh, r) & ~mask) | val; + W_REG(sii->osh, r, w); + } + + /* readback */ + w = R_REG(sii->osh, r); + + if (!fast) { + /* restore core index */ + if (origidx != coreidx) + ai_setcoreidx(&sii->pub, origidx); + + INTR_RESTORE(sii, intr_val); + } + + return (w); +} + +/* + * If there is no need for fiddling with interrupts or core switches (typically silicon + * back plane registers, pci registers and chipcommon registers), this function + * returns the register offset on this core to a mapped address. This address can + * be used for W_REG/R_REG directly. + * + * For accessing registers that would need a core switch, this function will return + * NULL. + */ +uint32 * +ai_corereg_addr(si_t *sih, uint coreidx, uint regoff) +{ + uint32 *r = NULL; + bool fast = FALSE; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + + ASSERT(GOODIDX(coreidx)); + ASSERT(regoff < SI_CORE_SIZE); + + if (coreidx >= SI_MAXCORES) + return 0; + + if (BUSTYPE(sih->bustype) == SI_BUS) { + /* If internal bus, we can always get at everything */ + fast = TRUE; + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + } else if (BUSTYPE(sih->bustype) == PCI_BUS) { + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + + fast = TRUE; + r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (uint32 *)((char *)sii->curmap + + ((regoff >= SBCONFIGOFF) ? + PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + + regoff); + } + } + + if (!fast) + return 0; + + return (r); +} + +void +ai_core_disable(si_t *sih, uint32 bits) +{ + si_info_t *sii = SI_INFO(sih); + volatile uint32 dummy; + uint32 status; + aidmp_t *ai; + + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + /* if core is already in reset, just return */ + if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) + return; + + /* ensure there are no pending backplane operations */ + SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + /* if pending backplane ops still, try waiting longer */ + if (status != 0) { + /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ + /* during driver load we may need more time */ + SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); + /* if still pending ops, continue on and try disable anyway */ + /* this is in big hammer path, so don't call wl_reinit in this case... */ + } + + W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); + dummy = R_REG(sii->osh, &ai->resetctrl); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + + W_REG(sii->osh, &ai->ioctrl, bits); + dummy = R_REG(sii->osh, &ai->ioctrl); + BCM_REFERENCE(dummy); + OSL_DELAY(10); +} + +/* 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(si_t *sih, uint32 bits, uint32 resetbits) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + volatile uint32 dummy; + uint loop_counter = 10; + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + /* ensure there are no pending backplane operations */ + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + + /* put core into reset state */ + W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); + OSL_DELAY(10); + + /* ensure there are no pending backplane operations */ + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); + + W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN)); + dummy = R_REG(sii->osh, &ai->ioctrl); + BCM_REFERENCE(dummy); + + /* ensure there are no pending backplane operations */ + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + + while (R_REG(sii->osh, &ai->resetctrl) != 0 && --loop_counter != 0) { + /* ensure there are no pending backplane operations */ + SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); + + + /* take core out of reset */ + W_REG(sii->osh, &ai->resetctrl, 0); + + /* ensure there are no pending backplane operations */ + SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); + } + + + W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); + dummy = R_REG(sii->osh, &ai->ioctrl); + BCM_REFERENCE(dummy); + OSL_DELAY(1); +} + +void +ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + uint32 w; + + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", + __FUNCTION__)); + return; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", + __FUNCTION__)); + return; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", + __FUNCTION__)); + return; + } + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + ASSERT((val & ~mask) == 0); + + if (mask || val) { + w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); + W_REG(sii->osh, &ai->ioctrl, w); + } +} + +uint32 +ai_core_cflags(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + uint32 w; + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", + __FUNCTION__)); + return 0; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", + __FUNCTION__)); + return 0; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", + __FUNCTION__)); + return 0; + } + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + ASSERT((val & ~mask) == 0); + + if (mask || val) { + w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); + W_REG(sii->osh, &ai->ioctrl, w); + } + + return R_REG(sii->osh, &ai->ioctrl); +} + +uint32 +ai_core_sflags(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + aidmp_t *ai; + uint32 w; + + if (BCM47162_DMP()) { + SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", + __FUNCTION__)); + return 0; + } + if (BCM5357_DMP()) { + SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", + __FUNCTION__)); + return 0; + } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", + __FUNCTION__)); + return 0; + } + + ASSERT(GOODREGS(sii->curwrap)); + ai = sii->curwrap; + + ASSERT((val & ~mask) == 0); + ASSERT((mask & ~SISF_CORE_BITS) == 0); + + if (mask || val) { + w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); + W_REG(sii->osh, &ai->iostatus, w); + } + + return R_REG(sii->osh, &ai->iostatus); +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c new file mode 100644 index 000000000000..aefbd763ece1 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c @@ -0,0 +1,295 @@ +/* + * bcmevent read-only data shared by kernel or app layers + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: bcmevent.c 696097 2017-04-25 09:26:01Z $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Use the actual name for event tracing */ +#define BCMEVENT_NAME(_event) {(_event), #_event} + +const bcmevent_name_t bcmevent_names[] = { + BCMEVENT_NAME(WLC_E_SET_SSID), + BCMEVENT_NAME(WLC_E_JOIN), + BCMEVENT_NAME(WLC_E_START), + BCMEVENT_NAME(WLC_E_AUTH), + BCMEVENT_NAME(WLC_E_AUTH_IND), + BCMEVENT_NAME(WLC_E_DEAUTH), + BCMEVENT_NAME(WLC_E_DEAUTH_IND), + BCMEVENT_NAME(WLC_E_ASSOC), + BCMEVENT_NAME(WLC_E_ASSOC_IND), + BCMEVENT_NAME(WLC_E_REASSOC), + BCMEVENT_NAME(WLC_E_REASSOC_IND), + BCMEVENT_NAME(WLC_E_DISASSOC), + BCMEVENT_NAME(WLC_E_DISASSOC_IND), + BCMEVENT_NAME(WLC_E_QUIET_START), + BCMEVENT_NAME(WLC_E_QUIET_END), + BCMEVENT_NAME(WLC_E_BEACON_RX), + BCMEVENT_NAME(WLC_E_LINK), + BCMEVENT_NAME(WLC_E_MIC_ERROR), + BCMEVENT_NAME(WLC_E_NDIS_LINK), + BCMEVENT_NAME(WLC_E_ROAM), + BCMEVENT_NAME(WLC_E_TXFAIL), + BCMEVENT_NAME(WLC_E_PMKID_CACHE), + BCMEVENT_NAME(WLC_E_RETROGRADE_TSF), + BCMEVENT_NAME(WLC_E_PRUNE), + BCMEVENT_NAME(WLC_E_AUTOAUTH), + BCMEVENT_NAME(WLC_E_EAPOL_MSG), + BCMEVENT_NAME(WLC_E_SCAN_COMPLETE), + BCMEVENT_NAME(WLC_E_ADDTS_IND), + BCMEVENT_NAME(WLC_E_DELTS_IND), + BCMEVENT_NAME(WLC_E_BCNSENT_IND), + BCMEVENT_NAME(WLC_E_BCNRX_MSG), + BCMEVENT_NAME(WLC_E_BCNLOST_MSG), + BCMEVENT_NAME(WLC_E_ROAM_PREP), + BCMEVENT_NAME(WLC_E_PFN_NET_FOUND), + BCMEVENT_NAME(WLC_E_PFN_NET_LOST), +#if defined(IBSS_PEER_DISCOVERY_EVENT) + BCMEVENT_NAME(WLC_E_IBSS_ASSOC), +#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */ + BCMEVENT_NAME(WLC_E_RADIO), + BCMEVENT_NAME(WLC_E_PSM_WATCHDOG), + BCMEVENT_NAME(WLC_E_PROBREQ_MSG), + BCMEVENT_NAME(WLC_E_SCAN_CONFIRM_IND), + BCMEVENT_NAME(WLC_E_PSK_SUP), + BCMEVENT_NAME(WLC_E_COUNTRY_CODE_CHANGED), + BCMEVENT_NAME(WLC_E_EXCEEDED_MEDIUM_TIME), + BCMEVENT_NAME(WLC_E_ICV_ERROR), + BCMEVENT_NAME(WLC_E_UNICAST_DECODE_ERROR), + BCMEVENT_NAME(WLC_E_MULTICAST_DECODE_ERROR), + BCMEVENT_NAME(WLC_E_TRACE), + BCMEVENT_NAME(WLC_E_IF), +#ifdef WLP2P + BCMEVENT_NAME(WLC_E_P2P_DISC_LISTEN_COMPLETE), +#endif + BCMEVENT_NAME(WLC_E_RSSI), + BCMEVENT_NAME(WLC_E_PFN_SCAN_COMPLETE), + BCMEVENT_NAME(WLC_E_EXTLOG_MSG), +#ifdef WIFI_ACT_FRAME + BCMEVENT_NAME(WLC_E_ACTION_FRAME), + BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX), + BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE), +#endif +#ifdef BCMWAPI_WAI + BCMEVENT_NAME(WLC_E_WAI_STA_EVENT), + BCMEVENT_NAME(WLC_E_WAI_MSG), +#endif /* BCMWAPI_WAI */ + BCMEVENT_NAME(WLC_E_ESCAN_RESULT), + BCMEVENT_NAME(WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE), +#ifdef WLP2P + BCMEVENT_NAME(WLC_E_PROBRESP_MSG), + BCMEVENT_NAME(WLC_E_P2P_PROBREQ_MSG), +#endif +#ifdef PROP_TXSTATUS + BCMEVENT_NAME(WLC_E_FIFO_CREDIT_MAP), +#endif + BCMEVENT_NAME(WLC_E_WAKE_EVENT), + BCMEVENT_NAME(WLC_E_DCS_REQUEST), + BCMEVENT_NAME(WLC_E_RM_COMPLETE), +#ifdef WLMEDIA_HTSF + BCMEVENT_NAME(WLC_E_HTSFSYNC), +#endif + BCMEVENT_NAME(WLC_E_OVERLAY_REQ), + BCMEVENT_NAME(WLC_E_CSA_COMPLETE_IND), + BCMEVENT_NAME(WLC_E_EXCESS_PM_WAKE_EVENT), + BCMEVENT_NAME(WLC_E_PFN_SCAN_NONE), + BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE), +#ifdef SOFTAP + BCMEVENT_NAME(WLC_E_GTK_PLUMBED), +#endif + BCMEVENT_NAME(WLC_E_ASSOC_REQ_IE), + BCMEVENT_NAME(WLC_E_ASSOC_RESP_IE), + BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX_NDIS), + BCMEVENT_NAME(WLC_E_BEACON_FRAME_RX), +#ifdef WLTDLS + BCMEVENT_NAME(WLC_E_TDLS_PEER_EVENT), +#endif /* WLTDLS */ + BCMEVENT_NAME(WLC_E_NATIVE), +#ifdef WLPKTDLYSTAT + BCMEVENT_NAME(WLC_E_PKTDELAY_IND), +#endif /* WLPKTDLYSTAT */ + BCMEVENT_NAME(WLC_E_SERVICE_FOUND), + BCMEVENT_NAME(WLC_E_GAS_FRAGMENT_RX), + BCMEVENT_NAME(WLC_E_GAS_COMPLETE), + BCMEVENT_NAME(WLC_E_P2PO_ADD_DEVICE), + BCMEVENT_NAME(WLC_E_P2PO_DEL_DEVICE), +#ifdef WLWNM + BCMEVENT_NAME(WLC_E_WNM_STA_SLEEP), +#endif /* WLWNM */ +#if defined(WL_PROXDETECT) + BCMEVENT_NAME(WLC_E_PROXD), +#endif + BCMEVENT_NAME(WLC_E_CCA_CHAN_QUAL), + BCMEVENT_NAME(WLC_E_BSSID), +#ifdef PROP_TXSTATUS + BCMEVENT_NAME(WLC_E_BCMC_CREDIT_SUPPORT), +#endif + BCMEVENT_NAME(WLC_E_TXFAIL_THRESH), +#ifdef GSCAN_SUPPORT + BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT), + BCMEVENT_NAME(WLC_E_PFN_SWC), +#endif /* GSCAN_SUPPORT */ + BCMEVENT_NAME(WLC_E_RMC_EVENT), +#ifdef GSCAN_SUPPORT + BCMEVENT_NAME(WLC_E_PFN_SSID_EXT), +#endif /* GSCAN_SUPPORT */ +}; + +const int bcmevent_names_size = ARRAYSIZE(bcmevent_names); + +/* + * Validate if the event is proper and if valid copy event header to event. + * If proper event pointer is passed, to just validate, pass NULL to event. + * + * Return values are + * BCME_OK - It is a BRCM event or BRCM dongle event + * BCME_NOTFOUND - Not BRCM, not an event, may be okay + * BCME_BADLEN - Bad length, should not process, just drop + */ +int +is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, + bcm_event_msg_u_t *out_event) +{ + uint16 evlen = 0; /* length in bcmeth_hdr */ + uint16 subtype; + uint16 usr_subtype; + bcm_event_t *bcm_event; + uint8 *pktend; + uint8 *evend; + int err = BCME_OK; + uint32 data_len = 0; /* data length in bcm_event */ + + pktend = (uint8 *)pktdata + pktlen; + bcm_event = (bcm_event_t *)pktdata; + + /* only care about 16-bit subtype / length versions */ + if ((uint8 *)&bcm_event->bcm_hdr < pktend) { + uint8 short_subtype = *(uint8 *)&bcm_event->bcm_hdr; + if (!(short_subtype & 0x80)) { + err = BCME_NOTFOUND; + goto done; + } + } + + /* must have both ether_header and bcmeth_hdr */ + if (pktlen < OFFSETOF(bcm_event_t, event)) { + err = BCME_BADLEN; + goto done; + } + + /* check length in bcmeth_hdr */ + + /* temporary - header length not always set properly. When the below + * !BCMDONGLEHOST is in all branches that use trunk DHD, the code + * under BCMDONGLEHOST can be removed. + */ + evlen = (uint16)(pktend - (uint8 *)&bcm_event->bcm_hdr.version); + evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen; + if (evend > pktend) { + err = BCME_BADLEN; + goto done; + } + + /* match on subtype, oui and usr subtype for BRCM events */ + subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.subtype); + if (subtype != BCMILCP_SUBTYPE_VENDOR_LONG) { + err = BCME_NOTFOUND; + goto done; + } + + if (bcmp(BRCM_OUI, &bcm_event->bcm_hdr.oui[0], DOT11_OUI_LEN)) { + err = BCME_NOTFOUND; + goto done; + } + + /* if it is a bcm_event or bcm_dngl_event_t, validate it */ + usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype); + switch (usr_subtype) { + case BCMILCP_BCM_SUBTYPE_EVENT: + /* check that header length and pkt length are sufficient */ + if ((pktlen < sizeof(bcm_event_t)) || + (evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) { + err = BCME_BADLEN; + goto done; + } + + /* ensure data length in event is not beyond the packet. */ + data_len = ntoh32_ua((void *)&bcm_event->event.datalen); + if (data_len > (pktlen - sizeof(bcm_event_t))) { + err = BCME_BADLEN; + goto done; + } + + if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) { + err = BCME_NOTFOUND; + goto done; + } + + if (out_event) { + /* ensure BRCM event pkt aligned */ + memcpy(&out_event->event, &bcm_event->event, sizeof(wl_event_msg_t)); + } + + break; + case BCMILCP_BCM_SUBTYPE_DNGLEVENT: + if ((pktlen < sizeof(bcm_dngl_event_t)) || + (evend < ((uint8 *)bcm_event + sizeof(bcm_dngl_event_t)))) { + err = BCME_BADLEN; + goto done; + } + + /* ensure data length in event is not beyond the packet. */ + data_len = ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata)->dngl_event.datalen); + if (data_len > (pktlen - sizeof(bcm_dngl_event_t))) { + err = BCME_BADLEN; + goto done; + } + + if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) { + err = BCME_NOTFOUND; + goto done; + } + + if (out_event) { + /* ensure BRCM dngl event pkt aligned */ + memcpy(&out_event->dngl_event, &((bcm_dngl_event_t *)pktdata)->dngl_event, + sizeof(bcm_dngl_event_msg_t)); + } + + break; + default: + err = BCME_NOTFOUND; + goto done; + } + + BCM_REFERENCE(data_len); +done: + return err; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c new file mode 100644 index 000000000000..98e561b6c3b3 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c @@ -0,0 +1,705 @@ +/* + * BCMSDH interface glue + * implement bcmsdh API for SDIOH driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh.c 455573 2014-02-14 17:49:31Z $ + */ + +/** + * @file bcmsdh.c + */ + +/* ****************** BCMSDH Interface Functions *************************** */ + +#include +#include +#include +#include +#include +#include +#include + +#include /* BRCM API for SDIO clients (such as wl, dhd) */ +#include /* common SDIO/controller interface */ +#include /* SDIO device core hardware definitions. */ +#include /* SDIO Device and Protocol Specs */ + +#define SDIOH_API_ACCESS_RETRY_LIMIT 2 +const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; + +/* local copy of bcm sd handler */ +bcmsdh_info_t * l_bcmsdh = NULL; + + +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) +extern int +sdioh_enable_hw_oob_intr(void *sdioh, bool enable); + +void +bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) +{ + sdioh_enable_hw_oob_intr(sdh->sdioh, enable); +} +#endif + +/* Attach BCMSDH layer to SDIO Host Controller Driver + * + * @param osh OSL Handle. + * @param cfghdl Configuration Handle. + * @param regsva Virtual address of controller registers. + * @param irq Interrupt number of SDIO controller. + * + * @return bcmsdh_info_t Handle to BCMSDH context. + */ +bcmsdh_info_t * +bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva) +{ + bcmsdh_info_t *bcmsdh; + + if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) { + BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); + return NULL; + } + bzero((char *)bcmsdh, sizeof(bcmsdh_info_t)); + bcmsdh->sdioh = sdioh; + bcmsdh->osh = osh; + bcmsdh->init_success = TRUE; + *regsva = SI_ENUM_BASE; + + /* Report the BAR, to fix if needed */ + bcmsdh->sbwad = SI_ENUM_BASE; + + /* save the handler locally */ + l_bcmsdh = bcmsdh; + + return bcmsdh; +} + +int +bcmsdh_detach(osl_t *osh, void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + if (bcmsdh != NULL) { + MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t)); + } + + l_bcmsdh = NULL; + + return 0; +} + +int +bcmsdh_iovar_op(void *sdh, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set); +} + +bool +bcmsdh_intr_query(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + bool on; + + ASSERT(bcmsdh); + status = sdioh_interrupt_query(bcmsdh->sdioh, &on); + if (SDIOH_API_SUCCESS(status)) + return FALSE; + else + return on; +} + +int +bcmsdh_intr_enable(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + ASSERT(bcmsdh); + + status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE); + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_intr_disable(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + ASSERT(bcmsdh); + + status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE); + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + ASSERT(bcmsdh); + + status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh); + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_intr_dereg(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + ASSERT(bcmsdh); + + status = sdioh_interrupt_deregister(bcmsdh->sdioh); + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +#if defined(DHD_DEBUG) +bool +bcmsdh_intr_pending(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + ASSERT(sdh); + return sdioh_interrupt_pending(bcmsdh->sdioh); +} +#endif + + +int +bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) +{ + ASSERT(sdh); + + /* don't support yet */ + return BCME_UNSUPPORTED; +} + +/** + * Read from SDIO Configuration Space + * @param sdh SDIO Host context. + * @param func_num Function number to read from. + * @param addr Address to read from. + * @param err Error return. + * @return value read from SDIO configuration space. + */ +uint8 +bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + int32 retry = 0; +#endif + uint8 data = 0; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + do { + if (retry) /* wait for 1 ms till bus get settled down */ + OSL_DELAY(1000); +#endif + status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); +#endif + if (err) + *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, + fnc_num, addr, data)); + + return data; +} + +void +bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + int32 retry = 0; +#endif + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + do { + if (retry) /* wait for 1 ms till bus get settled down */ + OSL_DELAY(1000); +#endif + status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT + } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); +#endif + if (err) + *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR; + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, + fnc_num, addr, data)); +} + +uint32 +bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + uint32 data = 0; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + + status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num, + addr, &data, 4); + + if (err) + *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, + fnc_num, addr, data)); + + return data; +} + +void +bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + + status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num, + addr, &data, 4); + + if (err) + *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num, + addr, data)); +} + + +int +bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + + uint8 *tmp_buf, *tmp_ptr; + uint8 *ptr; + bool ascii = func & ~0xf; + func &= 0x7; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + ASSERT(cis); + ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT); + + status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length); + + if (ascii) { + /* Move binary bits to tmp and format them into the provided buffer. */ + if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) { + BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__)); + return BCME_NOMEM; + } + bcopy(cis, tmp_buf, length); + for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) { + ptr += snprintf((char*)ptr, (cis + length - ptr - 4), + "%.2x ", *tmp_ptr & 0xff); + if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) + ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n"); + } + MFREE(bcmsdh->osh, tmp_buf, length); + } + + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + + +int +bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set) +{ + int err = 0; + uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK; + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + if (bar0 != bcmsdh->sbwad || force_set) { + bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, + (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); + if (!err) + bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, + (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); + if (!err) + bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, + (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); + + if (!err) + bcmsdh->sbwad = bar0; + else + /* invalidate cached window var */ + bcmsdh->sbwad = 0; + + } + + return err; +} + +uint32 +bcmsdh_reg_read(void *sdh, uint32 addr, uint size) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + uint32 word = 0; + + BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr)); + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + + if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)) + return 0xFFFFFFFF; + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + if (size == 4) + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + + status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, + SDIOH_READ, SDIO_FUNC_1, addr, &word, size); + + bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); + + BCMSDH_INFO(("uint32data = 0x%x\n", word)); + + /* if ok, return appropriately masked word */ + if (SDIOH_API_SUCCESS(status)) { + switch (size) { + case sizeof(uint8): + return (word & 0xff); + case sizeof(uint16): + return (word & 0xffff); + case sizeof(uint32): + return word; + default: + bcmsdh->regfail = TRUE; + + } + } + + /* otherwise, bad sdio access or invalid size */ + BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size)); + return 0xFFFFFFFF; +} + +uint32 +bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + int err = 0; + + BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", + __FUNCTION__, addr, size*8, data)); + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + ASSERT(bcmsdh->init_success); + + if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) + return err; + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + if (size == 4) + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1, + addr, &data, size); + bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); + + if (SDIOH_API_SUCCESS(status)) + return 0; + + BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n", + __FUNCTION__, data, addr, size)); + return 0xFFFFFFFF; +} + +bool +bcmsdh_regfail(void *sdh) +{ + return ((bcmsdh_info_t *)sdh)->regfail; +} + +int +bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, void *pkt, + bcmsdh_cmplt_fn_t complete_fn, void *handle) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + uint incr_fix; + uint width; + int err = 0; + + ASSERT(bcmsdh); + ASSERT(bcmsdh->init_success); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", + __FUNCTION__, fn, addr, nbytes)); + + /* Async not implemented yet */ + ASSERT(!(flags & SDIO_REQ_ASYNC)); + if (flags & SDIO_REQ_ASYNC) + return BCME_UNSUPPORTED; + + if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) + return err; + + 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 = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, + SDIOH_READ, fn, addr, width, nbytes, buf, pkt); + + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); +} + +int +bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, void *pkt, + bcmsdh_cmplt_fn_t complete_fn, void *handle) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + uint incr_fix; + uint width; + int err = 0; + + ASSERT(bcmsdh); + ASSERT(bcmsdh->init_success); + + BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", + __FUNCTION__, fn, addr, nbytes)); + + /* Async not implemented yet */ + ASSERT(!(flags & SDIO_REQ_ASYNC)); + if (flags & SDIO_REQ_ASYNC) + return BCME_UNSUPPORTED; + + if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) + return err; + + 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 = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, + SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt); + + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + SDIOH_API_RC status; + + ASSERT(bcmsdh); + ASSERT(bcmsdh->init_success); + ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0); + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + + status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC, + (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, + addr, 4, nbytes, buf, NULL); + + return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); +} + +int +bcmsdh_abort(void *sdh, uint fn) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_abort(bcmsdh->sdioh, fn); +} + +int +bcmsdh_start(void *sdh, int stage) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_start(bcmsdh->sdioh, stage); +} + +int +bcmsdh_stop(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_stop(bcmsdh->sdioh); +} + +int +bcmsdh_waitlockfree(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_waitlockfree(bcmsdh->sdioh); +} + + +int +bcmsdh_query_device(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0; + return (bcmsdh->vendevid); +} + +uint +bcmsdh_query_iofnum(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + return (sdioh_query_iofnum(bcmsdh->sdioh)); +} + +int +bcmsdh_reset(bcmsdh_info_t *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + return sdioh_sdio_reset(bcmsdh->sdioh); +} + +void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh) +{ + ASSERT(sdh); + return sdh->sdioh; +} + +/* Function to pass device-status bits to DHD. */ +uint32 +bcmsdh_get_dstatus(void *sdh) +{ + return 0; +} +uint32 +bcmsdh_cur_sbwad(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + return (bcmsdh->sbwad); +} + +void +bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev) +{ + return; +} + + +int +bcmsdh_sleep(void *sdh, bool enab) +{ +#ifdef SDIOH_SLEEP_ENABLED + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_sleep(sd, enab); +#else + return BCME_UNSUPPORTED; +#endif +} + +int +bcmsdh_gpio_init(void *sdh) +{ + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_gpio_init(sd); +} + +bool +bcmsdh_gpioin(void *sdh, uint32 gpio) +{ + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_gpioin(sd, gpio); +} + +int +bcmsdh_gpioouten(void *sdh, uint32 gpio) +{ + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_gpioouten(sd, gpio); +} + +int +bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) +{ + bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; + sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); + + return sdioh_gpioout(sd, gpio, enab); +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c new file mode 100644 index 000000000000..e57a2cfa1869 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c @@ -0,0 +1,466 @@ +/* + * SDIO access interface for drivers - linux specific (pci only) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh_linux.c 461443 2014-03-12 02:40:59Z $ + */ + +/** + * @file bcmsdh_linux.c + */ + +#define __UNDEF_NO_VERSION__ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +extern void dhdsdio_isr(void * args); +#include +#include +#include +#if defined(CONFIG_ARCH_ODIN) +#include +#endif /* defined(CONFIG_ARCH_ODIN) */ + +#include + +/* driver info, initialized when bcmsdh_register is called */ +static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL}; + +typedef enum { + DHD_INTR_INVALID = 0, + DHD_INTR_INBAND, + DHD_INTR_HWOOB, + DHD_INTR_SWOOB +} DHD_HOST_INTR_TYPE; + +/* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g. + * bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather + * than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this + * structure. + */ +typedef struct bcmsdh_os_info { + DHD_HOST_INTR_TYPE intr_type; + int oob_irq_num; /* valid when hardware or software oob in use */ + unsigned long oob_irq_flags; /* valid when hardware or software oob in use */ + bool oob_irq_registered; + bool oob_irq_enabled; + bool oob_irq_wake_enabled; + spinlock_t oob_irq_spinlock; + bcmsdh_cb_fn_t oob_irq_handler; + void *oob_irq_handler_context; + void *context; /* context returned from upper layer */ + void *sdioh; /* handle to lower layer (sdioh) */ + void *dev; /* handle to the underlying device */ + bool dev_wake_enabled; +} bcmsdh_os_info_t; + +/* debugging macros */ +#define SDLX_MSG(x) + +/** + * Checks to see if vendor and device IDs match a supported SDIO Host Controller. + */ +bool +bcmsdh_chipmatch(uint16 vendor, uint16 device) +{ + /* Add other vendors and devices as required */ + +#ifdef BCMSDIOH_STD + /* Check for Arasan host controller */ + if (vendor == VENDOR_SI_IMAGE) { + return (TRUE); + } + /* Check for BRCM 27XX Standard host controller */ + if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) { + return (TRUE); + } + /* Check for BRCM Standard host controller */ + if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) { + return (TRUE); + } + /* Check for TI PCIxx21 Standard host controller */ + if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) { + return (TRUE); + } + if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) { + return (TRUE); + } + /* Ricoh R5C822 Standard SDIO Host */ + if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) { + return (TRUE); + } + /* JMicron Standard SDIO Host */ + if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) { + return (TRUE); + } + +#endif /* BCMSDIOH_STD */ +#ifdef BCMSDIOH_SPI + /* This is the PciSpiHost. */ + if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) { + printf("Found PCI SPI Host Controller\n"); + return (TRUE); + } + +#endif /* BCMSDIOH_SPI */ + + return (FALSE); +} + +void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, + uint bus_num, uint slot_num) +{ + ulong regs; + bcmsdh_info_t *bcmsdh; + uint32 vendevid; + bcmsdh_os_info_t *bcmsdh_osinfo = NULL; + + bcmsdh = bcmsdh_attach(osh, sdioh, ®s); + if (bcmsdh == NULL) { + SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__)); + goto err; + } + bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t)); + if (bcmsdh_osinfo == NULL) { + SDLX_MSG(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__)); + goto err; + } + bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); + bcmsdh->os_cxt = bcmsdh_osinfo; + bcmsdh_osinfo->sdioh = sdioh; + bcmsdh_osinfo->dev = dev; + osl_set_bus_handle(osh, bcmsdh); + +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (dev && device_init_wakeup(dev, true) == 0) + bcmsdh_osinfo->dev_wake_enabled = TRUE; +#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ + +#if defined(OOB_INTR_ONLY) + spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock); + /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */ + bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info, + &bcmsdh_osinfo->oob_irq_flags); + if (bcmsdh_osinfo->oob_irq_num < 0) { + SDLX_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__)); + goto err; + } +#endif /* defined(BCMLXSDMMC) */ + + /* Read the vendor/device ID from the CIS */ + vendevid = bcmsdh_query_device(bcmsdh); + /* try to attach to the target device */ + bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num, + slot_num, 0, bus_type, (void *)regs, osh, bcmsdh); + if (bcmsdh_osinfo->context == NULL) { + SDLX_MSG(("%s: device attach failed\n", __FUNCTION__)); + goto err; + } + + return bcmsdh; + + /* error handling */ +err: + if (bcmsdh != NULL) + bcmsdh_detach(osh, bcmsdh); + if (bcmsdh_osinfo != NULL) + MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); + return NULL; +} + +int bcmsdh_remove(bcmsdh_info_t *bcmsdh) +{ + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (bcmsdh_osinfo->dev) + device_init_wakeup(bcmsdh_osinfo->dev, false); + bcmsdh_osinfo->dev_wake_enabled = FALSE; +#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ + + drvinfo.remove(bcmsdh_osinfo->context); + MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t)); + bcmsdh_detach(bcmsdh->osh, bcmsdh); + + return 0; +} + +int bcmsdh_suspend(bcmsdh_info_t *bcmsdh) +{ + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context)) + return -EBUSY; + return 0; +} + +int bcmsdh_resume(bcmsdh_info_t *bcmsdh) +{ + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + if (drvinfo.resume) + return drvinfo.resume(bcmsdh_osinfo->context); + return 0; +} + +extern int bcmsdh_register_client_driver(void); +extern void bcmsdh_unregister_client_driver(void); +extern int sdio_func_reg_notify(void* semaphore); +extern void sdio_func_unreg_notify(void); + +#if defined(BCMLXSDMMC) +int bcmsdh_reg_sdio_notify(void* semaphore) +{ + return sdio_func_reg_notify(semaphore); +} + +void bcmsdh_unreg_sdio_notify(void) +{ + sdio_func_unreg_notify(); +} +#endif /* defined(BCMLXSDMMC) */ + +int +bcmsdh_register(bcmsdh_driver_t *driver) +{ + int error = 0; + + drvinfo = *driver; + SDLX_MSG(("%s: register client driver\n", __FUNCTION__)); + error = bcmsdh_register_client_driver(); + if (error) + SDLX_MSG(("%s: failed %d\n", __FUNCTION__, error)); + + return error; +} + +void +bcmsdh_unregister(void) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) + if (bcmsdh_pci_driver.node.next == NULL) + return; +#endif + + bcmsdh_unregister_client_driver(); +} + +void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh) +{ +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + pm_stay_awake(bcmsdh_osinfo->dev); +#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ +} + +void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh) +{ +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + pm_relax(bcmsdh_osinfo->dev); +#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ +} + +bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh) +{ + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + return bcmsdh_osinfo->dev_wake_enabled; +} + +#if defined(OOB_INTR_ONLY) +void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable) +{ + unsigned long flags; + bcmsdh_os_info_t *bcmsdh_osinfo; + + if (!bcmsdh) + return; + + bcmsdh_osinfo = bcmsdh->os_cxt; + spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags); + if (bcmsdh_osinfo->oob_irq_enabled != enable) { + if (enable) + enable_irq(bcmsdh_osinfo->oob_irq_num); + else + disable_irq_nosync(bcmsdh_osinfo->oob_irq_num); + bcmsdh_osinfo->oob_irq_enabled = enable; + } + spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags); +} + +static irqreturn_t wlan_oob_irq(int irq, void *dev_id) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id; + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + bcmsdh_oob_intr_set(bcmsdh, FALSE); + bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context); + + return IRQ_HANDLED; +} + +int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, + void* oob_irq_handler_context) +{ + int err = 0; + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + SDLX_MSG(("%s: Enter\n", __FUNCTION__)); + if (bcmsdh_osinfo->oob_irq_registered) { + SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__)); + return -EBUSY; + } + SDLX_MSG(("%s OOB irq=%d flags=%X \n", __FUNCTION__, + (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags)); + bcmsdh_osinfo->oob_irq_handler = oob_irq_handler; + bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context; +#if defined(CONFIG_ARCH_ODIN) + err = odin_gpio_sms_request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, + bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); +#else + err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, + bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); +#endif /* defined(CONFIG_ARCH_ODIN) */ + if (err) { + SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err)); + return err; + } + + err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num); + if (!err) + bcmsdh_osinfo->oob_irq_wake_enabled = TRUE; + bcmsdh_osinfo->oob_irq_enabled = TRUE; + bcmsdh_osinfo->oob_irq_registered = TRUE; + return err; +} + +void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh) +{ + int err = 0; + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + + SDLX_MSG(("%s: Enter\n", __FUNCTION__)); + if (!bcmsdh_osinfo->oob_irq_registered) { + SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__)); + return; + } + if (bcmsdh_osinfo->oob_irq_wake_enabled) { + err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num); + if (!err) + bcmsdh_osinfo->oob_irq_wake_enabled = FALSE; + } + if (bcmsdh_osinfo->oob_irq_enabled) { + disable_irq(bcmsdh_osinfo->oob_irq_num); + bcmsdh_osinfo->oob_irq_enabled = FALSE; + } + free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh); + bcmsdh_osinfo->oob_irq_registered = FALSE; +} +#endif + +/* Module parameters specific to each host-controller driver */ + +extern uint sd_msglevel; /* Debug message level */ +module_param(sd_msglevel, uint, 0); + +extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */ +module_param(sd_power, uint, 0); + +extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */ +module_param(sd_clock, uint, 0); + +extern uint sd_divisor; /* Divisor (-1 means external clock) */ +module_param(sd_divisor, uint, 0); + +extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */ +module_param(sd_sdmode, uint, 0); + +extern uint sd_hiok; /* Ok to use hi-speed mode */ +module_param(sd_hiok, uint, 0); + +extern uint sd_f2_blocksize; +module_param(sd_f2_blocksize, int, 0); + +#ifdef BCMSDIOH_STD +extern int sd_uhsimode; +module_param(sd_uhsimode, int, 0); +extern uint sd_tuning_period; +module_param(sd_tuning_period, uint, 0); +extern int sd_delay_value; +module_param(sd_delay_value, uint, 0); + +/* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */ +extern char dhd_sdiod_uhsi_ds_override[2]; +module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0); + +#endif + +#ifdef BCMSDH_MODULE +EXPORT_SYMBOL(bcmsdh_attach); +EXPORT_SYMBOL(bcmsdh_detach); +EXPORT_SYMBOL(bcmsdh_intr_query); +EXPORT_SYMBOL(bcmsdh_intr_enable); +EXPORT_SYMBOL(bcmsdh_intr_disable); +EXPORT_SYMBOL(bcmsdh_intr_reg); +EXPORT_SYMBOL(bcmsdh_intr_dereg); + +#if defined(DHD_DEBUG) +EXPORT_SYMBOL(bcmsdh_intr_pending); +#endif + +EXPORT_SYMBOL(bcmsdh_devremove_reg); +EXPORT_SYMBOL(bcmsdh_cfg_read); +EXPORT_SYMBOL(bcmsdh_cfg_write); +EXPORT_SYMBOL(bcmsdh_cis_read); +EXPORT_SYMBOL(bcmsdh_reg_read); +EXPORT_SYMBOL(bcmsdh_reg_write); +EXPORT_SYMBOL(bcmsdh_regfail); +EXPORT_SYMBOL(bcmsdh_send_buf); +EXPORT_SYMBOL(bcmsdh_recv_buf); + +EXPORT_SYMBOL(bcmsdh_rwdata); +EXPORT_SYMBOL(bcmsdh_abort); +EXPORT_SYMBOL(bcmsdh_query_device); +EXPORT_SYMBOL(bcmsdh_query_iofnum); +EXPORT_SYMBOL(bcmsdh_iovar_op); +EXPORT_SYMBOL(bcmsdh_register); +EXPORT_SYMBOL(bcmsdh_unregister); +EXPORT_SYMBOL(bcmsdh_chipmatch); +EXPORT_SYMBOL(bcmsdh_reset); +EXPORT_SYMBOL(bcmsdh_waitlockfree); + +EXPORT_SYMBOL(bcmsdh_get_dstatus); +EXPORT_SYMBOL(bcmsdh_cfg_read_word); +EXPORT_SYMBOL(bcmsdh_cfg_write_word); +EXPORT_SYMBOL(bcmsdh_cur_sbwad); +EXPORT_SYMBOL(bcmsdh_chipinfo); + +#endif /* BCMSDH_MODULE */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c new file mode 100644 index 000000000000..2488cfbc78c5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c @@ -0,0 +1,1456 @@ +/* + * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh_sdmmc.c 457662 2014-02-24 15:07:28Z $ + */ +#include + +#include +#include +#include +#include +#include /* SDIO Device and Protocol Specs */ +#include /* Standard SDIO Host Controller Specification */ +#include /* bcmsdh to/from specific controller APIs */ +#include /* ioctl/iovars */ + +#include +#include +#include +#include +#include + +#include +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#include +extern volatile bool dhd_mmc_suspend; +#endif +#include "bcmsdh_sdmmc.h" + +#ifndef BCMSDH_MODULE +extern int sdio_function_init(void); +extern void sdio_function_cleanup(void); +#endif /* BCMSDH_MODULE */ + +#if !defined(OOB_INTR_ONLY) +static void IRQHandler(struct sdio_func *func); +static void IRQHandlerF2(struct sdio_func *func); +#endif /* !defined(OOB_INTR_ONLY) */ +static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); +extern int sdio_reset_comm(struct mmc_card *card); + +#define DEFAULT_SDIO_F2_BLKSIZE 512 +#ifndef CUSTOM_SDIO_F2_BLKSIZE +#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE +#endif + +#define MAX_IO_RW_EXTENDED_BLK 511 + +uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ +uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; +uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ + +uint sd_power = 1; /* Default to SD Slot powered ON */ +uint sd_clock = 1; /* Default to SD Clock turned ON */ +uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ +uint sd_msglevel = 0x01; +uint sd_use_dma = TRUE; + +#ifndef CUSTOM_RXCHAIN +#define CUSTOM_RXCHAIN 0 +#endif + +DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); +DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); +DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); +DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); + +#define DMA_ALIGN_MASK 0x03 +#define MMC_SDIO_ABORT_RETRY_LIMIT 5 + +int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); + +static int +sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) +{ + int err_ret; + uint32 fbraddr; + uint8 func; + + sd_trace(("%s\n", __FUNCTION__)); + + /* Get the Card's common CIS address */ + sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); + sd->func_cis_ptr[0] = sd->com_cis_ptr; + sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); + + /* Get the Card's function CIS (for each function) */ + for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; + func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { + sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); + sd_info(("%s: Function %d CIS Ptr = 0x%x\n", + __FUNCTION__, func, sd->func_cis_ptr[func])); + } + + sd->func_cis_ptr[0] = sd->com_cis_ptr; + sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); + + /* Enable Function 1 */ + sdio_claim_host(sd->func[1]); + err_ret = sdio_enable_func(sd->func[1]); + sdio_release_host(sd->func[1]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret)); + } + + return FALSE; +} + +/* + * Public entry points & extern's + */ +extern sdioh_info_t * +sdioh_attach(osl_t *osh, struct sdio_func *func) +{ + sdioh_info_t *sd = NULL; + int err_ret; + + sd_trace(("%s\n", __FUNCTION__)); + + if (func == NULL) { + sd_err(("%s: sdio function device is NULL\n", __FUNCTION__)); + return NULL; + } + + if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { + sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); + return NULL; + } + bzero((char *)sd, sizeof(sdioh_info_t)); + sd->osh = osh; + sd->fake_func0.num = 0; + sd->fake_func0.card = func->card; + sd->func[0] = &sd->fake_func0; + sd->func[1] = func->card->sdio_func[0]; + sd->func[2] = func->card->sdio_func[1]; + sd->num_funcs = 2; + sd->sd_blockmode = TRUE; + sd->use_client_ints = TRUE; + sd->client_block_size[0] = 64; + sd->use_rxchain = CUSTOM_RXCHAIN; + if (sd->func[1] == NULL || sd->func[2] == NULL) { + sd_err(("%s: func 1 or 2 is null \n", __FUNCTION__)); + goto fail; + } + sdio_set_drvdata(sd->func[1], sd); + + sdio_claim_host(sd->func[1]); + sd->client_block_size[1] = 64; + err_ret = sdio_set_block_size(sd->func[1], 64); + sdio_release_host(sd->func[1]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize(%d)\n", err_ret)); + goto fail; + } + + sdio_claim_host(sd->func[2]); + sd->client_block_size[2] = sd_f2_blocksize; + err_ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); + sdio_release_host(sd->func[2]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d(%d)\n", + sd_f2_blocksize, err_ret)); + goto fail; + } + + sdioh_sdmmc_card_enablefuncs(sd); + + sd_trace(("%s: Done\n", __FUNCTION__)); + return sd; + +fail: + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; +} + + +extern SDIOH_API_RC +sdioh_detach(osl_t *osh, sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + + if (sd) { + + /* Disable Function 2 */ + if (sd->func[2]) { + sdio_claim_host(sd->func[2]); + sdio_disable_func(sd->func[2]); + sdio_release_host(sd->func[2]); + } + + /* Disable Function 1 */ + if (sd->func[1]) { + sdio_claim_host(sd->func[1]); + sdio_disable_func(sd->func[1]); + sdio_release_host(sd->func[1]); + } + + sd->func[1] = NULL; + sd->func[2] = NULL; + + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + } + return SDIOH_API_RC_SUCCESS; +} + +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) + +extern SDIOH_API_RC +sdioh_enable_func_intr(sdioh_info_t *sd) +{ + uint8 reg; + int err; + + if (sd->func[0] == NULL) { + sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + sdio_claim_host(sd->func[0]); + reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); + if (err) { + sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); + sdio_release_host(sd->func[0]); + return SDIOH_API_RC_FAIL; + } + /* Enable F1 and F2 interrupts, clear master enable */ + reg &= ~INTR_CTL_MASTER_EN; + reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); + sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); + sdio_release_host(sd->func[0]); + + if (err) { + sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); + return SDIOH_API_RC_FAIL; + } + + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_disable_func_intr(sdioh_info_t *sd) +{ + uint8 reg; + int err; + + if (sd->func[0] == NULL) { + sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + sdio_claim_host(sd->func[0]); + reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); + if (err) { + sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); + sdio_release_host(sd->func[0]); + return SDIOH_API_RC_FAIL; + } + reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); + /* Disable master interrupt with the last function interrupt */ + if (!(reg & 0xFE)) + reg = 0; + sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); + sdio_release_host(sd->func[0]); + + if (err) { + sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); + return SDIOH_API_RC_FAIL; + } + + return SDIOH_API_RC_SUCCESS; +} +#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ + +/* Configure callback to client when we recieve client interrupt */ +extern SDIOH_API_RC +sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + if (fn == NULL) { + sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } +#if !defined(OOB_INTR_ONLY) + sd->intr_handler = fn; + sd->intr_handler_arg = argh; + sd->intr_handler_valid = TRUE; + + /* register and unmask irq */ + if (sd->func[2]) { + sdio_claim_host(sd->func[2]); + sdio_claim_irq(sd->func[2], IRQHandlerF2); + sdio_release_host(sd->func[2]); + } + + if (sd->func[1]) { + sdio_claim_host(sd->func[1]); + sdio_claim_irq(sd->func[1], IRQHandler); + sdio_release_host(sd->func[1]); + } +#elif defined(HW_OOB) + sdioh_enable_func_intr(sd); +#endif /* !defined(OOB_INTR_ONLY) */ + + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_deregister(sdioh_info_t *sd) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + +#if !defined(OOB_INTR_ONLY) + if (sd->func[1]) { + /* register and unmask irq */ + sdio_claim_host(sd->func[1]); + sdio_release_irq(sd->func[1]); + sdio_release_host(sd->func[1]); + } + + if (sd->func[2]) { + /* Claim host controller F2 */ + sdio_claim_host(sd->func[2]); + sdio_release_irq(sd->func[2]); + /* Release host controller F2 */ + sdio_release_host(sd->func[2]); + } + + sd->intr_handler_valid = FALSE; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; +#elif defined(HW_OOB) + sdioh_disable_func_intr(sd); +#endif /* !defined(OOB_INTR_ONLY) */ + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + *onoff = sd->client_intr_enabled; + return SDIOH_API_RC_SUCCESS; +} + +#if defined(DHD_DEBUG) +extern bool +sdioh_interrupt_pending(sdioh_info_t *sd) +{ + return (0); +} +#endif + +uint +sdioh_query_iofnum(sdioh_info_t *sd) +{ + return sd->num_funcs; +} + +/* IOVar table */ +enum { + IOV_MSGLEVEL = 1, + IOV_BLOCKMODE, + IOV_BLOCKSIZE, + IOV_DMA, + IOV_USEINTS, + IOV_NUMINTS, + IOV_NUMLOCALINTS, + IOV_HOSTREG, + IOV_DEVREG, + IOV_DIVISOR, + IOV_SDMODE, + IOV_HISPEED, + IOV_HCIREGS, + IOV_POWER, + IOV_CLOCK, + IOV_RXCHAIN +}; + +const bcm_iovar_t sdioh_iovars[] = { + {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, + {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, + {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ + {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, + {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, + {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, + {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, + {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, + {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, + {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, + {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, + {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 }, + {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +int +sdioh_iovar_op(sdioh_info_t *si, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + int32 int_val = 0; + bool bool_val; + uint32 actionid; + + ASSERT(name); + ASSERT(len >= 0); + + /* Get must have return space; Set does not take qualifiers */ + ASSERT(set || (arg && len)); + ASSERT(!set || (!params && !plen)); + + sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); + + if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { + bcmerror = BCME_UNSUPPORTED; + goto exit; + } + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) + goto exit; + + /* Set up params so get and set can share the convenience variables */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + val_size = sizeof(int); + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + BCM_REFERENCE(bool_val); + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + switch (actionid) { + case IOV_GVAL(IOV_MSGLEVEL): + int_val = (int32)sd_msglevel; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MSGLEVEL): + sd_msglevel = int_val; + break; + + case IOV_GVAL(IOV_BLOCKMODE): + int_val = (int32)si->sd_blockmode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_BLOCKMODE): + si->sd_blockmode = (bool)int_val; + /* Haven't figured out how to make non-block mode with DMA */ + break; + + case IOV_GVAL(IOV_BLOCKSIZE): + if ((uint32)int_val > si->num_funcs) { + bcmerror = BCME_BADARG; + break; + } + int_val = (int32)si->client_block_size[int_val]; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_BLOCKSIZE): + { + uint func = ((uint32)int_val >> 16); + uint blksize = (uint16)int_val; + uint maxsize; + + if (func > si->num_funcs) { + bcmerror = BCME_BADARG; + break; + } + + switch (func) { + case 0: maxsize = 32; break; + case 1: maxsize = BLOCK_SIZE_4318; break; + case 2: maxsize = BLOCK_SIZE_4328; break; + default: maxsize = 0; + } + if (blksize > maxsize) { + bcmerror = BCME_BADARG; + break; + } + if (!blksize) { + blksize = maxsize; + } + + /* Now set it */ + si->client_block_size[func] = blksize; + + break; + } + + case IOV_GVAL(IOV_RXCHAIN): + int_val = (int32)si->use_rxchain; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_DMA): + int_val = (int32)si->sd_use_dma; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DMA): + si->sd_use_dma = (bool)int_val; + break; + + case IOV_GVAL(IOV_USEINTS): + int_val = (int32)si->use_client_ints; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_USEINTS): + si->use_client_ints = (bool)int_val; + if (si->use_client_ints) + si->intmask |= CLIENT_INTR; + else + si->intmask &= ~CLIENT_INTR; + + break; + + case IOV_GVAL(IOV_DIVISOR): + int_val = (uint32)sd_divisor; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DIVISOR): + sd_divisor = int_val; + break; + + case IOV_GVAL(IOV_POWER): + int_val = (uint32)sd_power; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_POWER): + sd_power = int_val; + break; + + case IOV_GVAL(IOV_CLOCK): + int_val = (uint32)sd_clock; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_CLOCK): + sd_clock = int_val; + break; + + case IOV_GVAL(IOV_SDMODE): + int_val = (uint32)sd_sdmode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDMODE): + sd_sdmode = int_val; + break; + + case IOV_GVAL(IOV_HISPEED): + int_val = (uint32)sd_hiok; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_HISPEED): + sd_hiok = int_val; + break; + + case IOV_GVAL(IOV_NUMINTS): + int_val = (int32)si->intrcount; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_NUMLOCALINTS): + int_val = (int32)0; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_HOSTREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + + if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { + sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); + bcmerror = BCME_BADARG; + break; + } + + sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__, + (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), + sd_ptr->offset)); + if (sd_ptr->offset & 1) + int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */ + else if (sd_ptr->offset & 2) + int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */ + else + int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */ + + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_HOSTREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + + if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { + sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); + bcmerror = BCME_BADARG; + break; + } + + sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value, + (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), + sd_ptr->offset)); + break; + } + + case IOV_GVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data = 0; + + if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + + int_val = (int)data; + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data = (uint8)sd_ptr->value; + + if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + } + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } +exit: + + return bcmerror; +} + +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) + +SDIOH_API_RC +sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) +{ + SDIOH_API_RC status; + uint8 data; + + if (enable) + data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; + else + data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ + + status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); + return status; +} +#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ + +extern SDIOH_API_RC +sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + SDIOH_API_RC status; + /* No lock needed since sdioh_request_byte does locking */ + status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + /* No lock needed since sdioh_request_byte does locking */ + SDIOH_API_RC status; + status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); + return status; +} + +static int +sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) +{ + /* read 24 bits and return valid 17 bit addr */ + int i; + uint32 scratch, regdata; + uint8 *ptr = (uint8 *)&scratch; + for (i = 0; i < 3; i++) { + if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) + sd_err(("%s: Can't read!\n", __FUNCTION__)); + + *ptr++ = (uint8) regdata; + regaddr++; + } + + /* Only the lower 17-bits are valid */ + scratch = ltoh32(scratch); + scratch &= 0x0001FFFF; + return (scratch); +} + +extern SDIOH_API_RC +sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) +{ + uint32 count; + int offset; + uint32 foo; + uint8 *cis = cisd; + + sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); + + if (!sd->func_cis_ptr[func]) { + bzero(cis, length); + sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); + return SDIOH_API_RC_FAIL; + } + + sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); + + for (count = 0; count < length; count++) { + offset = sd->func_cis_ptr[func] + count; + if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { + sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + *cis = (uint8)(foo & 0xff); + cis++; + } + + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) +{ + int err_ret = 0; +#if defined(MMC_SDIO_ABORT) + int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; +#endif + + sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); + + DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); + DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); + if(rw) { /* CMD52 Write */ + if (func == 0) { + /* Can only directly write to some F0 registers. Handle F2 enable + * as a special case. + */ + if (regaddr == SDIOD_CCCR_IOEN) { + if (sd->func[2]) { + sdio_claim_host(sd->func[2]); + if (*byte & SDIO_FUNC_ENABLE_2) { + /* Enable Function 2 */ + err_ret = sdio_enable_func(sd->func[2]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: enable F2 failed:%d", + err_ret)); + } + } else { + /* Disable Function 2 */ + err_ret = sdio_disable_func(sd->func[2]); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d", + err_ret)); + } + } + sdio_release_host(sd->func[2]); + } + } +#if defined(MMC_SDIO_ABORT) + /* to allow abort command through F1 */ + else if (regaddr == SDIOD_CCCR_IOABORT) { + while (sdio_abort_retry--) { + if (sd->func[func]) { + sdio_claim_host(sd->func[func]); + /* + * this sdio_f0_writeb() can be replaced with + * another api depending upon MMC driver change. + * As of this time, this is temporaray one + */ + sdio_writeb(sd->func[func], + *byte, regaddr, &err_ret); + sdio_release_host(sd->func[func]); + } + if (!err_ret) + break; + } + } +#endif /* MMC_SDIO_ABORT */ + else if (regaddr < 0xF0) { + sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); + } else { + /* Claim host controller, perform F0 write, and release */ + if (sd->func[func]) { + sdio_claim_host(sd->func[func]); + sdio_f0_writeb(sd->func[func], + *byte, regaddr, &err_ret); + sdio_release_host(sd->func[func]); + } + } + } else { + /* Claim host controller, perform Fn write, and release */ + if (sd->func[func]) { + sdio_claim_host(sd->func[func]); + sdio_writeb(sd->func[func], *byte, regaddr, &err_ret); + sdio_release_host(sd->func[func]); + } + } + } else { /* CMD52 Read */ + /* Claim host controller, perform Fn read, and release */ + if (sd->func[func]) { + sdio_claim_host(sd->func[func]); + if (func == 0) { + *byte = sdio_f0_readb(sd->func[func], regaddr, &err_ret); + } else { + *byte = sdio_readb(sd->func[func], regaddr, &err_ret); + } + sdio_release_host(sd->func[func]); + } + } + + if (err_ret) { + if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ))) { + } else { + sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", + rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); + } + } + + return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + +extern SDIOH_API_RC +sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, + uint32 *word, uint nbytes) +{ + int err_ret = SDIOH_API_RC_FAIL; +#if defined(MMC_SDIO_ABORT) + int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; +#endif + + if (func == 0) { + sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", + __FUNCTION__, cmd_type, rw, func, addr, nbytes)); + + DHD_PM_RESUME_WAIT(sdioh_request_word_wait); + DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); + /* Claim host controller */ + sdio_claim_host(sd->func[func]); + + if(rw) { /* CMD52 Write */ + if (nbytes == 4) { + sdio_writel(sd->func[func], *word, addr, &err_ret); + } else if (nbytes == 2) { + sdio_writew(sd->func[func], (*word & 0xFFFF), addr, &err_ret); + } else { + sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); + } + } else { /* CMD52 Read */ + if (nbytes == 4) { + *word = sdio_readl(sd->func[func], addr, &err_ret); + } else if (nbytes == 2) { + *word = sdio_readw(sd->func[func], addr, &err_ret) & 0xFFFF; + } else { + sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); + } + } + + /* Release host controller */ + sdio_release_host(sd->func[func]); + + if (err_ret) { +#if defined(MMC_SDIO_ABORT) + /* Any error on CMD53 transaction should abort that function using function 0. */ + while (sdio_abort_retry--) { + if (sd->func[0]) { + sdio_claim_host(sd->func[0]); + /* + * this sdio_f0_writeb() can be replaced with another api + * depending upon MMC driver change. + * As of this time, this is temporaray one + */ + sdio_writeb(sd->func[0], + func, SDIOD_CCCR_IOABORT, &err_ret); + sdio_release_host(sd->func[0]); + } + if (!err_ret) + break; + } + if (err_ret) +#endif /* MMC_SDIO_ABORT */ + { + sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x", + rw ? "Write" : "Read", err_ret)); + } + } + + return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + +static SDIOH_API_RC +sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func, + uint addr, void *pkt) +{ + bool fifo = (fix_inc == SDIOH_DATA_FIX); + int err_ret = 0; + void *pnext; + uint ttl_len, pkt_offset; + uint blk_num; + uint blk_size; + uint max_blk_count; + uint max_req_size; + struct mmc_request mmc_req; + struct mmc_command mmc_cmd; + struct mmc_data mmc_dat; + uint32 sg_count; + struct sdio_func *sdio_func = sd->func[func]; + struct mmc_host *host = sdio_func->card->host; + + sd_trace(("%s: Enter\n", __FUNCTION__)); + ASSERT(pkt); + DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); + DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); + + blk_size = sd->client_block_size[func]; + max_blk_count = min(host->max_blk_count, (uint)MAX_IO_RW_EXTENDED_BLK); + max_req_size = min(max_blk_count * blk_size, host->max_req_size); + + pkt_offset = 0; + pnext = pkt; + + while (pnext != NULL) { + ttl_len = 0; + sg_count = 0; + memset(&mmc_req, 0, sizeof(struct mmc_request)); + memset(&mmc_cmd, 0, sizeof(struct mmc_command)); + memset(&mmc_dat, 0, sizeof(struct mmc_data)); + sg_init_table(sd->sg_list, ARRAYSIZE(sd->sg_list)); + + /* Set up scatter-gather DMA descriptors. this loop is to find out the max + * data we can transfer with one command 53. blocks per command is limited by + * host max_req_size and 9-bit max block number. when the total length of this + * packet chain is bigger than max_req_size, use multiple SD_IO_RW_EXTENDED + * commands (each transfer is still block aligned) + */ + while (pnext != NULL && ttl_len < max_req_size) { + int pkt_len; + int sg_data_size; + uint8 *pdata = (uint8*)PKTDATA(sd->osh, pnext); + + ASSERT(pdata != NULL); + pkt_len = PKTLEN(sd->osh, pnext); + sd_trace(("%s[%d] data=%p, len=%d\n", __FUNCTION__, write, pdata, pkt_len)); + /* sg_count is unlikely larger than the array size, and this is + * NOT something we can handle here, but in case it happens, PLEASE put + * a restriction on max tx/glom count (based on host->max_segs). + */ + if (sg_count >= ARRAYSIZE(sd->sg_list)) { + sd_err(("%s: sg list entries exceed limit\n", __FUNCTION__)); + return (SDIOH_API_RC_FAIL); + } + pdata += pkt_offset; + + sg_data_size = pkt_len - pkt_offset; + if (sg_data_size > max_req_size - ttl_len) + sg_data_size = max_req_size - ttl_len; + /* some platforms put a restriction on the data size of each scatter-gather + * DMA descriptor, use multiple sg buffers when xfer_size is bigger than + * max_seg_size + */ + if (sg_data_size > host->max_seg_size) + sg_data_size = host->max_seg_size; + sg_set_buf(&sd->sg_list[sg_count++], pdata, sg_data_size); + + ttl_len += sg_data_size; + pkt_offset += sg_data_size; + if (pkt_offset == pkt_len) { + pnext = PKTNEXT(sd->osh, pnext); + pkt_offset = 0; + } + } + + if (ttl_len % blk_size != 0) { + sd_err(("%s, data length %d not aligned to block size %d\n", + __FUNCTION__, ttl_len, blk_size)); + return SDIOH_API_RC_FAIL; + } + blk_num = ttl_len / blk_size; + mmc_dat.sg = sd->sg_list; + mmc_dat.sg_len = sg_count; + mmc_dat.blksz = blk_size; + mmc_dat.blocks = blk_num; + mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ + mmc_cmd.arg = write ? 1<<31 : 0; + mmc_cmd.arg |= (func & 0x7) << 28; + mmc_cmd.arg |= 1<<27; + mmc_cmd.arg |= fifo ? 0 : 1<<26; + mmc_cmd.arg |= (addr & 0x1FFFF) << 9; + mmc_cmd.arg |= blk_num & 0x1FF; + mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; + mmc_req.cmd = &mmc_cmd; + mmc_req.data = &mmc_dat; + if (!fifo) + addr += ttl_len; + + sdio_claim_host(sdio_func); + mmc_set_data_timeout(&mmc_dat, sdio_func->card); + mmc_wait_for_req(host, &mmc_req); + sdio_release_host(sdio_func); + + err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; + if (0 != err_ret) { + sd_err(("%s:CMD53 %s failed with code %d\n", + __FUNCTION__, write ? "write" : "read", err_ret)); + return SDIOH_API_RC_FAIL; + } + } + + sd_trace(("%s: Exit\n", __FUNCTION__)); + return SDIOH_API_RC_SUCCESS; +} + +static SDIOH_API_RC +sdioh_buffer_tofrom_bus(sdioh_info_t *sd, uint fix_inc, uint write, uint func, + uint addr, uint8 *buf, uint len) +{ + bool fifo = (fix_inc == SDIOH_DATA_FIX); + int err_ret = 0; + + sd_trace(("%s: Enter\n", __FUNCTION__)); + ASSERT(buf); + + /* NOTE: + * For all writes, each packet length is aligned to 32 (or 4) + * bytes in dhdsdio_txpkt_preprocess, and for glom the last packet length + * is aligned to block boundary. If you want to align each packet to + * a custom size, please do it in dhdsdio_txpkt_preprocess, NOT here + * + * For reads, the alignment is doen in sdioh_request_buffer. + * + */ + sdio_claim_host(sd->func[func]); + + if ((write) && (!fifo)) + err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); + else if (write) + err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); + else if (fifo) + err_ret = sdio_readsb(sd->func[func], buf, addr, len); + else + err_ret = sdio_memcpy_fromio(sd->func[func], buf, addr, len); + + sdio_release_host(sd->func[func]); + + if (err_ret) + sd_err(("%s: %s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=%d\n", __FUNCTION__, + (write) ? "TX" : "RX", buf, addr, len, err_ret)); + else + sd_trace(("%s: %s xfr'd %p, addr=0x%05x, len=%d\n", __FUNCTION__, + (write) ? "TX" : "RX", buf, addr, len)); + + sd_trace(("%s: Exit\n", __FUNCTION__)); + return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + + +/* + * 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. + * + */ +extern SDIOH_API_RC +sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, + uint addr, uint reg_width, uint buf_len, uint8 *buffer, void *pkt) +{ + SDIOH_API_RC status; + void *tmppkt; + + sd_trace(("%s: Enter\n", __FUNCTION__)); + DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); + DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); + + if (pkt) { + /* packet chain, only used for tx/rx glom, all packets length + * are aligned, total length is a block multiple + */ + if (PKTNEXT(sd->osh, pkt)) + return sdioh_request_packet_chain(sd, fix_inc, write, func, addr, pkt); + + /* non-glom mode, ignore the buffer parameter and use the packet pointer + * (this shouldn't happen) + */ + buffer = PKTDATA(sd->osh, pkt); + buf_len = PKTLEN(sd->osh, pkt); + } + + ASSERT(buffer); + + /* buffer and length are aligned, use it directly so we can avoid memory copy */ + if (((ulong)buffer & DMA_ALIGN_MASK) == 0 && (buf_len & DMA_ALIGN_MASK) == 0) + return sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, buffer, buf_len); + + sd_err(("%s: [%d] doing memory copy buf=%p, len=%d\n", + __FUNCTION__, write, buffer, buf_len)); + + /* otherwise, a memory copy is needed as the input buffer is not aligned */ + tmppkt = PKTGET_STATIC(sd->osh, buf_len + DEFAULT_SDIO_F2_BLKSIZE, write ? TRUE : FALSE); + if (tmppkt == NULL) { + sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, buf_len)); + return SDIOH_API_RC_FAIL; + } + + if (write) + bcopy(buffer, PKTDATA(sd->osh, tmppkt), buf_len); + + status = sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, + PKTDATA(sd->osh, tmppkt), ROUNDUP(buf_len, (DMA_ALIGN_MASK+1))); + + if (!write) + bcopy(PKTDATA(sd->osh, tmppkt), buffer, buf_len); + + PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE); + + return status; +} + +/* this function performs "abort" for both of host & device */ +extern int +sdioh_abort(sdioh_info_t *sd, uint func) +{ +#if defined(MMC_SDIO_ABORT) + char t_func = (char) func; +#endif /* defined(MMC_SDIO_ABORT) */ + sd_trace(("%s: Enter\n", __FUNCTION__)); + +#if defined(MMC_SDIO_ABORT) + /* issue abort cmd52 command through F1 */ + sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); +#endif /* defined(MMC_SDIO_ABORT) */ + + sd_trace(("%s: Exit\n", __FUNCTION__)); + return SDIOH_API_RC_SUCCESS; +} + +/* Reset and re-initialize the device */ +int sdioh_sdio_reset(sdioh_info_t *si) +{ + sd_trace(("%s: Enter\n", __FUNCTION__)); + sd_trace(("%s: Exit\n", __FUNCTION__)); + return SDIOH_API_RC_SUCCESS; +} + +/* Disable device interrupt */ +void +sdioh_sdmmc_devintr_off(sdioh_info_t *sd) +{ + sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); + sd->intmask &= ~CLIENT_INTR; +} + +/* Enable device interrupt */ +void +sdioh_sdmmc_devintr_on(sdioh_info_t *sd) +{ + sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); + sd->intmask |= CLIENT_INTR; +} + +/* Read client card reg */ +int +sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + + if ((func == 0) || (regsize == 1)) { + uint8 temp = 0; + + sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); + *data = temp; + *data &= 0xff; + sd_data(("%s: byte read data=0x%02x\n", + __FUNCTION__, *data)); + } else { + sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize); + if (regsize == 2) + *data &= 0xffff; + + sd_data(("%s: word read data=0x%08x\n", + __FUNCTION__, *data)); + } + + return SUCCESS; +} + +#if !defined(OOB_INTR_ONLY) +/* bcmsdh_sdmmc interrupt handler */ +static void IRQHandler(struct sdio_func *func) +{ + sdioh_info_t *sd; + + sd = sdio_get_drvdata(func); + + ASSERT(sd != NULL); + sdio_release_host(sd->func[0]); + + if (sd->use_client_ints) { + sd->intrcount++; + ASSERT(sd->intr_handler); + ASSERT(sd->intr_handler_arg); + (sd->intr_handler)(sd->intr_handler_arg); + } else { + sd_err(("bcmsdh_sdmmc: ***IRQHandler\n")); + + sd_err(("%s: Not ready for intr: enabled %d, handler %p\n", + __FUNCTION__, sd->client_intr_enabled, sd->intr_handler)); + } + + sdio_claim_host(sd->func[0]); +} + +/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ +static void IRQHandlerF2(struct sdio_func *func) +{ + sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n")); +} +#endif /* !defined(OOB_INTR_ONLY) */ + +#ifdef NOTUSED +/* Write client card reg */ +static int +sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) +{ + + if ((func == 0) || (regsize == 1)) { + uint8 temp; + + temp = data & 0xff; + sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); + sd_data(("%s: byte write data=0x%02x\n", + __FUNCTION__, data)); + } else { + if (regsize == 2) + data &= 0xffff; + + sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); + + sd_data(("%s: word write data=0x%08x\n", + __FUNCTION__, data)); + } + + return SUCCESS; +} +#endif /* NOTUSED */ + +int +sdioh_start(sdioh_info_t *sd, int stage) +{ + int ret; + + if (!sd) { + sd_err(("%s Failed, sd is NULL\n", __FUNCTION__)); + return (0); + } + + /* Need to do this stages as we can't enable the interrupt till + downloading of the firmware is complete, other wise polling + sdio access will come in way + */ + if (sd->func[0]) { + if (stage == 0) { + /* Since the power to the chip is killed, we will have + re enumerate the device again. Set the block size + and enable the fucntion 1 for in preparation for + downloading the code + */ + /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux + 2.6.27. The implementation prior to that is buggy, and needs broadcom's + patch for it + */ + if ((ret = sdio_reset_comm(sd->func[0]->card))) { + sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); + return ret; + } + else { + sd->num_funcs = 2; + sd->sd_blockmode = TRUE; + sd->use_client_ints = TRUE; + sd->client_block_size[0] = 64; + + if (sd->func[1]) { + /* Claim host controller */ + sdio_claim_host(sd->func[1]); + + sd->client_block_size[1] = 64; + ret = sdio_set_block_size(sd->func[1], 64); + if (ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 " + "blocksize(%d)\n", ret)); + } + + /* Release host controller F1 */ + sdio_release_host(sd->func[1]); + } + + if (sd->func[2]) { + /* Claim host controller F2 */ + sdio_claim_host(sd->func[2]); + + sd->client_block_size[2] = sd_f2_blocksize; + ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); + if (ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F2 " + "blocksize to %d(%d)\n", sd_f2_blocksize, ret)); + } + + /* Release host controller F2 */ + sdio_release_host(sd->func[2]); + } + + sdioh_sdmmc_card_enablefuncs(sd); + } + } else { +#if !defined(OOB_INTR_ONLY) + sdio_claim_host(sd->func[0]); + if (sd->func[2]) + sdio_claim_irq(sd->func[2], IRQHandlerF2); + if (sd->func[1]) + sdio_claim_irq(sd->func[1], IRQHandler); + sdio_release_host(sd->func[0]); +#else /* defined(OOB_INTR_ONLY) */ +#if defined(HW_OOB) + sdioh_enable_func_intr(sd); +#endif + bcmsdh_oob_intr_set(sd->bcmsdh, TRUE); +#endif /* !defined(OOB_INTR_ONLY) */ + } + } + else + sd_err(("%s Failed\n", __FUNCTION__)); + + return (0); +} + +int +sdioh_stop(sdioh_info_t *sd) +{ + /* MSM7201A Android sdio stack has bug with interrupt + So internaly within SDIO stack they are polling + which cause issue when device is turned off. So + unregister interrupt with SDIO stack to stop the + polling + */ + if (sd->func[0]) { +#if !defined(OOB_INTR_ONLY) + sdio_claim_host(sd->func[0]); + if (sd->func[1]) + sdio_release_irq(sd->func[1]); + if (sd->func[2]) + sdio_release_irq(sd->func[2]); + sdio_release_host(sd->func[0]); +#else /* defined(OOB_INTR_ONLY) */ +#if defined(HW_OOB) + sdioh_disable_func_intr(sd); +#endif + bcmsdh_oob_intr_set(sd->bcmsdh, FALSE); +#endif /* !defined(OOB_INTR_ONLY) */ + } + else + sd_err(("%s Failed\n", __FUNCTION__)); + return (0); +} + +int +sdioh_waitlockfree(sdioh_info_t *sd) +{ + return (1); +} + + +SDIOH_API_RC +sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) +{ + return SDIOH_API_RC_FAIL; +} + +SDIOH_API_RC +sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) +{ + return SDIOH_API_RC_FAIL; +} + +bool +sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) +{ + return FALSE; +} + +SDIOH_API_RC +sdioh_gpio_init(sdioh_info_t *sd) +{ + return SDIOH_API_RC_FAIL; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c new file mode 100644 index 000000000000..17c42b4f7ac4 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c @@ -0,0 +1,390 @@ +/* + * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh_sdmmc_linux.c 611357 2016-01-11 04:26:56Z $ + */ + +#include +#include +#include /* SDIO Device and Protocol Specs */ +#include /* bcmsdh to/from specific controller APIs */ +#include /* to get msglevel bit values */ + +#include /* request_irq() */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(SDIO_VENDOR_ID_BROADCOM) +#define SDIO_VENDOR_ID_BROADCOM 0x02d0 +#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ + +#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 + +#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) +#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4325) +#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4329) +#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) +#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) +#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) +#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4324) +#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) +#define SDIO_DEVICE_ID_BROADCOM_43239 43239 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ + +extern void wl_cfg80211_set_parent_dev(void *dev); +extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); +extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); +extern void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, + uint bus_num, uint slot_num); +extern int bcmsdh_remove(bcmsdh_info_t *bcmsdh); + +int sdio_function_init(void); +void sdio_function_cleanup(void); + +#define DESCRIPTION "bcmsdh_sdmmc Driver" +#define AUTHOR "Broadcom Corporation" + +/* module param defaults */ +static int clockoverride = 0; + +module_param(clockoverride, int, 0644); +MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); + +/* Maximum number of bcmsdh_sdmmc devices supported by driver */ +#define BCMSDH_SDMMC_MAX_DEVICES 1 + +extern volatile bool dhd_mmc_suspend; + +static int sdioh_probe(struct sdio_func *func) +{ + int host_idx = func->card->host->index; + uint32 rca = func->card->rca; + wifi_adapter_info_t *adapter; + osl_t *osh = NULL; + sdioh_info_t *sdioh = NULL; + + sd_err(("bus num (host idx)=%d, slot num (rca)=%d\n", host_idx, rca)); + adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca); + if (adapter != NULL) + sd_err(("found adapter info '%s'\n", adapter->name)); + else + sd_err(("can't find adapter info for this chip\n")); + +#ifdef WL_CFG80211 + wl_cfg80211_set_parent_dev(&func->dev); +#endif + + /* allocate SDIO Host Controller state info */ + osh = osl_attach(&func->dev, SDIO_BUS, TRUE); + if (osh == NULL) { + sd_err(("%s: osl_attach failed\n", __FUNCTION__)); + goto fail; + } + osl_static_mem_init(osh, adapter); + sdioh = sdioh_attach(osh, func); + if (sdioh == NULL) { + sd_err(("%s: sdioh_attach failed\n", __FUNCTION__)); + goto fail; + } + sdioh->bcmsdh = bcmsdh_probe(osh, &func->dev, sdioh, adapter, SDIO_BUS, host_idx, rca); + if (sdioh->bcmsdh == NULL) { + sd_err(("%s: bcmsdh_probe failed\n", __FUNCTION__)); + goto fail; + } + + sdio_set_drvdata(func, sdioh); + return 0; + +fail: + if (sdioh != NULL) + sdioh_detach(osh, sdioh); + if (osh != NULL) + osl_detach(osh); + return -ENOMEM; +} + +static void sdioh_remove(struct sdio_func *func) +{ + sdioh_info_t *sdioh; + osl_t *osh; + + sdioh = sdio_get_drvdata(func); + if (sdioh == NULL) { + sd_err(("%s: error, no sdioh handler found\n", __FUNCTION__)); + return; + } + + osh = sdioh->osh; + bcmsdh_remove(sdioh->bcmsdh); + sdioh_detach(osh, sdioh); + osl_detach(osh); +} + +static int bcmsdh_sdmmc_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret = 0; + + if (func == NULL) + return -EINVAL; + + sd_err(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); + sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); + sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); + sd_info(("sdio_device: 0x%04x\n", func->device)); + sd_info(("Function#: 0x%04x\n", func->num)); + + /* 4318 doesn't have function 2 */ + if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) + ret = sdioh_probe(func); + + return ret; +} + +static void bcmsdh_sdmmc_remove(struct sdio_func *func) +{ + if (func == NULL) { + sd_err(("%s is called with NULL SDIO function pointer\n", __FUNCTION__)); + return; + } + + sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); + sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); + sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); + sd_info(("sdio_device: 0x%04x\n", func->device)); + sd_info(("Function#: 0x%04x\n", func->num)); + + if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) + sdioh_remove(func); +} + +/* devices we support, null terminated */ +static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, + { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) +static int bcmsdh_sdmmc_suspend(struct device *pdev) +{ + int err; + sdioh_info_t *sdioh; + struct sdio_func *func = dev_to_sdio_func(pdev); + mmc_pm_flag_t sdio_flags; + + sd_err(("%s Enter\n", __FUNCTION__)); + if (func->num != 2) + return 0; + + dhd_mmc_suspend = TRUE; + sdioh = sdio_get_drvdata(func); + err = bcmsdh_suspend(sdioh->bcmsdh); + if (err) { + dhd_mmc_suspend = FALSE; + return err; + } + sdio_flags = sdio_get_host_pm_caps(func); + if (!(sdio_flags & MMC_PM_KEEP_POWER)) { + sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__)); + dhd_mmc_suspend = FALSE; + return -EINVAL; + } + + /* keep power while host suspended */ + err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (err) { + sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); + dhd_mmc_suspend = FALSE; + return err; + } +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE); +#endif + smp_mb(); + + return 0; +} + +static int bcmsdh_sdmmc_resume(struct device *pdev) +{ + sdioh_info_t *sdioh; + struct sdio_func *func = dev_to_sdio_func(pdev); + + sd_err(("%s Enter\n", __FUNCTION__)); + if (func->num != 2) + return 0; + + sdioh = sdio_get_drvdata(func); + dhd_mmc_suspend = FALSE; +#if defined(OOB_INTR_ONLY) + bcmsdh_resume(sdioh->bcmsdh); +#endif + + smp_mb(); + return 0; +} + +static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { + .suspend = bcmsdh_sdmmc_suspend, + .resume = bcmsdh_sdmmc_resume, +}; +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ + +#if defined(BCMLXSDMMC) +static struct semaphore *notify_semaphore = NULL; + +static int dummy_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + if (func && (func->num != 2)) { + return 0; + } + + if (notify_semaphore) + up(notify_semaphore); + return 0; +} + +static void dummy_remove(struct sdio_func *func) +{ +} + +static struct sdio_driver dummy_sdmmc_driver = { + .probe = dummy_probe, + .remove = dummy_remove, + .name = "dummy_sdmmc", + .id_table = bcmsdh_sdmmc_ids, + }; + +int sdio_func_reg_notify(void* semaphore) +{ + notify_semaphore = semaphore; + return sdio_register_driver(&dummy_sdmmc_driver); +} + +void sdio_func_unreg_notify(void) +{ + OSL_SLEEP(15); + sdio_unregister_driver(&dummy_sdmmc_driver); +} + +#endif /* defined(BCMLXSDMMC) */ + +static struct sdio_driver bcmsdh_sdmmc_driver = { + .probe = bcmsdh_sdmmc_probe, + .remove = bcmsdh_sdmmc_remove, + .name = "bcmsdh_sdmmc", + .id_table = bcmsdh_sdmmc_ids, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) + .drv = { + .pm = &bcmsdh_sdmmc_pm_ops, + }, +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ + }; + +struct sdos_info { + sdioh_info_t *sd; + spinlock_t lock; +}; + +/* Interrupt enable/disable */ +SDIOH_API_RC +sdioh_interrupt_set(sdioh_info_t *sd, bool enable) +{ + if (!sd) + return BCME_BADARG; + + sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); + return SDIOH_API_RC_SUCCESS; +} + +#ifdef BCMSDH_MODULE +static int __init +bcmsdh_module_init(void) +{ + int error = 0; + error = sdio_function_init(); + return error; +} + +static void __exit +bcmsdh_module_cleanup(void) +{ + sdio_function_cleanup(); +} + +module_init(bcmsdh_module_init); +module_exit(bcmsdh_module_cleanup); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(DESCRIPTION); +MODULE_AUTHOR(AUTHOR); + +#endif /* BCMSDH_MODULE */ +/* + * module init +*/ +int bcmsdh_register_client_driver(void) +{ + return sdio_register_driver(&bcmsdh_sdmmc_driver); +} + +/* + * module cleanup +*/ +void bcmsdh_unregister_client_driver(void) +{ + sdio_unregister_driver(&bcmsdh_sdmmc_driver); +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c new file mode 100644 index 000000000000..5f152518cd8e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c @@ -0,0 +1,249 @@ +/* + * Broadcom SPI Host Controller Driver - Linux Per-port + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdspi_linux.c 406045 2013-06-05 22:09:52Z $ + */ + +#include +#include + +#include /* bcmsdh to/from specific controller APIs */ +#include /* to get msglevel bit values */ + +#include +#include /* SDIO Device and Protocol Specs */ +#include /* request_irq(), free_irq() */ +#include +#include + +extern uint sd_crc; +module_param(sd_crc, uint, 0); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define KERNEL26 +#endif + +struct sdos_info { + sdioh_info_t *sd; + spinlock_t lock; + wait_queue_head_t intr_wait_queue; +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define BLOCKABLE() (!in_atomic()) +#else +#define BLOCKABLE() (!in_interrupt()) +#endif + +/* Interrupt handler */ +static irqreturn_t +sdspi_isr(int irq, void *dev_id +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +, struct pt_regs *ptregs +#endif +) +{ + sdioh_info_t *sd; + struct sdos_info *sdos; + bool ours; + + sd = (sdioh_info_t *)dev_id; + sd->local_intrcount++; + + if (!sd->card_init_done) { + sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq)); + return IRQ_RETVAL(FALSE); + } else { + ours = spi_check_client_intr(sd, NULL); + + /* For local interrupts, wake the waiting process */ + if (ours && sd->got_hcint) { + sdos = (struct sdos_info *)sd->sdos_info; + wake_up_interruptible(&sdos->intr_wait_queue); + } + + return IRQ_RETVAL(ours); + } +} + + +/* Register with Linux for interrupts */ +int +spi_register_irq(sdioh_info_t *sd, uint irq) +{ + sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq)); + if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) { + sd_err(("%s: request_irq() failed\n", __FUNCTION__)); + return ERROR; + } + return SUCCESS; +} + +/* Free Linux irq */ +void +spi_free_irq(uint irq, sdioh_info_t *sd) +{ + free_irq(irq, sd); +} + +/* Map Host controller registers */ +uint32 * +spi_reg_map(osl_t *osh, uintptr addr, int size) +{ + return (uint32 *)REG_MAP(addr, size); +} + +void +spi_reg_unmap(osl_t *osh, uintptr addr, int size) +{ + REG_UNMAP((void*)(uintptr)addr); +} + +int +spi_osinit(sdioh_info_t *sd) +{ + struct sdos_info *sdos; + + sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); + sd->sdos_info = (void*)sdos; + if (sdos == NULL) + return BCME_NOMEM; + + sdos->sd = sd; + spin_lock_init(&sdos->lock); + init_waitqueue_head(&sdos->intr_wait_queue); + return BCME_OK; +} + +void +spi_osfree(sdioh_info_t *sd) +{ + struct sdos_info *sdos; + ASSERT(sd && sd->sdos_info); + + sdos = (struct sdos_info *)sd->sdos_info; + MFREE(sd->osh, sdos, sizeof(struct sdos_info)); +} + +/* Interrupt enable/disable */ +SDIOH_API_RC +sdioh_interrupt_set(sdioh_info_t *sd, bool enable) +{ + ulong flags; + struct sdos_info *sdos; + + sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); + + sdos = (struct sdos_info *)sd->sdos_info; + ASSERT(sdos); + + if (!(sd->host_init_done && sd->card_init_done)) { + sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { + sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__)); + return SDIOH_API_RC_FAIL; + } + + /* Ensure atomicity for enable/disable calls */ + spin_lock_irqsave(&sdos->lock, flags); + + sd->client_intr_enabled = enable; + if (enable && !sd->lockcount) + spi_devintr_on(sd); + else + spi_devintr_off(sd); + + spin_unlock_irqrestore(&sdos->lock, flags); + + return SDIOH_API_RC_SUCCESS; +} + +/* Protect against reentrancy (disable device interrupts while executing) */ +void +spi_lock(sdioh_info_t *sd) +{ + ulong flags; + struct sdos_info *sdos; + + sdos = (struct sdos_info *)sd->sdos_info; + ASSERT(sdos); + + sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount)); + + spin_lock_irqsave(&sdos->lock, flags); + if (sd->lockcount) { + sd_err(("%s: Already locked!\n", __FUNCTION__)); + ASSERT(sd->lockcount == 0); + } + spi_devintr_off(sd); + sd->lockcount++; + spin_unlock_irqrestore(&sdos->lock, flags); +} + +/* Enable client interrupt */ +void +spi_unlock(sdioh_info_t *sd) +{ + ulong flags; + struct sdos_info *sdos; + + sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled)); + ASSERT(sd->lockcount > 0); + + sdos = (struct sdos_info *)sd->sdos_info; + ASSERT(sdos); + + spin_lock_irqsave(&sdos->lock, flags); + if (--sd->lockcount == 0 && sd->client_intr_enabled) { + spi_devintr_on(sd); + } + spin_unlock_irqrestore(&sdos->lock, flags); +} + +void spi_waitbits(sdioh_info_t *sd, bool yield) +{ +#ifndef BCMSDYIELD + ASSERT(!yield); +#endif + sd_trace(("%s: yield %d canblock %d\n", + __FUNCTION__, yield, BLOCKABLE())); + + /* Clear the "interrupt happened" flag and last intrstatus */ + sd->got_hcint = FALSE; + +#ifdef BCMSDYIELD + if (yield && BLOCKABLE()) { + struct sdos_info *sdos; + sdos = (struct sdos_info *)sd->sdos_info; + /* Wait for the indication, the interrupt will be masked when the ISR fires. */ + wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint)); + } else +#endif /* BCMSDYIELD */ + { + spi_spinbits(sd); + } + +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c new file mode 100644 index 000000000000..19cd1828eaf5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c @@ -0,0 +1,1810 @@ +/* + * Broadcom BCMSDH to gSPI Protocol Conversion Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmspibrcm.c 373331 2012-12-07 04:46:22Z $ + */ + +#define HSMODE + +#include + +#include +#include +#include +#include +#include +#include +#include +#include /* SDIO device core hardware definitions. */ +#include + +#include /* bcmsdh to/from specific controller APIs */ +#include /* ioctl/iovars */ +#include /* SDIO Device and Protocol Specs */ + +#include + + +#include +#include + +/* these are for the older cores... for newer cores we have control for each of them */ +#define F0_RESPONSE_DELAY 16 +#define F1_RESPONSE_DELAY 16 +#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY + + +#define GSPI_F0_RESP_DELAY 0 +#define GSPI_F1_RESP_DELAY F1_RESPONSE_DELAY +#define GSPI_F2_RESP_DELAY 0 +#define GSPI_F3_RESP_DELAY 0 + +#define CMDLEN 4 + +#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE) + +/* Globals */ +#if defined(DHD_DEBUG) +uint sd_msglevel = SDH_ERROR_VAL; +#else +uint sd_msglevel = 0; +#endif + +uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ +uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ +uint sd_f2_blocksize = 64; /* Default blocksize */ + + +uint sd_divisor = 2; +uint sd_power = 1; /* Default to SD Slot powered ON */ +uint sd_clock = 1; /* Default to SD Clock turned ON */ +uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ +uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ + +uint8 spi_outbuf[SPI_MAX_PKT_LEN]; +uint8 spi_inbuf[SPI_MAX_PKT_LEN]; + +/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits + * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. + */ +#define BUF2_PKT_LEN 128 +uint8 spi_outbuf2[BUF2_PKT_LEN]; +uint8 spi_inbuf2[BUF2_PKT_LEN]; + +#define SPISWAP_WD4(x) bcmswap32(x); +#define SPISWAP_WD2(x) (bcmswap16(x & 0xffff)) | \ + (bcmswap16((x & 0xffff0000) >> 16) << 16); + +/* Prototypes */ +static bool bcmspi_test_card(sdioh_info_t *sd); +static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); +static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); +static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen); +static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 *data); +static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 data); +static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, + uint8 *data); +static int bcmspi_driver_init(sdioh_info_t *sd); +static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data); +static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, + uint32 *data); +static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); +static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); + +/* + * Public entry points & extern's + */ +extern sdioh_info_t * +sdioh_attach(osl_t *osh, void *bar0, uint irq) +{ + sdioh_info_t *sd; + + sd_trace(("%s\n", __FUNCTION__)); + if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { + sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); + return NULL; + } + bzero((char *)sd, sizeof(sdioh_info_t)); + sd->osh = osh; + if (spi_osinit(sd) != 0) { + sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; + } + + sd->bar0 = bar0; + sd->irq = irq; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; + sd->intr_handler_valid = FALSE; + + /* Set defaults */ + sd->use_client_ints = TRUE; + sd->sd_use_dma = FALSE; /* DMA Not supported */ + + /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit + * mode + */ + sd->wordlen = 2; + + + if (!spi_hw_attach(sd)) { + sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + if (bcmspi_driver_init(sd) != SUCCESS) { + sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + if (spi_register_irq(sd, irq) != SUCCESS) { + sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + sd_trace(("%s: Done\n", __FUNCTION__)); + + return sd; +} + +extern SDIOH_API_RC +sdioh_detach(osl_t *osh, sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if (sd) { + sd_err(("%s: detaching from hardware\n", __FUNCTION__)); + spi_free_irq(sd->irq, sd); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + } + return SDIOH_API_RC_SUCCESS; +} + +/* Configure callback to client when we recieve client interrupt */ +extern SDIOH_API_RC +sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); +#if !defined(OOB_INTR_ONLY) + sd->intr_handler = fn; + sd->intr_handler_arg = argh; + sd->intr_handler_valid = TRUE; +#endif /* !defined(OOB_INTR_ONLY) */ + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_deregister(sdioh_info_t *sd) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); +#if !defined(OOB_INTR_ONLY) + sd->intr_handler_valid = FALSE; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; +#endif /* !defined(OOB_INTR_ONLY) */ + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + *onoff = sd->client_intr_enabled; + return SDIOH_API_RC_SUCCESS; +} + +#if defined(DHD_DEBUG) +extern bool +sdioh_interrupt_pending(sdioh_info_t *sd) +{ + return 0; +} +#endif + +extern SDIOH_API_RC +sdioh_query_device(sdioh_info_t *sd) +{ + /* Return a BRCM ID appropriate to the dongle class */ + return (sd->num_funcs > 1) ? BCM4329_D11N_ID : BCM4318_D11G_ID; +} + +/* Provide dstatus bits of spi-transaction for dhd layers. */ +extern uint32 +sdioh_get_dstatus(sdioh_info_t *sd) +{ + return sd->card_dstatus; +} + +extern void +sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) +{ + sd->chip = chip; + sd->chiprev = chiprev; +} + +extern void +sdioh_dwordmode(sdioh_info_t *sd, bool set) +{ + uint8 reg = 0; + int status; + + if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } + + if (set) { + reg |= DWORD_PKT_LEN_EN; + sd->dwordmode = TRUE; + sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ + } else { + reg &= ~DWORD_PKT_LEN_EN; + sd->dwordmode = FALSE; + sd->client_block_size[SPI_FUNC_2] = 2048; + } + + if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } +} + + +uint +sdioh_query_iofnum(sdioh_info_t *sd) +{ + return sd->num_funcs; +} + +/* IOVar table */ +enum { + IOV_MSGLEVEL = 1, + IOV_BLOCKMODE, + IOV_BLOCKSIZE, + IOV_DMA, + IOV_USEINTS, + IOV_NUMINTS, + IOV_NUMLOCALINTS, + IOV_HOSTREG, + IOV_DEVREG, + IOV_DIVISOR, + IOV_SDMODE, + IOV_HISPEED, + IOV_HCIREGS, + IOV_POWER, + IOV_CLOCK, + IOV_SPIERRSTATS, + IOV_RESP_DELAY_ALL +}; + +const bcm_iovar_t sdioh_iovars[] = { + {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, + {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ + {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, + {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, + {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, + {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, + {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, + {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, + {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, + {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, + {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, + {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, + {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +int +sdioh_iovar_op(sdioh_info_t *si, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + int32 int_val = 0; + bool bool_val; + uint32 actionid; +/* + sdioh_regs_t *regs; +*/ + + ASSERT(name); + ASSERT(len >= 0); + + /* Get must have return space; Set does not take qualifiers */ + ASSERT(set || (arg && len)); + ASSERT(!set || (!params && !plen)); + + sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); + + if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { + bcmerror = BCME_UNSUPPORTED; + goto exit; + } + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) + goto exit; + + /* Set up params so get and set can share the convenience variables */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + val_size = sizeof(int); + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + switch (actionid) { + case IOV_GVAL(IOV_MSGLEVEL): + int_val = (int32)sd_msglevel; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MSGLEVEL): + sd_msglevel = int_val; + break; + + case IOV_GVAL(IOV_BLOCKSIZE): + if ((uint32)int_val > si->num_funcs) { + bcmerror = BCME_BADARG; + break; + } + int_val = (int32)si->client_block_size[int_val]; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_DMA): + int_val = (int32)si->sd_use_dma; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DMA): + si->sd_use_dma = (bool)int_val; + break; + + case IOV_GVAL(IOV_USEINTS): + int_val = (int32)si->use_client_ints; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_USEINTS): + break; + + case IOV_GVAL(IOV_DIVISOR): + int_val = (uint32)sd_divisor; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DIVISOR): + sd_divisor = int_val; + if (!spi_start_clock(si, (uint16)sd_divisor)) { + sd_err(("%s: set clock failed\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + } + break; + + case IOV_GVAL(IOV_POWER): + int_val = (uint32)sd_power; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_POWER): + sd_power = int_val; + break; + + case IOV_GVAL(IOV_CLOCK): + int_val = (uint32)sd_clock; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_CLOCK): + sd_clock = int_val; + break; + + case IOV_GVAL(IOV_SDMODE): + int_val = (uint32)sd_sdmode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDMODE): + sd_sdmode = int_val; + break; + + case IOV_GVAL(IOV_HISPEED): + int_val = (uint32)sd_hiok; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_HISPEED): + sd_hiok = int_val; + + if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { + sd_err(("%s: Failed changing highspeed mode to %d.\n", + __FUNCTION__, sd_hiok)); + bcmerror = BCME_ERROR; + return ERROR; + } + break; + + case IOV_GVAL(IOV_NUMINTS): + int_val = (int32)si->intrcount; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_NUMLOCALINTS): + int_val = (int32)si->local_intrcount; + bcopy(&int_val, arg, val_size); + break; + case IOV_GVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data; + + if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + + int_val = (int)data; + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data = (uint8)sd_ptr->value; + + if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + } + + + case IOV_GVAL(IOV_SPIERRSTATS): + { + bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); + break; + } + + case IOV_SVAL(IOV_SPIERRSTATS): + { + bzero(&si->spierrstats, sizeof(struct spierrstats_t)); + break; + } + + case IOV_GVAL(IOV_RESP_DELAY_ALL): + int_val = (int32)si->resp_delay_all; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RESP_DELAY_ALL): + si->resp_delay_all = (bool)int_val; + int_val = STATUS_ENABLE|INTR_WITH_STATUS; + if (si->resp_delay_all) + int_val |= RESP_DELAY_ALL; + else { + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, + F1_RESPONSE_DELAY) != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + } + + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) + != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } +exit: + + return bcmerror; +} + +extern SDIOH_API_RC +sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + SDIOH_API_RC status; + /* No lock needed since sdioh_request_byte does locking */ + status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + /* No lock needed since sdioh_request_byte does locking */ + SDIOH_API_RC status; + + if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { + uint8 dummy_data; + status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); + if (status) { + sd_err(("sdioh_cfg_read() failed.\n")); + return status; + } + } + + status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) +{ + uint32 count; + int offset; + uint32 cis_byte; + uint16 *cis = (uint16 *)cisd; + uint bar0 = SI_ENUM_BASE; + int status; + uint8 data; + + sd_trace(("%s: Func %d\n", __FUNCTION__, func)); + + spi_lock(sd); + + /* Set sb window address to 0x18000000 */ + data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); + if (status == SUCCESS) { + data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + if (status == SUCCESS) { + data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + offset = CC_SROM_OTP; /* OTP offset in chipcommon. */ + for (count = 0; count < length/2; count++) { + if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { + sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + *cis = (uint16)cis_byte; + cis++; + offset += 2; + } + + spi_unlock(sd); + + return (BCME_OK); +} + +extern SDIOH_API_RC +sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + spi_lock(sd); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + if (rw == SDIOH_READ) { + sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr)); + } else { + sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr, data)); + } + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) { + spi_unlock(sd); + return status; + } + + if (rw == SDIOH_READ) { + *byte = (uint8)data; + sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *byte)); + } + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus=0x%x\n", dstatus)); + + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, + uint32 *word, uint nbytes) +{ + int status; + + spi_lock(sd); + + if (rw == SDIOH_READ) + status = bcmspi_card_regread(sd, func, addr, nbytes, word); + else + status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); + + spi_unlock(sd); + return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + +extern SDIOH_API_RC +sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, + uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) +{ + int len; + int buflen = (int)buflen_u; + bool fifo = (fix_inc == SDIOH_DATA_FIX); + + spi_lock(sd); + + ASSERT(reg_width == 4); + ASSERT(buflen_u < (1 << 30)); + ASSERT(sd->client_block_size[func]); + + sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", + __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', + buflen_u, sd->r_cnt, sd->t_cnt, pkt)); + + /* Break buffer down into blocksize chunks. */ + while (buflen > 0) { + len = MIN(sd->client_block_size[func], buflen); + if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { + sd_err(("%s: bcmspi_card_buf %s failed\n", + __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); + spi_unlock(sd); + return SDIOH_API_RC_FAIL; + } + buffer += len; + buflen -= len; + if (!fifo) + addr += len; + } + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. + * Its main aim is to have simpler spi writes rather than recursive writes. + * e.g. When there is a need to program response delay on the fly after detecting the SPI-func + * this call will allow to program the response delay. + */ +static int +bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) +{ + uint32 cmd_arg; + uint32 datalen = 1; + uint32 hostlen; + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf2 = SPISWAP_WD4(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)spi_outbuf2 = SPISWAP_WD2(cmd_arg); + if (datalen & 0x1) + datalen++; + } else { + sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (datalen != 0) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD4(byte); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD2(byte); + } + } + + /* +4 for cmd, +4 for dstatus */ + hostlen = datalen + 8; + hostlen += (4 - (hostlen & 0x3)); + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +/* Program the response delay corresponding to the spi function */ +static int +bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) +{ + if (sd->resp_delay_all == FALSE) + return (BCME_OK); + + if (sd->prev_fun == func) + return (BCME_OK); + + if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) + return (BCME_OK); + + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); + + /* Remember function for which to avoid reprogramming resp-delay in next iteration */ + sd->prev_fun = func; + + return (BCME_OK); + +} + +#define GSPI_RESYNC_PATTERN 0x0 + +/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. + * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is + * synchronised and all queued resuests are cancelled. + */ +static int +bcmspi_resync_f1(sdioh_info_t *sd) +{ + uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + *(uint32 *)spi_outbuf2 = cmd_arg; + + /* for Write, put the data into the output buffer */ + *(uint32 *)&spi_outbuf2[CMDLEN] = data; + + /* +4 for cmd, +4 for dstatus */ + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +uint32 dstatus_count = 0; + +static int +bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) +{ + uint32 dstatus = sd->card_dstatus; + struct spierrstats_t *spierrstats = &sd->spierrstats; + int err = SUCCESS; + + sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); + + /* Store dstatus of last few gSPI transactions */ + spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; + spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; + dstatus_count++; + + if (sd->card_init_done == FALSE) + return err; + + if (dstatus & STATUS_DATA_NOT_AVAILABLE) { + spierrstats->dna++; + sd_trace(("Read data not available on F1 addr = 0x%x\n", + GFIELD(cmd_arg, SPI_REG_ADDR))); + /* Clear dna bit */ + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); + } + + if (dstatus & STATUS_UNDERFLOW) { + spierrstats->rdunderflow++; + sd_err(("FIFO underflow happened due to current F2 read command.\n")); + } + + if (dstatus & STATUS_OVERFLOW) { + spierrstats->wroverflow++; + sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); + bcmspi_resync_f1(sd); + sd_err(("Recovering from F1 FIFO overflow.\n")); + } + + if (dstatus & STATUS_F2_INTR) { + spierrstats->f2interrupt++; + sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_F3_INTR) { + spierrstats->f3interrupt++; + sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_HOST_CMD_DATA_ERR) { + spierrstats->hostcmddataerr++; + sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); + } + + if (dstatus & STATUS_F2_PKT_AVAILABLE) { + spierrstats->f2pktavailable++; + sd_trace(("Packet is available/ready in F2 TX FIFO\n")); + sd_trace(("Packet length = %d\n", sd->dwordmode ? + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); + } + + if (dstatus & STATUS_F3_PKT_AVAILABLE) { + spierrstats->f3pktavailable++; + sd_err(("Packet is available/ready in F3 TX FIFO\n")); + sd_err(("Packet length = %d\n", + (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); + } + + return err; +} + +extern int +sdioh_abort(sdioh_info_t *sd, uint func) +{ + return 0; +} + +int +sdioh_start(sdioh_info_t *sd, int stage) +{ + return SUCCESS; +} + +int +sdioh_stop(sdioh_info_t *sd) +{ + return SUCCESS; +} + +int +sdioh_waitlockfree(sdioh_info_t *sd) +{ + return SUCCESS; +} + + +/* + * Private/Static work routines + */ +static int +bcmspi_host_init(sdioh_info_t *sd) +{ + + /* Default power on mode */ + sd->sd_mode = SDIOH_MODE_SPI; + sd->polled_mode = TRUE; + sd->host_init_done = TRUE; + sd->card_init_done = FALSE; + sd->adapter_slot = 1; + + return (SUCCESS); +} + +static int +get_client_blocksize(sdioh_info_t *sd) +{ + uint32 regdata[2]; + int status; + + /* Find F1/F2/F3 max packet size */ + if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, + 8, regdata)) != SUCCESS) { + return status; + } + + sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", + regdata[0], regdata[1])); + + sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; + sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); + ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); + + sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; + sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); + ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); + + sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; + sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); + ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); + + return 0; +} + +static int +bcmspi_client_init(sdioh_info_t *sd) +{ + uint32 status_en_reg = 0; + sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); + +#ifdef HSMODE + if (!spi_start_clock(sd, (uint16)sd_divisor)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#else + /* Start at ~400KHz clock rate for initialization */ + if (!spi_start_clock(sd, 128)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* HSMODE */ + + if (!bcmspi_host_device_init_adapt(sd)) { + sd_err(("bcmspi_host_device_init_adapt failed\n")); + return ERROR; + } + + if (!bcmspi_test_card(sd)) { + sd_err(("bcmspi_test_card failed\n")); + return ERROR; + } + + sd->num_funcs = SPI_MAX_IOFUNCS; + + get_client_blocksize(sd); + + /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ + bcmspi_resync_f1(sd); + + sd->dwordmode = FALSE; + + bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); + + sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); + status_en_reg |= INTR_WITH_STATUS; + + if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, + status_en_reg & 0xff) != SUCCESS) { + sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); + return ERROR; + } + +#ifndef HSMODE + /* After configuring for High-Speed mode, set the desired clock rate. */ + if (!spi_start_clock(sd, 4)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* HSMODE */ + + /* check to see if the response delay needs to be programmed properly */ + { + uint32 f1_respdelay = 0; + bcmspi_card_regread(sd, 0, SPID_RESP_DELAY_F1, 1, &f1_respdelay); + if ((f1_respdelay == 0) || (f1_respdelay == 0xFF)) { + /* older sdiodevice core and has no separte resp delay for each of */ + sd_err(("older corerev < 4 so use the same resp delay for all funcs\n")); + sd->resp_delay_new = FALSE; + } + else { + /* older sdiodevice core and has no separte resp delay for each of */ + int ret_val; + sd->resp_delay_new = TRUE; + sd_err(("new corerev >= 4 so set the resp delay for each of the funcs\n")); + sd_trace(("resp delay for funcs f0(%d), f1(%d), f2(%d), f3(%d)\n", + GSPI_F0_RESP_DELAY, GSPI_F1_RESP_DELAY, + GSPI_F2_RESP_DELAY, GSPI_F3_RESP_DELAY)); + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F0, 1, + GSPI_F0_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F0\n", __FUNCTION__)); + return ERROR; + } + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F1, 1, + GSPI_F1_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F1\n", __FUNCTION__)); + return ERROR; + } + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F2, 1, + GSPI_F2_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); + return ERROR; + } + ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F3, 1, + GSPI_F3_RESP_DELAY); + if (ret_val != SUCCESS) { + sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); + return ERROR; + } + } + } + + + sd->card_init_done = TRUE; + + /* get the device rev to program the prop respdelays */ + + return SUCCESS; +} + +static int +bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, + 4, ®data)) != SUCCESS) + return status; + + sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); + + + if (hsmode == TRUE) { + sd_trace(("Attempting to enable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + sd_trace(("Device is already in High-Speed mode.\n")); + return status; + } else { + regdata |= HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) { + return status; + } + } + } else { + sd_trace(("Attempting to disable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + regdata &= ~HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) + return status; + } + else { + sd_trace(("Device is already in Low-Speed mode.\n")); + return status; + } + } + spi_controller_highspeed_mode(sd, hsmode); + + return TRUE; +} + +#define bcmspi_find_curr_mode(sd) { \ + sd->wordlen = 2; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd->wordlen = 4; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd_trace(("Silicon testability issue: regdata = 0x%x." \ + " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ + OSL_DELAY(100000); \ +} + +#define INIT_ADAPT_LOOP 100 + +/* Adapt clock-phase-speed-bitwidth between host and device */ +static bool +bcmspi_host_device_init_adapt(sdioh_info_t *sd) +{ + uint32 wrregdata, regdata = 0; + int status; + int i; + + /* Due to a silicon testability issue, the first command from the Host + * to the device will get corrupted (first bit will be lost). So the + * Host should poll the device with a safe read request. ie: The Host + * should try to read F0 addr 0x14 using the Fixed address mode + * (This will prevent a unintended write command to be detected by device) + */ + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + /* If device was not power-cycled it will stay in 32bit mode with + * response-delay-all bit set. Alternate the iteration so that + * read either with or without response-delay for F0 to succeed. + */ + bcmspi_find_curr_mode(sd); + sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = TRUE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = FALSE; + } + + /* Bail out, device not detected */ + if (i == INIT_ADAPT_LOOP) + return FALSE; + + /* Softreset the spid logic */ + if ((sd->dwordmode) || (sd->wordlen == 4)) { + bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); + bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); + sd_trace(("reset reg read = 0x%x\n", regdata)); + sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, + sd->wordlen, sd->resp_delay_all)); + /* Restore default state after softreset */ + sd->wordlen = 2; + sd->dwordmode = FALSE; + } + + if (sd->wordlen == 4) { + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != + SUCCESS) + return FALSE; + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", + regdata)); + sd_trace(("Spid power was left on.\n")); + } else { + sd_err(("Spid power was left on but signature read failed." + " Value read = 0x%x\n", regdata)); + return FALSE; + } + } else { + sd->wordlen = 2; + +#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ + + wrregdata = (CTRL_REG_DEFAULT); + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); + +#ifndef HSMODE + wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); + wrregdata &= ~HIGH_SPEED_MODE; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); +#endif /* HSMODE */ + + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { + sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, + ®data)) != SUCCESS) + return FALSE; + } + OSL_DELAY(1000); + } + + /* Change to host controller intr-polarity of active-low */ + wrregdata &= ~INTR_POLARITY; + sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", + wrregdata)); + /* Change to 32bit mode */ + wrregdata |= WORD_LENGTH_32; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); + + /* Change command/data packaging in 32bit LE mode */ + sd->wordlen = 4; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); + sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); + } else { + sd_err(("Stale spid reg values read as it was kept powered. Value read =" + "0x%x\n", regdata)); + return FALSE; + } + } + + + return TRUE; +} + +static bool +bcmspi_test_card(sdioh_info_t *sd) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == (TEST_RO_DATA_32BIT_LE)) + sd_trace(("32bit LE regdata = 0x%x\n", regdata)); + else { + sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); + return FALSE; + } + + +#define RW_PATTERN1 0xA0A1A2A3 +#define RW_PATTERN2 0x4B5B6B7B + + regdata = RW_PATTERN1; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN1) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN1, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + regdata = RW_PATTERN2; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN2) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN2, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + return TRUE; +} + +static int +bcmspi_driver_init(sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if ((bcmspi_host_init(sd)) != SUCCESS) { + return ERROR; + } + + if (bcmspi_client_init(sd) != SUCCESS) { + return ERROR; + } + + return SUCCESS; +} + +/* Read device reg */ +static int +bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", + __FUNCTION__, cmd_arg, func, regaddr, regsize)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +static int +bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + + int status; + uint32 cmd_arg; + uint32 dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); + + sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", + __FUNCTION__, cmd_arg, func, regaddr, regsize)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) + return status; + + sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *data)); + + bcmspi_cmd_getdstatus(sd, &dstatus); + sd_trace(("dstatus =0x%x\n", dstatus)); + return SUCCESS; +} + +/* write a device register */ +static int +bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d data=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr, regsize, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus=0x%x\n", dstatus)); + + return SUCCESS; +} + +/* write a device register - 1 byte */ +static int +bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", + __FUNCTION__, cmd_arg, func, regaddr, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +void +bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) +{ + *dstatus_buffer = sd->card_dstatus; +} + +/* 'data' is of type uint32 whereas other buffers are of type uint8 */ +static int +bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen) +{ + uint32 i, j; + uint8 resp_delay = 0; + int err = SUCCESS; + uint32 hostlen; + uint32 spilen = 0; + uint32 dstatus_idx = 0; + uint16 templen, buslen, len, *ptr = NULL; + + sd_trace(("spi cmd = 0x%x\n", cmd_arg)); + + if (DWORDMODE_ON) { + spilen = GFIELD(cmd_arg, SPI_LEN); + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) || + (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1)) + dstatus_idx = spilen * 3; + + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + spilen = spilen << 2; + dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0; + /* convert len to mod16 size */ + spilen = ROUNDUP(spilen, 16); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } + } + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf = SPISWAP_WD4(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)spi_outbuf = SPISWAP_WD2(cmd_arg); + if (datalen & 0x1) + datalen++; + if (datalen < 4) + datalen = ROUNDUP(datalen, 4); + } else { + sd_err(("Host is %d bit spid, could not create SPI command.\n", + 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { + /* We send len field of hw-header always a mod16 size, both from host and dongle */ + if (DWORDMODE_ON) { + if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + /* ASSERT(*ptr == ~*(ptr + 1)); */ + templen = ROUNDUP(templen, 16); + *ptr = templen; + sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1)))); + } + } + + if (datalen != 0) { + for (i = 0; i < datalen/4; i++) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = + SPISWAP_WD4(data[i]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = + SPISWAP_WD2(data[i]); + } + } + } + } + + /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ + if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 0)) { + int func = GFIELD(cmd_arg, SPI_FUNCTION); + switch (func) { + case 0: + if (sd->resp_delay_new) + resp_delay = GSPI_F0_RESP_DELAY; + else + resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; + break; + case 1: + if (sd->resp_delay_new) + resp_delay = GSPI_F1_RESP_DELAY; + else + resp_delay = F1_RESPONSE_DELAY; + break; + case 2: + if (sd->resp_delay_new) + resp_delay = GSPI_F2_RESP_DELAY; + else + resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; + break; + default: + ASSERT(0); + break; + } + /* Program response delay */ + if (sd->resp_delay_new == FALSE) + bcmspi_prog_resp_delay(sd, func, resp_delay); + } + + /* +4 for cmd and +4 for dstatus */ + hostlen = datalen + 8 + resp_delay; + hostlen += dstatus_idx; + hostlen += (4 - (hostlen & 0x3)); + spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); + + /* for Read, get the data into the input buffer */ + if (datalen != 0) { + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ + for (j = 0; j < datalen/4; j++) { + if (sd->wordlen == 4) { /* 32bit spid */ + data[j] = SPISWAP_WD4(*(uint32 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + data[j] = SPISWAP_WD2(*(uint32 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay]); + } + } + + if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + buslen = len = ~(*(ptr + 1)); + buslen = ROUNDUP(buslen, 16); + /* populate actual len in hw-header */ + if (templen == buslen) + *ptr = len; + } + } + } + + /* Restore back the len field of the hw header */ + if (DWORDMODE_ON) { + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + ptr = (uint16 *)&data[0]; + *ptr = (uint16)(~*(ptr+1)); + } + } + + dstatus_idx += (datalen + CMDLEN + resp_delay); + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf[dstatus_idx]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf[dstatus_idx]); + } else { + sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", + 8 * sd->wordlen)); + return ERROR; + } + if (sd->card_dstatus == 0xffffffff) { + sd_err(("looks like not a GSPI device or device is not powered.\n")); + } + + err = bcmspi_update_stats(sd, cmd_arg); + + return err; + +} + +static int +bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data) +{ + int status; + uint32 cmd_arg; + bool write = rw == SDIOH_READ ? 0 : 1; + uint retries = 0; + + bool enable; + uint32 spilen; + + cmd_arg = 0; + + ASSERT(nbytes); + ASSERT(nbytes <= sd->client_block_size[func]); + + if (write) sd->t_cnt++; else sd->r_cnt++; + + if (func == 2) { + /* Frame len check limited by gSPI. */ + if ((nbytes > 2000) && write) { + sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); + } + /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ + /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ + if (write) { + uint32 dstatus; + /* check F2 ready with cached one */ + bcmspi_cmd_getdstatus(sd, &dstatus); + if ((dstatus & STATUS_F2_RX_READY) == 0) { + retries = WAIT_F2RXFIFORDY; + enable = 0; + while (retries-- && !enable) { + OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); + bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, + &dstatus); + if (dstatus & STATUS_F2_RX_READY) + enable = TRUE; + } + if (!enable) { + struct spierrstats_t *spierrstats = &sd->spierrstats; + spierrstats->f2rxnotready++; + sd_err(("F2 FIFO is not ready to receive data.\n")); + return ERROR; + } + sd_trace(("No of retries on F2 ready %d\n", + (WAIT_F2RXFIFORDY - retries))); + } + } + } + + /* F2 transfers happen on 0 addr */ + addr = (func == 2) ? 0 : addr; + + /* In pio mode buffer is read using fixed address fifo in func 1 */ + if ((func == 1) && (fifo)) + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); + else + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); + + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); + spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); + if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + /* convert len to mod4 size */ + spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } else + cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); + + if ((func == 2) && (fifo == 1)) { + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + } + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, nbytes)) != SUCCESS) { + sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, + (write ? "write" : "read"))); + return status; + } + + /* gSPI expects that hw-header-len is equal to spi-command-len */ + if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { + ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); + ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); + } + + if ((nbytes > 2000) && !write) { + sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); + } + + return SUCCESS; +} + +/* Reset and re-initialize the device */ +int +sdioh_sdio_reset(sdioh_info_t *si) +{ + si->card_init_done = FALSE; + return bcmspi_client_init(si); +} + +SDIOH_API_RC +sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) +{ + return SDIOH_API_RC_FAIL; +} + +SDIOH_API_RC +sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) +{ + return SDIOH_API_RC_FAIL; +} + +bool +sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) +{ + return FALSE; +} + +SDIOH_API_RC +sdioh_gpio_init(sdioh_info_t *sd) +{ + return SDIOH_API_RC_FAIL; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c new file mode 100644 index 000000000000..6b1a5f7c0d42 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c @@ -0,0 +1,3092 @@ +/* + * Driver O/S-independent utility routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: bcmutils.c 701450 2017-05-25 02:10:23Z $ + */ + +#include +#include +#include +#include +#ifdef BCMDRIVER + +#include +#include + +#else /* !BCMDRIVER */ + +#include +#include +#include + +#if defined(BCMEXTSUP) +#include +#endif + +#ifndef ASSERT +#define ASSERT(exp) +#endif + +#endif /* !BCMDRIVER */ + +#include +#include +#include +#include +#include +#include +#include + + +void *_bcmutils_dummy_fn = NULL; + + + +#ifdef BCMDRIVER + + + +/* copy a pkt buffer chain into a buffer */ +uint +pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) +{ + uint n, ret = 0; + + if (len < 0) + len = 4096; /* "infinite" */ + + /* skip 'offset' bytes */ + for (; p && offset; p = PKTNEXT(osh, p)) { + if (offset < (uint)PKTLEN(osh, p)) + break; + offset -= PKTLEN(osh, p); + } + + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = PKTNEXT(osh, p)) { + n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); + bcopy(PKTDATA(osh, p) + offset, buf, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; +} + +/* copy a buffer into a pkt buffer chain */ +uint +pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) +{ + uint n, ret = 0; + + + /* skip 'offset' bytes */ + for (; p && offset; p = PKTNEXT(osh, p)) { + if (offset < (uint)PKTLEN(osh, p)) + break; + offset -= PKTLEN(osh, p); + } + + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = PKTNEXT(osh, p)) { + n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); + bcopy(buf, PKTDATA(osh, p) + offset, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; +} + + + +/* return total length of buffer chain */ +uint BCMFASTPATH +pkttotlen(osl_t *osh, void *p) +{ + uint total; + int len; + + total = 0; + for (; p; p = PKTNEXT(osh, p)) { + len = PKTLEN(osh, p); + total += len; +#ifdef BCMLFRAG + if (BCMLFRAG_ENAB()) { + if (PKTISFRAG(osh, p)) { + total += PKTFRAGTOTLEN(osh, p); + } + } +#endif + } + + return (total); +} + +/* return the last buffer of chained pkt */ +void * +pktlast(osl_t *osh, void *p) +{ + for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) + ; + + return (p); +} + +/* count segments of a chained packet */ +uint BCMFASTPATH +pktsegcnt(osl_t *osh, void *p) +{ + uint cnt; + + for (cnt = 0; p; p = PKTNEXT(osh, p)) { + cnt++; +#ifdef BCMLFRAG + if (BCMLFRAG_ENAB()) { + if (PKTISFRAG(osh, p)) { + cnt += PKTFRAGTOTNUM(osh, p); + } + } +#endif + } + + return cnt; +} + + +/* count segments of a chained packet */ +uint BCMFASTPATH +pktsegcnt_war(osl_t *osh, void *p) +{ + uint cnt; + uint8 *pktdata; + uint len, remain, align64; + + for (cnt = 0; p; p = PKTNEXT(osh, p)) { + cnt++; + len = PKTLEN(osh, p); + if (len > 128) { + pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ + /* Check for page boundary straddle (2048B) */ + if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) + cnt++; + + align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ + align64 = (64 - align64) & 0x3f; + len -= align64; /* bytes from aligned 64B to end */ + /* if aligned to 128B, check for MOD 128 between 1 to 4B */ + remain = len % 128; + if (remain > 0 && remain <= 4) + cnt++; /* add extra seg */ + } + } + + return cnt; +} + +uint8 * BCMFASTPATH +pktdataoffset(osl_t *osh, void *p, uint offset) +{ + uint total = pkttotlen(osh, p); + uint pkt_off = 0, len = 0; + uint8 *pdata = (uint8 *) PKTDATA(osh, p); + + if (offset > total) + return NULL; + + for (; p; p = PKTNEXT(osh, p)) { + pdata = (uint8 *) PKTDATA(osh, p); + pkt_off = offset - len; + len += PKTLEN(osh, p); + if (len > offset) + break; + } + return (uint8*) (pdata+pkt_off); +} + + +/* given a offset in pdata, find the pkt seg hdr */ +void * +pktoffset(osl_t *osh, void *p, uint offset) +{ + uint total = pkttotlen(osh, p); + uint len = 0; + + if (offset > total) + return NULL; + + for (; p; p = PKTNEXT(osh, p)) { + len += PKTLEN(osh, p); + if (len > offset) + break; + } + return p; +} + +/* + * osl multiple-precedence packet queue + * hi_prec is always >= the number of the highest non-empty precedence + */ +void * BCMFASTPATH +pktq_penq(struct pktq *pq, int prec, void *p) +{ + struct pktq_prec *q; + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + if (q->head) + PKTSETLINK(q->tail, p); + else + q->head = p; + + q->tail = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + return p; +} + +void * BCMFASTPATH +pktq_penq_head(struct pktq *pq, int prec, void *p) +{ + struct pktq_prec *q; + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + if (q->head == NULL) + q->tail = p; + + PKTSETLINK(p, q->head); + q->head = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + return p; +} + +void * BCMFASTPATH +pktq_pdeq(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if (prev_p == NULL) + return NULL; + + if ((p = PKTLINK(prev_p)) == NULL) + return NULL; + + q->len--; + + pq->len--; + + PKTSETLINK(prev_p, PKTLINK(p)); + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg) +{ + struct pktq_prec *q; + void *p, *prev = NULL; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + p = q->head; + + while (p) { + if (fn == NULL || (*fn)(p, arg)) { + break; + } else { + prev = p; + p = PKTLINK(p); + } + } + if (p == NULL) + return NULL; + + if (prev == NULL) { + if ((q->head = PKTLINK(p)) == NULL) { + q->tail = NULL; + } + } else { + PKTSETLINK(prev, PKTLINK(p)); + if (q->tail == p) { + q->tail = prev; + } + } + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_pdeq_tail(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + void *p, *prev; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + for (prev = NULL; p != q->tail; p = PKTLINK(p)) + prev = p; + + if (prev) + PKTSETLINK(prev, NULL); + else + q->head = NULL; + + q->tail = prev; + q->len--; + + pq->len--; + + return p; +} + +void +pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) +{ + struct pktq_prec *q; + void *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 = PKTLINK(p); + else + PKTSETLINK(prev, PKTLINK(p)); + PKTSETLINK(p, NULL); + PKTFREE(osh, p, dir); + q->len--; + pq->len--; + p = (head ? q->head : PKTLINK(prev)); + } else { + prev = p; + p = PKTLINK(p); + } + } + + if (q->head == NULL) { + ASSERT(q->len == 0); + q->tail = NULL; + } +} + +bool BCMFASTPATH +pktq_pdel(struct pktq *pq, void *pktbuf, int prec) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + if (!pktbuf) + return FALSE; + + q = &pq->q[prec]; + + if (q->head == pktbuf) { + if ((q->head = PKTLINK(pktbuf)) == NULL) + q->tail = NULL; + } else { + for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) + ; + if (p == NULL) + return FALSE; + + PKTSETLINK(p, PKTLINK(pktbuf)); + if (q->tail == pktbuf) + q->tail = p; + } + + q->len--; + pq->len--; + PKTSETLINK(pktbuf, NULL); + return TRUE; +} + +void +pktq_init(struct pktq *pq, int num_prec, int max_len) +{ + int prec; + + ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); + + /* pq is variable size; only zero out what's requested */ + bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); + + pq->num_prec = (uint16)num_prec; + + pq->max = (uint16)max_len; + + for (prec = 0; prec < num_prec; prec++) + pq->q[prec].max = pq->max; +} + +void +pktq_set_max_plen(struct pktq *pq, int prec, int max_len) +{ + ASSERT(prec >= 0 && prec < pq->num_prec); + + if (prec < pq->num_prec) + pq->q[prec].max = (uint16)max_len; +} + +void * BCMFASTPATH +pktq_deq(struct pktq *pq, int *prec_out) +{ + struct pktq_prec *q; + void *p; + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + pq->len--; + + if (prec_out) + *prec_out = prec; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_deq_tail(struct pktq *pq, int *prec_out) +{ + struct pktq_prec *q; + void *p, *prev; + int prec; + + if (pq->len == 0) + return NULL; + + for (prec = 0; prec < pq->hi_prec; prec++) + if (pq->q[prec].head) + break; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + for (prev = NULL; p != q->tail; p = PKTLINK(p)) + prev = p; + + if (prev) + PKTSETLINK(prev, NULL); + else + q->head = NULL; + + q->tail = prev; + q->len--; + + pq->len--; + + if (prec_out) + *prec_out = prec; + + PKTSETLINK(p, NULL); + + return p; +} + +void * +pktq_peek(struct pktq *pq, int *prec_out) +{ + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + if (prec_out) + *prec_out = prec; + + return (pq->q[prec].head); +} + +void * +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); +} + +void +pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) +{ + int prec; + + /* Optimize flush, if pktq len = 0, just return. + * pktq len of 0 means pktq's prec q's are all empty. + */ + if (pq->len == 0) { + return; + } + + for (prec = 0; prec < pq->num_prec; prec++) + pktq_pflush(osh, pq, prec, dir, fn, arg); + if (fn == NULL) + ASSERT(pq->len == 0); +} + +/* Return sum of lengths of a specific set of precedences */ +int +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; +} + +/* Priority peek from a specific set of precedences */ +void * BCMFASTPATH +pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) +{ + struct pktq_prec *q; + void *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]; + + if ((p = q->head) == NULL) + return NULL; + + if (prec_out) + *prec_out = prec; + + return p; +} +/* Priority dequeue from a specific set of precedences */ +void * BCMFASTPATH +pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) +{ + struct pktq_prec *q; + void *p; + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) + if (prec-- == 0) + return NULL; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + if (prec_out) + *prec_out = prec; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +#endif /* BCMDRIVER */ + +#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) +const unsigned char bcm_ctype[] = { + + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ + _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, + _BCM_C, /* 8-15 */ + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ + _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ + _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ + _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ + _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ + _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, + _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ + _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, + _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ + _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ + _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ + _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ + _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ +}; + +ulong +bcm_strtoul(const char *cp, char **endp, uint base) +{ + ulong result, last_result = 0, value; + bool minus; + + minus = FALSE; + + while (bcm_isspace(*cp)) + cp++; + + if (cp[0] == '+') + cp++; + else if (cp[0] == '-') { + minus = TRUE; + cp++; + } + + if (base == 0) { + if (cp[0] == '0') { + if ((cp[1] == 'x') || (cp[1] == 'X')) { + base = 16; + cp = &cp[2]; + } else { + base = 8; + cp = &cp[1]; + } + } else + base = 10; + } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { + cp = &cp[2]; + } + + result = 0; + + while (bcm_isxdigit(*cp) && + (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { + result = result*base + value; + /* Detected overflow */ + if (result < last_result && !minus) + return (ulong)-1; + last_result = result; + cp++; + } + + if (minus) + result = (ulong)(-(long)result); + + if (endp) + *endp = DISCARD_QUAL(cp, char); + + return (result); +} + +int +bcm_atoi(const char *s) +{ + return (int)bcm_strtoul(s, NULL, 10); +} + +/* return pointer to location of substring 'needle' in 'haystack' */ +char * +bcmstrstr(const char *haystack, const char *needle) +{ + int len, nlen; + int i; + + if ((haystack == NULL) || (needle == NULL)) + return DISCARD_QUAL(haystack, char); + + nlen = strlen(needle); + len = strlen(haystack) - nlen + 1; + + for (i = 0; i < len; i++) + if (memcmp(needle, &haystack[i], nlen) == 0) + return DISCARD_QUAL(&haystack[i], char); + return (NULL); +} + +char * +bcmstrcat(char *dest, const char *src) +{ + char *p; + + p = dest + strlen(dest); + + while ((*p++ = *src++) != '\0') + ; + + return (dest); +} + +char * +bcmstrncat(char *dest, const char *src, uint size) +{ + char *endp; + char *p; + + p = dest + strlen(dest); + endp = p + size; + + while (p != endp && (*p++ = *src++) != '\0') + ; + + return (dest); +} + + +/**************************************************************************** +* Function: bcmstrtok +* +* Purpose: +* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), +* but allows strToken() to be used by different strings or callers at the same +* time. Each call modifies '*string' by substituting a NULL character for the +* first delimiter that is encountered, and updates 'string' to point to the char +* after the delimiter. Leading delimiters are skipped. +* +* Parameters: +* string (mod) Ptr to string ptr, updated by token. +* delimiters (in) Set of delimiter characters. +* tokdelim (out) Character that delimits the returned token. (May +* be set to NULL if token delimiter is not required). +* +* Returns: Pointer to the next token found. NULL when no more tokens are found. +***************************************************************************** +*/ +char * +bcmstrtok(char **string, const char *delimiters, char *tokdelim) +{ + unsigned char *str; + unsigned long map[8]; + int count; + char *nextoken; + + if (tokdelim != NULL) { + /* Prime the token delimiter */ + *tokdelim = '\0'; + } + + /* Clear control map */ + for (count = 0; count < 8; count++) { + map[count] = 0; + } + + /* Set bits in delimiter table */ + do { + map[*delimiters >> 5] |= (1 << (*delimiters & 31)); + } + while (*delimiters++); + + str = (unsigned char*)*string; + + /* Find beginning of token (skip over leading delimiters). Note that + * there is no token iff this loop sets str to point to the terminal + * null (*str == '\0') + */ + while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { + str++; + } + + nextoken = (char*)str; + + /* Find the end of the token. If it is not the end of the string, + * put a null there. + */ + for (; *str; str++) { + if (map[*str >> 5] & (1 << (*str & 31))) { + if (tokdelim != NULL) { + *tokdelim = *str; + } + + *str++ = '\0'; + break; + } + } + + *string = (char*)str; + + /* Determine if a token has been found. */ + if (nextoken == (char *) str) { + return NULL; + } + else { + return nextoken; + } +} + + +#define xToLower(C) \ + ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) + + +/**************************************************************************** +* Function: bcmstricmp +* +* Purpose: Compare to strings case insensitively. +* +* Parameters: s1 (in) First string to compare. +* s2 (in) Second string to compare. +* +* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if +* t1 > t2, when ignoring case sensitivity. +***************************************************************************** +*/ +int +bcmstricmp(const char *s1, const char *s2) +{ + char dc, sc; + + while (*s2 && *s1) { + dc = xToLower(*s1); + sc = xToLower(*s2); + if (dc < sc) return -1; + if (dc > sc) return 1; + s1++; + s2++; + } + + if (*s1 && !*s2) return 1; + if (!*s1 && *s2) return -1; + return 0; +} + + +/**************************************************************************** +* Function: bcmstrnicmp +* +* Purpose: Compare to strings case insensitively, upto a max of 'cnt' +* characters. +* +* Parameters: s1 (in) First string to compare. +* s2 (in) Second string to compare. +* cnt (in) Max characters to compare. +* +* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if +* t1 > t2, when ignoring case sensitivity. +***************************************************************************** +*/ +int +bcmstrnicmp(const char* s1, const char* s2, int cnt) +{ + char dc, sc; + + while (*s2 && *s1 && cnt) { + dc = xToLower(*s1); + sc = xToLower(*s2); + if (dc < sc) return -1; + if (dc > sc) return 1; + s1++; + s2++; + cnt--; + } + + if (!cnt) return 0; + if (*s1 && !*s2) return 1; + if (!*s1 && *s2) return -1; + return 0; +} + +/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ +int +bcm_ether_atoe(const char *p, struct ether_addr *ea) +{ + int i = 0; + char *ep; + + for (;;) { + ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); + p = ep; + if (!*p++ || i == 6) + break; + } + + return (i == 6); +} + +int +bcm_atoipv4(const char *p, struct ipv4_addr *ip) +{ + + int i = 0; + char *c; + for (;;) { + ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0); + if (*c++ != '.' || i == IPV4_ADDR_LEN) + break; + p = c; + } + return (i == IPV4_ADDR_LEN); +} +#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ + + +#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) +/* registry routine buffer preparation utility functions: + * parameter order is like strncpy, but returns count + * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) + */ +ulong +wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) +{ + ulong copyct = 1; + ushort i; + + if (abuflen == 0) + return 0; + + /* wbuflen is in bytes */ + wbuflen /= sizeof(ushort); + + for (i = 0; i < wbuflen; ++i) { + if (--abuflen == 0) + break; + *abuf++ = (char) *wbuf++; + ++copyct; + } + *abuf = '\0'; + + return copyct; +} +#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ + +char * +bcm_ether_ntoa(const struct ether_addr *ea, char *buf) +{ + static const char hex[] = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + const uint8 *octet = ea->octet; + char *p = buf; + int i; + + for (i = 0; i < 6; i++, octet++) { + *p++ = hex[(*octet >> 4) & 0xf]; + *p++ = hex[*octet & 0xf]; + *p++ = ':'; + } + + *(p-1) = '\0'; + + return (buf); +} + +char * +bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) +{ + snprintf(buf, 16, "%d.%d.%d.%d", + ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); + return (buf); +} + +char * +bcm_ipv6_ntoa(void *ipv6, char *buf) +{ + /* Implementing RFC 5952 Sections 4 + 5 */ + /* Not thoroughly tested */ + uint16 tmp[8]; + uint16 *a = &tmp[0]; + char *p = buf; + int i, i_max = -1, cnt = 0, cnt_max = 1; + uint8 *a4 = NULL; + memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN); + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if (a[i]) { + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + cnt = 0; + } else + cnt++; + } + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + if (i_max == 0 && + /* IPv4-translated: ::ffff:0:a.b.c.d */ + ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || + /* IPv4-mapped: ::ffff:a.b.c.d */ + (cnt_max == 5 && a[5] == 0xffff))) + a4 = (uint8*) (a + 6); + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if ((uint8*) (a + i) == a4) { + snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); + break; + } else if (i == i_max) { + *p++ = ':'; + i += cnt_max - 1; + p[0] = ':'; + p[1] = '\0'; + } else { + if (i) + *p++ = ':'; + p += snprintf(p, 8, "%x", ntoh16(a[i])); + } + } + + return buf; +} +#ifdef BCMDRIVER + +void +bcm_mdelay(uint ms) +{ + uint i; + + for (i = 0; i < ms; i++) { + OSL_DELAY(1000); + } +} + + + + + +#if defined(DHD_DEBUG) +/* pretty hex print a pkt buffer chain */ +void +prpkt(const char *msg, osl_t *osh, void *p0) +{ + void *p; + + if (msg && (msg[0] != '\0')) + printf("%s:\n", msg); + + for (p = p0; p; p = PKTNEXT(osh, p)) + prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); +} +#endif + +/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. + * Also updates the inplace vlan tag if requested. + * For debugging, it returns an indication of what it did. + */ +uint BCMFASTPATH +pktsetprio(void *pkt, bool update_vtag) +{ + struct ether_header *eh; + struct ethervlan_header *evh; + uint8 *pktdata; + int priority = 0; + int rc = 0; + + pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); + ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); + + eh = (struct ether_header *) pktdata; + + if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { + uint16 vlan_tag; + int vlan_prio, dscp_prio = 0; + + evh = (struct ethervlan_header *)eh; + + vlan_tag = ntoh16(evh->vlan_tag); + vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; + + if (evh->ether_type == hton16(ETHER_TYPE_IP)) { + uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); + uint8 tos_tc = IP_TOS46(ip_body); + dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + } + + /* DSCP priority gets precedence over 802.1P (vlan tag) */ + if (dscp_prio != 0) { + priority = dscp_prio; + rc |= PKTPRIO_VDSCP; + } else { + priority = vlan_prio; + rc |= PKTPRIO_VLAN; + } + /* + * If the DSCP priority is not the same as the VLAN priority, + * then overwrite the priority field in the vlan tag, with the + * DSCP priority value. This is required for Linux APs because + * the VLAN driver on Linux, overwrites the skb->priority field + * with the priority value in the vlan tag + */ + if (update_vtag && (priority != vlan_prio)) { + vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); + vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; + evh->vlan_tag = hton16(vlan_tag); + rc |= PKTPRIO_UPD; + } +#ifdef DHD_LOSSLESS_ROAMING + } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { + priority = PRIO_8021D_NC; + rc = PKTPRIO_DSCP; +#endif /* DHD_LOSSLESS_ROAMING */ + } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) { + uint8 *ip_body = pktdata + sizeof(struct ether_header); + uint8 tos_tc = IP_TOS46(ip_body); + uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; + switch (dscp) { + case DSCP_EF: + priority = PRIO_8021D_VO; + break; + case DSCP_AF31: + case DSCP_AF32: + case DSCP_AF33: + priority = PRIO_8021D_CL; + break; + case DSCP_AF21: + case DSCP_AF22: + case DSCP_AF23: + case DSCP_AF11: + case DSCP_AF12: + case DSCP_AF13: + priority = PRIO_8021D_EE; + break; + default: + priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + break; + } + + rc |= PKTPRIO_DSCP; + } + + ASSERT(priority >= 0 && priority <= MAXPRIO); + PKTSETPRIO(pkt, priority); + return (rc | priority); +} + + +static char bcm_undeferrstr[32]; +static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; + +/* Convert the error codes into related error strings */ +const char * +bcmerrorstr(int bcmerror) +{ + /* check if someone added a bcmerror code but forgot to add errorstring */ + ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); + + if (bcmerror > 0 || bcmerror < BCME_LAST) { + snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); + return bcm_undeferrstr; + } + + ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); + + return bcmerrorstrtable[-bcmerror]; +} + + + +/* iovar table lookup */ +const bcm_iovar_t* +bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) +{ + const bcm_iovar_t *vi; + const char *lookup_name; + + /* skip any ':' delimited option prefixes */ + lookup_name = strrchr(name, ':'); + if (lookup_name != NULL) + lookup_name++; + else + lookup_name = name; + + ASSERT(table != NULL); + + for (vi = table; vi->name; vi++) { + if (!strcmp(vi->name, lookup_name)) + return vi; + } + /* ran to end of table */ + + return NULL; /* var name not found */ +} + +int +bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) +{ + int bcmerror = 0; + + /* length check on io buf */ + switch (vi->type) { + case IOVT_BOOL: + case IOVT_INT8: + case IOVT_INT16: + case IOVT_INT32: + case IOVT_UINT8: + case IOVT_UINT16: + case IOVT_UINT32: + /* all integers are int32 sized args at the ioctl interface */ + if (len < (int)sizeof(int)) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_BUFFER: + /* buffer must meet minimum length requirement */ + if (len < vi->minlen) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_VOID: + if (!set) { + /* Cannot return nil... */ + bcmerror = BCME_UNSUPPORTED; + } else if (len) { + /* Set is an action w/o parameters */ + bcmerror = BCME_BUFTOOLONG; + } + break; + + default: + /* unknown type for length check in iovar info */ + ASSERT(0); + bcmerror = BCME_UNSUPPORTED; + } + + return bcmerror; +} + +#endif /* BCMDRIVER */ + + +uint8 * +bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst) +{ + uint8 *new_dst = dst; + bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst; + + /* dst buffer should always be valid */ + ASSERT(dst); + + /* data len must be within valid range */ + ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)); + + /* source data buffer pointer should be valid, unless datalen is 0 + * meaning no data with this TLV + */ + ASSERT((data != NULL) || (datalen == 0)); + + /* only do work if the inputs are valid + * - must have a dst to write to AND + * - datalen must be within range AND + * - the source data pointer must be non-NULL if datalen is non-zero + * (this last condition detects datalen > 0 with a NULL data pointer) + */ + if ((dst != NULL) && + ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) && + ((data != NULL) || (datalen == 0))) { + + /* write type, len fields */ + dst_tlv->id = (uint8)type; + dst_tlv->len = (uint8)datalen; + + /* if data is present, copy to the output buffer and update + * pointer to output buffer + */ + if (datalen > 0) { + + memcpy(dst_tlv->data, data, datalen); + } + + /* update the output destination poitner to point past + * the TLV written + */ + new_dst = dst + BCM_TLV_HDR_SIZE + datalen; + } + + return (new_dst); +} + +uint8 * +bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen) +{ + uint8 *new_dst = dst; + + if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) { + + /* if len + tlv hdr len is more than destlen, don't do anything + * just return the buffer untouched + */ + if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) { + + new_dst = bcm_write_tlv(type, data, datalen, dst); + } + } + + return (new_dst); +} + +uint8 * +bcm_copy_tlv(const void *src, uint8 *dst) +{ + uint8 *new_dst = dst; + const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; + uint totlen; + + ASSERT(dst && src); + if (dst && src) { + + totlen = BCM_TLV_HDR_SIZE + src_tlv->len; + memcpy(dst, src_tlv, totlen); + new_dst = dst + totlen; + } + + return (new_dst); +} + + +uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen) +{ + uint8 *new_dst = dst; + const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; + + ASSERT(src); + if (src) { + if (bcm_valid_tlv(src_tlv, dst_maxlen)) { + new_dst = bcm_copy_tlv(src, dst); + } + } + + return (new_dst); +} + + +#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) +/******************************************************************************* + * crc8 + * + * Computes a crc8 over the input data using the polynomial: + * + * x^8 + x^7 +x^6 + x^4 + x^2 + 1 + * + * The caller provides the initial value (either CRC8_INIT_VALUE + * or the previous returned value) to allow for processing of + * discontiguous blocks of data. When generating the CRC the + * caller is responsible for complementing the final return value + * and inserting it into the byte stream. When checking, a final + * return value of CRC8_GOOD_VALUE indicates a valid CRC. + * + * Reference: Dallas Semiconductor Application Note 27 + * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", + * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., + * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt + * + * **************************************************************************** + */ + +static const uint8 crc8_table[256] = { + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F +}; + +#define CRC_INNER_LOOP(n, c, x) \ + (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] + +uint8 +hndcrc8( + uint8 *pdata, /* pointer to array of data to process */ + uint nbytes, /* number of input data bytes to process */ + uint8 crc /* either CRC8_INIT_VALUE or previous return value */ +) +{ + /* hard code the crc loop instead of using CRC_INNER_LOOP macro + * to avoid the undefined and unnecessary (uint8 >> 8) operation. + */ + while (nbytes-- > 0) + crc = crc8_table[(crc ^ *pdata++) & 0xff]; + + return crc; +} + +/******************************************************************************* + * crc16 + * + * Computes a crc16 over the input data using the polynomial: + * + * x^16 + x^12 +x^5 + 1 + * + * The caller provides the initial value (either CRC16_INIT_VALUE + * or the previous returned value) to allow for processing of + * discontiguous blocks of data. When generating the CRC the + * caller is responsible for complementing the final return value + * and inserting it into the byte stream. When checking, a final + * return value of CRC16_GOOD_VALUE indicates a valid CRC. + * + * Reference: Dallas Semiconductor Application Note 27 + * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", + * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., + * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt + * + * **************************************************************************** + */ + +static const uint16 crc16_table[256] = { + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, + 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, + 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, + 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, + 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, + 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, + 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, + 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, + 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, + 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, + 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, + 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, + 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, + 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, + 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, + 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, + 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, + 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, + 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, + 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, + 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, + 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, + 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, + 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, + 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, + 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, + 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, + 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, + 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, + 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, + 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, + 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 +}; + +uint16 +hndcrc16( + uint8 *pdata, /* pointer to array of data to process */ + uint nbytes, /* number of input data bytes to process */ + uint16 crc /* either CRC16_INIT_VALUE or previous return value */ +) +{ + while (nbytes-- > 0) + CRC_INNER_LOOP(16, crc, *pdata++); + return crc; +} + +static const uint32 crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +/* + * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if + * accumulating over multiple pieces. + */ +uint32 +hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) +{ + uint8 *pend; + pend = pdata + nbytes; + while (pdata < pend) + CRC_INNER_LOOP(32, crc, *pdata++); + + return crc; +} + +#ifdef notdef +#define CLEN 1499 /* CRC Length */ +#define CBUFSIZ (CLEN+4) +#define CNBUFS 5 /* # of bufs */ + +void +testcrc32(void) +{ + uint j, k, l; + uint8 *buf; + uint len[CNBUFS]; + uint32 crcr; + uint32 crc32tv[CNBUFS] = + {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; + + ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); + + /* step through all possible alignments */ + for (l = 0; l <= 4; l++) { + for (j = 0; j < CNBUFS; j++) { + len[j] = CLEN; + for (k = 0; k < len[j]; k++) + *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; + } + + for (j = 0; j < CNBUFS; j++) { + crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); + ASSERT(crcr == crc32tv[j]); + } + } + + MFREE(buf, CBUFSIZ*CNBUFS); + return; +} +#endif /* notdef */ + +/* + * Advance from the current 1-byte tag/1-byte length/variable-length value + * triple, to the next, returning a pointer to the next. + * If the current or next TLV is invalid (does not fit in given buffer length), + * NULL is returned. + * *buflen is not modified if the TLV elt parameter is invalid, or is decremented + * by the TLV parameter's length if it is valid. + */ +bcm_tlv_t * +bcm_next_tlv(bcm_tlv_t *elt, int *buflen) +{ + int len; + + /* validate current elt */ + if (!bcm_valid_tlv(elt, *buflen)) { + return NULL; + } + + /* advance to next elt */ + len = elt->len; + elt = (bcm_tlv_t*)(elt->data + len); + *buflen -= (TLV_HDR_LEN + len); + + /* validate next elt */ + if (!bcm_valid_tlv(elt, *buflen)) { + return NULL; + } + + return elt; +} + +/* + * 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 + */ +bcm_tlv_t * +bcm_parse_tlvs(void *buf, int buflen, uint key) +{ + bcm_tlv_t *elt; + int totlen; + + elt = (bcm_tlv_t*)buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= TLV_HDR_LEN) { + int len = elt->len; + + /* validate remaining totlen */ + if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { + + return (elt); + } + + elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + + return NULL; +} + +/* + * 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. Stop parsing when we see an element whose ID is greater + * than the target key. + */ +bcm_tlv_t * +bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) +{ + bcm_tlv_t *elt; + int totlen; + + elt = (bcm_tlv_t*)buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= TLV_HDR_LEN) { + uint id = elt->id; + int len = elt->len; + + /* Punt if we start seeing IDs > than target key */ + if (id > key) { + return (NULL); + } + + /* validate remaining totlen */ + if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { + return (elt); + } + + elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + return NULL; +} +#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ + +#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ + defined(DHD_DEBUG) +int +bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len) +{ + int i, slen = 0; + uint32 bit, mask; + const char *name; + mask = bd->mask; + if (len < 2 || !buf) + return 0; + + buf[0] = '\0'; + + for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) { + bit = bd->bitfield[i].bit; + if ((flags & mask) == bit) { + if (len > (int)strlen(name)) { + slen = strlen(name); + strncpy(buf, name, slen+1); + } + break; + } + } + return slen; +} + +int +bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) +{ + int i; + char* p = buf; + char hexstr[16]; + int slen = 0, nlen = 0; + uint32 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, " "); + } + + /* 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 + +/* print bytes formatted as hex to a string. return the resulting string length */ +int +bcm_format_hex(char *str, const void *bytes, int len) +{ + int i; + char *p = str; + const uint8 *src = (const uint8*)bytes; + + for (i = 0; i < len; i++) { + p += snprintf(p, 3, "%02X", *src); + src++; + } + return (int)(p - str); +} + +/* pretty hex print a contiguous buffer */ +void +prhex(const char *msg, uchar *buf, uint nbytes) +{ + char line[128], *p; + int len = sizeof(line); + int nchar; + uint i; + + if (msg && (msg[0] != '\0')) + printf("%s:\n", msg); + + p = line; + for (i = 0; i < nbytes; i++) { + if (i % 16 == 0) { + nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ + p += nchar; + len -= nchar; + } + if (len > 0) { + nchar = snprintf(p, len, "%02x ", buf[i]); + p += nchar; + len -= nchar; + } + + if (i % 16 == 15) { + printf("%s\n", line); /* flush line */ + p = line; + len = sizeof(line); + } + } + + /* flush last partial line */ + if (p != line) + printf("%s\n", line); +} + +static const char *crypto_algo_names[] = { + "NONE", + "WEP1", + "TKIP", + "WEP128", + "AES_CCM", + "AES_OCB_MSDU", + "AES_OCB_MPDU", +#ifdef BCMCCX + "CKIP", + "CKIP_MMH", + "WEP_MMH", + "NALG", +#else + "NALG", + "UNDEF", + "UNDEF", + "UNDEF", +#endif /* BCMCCX */ + "WAPI", + "PMK", + "BIP", + "AES_GCM", + "AES_CCM256", + "AES_GCM256", + "BIP_CMAC256", + "BIP_GMAC", + "BIP_GMAC256", + "UNDEF" +}; + +const char * +bcm_crypto_algo_name(uint algo) +{ + return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; +} + + +char * +bcm_chipname(uint chipid, char *buf, uint len) +{ + const char *fmt; + + fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; + snprintf(buf, len, fmt, chipid); + return buf; +} + +/* Produce a human-readable string for boardrev */ +char * +bcm_brev_str(uint32 brev, char *buf) +{ + if (brev < 0x100) + snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); + else + snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); + + return (buf); +} + +#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ + +/* dump large strings to console */ +void +printbig(char *buf) +{ + uint len, max_len; + char c; + + len = strlen(buf); + + max_len = BUFSIZE_TODUMP_ATONCE; + + while (len > max_len) { + c = buf[max_len]; + buf[max_len] = '\0'; + printf("%s", buf); + buf[max_len] = c; + + buf += max_len; + len -= max_len; + } + /* print the remaining string */ + printf("%s\n", buf); + return; +} + +/* routine to dump fields in a fileddesc structure */ +uint +bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, + char *buf, uint32 bufsize) +{ + uint filled_len; + int len; + struct fielddesc *cur_ptr; + + filled_len = 0; + cur_ptr = fielddesc_array; + + while (bufsize > 1) { + if (cur_ptr->nameandfmt == NULL) + break; + len = snprintf(buf, bufsize, cur_ptr->nameandfmt, + read_rtn(arg0, arg1, cur_ptr->offset)); + /* check for snprintf overflow or error */ + if (len < 0 || (uint32)len >= bufsize) + len = bufsize - 1; + buf += len; + bufsize -= len; + filled_len += len; + cur_ptr++; + } + return filled_len; +} + +uint +bcm_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 */ + if (data && datalen != 0) { + memcpy(&buf[len], data, datalen); + len += datalen; + } + + return len; +} + +/* 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 uint16. + */ + +#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 uint16 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 +}; + +uint16 +bcm_qdbm_to_mw(uint8 qdbm) +{ + uint factor = 1; + int idx = qdbm - QDBM_OFFSET; + + if (idx >= QDBM_TABLE_LEN) { + /* clamp to max uint16 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); +} + +uint8 +bcm_mw_to_qdbm(uint16 mw) +{ + uint8 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 += (uint8)offset; + + return (qdbm); +} + + +uint +bcm_bitcount(uint8 *bitmap, uint length) +{ + uint bitcount = 0, i; + uint8 tmp; + for (i = 0; i < length; i++) { + tmp = bitmap[i]; + while (tmp) { + bitcount++; + tmp &= (tmp - 1); + } + } + return bitcount; +} + +#ifdef BCMDRIVER + +/* Initialization of bcmstrbuf structure */ +void +bcm_binit(struct bcmstrbuf *b, char *buf, uint size) +{ + b->origsize = b->size = size; + b->origbuf = b->buf = buf; +} + +/* Buffer sprintf wrapper to guard against buffer overflow */ +int +bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + + r = vsnprintf(b->buf, b->size, fmt, ap); + + /* Non Ansi C99 compliant returns -1, + * Ansi compliant return r >= b->size, + * bcmstdlib returns 0, handle all + */ + /* r == 0 is also the case when strlen(fmt) is zero. + * typically the case when "" is passed as argument. + */ + if ((r == -1) || (r >= (int)b->size)) { + b->size = 0; + } else { + b->size -= r; + b->buf += r; + } + + va_end(ap); + + return r; +} + +void +bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len) +{ + int i; + + if (msg != NULL && msg[0] != '\0') + bcm_bprintf(b, "%s", msg); + for (i = 0; i < len; i ++) + bcm_bprintf(b, "%02X", buf[i]); + if (newline) + bcm_bprintf(b, "\n"); +} + +void +bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) +{ + int i; + + for (i = 0; i < num_bytes; i++) { + num[i] += amount; + if (num[i] >= amount) + break; + amount = 1; + } +} + +int +bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) +{ + int i; + + for (i = nbytes - 1; i >= 0; i--) { + if (arg1[i] != arg2[i]) + return (arg1[i] - arg2[i]); + } + return 0; +} + +void +bcm_print_bytes(const char *name, const uchar *data, int len) +{ + int i; + int per_line = 0; + + printf("%s: %d \n", name ? name : "", len); + for (i = 0; i < len; i++) { + printf("%02x ", *data++); + per_line++; + if (per_line == 16) { + per_line = 0; + printf("\n"); + } + } + printf("\n"); +} + +/* Look for vendor-specific IE with specified OUI and optional type */ +bcm_tlv_t * +bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len) +{ + bcm_tlv_t *ie; + uint8 ie_len; + + ie = (bcm_tlv_t*)tlvs; + + /* make sure we are looking at a valid IE */ + if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) { + return NULL; + } + + /* Walk through the IEs looking for an OUI match */ + do { + ie_len = ie->len; + if ((ie->id == DOT11_MNG_PROPR_ID) && + (ie_len >= (DOT11_OUI_LEN + type_len)) && + !bcmp(ie->data, voui, DOT11_OUI_LEN)) + { + /* compare optional type */ + if (type_len == 0 || + !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { + return (ie); /* a match */ + } + } + } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL); + + return NULL; +} + +#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ + defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) +#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) + +int +bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) +{ + uint i, c; + char *p = buf; + char *endp = buf + SSID_FMT_BUF_LEN; + + if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; + + for (i = 0; i < ssid_len; i++) { + c = (uint)ssid[i]; + if (c == '\\') { + *p++ = '\\'; + *p++ = '\\'; + } else if (bcm_isprint((uchar)c)) { + *p++ = (char)c; + } else { + p += snprintf(p, (endp - p), "\\x%02X", c); + } + } + *p = '\0'; + ASSERT(p < endp); + + return (int)(p - buf); +} +#endif + +#endif /* BCMDRIVER */ + +/* + * ProcessVars:Takes a buffer of "=\n" lines read from a file and ending in a NUL. + * also accepts nvram files which are already in the format of =\0\=\0 + * 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. +*/ + +unsigned int +process_nvram_vars(char *varbuf, unsigned int len) +{ + char *dp; + bool findNewline; + int column; + unsigned int buf_len, n; + unsigned int pad = 0; + + dp = varbuf; + + findNewline = FALSE; + column = 0; + + for (n = 0; n < len; n++) { + 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 = (unsigned int)(dp - varbuf); + if (buf_len % 4) { + pad = 4 - buf_len % 4; + if (pad && (buf_len + pad <= len)) { + buf_len += pad; + } + } + + while (dp < varbuf + n) + *dp++ = 0; + + return buf_len; +} + +/* calculate a * b + c */ +void +bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c) +{ +#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;} + uint32 r1, r0; + uint32 a1, a0, b1, b0, t, cc = 0; + + a1 = a >> 16; + a0 = a & 0xffff; + b1 = b >> 16; + b0 = b & 0xffff; + + r0 = a0 * b0; + FORMALIZE(r0); + + t = (a1 * b0) << 16; + FORMALIZE(t); + + r0 += t; + FORMALIZE(r0); + + t = (a0 * b1) << 16; + FORMALIZE(t); + + r0 += t; + FORMALIZE(r0); + + FORMALIZE(c); + + r0 += c; + FORMALIZE(r0); + + r0 |= (cc % 2) ? 0x80000000 : 0; + r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2); + + *r_high = r1; + *r_low = r0; +} + +/* calculate a / b */ +void +bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b) +{ + uint32 a1 = a_high, a0 = a_low, r0 = 0; + + if (b < 2) + return; + + while (a1 != 0) { + r0 += (0xffffffff / b) * a1; + bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0); + } + + r0 += a0 / b; + *r = r0; +} + +#ifndef setbit /* As in the header file */ +#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS +/* Set bit in byte array. */ +void +setbit(void *array, uint bit) +{ + ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY); +} + +/* Clear bit in byte array. */ +void +clrbit(void *array, uint bit) +{ + ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY)); +} + +/* Test if bit is set in byte array. */ +bool +isset(const void *array, uint bit) +{ + return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))); +} + +/* Test if bit is clear in byte array. */ +bool +isclr(const void *array, uint bit) +{ + return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0); +} +#endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */ +#endif /* setbit */ + +void +bcm_bitprint32(const uint32 u32) +{ + int i; + for (i = NBITS(uint32) - 1; i >= 0; i--) { + isbitset(u32, i) ? printf("1") : printf("0"); + if ((i % NBBY) == 0) printf(" "); + } + printf("\n"); +} + +#ifdef BCMDRIVER +/* + * Hierarchical Multiword bitmap based small id allocator. + * + * Multilevel hierarchy bitmap. (maximum 2 levels) + * First hierarchy uses a multiword bitmap to identify 32bit words in the + * second hierarchy that have at least a single bit set. Each bit in a word of + * the second hierarchy represents a unique ID that may be allocated. + * + * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed. + * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word + * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs. + * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non + * non-zero bitmap word carrying at least one free ID. + * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations. + * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID + * + * Design Notes: + * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many + * bits are computed each time on allocation and deallocation, requiring 4 + * array indexed access and 3 arithmetic operations. When not defined, a runtime + * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed. + * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation. + * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may + * be used by defining BCM_MWBMAP_USE_CNTSETBITS. + * + * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array + * size is fixed. No intention to support larger than 4K indice allocation. ID + * allocators for ranges smaller than 4K will have a wastage of only 12Bytes + * with savings in not having to use an indirect access, had it been dynamically + * allocated. + */ +#define BCM_MWBMAP_ITEMS_MAX (4 * 1024) /* May increase to 16K */ + +#define BCM_MWBMAP_BITS_WORD (NBITS(uint32)) +#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD) +#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD) +#define BCM_MWBMAP_SHIFT_OP (5) +#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1)) +#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP) +#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP) + +/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */ +#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl)) +#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr)) + +#if defined(BCM_MWBMAP_DEBUG) +#define BCM_MWBMAP_AUDIT(mwb) \ + do { \ + ASSERT((mwb != NULL) && \ + (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \ + bcm_mwbmap_audit(mwb); \ + } while (0) +#define MWBMAP_ASSERT(exp) ASSERT(exp) +#define MWBMAP_DBG(x) printf x +#else /* !BCM_MWBMAP_DEBUG */ +#define BCM_MWBMAP_AUDIT(mwb) do {} while (0) +#define MWBMAP_ASSERT(exp) do {} while (0) +#define MWBMAP_DBG(x) +#endif /* !BCM_MWBMAP_DEBUG */ + + +typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ + uint16 wmaps; /* Total number of words in free wd bitmap */ + uint16 imaps; /* Total number of words in free id bitmap */ + int16 ifree; /* Count of free indices. Used only in audits */ + uint16 total; /* Total indices managed by multiword bitmap */ + + void * magic; /* Audit handle parameter from user */ + + uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */ +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */ +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + + uint32 id_bitmap[0]; /* Second level bitmap */ +} bcm_mwbmap_t; + +/* Incarnate a hierarchical multiword bitmap based small index allocator. */ +struct bcm_mwbmap * +bcm_mwbmap_init(osl_t *osh, uint32 items_max) +{ + struct bcm_mwbmap * mwbmap_p; + uint32 wordix, size, words, extra; + + /* Implementation Constraint: Uses 32bit word bitmap */ + MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U); + MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U); + MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX)); + MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U); + + ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX); + + /* Determine the number of words needed in the multiword bitmap */ + extra = BCM_MWBMAP_MODOP(items_max); + words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U); + + /* Allocate runtime state of multiword bitmap */ + /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ + size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); + mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); + if (mwbmap_p == (bcm_mwbmap_t *)NULL) { + ASSERT(0); + goto error1; + } + memset(mwbmap_p, 0, size); + + /* Initialize runtime multiword bitmap state */ + mwbmap_p->imaps = (uint16)words; + mwbmap_p->ifree = (int16)items_max; + mwbmap_p->total = (uint16)items_max; + + /* Setup magic, for use in audit of handle */ + mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p); + + /* Setup the second level bitmap of free indices */ + /* Mark all indices as available */ + for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) { + mwbmap_p->id_bitmap[wordix] = (uint32)(~0U); +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD; +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + } + + /* Ensure that extra indices are tagged as un-available */ + if (extra) { /* fixup the free ids in last bitmap and wd_count */ + uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1]; + *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */ +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + } + + /* Setup the first level bitmap hierarchy */ + extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps); + words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U); + + mwbmap_p->wmaps = (uint16)words; + + for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) + mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U); + if (extra) { + uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1]; + *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ + } + + return mwbmap_p; + +error1: + return BCM_MWBMAP_INVALID_HDL; +} + +/* Release resources used by multiword bitmap based small index allocator. */ +void +bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap) + + (sizeof(uint32) * mwbmap_p->imaps)); + return; +} + +/* Allocate a unique small index using a multiword bitmap index allocator. */ +uint32 +bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + /* Start with the first hierarchy */ + for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) { + + bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */ + + if (bitmap != 0U) { + + uint32 count, bitix, *bitmap_p; + + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + + /* clear all except trailing 1 */ + bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); + MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == + bcm_count_leading_zeros(bitmap)); + bitix = (BCM_MWBMAP_BITS_WORD - 1) + - bcm_count_leading_zeros(bitmap); /* use asm clz */ + wordix = BCM_MWBMAP_MULOP(wordix) + bitix; + + /* Clear bit if wd count is 0, without conditional branch */ +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1; +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + mwbmap_p->wd_count[wordix]--; + count = mwbmap_p->wd_count[wordix]; + MWBMAP_ASSERT(count == + (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1)); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + MWBMAP_ASSERT(count >= 0); + + /* clear wd_bitmap bit if id_map count is 0 */ + bitmap = (count == 0) << bitix; + + MWBMAP_DBG(( + "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count)); + + *bitmap_p ^= bitmap; + + /* Use bitix in the second hierarchy */ + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */ + MWBMAP_ASSERT(bitmap != 0U); + + /* clear all except trailing 1 */ + bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); + MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == + bcm_count_leading_zeros(bitmap)); + bitix = BCM_MWBMAP_MULOP(wordix) + + (BCM_MWBMAP_BITS_WORD - 1) + - bcm_count_leading_zeros(bitmap); /* use asm clz */ + + mwbmap_p->ifree--; /* decrement system wide free count */ + MWBMAP_ASSERT(mwbmap_p->ifree >= 0); + + MWBMAP_DBG(( + "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, + mwbmap_p->ifree)); + + *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */ + + return bitix; + } + } + + ASSERT(mwbmap_p->ifree == 0); + + return BCM_MWBMAP_INVALID_IDX; +} + +/* Force an index at a specified position to be in use */ +void +bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 count, wordix, bitmap, *bitmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + /* Start with second hierarchy */ + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + ASSERT((*bitmap_p & bitmap) == bitmap); + + mwbmap_p->ifree--; /* update free count */ + ASSERT(mwbmap_p->ifree >= 0); + + MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, + mwbmap_p->ifree)); + + *bitmap_p ^= bitmap; /* mark as in use */ + + /* Update first hierarchy */ + bitix = wordix; + + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + mwbmap_p->wd_count[bitix]--; + count = mwbmap_p->wd_count[bitix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + MWBMAP_ASSERT(count >= 0); + + bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix); + + MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", + BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, + (*bitmap_p) ^ bitmap, count)); + + *bitmap_p ^= bitmap; /* mark as in use */ + + return; +} + +/* Free a previously allocated index back into the multiword bitmap allocator */ +void +bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap, *bitmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + /* Start with second level hierarchy */ + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */ + + mwbmap_p->ifree++; /* update free count */ + ASSERT(mwbmap_p->ifree <= mwbmap_p->total); + + MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, + mwbmap_p->ifree)); + + *bitmap_p |= bitmap; /* mark as available */ + + /* Now update first level hierarchy */ + + bitix = wordix; + + wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */ + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[bitix]++; +#endif + +#if defined(BCM_MWBMAP_DEBUG) + { + uint32 count; +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[bitix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + + MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD); + + MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count)); + } +#endif /* BCM_MWBMAP_DEBUG */ + + *bitmap_p |= bitmap; + + return; +} + +/* Fetch the toal number of free indices in the multiword bitmap allocator */ +uint32 +bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(mwbmap_p->ifree >= 0); + + return mwbmap_p->ifree; +} + +/* Determine whether an index is inuse or free */ +bool +bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + + return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U); +} + +/* Debug dump a multiword bitmap allocator */ +void +bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl) +{ + uint32 ix, count; + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p, + mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total); + for (ix = 0U; ix < mwbmap_p->wmaps; ix++) { + printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]); + bcm_bitprint32(mwbmap_p->wd_bitmap[ix]); + printf("\n"); + } + for (ix = 0U; ix < mwbmap_p->imaps; ix++) { +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[ix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count); + bcm_bitprint32(mwbmap_p->id_bitmap[ix]); + printf("\n"); + } + + return; +} + +/* Audit a hierarchical multiword bitmap */ +void +bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p; + + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) { + + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + + for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { + if ((*bitmap_p) & (1 << bitix)) { + idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[idmap_ix]; + ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + ASSERT(count != 0U); + free_cnt += count; + } + } + } + + ASSERT(free_cnt == mwbmap_p->ifree); +} +/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ + +#endif /* BCMDRIVER */ + +/* calculate a >> b; and returns only lower 32 bits */ +void +bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b) +{ + uint32 a1 = a_high, a0 = a_low, r0 = 0; + + if (b == 0) { + r0 = a_low; + *r = r0; + return; + } + + if (b < 32) { + a0 = a0 >> b; + a1 = a1 & ((1 << b) - 1); + a1 = a1 << (32 - b); + r0 = a0 | a1; + *r = r0; + return; + } else { + r0 = a1 >> (b - 32); + *r = r0; + return; + } + +} + +/* calculate a + b where a is a 64 bit number and b is a 32 bit number */ +void +bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset) +{ + uint32 r1_lo = *r_lo; + (*r_lo) += offset; + if (*r_lo < r1_lo) + (*r_hi) ++; +} + +/* calculate a - b where a is a 64 bit number and b is a 32 bit number */ +void +bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset) +{ + uint32 r1_lo = *r_lo; + (*r_lo) -= offset; + if (*r_lo > r1_lo) + (*r_hi) --; +} + +#ifdef DEBUG_COUNTER +#if (OSL_SYSUPTIME_SUPPORT == TRUE) +void counter_printlog(counter_tbl_t *ctr_tbl) +{ + uint32 now; + + if (!ctr_tbl->enabled) + return; + + now = OSL_SYSUPTIME(); + + if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) { + uint8 i = 0; + printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print); + + for (i = 0; i < ctr_tbl->needed_cnt; i++) { + printf(" %u", ctr_tbl->cnt[i]); + } + printf("\n"); + + ctr_tbl->prev_log_print = now; + bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint)); + } +} +#else +/* OSL_SYSUPTIME is not supported so no way to get time */ +#define counter_printlog(a) do {} while (0) +#endif /* OSL_SYSUPTIME_SUPPORT == TRUE */ +#endif /* DEBUG_COUNTER */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c new file mode 100644 index 000000000000..4cc23b825abf --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c @@ -0,0 +1,1246 @@ +/* + * Misc utility routines used by kernel or app-level. + * Contents are wifi-specific, used by any kernel or app-level + * software that might want wifi things as it grows. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ + */ + +#include +#include +#include + +#ifdef BCMDRIVER +#include +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#else +#include +#include +#include +#ifndef ASSERT +#define ASSERT(exp) +#endif +#endif /* BCMDRIVER */ + +#include + +#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) +#include /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ +#endif + +/* Definitions for D11AC capable Chanspec type */ + +/* Chanspec ASCII representation with 802.11ac capability: + * [ 'g'] ['/' []['/'<1st80channel>'-'<2nd80channel>]] + * + * : + * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. + * Default value is 2g if channel <= 14, otherwise 5g. + * : + * channel number of the 5MHz, 10MHz, 20MHz channel, + * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. + * : + * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. + * : + * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. + * + * For 2.4GHz band 40MHz channels, the same primary channel may be the + * upper sideband for one 40MHz channel, and the lower sideband for an + * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel + * is being specified. + * + * For 40MHz in the 5GHz band and all channel bandwidths greater than + * 40MHz, the U/L specificaion is not allowed since the channels are + * non-overlapping and the primary sub-band is derived from its + * position in the wide bandwidth channel. + * + * <1st80Channel>: + * <2nd80Channel>: + * Required for 80+80, otherwise not allowed. + * Specifies the center channel of the first and second 80MHz band. + * + * In its simplest form, it is a 20MHz channel number, with the implied band + * of 2.4GHz if channel number <= 14, and 5GHz otherwise. + * + * To allow for backward compatibility with scripts, the old form for + * 40MHz channels is also allowed: + * + * : + * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz + * : + * "U" for upper, "L" for lower (or lower case "u" "l") + * + * 5 GHz Examples: + * Chanspec BW Center Ch Channel Range Primary Ch + * 5g8 20MHz 8 - - + * 52 20MHz 52 - - + * 52/40 40MHz 54 52-56 52 + * 56/40 40MHz 54 52-56 56 + * 52/80 80MHz 58 52-64 52 + * 56/80 80MHz 58 52-64 56 + * 60/80 80MHz 58 52-64 60 + * 64/80 80MHz 58 52-64 64 + * 52/160 160MHz 50 36-64 52 + * 36/160 160MGz 50 36-64 36 + * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 + * + * 2 GHz Examples: + * Chanspec BW Center Ch Channel Range Primary Ch + * 2g8 20MHz 8 - - + * 8 20MHz 8 - - + * 6 20MHz 6 - - + * 6/40l 40MHz 8 6-10 6 + * 6l 40MHz 8 6-10 6 + * 6/40u 40MHz 4 2-6 6 + * 6u 40MHz 4 2-6 6 + */ + +/* bandwidth ASCII string */ +static const char *wf_chspec_bw_str[] = +{ + "5", + "10", + "20", + "40", + "80", + "160", + "80+80", + "na" +}; + +static const uint8 wf_chspec_bw_mhz[] = +{5, 10, 20, 40, 80, 160, 160}; + +#define WF_NUM_BW \ + (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) + +/* 40MHz channels in 5GHz band */ +static const uint8 wf_5g_40m_chans[] = +{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; +#define WF_NUM_5G_40M_CHANS \ + (sizeof(wf_5g_40m_chans)/sizeof(uint8)) + +/* 80MHz channels in 5GHz band */ +static const uint8 wf_5g_80m_chans[] = +{42, 58, 106, 122, 138, 155}; +#define WF_NUM_5G_80M_CHANS \ + (sizeof(wf_5g_80m_chans)/sizeof(uint8)) + +/* 160MHz channels in 5GHz band */ +static const uint8 wf_5g_160m_chans[] = +{50, 114}; +#define WF_NUM_5G_160M_CHANS \ + (sizeof(wf_5g_160m_chans)/sizeof(uint8)) + + +/* convert bandwidth from chanspec to MHz */ +static uint +bw_chspec_to_mhz(chanspec_t chspec) +{ + uint bw; + + bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; + return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); +} + +/* bw in MHz, return the channel count from the center channel to the + * the channel at the edge of the band + */ +static uint8 +center_chan_to_edge(uint bw) +{ + /* edge channels separated by BW - 10MHz on each side + * delta from cf to edge is half of that, + * MHz to channel num conversion is 5MHz/channel + */ + return (uint8)(((bw - 20) / 2) / 5); +} + +/* return channel number of the low edge of the band + * given the center channel and BW + */ +static uint8 +channel_low_edge(uint center_ch, uint bw) +{ + return (uint8)(center_ch - center_chan_to_edge(bw)); +} + +/* return side band number given center channel and control channel + * return -1 on error + */ +static int +channel_to_sb(uint center_ch, uint ctl_ch, uint bw) +{ + uint lowest = channel_low_edge(center_ch, bw); + uint sb; + + if ((ctl_ch - lowest) % 4) { + /* bad ctl channel, not mult 4 */ + return -1; + } + + sb = ((ctl_ch - lowest) / 4); + + /* sb must be a index to a 20MHz channel in range */ + if (sb >= (bw / 20)) { + /* ctl_ch must have been too high for the center_ch */ + return -1; + } + + return sb; +} + +/* return control channel given center channel and side band */ +static uint8 +channel_to_ctl_chan(uint center_ch, uint bw, uint sb) +{ + return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); +} + +/* return index of 80MHz channel from channel number + * return -1 on error + */ +static int +channel_80mhz_to_id(uint ch) +{ + uint i; + for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { + if (ch == wf_5g_80m_chans[i]) + return i; + } + + return -1; +} + +/* given a chanspec and a string buffer, format the chanspec as a + * string, and return the original pointer a. + * Min buffer length must be CHANSPEC_STR_LEN. + * On error return NULL + */ +char * +wf_chspec_ntoa(chanspec_t chspec, char *buf) +{ + const char *band; + uint ctl_chan; + + if (wf_chspec_malformed(chspec)) + return NULL; + + band = ""; + + /* check for non-default band spec */ + if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || + (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) + band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; + + /* ctl channel */ + ctl_chan = wf_chspec_ctlchan(chspec); + + /* bandwidth and ctl sideband */ + if (CHSPEC_IS20(chspec)) { + snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); + } else if (!CHSPEC_IS8080(chspec)) { + const char *bw; + const char *sb = ""; + + bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; + +#ifdef CHANSPEC_NEW_40MHZ_FORMAT + /* ctl sideband string if needed for 2g 40MHz */ + if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { + sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; + } + + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); +#else + /* ctl sideband string instead of BW for 40MHz */ + if (CHSPEC_IS40(chspec)) { + sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; + snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); + } else { + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); + } +#endif /* CHANSPEC_NEW_40MHZ_FORMAT */ + + } else { + /* 80+80 */ + uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; + uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; + + /* convert to channel number */ + chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; + chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; + + /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ + snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); + } + + return (buf); +} + +static int +read_uint(const char **p, unsigned int *num) +{ + unsigned long val; + char *endp = NULL; + + val = strtoul(*p, &endp, 10); + /* if endp is the initial pointer value, then a number was not read */ + if (endp == *p) + return 0; + + /* advance the buffer pointer to the end of the integer string */ + *p = endp; + /* return the parsed integer */ + *num = (unsigned int)val; + + return 1; +} + +/* given a chanspec string, convert to a chanspec. + * On error return 0 + */ +chanspec_t +wf_chspec_aton(const char *a) +{ + chanspec_t chspec; + uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; + uint num, ctl_ch; + uint ch1, ch2; + char c, sb_ul = '\0'; + int i; + + bw = 20; + chspec_sb = 0; + chspec_ch = ch1 = ch2 = 0; + + /* parse channel num or band */ + if (!read_uint(&a, &num)) + return 0; + + /* if we are looking at a 'g', then the first number was a band */ + c = tolower((int)a[0]); + if (c == 'g') { + a ++; /* consume the char */ + + /* band must be "2" or "5" */ + if (num == 2) + chspec_band = WL_CHANSPEC_BAND_2G; + else if (num == 5) + chspec_band = WL_CHANSPEC_BAND_5G; + else + return 0; + + /* read the channel number */ + if (!read_uint(&a, &ctl_ch)) + return 0; + + c = tolower((int)a[0]); + } + else { + /* first number is channel, use default for band */ + ctl_ch = num; + chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); + } + + if (c == '\0') { + /* default BW of 20MHz */ + chspec_bw = WL_CHANSPEC_BW_20; + goto done_read; + } + + a ++; /* consume the 'u','l', or '/' */ + + /* check 'u'/'l' */ + if (c == 'u' || c == 'l') { + sb_ul = c; + chspec_bw = WL_CHANSPEC_BW_40; + goto done_read; + } + + /* next letter must be '/' */ + if (c != '/') + return 0; + + /* read bandwidth */ + if (!read_uint(&a, &bw)) + return 0; + + /* convert to chspec value */ + if (bw == 20) { + chspec_bw = WL_CHANSPEC_BW_20; + } else if (bw == 40) { + chspec_bw = WL_CHANSPEC_BW_40; + } else if (bw == 80) { + chspec_bw = WL_CHANSPEC_BW_80; + } else if (bw == 160) { + chspec_bw = WL_CHANSPEC_BW_160; + } else { + return 0; + } + + /* So far we have g/ + * Can now be followed by u/l if bw = 40, + * or '+80' if bw = 80, to make '80+80' bw. + */ + + c = tolower((int)a[0]); + + /* if we have a 2g/40 channel, we should have a l/u spec now */ + if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { + if (c == 'u' || c == 'l') { + a ++; /* consume the u/l char */ + sb_ul = c; + goto done_read; + } + } + + /* check for 80+80 */ + if (c == '+') { + /* 80+80 */ + static const char *plus80 = "80/"; + + /* must be looking at '+80/' + * check and consume this string. + */ + chspec_bw = WL_CHANSPEC_BW_8080; + + a ++; /* consume the char '+' */ + + /* consume the '80/' string */ + for (i = 0; i < 3; i++) { + if (*a++ != *plus80++) { + return 0; + } + } + + /* read primary 80MHz channel */ + if (!read_uint(&a, &ch1)) + return 0; + + /* must followed by '-' */ + if (a[0] != '-') + return 0; + a ++; /* consume the char */ + + /* read secondary 80MHz channel */ + if (!read_uint(&a, &ch2)) + return 0; + } + +done_read: + /* skip trailing white space */ + while (a[0] == ' ') { + a ++; + } + + /* must be end of string */ + if (a[0] != '\0') + return 0; + + /* Now have all the chanspec string parts read; + * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. + * chspec_band and chspec_bw are chanspec values. + * Need to convert ctl_ch, sb_ul, and ch1,ch2 into + * a center channel (or two) and sideband. + */ + + /* if a sb u/l string was given, just use that, + * guaranteed to be bw = 40 by sting parse. + */ + if (sb_ul != '\0') { + if (sb_ul == 'l') { + chspec_ch = UPPER_20_SB(ctl_ch); + chspec_sb = WL_CHANSPEC_CTL_SB_LLL; + } else if (sb_ul == 'u') { + chspec_ch = LOWER_20_SB(ctl_ch); + chspec_sb = WL_CHANSPEC_CTL_SB_LLU; + } + } + /* if the bw is 20, center and sideband are trivial */ + else if (chspec_bw == WL_CHANSPEC_BW_20) { + chspec_ch = ctl_ch; + chspec_sb = WL_CHANSPEC_CTL_SB_NONE; + } + /* if the bw is 40/80/160, not 80+80, a single method + * can be used to to find the center and sideband + */ + else if (chspec_bw != WL_CHANSPEC_BW_8080) { + /* figure out ctl sideband based on ctl channel and bandwidth */ + const uint8 *center_ch = NULL; + int num_ch = 0; + int sb = -1; + + if (chspec_bw == WL_CHANSPEC_BW_40) { + center_ch = wf_5g_40m_chans; + num_ch = WF_NUM_5G_40M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_80) { + center_ch = wf_5g_80m_chans; + num_ch = WF_NUM_5G_80M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_160) { + center_ch = wf_5g_160m_chans; + num_ch = WF_NUM_5G_160M_CHANS; + } else { + return 0; + } + + for (i = 0; i < num_ch; i ++) { + sb = channel_to_sb(center_ch[i], ctl_ch, bw); + if (sb >= 0) { + chspec_ch = center_ch[i]; + chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; + break; + } + } + + /* check for no matching sb/center */ + if (sb < 0) { + return 0; + } + } + /* Otherwise, bw is 80+80. Figure out channel pair and sb */ + else { + int ch1_id = 0, ch2_id = 0; + int sb; + + ch1_id = channel_80mhz_to_id(ch1); + ch2_id = channel_80mhz_to_id(ch2); + + /* validate channels */ + if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0) + return 0; + + /* combined channel in chspec */ + chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | + ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); + + /* figure out ctl sideband */ + + /* does the primary channel fit with the 1st 80MHz channel ? */ + sb = channel_to_sb(ch1, ctl_ch, bw); + if (sb < 0) { + /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ + sb = channel_to_sb(ch2, ctl_ch, bw); + if (sb < 0) { + /* no match for ctl_ch to either 80MHz center channel */ + return 0; + } + /* sb index is 0-3 for the low 80MHz channel, and 4-7 for + * the high 80MHz channel. Add 4 to to shift to high set. + */ + sb += 4; + } + + chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; + } + + chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); + + if (wf_chspec_malformed(chspec)) + return 0; + + return chspec; +} + +/* + * 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. + */ +bool +wf_chspec_malformed(chanspec_t chanspec) +{ + uint chspec_bw = CHSPEC_BW(chanspec); + uint chspec_ch = CHSPEC_CHANNEL(chanspec); + + /* must be 2G or 5G band */ + if (CHSPEC_IS2G(chanspec)) { + /* must be valid bandwidth */ + if (chspec_bw != WL_CHANSPEC_BW_20 && + chspec_bw != WL_CHANSPEC_BW_40) { + return TRUE; + } + } else if (CHSPEC_IS5G(chanspec)) { + if (chspec_bw == WL_CHANSPEC_BW_8080) { + uint ch1_id, ch2_id; + + /* channel number in 80+80 must be in range */ + ch1_id = CHSPEC_CHAN1(chanspec); + ch2_id = CHSPEC_CHAN2(chanspec); + if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) + return TRUE; + + /* ch2 must be above ch1 for the chanspec */ + if (ch2_id <= ch1_id) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || + chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { + + if (chspec_ch > MAXCHANNEL) { + return TRUE; + } + } else { + /* invalid bandwidth */ + return TRUE; + } + } else { + /* must be 2G or 5G band */ + return TRUE; + } + + /* side band needs to be consistent with bandwidth */ + if (chspec_bw == WL_CHANSPEC_BW_20) { + if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_40) { + if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_80) { + if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) + return TRUE; + } + + return FALSE; +} + +/* + * Verify the chanspec specifies a valid channel according to 802.11. + * RETURNS: TRUE if the chanspec is a valid 802.11 channel + */ +bool +wf_chspec_valid(chanspec_t chanspec) +{ + uint chspec_bw = CHSPEC_BW(chanspec); + uint chspec_ch = CHSPEC_CHANNEL(chanspec); + + if (wf_chspec_malformed(chanspec)) + return FALSE; + + if (CHSPEC_IS2G(chanspec)) { + /* must be valid bandwidth and channel range */ + if (chspec_bw == WL_CHANSPEC_BW_20) { + if (chspec_ch >= 1 && chspec_ch <= 14) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_40) { + if (chspec_ch >= 3 && chspec_ch <= 11) + return TRUE; + } + } else if (CHSPEC_IS5G(chanspec)) { + if (chspec_bw == WL_CHANSPEC_BW_8080) { + uint16 ch1, ch2; + + ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; + ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; + + /* the two channels must be separated by more than 80MHz by VHT req, + * and ch2 above ch1 for the chanspec + */ + if (ch2 > ch1 + CH_80MHZ_APART) + return TRUE; + } else { + const uint8 *center_ch; + uint num_ch, i; + + if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { + center_ch = wf_5g_40m_chans; + num_ch = WF_NUM_5G_40M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_80) { + center_ch = wf_5g_80m_chans; + num_ch = WF_NUM_5G_80M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_160) { + center_ch = wf_5g_160m_chans; + num_ch = WF_NUM_5G_160M_CHANS; + } else { + /* invalid bandwidth */ + return FALSE; + } + + /* check for a valid center channel */ + if (chspec_bw == WL_CHANSPEC_BW_20) { + /* We don't have an array of legal 20MHz 5G channels, but they are + * each side of the legal 40MHz channels. Check the chanspec + * channel against either side of the 40MHz channels. + */ + for (i = 0; i < num_ch; i ++) { + if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || + chspec_ch == (uint)UPPER_20_SB(center_ch[i])) + break; /* match found */ + } + + if (i == num_ch) { + /* check for channel 165 which is not the side band + * of 40MHz 5G channel + */ + if (chspec_ch == 165) + i = 0; + + /* check for legacy JP channels on failure */ + if (chspec_ch == 34 || chspec_ch == 38 || + chspec_ch == 42 || chspec_ch == 46) + i = 0; + } + } else { + /* check the chanspec channel to each legal channel */ + for (i = 0; i < num_ch; i ++) { + if (chspec_ch == center_ch[i]) + break; /* match found */ + } + } + + if (i < num_ch) { + /* match found */ + return TRUE; + } + } + } + + return FALSE; +} + +/* + * This function returns the channel number that control traffic is being sent on, for 20MHz + * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ + * sideband depending on the chanspec selected + */ +uint8 +wf_chspec_ctlchan(chanspec_t chspec) +{ + uint center_chan; + uint bw_mhz; + uint sb; + + ASSERT(!wf_chspec_malformed(chspec)); + + /* Is there a sideband ? */ + if (CHSPEC_IS20(chspec)) { + return CHSPEC_CHANNEL(chspec); + } else { + sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; + + if (CHSPEC_IS8080(chspec)) { + bw_mhz = 80; + + if (sb < 4) { + center_chan = CHSPEC_CHAN1(chspec); + } + else { + center_chan = CHSPEC_CHAN2(chspec); + sb -= 4; + } + + /* convert from channel index to channel number */ + center_chan = wf_5g_80m_chans[center_chan]; + } + else { + bw_mhz = bw_chspec_to_mhz(chspec); + center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; + } + + return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); + } +} + +/* given a chanspec, return the bandwidth string */ +char * +wf_chspec_to_bw_str(chanspec_t chspec) +{ + return (char *)wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)]; +} + +/* + * This function returns the chanspec of the control channel of a given chanspec + */ +chanspec_t +wf_chspec_ctlchspec(chanspec_t chspec) +{ + chanspec_t ctl_chspec = chspec; + uint8 ctl_chan; + + ASSERT(!wf_chspec_malformed(chspec)); + + /* Is there a sideband ? */ + if (!CHSPEC_IS20(chspec)) { + ctl_chan = wf_chspec_ctlchan(chspec); + ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; + ctl_chspec |= CHSPEC_BAND(chspec); + } + return ctl_chspec; +} + +/* return chanspec given control channel and bandwidth + * return 0 on error + */ +uint16 +wf_channel2chspec(uint ctl_ch, uint bw) +{ + uint16 chspec; + const uint8 *center_ch = NULL; + int num_ch = 0; + int sb = -1; + int i = 0; + + chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); + + chspec |= bw; + + if (bw == WL_CHANSPEC_BW_40) { + center_ch = wf_5g_40m_chans; + num_ch = WF_NUM_5G_40M_CHANS; + bw = 40; + } else if (bw == WL_CHANSPEC_BW_80) { + center_ch = wf_5g_80m_chans; + num_ch = WF_NUM_5G_80M_CHANS; + bw = 80; + } else if (bw == WL_CHANSPEC_BW_160) { + center_ch = wf_5g_160m_chans; + num_ch = WF_NUM_5G_160M_CHANS; + bw = 160; + } else if (bw == WL_CHANSPEC_BW_20) { + chspec |= ctl_ch; + return chspec; + } else { + return 0; + } + + for (i = 0; i < num_ch; i ++) { + sb = channel_to_sb(center_ch[i], ctl_ch, bw); + if (sb >= 0) { + chspec |= center_ch[i]; + chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); + break; + } + } + + /* check for no matching sb/center */ + if (sb < 0) { + return 0; + } + + return chspec; +} + +/* + * This function returns the chanspec for the primary 40MHz of an 80MHz channel. + * The control sideband specifies the same 20MHz channel that the 80MHz channel is using + * as the primary 20MHz channel. + */ +extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) +{ + chanspec_t chspec40 = chspec; + uint center_chan; + uint sb; + + ASSERT(!wf_chspec_malformed(chspec)); + + if (CHSPEC_IS80(chspec)) { + center_chan = CHSPEC_CHANNEL(chspec); + sb = CHSPEC_CTL_SB(chspec); + + if (sb == WL_CHANSPEC_CTL_SB_UL) { + /* Primary 40MHz is on upper side */ + sb = WL_CHANSPEC_CTL_SB_L; + center_chan += CH_20MHZ_APART; + } else if (sb == WL_CHANSPEC_CTL_SB_UU) { + /* Primary 40MHz is on upper side */ + sb = WL_CHANSPEC_CTL_SB_U; + center_chan += CH_20MHZ_APART; + } else { + /* Primary 40MHz is on lower side */ + /* sideband bits are the same for LL/LU and L/U */ + center_chan -= CH_20MHZ_APART; + } + + /* Create primary 40MHz chanspec */ + chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | + sb | center_chan); + } + + return chspec40; +} + +/* + * Return the channel number for a given frequency and base frequency. + * The returned channel number is relative to the given base frequency. + * If the given base frequency is zero, a base frequency of 5 GHz is assumed for + * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. + * + * Frequency is specified in MHz. + * The base frequency is specified as (start_factor * 500 kHz). + * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for + * 2.4 GHz and 5 GHz bands. + * + * The returned channel will be in the range [1, 14] in the 2.4 GHz band + * and [0, 200] otherwise. + * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the + * frequency is not a 2.4 GHz channel, or if the frequency is not and even + * multiple of 5 MHz from the base frequency to the base plus 1 GHz. + * + * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + */ +int +wf_mhz2channel(uint freq, uint start_factor) +{ + int ch = -1; + uint base; + int offset; + + /* take the default channel start frequency */ + if (start_factor == 0) { + if (freq >= 2400 && freq <= 2500) + start_factor = WF_CHAN_FACTOR_2_4_G; + else if (freq >= 5000 && freq <= 6000) + start_factor = WF_CHAN_FACTOR_5_G; + } + + if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) + return 14; + + base = start_factor / 2; + + /* check that the frequency is in 1GHz range of the base */ + if ((freq < base) || (freq > base + 1000)) + return -1; + + offset = freq - base; + ch = offset / 5; + + /* check that frequency is a 5MHz multiple from the base */ + if (offset != (ch * 5)) + return -1; + + /* restricted channel range check for 2.4G */ + if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) + return -1; + + return ch; +} + +/* + * Return the center frequency in MHz of the given channel and base frequency. + * The channel number is interpreted relative to the given base frequency. + * + * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. + * The base frequency is specified as (start_factor * 500 kHz). + * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G + * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands. + * The channel range of [1, 14] is only checked for a start_factor of + * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2). + * Odd start_factors produce channels on .5 MHz boundaries, in which case + * the answer is rounded down to an integral MHz. + * -1 is returned for an out of range channel. + * + * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + */ +int +wf_channel2mhz(uint ch, uint start_factor) +{ + int freq; + + if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || + (ch > 200)) + freq = -1; + else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) + freq = 2484; + else + freq = ch * 5 + start_factor / 2; + + return freq; +} + +static const uint16 sidebands[] = { + WL_CHANSPEC_CTL_SB_LLL, WL_CHANSPEC_CTL_SB_LLU, + WL_CHANSPEC_CTL_SB_LUL, WL_CHANSPEC_CTL_SB_LUU, + WL_CHANSPEC_CTL_SB_ULL, WL_CHANSPEC_CTL_SB_ULU, + WL_CHANSPEC_CTL_SB_UUL, WL_CHANSPEC_CTL_SB_UUU +}; + +/* + * Returns the chanspec 80Mhz channel corresponding to the following input + * parameters + * + * primary_channel - primary 20Mhz channel + * center_channel - center frequecny of the 80Mhz channel + * + * The center_channel can be one of {42, 58, 106, 122, 138, 155} + * + * returns INVCHANSPEC in case of error + */ +chanspec_t +wf_chspec_80(uint8 center_channel, uint8 primary_channel) +{ + + chanspec_t chanspec = INVCHANSPEC; + chanspec_t chanspec_cur; + uint i; + + for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) { + chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]); + if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) { + chanspec = chanspec_cur; + break; + } + } + /* If the loop ended early, we are good, otherwise we did not + * find a 80MHz chanspec with the given center_channel that had a primary channel + *matching the given primary_channel. + */ + return chanspec; +} + +/* + * Returns the 80+80 chanspec corresponding to the following input parameters + * + * primary_20mhz - Primary 20 Mhz channel + * chan1 - channel number of first 80 Mhz band + * chan2 - channel number of second 80 Mhz band + * + * parameters chan1 and chan2 are channel numbers in {42, 58, 106, 122, 138, 155} + * + * returns INVCHANSPEC in case of error + */ + +chanspec_t +wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan1, uint8 chan2) +{ + int sb = 0; + uint16 chanspec = 0; + int chan1_id = 0, chan2_id = 0; + + /* does the primary channel fit with the 1st 80MHz channel ? */ + sb = channel_to_sb(chan1, primary_20mhz, 80); + if (sb < 0) { + /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ + sb = channel_to_sb(chan2, primary_20mhz, 80); + if (sb < 0) { + /* no match for ctl_ch to either 80MHz center channel */ + return INVCHANSPEC; + } + /* sb index is 0-3 for the low 80MHz channel, and 4-7 for + * the high 80MHz channel. Add 4 to to shift to high set. + */ + sb += 4; + } + chan1_id = channel_80mhz_to_id(chan1); + chan2_id = channel_80mhz_to_id(chan2); + if (chan1_id == -1 || chan2_id == -1) + return INVCHANSPEC; + + chanspec = (chan1_id << WL_CHANSPEC_CHAN1_SHIFT)| + (chan2_id << WL_CHANSPEC_CHAN2_SHIFT)| + (sb << WL_CHANSPEC_CTL_SB_SHIFT)| + (WL_CHANSPEC_BW_8080)| + (WL_CHANSPEC_BAND_5G); + + return chanspec; + +} + +/* + * This function returns the 80Mhz channel for the given id. + */ +static uint8 +wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id) +{ + if (chan_80Mhz_id < WF_NUM_5G_80M_CHANS) + return wf_5g_80m_chans[chan_80Mhz_id]; + + return 0; +} + +/* + * Returns the primary 80 Mhz channel for the provided chanspec + * + * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved + * + * returns -1 in case the provided channel is 20/40 Mhz chanspec + */ + +uint8 +wf_chspec_primary80_channel(chanspec_t chanspec) +{ + uint8 chan1 = 0, chan2 = 0, primary_20mhz = 0, primary80_chan = 0; + int sb = 0; + + primary_20mhz = wf_chspec_ctlchan(chanspec); + + if (CHSPEC_IS80(chanspec)) { + primary80_chan = CHSPEC_CHANNEL(chanspec); + } + else if (CHSPEC_IS8080(chanspec)) { + chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); + chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); + + /* does the primary channel fit with the 1st 80MHz channel ? */ + sb = channel_to_sb(chan1, primary_20mhz, 80); + if (sb < 0) { + /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ + sb = channel_to_sb(chan2, primary_20mhz, 80); + if (!(sb < 0)) { + primary80_chan = chan2; + } + } + else { + primary80_chan = chan1; + } + } + else if (CHSPEC_IS160(chanspec)) { + chan1 = CHSPEC_CHANNEL(chanspec); + sb = channel_to_sb(chan1, primary_20mhz, 160); + if (!(sb < 0)) { + /* based on the sb value primary 80 channel can be retrieved + * if sb is in range 0 to 3 the lower band is the 80Mhz primary band + */ + if (sb < 4) { + primary80_chan = chan1 - CH_40MHZ_APART; + } + /* if sb is in range 4 to 7 the lower band is the 80Mhz primary band */ + else + { + primary80_chan = chan1 + CH_40MHZ_APART; + } + } + } + else { + /* for 20 and 40 Mhz */ + primary80_chan = -1; + } + return primary80_chan; +} + +/* + * Returns the secondary 80 Mhz channel for the provided chanspec + * + * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved + * + * returns -1 in case the provided channel is 20/40 Mhz chanspec + */ +uint8 +wf_chspec_secondary80_channel(chanspec_t chanspec) +{ + uint8 chan1 = 0, chan2 = 0, primary_20mhz = 0, secondary80_chan = 0; + int sb = 0; + + primary_20mhz = wf_chspec_ctlchan(chanspec); + if (CHSPEC_IS80(chanspec)) { + secondary80_chan = -1; + } + else if (CHSPEC_IS8080(chanspec)) { + chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); + chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); + + /* does the primary channel fit with the 1st 80MHz channel ? */ + sb = channel_to_sb(chan1, primary_20mhz, 80); + if (sb < 0) { + /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ + sb = channel_to_sb(chan2, primary_20mhz, 80); + if (!(sb < 0)) { + secondary80_chan = chan1; + } + } + else { + secondary80_chan = chan2; + } + } + else if (CHSPEC_IS160(chanspec)) { + chan1 = CHSPEC_CHANNEL(chanspec); + sb = channel_to_sb(chan1, primary_20mhz, 160); + if (!(sb < 0)) { + /* based on the sb value secondary 80 channel can be retrieved + *if sb is in range 0 to 3 upper band is the secondary 80Mhz band + */ + if (sb < 4) { + secondary80_chan = chan1 + CH_40MHZ_APART; + } + /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */ + else + { + secondary80_chan = chan1 - CH_40MHZ_APART; + } + } + } + else { + /* for 20 and 40 Mhz */ + secondary80_chan = -1; + } + return secondary80_chan; +} + +/* + * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. + * + * chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived + * + * returns INVCHANSPEC in case the provided channel is 20/40 Mhz chanspec + */ +chanspec_t +wf_chspec_primary80_chspec(chanspec_t chspec) +{ + chanspec_t chspec80; + uint center_chan, chan1 = 0, chan2 = 0; + uint sb; + + ASSERT(!wf_chspec_malformed(chspec)); + if (CHSPEC_IS8080(chspec)) { + chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); + chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec)); + + sb = CHSPEC_CTL_SB(chspec); + + if (sb < 4) { + /* Primary 80MHz is on lower side */ + center_chan = chan1; + } + else + { + /* Primary 80MHz is on upper side */ + center_chan = chan2; + sb -= 4; + } + /* Create primary 80MHz chanspec */ + chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 |sb | center_chan); + } + else if (CHSPEC_IS160(chspec)) { + center_chan = CHSPEC_CHANNEL(chspec); + sb = CHSPEC_CTL_SB(chspec); + + if (sb < 4) { + /* Primary 80MHz is on upper side */ + center_chan -= CH_40MHZ_APART; + } + else + { + /* Primary 80MHz is on lower side */ + center_chan += CH_40MHZ_APART; + sb -= 4; + } + /* Create primary 80MHz chanspec */ + chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); + } + else + { + chspec80 = INVCHANSPEC; + } + return chspec80; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h new file mode 100644 index 000000000000..9defecab9993 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h @@ -0,0 +1,516 @@ +/* + * Misc utility routines for WL and Apps + * This header file housing the define and function prototype use by + * both the wl driver, tools & Apps. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ + */ + +#ifndef _bcmwifi_channels_h_ +#define _bcmwifi_channels_h_ + + +/* A chanspec holds the channel number, band, bandwidth and control sideband */ +typedef uint16 chanspec_t; + +/* channel defines */ +#define CH_UPPER_SB 0x01 +#define CH_LOWER_SB 0x02 +#define CH_EWA_VALID 0x04 +#define CH_80MHZ_APART 16 +#define CH_40MHZ_APART 8 +#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 MAXCHANNEL 224 /* 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 uint8's all over + */ +#define CHSPEC_CTLOVLP(sp1, sp2, sep) (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < \ + (sep)) + +/* All builds use the new 11ac ratespec/chanspec */ +#undef D11AC_IOTYPES +#define D11AC_IOTYPES + +#define WL_CHANSPEC_CHAN_MASK 0x00ff +#define WL_CHANSPEC_CHAN_SHIFT 0 +#define WL_CHANSPEC_CHAN1_MASK 0x000f +#define WL_CHANSPEC_CHAN1_SHIFT 0 +#define WL_CHANSPEC_CHAN2_MASK 0x00f0 +#define WL_CHANSPEC_CHAN2_SHIFT 4 + +#define WL_CHANSPEC_CTL_SB_MASK 0x0700 +#define WL_CHANSPEC_CTL_SB_SHIFT 8 +#define WL_CHANSPEC_CTL_SB_LLL 0x0000 +#define WL_CHANSPEC_CTL_SB_LLU 0x0100 +#define WL_CHANSPEC_CTL_SB_LUL 0x0200 +#define WL_CHANSPEC_CTL_SB_LUU 0x0300 +#define WL_CHANSPEC_CTL_SB_ULL 0x0400 +#define WL_CHANSPEC_CTL_SB_ULU 0x0500 +#define WL_CHANSPEC_CTL_SB_UUL 0x0600 +#define WL_CHANSPEC_CTL_SB_UUU 0x0700 +#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL +#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU +#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL + +#define WL_CHANSPEC_BW_MASK 0x3800 +#define WL_CHANSPEC_BW_SHIFT 11 +#define WL_CHANSPEC_BW_5 0x0000 +#define WL_CHANSPEC_BW_10 0x0800 +#define WL_CHANSPEC_BW_20 0x1000 +#define WL_CHANSPEC_BW_40 0x1800 +#define WL_CHANSPEC_BW_80 0x2000 +#define WL_CHANSPEC_BW_160 0x2800 +#define WL_CHANSPEC_BW_8080 0x3000 + +#define WL_CHANSPEC_BAND_MASK 0xc000 +#define WL_CHANSPEC_BAND_SHIFT 14 +#define WL_CHANSPEC_BAND_2G 0x0000 +#define WL_CHANSPEC_BAND_3G 0x4000 +#define WL_CHANSPEC_BAND_4G 0x8000 +#define WL_CHANSPEC_BAND_5G 0xc000 +#define INVCHANSPEC 255 + +/* channel defines */ +#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ + ((channel) - CH_10MHZ_APART) : 0) +#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ + ((channel) + CH_10MHZ_APART) : 0) + +#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) +#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ + ((channel) + 3 * CH_10MHZ_APART) : 0) +#define LU_20_SB(channel) LOWER_20_SB(channel) +#define UL_20_SB(channel) UPPER_20_SB(channel) + +#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) +#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) +#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) +#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ + (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) +#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ + ((channel) + CH_20MHZ_APART) : 0) +#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ + ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ + WL_CHANSPEC_BAND_5G)) +#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | \ + WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) +#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | \ + WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) + +/* simple MACROs to get different fields of chanspec */ +#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) +#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT +#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT +#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) + +#ifdef WL11N_20MHZONLY + +#define CHSPEC_IS10(chspec) 0 +#define CHSPEC_IS20(chspec) 1 +#ifndef CHSPEC_IS40 +#define CHSPEC_IS40(chspec) 0 +#endif +#ifndef CHSPEC_IS80 +#define CHSPEC_IS80(chspec) 0 +#endif +#ifndef CHSPEC_IS160 +#define CHSPEC_IS160(chspec) 0 +#endif +#ifndef CHSPEC_IS8080 +#define CHSPEC_IS8080(chspec) 0 +#endif + +#else /* !WL11N_20MHZONLY */ + +#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 +#ifndef CHSPEC_IS80 +#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) +#endif +#ifndef CHSPEC_IS160 +#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) +#endif +#ifndef CHSPEC_IS8080 +#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) +#endif + +#endif /* !WL11N_20MHZONLY */ + +#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_UPPER(chspec) \ + ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) +#define CHSPEC_SB_LOWER(chspec) \ + ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) +#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) + +/** + * Number of chars needed for wf_chspec_ntoa() destination character buffer. + */ +#define CHANSPEC_STR_LEN 20 + + +#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\ + CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080) + +/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made +* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80, +* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080). +* +* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide. +* If both chspec bandwidth and bw is not 160 wide, then the comparison is made. +*/ +#define CHSPEC_BW_GE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) >= bw)) + +#define CHSPEC_BW_LE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) <= bw)) + +#define CHSPEC_BW_GT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) > bw)) + +#define CHSPEC_BW_LT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) < bw)) + +/* Legacy Chanspec defines + * These are the defines for the previous format of the chanspec_t + */ +#define WL_LCHANSPEC_CHAN_MASK 0x00ff +#define WL_LCHANSPEC_CHAN_SHIFT 0 + +#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 +#define WL_LCHANSPEC_CTL_SB_SHIFT 8 +#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 +#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 +#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 + +#define WL_LCHANSPEC_BW_MASK 0x0C00 +#define WL_LCHANSPEC_BW_SHIFT 10 +#define WL_LCHANSPEC_BW_10 0x0400 +#define WL_LCHANSPEC_BW_20 0x0800 +#define WL_LCHANSPEC_BW_40 0x0C00 + +#define WL_LCHANSPEC_BAND_MASK 0xf000 +#define WL_LCHANSPEC_BAND_SHIFT 12 +#define WL_LCHANSPEC_BAND_5G 0x1000 +#define WL_LCHANSPEC_BAND_2G 0x2000 + +#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) +#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) +#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) +#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) +#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) +#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) +#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) +#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) +#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) + +#define LCHSPEC_SB_UPPER(chspec) \ + ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \ + (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) +#define LCHSPEC_SB_LOWER(chspec) \ + ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \ + (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) + +#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) + +#define CH20MHZ_LCHSPEC(channel) \ + (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \ + WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G)) + +/* + * WF_CHAN_FACTOR_* constants are used to calculate channel frequency + * given a channel number. + * chan_freq = chan_factor * 500Mhz + chan_number * 5 + */ + +/** + * Channel Factor for the starting frequence of 2.4 GHz channels. + * The value corresponds to 2407 MHz. + */ +#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ + +/** + * Channel Factor for the starting frequence of 5 GHz channels. + * The value corresponds to 5000 MHz. + */ +#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ + +/** + * Channel Factor for the starting frequence of 4.9 GHz channels. + * The value corresponds to 4000 MHz. + */ +#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ + +#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ + +/** + * No of sub-band vlaue of the specified Mhz chanspec + */ +#define WF_NUM_SIDEBANDS_40MHZ 2 +#define WF_NUM_SIDEBANDS_80MHZ 4 +#define WF_NUM_SIDEBANDS_8080MHZ 4 +#define WF_NUM_SIDEBANDS_160MHZ 8 + +/** + * Convert chanspec to ascii string + * + * @param chspec chanspec format + * @param buf ascii string of chanspec + * + * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes + * + * @see CHANSPEC_STR_LEN + */ +extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); + +/** + * Convert ascii string to chanspec + * + * @param a pointer to input string + * + * @return >= 0 if successful or 0 otherwise + */ +extern chanspec_t wf_chspec_aton(const char *a); + +/** + * Verify the chanspec fields are valid. + * + * Verify the chanspec is using a legal set field values, i.e. that the chanspec + * specified a band, bw, ctl_sb and channel and that the combination could be + * legal given some set of circumstances. + * + * @param chanspec input chanspec to verify + * + * @return TRUE if the chanspec is malformed, FALSE if it looks good. + */ +extern bool wf_chspec_malformed(chanspec_t chanspec); + +/** + * Verify the chanspec specifies a valid channel according to 802.11. + * + * @param chanspec input chanspec to verify + * + * @return TRUE if the chanspec is a valid 802.11 channel + */ +extern bool wf_chspec_valid(chanspec_t chanspec); + +/** + * Return the primary (control) channel. + * + * This function returns the channel number of the primary 20MHz channel. For + * 20MHz channels this is just the channel number. For 40MHz or wider channels + * it is the primary 20MHz channel specified by the chanspec. + * + * @param chspec input chanspec + * + * @return Returns the channel number of the primary 20MHz channel + */ +extern uint8 wf_chspec_ctlchan(chanspec_t chspec); + +/** + * Return the bandwidth string. + * + * This function returns the bandwidth string for the passed chanspec. + * + * @param chspec input chanspec + * + * @return Returns the bandwidth string + */ +extern char * wf_chspec_to_bw_str(chanspec_t chspec); + +/** + * Return the primary (control) chanspec. + * + * This function returns the chanspec of the primary 20MHz channel. For 20MHz + * channels this is just the chanspec. For 40MHz or wider channels it is the + * chanspec of the primary 20MHZ channel specified by the chanspec. + * + * @param chspec input chanspec + * + * @return Returns the chanspec of the primary 20MHz channel + */ +extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); + +/** + * Return a channel number corresponding to a frequency. + * + * This function returns the chanspec for the primary 40MHz of an 80MHz channel. + * The control sideband specifies the same 20MHz channel that the 80MHz channel is using + * as the primary 20MHz channel. + */ +extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); + +/* + * Return the channel number for a given frequency and base frequency. + * The returned channel number is relative to the given base frequency. + * If the given base frequency is zero, a base frequency of 5 GHz is assumed for + * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. + * + * Frequency is specified in MHz. + * The base frequency is specified as (start_factor * 500 kHz). + * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for + * 2.4 GHz and 5 GHz bands. + * + * The returned channel will be in the range [1, 14] in the 2.4 GHz band + * and [0, 200] otherwise. + * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the + * frequency is not a 2.4 GHz channel, or if the frequency is not and even + * multiple of 5 MHz from the base frequency to the base plus 1 GHz. + * + * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + * + * @param freq frequency in MHz + * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz + * + * @return Returns a channel number + * + * @see WF_CHAN_FACTOR_2_4_G + * @see WF_CHAN_FACTOR_5_G + */ +extern int wf_mhz2channel(uint freq, uint start_factor); + +/** + * Return the center frequency in MHz of the given channel and base frequency. + * + * Return the center frequency in MHz of the given channel and base frequency. + * The channel number is interpreted relative to the given base frequency. + * + * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. + * The base frequency is specified as (start_factor * 500 kHz). + * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for + * 2.4 GHz and 5 GHz bands. + * The channel range of [1, 14] is only checked for a start_factor of + * WF_CHAN_FACTOR_2_4_G (4814). + * Odd start_factors produce channels on .5 MHz boundaries, in which case + * the answer is rounded down to an integral MHz. + * -1 is returned for an out of range channel. + * + * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + * + * @param channel input channel number + * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz + * + * @return Returns a frequency in MHz + * + * @see WF_CHAN_FACTOR_2_4_G + * @see WF_CHAN_FACTOR_5_G + */ +extern int wf_channel2mhz(uint channel, uint start_factor); + +/** + * Returns the chanspec 80Mhz channel corresponding to the following input + * parameters + * + * primary_channel - primary 20Mhz channel + * center_channel - center frequecny of the 80Mhz channel + * + * The center_channel can be one of {42, 58, 106, 122, 138, 155} + * + * returns INVCHANSPEC in case of error + */ +extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel); + +/** + * Convert ctl chan and bw to chanspec + * + * @param ctl_ch channel + * @param bw bandwidth + * + * @return > 0 if successful or 0 otherwise + * + */ +extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); + +extern uint wf_channel2freq(uint channel); +extern uint wf_freq2channel(uint freq); + +/* + * Returns the 80+80 chanspec corresponding to the following input parameters + * + * primary_20mhz - Primary 20 Mhz channel + * chan1 - channel number of first 80 Mhz band + * chan2 - channel number of second 80 Mhz band + * + * parameters chan1 and chan2 are channel numbers in {42, 58, 106, 122, 138, 155} + * + * returns INVCHANSPEC in case of error + */ + +extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz, +uint8 chan1_80Mhz, uint8 chan2_80Mhz); + +/* + * Returns the primary 80 Mhz channel for the provided chanspec + * + * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved + * + * returns -1 in case the provided channel is 20/40 Mhz chanspec + */ +extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec); + +/* + * Returns the secondary 80 Mhz channel for the provided chanspec + * + * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved + * + * returns -1 in case the provided channel is 20/40 Mhz chanspec + */ +extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec); + +/* + * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. + */ +extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec); + + +#endif /* _bcmwifi_channels_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h new file mode 100644 index 000000000000..9a29f929361c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h @@ -0,0 +1,458 @@ +/* + * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmwifi_rates.h 5187 2012-06-29 06:17:50Z $ + */ + +#ifndef _bcmwifi_rates_h_ +#define _bcmwifi_rates_h_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define WL_RATESET_SZ_DSSS 4 +#define WL_RATESET_SZ_OFDM 8 +#define WL_RATESET_SZ_HT_MCS 8 +#define WL_RATESET_SZ_VHT_MCS 10 + +#define WL_TX_CHAINS_MAX 3 + +#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */ + +/* Transmit channel bandwidths */ +typedef enum wl_tx_bw { + WL_TX_BW_20, + WL_TX_BW_40, + WL_TX_BW_80, + WL_TX_BW_160, + WL_TX_BW_20IN40, + WL_TX_BW_20IN80, + WL_TX_BW_40IN80, + WL_TX_BW_20IN160, + WL_TX_BW_40IN160, + WL_TX_BW_80IN160, + WL_TX_BW_ALL +} wl_tx_bw_t; + + +/* + * Transmit modes. + * Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed + */ +typedef enum wl_tx_mode { + WL_TX_MODE_NONE, + WL_TX_MODE_STBC, + WL_TX_MODE_CDD, + WL_TX_MODE_TXBF, + WL_NUM_TX_MODES +} wl_tx_mode_t; + + +/* Number of transmit chains */ +typedef enum wl_tx_chains { + WL_TX_CHAINS_1 = 1, + WL_TX_CHAINS_2, + WL_TX_CHAINS_3 +} wl_tx_chains_t; + + +/* Number of transmit streams */ +typedef enum wl_tx_nss { + WL_TX_NSS_1 = 1, + WL_TX_NSS_2, + WL_TX_NSS_3 +} wl_tx_nss_t; + + +typedef enum clm_rates { + /************ + * 1 chain * + ************ + */ + + /* 1 Stream */ + WL_RATE_1X1_DSSS_1 = 0, + WL_RATE_1X1_DSSS_2 = 1, + WL_RATE_1X1_DSSS_5_5 = 2, + WL_RATE_1X1_DSSS_11 = 3, + + WL_RATE_1X1_OFDM_6 = 4, + WL_RATE_1X1_OFDM_9 = 5, + WL_RATE_1X1_OFDM_12 = 6, + WL_RATE_1X1_OFDM_18 = 7, + WL_RATE_1X1_OFDM_24 = 8, + WL_RATE_1X1_OFDM_36 = 9, + WL_RATE_1X1_OFDM_48 = 10, + WL_RATE_1X1_OFDM_54 = 11, + + WL_RATE_1X1_MCS0 = 12, + WL_RATE_1X1_MCS1 = 13, + WL_RATE_1X1_MCS2 = 14, + WL_RATE_1X1_MCS3 = 15, + WL_RATE_1X1_MCS4 = 16, + WL_RATE_1X1_MCS5 = 17, + WL_RATE_1X1_MCS6 = 18, + WL_RATE_1X1_MCS7 = 19, + + WL_RATE_1X1_VHT0SS1 = 12, + WL_RATE_1X1_VHT1SS1 = 13, + WL_RATE_1X1_VHT2SS1 = 14, + WL_RATE_1X1_VHT3SS1 = 15, + WL_RATE_1X1_VHT4SS1 = 16, + WL_RATE_1X1_VHT5SS1 = 17, + WL_RATE_1X1_VHT6SS1 = 18, + WL_RATE_1X1_VHT7SS1 = 19, + WL_RATE_1X1_VHT8SS1 = 20, + WL_RATE_1X1_VHT9SS1 = 21, + + + /************ + * 2 chains * + ************ + */ + + /* 1 Stream expanded + 1 */ + WL_RATE_1X2_DSSS_1 = 22, + WL_RATE_1X2_DSSS_2 = 23, + WL_RATE_1X2_DSSS_5_5 = 24, + WL_RATE_1X2_DSSS_11 = 25, + + WL_RATE_1X2_CDD_OFDM_6 = 26, + WL_RATE_1X2_CDD_OFDM_9 = 27, + WL_RATE_1X2_CDD_OFDM_12 = 28, + WL_RATE_1X2_CDD_OFDM_18 = 29, + WL_RATE_1X2_CDD_OFDM_24 = 30, + WL_RATE_1X2_CDD_OFDM_36 = 31, + WL_RATE_1X2_CDD_OFDM_48 = 32, + WL_RATE_1X2_CDD_OFDM_54 = 33, + + WL_RATE_1X2_CDD_MCS0 = 34, + WL_RATE_1X2_CDD_MCS1 = 35, + WL_RATE_1X2_CDD_MCS2 = 36, + WL_RATE_1X2_CDD_MCS3 = 37, + WL_RATE_1X2_CDD_MCS4 = 38, + WL_RATE_1X2_CDD_MCS5 = 39, + WL_RATE_1X2_CDD_MCS6 = 40, + WL_RATE_1X2_CDD_MCS7 = 41, + + WL_RATE_1X2_VHT0SS1 = 34, + WL_RATE_1X2_VHT1SS1 = 35, + WL_RATE_1X2_VHT2SS1 = 36, + WL_RATE_1X2_VHT3SS1 = 37, + WL_RATE_1X2_VHT4SS1 = 38, + WL_RATE_1X2_VHT5SS1 = 39, + WL_RATE_1X2_VHT6SS1 = 40, + WL_RATE_1X2_VHT7SS1 = 41, + WL_RATE_1X2_VHT8SS1 = 42, + WL_RATE_1X2_VHT9SS1 = 43, + + /* 2 Streams */ + WL_RATE_2X2_STBC_MCS0 = 44, + WL_RATE_2X2_STBC_MCS1 = 45, + WL_RATE_2X2_STBC_MCS2 = 46, + WL_RATE_2X2_STBC_MCS3 = 47, + WL_RATE_2X2_STBC_MCS4 = 48, + WL_RATE_2X2_STBC_MCS5 = 49, + WL_RATE_2X2_STBC_MCS6 = 50, + WL_RATE_2X2_STBC_MCS7 = 51, + + WL_RATE_2X2_STBC_VHT0SS1 = 44, + WL_RATE_2X2_STBC_VHT1SS1 = 45, + WL_RATE_2X2_STBC_VHT2SS1 = 46, + WL_RATE_2X2_STBC_VHT3SS1 = 47, + WL_RATE_2X2_STBC_VHT4SS1 = 48, + WL_RATE_2X2_STBC_VHT5SS1 = 49, + WL_RATE_2X2_STBC_VHT6SS1 = 50, + WL_RATE_2X2_STBC_VHT7SS1 = 51, + WL_RATE_2X2_STBC_VHT8SS1 = 52, + WL_RATE_2X2_STBC_VHT9SS1 = 53, + + WL_RATE_2X2_SDM_MCS8 = 54, + WL_RATE_2X2_SDM_MCS9 = 55, + WL_RATE_2X2_SDM_MCS10 = 56, + WL_RATE_2X2_SDM_MCS11 = 57, + WL_RATE_2X2_SDM_MCS12 = 58, + WL_RATE_2X2_SDM_MCS13 = 59, + WL_RATE_2X2_SDM_MCS14 = 60, + WL_RATE_2X2_SDM_MCS15 = 61, + + WL_RATE_2X2_VHT0SS2 = 54, + WL_RATE_2X2_VHT1SS2 = 55, + WL_RATE_2X2_VHT2SS2 = 56, + WL_RATE_2X2_VHT3SS2 = 57, + WL_RATE_2X2_VHT4SS2 = 58, + WL_RATE_2X2_VHT5SS2 = 59, + WL_RATE_2X2_VHT6SS2 = 60, + WL_RATE_2X2_VHT7SS2 = 61, + WL_RATE_2X2_VHT8SS2 = 62, + WL_RATE_2X2_VHT9SS2 = 63, + + /************ + * 3 chains * + ************ + */ + + /* 1 Stream expanded + 2 */ + WL_RATE_1X3_DSSS_1 = 64, + WL_RATE_1X3_DSSS_2 = 65, + WL_RATE_1X3_DSSS_5_5 = 66, + WL_RATE_1X3_DSSS_11 = 67, + + WL_RATE_1X3_CDD_OFDM_6 = 68, + WL_RATE_1X3_CDD_OFDM_9 = 69, + WL_RATE_1X3_CDD_OFDM_12 = 70, + WL_RATE_1X3_CDD_OFDM_18 = 71, + WL_RATE_1X3_CDD_OFDM_24 = 72, + WL_RATE_1X3_CDD_OFDM_36 = 73, + WL_RATE_1X3_CDD_OFDM_48 = 74, + WL_RATE_1X3_CDD_OFDM_54 = 75, + + WL_RATE_1X3_CDD_MCS0 = 76, + WL_RATE_1X3_CDD_MCS1 = 77, + WL_RATE_1X3_CDD_MCS2 = 78, + WL_RATE_1X3_CDD_MCS3 = 79, + WL_RATE_1X3_CDD_MCS4 = 80, + WL_RATE_1X3_CDD_MCS5 = 81, + WL_RATE_1X3_CDD_MCS6 = 82, + WL_RATE_1X3_CDD_MCS7 = 83, + + WL_RATE_1X3_VHT0SS1 = 76, + WL_RATE_1X3_VHT1SS1 = 77, + WL_RATE_1X3_VHT2SS1 = 78, + WL_RATE_1X3_VHT3SS1 = 79, + WL_RATE_1X3_VHT4SS1 = 80, + WL_RATE_1X3_VHT5SS1 = 81, + WL_RATE_1X3_VHT6SS1 = 82, + WL_RATE_1X3_VHT7SS1 = 83, + WL_RATE_1X3_VHT8SS1 = 84, + WL_RATE_1X3_VHT9SS1 = 85, + + /* 2 Streams expanded + 1 */ + WL_RATE_2X3_STBC_MCS0 = 86, + WL_RATE_2X3_STBC_MCS1 = 87, + WL_RATE_2X3_STBC_MCS2 = 88, + WL_RATE_2X3_STBC_MCS3 = 89, + WL_RATE_2X3_STBC_MCS4 = 90, + WL_RATE_2X3_STBC_MCS5 = 91, + WL_RATE_2X3_STBC_MCS6 = 92, + WL_RATE_2X3_STBC_MCS7 = 93, + + WL_RATE_2X3_STBC_VHT0SS1 = 86, + WL_RATE_2X3_STBC_VHT1SS1 = 87, + WL_RATE_2X3_STBC_VHT2SS1 = 88, + WL_RATE_2X3_STBC_VHT3SS1 = 89, + WL_RATE_2X3_STBC_VHT4SS1 = 90, + WL_RATE_2X3_STBC_VHT5SS1 = 91, + WL_RATE_2X3_STBC_VHT6SS1 = 92, + WL_RATE_2X3_STBC_VHT7SS1 = 93, + WL_RATE_2X3_STBC_VHT8SS1 = 94, + WL_RATE_2X3_STBC_VHT9SS1 = 95, + + WL_RATE_2X3_SDM_MCS8 = 96, + WL_RATE_2X3_SDM_MCS9 = 97, + WL_RATE_2X3_SDM_MCS10 = 98, + WL_RATE_2X3_SDM_MCS11 = 99, + WL_RATE_2X3_SDM_MCS12 = 100, + WL_RATE_2X3_SDM_MCS13 = 101, + WL_RATE_2X3_SDM_MCS14 = 102, + WL_RATE_2X3_SDM_MCS15 = 103, + + WL_RATE_2X3_VHT0SS2 = 96, + WL_RATE_2X3_VHT1SS2 = 97, + WL_RATE_2X3_VHT2SS2 = 98, + WL_RATE_2X3_VHT3SS2 = 99, + WL_RATE_2X3_VHT4SS2 = 100, + WL_RATE_2X3_VHT5SS2 = 101, + WL_RATE_2X3_VHT6SS2 = 102, + WL_RATE_2X3_VHT7SS2 = 103, + WL_RATE_2X3_VHT8SS2 = 104, + WL_RATE_2X3_VHT9SS2 = 105, + + /* 3 Streams */ + WL_RATE_3X3_SDM_MCS16 = 106, + WL_RATE_3X3_SDM_MCS17 = 107, + WL_RATE_3X3_SDM_MCS18 = 108, + WL_RATE_3X3_SDM_MCS19 = 109, + WL_RATE_3X3_SDM_MCS20 = 110, + WL_RATE_3X3_SDM_MCS21 = 111, + WL_RATE_3X3_SDM_MCS22 = 112, + WL_RATE_3X3_SDM_MCS23 = 113, + + WL_RATE_3X3_VHT0SS3 = 106, + WL_RATE_3X3_VHT1SS3 = 107, + WL_RATE_3X3_VHT2SS3 = 108, + WL_RATE_3X3_VHT3SS3 = 109, + WL_RATE_3X3_VHT4SS3 = 110, + WL_RATE_3X3_VHT5SS3 = 111, + WL_RATE_3X3_VHT6SS3 = 112, + WL_RATE_3X3_VHT7SS3 = 113, + WL_RATE_3X3_VHT8SS3 = 114, + WL_RATE_3X3_VHT9SS3 = 115, + + + /**************************** + * TX Beamforming, 2 chains * + **************************** + */ + + /* 1 Stream expanded + 1 */ + + WL_RATE_1X2_TXBF_OFDM_6 = 116, + WL_RATE_1X2_TXBF_OFDM_9 = 117, + WL_RATE_1X2_TXBF_OFDM_12 = 118, + WL_RATE_1X2_TXBF_OFDM_18 = 119, + WL_RATE_1X2_TXBF_OFDM_24 = 120, + WL_RATE_1X2_TXBF_OFDM_36 = 121, + WL_RATE_1X2_TXBF_OFDM_48 = 122, + WL_RATE_1X2_TXBF_OFDM_54 = 123, + + WL_RATE_1X2_TXBF_MCS0 = 124, + WL_RATE_1X2_TXBF_MCS1 = 125, + WL_RATE_1X2_TXBF_MCS2 = 126, + WL_RATE_1X2_TXBF_MCS3 = 127, + WL_RATE_1X2_TXBF_MCS4 = 128, + WL_RATE_1X2_TXBF_MCS5 = 129, + WL_RATE_1X2_TXBF_MCS6 = 130, + WL_RATE_1X2_TXBF_MCS7 = 131, + + WL_RATE_1X2_TXBF_VHT0SS1 = 124, + WL_RATE_1X2_TXBF_VHT1SS1 = 125, + WL_RATE_1X2_TXBF_VHT2SS1 = 126, + WL_RATE_1X2_TXBF_VHT3SS1 = 127, + WL_RATE_1X2_TXBF_VHT4SS1 = 128, + WL_RATE_1X2_TXBF_VHT5SS1 = 129, + WL_RATE_1X2_TXBF_VHT6SS1 = 130, + WL_RATE_1X2_TXBF_VHT7SS1 = 131, + WL_RATE_1X2_TXBF_VHT8SS1 = 132, + WL_RATE_1X2_TXBF_VHT9SS1 = 133, + + /* 2 Streams */ + + WL_RATE_2X2_TXBF_SDM_MCS8 = 134, + WL_RATE_2X2_TXBF_SDM_MCS9 = 135, + WL_RATE_2X2_TXBF_SDM_MCS10 = 136, + WL_RATE_2X2_TXBF_SDM_MCS11 = 137, + WL_RATE_2X2_TXBF_SDM_MCS12 = 138, + WL_RATE_2X2_TXBF_SDM_MCS13 = 139, + WL_RATE_2X2_TXBF_SDM_MCS14 = 140, + WL_RATE_2X2_TXBF_SDM_MCS15 = 141, + + WL_RATE_2X2_TXBF_VHT0SS2 = 134, + WL_RATE_2X2_TXBF_VHT1SS2 = 135, + WL_RATE_2X2_TXBF_VHT2SS2 = 136, + WL_RATE_2X2_TXBF_VHT3SS2 = 137, + WL_RATE_2X2_TXBF_VHT4SS2 = 138, + WL_RATE_2X2_TXBF_VHT5SS2 = 139, + WL_RATE_2X2_TXBF_VHT6SS2 = 140, + WL_RATE_2X2_TXBF_VHT7SS2 = 141, + + + /**************************** + * TX Beamforming, 3 chains * + **************************** + */ + + /* 1 Stream expanded + 2 */ + + WL_RATE_1X3_TXBF_OFDM_6 = 142, + WL_RATE_1X3_TXBF_OFDM_9 = 143, + WL_RATE_1X3_TXBF_OFDM_12 = 144, + WL_RATE_1X3_TXBF_OFDM_18 = 145, + WL_RATE_1X3_TXBF_OFDM_24 = 146, + WL_RATE_1X3_TXBF_OFDM_36 = 147, + WL_RATE_1X3_TXBF_OFDM_48 = 148, + WL_RATE_1X3_TXBF_OFDM_54 = 149, + + WL_RATE_1X3_TXBF_MCS0 = 150, + WL_RATE_1X3_TXBF_MCS1 = 151, + WL_RATE_1X3_TXBF_MCS2 = 152, + WL_RATE_1X3_TXBF_MCS3 = 153, + WL_RATE_1X3_TXBF_MCS4 = 154, + WL_RATE_1X3_TXBF_MCS5 = 155, + WL_RATE_1X3_TXBF_MCS6 = 156, + WL_RATE_1X3_TXBF_MCS7 = 157, + + WL_RATE_1X3_TXBF_VHT0SS1 = 150, + WL_RATE_1X3_TXBF_VHT1SS1 = 151, + WL_RATE_1X3_TXBF_VHT2SS1 = 152, + WL_RATE_1X3_TXBF_VHT3SS1 = 153, + WL_RATE_1X3_TXBF_VHT4SS1 = 154, + WL_RATE_1X3_TXBF_VHT5SS1 = 155, + WL_RATE_1X3_TXBF_VHT6SS1 = 156, + WL_RATE_1X3_TXBF_VHT7SS1 = 157, + WL_RATE_1X3_TXBF_VHT8SS1 = 158, + WL_RATE_1X3_TXBF_VHT9SS1 = 159, + + /* 2 Streams expanded + 1 */ + + WL_RATE_2X3_TXBF_SDM_MCS8 = 160, + WL_RATE_2X3_TXBF_SDM_MCS9 = 161, + WL_RATE_2X3_TXBF_SDM_MCS10 = 162, + WL_RATE_2X3_TXBF_SDM_MCS11 = 163, + WL_RATE_2X3_TXBF_SDM_MCS12 = 164, + WL_RATE_2X3_TXBF_SDM_MCS13 = 165, + WL_RATE_2X3_TXBF_SDM_MCS14 = 166, + WL_RATE_2X3_TXBF_SDM_MCS15 = 167, + + WL_RATE_2X3_TXBF_VHT0SS2 = 160, + WL_RATE_2X3_TXBF_VHT1SS2 = 161, + WL_RATE_2X3_TXBF_VHT2SS2 = 162, + WL_RATE_2X3_TXBF_VHT3SS2 = 163, + WL_RATE_2X3_TXBF_VHT4SS2 = 164, + WL_RATE_2X3_TXBF_VHT5SS2 = 165, + WL_RATE_2X3_TXBF_VHT6SS2 = 166, + WL_RATE_2X3_TXBF_VHT7SS2 = 167, + WL_RATE_2X3_TXBF_VHT8SS2 = 168, + WL_RATE_2X3_TXBF_VHT9SS2 = 169, + + /* 3 Streams */ + + WL_RATE_3X3_TXBF_SDM_MCS16 = 170, + WL_RATE_3X3_TXBF_SDM_MCS17 = 171, + WL_RATE_3X3_TXBF_SDM_MCS18 = 172, + WL_RATE_3X3_TXBF_SDM_MCS19 = 173, + WL_RATE_3X3_TXBF_SDM_MCS20 = 174, + WL_RATE_3X3_TXBF_SDM_MCS21 = 175, + WL_RATE_3X3_TXBF_SDM_MCS22 = 176, + WL_RATE_3X3_TXBF_SDM_MCS23 = 177, + + WL_RATE_3X3_TXBF_VHT0SS3 = 170, + WL_RATE_3X3_TXBF_VHT1SS3 = 171, + WL_RATE_3X3_TXBF_VHT2SS3 = 172, + WL_RATE_3X3_TXBF_VHT3SS3 = 173, + WL_RATE_3X3_TXBF_VHT4SS3 = 174, + WL_RATE_3X3_TXBF_VHT5SS3 = 175, + WL_RATE_3X3_TXBF_VHT6SS3 = 176, + WL_RATE_3X3_TXBF_VHT7SS3 = 177 +} clm_rates_t; + +/* Number of rate codes */ +#define WL_NUMRATES 178 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _bcmwifi_rates_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c new file mode 100644 index 000000000000..3f8e67cd5cf6 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c @@ -0,0 +1,410 @@ +/* + * Driver O/S-independent utility routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: bcmxtlv.c 487603 2014-06-26 12:33:22Z $ + */ + +#include + +#include +#include + +#include + +#ifdef BCMDRIVER + #include +#else /* !BCMDRIVER */ + #include /* AS!!! */ + #include + #include +#include +#ifndef ASSERT + #define ASSERT(exp) +#endif +inline void* MALLOCZ(void *o, size_t s) { BCM_REFERENCE(o); return calloc(1, s); } +inline void MFREE(void *o, void *p, size_t s) { BCM_REFERENCE(o); BCM_REFERENCE(s); free(p); } +#endif /* !BCMDRIVER */ + +#include +#include + +static INLINE int bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts) +{ + return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + BCM_XTLV_HDR_SIZE, 4) + : (dlen + BCM_XTLV_HDR_SIZE)); +} + +bcm_xtlv_t * +bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts) +{ + int sz; + /* advance to next elt */ + sz = BCM_XTLV_SIZE(elt, opts); + elt = (bcm_xtlv_t*)((uint8 *)elt + sz); + *buflen -= sz; + + /* validate next elt */ + if (!bcm_valid_xtlv(elt, *buflen, opts)) + return NULL; + + return elt; +} + +int +bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, bcm_xtlv_opts_t opts) +{ + if (!tlv_buf || !buf || !len) + return BCME_BADARG; + + tlv_buf->opts = opts; + tlv_buf->size = len; + tlv_buf->head = buf; + tlv_buf->buf = buf; + return BCME_OK; +} + +uint16 +bcm_xtlv_buf_len(bcm_xtlvbuf_t *tbuf) +{ + if (tbuf == NULL) return 0; + return (tbuf->buf - tbuf->head); +} +uint16 +bcm_xtlv_buf_rlen(bcm_xtlvbuf_t *tbuf) +{ + if (tbuf == NULL) return 0; + return tbuf->size - bcm_xtlv_buf_len(tbuf); +} +uint8 * +bcm_xtlv_buf(bcm_xtlvbuf_t *tbuf) +{ + if (tbuf == NULL) return NULL; + return tbuf->buf; +} +uint8 * +bcm_xtlv_head(bcm_xtlvbuf_t *tbuf) +{ + if (tbuf == NULL) return NULL; + return tbuf->head; +} +int +bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const void *data, uint16 dlen) +{ + bcm_xtlv_t *xtlv; + int size; + + if (tbuf == NULL) + return BCME_BADARG; + size = bcm_xtlv_size_for_data(dlen, tbuf->opts); + if (bcm_xtlv_buf_rlen(tbuf) < size) + return BCME_NOMEM; + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); + xtlv->id = htol16(type); + xtlv->len = htol16(dlen); + memcpy(xtlv->data, data, dlen); + tbuf->buf += size; + return BCME_OK; +} +int +bcm_xtlv_put_8(bcm_xtlvbuf_t *tbuf, uint16 type, const int8 data) +{ + bcm_xtlv_t *xtlv; + int size; + + if (tbuf == NULL) + return BCME_BADARG; + size = bcm_xtlv_size_for_data(1, tbuf->opts); + if (bcm_xtlv_buf_rlen(tbuf) < size) + return BCME_NOMEM; + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); + xtlv->id = htol16(type); + xtlv->len = htol16(sizeof(data)); + xtlv->data[0] = data; + tbuf->buf += size; + return BCME_OK; +} +int +bcm_xtlv_put_16(bcm_xtlvbuf_t *tbuf, uint16 type, const int16 data) +{ + bcm_xtlv_t *xtlv; + int size; + + if (tbuf == NULL) + return BCME_BADARG; + size = bcm_xtlv_size_for_data(2, tbuf->opts); + if (bcm_xtlv_buf_rlen(tbuf) < size) + return BCME_NOMEM; + + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); + xtlv->id = htol16(type); + xtlv->len = htol16(sizeof(data)); + htol16_ua_store(data, xtlv->data); + tbuf->buf += size; + return BCME_OK; +} +int +bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data) +{ + bcm_xtlv_t *xtlv; + int size; + + if (tbuf == NULL) + return BCME_BADARG; + size = bcm_xtlv_size_for_data(4, tbuf->opts); + if (bcm_xtlv_buf_rlen(tbuf) < size) + return BCME_NOMEM; + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); + xtlv->id = htol16(type); + xtlv->len = htol16(sizeof(data)); + htol32_ua_store(data, xtlv->data); + tbuf->buf += size; + return BCME_OK; +} + +/* + * upacks xtlv record from buf checks the type + * copies data to callers buffer + * advances tlv pointer to next record + * caller's resposible for dst space check + */ +int +bcm_unpack_xtlv_entry(uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst, + bcm_xtlv_opts_t opts) +{ + bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; + uint16 len; + uint16 type; + + ASSERT(ptlv); + /* tlv headr is always packed in LE order */ + len = ltoh16(ptlv->len); + type = ltoh16(ptlv->id); + if (len == 0) { + /* z-len tlv headers: allow, but don't process */ + printf("z-len, skip unpack\n"); + } else { + if ((type != xpct_type) || + (len > xpct_len)) { + printf("xtlv_unpack Error: found[type:%d,len:%d] != xpct[type:%d,len:%d]\n", + type, len, xpct_type, xpct_len); + return BCME_BADARG; + } + /* copy tlv record to caller's buffer */ + memcpy(dst, ptlv->data, ptlv->len); + } + *tlv_buf += BCM_XTLV_SIZE(ptlv, opts); + return BCME_OK; +} + +/* + * packs user data into tlv record + * advances tlv pointer to next xtlv slot + * buflen is used for tlv_buf space check + */ +int +bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src, + bcm_xtlv_opts_t opts) +{ + bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; + int size; + + ASSERT(ptlv); + ASSERT(src); + + size = bcm_xtlv_size_for_data(len, opts); + + /* copy data from tlv buffer to dst provided by user */ + if (size > *buflen) { + printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n", + size, *buflen); + return BCME_BADLEN; + } + ptlv->id = htol16(type); + ptlv->len = htol16(len); + + /* copy callers data */ + memcpy(ptlv->data, src, len); + + /* advance callers pointer to tlv buff */ + *tlv_buf += size; + /* decrement the len */ + *buflen -= size; + return BCME_OK; +} + +/* + * unpack all xtlv records from the issue a callback + * to set function one call per found tlv record + */ +int +bcm_unpack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, + bcm_xtlv_unpack_cbfn_t *cbfn) +{ + uint16 len; + uint16 type; + int res = 0; + int size; + bcm_xtlv_t *ptlv; + int sbuflen = buflen; + + ASSERT(!buflen || tlv_buf); + ASSERT(!buflen || cbfn); + + while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) { + ptlv = (bcm_xtlv_t *)tlv_buf; + + /* tlv header is always packed in LE order */ + len = ltoh16(ptlv->len); + type = ltoh16(ptlv->id); + + size = bcm_xtlv_size_for_data(len, opts); + + sbuflen -= size; + /* check for possible buffer overrun */ + if (sbuflen < 0) + break; + + if ((res = cbfn(ctx, ptlv->data, type, len)) != BCME_OK) + break; + tlv_buf += size; + } + return res; +} + +int +bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, + bcm_pack_xtlv_next_info_cbfn_t get_next, bcm_pack_xtlv_pack_next_cbfn_t pack_next, + int *outlen) +{ + int res = BCME_OK; + uint16 tlv_id; + uint16 tlv_len; + uint8 *startp; + uint8 *endp; + uint8 *buf; + bool more; + int size; + + ASSERT(get_next && pack_next); + + buf = (uint8 *)tlv_buf; + startp = buf; + endp = (uint8 *)buf + buflen; + more = TRUE; + while (more && (buf < endp)) { + more = get_next(ctx, &tlv_id, &tlv_len); + size = bcm_xtlv_size_for_data(tlv_len, opts); + if ((buf + size) >= endp) { + res = BCME_BUFTOOSHORT; + goto done; + } + + htol16_ua_store(tlv_id, buf); + htol16_ua_store(tlv_len, buf + sizeof(tlv_id)); + pack_next(ctx, tlv_id, tlv_len, buf + BCM_XTLV_HDR_SIZE); + buf += size; + } + + if (more) + res = BCME_BUFTOOSHORT; + +done: + if (outlen) + *outlen = buf - startp; + return res; +} + +/* + * pack xtlv buffer from memory according to xtlv_desc_t + */ +int +bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items, + bcm_xtlv_opts_t opts) +{ + int res = 0; + uint8 *ptlv = (uint8 *)*tlv_buf; + + while (items->type != 0) { + if ((items->len > 0) && (res = bcm_pack_xtlv_entry(&ptlv, + buflen, items->type, + items->len, items->ptr, opts) != BCME_OK)) { + break; + } + items++; + } + *tlv_buf = ptlv; /* update the external pointer */ + return res; +} + +/* + * unpack xtlv buffer to memory according to xtlv_desc_t + * + */ +int +bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items, bcm_xtlv_opts_t opts) +{ + int res = BCME_OK; + bcm_xtlv_t *elt; + + elt = bcm_valid_xtlv((bcm_xtlv_t *)tlv_buf, *buflen, opts) ? (bcm_xtlv_t *)tlv_buf : NULL; + if (!elt || !items) { + res = BCME_BADARG; + return res; + } + + for (; elt != NULL && res == BCME_OK; elt = bcm_next_xtlv(elt, buflen, opts)) { + /* find matches in desc_t items */ + xtlv_desc_t *dst_desc = items; + uint16 len = ltoh16(elt->len); + + while (dst_desc->type != 0) { + if (ltoh16(elt->id) != dst_desc->type) { + dst_desc++; + continue; + } + if (len != dst_desc->len) + res = BCME_BADLEN; + else + memcpy(dst_desc->ptr, elt->data, len); + break; + } + if (dst_desc->type == 0) + res = BCME_NOTFOUND; + } + + if (*buflen != 0 && res == BCME_OK) + res = BCME_BUFTOOSHORT; + + return res; +} + +int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts) +{ + int size; /* entire size of the XTLV including header, data, and optional padding */ + int len; /* XTLV's value real length wthout padding */ + + len = BCM_XTLV_LEN(elt); + + size = bcm_xtlv_size_for_data(len, opts); + + return size; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd.h new file mode 100644 index 000000000000..743fa9c40863 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd.h @@ -0,0 +1,1007 @@ +/* + * Header file describing the internal (inter-module) DHD interfaces. + * + * Provides type definitions and function prototypes used to link the + * DHD OS, bus, and protocol modules. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2013 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd.h 701450 2017-05-25 02:10:23Z $ + */ + +/**************** + * Common types * + */ + +#ifndef _dhd_h_ +#define _dhd_h_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ +/* The kernel threading is sdio-specific */ +struct task_struct; +struct sched_param; +int setScheduler(struct task_struct *p, int policy, struct sched_param *param); +int get_scheduler_policy(struct task_struct *p); + +#define ALL_INTERFACES 0xff + +#include +#include + + +#ifdef CONFIG_BCM_WLAN_RAMDUMP +#include +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + +#if defined(WL11U) && !defined(MFP) +#define MFP /* Applying interaction with MFP by spec HS2.0 REL2 */ +#endif /* WL11U */ + +#if defined(KEEP_ALIVE) +/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ +#define KEEP_ALIVE_PERIOD 55000 +#define NULL_PKT_STR "null_pkt" +#endif /* KEEP_ALIVE */ +/* Forward decls */ +struct dhd_bus; +struct dhd_prot; +struct dhd_info; +struct dhd_ioctl; + +/* The level of bus communication with the dongle */ +enum dhd_bus_state { + DHD_BUS_DOWN, /* Not ready for frame transfers */ + DHD_BUS_LOAD, /* Download access only (CPU reset) */ + DHD_BUS_DATA /* Ready for frame transfers */ +}; + + +enum dhd_op_flags { +/* Firmware requested operation mode */ + DHD_FLAG_STA_MODE = (1 << (0)), /* STA only */ + DHD_FLAG_HOSTAP_MODE = (1 << (1)), /* SOFTAP only */ + DHD_FLAG_P2P_MODE = (1 << (2)), /* P2P Only */ + /* STA + P2P */ + DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), + DHD_FLAG_CONCURR_MULTI_CHAN_MODE = (1 << (4)), /* STA + P2P */ + /* Current P2P mode for P2P connection */ + DHD_FLAG_P2P_GC_MODE = (1 << (5)), + DHD_FLAG_P2P_GO_MODE = (1 << (6)), + DHD_FLAG_MBSS_MODE = (1 << (7)), /* MBSS in future */ + DHD_FLAG_IBSS_MODE = (1 << (8)), + DHD_FLAG_MFG_MODE = (1 << (9)) +}; + +/* Max sequential TX/RX Control timeouts to set HANG event */ +#ifndef MAX_CNTL_TX_TIMEOUT +#define MAX_CNTL_TX_TIMEOUT 2 +#endif /* MAX_CNTL_TX_TIMEOUT */ +#ifndef MAX_CNTL_RX_TIMEOUT +#define MAX_CNTL_RX_TIMEOUT 1 +#endif /* MAX_CNTL_RX_TIMEOUT */ + +#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ +#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ +#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ + +#ifndef POWERUP_MAX_RETRY +#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ +#endif +#ifndef POWERUP_WAIT_MS +#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ +#endif + +enum dhd_bus_wake_state { + WAKE_LOCK_OFF, + WAKE_LOCK_PRIV, + WAKE_LOCK_DPC, + WAKE_LOCK_IOCTL, + WAKE_LOCK_DOWNLOAD, + WAKE_LOCK_TMOUT, + WAKE_LOCK_WATCHDOG, + WAKE_LOCK_LINK_DOWN_TMOUT, + WAKE_LOCK_PNO_FIND_TMOUT, + WAKE_LOCK_SOFTAP_SET, + WAKE_LOCK_SOFTAP_STOP, + WAKE_LOCK_SOFTAP_START, + WAKE_LOCK_SOFTAP_THREAD +}; + +enum dhd_prealloc_index { + DHD_PREALLOC_PROT = 0, + DHD_PREALLOC_RXBUF, + DHD_PREALLOC_DATABUF, + DHD_PREALLOC_OSL_BUF, +#if defined(STATIC_WL_PRIV_STRUCT) + DHD_PREALLOC_WIPHY_ESCAN0 = 5, +#endif /* STATIC_WL_PRIV_STRUCT */ + DHD_PREALLOC_DHD_INFO = 7, + DHD_PREALLOC_DHD_WLFC_INFO = 8, + DHD_PREALLOC_DHD_WLFC_HANGER = 12 +}; + +/* Packet alignment for most efficient SDIO (can change based on platform) */ +#ifndef DHD_SDALIGN +#define DHD_SDALIGN 32 +#endif + +#ifdef DHD_DEBUG +#define DHD_JOIN_MAX_TIME_DEFAULT 10000 /* ms: Max time out for joining AP */ +#define DHD_SCAN_DEF_TIMEOUT 10000 /* ms: Max time out for scan in progress */ +#endif + +/* host reordering packts logic */ +/* followed the structure to hold the reorder buffers (void **p) */ +typedef struct reorder_info { + void **p; + uint8 flow_id; + uint8 cur_idx; + uint8 exp_idx; + uint8 max_idx; + uint8 pend_pkts; +} reorder_info_t; + +#ifdef DHDTCPACK_SUPPRESS +#define TCPACK_SUP_OFF 0 /* TCPACK suppress off */ +/* Replace TCPACK in txq when new coming one has higher ACK number. */ +#define TCPACK_SUP_REPLACE 1 +/* TCPACK_SUP_REPLACE + delayed TCPACK TX unless ACK to PSH DATA. + * This will give benefits to Half-Duplex bus interface(e.g. SDIO) that + * 1. we are able to read TCP DATA packets first from the bus + * 2. TCPACKs that do not need to hurry delivered remains longer in TXQ so can be suppressed. + */ +#define TCPACK_SUP_DELAYTX 2 +#endif /* DHDTCPACK_SUPPRESS */ + +/* Common structure for module and instance linkage */ +typedef struct dhd_pub { + /* Linkage ponters */ + osl_t *osh; /* OSL handle */ + struct dhd_bus *bus; /* Bus module handle */ + struct dhd_prot *prot; /* Protocol module handle */ + struct dhd_info *info; /* Info module handle */ + + /* to NDIS developer, the structure dhd_common is redundant, + * please do NOT merge it back from other branches !!! + */ + + + /* Internal dhd items */ + bool up; /* Driver up/down (to OS) */ + bool txoff; /* Transmit flow-controlled */ + bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ + enum dhd_bus_state busstate; + uint hdrlen; /* Total DHD header length (proto + bus) */ + uint maxctl; /* Max size rxctl request from proto to bus */ + uint rxsz; /* Rx buffer size bus module should use */ + uint8 wme_dp; /* wme discard priority */ + + /* Dongle media info */ + bool iswl; /* Dongle-resident driver is wl */ + ulong drv_version; /* Version of dongle-resident driver */ + struct ether_addr mac; /* MAC address obtained from dongle */ + dngl_stats_t dstats; /* Stats for dongle-based data */ + + /* Additional stats for the bus level */ + ulong tx_packets; /* Data packets sent to dongle */ + ulong tx_multicast; /* Multicast data packets sent to dongle */ + ulong tx_errors; /* Errors in sending data to dongle */ + ulong tx_ctlpkts; /* Control packets sent to dongle */ + ulong tx_ctlerrs; /* Errors sending control frames to dongle */ + ulong rx_packets; /* Packets sent up the network interface */ + ulong rx_multicast; /* Multicast packets sent up the network interface */ + ulong rx_errors; /* Errors processing rx data packets */ + ulong rx_ctlpkts; /* Control frames processed from dongle */ + ulong rx_ctlerrs; /* Errors in processing rx control frames */ + ulong rx_dropped; /* Packets dropped locally (no memory) */ + ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ + ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ + + ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ + ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ + ulong fc_packets; /* Number of flow control pkts recvd */ + + /* Last error return */ + int bcmerror; + uint tickcnt; + + /* Last error from dongle */ + int dongle_error; + + uint8 country_code[WLC_CNTRY_BUF_SZ]; + + /* Suspend disable flag and "in suspend" flag */ + int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ + int in_suspend; /* flag set to 1 when early suspend called */ +#ifdef PNO_SUPPORT + int pno_enable; /* pno status : "1" is pno enable */ + int pno_suspend; /* pno suspend status : "1" is pno suspended */ +#endif /* PNO_SUPPORT */ + /* DTIM skip value, default 0(or 1) means wake each DTIM + * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) + */ + int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ +#ifdef PKT_FILTER_SUPPORT + int early_suspended; /* Early suspend status */ + int dhcp_in_progress; /* DHCP period */ +#endif + + /* Pkt filter defination */ + char * pktfilter[100]; + int pktfilter_count; + + wl_country_t dhd_cspec; /* Current Locale info */ + char eventmask[WL_EVENTING_MASK_LEN]; + int op_mode; /* STA, HostAPD, WFD, SoftAP */ + +/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. + * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework + * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile + */ +/* #define WL_ENABLE_P2P_IF 1 */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ + struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ +#endif + +#ifdef PROP_TXSTATUS + bool wlfc_enabled; + int wlfc_mode; + void* wlfc_state; + /* + Mode in which the dhd flow control shall operate. Must be set before + traffic starts to the device. + 0 - Do not do any proptxtstatus flow control + 1 - Use implied credit from a packet status + 2 - Use explicit credit + 3 - Only AMPDU hostreorder used. no wlfc. + */ + uint8 proptxstatus_mode; + bool proptxstatus_txoff; + bool proptxstatus_module_ignore; + bool proptxstatus_credit_ignore; + bool proptxstatus_txstatus_ignore; + + bool wlfc_rxpkt_chk; + /* + * implement below functions in each platform if needed. + */ + /* platform specific function whether to skip flow control */ + bool (*skip_fc)(void); + /* platform specific function for wlfc_enable and wlfc_deinit */ + void (*plat_init)(void *dhd); + void (*plat_deinit)(void *dhd); +#endif /* PROP_TXSTATUS */ +#ifdef PNO_SUPPORT + void *pno_state; +#endif +#ifdef RTT_SUPPORT + void *rtt_state; +#endif +#ifdef ROAM_AP_ENV_DETECTION + bool roam_env_detection; +#endif + bool dongle_isolation; + bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ + int hang_was_sent; + int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ + int txcnt_timeout; /* counter txcnt timeout to send HANG */ + bool hang_report; /* enable hang report by default */ +#ifdef WLMEDIA_HTSF + uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ +#endif +#ifdef WLTDLS + bool tdls_enable; +#endif + struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; + char fw_capabilities[WLC_IOCTL_SMLEN]; + #define MAXSKBPEND 1024 + void *skbbuf[MAXSKBPEND]; + uint32 store_idx; + uint32 sent_idx; +#ifdef DHDTCPACK_SUPPRESS + uint8 tcpack_sup_mode; /* TCPACK suppress mode */ + void *tcpack_sup_module; /* TCPACK suppress module */ +#endif /* DHDTCPACK_SUPPRESS */ +#if defined(ARP_OFFLOAD_SUPPORT) + uint32 arp_version; +#endif +#if defined(CUSTOMER_HW5) + bool dhd_bug_on; +#endif +#ifdef CONFIG_BCM_WLAN_RAMDUMP + char crash_reason[BCM_WLAN_CRASH_REASON_LEN]; +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ +#ifdef GSCAN_SUPPORT + bool lazy_roam_enable; +#endif /* GSCAN_SUPPORT */ + uint8 *soc_ram; + uint32 soc_ram_length; +#ifdef DHD_LOSSLESS_ROAMING + uint8 dequeue_prec_map; +#endif /* DHD_LOSSLESS_ROAMING */ + uint8 rand_mac_oui[DOT11_OUI_LEN]; +} dhd_pub_t; +#if defined(CUSTOMER_HW5) +#define MAX_RESCHED_CNT 600 +#endif + + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) + + #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); + #define _DHD_PM_RESUME_WAIT(a, b) do {\ + int retry = 0; \ + SMP_RD_BARRIER_DEPENDS(); \ + while (dhd_mmc_suspend && retry++ != b) { \ + SMP_RD_BARRIER_DEPENDS(); \ + wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ + } \ + } while (0) + #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) + #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) + #ifdef CUSTOMER_HW4 + #define DHD_PM_RESUME_RETURN_ERROR(a) do { \ + if (dhd_mmc_suspend) { \ + printf("%s[%d]: mmc is still in suspend state!!!\n", \ + __FUNCTION__, __LINE__); \ + return a; \ + } \ + } while (0) + #else + #define DHD_PM_RESUME_RETURN_ERROR(a) do { \ + if (dhd_mmc_suspend) return a; } while (0) + #endif + #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) + + #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); + #define SPINWAIT_SLEEP(a, exp, us) do { \ + uint countdown = (us) + 9999; \ + while ((exp) && (countdown >= 10000)) { \ + wait_event_interruptible_timeout(a, FALSE, 1); \ + countdown -= 10000; \ + } \ + } while (0) + + #else + + #define DHD_PM_RESUME_WAIT_INIT(a) + #define DHD_PM_RESUME_WAIT(a) + #define DHD_PM_RESUME_WAIT_FOREVER(a) + #define DHD_PM_RESUME_RETURN_ERROR(a) + #define DHD_PM_RESUME_RETURN + + #define DHD_SPINWAIT_SLEEP_INIT(a) + #define SPINWAIT_SLEEP(a, exp, us) do { \ + uint countdown = (us) + 9; \ + while ((exp) && (countdown >= 10)) { \ + OSL_DELAY(10); \ + countdown -= 10; \ + } \ + } while (0) + + #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + +#ifdef CONFIG_BCM_WLAN_RAMDUMP +extern char bcm_wlan_ver_info[BCM_WLAN_CRASH_REASON_LEN]; +#define bcm_add_crash_reason(dst, fmt, ...) do { \ + int rest = 0; \ + int pos = strnlen(dst, sizeof(dst)); \ + if (pos == 0) \ + pos += snprintf(&dst[0], sizeof(dst), "%s", bcm_wlan_ver_info); \ + rest = sizeof(dst) - pos; \ + if (rest > 1) { \ + snprintf(&dst[pos], rest, (fmt), ##__VA_ARGS__); \ + } \ + } while (0) +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + +#ifndef OSL_SLEEP +#define OSL_SLEEP(ms) OSL_DELAY(ms*1000) +#endif /* OSL_SLEEP */ + +#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ + +unsigned long dhd_os_spin_lock(dhd_pub_t *pub); +void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); +#ifdef PNO_SUPPORT +int dhd_pno_clean(dhd_pub_t *dhd); +#endif /* PNO_SUPPORT */ +/* + * Wake locks are an Android power management concept. They are used by applications and services + * to request CPU resources. + */ +extern int dhd_os_wake_lock(dhd_pub_t *pub); +extern int dhd_os_wake_unlock(dhd_pub_t *pub); +extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); +extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); +extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); +extern int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub); +extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); +extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); + +inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_init(&dhdp->wl_softap_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +} + +inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_lock(&dhdp->wl_softap_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +} + +inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_unlock(&dhdp->wl_softap_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +} + +#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) +#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) +#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) +#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ + dhd_os_wake_lock_rx_timeout_enable(pub, val) +#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ + dhd_os_wake_lock_ctrl_timeout_enable(pub, val) +#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \ + dhd_os_wake_lock_ctrl_timeout_cancel(pub) + +#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub) +#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub) +#define DHD_PACKET_TIMEOUT_MS 500 +#define DHD_EVENT_TIMEOUT_MS 1500 + + +/* interface operations (register, remove) should be atomic, use this lock to prevent race + * condition among wifi on/off and interface operation functions + */ +void dhd_net_if_lock(struct net_device *dev); +void dhd_net_if_unlock(struct net_device *dev); + + +typedef enum dhd_attach_states +{ + DHD_ATTACH_STATE_INIT = 0x0, + DHD_ATTACH_STATE_NET_ALLOC = 0x1, + DHD_ATTACH_STATE_DHD_ALLOC = 0x2, + DHD_ATTACH_STATE_ADD_IF = 0x4, + DHD_ATTACH_STATE_PROT_ATTACH = 0x8, + DHD_ATTACH_STATE_WL_ATTACH = 0x10, + DHD_ATTACH_STATE_THREADS_CREATED = 0x20, + DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, + DHD_ATTACH_STATE_CFG80211 = 0x80, + DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, + DHD_ATTACH_STATE_DONE = 0x200 +} dhd_attach_states_t; + +/* Value -1 means we are unsuccessful in creating the kthread. */ +#define DHD_PID_KT_INVALID -1 +/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ +#define DHD_PID_KT_TL_INVALID -2 + +/* + * Exported from dhd OS modules (dhd_linux/dhd_ndis) + */ + +/* Indication from bus module regarding presence/insertion of dongle. + * Return dhd_pub_t 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 dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); +#if defined(WLP2P) && defined(WL_CFG80211) +/* To allow attach/detach calls corresponding to p2p0 interface */ +extern int dhd_attach_p2p(dhd_pub_t *); +extern int dhd_detach_p2p(dhd_pub_t *); +#endif /* WLP2P && WL_CFG80211 */ +extern int dhd_register_if(dhd_pub_t *dhdp, int idx, bool need_rtnl_lock); + +/* Indication from bus module regarding removal/absence of dongle */ +extern void dhd_detach(dhd_pub_t *dhdp); +extern void dhd_free(dhd_pub_t *dhdp); + +/* Indication from bus module to change flow-control state */ +extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); + +/* Store the status of a connection attempt for later retrieval by an iovar */ +extern void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason); + +extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); + +/* Receive frame for delivery to OS. Callee disposes of rxp. */ +extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); + +/* Return pointer to interface name */ +extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); + +/* Request scheduling of the bus dpc */ +extern void dhd_sched_dpc(dhd_pub_t *dhdp); + +/* Notify tx completion */ +extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); +extern int dhd_dev_get_feature_set(struct net_device *dev); +extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); + +#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */ +#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */ +#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */ +#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */ +#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */ +#define WIFI_FEATURE_GSCAN 0x0020 /* Google-Scan APIs */ +#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness Networking */ +#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */ +#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */ +#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */ +#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */ +#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */ +#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link setup */ +#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off channel */ +#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */ +#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA Concurrency */ +#define WIFI_FEATURE_LINKSTAT 0x10000 /* Support for Linkstats */ +#define WIFI_FEATURE_HAL_EPNO 0x40000 /* WiFi PNO enhanced */ +#define WIFI_FEATURE_RSSI_MONITOR 0x80000 /* RSSI Monitor */ + +#define MAX_FEATURE_SET_CONCURRRENT_GROUPS 3 + +extern int dhd_dev_get_feature_set(struct net_device *dev); +extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); +extern int dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui); +extern int dhd_set_rand_mac_oui(dhd_pub_t *dhd); + +#ifdef GSCAN_SUPPORT +extern int dhd_dev_set_lazy_roam_cfg(struct net_device *dev, + wlc_roam_exp_params_t *roam_param); +extern int dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable); +extern int dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, + wl_bssid_pref_cfg_t *bssid_pref, uint32 flush); +extern int dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, + uint32 len, uint32 flush); +extern int dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *whitelist, + uint32 len, uint32 flush); +#endif /* GSCAN_SUPPORT */ + +#ifdef RSSI_MONITOR_SUPPORT +extern int dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, + int8 max_rssi, int8 min_rssi); + +#define DHD_RSSI_MONITOR_EVT_VERSION 1 +typedef struct { + uint8 version; + int8 cur_rssi; + struct ether_addr BSSID; +} dhd_rssi_monitor_evt_t; +#endif /* RSSI_MONITOR_SUPPORT */ + +/* OS independent layer functions */ +extern int dhd_os_proto_block(dhd_pub_t * pub); +extern int dhd_os_proto_unblock(dhd_pub_t * pub); +extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending); +extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); +extern unsigned int dhd_os_get_ioctl_resp_timeout(void); +extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); + +extern int dhd_os_get_image_block(char * buf, int len, void * image); +extern void * dhd_os_open_image(char * filename); +extern void dhd_os_close_image(void * image); +extern void dhd_os_wd_timer(void *bus, uint wdtick); +extern void dhd_os_sdlock(dhd_pub_t * pub); +extern void dhd_os_sdunlock(dhd_pub_t * pub); +extern void dhd_os_sdlock_txq(dhd_pub_t * pub); +extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); +extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); +extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); +extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); +#ifdef DHDTCPACK_SUPPRESS +extern void dhd_os_tcpacklock(dhd_pub_t *pub); +extern void dhd_os_tcpackunlock(dhd_pub_t *pub); +#endif /* DHDTCPACK_SUPPRESS */ + +extern int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr); +extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff); +#ifdef GET_CUSTOM_MAC_ENABLE +extern int somc_get_mac_address(unsigned char *buf); +#endif /* GET_CUSTOM_MAC_ENABLE */ +extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf); +extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec); +extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); +extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); +extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); +extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); +extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); +extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); +extern bool dhd_os_check_if_up(dhd_pub_t *pub); +extern int dhd_os_check_wakelock(dhd_pub_t *pub); + + +#if defined(KEEP_ALIVE) +extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); +#endif /* KEEP_ALIVE */ + + +#ifdef PKT_FILTER_SUPPORT +#define DHD_UNICAST_FILTER_NUM 0 +#define DHD_BROADCAST_FILTER_NUM 1 +#define DHD_MULTICAST4_FILTER_NUM 2 +#define DHD_MULTICAST6_FILTER_NUM 3 +#define DHD_MDNS_FILTER_NUM 4 +#define DHD_ARP_FILTER_NUM 5 +extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val); +extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); +extern int net_os_enable_packet_filter(struct net_device *dev, int val); +extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); +#endif /* PKT_FILTER_SUPPORT */ + +extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); +extern bool dhd_support_sta_mode(dhd_pub_t *dhd); + +#ifdef DHD_DEBUG +extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); +#endif /* DHD_DEBUG */ + +extern void dhd_os_sdtxlock(dhd_pub_t * pub); +extern void dhd_os_sdtxunlock(dhd_pub_t * pub); + +typedef struct { + uint32 limit; /* Expiration time (usec) */ + uint32 increment; /* Current expiration increment (usec) */ + uint32 elapsed; /* Current elapsed time (usec) */ + uint32 tick; /* O/S tick time (usec) */ +} dhd_timeout_t; + +#if defined(KEEP_ALIVE) +extern int dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, + u16 ip_pkt_len, u8* src_mac_addr, u8* dst_mac_addr, u32 period_msec); +extern int dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id); +#endif /* defined(KEEP_ALIVE) */ + +extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); +extern int dhd_timeout_expired(dhd_timeout_t *tmo); + +extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); +extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); +extern struct net_device * dhd_idx2net(void *pub, int ifidx); +extern int net_os_send_hang_message(struct net_device *dev); +extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, size_t pktlen, + wl_event_msg_t *, void **data_ptr); +extern void wl_event_to_host_order(wl_event_msg_t * evt); +extern int wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu); + +extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); +extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, + int ifindex); +extern void dhd_common_init(osl_t *osh); + +extern int dhd_do_driver_init(struct net_device *net); +extern int dhd_event_ifadd(struct dhd_info *dhd, struct wl_event_data_if *ifevent, + char *name, uint8 *mac); +extern int dhd_event_ifdel(struct dhd_info *dhd, struct wl_event_data_if *ifevent, + char *name, uint8 *mac); +extern struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name, + uint8 *mac, uint8 bssidx, bool need_rtnl_lock); +extern int dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock); +extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); +extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); +extern void dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx); +extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); + +/* Send packet to dongle via data channel */ +extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); + +/* send up locally generated event */ +extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); +/* Send event to host */ +extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); +#ifdef LOG_INTO_TCPDUMP +extern void dhd_sendup_log(dhd_pub_t *dhdp, void *data, int len); +#endif /* LOG_INTO_TCPDUMP */ +extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); +extern uint dhd_bus_status(dhd_pub_t *dhdp); +extern int dhd_bus_start(dhd_pub_t *dhdp); +extern int dhd_bus_suspend(dhd_pub_t *dhdpub); +extern int dhd_bus_resume(dhd_pub_t *dhdpub, int stage); +extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); +extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); +extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); +extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); +extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); +extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); + +#if defined(KEEP_ALIVE) +extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); +#endif /* KEEP_ALIVE */ + +extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); +int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, + char *res_buf, uint res_len, int set); +extern int dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, + uint cmd_len, char **resptr, uint resp_len); +typedef enum cust_gpio_modes { + WLAN_RESET_ON, + WLAN_RESET_OFF, + WLAN_POWER_ON, + WLAN_POWER_OFF +} cust_gpio_modes_t; + +extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); +extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); +/* + * Insmod parameters for debug/test + */ + +/* Watchdog timer interval */ +extern uint dhd_watchdog_ms; + +#if defined(DHD_DEBUG) +/* Console output poll interval */ +extern uint dhd_console_ms; +extern uint wl_msg_level; +#endif /* defined(DHD_DEBUG) */ + +extern uint dhd_slpauto; + +/* Use interrupts */ +extern uint dhd_intr; + +/* Use polling */ +extern uint dhd_poll; + +/* ARP offload agent mode */ +extern uint dhd_arp_mode; + +/* ARP offload enable */ +extern uint dhd_arp_enable; + +/* Pkt filte enable control */ +extern uint dhd_pkt_filter_enable; + +/* Pkt filter init setup */ +extern uint dhd_pkt_filter_init; + +/* Pkt filter mode control */ +extern uint dhd_master_mode; + +/* Roaming mode control */ +extern uint dhd_roam_disable; + +/* Roaming mode control */ +extern uint dhd_radio_up; + +/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ +extern int dhd_idletime; +#ifdef DHD_USE_IDLECOUNT +#define DHD_IDLETIME_TICKS 5 +#else +#define DHD_IDLETIME_TICKS 1 +#endif /* DHD_USE_IDLECOUNT */ + +/* SDIO Drive Strength */ +extern uint dhd_sdiod_drive_strength; + +/* Override to force tx queueing all the time */ +extern uint dhd_force_tx_queueing; +/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ +#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */ +#ifndef CUSTOM_KEEP_ALIVE_SETTING +#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE +#endif /* DEFAULT_KEEP_ALIVE_VALUE */ + +#define NULL_PKT_STR "null_pkt" + +/* hooks for custom glom setting option via Makefile */ +#define DEFAULT_GLOM_VALUE -1 +#ifndef CUSTOM_GLOM_SETTING +#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE +#endif +#define WL_AUTO_ROAM_TRIGGER -75 +/* hooks for custom Roaming Trigger setting via Makefile */ +#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ +#define DEFAULT_ROAM_TRIGGER_SETTING -1 +#ifndef CUSTOM_ROAM_TRIGGER_SETTING +#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE +#endif + +/* hooks for custom Roaming Romaing setting via Makefile */ +#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ +#define DEFAULT_ROAM_DELTA_SETTING -1 +#ifndef CUSTOM_ROAM_DELTA_SETTING +#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE +#endif + +/* hooks for custom PNO Event wake lock to guarantee enough time + for the Platform to detect Event before system suspended +*/ +#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */ +#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME +#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME +#endif +/* hooks for custom dhd_dpc_prio setting option via Makefile */ +#define DEFAULT_DHP_DPC_PRIO 1 +#ifndef CUSTOM_DPC_PRIO_SETTING +#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO +#endif + +#ifndef CUSTOM_LISTEN_INTERVAL +#define CUSTOM_LISTEN_INTERVAL LISTEN_INTERVAL +#endif /* CUSTOM_LISTEN_INTERVAL */ + +#define DEFAULT_SUSPEND_BCN_LI_DTIM 3 +#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM +#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM +#endif + +#ifndef CUSTOM_RXF_PRIO_SETTING +#define CUSTOM_RXF_PRIO_SETTING MAX((CUSTOM_DPC_PRIO_SETTING - 1), 1) +#endif + +#define DEFAULT_WIFI_TURNOFF_DELAY 0 +#define WIFI_TURNOFF_DELAY DEFAULT_WIFI_TURNOFF_DELAY + +#define DEFAULT_WIFI_TURNON_DELAY 200 +#ifndef WIFI_TURNON_DELAY +#define WIFI_TURNON_DELAY DEFAULT_WIFI_TURNON_DELAY +#endif /* WIFI_TURNON_DELAY */ + +#ifdef WLTDLS +#ifndef CUSTOM_TDLS_IDLE_MODE_SETTING +#define CUSTOM_TDLS_IDLE_MODE_SETTING 60000 /* 60sec to tear down TDLS of not active */ +#endif +#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_HIGH +#define CUSTOM_TDLS_RSSI_THRESHOLD_HIGH -70 /* rssi threshold for establishing TDLS link */ +#endif +#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_LOW +#define CUSTOM_TDLS_RSSI_THRESHOLD_LOW -80 /* rssi threshold for tearing down TDLS link */ +#endif +#endif /* WLTDLS */ + +#ifdef DHD_DEBUG +extern int dhd_start_join_timer(dhd_pub_t *pub); +extern int dhd_del_join_timer(dhd_pub_t *pub); +extern int dhd_set_join_timeout(dhd_pub_t *pub, uint32 timeout); +extern uint32 dhd_get_join_timeout(dhd_pub_t *pub); +extern int dhd_add_scan_timer(dhd_pub_t *dhd_pub); +extern int dhd_del_scan_timer(dhd_pub_t *dhd_pub); +extern int dhd_set_scan_timeout(dhd_pub_t *pub, uint32 timeout); +extern uint32 dhd_get_scan_timeout(dhd_pub_t *pub); +#endif /* DHD_DEBUG */ + +#ifdef SET_RETRY_LIMIT +#define DEFAULT_SHORT_RETRY_LIMIT 13 +#ifndef CUSTOM_SRL_SETTING +#define CUSTOM_SRL_SETTING DEFAULT_SHORT_RETRY_LIMIT +#endif + +#define DEFAULT_LONG_RETRY_LIMIT 13 +#ifndef CUSTOM_LRL_SETTING +#define CUSTOM_LRL_SETTING DEFAULT_LONG_RETRY_LIMIT +#endif +#endif /* SET_RETRY_LIMIT */ + +#define MAX_DTIM_SKIP_BEACON_INTERVAL 100 /* max allowed associated AP beacon for DTIM skip */ +#ifndef MAX_DTIM_ALLOWED_INTERVAL +#define MAX_DTIM_ALLOWED_INTERVAL 600 /* max allowed total beacon interval for DTIM skip */ +#endif +#define NO_DTIM_SKIP 1 +#ifdef SDTEST +/* Echo packet generator (SDIO), pkts/s */ +extern uint dhd_pktgen; + +/* Echo packet len (0 => sawtooth, max 1800) */ +extern uint dhd_pktgen_len; +#define MAX_PKTGEN_LEN 1800 +#endif + + +/* optionally set by a module_param_string() */ +#define MOD_PARAM_PATHLEN 2048 +#define MOD_PARAM_INFOLEN 512 + +#ifdef SOFTAP +extern char fw_path2[MOD_PARAM_PATHLEN]; +#endif + +/* Flag to indicate if we should download firmware on driver load */ +extern uint dhd_download_fw_on_driverload; + + +/* For supporting multiple interfaces */ +#define DHD_MAX_IFS 16 +#define DHD_DEL_IF -0xe +#define DHD_BAD_IF -0xf + +extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); +extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); + +#define IFLOCK_INIT(lock) *lock = 0 +#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ + NdisStallExecution(1); +#define IFUNLOCK(lock) InterlockedExchange((lock), 0) +#define IFLOCK_FREE(lock) +#define FW_SUPPORTED(dhd, capa) ((strstr(dhd->fw_capabilities, #capa) != NULL)) +#ifdef ARP_OFFLOAD_SUPPORT +#define MAX_IPV4_ENTRIES 8 +void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); +void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); + +/* dhd_commn arp offload wrapers */ +void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx); +void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); +int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); +void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef WLTDLS +int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac); +#endif +/* Neighbor Discovery Offload Support */ +int dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable); +int dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipaddr, int idx); +int dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx); +/* ioctl processing for nl80211 */ +int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, struct dhd_ioctl *ioc, void *data_buf); + +void dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path); +void dhd_set_bus_state(void *bus, uint32 state); + +/* Remove proper pkts(either one no-frag pkt or whole fragmented pkts) */ +typedef int (*f_droppkt_t)(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ); +extern bool dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn); + +#ifdef PROP_TXSTATUS +int dhd_os_wlfc_block(dhd_pub_t *pub); +int dhd_os_wlfc_unblock(dhd_pub_t *pub); +extern const uint8 prio2fifo[]; +#endif /* PROP_TXSTATUS */ + +uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail); +void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size); + +#if defined(CONFIG_DHD_USE_STATIC_BUF) +#define DHD_OS_PREALLOC(dhdpub, section, size) dhd_os_prealloc(dhdpub, section, size, FALSE) +#define DHD_OS_PREFREE(dhdpub, addr, size) dhd_os_prefree(dhdpub, addr, size) +#else +#define DHD_OS_PREALLOC(dhdpub, section, size) MALLOC(dhdpub->osh, size) +#define DHD_OS_PREFREE(dhdpub, addr, size) MFREE(dhdpub->osh, addr, size) +#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ + + +void dhd_save_fwdump(dhd_pub_t *dhd_pub, void * buffer, uint32 length); + +#endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c new file mode 100644 index 000000000000..62b78e61d309 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c @@ -0,0 +1,328 @@ +/* + * BT-AMP support routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_bta.c 701450 2017-05-25 02:10:23Z $ + */ +#error "WLBTAMP is not defined" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#ifdef SEND_HCI_CMD_VIA_IOCTL +#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE + +/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */ +int +dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) +{ + amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; + int ret; + + if (cmd_len < HCI_CMD_PREAMBLE_SIZE) + return BCME_BADLEN; + + if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) + return BCME_BADLEN; + + ret = dhd_iovar(pub, 0, "HCI_cmd", (char *)cmd, + (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, NULL, 0, TRUE); + + + return ret; +} +#else /* !SEND_HCI_CMD_VIA_IOCTL */ + +static void +dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh) +{ + int prec; + struct pktq *q; + uint count = 0; + + q = dhd_bus_txq(pub->bus); + if (q == NULL) + return; + + DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh)); + + dhd_os_sdlock_txq(pub); + + /* Walk through the txq and toss all HCI ACL data packets */ + PKTQ_PREC_ITER(q, prec) { + void *head_pkt = NULL; + + while (pktq_ppeek(q, prec) != head_pkt) { + void *pkt = pktq_pdeq(q, prec); + int ifidx; + + dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL); + + if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) { + struct ether_header *eh = + (struct ether_header *)PKTDATA(pub->osh, pkt); + + if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { + struct dot11_llc_snap_header *lsh = + (struct dot11_llc_snap_header *)&eh[1]; + + if (bcmp(lsh, BT_SIG_SNAP_MPROT, + DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && + ntoh16(lsh->type) == BTA_PROT_L2CAP) { + amp_hci_ACL_data_t *ACL_data = + (amp_hci_ACL_data_t *)&lsh[1]; + uint16 handle = ltoh16(ACL_data->handle); + + if (HCI_ACL_DATA_HANDLE(handle) == llh) { + PKTFREE(pub->osh, pkt, TRUE); + count ++; + continue; + } + } + } + } + + dhd_prot_hdrpush(pub, ifidx, pkt); + + if (head_pkt == NULL) + head_pkt = pkt; + pktq_penq(q, prec, pkt); + } + } + + dhd_os_sdunlock_txq(pub); + + DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh)); +} + +/* Handle HCI cmd locally. + * Return 0: continue to send the cmd across SDIO + * < 0: stop, fail + * > 0: stop, succuess + */ +static int +_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd) +{ + int status = 0; + + switch (ltoh16_ua((uint8 *)&cmd->opcode)) { + case HCI_Enhanced_Flush: { + eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms; + dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh)); + break; + } + default: + break; + } + + return status; +} + +/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */ +int +dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) +{ + amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; + struct ether_header *eh; + struct dot11_llc_snap_header *lsh; + osl_t *osh = pub->osh; + uint len; + void *p; + int status; + + if (cmd_len < HCI_CMD_PREAMBLE_SIZE) { + DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len)); + return BCME_BADLEN; + } + + if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) { + DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n", + len, cmd_len)); + /* return BCME_BADLEN; */ + } + + p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); + if (p == NULL) { + DHD_ERROR(("dhd_bta_docmd: out of memory\n")); + return BCME_NOMEM; + } + + + /* intercept and handle the HCI cmd locally */ + if ((status = _dhd_bta_docmd(pub, cmd)) > 0) + return 0; + else if (status < 0) + return status; + + /* copy in HCI cmd */ + PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); + bcopy(cmd, PKTDATA(osh, p), len); + + /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ + PKTPUSH(osh, p, RFC1042_HDR_LEN); + eh = (struct ether_header *)PKTDATA(osh, p); + bzero(eh->ether_dhost, ETHER_ADDR_LEN); + ETHER_SET_LOCALADDR(eh->ether_dhost); + bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); + eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); + lsh = (struct dot11_llc_snap_header *)&eh[1]; + bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); + lsh->type = 0; + + return dhd_sendpkt(pub, 0, p); +} +#endif /* !SEND_HCI_CMD_VIA_IOCTL */ + +/* Send HCI ACL data to dongle via data channel */ +int +dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len) +{ + amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf; + struct ether_header *eh; + struct dot11_llc_snap_header *lsh; + osl_t *osh = pub->osh; + uint len; + void *p; + + if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) { + DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len)); + return BCME_BADLEN; + } + + if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) { + DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n", + len, data_len)); + /* return BCME_BADLEN; */ + } + + p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); + if (p == NULL) { + DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n")); + return BCME_NOMEM; + } + + + /* copy in HCI ACL data header and HCI ACL data */ + PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); + bcopy(data, PKTDATA(osh, p), len); + + /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ + PKTPUSH(osh, p, RFC1042_HDR_LEN); + eh = (struct ether_header *)PKTDATA(osh, p); + bzero(eh->ether_dhost, ETHER_ADDR_LEN); + bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); + eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); + lsh = (struct dot11_llc_snap_header *)&eh[1]; + bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); + lsh->type = HTON16(BTA_PROT_L2CAP); + + return dhd_sendpkt(pub, 0, p); +} + +/* txcomplete callback */ +void +dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success) +{ + uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp); + amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN); + uint16 handle = ltoh16(ACL_data->handle); + uint16 llh = HCI_ACL_DATA_HANDLE(handle); + + wl_event_msg_t event; + uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)]; + amp_hci_event_t *evt; + num_completed_data_blocks_evt_parms_t *parms; + + uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t); + + /* update the event struct */ + memset(&event, 0, sizeof(event)); + event.version = hton16(BCM_EVENT_MSG_VERSION); + event.event_type = hton32(WLC_E_BTA_HCI_EVENT); + event.status = 0; + event.reason = 0; + event.auth_type = 0; + event.datalen = hton32(len); + event.flags = 0; + + /* generate Number of Completed Blocks event */ + evt = (amp_hci_event_t *)data; + evt->ecode = HCI_Number_of_Completed_Data_Blocks; + evt->plen = sizeof(num_completed_data_blocks_evt_parms_t); + + parms = (num_completed_data_blocks_evt_parms_t *)evt->parms; + htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks); + parms->num_handles = 1; + htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle); + parms->completed[0].pkts = 1; + parms->completed[0].blocks = 1; + + dhd_sendup_event_common(dhdp, &event, data); +} + +/* event callback */ +void +dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) +{ + amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; + + ASSERT(dhdp); + ASSERT(evt); + + switch (evt->ecode) { + case HCI_Command_Complete: { + cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; + switch (ltoh16_ua((uint8 *)&parms->opcode)) { + case HCI_Read_Data_Block_Size: { + read_data_block_size_evt_parms_t *parms2 = + (read_data_block_size_evt_parms_t *)parms->parms; + dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num); + break; + } + } + break; + } + + case HCI_Flush_Occurred: { + flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms; + dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle)); + break; + } + default: + break; + } +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h new file mode 100644 index 000000000000..0c5e9de534e9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h @@ -0,0 +1,39 @@ +/* + * BT-AMP support routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_bta.h 291086 2011-10-21 01:17:24Z $ + */ +#ifndef __dhd_bta_h__ +#define __dhd_bta_h__ + +struct dhd_pub; + +extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len); + +extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len); + +extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len); +extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success); + + +#endif /* __dhd_bta_h__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h new file mode 100644 index 000000000000..14515e12b1e7 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h @@ -0,0 +1,158 @@ +/* + * Header file describing the internal (inter-module) DHD interfaces. + * + * Provides type definitions and function prototypes used to link the + * DHD OS, bus, and protocol modules. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_bus.h 457888 2014-02-25 03:34:39Z $ + */ + +#ifndef _dhd_bus_h_ +#define _dhd_bus_h_ + +/* + * Exported from dhd bus module (dhd_usb, dhd_sdio) + */ + +/* Indicate (dis)interest in finding dongles. */ +extern int dhd_bus_register(void); +extern void dhd_bus_unregister(void); + +/* Download firmware image and nvram image */ +extern int dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, char *fw_path, char *nv_path); + +/* Stop bus module: clear pending frames, disable data flow */ +extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); + +/* Initialize bus module: prepare for communication w/dongle */ +extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); + +/* Get the Bus Idle Time */ +extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); + +/* Set the Bus Idle Time */ +extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); + +/* Send a data frame to the dongle. Callee disposes of txp. */ +#ifdef BCMPCIE +extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx); +#else +extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); +#endif + + +/* Send/receive a control message to/from the dongle. + * Expects caller to enforce a single outstanding transaction. + */ +extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); +extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); + +/* Watchdog timer function */ +extern bool dhd_bus_watchdog(dhd_pub_t *dhd); + +extern int dhd_bus_oob_intr_register(dhd_pub_t *dhdp); +extern void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp); +extern void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable); +extern void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub); +extern void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub); +extern bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub); + +#if defined(DHD_DEBUG) +/* Device console input function */ +extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); +#endif /* defined(DHD_DEBUG) */ + +/* Deferred processing for the bus, return TRUE requests reschedule */ +extern bool dhd_bus_dpc(struct dhd_bus *bus); +extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); + + +/* Check for and handle local prot-specific iovar commands */ +extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set); + +/* Add bus dump output to a buffer */ +extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); + +/* Clear any bus counters */ +extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); + +/* return the dongle chipid */ +extern uint dhd_bus_chip(struct dhd_bus *bus); + +/* return the dongle chiprev */ +extern uint dhd_bus_chiprev(struct dhd_bus *bus); + +/* Set user-specified nvram parameters. */ +extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); + +extern void *dhd_bus_pub(struct dhd_bus *bus); +extern void *dhd_bus_txq(struct dhd_bus *bus); +extern void *dhd_bus_sih(struct dhd_bus *bus); +extern uint dhd_bus_hdrlen(struct dhd_bus *bus); +extern void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val); + +#define DHD_SET_BUS_STATE_DOWN(_bus) do { \ + (_bus)->dhd->busstate = DHD_BUS_DOWN; \ +} while (0) + +/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ +extern int dhd_bus_reg_sdio_notify(void* semaphore); +extern void dhd_bus_unreg_sdio_notify(void); +extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable); +extern int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, + uint32 *slot_num); + +#ifdef BCMPCIE +enum { + DNGL_TO_HOST_BUF_IOCT, + DNGL_TO_HOST_BUF_ADDR, + HOST_TO_DNGL_BUF_ADDR, + HOST_TO_DNGL_WPTR, + HOST_TO_DNGL_RPTR, + DNGL_TO_HOST_WPTR, + DNGL_TO_HOST_RPTR, + TOTAL_LFRAG_PACKET_CNT, + HOST_TO_DNGL_CTRLBUF_ADDR, + DNGL_TO_HOST_CTRLBUF_ADDR, + HTOD_CTRL_RPTR, + HTOD_CTRL_WPTR, + DTOH_CTRL_RPTR, + DTOH_CTRL_WPTR, + HTOD_MB_DATA, + DTOH_MB_DATA, + MAX_HOST_RXBUFS +}; +typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32); +extern void dhd_bus_cmn_writeshared(struct dhd_bus *bus, void * data, uint32 len, uint8 type); +extern void dhd_bus_ringbell(struct dhd_bus *bus, uint32 value); +extern void dhd_bus_cmn_readshared(struct dhd_bus *bus, void* data, uint8 type); +extern uint32 dhd_bus_get_sharedflags(struct dhd_bus *bus); +extern void dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count); +extern void dhd_bus_start_queue(struct dhd_bus *bus); +extern void dhd_bus_stop_queue(struct dhd_bus *bus); +extern void dhd_bus_update_retlen(struct dhd_bus *bus, uint32 retlen, uint32 cmd_id, uint32 status, + uint32 inline_data); +extern dhd_mb_ring_t dhd_bus_get_mbintr_fn(struct dhd_bus *bus); +#endif /* BCMPCIE */ +#endif /* _dhd_bus_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c new file mode 100644 index 000000000000..00d4821d7e5e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c @@ -0,0 +1,795 @@ +/* + * DHD Protocol Module for CDC and BDC. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_cdc.c 701450 2017-05-25 02:10:23Z $ + * + * BDC is like CDC, except it includes a header for data packets to convey + * packet priority over the bus, and flags (e.g. to indicate checksum status + * for dongle offload.) + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + + +#ifdef PROP_TXSTATUS +#include +#include +#endif + + +#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ +#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE + * defined in dhd_sdio.c (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 + */ + +typedef struct dhd_prot { + uint16 reqid; + uint8 pending; + uint32 lastcmd; + uint8 bus_header[BUS_HEADER_LEN]; + cdc_ioctl_t msg; + unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; +} dhd_prot_t; + + +static int +dhdcdc_msg(dhd_pub_t *dhd) +{ + int err = 0; + dhd_prot_t *prot = dhd->prot; + int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + DHD_OS_WAKE_LOCK(dhd); + + /* 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 */ + err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); + + DHD_OS_WAKE_UNLOCK(dhd); + return err; +} + +static int +dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) +{ + int ret; + int cdc_len = len + sizeof(cdc_ioctl_t); + dhd_prot_t *prot = dhd->prot; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + +#if defined(CUSTOMER_HW5) + DHD_OS_WAKE_LOCK(dhd); +#endif + + do { + ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); + if (ret < 0) + break; + } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); + +#if defined(CUSTOMER_HW5) + DHD_OS_WAKE_UNLOCK(dhd); +#endif + + return ret; +} + +static int +dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) +{ + dhd_prot_t *prot = dhd->prot; + cdc_ioctl_t *msg = &prot->msg; + int ret = 0, retries = 0; + uint32 id, flags = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); + + + /* Respond "bcmerror" and "bcmerrorstr" with local cache */ + if (cmd == WLC_GET_VAR && buf) + { + if (!strcmp((char *)buf, "bcmerrorstr")) + { + strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN); + goto done; + } + else if (!strcmp((char *)buf, "bcmerror")) + { + *(int *)buf = dhd->dongle_error; + goto done; + } + } + + memset(msg, 0, sizeof(cdc_ioctl_t)); + + msg->cmd = htol32(cmd); + msg->len = htol32(len); + msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); + CDC_SET_IF_IDX(msg, ifidx); + /* add additional action bits */ + action &= WL_IOCTL_ACTION_MASK; + msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); + msg->flags = htol32(msg->flags); + + if (buf) + memcpy(prot->buf, buf, len); + + if ((ret = dhdcdc_msg(dhd)) < 0) { + if (!dhd->hang_was_sent) + DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret)); + goto done; + } + +retry: + /* wait for interrupt and get first fragment */ + if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) + goto done; + + flags = ltoh32(msg->flags); + id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; + + if ((id < prot->reqid) && (++retries < RETRIES)) + goto retry; + if (id != prot->reqid) { + DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", + dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); + ret = -EINVAL; + goto done; + } + + /* Copy info buffer */ + if (buf) + { + if (ret < (int)len) + len = ret; + memcpy(buf, (void*) prot->buf, len); + } + + /* Check the ERROR flag */ + if (flags & CDCF_IOC_ERROR) + { + ret = ltoh32(msg->status); + /* Cache error from dongle */ + dhd->dongle_error = ret; + } + +done: + return ret; +} + + +static int +dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) +{ + dhd_prot_t *prot = dhd->prot; + cdc_ioctl_t *msg = &prot->msg; + int ret = 0; + uint32 flags, id; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); + + if (dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + return -EIO; + } + + /* don't talk to the dongle if fw is about to be reloaded */ + if (dhd->hang_was_sent) { + DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", + __FUNCTION__)); + return -EIO; + } + + memset(msg, 0, sizeof(cdc_ioctl_t)); + + msg->cmd = htol32(cmd); + msg->len = htol32(len); + msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); + CDC_SET_IF_IDX(msg, ifidx); + /* add additional action bits */ + action &= WL_IOCTL_ACTION_MASK; + msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; + msg->flags = htol32(msg->flags); + + if (buf) + memcpy(prot->buf, buf, len); + + if ((ret = dhdcdc_msg(dhd)) < 0) { + DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret)); + goto done; + } + + if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) + goto done; + + flags = ltoh32(msg->flags); + id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; + + if (id != prot->reqid) { + DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", + dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); + ret = -EINVAL; + goto done; + } + + /* Check the ERROR flag */ + if (flags & CDCF_IOC_ERROR) + { + ret = ltoh32(msg->status); + /* Cache error from dongle */ + dhd->dongle_error = ret; + } + +done: + return ret; +} + + +int +dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) +{ + dhd_prot_t *prot = dhd->prot; + int ret = -1; + uint8 action; + + if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + goto done; + } + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(len <= WLC_IOCTL_MAXLEN); + + if (len > WLC_IOCTL_MAXLEN) + goto done; + + if (prot->pending == TRUE) { + DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", + ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, + (unsigned long)prot->lastcmd)); + if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { + DHD_TRACE(("iovar cmd=%s\n", (char*)buf)); + } + goto done; + } + + prot->pending = TRUE; + prot->lastcmd = ioc->cmd; + action = ioc->set; + if (action & WL_IOCTL_ACTION_SET) + ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); + else { + ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); + if (ret > 0) + ioc->used = ret - sizeof(cdc_ioctl_t); + } + + /* Too many programs assume ioctl() returns 0 on success */ + if (ret >= 0) + ret = 0; + else { + cdc_ioctl_t *msg = &prot->msg; + ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ + } + + /* Intercept the wme_dp ioctl here */ + if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { + int slen, val = 0; + + slen = strlen("wme_dp") + 1; + if (len >= (int)(slen + sizeof(int))) + bcopy(((char *)buf + slen), &val, sizeof(int)); + dhd->wme_dp = (uint8) ltoh32(val); + } + + prot->pending = FALSE; + +done: + + return ret; +} + +int +dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + return BCME_UNSUPPORTED; +} + +void +dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); +#ifdef PROP_TXSTATUS + dhd_wlfc_dump(dhdp, strbuf); +#endif +} + +/* The FreeBSD PKTPUSH could change the packet buf pinter + so we need to make it changable +*/ +#define PKTBUF pktbuf +void +dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) +{ +#ifdef BDC + struct bdc_header *h; +#endif /* BDC */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + +#ifdef BDC + /* Push BDC header used to convey priority for buses that don't */ + + PKTPUSH(dhd->osh, PKTBUF, BDC_HEADER_LEN); + + h = (struct bdc_header *)PKTDATA(dhd->osh, PKTBUF); + + h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); + if (PKTSUMNEEDED(PKTBUF)) + h->flags |= BDC_FLAG_SUM_NEEDED; + + + h->priority = (PKTPRIO(PKTBUF) & BDC_PRIORITY_MASK); + h->flags2 = 0; + h->dataOffset = 0; +#endif /* BDC */ + BDC_SET_IF_IDX(h, ifidx); +} +#undef PKTBUF /* Only defined in the above routine */ + +int +dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, + uint *reorder_info_len) +{ +#ifdef BDC + struct bdc_header *h; +#endif + uint8 data_offset = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + +#ifdef BDC + if (reorder_info_len) + *reorder_info_len = 0; + /* Pop BDC header used to convey priority for buses that don't */ + + if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { + DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN)); + return BCME_ERROR; + } + + h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); + + if (!ifidx) { + /* for tx packet, skip the analysis */ + data_offset = h->dataOffset; + PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); + goto exit; + } + + if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { + DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", + __FUNCTION__, *ifidx)); + return BCME_ERROR; + } + + if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { + DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", + dhd_ifname(dhd, *ifidx), h->flags)); + if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) + h->dataOffset = 0; + else + return BCME_ERROR; + } + + if (h->flags & BDC_FLAG_SUM_GOOD) { + DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n", + dhd_ifname(dhd, *ifidx), h->flags)); + PKTSETSUMGOOD(pktbuf, TRUE); + } + + PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); + data_offset = h->dataOffset; + PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); +#endif /* BDC */ + + +#ifdef PROP_TXSTATUS + if (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf))) { + /* + - parse txstatus only for packets that came from the firmware + */ + dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), + reorder_buf_info, reorder_info_len); + + } +#endif /* PROP_TXSTATUS */ + +exit: + PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); + return 0; +} + + +int +dhd_prot_attach(dhd_pub_t *dhd) +{ + dhd_prot_t *cdc; + + if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } + memset(cdc, 0, sizeof(dhd_prot_t)); + + /* ensure that the msg buf directly follows the cdc msg struct */ + if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) { + DHD_ERROR(("dhd_prot_t is not correctly defined\n")); + goto fail; + } + + dhd->prot = cdc; +#ifdef BDC + dhd->hdrlen += BDC_HEADER_LEN; +#endif + dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN; + return 0; + +fail: + if (cdc != NULL) + DHD_OS_PREFREE(dhd, cdc, sizeof(dhd_prot_t)); + return BCME_NOMEM; +} + +/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ +void +dhd_prot_detach(dhd_pub_t *dhd) +{ +#ifdef PROP_TXSTATUS + dhd_wlfc_deinit(dhd); +#endif + DHD_OS_PREFREE(dhd, dhd->prot, sizeof(dhd_prot_t)); + dhd->prot = NULL; +} + +void +dhd_prot_dstats(dhd_pub_t *dhd) +{ +/* No stats from dongle added yet, copy bus stats */ + dhd->dstats.tx_packets = dhd->tx_packets; + dhd->dstats.tx_errors = dhd->tx_errors; + dhd->dstats.rx_packets = dhd->rx_packets; + dhd->dstats.rx_errors = dhd->rx_errors; + dhd->dstats.rx_dropped = dhd->rx_dropped; + dhd->dstats.multicast = dhd->rx_multicast; + return; +} + +int +dhd_prot_init(dhd_pub_t *dhd) +{ + int ret = 0; + wlc_rev_info_t revinfo; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + + /* Get the device rev info */ + memset(&revinfo, 0, sizeof(revinfo)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); + if (ret < 0) + goto done; + + + ret = dhd_preinit_ioctls(dhd); + + /* Always assumes wl for now */ + dhd->iswl = TRUE; + +done: + return ret; +} + +void +dhd_prot_stop(dhd_pub_t *dhd) +{ +/* Nothing to do for CDC */ +} + + +static void +dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, + uint32 *pkt_count, void **pplast, uint8 start, uint8 end) +{ + void *plast = NULL, *p; + uint32 pkt_cnt = 0; + + if (ptr->pend_pkts == 0) { + DHD_REORDER(("%s: no packets in reorder queue \n", __FUNCTION__)); + *pplast = NULL; + *pkt_count = 0; + *pkt = NULL; + return; + } + do { + p = (void *)(ptr->p[start]); + ptr->p[start] = NULL; + + if (p != NULL) { + if (plast == NULL) + *pkt = p; + else + PKTSETNEXT(osh, plast, p); + + plast = p; + pkt_cnt++; + } + start++; + if (start > ptr->max_idx) + start = 0; + } while (start != end); + *pplast = plast; + *pkt_count = pkt_cnt; + ptr->pend_pkts -= (uint8)pkt_cnt; +} + +int +dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, + void **pkt, uint32 *pkt_count) +{ + uint8 flow_id, max_idx, cur_idx, exp_idx; + struct reorder_info *ptr; + uint8 flags; + void *cur_pkt, *plast = NULL; + uint32 cnt = 0; + + if (pkt == NULL) { + if (pkt_count != NULL) + *pkt_count = 0; + return 0; + } + + flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; + flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; + + DHD_REORDER(("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags, + reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET], + reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET], + reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET])); + + /* validate flags and flow id */ + if (flags == 0xFF) { + DHD_ERROR(("%s: invalid flags...so ignore this packet\n", __FUNCTION__)); + *pkt_count = 1; + return 0; + } + + cur_pkt = *pkt; + *pkt = NULL; + + ptr = dhd->reorder_bufs[flow_id]; + if (flags & WLHOST_REORDERDATA_DEL_FLOW) { + uint32 buf_size = sizeof(struct reorder_info); + + DHD_REORDER(("%s: Flags indicating to delete a flow id %d\n", + __FUNCTION__, flow_id)); + + if (ptr == NULL) { + DHD_REORDER(("%s: received flags to cleanup, but no flow (%d) yet\n", + __FUNCTION__, flow_id)); + *pkt_count = 1; + *pkt = cur_pkt; + return 0; + } + + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, + ptr->exp_idx, ptr->exp_idx); + /* set it to the last packet */ + if (plast) { + PKTSETNEXT(dhd->osh, plast, cur_pkt); + cnt++; + } + else { + if (cnt != 0) { + DHD_ERROR(("%s: del flow: something fishy, pending packets %d\n", + __FUNCTION__, cnt)); + } + *pkt = cur_pkt; + cnt = 1; + } + buf_size += ((ptr->max_idx + 1) * sizeof(void *)); + MFREE(dhd->osh, ptr, buf_size); + dhd->reorder_bufs[flow_id] = NULL; + *pkt_count = cnt; + return 0; + } + /* all the other cases depend on the existance of the reorder struct for that flow id */ + if (ptr == NULL) { + uint32 buf_size_alloc = sizeof(reorder_info_t); + max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; + + buf_size_alloc += ((max_idx + 1) * sizeof(void*)); + /* allocate space to hold the buffers, index etc */ + + DHD_REORDER(("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n", + __FUNCTION__, buf_size_alloc, flow_id, max_idx)); + ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc); + if (ptr == NULL) { + DHD_ERROR(("%s: Malloc failed to alloc buffer\n", __FUNCTION__)); + *pkt_count = 1; + return 0; + } + bzero(ptr, buf_size_alloc); + dhd->reorder_bufs[flow_id] = ptr; + ptr->p = (void *)(ptr+1); + ptr->max_idx = max_idx; + } + if (flags & WLHOST_REORDERDATA_NEW_HOLE) { + DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__)); + if (ptr->pend_pkts) { + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, + ptr->exp_idx, ptr->exp_idx); + ptr->pend_pkts = 0; + } + ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; + ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; + ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; + ptr->p[ptr->cur_idx] = cur_pkt; + ptr->pend_pkts++; + *pkt_count = cnt; + } + else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) { + cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; + exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; + + + if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) { + /* still in the current hole */ + /* enqueue the current on the buffer chain */ + if (ptr->p[cur_idx] != NULL) { + DHD_REORDER(("%s: HOLE: ERROR buffer pending..free it\n", + __FUNCTION__)); + PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); + ptr->p[cur_idx] = NULL; + } + ptr->p[cur_idx] = cur_pkt; + ptr->pend_pkts++; + ptr->cur_idx = cur_idx; + DHD_REORDER(("%s: fill up a hole..pending packets is %d\n", + __FUNCTION__, ptr->pend_pkts)); + *pkt_count = 0; + *pkt = NULL; + } + else if (ptr->exp_idx == cur_idx) { + /* got the right one ..flush from cur to exp and update exp */ + DHD_REORDER(("%s: got the right one now, cur_idx is %d\n", + __FUNCTION__, cur_idx)); + if (ptr->p[cur_idx] != NULL) { + DHD_REORDER(("%s: Error buffer pending..free it\n", + __FUNCTION__)); + PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); + ptr->p[cur_idx] = NULL; + } + ptr->p[cur_idx] = cur_pkt; + ptr->pend_pkts++; + + ptr->cur_idx = cur_idx; + ptr->exp_idx = exp_idx; + + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, + cur_idx, exp_idx); + *pkt_count = cnt; + DHD_REORDER(("%s: freeing up buffers %d, still pending %d\n", + __FUNCTION__, cnt, ptr->pend_pkts)); + } + else { + uint8 end_idx; + bool flush_current = FALSE; + /* both cur and exp are moved now .. */ + DHD_REORDER(("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n", + __FUNCTION__, flow_id, ptr->cur_idx, cur_idx, + ptr->exp_idx, exp_idx)); + if (flags & WLHOST_REORDERDATA_FLUSH_ALL) + end_idx = ptr->exp_idx; + else + end_idx = exp_idx; + + /* flush pkts first */ + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, + ptr->exp_idx, end_idx); + + if (cur_idx == ptr->max_idx) { + if (exp_idx == 0) + flush_current = TRUE; + } else { + if (exp_idx == cur_idx + 1) + flush_current = TRUE; + } + if (flush_current) { + if (plast) + PKTSETNEXT(dhd->osh, plast, cur_pkt); + else + *pkt = cur_pkt; + cnt++; + } + else { + ptr->p[cur_idx] = cur_pkt; + ptr->pend_pkts++; + } + ptr->exp_idx = exp_idx; + ptr->cur_idx = cur_idx; + *pkt_count = cnt; + } + } + else { + uint8 end_idx; + /* no real packet but update to exp_seq...that means explicit window move */ + exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; + + DHD_REORDER(("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n", + __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx)); + if (flags & WLHOST_REORDERDATA_FLUSH_ALL) + end_idx = ptr->exp_idx; + else + end_idx = exp_idx; + + dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx); + if (plast) + PKTSETNEXT(dhd->osh, plast, cur_pkt); + else + *pkt = cur_pkt; + cnt++; + *pkt_count = cnt; + /* set the new expected idx */ + ptr->exp_idx = exp_idx; + } + return 0; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c new file mode 100644 index 000000000000..ed3a7690b342 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c @@ -0,0 +1,301 @@ +/* + * Linux cfg80211 driver - Dongle Host Driver (DHD) related + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + */ + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef PKT_FILTER_SUPPORT +#include +#include +#endif +extern struct bcm_cfg80211 *g_bcm_cfg; + +#ifdef PKT_FILTER_SUPPORT +extern uint dhd_pkt_filter_enable; +extern uint dhd_master_mode; +extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); +#endif + +static int dhd_dongle_up = FALSE; + +#include +#include +#include +#include +#include + +static s32 wl_dongle_up(struct net_device *ndev, u32 up); + +/** + * Function implementations + */ + +s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg) +{ + dhd_dongle_up = FALSE; + return 0; +} + +s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg) +{ + dhd_dongle_up = FALSE; + return 0; +} + +s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg) +{ + dhd_dongle_up = FALSE; + return 0; +} + +s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + dhd->op_mode |= val; + WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode)); +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd->arp_version == 1) { + /* IF P2P is enabled, disable arpoe */ + dhd_arp_offload_set(dhd, 0); + dhd_arp_offload_enable(dhd, false); + } +#endif /* ARP_OFFLOAD_SUPPORT */ + + return 0; +} + +s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); + WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode)); + +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd->arp_version == 1) { + /* IF P2P is disabled, enable arpoe back for STA mode. */ + dhd_arp_offload_set(dhd, dhd_arp_mode); + dhd_arp_offload_enable(dhd, true); + } +#endif /* ARP_OFFLOAD_SUPPORT */ + + return 0; +} + +struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, + uint8 *mac, uint8 bssidx) +{ + return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE); +} + +int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) +{ + return dhd_register_if(cfg->pub, ifidx, FALSE); +} + +int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) +{ + return dhd_remove_if(cfg->pub, ifidx, FALSE); +} + +struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev) +{ + if (ndev) { + if (ndev->ieee80211_ptr) { + kfree(ndev->ieee80211_ptr); + ndev->ieee80211_ptr = NULL; + } + free_netdev(ndev); + return NULL; + } + + return ndev; +} + +void dhd_netdev_free(struct net_device *ndev) +{ +#ifdef WL_CFG80211 + ndev = dhd_cfg80211_netdev_free(ndev); +#endif + if (ndev) + free_netdev(ndev); +} + +static s32 wl_dongle_up(struct net_device *ndev, u32 up) +{ + s32 err = 0; + + err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + } + return err; +} + +s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) +{ +#ifndef DHD_SDALIGN +#define DHD_SDALIGN 32 +#endif + struct net_device *ndev; + s32 err = 0; + + WL_TRACE(("In\n")); + if (dhd_dongle_up) { + WL_ERR(("Dongle is already up\n")); + return err; + } + + ndev = bcmcfg_to_prmry_ndev(cfg); + + err = wl_dongle_up(ndev, 0); + if (unlikely(err)) { + WL_ERR(("wl_dongle_up failed\n")); + goto default_conf_out; + } + dhd_dongle_up = true; + +default_conf_out: + + return err; + +} + +#ifdef CONFIG_NL80211_TESTMODE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len) +#else +int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ +{ + struct sk_buff *reply; + struct bcm_cfg80211 *cfg; + dhd_pub_t *dhd; + struct bcm_nlmsg_hdr *nlioc = data; + dhd_ioctl_t ioc = { 0 }; + int err = 0; + void *buf = NULL, *cur; + u16 buflen; + u16 maxmsglen = PAGE_SIZE - 0x100; + bool newbuf = false; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + int8 index = 0; + struct net_device *ndev = NULL; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ + + WL_TRACE(("entry: cmd = %d\n", nlioc->cmd)); + cfg = wiphy_priv(wiphy); + dhd = cfg->pub; + + DHD_OS_WAKE_LOCK(dhd); + + /* send to dongle only if we are not waiting for reload already */ + if (dhd->hang_was_sent) { + WL_ERR(("HANG was sent up earlier\n")); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS); + DHD_OS_WAKE_UNLOCK(dhd); + return OSL_ERROR(BCME_DONGLE_DOWN); + } + + len -= sizeof(struct bcm_nlmsg_hdr); + + if (nlioc->len > 0) { + if (nlioc->len <= len) { + buf = (void *)nlioc + nlioc->offset; + *(char *)(buf + nlioc->len) = '\0'; + } else { + if (nlioc->len > DHD_IOCTL_MAXLEN) + nlioc->len = DHD_IOCTL_MAXLEN; + buf = vzalloc(nlioc->len); + if (!buf) + return -ENOMEM; + newbuf = true; + memcpy(buf, (void *)nlioc + nlioc->offset, len); + *(char *)(buf + len) = '\0'; + } + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + ndev = wdev_to_wlc_ndev(wdev, cfg); + index = dhd_net2idx(dhd->info, ndev); + if (index == DHD_BAD_IF) { + WL_ERR(("Bad ifidx from wdev:%p\n", wdev)); + return BCME_ERROR; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ + + ioc.cmd = nlioc->cmd; + ioc.len = nlioc->len; + ioc.set = nlioc->set; + ioc.driver = nlioc->magic; + err = dhd_ioctl_process(dhd, 0, &ioc, buf); + if (err) { + WL_TRACE(("dhd_ioctl_process return err %d\n", err)); + err = OSL_ERROR(err); + goto done; + } + + cur = buf; + while (nlioc->len > 0) { + buflen = nlioc->len > maxmsglen ? maxmsglen : nlioc->len; + nlioc->len -= buflen; + reply = cfg80211_testmode_alloc_reply_skb(wiphy, buflen+4); + if (!reply) { + WL_ERR(("Failed to allocate reply msg\n")); + err = -ENOMEM; + break; + } + + if (nla_put(reply, BCM_NLATTR_DATA, buflen, cur) || + nla_put_u16(reply, BCM_NLATTR_LEN, buflen)) { + kfree_skb(reply); + err = -ENOBUFS; + break; + } + + do { + err = cfg80211_testmode_reply(reply); + } while (err == -EAGAIN); + if (err) { + WL_ERR(("testmode reply failed:%d\n", err)); + break; + } + cur += buflen; + } + +done: + if (newbuf) + vfree(buf); + DHD_OS_WAKE_UNLOCK(dhd); + return err; +} +#endif /* CONFIG_NL80211_TESTMODE */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h new file mode 100644 index 000000000000..a160571ad8c9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h @@ -0,0 +1,59 @@ +/* + * Linux cfg80211 driver - Dongle Host Driver (DHD) related + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + */ + + +#ifndef __DHD_CFG80211__ +#define __DHD_CFG80211__ + +#include +#include + +s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg); +s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg); +s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg); +s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val); +s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg); +s32 dhd_config_dongle(struct bcm_cfg80211 *cfg); + +#ifdef CONFIG_NL80211_TESTMODE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len); +#else +int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static inline int +dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len) +#else +static inline int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ +{ + return 0; +} +#endif /* CONFIG_NL80211_TESTMODE */ + +#endif /* __DHD_CFG80211__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c new file mode 100644 index 000000000000..d141eb539c2c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c @@ -0,0 +1,2354 @@ +/* + * Broadcom Dongle Host Driver (DHD), common DHD core. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_common.c 701450 2017-05-25 02:10:23Z $ + */ +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#ifdef WL_CFG80211 +#include +#endif +#ifdef PNO_SUPPORT +#include +#endif +#ifdef RTT_SUPPORT +#include +#endif +#ifdef SET_RANDOM_MAC_SOFTAP +#include +#include +#endif +#ifdef RTT_SUPPORT +#include +#endif +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) + +#ifdef PROP_TXSTATUS +#include +#include +#endif + +#ifdef WLMEDIA_HTSF +extern void htsf_update(struct dhd_info *dhd, void *data); +#endif +int dhd_msg_level = DHD_ERROR_VAL; + + +#if defined(WL_WIRELESS_EXT) +#include +#endif + +#ifdef SOFTAP +char fw_path2[MOD_PARAM_PATHLEN]; +extern bool softap_enabled; +#endif + +/* Last connection success/failure status */ +uint32 dhd_conn_event; +uint32 dhd_conn_status; +uint32 dhd_conn_reason; + +extern int dhd_iscan_request(void * dhdp, uint16 action); +extern void dhd_ind_scan_confirm(void *h, bool status); +extern int dhd_iscan_in_progress(void *h); +void dhd_iscan_lock(void); +void dhd_iscan_unlock(void); +extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); +#if !defined(AP) && defined(WLP2P) +extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); +#endif +bool ap_cfg_running = FALSE; +bool ap_fw_loaded = FALSE; + +/* Version string to report */ +#ifdef DHD_DEBUG +#ifndef SRCBASE +#define SRCBASE "drivers/net/wireless/bcmdhd_bcm43455" +#endif +#define DHD_COMPILED "\nCompiled in " SRCBASE +#endif /* DHD_DEBUG */ + +#if defined(DHD_DEBUG) +const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR + DHD_COMPILED " on " __DATE__ " at " __TIME__; +#else +const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nCompiled from "; +#endif + +void dhd_set_timer(void *bus, uint wdtick); + +/* IOVar table */ +enum { + IOV_VERSION = 1, + IOV_MSGLEVEL, + IOV_BCMERRORSTR, + IOV_BCMERROR, + IOV_WDTICK, + IOV_DUMP, + IOV_CLEARCOUNTS, + IOV_LOGDUMP, + IOV_LOGCAL, + IOV_LOGSTAMP, + IOV_GPIOOB, + IOV_IOCTLTIMEOUT, +#if defined(DHD_DEBUG) + IOV_CONS, + IOV_DCONSOLE_POLL, + IOV_DHD_JOIN_TIMEOUT_DBG, + IOV_SCAN_TIMEOUT, +#endif /* defined(DHD_DEBUG) */ +#ifdef PROP_TXSTATUS + IOV_PROPTXSTATUS_ENABLE, + IOV_PROPTXSTATUS_MODE, + IOV_PROPTXSTATUS_OPT, + IOV_PROPTXSTATUS_MODULE_IGNORE, + IOV_PROPTXSTATUS_CREDIT_IGNORE, + IOV_PROPTXSTATUS_TXSTATUS_IGNORE, + IOV_PROPTXSTATUS_RXPKT_CHK, +#endif /* PROP_TXSTATUS */ + IOV_BUS_TYPE, +#ifdef WLMEDIA_HTSF + IOV_WLPKTDLYSTAT_SZ, +#endif + IOV_CHANGEMTU, + IOV_HOSTREORDER_FLOWS, +#ifdef DHDTCPACK_SUPPRESS + IOV_TCPACK_SUPPRESS, +#endif /* DHDTCPACK_SUPPRESS */ + IOV_LAST +}; + +const bcm_iovar_t dhd_iovars[] = { + {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, +#ifdef DHD_DEBUG + {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, +#endif /* DHD_DEBUG */ + {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, + {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, + {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, + {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, +#ifdef DHD_DEBUG + {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, + {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, + {"scan_timeout", IOV_SCAN_TIMEOUT, 0, IOVT_UINT32, 0 }, + {"join_timeout_dbg", IOV_DHD_JOIN_TIMEOUT_DBG, 0, IOVT_UINT32, 0 }, +#endif + {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, + {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, + {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, +#ifdef PROP_TXSTATUS + {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_BOOL, 0 }, + /* + set the proptxtstatus operation mode: + 0 - Do not do any proptxtstatus flow control + 1 - Use implied credit from a packet status + 2 - Use explicit credit + */ + {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, + {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, IOVT_UINT32, 0 }, + {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, IOVT_BOOL, 0 }, + {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, IOVT_BOOL, 0 }, + {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, IOVT_BOOL, 0 }, + {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, IOVT_BOOL, 0 }, +#endif /* PROP_TXSTATUS */ + {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, +#ifdef WLMEDIA_HTSF + {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, +#endif + {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, + {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER, + (WLHOST_REORDERDATA_MAXFLOWS + 1) }, +#ifdef DHDTCPACK_SUPPRESS + {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, IOVT_UINT8, 0 }, +#endif /* DHDTCPACK_SUPPRESS */ + {NULL, 0, 0, 0, 0 } +}; + +#define DHD_IOVAR_BUF_SIZE 128 + + +void dhd_save_fwdump(dhd_pub_t *dhd_pub, void * buffer, uint32 length) +{ + + if (dhd_pub->soc_ram == NULL) { + dhd_pub->soc_ram = (uint8*) MALLOCZ(dhd_pub->osh, length); + if (dhd_pub->soc_ram == NULL) { + DHD_ERROR(("%s: Failed to allocate memory for fw crash snap shot.\n", + __FUNCTION__)); + return; + } + } + dhd_pub->soc_ram_length = length; + memcpy(dhd_pub->soc_ram, buffer, length); +} + +/* to NDIS developer, the structure dhd_common is redundant, + * please do NOT merge it back from other branches !!! + */ + +static int +dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) +{ + char eabuf[ETHER_ADDR_STR_LEN]; + + struct bcmstrbuf b; + struct bcmstrbuf *strbuf = &b; + + bcm_binit(strbuf, buf, buflen); + + /* Base DHD info */ + bcm_bprintf(strbuf, "%s\n", dhd_version); + bcm_bprintf(strbuf, "\n"); + bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", + dhdp->up, dhdp->txoff, dhdp->busstate); + bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n", + dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); + bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", + dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); + bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt); + + bcm_bprintf(strbuf, "dongle stats:\n"); + bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n", + dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, + dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); + bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n", + dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, + dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); + bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast); + + bcm_bprintf(strbuf, "bus stats:\n"); + bcm_bprintf(strbuf, "tx_packets %lu tx_multicast %lu tx_errors %lu\n", + dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors); + bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", + dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); + bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n", + dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); + bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n", + dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); + bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n", + dhdp->rx_readahead_cnt, dhdp->tx_realloc); + bcm_bprintf(strbuf, "\n"); + + /* Add any prot info */ + dhd_prot_dump(dhdp, strbuf); + bcm_bprintf(strbuf, "\n"); + + /* Add any bus info */ + dhd_bus_dump(dhdp, strbuf); + + return (!strbuf->size ? BCME_BUFTOOSHORT : 0); +} + +int +dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex) +{ + wl_ioctl_t ioc; + + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + ioc.set = set; + + return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); +} + + +int +dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len) +{ + int ret = 0; + + if (dhd_os_proto_block(dhd_pub)) + { + + ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); + if ((ret) && (dhd_pub->up)) + /* Send hang event only if dhd_open() was success */ + dhd_os_check_hang(dhd_pub, ifindex, ret); + + if (ret == -ETIMEDOUT && !dhd_pub->up) { + DHD_ERROR(("%s: 'resumed on timeout' error is " + "occurred before the interface does not" + " bring up\n", __FUNCTION__)); + dhd_pub->busstate = DHD_BUS_DOWN; + } + + dhd_os_proto_unblock(dhd_pub); + + + } + + return ret; +} + +static int +dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, + void *params, int plen, void *arg, int len, int val_size) +{ + int bcmerror = 0; + int32 int_val = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) + goto exit; + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + switch (actionid) { + case IOV_GVAL(IOV_VERSION): + /* Need to have checked buffer length */ + bcm_strncpy_s((char*)arg, len, dhd_version, len); + break; + + case IOV_GVAL(IOV_MSGLEVEL): + int_val = (int32)dhd_msg_level; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MSGLEVEL): +#ifdef WL_CFG80211 + /* Enable DHD and WL logs in oneshot */ + if (int_val & DHD_WL_VAL2) + wl_cfg80211_enable_trace(TRUE, int_val & (~DHD_WL_VAL2)); + else if (int_val & DHD_WL_VAL) + wl_cfg80211_enable_trace(FALSE, WL_DBG_DBG); + if (!(int_val & DHD_WL_VAL2)) +#endif /* WL_CFG80211 */ + dhd_msg_level = int_val; + break; + case IOV_GVAL(IOV_BCMERRORSTR): + bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); + ((char *)arg)[BCME_STRLEN - 1] = 0x00; + break; + + case IOV_GVAL(IOV_BCMERROR): + int_val = (int32)dhd_pub->bcmerror; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_WDTICK): + int_val = (int32)dhd_watchdog_ms; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_WDTICK): + if (!dhd_pub->up) { + bcmerror = BCME_NOTUP; + break; + } + dhd_os_wd_timer(dhd_pub, (uint)int_val); + break; + + case IOV_GVAL(IOV_DUMP): + bcmerror = dhd_dump(dhd_pub, arg, len); + break; + +#ifdef DHD_DEBUG + case IOV_GVAL(IOV_SCAN_TIMEOUT): + { + uint32 scan_timeout = dhd_get_scan_timeout(dhd_pub); + bcopy(&scan_timeout, arg, sizeof(scan_timeout)); + break; + } + case IOV_SVAL(IOV_SCAN_TIMEOUT): + { + uint32 scan_timeout; + bcopy(((uint8*)params), &scan_timeout, sizeof(scan_timeout)); + dhd_set_scan_timeout(dhd_pub, scan_timeout); + break; + } + case IOV_GVAL(IOV_DHD_JOIN_TIMEOUT_DBG): + { + uint32 join_timeout = dhd_get_join_timeout(dhd_pub); + bcopy(&join_timeout, arg, sizeof(join_timeout)); + break; + } + case IOV_SVAL(IOV_DHD_JOIN_TIMEOUT_DBG): + { + uint32 join_timeout; + bcopy(((uint8*)params), &join_timeout, sizeof(join_timeout)); + dhd_set_join_timeout(dhd_pub, join_timeout); + break; + } +#endif /* DHD_DEBUG */ + +#ifdef DHD_DEBUG + case IOV_GVAL(IOV_DCONSOLE_POLL): + int_val = (int32)dhd_console_ms; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DCONSOLE_POLL): + dhd_console_ms = (uint)int_val; + break; + + case IOV_SVAL(IOV_CONS): + if (len > 0) + bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); + break; +#endif /* DHD_DEBUG */ + + case IOV_SVAL(IOV_CLEARCOUNTS): + dhd_pub->tx_packets = dhd_pub->rx_packets = 0; + dhd_pub->tx_errors = dhd_pub->rx_errors = 0; + dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; + dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; + dhd_pub->rx_dropped = 0; + dhd_pub->rx_readahead_cnt = 0; + dhd_pub->tx_realloc = 0; + dhd_pub->wd_dpc_sched = 0; + memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); + dhd_bus_clearcounts(dhd_pub); +#ifdef PROP_TXSTATUS + /* clear proptxstatus related counters */ + dhd_wlfc_clear_counts(dhd_pub); +#endif /* PROP_TXSTATUS */ + break; + + + case IOV_GVAL(IOV_IOCTLTIMEOUT): { + int_val = (int32)dhd_os_get_ioctl_resp_timeout(); + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_IOCTLTIMEOUT): { + if (int_val <= 0) + bcmerror = BCME_BADARG; + else + dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); + break; + } + + +#ifdef PROP_TXSTATUS + case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): { + bool wlfc_enab = FALSE; + bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); + if (bcmerror != BCME_OK) + goto exit; + int_val = wlfc_enab ? 1 : 0; + bcopy(&int_val, arg, val_size); + break; + } + case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): { + bool wlfc_enab = FALSE; + bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); + if (bcmerror != BCME_OK) + goto exit; + + /* wlfc is already set as desired */ + if (wlfc_enab == (int_val == 0 ? FALSE : TRUE)) + goto exit; + + if (int_val == TRUE) + bcmerror = dhd_wlfc_init(dhd_pub); + else + bcmerror = dhd_wlfc_deinit(dhd_pub); + + break; + } + case IOV_GVAL(IOV_PROPTXSTATUS_MODE): + bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_MODE): + dhd_wlfc_set_mode(dhd_pub, int_val); + break; + + case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): + bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): + dhd_wlfc_set_module_ignore(dhd_pub, int_val); + break; + + case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): + bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): + dhd_wlfc_set_credit_ignore(dhd_pub, int_val); + break; + + case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): + bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): + dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val); + break; + + case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK): + bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val); + if (bcmerror != BCME_OK) + goto exit; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK): + dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val); + break; + +#endif /* PROP_TXSTATUS */ + + case IOV_GVAL(IOV_BUS_TYPE): + /* The dhd application queries the driver to check if its usb or sdio. */ +#ifdef BCMDHDUSB + int_val = BUS_TYPE_USB; +#endif + int_val = BUS_TYPE_SDIO; +#ifdef PCIE_FULL_DONGLE + int_val = BUS_TYPE_PCIE; +#endif + bcopy(&int_val, arg, val_size); + break; + + +#ifdef WLMEDIA_HTSF + case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): + int_val = dhd_pub->htsfdlystat_sz; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): + dhd_pub->htsfdlystat_sz = int_val & 0xff; + printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); + break; +#endif + case IOV_SVAL(IOV_CHANGEMTU): + int_val &= 0xffff; + bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); + break; + + case IOV_GVAL(IOV_HOSTREORDER_FLOWS): + { + uint i = 0; + uint8 *ptr = (uint8 *)arg; + uint8 count = 0; + + ptr++; + for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { + if (dhd_pub->reorder_bufs[i] != NULL) { + *ptr = dhd_pub->reorder_bufs[i]->flow_id; + ptr++; + count++; + } + } + ptr = (uint8 *)arg; + *ptr = count; + break; + } +#ifdef DHDTCPACK_SUPPRESS + case IOV_GVAL(IOV_TCPACK_SUPPRESS): { + int_val = (uint32)dhd_pub->tcpack_sup_mode; + bcopy(&int_val, arg, val_size); + break; + } + case IOV_SVAL(IOV_TCPACK_SUPPRESS): { + bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val); + break; + } +#endif /* DHDTCPACK_SUPPRESS */ + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } + +exit: + DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); + return bcmerror; +} + +/* Store the status of a connection attempt for later retrieval by an iovar */ +void +dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) +{ + /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID + * because an encryption/rsn mismatch results in both events, and + * the important information is in the WLC_E_PRUNE. + */ + if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && + dhd_conn_event == WLC_E_PRUNE)) { + dhd_conn_event = event; + dhd_conn_status = status; + dhd_conn_reason = reason; + } +} + +bool +dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) +{ + void *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)) { + 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 = pktq_peek_tail(q, &eprec); + ASSERT(p); + if (eprec > prec || eprec < 0) + return FALSE; + } + + /* Evict if needed */ + if (eprec >= 0) { + /* Detect queueing to unconfigured precedence */ + ASSERT(!pktq_pempty(q, eprec)); + discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); + if (eprec == prec && !discard_oldest) + return FALSE; /* refuse newer (incoming) packet */ + /* Evict packet according to discard policy */ + p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); + ASSERT(p); +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + PKTFREE(dhdp->osh, p, TRUE); + } + + /* Enqueue */ + p = pktq_penq(q, prec, pkt); + ASSERT(p); + + return TRUE; +} + +/* + * Functions to drop proper pkts from queue: + * If one pkt in queue is non-fragmented, drop first non-fragmented pkt only + * If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts + * If can't find pkts matching upper 2 cases, drop first pkt anyway + */ +bool +dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn) +{ + struct pktq_prec *q = NULL; + void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL; + pkt_frag_t frag_info; + + ASSERT(dhdp && pq); + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + p = q->head; + + if (p == NULL) + return FALSE; + + while (p) { + frag_info = pkt_frag_info(dhdp->osh, p); + if (frag_info == DHD_PKT_FRAG_NONE) { + break; + } else if (frag_info == DHD_PKT_FRAG_FIRST) { + if (first) { + /* No last frag pkt, use prev as last */ + last = prev; + break; + } else { + first = p; + prev_first = prev; + } + } else if (frag_info == DHD_PKT_FRAG_LAST) { + if (first) { + last = p; + break; + } + } + + prev = p; + p = PKTLINK(p); + } + + if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) { + /* Not found matching pkts, use oldest */ + prev = NULL; + p = q->head; + frag_info = 0; + } + + if (frag_info == DHD_PKT_FRAG_NONE) { + first = last = p; + prev_first = prev; + } + + p = first; + while (p) { + next = PKTLINK(p); + q->len--; + pq->len--; + + PKTSETLINK(p, NULL); + + if (fn) + fn(dhdp, prec, p, TRUE); + + if (p == last) + break; + + p = next; + } + + if (prev_first == NULL) { + if ((q->head = next) == NULL) + q->tail = NULL; + } else { + PKTSETLINK(prev_first, next); + if (!next) + q->tail = prev_first; + } + + return TRUE; +} + +static int +dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + int bcmerror = 0; + int val_size; + const bcm_iovar_t *vi = NULL; + uint32 actionid; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(name); + ASSERT(len >= 0); + + /* Get MUST have return space */ + ASSERT(set || (arg && len)); + + /* Set does NOT take qualifiers */ + ASSERT(!set || (!params && !plen)); + + if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { + bcmerror = BCME_UNSUPPORTED; + goto exit; + } + + DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, + name, (set ? "set" : "get"), len, plen)); + + /* set up 'params' pointer in case this is a set command so that + * the convenience int and bool code can be common to set and get + */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + /* all other types are integer sized */ + val_size = sizeof(int); + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + + bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); + +exit: + return bcmerror; +} + +int +dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) +{ + int bcmerror = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!buf) { + return BCME_BADARG; + } + + switch (ioc->cmd) { + case DHD_GET_MAGIC: + if (buflen < sizeof(int)) + bcmerror = BCME_BUFTOOSHORT; + else + *(int*)buf = DHD_IOCTL_MAGIC; + break; + + case DHD_GET_VERSION: + if (buflen < sizeof(int)) + bcmerror = BCME_BUFTOOSHORT; + else + *(int*)buf = DHD_IOCTL_VERSION; + break; + + case DHD_GET_VAR: + case DHD_SET_VAR: { + char *arg; + uint arglen; + + /* scan past the name to any arguments */ + for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) + ; + + if (*arg) { + bcmerror = BCME_BUFTOOSHORT; + break; + } + + /* account for the NUL terminator */ + arg++, arglen--; + + /* call with the appropriate arguments */ + if (ioc->cmd == DHD_GET_VAR) + bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, + buf, buflen, IOV_GET); + else + bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); + if (bcmerror != BCME_UNSUPPORTED) + break; + + /* not in generic table, try protocol module */ + if (ioc->cmd == DHD_GET_VAR) + bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, + arglen, buf, buflen, IOV_GET); + else + bcmerror = dhd_prot_iovar_op(dhd_pub, buf, + NULL, 0, arg, arglen, IOV_SET); + if (bcmerror != BCME_UNSUPPORTED) + break; + + /* if still not found, try bus module */ + if (ioc->cmd == DHD_GET_VAR) { + bcmerror = dhd_bus_iovar_op(dhd_pub, buf, + arg, arglen, buf, buflen, IOV_GET); + } else { + bcmerror = dhd_bus_iovar_op(dhd_pub, buf, + NULL, 0, arg, arglen, IOV_SET); + } + + break; + } + + default: + bcmerror = BCME_UNSUPPORTED; + } + + return bcmerror; +} + +#ifdef SHOW_EVENTS +static void +wl_show_host_event(wl_event_msg_t *event, void *event_data) +{ + uint i, status, reason; + bool group = FALSE, flush_txq = FALSE, link = FALSE; + const char *auth_str; + const char *event_name; + uchar *buf; + char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; + uint event_type, flags, auth_type, datalen; + + event_type = ntoh32(event->event_type); + flags = ntoh16(event->flags); + status = ntoh32(event->status); + reason = ntoh32(event->reason); + BCM_REFERENCE(reason); + auth_type = ntoh32(event->auth_type); + datalen = ntoh32(event->datalen); + + /* debug dump of event messages */ + snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", + (uchar)event->addr.octet[0]&0xff, + (uchar)event->addr.octet[1]&0xff, + (uchar)event->addr.octet[2]&0xff, + (uchar)event->addr.octet[3]&0xff, + (uchar)event->addr.octet[4]&0xff, + (uchar)event->addr.octet[5]&0xff); + + event_name = "UNKNOWN"; + for (i = 0; i < (uint)bcmevent_names_size; i++) + if (bcmevent_names[i].event == event_type) + event_name = bcmevent_names[i].name; + + if (flags & WLC_EVENT_MSG_LINK) + link = TRUE; + if (flags & WLC_EVENT_MSG_GROUP) + group = TRUE; + if (flags & WLC_EVENT_MSG_FLUSHTXQ) + flush_txq = TRUE; + + switch (event_type) { + case WLC_E_START: + case WLC_E_DEAUTH: + case WLC_E_DISASSOC: + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + break; + + case WLC_E_ASSOC_IND: + case WLC_E_REASSOC_IND: + + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + break; + + case WLC_E_ASSOC: + case WLC_E_REASSOC: + if (status == WLC_E_STATUS_SUCCESS) { + DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); + } else if (status == WLC_E_STATUS_TIMEOUT) { + DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); + } else if (status == WLC_E_STATUS_FAIL) { + DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", + event_name, eabuf, (int)reason)); + } else { + DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n", + event_name, eabuf, (int)status)); + } + break; + + case WLC_E_DEAUTH_IND: + case WLC_E_DISASSOC_IND: + DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); + break; + + case WLC_E_AUTH: + case WLC_E_AUTH_IND: + if (auth_type == DOT11_OPEN_SYSTEM) + auth_str = "Open System"; + else if (auth_type == DOT11_SHARED_KEY) + auth_str = "Shared Key"; + else { + snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); + auth_str = err_msg; + } + if (event_type == WLC_E_AUTH_IND) { + DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); + } else if (status == WLC_E_STATUS_SUCCESS) { + DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", + event_name, eabuf, auth_str)); + } else if (status == WLC_E_STATUS_TIMEOUT) { + DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", + event_name, eabuf, auth_str)); + } else if (status == WLC_E_STATUS_FAIL) { + DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", + event_name, eabuf, auth_str, (int)reason)); + } + BCM_REFERENCE(auth_str); + + break; + + case WLC_E_JOIN: + case WLC_E_ROAM: + case WLC_E_SET_SSID: + if (status == WLC_E_STATUS_SUCCESS) { + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + } else if (status == WLC_E_STATUS_FAIL) { + DHD_EVENT(("MACEVENT: %s, failed\n", event_name)); + } else if (status == WLC_E_STATUS_NO_NETWORKS) { + DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name)); + } else { + DHD_EVENT(("MACEVENT: %s, unexpected status %d\n", + event_name, (int)status)); + } + break; + + case WLC_E_BEACON_RX: + if (status == WLC_E_STATUS_SUCCESS) { + DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); + } else if (status == WLC_E_STATUS_FAIL) { + DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); + } else { + DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); + } + break; + + case WLC_E_LINK: + DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); + BCM_REFERENCE(link); + break; + + case WLC_E_MIC_ERROR: + DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", + event_name, eabuf, group, flush_txq)); + BCM_REFERENCE(group); + BCM_REFERENCE(flush_txq); + break; + + case WLC_E_ICV_ERROR: + case WLC_E_UNICAST_DECODE_ERROR: + case WLC_E_MULTICAST_DECODE_ERROR: + DHD_EVENT(("MACEVENT: %s, MAC %s\n", + event_name, eabuf)); + break; + + case WLC_E_TXFAIL: + DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf)); + break; + + case WLC_E_SCAN_COMPLETE: + case WLC_E_ASSOC_REQ_IE: + case WLC_E_ASSOC_RESP_IE: + case WLC_E_PMKID_CACHE: + DHD_EVENT(("MACEVENT: %s\n", event_name)); + break; + + case WLC_E_PFN_NET_FOUND: + case WLC_E_PFN_NET_LOST: + case WLC_E_PFN_SCAN_COMPLETE: + case WLC_E_PFN_SCAN_NONE: + case WLC_E_PFN_SCAN_ALLGONE: + DHD_EVENT(("PNOEVENT: %s\n", event_name)); + break; + + case WLC_E_PSK_SUP: + case WLC_E_PRUNE: + DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", + event_name, (int)status, (int)reason)); + break; + +#ifdef WIFI_ACT_FRAME + case WLC_E_ACTION_FRAME: + DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); + break; +#endif /* WIFI_ACT_FRAME */ + + case WLC_E_TRACE: { + static uint32 seqnum_prev = 0; + static uint32 logtrace_seqnum_prev = 0; + msgtrace_hdr_t hdr; + uint32 nblost; + char *s, *p; + + buf = (uchar *) event_data; + memcpy(&hdr, buf, MSGTRACE_HDRLEN); + + if (hdr.version != MSGTRACE_VERSION) { + printf("\nMACEVENT: %s [unsupported version --> " + "dhd version:%d dongle version:%d]\n", + event_name, MSGTRACE_VERSION, hdr.version); + /* Reset datalen to avoid display below */ + datalen = 0; + break; + } + + if (hdr.trace_type == MSGTRACE_HDR_TYPE_MSG) { + /* There are 2 bytes available at the end of data */ + buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; + + if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { + printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" + "discarded_bytes %d discarded_printf %d]\n", + ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); + } + + nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; + if (nblost > 0) { + printf("\nWLC_E_TRACE: [Event lost (msg) --> seqnum %d nblost %d\n", + ntoh32(hdr.seqnum), nblost); + } + seqnum_prev = ntoh32(hdr.seqnum); + + /* Display the trace buffer. Advance from \n to \n to avoid display big + * printf (issue with Linux printk ) + */ + p = (char *)&buf[MSGTRACE_HDRLEN]; + while (*p != '\0' && (s = strstr(p, "\n")) != NULL) { + *s = '\0'; + printf("WLC_E_TRACE: %s\n", p); + p = s+1; + } + if (*p) printf("WLC_E_TRACE: %s", p); + + /* Reset datalen to avoid display below */ + datalen = 0; + + } else if (hdr.trace_type == MSGTRACE_HDR_TYPE_LOG) { + /* Let the standard event printing work for now */ + uint32 timestamp, w; + if (ntoh32(hdr.seqnum) == logtrace_seqnum_prev) { + printf("\nWLC_E_TRACE: [Event duplicate (log) %d", + logtrace_seqnum_prev); + } else { + nblost = ntoh32(hdr.seqnum) - logtrace_seqnum_prev - 1; + if (nblost > 0) { + printf("\nWLC_E_TRACE: [Event lost (log)" + " --> seqnum %d nblost %d\n", + ntoh32(hdr.seqnum), nblost); + } + logtrace_seqnum_prev = ntoh32(hdr.seqnum); + + p = (char *)&buf[MSGTRACE_HDRLEN]; + datalen -= MSGTRACE_HDRLEN; + w = ntoh32((uint32) *p); + p += 4; + datalen -= 4; + timestamp = ntoh32((uint32) *p); + printf("Logtrace %x timestamp %x %x", + logtrace_seqnum_prev, timestamp, w); + + while (datalen > 4) { + p += 4; + datalen -= 4; + /* Print each word. DO NOT ntoh it. */ + printf(" %8.8x", *((uint32 *) p)); + } + printf("\n"); + } + datalen = 0; + } + + break; + } + + + case WLC_E_RSSI: + DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); + break; + + case WLC_E_SERVICE_FOUND: + case WLC_E_P2PO_ADD_DEVICE: + case WLC_E_P2PO_DEL_DEVICE: + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + break; + + + case WLC_E_CCA_CHAN_QUAL: + if (datalen) { + buf = (uchar *) event_data; + DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d, " + "channel 0x%02x \n", event_name, event_type, eabuf, (int)status, + (int)reason, (int)auth_type, *(buf + 4))); + } + break; + + + default: + DHD_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 (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen) { + buf = (uchar *) event_data; + DHD_EVENT((" data (%d) : ", datalen)); + for (i = 0; i < datalen; i++) + DHD_EVENT((" 0x%02x ", *buf++)); + DHD_EVENT(("\n")); + } +} +#endif /* SHOW_EVENTS */ + +/* Check whether packet is a BRCM event pkt. If it is, record event data. */ +int +wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu) +{ + int ret; + + ret = is_wlc_event_frame(pktdata, pktlen, 0, evu); + if (ret != BCME_OK) { + DHD_ERROR(("%s: Invalid event frame, err = %d\n", + __FUNCTION__, ret)); + } + + return ret; +} + +int +wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, size_t pktlen, + wl_event_msg_t *event, void **data_ptr) +{ + bcm_event_t *pvt_data = (bcm_event_t *)pktdata; + uint8 *event_data; + uint32 type, status, datalen; + uint16 flags; + uint evlen; + int ret; + uint16 usr_subtype; + bcm_event_msg_u_t evu; + + ret = wl_host_event_get_data(pktdata, pktlen, &evu); + if (ret != BCME_OK) { + return ret; + } + + usr_subtype = ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype); + switch (usr_subtype) { + case BCMILCP_BCM_SUBTYPE_EVENT: + memcpy(event, &evu.event, sizeof(wl_event_msg_t)); + *data_ptr = &pvt_data[1]; + break; + + case BCMILCP_BCM_SUBTYPE_DNGLEVENT: + return BCME_NOTFOUND; + + default: + return BCME_NOTFOUND; + } + + /* start wl_event_msg process */ + event_data = *data_ptr; + type = ntoh32_ua((void *)&event->event_type); + flags = ntoh16_ua((void *)&event->flags); + status = ntoh32_ua((void *)&event->status); + datalen = ntoh32_ua((void *)&event->datalen); + + evlen = datalen + sizeof(bcm_event_t); + + switch (type) { +#ifdef DHD_DEBUG + case WLC_E_JOIN_START: + case WLC_E_ROAM_START: + dhd_start_join_timer(dhd_pub); + break; + case WLC_E_ASSOC: + case WLC_E_REASSOC: + if ((status != WLC_E_STATUS_TIMEOUT) && (status != WLC_E_STATUS_FAIL)) + break; + case WLC_E_SET_SSID: + if (status != WLC_E_STATUS_SUCCESS) + break; + case WLC_E_JOIN: + case WLC_E_ROAM: + dhd_del_join_timer(dhd_pub); + break; + + case WLC_E_SCAN_CONFIRM_IND: + dhd_add_scan_timer(dhd_pub); + break; + + case WLC_E_ESCAN_RESULT: + dhd_del_scan_timer(dhd_pub); + break; +#endif /* DHD_DEBUG */ +#ifdef PROP_TXSTATUS + case WLC_E_FIFO_CREDIT_MAP: + dhd_wlfc_enable(dhd_pub); + dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data); + WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " + "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], + event_data[2], + event_data[3], event_data[4], event_data[5])); + break; + + case WLC_E_BCMC_CREDIT_SUPPORT: + dhd_wlfc_BCMCCredit_support_event(dhd_pub); + break; +#endif + + case WLC_E_IF: { + struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data; + + /* Ignore the event if NOIF is set */ + if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) { + DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n")); + return (BCME_UNSUPPORTED); + } + +#ifdef PROP_TXSTATUS + { + uint8* ea = pvt_data->eth.ether_dhost; + WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " + "[%02x:%02x:%02x:%02x:%02x:%02x]\n", + ifevent->ifidx, + ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD":"DEL"), + ((ifevent->role == 0) ? "STA":"AP "), + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); + (void)ea; + + if (ifevent->opcode == WLC_E_IF_CHANGE) + dhd_wlfc_interface_event(dhd_pub, + eWLFC_MAC_ENTRY_ACTION_UPDATE, + ifevent->ifidx, ifevent->role, ea); + else + dhd_wlfc_interface_event(dhd_pub, + ((ifevent->opcode == WLC_E_IF_ADD) ? + eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), + ifevent->ifidx, ifevent->role, ea); + + /* dhd already has created an interface by default, for 0 */ + if (ifevent->ifidx == 0) + break; + } +#endif /* PROP_TXSTATUS */ + + if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { + if (ifevent->opcode == WLC_E_IF_ADD) { + if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname, + event->addr.octet)) { + + DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d %s\n", + __FUNCTION__, ifevent->ifidx, event->ifname)); + return (BCME_ERROR); + } + } else if (ifevent->opcode == WLC_E_IF_DEL) { + dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname, + event->addr.octet); + } else if (ifevent->opcode == WLC_E_IF_CHANGE) { +#ifdef WL_CFG80211 + wl_cfg80211_notify_ifchange(ifevent->ifidx, + event->ifname, event->addr.octet, ifevent->bssidx); +#endif /* WL_CFG80211 */ + } + } else { +#ifndef PROP_TXSTATUS + DHD_ERROR(("%s: Invalid ifidx %d for %s\n", + __FUNCTION__, ifevent->ifidx, event->ifname)); +#endif /* !PROP_TXSTATUS */ + } + + /* send up the if event: btamp user needs it */ + *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); + /* push up to external supp/auth */ + dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); + break; + } +#ifdef WLMEDIA_HTSF + case WLC_E_HTSFSYNC: + htsf_update(dhd_pub->info, event_data); + break; +#endif /* WLMEDIA_HTSF */ + case WLC_E_NDIS_LINK: { + uint32 temp = hton32(WLC_E_LINK); + + memcpy((void *)(&pvt_data->event.event_type), &temp, + sizeof(pvt_data->event.event_type)); + } + case WLC_E_PFN_NET_FOUND: + case WLC_E_PFN_NET_LOST: + break; +#if defined(PNO_SUPPORT) + case WLC_E_PFN_BSSID_NET_FOUND: + case WLC_E_PFN_BSSID_NET_LOST: + case WLC_E_PFN_BEST_BATCHING: + dhd_pno_event_handler(dhd_pub, event, (void *)event_data); + break; +#endif + /* These are what external supplicant/authenticator wants */ + /* fall through */ +#if defined(RTT_SUPPORT) + case WLC_E_PROXD: + dhd_rtt_event_handler(dhd_pub, event, (void *)event_data); + break; +#endif /* RTT_SUPPORT */ + case WLC_E_LINK: + case WLC_E_DEAUTH: + case WLC_E_DEAUTH_IND: + case WLC_E_DISASSOC: + case WLC_E_DISASSOC_IND: + DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", + __FUNCTION__, type, flags, status)); + /* fall through */ + default: + *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); + /* push up to external supp/auth */ + dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); + DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", + __FUNCTION__, type, flags, status)); + BCM_REFERENCE(flags); + BCM_REFERENCE(status); + + break; + } + +#ifdef SHOW_EVENTS + wl_show_host_event(event, (void *)event_data); +#endif /* SHOW_EVENTS */ + + return (BCME_OK); +} + +void +wl_event_to_host_order(wl_event_msg_t * evt) +{ + /* Event struct members passed from dongle to host are stored in network + * byte order. Convert all members to host-order. + */ + evt->event_type = ntoh32(evt->event_type); + evt->flags = ntoh16(evt->flags); + evt->status = ntoh32(evt->status); + evt->reason = ntoh32(evt->reason); + evt->auth_type = ntoh32(evt->auth_type); + evt->datalen = ntoh32(evt->datalen); + evt->version = ntoh16(evt->version); +} + +void +dhd_print_buf(void *pbuf, int len, int bytes_per_line) +{ +#ifdef DHD_DEBUG + int i, j = 0; + unsigned char *buf = pbuf; + + if (bytes_per_line == 0) { + bytes_per_line = len; + } + + for (i = 0; i < len; i++) { + printf("%2.2x", *buf++); + j++; + if (j == bytes_per_line) { + printf("\n"); + j = 0; + } else { + printf(":"); + } + } + printf("\n"); +#endif /* DHD_DEBUG */ +} +#ifndef strtoul +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#endif + +#ifdef PKT_FILTER_SUPPORT +/* Convert user's input in hex pattern to byte-size mask */ +static int +wl_pattern_atoh(char *src, char *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && + strncmp(src, "0X", 2) != 0) { + DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); + return -1; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); + return -1; + } + for (i = 0; *src != '\0'; i++) { + char num[3]; + bcm_strncpy_s(num, sizeof(num), src, 2); + num[2] = '\0'; + dst[i] = (uint8)strtoul(num, NULL, 16); + src += 2; + } + return i; +} + +void +dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) +{ + char *argv[8]; + int i = 0; + const char *str; + int buf_len; + int str_len; + char *arg_save = 0, *arg_org = 0; + int rc; + char buf[128]; + wl_pkt_filter_enable_t enable_parm; + wl_pkt_filter_enable_t * pkt_filterp; + + if (!arg) + return; + + if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } + arg_org = arg_save; + memcpy(arg_save, arg, strlen(arg) + 1); + + argv[i] = bcmstrtok(&arg_save, " ", 0); + + i = 0; + if (argv[i] == NULL) { + DHD_ERROR(("No args provided\n")); + goto fail; + } + + str = "pkt_filter_enable"; + str_len = strlen(str); + bcm_strncpy_s(buf, sizeof(buf), str, str_len); + buf[str_len] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); + + /* Parse packet filter id. */ + enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); + + /* Parse enable/disable value. */ + enable_parm.enable = htod32(enable); + + buf_len += sizeof(enable_parm); + memcpy((char *)pkt_filterp, + &enable_parm, + sizeof(enable_parm)); + + /* Enable/disable the specified filter. */ + rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); + rc = rc >= 0 ? 0 : rc; + if (rc) + DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", + __FUNCTION__, arg, rc)); + else + DHD_TRACE(("%s: successfully added pktfilter %s\n", + __FUNCTION__, arg)); + + /* Contorl the master mode */ + rc = dhd_iovar(dhd, 0, "pkt_filter_mode", (char *)&master_mode, + sizeof(master_mode), NULL, 0, TRUE); + + rc = rc >= 0 ? 0 : rc; + if (rc) + DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", + __FUNCTION__, arg, rc)); +fail: + if (arg_org) + MFREE(dhd->osh, arg_org, strlen(arg) + 1); +} + +void +dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) +{ + const char *str; + wl_pkt_filter_t pkt_filter; + wl_pkt_filter_t *pkt_filterp; + int buf_len; + int str_len; + int rc; + uint32 mask_size; + uint32 pattern_size; + char *argv[8], * buf = 0; + int i = 0; + char *arg_save = 0, *arg_org = 0; +#define BUF_SIZE 2048 + + if (!arg) + return; + + if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } + + arg_org = arg_save; + + if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } + + memcpy(arg_save, arg, strlen(arg) + 1); + + if (strlen(arg) > BUF_SIZE) { + DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); + goto fail; + } + + argv[i] = bcmstrtok(&arg_save, " ", 0); + while (argv[i++]) + argv[i] = bcmstrtok(&arg_save, " ", 0); + + i = 0; + if (argv[i] == NULL) { + DHD_ERROR(("No args provided\n")); + goto fail; + } + + str = "pkt_filter_add"; + str_len = strlen(str); + bcm_strncpy_s(buf, BUF_SIZE, str, str_len); + buf[ str_len ] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); + + /* Parse packet filter id. */ + pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Polarity not provided\n")); + goto fail; + } + + /* Parse filter polarity. */ + pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Filter type not provided\n")); + goto fail; + } + + /* Parse filter type. */ + pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Offset not provided\n")); + goto fail; + } + + /* Parse pattern filter offset. */ + pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Bitmask not provided\n")); + goto fail; + } + + /* Parse pattern filter mask. */ + mask_size = + htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Pattern not provided\n")); + goto fail; + } + + /* Parse pattern filter pattern. */ + pattern_size = + htod32(wl_pattern_atoh(argv[i], + (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); + + if (mask_size != pattern_size) { + DHD_ERROR(("Mask and pattern not the same size\n")); + goto fail; + } + + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_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, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); + + rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); + rc = rc >= 0 ? 0 : rc; + + if (rc) + DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", + __FUNCTION__, arg, rc)); + else + DHD_TRACE(("%s: successfully added pktfilter %s\n", + __FUNCTION__, arg)); + +fail: + if (arg_org) + MFREE(dhd->osh, arg_org, strlen(arg) + 1); + + if (buf) + MFREE(dhd->osh, buf, BUF_SIZE); +} + +void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id) +{ + int ret; + + ret = dhd_iovar(dhd, 0, "pkt_filter_delete", (char *)&id, sizeof(id), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n", + __FUNCTION__, id, ret)); + } +} +#endif /* PKT_FILTER_SUPPORT */ + +/* ========================== */ +/* ==== ARP OFFLOAD SUPPORT = */ +/* ========================== */ +#ifdef ARP_OFFLOAD_SUPPORT +void +dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) +{ + int ret; + + ret = dhd_iovar(dhd, 0, "arp_ol", (char *)&arp_mode, sizeof(arp_mode), NULL, 0, TRUE); + ret = ret >= 0 ? 0 : ret; + if (ret) + DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, ret = %d\n", + __FUNCTION__, arp_mode, ret)); + else + DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", + __FUNCTION__, arp_mode)); +} + +void +dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) +{ + char iovbuf[DHD_IOVAR_BUF_SIZE]; + int ret; + + ret = dhd_iovar(dhd, 0, "arpoe", (char *)&arp_enable, sizeof(arp_enable), NULL, 0, TRUE); + ret = ret >= 0 ? 0 : ret; + if (ret) + DHD_TRACE(("%s: failed to enabe ARP offload to %d, ret = %d\n", + __FUNCTION__, arp_enable, ret)); + else + DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", + __FUNCTION__, arp_enable)); + + if (arp_enable) { + uint32 version; + ret = dhd_iovar(dhd, 0, "arp_version", NULL, 0, (char *)iovbuf, + sizeof(iovbuf), FALSE); + if (ret) { + DHD_INFO(("%s: fail to get version (maybe version 1:ret = %d\n", + __FUNCTION__, ret)); + dhd->arp_version = 1; + } + else { + memcpy(&version, iovbuf, sizeof(version)); + DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version)); + dhd->arp_version = version; + } + } +} + +void +dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) +{ + int ret = 0; + + if (dhd == NULL) return; + if (dhd->arp_version == 1) + idx = 0; + + ret = dhd_iovar(dhd, idx, "arp_table_clear", NULL, 0, NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); +} + +void +dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) +{ + int ret = 0; + + if (dhd == NULL) return; + if (dhd->arp_version == 1) + idx = 0; + + ret = dhd_iovar(dhd, idx, "arp_hostip_clear", NULL, 0, NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); +} + +void +dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) +{ + int ret; + + if (dhd == NULL) return; + if (dhd->arp_version == 1) + idx = 0; + + ret = dhd_iovar(dhd, idx, "arp_hostip", (char *)&ipaddr, sizeof(ipaddr), + NULL, 0, TRUE); + if (ret) + DHD_TRACE(("%s: ARP ip addr add failed, ret = %d\n", __FUNCTION__, ret)); + else + DHD_TRACE(("%s: sARP H ipaddr entry added \n", + __FUNCTION__)); +} + +int +dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) +{ + int ret, i; + + uint32 *ptr32 = buf; + bool clr_bottom = FALSE; + + if (!buf) + return -1; + if (dhd == NULL) return -1; + if (dhd->arp_version == 1) + idx = 0; + + ret = dhd_iovar(dhd, idx, "arp_hostip", NULL, 0, (char *)buf, buflen, + FALSE); + if (ret) { + DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", + __FUNCTION__, ret)); + + return -1; + } + + /* clean up the buf, ascii reminder */ + for (i = 0; i < MAX_IPV4_ENTRIES; i++) { + if (!clr_bottom) { + if (*ptr32 == 0) + clr_bottom = TRUE; + } else { + *ptr32 = 0; + } + ptr32++; + } + + return 0; +} +#endif /* ARP_OFFLOAD_SUPPORT */ + +/* + * Neighbor Discovery Offload: enable NDO feature + * Called by ipv6 event handler when interface comes up/goes down + */ +int +dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable) +{ + int ret; + + if (dhd == NULL) + return -1; + + ret = dhd_iovar(dhd, 0, "ndoe", (char *)&ndo_enable, sizeof(ndo_enable), + NULL, 0, TRUE); + if (ret) + DHD_ERROR(("%s: failed to enabe ndo to %d, ret = %d\n", + __FUNCTION__, ndo_enable, ret)); + else + DHD_TRACE(("%s: successfully enabed ndo offload to %d\n", + __FUNCTION__, ndo_enable)); + + return ret; +} + +/* + * Neighbor Discover Offload: enable NDO feature + * Called by ipv6 event handler when interface comes up + */ +int +dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx) +{ + int ret; + + if (dhd == NULL) + return -1; + + ret = dhd_iovar(dhd, idx, "nd_hostip", (char *)ipv6addr, IPV6_ADDR_LEN, + NULL, 0, TRUE); + if (ret) + DHD_ERROR(("%s: ndo ip addr add failed, ret = %d\n", + __FUNCTION__, ret)); + else + DHD_TRACE(("%s: ndo ipaddr entry added \n", + __FUNCTION__)); + + return ret; +} +/* + * Neighbor Discover Offload: enable NDO feature + * Called by ipv6 event handler when interface goes down + */ +int +dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx) +{ + int ret; + + if (dhd == NULL) + return -1; + + ret = dhd_iovar(dhd, idx, "nd_hostip_clear", NULL, 0, + NULL, 0, TRUE); + if (ret) + DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n", + __FUNCTION__, ret)); + else + DHD_TRACE(("%s: ndo ipaddr entry removed \n", + __FUNCTION__)); + + return ret; +} + +/* send up locally generated event */ +void +dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) +{ + switch (ntoh32(event->event_type)) { + default: + break; + } + + /* Call per-port handler. */ + dhd_sendup_event(dhdp, event, data); +} + + +/* + * returns = TRUE if associated, FALSE if not associated + */ +bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) +{ + char bssid[6], zbuf[6]; + int ret = -1; + + bzero(bssid, 6); + bzero(zbuf, 6); + + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0); + DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); + + if (ret == BCME_NOTASSOCIATED) { + DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); + } + + if (retval) + *retval = ret; + + if (ret < 0) + return FALSE; + + if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { + /* STA is assocoated BSSID is non zero */ + + if (bss_buf) { + /* return bss if caller provided buf */ + memcpy(bss_buf, bssid, ETHER_ADDR_LEN); + } + return TRUE; + } else { + DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); + return FALSE; + } +} + + +/* Function to estimate possible DTIM_SKIP value */ +int +dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) +{ + int bcn_li_dtim = 1; /* deafult no dtim skip setting */ + int ret = -1; + int dtim_period = 0; + int ap_beacon = 0; + int allowed_skip_dtim_cnt = 0; + /* Check if associated */ + if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { + DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); + goto exit; + } + + /* read associated AP beacon interval */ + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, + &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) { + DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); + goto exit; + } + + /* read associated ap's dtim setup */ + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, + &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) { + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); + goto exit; + } + + /* if not assocated just eixt */ + if (dtim_period == 0) { + goto exit; + } + + /* attemp to use platform defined dtim skip interval */ + bcn_li_dtim = dhd->suspend_bcn_li_dtim; + + /* check if sta listen interval fits into AP dtim */ + if (dtim_period > CUSTOM_LISTEN_INTERVAL) { + /* AP DTIM to big for our Listen Interval : no dtim skiping */ + bcn_li_dtim = NO_DTIM_SKIP; + DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", + __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL)); + goto exit; + } + + if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { + allowed_skip_dtim_cnt = MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon); + bcn_li_dtim = (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; + } + + if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) { + /* Round up dtim_skip to fit into STAs Listen Interval */ + bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period); + DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); + } + + DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", + __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL)); + +exit: + return bcn_li_dtim; +} + +/* Check if the mode supports STA MODE */ +bool dhd_support_sta_mode(dhd_pub_t *dhd) +{ + +#ifdef WL_CFG80211 + if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) + return FALSE; + else +#endif /* WL_CFG80211 */ + return TRUE; +} + +#if defined(KEEP_ALIVE) +int dhd_keep_alive_onoff(dhd_pub_t *dhd) +{ + char buf[256]; + const char *str; + wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0}; + wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + int buf_len; + int str_len; + int res = -1; + + if (!dhd_support_sta_mode(dhd)) + return res; + + DHD_TRACE(("%s execution\n", __FUNCTION__)); + + str = "mkeep_alive"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[ str_len ] = '\0'; + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); + mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING; + buf_len = str_len + 1; + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + /* Setup keep alive zero for null packet generation */ + mkeep_alive_pkt.keep_alive_id = 0; + mkeep_alive_pkt.len_bytes = 0; + buf_len += WL_MKEEP_ALIVE_FIXED_LEN; + bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); + /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and + * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); + + res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); + + return res; +} +#endif /* defined(KEEP_ALIVE) */ +#define CSCAN_TLV_TYPE_SSID_IE 'S' +/* + * SSIDs list parsing from cscan tlv list + */ +int +wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left) +{ + char* str; + int idx = 0; + + if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + str = *list_str; + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { + *list_str = str; + DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + return idx; + } + + /* Get proper CSCAN_TLV_TYPE_SSID_IE */ + *bytes_left -= 1; + str += 1; + ssid[idx].rssi_thresh = 0; + if (str[0] == 0) { + /* Broadcast SSID */ + ssid[idx].SSID_len = 0; + memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); + *bytes_left -= 1; + str += 1; + + DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); + } + else if (str[0] <= DOT11_MAX_SSID_LEN) { + /* Get proper SSID size */ + ssid[idx].SSID_len = str[0]; + *bytes_left -= 1; + str += 1; + + /* Get SSID */ + if (ssid[idx].SSID_len > *bytes_left) { + DHD_ERROR(("%s out of memory range len=%d but left=%d\n", + __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); + return -1; + } + + memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); + + *bytes_left -= ssid[idx].SSID_len; + str += ssid[idx].SSID_len; + ssid[idx].hidden = TRUE; + + DHD_TRACE(("%s :size=%d left=%d\n", + (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); + } + else { + DHD_ERROR(("### SSID size more that %d\n", str[0])); + return -1; + } + + if (idx++ > max) { + DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); + return -1; + } + } + + *list_str = str; + return idx; +} +#if defined(WL_WIRELESS_EXT) +/* Android ComboSCAN support */ + +/* + * data parsing from ComboScan tlv list +*/ +int +wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, + int input_size, int *bytes_left) +{ + char* str; + uint16 short_temp; + uint32 int_temp; + + if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + str = *list_str; + + /* Clean all dest bytes */ + memset(dst, 0, dst_size); + while (*bytes_left > 0) { + + if (str[0] != token) { + DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", + __FUNCTION__, token, str[0], *bytes_left)); + return -1; + } + + *bytes_left -= 1; + str += 1; + + if (input_size == 1) { + memcpy(dst, str, input_size); + } + else if (input_size == 2) { + memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), + input_size); + } + else if (input_size == 4) { + memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), + input_size); + } + + *bytes_left -= input_size; + str += input_size; + *list_str = str; + return 1; + } + return 1; +} + +/* + * channel list parsing from cscan tlv list +*/ +int +wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, + int channel_num, int *bytes_left) +{ + char* str; + int idx = 0; + + if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + str = *list_str; + + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { + *list_str = str; + DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + return idx; + } + /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ + *bytes_left -= 1; + str += 1; + + if (str[0] == 0) { + /* All channels */ + channel_list[idx] = 0x0; + } + else { + channel_list[idx] = (uint16)str[0]; + DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); + } + *bytes_left -= 1; + str += 1; + + if (idx++ > 255) { + DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); + return -1; + } + } + + *list_str = str; + return idx; +} + +/* Parse a comma-separated list from list_str into ssid array, starting + * at index idx. Max specifies size of the ssid array. Parses ssids + * and returns updated idx; if idx >= max not all fit, the excess have + * not been copied. Returns -1 on empty string, or on ssid too long. + */ +int +wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) +{ + char* str, *ptr; + + if ((list_str == NULL) || (*list_str == NULL)) + return -1; + + for (str = *list_str; str != NULL; str = ptr) { + + /* check for next TAG */ + if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { + *list_str = str + strlen(GET_CHANNEL); + return idx; + } + + if ((ptr = strchr(str, ',')) != NULL) { + *ptr++ = '\0'; + } + + if (strlen(str) > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); + return -1; + } + + if (strlen(str) == 0) + ssid[idx].SSID_len = 0; + + if (idx < max) { + bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); + strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); + ssid[idx].SSID_len = strlen(str); + } + idx++; + } + return idx; +} + +/* + * Parse channel list from iwpriv CSCAN + */ +int +wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) +{ + int num; + int val; + char* str; + char* endptr = NULL; + + if ((list_str == NULL)||(*list_str == NULL)) + return -1; + + str = *list_str; + num = 0; + while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { + val = (int)strtoul(str, &endptr, 0); + if (endptr == str) { + printf("could not parse channel number starting at" + " substring \"%s\" in list:\n%s\n", + str, *list_str); + return -1; + } + str = endptr + strspn(endptr, " ,"); + + if (num == channel_num) { + DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", + channel_num, *list_str)); + return -1; + } + + channel_list[num++] = (uint16)val; + } + *list_str = str; + return num; +} + +#endif diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c new file mode 100644 index 000000000000..d45598994a6a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c @@ -0,0 +1,588 @@ +/* +* Customer code to add GPIO control during WLAN start/stop +* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 2013 Sony Mobile Communications Inc. +* +* Unless you and Broadcom execute a separate written software license +* agreement governing use of this software, this software is licensed to you +* under the terms of the GNU General Public License version 2 (the "GPL"), +* available at http://www.broadcom.com/licenses/GPLv2.php, with the +* following added to such license: +* +* As a special exception, the copyright holders of this software give you +* permission to link this software with independent modules, and to copy and +* distribute the resulting executable under terms of your choice, provided that +* you also meet, for each linked independent module, the terms and conditions of +* the license of that module. An independent module is a module which is not +* derived from this software. The special exception does not apply to any +* modifications of the software. +* +* Notwithstanding the above, under no circumstances may you combine this +* software in any way with any other Broadcom software provided under a license +* other than the GPL, without Broadcom's express prior written consent. +* +* $Id: dhd_custom_gpio.c 684925 2017-02-15 01:55:31Z $ +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#if defined(WL_WIRELESS_EXT) +#include +#endif + +#define WL_ERROR(x) printf x +#define WL_TRACE(x) + +#if defined(CUSTOMER_HW2) + + +#endif + +#ifdef GET_CUSTOM_MAC_ENABLE +#define MACADDR_BUF_LEN 64 +#define MACADDR_PATH "/data/etc/wlan_macaddr0" +#endif /* GET_CUSTOM_MAC_ENABLE */ + +#if defined(OOB_INTR_ONLY) + +#if defined(BCMLXSDMMC) +extern int sdioh_mmc_irq(int irq); +#endif /* (BCMLXSDMMC) */ + +#if defined(CUSTOMER_HW3) +#include +#endif + +/* Customer specific Host GPIO defintion */ +static int dhd_oob_gpio_num = -1; + +module_param(dhd_oob_gpio_num, int, 0644); +MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); + +/* This function will return: + * 1) return : Host gpio interrupt number per customer platform + * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge + * + * NOTE : + * Customer should check his platform definitions + * and his Host Interrupt spec + * to figure out the proper setting for his platform. + * Broadcom provides just reference settings as example. + * + */ +int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr) +{ + int host_oob_irq = 0; + +#if defined(CUSTOMER_HW2) + host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr); + +#else +#if defined(CUSTOM_OOB_GPIO_NUM) + if (dhd_oob_gpio_num < 0) { + dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; + } +#endif /* CUSTOMER_OOB_GPIO_NUM */ + + if (dhd_oob_gpio_num < 0) { + WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", + __FUNCTION__)); + return (dhd_oob_gpio_num); + } + + WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", + __FUNCTION__, dhd_oob_gpio_num)); + +#if defined(CUSTOMER_HW3) + gpio_request(dhd_oob_gpio_num, "oob irq"); + host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); + gpio_direction_input(dhd_oob_gpio_num); +#endif /* defined CUSTOMER_HW3 */ +#endif + + return (host_oob_irq); +} +#endif + +/* Customer function to control hw specific wlan gpios */ +int +dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff) +{ + int err = 0; + + return err; +} + +#ifdef GET_CUSTOM_MAC_ENABLE +int somc_get_mac_address(unsigned char *buf) +{ + int ret = -EINVAL; + int len; + unsigned char macaddr_buf[MACADDR_BUF_LEN]; + void *fp = NULL; + struct ether_addr eth; + + if (!buf) + return -EINVAL; + + fp = dhd_os_open_image(MACADDR_PATH); + if (!fp) { + WL_ERROR(("%s: file open error\n", __FUNCTION__)); + goto err; + } + + len = dhd_os_get_image_block(macaddr_buf, MACADDR_BUF_LEN, fp); + if (len <= 0 || MACADDR_BUF_LEN <= len) { + WL_ERROR(("%s: file read error\n", __FUNCTION__)); + goto err; + } + macaddr_buf[len] = '\0'; + + /* convert mac address */ + ret = !bcm_ether_atoe(macaddr_buf, ð); + if (ret) { + WL_ERROR(("%s: convert mac value fail\n", __FUNCTION__)); + goto err; + } + + memcpy(buf, eth.octet, ETHER_ADDR_LEN); +err: + if (fp) + dhd_os_close_image(fp); + return ret; +} + +/* Function to get custom MAC address */ +int +dhd_custom_get_mac_address(void *adapter, unsigned char *buf) +{ + int ret = 0; + + WL_TRACE(("%s Enter\n", __FUNCTION__)); + if (!buf) + return -EINVAL; + + /* Customer access to MAC address stored outside of DHD driver */ +#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + ret = wifi_platform_get_mac_addr(adapter, buf); +#endif + +#ifdef EXAMPLE_GET_MAC + /* EXAMPLE code */ + { + struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; + bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); + } +#endif /* EXAMPLE_GET_MAC */ + + return ret; +} +#endif /* GET_CUSTOM_MAC_ENABLE */ + +struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ + char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ + int32 custom_locale_rev; /* Custom local revisin default -1 */ +}; +/* Customized Locale table : OPTIONAL feature */ +const struct cntry_locales_custom translate_custom_table[] = { +/* Table should be filled out based on custom platform regulatory requirement */ +#ifdef EXAMPLE_TABLE + {"", "XY", 4}, /* Universal if Country code is unknown or empty */ + {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ + {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ + {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ + {"AT", "EU", 5}, + {"BE", "EU", 5}, + {"BG", "EU", 5}, + {"CY", "EU", 5}, + {"CZ", "EU", 5}, + {"DK", "EU", 5}, + {"EE", "EU", 5}, + {"FI", "EU", 5}, + {"FR", "EU", 5}, + {"DE", "EU", 5}, + {"GR", "EU", 5}, + {"HU", "EU", 5}, + {"IE", "EU", 5}, + {"IT", "EU", 5}, + {"LV", "EU", 5}, + {"LI", "EU", 5}, + {"LT", "EU", 5}, + {"LU", "EU", 5}, + {"MT", "EU", 5}, + {"NL", "EU", 5}, + {"PL", "EU", 5}, + {"PT", "EU", 5}, + {"RO", "EU", 5}, + {"SK", "EU", 5}, + {"SI", "EU", 5}, + {"ES", "EU", 5}, + {"SE", "EU", 5}, + {"GB", "EU", 5}, + {"KR", "XY", 3}, + {"AU", "XY", 3}, + {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ + {"TW", "XY", 3}, + {"AR", "XY", 3}, + {"MX", "XY", 3}, + {"IL", "IL", 0}, + {"CH", "CH", 0}, + {"TR", "TR", 0}, + {"NO", "NO", 0}, +#endif /* EXMAPLE_TABLE */ +#if defined(CUSTOMER_HW2) && !defined(CUSTOMER_HW5) +#if defined(BCM4335_CHIP) + {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ +#endif + {"AE", "AE", 1}, + {"AR", "AR", 1}, + {"AT", "AT", 1}, + {"AU", "AU", 2}, + {"BE", "BE", 1}, + {"BG", "BG", 1}, + {"BN", "BN", 1}, + {"CA", "CA", 2}, + {"CH", "CH", 1}, + {"CY", "CY", 1}, + {"CZ", "CZ", 1}, + {"DE", "DE", 3}, + {"DK", "DK", 1}, + {"EE", "EE", 1}, + {"ES", "ES", 1}, + {"FI", "FI", 1}, + {"FR", "FR", 1}, + {"GB", "GB", 1}, + {"GR", "GR", 1}, + {"HR", "HR", 1}, + {"HU", "HU", 1}, + {"IE", "IE", 1}, + {"IS", "IS", 1}, + {"IT", "IT", 1}, + {"ID", "ID", 1}, + {"JP", "JP", 8}, + {"KR", "KR", 24}, + {"KW", "KW", 1}, + {"LI", "LI", 1}, + {"LT", "LT", 1}, + {"LU", "LU", 1}, + {"LV", "LV", 1}, + {"MA", "MA", 1}, + {"MT", "MT", 1}, + {"MX", "MX", 1}, + {"NL", "NL", 1}, + {"NO", "NO", 1}, + {"PL", "PL", 1}, + {"PT", "PT", 1}, + {"PY", "PY", 1}, + {"RO", "RO", 1}, + {"SE", "SE", 1}, + {"SI", "SI", 1}, + {"SK", "SK", 1}, + {"TR", "TR", 7}, + {"TW", "TW", 1}, + {"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ + {"SD", "XZ", 11}, /* Universal if Country code is SUDAN */ + {"SY", "XZ", 11}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ + {"GL", "XZ", 11}, /* Universal if Country code is GREENLAND */ + {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ + {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ + {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ +#ifdef BCM4330_CHIP + {"RU", "RU", 1}, + {"US", "US", 5} +#endif + +#elif defined(CUSTOMER_HW5) + /* default ccode/regrev */ + {"", "XT", 54}, /* Universal if Country code is unknown or empty */ + {"IR", "XT", 54}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ + {"SD", "XT", 54}, /* Universal if Country code is SUDAN */ + {"SY", "XT", 54}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ + {"GL", "E0", 979}, /* Universal if Country code is GREENLAND */ + {"PS", "XT", 54}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ + {"TL", "XT", 54}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ + {"MH", "XT", 54}, /* Universal if Country code is MARSHALL ISLANDS */ + {"CK", "XT", 54}, /* Universal if Country code is Cook Islands */ + {"CU", "XT", 54}, /* Universal if Country code is Cuba */ + {"FO", "XT", 54}, /* Universal if Country code is Faroe Islands */ + {"GI", "XT", 54}, /* Universal if Country code is Gibraltar */ + {"KP", "XT", 54}, /* Universal if Country code is North Korea */ + {"NE", "XT", 54}, /* Universal if Country code is Niger (Republic of the) */ + {"PM", "XT", 54}, /* Universal if Country code is Saint Pierre and Miquelon */ + {"WF", "XT", 54}, /* Universal if Country code is Wallis and Futuna */ + + {"XA", "XX", 4}, /* Default country code for INDONESIA */ + {"XC", "XT", 998}, /* Default country code for RUSSIA */ + {"XD", "XT", 65}, /* Default country code for CHILE */ + {"AD", "AD", 0}, + {"AE", "AE", 212}, + {"AF", "AF", 0}, + {"AG", "XT", 54}, + {"AI", "AI", 2}, + {"AL", "AL", 2}, + {"AM", "AM", 0}, + {"AN", "AN", 3}, + {"AO", "AO", 0}, + {"AR", "AR", 212}, + {"AS", "AS", 15}, + {"AT", "E0", 979}, + {"AU", "AU", 212}, + {"AW", "XT", 54}, + {"AZ", "XT", 54}, + {"BA", "BA", 2}, + {"BB", "BB", 0}, + {"BD", "XT", 54}, + {"BE", "E0", 979}, + {"BF", "XT", 54}, + {"BG", "E0", 979}, + {"BH", "BH", 4}, + {"BI", "BI", 0}, + {"BJ", "BJ", 0}, + {"BM", "BM", 15}, + {"BN", "BN", 4}, + {"BO", "XT", 54}, + {"BR", "BR", 212}, + {"BS", "XT", 54}, + {"BT", "XT", 54}, + {"BW", "BW", 1}, + {"BY", "XT", 54}, + {"BZ", "XT", 54}, + {"CA", "CA", 212}, + {"CD", "CD", 0}, + {"CF", "CF", 0}, + {"CG", "CG", 0}, + {"CH", "E0", 979}, + {"CI", "CI", 0}, + {"CL", "CL", 212}, + {"CM", "CM", 0}, + {"CN", "CN", 212}, + {"CO", "CO", 212}, + {"CR", "CR", 21}, + {"CV", "CV", 0}, + {"CX", "CX", 1}, + {"CY", "E0", 979}, + {"CZ", "E0", 979}, + {"DE", "E0", 979}, + {"DJ", "DJ", 0}, + {"DK", "E0", 979}, + {"DM", "XT", 54}, + {"DO", "XT", 54}, + {"DZ", "DZ", 1}, + {"EC", "EC", 23}, + {"EE", "E0", 979}, + {"EG", "EG", 212}, + {"ER", "ER", 0}, + {"ES", "E0", 979}, + {"ET", "ET", 2}, + {"FI", "E0", 979}, + {"FJ", "XT", 54}, + {"FK", "FK", 0}, + {"FM", "XT", 54}, + {"FR", "E0", 979}, + {"GA", "GA", 0}, + {"GB", "E0", 979}, + {"GD", "XT", 54}, + {"GE", "GE", 0}, + {"GF", "GF", 2}, + {"GH", "GH", 0}, + {"GM", "GM", 0}, + {"GN", "GN", 0}, + {"GP", "GP", 2}, + {"GQ", "GQ", 0}, + {"GR", "E0", 979}, + {"GT", "XT", 54}, + {"GU", "GU", 17}, + {"GW", "GW", 0}, + {"GY", "GY", 0}, + {"HK", "HK", 212}, + {"HN", "HN", 0}, + {"HR", "E0", 979}, + {"HT", "HT", 0}, + {"HU", "E0", 979}, + {"ID", "ID", 212}, + {"IE", "E0", 979}, + {"IL", "IL", 7}, + {"IN", "IN", 212}, + {"IQ", "IQ", 0}, + {"IS", "E0", 979}, + {"IT", "E0", 979}, + {"JM", "JM", 0}, + {"JO", "JO", 3}, + {"JP", "JP", 212}, + {"KE", "KE", 0}, + {"KG", "KG", 0}, + {"KH", "KH", 4}, + {"KI", "KI", 1}, + {"KM", "KM", 0}, + {"KN", "XT", 54}, + {"KR", "KR", 212}, + {"KW", "KW", 5}, + {"KY", "KY", 4}, + {"KZ", "KZ", 212}, + {"LA", "LA", 4}, + {"LB", "LB", 6}, + {"LC", "XT", 54}, + {"LI", "E0", 979}, + {"LK", "XT", 54}, + {"LR", "LR", 2}, + {"LS", "LS", 2}, + {"LT", "E0", 979}, + {"LU", "E0", 979}, + {"LV", "E0", 979}, + {"LY", "LY", 0}, + {"MA", "MA", 2}, + {"MC", "E0", 979}, + {"MD", "MD", 2}, + {"ME", "ME", 2}, + {"MF", "XT", 54}, + {"MG", "MG", 0}, + {"MK", "E0", 979}, + {"ML", "ML", 0}, + {"MM", "MM", 0}, + {"MN", "XT", 54}, + {"MO", "MO", 2}, + {"MP", "XT", 54}, + {"MQ", "MQ", 2}, + {"MR", "MR", 2}, + {"MS", "MS", 0}, + {"MT", "E0", 979}, + {"MU", "MU", 2}, + {"MV", "MV", 3}, + {"MW", "XT", 54}, + {"MX", "MX", 212}, + {"MY", "MY", 998}, + {"MZ", "XT", 54}, + {"NA", "XT", 54}, + {"NC", "NC", 0}, + {"NG", "NG", 0}, + {"NI", "NI", 0}, + {"NL", "E0", 979}, + {"NO", "E0", 979}, + {"NP", "NP", 3}, + {"NR", "NR", 0}, + {"NZ", "NZ", 9}, + {"OM", "OM", 4}, + {"PA", "PA", 17}, + {"PE", "PE", 212}, + {"PF", "PF", 0}, + {"PG", "PG", 2}, + {"PH", "PH", 212}, + {"PK", "PK", 0}, + {"PL", "E0", 979}, + {"PR", "PR", 25}, + {"PT", "E0", 979}, + {"PW", "XT", 54}, + {"PY", "PY", 4}, + {"QA", "QA", 0}, + {"RE", "RE", 2}, + {"RO", "E0", 979}, + {"RS", "RS", 2}, + {"RU", "RU", 212}, + {"RW", "XT", 54}, + {"SA", "SA", 212}, + {"SB", "SB", 0}, + {"SC", "XT", 54}, + {"SE", "E0", 979}, + {"SG", "SG", 212}, + {"SI", "E0", 979}, + {"SK", "E0", 979}, + {"SL", "SL", 0}, + {"SM", "SM", 0}, + {"SN", "SN", 2}, + {"SO", "SO", 0}, + {"SR", "SR", 0}, + {"ST", "ST", 0}, + {"SV", "XT", 54}, + {"SZ", "SZ", 0}, + {"TC", "TC", 0}, + {"TD", "TD", 0}, + {"TF", "TF", 0}, + {"TG", "TG", 0}, + {"TH", "TH", 212}, + {"TJ", "TJ", 0}, + {"TM", "TM", 0}, + {"TN", "TN", 0}, + {"TO", "TO", 0}, + {"TR", "E0", 979}, + {"TT", "TT", 5}, + {"TV", "TV", 0}, + {"TW", "TW", 996}, + {"TZ", "XT", 54}, +#ifdef ENABLE_80211AC_FOR_UA + {"UA", "UA", 999}, +#else + {"UA", "UA", 212}, +#endif + {"UG", "XT", 54}, + {"US", "US", 996}, + {"UY", "UY", 5}, + {"UZ", "XT", 54}, + {"VA", "VA", 2}, + {"VC", "XT", 54}, + {"VE", "VE", 3}, + {"VG", "XT", 54}, + {"VI", "VI", 18}, + {"VN", "XT", 54}, + {"VU", "XT", 54}, + {"WS", "XT", 54}, + {"YE", "XT", 54}, + {"YT", "YT", 2}, + {"ZA", "ZA", 212}, + {"ZM", "ZM", 2}, + {"ZW", "XT", 54}, +#endif /* CUSTOMER_HW2 and CUSTOMER_HW5 */ +}; + + +/* Customized Locale convertor +* input : ISO 3166-1 country abbreviation +* output: customized cspec +*/ +void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec) +{ +#if 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))) + + struct cntry_locales_custom *cloc_ptr; + + if (!cspec) + return; + + cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code); + if (cloc_ptr) { + strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = cloc_ptr->custom_locale_rev; + } + return; +#else + int size, i; + + size = ARRAYSIZE(translate_custom_table); + + if (cspec == 0) + return; + + if (size == 0) + return; + + for (i = 0; i < size; i++) { + if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { + memcpy(cspec->ccode, + translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = translate_custom_table[i].custom_locale_rev; + return; + } + } + /* if no country code matched return first universal code from translate_custom_table */ + memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = translate_custom_table[0].custom_locale_rev; + return; +#endif /* 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))) */ +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h new file mode 100644 index 000000000000..796d5598acd1 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h @@ -0,0 +1,126 @@ +/* + * Debug/trace/assert driver definitions for Dongle Host Driver. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_dbg.h 516345 2014-11-19 11:58:57Z $ + */ + +#ifndef _dhd_dbg_ +#define _dhd_dbg_ + +#define USE_NET_RATELIMIT 1 + +#if defined(DHD_DEBUG) + +#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && USE_NET_RATELIMIT) \ + printf args;} while (0) +#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) +#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) +#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) +#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0) +#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0) +#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0) +#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0) +#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0) +#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) +#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) +#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0) +#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) +#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) +#define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) +#define DHD_PNO(args) do {if (dhd_msg_level & DHD_PNO_VAL) printf args;} while (0) +#define DHD_RTT(args) do {if (dhd_msg_level & DHD_RTT_VAL) printf args;} while (0) + +#define DHD_TRACE_HW4 DHD_TRACE + +#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) +#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) +#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) +#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL) +#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL) +#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL) +#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL) +#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL) +#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL) +#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) +#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) +#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) +#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) +#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL) +#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL) +#define DHD_NOCHECKDIED_ON() (dhd_msg_level & DHD_NOCHECKDIED_VAL) +#define DHD_PNO_ON() (dhd_msg_level & DHD_PNO_VAL) +#define DHD_RTT_ON() (dhd_msg_level & DHD_RTT_VAL) + +#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ + +#define DHD_ERROR(args) do {if (USE_NET_RATELIMIT) printf args;} while (0) +#define DHD_TRACE(args) +#define DHD_INFO(args) +#define DHD_DATA(args) +#define DHD_CTL(args) +#define DHD_TIMER(args) +#define DHD_HDRS(args) +#define DHD_BYTES(args) +#define DHD_INTR(args) +#define DHD_GLOM(args) +#define DHD_EVENT(args) +#define DHD_BTA(args) +#define DHD_ISCAN(args) +#define DHD_ARPOE(args) +#define DHD_REORDER(args) +#define DHD_PNO(args) + +#define DHD_TRACE_HW4 DHD_TRACE + +#define DHD_ERROR_ON() 0 +#define DHD_TRACE_ON() 0 +#define DHD_INFO_ON() 0 +#define DHD_DATA_ON() 0 +#define DHD_CTL_ON() 0 +#define DHD_TIMER_ON() 0 +#define DHD_HDRS_ON() 0 +#define DHD_BYTES_ON() 0 +#define DHD_INTR_ON() 0 +#define DHD_GLOM_ON() 0 +#define DHD_EVENT_ON() 0 +#define DHD_BTA_ON() 0 +#define DHD_ISCAN_ON() 0 +#define DHD_ARPOE_ON() 0 +#define DHD_REORDER_ON() 0 +#define DHD_NOCHECKDIED_ON() 0 +#define DHD_PNO_ON() 0 +#define DHD_RTT_ON() 0 + +#endif + +#define DHD_LOG(args) + +#define DHD_BLOG(cp, size) + +#define DHD_NONE(args) +extern int dhd_msg_level; + +/* Defines msg bits */ +#include + +#endif /* _dhd_dbg_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c new file mode 100644 index 000000000000..b7760c5cd1bb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c @@ -0,0 +1,953 @@ +/* + * IP Packet Parser Module. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_ip.c 486237 2014-06-19 09:22:00Z $ + */ +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef DHDTCPACK_SUPPRESS +#include +#include +#endif /* DHDTCPACK_SUPPRESS */ + +/* special values */ +/* 802.3 llc/snap header */ +static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; + +pkt_frag_t pkt_frag_info(osl_t *osh, void *p) +{ + uint8 *frame; + int length; + uint8 *pt; /* Pointer to type field */ + uint16 ethertype; + struct ipv4_hdr *iph; /* IP frame pointer */ + int ipl; /* IP frame length */ + uint16 iph_frag; + + ASSERT(osh && p); + + frame = PKTDATA(osh, p); + length = PKTLEN(osh, p); + + /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ + if (length < ETHER_HDR_LEN) { + DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length)); + return DHD_PKT_FRAG_NONE; + } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { + /* Frame is Ethernet II */ + pt = frame + ETHER_TYPE_OFFSET; + } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && + !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { + pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; + } else { + DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__)); + return DHD_PKT_FRAG_NONE; + } + + ethertype = ntoh16(*(uint16 *)pt); + + /* Skip VLAN tag, if any */ + if (ethertype == ETHER_TYPE_8021Q) { + pt += VLAN_TAG_LEN; + + if (pt + ETHER_TYPE_LEN > frame + length) { + DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length)); + return DHD_PKT_FRAG_NONE; + } + + ethertype = ntoh16(*(uint16 *)pt); + } + + if (ethertype != ETHER_TYPE_IP) { + DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n", + __FUNCTION__, ethertype, length)); + return DHD_PKT_FRAG_NONE; + } + + iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); + ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame)); + + /* We support IPv4 only */ + if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) { + DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl)); + return DHD_PKT_FRAG_NONE; + } + + iph_frag = ntoh16(iph->frag); + + if (iph_frag & IPV4_FRAG_DONT) { + return DHD_PKT_FRAG_NONE; + } else if ((iph_frag & IPV4_FRAG_MORE) == 0) { + return DHD_PKT_FRAG_LAST; + } else { + return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST; + } +} + +#ifdef DHDTCPACK_SUPPRESS + +typedef struct { + void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */ + void *pkt_ether_hdr; /* Ethernet header pointer of pkt_in_q */ +} tcpack_info_t; + +typedef struct _tdata_psh_info_t { + uint32 end_seq; /* end seq# of a received TCP PSH DATA pkt */ + struct _tdata_psh_info_t *next; /* next pointer of the link chain */ +} tdata_psh_info_t; + +typedef struct { + uint8 src_ip_addr[IPV4_ADDR_LEN]; /* SRC ip addrs of this TCP stream */ + uint8 dst_ip_addr[IPV4_ADDR_LEN]; /* DST ip addrs of this TCP stream */ + uint8 src_tcp_port[TCP_PORT_LEN]; /* SRC tcp ports of this TCP stream */ + uint8 dst_tcp_port[TCP_PORT_LEN]; /* DST tcp ports of this TCP stream */ + tdata_psh_info_t *tdata_psh_info_head; /* Head of received TCP PSH DATA chain */ + tdata_psh_info_t *tdata_psh_info_tail; /* Tail of received TCP PSH DATA chain */ + uint32 last_used_time; /* The last time this tcpdata_info was used(in ms) */ +} tcpdata_info_t; + +/* TCPACK SUPPRESS module */ +typedef struct { + int tcpack_info_cnt; + tcpack_info_t tcpack_info_tbl[TCPACK_INFO_MAXNUM]; /* Info of TCP ACK to send */ + int tcpdata_info_cnt; + tcpdata_info_t tcpdata_info_tbl[TCPDATA_INFO_MAXNUM]; /* Info of received TCP DATA */ + tdata_psh_info_t *tdata_psh_info_pool; /* Pointer to tdata_psh_info elements pool */ + tdata_psh_info_t *tdata_psh_info_free; /* free tdata_psh_info elements chain in pool */ +#ifdef DHDTCPACK_SUP_DBG + int psh_info_enq_num; /* Number of free TCP PSH DATA info elements in pool */ +#endif /* DHDTCPACK_SUP_DBG */ +} tcpack_sup_module_t; + +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) +counter_tbl_t tack_tbl = {"tcpACK", 0, 1000, 10, {0, }, 1}; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + +static void +_tdata_psh_info_pool_enq(tcpack_sup_module_t *tcpack_sup_mod, + tdata_psh_info_t *tdata_psh_info) +{ + if ((tcpack_sup_mod == NULL) || (tdata_psh_info == NULL)) { + DHD_ERROR(("%s %d: ERROR %p %p\n", __FUNCTION__, __LINE__, + tcpack_sup_mod, tdata_psh_info)); + return; + } + + ASSERT(tdata_psh_info->next == NULL); + tdata_psh_info->next = tcpack_sup_mod->tdata_psh_info_free; + tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info; +#ifdef DHDTCPACK_SUP_DBG + tcpack_sup_mod->psh_info_enq_num++; +#endif +} + +static tdata_psh_info_t* +_tdata_psh_info_pool_deq(tcpack_sup_module_t *tcpack_sup_mod) +{ + tdata_psh_info_t *tdata_psh_info = NULL; + + if (tcpack_sup_mod == NULL) { + DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__, __LINE__, + tcpack_sup_mod)); + return NULL; + } + + tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free; + if (tdata_psh_info == NULL) + DHD_ERROR(("%s %d: Out of tdata_disc_grp\n", __FUNCTION__, __LINE__)); + else { + tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; + tdata_psh_info->next = NULL; +#ifdef DHDTCPACK_SUP_DBG + tcpack_sup_mod->psh_info_enq_num--; +#endif /* DHDTCPACK_SUP_DBG */ + } + + return tdata_psh_info; +} + +static int _tdata_psh_info_pool_init(dhd_pub_t *dhdp, + tcpack_sup_module_t *tcpack_sup_mod) +{ + tdata_psh_info_t *tdata_psh_info_pool = NULL; + uint i; + + DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); + + if (tcpack_sup_mod == NULL) + return BCME_ERROR; + + ASSERT(tcpack_sup_mod->tdata_psh_info_pool == NULL); + ASSERT(tcpack_sup_mod->tdata_psh_info_free == NULL); + + tdata_psh_info_pool = + MALLOC(dhdp->osh, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); + + if (tdata_psh_info_pool == NULL) + return BCME_NOMEM; + bzero(tdata_psh_info_pool, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); +#ifdef DHDTCPACK_SUP_DBG + tcpack_sup_mod->psh_info_enq_num = 0; +#endif /* DHDTCPACK_SUP_DBG */ + + /* Enqueue newly allocated tcpdata psh info elements to the pool */ + for (i = 0; i < TCPDATA_PSH_INFO_MAXNUM; i++) + _tdata_psh_info_pool_enq(tcpack_sup_mod, &tdata_psh_info_pool[i]); + + ASSERT(tcpack_sup_mod->tdata_psh_info_free != NULL); + tcpack_sup_mod->tdata_psh_info_pool = tdata_psh_info_pool; + + return BCME_OK; +} + +static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp, + tcpack_sup_module_t *tcpack_sup_mod) +{ + uint i; + tdata_psh_info_t *tdata_psh_info; + + DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); + + if (tcpack_sup_mod == NULL) { + DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n", + __FUNCTION__, __LINE__)); + return; + } + + for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { + tcpdata_info_t *tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; + /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */ + while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { + tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; + tdata_psh_info->next = NULL; + _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); + } + tcpdata_info->tdata_psh_info_tail = NULL; + } +#ifdef DHDTCPACK_SUP_DBG + DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); +#endif /* DHDTCPACK_SUP_DBG */ + + i = 0; + /* Be sure we recollected all tdata_psh_info elements */ + while ((tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free)) { + tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; + tdata_psh_info->next = NULL; + i++; + } + ASSERT(i == TCPDATA_PSH_INFO_MAXNUM); + MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool, + sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); + tcpack_sup_mod->tdata_psh_info_pool = NULL; + + return; +} + +int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode) +{ + int ret = BCME_OK; + + dhd_os_tcpacklock(dhdp); + + if (dhdp->tcpack_sup_mode == mode) { + DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode)); + goto exit; + } + + if (mode > TCPACK_SUP_DELAYTX) { + DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__, __LINE__, mode)); + ret = BCME_BADARG; + goto exit; + } + + DHD_TRACE(("%s: %d -> %d\n", + __FUNCTION__, dhdp->tcpack_sup_mode, mode)); + + /* Old tcpack_sup_mode is TCPACK_SUP_DELAYTX */ + if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX) { + tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; + /* We won't need tdata_psh_info pool and tcpddata_info_tbl anymore */ + _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_mod); + tcpack_sup_mod->tcpdata_info_cnt = 0; + bzero(tcpack_sup_mod->tcpdata_info_tbl, + sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM); + /* For half duplex bus interface, tx precedes rx by default */ + if (dhdp->bus) + dhd_bus_set_dotxinrx(dhdp->bus, TRUE); + } + + dhdp->tcpack_sup_mode = mode; + + if (mode == TCPACK_SUP_OFF) { + ASSERT(dhdp->tcpack_sup_module != NULL); + MFREE(dhdp->osh, dhdp->tcpack_sup_module, sizeof(tcpack_sup_module_t)); + dhdp->tcpack_sup_module = NULL; + goto exit; + } + + if (dhdp->tcpack_sup_module == NULL) { + tcpack_sup_module_t *tcpack_sup_mod = + MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t)); + if (tcpack_sup_mod == NULL) { + DHD_ERROR(("%s %d: No MEM\n", __FUNCTION__, __LINE__)); + dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; + ret = BCME_NOMEM; + goto exit; + } + bzero(tcpack_sup_mod, sizeof(tcpack_sup_module_t)); + dhdp->tcpack_sup_module = tcpack_sup_mod; + } + + if (mode == TCPACK_SUP_DELAYTX) { + ret = _tdata_psh_info_pool_init(dhdp, dhdp->tcpack_sup_module); + if (ret != BCME_OK) + DHD_ERROR(("%s %d: pool init fail with %d\n", __FUNCTION__, __LINE__, ret)); + else if (dhdp->bus) + dhd_bus_set_dotxinrx(dhdp->bus, FALSE); + } + +exit: + dhd_os_tcpackunlock(dhdp); + return ret; +} + +void +dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp) +{ + tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; + + if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) + goto exit; + + dhd_os_tcpacklock(dhdp); + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", + __FUNCTION__, __LINE__)); + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + tcpack_sup_mod->tcpack_info_cnt = 0; + bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM); + dhd_os_tcpackunlock(dhdp); + +exit: + return; +} + +inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt) +{ + uint8 i; + tcpack_sup_module_t *tcpack_sup_mod; + tcpack_info_t *tcpack_info_tbl; + int tbl_cnt; + uint pushed_len; + int ret = BCME_OK; + void *pdata; + uint32 pktlen; + + if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) + goto exit; + + pdata = PKTDATA(dhdp->osh, pkt); + + /* Length of BDC(+WLFC) headers pushed */ + pushed_len = BDC_HEADER_LEN + (((struct bdc_header *)pdata)->dataOffset * 4); + pktlen = PKTLEN(dhdp->osh, pkt) - pushed_len; + + if (pktlen < TCPACKSZMIN || pktlen > TCPACKSZMAX) { + DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", + __FUNCTION__, __LINE__, pktlen)); + goto exit; + } + + dhd_os_tcpacklock(dhdp); + tcpack_sup_mod = dhdp->tcpack_sup_module; + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); + ret = BCME_ERROR; + dhd_os_tcpackunlock(dhdp); + goto exit; + } + tbl_cnt = tcpack_sup_mod->tcpack_info_cnt; + tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; + + ASSERT(tbl_cnt <= TCPACK_INFO_MAXNUM); + + for (i = 0; i < tbl_cnt; i++) { + if (tcpack_info_tbl[i].pkt_in_q == pkt) { + DHD_TRACE(("%s %d: pkt %p sent out. idx %d, tbl_cnt %d\n", + __FUNCTION__, __LINE__, pkt, i, tbl_cnt)); + /* This pkt is being transmitted so remove the tcp_ack_info of it. */ + if (i < tbl_cnt - 1) { + bcopy(&tcpack_info_tbl[tbl_cnt - 1], + &tcpack_info_tbl[i], sizeof(tcpack_info_t)); + } + bzero(&tcpack_info_tbl[tbl_cnt - 1], sizeof(tcpack_info_t)); + if (--tcpack_sup_mod->tcpack_info_cnt < 0) { + DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); + ret = BCME_ERROR; + } + break; + } + } + dhd_os_tcpackunlock(dhdp); + +exit: + return ret; +} + +static INLINE bool dhd_tcpdata_psh_acked(dhd_pub_t *dhdp, uint8 *ip_hdr, + uint8 *tcp_hdr, uint32 tcp_ack_num) +{ + tcpack_sup_module_t *tcpack_sup_mod; + int i; + tcpdata_info_t *tcpdata_info = NULL; + tdata_psh_info_t *tdata_psh_info = NULL; + bool ret = FALSE; + + if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) + goto exit; + + tcpack_sup_mod = dhdp->tcpack_sup_module; + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); + goto exit; + } + + DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d, ack %u\n", __FUNCTION__, __LINE__, + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), + tcp_ack_num)); + + for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { + tcpdata_info_t *tcpdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; + DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d\n", __FUNCTION__, __LINE__, i, + IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->src_ip_addr)), + IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->dst_ip_addr)), + ntoh16_ua(tcpdata_info_tmp->src_tcp_port), + ntoh16_ua(tcpdata_info_tmp->dst_tcp_port))); + + /* If either IP address or TCP port number does not match, skip. */ + if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], + tcpdata_info_tmp->dst_ip_addr, IPV4_ADDR_LEN) == 0 && + memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET], + tcpdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN) == 0 && + memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], + tcpdata_info_tmp->dst_tcp_port, TCP_PORT_LEN) == 0 && + memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET], + tcpdata_info_tmp->src_tcp_port, TCP_PORT_LEN) == 0) { + tcpdata_info = tcpdata_info_tmp; + break; + } + } + + if (tcpdata_info == NULL) { + DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__, __LINE__)); + goto exit; + } + + if (tcpdata_info->tdata_psh_info_head == NULL) { + DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__, __LINE__)); + } + + while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { + if (IS_TCPSEQ_GE(tcp_ack_num, tdata_psh_info->end_seq)) { + DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n", + __FUNCTION__, __LINE__, tcp_ack_num, tdata_psh_info->end_seq)); + tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; + tdata_psh_info->next = NULL; + _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); + ret = TRUE; + } else + break; + } + if (tdata_psh_info == NULL) + tcpdata_info->tdata_psh_info_tail = NULL; + +#ifdef DHDTCPACK_SUP_DBG + DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); +#endif /* DHDTCPACK_SUP_DBG */ + +exit: + return ret; +} + +bool +dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt) +{ + uint8 *new_ether_hdr; /* Ethernet header of the new packet */ + uint16 new_ether_type; /* Ethernet type of the new packet */ + uint8 *new_ip_hdr; /* IP header of the new packet */ + uint8 *new_tcp_hdr; /* TCP header of the new packet */ + uint32 new_ip_hdr_len; /* IP header length of the new packet */ + uint32 cur_framelen; + uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ + uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ + uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ + tcpack_sup_module_t *tcpack_sup_mod; + tcpack_info_t *tcpack_info_tbl; + int i; + bool ret = FALSE; + bool set_dotxinrx = TRUE; + + if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) + goto exit; + + new_ether_hdr = PKTDATA(dhdp->osh, pkt); + cur_framelen = PKTLEN(dhdp->osh, pkt); + + if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { + DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", + __FUNCTION__, __LINE__, cur_framelen)); + goto exit; + } + + new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; + + if (new_ether_type != ETHER_TYPE_IP) { + DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", + __FUNCTION__, __LINE__, new_ether_type)); + goto exit; + } + + DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); + + new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; + cur_framelen -= ETHER_HDR_LEN; + + ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); + + new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); + if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { + DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", + __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); + goto exit; + } + + new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; + cur_framelen -= new_ip_hdr_len; + + ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); + + DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); + + /* is it an ack ? Allow only ACK flag, not to suppress others. */ + if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { + DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", + __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); + goto exit; + } + + new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); + new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); + + /* This packet has TCP data, so just send */ + if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { + DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); + goto exit; + } + + ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); + + new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); + + DHD_TRACE(("%s %d: TCP ACK with zero DATA length" + " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", + __FUNCTION__, __LINE__, + IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); + + /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ + dhd_os_tcpacklock(dhdp); +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + counter_printlog(&tack_tbl); + tack_tbl.cnt[0]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + + tcpack_sup_mod = dhdp->tcpack_sup_module; + tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); + ret = BCME_ERROR; + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + if (dhd_tcpdata_psh_acked(dhdp, new_ip_hdr, new_tcp_hdr, new_tcp_ack_num)) { + /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */ +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[5]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + } else + set_dotxinrx = FALSE; + + for (i = 0; i < tcpack_sup_mod->tcpack_info_cnt; i++) { + void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ + uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; + uint32 old_ip_hdr_len, old_tcp_hdr_len; + uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ + + if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { + DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n", + __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); + break; + } + + if (PKTDATA(dhdp->osh, oldpkt) == NULL) { + DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n", + __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); + break; + } + + old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; + old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; + old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); + old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; + old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); + + DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, + IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); + + /* If either of IP address or TCP port number does not match, skip. */ + if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], + &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || + memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], + &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) + continue; + + old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); + + if (IS_TCPSEQ_GT(new_tcp_ack_num, old_tcpack_num)) { + /* New packet has higher TCP ACK number, so it replaces the old packet */ + if (new_ip_hdr_len == old_ip_hdr_len && + new_tcp_hdr_len == old_tcp_hdr_len) { + ASSERT(memcmp(new_ether_hdr, old_ether_hdr, ETHER_HDR_LEN) == 0); + bcopy(new_ip_hdr, old_ip_hdr, new_ip_total_len); + PKTFREE(dhdp->osh, pkt, FALSE); + DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n", + __FUNCTION__, __LINE__, old_tcpack_num, new_tcp_ack_num)); +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[2]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + ret = TRUE; + } else + DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d\n", + __FUNCTION__, __LINE__, new_ip_hdr_len, old_ip_hdr_len, + new_tcp_hdr_len, old_tcp_hdr_len)); + } else if (new_tcp_ack_num == old_tcpack_num) { + set_dotxinrx = TRUE; + /* TCPACK retransmission */ +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[3]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + } else { + DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n", + __FUNCTION__, __LINE__, old_tcpack_num, oldpkt, + new_tcp_ack_num, pkt)); + } + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + if (i == tcpack_sup_mod->tcpack_info_cnt && i < TCPACK_INFO_MAXNUM) { + /* No TCPACK packet with the same IP addr and TCP port is found + * in tcp_ack_info_tbl. So add this packet to the table. + */ + DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", + __FUNCTION__, __LINE__, pkt, new_ether_hdr, + tcpack_sup_mod->tcpack_info_cnt)); + + tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_in_q = pkt; + tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_ether_hdr = new_ether_hdr; + tcpack_sup_mod->tcpack_info_cnt++; +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[1]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + } else { + ASSERT(i == tcpack_sup_mod->tcpack_info_cnt); + DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", + __FUNCTION__, __LINE__)); + } + dhd_os_tcpackunlock(dhdp); + +exit: + /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */ + if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX && set_dotxinrx) + dhd_bus_set_dotxinrx(dhdp->bus, TRUE); + + return ret; +} + +bool +dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt) +{ + uint8 *ether_hdr; /* Ethernet header of the new packet */ + uint16 ether_type; /* Ethernet type of the new packet */ + uint8 *ip_hdr; /* IP header of the new packet */ + uint8 *tcp_hdr; /* TCP header of the new packet */ + uint32 ip_hdr_len; /* IP header length of the new packet */ + uint32 cur_framelen; + uint16 ip_total_len; /* Total length of IP packet for the new packet */ + uint32 tcp_hdr_len; /* TCP header length of the new packet */ + uint32 tcp_seq_num; /* TCP sequence number of the new packet */ + uint16 tcp_data_len; /* TCP DATA length that excludes IP and TCP headers */ + uint32 end_tcp_seq_num; /* TCP seq number of the last byte in the new packet */ + tcpack_sup_module_t *tcpack_sup_mod; + tcpdata_info_t *tcpdata_info = NULL; + tdata_psh_info_t *tdata_psh_info; + + int i; + bool ret = FALSE; + + if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) + goto exit; + + ether_hdr = PKTDATA(dhdp->osh, pkt); + cur_framelen = PKTLEN(dhdp->osh, pkt); + + ether_type = ether_hdr[12] << 8 | ether_hdr[13]; + + if (ether_type != ETHER_TYPE_IP) { + DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", + __FUNCTION__, __LINE__, ether_type)); + goto exit; + } + + DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, ether_type)); + + ip_hdr = ether_hdr + ETHER_HDR_LEN; + cur_framelen -= ETHER_HDR_LEN; + + ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); + + ip_hdr_len = IPV4_HLEN(ip_hdr); + if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { + DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", + __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr))); + goto exit; + } + + tcp_hdr = ip_hdr + ip_hdr_len; + cur_framelen -= ip_hdr_len; + + ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); + + DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); + + ip_total_len = ntoh16_ua(&ip_hdr[IPV4_PKTLEN_OFFSET]); + tcp_hdr_len = 4 * TCP_HDRLEN(tcp_hdr[TCP_HLEN_OFFSET]); + + /* This packet is mere TCP ACK, so do nothing */ + if (ip_total_len == ip_hdr_len + tcp_hdr_len) { + DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__, __LINE__)); + goto exit; + } + + ASSERT(ip_total_len > ip_hdr_len + tcp_hdr_len); + + if ((tcp_hdr[TCP_FLAGS_OFFSET] & TCP_FLAG_PSH) == 0) { + DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__, __LINE__)); + goto exit; + } + + DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length" + " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d, flag 0x%x\n", + __FUNCTION__, __LINE__, + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), + tcp_hdr[TCP_FLAGS_OFFSET])); + + dhd_os_tcpacklock(dhdp); + tcpack_sup_mod = dhdp->tcpack_sup_module; + + if (!tcpack_sup_mod) { + DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); + ret = BCME_ERROR; + dhd_os_tcpackunlock(dhdp); + goto exit; + } + + /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */ + i = 0; + while (i < tcpack_sup_mod->tcpdata_info_cnt) { + tcpdata_info_t *tdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; + uint32 now_in_ms = OSL_SYSUPTIME(); + DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d\n", __FUNCTION__, __LINE__, i, + IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->src_ip_addr)), + IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->dst_ip_addr)), + ntoh16_ua(tdata_info_tmp->src_tcp_port), + ntoh16_ua(tdata_info_tmp->dst_tcp_port))); + + /* If both IP address and TCP port number match, we found it so break. */ + if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], + (void *)tdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN * 2) == 0 && + memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], + (void *)tdata_info_tmp->src_tcp_port, TCP_PORT_LEN * 2) == 0) { + tcpdata_info = tdata_info_tmp; + tcpdata_info->last_used_time = now_in_ms; + break; + } + + if (now_in_ms - tdata_info_tmp->last_used_time > TCPDATA_INFO_TIMEOUT) { + tdata_psh_info_t *tdata_psh_info_tmp; + tcpdata_info_t *last_tdata_info; + + while ((tdata_psh_info_tmp = tdata_info_tmp->tdata_psh_info_head)) { + tdata_info_tmp->tdata_psh_info_head = tdata_psh_info_tmp->next; + tdata_psh_info_tmp->next = NULL; + DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n", + __FUNCTION__, __LINE__, tdata_psh_info_tmp->end_seq)); + _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info_tmp); + } +#ifdef DHDTCPACK_SUP_DBG + DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); +#endif /* DHDTCPACK_SUP_DBG */ + tcpack_sup_mod->tcpdata_info_cnt--; + ASSERT(tcpack_sup_mod->tcpdata_info_cnt >= 0); + + last_tdata_info = + &tcpack_sup_mod->tcpdata_info_tbl[tcpack_sup_mod->tcpdata_info_cnt]; + if (i < tcpack_sup_mod->tcpdata_info_cnt) { + ASSERT(last_tdata_info != tdata_info_tmp); + bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t)); + } + bzero(last_tdata_info, sizeof(tcpdata_info_t)); + DHD_ERROR(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n", + __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt)); + /* Don't increase "i" here, so that the prev last tcpdata_info is checked */ + } else + i++; + } + + tcp_seq_num = ntoh32_ua(&tcp_hdr[TCP_SEQ_NUM_OFFSET]); + tcp_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len; + end_tcp_seq_num = tcp_seq_num + tcp_data_len; + + if (tcpdata_info == NULL) { + ASSERT(i == tcpack_sup_mod->tcpdata_info_cnt); + if (i >= TCPDATA_INFO_MAXNUM) { + DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d" + " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", + __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt, + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); + dhd_os_tcpackunlock(dhdp); + goto exit; + } + tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; + + /* No TCP flow with the same IP addr and TCP port is found + * in tcp_data_info_tbl. So add this flow to the table. + */ + DHD_ERROR(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR + " TCP port %d %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt, + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), + IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), + ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), + ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); + + bcopy(&ip_hdr[IPV4_SRC_IP_OFFSET], (void *)tcpdata_info->src_ip_addr, + IPV4_ADDR_LEN * 2); + bcopy(&tcp_hdr[TCP_SRC_PORT_OFFSET], (void *)tcpdata_info->src_tcp_port, + TCP_PORT_LEN * 2); + + tcpdata_info->last_used_time = OSL_SYSUPTIME(); + tcpack_sup_mod->tcpdata_info_cnt++; + } + + ASSERT(tcpdata_info != NULL); + + tdata_psh_info = _tdata_psh_info_pool_deq(tcpack_sup_mod); +#ifdef DHDTCPACK_SUP_DBG + DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", + __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); +#endif /* DHDTCPACK_SUP_DBG */ + + if (tdata_psh_info == NULL) { + DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__, __LINE__)); + ret = BCME_ERROR; + dhd_os_tcpackunlock(dhdp); + goto exit; + } + tdata_psh_info->end_seq = end_tcp_seq_num; + +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) + tack_tbl.cnt[4]++; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ + + DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n", + __FUNCTION__, __LINE__, tdata_psh_info->end_seq)); + + ASSERT(tdata_psh_info->next == NULL); + + if (tcpdata_info->tdata_psh_info_head == NULL) + tcpdata_info->tdata_psh_info_head = tdata_psh_info; + else { + ASSERT(tcpdata_info->tdata_psh_info_tail); + tcpdata_info->tdata_psh_info_tail->next = tdata_psh_info; + } + tcpdata_info->tdata_psh_info_tail = tdata_psh_info; + + dhd_os_tcpackunlock(dhdp); + +exit: + return ret; +} + +#endif /* DHDTCPACK_SUPPRESS */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h new file mode 100644 index 000000000000..08765033c0be --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h @@ -0,0 +1,71 @@ +/* + * Header file describing the common ip parser function. + * + * Provides type definitions and function prototypes used to parse ip packet. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_ip.h 457888 2014-02-25 03:34:39Z $ + */ + +#ifndef _dhd_ip_h_ +#define _dhd_ip_h_ + +#ifdef DHDTCPACK_SUPPRESS +#include +#include +#include +#endif /* DHDTCPACK_SUPPRESS */ + +typedef enum pkt_frag +{ + DHD_PKT_FRAG_NONE = 0, + DHD_PKT_FRAG_FIRST, + DHD_PKT_FRAG_CONT, + DHD_PKT_FRAG_LAST +} pkt_frag_t; + +extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p); + +#ifdef DHDTCPACK_SUPPRESS +#define TCPACKSZMIN (ETHER_HDR_LEN + IPV4_MIN_HEADER_LEN + TCP_MIN_HEADER_LEN) +/* Size of MAX possible TCP ACK packet. Extra bytes for IP/TCP option fields */ +#define TCPACKSZMAX (TCPACKSZMIN + 100) + +/* Max number of TCP streams that have own src/dst IP addrs and TCP ports */ +#define TCPACK_INFO_MAXNUM 4 +#define TCPDATA_INFO_MAXNUM 4 +#define TCPDATA_PSH_INFO_MAXNUM (8 * TCPDATA_INFO_MAXNUM) + +#define TCPDATA_INFO_TIMEOUT 5000 /* Remove tcpdata_info if inactive for this time (in ms) */ + +extern int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 on); +extern void dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp); +extern int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt); +extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt); +extern bool dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt); + +#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) +extern counter_tbl_t tack_tbl; +#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ +#endif /* DHDTCPACK_SUPPRESS */ + +#endif /* _dhd_ip_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c new file mode 100644 index 000000000000..b711dd781e9a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c @@ -0,0 +1,8412 @@ +/* + * Broadcom Dongle Host Driver (DHD), Linux-specific network interface + * Basically selected code segments from usb-cdc.c and usb-rndis.c + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux.c 701450 2017-05-25 02:10:23Z $ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_WAKELOCK +#include +#endif +#ifdef WL_CFG80211 +#include +#endif +#ifdef CUSTOM_COUNTRY_CODE +#include +#endif +#ifdef PNO_SUPPORT +#include +#endif +#ifdef RTT_SUPPORT +#include +#endif + +#ifdef CONFIG_COMPAT +#include +#endif + +#ifdef AMPDU_VO_ENABLE +#include +#endif /* AMPDU_VO_ENABLE */ +#ifdef DHDTCPACK_SUPPRESS +#include +#endif /* DHDTCPACK_SUPPRESS */ + + +#ifdef WLMEDIA_HTSF +#include +#include + +#define HTSF_MINLEN 200 /* min. packet length to timestamp */ +#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ +#define TSMAX 1000 /* max no. of timing record kept */ +#define NUMBIN 34 + +static uint32 tsidx = 0; +static uint32 htsf_seqnum = 0; +uint32 tsfsync; +struct timeval tsync; +static uint32 tsport = 5010; + +typedef struct histo_ { + uint32 bin[NUMBIN]; +} histo_t; + +#if !ISPOWEROF2(DHD_SDALIGN) +#error DHD_SDALIGN is not a power of 2! +#endif + +static histo_t vi_d1, vi_d2, vi_d3, vi_d4; +#endif /* WLMEDIA_HTSF */ + + + +#if defined(SOFTAP) +extern bool ap_cfg_running; +extern bool ap_fw_loaded; +#endif + + +#ifdef ENABLE_ADAPTIVE_SCHED +#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */ +#ifndef CUSTOM_CPUFREQ_THRESH +#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH +#endif /* CUSTOM_CPUFREQ_THRESH */ +#endif /* ENABLE_ADAPTIVE_SCHED */ + +/* enable HOSTIP cache update from the host side when an eth0:N is up */ +#define AOE_IP_ALIAS_SUPPORT 1 + +#ifdef BCM_FD_AGGR +#include +#include +#endif +#ifdef PROP_TXSTATUS +#include +#include +#endif + +#include + +#include + +#ifdef ARP_OFFLOAD_SUPPORT +void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); +static int dhd_inetaddr_notifier_call(struct notifier_block *this, + unsigned long event, void *ptr); +static struct notifier_block dhd_inetaddr_notifier = { + .notifier_call = dhd_inetaddr_notifier_call +}; +/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be + * created in kernel notifier link list (with 'next' pointing to itself) + */ +static bool dhd_inetaddr_notifier_registered = FALSE; +#endif /* ARP_OFFLOAD_SUPPORT */ + +static int dhd_inet6addr_notifier_call(struct notifier_block *this, + unsigned long event, void *ptr); +static struct notifier_block dhd_inet6addr_notifier = { + .notifier_call = dhd_inet6addr_notifier_call +}; +/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be + * created in kernel notifier link list (with 'next' pointing to itself) + */ +static bool dhd_inet6addr_notifier_registered = FALSE; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#include +volatile bool dhd_mmc_suspend = FALSE; +DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + +#if defined(OOB_INTR_ONLY) +extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +static void dhd_hang_process(void *dhd_info, void *event_data, u8 event); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +MODULE_LICENSE("GPL v2"); +#endif /* LinuxVer */ + +#include + +#ifdef BCM_FD_AGGR +#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) +#else +#ifndef PROP_TXSTATUS +#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) +#else +#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) +#endif +#endif /* BCM_FD_AGGR */ + +#ifdef PROP_TXSTATUS +extern bool dhd_wlfc_skip_fc(void); +extern void dhd_wlfc_plat_init(void *dhd); +extern void dhd_wlfc_plat_deinit(void *dhd); +#endif /* PROP_TXSTATUS */ + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) +const char * +print_tainted() +{ + return ""; +} +#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ + +/* Linux wireless extension support */ +#if defined(WL_WIRELESS_EXT) +#include +extern wl_iw_extra_params_t g_wl_iw_params; +#endif /* defined(WL_WIRELESS_EXT) */ + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) +#include +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ + +extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); + +#ifdef PKT_FILTER_SUPPORT +extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); +extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); +extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id); +#endif + + +#ifdef READ_MACADDR +extern int dhd_read_macaddr(struct dhd_info *dhd); +#else +static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; } +#endif +#ifdef WRITE_MACADDR +extern int dhd_write_macaddr(struct ether_addr *mac); +#else +static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; } +#endif + +#ifdef ENABLE_CONTROL_SCHED +#ifndef ENABLE_ADAPTIVE_SCHED +#error ENABLE_ADAPTIVE_SCHED not define. +#endif /* ENABLE_ADAPTIVE_SCHED */ +static int dhd_sysfs_create_node(struct net_device *net); +static void dhd_sysfs_destroy_node(struct net_device *net); +#endif /* ENABLE_CONTROL_SCHED */ + + + + +typedef struct dhd_if_event { + struct list_head list; + wl_event_data_if_t event; + char name[IFNAMSIZ+1]; + uint8 mac[ETHER_ADDR_LEN]; +} dhd_if_event_t; + +/* Interface control information */ +typedef struct dhd_if { + struct dhd_info *info; /* back pointer to dhd_info */ + /* OS/stack specifics */ + struct net_device *net; + struct net_device_stats stats; + int idx; /* iface idx in dongle */ + uint subunit; /* subunit */ + uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ + bool attached; /* Delayed attachment when unset */ + bool txflowcontrol; /* Per interface flow control indicator */ + char name[IFNAMSIZ+1]; /* linux interface name */ + uint8 bssidx; /* bsscfg index for the interface */ + bool set_macaddress; + bool set_multicast; +} dhd_if_t; + +#ifdef WLMEDIA_HTSF +typedef struct { + uint32 low; + uint32 high; +} tsf_t; + +typedef struct { + uint32 last_cycle; + uint32 last_sec; + uint32 last_tsf; + uint32 coef; /* scaling factor */ + uint32 coefdec1; /* first decimal */ + uint32 coefdec2; /* second decimal */ +} htsf_t; + +typedef struct { + uint32 t1; + uint32 t2; + uint32 t3; + uint32 t4; +} tstamp_t; + +static tstamp_t ts[TSMAX]; +static tstamp_t maxdelayts; +static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; + +#endif /* WLMEDIA_HTSF */ + +struct ipv6_work_info_t { + uint8 if_idx; + char ipv6_addr[16]; + unsigned long event; +}; + +#ifdef DHD_DEBUG +typedef struct dhd_dump { + uint8 *buf; + int bufsize; +} dhd_dump_t; +#endif /* DHD_DEBUG */ + +/* Local private structure (extension of pub) */ +typedef struct dhd_info { +#if defined(WL_WIRELESS_EXT) + wl_iw_t iw; /* wireless extensions state (must be first) */ +#endif /* defined(WL_WIRELESS_EXT) */ + + dhd_pub_t pub; + void *adapter; /* adapter information, interrupt, fw path etc. */ + char fw_path[PATH_MAX]; /* path to firmware image */ + char nv_path[PATH_MAX]; /* path to nvram vars file */ + + /* For supporting multiple interfaces */ + dhd_if_t *iflist[DHD_MAX_IFS]; + + struct semaphore proto_sem; +#ifdef PROP_TXSTATUS + spinlock_t wlfc_spinlock; + +#endif /* PROP_TXSTATUS */ +#ifdef WLMEDIA_HTSF + htsf_t htsf; +#endif + wait_queue_head_t ioctl_resp_wait; + uint32 default_wd_interval; + + struct timer_list timer; + bool wd_timer_valid; + struct tasklet_struct tasklet; + spinlock_t sdlock; + spinlock_t txqlock; + spinlock_t dhd_lock; + + struct semaphore sdsem; + tsk_ctl_t thr_dpc_ctl; + tsk_ctl_t thr_wdt_ctl; + + tsk_ctl_t thr_rxf_ctl; + spinlock_t rxf_lock; + bool rxthread_enabled; + + /* Wakelocks */ +#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + struct wake_lock wl_wifi; /* Wifi wakelock */ + struct wake_lock wl_rxwake; /* Wifi rx wakelock */ + struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */ + struct wake_lock wl_wdwake; /* Wifi wd wakelock */ +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + /* net_device interface lock, prevent race conditions among net_dev interface + * calls and wifi_on or wifi_off + */ + struct mutex dhd_net_if_mutex; + struct mutex dhd_suspend_mutex; +#endif + spinlock_t wakelock_spinlock; + uint32 wakelock_counter; + bool waive_wakelock; + uint32 wakelock_before_waive; + int wakelock_wd_counter; + int wakelock_rx_timeout_enable; + int wakelock_ctrl_timeout_enable; + + /* Thread to issue ioctl for multicast */ + wait_queue_head_t ctrl_wait; + atomic_t pend_8021x_cnt; + dhd_attach_states_t dhd_state; + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ + +#ifdef ARP_OFFLOAD_SUPPORT + u32 pend_ipaddr; +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef BCM_FD_AGGR + void *rpc_th; + void *rpc_osh; + struct timer_list rpcth_timer; + bool rpcth_timer_active; + bool fdaggr; +#endif +#ifdef DHDTCPACK_SUPPRESS + spinlock_t tcpack_lock; +#endif /* DHDTCPACK_SUPPRESS */ + void *dhd_deferred_wq; +#ifdef DEBUG_CPU_FREQ + struct notifier_block freq_trans; + int __percpu *new_freq; +#endif + unsigned int unit; + struct notifier_block pm_notifier; +#ifdef SAR_SUPPORT + struct notifier_block sar_notifier; +#endif +#ifdef DHD_DEBUG + dhd_dump_t *dump; + struct timer_list join_timer; + u32 join_timeout_val; + bool join_timer_active; + uint scan_time_count; + struct timer_list scan_timer; + bool scan_timer_active; +#endif /* DHD_DEBUG */ +} dhd_info_t; + +/* Flag to indicate if we should download firmware on driver load */ +uint dhd_download_fw_on_driverload = TRUE; + +/* Definitions to provide path to the firmware and nvram + * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" + */ +char firmware_path[MOD_PARAM_PATHLEN]; +char nvram_path[MOD_PARAM_PATHLEN]; + +/* information string to keep firmware, chio, cheip version info visiable from log */ +char info_string[MOD_PARAM_INFOLEN]; +module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); +#ifdef CONFIG_BCM_WLAN_RAMDUMP +char bcm_wlan_ver_info[BCM_WLAN_CRASH_REASON_LEN]; +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ +int op_mode = 0; +int disable_proptx = 0; +module_param(op_mode, int, 0644); +extern int wl_control_wl_start(struct net_device *dev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC) +struct semaphore dhd_registration_sem; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + +/* deferred handlers */ +static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event); +static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event); +static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event); +static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event); +static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event); + +#ifdef WL_CFG80211 +extern void dhd_netdev_free(struct net_device *ndev); +#endif /* WL_CFG80211 */ + +/* Error bits */ +module_param(dhd_msg_level, int, 0); + +#ifdef ARP_OFFLOAD_SUPPORT +/* ARP offload enable */ +uint dhd_arp_enable = TRUE; +module_param(dhd_arp_enable, uint, 0); + +/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ + +uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; + +module_param(dhd_arp_mode, uint, 0); +#endif /* ARP_OFFLOAD_SUPPORT */ + +/* Disable Prop tx */ +module_param(disable_proptx, int, 0644); +/* load firmware and/or nvram values from the filesystem */ +module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); +module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660); + +/* Disable VHT(11ac) mode */ +#if !defined(DISABLE_11AC) +int somc_disable_vht = 0; +module_param(somc_disable_vht, int, 0660); +#endif /* ! DISABLE_11AC */ + +/* Watchdog interval */ + +/* extend watchdog expiration to 2 seconds when DPC is running */ +#define WATCHDOG_EXTEND_INTERVAL (2000) + +uint dhd_watchdog_ms = 10; +module_param(dhd_watchdog_ms, uint, 0); + +#if defined(DHD_DEBUG) +/* Console poll interval */ +uint dhd_console_ms = 0; +module_param(dhd_console_ms, uint, 0644); +#endif /* defined(DHD_DEBUG) */ + + +uint dhd_slpauto = TRUE; +module_param(dhd_slpauto, uint, 0); + +#ifdef PKT_FILTER_SUPPORT +/* Global Pkt filter enable control */ +uint dhd_pkt_filter_enable = TRUE; +module_param(dhd_pkt_filter_enable, uint, 0); +#endif + +/* Pkt filter init setup */ +uint dhd_pkt_filter_init = 0; +module_param(dhd_pkt_filter_init, uint, 0); + +/* Pkt filter mode control */ +uint dhd_master_mode = TRUE; +module_param(dhd_master_mode, uint, 0); + +int dhd_watchdog_prio = 0; +module_param(dhd_watchdog_prio, int, 0); + +/* DPC thread priority */ +int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; +module_param(dhd_dpc_prio, int, 0); + +/* RX frame thread priority */ +int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; +module_param(dhd_rxf_prio, int, 0); + +#if !defined(BCMDHDUSB) +extern int dhd_dongle_ramsize; +module_param(dhd_dongle_ramsize, int, 0); +#endif /* BCMDHDUSB */ + +/* Keep track of number of instances */ +static int dhd_found = 0; +static int instance_base = 0; /* Starting instance number */ +module_param(instance_base, int, 0644); + +/* Control fw roaming */ +#ifdef BCMCCX +uint dhd_roam_disable = 0; +#else +uint dhd_roam_disable = 0; +#endif /* BCMCCX */ + +/* Control radio state */ +uint dhd_radio_up = 1; + +/* Network inteface name */ +char iface_name[IFNAMSIZ] = {'\0'}; +module_param_string(iface_name, iface_name, IFNAMSIZ, 0); + +/* The following are specific to the SDIO dongle */ + +/* IOCTL response timeout */ +int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; + +/* Idle timeout for backplane clock */ +int dhd_idletime = DHD_IDLETIME_TICKS; +module_param(dhd_idletime, int, 0); + +/* Use polling */ +uint dhd_poll = FALSE; +module_param(dhd_poll, uint, 0); + +/* Use interrupts */ +uint dhd_intr = TRUE; +module_param(dhd_intr, uint, 0); + +/* SDIO Drive Strength (in milliamps) */ +uint dhd_sdiod_drive_strength = 6; +module_param(dhd_sdiod_drive_strength, uint, 0); + +/* Tx/Rx bounds */ +extern uint dhd_txbound; +extern uint dhd_rxbound; +module_param(dhd_txbound, uint, 0); +module_param(dhd_rxbound, uint, 0); + +/* Deferred transmits */ +extern uint dhd_deferred_tx; +module_param(dhd_deferred_tx, uint, 0); + +#ifdef BCMDBGFS +extern void dhd_dbg_init(dhd_pub_t *dhdp); +extern void dhd_dbg_remove(void); +#endif /* BCMDBGFS */ + + + +#ifdef SDTEST +/* Echo packet generator (pkts/s) */ +uint dhd_pktgen = 0; +module_param(dhd_pktgen, uint, 0); + +/* Echo packet len (0 => sawtooth, max 2040) */ +uint dhd_pktgen_len = 0; +module_param(dhd_pktgen_len, uint, 0); +#endif /* SDTEST */ + + +extern char dhd_version[]; + +int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); +static void dhd_net_if_lock_local(dhd_info_t *dhd); +static void dhd_net_if_unlock_local(dhd_info_t *dhd); +static void dhd_suspend_lock(dhd_pub_t *dhdp); +static void dhd_suspend_unlock(dhd_pub_t *dhdp); + +#ifdef WLMEDIA_HTSF +void htsf_update(dhd_info_t *dhd, void *data); +tsf_t prev_tsf, cur_tsf; + +uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); +static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); +static void dhd_dump_latency(void); +static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); +static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); +static void dhd_dump_htsfhisto(histo_t *his, char *s); +#endif /* WLMEDIA_HTSF */ + +/* Monitor interface */ +int dhd_monitor_init(void *dhd_pub); +int dhd_monitor_uninit(void); + + +#if defined(WL_WIRELESS_EXT) +struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); +#endif /* defined(WL_WIRELESS_EXT) */ + +static void dhd_dpc(ulong data); +/* forward decl */ +extern int dhd_wait_pend8021x(struct net_device *dev); +void dhd_os_wd_timer_extend(void *bus, bool extend); + +#ifdef TOE +#ifndef BDC +#error TOE requires BDC +#endif /* !BDC */ +static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); +static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); +#endif /* TOE */ + +static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, + wl_event_msg_t *event_ptr, void **data_ptr); +#if defined(SUPPORT_P2P_GO_PS) +#ifdef PROP_TXSTATUS +static int dhd_wakelock_waive(dhd_info_t *dhdinfo); +static int dhd_wakelock_restore(dhd_info_t *dhdinfo); +#endif +#endif /* defined(SUPPORT_P2P_GO_PS) */ + +#if defined(CONFIG_PM_SLEEP) +static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) +{ + int ret = NOTIFY_DONE; + bool suspend = FALSE; + dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier); + + BCM_REFERENCE(dhdinfo); + switch (action) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + suspend = TRUE; + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + suspend = FALSE; + break; + } + +#if defined(SUPPORT_P2P_GO_PS) +#ifdef PROP_TXSTATUS + if (suspend) { + dhd_wakelock_waive(dhdinfo); + dhd_wlfc_suspend(&dhdinfo->pub); + dhd_wakelock_restore(dhdinfo); + } else { + dhd_wlfc_resume(&dhdinfo->pub); + } + +#endif +#endif /* defined(SUPPORT_P2P_GO_PS) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(2, 6, 39)) + dhd_mmc_suspend = suspend; + smp_mb(); +#endif + return ret; +} + +/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be + * created in kernel notifier link list (with 'next' pointing to itself) + */ +static bool dhd_pm_notifier_registered = FALSE; + +extern int register_pm_notifier(struct notifier_block *nb); +extern int unregister_pm_notifier(struct notifier_block *nb); +#endif /* defined(CONFIG_PM_SLEEP) */ + +#ifdef SAR_SUPPORT +static int dhd_sar_callback(struct notifier_block *nfb, unsigned long action, void *ignored) +{ + dhd_info_t *dhd = (dhd_info_t*)container_of(nfb, struct dhd_info, sar_notifier); + s32 sar_enable; + int ret = 0; + + /* '1' means activate sarlimit and '0' means back to normal state (deactivate + * sarlimit) + */ + sar_enable = action ? 1 : 0; + + ret = dhd_iovar(dhd, 0, "sar_enable", (char *)&sar_enable, sizeof(sar_enable), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s wl sar_enable %d failed %d\n", __FUNCTION__, sar_enable, ret)); + + return NOTIFY_DONE; +} + +static bool dhd_sar_notifier_registered = FALSE; + +extern int register_notifier_by_sar(struct notifier_block *nb); +extern int unregister_notifier_by_sar(struct notifier_block *nb); +#endif /* defined(SAR_SUPPORT) */ + +/* Request scheduling of the bus rx frame */ +static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb); +static void dhd_os_rxflock(dhd_pub_t *pub); +static void dhd_os_rxfunlock(dhd_pub_t *pub); + +static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb) +{ + uint32 store_idx; + uint32 sent_idx; + + if (!skb) { + DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n")); + return BCME_ERROR; + } + + dhd_os_rxflock(dhdp); + store_idx = dhdp->store_idx; + sent_idx = dhdp->sent_idx; + if (dhdp->skbbuf[store_idx] != NULL) { + /* Make sure the previous packets are processed */ + dhd_os_rxfunlock(dhdp); +#ifdef RXF_DEQUEUE_ON_BUSY + DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", + skb, store_idx, sent_idx)); + return BCME_BUSY; +#else /* RXF_DEQUEUE_ON_BUSY */ + DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", + skb, store_idx, sent_idx)); + /* removed msleep here, should use wait_event_timeout if we + * want to give rx frame thread a chance to run + */ +#if defined(WAIT_DEQUEUE) + OSL_SLEEP(1); +#endif + return BCME_ERROR; +#endif /* RXF_DEQUEUE_ON_BUSY */ + } + DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n", + skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1))); + dhdp->skbbuf[store_idx] = skb; + dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1); + dhd_os_rxfunlock(dhdp); + + return BCME_OK; +} + +static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp) +{ + uint32 store_idx; + uint32 sent_idx; + void *skb; + + dhd_os_rxflock(dhdp); + + store_idx = dhdp->store_idx; + sent_idx = dhdp->sent_idx; + skb = dhdp->skbbuf[sent_idx]; + + if (skb == NULL) { + dhd_os_rxfunlock(dhdp); + DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n", + store_idx, sent_idx)); + return NULL; + } + + dhdp->skbbuf[sent_idx] = NULL; + dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1); + + DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n", + skb, sent_idx)); + + dhd_os_rxfunlock(dhdp); + + return skb; +} + +static int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + if (prepost) { /* pre process */ + dhd_read_macaddr(dhd); + } else { /* post process */ + dhd_write_macaddr(&dhd->pub.mac); + } + + return 0; +} + +#if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) +static bool +_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode) +{ + bool _apply = FALSE; + /* In case of IBSS mode, apply arp pkt filter */ + if (op_mode & DHD_FLAG_IBSS_MODE) { + _apply = TRUE; + goto exit; + } + /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */ + if ((dhd->arp_version == 1) && + (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { + _apply = TRUE; + goto exit; + } + +exit: + return _apply; +} +#endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */ + +void dhd_set_packet_filter(dhd_pub_t *dhd) +{ +#ifdef PKT_FILTER_SUPPORT + int i; + + DHD_TRACE(("%s: enter\n", __FUNCTION__)); + if (dhd_pkt_filter_enable) { + for (i = 0; i < dhd->pktfilter_count; i++) { + dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); + } + } +#endif /* PKT_FILTER_SUPPORT */ +} + +void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) +{ +#ifdef PKT_FILTER_SUPPORT + int i; + + DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value)); + /* 1 - Enable packet filter, only allow unicast packet to send up */ + /* 0 - Disable packet filter */ + if (dhd_pkt_filter_enable && (!value || + (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) + { + for (i = 0; i < dhd->pktfilter_count; i++) { +#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER + if (value && (i == DHD_ARP_FILTER_NUM) && + !_turn_on_arp_filter(dhd, dhd->op_mode)) { + DHD_TRACE(("Do not turn on ARP white list pkt filter:" + "val %d, cnt %d, op_mode 0x%x\n", + value, i, dhd->op_mode)); + continue; + } +#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ + dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], + value, dhd_master_mode); + } + } +#endif /* PKT_FILTER_SUPPORT */ +} + +static int dhd_set_suspend(int value, dhd_pub_t *dhd) +{ +#ifndef SUPPORT_PM2_ONLY + int power_mode = PM_MAX; +#endif /* SUPPORT_PM2_ONLY */ + /* wl_pkt_filter_enable_t enable_parm; */ + int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ +#ifndef ENABLE_FW_ROAM_SUSPEND + uint roamvar = 1; +#endif /* ENABLE_FW_ROAM_SUSPEND */ + uint nd_ra_filter = 0; + int ret = 0; + +#ifdef DYNAMIC_SWOOB_DURATION +#ifndef CUSTOM_INTR_WIDTH +#define CUSTOM_INTR_WIDTH 100 +#endif /* CUSTOM_INTR_WIDTH */ + int intr_width = 0; +#endif /* DYNAMIC_SWOOB_DURATION */ + if (!dhd) + return -ENODEV; + + DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", + __FUNCTION__, value, dhd->in_suspend)); + + dhd_suspend_lock(dhd); + + if (dhd->up) { + if (value && dhd->in_suspend) { +#ifdef PKT_FILTER_SUPPORT + dhd->early_suspended = 1; +#endif + /* Kernel suspended */ + DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); + +#ifndef SUPPORT_PM2_ONLY + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); +#endif /* SUPPORT_PM2_ONLY */ + + /* Enable packet filter, only allow unicast packet to send up */ + dhd_enable_packet_filter(1, dhd); + + + /* If DTIM skip is set up as default, force it to wake + * each third DTIM for better power savings. Note that + * one side effect is a chance to miss BC/MC packet. + */ + bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); + + ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, + sizeof(bcn_li_dtim), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); + +#ifndef ENABLE_FW_ROAM_SUSPEND + /* Disable firmware roaming during suspend */ + dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, + sizeof(roamvar), NULL, 0, TRUE); +#endif /* ENABLE_FW_ROAM_SUSPEND */ + if (FW_SUPPORTED(dhd, ndoe)) { + /* enable IPv6 RA filter in firmware during suspend */ + nd_ra_filter = 1; + ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", + (char *)&nd_ra_filter, sizeof(nd_ra_filter), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("failed to set nd_ra_filter (%d)\n", + ret)); + } +#ifdef DYNAMIC_SWOOB_DURATION + intr_width = CUSTOM_INTR_WIDTH; + ret = dhd_iovar(dhd, 0, "bus:intr_width", (char *)&intr_width, + sizeof(intr_width), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("failed to set intr_width (%d)\n", ret)); + } +#endif /* DYNAMIC_SWOOB_DURATION */ + } else { +#ifdef PKT_FILTER_SUPPORT + dhd->early_suspended = 0; +#endif + /* Kernel resumed */ + DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__)); +#ifdef DYNAMIC_SWOOB_DURATION + intr_width = 0; + ret = dhd_iovar(dhd, 0, "bus:intr_width", (char *)&intr_width, + sizeof(intr_width), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("failed to set intr_width (%d)\n", ret)); + } +#endif /* DYNAMIC_SWOOB_DURATION */ + +#ifndef SUPPORT_PM2_ONLY + power_mode = PM_FAST; + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); +#endif /* SUPPORT_PM2_ONLY */ +#ifdef PKT_FILTER_SUPPORT + /* disable pkt filter */ + dhd_enable_packet_filter(0, dhd); +#endif /* PKT_FILTER_SUPPORT */ + + /* restore pre-suspend setting for dtim_skip */ + dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, + sizeof(bcn_li_dtim), NULL, 0, TRUE); +#ifndef ENABLE_FW_ROAM_SUSPEND + roamvar = dhd_roam_disable; + dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, + sizeof(roamvar), NULL, 0, TRUE); +#endif /* ENABLE_FW_ROAM_SUSPEND */ + if (FW_SUPPORTED(dhd, ndoe)) { + /* disable IPv6 RA filter in firmware during suspend */ + nd_ra_filter = 0; + ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", + (char *)&nd_ra_filter, sizeof(nd_ra_filter), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("failed to set nd_ra_filter (%d)\n", + ret)); + } + } + } + dhd_suspend_unlock(dhd); + + return 0; +} + +static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) +{ + dhd_pub_t *dhdp = &dhd->pub; + int ret = 0; + + DHD_OS_WAKE_LOCK(dhdp); + /* Set flag when early suspend was called */ + dhdp->in_suspend = val; + if ((force || !dhdp->suspend_disable_flag) && + dhd_support_sta_mode(dhdp)) + { + ret = dhd_set_suspend(val, dhdp); + } + + DHD_OS_WAKE_UNLOCK(dhdp); + return ret; +} + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) +static void dhd_early_suspend(struct early_suspend *h) +{ + struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); + DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); + + if (dhd) + dhd_suspend_resume_helper(dhd, 1, 0); +} + +static void dhd_late_resume(struct early_suspend *h) +{ + struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); + DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); + + if (dhd) + dhd_suspend_resume_helper(dhd, 0, 0); +} +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ + +/* + * Generalized timeout mechanism. Uses spin sleep with exponential back-off until + * the sleep time reaches one jiffy, then switches over to task delay. Usage: + * + * dhd_timeout_start(&tmo, usec); + * while (!dhd_timeout_expired(&tmo)) + * if (poll_something()) + * break; + * if (dhd_timeout_expired(&tmo)) + * fatal(); + */ + +void +dhd_timeout_start(dhd_timeout_t *tmo, uint usec) +{ + tmo->limit = usec; + tmo->increment = 0; + tmo->elapsed = 0; + tmo->tick = jiffies_to_usecs(1); +} + +int +dhd_timeout_expired(dhd_timeout_t *tmo) +{ + /* Does nothing the first call */ + if (tmo->increment == 0) { + tmo->increment = 1; + return 0; + } + + if (tmo->elapsed >= tmo->limit) + return 1; + + /* Add the delay that's about to take place */ + tmo->elapsed += tmo->increment; + + if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) { + OSL_DELAY(tmo->increment); + tmo->increment *= 2; + if (tmo->increment > tmo->tick) + tmo->increment = tmo->tick; + } else { + wait_queue_head_t delay_wait; + DECLARE_WAITQUEUE(wait, current); + init_waitqueue_head(&delay_wait); + add_wait_queue(&delay_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + remove_wait_queue(&delay_wait, &wait); + set_current_state(TASK_RUNNING); + } + + return 0; +} + +int +dhd_net2idx(dhd_info_t *dhd, struct net_device *net) +{ + int i = 0; + + ASSERT(dhd); + while (i < DHD_MAX_IFS) { + if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net)) + return i; + i++; + } + + return DHD_BAD_IF; +} + +struct net_device * dhd_idx2net(void *pub, int ifidx) +{ + struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; + struct dhd_info *dhd_info; + + if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) + return NULL; + dhd_info = dhd_pub->info; + if (dhd_info && dhd_info->iflist[ifidx]) + return dhd_info->iflist[ifidx]->net; + return NULL; +} + +int +dhd_ifname2idx(dhd_info_t *dhd, char *name) +{ + int i = DHD_MAX_IFS; + + ASSERT(dhd); + + if (name == NULL || *name == '\0') + return 0; + + while (--i > 0) + if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ)) + break; + + DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name)); + + return i; /* default - the primary interface */ +} + +char * +dhd_ifname(dhd_pub_t *dhdp, int ifidx) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + ASSERT(dhd); + + if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { + DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); + return ""; + } + + if (dhd->iflist[ifidx] == NULL) { + DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); + return ""; + } + + if (dhd->iflist[ifidx]->net) + return dhd->iflist[ifidx]->net->name; + + return ""; +} + +uint8 * +dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) +{ + int i; + dhd_info_t *dhd = (dhd_info_t *)dhdp; + + ASSERT(dhd); + for (i = 0; i < DHD_MAX_IFS; i++) + if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) + return dhd->iflist[i]->mac_addr; + + return NULL; +} + + +static void +_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) +{ + struct net_device *dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + struct netdev_hw_addr *ha; +#else + struct dev_mc_list *mclist; +#endif + uint32 allmulti, cnt; + + wl_ioctl_t ioc; + char *buf, *bufp; + uint buflen; + int ret; + + ASSERT(dhd && dhd->iflist[ifidx]); + dev = dhd->iflist[ifidx]->net; + if (!dev) + return; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_lock_bh(dev); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + cnt = netdev_mc_count(dev); +#else + cnt = dev->mc_count; +#endif /* LINUX_VERSION_CODE */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_unlock_bh(dev); +#endif + + /* Determine initial value of allmulti flag */ + allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; + + /* Send down the multicast list first. */ + + + buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); + if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { + DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", + dhd_ifname(&dhd->pub, ifidx), cnt)); + return; + } + + strncpy(bufp, "mcast_list", buflen - 1); + bufp[buflen - 1] = '\0'; + bufp += strlen("mcast_list") + 1; + + cnt = htol32(cnt); + memcpy(bufp, &cnt, sizeof(cnt)); + bufp += sizeof(cnt); + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_lock_bh(dev); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + netdev_for_each_mc_addr(ha, dev) { + if (!cnt) + break; + memcpy(bufp, ha->addr, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; + cnt--; + } +#else + for (mclist = dev->mc_list; (mclist && (cnt > 0)); + cnt--, mclist = mclist->next) { + memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; + } +#endif /* LINUX_VERSION_CODE */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_unlock_bh(dev); +#endif + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = WLC_SET_VAR; + ioc.buf = buf; + ioc.len = buflen; + ioc.set = TRUE; + + ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + if (ret < 0) { + DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", + dhd_ifname(&dhd->pub, ifidx), cnt)); + allmulti = cnt ? TRUE : allmulti; + } + + MFREE(dhd->pub.osh, buf, buflen); + + /* 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... + */ + allmulti = htol32(allmulti); + ret = dhd_iovar(&dhd->pub, ifidx, "allmulti", (char *)&allmulti, + sizeof(allmulti), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: set allmulti %d failed\n", + dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); + } + + /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ + + allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; + + allmulti = htol32(allmulti); + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = WLC_SET_PROMISC; + ioc.buf = &allmulti; + ioc.len = sizeof(allmulti); + ioc.set = TRUE; + + ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + if (ret < 0) { + DHD_ERROR(("%s: set promisc %d failed\n", + dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); + } +} + +int +_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr) +{ + int ret; + ret = dhd_iovar(&dhd->pub, ifidx, "cur_etheraddr", (char *)addr, + ETHER_ADDR_LEN, NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); + } else { + memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); + if (ifidx == 0) + memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); + } + + return ret; +} + +#ifdef SOFTAP +extern struct net_device *ap_net_dev; +extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ +#endif + +static void +dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + dhd_if_event_t *if_event = event_info; + struct net_device *ndev; + int ifidx, bssidx; + int ret; + + if (event != DHD_WQ_WORK_IF_ADD) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return; + } + + if (!if_event) { + DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); + return; + } + + dhd_net_if_lock_local(dhd); + DHD_OS_WAKE_LOCK(&dhd->pub); + + ifidx = if_event->event.ifidx; + bssidx = if_event->event.bssidx; + DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx)); + + ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name, + if_event->mac, bssidx, TRUE); + if (!ndev) { + DHD_ERROR(("%s: net device alloc failed \n", __FUNCTION__)); + goto done; + } + + ret = dhd_register_if(&dhd->pub, ifidx, TRUE); + if (ret != BCME_OK) { + DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__)); + dhd_remove_if(&dhd->pub, ifidx, TRUE); + } +done: + MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); + + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_net_if_unlock_local(dhd); +} + +static void +dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + int ifidx; + dhd_if_event_t *if_event = event_info; + + + if (event != DHD_WQ_WORK_IF_DEL) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return; + } + + if (!if_event) { + DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); + return; + } + + dhd_net_if_lock_local(dhd); + DHD_OS_WAKE_LOCK(&dhd->pub); + + ifidx = if_event->event.ifidx; + DHD_TRACE(("Removing interface with idx %d\n", ifidx)); + + dhd_remove_if(&dhd->pub, ifidx, TRUE); + + MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); + + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_net_if_unlock_local(dhd); +} + +static void +dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + dhd_if_t *ifp = event_info; + +#ifdef SOFTAP + unsigned long flags; + bool in_ap = FALSE; +#endif + + if (event != DHD_WQ_WORK_SET_MAC) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + } + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return; + } + +#ifdef SOFTAP + flags = dhd_os_spin_lock(&dhd->pub); + in_ap = (ap_net_dev != NULL); + dhd_os_spin_unlock(&dhd->pub, flags); + + if (in_ap) { + DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n", + ifp->net->name)); + return; + } +#endif + dhd_net_if_lock_local(dhd); + DHD_OS_WAKE_LOCK(&dhd->pub); + + if (ifp == NULL || !dhd->pub.up) { + DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); + goto done; + } + + DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__)); + ifp->set_macaddress = FALSE; + if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0) + DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); + else + DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); + +done: + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_net_if_unlock_local(dhd); +} + +static void +dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + dhd_if_t *ifp = event_info; + int ifidx; + +#ifdef SOFTAP + bool in_ap = FALSE; + unsigned long flags; +#endif + + if (event != DHD_WQ_WORK_SET_MCAST_LIST) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return; + } + +#ifdef SOFTAP + flags = dhd_os_spin_lock(&dhd->pub); + in_ap = (ap_net_dev != NULL); + dhd_os_spin_unlock(&dhd->pub, flags); + + if (in_ap) { + DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n", + ifp->net->name)); + ifp->set_multicast = FALSE; + return; + } +#endif + + dhd_net_if_lock_local(dhd); + DHD_OS_WAKE_LOCK(&dhd->pub); + + if (ifp == NULL || !dhd->pub.up) { + DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); + goto done; + } + + ifidx = ifp->idx; + + + _dhd_set_multicast_list(dhd, ifidx); + DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx)); + +done: + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_net_if_unlock_local(dhd); +} + +static int +dhd_set_mac_address(struct net_device *dev, void *addr) +{ + int ret = 0; + + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + struct sockaddr *sa = (struct sockaddr *)addr; + int ifidx; + dhd_if_t *dhdif; + + ifidx = dhd_net2idx(dhd, dev); + if (ifidx == DHD_BAD_IF) + return -1; + + dhdif = dhd->iflist[ifidx]; + + dhd_net_if_lock_local(dhd); + memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN); + dhdif->set_macaddress = TRUE; + dhd_net_if_unlock_local(dhd); + dhd_deferred_schedule_work((void *)dhdif, DHD_WQ_WORK_SET_MAC, + dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW); + return ret; +} + +static void +dhd_set_multicast_list(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ifidx; + + ifidx = dhd_net2idx(dhd, dev); + if (ifidx == DHD_BAD_IF) + return; + + dhd->iflist[ifidx]->set_multicast = TRUE; + dhd_deferred_schedule_work((void *)dhd->iflist[ifidx], DHD_WQ_WORK_SET_MCAST_LIST, + dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW); +} + +#ifdef PROP_TXSTATUS +int +dhd_os_wlfc_block(dhd_pub_t *pub) +{ + dhd_info_t *di = (dhd_info_t *)(pub->info); + ASSERT(di != NULL); + spin_lock_bh(&di->wlfc_spinlock); + return 1; +} + +int +dhd_os_wlfc_unblock(dhd_pub_t *pub) +{ + dhd_info_t *di = (dhd_info_t *)(pub->info); + + ASSERT(di != NULL); + spin_unlock_bh(&di->wlfc_spinlock); + return 1; +} + +const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; +const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; +#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] + +#endif /* PROP_TXSTATUS */ +int BCMFASTPATH +dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) +{ + int ret = BCME_OK; + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct ether_header *eh = NULL; + + /* Reject if down */ + if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { + /* free the packet here since the caller won't */ + PKTFREE(dhdp->osh, pktbuf, TRUE); + return -ENODEV; + } + + /* Update multicast statistic */ + if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { + uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); + eh = (struct ether_header *)pktdata; + + if (ETHER_ISMULTI(eh->ether_dhost)) + dhdp->tx_multicast++; + if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) + atomic_inc(&dhd->pend_8021x_cnt); + } else { + PKTFREE(dhd->pub.osh, pktbuf, TRUE); + return BCME_ERROR; + } + +#ifdef DHDTCPACK_SUPPRESS + /* If this packet has replaced another packet and got freed, just return */ + if (dhd_tcpack_suppress(dhdp, pktbuf)) + return ret; +#endif /* DHDTCPACK_SUPPRESS */ + + /* Look into the packet and update the packet priority */ +#ifndef PKTPRIO_OVERRIDE + if (PKTPRIO(pktbuf) == 0) +#endif + pktsetprio(pktbuf, FALSE); + +#ifdef PROP_TXSTATUS + if (dhd_wlfc_is_supported(dhdp)) { + /* store the interface ID */ + DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); + + /* store destination MAC in the tag as well */ + DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); + + /* decide which FIFO this packet belongs to */ + if (ETHER_ISMULTI(eh->ether_dhost)) + /* one additional queue index (highest AC + 1) is used for bc/mc queue */ + DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); + else + DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); + } else +#endif /* PROP_TXSTATUS */ + /* If the protocol uses a data header, apply it */ + dhd_prot_hdrpush(dhdp, ifidx, pktbuf); + + /* Use bus module to send data frame */ +#ifdef WLMEDIA_HTSF + dhd_htsf_addtxts(dhdp, pktbuf); +#endif +#ifdef PROP_TXSTATUS + { + if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata, + dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) { + /* non-proptxstatus way */ + ret = dhd_bus_txdata(dhdp->bus, pktbuf); + } + } +#else +#ifdef BCMPCIE + ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); +#else + ret = dhd_bus_txdata(dhdp->bus, pktbuf); +#endif /* BCMPCIE */ +#endif /* PROP_TXSTATUS */ + + return ret; +} + +int BCMFASTPATH +dhd_start_xmit(struct sk_buff *skb, struct net_device *net) +{ + int ret; + uint datalen; + void *pktbuf; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + dhd_if_t *ifp = NULL; + int ifidx; +#ifdef WLMEDIA_HTSF + uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; +#else + uint8 htsfdlystat_sz = 0; +#endif + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + DHD_OS_WAKE_LOCK(&dhd->pub); + + /* Reject if down */ + if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) { + DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", + __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); + netif_stop_queue(net); + /* Send Event when bus down detected during data session */ + if (dhd->pub.up) { + DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(dhd->pub.crash_reason, + "%s: Event HANG sent up\n", __FUNCTION__); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + net_os_send_hang_message(net); + } + DHD_OS_WAKE_UNLOCK(&dhd->pub); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) + return -ENODEV; +#else + return NETDEV_TX_BUSY; +#endif + } + + ifidx = dhd_net2idx(dhd, net); + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); + netif_stop_queue(net); + DHD_OS_WAKE_UNLOCK(&dhd->pub); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) + return -ENODEV; +#else + return NETDEV_TX_BUSY; +#endif + } + + /* re-align socket buffer if "skb->data" is odd adress */ + if (((unsigned long)(skb->data)) & 0x1) { + unsigned char *data = skb->data; + uint32 length = skb->len; + PKTPUSH(dhd->pub.osh, skb, 1); + memmove(skb->data, data, length); + PKTSETLEN(dhd->pub.osh, skb, length); + } + + ifp = dhd->iflist[ifidx]; + datalen = PKTLEN(dhd->pub.osh, skb); + + /* Make sure there's enough room for any header */ + + if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { + struct sk_buff *skb2; + + DHD_INFO(("%s: insufficient headroom\n", + dhd_ifname(&dhd->pub, ifidx))); + dhd->pub.tx_realloc++; + + skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); + + dev_kfree_skb(skb); + if ((skb = skb2) == NULL) { + DHD_ERROR(("%s: skb_realloc_headroom failed\n", + dhd_ifname(&dhd->pub, ifidx))); + ret = -ENOMEM; + goto done; + } + } + + /* Convert to packet */ + if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { + DHD_ERROR(("%s: PKTFRMNATIVE failed\n", + dhd_ifname(&dhd->pub, ifidx))); + dev_kfree_skb_any(skb); + ret = -ENOMEM; + goto done; + } +#ifdef WLMEDIA_HTSF + if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { + uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); + struct ether_header *eh = (struct ether_header *)pktdata; + + if (!ETHER_ISMULTI(eh->ether_dhost) && + (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { + eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); + } + } +#endif + + ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); + +done: + if (ret) { + ifp->stats.tx_dropped++; + } + else { + +#ifdef PROP_TXSTATUS + /* tx_packets counter can counted only when wlfc is disabled */ + if (!dhd_wlfc_is_supported(&dhd->pub)) +#endif + { + dhd->pub.tx_packets++; + ifp->stats.tx_packets++; + ifp->stats.tx_bytes += datalen; + } + } + + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + /* Return ok: we always eat the packet */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) + return 0; +#else + return NETDEV_TX_OK; +#endif +} + +void +dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) +{ + struct net_device *net; + dhd_info_t *dhd = dhdp->info; + int i; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(dhd); + +#ifdef DHD_LOSSLESS_ROAMING + /* block flowcontrol during roaming */ + if ((dhdp->dequeue_prec_map == 1 << PRIO_8021D_NC) && state == ON) { + return; + } +#endif /* DHD_LOSSLESS_ROAMING */ + + if (ifidx == ALL_INTERFACES) { + /* Flow control on all active interfaces */ + dhdp->txoff = state; + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + net = dhd->iflist[i]->net; + if (state == ON) + netif_stop_queue(net); + else + netif_wake_queue(net); + } + } + } + else { + if (dhd->iflist[ifidx]) { + net = dhd->iflist[ifidx]->net; + if (state == ON) + netif_stop_queue(net); + else + netif_wake_queue(net); + } + } +} + +#ifdef DHD_RX_DUMP +typedef struct { + uint16 type; + const char *str; +} PKTTYPE_INFO; + +static const PKTTYPE_INFO packet_type_info[] = +{ + { ETHER_TYPE_IP, "IP" }, + { ETHER_TYPE_ARP, "ARP" }, + { ETHER_TYPE_BRCM, "BRCM" }, + { ETHER_TYPE_802_1X, "802.1X" }, + { ETHER_TYPE_WAI, "WAPI" }, + { 0, ""} +}; + +static const char *_get_packet_type_str(uint16 type) +{ + int i; + int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; + + for (i = 0; i < n; i++) { + if (packet_type_info[i].type == type) + return packet_type_info[i].str; + } + + return packet_type_info[n].str; +} +#endif /* DHD_RX_DUMP */ + + +void +dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + struct sk_buff *skb; + uchar *eth; + uint len; + void *data, *pnext = NULL; + int i; + dhd_if_t *ifp; + wl_event_msg_t event; + int tout_rx = 0; + int tout_ctrl = 0; + void *skbhead = NULL; + void *skbprev = NULL; +#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) + char *dump_data; + uint16 protocol; +#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { + struct ether_header *eh; + + pnext = PKTNEXT(dhdp->osh, pktbuf); + PKTSETNEXT(dhdp->osh, pktbuf, NULL); + + ifp = dhd->iflist[ifidx]; + if (ifp == NULL) { + DHD_ERROR(("%s: ifp is NULL. drop packet\n", + __FUNCTION__)); + PKTFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); + /* Dropping only data packets before registering net device to avoid kernel panic */ +#ifndef PROP_TXSTATUS_VSDB + if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) && + (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { +#else + if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) && + (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { +#endif /* PROP_TXSTATUS_VSDB */ + DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", + __FUNCTION__)); + PKTFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + + +#ifdef PROP_TXSTATUS + if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) { + /* WLFC may send header only packet when + there is an urgent message but no packet to + piggy-back on + */ + PKTFREE(dhdp->osh, pktbuf, FALSE); + continue; + } +#endif +#ifdef DHDTCPACK_SUPPRESS + dhd_tcpdata_info_get(dhdp, pktbuf); +#endif + skb = PKTTONATIVE(dhdp->osh, pktbuf); + + ifp = dhd->iflist[ifidx]; + if (ifp == NULL) + ifp = dhd->iflist[0]; + + ASSERT(ifp); + skb->dev = ifp->net; + + + /* 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; + +#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) + dump_data = skb->data; + protocol = (dump_data[12] << 8) | dump_data[13]; + + if (protocol == ETHER_TYPE_802_1X) { + DHD_ERROR(("ETHER_TYPE_802_1X: " + "ver %d, type %d, replay %d\n", + dump_data[14], dump_data[15], + dump_data[30])); + } +#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */ +#if defined(DHD_RX_DUMP) + DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol))); + if (protocol != ETHER_TYPE_BRCM) { + if (dump_data[0] == 0xFF) { + DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__)); + + if ((dump_data[12] == 8) && + (dump_data[13] == 6)) { + DHD_ERROR(("%s: ARP %d\n", + __FUNCTION__, dump_data[0x15])); + } + } else if (dump_data[0] & 1) { + DHD_ERROR(("%s: MULTICAST: " MACDBG "\n", + __FUNCTION__, MAC2STRDBG(dump_data))); + } +#ifdef DHD_RX_FULL_DUMP + { + int k; + for (k = 0; k < skb->len; k++) { + DHD_ERROR(("%02X ", dump_data[k])); + if ((k & 15) == 15) + DHD_ERROR(("\n")); + } + DHD_ERROR(("\n")); + } +#endif /* DHD_RX_FULL_DUMP */ + } +#endif /* DHD_RX_DUMP */ + + skb->protocol = eth_type_trans(skb, skb->dev); + + if (skb->pkt_type == PACKET_MULTICAST) { + dhd->pub.rx_multicast++; + ifp->stats.multicast++; + } + + skb->data = eth; + skb->len = len; + +#ifdef WLMEDIA_HTSF + dhd_htsf_addrxts(dhdp, pktbuf); +#endif + /* Strip header, count, deliver upward */ + skb_pull(skb, ETH_HLEN); + + /* Process special event packets and then discard them */ + memset(&event, 0, sizeof(event)); + if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { + int ret_event; + + ret_event = dhd_wl_host_event(dhd, &ifidx, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + skb_mac_header(skb), +#else + skb->mac.raw, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ + len, + &event, + &data); + + if (ret_event != BCME_OK) { + PKTFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + + wl_event_to_host_order(&event); + if (!tout_ctrl) + tout_ctrl = DHD_PACKET_TIMEOUT_MS; + +#if defined(PNO_SUPPORT) + if (event.event_type == WLC_E_PFN_NET_FOUND) { + /* enforce custom wake lock to garantee that Kernel not suspended */ + tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; + } +#endif /* PNO_SUPPORT */ + +#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + PKTFREE(dhdp->osh, pktbuf, FALSE); + continue; +#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ + } else { + tout_rx = DHD_PACKET_TIMEOUT_MS; + +#ifdef PROP_TXSTATUS + dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb)); +#endif /* PROP_TXSTATUS */ + } + + ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); + ifp = dhd->iflist[ifidx]; + + if (ifp->net) + ifp->net->last_rx = jiffies; + + if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { + dhdp->dstats.rx_bytes += skb->len; + dhdp->rx_packets++; /* Local count */ + ifp->stats.rx_bytes += skb->len; + ifp->stats.rx_packets++; + } + + if (in_interrupt()) { + netif_rx(skb); + } else { + if (dhd->rxthread_enabled) { + if (!skbhead) + skbhead = skb; + else + PKTSETNEXT(dhdp->osh, skbprev, skb); + skbprev = 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. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + netif_rx_ni(skb); +#else + ulong flags; + netif_rx(skb); + local_irq_save(flags); + RAISE_RX_SOFTIRQ(); + local_irq_restore(flags); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ + } + } + } + + if (dhd->rxthread_enabled && skbhead) + dhd_sched_rxf(dhdp, skbhead); + + DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); +} + +void +dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx) +{ + /* Linux version has nothing to do */ + return; +} + +void +dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) +{ + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct ether_header *eh; + uint16 type; + + dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); + + eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); + type = ntoh16(eh->ether_type); + + if (type == ETHER_TYPE_802_1X) + atomic_dec(&dhd->pend_8021x_cnt); + +#ifdef PROP_TXSTATUS + if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) { + dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))]; + uint datalen = PKTLEN(dhd->pub.osh, txp); + + if (success) { + dhd->pub.tx_packets++; + ifp->stats.tx_packets++; + ifp->stats.tx_bytes += datalen; + } else { + ifp->stats.tx_dropped++; + } + } +#endif +} + +static struct net_device_stats * +dhd_get_stats(struct net_device *net) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + dhd_if_t *ifp; + int ifidx; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ifidx = dhd_net2idx(dhd, net); + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); + + memset(&net->stats, 0, sizeof(net->stats)); + return &net->stats; + } + + ifp = dhd->iflist[ifidx]; + ASSERT(dhd && ifp); + + if (dhd->pub.up) { + /* Use the protocol to get dongle stats */ + dhd_prot_dstats(&dhd->pub); + } + return &ifp->stats; +} + +static int +dhd_watchdog_thread(void *data) +{ + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; + /* This thread doesn't need any user-level access, + * so get rid of all our resources + */ + if (dhd_watchdog_prio > 0) { + struct sched_param param; + param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? + dhd_watchdog_prio:(MAX_RT_PRIO-1); + setScheduler(current, SCHED_FIFO, ¶m); + } + + while (1) + if (down_interruptible (&tsk->sema) == 0) { + unsigned long flags; + unsigned long jiffies_at_start = jiffies; + unsigned long time_lapse; + + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } + + dhd_os_sdlock(&dhd->pub); + if (dhd->pub.dongle_reset == FALSE) { + DHD_TIMER(("%s:\n", __FUNCTION__)); + + /* Call the bus module watchdog */ + dhd_bus_watchdog(&dhd->pub); + + flags = dhd_os_spin_lock(&dhd->pub); + /* Count the tick for reference */ + dhd->pub.tickcnt++; + time_lapse = jiffies - jiffies_at_start; + + /* Reschedule the watchdog */ + if (dhd->wd_timer_valid) + mod_timer(&dhd->timer, + jiffies + + msecs_to_jiffies(dhd_watchdog_ms) - + min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); + dhd_os_spin_unlock(&dhd->pub, flags); + } + dhd_os_sdunlock(&dhd->pub); + } else { + break; + } + + complete_and_exit(&tsk->completed, 0); +} + +static void dhd_watchdog(ulong data) +{ + dhd_info_t *dhd = (dhd_info_t *)data; + unsigned long flags; + + if (dhd->pub.dongle_reset) { + return; + } + + if (dhd->thr_wdt_ctl.thr_pid >= 0) { + up(&dhd->thr_wdt_ctl.sema); + return; + } + + dhd_os_sdlock(&dhd->pub); + /* Call the bus module watchdog */ + dhd_bus_watchdog(&dhd->pub); + + flags = dhd_os_spin_lock(&dhd->pub); + /* Count the tick for reference */ + dhd->pub.tickcnt++; + + /* Reschedule the watchdog */ + if (dhd->wd_timer_valid) + mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); + dhd_os_spin_unlock(&dhd->pub, flags); + dhd_os_sdunlock(&dhd->pub); +} + +#ifdef ENABLE_ADAPTIVE_SCHED +/* DPC thread policy */ +static int dhd_dpc_poli = SCHED_FIFO; +static void +dhd_sched_policy(int prio) +{ + struct sched_param param; + if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) { + param.sched_priority = 0; + setScheduler(current, SCHED_NORMAL, ¶m); + } else { + if (get_scheduler_policy(current) != SCHED_FIFO) { + param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1); + setScheduler(current, dhd_dpc_poli, ¶m); + } + } +} +#endif /* ENABLE_ADAPTIVE_SCHED */ +#ifdef DEBUG_CPU_FREQ +static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) +{ + dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans); + struct cpufreq_freqs *freq = data; + if (dhd) { + if (!dhd->new_freq) + goto exit; + if (val == CPUFREQ_POSTCHANGE) { + DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n", + freq->new, freq->cpu)); + *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new; + } + } +exit: + return 0; +} +#endif /* DEBUG_CPU_FREQ */ +static int +dhd_dpc_thread(void *data) +{ + + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; + + /* This thread doesn't need any user-level access, + * so get rid of all our resources + */ + if (dhd_dpc_prio > 0) + { + struct sched_param param; + param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); + setScheduler(current, SCHED_FIFO, ¶m); + } + +#ifdef CUSTOM_DPC_CPUCORE + set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE)); +#endif + /* Run until signal received */ + while (1) { + if (!binary_sema_down(tsk)) { +#ifdef ENABLE_ADAPTIVE_SCHED + dhd_sched_policy(dhd_dpc_prio); +#endif /* ENABLE_ADAPTIVE_SCHED */ + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } + + /* Call bus dpc unless it indicated down (then clean stop) */ + if (dhd->pub.busstate != DHD_BUS_DOWN) { +#if defined(CUSTOMER_HW5) + int resched_cnt = 0; +#endif + dhd_os_wd_timer_extend(&dhd->pub, TRUE); + while (dhd_bus_dpc(dhd->pub.bus)) { + /* process all data */ +#if defined(CUSTOMER_HW5) + resched_cnt++; + if (resched_cnt > MAX_RESCHED_CNT) { + DHD_INFO(("%s Calling msleep to" + "let other processes run. \n", + __FUNCTION__)); + dhd->pub.dhd_bug_on = true; + resched_cnt = 0; + OSL_SLEEP(1); + } +#endif + } + dhd_os_wd_timer_extend(&dhd->pub, FALSE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + } else { + if (dhd->pub.up) + dhd_bus_stop(dhd->pub.bus, TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + } + } + else + break; + } + complete_and_exit(&tsk->completed, 0); +} + +static int +dhd_rxf_thread(void *data) +{ + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; + dhd_pub_t *pub = &dhd->pub; +#if defined(WAIT_DEQUEUE) +#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */ + ulong watchdogTime = OSL_SYSUPTIME(); /* msec */ +#endif + + /* This thread doesn't need any user-level access, + * so get rid of all our resources + */ + if (dhd_rxf_prio > 0) + { + struct sched_param param; + param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1); + setScheduler(current, SCHED_FIFO, ¶m); + } + + DAEMONIZE("dhd_rxf"); + /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ + + /* signal: thread has started */ + complete(&tsk->completed); + + /* Run until signal received */ + while (1) { + if (down_interruptible(&tsk->sema) == 0) { + void *skb; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + ulong flags; +#endif +#ifdef ENABLE_ADAPTIVE_SCHED + dhd_sched_policy(dhd_rxf_prio); +#endif /* ENABLE_ADAPTIVE_SCHED */ + + SMP_RD_BARRIER_DEPENDS(); + + if (tsk->terminated) { + break; + } + skb = dhd_rxf_dequeue(pub); + + if (skb == NULL) { + continue; + } + while (skb) { + void *skbnext = PKTNEXT(pub->osh, skb); + PKTSETNEXT(pub->osh, skb, NULL); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + netif_rx_ni(skb); +#else + netif_rx(skb); + local_irq_save(flags); + RAISE_RX_SOFTIRQ(); + local_irq_restore(flags); + +#endif + skb = skbnext; + } +#if defined(WAIT_DEQUEUE) + if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) { + OSL_SLEEP(1); + watchdogTime = OSL_SYSUPTIME(); + } +#endif + + DHD_OS_WAKE_UNLOCK(pub); + } + else + break; + } + + complete_and_exit(&tsk->completed, 0); +} + +static void +dhd_dpc(ulong data) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)data; + + /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] + * down below , wake lock is set, + * the tasklet is initialized in dhd_attach() + */ + /* Call bus dpc unless it indicated down (then clean stop) */ + if (dhd->pub.busstate != DHD_BUS_DOWN) { + if (dhd_bus_dpc(dhd->pub.bus)) + tasklet_schedule(&dhd->tasklet); + else + DHD_OS_WAKE_UNLOCK(&dhd->pub); + } else { + dhd_bus_stop(dhd->pub.bus, TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + } +} + +void +dhd_sched_dpc(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + DHD_OS_WAKE_LOCK(dhdp); + if (dhd->thr_dpc_ctl.thr_pid >= 0) { + /* If the semaphore does not get up, + * wake unlock should be done here + */ + if (!binary_sema_up(&dhd->thr_dpc_ctl)) + DHD_OS_WAKE_UNLOCK(dhdp); + return; + } else { + tasklet_schedule(&dhd->tasklet); + } +} + +static void +dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; +#ifdef RXF_DEQUEUE_ON_BUSY + int ret = BCME_OK; + int retry = 2; +#endif /* RXF_DEQUEUE_ON_BUSY */ + + DHD_OS_WAKE_LOCK(dhdp); + + DHD_TRACE(("dhd_sched_rxf: Enter\n")); +#ifdef RXF_DEQUEUE_ON_BUSY + do { + ret = dhd_rxf_enqueue(dhdp, skb); + if (ret == BCME_OK || ret == BCME_ERROR) + break; + else + OSL_SLEEP(50); /* waiting for dequeueing */ + } while (retry-- > 0); + + if (retry <= 0 && ret == BCME_BUSY) { + void *skbp = skb; + + while (skbp) { + void *skbnext = PKTNEXT(dhdp->osh, skbp); + PKTSETNEXT(dhdp->osh, skbp, NULL); + netif_rx_ni(skbp); + skbp = skbnext; + } + DHD_ERROR(("send skb to kernel backlog without rxf_thread\n")); + } + else { + if (dhd->thr_rxf_ctl.thr_pid >= 0) { + up(&dhd->thr_rxf_ctl.sema); + } + } +#else /* RXF_DEQUEUE_ON_BUSY */ + do { + if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK) + break; + } while (1); + if (dhd->thr_rxf_ctl.thr_pid >= 0) { + up(&dhd->thr_rxf_ctl.sema); + } + return; +#endif /* RXF_DEQUEUE_ON_BUSY */ +} + +#ifdef TOE +/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ +static int +dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) +{ + char buf[32]; + int ret; + + ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", NULL, 0, (char *)buf, sizeof(buf), FALSE); + if (ret < 0) { + /* Check for older dongle image that doesn't support toe_ol */ + if (ret == -EIO) { + DHD_ERROR(("%s: toe not supported by device\n", dhd_ifname(&dhd->pub, + ifidx))); + return -EOPNOTSUPP; + } + + DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); + return ret; + } + + memcpy(toe_ol, buf, sizeof(uint32)); + return 0; +} + +/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ +static int +dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) +{ + int toe, ret; + + /* Set toe_ol as requested */ + ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", (char *)&toe_ol, sizeof(toe_ol), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", + dhd_ifname(&dhd->pub, ifidx), ret)); + return ret; + } + + /* Enable toe globally only if any components are enabled. */ + toe = (toe_ol != 0); + ret = dhd_iovar(&dhd->pub, ifidx, "toe", (char *)&toe, sizeof(toe), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); + return ret; + } + + return 0; +} +#endif /* TOE */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +static void +dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + + snprintf(info->driver, sizeof(info->driver), "wl"); + snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); +} + +struct ethtool_ops dhd_ethtool_ops = { + .get_drvinfo = dhd_ethtool_get_drvinfo +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) +static int +dhd_ethtool(dhd_info_t *dhd, void *uaddr) +{ + struct ethtool_drvinfo info; + char drvname[sizeof(info.driver)]; + uint32 cmd; +#ifdef TOE + struct ethtool_value edata; + uint32 toe_cmpnt, csum_dir; + int ret; +#endif + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* all ethtool calls start with a cmd word */ + if (copy_from_user(&cmd, uaddr, sizeof (uint32))) + 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 dhd requested, identify ourselves */ + if (strcmp(drvname, "?dhd") == 0) { + snprintf(info.driver, sizeof(info.driver), "dhd"); + strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); + info.version[sizeof(info.version) - 1] = '\0'; + } + + /* otherwise, require dongle to be up */ + else if (!dhd->pub.up) { + DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); + return -ENODEV; + } + + /* finally, report dongle driver type */ + else if (dhd->pub.iswl) + snprintf(info.driver, sizeof(info.driver), "wl"); + else + snprintf(info.driver, sizeof(info.driver), "xx"); + + snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); + if (copy_to_user(uaddr, &info, sizeof(info))) + return -EFAULT; + DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, + (int)sizeof(drvname), drvname, info.driver)); + break; + +#ifdef TOE + /* Get toe offload components from dongle */ + case ETHTOOL_GRXCSUM: + case ETHTOOL_GTXCSUM: + if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 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 */ + if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 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; + + if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) + return ret; + + /* If setting TX checksum mode, tell Linux the new mode */ + if (cmd == ETHTOOL_STXCSUM) { + if (edata.data) + dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; + else + dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; + } + + break; +#endif /* TOE */ + + default: + return -EOPNOTSUPP; + } + + return 0; +} +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ + +static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) +{ + dhd_info_t *dhd; + + if (!dhdp) { + DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); + return FALSE; + } + + if (!dhdp->up) + return FALSE; + + dhd = (dhd_info_t *)dhdp->info; +#if !defined(BCMPCIE) + if (dhd->thr_dpc_ctl.thr_pid < 0) { + DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); + return FALSE; + } +#endif + + if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || + ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { + DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, + dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(dhdp->crash_reason, + "%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, + dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + net_os_send_hang_message(net); + return TRUE; + } + return FALSE; +} + +int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf) +{ + int bcmerror = BCME_OK; + int buflen = 0; + struct net_device *net; + + net = dhd_idx2net(pub, ifidx); + if (!net) { + bcmerror = BCME_BADARG; + goto done; + } + + if (data_buf) + buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN); + + /* check for local dhd ioctl and handle it */ + if (ioc->driver == DHD_IOCTL_MAGIC) { + bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen); + if (bcmerror) + pub->bcmerror = bcmerror; + goto done; + } + + + /* send to dongle (must be up, and wl). */ + if (pub->busstate != DHD_BUS_DATA) { + bcmerror = BCME_DONGLE_DOWN; + goto done; + } + + if (!pub->iswl) { + bcmerror = BCME_DONGLE_DOWN; + goto done; + } + + /* + * Flush the TX queue if required for proper message serialization: + * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to + * prevent M4 encryption and + * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to + * prevent disassoc frame being sent before WPS-DONE frame. + */ + if (ioc->cmd == WLC_SET_KEY || + (ioc->cmd == WLC_SET_VAR && data_buf != NULL && + strncmp("wsec_key", data_buf, 9) == 0) || + (ioc->cmd == WLC_SET_VAR && data_buf != NULL && + strncmp("bsscfg:wsec_key", data_buf, 15) == 0) || + ioc->cmd == WLC_DISASSOC) + dhd_wait_pend8021x(net); + +#ifdef WLMEDIA_HTSF + if (data_buf) { + /* short cut wl ioctl calls here */ + if (strcmp("htsf", data_buf) == 0) { + dhd_ioctl_htsf_get(dhd, 0); + return BCME_OK; + } + + if (strcmp("htsflate", data_buf) == 0) { + if (ioc->set) { + memset(ts, 0, sizeof(tstamp_t)*TSMAX); + memset(&maxdelayts, 0, sizeof(tstamp_t)); + maxdelay = 0; + tspktcnt = 0; + maxdelaypktno = 0; + memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); + } else { + dhd_dump_latency(); + } + return BCME_OK; + } + if (strcmp("htsfclear", data_buf) == 0) { + memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); + htsf_seqnum = 0; + return BCME_OK; + } + if (strcmp("htsfhis", data_buf) == 0) { + dhd_dump_htsfhisto(&vi_d1, "H to D"); + dhd_dump_htsfhisto(&vi_d2, "D to D"); + dhd_dump_htsfhisto(&vi_d3, "D to H"); + dhd_dump_htsfhisto(&vi_d4, "H to H"); + return BCME_OK; + } + if (strcmp("tsport", data_buf) == 0) { + if (ioc->set) { + memcpy(&tsport, data_buf + 7, 4); + } else { + DHD_ERROR(("current timestamp port: %d \n", tsport)); + } + return BCME_OK; + } + } +#endif /* WLMEDIA_HTSF */ + + if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) && + data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) { +#ifdef BCM_FD_AGGR + bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); +#else + bcmerror = BCME_UNSUPPORTED; +#endif + goto done; + } + + if (ioc->cmd == WLC_SET_VAR && data_buf != NULL && + strncmp("qtxpower", data_buf, 8) == 0) { + if (somc_update_qtxpower((char *)data_buf + 9, *((char *)data_buf + 12), 0) != 0) { + DHD_ERROR(("qtxpower on chain0 failed\n")); + bcmerror = BCME_ERROR; + goto done; + } +#ifdef SOMC_MIMO + if (somc_update_qtxpower((char *)data_buf + 10, *((char *)data_buf + 12), 1) != 0) { + DHD_ERROR(("qtxpower on chain1 failed\n")); + bcmerror = BCME_ERROR; + goto done; + } +#else + /* initialize chain1 value just in case since it's not needed for SISO */ + *((char *)data_buf + 10) = 0; +#endif + } + + bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); + +done: + dhd_check_hang(net, pub, bcmerror); + + return bcmerror; +} + +static int +dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + dhd_ioctl_t ioc; + int bcmerror = 0; + int ifidx; + int ret; + void *local_buf = NULL; + u16 buflen = 0; + + DHD_OS_WAKE_LOCK(&dhd->pub); + + /* send to dongle only if we are not waiting for reload already */ + if (dhd->pub.hang_was_sent) { + DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return OSL_ERROR(BCME_DONGLE_DOWN); + } + + ifidx = dhd_net2idx(dhd, net); + DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); + + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return -1; + } + +#if defined(WL_WIRELESS_EXT) + /* linux wireless extensions */ + if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { + /* may recurse, do NOT lock */ + ret = wl_iw_ioctl(net, ifr, cmd); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } +#endif /* defined(WL_WIRELESS_EXT) */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) + if (cmd == SIOCETHTOOL) { + ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ + + if (cmd == SIOCDEVPRIVATE+1) { + ret = wl_android_priv_cmd(net, ifr, cmd); + dhd_check_hang(net, &dhd->pub, ret); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } + + if (cmd != SIOCDEVPRIVATE) { + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return -EOPNOTSUPP; + } + + memset(&ioc, 0, sizeof(ioc)); + +#ifdef CONFIG_COMPAT + if (is_compat_task()) { + compat_wl_ioctl_t compat_ioc; + if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) { + bcmerror = BCME_BADADDR; + goto done; + } + ioc.cmd = compat_ioc.cmd; + ioc.buf = compat_ptr(compat_ioc.buf); + ioc.len = compat_ioc.len; + ioc.set = compat_ioc.set; + ioc.used = compat_ioc.used; + ioc.needed = compat_ioc.needed; + /* To differentiate between wl and dhd read 4 more byes */ + if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), + sizeof(uint)) != 0)) { + bcmerror = BCME_BADADDR; + goto done; + } + } else +#endif /* CONFIG_COMPAT */ + { + /* Copy the ioc control structure part of ioctl request */ + if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { + bcmerror = BCME_BADADDR; + goto done; + } + + /* To differentiate between wl and dhd read 4 more byes */ + if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), + sizeof(uint)) != 0)) { + bcmerror = BCME_BADADDR; + goto done; + } + } + + if (!capable(CAP_NET_ADMIN)) { + bcmerror = BCME_EPERM; + goto done; + } + + if (ioc.len > 0) { + buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); + if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) { + bcmerror = BCME_NOMEM; + goto done; + } + if (copy_from_user(local_buf, ioc.buf, buflen)) { + bcmerror = BCME_BADADDR; + goto done; + } + *(char *)(local_buf + buflen) = '\0'; + } + + bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf); + + if (!bcmerror && buflen && local_buf && ioc.buf) { + if (copy_to_user(ioc.buf, local_buf, buflen)) + bcmerror = -EFAULT; + } + +done: + if (local_buf) + MFREE(dhd->pub.osh, local_buf, buflen+1); + + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + return OSL_ERROR(bcmerror); +} + + + + +static int +dhd_stop(struct net_device *net) +{ + int ifidx = 0; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + + + DHD_OS_WAKE_LOCK(&dhd->pub); + DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); + if (dhd->pub.up == 0) { + goto exit; + } + + + ifidx = dhd_net2idx(dhd, net); + BCM_REFERENCE(ifidx); + + /* Set state and stop OS transmissions */ + netif_stop_queue(net); + dhd->pub.up = 0; + +#ifdef ENABLE_CONTROL_SCHED + dhd_sysfs_destroy_node(net); + dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; + dhd_dpc_poli = SCHED_FIFO; +#endif /* ENABLE_CONTROL_SCHED */ + +#ifdef WL_CFG80211 + if (ifidx == 0) { + wl_cfg80211_down(NULL); + + /* + * For CFG80211: Clean up all the left over virtual interfaces + * when the primary Interface is brought down. [ifconfig wlan0 down] + */ + if (!dhd_download_fw_on_driverload) { + if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && + (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { + int i; + + dhd_net_if_lock_local(dhd); + for (i = 1; i < DHD_MAX_IFS; i++) + dhd_remove_if(&dhd->pub, i, FALSE); + dhd_net_if_unlock_local(dhd); + } + } + } +#endif /* WL_CFG80211 */ + +#ifdef PROP_TXSTATUS + dhd_wlfc_cleanup(&dhd->pub, NULL, 0); +#endif + /* Stop the protocol module */ + dhd_prot_stop(&dhd->pub); + + OLD_MOD_DEC_USE_COUNT; +exit: +#if defined(WL_CFG80211) + if (ifidx == 0 && !dhd_download_fw_on_driverload) + wl_android_wifi_off(net); +#endif + dhd->pub.rxcnt_timeout = 0; + dhd->pub.txcnt_timeout = 0; + + dhd->pub.hang_was_sent = 0; + + /* Clear country spec for for built-in type driver */ + if (!dhd_download_fw_on_driverload) { + dhd->pub.dhd_cspec.country_abbrev[0] = 0x00; + dhd->pub.dhd_cspec.rev = 0; + dhd->pub.dhd_cspec.ccode[0] = 0x00; + } + + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return 0; +} + +#if defined(WL_CFG80211) && defined(USE_INITIAL_SHORT_DWELL_TIME) +extern bool g_first_broadcast_scan; +#endif + +#ifdef WL11U +static int dhd_interworking_enable(dhd_pub_t *dhd) +{ + uint32 enable = true; + int ret = BCME_OK; + + ret = dhd_iovar(dhd, 0, "interworking", (char *)&enable, sizeof(enable), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret)); + } + + if (ret == BCME_OK) { + /* basic capabilities for HS20 REL2 */ + uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF; + ret = dhd_iovar(dhd, 0, "wnm", (char *)&cap, sizeof(cap), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret)); + } + } + + return ret; +} +#endif /* WL11u */ + +#ifdef ENABLE_CONTROL_SCHED +static ssize_t +read_dpc_prio(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) +{ + DHD_INFO(("%s: read cur_prio(%d), cur_poli(%d)\n", + __FUNCTION__, dhd_dpc_prio, dhd_dpc_poli)); + memset(buf, 0, sizeof(uint32)); + count += snprintf(buf, sizeof(uint32), "%d", dhd_dpc_prio + (dhd_dpc_poli * 100)); + return count; +} + +static ssize_t +write_dpc_prio(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, loff_t off, size_t size) +{ + uint32 new_prio = 0; + uint32 cur_prio = dhd_dpc_prio + (dhd_dpc_poli * 100); + + memcpy(&new_prio, buf, sizeof(uint32)); + new_prio = bcm_atoi((char*)&new_prio); + + if (new_prio < 0 || new_prio > 199) { + DHD_ERROR(("%s: ERROR invalid new_prio(%d)\n", + __FUNCTION__, new_prio)); + return -EINVAL; + } + + if (cur_prio != new_prio) { + dhd_dpc_prio = new_prio % 100; + dhd_dpc_poli = new_prio / 100; + DHD_INFO(("%s: write new_prio(%d), new_policy(%d)\n", + __FUNCTION__, dhd_dpc_prio, dhd_dpc_poli)); + } + + return sizeof(uint32); +} + +static struct bin_attribute dpc_prio_attr = { + .attr = {.name = "dpc_prio", .mode = 0644}, + .size = sizeof(uint32), + .read = read_dpc_prio, + .write = write_dpc_prio, +}; + +static int +dhd_sysfs_create_node(struct net_device *net) +{ + int ret; + + DHD_INFO(("%s Enter\n", __func__)); + ret = sysfs_create_bin_file(&net->dev.kobj, &dpc_prio_attr); + + if (ret) { + DHD_ERROR(("%s: create dpc_prio sysfs fail, ret(%d)\n", __FUNCTION__, ret)); + return ret; + } + return 0; +} + +static void +dhd_sysfs_destroy_node(struct net_device *net) +{ + DHD_INFO(("%s Enter\n", __FUNCTION__)); + sysfs_remove_bin_file(&net->dev.kobj, &dpc_prio_attr); +} +#endif /* ENABLE_CONTROL_SCHED */ + + +static int +dhd_open(struct net_device *net) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); +#ifdef TOE + uint32 toe_ol; +#endif + int ifidx; + int32 ret = 0; + + + + + DHD_OS_WAKE_LOCK(&dhd->pub); + dhd->pub.dongle_trap_occured = 0; + dhd->pub.hang_was_sent = 0; +#ifdef DHD_LOSSLESS_ROAMING + dhd->pub.dequeue_prec_map = ALLPRIO; +#endif /* DHD_LOSSLESS_ROAMING */ + +#ifdef ENABLE_CONTROL_SCHED + ret = dhd_sysfs_create_node(net); + if (ret) { + DHD_ERROR(("%s: Failed to setup dpc_prio ret(%d)\n", __FUNCTION__, ret)); + goto exit; + } +#endif /* ENABLE_CONTROL_SCHED */ + +#if !defined(WL_CFG80211) + /* + * Force start if ifconfig_up gets called before START command + * We keep WEXT's wl_control_wl_start to provide backward compatibility + * This should be removed in the future + */ + ret = wl_control_wl_start(net); + if (ret != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } + +#endif + + ifidx = dhd_net2idx(dhd, net); + DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); + + if (ifidx < 0) { + DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__)); + ret = -1; + goto exit; + } + + if (!dhd->iflist[ifidx]) { + DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); + ret = -1; + goto exit; + } + + if (ifidx == 0) { + atomic_set(&dhd->pend_8021x_cnt, 0); +#if defined(WL_CFG80211) + if (!dhd_download_fw_on_driverload) { + DHD_ERROR(("\n%s\n", dhd_version)); +#if defined(USE_INITIAL_SHORT_DWELL_TIME) + g_first_broadcast_scan = TRUE; +#endif + ret = wl_android_wifi_on(net); + if (ret != 0) { + DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n", + __FUNCTION__, ret)); + ret = -1; + goto exit; + } + } +#endif + + if (dhd->pub.busstate != DHD_BUS_DATA) { + + /* try to bring up bus */ + if ((ret = dhd_bus_start(&dhd->pub)) != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } + + } + + /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */ + memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); + +#ifdef TOE + /* Get current TOE mode from dongle */ + if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) + dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; + else + dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; +#endif /* TOE */ + +#if defined(WL_CFG80211) + if (unlikely(wl_cfg80211_up(NULL))) { + DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); + ret = -1; + goto exit; + } +#endif /* WL_CFG80211 */ + } + + /* Allow transmit calls */ + netif_start_queue(net); + dhd->pub.up = 1; + +#ifdef BCMDBGFS + dhd_dbg_init(&dhd->pub); +#endif + + OLD_MOD_INC_USE_COUNT; +exit: + if (ret) + dhd_stop(net); + + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + + return ret; +} + +int dhd_do_driver_init(struct net_device *net) +{ + dhd_info_t *dhd = NULL; + + if (!net) { + DHD_ERROR(("Primary Interface not initialized \n")); + return -EINVAL; + } + + + /* && defined(OEM_ANDROID) && defined(BCMSDIO) */ + dhd = *(dhd_info_t **)netdev_priv(net); + + /* If driver is already initialized, do nothing + */ + if (dhd->pub.busstate == DHD_BUS_DATA) { + DHD_TRACE(("Driver already Inititalized. Nothing to do")); + return 0; + } + + if (dhd_open(net) < 0) { + DHD_ERROR(("Driver Init Failed \n")); + return -1; + } + + return 0; +} + +int +dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) +{ + +#ifdef WL_CFG80211 + if (wl_cfg80211_notify_ifadd(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) + return BCME_OK; +#endif + + /* handle IF event caused by wl commands, SoftAP, WEXT and + * anything else. This has to be done asynchronously otherwise + * DPC will be blocked (and iovars will timeout as DPC has no chance + * to read the response back) + */ + if (ifevent->ifidx > 0) { + dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); + + memcpy(&if_event->event, ifevent, sizeof(if_event->event)); + memcpy(if_event->mac, mac, ETHER_ADDR_LEN); + strncpy(if_event->name, name, IFNAMSIZ); + if_event->name[IFNAMSIZ - 1] = '\0'; + dhd_deferred_schedule_work((void *)if_event, DHD_WQ_WORK_IF_ADD, + dhd_ifadd_event_handler, DHD_WORK_PRIORITY_LOW); + } + + return BCME_OK; +} + +int +dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) +{ + dhd_if_event_t *if_event; + +#ifdef WL_CFG80211 + if (wl_cfg80211_notify_ifdel(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) + return BCME_OK; +#endif /* WL_CFG80211 */ + + /* handle IF event caused by wl commands, SoftAP, WEXT and + * anything else + */ + if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); + memcpy(&if_event->event, ifevent, sizeof(if_event->event)); + memcpy(if_event->mac, mac, ETHER_ADDR_LEN); + strncpy(if_event->name, name, IFNAMSIZ); + if_event->name[IFNAMSIZ - 1] = '\0'; + dhd_deferred_schedule_work((void *)if_event, DHD_WQ_WORK_IF_DEL, + dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW); + + return BCME_OK; +} + +/* unregister and free the existing net_device interface (if any) in iflist and + * allocate a new one. the slot is reused. this function does NOT register the + * new interface to linux kernel. dhd_register_if does the job + */ +struct net_device* +dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name, + uint8 *mac, uint8 bssidx, bool need_rtnl_lock) +{ + dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; + dhd_if_t *ifp; + + ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS)); + ifp = dhdinfo->iflist[ifidx]; + + if (ifp != NULL) { + if (ifp->net != NULL) { + DHD_ERROR(("%s: free existing IF %s\n", __FUNCTION__, ifp->net->name)); + + /* in unregister_netdev case, the interface gets freed by net->destructor + * (which is set to free_netdev) + */ + if (ifp->net->reg_state == NETREG_UNINITIALIZED) { + free_netdev(ifp->net); + } else { + netif_stop_queue(ifp->net); + if (need_rtnl_lock) + unregister_netdev(ifp->net); + else + unregister_netdevice(ifp->net); + } + ifp->net = NULL; + } + } else { + ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t)); + if (ifp == NULL) { + DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t))); + return NULL; + } + } + + memset(ifp, 0, sizeof(dhd_if_t)); + ifp->info = dhdinfo; + ifp->idx = ifidx; + ifp->bssidx = bssidx; + if (mac != NULL) + memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN); + + /* Allocate etherdev, including space for private structure */ + ifp->net = alloc_etherdev(sizeof(dhdinfo)); + if (ifp->net == NULL) { + DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo))); + goto fail; + } + memcpy(netdev_priv(ifp->net), &dhdinfo, sizeof(dhdinfo)); + if (name && name[0]) { + strncpy(ifp->net->name, name, IFNAMSIZ); + ifp->net->name[IFNAMSIZ - 1] = '\0'; + } +#ifdef WL_CFG80211 + if (ifidx == 0) + ifp->net->destructor = free_netdev; + else + ifp->net->destructor = dhd_netdev_free; +#else + ifp->net->destructor = free_netdev; +#endif /* WL_CFG80211 */ + strncpy(ifp->name, ifp->net->name, IFNAMSIZ); + ifp->name[IFNAMSIZ - 1] = '\0'; + dhdinfo->iflist[ifidx] = ifp; + return ifp->net; + +fail: + if (ifp != NULL) { + if (ifp->net != NULL) { + free_netdev(ifp->net); + ifp->net = NULL; + } + MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); + ifp = NULL; + } + dhdinfo->iflist[ifidx] = NULL; + return NULL; +} + +/* unregister and free the the net_device interface associated with the indexed + * slot, also free the slot memory and set the slot pointer to NULL + */ +int +dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) +{ + dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; + dhd_if_t *ifp; + + ifp = dhdinfo->iflist[ifidx]; + if (ifp != NULL) { + if (ifp->net != NULL) { + DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx)); + + /* in unregister_netdev case, the interface gets freed by net->destructor + * (which is set to free_netdev) + */ + if (ifp->net->reg_state == NETREG_UNINITIALIZED) { + free_netdev(ifp->net); + } else { + netif_stop_queue(ifp->net); + + if (need_rtnl_lock) + unregister_netdev(ifp->net); + else + unregister_netdevice(ifp->net); + } + ifp->net = NULL; + } + + dhdinfo->iflist[ifidx] = NULL; + MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); + + } + + return BCME_OK; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) +static struct net_device_ops dhd_ops_pri = { + .ndo_open = dhd_open, + .ndo_stop = dhd_stop, + .ndo_get_stats = dhd_get_stats, + .ndo_do_ioctl = dhd_ioctl_entry, + .ndo_start_xmit = dhd_start_xmit, + .ndo_set_mac_address = dhd_set_mac_address, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + .ndo_set_rx_mode = dhd_set_multicast_list, +#else + .ndo_set_multicast_list = dhd_set_multicast_list, +#endif +}; + +static struct net_device_ops dhd_ops_virt = { + .ndo_get_stats = dhd_get_stats, + .ndo_do_ioctl = dhd_ioctl_entry, + .ndo_start_xmit = dhd_start_xmit, + .ndo_set_mac_address = dhd_set_mac_address, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + .ndo_set_rx_mode = dhd_set_multicast_list, +#else + .ndo_set_multicast_list = dhd_set_multicast_list, +#endif +}; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ + +#ifdef DEBUGGER +extern void debugger_init(void *bus_handle); +#endif + + +dhd_pub_t * +dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) +{ + dhd_info_t *dhd = NULL; + struct net_device *net = NULL; + char if_name[IFNAMSIZ] = {'\0'}; + uint32 bus_type = -1; + uint32 bus_num = -1; + uint32 slot_num = -1; + wifi_adapter_info_t *adapter = NULL; +#ifdef CUSTOM_COUNTRY_CODE + struct cntry_locales_custom *cloc_ptr = NULL; +#endif /* CUSTOM_COUNTRY_CODE */ + + dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* will implement get_ids for DBUS later */ + dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); + adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); + + /* Allocate primary dhd_info */ + dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t)); + if (dhd == NULL) { + dhd = MALLOC(osh, sizeof(dhd_info_t)); + if (dhd == NULL) { + DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); + goto fail; + } + } + memset(dhd, 0, sizeof(dhd_info_t)); + dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; + + dhd->pub.osh = osh; + dhd->adapter = adapter; + +#ifdef GET_CUSTOM_MAC_ENABLE + wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet); +#endif /* GET_CUSTOM_MAC_ENABLE */ +#ifdef CUSTOM_COUNTRY_CODE + cloc_ptr = wifi_platform_get_country_code(dhd->adapter, dhd->pub.dhd_cspec.ccode); + if (cloc_ptr) { + strlcpy(dhd->pub.dhd_cspec.country_abbrev, cloc_ptr->iso_abbrev, WLC_CNTRY_BUF_SZ); + strlcpy(dhd->pub.dhd_cspec.ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); + dhd->pub.dhd_cspec.rev = cloc_ptr->custom_locale_rev; + get_customized_country_code(dhd->adapter, dhd->pub.dhd_cspec.ccode, + &dhd->pub.dhd_cspec); + } +#endif /* CUSTOM_COUNTRY_CODE */ + dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; + dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; + + /* Initialize thread based operation and lock */ + sema_init(&dhd->sdsem, 1); + + /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name. + * This is indeed a hack but we have to make it work properly before we have a better + * solution + */ + dhd_update_fw_nv_path(dhd); + + /* Link to info module */ + dhd->pub.info = dhd; + /* Link to bus module */ + dhd->pub.bus = bus; + dhd->pub.hdrlen = bus_hdrlen; + + /* Set network interface name if it was provided as module parameter */ + if (iface_name[0]) { + int len; + char ch; + strncpy(if_name, iface_name, IFNAMSIZ); + if_name[IFNAMSIZ - 1] = 0; + len = strlen(if_name); + ch = if_name[len - 1]; + if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) + strcat(if_name, "%d"); + } + net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE); + if (net == NULL) + goto fail; + dhd_state |= DHD_ATTACH_STATE_ADD_IF; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + net->open = NULL; +#else + net->netdev_ops = NULL; +#endif + + sema_init(&dhd->proto_sem, 1); + +#ifdef PROP_TXSTATUS + spin_lock_init(&dhd->wlfc_spinlock); + + dhd->pub.skip_fc = dhd_wlfc_skip_fc; + dhd->pub.plat_init = dhd_wlfc_plat_init; + dhd->pub.plat_deinit = dhd_wlfc_plat_deinit; +#endif /* PROP_TXSTATUS */ + + /* Initialize other structure content */ + init_waitqueue_head(&dhd->ioctl_resp_wait); + init_waitqueue_head(&dhd->ctrl_wait); + + /* Initialize the spinlocks */ + spin_lock_init(&dhd->sdlock); + spin_lock_init(&dhd->txqlock); + spin_lock_init(&dhd->dhd_lock); + spin_lock_init(&dhd->rxf_lock); +#if defined(RXFRAME_THREAD) + dhd->rxthread_enabled = TRUE; +#endif /* defined(RXFRAME_THREAD) */ + +#ifdef DHDTCPACK_SUPPRESS + spin_lock_init(&dhd->tcpack_lock); +#endif /* DHDTCPACK_SUPPRESS */ + + /* Initialize Wakelock stuff */ + spin_lock_init(&dhd->wakelock_spinlock); + dhd->wakelock_counter = 0; + dhd->wakelock_wd_counter = 0; + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; + dhd->waive_wakelock = FALSE; +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); + wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); + wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); + wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); +#endif /* CONFIG_HAS_WAKELOCK */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_init(&dhd->dhd_net_if_mutex); + mutex_init(&dhd->dhd_suspend_mutex); +#endif + dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; + + /* Attach and link in the protocol */ + if (dhd_prot_attach(&dhd->pub) != 0) { + DHD_ERROR(("dhd_prot_attach failed\n")); + goto fail; + } + dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; + +#ifdef WL_CFG80211 + /* Attach and link in the cfg80211 */ + if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { + DHD_ERROR(("wl_cfg80211_attach failed\n")); + goto fail; + } + + dhd_monitor_init(&dhd->pub); + dhd_state |= DHD_ATTACH_STATE_CFG80211; +#endif +#if defined(WL_WIRELESS_EXT) + /* Attach and link in the iw */ + if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { + if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { + DHD_ERROR(("wl_iw_attach failed\n")); + goto fail; + } + dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; + } +#endif /* defined(WL_WIRELESS_EXT) */ + + + /* Set up the watchdog timer */ + init_timer(&dhd->timer); + dhd->timer.data = (ulong)dhd; + dhd->timer.function = dhd_watchdog; + dhd->default_wd_interval = dhd_watchdog_ms; + + if (dhd_watchdog_prio >= 0) { + /* Initialize watchdog thread */ + PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); + + } else { + dhd->thr_wdt_ctl.thr_pid = -1; + } + +#ifdef DEBUGGER + debugger_init((void *) bus); +#endif + + /* Set up the bottom half handler */ + if (dhd_dpc_prio >= 0) { + /* Initialize DPC thread */ + PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); + } else { + /* use tasklet for dpc */ + tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); + dhd->thr_dpc_ctl.thr_pid = -1; + } + + if (dhd->rxthread_enabled) { + bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND); + /* Initialize RXF thread */ + PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf"); + } + + dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; + + /* + * Save the dhd_info into the priv + */ + memcpy(netdev_priv(net), &dhd, sizeof(dhd)); + +#if defined(CONFIG_PM_SLEEP) + dhd->pm_notifier.notifier_call = dhd_pm_callback; + dhd->pm_notifier.priority = 10; + if (!dhd_pm_notifier_registered) { + dhd_pm_notifier_registered = TRUE; + register_pm_notifier(&dhd->pm_notifier); + } +#endif /* CONFIG_PM_SLEEP */ + +#ifdef SAR_SUPPORT + dhd->sar_notifier.notifier_call = dhd_sar_callback; + if (!dhd_sar_notifier_registered) { + dhd_sar_notifier_registered = TRUE; + register_notifier_by_sar(&dhd->sar_notifier); + } +#endif + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) + dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; + dhd->early_suspend.suspend = dhd_early_suspend; + dhd->early_suspend.resume = dhd_late_resume; + register_early_suspend(&dhd->early_suspend); + dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ + +#ifdef ARP_OFFLOAD_SUPPORT + dhd->pend_ipaddr = 0; + if (!dhd_inetaddr_notifier_registered) { + dhd_inetaddr_notifier_registered = TRUE; + register_inetaddr_notifier(&dhd_inetaddr_notifier); + } +#endif /* ARP_OFFLOAD_SUPPORT */ + if (!dhd_inet6addr_notifier_registered) { + dhd_inet6addr_notifier_registered = TRUE; + register_inet6addr_notifier(&dhd_inet6addr_notifier); + } + dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd); +#ifdef DEBUG_CPU_FREQ + dhd->new_freq = alloc_percpu(int); + dhd->freq_trans.notifier_call = dhd_cpufreq_notifier; + cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); +#endif +#ifdef DHDTCPACK_SUPPRESS + dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DELAYTX); +#endif /* DHDTCPACK_SUPPRESS */ +#ifdef DHD_DEBUG + dhd->join_timeout_val = DHD_JOIN_MAX_TIME_DEFAULT; + dhd->scan_time_count = DHD_SCAN_DEF_TIMEOUT; +#endif + dhd_state |= DHD_ATTACH_STATE_DONE; + dhd->dhd_state = dhd_state; + + dhd->unit = dhd_found + instance_base; + dhd_found++; + return &dhd->pub; + +fail: + if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) { + DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", + __FUNCTION__, dhd_state, &dhd->pub)); + dhd->dhd_state = dhd_state; + dhd_detach(&dhd->pub); + dhd_free(&dhd->pub); + } + + return NULL; +} + +int dhd_get_fw_mode(dhd_info_t *dhdinfo) +{ + if (strstr(dhdinfo->fw_path, "_apsta") != NULL) + return DHD_FLAG_HOSTAP_MODE; + if (strstr(dhdinfo->fw_path, "_p2p") != NULL) + return DHD_FLAG_P2P_MODE; + if (strstr(dhdinfo->fw_path, "_ibss") != NULL) + return DHD_FLAG_IBSS_MODE; + if (strstr(dhdinfo->fw_path, "_mfg") != NULL) + return DHD_FLAG_MFG_MODE; + + return DHD_FLAG_STA_MODE; +} + +bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) +{ + int fw_len; + int nv_len; + const char *fw = NULL; + const char *nv = NULL; + wifi_adapter_info_t *adapter = dhdinfo->adapter; + + + /* Update firmware and nvram path. The path may be from adapter info or module parameter + * The path from adapter info is used for initialization only (as it won't change). + * + * The firmware_path/nvram_path module parameter may be changed by the system at run + * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private + * command may change dhdinfo->fw_path. As such we need to clear the path info in + * module parameter after it is copied. We won't update the path until the module parameter + * is changed again (first character is not '\0') + */ + + /* set default firmware and nvram path for built-in type driver */ + if (!dhd_download_fw_on_driverload) { +#ifdef CONFIG_BCMDHD_FW_PATH + fw = CONFIG_BCMDHD_FW_PATH; +#endif /* CONFIG_BCMDHD_FW_PATH */ +#ifdef CONFIG_BCMDHD_NVRAM_PATH + nv = CONFIG_BCMDHD_NVRAM_PATH; +#endif /* CONFIG_BCMDHD_NVRAM_PATH */ + } + + /* check if we need to initialize the path */ + if (dhdinfo->fw_path[0] == '\0') { + if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0') + fw = adapter->fw_path; + + } + if (dhdinfo->nv_path[0] == '\0') { + if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0') + nv = adapter->nv_path; + } + + /* Use module parameter if it is valid, EVEN IF the path has not been initialized + * + * TODO: need a solution for multi-chip, can't use the same firmware for all chips + */ + if (firmware_path[0] != '\0') + fw = firmware_path; + if (nvram_path[0] != '\0') + nv = nvram_path; + + if (fw && fw[0] != '\0') { + fw_len = strlen(fw); + if (fw_len >= sizeof(dhdinfo->fw_path)) { + DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n")); + return FALSE; + } + strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path)); + if (dhdinfo->fw_path[fw_len-1] == '\n') + dhdinfo->fw_path[fw_len-1] = '\0'; + } + if (nv && nv[0] != '\0') { + nv_len = strlen(nv); + if (nv_len >= sizeof(dhdinfo->nv_path)) { + DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n")); + return FALSE; + } + strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path)); + if (dhdinfo->nv_path[nv_len-1] == '\n') + dhdinfo->nv_path[nv_len-1] = '\0'; + } + + /* clear the path in module parameter */ + firmware_path[0] = '\0'; + nvram_path[0] = '\0'; + + if (dhdinfo->fw_path[0] == '\0') { + DHD_ERROR(("firmware path not found\n")); + return FALSE; + } + if (dhdinfo->nv_path[0] == '\0') { + DHD_ERROR(("nvram path not found\n")); + return FALSE; + } + + return TRUE; +} + + +int +dhd_bus_start(dhd_pub_t *dhdp) +{ + int ret = -1; + dhd_info_t *dhd = (dhd_info_t*)dhdp->info; + unsigned long flags; + + ASSERT(dhd); + + DHD_TRACE(("Enter %s:\n", __FUNCTION__)); + + /* try to download image and nvram to the dongle */ + if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) { + DHD_INFO(("%s download fw %s, nv %s\n", __FUNCTION__, dhd->fw_path, dhd->nv_path)); + ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, + dhd->fw_path, dhd->nv_path); + if (ret < 0) { + DHD_ERROR(("%s: failed to download firmware %s\n", + __FUNCTION__, dhd->fw_path)); + return ret; + } + } + if (dhd->pub.busstate != DHD_BUS_LOAD) { + return -ENETDOWN; + } + + dhd_os_sdlock(dhdp); + + /* Start the watchdog timer */ + dhd->pub.tickcnt = 0; + dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); + + /* Bring up the bus */ + if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { + + DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); + dhd_os_sdunlock(dhdp); + return ret; + } +#if defined(OOB_INTR_ONLY) + /* Host registration for OOB interrupt */ + if (dhd_bus_oob_intr_register(dhdp)) { + /* deactivate timer and wait for the handler to finish */ + + flags = dhd_os_spin_lock(&dhd->pub); + dhd->wd_timer_valid = FALSE; + dhd_os_spin_unlock(&dhd->pub, flags); + del_timer_sync(&dhd->timer); + + DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); + dhd_os_sdunlock(dhdp); + DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); + return -ENODEV; + } + + /* Enable oob at firmware */ + dhd_enable_oob_intr(dhd->pub.bus, TRUE); +#endif + + /* If bus is not ready, can't come up */ + if (dhd->pub.busstate != DHD_BUS_DATA) { + flags = dhd_os_spin_lock(&dhd->pub); + dhd->wd_timer_valid = FALSE; + dhd_os_spin_unlock(&dhd->pub, flags); + del_timer_sync(&dhd->timer); + DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); + dhd_os_sdunlock(dhdp); + DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); + return -ENODEV; + } + + dhd_os_sdunlock(dhdp); + + dhd_process_cid_mac(dhdp, TRUE); + + /* Bus is ready, do any protocol initialization */ + if ((ret = dhd_prot_init(&dhd->pub)) < 0) + return ret; + + dhd_process_cid_mac(dhdp, FALSE); + +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd->pend_ipaddr) { +#ifdef AOE_IP_ALIAS_SUPPORT + aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); +#endif /* AOE_IP_ALIAS_SUPPORT */ + dhd->pend_ipaddr = 0; + } +#endif /* ARP_OFFLOAD_SUPPORT */ + + return 0; +} +#ifdef WLTDLS +int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac) +{ + uint32 tdls = tdls_on; + int ret = 0; + uint32 tdls_auto_op = 0; + uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING; + int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH; + int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW; + BCM_REFERENCE(mac); + if (!FW_SUPPORTED(dhd, tdls)) + return BCME_ERROR; + + if (dhd->tdls_enable == tdls_on) + goto auto_mode; + ret = dhd_iovar(dhd, 0, "tdls_enable", (char *)&tdls, sizeof(tdls), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret)); + goto exit; + } + dhd->tdls_enable = tdls_on; +auto_mode: + + tdls_auto_op = auto_on; + ret = dhd_iovar(dhd, 0, "tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), NULL, + 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); + goto exit; + } + + if (tdls_auto_op) { + ret = dhd_iovar(dhd, 0, "tdls_idle_time", (char *)&tdls_idle_time, + sizeof(tdls_idle_time), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); + goto exit; + } + ret = dhd_iovar(dhd, 0, "tdls_rssi_high", (char *)&tdls_rssi_high, + sizeof(tdls_rssi_high), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret)); + goto exit; + } + ret = dhd_iovar(dhd, 0, "tdls_rssi_low", (char *)&tdls_rssi_low, + sizeof(tdls_rssi_low), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret)); + goto exit; + } + } + +exit: + return ret; +} +int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + if (dhd) + ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac); + else + ret = BCME_ERROR; + return ret; +} +#endif + +bool dhd_is_concurrent_mode(dhd_pub_t *dhd) +{ + if (!dhd) + return FALSE; + + if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) + return TRUE; + else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == + DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) + return TRUE; + else + return FALSE; +} +#if !defined(AP) && defined(WLP2P) +/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware + * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA + * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware + * would still be named as fw_bcmdhd_apsta. + */ +uint32 +dhd_get_concurrent_capabilites(dhd_pub_t *dhd) +{ + int32 ret = 0; + char buf[WLC_IOCTL_SMLEN]; + bool mchan_supported = FALSE; + /* if dhd->op_mode is already set for HOSTAP and Manufacturing + * test mode, that means we only will use the mode as it is + */ + if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE)) + return 0; + if (FW_SUPPORTED(dhd, vsdb)) { + mchan_supported = TRUE; + } + if (!FW_SUPPORTED(dhd, p2p)) { + DHD_TRACE(("Chip does not support p2p\n")); + return 0; + } + else { + /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ + memset(buf, 0, sizeof(buf)); + ret = dhd_iovar(dhd, 0, "p2p", NULL, 0, (char *)buf, + sizeof(buf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); + return 0; + } + else { + if (buf[0] == 1) { + /* By default, chip supports single chan concurrency, + * now lets check for mchan + */ + ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; + if (mchan_supported) + ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; +#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) + /* For customer_hw4, although ICS, + * we still support concurrent mode + */ + return ret; +#else + return 0; +#endif + } + } + } + return 0; +} +#endif + + +int +dhd_preinit_ioctls(dhd_pub_t *dhd) +{ + int ret = 0; + char eventmask[WL_EVENTING_MASK_LEN]; + char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ + uint32 buf_key_b4_m4 = 1; + uint8 msglen; + eventmsgs_ext_t *eventmask_msg = NULL; + char* iov_buf = NULL; + int ret2 = 0; +#ifdef WLAIBSS + aibss_bcn_force_config_t bcn_config; + uint32 aibss; +#endif +#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ + defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) + uint32 ampdu_ba_wsize = 0; +#endif /* CUSTOM_AMPDU_BA_WSIZE ||(WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ +#if defined(CUSTOM_AMPDU_MPDU) + uint32 ampdu_mpdu = 0; +#endif + +#ifdef PROP_TXSTATUS + int wlfc_enable = TRUE; +#ifndef DISABLE_11N + uint32 hostreorder = 1; +#endif /* DISABLE_11N */ +#endif /* PROP_TXSTATUS */ + +#ifdef DHD_ENABLE_LPC + uint32 lpc = 1; +#endif /* DHD_ENABLE_LPC */ + uint power_mode = PM_FAST; + uint32 dongle_align = DHD_SDALIGN; + uint32 glom = CUSTOM_GLOM_SETTING; +#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) + uint32 credall = 1; +#endif +#ifdef SOMC_WLAN_BCN_TIMEOUT + uint bcn_timeout = SOMC_WLAN_BCN_TIMEOUT; +#else +#if defined(VSDB) || defined(ROAM_ENABLE) + uint bcn_timeout = 8; +#else + uint bcn_timeout = 4; +#endif +#endif /* SOMC_WLAN_BCN_TIMEOUT */ + uint retry_max = 7; +#if defined(ARP_OFFLOAD_SUPPORT) + int arpoe = 1; +#endif + int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; + int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; + int scan_passive_time = DHD_SCAN_PASSIVE_TIME; + char buf[WLC_IOCTL_SMLEN]; + char *ptr; + uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ +#ifdef ROAM_ENABLE + uint roamvar = 0; + int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; + int roam_scan_period[2] = {10, WLC_BAND_ALL}; + int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; +#ifdef ROAM_AP_ENV_DETECTION + int roam_env_mode = AP_ENV_INDETERMINATE; +#endif /* ROAM_AP_ENV_DETECTION */ +#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC + int roam_fullscan_period = 60; +#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ + int roam_fullscan_period = 120; +#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ +#else +#ifdef DISABLE_BUILTIN_ROAM + uint roamvar = 1; +#endif /* DISABLE_BUILTIN_ROAM */ +#endif /* ROAM_ENABLE */ + +#if defined(SOFTAP) + uint dtim = 1; +#endif +#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) + uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ + struct ether_addr p2p_ea; +#endif +#ifdef BCMCCX + uint32 ccx = 1; +#endif + +#ifdef SET_RETRY_LIMIT + uint srl = CUSTOM_SRL_SETTING; + uint lrl = CUSTOM_LRL_SETTING; +#endif /* SET_RETRY_LIMIT */ +#if defined(AP) || defined(WLP2P) + uint32 apsta = 1; /* Enable APSTA mode */ +#endif /* defined(AP) || defined(WLP2P) */ +#ifdef GET_CUSTOM_MAC_ENABLE + struct ether_addr ea_addr; +#endif /* GET_CUSTOM_MAC_ENABLE */ + +#ifdef DISABLE_11N + uint32 nmode = 0; +#endif /* DISABLE_11N */ + + uint32 vhtmode = 0; +#ifdef USE_WL_TXBF + uint32 txbf = 1; +#endif /* USE_WL_TXBF */ +#ifdef DISABLE_TXBFR + uint32 txbf_bfr_cap = 0; +#endif /* DISABLE_TXBFR */ +#ifdef AMPDU_VO_ENABLE + struct ampdu_tid_control tid; +#endif +#ifdef USE_WL_FRAMEBURST + uint32 frameburst = 1; +#endif /* USE_WL_FRAMEBURST */ +#ifdef DHD_SET_FW_HIGHSPEED + uint32 ack_ratio = 250; + uint32 ack_ratio_depth = 64; +#endif /* DHD_SET_FW_HIGHSPEED */ +#ifdef SUPPORT_2G_VHT + uint32 vht_features = 0x3; /* 2G enable | rates all */ +#endif /* SUPPORT_2G_VHT */ +#ifdef DISABLE_11N_PROPRIETARY_RATES + uint32 ht_features = 0; +#endif /* DISABLE_11N_PROPRIETARY_RATES */ +#ifdef CUSTOM_PSPRETEND_THR + uint32 pspretend_thr = CUSTOM_PSPRETEND_THR; +#endif +#ifdef DISABLE_BCN_DLY + uint bcn_to_dly = 0; +#endif + +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = TRUE; +#endif /* PKT_FILTER_SUPPORT */ +#ifdef WLTDLS + dhd->tdls_enable = FALSE; +#endif /* WLTDLS */ + dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; + DHD_TRACE(("Enter %s\n", __FUNCTION__)); + dhd->op_mode = 0; + if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || + (op_mode == DHD_FLAG_MFG_MODE)) { + /* Check and adjust IOCTL response timeout for Manufactring firmware */ + dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT); + DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n", + __FUNCTION__)); + } + else { + dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); + DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__)); + } +#ifdef GET_CUSTOM_MAC_ENABLE + ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet); + if (!ret) { + ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)&ea_addr, ETHER_ADDR_LEN, NULL, 0, + TRUE); + if (ret < 0) { + DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); + return BCME_NOTUP; + } + memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN); + } else { +#endif /* GET_CUSTOM_MAC_ENABLE */ + /* Get the default device MAC address directly from firmware */ + ret = dhd_iovar(dhd, 0, "cur_etheraddr", NULL, 0, (char *)buf, sizeof(buf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); + return BCME_NOTUP; + } + /* Update public MAC address after reading from Firmware */ + memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); + +#ifdef GET_CUSTOM_MAC_ENABLE + } +#endif /* GET_CUSTOM_MAC_ENABLE */ + /* get a capabilities from firmware */ + memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities)); + ret = dhd_iovar(dhd, 0, "cap", NULL, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities), + FALSE); + if (ret < 0) { + DHD_ERROR(("%s: Get Capability failed (error=%d)\n", + __FUNCTION__, ret)); + return 0; + } + if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) || + (op_mode == DHD_FLAG_HOSTAP_MODE)) { +#ifdef SET_RANDOM_MAC_SOFTAP + uint rand_mac; +#endif + dhd->op_mode = DHD_FLAG_HOSTAP_MODE; +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 0; +#endif +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = FALSE; +#endif +#ifdef SET_RANDOM_MAC_SOFTAP + SRANDOM32((uint)jiffies); + rand_mac = RANDOM32(); + iovbuf[0] = 0x02; /* locally administered bit */ + iovbuf[1] = 0x1A; + iovbuf[2] = 0x11; + iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; + iovbuf[4] = (unsigned char)(rand_mac >> 8); + iovbuf[5] = (unsigned char)(rand_mac >> 16); + + ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)iovbuf, ETHER_ADDR_LEN, NULL, 0, + TRUE); + if (ret < 0) { + DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); + } else + memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); +#endif /* SET_RANDOM_MAC_SOFTAP */ +#if !defined(AP) && defined(WL_CFG80211) + /* Turn off MPC in AP mode */ + ret = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, + TRUE); + if (ret < 0) { + DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); + } +#endif +#ifdef SET_RETRY_LIMIT + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SRL, (char *)&srl, + sizeof(srl), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set SRL failed %d\n", __FUNCTION__, ret)); + } + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_LRL, (char *)&lrl, + sizeof(lrl), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set LRL failed %d\n", __FUNCTION__, ret)); + } +#endif /* SET_RETRY_LIMIT */ + } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || + (op_mode == DHD_FLAG_MFG_MODE)) { +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 0; +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = FALSE; +#endif /* PKT_FILTER_SUPPORT */ + dhd->op_mode = DHD_FLAG_MFG_MODE; + } else { + uint32 concurrent_mode = 0; + if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) || + (op_mode == DHD_FLAG_P2P_MODE)) { +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 0; +#endif +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = FALSE; +#endif + dhd->op_mode = DHD_FLAG_P2P_MODE; + } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) || + (op_mode == DHD_FLAG_IBSS_MODE)) { + dhd->op_mode = DHD_FLAG_IBSS_MODE; + } else + dhd->op_mode = DHD_FLAG_STA_MODE; +#if !defined(AP) && defined(WLP2P) + if (dhd->op_mode != DHD_FLAG_IBSS_MODE && + (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 1; +#endif + dhd->op_mode |= concurrent_mode; + } + + /* Check if we are enabling p2p */ + if (dhd->op_mode & DHD_FLAG_P2P_MODE) { + ret = dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, + TRUE); + if (ret < 0) + DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret)); + + memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); + ETHER_SET_LOCALADDR(&p2p_ea); + ret = dhd_iovar(dhd, 0, "p2p_da_override", (char *)&p2p_ea, + sizeof(p2p_ea), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); + else + DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); + } +#else + (void)concurrent_mode; +#endif + } + + DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n", + dhd->op_mode, MAC2STRDBG(dhd->mac.octet))); + /* Set Country code */ + if (dhd->dhd_cspec.ccode[0] != 0) { + ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); + } + +#if !defined(DISABLE_11AC) + if (somc_disable_vht) + { +#endif /* ! DISABLE_11AC */ + ret = dhd_iovar(dhd, 0, "vhtmode", (char *)&vhtmode, sizeof(vhtmode), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s wl vhtmode 0 failed %d\n", __FUNCTION__, ret)); + else + DHD_ERROR(("%s VHT(11ac) mode is disabled\n", __FUNCTION__)); +#if !defined(DISABLE_11AC) + } +#endif /* ! DISABLE_11AC */ + + /* Set Listen Interval */ + ret = dhd_iovar(dhd, 0, "assoc_listen", (char *)&listen_interval, sizeof(listen_interval), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); + +#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) + /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ + dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), NULL, 0, TRUE); +#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ +#if defined(ROAM_ENABLE) + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, + sizeof(roam_scan_period), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret)); + if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, + sizeof(roam_delta), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); + ret = dhd_iovar(dhd, 0, "fullroamperiod", (char *)&roam_fullscan_period, + sizeof(roam_fullscan_period), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); +#ifdef ROAM_AP_ENV_DETECTION + if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) { + ret = dhd_iovar(dhd, 0, "roam_env_detection", (char *)&roam_env_mode, + sizeof(roam_env_mode), NULL, 0, TRUE); + if (ret == BCME_OK) + dhd->roam_env_detection = TRUE; + else + dhd->roam_env_detection = FALSE; + } +#endif /* ROAM_AP_ENV_DETECTION */ +#endif /* ROAM_ENABLE */ + +#ifdef BCMCCX + dhd_iovar(dhd, 0, "ccx_enable", (char *)&ccx, sizeof(ccx), NULL, 0, TRUE); +#endif /* BCMCCX */ +#ifdef WLTDLS + /* by default TDLS on and auto mode off */ + _dhd_tdls_enable(dhd, true, false, NULL); +#endif /* WLTDLS */ + +#ifdef DHD_ENABLE_LPC + /* Set lpc 1 */ + ret = dhd_iovar(dhd, 0, "lpc", (char *)&lpc, sizeof(lpc), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); + } +#endif /* DHD_ENABLE_LPC */ + + /* Set PowerSave mode */ + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); + + /* Match Host and Dongle rx alignment */ + dhd_iovar(dhd, 0, "bus:txglomalign", (char *)&dongle_align, sizeof(dongle_align), + NULL, 0, TRUE); +#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) + /* enable credall to reduce the chance of no bus credit happened. */ + dhd_iovar(dhd, 0, "bus:credall", (char *)&credall, sizeof(credall), NULL, 0, TRUE); +#endif + + if (glom != DEFAULT_GLOM_VALUE) { + DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom)); + dhd_iovar(dhd, 0, "bus:txglom", (char *)&glom, sizeof(glom), NULL, 0, TRUE); + } + + /* Setup timeout if Beacons are lost and roam is off to report link down */ + dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, sizeof(bcn_timeout), NULL, 0, TRUE); +#ifdef SOMC_WLAN_SCAN_NPROBES + { + const uint32 scan_nprobes = SOMC_WLAN_SCAN_NPROBES; + if (( ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_NPROBES, (char *)&scan_nprobes, + sizeof(scan_nprobes), TRUE, 0)) < 0) + DHD_ERROR(("%s: set scan_nprobes failed %d\n", __FUNCTION__, ret)); + } +#endif + +#ifdef DISABLE_BCN_DLY + /* Set bcn_to_dly to delay link down until roam complete */ + dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, sizeof(bcn_to_dly), NULL, 0, TRUE); +#endif + /* Setup assoc_retry_max count to reconnect target AP in dongle */ + dhd_iovar(dhd, 0, "assoc_retry_max", (char *)&retry_max, sizeof(retry_max), NULL, 0, TRUE); +#if defined(AP) && !defined(WLP2P) + /* Turn off MPC in AP mode */ + dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); + dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, TRUE); +#endif /* defined(AP) && !defined(WLP2P) */ + + + +#if defined(SOFTAP) + if (ap_fw_loaded == TRUE) { + dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); + } +#endif + +#if defined(KEEP_ALIVE) + { + /* Set Keep Alive : be sure to use FW with -keepalive */ + int res; + +#if defined(SOFTAP) + if (ap_fw_loaded == FALSE) +#endif + if (!(dhd->op_mode & + (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) { + if ((res = dhd_keep_alive_onoff(dhd)) < 0) + DHD_ERROR(("%s set keeplive failed %d\n", + __FUNCTION__, res)); + } + } +#endif /* defined(KEEP_ALIVE) */ +#ifdef USE_WL_TXBF + ret = dhd_iovar(dhd, 0, "txbf", (char *)&txbf, sizeof(txbf), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret)); + } +#endif /* USE_WL_TXBF */ +#ifdef DISABLE_TXBFR + ret = dhd_iovar(dhd, 0, "txbf_bfr_cap", (char *)&txbf_bfr_cap, sizeof(txbf_bfr_cap), + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Clear txbf_bfr_cap failed %d\n", __FUNCTION__, ret)); + } +#endif /* DISABLE_TXBFR */ +#ifdef USE_WL_FRAMEBURST +#ifdef DISABLE_WL_FRAMEBURST_SOFTAP + /* Disable Framebursting for SofAP */ + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { + frameburst = 0; + } +#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */ + /* Set frameburst to value */ + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst, + sizeof(frameburst), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set frameburst failed %d\n", __FUNCTION__, ret)); + } +#endif /* USE_WL_FRAMEBURST */ +#ifdef DHD_SET_FW_HIGHSPEED + /* Set ack_ratio */ + ret = dhd_iovar(dhd, 0, "ack_ratio", (char *)&ack_ratio, sizeof(ack_ratio), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s Set ack_ratio failed %d\n", __FUNCTION__, ret)); + + /* Set ack_ratio_depth */ + ret = dhd_iovar(dhd, 0, "ack_ratio_depth", (char *)&ack_ratio_depth, + sizeof(ack_ratio_depth), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s Set ack_ratio_depth failed %d\n", __FUNCTION__, ret)); +#endif /* DHD_SET_FW_HIGHSPEED */ +#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ + defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) + /* Set ampdu ba wsize to 64 or 16 */ +#ifdef CUSTOM_AMPDU_BA_WSIZE + ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE; +#endif +#if defined(WLAIBSS) && defined(CUSTOM_IBSS_AMPDU_BA_WSIZE) + if (dhd->op_mode == DHD_FLAG_IBSS_MODE) + ampdu_ba_wsize = CUSTOM_IBSS_AMPDU_BA_WSIZE; +#endif /* WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE */ + if (ampdu_ba_wsize != 0) { + ret = dhd_iovar(dhd, 0, "ampdu_ba_wsize", (char *)&du_ba_wsize, + sizeof(ampdu_ba_wsize), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n", + __FUNCTION__, ampdu_ba_wsize, ret)); + } + } +#endif /* CUSTOM_AMPDU_BA_WSIZE || (WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ + + iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + if (iov_buf == NULL) { + DHD_ERROR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN)); + ret = BCME_NOMEM; + goto done; + } +#ifdef WLAIBSS + /* Configure custom IBSS beacon transmission */ + if (dhd->op_mode & DHD_FLAG_IBSS_MODE) + { + aibss = 1; + ret = dhd_iovar(dhd, 0, "aibss", (char *)&aibss, sizeof(aibss), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set aibss to %d failed %d\n", + __FUNCTION__, aibss, ret)); + } + } + memset(&bcn_config, 0, sizeof(bcn_config)); + bcn_config.initial_min_bcn_dur = AIBSS_INITIAL_MIN_BCN_DUR; + bcn_config.min_bcn_dur = AIBSS_MIN_BCN_DUR; + bcn_config.bcn_flood_dur = AIBSS_BCN_FLOOD_DUR; + bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0; + bcn_config.len = sizeof(bcn_config); + + ret = dhd_iovar(dhd, 0, "aibss_bcn_force_config", (char *)&bcn_config, + sizeof(aibss_bcn_force_config_t), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set aibss_bcn_force_config to %d, %d, %d failed %d\n", + __FUNCTION__, AIBSS_INITIAL_MIN_BCN_DUR, AIBSS_MIN_BCN_DUR, + AIBSS_BCN_FLOOD_DUR, ret)); + } +#endif /* WLAIBSS */ + +#if defined(CUSTOM_AMPDU_MPDU) + ampdu_mpdu = CUSTOM_AMPDU_MPDU; + if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) { + ret = dhd_iovar(dhd, 0, "ampdu_mpdu", (char *)&du_mpdu, sizeof(ampdu_mpdu), + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n", + __FUNCTION__, CUSTOM_AMPDU_MPDU, ret)); + } + } +#endif /* CUSTOM_AMPDU_MPDU */ + +#ifdef SUPPORT_2G_VHT + ret = dhd_iovar(dhd, 0, "vht_features", (char *)&vht_features, sizeof(vht_features), + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret)); + } +#endif /* SUPPORT_2G_VHT */ +#ifdef DISABLE_11N_PROPRIETARY_RATES + ret = dhd_iovar(dhd, 0, "ht_features", (char *)&ht_features, sizeof(ht_features), NULL, 0, + TRUE); + if (ret < 0) + DHD_ERROR(("%s ht_features set failed %d\n", __FUNCTION__, ret)); +#endif /* DISABLE_11N_PROPRIETARY_RATES */ +#ifdef CUSTOM_PSPRETEND_THR + /* Turn off MPC in AP mode */ + ret = dhd_iovar(dhd, 0, "pspretend_threshold", (char *)&pspretend_thr, + sizeof(pspretend_thr), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n", + __FUNCTION__, ret)); +#endif + + ret = dhd_iovar(dhd, 0, "buf_key_b4_m4", (char *)&buf_key_b4_m4, sizeof(buf_key_b4_m4), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret)); + + /* Read event_msgs mask */ + ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, + sizeof(iovbuf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret)); + goto done; + } + bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); + + /* Setup event_msgs */ + setbit(eventmask, WLC_E_SET_SSID); + setbit(eventmask, WLC_E_PRUNE); + setbit(eventmask, WLC_E_AUTH); + setbit(eventmask, WLC_E_ASSOC); + setbit(eventmask, WLC_E_REASSOC); + setbit(eventmask, WLC_E_REASSOC_IND); + setbit(eventmask, WLC_E_DEAUTH); + setbit(eventmask, WLC_E_DEAUTH_IND); + setbit(eventmask, WLC_E_DISASSOC_IND); + setbit(eventmask, WLC_E_DISASSOC); + setbit(eventmask, WLC_E_JOIN); + setbit(eventmask, WLC_E_START); + setbit(eventmask, WLC_E_ASSOC_IND); + setbit(eventmask, WLC_E_PSK_SUP); + setbit(eventmask, WLC_E_LINK); + setbit(eventmask, WLC_E_NDIS_LINK); + setbit(eventmask, WLC_E_MIC_ERROR); + setbit(eventmask, WLC_E_ASSOC_REQ_IE); + setbit(eventmask, WLC_E_ASSOC_RESP_IE); +#ifndef WL_CFG80211 + setbit(eventmask, WLC_E_PMKID_CACHE); + setbit(eventmask, WLC_E_TXFAIL); +#endif + setbit(eventmask, WLC_E_JOIN_START); + setbit(eventmask, WLC_E_SCAN_COMPLETE); +#ifdef DHD_DEBUG + setbit(eventmask, WLC_E_SCAN_CONFIRM_IND); +#endif +#ifdef WLMEDIA_HTSF + setbit(eventmask, WLC_E_HTSFSYNC); +#endif /* WLMEDIA_HTSF */ +#ifdef PNO_SUPPORT + setbit(eventmask, WLC_E_PFN_NET_FOUND); + setbit(eventmask, WLC_E_PFN_BEST_BATCHING); + setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND); + setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST); +#endif /* PNO_SUPPORT */ + /* enable dongle roaming event */ + setbit(eventmask, WLC_E_ROAM); + setbit(eventmask, WLC_E_BSSID); +#ifdef BCMCCX + setbit(eventmask, WLC_E_ADDTS_IND); + setbit(eventmask, WLC_E_DELTS_IND); +#endif /* BCMCCX */ +#ifdef WLTDLS + setbit(eventmask, WLC_E_TDLS_PEER_EVENT); +#endif /* WLTDLS */ +#ifdef RTT_SUPPORT + setbit(eventmask, WLC_E_PROXD); +#endif /* RTT_SUPPORT */ +#ifdef WL_CFG80211 + setbit(eventmask, WLC_E_ESCAN_RESULT); + if (dhd->op_mode & DHD_FLAG_P2P_MODE) { + setbit(eventmask, WLC_E_ACTION_FRAME_RX); + setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); + } +#endif /* WL_CFG80211 */ +#ifdef WLAIBSS + setbit(eventmask, WLC_E_AIBSS_TXFAIL); +#endif /* WLAIBSS */ + setbit(eventmask, WLC_E_TRACE); +#ifdef DHD_LOSSLESS_ROAMING + setbit(eventmask, WLC_E_ROAM_PREP); +#endif /* DHD_LOSSLESS_ROAMING */ + + /* Write updated Event mask */ + ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret)); + goto done; + } + + /* make up event mask ext message iovar for event larger than 128 */ + msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE; + eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL); + if (eventmask_msg == NULL) { + DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen)); + ret = BCME_NOMEM; + goto done; + } + bzero(eventmask_msg, msglen); + eventmask_msg->ver = EVENTMSGS_VER; + eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; + + /* Read event_msgs_ext mask */ + ret2 = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, + WLC_IOCTL_SMLEN, FALSE); + if (ret2 != BCME_UNSUPPORTED) + ret = ret2; + if (ret2 == 0) { /* event_msgs_ext must be supported */ + bcopy(iov_buf, eventmask_msg, msglen); +#ifdef RSSI_MONITOR_SUPPORT + setbit(eventmask_msg->mask, WLC_E_RSSI_LQM); +#endif /* RSSI_MONITOR_SUPPORT */ +#ifdef GSCAN_SUPPORT + setbit(eventmask_msg->mask, WLC_E_PFN_GSCAN_FULL_RESULT); + setbit(eventmask_msg->mask, WLC_E_PFN_SCAN_COMPLETE); + setbit(eventmask_msg->mask, WLC_E_PFN_SWC); + setbit(eventmask_msg->mask, WLC_E_PFN_SSID_EXT); +#endif /* GSCAN_SUPPORT */ + + /* Write updated Event mask */ + eventmask_msg->ver = EVENTMSGS_VER; + eventmask_msg->command = EVENTMSGS_SET_MASK; + eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; + ret = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, NULL, 0, + TRUE); + if (ret < 0) { + DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret)); + goto done; + } + } else if (ret2 < 0) { + DHD_ERROR(("%s read event mask ext unsupported %d\n", __FUNCTION__, ret2)); + } /* unsupported is ok */ + + dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, + sizeof(scan_assoc_time), TRUE, 0); + dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, + sizeof(scan_unassoc_time), TRUE, 0); + dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, + sizeof(scan_passive_time), TRUE, 0); + +#ifdef ARP_OFFLOAD_SUPPORT + /* Set and enable ARP offload feature for STA only */ +#if defined(SOFTAP) + if (arpoe && !ap_fw_loaded) { +#else + if (arpoe) { +#endif + dhd_arp_offload_enable(dhd, TRUE); + dhd_arp_offload_set(dhd, dhd_arp_mode); + } else { + dhd_arp_offload_enable(dhd, FALSE); + dhd_arp_offload_set(dhd, 0); + } + dhd_arp_enable = arpoe; +#endif /* ARP_OFFLOAD_SUPPORT */ + +#ifdef PKT_FILTER_SUPPORT + /* Setup default defintions for pktfilter , enable in suspend */ + dhd->pktfilter_count = 6; + /* Setup filter to allow only unicast */ + dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; + dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; + dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; + dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; + /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ + dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; + /* apply APP pktfilter */ + dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; + + +#if defined(SOFTAP) + if (ap_fw_loaded) { + dhd_enable_packet_filter(0, dhd); + } +#endif /* defined(SOFTAP) */ + dhd_set_packet_filter(dhd); +#endif /* PKT_FILTER_SUPPORT */ +#ifdef DISABLE_11N + ret = dhd_iovar(dhd, 0, "nmode", (char *)&nmode, sizeof(nmode), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); +#endif /* DISABLE_11N */ + +#ifdef AMPDU_VO_ENABLE + tid.tid = PRIO_8021D_VO; /* Enable TID(6) for voice */ + tid.enable = TRUE; + dhd_iovar(dhd, 0, "ampdu_tid", (char *)&tid, sizeof(tid), NULL, 0, TRUE); + + tid.tid = PRIO_8021D_NC; /* Enable TID(7) for voice */ + tid.enable = TRUE; + dhd_iovar(dhd, 0, "ampdu_tid", (char *)&tid, sizeof(tid), NULL, 0, TRUE); +#endif +#ifdef SOMC_MAX_ASSOC_NUM + { + /* Set the maximum number of stations for P2P / SoftAP */ + const uint32 max = SOMC_MAX_ASSOC_NUM; + dhd_iovar(dhd, 0, "maxassoc", (char *)&max, sizeof(max), NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("%s: maxassoc set failed %d\n", __FUNCTION__, ret)); + } +#endif /* SOMC_MAX_ASSOC_NUM */ + + /* query for 'ver' to get version info from firmware */ + memset(buf, 0, sizeof(buf)); + ptr = buf; + ret = dhd_iovar(dhd, 0, "ver", NULL, 0, (char *)buf, sizeof(buf), FALSE); + if (ret < 0) + DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); + else { + bcmstrtok(&ptr, "\n", 0); + /* Print fw version info */ + DHD_ERROR(("Firmware version = %s\n", buf)); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + snprintf(bcm_wlan_ver_info, sizeof(bcm_wlan_ver_info), + "firmware_version %s\ndhd_version %s\n", + buf, EPI_VERSION_STR); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + dhd_set_version_info(dhd, buf); + } + + dhd_txglom_enable(dhd, TRUE); + +#ifdef PROP_TXSTATUS + if (disable_proptx || +#ifdef PROP_TXSTATUS_VSDB + /* enable WLFC only if the firmware is VSDB when it is in STA mode */ + (dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) || +#endif /* PROP_TXSTATUS_VSDB */ + FALSE) { + wlfc_enable = FALSE; + } + +#ifndef DISABLE_11N + ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, sizeof(hostreorder), + NULL, 0, TRUE); + if (ret2 < 0) { + DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2)); + if (ret2 != BCME_UNSUPPORTED) + ret = ret2; + if (ret2 != BCME_OK) + hostreorder = 0; + } +#endif /* DISABLE_11N */ + if (wlfc_enable) + dhd_wlfc_init(dhd); +#ifndef DISABLE_11N + else if (hostreorder) + dhd_wlfc_hostreorder_init(dhd); +#endif /* DISABLE_11N */ + +#endif /* PROP_TXSTATUS */ +#ifdef PNO_SUPPORT + if (!dhd->pno_state) { + dhd_pno_init(dhd); + } +#endif +#ifdef RTT_SUPPORT + if (!dhd->rtt_state) { + ret = dhd_rtt_init(dhd); + if (ret < 0) { + DHD_ERROR(("%s failed to initialize RTT\n", __FUNCTION__)); + } + } +#endif +#ifdef WL11U + dhd_interworking_enable(dhd); +#endif /* WL11U */ + +done: + + if (eventmask_msg) + kfree(eventmask_msg); + if (iov_buf) + kfree(iov_buf); + + return ret; +} + + +int +dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, char *res_buf, + uint res_len, int set) +{ + char *buf = NULL; + int input_len; + wl_ioctl_t ioc; + int ret; + + if (res_len > WLC_IOCTL_MAXLEN || param_len > WLC_IOCTL_MAXLEN) + return BCME_BADARG; + + input_len = strlen(name) + 1 + param_len; + if (input_len > WLC_IOCTL_MAXLEN) + return BCME_BADARG; + + buf = NULL; + if (set) { + if (res_buf || res_len != 0) { + DHD_ERROR(("%s: SET wrong arguemnet\n", __FUNCTION__)); + ret = BCME_BADARG; + goto exit; + } + buf = kzalloc(input_len, GFP_KERNEL); + if (!buf) { + DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); + if (!ret) { + ret = BCME_NOMEM; + goto exit; + } + + ioc.cmd = WLC_SET_VAR; + ioc.buf = buf; + ioc.len = input_len; + ioc.set = set; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + } else { + if (!res_buf || !res_len) { + DHD_ERROR(("%s: GET failed. resp_buf NULL or length 0.\n", __FUNCTION__)); + ret = BCME_BADARG; + goto exit; + } + + if (res_len < input_len) { + DHD_INFO(("%s: res_len(%d) < input_len(%d)\n", __FUNCTION__, + res_len, input_len)); + buf = kzalloc(input_len, GFP_KERNEL); + if (!buf) { + DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); + if (!ret) { + ret = BCME_NOMEM; + goto exit; + } + + ioc.cmd = WLC_GET_VAR; + ioc.buf = buf; + ioc.len = input_len; + ioc.set = set; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + if (ret == BCME_OK) { + memcpy(res_buf, buf, res_len); + } + } else { + memset(res_buf, 0, res_len); + ret = bcm_mkiovar(name, param_buf, param_len, res_buf, res_len); + if (!ret) { + ret = BCME_NOMEM; + goto exit; + } + + ioc.cmd = WLC_GET_VAR; + ioc.buf = res_buf; + ioc.len = res_len; + ioc.set = set; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + } + } + +exit: + kfree(buf); + return ret; +} + +int +dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, + uint cmd_len, char **resptr, uint resp_len) +{ + int len = resp_len; + int ret; + char *buf = *resptr; + wl_ioctl_t ioc; + if (resp_len > WLC_IOCTL_MAXLEN) + return BCME_BADARG; + + memset(buf, 0, resp_len); + + bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); + + memset(&ioc, 0, sizeof(ioc)); + + ioc.cmd = WLC_GET_VAR; + ioc.buf = buf; + ioc.len = len; + ioc.set = 0; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + + return ret; +} + +int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) +{ + struct dhd_info *dhd = dhdp->info; + struct net_device *dev = NULL; + + ASSERT(dhd && dhd->iflist[ifidx]); + dev = dhd->iflist[ifidx]->net; + ASSERT(dev); + + if (netif_running(dev)) { + DHD_ERROR(("%s: Must be down to change its MTU", dev->name)); + return BCME_NOTDOWN; + } + +#define DHD_MIN_MTU 1500 +#define DHD_MAX_MTU 1752 + + if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { + DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu)); + return BCME_BADARG; + } + + dev->mtu = new_mtu; + return 0; +} + +#ifdef ARP_OFFLOAD_SUPPORT +/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ +void +aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx) +{ + u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ + int i; + int ret; + + bzero(ipv4_buf, sizeof(ipv4_buf)); + + /* display what we've got */ + ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); + DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__)); + if (ret) { + DHD_ERROR(("%s failed\n", __FUNCTION__)); + return; + } +#ifdef AOE_DBG + dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ +#endif + /* now we saved hoste_ip table, clr it in the dongle AOE */ + dhd_aoe_hostip_clr(dhd_pub, idx); + + for (i = 0; i < MAX_IPV4_ENTRIES; i++) { + if (add && (ipv4_buf[i] == 0)) { + ipv4_buf[i] = ipa; + add = FALSE; /* added ipa to local table */ + DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n", + __FUNCTION__, i)); + } else if (ipv4_buf[i] == ipa) { + ipv4_buf[i] = 0; + DHD_ARPOE(("%s: removed IP:%x from temp table %d\n", + __FUNCTION__, ipa, i)); + } + + if (ipv4_buf[i] != 0) { + /* add back host_ip entries from our local cache */ + dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx); + DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n", + __FUNCTION__, ipv4_buf[i], i)); + } + } +#ifdef AOE_DBG + /* see the resulting hostip table */ + dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); + DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__)); + dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ +#endif +} + +/* + * Notification mechanism from kernel to our driver. This function is called by the Linux kernel + * whenever there is an event related to an IP address. + * ptr : kernel provided pointer to IP address that has changed + */ +static int dhd_inetaddr_notifier_call(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + + dhd_info_t *dhd; + dhd_pub_t *dhd_pub; + int idx; + + if (!dhd_arp_enable) + return NOTIFY_DONE; + if (!ifa || !(ifa->ifa_dev->dev)) + return NOTIFY_DONE; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) + /* Filter notifications meant for non Broadcom devices */ + if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) && + (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) { +#if defined(WL_ENABLE_P2P_IF) + if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) +#endif /* WL_ENABLE_P2P_IF */ + return NOTIFY_DONE; + } +#endif /* LINUX_VERSION_CODE */ + + dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev); + if (!dhd) + return NOTIFY_DONE; + + dhd_pub = &dhd->pub; + + if (dhd_pub->arp_version == 1) { + idx = 0; + } + else { + for (idx = 0; idx < DHD_MAX_IFS; idx++) { + if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev) + break; + } + if (idx < DHD_MAX_IFS) + DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net, + dhd->iflist[idx]->name, dhd->iflist[idx]->idx)); + else { + DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label)); + idx = 0; + } + } + + switch (event) { + case NETDEV_UP: + DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", + __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); + + if (dhd->pub.busstate != DHD_BUS_DATA) { + DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); + if (dhd->pend_ipaddr) { + DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", + __FUNCTION__, dhd->pend_ipaddr)); + } + dhd->pend_ipaddr = ifa->ifa_address; + break; + } + +#ifdef AOE_IP_ALIAS_SUPPORT + DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", + __FUNCTION__)); + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx); +#endif /* AOE_IP_ALIAS_SUPPORT */ + break; + + case NETDEV_DOWN: + DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", + __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); + dhd->pend_ipaddr = 0; +#ifdef AOE_IP_ALIAS_SUPPORT + DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n", + __FUNCTION__)); + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx); +#else + dhd_aoe_hostip_clr(&dhd->pub, idx); + dhd_aoe_arp_clr(&dhd->pub, idx); +#endif /* AOE_IP_ALIAS_SUPPORT */ + break; + + default: + DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n", + __func__, ifa->ifa_label, event)); + break; + } + return NOTIFY_DONE; +} +#endif /* ARP_OFFLOAD_SUPPORT */ + +/* Neighbor Discovery Offload: defered handler */ +static void +dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event) +{ + struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data; + dhd_pub_t *pub = &((dhd_info_t *)dhd_info)->pub; + int ret; + + if (event != DHD_WQ_WORK_IPV6_NDO) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + + if (!ndo_work) { + DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__)); + return; + } + + if (!pub) { + DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__)); + return; + } + + if (ndo_work->if_idx) { + DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx)); + return; + } + + switch (ndo_work->event) { + case NETDEV_UP: + DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__)); + ret = dhd_ndo_enable(pub, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret)); + } + + ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx); + if (ret < 0) { + DHD_ERROR(("%s: Adding host ip for NDO failed %d\n", + __FUNCTION__, ret)); + } + break; + case NETDEV_DOWN: + DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__)); + ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx); + if (ret < 0) { + DHD_ERROR(("%s: Removing host ip for NDO failed %d\n", + __FUNCTION__, ret)); + goto done; + } + + ret = dhd_ndo_enable(pub, FALSE); + if (ret < 0) { + DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret)); + goto done; + } + break; + default: + DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__)); + break; + } +done: + /* free ndo_work. alloced while scheduling the work */ + kfree(ndo_work); + + return; +} + +/* + * Neighbor Discovery Offload: Called when an interface + * is assigned with ipv6 address. + * Handles only primary interface + */ +static int dhd_inet6addr_notifier_call(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + dhd_info_t *dhd; + dhd_pub_t *dhd_pub; + struct inet6_ifaddr *inet6_ifa = ptr; + struct in6_addr *ipv6_addr = &inet6_ifa->addr; + struct ipv6_work_info_t *ndo_info; + int idx = 0; /* REVISIT */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) + /* Filter notifications meant for non Broadcom devices */ + if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) { + return NOTIFY_DONE; + } +#endif /* LINUX_VERSION_CODE */ + + dhd = *(dhd_info_t **)netdev_priv(inet6_ifa->idev->dev); + if (!dhd) + return NOTIFY_DONE; + + if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev) + return NOTIFY_DONE; + dhd_pub = &dhd->pub; + if (!FW_SUPPORTED(dhd_pub, ndoe)) + return NOTIFY_DONE; + + ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC); + if (!ndo_info) { + DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__)); + return NOTIFY_DONE; + } + + ndo_info->event = event; + ndo_info->if_idx = idx; + memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN); + + /* defer the work to thread as it may block kernel */ + dhd_deferred_schedule_work((void *)ndo_info, DHD_WQ_WORK_IPV6_NDO, + dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW); + return NOTIFY_DONE; +} + +int +dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + struct net_device *net = NULL; + int err = 0; + uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; + + DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); + + ASSERT(dhd && dhd->iflist[ifidx]); + net = dhd->iflist[ifidx]->net; + ASSERT(net); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + ASSERT(!net->open); + net->get_stats = dhd_get_stats; + net->do_ioctl = dhd_ioctl_entry; + net->hard_start_xmit = dhd_start_xmit; + net->set_mac_address = dhd_set_mac_address; + net->set_multicast_list = dhd_set_multicast_list; + net->open = net->stop = NULL; +#else + ASSERT(!net->netdev_ops); + net->netdev_ops = &dhd_ops_virt; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + + /* Ok, link into the network layer... */ + if (ifidx == 0) { + /* + * device functions for the primary interface only + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + net->open = dhd_open; + net->stop = dhd_stop; +#else + net->netdev_ops = &dhd_ops_pri; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) + memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); + } else { + /* + * We have to use the primary MAC for virtual interfaces + */ + memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN); + /* + * Android sets the locally administered bit to indicate that this is a + * portable hotspot. This will not work in simultaneous AP/STA mode, + * nor with P2P. Need to set the Donlge's MAC address, and then use that. + */ + if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, + ETHER_ADDR_LEN)) { + DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", + __func__, net->name)); + temp_addr[0] |= 0x02; + } + } + + net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + net->ethtool_ops = &dhd_ethtool_ops; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + +#if defined(WL_WIRELESS_EXT) +#if WIRELESS_EXT < 19 + net->get_wireless_stats = dhd_get_wireless_stats; +#endif /* WIRELESS_EXT < 19 */ +#if WIRELESS_EXT > 12 + net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; +#endif /* WIRELESS_EXT > 12 */ +#endif /* defined(WL_WIRELESS_EXT) */ + + dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); + + memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); + + if (ifidx == 0) + printf("%s\n", dhd_version); + + if (need_rtnl_lock) + err = register_netdev(net); + else + err = register_netdevice(net); + + if (err != 0) { + DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err)); + goto fail; + } + + + printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name, + MAC2STRDBG(net->dev_addr)); + +#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211) + wl_iw_iscan_set_scan_broadcast_prep(net, 1); +#endif + +#if defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + if (ifidx == 0) { +#ifdef BCMLXSDMMC + up(&dhd_registration_sem); +#endif + if (!dhd_download_fw_on_driverload) { + dhd_net_bus_devreset(net, TRUE); + dhd_net_bus_suspend(net); + wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY); + } + } +#endif /* OEM_ANDROID && BCMLXSDMMC && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + return 0; + +fail: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) + net->open = NULL; +#else + net->netdev_ops = NULL; +#endif + return err; +} + +void +dhd_bus_detach(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (dhdp) { + dhd = (dhd_info_t *)dhdp->info; + if (dhd) { + + /* + * In case of Android cfg80211 driver, the bus is down in dhd_stop, + * calling stop again will cuase SD read/write errors. + */ + if (dhd->pub.busstate != DHD_BUS_DOWN) { + /* Stop the protocol module */ + dhd_prot_stop(&dhd->pub); + + /* Stop the bus module */ + dhd_bus_stop(dhd->pub.bus, TRUE); + } + +#if defined(OOB_INTR_ONLY) + dhd_bus_oob_intr_unregister(dhdp); +#endif + } + } +} + + +void dhd_detach(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd; + unsigned long flags; + int timer_valid = FALSE; + + if (!dhdp) + return; + + dhd = (dhd_info_t *)dhdp->info; + if (!dhd) + return; + + DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); + + dhd->pub.up = 0; + if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { + /* Give sufficient time for threads to start running in case + * dhd_attach() has failed + */ + OSL_SLEEP(100); + } + + if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { + dhd_bus_detach(dhdp); + + if (dhdp->prot) + dhd_prot_detach(dhdp); + } + +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd_inetaddr_notifier_registered) { + dhd_inetaddr_notifier_registered = FALSE; + unregister_inetaddr_notifier(&dhd_inetaddr_notifier); + } +#endif /* ARP_OFFLOAD_SUPPORT */ + if (dhd_inet6addr_notifier_registered) { + dhd_inet6addr_notifier_registered = FALSE; + unregister_inet6addr_notifier(&dhd_inet6addr_notifier); + } + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) + if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { + if (dhd->early_suspend.suspend) + unregister_early_suspend(&dhd->early_suspend); + } +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ + +#if defined(WL_WIRELESS_EXT) + if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { + /* Detatch and unlink in the iw */ + wl_iw_detach(); + } +#endif /* defined(WL_WIRELESS_EXT) */ + + /* delete all interfaces, start with virtual */ + if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { + int i = 1; + dhd_if_t *ifp; + + /* Cleanup virtual interfaces */ + dhd_net_if_lock_local(dhd); + for (i = 1; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) + dhd_remove_if(&dhd->pub, i, TRUE); + } + dhd_net_if_unlock_local(dhd); + + /* delete primary interface 0 */ + ifp = dhd->iflist[0]; + ASSERT(ifp); + ASSERT(ifp->net); + if (ifp && ifp->net) { + /* in unregister_netdev case, the interface gets freed by net->destructor + * (which is set to free_netdev) + */ + if (ifp->net->reg_state == NETREG_UNINITIALIZED) + free_netdev(ifp->net); + else + unregister_netdev(ifp->net); + ifp->net = NULL; + MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); + dhd->iflist[0] = NULL; + } + } + + /* Clear the watchdog timer */ + flags = dhd_os_spin_lock(&dhd->pub); + timer_valid = dhd->wd_timer_valid; + dhd->wd_timer_valid = FALSE; + dhd_os_spin_unlock(&dhd->pub, flags); + if (timer_valid) + del_timer_sync(&dhd->timer); + + if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { + if (dhd->thr_wdt_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_wdt_ctl); + } + + if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_rxf_ctl); + } + + if (dhd->thr_dpc_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_dpc_ctl); + } else + tasklet_kill(&dhd->tasklet); + } +#ifdef WL_CFG80211 + if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { + wl_cfg80211_detach(NULL); + dhd_monitor_uninit(); + } +#endif + /* free deferred work queue */ + dhd_deferred_work_deinit(dhd->dhd_deferred_wq); + dhd->dhd_deferred_wq = NULL; + +#ifdef PNO_SUPPORT + if (dhdp->pno_state) + dhd_pno_deinit(dhdp); +#endif +#ifdef RTT_SUPPORT + if (dhdp->rtt_state) { + dhd_rtt_deinit(dhdp); + } +#endif +#if defined(CONFIG_PM_SLEEP) + if (dhd_pm_notifier_registered) { + unregister_pm_notifier(&dhd->pm_notifier); + dhd_pm_notifier_registered = FALSE; + } +#endif /* CONFIG_PM_SLEEP */ +#ifdef SAR_SUPPORT + if (dhd_sar_notifier_registered) { + unregister_notifier_by_sar(&dhd->sar_notifier); + dhd_sar_notifier_registered = FALSE; + } +#endif +#ifdef DEBUG_CPU_FREQ + if (dhd->new_freq) + free_percpu(dhd->new_freq); + dhd->new_freq = NULL; + cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); +#endif + if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { + DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); +#ifdef CONFIG_HAS_WAKELOCK + dhd->wakelock_counter = 0; + dhd->wakelock_wd_counter = 0; + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; + wake_lock_destroy(&dhd->wl_wifi); + wake_lock_destroy(&dhd->wl_rxwake); + wake_lock_destroy(&dhd->wl_ctrlwake); + wake_lock_destroy(&dhd->wl_wdwake); +#endif /* CONFIG_HAS_WAKELOCK */ + } + + +#ifdef DHDTCPACK_SUPPRESS + /* This will free all MEM allocated for TCPACK SUPPRESS */ + dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); +#endif /* DHDTCPACK_SUPPRESS */ +} + + +void +dhd_free(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (dhdp) { + int i; + for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { + if (dhdp->reorder_bufs[i]) { + reorder_info_t *ptr; + uint32 buf_size = sizeof(struct reorder_info); + + ptr = dhdp->reorder_bufs[i]; + + buf_size += ((ptr->max_idx + 1) * sizeof(void*)); + DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", + i, ptr->max_idx, buf_size)); + + MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); + dhdp->reorder_bufs[i] = NULL; + } + } + dhd = (dhd_info_t *)dhdp->info; + if (dhdp->soc_ram) { + MFREE(dhd->pub.osh, dhdp->soc_ram, dhdp->soc_ram_length); + dhdp->soc_ram = NULL; + } + + /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */ + if (dhd && + dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE)) + MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); + dhd = NULL; + } +} + +static void __exit +dhd_module_cleanup(void) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + dhd_bus_unregister(); + + wl_android_exit(); + + dhd_wifi_platform_unregister_drv(); +} + +#define BCMCONF "/data/misc/wifi/bcm_debug.conf" + +static int __init +dhd_module_init(void) +{ + int err; + void *fp = NULL; + + DHD_ERROR(("%s in\n", __FUNCTION__)); + err = dhd_wifi_platform_register_drv(); + + fp = dhd_os_open_image(BCMCONF); + if (fp) { + unsigned char buf[7]; + long res = 0; + int len = dhd_os_get_image_block(buf, 7, fp); + if (len > 0 && len < 7) { + buf[len] = '\0'; + if (!kstrtol(buf, 16, &res)) + dhd_msg_level = (int)res; + } else { + DHD_ERROR(("Error in dbg level pattern\n")); + } + dhd_os_close_image(fp); + } + + return err; +} + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +#if defined(CONFIG_DEFERRED_INITCALLS) +deferred_module_init(dhd_module_init); +#elif defined(USE_LATE_INITCALL_SYNC) +late_initcall_sync(dhd_module_init); +#else +late_initcall(dhd_module_init); +#endif /* USE_LATE_INITCALL_SYNC */ +#else +module_init(dhd_module_init); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ + +module_exit(dhd_module_cleanup); + +/* + * OS specific functions required to implement DHD driver in OS independent way + */ +int +dhd_os_proto_block(dhd_pub_t *pub) +{ + dhd_info_t * dhd = (dhd_info_t *)(pub->info); + + if (dhd) { + down(&dhd->proto_sem); + return 1; + } + + return 0; +} + +int +dhd_os_proto_unblock(dhd_pub_t *pub) +{ + dhd_info_t * dhd = (dhd_info_t *)(pub->info); + + if (dhd) { + up(&dhd->proto_sem); + return 1; + } + + return 0; +} + +unsigned int +dhd_os_get_ioctl_resp_timeout(void) +{ + return ((unsigned int)dhd_ioctl_timeout_msec); +} + +void +dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) +{ + dhd_ioctl_timeout_msec = (int)timeout_msec; +} + +int +dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) +{ + dhd_info_t * dhd = (dhd_info_t *)(pub->info); + int timeout; + + /* Convert timeout in millsecond to jiffies */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); +#else + timeout = dhd_ioctl_timeout_msec * HZ / 1000; +#endif + + timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); + return timeout; +} + +int +dhd_os_ioctl_resp_wake(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + wake_up(&dhd->ioctl_resp_wait); + return 0; +} + +void +dhd_os_wd_timer_extend(void *bus, bool extend) +{ + dhd_pub_t *pub = bus; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + + if (extend) + dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL); + else + dhd_os_wd_timer(bus, dhd->default_wd_interval); +} + + +void +dhd_os_wd_timer(void *bus, uint wdtick) +{ + dhd_pub_t *pub = bus; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + unsigned long flags; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!dhd) { + DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); + return; + } + + flags = dhd_os_spin_lock(pub); + + /* don't start the wd until fw is loaded */ + if (pub->busstate == DHD_BUS_DOWN) { + dhd_os_spin_unlock(pub, flags); + if (!wdtick) + DHD_OS_WD_WAKE_UNLOCK(pub); + return; + } + + /* Totally stop the timer */ + if (!wdtick && dhd->wd_timer_valid == TRUE) { + dhd->wd_timer_valid = FALSE; + dhd_os_spin_unlock(pub, flags); + del_timer_sync(&dhd->timer); + DHD_OS_WD_WAKE_UNLOCK(pub); + return; + } + + if (wdtick) { + DHD_OS_WD_WAKE_LOCK(pub); + dhd_watchdog_ms = (uint)wdtick; + /* Re arm the timer, at last watchdog period */ + mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); + dhd->wd_timer_valid = TRUE; + } + dhd_os_spin_unlock(pub, flags); +} + +void * +dhd_os_open_image(char *filename) +{ + struct file *fp; + + fp = filp_open(filename, O_RDONLY, 0); + /* + * 2.6.11 (FC4) supports filp_open() but later revs don't? + * Alternative: + * fp = open_namei(AT_FDCWD, filename, O_RD, 0); + * ??? + */ + if (IS_ERR(fp)) + fp = NULL; + + return fp; +} + +int +dhd_os_get_image_block(char *buf, int len, void *image) +{ + struct file *fp = (struct file *)image; + int rdlen; + + if (!image) + return 0; + + rdlen = kernel_read(fp, fp->f_pos, buf, len); + if (rdlen > 0) + fp->f_pos += rdlen; + + return rdlen; +} + +void +dhd_os_close_image(void *image) +{ + if (image) + filp_close((struct file *)image, NULL); +} + +void +dhd_os_sdlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + + if (dhd_dpc_prio >= 0) + down(&dhd->sdsem); + else + spin_lock_bh(&dhd->sdlock); +} + +void +dhd_os_sdunlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + + if (dhd_dpc_prio >= 0) + up(&dhd->sdsem); + else + spin_unlock_bh(&dhd->sdlock); +} + +void +dhd_os_sdlock_txq(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_bh(&dhd->txqlock); +} + +void +dhd_os_sdunlock_txq(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_bh(&dhd->txqlock); +} + +void +dhd_os_sdlock_rxq(dhd_pub_t *pub) +{ +} + +void +dhd_os_sdunlock_rxq(dhd_pub_t *pub) +{ +} + +void +dhd_os_sdtxlock(dhd_pub_t *pub) +{ + dhd_os_sdlock(pub); +} + +void +dhd_os_sdtxunlock(dhd_pub_t *pub) +{ + dhd_os_sdunlock(pub); +} + +static void +dhd_os_rxflock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_bh(&dhd->rxf_lock); + +} + +static void +dhd_os_rxfunlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_bh(&dhd->rxf_lock); +} + +#ifdef DHDTCPACK_SUPPRESS +void +dhd_os_tcpacklock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_bh(&dhd->tcpack_lock); + +} + +void +dhd_os_tcpackunlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_bh(&dhd->tcpack_lock); +} +#endif /* DHDTCPACK_SUPPRESS */ + +uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail) +{ + uint8* buf; + gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; + + buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size); + if (buf == NULL) { + DHD_ERROR(("%s: failed to alloc memory, section: %d," + " size: %dbytes", __FUNCTION__, section, size)); + if (kmalloc_if_fail) + buf = kmalloc(size, flags); + } + + return buf; +} + +void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size) +{ +} + +#if defined(WL_WIRELESS_EXT) +struct iw_statistics * +dhd_get_wireless_stats(struct net_device *dev) +{ + int res = 0; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (!dhd->pub.up) { + return NULL; + } + + res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); + + if (res == 0) + return &dhd->iw.wstats; + else + return NULL; +} +#endif /* defined(WL_WIRELESS_EXT) */ + +static int +dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, + wl_event_msg_t *event, void **data) +{ + int bcmerror = 0; + ASSERT(dhd != NULL); + + bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data); + if (bcmerror != BCME_OK) + return (bcmerror); + +#if defined(WL_WIRELESS_EXT) + if (event->bsscfgidx == 0) { + /* + * Wireless ext is on primary interface only + */ + + ASSERT(dhd->iflist[*ifidx] != NULL); + ASSERT(dhd->iflist[*ifidx]->net != NULL); + + if (dhd->iflist[*ifidx]->net) { + wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); + } + } +#endif /* defined(WL_WIRELESS_EXT) */ + +#ifdef WL_CFG80211 + ASSERT(dhd->iflist[*ifidx] != NULL); + ASSERT(dhd->iflist[*ifidx]->net != NULL); + if (dhd->iflist[*ifidx]->net) + wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); +#endif /* defined(WL_CFG80211) */ + + return (bcmerror); +} + +/* send up locally generated event */ +void +dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) +{ + switch (ntoh32(event->event_type)) { + + default: + break; + } +} + +#ifdef LOG_INTO_TCPDUMP +void +dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len) +{ + struct sk_buff *p, *skb; + uint32 pktlen; + int len; + dhd_if_t *ifp; + dhd_info_t *dhd; + uchar *skb_data; + int ifidx = 0; + struct ether_header eth; + + pktlen = sizeof(eth) + data_len; + dhd = dhdp->info; + + if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { + ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); + + bcopy(&dhdp->mac, ð.ether_dhost, ETHER_ADDR_LEN); + bcopy(&dhdp->mac, ð.ether_shost, ETHER_ADDR_LEN); + ETHER_TOGGLE_LOCALADDR(ð.ether_shost); + eth.ether_type = hton16(ETHER_TYPE_BRCM); + + bcopy((void *)ð, PKTDATA(dhdp->osh, p), sizeof(eth)); + bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len); + skb = PKTTONATIVE(dhdp->osh, p); + skb_data = skb->data; + len = skb->len; + + ifidx = dhd_ifname2idx(dhd, "wlan0"); + ifp = dhd->iflist[ifidx]; + if (ifp == NULL) + ifp = dhd->iflist[0]; + + ASSERT(ifp); + skb->dev = ifp->net; + skb->protocol = eth_type_trans(skb, skb->dev); + skb->data = skb_data; + skb->len = len; + + /* Strip header, count, deliver upward */ + skb_pull(skb, ETH_HLEN); + + /* Send the packet */ + if (in_interrupt()) { + netif_rx(skb); + } else { + netif_rx_ni(skb); + } + } + else { + /* Could not allocate a sk_buf */ + DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__)); + } +} +#endif /* LOG_INTO_TCPDUMP */ + +void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + struct dhd_info *dhdinfo = dhd->info; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); +#else + int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + + dhd_os_sdunlock(dhd); + wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); + dhd_os_sdlock(dhd); +#endif + return; +} + +void dhd_wait_event_wakeup(dhd_pub_t *dhd) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + struct dhd_info *dhdinfo = dhd->info; + if (waitqueue_active(&dhdinfo->ctrl_wait)) + wake_up(&dhdinfo->ctrl_wait); +#endif + return; +} + +int +dhd_net_bus_devreset(struct net_device *dev, uint8 flag) +{ + int ret; + + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (flag == TRUE) { + /* Issue wl down command before resetting the chip */ + if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { + DHD_TRACE(("%s: wl down failed\n", __FUNCTION__)); + } +#ifdef PROP_TXSTATUS + if (dhd->pub.wlfc_enabled) + dhd_wlfc_deinit(&dhd->pub); +#endif /* PROP_TXSTATUS */ +#ifdef PNO_SUPPORT + if (dhd->pub.pno_state) + dhd_pno_deinit(&dhd->pub); +#endif +#ifdef RTT_SUPPORT + if (dhd->pub.rtt_state) { + dhd_rtt_deinit(&dhd->pub); + } +#endif /* RTT_SUPPORT */ + } + + if (!flag) { + dhd_update_fw_nv_path(dhd); + /* update firmware and nvram path to sdio bus */ + dhd_bus_update_fw_nv_path(dhd->pub.bus, + dhd->fw_path, dhd->nv_path); + } + + ret = dhd_bus_devreset(&dhd->pub, flag); + if (ret) { + DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); + return ret; + } + + return ret; +} + +int +dhd_net_bus_suspend(struct net_device *dev) +{ + dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev); + return dhd_bus_suspend(&dhdinfo->pub); +} + +int +dhd_net_bus_resume(struct net_device *dev, uint8 stage) +{ + dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev); + return dhd_bus_resume(&dhdinfo->pub, stage); +} + +int net_os_set_suspend_disable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) { + ret = dhd->pub.suspend_disable_flag; + dhd->pub.suspend_disable_flag = val; + } + return ret; +} + +int net_os_set_suspend(struct net_device *dev, int val, int force) +{ + int ret = 0; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd) { +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) + ret = dhd_set_suspend(val, &dhd->pub); +#else + ret = dhd_suspend_resume_helper(dhd, val, force); +#endif +#ifdef WL_CFG80211 + wl_cfg80211_update_power_mode(dev); +#endif + } + return ret; +} + +int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd) + dhd->pub.suspend_bcn_li_dtim = val; + + return 0; +} + +#ifdef PKT_FILTER_SUPPORT +int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + char *filterp = NULL; + int filter_id = 0; + int ret = 0; + + if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || + (num == DHD_MDNS_FILTER_NUM)) + return ret; + if (num >= dhd->pub.pktfilter_count) + return -EINVAL; + switch (num) { + case DHD_BROADCAST_FILTER_NUM: + filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; + filter_id = 101; + break; + case DHD_MULTICAST4_FILTER_NUM: + filterp = "102 0 0 0 0xFFFFFF 0x01005E"; + filter_id = 102; + break; + case DHD_MULTICAST6_FILTER_NUM: + filterp = "103 0 0 0 0xFFFF 0x3333"; + filter_id = 103; + break; + default: + return -EINVAL; + } + + /* Add filter */ + if (add_remove) { + dhd->pub.pktfilter[num] = filterp; + dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); + } else { /* Delete filter */ + if (dhd->pub.pktfilter[num] != NULL) { + dhd_pktfilter_offload_delete(&dhd->pub, filter_id); + dhd->pub.pktfilter[num] = NULL; + } + } + return ret; +} + +int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) + +{ + int ret = 0; + + /* Packet filtering is set only if we still in early-suspend and + * we need either to turn it ON or turn it OFF + * We can always turn it OFF in case of early-suspend, but we turn it + * back ON only if suspend_disable_flag was not set + */ + if (dhdp && dhdp->up) { + if (dhdp->in_suspend) { + if (!val || (val && !dhdp->suspend_disable_flag)) + dhd_enable_packet_filter(val, dhdp); + } + } + return ret; +} + +/* function to enable/disable packet for Network device */ +int net_os_enable_packet_filter(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return dhd_os_enable_packet_filter(&dhd->pub, val); +} +#endif /* PKT_FILTER_SUPPORT */ + +int +dhd_dev_init_ioctl(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret; + + dhd_process_cid_mac(&dhd->pub, TRUE); + + if ((ret = dhd_prot_init(&dhd->pub)) < 0) + goto done; + + dhd_process_cid_mac(&dhd->pub, FALSE); + +done: + return ret; +} + +int +dhd_dev_get_feature_set(struct net_device *dev) +{ + dhd_info_t *ptr = *(dhd_info_t **)netdev_priv(dev); + dhd_pub_t *dhd = (&ptr->pub); + int feature_set = 0; + + if (!dhd) + return feature_set; + + if (FW_SUPPORTED(dhd, sta)) + feature_set |= WIFI_FEATURE_INFRA; + if (FW_SUPPORTED(dhd, dualband)) + feature_set |= WIFI_FEATURE_INFRA_5G; + if (FW_SUPPORTED(dhd, p2p)) + feature_set |= WIFI_FEATURE_P2P; + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) + feature_set |= WIFI_FEATURE_SOFT_AP; + if (FW_SUPPORTED(dhd, tdls)) + feature_set |= WIFI_FEATURE_TDLS; + if (FW_SUPPORTED(dhd, vsdb)) + feature_set |= WIFI_FEATURE_TDLS_OFFCHANNEL; + if (FW_SUPPORTED(dhd, nan)) { + feature_set |= WIFI_FEATURE_NAN; + /* NAN is essentail for d2d rtt */ + if (FW_SUPPORTED(dhd, rttd2d)) + feature_set |= WIFI_FEATURE_D2D_RTT; + } +#ifdef RTT_SUPPORT + feature_set |= WIFI_FEATURE_D2AP_RTT; +#endif /* RTT_SUPPORT */ +#ifdef LINKSTAT_SUPPORT + feature_set |= WIFI_FEATURE_LINKSTAT; +#endif /* LINKSTAT_SUPPORT */ + /* Supports STA + STA always */ + feature_set |= WIFI_FEATURE_ADDITIONAL_STA; +#ifdef PNO_SUPPORT + if (dhd_is_pno_supported(dhd)) { + feature_set |= WIFI_FEATURE_PNO; + feature_set |= WIFI_FEATURE_BATCH_SCAN; +#ifdef GSCAN_SUPPORT + feature_set |= WIFI_FEATURE_GSCAN; +#endif /* GSCAN_SUPPORT */ +#ifdef EPNO_SUPPORT + feature_set |= WIFI_FEATURE_HAL_EPNO; +#endif /* EPNO_SUPPORT */ + } +#endif /* PNO_SUPPORT */ +#ifdef RSSI_MONITOR_SUPPORT + if (FW_SUPPORTED(dhd, rssi_mon)) { + feature_set |= WIFI_FEATURE_RSSI_MONITOR; + } +#endif +#ifdef WL11U + feature_set |= WIFI_FEATURE_HOTSPOT; +#endif /* WL11U */ + return feature_set; +} + +int* +dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num) +{ + int feature_set_full, mem_needed; + int *ret; + + *num = 0; + mem_needed = sizeof(int) * MAX_FEATURE_SET_CONCURRRENT_GROUPS; + ret = (int *) kmalloc(mem_needed, GFP_KERNEL); + + if (!ret) { + DHD_ERROR(("%s: failed to allocate %d bytes\n", __FUNCTION__, + mem_needed)); + return ret; + } + + feature_set_full = dhd_dev_get_feature_set(dev); + + ret[0] = (feature_set_full & WIFI_FEATURE_INFRA) | + (feature_set_full & WIFI_FEATURE_INFRA_5G) | + (feature_set_full & WIFI_FEATURE_NAN) | + (feature_set_full & WIFI_FEATURE_D2D_RTT) | + (feature_set_full & WIFI_FEATURE_D2AP_RTT) | + (feature_set_full & WIFI_FEATURE_PNO) | + (feature_set_full & WIFI_FEATURE_HAL_EPNO) | + (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | + (feature_set_full & WIFI_FEATURE_BATCH_SCAN) | + (feature_set_full & WIFI_FEATURE_GSCAN) | + (feature_set_full & WIFI_FEATURE_HOTSPOT) | + (feature_set_full & WIFI_FEATURE_ADDITIONAL_STA) | + (feature_set_full & WIFI_FEATURE_EPR); + + ret[1] = (feature_set_full & WIFI_FEATURE_INFRA) | + (feature_set_full & WIFI_FEATURE_INFRA_5G) | + (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | + /* Not yet verified NAN with P2P */ + /* (feature_set_full & WIFI_FEATURE_NAN) | */ + (feature_set_full & WIFI_FEATURE_P2P) | + (feature_set_full & WIFI_FEATURE_D2AP_RTT) | + (feature_set_full & WIFI_FEATURE_D2D_RTT) | + (feature_set_full & WIFI_FEATURE_EPR); + + ret[2] = (feature_set_full & WIFI_FEATURE_INFRA) | + (feature_set_full & WIFI_FEATURE_INFRA_5G) | + (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | + (feature_set_full & WIFI_FEATURE_NAN) | + (feature_set_full & WIFI_FEATURE_D2D_RTT) | + (feature_set_full & WIFI_FEATURE_D2AP_RTT) | + (feature_set_full & WIFI_FEATURE_TDLS) | + (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL) | + (feature_set_full & WIFI_FEATURE_EPR); + *num = MAX_FEATURE_SET_CONCURRRENT_GROUPS; + + return ret; +} + +#ifdef PNO_SUPPORT +/* Linux wrapper to call common dhd_pno_stop_for_ssid */ +int +dhd_dev_pno_stop_for_ssid(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_stop_for_ssid(&dhd->pub)); +} +/* Linux wrapper to call common dhd_pno_set_for_ssid */ +int +dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr, + pno_repeat, pno_freq_expo_max, channel_list, nchan)); +} + +/* Linux wrapper to call common dhd_pno_enable */ +int +dhd_dev_pno_enable(struct net_device *dev, int enable) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_enable(&dhd->pub, enable)); +} + +/* Linux wrapper to call common dhd_pno_set_for_hotlist */ +int +dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params)); +} +/* Linux wrapper to call common dhd_dev_pno_stop_for_batch */ +int +dhd_dev_pno_stop_for_batch(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + return (dhd_pno_stop_for_batch(&dhd->pub)); +} +/* Linux wrapper to call common dhd_dev_pno_set_for_batch */ +int +dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + return (dhd_pno_set_for_batch(&dhd->pub, batch_params)); +} +/* Linux wrapper to call common dhd_dev_pno_get_for_batch */ +int +dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL)); +} + +#endif /* PNO_SUPPORT */ + +#ifdef RSSI_MONITOR_SUPPORT +int +dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, + int8 max_rssi, int8 min_rssi) +{ + int err; + wl_rssi_monitor_cfg_t rssi_monitor; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + rssi_monitor.version = RSSI_MONITOR_VERSION; + rssi_monitor.max_rssi = max_rssi; + rssi_monitor.min_rssi = min_rssi; + rssi_monitor.flags = start ? 0: RSSI_MONITOR_STOP; + err = dhd_iovar(&dhd->pub, 0, "rssi_monitor", (char *)&rssi_monitor, sizeof(rssi_monitor), + NULL, 0, TRUE); + if (err < 0 && err != BCME_UNSUPPORTED) { + DHD_ERROR(("%s : Failed to execute rssi_monitor %d\n", __FUNCTION__, err)); + } + return err; +} +#endif /* RSSI_MONITOR_SUPPORT */ + +int +dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + dhd_pub_t *dhdp = &dhd->pub; + + if (!dhdp || !oui) { + DHD_ERROR(("NULL POINTER : %s\n", + __FUNCTION__)); + return BCME_ERROR; + } + if (ETHER_ISMULTI(oui)) { + DHD_ERROR(("Expected unicast OUI\n")); + return BCME_ERROR; + } else { + uint8 *rand_mac_oui = dhdp->rand_mac_oui; + memcpy(rand_mac_oui, oui, DOT11_OUI_LEN); + DHD_ERROR(("Random MAC OUI to be used - %02x:%02x:%02x\n", rand_mac_oui[0], + rand_mac_oui[1], rand_mac_oui[2])); + } + return BCME_OK; +} + +int +dhd_set_rand_mac_oui(dhd_pub_t *dhd) +{ + int err; + wl_pfn_macaddr_cfg_t cfg; + uint8 *rand_mac_oui = dhd->rand_mac_oui; + + memset(&cfg.macaddr, 0, ETHER_ADDR_LEN); + memcpy(&cfg.macaddr, rand_mac_oui, DOT11_OUI_LEN); + cfg.version = WL_PFN_MACADDR_CFG_VER; + if (ETHER_ISNULLADDR(&cfg.macaddr)) + cfg.flags = 0; + else + cfg.flags = (WL_PFN_MAC_OUI_ONLY_MASK | WL_PFN_SET_MAC_UNASSOC_MASK); + + DHD_ERROR(("Setting rand mac oui to FW - %02x:%02x:%02x\n", rand_mac_oui[0], + rand_mac_oui[1], rand_mac_oui[2])); + + err = dhd_iovar(dhd, 0, "pfn_macaddr", (char *)&cfg, sizeof(cfg), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_macaddr %d\n", __FUNCTION__, err)); + } + return err; +} + +#ifdef RTT_SUPPORT +/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ +int +dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_set_cfg(&dhd->pub, buf)); +} +int +dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_stop(&dhd->pub, mac_list, mac_cnt)); +} + +int +dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, dhd_rtt_compl_noti_fn noti_fn) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_register_noti_callback(&dhd->pub, ctx, noti_fn)); +} +int +dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_unregister_noti_callback(&dhd->pub, noti_fn)); +} + +int +dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_rtt_capability(&dhd->pub, capa)); +} +#endif /* RTT_SUPPORT */ + +#ifdef GSCAN_SUPPORT +/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ +int +dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, + void *buf, uint8 flush) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_set_cfg_gscan(&dhd->pub, type, buf, flush)); +} + +/* Linux wrapper to call common dhd_pno_get_gscan */ +void * +dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, + void *info, uint32 *len) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_get_gscan(&dhd->pub, type, info, len)); +} + +/* Linux wrapper to call common dhd_wait_batch_results_complete */ +int +dhd_dev_wait_batch_results_complete(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_wait_batch_results_complete(&dhd->pub)); +} + +/* Linux wrapper to call common dhd_pno_lock_batch_results */ +int +dhd_dev_pno_lock_access_batch_results(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_lock_batch_results(&dhd->pub)); +} +/* Linux wrapper to call common dhd_pno_unlock_batch_results */ +void +dhd_dev_pno_unlock_access_batch_results(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_unlock_batch_results(&dhd->pub)); +} + +/* Linux wrapper to call common dhd_pno_initiate_gscan_request */ +int +dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_initiate_gscan_request(&dhd->pub, run, flush)); +} + +/* Linux wrapper to call common dhd_pno_enable_full_scan_result */ +int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time_flag) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_enable_full_scan_result(&dhd->pub, real_time_flag)); +} + +/* Linux wrapper to call common dhd_handle_swc_evt */ +void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_handle_swc_evt(&dhd->pub, data, send_evt_bytes)); +} + +/* Linux wrapper to call common dhd_handle_hotlist_scan_evt */ +void * dhd_dev_hotlist_scan_event(struct net_device *dev, + const void *data, int *send_evt_bytes, hotlist_type_t type) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_handle_hotlist_scan_evt(&dhd->pub, data, send_evt_bytes, type)); +} + +/* Linux wrapper to call common dhd_process_full_gscan_result */ +void * dhd_dev_process_full_gscan_result(struct net_device *dev, +const void *data, int *send_evt_bytes) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_process_full_gscan_result(&dhd->pub, data, send_evt_bytes)); +} + +void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + dhd_gscan_hotlist_cache_cleanup(&dhd->pub, type); + + return; +} + +int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_gscan_batch_cache_cleanup(&dhd->pub)); +} + +/* Linux wrapper to call common dhd_retreive_batch_scan_results */ +int dhd_dev_retrieve_batch_scan(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_retreive_batch_scan_results(&dhd->pub)); +} + +/* Linux wrapper to call common dhd_pno_process_epno_result */ +void * dhd_dev_process_epno_result(struct net_device *dev, + const void *data, uint32 event, int *send_evt_bytes) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_process_epno_result(&dhd->pub, data, event, send_evt_bytes)); +} + +int +dhd_dev_set_lazy_roam_cfg(struct net_device *dev, + wlc_roam_exp_params_t *roam_param) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + wl_roam_exp_cfg_t roam_exp_cfg; + int err; + + if (!roam_param) { + return BCME_BADARG; + } + + DHD_ERROR(("a_band_boost_thr %d a_band_penalty_thr %d\n", + roam_param->a_band_boost_threshold, roam_param->a_band_penalty_threshold)); + DHD_ERROR(("a_band_boost_factor %d a_band_penalty_factor %d cur_bssid_boost %d\n", + roam_param->a_band_boost_factor, roam_param->a_band_penalty_factor, + roam_param->cur_bssid_boost)); + DHD_ERROR(("alert_roam_trigger_thr %d a_band_max_boost %d\n", + roam_param->alert_roam_trigger_threshold, roam_param->a_band_max_boost)); + + memcpy(&roam_exp_cfg.params, roam_param, sizeof(*roam_param)); + roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; + roam_exp_cfg.flags = ROAM_EXP_CFG_PRESENT; + if (dhd->pub.lazy_roam_enable) { + roam_exp_cfg.flags |= ROAM_EXP_ENABLE_FLAG; + } + err = dhd_iovar(&dhd->pub, 0, "roam_exp_params", + (char *)&roam_exp_cfg, sizeof(roam_exp_cfg), NULL, 0, + TRUE); + if (err < 0) { + DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); + } + return err; +} + +int +dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable) +{ + int err; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + wl_roam_exp_cfg_t roam_exp_cfg; + + memset(&roam_exp_cfg, 0, sizeof(roam_exp_cfg)); + roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; + if (enable) { + roam_exp_cfg.flags = ROAM_EXP_ENABLE_FLAG; + } + + err = dhd_iovar(&dhd->pub, 0, "roam_exp_params", + (char *)&roam_exp_cfg, sizeof(roam_exp_cfg), NULL, 0, + TRUE); + if (err < 0) { + DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); + } else { + dhd->pub.lazy_roam_enable = (enable != 0); + } + return err; +} +int +dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, + wl_bssid_pref_cfg_t *bssid_pref, uint32 flush) +{ + int err; + int len; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + bssid_pref->version = BSSID_PREF_LIST_VERSION; + /* By default programming bssid pref flushes out old values */ + bssid_pref->flags = (flush && !bssid_pref->count) ? ROAM_EXP_CLEAR_BSSID_PREF: 0; + len = sizeof(wl_bssid_pref_cfg_t); + len += (bssid_pref->count - 1) * sizeof(wl_bssid_pref_list_t); + err = dhd_iovar(&dhd->pub, 0, "roam_exp_bssid_pref", + (char *)bssid_pref, len, NULL, 0, TRUE); + if (err != BCME_OK) { + DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); + } + return err; +} +int +dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, + uint32 len, uint32 flush) +{ + int err; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int macmode; + + if (blacklist) { + err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACLIST, (char *)blacklist, + len, TRUE, 0); + if (err != BCME_OK) { + DHD_ERROR(("%s : WLC_SET_MACLIST failed %d\n", __FUNCTION__, err)); + return err; + } + } + /* By default programming blacklist flushes out old values */ + macmode = (flush && !blacklist) ? WLC_MACMODE_DISABLED : WLC_MACMODE_DENY; + err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACMODE, (char *)&macmode, + sizeof(macmode), TRUE, 0); + if (err != BCME_OK) { + DHD_ERROR(("%s : WLC_SET_MACMODE failed %d\n", __FUNCTION__, err)); + } + return err; +} +int +dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid_whitelist, + uint32 len, uint32 flush) +{ + int err; + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + wl_ssid_whitelist_t whitelist_ssid_flush; + + if (!ssid_whitelist) { + if (flush) { + ssid_whitelist = &whitelist_ssid_flush; + ssid_whitelist->ssid_count = 0; + } else { + DHD_ERROR(("%s : Nothing to do here\n", __FUNCTION__)); + return BCME_BADARG; + } + } + ssid_whitelist->version = SSID_WHITELIST_VERSION; + ssid_whitelist->flags = flush ? ROAM_EXP_CLEAR_SSID_WHITELIST : 0; + err = dhd_iovar(&dhd->pub, 0, "roam_exp_ssid_whitelist", (char *)ssid_whitelist, len, NULL, + 0, TRUE); + if (err != BCME_OK) { + DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); + } + return err; +} +#ifdef ANQPO_SUPPORT +void * dhd_dev_process_anqpo_result(struct net_device *dev, + const void *data, uint32 event, int *send_evt_bytes) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_process_anqpo_result(&dhd->pub, data, event, send_evt_bytes)); +} +#endif /* ANQPO_SUPPORT */ +#endif /* GSCAN_SUPPORT */ + +bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_is_legacy_pno_enabled(&dhd->pub)); +} + +#if defined(KEEP_ALIVE) +#define TEMP_BUF_SIZE 512 +#define FRAME_SIZE 300 +int +dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, u16 ip_pkt_len, + u8* src_mac, u8* dst_mac, u32 period_msec) +{ + char *pbuf; + const char *str; + wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0}; + wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + int buf_len; + int str_len; + int res = BCME_ERROR; + int len_bytes = 0; + int i; + + /* ether frame to have both max IP pkt (256 bytes) and ether header */ + char *pmac_frame; + + /* + * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, + * dongle shall reject a mkeep_alive request. + */ + if (!dhd_support_sta_mode(dhd_pub)) + return res; + + DHD_TRACE(("%s execution\n", __FUNCTION__)); + + if ((pbuf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { + DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE)); + res = BCME_NOMEM; + return res; + } + + if ((pmac_frame = kzalloc(FRAME_SIZE, GFP_KERNEL)) == NULL) { + DHD_ERROR(("failed to allocate mac_frame with size %d\n", FRAME_SIZE)); + res = BCME_NOMEM; + goto exit; + } + + /* + * Get current mkeep-alive status. + */ + res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), + pbuf, TEMP_BUF_SIZE, FALSE); + + if (res < 0) { + DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); + goto exit; + } else { + /* Check available ID whether it is occupied */ + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; + if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { + DHD_ERROR(("%s: Get mkeep_alive failed, ID %u is in use.\n", + __FUNCTION__, mkeep_alive_id)); + + /* Current occupied ID info */ + DHD_ERROR(("%s: mkeep_alive\n", __FUNCTION__)); + DHD_ERROR((" Id : %d\n" + " Period: %d msec\n" + " Length: %d\n" + " Packet: 0x", + mkeep_alive_pktp->keep_alive_id, + dtoh32(mkeep_alive_pktp->period_msec), + dtoh16(mkeep_alive_pktp->len_bytes))); + + for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { + DHD_ERROR(("%02x", mkeep_alive_pktp->data[i])); + } + DHD_ERROR(("\n")); + + res = BCME_NOTFOUND; + goto exit; + } + } + + /* Request the specified ID */ + memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); + memset(pbuf, 0, TEMP_BUF_SIZE); + str = "mkeep_alive"; + str_len = strlen(str); + strncpy(pbuf, str, str_len); + pbuf[str_len] = '\0'; + + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1); + mkeep_alive_pkt.period_msec = htod32(period_msec); + buf_len = str_len + 1; + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + + /* ID assigned */ + mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; + + buf_len += WL_MKEEP_ALIVE_FIXED_LEN; + + /* + * Build up Ethernet Frame + */ + + /* Mapping dest mac addr */ + memcpy(pmac_frame, dst_mac, ETHER_ADDR_LEN); + pmac_frame += ETHER_ADDR_LEN; + + /* Mapping src mac addr */ + memcpy(pmac_frame, src_mac, ETHER_ADDR_LEN); + pmac_frame += ETHER_ADDR_LEN; + + /* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */ + *(pmac_frame++) = 0x08; + *(pmac_frame++) = 0x00; + + /* Mapping IP pkt */ + memcpy(pmac_frame, ip_pkt, ip_pkt_len); + pmac_frame += ip_pkt_len; + + /* + * Length of ether frame (assume to be all hexa bytes) + * = src mac + dst mac + ether type + ip pkt len + */ + len_bytes = ETHER_ADDR_LEN*2 + ETHER_TYPE_LEN + ip_pkt_len; + /* Get back to the beginning. */ + pmac_frame -= len_bytes; + memcpy(mkeep_alive_pktp->data, pmac_frame, len_bytes); + buf_len += len_bytes; + mkeep_alive_pkt.len_bytes = htod16(len_bytes); + + /* + * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and + * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); + + res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0); +exit: + kfree(pmac_frame); + kfree(pbuf); + return res; +} + +int +dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id) +{ + char *pbuf; + wl_mkeep_alive_pkt_t mkeep_alive_pkt; + wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + int res = BCME_ERROR; + int i; + + /* + * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, + * dongle shall reject a mkeep_alive request. + */ + if (!dhd_support_sta_mode(dhd_pub)) + return res; + + DHD_TRACE(("%s execution\n", __FUNCTION__)); + + /* + * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt. + */ + if ((pbuf = kmalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { + DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE)); + return res; + } + + res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, + sizeof(mkeep_alive_id), pbuf, TEMP_BUF_SIZE, FALSE); + + if (res < 0) { + DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); + goto exit; + } else { + /* Check occupied ID */ + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; + DHD_INFO(("%s: mkeep_alive\n", __FUNCTION__)); + DHD_INFO((" Id : %d\n" + " Period: %d msec\n" + " Length: %d\n" + " Packet: 0x", + mkeep_alive_pktp->keep_alive_id, + dtoh32(mkeep_alive_pktp->period_msec), + dtoh16(mkeep_alive_pktp->len_bytes))); + + for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { + DHD_INFO(("%02x", mkeep_alive_pktp->data[i])); + } + DHD_INFO(("\n")); + } + + /* Make it stop if available */ + if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { + DHD_INFO(("stop mkeep_alive on ID %d\n", mkeep_alive_id)); + memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); + mkeep_alive_pkt.period_msec = 0; + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; + + res = dhd_iovar(dhd_pub, 0, "mkeep_alive", + (char *)&mkeep_alive_pkt, + WL_MKEEP_ALIVE_FIXED_LEN, NULL, 0, TRUE); + } else { + DHD_ERROR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id)); + res = BCME_NOTFOUND; + } +exit: + kfree(pbuf); + return res; +} +#endif /* defined(KEEP_ALIVE) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +static void dhd_hang_process(void *dhd_info, void *event_info, u8 event) +{ + dhd_info_t *dhd; + struct net_device *dev; + + dhd = (dhd_info_t *)dhd_info; + dev = dhd->iflist[0]->net; + + if (dev) { + rtnl_lock(); + dev_close(dev); + rtnl_unlock(); +#if defined(WL_WIRELESS_EXT) + wl_iw_send_priv_event(dev, "HANG"); +#endif +#if defined(WL_CFG80211) + wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); +#endif + } +} + +int dhd_os_send_hang_message(dhd_pub_t *dhdp) +{ + int ret = 0; + if (dhdp) { + if (!dhdp->hang_was_sent) { + dhdp->hang_was_sent = 1; + dhd_deferred_schedule_work((void *)dhdp, DHD_WQ_WORK_HANG_MSG, + dhd_hang_process, DHD_WORK_PRIORITY_HIGH); + } + } + return ret; +} + +int net_os_send_hang_message(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) { + /* Report FW problem when enabled */ + if (dhd->pub.hang_report) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + ret = dhd_os_send_hang_message(&dhd->pub); +#else + ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); +#endif + } else { + DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n", + __FUNCTION__)); + /* Enforce bus down to stop any future traffic */ + dhd->pub.busstate = DHD_BUS_DOWN; + } + } + return ret; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ + + +int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + return wifi_platform_set_power(dhd->adapter, on, delay_msec); +} + +void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, + wl_country_t *cspec) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + get_customized_country_code(dhd->adapter, country_iso_code, cspec); +} +void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + if (dhd && dhd->pub.up) { + memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); +#ifdef WL_CFG80211 + wl_update_wiphybands(NULL, notify); +#endif + } +} + +void dhd_bus_band_set(struct net_device *dev, uint band) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + if (dhd && dhd->pub.up) { +#ifdef WL_CFG80211 + wl_update_wiphybands(NULL, true); +#endif + } +} + +int dhd_net_set_fw_path(struct net_device *dev, char *fw) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (!fw || fw[0] == '\0') + return -EINVAL; + + strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1); + dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0'; + +#if defined(SOFTAP) + if (strstr(fw, "apsta") != NULL) { + DHD_INFO(("GOT APSTA FIRMWARE\n")); + ap_fw_loaded = TRUE; + } else { + DHD_INFO(("GOT STA FIRMWARE\n")); + ap_fw_loaded = FALSE; + } +#endif + return 0; +} + +void dhd_net_if_lock(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + dhd_net_if_lock_local(dhd); +} + +void dhd_net_if_unlock(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + dhd_net_if_unlock_local(dhd); +} + +static void dhd_net_if_lock_local(dhd_info_t *dhd) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + if (dhd) + mutex_lock(&dhd->dhd_net_if_mutex); +#endif +} + +static void dhd_net_if_unlock_local(dhd_info_t *dhd) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + if (dhd) + mutex_unlock(&dhd->dhd_net_if_mutex); +#endif +} + +static void dhd_suspend_lock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_lock(&dhd->dhd_suspend_mutex); +#endif +} + +static void dhd_suspend_unlock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_unlock(&dhd->dhd_suspend_mutex); +#endif +} + +unsigned long dhd_os_spin_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags = 0; + + if (dhd) + spin_lock_irqsave(&dhd->dhd_lock, flags); + + return flags; +} + +void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + spin_unlock_irqrestore(&dhd->dhd_lock, flags); +} + +static int +dhd_get_pend_8021x_cnt(dhd_info_t *dhd) +{ + return (atomic_read(&dhd->pend_8021x_cnt)); +} + +#define MAX_WAIT_FOR_8021X_TX 50 + +int +dhd_wait_pend8021x(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int timeout = msecs_to_jiffies(10); + int ntimes = MAX_WAIT_FOR_8021X_TX; + int pend = dhd_get_pend_8021x_cnt(dhd); + + while (ntimes && pend) { + if (pend) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(timeout); + set_current_state(TASK_RUNNING); + ntimes--; + } + pend = dhd_get_pend_8021x_cnt(dhd); + } + if (ntimes == 0) + { + atomic_set(&dhd->pend_8021x_cnt, 0); + DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__)); + } + return pend; +} + +#ifdef DHD_DEBUG +int +write_to_file(dhd_pub_t *dhd, uint8 *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("/data/mem_dump", O_WRONLY|O_CREAT, 0640); + + if (IS_ERR(fp)) { + fp = NULL; + printf("%s: open file error\n", __FUNCTION__); + ret = -1; + goto exit; + } + + /* Write buf to file */ + fp->f_op->write(fp, buf, size, &pos); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) + fp->f_op->fsync(fp, 0, size-1, 1); +#else + fp->f_op->fsync(fp, 1); +#endif /* KERNEL_VERSION(3, 1, 0) */ + +exit: + /* free buf before return */ + if (buf) { + MFREE(dhd->osh, buf, size); + } + /* close file before return */ + if (fp) + filp_close(fp, current->files); + /* restore previous address limit */ + set_fs(old_fs); + + return ret; +} + +static void dhd_join_timeout(ulong data) +{ + dhd_info_t *dhd = (dhd_info_t *)data; + if (dhd->join_timer_active) + DHD_ERROR(("DHD: %s: JOIN TIMEOUT\n", + __FUNCTION__)); +} + +int dhd_start_join_timer(dhd_pub_t *pub) +{ + int ret; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + DHD_INFO(("DHD: Join Timer Started:%s:\n", __FUNCTION__)); + if (!dhd->join_timeout_val) + dhd->join_timeout_val = DHD_JOIN_MAX_TIME_DEFAULT; + init_timer(&dhd->join_timer); + dhd->join_timer.data = (ulong)dhd; + dhd->join_timer.function = dhd_join_timeout; + dhd->join_timer_active = TRUE; + ret = mod_timer(&dhd->join_timer, jiffies + msecs_to_jiffies(dhd->join_timeout_val)); + return ret; +} +int dhd_del_join_timer(dhd_pub_t *pub) +{ + int ret = BCME_OK; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + if (dhd->join_timer_active) { + ret = del_timer(&dhd->join_timer); + DHD_INFO(("DHD: Join Timer Stopped:%s:\n", __FUNCTION__)); + } + return ret; +} +int dhd_set_join_timeout(dhd_pub_t *pub, uint32 timeout) +{ + int ret = BCME_OK; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + if (timeout) { + dhd->join_timeout_val = timeout; + return ret; + } + DHD_ERROR(("DHD: Join Timer Can not be zero:%s:\n", __FUNCTION__)); + return BCME_ERROR; +} +uint32 dhd_get_join_timeout(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)pub->info; + return dhd->join_timeout_val; +} + +static void dhd_scan_timeout(ulong data) +{ + dhd_info_t *dhd = (dhd_info_t *)data; + if (dhd->scan_timer_active) { + DHD_ERROR(("DHD: %s: SCAN TIMEOUT\n", + __FUNCTION__)); + } +} +int dhd_add_scan_timer(dhd_pub_t *pub) +{ + int ret; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + DHD_ERROR(("DHD: Scan Timer Started:%s:\n", __FUNCTION__)); + if (!dhd->scan_time_count) + dhd->scan_time_count = DHD_SCAN_DEF_TIMEOUT; + init_timer(&dhd->scan_timer); + dhd->scan_timer.data = (ulong)dhd; + dhd->scan_timer.function = dhd_scan_timeout; + dhd->scan_timer_active = TRUE; + ret = mod_timer(&dhd->scan_timer, jiffies + msecs_to_jiffies(dhd->scan_time_count)); + return ret; +} +int dhd_del_scan_timer(dhd_pub_t *pub) +{ + int ret = BCME_OK; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + if (dhd->scan_timer_active) { + ret = del_timer(&dhd->scan_timer); + DHD_INFO(("DHD: Scan Timer Stopped:%s:\n", __FUNCTION__)); + } + return ret; +} + +int dhd_set_scan_timeout(dhd_pub_t *pub, uint32 timeout) +{ + int ret = BCME_OK; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + if (timeout) { + dhd->scan_time_count = timeout; + return ret; + } + DHD_ERROR(("DHD: Scan Timer Can not be zero:%s:\n", __FUNCTION__)); + return BCME_ERROR; +} +uint32 dhd_get_scan_timeout(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)pub->info; + return dhd->scan_time_count; +} +#endif /* DHD_DEBUG */ + +int dhd_os_wake_lock_timeout(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? + dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; +#ifdef CONFIG_HAS_WAKELOCK + if (dhd->wakelock_rx_timeout_enable) + wake_lock_timeout(&dhd->wl_rxwake, + msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); + if (dhd->wakelock_ctrl_timeout_enable) + wake_lock_timeout(&dhd->wl_ctrlwake, + msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); +#endif + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +int net_os_wake_lock_timeout(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_timeout(&dhd->pub); + return ret; +} + +int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (val > dhd->wakelock_rx_timeout_enable) + dhd->wakelock_rx_timeout_enable = val; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return 0; +} + +int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (val > dhd->wakelock_ctrl_timeout_enable) + dhd->wakelock_ctrl_timeout_enable = val; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return 0; +} + +int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + dhd->wakelock_ctrl_timeout_enable = 0; +#ifdef CONFIG_HAS_WAKELOCK + if (wake_lock_active(&dhd->wl_ctrlwake)) + wake_unlock(&dhd->wl_ctrlwake); +#endif + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return 0; +} + +int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); + return ret; +} + +int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); + return ret; +} + +int dhd_os_wake_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { +#ifdef CONFIG_HAS_WAKELOCK + wake_lock(&dhd->wl_wifi); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_stay_awake(pub); +#endif + } + dhd->wakelock_counter++; + ret = dhd->wakelock_counter; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +int net_os_wake_lock(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock(&dhd->pub); + return ret; +} + +int dhd_os_wake_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + dhd_os_wake_lock_timeout(pub); + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (dhd->wakelock_counter > 0) { + dhd->wakelock_counter--; + if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { +#ifdef CONFIG_HAS_WAKELOCK + wake_unlock(&dhd->wl_wifi); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_relax(pub); +#endif + } + ret = dhd->wakelock_counter; + } + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_os_check_wakelock(dhd_pub_t *pub) +{ +#if defined(CONFIG_HAS_WAKELOCK) || (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_info_t *dhd; + + if (!pub) + return 0; + dhd = (dhd_info_t *)(pub->info); +#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ + +#ifdef CONFIG_HAS_WAKELOCK + /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ + if (dhd && (wake_lock_active(&dhd->wl_wifi) || + (wake_lock_active(&dhd->wl_wdwake)))) + return 1; +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) + return 1; +#endif + return 0; +} +int net_os_wake_unlock(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_unlock(&dhd->pub); + return ret; +} + +int dhd_os_wd_wake_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (dhd->wakelock_wd_counter == 0 && !dhd->waive_wakelock) { +#ifdef CONFIG_HAS_WAKELOCK + /* if wakelock_wd_counter was never used : lock it at once */ + wake_lock(&dhd->wl_wdwake); +#endif + } + dhd->wakelock_wd_counter++; + ret = dhd->wakelock_wd_counter; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_os_wd_wake_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (dhd->wakelock_wd_counter > 0) { + dhd->wakelock_wd_counter = 0; + if (!dhd->waive_wakelock) { +#ifdef CONFIG_HAS_WAKELOCK + wake_unlock(&dhd->wl_wdwake); +#endif + } + } + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} + +#ifdef PROP_TXSTATUS +/* waive wakelocks for operations such as IOVARs in suspend function, must be closed + * by a paired function call to dhd_wakelock_restore. returns current wakelock counter + */ +int dhd_wakelock_waive(dhd_info_t *dhdinfo) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&dhdinfo->wakelock_spinlock, flags); + /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ + if (dhdinfo->waive_wakelock) + goto exit; + /* record current lock status */ + dhdinfo->wakelock_before_waive = dhdinfo->wakelock_counter; + dhdinfo->waive_wakelock = TRUE; + +exit: + ret = dhdinfo->wakelock_wd_counter; + spin_unlock_irqrestore(&dhdinfo->wakelock_spinlock, flags); + return ret; +} + +int dhd_wakelock_restore(dhd_info_t *dhdinfo) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&dhdinfo->wakelock_spinlock, flags); + /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ + if (!dhdinfo->waive_wakelock) + goto exit; + + dhdinfo->waive_wakelock = FALSE; + /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore, + * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases + * the lock in between, do the same by calling wake_unlock or pm_relax + */ + if (dhdinfo->wakelock_before_waive == 0 && dhdinfo->wakelock_counter > 0) { +#ifdef CONFIG_HAS_WAKELOCK + wake_lock(&dhdinfo->wl_wifi); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_stay_awake(&dhdinfo->pub); +#endif + } else if (dhdinfo->wakelock_before_waive > 0 && dhdinfo->wakelock_counter == 0) { +#ifdef CONFIG_HAS_WAKELOCK + wake_unlock(&dhdinfo->wl_wifi); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + dhd_bus_dev_pm_relax(&dhdinfo->pub); +#endif + } + dhdinfo->wakelock_before_waive = 0; +exit: + ret = dhdinfo->wakelock_wd_counter; + spin_unlock_irqrestore(&dhdinfo->wakelock_spinlock, flags); + return ret; +} +#endif /* PROP_TXSTATUS */ + +bool dhd_os_check_if_up(dhd_pub_t *pub) +{ + if (!pub) + return FALSE; + return pub->up; +} + +/* function to collect firmware, chip id and chip version info */ +void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) +{ + int i; + + i = snprintf(info_string, sizeof(info_string), + " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); + + if (!dhdp) + return; + + i = snprintf(&info_string[i], sizeof(info_string) - i, + "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), + dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); +} +int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) +{ + int ifidx; + int ret = 0; + dhd_info_t *dhd = NULL; + + if (!net || !netdev_priv(net)) { + DHD_ERROR(("%s invalid parameter\n", __FUNCTION__)); + return -EINVAL; + } + + dhd = *(dhd_info_t **)netdev_priv(net); + if (!dhd) + return -EINVAL; + + ifidx = dhd_net2idx(dhd, net); + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); + return -ENODEV; + } + + DHD_OS_WAKE_LOCK(&dhd->pub); + ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); + dhd_check_hang(net, &dhd->pub, ret); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + return ret; +} + +bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) +{ + struct net_device *net; + + net = dhd_idx2net(dhdp, ifidx); + if (!net) { + DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx)); + return -EINVAL; + } + + return dhd_check_hang(net, dhdp, ret); +} + + +#ifdef PROP_TXSTATUS + +void dhd_wlfc_plat_init(void *dhd) +{ + return; +} + +void dhd_wlfc_plat_deinit(void *dhd) +{ + return; +} + +bool dhd_wlfc_skip_fc(void) +{ + return FALSE; +} +#endif /* PROP_TXSTATUS */ + +#ifdef BCMDBGFS + +#include + +extern uint32 dhd_readregl(void *bp, uint32 addr); +extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); + +typedef struct dhd_dbgfs { + struct dentry *debugfs_dir; + struct dentry *debugfs_mem; + dhd_pub_t *dhdp; + uint32 size; +} dhd_dbgfs_t; + +dhd_dbgfs_t g_dbgfs; + +static int +dhd_dbg_state_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t +dhd_dbg_state_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + ssize_t rval; + uint32 tmp; + loff_t pos = *ppos; + size_t ret; + + if (pos < 0) + return -EINVAL; + if (pos >= g_dbgfs.size || !count) + return 0; + if (count > g_dbgfs.size - pos) + count = g_dbgfs.size - pos; + + /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ + tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); + + ret = copy_to_user(ubuf, &tmp, 4); + if (ret == count) + return -EFAULT; + + count -= ret; + *ppos = pos + count; + rval = count; + + return rval; +} + + +static ssize_t +dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) +{ + loff_t pos = *ppos; + size_t ret; + uint32 buf; + + if (pos < 0) + return -EINVAL; + if (pos >= g_dbgfs.size || !count) + return 0; + if (count > g_dbgfs.size - pos) + count = g_dbgfs.size - pos; + + ret = copy_from_user(&buf, ubuf, sizeof(uint32)); + if (ret == count) + return -EFAULT; + + /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ + dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); + + return count; +} + + +loff_t +dhd_debugfs_lseek(struct file *file, loff_t off, int whence) +{ + loff_t pos = -1; + + switch (whence) { + case 0: + pos = off; + break; + case 1: + pos = file->f_pos + off; + break; + case 2: + pos = g_dbgfs.size - off; + } + return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); +} + +static const struct file_operations dhd_dbg_state_ops = { + .read = dhd_dbg_state_read, + .write = dhd_debugfs_write, + .open = dhd_dbg_state_open, + .llseek = dhd_debugfs_lseek +}; + +static void dhd_dbg_create(void) +{ + if (g_dbgfs.debugfs_dir) { + g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, + NULL, &dhd_dbg_state_ops); + } +} + +void dhd_dbg_init(dhd_pub_t *dhdp) +{ + int err; + + g_dbgfs.dhdp = dhdp; + g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ + + g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); + if (IS_ERR(g_dbgfs.debugfs_dir)) { + err = PTR_ERR(g_dbgfs.debugfs_dir); + g_dbgfs.debugfs_dir = NULL; + return; + } + + dhd_dbg_create(); + + return; +} + +void dhd_dbg_remove(void) +{ + debugfs_remove(g_dbgfs.debugfs_mem); + debugfs_remove(g_dbgfs.debugfs_dir); + + bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); + +} +#endif /* ifdef BCMDBGFS */ + +#ifdef WLMEDIA_HTSF + +static +void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) +{ + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct sk_buff *skb; + uint32 htsf = 0; + uint16 dport = 0, oldmagic = 0xACAC; + char *p1; + htsfts_t ts; + + /* timestamp packet */ + + p1 = (char*) PKTDATA(dhdp->osh, pktbuf); + + if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { +/* memcpy(&proto, p1+26, 4); */ + memcpy(&dport, p1+40, 2); +/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ + dport = ntoh16(dport); + } + + /* timestamp only if icmp or udb iperf with port 5555 */ +/* if (proto == 17 && dport == tsport) { */ + if (dport >= tsport && dport <= tsport + 20) { + + skb = (struct sk_buff *) pktbuf; + + htsf = dhd_get_htsf(dhd, 0); + memset(skb->data + 44, 0, 2); /* clear checksum */ + memcpy(skb->data+82, &oldmagic, 2); + memcpy(skb->data+84, &htsf, 4); + + memset(&ts, 0, sizeof(htsfts_t)); + ts.magic = HTSFMAGIC; + ts.prio = PKTPRIO(pktbuf); + ts.seqnum = htsf_seqnum++; + ts.c10 = get_cycles(); + ts.t10 = htsf; + ts.endmagic = HTSFENDMAGIC; + + memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); + } +} + +static void dhd_dump_htsfhisto(histo_t *his, char *s) +{ + int pktcnt = 0, curval = 0, i; + for (i = 0; i < (NUMBIN-2); i++) { + curval += 500; + printf("%d ", his->bin[i]); + pktcnt += his->bin[i]; + } + printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, + his->bin[NUMBIN-1], s); +} + +static +void sorttobin(int value, histo_t *histo) +{ + int i, binval = 0; + + if (value < 0) { + histo->bin[NUMBIN-1]++; + return; + } + if (value > histo->bin[NUMBIN-2]) /* store the max value */ + histo->bin[NUMBIN-2] = value; + + for (i = 0; i < (NUMBIN-2); i++) { + binval += 500; /* 500m s bins */ + if (value <= binval) { + histo->bin[i]++; + return; + } + } + histo->bin[NUMBIN-3]++; +} + +static +void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + struct sk_buff *skb; + char *p1; + uint16 old_magic; + int d1, d2, d3, end2end; + htsfts_t *htsf_ts; + uint32 htsf; + + skb = PKTTONATIVE(dhdp->osh, pktbuf); + p1 = (char*)PKTDATA(dhdp->osh, pktbuf); + + if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { + memcpy(&old_magic, p1+78, 2); + htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); + } + else + return; + + if (htsf_ts->magic == HTSFMAGIC) { + htsf_ts->tE0 = dhd_get_htsf(dhd, 0); + htsf_ts->cE0 = get_cycles(); + } + + if (old_magic == 0xACAC) { + + tspktcnt++; + htsf = dhd_get_htsf(dhd, 0); + memcpy(skb->data+92, &htsf, sizeof(uint32)); + + memcpy(&ts[tsidx].t1, skb->data+80, 16); + + d1 = ts[tsidx].t2 - ts[tsidx].t1; + d2 = ts[tsidx].t3 - ts[tsidx].t2; + d3 = ts[tsidx].t4 - ts[tsidx].t3; + end2end = ts[tsidx].t4 - ts[tsidx].t1; + + sorttobin(d1, &vi_d1); + sorttobin(d2, &vi_d2); + sorttobin(d3, &vi_d3); + sorttobin(end2end, &vi_d4); + + if (end2end > 0 && end2end > maxdelay) { + maxdelay = end2end; + maxdelaypktno = tspktcnt; + memcpy(&maxdelayts, &ts[tsidx], 16); + } + if (++tsidx >= TSMAX) + tsidx = 0; + } +} + +uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) +{ + uint32 htsf = 0, cur_cycle, delta, delta_us; + uint32 factor, baseval, baseval2; + cycles_t t; + + t = get_cycles(); + cur_cycle = t; + + if (cur_cycle > dhd->htsf.last_cycle) + delta = cur_cycle - dhd->htsf.last_cycle; + else { + delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); + } + + delta = delta >> 4; + + if (dhd->htsf.coef) { + /* times ten to get the first digit */ + factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); + baseval = (delta*10)/factor; + baseval2 = (delta*10)/(factor+1); + delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); + htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; + } + else { + DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n")); + } + + return htsf; +} + +static void dhd_dump_latency(void) +{ + int i, max = 0; + int d1, d2, d3, d4, d5; + + printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); + for (i = 0; i < TSMAX; i++) { + d1 = ts[i].t2 - ts[i].t1; + d2 = ts[i].t3 - ts[i].t2; + d3 = ts[i].t4 - ts[i].t3; + d4 = ts[i].t4 - ts[i].t1; + d5 = ts[max].t4-ts[max].t1; + if (d4 > d5 && d4 > 0) { + max = i; + } + printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", + ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, + d1, d2, d3, d4, i); + } + + printf("current idx = %d \n", tsidx); + + printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); + printf("%08X %08X %08X %08X \t%d %d %d %d\n", + maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, + maxdelayts.t2 - maxdelayts.t1, + maxdelayts.t3 - maxdelayts.t2, + maxdelayts.t4 - maxdelayts.t3, + maxdelayts.t4 - maxdelayts.t1); +} + + +static int +dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) +{ + char buf[32]; + int ret; + uint32 s1, s2; + + struct tsf { + uint32 low; + uint32 high; + } tsf_buf; + + memset(&tsf_buf, 0, sizeof(tsf_buf)); + + s1 = dhd_get_htsf(dhd, 0); + ret = dhd_iovar(&dhd->pub, ifidx, "tsf", NULL, 0, buf, sizeof(buf), FALSE); + if (ret < 0) { + if (ret == -EIO) { + DHD_ERROR(("%s: tsf is not supported by device\n", + dhd_ifname(&dhd->pub, ifidx))); + return -EOPNOTSUPP; + } + return ret; + } + s2 = dhd_get_htsf(dhd, 0); + + memcpy(&tsf_buf, buf, sizeof(tsf_buf)); + printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", + tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, + dhd->htsf.coefdec2, s2-tsf_buf.low); + printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); + return 0; +} + +void htsf_update(dhd_info_t *dhd, void *data) +{ + static ulong cur_cycle = 0, prev_cycle = 0; + uint32 htsf, tsf_delta = 0; + uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; + ulong b, a; + cycles_t t; + + /* cycles_t in inlcude/mips/timex.h */ + + t = get_cycles(); + + prev_cycle = cur_cycle; + cur_cycle = t; + + if (cur_cycle > prev_cycle) + cyc_delta = cur_cycle - prev_cycle; + else { + b = cur_cycle; + a = prev_cycle; + cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); + } + + if (data == NULL) + printf(" tsf update ata point er is null \n"); + + memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); + memcpy(&cur_tsf, data, sizeof(tsf_t)); + + if (cur_tsf.low == 0) { + DHD_INFO((" ---- 0 TSF, do not update, return\n")); + return; + } + + if (cur_tsf.low > prev_tsf.low) + tsf_delta = (cur_tsf.low - prev_tsf.low); + else { + DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", + cur_tsf.low, prev_tsf.low)); + if (cur_tsf.high > prev_tsf.high) { + tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); + DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta)); + } + else + return; /* do not update */ + } + + if (tsf_delta) { + hfactor = cyc_delta / tsf_delta; + tmp = (cyc_delta - (hfactor * tsf_delta))*10; + dec1 = tmp/tsf_delta; + dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; + tmp = (tmp - (dec1*tsf_delta))*10; + dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; + + if (dec3 > 4) { + if (dec2 == 9) { + dec2 = 0; + if (dec1 == 9) { + dec1 = 0; + hfactor++; + } + else { + dec1++; + } + } + else + dec2++; + } + } + + if (hfactor) { + htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; + dhd->htsf.coef = hfactor; + dhd->htsf.last_cycle = cur_cycle; + dhd->htsf.last_tsf = cur_tsf.low; + dhd->htsf.coefdec1 = dec1; + dhd->htsf.coefdec2 = dec2; + } + else { + htsf = prev_tsf.low; + } +} + +#endif /* WLMEDIA_HTSF */ + + +#ifdef CUSTOMER_HW5 +bool dhd_is_p2p_connection(struct net_device *ndev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(ndev); + + if (dhd->pub.op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE)) { + return TRUE; + } + return FALSE; +} +#endif /* CUSTOMER_HW5 */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h new file mode 100644 index 000000000000..af6517b8de7b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h @@ -0,0 +1,74 @@ +/* + * DHD Linux header file (dhd_linux exports for cfg80211 and other components) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux.h 399301 2013-04-29 21:41:52Z $ + */ + +/* wifi platform functions for power, interrupt and pre-alloc, either + * from Android-like platform device data, or Broadcom wifi platform + * device data. + * + */ +#ifndef __DHD_LINUX_H__ +#define __DHD_LINUX_H__ + +#include +#include +#include +#include + +#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ + +typedef struct wifi_adapter_info { + const char *name; + uint irq_num; + uint intr_flags; + const char *fw_path; + const char *nv_path; + void *wifi_plat_data; /* wifi ctrl func, for backward compatibility */ + uint bus_type; + uint bus_num; + uint slot_num; +} wifi_adapter_info_t; + +typedef struct bcmdhd_wifi_platdata { + uint num_adapters; + wifi_adapter_info_t *adapters; +} bcmdhd_wifi_platdata_t; + +int dhd_wifi_platform_register_drv(void); +void dhd_wifi_platform_unregister_drv(void); +wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, + uint32 slot_num); +int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec); +int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present); +int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr); +int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf); +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode); +void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size); +void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter); + +int dhd_get_fw_mode(struct dhd_info *dhdinfo); +bool dhd_update_fw_nv_path(struct dhd_info *dhdinfo); + +#endif /* __DHD_LINUX_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c new file mode 100644 index 000000000000..a25ce6f51beb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c @@ -0,0 +1,760 @@ +/* + * Linux platform device for DHD WLAN adapter + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2013 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux_platdev.c 401742 2013-05-13 15:03:21Z $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_WIFI_CONTROL_FUNC) +#include +#endif +#ifdef CONFIG_DTS +#include +#include +#endif /* CONFIG_DTS */ +#ifdef CONFIG_SOMC_WIFI_CONTROL +#include +#endif /* CONFIG_SOMC_WIFI_CONTROL */ +#if !defined(CONFIG_WIFI_CONTROL_FUNC) +struct wifi_platform_data { + int (*set_power)(int val); + int (*set_reset)(int val); + int (*set_carddetect)(int val); + void *(*mem_prealloc)(int section, unsigned long size); + int (*get_mac_addr)(unsigned char *buf); + void *(*get_country_code)(char *ccode); +}; +#endif /* CONFIG_WIFI_CONTROL_FUNC */ + +#define WIFI_PLAT_NAME "bcmdhd_wlan" +#define WIFI_PLAT_NAME2 "bcm4329_wlan" +#define WIFI_PLAT_EXT "bcmdhd_wifi_platform" + +#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) +struct regulator *wifi_regulator = NULL; +#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ + +bool cfg_multichip = FALSE; +bcmdhd_wifi_platdata_t *dhd_wifi_platdata = NULL; +static int wifi_plat_dev_probe_ret = 0; +static bool is_power_on = FALSE; +#if !defined(CONFIG_DTS) +#if defined(DHD_OF_SUPPORT) +static bool dts_enabled = TRUE; +extern struct resource dhd_wlan_resources; +extern struct wifi_platform_data dhd_wlan_control; +#else +static bool dts_enabled = FALSE; +struct resource dhd_wlan_resources = {0}; +struct wifi_platform_data dhd_wlan_control = {0}; +#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */ +#endif /* !defind(CONFIG_DTS) */ + +static int dhd_wifi_platform_load(void); + +extern void* wl_cfg80211_get_dhdp(void); + +#ifdef ENABLE_4335BT_WAR +extern int bcm_bt_lock(int cookie); +extern void bcm_bt_unlock(int cookie); +static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ +#endif /* ENABLE_4335BT_WAR */ + +wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num) +{ + int i; + + if (dhd_wifi_platdata == NULL) + return NULL; + + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; + if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && + (adapter->bus_num == -1 || adapter->bus_num == bus_num) && + (adapter->slot_num == -1 || adapter->slot_num == slot_num)) { + DHD_TRACE(("found adapter info '%s'\n", adapter->name)); + return adapter; + } + } + return NULL; +} + +void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size) +{ + void *alloc_ptr = NULL; + struct wifi_platform_data *plat_data; + + if (!adapter || !adapter->wifi_plat_data) + return NULL; + plat_data = adapter->wifi_plat_data; + if (plat_data->mem_prealloc) { + alloc_ptr = plat_data->mem_prealloc(section, size); + if (alloc_ptr) { + DHD_INFO(("success alloc section %d\n", section)); + if (size != 0L) + bzero(alloc_ptr, size); + return alloc_ptr; + } + } + + DHD_ERROR(("%s: failed to alloc static mem section %d\n", __FUNCTION__, section)); + return NULL; +} + +void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter) +{ + struct wifi_platform_data *plat_data; + + if (!adapter || !adapter->wifi_plat_data) + return NULL; + plat_data = adapter->wifi_plat_data; + return plat_data->mem_prealloc; +} + +int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr) +{ + if (adapter == NULL) + return -1; + if (irq_flags_ptr) + *irq_flags_ptr = adapter->intr_flags; + return adapter->irq_num; +} + +int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec) +{ + int err = 0; +#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) + if (on) { + err = regulator_enable(wifi_regulator); + is_power_on = TRUE; + } + else { + err = regulator_disable(wifi_regulator); + is_power_on = FALSE; + } + if (err < 0) + DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__)); +#else + struct wifi_platform_data *plat_data; + + if (!adapter || !adapter->wifi_plat_data) + return -EINVAL; + plat_data = adapter->wifi_plat_data; + + DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); + if (plat_data->set_power) { +#ifdef ENABLE_4335BT_WAR + if (on) { + printk("WiFi: trying to acquire BT lock\n"); + if (bcm_bt_lock(lock_cookie_wifi) != 0) + printk("** WiFi: timeout in acquiring bt lock**\n"); + printk("%s: btlock acquired\n", __FUNCTION__); + } + else { + /* For a exceptional case, release btlock */ + bcm_bt_unlock(lock_cookie_wifi); + } +#endif /* ENABLE_4335BT_WAR */ + + err = plat_data->set_power(on); + } + + if (msec && !err) + OSL_SLEEP(msec); + + if (on && !err) + is_power_on = TRUE; + else + is_power_on = FALSE; + +#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ + + return err; +} + +int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present) +{ + int err = 0; + struct wifi_platform_data *plat_data; + + if (!adapter || !adapter->wifi_plat_data) + return -EINVAL; + plat_data = adapter->wifi_plat_data; + + DHD_ERROR(("%s device present %d\n", __FUNCTION__, device_present)); + if (plat_data->set_carddetect) { + err = plat_data->set_carddetect(device_present); + } + return err; + +} + +int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf) +{ + struct wifi_platform_data *plat_data; + + DHD_ERROR(("%s\n", __FUNCTION__)); + if (!buf || !adapter || !adapter->wifi_plat_data) + return -EINVAL; + plat_data = adapter->wifi_plat_data; + if (plat_data->get_mac_addr) { + return plat_data->get_mac_addr(buf); + } +#ifdef GET_CUSTOM_MAC_ENABLE + return somc_get_mac_address(buf); +#else + return -EOPNOTSUPP; +#endif +} + +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) +{ + /* get_country_code was added after 2.6.39 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) + struct wifi_platform_data *plat_data; + + if (!ccode || !adapter || !adapter->wifi_plat_data) + return NULL; + plat_data = adapter->wifi_plat_data; + + DHD_TRACE(("%s\n", __FUNCTION__)); + if (plat_data->get_country_code) { + return plat_data->get_country_code(ccode); + } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ + + return NULL; +} + +static int wifi_plat_dev_drv_probe(struct platform_device *pdev) +{ + struct resource *resource; + wifi_adapter_info_t *adapter; +#ifdef CONFIG_DTS + int irq, gpio; +#endif /* CONFIG_DTS */ + + /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") + * is kept for backward compatibility and supports only 1 adapter + */ + ASSERT(dhd_wifi_platdata != NULL); + ASSERT(dhd_wifi_platdata->num_adapters == 1); + adapter = &dhd_wifi_platdata->adapters[0]; +#ifdef CONFIG_SOMC_WIFI_CONTROL + adapter->wifi_plat_data = (void *)&somc_wifi_control; +#else + adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data); +#endif /* CONFIG_SOMC_WIFI_CONTROL */ + resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); + if (resource == NULL) + resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); + if (resource) { + adapter->irq_num = resource->start; + adapter->intr_flags = resource->flags; + } +#ifdef CONFIG_SOMC_WIFI_CONTROL + somc_wifi_init(pdev); +#endif /* CONFIG_SOMC_WIFI_CONTROL */ +#ifdef CONFIG_DTS +#ifndef CUSTOMER_HW5 + wifi_regulator = regulator_get(&pdev->dev, "wlreg_on"); + if (wifi_regulator == NULL) { + DHD_ERROR(("%s regulator is null\n", __FUNCTION__)); + return -1; + } +#endif /* CUSTOMER_HW5 */ + /* This is to get the irq for the OOB */ +#ifdef CONFIG_SOMC_WIFI_CONTROL + gpio = of_get_gpio(pdev->dev.of_node, 1); +#else + gpio = of_get_gpio(pdev->dev.of_node, 0); +#endif /* CONFIG_SOMC_WIFI_CONTROL */ + if (gpio < 0) { + DHD_ERROR(("%s gpio information is incorrect\n", __FUNCTION__)); + return -1; + } + irq = gpio_to_irq(gpio); + if (irq < 0) { + DHD_ERROR(("%s irq information is incorrect\n", __FUNCTION__)); + return -1; + } + adapter->irq_num = irq; + + /* need to change the flags according to our requirement */ + adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | + IORESOURCE_IRQ_SHAREABLE; +#endif /* CONFIG_DTS */ + + wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); + return wifi_plat_dev_probe_ret; +} + +static int wifi_plat_dev_drv_remove(struct platform_device *pdev) +{ + wifi_adapter_info_t *adapter; + + /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") + * is kept for backward compatibility and supports only 1 adapter + */ + ASSERT(dhd_wifi_platdata != NULL); + ASSERT(dhd_wifi_platdata->num_adapters == 1); + adapter = &dhd_wifi_platdata->adapters[0]; + if (is_power_on) { + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); +#ifndef CUSTOMER_HW5 + wifi_platform_bus_enumerate(adapter, FALSE); +#endif + } +#ifdef CUSTOMER_HW5 + /* Sony mobile uses ENABLE_INSMOD_NO_FW_LOAD for module type driver + * They want to download firmware when primary interface is brought up + * The is_power_on is set to false through wl_android_wifi_off(). + * So move the func to here. + */ + wifi_platform_bus_enumerate(adapter, FALSE); +#endif + +#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) + regulator_put(wifi_regulator); +#endif /* defined(CONFIG_DTS) && !defined(CUSTOMER_HW5) */ +#ifdef CONFIG_SOMC_WIFI_CONTROL + somc_wifi_deinit(pdev); +#endif /* CONFIG_SOMC_WIFI_CONTROL */ + return 0; +} + +static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(0); +#endif /* (OOB_INTR_ONLY) */ + return 0; +} + +static int wifi_plat_dev_drv_resume(struct platform_device *pdev) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) + if (dhd_os_check_if_up(wl_cfg80211_get_dhdp())) + bcmsdh_oob_intr_set(1); +#endif /* (OOB_INTR_ONLY) */ + return 0; +} + +#ifdef CONFIG_DTS +static const struct of_device_id wifi_device_dt_match[] = { + { .compatible = "android,bcmdhd_wlan", }, + {}, +}; +#endif /* CONFIG_DTS */ +static struct platform_driver wifi_platform_dev_driver = { + .probe = wifi_plat_dev_drv_probe, + .remove = wifi_plat_dev_drv_remove, + .suspend = wifi_plat_dev_drv_suspend, + .resume = wifi_plat_dev_drv_resume, + .driver = { + .name = WIFI_PLAT_NAME, +#ifdef CONFIG_DTS + .of_match_table = wifi_device_dt_match, +#endif /* CONFIG_DTS */ + } +}; + +static struct platform_driver wifi_platform_dev_driver_legacy = { + .probe = wifi_plat_dev_drv_probe, + .remove = wifi_plat_dev_drv_remove, + .suspend = wifi_plat_dev_drv_suspend, + .resume = wifi_plat_dev_drv_resume, + .driver = { + .name = WIFI_PLAT_NAME2, + } +}; + +static int wifi_platdev_match(struct device *dev, void *data) +{ + char *name = (char*)data; + struct platform_device *pdev = to_platform_device(dev); + + if (strcmp(pdev->name, name) == 0) { + DHD_ERROR(("found wifi platform device %s\n", name)); + return TRUE; + } + + return FALSE; +} + +static int wifi_ctrlfunc_register_drv(void) +{ + int err = 0; + struct device *dev1, *dev2; + wifi_adapter_info_t *adapter; + + dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); + dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); + +#if !defined(CONFIG_DTS) + if (!dts_enabled) { + if (dev1 == NULL && dev2 == NULL) { + DHD_ERROR(("no wifi platform data, skip\n")); + return -ENXIO; + } + } +#endif /* !defined(CONFIG_DTS) */ + + /* multi-chip support not enabled, build one adapter information for + * DHD (either SDIO, USB or PCIe) + */ + adapter = kzalloc(sizeof(wifi_adapter_info_t), GFP_KERNEL); + adapter->name = "DHD generic adapter"; + adapter->bus_type = -1; + adapter->bus_num = -1; + adapter->slot_num = -1; + adapter->irq_num = -1; + is_power_on = FALSE; + wifi_plat_dev_probe_ret = 0; + dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL); + dhd_wifi_platdata->num_adapters = 1; + dhd_wifi_platdata->adapters = adapter; + + if (dev1) { + err = platform_driver_register(&wifi_platform_dev_driver); + if (err) { + DHD_ERROR(("%s: failed to register wifi ctrl func driver\n", + __FUNCTION__)); + return err; + } + } + if (dev2) { + err = platform_driver_register(&wifi_platform_dev_driver_legacy); + if (err) { + DHD_ERROR(("%s: failed to register wifi ctrl func legacy driver\n", + __FUNCTION__)); + return err; + } + } + +#if !defined(CONFIG_DTS) + if (dts_enabled) { + struct resource *resource; + adapter->wifi_plat_data = (void *)&dhd_wlan_control; + resource = &dhd_wlan_resources; + adapter->irq_num = resource->start; + adapter->intr_flags = resource->flags; + wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); + } +#endif /* !defined(CONFIG_DTS) */ + + +#ifdef CONFIG_DTS + wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver); +#endif /* CONFIG_DTS */ + + /* return probe function's return value if registeration succeeded */ + return wifi_plat_dev_probe_ret; +} + +void wifi_ctrlfunc_unregister_drv(void) +{ + +#ifdef CONFIG_DTS + DHD_ERROR(("unregister wifi platform drivers\n")); + platform_driver_unregister(&wifi_platform_dev_driver); +#else + struct device *dev1, *dev2; + dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); + dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); + if (!dts_enabled) + if (dev1 == NULL && dev2 == NULL) + return; + + DHD_ERROR(("unregister wifi platform drivers\n")); + if (dev1) + platform_driver_unregister(&wifi_platform_dev_driver); + if (dev2) + platform_driver_unregister(&wifi_platform_dev_driver_legacy); + if (dts_enabled) { + wifi_adapter_info_t *adapter; + adapter = &dhd_wifi_platdata->adapters[0]; + if (is_power_on) { + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + wifi_platform_bus_enumerate(adapter, FALSE); + } + } +#endif /* !defined(CONFIG_DTS) */ + + kfree(dhd_wifi_platdata->adapters); + dhd_wifi_platdata->adapters = NULL; + dhd_wifi_platdata->num_adapters = 0; + kfree(dhd_wifi_platdata); + dhd_wifi_platdata = NULL; +} + +static int bcmdhd_wifi_plat_dev_drv_probe(struct platform_device *pdev) +{ + dhd_wifi_platdata = (bcmdhd_wifi_platdata_t *)(pdev->dev.platform_data); + + return dhd_wifi_platform_load(); +} + +static int bcmdhd_wifi_plat_dev_drv_remove(struct platform_device *pdev) +{ + int i; + wifi_adapter_info_t *adapter; + ASSERT(dhd_wifi_platdata != NULL); + + /* power down all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + adapter = &dhd_wifi_platdata->adapters[i]; + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + wifi_platform_bus_enumerate(adapter, FALSE); + } + return 0; +} + +static struct platform_driver dhd_wifi_platform_dev_driver = { + .probe = bcmdhd_wifi_plat_dev_drv_probe, + .remove = bcmdhd_wifi_plat_dev_drv_remove, + .driver = { + .name = WIFI_PLAT_EXT, + } +}; + +int dhd_wifi_platform_register_drv(void) +{ + int err = 0; + struct device *dev; + + /* register Broadcom wifi platform data driver if multi-chip is enabled, + * otherwise use Android style wifi platform data (aka wifi control function) + * if it exists + * + * to support multi-chip DHD, Broadcom wifi platform data device must + * be added in kernel early boot (e.g. board config file). + */ + if (cfg_multichip) { + dev = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_EXT, wifi_platdev_match); + if (dev == NULL) { + DHD_ERROR(("bcmdhd wifi platform data device not found!!\n")); + return -ENXIO; + } + err = platform_driver_register(&dhd_wifi_platform_dev_driver); + } else { + err = wifi_ctrlfunc_register_drv(); + + /* no wifi ctrl func either, load bus directly and ignore this error */ + if (err) { + if (err == -ENXIO) { + /* wifi ctrl function does not exist */ + err = dhd_wifi_platform_load(); + } else { + /* unregister driver due to initialization failure */ + wifi_ctrlfunc_unregister_drv(); + } + } + } + + return err; +} + +#ifdef BCMPCIE +static int dhd_wifi_platform_load_pcie(void) +{ + int err = 0; + err = dhd_bus_register(); + return err; +} +#else +static int dhd_wifi_platform_load_pcie(void) +{ + return 0; +} +#endif /* BCMPCIE */ + + +void dhd_wifi_platform_unregister_drv(void) +{ + if (cfg_multichip) + platform_driver_unregister(&dhd_wifi_platform_dev_driver); + else + wifi_ctrlfunc_unregister_drv(); +} + +extern int dhd_watchdog_prio; +extern int dhd_dpc_prio; +extern uint dhd_deferred_tx; +#if defined(BCMLXSDMMC) +extern struct semaphore dhd_registration_sem; +#endif + +static int dhd_wifi_platform_load_sdio(void) +{ + int i; + int err = 0; + wifi_adapter_info_t *adapter; + + BCM_REFERENCE(i); + BCM_REFERENCE(adapter); + /* Sanity check on the module parameters + * - Both watchdog and DPC as tasklets are ok + * - If both watchdog and DPC are threads, TX must be deferred + */ + if (!(dhd_watchdog_prio < 0 && dhd_dpc_prio < 0) && + !(dhd_watchdog_prio >= 0 && dhd_dpc_prio >= 0 && dhd_deferred_tx)) + return -EINVAL; + +#if defined(BCMLXSDMMC) + if (dhd_wifi_platdata == NULL) { + DHD_ERROR(("DHD wifi platform data is required for Android build\n")); + return -EINVAL; + } + + sema_init(&dhd_registration_sem, 0); + /* power up all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + bool chip_up = FALSE; + int retry = POWERUP_MAX_RETRY; + struct semaphore dhd_chipup_sem; + + adapter = &dhd_wifi_platdata->adapters[i]; + + DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); + DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", + adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); + DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", + adapter->bus_type, adapter->bus_num, adapter->slot_num)); + + do { + sema_init(&dhd_chipup_sem, 0); + err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); + if (err) { + DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n", + __FUNCTION__, err)); + return err; + } + err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); + if (err) { + /* WL_REG_ON state unknown, Power off forcely */ + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + continue; + } else { + wifi_platform_bus_enumerate(adapter, TRUE); + err = 0; + } + + if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { + dhd_bus_unreg_sdio_notify(); + chip_up = TRUE; + break; + } + + DHD_ERROR(("failed to power up %s, %d retry left\n", adapter->name, retry)); + dhd_bus_unreg_sdio_notify(); + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + wifi_platform_bus_enumerate(adapter, FALSE); + } while (retry--); + + if (!chip_up) { + DHD_ERROR(("failed to power up %s, max retry reached**\n", adapter->name)); + return -ENODEV; + } + + } + + err = dhd_bus_register(); + + if (err) { + DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); + goto fail; + } + + + /* + * Wait till MMC sdio_register_driver callback called and made driver attach. + * It's needed to make sync up exit from dhd insmod and + * Kernel MMC sdio device callback registration + */ + err = down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); + if (err) { + DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__)); + dhd_bus_unregister(); + goto fail; + } + + return err; + +fail: + /* power down all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + adapter = &dhd_wifi_platdata->adapters[i]; + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + wifi_platform_bus_enumerate(adapter, FALSE); + } +#else + + /* x86 bring-up PC needs no power-up operations */ + err = dhd_bus_register(); + +#endif + + return err; +} + +static int dhd_wifi_platform_load_usb(void) +{ + return 0; +} + +static int dhd_wifi_platform_load() +{ + int err = 0; + + wl_android_init(); + + if ((err = dhd_wifi_platform_load_usb())) + goto end; + else if ((err = dhd_wifi_platform_load_sdio())) + goto end; + else + err = dhd_wifi_platform_load_pcie(); + +end: + if (err) + wl_android_exit(); + else + wl_android_post_init(); + + return err; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c new file mode 100644 index 000000000000..4b62ee40c2f1 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c @@ -0,0 +1,48 @@ +/* + * Expose some of the kernel scheduler routines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux_sched.c 457596 2014-02-24 02:24:14Z $ + */ +#include +#include +#include +#include +#include + +int setScheduler(struct task_struct *p, int policy, struct sched_param *param) +{ + int rc = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + rc = sched_setscheduler(p, policy, param); +#endif /* LinuxVer */ + return rc; +} + +int get_scheduler_policy(struct task_struct *p) +{ + int rc = SCHED_NORMAL; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + rc = p->policy; +#endif /* LinuxVer */ + return rc; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c new file mode 100644 index 000000000000..ea4d567b1941 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c @@ -0,0 +1,316 @@ +/* + * Broadcom Dongle Host Driver (DHD), Generic work queue framework + * Generic interface to handle dhd deferred work events + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux_wq.c 411851 2013-07-10 20:48:00Z $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct dhd_deferred_event_t { + u8 event; /* holds the event */ + void *event_data; /* Holds event specific data */ + event_handler_t event_handler; +}; +#define DEFRD_EVT_SIZE sizeof(struct dhd_deferred_event_t) + +struct dhd_deferred_wq { + struct work_struct deferred_work; /* should be the first member */ + + /* + * work events may occur simultaneously. + * Can hold upto 64 low priority events and 4 high priority events + */ +#define DHD_PRIO_WORK_FIFO_SIZE (4 * sizeof(struct dhd_deferred_event_t)) +#define DHD_WORK_FIFO_SIZE (64 * sizeof(struct dhd_deferred_event_t)) + struct kfifo *prio_fifo; + struct kfifo *work_fifo; + u8 *prio_fifo_buf; + u8 *work_fifo_buf; + spinlock_t work_lock; + void *dhd_info; /* review: does it require */ +}; +struct dhd_deferred_wq *deferred_wq = NULL; + +static inline struct kfifo* +dhd_kfifo_init(u8 *buf, int size, spinlock_t *lock) +{ + struct kfifo *fifo; + gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) + fifo = kfifo_init(buf, size, flags, lock); +#else + fifo = (struct kfifo *)kzalloc(sizeof(struct kfifo), flags); + if (!fifo) { + return NULL; + } + kfifo_init(fifo, buf, size); +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ + return fifo; +} + +static inline void +dhd_kfifo_free(struct kfifo *fifo) +{ + kfifo_free(fifo); +} + +/* deferred work functions */ +static void dhd_deferred_work_handler(struct work_struct *data); + +void* +dhd_deferred_work_init(void *dhd_info) +{ + struct dhd_deferred_wq *work = NULL; + u8* buf; + unsigned long fifo_size = 0; + gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC; + + if (!dhd_info) { + DHD_ERROR(("%s: dhd info not initialized\n", __FUNCTION__)); + goto return_null; + } + + work = (struct dhd_deferred_wq *)kzalloc(sizeof(struct dhd_deferred_wq), + flags); + + if (!work) { + DHD_ERROR(("%s: work queue creation failed \n", __FUNCTION__)); + goto return_null; + } + + INIT_WORK((struct work_struct *)work, dhd_deferred_work_handler); + + /* initialize event fifo */ + spin_lock_init(&work->work_lock); + + /* allocate buffer to hold prio events */ + fifo_size = DHD_PRIO_WORK_FIFO_SIZE; + fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); + buf = (u8*)kzalloc(fifo_size, flags); + if (!buf) { + DHD_ERROR(("%s: prio work fifo allocation failed \n", __FUNCTION__)); + goto return_null; + } + + /* Initialize prio event fifo */ + work->prio_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); + if (!work->prio_fifo) { + kfree(buf); + goto return_null; + } + + /* allocate buffer to hold work events */ + fifo_size = DHD_WORK_FIFO_SIZE; + fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); + buf = (u8*)kzalloc(fifo_size, flags); + if (!buf) { + DHD_ERROR(("%s: work fifo allocation failed \n", __FUNCTION__)); + goto return_null; + } + + /* Initialize event fifo */ + work->work_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); + if (!work->work_fifo) { + kfree(buf); + goto return_null; + } + + work->dhd_info = dhd_info; + deferred_wq = work; + DHD_ERROR(("%s: work queue initialized \n", __FUNCTION__)); + return work; + +return_null: + + if (work) + dhd_deferred_work_deinit(work); + + return NULL; +} + +void +dhd_deferred_work_deinit(void *work) +{ + struct dhd_deferred_wq *deferred_work = work; + + + if (!deferred_work) { + DHD_ERROR(("%s: deferred work has been freed alread \n", __FUNCTION__)); + return; + } + + /* cancel the deferred work handling */ + cancel_work_sync((struct work_struct *)deferred_work); + + /* + * free work event fifo. + * kfifo_free frees locally allocated fifo buffer + */ + if (deferred_work->prio_fifo) + dhd_kfifo_free(deferred_work->prio_fifo); + + if (deferred_work->work_fifo) + dhd_kfifo_free(deferred_work->work_fifo); + + kfree(deferred_work); + + /* deinit internal reference pointer */ + deferred_wq = NULL; +} + +/* + * Prepares event to be queued + * Schedules the event + */ +int +dhd_deferred_schedule_work(void *event_data, u8 event, event_handler_t event_handler, u8 priority) +{ + struct dhd_deferred_event_t deferred_event; + int status; + + if (!deferred_wq) { + DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); + ASSERT(0); + return DHD_WQ_STS_UNINITIALIZED; + } + + if (!event || (event >= DHD_MAX_WQ_EVENTS)) { + DHD_ERROR(("%s: Unknown event \n", __FUNCTION__)); + return DHD_WQ_STS_UNKNOWN_EVENT; + } + + /* + * default element size is 1, which can be changed + * using kfifo_esize(). Older kernel(FC11) doesn't support + * changing element size. For compatibility changing + * element size is not prefered + */ + ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); + ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); + + deferred_event.event = event; + deferred_event.event_data = event_data; + deferred_event.event_handler = event_handler; + + if (priority == DHD_WORK_PRIORITY_HIGH) { + status = kfifo_in_spinlocked(deferred_wq->prio_fifo, &deferred_event, + DEFRD_EVT_SIZE, &deferred_wq->work_lock); + } else { + status = kfifo_in_spinlocked(deferred_wq->work_fifo, &deferred_event, + DEFRD_EVT_SIZE, &deferred_wq->work_lock); + } + + if (!status) { + return DHD_WQ_STS_SCHED_FAILED; + } + schedule_work((struct work_struct *)deferred_wq); + return DHD_WQ_STS_OK; +} + +static int +dhd_get_scheduled_work(struct dhd_deferred_event_t *event) +{ + int status = 0; + + if (!deferred_wq) { + DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); + return DHD_WQ_STS_UNINITIALIZED; + } + + /* + * default element size is 1 byte, which can be changed + * using kfifo_esize(). Older kernel(FC11) doesn't support + * changing element size. For compatibility changing + * element size is not prefered + */ + ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); + ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); + + /* first read priorit event fifo */ + status = kfifo_out_spinlocked(deferred_wq->prio_fifo, event, + DEFRD_EVT_SIZE, &deferred_wq->work_lock); + + if (!status) { + /* priority fifo is empty. Now read low prio work fifo */ + status = kfifo_out_spinlocked(deferred_wq->work_fifo, event, + DEFRD_EVT_SIZE, &deferred_wq->work_lock); + } + + return status; +} + +/* + * Called when work is scheduled + */ +static void +dhd_deferred_work_handler(struct work_struct *work) +{ + struct dhd_deferred_wq *deferred_work = (struct dhd_deferred_wq *)work; + struct dhd_deferred_event_t work_event; + int status; + + if (!deferred_work) { + DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); + return; + } + + do { + status = dhd_get_scheduled_work(&work_event); + DHD_TRACE(("%s: event to handle %d \n", __FUNCTION__, status)); + if (!status) { + DHD_TRACE(("%s: No event to handle %d \n", __FUNCTION__, status)); + break; + } + + if (work_event.event > DHD_MAX_WQ_EVENTS) { + DHD_TRACE(("%s: Unknown event %d \n", __FUNCTION__, work_event.event)); + break; + } + + if (work_event.event_handler) { + work_event.event_handler(deferred_work->dhd_info, + work_event.event_data, work_event.event); + } else { + DHD_ERROR(("%s: event not defined %d\n", __FUNCTION__, work_event.event)); + } + } while (1); + return; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h new file mode 100644 index 000000000000..1066250b2824 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h @@ -0,0 +1,64 @@ +/* + * Broadcom Dongle Host Driver (DHD), Generic work queue framework + * Generic interface to handle dhd deferred work events + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_linux_wq.h 408802 2013-06-20 19:08:47Z $ + */ +#ifndef _dhd_linux_wq_h_ +#define _dhd_linux_wq_h_ +/* + * Work event definitions + */ +enum _wq_event { + DHD_WQ_WORK_IF_ADD = 1, + DHD_WQ_WORK_IF_DEL, + DHD_WQ_WORK_SET_MAC, + DHD_WQ_WORK_SET_MCAST_LIST, + DHD_WQ_WORK_IPV6_NDO, + DHD_WQ_WORK_HANG_MSG, + + DHD_MAX_WQ_EVENTS +}; + +/* + * Work event priority + */ +#define DHD_WORK_PRIORITY_LOW 0 +#define DHD_WORK_PRIORITY_HIGH 1 + +/* + * Error definitions + */ +#define DHD_WQ_STS_OK 0 +#define DHD_WQ_STS_FAILED -1 /* General failure */ +#define DHD_WQ_STS_UNINITIALIZED -2 +#define DHD_WQ_STS_SCHED_FAILED -3 +#define DHD_WQ_STS_UNKNOWN_EVENT -4 + +typedef void (*event_handler_t)(void *handle, void *event_data, u8 event); + +void *dhd_deferred_work_init(void *dhd); +void dhd_deferred_work_deinit(void *work); +int dhd_deferred_schedule_work(void *event_data, u8 event, + event_handler_t evt_handler, u8 priority); +#endif /* _dhd_linux_wq_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c new file mode 100644 index 000000000000..d9470d5d2b87 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c @@ -0,0 +1,4158 @@ +/* + * Broadcom Dongle Host Driver (DHD) + * Prefered Network Offload and Wi-Fi Location Service(WLS) code. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_pno.c 423669 2013-09-18 13:01:55Z yangj$ + */ + +#if defined(GSCAN_SUPPORT) && !defined(PNO_SUPPORT) +#error "GSCAN needs PNO to be enabled!" +#endif + +#ifdef PNO_SUPPORT +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef GSCAN_SUPPORT +#include +#endif /* GSCAN_SUPPORT */ + +#ifdef __BIG_ENDIAN +#include +#define htod32(i) (bcmswap32(i)) +#define htod16(i) (bcmswap16(i)) +#define dtoh32(i) (bcmswap32(i)) +#define dtoh16(i) (bcmswap16(i)) +#define htodchanspec(i) htod16(i) +#define dtohchanspec(i) dtoh16(i) +#else +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) +#endif /* IL_BIGENDINA */ + +#define NULL_CHECK(p, s, err) \ + do { \ + if (!(p)) { \ + printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ + err = BCME_ERROR; \ + return err; \ + } \ + } while (0) +#define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) +#define PNO_BESTNET_LEN 2048 +#define PNO_ON 1 +#define PNO_OFF 0 +#define CHANNEL_2G_MAX 14 +#define CHANNEL_5G_MAX 165 +#define MAX_NODE_CNT 5 +#define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE) +#define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \ + - (uint32)(timestamp2/1000))) +#define TIME_DIFF_MS(timestamp1, timestamp2) (abs((uint32)(timestamp1) \ + - (uint32)(timestamp2))) +#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ + (ts).tv_nsec / NSEC_PER_USEC) + +#define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") +#define TIME_MIN_DIFF 5 + +static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, + dhd_pno_status_info_t *pno_state); +#ifdef GSCAN_SUPPORT +static wl_pfn_gscan_ch_bucket_cfg_t * +dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state, + uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw); +#endif /* GSCAN_SUPPORT */ + +static inline bool +is_dfs(uint16 channel) +{ + if (channel >= 52 && channel <= 64) /* class 2 */ + return TRUE; + else if (channel >= 100 && channel <= 140) /* class 4 */ + return TRUE; + else + return FALSE; +} +int +dhd_pno_clean(dhd_pub_t *dhd) +{ + int pfn = 0; + int err; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + /* Disable PNO */ + err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn(error : %d)\n", + __FUNCTION__, err)); + goto exit; + } + _pno_state->pno_status = DHD_PNO_DISABLED; + err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfnclear(error : %d)\n", + __FUNCTION__, err)); + } +exit: + return err; +} + +bool +dhd_is_pno_supported(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + if (!dhd || !dhd->pno_state) { + DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__)); + return FALSE; + } + _pno_state = PNO_GET_PNOSTATE(dhd); + return WLS_SUPPORTED(_pno_state); +} + +bool +dhd_is_legacy_pno_enabled(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + + if (!dhd || !dhd->pno_state) { + DHD_ERROR(("NULL POINTER : %s\n", + __FUNCTION__)); + return FALSE; + } + _pno_state = PNO_GET_PNOSTATE(dhd); + return ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) != 0); +} + +#ifdef GSCAN_SUPPORT +static uint64 +convert_fw_rel_time_to_systime(uint32 fw_ts_ms) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + return ((uint64)(TIMESPEC_TO_US(ts)) - (uint64)(fw_ts_ms * 1000)); +} + +static void +dhd_pno_idx_to_ssid(struct dhd_pno_gscan_params *gscan_params, + dhd_epno_results_t *res, uint32 idx) +{ + dhd_epno_params_t *iter, *next; + + if (gscan_params->num_epno_ssid > 0) { + list_for_each_entry_safe(iter, next, + &gscan_params->epno_ssid_list, list) { + if (iter->index == idx) { + memcpy(res->ssid, iter->ssid, iter->ssid_len); + res->ssid_len = iter->ssid_len; + return; + } + } + } + /* If we are here then there was no match */ + res->ssid[0] = '\0'; + res->ssid_len = 0; + return; +} + +/* Cleanup all results */ +static void +dhd_gscan_clear_all_batch_results(dhd_pub_t *dhd) +{ + struct dhd_pno_gscan_params *gscan_params; + dhd_pno_status_info_t *_pno_state; + gscan_results_cache_t *iter; + + _pno_state = PNO_GET_PNOSTATE(dhd); + gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; + iter = gscan_params->gscan_batch_cache; + /* Mark everything as consumed */ + while (iter) { + iter->tot_consumed = iter->tot_count; + iter = iter->next; + } + dhd_gscan_batch_cache_cleanup(dhd); + return; +} + +static int +_dhd_pno_gscan_cfg(dhd_pub_t *dhd, wl_pfn_gscan_cfg_t *pfncfg_gscan_param, int size) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + + err = dhd_iovar(dhd, 0, "pfn_gscan_cfg", (char *)pfncfg_gscan_param, size, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfncfg_gscan_param\n", __FUNCTION__)); + goto exit; + } +exit: + return err; +} + +static bool +is_batch_retrieval_complete(struct dhd_pno_gscan_params *gscan_params) +{ + smp_rmb(); + return (gscan_params->get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE); +} +#endif /* GSCAN_SUPPORT */ + +static int +_dhd_pno_suspend(dhd_pub_t *dhd) +{ + int err; + int suspend = 1; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err)); + goto exit; + + } + _pno_state->pno_status = DHD_PNO_SUSPEND; +exit: + return err; +} +static int +_dhd_pno_enable(dhd_pub_t *dhd, int enable) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (enable & 0xfffe) { + DHD_ERROR(("%s invalid value\n", __FUNCTION__)); + err = BCME_BADARG; + goto exit; + } + if (!dhd_support_sta_mode(dhd)) { + DHD_ERROR(("PNO is not allowed for non-STA mode")); + err = BCME_BADOPTION; + goto exit; + } + if (enable) { + if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && + dhd_is_associated(dhd, NULL, NULL)) { + DHD_ERROR(("%s Legacy PNO mode cannot be enabled " + "in assoc mode , ignore it\n", __FUNCTION__)); + err = BCME_BADOPTION; + goto exit; + } + } + /* Enable/Disable PNO */ + err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_set - %d\n", __FUNCTION__, err)); + goto exit; + } + _pno_state->pno_status = (enable)? + DHD_PNO_ENABLED : DHD_PNO_DISABLED; + if (!enable) + _pno_state->pno_mode = DHD_PNO_NONE_MODE; + + DHD_PNO(("%s set pno as %s\n", + __FUNCTION__, enable ? "Enable" : "Disable")); +exit: + return err; +} + +static int +_dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode) +{ + int err = BCME_OK; + wl_pfn_param_t pfn_param; + dhd_pno_params_t *_params; + dhd_pno_status_info_t *_pno_state; + bool combined_scan = FALSE; + DHD_PNO(("%s enter\n", __FUNCTION__)); + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + memset(&pfn_param, 0, sizeof(pfn_param)); + + /* set pfn parameters */ + pfn_param.version = htod32(PFN_VERSION); + pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) | + (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT)); + if (mode == DHD_PNO_LEGACY_MODE) { + /* check and set extra pno params */ + if ((pno_params->params_legacy.pno_repeat != 0) || + (pno_params->params_legacy.pno_freq_expo_max != 0)) { + pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); + pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); + pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max); + } + /* set up pno scan fr */ + if (pno_params->params_legacy.scan_fr != 0) + pfn_param.scan_freq = htod32(pno_params->params_legacy.scan_fr); + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + DHD_PNO(("will enable combined scan with BATCHIG SCAN MODE\n")); + mode |= DHD_PNO_BATCH_MODE; + combined_scan = TRUE; + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + DHD_PNO(("will enable combined scan with HOTLIST SCAN MODE\n")); + mode |= DHD_PNO_HOTLIST_MODE; + combined_scan = TRUE; + } +#ifdef GSCAN_SUPPORT + else if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + DHD_PNO(("will enable combined scan with GSCAN SCAN MODE\n")); + mode |= DHD_PNO_GSCAN_MODE; + } +#endif /* GSCAN_SUPPORT */ + } + if (mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { + /* Scan frequency of 30 sec */ + pfn_param.scan_freq = htod32(30); + /* slow adapt scan is off by default */ + pfn_param.slow_freq = htod32(0); + /* RSSI margin of 30 dBm */ + pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); + /* Network timeout 60 sec */ + pfn_param.lost_network_timeout = htod32(60); + /* best n = 2 by default */ + pfn_param.bestn = DEFAULT_BESTN; + /* mscan m=0 by default, so not record best networks by default */ + pfn_param.mscan = DEFAULT_MSCAN; + /* default repeat = 10 */ + pfn_param.repeat = DEFAULT_REPEAT; + /* by default, maximum scan interval = 2^2 + * scan_freq when adaptive scan is turned on + */ + pfn_param.exp = DEFAULT_EXP; + if (mode == DHD_PNO_BATCH_MODE) { + /* In case of BATCH SCAN */ + if (pno_params->params_batch.bestn) + pfn_param.bestn = pno_params->params_batch.bestn; + if (pno_params->params_batch.scan_fr) + pfn_param.scan_freq = htod32(pno_params->params_batch.scan_fr); + if (pno_params->params_batch.mscan) + pfn_param.mscan = pno_params->params_batch.mscan; + /* enable broadcast scan */ + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + } else if (mode == DHD_PNO_HOTLIST_MODE) { + /* In case of HOTLIST SCAN */ + if (pno_params->params_hotlist.scan_fr) + pfn_param.scan_freq = htod32(pno_params->params_hotlist.scan_fr); + pfn_param.bestn = 0; + pfn_param.repeat = 0; + /* enable broadcast scan */ + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + } + if (combined_scan) { + /* Disable Adaptive Scan */ + pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT)); + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + pfn_param.repeat = 0; + pfn_param.exp = 0; + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + /* In case of Legacy PNO + BATCH SCAN */ + _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + if (_params->params_batch.bestn) + pfn_param.bestn = _params->params_batch.bestn; + if (_params->params_batch.scan_fr) + pfn_param.scan_freq = htod32(_params->params_batch.scan_fr); + if (_params->params_batch.mscan) + pfn_param.mscan = _params->params_batch.mscan; + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + /* In case of Legacy PNO + HOTLIST SCAN */ + _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + if (_params->params_hotlist.scan_fr) + pfn_param.scan_freq = htod32(_params->params_hotlist.scan_fr); + pfn_param.bestn = 0; + pfn_param.repeat = 0; + } + } + } +#ifdef GSCAN_SUPPORT + if (mode & DHD_PNO_GSCAN_MODE) { + uint32 lost_network_timeout; + + pfn_param.scan_freq = htod32(pno_params->params_gscan.scan_fr); + if (pno_params->params_gscan.mscan) { + pfn_param.bestn = pno_params->params_gscan.bestn; + pfn_param.mscan = pno_params->params_gscan.mscan; + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + } + /* RSSI margin of 30 dBm */ + pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); + pfn_param.repeat = 0; + pfn_param.exp = 0; + pfn_param.slow_freq = 0; + pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); + + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + dhd_pno_params_t *_params; + + _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + + pfn_param.scan_freq = htod32(gcd(pno_params->params_gscan.scan_fr, + _params->params_legacy.scan_fr)); + + if ((_params->params_legacy.pno_repeat != 0) || + (_params->params_legacy.pno_freq_expo_max != 0)) { + pfn_param.repeat = (uchar) (_params->params_legacy.pno_repeat); + pfn_param.exp = (uchar) (_params->params_legacy.pno_freq_expo_max); + } + } + + lost_network_timeout = (pno_params->params_gscan.max_ch_bucket_freq * + pfn_param.scan_freq * pno_params->params_gscan.lost_ap_window); + if (lost_network_timeout) { + pfn_param.lost_network_timeout = htod32(MIN(lost_network_timeout, + GSCAN_MIN_BSSID_TIMEOUT)); + } else { + pfn_param.lost_network_timeout = htod32(GSCAN_MIN_BSSID_TIMEOUT); + } + } else +#endif /* GSCAN_SUPPORT */ + { + + if (pfn_param.scan_freq < htod32(PNO_SCAN_MIN_FW_SEC) || + pfn_param.scan_freq > htod32(PNO_SCAN_MAX_FW_SEC)) { + DHD_ERROR(("%s pno freq(%d sec) is not valid \n", + __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); + err = BCME_BADARG; + goto exit; + } + + } + + err = dhd_set_rand_mac_oui(dhd); + /* Ignore if chip doesnt support the feature */ + if (err < 0 && err != BCME_UNSUPPORTED) { + DHD_ERROR(("%s : failed to set random mac for PNO scan, %d\n", __FUNCTION__, err)); + goto exit; + } + +#ifdef GSCAN_SUPPORT + if (mode == DHD_PNO_BATCH_MODE || + ((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) { +#else + if (mode == DHD_PNO_BATCH_MODE) { +#endif /* GSCAN_SUPPORT */ + int _tmp = pfn_param.bestn; + /* set bestn to calculate the max mscan which firmware supports */ + err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to set pfnmem\n", __FUNCTION__)); + goto exit; + } + /* get max mscan which the firmware supports */ + err = dhd_iovar(dhd, 0, "pfnmem", NULL, 0, (char *)&_tmp, sizeof(_tmp), FALSE); + if (err < 0) { + DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__)); + goto exit; + } + pfn_param.mscan = MIN(pfn_param.mscan, _tmp); + DHD_PNO((" returned mscan : %d, set bestn : %d mscan %d\n", _tmp, pfn_param.bestn, + pfn_param.mscan)); + } + err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err)); + goto exit; + } + /* need to return mscan if this is for batch scan instead of err */ + err = (mode == DHD_PNO_BATCH_MODE)? pfn_param.mscan : err; +exit: + return err; +} +static int +_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssids_list, int nssid) +{ + int err = BCME_OK; + int i = 0; + wl_pfn_t pfn_element; + + NULL_CHECK(dhd, "dhd is NULL", err); + if (nssid) { + NULL_CHECK(ssids_list, "ssid list is NULL", err); + } + memset(&pfn_element, 0, sizeof(pfn_element)); + { + int j; + for (j = 0; j < nssid; j++) { + DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n", + ssids_list[j].SSID, ssids_list[j].SSID_len, ssids_list[j].hidden, + ssids_list[j].flags, ssids_list[i].rssi_thresh)); + } + } + /* Check for broadcast ssid */ + for (i = 0; i < nssid; i++) { + if (!ssids_list[i].SSID_len) { + DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", i)); + err = BCME_ERROR; + goto exit; + } + } + /* set all pfn ssid */ + for (i = 0; i < nssid; i++) { + pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); + pfn_element.auth = (DOT11_OPEN_SYSTEM); + pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); + pfn_element.wsec = htod32(0); + pfn_element.infra = htod32(1); + if (ssids_list[i].hidden) { + pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); + } else { + pfn_element.flags = 0; + } + pfn_element.flags |= htod32(ssids_list[i].flags); + /* If a single RSSI threshold is defined, use that */ +#ifdef PNO_MIN_RSSI_TRIGGER + pfn_element.flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT); +#else + pfn_element.flags |= ((ssids_list[i].rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT); +#endif /* PNO_MIN_RSSI_TRIGGER */ + memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, + ssids_list[i].SSID_len); + pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; + err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, sizeof(wl_pfn_t), + NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); + goto exit; + } + } +exit: + return err; +} +/* qsort compare function */ +static int +_dhd_pno_cmpfunc(const void *a, const void *b) +{ + return (*(uint16*)a - *(uint16*)b); +} +static int +_dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan, + uint16 *chan_list1, int nchan1, uint16 *chan_list2, int nchan2) +{ + int err = BCME_OK; + int i = 0, j = 0, k = 0; + uint16 tmp; + NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); + NULL_CHECK(nchan, "nchan is NULL", err); + NULL_CHECK(chan_list1, "chan_list1 is NULL", err); + NULL_CHECK(chan_list2, "chan_list2 is NULL", err); + /* chan_list1 and chan_list2 should be sorted at first */ + while (i < nchan1 && j < nchan2) { + tmp = chan_list1[i] < chan_list2[j]? + chan_list1[i++] : chan_list2[j++]; + for (; i < nchan1 && chan_list1[i] == tmp; i++); + for (; j < nchan2 && chan_list2[j] == tmp; j++); + d_chan_list[k++] = tmp; + } + + while (i < nchan1) { + tmp = chan_list1[i++]; + for (; i < nchan1 && chan_list1[i] == tmp; i++); + d_chan_list[k++] = tmp; + } + + while (j < nchan2) { + tmp = chan_list2[j++]; + for (; j < nchan2 && chan_list2[j] == tmp; j++); + d_chan_list[k++] = tmp; + + } + *nchan = k; + return err; +} +static int +_dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list, + int *nchan, uint8 band, bool skip_dfs) +{ + int err = BCME_OK; + int i, j; + uint32 chan_buf[WL_NUMCHANNELS + 1]; + wl_uint32_list_t *list; + NULL_CHECK(dhd, "dhd is NULL", err); + if (*nchan) { + NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); + } + memset(chan_buf, 0, sizeof(chan_buf)); + list = (wl_uint32_list_t *) (void *)chan_buf; + list->count = htod32(WL_NUMCHANNELS); + err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); + if (err < 0) { + DHD_ERROR(("failed to get channel list (err: %d)\n", err)); + goto exit; + } + for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) { + if (band == WLC_BAND_2G) { + if (dtoh32(list->element[i]) > CHANNEL_2G_MAX) + continue; + } else if (band == WLC_BAND_5G) { + if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX) + continue; + if (skip_dfs && is_dfs(dtoh32(list->element[i]))) + continue; + + } else if (band == WLC_BAND_AUTO) { + if (skip_dfs || !is_dfs(dtoh32(list->element[i]))) + continue; + + } else { /* All channels */ + if (skip_dfs && is_dfs(dtoh32(list->element[i]))) + continue; + } + if (dtoh32(list->element[i]) <= CHANNEL_5G_MAX) { + d_chan_list[j++] = (uint16) dtoh32(list->element[i]); + } else { + err = BCME_BADCHAN; + goto exit; + } + } + *nchan = j; +exit: + return err; +} +static int +_dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batch, + char *buf, int nbufsize) +{ + int err = BCME_OK; + int bytes_written = 0, nreadsize = 0; + int t_delta = 0; + int nleftsize = nbufsize; + uint8 cnt = 0; + char *bp = buf; + char eabuf[ETHER_ADDR_STR_LEN]; +#ifdef PNO_DEBUG + char *_base_bp; + char msg[150]; +#endif + dhd_pno_bestnet_entry_t *iter, *next; + dhd_pno_scan_results_t *siter, *snext; + dhd_pno_best_header_t *phead, *pprev; + NULL_CHECK(params_batch, "params_batch is NULL", err); + if (nbufsize > 0) + NULL_CHECK(buf, "buf is NULL", err); + /* initialize the buffer */ + memset(buf, 0, nbufsize); + DHD_PNO(("%s enter \n", __FUNCTION__)); + /* # of scans */ + if (!params_batch->get_batch.batch_started) { + bp += nreadsize = sprintf(bp, "scancount=%d\n", + params_batch->get_batch.expired_tot_scan_cnt); + nleftsize -= nreadsize; + params_batch->get_batch.batch_started = TRUE; + } + DHD_PNO(("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt)); + /* preestimate scan count until which scan result this report is going to end */ + list_for_each_entry_safe(siter, snext, + ¶ms_batch->get_batch.expired_scan_results_list, list) { + phead = siter->bestnetheader; + while (phead != NULL) { + /* if left_size is less than bestheader total size , stop this */ + if (nleftsize <= + (phead->tot_size + phead->tot_cnt * ENTRY_OVERHEAD)) + goto exit; + /* increase scan count */ + cnt++; + /* # best of each scan */ + DHD_PNO(("\n\n", cnt - 1, phead->tot_cnt)); + /* attribute of the scan */ + if (phead->reason & PNO_STATUS_ABORT_MASK) { + bp += nreadsize = sprintf(bp, "trunc\n"); + nleftsize -= nreadsize; + } + list_for_each_entry_safe(iter, next, + &phead->entry_list, list) { + t_delta = jiffies_to_msecs(jiffies - iter->recorded_time); +#ifdef PNO_DEBUG + _base_bp = bp; + memset(msg, 0, sizeof(msg)); +#endif + /* BSSID info */ + bp += nreadsize = sprintf(bp, "bssid=%s\n", + bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf)); + nleftsize -= nreadsize; + /* SSID */ + bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID); + nleftsize -= nreadsize; + /* channel */ + bp += nreadsize = sprintf(bp, "freq=%d\n", + wf_channel2mhz(iter->channel, + iter->channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + nleftsize -= nreadsize; + /* RSSI */ + bp += nreadsize = sprintf(bp, "level=%d\n", iter->RSSI); + nleftsize -= nreadsize; + /* add the time consumed in Driver to the timestamp of firmware */ + iter->timestamp += t_delta; + bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp); + nleftsize -= nreadsize; + /* RTT0 */ + bp += nreadsize = sprintf(bp, "dist=%d\n", + (iter->rtt0 == 0)? -1 : iter->rtt0); + nleftsize -= nreadsize; + /* RTT1 */ + bp += nreadsize = sprintf(bp, "distSd=%d\n", + (iter->rtt0 == 0)? -1 : iter->rtt1); + nleftsize -= nreadsize; + bp += nreadsize = sprintf(bp, "%s", AP_END_MARKER); + nleftsize -= nreadsize; + list_del(&iter->list); + MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); +#ifdef PNO_DEBUG + memcpy(msg, _base_bp, bp - _base_bp); + DHD_PNO(("Entry : \n%s", msg)); +#endif + } + bp += nreadsize = sprintf(bp, "%s", SCAN_END_MARKER); + DHD_PNO(("%s", SCAN_END_MARKER)); + nleftsize -= nreadsize; + pprev = phead; + /* reset the header */ + siter->bestnetheader = phead = phead->next; + MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); + + siter->cnt_header--; + } + if (phead == NULL) { + /* we store all entry in this scan , so it is ok to delete */ + list_del(&siter->list); + MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); + } + } +exit: + if (cnt < params_batch->get_batch.expired_tot_scan_cnt) { + DHD_ERROR(("Buffer size is small to save all batch entry," + " cnt : %d (remained_scan_cnt): %d\n", + cnt, params_batch->get_batch.expired_tot_scan_cnt - cnt)); + } + params_batch->get_batch.expired_tot_scan_cnt -= cnt; + /* set FALSE only if the link list is empty after returning the data */ + if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) { + params_batch->get_batch.batch_started = FALSE; + bp += sprintf(bp, "%s", RESULTS_END_MARKER); + DHD_PNO(("%s", RESULTS_END_MARKER)); + DHD_PNO(("%s : Getting the batching data is complete\n", __FUNCTION__)); + } + /* return used memory in buffer */ + bytes_written = (int32)(bp - buf); + return bytes_written; +} +static int +_dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last) +{ + int err = BCME_OK; + int removed_scan_cnt = 0; + dhd_pno_scan_results_t *siter, *snext; + dhd_pno_best_header_t *phead, *pprev; + dhd_pno_bestnet_entry_t *iter, *next; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(head, "head is NULL", err); + NULL_CHECK(head->next, "head->next is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + list_for_each_entry_safe(siter, snext, + head, list) { + if (only_last) { + /* in case that we need to delete only last one */ + if (!list_is_last(&siter->list, head)) { + /* skip if the one is not last */ + continue; + } + } + /* delete all data belong if the one is last */ + phead = siter->bestnetheader; + while (phead != NULL) { + removed_scan_cnt++; + list_for_each_entry_safe(iter, next, + &phead->entry_list, list) { + list_del(&iter->list); + MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); + } + pprev = phead; + phead = phead->next; + MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); + } + if (phead == NULL) { + /* it is ok to delete top node */ + list_del(&siter->list); + MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); + } + } + return removed_scan_cnt; +} + +static int +_dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) +{ + int err = BCME_OK; + int i = 0; + wl_pfn_cfg_t pfncfg_param; + NULL_CHECK(dhd, "dhd is NULL", err); + if (nchan) { + NULL_CHECK(channel_list, "nchan is NULL", err); + } + if (nchan > WL_NUMCHANNELS) { + return BCME_RANGE; + } + DHD_PNO(("%s enter : nchan : %d\n", __FUNCTION__, nchan)); + memset(&pfncfg_param, 0, sizeof(wl_pfn_cfg_t)); + /* Setup default values */ + pfncfg_param.reporttype = htod32(WL_PFN_REPORT_ALLNET); + pfncfg_param.channel_num = htod32(0); + + for (i = 0; i < nchan; i++) + pfncfg_param.channel_list[i] = channel_list[i]; + + pfncfg_param.channel_num = htod32(nchan); + err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), NULL, 0, + TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); + goto exit; + } +exit: + return err; +} +static int +_dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL\n", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + mutex_lock(&_pno_state->pno_mutex); + switch (mode) { + case DHD_PNO_LEGACY_MODE: { + struct dhd_pno_ssid *iter, *next; + if (params->params_legacy.nssid > 0) { + list_for_each_entry_safe(iter, next, + ¶ms->params_legacy.ssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + params->params_legacy.nssid = 0; + params->params_legacy.scan_fr = 0; + params->params_legacy.pno_freq_expo_max = 0; + params->params_legacy.pno_repeat = 0; + params->params_legacy.nchan = 0; + memset(params->params_legacy.chan_list, 0, + sizeof(params->params_legacy.chan_list)); + break; + } + case DHD_PNO_BATCH_MODE: { + params->params_batch.scan_fr = 0; + params->params_batch.mscan = 0; + params->params_batch.nchan = 0; + params->params_batch.rtt = 0; + params->params_batch.bestn = 0; + params->params_batch.nchan = 0; + params->params_batch.band = WLC_BAND_AUTO; + memset(params->params_batch.chan_list, 0, + sizeof(params->params_batch.chan_list)); + params->params_batch.get_batch.batch_started = FALSE; + params->params_batch.get_batch.buf = NULL; + params->params_batch.get_batch.bufsize = 0; + params->params_batch.get_batch.reason = 0; + _dhd_pno_clear_all_batch_results(dhd, + ¶ms->params_batch.get_batch.scan_results_list, FALSE); + _dhd_pno_clear_all_batch_results(dhd, + ¶ms->params_batch.get_batch.expired_scan_results_list, FALSE); + params->params_batch.get_batch.tot_scan_cnt = 0; + params->params_batch.get_batch.expired_tot_scan_cnt = 0; + params->params_batch.get_batch.top_node_cnt = 0; + INIT_LIST_HEAD(¶ms->params_batch.get_batch.scan_results_list); + INIT_LIST_HEAD(¶ms->params_batch.get_batch.expired_scan_results_list); + break; + } + case DHD_PNO_HOTLIST_MODE: { + struct dhd_pno_bssid *iter, *next; + if (params->params_hotlist.nbssid > 0) { + list_for_each_entry_safe(iter, next, + ¶ms->params_hotlist.bssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + params->params_hotlist.scan_fr = 0; + params->params_hotlist.nbssid = 0; + params->params_hotlist.nchan = 0; + params->params_batch.band = WLC_BAND_AUTO; + memset(params->params_hotlist.chan_list, 0, + sizeof(params->params_hotlist.chan_list)); + break; + } + default: + DHD_ERROR(("%s : unknown mode : %d\n", __FUNCTION__, mode)); + break; + } + mutex_unlock(&_pno_state->pno_mutex); + return err; +} +static int +_dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + if (nbssid) { + NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); + } + err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)p_pfn_bssid, + sizeof(wl_pfn_bssid_t) * nbssid, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); + goto exit; + } +exit: + return err; +} + +#ifdef GSCAN_SUPPORT + static int +_dhd_pno_add_significant_bssid(dhd_pub_t *dhd, + wl_pfn_significant_bssid_t *p_pfn_significant_bssid, int nbssid) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + + if (!nbssid) { + err = BCME_ERROR; + goto exit; + } + + NULL_CHECK(p_pfn_significant_bssid, "bssid list is NULL", err); + + err = dhd_iovar(dhd, 0, "pfn_add_swc_bssid", (char *)p_pfn_significant_bssid, + sizeof(wl_pfn_significant_bssid_t) * nbssid, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_significant_bssid %d\n", __FUNCTION__, err)); + goto exit; + } +exit: + return err; +} +#endif /* GSCAN_SUPPORT */ + +int +dhd_pno_stop_for_ssid(dhd_pub_t *dhd) +{ + int err = BCME_OK; + uint32 mode = 0; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + wl_pfn_bssid_t *p_pfn_bssid = NULL; + NULL_CHECK(dhd, "dev is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { + DHD_ERROR(("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__)); + goto exit; + } + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + struct dhd_pno_gscan_params *gscan_params; + + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + gscan_params = &_params->params_gscan; + if (gscan_params->mscan) { + /* retrieve the batching data from firmware into host */ + err = dhd_wait_batch_results_complete(dhd); + if (err != BCME_OK) + goto exit; + } + /* save current pno_mode before calling dhd_pno_clean */ + mutex_lock(&_pno_state->pno_mutex); + mode = _pno_state->pno_mode; + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + mutex_unlock(&_pno_state->pno_mutex); + goto exit; + } + /* restore previous pno_mode */ + _pno_state->pno_mode = mode; + mutex_unlock(&_pno_state->pno_mutex); + /* Restart gscan */ + err = dhd_pno_initiate_gscan_request(dhd, 1, 0); + + goto exit; + } +#endif /* GSCAN_SUPPORT */ + + + /* restart Batch mode if the batch mode is on */ + if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { + /* retrieve the batching data from firmware into host */ + dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); + /* save current pno_mode before calling dhd_pno_clean */ + mode = _pno_state->pno_mode; + dhd_pno_clean(dhd); + /* restore previous pno_mode */ + _pno_state->pno_mode = mode; + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + /* restart BATCH SCAN */ + err = dhd_pno_set_for_batch(dhd, &_params->params_batch); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + /* restart HOTLIST SCAN */ + struct dhd_pno_bssid *iter, *next; + _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * + _params->params_hotlist.nbssid, GFP_KERNEL); + if (p_pfn_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" + " (count: %d)", + __FUNCTION__, _params->params_hotlist.nbssid)); + err = BCME_ERROR; + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + goto exit; + } + /* convert dhd_pno_bssid to wl_pfn_bssid */ + list_for_each_entry_safe(iter, next, + &_params->params_hotlist.bssid_list, list) { + memcpy(&p_pfn_bssid->macaddr, + &iter->macaddr, ETHER_ADDR_LEN); + p_pfn_bssid->flags = iter->flags; + p_pfn_bssid++; + } + err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + } else { + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } +exit: + if (p_pfn_bssid) + kfree(p_pfn_bssid); + return err; +} + +int +dhd_pno_enable(dhd_pub_t *dhd, int enable) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + return (_dhd_pno_enable(dhd, enable)); +} + +static +wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, + dhd_pno_status_info_t *pno_state) +{ + int err = BCME_OK; + int i; + struct dhd_pno_ssid *iter, *next; + dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + wlc_ssid_ext_t *p_ssid_list; + + p_ssid_list = kzalloc(sizeof(wlc_ssid_ext_t) * + _params1->params_legacy.nssid, GFP_KERNEL); + if (p_ssid_list == NULL) { + DHD_ERROR(("%s : failed to allocate wlc_ssid_ext_t array (count: %d)", + __FUNCTION__, _params1->params_legacy.nssid)); + err = BCME_ERROR; + pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + goto exit; + } + i = 0; + /* convert dhd_pno_ssid to wlc_ssid_ext_t */ + list_for_each_entry_safe(iter, next, &_params1->params_legacy.ssid_list, list) { + p_ssid_list[i].SSID_len = iter->SSID_len; + p_ssid_list[i].hidden = iter->hidden; + p_ssid_list[i].rssi_thresh = iter->rssi_thresh; + memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); + i++; + } +exit: + return p_ssid_list; +} + +#ifdef GSCAN_SUPPORT +static int dhd_epno_set_ssid(dhd_pub_t *dhd, + dhd_pno_status_info_t *pno_state) +{ + int err = BCME_OK; + dhd_epno_params_t *iter, *next; + dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + struct dhd_pno_gscan_params *gscan_params; + wlc_ssid_ext_t ssid_elem; + wl_pfn_ext_list_t *p_ssid_ext_elem = NULL; + uint32 mem_needed = 0, i = 0; + uint16 num_visible_epno_ssid; + uint8 flags; + + gscan_params = &_params1->params_gscan; + num_visible_epno_ssid = gscan_params->num_visible_epno_ssid; + + if (num_visible_epno_ssid) { + mem_needed = sizeof(wl_pfn_ext_list_t) + (sizeof(wl_pfn_ext_t) * + (num_visible_epno_ssid - 1)); + p_ssid_ext_elem = kzalloc(mem_needed, GFP_KERNEL); + if (p_ssid_ext_elem == NULL) { + DHD_ERROR(("%s : failed to allocate memory %u\n", + __FUNCTION__, mem_needed)); + err = BCME_NOMEM; + goto exit; + } + p_ssid_ext_elem->version = PFN_SSID_EXT_VERSION; + p_ssid_ext_elem->count = num_visible_epno_ssid; + } + + DHD_PNO(("Total ssids %d, visible SSIDs %d\n", gscan_params->num_epno_ssid, + num_visible_epno_ssid)); + + /* convert dhd_pno_ssid to wlc_ssid_ext_t */ + list_for_each_entry_safe(iter, next, &gscan_params->epno_ssid_list, list) { + if (iter->flags & DHD_PNO_USE_SSID) { + memset(&ssid_elem, 0, sizeof(ssid_elem)); + ssid_elem.SSID_len = iter->ssid_len; + ssid_elem.hidden = TRUE; + flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? + WL_PFN_SSID_A_BAND_TRIG: 0; + flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? + WL_PFN_SSID_BG_BAND_TRIG: 0; + ssid_elem.flags = flags; + ssid_elem.rssi_thresh = iter->rssi_thresh; + memcpy(ssid_elem.SSID, iter->ssid, iter->ssid_len); + if ((err = _dhd_pno_add_ssid(dhd, &ssid_elem, 1)) < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + } else if (i < num_visible_epno_ssid) { + p_ssid_ext_elem->pfn_ext[i].rssi_thresh = iter->rssi_thresh; + switch (iter->auth) { + case DHD_PNO_AUTH_CODE_OPEN: + p_ssid_ext_elem->pfn_ext[i].wpa_auth = WPA_AUTH_DISABLED; + break; + case DHD_PNO_AUTH_CODE_PSK: + p_ssid_ext_elem->pfn_ext[i].wpa_auth = + (WPA2_AUTH_PSK | WPA_AUTH_PSK); + break; + case DHD_PNO_AUTH_CODE_EAPOL: + p_ssid_ext_elem->pfn_ext[i].wpa_auth = + (uint16)WPA_AUTH_PFN_ANY; + break; + default: + p_ssid_ext_elem->pfn_ext[i].wpa_auth = + (uint16)WPA_AUTH_PFN_ANY; + break; + } + memcpy(p_ssid_ext_elem->pfn_ext[i].ssid, iter->ssid, iter->ssid_len); + p_ssid_ext_elem->pfn_ext[i].ssid_len = iter->ssid_len; + iter->index = gscan_params->ssid_ext_last_used_index++; + flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? + WL_PFN_SSID_A_BAND_TRIG: 0; + flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? + WL_PFN_SSID_BG_BAND_TRIG: 0; + p_ssid_ext_elem->pfn_ext[i].flags = flags; + DHD_PNO(("SSID %s idx %d rssi thresh %d flags %x\n", iter->ssid, + iter->index, iter->rssi_thresh, flags)); + i++; + } + } + if (num_visible_epno_ssid) { + err = dhd_iovar(dhd, 0, "pfn_add_ssid_ext", (char *)p_ssid_ext_elem, + mem_needed, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_add_pno_ext_ssid %d\n", __FUNCTION__, + err)); + } + } +exit: + kfree(p_ssid_ext_elem); + return err; +} +#endif /* GSCAN_SUPPORT */ + +static int +dhd_pno_add_to_ssid_list(dhd_pno_params_t *params, wlc_ssid_ext_t *ssid_list, + int nssid) +{ + int ret = 0; + int i; + struct dhd_pno_ssid *_pno_ssid; + + for (i = 0; i < nssid; i++) { + if (ssid_list[i].SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s : Invalid SSID length %d\n", + __FUNCTION__, ssid_list[i].SSID_len)); + ret = BCME_ERROR; + goto exit; + } + _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); + if (_pno_ssid == NULL) { + DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n", + __FUNCTION__)); + ret = BCME_ERROR; + goto exit; + } + _pno_ssid->SSID_len = ssid_list[i].SSID_len; + _pno_ssid->hidden = ssid_list[i].hidden; + _pno_ssid->rssi_thresh = ssid_list[i].rssi_thresh; + memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); + list_add_tail(&_pno_ssid->list, ¶ms->params_legacy.ssid_list); + params->params_legacy.nssid++; + } + +exit: + return ret; +} + +int +dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) +{ + dhd_pno_params_t *_params; + dhd_pno_params_t *_params2; + dhd_pno_status_info_t *_pno_state; + uint16 _chan_list[WL_NUMCHANNELS]; + int32 tot_nchan = 0; + int err = BCME_OK; + int i; + int mode = 0; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit_no_clear; + } + DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d," + "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, + scan_fr, pno_repeat, pno_freq_expo_max, nchan)); + + _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + /* If GSCAN is also ON will handle this down below */ +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE && + !(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { +#else + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { +#endif /* GSCAN_SUPPORT */ + DHD_ERROR(("%s : Legacy PNO mode was already started, " + "will disable previous one to start new one\n", __FUNCTION__)); + err = dhd_pno_stop_for_ssid(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to stop legacy PNO (err %d)\n", + __FUNCTION__, err)); + goto exit_no_clear; + } + } + _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", + __FUNCTION__, err)); + goto exit_no_clear; + } + memset(_chan_list, 0, sizeof(_chan_list)); + tot_nchan = MIN(nchan, WL_NUMCHANNELS); + if (tot_nchan > 0 && channel_list) { + for (i = 0; i < tot_nchan; i++) + _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i]; + } +#ifdef GSCAN_SUPPORT + else { + tot_nchan = WL_NUMCHANNELS; + err = _dhd_pno_get_channels(dhd, _chan_list, &tot_nchan, + (WLC_BAND_2G | WLC_BAND_5G), FALSE); + if (err < 0) { + tot_nchan = 0; + DHD_PNO(("Could not get channel list for PNO SSID\n")); + } else { + for (i = 0; i < tot_nchan; i++) + _params->params_legacy.chan_list[i] = _chan_list[i]; + } + } +#endif /* GSCAN_SUPPORT */ + + if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { + DHD_PNO(("BATCH SCAN is on progress in firmware\n")); + /* retrieve the batching data from firmware into host */ + dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = _dhd_pno_enable(dhd, PNO_OFF); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + goto exit_no_clear; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + /* use superset of channel list between two mode */ + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + if (_params2->params_batch.nchan > 0 && tot_nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_batch.chan_list[0], + _params2->params_batch.nchan, + &channel_list[0], tot_nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + " between legacy and batch\n", + __FUNCTION__)); + goto exit_no_clear; + } + } else { + DHD_PNO(("superset channel will use" + " all channels in firmware\n")); + } + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + if (_params2->params_hotlist.nchan > 0 && tot_nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_hotlist.chan_list[0], + _params2->params_hotlist.nchan, + &channel_list[0], tot_nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + " between legacy and hotlist\n", + __FUNCTION__)); + goto exit_no_clear; + } + } + } + } + _params->params_legacy.scan_fr = scan_fr; + _params->params_legacy.pno_repeat = pno_repeat; + _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max; + _params->params_legacy.nchan = tot_nchan; + _params->params_legacy.nssid = 0; + INIT_LIST_HEAD(&_params->params_legacy.ssid_list); + +#ifdef GSCAN_SUPPORT + /* dhd_pno_initiate_gscan_request will handle simultaneous Legacy PNO and GSCAN */ + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { + err = BCME_ERROR; + goto exit; + } + DHD_PNO(("GSCAN mode is ON! Will restart GSCAN+Legacy PNO\n")); + err = dhd_pno_initiate_gscan_request(dhd, 1, 0); + goto exit; + } +#endif /* GSCAN_SUPPORT */ + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_LEGACY_MODE)) < 0) { + DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); + goto exit; + } + if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { + DHD_ERROR(("failed to add ssid list(err %d), %d in firmware\n", err, nssid)); + goto exit; + } + if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { + err = BCME_ERROR; + goto exit; + } + if (tot_nchan > 0) { + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + } + if (_pno_state->pno_status == DHD_PNO_DISABLED) { + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) + DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); + } +exit: + if (err < 0) { + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + } +exit_no_clear: + /* clear mode in case of error */ + if (err < 0) { + int ret = dhd_pno_clean(dhd); + + if (ret < 0) { + DHD_ERROR(("%s : dhd_pno_clean failure (err: %d)\n", + __FUNCTION__, ret)); + } else { + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + } + } + return err; +} +int +dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) +{ + int err = BCME_OK; + uint16 _chan_list[WL_NUMCHANNELS]; + int rem_nchan = 0, tot_nchan = 0; + int mode = 0, mscan = 0; + dhd_pno_params_t *_params; + dhd_pno_params_t *_params2; + dhd_pno_status_info_t *_pno_state; + wlc_ssid_ext_t *p_ssid_list = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + NULL_CHECK(batch_params, "batch_params is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + _pno_state->pno_mode |= DHD_PNO_BATCH_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", + __FUNCTION__)); + goto exit; + } + } else { + /* batch mode is already started */ + return -EBUSY; + } + _params->params_batch.scan_fr = batch_params->scan_fr; + _params->params_batch.bestn = batch_params->bestn; + _params->params_batch.mscan = (batch_params->mscan)? + batch_params->mscan : DEFAULT_BATCH_MSCAN; + _params->params_batch.nchan = batch_params->nchan; + memcpy(_params->params_batch.chan_list, batch_params->chan_list, + sizeof(_params->params_batch.chan_list)); + + memset(_chan_list, 0, sizeof(_chan_list)); + + rem_nchan = ARRAYSIZE(batch_params->chan_list) - batch_params->nchan; + if (batch_params->band == WLC_BAND_2G || batch_params->band == WLC_BAND_5G) { + /* get a valid channel list based on band B or A */ + err = _dhd_pno_get_channels(dhd, + &_params->params_batch.chan_list[batch_params->nchan], + &rem_nchan, batch_params->band, FALSE); + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", + __FUNCTION__, batch_params->band)); + goto exit; + } + /* now we need to update nchan because rem_chan has valid channel count */ + _params->params_batch.nchan += rem_nchan; + /* need to sort channel list */ + sort(_params->params_batch.chan_list, _params->params_batch.nchan, + sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL); + } +#ifdef PNO_DEBUG +{ + DHD_PNO(("Channel list : ")); + for (i = 0; i < _params->params_batch.nchan; i++) { + DHD_PNO(("%d ", _params->params_batch.chan_list[i])); + } + DHD_PNO(("\n")); +} +#endif + if (_params->params_batch.nchan) { + /* copy the channel list into local array */ + memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list)); + tot_nchan = _params->params_batch.nchan; + } + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + DHD_PNO(("PNO SSID is on progress in firmware\n")); + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = _dhd_pno_enable(dhd, PNO_OFF); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + goto exit; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + /* Use the superset for channelist between two mode */ + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + if (_params2->params_legacy.nchan > 0 && _params->params_batch.nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_legacy.chan_list[0], + _params2->params_legacy.nchan, + &_params->params_batch.chan_list[0], _params->params_batch.nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + " between legacy and batch\n", + __FUNCTION__)); + goto exit; + } + } else { + DHD_PNO(("superset channel will use all channels in firmware\n")); + } + p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!p_ssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list, + _params2->params_legacy.nssid)) < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + } + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_BATCH_MODE)) < 0) { + DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } else { + /* we need to return mscan */ + mscan = err; + } + if (tot_nchan > 0) { + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + } + if (_pno_state->pno_status == DHD_PNO_DISABLED) { + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) + DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); + } +exit: + /* clear mode in case of error */ + if (err < 0) + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + else { + /* return #max scan firmware can do */ + err = mscan; + } + if (p_ssid_list) + kfree(p_ssid_list); + return err; +} + +#ifdef GSCAN_SUPPORT +static void dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params, + dhd_pno_status_info_t *_pno_state, uint8 flags) +{ + DHD_PNO(("%s enter\n", __FUNCTION__)); + + + if (flags & GSCAN_FLUSH_SCAN_CFG) { + _params->params_gscan.bestn = 0; + _params->params_gscan.mscan = 0; + _params->params_gscan.buffer_threshold = GSCAN_BATCH_NO_THR_SET; + _params->params_gscan.scan_fr = 0; + _params->params_gscan.send_all_results_flag = 0; + memset(_params->params_gscan.channel_bucket, 0, + _params->params_gscan.nchannel_buckets * + sizeof(struct dhd_pno_gscan_channel_bucket)); + _params->params_gscan.nchannel_buckets = 0; + DHD_PNO(("Flush Scan config\n")); + } + if (flags & GSCAN_FLUSH_HOTLIST_CFG) { + struct dhd_pno_bssid *iter, *next; + if (_params->params_gscan.nbssid_hotlist > 0) { + list_for_each_entry_safe(iter, next, + &_params->params_gscan.hotlist_bssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + _params->params_gscan.nbssid_hotlist = 0; + DHD_PNO(("Flush Hotlist Config\n")); + } + if (flags & GSCAN_FLUSH_SIGNIFICANT_CFG) { + dhd_pno_significant_bssid_t *iter, *next; + + if (_params->params_gscan.nbssid_significant_change > 0) { + list_for_each_entry_safe(iter, next, + &_params->params_gscan.significant_bssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + _params->params_gscan.nbssid_significant_change = 0; + DHD_PNO(("Flush Significant Change Config\n")); + } + if (flags & GSCAN_FLUSH_EPNO_CFG) { + dhd_epno_params_t *iter, *next; + + if (_params->params_gscan.num_epno_ssid > 0) { + list_for_each_entry_safe(iter, next, + &_params->params_gscan.epno_ssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + _params->params_gscan.num_epno_ssid = 0; + _params->params_gscan.num_visible_epno_ssid = 0; + _params->params_gscan.ssid_ext_last_used_index = 0; + DHD_PNO(("Flushed ePNO Config\n")); + } + + return; +} + +int +dhd_pno_lock_batch_results(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + int err = BCME_OK; + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + mutex_lock(&_pno_state->pno_mutex); + return err; +} + +void +dhd_pno_unlock_batch_results(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + _pno_state = PNO_GET_PNOSTATE(dhd); + mutex_unlock(&_pno_state->pno_mutex); + return; +} + +int +dhd_wait_batch_results_complete(dhd_pub_t *dhd) +{ + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + int err = BCME_OK; + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + /* Has the workqueue finished its job already?? */ + if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_IN_PROGRESS) { + DHD_PNO(("%s: Waiting to complete retrieval..\n", __FUNCTION__)); + wait_event_interruptible_timeout(_pno_state->batch_get_wait, + is_batch_retrieval_complete(&_params->params_gscan), + msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); + } else { /* GSCAN_BATCH_RETRIEVAL_COMPLETE */ + gscan_results_cache_t *iter; + uint16 num_results = 0; + + mutex_lock(&_pno_state->pno_mutex); + iter = _params->params_gscan.gscan_batch_cache; + while (iter) { + num_results += iter->tot_count - iter->tot_consumed; + iter = iter->next; + } + mutex_unlock(&_pno_state->pno_mutex); + + /* All results consumed/No results cached?? + * Get fresh results from FW + */ + if ((_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) && !num_results) { + DHD_PNO(("%s: No results cached, getting from FW..\n", __FUNCTION__)); + err = dhd_retreive_batch_scan_results(dhd); + if (err == BCME_OK) { + wait_event_interruptible_timeout(_pno_state->batch_get_wait, + is_batch_retrieval_complete(&_params->params_gscan), + msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); + } + } + } + DHD_PNO(("%s: Wait complete\n", __FUNCTION__)); + return err; +} + +static void * +dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len) +{ + gscan_results_cache_t *iter, *results; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + uint16 num_scan_ids = 0, num_results = 0; + + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + iter = results = _params->params_gscan.gscan_batch_cache; + while (iter) { + num_results += iter->tot_count - iter->tot_consumed; + num_scan_ids++; + iter = iter->next; + } + + *len = ((num_results << 16) | (num_scan_ids)); + return results; +} + +void * +dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, + void *info, uint32 *len) +{ + void *ret = NULL; + dhd_pno_gscan_capabilities_t *ptr; + dhd_epno_params_t *epno_params; + dhd_pno_params_t *_params; + dhd_pno_status_info_t *_pno_state; + + if (!dhd || !dhd->pno_state) { + DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__)); + return NULL; + } + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + if (!len) { + DHD_ERROR(("%s: len is NULL\n", __FUNCTION__)); + return NULL; + } + + switch (type) { + case DHD_PNO_GET_CAPABILITIES: + ptr = (dhd_pno_gscan_capabilities_t *) + kmalloc(sizeof(dhd_pno_gscan_capabilities_t), GFP_KERNEL); + if (!ptr) + break; + /* Hardcoding these values for now, need to get + * these values from FW, will change in a later check-in + */ + ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE; + ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS; + ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; + ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX; + ptr->max_scan_reporting_threshold = 100; + ptr->max_hotlist_aps = PFN_HOTLIST_MAX_NUM_APS; + ptr->max_significant_wifi_change_aps = PFN_SWC_MAX_NUM_APS; + ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; + ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; + ptr->max_white_list_ssid = MAX_WHITELIST_SSID; + ret = (void *)ptr; + *len = sizeof(dhd_pno_gscan_capabilities_t); + break; + + case DHD_PNO_GET_BATCH_RESULTS: + ret = dhd_get_gscan_batch_results(dhd, len); + break; + case DHD_PNO_GET_CHANNEL_LIST: + if (info) { + uint16 ch_list[WL_NUMCHANNELS]; + uint32 *ptr, mem_needed, i; + int32 err, nchan = WL_NUMCHANNELS; + uint32 *gscan_band = (uint32 *) info; + uint8 band = 0; + + /* No band specified?, nothing to do */ + if ((*gscan_band & GSCAN_BAND_MASK) == 0) { + DHD_PNO(("No band specified\n")); + *len = 0; + break; + } + + /* HAL and DHD use different bits for 2.4G and + * 5G in bitmap. Hence translating it here... + */ + if (*gscan_band & GSCAN_BG_BAND_MASK) { + band |= WLC_BAND_2G; + } + if (*gscan_band & GSCAN_A_BAND_MASK) { + band |= WLC_BAND_5G; + } + + err = _dhd_pno_get_channels(dhd, ch_list, &nchan, + (band & GSCAN_ABG_BAND_MASK), + !(*gscan_band & GSCAN_DFS_MASK)); + + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list\n", + __FUNCTION__)); + *len = 0; + } else { + mem_needed = sizeof(uint32) * nchan; + ptr = (uint32 *) kmalloc(mem_needed, GFP_KERNEL); + if (!ptr) { + DHD_ERROR(("%s: Unable to malloc %d bytes\n", + __FUNCTION__, mem_needed)); + break; + } + for (i = 0; i < nchan; i++) { + ptr[i] = wf_channel2mhz(ch_list[i], + (ch_list[i] <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + } + ret = ptr; + *len = mem_needed; + } + } else { + *len = 0; + DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__)); + } + break; + case DHD_PNO_GET_EPNO_SSID_ELEM: + if (_params->params_gscan.num_epno_ssid >= + (MAX_EPNO_SSID_NUM + MAX_EPNO_HIDDEN_SSID)) { + DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n", + _params->params_gscan.num_epno_ssid)); + return NULL; + } + + if (!_params->params_gscan.num_epno_ssid) + INIT_LIST_HEAD(&_params->params_gscan.epno_ssid_list); + + epno_params = kzalloc(sizeof(dhd_epno_params_t), GFP_KERNEL); + if (!epno_params) { + DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes", + sizeof(dhd_epno_params_t))); + return NULL; + } + _params->params_gscan.num_epno_ssid++; + epno_params->index = DHD_EPNO_DEFAULT_INDEX; + list_add_tail(&epno_params->list, &_params->params_gscan.epno_ssid_list); + ret = epno_params; + default: + DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); + break; + } + + return ret; +} + +int +dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, + void *buf, uint8 flush) +{ + int err = BCME_OK; + dhd_pno_params_t *_params; + int i; + dhd_pno_status_info_t *_pno_state; + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + mutex_lock(&_pno_state->pno_mutex); + + switch (type) { + case DHD_PNO_BATCH_SCAN_CFG_ID: + { + gscan_batch_params_t *ptr = (gscan_batch_params_t *)buf; + _params->params_gscan.bestn = ptr->bestn; + _params->params_gscan.mscan = ptr->mscan; + _params->params_gscan.buffer_threshold = ptr->buffer_threshold; + } + break; + case DHD_PNO_GEOFENCE_SCAN_CFG_ID: + { + gscan_hotlist_scan_params_t *ptr = + (gscan_hotlist_scan_params_t *)buf; + struct dhd_pno_bssid *_pno_bssid; + struct bssid_t *bssid_ptr; + int8 flags; + + if (flush) { + dhd_pno_reset_cfg_gscan(_params, _pno_state, + GSCAN_FLUSH_HOTLIST_CFG); + } + + if (!ptr->nbssid) + break; + + if (!_params->params_gscan.nbssid_hotlist) + INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list); + + if ((_params->params_gscan.nbssid_hotlist + + ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { + DHD_ERROR(("Excessive number of hotlist APs programmed " + "%d\n", (_params->params_gscan.nbssid_hotlist + + ptr->nbssid))); + err = BCME_RANGE; + goto exit; + } + + for (i = 0, bssid_ptr = ptr->bssid; i < ptr->nbssid; i++, + bssid_ptr++) { + _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), + GFP_KERNEL); + + if (!_pno_bssid) { + DHD_ERROR(("_pno_bssid is NULL, cannot kalloc " + "%zd bytes", + sizeof(struct dhd_pno_bssid))); + err = BCME_NOMEM; + goto exit; + } + memcpy(&_pno_bssid->macaddr, &bssid_ptr->macaddr, + ETHER_ADDR_LEN); + + flags = (int8) bssid_ptr->rssi_reporting_threshold; + _pno_bssid->flags = flags << WL_PFN_RSSI_SHIFT; + list_add_tail(&_pno_bssid->list, + &_params->params_gscan.hotlist_bssid_list); + } + + _params->params_gscan.nbssid_hotlist += ptr->nbssid; + _params->params_gscan.lost_ap_window = ptr->lost_ap_window; + } + break; + case DHD_PNO_SIGNIFICANT_SCAN_CFG_ID: + { + gscan_swc_params_t *ptr = (gscan_swc_params_t *)buf; + dhd_pno_significant_bssid_t *_pno_significant_change_bssid; + wl_pfn_significant_bssid_t *significant_bssid_ptr; + + if (flush) { + dhd_pno_reset_cfg_gscan(_params, _pno_state, + GSCAN_FLUSH_SIGNIFICANT_CFG); + } + + if (!ptr->nbssid) + break; + + if (!_params->params_gscan.nbssid_significant_change) + INIT_LIST_HEAD( + &_params->params_gscan.significant_bssid_list); + + if ((_params->params_gscan.nbssid_significant_change + + ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { + DHD_ERROR(("Excessive number of SWC APs programmed %d\n", + (_params->params_gscan.nbssid_significant_change + + ptr->nbssid))); + err = BCME_RANGE; + goto exit; + } + + for (i = 0, significant_bssid_ptr = ptr->bssid_elem_list; + i < ptr->nbssid; i++, significant_bssid_ptr++) { + _pno_significant_change_bssid = + kzalloc(sizeof(dhd_pno_significant_bssid_t), + GFP_KERNEL); + + if (!_pno_significant_change_bssid) { + DHD_ERROR(("SWC bssidptr is NULL, cannot kalloc " + "%zd bytes", + sizeof(dhd_pno_significant_bssid_t))); + err = BCME_NOMEM; + goto exit; + } + memcpy(&_pno_significant_change_bssid->BSSID, + &significant_bssid_ptr->macaddr, ETHER_ADDR_LEN); + _pno_significant_change_bssid->rssi_low_threshold = + significant_bssid_ptr->rssi_low_threshold; + _pno_significant_change_bssid->rssi_high_threshold = + significant_bssid_ptr->rssi_high_threshold; + list_add_tail(&_pno_significant_change_bssid->list, + &_params->params_gscan.significant_bssid_list); + } + + _params->params_gscan.swc_nbssid_threshold = ptr->swc_threshold; + _params->params_gscan.swc_rssi_window_size = ptr->rssi_window; + _params->params_gscan.lost_ap_window = ptr->lost_ap_window; + _params->params_gscan.nbssid_significant_change += ptr->nbssid; + } + break; + case DHD_PNO_SCAN_CFG_ID: + { + int i, k; + uint16 band; + gscan_scan_params_t *ptr = (gscan_scan_params_t *)buf; + struct dhd_pno_gscan_channel_bucket *ch_bucket; + + if (ptr->nchannel_buckets <= GSCAN_MAX_CH_BUCKETS) { + _params->params_gscan.nchannel_buckets = + ptr->nchannel_buckets; + + memcpy(_params->params_gscan.channel_bucket, + ptr->channel_bucket, + _params->params_gscan.nchannel_buckets * + sizeof(struct dhd_pno_gscan_channel_bucket)); + ch_bucket = _params->params_gscan.channel_bucket; + + for (i = 0; i < ptr->nchannel_buckets; i++) { + band = ch_bucket[i].band; + for (k = 0; k < ptr->channel_bucket[i].num_channels; + k++) { + ch_bucket[i].chan_list[k] = + wf_mhz2channel( + ptr->channel_bucket[i].chan_list[k], + 0); + } + ch_bucket[i].band = 0; + /* HAL and DHD use different bits for 2.4G and + * 5G in bitmap. Hence translating it here... + */ + if (band & GSCAN_BG_BAND_MASK) + ch_bucket[i].band |= WLC_BAND_2G; + if (band & GSCAN_A_BAND_MASK) + ch_bucket[i].band |= WLC_BAND_5G; + if (band & GSCAN_DFS_MASK) + ch_bucket[i].band |= GSCAN_DFS_MASK; + + DHD_PNO(("band %d report_flag %d\n", + ch_bucket[i].band, + ch_bucket[i].report_flag)); + } + + for (i = 0; i < ptr->nchannel_buckets; i++) { + ch_bucket[i].bucket_freq_multiple = + ch_bucket[i].bucket_freq_multiple/ptr->scan_fr; + ch_bucket[i].bucket_max_multiple = + ch_bucket[i].bucket_max_multiple/ptr->scan_fr; + DHD_PNO(("mult %d max_mult %d\n", + ch_bucket[i].bucket_freq_multiple, + ch_bucket[i].bucket_max_multiple)); + } + _params->params_gscan.scan_fr = ptr->scan_fr; + + DHD_PNO(("num_buckets %d scan_fr %d\n", + ptr->nchannel_buckets, + _params->params_gscan.scan_fr)); + } else { + err = BCME_BADARG; + } + } + break; + case DHD_PNO_EPNO_CFG_ID: + if (flush) { + dhd_pno_reset_cfg_gscan(_params, _pno_state, + GSCAN_FLUSH_EPNO_CFG); + } else { + _params->params_gscan.num_visible_epno_ssid += *((uint16 *)buf); + } + break; + default: + err = BCME_BADARG; + DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); + break; + } +exit: + mutex_unlock(&_pno_state->pno_mutex); + return err; + +} + +static bool +validate_gscan_params(struct dhd_pno_gscan_params *gscan_params) +{ + unsigned int i, k; + + if (!gscan_params->scan_fr || !gscan_params->nchannel_buckets) { + DHD_ERROR(("%s : Scan freq - %d or number of channel buckets - %d is empty\n", + __FUNCTION__, gscan_params->scan_fr, gscan_params->nchannel_buckets)); + return false; + } + + for (i = 0; i < gscan_params->nchannel_buckets; i++) { + if (!gscan_params->channel_bucket[i].band) { + for (k = 0; k < gscan_params->channel_bucket[i].num_channels; k++) { + if (gscan_params->channel_bucket[i].chan_list[k] > CHANNEL_5G_MAX) { + DHD_ERROR(("%s : Unknown channel %d\n", __FUNCTION__, + gscan_params->channel_bucket[i].chan_list[k])); + return false; + } + } + } + } + + return true; +} + +static int +dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) +{ + int err = BCME_OK; + int mode, i = 0, k; + uint16 _chan_list[WL_NUMCHANNELS]; + int tot_nchan = 0; + int num_buckets_to_fw, tot_num_buckets, gscan_param_size; + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL; + wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL; + wl_pfn_significant_bssid_t *p_pfn_significant_bssid = NULL; + wl_pfn_bssid_t *p_pfn_bssid = NULL; + wlc_ssid_ext_t *pssid_list = NULL; + dhd_pno_params_t *params_legacy; + dhd_pno_params_t *_params; + + params_legacy = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + NULL_CHECK(gscan_params, "gscan_params is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + + if (!validate_gscan_params(gscan_params)) { + DHD_ERROR(("%s : Cannot start gscan - bad params\n", __FUNCTION__)); + err = BCME_BADARG; + goto exit; + } + /* Create channel list based on channel buckets */ + if (!(ch_bucket = dhd_pno_gscan_create_channel_list(dhd, _pno_state, + _chan_list, &tot_num_buckets, &num_buckets_to_fw))) { + goto exit; + } + + mutex_lock(&_pno_state->pno_mutex); + /* Clear any pre-existing results in our cache + * not consumed by framework + */ + dhd_gscan_clear_all_batch_results(dhd); + if (_pno_state->pno_mode & (DHD_PNO_GSCAN_MODE | DHD_PNO_LEGACY_MODE)) { + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + mutex_unlock(&_pno_state->pno_mutex); + goto exit; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + } + _pno_state->pno_mode |= DHD_PNO_GSCAN_MODE; + mutex_unlock(&_pno_state->pno_mutex); + + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + + if (!pssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + + if ((err = _dhd_pno_add_ssid(dhd, pssid_list, + params_legacy->params_legacy.nssid)) < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + } + + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_GSCAN_MODE)) < 0) { + DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); + goto exit; + } + + gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + + (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); + pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOC(dhd->osh, gscan_param_size); + + if (!pfn_gscan_cfg_t) { + DHD_ERROR(("%s: failed to malloc memory of size %d\n", + __FUNCTION__, gscan_param_size)); + err = BCME_NOMEM; + goto exit; + } + + pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION; + if (gscan_params->mscan) { + pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold; + } else { + pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; + } + if (gscan_params->nbssid_significant_change) { + pfn_gscan_cfg_t->swc_nbssid_threshold = gscan_params->swc_nbssid_threshold; + pfn_gscan_cfg_t->swc_rssi_window_size = gscan_params->swc_rssi_window_size; + pfn_gscan_cfg_t->lost_ap_window = gscan_params->lost_ap_window; + } else { + pfn_gscan_cfg_t->swc_nbssid_threshold = 0; + pfn_gscan_cfg_t->swc_rssi_window_size = 0; + pfn_gscan_cfg_t->lost_ap_window = 0; + } + + pfn_gscan_cfg_t->flags = + (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); + pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw; + pfn_gscan_cfg_t->retry_threshold = GSCAN_RETRY_THRESHOLD; + + for (i = 0, k = 0; i < tot_num_buckets; i++) { + if (ch_bucket[i].bucket_end_index != CHANNEL_BUCKET_EMPTY_INDEX) { + pfn_gscan_cfg_t->channel_bucket[k].bucket_end_index = + ch_bucket[i].bucket_end_index; + pfn_gscan_cfg_t->channel_bucket[k].bucket_freq_multiple = + ch_bucket[i].bucket_freq_multiple; + pfn_gscan_cfg_t->channel_bucket[k].max_freq_multiple = + ch_bucket[i].max_freq_multiple; + pfn_gscan_cfg_t->channel_bucket[k].repeat = + ch_bucket[i].repeat; + pfn_gscan_cfg_t->channel_bucket[k].flag = + ch_bucket[i].flag; + k++; + } + } + + tot_nchan = pfn_gscan_cfg_t->channel_bucket[num_buckets_to_fw - 1].bucket_end_index + 1; + DHD_PNO(("Total channel num %d total ch_buckets %d ch_buckets_to_fw %d \n", tot_nchan, + tot_num_buckets, num_buckets_to_fw)); + + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + + if ((err = _dhd_pno_gscan_cfg(dhd, pfn_gscan_cfg_t, gscan_param_size)) < 0) { + DHD_ERROR(("%s : failed to set call pno_gscan_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + if (gscan_params->nbssid_significant_change) { + dhd_pno_significant_bssid_t *iter, *next; + + p_pfn_significant_bssid = kzalloc(sizeof(wl_pfn_significant_bssid_t) * + gscan_params->nbssid_significant_change, GFP_KERNEL); + if (p_pfn_significant_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate memory %zd\n", __FUNCTION__, + sizeof(wl_pfn_significant_bssid_t) * + gscan_params->nbssid_significant_change)); + err = BCME_NOMEM; + goto exit; + } + i = 0; + /* convert dhd_pno_significant_bssid_t to wl_pfn_significant_bssid_t */ + list_for_each_entry_safe(iter, next, &gscan_params->significant_bssid_list, list) { + p_pfn_significant_bssid[i].rssi_low_threshold = iter->rssi_low_threshold; + p_pfn_significant_bssid[i].rssi_high_threshold = iter->rssi_high_threshold; + memcpy(&p_pfn_significant_bssid[i].macaddr, &iter->BSSID, ETHER_ADDR_LEN); + i++; + } + + DHD_PNO(("nbssid_significant_change %d \n", + gscan_params->nbssid_significant_change)); + err = _dhd_pno_add_significant_bssid(dhd, p_pfn_significant_bssid, + gscan_params->nbssid_significant_change); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_add_significant_bssid(err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + } + + if (gscan_params->nbssid_hotlist) { + struct dhd_pno_bssid *iter, *next; + wl_pfn_bssid_t *ptr; + p_pfn_bssid = (wl_pfn_bssid_t *)kzalloc(sizeof(wl_pfn_bssid_t) * + gscan_params->nbssid_hotlist, GFP_KERNEL); + if (p_pfn_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" + " (count: %d)", + __FUNCTION__, _params->params_hotlist.nbssid)); + err = BCME_NOMEM; + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + goto exit; + } + ptr = p_pfn_bssid; + /* convert dhd_pno_bssid to wl_pfn_bssid */ + DHD_PNO(("nhotlist %d\n", gscan_params->nbssid_hotlist)); + list_for_each_entry_safe(iter, next, + &gscan_params->hotlist_bssid_list, list) { + memcpy(&ptr->macaddr, + &iter->macaddr, ETHER_ADDR_LEN); + ptr->flags = iter->flags; + ptr++; + } + + err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, gscan_params->nbssid_hotlist); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + } + + if (gscan_params->num_epno_ssid > 0) { + DHD_PNO(("num_epno_ssid %d\n", gscan_params->num_epno_ssid)); + err = dhd_epno_set_ssid(dhd, _pno_state); + if (err < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + } + + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) { + DHD_ERROR(("%s : failed to enable PNO err %d\n", __FUNCTION__, err)); + } + +exit: + /* clear mode in case of error */ + if (err < 0) { + int ret = dhd_pno_clean(dhd); + + if (ret < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, ret)); + } else { + _pno_state->pno_mode &= ~DHD_PNO_GSCAN_MODE; + } + } + kfree(pssid_list); + kfree(p_pfn_significant_bssid); + kfree(p_pfn_bssid); + if (pfn_gscan_cfg_t) { + MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size); + } + if (ch_bucket) { + MFREE(dhd->osh, ch_bucket, + (tot_num_buckets * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); + } + return err; +} + +static wl_pfn_gscan_ch_bucket_cfg_t * +dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, + dhd_pno_status_info_t *_pno_state, + uint16 *chan_list, + uint32 *num_buckets, + uint32 *num_buckets_to_fw) +{ + int i, num_channels, err, nchan = WL_NUMCHANNELS, ch_cnt; + uint16 *ptr = chan_list, max; + wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket; + dhd_pno_params_t *_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + bool is_pno_legacy_running = _pno_state->pno_mode & DHD_PNO_LEGACY_MODE; + dhd_pno_gscan_channel_bucket_t *gscan_buckets = _params->params_gscan.channel_bucket; + + if (is_pno_legacy_running) + *num_buckets = _params->params_gscan.nchannel_buckets + 1; + else + *num_buckets = _params->params_gscan.nchannel_buckets; + + *num_buckets_to_fw = 0; + + ch_bucket = (wl_pfn_gscan_ch_bucket_cfg_t *) MALLOC(dhd->osh, + ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); + + if (!ch_bucket) { + DHD_ERROR(("%s: failed to malloc memory of size %zd\n", + __FUNCTION__, (*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); + *num_buckets_to_fw = *num_buckets = 0; + return NULL; + } + + max = gscan_buckets[0].bucket_freq_multiple; + num_channels = 0; + /* nchan is the remaining space left in chan_list buffer + * So any overflow list of channels is ignored + */ + for (i = 0; i < _params->params_gscan.nchannel_buckets && nchan; i++) { + if (!gscan_buckets[i].band) { + ch_cnt = MIN(gscan_buckets[i].num_channels, (uint8)nchan); + num_channels += ch_cnt; + memcpy(ptr, gscan_buckets[i].chan_list, + ch_cnt * sizeof(uint16)); + ptr = ptr + ch_cnt; + } else { + /* get a valid channel list based on band B or A */ + err = _dhd_pno_get_channels(dhd, ptr, + &nchan, (gscan_buckets[i].band & GSCAN_ABG_BAND_MASK), + !(gscan_buckets[i].band & GSCAN_DFS_MASK)); + + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", + __FUNCTION__, gscan_buckets[i].band)); + MFREE(dhd->osh, ch_bucket, + ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); + *num_buckets_to_fw = *num_buckets = 0; + return NULL; + } + + num_channels += nchan; + ptr = ptr + nchan; + } + + ch_bucket[i].bucket_end_index = num_channels - 1; + ch_bucket[i].bucket_freq_multiple = gscan_buckets[i].bucket_freq_multiple; + ch_bucket[i].repeat = gscan_buckets[i].repeat; + ch_bucket[i].max_freq_multiple = gscan_buckets[i].bucket_max_multiple; + ch_bucket[i].flag = gscan_buckets[i].report_flag; + /* HAL and FW interpretations are opposite for this bit */ + ch_bucket[i].flag ^= DHD_PNO_REPORT_NO_BATCH; + if (max < gscan_buckets[i].bucket_freq_multiple) + max = gscan_buckets[i].bucket_freq_multiple; + nchan = WL_NUMCHANNELS - num_channels; + *num_buckets_to_fw = *num_buckets_to_fw + 1; + DHD_PNO(("end_idx %d freq_mult - %d\n", + ch_bucket[i].bucket_end_index, ch_bucket[i].bucket_freq_multiple)); + } + + _params->params_gscan.max_ch_bucket_freq = max; + /* Legacy PNO maybe running, which means we need to create a legacy PNO bucket + * Get GCF of Legacy PNO and Gscan scanfreq + */ + if (is_pno_legacy_running) { + dhd_pno_params_t *_params1 = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + uint16 *legacy_chan_list = _params1->params_legacy.chan_list; + uint16 common_freq; + uint32 legacy_bucket_idx = _params->params_gscan.nchannel_buckets; + /* If no space is left then only the gscan buckets will be sent to FW */ + if (nchan) { + common_freq = gcd(_params->params_gscan.scan_fr, + _params1->params_legacy.scan_fr); + max = gscan_buckets[0].bucket_freq_multiple; + /* GSCAN buckets */ + for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) { + ch_bucket[i].bucket_freq_multiple *= _params->params_gscan.scan_fr; + ch_bucket[i].bucket_freq_multiple /= common_freq; + if (max < gscan_buckets[i].bucket_freq_multiple) + max = gscan_buckets[i].bucket_freq_multiple; + } + /* Legacy PNO bucket */ + ch_bucket[legacy_bucket_idx].bucket_freq_multiple = + _params1->params_legacy.scan_fr; + ch_bucket[legacy_bucket_idx].bucket_freq_multiple /= + common_freq; + _params->params_gscan.max_ch_bucket_freq = MAX(max, + ch_bucket[legacy_bucket_idx].bucket_freq_multiple); + ch_bucket[legacy_bucket_idx].flag = CH_BUCKET_REPORT_REGULAR; + /* Now add channels to the legacy scan bucket */ + for (i = 0; i < _params1->params_legacy.nchan && nchan; i++, nchan--) { + ptr[i] = legacy_chan_list[i]; + num_channels++; + } + ch_bucket[legacy_bucket_idx].bucket_end_index = num_channels - 1; + *num_buckets_to_fw = *num_buckets_to_fw + 1; + DHD_PNO(("end_idx %d freq_mult - %d\n", + ch_bucket[legacy_bucket_idx].bucket_end_index, + ch_bucket[legacy_bucket_idx].bucket_freq_multiple)); + } + } + return ch_bucket; +} + +static int +dhd_pno_stop_for_gscan(dhd_pub_t *dhd) +{ + int err = BCME_OK; + int mode; + dhd_pno_status_info_t *_pno_state; + wlc_ssid_ext_t *pssid_list = NULL; + + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", + __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + + if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { + DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); + goto exit; + } + if (_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.mscan) { + /* retrieve the batching data from firmware into host */ + err = dhd_wait_batch_results_complete(dhd); + if (err != BCME_OK) + goto exit; + } + mutex_lock(&_pno_state->pno_mutex); + mode = _pno_state->pno_mode & ~DHD_PNO_GSCAN_MODE; + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + mutex_unlock(&_pno_state->pno_mutex); + return err; + } + _pno_state->pno_mode = mode; + mutex_unlock(&_pno_state->pno_mutex); + _pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.ssid_ext_last_used_index = 0; + + /* Reprogram Legacy PNO if it was running */ + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + struct dhd_pno_legacy_params *params_legacy; + uint16 chan_list[WL_NUMCHANNELS]; + + params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!pssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + + DHD_PNO(("Restarting Legacy PNO SSID scan...\n")); + memcpy(chan_list, params_legacy->chan_list, + (params_legacy->nchan * sizeof(uint16))); + err = dhd_pno_set_for_ssid(dhd, pssid_list, params_legacy->nssid, + params_legacy->scan_fr, params_legacy->pno_repeat, + params_legacy->pno_freq_expo_max, chan_list, + params_legacy->nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + + } + +exit: + kfree(pssid_list); + return err; +} + +int +dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush) +{ + int err = BCME_OK; + dhd_pno_params_t *params; + dhd_pno_status_info_t *_pno_state; + struct dhd_pno_gscan_params *gscan_params; + + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + DHD_ERROR(("%s enter - run %d flush %d\n", __FUNCTION__, run, flush)); + + params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + gscan_params = ¶ms->params_gscan; + + if (run) { + err = dhd_pno_set_for_gscan(dhd, gscan_params); + } else { + if (flush) { + mutex_lock(&_pno_state->pno_mutex); + dhd_pno_reset_cfg_gscan(params, _pno_state, GSCAN_FLUSH_ALL_CFG); + mutex_unlock(&_pno_state->pno_mutex); + } + /* Need to stop all gscan */ + err = dhd_pno_stop_for_gscan(dhd); + } + + return err; +} + +int +dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag) +{ + int err = BCME_OK; + dhd_pno_params_t *params; + dhd_pno_status_info_t *_pno_state; + struct dhd_pno_gscan_params *gscan_params; + uint8 old_flag; + + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + + params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + gscan_params = ¶ms->params_gscan; + + mutex_lock(&_pno_state->pno_mutex); + + old_flag = gscan_params->send_all_results_flag; + gscan_params->send_all_results_flag = (uint8) real_time_flag; + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + if (old_flag != gscan_params->send_all_results_flag) { + wl_pfn_gscan_cfg_t gscan_cfg; + gscan_cfg.version = WL_GSCAN_CFG_VERSION; + gscan_cfg.flags = (gscan_params->send_all_results_flag & + GSCAN_SEND_ALL_RESULTS_MASK); + gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK; + + if ((err = _dhd_pno_gscan_cfg(dhd, &gscan_cfg, + sizeof(wl_pfn_gscan_cfg_t))) < 0) { + DHD_ERROR(("%s : pno_gscan_cfg failed (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit_mutex_unlock; + } + } else { + DHD_PNO(("No change in flag - %d\n", old_flag)); + } + } else { + DHD_PNO(("Gscan not started\n")); + } +exit_mutex_unlock: + mutex_unlock(&_pno_state->pno_mutex); +exit: + return err; +} + +/* Cleanup any consumed results + * Return TRUE if all results consumed, else FALSE + */ +int +dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd) +{ + int ret = 0; + dhd_pno_params_t *params; + struct dhd_pno_gscan_params *gscan_params; + dhd_pno_status_info_t *_pno_state; + gscan_results_cache_t *iter, *tmp; + + _pno_state = PNO_GET_PNOSTATE(dhd); + params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + gscan_params = ¶ms->params_gscan; + iter = gscan_params->gscan_batch_cache; + + while (iter) { + if (iter->tot_consumed == iter->tot_count) { + tmp = iter->next; + kfree(iter); + iter = tmp; + } else + break; + } + gscan_params->gscan_batch_cache = iter; + ret = (iter == NULL); + return ret; +} + +static int +_dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) +{ + int err = BCME_OK; + uint32 timestamp = 0, ts = 0, i, j, timediff; + dhd_pno_params_t *params; + dhd_pno_status_info_t *_pno_state; + wl_pfn_lnet_info_t *plnetinfo; + struct dhd_pno_gscan_params *gscan_params; + wl_pfn_lscanresults_t *plbestnet = NULL; + gscan_results_cache_t *iter, *tail; + wifi_gscan_result_t *result; + uint8 *nAPs_per_scan = NULL; + uint8 num_scans_in_cur_iter; + uint16 count; + + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + + _pno_state = PNO_GET_PNOSTATE(dhd); + params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { + DHD_ERROR(("%s: GSCAN is not enabled\n", __FUNCTION__)); + goto exit; + } + gscan_params = ¶ms->params_gscan; + nAPs_per_scan = (uint8 *) MALLOC(dhd->osh, gscan_params->mscan); + + if (!nAPs_per_scan) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, + gscan_params->mscan)); + err = BCME_NOMEM; + goto exit; + } + + plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + + mutex_lock(&_pno_state->pno_mutex); + + dhd_gscan_clear_all_batch_results(dhd); + + if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { + DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); + goto exit_mutex_unlock; + } + + timediff = gscan_params->scan_fr * 1000; + timediff = timediff >> 1; + + /* Ok, now lets start getting results from the FW */ + plbestnet->status = PFN_INCOMPLETE; + tail = gscan_params->gscan_batch_cache; + while (plbestnet->status != PFN_COMPLETE) { + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN, + FALSE); + if (err < 0) { + DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n", + __FUNCTION__, err)); + goto exit_mutex_unlock; + } + DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, + plbestnet->status, plbestnet->count)); + if (plbestnet->version != PFN_SCANRESULT_VERSION) { + err = BCME_VERSION; + DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", + plbestnet->version, PFN_SCANRESULT_VERSION)); + goto exit_mutex_unlock; + } + if (plbestnet->count == 0) { + DHD_PNO(("No more batch results\n")); + goto exit_mutex_unlock; + } + num_scans_in_cur_iter = 0; + timestamp = plbestnet->netinfo[0].timestamp; + /* find out how many scans' results did we get in this batch of FW results */ + for (i = 0, count = 0; i < plbestnet->count; i++, count++) { + plnetinfo = &plbestnet->netinfo[i]; + /* Unlikely to happen, but just in case the results from + * FW doesnt make sense..... Assume its part of one single scan + */ + if (num_scans_in_cur_iter > gscan_params->mscan) { + num_scans_in_cur_iter = 0; + count = plbestnet->count; + break; + } + if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) { + nAPs_per_scan[num_scans_in_cur_iter] = count; + count = 0; + num_scans_in_cur_iter++; + } + timestamp = plnetinfo->timestamp; + } + nAPs_per_scan[num_scans_in_cur_iter] = count; + num_scans_in_cur_iter++; + + DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter)); + plnetinfo = &plbestnet->netinfo[0]; + + for (i = 0; i < num_scans_in_cur_iter; i++) { + iter = (gscan_results_cache_t *) + kmalloc(((nAPs_per_scan[i] - 1) * sizeof(wifi_gscan_result_t)) + + sizeof(gscan_results_cache_t), GFP_KERNEL); + if (!iter) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", + __FUNCTION__, gscan_params->mscan)); + err = BCME_NOMEM; + goto exit_mutex_unlock; + } + /* Need this check because the new set of results from FW + * maybe a continuation of previous sets' scan results + */ + if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) { + iter->scan_id = ++gscan_params->scan_id; + } else { + iter->scan_id = gscan_params->scan_id; + } + DHD_PNO(("scan_id %d tot_count %d\n", gscan_params->scan_id, + nAPs_per_scan[i])); + iter->tot_count = nAPs_per_scan[i]; + iter->tot_consumed = 0; + iter->flag = 0; + if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { + DHD_PNO(("This scan is aborted\n")); + iter->flag = (ENABLE << PNO_STATUS_ABORT); + } else if (gscan_params->reason) { + iter->flag = (ENABLE << gscan_params->reason); + } + + if (!tail) { + gscan_params->gscan_batch_cache = iter; + } else { + tail->next = iter; + } + tail = iter; + iter->next = NULL; + for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) { + result = &iter->results[j]; + + result->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, + (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + result->rssi = (int32) plnetinfo->RSSI; + /* Info not available & not expected */ + result->beacon_period = 0; + result->capability = 0; + result->ie_length = 0; + result->rtt = (uint64) plnetinfo->rtt0; + result->rtt_sd = (uint64) plnetinfo->rtt1; + result->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); + ts = plnetinfo->timestamp; + if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length %d\n", + __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); + plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + memcpy(result->ssid, plnetinfo->pfnsubnet.SSID, + plnetinfo->pfnsubnet.SSID_len); + result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; + memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID, + ETHER_ADDR_LEN); + + DHD_PNO(("\tSSID : ")); + DHD_PNO(("\n")); + DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", + result->macaddr.octet[0], + result->macaddr.octet[1], + result->macaddr.octet[2], + result->macaddr.octet[3], + result->macaddr.octet[4], + result->macaddr.octet[5])); + DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", + plnetinfo->pfnsubnet.channel, + plnetinfo->RSSI, plnetinfo->timestamp)); + DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", + plnetinfo->rtt0, plnetinfo->rtt1)); + } + } + } +exit_mutex_unlock: + mutex_unlock(&_pno_state->pno_mutex); +exit: + params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_COMPLETE; + smp_wmb(); + wake_up_interruptible(&_pno_state->batch_get_wait); + if (nAPs_per_scan) { + MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan); + } + if (plbestnet) { + MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); + } + DHD_PNO(("Batch retrieval done!\n")); + return err; +} +#endif /* GSCAN_SUPPORT */ + +static int +_dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) +{ + int err = BCME_OK; + int i, j; + uint32 timestamp = 0; + dhd_pno_params_t *_params = NULL; + dhd_pno_status_info_t *_pno_state = NULL; + wl_pfn_lscanresults_t *plbestnet = NULL; + wl_pfn_lnet_info_t *plnetinfo; + dhd_pno_bestnet_entry_t *pbestnet_entry; + dhd_pno_best_header_t *pbestnetheader = NULL; + dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext; + bool allocate_header = FALSE; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit_no_unlock; + } + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit_no_unlock; + } + + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); + goto exit_no_unlock; + } + mutex_lock(&_pno_state->pno_mutex); + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + if (buf && bufsize) { + if (!list_empty(&_params->params_batch.get_batch.expired_scan_results_list)) { + /* need to check whether we have cashed data or not */ + DHD_PNO(("%s: have cashed batching data in Driver\n", + __FUNCTION__)); + /* convert to results format */ + goto convert_format; + } else { + /* this is a first try to get batching results */ + if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { + /* move the scan_results_list to expired_scan_results_lists */ + list_for_each_entry_safe(siter, snext, + &_params->params_batch.get_batch.scan_results_list, list) { + list_move_tail(&siter->list, + &_params->params_batch.get_batch.expired_scan_results_list); + } + _params->params_batch.get_batch.top_node_cnt = 0; + _params->params_batch.get_batch.expired_tot_scan_cnt = + _params->params_batch.get_batch.tot_scan_cnt; + _params->params_batch.get_batch.tot_scan_cnt = 0; + goto convert_format; + } + } + } + /* create dhd_pno_scan_results_t whenever we got event WLC_E_PFN_BEST_BATCHING */ + pscan_results = (dhd_pno_scan_results_t *)MALLOC(dhd->osh, SCAN_RESULTS_SIZE); + if (pscan_results == NULL) { + err = BCME_NOMEM; + DHD_ERROR(("failed to allocate dhd_pno_scan_results_t\n")); + goto exit; + } + pscan_results->bestnetheader = NULL; + pscan_results->cnt_header = 0; + /* add the element into list unless total node cnt is less than MAX_NODE_ CNT */ + if (_params->params_batch.get_batch.top_node_cnt < MAX_NODE_CNT) { + list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); + _params->params_batch.get_batch.top_node_cnt++; + } else { + int _removed_scan_cnt; + /* remove oldest one and add new one */ + DHD_PNO(("%s : Remove oldest node and add new one\n", __FUNCTION__)); + _removed_scan_cnt = _dhd_pno_clear_all_batch_results(dhd, + &_params->params_batch.get_batch.scan_results_list, TRUE); + _params->params_batch.get_batch.tot_scan_cnt -= _removed_scan_cnt; + list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); + + } + plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + memset(plbestnet, 0, PNO_BESTNET_LEN); + while (plbestnet->status != PFN_COMPLETE) { + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN, + FALSE); + if (err < 0) { + if (err == BCME_EPERM) { + DHD_ERROR(("we cannot get the batching data " + "during scanning in firmware, try again\n,")); + msleep(500); + continue; + } else { + DHD_ERROR(("%s : failed to execute pfnlbest (err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + } + DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, + plbestnet->status, plbestnet->count)); + if (plbestnet->version != PFN_SCANRESULT_VERSION) { + err = BCME_VERSION; + DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", + plbestnet->version, PFN_SCANRESULT_VERSION)); + goto exit; + } + plnetinfo = plbestnet->netinfo; + for (i = 0; i < plbestnet->count; i++) { + pbestnet_entry = (dhd_pno_bestnet_entry_t *) + MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); + if (pbestnet_entry == NULL) { + err = BCME_NOMEM; + DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); + goto exit; + } + memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE); + pbestnet_entry->recorded_time = jiffies; /* record the current time */ + /* create header for the first entry */ + allocate_header = (i == 0)? TRUE : FALSE; + /* check whether the new generation is started or not */ + if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) + > TIME_MIN_DIFF)) + allocate_header = TRUE; + timestamp = plnetinfo->timestamp; + if (allocate_header) { + pbestnetheader = (dhd_pno_best_header_t *) + MALLOC(dhd->osh, BEST_HEADER_SIZE); + if (pbestnetheader == NULL) { + err = BCME_NOMEM; + if (pbestnet_entry) + MFREE(dhd->osh, pbestnet_entry, + BESTNET_ENTRY_SIZE); + DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); + goto exit; + } + /* increase total cnt of bestnet header */ + pscan_results->cnt_header++; + /* need to record the reason to call dhd_pno_get_for_bach */ + if (reason) + pbestnetheader->reason = (ENABLE << reason); + memset(pbestnetheader, 0, BEST_HEADER_SIZE); + /* initialize the head of linked list */ + INIT_LIST_HEAD(&(pbestnetheader->entry_list)); + /* link the pbestnet heaer into existed list */ + if (pscan_results->bestnetheader == NULL) + /* In case of header */ + pscan_results->bestnetheader = pbestnetheader; + else { + dhd_pno_best_header_t *head = pscan_results->bestnetheader; + pscan_results->bestnetheader = pbestnetheader; + pbestnetheader->next = head; + } + } + /* fills the best network info */ + pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; + pbestnet_entry->RSSI = plnetinfo->RSSI; + if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { + /* if RSSI is positive value, we assume that + * this scan is aborted by other scan + */ + DHD_PNO(("This scan is aborted\n")); + pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); + } + pbestnet_entry->rtt0 = plnetinfo->rtt0; + pbestnet_entry->rtt1 = plnetinfo->rtt1; + pbestnet_entry->timestamp = plnetinfo->timestamp; + if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length %d: trimming it to max\n", + __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); + plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; + memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, + pbestnet_entry->SSID_len); + memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); + /* add the element into list */ + list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); + /* increase best entry count */ + pbestnetheader->tot_cnt++; + pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; + DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1)); + DHD_PNO(("\tSSID : ")); + for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) + DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j])); + DHD_PNO(("\n")); + DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", + plnetinfo->pfnsubnet.BSSID.octet[0], + plnetinfo->pfnsubnet.BSSID.octet[1], + plnetinfo->pfnsubnet.BSSID.octet[2], + plnetinfo->pfnsubnet.BSSID.octet[3], + plnetinfo->pfnsubnet.BSSID.octet[4], + plnetinfo->pfnsubnet.BSSID.octet[5])); + DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", + plnetinfo->pfnsubnet.channel, + plnetinfo->RSSI, plnetinfo->timestamp)); + DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1)); + plnetinfo++; + } + } + if (pscan_results->cnt_header == 0) { + /* In case that we didn't get any data from the firmware + * Remove the current scan_result list from get_bach.scan_results_list. + */ + DHD_PNO(("NO BATCH DATA from Firmware, Delete current SCAN RESULT LIST\n")); + list_del(&pscan_results->list); + MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE); + _params->params_batch.get_batch.top_node_cnt--; + } else { + /* increase total scan count using current scan count */ + _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; + } + + if (buf && bufsize) { + /* This is a first try to get batching results */ + if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { + /* move the scan_results_list to expired_scan_results_lists */ + list_for_each_entry_safe(siter, snext, + &_params->params_batch.get_batch.scan_results_list, list) { + list_move_tail(&siter->list, + &_params->params_batch.get_batch.expired_scan_results_list); + } + /* reset gloval values after moving to expired list */ + _params->params_batch.get_batch.top_node_cnt = 0; + _params->params_batch.get_batch.expired_tot_scan_cnt = + _params->params_batch.get_batch.tot_scan_cnt; + _params->params_batch.get_batch.tot_scan_cnt = 0; + } +convert_format: + err = _dhd_pno_convert_format(dhd, &_params->params_batch, buf, bufsize); + if (err < 0) { + DHD_ERROR(("failed to convert the data into upper layer format\n")); + goto exit; + } + } +exit: + if (plbestnet) + MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); + if (_params) { + _params->params_batch.get_batch.buf = NULL; + _params->params_batch.get_batch.bufsize = 0; + _params->params_batch.get_batch.bytes_written = err; + } + mutex_unlock(&_pno_state->pno_mutex); +exit_no_unlock: + if (waitqueue_active(&_pno_state->get_batch_done.wait)) + complete(&_pno_state->get_batch_done); + return err; +} +static void +_dhd_pno_get_batch_handler(struct work_struct *work) +{ + dhd_pno_status_info_t *_pno_state; + dhd_pub_t *dhd; + struct dhd_pno_batch_params *params_batch; + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = container_of(work, struct dhd_pno_status_info, work); + dhd = _pno_state->dhd; + if (dhd == NULL) { + DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); + return; + } +#ifdef GSCAN_SUPPORT + _dhd_pno_get_gscan_batch_from_fw(dhd); +#endif /* GSCAN_SUPPORT */ + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; + + _dhd_pno_get_for_batch(dhd, params_batch->get_batch.buf, + params_batch->get_batch.bufsize, params_batch->get_batch.reason); + } +} + +int +dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) +{ + int err = BCME_OK; + char *pbuf = buf; + dhd_pno_status_info_t *_pno_state; + struct dhd_pno_batch_params *params_batch; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + struct dhd_pno_gscan_params *gscan_params; + gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; + gscan_params->reason = reason; + err = dhd_retreive_batch_scan_results(dhd); + if (err == BCME_OK) { + wait_event_interruptible_timeout(_pno_state->batch_get_wait, + is_batch_retrieval_complete(gscan_params), + msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); + } + } else +#endif + { + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); + memset(pbuf, 0, bufsize); + pbuf += sprintf(pbuf, "scancount=%d\n", 0); + sprintf(pbuf, "%s", RESULTS_END_MARKER); + err = strlen(buf); + goto exit; + } + params_batch->get_batch.buf = buf; + params_batch->get_batch.bufsize = bufsize; + params_batch->get_batch.reason = reason; + params_batch->get_batch.bytes_written = 0; + schedule_work(&_pno_state->work); + wait_for_completion(&_pno_state->get_batch_done); + } + +#ifdef GSCAN_SUPPORT + if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) +#endif + err = params_batch->get_batch.bytes_written; +exit: + return err; +} + +int +dhd_pno_stop_for_batch(dhd_pub_t *dhd) +{ + int err = BCME_OK; + int mode = 0; + int i = 0; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + wl_pfn_bssid_t *p_pfn_bssid = NULL; + wlc_ssid_ext_t *p_ssid_list = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", + __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + DHD_PNO(("Gscan is ongoing, nothing to stop here\n")); + return err; + } +#endif + + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + DHD_ERROR(("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__)); + goto exit; + } + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { + mode = _pno_state->pno_mode; + dhd_pno_clean(dhd); + _pno_state->pno_mode = mode; + /* restart Legacy PNO if the Legacy PNO is on */ + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + struct dhd_pno_legacy_params *_params_legacy; + _params_legacy = + &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); + p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!p_ssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, + _params_legacy->scan_fr, _params_legacy->pno_repeat, + _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, + _params_legacy->nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + struct dhd_pno_bssid *iter, *next; + _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * + _params->params_hotlist.nbssid, GFP_KERNEL); + if (p_pfn_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" + " (count: %d)", + __FUNCTION__, _params->params_hotlist.nbssid)); + err = BCME_ERROR; + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + goto exit; + } + i = 0; + /* convert dhd_pno_bssid to wl_pfn_bssid */ + list_for_each_entry_safe(iter, next, + &_params->params_hotlist.bssid_list, list) { + memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN); + p_pfn_bssid[i].flags = iter->flags; + i++; + } + err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + } else { + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } +exit: + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); + if (p_ssid_list) + kfree(p_ssid_list); + if (p_pfn_bssid) + kfree(p_pfn_bssid); + return err; +} + +int +dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params) +{ + int err = BCME_OK; + int i; + uint16 _chan_list[WL_NUMCHANNELS]; + int rem_nchan = 0; + int tot_nchan = 0; + int mode = 0; + dhd_pno_params_t *_params; + dhd_pno_params_t *_params2; + struct dhd_pno_bssid *_pno_bssid; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + NULL_CHECK(hotlist_params, "hotlist_params is NULL", err); + NULL_CHECK(p_pfn_bssid, "p_pfn_bssid is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + _params = &_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]; + if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { + _pno_state->pno_mode |= DHD_PNO_HOTLIST_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_HOTLIST_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", + __FUNCTION__)); + goto exit; + } + } + _params->params_batch.nchan = hotlist_params->nchan; + _params->params_batch.scan_fr = hotlist_params->scan_fr; + if (hotlist_params->nchan) + memcpy(_params->params_hotlist.chan_list, hotlist_params->chan_list, + sizeof(_params->params_hotlist.chan_list)); + memset(_chan_list, 0, sizeof(_chan_list)); + + rem_nchan = ARRAYSIZE(hotlist_params->chan_list) - hotlist_params->nchan; + if (hotlist_params->band == WLC_BAND_2G || hotlist_params->band == WLC_BAND_5G) { + /* get a valid channel list based on band B or A */ + err = _dhd_pno_get_channels(dhd, + &_params->params_hotlist.chan_list[hotlist_params->nchan], + &rem_nchan, hotlist_params->band, FALSE); + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", + __FUNCTION__, hotlist_params->band)); + goto exit; + } + /* now we need to update nchan because rem_chan has valid channel count */ + _params->params_hotlist.nchan += rem_nchan; + /* need to sort channel list */ + sort(_params->params_hotlist.chan_list, _params->params_hotlist.nchan, + sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL); + } +#ifdef PNO_DEBUG +{ + int i; + DHD_PNO(("Channel list : ")); + for (i = 0; i < _params->params_batch.nchan; i++) { + DHD_PNO(("%d ", _params->params_batch.chan_list[i])); + } + DHD_PNO(("\n")); +} +#endif + if (_params->params_hotlist.nchan) { + /* copy the channel list into local array */ + memcpy(_chan_list, _params->params_hotlist.chan_list, + sizeof(_chan_list)); + tot_nchan = _params->params_hotlist.nchan; + } + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + DHD_PNO(("PNO SSID is on progress in firmware\n")); + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = _dhd_pno_enable(dhd, PNO_OFF); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + goto exit; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + /* Use the superset for channelist between two mode */ + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + if (_params2->params_legacy.nchan > 0 && + _params->params_hotlist.nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_legacy.chan_list[0], + _params2->params_legacy.nchan, + &_params->params_hotlist.chan_list[0], + _params->params_hotlist.nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + "between legacy and hotlist\n", + __FUNCTION__)); + goto exit; + } + } + + } + + INIT_LIST_HEAD(&(_params->params_hotlist.bssid_list)); + + err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, hotlist_params->nbssid); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_HOTLIST_MODE)) < 0) { + DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + if (tot_nchan > 0) { + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + } + for (i = 0; i < hotlist_params->nbssid; i++) { + _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); + NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err); + memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN); + _pno_bssid->flags = p_pfn_bssid[i].flags; + list_add_tail(&_pno_bssid->list, &_params->params_hotlist.bssid_list); + } + _params->params_hotlist.nbssid = hotlist_params->nbssid; + if (_pno_state->pno_status == DHD_PNO_DISABLED) { + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) + DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); + } +exit: + /* clear mode in case of error */ + if (err < 0) + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + return err; +} + +int +dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) +{ + int err = BCME_OK; + uint32 mode = 0; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + wlc_ssid_ext_t *p_ssid_list = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", + __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + + if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { + DHD_ERROR(("%s : Hotlist MODE is not enabled\n", + __FUNCTION__)); + goto exit; + } + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + + if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_BATCH_MODE)) { + /* retrieve the batching data from firmware into host */ + dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); + /* save current pno_mode before calling dhd_pno_clean */ + mode = _pno_state->pno_mode; + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + /* restore previos pno mode */ + _pno_state->pno_mode = mode; + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + /* restart Legacy PNO Scan */ + struct dhd_pno_legacy_params *_params_legacy; + _params_legacy = + &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); + p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!p_ssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); + goto exit; + } + err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, + _params_legacy->scan_fr, _params_legacy->pno_repeat, + _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, + _params_legacy->nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } else if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + /* restart Batching Scan */ + _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + /* restart BATCH SCAN */ + err = dhd_pno_set_for_batch(dhd, &_params->params_batch); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + } else { + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } +exit: + if (p_ssid_list) + kfree(p_ssid_list); + return err; +} + +#ifdef GSCAN_SUPPORT +int +dhd_retreive_batch_scan_results(dhd_pub_t *dhd) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + struct dhd_pno_batch_params *params_batch; + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; + if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE) { + DHD_PNO(("Retreive batch results\n")); + params_batch->get_batch.buf = NULL; + params_batch->get_batch.bufsize = 0; + params_batch->get_batch.reason = PNO_STATUS_EVENT; + _params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_IN_PROGRESS; + smp_wmb(); + schedule_work(&_pno_state->work); + } else { + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING retrieval" + "already in progress, will skip\n", __FUNCTION__)); + err = BCME_ERROR; + } + + return err; +} + +/* Handle Significant WiFi Change (SWC) event from FW + * Send event to HAL when all results arrive from FW + */ +void * +dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes) +{ + void *ptr = NULL; + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + struct dhd_pno_gscan_params *gscan_params; + struct dhd_pno_swc_evt_param *params; + wl_pfn_swc_results_t *results = (wl_pfn_swc_results_t *)event_data; + wl_pfn_significant_net_t *change_array; + int i; + + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + params = &(gscan_params->param_significant); + + if (!results->total_count) { + *send_evt_bytes = 0; + return ptr; + } + + if (!params->results_rxed_so_far) { + if (!params->change_array) { + params->change_array = (wl_pfn_significant_net_t *) + kmalloc(sizeof(wl_pfn_significant_net_t) * results->total_count, + GFP_KERNEL); + + if (!params->change_array) { + DHD_ERROR(("%s Cannot Malloc %zd bytes!!\n", __FUNCTION__, + sizeof(wl_pfn_significant_net_t) * results->total_count)); + *send_evt_bytes = 0; + return ptr; + } + } else { + DHD_ERROR(("RX'ed WLC_E_PFN_SWC evt from FW, previous evt not complete!!")); + *send_evt_bytes = 0; + return ptr; + } + } + + DHD_PNO(("%s: pkt_count %d total_count %d\n", __FUNCTION__, + results->pkt_count, results->total_count)); + + for (i = 0; i < results->pkt_count; i++) { + DHD_PNO(("\t %02x:%02x:%02x:%02x:%02x:%02x\n", + results->list[i].BSSID.octet[0], + results->list[i].BSSID.octet[1], + results->list[i].BSSID.octet[2], + results->list[i].BSSID.octet[3], + results->list[i].BSSID.octet[4], + results->list[i].BSSID.octet[5])); + } + + change_array = ¶ms->change_array[params->results_rxed_so_far]; + if ((params->results_rxed_so_far + results->pkt_count) <= results->total_count) { + memcpy(change_array, results->list, + sizeof(wl_pfn_significant_net_t) * results->pkt_count); + params->results_rxed_so_far += results->pkt_count; + } else { + /* In case of spurious event or invalid data send hang event */ + dhd_os_send_hang_message(dhd); + } + + if (params->results_rxed_so_far == results->total_count) { + params->results_rxed_so_far = 0; + *send_evt_bytes = sizeof(wl_pfn_significant_net_t) * results->total_count; + /* Pack up change buffer to send up and reset + * results_rxed_so_far, after its done. + */ + ptr = (void *) params->change_array; + /* expecting the callee to free this mem chunk */ + params->change_array = NULL; + } + else { + *send_evt_bytes = 0; + } + + return ptr; +} + +void +dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) +{ + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + struct dhd_pno_gscan_params *gscan_params; + gscan_results_cache_t *iter, *tmp; + + if (!_pno_state) + return; + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + + if (type == HOTLIST_FOUND) { + iter = gscan_params->gscan_hotlist_found; + gscan_params->gscan_hotlist_found = NULL; + } else { + iter = gscan_params->gscan_hotlist_lost; + gscan_params->gscan_hotlist_lost = NULL; + } + + while (iter) { + tmp = iter->next; + kfree(iter); + iter = tmp; + } + + return; +} + +void * +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) +{ + wl_bss_info_t *bi = NULL; + wl_gscan_result_t *gscan_result; + wifi_gscan_result_t *result = NULL; + u32 bi_length = 0; + uint8 channel; + uint32 mem_needed; + struct timespec ts; + + *size = 0; + + gscan_result = (wl_gscan_result_t *)data; + + if (!gscan_result) { + DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); + goto exit; + } + if (!gscan_result->bss_info) { + DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); + goto exit; + } + bi = &gscan_result->bss_info[0].info; + bi_length = dtoh32(bi->length); + if (bi_length != (dtoh32(gscan_result->buflen) - + WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) { + DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); + goto exit; + } + if (bi->SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", bi->SSID_len)); + bi->SSID_len = DOT11_MAX_SSID_LEN; + } + + mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi->ie_length; + result = kmalloc(mem_needed, GFP_KERNEL); + + if (!result) { + DHD_ERROR(("%s Cannot malloc scan result buffer %d bytes\n", + __FUNCTION__, mem_needed)); + goto exit; + } + + memcpy(result->ssid, bi->SSID, bi->SSID_len); + result->ssid[bi->SSID_len] = '\0'; + channel = wf_chspec_ctlchan(bi->chanspec); + result->channel = wf_channel2mhz(channel, + (channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + result->rssi = (int32) bi->RSSI; + result->rtt = 0; + result->rtt_sd = 0; + get_monotonic_boottime(&ts); + result->ts = (uint64) TIMESPEC_TO_US(ts); + result->beacon_period = dtoh16(bi->beacon_period); + result->capability = dtoh16(bi->capability); + result->ie_length = dtoh32(bi->ie_length); + memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN); + memcpy(result->ie_data, ((uint8 *)bi + bi->ie_offset), bi->ie_length); + *size = mem_needed; +exit: + return result; +} + +void * +dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size) +{ + dhd_epno_results_t *results = NULL; + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + struct dhd_pno_gscan_params *gscan_params; + uint32 count, mem_needed = 0, i; + uint8 ssid[DOT11_MAX_SSID_LEN + 1]; + struct ether_addr *bssid; + + *size = 0; + if (!_pno_state) + return NULL; + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + + if (event == WLC_E_PFN_SSID_EXT) { + wl_pfn_ssid_ext_result_t *evt_data; + evt_data = (wl_pfn_ssid_ext_result_t *) data; + + if (evt_data->version != PFN_SSID_EXT_VERSION) { + DHD_PNO(("ePNO event: Incorrect version %d %d\n", evt_data->version, + PFN_SSID_EXT_VERSION)); + return NULL; + } + count = evt_data->count; + mem_needed = sizeof(dhd_epno_results_t) * count; + results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); + if (!results) { + DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, + mem_needed)); + return NULL; + } + DHD_ERROR(("Rx'ed WLC_E_PFN_SSID_EXT event: %d results\n", count)); + for (i = 0; i < count; i++) { + results[i].rssi = evt_data->net[i].rssi; + results[i].channel = wf_channel2mhz(evt_data->net[i].channel, + (evt_data->net[i].channel <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + results[i].flags = evt_data->net[i].flags; + dhd_pno_idx_to_ssid(gscan_params, &results[i], + evt_data->net[i].index); + memcpy(ssid, results[i].ssid, results[i].ssid_len); + bssid = &results[i].bssid; + memcpy(bssid, &evt_data->net[i].bssid, ETHER_ADDR_LEN); + ssid[results[i].ssid_len] = '\0'; + DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " + "idx %d ch %d rssi %d flags %d\n", ssid, + bssid->octet[0], bssid->octet[1], + bssid->octet[2], bssid->octet[3], + bssid->octet[4], bssid->octet[5], + evt_data->net[i].index, results[i].channel, + results[i].rssi, results[i].flags)); + } + } else if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) { + wl_pfn_scanresults_t *pfn_result = (wl_pfn_scanresults_t *)data; + wl_pfn_net_info_t *net; + + if (pfn_result->version != PFN_SCANRESULT_VERSION) { + DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, + pfn_result->version, PFN_SCANRESULT_VERSION)); + return NULL; + } + count = pfn_result->count; + mem_needed = sizeof(dhd_epno_results_t) * count; + results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); + if (!results) { + DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, + mem_needed)); + return NULL; + } + for (i = 0; i < count; i++) { + net = &pfn_result->netinfo[i]; + results[i].rssi = net->RSSI; + results[i].channel = wf_channel2mhz(net->pfnsubnet.channel, + (net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + results[i].flags = (event == WLC_E_PFN_NET_FOUND) ? + WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST; + results[i].ssid_len = min(net->pfnsubnet.SSID_len, + (uint8)DOT11_MAX_SSID_LEN); + bssid = &results[i].bssid; + memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN); + memcpy(results[i].ssid, net->pfnsubnet.SSID, results[i].ssid_len); + memcpy(ssid, results[i].ssid, results[i].ssid_len); + ssid[results[i].ssid_len] = '\0'; + DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " + "ch %d rssi %d flags %d\n", ssid, + bssid->octet[0], bssid->octet[1], + bssid->octet[2], bssid->octet[3], + bssid->octet[4], bssid->octet[5], + results[i].channel, results[i].rssi, results[i].flags)); + } + } + *size = mem_needed; + return results; +} + +#ifdef ANQPO_SUPPORT +void * +dhd_pno_process_anqpo_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size) +{ + wl_bss_info_t *bi = (wl_bss_info_t *)data; + wifi_gscan_result_t *result = NULL; + wl_event_gas_t *gas_data; + uint8 channel; + uint32 mem_needed; + struct timespec ts; + + if ((bi->SSID_len > DOT11_MAX_SSID_LEN) || + (bi->ie_length > (*size - sizeof(wl_bss_info_t))) || + (bi->ie_offset < sizeof(wl_bss_info_t)) || + (bi->ie_offset > (sizeof(wl_bss_info_t) + bi->ie_length))) { + DHD_ERROR(("%s: tot:%d,SSID:%d,ie_len:%d,ie_off:%d\n", + __FUNCTION__, *size, bi->SSID_len, + bi->ie_length, bi->ie_offset)); + return NULL; + } + + gas_data = (wl_event_gas_t *)((uint8 *)data + bi->ie_offset + bi->ie_length); + if (gas_data->data_len > (*size - (bi->ie_offset + bi->ie_length))) { + DHD_ERROR(("%s: wrong gas_data_len:%d\n", + __FUNCTION__, gas_data->data_len)); + return NULL; + } + + if (event == WLC_E_PFN_NET_FOUND) { + mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi->ie_length + + OFFSETOF(wl_event_gas_t, data) + gas_data->data_len + + sizeof(int); + result = (wifi_gscan_result_t *) kmalloc(mem_needed, GFP_KERNEL); + if (result == NULL) { + DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, mem_needed)); + return NULL; + } + + memcpy(result->ssid, bi->SSID, bi->SSID_len); + result->ssid[bi->SSID_len] = '\0'; + channel = wf_chspec_ctlchan(bi->chanspec); + result->channel = wf_channel2mhz(channel, (channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + result->rssi = (int32) bi->RSSI; + result->rtt = 0; + result->rtt_sd = 0; + get_monotonic_boottime(&ts); + result->ts = (uint64) TIMESPEC_TO_US(ts); + result->beacon_period = dtoh16(bi->beacon_period); + result->capability = dtoh16(bi->capability); + result->ie_length = dtoh32(bi->ie_length); + memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN); + memcpy(result->ie_data, ((uint8 *)bi + bi->ie_offset), bi->ie_length); + /* append ANQP data to end of scan result */ + memcpy((uint8 *)result+OFFSETOF(wifi_gscan_result_t, ie_data)+bi->ie_length, + gas_data, OFFSETOF(wl_event_gas_t, data)+gas_data->data_len); + /* append network id to end of result */ + memcpy((uint8 *)result+mem_needed-sizeof(int), + (uint8 *)data+(*size)-sizeof(int), sizeof(int)); + *size = mem_needed; + } else { + DHD_ERROR(("%s unknown event: %d!!\n", __FUNCTION__, event)); + } + + return result; +} +#endif /* ANQPO_SUPPORT */ + +void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, + hotlist_type_t type) +{ + void *ptr = NULL; + dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + struct dhd_pno_gscan_params *gscan_params; + wl_pfn_scanresults_t *results = (wl_pfn_scanresults_t *)event_data; + wifi_gscan_result_t *hotlist_found_array; + wl_pfn_net_info_t *plnetinfo; + gscan_results_cache_t *gscan_hotlist_cache; + int malloc_size = 0, i, total = 0; + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + + if (!results->count) { + *send_evt_bytes = 0; + return ptr; + } + + malloc_size = sizeof(gscan_results_cache_t) + + ((results->count - 1) * sizeof(wifi_gscan_result_t)); + gscan_hotlist_cache = (gscan_results_cache_t *) kmalloc(malloc_size, GFP_KERNEL); + + if (!gscan_hotlist_cache) { + DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size)); + *send_evt_bytes = 0; + return ptr; + } + + if (type == HOTLIST_FOUND) { + gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found; + gscan_params->gscan_hotlist_found = gscan_hotlist_cache; + DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, results->count)); + } else { + gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost; + gscan_params->gscan_hotlist_lost = gscan_hotlist_cache; + DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, results->count)); + } + + gscan_hotlist_cache->tot_count = results->count; + gscan_hotlist_cache->tot_consumed = 0; + plnetinfo = results->netinfo; + + for (i = 0; i < results->count; i++, plnetinfo++) { + hotlist_found_array = &gscan_hotlist_cache->results[i]; + hotlist_found_array->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, + (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + hotlist_found_array->rssi = (int32) plnetinfo->RSSI; + /* Info not available & not expected */ + hotlist_found_array->beacon_period = 0; + hotlist_found_array->capability = 0; + hotlist_found_array->ie_length = 0; + + hotlist_found_array->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); + if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", + plnetinfo->pfnsubnet.SSID_len)); + plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + memcpy(hotlist_found_array->ssid, plnetinfo->pfnsubnet.SSID, + plnetinfo->pfnsubnet.SSID_len); + hotlist_found_array->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; + + memcpy(&hotlist_found_array->macaddr, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); + DHD_PNO(("\t%s %02x:%02x:%02x:%02x:%02x:%02x rssi %d\n", hotlist_found_array->ssid, + hotlist_found_array->macaddr.octet[0], + hotlist_found_array->macaddr.octet[1], + hotlist_found_array->macaddr.octet[2], + hotlist_found_array->macaddr.octet[3], + hotlist_found_array->macaddr.octet[4], + hotlist_found_array->macaddr.octet[5], + hotlist_found_array->rssi)); + } + + if (results->status == PFN_COMPLETE) { + ptr = (void *) gscan_hotlist_cache; + while (gscan_hotlist_cache) { + total += gscan_hotlist_cache->tot_count; + gscan_hotlist_cache = gscan_hotlist_cache->next; + } + *send_evt_bytes = total * sizeof(wifi_gscan_result_t); + } + + return ptr; +} +#endif /* GSCAN_SUPPORT */ + +int +dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) +{ + int err = BCME_OK; + uint status, event_type, flags, datalen; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + event_type = ntoh32(event->event_type); + flags = ntoh16(event->flags); + status = ntoh32(event->status); + datalen = ntoh32(event->datalen); + DHD_PNO(("%s enter : event_type :%d\n", __FUNCTION__, event_type)); + switch (event_type) { + case WLC_E_PFN_BSSID_NET_FOUND: + case WLC_E_PFN_BSSID_NET_LOST: + /* TODO : need to implement event logic using generic netlink */ + break; + case WLC_E_PFN_BEST_BATCHING: +#ifndef GSCAN_SUPPORT + { + struct dhd_pno_batch_params *params_batch; + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; + if (!waitqueue_active(&_pno_state->get_batch_done.wait)) { + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); + params_batch->get_batch.buf = NULL; + params_batch->get_batch.bufsize = 0; + params_batch->get_batch.reason = PNO_STATUS_EVENT; + schedule_work(&_pno_state->work); + } else + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING" + "will skip this event\n", __FUNCTION__)); + break; + } +#else + break; +#endif /* !GSCAN_SUPPORT */ + default: + DHD_ERROR(("unknown event : %d\n", event_type)); + } +exit: + return err; +} + +int dhd_pno_init(dhd_pub_t *dhd) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + char *buf = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + UNUSED_PARAMETER(_dhd_pno_suspend); + if (dhd->pno_state) + goto exit; + dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t)); + NULL_CHECK(dhd->pno_state, "failed to create dhd_pno_state", err); + memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t)); + /* need to check whether current firmware support batching and hotlist scan */ + _pno_state = PNO_GET_PNOSTATE(dhd); + _pno_state->wls_supported = TRUE; + _pno_state->dhd = dhd; + mutex_init(&_pno_state->pno_mutex); + INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler); + init_completion(&_pno_state->get_batch_done); + +#ifdef GSCAN_SUPPORT + init_waitqueue_head(&_pno_state->batch_get_wait); +#endif /* GSCAN_SUPPORT */ + buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + if (!buf) { + DHD_ERROR((":%s buf alloc err.\n", __FUNCTION__)); + return BCME_NOMEM; + } + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, buf, WLC_IOCTL_SMLEN, + FALSE); + if (err == BCME_UNSUPPORTED) { + _pno_state->wls_supported = FALSE; + DHD_INFO(("Current firmware doesn't support" + " Android Location Service\n")); + } +exit: + kfree(buf); + return err; +} +int dhd_pno_deinit(dhd_pub_t *dhd) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + NULL_CHECK(dhd, "dhd is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + NULL_CHECK(_pno_state, "pno_state is NULL", err); + /* may need to free legacy ssid_list */ + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + _params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + } + +#ifdef GSCAN_SUPPORT + if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + mutex_lock(&_pno_state->pno_mutex); + dhd_pno_reset_cfg_gscan(_params, _pno_state, GSCAN_FLUSH_ALL_CFG); + mutex_unlock(&_pno_state->pno_mutex); + } +#endif /* GSCAN_SUPPORT */ + + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + /* clear resource if the BATCH MODE is on */ + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); + } + cancel_work_sync(&_pno_state->work); + MFREE(dhd->osh, _pno_state, sizeof(dhd_pno_status_info_t)); + dhd->pno_state = NULL; + return err; +} +#endif /* PNO_SUPPORT */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h new file mode 100644 index 000000000000..cf7fa9fbdb4e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h @@ -0,0 +1,583 @@ +/* + * Header file of Broadcom Dongle Host Driver (DHD) + * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_pno.h 423669 2013-09-18 13:01:55Z $ + */ + +#ifndef __DHD_PNO_H__ +#define __DHD_PNO_H__ + +#if defined(PNO_SUPPORT) +#define PNO_TLV_PREFIX 'S' +#define PNO_TLV_VERSION '1' +#define PNO_TLV_SUBTYPE_LEGACY_PNO '2' +#define PNO_TLV_RESERVED '0' + +#define PNO_BATCHING_SET "SET" +#define PNO_BATCHING_GET "GET" +#define PNO_BATCHING_STOP "STOP" + +#define PNO_PARAMS_DELIMETER " " +#define PNO_PARAM_CHANNEL_DELIMETER "," +#define PNO_PARAM_VALUE_DELLIMETER '=' +#define PNO_PARAM_SCANFREQ "SCANFREQ" +#define PNO_PARAM_BESTN "BESTN" +#define PNO_PARAM_MSCAN "MSCAN" +#define PNO_PARAM_CHANNEL "CHANNEL" +#define PNO_PARAM_RTT "RTT" + +#define PNO_TLV_TYPE_SSID_IE 'S' +#define PNO_TLV_TYPE_TIME 'T' +#define PNO_TLV_FREQ_REPEAT 'R' +#define PNO_TLV_FREQ_EXPO_MAX 'M' + +#define MAXNUM_SSID_PER_ADD 16 +#define MAXNUM_PNO_PARAMS 2 +#define PNO_TLV_COMMON_LENGTH 1 +#define DEFAULT_BATCH_MSCAN 16 + +#define RESULTS_END_MARKER "----\n" +#define SCAN_END_MARKER "####\n" +#define AP_END_MARKER "====\n" + +#define PNO_RSSI_MARGIN_DBM 30 + +#ifdef GSCAN_SUPPORT + +#define GSCAN_MAX_CH_BUCKETS 8 +#define GSCAN_MAX_CHANNELS_IN_BUCKET 32 +#define GSCAN_MAX_AP_CACHE_PER_SCAN 32 +#define GSCAN_MAX_AP_CACHE 320 +#define GSCAN_BG_BAND_MASK (1 << 0) +#define GSCAN_A_BAND_MASK (1 << 1) +#define GSCAN_DFS_MASK (1 << 2) +#define GSCAN_ABG_BAND_MASK (GSCAN_A_BAND_MASK | GSCAN_BG_BAND_MASK) +#define GSCAN_BAND_MASK (GSCAN_ABG_BAND_MASK | GSCAN_DFS_MASK) + +#define GSCAN_FLUSH_HOTLIST_CFG (1 << 0) +#define GSCAN_FLUSH_SIGNIFICANT_CFG (1 << 1) +#define GSCAN_FLUSH_SCAN_CFG (1 << 2) +#define GSCAN_FLUSH_EPNO_CFG (1 << 3) +#define GSCAN_FLUSH_ALL_CFG (GSCAN_FLUSH_SCAN_CFG | \ + GSCAN_FLUSH_SIGNIFICANT_CFG | \ + GSCAN_FLUSH_HOTLIST_CFG | \ + GSCAN_FLUSH_EPNO_CFG) +#define DHD_EPNO_HIDDEN_SSID (1 << 0) +#define DHD_EPNO_A_BAND_TRIG (1 << 1) +#define DHD_EPNO_BG_BAND_TRIG (1 << 2) +#define DHD_EPNO_STRICT_MATCH (1 << 3) +#define DHD_PNO_USE_SSID (DHD_EPNO_HIDDEN_SSID | DHD_EPNO_STRICT_MATCH) + +/* Do not change GSCAN_BATCH_RETRIEVAL_COMPLETE */ +#define GSCAN_BATCH_RETRIEVAL_COMPLETE 0 +#define GSCAN_BATCH_RETRIEVAL_IN_PROGRESS 1 +#define GSCAN_BATCH_NO_THR_SET 101 +#define GSCAN_LOST_AP_WINDOW_DEFAULT 4 +#define GSCAN_MIN_BSSID_TIMEOUT 90 +#define GSCAN_BATCH_GET_MAX_WAIT 500 + +#define CHANNEL_BUCKET_EMPTY_INDEX 0xFF +#define GSCAN_RETRY_THRESHOLD 3 +#define MAX_EPNO_SSID_NUM 32 +#define GSCAN_ANQPO_MAX_HS_LIST_SIZE 16 +#define ANQPO_MAX_HS_NAI_REALM_SIZE 256 +#endif /* GSCAN_SUPPORT */ + +enum scan_status { + /* SCAN ABORT by other scan */ + PNO_STATUS_ABORT, + /* RTT is presence or not */ + PNO_STATUS_RTT_PRESENCE, + /* Disable PNO by Driver */ + PNO_STATUS_DISABLE, + /* NORMAL BATCHING GET */ + PNO_STATUS_NORMAL, + /* WLC_E_PFN_BEST_BATCHING */ + PNO_STATUS_EVENT, + PNO_STATUS_MAX +}; +#define PNO_STATUS_ABORT_MASK 0x0001 +#define PNO_STATUS_RTT_MASK 0x0002 +#define PNO_STATUS_DISABLE_MASK 0x0004 +#define PNO_STATUS_OOM_MASK 0x0010 + +enum index_mode { + INDEX_OF_LEGACY_PARAMS, + INDEX_OF_BATCH_PARAMS, + INDEX_OF_HOTLIST_PARAMS, + /* GSCAN includes hotlist scan and they do not run + * independent of each other + */ +#ifdef GSCAN_SUPPORT + INDEX_OF_GSCAN_PARAMS = INDEX_OF_HOTLIST_PARAMS, +#endif /* GSCAN_SUPPORT */ + INDEX_MODE_MAX +}; +enum dhd_pno_status { + DHD_PNO_DISABLED, + DHD_PNO_ENABLED, + DHD_PNO_SUSPEND +}; +typedef struct cmd_tlv { + char prefix; + char version; + char subtype; + char reserved; +} cmd_tlv_t; + +#ifdef GSCAN_SUPPORT +typedef enum { + WIFI_BAND_UNSPECIFIED, + WIFI_BAND_BG = 1, /* 2.4 GHz */ + WIFI_BAND_A = 2, /* 5 GHz without DFS */ + WIFI_BAND_A_DFS = 4, /* 5 GHz DFS only */ + WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ + WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ + WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ +} gscan_wifi_band_t; + +typedef enum { + HOTLIST_LOST, + HOTLIST_FOUND +} hotlist_type_t; + +typedef enum dhd_pno_gscan_cmd_cfg { + DHD_PNO_BATCH_SCAN_CFG_ID, + DHD_PNO_GEOFENCE_SCAN_CFG_ID, + DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, + DHD_PNO_SCAN_CFG_ID, + DHD_PNO_GET_CAPABILITIES, + DHD_PNO_GET_BATCH_RESULTS, + DHD_PNO_GET_CHANNEL_LIST, + DHD_PNO_GET_EPNO_SSID_ELEM, + DHD_PNO_EPNO_CFG_ID, + DHD_PNO_GET_AUTOJOIN_CAPABILITIES +} dhd_pno_gscan_cmd_cfg_t; + +typedef enum dhd_pno_mode { + /* Wi-Fi Legacy PNO Mode */ + DHD_PNO_NONE_MODE = 0, + DHD_PNO_LEGACY_MODE = (1 << (0)), + /* Wi-Fi Android BATCH SCAN Mode */ + DHD_PNO_BATCH_MODE = (1 << (1)), + /* Wi-Fi Android Hotlist SCAN Mode */ + DHD_PNO_HOTLIST_MODE = (1 << (2)), + /* Wi-Fi Google Android SCAN Mode */ + DHD_PNO_GSCAN_MODE = (1 << (3)) +} dhd_pno_mode_t; +#else +typedef enum dhd_pno_mode { + /* Wi-Fi Legacy PNO Mode */ + DHD_PNO_NONE_MODE = 0, + DHD_PNO_LEGACY_MODE = (1 << (0)), + /* Wi-Fi Android BATCH SCAN Mode */ + DHD_PNO_BATCH_MODE = (1 << (1)), + /* Wi-Fi Android Hotlist SCAN Mode */ + DHD_PNO_HOTLIST_MODE = (1 << (2)) +} dhd_pno_mode_t; +#endif /* GSCAN_SUPPORT */ +struct dhd_pno_ssid { + bool hidden; + int8 rssi_thresh; + uint8 dummy; + uint16 SSID_len; + uchar SSID[DOT11_MAX_SSID_LEN]; + struct list_head list; +}; +struct dhd_pno_bssid { + struct ether_addr macaddr; + /* Bit4: suppress_lost, Bit3: suppress_found */ + uint16 flags; + struct list_head list; +}; +typedef struct dhd_pno_bestnet_entry { + struct ether_addr BSSID; + uint8 SSID_len; + uint8 SSID[DOT11_MAX_SSID_LEN]; + int8 RSSI; + uint8 channel; + uint32 timestamp; + uint16 rtt0; /* distance_cm based on RTT */ + uint16 rtt1; /* distance_cm based on sample standard deviation */ + unsigned long recorded_time; + struct list_head list; +} dhd_pno_bestnet_entry_t; +#define BESTNET_ENTRY_SIZE (sizeof(dhd_pno_bestnet_entry_t)) + +typedef struct dhd_pno_bestnet_header { + struct dhd_pno_bestnet_header *next; + uint8 reason; + uint32 tot_cnt; + uint32 tot_size; + struct list_head entry_list; +} dhd_pno_best_header_t; +#define BEST_HEADER_SIZE (sizeof(dhd_pno_best_header_t)) + +typedef struct dhd_pno_scan_results { + dhd_pno_best_header_t *bestnetheader; + uint8 cnt_header; + struct list_head list; +} dhd_pno_scan_results_t; +#define SCAN_RESULTS_SIZE (sizeof(dhd_pno_scan_results_t)) + +struct dhd_pno_get_batch_info { + /* info related to get batch */ + char *buf; + bool batch_started; + uint32 tot_scan_cnt; + uint32 expired_tot_scan_cnt; + uint32 top_node_cnt; + uint32 bufsize; + uint32 bytes_written; + int reason; + struct list_head scan_results_list; + struct list_head expired_scan_results_list; +}; +struct dhd_pno_legacy_params { + uint16 scan_fr; + uint16 chan_list[WL_NUMCHANNELS]; + uint16 nchan; + int pno_repeat; + int pno_freq_expo_max; + int nssid; + struct list_head ssid_list; +}; +struct dhd_pno_batch_params { + int32 scan_fr; + uint8 bestn; + uint8 mscan; + uint8 band; + uint16 chan_list[WL_NUMCHANNELS]; + uint16 nchan; + uint16 rtt; + struct dhd_pno_get_batch_info get_batch; +}; +struct dhd_pno_hotlist_params { + uint8 band; + int32 scan_fr; + uint16 chan_list[WL_NUMCHANNELS]; + uint16 nchan; + uint16 nbssid; + struct list_head bssid_list; +}; + +#ifdef GSCAN_SUPPORT +#define DHD_PNO_REPORT_NO_BATCH (1 << 2) + +typedef struct dhd_pno_gscan_channel_bucket { + uint16 bucket_freq_multiple; + /* band = 1 All bg band channels, + * band = 2 All a band channels, + * band = 0 chan_list channels + */ + uint16 band; + uint8 report_flag; + uint8 num_channels; + uint16 repeat; + uint16 bucket_max_multiple; + uint16 chan_list[GSCAN_MAX_CHANNELS_IN_BUCKET]; +} dhd_pno_gscan_channel_bucket_t; + + +#define DHD_PNO_AUTH_CODE_OPEN 1 /* Open */ +#define DHD_PNO_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ +#define DHD_PNO_AUTH_CODE_EAPOL 4 /* any EAPOL */ + +#define DHD_EPNO_DEFAULT_INDEX 0xFFFFFFFF + +typedef struct dhd_epno_params { + uint8 ssid[DOT11_MAX_SSID_LEN]; + uint8 ssid_len; + int8 rssi_thresh; + uint8 flags; + uint8 auth; + /* index required only for visble ssid */ + uint32 index; + struct list_head list; +} dhd_epno_params_t; + +typedef struct dhd_epno_results { + uint8 ssid[DOT11_MAX_SSID_LEN]; + uint8 ssid_len; + int8 rssi; + uint16 channel; + uint16 flags; + struct ether_addr bssid; +} dhd_epno_results_t; + +struct dhd_pno_swc_evt_param { + uint16 results_rxed_so_far; + wl_pfn_significant_net_t *change_array; +}; + +typedef struct wifi_gscan_result { + uint64 ts; /* Time of discovery */ + char ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated */ + struct ether_addr macaddr; /* BSSID */ + uint32 channel; /* channel frequency in MHz */ + int32 rssi; /* in db */ + uint64 rtt; /* in nanoseconds */ + uint64 rtt_sd; /* standard deviation in rtt */ + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint32 ie_length; /* byte length of Information Elements */ + char ie_data[1]; /* IE data to follow */ +} wifi_gscan_result_t; + +typedef struct gscan_results_cache { + struct gscan_results_cache *next; + uint8 scan_id; + uint8 flag; + uint8 tot_count; + uint8 tot_consumed; + wifi_gscan_result_t results[1]; +} gscan_results_cache_t; + +#ifdef ANQPO_SUPPORT +typedef struct { + int id; + char realm[ANQPO_MAX_HS_NAI_REALM_SIZE]; + int64_t roamingConsortiumIds[ANQPO_MAX_PFN_HS]; + uint8 plmn[ANQPO_MCC_LENGTH]; +} wifi_passpoint_network; +#endif /* ANQPO_SUPPORT */ + +typedef struct dhd_pno_gscan_capabilities { + int max_scan_cache_size; + int max_scan_buckets; + int max_ap_cache_per_scan; + int max_rssi_sample_size; + int max_scan_reporting_threshold; + int max_hotlist_aps; + int max_significant_wifi_change_aps; + int max_epno_ssid_crc32; + int max_epno_hidden_ssid; + int max_white_list_ssid; +} dhd_pno_gscan_capabilities_t; + +struct dhd_pno_gscan_params { + int32 scan_fr; + uint8 bestn; + uint8 mscan; + uint8 buffer_threshold; + uint8 swc_nbssid_threshold; + uint8 swc_rssi_window_size; + uint8 lost_ap_window; + uint8 nchannel_buckets; + uint8 reason; + uint8 get_batch_flag; + uint8 send_all_results_flag; + uint16 max_ch_bucket_freq; + gscan_results_cache_t *gscan_batch_cache; + gscan_results_cache_t *gscan_hotlist_found; + gscan_results_cache_t *gscan_hotlist_lost; + uint16 nbssid_significant_change; + uint16 nbssid_hotlist; + uint16 num_epno_ssid; + uint8 num_visible_epno_ssid; + /* To keep track of visble ssid index + * across multiple FW configs i.e. config + * w/o clear in between + */ + uint8 ssid_ext_last_used_index; + struct dhd_pno_swc_evt_param param_significant; + struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; + struct list_head hotlist_bssid_list; + struct list_head significant_bssid_list; + struct list_head epno_ssid_list; + uint32 scan_id; +}; + +typedef struct gscan_scan_params { + int32 scan_fr; + uint16 nchannel_buckets; + struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; +} gscan_scan_params_t; + +typedef struct gscan_batch_params { + uint8 bestn; + uint8 mscan; + uint8 buffer_threshold; +} gscan_batch_params_t; + +struct bssid_t { + struct ether_addr macaddr; + int16 rssi_reporting_threshold; /* 0 -> no reporting threshold */ +}; + +typedef struct gscan_hotlist_scan_params { + uint16 lost_ap_window; /* number of scans to declare LOST */ + uint16 nbssid; /* number of bssids */ + struct bssid_t bssid[1]; /* n bssids to follow */ +} gscan_hotlist_scan_params_t; + +/* SWC (Significant WiFi Change) params */ +typedef struct gscan_swc_params { + /* Rssi averaging window size */ + uint8 rssi_window; + /* Number of scans that the AP has to be absent before + * being declared LOST + */ + uint8 lost_ap_window; + /* if x Aps have a significant change generate an event. */ + uint8 swc_threshold; + uint8 nbssid; + wl_pfn_significant_bssid_t bssid_elem_list[1]; +} gscan_swc_params_t; + +typedef struct dhd_pno_significant_bssid { + struct ether_addr BSSID; + int8 rssi_low_threshold; + int8 rssi_high_threshold; + struct list_head list; +} dhd_pno_significant_bssid_t; +#endif /* GSCAN_SUPPORT */ +typedef union dhd_pno_params { + struct dhd_pno_legacy_params params_legacy; + struct dhd_pno_batch_params params_batch; + struct dhd_pno_hotlist_params params_hotlist; +#ifdef GSCAN_SUPPORT + struct dhd_pno_gscan_params params_gscan; +#endif /* GSCAN_SUPPORT */ +} dhd_pno_params_t; +typedef struct dhd_pno_status_info { + dhd_pub_t *dhd; + struct work_struct work; + struct mutex pno_mutex; +#ifdef GSCAN_SUPPORT + wait_queue_head_t batch_get_wait; +#endif /* GSCAN_SUPPORT */ + struct completion get_batch_done; + bool wls_supported; /* wifi location service supported or not */ + enum dhd_pno_status pno_status; + enum dhd_pno_mode pno_mode; + dhd_pno_params_t pno_params_arr[INDEX_MODE_MAX]; + struct list_head head_list; +} dhd_pno_status_info_t; + +/* wrapper functions */ +extern int +dhd_dev_pno_enable(struct net_device *dev, int enable); + +extern int +dhd_dev_pno_stop_for_ssid(struct net_device *dev); + +extern int +dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); + +extern int +dhd_dev_pno_set_for_batch(struct net_device *dev, + struct dhd_pno_batch_params *batch_params); + +extern int +dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize); + +extern int +dhd_dev_pno_stop_for_batch(struct net_device *dev); + +extern int +dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params); +extern bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev); +#ifdef GSCAN_SUPPORT +extern int +dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, + void *buf, uint8 flush); +extern void * +dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, void *info, + uint32 *len); +int dhd_dev_pno_lock_access_batch_results(struct net_device *dev); +void dhd_dev_pno_unlock_access_batch_results(struct net_device *dev); +extern int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush); +extern int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time); +extern void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, + int *send_evt_bytes); +int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); +extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, + const void *data, int *send_evt_bytes, hotlist_type_t type); +void * dhd_dev_process_full_gscan_result(struct net_device *dev, + const void *data, int *send_evt_bytes); +extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); +extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); +extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); +extern void * dhd_dev_process_epno_result(struct net_device *dev, + const void *data, uint32 event, int *send_evt_bytes); +#ifdef ANQPO_SUPPORT +extern void * dhd_dev_process_anqpo_result(struct net_device *dev, + const void *data, uint32 event, int *send_evt_bytes); +#endif /* ANQPO_SUPPORT */ +#endif /* GSCAN_SUPPORT */ +/* dhd pno fuctions */ +extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd); +extern int dhd_pno_enable(dhd_pub_t *dhd, int enable); +extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); + +extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params); + +extern int dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason); + + +extern int dhd_pno_stop_for_batch(dhd_pub_t *dhd); + +extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params); + +extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd); + +extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); +extern int dhd_pno_init(dhd_pub_t *dhd); +extern int dhd_pno_deinit(dhd_pub_t *dhd); +extern bool dhd_is_pno_supported(dhd_pub_t *dhd); +extern int dhd_pno_set_mac_oui(dhd_pub_t *dhd, uint8 *oui); +extern bool dhd_is_legacy_pno_enabled(dhd_pub_t *dhd); +#ifdef GSCAN_SUPPORT +extern int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, + void *buf, uint8 flush); +extern void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *info, + uint32 *len); +extern int dhd_pno_lock_batch_results(dhd_pub_t *dhd); +extern void dhd_pno_unlock_batch_results(dhd_pub_t *dhd); +extern int dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush); +extern int dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag); +extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *buf); +extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); +extern void *dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes); +extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, + int *send_evt_bytes, hotlist_type_t type); +extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, + int *send_evt_bytes); +extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); +extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); +extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); +extern void * dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, + uint32 event, int *size); +#ifdef ANQPO_SUPPORT +extern void * dhd_pno_process_anqpo_result(dhd_pub_t *dhd, + const void *data, uint32 event, int *size); +#endif /* ANQPO_SUPPORT */ +#endif /* GSCAN_SUPPORT */ +#endif + +#endif /* __DHD_PNO_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h new file mode 100644 index 000000000000..6b95755938bb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h @@ -0,0 +1,115 @@ +/* + * Header file describing the internal (inter-module) DHD interfaces. + * + * Provides type definitions and function prototypes used to link the + * DHD OS, bus, and protocol modules. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_proto.h 455951 2014-02-17 10:52:22Z $ + */ + +#ifndef _dhd_proto_h_ +#define _dhd_proto_h_ + +#include +#include + +#ifndef IOCTL_RESP_TIMEOUT +#define IOCTL_RESP_TIMEOUT 2000 /* In milli second default value for Production FW */ +#endif /* IOCTL_RESP_TIMEOUT */ + +#ifndef MFG_IOCTL_RESP_TIMEOUT +#define MFG_IOCTL_RESP_TIMEOUT 20000 /* In milli second default value for MFG FW */ +#endif /* MFG_IOCTL_RESP_TIMEOUT */ + +/* + * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) + */ + +/* Linkage, sets prot link and updates hdrlen in pub */ +extern int dhd_prot_attach(dhd_pub_t *dhdp); + +/* Unlink, frees allocated protocol memory (including dhd_prot) */ +extern void dhd_prot_detach(dhd_pub_t *dhdp); + +/* Initialize protocol: sync w/dongle state. + * Sets dongle media info (iswl, drv_version, mac address). + */ +extern int dhd_prot_init(dhd_pub_t *dhdp); + +/* Stop protocol: sync w/dongle state. */ +extern void dhd_prot_stop(dhd_pub_t *dhdp); + +/* Add any protocol-specific data header. + * Caller must reserve prot_hdrlen prepend space. + */ +extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); + +/* Remove any protocol-specific data header. */ +extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); + +/* Use protocol to issue ioctl to dongle */ +extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); + +/* Handles a protocol control response asynchronously */ +extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); + +/* Check for and handle local prot-specific iovar commands */ +extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set); + +/* Add prot dump output to a buffer */ +extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); + +/* Update local copy of dongle statistics */ +extern void dhd_prot_dstats(dhd_pub_t *dhdp); + +extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); + +extern int dhd_preinit_ioctls(dhd_pub_t *dhd); + +extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, + uint reorder_info_len, void **pkt, uint32 *free_buf_count); + +#ifdef BCMPCIE +extern int dhd_prot_process_msgbuf(dhd_pub_t *dhd); +extern int dhd_prot_process_ctrlbuf(dhd_pub_t * dhd); +extern bool dhd_prot_dtohsplit(dhd_pub_t * dhd); +extern int dhd_post_dummy_msg(dhd_pub_t *dhd); +extern int dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len); +extern void dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 offset); +extern int dhd_prot_txdata(dhd_pub_t *dhd, void *p, uint8 ifidx); +extern int dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd, uint len, uint srcdelay, uint destdelay); +#endif + +/******************************** + * For version-string expansion * + */ +#if defined(BDC) +#define DHD_PROTOCOL "bdc" +#elif defined(CDC) +#define DHD_PROTOCOL "cdc" +#else +#define DHD_PROTOCOL "unknown" +#endif /* proto */ + +#endif /* _dhd_proto_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c new file mode 100644 index 000000000000..2614ceb7dae4 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c @@ -0,0 +1,1906 @@ +/* + * Header file of Broadcom Dongle Host Driver (DHD) + * Copyright (C) 1999-2014, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_rtt.c 423669 2014-07-01 13:01:55Z $ + */ +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#define GET_RTTSTATE(dhd) ((rtt_status_info_t *)dhd->rtt_state) +static DEFINE_SPINLOCK(noti_list_lock); +#define NULL_CHECK(p, s, err) \ + do { \ + if (!(p)) { \ + printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ + err = BCME_ERROR; \ + return err; \ + } \ + } while (0) + +#define RTT_IS_ENABLED(rtt_status) (rtt_status->status == RTT_ENABLED) +#define RTT_IS_STOPPED(rtt_status) (rtt_status->status == RTT_STOPPED) +#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ + (ts).tv_nsec / NSEC_PER_USEC) + +#define FTM_IOC_BUFSZ 2048 /* ioc buffsize for our module (> BCM_XTLV_HDR_SIZE) */ +#define FTM_AVAIL_MAX_SLOTS 32 +#define FTM_MAX_CONFIGS 10 +#define FTM_MAX_PARAMS 10 +#define FTM_DEFAULT_SESSION 1 +#define FTM_BURST_TIMEOUT_UNIT 250 /* 250 ns */ +#define FTM_INVALID -1 +#define FTM_DEFAULT_CNT_20M 12 +#define FTM_DEFAULT_CNT_40M 10 +#define FTM_DEFAULT_CNT_80M 5 + +/* convenience macros */ +#define FTM_TU2MICRO(_tu) ((uint64)(_tu) << 10) +#define FTM_MICRO2TU(_tu) ((uint64)(_tu) >> 10) +#define FTM_TU2MILLI(_tu) ((uint32)FTM_TU2MICRO(_tu) / 1000) +#define FTM_MICRO2MILLI(_x) ((uint32)(_x) / 1000) +#define FTM_MICRO2SEC(_x) ((uint32)(_x) / 1000000) +#define FTM_INTVL2NSEC(_intvl) ((uint32)ftm_intvl2nsec(_intvl)) +#define FTM_INTVL2USEC(_intvl) ((uint32)ftm_intvl2usec(_intvl)) +#define FTM_INTVL2MSEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000) +#define FTM_INTVL2SEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000000) +#define FTM_USECIN100MILLI(_usec) ((_usec) / 100000) + +/* broadcom specific set to have more accurate data */ +#define ENABLE_VHT_ACK + +struct rtt_noti_callback { + struct list_head list; + void *ctx; + dhd_rtt_compl_noti_fn noti_fn; +}; + +typedef struct rtt_status_info { + dhd_pub_t *dhd; + int8 status; /* current status for the current entry */ + int8 txchain; /* current device tx chain */ + int8 mpc; /* indicate we change mpc mode */ + int8 cur_idx; /* current entry to do RTT */ + struct capability { + int32 proto :8; + int32 feature :8; + int32 preamble :8; + int32 bw :8; + } rtt_capa; /* rtt capability */ + struct mutex rtt_mutex; + rtt_config_params_t rtt_config; + struct work_struct work; + struct list_head noti_fn_list; + struct list_head rtt_results_cache; /* store results for RTT */ +} rtt_status_info_t; + +/* bitmask indicating which command groups; */ +typedef enum { + FTM_SUBCMD_FLAG_METHOD = 0x01, /* FTM method command */ + FTM_SUBCMD_FLAG_SESSION = 0x02, /* FTM session command */ + FTM_SUBCMD_FLAG_ALL = FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION +} ftm_subcmd_flag_t; + +/* proxd ftm config-category definition */ +typedef enum { + FTM_CONFIG_CAT_GENERAL = 1, /* generial configuration */ + FTM_CONFIG_CAT_OPTIONS = 2, /* 'config options' */ + FTM_CONFIG_CAT_AVAIL = 3, /* 'config avail' */ +} ftm_config_category_t; + + +typedef struct ftm_subcmd_info { + int16 version; /* FTM version (optional) */ + char *name; /* cmd-name string as cmdline input */ + wl_proxd_cmd_t cmdid; /* cmd-id */ + bcm_xtlv_unpack_cbfn_t *handler; /* cmd response handler (optional) */ + ftm_subcmd_flag_t cmdflag; /* CMD flag (optional) */ +} ftm_subcmd_info_t; + + +typedef struct ftm_config_options_info { + uint32 flags; /* wl_proxd_flags_t/wl_proxd_session_flags_t */ + bool enable; +} ftm_config_options_info_t; + +typedef struct ftm_config_param_info { + uint16 tlvid; /* mapping TLV id for the item */ + union { + uint32 chanspec; + struct ether_addr mac_addr; + wl_proxd_intvl_t data_intvl; + uint32 data32; + uint16 data16; + uint8 data8; + }; +} ftm_config_param_info_t; + +/* +* definition for id-string mapping. +* This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string +* for debug-display or cmd-log-display +*/ +typedef struct ftm_strmap_entry { + int32 id; + char *text; +} ftm_strmap_entry_t; + + +typedef struct ftm_status_map_host_entry { + wl_proxd_status_t proxd_status; + rtt_reason_t rtt_reason; +} ftm_status_map_host_entry_t; + +static int +dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len); + +static wifi_rate_t +dhd_rtt_convert_rate_to_host(uint32 ratespec); + +static int +dhd_rtt_start(dhd_pub_t *dhd); + +/* ftm status mapping to host status */ +static const ftm_status_map_host_entry_t ftm_status_map_info[] = { + {WL_PROXD_E_INCOMPLETE, RTT_REASON_FAILURE}, + {WL_PROXD_E_OVERRIDDEN, RTT_REASON_FAILURE}, + {WL_PROXD_E_ASAP_FAILED, RTT_REASON_FAILURE}, + {WL_PROXD_E_NOTSTARTED, RTT_REASON_FAIL_NOT_SCHEDULED_YET}, + {WL_PROXD_E_INVALIDAVB, RTT_REASON_FAIL_INVALID_TS}, + {WL_PROXD_E_INCAPABLE, RTT_REASON_FAIL_NO_CAPABILITY}, + {WL_PROXD_E_MISMATCH, RTT_REASON_FAILURE}, + {WL_PROXD_E_DUP_SESSION, RTT_REASON_FAILURE}, + {WL_PROXD_E_REMOTE_FAIL, RTT_REASON_FAILURE}, + {WL_PROXD_E_REMOTE_INCAPABLE, RTT_REASON_FAILURE}, + {WL_PROXD_E_SCHED_FAIL, RTT_REASON_FAIL_SCHEDULE}, + {WL_PROXD_E_PROTO, RTT_REASON_FAIL_PROTOCOL}, + {WL_PROXD_E_EXPIRED, RTT_REASON_FAILURE}, + {WL_PROXD_E_TIMEOUT, RTT_REASON_FAIL_TM_TIMEOUT}, + {WL_PROXD_E_NOACK, RTT_REASON_FAIL_NO_RSP}, + {WL_PROXD_E_DEFERRED, RTT_REASON_FAILURE}, + {WL_PROXD_E_INVALID_SID, RTT_REASON_FAILURE}, + {WL_PROXD_E_REMOTE_CANCEL, RTT_REASON_FAILURE}, + {WL_PROXD_E_CANCELED, RTT_REASON_ABORTED}, + {WL_PROXD_E_INVALID_SESSION, RTT_REASON_FAILURE}, + {WL_PROXD_E_BAD_STATE, RTT_REASON_FAILURE}, + {WL_PROXD_E_ERROR, RTT_REASON_FAILURE}, + {WL_PROXD_E_OK, RTT_REASON_SUCCESS} +}; + +/* ftm tlv-id mapping */ +static const ftm_strmap_entry_t ftm_tlvid_loginfo[] = { + /* { WL_PROXD_TLV_ID_xxx, "text for WL_PROXD_TLV_ID_xxx" }, */ + { WL_PROXD_TLV_ID_NONE, "none" }, + { WL_PROXD_TLV_ID_METHOD, "method" }, + { WL_PROXD_TLV_ID_FLAGS, "flags" }, + { WL_PROXD_TLV_ID_CHANSPEC, "chanspec" }, + { WL_PROXD_TLV_ID_TX_POWER, "tx power" }, + { WL_PROXD_TLV_ID_RATESPEC, "ratespec" }, + { WL_PROXD_TLV_ID_BURST_DURATION, "burst duration" }, + { WL_PROXD_TLV_ID_BURST_PERIOD, "burst period" }, + { WL_PROXD_TLV_ID_BURST_FTM_SEP, "burst ftm sep" }, + { WL_PROXD_TLV_ID_BURST_NUM_FTM, "burst num ftm" }, + { WL_PROXD_TLV_ID_NUM_BURST, "num burst" }, + { WL_PROXD_TLV_ID_FTM_RETRIES, "ftm retries" }, + { WL_PROXD_TLV_ID_BSS_INDEX, "BSS index" }, + { WL_PROXD_TLV_ID_BSSID, "bssid" }, + { WL_PROXD_TLV_ID_INIT_DELAY, "burst init delay" }, + { WL_PROXD_TLV_ID_BURST_TIMEOUT, "burst timeout" }, + { WL_PROXD_TLV_ID_EVENT_MASK, "event mask" }, + { WL_PROXD_TLV_ID_FLAGS_MASK, "flags mask" }, + { WL_PROXD_TLV_ID_PEER_MAC, "peer addr" }, + { WL_PROXD_TLV_ID_FTM_REQ, "ftm req" }, + { WL_PROXD_TLV_ID_LCI_REQ, "lci req" }, + { WL_PROXD_TLV_ID_LCI, "lci" }, + { WL_PROXD_TLV_ID_CIVIC_REQ, "civic req" }, + { WL_PROXD_TLV_ID_CIVIC, "civic" }, + { WL_PROXD_TLV_ID_AVAIL, "availability" }, + { WL_PROXD_TLV_ID_SESSION_FLAGS, "session flags" }, + { WL_PROXD_TLV_ID_SESSION_FLAGS_MASK, "session flags mask" }, + { WL_PROXD_TLV_ID_RX_MAX_BURST, "rx max bursts" }, + { WL_PROXD_TLV_ID_RANGING_INFO, "ranging info" }, + { WL_PROXD_TLV_ID_RANGING_FLAGS, "ranging flags" }, + { WL_PROXD_TLV_ID_RANGING_FLAGS_MASK, "ranging flags mask" }, + /* output - 512 + x */ + { WL_PROXD_TLV_ID_STATUS, "status" }, + { WL_PROXD_TLV_ID_COUNTERS, "counters" }, + { WL_PROXD_TLV_ID_INFO, "info" }, + { WL_PROXD_TLV_ID_RTT_RESULT, "rtt result" }, + { WL_PROXD_TLV_ID_AOA_RESULT, "aoa result" }, + { WL_PROXD_TLV_ID_SESSION_INFO, "session info" }, + { WL_PROXD_TLV_ID_SESSION_STATUS, "session status" }, + { WL_PROXD_TLV_ID_SESSION_ID_LIST, "session ids" }, + /* debug tlvs can be added starting 1024 */ + { WL_PROXD_TLV_ID_DEBUG_MASK, "debug mask" }, + { WL_PROXD_TLV_ID_COLLECT, "collect" }, + { WL_PROXD_TLV_ID_STRBUF, "result" } +}; + +static const ftm_strmap_entry_t ftm_event_type_loginfo[] = { + /* wl_proxd_event_type_t, text-string */ + { WL_PROXD_EVENT_NONE, "none" }, + { WL_PROXD_EVENT_SESSION_CREATE, "session create" }, + { WL_PROXD_EVENT_SESSION_START, "session start" }, + { WL_PROXD_EVENT_FTM_REQ, "FTM req" }, + { WL_PROXD_EVENT_BURST_START, "burst start" }, + { WL_PROXD_EVENT_BURST_END, "burst end" }, + { WL_PROXD_EVENT_SESSION_END, "session end" }, + { WL_PROXD_EVENT_SESSION_RESTART, "session restart" }, + { WL_PROXD_EVENT_BURST_RESCHED, "burst rescheduled" }, + { WL_PROXD_EVENT_SESSION_DESTROY, "session destroy" }, + { WL_PROXD_EVENT_RANGE_REQ, "range request" }, + { WL_PROXD_EVENT_FTM_FRAME, "FTM frame" }, + { WL_PROXD_EVENT_DELAY, "delay" }, + { WL_PROXD_EVENT_VS_INITIATOR_RPT, "initiator-report " }, /* rx initiator-rpt */ + { WL_PROXD_EVENT_RANGING, "ranging " }, +}; + +/* +* session-state --> text string mapping +*/ +static const ftm_strmap_entry_t ftm_session_state_value_loginfo[] = { + /* wl_proxd_session_state_t, text string */ + { WL_PROXD_SESSION_STATE_CREATED, "created" }, + { WL_PROXD_SESSION_STATE_CONFIGURED, "configured" }, + { WL_PROXD_SESSION_STATE_STARTED, "started" }, + { WL_PROXD_SESSION_STATE_DELAY, "delay" }, + { WL_PROXD_SESSION_STATE_USER_WAIT, "user-wait" }, + { WL_PROXD_SESSION_STATE_SCHED_WAIT, "sched-wait" }, + { WL_PROXD_SESSION_STATE_BURST, "burst" }, + { WL_PROXD_SESSION_STATE_STOPPING, "stopping" }, + { WL_PROXD_SESSION_STATE_ENDED, "ended" }, + { WL_PROXD_SESSION_STATE_DESTROYING, "destroying" }, + { WL_PROXD_SESSION_STATE_NONE, "none" } +}; + +/* +* ranging-state --> text string mapping +*/ +static const ftm_strmap_entry_t ftm_ranging_state_value_loginfo [] = { + /* wl_proxd_ranging_state_t, text string */ + { WL_PROXD_RANGING_STATE_NONE, "none" }, + { WL_PROXD_RANGING_STATE_NOTSTARTED, "nonstarted" }, + { WL_PROXD_RANGING_STATE_INPROGRESS, "inprogress" }, + { WL_PROXD_RANGING_STATE_DONE, "done" }, +}; + +/* +* status --> text string mapping +*/ +static const ftm_strmap_entry_t ftm_status_value_loginfo[] = { + /* wl_proxd_status_t, text-string */ + { WL_PROXD_E_OVERRIDDEN, "overridden" }, + { WL_PROXD_E_ASAP_FAILED, "ASAP failed" }, + { WL_PROXD_E_NOTSTARTED, "not started" }, + { WL_PROXD_E_INVALIDAVB, "invalid AVB" }, + { WL_PROXD_E_INCAPABLE, "incapable" }, + { WL_PROXD_E_MISMATCH, "mismatch"}, + { WL_PROXD_E_DUP_SESSION, "dup session" }, + { WL_PROXD_E_REMOTE_FAIL, "remote fail" }, + { WL_PROXD_E_REMOTE_INCAPABLE, "remote incapable" }, + { WL_PROXD_E_SCHED_FAIL, "sched failure" }, + { WL_PROXD_E_PROTO, "protocol error" }, + { WL_PROXD_E_EXPIRED, "expired" }, + { WL_PROXD_E_TIMEOUT, "timeout" }, + { WL_PROXD_E_NOACK, "no ack" }, + { WL_PROXD_E_DEFERRED, "deferred" }, + { WL_PROXD_E_INVALID_SID, "invalid session id" }, + { WL_PROXD_E_REMOTE_CANCEL, "remote cancel" }, + { WL_PROXD_E_CANCELED, "canceled" }, + { WL_PROXD_E_INVALID_SESSION, "invalid session" }, + { WL_PROXD_E_BAD_STATE, "bad state" }, + { WL_PROXD_E_ERROR, "error" }, + { WL_PROXD_E_OK, "OK" } +}; + +/* +* time interval unit --> text string mapping +*/ +static const ftm_strmap_entry_t ftm_tmu_value_loginfo[] = { + /* wl_proxd_tmu_t, text-string */ + { WL_PROXD_TMU_TU, "TU" }, + { WL_PROXD_TMU_SEC, "sec" }, + { WL_PROXD_TMU_MILLI_SEC, "ms" }, + { WL_PROXD_TMU_MICRO_SEC, "us" }, + { WL_PROXD_TMU_NANO_SEC, "ns" }, + { WL_PROXD_TMU_PICO_SEC, "ps" } +}; + +#define RSPEC_BW(rspec) ((rspec) & WL_RSPEC_BW_MASK) +#define RSPEC_IS20MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_20MHZ) +#define RSPEC_IS40MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_40MHZ) +#define RSPEC_IS80MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_80MHZ) +#define RSPEC_IS160MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_160MHZ) + +#define IS_MCS(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) != WL_RSPEC_ENCODE_RATE) +#define IS_STBC(rspec) (((((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) || \ + (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)) && \ + (((rspec) & WL_RSPEC_STBC) == WL_RSPEC_STBC)) +#define RSPEC_ISSGI(rspec) (((rspec) & WL_RSPEC_SGI) != 0) +#define RSPEC_ISLDPC(rspec) (((rspec) & WL_RSPEC_LDPC) != 0) +#define RSPEC_ISSTBC(rspec) (((rspec) & WL_RSPEC_STBC) != 0) +#define RSPEC_ISTXBF(rspec) (((rspec) & WL_RSPEC_TXBF) != 0) +#define RSPEC_ISVHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) +#define RSPEC_ISHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) +#define RSPEC_ISLEGACY(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) +#define RSPEC2RATE(rspec) (RSPEC_ISLEGACY(rspec) ? \ + ((rspec) & RSPEC_RATE_MASK) : rate_rspec2rate(rspec)) +/* return rate in unit of 500Kbps -- for internal use in wlc_rate_sel.c */ +#define RSPEC2KBPS(rspec) rate_rspec2rate(rspec) + +struct ieee_80211_mcs_rate_info { + uint8 constellation_bits; + uint8 coding_q; + uint8 coding_d; +}; + +static const struct ieee_80211_mcs_rate_info wl_mcs_info[] = { + { 1, 1, 2 }, /* MCS 0: MOD: BPSK, CR 1/2 */ + { 2, 1, 2 }, /* MCS 1: MOD: QPSK, CR 1/2 */ + { 2, 3, 4 }, /* MCS 2: MOD: QPSK, CR 3/4 */ + { 4, 1, 2 }, /* MCS 3: MOD: 16QAM, CR 1/2 */ + { 4, 3, 4 }, /* MCS 4: MOD: 16QAM, CR 3/4 */ + { 6, 2, 3 }, /* MCS 5: MOD: 64QAM, CR 2/3 */ + { 6, 3, 4 }, /* MCS 6: MOD: 64QAM, CR 3/4 */ + { 6, 5, 6 }, /* MCS 7: MOD: 64QAM, CR 5/6 */ + { 8, 3, 4 }, /* MCS 8: MOD: 256QAM, CR 3/4 */ + { 8, 5, 6 } /* MCS 9: MOD: 256QAM, CR 5/6 */ +}; + +/** + * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination. + * 'mcs' : a *single* spatial stream MCS (11n or 11ac) + */ +uint +rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) +{ + const int ksps = 250; /* kilo symbols per sec, 4 us sym */ + const int Nsd_20MHz = 52; + const int Nsd_40MHz = 108; + const int Nsd_80MHz = 234; + const int Nsd_160MHz = 468; + uint rate; + + if (mcs == 32) { + /* just return fixed values for mcs32 instead of trying to parametrize */ + rate = (sgi == 0) ? 6000 : 6778; + } else if (mcs <= 9) { + /* This calculation works for 11n HT and 11ac VHT if the HT mcs values + * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. + * That is, HT MCS 23 is a base MCS = 7, Nss = 3 + */ + + /* find the number of complex numbers per symbol */ + if (RSPEC_IS20MHZ(bw)) { + rate = Nsd_20MHz; + } else if (RSPEC_IS40MHZ(bw)) { + rate = Nsd_40MHz; + } else if (bw == WL_RSPEC_BW_80MHZ) { + rate = Nsd_80MHz; + } else if (bw == WL_RSPEC_BW_160MHZ) { + rate = Nsd_160MHz; + } else { + rate = 0; + } + + /* multiply by bits per number from the constellation in use */ + rate = rate * wl_mcs_info[mcs].constellation_bits; + + /* adjust for the number of spatial streams */ + rate = rate * nss; + + /* adjust for the coding rate given as a quotient and divisor */ + rate = (rate * wl_mcs_info[mcs].coding_q) / wl_mcs_info[mcs].coding_d; + + /* multiply by Kilo symbols per sec to get Kbps */ + rate = rate * ksps; + + /* adjust the symbols per sec for SGI + * symbol duration is 4 us without SGI, and 3.6 us with SGI, + * so ratio is 10 / 9 + */ + if (sgi) { + /* add 4 for rounding of division by 9 */ + rate = ((rate * 10) + 4) / 9; + } + } else { + rate = 0; + } + + return rate; +} /* wlc_rate_mcs2rate */ + +/** take a well formed ratespec_t arg and return phy rate in [Kbps] units */ +int +rate_rspec2rate(uint32 rspec) +{ + int rate = -1; + + if (RSPEC_ISLEGACY(rspec)) { + rate = 500 * (rspec & WL_RSPEC_RATE_MASK); + } else if (RSPEC_ISHT(rspec)) { + uint mcs = (rspec & WL_RSPEC_RATE_MASK); + + if (mcs == 32) { + rate = rate_mcs2rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec)); + } else { + uint nss = 1 + (mcs / 8); + mcs = mcs % 8; + rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); + } + } else if (RSPEC_ISVHT(rspec)) { + uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK); + uint nss = (rspec & WL_RSPEC_VHT_MCS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; + + ASSERT(mcs <= 9); + ASSERT(nss <= 8); + + rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); + } else { + ASSERT(0); + } + + return (rate == 0) ? -1 : rate; +} + +char resp_buf[WLC_IOCTL_SMLEN]; + +static uint64 +ftm_intvl2nsec(const wl_proxd_intvl_t *intvl) +{ + uint64 ret; + ret = intvl->intvl; + switch (intvl->tmu) { + case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret) * 1000; break; + case WL_PROXD_TMU_SEC: ret *= 1000000000; break; + case WL_PROXD_TMU_MILLI_SEC: ret *= 1000000; break; + case WL_PROXD_TMU_MICRO_SEC: ret *= 1000; break; + case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000; break; + case WL_PROXD_TMU_NANO_SEC: /* fall through */ + default: break; + } + return ret; +} +uint64 +ftm_intvl2usec(const wl_proxd_intvl_t *intvl) +{ + uint64 ret; + ret = intvl->intvl; + switch (intvl->tmu) { + case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret); break; + case WL_PROXD_TMU_SEC: ret *= 1000000; break; + case WL_PROXD_TMU_NANO_SEC: ret = intvl->intvl / 1000; break; + case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000000; break; + case WL_PROXD_TMU_MILLI_SEC: ret *= 1000; break; + case WL_PROXD_TMU_MICRO_SEC: /* fall through */ + default: break; + } + return ret; +} + +/* +* lookup 'id' (as a key) from a fw status to host map table +* if found, return the corresponding reason code +*/ + +static rtt_reason_t +ftm_get_statusmap_info(wl_proxd_status_t id, const ftm_status_map_host_entry_t *p_table, + uint32 num_entries) +{ + int i; + const ftm_status_map_host_entry_t *p_entry; + /* scan thru the table till end */ + p_entry = p_table; + for (i = 0; i < (int) num_entries; i++) + { + if (p_entry->proxd_status == id) { + return p_entry->rtt_reason; + } + p_entry++; /* next entry */ + } + return RTT_REASON_FAILURE; /* not found */ +} +/* +* lookup 'id' (as a key) from a table +* if found, return the entry pointer, otherwise return NULL +*/ +static const ftm_strmap_entry_t* +ftm_get_strmap_info(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) +{ + int i; + const ftm_strmap_entry_t *p_entry; + + /* scan thru the table till end */ + p_entry = p_table; + for (i = 0; i < (int) num_entries; i++) + { + if (p_entry->id == id) + return p_entry; + p_entry++; /* next entry */ + } + return NULL; /* not found */ +} + +/* +* map enum to a text-string for display, this function is called by the following: +* For debug/trace: +* ftm_[cmdid|tlvid]_to_str() +* For TLV-output log for 'get' commands +* ftm_[method|tmu|caps|status|state]_value_to_logstr() +* Input: +* pTable -- point to a 'enum to string' table. +*/ +static const char * +ftm_map_id_to_str(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) +{ + const ftm_strmap_entry_t*p_entry = ftm_get_strmap_info(id, p_table, num_entries); + if (p_entry) + return (p_entry->text); + + return "invalid"; +} + + +#ifdef RTT_DEBUG + +/* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */ +#define DEF_STRMAP_ENTRY(id) { (id), #id } + +/* ftm cmd-id mapping */ +static const ftm_strmap_entry_t ftm_cmdid_map[] = { + /* {wl_proxd_cmd_t(WL_PROXD_CMD_xxx), "WL_PROXD_CMD_xxx" }, */ + DEF_STRMAP_ENTRY(WL_PROXD_CMD_NONE), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_VERSION), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_ENABLE), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_DISABLE), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_CONFIG), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_SESSION), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_BURST_REQUEST), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_SESSION), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_DELETE_SESSION), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RESULT), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_INFO), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_STATUS), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_SESSIONS), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_COUNTERS), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_CLEAR_COUNTERS), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_COLLECT), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_TUNE), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_DUMP), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_RANGING), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_RANGING), + DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RANGING_INFO), +}; + +/* +* map a ftm cmd-id to a text-string for display +*/ +static const char * +ftm_cmdid_to_str(uint16 cmdid) +{ + return ftm_map_id_to_str((int32) cmdid, &ftm_cmdid_map[0], ARRAYSIZE(ftm_cmdid_map)); +} +#endif /* RTT_DEBUG */ + + +/* +* convert BCME_xxx error codes into related error strings +* note, bcmerrorstr() defined in bcmutils is for BCMDRIVER only, +* this duplicate copy is for WL access and may need to clean up later +*/ +static const char *ftm_bcmerrorstrtable[] = BCMERRSTRINGTABLE; +static const char * +ftm_status_value_to_logstr(wl_proxd_status_t status) +{ + static char ftm_msgbuf_status_undef[32]; + const ftm_strmap_entry_t *p_loginfo; + int bcmerror; + + /* check if within BCME_xxx error range */ + bcmerror = (int) status; + if (VALID_BCMERROR(bcmerror)) + return ftm_bcmerrorstrtable[-bcmerror]; + + /* otherwise, look for 'proxd ftm status' range */ + p_loginfo = ftm_get_strmap_info((int32) status, + &ftm_status_value_loginfo[0], ARRAYSIZE(ftm_status_value_loginfo)); + if (p_loginfo) + return p_loginfo->text; + + /* report for 'out of range' FTM-status error code */ + memset(ftm_msgbuf_status_undef, 0, sizeof(ftm_msgbuf_status_undef)); + snprintf(ftm_msgbuf_status_undef, sizeof(ftm_msgbuf_status_undef), + "Undefined status %d", status); + return &ftm_msgbuf_status_undef[0]; +} + +static const char * +ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu) +{ + return ftm_map_id_to_str((int32)tmu, + &ftm_tmu_value_loginfo[0], ARRAYSIZE(ftm_tmu_value_loginfo)); +} + +static const ftm_strmap_entry_t* +ftm_get_event_type_loginfo(wl_proxd_event_type_t event_type) +{ + /* look up 'event-type' from a predefined table */ + return ftm_get_strmap_info((int32) event_type, + ftm_event_type_loginfo, ARRAYSIZE(ftm_event_type_loginfo)); +} + +static const char * +ftm_session_state_value_to_logstr(wl_proxd_session_state_t state) +{ + return ftm_map_id_to_str((int32)state, &ftm_session_state_value_loginfo[0], + ARRAYSIZE(ftm_session_state_value_loginfo)); +} + + +/* +* send 'proxd' iovar for all ftm get-related commands +*/ +static int +rtt_do_get_ioctl(dhd_pub_t *dhd, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize, + ftm_subcmd_info_t *p_subcmd_info) +{ + + wl_proxd_iov_t *p_iovresp = (wl_proxd_iov_t *)resp_buf; + int status; + int tlvs_len; + /* send getbuf proxd iovar */ + status = dhd_getiovar(dhd, 0, "proxd", (char *)p_proxd_iov, + proxd_iovsize, (char **)&p_iovresp, WLC_IOCTL_SMLEN); + if (status != BCME_OK) { + DHD_ERROR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n", + __FUNCTION__, p_subcmd_info->cmdid, status)); + return status; + } + if (p_subcmd_info->cmdid == WL_PROXD_CMD_GET_VERSION) { + p_subcmd_info->version = ltoh16(p_iovresp->version); + DHD_RTT(("ftm version: 0x%x\n", ltoh16(p_iovresp->version))); + goto exit; + } + + tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE; + if (tlvs_len < 0) { + DHD_ERROR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n", + __FUNCTION__, ltoh16(p_iovresp->len), (int) WL_PROXD_IOV_HDR_SIZE)); + tlvs_len = 0; + } + + if (tlvs_len > 0 && p_subcmd_info->handler) { + /* unpack TLVs and invokes the cbfn for processing */ + status = bcm_unpack_xtlv_buf(p_proxd_iov, (uint8 *)p_iovresp->tlvs, + tlvs_len, BCM_XTLV_OPTION_ALIGN32, p_subcmd_info->handler); + } +exit: + return status; +} + + +static wl_proxd_iov_t * +rtt_alloc_getset_buf(wl_proxd_method_t method, wl_proxd_session_id_t session_id, + wl_proxd_cmd_t cmdid, uint16 tlvs_bufsize, uint16 *p_out_bufsize) +{ + uint16 proxd_iovsize; + uint16 kflags; + wl_proxd_tlv_t *p_tlv; + wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) NULL; + + *p_out_bufsize = 0; /* init */ + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + /* calculate the whole buffer size, including one reserve-tlv entry in the header */ + proxd_iovsize = sizeof(wl_proxd_iov_t) + tlvs_bufsize; + + p_proxd_iov = kzalloc(proxd_iovsize, kflags); + if (p_proxd_iov == NULL) { + DHD_ERROR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize)); + return NULL; + } + + /* setup proxd-FTM-method iovar header */ + p_proxd_iov->version = htol16(WL_PROXD_API_VERSION); + p_proxd_iov->len = htol16(proxd_iovsize); /* caller may adjust it based on #of TLVs */ + p_proxd_iov->cmd = htol16(cmdid); + p_proxd_iov->method = htol16(method); + p_proxd_iov->sid = htol16(session_id); + + /* initialize the reserved/dummy-TLV in iovar header */ + p_tlv = p_proxd_iov->tlvs; + p_tlv->id = htol16(WL_PROXD_TLV_ID_NONE); + p_tlv->len = htol16(0); + + *p_out_bufsize = proxd_iovsize; /* for caller's reference */ + + return p_proxd_iov; +} + + +static int +dhd_rtt_common_get_handler(dhd_pub_t *dhd, ftm_subcmd_info_t *p_subcmd_info, + wl_proxd_method_t method, + wl_proxd_session_id_t session_id) +{ + int status = BCME_OK; + uint16 proxd_iovsize = 0; + wl_proxd_iov_t *p_proxd_iov; +#ifdef RTT_DEBUG + DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", + __FUNCTION__, method, session_id, p_subcmd_info->cmdid, + ftm_cmdid_to_str(p_subcmd_info->cmdid))); +#endif + /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ + p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, + 0, &proxd_iovsize); + + if (p_proxd_iov == NULL) + return BCME_NOMEM; + + status = rtt_do_get_ioctl(dhd, p_proxd_iov, proxd_iovsize, p_subcmd_info); + + if (status != BCME_OK) { + DHD_RTT(("%s failed: status=%d\n", __FUNCTION__, status)); + } + kfree(p_proxd_iov); + return status; +} + +/* +* common handler for set-related proxd method commands which require no TLV as input +* wl proxd ftm [session-id] +* e.g. +* wl proxd ftm enable -- to enable ftm +* wl proxd ftm disable -- to disable ftm +* wl proxd ftm start -- to start a specified session +* wl proxd ftm stop -- to cancel a specified session; +* state is maintained till session is delete. +* wl proxd ftm delete -- to delete a specified session +* wl proxd ftm [] clear-counters -- to clear counters +* wl proxd ftm burst-request -- on initiator: to send burst request; +* on target: send FTM frame +* wl proxd ftm collect +* wl proxd ftm tune (TBD) +*/ +static int +dhd_rtt_common_set_handler(dhd_pub_t *dhd, const ftm_subcmd_info_t *p_subcmd_info, + wl_proxd_method_t method, wl_proxd_session_id_t session_id) +{ + uint16 proxd_iovsize; + wl_proxd_iov_t *p_proxd_iov; + int ret; + +#ifdef RTT_DEBUG + DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", + __FUNCTION__, method, session_id, p_subcmd_info->cmdid, + ftm_cmdid_to_str(p_subcmd_info->cmdid))); +#endif + + /* allocate and initialize a temp buffer for 'set proxd' iovar */ + proxd_iovsize = 0; + p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, + 0, &proxd_iovsize); /* no TLV */ + if (p_proxd_iov == NULL) + return BCME_NOMEM; + + /* no TLV to pack, simply issue a set-proxd iovar */ + ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, proxd_iovsize, NULL, 0, TRUE); +#ifdef RTT_DEBUG + if (ret != BCME_OK) { + DHD_RTT(("error: IOVAR failed, status=%d\n", ret)); + } +#endif + /* clean up */ + kfree(p_proxd_iov); + + return ret; +} + +static int +rtt_unpack_xtlv_cbfn(void *ctx, uint8 *p_data, uint16 tlvid, uint16 len) +{ + int ret = BCME_OK; + wl_proxd_ftm_session_status_t *p_data_info; + switch (tlvid) { + case WL_PROXD_TLV_ID_RTT_RESULT: + ret = dhd_rtt_convert_results_to_host((rtt_report_t *)ctx, + p_data, tlvid, len); + break; + case WL_PROXD_TLV_ID_SESSION_STATUS: + memcpy(ctx, p_data, sizeof(wl_proxd_ftm_session_status_t)); + p_data_info = (wl_proxd_ftm_session_status_t *)ctx; + p_data_info->state = ltoh16_ua(&p_data_info->state); + p_data_info->status = ltoh32_ua(&p_data_info->status); + break; + default: + DHD_ERROR(("> Unsupported TLV ID %d\n", tlvid)); + ret = BCME_ERROR; + break; + } + + return ret; +} +static int +rtt_handle_config_options(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, + uint16 *p_buf_space_left, ftm_config_options_info_t *ftm_configs, int ftm_cfg_cnt) +{ + int ret = BCME_OK; + int cfg_idx = 0; + uint32 flags = WL_PROXD_FLAG_NONE; + uint32 flags_mask = WL_PROXD_FLAG_NONE; + uint32 new_mask; /* cmdline input */ + ftm_config_options_info_t *p_option_info; + uint16 type = (session_id == WL_PROXD_SESSION_ID_GLOBAL) ? + WL_PROXD_TLV_ID_FLAGS_MASK : WL_PROXD_TLV_ID_SESSION_FLAGS_MASK; + for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { + p_option_info = (ftm_configs + cfg_idx); + if (p_option_info != NULL) { + new_mask = p_option_info->flags; + /* update flags mask */ + flags_mask |= new_mask; + if (p_option_info->enable) { + flags |= new_mask; /* set the bit on */ + } else { + flags &= ~new_mask; /* set the bit off */ + } + } + } + flags = htol32(flags); + flags_mask = htol32(flags_mask); + /* setup flags_mask TLV */ + ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, + type, sizeof(uint32), &flags_mask, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + DHD_ERROR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n", + __FUNCTION__, ret)); + goto exit; + } + + type = (session_id == WL_PROXD_SESSION_ID_GLOBAL)? + WL_PROXD_TLV_ID_FLAGS : WL_PROXD_TLV_ID_SESSION_FLAGS; + /* setup flags TLV */ + ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, + type, sizeof(uint32), &flags, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { +#ifdef RTT_DEBUG + DHD_RTT(("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n", + __FUNCTION__, ret)); +#endif + } +exit: + return ret; +} + +static int +rtt_handle_config_general(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, + uint16 *p_buf_space_left, ftm_config_param_info_t *ftm_configs, int ftm_cfg_cnt) +{ + int ret = BCME_OK; + int cfg_idx = 0; + uint32 chanspec; + ftm_config_param_info_t *p_config_param_info; + void *p_src_data; + uint16 src_data_size; /* size of data pointed by p_src_data as 'source' */ + for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { + p_config_param_info = (ftm_configs + cfg_idx); + if (p_config_param_info != NULL) { + switch (p_config_param_info->tlvid) { + case WL_PROXD_TLV_ID_BSS_INDEX: + case WL_PROXD_TLV_ID_FTM_RETRIES: + case WL_PROXD_TLV_ID_FTM_REQ_RETRIES: + p_src_data = &p_config_param_info->data8; + src_data_size = sizeof(uint8); + break; + case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* uint16 */ + case WL_PROXD_TLV_ID_NUM_BURST: + case WL_PROXD_TLV_ID_RX_MAX_BURST: + p_src_data = &p_config_param_info->data16; + src_data_size = sizeof(uint16); + break; + case WL_PROXD_TLV_ID_TX_POWER: /* uint32 */ + case WL_PROXD_TLV_ID_RATESPEC: + case WL_PROXD_TLV_ID_EVENT_MASK: /* wl_proxd_event_mask_t/uint32 */ + case WL_PROXD_TLV_ID_DEBUG_MASK: + p_src_data = &p_config_param_info->data32; + src_data_size = sizeof(uint32); + break; + case WL_PROXD_TLV_ID_CHANSPEC: /* chanspec_t --> 32bit */ + chanspec = p_config_param_info->chanspec; + p_src_data = (void *) &chanspec; + src_data_size = sizeof(uint32); + break; + case WL_PROXD_TLV_ID_BSSID: /* mac address */ + case WL_PROXD_TLV_ID_PEER_MAC: + p_src_data = &p_config_param_info->mac_addr; + src_data_size = sizeof(struct ether_addr); + break; + case WL_PROXD_TLV_ID_BURST_DURATION: /* wl_proxd_intvl_t */ + case WL_PROXD_TLV_ID_BURST_PERIOD: + case WL_PROXD_TLV_ID_BURST_FTM_SEP: + case WL_PROXD_TLV_ID_BURST_TIMEOUT: + case WL_PROXD_TLV_ID_INIT_DELAY: + p_src_data = &p_config_param_info->data_intvl; + src_data_size = sizeof(wl_proxd_intvl_t); + break; + default: + ret = BCME_BADARG; + break; + } + if (ret != BCME_OK) { + DHD_ERROR(("%s bad TLV ID : %d\n", + __FUNCTION__, p_config_param_info->tlvid)); + break; + } + + ret = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left, + p_config_param_info->tlvid, src_data_size, p_src_data, + BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + DHD_ERROR(("%s: bcm_pack_xltv_entry() failed," + " status=%d\n", __FUNCTION__, ret)); + break; + } + + } + } + return ret; +} + +static int +dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version) +{ + int ret; + ftm_subcmd_info_t subcmd_info; + subcmd_info.name = "ver"; + subcmd_info.cmdid = WL_PROXD_CMD_GET_VERSION; + subcmd_info.handler = NULL; + ret = dhd_rtt_common_get_handler(dhd, &subcmd_info, + WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); + *out_version = (ret == BCME_OK) ? subcmd_info.version : 0; + return ret; +} + +static int +dhd_rtt_ftm_enable(dhd_pub_t *dhd, bool enable) +{ + ftm_subcmd_info_t subcmd_info; + subcmd_info.name = (enable)? "enable" : "disable"; + subcmd_info.cmdid = (enable)? WL_PROXD_CMD_ENABLE: WL_PROXD_CMD_DISABLE; + subcmd_info.handler = NULL; + return dhd_rtt_common_set_handler(dhd, &subcmd_info, + WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); +} + +static int +dhd_rtt_start_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, bool start) +{ + ftm_subcmd_info_t subcmd_info; + subcmd_info.name = (start)? "start session" : "stop session"; + subcmd_info.cmdid = (start)? WL_PROXD_CMD_START_SESSION: WL_PROXD_CMD_STOP_SESSION; + subcmd_info.handler = NULL; + return dhd_rtt_common_set_handler(dhd, &subcmd_info, + WL_PROXD_METHOD_FTM, session_id); +} + +static int +dhd_rtt_delete_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id) +{ + ftm_subcmd_info_t subcmd_info; + subcmd_info.name = "delete session"; + subcmd_info.cmdid = WL_PROXD_CMD_DELETE_SESSION; + subcmd_info.handler = NULL; + return dhd_rtt_common_set_handler(dhd, &subcmd_info, + WL_PROXD_METHOD_FTM, session_id); +} + +static int +dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, + ftm_config_category_t catagory, void *ftm_configs, int ftm_cfg_cnt) +{ + ftm_subcmd_info_t subcmd_info; + wl_proxd_tlv_t *p_tlv; + /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ + wl_proxd_iov_t *p_proxd_iov; + uint16 proxd_iovsize = 0; + uint16 bufsize; + uint16 buf_space_left; + uint16 all_tlvsize; + int ret = BCME_OK; + + subcmd_info.name = "config"; + subcmd_info.cmdid = WL_PROXD_CMD_CONFIG; + + p_proxd_iov = rtt_alloc_getset_buf(WL_PROXD_METHOD_FTM, session_id, subcmd_info.cmdid, + FTM_IOC_BUFSZ, &proxd_iovsize); + + if (p_proxd_iov == NULL) { + DHD_ERROR(("%s : failed to allocate the iovar (size :%d)\n", + __FUNCTION__, FTM_IOC_BUFSZ)); + return BCME_NOMEM; + } + /* setup TLVs */ + bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */ + p_tlv = &p_proxd_iov->tlvs[0]; + /* TLV buffer starts with a full size, will decrement for each packed TLV */ + buf_space_left = bufsize; + if (catagory == FTM_CONFIG_CAT_OPTIONS) { + ret = rtt_handle_config_options(session_id, &p_tlv, &buf_space_left, + (ftm_config_options_info_t *)ftm_configs, ftm_cfg_cnt); + } else if (catagory == FTM_CONFIG_CAT_GENERAL) { + ret = rtt_handle_config_general(session_id, &p_tlv, &buf_space_left, + (ftm_config_param_info_t *)ftm_configs, ftm_cfg_cnt); + } + if (ret == BCME_OK) { + /* update the iov header, set len to include all TLVs + header */ + all_tlvsize = (bufsize - buf_space_left); + p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE); + ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, + all_tlvsize + WL_PROXD_IOV_HDR_SIZE, NULL, 0, TRUE); + if (ret != BCME_OK) { + DHD_ERROR(("%s : failed to set config\n", __FUNCTION__)); + } + } + /* clean up */ + kfree(p_proxd_iov); + return ret; +} + +chanspec_t +dhd_rtt_convert_to_chspec(wifi_channel_info_t channel) +{ + int bw; + chanspec_t chanspec = 0; + uint8 center_chan; + uint8 primary_chan; + /* set witdh to 20MHZ for 2.4G HZ */ + if (channel.center_freq >= 2400 && channel.center_freq <= 2500) { + channel.width = WIFI_CHAN_WIDTH_20; + } + switch (channel.width) { + case WIFI_CHAN_WIDTH_20: + bw = WL_CHANSPEC_BW_20; + primary_chan = wf_mhz2channel(channel.center_freq, 0); + chanspec = wf_channel2chspec(primary_chan, bw); + break; + case WIFI_CHAN_WIDTH_40: + bw = WL_CHANSPEC_BW_40; + primary_chan = wf_mhz2channel(channel.center_freq, 0); + chanspec = wf_channel2chspec(primary_chan, bw); + break; + case WIFI_CHAN_WIDTH_80: + bw = WL_CHANSPEC_BW_80; + primary_chan = wf_mhz2channel(channel.center_freq, 0); + center_chan = wf_mhz2channel(channel.center_freq0, 0); + chanspec = wf_chspec_80(center_chan, primary_chan); + break; + default: + DHD_ERROR(("doesn't support this bandwith : %d", channel.width)); + bw = -1; + break; + } + return chanspec; +} + +int +dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params) +{ + int err = BCME_OK; + int idx; + rtt_status_info_t *rtt_status; + NULL_CHECK(params, "params is NULL", err); + + NULL_CHECK(dhd, "dhd is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + if (!HAS_11MC_CAP(rtt_status->rtt_capa.proto)) { + DHD_ERROR(("doesn't support RTT \n")); + return BCME_ERROR; + } + if (rtt_status->status != RTT_STOPPED) { + DHD_ERROR(("rtt is already started\n")); + return BCME_BUSY; + } + DHD_RTT(("%s enter\n", __FUNCTION__)); + + memset(rtt_status->rtt_config.target_info, 0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); + rtt_status->rtt_config.rtt_target_cnt = params->rtt_target_cnt; + memcpy(rtt_status->rtt_config.target_info, + params->target_info, TARGET_INFO_SIZE(params->rtt_target_cnt)); + rtt_status->status = RTT_STARTED; + /* start to measure RTT from first device */ + /* find next target to trigger RTT */ + for (idx = rtt_status->cur_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { + /* skip the disabled device */ + if (rtt_status->rtt_config.target_info[idx].disable) { + continue; + } else { + /* set the idx to cur_idx */ + rtt_status->cur_idx = idx; + break; + } + } + if (idx < rtt_status->rtt_config.rtt_target_cnt) { + DHD_RTT(("rtt_status->cur_idx : %d\n", rtt_status->cur_idx)); + schedule_work(&rtt_status->work); + } + return err; +} + +int +dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt) +{ + int err = BCME_OK; + int i = 0, j = 0; + rtt_status_info_t *rtt_status; + + NULL_CHECK(dhd, "dhd is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + if (rtt_status->status == RTT_STOPPED) { + DHD_ERROR(("rtt is not started\n")); + return BCME_OK; + } + DHD_RTT(("%s enter\n", __FUNCTION__)); + mutex_lock(&rtt_status->rtt_mutex); + for (i = 0; i < mac_cnt; i++) { + for (j = 0; j < rtt_status->rtt_config.rtt_target_cnt; j++) { + if (!bcmp(&mac_list[i], &rtt_status->rtt_config.target_info[j].addr, + ETHER_ADDR_LEN)) { + rtt_status->rtt_config.target_info[j].disable = TRUE; + } + } + } + mutex_unlock(&rtt_status->rtt_mutex); + return err; +} + +static int +dhd_rtt_start(dhd_pub_t *dhd) +{ + int err = BCME_OK; + char eabuf[ETHER_ADDR_STR_LEN]; + char chanbuf[CHANSPEC_STR_LEN]; + int mpc = 0; + int ftm_cfg_cnt = 0; + int ftm_param_cnt = 0; + ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS]; + ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS]; + rtt_target_info_t *rtt_target; + rtt_status_info_t *rtt_status; + NULL_CHECK(dhd, "dhd is NULL", err); + + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + + if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) { + err = BCME_RANGE; + DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx)); + goto exit; + } + /* turn off mpc in case of non-associted */ + if (!dhd_is_associated(dhd, NULL, NULL)) { + err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); + if (err) { + DHD_ERROR(("%s : failed to set mpc\n", __FUNCTION__)); + goto exit; + } + rtt_status->mpc = 1; /* Either failure or complete, we need to enable mpc */ + } + + mutex_lock(&rtt_status->rtt_mutex); + /* Get a target information */ + rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; + mutex_unlock(&rtt_status->rtt_mutex); + DHD_RTT(("%s enter\n", __FUNCTION__)); + if (!RTT_IS_ENABLED(rtt_status)) { + /* enable ftm */ + err = dhd_rtt_ftm_enable(dhd, TRUE); + if (err) { + DHD_ERROR(("failed to enable FTM (%d)\n", err)); + goto exit; + } + } + rtt_status->status = RTT_ENABLED; + + /* delete session of index default sesession */ + err = dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION); + if (err < 0 && err != BCME_NOTFOUND) { + DHD_ERROR(("failed to delete session of FTM (%d)\n", err)); + goto exit; + } + memset(ftm_configs, 0, sizeof(ftm_configs)); + memset(ftm_params, 0, sizeof(ftm_params)); + + /* configure the session 1 as initiator */ + ftm_configs[ftm_cfg_cnt].enable = TRUE; + ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_INITIATOR; + dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS, + ftm_configs, ftm_cfg_cnt); + /* target's mac address */ + if (!ETHER_ISNULLADDR(rtt_target->addr.octet)) { + ftm_params[ftm_param_cnt].mac_addr = rtt_target->addr; + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_PEER_MAC; + DHD_RTT((">\t target %s\n", bcm_ether_ntoa(&rtt_target->addr, eabuf))); + } + /* target's chanspec */ + if (rtt_target->chanspec) { + ftm_params[ftm_param_cnt].chanspec = htol32((uint32)rtt_target->chanspec); + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_CHANSPEC; + DHD_RTT((">\t chanspec : %s\n", wf_chspec_ntoa(rtt_target->chanspec, chanbuf))); + } + /* num-burst */ + if (rtt_target->num_burst) { + ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_burst); + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_NUM_BURST; + DHD_RTT((">\t num of burst : %d\n", rtt_target->num_burst)); + } + /* number of frame per burst */ + if (rtt_target->num_frames_per_burst == 0) { + rtt_target->num_frames_per_burst = + CHSPEC_IS20(rtt_target->chanspec) ? FTM_DEFAULT_CNT_20M : + CHSPEC_IS40(rtt_target->chanspec) ? FTM_DEFAULT_CNT_40M : + FTM_DEFAULT_CNT_80M; + } + ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_frames_per_burst); + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_NUM_FTM; + DHD_RTT((">\t number of frame per burst : %d\n", rtt_target->num_frames_per_burst)); + /* FTM retry count */ + if (rtt_target->num_retries_per_ftm) { + ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftm; + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_RETRIES; + DHD_RTT((">\t retry count of FTM : %d\n", rtt_target->num_retries_per_ftm)); + } + /* FTM Request retry count */ + if (rtt_target->num_retries_per_ftmr) { + ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftmr; + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_REQ_RETRIES; + DHD_RTT((">\t retry count of FTM Req : %d\n", rtt_target->num_retries_per_ftm)); + } + /* burst-period */ + if (rtt_target->interval) { + ftm_params[ftm_param_cnt].data_intvl.intvl = htol32(rtt_target->interval); /* ms */ + ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC; + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_PERIOD; + DHD_RTT((">\t burst period : %d ms\n", rtt_target->interval)); + } + /* burst-timeout */ + if (rtt_target->burst_timeout) { + ftm_params[ftm_param_cnt].data_intvl.intvl = + htol32(rtt_target->burst_timeout * FTM_BURST_TIMEOUT_UNIT); + ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MICRO_SEC; + ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_TIMEOUT; + DHD_RTT((">\t burst timeout : %d us\n", + rtt_target->burst_timeout * WL_PROXD_TMU_MICRO_SEC)); + } + dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_GENERAL, + ftm_params, ftm_param_cnt); + + err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE); + if (err) { + DHD_ERROR(("failed to start session of FTM : error %d\n", err)); + } +exit: + if (err) { + rtt_status->status = RTT_STOPPED; + /* disable FTM */ + dhd_rtt_ftm_enable(dhd, FALSE); + if (rtt_status->mpc) { + /* enable mpc again in case of error */ + mpc = 1; + rtt_status->mpc = 0; + err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); + } + } + return err; +} + +int +dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn) +{ + int err = BCME_OK; + struct rtt_noti_callback *cb = NULL, *iter; + rtt_status_info_t *rtt_status; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(noti_fn, "noti_fn is NULL", err); + + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + spin_lock_bh(¬i_list_lock); + list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { + if (iter->noti_fn == noti_fn) { + goto exit; + } + } + cb = kmalloc(sizeof(struct rtt_noti_callback), GFP_ATOMIC); + if (!cb) { + err = -ENOMEM; + goto exit; + } + cb->noti_fn = noti_fn; + cb->ctx = ctx; + list_add(&cb->list, &rtt_status->noti_fn_list); +exit: + spin_unlock_bh(¬i_list_lock); + return err; +} + +int +dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn) +{ + int err = BCME_OK; + struct rtt_noti_callback *cb = NULL, *iter; + rtt_status_info_t *rtt_status; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(noti_fn, "noti_fn is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + spin_lock_bh(¬i_list_lock); + list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { + if (iter->noti_fn == noti_fn) { + cb = iter; + list_del(&cb->list); + break; + } + } + spin_unlock_bh(¬i_list_lock); + if (cb) { + kfree(cb); + } + return err; +} + +static wifi_rate_t +dhd_rtt_convert_rate_to_host(uint32 rspec) +{ + wifi_rate_t host_rate; + if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { + host_rate.preamble = 0; + } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { + host_rate.preamble = 2; + host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; + } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { + host_rate.preamble = 3; + host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; + host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; + } + host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1; + host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ + DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); + return host_rate; +} + + +static int +dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len) +{ + int err = BCME_OK; + char eabuf[ETHER_ADDR_STR_LEN]; + wl_proxd_rtt_result_t *p_data_info; + wl_proxd_result_flags_t flags; + wl_proxd_session_state_t session_state; + wl_proxd_status_t proxd_status; + struct timespec ts; + uint32 ratespec; + uint32 avg_dist; + wl_proxd_rtt_sample_t *p_sample; + wl_proxd_intvl_t rtt; + wl_proxd_intvl_t p_time; + + NULL_CHECK(rtt_report, "rtt_report is NULL", err); + NULL_CHECK(p_data, "p_data is NULL", err); + DHD_RTT(("%s enter\n", __FUNCTION__)); + p_data_info = (wl_proxd_rtt_result_t *) p_data; + /* unpack and format 'flags' for display */ + flags = ltoh16_ua(&p_data_info->flags); + + /* session state and status */ + session_state = ltoh16_ua(&p_data_info->state); + proxd_status = ltoh32_ua(&p_data_info->status); + DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n", + bcm_ether_ntoa((&(p_data_info->peer)), eabuf), + session_state, + ftm_session_state_value_to_logstr(session_state), + proxd_status, + ftm_status_value_to_logstr(proxd_status))); + + /* show avg_dist (1/256m units), burst_num */ + avg_dist = ltoh32_ua(&p_data_info->avg_dist); + if (avg_dist == 0xffffffff) { /* report 'failure' case */ + DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n", + ltoh16_ua(&p_data_info->burst_num), + p_data_info->num_valid_rtt)); /* in a session */ + avg_dist = FTM_INVALID; + } + else { + DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n", + avg_dist >> 8, /* 1/256m units */ + ((avg_dist & 0xff) * 625) >> 4, + ltoh16_ua(&p_data_info->burst_num), + p_data_info->num_valid_rtt, + p_data_info->num_ftm)); /* in a session */ + } + /* show 'avg_rtt' sample */ + p_sample = &p_data_info->avg_rtt; + DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d ratespec=0x%08x\n", + (int16) ltoh16_ua(&p_sample->rssi), + ltoh32_ua(&p_sample->rtt.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)), + ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10, + ltoh32_ua(&p_sample->ratespec))); + + /* set peer address */ + rtt_report->addr = p_data_info->peer; + /* burst num */ + rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num); + /* success num */ + rtt_report->success_num = p_data_info->num_valid_rtt; + /* actual number of FTM supported by peer */ + rtt_report->num_per_burst_peer = p_data_info->num_ftm; + /* status */ + rtt_report->status = ftm_get_statusmap_info(proxd_status, + &ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info)); + /* rssi (0.5db) */ + rtt_report->rssi = (int16)ltoh16_ua(&p_data_info->avg_rtt.rssi) * 2; + /* rx rate */ + ratespec = ltoh32_ua(&p_data_info->avg_rtt.ratespec); + rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec); + /* rtt_sd */ + rtt.tmu = ltoh16_ua(&p_data_info->avg_rtt.rtt.tmu); + rtt.intvl = ltoh32_ua(&p_data_info->avg_rtt.rtt.intvl); + rtt_report->rtt = FTM_INTVL2NSEC(&rtt) * 10; /* nano -> 0.1 nano */ + rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */ + DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt)); + DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi)); + + /* average distance */ + if (avg_dist != FTM_INVALID) { + rtt_report->distance = (avg_dist >> 8) * 100; /* meter -> cm */ + rtt_report->distance += (avg_dist & 0xff) * 100 / 256; + } else { + rtt_report->distance = FTM_INVALID; + } + /* time stamp */ + /* get the time elapsed from boot time */ + get_monotonic_boottime(&ts); + rtt_report->ts = (uint64)TIMESPEC_TO_US(ts); + + if (proxd_status == WL_PROXD_E_REMOTE_FAIL) { + /* retry time after failure */ + p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); + p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); + rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */ + DHD_RTT((">\tretry_after: %d%s\n", + ltoh32_ua(&p_data_info->u.retry_after.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu)))); + } else { + /* burst duration */ + p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); + p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); + rtt_report->burst_duration = FTM_INTVL2MSEC(&p_time); /* s -> ms */ + DHD_RTT((">\tburst_duration: %d%s\n", + ltoh32_ua(&p_data_info->u.burst_duration.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu)))); + } + return err; +} + +int +dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) +{ + int ret = BCME_OK; + int tlvs_len; + int idx; + uint16 version; + wl_proxd_event_t *p_event; + wl_proxd_event_type_t event_type; + wl_proxd_ftm_session_status_t session_status; + const ftm_strmap_entry_t *p_loginfo; + rtt_status_info_t *rtt_status; + rtt_target_info_t *rtt_target_info; + struct rtt_noti_callback *iter; + rtt_results_header_t *entry = NULL, *next = NULL, *rtt_results_header = NULL; + rtt_result_t *rtt_result, *next2; + gfp_t kflags; + bool is_new = TRUE; + + NULL_CHECK(dhd, "dhd is NULL", ret); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", ret); + + event_type = ntoh32_ua((void *)&event->event_type); + + if (event_type != WLC_E_PROXD) { + goto exit; + } + if (RTT_IS_STOPPED(rtt_status)) { + /* Ignore the Proxd event */ + goto exit; + } + p_event = (wl_proxd_event_t *) event_data; + version = ltoh16(p_event->version); + if (version < WL_PROXD_API_VERSION) { + DHD_ERROR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n", + version, WL_PROXD_API_VERSION)); + goto exit; + } + if (!in_atomic()) { + mutex_lock(&rtt_status->rtt_mutex); + } + event_type = (wl_proxd_event_type_t) ltoh16(p_event->type); + + kflags = in_softirq()? GFP_ATOMIC : GFP_KERNEL; + + DHD_RTT(("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x\n", + p_event->type, ntoh16(p_event->type), ltoh16(p_event->type))); + p_loginfo = ftm_get_event_type_loginfo(event_type); + if (p_loginfo == NULL) { + DHD_ERROR(("receive an invalid FTM event %d\n", event_type)); + goto exit; /* ignore this event */ + } + /* get TLVs len, skip over event header */ + tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs); + DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n", + p_loginfo->text, + version, + ltoh16(p_event->len), + ltoh16(p_event->method), + ltoh16(p_event->sid), + tlvs_len)); + rtt_target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; + /* find a rtt_report_header for this mac address */ + list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) { + if (!memcmp(&entry->peer_mac, &event->addr, ETHER_ADDR_LEN)) { + /* found a rtt_report_header for peer_mac in the list */ + is_new = FALSE; + rtt_results_header = entry; + break; + } + } + + switch (event_type) { + case WL_PROXD_EVENT_SESSION_CREATE: + DHD_RTT(("WL_PROXD_EVENT_SESSION_CREATE\n")); + break; + case WL_PROXD_EVENT_SESSION_START: + DHD_RTT(("WL_PROXD_EVENT_SESSION_START\n")); + break; + case WL_PROXD_EVENT_BURST_START: + DHD_RTT(("WL_PROXD_EVENT_BURST_START\n")); + break; + case WL_PROXD_EVENT_BURST_END: + DHD_RTT(("WL_PROXD_EVENT_BURST_END\n")); + if (is_new) { + /* allocate new header for rtt_results */ + rtt_results_header = kzalloc(sizeof(rtt_results_header_t), GFP_KERNEL); + if (!rtt_results_header) { + if (!in_atomic()) { + mutex_unlock(&rtt_status->rtt_mutex); + } + ret = -ENOMEM; + goto exit; + } + /* Initialize the head of list for rtt result */ + INIT_LIST_HEAD(&rtt_results_header->result_list); + rtt_results_header->peer_mac = event->addr; + list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache); + } + if (tlvs_len > 0) { + /* allocate rtt_results for new results */ + rtt_result = kzalloc(sizeof(rtt_result_t), kflags); + if (!rtt_result) { + if (!in_atomic()) { + mutex_unlock(&rtt_status->rtt_mutex); + } + ret = -ENOMEM; + goto exit; + } + /* unpack TLVs and invokes the cbfn to print the event content TLVs */ + ret = bcm_unpack_xtlv_buf((void *) &(rtt_result->report), + (uint8 *)&p_event->tlvs[0], tlvs_len, + BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); + if (ret != BCME_OK) { + DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", + __FUNCTION__)); + goto exit; + } + /* fill out the results from the configuration param */ + rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst; + rtt_result->report.type = RTT_TWO_WAY; + DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num)); + rtt_result->report_len = RTT_REPORT_SIZE; + + list_add_tail(&rtt_result->list, &rtt_results_header->result_list); + rtt_results_header->result_cnt++; + rtt_results_header->result_tot_len += rtt_result->report_len; + } + break; + case WL_PROXD_EVENT_SESSION_END: + DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n")); + if (tlvs_len > 0) { + /* unpack TLVs and invokes the cbfn to print the event content TLVs */ + ret = bcm_unpack_xtlv_buf((void *) &session_status, + (uint8 *)&p_event->tlvs[0], tlvs_len, + BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); + if (ret != BCME_OK) { + DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", + __FUNCTION__)); + goto exit; + } + } + /* find next target to trigger RTT */ + for (idx = (rtt_status->cur_idx + 1); + idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { + /* skip the disabled device */ + if (rtt_status->rtt_config.target_info[idx].disable) { + continue; + } else { + /* set the idx to cur_idx */ + rtt_status->cur_idx = idx; + break; + } + } + if (idx < rtt_status->rtt_config.rtt_target_cnt) { + /* restart to measure RTT from next device */ + schedule_work(&rtt_status->work); + } else { + DHD_RTT(("RTT_STOPPED\n")); + rtt_status->status = RTT_STOPPED; + /* to turn on mpc mode */ + schedule_work(&rtt_status->work); + /* notify the completed information to others */ + list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { + iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache); + } + /* remove the rtt results in cache */ + if (!list_empty(&rtt_status->rtt_results_cache)) { + /* Iterate rtt_results_header list */ + list_for_each_entry_safe(entry, next, + &rtt_status->rtt_results_cache, list) { + list_del(&entry->list); + /* Iterate rtt_result list */ + list_for_each_entry_safe(rtt_result, next2, + &entry->result_list, list) { + list_del(&rtt_result->list); + kfree(rtt_result); + } + kfree(entry); + } + } + + /* reinitialize the HEAD */ + INIT_LIST_HEAD(&rtt_status->rtt_results_cache); + /* clear information for rtt_config */ + rtt_status->rtt_config.rtt_target_cnt = 0; + memset(rtt_status->rtt_config.target_info, 0, + TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); + rtt_status->cur_idx = 0; + } + break; + case WL_PROXD_EVENT_SESSION_RESTART: + DHD_RTT(("WL_PROXD_EVENT_SESSION_RESTART\n")); + break; + case WL_PROXD_EVENT_BURST_RESCHED: + DHD_RTT(("WL_PROXD_EVENT_BURST_RESCHED\n")); + break; + case WL_PROXD_EVENT_SESSION_DESTROY: + DHD_RTT(("WL_PROXD_EVENT_SESSION_DESTROY\n")); + break; + case WL_PROXD_EVENT_FTM_FRAME: + DHD_RTT(("WL_PROXD_EVENT_FTM_FRAME\n")); + break; + case WL_PROXD_EVENT_DELAY: + DHD_RTT(("WL_PROXD_EVENT_DELAY\n")); + break; + case WL_PROXD_EVENT_VS_INITIATOR_RPT: + DHD_RTT(("WL_PROXD_EVENT_VS_INITIATOR_RPT\n ")); + break; + case WL_PROXD_EVENT_RANGING: + DHD_RTT(("WL_PROXD_EVENT_RANGING\n")); + break; + + default: + DHD_ERROR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type)); + break; + } + if (!in_atomic()) { + mutex_unlock(&rtt_status->rtt_mutex); + } +exit: + return ret; +} + +static void +dhd_rtt_work(struct work_struct *work) +{ + rtt_status_info_t *rtt_status; + dhd_pub_t *dhd; + rtt_status = container_of(work, rtt_status_info_t, work); + if (rtt_status == NULL) { + DHD_ERROR(("%s : rtt_status is NULL\n", __FUNCTION__)); + return; + } + dhd = rtt_status->dhd; + if (dhd == NULL) { + DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); + return; + } + (void) dhd_rtt_start(dhd); +} + +int +dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa) +{ + rtt_status_info_t *rtt_status; + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + NULL_CHECK(capa, "capa is NULL", err); + bzero(capa, sizeof(rtt_capabilities_t)); + switch (rtt_status->rtt_capa.proto) { + case RTT_CAP_ONE_WAY: + capa->rtt_one_sided_supported = 1; + break; + case RTT_CAP_FTM_WAY: + capa->rtt_ftm_supported = 1; + break; + } + + switch (rtt_status->rtt_capa.feature) { + case RTT_FEATURE_LCI: + capa->lci_support = 1; + break; + case RTT_FEATURE_LCR: + capa->lcr_support = 1; + break; + case RTT_FEATURE_PREAMBLE: + capa->preamble_support = 1; + break; + case RTT_FEATURE_BW: + capa->bw_support = 1; + break; + } + /* bit mask */ + capa->preamble_support = rtt_status->rtt_capa.preamble; + capa->bw_support = rtt_status->rtt_capa.bw; + + return err; +} + +int +dhd_rtt_init(dhd_pub_t *dhd) +{ + int err = BCME_OK, ret; + int32 up = 1; + int32 version; + rtt_status_info_t *rtt_status; + NULL_CHECK(dhd, "dhd is NULL", err); + if (dhd->rtt_state) { + return err; + } + dhd->rtt_state = kzalloc(sizeof(rtt_status_info_t), GFP_KERNEL); + if (dhd->rtt_state == NULL) { + err = BCME_NOMEM; + DHD_ERROR(("%s : failed to create rtt_state\n", __FUNCTION__)); + return err; + } + bzero(dhd->rtt_state, sizeof(rtt_status_info_t)); + rtt_status = GET_RTTSTATE(dhd); + rtt_status->rtt_config.target_info = + kzalloc(TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT), GFP_KERNEL); + if (rtt_status->rtt_config.target_info == NULL) { + DHD_ERROR(("%s failed to allocate the target info for %d\n", + __FUNCTION__, RTT_MAX_TARGET_CNT)); + err = BCME_NOMEM; + goto exit; + } + rtt_status->dhd = dhd; + /* need to do WLC_UP */ + dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(int32), TRUE, 0); + + ret = dhd_rtt_get_version(dhd, &version); + if (ret == BCME_OK && (version == WL_PROXD_API_VERSION)) { + DHD_ERROR(("%s : FTM is supported\n", __FUNCTION__)); + /* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */ + rtt_status->rtt_capa.proto |= RTT_CAP_FTM_WAY; + + /* indicate to set tx rate */ + rtt_status->rtt_capa.feature |= RTT_FEATURE_PREAMBLE; + rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_VHT; + rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_HT; + + /* indicate to set bandwith */ + rtt_status->rtt_capa.feature |= RTT_FEATURE_BW; + rtt_status->rtt_capa.bw |= RTT_BW_20; + rtt_status->rtt_capa.bw |= RTT_BW_40; + rtt_status->rtt_capa.bw |= RTT_BW_80; + } else { + if ((ret != BCME_OK) || (version == 0)) { + DHD_ERROR(("%s : FTM is not supported\n", __FUNCTION__)); + } else { + DHD_ERROR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n", + __FUNCTION__, WL_PROXD_API_VERSION, version)); + } + } + mutex_init(&rtt_status->rtt_mutex); + INIT_LIST_HEAD(&rtt_status->noti_fn_list); + INIT_LIST_HEAD(&rtt_status->rtt_results_cache); + INIT_WORK(&rtt_status->work, dhd_rtt_work); +exit: + if (err < 0) { + kfree(rtt_status->rtt_config.target_info); + kfree(dhd->rtt_state); + } + return err; +} + +int +dhd_rtt_deinit(dhd_pub_t *dhd) +{ + int err = BCME_OK; + rtt_status_info_t *rtt_status; + rtt_results_header_t *rtt_header, *next; + rtt_result_t *rtt_result, *next2; + struct rtt_noti_callback *iter, *iter2; + NULL_CHECK(dhd, "dhd is NULL", err); + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + rtt_status->status = RTT_STOPPED; + /* clear evt callback list */ + if (!list_empty(&rtt_status->noti_fn_list)) { + list_for_each_entry_safe(iter, iter2, &rtt_status->noti_fn_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + /* remove the rtt results */ + if (!list_empty(&rtt_status->rtt_results_cache)) { + list_for_each_entry_safe(rtt_header, next, &rtt_status->rtt_results_cache, list) { + list_del(&rtt_header->list); + list_for_each_entry_safe(rtt_result, next2, + &rtt_header->result_list, list) { + list_del(&rtt_result->list); + kfree(rtt_result); + } + kfree(rtt_header); + } + } + kfree(rtt_status->rtt_config.target_info); + kfree(dhd->rtt_state); + dhd->rtt_state = NULL; + return err; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h new file mode 100644 index 000000000000..308f657391a5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h @@ -0,0 +1,284 @@ +/* + * Header file of Broadcom Dongle Host Driver (DHD) + * Copyright (C) 1999-2014, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_rtt.h 423669 2014-07-01 13:01:56Z $ + */ +#ifndef __DHD_RTT_H__ +#define __DHD_RTT_H__ + +#include "dngl_stats.h" + +#define RTT_MAX_TARGET_CNT 50 +#define RTT_MAX_FRAME_CNT 25 +#define RTT_MAX_RETRY_CNT 10 +#define DEFAULT_FTM_CNT 6 +#define DEFAULT_RETRY_CNT 6 +#define TARGET_INFO_SIZE(count) (sizeof(rtt_target_info_t) * count) + +#define TARGET_TYPE(target) (target->type) + +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +/* DSSS, CCK and 802.11n rates in [500kbps] units */ +#define WL_MAXRATE 108 /* in 500kbps units */ +#define WL_RATE_1M 2 /* in 500kbps units */ +#define WL_RATE_2M 4 /* in 500kbps units */ +#define WL_RATE_5M5 11 /* in 500kbps units */ +#define WL_RATE_11M 22 /* in 500kbps units */ +#define WL_RATE_6M 12 /* in 500kbps units */ +#define WL_RATE_9M 18 /* in 500kbps units */ +#define WL_RATE_12M 24 /* in 500kbps units */ +#define WL_RATE_18M 36 /* in 500kbps units */ +#define WL_RATE_24M 48 /* in 500kbps units */ +#define WL_RATE_36M 72 /* in 500kbps units */ +#define WL_RATE_48M 96 /* in 500kbps units */ +#define WL_RATE_54M 108 /* in 500kbps units */ + + +enum rtt_role { + RTT_INITIATOR = 0, + RTT_TARGET = 1 +}; +enum rtt_status { + RTT_STOPPED = 0, + RTT_STARTED = 1, + RTT_ENABLED = 2 +}; +typedef int64_t wifi_timestamp; /* In microseconds (us) */ +typedef int64_t wifi_timespan; +typedef int32 wifi_rssi; + +typedef enum { + RTT_INVALID, + RTT_ONE_WAY, + RTT_TWO_WAY, + RTT_AUTO +} rtt_type_t; + +typedef enum { + RTT_PEER_STA, + RTT_PEER_AP, + RTT_PEER_P2P, + RTT_PEER_NAN, + RTT_PEER_INVALID +} rtt_peer_type_t; + +typedef enum rtt_reason { + RTT_REASON_SUCCESS, + RTT_REASON_FAILURE, + RTT_REASON_FAIL_NO_RSP, + RTT_REASON_FAIL_INVALID_TS, /* Invalid timestamp */ + RTT_REASON_FAIL_PROTOCOL, /* 11mc protocol failed */ + RTT_REASON_FAIL_REJECTED, + RTT_REASON_FAIL_NOT_SCHEDULED_YET, + RTT_REASON_FAIL_SCHEDULE, /* schedule failed */ + RTT_REASON_FAIL_TM_TIMEOUT, + RTT_REASON_FAIL_AP_ON_DIFF_CHANNEL, + RTT_REASON_FAIL_NO_CAPABILITY, + RTT_REASON_FAIL_BUSY_TRY_LATER, + RTT_REASON_ABORTED +} rtt_reason_t; + +enum { + RTT_CAP_ONE_WAY = BIT(0), + /* IEEE802.11mc */ + RTT_CAP_FTM_WAY = BIT(1) +}; + +enum { + RTT_FEATURE_LCI = BIT(0), + RTT_FEATURE_LCR = BIT(1), + RTT_FEATURE_PREAMBLE = BIT(2), + RTT_FEATURE_BW = BIT(3) +}; + +enum { + RTT_PREAMBLE_LEGACY = BIT(0), + RTT_PREAMBLE_HT = BIT(1), + RTT_PREAMBLE_VHT = BIT(2) +}; + + +enum { + RTT_BW_5 = BIT(0), + RTT_BW_10 = BIT(1), + RTT_BW_20 = BIT(2), + RTT_BW_40 = BIT(3), + RTT_BW_80 = BIT(4), + RTT_BW_160 = BIT(5) +}; +#define FTM_MAX_NUM_BURST_EXP 14 +#define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) +#define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) +#define HAS_RTT_CAP(cap) (HAS_ONEWAY_CAP(cap) || HAS_11MC_CAP(cap)) + +typedef struct wifi_channel_info { + wifi_channel_width_t width; + wifi_channel center_freq; /* primary 20 MHz channel */ + wifi_channel center_freq0; /* center freq (MHz) first segment */ + wifi_channel center_freq1; /* center freq (MHz) second segment valid for 80 + 80 */ +} wifi_channel_info_t; + +typedef struct wifi_rate { + uint32 preamble :3; /* 0: OFDM, 1: CCK, 2 : HT, 3: VHT, 4..7 reserved */ + uint32 nss :2; /* 1 : 1x1, 2: 2x2, 3: 3x3, 4: 4x4 */ + uint32 bw :3; /* 0: 20Mhz, 1: 40Mhz, 2: 80Mhz, 3: 160Mhz */ + /* OFDM/CCK rate code would be as per IEEE std in the unit of 0.5 mb + * HT/VHT it would be mcs index + */ + uint32 rateMcsIdx :8; + uint32 reserved :16; /* reserved */ + uint32 bitrate; /* unit of 100 Kbps */ +} wifi_rate_t; + +typedef struct rtt_target_info { + struct ether_addr addr; + rtt_type_t type; /* rtt_type */ + rtt_peer_type_t peer; /* peer type */ + wifi_channel_info_t channel; /* channel information */ + chanspec_t chanspec; /* chanspec for channel */ + bool disable; /* disable for RTT measurement */ + uint32 interval; /* interval of RTT measurement (unit ms) when continuous = true */ + uint16 num_burst; /* total number of RTT bursts when multi_burst = 1 */ + uint32 num_frames_per_burst; + /* num of frames in each RTT burst + * for single side, measurement result num = frame number + * for 2 side RTT, measurement result num = frame number - 1 + */ + uint32 num_retries_per_ftm; /* retry time for RTT measurment frame */ + /* following fields are only valid for 2 side RTT */ + uint32 num_retries_per_ftmr; + uint8 LCI_request; + uint8 LCR_request; + uint32 burst_timeout; + uint8 preamble; /* 0 - Legacy, 1 - HT, 2 - VHT */ + uint8 bw; /* 5, 10, 20, 40, 80, 160 */ +} rtt_target_info_t; + + +typedef struct rtt_report { + struct ether_addr addr; + unsigned int burst_num; /* # of burst inside a multi-burst request */ + unsigned int ftm_num; /* total RTT measurement frames */ + unsigned int success_num; /* total successful RTT measurement frames */ + uint8 num_per_burst_peer; /* max number of FTM number per burst the peer support */ + rtt_reason_t status; /* raging status */ + /* in s, 11mc only, only for RTT_REASON_FAIL_BUSY_TRY_LATER, 1- 31s */ + uint8 retry_after_duration; + rtt_type_t type; /* rtt type */ + wifi_rssi rssi; /* average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB */ + wifi_rssi rssi_spread; /* rssi spread in 0.5 db steps e.g. 5 implies 2.5 spread */ + wifi_rate_t tx_rate; /* tx rate */ + wifi_rate_t rx_rate; /* rx rate */ + wifi_timespan rtt; /* round trip time in 0.1 nanoseconds */ + wifi_timespan rtt_sd; /* rtt standard deviation in 0.1 nanoseconds */ + wifi_timespan rtt_spread; /* difference between max and min rtt times recorded */ + int distance; /* distance in cm (optional) */ + int distance_sd; /* standard deviation in cm (optional) */ + int distance_spread; /* difference between max and min distance recorded (optional) */ + wifi_timestamp ts; /* time of the measurement (in microseconds since boot) */ + int burst_duration; /* in ms, how long the FW time is to fininish one burst measurement */ + bcm_tlv_t *LCI; /* LCI Report */ + bcm_tlv_t *LCR; /* Location Civic Report */ +} rtt_report_t; +#define RTT_REPORT_SIZE (sizeof(rtt_report_t)) + +/* rtt_results_header to maintain rtt result list per mac address */ +typedef struct rtt_results_header { + struct ether_addr peer_mac; + uint32 result_cnt; + uint32 result_tot_len; /* sum of report_len of rtt_result */ + struct list_head list; + struct list_head result_list; +} rtt_results_header_t; + +/* rtt_result to link all of rtt_report */ +typedef struct rtt_result { + struct list_head list; + struct rtt_report report; + int32 report_len; /* total length of rtt_report */ +} rtt_result_t; + +/* RTT Capabilities */ +typedef struct rtt_capabilities { + uint8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */ + uint8 rtt_ftm_supported; /* if ftm rtt data collection is supported */ + uint8 lci_support; /* location configuration information */ + uint8 lcr_support; /* Civic Location */ + uint8 preamble_support; /* bit mask indicate what preamble is supported */ + uint8 bw_support; /* bit mask indicate what BW is supported */ +} rtt_capabilities_t; + +typedef struct rtt_config_params { + int8 rtt_target_cnt; + rtt_target_info_t *target_info; +} rtt_config_params_t; + +typedef void (*dhd_rtt_compl_noti_fn)(void *ctx, void *rtt_data); +/* Linux wrapper to call common dhd_rtt_set_cfg */ +int +dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf); + +int +dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt); + +int +dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, + dhd_rtt_compl_noti_fn noti_fn); + +int +dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn); + +int +dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa); + +/* export to upper layer */ +chanspec_t +dhd_rtt_convert_to_chspec(wifi_channel_info_t channel); + +int +dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params); + +int +dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt); + + +int +dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn); + +int +dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn); + +int +dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); + +int +dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa); + +int +dhd_rtt_init(dhd_pub_t *dhd); + +int +dhd_rtt_deinit(dhd_pub_t *dhd); +#endif /* __DHD_RTT_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c new file mode 100644 index 000000000000..44ec2b607ab8 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c @@ -0,0 +1,8334 @@ +/* + * DHD Bus Module for SDIO + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_sdio.c 701450 2017-05-25 02:10:23Z $ + */ + +#include +#include +#include + +#ifdef BCMEMBEDIMAGE +#include BCMEMBEDIMAGE +#endif /* BCMEMBEDIMAGE */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#if defined(DHD_DEBUG) +#include +#include +#endif /* defined(DHD_DEBUG) */ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef PROP_TXSTATUS +#include +#endif + +#ifdef DHDTCPACK_SUPPRESS +#include +#endif + +#include + +bool dhd_mp_halting(dhd_pub_t *dhdp); +extern void bcmsdh_waitfor_iodrain(void *sdh); +extern void bcmsdh_reject_ioreqs(void *sdh, bool reject); +extern bool bcmsdh_fatal_error(void *sdh); + +#ifndef DHDSDIO_MEM_DUMP_FNAME +#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" +#endif + +#define QLEN (1024) /* bulk rx and tx queue lengths */ +#define FCHI (QLEN - 10) +#define FCLOW (FCHI / 2) +#define PRIOMASK 7 + +#define TXRETRIES 2 /* # of retries for tx frames */ +#define READ_FRM_CNT_RETRIES 3 +#ifndef DHD_RXBOUND +#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ +#endif + +#ifndef DHD_TXBOUND +#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ +#endif + +#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ + +#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ +#define MAX_NVRAMBUF_SIZE (6 * 1024) /* max nvram buf size */ +#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */ + +#ifndef DHD_FIRSTREAD +#define DHD_FIRSTREAD 32 +#endif +#if !ISPOWEROF2(DHD_FIRSTREAD) +#error DHD_FIRSTREAD is not a power of 2! +#endif + +/* Total length of frame header for dongle protocol */ +#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) +#define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN) +#define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE + +#ifdef SDTEST +#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) +#else +#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) +#endif + +/* Space for header read, limit for data packets */ +#ifndef MAX_HDR_READ +#define MAX_HDR_READ 32 +#endif +#if !ISPOWEROF2(MAX_HDR_READ) +#error MAX_HDR_READ is not a power of 2! +#endif + +#define MAX_RX_DATASZ 2048 + +/* Maximum milliseconds to wait for F2 to come up */ +#define DHD_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). + */ +#if (PMU_MAX_TRANSITION_DLY <= 1000000) +#undef PMU_MAX_TRANSITION_DLY +#define PMU_MAX_TRANSITION_DLY 1000000 +#endif + +/* hooks for limiting threshold custom tx num in rx processing */ +#define DEFAULT_TXINRX_THRES 0 +#ifndef CUSTOM_TXINRX_THRES +#define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES +#endif + +/* Value for ChipClockCSR during initial setup */ +#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) +#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) + +/* Flags for SDH calls */ +#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) + +/* Packet free applicable unconditionally for sdio and sdspi. Conditional if + * bufpool was present for gspi bus. + */ +#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ + PKTFREE(bus->dhd->osh, pkt, FALSE); +DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); + + +#ifdef DHD_DEBUG +/* Device console log buffer state */ +#define CONSOLE_LINE_MAX 192 +#define CONSOLE_BUFFER_MAX 2024 +typedef struct dhd_console { + uint count; /* Poll interval msec counter */ + uint log_addr; /* Log struct address (fixed) */ + hndrte_log_t log; /* Log struct (host copy) */ + uint bufsize; /* Size of log buffer */ + uint8 *buf; /* Log buffer (host copy) */ + uint last; /* Last buffer read index */ +} dhd_console_t; +#endif /* DHD_DEBUG */ + +#define REMAP_ENAB(bus) ((bus)->remap) +#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) +#define KSO_ENAB(bus) ((bus)->kso) +#define SR_ENAB(bus) ((bus)->_srenab) +#define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto)) +#define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618) +#define MIN_RSRC_SR 0x3 +#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) +#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) +#define RCTL_MACPHY_DISABLE_MASK (1 << 26) +#define RCTL_LOGIC_DISABLE_MASK (1 << 27) + +#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) +#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ +#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ +#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ +#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) +#define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2) +#define OVERFLOW_BLKSZ512_WM 96 +#define OVERFLOW_BLKSZ512_MES 80 + +#define CC_PMUCC3 (0x3) +#if defined(CUSTOMER_HW5) +#define DHD_DPC_LOG_SZ (256) +#endif /* CUSTOMER_HW5 */ +/* Private data for SDIO bus interaction */ +typedef struct dhd_bus { + dhd_pub_t *dhd; + + bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ + si_t *sih; /* Handle for SI calls */ + char *vars; /* Variables (from CIS and/or other) */ + uint varsz; /* Size of variables buffer */ + uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ + + sdpcmd_regs_t *regs; /* Registers for SDIO core */ + uint sdpcmrev; /* SDIO core revision */ + uint armrev; /* CPU core revision */ + uint ramrev; /* SOCRAM core revision */ + uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ + uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ + uint32 srmemsize; /* Size of SRMEM */ + + uint32 bus; /* gSPI or SDIO bus */ + uint32 bus_num; /* bus number */ + uint32 slot_num; /* slot ID */ + uint32 hostintmask; /* Copy of Host Interrupt Mask */ + uint32 intstatus; /* Intstatus bits (events) pending */ + bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ + bool fcstate; /* State of dongle flow-control */ + + uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ + char *fw_path; /* module_param: path to firmware image */ + char *nv_path; /* module_param: path to nvram vars file */ + const char *nvram_params; /* user specified nvram params. */ + + uint blocksize; /* Block size of SDIO transfers */ + uint roundup; /* Max roundup limit */ + + struct pktq txq; /* Queue length used for flow-control */ + uint8 flowcontrol; /* per prio flow control bitmask */ + uint8 tx_seq; /* Transmit sequence number (next) */ + uint8 tx_max; /* Maximum transmit sequence allowed */ + + uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; + uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ + uint16 nextlen; /* Next Read Len from last header */ + uint8 rx_seq; /* Receive sequence number (expected) */ + bool rxskip; /* Skip receive (awaiting NAK ACK) */ + + void *glomd; /* Packet containing glomming descriptor */ + void *glom; /* Packet chain for glommed superframe */ + uint glomerr; /* Glom packet read errors */ + + uint8 *rxbuf; /* Buffer for receiving control packets */ + uint rxblen; /* Allocated length of rxbuf */ + uint8 *rxctl; /* Aligned pointer into rxbuf */ + uint8 *databuf; /* Buffer for receiving big glom packet */ + uint8 *dataptr; /* Aligned pointer into databuf */ + uint rxlen; /* Length of valid data in buffer */ + + uint8 sdpcm_ver; /* Bus protocol reported by dongle */ + + bool intr; /* Use interrupts */ + bool poll; /* Use polling */ + bool ipend; /* Device interrupt is pending */ + bool intdis; /* Interrupts disabled by isr */ + 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 DHD_DEBUG + dhd_console_t console; /* Console output polling support */ + uint console_addr; /* Console address from shared struct */ +#endif /* DHD_DEBUG */ + + uint regfails; /* Count of R_REG/W_REG failures */ + + uint clkstate; /* State of sd and backplane clock(s) */ + bool activity; /* Activity flag for clock down */ + int32 idletime; /* Control for activity timeout */ + int32 idlecount; /* Activity timeout counter */ + int32 idleclock; /* How to set bus driver when idle */ + int32 sd_divisor; /* Speed control to bus driver */ + int32 sd_mode; /* Mode control to bus driver */ + int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ + bool use_rxchain; /* If dhd should use PKT chains */ + bool sleeping; /* Is SDIO bus sleeping? */ +#if defined(SUPPORT_P2P_GO_PS) + wait_queue_head_t bus_sleep; +#endif /* LINUX && SUPPORT_P2P_GO_PS */ + uint rxflow_mode; /* Rx flow control mode */ + bool rxflow; /* Is rx flow control on */ + uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ + 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; + int32 txinrx_thres; /* num of in-queued pkts */ + int32 dotxinrx; /* tx first in dhdsdio_readframes */ +#ifdef SDTEST + /* external loopback */ + bool ext_loop; + uint8 loopid; + + /* pktgen configuration */ + uint pktgen_freq; /* Ticks between bursts */ + uint pktgen_count; /* Packets to send each burst */ + uint pktgen_print; /* Bursts between count displays */ + uint pktgen_total; /* Stop after this many */ + uint pktgen_minlen; /* Minimum packet data len */ + uint pktgen_maxlen; /* Maximum packet data len */ + uint pktgen_mode; /* Configured mode: tx, rx, or echo */ + uint pktgen_stop; /* Number of tx failures causing stop */ + + /* active pktgen fields */ + uint pktgen_tick; /* Tick counter for bursts */ + uint pktgen_ptick; /* Burst counter for printing */ + uint pktgen_sent; /* Number of test packets generated */ + uint pktgen_rcvd; /* Number of test packets received */ + uint pktgen_prev_time; /* Time at which previous stats where printed */ + uint pktgen_prev_sent; /* Number of test packets generated when + * previous stats were printed + */ + uint pktgen_prev_rcvd; /* Number of test packets received when + * previous stats were printed + */ + uint pktgen_fail; /* Number of failed send attempts */ + uint16 pktgen_len; /* Length of next packet to send */ +#define PKTGEN_RCV_IDLE (0) +#define PKTGEN_RCV_ONGOING (1) + uint16 pktgen_rcv_state; /* receive state */ + uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ +#endif /* SDTEST */ + + /* 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 */ +#ifdef DHDENABLE_TAILPAD + uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */ + uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */ +#endif + uint8 *ctrl_frame_buf; + uint32 ctrl_frame_len; + bool ctrl_frame_stat; + uint32 rxint_mode; /* rx interrupt mode */ + bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram + * Available with socram rev 16 + * Remap region not DMA-able + */ + bool kso; + bool _slpauto; + bool _oobwakeup; + bool _srenab; + bool readframes; + bool reqbussleep; + uint32 resetinstr; + uint32 dongle_ram_base; + + void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */ + uint32 txglom_cnt; /* Number of pkts in the glom array */ + uint32 txglom_total_len; /* Total length of pkts in glom array */ + bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled */ + uint32 txglomsize; /* Glom size limitation */ + void *pad_pkt; +#if defined(CUSTOMER_HW5) + char dpc_log_previous[DHD_DPC_LOG_SZ]; + char dpc_log_current[DHD_DPC_LOG_SZ]; + int dpc_log_loops; +#endif /* CUSTOMER_HW5 */ +} dhd_bus_t; + +/* clkstate */ +#define CLK_NONE 0 +#define CLK_SDONLY 1 +#define CLK_PENDING 2 /* Not used yet */ +#define CLK_AVAIL 3 + +#define DHD_NOPMU(dhd) (FALSE) + +#ifdef DHD_DEBUG +static int qcount[NUMPRIO]; +static int tx_packets[NUMPRIO]; +#endif /* DHD_DEBUG */ + +/* Deferred transmit */ +const uint dhd_deferred_tx = 1; + +extern uint dhd_watchdog_ms; + +extern void dhd_os_wd_timer(void *bus, uint wdtick); + +/* Tx/Rx bounds */ +uint dhd_txbound; +uint dhd_rxbound; +uint dhd_txminmax = DHD_TXMINMAX; + +/* override the RAM size if possible */ +#define DONGLE_MIN_RAMSIZE (128 *1024) +int dhd_dongle_ramsize; + +uint dhd_doflow = TRUE; +uint dhd_dpcpoll = FALSE; + +module_param(dhd_doflow, uint, 0644); +module_param(dhd_dpcpoll, uint, 0644); + +static bool dhd_alignctl; + +static bool sd1idle; + +static bool retrydata; +#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) + +static uint watermark = 8; +static uint mesbusyctrl = 0; +static const uint firstread = DHD_FIRSTREAD; + +/* Retry count for register access failures */ +static const uint retry_limit = 2; + +/* Force even SD lengths (some host controllers mess up on odd bytes) */ +static bool forcealign; + +#define ALIGNMENT 4 + +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) +extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); +#endif + +#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) +#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD +#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ +#define PKTALIGN(osh, p, len, align) \ + do { \ + uintptr datalign; \ + datalign = (uintptr)PKTDATA((osh), (p)); \ + datalign = ROUNDUP(datalign, (align)) - datalign; \ + ASSERT(datalign < (align)); \ + ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ + if (datalign) \ + PKTPULL((osh), (p), (uint)datalign); \ + PKTSETLEN((osh), (p), (len)); \ + } while (0) + +/* Limit on rounding up frames */ +static const uint max_roundup = 512; + +/* Try doing readahead */ +static bool dhd_readahead; + +/* To check if there's window offered */ +#define DATAOK(bus) \ + (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ + (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) + +/* To check if there's window offered for ctrl frame */ +#define TXCTLOK(bus) \ + (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ + (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) + +/* Number of pkts available in dongle for data RX */ +#define DATABUFCNT(bus) \ + ((uint8)(bus->tx_max - bus->tx_seq) - 1) + +/* Macros to get register read/write status */ +/* NOTE: these assume a local dhdsdio_bus_t *bus! */ +#define R_SDREG(regvar, regaddr, retryvar) \ +do { \ + retryvar = 0; \ + do { \ + regvar = R_REG(bus->dhd->osh, regaddr); \ + } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ + if (retryvar) { \ + bus->regfails += (retryvar-1); \ + if (retryvar > retry_limit) { \ + DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \ + __FUNCTION__, __LINE__)); \ + regvar = 0; \ + } \ + } \ +} while (0) + +#define W_SDREG(regval, regaddr, retryvar) \ +do { \ + retryvar = 0; \ + do { \ + W_REG(bus->dhd->osh, regaddr, regval); \ + } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ + if (retryvar) { \ + bus->regfails += (retryvar-1); \ + if (retryvar > retry_limit) \ + DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \ + __FUNCTION__, __LINE__)); \ + } \ +} while (0) + +#define BUS_WAKE(bus) \ + do { \ + bus->idlecount = 0; \ + if ((bus)->sleeping) \ + dhdsdio_bussleep((bus), FALSE); \ + } while (0); + +/* + * pktavail interrupts from dongle to host can be managed in 3 different ways + * whenever there is a packet available in dongle to transmit to host. + * + * Mode 0: Dongle writes the software host mailbox and host is interrupted. + * Mode 1: (sdiod core rev >= 4) + * Device sets a new bit in the intstatus whenever there is a packet + * available in fifo. Host can't clear this specific status bit until all the + * packets are read from the FIFO. No need to ack dongle intstatus. + * Mode 2: (sdiod core rev >= 4) + * Device sets a bit in the intstatus, and host acks this by writing + * one to this bit. Dongle won't generate anymore packet interrupts + * until host reads all the packets from the dongle and reads a zero to + * figure that there are no more packets. No need to disable host ints. + * Need to ack the intstatus. + */ + +#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ +#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ +#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ + + +#define FRAME_AVAIL_MASK(bus) \ + ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) + +#define DHD_BUS SDIO_BUS + +#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) + +#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) + +#define GSPI_PR55150_BAILOUT + +#ifdef SDTEST +static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); +static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count); +#endif + +#ifdef DHD_DEBUG +static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); +static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); +static int dhdsdio_mem_dump(dhd_bus_t *bus); +#endif /* DHD_DEBUG */ + +static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap); +static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); + +static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); +static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); +static void dhdsdio_disconnect(void *ptr); +static bool dhdsdio_chipmatch(uint16 chipid); +static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, + void * regsva, uint16 devid); +static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); +static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); +static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, + bool reset_flag); + +static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size); +static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, + void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); +static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, + void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry); +static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt); +static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, + int prev_chain_total_len, bool last_chained_pkt, + int *pad_pkt_len, void **new_pkt); +static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt); + +static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); +static int _dhdsdio_download_firmware(dhd_bus_t *bus); + +static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); +static int dhdsdio_download_nvram(dhd_bus_t *bus); +#ifdef BCMEMBEDIMAGE +static int dhdsdio_download_code_array(dhd_bus_t *bus); +#endif +static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep); +static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok); +static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus); + +#ifdef WLMEDIA_HTSF +#include +extern uint32 dhd_get_htsf(void *dhd, int ifidx); +#endif /* WLMEDIA_HTSF */ + +static void +dhdsdio_tune_fifoparam(struct dhd_bus *bus) +{ + int err; + uint8 devctl, wm, mes; + + if (bus->sih->buscorerev >= 15) { + /* See .ppt in PR for these recommended values */ + if (bus->blocksize == 512) { + wm = OVERFLOW_BLKSZ512_WM; + mes = OVERFLOW_BLKSZ512_MES; + } else { + mes = bus->blocksize/4; + wm = bus->blocksize/4; + } + + watermark = wm; + mesbusyctrl = mes; + } else { + DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n", + bus->sih->buscorerev)); + return; + } + + /* Update watermark */ + if (wm > 0) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err); + + devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl |= SBSDIO_DEVCTL_F2WM_ENAB; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } + + /* Update MES */ + if (mes > 0) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, + (mes | SBSDIO_MESBUSYCTRL_ENAB), &err); + } + + DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n", + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err), + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err), + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err))); +} + +static void +dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size) +{ + int32 min_size = DONGLE_MIN_RAMSIZE; + /* Restrict the ramsize to user specified limit */ + DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", + dhd_dongle_ramsize, min_size)); + if ((dhd_dongle_ramsize > min_size) && + (dhd_dongle_ramsize < (int32)bus->orig_ramsize)) + bus->ramsize = dhd_dongle_ramsize; +} + +static int +dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) +{ + int err = 0; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, + (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); + if (!err) + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, + (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); + if (!err) + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, + (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); + return err; +} + + +#ifdef USE_OOB_GPIO1 +static int +dhdsdio_oobwakeup_init(dhd_bus_t *bus) +{ + uint32 val, addr, data; + + bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP); + + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + + /* Set device for gpio1 wakeup */ + bcmsdh_reg_write(bus->sdh, addr, 4, 2); + val = bcmsdh_reg_read(bus->sdh, data, 4); + val |= CC_CHIPCTRL2_GPIO1_WAKEUP; + bcmsdh_reg_write(bus->sdh, data, 4, val); + + bus->_oobwakeup = TRUE; + + return 0; +} +#endif /* USE_OOB_GPIO1 */ + +/* + * Query if FW is in SR mode + */ +static bool +dhdsdio_sr_cap(dhd_bus_t *bus) +{ + bool cap = FALSE; + uint32 core_capext, addr, data; + + + if (bus->sih->chip == BCM43430_CHIP_ID) { + /* check if fw initialized sr engine */ + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, sr_control1); + if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0) + cap = TRUE; + + return cap; + } + + if (bus->sih->chip == BCM4324_CHIP_ID) { + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + bcmsdh_reg_write(bus->sdh, addr, 4, 3); + core_capext = bcmsdh_reg_read(bus->sdh, data, 4); + } else if (bus->sih->chip == BCM4330_CHIP_ID) { + core_capext = FALSE; + } else if ((bus->sih->chip == BCM4335_CHIP_ID) || + (bus->sih->chip == BCM4339_CHIP_ID) || + (bus->sih->chip == BCM43349_CHIP_ID) || + (bus->sih->chip == BCM4345_CHIP_ID) || + (bus->sih->chip == BCM43454_CHIP_ID) || + (bus->sih->chip == BCM4354_CHIP_ID) || + (bus->sih->chip == BCM4356_CHIP_ID) || + (bus->sih->chip == BCM4350_CHIP_ID)) { + core_capext = TRUE; + } else { + core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); + core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK); + } + if (!(core_capext)) + return FALSE; + + if (bus->sih->chip == BCM4324_CHIP_ID) { + /* FIX: Should change to query SR control register instead */ + cap = TRUE; + } else if ((bus->sih->chip == BCM4335_CHIP_ID) || + (bus->sih->chip == BCM4339_CHIP_ID) || + (bus->sih->chip == BCM43349_CHIP_ID) || + (bus->sih->chip == BCM4345_CHIP_ID) || + (bus->sih->chip == BCM43454_CHIP_ID) || + (bus->sih->chip == BCM4354_CHIP_ID) || + (bus->sih->chip == BCM4356_CHIP_ID) || + (bus->sih->chip == BCM4350_CHIP_ID)) { + uint32 enabval = 0; + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); + enabval = bcmsdh_reg_read(bus->sdh, data, 4); + + if ((bus->sih->chip == BCM4350_CHIP_ID) || + (bus->sih->chip == BCM4345_CHIP_ID) || + (bus->sih->chip == BCM43454_CHIP_ID) || + (bus->sih->chip == BCM4356_CHIP_ID) || + (bus->sih->chip == BCM4354_CHIP_ID)) + enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE; + + if (enabval) + cap = TRUE; + } else { + data = bcmsdh_reg_read(bus->sdh, + SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4); + if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) + cap = TRUE; + } + + return cap; +} + +static int +dhdsdio_srwar_init(dhd_bus_t *bus) +{ + bcmsdh_gpio_init(bus->sdh); + +#ifdef USE_OOB_GPIO1 + dhdsdio_oobwakeup_init(bus); +#endif + + + return 0; +} + +static int +dhdsdio_sr_init(dhd_bus_t *bus) +{ + uint8 val; + int err = 0; + + if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) + dhdsdio_srwar_init(bus); + + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); + val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, + 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); + + /* Add CMD14 Support */ + dhdsdio_devcap_set(bus, + (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT)); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err); + + bus->_slpauto = dhd_slpauto ? TRUE : FALSE; + + bus->_srenab = TRUE; + + return 0; +} + +/* + * FIX: Be sure KSO bit is enabled + * Currently, it's defaulting to 0 which should be 1. + */ +static int +dhdsdio_clk_kso_init(dhd_bus_t *bus) +{ + uint8 val; + int err = 0; + + /* set flag */ + bus->kso = TRUE; + + /* + * Enable KeepSdioOn (KSO) bit for normal operation + * Default is 0 (4334A0) so set it. Fixed in B0. + */ + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL); + if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { + val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); + if (err) + DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err)); + } + + return 0; +} + +#define KSO_DBG(x) +#define KSO_WAIT_US 50 +#define KSO_WAIT_MS 1 +#define KSO_SLEEP_RETRY_COUNT 20 +#define ERROR_BCME_NODEVICE_MAX 1 + +#if defined(CUSTOMER_HW5) +#define MAX_KSO_ATTEMPTS 64 +#else +#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) +#endif +static int +dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) +{ + uint8 wr_val = 0, rd_val, cmp_val, bmask; + int err = 0; + int try_cnt = 0; + + KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); + + wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); + + if (on) { + cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; + bmask = cmp_val; + + OSL_SLEEP(3); + } else { + /* Put device to sleep, turn off KSO */ + cmp_val = 0; + bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; + } + + do { + rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); + if (((rd_val & bmask) == cmp_val) && !err) + break; + + KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); + + if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) { + OSL_SLEEP(KSO_WAIT_MS); + } else + OSL_DELAY(KSO_WAIT_US); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); + } while (try_cnt++ < MAX_KSO_ATTEMPTS); + + + if (try_cnt > 2) + KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", + __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); + + if (try_cnt > MAX_KSO_ATTEMPTS) { + DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", + __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); + } + return err; +} + +static int +dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) +{ + int err = 0; + + if (on == FALSE) { + + BUS_WAKE(bus); + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__, + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err))); + dhdsdio_clk_kso_enab(bus, FALSE); + } else { + DHD_ERROR(("%s: KSO enable\n", __FUNCTION__)); + + /* Make sure we have SD bus access */ + if (bus->clkstate == CLK_NONE) { + DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__)); + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } + + dhdsdio_clk_kso_enab(bus, TRUE); + + DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__, + dhdsdio_sleepcsr_get(bus))); + } + + bus->kso = on; + BCM_REFERENCE(err); + + return 0; +} + +static uint8 +dhdsdio_sleepcsr_get(dhd_bus_t *bus) +{ + int err = 0; + uint8 val = 0; + + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); + if (err) + DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err)); + + return val; +} + +uint8 +dhdsdio_devcap_get(dhd_bus_t *bus) +{ + return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL); +} + +static int +dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap) +{ + int err = 0; + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err); + if (err) + DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err)); + + return 0; +} + +static int +dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) +{ + int err = 0, retry; + uint8 val; + + retry = 0; + if (on == TRUE) { + /* Enter Sleep */ + + /* Be sure we request clk before going to sleep + * so we can wake-up with clk request already set + * else device can go back to sleep immediately + */ + if (!SLPAUTO_ENAB(bus)) + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + else { + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if ((val & SBSDIO_CSR_MASK) == 0) { + DHD_ERROR(("%s: No clock before enter sleep:0x%x\n", + __FUNCTION__, val)); + + /* Reset clock request */ + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + SBSDIO_ALP_AVAIL_REQ, &err); + DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__, + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err))); + } + } + + DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__, + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err))); +#ifdef USE_CMD14 + err = bcmsdh_sleep(bus->sdh, TRUE); +#else + err = dhdsdio_clk_kso_enab(bus, FALSE); + if (OOB_WAKEUP_ENAB(bus)) + { + err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ + } +#endif /* USE_CMD14 */ + } else { + /* Exit Sleep */ + /* Make sure we have SD bus access */ + if (bus->clkstate == CLK_NONE) { + DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__)); + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } + + if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), + GPIO_DEV_SRSTATE_TIMEOUT); + + if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { + DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n")); + } + } +#ifdef USE_CMD14 + err = bcmsdh_sleep(bus->sdh, FALSE); + if (SLPAUTO_ENAB(bus) && (err != 0)) { + OSL_DELAY(10000); + DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__)); + + /* Toggle sleep to resync with host and device */ + err = bcmsdh_sleep(bus->sdh, TRUE); + OSL_DELAY(10000); + err = bcmsdh_sleep(bus->sdh, FALSE); + + if (err) { + OSL_DELAY(10000); + DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__)); + + /* Toggle sleep to resync with host and device */ + err = bcmsdh_sleep(bus->sdh, TRUE); + OSL_DELAY(10000); + err = bcmsdh_sleep(bus->sdh, FALSE); + if (err) { + DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__)); + DHD_ERROR(("%s: FATAL: Device non-response!\n", + __FUNCTION__)); + err = 0; + } + } + } +#else + if (OOB_WAKEUP_ENAB(bus)) + { + err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ + } + do { + err = dhdsdio_clk_kso_enab(bus, TRUE); + if (err) + OSL_SLEEP(10); + } while ((err != 0) && (++retry < 3)); + + if (err != 0) { + DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry)); + err = 0; /* continue anyway */ + } +#endif /* !USE_CMD14 */ + + if (err == 0) { + uint8 csr; + + /* Wait for device ready during transition to wake-up */ + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + (((csr = dhdsdio_sleepcsr_get(bus)) & + SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != + (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); + + DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr)); + + if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) { + DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n", + __FUNCTION__, csr)); + err = BCME_NODEVICE; + } + + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != + (SBSDIO_HT_AVAIL)), (10000)); + + DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr)); + if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) { + DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n", + __FUNCTION__, csr)); + err = BCME_NODEVICE; + } + } + } + + /* Update if successful */ + if (err == 0) + bus->kso = on ? FALSE : TRUE; + else { + DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n", + __FUNCTION__, bus->kso, on, err)); + if (!on && retry > 2) + bus->kso = FALSE; + } + + return err; +} + +/* Turn backplane clock on or off */ +static int +dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) +{ +#define HT_AVAIL_ERROR_MAX 10 + static int ht_avail_error = 0; + int err; + uint8 clkctl, clkreq, devctl; + bcmsdh_info_t *sdh; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + clkctl = 0; + sdh = bus->sdh; + + + if (!KSO_ENAB(bus)) + return BCME_OK; + + if (SLPAUTO_ENAB(bus)) { + bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); + return BCME_OK; + } + + if (on) { + /* Request HT Avail */ + clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; + + + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); + if (err) { + ht_avail_error++; + if (ht_avail_error < HT_AVAIL_ERROR_MAX) { + DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + else if (ht_avail_error == HT_AVAIL_ERROR_MAX) { +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + "%s ht_avail_error = %d\n", __func__, ht_avail_error); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + dhd_os_send_hang_message(bus->dhd); + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ + return BCME_ERROR; + } else { + ht_avail_error = 0; + } + + + /* Check current status */ + clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (err) { + DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err)); + return BCME_ERROR; + } + +#if !defined(OOB_INTR_ONLY) + /* Go to pending and await interrupt if appropriate */ + if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { + /* Allow only clock-available interrupt */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + if (err) { + DHD_ERROR(("%s: Devctl access error setting CA: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + + devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + DHD_INFO(("CLKCTL: set PENDING\n")); + bus->clkstate = CLK_PENDING; + return BCME_OK; + } else +#endif /* !defined (OOB_INTR_ONLY) */ + { + if (bus->clkstate == CLK_PENDING) { + /* Cancel CA-only interrupt filter */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } + } + + /* Otherwise, wait here (polling) for HT Avail */ + if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err)), + !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); + } + if (err) { + DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); + return BCME_ERROR; + } + if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { + DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n", + __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl)); + return BCME_ERROR; + } + + /* Mark clock available */ + bus->clkstate = CLK_AVAIL; + DHD_INFO(("CLKCTL: turned ON\n")); + +#if defined(DHD_DEBUG) + if (bus->alp_only == TRUE) { +#if !defined(BCMLXSDMMC) + if (!SBSDIO_ALPONLY(clkctl)) { + DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__)); + } +#endif /* !defined(BCMLXSDMMC) */ + } else { + if (SBSDIO_ALPONLY(clkctl)) { + DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__)); + } + } +#endif /* defined (DHD_DEBUG) */ + + bus->activity = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ + } else { + clkreq = 0; + + if (bus->clkstate == CLK_PENDING) { + /* Cancel CA-only interrupt filter */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } + + bus->clkstate = CLK_SDONLY; + if (!SR_ENAB(bus)) { + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); + DHD_INFO(("CLKCTL: turned OFF\n")); + if (err) { + DHD_ERROR(("%s: Failed access turning clock off: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } + } + return BCME_OK; +} + +/* Change idle/active SD state */ +static int +dhdsdio_sdclk(dhd_bus_t *bus, bool on) +{ + int err; + int32 iovalue; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (on) { + if (bus->idleclock == DHD_IDLE_STOP) { + /* Turn on clock and restore mode */ + iovalue = 1; + err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error enabling sd_clock: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + + iovalue = bus->sd_mode; + err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error changing sd_mode: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } else if (bus->idleclock != DHD_IDLE_ACTIVE) { + /* Restore clock speed */ + iovalue = bus->sd_divisor; + err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error restoring sd_divisor: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } + bus->clkstate = CLK_SDONLY; + } else { + /* Stop or slow the SD clock itself */ + if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { + DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n", + __FUNCTION__, bus->sd_divisor, bus->sd_mode)); + return BCME_ERROR; + } + if (bus->idleclock == DHD_IDLE_STOP) { + if (sd1idle) { + /* Change to SD1 mode and turn off clock */ + iovalue = 1; + err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error changing sd_clock: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } + + iovalue = 0; + err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error disabling sd_clock: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } else if (bus->idleclock != DHD_IDLE_ACTIVE) { + /* Set divisor to idle value */ + iovalue = bus->idleclock; + err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, + &iovalue, sizeof(iovalue), TRUE); + if (err) { + DHD_ERROR(("%s: error changing sd_divisor: %d\n", + __FUNCTION__, err)); + return BCME_ERROR; + } + } + bus->clkstate = CLK_NONE; + } + + return BCME_OK; +} + +/* Transition SD and backplane clock readiness */ +static int +dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) +{ + int ret = BCME_OK; +#ifdef DHD_DEBUG + uint oldstate = bus->clkstate; +#endif /* DHD_DEBUG */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Early exit if we're already there */ + if (bus->clkstate == target) { + if (target == CLK_AVAIL) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + bus->activity = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ + } + return ret; + } + + switch (target) { + case CLK_AVAIL: + /* Make sure SD clock is available */ + if (bus->clkstate == CLK_NONE) + dhdsdio_sdclk(bus, TRUE); + /* Now request HT Avail on the backplane */ + ret = dhdsdio_htclk(bus, TRUE, pendok); + if (ret == BCME_OK) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + bus->activity = TRUE; +#ifdef DHD_USE_IDLECOUNT + bus->idlecount = 0; +#endif /* DHD_USE_IDLECOUNT */ + } + break; + + case CLK_SDONLY: + /* Remove HT request, or bring up SD clock */ + if (bus->clkstate == CLK_NONE) + ret = dhdsdio_sdclk(bus, TRUE); + else if (bus->clkstate == CLK_AVAIL) + ret = dhdsdio_htclk(bus, FALSE, FALSE); + else + DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", + bus->clkstate, target)); + if (ret == BCME_OK) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + } + break; + + case CLK_NONE: + /* Make sure to remove HT request */ + if (bus->clkstate == CLK_AVAIL) + ret = dhdsdio_htclk(bus, FALSE, FALSE); + /* Now remove the SD clock */ + ret = dhdsdio_sdclk(bus, FALSE); +#ifdef DHD_DEBUG + if (dhd_console_ms == 0) +#endif /* DHD_DEBUG */ + if (bus->poll == 0) + dhd_os_wd_timer(bus->dhd, 0); + break; + } +#ifdef DHD_DEBUG + DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); +#endif /* DHD_DEBUG */ + + return ret; +} + +static int +dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) +{ + int err = 0; + bcmsdh_info_t *sdh = bus->sdh; + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + + DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", + (sleep ? "SLEEP" : "WAKE"), + (bus->sleeping ? "SLEEP" : "WAKE"))); + + if (bus->dhd->hang_was_sent) + return BCME_ERROR; + + /* Done if we're already in the requested state */ + if (sleep == bus->sleeping) + return BCME_OK; + + /* Going to sleep: set the alarm and turn off the lights... */ + if (sleep) { + /* Don't sleep if something is pending */ +#if defined(CUSTOMER_HW5) + if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes || + bus->ctrl_frame_stat) +#else + if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) +#endif + return BCME_BUSY; + + + if (!SLPAUTO_ENAB(bus)) { + /* Disable SDIO interrupts (no longer interested) */ + bcmsdh_intr_disable(bus->sdh); + + /* Make sure the controller has the bus up */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Tell device to start using OOB wakeup */ + W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); + + /* Turn off our contribution to the HT clock request */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); + + /* Isolate the bus */ + if (bus->sih->chip != BCM4329_CHIP_ID && + bus->sih->chip != BCM4319_CHIP_ID) { + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, + SBSDIO_DEVCTL_PADS_ISO, NULL); + } + } else { + /* Leave interrupts enabled since device can exit sleep and + * interrupt host + */ + err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */); + } + + /* Change state */ + bus->sleeping = TRUE; +#if defined(SUPPORT_P2P_GO_PS) + wake_up(&bus->bus_sleep); +#endif /* LINUX && SUPPORT_P2P_GO_PS */ + } else { + /* Waking up: bus power up is ok, set local state */ + + if (!SLPAUTO_ENAB(bus)) { + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err); + + /* Force pad isolation off if possible (in case power never toggled) */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); + + + /* Make sure the controller has the bus up */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Send misc interrupt to indicate OOB not needed */ + W_SDREG(0, ®s->tosbmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); + + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); + + /* Make sure we have SD bus access */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + + /* Enable interrupts again */ + if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { + bus->intdis = FALSE; + bcmsdh_intr_enable(bus->sdh); + } + } else { + err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */); + } + + if (err == 0) { + /* Change state */ + bus->sleeping = FALSE; + } + } + + return err; +} + + +#if defined(OOB_INTR_ONLY) +void +dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) +{ +#if defined(HW_OOB) + bcmsdh_enable_hw_oob_intr(bus->sdh, enable); +#else + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (enable == TRUE) { + + /* Tell device to start using OOB wakeup */ + W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); + + } else { + /* Send misc interrupt to indicate OOB not needed */ + W_SDREG(0, ®s->tosbmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); + } + + /* Turn off our contribution to the HT clock request */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); +#endif /* !defined(HW_OOB) */ +} +#endif + +int +dhd_bus_txdata(struct dhd_bus *bus, void *pkt) +{ + int ret = BCME_ERROR; + osl_t *osh; + uint datalen, prec; +#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP) + uint8 *dump_data; + uint16 protocol; +#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + osh = bus->dhd->osh; + datalen = PKTLEN(osh, pkt); + +#ifdef SDTEST + /* Push the test header if doing loopback */ + if (bus->ext_loop) { + uint8* data; + PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); + data = PKTDATA(osh, pkt); + *data++ = SDPCM_TEST_ECHOREQ; + *data++ = (uint8)bus->loopid++; + *data++ = (datalen >> 0); + *data++ = (datalen >> 8); + datalen += SDPCM_TEST_HDRLEN; + } +#else /* SDTEST */ + BCM_REFERENCE(datalen); +#endif /* SDTEST */ + +#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP) + dump_data = PKTDATA(osh, pkt); + dump_data += 4; /* skip 4 bytes header */ + protocol = (dump_data[12] << 8) | dump_data[13]; + + if (protocol == ETHER_TYPE_802_1X) { + DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n", + dump_data[14], dump_data[15], dump_data[30])); + } +#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */ + +#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP) + { + int i; + DHD_ERROR(("TX DUMP\n")); + + for (i = 0; i < (datalen - 4); i++) { + DHD_ERROR(("%02X ", dump_data[i])); + if ((i & 15) == 15) + printk("\n"); + } + DHD_ERROR(("\n")); + } +#endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */ + + prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); + + /* Check for existing queue, current flow-control, pending event, or pending clock */ + if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || + (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || + (bus->clkstate != CLK_AVAIL)) { + bool deq_ret; + int pkq_len; + + DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq))); + bus->fcqueued++; + + /* Priority based enq */ + dhd_os_sdlock_txq(bus->dhd); + deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec); + dhd_os_sdunlock_txq(bus->dhd); + + if (!deq_ret) { +#ifdef PROP_TXSTATUS + if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0) +#endif /* PROP_TXSTATUS */ + { +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + dhd_txcomplete(bus->dhd, pkt, FALSE); + PKTFREE(osh, pkt, TRUE); + } + ret = BCME_NORESOURCE; + } else + ret = BCME_OK; + + dhd_os_sdlock_txq(bus->dhd); + pkq_len = pktq_len(&bus->txq); + dhd_os_sdunlock_txq(bus->dhd); + if (pkq_len >= FCHI) { + bool wlfc_enabled = FALSE; +#ifdef PROP_TXSTATUS + wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) != + WLFC_UNSUPPORTED); +#endif + if (!wlfc_enabled && dhd_doflow) { + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); + } + } + +#ifdef DHD_DEBUG + dhd_os_sdlock_txq(bus->dhd); + if (pktq_plen(&bus->txq, prec) > qcount[prec]) + qcount[prec] = pktq_plen(&bus->txq, prec); + dhd_os_sdunlock_txq(bus->dhd); +#endif + + /* Schedule DPC if needed to send queued packet(s) */ + if (dhd_deferred_tx && !bus->dpc_sched) { + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + } + } else { + int chan = SDPCM_DATA_CHANNEL; + +#ifdef SDTEST + chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL); +#endif + /* Lock: we're about to use shared data/code (and SDIO) */ + dhd_os_sdlock(bus->dhd); + + /* Otherwise, send it now */ + BUS_WAKE(bus); + /* Make sure back plane ht clk is on, no pending allowed */ + dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); + + ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE); + + if (ret != BCME_OK) + bus->dhd->tx_errors++; + else + bus->dhd->dstats.tx_bytes += datalen; + + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + } + + return ret; +} + +/* align packet data pointer and packet length to n-byte boundary, process packet headers, + * a new packet may be allocated if there is not enough head and/or tail from for padding. + * the caller is responsible for updating the glom size in the head packet (when glom is + * used) + * + * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter + * is taken in tx glom mode only + * + * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment + * padding, NULL if not needed, the caller is responsible for freeing the new packet + * + * return: positive value - length of the packet, including head and tail padding + * negative value - errors + */ +static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, + int prev_chain_total_len, bool last_chained_pkt, + int *pad_pkt_len, void **new_pkt) +{ + osl_t *osh; + uint8 *frame; + int pkt_len; + int modulo; + int head_padding; + int tail_padding = 0; + uint32 swheader; + uint32 swhdr_offset; + bool alloc_new_pkt = FALSE; + uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; + + *new_pkt = NULL; + osh = bus->dhd->osh; + +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + + /* Add space for the SDPCM hardware/software headers */ + PKTPUSH(osh, pkt, sdpcm_hdrlen); + ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); + + frame = (uint8*)PKTDATA(osh, pkt); + pkt_len = (uint16)PKTLEN(osh, pkt); + +#ifdef WLMEDIA_HTSF + frame = (uint8*)PKTDATA(osh, pkt); + if (PKTLEN(osh, pkt) >= 100) { + htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12); + if (htsf_ts->magic == HTSFMAGIC) { + htsf_ts->c20 = get_cycles(); + htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); + } + } +#endif /* WLMEDIA_HTSF */ +#ifdef DHD_DEBUG + if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) + tx_packets[PKTPRIO(pkt)]++; +#endif /* DHD_DEBUG */ + + /* align the data pointer, allocate a new packet if there is not enough space (new + * packet data pointer will be aligned thus no padding will be needed) + */ + head_padding = (ulong)frame % DHD_SDALIGN; + if (PKTHEADROOM(osh, pkt) < head_padding) { + head_padding = 0; + alloc_new_pkt = TRUE; + } else { + uint cur_chain_total_len; + int chain_tail_padding = 0; + + /* All packets need to be aligned by DHD_SDALIGN */ + modulo = (pkt_len + head_padding) % DHD_SDALIGN; + tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; + + /* Total pkt chain length needs to be aligned by block size, + * unless it is a single pkt chain with total length less than one block size, + * which we prefer sending by byte mode. + * + * Do the chain alignment here if + * 1. This is the last pkt of the chain of multiple pkts or a single pkt. + * 2-1. This chain is of multiple pkts, or + * 2-2. This is a single pkt whose size is longer than one block size. + */ + cur_chain_total_len = prev_chain_total_len + + (head_padding + pkt_len + tail_padding); + if (last_chained_pkt && bus->blocksize != 0 && + (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { + modulo = cur_chain_total_len % bus->blocksize; + chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; + } + +#ifdef DHDENABLE_TAILPAD + if (PKTTAILROOM(osh, pkt) < tail_padding) { + /* We don't have tail room to align by DHD_SDALIGN */ + alloc_new_pkt = TRUE; + bus->tx_tailpad_pktget++; + } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) { + /* We have tail room for tail_padding of this pkt itself, but not for + * total pkt chain alignment by block size. + * Use the padding packet to avoid memory copy if applicable, + * otherwise, just allocate a new pkt. + */ + if (bus->pad_pkt) { + *pad_pkt_len = chain_tail_padding; + bus->tx_tailpad_chain++; + } else { + alloc_new_pkt = TRUE; + bus->tx_tailpad_pktget++; + } + } else + /* This last pkt's tailroom is sufficient to hold both tail_padding + * of the pkt itself and chain_tail_padding of total pkt chain + */ +#endif /* DHDENABLE_TAILPAD */ + tail_padding += chain_tail_padding; + } + + DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n", + __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len)); + + if (alloc_new_pkt) { + void *tmp_pkt; + int newpkt_size; + int cur_total_len; + + ASSERT(*pad_pkt_len == 0); + + DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__)); + + /* head pointer is aligned now, no padding needed */ + head_padding = 0; + + /* update the tail padding as it depends on the head padding, since a new packet is + * allocated, the head padding is non longer needed and packet length is chagned + */ + + cur_total_len = prev_chain_total_len + pkt_len; + if (last_chained_pkt && bus->blocksize != 0 && + (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { + modulo = cur_total_len % bus->blocksize; + tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; + } + else { + modulo = pkt_len % DHD_SDALIGN; + tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; + } + + newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN; + bus->dhd->tx_realloc++; + tmp_pkt = PKTGET(osh, newpkt_size, TRUE); + if (tmp_pkt == NULL) { + DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size)); + return BCME_NOMEM; + } + PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN); + bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt)); + *new_pkt = tmp_pkt; + pkt = tmp_pkt; + } + + if (head_padding) + PKTPUSH(osh, pkt, head_padding); + + frame = (uint8*)PKTDATA(osh, pkt); + bzero(frame, head_padding + sdpcm_hdrlen); + pkt_len = (uint16)PKTLEN(osh, pkt); + + /* the header has the followming format + * 4-byte HW frame tag: length, ~length (for glom this is the total length) + * + * 8-byte HW extesion flags (glom mode only) as the following: + * 2-byte packet length, excluding HW tag and padding + * 2-byte frame channel and frame flags (e.g. next frame following) + * 2-byte header length + * 2-byte tail padding size + * + * 8-byte SW frame tags as the following + * 4-byte flags: host tx seq, channel, data offset + * 4-byte flags: TBD + */ + + swhdr_offset = SDPCM_FRAMETAG_LEN; + + /* hardware frame tag: + * + * in tx-glom mode, dongle only checks the hardware frame tag in the first + * packet and sees it as the total lenght of the glom (including tail padding), + * for each packet in the glom, the packet length needs to be updated, (see + * below PKTSETLEN) + * + * in non tx-glom mode, PKTLEN still need to include tail padding as to be + * referred to in sdioh_request_buffer(). The tail length will be excluded in + * dhdsdio_txpkt_postprocess(). + */ + *(uint16*)frame = (uint16)htol16(pkt_len); + *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len); + pkt_len += tail_padding; + + /* hardware extesion flags */ + if (bus->txglom_enable) { + uint32 hwheader1; + uint32 hwheader2; + + swhdr_offset += SDPCM_HWEXT_LEN; + hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) | + (last_chained_pkt << 24); + hwheader2 = (tail_padding) << 16; + htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); + htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); + } + PKTSETLEN((osh), (pkt), (pkt_len)); + + /* software frame tags */ + swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) + | (txseq % SDPCM_SEQUENCE_WRAP) | + (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); + htol32_ua_store(swheader, frame + swhdr_offset); + htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader)); + + return pkt_len; +} + +static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt) +{ + osl_t *osh; + uint8 *frame; + int data_offset; + int tail_padding; + int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0); + + (void)osh; + osh = bus->dhd->osh; + + /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */ + frame = (uint8*)PKTDATA(osh, pkt); + + DHD_INFO(("%s PKTLEN before postprocess %d", + __FUNCTION__, PKTLEN(osh, pkt))); + + /* PKTLEN still includes tail_padding, so exclude it. + * We shall have head_padding + original pkt_len for PKTLEN afterwards. + */ + if (bus->txglom_enable) { + /* txglom pkts have tail_padding length in HW ext header */ + tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16; + PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding); + DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n", + tail_padding, PKTLEN(osh, pkt))); + } else { + /* non-txglom pkts have head_padding + original pkt length in HW frame tag. + * We cannot refer to this field for txglom pkts as the first pkt of the chain will + * have the field for the total length of the chain. + */ + PKTSETLEN(osh, pkt, *(uint16*)frame); + DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n", + *(uint16*)frame, PKTLEN(osh, pkt))); + } + + data_offset = ltoh32_ua(frame + swhdr_offset); + data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; + /* Get rid of sdpcm header + head_padding */ + PKTPULL(osh, pkt, data_offset); + + DHD_INFO(("%s data_offset %d, PKTLEN %d\n", + __FUNCTION__, data_offset, PKTLEN(osh, pkt))); + + return BCME_OK; +} + +static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt) +{ + int i; + int ret = 0; + osl_t *osh; + bcmsdh_info_t *sdh; + void *pkt = NULL; + void *pkt_chain; + int total_len = 0; + void *head_pkt = NULL; + void *prev_pkt = NULL; + int pad_pkt_len = 0; + int new_pkt_num = 0; + void *new_pkts[MAX_TX_PKTCHAIN_CNT]; + bool wlfc_enabled = FALSE; + + if (bus->dhd->dongle_reset) + return BCME_NOTREADY; + + sdh = bus->sdh; + osh = bus->dhd->osh; + /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */ + new_pkts[0] = NULL; + + for (i = 0; i < num_pkt; i++) { + int pkt_len; + bool last_pkt; + void *new_pkt = NULL; + + pkt = pkts[i]; + ASSERT(pkt); + last_pkt = (i == num_pkt - 1); + pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i, + total_len, last_pkt, &pad_pkt_len, &new_pkt); + if (pkt_len <= 0) + goto done; + if (new_pkt) { + pkt = new_pkt; + new_pkts[new_pkt_num++] = new_pkt; + } + total_len += pkt_len; + + PKTSETNEXT(osh, pkt, NULL); + /* insert the packet into the list */ + head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt); + prev_pkt = pkt; + + } + + /* Update the HW frame tag (total length) in the first pkt of the glom */ + if (bus->txglom_enable) { + uint8 *frame; + + total_len += pad_pkt_len; + frame = (uint8*)PKTDATA(osh, head_pkt); + *(uint16*)frame = (uint16)htol16(total_len); + *(((uint16*)frame) + 1) = (uint16)htol16(~total_len); + + } + + /* if a padding packet if needed, insert it to the end of the link list */ + if (pad_pkt_len) { + PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len); + PKTSETNEXT(osh, pkt, bus->pad_pkt); + } + + /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet + * parameter is not NULL, for non packet chian we pass NULL pkt pointer + * so it will take the aligned length and buffer pointer. + */ + pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL; + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES); + if (ret == BCME_OK) + bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP; + + /* if a padding packet was needed, remove it from the link list as it not a data pkt */ + if (pad_pkt_len && pkt) + PKTSETNEXT(osh, pkt, NULL); + +done: + pkt = head_pkt; + while (pkt) { + void *pkt_next = PKTNEXT(osh, pkt); + PKTSETNEXT(osh, pkt, NULL); + dhdsdio_txpkt_postprocess(bus, pkt); + pkt = pkt_next; + } + + /* new packets might be allocated due to insufficient room for padding, but we + * still have to indicate the original packets to upper layer + */ + for (i = 0; i < num_pkt; i++) { + pkt = pkts[i]; + wlfc_enabled = FALSE; +#ifdef PROP_TXSTATUS + if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) { + wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) != + WLFC_UNSUPPORTED); + } +#endif /* PROP_TXSTATUS */ + if (!wlfc_enabled) { + PKTSETNEXT(osh, pkt, NULL); + dhd_txcomplete(bus->dhd, pkt, ret != 0); + if (free_pkt) + PKTFREE(osh, pkt, TRUE); + } + } + + for (i = 0; i < new_pkt_num; i++) + PKTFREE(osh, new_pkts[i], TRUE); + + return ret; +} + +static uint +dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) +{ + uint cnt = 0; + uint8 tx_prec_map; + uint16 txpktqlen = 0; + uint32 intstatus = 0; + uint retries = 0; + osl_t *osh; + uint datalen = 0; + dhd_pub_t *dhd = bus->dhd; + sdpcmd_regs_t *regs = bus->regs; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + return BCME_NODEVICE; + } + + osh = dhd->osh; + tx_prec_map = ~bus->flowcontrol; +#ifdef DHD_LOSSLESS_ROAMING + tx_prec_map &= dhd->dequeue_prec_map; +#endif /* DHD_LOSSLESS_ROAMING */ + for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) { + int i; + int num_pkt = 1; + void *pkts[MAX_TX_PKTCHAIN_CNT]; + int prec_out; + + dhd_os_sdlock_txq(bus->dhd); + if (bus->txglom_enable) { + num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize); + num_pkt = MIN(num_pkt, ARRAYSIZE(pkts)); + } + num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map)); + for (i = 0; i < num_pkt; i++) { + pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); + datalen += PKTLEN(osh, pkts[i]); + } + dhd_os_sdunlock_txq(bus->dhd); + + if (i == 0) + break; + if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK) + dhd->tx_errors++; + else + dhd->dstats.tx_bytes += datalen; + cnt += i; + + /* In poll mode, need to check for other events */ + if (!bus->intr && cnt) + { + /* Check device status, signal pending interrupt */ + R_SDREG(intstatus, ®s->intstatus, retries); + bus->f2txdata++; + if (bcmsdh_regfail(bus->sdh)) + break; + if (intstatus & bus->hostintmask) + bus->ipend = TRUE; + } + + } + + dhd_os_sdlock_txq(bus->dhd); + txpktqlen = pktq_len(&bus->txq); + dhd_os_sdunlock_txq(bus->dhd); + + /* Do flow-control if needed */ + if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) { + bool wlfc_enabled = FALSE; +#ifdef PROP_TXSTATUS + wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED); +#endif + if (!wlfc_enabled && dhd_doflow && dhd->txoff) { + dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); + } + } + + return cnt; +} + +static void +dhdsdio_sendpendctl(dhd_bus_t *bus) +{ + bcmsdh_info_t *sdh = bus->sdh; + int ret; + uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; + + if (bus->txglom_enable) + frame_seq += SDPCM_HWEXT_LEN; + + if (*frame_seq != bus->tx_seq) { + DHD_INFO(("%s IOCTL frame seq lag detected!" + " frm_seq:%d != bus->tx_seq:%d, corrected\n", + __FUNCTION__, *frame_seq, bus->tx_seq)); + *frame_seq = bus->tx_seq; + } + + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, + NULL, NULL, NULL, 1); + if (ret == BCME_OK) + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + + bus->ctrl_frame_stat = FALSE; + dhd_wait_event_wakeup(bus->dhd); +} + +int +dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) +{ + static int err_nodevice = 0; + uint8 *frame; + uint16 len; + uint32 swheader; + bcmsdh_info_t *sdh = bus->sdh; + uint8 doff = 0; + int ret = -1; + uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) + return -EIO; + + /* 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) */ + if (dhd_alignctl) { + if ((doff = ((uintptr)frame % DHD_SDALIGN))) { + frame -= doff; + len += doff; + msglen += doff; + bzero(frame, doff + sdpcm_hdrlen); + } + ASSERT(doff < DHD_SDALIGN); + } + doff += sdpcm_hdrlen; + + /* Round send length to next SDIO block */ + if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { + uint16 pad = bus->blocksize - (len % bus->blocksize); + if ((pad <= bus->roundup) && (pad < bus->blocksize)) + len += pad; + } else if (len % DHD_SDALIGN) { + len += DHD_SDALIGN - (len % DHD_SDALIGN); + } + + /* Satisfy length-alignment requirements */ + if (forcealign && (len & (ALIGNMENT - 1))) + len = ROUNDUP(len, ALIGNMENT); + + ASSERT(ISALIGNED((uintptr)frame, 2)); + + + /* Need to lock here to protect txseq and SDIO tx calls */ + dhd_os_sdlock(bus->dhd); + + BUS_WAKE(bus); + + /* Make sure backplane clock is on */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ + *(uint16*)frame = htol16((uint16)msglen); + *(((uint16*)frame) + 1) = htol16(~msglen); + + if (bus->txglom_enable) { + uint32 hwheader1, hwheader2; + /* 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); + htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); + htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + + SDPCM_HWEXT_LEN + sizeof(swheader)); + + hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24); + hwheader2 = (len - (msglen)) << 16; + htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); + htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); + + *(uint16*)frame = htol16(len); + *(((uint16*)frame) + 1) = htol16(~(len)); + } else { + /* 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); + htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); + htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); + } + if (!TXCTLOK(bus)) { + DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", + __FUNCTION__, bus->tx_max, bus->tx_seq)); + bus->ctrl_frame_stat = TRUE; + /* Send from dpc */ + bus->ctrl_frame_buf = frame; + bus->ctrl_frame_len = len; + + if (!bus->dpc_sched) { + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + } + if (bus->ctrl_frame_stat) { + dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); + } + + if (bus->ctrl_frame_stat == FALSE) { + DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); + ret = 0; + } else { + bus->dhd->txcnt_timeout++; + if (!bus->dhd->hang_was_sent) { + DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", + __FUNCTION__, bus->dhd->txcnt_timeout)); + } + ret = -1; + bus->ctrl_frame_stat = FALSE; + goto done; + } + } + + bus->dhd->txcnt_timeout = 0; + bus->ctrl_frame_stat = TRUE; + + if (ret == -1) { +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_CTL_ON()) { + prhex("Tx Frame", frame, len); + } else if (DHD_HDRS_ON()) { + prhex("TxHdr", frame, MIN(len, 16)); + } +#endif + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + frame, len, NULL, NULL, NULL, TXRETRIES); + if (ret == BCME_OK) + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + } + bus->ctrl_frame_stat = FALSE; + +done: + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + + if (ret) + bus->dhd->tx_ctlerrs++; + else + bus->dhd->tx_ctlpkts++; + + if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) + return -ETIMEDOUT; + + if (ret == BCME_NODEVICE) + err_nodevice++; + else + err_nodevice = 0; + + return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0; +} + +int +dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) +{ + int timeleft; + uint rxlen = 0; + bool pending; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) + return -EIO; + + /* Wait until control frame is available */ + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); + + dhd_os_sdlock(bus->dhd); + rxlen = bus->rxlen; + bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); + bus->rxlen = 0; + dhd_os_sdunlock(bus->dhd); + + if (rxlen) { + DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", + __FUNCTION__, rxlen, msglen)); + } else if (timeleft == 0) { +#ifdef DHD_DEBUG + uint32 status, retry = 0; + R_SDREG(status, &bus->regs->intstatus, retry); + DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n", + __FUNCTION__, status)); +#else + DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); +#endif /* DHD_DEBUG */ +#ifdef DHD_DEBUG + dhd_os_sdlock(bus->dhd); + dhdsdio_checkdied(bus, NULL, 0); + dhd_os_sdunlock(bus->dhd); +#endif /* DHD_DEBUG */ + } else if (pending == TRUE) { + /* signal pending */ + DHD_ERROR(("%s: signal pending\n", __FUNCTION__)); + return -EINTR; + + } else { + DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); +#ifdef DHD_DEBUG + dhd_os_sdlock(bus->dhd); + dhdsdio_checkdied(bus, NULL, 0); + dhd_os_sdunlock(bus->dhd); +#endif /* DHD_DEBUG */ + } + if (timeleft == 0) { + if (rxlen == 0) + bus->dhd->rxcnt_timeout++; + DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__, + bus->dhd->rxcnt_timeout, rxlen)); + } + else + bus->dhd->rxcnt_timeout = 0; + + if (rxlen) + bus->dhd->rx_ctlpkts++; + else + bus->dhd->rx_ctlerrs++; + + if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) + return -ETIMEDOUT; + + if (bus->dhd->dongle_trap_occured) + return -EREMOTEIO; + + return rxlen ? (int)rxlen : -EIO; +} + +/* IOVar table */ +enum { + IOV_INTR = 1, + IOV_POLLRATE, + IOV_SDREG, + IOV_SBREG, + IOV_SDCIS, + IOV_MEMBYTES, + IOV_RAMSIZE, + IOV_RAMSTART, +#ifdef DHD_DEBUG + IOV_CHECKDIED, + IOV_SERIALCONS, +#endif /* DHD_DEBUG */ + IOV_SET_DOWNLOAD_STATE, + IOV_SOCRAM_STATE, + IOV_FORCEEVEN, + IOV_SDIOD_DRIVE, + IOV_READAHEAD, + IOV_SDRXCHAIN, + IOV_ALIGNCTL, + IOV_SDALIGN, + IOV_DEVRESET, + IOV_CPU, +#if defined(USE_SDIOFIFO_IOVAR) + IOV_WATERMARK, + IOV_MESBUSYCTRL, +#endif /* USE_SDIOFIFO_IOVAR */ +#ifdef SDTEST + IOV_PKTGEN, + IOV_EXTLOOP, +#endif /* SDTEST */ + IOV_SPROM, + IOV_TXBOUND, + IOV_RXBOUND, + IOV_TXMINMAX, + IOV_IDLETIME, + IOV_IDLECLOCK, + IOV_SD1IDLE, + IOV_SLEEP, + IOV_DONGLEISOLATION, + IOV_KSO, + IOV_DEVSLEEP, + IOV_DEVCAP, + IOV_VARS, +#ifdef SOFTAP + IOV_FWPATH, +#endif + IOV_TXGLOMSIZE, + IOV_TXGLOMMODE, + IOV_HANGREPORT, + IOV_TXINRX_THRES +}; + +const bcm_iovar_t dhdsdio_iovars[] = { + {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, + {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 }, + {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 }, + {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, + {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, + {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, + {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, + {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 }, + {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 }, + {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, + {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, + {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, + {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, + {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, + {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 }, + {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, + {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, + {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, +#ifdef DHD_DEBUG + {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, + {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, + {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, + {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, + {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, + {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, +#ifdef DHD_DEBUG + {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, + {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 }, +#endif /* DHD_DEBUG */ +#endif /* DHD_DEBUG */ +#ifdef SDTEST + {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, + {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, +#endif /* SDTEST */ +#if defined(USE_SDIOFIFO_IOVAR) + {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 }, + {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 }, +#endif /* USE_SDIOFIFO_IOVAR */ + {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 }, + {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, + {"kso", IOV_KSO, 0, IOVT_UINT32, 0 }, + {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 }, +#ifdef SOFTAP + {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, +#endif + {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 }, + {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 }, + {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +static void +dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) +{ + uint q1, q2; + + if (!div) { + bcm_bprintf(strbuf, "%s N/A", desc); + } else { + q1 = num / div; + q2 = (100 * (num - (q1 * div))) / div; + bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); + } +} + +void +dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + dhd_bus_t *bus = dhdp->bus; + + bcm_bprintf(strbuf, "Bus SDIO structure:\n"); + bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", + bus->hostintmask, bus->intstatus, bus->sdpcm_ver); + bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n", + bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, + bus->rxlen, bus->rx_seq); + bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n", + bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); + bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n", + bus->pollrate, bus->pollcnt, bus->regfails); + + bcm_bprintf(strbuf, "\nAdditional counters:\n"); +#ifdef DHDENABLE_TAILPAD + bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n", + bus->tx_tailpad_chain, bus->tx_tailpad_pktget); +#endif + bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n", + bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, + bus->rxc_errors); + bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n", + bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); + bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n", + bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); + bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n", + bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); + bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n", + (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, + bus->f2txdata, bus->f1regdata); + { + dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, + (bus->f2rxhdrs + bus->f2rxdata)); + dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); + dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, + (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); + dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); + bcm_bprintf(strbuf, "\n"); + + dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), + bus->dhd->rx_packets); + dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes); + bcm_bprintf(strbuf, "\n"); + + dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata); + dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata); + dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets, + (bus->f2txdata + bus->f1regdata)); + dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount); + bcm_bprintf(strbuf, "\n"); + + dhd_dump_pct(strbuf, "Total: pkts/f2rw", + (bus->dhd->tx_packets + bus->dhd->rx_packets), + (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); + dhd_dump_pct(strbuf, ", pkts/f1sd", + (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata); + dhd_dump_pct(strbuf, ", pkts/sd", + (bus->dhd->tx_packets + bus->dhd->rx_packets), + (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); + dhd_dump_pct(strbuf, ", pkts/int", + (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount); + bcm_bprintf(strbuf, "\n\n"); + } + +#ifdef SDTEST + if (bus->pktgen_count) { + bcm_bprintf(strbuf, "pktgen config and count:\n"); + bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n", + bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, + bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); + bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n", + bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); + } +#endif /* SDTEST */ +#ifdef DHD_DEBUG + bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", + bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); + bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup); +#endif /* DHD_DEBUG */ + bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", + bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); +} + +void +dhd_bus_clearcounts(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; + + bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; + bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; + bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; +#ifdef DHDENABLE_TAILPAD + bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0; +#endif + bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; + bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; + bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; +} + +#ifdef SDTEST +static int +dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg) +{ + dhd_pktgen_t pktgen; + + pktgen.version = DHD_PKTGEN_VERSION; + pktgen.freq = bus->pktgen_freq; + pktgen.count = bus->pktgen_count; + pktgen.print = bus->pktgen_print; + pktgen.total = bus->pktgen_total; + pktgen.minlen = bus->pktgen_minlen; + pktgen.maxlen = bus->pktgen_maxlen; + pktgen.numsent = bus->pktgen_sent; + pktgen.numrcvd = bus->pktgen_rcvd; + pktgen.numfail = bus->pktgen_fail; + pktgen.mode = bus->pktgen_mode; + pktgen.stop = bus->pktgen_stop; + + bcopy(&pktgen, arg, sizeof(pktgen)); + + return 0; +} + +static int +dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) +{ + dhd_pktgen_t pktgen; + uint oldcnt, oldmode; + + bcopy(arg, &pktgen, sizeof(pktgen)); + if (pktgen.version != DHD_PKTGEN_VERSION) + return BCME_BADARG; + + oldcnt = bus->pktgen_count; + oldmode = bus->pktgen_mode; + + bus->pktgen_freq = pktgen.freq; + bus->pktgen_count = pktgen.count; + bus->pktgen_print = pktgen.print; + bus->pktgen_total = pktgen.total; + bus->pktgen_minlen = pktgen.minlen; + bus->pktgen_maxlen = pktgen.maxlen; + bus->pktgen_mode = pktgen.mode; + bus->pktgen_stop = pktgen.stop; + + bus->pktgen_tick = bus->pktgen_ptick = 0; + bus->pktgen_prev_time = jiffies; + bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen); + bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen); + + /* Clear counts for a new pktgen (mode change, or was stopped) */ + if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) { + bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0; + bus->pktgen_prev_rcvd = bus->pktgen_fail = 0; + } + + return 0; +} +#endif /* SDTEST */ + +static void +dhdsdio_devram_remap(dhd_bus_t *bus, bool val) +{ + uint8 enable, protect, remap; + + si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); + remap = val ? TRUE : FALSE; + si_socdevram(bus->sih, TRUE, &enable, &protect, &remap); +} + +static int +dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size) +{ + int bcmerror = 0; + uint32 sdaddr; + uint dsize; + + /* In remap mode, adjust address beyond socram and redirect + * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize + * is not backplane accessible + */ + if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) { + address -= bus->orig_ramsize; + address += SOCDEVRAM_BP_ADDR; + } + + /* 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 */ + if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { + DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); + goto xfer_done; + } + + /* Do the transfer(s) */ + while (size) { + DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n", + __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr, + (address & SBSDIO_SBWINDOW_MASK))); + if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) { + DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__)); + break; + } + + /* Adjust for next transfer (if any) */ + if ((size -= dsize)) { + data += dsize; + address += dsize; + if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { + DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); + break; + } + sdaddr = 0; + dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); + } + + } + +xfer_done: + /* Return the window to backplane enumeration space for core access */ + if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { + DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, + bcmsdh_cur_sbwad(bus->sdh))); + } + + return bcmerror; +} + +#ifdef DHD_DEBUG +static int +dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) +{ + uint32 addr; + int rv, i; + uint32 shaddr = 0; + + if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus)) + bus->srmemsize = 0; + + shaddr = bus->dongle_ram_base + bus->ramsize - 4; + i = 0; + do { + /* Read last word in memory to determine address of sdpcm_shared structure */ + if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) + return rv; + + addr = ltoh32(addr); + + DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); + + /* + * Check if addr is valid. + * NVRAM length at the end of memory should have been overwritten. + */ + if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { + if ((bus->srmemsize > 0) && (i++ == 0)) { + shaddr -= bus->srmemsize; + } else { + DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", + __FUNCTION__, addr)); + return BCME_ERROR; + } + } else + break; + } while (i < 2); + + /* Read hndrte_shared structure */ + if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) + return rv; + + /* Endianness */ + sh->flags = ltoh32(sh->flags); + sh->trap_addr = ltoh32(sh->trap_addr); + sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); + sh->assert_file_addr = ltoh32(sh->assert_file_addr); + sh->assert_line = ltoh32(sh->assert_line); + sh->console_addr = ltoh32(sh->console_addr); + sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); + + if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) + return BCME_OK; + + if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { + DHD_ERROR(("%s: sdpcm_shared version %d in dhd " + "is different than sdpcm_shared version %d in dongle\n", + __FUNCTION__, SDPCM_SHARED_VERSION, + sh->flags & SDPCM_SHARED_VERSION_MASK)); + return BCME_ERROR; + } + + return BCME_OK; +} + +#define CONSOLE_LINE_MAX 192 + +static int +dhdsdio_readconsole(dhd_bus_t *bus) +{ + dhd_console_t *c = &bus->console; + uint8 line[CONSOLE_LINE_MAX], ch; + uint32 n, idx, addr; + int rv; + + /* Don't do anything until FWREADY updates console address */ + if (bus->console_addr == 0) + return 0; + + if (!KSO_ENAB(bus)) + return 0; + + /* Read console log struct */ + addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) + return rv; + + /* Allocate console buffer (one time only) */ + if (c->buf == NULL) { + c->bufsize = ltoh32(c->log.buf_size); + if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) + return BCME_NOMEM; + } + + idx = ltoh32(c->log.idx); + + /* Protect against corrupt value */ + if (idx > c->bufsize) + return BCME_ERROR; + + /* Skip reading the console buffer if the index pointer has not moved */ + if (idx == c->last) + return BCME_OK; + + /* Read the console buffer */ + addr = ltoh32(c->log.buf); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 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; + printf("CONSOLE: %s\n", line); +#ifdef LOG_INTO_TCPDUMP + dhd_sendup_log(bus->dhd, line, n); +#endif /* LOG_INTO_TCPDUMP */ + } + } +break2: + + return BCME_OK; +} + +static int +dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) +{ + int bcmerror = 0; + uint msize = 512; + char *mbuffer = NULL; + char *console_buffer = NULL; + uint maxstrlen = 256; + char *str = NULL; + trap_t tr; + sdpcm_shared_t sdpcm_shared; + struct bcmstrbuf strbuf; + uint32 console_ptr, console_size, console_index; + uint8 line[CONSOLE_LINE_MAX], ch; + uint32 n, i, addr; + int rv; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (DHD_NOCHECKDIED_ON()) + return 0; + + if (data == NULL) { + /* + * Called after a rx ctrl timeout. "data" is NULL. + * allocate memory to trace the trap or assert. + */ + size = msize; + mbuffer = data = MALLOC(bus->dhd->osh, msize); + if (mbuffer == NULL) { + DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); + bcmerror = BCME_NOMEM; + goto done; + } + } + + if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { + DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); + bcmerror = BCME_NOMEM; + goto done; + } + + if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0) + goto done; + + bcm_binit(&strbuf, data, size); + + bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", + sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); + + if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { + /* NOTE: Misspelled assert is intentional - DO NOT FIX. + * (Avoids conflict with real asserts for programmatic parsing of output.) + */ + bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); + } + + if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) { + /* NOTE: Misspelled assert is intentional - DO NOT FIX. + * (Avoids conflict with real asserts for programmatic parsing of output.) + */ + bcm_bprintf(&strbuf, "No trap%s in dongle", + (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) + ?"/assrt" :""); + } else { + if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { + /* Download assert */ + bcm_bprintf(&strbuf, "Dongle assert"); + if (sdpcm_shared.assert_exp_addr != 0) { + str[0] = '\0'; + if ((bcmerror = dhdsdio_membytes(bus, FALSE, + sdpcm_shared.assert_exp_addr, + (uint8 *)str, maxstrlen)) < 0) + goto done; + + str[maxstrlen - 1] = '\0'; + bcm_bprintf(&strbuf, " expr \"%s\"", str); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + " expr \"%s\"", str); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + } + + if (sdpcm_shared.assert_file_addr != 0) { + str[0] = '\0'; + if ((bcmerror = dhdsdio_membytes(bus, FALSE, + sdpcm_shared.assert_file_addr, + (uint8 *)str, maxstrlen)) < 0) + goto done; + + str[maxstrlen - 1] = '\0'; + bcm_bprintf(&strbuf, " file \"%s\"", str); +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + " file \"%s\"", str); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + } + + bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line); + } + + if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { + bus->dhd->dongle_trap_occured = TRUE; + if ((bcmerror = dhdsdio_membytes(bus, FALSE, + sdpcm_shared.trap_addr, + (uint8*)&tr, sizeof(trap_t))) < 0) + goto done; + + bcm_bprintf(&strbuf, + "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," + "lp 0x%x, rpc 0x%x Trap offset 0x%x, " + "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " + "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", + ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), + ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), + ltoh32(sdpcm_shared.trap_addr), + ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), + ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); + +#ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(bus->dhd->crash_reason, + "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," + "lp 0x%x, rpc 0x%x Trap offset 0x%x, " + "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " + "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", + ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), + ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), + ltoh32(sdpcm_shared.trap_addr), + ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), + ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, + (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) + goto printbuf; + + addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, + (uint8 *)&console_size, sizeof(console_size))) < 0) + goto printbuf; + + addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, + (uint8 *)&console_index, sizeof(console_index))) < 0) + goto printbuf; + + console_ptr = ltoh32(console_ptr); + console_size = ltoh32(console_size); + console_index = ltoh32(console_index); + + if (console_size > CONSOLE_BUFFER_MAX || + !(console_buffer = MALLOC(bus->dhd->osh, console_size))) + goto printbuf; + + if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, + (uint8 *)console_buffer, console_size)) < 0) + goto printbuf; + + for (i = 0, n = 0; i < console_size; i += n + 1) { + for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { + ch = console_buffer[(console_index + i + n) % console_size]; + if (ch == '\n') + break; + line[n] = ch; + } + + + if (n > 0) { + if (line[n - 1] == '\r') + n--; + line[n] = 0; + /* Don't use DHD_ERROR macro since we print + * a lot of information quickly. The macro + * will truncate a lot of the printfs + */ + + if (dhd_msg_level & DHD_ERROR_VAL) + printf("CONSOLE: %s\n", line); + } + } + } + } + +printbuf: + if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { + DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); + } + +#ifdef DHD_DEBUG + if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { + /* Mem dump to a file on device */ + dhdsdio_mem_dump(bus); + /* In some cases, the host back trace could be relevant too. */ + WARN_ON(1); + } +#endif /* DHD_DEBUG */ + +done: + if (mbuffer) + MFREE(bus->dhd->osh, mbuffer, msize); + if (str) + MFREE(bus->dhd->osh, str, maxstrlen); + if (console_buffer) + MFREE(bus->dhd->osh, console_buffer, console_size); + + return bcmerror; +} + +static int +dhdsdio_mem_dump(dhd_bus_t *bus) +{ + int ret = 0; + int size; /* Full mem size */ + int start = bus->dongle_ram_base; /* Start address */ + int read_size = 0; /* Read size of each iteration */ + uint8 *buf = NULL, *databuf = NULL; + + /* Get full mem size */ + size = bus->ramsize; + buf = MALLOC(bus->dhd->osh, size); + if (!buf) { + printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size); + return -1; + } + + /* Read mem content */ + DHD_ERROR(("Dump dongle memory")); + databuf = buf; + while (size) + { + read_size = MIN(MEMBLOCK, size); + if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size))) + { + DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret)); + if (buf) { + MFREE(bus->dhd->osh, buf, size); + } + return -1; + } + /* Decrement size and increment start address */ + size -= read_size; + start += read_size; + databuf += read_size; + } + DHD_ERROR(("Done\n")); + + dhd_save_fwdump(bus->dhd, buf, bus->ramsize); +#ifndef CONFIG_BCM_WLAN_RAMDUMP + /* free buf before return !!! */ + if (write_to_file(bus->dhd, buf, bus->ramsize)) + { + printf("%s: Error writing to files\n", __FUNCTION__); + return -1; + } + + /* buf free handled in write_to_file, not here */ +#else + bcm_wlan_crash_reason(bus->dhd->crash_reason); + bcm_wlan_ramdump(buf, bus->ramsize); + memset(bus->dhd->crash_reason, 0 , sizeof(bus->dhd->crash_reason)); + MFREE(bus->dhd->osh, buf, bus->ramsize); +#endif /* CONFIG_BCM_WLAN_RAMDUMP */ + return 0; +} +#endif /* DHD_DEBUG */ + +int +dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) +{ + int bcmerror = BCME_OK; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Basic sanity checks */ + if (bus->dhd->up) { + bcmerror = BCME_NOTDOWN; + goto err; + } + if (!len) { + bcmerror = BCME_BUFTOOSHORT; + goto err; + } + + /* Free the old ones and replace with passed variables */ + if (bus->vars) + MFREE(bus->dhd->osh, bus->vars, bus->varsz); + + bus->vars = MALLOC(bus->dhd->osh, len); + bus->varsz = bus->vars ? len : 0; + if (bus->vars == NULL) { + bcmerror = BCME_NOMEM; + goto err; + } + + /* Copy the passed variables, which should include the terminating double-null */ + bcopy(arg, bus->vars, bus->varsz); +err: + return bcmerror; +} + +#ifdef DHD_DEBUG + +#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) +#define CC_CHIPCTRL_JTAG_SEL (1 << 3) +#define CC_CHIPCTRL_GPIO_SEL (0x3) +#define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28) + +static int +dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) +{ + int int_val; + uint32 addr, data, uart_enab = 0; + uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL; + uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL; + + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + *bcmerror = 0; + + bcmsdh_reg_write(bus->sdh, addr, 4, 1); + if (bcmsdh_regfail(bus->sdh)) { + *bcmerror = BCME_SDIO_ERROR; + return -1; + } + int_val = bcmsdh_reg_read(bus->sdh, data, 4); + if (bcmsdh_regfail(bus->sdh)) { + *bcmerror = BCME_SDIO_ERROR; + return -1; + } + if (bus->sih->chip == BCM4330_CHIP_ID) { + uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; + } + else if (bus->sih->chip == BCM4334_CHIP_ID || + bus->sih->chip == BCM43340_CHIP_ID || + bus->sih->chip == BCM43341_CHIP_ID || + bus->sih->chip == BCM43342_CHIP_ID || + 0) { + if (enable) { + /* Moved to PMU chipcontrol 1 from 4330 */ + int_val &= ~gpio_sel; + int_val |= jtag_sel; + } else { + int_val |= gpio_sel; + int_val &= ~jtag_sel; + } + uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334; + } + + if (!set) + return (int_val & uart_enab); + if (enable) + int_val |= uart_enab; + else + int_val &= ~uart_enab; + bcmsdh_reg_write(bus->sdh, data, 4, int_val); + if (bcmsdh_regfail(bus->sdh)) { + *bcmerror = BCME_SDIO_ERROR; + return -1; + } + if (bus->sih->chip == BCM4330_CHIP_ID) { + uint32 chipcontrol; + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); + chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); + chipcontrol &= ~jtag_sel; + if (enable) { + chipcontrol |= jtag_sel; + chipcontrol &= ~gpio_sel; + } + bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); + } + + return (int_val & uart_enab); +} +#endif + +static int +dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, + void *params, int plen, void *arg, int len, int val_size) +{ + int bcmerror = 0; + int32 int_val = 0; + bool bool_val = 0; + + DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", + __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) + goto exit; + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + + + /* Some ioctls use the bus */ + dhd_os_sdlock(bus->dhd); + + /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ + if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || + actionid == IOV_GVAL(IOV_DEVRESET))) { + bcmerror = BCME_NOTREADY; + goto exit; + } + + /* + * Special handling for keepSdioOn: New SDIO Wake-up Mechanism + */ + if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) { + dhdsdio_clk_kso_iovar(bus, bool_val); + goto exit; + } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { + { + dhdsdio_clk_devsleep_iovar(bus, bool_val); + if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { + DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n", + bus->dpc_sched)); + if (!bus->dpc_sched) { + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + } + } + } + goto exit; + } + + /* Handle sleep stuff before any clock mucking */ + if (vi->varid == IOV_SLEEP) { + if (IOV_ISSET(actionid)) { + bcmerror = dhdsdio_bussleep(bus, bool_val); + } else { + int_val = (int32)bus->sleeping; + bcopy(&int_val, arg, val_size); + } + goto exit; + } + + /* Request clock to allow SDIO accesses */ + if (!bus->dhd->dongle_reset) { + BUS_WAKE(bus); + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + } + + switch (actionid) { + case IOV_GVAL(IOV_INTR): + int_val = (int32)bus->intr; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_INTR): + bus->intr = bool_val; + bus->intdis = FALSE; + if (bus->dhd->up) { + if (bus->intr) { + DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); + bcmsdh_intr_enable(bus->sdh); + } else { + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + bcmsdh_intr_disable(bus->sdh); + } + } + break; + + case IOV_GVAL(IOV_POLLRATE): + int_val = (int32)bus->pollrate; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_POLLRATE): + bus->pollrate = (uint)int_val; + bus->poll = (bus->pollrate != 0); + break; + + case IOV_GVAL(IOV_IDLETIME): + int_val = bus->idletime; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_IDLETIME): + if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) { + bcmerror = BCME_BADARG; + } else { + bus->idletime = int_val; + } + break; + + case IOV_GVAL(IOV_IDLECLOCK): + int_val = (int32)bus->idleclock; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_IDLECLOCK): + bus->idleclock = int_val; + break; + + case IOV_GVAL(IOV_SD1IDLE): + int_val = (int32)sd1idle; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SD1IDLE): + sd1idle = bool_val; + break; + + + case IOV_SVAL(IOV_MEMBYTES): + case IOV_GVAL(IOV_MEMBYTES): + { + uint32 address; + uint size, dsize; + uint8 *data; + + bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); + + ASSERT(plen >= 2*sizeof(int)); + + address = (uint32)int_val; + bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); + size = (uint)int_val; + + /* Do some validation */ + dsize = set ? plen - (2 * sizeof(int)) : len; + if (dsize < size) { + DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", + __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); + bcmerror = BCME_BADARG; + break; + } + + DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, + (set ? "write" : "read"), size, address)); + + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* + * If address is start of RAM (i.e. a downloaded image), + * store the reset instruction to be written in 0 + */ + if (set && address == bus->dongle_ram_base) { + bus->resetinstr = *(((uint32*)params) + 2); + } + } else { + /* If we know about SOCRAM, check for a fit */ + if ((bus->orig_ramsize) && + ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) + { + uint8 enable, protect, remap; + si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); + if (!enable || protect) { + DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", + __FUNCTION__, bus->orig_ramsize, size, address)); + DHD_ERROR(("%s: socram enable %d, protect %d\n", + __FUNCTION__, enable, protect)); + bcmerror = BCME_BADARG; + break; + } + + if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { + uint32 devramsize = si_socdevram_size(bus->sih); + if ((address < SOCDEVRAM_ARM_ADDR) || + (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { + DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n", + __FUNCTION__, address, size)); + DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n", + __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize)); + bcmerror = BCME_BADARG; + break; + } + /* move it such that address is real now */ + address -= SOCDEVRAM_ARM_ADDR; + address += SOCDEVRAM_BP_ADDR; + DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", + __FUNCTION__, (set ? "write" : "read"), size, address)); + } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { + /* Can not access remap region while devram remap bit is set + * ROM content would be returned in this case + */ + DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n", + __FUNCTION__, address)); + bcmerror = BCME_ERROR; + break; + } + } + } + + /* Generate the actual data pointer */ + data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; + + /* Call to do the transfer */ + bcmerror = dhdsdio_membytes(bus, set, address, data, size); + + break; + } + + case IOV_GVAL(IOV_RAMSIZE): + int_val = (int32)bus->ramsize; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_RAMSTART): + int_val = (int32)bus->dongle_ram_base; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_SDIOD_DRIVE): + int_val = (int32)dhd_sdiod_drive_strength; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDIOD_DRIVE): + dhd_sdiod_drive_strength = int_val; + si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength); + break; + + case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): + bcmerror = dhdsdio_download_state(bus, bool_val); + break; + + case IOV_SVAL(IOV_SOCRAM_STATE): + bcmerror = dhdsdio_download_state(bus, bool_val); + break; + + case IOV_SVAL(IOV_VARS): + bcmerror = dhdsdio_downloadvars(bus, arg, len); + break; + + case IOV_GVAL(IOV_READAHEAD): + int_val = (int32)dhd_readahead; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_READAHEAD): + if (bool_val && !dhd_readahead) + bus->nextlen = 0; + dhd_readahead = bool_val; + break; + + case IOV_GVAL(IOV_SDRXCHAIN): + int_val = (int32)bus->use_rxchain; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDRXCHAIN): + if (bool_val && !bus->sd_rxchain) + bcmerror = BCME_UNSUPPORTED; + else + bus->use_rxchain = bool_val; + break; + case IOV_GVAL(IOV_ALIGNCTL): + int_val = (int32)dhd_alignctl; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_ALIGNCTL): + dhd_alignctl = bool_val; + break; + + case IOV_GVAL(IOV_SDALIGN): + int_val = DHD_SDALIGN; + bcopy(&int_val, arg, val_size); + break; + +#ifdef DHD_DEBUG + case IOV_GVAL(IOV_VARS): + if (bus->varsz < (uint)len) + bcopy(bus->vars, arg, bus->varsz); + else + bcmerror = BCME_BUFTOOSHORT; + break; +#endif /* DHD_DEBUG */ + +#ifdef DHD_DEBUG + case IOV_GVAL(IOV_SDREG): + { + sdreg_t *sd_ptr; + uint32 addr, size; + + sd_ptr = (sdreg_t *)params; + + addr = (uint32)((ulong)bus->regs + sd_ptr->offset); + size = sd_ptr->func; + int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); + if (bcmsdh_regfail(bus->sdh)) + bcmerror = BCME_SDIO_ERROR; + bcopy(&int_val, arg, sizeof(int32)); + break; + } + + case IOV_SVAL(IOV_SDREG): + { + sdreg_t *sd_ptr; + uint32 addr, size; + + sd_ptr = (sdreg_t *)params; + + addr = (uint32)((ulong)bus->regs + sd_ptr->offset); + size = sd_ptr->func; + bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value); + if (bcmsdh_regfail(bus->sdh)) + bcmerror = BCME_SDIO_ERROR; + break; + } + + /* Same as above, but offset is not backplane (not SDIO core) */ + case IOV_GVAL(IOV_SBREG): + { + sdreg_t sdreg; + uint32 addr, size; + + bcopy(params, &sdreg, sizeof(sdreg)); + + addr = SI_ENUM_BASE + sdreg.offset; + size = sdreg.func; + int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); + if (bcmsdh_regfail(bus->sdh)) + bcmerror = BCME_SDIO_ERROR; + bcopy(&int_val, arg, sizeof(int32)); + break; + } + + case IOV_SVAL(IOV_SBREG): + { + sdreg_t sdreg; + uint32 addr, size; + + bcopy(params, &sdreg, sizeof(sdreg)); + + addr = SI_ENUM_BASE + sdreg.offset; + size = sdreg.func; + bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value); + if (bcmsdh_regfail(bus->sdh)) + bcmerror = BCME_SDIO_ERROR; + break; + } + + case IOV_GVAL(IOV_SDCIS): + { + *(char *)arg = 0; + + bcmstrcat(arg, "\nFunc 0\n"); + bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); + bcmstrcat(arg, "\nFunc 1\n"); + bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); + bcmstrcat(arg, "\nFunc 2\n"); + bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); + break; + } + + case IOV_GVAL(IOV_FORCEEVEN): + int_val = (int32)forcealign; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_FORCEEVEN): + forcealign = bool_val; + break; + + case IOV_GVAL(IOV_TXBOUND): + int_val = (int32)dhd_txbound; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TXBOUND): + dhd_txbound = (uint)int_val; + break; + + case IOV_GVAL(IOV_RXBOUND): + int_val = (int32)dhd_rxbound; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RXBOUND): + dhd_rxbound = (uint)int_val; + break; + + case IOV_GVAL(IOV_TXMINMAX): + int_val = (int32)dhd_txminmax; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TXMINMAX): + dhd_txminmax = (uint)int_val; + break; + + case IOV_GVAL(IOV_SERIALCONS): + int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); + if (bcmerror != 0) + break; + + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SERIALCONS): + dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); + break; + + +#endif /* DHD_DEBUG */ + + +#ifdef SDTEST + case IOV_GVAL(IOV_EXTLOOP): + int_val = (int32)bus->ext_loop; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_EXTLOOP): + bus->ext_loop = bool_val; + break; + + case IOV_GVAL(IOV_PKTGEN): + bcmerror = dhdsdio_pktgen_get(bus, arg); + break; + + case IOV_SVAL(IOV_PKTGEN): + bcmerror = dhdsdio_pktgen_set(bus, arg); + break; +#endif /* SDTEST */ + +#if defined(USE_SDIOFIFO_IOVAR) + case IOV_GVAL(IOV_WATERMARK): + int_val = (int32)watermark; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_WATERMARK): + watermark = (uint)int_val; + watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark; + DHD_ERROR(("Setting watermark as 0x%x.\n", watermark)); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL); + break; + + case IOV_GVAL(IOV_MESBUSYCTRL): + int_val = (int32)mesbusyctrl; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MESBUSYCTRL): + mesbusyctrl = (uint)int_val; + mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) + ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; + DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl)); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, + ((uint8)mesbusyctrl | 0x80), NULL); + break; +#endif + + + case IOV_GVAL(IOV_DONGLEISOLATION): + int_val = bus->dhd->dongle_isolation; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DONGLEISOLATION): + bus->dhd->dongle_isolation = bool_val; + break; + + case IOV_SVAL(IOV_DEVRESET): + DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", + __FUNCTION__, bool_val, bus->dhd->dongle_reset, + bus->dhd->busstate)); + + ASSERT(bus->dhd->osh); + /* ASSERT(bus->cl_devid); */ + + dhd_bus_devreset(bus->dhd, (uint8)bool_val); + + break; + /* + * softap firmware is updated through module parameter or android private command + */ + + case IOV_GVAL(IOV_DEVRESET): + DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__)); + + /* Get its status */ + int_val = (bool) bus->dhd->dongle_reset; + bcopy(&int_val, arg, val_size); + + break; + + case IOV_GVAL(IOV_KSO): + int_val = dhdsdio_sleepcsr_get(bus); + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_DEVCAP): + int_val = dhdsdio_devcap_get(bus); + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DEVCAP): + dhdsdio_devcap_set(bus, (uint8) int_val); + break; + case IOV_GVAL(IOV_TXGLOMSIZE): + int_val = (int32)bus->txglomsize; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_TXGLOMSIZE): + if (int_val > SDPCM_MAXGLOM_SIZE) { + bcmerror = BCME_ERROR; + } else { + bus->txglomsize = (uint)int_val; + } + break; + case IOV_SVAL(IOV_HANGREPORT): + bus->dhd->hang_report = bool_val; + DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report)); + break; + + case IOV_GVAL(IOV_HANGREPORT): + int_val = (int32)bus->dhd->hang_report; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_TXINRX_THRES): + int_val = bus->txinrx_thres; + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_TXINRX_THRES): + if (int_val < 0) { + bcmerror = BCME_BADARG; + } else { + bus->txinrx_thres = int_val; + } + break; + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } + +exit: + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + + return bcmerror; +} + +static int +dhdsdio_write_vars(dhd_bus_t *bus) +{ + int bcmerror = 0; + uint32 varsize, phys_size; + uint32 varaddr; + uint8 *vbuffer; + uint32 varsizew; +#ifdef DHD_DEBUG + uint8 *nvram_ularray; +#endif /* DHD_DEBUG */ + + /* 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; + + varaddr += bus->dongle_ram_base; + + if (bus->vars) { + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { + if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { + DHD_ERROR(("PR85623WAR in place\n")); + varsize += 4; + varaddr -= 4; + } + } + + vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); + if (!vbuffer) + return BCME_NOMEM; + + bzero(vbuffer, varsize); + bcopy(bus->vars, vbuffer, bus->varsz); + + /* Write the vars list */ + bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); +#ifdef DHD_DEBUG + /* Verify NVRAM bytes */ + DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); + nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); + if (!nvram_ularray) { + MFREE(bus->dhd->osh, vbuffer, varsize); + return BCME_NOMEM; + } + + /* Upload image to verify downloaded contents. */ + memset(nvram_ularray, 0xaa, varsize); + + /* Read the vars list to temp buffer for comparison */ + bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", + __FUNCTION__, bcmerror, varsize, varaddr)); + } + /* Compare the org NVRAM with the one read from RAM */ + if (memcmp(vbuffer, nvram_ularray, varsize)) { + DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); + } else + DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", + __FUNCTION__)); + + MFREE(bus->dhd->osh, nvram_ularray, varsize); +#endif /* DHD_DEBUG */ + + MFREE(bus->dhd->osh, vbuffer, varsize); + } + + phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; + + phys_size += bus->dongle_ram_base; + + /* adjust to the user specified RAM */ + DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", + phys_size, bus->ramsize)); + DHD_INFO(("Vars are at %d, orig varsize is %d\n", + varaddr, varsize)); + varsize = ((phys_size - 4) - varaddr); + + /* + * Determine the length token: + * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. + */ + if (bcmerror) { + varsizew = 0; + } else { + varsizew = varsize / 4; + varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); + varsizew = htol32(varsizew); + } + + DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); + + /* Write the length token to the last word */ + bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4), + (uint8*)&varsizew, 4); + + return bcmerror; +} + +static int +dhdsdio_download_state(dhd_bus_t *bus, bool enter) +{ + uint retries; + int bcmerror = 0; + int foundcr4 = 0; + + if (!bus->sih) + return BCME_ERROR; + /* 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; + + if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && + !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + foundcr4 = 1; + } else { + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + } + + if (!foundcr4) { + si_core_disable(bus->sih, 0); + if (bcmsdh_regfail(bus->sdh)) { + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + si_core_reset(bus->sih, 0, 0); + if (bcmsdh_regfail(bus->sdh)) { + DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", + __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + + /* Disable remap for download */ + if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) + dhdsdio_devram_remap(bus, FALSE); + + if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID) { + /* Disabling Remap for SRAM_3 */ + si_socram_set_bankpda(bus->sih, 0x3, 0x0); + } + + /* Clear the top bit of memory */ + if (bus->ramsize) { + uint32 zeros = 0; + if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, + (uint8*)&zeros, 4) < 0) { + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + } + } else { + /* For CR4, + * Halt ARM + * Remove ARM reset + * Read RAM base address [0x18_0000] + * [next] Download firmware + * [done at else] Populate the reset vector + * [done at else] Remove ARM halt + */ + /* Halt ARM & remove reset */ + si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); + } + } else { + if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + if (!si_iscoreup(bus->sih)) { + DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + + if ((bcmerror = dhdsdio_write_vars(bus))) { + DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); + goto fail; + } + + /* Enable remap before ARM reset but after vars. + * No backplane access in remap mode + */ + if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) + dhdsdio_devram_remap(bus, TRUE); + + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && + !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); + + + if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && + !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + } else { + /* cr4 has no socram, but tcm's */ + /* write vars */ + if ((bcmerror = dhdsdio_write_vars(bus))) { + DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); + goto fail; + } + + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && + !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); + + /* switch back to arm core again */ + if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + /* write address 0 with reset instruction */ + bcmerror = dhdsdio_membytes(bus, TRUE, 0, + (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); + + /* now remove reset and halt and continue to run CR4 */ + } + + si_core_reset(bus->sih, 0, 0); + if (bcmsdh_regfail(bus->sdh)) { + DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + + /* Allow HT Clock now that the ARM is running. */ + bus->alp_only = FALSE; + + bus->dhd->busstate = DHD_BUS_LOAD; + } + +fail: + /* Always return to SDIOD core */ + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) + si_setcore(bus->sih, SDIOD_CORE_ID, 0); + + return bcmerror; +} + +int +dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + dhd_bus_t *bus = dhdp->bus; + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + uint32 actionid; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(name); + ASSERT(len >= 0); + + /* Get MUST have return space */ + ASSERT(set || (arg && len)); + + /* Set does NOT take qualifiers */ + ASSERT(!set || (!params && !plen)); + + /* Look up var locally; if not found pass to host driver */ + if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) { + dhd_os_sdlock(bus->dhd); + + BUS_WAKE(bus); + + /* Turn on clock in case SD command needs backplane */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set); + + /* Check for bus configuration changes of interest */ + + /* If it was divisor change, read the new one */ + if (set && strcmp(name, "sd_divisor") == 0) { + if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, + &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { + bus->sd_divisor = -1; + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); + } else { + DHD_INFO(("%s: noted %s update, value now %d\n", + __FUNCTION__, name, bus->sd_divisor)); + } + } + /* If it was a mode change, read the new one */ + if (set && strcmp(name, "sd_mode") == 0) { + if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, + &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { + bus->sd_mode = -1; + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); + } else { + DHD_INFO(("%s: noted %s update, value now %d\n", + __FUNCTION__, name, bus->sd_mode)); + } + } + /* Similar check for blocksize change */ + if (set && strcmp(name, "sd_blocksize") == 0) { + int32 fnum = 2; + if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32), + &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { + bus->blocksize = 0; + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); + } else { + DHD_INFO(("%s: noted %s update, value now %d\n", + __FUNCTION__, "sd_blocksize", bus->blocksize)); + + dhdsdio_tune_fifoparam(bus); + } + } + bus->roundup = MIN(max_roundup, bus->blocksize); + + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + goto exit; + } + + DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, + name, (set ? "set" : "get"), len, plen)); + + /* set up 'params' pointer in case this is a set command so that + * the convenience int and bool code can be common to set and get + */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + /* all other types are integer sized */ + val_size = sizeof(int); + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); + +exit: + return bcmerror; +} + +void +dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) +{ + osl_t *osh; + uint32 local_hostintmask; + uint8 saveclk; + uint retries; + int err; + bool wlfc_enabled = FALSE; + + if (!bus->dhd) + return; + + osh = bus->dhd->osh; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + bcmsdh_waitlockfree(bus->sdh); + + if (enforce_mutex) + dhd_os_sdlock(bus->dhd); + + if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { + /* if Firmware already hangs disbale any interrupt */ + bus->dhd->busstate = DHD_BUS_DOWN; + bus->hostintmask = 0; + bcmsdh_intr_disable(bus->sdh); + } else { + + BUS_WAKE(bus); + + /* Change our idea of bus state */ + bus->dhd->busstate = DHD_BUS_DOWN; + + if (KSO_ENAB(bus)) { + + /* Enable clock for device interrupts */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Disable and clear interrupts at the chip level also */ + W_SDREG(0, &bus->regs->hostintmask, retries); + local_hostintmask = bus->hostintmask; + bus->hostintmask = 0; + + /* Force clocks on backplane to be sure F2 interrupt propagates */ + saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (!err) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); + } + if (err) { + DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", + __FUNCTION__, err)); + } + + /* Turn off the bus (F2), free any pending packets */ + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + bcmsdh_intr_disable(bus->sdh); + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); + + /* Clear any pending interrupts now that F2 is disabled */ + W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); + } + + /* Turn off the backplane clock (only) */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } + +#ifdef PROP_TXSTATUS + wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED); +#endif + if (!wlfc_enabled) { +#ifdef DHDTCPACK_SUPPRESS + /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, + * when there is a newly coming packet from network stack. + */ + dhd_tcpack_info_tbl_clean(bus->dhd); +#endif /* DHDTCPACK_SUPPRESS */ + /* Clear the data packet queues */ + pktq_flush(osh, &bus->txq, TRUE, NULL, 0); + } + + /* Clear any held glomming stuff */ + if (bus->glomd) + PKTFREE(osh, bus->glomd, FALSE); + + if (bus->glom) + PKTFREE(osh, bus->glom, FALSE); + + bus->glom = bus->glomd = NULL; + + /* Clear rx control and wake any waiters */ + bus->rxlen = 0; + dhd_os_ioctl_resp_wake(bus->dhd); + + /* Reset some F2 state stuff */ + bus->rxskip = FALSE; + bus->tx_seq = bus->rx_seq = 0; + + bus->tx_max = 4; + + if (enforce_mutex) + dhd_os_sdunlock(bus->dhd); +} + +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD) +extern uint sd_txglom; +#endif +void +dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) +{ + /* can't enable host txglom by default, some platforms have no + * (or crappy) ADMA support and txglom will cause kernel assertions (e.g. + * panda board) + */ + dhd_bus_t *bus = dhdp->bus; +#ifdef BCMSDIOH_TXGLOM + uint32 rxglom; + int32 ret; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + +#ifdef BCMSDIOH_STD + if (enable) + enable = sd_txglom; +#endif /* BCMSDIOH_STD */ + + if (enable) { + rxglom = 1; + ret = dhd_iovar(dhdp, 0, "bus:rxglom", (char *)&rxglom, sizeof(rxglom), NULL, 0, + TRUE); + if (ret >= 0) + bus->txglom_enable = TRUE; + else { +#ifdef BCMSDIOH_STD + sd_txglom = 0; +#endif /* BCMSDIOH_STD */ + bus->txglom_enable = FALSE; + } + } else +#endif /* BCMSDIOH_TXGLOM */ + bus->txglom_enable = FALSE; +} + +int +dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) +{ + dhd_bus_t *bus = dhdp->bus; + dhd_timeout_t tmo; + uint retries = 0; + uint8 ready, enable; + int err, ret = 0; + uint8 saveclk; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(bus->dhd); + if (!bus->dhd) + return 0; + + if (enforce_mutex) + dhd_os_sdlock(bus->dhd); + + /* Make sure backplane clock is on, needed to generate F2 interrupt */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (bus->clkstate != CLK_AVAIL) { + DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate)); + ret = -1; + goto exit; + } + + + /* Force clocks on backplane to be sure F2 interrupt propagates */ + saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (!err) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); + } + if (err) { + DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); + ret = -1; + goto exit; + } + + /* Enable function 2 (frame transfers) */ + W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT), + &bus->regs->tosbmailboxdata, retries); + enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); + + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); + + /* Give the dongle some time to do its thing and set IOR2 */ + dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); + + ready = 0; + while (ready != enable && !dhd_timeout_expired(&tmo)) + ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); + + DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", + __FUNCTION__, enable, ready, tmo.elapsed)); + + + /* If F2 successfully enabled, set core and enable interrupts */ + if (ready == enable) { + /* Make sure we're talking to the core. */ + if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) + bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); + ASSERT(bus->regs != NULL); + + /* Set up the interrupt mask and enable interrupts */ + bus->hostintmask = HOSTINTMASK; + /* corerev 4 could use the newer interrupt logic to detect the frames */ + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && + (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { + bus->hostintmask &= ~I_HMB_FRAME_IND; + bus->hostintmask |= I_XMTDATA_AVAIL; + } + W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); + + if (bus->sih->buscorerev < 15) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, + (uint8)watermark, &err); + } + + /* Set bus state according to enable result */ + dhdp->busstate = DHD_BUS_DATA; + + /* bcmsdh_intr_unmask(bus->sdh); */ + + bus->intdis = FALSE; + if (bus->intr) { + DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); + bcmsdh_intr_enable(bus->sdh); + } else { + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + bcmsdh_intr_disable(bus->sdh); + } + + } + + + else { + /* Disable F2 again */ + enable = SDIO_FUNC_ENABLE_1; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); + } + + if (dhdsdio_sr_cap(bus)) { + dhdsdio_sr_init(bus); + /* Masking the chip active interrupt permanantly */ + bus->hostintmask &= ~I_CHIPACTIVE; + W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); + DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n", + __FUNCTION__, bus->hostintmask)); + } + else + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); + + /* If we didn't come up, turn off backplane clock */ + if (dhdp->busstate != DHD_BUS_DATA) + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + + +exit: + if (enforce_mutex) + dhd_os_sdunlock(bus->dhd); + + return ret; +} + +static void +dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) +{ + bcmsdh_info_t *sdh = bus->sdh; + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + uint16 lastrbc; + uint8 hi, lo; + int err; + + DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__, + (abort ? "abort command, " : ""), (rtx ? ", send NAK" : ""))); + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + return; + } + + if (abort) { + bcmsdh_abort(sdh, SDIO_FUNC_2); + } + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); + if (err) { + DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__)); + goto fail; + } + bus->f1regdata++; + + /* Wait until the packet has been flushed (device/FIFO stable) */ + for (lastrbc = retries = 0xffff; retries > 0; retries--) { + hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); + lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err); + if (err) { + DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__)); + goto fail; + } + + bus->f1regdata += 2; + + if ((hi == 0) && (lo == 0)) + break; + + if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { + DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n", + __FUNCTION__, lastrbc, ((hi << 8) + lo))); + } + lastrbc = (hi << 8) + lo; + } + + if (!retries) { + DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc)); + } else { + DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries))); + } + + if (rtx) { + bus->rxrtx++; + W_SDREG(SMB_NAK, ®s->tosbmailbox, retries); + bus->f1regdata++; + if (retries <= retry_limit) { + bus->rxskip = TRUE; + } + } + + /* Clear partial in any case */ + bus->nextlen = 0; + +fail: + /* If we can't reach the device, signal failure */ + if (err || bcmsdh_regfail(sdh)) + bus->dhd->busstate = DHD_BUS_DOWN; +} + +static void +dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) +{ + bcmsdh_info_t *sdh = bus->sdh; + uint rdlen, pad; + + int sdret; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Control data already received in aligned rxctl */ + if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) + goto gotpkt; + + ASSERT(bus->rxbuf); + /* Set rxctl for frame (w/optional alignment) */ + bus->rxctl = bus->rxbuf; + if (dhd_alignctl) { + bus->rxctl += firstread; + if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) + bus->rxctl += (DHD_SDALIGN - pad); + bus->rxctl -= firstread; + } + ASSERT(bus->rxctl >= bus->rxbuf); + + /* Copy the already-read portion over */ + bcopy(hdr, bus->rxctl, firstread); + if (len <= firstread) + goto gotpkt; + + /* Copy the full data pkt in gSPI case and process ioctl. */ + if (bus->bus == SPI_BUS) { + bcopy(hdr, bus->rxctl, len); + goto gotpkt; + } + + /* Raise rdlen to next SDIO block to avoid tail command */ + rdlen = len - 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->dhd->maxctl)) + rdlen += pad; + } else if (rdlen % DHD_SDALIGN) { + rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); + } + + /* Satisfy length-alignment requirements */ + if (forcealign && (rdlen & (ALIGNMENT - 1))) + rdlen = ROUNDUP(rdlen, ALIGNMENT); + + /* Drop if the read is too big or it exceeds our maximum */ + if ((rdlen + firstread) > bus->dhd->maxctl) { + DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n", + __FUNCTION__, rdlen, bus->dhd->maxctl)); + bus->dhd->rx_errors++; + dhdsdio_rxfail(bus, FALSE, FALSE); + goto done; + } + + if ((len - doff) > bus->dhd->maxctl) { + DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", + __FUNCTION__, len, (len - doff), bus->dhd->maxctl)); + bus->dhd->rx_errors++; bus->rx_toolong++; + dhdsdio_rxfail(bus, FALSE, FALSE); + goto done; + } + + + /* Read remainder of frame body into the rxctl buffer */ + sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); + bus->f2rxdata++; + ASSERT(sdret != BCME_PENDING); + + /* Control frame failures need retransmission */ + if (sdret < 0) { + DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret)); + bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */ + dhdsdio_rxfail(bus, TRUE, TRUE); + goto done; + } + +gotpkt: + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_CTL_ON()) { + prhex("RxCtrl", bus->rxctl, len); + } +#endif + + /* Point to valid data and indicate its length */ + bus->rxctl += doff; + bus->rxlen = len - doff; + +done: + /* Awake any waiters */ + dhd_os_ioctl_resp_wake(bus->dhd); +} +int +dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, + void **pkt, uint32 *pkt_count); + +static uint8 +dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) +{ + uint16 dlen, totlen; + uint8 *dptr, num = 0; + + uint16 sublen, check; + void *pfirst, *plast, *pnext; + void * list_tail[DHD_MAX_IFS] = { NULL }; + void * list_head[DHD_MAX_IFS] = { NULL }; + uint8 idx; + osl_t *osh = bus->dhd->osh; + + int errcode; + uint8 chan, seq, doff, sfdoff; + uint8 txmax; + uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; + uint reorder_info_len; + + int ifidx = 0; + bool usechain = bus->use_rxchain; + + /* If packets, issue read(s) and send up packet chain */ + /* Return sequence numbers consumed? */ + + DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom)); + + /* If there's a descriptor, generate the packet chain */ + if (bus->glomd) { + dhd_os_sdlock_rxq(bus->dhd); + + pfirst = plast = pnext = NULL; + dlen = (uint16)PKTLEN(osh, bus->glomd); + dptr = PKTDATA(osh, bus->glomd); + if (!dlen || (dlen & 1)) { + DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n", + __FUNCTION__, dlen)); + dlen = 0; + } + + for (totlen = num = 0; dlen; num++) { + /* Get (and move past) next length */ + sublen = ltoh16_ua(dptr); + dlen -= sizeof(uint16); + dptr += sizeof(uint16); + if ((sublen < SDPCM_HDRLEN) || + ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { + DHD_ERROR(("%s: descriptor len %d bad: %d\n", + __FUNCTION__, num, sublen)); + pnext = NULL; + break; + } + if (sublen % DHD_SDALIGN) { + DHD_ERROR(("%s: sublen %d not a multiple of %d\n", + __FUNCTION__, sublen, DHD_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 */ + if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) { + DHD_ERROR(("%s: PKTGET failed, num %d len %d\n", + __FUNCTION__, num, sublen)); + break; + } + ASSERT(!PKTLINK(pnext)); + if (!pfirst) { + ASSERT(!plast); + pfirst = plast = pnext; + } else { + ASSERT(plast); + PKTSETNEXT(osh, plast, pnext); + plast = pnext; + } + + /* Adhere to start alignment requirements */ + PKTALIGN(osh, pnext, sublen, DHD_SDALIGN); + } + + /* If all allocations succeeded, save packet chain in bus structure */ + if (pnext) { + DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n", + __FUNCTION__, totlen, num)); + if (DHD_GLOM_ON() && bus->nextlen) { + if (totlen != bus->nextlen) { + DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d " + "rxseq %d\n", __FUNCTION__, bus->nextlen, + totlen, rxseq)); + } + } + bus->glom = pfirst; + pfirst = pnext = NULL; + } else { + if (pfirst) + PKTFREE(osh, pfirst, FALSE); + bus->glom = NULL; + num = 0; + } + + /* Done with descriptor packet */ + PKTFREE(osh, bus->glomd, FALSE); + bus->glomd = NULL; + bus->nextlen = 0; + + dhd_os_sdunlock_rxq(bus->dhd); + } + + /* Ok -- either we just generated a packet chain, or had one from before */ + if (bus->glom) { + if (DHD_GLOM_ON()) { + DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__)); + for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) { + DHD_GLOM((" %p: %p len 0x%04x (%d)\n", + pnext, (uint8*)PKTDATA(osh, pnext), + PKTLEN(osh, pnext), PKTLEN(osh, pnext))); + } + } + + pfirst = bus->glom; + dlen = (uint16)pkttotlen(osh, 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 = dhd_bcmsdh_recv_buf(bus, + bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, + F2SYNC, (uint8*)PKTDATA(osh, pfirst), + dlen, pfirst, NULL, NULL); + } else if (bus->dataptr) { + errcode = dhd_bcmsdh_recv_buf(bus, + bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, + F2SYNC, bus->dataptr, + dlen, NULL, NULL, NULL); + sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); + if (sublen != dlen) { + DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n", + __FUNCTION__, dlen, sublen)); + errcode = -1; + } + pnext = NULL; + } else { + DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen)); + errcode = -1; + } + bus->f2rxdata++; + ASSERT(errcode != BCME_PENDING); + + /* On failure, kill the superframe, allow a couple retries */ + if (errcode < 0) { + DHD_ERROR(("%s: glom read of %d bytes failed: %d\n", + __FUNCTION__, dlen, errcode)); + bus->dhd->rx_errors++; + + if (bus->glomerr++ < 3) { + dhdsdio_rxfail(bus, TRUE, TRUE); + } else { + bus->glomerr = 0; + dhdsdio_rxfail(bus, TRUE, FALSE); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(osh, bus->glom, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + bus->rxglomfail++; + bus->glom = NULL; + } + return 0; + } + +#ifdef DHD_DEBUG + if (DHD_GLOM_ON()) { + prhex("SUPERFRAME", PKTDATA(osh, pfirst), + MIN(PKTLEN(osh, pfirst), 48)); + } +#endif + + + /* Validate the superframe header */ + dptr = (uint8 *)PKTDATA(osh, pfirst); + sublen = ltoh16_ua(dptr); + check = ltoh16_ua(dptr + sizeof(uint16)); + + 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) { + DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n", + __FUNCTION__, 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 ((uint16)~(sublen^check)) { + DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n", + __FUNCTION__, sublen, check)); + errcode = -1; + } else if (ROUNDUP(sublen, bus->blocksize) != dlen) { + DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", + __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen)); + errcode = -1; + } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) { + DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__, + SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]))); + errcode = -1; + } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { + DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__)); + errcode = -1; + } else if ((doff < SDPCM_HDRLEN) || + (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) { + DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", + __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), + SDPCM_HDRLEN)); + errcode = -1; + } + + /* Check sequence number of superframe SW header */ + if (rxseq != seq) { + DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n", + __FUNCTION__, seq, rxseq)); + bus->rx_badseq++; + rxseq = seq; + } + + /* Check window for sanity */ + if ((uint8)(txmax - bus->tx_seq) > 0x70) { + DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + __FUNCTION__, txmax, bus->tx_seq)); + txmax = bus->tx_max; + } + bus->tx_max = txmax; + + /* Remove superframe header, remember offset */ + PKTPULL(osh, pfirst, doff); + sfdoff = doff; + + /* Validate all the subframe headers */ + for (num = 0, pnext = pfirst; pnext && !errcode; + num++, pnext = PKTNEXT(osh, pnext)) { + dptr = (uint8 *)PKTDATA(osh, pnext); + dlen = (uint16)PKTLEN(osh, pnext); + sublen = ltoh16_ua(dptr); + check = ltoh16_ua(dptr + sizeof(uint16)); + chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); + doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); +#ifdef DHD_DEBUG + if (DHD_GLOM_ON()) { + prhex("subframe", dptr, 32); + } +#endif + + if ((uint16)~(sublen^check)) { + DHD_ERROR(("%s (subframe %d): HW hdr error: " + "len/check 0x%04x/0x%04x\n", + __FUNCTION__, num, sublen, check)); + errcode = -1; + } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { + DHD_ERROR(("%s (subframe %d): length mismatch: " + "len 0x%04x, expect 0x%04x\n", + __FUNCTION__, num, sublen, dlen)); + errcode = -1; + } else if ((chan != SDPCM_DATA_CHANNEL) && + (chan != SDPCM_EVENT_CHANNEL)) { + DHD_ERROR(("%s (subframe %d): bad channel %d\n", + __FUNCTION__, num, chan)); + errcode = -1; + } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { + DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n", + __FUNCTION__, 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 */ + PKTPUSH(osh, pfirst, sfdoff); + dhdsdio_rxfail(bus, TRUE, TRUE); + } else { + bus->glomerr = 0; + dhdsdio_rxfail(bus, TRUE, FALSE); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(osh, bus->glom, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + bus->rxglomfail++; + bus->glom = NULL; + } + bus->nextlen = 0; + return 0; + } + + /* Basic SD framing looks ok - process each packet (header) */ + bus->glom = NULL; + plast = NULL; + + dhd_os_sdlock_rxq(bus->dhd); + for (num = 0; pfirst; rxseq++, pfirst = pnext) { + pnext = PKTNEXT(osh, pfirst); + PKTSETNEXT(osh, pfirst, NULL); + + dptr = (uint8 *)PKTDATA(osh, pfirst); + sublen = ltoh16_ua(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]); + + DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", + __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst), + PKTLEN(osh, pfirst), sublen, chan, seq)); + + ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); + + if (rxseq != seq) { + DHD_GLOM(("%s: rx_seq %d, expected %d\n", + __FUNCTION__, seq, rxseq)); + bus->rx_badseq++; + rxseq = seq; + } + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_DATA_ON()) { + prhex("Rx Subframe Data", dptr, dlen); + } +#endif + + PKTSETLEN(osh, pfirst, sublen); + PKTPULL(osh, pfirst, doff); + + reorder_info_len = sizeof(reorder_info_buf); + + if (PKTLEN(osh, pfirst) == 0) { + PKTFREE(bus->dhd->osh, pfirst, FALSE); + continue; + } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, + &reorder_info_len) != 0) { + DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); + bus->dhd->rx_errors++; + PKTFREE(osh, pfirst, FALSE); + continue; + } + if (reorder_info_len) { + uint32 free_buf_count; + void *ppfirst; + + ppfirst = pfirst; + /* Reordering info from the firmware */ + dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, + reorder_info_len, &ppfirst, &free_buf_count); + + if (free_buf_count == 0) { + continue; + } + else { + void *temp; + + /* go to the end of the chain and attach the pnext there */ + temp = ppfirst; + while (PKTNEXT(osh, temp) != NULL) { + temp = PKTNEXT(osh, temp); + } + pfirst = temp; + if (list_tail[ifidx] == NULL) + list_head[ifidx] = ppfirst; + else + PKTSETNEXT(osh, list_tail[ifidx], ppfirst); + list_tail[ifidx] = pfirst; + } + + num += (uint8)free_buf_count; + } + else { + /* this packet will go up, link back into chain and count it */ + + if (list_tail[ifidx] == NULL) { + list_head[ifidx] = list_tail[ifidx] = pfirst; + } + else { + PKTSETNEXT(osh, list_tail[ifidx], pfirst); + list_tail[ifidx] = pfirst; + } + num++; + } +#ifdef DHD_DEBUG + if (DHD_GLOM_ON()) { + DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n", + __FUNCTION__, num, pfirst, + PKTDATA(osh, pfirst), PKTLEN(osh, pfirst), + PKTNEXT(osh, pfirst), PKTLINK(pfirst))); + prhex("", (uint8 *)PKTDATA(osh, pfirst), + MIN(PKTLEN(osh, pfirst), 32)); + } +#endif /* DHD_DEBUG */ + } + dhd_os_sdunlock_rxq(bus->dhd); + + for (idx = 0; idx < DHD_MAX_IFS; idx++) { + if (list_head[idx]) { + void *temp; + uint8 cnt = 0; + temp = list_head[idx]; + do { + temp = PKTNEXT(osh, temp); + cnt++; + } while (temp); + if (cnt) { + dhd_os_sdunlock(bus->dhd); + dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); + dhd_os_sdlock(bus->dhd); + } + } + } + bus->rxglomframes++; + bus->rxglompkts += num; + } + return num; +} + + +/* Return TRUE if there may be more frames to read */ +static uint +dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) +{ + osl_t *osh = bus->dhd->osh; + bcmsdh_info_t *sdh = bus->sdh; + + uint16 len, check; /* Extracted hardware header fields */ + uint8 chan, seq, doff; /* Extracted software header fields */ + uint8 fcbits; /* Extracted fcbits from software header */ + uint8 delta; + + void *pkt; /* Packet for event or data frames */ + uint16 pad; /* Number of pad bytes to read */ + uint16 rdlen; /* Total number of bytes to read */ + uint8 rxseq; /* Next sequence number to expect */ + uint rxleft = 0; /* Remaining number of frames allowed */ + int sdret; /* Return code from bcmsdh calls */ + uint8 txmax; /* Maximum tx sequence offered */ + bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ + uint8 *rxbuf; + int ifidx = 0; + uint rxcount = 0; /* Total frames read */ + uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; + uint reorder_info_len; + uint pkt_count; + +#if defined(DHD_DEBUG) || defined(SDTEST) + bool sdtest = FALSE; /* To limit message spew from test mode */ +#endif + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + bus->readframes = TRUE; + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: KSO off\n", __FUNCTION__)); + bus->readframes = FALSE; + return 0; + } + + ASSERT(maxframes); + +#ifdef SDTEST + /* Allow pktgen to override maxframes */ + if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { + maxframes = bus->pktgen_count; + sdtest = TRUE; + } +#endif + + /* Not finished unless we encounter no more frames indication */ + *finished = FALSE; + + + for (rxseq = bus->rx_seq, rxleft = maxframes; + !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; + rxseq++, rxleft--) { +#ifdef DHDTCPACK_SUP_DBG + if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) { + if (bus->dotxinrx == FALSE) + DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n", + __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode)); + } +#ifdef DEBUG_COUNTER + else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) { + tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++; + } +#endif /* DEBUG_COUNTER */ +#endif /* DHDTCPACK_SUP_DBG */ + /* tx more to improve rx performance */ + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { + dhdsdio_sendpendctl(bus); + } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) && + !bus->fcstate && DATAOK(bus) && + (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) { + dhdsdio_sendfromq(bus, dhd_txbound); +#ifdef DHDTCPACK_SUPPRESS + /* In TCPACK_SUP_DELAYTX mode, do txinrx only if + * 1. Any DATA packet to TX + * 2. TCPACK to TCPDATA PSH packets. + * in bus txq. + */ + bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ? + FALSE : TRUE; +#endif + } + + /* Handle glomming separately */ + if (bus->glom || bus->glomd) { + uint8 cnt; + DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n", + __FUNCTION__, bus->glomd, bus->glom)); + cnt = dhdsdio_rxglom(bus, rxseq); + DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt)); + rxseq += cnt - 1; + rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; + continue; + } + + /* Try doing single read if we can */ + if (dhd_readahead && bus->nextlen) { + uint16 nextlen = bus->nextlen; + bus->nextlen = 0; + + if (bus->bus == SPI_BUS) { + rdlen = len = nextlen; + } + else { + rdlen = len = nextlen << 4; + + /* 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 + firstread) < MAX_RX_DATASZ)) + rdlen += pad; + } else if (rdlen % DHD_SDALIGN) { + rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); + } + } + + /* We use bus->rxctl buffer in WinXP for initial control pkt receives. + * Later we use buffer-poll for data as well as control packets. + * This is required because dhd receives full frame in gSPI unlike SDIO. + * After the frame is received we have to distinguish whether it is data + * or non-data frame. + */ + /* Allocate a packet buffer */ + dhd_os_sdlock_rxq(bus->dhd); + if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) { + if (bus->bus == SPI_BUS) { + bus->usebufpool = FALSE; + bus->rxctl = bus->rxbuf; + if (dhd_alignctl) { + bus->rxctl += firstread; + if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) + bus->rxctl += (DHD_SDALIGN - pad); + bus->rxctl -= firstread; + } + ASSERT(bus->rxctl >= bus->rxbuf); + rxbuf = bus->rxctl; + /* Read the entire frame */ + sdret = dhd_bcmsdh_recv_buf(bus, + bcmsdh_cur_sbwad(sdh), + SDIO_FUNC_2, + F2SYNC, rxbuf, rdlen, + NULL, NULL, NULL); + bus->f2rxdata++; + ASSERT(sdret != BCME_PENDING); + + + /* Control frame failures need retransmission */ + if (sdret < 0) { + DHD_ERROR(("%s: read %d control bytes failed: %d\n", + __FUNCTION__, rdlen, sdret)); + /* dhd.rx_ctlerrs is higher level */ + bus->rxc_errors++; + dhd_os_sdunlock_rxq(bus->dhd); + dhdsdio_rxfail(bus, TRUE, + (bus->bus == SPI_BUS) ? FALSE : TRUE); + continue; + } + } else { + /* Give up on data, request rtx of events */ + DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d " + "expected rxseq %d\n", + __FUNCTION__, len, rdlen, rxseq)); + /* Just go try again w/normal header read */ + dhd_os_sdunlock_rxq(bus->dhd); + continue; + } + } else { + if (bus->bus == SPI_BUS) + bus->usebufpool = TRUE; + + ASSERT(!PKTLINK(pkt)); + PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); + rxbuf = (uint8 *)PKTDATA(osh, pkt); + /* Read the entire frame */ + sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), + SDIO_FUNC_2, + F2SYNC, rxbuf, rdlen, + pkt, NULL, NULL); + bus->f2rxdata++; + ASSERT(sdret != BCME_PENDING); + + if (sdret < 0) { + DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n", + __FUNCTION__, rdlen, sdret)); + PKTFREE(bus->dhd->osh, pkt, FALSE); + bus->dhd->rx_errors++; + dhd_os_sdunlock_rxq(bus->dhd); + /* Force retry w/normal header read. Don't attempt NAK for + * gSPI + */ + dhdsdio_rxfail(bus, TRUE, + (bus->bus == SPI_BUS) ? FALSE : TRUE); + continue; + } + } + dhd_os_sdunlock_rxq(bus->dhd); + + /* Now check the header */ + bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN); + + /* Extract hardware header fields */ + len = ltoh16_ua(bus->rxhdr); + check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); + + /* All zeros means readahead info was bad */ + if (!(len|check)) { + DHD_INFO(("%s (nextlen): read zeros in HW header???\n", + __FUNCTION__)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + GSPI_PR55150_BAILOUT; + continue; + } + + /* Validate check bytes */ + if ((uint16)~(len^check)) { + DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check" + " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen, + len, check)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + bus->rx_badhdr++; + dhdsdio_rxfail(bus, FALSE, FALSE); + GSPI_PR55150_BAILOUT; + continue; + } + + /* Validate frame length */ + if (len < SDPCM_HDRLEN) { + DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n", + __FUNCTION__, len)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + GSPI_PR55150_BAILOUT; + continue; + } + + /* 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) */ + DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; " + "expected rxseq %d\n", + __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE); + GSPI_PR55150_BAILOUT; + 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) { + DHD_INFO(("%s (nextlen): got frame w/nextlen too large" + " (%d), seq %d\n", __FUNCTION__, bus->nextlen, + seq)); + bus->nextlen = 0; + } + + bus->dhd->rx_readahead_cnt ++; + /* Handle Flow Control */ + fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); + + delta = 0; + if (~bus->flowcontrol & fcbits) { + bus->fc_xoff++; + delta = 1; + } + if (bus->flowcontrol & ~fcbits) { + bus->fc_xon++; + delta = 1; + } + + if (delta) { + bus->fc_rcvd++; + bus->flowcontrol = fcbits; + } + + /* Check and update sequence number */ + if (rxseq != seq) { + DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n", + __FUNCTION__, seq, rxseq)); + bus->rx_badseq++; + rxseq = seq; + } + + /* Check window for sanity */ + if ((uint8)(txmax - bus->tx_seq) > 0x70) { + DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + __FUNCTION__, txmax, bus->tx_seq)); + txmax = bus->tx_max; + } + bus->tx_max = txmax; + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_DATA_ON()) { + prhex("Rx Data", rxbuf, len); + } else if (DHD_HDRS_ON()) { + prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); + } +#endif + + if (chan == SDPCM_CONTROL_CHANNEL) { + if (bus->bus == SPI_BUS) { + dhdsdio_read_control(bus, rxbuf, len, doff); + if (bus->usebufpool) { + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(bus->dhd->osh, pkt, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + } + continue; + } else { + DHD_ERROR(("%s (nextlen): readahead on control" + " packet %d?\n", __FUNCTION__, seq)); + /* Force retry w/normal header read */ + bus->nextlen = 0; + dhdsdio_rxfail(bus, FALSE, TRUE); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + continue; + } + } + + if ((bus->bus == SPI_BUS) && !bus->usebufpool) { + DHD_ERROR(("Received %d bytes on %d channel. Running out of " + "rx pktbuf's or not yet malloced.\n", len, chan)); + continue; + } + + /* Validate data offset */ + if ((doff < SDPCM_HDRLEN) || (doff > len)) { + DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n", + __FUNCTION__, doff, len, SDPCM_HDRLEN)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE2(); + dhd_os_sdunlock_rxq(bus->dhd); + ASSERT(0); + dhdsdio_rxfail(bus, FALSE, FALSE); + continue; + } + + /* All done with this one -- now deliver the packet */ + goto deliver; + } + /* gSPI frames should not be handled in fractions */ + if (bus->bus == SPI_BUS) { + break; + } + + /* Read frame header (hardware and software) */ + sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + bus->rxhdr, firstread, NULL, NULL, NULL); + bus->f2rxhdrs++; + ASSERT(sdret != BCME_PENDING); + + if (sdret < 0) { + DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret)); + bus->rx_hdrfail++; + dhdsdio_rxfail(bus, TRUE, TRUE); + continue; + } + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() || DHD_HDRS_ON()) { + prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); + } +#endif + + /* Extract hardware header fields */ + len = ltoh16_ua(bus->rxhdr); + check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); + + /* All zeros means no more frames */ + if (!(len|check)) { + *finished = TRUE; + break; + } + + /* Validate check bytes */ + if ((uint16)~(len^check)) { + DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n", + __FUNCTION__, len, check)); + bus->rx_badhdr++; + dhdsdio_rxfail(bus, FALSE, FALSE); + continue; + } + + /* Validate frame length */ + if (len < SDPCM_HDRLEN) { + DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, 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)) { + DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n", + __FUNCTION__, doff, len, SDPCM_HDRLEN, seq)); + bus->rx_badhdr++; + ASSERT(0); + dhdsdio_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) { + DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n", + __FUNCTION__, bus->nextlen, seq)); + bus->nextlen = 0; + } + + /* Handle Flow Control */ + fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); + + delta = 0; + if (~bus->flowcontrol & fcbits) { + bus->fc_xoff++; + delta = 1; + } + if (bus->flowcontrol & ~fcbits) { + bus->fc_xon++; + delta = 1; + } + + if (delta) { + bus->fc_rcvd++; + bus->flowcontrol = fcbits; + } + + /* Check and update sequence number */ + if (rxseq != seq) { + DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq)); + bus->rx_badseq++; + rxseq = seq; + } + + /* Check window for sanity */ + if ((uint8)(txmax - bus->tx_seq) > 0x70) { + DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + __FUNCTION__, txmax, bus->tx_seq)); + txmax = bus->tx_max; + } + bus->tx_max = txmax; + + /* Call a separate function for control frames */ + if (chan == SDPCM_CONTROL_CHANNEL) { + dhdsdio_read_control(bus, bus->rxhdr, len, doff); + continue; + } + + ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) || + (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL)); + + /* Length to read */ + rdlen = (len > firstread) ? (len - 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 + firstread) < MAX_RX_DATASZ)) + rdlen += pad; + } else if (rdlen % DHD_SDALIGN) { + rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); + } + + /* Satisfy length-alignment requirements */ + if (forcealign && (rdlen & (ALIGNMENT - 1))) + rdlen = ROUNDUP(rdlen, ALIGNMENT); + + if ((rdlen + firstread) > MAX_RX_DATASZ) { + /* Too long -- skip this frame */ + DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen)); + bus->dhd->rx_errors++; bus->rx_toolong++; + dhdsdio_rxfail(bus, FALSE, FALSE); + continue; + } + + dhd_os_sdlock_rxq(bus->dhd); + if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) { + /* Give up on data, request rtx of events */ + DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n", + __FUNCTION__, rdlen, chan)); + bus->dhd->rx_dropped++; + dhd_os_sdunlock_rxq(bus->dhd); + dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan)); + continue; + } + dhd_os_sdunlock_rxq(bus->dhd); + + ASSERT(!PKTLINK(pkt)); + + /* Leave room for what we already read, and align remainder */ + ASSERT(firstread < (PKTLEN(osh, pkt))); + PKTPULL(osh, pkt, firstread); + PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); + + /* Read the remaining frame data */ + sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); + bus->f2rxdata++; + ASSERT(sdret != BCME_PENDING); + + if (sdret < 0) { + DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen, + ((chan == SDPCM_EVENT_CHANNEL) ? "event" : + ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(bus->dhd->osh, pkt, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + bus->dhd->rx_errors++; + dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan)); + continue; + } + + /* Copy the already-read portion */ + PKTPUSH(osh, pkt, firstread); + bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread); + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_DATA_ON()) { + prhex("Rx Data", PKTDATA(osh, pkt), len); + } +#endif + +deliver: + /* Save superframe descriptor and allocate packet frame */ + if (chan == SDPCM_GLOM_CHANNEL) { + if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { + DHD_GLOM(("%s: got glom descriptor, %d bytes:\n", + __FUNCTION__, len)); +#ifdef DHD_DEBUG + if (DHD_GLOM_ON()) { + prhex("Glom Data", PKTDATA(osh, pkt), len); + } +#endif + PKTSETLEN(osh, pkt, len); + ASSERT(doff == SDPCM_HDRLEN); + PKTPULL(osh, pkt, SDPCM_HDRLEN); + bus->glomd = pkt; + } else { + DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__)); + dhdsdio_rxfail(bus, FALSE, FALSE); + } + continue; + } + + /* Fill in packet len and prio, deliver upward */ + PKTSETLEN(osh, pkt, len); + PKTPULL(osh, pkt, doff); + +#ifdef SDTEST + /* Test channel packets are processed separately */ + if (chan == SDPCM_TEST_CHANNEL) { + dhdsdio_testrcv(bus, pkt, seq); + continue; + } +#endif /* SDTEST */ + + if (PKTLEN(osh, pkt) == 0) { + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(bus->dhd->osh, pkt, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + continue; + } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf, + &reorder_info_len) != 0) { + DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); + dhd_os_sdlock_rxq(bus->dhd); + PKTFREE(bus->dhd->osh, pkt, FALSE); + dhd_os_sdunlock_rxq(bus->dhd); + bus->dhd->rx_errors++; + continue; + } + if (reorder_info_len) { + /* Reordering info from the firmware */ + dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len, + &pkt, &pkt_count); + if (pkt_count == 0) + continue; + } + else + pkt_count = 1; + + /* Unlock during rx call */ + dhd_os_sdunlock(bus->dhd); + dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); + dhd_os_sdlock(bus->dhd); + } + rxcount = maxframes - rxleft; +#ifdef DHD_DEBUG + /* Message if we hit the limit */ + if (!rxleft && !sdtest) + DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes)); + else +#endif /* DHD_DEBUG */ + DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount)); + /* Back off rxseq if awaiting rtx, update rx_seq */ + if (bus->rxskip) + rxseq--; + bus->rx_seq = rxseq; + + if (bus->reqbussleep) + { + dhdsdio_bussleep(bus, TRUE); + bus->reqbussleep = FALSE; + } + bus->readframes = FALSE; + + return rxcount; +} + +static uint32 +dhdsdio_hostmail(dhd_bus_t *bus) +{ + sdpcmd_regs_t *regs = bus->regs; + uint32 intstatus = 0; + uint32 hmb_data; + uint8 fcbits; + uint retries = 0; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Read mailbox data and ack that we did so */ + R_SDREG(hmb_data, ®s->tohostmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries); + bus->f1regdata += 2; + + /* Dongle recomposed rx frames, accept them again */ + if (hmb_data & HMB_DATA_NAKHANDLED) { + DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq)); + if (!bus->rxskip) { + DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__)); + } + bus->rxskip = FALSE; + intstatus |= FRAME_AVAIL_MASK(bus); + } + + /* + * 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) + DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n", + bus->sdpcm_ver, SDPCM_PROT_VERSION)); + else + DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver)); + /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && + (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { + uint32 val; + + val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); + val &= ~CC_XMTDATAAVAIL_MODE; + val |= CC_XMTDATAAVAIL_CTRL; + W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); + + val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); + } + +#ifdef DHD_DEBUG + /* Retrieve console state address now that firmware should have updated it */ + { + sdpcm_shared_t shared; + if (dhdsdio_readshared(bus, &shared) == 0) + bus->console_addr = shared.console_addr; + } +#endif /* DHD_DEBUG */ + } + + /* + * Flow Control has been moved into the RX headers and this out of band + * method isn't used any more. Leave this here for possibly 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; + } + +#ifdef DHD_DEBUG + /* At least print a message if FW halted */ + if (hmb_data & HMB_DATA_FWHALT) { + DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n")); + dhdsdio_checkdied(bus, NULL, 0); + bus->dhd->busstate = DHD_BUS_DOWN; + } +#endif /* DHD_DEBUG */ + + /* Shouldn't be any others */ + if (hmb_data & ~(HMB_DATA_DEVREADY | + HMB_DATA_FWHALT | + HMB_DATA_NAKHANDLED | + HMB_DATA_FC | + HMB_DATA_FWREADY | + HMB_DATA_FCDATA_MASK | + HMB_DATA_VERSION_MASK)) { + DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data)); + } + + return intstatus; +} + +static bool +dhdsdio_dpc(dhd_bus_t *bus) +{ + bcmsdh_info_t *sdh = bus->sdh; + sdpcmd_regs_t *regs = bus->regs; + uint32 intstatus, newstatus = 0; + uint retries = 0; + uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */ + uint txlimit = dhd_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 */ +#if defined(CUSTOMER_HW5) + bool is_resched_by_readframe = FALSE; +#endif + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + dhd_os_sdlock(bus->dhd); + + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); + bus->intstatus = 0; + dhd_os_sdunlock(bus->dhd); + return 0; + } + + /* Start with leftover status bits */ + intstatus = bus->intstatus; + + if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + goto exit; + } + + /* If waiting for HTAVAIL, check status */ + if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) { + int err; + uint8 clkctl, devctl = 0; + +#ifdef DHD_DEBUG + /* Check for inconsistent device control */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + if (err) { + DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err)); + bus->dhd->busstate = DHD_BUS_DOWN; + } else { + ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); + } +#endif /* DHD_DEBUG */ + + /* Read CSR, if clock on switch to AVAIL, else ignore */ + clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (err) { + DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err)); + bus->dhd->busstate = DHD_BUS_DOWN; + } + + DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl)); + + if (SBSDIO_HTAV(clkctl)) { + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + if (err) { + DHD_ERROR(("%s: error reading DEVCTL: %d\n", + __FUNCTION__, err)); + bus->dhd->busstate = DHD_BUS_DOWN; + } + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + if (err) { + DHD_ERROR(("%s: error writing DEVCTL: %d\n", + __FUNCTION__, err)); + bus->dhd->busstate = DHD_BUS_DOWN; + } + bus->clkstate = CLK_AVAIL; + } else { + goto clkwait; + } + } + + BUS_WAKE(bus); + + /* Make sure backplane clock is on */ + dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); + if (bus->clkstate != CLK_AVAIL) + goto clkwait; + + /* Pending interrupt indicates new device status */ + if (bus->ipend) { + bus->ipend = FALSE; + R_SDREG(newstatus, ®s->intstatus, retries); + bus->f1regdata++; + if (bcmsdh_regfail(bus->sdh)) + newstatus = 0; + newstatus &= bus->hostintmask; + bus->fcstate = !!(newstatus & I_HMB_FC_STATE); + if (newstatus) { + bus->f1regdata++; + if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && + (newstatus == I_XMTDATA_AVAIL)) { + } + else + W_SDREG(newstatus, ®s->intstatus, retries); + } + } + + /* 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_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries); + R_SDREG(newstatus, ®s->intstatus, retries); + bus->f1regdata += 2; + bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); + intstatus |= (newstatus & bus->hostintmask); + } + + /* Just being here means nothing more to do for chipactive */ + if (intstatus & I_CHIPACTIVE) { + /* ASSERT(bus->clkstate == CLK_AVAIL); */ + intstatus &= ~I_CHIPACTIVE; + } + + /* Handle host mailbox indication */ + if (intstatus & I_HMB_HOST_INT) { + intstatus &= ~I_HMB_HOST_INT; + intstatus |= dhdsdio_hostmail(bus); + } + + /* Generally don't ask for these, can get CRC errors... */ + if (intstatus & I_WR_OOSYNC) { + DHD_ERROR(("Dongle reports WR_OOSYNC\n")); + intstatus &= ~I_WR_OOSYNC; + } + + if (intstatus & I_RD_OOSYNC) { + DHD_ERROR(("Dongle reports RD_OOSYNC\n")); + intstatus &= ~I_RD_OOSYNC; + } + + if (intstatus & I_SBINT) { + DHD_ERROR(("Dongle reports SBINT\n")); + intstatus &= ~I_SBINT; + } + + /* Would be active due to wake-wlan in gSPI */ + if (intstatus & I_CHIPACTIVE) { + DHD_INFO(("Dongle reports CHIPACTIVE\n")); + intstatus &= ~I_CHIPACTIVE; + } + + if (intstatus & I_HMB_FC_STATE) { + DHD_INFO(("Dongle reports HMB_FC_STATE\n")); + intstatus &= ~I_HMB_FC_STATE; + } + + /* Ignore frame indications if rxskip is set */ + if (bus->rxskip) { + intstatus &= ~FRAME_AVAIL_MASK(bus); + } + + /* On frame indication, read available frames */ + if (PKT_AVAILABLE(bus, intstatus)) { + framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); + if (rxdone || bus->rxskip) + intstatus &= ~FRAME_AVAIL_MASK(bus); + rxlimit -= MIN(framecnt, rxlimit); + } + + /* Keep still-pending events for next scheduling */ + bus->intstatus = intstatus; + +clkwait: + /* Re-enable interrupts to detect new device events (mailbox, rx frame) + * or clock availability. (Allows tx loop to check ipend if desired.) + * (Unless register access seems hosed, as we may not be able to ACK...) + */ + if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) { + DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", + __FUNCTION__, rxdone, framecnt)); + bus->intdis = FALSE; +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(bus->sdh, TRUE); +#endif /* defined(OOB_INTR_ONLY) */ + bcmsdh_intr_enable(sdh); + } + +#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) + /* In case of SW-OOB(using edge trigger), + * Check interrupt status in the dongle again after enable irq on the host. + * and rechedule dpc if interrupt is pended in the dongle. + * There is a chance to miss OOB interrupt while irq is disabled on the host. + * No need to do this with HW-OOB(level trigger) + */ + R_SDREG(newstatus, ®s->intstatus, retries); + if (bcmsdh_regfail(bus->sdh)) + newstatus = 0; + if (newstatus & bus->hostintmask) { + bus->ipend = TRUE; + resched = TRUE; + } +#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ + +#ifdef PROP_TXSTATUS + dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE); +#endif + + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) + dhdsdio_sendpendctl(bus); + + /* Send queued frames (limit 1 if rx may still be pending) */ + else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && + pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { + framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax); + framecnt = dhdsdio_sendfromq(bus, framecnt); + txlimit -= framecnt; + } + /* Resched the DPC if ctrl cmd is pending on bus credit */ + if (bus->ctrl_frame_stat) + resched = TRUE; + + /* 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->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { + if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & + SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { + /* Bus failed because of KSO */ + DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__)); + bus->kso = FALSE; + } else { + DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n", + __FUNCTION__)); + bus->dhd->busstate = DHD_BUS_DOWN; + bus->intstatus = 0; + } + } else if (bus->clkstate == CLK_PENDING) { + /* Awaiting I_CHIPACTIVE; don't resched */ + } else if (bus->intstatus || bus->ipend || + (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || + PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ + resched = TRUE; + } + + bus->dpc_sched = resched; + + /* If we're done for now, turn off clock request. */ + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + } + +exit: + + if (!resched && dhd_dpcpoll) { + if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) { + resched = TRUE; +#if defined(CUSTOMER_HW5) + is_resched_by_readframe = TRUE; +#endif + } + } + + dhd_os_sdunlock(bus->dhd); +#if defined(CUSTOMER_HW5) + if (bus->dhd->dhd_bug_on) { + sprintf(bus->dpc_log_current, "%s: resched = %d ctrl_frame_stat = %d " + "intstatus 0x%08x ipend = %d pktq_mlen = %d " + "is_resched_by_readframe = %d TXCTLOK = %d, clkstate = %d\n", + __FUNCTION__, resched, bus->ctrl_frame_stat, + bus->intstatus, bus->ipend, + pktq_mlen(&bus->txq, ~bus->flowcontrol), is_resched_by_readframe, + TXCTLOK(bus), bus->clkstate); + if (strcmp(bus->dpc_log_previous, bus->dpc_log_current) == 0) { + /* Same log */ + bus->dpc_log_loops++; + } else { + if (bus->dpc_log_loops) { + DHD_ERROR(("(%d) %s\n", bus->dpc_log_loops, bus->dpc_log_previous)); + } + DHD_ERROR(("%s\n", bus->dpc_log_current)); + strcpy(bus->dpc_log_previous, bus->dpc_log_current); + bus->dpc_log_loops = 0; + } + bus->dhd->dhd_bug_on = FALSE; + } +#endif /* CUSTOMER_HW5 */ + return resched; +} + +bool +dhd_bus_dpc(struct dhd_bus *bus) +{ + bool resched; + + /* Call the DPC directly. */ + DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); + resched = dhdsdio_dpc(bus); + + return resched; +} + +void +dhdsdio_isr(void *arg) +{ + dhd_bus_t *bus = (dhd_bus_t*)arg; + bcmsdh_info_t *sdh; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!bus) { + DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); + return; + } + sdh = bus->sdh; + + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + return; + } + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* Count the interrupt call */ + bus->intrcount++; + bus->ipend = TRUE; + + /* Shouldn't get this interrupt if we're sleeping? */ + if (!SLPAUTO_ENAB(bus)) { + if (bus->sleeping) { + DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n")); + return; + } else if (!KSO_ENAB(bus)) { + DHD_ERROR(("ISR in devsleep 1\n")); + } + } + + /* Disable additional interrupts (is this needed now)? */ + if (bus->intr) { + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + } else { + DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n")); + } + + bcmsdh_intr_disable(sdh); + bus->intdis = TRUE; + +#if defined(SDIO_ISR_THREAD) + DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); + DHD_OS_WAKE_LOCK(bus->dhd); + dhdsdio_dpc(bus); + DHD_OS_WAKE_UNLOCK(bus->dhd); +#else + + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + +#endif /* defined(SDIO_ISR_THREAD) */ + +} + +#ifdef SDTEST +static void +dhdsdio_pktgen_init(dhd_bus_t *bus) +{ + /* Default to specified length, or full range */ + if (dhd_pktgen_len) { + bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN); + bus->pktgen_minlen = bus->pktgen_maxlen; + } else { + bus->pktgen_maxlen = MAX_PKTGEN_LEN; + bus->pktgen_minlen = 0; + } + bus->pktgen_len = (uint16)bus->pktgen_minlen; + + /* Default to per-watchdog burst with 10s print time */ + bus->pktgen_freq = 1; + bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0; + bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; + + /* Default to echo mode */ + bus->pktgen_mode = DHD_PKTGEN_ECHO; + bus->pktgen_stop = 1; +} + +static void +dhdsdio_pktgen(dhd_bus_t *bus) +{ + void *pkt; + uint8 *data; + uint pktcount; + uint fillbyte; + osl_t *osh = bus->dhd->osh; + uint16 len; + ulong time_lapse; + uint sent_pkts; + uint rcvd_pkts; + + /* Display current count if appropriate */ + if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { + bus->pktgen_ptick = 0; + printf("%s: send attempts %d, rcvd %d, errors %d\n", + __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); + + /* Print throughput stats only for constant length packet runs */ + if (bus->pktgen_minlen == bus->pktgen_maxlen) { + time_lapse = jiffies - bus->pktgen_prev_time; + bus->pktgen_prev_time = jiffies; + sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent; + bus->pktgen_prev_sent = bus->pktgen_sent; + rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd; + bus->pktgen_prev_rcvd = bus->pktgen_rcvd; + + printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n", + __FUNCTION__, + (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8, + (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8); + } + } + + /* For recv mode, just make sure dongle has started sending */ + if (bus->pktgen_mode == DHD_PKTGEN_RECV) { + if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { + bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; + dhdsdio_sdtest_set(bus, bus->pktgen_total); + } + return; + } + + /* Otherwise, generate or request the specified number of packets */ + for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) { + /* Stop if total has been reached */ + if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) { + bus->pktgen_count = 0; + break; + } + + /* Allocate an appropriate-sized packet */ + if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { + len = SDPCM_TEST_PKT_CNT_FLD_LEN; + } else { + len = bus->pktgen_len; + } + if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), + TRUE))) {; + DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); + break; + } + PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); + data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; + + /* Write test header cmd and extra based on mode */ + switch (bus->pktgen_mode) { + case DHD_PKTGEN_ECHO: + *data++ = SDPCM_TEST_ECHOREQ; + *data++ = (uint8)bus->pktgen_sent; + break; + + case DHD_PKTGEN_SEND: + *data++ = SDPCM_TEST_DISCARD; + *data++ = (uint8)bus->pktgen_sent; + break; + + case DHD_PKTGEN_RXBURST: + *data++ = SDPCM_TEST_BURST; + *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */ + break; + + default: + DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode)); + PKTFREE(osh, pkt, TRUE); + bus->pktgen_count = 0; + return; + } + + /* Write test header length field */ + *data++ = (bus->pktgen_len >> 0); + *data++ = (bus->pktgen_len >> 8); + + /* Write frame count in a 4 byte field adjucent to SDPCM test header for + * burst mode + */ + if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { + *data++ = (uint8)(bus->pktgen_count >> 0); + *data++ = (uint8)(bus->pktgen_count >> 8); + *data++ = (uint8)(bus->pktgen_count >> 16); + *data++ = (uint8)(bus->pktgen_count >> 24); + } else { + + /* Then fill in the remainder -- N/A for burst */ + for (fillbyte = 0; fillbyte < len; fillbyte++) + *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); + } + +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_DATA_ON()) { + data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; + prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN); + } +#endif + + /* Send it */ + if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) { + bus->pktgen_fail++; + if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) + bus->pktgen_count = 0; + } + bus->pktgen_sent++; + + /* Bump length if not fixed, wrap at max */ + if (++bus->pktgen_len > bus->pktgen_maxlen) + bus->pktgen_len = (uint16)bus->pktgen_minlen; + + /* Special case for burst mode: just send one request! */ + if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) + break; + } +} + +static void +dhdsdio_sdtest_set(dhd_bus_t *bus, uint count) +{ + void *pkt; + uint8 *data; + osl_t *osh = bus->dhd->osh; + + /* Allocate the packet */ + if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + + SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) { + DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); + return; + } + PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + + SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN); + data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; + + /* Fill in the test header */ + *data++ = SDPCM_TEST_SEND; + *data++ = (count > 0)?TRUE:FALSE; + *data++ = (bus->pktgen_maxlen >> 0); + *data++ = (bus->pktgen_maxlen >> 8); + *data++ = (uint8)(count >> 0); + *data++ = (uint8)(count >> 8); + *data++ = (uint8)(count >> 16); + *data++ = (uint8)(count >> 24); + + /* Send it */ + if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) + bus->pktgen_fail++; +} + + +static void +dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) +{ + osl_t *osh = bus->dhd->osh; + uint8 *data; + uint pktlen; + + uint8 cmd; + uint8 extra; + uint16 len; + uint16 offset; + + /* Check for min length */ + if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) { + DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen)); + PKTFREE(osh, pkt, FALSE); + return; + } + + /* Extract header fields */ + data = PKTDATA(osh, pkt); + cmd = *data++; + extra = *data++; + len = *data++; len += *data++ << 8; + DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len)); + /* Check length for relevant commands */ + if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { + if (pktlen != len + SDPCM_TEST_HDRLEN) { + DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d" + " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); + PKTFREE(osh, pkt, FALSE); + return; + } + } + + /* Process as per command */ + switch (cmd) { + case SDPCM_TEST_ECHOREQ: + /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ + *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; + if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) { + bus->pktgen_sent++; + } else { + bus->pktgen_fail++; + PKTFREE(osh, pkt, FALSE); + } + bus->pktgen_rcvd++; + break; + + case SDPCM_TEST_ECHORSP: + if (bus->ext_loop) { + PKTFREE(osh, pkt, FALSE); + bus->pktgen_rcvd++; + break; + } + + for (offset = 0; offset < len; offset++, data++) { + if (*data != SDPCM_TEST_FILL(offset, extra)) { + DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: " + "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n", + offset, len, SDPCM_TEST_FILL(offset, extra), *data)); + break; + } + } + PKTFREE(osh, pkt, FALSE); + bus->pktgen_rcvd++; + break; + + case SDPCM_TEST_DISCARD: + { + int i = 0; + uint8 *prn = data; + uint8 testval = extra; + for (i = 0; i < len; i++) { + if (*prn != testval) { + DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", + i, bus->pktgen_rcvd_rcvsession, testval, *prn)); + prn++; testval++; + } + } + } + PKTFREE(osh, pkt, FALSE); + bus->pktgen_rcvd++; + break; + + case SDPCM_TEST_BURST: + case SDPCM_TEST_SEND: + default: + DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d" + " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); + PKTFREE(osh, pkt, FALSE); + break; + } + + /* For recv mode, stop at limit (and tell dongle to stop sending) */ + if (bus->pktgen_mode == DHD_PKTGEN_RECV) { + if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { + bus->pktgen_rcvd_rcvsession++; + + if (bus->pktgen_total && + (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { + bus->pktgen_count = 0; + DHD_ERROR(("Pktgen:rcv test complete!\n")); + bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; + dhdsdio_sdtest_set(bus, FALSE); + bus->pktgen_rcvd_rcvsession = 0; + } + } + } +} +#endif /* SDTEST */ + +int dhd_bus_oob_intr_register(dhd_pub_t *dhdp) +{ + int err = 0; + +#if defined(OOB_INTR_ONLY) + err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus); +#endif + return err; +} + +void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp) +{ +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_unregister(dhdp->bus->sdh); +#endif +} + +void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable) +{ +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(dhdp->bus->sdh, enable); +#endif +} + +void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub) +{ + bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh); +} + +void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub) +{ + bcmsdh_dev_relax(dhdpub->bus->sdh); +} + +bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub) +{ + bool enabled = FALSE; + + enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh); + return enabled; +} + +extern bool +dhd_bus_watchdog(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus; + + DHD_TIMER(("%s: Enter\n", __FUNCTION__)); + + bus = dhdp->bus; + + if (bus->dhd->dongle_reset) + return FALSE; + + if (bus->dhd->hang_was_sent) { + dhd_os_wd_timer(bus->dhd, 0); + return FALSE; + } + + /* Ignore the timer if simulating bus down */ + if (!SLPAUTO_ENAB(bus) && bus->sleeping) + return FALSE; + + if (dhdp->busstate == DHD_BUS_DOWN) + return FALSE; + + /* Poll period: check device if appropriate. */ + if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) { + uint32 intstatus = 0; + + /* Reset poll tick */ + bus->polltick = 0; + + /* Check device if no interrupts */ + if (!bus->intr || (bus->intrcount == bus->lastintrs)) { + + if (!bus->dpc_sched) { + uint8 devpend; + devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, + SDIOD_CCCR_INTPEND, 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; + if (bus->intr) { + bcmsdh_intr_disable(bus->sdh); + } + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + } + } + + /* Update interrupt tracking */ + bus->lastintrs = bus->intrcount; + } + +#ifdef DHD_DEBUG + /* Poll for console output periodically */ + if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { + bus->console.count += dhd_watchdog_ms; + if (bus->console.count >= dhd_console_ms) { + bus->console.count -= dhd_console_ms; + /* Make sure backplane clock is on */ + if (SLPAUTO_ENAB(bus)) + dhdsdio_bussleep(bus, FALSE); + else + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (dhdsdio_readconsole(bus) < 0) + dhd_console_ms = 0; /* On error, stop trying */ + } + } +#endif /* DHD_DEBUG */ + +#ifdef SDTEST + /* Generate packets if configured */ + if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { + /* Make sure backplane clock is on */ + if (SLPAUTO_ENAB(bus)) + dhdsdio_bussleep(bus, FALSE); + else + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + bus->pktgen_tick = 0; + dhdsdio_pktgen(bus); + } +#endif + + /* On idle timeout clear activity flag and/or turn off clock */ +#ifdef DHD_USE_IDLECOUNT + if (bus->activity) + bus->activity = FALSE; + else { + bus->idlecount++; + + if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) { + DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); + if (SLPAUTO_ENAB(bus)) { + if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) + dhd_os_wd_timer(bus->dhd, 0); + } else + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + + bus->idlecount = 0; + } + } +#else + if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { + if (++bus->idlecount >= bus->idletime) { + bus->idlecount = 0; + if (bus->activity) { + bus->activity = FALSE; + if (SLPAUTO_ENAB(bus)) { + if (!bus->readframes) + dhdsdio_bussleep(bus, TRUE); + else + bus->reqbussleep = TRUE; + } + else + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + } + } + } +#endif /* DHD_USE_IDLECOUNT */ + + return bus->ipend; +} + +#ifdef DHD_DEBUG +extern int +dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) +{ + dhd_bus_t *bus = dhdp->bus; + uint32 addr, val; + int rv; + void *pkt; + + /* Address could be zero if CONSOLE := 0 in dongle Makefile */ + if (bus->console_addr == 0) + return BCME_UNSUPPORTED; + + /* Exclusive bus access */ + dhd_os_sdlock(bus->dhd); + + /* Don't allow input if dongle is in reset */ + if (bus->dhd->dongle_reset) { + dhd_os_sdunlock(bus->dhd); + return BCME_NOTREADY; + } + + /* Request clock to allow SDIO accesses */ + BUS_WAKE(bus); + /* No pend allowed since txpkt is called later, ht clk has to be on */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Zero cbuf_index */ + addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx); + val = htol32(0); + if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) + goto done; + + /* Write message into cbuf */ + addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf); + if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) + goto done; + + /* Write length into vcons_in */ + addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in); + val = htol32(msglen); + if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) + goto done; + + /* Bump dongle by sending an empty packet on the event channel. + * sdpcm_sendup (RX) checks for virtual console input. + */ + if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) + rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE); + +done: + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + + return rv; +} +#endif /* DHD_DEBUG */ + +#ifdef DHD_DEBUG +static void +dhd_dump_cis(uint fn, uint8 *cis) +{ + uint byte, tag, tdata; + DHD_INFO(("Function %d CIS:\n", fn)); + + for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { + if ((byte % 16) == 0) + DHD_INFO((" ")); + DHD_INFO(("%02x ", cis[byte])); + if ((byte % 16) == 15) + DHD_INFO(("\n")); + if (!tdata--) { + tag = cis[byte]; + if (tag == 0xff) + break; + else if (!tag) + tdata = 0; + else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) + tdata = cis[byte + 1] + 1; + else + DHD_INFO(("]")); + } + } + if ((byte % 16) != 15) + DHD_INFO(("\n")); +} +#endif /* DHD_DEBUG */ + +static bool +dhdsdio_chipmatch(uint16 chipid) +{ + if (chipid == BCM4325_CHIP_ID) + return TRUE; + if (chipid == BCM4329_CHIP_ID) + return TRUE; + if (chipid == BCM4315_CHIP_ID) + return TRUE; + if (chipid == BCM4319_CHIP_ID) + return TRUE; + if (chipid == BCM4336_CHIP_ID) + return TRUE; + if (chipid == BCM4330_CHIP_ID) + return TRUE; + if (chipid == BCM43237_CHIP_ID) + return TRUE; + if (chipid == BCM43362_CHIP_ID) + return TRUE; + if (chipid == BCM4314_CHIP_ID) + return TRUE; + if (chipid == BCM43242_CHIP_ID) + return TRUE; + if (chipid == BCM43340_CHIP_ID) + return TRUE; + if (chipid == BCM43341_CHIP_ID) + return TRUE; + if (chipid == BCM43143_CHIP_ID) + return TRUE; + if (chipid == BCM43342_CHIP_ID) + return TRUE; + if (chipid == BCM4334_CHIP_ID) + return TRUE; + if (chipid == BCM43239_CHIP_ID) + return TRUE; + if (chipid == BCM4324_CHIP_ID) + return TRUE; + if (chipid == BCM4335_CHIP_ID) + return TRUE; + if (chipid == BCM4339_CHIP_ID) + return TRUE; + if (chipid == BCM43349_CHIP_ID) + return TRUE; + if (chipid == BCM4345_CHIP_ID || chipid == BCM43454_CHIP_ID) + return TRUE; + if (chipid == BCM4350_CHIP_ID) + return TRUE; + if (chipid == BCM4354_CHIP_ID) + return TRUE; + if (chipid == BCM4356_CHIP_ID) + return TRUE; + if (chipid == BCM43430_CHIP_ID) + return TRUE; + return FALSE; +} + +static void * +dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, + uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) +{ + int ret; + dhd_bus_t *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. + */ + dhd_txbound = DHD_TXBOUND; + dhd_rxbound = DHD_RXBOUND; + dhd_alignctl = TRUE; + sd1idle = TRUE; + dhd_readahead = TRUE; + retrydata = FALSE; + + dhd_doflow = FALSE; + dhd_dongle_ramsize = 0; + dhd_txminmax = DHD_TXMINMAX; + + forcealign = TRUE; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid)); + + /* We make assumptions about address window mappings */ + ASSERT((uintptr)regsva == SI_ENUM_BASE); + + /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start + * means early parse could fail, so here we should get either an ID + * we recognize OR (-1) indicating we must request power first. + */ + /* Check the Vendor ID */ + switch (venid) { + case 0x0000: + case VENDOR_BROADCOM: + break; + default: + DHD_ERROR(("%s: unknown vendor: 0x%04x\n", + __FUNCTION__, venid)); + goto forcereturn; + } + + /* Check the Device ID and make sure it's one that we support */ + switch (devid) { + case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */ + case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */ + case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */ + DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__)); + break; + case BCM4329_D11N_ID: /* 4329 802.11n dualband device */ + case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */ + case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */ + case 0x4329: + DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__)); + break; + case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */ + case BCM4315_D11G_ID: /* 4315 802.11g id */ + case BCM4315_D11A_ID: /* 4315 802.11a id */ + DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__)); + break; + case BCM4319_D11N_ID: /* 4319 802.11n id */ + case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ + case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ + DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__)); + break; + case 0: + DHD_INFO(("%s: allow device id 0, will check chip internals\n", + __FUNCTION__)); + break; + + default: + DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", + __FUNCTION__, venid, devid)); + goto forcereturn; + } + + if (osh == NULL) { + DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__)); + goto forcereturn; + } + + /* Allocate private bus interface state */ + if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { + DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); + goto fail; + } + bzero(bus, sizeof(dhd_bus_t)); + bus->sdh = sdh; + bus->cl_devid = (uint16)devid; + bus->bus = DHD_BUS; + bus->bus_num = bus_no; + bus->slot_num = slot; + bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; + bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */ + +#if defined(SUPPORT_P2P_GO_PS) + init_waitqueue_head(&bus->bus_sleep); +#endif /* LINUX && SUPPORT_P2P_GO_PS */ + + /* attempt to attach to the dongle */ + if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { + DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__)); + goto fail; + } + + /* Attach to the dhd/OS/network interface */ + if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) { + DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); + goto fail; + } + + /* Allocate buffers */ + if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { + DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__)); + goto fail; + } + + if (!(dhdsdio_probe_init(bus, osh, sdh))) { + DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__)); + goto fail; + } + + if (bus->intr) { + /* Register interrupt callback, but mask it (not operational yet). */ + DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__)); + bcmsdh_intr_disable(sdh); + if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { + DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n", + __FUNCTION__, ret)); + goto fail; + } + DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__)); + } else { + DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n", + __FUNCTION__)); + } + + DHD_INFO(("%s: completed!!\n", __FUNCTION__)); + + /* if firmware path present try to download and bring up bus */ + bus->dhd->hang_report = TRUE; + if (dhd_download_fw_on_driverload) { + if ((ret = dhd_bus_start(bus->dhd)) != 0) { + DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); + goto fail; + } + } + /* Ok, have the per-port tell the stack we're open for business */ + if (dhd_register_if(bus->dhd, 0, TRUE) != 0) { + DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); + goto fail; + } + + + return bus; + +fail: + dhdsdio_release(bus, osh); + +forcereturn: + + return NULL; +} + +static bool +dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, + uint16 devid) +{ + int err = 0; + uint8 clkctl = 0; + + bus->alp_only = TRUE; + bus->sih = NULL; + + /* Return the window to backplane enumeration space for core access */ + if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) { + DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__)); + } + + + /* Force PLL off until si_attach() programs PLL control regs */ + + + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err); + if (!err) + clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + + if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) { + DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", + err, DHD_INIT_CLKCTL1, clkctl)); + goto fail; + } + +#ifdef DHD_DEBUG + if (DHD_INFO_ON()) { + uint fn, numfn; + uint8 *cis[SDIOD_MAX_IOFUNCS]; + int err = 0; + + numfn = bcmsdh_query_iofnum(sdh); + ASSERT(numfn <= SDIOD_MAX_IOFUNCS); + + /* Make sure ALP is available before trying to read CIS */ + SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, NULL)), + !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY); + + /* Now request ALP be put on the bus */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + DHD_INIT_CLKCTL2, &err); + OSL_DELAY(65); + + for (fn = 0; fn <= numfn; fn++) { + if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { + DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn)); + break; + } + bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); + + if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) { + DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err)); + MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); + break; + } + dhd_dump_cis(fn, cis[fn]); + } + + while (fn-- > 0) { + ASSERT(cis[fn]); + MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); + } + + if (err) { + DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n")); + goto fail; + } + } +#endif /* DHD_DEBUG */ + + /* si_attach() will provide an SI handle and scan the backplane */ + if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, + &bus->vars, &bus->varsz))) { + DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); + goto fail; + } + +#ifdef DHD_DEBUG + DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n", + bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg)); +#endif /* DHD_DEBUG */ + + + bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); + + if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { + DHD_ERROR(("%s: unsupported chip: 0x%04x\n", + __FUNCTION__, bus->sih->chip)); + goto fail; + } + + if (bus->sih->buscorerev >= 12) + dhdsdio_clk_kso_init(bus); + else + bus->kso = TRUE; + + if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) { + } + + si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); + + + /* Get info on the ARM and SOCRAM cores... */ + if (!DHD_NOPMU(bus)) { + if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || + (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || + (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { + bus->armrev = si_corerev(bus->sih); + } else { + DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); + goto fail; + } + + if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { + DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); + goto fail; + } + } else { + /* cr4 has a different way to find the RAM size from TCM's */ + if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { + DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); + goto fail; + } + /* also populate base address */ + switch ((uint16)bus->sih->chip) { + case BCM4335_CHIP_ID: + case BCM4339_CHIP_ID: + case BCM43349_CHIP_ID: + bus->dongle_ram_base = CR4_4335_RAM_BASE; + break; + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM4356_CHIP_ID: + bus->dongle_ram_base = CR4_4350_RAM_BASE; + break; + case BCM4360_CHIP_ID: + bus->dongle_ram_base = CR4_4360_RAM_BASE; + break; + case BCM4345_CHIP_ID: + case BCM43454_CHIP_ID: + bus->dongle_ram_base = (bus->sih->chiprev < 6) /* from 4345C0 */ + ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE; + break; + default: + bus->dongle_ram_base = 0; + DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", + __FUNCTION__, bus->dongle_ram_base)); + } + } + bus->ramsize = bus->orig_ramsize; + if (dhd_dongle_ramsize) + dhd_dongle_setramsize(bus, dhd_dongle_ramsize); + + DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", + bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); + + bus->srmemsize = si_socram_srmem_size(bus->sih); + } + + /* ...but normally deal with the SDPCMDEV core */ + if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) && + !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) { + DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__)); + goto fail; + } + bus->sdpcmrev = si_corerev(bus->sih); + + /* Set core control so an SDIO reset does a backplane reset */ + OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); + bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; + + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && + (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) + { + uint32 val; + + val = R_REG(osh, &bus->regs->corecontrol); + val &= ~CC_XMTDATAAVAIL_MODE; + val |= CC_XMTDATAAVAIL_CTRL; + W_REG(osh, &bus->regs->corecontrol, val); + } + + + pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); + + /* Locate an appropriately-aligned portion of hdrbuf */ + bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); + + /* Set the poll and/or interrupt flags */ + bus->intr = (bool)dhd_intr; + if ((bus->poll = (bool)dhd_poll)) + bus->pollrate = 1; + + /* Setting default Glom size */ + bus->txglomsize = SDPCM_DEFGLOM_SIZE; + + return TRUE; + +fail: + if (bus->sih != NULL) { + si_detach(bus->sih); + bus->sih = NULL; + } + return FALSE; +} + +static bool +dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->maxctl) { + bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; + if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) { + DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", + __FUNCTION__, bus->rxblen)); + goto fail; + } + } + /* Allocate buffer to receive glomed packet */ + if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { + DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", + __FUNCTION__, MAX_DATA_BUF)); + /* release rxbuf which was already located as above */ + if (!bus->rxblen) + DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen); + goto fail; + } + + /* Align the buffer */ + if ((uintptr)bus->databuf % DHD_SDALIGN) + bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN)); + else + bus->dataptr = bus->databuf; + + return TRUE; + +fail: + return FALSE; +} + +static bool +dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) +{ + int32 fnum; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + bus->_srenab = FALSE; + +#ifdef SDTEST + dhdsdio_pktgen_init(bus); +#endif /* SDTEST */ + + /* Disable F2 to clear any intermediate frame state on the dongle */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); + + bus->dhd->busstate = DHD_BUS_DOWN; + bus->sleeping = FALSE; + bus->rxflow = FALSE; + bus->prev_rxlim_hit = 0; + + /* Done with backplane-dependent accesses, can drop clock... */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + + /* ...and initialize clock/power states */ + bus->clkstate = CLK_SDONLY; + bus->idletime = (int32)dhd_idletime; + bus->idleclock = DHD_IDLE_ACTIVE; + + /* Query the SD clock speed */ + if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, + &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor")); + bus->sd_divisor = -1; + } else { + DHD_INFO(("%s: Initial value for %s is %d\n", + __FUNCTION__, "sd_divisor", bus->sd_divisor)); + } + + /* Query the SD bus mode */ + if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, + &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode")); + bus->sd_mode = -1; + } else { + DHD_INFO(("%s: Initial value for %s is %d\n", + __FUNCTION__, "sd_mode", bus->sd_mode)); + } + + /* Query the F2 block size, set roundup accordingly */ + fnum = 2; + if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32), + &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { + bus->blocksize = 0; + DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); + } else { + DHD_INFO(("%s: Initial value for %s is %d\n", + __FUNCTION__, "sd_blocksize", bus->blocksize)); + + dhdsdio_tune_fifoparam(bus); + } + bus->roundup = MIN(max_roundup, bus->blocksize); + + if (bus->pad_pkt) + PKTFREE(osh, bus->pad_pkt, FALSE); + bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE); + if (bus->pad_pkt == NULL) + DHD_ERROR(("failed to allocate padding packet\n")); + else { + int alignment_offset = 0; + uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt); + if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN))) + PKTPUSH(osh, bus->pad_pkt, alignment_offset); + PKTSETNEXT(osh, bus->pad_pkt, NULL); + } + + /* Query if bus module supports packet chaining, default to use if supported */ + if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, + &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) { + bus->sd_rxchain = FALSE; + } else { + DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n", + __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support"))); + } + bus->use_rxchain = (bool)bus->sd_rxchain; + bus->txinrx_thres = CUSTOM_TXINRX_THRES; + /* TX first in dhdsdio_readframes() */ + bus->dotxinrx = TRUE; +#if defined(CUSTOMER_HW5) + memset(bus->dpc_log_previous, 0, sizeof(bus->dpc_log_previous)); + memset(bus->dpc_log_current, 0, sizeof(bus->dpc_log_current)); + bus->dpc_log_loops = 0; +#endif /* CUSTOMER_HW5 */ + + return TRUE; +} + +int +dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, + char *pfw_path, char *pnv_path) +{ + int ret; + + bus->fw_path = pfw_path; + bus->nv_path = pnv_path; + + ret = dhdsdio_download_firmware(bus, osh, bus->sdh); + + + return ret; +} + +static int +dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) +{ + int ret; + + + DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n", + __FUNCTION__, bus->fw_path, bus->nv_path)); + DHD_OS_WAKE_LOCK(bus->dhd); + + /* Download the firmware */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + ret = _dhdsdio_download_firmware(bus); + + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + + DHD_OS_WAKE_UNLOCK(bus->dhd); + return ret; +} + +/* Detach and free everything */ +static void +dhdsdio_release(dhd_bus_t *bus, osl_t *osh) +{ + bool dongle_isolation = FALSE; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus) { + ASSERT(osh); + + if (bus->dhd) { + dongle_isolation = bus->dhd->dongle_isolation; + dhd_detach(bus->dhd); + } + + /* De-register interrupt handler */ + bcmsdh_intr_disable(bus->sdh); + bcmsdh_intr_dereg(bus->sdh); + + if (bus->dhd) { + dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); + dhd_free(bus->dhd); + bus->dhd = NULL; + } + + dhdsdio_release_malloc(bus, osh); + +#ifdef DHD_DEBUG + if (bus->console.buf != NULL) + MFREE(osh, bus->console.buf, bus->console.bufsize); +#endif + + if (bus->pad_pkt) + PKTFREE(osh, bus->pad_pkt, FALSE); + + MFREE(osh, bus, sizeof(dhd_bus_t)); + } + + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); +} + +static void +dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd && bus->dhd->dongle_reset) + return; + + if (bus->rxbuf) { +#ifndef CONFIG_DHD_USE_STATIC_BUF + MFREE(osh, bus->rxbuf, bus->rxblen); +#endif + bus->rxctl = bus->rxbuf = NULL; + bus->rxlen = 0; + } + + if (bus->databuf) { +#ifndef CONFIG_DHD_USE_STATIC_BUF + MFREE(osh, bus->databuf, MAX_DATA_BUF); +#endif + bus->databuf = NULL; + } + + if (bus->vars && bus->varsz) { + MFREE(osh, bus->vars, bus->varsz); + bus->vars = NULL; + } + +} + + +static void +dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) +{ + DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, + bus->dhd, bus->dhd->dongle_reset)); + + if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) + return; + + if (bus->sih) { +#if !defined(BCMLXSDMMC) + if (bus->dhd) { + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + } + if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) + si_watchdog(bus->sih, 4); +#endif /* !defined(BCMLXSDMMC) */ + if (bus->dhd) { + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + } + si_detach(bus->sih); + bus->sih = NULL; + if (bus->vars && bus->varsz) + MFREE(osh, bus->vars, bus->varsz); + bus->vars = NULL; + } + + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); +} + +static void +dhdsdio_disconnect(void *ptr) +{ + dhd_bus_t *bus = (dhd_bus_t *)ptr; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + + + if (bus) { + ASSERT(bus->dhd); + dhdsdio_release(bus, bus->dhd->osh); + } + + + + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); +} + +static int +dhdsdio_suspend(void *context) +{ + int ret = 0; + + dhd_bus_t *bus = (dhd_bus_t*)context; +#ifdef SUPPORT_P2P_GO_PS + int wait_time = 0; + + if (bus->idletime > 0) { + wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms); + } +#endif /* SUPPORT_P2P_GO_PS */ + ret = dhd_os_check_wakelock(bus->dhd); +#ifdef SUPPORT_P2P_GO_PS + if ((!ret) && (bus->dhd->up) && (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) { + if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) { + if (!bus->sleeping) { + return 1; + } + } + } +#endif /* SUPPORT_P2P_GO_PS */ + return ret; +} + +static int +dhdsdio_resume(void *context) +{ +#if defined(OOB_INTR_ONLY) + dhd_bus_t *bus = (dhd_bus_t*)context; + + if (dhd_os_check_if_up(bus->dhd)) + bcmsdh_oob_intr_set(bus->sdh, TRUE); +#endif + return 0; +} + + +/* Register/Unregister functions are called by the main DHD entry + * point (e.g. module insertion) to link with the bus driver, in + * order to look for or await the device. + */ + +static bcmsdh_driver_t dhd_sdio = { + dhdsdio_probe, + dhdsdio_disconnect, + dhdsdio_suspend, + dhdsdio_resume +}; + +int +dhd_bus_register(void) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + return bcmsdh_register(&dhd_sdio); +} + +void +dhd_bus_unregister(void) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + bcmsdh_unregister(); +} + +#if defined(BCMLXSDMMC) +/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ +int dhd_bus_reg_sdio_notify(void* semaphore) +{ + return bcmsdh_reg_sdio_notify(semaphore); +} + +void dhd_bus_unreg_sdio_notify(void) +{ + bcmsdh_unreg_sdio_notify(); +} +#endif /* defined(BCMLXSDMMC) */ + +#ifdef BCMEMBEDIMAGE +static int +dhdsdio_download_code_array(struct dhd_bus *bus) +{ + int bcmerror = -1; + int offset = 0; + unsigned char *ularray = NULL; + + DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__)); + + /* Download image */ + while ((offset + MEMBLOCK) < sizeof(dlarray)) { + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)dlarray)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + + bcmerror = dhdsdio_membytes(bus, TRUE, offset, + (uint8 *) (dlarray + offset), MEMBLOCK); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + + offset += MEMBLOCK; + } + + if (offset < sizeof(dlarray)) { + bcmerror = dhdsdio_membytes(bus, TRUE, offset, + (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); + goto err; + } + } + +#ifdef DHD_DEBUG + /* Upload and compare the downloaded code */ + { + ularray = MALLOC(bus->dhd->osh, bus->ramsize); + /* Upload image to verify downloaded contents. */ + offset = 0; + memset(ularray, 0xaa, bus->ramsize); + while ((offset + MEMBLOCK) < sizeof(dlarray)) { + bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + + offset += MEMBLOCK; + } + + if (offset < sizeof(dlarray)) { + bcmerror = dhdsdio_membytes(bus, FALSE, offset, + ularray + offset, sizeof(dlarray) - offset); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); + goto err; + } + } + + if (memcmp(dlarray, ularray, sizeof(dlarray))) { + DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", + __FUNCTION__, dlimagename, dlimagever, dlimagedate)); + goto err; + } else + DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", + __FUNCTION__, dlimagename, dlimagever, dlimagedate)); + + } +#endif /* DHD_DEBUG */ + +err: + if (ularray) + MFREE(bus->dhd->osh, ularray, bus->ramsize); + return bcmerror; +} +#endif /* BCMEMBEDIMAGE */ + +static int +dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) +{ + int bcmerror = -1; + int offset = 0; + int len; + void *image = NULL; + uint8 *memblock = NULL, *memptr; + + DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); + + image = dhd_os_open_image(pfw_path); + if (image == NULL) + goto err; + + memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); + if (memblock == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); + goto err; + } + if ((uint32)(uintptr)memblock % DHD_SDALIGN) + memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); + + /* Download image */ + while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { + if (len < 0) { + DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); + bcmerror = BCME_ERROR; + goto err; + } + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)memptr)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + + bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + + offset += MEMBLOCK; + } + +err: + if (memblock) + MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); + + if (image) + dhd_os_close_image(image); + + return bcmerror; +} + +/* + EXAMPLE: nvram_array + nvram_arry format: + name=value + Use carriage return at the end of each assignment, and an empty string with + carriage return at the end of array. + + For example: + unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"}; + Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx. + + Search "EXAMPLE: nvram_array" to see how the array is activated. +*/ + +void +dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params) +{ + bus->nvram_params = nvram_params; +} + +static int +dhdsdio_download_nvram(struct dhd_bus *bus) +{ + int bcmerror = -1; + uint len; + void * image = NULL; + char * memblock = NULL; + char *bufp; + char *pnv_path; + bool nvram_file_exists; + + pnv_path = bus->nv_path; + + nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); + if (!nvram_file_exists && (bus->nvram_params == NULL)) + return (0); + + if (nvram_file_exists) { + image = dhd_os_open_image(pnv_path); + if (image == NULL) + goto err; + } + + memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); + if (memblock == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", + __FUNCTION__, MAX_NVRAMBUF_SIZE)); + goto err; + } + + /* Download variables */ + if (nvram_file_exists) { + len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); + } + else { + len = strlen(bus->nvram_params); + ASSERT(len <= MAX_NVRAMBUF_SIZE); + memcpy(memblock, bus->nvram_params, len); + } + if (len > 0 && len < MAX_NVRAMBUF_SIZE) { + bufp = (char *)memblock; + bufp[len] = 0; + + if (somc_txpower_calibrate(memblock, len) != BCME_OK) { + DHD_ERROR(("%s: error calibrating tx power\n", __FUNCTION__)); + goto err; + } + + len = process_nvram_vars(bufp, len); + if (len % 4) { + len += 4 - (len % 4); + } + bufp += len; + *bufp++ = 0; + if (len) + bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1); + if (bcmerror) { + DHD_ERROR(("%s: error downloading vars: %d\n", + __FUNCTION__, bcmerror)); + } + } + else { + DHD_ERROR(("%s: error reading nvram file: %d\n", + __FUNCTION__, len)); + bcmerror = BCME_SDIO_ERROR; + } + +err: + if (memblock) + MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); + + if (image) + dhd_os_close_image(image); + + return bcmerror; +} + +static int +_dhdsdio_download_firmware(struct dhd_bus *bus) +{ + int bcmerror = -1; + + bool embed = FALSE; /* download embedded firmware */ + bool dlok = FALSE; /* download firmware succeeded */ + + /* Out immediately if no image to download */ + if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { +#ifdef BCMEMBEDIMAGE + embed = TRUE; +#else + return 0; +#endif + } + + /* Keep arm in reset */ + if (dhdsdio_download_state(bus, TRUE)) { + DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); + goto err; + } + + /* External image takes precedence if specified */ + if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { + if (dhdsdio_download_code_file(bus, bus->fw_path)) { + DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); +#ifdef BCMEMBEDIMAGE + embed = TRUE; +#else + goto err; +#endif + } + else { + embed = FALSE; + dlok = TRUE; + } + } + +#ifdef BCMEMBEDIMAGE + if (embed) { + if (dhdsdio_download_code_array(bus)) { + DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); + goto err; + } + else { + dlok = TRUE; + } + } +#else + BCM_REFERENCE(embed); +#endif + if (!dlok) { + DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); + goto err; + } + + /* EXAMPLE: nvram_array */ + /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ + /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ + + /* External nvram takes precedence if specified */ + if (dhdsdio_download_nvram(bus)) { + DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); + goto err; + } + + /* Take arm out of reset */ + if (dhdsdio_download_state(bus, FALSE)) { + DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); + goto err; + } + + bcmerror = 0; + +err: + return bcmerror; +} + +static int +dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, + void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) +{ + int status; + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + return BCME_NODEVICE; + } + + status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle); + + return status; +} + +static int +dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, + void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry) +{ + int ret; + int i = 0; + int retries = 0; + bcmsdh_info_t *sdh; + + if (!KSO_ENAB(bus)) { + DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); + return BCME_NODEVICE; + } + + sdh = bus->sdh; + do { + ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, + pkt, complete, handle); + + bus->f2txdata++; + ASSERT(ret != BCME_PENDING); + + if (ret == BCME_NODEVICE) { + DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); + } else if (ret < 0) { + /* On failure, abort the command and terminate the frame */ + DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n", + __FUNCTION__, ret)); + bus->tx_sderrs++; + bus->f1regdata++; + bus->dhd->tx_errors++; + bcmsdh_abort(sdh, SDIO_FUNC_2); + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, NULL); + for (i = 0; i < READ_FRM_CNT_RETRIES; i++) { + uint8 hi, lo; + hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI, + NULL); + lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO, + NULL); + bus->f1regdata += 2; + if ((hi == 0) && (lo == 0)) + break; + } + } + } while ((ret < 0) && retrydata && ++retries < max_retry); + + return ret; +} + +uint +dhd_bus_chip(struct dhd_bus *bus) +{ + ASSERT(bus->sih != NULL); + return bus->sih->chip; +} + +uint +dhd_bus_chiprev(struct dhd_bus *bus) +{ + ASSERT(bus); + ASSERT(bus->sih != NULL); + return bus->sih->chiprev; +} + +void * +dhd_bus_pub(struct dhd_bus *bus) +{ + return bus->dhd; +} + +void * +dhd_bus_sih(struct dhd_bus *bus) +{ + return (void *)bus->sih; +} + +void * +dhd_bus_txq(struct dhd_bus *bus) +{ + return &bus->txq; +} + +void +dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val) +{ + bus->dotxinrx = val; +} + +int +dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) +{ + int bcmerror = 0; + dhd_bus_t *bus; + + bus = dhdp->bus; + + if (flag == TRUE) { + if (!bus->dhd->dongle_reset) { + dhd_os_sdlock(dhdp); + dhd_os_wd_timer(dhdp, 0); +#if !defined(IGNORE_ETH0_DOWN) + /* Force flow control as protection when stop come before ifconfig_down */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); +#endif /* !defined(IGNORE_ETH0_DOWN) */ + /* Expect app to have torn down any connection before calling */ + /* Stop the bus, disable F2 */ + dhd_bus_stop(bus, FALSE); + +#if defined(OOB_INTR_ONLY) + /* Clean up any pending IRQ */ + dhd_enable_oob_intr(bus, FALSE); + bcmsdh_oob_intr_set(bus->sdh, FALSE); + bcmsdh_oob_intr_unregister(bus->sdh); +#endif + + /* Clean tx/rx buffer pointers, detach from the dongle */ + dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); + + bus->dhd->dongle_reset = TRUE; + bus->dhd->up = FALSE; + dhd_txglom_enable(dhdp, FALSE); + dhd_os_sdunlock(dhdp); + + DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); + /* App can now remove power from device */ + } else + bcmerror = BCME_SDIO_ERROR; + } else { + /* App must have restored power to device before calling */ + + DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) { + /* Turn on WLAN */ + dhd_os_sdlock(dhdp); + /* Reset SD client */ + bcmsdh_reset(bus->sdh); + + /* Attempt to re-attach & download */ + if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh, + (uint32 *)SI_ENUM_BASE, + bus->cl_devid)) { + /* Attempt to download binary to the dongle */ + if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) && + dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) { + + /* Re-init bus, enable F2 transfer */ + bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); + if (bcmerror == BCME_OK) { +#if defined(OOB_INTR_ONLY) + dhd_enable_oob_intr(bus, TRUE); + bcmsdh_oob_intr_register(bus->sdh, + dhdsdio_isr, bus); + bcmsdh_oob_intr_set(bus->sdh, TRUE); +#endif + + bus->dhd->dongle_reset = FALSE; + bus->dhd->up = TRUE; + +#if !defined(IGNORE_ETH0_DOWN) + /* Restore flow control */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); +#endif + dhd_os_wd_timer(dhdp, dhd_watchdog_ms); + + DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); + } else { + dhd_bus_stop(bus, FALSE); + dhdsdio_release_dongle(bus, bus->dhd->osh, + TRUE, FALSE); + } + } else + bcmerror = BCME_SDIO_ERROR; + } else + bcmerror = BCME_SDIO_ERROR; + + dhd_os_sdunlock(dhdp); + } else { + bcmerror = BCME_SDIO_ERROR; + DHD_INFO(("%s called when dongle is not in reset\n", + __FUNCTION__)); + DHD_INFO(("Will call dhd_bus_start instead\n")); + dhd_bus_resume(dhdp, 1); + if ((bcmerror = dhd_bus_start(dhdp)) != 0) + DHD_ERROR(("%s: dhd_bus_start fail with %d\n", + __FUNCTION__, bcmerror)); + } + } + return bcmerror; +} + +int dhd_bus_suspend(dhd_pub_t *dhdpub) +{ + return bcmsdh_stop(dhdpub->bus->sdh); +} + +int dhd_bus_resume(dhd_pub_t *dhdpub, int stage) +{ + return bcmsdh_start(dhdpub->bus->sdh, stage); +} + +/* Get Chip ID version */ +uint dhd_bus_chip_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + + return bus->sih->chip; +} + +/* Get Chip Rev ID version */ +uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + + return bus->sih->chiprev; +} + +/* Get Chip Pkg ID version */ +uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + + return bus->sih->chippkg; +} + +int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num) +{ + *bus_type = bus->bus; + *bus_num = bus->bus_num; + *slot_num = bus->slot_num; + return 0; +} + +int +dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) +{ + dhd_bus_t *bus; + + bus = dhdp->bus; + return dhdsdio_membytes(bus, set, address, data, size); +} + + +void +dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path) +{ + bus->fw_path = pfw_path; + bus->nv_path = pnv_path; +} + +int +dhd_enableOOB(dhd_pub_t *dhd, bool sleep) +{ + dhd_bus_t *bus = dhd->bus; + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + + if (sleep) { + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + /* Tell device to start using OOB wakeup */ + W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); + if (retries > retry_limit) { + DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); + return BCME_BUSY; + } + /* Turn off our contribution to the HT clock request */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } else { + /* Make sure the controller has the bus up */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Send misc interrupt to indicate OOB not needed */ + W_SDREG(0, ®s->tosbmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); + + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); + + /* Make sure we have SD bus access */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } + return BCME_OK; +} + +void +dhd_bus_pktq_flush(dhd_pub_t *dhdp) +{ + dhd_bus_t *bus = dhdp->bus; + bool wlfc_enabled = FALSE; + +#ifdef PROP_TXSTATUS + wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED); +#endif + if (!wlfc_enabled) { +#ifdef DHDTCPACK_SUPPRESS + /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, + * when there is a newly coming packet from network stack. + */ + dhd_tcpack_info_tbl_clean(bus->dhd); +#endif /* DHDTCPACK_SUPPRESS */ + /* Clear the data packet queues */ + pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0); + } +} + +int +dhd_sr_config(dhd_pub_t *dhd, bool on) +{ + dhd_bus_t *bus = dhd->bus; + + if (!bus->_srenab) + return -1; + + return dhdsdio_clk_devsleep_iovar(bus, on); +} + +uint16 +dhd_get_chipid(dhd_pub_t *dhd) +{ + dhd_bus_t *bus = dhd->bus; + + if (bus && bus->sih) + return (uint16)bus->sih->chip; + else + return 0; +} + +#ifdef DEBUGGER +uint32 dhd_sdio_reg_read(void *h, uint32 addr) +{ + uint32 rval; + struct dhd_bus *bus = (struct dhd_bus *) h; + + dhd_os_sdlock(bus->dhd); + + BUS_WAKE(bus); + + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + rval = bcmsdh_reg_read(bus->sdh, addr, 4); + + dhd_os_sdunlock(bus->dhd); + + return rval; +} + +void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val) +{ + struct dhd_bus *bus = (struct dhd_bus *) h; + + dhd_os_sdlock(bus->dhd); + + BUS_WAKE(bus); + + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + bcmsdh_reg_write(bus->sdh, addr, 4, val); + + dhd_os_sdunlock(bus->dhd); +} +#endif /* DEBUGGER */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.c new file mode 100644 index 000000000000..de106110b05d --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Author: Daisuke Niwa daisuke.x.niwa@sonymobile.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +/* miscTA items */ +typedef enum somc_nv_item { + SOMC_TA_TXPWR_2_4G = 0, + SOMC_TA_TXPWR_5G_LOW, + SOMC_TA_TXPWR_5G_MID, + SOMC_TA_TXPWR_5G_HIGH, + SOMC_TA_TXPWR_CO1_2_4G, + SOMC_TA_TXPWR_CO1_5G_LOW, + SOMC_TA_TXPWR_CO1_5G_MID, + SOMC_TA_TXPWR_CO1_5G_HIGH, +} somc_nv_item_t; + +/* Paths to miscTA import files */ +static const char *somc_ta_paths[] = { + "/data/etc/wlan_txpower_2_4g", + "/data/etc/wlan_txpower_5g_low", + "/data/etc/wlan_txpower_5g_mid", + "/data/etc/wlan_txpower_5g_high", + "/data/etc/wlan_txpower_co1_2_4g", + "/data/etc/wlan_txpower_co1_5g_low", + "/data/etc/wlan_txpower_co1_5g_mid", + "/data/etc/wlan_txpower_co1_5g_high", +}; + +#define SOMC_NV_IS_5G(i) (i % 4 == 0 ? 0 : 1) +#define SOMC_NV_GET_CHAIN(i) (i < SOMC_TA_TXPWR_CO1_2_4G ? 0 : 1) + +#define SOMC_MAX_TABUF_SIZE 128 +#define SOMC_TXPWR_BUF_SIZE 7 + +/* Keys used in calibration file for tx power */ +#define SOMC_CKEY_TXPWR_2_4G_11B "cckbw202gpo" +#define SOMC_CKEY_TXPWR_2_4G_11A "dot11agofdmhrbw202gpo" +#define SOMC_CKEY_TXPWR_2_4G_11A_2 "ofdmlrbw202gpo" +#define SOMC_CKEY_TXPWR_2_4G_11N "mcsbw202gpo" +#define SOMC_CKEY_TXPWR_5G_LOW_11A "mcsbw205glpo" +#define SOMC_CKEY_TXPWR_5G_LOW_11N "mcsbw405glpo" +#define SOMC_CKEY_TXPWR_5G_LOW_11AC "mcsbw805glpo" +#define SOMC_CKEY_TXPWR_5G_MID_11A "mcsbw205gmpo" +#define SOMC_CKEY_TXPWR_5G_MID_11N "mcsbw405gmpo" +#define SOMC_CKEY_TXPWR_5G_MID_11AC "mcsbw805gmpo" +#define SOMC_CKEY_TXPWR_5G_HIGH_11A "mcsbw205ghpo" +#define SOMC_CKEY_TXPWR_5G_HIGH_11N "mcsbw405ghpo" +#define SOMC_CKEY_TXPWR_5G_HIGH_11AC "mcsbw805ghpo" + +#define SOMC_TXPWR_MAX 127 +#define SOMC_TXPWR_5G 0x20 + +typedef struct { + char *key; /* Key for tx power (see the definitions above) */ + int len; /* Length of a unit of PPR (not incl. "0x") */ + int offset; /* Offset to PPR */ +} somc_ppr_item_t; + +/* List of ppr item handled by somc_txpower_calibrate() */ +static const somc_ppr_item_t somc_ppr_items[] = { + { SOMC_CKEY_TXPWR_2_4G_11B, 4, 0}, + { SOMC_CKEY_TXPWR_2_4G_11A, 4, 0}, + { SOMC_CKEY_TXPWR_2_4G_11A_2, 4, 2}, + { SOMC_CKEY_TXPWR_2_4G_11N, 8, 0}, + { SOMC_CKEY_TXPWR_5G_LOW_11A, 8, 0}, + { SOMC_CKEY_TXPWR_5G_LOW_11N, 8, 0}, + { SOMC_CKEY_TXPWR_5G_LOW_11AC, 8, 0}, + { SOMC_CKEY_TXPWR_5G_MID_11A, 8, 0}, + { SOMC_CKEY_TXPWR_5G_MID_11N, 8, 0}, + { SOMC_CKEY_TXPWR_5G_MID_11AC, 8, 0}, + { SOMC_CKEY_TXPWR_5G_HIGH_11A, 8, 0}, + { SOMC_CKEY_TXPWR_5G_HIGH_11N, 8, 0}, + { SOMC_CKEY_TXPWR_5G_HIGH_11AC, 8, 0}, +}; + +/* {2.4GHz: {chain0, chain1}, 5GHz: {chain0, chain1}} */ +static int somc_txpower_min_deltas[2][2] = {{0, 0},{0, 0}}; + +static int +somc_txpower_get_min_delta(int band5g, int chain) +{ + int min_delta = somc_txpower_min_deltas[band5g][chain]; + return (min_delta == INT_MAX) ? 0 : min_delta; +} + +static void +somc_txpower_update_min_delta(const int *delta, int num, int band5g, int chain) +{ + int *min_delta = &somc_txpower_min_deltas[band5g][chain]; + while (num > 0) { + num--; + if (band5g && (num == 0)) /* ignore 11b delta value for 5GHz */ + continue; + if (!band5g && (num > 2)) /* ignore 11n-40/11ac delta values for 2.4GHz */ + continue; + *min_delta = MIN(*min_delta, delta[num]); + } +} + +static int +somc_read_file(const char *path, unsigned char *buf, int buf_len) +{ + int ret = -1; + int len; + struct file *fp = NULL; + + if (!path || !buf) + goto err; + + fp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(fp)) { + DHD_ERROR(("%s: file open error: %s\n", __FUNCTION__, path)); + if (PTR_ERR(fp) == -ENOENT) { + DHD_ERROR(("%s: file does not exist: %s\n", __FUNCTION__, path)); + ret = -2; + } + fp = NULL; + goto err; + } + + len = dhd_os_get_image_block(buf, buf_len, (void *)fp); + if (len <= 0 || buf_len <= len) { + DHD_ERROR(("%s: file read error: %s\n", __FUNCTION__, path)); + goto err; + } + buf[len] = '\0'; + + ret = 0; +err: + if (fp) + filp_close(fp, NULL); + return ret; +} + +static int +somc_read_ta(somc_nv_item_t item, unsigned char *buf, int buf_len) +{ + char ta_buf[SOMC_MAX_TABUF_SIZE] = {0}; + int *d, ret; + + ret = somc_read_file(somc_ta_paths[item], ta_buf, sizeof(ta_buf)); + if (ret != 0) + return ret; + + switch (item) { + case SOMC_TA_TXPWR_2_4G: + case SOMC_TA_TXPWR_5G_LOW: + case SOMC_TA_TXPWR_5G_MID: + case SOMC_TA_TXPWR_5G_HIGH: + case SOMC_TA_TXPWR_CO1_2_4G: + case SOMC_TA_TXPWR_CO1_5G_LOW: + case SOMC_TA_TXPWR_CO1_5G_MID: + case SOMC_TA_TXPWR_CO1_5G_HIGH: + if (buf_len < SOMC_TXPWR_BUF_SIZE) + return -1; + d = (int *)buf; + if (sscanf(ta_buf, "%d:%d:%d:%d:%d:%d:%d", + &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6]) != 7) { + DHD_ERROR(("%s: tx power parse error: %s\n", + __FUNCTION__, somc_ta_paths[item])); + return -1; + } + + printk("%s: tx power in miscTA(%s),\n 11b:11a:11n(20MHz):11n(40MHz):" + "11ac(20MHz):11ac(40MHz):11ac(80MHz)=,\n %d:%d:%d:%d:%d:%d:%d\n", + __FUNCTION__, somc_ta_paths[item], + d[0], d[1], d[2], d[3], d[4], d[5], d[6]); + break; + default: + return -1; + } + + return 0; +} + +static int +somc_txpower_apply_delta(const unsigned char *key, int len, int offset, + int delta, unsigned char *nvram, int nvram_len) +{ + unsigned char *end = nvram + nvram_len - 1; + unsigned char *k, *v, *t; + unsigned int power_h, power_l; + int i, j, v_len = len * 2 + 5; /* e.g. "0x5555,0x1111" (= 4 * 2 + 5) */ + const unsigned char *fmt; + + if (!key || !nvram || offset >= len || (len != 4 && len != 8)) + return -1; + + fmt = (len == 4) ? "0x%04x,0x%04x" : "0x%08x,0x%08x"; + + /* look up key in nvram */ + if ((k = strnstr(nvram, key, nvram_len)) == NULL) { + DHD_ERROR(("%s: key not found: %s\n", __FUNCTION__, key)); + return -1; + } + + /* extract value */ + v = k + strlen(key); + if (v > end || *v != '=') { + DHD_ERROR(("%s: value parse error: %s\n", __FUNCTION__, key)); + return -1; + } + v += 1; + + if (v > end || (t = strnchr(v, end - v + 1, '\n')) == NULL || + t - v != v_len) { + DHD_ERROR(("%s: value parse error: %s\n", __FUNCTION__, key)); + return -1; + } + + /* extract each values */ + if (sscanf(v, fmt, &power_l, &power_h) != 2) { + DHD_ERROR(("%s: power offset values parse error: %s\n", __FUNCTION__, key)); + return -1; + } + + /* convert unit since nvram uses 1/2dB step, miscTA uses 1/100dB step */ + if (delta < 0 && delta % 50 != 0) + delta = delta / 50 - 1; + else + delta = delta / 50; + + for (i = 0, j = len - offset; i < j; i++) { + int val, sft = i * 4; + /* combine low and high 4 bits into a value(8bit) */ + val = ((power_l >> sft) & 0xf) | (((power_h >> sft) & 0xf) << 4); + /* apply delta */ + val -= delta; + val = (val > 0xff) ? 0xff : (val < 0x00) ? 0x00 : val; + /* separate power to low and high again */ + power_l &= ~(0xf << sft); + power_l |= (val & 0x0f) << sft; + power_h &= ~(0xf << sft); + power_h |= ((val & 0xf0) >> 4) << sft; + } + + snprintf(v, v_len + 1, fmt, power_l, power_h); + v[v_len] = '\n'; + + return 0; +} + +int somc_txpower_calibrate(char *nvram, int nvram_len) +{ + int v[4][SOMC_TXPWR_BUF_SIZE]; /* tx power offset(s) */ + int i, j, ta_num, delta[sizeof(somc_ppr_items) / sizeof(somc_ppr_items[0])]; + +#ifdef SOMC_MIMO + ta_num = SOMC_TA_TXPWR_CO1_5G_HIGH + 1; +#else + ta_num = SOMC_TA_TXPWR_5G_HIGH + 1; +#endif + /* initialize minimum delta (used for tx power trim) */ + for (i = 0; i < 4; i++) { + for (j = 0; j < SOMC_TXPWR_BUF_SIZE; j++) { + v[i][j] = INT_MAX; + } + } + + /* initialize minimum delta (used for tx power back-off) */ + somc_txpower_min_deltas[0][0 /* chain0 */] = INT_MAX; + somc_txpower_min_deltas[1][0 /* chain0 */] = INT_MAX; + somc_txpower_min_deltas[0][1 /* chain1 */] = INT_MAX; + somc_txpower_min_deltas[1][1 /* chain1 */] = INT_MAX; + + for (i = 0; i < ta_num; i++) { + int ret; + int tv[SOMC_TXPWR_BUF_SIZE] = {0}; + + /* no need to update delta if miscTA doesn't exist(ret == 2) */ + ret = somc_read_ta(i, (char *)tv, sizeof(tv)); + if (ret == 0) { + somc_txpower_update_min_delta(tv, SOMC_TXPWR_BUF_SIZE, + SOMC_NV_IS_5G(i), SOMC_NV_GET_CHAIN(i)); + /* select minimum delta between chain0 and chain1 */ + for (j = 0; j < SOMC_TXPWR_BUF_SIZE; j++) + v[i % 4][j] = MIN(v[i % 4][j], tv[j]); + } else if (ret != -2) + return BCME_OK; + } + + /* construct delta data structure for 2.4GHz + * TA value "v[0]" consists of the following format. + * {11b}:{11a}:{11n-20} + */ + delta[0] = v[0][0]; /* {11b} */ + delta[1] = v[0][1]; /* {11a} */ + delta[2] = v[0][1]; /* {11a} */ + delta[3] = v[0][2]; /* {11n-20} */ + + /* construct delta data structure for 5GHz(low/mid/high) + * TA values "v[1],v[2],v[3]" consist of the following format. + * {11b}:{11a}:{11n-20}:{11n-40}:{11ac-20}:{11ac-40}:{11ac-80} + */ + for (i = 1; i < 4; i++) { + /* minimum delta between {11a}, {11n-20}, {11ac-20} for 20MHz */ + delta[i * 3 + 1] = MIN(MIN(v[i][1], v[i][2]), v[i][4]); + /* minimum delta between {11n-40}, {11ac-40} for 40MHz */ + delta[i * 3 + 2] = MIN(v[i][3], v[i][5]); + /* {11ac-80} for 80MHz */ + delta[i * 3 + 3] = v[i][6]; + } + + /* Apply delta (tx power trim) */ + for (i = 0; i < sizeof(somc_ppr_items) / sizeof(somc_ppr_items[0]); i++) { + if (delta[i] == INT_MAX) + continue; + if (somc_txpower_apply_delta(somc_ppr_items[i].key, somc_ppr_items[i].len, + somc_ppr_items[i].offset, delta[i], nvram, nvram_len) != 0) + return BCME_ERROR; + } + + return BCME_OK; +} + +int somc_update_qtxpower(char *buf, char band, int chain) +{ + int in_qdbm, power; + int delta = somc_txpower_get_min_delta((band & SOMC_TXPWR_5G) != 0, chain); + + in_qdbm = *buf; + + if (in_qdbm < 0 || SOMC_TXPWR_MAX < in_qdbm) + return -1; + + /* convert unit for calculation since 'delta' uses 1/100dB step */ + power = in_qdbm + delta / (100 / 4); + if (power > 0) { + power = (power > SOMC_TXPWR_MAX) ? SOMC_TXPWR_MAX : power; + } else { + power = 0; + } + *buf = (char)power; + + printk("%s: Set max tx power: %d qdBm (delta=%d)\n", + __FUNCTION__, power, delta); + + return 0; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.h new file mode 100644 index 000000000000..4c83517241a2 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * Author: Daisuke Niwa daisuke.x.niwa@sonymobile.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#ifndef __DHD_SOMC_CUSTOM_H__ +#define __DHD_SOMC_CUSTOM_H__ + +extern int somc_txpower_calibrate(char *nvram, int nvram_len); +extern int somc_update_qtxpower(char *buf, char band, int chain); + +#endif /* __DHD_SOMC_CUSTOM_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c new file mode 100644 index 000000000000..52700ac94ff9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c @@ -0,0 +1,4046 @@ +/* + * DHD PROP_TXSTATUS Module. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_wlfc.c 701450 2017-05-25 02:10:23Z $ + * + */ + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#ifdef PROP_TXSTATUS +#include +#include +#endif +#ifdef DHDTCPACK_SUPPRESS +#include +#endif /* DHDTCPACK_SUPPRESS */ + + +/* + * wlfc naming and lock rules: + * + * 1. Private functions name like _dhd_wlfc_XXX, declared as static and avoid wlfc lock operation. + * 2. Public functions name like dhd_wlfc_XXX, use wlfc lock if needed. + * 3. Non-Proptxstatus module call public functions only and avoid wlfc lock operation. + * + */ + + +#ifdef PROP_TXSTATUS + +#define DHD_WLFC_QMON_COMPLETE(entry) + +#define LIMIT_BORROW + + +static uint16 +_dhd_wlfc_adjusted_seq(void* p, uint8 current_seq) +{ + uint16 seq; + + if (!p) { + return 0xffff; + } + + seq = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + if (seq < current_seq) { + /* wrap around */ + seq += 256; + } + + return seq; +} + +static void +_dhd_wlfc_prec_enque(struct pktq *pq, int prec, void* p, bool qHead, + uint8 current_seq, bool reOrder) +{ + struct pktq_prec *q; + uint16 seq, seq2; + void *p2, *p2_prev; + + if (!p) + return; + + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + PKTSETLINK(p, NULL); + if (q->head == NULL) { + /* empty queue */ + q->head = p; + q->tail = p; + } else { + if (reOrder && (prec & 1)) { + seq = _dhd_wlfc_adjusted_seq(p, current_seq); + p2 = qHead ? q->head : q->tail; + seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); + + if ((qHead &&((seq+1) > seq2)) || (!qHead && ((seq2+1) > seq))) { + /* need reorder */ + p2 = q->head; + p2_prev = NULL; + seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); + + while (seq > seq2) { + p2_prev = p2; + p2 = PKTLINK(p2); + if (!p2) { + break; + } + seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); + } + + if (p2_prev == NULL) { + /* insert head */ + PKTSETLINK(p, q->head); + q->head = p; + } else if (p2 == NULL) { + /* insert tail */ + PKTSETLINK(p2_prev, p); + q->tail = p; + } else { + /* insert after p2_prev */ + PKTSETLINK(p, PKTLINK(p2_prev)); + PKTSETLINK(p2_prev, p); + } + goto exit; + } + } + + if (qHead) { + PKTSETLINK(p, q->head); + q->head = p; + } else { + PKTSETLINK(q->tail, p); + q->tail = p; + } + } + +exit: + + q->len++; + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; +} + +/* Create a place to store all packet pointers submitted to the firmware until + a status comes back, suppress or otherwise. + + hang-er: noun, a contrivance on which things are hung, as a hook. +*/ +static void* +_dhd_wlfc_hanger_create(dhd_pub_t *dhd, int max_items) +{ + int i; + wlfc_hanger_t* hanger; + + /* allow only up to a specific size for now */ + ASSERT(max_items == WLFC_HANGER_MAXITEMS); + + if ((hanger = (wlfc_hanger_t*)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_DHD_WLFC_HANGER, + WLFC_HANGER_SIZE(max_items))) == NULL) { + return NULL; + } + memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); + hanger->max_items = max_items; + + for (i = 0; i < hanger->max_items; i++) { + hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } + return hanger; +} + +static int +_dhd_wlfc_hanger_delete(dhd_pub_t *dhd, void* hanger) +{ + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h) { + DHD_OS_PREFREE(dhd, h, WLFC_HANGER_SIZE(h->max_items)); + return BCME_OK; + } + return BCME_BADARG; +} + +static uint16 +_dhd_wlfc_hanger_get_free_slot(void* hanger) +{ + uint32 i; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h) { + i = h->slot_pos + 1; + if (i == h->max_items) { + i = 0; + } + while (i != h->slot_pos) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { + h->slot_pos = i; + return (uint16)i; + } + i++; + if (i == h->max_items) + i = 0; + } + h->failed_slotfind++; + } + return WLFC_HANGER_MAXITEMS; +} + +static int +_dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + *gen = 0xff; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + + if (h) { + if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || + (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { + *gen = h->items[slot_id].gen; + } + else { + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +_dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { + if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { + h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; + h->items[slot_id].pkt = pkt; + h->pushed++; + } + else { + h->failed_to_push++; + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +_dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + + if (h) { + if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { + *pktout = h->items[slot_id].pkt; + if (remove_from_hanger) { + h->items[slot_id].state = + WLFC_HANGER_ITEM_STATE_FREE; + h->items[slot_id].pkt = NULL; + h->items[slot_id].gen = 0xff; + h->items[slot_id].identifier = 0; + h->popped++; + } + } + else { + h->failed_to_pop++; + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +_dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + if (h) { + h->items[slot_id].gen = gen; + if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { + h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; + } + else + rc = BCME_BADARG; + } + else + rc = BCME_BADARG; + + return rc; +} + +static void +_dhd_wlfc_hanger_waitevent_set(void* hanger, uint32 hslot, uint8 waitevent) +{ + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + ASSERT(h && (hslot < (uint32) h->max_items)); + + h->items[hslot].waitevent = waitevent; +} + +static uint8 +_dhd_wlfc_hanger_waitevent_decreturn(void* hanger, uint32 hslot) +{ + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + ASSERT(h && (hslot < (uint32) h->max_items)); + + h->items[hslot].waitevent--; + return h->items[hslot].waitevent; +} + +/* return true if the slot is only waiting for clean */ +static bool +_dhd_wlfc_hanger_wait_clean(void* hanger, uint32 hslot) +{ + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if ((hslot < (uint32) h->max_items) && + (h->items[hslot].state == WLFC_HANGER_ITEM_STATE_WAIT_CLEAN)) { + /* the packet should be already freed by _dhd_wlfc_cleanup */ + h->items[hslot].state = WLFC_HANGER_ITEM_STATE_FREE; + h->items[hslot].pkt = NULL; + h->items[hslot].gen = 0xff; + h->items[hslot].identifier = 0; + return TRUE; + } + + return FALSE; +} + +/* remove reference of specific packet in hanger */ +static bool +_dhd_wlfc_hanger_remove_reference(wlfc_hanger_t* h, void* pkt) +{ + int i; + + if (!h || !pkt) { + return FALSE; + } + + for (i = 0; i < h->max_items; i++) { + if (pkt == h->items[i].pkt) { + if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) || + (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + h->items[i].pkt = NULL; + h->items[i].gen = 0xff; + h->items[i].identifier = 0; + } + return TRUE; + } + } + + return FALSE; +} + + +static int +_dhd_wlfc_enque_afq(athost_wl_status_info_t* ctx, void *p) +{ + wlfc_mac_descriptor_t* entry; + uint16 entry_idx = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + uint8 prec = DHD_PKTTAG_FIFO(PKTTAG(p)); + + if (entry_idx < WLFC_MAC_DESC_TABLE_SIZE) + entry = &ctx->destination_entries.nodes[entry_idx]; + else if (entry_idx < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) + entry = &ctx->destination_entries.interfaces[entry_idx - WLFC_MAC_DESC_TABLE_SIZE]; + else + entry = &ctx->destination_entries.other; + + pktq_penq(&entry->afq, prec, p); + + return BCME_OK; +} + +static int +_dhd_wlfc_deque_afq(athost_wl_status_info_t* ctx, uint16 hslot, uint8 hcnt, uint8 prec, + void **pktout) +{ + wlfc_mac_descriptor_t *entry; + struct pktq *pq; + struct pktq_prec *q; + void *p, *b; + + if (!ctx) { + DHD_ERROR(("%s: ctx(%p), pktout(%p)\n", __FUNCTION__, ctx, pktout)); + return BCME_BADARG; + } + + if (pktout) { + *pktout = NULL; + } + + ASSERT(hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM + 1)); + + if (hslot < WLFC_MAC_DESC_TABLE_SIZE) + entry = &ctx->destination_entries.nodes[hslot]; + else if (hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) + entry = &ctx->destination_entries.interfaces[hslot - WLFC_MAC_DESC_TABLE_SIZE]; + else + entry = &ctx->destination_entries.other; + + pq = &entry->afq; + + ASSERT(prec < pq->num_prec); + + q = &pq->q[prec]; + + b = NULL; + p = q->head; + + while (p && (hcnt != WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))))) + { + b = p; + p = PKTLINK(p); + } + + if (p == NULL) { + /* none is matched */ + if (b) { + DHD_ERROR(("%s: can't find matching seq(%d)\n", __FUNCTION__, hcnt)); + } else { + DHD_ERROR(("%s: queue is empty\n", __FUNCTION__)); + } + + return BCME_ERROR; + } + + if (!b) { + /* head packet is matched */ + if ((q->head = PKTLINK(p)) == NULL) { + q->tail = NULL; + } + } else { + /* middle packet is matched */ + DHD_INFO(("%s: out of order, seq(%d), head_seq(%d)\n", __FUNCTION__, hcnt, + WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(q->head))))); + ctx->stats.ooo_pkts[prec]++; + PKTSETLINK(b, PKTLINK(p)); + if (PKTLINK(p) == NULL) { + q->tail = b; + } + } + + q->len--; + pq->len--; + + PKTSETLINK(p, NULL); + + if (pktout) { + *pktout = p; + } + + return BCME_OK; +} + +static int +_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, + uint8 tim_bmp, uint8 mac_handle, uint32 htodtag, uint16 htodseq, bool skip_wlfc_hdr) +{ + uint32 wl_pktinfo = 0; + uint8* wlh; + uint8 dataOffset = 0; + uint8 fillers; + uint8 tim_signal_len = 0; + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + + struct bdc_header *h; + + if (skip_wlfc_hdr) + goto push_bdc_hdr; + + if (tim_signal) { + tim_signal_len = TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; + } + + /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ + dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + TLV_HDR_LEN + tim_signal_len; + if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { + dataOffset += WLFC_CTL_VALUE_LEN_SEQ; + } + + fillers = ROUNDUP(dataOffset, 4) - dataOffset; + dataOffset += fillers; + + PKTPUSH(ctx->osh, p, dataOffset); + wlh = (uint8*) PKTDATA(ctx->osh, p); + + wl_pktinfo = htol32(htodtag); + + wlh[TLV_TAG_OFF] = WLFC_CTL_TYPE_PKTTAG; + wlh[TLV_LEN_OFF] = WLFC_CTL_VALUE_LEN_PKTTAG; + memcpy(&wlh[TLV_HDR_LEN], &wl_pktinfo, sizeof(uint32)); + + if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { + uint16 wl_seqinfo = htol16(htodseq); + wlh[TLV_LEN_OFF] += WLFC_CTL_VALUE_LEN_SEQ; + memcpy(&wlh[TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PKTTAG], &wl_seqinfo, + WLFC_CTL_VALUE_LEN_SEQ); + } + + if (tim_signal_len) { + wlh[dataOffset - fillers - tim_signal_len ] = + WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; + wlh[dataOffset - fillers - tim_signal_len + 1] = + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; + wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; + wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; + } + if (fillers) + memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); + +push_bdc_hdr: + + PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); + h = (struct bdc_header *)PKTDATA(ctx->osh, p); + h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); + if (PKTSUMNEEDED(p)) + h->flags |= BDC_FLAG_SUM_NEEDED; + + + h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); + h->flags2 = 0; + h->dataOffset = dataOffset >> 2; + BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); + return BCME_OK; +} + +static int +_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) +{ + struct bdc_header *h; + + if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { + DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); + return BCME_ERROR; + } + h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); + + /* pull BDC header */ + PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); + + if (PKTLEN(ctx->osh, pktbuf) < (uint)(h->dataOffset << 2)) { + DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); + return BCME_ERROR; + } + + /* pull wl-header */ + PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); + return BCME_OK; +} + +static wlfc_mac_descriptor_t* +_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) +{ + int i; + wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; + uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); + uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); + wlfc_mac_descriptor_t* entry = DHD_PKTTAG_ENTRY(PKTTAG(p)); + int iftype = ctx->destination_entries.interfaces[ifid].iftype; + + /* saved one exists, return it */ + if (entry) + return entry; + + /* Multicast destination, STA and P2P clients get the interface entry. + * STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations + * have their own entry. + */ + if ((iftype == WLC_E_IF_ROLE_STA || ETHER_ISMULTI(dstn) || + iftype == WLC_E_IF_ROLE_P2P_CLIENT) && + (ctx->destination_entries.interfaces[ifid].occupied)) { + entry = &ctx->destination_entries.interfaces[ifid]; + } + + if (entry && ETHER_ISMULTI(dstn)) { + DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); + return entry; + } + + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (table[i].occupied) { + if (table[i].interface_id == ifid) { + if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) { + entry = &table[i]; + break; + } + } + } + } + + if (entry == NULL) + entry = &ctx->destination_entries.other; + + DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); + + return entry; +} + +static int +_dhd_wlfc_prec_drop(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ) +{ + athost_wl_status_info_t* ctx; + void *pout = NULL; + + ASSERT(dhdp && p); + ASSERT(prec >= 0 && prec <= WLFC_PSQ_PREC_COUNT); + + ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; + + if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { + /* suppressed queue, need pop from hanger */ + _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG + (PKTTAG(p))), &pout, 1); + ASSERT(p == pout); + } + + if (!(prec & 1)) { +#ifdef DHDTCPACK_SUPPRESS + /* pkt in delayed q, so fake push BDC header for + * dhd_tcpack_check_xmit() and dhd_txcomplete(). + */ + _dhd_wlfc_pushheader(ctx, p, FALSE, 0, 0, 0, 0, TRUE); + + /* This packet is about to be freed, so remove it from tcp_ack_info_tbl + * This must be one of... + * 1. A pkt already in delayQ is evicted by another pkt with higher precedence + * in _dhd_wlfc_prec_enq_with_drop() + * 2. A pkt could not be enqueued to delayQ because it is full, + * in _dhd_wlfc_enque_delayq(). + * 3. A pkt could not be enqueued to delayQ because it is full, + * in _dhd_wlfc_rollback_packet_toq(). + */ + if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" + " Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + } + + if (bPktInQ) { + ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; + ctx->pkt_cnt_per_ac[prec>>1]--; + } + + dhd_txcomplete(dhdp, p, FALSE); + PKTFREE(ctx->osh, p, TRUE); + ctx->stats.pktout++; + ctx->stats.drop_pkts[prec]++; + + return 0; +} + +static bool +_dhd_wlfc_prec_enq_with_drop(dhd_pub_t *dhdp, struct pktq *pq, void *pkt, int prec, bool qHead, + uint8 current_seq) +{ + void *p = NULL; + int eprec = -1; /* precedence to evict from */ + athost_wl_status_info_t* ctx; + + ASSERT(dhdp && pq && pkt); + ASSERT(prec >= 0 && prec < pq->num_prec); + + ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; + + /* Fast case, precedence queue is not full and we are also not + * exceeding total queue length + */ + if (!pktq_pfull(pq, prec) && !pktq_full(pq)) { + goto exit; + } + + /* Determine precedence from which to evict packet, if any */ + if (pktq_pfull(pq, prec)) + eprec = prec; + else if (pktq_full(pq)) { + p = pktq_peek_tail(pq, &eprec); + if (!p) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return FALSE; + } + if ((eprec > prec) || (eprec < 0)) { + if (!pktq_pempty(pq, prec)) { + eprec = prec; + } else { + return FALSE; + } + } + } + + /* Evict if needed */ + if (eprec >= 0) { + /* Detect queueing to unconfigured precedence */ + ASSERT(!pktq_pempty(pq, eprec)); + /* Evict all fragmented frames */ + dhd_prec_drop_pkts(dhdp, pq, eprec, _dhd_wlfc_prec_drop); + } + +exit: + /* Enqueue */ + _dhd_wlfc_prec_enque(pq, prec, pkt, qHead, current_seq, + WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)); + ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(pkt))][prec>>1]++; + ctx->pkt_cnt_per_ac[prec>>1]++; + + return TRUE; +} + + +static int +_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, + void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) +{ + /* + put the packet back to the head of queue + + - suppressed packet goes back to suppress sub-queue + - pull out the header, if new or delayed packet + + Note: hslot is used only when header removal is done. + */ + wlfc_mac_descriptor_t* entry; + int rc = BCME_OK; + int prec, fifo_id; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + prec = DHD_PKTTAG_FIFO(PKTTAG(p)); + fifo_id = prec << 1; + if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) + fifo_id += 1; + if (entry != NULL) { + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the firmware (for pspoll etc.) + */ + if ((prec != AC_COUNT) && !DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) + entry->requested_credit++; + + if (pkt_type == eWLFC_PKTTYPE_DELAYED) { + /* decrement sequence count */ + WLFC_DECR_SEQCOUNT(entry, prec); + /* remove header first */ + rc = _dhd_wlfc_pullheader(ctx, p); + if (rc != BCME_OK) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + goto exit; + } + } + + if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, fifo_id, TRUE, + WLFC_SEQCOUNT(entry, fifo_id>>1)) + == FALSE) { + /* enque failed */ + DHD_ERROR(("Error: %s():%d, fifo_id(%d)\n", + __FUNCTION__, __LINE__, fifo_id)); + rc = BCME_ERROR; + } + } else { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + rc = BCME_ERROR; + } +exit: + if (rc != BCME_OK) { + ctx->stats.rollback_failed++; + _dhd_wlfc_prec_drop(ctx->dhdp, fifo_id, p, FALSE); + } + else + ctx->stats.rollback++; + + return rc; +} + +static bool +_dhd_wlfc_allow_fc(athost_wl_status_info_t* ctx, uint8 ifid) +{ + int prec, ac_traffic = WLFC_NO_TRAFFIC; + + for (prec = 0; prec < AC_COUNT; prec++) { + if (ctx->pkt_cnt_in_q[ifid][prec] > 0) { + if (ac_traffic == WLFC_NO_TRAFFIC) + ac_traffic = prec + 1; + else if (ac_traffic != (prec + 1)) + ac_traffic = WLFC_MULTI_TRAFFIC; + } + } + + if (ac_traffic >= 1 && ac_traffic <= AC_COUNT) { + /* single AC (BE/BK/VI/VO) in queue */ + if (ctx->allow_fc) { + return TRUE; + } else { + uint32 delta; + uint32 curr_t = OSL_SYSUPTIME(); + + if (ctx->fc_defer_timestamp == 0) { + /* first signle ac scenario */ + ctx->fc_defer_timestamp = curr_t; + return FALSE; + } + + /* single AC duration, this handles wrap around, e.g. 1 - ~0 = 2. */ + delta = curr_t - ctx->fc_defer_timestamp; + if (delta >= WLFC_FC_DEFER_PERIOD_MS) { + ctx->allow_fc = TRUE; + } + } + } else { + /* multiple ACs or BCMC in queue */ + ctx->allow_fc = FALSE; + ctx->fc_defer_timestamp = 0; + } + + return ctx->allow_fc; +} + +static void +_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) +{ + dhd_pub_t *dhdp; + + ASSERT(ctx); + + dhdp = (dhd_pub_t *)ctx->dhdp; + ASSERT(dhdp); + + if (dhdp->skip_fc && dhdp->skip_fc()) + return; + + if ((ctx->hostif_flow_state[if_id] == OFF) && !_dhd_wlfc_allow_fc(ctx, if_id)) + return; + + if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { + /* start traffic */ + ctx->hostif_flow_state[if_id] = OFF; + /* + WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", + pq->len, if_id, __FUNCTION__)); + */ + WLFC_DBGMESG(("F")); + + dhd_txflowcontrol(dhdp, if_id, OFF); + + ctx->toggle_host_if = 0; + } + + if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { + /* stop traffic */ + ctx->hostif_flow_state[if_id] = ON; + /* + WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", + pq->len, if_id, __FUNCTION__)); + */ + WLFC_DBGMESG(("N")); + + dhd_txflowcontrol(dhdp, if_id, ON); + + ctx->host_ifidx = if_id; + ctx->toggle_host_if = 1; + } + + return; +} + +static int +_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + uint8 ta_bmp) +{ + int rc = BCME_OK; + void* p = NULL; + int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 16; + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + + if (dhdp->proptxstatus_txoff) { + rc = BCME_NORESOURCE; + return rc; + } + + /* allocate a dummy packet */ + p = PKTGET(ctx->osh, dummylen, TRUE); + if (p) { + PKTPULL(ctx->osh, p, dummylen); + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); + _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0, 0, FALSE); + DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); + DHD_PKTTAG_WLFCPKT_SET(PKTTAG(p), 1); +#ifdef PROP_TXSTATUS_DEBUG + ctx->stats.signal_only_pkts_sent++; +#endif + +#if defined(BCMPCIE) + rc = dhd_bus_txdata(dhdp->bus, p, ctx->host_ifidx); +#else + rc = dhd_bus_txdata(dhdp->bus, p); +#endif + if (rc != BCME_OK) { + _dhd_wlfc_pullheader(ctx, p); + PKTFREE(ctx->osh, p, TRUE); + } + } + else { + DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", + __FUNCTION__, dummylen)); + rc = BCME_NOMEM; + } + return rc; +} + +/* Return TRUE if traffic availability changed */ +static bool +_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + int prec) +{ + bool rc = FALSE; + + if (entry->state == WLFC_STATE_CLOSE) { + if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && + (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { + + if (entry->traffic_pending_bmp & NBITVAL(prec)) { + rc = TRUE; + entry->traffic_pending_bmp = + entry->traffic_pending_bmp & ~ NBITVAL(prec); + } + } + else { + if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { + rc = TRUE; + entry->traffic_pending_bmp = + entry->traffic_pending_bmp | NBITVAL(prec); + } + } + } + if (rc) { + /* request a TIM update to firmware at the next piggyback opportunity */ + if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { + entry->send_tim_signal = 1; + _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); + entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; + entry->send_tim_signal = 0; + } + else { + rc = FALSE; + } + } + return rc; +} + +static int +_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) +{ + wlfc_mac_descriptor_t* entry; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + if (entry == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_NOTFOUND; + } + /* + - suppressed packets go to sub_queue[2*prec + 1] AND + - delayed packets go to sub_queue[2*prec + 0] to ensure + order of delivery. + */ + if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, ((prec << 1) + 1), FALSE, + WLFC_SEQCOUNT(entry, prec)) + == FALSE) { + ctx->stats.delayq_full_error++; + /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ + WLFC_DBGMESG(("s")); + return BCME_ERROR; + } + + /* A packet has been pushed, update traffic availability bitmap, if applicable */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); + return BCME_OK; +} + +static int +_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, + wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) +{ + int rc = BCME_OK; + int hslot = WLFC_HANGER_MAXITEMS; + bool send_tim_update = FALSE; + uint32 htod = 0; + uint16 htodseq = 0; + uint8 free_ctr; + int gen = 0xff; + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + + *slot = hslot; + + if (entry == NULL) { + entry = _dhd_wlfc_find_table_entry(ctx, p); + } + + if (entry == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_ERROR; + } + + if (entry->send_tim_signal) { + send_tim_update = TRUE; + entry->send_tim_signal = 0; + entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; + } + + if (header_needed) { + if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { + hslot = (uint)(entry - &ctx->destination_entries.nodes[0]); + } else { + hslot = _dhd_wlfc_hanger_get_free_slot(ctx->hanger); + } + gen = entry->generation; + free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); + } else { + if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { + htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(p)); + } + + hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + + if (WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)) { + gen = entry->generation; + } else if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { + gen = WL_TXSTATUS_GET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + } else { + _dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); + } + + free_ctr = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + /* remove old header */ + _dhd_wlfc_pullheader(ctx, p); + } + + if (hslot >= WLFC_HANGER_MAXITEMS) { + DHD_ERROR(("Error: %s():no hanger slot available\n", __FUNCTION__)); + return BCME_ERROR; + } + + WL_TXSTATUS_SET_FREERUNCTR(htod, free_ctr); + WL_TXSTATUS_SET_HSLOT(htod, hslot); + WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); + WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); + WL_TXSTATUS_SET_GENERATION(htod, gen); + DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); + + if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { + /* + Indicate that this packet is being sent in response to an + explicit request from the firmware side. + */ + WLFC_PKTFLAG_SET_PKTREQUESTED(htod); + } else { + WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); + } + + rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, + entry->traffic_lastreported_bmp, entry->mac_handle, htod, htodseq, FALSE); + if (rc == BCME_OK) { + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); + + if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && header_needed) { + /* + a new header was created for this packet. + push to hanger slot and scrub q. Since bus + send succeeded, increment seq number as well. + */ + rc = _dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); + if (rc == BCME_OK) { +#ifdef PROP_TXSTATUS_DEBUG + ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = + OSL_SYSUPTIME(); +#endif + } else { + DHD_ERROR(("%s() hanger_pushpkt() failed, rc: %d\n", + __FUNCTION__, rc)); + } + } + + if ((rc == BCME_OK) && header_needed) { + /* increment free running sequence count */ + WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); + } + } + *slot = hslot; + return rc; +} + +static int +_dhd_wlfc_is_destination_open(athost_wl_status_info_t* ctx, + wlfc_mac_descriptor_t* entry, int prec) +{ + if (entry->interface_id >= WLFC_MAX_IFNUM) { + ASSERT(&ctx->destination_entries.other == entry); + return 1; + } + if (ctx->destination_entries.interfaces[entry->interface_id].iftype == + WLC_E_IF_ROLE_P2P_GO) { + /* - destination interface is of type p2p GO. + For a p2pGO interface, if the destination is OPEN but the interface is + CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is + destination-specific-credit left send packets. This is because the + firmware storing the destination-specific-requested packet in queue. + */ + if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && + (entry->requested_packet == 0)) { + return 0; + } + } + /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ + if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && + (entry->requested_packet == 0)) || + (!(entry->ac_bitmap & (1 << prec)))) { + return 0; + } + + return 1; +} + +static void* +_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, int prec, + uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out, + bool only_no_credit) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + wlfc_mac_descriptor_t* entry; + int total_entries; + void* p = NULL; + int i; + + *entry_out = NULL; + /* most cases a packet will count against FIFO credit */ + *ac_credit_spent = ((prec == AC_COUNT) && !ctx->bcmc_credit_supported) ? 0 : 1; + + /* search all entries, include nodes as well as interfaces */ + if (only_no_credit) { + total_entries = ctx->requested_entry_count; + } else { + total_entries = ctx->active_entry_count; + } + + for (i = 0; i < total_entries; i++) { + if (only_no_credit) { + entry = ctx->requested_entry[i]; + } else { + entry = ctx->active_entry_head; + /* move head to ensure fair round-robin */ + ctx->active_entry_head = ctx->active_entry_head->next; + } + ASSERT(entry); + + if (entry->occupied && _dhd_wlfc_is_destination_open(ctx, entry, prec) && + (entry->transit_count < WL_TXSTATUS_FREERUNCTR_MASK) && + !(WLFC_GET_REORDERSUPP(dhdp->wlfc_mode) && entry->suppressed)) { + if (entry->state == WLFC_STATE_CLOSE) { + *ac_credit_spent = 0; + } + + /* higher precedence will be picked up first, + * i.e. suppressed packets before delayed ones + */ + p = pktq_pdeq(&entry->psq, PSQ_SUP_IDX(prec)); + *needs_hdr = 0; + if (p == NULL) { + if (entry->suppressed == TRUE) { + /* skip this entry */ + continue; + } + /* De-Q from delay Q */ + p = pktq_pdeq(&entry->psq, PSQ_DLY_IDX(prec)); + *needs_hdr = 1; + } + + if (p != NULL) { + /* did the packet come from suppress sub-queue? */ + if (entry->requested_credit > 0) { + entry->requested_credit--; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_sent_packets++; +#endif + } else if (entry->requested_packet > 0) { + entry->requested_packet--; + DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); + } + + *entry_out = entry; + ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec]--; + ctx->pkt_cnt_per_ac[prec]--; + _dhd_wlfc_flow_control_check(ctx, &entry->psq, + DHD_PKTTAG_IF(PKTTAG(p))); + /* + A packet has been picked up, update traffic + availability bitmap, if applicable + */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + return p; + } + } + } + return NULL; +} + +static int +_dhd_wlfc_enque_delayq(athost_wl_status_info_t* ctx, void* pktbuf, int prec) +{ + wlfc_mac_descriptor_t* entry; + + if (pktbuf != NULL) { + entry = _dhd_wlfc_find_table_entry(ctx, pktbuf); + if (entry == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_ERROR; + } + + /* + - suppressed packets go to sub_queue[2*prec + 1] AND + - delayed packets go to sub_queue[2*prec + 0] to ensure + order of delivery. + */ + if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, pktbuf, (prec << 1), + FALSE, WLFC_SEQCOUNT(entry, prec)) + == FALSE) { + WLFC_DBGMESG(("D")); + ctx->stats.delayq_full_error++; + return BCME_ERROR; + } + + + /* + A packet has been pushed, update traffic availability bitmap, + if applicable + */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + } + + return BCME_OK; +} + +static bool _dhd_wlfc_ifpkt_fn(void* p, void *p_ifid) +{ + if (!p || !p_ifid) + return FALSE; + + return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (*((uint8 *)p_ifid) == DHD_PKTTAG_IF(PKTTAG(p)))); +} + +static bool _dhd_wlfc_entrypkt_fn(void* p, void *entry) +{ + if (!p || !entry) + return FALSE; + + return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (entry == DHD_PKTTAG_ENTRY(PKTTAG(p)))); +} + +static void +_dhd_wlfc_return_implied_credit(athost_wl_status_info_t* wlfc, void* pkt) +{ + dhd_pub_t *dhdp; + + if (!wlfc || !pkt) { + return; + } + + dhdp = (dhd_pub_t *)(wlfc->dhdp); + if (dhdp && (dhdp->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) && + DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { + int lender, credit_returned = 0; + uint8 fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pkt)); + + /* Note that borrower is fifo_id */ + /* Return credits to highest priority lender first */ + for (lender = AC_COUNT; lender >= 0; lender--) { + if (wlfc->credits_borrowed[fifo_id][lender] > 0) { + wlfc->FIFO_credit[lender]++; + wlfc->credits_borrowed[fifo_id][lender]--; + credit_returned = 1; + break; + } + } + + if (!credit_returned) { + wlfc->FIFO_credit[fifo_id]++; + } + } +} + +static void +_dhd_wlfc_pktq_flush(athost_wl_status_info_t* ctx, struct pktq *pq, + bool dir, f_processpkt_t fn, void *arg, q_type_t q_type) +{ + int prec; + dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; + + ASSERT(dhdp); + + /* Optimize flush, if pktq len = 0, just return. + * pktq len of 0 means pktq's prec q's are all empty. + */ + if (pq->len == 0) { + return; + } + + + for (prec = 0; prec < pq->num_prec; prec++) { + struct pktq_prec *q; + void *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 = PKTLINK(p); + else + PKTSETLINK(prev, PKTLINK(p)); + if (q_type == Q_TYPE_PSQ) { + if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { + _dhd_wlfc_hanger_remove_reference(ctx->hanger, p); + } + ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; + ctx->pkt_cnt_per_ac[prec>>1]--; + ctx->stats.cleanup_psq_cnt++; + if (!(prec & 1)) { + /* pkt in delayed q, so fake push BDC header for + * dhd_tcpack_check_xmit() and dhd_txcomplete(). + */ + _dhd_wlfc_pushheader(ctx, p, FALSE, 0, 0, + 0, 0, TRUE); +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" + " Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(dhdp, + TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + } + } else if (q_type == Q_TYPE_AFQ) { + wlfc_mac_descriptor_t* entry = + _dhd_wlfc_find_table_entry(ctx, p); + entry->transit_count--; + if (entry->suppressed && + (--entry->suppr_transit_count == 0)) { + entry->suppressed = FALSE; + } + _dhd_wlfc_return_implied_credit(ctx, p); + ctx->stats.cleanup_fw_cnt++; + } + PKTSETLINK(p, NULL); + dhd_txcomplete(dhdp, p, FALSE); + PKTFREE(ctx->osh, p, dir); + if (dir) { + ctx->stats.pktout++; + } + q->len--; + pq->len--; + p = (head ? q->head : PKTLINK(prev)); + } else { + prev = p; + p = PKTLINK(p); + } + } + + if (q->head == NULL) { + ASSERT(q->len == 0); + q->tail = NULL; + } + + } + + if (fn == NULL) + ASSERT(pq->len == 0); +} + +static void* +_dhd_wlfc_pktq_pdeq_with_fn(struct pktq *pq, int prec, f_processpkt_t fn, void *arg) +{ + struct pktq_prec *q; + void *p, *prev = NULL; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + p = q->head; + + while (p) { + if (fn == NULL || (*fn)(p, arg)) { + break; + } else { + prev = p; + p = PKTLINK(p); + } + } + if (p == NULL) + return NULL; + + if (prev == NULL) { + if ((q->head = PKTLINK(p)) == NULL) { + q->tail = NULL; + } + } else { + PKTSETLINK(prev, PKTLINK(p)); + if (q->tail == p) { + q->tail = prev; + } + } + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +static void +_dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + int prec; + void *pkt = NULL, *head = NULL, *tail = NULL; + struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; + wlfc_mac_descriptor_t* entry; + + dhd_os_sdlock_txq(dhd); + for (prec = 0; prec < txq->num_prec; prec++) { + while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { +#ifdef DHDTCPACK_SUPPRESS + if (dhd_tcpack_check_xmit(dhd, pkt) == BCME_ERROR) { + DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", + __FUNCTION__, __LINE__)); + dhd_tcpack_suppress_set(dhd, TCPACK_SUP_OFF); + } +#endif /* DHDTCPACK_SUPPRESS */ + if (!head) { + head = pkt; + } + if (tail) { + PKTSETLINK(tail, pkt); + } + tail = pkt; + } + } + dhd_os_sdunlock_txq(dhd); + + + while ((pkt = head)) { + head = PKTLINK(pkt); + PKTSETLINK(pkt, NULL); + entry = _dhd_wlfc_find_table_entry(wlfc, pkt); + + if (!WLFC_GET_AFQ(dhd->wlfc_mode) && + !_dhd_wlfc_hanger_remove_reference(h, pkt)) { + DHD_ERROR(("%s: can't find pkt(%p) in hanger, free it anyway\n", + __FUNCTION__, pkt)); + } + entry->transit_count--; + if (entry->suppressed && + (--entry->suppr_transit_count == 0)) { + entry->suppressed = FALSE; + } + _dhd_wlfc_return_implied_credit(wlfc, pkt); + dhd_txcomplete(dhd, pkt, FALSE); + PKTFREE(wlfc->osh, pkt, TRUE); + wlfc->stats.pktout++; + wlfc->stats.cleanup_txq_cnt++; + + } +} + +void +_dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + int i; + int total_entries; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; + + wlfc->stats.cleanup_txq_cnt = 0; + wlfc->stats.cleanup_psq_cnt = 0; + wlfc->stats.cleanup_fw_cnt = 0; + /* + * flush sequence shoulde be txq -> psq -> hanger/afq, hanger has to be last one + */ + /* flush bus->txq */ + _dhd_wlfc_cleanup_txq(dhd, fn, arg); + + + /* flush psq, search all entries, include nodes as well as interfaces */ + total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); + table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; + + for (i = 0; i < total_entries; i++) { + if (table[i].occupied) { + /* release packets held in PSQ (both delayed and suppressed) */ + if (table[i].psq.len) { + WLFC_DBGMESG(("%s(): PSQ[%d].len = %d\n", + __FUNCTION__, i, table[i].psq.len)); + _dhd_wlfc_pktq_flush(wlfc, &table[i].psq, TRUE, + fn, arg, Q_TYPE_PSQ); + } + + /* free packets held in AFQ */ + if (WLFC_GET_AFQ(dhd->wlfc_mode) && (table[i].afq.len)) { + _dhd_wlfc_pktq_flush(wlfc, &table[i].afq, TRUE, + fn, arg, Q_TYPE_AFQ); + } + + if ((fn == NULL) && (&table[i] != &wlfc->destination_entries.other)) { + table[i].occupied = 0; + if (table[i].transit_count || table[i].suppr_transit_count) { + DHD_ERROR(("%s: table[%d] transit(%d), suppr_tansit(%d)\n", + __FUNCTION__, i, + table[i].transit_count, + table[i].suppr_transit_count)); + } + } + } + } + + /* + . flush remained pkt in hanger queue, not in bus->txq nor psq. + . the remained pkt was successfully downloaded to dongle already. + . hanger slot state cannot be set to free until receive txstatus update. + */ + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + for (i = 0; i < h->max_items; i++) { + if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) || + (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { + if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { + table = _dhd_wlfc_find_table_entry(wlfc, h->items[i].pkt); + table->transit_count--; + if (table->suppressed && + (--table->suppr_transit_count == 0)) { + table->suppressed = FALSE; + } + _dhd_wlfc_return_implied_credit(wlfc, h->items[i].pkt); + dhd_txcomplete(dhd, h->items[i].pkt, FALSE); + PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); + wlfc->stats.pktout++; + wlfc->stats.cleanup_fw_cnt++; + h->items[i].state = WLFC_HANGER_ITEM_STATE_WAIT_CLEAN; + } + } + } + } + + return; +} + +static int +_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + uint8 action, uint8 ifid, uint8 iftype, uint8* ea, + f_processpkt_t fn, void *arg) +{ + int rc = BCME_OK; + + + if ((action == eWLFC_MAC_ENTRY_ACTION_ADD) || (action == eWLFC_MAC_ENTRY_ACTION_UPDATE)) { + entry->occupied = 1; + entry->state = WLFC_STATE_OPEN; + entry->requested_credit = 0; + entry->interface_id = ifid; + entry->iftype = iftype; + entry->ac_bitmap = 0xff; /* update this when handling APSD */ + /* for an interface entry we may not care about the MAC address */ + if (ea != NULL) + memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); + + if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { + dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); + pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); + if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { + pktq_init(&entry->afq, WLFC_AFQ_PREC_COUNT, WLFC_PSQ_LEN); + } + + if (entry->next == NULL) { + /* not linked to anywhere, add to tail */ + if (ctx->active_entry_head) { + entry->prev = ctx->active_entry_head->prev; + ctx->active_entry_head->prev->next = entry; + ctx->active_entry_head->prev = entry; + entry->next = ctx->active_entry_head; + + } else { + ASSERT(ctx->active_entry_count == 0); + entry->prev = entry->next = entry; + ctx->active_entry_head = entry; + } + ctx->active_entry_count++; + } else { + DHD_ERROR(("%s():%d, entry(%d)\n", __FUNCTION__, __LINE__, + (int)(entry - &ctx->destination_entries.nodes[0]))); + } + } + } else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { + /* When the entry is deleted, the packets that are queued in the entry must be + cleanup. The cleanup action should be before the occupied is set as 0. + */ + _dhd_wlfc_cleanup(ctx->dhdp, fn, arg); + _dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid); + + entry->occupied = 0; + entry->suppressed = 0; + entry->state = WLFC_STATE_CLOSE; + entry->requested_credit = 0; + entry->transit_count = 0; + entry->suppr_transit_count = 0; + memset(&entry->ea[0], 0, ETHER_ADDR_LEN); + + if (entry->next) { + /* not floating, remove from Q */ + if (ctx->active_entry_count <= 1) { + /* last item */ + ctx->active_entry_head = NULL; + ctx->active_entry_count = 0; + } else { + entry->prev->next = entry->next; + entry->next->prev = entry->prev; + if (entry == ctx->active_entry_head) { + ctx->active_entry_head = entry->next; + } + ctx->active_entry_count--; + } + entry->next = entry->prev = NULL; + } else { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + } + } + return rc; +} + +#ifdef LIMIT_BORROW +static int +_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, int highest_lender_ac, int borrower_ac) +{ + int lender_ac; + int rc = -1; + + if (ctx == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return -1; + } + + /* Borrow from lowest priority available AC (including BC/MC credits) */ + for (lender_ac = 0; lender_ac <= highest_lender_ac; lender_ac++) { + if (ctx->FIFO_credit[lender_ac] > 0) { + ctx->credits_borrowed[borrower_ac][lender_ac]++; + ctx->FIFO_credit[lender_ac]--; + rc = lender_ac; + break; + } + } + + return rc; +} + +static int _dhd_wlfc_return_credit(athost_wl_status_info_t* ctx, int lender_ac, int borrower_ac) +{ + if ((ctx == NULL) || (lender_ac < 0) || (lender_ac > AC_COUNT) || + (borrower_ac < 0) || (borrower_ac > AC_COUNT)) { + DHD_ERROR(("Error: %s():%d, ctx(%p), lender_ac(%d), borrower_ac(%d)\n", + __FUNCTION__, __LINE__, ctx, lender_ac, borrower_ac)); + + return BCME_BADARG; + } + + ctx->credits_borrowed[borrower_ac][lender_ac]--; + ctx->FIFO_credit[lender_ac]++; + + return BCME_OK; +} +#endif /* LIMIT_BORROW */ + +static int +_dhd_wlfc_interface_entry_update(void* state, + uint8 action, uint8 ifid, uint8 iftype, uint8* ea) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + wlfc_mac_descriptor_t* entry; + + if (ifid >= WLFC_MAX_IFNUM) + return BCME_BADARG; + + entry = &ctx->destination_entries.interfaces[ifid]; + + return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea, + _dhd_wlfc_ifpkt_fn, &ifid); +} + +static int +_dhd_wlfc_BCMCCredit_support_update(void* state) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + + ctx->bcmc_credit_supported = TRUE; + return BCME_OK; +} + +static int +_dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + int i; + + for (i = 0; i <= 4; i++) { + if (ctx->Init_FIFO_credit[i] != ctx->FIFO_credit[i]) { + DHD_ERROR(("%s: credit[i] is not returned, (%d %d)\n", + __FUNCTION__, ctx->Init_FIFO_credit[i], ctx->FIFO_credit[i])); + } + } + + /* update the AC FIFO credit map */ + ctx->FIFO_credit[0] += (credits[0] - ctx->Init_FIFO_credit[0]); + ctx->FIFO_credit[1] += (credits[1] - ctx->Init_FIFO_credit[1]); + ctx->FIFO_credit[2] += (credits[2] - ctx->Init_FIFO_credit[2]); + ctx->FIFO_credit[3] += (credits[3] - ctx->Init_FIFO_credit[3]); + ctx->FIFO_credit[4] += (credits[4] - ctx->Init_FIFO_credit[4]); + + ctx->Init_FIFO_credit[0] = credits[0]; + ctx->Init_FIFO_credit[1] = credits[1]; + ctx->Init_FIFO_credit[2] = credits[2]; + ctx->Init_FIFO_credit[3] = credits[3]; + ctx->Init_FIFO_credit[4] = credits[4]; + + /* credit for ATIM FIFO is not used yet. */ + ctx->Init_FIFO_credit[5] = ctx->FIFO_credit[5] = 0; + + return BCME_OK; +} + +static int +_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, + dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) +{ + uint32 hslot; + int rc; + dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); + + /* + if ac_fifo_credit_spent = 0 + + This packet will not count against the FIFO credit. + To ensure the txstatus corresponding to this packet + does not provide an implied credit (default behavior) + mark the packet accordingly. + + if ac_fifo_credit_spent = 1 + + This is a normal packet and it counts against the FIFO + credit count. + */ + DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); + rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, + commit_info->needs_hdr, &hslot); + + if (rc == BCME_OK) { + DHD_PKTTAG_WLFCPKT_SET(PKTTAG(commit_info->p), 1); + rc = fcommit(commit_ctx, commit_info->p); + if (rc == BCME_OK) { + uint8 gen = WL_TXSTATUS_GET_GENERATION( + DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))); + if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { + _dhd_wlfc_hanger_waitevent_set(ctx->hanger, hslot, + WLFC_HANGER_ITEM_WAIT_EVENT_COUNT); + } + ctx->stats.pkt2bus++; + if (commit_info->ac_fifo_credit_spent || (ac == AC_COUNT)) { + ctx->stats.send_pkts[ac]++; + WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); + } + + if (gen != commit_info->mac_entry->generation) { + /* will be suppressed back by design */ + if (!commit_info->mac_entry->suppressed) { + commit_info->mac_entry->suppressed = TRUE; + } + commit_info->mac_entry->suppr_transit_count++; + } + commit_info->mac_entry->transit_count++; + } else if (commit_info->needs_hdr) { + if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { + void *pout = NULL; + /* pop hanger for delayed packet */ + _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT( + DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))), &pout, 1); + ASSERT(commit_info->p == pout); + } + } + } else { + ctx->stats.generic_error++; + } + + if (rc != BCME_OK) { + /* + pretx pkt process or bus commit has failed, rollback. + - remove wl-header for a delayed packet + - save wl-header header for suppressed packets + - reset credit check flag + */ + _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, commit_info->pkt_type, hslot); + DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), 0); + } + + return rc; +} + +static uint8 +_dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) +{ + wlfc_mac_descriptor_t* table = + ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; + uint8 table_index; + + if (ea != NULL) { + for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { + if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && + table[table_index].occupied) + return table_index; + } + } + return WLFC_MAC_DESC_ID_INVALID; +} + +static int +_dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, void** p_mac) +{ + uint8 status_flag; + uint32 status; + int ret = BCME_OK; + int remove_from_hanger = 1; + void* pktbuf = NULL; + uint8 fifo_id = 0, gen = 0, count = 0, hcnt; + uint16 hslot; + wlfc_mac_descriptor_t* entry = NULL; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + uint16 seq = 0, seq_fromfw = 0, seq_num = 0; + + memcpy(&status, pkt_info, sizeof(uint32)); + status_flag = WL_TXSTATUS_GET_FLAGS(status); + hcnt = WL_TXSTATUS_GET_FREERUNCTR(status); + hslot = WL_TXSTATUS_GET_HSLOT(status); + fifo_id = WL_TXSTATUS_GET_FIFO(status); + gen = WL_TXSTATUS_GET_GENERATION(status); + + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { + memcpy(&seq, pkt_info + WLFC_CTL_VALUE_LEN_TXSTATUS, WLFC_CTL_VALUE_LEN_SEQ); + seq_fromfw = WL_SEQ_GET_FROMFW(seq); + seq_num = WL_SEQ_GET_NUM(seq); + } + + wlfc->stats.txstatus_in += len; + + if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { + wlfc->stats.pkt_freed += len; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_DISCARD_NOACK) { + wlfc->stats.pkt_freed += len; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { + wlfc->stats.d11_suppress += len; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { + wlfc->stats.wl_suppress += len; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { + wlfc->stats.wlc_tossed_pkts += len; + } + + if (dhd->proptxstatus_txstatus_ignore) { + if (!remove_from_hanger) { + DHD_ERROR(("suppress txstatus: %d\n", status_flag)); + } + return BCME_OK; + } + + while (count < len) { + if (WLFC_GET_AFQ(dhd->wlfc_mode)) { + ret = _dhd_wlfc_deque_afq(wlfc, hslot, hcnt, fifo_id, &pktbuf); + } else { + if (_dhd_wlfc_hanger_wait_clean(wlfc->hanger, hslot)) { + goto cont; + } + + ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, hslot, &pktbuf, 0); + } + + if ((ret != BCME_OK) || !pktbuf) { + goto cont; + } + + /* set fifo_id to correct value because not all FW does that */ + fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + + if (!remove_from_hanger) { + /* this packet was suppressed */ + if (!entry->suppressed || (entry->generation != gen)) { + if (!entry->suppressed) { + entry->suppr_transit_count = entry->transit_count; + if (p_mac) { + *p_mac = entry; + } + } else { + DHD_ERROR(("gen(%d), entry->generation(%d)\n", + gen, entry->generation)); + } + entry->suppressed = TRUE; + + } + entry->generation = gen; + } + +#ifdef PROP_TXSTATUS_DEBUG + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) + { + uint32 new_t = OSL_SYSUPTIME(); + uint32 old_t; + uint32 delta; + old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[hslot].push_time; + + + wlfc->stats.latency_sample_count++; + if (new_t > old_t) + delta = new_t - old_t; + else + delta = 0xffffffff + new_t - old_t; + wlfc->stats.total_status_latency += delta; + wlfc->stats.latency_most_recent = delta; + + wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; + if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) + wlfc->stats.idx_delta = 0; + } +#endif /* PROP_TXSTATUS_DEBUG */ + + /* pick up the implicit credit from this packet */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { + _dhd_wlfc_return_implied_credit(wlfc, pktbuf); + } else { + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the destination entry (for pspoll etc.) + */ + if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) + entry->requested_credit++; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_acks++; +#endif + } + + if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || + (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { + /* save generation bit inside packet */ + WL_TXSTATUS_SET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(pktbuf)), gen); + + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { + WL_SEQ_SET_FROMDRV(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_fromfw); + WL_SEQ_SET_NUM(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_num); + } + + ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); + if (ret != BCME_OK) { + /* delay q is full, drop this packet */ + DHD_WLFC_QMON_COMPLETE(entry); + _dhd_wlfc_prec_drop(dhd, (fifo_id << 1) + 1, pktbuf, FALSE); + } else { + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + /* Mark suppressed to avoid a double free + during wlfc cleanup + */ + _dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, hslot, gen); + } + } + } else { + uint8 waitevent = 0; + void *pktbuf_tmp = NULL; + dhd_txcomplete(dhd, pktbuf, TRUE); + + DHD_WLFC_QMON_COMPLETE(entry); + wlfc->stats.pktout++; + + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + waitevent = _dhd_wlfc_hanger_waitevent_decreturn(wlfc->hanger, + hslot); + if (!waitevent) { + ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, + hslot, &pktbuf_tmp, 1); + ASSERT((ret == BCME_OK) && (pktbuf == pktbuf_tmp)); + } + } + if (!waitevent) { + /* free the packet */ + PKTFREE(wlfc->osh, pktbuf, TRUE); + } + } + /* pkt back from firmware side */ + entry->transit_count--; + if (entry->suppressed && (--entry->suppr_transit_count == 0)) { + entry->suppressed = FALSE; + } + +cont: + hcnt = (hcnt + 1) & WL_TXSTATUS_FREERUNCTR_MASK; + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + hslot = (hslot + 1) & WL_TXSTATUS_HSLOT_MASK; + } + + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode) && seq_fromfw) { + seq_num = (seq_num + 1) & WL_SEQ_NUM_MASK; + } + + count++; + } + return BCME_OK; +} + +static int +_dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) +{ + int i; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { +#ifdef PROP_TXSTATUS_DEBUG + wlfc->stats.fifo_credits_back[i] += credits[i]; +#endif + + /* update FIFO credits */ + if (dhd->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) + { + int lender; /* Note that borrower is i */ + + /* Return credits to highest priority lender first */ + for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { + if (wlfc->credits_borrowed[i][lender] > 0) { + if (credits[i] >= wlfc->credits_borrowed[i][lender]) { + credits[i] -= + (uint8)wlfc->credits_borrowed[i][lender]; + wlfc->FIFO_credit[lender] += + wlfc->credits_borrowed[i][lender]; + wlfc->credits_borrowed[i][lender] = 0; + } + else { + wlfc->credits_borrowed[i][lender] -= credits[i]; + wlfc->FIFO_credit[lender] += credits[i]; + credits[i] = 0; + } + } + } + + /* If we have more credits left over, these must belong to the AC */ + if (credits[i] > 0) { + wlfc->FIFO_credit[i] += credits[i]; + } + + if (wlfc->FIFO_credit[i] > wlfc->Init_FIFO_credit[i]) { + wlfc->FIFO_credit[i] = wlfc->Init_FIFO_credit[i]; + } + } + } + + return BCME_OK; +} + +static void +_dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* entry; + int prec; + void *pkt = NULL, *head = NULL, *tail = NULL; + struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); + uint8 results[WLFC_CTL_VALUE_LEN_TXSTATUS+WLFC_CTL_VALUE_LEN_SEQ]; + uint8 credits[WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK] = {0}; + uint32 htod = 0; + uint16 htodseq = 0; + bool bCreditUpdate = FALSE; + + dhd_os_sdlock_txq(dhd); + for (prec = 0; prec < txq->num_prec; prec++) { + while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { + if (!head) { + head = pkt; + } + if (tail) { + PKTSETLINK(tail, pkt); + } + tail = pkt; + } + } + dhd_os_sdunlock_txq(dhd); + + while ((pkt = head)) { + head = PKTLINK(pkt); + PKTSETLINK(pkt, NULL); + + entry = _dhd_wlfc_find_table_entry(wlfc, pkt); + + /* fake a suppression txstatus */ + htod = DHD_PKTTAG_H2DTAG(PKTTAG(pkt)); + WL_TXSTATUS_SET_FLAGS(htod, WLFC_CTL_PKTFLAG_WLSUPPRESS); + WL_TXSTATUS_SET_GENERATION(htod, entry->generation); + memcpy(results, &htod, WLFC_CTL_VALUE_LEN_TXSTATUS); + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { + htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(pkt)); + if (WL_SEQ_GET_FROMDRV(htodseq)) { + WL_SEQ_SET_FROMFW(htodseq, 1); + WL_SEQ_SET_FROMDRV(htodseq, 0); + } + memcpy(results + WLFC_CTL_VALUE_LEN_TXSTATUS, &htodseq, + WLFC_CTL_VALUE_LEN_SEQ); + } + if (WLFC_GET_AFQ(dhd->wlfc_mode)) { + _dhd_wlfc_enque_afq(wlfc, pkt); + } + _dhd_wlfc_compressed_txstatus_update(dhd, results, 1, NULL); + + /* fake a fifo credit back */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { + credits[DHD_PKTTAG_FIFO(PKTTAG(pkt))]++; + bCreditUpdate = TRUE; + } + } + + if (bCreditUpdate) { + _dhd_wlfc_fifocreditback_indicate(dhd, credits); + } +} + + +static int +_dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) +{ + uint32 timestamp; + + (void)dhd; + + bcopy(&value[2], ×tamp, sizeof(uint32)); + DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp)); + return BCME_OK; +} + +static int +_dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) +{ + (void)dhd; + (void)rssi; + return BCME_OK; +} + +static void +_dhd_wlfc_add_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) +{ + int i; + + if (!wlfc || !entry) { + return; + } + + for (i = 0; i < wlfc->requested_entry_count; i++) { + if (entry == wlfc->requested_entry[i]) { + break; + } + } + + if (i == wlfc->requested_entry_count) { + /* no match entry found */ + ASSERT(wlfc->requested_entry_count <= (WLFC_MAC_DESC_TABLE_SIZE-1)); + wlfc->requested_entry[wlfc->requested_entry_count++] = entry; + } +} + +static void +_dhd_wlfc_remove_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) +{ + int i; + + if (!wlfc || !entry) { + return; + } + + for (i = 0; i < wlfc->requested_entry_count; i++) { + if (entry == wlfc->requested_entry[i]) { + break; + } + } + + if (i < wlfc->requested_entry_count) { + /* found */ + ASSERT(wlfc->requested_entry_count > 0); + wlfc->requested_entry_count--; + if (i != wlfc->requested_entry_count) { + wlfc->requested_entry[i] = + wlfc->requested_entry[wlfc->requested_entry_count]; + } + wlfc->requested_entry[wlfc->requested_entry_count] = NULL; + } +} + +static int +_dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + int rc; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + uint8 existing_index; + uint8 table_index; + uint8 ifid; + uint8* ea; + + WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", + __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], + ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), + WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); + + table = wlfc->destination_entries.nodes; + table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); + ifid = value[1]; + ea = &value[2]; + + _dhd_wlfc_remove_requested_entry(wlfc, &table[table_index]); + if (type == WLFC_CTL_TYPE_MACDESC_ADD) { + existing_index = _dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); + if ((existing_index != WLFC_MAC_DESC_ID_INVALID) && + (existing_index != table_index) && table[existing_index].occupied) { + /* + there is an existing different entry, free the old one + and move it to new index if necessary. + */ + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[existing_index], + eWLFC_MAC_ENTRY_ACTION_DEL, table[existing_index].interface_id, + table[existing_index].iftype, NULL, _dhd_wlfc_entrypkt_fn, + &table[existing_index]); + } + + if (!table[table_index].occupied) { + /* this new MAC entry does not exist, create one */ + table[table_index].mac_handle = value[0]; + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], + eWLFC_MAC_ENTRY_ACTION_ADD, ifid, + wlfc->destination_entries.interfaces[ifid].iftype, + ea, NULL, NULL); + } else { + /* the space should have been empty, but it's not */ + wlfc->stats.mac_update_failed++; + } + } + + if (type == WLFC_CTL_TYPE_MACDESC_DEL) { + if (table[table_index].occupied) { + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], + eWLFC_MAC_ENTRY_ACTION_DEL, ifid, + wlfc->destination_entries.interfaces[ifid].iftype, + ea, _dhd_wlfc_entrypkt_fn, &table[table_index]); + } else { + /* the space should have been occupied, but it's not */ + wlfc->stats.mac_update_failed++; + } + } + BCM_REFERENCE(rc); + return BCME_OK; +} + +static int +_dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + /* Handle PS on/off indication */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle = value[0]; + int i; + + table = wlfc->destination_entries.nodes; + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + /* a fresh PS mode should wipe old ps credits? */ + desc->requested_credit = 0; + if (type == WLFC_CTL_TYPE_MAC_OPEN) { + desc->state = WLFC_STATE_OPEN; + desc->ac_bitmap = 0xff; + DHD_WLFC_CTRINC_MAC_OPEN(desc); + _dhd_wlfc_remove_requested_entry(wlfc, desc); + } + else { + desc->state = WLFC_STATE_CLOSE; + DHD_WLFC_CTRINC_MAC_CLOSE(desc); + /* + Indicate to firmware if there is any traffic pending. + */ + for (i = 0; i < AC_COUNT; i++) { + _dhd_wlfc_traffic_pending_check(wlfc, desc, i); + } + } + } + else { + wlfc->stats.psmode_update_failed++; + } + return BCME_OK; +} + +static int +_dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + /* Handle PS on/off indication */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + uint8 if_id = value[0]; + + if (if_id < WLFC_MAX_IFNUM) { + table = wlfc->destination_entries.interfaces; + if (table[if_id].occupied) { + if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { + table[if_id].state = WLFC_STATE_OPEN; + /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ + } + else { + table[if_id].state = WLFC_STATE_CLOSE; + /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ + } + return BCME_OK; + } + } + wlfc->stats.interface_update_failed++; + + return BCME_OK; +} + +static int +_dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle; + uint8 credit; + + table = wlfc->destination_entries.nodes; + mac_handle = value[1]; + credit = value[0]; + + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + desc->requested_credit = credit; + + desc->ac_bitmap = value[2] & (~(1<stats.credit_request_failed++; + } + return BCME_OK; +} + +static int +_dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle; + uint8 packet_count; + + table = wlfc->destination_entries.nodes; + mac_handle = value[1]; + packet_count = value[0]; + + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + desc->requested_packet = packet_count; + + desc->ac_bitmap = value[2] & (~(1<stats.packet_request_failed++; + } + return BCME_OK; +} + +static void +_dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) +{ + if (info_len) { + /* Check copy length to avoid buffer overrun. In case of length exceeding + * WLHOST_REORDERDATA_TOTLEN, return failure instead sending incomplete result + * of length WLHOST_REORDERDATA_TOTLEN + */ + if ((info_buf) && (len <= WLHOST_REORDERDATA_TOTLEN)) { + bcopy(val, info_buf, len); + *info_len = len; + } + else + *info_len = 0; + } +} + +/* + * public functions + */ + +bool dhd_wlfc_is_supported(dhd_pub_t *dhd) +{ + bool rc = TRUE; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return FALSE; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + rc = FALSE; + } + + dhd_os_wlfc_unblock(dhd); + + return rc; +} + +int dhd_wlfc_enable(dhd_pub_t *dhd) +{ + int i, rc = BCME_OK; + athost_wl_status_info_t* wlfc; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_enabled || dhd->wlfc_state) { + rc = BCME_OK; + goto exit; + } + + /* allocate space to track txstatus propagated from firmware */ + dhd->wlfc_state = DHD_OS_PREALLOC(dhd, DHD_PREALLOC_DHD_WLFC_INFO, + sizeof(athost_wl_status_info_t)); + if (dhd->wlfc_state == NULL) { + rc = BCME_NOMEM; + goto exit; + } + + /* initialize state space */ + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + memset(wlfc, 0, sizeof(athost_wl_status_info_t)); + + /* remember osh & dhdp */ + wlfc->osh = dhd->osh; + wlfc->dhdp = dhd; + + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + wlfc->hanger = _dhd_wlfc_hanger_create(dhd, WLFC_HANGER_MAXITEMS); + if (wlfc->hanger == NULL) { + DHD_OS_PREFREE(dhd, dhd->wlfc_state, + sizeof(athost_wl_status_info_t)); + dhd->wlfc_state = NULL; + rc = BCME_NOMEM; + goto exit; + } + } + + dhd->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; + /* default to check rx pkt */ + if (dhd->op_mode & DHD_FLAG_IBSS_MODE) { + dhd->wlfc_rxpkt_chk = FALSE; + } else { + dhd->wlfc_rxpkt_chk = TRUE; + } + + + /* initialize all interfaces to accept traffic */ + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + wlfc->hostif_flow_state[i] = OFF; + } + + _dhd_wlfc_mac_entry_update(wlfc, &wlfc->destination_entries.other, + eWLFC_MAC_ENTRY_ACTION_ADD, 0xff, 0, NULL, NULL, NULL); + + wlfc->allow_credit_borrow = 0; + wlfc->single_ac = 0; + wlfc->single_ac_timestamp = 0; + + +exit: + dhd_os_wlfc_unblock(dhd); + + return rc; +} + +int +dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, + uint *reorder_info_len) +{ + uint8 type, len; + uint8* value; + uint8* tmpbuf; + uint16 remainder = (uint16)tlv_hdr_len; + uint16 processed = 0; + athost_wl_status_info_t* wlfc = NULL; + void* entry; + + if ((dhd == NULL) || (pktbuf == NULL)) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (dhd->proptxstatus_mode != WLFC_ONLY_AMPDU_HOSTREORDER) { + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + } + + tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); + + if (remainder) { + while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { + type = tmpbuf[processed]; + if (type == WLFC_CTL_TYPE_FILLER) { + remainder -= 1; + processed += 1; + continue; + } + + len = tmpbuf[processed + 1]; + value = &tmpbuf[processed + 2]; + + if (remainder < (2 + len)) + break; + + remainder -= 2 + len; + processed += 2 + len; + entry = NULL; + + DHD_INFO(("%s():%d type %d remainder %d processed %d\n", + __FUNCTION__, __LINE__, type, remainder, processed)); + + if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) + _dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, + reorder_info_len); + + if (wlfc == NULL) { + ASSERT(dhd->proptxstatus_mode == WLFC_ONLY_AMPDU_HOSTREORDER); + + if (type != WLFC_CTL_TYPE_HOST_REORDER_RXPKTS && + type != WLFC_CTL_TYPE_TRANS_ID) + DHD_INFO(("%s():%d dhd->wlfc_state is NULL yet!" + " type %d remainder %d processed %d\n", + __FUNCTION__, __LINE__, type, remainder, processed)); + continue; + } + + if (type == WLFC_CTL_TYPE_TXSTATUS) { + _dhd_wlfc_compressed_txstatus_update(dhd, value, 1, &entry); + } + else if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) { + uint8 compcnt_offset = WLFC_CTL_VALUE_LEN_TXSTATUS; + + if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { + compcnt_offset += WLFC_CTL_VALUE_LEN_SEQ; + } + _dhd_wlfc_compressed_txstatus_update(dhd, value, + value[compcnt_offset], &entry); + } + else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) + _dhd_wlfc_fifocreditback_indicate(dhd, value); + + else if (type == WLFC_CTL_TYPE_RSSI) + _dhd_wlfc_rssi_indicate(dhd, value); + + else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) + _dhd_wlfc_credit_request(dhd, value); + + else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) + _dhd_wlfc_packet_request(dhd, value); + + else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || + (type == WLFC_CTL_TYPE_MAC_CLOSE)) + _dhd_wlfc_psmode_update(dhd, value, type); + + else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || + (type == WLFC_CTL_TYPE_MACDESC_DEL)) + _dhd_wlfc_mac_table_update(dhd, value, type); + + else if (type == WLFC_CTL_TYPE_TRANS_ID) + _dhd_wlfc_dbg_senum_check(dhd, value); + + else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || + (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { + _dhd_wlfc_interface_update(dhd, value, type); + } + + if (entry && WLFC_GET_REORDERSUPP(dhd->wlfc_mode)) { + /* suppress all packets for this mac entry from bus->txq */ + _dhd_wlfc_suppress_txq(dhd, _dhd_wlfc_entrypkt_fn, entry); + } + } + if (remainder != 0 && wlfc) { + /* trouble..., something is not right */ + wlfc->stats.tlv_parse_failed++; + } + } + + if (wlfc) + wlfc->stats.dhd_hdrpulls++; + + dhd_os_wlfc_unblock(dhd); + return BCME_OK; +} + +int +dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf, + bool need_toggle_host_if) +{ + int ac, single_ac = 0, rc = BCME_OK; + dhd_wlfc_commit_info_t commit_info; + athost_wl_status_info_t* ctx; + int bus_retry_count = 0; + + uint8 tx_map = 0; /* packets (send + in queue), Bitmask for 4 ACs + BC/MC */ + uint8 rx_map = 0; /* received packets, Bitmask for 4 ACs + BC/MC */ + uint8 packets_map = 0; /* packets in queue, Bitmask for 4 ACs + BC/MC */ + bool no_credit = FALSE; + +#ifdef LIMIT_BORROW + int lender; +#endif + + if ((dhdp == NULL) || (fcommit == NULL)) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + if (pktbuf) { + DHD_PKTTAG_WLFCPKT_SET(PKTTAG(pktbuf), 0); + } + rc = WLFC_UNSUPPORTED; + goto exit2; + } + + ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; + + + if (dhdp->proptxstatus_module_ignore) { + if (pktbuf) { + uint32 htod = 0; + WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); + _dhd_wlfc_pushheader(ctx, pktbuf, FALSE, 0, 0, htod, 0, FALSE); + if (fcommit(commit_ctx, pktbuf)) + PKTFREE(ctx->osh, pktbuf, TRUE); + rc = BCME_OK; + } + goto exit; + } + + memset(&commit_info, 0, sizeof(commit_info)); + + /* + Commit packets for regular AC traffic. Higher priority first. + First, use up FIFO credits available to each AC. Based on distribution + and credits left, borrow from other ACs as applicable + + -NOTE: + If the bus between the host and firmware is overwhelmed by the + traffic from host, it is possible that higher priority traffic + starves the lower priority queue. If that occurs often, we may + have to employ weighted round-robin or ucode scheme to avoid + low priority packet starvation. + */ + + if (pktbuf) { + ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + /* en-queue the packets to respective queue. */ + rc = _dhd_wlfc_enque_delayq(ctx, pktbuf, ac); + if (rc) + _dhd_wlfc_prec_drop(ctx->dhdp, (ac << 1), pktbuf, FALSE); + else + ctx->stats.pktin++; + } + + for (ac = AC_COUNT; ac >= 0; ac--) { + if (dhdp->wlfc_rxpkt_chk) { + /* check rx packet */ + uint32 curr_t = OSL_SYSUPTIME(), delta; + + delta = curr_t - ctx->rx_timestamp[ac]; + if (delta < WLFC_RX_DETECTION_THRESHOLD_MS) { + rx_map |= (1 << ac); + } + } + + if (ctx->pkt_cnt_per_ac[ac] == 0) { + continue; + } + tx_map |= (1 << ac); + single_ac = ac + 1; + while (FALSE == dhdp->proptxstatus_txoff) { + /* packets from delayQ with less priority are fresh and + * they'd need header and have no MAC entry + */ + no_credit = (ctx->FIFO_credit[ac] < 1); + if (dhdp->proptxstatus_credit_ignore || + ((ac == AC_COUNT) && !ctx->bcmc_credit_supported)) { + no_credit = FALSE; + } + commit_info.needs_hdr = 1; + commit_info.mac_entry = NULL; + commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, + &(commit_info.ac_fifo_credit_spent), + &(commit_info.needs_hdr), + &(commit_info.mac_entry), + no_credit); + commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : + eWLFC_PKTTYPE_SUPPRESSED; + + if (commit_info.p == NULL) { + break; + } + + if (!dhdp->proptxstatus_credit_ignore) { + ASSERT(ctx->FIFO_credit[ac] >= commit_info.ac_fifo_credit_spent); + } + /* here we can ensure have credit or no credit needed */ + rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, fcommit, + commit_ctx); + + /* Bus commits may fail (e.g. flow control); abort after retries */ + if (rc == BCME_OK) { + if (commit_info.ac_fifo_credit_spent) + ctx->FIFO_credit[ac]--; + } else { + bus_retry_count++; + if (bus_retry_count >= BUS_RETRIES) { + DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); + goto exit; + } + } + } + + if (ctx->pkt_cnt_per_ac[ac]) { + packets_map |= (1 << ac); + } + } + + if ((tx_map == 0) || dhdp->proptxstatus_credit_ignore) { + /* nothing send out or remain in queue */ + rc = BCME_OK; + goto exit; + } + + if (((tx_map & (tx_map - 1)) == 0) && (tx_map >= rx_map)) { + /* only one tx ac exist and no higher rx ac */ + if ((single_ac == ctx->single_ac) && ctx->allow_credit_borrow) { + ac = single_ac - 1; + } else { + uint32 delta; + uint32 curr_t = OSL_SYSUPTIME(); + + if (single_ac != ctx->single_ac) { + /* new single ac traffic (first single ac or different single ac) */ + ctx->allow_credit_borrow = 0; + ctx->single_ac_timestamp = curr_t; + ctx->single_ac = (uint8)single_ac; + rc = BCME_OK; + goto exit; + } + /* same ac traffic, check if it lasts enough time */ + delta = curr_t - ctx->single_ac_timestamp; + + if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { + /* wait enough time, can borrow now */ + ctx->allow_credit_borrow = 1; + ac = single_ac - 1; + } else { + rc = BCME_OK; + goto exit; + } + } + } else { + /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ + ctx->allow_credit_borrow = 0; + ctx->single_ac_timestamp = 0; + ctx->single_ac = 0; + rc = BCME_OK; + goto exit; + } + + if (packets_map == 0) { + /* nothing to send, skip borrow */ + rc = BCME_OK; + goto exit; + } + + /* At this point, borrow all credits only for ac */ + while (FALSE == dhdp->proptxstatus_txoff) { +#ifdef LIMIT_BORROW + if ((lender = _dhd_wlfc_borrow_credit(ctx, AC_COUNT, ac)) == -1) { + break; + } +#endif + commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, + &(commit_info.ac_fifo_credit_spent), + &(commit_info.needs_hdr), + &(commit_info.mac_entry), + FALSE); + if (commit_info.p == NULL) { + /* before borrow only one ac exists and now this only ac is empty */ +#ifdef LIMIT_BORROW + _dhd_wlfc_return_credit(ctx, lender, ac); +#endif + break; + } + + commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : + eWLFC_PKTTYPE_SUPPRESSED; + + rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, + fcommit, commit_ctx); + + /* Bus commits may fail (e.g. flow control); abort after retries */ + if (rc == BCME_OK) { + + if (commit_info.ac_fifo_credit_spent) { +#ifndef LIMIT_BORROW + ctx->FIFO_credit[ac]--; +#endif + } else { +#ifdef LIMIT_BORROW + _dhd_wlfc_return_credit(ctx, lender, ac); +#endif + } + } else { +#ifdef LIMIT_BORROW + _dhd_wlfc_return_credit(ctx, lender, ac); +#endif + bus_retry_count++; + if (bus_retry_count >= BUS_RETRIES) { + DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); + goto exit; + } + } + } + +exit: + if (need_toggle_host_if && ctx->toggle_host_if) { + ctx->toggle_host_if = 0; + } + +exit2: + dhd_os_wlfc_unblock(dhdp); + return rc; +} + +int +dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) +{ + athost_wl_status_info_t* wlfc; + void* pout = NULL; + int rtn = BCME_OK; + if ((dhd == NULL) || (txp == NULL)) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + rtn = WLFC_UNSUPPORTED; + goto EXIT; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { +#ifdef PROP_TXSTATUS_DEBUG + wlfc->stats.signal_only_pkts_freed++; +#endif + /* is this a signal-only packet? */ + _dhd_wlfc_pullheader(wlfc, txp); + PKTFREE(wlfc->osh, txp, TRUE); + goto EXIT; + } + + if (!success || dhd->proptxstatus_txstatus_ignore) { + wlfc_mac_descriptor_t *entry = _dhd_wlfc_find_table_entry(wlfc, txp); + + WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", + __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + _dhd_wlfc_hanger_poppkt(wlfc->hanger, WL_TXSTATUS_GET_HSLOT( + DHD_PKTTAG_H2DTAG(PKTTAG(txp))), &pout, 1); + ASSERT(txp == pout); + } + + /* indicate failure and free the packet */ + dhd_txcomplete(dhd, txp, success); + + /* return the credit, if necessary */ + _dhd_wlfc_return_implied_credit(wlfc, txp); + + entry->transit_count--; + if (entry->suppressed && (--entry->suppr_transit_count == 0)) { + entry->suppressed = FALSE; + } + + PKTFREE(wlfc->osh, txp, TRUE); + wlfc->stats.pktout++; + } else { + /* bus confirmed pkt went to firmware side */ + if (WLFC_GET_AFQ(dhd->wlfc_mode)) { + _dhd_wlfc_enque_afq(wlfc, txp); + } else { + int ret; + void *pktbuf_tmp = NULL; + int hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(txp))); + if (_dhd_wlfc_hanger_waitevent_decreturn(wlfc->hanger, hslot) == 0) { + ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, hslot, &pktbuf_tmp, 1); + BCM_REFERENCE(ret); + ASSERT((ret == BCME_OK) && pktbuf_tmp && (txp == pktbuf_tmp)); + + /* free the packet */ + PKTFREE(wlfc->osh, txp, TRUE); + } + } + } + +EXIT: + dhd_os_wlfc_unblock(dhd); + return rtn; +} + +int +dhd_wlfc_init(dhd_pub_t *dhd) +{ + char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */ + /* enable all signals & indicate host proptxstatus logic is active */ + uint32 tlv, mode, fw_caps; + int ret = 0; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + if (dhd->wlfc_enabled) { + DHD_ERROR(("%s():%d, Already enabled!\n", __FUNCTION__, __LINE__)); + dhd_os_wlfc_unblock(dhd); + return BCME_OK; + } + dhd->wlfc_enabled = TRUE; + dhd_os_wlfc_unblock(dhd); + + tlv = WLFC_FLAGS_RSSI_SIGNALS | + WLFC_FLAGS_XONXOFF_SIGNALS | + WLFC_FLAGS_CREDIT_STATUS_SIGNALS | + WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | + WLFC_FLAGS_HOST_RXRERODER_ACTIVE; + + + /* + try to enable/disable signaling by sending "tlv" iovar. if that fails, + fallback to no flow control? Print a message for now. + */ + + /* enable proptxtstatus signaling by default */ + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); + } + else { + /* + Leaving the message for now, it should be removed after a while; once + the tlv situation is stable. + */ + DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", + dhd->wlfc_enabled?"enabled":"disabled", tlv)); + } + + /* query caps */ + ret = dhd_iovar(dhd, 0, "wlfc_mode", (char *)&mode, sizeof(mode), + iovbuf, sizeof(iovbuf), FALSE); + if (ret >= 0) { + fw_caps = *((uint32 *)iovbuf); + mode = 0; + DHD_ERROR(("%s: query wlfc_mode succeed, fw_caps=0x%x\n", __FUNCTION__, fw_caps)); + + if (WLFC_IS_OLD_DEF(fw_caps)) { + /* enable proptxtstatus v2 by default */ + mode = WLFC_MODE_AFQ; + } else { + WLFC_SET_AFQ(mode, WLFC_GET_AFQ(fw_caps)); + WLFC_SET_REUSESEQ(mode, WLFC_GET_REUSESEQ(fw_caps)); + WLFC_SET_REORDERSUPP(mode, WLFC_GET_REORDERSUPP(fw_caps)); + } + dhd_iovar(dhd, 0, "wlfc_mode", (char *)&mode, sizeof(mode), NULL, 0, TRUE); + } + + dhd_os_wlfc_block(dhd); + + dhd->wlfc_mode = 0; + if (ret >= 0) { + if (WLFC_IS_OLD_DEF(mode)) { + WLFC_SET_AFQ(dhd->wlfc_mode, (mode == WLFC_MODE_AFQ)); + } else { + dhd->wlfc_mode = mode; + } + } + DHD_ERROR(("dhd_wlfc_init(): wlfc_mode=0x%x, ret=%d\n", dhd->wlfc_mode, ret)); + + dhd_os_wlfc_unblock(dhd); + + if (dhd->plat_init) + dhd->plat_init((void *)dhd); + + return BCME_OK; +} + +int +dhd_wlfc_hostreorder_init(dhd_pub_t *dhd) +{ + /* enable only ampdu hostreorder here */ + uint32 tlv; + int ret; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + DHD_TRACE(("%s():%d Enter\n", __FUNCTION__, __LINE__)); + + tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; + + /* enable proptxtstatus signaling by default */ + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s(): failed to enable/disable bdcv2 tlv signaling\n", + __FUNCTION__)); + } + else { + /* + Leaving the message for now, it should be removed after a while; once + the tlv situation is stable. + */ + DHD_ERROR(("%s(): successful bdcv2 tlv signaling, %d\n", + __FUNCTION__, tlv)); + } + + dhd_os_wlfc_block(dhd); + dhd->proptxstatus_mode = WLFC_ONLY_AMPDU_HOSTREORDER; + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +#ifdef SUPPORT_P2P_GO_PS +int +dhd_wlfc_suspend(dhd_pub_t *dhd) +{ + + uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ + uint32 tlv = 0; + int ret; + + DHD_TRACE(("%s: masking wlfc events\n", __FUNCTION__)); + if (!dhd->wlfc_enabled) + return -1; + + ret = dhd_iovar(dhd, 0, "tlv", NULL, 0, + (char *)iovbuf, sizeof(iovbuf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); + return -1; + } + tlv = iovbuf[0]; + if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == 0) + return 0; + tlv &= ~(WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); + + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", + __FUNCTION__, tlv)); + return -1; + } + + return 0; +} + + int +dhd_wlfc_resume(dhd_pub_t *dhd) +{ + uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ + uint32 tlv = 0; + int ret; + + DHD_TRACE(("%s: unmasking wlfc events\n", __FUNCTION__)); + if (!dhd->wlfc_enabled) + return -1; + + ret = dhd_iovar(dhd, 0, "tlv", NULL, 0, + (char *)iovbuf, sizeof(iovbuf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); + return -1; + } + tlv = iovbuf[0]; + if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == + (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) + return 0; + tlv |= (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", + __FUNCTION__, tlv)); + return -1; + } + + return 0; +} +#endif /* SUPPORT_P2P_GO_PS */ + +int +dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + _dhd_wlfc_cleanup_txq(dhd, fn, arg); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +/* release all packet resources */ +int +dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) +{ + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + _dhd_wlfc_cleanup(dhd, fn, arg); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int +dhd_wlfc_deinit(dhd_pub_t *dhd) +{ + char iovbuf[32]; /* Room for "ampdu_hostreorder" or "tlv" + '\0' + parameter */ + /* cleanup all psq related resources */ + athost_wl_status_info_t* wlfc; + uint32 tlv = 0; + uint32 hostreorder = 0; + int ret = BCME_OK; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + if (!dhd->wlfc_enabled) { + DHD_ERROR(("%s():%d, Already disabled!\n", __FUNCTION__, __LINE__)); + dhd_os_wlfc_unblock(dhd); + return BCME_OK; + } + dhd->wlfc_enabled = FALSE; + dhd_os_wlfc_unblock(dhd); + + /* query ampdu hostreorder */ + ret = dhd_iovar(dhd, 0, "ampdu_hostreorder", NULL, 0, + (char *)iovbuf, sizeof(iovbuf), FALSE); + if (ret == BCME_OK) + hostreorder = *((uint32 *)iovbuf); + else { + hostreorder = 0; + DHD_ERROR(("%s():%d, ampdu_hostreorder get failed Err = %d\n", + __FUNCTION__, __LINE__, ret)); + } + + if (hostreorder) { + tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; + DHD_ERROR(("%s():%d, maintain HOST RXRERODER flag in tvl\n", + __FUNCTION__, __LINE__)); + } + + /* Disable proptxtstatus signaling for deinit */ + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret == BCME_OK) { + /* + Leaving the message for now, it should be removed after a while; once + the tlv situation is stable. + */ + DHD_ERROR(("%s():%d successfully %s bdcv2 tlv signaling, %d\n", + __FUNCTION__, __LINE__, + dhd->wlfc_enabled?"enabled":"disabled", tlv)); + } else + DHD_ERROR(("%s():%d failed to enable/disable bdcv2 tlv signaling Err = %d\n", + __FUNCTION__, __LINE__, ret)); + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + +#ifdef PROP_TXSTATUS_DEBUG + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) + { + int i; + wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; + for (i = 0; i < h->max_items; i++) { + if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { + WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", + __FUNCTION__, i, h->items[i].pkt, + DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); + } + } + } +#endif + + _dhd_wlfc_cleanup(dhd, NULL, NULL); + + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + /* delete hanger */ + _dhd_wlfc_hanger_delete(dhd, wlfc->hanger); + } + + + /* free top structure */ + DHD_OS_PREFREE(dhd, dhd->wlfc_state, + sizeof(athost_wl_status_info_t)); + dhd->wlfc_state = NULL; + dhd->proptxstatus_mode = hostreorder ? + WLFC_ONLY_AMPDU_HOSTREORDER : WLFC_FCMODE_NONE; + + dhd_os_wlfc_unblock(dhd); + + if (dhd->plat_deinit) + dhd->plat_deinit((void *)dhd); + return BCME_OK; +} + +int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea) +{ + int rc; + + if (dhdp == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhdp); + return WLFC_UNSUPPORTED; + } + + rc = _dhd_wlfc_interface_entry_update(dhdp->wlfc_state, action, ifid, iftype, ea); + + dhd_os_wlfc_unblock(dhdp); + return rc; +} + +int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data) +{ + int rc; + + if (dhdp == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhdp); + return WLFC_UNSUPPORTED; + } + + rc = _dhd_wlfc_FIFOcreditmap_update(dhdp->wlfc_state, event_data); + + dhd_os_wlfc_unblock(dhdp); + + return rc; +} + +int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp) +{ + int rc; + + if (dhdp == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhdp); + return WLFC_UNSUPPORTED; + } + + rc = _dhd_wlfc_BCMCCredit_support_update(dhdp->wlfc_state); + + dhd_os_wlfc_unblock(dhdp); + return rc; +} + +int +dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + int i; + uint8* ea; + athost_wl_status_info_t* wlfc; + wlfc_hanger_t* h; + wlfc_mac_descriptor_t* mac_table; + wlfc_mac_descriptor_t* interfaces; + char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; + + if (!dhdp || !strbuf) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhdp); + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhdp); + return WLFC_UNSUPPORTED; + } + + wlfc = (athost_wl_status_info_t*)dhdp->wlfc_state; + + h = (wlfc_hanger_t*)wlfc->hanger; + if (h == NULL) { + bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); + } + + mac_table = wlfc->destination_entries.nodes; + interfaces = wlfc->destination_entries.interfaces; + bcm_bprintf(strbuf, "---- wlfc stats ----\n"); + + if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { + h = (wlfc_hanger_t*)wlfc->hanger; + if (h == NULL) { + bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); + } else { + bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," + "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", + h->pushed, + h->popped, + h->failed_to_push, + h->failed_to_pop, + h->failed_slotfind, + (h->pushed - h->popped)); + } + } + + bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " + "(dq_full,rollback_fail) = (%d,%d,%d,%d), (%d,%d)\n", + wlfc->stats.tlv_parse_failed, + wlfc->stats.credit_request_failed, + wlfc->stats.mac_update_failed, + wlfc->stats.psmode_update_failed, + wlfc->stats.delayq_full_error, + wlfc->stats.rollback_failed); + + bcm_bprintf(strbuf, "PKTS (init_credit,credit,sent,drop_d,drop_s,outoforder) " + "(AC0[%d,%d,%d,%d,%d,%d],AC1[%d,%d,%d,%d,%d,%d],AC2[%d,%d,%d,%d,%d,%d]," + "AC3[%d,%d,%d,%d,%d,%d],BC_MC[%d,%d,%d,%d,%d,%d])\n", + wlfc->Init_FIFO_credit[0], wlfc->FIFO_credit[0], wlfc->stats.send_pkts[0], + wlfc->stats.drop_pkts[0], wlfc->stats.drop_pkts[1], wlfc->stats.ooo_pkts[0], + wlfc->Init_FIFO_credit[1], wlfc->FIFO_credit[1], wlfc->stats.send_pkts[1], + wlfc->stats.drop_pkts[2], wlfc->stats.drop_pkts[3], wlfc->stats.ooo_pkts[1], + wlfc->Init_FIFO_credit[2], wlfc->FIFO_credit[2], wlfc->stats.send_pkts[2], + wlfc->stats.drop_pkts[4], wlfc->stats.drop_pkts[5], wlfc->stats.ooo_pkts[2], + wlfc->Init_FIFO_credit[3], wlfc->FIFO_credit[3], wlfc->stats.send_pkts[3], + wlfc->stats.drop_pkts[6], wlfc->stats.drop_pkts[7], wlfc->stats.ooo_pkts[3], + wlfc->Init_FIFO_credit[4], wlfc->FIFO_credit[4], wlfc->stats.send_pkts[4], + wlfc->stats.drop_pkts[8], wlfc->stats.drop_pkts[9], wlfc->stats.ooo_pkts[4]); + + bcm_bprintf(strbuf, "\n"); + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (interfaces[i].occupied) { + char* iftype_desc; + + if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) + iftype_desc = "hostif_flow_state[i] == OFF) + ? " OFF":" ON")); + + bcm_bprintf(strbuf, "INTERFACE[%d].PSQ(len,state,credit),(trans,supp_trans)" + "= (%d,%s,%d),(%d,%d)\n", + i, + interfaces[i].psq.len, + ((interfaces[i].state == + WLFC_STATE_OPEN) ? "OPEN":"CLOSE"), + interfaces[i].requested_credit, + interfaces[i].transit_count, interfaces[i].suppr_transit_count); + + bcm_bprintf(strbuf, "INTERFACE[%d].PSQ" + "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," + "(delay3,sup3,afq3),(delay4,sup4,afq4) = (%d,%d,%d)," + "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", + i, + interfaces[i].psq.q[0].len, + interfaces[i].psq.q[1].len, + interfaces[i].afq.q[0].len, + interfaces[i].psq.q[2].len, + interfaces[i].psq.q[3].len, + interfaces[i].afq.q[1].len, + interfaces[i].psq.q[4].len, + interfaces[i].psq.q[5].len, + interfaces[i].afq.q[2].len, + interfaces[i].psq.q[6].len, + interfaces[i].psq.q[7].len, + interfaces[i].afq.q[3].len, + interfaces[i].psq.q[8].len, + interfaces[i].psq.q[9].len, + interfaces[i].afq.q[4].len); + } + } + + bcm_bprintf(strbuf, "\n"); + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (mac_table[i].occupied) { + ea = mac_table[i].ea; + bcm_bprintf(strbuf, "MAC_table[%d].ea = " + "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], + mac_table[i].interface_id); + + bcm_bprintf(strbuf, "MAC_table[%d].PSQ(len,state,credit),(trans,supp_trans)" + "= (%d,%s,%d),(%d,%d)\n", + i, + mac_table[i].psq.len, + ((mac_table[i].state == + WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), + mac_table[i].requested_credit, + mac_table[i].transit_count, mac_table[i].suppr_transit_count); +#ifdef PROP_TXSTATUS_DEBUG + bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", + i, mac_table[i].opened_ct, mac_table[i].closed_ct); +#endif + bcm_bprintf(strbuf, "MAC_table[%d].PSQ" + "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," + "(delay3,sup3,afq3),(delay4,sup4,afq4) =(%d,%d,%d)," + "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", + i, + mac_table[i].psq.q[0].len, + mac_table[i].psq.q[1].len, + mac_table[i].afq.q[0].len, + mac_table[i].psq.q[2].len, + mac_table[i].psq.q[3].len, + mac_table[i].afq.q[1].len, + mac_table[i].psq.q[4].len, + mac_table[i].psq.q[5].len, + mac_table[i].afq.q[2].len, + mac_table[i].psq.q[6].len, + mac_table[i].psq.q[7].len, + mac_table[i].afq.q[3].len, + mac_table[i].psq.q[8].len, + mac_table[i].psq.q[9].len, + mac_table[i].afq.q[4].len); + + } + } + +#ifdef PROP_TXSTATUS_DEBUG + { + int avg; + int moving_avg = 0; + int moving_samples; + + if (wlfc->stats.latency_sample_count) { + moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); + + for (i = 0; i < moving_samples; i++) + moving_avg += wlfc->stats.deltas[i]; + moving_avg /= moving_samples; + + avg = (100 * wlfc->stats.total_status_latency) / + wlfc->stats.latency_sample_count; + bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " + "(%d.%d, %03d, %03d)\n", + moving_samples, avg/100, (avg - (avg/100)*100), + wlfc->stats.latency_most_recent, + moving_avg); + } + } + + bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " + "back = (%d,%d,%d,%d,%d,%d)\n", + wlfc->stats.fifo_credits_sent[0], + wlfc->stats.fifo_credits_sent[1], + wlfc->stats.fifo_credits_sent[2], + wlfc->stats.fifo_credits_sent[3], + wlfc->stats.fifo_credits_sent[4], + wlfc->stats.fifo_credits_sent[5], + + wlfc->stats.fifo_credits_back[0], + wlfc->stats.fifo_credits_back[1], + wlfc->stats.fifo_credits_back[2], + wlfc->stats.fifo_credits_back[3], + wlfc->stats.fifo_credits_back[4], + wlfc->stats.fifo_credits_back[5]); + { + uint32 fifo_cr_sent = 0; + uint32 fifo_cr_acked = 0; + uint32 request_cr_sent = 0; + uint32 request_cr_ack = 0; + uint32 bc_mc_cr_ack = 0; + + for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { + fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; + } + + for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { + fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; + } + + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (wlfc->destination_entries.nodes[i].occupied) { + request_cr_sent += + wlfc->destination_entries.nodes[i].dstncredit_sent_packets; + } + } + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (wlfc->destination_entries.interfaces[i].occupied) { + request_cr_sent += + wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; + } + } + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (wlfc->destination_entries.nodes[i].occupied) { + request_cr_ack += + wlfc->destination_entries.nodes[i].dstncredit_acks; + } + } + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (wlfc->destination_entries.interfaces[i].occupied) { + request_cr_ack += + wlfc->destination_entries.interfaces[i].dstncredit_acks; + } + } + bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," + "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", + fifo_cr_sent, fifo_cr_acked, + request_cr_sent, request_cr_ack, + wlfc->destination_entries.other.dstncredit_acks, + bc_mc_cr_ack, + wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); + } +#endif /* PROP_TXSTATUS_DEBUG */ + bcm_bprintf(strbuf, "\n"); + bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull,out),(dropped,hdr_only,wlc_tossed)" + "(freed,free_err,rollback)) = " + "((%d,%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", + wlfc->stats.pktin, + wlfc->stats.pkt2bus, + wlfc->stats.txstatus_in, + wlfc->stats.dhd_hdrpulls, + wlfc->stats.pktout, + + wlfc->stats.pktdropped, + wlfc->stats.wlfc_header_only_pkt, + wlfc->stats.wlc_tossed_pkts, + + wlfc->stats.pkt_freed, + wlfc->stats.pkt_free_err, wlfc->stats.rollback); + + bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " + "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", + wlfc->stats.d11_suppress, + wlfc->stats.wl_suppress, + wlfc->stats.bad_suppress, + + wlfc->stats.psq_d11sup_enq, + wlfc->stats.psq_wlsup_enq, + wlfc->stats.psq_hostq_enq, + wlfc->stats.mac_handle_notfound, + + wlfc->stats.psq_d11sup_retx, + wlfc->stats.psq_wlsup_retx, + wlfc->stats.psq_hostq_retx); + + bcm_bprintf(strbuf, "wlfc- cleanup(txq,psq,fw) = (%d,%d,%d)\n", + wlfc->stats.cleanup_txq_cnt, + wlfc->stats.cleanup_psq_cnt, + wlfc->stats.cleanup_fw_cnt); + + bcm_bprintf(strbuf, "wlfc- generic error: %d\n", wlfc->stats.generic_error); + + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + bcm_bprintf(strbuf, "wlfc- if[%d], pkt_cnt_in_q/AC[0-4] = (%d,%d,%d,%d,%d)\n", i, + wlfc->pkt_cnt_in_q[i][0], + wlfc->pkt_cnt_in_q[i][1], + wlfc->pkt_cnt_in_q[i][2], + wlfc->pkt_cnt_in_q[i][3], + wlfc->pkt_cnt_in_q[i][4]); + } + bcm_bprintf(strbuf, "\n"); + + dhd_os_wlfc_unblock(dhdp); + return BCME_OK; +} + +int dhd_wlfc_clear_counts(dhd_pub_t *dhd) +{ + athost_wl_status_info_t* wlfc; + wlfc_hanger_t* hanger; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + + memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); + + if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { + hanger = (wlfc_hanger_t*)wlfc->hanger; + + hanger->pushed = 0; + hanger->popped = 0; + hanger->failed_slotfind = 0; + hanger->failed_to_pop = 0; + hanger->failed_to_push = 0; + } + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->wlfc_enabled; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->wlfc_state ? dhd->proptxstatus_mode : 0; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val) +{ + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (dhd->wlfc_state) { + dhd->proptxstatus_mode = val & 0xff; + } + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf) +{ + athost_wl_status_info_t* wlfc; + bool rc = FALSE; + + if (dhd == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return FALSE; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return FALSE; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + + if (PKTLEN(wlfc->osh, pktbuf) == 0) { + wlfc->stats.wlfc_header_only_pkt++; + rc = TRUE; + } + + dhd_os_wlfc_unblock(dhd); + + return rc; +} + +int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock) +{ + if (dhdp == NULL) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + if (bAcquireLock) { + dhd_os_wlfc_block(dhdp); + } + + if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE) || + dhdp->proptxstatus_module_ignore) { + if (bAcquireLock) { + dhd_os_wlfc_unblock(dhdp); + } + return WLFC_UNSUPPORTED; + } + + if (state != dhdp->proptxstatus_txoff) { + dhdp->proptxstatus_txoff = state; + } + + if (bAcquireLock) { + dhd_os_wlfc_unblock(dhdp); + } + + return BCME_OK; +} + +int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio) +{ + athost_wl_status_info_t* wlfc; + int rx_path_ac = -1; + + if ((dhd == NULL) || (prio >= NUMPRIO)) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if (!dhd->wlfc_rxpkt_chk) { + dhd_os_wlfc_unblock(dhd); + return BCME_OK; + } + + if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { + dhd_os_wlfc_unblock(dhd); + return WLFC_UNSUPPORTED; + } + + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + + rx_path_ac = prio2fifo[prio]; + wlfc->rx_timestamp[rx_path_ac] = OSL_SYSUPTIME(); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->proptxstatus_module_ignore; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val) +{ + uint32 tlv = 0; + bool bChanged = FALSE; + int ret; + + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + if ((bool)val != dhd->proptxstatus_module_ignore) { + dhd->proptxstatus_module_ignore = (val != 0); + /* force txstatus_ignore sync with proptxstatus_module_ignore */ + dhd->proptxstatus_txstatus_ignore = dhd->proptxstatus_module_ignore; + if (FALSE == dhd->proptxstatus_module_ignore) { + tlv = WLFC_FLAGS_RSSI_SIGNALS | + WLFC_FLAGS_XONXOFF_SIGNALS | + WLFC_FLAGS_CREDIT_STATUS_SIGNALS | + WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE; + } + /* always enable host reorder */ + tlv |= WLFC_FLAGS_HOST_RXRERODER_ACTIVE; + bChanged = TRUE; + } + + dhd_os_wlfc_unblock(dhd); + + if (bChanged) { + /* select enable proptxtstatus signaling */ + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", + __FUNCTION__, tlv)); + } + else { + DHD_ERROR(("%s: successfully set bdcv2 tlv signaling to 0x%x\n", + __FUNCTION__, tlv)); + } + } + return BCME_OK; +} + +int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->proptxstatus_credit_ignore; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val) +{ + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + dhd->proptxstatus_credit_ignore = (val != 0); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->proptxstatus_txstatus_ignore; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val) +{ + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + dhd->proptxstatus_txstatus_ignore = (val != 0); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val) +{ + if (!dhd || !val) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + *val = dhd->wlfc_rxpkt_chk; + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} + +int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val) +{ + if (!dhd) { + DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + dhd_os_wlfc_block(dhd); + + dhd->wlfc_rxpkt_chk = (val != 0); + + dhd_os_wlfc_unblock(dhd); + + return BCME_OK; +} +#endif /* PROP_TXSTATUS */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h new file mode 100644 index 000000000000..ee5d00489bd5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h @@ -0,0 +1,513 @@ +/* +* Copyright (C) 1999-2017, Broadcom Corporation +* +* Unless you and Broadcom execute a separate written software license +* agreement governing use of this software, this software is licensed to you +* under the terms of the GNU General Public License version 2 (the "GPL"), +* available at http://www.broadcom.com/licenses/GPLv2.php, with the +* following added to such license: +* +* As a special exception, the copyright holders of this software give you +* permission to link this software with independent modules, and to copy and +* distribute the resulting executable under terms of your choice, provided that +* you also meet, for each linked independent module, the terms and conditions of +* the license of that module. An independent module is a module which is not +* derived from this software. The special exception does not apply to any +* modifications of the software. +* +* Notwithstanding the above, under no circumstances may you combine this +* software in any way with any other Broadcom software provided under a license +* other than the GPL, without Broadcom's express prior written consent. +* $Id: dhd_wlfc.h 485659 2014-06-16 21:33:12Z $ +* +*/ +#ifndef __wlfc_host_driver_definitions_h__ +#define __wlfc_host_driver_definitions_h__ + + +/* #define OOO_DEBUG */ + +#define WLFC_UNSUPPORTED -9999 + +#define WLFC_NO_TRAFFIC -1 +#define WLFC_MULTI_TRAFFIC 0 + +#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ + +/* 16 bits will provide an absolute max of 65536 slots */ +#define WLFC_HANGER_MAXITEMS 3072 + +#define WLFC_HANGER_ITEM_STATE_FREE 1 +#define WLFC_HANGER_ITEM_STATE_INUSE 2 +#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 +#define WLFC_HANGER_ITEM_STATE_WAIT_CLEAN 4 + +#define WLFC_HANGER_ITEM_WAIT_EVENT_COUNT 2 +#define WLFC_HANGER_ITEM_WAIT_EVENT_INVALID 255 + +typedef enum { + Q_TYPE_PSQ, + Q_TYPE_AFQ +} q_type_t; + +typedef enum ewlfc_packet_state { + eWLFC_PKTTYPE_NEW, + eWLFC_PKTTYPE_DELAYED, + eWLFC_PKTTYPE_SUPPRESSED, + eWLFC_PKTTYPE_MAX +} ewlfc_packet_state_t; + +typedef enum ewlfc_mac_entry_action { + eWLFC_MAC_ENTRY_ACTION_ADD, + eWLFC_MAC_ENTRY_ACTION_DEL, + eWLFC_MAC_ENTRY_ACTION_UPDATE, + eWLFC_MAC_ENTRY_ACTION_MAX +} ewlfc_mac_entry_action_t; + +typedef struct wlfc_hanger_item { + uint8 state; + uint8 gen; + uint8 waitevent; /* wait txstatus_update and txcomplete before free a packet */ + uint8 pad; + uint32 identifier; + void* pkt; +#ifdef PROP_TXSTATUS_DEBUG + uint32 push_time; +#endif + struct wlfc_hanger_item *next; +} wlfc_hanger_item_t; + +typedef struct wlfc_hanger { + int max_items; + uint32 pushed; + uint32 popped; + uint32 failed_to_push; + uint32 failed_to_pop; + uint32 failed_slotfind; + uint32 slot_pos; + wlfc_hanger_item_t items[1]; +} wlfc_hanger_t; + +#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ + sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) + +#define WLFC_STATE_OPEN 1 +#define WLFC_STATE_CLOSE 2 + +#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ +#define WLFC_AFQ_PREC_COUNT (AC_COUNT + 1) + +#define WLFC_PSQ_LEN 2048 + +#define WLFC_FLOWCONTROL_HIWATER (2048 - 256) +#define WLFC_FLOWCONTROL_LOWATER 256 + +#define WLFC_LOG_BUF_SIZE (1024*1024) + +typedef struct wlfc_mac_descriptor { + uint8 occupied; + uint8 interface_id; + uint8 iftype; + uint8 state; + uint8 ac_bitmap; /* for APSD */ + uint8 requested_credit; + uint8 requested_packet; + uint8 ea[ETHER_ADDR_LEN]; + /* + maintain (MAC,AC) based seq count for + packets going to the device. As well as bc/mc. + */ + uint8 seq[AC_COUNT + 1]; + uint8 generation; + struct pktq psq; + /* packets at firmware */ + struct pktq afq; + /* The AC pending bitmap that was reported to the fw at last change */ + uint8 traffic_lastreported_bmp; + /* The new AC pending bitmap */ + uint8 traffic_pending_bmp; + /* 1= send on next opportunity */ + uint8 send_tim_signal; + uint8 mac_handle; + /* Number of packets at dongle for this entry. */ + uint transit_count; + /* Numbe of suppression to wait before evict from delayQ */ + uint suppr_transit_count; + /* flag. TRUE when in suppress state */ + uint8 suppressed; + + +#ifdef PROP_TXSTATUS_DEBUG + uint32 dstncredit_sent_packets; + uint32 dstncredit_acks; + uint32 opened_ct; + uint32 closed_ct; +#endif + struct wlfc_mac_descriptor* prev; + struct wlfc_mac_descriptor* next; +} wlfc_mac_descriptor_t; + +typedef struct dhd_wlfc_commit_info { + uint8 needs_hdr; + uint8 ac_fifo_credit_spent; + ewlfc_packet_state_t pkt_type; + wlfc_mac_descriptor_t* mac_entry; + void* p; +} dhd_wlfc_commit_info_t; + +#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ + entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) + +#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ +#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] + +typedef struct athost_wl_stat_counters { + uint32 pktin; + uint32 pktout; + uint32 pkt2bus; + uint32 pktdropped; + uint32 tlv_parse_failed; + uint32 rollback; + uint32 rollback_failed; + uint32 delayq_full_error; + uint32 credit_request_failed; + uint32 packet_request_failed; + uint32 mac_update_failed; + uint32 psmode_update_failed; + uint32 interface_update_failed; + uint32 wlfc_header_only_pkt; + uint32 txstatus_in; + uint32 d11_suppress; + uint32 wl_suppress; + uint32 bad_suppress; + uint32 pkt_freed; + uint32 pkt_free_err; + uint32 psq_wlsup_retx; + uint32 psq_wlsup_enq; + uint32 psq_d11sup_retx; + uint32 psq_d11sup_enq; + uint32 psq_hostq_retx; + uint32 psq_hostq_enq; + uint32 mac_handle_notfound; + uint32 wlc_tossed_pkts; + uint32 dhd_hdrpulls; + uint32 generic_error; + /* an extra one for bc/mc traffic */ + uint32 send_pkts[AC_COUNT + 1]; + uint32 drop_pkts[WLFC_PSQ_PREC_COUNT]; + uint32 ooo_pkts[AC_COUNT + 1]; +#ifdef PROP_TXSTATUS_DEBUG + /* all pkt2bus -> txstatus latency accumulated */ + uint32 latency_sample_count; + uint32 total_status_latency; + uint32 latency_most_recent; + int idx_delta; + uint32 deltas[10]; + uint32 fifo_credits_sent[6]; + uint32 fifo_credits_back[6]; + uint32 dropped_qfull[6]; + uint32 signal_only_pkts_sent; + uint32 signal_only_pkts_freed; +#endif + uint32 cleanup_txq_cnt; + uint32 cleanup_psq_cnt; + uint32 cleanup_fw_cnt; +} athost_wl_stat_counters_t; + +#ifdef PROP_TXSTATUS_DEBUG +#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ + (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) +#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ + (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) +#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ + (ctx)->stats.dropped_qfull[(ac)]++;} while (0) +#else +#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) +#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) +#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) +#endif + +#define WLFC_FCMODE_NONE 0 +#define WLFC_FCMODE_IMPLIED_CREDIT 1 +#define WLFC_FCMODE_EXPLICIT_CREDIT 2 +#define WLFC_ONLY_AMPDU_HOSTREORDER 3 + +/* How long to defer borrowing in milliseconds */ +#define WLFC_BORROW_DEFER_PERIOD_MS 100 + +/* How long to defer flow control in milliseconds */ +#define WLFC_FC_DEFER_PERIOD_MS 200 + +/* How long to detect occurance per AC in miliseconds */ +#define WLFC_RX_DETECTION_THRESHOLD_MS 100 + +/* Mask to represent available ACs (note: BC/MC is ignored */ +#define WLFC_AC_MASK 0xF + +typedef struct athost_wl_status_info { + uint8 last_seqid_to_wlc; + + /* OSL handle */ + osl_t* osh; + /* dhd pub */ + void* dhdp; + + /* stats */ + athost_wl_stat_counters_t stats; + + int Init_FIFO_credit[AC_COUNT + 2]; + + /* the additional ones are for bc/mc and ATIM FIFO */ + int FIFO_credit[AC_COUNT + 2]; + + /* Credit borrow counts for each FIFO from each of the other FIFOs */ + int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; + + /* packet hanger and MAC->handle lookup table */ + void* hanger; + struct { + /* table for individual nodes */ + wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; + /* table for interfaces */ + wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; + /* OS may send packets to unknown (unassociated) destinations */ + /* A place holder for bc/mc and packets to unknown destinations */ + wlfc_mac_descriptor_t other; + } destination_entries; + + wlfc_mac_descriptor_t *active_entry_head; + int active_entry_count; + + wlfc_mac_descriptor_t* requested_entry[WLFC_MAC_DESC_TABLE_SIZE]; + int requested_entry_count; + + /* pkt counts for each interface and ac */ + int pkt_cnt_in_q[WLFC_MAX_IFNUM][AC_COUNT+1]; + int pkt_cnt_per_ac[AC_COUNT+1]; + uint8 allow_fc; + uint32 fc_defer_timestamp; + uint32 rx_timestamp[AC_COUNT+1]; + /* ON/OFF state for flow control to the host network interface */ + uint8 hostif_flow_state[WLFC_MAX_IFNUM]; + uint8 host_ifidx; + /* to flow control an OS interface */ + uint8 toggle_host_if; + + /* To borrow credits */ + uint8 allow_credit_borrow; + + /* ac number for the first single ac traffic */ + uint8 single_ac; + + /* Timestamp for the first single ac traffic */ + uint32 single_ac_timestamp; + + bool bcmc_credit_supported; + +} athost_wl_status_info_t; + +/* Please be mindful that total pkttag space is 32 octets only */ +typedef struct dhd_pkttag { + /* + b[15] - 1 = wlfc packet + b[14:13] - encryption exemption + b[12 ] - 1 = event channel + b[11 ] - 1 = this packet was sent in response to one time packet request, + do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. + b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] + b[9 ] - 1 = packet is host->firmware (transmit direction) + - 0 = packet received from firmware (firmware->host) + b[8 ] - 1 = packet was sent due to credit_request (pspoll), + packet does not count against FIFO credit. + - 0 = normal transaction, packet counts against FIFO credit + b[7 ] - 1 = AP, 0 = STA + b[6:4] - AC FIFO number + b[3:0] - interface index + */ + uint16 if_flags; + /* destination MAC address for this packet so that not every + module needs to open the packet to find this + */ + uint8 dstn_ether[ETHER_ADDR_LEN]; + /* + This 32-bit goes from host to device for every packet. + */ + uint32 htod_tag; + + /* + This 16-bit is original seq number for every suppress packet. + */ + uint16 htod_seq; + + /* + This address is mac entry for every packet. + */ + void* entry; + /* bus specific stuff */ + union { + struct { + void* stuff; + uint32 thing1; + uint32 thing2; + } sd; + struct { + void* bus; + void* urb; + } usb; + } bus_specific; +} dhd_pkttag_t; + +#define DHD_PKTTAG_WLFCPKT_MASK 0x1 +#define DHD_PKTTAG_WLFCPKT_SHIFT 15 +#define DHD_PKTTAG_WLFCPKT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_WLFCPKT_MASK << DHD_PKTTAG_WLFCPKT_SHIFT)) | \ + (((value) & DHD_PKTTAG_WLFCPKT_MASK) << DHD_PKTTAG_WLFCPKT_SHIFT) +#define DHD_PKTTAG_WLFCPKT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_WLFCPKT_SHIFT) & DHD_PKTTAG_WLFCPKT_MASK) + +#define DHD_PKTTAG_EXEMPT_MASK 0x3 +#define DHD_PKTTAG_EXEMPT_SHIFT 13 +#define DHD_PKTTAG_EXEMPT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_EXEMPT_MASK << DHD_PKTTAG_EXEMPT_SHIFT)) | \ + (((value) & DHD_PKTTAG_EXEMPT_MASK) << DHD_PKTTAG_EXEMPT_SHIFT) +#define DHD_PKTTAG_EXEMPT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_EXEMPT_SHIFT) & DHD_PKTTAG_EXEMPT_MASK) + +#define DHD_PKTTAG_EVENT_MASK 0x1 +#define DHD_PKTTAG_EVENT_SHIFT 12 +#define DHD_PKTTAG_SETEVENT(tag, event) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_EVENT_MASK << DHD_PKTTAG_EVENT_SHIFT)) | \ + (((event) & DHD_PKTTAG_EVENT_MASK) << DHD_PKTTAG_EVENT_SHIFT) +#define DHD_PKTTAG_EVENT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_EVENT_SHIFT) & DHD_PKTTAG_EVENT_MASK) + +#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 +#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 +#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ + (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) +#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) + +#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 +#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 +#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ + (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) +#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) + +#define DHD_PKTTAG_PKTDIR_MASK 0x1 +#define DHD_PKTTAG_PKTDIR_SHIFT 9 +#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ + (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) +#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) + +#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 +#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 +#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ + (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) +#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) + +#define DHD_PKTTAG_IFTYPE_MASK 0x1 +#define DHD_PKTTAG_IFTYPE_SHIFT 7 +#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ + (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) +#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) + +#define DHD_PKTTAG_FIFO_MASK 0x7 +#define DHD_PKTTAG_FIFO_SHIFT 4 +#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ + (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) +#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) + +#define DHD_PKTTAG_IF_MASK 0xf +#define DHD_PKTTAG_IF_SHIFT 0 +#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_IF_MASK << DHD_PKTTAG_IF_SHIFT)) | \ + (((if) & DHD_PKTTAG_IF_MASK) << DHD_PKTTAG_IF_SHIFT) +#define DHD_PKTTAG_IF(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_IF_SHIFT) & DHD_PKTTAG_IF_MASK) + +#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ + (dstn_MAC_ea), ETHER_ADDR_LEN) +#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether + +#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) +#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) + +#define DHD_PKTTAG_SET_H2DSEQ(tag, seq) ((dhd_pkttag_t*)(tag))->htod_seq = (seq) +#define DHD_PKTTAG_H2DSEQ(tag) (((dhd_pkttag_t*)(tag))->htod_seq) + +#define DHD_PKTTAG_SET_ENTRY(tag, entry) ((dhd_pkttag_t*)(tag))->entry = (entry) +#define DHD_PKTTAG_ENTRY(tag) (((dhd_pkttag_t*)(tag))->entry) + +#define PSQ_SUP_IDX(x) (x * 2 + 1) +#define PSQ_DLY_IDX(x) (x * 2) + +typedef int (*f_commitpkt_t)(void* ctx, void* p); +typedef bool (*f_processpkt_t)(void* p, void* arg); + +#ifdef PROP_TXSTATUS_DEBUG +#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) +#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) +#else +#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) +#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) +#endif + +/* public functions */ +int dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, + uchar *reorder_info_buf, uint *reorder_info_len); +int dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, + void* commit_ctx, void *pktbuf, bool need_toggle_host_if); +int dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); +int dhd_wlfc_init(dhd_pub_t *dhd); +int dhd_wlfc_hostreorder_init(dhd_pub_t *dhd); +#ifdef SUPPORT_P2P_GO_PS +int dhd_wlfc_suspend(dhd_pub_t *dhd); +int dhd_wlfc_resume(dhd_pub_t *dhd); +#endif /* SUPPORT_P2P_GO_PS */ +int dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg); +int dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void* arg); +int dhd_wlfc_deinit(dhd_pub_t *dhd); +int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea); +int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data); +int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp); +int dhd_wlfc_enable(dhd_pub_t *dhdp); +int dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +int dhd_wlfc_clear_counts(dhd_pub_t *dhd); +int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val); +int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val); +bool dhd_wlfc_is_supported(dhd_pub_t *dhd); +bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf); +int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock); +int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio); + +int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val); +int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val); +int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val); + +int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val); +int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val); +#endif /* __wlfc_host_driver_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h b/drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h new file mode 100644 index 000000000000..73024f1e4274 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h @@ -0,0 +1,309 @@ +/* + * Common stats definitions for clients of dongle + * ports + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dngl_stats.h 604675 2015-12-08 06:42:14Z $ + */ + +#ifndef _dngl_stats_h_ +#define _dngl_stats_h_ + +typedef struct { + 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 */ +} dngl_stats_t; + +#ifdef LINKSTAT_SUPPORT +typedef int wifi_radio; +typedef int wifi_channel; +typedef int wifi_rssi; + +typedef enum wifi_channel_width { + WIFI_CHAN_WIDTH_20 = 0, + WIFI_CHAN_WIDTH_40 = 1, + WIFI_CHAN_WIDTH_80 = 2, + WIFI_CHAN_WIDTH_160 = 3, + WIFI_CHAN_WIDTH_80P80 = 4, + WIFI_CHAN_WIDTH_5 = 5, + WIFI_CHAN_WIDTH_10 = 6, + WIFI_CHAN_WIDTH_INVALID = -1 +} wifi_channel_width_t; + +typedef enum { + WIFI_DISCONNECTED = 0, + WIFI_AUTHENTICATING = 1, + WIFI_ASSOCIATING = 2, + WIFI_ASSOCIATED = 3, + WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ + WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ +} wifi_connection_state; + +typedef enum { + WIFI_ROAMING_IDLE = 0, + WIFI_ROAMING_ACTIVE = 1 +} wifi_roam_state; + +typedef enum { + WIFI_INTERFACE_STA = 0, + WIFI_INTERFACE_SOFTAP = 1, + WIFI_INTERFACE_IBSS = 2, + WIFI_INTERFACE_P2P_CLIENT = 3, + WIFI_INTERFACE_P2P_GO = 4, + WIFI_INTERFACE_NAN = 5, + WIFI_INTERFACE_MESH = 6 +} wifi_interface_mode; + +/* set for QOS association */ +#define WIFI_CAPABILITY_QOS 0x00000001 +/* set for protected association (802.11 beacon frame control protected bit set) */ +#define WIFI_CAPABILITY_PROTECTED 0x00000002 +/* set if 802.11 Extended Capabilities element interworking bit is set */ +#define WIFI_CAPABILITY_INTERWORKING 0x00000004 +/* set for HS20 association */ +#define WIFI_CAPABILITY_HS20 0x00000008 +/* set is 802.11 Extended Capabilities element UTF-8 SSID bit is set */ +#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 +/* set is 802.11 Country Element is present */ +#define WIFI_CAPABILITY_COUNTRY 0x00000020 + +typedef struct { + wifi_interface_mode mode; /* interface mode */ + uint8 mac_addr[6]; /* interface mac address (self) */ + wifi_connection_state state; /* connection state (valid for STA, CLI only) */ + wifi_roam_state roaming; /* roaming state */ + uint32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ + uint8 ssid[33]; /* null terminated SSID */ + uint8 bssid[6]; /* bssid */ + uint8 ap_country_str[3]; /* country string advertised by AP */ + uint8 country_str[3]; /* country string for this association */ +} wifi_interface_info; + +typedef wifi_interface_info *wifi_interface_handle; + +/* channel information */ +typedef struct { + wifi_channel_width_t width; /* channel width (20, 40, 80, 80+80, 160) */ + wifi_channel center_freq; /* primary 20 MHz channel */ + wifi_channel center_freq0; /* center frequency (MHz) first segment */ + wifi_channel center_freq1; /* center frequency (MHz) second segment */ +} wifi_channel_info; + +/* wifi rate */ +typedef struct { + uint32 preamble :3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ + uint32 nss :2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ + uint32 bw :3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ + uint32 rateMcsIdx :8; /* OFDM/CCK rate code would be as per + * ieee std in the units of 0.5mbps + */ + /* HT/VHT it would be mcs index */ + uint32 reserved :16; /* reserved */ + uint32 bitrate; /* units of 100 Kbps */ +} wifi_rate; + +typedef struct { + uint32 preamble; + uint32 nss; + uint32 bw; + uint32 rateMcsIdx; + uint32 reserved; + uint32 bitrate; +} wifi_rate_v2; + +/* channel statistics */ +typedef struct { + wifi_channel_info channel; /* channel */ + uint32 on_time; /* msecs the radio is awake + * (32 bits number accruing over time) + */ + uint32 cca_busy_time; /* msecs the CCA register is + * busy (32 bits number accruing over time) + */ +} wifi_channel_stat; + +/* radio statistics */ +typedef struct { + wifi_radio radio; /* wifi radio (if multiple radio supported) */ + /* all msecs in 32 bits number accruing over time */ + uint32 on_time; /* msecs the radio is awake */ + uint32 tx_time; /* msecs the radio is transmitting */ + uint32 rx_time; /* msecs the radio is in active receive */ + uint32 on_time_scan; /* msecs the radio is awake due to all scan */ + uint32 on_time_nbd; /* msecs the radio is awake due to NAN */ + uint32 on_time_gscan; /* msecs the radio is awake due to Gscan */ + uint32 on_time_roam_scan; /* msecs the radio is awake due to roam scan */ + uint32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan */ + uint32 on_time_hs20; /* msecs the radio is awake due to + * HS2.0 scans and GAS exchange + */ + uint32 num_channels; /* number of channels */ + wifi_channel_stat channels[]; /* channel statistics */ +} wifi_radio_stat; + +typedef struct { + uint16 version; + uint16 length; + wifi_radio radio; + uint32 on_time; + uint32 tx_time; + uint32 rx_time; + uint32 on_time_scan; + uint32 on_time_nbd; + uint32 on_time_gscan; + uint32 on_time_roam_scan; + uint32 on_time_pno_scan; + uint32 on_time_hs20; + uint32 num_channels; + uint8 channels[1]; +} wifi_radio_stat_v2; + +/* per rate statistics */ +typedef struct { + wifi_rate rate; /* rate information */ + uint32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ + uint32 rx_mpdu; /* number of received data pkts */ + uint32 mpdu_lost; /* number of data packet losses (no ACK) */ + uint32 retries; /* total number of data pkt retries */ + uint32 retries_short; /* number of short data pkt retries */ + uint32 retries_long; /* number of long data pkt retries */ +} wifi_rate_stat; + +typedef struct { + uint16 version; + uint16 length; + uint32 tx_mpdu; + uint32 rx_mpdu; + uint32 mpdu_lost; + uint32 retries; + uint32 retries_short; + uint32 retries_long; + wifi_rate_v2 rate; +} wifi_rate_stat_v2; + +/* access categories */ +typedef enum { + WIFI_AC_VO = 0, + WIFI_AC_VI = 1, + WIFI_AC_BE = 2, + WIFI_AC_BK = 3, + WIFI_AC_MAX = 4 +} wifi_traffic_ac; + +/* wifi peer type */ +typedef enum +{ + WIFI_PEER_STA, + WIFI_PEER_AP, + WIFI_PEER_P2P_GO, + WIFI_PEER_P2P_CLIENT, + WIFI_PEER_NAN, + WIFI_PEER_TDLS, + WIFI_PEER_INVALID +} wifi_peer_type; + +/* per peer statistics */ +typedef struct { + wifi_peer_type type; /* peer type (AP, TDLS, GO etc.) */ + uint8 peer_mac_address[6]; /* mac address */ + uint32 capabilities; /* peer WIFI_CAPABILITY_XXX */ + uint32 num_rate; /* number of rates */ + wifi_rate_stat rate_stats[]; /* per rate statistics, number of entries = num_rate */ +} wifi_peer_info; + +/* per access category statistics */ +typedef struct { + wifi_traffic_ac ac; /* access category (VI, VO, BE, BK) */ + uint32 tx_mpdu; /* number of successfully transmitted + * unicast data pkts (ACK rcvd) + */ + uint32 rx_mpdu; /* number of received unicast mpdus */ + uint32 tx_mcast; /* number of successfully transmitted + * multicast data packets + */ + /* STA case: implies ACK received from AP + * for the unicast packet in which mcast pkt was sent + */ + uint32 rx_mcast; /* number of received multicast data packets */ + uint32 rx_ampdu; /* number of received unicast a-mpdus */ + uint32 tx_ampdu; /* number of transmitted unicast a-mpdus */ + uint32 mpdu_lost; /* number of data pkt losses (no ACK) */ + uint32 retries; /* total number of data pkt retries */ + uint32 retries_short; /* number of short data pkt retries */ + uint32 retries_long; /* number of long data pkt retries */ + uint32 contention_time_min; /* data pkt min contention time (usecs) */ + uint32 contention_time_max; /* data pkt max contention time (usecs) */ + uint32 contention_time_avg; /* data pkt avg contention time (usecs) */ + uint32 contention_num_samples; /* num of data pkts used for contention statistics */ +} wifi_wmm_ac_stat; + +/* interface statistics */ +typedef struct { + wifi_interface_handle iface; /* wifi interface */ + wifi_interface_info info; /* current state of the interface */ + uint32 beacon_rx; /* access point beacon received count + * from connected AP + */ + uint64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT) + * The average_tsf_offset field is used so as to calculate + * the typical beacon contention time on the channel as well + * may be used to debug beacon synchronization and related + * power consumption issue + */ + uint32 leaky_ap_detected; /* indicate that this AP typically leaks packets beyond + * the driver guard time. + */ + uint32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after + * frame with PM bit set was ACK'ed by AP + */ + uint32 leaky_ap_guard_time; /* guard time currently in force (when implementing IEEE + * power management based on frame control PM bit), How long + * driver waits before shutting down the radio and after + * receiving an ACK for a data frame with PM bit set) + */ + uint32 mgmt_rx; /* access point mgmt frames received count + * from connected AP (including Beacon) + */ + uint32 mgmt_action_rx; /* action frames received count */ + uint32 mgmt_action_tx; /* action frames transmit count */ + wifi_rssi rssi_mgmt; /* access Point Beacon and + * Management frames RSSI (averaged) + */ + wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) + * from connected AP + */ + wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) + * from connected AP + */ + wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ + uint32 num_peers; /* number of peers */ + wifi_peer_info peer_info[]; /* per peer statistics */ +} wifi_iface_stat; +#endif /* LINKSTAT_SUPPORT */ +#endif /* _dngl_stats_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h new file mode 100644 index 000000000000..f5f5148cd5b3 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h @@ -0,0 +1,40 @@ +/* + * Dongle WL Header definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dngl_wlhdr.h 241182 2011-02-17 21:50:03Z $ + */ + +#ifndef _dngl_wlhdr_h_ +#define _dngl_wlhdr_h_ + +typedef struct wl_header { + uint8 type; /* Header type */ + uint8 version; /* Header version */ + int8 rssi; /* RSSI */ + uint8 pad; /* Unused */ +} wl_header_t; + +#define WL_HEADER_LEN sizeof(wl_header_t) +#define WL_HEADER_TYPE 0 +#define WL_HEADER_VER 1 +#endif /* _dngl_wlhdr_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c b/drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c new file mode 100644 index 000000000000..31fcf91f0223 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c @@ -0,0 +1,282 @@ +/* + * Misc utility routines for accessing PMU corerev specific features + * of the SiliconBackplane-based Broadcom chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hndpmu.c 433378 2013-10-31 17:19:39Z $ + */ + + +/* + * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs. + * However, in the context of this file the baseband ('BB') PLL/FLL is referred to. + * + * Throughout this code, the prefixes 'pmu0_', 'pmu1_' and 'pmu2_' are used. + * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012) + * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports + * fractional frequency generation. pmu2_ does not support fractional frequency generation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PMU_ERROR(args) + +#define PMU_MSG(args) + +/* To check in verbose debugging messages not intended + * to be on except on private builds. + */ +#define PMU_NONE(args) + +/** contains resource bit positions for a specific chip */ +struct rsc_per_chip_s { + uint8 ht_avail; + uint8 macphy_clkavail; + uint8 ht_start; + uint8 otp_pu; +}; + +typedef struct rsc_per_chip_s rsc_per_chip_t; + + +/* SDIO Pad drive strength to select value mappings. + * The last strength value in each table must be 0 (the tri-state value). + */ +typedef struct { + uint8 strength; /* Pad Drive Strength in mA */ + uint8 sel; /* Chip-specific select value */ +} sdiod_drive_str_t; + +/* SDIO Drive Strength to sel value table for PMU Rev 1 */ +static const sdiod_drive_str_t 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 sdiod_drive_str_t 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 sdiod_drive_str_t sdiod_drive_strength_tab3[] = { + {32, 0x7}, + {26, 0x6}, + {22, 0x5}, + {16, 0x4}, + {12, 0x3}, + {8, 0x2}, + {4, 0x1}, + {0, 0x0} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { + {32, 0x6}, + {26, 0x7}, + {22, 0x4}, + {16, 0x5}, + {12, 0x2}, + {8, 0x3}, + {4, 0x0}, + {0, 0x1} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ + +/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { + {6, 0x7}, + {5, 0x6}, + {4, 0x5}, + {3, 0x4}, + {2, 0x2}, + {1, 0x1}, + {0, 0x0} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ + +/** SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { + {3, 0x3}, + {2, 0x2}, + {1, 0x1}, + {0, 0x0} }; + + +/** + * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel + * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture + * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has + * been written '1'. + */ +#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 + +static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = { + /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */ + {16, 0x7}, + {12, 0x5}, + {8, 0x3}, + {4, 0x1} }; /* note: 43143 does not support tristate */ + +#else + +static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = { + /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */ + {8, 0x7}, + {6, 0x5}, + {4, 0x3}, + {2, 0x1} }; /* note: 43143 does not support tristate */ + +#endif /* BCM_SDIO_VDDIO */ + +#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) + +/** + * Balance between stable SDIO operation and power consumption is achieved using this function. + * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this + * function should read the VDDIO itself to select the correct table. For now it has been solved + * with the 'BCM_SDIO_VDDIO' preprocessor constant. + * + * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if + * hardware supports this), if no hw support drive strength is not programmed. + */ +void +si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) +{ + chipcregs_t *cc; + uint origidx, intr_val = 0; + sdiod_drive_str_t *str_tab = NULL; + uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */ + uint32 str_shift = 0; + uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */ + uint32 str_ovr_pmuval = 0; /* position of bit within this register */ + + if (!(sih->cccaps & CC_CAP_PMU)) { + return; + } + + /* Remember original core before switch to chipc */ + cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); + + switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { + case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): + str_tab = (sdiod_drive_str_t *)&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): + case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): + if (sih->pmurev == 8) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; + } + else if (sih->pmurev == 11) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; + } + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; + str_mask = 0x00001800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): +#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 + if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; + } +#else + if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; + } +#endif /* BCM_SDIO_VDDIO */ + str_mask = 0x00000007; + str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; + break; + default: + PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", + bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); + break; + } + + if (str_tab != NULL && cc != NULL) { + uint32 cc_data_temp; + int i; + + /* Pick the lowest available drive strength equal or greater than the + * requested strength. Drive strength of 0 requests tri-state. + */ + for (i = 0; drivestrength < str_tab[i].strength; i++) + ; + + if (i > 0 && drivestrength > str_tab[i].strength) + i--; + + W_REG(osh, &cc->chipcontrol_addr, PMU_CHIPCTL1); + cc_data_temp = R_REG(osh, &cc->chipcontrol_data); + cc_data_temp &= ~str_mask; + cc_data_temp |= str_tab[i].sel << str_shift; + W_REG(osh, &cc->chipcontrol_data, cc_data_temp); + if (str_ovr_pmuval) { /* enables the selected drive strength */ + W_REG(osh, &cc->chipcontrol_addr, str_ovr_pmuctl); + OR_REG(osh, &cc->chipcontrol_data, str_ovr_pmuval); + } + PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", + drivestrength, str_tab[i].strength)); + } + + /* Return to original core */ + si_restore_core(sih, origidx, intr_val); +} /* si_sdiod_drive_strength_init */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/Makefile b/drivers/net/wireless/bcmdhd_bcm43455/include/Makefile new file mode 100644 index 000000000000..797ee2563e33 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/Makefile @@ -0,0 +1,71 @@ +#!/bin/bash +# +# Copyright (C) 1999-2017, Broadcom Corporation +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to you +# under the terms of the GNU General Public License version 2 (the "GPL"), +# available at http://www.broadcom.com/licenses/GPLv2.php, with the +# following added to such license: +# +# As a special exception, the copyright holders of this software give you +# permission to link this software with independent modules, and to copy and +# distribute the resulting executable under terms of your choice, provided that +# you also meet, for each linked independent module, the terms and conditions of +# the license of that module. An independent module is a module which is not +# derived from this software. The special exception does not apply to any +# modifications of the software. +# +# Notwithstanding the above, under no circumstances may you combine this +# software in any way with any other Broadcom software provided under a license +# other than the GPL, without Broadcom's express prior written consent. +# +# This script serves following purpose: +# +# 1. It generates native version information by querying +# automerger maintained database to see where src/include +# came from +# 2. For select components, as listed in compvers.sh +# it generates component version files +# +# $Id: Makefile 528449 2015-01-22 09:38:18Z $ +# + +export SRCBASE:=.. + +TARGETS := epivers.h + +ifdef VERBOSE +export VERBOSE +endif + +all release: epivers compvers + +# Generate epivers.h for native branch url +epivers: + bash epivers.sh + +# Generate component versions based on component url +compvers: + @if [ -s "compvers.sh" ]; then \ + echo "Generating component versions, if any"; \ + bash compvers.sh; \ + else \ + echo "Skipping component version generation"; \ + fi + +# Generate epivers.h for native branch version +clean_compvers: + @if [ -s "compvers.sh" ]; then \ + echo "bash compvers.sh clean"; \ + bash compvers.sh clean; \ + else \ + echo "Skipping component version clean"; \ + fi + +clean: + rm -f $(TARGETS) *.prev + +clean_all: clean clean_compvers + +.PHONY: all release clean epivers compvers clean_compvers diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h b/drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h new file mode 100644 index 000000000000..831865dd8817 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h @@ -0,0 +1,386 @@ +/* + * Broadcom AMBA Interconnect definitions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: aidmp.h 404499 2013-05-28 01:06:37Z $ + */ + +#ifndef _AIDMP_H +#define _AIDMP_H + +/* Manufacturer Ids */ +#define MFGID_ARM 0x43b +#define MFGID_BRCM 0x4bf +#define MFGID_MIPS 0x4a7 + +/* Component Classes */ +#define CC_SIM 0 +#define CC_EROM 1 +#define CC_CORESIGHT 9 +#define CC_VERIF 0xb +#define CC_OPTIMO 0xd +#define CC_GEN 0xe +#define CC_PRIMECELL 0xf + +/* 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 MasterPortDesc */ +#define MPD_MUI_MASK 0x0000ff00 +#define MPD_MUI_SHIFT 8 +#define MPD_MP_MASK 0x000000f0 +#define MPD_MP_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 + + +#ifndef _LANGUAGE_ASSEMBLY + +typedef volatile struct _aidmp { + uint32 oobselina30; /* 0x000 */ + uint32 oobselina74; /* 0x004 */ + uint32 PAD[6]; + uint32 oobselinb30; /* 0x020 */ + uint32 oobselinb74; /* 0x024 */ + uint32 PAD[6]; + uint32 oobselinc30; /* 0x040 */ + uint32 oobselinc74; /* 0x044 */ + uint32 PAD[6]; + uint32 oobselind30; /* 0x060 */ + uint32 oobselind74; /* 0x064 */ + uint32 PAD[38]; + uint32 oobselouta30; /* 0x100 */ + uint32 oobselouta74; /* 0x104 */ + uint32 PAD[6]; + uint32 oobseloutb30; /* 0x120 */ + uint32 oobseloutb74; /* 0x124 */ + uint32 PAD[6]; + uint32 oobseloutc30; /* 0x140 */ + uint32 oobseloutc74; /* 0x144 */ + uint32 PAD[6]; + uint32 oobseloutd30; /* 0x160 */ + uint32 oobseloutd74; /* 0x164 */ + uint32 PAD[38]; + uint32 oobsynca; /* 0x200 */ + uint32 oobseloutaen; /* 0x204 */ + uint32 PAD[6]; + uint32 oobsyncb; /* 0x220 */ + uint32 oobseloutben; /* 0x224 */ + uint32 PAD[6]; + uint32 oobsyncc; /* 0x240 */ + uint32 oobseloutcen; /* 0x244 */ + uint32 PAD[6]; + uint32 oobsyncd; /* 0x260 */ + uint32 oobseloutden; /* 0x264 */ + uint32 PAD[38]; + uint32 oobaextwidth; /* 0x300 */ + uint32 oobainwidth; /* 0x304 */ + uint32 oobaoutwidth; /* 0x308 */ + uint32 PAD[5]; + uint32 oobbextwidth; /* 0x320 */ + uint32 oobbinwidth; /* 0x324 */ + uint32 oobboutwidth; /* 0x328 */ + uint32 PAD[5]; + uint32 oobcextwidth; /* 0x340 */ + uint32 oobcinwidth; /* 0x344 */ + uint32 oobcoutwidth; /* 0x348 */ + uint32 PAD[5]; + uint32 oobdextwidth; /* 0x360 */ + uint32 oobdinwidth; /* 0x364 */ + uint32 oobdoutwidth; /* 0x368 */ + uint32 PAD[37]; + uint32 ioctrlset; /* 0x400 */ + uint32 ioctrlclear; /* 0x404 */ + uint32 ioctrl; /* 0x408 */ + uint32 PAD[61]; + uint32 iostatus; /* 0x500 */ + uint32 PAD[127]; + uint32 ioctrlwidth; /* 0x700 */ + uint32 iostatuswidth; /* 0x704 */ + uint32 PAD[62]; + uint32 resetctrl; /* 0x800 */ + uint32 resetstatus; /* 0x804 */ + uint32 resetreadid; /* 0x808 */ + uint32 resetwriteid; /* 0x80c */ + uint32 PAD[60]; + uint32 errlogctrl; /* 0x900 */ + uint32 errlogdone; /* 0x904 */ + uint32 errlogstatus; /* 0x908 */ + uint32 errlogaddrlo; /* 0x90c */ + uint32 errlogaddrhi; /* 0x910 */ + uint32 errlogid; /* 0x914 */ + uint32 errloguser; /* 0x918 */ + uint32 errlogflags; /* 0x91c */ + uint32 PAD[56]; + uint32 intstatus; /* 0xa00 */ + uint32 PAD[255]; + uint32 config; /* 0xe00 */ + uint32 PAD[63]; + uint32 itcr; /* 0xf00 */ + uint32 PAD[3]; + uint32 itipooba; /* 0xf10 */ + uint32 itipoobb; /* 0xf14 */ + uint32 itipoobc; /* 0xf18 */ + uint32 itipoobd; /* 0xf1c */ + uint32 PAD[4]; + uint32 itipoobaout; /* 0xf30 */ + uint32 itipoobbout; /* 0xf34 */ + uint32 itipoobcout; /* 0xf38 */ + uint32 itipoobdout; /* 0xf3c */ + uint32 PAD[4]; + uint32 itopooba; /* 0xf50 */ + uint32 itopoobb; /* 0xf54 */ + uint32 itopoobc; /* 0xf58 */ + uint32 itopoobd; /* 0xf5c */ + uint32 PAD[4]; + uint32 itopoobain; /* 0xf70 */ + uint32 itopoobbin; /* 0xf74 */ + uint32 itopoobcin; /* 0xf78 */ + uint32 itopoobdin; /* 0xf7c */ + uint32 PAD[4]; + uint32 itopreset; /* 0xf90 */ + uint32 PAD[15]; + uint32 peripherialid4; /* 0xfd0 */ + uint32 peripherialid5; /* 0xfd4 */ + uint32 peripherialid6; /* 0xfd8 */ + uint32 peripherialid7; /* 0xfdc */ + uint32 peripherialid0; /* 0xfe0 */ + uint32 peripherialid1; /* 0xfe4 */ + uint32 peripherialid2; /* 0xfe8 */ + uint32 peripherialid3; /* 0xfec */ + uint32 componentid0; /* 0xff0 */ + uint32 componentid1; /* 0xff4 */ + uint32 componentid2; /* 0xff8 */ + uint32 componentid3; /* 0xffc */ +} aidmp_t; + +#endif /* _LANGUAGE_ASSEMBLY */ + +/* Out-of-band Router registers */ +#define OOB_BUSCONFIG 0x020 +#define OOB_STATUSA 0x100 +#define OOB_STATUSB 0x104 +#define OOB_STATUSC 0x108 +#define OOB_STATUSD 0x10c +#define OOB_ENABLEA0 0x200 +#define OOB_ENABLEA1 0x204 +#define OOB_ENABLEA2 0x208 +#define OOB_ENABLEA3 0x20c +#define OOB_ENABLEB0 0x280 +#define OOB_ENABLEB1 0x284 +#define OOB_ENABLEB2 0x288 +#define OOB_ENABLEB3 0x28c +#define OOB_ENABLEC0 0x300 +#define OOB_ENABLEC1 0x304 +#define OOB_ENABLEC2 0x308 +#define OOB_ENABLEC3 0x30c +#define OOB_ENABLED0 0x380 +#define OOB_ENABLED1 0x384 +#define OOB_ENABLED2 0x388 +#define OOB_ENABLED3 0x38c +#define OOB_ITCR 0xf00 +#define OOB_ITIPOOBA 0xf10 +#define OOB_ITIPOOBB 0xf14 +#define OOB_ITIPOOBC 0xf18 +#define OOB_ITIPOOBD 0xf1c +#define OOB_ITOPOOBA 0xf30 +#define OOB_ITOPOOBB 0xf34 +#define OOB_ITOPOOBC 0xf38 +#define OOB_ITOPOOBD 0xf3c + +/* DMP wrapper registers */ +#define AI_OOBSELINA30 0x000 +#define AI_OOBSELINA74 0x004 +#define AI_OOBSELINB30 0x020 +#define AI_OOBSELINB74 0x024 +#define AI_OOBSELINC30 0x040 +#define AI_OOBSELINC74 0x044 +#define AI_OOBSELIND30 0x060 +#define AI_OOBSELIND74 0x064 +#define AI_OOBSELOUTA30 0x100 +#define AI_OOBSELOUTA74 0x104 +#define AI_OOBSELOUTB30 0x120 +#define AI_OOBSELOUTB74 0x124 +#define AI_OOBSELOUTC30 0x140 +#define AI_OOBSELOUTC74 0x144 +#define AI_OOBSELOUTD30 0x160 +#define AI_OOBSELOUTD74 0x164 +#define AI_OOBSYNCA 0x200 +#define AI_OOBSELOUTAEN 0x204 +#define AI_OOBSYNCB 0x220 +#define AI_OOBSELOUTBEN 0x224 +#define AI_OOBSYNCC 0x240 +#define AI_OOBSELOUTCEN 0x244 +#define AI_OOBSYNCD 0x260 +#define AI_OOBSELOUTDEN 0x264 +#define AI_OOBAEXTWIDTH 0x300 +#define AI_OOBAINWIDTH 0x304 +#define AI_OOBAOUTWIDTH 0x308 +#define AI_OOBBEXTWIDTH 0x320 +#define AI_OOBBINWIDTH 0x324 +#define AI_OOBBOUTWIDTH 0x328 +#define AI_OOBCEXTWIDTH 0x340 +#define AI_OOBCINWIDTH 0x344 +#define AI_OOBCOUTWIDTH 0x348 +#define AI_OOBDEXTWIDTH 0x360 +#define AI_OOBDINWIDTH 0x364 +#define AI_OOBDOUTWIDTH 0x368 + + +#define AI_IOCTRLSET 0x400 +#define AI_IOCTRLCLEAR 0x404 +#define AI_IOCTRL 0x408 +#define AI_IOSTATUS 0x500 +#define AI_RESETCTRL 0x800 +#define AI_RESETSTATUS 0x804 + +#define AI_IOCTRLWIDTH 0x700 +#define AI_IOSTATUSWIDTH 0x704 + +#define AI_RESETREADID 0x808 +#define AI_RESETWRITEID 0x80c +#define AI_ERRLOGCTRL 0xa00 +#define AI_ERRLOGDONE 0xa04 +#define AI_ERRLOGSTATUS 0xa08 +#define AI_ERRLOGADDRLO 0xa0c +#define AI_ERRLOGADDRHI 0xa10 +#define AI_ERRLOGID 0xa14 +#define AI_ERRLOGUSER 0xa18 +#define AI_ERRLOGFLAGS 0xa1c +#define AI_INTSTATUS 0xa00 +#define AI_CONFIG 0xe00 +#define AI_ITCR 0xf00 +#define AI_ITIPOOBA 0xf10 +#define AI_ITIPOOBB 0xf14 +#define AI_ITIPOOBC 0xf18 +#define AI_ITIPOOBD 0xf1c +#define AI_ITIPOOBAOUT 0xf30 +#define AI_ITIPOOBBOUT 0xf34 +#define AI_ITIPOOBCOUT 0xf38 +#define AI_ITIPOOBDOUT 0xf3c +#define AI_ITOPOOBA 0xf50 +#define AI_ITOPOOBB 0xf54 +#define AI_ITOPOOBC 0xf58 +#define AI_ITOPOOBD 0xf5c +#define AI_ITOPOOBAIN 0xf70 +#define AI_ITOPOOBBIN 0xf74 +#define AI_ITOPOOBCIN 0xf78 +#define AI_ITOPOOBDIN 0xf7c +#define AI_ITOPRESET 0xf90 +#define AI_PERIPHERIALID4 0xfd0 +#define AI_PERIPHERIALID5 0xfd4 +#define AI_PERIPHERIALID6 0xfd8 +#define AI_PERIPHERIALID7 0xfdc +#define AI_PERIPHERIALID0 0xfe0 +#define AI_PERIPHERIALID1 0xfe4 +#define AI_PERIPHERIALID2 0xfe8 +#define AI_PERIPHERIALID3 0xfec +#define AI_COMPONENTID0 0xff0 +#define AI_COMPONENTID1 0xff4 +#define AI_COMPONENTID2 0xff8 +#define AI_COMPONENTID3 0xffc + +/* resetctrl */ +#define AIRC_RESET 1 + +/* config */ +#define AICFG_OOB 0x00000020 +#define AICFG_IOS 0x00000010 +#define AICFG_IOC 0x00000008 +#define AICFG_TO 0x00000004 +#define AICFG_ERRL 0x00000002 +#define AICFG_RST 0x00000001 + +/* bit defines for AI_OOBSELOUTB74 reg */ +#define OOB_SEL_OUTEN_B_5 15 +#define OOB_SEL_OUTEN_B_6 23 + +/* AI_OOBSEL for A/B/C/D, 0-7 */ +#define AI_OOBSEL_MASK 0x1F +#define AI_OOBSEL_0_SHIFT 0 +#define AI_OOBSEL_1_SHIFT 8 +#define AI_OOBSEL_2_SHIFT 16 +#define AI_OOBSEL_3_SHIFT 24 +#define AI_OOBSEL_4_SHIFT 0 +#define AI_OOBSEL_5_SHIFT 8 +#define AI_OOBSEL_6_SHIFT 16 +#define AI_OOBSEL_7_SHIFT 24 + +#endif /* _AIDMP_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h new file mode 100644 index 000000000000..7c6e70f449ef --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h @@ -0,0 +1,29 @@ +/* + * BCM common config options + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcm_cfg.h 351867 2012-08-21 18:46:16Z $ + */ + +#ifndef _bcm_cfg_h_ +#define _bcm_cfg_h_ +#endif /* _bcm_cfg_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h new file mode 100644 index 000000000000..b05ba3704aeb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h @@ -0,0 +1,361 @@ +/* + * Memory pools library, Public interface + * + * API Overview + * + * This package provides a memory allocation subsystem based on pools of + * homogenous objects. + * + * Instrumentation is available for reporting memory utilization both + * on a per-data-structure basis and system wide. + * + * There are two main types defined in this API. + * + * pool manager: A singleton object that acts as a factory for + * pool allocators. It also is used for global + * instrumentation, such as reporting all blocks + * in use across all data structures. The pool manager + * creates and provides individual memory pools + * upon request to application code. + * + * memory pool: An object for allocating homogenous memory blocks. + * + * Global identifiers in this module use the following prefixes: + * bcm_mpm_* Memory pool manager + * bcm_mp_* Memory pool + * + * There are two main types of memory pools: + * + * prealloc: The contiguous memory block of objects can either be supplied + * by the client or malloc'ed by the memory manager. The objects are + * allocated out of a block of memory and freed back to the block. + * + * heap: The memory pool allocator uses the heap (malloc/free) for memory. + * In this case, the pool allocator is just providing statistics + * and instrumentation on top of the heap, without modifying the heap + * allocation implementation. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcm_mpool_pub.h 407097 2013-06-11 18:43:16Z $ + */ + +#ifndef _BCM_MPOOL_PUB_H +#define _BCM_MPOOL_PUB_H 1 + +#include /* needed for uint16 */ + + +/* +************************************************************************** +* +* Type definitions, handles +* +************************************************************************** +*/ + +/* Forward declaration of OSL handle. */ +struct osl_info; + +/* Forward declaration of string buffer. */ +struct bcmstrbuf; + +/* + * Opaque type definition for the pool manager handle. This object is used for global + * memory pool operations such as obtaining a new pool, deleting a pool, iterating and + * instrumentation/debugging. + */ +struct bcm_mpm_mgr; +typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h; + +/* + * Opaque type definition for an instance of a pool. This handle is used for allocating + * and freeing memory through the pool, as well as management/instrumentation on this + * specific pool. + */ +struct bcm_mp_pool; +typedef struct bcm_mp_pool *bcm_mp_pool_h; + + +/* + * To make instrumentation more readable, every memory + * pool must have a readable name. Pool names are up to + * 8 bytes including '\0' termination. (7 printable characters.) + */ +#define BCM_MP_NAMELEN 8 + + +/* + * Type definition for pool statistics. + */ +typedef struct bcm_mp_stats { + char name[BCM_MP_NAMELEN]; /* Name of this pool. */ + unsigned int objsz; /* Object size allocated in this pool */ + uint16 nobj; /* Total number of objects in this pool */ + uint16 num_alloc; /* Number of objects currently allocated */ + uint16 high_water; /* Max number of allocated objects. */ + uint16 failed_alloc; /* Failed allocations. */ +} bcm_mp_stats_t; + + +/* +************************************************************************** +* +* API Routines on the pool manager. +* +************************************************************************** +*/ + +/* + * bcm_mpm_init() - initialize the whole memory pool system. + * + * Parameters: + * osh: INPUT Operating system handle. Needed for heap memory allocation. + * max_pools: INPUT Maximum number of mempools supported. + * mgr: OUTPUT The handle is written with the new pools manager object/handle. + * + * Returns: + * BCME_OK Object initialized successfully. May be used. + * BCME_NOMEM Initialization failed due to no memory. Object must not be used. + */ +int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp); + + +/* + * bcm_mpm_deinit() - de-initialize the whole memory pool system. + * + * Parameters: + * mgr: INPUT Pointer to pool manager handle. + * + * Returns: + * BCME_OK Memory pool manager successfully de-initialized. + * other Indicated error occured during de-initialization. + */ +int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); + +/* + * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The + * pool uses a contiguous block of pre-alloced + * memory. The memory block may either be provided + * by the client or dynamically allocated by the + * pool manager. + * + * Parameters: + * mgr: INPUT The handle to the pool manager + * obj_sz: INPUT Size of objects that will be allocated by the new pool + * Must be >= sizeof(void *). + * nobj: INPUT Maximum number of concurrently existing objects to support + * memstart INPUT Pointer to the memory to use, or NULL to malloc() + * memsize INPUT Number of bytes referenced from memstart (for error checking). + * Must be 0 if 'memstart' is NULL. + * poolname INPUT For instrumentation, the name of the pool + * newp: OUTPUT The handle for the new pool, if creation is successful + * + * Returns: + * BCME_OK Pool created ok. + * other Pool not created due to indicated error. newpoolp set to NULL. + * + * + */ +int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, + unsigned int obj_sz, + int nobj, + void *memstart, + unsigned int memsize, + const char poolname[BCM_MP_NAMELEN], + bcm_mp_pool_h *newp); + + +/* + * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after + * all memory objects have been freed back to the pool. + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * pool: INPUT The handle of the pool to delete + * + * Returns: + * BCME_OK Pool deleted ok. + * other Pool not deleted due to indicated error. + * + */ +int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); + +/* + * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory + * pool allocator uses the heap (malloc/free) for memory. + * In this case, the pool allocator is just providing + * statistics and instrumentation on top of the heap, + * without modifying the heap allocation implementation. + * + * Parameters: + * mgr: INPUT The handle to the pool manager + * obj_sz: INPUT Size of objects that will be allocated by the new pool + * poolname INPUT For instrumentation, the name of the pool + * newp: OUTPUT The handle for the new pool, if creation is successful + * + * Returns: + * BCME_OK Pool created ok. + * other Pool not created due to indicated error. newpoolp set to NULL. + * + * + */ +int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, + const char poolname[BCM_MP_NAMELEN], + bcm_mp_pool_h *newp); + + +/* + * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after + * all memory objects have been freed back to the pool. + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * pool: INPUT The handle of the pool to delete + * + * Returns: + * BCME_OK Pool deleted ok. + * other Pool not deleted due to indicated error. + * + */ +int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); + + +/* + * bcm_mpm_stats() - Return stats for all pools + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * stats: OUTPUT Array of pool statistics. + * nentries: MOD Max elements in 'stats' array on INPUT. Actual number + * of array elements copied to 'stats' on OUTPUT. + * + * Returns: + * BCME_OK Ok + * other Error getting stats. + * + */ +int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries); + + +/* + * bcm_mpm_dump() - Display statistics on all pools + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * b: OUTPUT Output buffer. + * + * Returns: + * BCME_OK Ok + * other Error during dump. + * + */ +int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b); + + +/* + * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to + * compensate for alignment requirements of the objects. + * This function provides the padded object size. If clients + * pre-allocate a memory slab for a memory pool, the + * padded object size should be used by the client to allocate + * the memory slab (in order to provide sufficent space for + * the maximum number of objects). + * + * Parameters: + * mgr: INPUT The handle to the pools manager. + * obj_sz: INPUT Input object size. + * padded_obj_sz: OUTPUT Padded object size. + * + * Returns: + * BCME_OK Ok + * BCME_BADARG Bad arguments. + * + */ +int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz); + + +/* +*************************************************************************** +* +* API Routines on a specific pool. +* +*************************************************************************** +*/ + + +/* + * bcm_mp_alloc() - Allocate a memory pool object. + * + * Parameters: + * pool: INPUT The handle to the pool. + * + * Returns: + * A pointer to the new object. NULL on error. + * + */ +void* bcm_mp_alloc(bcm_mp_pool_h pool); + +/* + * bcm_mp_free() - Free a memory pool object. + * + * Parameters: + * pool: INPUT The handle to the pool. + * objp: INPUT A pointer to the object to free. + * + * Returns: + * BCME_OK Ok + * other Error during free. + * + */ +int bcm_mp_free(bcm_mp_pool_h pool, void *objp); + +/* + * bcm_mp_stats() - Return stats for this pool + * + * Parameters: + * pool: INPUT The handle to the pool + * stats: OUTPUT Pool statistics + * + * Returns: + * BCME_OK Ok + * other Error getting statistics. + * + */ +int bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats); + + +/* + * bcm_mp_dump() - Dump a pool + * + * Parameters: + * pool: INPUT The handle to the pool + * b OUTPUT Output buffer + * + * Returns: + * BCME_OK Ok + * other Error during dump. + * + */ +int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b); + + +#endif /* _BCM_MPOOL_PUB_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h new file mode 100644 index 000000000000..c93b6f619b20 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h @@ -0,0 +1,132 @@ +/* + * CDC network driver ioctl/indication encoding + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmcdc.h 318308 2012-03-02 02:23:42Z $ + */ +#ifndef _bcmcdc_h_ +#define _bcmcdc_h_ +#include + +typedef struct cdc_ioctl { + uint32 cmd; /* ioctl command value */ + uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */ + uint32 flags; /* flag defns given below */ + uint32 status; /* status code returned from the device */ +} cdc_ioctl_t; + +/* Max valid buffer size that can be sent to the dongle */ +#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN + +/* len field is divided into input and output buffer lengths */ +#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */ + /* excluding IOCTL header */ +#define CDCL_IOC_OUTLEN_SHIFT 0 +#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */ +#define CDCL_IOC_INLEN_SHIFT 16 + +/* CDC flag definitions */ +#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */ +#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */ +#define CDCF_IOC_OVL_IDX_MASK 0x3c /* overlay region index mask */ +#define CDCF_IOC_OVL_RSV 0x40 /* 1=reserve this overlay region */ +#define CDCF_IOC_OVL 0x80 /* 1=this ioctl corresponds to an overlay */ +#define CDCF_IOC_ACTION_MASK 0xfe /* SET/GET, OVL_IDX, OVL_RSV, OVL mask */ +#define CDCF_IOC_ACTION_SHIFT 1 /* SET/GET, OVL_IDX, OVL_RSV, OVL shift */ +#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */ +#define CDCF_IOC_IF_SHIFT 12 +#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */ +#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */ + +#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) +#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) + +#define CDC_GET_IF_IDX(hdr) \ + ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) +#define CDC_SET_IF_IDX(hdr, idx) \ + ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) + +/* + * BDC header + * + * The BDC header is used on data packets to convey priority across USB. + */ + +struct bdc_header { + uint8 flags; /* Flags */ + uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 USB flow control info */ + uint8 flags2; + uint8 dataOffset; /* Offset from end of BDC header to packet data, in + * 4-byte words. Leaves room for optional headers. + */ +}; + +#define BDC_HEADER_LEN 4 + +/* flags field bitmap */ +#define BDC_FLAG_80211_PKT 0x01 /* Packet is in 802.11 format (dongle -> host) */ +#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */ +#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums: host->device */ +#define BDC_FLAG_EVENT_MSG 0x08 /* Payload contains an event msg: device->host */ +#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ +#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ + +/* priority field bitmap */ +#define BDC_PRIORITY_MASK 0x07 +#define BDC_PRIORITY_FC_MASK 0xf0 /* flow control info mask */ +#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */ + +/* flags2 field bitmap */ +#define BDC_FLAG2_IF_MASK 0x0f /* interface index (host <-> dongle) */ +#define BDC_FLAG2_IF_SHIFT 0 +#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */ + /* FLOW CONTROL info only */ + +/* version numbers */ +#define BDC_PROTO_VER_1 1 /* Old Protocol version */ +#define BDC_PROTO_VER 2 /* Protocol version */ + +/* flags2.if field access macros */ +#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))) + +#define BDC_FLAG2_PAD_MASK 0xf0 +#define BDC_FLAG_PAD_MASK 0x03 +#define BDC_FLAG2_PAD_SHIFT 2 +#define BDC_FLAG_PAD_SHIFT 0 +#define BDC_FLAG2_PAD_IDX 0x3c +#define BDC_FLAG_PAD_IDX 0x03 +#define BDC_GET_PAD_LEN(hdr) \ + ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ + ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) +#define BDC_SET_PAD_LEN(hdr, idx) \ + ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ + (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ + ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ + (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) + +#endif /* _bcmcdc_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h new file mode 100644 index 000000000000..15c00f718a31 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h @@ -0,0 +1,348 @@ +/* + * Misc system wide definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmdefs.h 433011 2013-10-30 09:19:54Z $ + */ + +#ifndef _bcmdefs_h_ +#define _bcmdefs_h_ + +/* + * One doesn't need to include this file explicitly, gets included automatically if + * typedefs.h is included. + */ + +/* Use BCM_REFERENCE to suppress warnings about intentionally-unused function + * arguments or local variables. + */ +#define BCM_REFERENCE(data) ((void)(data)) + +/* Allow for suppressing unused variable warnings. */ +#ifdef __GNUC__ +#define UNUSED_VAR __attribute__ ((unused)) +#else +#define UNUSED_VAR +#endif + +/* Compile-time assert can be used in place of ASSERT if the expression evaluates + * to a constant at compile time. + */ +#define STATIC_ASSERT(expr) { \ + /* Make sure the expression is constant. */ \ + typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \ + /* Make sure the expression is true. */ \ + typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \ +} + +/* Reclaiming text and data : + * The following macros specify special linker sections that can be reclaimed + * after a system is considered 'up'. + * BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN, + * as in most cases, the attach function calls the detach function to clean up on error). + */ + +#define bcmreclaimed 0 +#define _data _data +#define _fn _fn +#define BCMPREATTACHDATA(_data) _data +#define BCMPREATTACHFN(_fn) _fn +#define _data _data +#define _fn _fn +#define _fn _fn +#define BCMNMIATTACHFN(_fn) _fn +#define BCMNMIATTACHDATA(_data) _data +#define CONST const + +#undef BCM47XX_CA9 + +#ifndef BCMFASTPATH +#if defined(BCM47XX_CA9) +#define BCMFASTPATH __attribute__ ((__section__ (".text.fastpath"))) +#define BCMFASTPATH_HOST __attribute__ ((__section__ (".text.fastpath_host"))) +#else +#define BCMFASTPATH +#define BCMFASTPATH_HOST +#endif +#endif /* BCMFASTPATH */ + + +/* Use the BCMRAMFN() macro to tag functions in source that must be included in RAM (excluded from + * ROM). This should eliminate the need to manually specify these functions in the ROM config file. + * It should only be used in special cases where the function must be in RAM for *all* ROM-based + * chips. + */ + #define BCMRAMFN(_fn) _fn + + + +/* Put some library data/code into ROM to reduce RAM requirements */ +#define _data _data +#define BCMROMDAT_NAME(_data) _data +#define _fn _fn +#define _fn _fn +#define STATIC static +#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data) +#define BCMROMDAT_SIZEOF(data) sizeof(data) +#define BCMROMDAT_APATCH(data) +#define BCMROMDAT_SPATCH(data) + +/* Bus types */ +#define SI_BUS 0 /* SOC Interconnect */ +#define PCI_BUS 1 /* PCI target */ +#define PCMCIA_BUS 2 /* PCMCIA target */ +#define SDIO_BUS 3 /* SDIO target */ +#define JTAG_BUS 4 /* JTAG */ +#define USB_BUS 5 /* USB (does not support R/W REG) */ +#define SPI_BUS 6 /* gSPI target */ +#define RPC_BUS 7 /* RPC target */ + +/* Allows size optimization for single-bus image */ +#ifdef BCMBUSTYPE +#define BUSTYPE(bus) (BCMBUSTYPE) +#else +#define BUSTYPE(bus) (bus) +#endif + +/* Allows size optimization for single-backplane image */ +#ifdef BCMCHIPTYPE +#define CHIPTYPE(bus) (BCMCHIPTYPE) +#else +#define CHIPTYPE(bus) (bus) +#endif + + +/* Allows size optimization for SPROM support */ +#if defined(BCMSPROMBUS) +#define SPROMBUS (BCMSPROMBUS) +#elif defined(SI_PCMCIA_SROM) +#define SPROMBUS (PCMCIA_BUS) +#else +#define SPROMBUS (PCI_BUS) +#endif + +/* Allows size optimization for single-chip image */ +#ifdef BCMCHIPID +#define CHIPID(chip) (BCMCHIPID) +#else +#define CHIPID(chip) (chip) +#endif + +#ifdef BCMCHIPREV +#define CHIPREV(rev) (BCMCHIPREV) +#else +#define CHIPREV(rev) (rev) +#endif + +/* Defines for DMA Address Width - Shared between OSL and HNDDMA */ +#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ +#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */ +#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */ + +#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */ +#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */ +#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */ +#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */ + +typedef struct { + uint32 loaddr; + uint32 hiaddr; +} dma64addr_t; + +#define PHYSADDR64HI(_pa) ((_pa).hiaddr) +#define PHYSADDR64HISET(_pa, _val) \ + do { \ + (_pa).hiaddr = (_val); \ + } while (0) +#define PHYSADDR64LO(_pa) ((_pa).loaddr) +#define PHYSADDR64LOSET(_pa, _val) \ + do { \ + (_pa).loaddr = (_val); \ + } while (0) + +#ifdef BCMDMA64OSL +typedef dma64addr_t dmaaddr_t; +#define PHYSADDRHI(_pa) PHYSADDR64HI(_pa) +#define PHYSADDRHISET(_pa, _val) PHYSADDR64HISET(_pa, _val) +#define PHYSADDRLO(_pa) PHYSADDR64LO(_pa) +#define PHYSADDRLOSET(_pa, _val) PHYSADDR64LOSET(_pa, _val) + +#else +typedef unsigned long dmaaddr_t; +#define PHYSADDRHI(_pa) (0) +#define PHYSADDRHISET(_pa, _val) +#define PHYSADDRLO(_pa) ((_pa)) +#define PHYSADDRLOSET(_pa, _val) \ + do { \ + (_pa) = (_val); \ + } while (0) +#endif /* BCMDMA64OSL */ + +/* One physical DMA segment */ +typedef struct { + dmaaddr_t addr; + uint32 length; +} hnddma_seg_t; + +#define MAX_DMA_SEGS 8 + + +typedef struct { + void *oshdmah; /* Opaque handle for OSL to store its information */ + uint origsize; /* Size of the virtual packet */ + uint nsegs; + hnddma_seg_t segs[MAX_DMA_SEGS]; +} hnddma_seg_map_t; + + +/* 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 (hnddma.c). + */ + +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) +/* add 40 bytes to allow for extra RPC header and info */ +#define BCMEXTRAHDROOM 260 +#else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ +#if defined(BCM47XX_CA9) +#define BCMEXTRAHDROOM 224 +#else +#define BCMEXTRAHDROOM 204 +#endif /* linux && BCM47XX_CA9 */ +#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ + +/* Packet alignment for most efficient SDIO (can change based on platform) */ +#ifndef SDALIGN +#define SDALIGN 32 +#endif + +/* Headroom required for dongle-to-host communication. Packets allocated + * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should + * leave this much room in front for low-level message headers which may + * be needed to get across the dongle bus to the host. (These messages + * don't go over the network, so room for the full WL header above would + * be a waste.). +*/ +#define BCMDONGLEHDRSZ 12 +#define BCMDONGLEPADSZ 16 + +#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) + + +#if defined(NO_BCMDBG_ASSERT) +# undef BCMDBG_ASSERT +# undef BCMASSERT_LOG +#endif + +#if defined(BCMASSERT_LOG) +#define BCMASSERT_SUPPORT +#endif + +/* 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 BCMSMALL to remove misc features for memory-constrained environments */ +#ifdef BCMSMALL +#undef BCMSPACE +#define bcmspace FALSE /* if (bcmspace) code is discarded */ +#else +#define BCMSPACE +#define bcmspace TRUE /* if (bcmspace) code is retained */ +#endif + +/* Max. nvram variable table size */ +#ifndef MAXSZ_NVRAM_VARS +#define MAXSZ_NVRAM_VARS 4096 +#endif + + + +/* WL_ENAB_RUNTIME_CHECK may be set based upon the #define below (for ROM builds). It may also + * be defined via makefiles (e.g. ROM auto abandon unoptimized compiles). + */ + + +#ifdef BCMLFRAG /* BCMLFRAG support enab macros */ + extern bool _bcmlfrag; + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCMLFRAG_ENAB() (_bcmlfrag) + #elif defined(BCMLFRAG_DISABLED) + #define BCMLFRAG_ENAB() (0) + #else + #define BCMLFRAG_ENAB() (1) + #endif +#else + #define BCMLFRAG_ENAB() (0) +#endif /* BCMLFRAG_ENAB */ +#ifdef BCMSPLITRX /* BCMLFRAG support enab macros */ + extern bool _bcmsplitrx; + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCMSPLITRX_ENAB() (_bcmsplitrx) + #elif defined(BCMSPLITRX_DISABLED) + #define BCMSPLITRX_ENAB() (0) + #else + #define BCMSPLITRX_ENAB() (1) + #endif +#else + #define BCMSPLITRX_ENAB() (0) +#endif /* BCMSPLITRX */ +#ifdef BCM_SPLITBUF + extern bool _bcmsplitbuf; + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCM_SPLITBUF_ENAB() (_bcmsplitbuf) + #elif defined(BCM_SPLITBUF_DISABLED) + #define BCM_SPLITBUF_ENAB() (0) + #else + #define BCM_SPLITBUF_ENAB() (1) + #endif +#else + #define BCM_SPLITBUF_ENAB() (0) +#endif /* BCM_SPLITBUF */ +/* Max size for reclaimable NVRAM array */ +#ifdef DL_NVRAM +#define NVRAM_ARRAY_MAXSIZE DL_NVRAM +#else +#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS +#endif /* DL_NVRAM */ + +#ifdef BCMUSBDEV_ENABLED +extern uint32 gFWID; +#endif + + +#endif /* _bcmdefs_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h new file mode 100644 index 000000000000..ebc57c71d56f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h @@ -0,0 +1,689 @@ +/* + * Broadcom device-specific manifest constants. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmdevs.h 527126 2015-01-16 03:33:51Z $ + */ + +#ifndef _BCMDEVS_H +#define _BCMDEVS_H + +/* PCI vendor IDs */ +#define VENDOR_EPIGRAM 0xfeda +#define VENDOR_BROADCOM 0x14e4 +#define VENDOR_3COM 0x10b7 +#define VENDOR_NETGEAR 0x1385 +#define VENDOR_DIAMOND 0x1092 +#define VENDOR_INTEL 0x8086 +#define VENDOR_DELL 0x1028 +#define VENDOR_HP 0x103c +#define VENDOR_HP_COMPAQ 0x0e11 +#define VENDOR_APPLE 0x106b +#define VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */ +#define VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */ +#define VENDOR_TI 0x104c /* Texas Instruments */ +#define VENDOR_RICOH 0x1180 /* Ricoh */ +#define VENDOR_JMICRON 0x197b + + +/* PCMCIA vendor IDs */ +#define VENDOR_BROADCOM_PCMCIA 0x02d0 + +/* SDIO vendor IDs */ +#define VENDOR_BROADCOM_SDIO 0x00BF + +/* DONGLE VID/PIDs */ +#define BCM_DNGL_VID 0x0a5c +#define BCM_DNGL_BL_PID_4328 0xbd12 +#define BCM_DNGL_BL_PID_4322 0xbd13 +#define BCM_DNGL_BL_PID_4319 0xbd16 +#define BCM_DNGL_BL_PID_43236 0xbd17 +#define BCM_DNGL_BL_PID_4332 0xbd18 +#define BCM_DNGL_BL_PID_4330 0xbd19 +#define BCM_DNGL_BL_PID_4334 0xbd1a +#define BCM_DNGL_BL_PID_43239 0xbd1b +#define BCM_DNGL_BL_PID_4324 0xbd1c +#define BCM_DNGL_BL_PID_4360 0xbd1d +#define BCM_DNGL_BL_PID_43143 0xbd1e +#define BCM_DNGL_BL_PID_43242 0xbd1f +#define BCM_DNGL_BL_PID_43342 0xbd21 +#define BCM_DNGL_BL_PID_4335 0xbd20 +#define BCM_DNGL_BL_PID_43341 0xbd22 +#define BCM_DNGL_BL_PID_4350 0xbd23 +#define BCM_DNGL_BL_PID_4345 0xbd24 +#define BCM_DNGL_BL_PID_4349 0xbd25 +#define BCM_DNGL_BL_PID_4354 0xbd26 + +#define BCM_DNGL_BDC_PID 0x0bdc +#define BCM_DNGL_JTAG_PID 0x4a44 + +/* HW USB BLOCK [CPULESS USB] PIDs */ +#define BCM_HWUSB_PID_43239 43239 + +/* PCI Device IDs */ +#define BCM4210_DEVICE_ID 0x1072 /* never used */ +#define BCM4230_DEVICE_ID 0x1086 /* never used */ +#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */ +#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */ +#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */ +#define BCM4211_DEVICE_ID 0x4211 +#define BCM4231_DEVICE_ID 0x4231 +#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */ +#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */ +#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */ +#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */ +#define BCM4328_D11DUAL_ID 0x4314 /* 4328/4312 802.11a/g id */ +#define BCM4328_D11G_ID 0x4315 /* 4328/4312 802.11g id */ +#define BCM4328_D11A_ID 0x4316 /* 4328/4312 802.11a id */ +#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */ +#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */ +#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */ +#define BCM4325_D11DUAL_ID 0x431b /* 4325 802.11a/g id */ +#define BCM4325_D11G_ID 0x431c /* 4325 802.11g id */ +#define BCM4325_D11A_ID 0x431d /* 4325 802.11a id */ +#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */ +#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */ +#define BCM4306_UART_ID 0x4322 /* 4306 uart */ +#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */ +#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */ +#define BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G_ID; INF w/loose binding war */ +#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */ +#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Ghz band id */ +#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */ +#define BCM4322_D11N_ID 0x432b /* 4322 802.11n dualband device */ +#define BCM4322_D11N2G_ID 0x432c /* 4322 802.11n 2.4GHz device */ +#define BCM4322_D11N5G_ID 0x432d /* 4322 802.11n 5GHz device */ +#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */ +#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ +#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ +#define BCM4315_D11DUAL_ID 0x4334 /* 4315 802.11a/g id */ +#define BCM4315_D11G_ID 0x4335 /* 4315 802.11g id */ +#define BCM4315_D11A_ID 0x4336 /* 4315 802.11a id */ +#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 BCM43231_D11N2G_ID 0x4340 /* 43231 802.11n 2.4GHz device */ +#define BCM43221_D11N2G_ID 0x4341 /* 43221 802.11n 2.4GHz device */ +#define BCM43222_D11N_ID 0x4350 /* 43222 802.11n dualband device */ +#define BCM43222_D11N2G_ID 0x4351 /* 43222 802.11n 2.4GHz device */ +#define BCM43222_D11N5G_ID 0x4352 /* 43222 802.11n 5GHz device */ +#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ +#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */ +#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband device */ +#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ +#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ +#define BCM43236_D11N5G_ID 0x4348 /* 43236 802.11n 5GHz device */ +#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ +#define BCM43421_D11N_ID 0xA99D /* 43421 802.11n dualband device */ +#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ +#define BCM4330_D11N_ID 0x4360 /* 4330 802.11n dualband device */ +#define BCM4330_D11N2G_ID 0x4361 /* 4330 802.11n 2.4G device */ +#define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */ +#define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */ +#define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */ +#define BCM6362_D11N2G_ID 0x433f /* 6362 802.11n 2.4Ghz band id */ +#define BCM6362_D11N5G_ID 0x434f /* 6362 802.11n 5Ghz band id */ +#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */ +#define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */ +#define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */ +#define BCM43237_D11N_ID 0x4355 /* 43237 802.11n dualband device */ +#define BCM43237_D11N5G_ID 0x4356 /* 43237 802.11n 5GHz device */ +#define BCM43227_D11N2G_ID 0x4358 /* 43228 802.11n 2.4GHz device */ +#define BCM43228_D11N_ID 0x4359 /* 43228 802.11n DualBand device */ +#define BCM43228_D11N5G_ID 0x435a /* 43228 802.11n 5GHz device */ +#define BCM43362_D11N_ID 0x4363 /* 43362 802.11n 2.4GHz device */ +#define BCM43239_D11N_ID 0x4370 /* 43239 802.11n dualband device */ +#define BCM4324_D11N_ID 0x4374 /* 4324 802.11n dualband device */ +#define BCM43217_D11N2G_ID 0x43a9 /* 43217 802.11n 2.4GHz device */ +#define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */ +#define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */ +#define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */ +#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ +#define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */ +#define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */ +#define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */ +#define BCM43342_D11N_ID 0x4383 /* 43342 802.11n dualband device */ +#define BCM43342_D11N2G_ID 0x4384 /* 43342 802.11n 2.4G device */ +#define BCM43342_D11N5G_ID 0x4385 /* 43342 802.11n 5G device */ +#define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */ +#define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */ +#define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */ +#define BCM4360_D11AC_ID 0x43a0 +#define BCM4360_D11AC2G_ID 0x43a1 +#define BCM4360_D11AC5G_ID 0x43a2 +#define BCM4345_D11AC_ID 0x43ab /* 4345 802.11ac dualband device */ +#define BCM4345_D11AC2G_ID 0x43ac /* 4345 802.11ac 2.4G device */ +#define BCM4345_D11AC5G_ID 0x43ad /* 4345 802.11ac 5G device */ +#define BCM4335_D11AC_ID 0x43ae +#define BCM4335_D11AC2G_ID 0x43af +#define BCM4335_D11AC5G_ID 0x43b0 +#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ +#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ +#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ +#define BCM43602_D11AC_ID 0x43ba /* ac dualband PCI devid SPROM programmed */ +#define BCM43602_D11AC2G_ID 0x43bb /* 43602 802.11ac 2.4G device */ +#define BCM43602_D11AC5G_ID 0x43bc /* 43602 802.11ac 5G device */ + +/* PCI Subsystem ID */ +#define BCM943228HMB_SSID_VEN1 0x0607 +#define BCM94313HMGBL_SSID_VEN1 0x0608 +#define BCM94313HMG_SSID_VEN1 0x0609 +#define BCM943142HM_SSID_VEN1 0x0611 + +#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ + +#define BCM43242_D11N_ID 0x4367 /* 43242 802.11n dualband device */ +#define BCM43242_D11N2G_ID 0x4368 /* 43242 802.11n 2.4G device */ +#define BCM43242_D11N5G_ID 0x4369 /* 43242 802.11n 5G device */ + +#define BCM4350_D11AC_ID 0x43a3 +#define BCM4350_D11AC2G_ID 0x43a4 +#define BCM4350_D11AC5G_ID 0x43a5 + +#define BCM43556_D11AC_ID 0x43b7 +#define BCM43556_D11AC2G_ID 0x43b8 +#define BCM43556_D11AC5G_ID 0x43b9 + +#define BCM43558_D11AC_ID 0x43c0 +#define BCM43558_D11AC2G_ID 0x43c1 +#define BCM43558_D11AC5G_ID 0x43c2 + +#define BCM43566_D11AC_ID 0x43d3 +#define BCM43566_D11AC2G_ID 0x43d4 +#define BCM43566_D11AC5G_ID 0x43d5 + +#define BCM43568_D11AC_ID 0x43d6 +#define BCM43568_D11AC2G_ID 0x43d7 +#define BCM43568_D11AC5G_ID 0x43d8 + +#define BCM43569_D11AC_ID 0x43d9 +#define BCM43569_D11AC2G_ID 0x43da +#define BCM43569_D11AC5G_ID 0x43db + +#define BCM4354_D11AC_ID 0x43df /* 4354 802.11ac dualband device */ +#define BCM4354_D11AC2G_ID 0x43e0 /* 4354 802.11ac 2.4G device */ +#define BCM4354_D11AC5G_ID 0x43e1 /* 4354 802.11ac 5G device */ +#define BCM43430_D11N2G_ID 0x43e2 /* 43430 802.11n 2.4G device */ + + +#define BCM43349_D11N_ID 0x43e6 /* 43349 802.11n dualband id */ +#define BCM43349_D11N2G_ID 0x43e7 /* 43349 802.11n 2.4Ghz band id */ +#define BCM43349_D11N5G_ID 0x43e8 /* 43349 802.11n 5Ghz band id */ + +#define BCM4356_D11AC_ID 0x43ec /* 4356 802.11ac dualband device */ +#define BCM4356_D11AC2G_ID 0x43ed /* 4356 802.11ac 2.4G device */ +#define BCM4356_D11AC5G_ID 0x43ee /* 4356 802.11ac 5G device */ + +#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */ +#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */ +#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */ +#define BCM_JTAGM_ID 0x43f1 /* BCM jtagm device id */ +#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */ +#define BCM_SDIOH_ID 0x43f3 /* BCM sdio host id */ +#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */ +#define SPIH_FPGA_ID 0x43f5 /* PCI SPI Host Controller FPGA */ +#define BCM_SPIH_ID 0x43f6 /* Synopsis SPI Host Controller */ +#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */ +#define BCM_JTAGM2_ID 0x43f9 /* BCM alternate jtagm device id */ +#define SDHCI_FPGA_ID 0x43fa /* Standard SDIO Host Controller FPGA */ +#define BCM4402_ENET_ID 0x4402 /* 4402 enet */ +#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */ +#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */ +#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */ +#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */ +#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */ +#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */ +#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */ +#define BCM47XX_AUDIO_ID 0x4711 /* 47xx audio codec */ +#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */ +#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */ +#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */ +#define BCM47XX_GMAC_ID 0x4715 /* 47xx Unimac based GbE */ +#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */ +#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */ +#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */ +#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */ +#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */ +#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */ +#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */ +#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */ +#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */ +#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */ +#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */ +#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */ +#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */ +#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */ +#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */ +#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */ +#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */ +#define JINVANI_SDIOH_ID 0x4743 /* Jinvani SDIO Gold Host */ +#define BCM27XX_SDIOH_ID 0x2702 /* BCM27xx Standard SDIO Host */ +#define PCIXX21_FLASHMEDIA_ID 0x803b /* TI PCI xx21 Standard Host Controller */ +#define PCIXX21_SDIOH_ID 0x803c /* TI PCI xx21 Standard Host Controller */ +#define R5C822_SDIOH_ID 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */ +#define JMICRON_SDIOH_ID 0x2381 /* JMicron Standard SDIO Host Controller */ + +/* Chip IDs */ +#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */ +#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */ +#define BCM43111_CHIP_ID 43111 /* 43111 chipcommon chipid (OTP chipid) */ +#define BCM43112_CHIP_ID 43112 /* 43112 chipcommon chipid (OTP chipid) */ +#define BCM4312_CHIP_ID 0x4312 /* 4312 chipcommon chipid */ +#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ +#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP chipid) */ +#define BCM4315_CHIP_ID 0x4315 /* 4315 chip id */ +#define BCM4318_CHIP_ID 0x4318 /* 4318 chipcommon chipid */ +#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ +#define BCM4320_CHIP_ID 0x4320 /* 4320 chipcommon chipid */ +#define BCM4321_CHIP_ID 0x4321 /* 4321 chipcommon chipid */ +#define BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP chipid) */ +#define BCM4322_CHIP_ID 0x4322 /* 4322 chipcommon chipid */ +#define BCM43221_CHIP_ID 43221 /* 43221 chipcommon chipid (OTP chipid) */ +#define BCM43222_CHIP_ID 43222 /* 43222 chipcommon chipid */ +#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ +#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ +#define BCM43227_CHIP_ID 43227 /* 43227 chipcommon chipid */ +#define BCM43228_CHIP_ID 43228 /* 43228 chipcommon chipid */ +#define BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */ +#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (OTP chipid) */ +#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */ +#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ +#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ +#define BCM43237_CHIP_ID 43237 /* 43237 chipcommon chipid */ +#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ +#define BCM43239_CHIP_ID 43239 /* 43239 chipcommon chipid */ +#define BCM43420_CHIP_ID 43420 /* 43222 chipcommon chipid (OTP, RBBU) */ +#define BCM43421_CHIP_ID 43421 /* 43224 chipcommon chipid (OTP, RBBU) */ +#define BCM43428_CHIP_ID 43428 /* 43228 chipcommon chipid (OTP, RBBU) */ +#define BCM43431_CHIP_ID 43431 /* 4331 chipcommon chipid (OTP, RBBU) */ +#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ +#define BCM4325_CHIP_ID 0x4325 /* 4325 chip id */ +#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */ +#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ +#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ +#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ +#define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */ +#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ +#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ +#define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */ +#define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */ +#define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */ +#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */ +#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */ +#define BCM43243_CHIP_ID 43243 /* 43243 chipcommon chipid */ +#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */ +#define BCM4335_CHIP_ID 0x4335 /* 4335 chipcommon chipid */ +#define BCM4339_CHIP_ID 0x4339 /* 4339 chipcommon chipid */ +#define BCM43349_CHIP_ID 43349 /* 43349(0xA955) chipcommon chipid */ +#define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */ +#define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */ +#define BCM43526_CHIP_ID 0xAA06 +#define BCM43340_CHIP_ID 43340 /* 43340 chipcommon chipid */ +#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */ +#define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */ +#define BCM4350_CHIP_ID 0x4350 /* 4350 chipcommon chipid */ +#define BCM4354_CHIP_ID 0x4354 /* 4354 chipcommon chipid */ +#define BCM4356_CHIP_ID 0x4356 /* 4356 chipcommon chipid */ +#define BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */ +#define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */ +#define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */ +#define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */ +#define BCM43569_CHIP_ID 0xAA31 /* 43569 chipcommon chipid */ +#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \ + (CHIPID(chipid) == BCM4354_CHIP_ID) || \ + (CHIPID(chipid) == BCM4356_CHIP_ID) || \ + (CHIPID(chipid) == BCM43556_CHIP_ID) || \ + (CHIPID(chipid) == BCM43558_CHIP_ID) || \ + (CHIPID(chipid) == BCM43566_CHIP_ID) || \ + (CHIPID(chipid) == BCM43568_CHIP_ID) || \ + (CHIPID(chipid) == BCM43569_CHIP_ID)) /* 4350 variations */ +#define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */ +#define BCM43454_CHIP_ID 43454 /* 43454 chipcommon chipid */ +#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */ + +#define BCM43602_CHIP_ID 0xaa52 /* 43602 chipcommon chipid */ + +#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */ +#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */ +#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */ +#define BCM4706_CHIP_ID 0x5300 /* 4706 chipcommon chipid */ +#define BCM4707_CHIP_ID 53010 /* 4707 chipcommon chipid */ +#define BCM53018_CHIP_ID 53018 /* 53018 chipcommon chipid */ +#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || ((chipid) == BCM53018_CHIP_ID)) +#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */ +#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */ +#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) */ +#define BCM4749_CHIP_ID 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */ +#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */ +#define BCM5350_CHIP_ID 0x5350 /* 5350 chipcommon chipid */ +#define BCM5352_CHIP_ID 0x5352 /* 5352 chipcommon chipid */ +#define BCM5354_CHIP_ID 0x5354 /* 5354 chipcommon chipid */ +#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */ +#define BCM5356_CHIP_ID 0x5356 /* 5356 chipcommon chipid */ +#define BCM5357_CHIP_ID 0x5357 /* 5357 chipcommon chipid */ +#define BCM53572_CHIP_ID 53572 /* 53572 chipcommon chipid */ + +/* Package IDs */ +#define BCM4303_PKG_ID 2 /* 4303 package id */ +#define BCM4309_PKG_ID 1 /* 4309 package id */ +#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */ +#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */ +#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */ +#define BCM4328USBD11G_PKG_ID 2 /* 4328 802.11g USB package id */ +#define BCM4328USBDUAL_PKG_ID 3 /* 4328 802.11a/g USB package id */ +#define BCM4328SDIOD11G_PKG_ID 4 /* 4328 802.11g SDIO package id */ +#define BCM4328SDIODUAL_PKG_ID 5 /* 4328 802.11a/g SDIO package id */ +#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */ +#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */ +#define BCM5354E_PKG_ID 1 /* 5354E package id */ +#define BCM4716_PKG_ID 8 /* 4716 package id */ +#define BCM4717_PKG_ID 9 /* 4717 package id */ +#define BCM4718_PKG_ID 10 /* 4718 package id */ +#define BCM5356_PKG_NONMODE 1 /* 5356 package without nmode suppport */ +#define BCM5358U_PKG_ID 8 /* 5358U package id */ +#define BCM5358_PKG_ID 9 /* 5358 package id */ +#define BCM47186_PKG_ID 10 /* 47186 package id */ +#define BCM5357_PKG_ID 11 /* 5357 package id */ +#define BCM5356U_PKG_ID 12 /* 5356U package id */ +#define BCM53572_PKG_ID 8 /* 53572 package id */ +#define BCM5357C0_PKG_ID 8 /* 5357c0 package id (the same as 53572) */ +#define BCM47188_PKG_ID 9 /* 47188 package id */ +#define BCM5358C0_PKG_ID 0xa /* 5358c0 package id */ +#define BCM5356C0_PKG_ID 0xb /* 5356c0 package id */ +#define BCM4331TT_PKG_ID 8 /* 4331 12x12 package id */ +#define BCM4331TN_PKG_ID 9 /* 4331 12x9 package id */ +#define BCM4331TNA0_PKG_ID 0xb /* 4331 12x9 package id */ +#define BCM4706L_PKG_ID 1 /* 4706L package id */ + +#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */ +#define HDLSIM_PKG_ID 14 /* HDL simulator package id */ +#define HWSIM_PKG_ID 15 /* Hardware simulator package id */ +#define BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */ +#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ +#define BCM4336_WLBGA_PKG_ID 0x8 +#define BCM4330_WLBGA_PKG_ID 0x0 +#define BCM4314PCIE_ARM_PKG_ID (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */ +#define BCM4314SDIO_PKG_ID (8 | 1) /* 4314 QFN SDIO package id */ +#define BCM4314PCIE_PKG_ID (8 | 2) /* 4314 QFN PCI (ARM-less) package id */ +#define BCM4314SDIO_ARM_PKG_ID (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */ +#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) /* 4314 FpBGA SDIO package id */ +#define BCM4314DEV_PKG_ID (8 | 6) /* 4314 Developement package id */ + +#define BCM4707_PKG_ID 1 /* 4707 package id */ +#define BCM4708_PKG_ID 2 /* 4708 package id */ +#define BCM4709_PKG_ID 0 /* 4709 package id */ + +#define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */ +#define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */ + +#define BCM4335_WLCSP_PKG_ID (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */ +#define BCM4335_FCBGA_PKG_ID (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */ +#define BCM4335_WLBGA_PKG_ID (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */ +#define BCM4335_FCBGAD_PKG_ID (0x3) /* FCBGA Debug Debug/Dev All if's. */ +#define BCM4335_PKG_MASK (0x3) + +/* boardflags */ +#define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */ +#define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */ +#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */ +#define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio 13 radio disable indication, UNUSED */ +#define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */ +#define BFL_DIS_256QAM 0x00000008 +#define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */ +#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */ +#define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */ +#define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */ +#define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */ +#define BFL_UNUSED 0x00000200 +#define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ +#define BFL_FEM 0x00000800 /* Board supports the Front End Module */ +#define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ +#define BFL_HGPA 0x00002000 /* Board has a high gain PA */ +#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */ +#define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */ +#define BFL_NOPA 0x00010000 /* Board has no PA */ +#define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */ +#define BFL_PAREF 0x00040000 /* Board uses the PARef LDO */ +#define BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */ +#define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */ +#define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */ +#define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */ +#define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */ +#define BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */ +#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */ +#define BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */ +#define BFL_FASTPWR 0x08000000 +#define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */ +#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ +#define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */ +#define BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ +#define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */ +#define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field + * when this flag is set + */ +#define BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */ + +/* boardflags2 */ +#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */ +#define BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ +#define BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */ +#define BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */ +#define BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */ +#define BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */ +#define BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */ +#define BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */ +#define BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace + * BFL2_BTC3WIRE + */ +#define BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */ +#define BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */ +#define BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */ +#define BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */ +#define BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ +#define BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */ +#define BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */ +#define BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */ +#define BFL2_DAC_SPUR_IMPROVEMENT 0x00008000 /* Reducing DAC Spurs */ +#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */ +#define BFL2_IPALVLSHIFT_3P3 0x00020000 +#define BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */ +#define BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */ + /* Most drivers will turn it off without this flag */ + /* to save power. */ + +#define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */ +#define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */ +#define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */ +#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */ +#define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value + * than programmed. The exact delta is decided by + * driver per chip/boardtype. This can be used + * when tempsense qualification happens after shipment + */ +#define BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */ +#define BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */ +#define BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save */ + /* ucode control of eLNA during Tx */ +#define BFL2_4313_RADIOREG 0x10000000 + /* board rework */ +#define BFL2_DYNAMIC_VMID 0x10000000 /* enable dynamic Vmid in idle TSSI CAL for 4331 */ + +#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ +#define BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */ +#define BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */ +#define BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */ + +/* SROM 11 - 11ac boardflag definitions */ +#define BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */ +#define BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */ +#define BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ +#define BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ +#define BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ +#define BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ +#define BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */ +#define BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */ +#define BFL2_SROM11_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ + +/* boardflags3 */ +#define BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */ +#define BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */ +#define BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */ +#define BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */ +#define BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */ +#define BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */ +#define BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */ +#define BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */ +#define BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */ +#define BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */ +#define BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */ +#define BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */ +#define BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */ +#define BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */ +#define BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */ +#define BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */ +#define BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */ +#define BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */ +#define BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */ +#define BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */ +/* acphy, to use backed off gaintbl for lte-coex */ +#define BFL3_LTECOEX_GAINTBL_EN 0x00060000 +/* acphy, to use backed off gaintbl for lte-coex */ +#define BFL3_LTECOEX_GAINTBL_EN_SHIFT 17 +#define BFL3_5G_SPUR_WAR 0x00080000 /* acphy, enable spur WAR in 5G band */ + +/* acphy: lpmode2g and lpmode_5g related boardflags */ +#define BFL3_ACPHY_LPMODE_2G 0x00300000 /* bits 20:21 for lpmode_2g choice */ +#define BFL3_ACPHY_LPMODE_2G_SHIFT 20 + +#define BFL3_ACPHY_LPMODE_5G 0x00C00000 /* bits 22:23 for lpmode_5g choice */ +#define BFL3_ACPHY_LPMODE_5G_SHIFT 22 + +#define BFL3_EXT_LPO_ISCLOCK 0x02000000 /* External LPO is clock, not x-tal */ +#define BFL3_FORCE_INT_LPO_SEL 0x04000000 /* Force internal lpo */ +#define BFL3_FORCE_EXT_LPO_SEL 0x08000000 /* Force external lpo */ + +#define BFL3_EN_BRCM_IMPBF 0x10000000 /* acphy, Allow BRCM Implicit TxBF */ +#define BFL3_AVVMID_FROM_NVRAM 0x40000000 /* Read Av Vmid from NVRAM */ +#define BFL3_VLIN_EN_FROM_NVRAM 0x80000000 /* Read Vlin En from NVRAM */ + +#define BFL3_AVVMID_FROM_NVRAM_SHIFT 30 /* Read Av Vmid from NVRAM */ +#define BFL3_VLIN_EN_FROM_NVRAM_SHIFT 31 /* Enable Vlin from NVRAM */ + + +/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */ +#define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ +#define BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */ +#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */ +#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */ +#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */ +#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */ +#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */ +#define BOARD_GPIO_12 0x1000 /* gpio 12 */ +#define BOARD_GPIO_13 0x2000 /* gpio 13 */ +#define BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */ +#define BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */ +#define BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */ +#define BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */ +#define BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */ +#define BOARD_GPIO_2_WLAN_PWR 0x04 /* throttle WLAN power on X29C board */ +#define BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */ +#define BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */ + +#define GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */ +#define GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */ +#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */ +#define GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */ +#define GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */ +#define GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */ +#define GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */ + +#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ +#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ +#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal power-up */ +#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL power-down */ + +/* power control defines */ +#define PLL_DELAY 150 /* us pll on delay */ +#define FREF_DELAY 200 /* us fref change delay */ +#define MIN_SLOW_CLK 32 /* us Slow clock period */ +#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ + + +/* 43341 Boards */ +#define BCM943341WLABGS_SSID 0x062d + +/* 43342 Boards */ +#define BCM943342FCAGBI_SSID 0x0641 + +/* 43602 Boards, unclear yet what boards will be created. */ +#define BCM943602RSVD1_SSID 0x06a5 +#define BCM943602RSVD2_SSID 0x06a6 + +/* # of GPIO pins */ +#define GPIO_NUMPINS 32 + +/* These values are used by dhd host driver. */ +#define RDL_RAM_BASE_4319 0x60000000 +#define RDL_RAM_BASE_4329 0x60000000 +#define RDL_RAM_SIZE_4319 0x48000 +#define RDL_RAM_SIZE_4329 0x48000 +#define RDL_RAM_SIZE_43236 0x70000 +#define RDL_RAM_BASE_43236 0x60000000 +#define RDL_RAM_SIZE_4328 0x60000 +#define RDL_RAM_BASE_4328 0x80000000 +#define RDL_RAM_SIZE_4322 0x60000 +#define RDL_RAM_BASE_4322 0x60000000 +#define RDL_RAM_SIZE_4360 0xA0000 +#define RDL_RAM_BASE_4360 0x60000000 +#define RDL_RAM_SIZE_43242 0x90000 +#define RDL_RAM_BASE_43242 0x60000000 +#define RDL_RAM_SIZE_43143 0x70000 +#define RDL_RAM_BASE_43143 0x60000000 +#define RDL_RAM_SIZE_4350 0xC0000 +#define RDL_RAM_BASE_4350 0x180800 + +/* generic defs for nvram "muxenab" bits +* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options. +*/ +#define MUXENAB_UART 0x00000001 +#define MUXENAB_GPIO 0x00000002 +#define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */ +#define MUXENAB_JTAG 0x00000008 +#define MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */ +#define MUXENAB_I2S_EN 0x00000020 +#define MUXENAB_I2S_MASTER 0x00000040 +#define MUXENAB_I2S_FULL 0x00000080 +#define MUXENAB_SFLASH 0x00000100 +#define MUXENAB_RFSWCTRL0 0x00000200 +#define MUXENAB_RFSWCTRL1 0x00000400 +#define MUXENAB_RFSWCTRL2 0x00000800 +#define MUXENAB_SECI 0x00001000 +#define MUXENAB_BT_LEGACY 0x00002000 +#define MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */ + +/* Boot flags */ +#define FLASH_KERNEL_NFLASH 0x00000001 +#define FLASH_BOOT_NFLASH 0x00000002 + +#endif /* _BCMDEVS_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h new file mode 100644 index 000000000000..970989e38f6b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h @@ -0,0 +1,329 @@ +/* + * Byte order utilities + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmendian.h 402715 2013-05-16 18:50:09Z $ + * + * This file by default provides proper behavior on little-endian architectures. + * On big-endian architectures, IL_BIGENDIAN should be defined. + */ + +#ifndef _BCMENDIAN_H_ +#define _BCMENDIAN_H_ + +#include + +/* Reverse the bytes in a 16-bit value */ +#define BCMSWAP16(val) \ + ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ + (((uint16)(val) & (uint16)0xff00U) >> 8))) + +/* Reverse the bytes in a 32-bit value */ +#define BCMSWAP32(val) \ + ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ + (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ + (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ + (((uint32)(val) & (uint32)0xff000000U) >> 24))) + +/* Reverse the two 16-bit halves of a 32-bit value */ +#define BCMSWAP32BY16(val) \ + ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ + (((uint32)(val) & (uint32)0xffff0000U) >> 16))) + +/* Reverse the bytes in a 64-bit value */ +#define BCMSWAP64(val) \ + ((uint64)((((uint64)(val) & 0x00000000000000ffULL) << 56) | \ + (((uint64)(val) & 0x000000000000ff00ULL) << 40) | \ + (((uint64)(val) & 0x0000000000ff0000ULL) << 24) | \ + (((uint64)(val) & 0x00000000ff000000ULL) << 8) | \ + (((uint64)(val) & 0x000000ff00000000ULL) >> 8) | \ + (((uint64)(val) & 0x0000ff0000000000ULL) >> 24) | \ + (((uint64)(val) & 0x00ff000000000000ULL) >> 40) | \ + (((uint64)(val) & 0xff00000000000000ULL) >> 56))) + +/* Reverse the two 32-bit halves of a 64-bit value */ +#define BCMSWAP64BY32(val) \ + ((uint64)((((uint64)(val) & 0x00000000ffffffffULL) << 32) | \ + (((uint64)(val) & 0xffffffff00000000ULL) >> 32))) + + +/* Byte swapping macros + * Host <=> Network (Big Endian) for 16- and 32-bit values + * Host <=> Little-Endian for 16- and 32-bit values + */ +#ifndef hton16 +#define HTON16(i) BCMSWAP16(i) +#define hton16(i) bcmswap16(i) +#define HTON32(i) BCMSWAP32(i) +#define hton32(i) bcmswap32(i) +#define NTOH16(i) BCMSWAP16(i) +#define ntoh16(i) bcmswap16(i) +#define NTOH32(i) BCMSWAP32(i) +#define ntoh32(i) bcmswap32(i) +#define LTOH16(i) (i) +#define ltoh16(i) (i) +#define LTOH32(i) (i) +#define ltoh32(i) (i) +#define HTOL16(i) (i) +#define htol16(i) (i) +#define HTOL32(i) (i) +#define htol32(i) (i) +#define HTOL64(i) (i) +#define htol64(i) (i) +#endif /* hton16 */ + +#define ltoh16_buf(buf, i) +#define htol16_buf(buf, i) + +/* Unaligned loads and stores in host byte order */ +#define load32_ua(a) ltoh32_ua(a) +#define store32_ua(a, v) htol32_ua_store(v, a) +#define load16_ua(a) ltoh16_ua(a) +#define store16_ua(a, v) htol16_ua_store(v, a) + +#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) +#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) +#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) +#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) + +#define ltoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#define ntoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#ifdef __GNUC__ + +/* GNU macro versions avoid referencing the argument multiple times, while also + * avoiding the -fno-inline used in ROM builds. + */ + +#define bcmswap16(val) ({ \ + uint16 _val = (val); \ + BCMSWAP16(_val); \ +}) + +#define bcmswap32(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32(_val); \ +}) + +#define bcmswap64(val) ({ \ + uint64 _val = (val); \ + BCMSWAP64(_val); \ +}) + +#define bcmswap32by16(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32BY16(_val); \ +}) + +#define bcmswap16_buf(buf, len) ({ \ + uint16 *_buf = (uint16 *)(buf); \ + uint _wds = (len) / 2; \ + while (_wds--) { \ + *_buf = bcmswap16(*_buf); \ + _buf++; \ + } \ +}) + +#define htol16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = _val >> 8; \ +}) + +#define htol32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = (_val >> 8) & 0xff; \ + _bytes[2] = (_val >> 16) & 0xff; \ + _bytes[3] = _val >> 24; \ +}) + +#define hton16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 8; \ + _bytes[1] = _val & 0xff; \ +}) + +#define hton32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 24; \ + _bytes[1] = (_val >> 16) & 0xff; \ + _bytes[2] = (_val >> 8) & 0xff; \ + _bytes[3] = _val & 0xff; \ +}) + +#define ltoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH16_UA(_bytes); \ +}) + +#define ltoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH32_UA(_bytes); \ +}) + +#define ntoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH16_UA(_bytes); \ +}) + +#define ntoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH32_UA(_bytes); \ +}) + +#else /* !__GNUC__ */ + +/* Inline versions avoid referencing the argument multiple times */ +static INLINE uint16 +bcmswap16(uint16 val) +{ + return BCMSWAP16(val); +} + +static INLINE uint32 +bcmswap32(uint32 val) +{ + return BCMSWAP32(val); +} + +static INLINE uint64 +bcmswap64(uint64 val) +{ + return BCMSWAP64(val); +} + +static INLINE uint32 +bcmswap32by16(uint32 val) +{ + return BCMSWAP32BY16(val); +} + +/* Reverse pairs of bytes in a buffer (not for high-performance use) */ +/* buf - start of buffer of shorts to swap */ +/* len - byte length of buffer */ +static INLINE void +bcmswap16_buf(uint16 *buf, uint len) +{ + len = len / 2; + + while (len--) { + *buf = bcmswap16(*buf); + buf++; + } +} + +/* + * Store 16-bit value to unaligned little-endian byte array. + */ +static INLINE void +htol16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[0] = val & 0xff; + bytes[1] = val >> 8; +} + +/* + * Store 32-bit value to unaligned little-endian byte array. + */ +static INLINE void +htol32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[0] = val & 0xff; + bytes[1] = (val >> 8) & 0xff; + bytes[2] = (val >> 16) & 0xff; + bytes[3] = val >> 24; +} + +/* + * Store 16-bit value to unaligned network-(big-)endian byte array. + */ +static INLINE void +hton16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[0] = val >> 8; + bytes[1] = val & 0xff; +} + +/* + * Store 32-bit value to unaligned network-(big-)endian byte array. + */ +static INLINE void +hton32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[0] = val >> 24; + bytes[1] = (val >> 16) & 0xff; + bytes[2] = (val >> 8) & 0xff; + bytes[3] = val & 0xff; +} + +/* + * Load 16-bit value from unaligned little-endian byte array. + */ +static INLINE uint16 +ltoh16_ua(const void *bytes) +{ + return _LTOH16_UA((const uint8 *)bytes); +} + +/* + * Load 32-bit value from unaligned little-endian byte array. + */ +static INLINE uint32 +ltoh32_ua(const void *bytes) +{ + return _LTOH32_UA((const uint8 *)bytes); +} + +/* + * Load 16-bit value from unaligned big-(network-)endian byte array. + */ +static INLINE uint16 +ntoh16_ua(const void *bytes) +{ + return _NTOH16_UA((const uint8 *)bytes); +} + +/* + * Load 32-bit value from unaligned big-(network-)endian byte array. + */ +static INLINE uint32 +ntoh32_ua(const void *bytes) +{ + return _NTOH32_UA((const uint8 *)bytes); +} + +#endif /* !__GNUC__ */ +#endif /* !_BCMENDIAN_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h new file mode 100644 index 000000000000..3fbc303bd528 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h @@ -0,0 +1,272 @@ +/* + * NVRAM variable manipulation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmnvram.h 428512 2013-10-09 02:12:11Z $ + */ + +#ifndef _bcmnvram_h_ +#define _bcmnvram_h_ + +#ifndef _LANGUAGE_ASSEMBLY + +#include +#include + +struct nvram_header { + uint32 magic; + uint32 len; + uint32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ + uint32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ + uint32 config_ncdl; /* ncdl values for memc */ +}; + +struct nvram_tuple { + char *name; + char *value; + struct nvram_tuple *next; +}; + +/* + * Get default value for an NVRAM variable + */ +extern char *nvram_default_get(const char *name); +/* + * validate/restore all per-interface related variables + */ +extern void nvram_validate_all(char *prefix, bool restore); + +/* + * restore specific per-interface variable + */ +extern void nvram_restore_var(char *prefix, char *name); + +/* + * Initialize NVRAM access. May be unnecessary or undefined on certain + * platforms. + */ +extern int nvram_init(void *sih); +extern int nvram_deinit(void *sih); + + +/* + * Append a chunk of nvram variables to the global list + */ +extern int nvram_append(void *si, char *vars, uint varsz); + +extern void nvram_get_global_vars(char **varlst, uint *varsz); + + +/* + * Check for reset button press for restoring factory defaults. + */ +extern int nvram_reset(void *sih); + +/* + * Disable NVRAM access. May be unnecessary or undefined on certain + * platforms. + */ +extern void nvram_exit(void *sih); + +/* + * Get the value of an NVRAM variable. The pointer returned may be + * invalid after a set. + * @param name name of variable to get + * @return value of variable or NULL if undefined + */ +extern char * nvram_get(const char *name); + +/* + * Read the reset GPIO value from the nvram and set the GPIO + * as input + */ +extern int nvram_resetgpio_init(void *sih); + +/* + * Get the value of an NVRAM variable. + * @param name name of variable to get + * @return value of variable or NUL if undefined + */ +static INLINE char * +nvram_safe_get(const char *name) +{ + char *p = nvram_get(name); + return p ? p : ""; +} + +/* + * Match an NVRAM variable. + * @param name name of variable to match + * @param match value to compare against value of variable + * @return TRUE if variable is defined and its value is string equal + * to match or FALSE otherwise + */ +static INLINE int +nvram_match(const char *name, const char *match) +{ + const char *value = nvram_get(name); + return (value && !strcmp(value, match)); +} + +/* + * Inversely match an NVRAM variable. + * @param name name of variable to match + * @param match value to compare against value of variable + * @return TRUE if variable is defined and its value is not string + * equal to invmatch or FALSE otherwise + */ +static INLINE int +nvram_invmatch(const char *name, const char *invmatch) +{ + const char *value = nvram_get(name); + return (value && strcmp(value, invmatch)); +} + +/* + * Set the value of an NVRAM variable. The name and value strings are + * copied into private storage. Pointers to previously set values + * may become invalid. The new value may be immediately + * retrieved but will not be permanently stored until a commit. + * @param name name of variable to set + * @param value value of variable + * @return 0 on success and errno on failure + */ +extern int nvram_set(const char *name, const char *value); + +/* + * Unset an NVRAM variable. Pointers to previously set values + * remain valid until a set. + * @param name name of variable to unset + * @return 0 on success and errno on failure + * NOTE: use nvram_commit to commit this change to flash. + */ +extern int nvram_unset(const char *name); + +/* + * Commit NVRAM variables to permanent storage. All pointers to values + * may be invalid after a commit. + * NVRAM values are undefined after a commit. + * @param nvram_corrupt true to corrupt nvram, false otherwise. + * @return 0 on success and errno on failure + */ +extern int nvram_commit_internal(bool nvram_corrupt); + +/* + * Commit NVRAM variables to permanent storage. All pointers to values + * may be invalid after a commit. + * NVRAM values are undefined after a commit. + * @return 0 on success and errno on failure + */ +extern int nvram_commit(void); + +/* + * Get all NVRAM variables (format name=value\0 ... \0\0). + * @param buf buffer to store variables + * @param count size of buffer in bytes + * @return 0 on success and errno on failure + */ +extern int nvram_getall(char *nvram_buf, int count); + +/* + * returns the crc value of the nvram + * @param nvh nvram header pointer + */ +uint8 nvram_calc_crc(struct nvram_header * nvh); + +extern int nvram_space; +#endif /* _LANGUAGE_ASSEMBLY */ + +/* The NVRAM version number stored as an NVRAM variable */ +#define NVRAM_SOFTWARE_VERSION "1" + +#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */ +#define NVRAM_CLEAR_MAGIC 0x0 +#define NVRAM_INVALID_MAGIC 0xFFFFFFFF +#define NVRAM_VERSION 1 +#define NVRAM_HEADER_SIZE 20 +/* This definition is for precommit staging, and will be removed */ +#define NVRAM_SPACE 0x8000 +/* For CFE builds this gets passed in thru the makefile */ +#ifndef MAX_NVRAM_SPACE +#define MAX_NVRAM_SPACE 0x10000 +#endif +#define DEF_NVRAM_SPACE 0x8000 +#define ROM_ENVRAM_SPACE 0x1000 +#define NVRAM_LZMA_MAGIC 0x4c5a4d41 /* 'LZMA' */ + +#define NVRAM_MAX_VALUE_LEN 255 +#define NVRAM_MAX_PARAM_LEN 64 + +#define NVRAM_CRC_START_POSITION 9 /* magic, len, crc8 to be skipped */ +#define NVRAM_CRC_VER_MASK 0xffffff00 /* for crc_ver_init */ + +/* Offsets to embedded nvram area */ +#define NVRAM_START_COMPRESSED 0x400 +#define NVRAM_START 0x1000 + +#define BCM_JUMBO_NVRAM_DELIMIT '\n' +#define BCM_JUMBO_START "Broadcom Jumbo Nvram file" + + +#if (defined(FAILSAFE_UPGRADE) || defined(CONFIG_FAILSAFE_UPGRADE) || \ + defined(__CONFIG_FAILSAFE_UPGRADE_SUPPORT__)) +#define IMAGE_SIZE "image_size" +#define BOOTPARTITION "bootpartition" +#define IMAGE_BOOT BOOTPARTITION +#define PARTIALBOOTS "partialboots" +#define MAXPARTIALBOOTS "maxpartialboots" +#define IMAGE_1ST_FLASH_TRX "flash0.trx" +#define IMAGE_1ST_FLASH_OS "flash0.os" +#define IMAGE_2ND_FLASH_TRX "flash0.trx2" +#define IMAGE_2ND_FLASH_OS "flash0.os2" +#define IMAGE_FIRST_OFFSET "image_first_offset" +#define IMAGE_SECOND_OFFSET "image_second_offset" +#define LINUX_FIRST "linux" +#define LINUX_SECOND "linux2" +#endif + +#if (defined(DUAL_IMAGE) || defined(CONFIG_DUAL_IMAGE) || \ + defined(__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__)) +/* Shared by all: CFE, Linux Kernel, and Ap */ +#define IMAGE_BOOT "image_boot" +#define BOOTPARTITION IMAGE_BOOT +/* CFE variables */ +#define IMAGE_1ST_FLASH_TRX "flash0.trx" +#define IMAGE_1ST_FLASH_OS "flash0.os" +#define IMAGE_2ND_FLASH_TRX "flash0.trx2" +#define IMAGE_2ND_FLASH_OS "flash0.os2" +#define IMAGE_SIZE "image_size" + +/* CFE and Linux Kernel shared variables */ +#define IMAGE_FIRST_OFFSET "image_first_offset" +#define IMAGE_SECOND_OFFSET "image_second_offset" + +/* Linux application variables */ +#define LINUX_FIRST "linux" +#define LINUX_SECOND "linux2" +#define POLICY_TOGGLE "toggle" +#define LINUX_PART_TO_FLASH "linux_to_flash" +#define LINUX_FLASH_POLICY "linux_flash_policy" + +#endif /* defined(DUAL_IMAGE||CONFIG_DUAL_IMAGE)||__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__ */ + +#endif /* _bcmnvram_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h new file mode 100644 index 000000000000..d4781abb982a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h @@ -0,0 +1,181 @@ +/* + * Broadcom PCI-SPI Host Controller Register Definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmpcispi.h 241182 2011-02-17 21:50:03Z $ + */ +#ifndef _BCM_PCI_SPI_H +#define _BCM_PCI_SPI_H + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif /* PAD */ + + +typedef volatile struct { + uint32 spih_ctrl; /* 0x00 SPI Control Register */ + uint32 spih_stat; /* 0x04 SPI Status Register */ + uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ + uint32 spih_ext; /* 0x0C SPI Extension Register */ + uint32 PAD[4]; /* 0x10-0x1F PADDING */ + + uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ + uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ + uint32 PAD[6]; /* 0x28-0x3F PADDING */ + + uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ + uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ + /* 1=Active High) */ + uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ + uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ + uint32 PAD[4]; /* 0x50-0x5F PADDING */ + + uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ + uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ + uint32 PAD[1]; /* 0x68 PADDING */ + uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ + uint32 PAD[4]; /* 0x70-0x7F PADDING */ + uint32 PAD[8]; /* 0x80-0x9F PADDING */ + uint32 PAD[8]; /* 0xA0-0xBF PADDING */ + uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ + uint32 spih_pll_status; /* 0xC4 PLL Status Register */ + uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ + uint32 spih_clk_count; /* 0xCC External Clock Count Register */ + +} spih_regs_t; + +typedef volatile struct { + uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ + uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ + + uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ + uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ + uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ + uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ + uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ + uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ + uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ + uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ + uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ + uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ + uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ + uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ + uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ + uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ + uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ + uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ + uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ + uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ + uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ + uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ + uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ + uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ + uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ + uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ + uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ + uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ + + uint32 PAD[5]; /* 0x16C-0x17F PADDING */ + + uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ + uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ + uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ + uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ + uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ + uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ + uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ + uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ + uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ + uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ + uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ + uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ + uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ + uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ + uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ + uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ + uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ + uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ + uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ + uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ + uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ + uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ + uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ + uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ + uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ + uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ + + uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ + uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ + uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ +} spih_pciregs_t; + +/* + * PCI Core interrupt enable and status bit definitions. + */ + +/* PCI Core ICR Register bit definitions */ +#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ +#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ +#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ +#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ +#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ +#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ + + +/* PCI Core ISR Register bit definitions */ +#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ +#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ +#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ +#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ +#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ + + +/* Registers on the Wishbone bus */ +#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ +#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ +#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ + +/* GPIO Bit definitions */ +#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ +#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ +#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ + +/* SPI Status Register Bit definitions */ +#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ +#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ +#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ +#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ +#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ +#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ + +#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ + +#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ +#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ + +/* Spin bit loop bound check */ +#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ + +#endif /* _BCM_PCI_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h new file mode 100644 index 000000000000..84c232f8a059 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h @@ -0,0 +1,36 @@ +/* + * Performance counters software interface. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmperf.h 241182 2011-02-17 21:50:03Z $ + */ +/* essai */ +#ifndef _BCMPERF_H_ +#define _BCMPERF_H_ +/* get cache hits and misses */ +#define BCMPERF_ENABLE_INSTRCOUNT() +#define BCMPERF_ENABLE_ICACHE_MISS() +#define BCMPERF_ENABLE_ICACHE_HIT() +#define BCMPERF_GETICACHE_MISS(x) ((x) = 0) +#define BCMPERF_GETICACHE_HIT(x) ((x) = 0) +#define BCMPERF_GETINSTRCOUNT(x) ((x) = 0) +#endif /* _BCMPERF_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h new file mode 100644 index 000000000000..4d4634ba6585 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h @@ -0,0 +1,143 @@ +/* + * Definitions for API from sdio common code (bcmsdh) to individual + * host controller drivers. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdbus.h 408158 2013-06-17 22:15:35Z $ + */ + +#ifndef _sdio_api_h_ +#define _sdio_api_h_ + + +#define SDIOH_API_RC_SUCCESS (0x00) +#define SDIOH_API_RC_FAIL (0x01) +#define SDIOH_API_SUCCESS(status) (status == 0) + +#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 */ + +#define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */ +#define SDIOH_CMD_TYPE_APPEND 1 /* Append command */ +#define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */ + +#define SDIOH_DATA_PIO 0 /* PIO mode */ +#define SDIOH_DATA_DMA 1 /* DMA mode */ + +/* Max number of glommed pkts */ +#ifdef CUSTOM_MAX_TXGLOM_SIZE +#define SDPCM_MAXGLOM_SIZE CUSTOM_MAX_TXGLOM_SIZE +#else +#define SDPCM_MAXGLOM_SIZE 40 +#endif /* CUSTOM_MAX_TXGLOM_SIZE */ + +#define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ +#define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ + +#ifdef CUSTOM_DEF_TXGLOM_SIZE +#define SDPCM_DEFGLOM_SIZE CUSTOM_DEF_TXGLOM_SIZE +#else +#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE +#endif /* CUSTOM_DEF_TXGLOM_SIZE */ + +#if SDPCM_DEFGLOM_SIZE > SDPCM_MAXGLOM_SIZE +#warning "SDPCM_DEFGLOM_SIZE cannot be higher than SDPCM_MAXGLOM_SIZE!!" +#undef SDPCM_DEFGLOM_SIZE +#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE +#endif + +typedef int SDIOH_API_RC; + +/* SDio Host structure */ +typedef struct sdioh_info sdioh_info_t; + +/* callback function, taking one arg */ +typedef void (*sdioh_cb_fn_t)(void *); + +extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); +extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); + +/* query whether SD interrupt is enabled or not */ +extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff); + +/* enable or disable SD interrupt */ +extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); + +#if defined(DHD_DEBUG) +extern bool sdioh_interrupt_pending(sdioh_info_t *si); +#endif + +/* read or write one byte using cmd52 */ +extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte); + +/* read or write 2/4 bytes using cmd53 */ +extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *si, uint cmd_type, uint rw, uint fnc, + uint addr, uint32 *word, uint nbyte); + +/* read or write any buffer using cmd53 */ +extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc, + uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer, + void *pkt); + +/* get cis data */ +extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); + +extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); +extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); + +/* query number of io functions */ +extern uint sdioh_query_iofnum(sdioh_info_t *si); + +/* handle iovars */ +extern int sdioh_iovar_op(sdioh_info_t *si, const char *name, + void *params, int plen, void *arg, int len, bool set); + +/* Issue abort to the specified function and clear controller as needed */ +extern int sdioh_abort(sdioh_info_t *si, uint fnc); + +/* Start and Stop SDIO without re-enumerating the SD card. */ +extern int sdioh_start(sdioh_info_t *si, int stage); +extern int sdioh_stop(sdioh_info_t *si); + +/* Wait system lock free */ +extern int sdioh_waitlockfree(sdioh_info_t *si); + +/* Reset and re-initialize the device */ +extern int sdioh_sdio_reset(sdioh_info_t *si); + + + +#if defined(BCMSDIOH_STD) + #define SDIOH_SLEEP_ENABLED +#endif +extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab); + +/* GPIO support */ +extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd); +extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio); +extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio); +extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab); + +#endif /* _sdio_api_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h new file mode 100644 index 000000000000..099120a34d60 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h @@ -0,0 +1,251 @@ +/* + * SDIO host client driver interface of Broadcom HNBU + * export functions to client drivers + * abstract OS and BUS specific details of SDIO + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh.h 455573 2014-02-14 17:49:31Z $ + */ + +/** + * @file bcmsdh.h + */ + +#ifndef _bcmsdh_h_ +#define _bcmsdh_h_ + +#define BCMSDH_ERROR_VAL 0x0001 /* Error */ +#define BCMSDH_INFO_VAL 0x0002 /* Info */ +extern const uint bcmsdh_msglevel; + +#define BCMSDH_ERROR(x) +#define BCMSDH_INFO(x) + +#if (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || defined(BCMSDIOH_SPI)) +#define BCMSDH_ADAPTER +#endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */ + +/* forward declarations */ +typedef struct bcmsdh_info bcmsdh_info_t; +typedef void (*bcmsdh_cb_fn_t)(void *); + +extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva); +/** + * BCMSDH API context + */ +struct bcmsdh_info +{ + bool init_success; /* underlying driver successfully attached */ + void *sdioh; /* handler for sdioh */ + uint32 vendevid; /* Target Vendor and Device ID on SD bus */ + osl_t *osh; + bool regfail; /* Save status of last reg_read/reg_write call */ + uint32 sbwad; /* Save backplane window address */ + void *os_cxt; /* Pointer to per-OS private data */ +}; + +/* Detach - freeup resources allocated in attach */ +extern int bcmsdh_detach(osl_t *osh, void *sdh); + +/* Query if SD device interrupts are enabled */ +extern bool bcmsdh_intr_query(void *sdh); + +/* Enable/disable SD interrupt */ +extern int bcmsdh_intr_enable(void *sdh); +extern int bcmsdh_intr_disable(void *sdh); + +/* Register/deregister device interrupt handler. */ +extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); +extern int bcmsdh_intr_dereg(void *sdh); +/* Enable/disable SD card interrupt forward */ +extern void bcmsdh_intr_forward(void *sdh, bool pass); + +#if defined(DHD_DEBUG) +/* Query pending interrupt status from the host controller */ +extern bool bcmsdh_intr_pending(void *sdh); +#endif + +/* Register a callback to be called if and when bcmsdh detects + * device removal. No-op in the case of non-removable/hardwired devices. + */ +extern int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); + +/* 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 uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err); +extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err); + +/* Read/Write 4bytes from/to cfg space */ +extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err); +extern void bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err); + +/* Read CIS content for specified function. + * fn: function whose CIS is being requested (0 is common CIS) + * cis: pointer to memory location to place results + * length: number of bytes to read + * Internally, this routine uses the values from the cis base regs (0x9-0xB) + * to form an SDIO-space address to read the data from. + */ +extern int bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length); + +/* 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 uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size); +extern uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data); + +/* set sb address window */ +extern int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set); + +/* Indicate if last reg read/write failed */ +extern bool bcmsdh_regfail(void *sdh); + +/* 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. + */ +typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting); +extern int bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, void *pkt, + bcmsdh_cmplt_fn_t complete_fn, void *handle); +extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, + uint8 *buf, uint nbytes, void *pkt, + bcmsdh_cmplt_fn_t complete_fn, void *handle); + +extern void bcmsdh_glom_post(void *sdh, uint8 *frame, void *pkt, uint len); +extern void bcmsdh_glom_clear(void *sdh); +extern uint bcmsdh_set_mode(void *sdh, uint mode); +extern bool bcmsdh_glom_enabled(void); +/* Flags bits */ +#define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */ +#define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */ +#define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */ +#define SDIO_BYTE_MODE 0x8 /* Byte mode request(non-block mode) */ + +/* Pending (non-error) return code */ +#define BCME_PENDING 1 + +/* 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 bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes); + +/* Issue an abort to the specified function */ +extern int bcmsdh_abort(void *sdh, uint fn); + +/* Start SDIO Host Controller communication */ +extern int bcmsdh_start(void *sdh, int stage); + +/* Stop SDIO Host Controller communication */ +extern int bcmsdh_stop(void *sdh); + +/* Wait system lock free */ +extern int bcmsdh_waitlockfree(void *sdh); + +/* Returns the "Device ID" of target device on the SDIO bus. */ +extern int bcmsdh_query_device(void *sdh); + +/* Returns the number of IO functions reported by the device */ +extern uint bcmsdh_query_iofnum(void *sdh); + +/* Miscellaneous knob tweaker. */ +extern int bcmsdh_iovar_op(void *sdh, const char *name, + void *params, int plen, void *arg, int len, bool set); + +/* Reset and reinitialize the device */ +extern int bcmsdh_reset(bcmsdh_info_t *sdh); + +/* helper functions */ + +/* callback functions */ +typedef struct { + /* probe the device */ + void *(*probe)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot, + uint16 func, uint bustype, void * regsva, osl_t * osh, + void * param); + /* remove the device */ + void (*remove)(void *context); + /* can we suspend now */ + int (*suspend)(void *context); + /* resume from suspend */ + int (*resume)(void *context); +} bcmsdh_driver_t; + +/* platform specific/high level functions */ +extern int bcmsdh_register(bcmsdh_driver_t *driver); +extern void bcmsdh_unregister(void); +extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device); +extern void bcmsdh_device_remove(void * sdh); + +extern int bcmsdh_reg_sdio_notify(void* semaphore); +extern void bcmsdh_unreg_sdio_notify(void); + +#if defined(OOB_INTR_ONLY) +extern int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, + void* oob_irq_handler_context); +extern void bcmsdh_oob_intr_unregister(bcmsdh_info_t *sdh); +extern void bcmsdh_oob_intr_set(bcmsdh_info_t *sdh, bool enable); +#endif +extern void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *sdh); +extern void bcmsdh_dev_relax(bcmsdh_info_t *sdh); +extern bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *sdh); + +int bcmsdh_suspend(bcmsdh_info_t *bcmsdh); +int bcmsdh_resume(bcmsdh_info_t *bcmsdh); + +/* Function to pass device-status bits to DHD. */ +extern uint32 bcmsdh_get_dstatus(void *sdh); + +/* Function to return current window addr */ +extern uint32 bcmsdh_cur_sbwad(void *sdh); + +/* Function to pass chipid and rev to lower layers for controlling pr's */ +extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); + + +extern int bcmsdh_sleep(void *sdh, bool enab); + +/* GPIO support */ +extern int bcmsdh_gpio_init(void *sd); +extern bool bcmsdh_gpioin(void *sd, uint32 gpio); +extern int bcmsdh_gpioouten(void *sd, uint32 gpio); +extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); + +#endif /* _bcmsdh_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h new file mode 100644 index 000000000000..5ad8ae077270 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h @@ -0,0 +1,117 @@ +/* + * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdh_sdmmc.h 444019 2013-12-18 08:36:54Z $ + */ + +#ifndef __BCMSDH_SDMMC_H__ +#define __BCMSDH_SDMMC_H__ + +#define sd_err(x) +#define sd_trace(x) +#define sd_info(x) +#define sd_debug(x) +#define sd_data(x) +#define sd_ctrl(x) + + +#define sd_sync_dma(sd, read, nbytes) +#define sd_init_dma(sd) +#define sd_ack_intr(sd) +#define sd_wakeup(sd); + +#define sd_log(x) + +#define SDIOH_ASSERT(exp) \ + do { if (!(exp)) \ + printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ + } while (0) + +#define BLOCK_SIZE_4318 64 +#define BLOCK_SIZE_4328 512 + +/* internal return code */ +#define SUCCESS 0 +#define ERROR 1 + +/* private bus modes */ +#define SDIOH_MODE_SD4 2 +#define CLIENT_INTR 0x100 /* Get rid of this! */ +#define SDIOH_SDMMC_MAX_SG_ENTRIES (SDPCM_MAXGLOM_SIZE+2) + +struct sdioh_info { + osl_t *osh; /* osh handler */ + void *bcmsdh; /* upper layer handle */ + bool client_intr_enabled; /* interrupt connnected flag */ + bool intr_handler_valid; /* client driver interrupt handler valid */ + sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ + void *intr_handler_arg; /* argument to call interrupt handler */ + uint16 intmask; /* Current active interrupts */ + + int intrcount; /* Client interrupts */ + bool sd_use_dma; /* DMA on CMD53 */ + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + /* Must be on for sd_multiblock to be effective */ + bool use_client_ints; /* If this is false, make sure to restore */ + int sd_mode; /* SD1/SD4/SPI */ + int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ + uint8 num_funcs; /* Supported funcs on client */ + uint32 com_cis_ptr; + uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; + bool use_rxchain; + struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; + struct sdio_func fake_func0; + struct sdio_func *func[SDIOD_MAX_IOFUNCS]; + +}; + +/************************************************************ + * Internal interfaces: per-port references into bcmsdh_sdmmc.c + */ + +/* Global message bits */ +extern uint sd_msglevel; + +/* OS-independent interrupt handler */ +extern bool check_client_intr(sdioh_info_t *sd); + +/* Core interrupt enable/disable of device interrupts */ +extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); +extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); + + +/************************************************************** + * Internal interfaces: bcmsdh_sdmmc.c references to per-port code + */ + +/* Register mapping routines */ +extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size); +extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size); + +/* Interrupt (de)registration routines */ +extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); +extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd); + +extern sdioh_info_t *sdioh_attach(osl_t *osh, struct sdio_func *func); +extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); +#endif /* __BCMSDH_SDMMC_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h new file mode 100644 index 000000000000..2bfac6693ec4 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h @@ -0,0 +1,281 @@ +/* + * Broadcom SDIO/PCMCIA + * Software-specific definitions shared between device and host side + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdpcm.h 414378 2013-07-24 15:58:50Z $ + */ + +#ifndef _bcmsdpcm_h_ +#define _bcmsdpcm_h_ + +/* + * Software allocation of To SB Mailbox resources + */ + +/* intstatus bits */ +#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */ +#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */ +#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */ +#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */ + +#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) + +/* tosbmailbox bits corresponding to intstatus bits */ +#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ +#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ +#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ +#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ +#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */ + +/* tosbmailboxdata */ +#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */ +#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */ + +/* + * Software allocation of To Host Mailbox resources + */ + +/* intstatus bits */ +#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */ +#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */ +#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */ +#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */ + +#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT) + +/* tohostmailbox bits corresponding to intstatus bits */ +#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */ +#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */ +#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ +#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ +#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */ + +/* tohostmailboxdata */ +#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */ +#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */ +#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */ +#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */ +#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */ + +#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */ +#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ + +#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */ +#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ + +/* + * Software-defined protocol header + */ + +/* Current protocol version */ +#define SDPCM_PROT_VERSION 4 + +/* SW frame header */ +#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ +#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ + +#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ +#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ +#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ + +#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ +#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ +#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ + +/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ +#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ +#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ +#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ +#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) (((uint8 *)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) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) +#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ +#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) +#define SDPCM_VERSION_OFFSET 6 /* Version # */ +#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) +#define SDPCM_UNUSED_OFFSET 7 /* Spare */ +#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) + +#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ + +/* logical channel numbers */ +#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response 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 (superframes) */ +#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ +#define SDPCM_MAX_CHANNEL 15 + +#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ + +#define SDPCM_FLAG_RESVD0 0x01 +#define SDPCM_FLAG_RESVD1 0x02 +#define SDPCM_FLAG_GSPI_TXENAB 0x04 +#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ + +/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ +#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) + +#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80) + +/* For TEST_CHANNEL packets, define another 4-byte header */ +#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2); + * Semantics of Ext byte depend on command. + * Len is current or requested frame length, not + * including test header; sent little-endian. + */ +#define SDPCM_TEST_PKT_CNT_FLD_LEN 4 /* Packet count filed legth */ +#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ +#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ +#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ +#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count + * (Backward compatabilty) Set frame count in a + * 4 byte filed adjacent to the HDR + */ +#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off + * Set frame count in a 4 byte filed adjacent to + * the HDR + */ + +/* Handy macro for filling in datagen packets with a pattern */ +#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) + +/* + * Software counters (first part matches hardware counters) + */ + +typedef volatile struct { + uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ + uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ + uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ + uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ + uint32 abort; /* AbortCount, SDIO: aborts */ + uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ + uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ + uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ + uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ + uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ + uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ + uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ + uint32 rxdescuflo; /* receive descriptor underflows */ + uint32 rxfifooflo; /* receive fifo overflows */ + uint32 txfifouflo; /* transmit fifo underflows */ + uint32 runt; /* runt (too short) frames recv'd from bus */ + uint32 badlen; /* frame's rxh len does not match its hw tag len */ + uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ + uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ + uint32 rxfcrc; /* frame rx header indicates crc error */ + uint32 rxfwoos; /* frame rx header indicates write out of sync */ + uint32 rxfwft; /* frame rx header indicates write frame termination */ + uint32 rxfabort; /* frame rx header indicates frame aborted */ + uint32 woosint; /* write out of sync interrupt */ + uint32 roosint; /* read out of sync interrupt */ + uint32 rftermint; /* read frame terminate interrupt */ + uint32 wftermint; /* write frame terminate interrupt */ +} sdpcmd_cnt_t; + +/* + * Register Access Macros + */ + +#define SDIODREV_IS(var, val) ((var) == (val)) +#define SDIODREV_GE(var, val) ((var) >= (val)) +#define SDIODREV_GT(var, val) ((var) > (val)) +#define SDIODREV_LT(var, val) ((var) < (val)) +#define SDIODREV_LE(var, val) ((var) <= (val)) + +#define SDIODDMAREG32(h, dir, chnl) \ + ((dir) == DMA_TX ? \ + (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ + (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv)) + +#define SDIODDMAREG64(h, dir, chnl) \ + ((dir) == DMA_TX ? \ + (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ + (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv)) + +#define SDIODDMAREG(h, dir, chnl) \ + (SDIODREV_LT((h)->corerev, 1) ? \ + SDIODDMAREG32((h), (dir), (chnl)) : \ + SDIODDMAREG64((h), (dir), (chnl))) + +#define PCMDDMAREG(h, dir, chnl) \ + ((dir) == DMA_TX ? \ + (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \ + (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv)) + +#define SDPCMDMAREG(h, dir, chnl, coreid) \ + ((coreid) == SDIOD_CORE_ID ? \ + SDIODDMAREG(h, dir, chnl) : \ + PCMDDMAREG(h, dir, chnl)) + +#define SDIODFIFOREG(h, corerev) \ + (SDIODREV_LT((corerev), 1) ? \ + ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \ + ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo))) + +#define PCMDFIFOREG(h) \ + ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo)) + +#define SDPCMFIFOREG(h, coreid, corerev) \ + ((coreid) == SDIOD_CORE_ID ? \ + SDIODFIFOREG(h, corerev) : \ + PCMDFIFOREG(h)) + +/* + * Shared structure between dongle and the host. + * The structure contains pointers to trap or assert information. + */ +#define SDPCM_SHARED_VERSION 0x0001 +#define SDPCM_SHARED_VERSION_MASK 0x00FF +#define SDPCM_SHARED_ASSERT_BUILT 0x0100 +#define SDPCM_SHARED_ASSERT 0x0200 +#define SDPCM_SHARED_TRAP 0x0400 +#define SDPCM_SHARED_IN_BRPT 0x0800 +#define SDPCM_SHARED_SET_BRPT 0x1000 +#define SDPCM_SHARED_PENDING_BRPT 0x2000 + +typedef struct { + uint32 flags; + uint32 trap_addr; + uint32 assert_exp_addr; + uint32 assert_file_addr; + uint32 assert_line; + uint32 console_addr; /* Address of hndrte_cons_t */ + uint32 msgtrace_addr; + uint32 fwid; +} sdpcm_shared_t; + +extern sdpcm_shared_t sdpcm_shared; + +/* Function can be used to notify host of FW halt */ +extern void sdpcmd_fwhalt(void); + +#endif /* _bcmsdpcm_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h new file mode 100644 index 000000000000..1fc1fd4eef6b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h @@ -0,0 +1,135 @@ +/* + * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdspi.h 294363 2011-11-06 23:02:20Z $ + */ +#ifndef _BCM_SD_SPI_H +#define _BCM_SD_SPI_H + +/* global msglevel for debug messages - bitvals come from sdiovar.h */ + +#define sd_err(x) +#define sd_trace(x) +#define sd_info(x) +#define sd_debug(x) +#define sd_data(x) +#define sd_ctrl(x) + +#define sd_log(x) + +#define SDIOH_ASSERT(exp) \ + do { if (!(exp)) \ + printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ + } while (0) + +#define BLOCK_SIZE_4318 64 +#define BLOCK_SIZE_4328 512 + +/* internal return code */ +#define SUCCESS 0 +#undef ERROR +#define ERROR 1 + +/* private bus modes */ +#define SDIOH_MODE_SPI 0 + +#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ +#define USE_MULTIBLOCK 0x4 + +struct sdioh_info { + uint cfg_bar; /* pci cfg address for bar */ + uint32 caps; /* cached value of capabilities reg */ + uint bar0; /* BAR0 for PCI Device */ + osl_t *osh; /* osh handler */ + void *controller; /* Pointer to SPI Controller's private data struct */ + + uint lockcount; /* nest count of sdspi_lock() calls */ + bool client_intr_enabled; /* interrupt connnected flag */ + bool intr_handler_valid; /* client driver interrupt handler valid */ + sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ + void *intr_handler_arg; /* argument to call interrupt handler */ + bool initialized; /* card initialized */ + uint32 target_dev; /* Target device ID */ + uint32 intmask; /* Current active interrupts */ + void *sdos_info; /* Pointer to per-OS private data */ + + uint32 controller_type; /* Host controller type */ + uint8 version; /* Host Controller Spec Compliance Version */ + uint irq; /* Client irq */ + uint32 intrcount; /* Client interrupts */ + uint32 local_intrcount; /* Controller interrupts */ + bool host_init_done; /* Controller initted */ + bool card_init_done; /* Client SDIO interface initted */ + bool polled_mode; /* polling for command completion */ + + bool sd_use_dma; /* DMA on CMD53 */ + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + /* Must be on for sd_multiblock to be effective */ + bool use_client_ints; /* If this is false, make sure to restore */ + bool got_hcint; /* Host Controller interrupt. */ + /* polling hack in wl_linux.c:wl_timer() */ + int adapter_slot; /* Maybe dealing with multiple slots/controllers */ + int sd_mode; /* SD1/SD4/SPI */ + int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ + uint32 data_xfer_count; /* Current register transfer size */ + uint32 cmd53_wr_data; /* Used to pass CMD53 write data */ + uint32 card_response; /* Used to pass back response status byte */ + uint32 card_rsp_data; /* Used to pass back response data word */ + uint16 card_rca; /* Current Address */ + uint8 num_funcs; /* Supported funcs on client */ + uint32 com_cis_ptr; + uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; + void *dma_buf; + ulong dma_phys; + int r_cnt; /* rx count */ + int t_cnt; /* tx_count */ +}; + +/************************************************************ + * Internal interfaces: per-port references into bcmsdspi.c + */ + +/* Global message bits */ +extern uint sd_msglevel; + +/************************************************************** + * Internal interfaces: bcmsdspi.c references to per-port code + */ + +/* Register mapping routines */ +extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); +extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); + +/* Interrupt (de)registration routines */ +extern int spi_register_irq(sdioh_info_t *sd, uint irq); +extern void spi_free_irq(uint irq, sdioh_info_t *sd); + +/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ +extern void spi_lock(sdioh_info_t *sd); +extern void spi_unlock(sdioh_info_t *sd); + +/* Allocate/init/free per-OS private data */ +extern int spi_osinit(sdioh_info_t *sd); +extern void spi_osfree(sdioh_info_t *sd); + +#endif /* _BCM_SD_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h new file mode 100644 index 000000000000..9edb37286712 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h @@ -0,0 +1,282 @@ +/* + * 'Standard' SDIO HOST CONTROLLER driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsdstd.h 528504 2015-01-22 11:15:31Z $ + */ +#ifndef _BCM_SD_STD_H +#define _BCM_SD_STD_H + +/* global msglevel for debug messages - bitvals come from sdiovar.h */ +#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) +#define sd_trace(x) +#define sd_info(x) +#define sd_debug(x) +#define sd_data(x) +#define sd_ctrl(x) +#define sd_dma(x) + +#define sd_sync_dma(sd, read, nbytes) +#define sd_init_dma(sd) +#define sd_ack_intr(sd) +#define sd_wakeup(sd); +/* Allocate/init/free per-OS private data */ +extern int sdstd_osinit(sdioh_info_t *sd); +extern void sdstd_osfree(sdioh_info_t *sd); + +#define sd_log(x) + +#define SDIOH_ASSERT(exp) \ + do { if (!(exp)) \ + printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ + } while (0) + +#define BLOCK_SIZE_4318 64 +#define BLOCK_SIZE_4328 512 + +/* internal return code */ +#define SUCCESS 0 +#define ERROR 1 + +/* private bus modes */ +#define SDIOH_MODE_SPI 0 +#define SDIOH_MODE_SD1 1 +#define SDIOH_MODE_SD4 2 + +#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */ +#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */ + +#define SDIOH_TYPE_ARASAN_HDK 1 +#define SDIOH_TYPE_BCM27XX 2 +#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */ +#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */ +#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */ + +/* For linux, allow yielding for dongle */ +#define BCMSDYIELD + +/* Expected card status value for CMD7 */ +#define SDIOH_CMD7_EXP_STATUS 0x00001E00 + +#define RETRIES_LARGE 100000 +#define sdstd_os_yield(sd) do {} while (0) +#define RETRIES_SMALL 100 + + +#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ +#define USE_MULTIBLOCK 0x4 + +#define USE_FIFO 0x8 /* Fifo vs non-fifo */ + +#define CLIENT_INTR 0x100 /* Get rid of this! */ + +#define HC_INTR_RETUNING 0x1000 + + +#ifdef BCMSDIOH_TXGLOM +/* Total glom pkt can not exceed 64K + * need one more slot for glom padding packet + */ +#define SDIOH_MAXGLOM_SIZE (40+1) + +typedef struct glom_buf { + uint32 count; /* Total number of pkts queued */ + void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */ + ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */ + uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */ +} glom_buf_t; +#endif + +struct sdioh_info { + uint cfg_bar; /* pci cfg address for bar */ + uint32 caps; /* cached value of capabilities reg */ + uint32 curr_caps; /* max current capabilities reg */ + + osl_t *osh; /* osh handler */ + volatile char *mem_space; /* pci device memory va */ + uint lockcount; /* nest count of sdstd_lock() calls */ + bool client_intr_enabled; /* interrupt connnected flag */ + bool intr_handler_valid; /* client driver interrupt handler valid */ + sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ + void *intr_handler_arg; /* argument to call interrupt handler */ + bool initialized; /* card initialized */ + uint target_dev; /* Target device ID */ + uint16 intmask; /* Current active interrupts */ + void *sdos_info; /* Pointer to per-OS private data */ + void *bcmsdh; /* handler to upper layer stack (bcmsdh) */ + + uint32 controller_type; /* Host controller type */ + uint8 version; /* Host Controller Spec Compliance Version */ + uint irq; /* Client irq */ + int intrcount; /* Client interrupts */ + int local_intrcount; /* Controller interrupts */ + bool host_init_done; /* Controller initted */ + bool card_init_done; /* Client SDIO interface initted */ + bool polled_mode; /* polling for command completion */ + + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + /* Must be on for sd_multiblock to be effective */ + bool use_client_ints; /* If this is false, make sure to restore */ + /* polling hack in wl_linux.c:wl_timer() */ + int adapter_slot; /* Maybe dealing with multiple slots/controllers */ + int sd_mode; /* SD1/SD4/SPI */ + int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ + uint32 data_xfer_count; /* Current transfer */ + uint16 card_rca; /* Current Address */ + int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */ + uint8 num_funcs; /* Supported funcs on client */ + uint32 com_cis_ptr; + uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; + void *dma_buf; /* DMA Buffer virtual address */ + ulong dma_phys; /* DMA Buffer physical address */ + void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */ + ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */ + + /* adjustments needed to make the dma align properly */ + void *dma_start_buf; + ulong dma_start_phys; + uint alloced_dma_size; + void *adma2_dscr_start_buf; + ulong adma2_dscr_start_phys; + uint alloced_adma2_dscr_size; + + int r_cnt; /* rx count */ + int t_cnt; /* tx_count */ + bool got_hcint; /* local interrupt flag */ + uint16 last_intrstatus; /* to cache intrstatus */ + int host_UHSISupported; /* whether UHSI is supported for HC. */ + int card_UHSI_voltage_Supported; /* whether UHSI is supported for + * Card in terms of Voltage [1.8 or 3.3]. + */ + int global_UHSI_Supp; /* type of UHSI support in both host and card. + * HOST_SDR_UNSUPP: capabilities not supported/matched + * HOST_SDR_12_25: SDR12 and SDR25 supported + * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd + */ + volatile int sd3_dat_state; /* data transfer state used for retuning check */ + volatile int sd3_tun_state; /* tuning state used for retuning check */ + bool sd3_tuning_reqd; /* tuning requirement parameter */ + uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ +#ifdef BCMSDIOH_TXGLOM + glom_buf_t glom_info; /* pkt information used for glomming */ + uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ +#endif +}; + +#define DMA_MODE_NONE 0 +#define DMA_MODE_SDMA 1 +#define DMA_MODE_ADMA1 2 +#define DMA_MODE_ADMA2 3 +#define DMA_MODE_ADMA2_64 4 +#define DMA_MODE_AUTO -1 + +#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) + +/* States for Tuning and corr data */ +#define TUNING_IDLE 0 +#define TUNING_START 1 +#define TUNING_START_AFTER_DAT 2 +#define TUNING_ONGOING 3 + +#define DATA_TRANSFER_IDLE 0 +#define DATA_TRANSFER_ONGOING 1 + +#define CHECK_TUNING_PRE_DATA 1 +#define CHECK_TUNING_POST_DATA 2 + + +#ifdef DHD_DEBUG +#define SD_DHD_DISABLE_PERIODIC_TUNING 0x01 +#define SD_DHD_ENABLE_PERIODIC_TUNING 0x00 +#endif + + +/************************************************************ + * Internal interfaces: per-port references into bcmsdstd.c + */ + +/* Global message bits */ +extern uint sd_msglevel; + +/* OS-independent interrupt handler */ +extern bool check_client_intr(sdioh_info_t *sd); + +/* Core interrupt enable/disable of device interrupts */ +extern void sdstd_devintr_on(sdioh_info_t *sd); +extern void sdstd_devintr_off(sdioh_info_t *sd); + +/* Enable/disable interrupts for local controller events */ +extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err); +extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err); + +/* Wait for specified interrupt and error bits to be set */ +extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err); + + +/************************************************************** + * Internal interfaces: bcmsdstd.c references to per-port code + */ + +/* Register mapping routines */ +extern uint32 *sdstd_reg_map(osl_t *osh, ulong addr, int size); +extern void sdstd_reg_unmap(osl_t *osh, ulong addr, int size); + +/* Interrupt (de)registration routines */ +extern int sdstd_register_irq(sdioh_info_t *sd, uint irq); +extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); + +/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ +extern void sdstd_lock(sdioh_info_t *sd); +extern void sdstd_unlock(sdioh_info_t *sd); +extern void sdstd_waitlockfree(sdioh_info_t *sd); + +/* OS-specific wrappers for safe concurrent register access */ +extern void sdstd_os_lock_irqsave(sdioh_info_t *sd, ulong* flags); +extern void sdstd_os_unlock_irqrestore(sdioh_info_t *sd, ulong* flags); + +/* OS-specific wait-for-interrupt-or-status */ +extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits); + +/* used by bcmsdstd_linux [implemented in sdstd] */ +extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd); +extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); +extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); +extern void sdstd_3_check_and_do_tuning(sdioh_info_t *sd, int tuning_param); +extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); +extern int sdstd_3_get_tune_state(sdioh_info_t *sd); +extern int sdstd_3_get_data_state(sdioh_info_t *sd); +extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); +extern void sdstd_3_set_data_state(sdioh_info_t *sd, int state); +extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); +extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); +extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode); + +/* used by sdstd [implemented in bcmsdstd_linux/ndis] */ +extern void sdstd_3_start_tuning(sdioh_info_t *sd); +extern void sdstd_3_osinit_tuning(sdioh_info_t *sd); +extern void sdstd_3_osclean_tuning(sdioh_info_t *sd); + +extern void sdstd_enable_disable_periodic_timer(sdioh_info_t * sd, uint val); + +extern sdioh_info_t *sdioh_attach(osl_t *osh, void *bar0, uint irq); +extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); +#endif /* _BCM_SD_STD_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h new file mode 100644 index 000000000000..193dc8e0c9ca --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h @@ -0,0 +1,40 @@ +/* + * Broadcom SPI Low-Level Hardware Driver API + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmspi.h 241182 2011-02-17 21:50:03Z $ + */ +#ifndef _BCM_SPI_H +#define _BCM_SPI_H + +extern void spi_devintr_off(sdioh_info_t *sd); +extern void spi_devintr_on(sdioh_info_t *sd); +extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); +extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); +extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); +extern bool spi_hw_attach(sdioh_info_t *sd); +extern bool spi_hw_detach(sdioh_info_t *sd); +extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); +extern void spi_spinbits(sdioh_info_t *sd); +extern void spi_waitbits(sdioh_info_t *sd, bool yield); + +#endif /* _BCM_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h new file mode 100644 index 000000000000..c81e6049ae03 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h @@ -0,0 +1,162 @@ +/* + * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmspibrcm.h 373331 2012-12-07 04:46:22Z $ + */ +#ifndef _BCM_SPI_BRCM_H +#define _BCM_SPI_BRCM_H + +#ifndef SPI_MAX_IOFUNCS +/* Maximum number of I/O funcs */ +#define SPI_MAX_IOFUNCS 4 +#endif +/* global msglevel for debug messages - bitvals come from sdiovar.h */ + +#if defined(DHD_DEBUG) +#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) +#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) +#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) +#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0) +#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) +#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0) +#else +#define sd_err(x) +#define sd_trace(x) +#define sd_info(x) +#define sd_debug(x) +#define sd_data(x) +#define sd_ctrl(x) +#endif + +#define sd_log(x) + +#define SDIOH_ASSERT(exp) \ + do { if (!(exp)) \ + printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ + } while (0) + +#define BLOCK_SIZE_F1 64 +#define BLOCK_SIZE_F2 2048 +#define BLOCK_SIZE_F3 2048 + +/* internal return code */ +#define SUCCESS 0 +#undef ERROR +#define ERROR 1 +#define ERROR_UF 2 +#define ERROR_OF 3 + +/* private bus modes */ +#define SDIOH_MODE_SPI 0 + +#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ +#define USE_MULTIBLOCK 0x4 + +struct sdioh_info { + uint cfg_bar; /* pci cfg address for bar */ + uint32 caps; /* cached value of capabilities reg */ + void *bar0; /* BAR0 for PCI Device */ + osl_t *osh; /* osh handler */ + void *controller; /* Pointer to SPI Controller's private data struct */ + uint lockcount; /* nest count of spi_lock() calls */ + bool client_intr_enabled; /* interrupt connnected flag */ + bool intr_handler_valid; /* client driver interrupt handler valid */ + sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ + void *intr_handler_arg; /* argument to call interrupt handler */ + bool initialized; /* card initialized */ + uint32 target_dev; /* Target device ID */ + uint32 intmask; /* Current active interrupts */ + void *sdos_info; /* Pointer to per-OS private data */ + uint32 controller_type; /* Host controller type */ + uint8 version; /* Host Controller Spec Compliance Version */ + uint irq; /* Client irq */ + uint32 intrcount; /* Client interrupts */ + uint32 local_intrcount; /* Controller interrupts */ + bool host_init_done; /* Controller initted */ + bool card_init_done; /* Client SDIO interface initted */ + bool polled_mode; /* polling for command completion */ + + bool sd_use_dma; /* DMA on CMD53 */ + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + /* Must be on for sd_multiblock to be effective */ + bool use_client_ints; /* If this is false, make sure to restore */ + /* polling hack in wl_linux.c:wl_timer() */ + int adapter_slot; /* Maybe dealing with multiple slots/controllers */ + int sd_mode; /* SD1/SD4/SPI */ + int client_block_size[SPI_MAX_IOFUNCS]; /* Blocksize */ + uint32 data_xfer_count; /* Current transfer */ + uint16 card_rca; /* Current Address */ + uint8 num_funcs; /* Supported funcs on client */ + uint32 card_dstatus; /* 32bit device status */ + uint32 com_cis_ptr; + uint32 func_cis_ptr[SPI_MAX_IOFUNCS]; + void *dma_buf; + ulong dma_phys; + int r_cnt; /* rx count */ + int t_cnt; /* tx_count */ + uint32 wordlen; /* host processor 16/32bits */ + uint32 prev_fun; + uint32 chip; + uint32 chiprev; + bool resp_delay_all; + bool dwordmode; + bool resp_delay_new; + + struct spierrstats_t spierrstats; +}; + +/************************************************************ + * Internal interfaces: per-port references into bcmspibrcm.c + */ + +/* Global message bits */ +extern uint sd_msglevel; + +/************************************************************** + * Internal interfaces: bcmspibrcm.c references to per-port code + */ + +/* Interrupt (de)registration routines */ +extern int spi_register_irq(sdioh_info_t *sd, uint irq); +extern void spi_free_irq(uint irq, sdioh_info_t *sd); + +/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ +extern void spi_lock(sdioh_info_t *sd); +extern void spi_unlock(sdioh_info_t *sd); + +/* Allocate/init/free per-OS private data */ +extern int spi_osinit(sdioh_info_t *sd); +extern void spi_osfree(sdioh_info_t *sd); + +#define SPI_RW_FLAG_M BITFIELD_MASK(1) /* Bit [31] - R/W Command Bit */ +#define SPI_RW_FLAG_S 31 +#define SPI_ACCESS_M BITFIELD_MASK(1) /* Bit [30] - Fixed/Incr Access */ +#define SPI_ACCESS_S 30 +#define SPI_FUNCTION_M BITFIELD_MASK(2) /* Bit [29:28] - Function Number */ +#define SPI_FUNCTION_S 28 +#define SPI_REG_ADDR_M BITFIELD_MASK(17) /* Bit [27:11] - Address */ +#define SPI_REG_ADDR_S 11 +#define SPI_LEN_M BITFIELD_MASK(11) /* Bit [10:0] - Packet length */ +#define SPI_LEN_S 0 + +#endif /* _BCM_SPI_BRCM_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h new file mode 100644 index 000000000000..1baebcdf90bb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h @@ -0,0 +1,633 @@ +/* + * SROM format definition. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsrom_fmt.h 427005 2013-10-02 00:15:10Z $ + */ + +#ifndef _bcmsrom_fmt_h_ +#define _bcmsrom_fmt_h_ + +#define SROM_MAXREV 11 /* max revisiton supported by driver */ + +/* Maximum srom: 6 Kilobits == 768 bytes */ +#define SROM_MAX 768 +#define SROM_MAXW 384 +#define VARS_MAX 4096 + +/* PCI fields */ +#define PCI_F0DEVID 48 + + +#define SROM_WORDS 64 + +#define SROM3_SWRGN_OFF 28 /* s/w region offset in words */ + +#define SROM_SSID 2 +#define SROM_SVID 3 + +#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_ET0 39 +#define SROM_MACMID_ET0 40 +#define SROM_MACLO_ET0 41 +#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 SROM2_ENETPHY 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 accomodate + * MIMO features. It assumes up to two PCIE functions and 440 bytes + * of useable srom i.e. the useable 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_AA2G_MASK 0x00ff +#define SROM4_AA2G_SHIFT 0 +#define SROM4_AA5G_MASK 0xff00 +#define SROM4_AA5G_SHIFT 8 + +#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 + +/* Fields in the ITT_MAXP and 5GLH_MAXP words */ +#define B2G_MAXP_MASK 0xff +#define B2G_ITT_SHIFT 8 +#define B5G_MAXP_MASK 0xff +#define B5G_ITT_SHIFT 8 +#define B5GH_MAXP_MASK 0xff +#define B5GL_MAXP_SHIFT 8 + +/* 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_SIGN 64 + +#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 + +#define SROM8_EXTLNAGAIN 93 + +/* Temperature delta for PHY calibration */ +#define SROM8_PHYCAL_TEMPDELTA 94 + +/* Measured power 1 & 2, 0-13 bits at offset 95, MSB 2 bits are unused for now. */ +#define SROM8_MPWR_1_AND_2 95 + + +/* 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) + +#define SROM8_CRCREV 219 + +/* 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 +#define SROM8_RXGAINERR_2G 205 +#define SROM8_RXGAINERR_5GL 206 +#define SROM8_RXGAINERR_5GM 207 +#define SROM8_RXGAINERR_5GH 208 +#define SROM8_RXGAINERR_5GU 209 +#define SROM8_SUBBAND_PPR 210 +#define SROM8_PCIEINGRESS_WAR 211 +#define SROM9_SAR 212 + +#define SROM8_NOISELVL_2G 213 +#define SROM8_NOISELVL_5GL 214 +#define SROM8_NOISELVL_5GM 215 +#define SROM8_NOISELVL_5GH 216 +#define SROM8_NOISELVL_5GU 217 +#define SROM8_NOISECALOFFSET 218 + +#define SROM9_REV_CRC 219 + +#define SROM10_CCKPWROFFSET 218 +#define SROM10_SIGN 219 +#define SROM10_SWCTRLMAP_2G 220 +#define SROM10_CRCREV 229 + +#define SROM10_WORDS 230 +#define SROM10_SIGNATURE SROM4_SIGNATURE + + +/* SROM REV 11 */ +#define SROM11_BREV 65 + +#define SROM11_BFL0 66 +#define SROM11_BFL1 67 +#define SROM11_BFL2 68 +#define SROM11_BFL3 69 +#define SROM11_BFL4 70 +#define SROM11_BFL5 71 + +#define SROM11_MACHI 72 +#define SROM11_MACMID 73 +#define SROM11_MACLO 74 + +#define SROM11_CCODE 75 +#define SROM11_REGREV 76 + +#define SROM11_LEDBH10 77 +#define SROM11_LEDBH32 78 + +#define SROM11_LEDDC 79 + +#define SROM11_AA 80 + +#define SROM11_AGBG10 81 +#define SROM11_AGBG2A0 82 +#define SROM11_AGA21 83 + +#define SROM11_TXRXC 84 + +#define SROM11_FEM_CFG1 85 +#define SROM11_FEM_CFG2 86 + +/* Masks and offsets for FEM_CFG */ +#define SROM11_FEMCTRL_MASK 0xf800 +#define SROM11_FEMCTRL_SHIFT 11 +#define SROM11_PAPDCAP_MASK 0x0400 +#define SROM11_PAPDCAP_SHIFT 10 +#define SROM11_TWORANGETSSI_MASK 0x0200 +#define SROM11_TWORANGETSSI_SHIFT 9 +#define SROM11_PDGAIN_MASK 0x01f0 +#define SROM11_PDGAIN_SHIFT 4 +#define SROM11_EPAGAIN_MASK 0x000e +#define SROM11_EPAGAIN_SHIFT 1 +#define SROM11_TSSIPOSSLOPE_MASK 0x0001 +#define SROM11_TSSIPOSSLOPE_SHIFT 0 +#define SROM11_GAINCTRLSPH_MASK 0xf800 +#define SROM11_GAINCTRLSPH_SHIFT 11 + +#define SROM11_THERMAL 87 +#define SROM11_MPWR_RAWTS 88 +#define SROM11_TS_SLP_OPT_CORRX 89 +#define SROM11_XTAL_FREQ 90 +#define SROM11_5GB0_4080_W0_A1 91 +#define SROM11_PHYCAL_TEMPDELTA 92 +#define SROM11_MPWR_1_AND_2 93 +#define SROM11_5GB0_4080_W1_A1 94 +#define SROM11_TSSIFLOOR_2G 95 +#define SROM11_TSSIFLOOR_5GL 96 +#define SROM11_TSSIFLOOR_5GM 97 +#define SROM11_TSSIFLOOR_5GH 98 +#define SROM11_TSSIFLOOR_5GU 99 + +/* Masks and offsets for Terrmal parameters */ +#define SROM11_TEMPS_PERIOD_MASK 0xf0 +#define SROM11_TEMPS_PERIOD_SHIFT 4 +#define SROM11_TEMPS_HYSTERESIS_MASK 0x0f +#define SROM11_TEMPS_HYSTERESIS_SHIFT 0 +#define SROM11_TEMPCORRX_MASK 0xfc +#define SROM11_TEMPCORRX_SHIFT 2 +#define SROM11_TEMPSENSE_OPTION_MASK 0x3 +#define SROM11_TEMPSENSE_OPTION_SHIFT 0 + +#define SROM11_PDOFF_2G_40M_A0_MASK 0x000f +#define SROM11_PDOFF_2G_40M_A0_SHIFT 0 +#define SROM11_PDOFF_2G_40M_A1_MASK 0x00f0 +#define SROM11_PDOFF_2G_40M_A1_SHIFT 4 +#define SROM11_PDOFF_2G_40M_A2_MASK 0x0f00 +#define SROM11_PDOFF_2G_40M_A2_SHIFT 8 +#define SROM11_PDOFF_2G_40M_VALID_MASK 0x8000 +#define SROM11_PDOFF_2G_40M_VALID_SHIFT 15 + +#define SROM11_PDOFF_2G_40M 100 +#define SROM11_PDOFF_40M_A0 101 +#define SROM11_PDOFF_40M_A1 102 +#define SROM11_PDOFF_40M_A2 103 +#define SROM11_5GB0_4080_W2_A1 103 +#define SROM11_PDOFF_80M_A0 104 +#define SROM11_PDOFF_80M_A1 105 +#define SROM11_PDOFF_80M_A2 106 +#define SROM11_5GB1_4080_W0_A1 106 + +#define SROM11_SUBBAND5GVER 107 + +/* Per-path fields and offset */ +#define MAX_PATH_SROM_11 3 +#define SROM11_PATH0 108 +#define SROM11_PATH1 128 +#define SROM11_PATH2 148 + +#define SROM11_2G_MAXP 0 +#define SROM11_5GB1_4080_PA 0 +#define SROM11_2G_PA 1 +#define SROM11_5GB2_4080_PA 2 +#define SROM11_RXGAINS1 4 +#define SROM11_RXGAINS 5 +#define SROM11_5GB3_4080_PA 5 +#define SROM11_5GB1B0_MAXP 6 +#define SROM11_5GB3B2_MAXP 7 +#define SROM11_5GB0_PA 8 +#define SROM11_5GB1_PA 11 +#define SROM11_5GB2_PA 14 +#define SROM11_5GB3_PA 17 + +/* Masks and offsets for rxgains */ +#define SROM11_RXGAINS5GTRELNABYPA_MASK 0x8000 +#define SROM11_RXGAINS5GTRELNABYPA_SHIFT 15 +#define SROM11_RXGAINS5GTRISOA_MASK 0x7800 +#define SROM11_RXGAINS5GTRISOA_SHIFT 11 +#define SROM11_RXGAINS5GELNAGAINA_MASK 0x0700 +#define SROM11_RXGAINS5GELNAGAINA_SHIFT 8 +#define SROM11_RXGAINS2GTRELNABYPA_MASK 0x0080 +#define SROM11_RXGAINS2GTRELNABYPA_SHIFT 7 +#define SROM11_RXGAINS2GTRISOA_MASK 0x0078 +#define SROM11_RXGAINS2GTRISOA_SHIFT 3 +#define SROM11_RXGAINS2GELNAGAINA_MASK 0x0007 +#define SROM11_RXGAINS2GELNAGAINA_SHIFT 0 +#define SROM11_RXGAINS5GHTRELNABYPA_MASK 0x8000 +#define SROM11_RXGAINS5GHTRELNABYPA_SHIFT 15 +#define SROM11_RXGAINS5GHTRISOA_MASK 0x7800 +#define SROM11_RXGAINS5GHTRISOA_SHIFT 11 +#define SROM11_RXGAINS5GHELNAGAINA_MASK 0x0700 +#define SROM11_RXGAINS5GHELNAGAINA_SHIFT 8 +#define SROM11_RXGAINS5GMTRELNABYPA_MASK 0x0080 +#define SROM11_RXGAINS5GMTRELNABYPA_SHIFT 7 +#define SROM11_RXGAINS5GMTRISOA_MASK 0x0078 +#define SROM11_RXGAINS5GMTRISOA_SHIFT 3 +#define SROM11_RXGAINS5GMELNAGAINA_MASK 0x0007 +#define SROM11_RXGAINS5GMELNAGAINA_SHIFT 0 + +/* Power per rate */ +#define SROM11_CCKBW202GPO 168 +#define SROM11_CCKBW20UL2GPO 169 +#define SROM11_MCSBW202GPO 170 +#define SROM11_MCSBW202GPO_1 171 +#define SROM11_MCSBW402GPO 172 +#define SROM11_MCSBW402GPO_1 173 +#define SROM11_DOT11AGOFDMHRBW202GPO 174 +#define SROM11_OFDMLRBW202GPO 175 + +#define SROM11_MCSBW205GLPO 176 +#define SROM11_MCSBW205GLPO_1 177 +#define SROM11_MCSBW405GLPO 178 +#define SROM11_MCSBW405GLPO_1 179 +#define SROM11_MCSBW805GLPO 180 +#define SROM11_MCSBW805GLPO_1 181 +#define SROM11_RPCAL_2G 182 +#define SROM11_RPCAL_5GL 183 +#define SROM11_MCSBW205GMPO 184 +#define SROM11_MCSBW205GMPO_1 185 +#define SROM11_MCSBW405GMPO 186 +#define SROM11_MCSBW405GMPO_1 187 +#define SROM11_MCSBW805GMPO 188 +#define SROM11_MCSBW805GMPO_1 189 +#define SROM11_RPCAL_5GM 190 +#define SROM11_RPCAL_5GH 191 +#define SROM11_MCSBW205GHPO 192 +#define SROM11_MCSBW205GHPO_1 193 +#define SROM11_MCSBW405GHPO 194 +#define SROM11_MCSBW405GHPO_1 195 +#define SROM11_MCSBW805GHPO 196 +#define SROM11_MCSBW805GHPO_1 197 +#define SROM11_RPCAL_5GU 198 +#define SROM11_PDOFF_2G_CCK 199 +#define SROM11_MCSLR5GLPO 200 +#define SROM11_MCSLR5GMPO 201 +#define SROM11_MCSLR5GHPO 202 + +#define SROM11_SB20IN40HRPO 203 +#define SROM11_SB20IN80AND160HR5GLPO 204 +#define SROM11_SB40AND80HR5GLPO 205 +#define SROM11_SB20IN80AND160HR5GMPO 206 +#define SROM11_SB40AND80HR5GMPO 207 +#define SROM11_SB20IN80AND160HR5GHPO 208 +#define SROM11_SB40AND80HR5GHPO 209 +#define SROM11_SB20IN40LRPO 210 +#define SROM11_SB20IN80AND160LR5GLPO 211 +#define SROM11_SB40AND80LR5GLPO 212 +#define SROM11_TXIDXCAP2G 212 +#define SROM11_SB20IN80AND160LR5GMPO 213 +#define SROM11_SB40AND80LR5GMPO 214 +#define SROM11_TXIDXCAP5G 214 +#define SROM11_SB20IN80AND160LR5GHPO 215 +#define SROM11_SB40AND80LR5GHPO 216 + +#define SROM11_DOT11AGDUPHRPO 217 +#define SROM11_DOT11AGDUPLRPO 218 + +/* MISC */ +#define SROM11_PCIEINGRESS_WAR 220 +#define SROM11_SAR 221 + +#define SROM11_NOISELVL_2G 222 +#define SROM11_NOISELVL_5GL 223 +#define SROM11_NOISELVL_5GM 224 +#define SROM11_NOISELVL_5GH 225 +#define SROM11_NOISELVL_5GU 226 + +#define SROM11_RXGAINERR_2G 227 +#define SROM11_RXGAINERR_5GL 228 +#define SROM11_RXGAINERR_5GM 229 +#define SROM11_RXGAINERR_5GH 230 +#define SROM11_RXGAINERR_5GU 231 + +#define SROM11_SIGN 64 +#define SROM11_CRCREV 233 + +#define SROM11_WORDS 234 +#define SROM11_SIGNATURE 0x0634 + +typedef struct { + uint8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */ + uint8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */ + uint8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */ + uint8 triso; /* TR switch isolation */ + uint8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */ +} srom_fem_t; + +#endif /* _bcmsrom_fmt_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h new file mode 100644 index 000000000000..c8335b56eb5f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h @@ -0,0 +1,1014 @@ +/* + * Table that encodes the srom formats for PCI/PCIe NICs. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmsrom_tbl.h 427005 2013-10-02 00:15:10Z $ + */ + +#ifndef _bcmsrom_tbl_h_ +#define _bcmsrom_tbl_h_ + +#include "sbpcmcia.h" +#include "wlioctl.h" + +typedef struct { + const char *name; + uint32 revmask; + uint32 flags; + uint16 off; + uint16 mask; +} sromvar_t; + +#define SRFL_MORE 1 /* value continues as described by the next entry */ +#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 */ +#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */ +#define SRFL_ARRAY 0x100 /* value is in an array. All elements EXCEPT FOR THE LAST + * ONE in the array should have this flag set. + */ + + +#define SROM_DEVID_PCIE 48 + +/* Assumptions: + * - Ethernet address spans across 3 consective 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 sromvar_t pci_sromvars[] = { +#if defined(CABLECPE) + {"devid", 0xffffff00, SRFL_PRHEX, PCI_F0DEVID, 0xffff}, +#elif defined(BCMPCIEDEV) && defined(BCMPCIEDEV_ENABLED) + {"devid", 0xffffff00, SRFL_PRHEX, SROM_DEVID_PCIE, 0xffff}, +#else + {"devid", 0xffffff00, SRFL_PRHEX|SRFL_NOVAR, PCI_F0DEVID, 0xffff}, +#endif + {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK}, + {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, + {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, + {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, + {"boardflags", 0x00000004, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM_BFL2, 0xffff}, + {"boardflags", 0x00000008, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM3_BFL2, 0xffff}, + {"boardflags", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL0, 0xffff}, + {"", 0, 0, SROM4_BFL1, 0xffff}, + {"boardflags", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL0, 0xffff}, + {"", 0, 0, SROM5_BFL1, 0xffff}, + {"boardflags", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL0, 0xffff}, + {"", 0, 0, SROM8_BFL1, 0xffff}, + {"boardflags2", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL2, 0xffff}, + {"", 0, 0, SROM4_BFL3, 0xffff}, + {"boardflags2", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL2, 0xffff}, + {"", 0, 0, SROM5_BFL3, 0xffff}, + {"boardflags2", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL2, 0xffff}, + {"", 0, 0, SROM8_BFL3, 0xffff}, + {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, + {"subvid", 0xfffffffc, SRFL_PRHEX, SROM_SVID, 0xffff}, + {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, + {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff}, + {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff}, + {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff}, + {"boardnum", 0x00000700, 0, SROM8_MACLO, 0xffff}, + {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, + {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, + {"regrev", 0x00000010, 0, SROM4_REGREV, 0x00ff}, + {"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff}, + {"regrev", 0x00000700, 0, SROM8_REGREV, 0x00ff}, + {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff}, + {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, + {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff}, + {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, + {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff}, + {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, + {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff}, + {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, + {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff}, + {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, + {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff}, + {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, + {"ledbh0", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, + {"ledbh1", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, + {"ledbh2", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, + {"ledbh3", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, + {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, + {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, + {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, + {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff}, + {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff}, + {"pa0b0", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, + {"pa0b1", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, + {"pa0b2", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, + {"pa0itssit", 0x00000700, 0, SROM8_W0_ITTMAXP, 0xff00}, + {"pa0maxpwr", 0x00000700, 0, SROM8_W0_ITTMAXP, 0x00ff}, + {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff}, + {"opo", 0x00000700, 0, SROM8_2G_OFDMPO, 0x00ff}, + {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, + {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff}, + {"aa2g", 0x00000700, 0, SROM8_AA, 0x00ff}, + {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, + {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, + {"aa5g", 0x00000700, 0, SROM8_AA, 0xff00}, + {"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff}, + {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00}, + {"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff}, + {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00}, + {"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff}, + {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00}, + {"ag0", 0x00000700, 0, SROM8_AG10, 0x00ff}, + {"ag1", 0x00000700, 0, SROM8_AG10, 0xff00}, + {"ag2", 0x00000700, 0, SROM8_AG32, 0x00ff}, + {"ag3", 0x00000700, 0, SROM8_AG32, 0xff00}, + {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, + {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, + {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, + {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, + {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, + {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, + {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, + {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, + {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, + {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00}, + {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, + {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, + {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff}, + {"pa1b0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, + {"pa1b1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, + {"pa1b2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, + {"pa1lob0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, + {"pa1lob1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, + {"pa1lob2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, + {"pa1hib0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, + {"pa1hib1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, + {"pa1hib2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, + {"pa1itssit", 0x00000700, 0, SROM8_W1_ITTMAXP, 0xff00}, + {"pa1maxpwr", 0x00000700, 0, SROM8_W1_ITTMAXP, 0x00ff}, + {"pa1lomaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0xff00}, + {"pa1himaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, + {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, + {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, + {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, + {"bxa2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x1800}, + {"rssisav2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x0700}, + {"rssismc2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x000f}, + {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, + {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, + {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, + {"bxa5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x1800}, + {"rssisav5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x0700}, + {"rssismc5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x000f}, + {"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff}, + {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00}, + {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff}, + {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00}, + {"tri2g", 0x00000700, 0, SROM8_TRI52G, 0x00ff}, + {"tri5g", 0x00000700, 0, SROM8_TRI52G, 0xff00}, + {"tri5gl", 0x00000700, 0, SROM8_TRI5GHL, 0x00ff}, + {"tri5gh", 0x00000700, 0, SROM8_TRI5GHL, 0xff00}, + {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, + {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, + {"rxpo2g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, + {"rxpo5g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, + {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK}, + {"txchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, + {"tssipos2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK}, + {"extpagain2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK}, + {"pdetrange2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK}, + {"triso2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, + {"antswctl2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK}, + {"tssipos5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK}, + {"extpagain5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK}, + {"pdetrange5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK}, + {"triso5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, + {"antswctl5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK}, + {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff}, + {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, + {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff}, + {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, + {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff}, + {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, + {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff}, + {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, + {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff}, + {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, + {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff}, + {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, + {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff}, + {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, + {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff}, + {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, + + {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, + {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, + {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, + {"ccode", 0x00000700, SRFL_CCODE, SROM8_CCODE, 0xffff}, + {"macaddr", 0x00000700, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, + {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, + {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, + {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, + {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff}, + {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff}, + {"leddc", 0x00000700, SRFL_NOFFS|SRFL_LEDDC, SROM8_LEDDC, 0xffff}, + {"leddc", 0x000000e0, SRFL_NOFFS|SRFL_LEDDC, SROM5_LEDDC, 0xffff}, + {"leddc", 0x00000010, SRFL_NOFFS|SRFL_LEDDC, SROM4_LEDDC, 0xffff}, + {"leddc", 0x00000008, SRFL_NOFFS|SRFL_LEDDC, SROM3_LEDDC, 0xffff}, + + {"tempthresh", 0x00000700, 0, SROM8_THERMAL, 0xff00}, + {"tempoffset", 0x00000700, 0, SROM8_THERMAL, 0x00ff}, + {"rawtempsense", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff}, + {"measpower", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00}, + {"tempsense_slope", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff}, + {"tempcorrx", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00}, + {"tempsense_option", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300}, + {"freqoffset_corr", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f}, + {"iqcal_swp_dis", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010}, + {"hw_iqcal_en", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020}, + {"elna2g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0x00ff}, + {"elna5g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0xff00}, + {"phycal_tempdelta", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff}, + {"temps_period", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x0f00}, + {"temps_hysteresis", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0xf000}, + {"measpower1", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x007f}, + {"measpower2", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x3f80}, + + {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, + {"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, + {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, + {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, + {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, + {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, + {"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, + {"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, + {"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, + {"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, + {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, + {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, + {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, + {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, + {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, + {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, + {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, + {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, + {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, + {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, + {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, + {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, + {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, + {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, + {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, + {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, + {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, + {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, + {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, + {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, + {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, + {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, + {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, + {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, + {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, + {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, + {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, + {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, + {"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff}, + {"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff}, + {"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff}, + {"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff}, + {"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff}, + {"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff}, + {"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff}, + {"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff}, + {"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff}, + {"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff}, + {"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff}, + {"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff}, + {"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff}, + {"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff}, + {"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff}, + {"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff}, + {"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff}, + {"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff}, + {"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff}, + {"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff}, + {"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff}, + {"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff}, + {"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff}, + {"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff}, + {"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff}, + {"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff}, + {"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff}, + {"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff}, + {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff}, + {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff}, + {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff}, + {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, + {"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff}, + {"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff}, + {"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff}, + {"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, + + /* power per rate from sromrev 9 */ + {"cckbw202gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20, 0xffff}, + {"cckbw20ul2gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, + {"legofdmbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, + {"legofdmbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, + {"legofdmbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, + {"legofdmbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, + {"mcsbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw402gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, + {"mcsbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw405glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, + {"mcsbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw405gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, + {"mcsbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw405ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, + {"mcs32po", 0x00000600, 0, SROM9_PO_MCS32, 0xffff}, + {"legofdm40duppo", 0x00000600, 0, SROM9_PO_LOFDM40DUP, 0xffff}, + {"pcieingress_war", 0x00000700, 0, SROM8_PCIEINGRESS_WAR, 0xf}, + {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f}, + {"rxgainerr2ga1", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x07c0}, + {"rxgainerr2ga2", 0x00000700, 0, SROM8_RXGAINERR_2G, 0xf800}, + {"rxgainerr5gla0", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x003f}, + {"rxgainerr5gla1", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x07c0}, + {"rxgainerr5gla2", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0xf800}, + {"rxgainerr5gma0", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x003f}, + {"rxgainerr5gma1", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x07c0}, + {"rxgainerr5gma2", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0xf800}, + {"rxgainerr5gha0", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x003f}, + {"rxgainerr5gha1", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x07c0}, + {"rxgainerr5gha2", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0xf800}, + {"rxgainerr5gua0", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x003f}, + {"rxgainerr5gua1", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x07c0}, + {"rxgainerr5gua2", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0xf800}, + {"sar2g", 0x00000600, 0, SROM9_SAR, 0x00ff}, + {"sar5g", 0x00000600, 0, SROM9_SAR, 0xff00}, + {"noiselvl2ga0", 0x00000700, 0, SROM8_NOISELVL_2G, 0x001f}, + {"noiselvl2ga1", 0x00000700, 0, SROM8_NOISELVL_2G, 0x03e0}, + {"noiselvl2ga2", 0x00000700, 0, SROM8_NOISELVL_2G, 0x7c00}, + {"noiselvl5gla0", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x001f}, + {"noiselvl5gla1", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x03e0}, + {"noiselvl5gla2", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x7c00}, + {"noiselvl5gma0", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x001f}, + {"noiselvl5gma1", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x03e0}, + {"noiselvl5gma2", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x7c00}, + {"noiselvl5gha0", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x001f}, + {"noiselvl5gha1", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x03e0}, + {"noiselvl5gha2", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x7c00}, + {"noiselvl5gua0", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x001f}, + {"noiselvl5gua1", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x03e0}, + {"noiselvl5gua2", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x7c00}, + {"noisecaloffset", 0x00000300, 0, SROM8_NOISECALOFFSET, 0x00ff}, + {"noisecaloffset5g", 0x00000300, 0, SROM8_NOISECALOFFSET, 0xff00}, + {"subband5gver", 0x00000700, 0, SROM8_SUBBAND_PPR, 0x7}, + + {"cckPwrOffset", 0x00000400, 0, SROM10_CCKPWROFFSET, 0xffff}, + /* swctrlmap_2g array, note that the last element doesn't have SRFL_ARRAY flag set */ + {"swctrlmap_2g", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 1, 0xffff}, + {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 2, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 3, 0xffff}, + {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 4, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 5, 0xffff}, + {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 6, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 7, 0xffff}, + {"", 0x00000400, SRFL_PRHEX, SROM10_SWCTRLMAP_2G + 8, 0xffff}, + + /* sromrev 11 */ + {"boardflags3", 0xfffff800, SRFL_PRHEX|SRFL_MORE, SROM11_BFL4, 0xffff}, + {"", 0, 0, SROM11_BFL5, 0xffff}, + {"boardnum", 0xfffff800, 0, SROM11_MACLO, 0xffff}, + {"macaddr", 0xfffff800, SRFL_ETHADDR, SROM11_MACHI, 0xffff}, + {"ccode", 0xfffff800, SRFL_CCODE, SROM11_CCODE, 0xffff}, + {"regrev", 0xfffff800, 0, SROM11_REGREV, 0x00ff}, + {"ledbh0", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0x00ff}, + {"ledbh1", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0xff00}, + {"ledbh2", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0x00ff}, + {"ledbh3", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0xff00}, + {"leddc", 0xfffff800, SRFL_NOFFS|SRFL_LEDDC, SROM11_LEDDC, 0xffff}, + {"aa2g", 0xfffff800, 0, SROM11_AA, 0x00ff}, + {"aa5g", 0xfffff800, 0, SROM11_AA, 0xff00}, + {"agbg0", 0xfffff800, 0, SROM11_AGBG10, 0xff00}, + {"agbg1", 0xfffff800, 0, SROM11_AGBG10, 0x00ff}, + {"agbg2", 0xfffff800, 0, SROM11_AGBG2A0, 0xff00}, + {"aga0", 0xfffff800, 0, SROM11_AGBG2A0, 0x00ff}, + {"aga1", 0xfffff800, 0, SROM11_AGA21, 0xff00}, + {"aga2", 0xfffff800, 0, SROM11_AGA21, 0x00ff}, + {"txchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_SWITCH_MASK}, + + {"tssiposslope2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0001}, + {"epagain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x000e}, + {"pdgain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x01f0}, + {"tworangetssi2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0200}, + {"papdcap2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0400}, + {"femctrl", 0xfffff800, 0, SROM11_FEM_CFG1, 0xf800}, + + {"tssiposslope5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0001}, + {"epagain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x000e}, + {"pdgain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x01f0}, + {"tworangetssi5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0200}, + {"papdcap5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0400}, + {"gainctrlsph", 0xfffff800, 0, SROM11_FEM_CFG2, 0xf800}, + + {"tempthresh", 0xfffff800, 0, SROM11_THERMAL, 0xff00}, + {"tempoffset", 0xfffff800, 0, SROM11_THERMAL, 0x00ff}, + {"rawtempsense", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0x01ff}, + {"measpower", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0xfe00}, + {"tempsense_slope", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x00ff}, + {"tempcorrx", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0xfc00}, + {"tempsense_option", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x0300}, + {"xtalfreq", 0xfffff800, 0, SROM11_XTAL_FREQ, 0xffff}, + /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #1 */ + {"pa5gbw4080a1", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W0_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W1_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W2_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_4080_W0_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_4080_PA + 2, 0xffff}, + {"phycal_tempdelta", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x00ff}, + {"temps_period", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x0f00}, + {"temps_hysteresis", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0xf000}, + {"measpower1", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x007f}, + {"measpower2", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x3f80}, + {"tssifloor2g", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_2G, 0x03ff}, + {"tssifloor5g", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GL, 0x03ff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GM, 0x03ff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GH, 0x03ff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_5GU, 0x03ff}, + {"pdoffset2g40ma0", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x000f}, + {"pdoffset2g40ma1", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x00f0}, + {"pdoffset2g40ma2", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x0f00}, + {"pdoffset2g40mvalid", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x8000}, + {"pdoffset40ma0", 0xfffff800, 0, SROM11_PDOFF_40M_A0, 0xffff}, + {"pdoffset40ma1", 0xfffff800, 0, SROM11_PDOFF_40M_A1, 0xffff}, + {"pdoffset40ma2", 0xfffff800, 0, SROM11_PDOFF_40M_A2, 0xffff}, + {"pdoffset80ma0", 0xfffff800, 0, SROM11_PDOFF_80M_A0, 0xffff}, + {"pdoffset80ma1", 0xfffff800, 0, SROM11_PDOFF_80M_A1, 0xffff}, + {"pdoffset80ma2", 0xfffff800, 0, SROM11_PDOFF_80M_A2, 0xffff}, + + {"subband5gver", 0xfffff800, SRFL_PRHEX, SROM11_SUBBAND5GVER, 0xffff}, + {"paparambwver", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0xf000}, + /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #0 */ + {"pa5gbw4080a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 +SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, + /* Special PA Params for 4335 5G Band, 40 MHz BW */ + {"pa5gbw40a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_5GB3_PA + 2, 0xffff}, + /* Special PA Params for 4335 5G Band, 80 MHz BW */ + {"pa5gbw80a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, + /* Special PA Params for 4335 2G Band, CCK */ + {"pa2gccka0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_2G_PA + 2, 0xffff}, + + /* power per rate */ + {"cckbw202gpo", 0xfffff800, 0, SROM11_CCKBW202GPO, 0xffff}, + {"cckbw20ul2gpo", 0xfffff800, 0, SROM11_CCKBW20UL2GPO, 0xffff}, + {"mcsbw202gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW202GPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW202GPO_1, 0xffff}, + {"mcsbw402gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW402GPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW402GPO_1, 0xffff}, + {"dot11agofdmhrbw202gpo", 0xfffff800, 0, SROM11_DOT11AGOFDMHRBW202GPO, 0xffff}, + {"ofdmlrbw202gpo", 0xfffff800, 0, SROM11_OFDMLRBW202GPO, 0xffff}, + {"mcsbw205glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GLPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW205GLPO_1, 0xffff}, + {"mcsbw405glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GLPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW405GLPO_1, 0xffff}, + {"mcsbw805glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GLPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW805GLPO_1, 0xffff}, + {"mcsbw205gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GMPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW205GMPO_1, 0xffff}, + {"mcsbw405gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GMPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW405GMPO_1, 0xffff}, + {"mcsbw805gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GMPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW805GMPO_1, 0xffff}, + {"mcsbw205ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GHPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW205GHPO_1, 0xffff}, + {"mcsbw405ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GHPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW405GHPO_1, 0xffff}, + {"mcsbw805ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GHPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW805GHPO_1, 0xffff}, + {"mcslr5glpo", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0x0fff}, + {"mcslr5gmpo", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0xffff}, + {"mcslr5ghpo", 0xfffff800, 0, SROM11_MCSLR5GHPO, 0xffff}, + {"sb20in40hrpo", 0xfffff800, 0, SROM11_SB20IN40HRPO, 0xffff}, + {"sb20in80and160hr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GLPO, 0xffff}, + {"sb40and80hr5glpo", 0xfffff800, 0, SROM11_SB40AND80HR5GLPO, 0xffff}, + {"sb20in80and160hr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GMPO, 0xffff}, + {"sb40and80hr5gmpo", 0xfffff800, 0, SROM11_SB40AND80HR5GMPO, 0xffff}, + {"sb20in80and160hr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GHPO, 0xffff}, + {"sb40and80hr5ghpo", 0xfffff800, 0, SROM11_SB40AND80HR5GHPO, 0xffff}, + {"sb20in40lrpo", 0xfffff800, 0, SROM11_SB20IN40LRPO, 0xffff}, + {"sb20in80and160lr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GLPO, 0xffff}, + {"sb40and80lr5glpo", 0xfffff800, 0, SROM11_SB40AND80LR5GLPO, 0xffff}, + {"sb20in80and160lr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GMPO, 0xffff}, + {"sb40and80lr5gmpo", 0xfffff800, 0, SROM11_SB40AND80LR5GMPO, 0xffff}, + {"sb20in80and160lr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GHPO, 0xffff}, + {"sb40and80lr5ghpo", 0xfffff800, 0, SROM11_SB40AND80LR5GHPO, 0xffff}, + {"dot11agduphrpo", 0xfffff800, 0, SROM11_DOT11AGDUPHRPO, 0xffff}, + {"dot11agduplrpo", 0xfffff800, 0, SROM11_DOT11AGDUPLRPO, 0xffff}, + + /* Misc */ + {"sar2g", 0xfffff800, 0, SROM11_SAR, 0x00ff}, + {"sar5g", 0xfffff800, 0, SROM11_SAR, 0xff00}, + + {"noiselvl2ga0", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x001f}, + {"noiselvl2ga1", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x03e0}, + {"noiselvl2ga2", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x7c00}, + {"noiselvl5ga0", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x001f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x001f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x001f}, + {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x001f}, + {"noiselvl5ga1", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x03e0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x03e0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x03e0}, + {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x03e0}, + {"noiselvl5ga2", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x7c00}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x7c00}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x7c00}, + {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x7c00}, + + {"rxgainerr2ga0", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x003f}, + {"rxgainerr2ga1", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x07c0}, + {"rxgainerr2ga2", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0xf800}, + {"rxgainerr5ga0", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x003f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x003f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x003f}, + {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x003f}, + {"rxgainerr5ga1", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x07c0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x07c0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x07c0}, + {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x07c0}, + {"rxgainerr5ga2", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0xf800}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0xf800}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0xf800}, + {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0xf800}, + {"rpcal2g", 0xfffff800, 0, SROM11_RPCAL_2G, 0xffff}, + {"rpcal5gb0", 0xfffff800, 0, SROM11_RPCAL_5GL, 0xffff}, + {"rpcal5gb1", 0xfffff800, 0, SROM11_RPCAL_5GM, 0xffff}, + {"rpcal5gb2", 0xfffff800, 0, SROM11_RPCAL_5GH, 0xffff}, + {"rpcal5gb3", 0xfffff800, 0, SROM11_RPCAL_5GU, 0xffff}, + {"txidxcap2g", 0xfffff800, 0, SROM11_TXIDXCAP2G, 0x0ff0}, + {"txidxcap5g", 0xfffff800, 0, SROM11_TXIDXCAP5G, 0x0ff0}, + {"pdoffsetcckma0", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x000f}, + {"pdoffsetcckma1", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x00f0}, + {"pdoffsetcckma2", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x0f00}, + {NULL, 0, 0, 0, 0} +}; + +static const sromvar_t perpath_pci_sromvars[] = { + {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff}, + {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, + {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, + {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, + {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, + {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff}, + {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff}, + {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, + {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, + {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, + {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, + {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, + {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff}, + {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff}, + {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff}, + {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, + {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff}, + {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff}, + {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff}, + {"maxp2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0x00ff}, + {"itt2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, + {"pa2gw1a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, + {"pa2gw2a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, + {"maxp5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0x00ff}, + {"maxp5gha", 0x00000700, 0, SROM8_5GLH_MAXP, 0x00ff}, + {"maxp5gla", 0x00000700, 0, SROM8_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, + {"pa5gw1a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, + {"pa5gw2a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, + {"pa5glw0a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, + {"pa5glw1a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff}, + {"pa5glw2a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff}, + {"pa5ghw0a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, + {"pa5ghw1a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff}, + {"pa5ghw2a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff}, + + /* sromrev 11 */ + {"maxp2ga", 0xfffff800, 0, SROM11_2G_MAXP, 0x00ff}, + {"pa2ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_2G_PA + 2, 0xffff}, + {"rxgains5gmelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0007}, + {"rxgains5gmtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0078}, + {"rxgains5gmtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0080}, + {"rxgains5ghelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0700}, + {"rxgains5ghtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x7800}, + {"rxgains5ghtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x8000}, + {"rxgains2gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0007}, + {"rxgains2gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x0078}, + {"rxgains2gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x0080}, + {"rxgains5gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0700}, + {"rxgains5gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x7800}, + {"rxgains5gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x8000}, + {"maxp5ga", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0x00ff}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0xff00}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB3B2_MAXP, 0x00ff}, + {"", 0xfffff800, 0, SROM11_5GB3B2_MAXP, 0xff00}, + {"pa5ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_5GB3_PA + 2, 0xffff}, + + {NULL, 0, 0, 0, 0} +}; + +#if !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) +#define PHY_TYPE_HT 7 /* HT-Phy value */ +#define PHY_TYPE_N 4 /* N-Phy value */ +#define PHY_TYPE_LP 5 /* LP-Phy value */ +#endif /* !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) */ +#if !defined(PHY_TYPE_AC) +#define PHY_TYPE_AC 11 /* AC-Phy value */ +#endif /* !defined(PHY_TYPE_AC) */ +#if !defined(PHY_TYPE_NULL) +#define PHY_TYPE_NULL 0xf /* Invalid Phy value */ +#endif /* !defined(PHY_TYPE_NULL) */ + +typedef struct { + uint16 phy_type; + uint16 bandrange; + uint16 chain; + const char *vars; +} pavars_t; + +static const pavars_t pavars[] = { + /* HTPHY */ + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 2, "pa2gw0a2 pa2gw1a2 pa2gw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 2, "pa5glw0a2 pa5glw1a2 pa5glw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 2, "pa5gw0a2 pa5gw1a2 pa5gw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 2, "pa5ghw0a2 pa5ghw1a2 pa5ghw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 0, "pa5gw0a3 pa5gw1a3 pa5gw2a3"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 1, "pa5glw0a3 pa5glw1a3 pa5glw2a3"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 2, "pa5ghw0a3 pa5ghw1a3 pa5ghw2a3"}, + /* NPHY */ + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, + /* LPPHY */ + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_2G, 0, "pa0b0 pa0b1 pa0b2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GL, 0, "pa1lob0 pa1lob1 pa1lob2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GM, 0, "pa1b0 pa1b1 pa1b2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GH, 0, "pa1hib0 pa1hib1 pa1hib2"}, + /* ACPHY */ + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5ga2"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +/* pavars table when paparambwver is 1 */ +static const pavars_t pavars_bwver_1[] = { + /* ACPHY */ + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gccka0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga2"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5gbw40a0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw80a0"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +/* pavars table when paparambwver is 2 */ +static const pavars_t pavars_bwver_2[] = { + /* ACPHY */ + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw4080a0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 3, "pa5gbw4080a1"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +typedef struct { + uint16 phy_type; + uint16 bandrange; + const char *vars; +} povars_t; + +static const povars_t povars[] = { + /* NPHY */ + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, "mcs2gpo0 mcs2gpo1 mcs2gpo2 mcs2gpo3 " + "mcs2gpo4 mcs2gpo5 mcs2gpo6 mcs2gpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, "mcs5glpo0 mcs5glpo1 mcs5glpo2 mcs5glpo3 " + "mcs5glpo4 mcs5glpo5 mcs5glpo6 mcs5glpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, "mcs5gpo0 mcs5gpo1 mcs5gpo2 mcs5gpo3 " + "mcs5gpo4 mcs5gpo5 mcs5gpo6 mcs5gpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, "mcs5ghpo0 mcs5ghpo1 mcs5ghpo2 mcs5ghpo3 " + "mcs5ghpo4 mcs5ghpo5 mcs5ghpo6 mcs5ghpo7"}, + {PHY_TYPE_NULL, 0, ""} +}; + +typedef struct { + uint8 tag; /* Broadcom subtag name */ + uint32 revmask; /* Supported cis_sromrev */ + uint8 len; /* Length field of the tuple, note that it includes the + * subtag name (1 byte): 1 + tuple content length + */ + const char *params; +} cis_tuple_t; + +#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */ +#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */ +#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */ +#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */ + +static const cis_tuple_t cis_hnbuvars[] = { + {OTP_RAW1, 0xffffffff, 0, ""}, /* special case */ + {OTP_VERS_1, 0xffffffff, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */ + {OTP_MANFID, 0xffffffff, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */ + /* Unified OTP: tupple to embed USB manfid inside SDIO CIS */ + {HNBU_UMANFID, 0xffffffff, 8, "8usbmanfid"}, + {HNBU_SROMREV, 0xffffffff, 2, "1sromrev"}, + /* NOTE: subdevid is also written to boardtype. + * Need to write HNBU_BOARDTYPE to change it if it is different. + */ + {HNBU_CHIPID, 0xffffffff, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"}, + {HNBU_BOARDREV, 0xffffffff, 3, "2boardrev"}, + {HNBU_PAPARMS, 0xffffffff, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"}, + {HNBU_AA, 0xffffffff, 3, "1aa2g 1aa5g"}, + {HNBU_AA, 0xffffffff, 3, "1aa0 1aa1"}, /* backward compatibility */ + {HNBU_AG, 0xffffffff, 5, "1ag0 1ag1 1ag2 1ag3"}, + {HNBU_BOARDFLAGS, 0xffffffff, 13, "4boardflags 4boardflags2 4boardflags3"}, + {HNBU_LEDS, 0xffffffff, 17, "1ledbh0 1ledbh1 1ledbh2 1ledbh3 1ledbh4 1ledbh5 " + "1ledbh6 1ledbh7 1ledbh8 1ledbh9 1ledbh10 1ledbh11 1ledbh12 1ledbh13 1ledbh14 1ledbh15"}, + {HNBU_CCODE, 0xffffffff, 4, "2ccode 1cctl"}, + {HNBU_CCKPO, 0xffffffff, 3, "2cckpo"}, + {HNBU_OFDMPO, 0xffffffff, 5, "4ofdmpo"}, + {HNBU_PAPARMS5G, 0xffffffff, 23, "2pa1b0 2pa1b1 2pa1b2 2pa1lob0 2pa1lob1 2pa1lob2 " + "2pa1hib0 2pa1hib1 2pa1hib2 1pa1itssit " + "1pa1maxpwr 1pa1lomaxpwr 1pa1himaxpwr"}, + {HNBU_RDLID, 0xffffffff, 3, "2rdlid"}, + {HNBU_RSSISMBXA2G, 0xffffffff, 3, "0rssismf2g 0rssismc2g " + "0rssisav2g 0bxa2g"}, /* special case */ + {HNBU_RSSISMBXA5G, 0xffffffff, 3, "0rssismf5g 0rssismc5g " + "0rssisav5g 0bxa5g"}, /* special case */ + {HNBU_XTALFREQ, 0xffffffff, 5, "4xtalfreq"}, + {HNBU_TRI2G, 0xffffffff, 2, "1tri2g"}, + {HNBU_TRI5G, 0xffffffff, 4, "1tri5gl 1tri5g 1tri5gh"}, + {HNBU_RXPO2G, 0xffffffff, 2, "1rxpo2g"}, + {HNBU_RXPO5G, 0xffffffff, 2, "1rxpo5g"}, + {HNBU_BOARDNUM, 0xffffffff, 3, "2boardnum"}, + {HNBU_MACADDR, 0xffffffff, 7, "6macaddr"}, /* special case */ + {HNBU_RDLSN, 0xffffffff, 3, "2rdlsn"}, + {HNBU_BOARDTYPE, 0xffffffff, 3, "2boardtype"}, + {HNBU_LEDDC, 0xffffffff, 3, "2leddc"}, + {HNBU_RDLRNDIS, 0xffffffff, 2, "1rdlndis"}, + {HNBU_CHAINSWITCH, 0xffffffff, 5, "1txchain 1rxchain 2antswitch"}, + {HNBU_REGREV, 0xffffffff, 2, "1regrev"}, + {HNBU_FEM, 0x000007fe, 5, "0antswctl2g 0triso2g 0pdetrange2g 0extpagain2g " + "0tssipos2g 0antswctl5g 0triso5g 0pdetrange5g 0extpagain5g 0tssipos5g"}, /* special case */ + {HNBU_PAPARMS_C0, 0x000007fe, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 " + "2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 2pa5gw1a0 2pa5gw2a0 " + "2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 2pa5ghw1a0 2pa5ghw2a0"}, + {HNBU_PAPARMS_C1, 0x000007fe, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 " + "2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 2pa5gw1a1 2pa5gw2a1 " + "2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 2pa5ghw1a1 2pa5ghw2a1"}, + {HNBU_PO_CCKOFDM, 0xffffffff, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo " + "4ofdm5ghpo"}, + {HNBU_PO_MCS2G, 0xffffffff, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 " + "2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"}, + {HNBU_PO_MCS5GM, 0xffffffff, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 " + "2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"}, + {HNBU_PO_MCS5GLH, 0xffffffff, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 " + "2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 " + "2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 " + "2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"}, + {HNBU_CCKFILTTYPE, 0xffffffff, 2, "1cckdigfilttype"}, + {HNBU_PO_CDD, 0xffffffff, 3, "2cddpo"}, + {HNBU_PO_STBC, 0xffffffff, 3, "2stbcpo"}, + {HNBU_PO_40M, 0xffffffff, 3, "2bw40po"}, + {HNBU_PO_40MDUP, 0xffffffff, 3, "2bwduppo"}, + {HNBU_RDLRWU, 0xffffffff, 2, "1rdlrwu"}, + {HNBU_WPS, 0xffffffff, 3, "1wpsgpio 1wpsled"}, + {HNBU_USBFS, 0xffffffff, 2, "1usbfs"}, + {HNBU_ELNA2G, 0xffffffff, 2, "1elna2g"}, + {HNBU_ELNA5G, 0xffffffff, 2, "1elna5g"}, + {HNBU_CUSTOM1, 0xffffffff, 5, "4customvar1"}, + {OTP_RAW, 0xffffffff, 0, ""}, /* special case */ + {HNBU_OFDMPO5G, 0xffffffff, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"}, + {HNBU_USBEPNUM, 0xffffffff, 3, "2usbepnum"}, + {HNBU_CCKBW202GPO, 0xffffffff, 5, "2cckbw202gpo 2cckbw20ul2gpo"}, + {HNBU_LEGOFDMBW202GPO, 0xffffffff, 9, "4legofdmbw202gpo 4legofdmbw20ul2gpo"}, + {HNBU_LEGOFDMBW205GPO, 0xffffffff, 25, "4legofdmbw205glpo 4legofdmbw20ul5glpo " + "4legofdmbw205gmpo 4legofdmbw20ul5gmpo 4legofdmbw205ghpo 4legofdmbw20ul5ghpo"}, + {HNBU_MCS2GPO, 0xffffffff, 13, "4mcsbw202gpo 4mcsbw20ul2gpo 4mcsbw402gpo"}, + {HNBU_MCS5GLPO, 0xffffffff, 13, "4mcsbw205glpo 4mcsbw20ul5glpo 4mcsbw405glpo"}, + {HNBU_MCS5GMPO, 0xffffffff, 13, "4mcsbw205gmpo 4mcsbw20ul5gmpo 4mcsbw405gmpo"}, + {HNBU_MCS5GHPO, 0xffffffff, 13, "4mcsbw205ghpo 4mcsbw20ul5ghpo 4mcsbw405ghpo"}, + {HNBU_MCS32PO, 0xffffffff, 3, "2mcs32po"}, + {HNBU_LEG40DUPPO, 0xffffffff, 3, "2legofdm40duppo"}, + {HNBU_TEMPTHRESH, 0xffffffff, 7, "1tempthresh 0temps_period 0temps_hysteresis " + "1tempoffset 1tempsense_slope 0tempcorrx 0tempsense_option " + "1phycal_tempdelta"}, /* special case */ + {HNBU_MUXENAB, 0xffffffff, 2, "1muxenab"}, + {HNBU_FEM_CFG, 0xfffff800, 5, "0femctrl 0papdcap2g 0tworangetssi2g 0pdgain2g " + "0epagain2g 0tssiposslope2g 0gainctrlsph 0papdcap5g 0tworangetssi5g 0pdgain5g 0epagain5g " + "0tssiposslope5g"}, /* special case */ + {HNBU_ACPA_C0, 0xfffff800, 39, "2subband5gver 2maxp2ga0 2*3pa2ga0 " + "1*4maxp5ga0 2*12pa5ga0"}, + {HNBU_ACPA_C1, 0xfffff800, 37, "2maxp2ga1 2*3pa2ga1 1*4maxp5ga1 2*12pa5ga1"}, + {HNBU_ACPA_C2, 0xfffff800, 37, "2maxp2ga2 2*3pa2ga2 1*4maxp5ga2 2*12pa5ga2"}, + {HNBU_MEAS_PWR, 0xfffff800, 5, "1measpower 1measpower1 1measpower2 2rawtempsense"}, + {HNBU_PDOFF, 0xfffff800, 13, "2pdoffset40ma0 2pdoffset40ma1 2pdoffset40ma2 " + "2pdoffset80ma0 2pdoffset80ma1 2pdoffset80ma2"}, + {HNBU_ACPPR_2GPO, 0xfffff800, 5, "2dot11agofdmhrbw202gpo 2ofdmlrbw202gpo"}, + {HNBU_ACPPR_5GPO, 0xfffff800, 31, "4mcsbw805glpo 4mcsbw1605glpo 4mcsbw805gmpo " + "4mcsbw1605gmpo 4mcsbw805ghpo 4mcsbw1605ghpo 2mcslr5glpo 2mcslr5gmpo 2mcslr5ghpo"}, + {HNBU_ACPPR_SBPO, 0xfffff800, 33, "2sb20in40hrpo 2sb20in80and160hr5glpo " + "2sb40and80hr5glpo 2sb20in80and160hr5gmpo 2sb40and80hr5gmpo 2sb20in80and160hr5ghpo " + "2sb40and80hr5ghpo 2sb20in40lrpo 2sb20in80and160lr5glpo 2sb40and80lr5glpo " + "2sb20in80and160lr5gmpo 2sb40and80lr5gmpo 2sb20in80and160lr5ghpo 2sb40and80lr5ghpo " + "2dot11agduphrpo 2dot11agduplrpo"}, + {HNBU_NOISELVL, 0xfffff800, 16, "1noiselvl2ga0 1noiselvl2ga1 1noiselvl2ga2 " + "1*4noiselvl5ga0 1*4noiselvl5ga1 1*4noiselvl5ga2"}, + {HNBU_RXGAIN_ERR, 0xfffff800, 16, "1rxgainerr2ga0 1rxgainerr2ga1 1rxgainerr2ga2 " + "1*4rxgainerr5ga0 1*4rxgainerr5ga1 1*4rxgainerr5ga2"}, + {HNBU_AGBGA, 0xfffff800, 7, "1agbg0 1agbg1 1agbg2 1aga0 1aga1 1aga2"}, + {HNBU_UUID, 0xffffffff, 17, "16uuid"}, + {HNBU_WOWLGPIO, 0xffffffff, 2, "1wowl_gpio"}, + {HNBU_ACRXGAINS_C0, 0xfffff800, 5, "0rxgains5gtrelnabypa0 0rxgains5gtrisoa0 " + "0rxgains5gelnagaina0 0rxgains2gtrelnabypa0 0rxgains2gtrisoa0 0rxgains2gelnagaina0 " + "0rxgains5ghtrelnabypa0 0rxgains5ghtrisoa0 0rxgains5ghelnagaina0 0rxgains5gmtrelnabypa0 " + "0rxgains5gmtrisoa0 0rxgains5gmelnagaina0"}, /* special case */ + {HNBU_ACRXGAINS_C1, 0xfffff800, 5, "0rxgains5gtrelnabypa1 0rxgains5gtrisoa1 " + "0rxgains5gelnagaina1 0rxgains2gtrelnabypa1 0rxgains2gtrisoa1 0rxgains2gelnagaina1 " + "0rxgains5ghtrelnabypa1 0rxgains5ghtrisoa1 0rxgains5ghelnagaina1 0rxgains5gmtrelnabypa1 " + "0rxgains5gmtrisoa1 0rxgains5gmelnagaina1"}, /* special case */ + {HNBU_ACRXGAINS_C2, 0xfffff800, 5, "0rxgains5gtrelnabypa2 0rxgains5gtrisoa2 " + "0rxgains5gelnagaina2 0rxgains2gtrelnabypa2 0rxgains2gtrisoa2 0rxgains2gelnagaina2 " + "0rxgains5ghtrelnabypa2 0rxgains5ghtrisoa2 0rxgains5ghelnagaina2 0rxgains5gmtrelnabypa2 " + "0rxgains5gmtrisoa2 0rxgains5gmelnagaina2"}, /* special case */ + {HNBU_TXDUTY, 0xfffff800, 9, "2tx_duty_cycle_ofdm_40_5g " + "2tx_duty_cycle_thresh_40_5g 2tx_duty_cycle_ofdm_80_5g 2tx_duty_cycle_thresh_80_5g"}, + {HNBU_PDOFF_2G, 0xfffff800, 3, "0pdoffset2g40ma0 0pdoffset2g40ma1 " + "0pdoffset2g40ma2 0pdoffset2g40mvalid"}, + {HNBU_ACPA_CCK, 0xfffff800, 7, "2*3pa2gccka0"}, + {HNBU_ACPA_40, 0xfffff800, 25, "2*12pa5gbw40a0"}, + {HNBU_ACPA_80, 0xfffff800, 25, "2*12pa5gbw80a0"}, + {HNBU_ACPA_4080, 0xfffff800, 49, "2*12pa5gbw4080a0 2*12pa5gbw4080a1"}, + {HNBU_SUBBAND5GVER, 0xfffff800, 3, "2subband5gver"}, + {HNBU_PAPARAMBWVER, 0xfffff800, 2, "1paparambwver"}, + {0xFF, 0xffffffff, 0, ""} +}; + +#endif /* _bcmsrom_tbl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h new file mode 100644 index 000000000000..1743d1f8e927 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h @@ -0,0 +1,1238 @@ +/* + * Misc useful os-independent macros and functions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmutils.h 596861 2015-11-03 08:54:58Z $ + */ + +#ifndef _bcmutils_h_ +#define _bcmutils_h_ + +#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) +#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) +#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PKTQ_LOG +#include +#endif + +/* ctype replacement */ +#define _BCM_U 0x01 /* upper */ +#define _BCM_L 0x02 /* lower */ +#define _BCM_D 0x04 /* digit */ +#define _BCM_C 0x08 /* cntrl */ +#define _BCM_P 0x10 /* punct */ +#define _BCM_S 0x20 /* white space (space/lf/tab) */ +#define _BCM_X 0x40 /* hex digit */ +#define _BCM_SP 0x80 /* hard space (0x20) */ + +extern const unsigned char bcm_ctype[]; +#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) + +#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) +#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) +#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) +#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) +#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) +#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) +#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) +#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) +#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) +#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) +#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) +#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) + +/* Buffer structure for collecting string-formatted data +* using bcm_bprintf() API. +* Use bcm_binit() to initialize before use +*/ + +struct bcmstrbuf { + char *buf; /* pointer to current position in origbuf */ + unsigned int size; /* current (residual) size in bytes */ + char *origbuf; /* unmodified pointer to orignal buffer */ + unsigned int origsize; /* unmodified orignal buffer size in bytes */ +}; + +/* ** driver-only section ** */ +#ifdef BCMDRIVER +#include + +#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */ + +/* + * 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. + */ +#ifndef SPINWAIT_POLL_PERIOD +#define SPINWAIT_POLL_PERIOD 10 +#endif + +#define SPINWAIT(exp, us) { \ + uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1); \ + while ((exp) && (countdown >= SPINWAIT_POLL_PERIOD)) { \ + OSL_DELAY(SPINWAIT_POLL_PERIOD); \ + countdown -= SPINWAIT_POLL_PERIOD; \ + } \ +} + +/* osl multi-precedence packet queue */ +#define PKTQ_LEN_MAX 0xFFFF /* Max uint16 65535 packets */ +#ifndef PKTQ_LEN_DEFAULT +#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ +#endif +#ifndef PKTQ_MAX_PREC +#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ +#endif + +typedef struct pktq_prec { + void *head; /* first packet to dequeue */ + void *tail; /* last packet to dequeue */ + uint16 len; /* number of queued packets */ + uint16 max; /* maximum number of queued packets */ +} pktq_prec_t; + +#ifdef PKTQ_LOG +typedef struct { + uint32 requested; /* packets requested to be stored */ + uint32 stored; /* packets stored */ + uint32 saved; /* packets saved, + because a lowest priority queue has given away one packet + */ + uint32 selfsaved; /* packets saved, + because an older packet from the same queue has been dropped + */ + uint32 full_dropped; /* packets dropped, + because pktq is full with higher precedence packets + */ + uint32 dropped; /* packets dropped because pktq per that precedence is full */ + uint32 sacrificed; /* packets dropped, + in order to save one from a queue of a highest priority + */ + uint32 busy; /* packets droped because of hardware/transmission error */ + uint32 retry; /* packets re-sent because they were not received */ + uint32 ps_retry; /* packets retried again prior to moving power save mode */ + uint32 suppress; /* packets which were suppressed and not transmitted */ + uint32 retry_drop; /* packets finally dropped after retry limit */ + uint32 max_avail; /* the high-water mark of the queue capacity for packets - + goes to zero as queue fills + */ + uint32 max_used; /* the high-water mark of the queue utilisation for packets - + increases with use ('inverse' of max_avail) + */ + uint32 queue_capacity; /* the maximum capacity of the queue */ + uint32 rtsfail; /* count of rts attempts that failed to receive cts */ + uint32 acked; /* count of packets sent (acked) successfully */ + uint32 txrate_succ; /* running total of phy rate of packets sent successfully */ + uint32 txrate_main; /* running totoal of primary phy rate of all packets */ + uint32 throughput; /* actual data transferred successfully */ + uint32 airtime; /* cumulative total medium access delay in useconds */ + uint32 _logtime; /* timestamp of last counter clear */ +} pktq_counters_t; + +typedef struct { + uint32 _prec_log; + pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */ +} pktq_log_t; +#endif /* PKTQ_LOG */ + + +#define PKTQ_COMMON \ + uint16 num_prec; /* number of precedences in use */ \ + uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ \ + uint16 max; /* total max packets */ \ + uint16 len; /* total number of packets */ + +/* multi-priority pkt queue */ +struct pktq { + PKTQ_COMMON + /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ + struct pktq_prec q[PKTQ_MAX_PREC]; +#ifdef PKTQ_LOG + pktq_log_t* pktqlog; +#endif +}; + +/* simple, non-priority pkt queue */ +struct spktq { + PKTQ_COMMON + /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ + struct pktq_prec q[1]; +}; + +#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) + +/* fn(pkt, arg). return true if pkt belongs to if */ +typedef bool (*ifpkt_cb_t)(void*, int); + +#ifdef BCMPKTPOOL +#define POOL_ENAB(pool) ((pool) && (pool)->inited) +#define SHARED_POOL (pktpool_shared) +#else /* BCMPKTPOOL */ +#define POOL_ENAB(bus) 0 +#define SHARED_POOL ((struct pktpool *)NULL) +#endif /* BCMPKTPOOL */ + +#ifdef BCMFRAGPOOL +#define SHARED_FRAG_POOL (pktpool_shared_lfrag) +#endif +#define SHARED_RXFRAG_POOL (pktpool_shared_rxlfrag) + + +#ifndef PKTPOOL_LEN_MAX +#define PKTPOOL_LEN_MAX 40 +#endif /* PKTPOOL_LEN_MAX */ +#define PKTPOOL_CB_MAX 3 + +struct pktpool; +typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); +typedef struct { + pktpool_cb_t cb; + void *arg; +} pktpool_cbinfo_t; +/* call back fn extension to populate host address in pool pkt */ +typedef int (*pktpool_cb_extn_t)(struct pktpool *pool, void *arg, void* pkt); +typedef struct { + pktpool_cb_extn_t cb; + void *arg; +} pktpool_cbextn_info_t; + + +#ifdef BCMDBG_POOL +/* pkt pool debug states */ +#define POOL_IDLE 0 +#define POOL_RXFILL 1 +#define POOL_RXDH 2 +#define POOL_RXD11 3 +#define POOL_TXDH 4 +#define POOL_TXD11 5 +#define POOL_AMPDU 6 +#define POOL_TXENQ 7 + +typedef struct { + void *p; + uint32 cycles; + uint32 dur; +} pktpool_dbg_t; + +typedef struct { + uint8 txdh; /* tx to host */ + uint8 txd11; /* tx to d11 */ + uint8 enq; /* waiting in q */ + uint8 rxdh; /* rx from host */ + uint8 rxd11; /* rx from d11 */ + uint8 rxfill; /* dma_rxfill */ + uint8 idle; /* avail in pool */ +} pktpool_stats_t; +#endif /* BCMDBG_POOL */ + +typedef struct pktpool { + bool inited; /* pktpool_init was successful */ + uint8 type; /* type of lbuf: basic, frag, etc */ + uint8 id; /* pktpool ID: index in registry */ + bool istx; /* direction: transmit or receive data path */ + + void * freelist; /* free list: see PKTNEXTFREE(), PKTSETNEXTFREE() */ + uint16 avail; /* number of packets in pool's free list */ + uint16 len; /* number of packets managed by pool */ + uint16 maxlen; /* maximum size of pool <= PKTPOOL_LEN_MAX */ + uint16 plen; /* size of pkt buffer, excluding lbuf|lbuf_frag */ + + bool empty; + uint8 cbtoggle; + uint8 cbcnt; + uint8 ecbcnt; + bool emptycb_disable; + pktpool_cbinfo_t *availcb_excl; + pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; + pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; + pktpool_cbextn_info_t cbext; +#ifdef BCMDBG_POOL + uint8 dbg_cbcnt; + pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; + uint16 dbg_qlen; + pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; +#endif +} pktpool_t; + +extern pktpool_t *pktpool_shared; +#ifdef BCMFRAGPOOL +extern pktpool_t *pktpool_shared_lfrag; +#endif +extern pktpool_t *pktpool_shared_rxlfrag; + +/* Incarnate a pktpool registry. On success returns total_pools. */ +extern int pktpool_attach(osl_t *osh, uint32 total_pools); +extern int pktpool_dettach(osl_t *osh); /* Relinquish registry */ + +extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx, uint8 type); +extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); +extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); +extern void* pktpool_get(pktpool_t *pktp); +extern void pktpool_free(pktpool_t *pktp, void *p); +extern int pktpool_add(pktpool_t *pktp, void *p); +extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); +extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); +extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); +extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); +extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); +extern bool pktpool_emptycb_disabled(pktpool_t *pktp); +int pktpool_hostaddr_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg); +#define POOLPTR(pp) ((pktpool_t *)(pp)) +#define POOLID(pp) (POOLPTR(pp)->id) + +#define POOLSETID(pp, ppid) (POOLPTR(pp)->id = (ppid)) + +#define pktpool_len(pp) (POOLPTR(pp)->len) +#define pktpool_avail(pp) (POOLPTR(pp)->avail) +#define pktpool_plen(pp) (POOLPTR(pp)->plen) +#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) + + +/* + * ---------------------------------------------------------------------------- + * A pool ID is assigned with a pkt pool during pool initialization. This is + * done by maintaining a registry of all initialized pools, and the registry + * index at which the pool is registered is used as the pool's unique ID. + * ID 0 is reserved and is used to signify an invalid pool ID. + * All packets henceforth allocated from a pool will be tagged with the pool's + * unique ID. Packets allocated from the heap will use the reserved ID = 0. + * Packets with non-zero pool id signify that they were allocated from a pool. + * A maximum of 15 pools are supported, allowing a 4bit pool ID to be used + * in place of a 32bit pool pointer in each packet. + * ---------------------------------------------------------------------------- + */ +#define PKTPOOL_INVALID_ID (0) +#define PKTPOOL_MAXIMUM_ID (15) + +/* Registry of pktpool(s) */ +extern pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; + +/* Pool ID to/from Pool Pointer converters */ +#define PKTPOOL_ID2PTR(id) (pktpools_registry[id]) +#define PKTPOOL_PTR2ID(pp) (POOLID(pp)) + + +#ifdef BCMDBG_POOL +extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_start_trigger(pktpool_t *pktp, void *p); +extern int pktpool_dbg_dump(pktpool_t *pktp); +extern int pktpool_dbg_notify(pktpool_t *pktp); +extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); +#endif /* BCMDBG_POOL */ + +/* forward definition of ether_addr structure used by some function prototypes */ + +struct ether_addr; + +extern int ether_isbcast(const void *ea); +extern int ether_isnulladdr(const void *ea); + +/* operations on a specific precedence in packet queue */ + +#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) +#define pktq_pmax(pq, prec) ((pq)->q[prec].max) +#define pktq_plen(pq, prec) ((pq)->q[prec].len) +#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) +#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) +#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) + +#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) +#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) + +extern void *pktq_penq(struct pktq *pq, int prec, void *p); +extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); +extern void *pktq_pdeq(struct pktq *pq, int prec); +extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); +extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg); +extern void *pktq_pdeq_tail(struct pktq *pq, int prec); +/* Empty the queue at particular precedence level */ +extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, + ifpkt_cb_t fn, int arg); +/* Remove a specified packet from its queue */ +extern bool pktq_pdel(struct pktq *pq, void *p, int prec); + +/* operations on a set of precedences in packet queue */ + +extern int pktq_mlen(struct pktq *pq, uint prec_bmp); +extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); +extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); + +/* operations on packet queue as a whole */ + +#define pktq_len(pq) ((int)(pq)->len) +#define pktq_max(pq) ((int)(pq)->max) +#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) +#define pktq_full(pq) ((pq)->len >= (pq)->max) +#define pktq_empty(pq) ((pq)->len == 0) + +/* operations for single precedence queues */ +#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) +#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) +#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) +#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) +#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) + +extern void pktq_init(struct pktq *pq, int num_prec, int max_len); +extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); + +/* prec_out may be NULL if caller is not interested in return value */ +extern void *pktq_deq(struct pktq *pq, int *prec_out); +extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); +extern void *pktq_peek(struct pktq *pq, int *prec_out); +extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); +extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); + +/* externs */ +/* packet */ +extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); +extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); +extern uint pkttotlen(osl_t *osh, void *p); +extern void *pktlast(osl_t *osh, void *p); +extern uint pktsegcnt(osl_t *osh, void *p); +extern uint pktsegcnt_war(osl_t *osh, void *p); +extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset); +extern void *pktoffset(osl_t *osh, void *p, uint offset); + +/* Get priority from a packet and pass it back in scb (or equiv) */ +#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */ +#define PKTPRIO_VLAN 0x200 /* VLAN prio found */ +#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ +#define PKTPRIO_DSCP 0x800 /* DSCP prio found */ + +/* DSCP type definitions (RFC4594) */ +/* AF1x: High-Throughput Data (RFC2597) */ +#define DSCP_AF11 0x0A +#define DSCP_AF12 0x0C +#define DSCP_AF13 0x0E +/* AF2x: Low-Latency Data (RFC2597) */ +#define DSCP_AF21 0x12 +#define DSCP_AF22 0x14 +#define DSCP_AF23 0x16 +/* AF3x: Multimedia Streaming (RFC2597) */ +#define DSCP_AF31 0x1A +#define DSCP_AF32 0x1C +#define DSCP_AF33 0x1E +/* EF: Telephony (RFC3246) */ +#define DSCP_EF 0x2E + +extern uint pktsetprio(void *pkt, bool update_vtag); + +/* string */ +extern int bcm_atoi(const char *s); +extern ulong bcm_strtoul(const char *cp, char **endp, uint base); +extern char *bcmstrstr(const char *haystack, const char *needle); +extern char *bcmstrcat(char *dest, const char *src); +extern char *bcmstrncat(char *dest, const char *src, uint size); +extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); +char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); +int bcmstricmp(const char *s1, const char *s2); +int bcmstrnicmp(const char* s1, const char* s2, int cnt); + + +/* ethernet address */ +extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); +extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); + +/* ip address */ +struct ipv4_addr; +extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); +extern char *bcm_ipv6_ntoa(void *ipv6, char *buf); +extern int bcm_atoipv4(const char *p, struct ipv4_addr *ip); + +/* delay */ +extern void bcm_mdelay(uint ms); +/* variable access */ +#define NVRAM_RECLAIM_CHECK(name) + +extern char *getvar(char *vars, const char *name); +extern int getintvar(char *vars, const char *name); +extern int getintvararray(char *vars, const char *name, int index); +extern int getintvararraysize(char *vars, const char *name); +extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); +#define bcm_perf_enable() +#define bcmstats(fmt) +#define bcmlog(fmt, a1, a2) +#define bcmdumplog(buf, size) *buf = '\0' +#define bcmdumplogent(buf, idx) -1 + +#define TSF_TICKS_PER_MS 1000 + +#define bcmtslog(tstamp, fmt, a1, a2) +#define bcmprinttslogs() +#define bcmprinttstamp(us) +#define bcmdumptslog(buf, size) + +extern char *bcm_nvram_vars(uint *length); +extern int bcm_nvram_cache(void *sih); + +/* Support for sharing code across in-driver iovar implementations. + * The intent is that a driver use this structure to map iovar names + * to its (private) iovar identifiers, and the lookup function to + * find the entry. Macros are provided to map ids and get/set actions + * into a single number space for a switch statement. + */ + +/* iovar structure */ +typedef struct bcm_iovar { + const char *name; /* name for lookup and display */ + uint16 varid; /* id for switch */ + uint16 flags; /* driver-specific flag bits */ + uint16 type; /* base type of argument */ + uint16 minlen; /* min length for buffer vars */ +} bcm_iovar_t; + +/* varid definitions are per-driver, may use these get/set bits */ + +/* IOVar action bits for id mapping */ +#define IOV_GET 0 /* Get an iovar */ +#define IOV_SET 1 /* Set an iovar */ + +/* Varid to actionid mapping */ +#define IOV_GVAL(id) ((id) * 2) +#define IOV_SVAL(id) ((id) * 2 + IOV_SET) +#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) +#define IOV_ID(actionid) (actionid >> 1) + +/* flags are per-driver based on driver attributes */ + +extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); +extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); +#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ + defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) +extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); +#endif +#endif /* BCMDRIVER */ + +/* Base type definitions */ +#define IOVT_VOID 0 /* no value (implictly set only) */ +#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */ +#define IOVT_INT8 2 /* integer values are range-checked */ +#define IOVT_UINT8 3 /* unsigned int 8 bits */ +#define IOVT_INT16 4 /* int 16 bits */ +#define IOVT_UINT16 5 /* unsigned int 16 bits */ +#define IOVT_INT32 6 /* int 32 bits */ +#define IOVT_UINT32 7 /* unsigned int 32 bits */ +#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */ +#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) + +/* Initializer for IOV type strings */ +#define BCM_IOV_TYPE_INIT { \ + "void", \ + "bool", \ + "int8", \ + "uint8", \ + "int16", \ + "uint16", \ + "int32", \ + "uint32", \ + "buffer", \ + "" } + +#define BCM_IOVT_IS_INT(type) (\ + (type == IOVT_BOOL) || \ + (type == IOVT_INT8) || \ + (type == IOVT_UINT8) || \ + (type == IOVT_INT16) || \ + (type == IOVT_UINT16) || \ + (type == IOVT_INT32) || \ + (type == IOVT_UINT32)) + +/* ** driver/apps-shared section ** */ + +#define BCME_STRLEN 64 /* Max string length for BCM errors */ +#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) + + +/* + * error codes could be added but the defined ones shouldn't be changed/deleted + * these error codes are exposed to the user code + * when ever a new error code is added to this list + * please update errorstring table with the related error string and + * update osl files with os specific errorcode map +*/ + +#define BCME_OK 0 /* Success */ +#define BCME_ERROR -1 /* Error generic */ +#define BCME_BADARG -2 /* Bad Argument */ +#define BCME_BADOPTION -3 /* Bad option */ +#define BCME_NOTUP -4 /* Not up */ +#define BCME_NOTDOWN -5 /* Not down */ +#define BCME_NOTAP -6 /* Not AP */ +#define BCME_NOTSTA -7 /* Not STA */ +#define BCME_BADKEYIDX -8 /* BAD Key Index */ +#define BCME_RADIOOFF -9 /* Radio Off */ +#define BCME_NOTBANDLOCKED -10 /* Not band locked */ +#define BCME_NOCLK -11 /* No Clock */ +#define BCME_BADRATESET -12 /* BAD Rate valueset */ +#define BCME_BADBAND -13 /* BAD Band */ +#define BCME_BUFTOOSHORT -14 /* Buffer too short */ +#define BCME_BUFTOOLONG -15 /* Buffer too long */ +#define BCME_BUSY -16 /* Busy */ +#define BCME_NOTASSOCIATED -17 /* Not Associated */ +#define BCME_BADSSIDLEN -18 /* Bad SSID len */ +#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ +#define BCME_BADCHAN -20 /* Bad Channel */ +#define BCME_BADADDR -21 /* Bad Address */ +#define BCME_NORESOURCE -22 /* Not Enough Resources */ +#define BCME_UNSUPPORTED -23 /* Unsupported */ +#define BCME_BADLEN -24 /* Bad length */ +#define BCME_NOTREADY -25 /* Not Ready */ +#define BCME_EPERM -26 /* Not Permitted */ +#define BCME_NOMEM -27 /* No Memory */ +#define BCME_ASSOCIATED -28 /* Associated */ +#define BCME_RANGE -29 /* Not In Range */ +#define BCME_NOTFOUND -30 /* Not Found */ +#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ +#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ +#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ +#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ +#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ +#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ +#define BCME_VERSION -37 /* Incorrect version */ +#define BCME_TXFAIL -38 /* TX failure */ +#define BCME_RXFAIL -39 /* RX failure */ +#define BCME_NODEVICE -40 /* Device not present */ +#define BCME_NMODE_DISABLED -41 /* NMODE disabled */ +#define BCME_NONRESIDENT -42 /* access to nonresident overlay */ +#define BCME_SCANREJECT -43 /* reject scan request */ +#define BCME_USAGE_ERROR -44 /* WLCMD usage error */ +#define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */ +#define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */ +#define BCME_DISABLED -47 /* Disabled in this build */ +#define BCME_DECERR -48 /* Decrypt error */ +#define BCME_ENCERR -49 /* Encrypt error */ +#define BCME_MICERR -50 /* Integrity/MIC error */ +#define BCME_REPLAY -51 /* Replay */ +#define BCME_IE_NOTFOUND -52 /* IE not found */ +#define BCME_LAST BCME_IE_NOTFOUND + +#define BCME_NOTENABLED BCME_DISABLED + +/* These are collection of BCME Error strings */ +#define BCMERRSTRINGTABLE { \ + "OK", \ + "Undefined error", \ + "Bad Argument", \ + "Bad Option", \ + "Not up", \ + "Not down", \ + "Not AP", \ + "Not STA", \ + "Bad Key Index", \ + "Radio Off", \ + "Not band locked", \ + "No clock", \ + "Bad Rate valueset", \ + "Bad Band", \ + "Buffer too short", \ + "Buffer too long", \ + "Busy", \ + "Not Associated", \ + "Bad SSID len", \ + "Out of Range Channel", \ + "Bad Channel", \ + "Bad Address", \ + "Not Enough Resources", \ + "Unsupported", \ + "Bad length", \ + "Not Ready", \ + "Not Permitted", \ + "No Memory", \ + "Associated", \ + "Not In Range", \ + "Not Found", \ + "WME Not Enabled", \ + "TSPEC Not Found", \ + "ACM Not Supported", \ + "Not WME Association", \ + "SDIO Bus Error", \ + "Dongle Not Accessible", \ + "Incorrect version", \ + "TX Failure", \ + "RX Failure", \ + "Device Not Present", \ + "NMODE Disabled", \ + "Nonresident overlay access", \ + "Scan Rejected", \ + "WLCMD usage error", \ + "WLCMD ioctl error", \ + "RWL serial port error", \ + "Disabled", \ + "Decrypt error", \ + "Encrypt error", \ + "MIC error", \ + "Replay", \ + "IE not found", \ +} + +#ifndef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) +#endif /* ABS */ + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* MIN */ + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif /* MAX */ + +/* limit to [min, max] */ +#ifndef LIMIT_TO_RANGE +#define LIMIT_TO_RANGE(x, min, max) \ + ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) +#endif /* LIMIT_TO_RANGE */ + +/* limit to max */ +#ifndef LIMIT_TO_MAX +#define LIMIT_TO_MAX(x, max) \ + (((x) > (max) ? (max) : (x))) +#endif /* LIMIT_TO_MAX */ + +/* limit to min */ +#ifndef LIMIT_TO_MIN +#define LIMIT_TO_MIN(x, min) \ + (((x) < (min) ? (min) : (x))) +#endif /* LIMIT_TO_MIN */ + +#define DELTA(curr, prev) ((curr) > (prev) ? ((curr) - (prev)) : \ + (0xffffffff - (prev) + (curr) + 1)) +#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) +#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#define ROUNDDN(p, align) ((p) & ~((align) - 1)) +#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) +#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ + & ~((boundary) - 1)) +#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ + & ~((boundary) - 1)) +#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) +#define VALID_MASK(mask) !((mask) & ((mask) + 1)) + +#ifndef OFFSETOF +#ifdef __ARMCC_VERSION +/* + * The ARM RVCT compiler complains when using OFFSETOF where a constant + * expression is expected, such as an initializer for a static object. + * offsetof from the runtime library doesn't have that problem. + */ +#include +#define OFFSETOF(type, member) offsetof(type, member) +#else +# if ((__GNUC__ >= 4) && (__GNUC_MINOR__ >= 8)) +/* GCC 4.8+ complains when using our OFFSETOF macro in array length declarations. */ +# define OFFSETOF(type, member) __builtin_offsetof(type, member) +# else +# define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) +# endif /* GCC 4.8 or newer */ +#endif /* __ARMCC_VERSION */ +#endif /* OFFSETOF */ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) +#endif + +#ifndef ARRAYLAST /* returns pointer to last array element */ +#define ARRAYLAST(a) (&a[ARRAYSIZE(a)-1]) +#endif + +/* Reference a function; used to prevent a static function from being optimized out */ +extern void *_bcmutils_dummy_fn; +#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) + +/* bit map related macros */ +#ifndef setbit +#ifndef NBBY /* the BSD family defines NBBY */ +#define NBBY 8 /* 8 bits per byte */ +#endif /* #ifndef NBBY */ +#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS +extern void setbit(void *array, uint bit); +extern void clrbit(void *array, uint bit); +extern bool isset(const void *array, uint bit); +extern bool isclr(const void *array, uint bit); +#else +#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) +#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) +#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) +#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) +#endif +#endif /* setbit */ + +#define isbitset(a, i) (((a) & (1 << (i))) != 0) + +#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) + +extern void bcm_bitprint32(const uint32 u32); + +/* + * ---------------------------------------------------------------------------- + * Multiword map of 2bits, nibbles + * setbit2 setbit4 (void *ptr, uint32 ix, uint32 val) + * getbit2 getbit4 (void *ptr, uint32 ix) + * ---------------------------------------------------------------------------- + */ + +#define DECLARE_MAP_API(NB, RSH, LSH, OFF, MSK) \ +static INLINE void setbit##NB(void *ptr, uint32 ix, uint32 val) \ +{ \ + uint32 *addr = (uint32 *)ptr; \ + uint32 *a = addr + (ix >> RSH); /* (ix / 2^RSH) */ \ + uint32 pos = (ix & OFF) << LSH; /* (ix % 2^RSH) * 2^LSH */ \ + uint32 mask = (MSK << pos); \ + uint32 tmp = *a & ~mask; \ + *a = tmp | (val << pos); \ +} \ +static INLINE uint32 getbit##NB(void *ptr, uint32 ix) \ +{ \ + uint32 *addr = (uint32 *)ptr; \ + uint32 *a = addr + (ix >> RSH); \ + uint32 pos = (ix & OFF) << LSH; \ + return ((*a >> pos) & MSK); \ +} + +DECLARE_MAP_API(2, 4, 1, 15U, 0x0003) /* setbit2() and getbit2() */ +DECLARE_MAP_API(4, 3, 2, 7U, 0x000F) /* setbit4() and getbit4() */ + + +/* 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 MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 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)) + +/* modulo add/sub - assumes x, y E [0, bound - 1] */ +#define MODADD(x, y, bound) \ + MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) +#define MODSUB(x, y, bound) \ + MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) + +/* module 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)) + +/* crc defines */ +#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */ +#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */ +#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */ +#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */ +#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */ +#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */ + +/* use for direct output of MAC address in printf etc */ +#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" +#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ + ((struct ether_addr *) (ea))->octet[1], \ + ((struct ether_addr *) (ea))->octet[2], \ + ((struct ether_addr *) (ea))->octet[3], \ + ((struct ether_addr *) (ea))->octet[4], \ + ((struct ether_addr *) (ea))->octet[5] + +#define ETHER_TO_MACF(ea) (ea).octet[0], \ + (ea).octet[1], \ + (ea).octet[2], \ + (ea).octet[3], \ + (ea).octet[4], \ + (ea).octet[5] +#if !defined(SIMPLE_MAC_PRINT) +#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC2STR(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] +#else +#define MACDBG "%02x:%02x:%02x" +#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] +#define MACSTR "%02x:%02x:%02x" +#define MAC2STR(ea) (ea)[0], (ea)[4], (ea)[5] +#endif /* SIMPLE_MAC_PRINT */ + +/* bcm_format_flags() bit description structure */ +typedef struct bcm_bit_desc { + uint32 bit; + const char* name; +} bcm_bit_desc_t; + +/* bcm_format_field */ +typedef struct bcm_bit_desc_ex { + uint32 mask; + const bcm_bit_desc_t *bitfield; +} bcm_bit_desc_ex_t; + +/* buffer length for ethernet address from bcm_ether_ntoa() */ +#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */ + +/* crypto utility function */ +/* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */ +static INLINE void +xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) +{ + if ( +#ifdef __i386__ + 1 || +#endif + (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { + /* ARM CM3 rel time: 1229 (727 if alignment check could be omitted) */ + /* x86 supports unaligned. This version runs 6x-9x faster on x86. */ + ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; + ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; + ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; + ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; + } else { + /* ARM CM3 rel time: 4668 (4191 if alignment check could be omitted) */ + int k; + for (k = 0; k < 16; k++) + dst[k] = src1[k] ^ src2[k]; + } +} + +/* externs */ +/* crc */ +extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); +extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); +extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); + +/* format/print */ +#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ + defined(WLMSG_ASSOC) +/* print out the value a field has: fields may have 1-32 bits and may hold any value */ +extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len); +/* print out which bits in flags are set */ +extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); +#endif + +extern int bcm_format_hex(char *str, const void *bytes, int len); + +extern const char *bcm_crypto_algo_name(uint algo); +extern char *bcm_chipname(uint chipid, char *buf, uint len); +extern char *bcm_brev_str(uint32 brev, char *buf); +extern void printbig(char *buf); +extern void prhex(const char *msg, uchar *buf, uint len); + +/* IE parsing */ + +/* tag_ID/length/value_buffer tuple */ +typedef struct bcm_tlv { + uint8 id; + uint8 len; + uint8 data[1]; +} bcm_tlv_t; + +/* bcm tlv w/ 16 bit id/len */ +typedef struct bcm_xtlv { + uint16 id; + uint16 len; + uint8 data[1]; +} bcm_xtlv_t; + +/* descriptor of xtlv data src or dst */ +typedef struct { + uint16 type; + uint16 len; + void *ptr; /* ptr to memory location */ +} xtlv_desc_t; + +/* xtlv options */ +#define BCM_XTLV_OPTION_NONE 0x0000 +#define BCM_XTLV_OPTION_ALIGN32 0x0001 + +typedef uint16 bcm_xtlv_opts_t; +struct bcm_xtlvbuf { + bcm_xtlv_opts_t opts; + uint16 size; + uint8 *head; /* point to head of buffer */ + uint8 *buf; /* current position of buffer */ + /* allocated buffer may follow, but not necessarily */ +}; +typedef struct bcm_xtlvbuf bcm_xtlvbuf_t; + +#define BCM_TLV_MAX_DATA_SIZE (255) +#define BCM_XTLV_MAX_DATA_SIZE (65535) +#define BCM_TLV_HDR_SIZE (OFFSETOF(bcm_tlv_t, data)) + +#define BCM_XTLV_HDR_SIZE (OFFSETOF(bcm_xtlv_t, data)) +/* LEN only stores the value's length without padding */ +#define BCM_XTLV_LEN(elt) ltoh16_ua(&(elt->len)) +#define BCM_XTLV_ID(elt) ltoh16_ua(&(elt->id)) +/* entire size of the XTLV including header, data, and optional padding */ +#define BCM_XTLV_SIZE(elt, opts) bcm_xtlv_size(elt, opts) +#define bcm_valid_xtlv(elt, buflen, opts) (elt && ((int)(buflen) >= (int)BCM_XTLV_SIZE(elt, opts))) + +/* Check that bcm_tlv_t fits into the given buflen */ +#define bcm_valid_tlv(elt, buflen) (\ + ((int)(buflen) >= (int)BCM_TLV_HDR_SIZE) && \ + ((int)(buflen) >= (int)(BCM_TLV_HDR_SIZE + (elt)->len))) + +extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); +extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); +extern bcm_tlv_t *bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen); + +extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); + +extern bcm_tlv_t *bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, + int type_len); + +extern uint8 *bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst); +extern uint8 *bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, + int dst_maxlen); + +extern uint8 *bcm_copy_tlv(const void *src, uint8 *dst); +extern uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen); + +/* xtlv */ + +/* return the next xtlv element, and update buffer len (remaining). Buffer length + * updated includes padding as specified by options + */ +extern bcm_xtlv_t *bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts); + +/* initialize an xtlv buffer. Use options specified for packing/unpacking using + * the buffer. Caller is responsible for allocating both buffers. + */ +extern int bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, + bcm_xtlv_opts_t opts); + +extern uint16 bcm_xtlv_buf_len(struct bcm_xtlvbuf *tbuf); +extern uint16 bcm_xtlv_buf_rlen(struct bcm_xtlvbuf *tbuf); +extern uint8 *bcm_xtlv_buf(struct bcm_xtlvbuf *tbuf); +extern uint8 *bcm_xtlv_head(struct bcm_xtlvbuf *tbuf); +extern int bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const void *data, uint16 dlen); +extern int bcm_xtlv_put_8(bcm_xtlvbuf_t *tbuf, uint16 type, const int8 data); +extern int bcm_xtlv_put_16(bcm_xtlvbuf_t *tbuf, uint16 type, const int16 data); +extern int bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data); +extern int bcm_unpack_xtlv_entry(uint8 **buf, uint16 xpct_type, uint16 xpct_len, + void *dst, bcm_xtlv_opts_t opts); +extern int bcm_pack_xtlv_entry(uint8 **buf, uint16 *buflen, uint16 type, uint16 len, + void *src, bcm_xtlv_opts_t opts); +extern int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts); + +/* callback for unpacking xtlv from a buffer into context. */ +typedef int (bcm_xtlv_unpack_cbfn_t)(void *ctx, uint8 *buf, uint16 type, uint16 len); + +/* unpack a tlv buffer using buffer, options, and callback */ +extern int bcm_unpack_xtlv_buf(void *ctx, uint8 *buf, uint16 buflen, + bcm_xtlv_opts_t opts, bcm_xtlv_unpack_cbfn_t *cbfn); + +/* unpack a set of tlvs from the buffer using provided xtlv desc */ +extern int bcm_unpack_xtlv_buf_to_mem(void *buf, int *buflen, xtlv_desc_t *items, + bcm_xtlv_opts_t opts); + +/* pack a set of tlvs into buffer using provided xtlv desc */ +extern int bcm_pack_xtlv_buf_from_mem(void **buf, uint16 *buflen, xtlv_desc_t *items, + bcm_xtlv_opts_t opts); + +/* callback to return next tlv id and len to pack, if there is more tlvs to come and + * options e.g. alignment + */ +typedef bool (*bcm_pack_xtlv_next_info_cbfn_t)(void *ctx, uint16 *tlv_id, uint16 *tlv_len); + +/* callback to pack the tlv into length validated buffer */ +typedef void (*bcm_pack_xtlv_pack_next_cbfn_t)(void *ctx, + uint16 tlv_id, uint16 tlv_len, uint8* buf); + +/* pack a set of tlvs into buffer using get_next to interate */ +int bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, + bcm_xtlv_opts_t opts, bcm_pack_xtlv_next_info_cbfn_t get_next, + bcm_pack_xtlv_pack_next_cbfn_t pack_next, int *outlen); + +/* bcmerror */ +extern const char *bcmerrorstr(int bcmerror); + +/* multi-bool data type: set of bools, mbool is true if any is set */ +typedef uint32 mbool; +#define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */ +#define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */ +#define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */ +#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) + +/* generic datastruct to help dump routines */ +struct fielddesc { + const char *nameandfmt; + uint32 offset; + uint32 len; +}; + +extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); +extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); + +extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); +extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); +extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); + +typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); +extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, + char *buf, uint32 bufsize); +extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); + +extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); + +/* power conversion */ +extern uint16 bcm_qdbm_to_mw(uint8 qdbm); +extern uint8 bcm_mw_to_qdbm(uint16 mw); +extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); + +unsigned int process_nvram_vars(char *varbuf, unsigned int len); + +/* calculate a * b + c */ +extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c); +/* calculate a / b */ +extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b); + + +/* Public domain bit twiddling hacks/utilities: Sean Eron Anderson */ + +/* Table driven count set bits. */ +static const uint8 /* Table only for use by bcm_cntsetbits */ +_CSBTBL[256] = +{ +# define B2(n) n, n + 1, n + 1, n + 2 +# define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2) +# define B6(n) B4(n), B4(n + 1), B4(n + 1), B4(n + 2) + B6(0), B6(0 + 1), B6(0 + 1), B6(0 + 2) +}; + +static INLINE uint32 /* Uses table _CSBTBL for fast counting of 1's in a u32 */ +bcm_cntsetbits(const uint32 u32) +{ + /* function local scope declaration of const _CSBTBL[] */ + const uint8 * p = (const uint8 *)&u32; + return (_CSBTBL[p[0]] + _CSBTBL[p[1]] + _CSBTBL[p[2]] + _CSBTBL[p[3]]); +} + + +static INLINE int /* C equivalent count of leading 0's in a u32 */ +C_bcm_count_leading_zeros(uint32 u32) +{ + int shifts = 0; + while (u32) { + shifts++; u32 >>= 1; + } + return (32U - shifts); +} + +#ifdef BCMDRIVER +/* + * Assembly instructions: Count Leading Zeros + * "clz" : MIPS, ARM + * "cntlzw" : PowerPC + * "BSF" : x86 + * "lzcnt" : AMD, SPARC + */ + +#if defined(__arm__) + +#if defined(__ARM_ARCH_7M__) /* Cortex M3 */ +#define __USE_ASM_CLZ__ +#endif /* __ARM_ARCH_7M__ */ + +#if defined(__ARM_ARCH_7R__) /* Cortex R4 */ +#define __USE_ASM_CLZ__ +#endif /* __ARM_ARCH_7R__ */ + +#endif /* __arm__ */ + +static INLINE int +bcm_count_leading_zeros(uint32 u32) +{ +#if defined(__USE_ASM_CLZ__) + int zeros; + __asm__ volatile("clz %0, %1 \n" : "=r" (zeros) : "r" (u32)); + return zeros; +#else /* C equivalent */ + return C_bcm_count_leading_zeros(u32); +#endif /* C equivalent */ +} + +/* INTERFACE: Multiword bitmap based small id allocator. */ +struct bcm_mwbmap; /* forward declaration for use as an opaque mwbmap handle */ + +#define BCM_MWBMAP_INVALID_HDL ((struct bcm_mwbmap *)NULL) +#define BCM_MWBMAP_INVALID_IDX ((uint32)(~0U)) + +/* Incarnate a multiword bitmap based small index allocator */ +extern struct bcm_mwbmap * bcm_mwbmap_init(osl_t * osh, uint32 items_max); + +/* Free up the multiword bitmap index allocator */ +extern void bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl); + +/* Allocate a unique small index using a multiword bitmap index allocator */ +extern uint32 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl); + +/* Force an index at a specified position to be in use */ +extern void bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); + +/* Free a previously allocated index back into the multiword bitmap allocator */ +extern void bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); + +/* Fetch the toal number of free indices in the multiword bitmap allocator */ +extern uint32 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl); + +/* Determine whether an index is inuse or free */ +extern bool bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); + +/* Debug dump a multiword bitmap allocator */ +extern void bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl); + +extern void bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl); +/* End - Multiword bitmap based small Id allocator. */ +#endif /* BCMDRIVER */ + +extern void bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b); + +void bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset); +void bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset); + +#ifdef __cplusplus + } +#endif + +#ifdef DEBUG_COUNTER +#define CNTR_TBL_MAX 10 +typedef struct _counter_tbl_t { + char name[16]; /* name of this counter table */ + uint32 prev_log_print; /* Internal use. Timestamp of the previous log print */ + uint log_print_interval; /* Desired interval to print logs in ms */ + uint needed_cnt; /* How many counters need to be used */ + uint32 cnt[CNTR_TBL_MAX]; /* Counting entries to increase at desired places */ + bool enabled; /* Whether to enable printing log */ +} counter_tbl_t; + + +void counter_printlog(counter_tbl_t *ctr_tbl); +#endif /* DEBUG_COUNTER */ + +#endif /* _bcmutils_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h new file mode 100644 index 000000000000..edb22d53ea84 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h @@ -0,0 +1,64 @@ +/* + * Definitions for nl80211 testmode access to host driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: brcm_nl80211.h 596861 2015-11-03 08:54:58Z $ + * + */ + +#ifndef _brcm_nl80211_h_ +#define _brcm_nl80211_h_ + +#define OUI_BRCM 0x001018 + +enum wl_vendor_subcmd { + BRCM_VENDOR_SCMD_UNSPEC, + BRCM_VENDOR_SCMD_PRIV_STR, + BRCM_VENDOR_SCMD_BCM_STR +}; + +struct bcm_nlmsg_hdr { + uint cmd; /* common ioctl definition */ + uint len; /* attached buffer length */ + uint offset; /* user buffer offset */ + uint set; /* get or set request optional */ + uint magic; /* magic number for verification */ +}; + +enum bcmnl_attrs { + BCM_NLATTR_UNSPEC, + + BCM_NLATTR_LEN, + BCM_NLATTR_DATA, + + __BCM_NLATTR_AFTER_LAST, + BCM_NLATTR_MAX = __BCM_NLATTR_AFTER_LAST - 1 +}; + +struct nl_prv_data { + int err; /* return result */ + void *data; /* ioctl return buffer pointer */ + uint len; /* ioctl return buffer length */ + struct bcm_nlmsg_hdr *nlioc; /* bcm_nlmsg_hdr header pointer */ +}; + +#endif /* _brcm_nl80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h b/drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h new file mode 100644 index 000000000000..fe898da34ac9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h @@ -0,0 +1,582 @@ +/* + * Dongle BUS interface Abstraction layer + * target serial buses like USB, SDIO, SPI, etc. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dbus.h 423346 2013-09-11 22:38:40Z $ + */ + +#ifndef __DBUS_H__ +#define __DBUS_H__ + +#include "typedefs.h" + +#define DBUSTRACE(args) +#define DBUSERR(args) +#define DBUSINFO(args) +#define DBUSDBGLOCK(args) + +enum { + DBUS_OK = 0, + DBUS_ERR = -200, + DBUS_ERR_TIMEOUT, + DBUS_ERR_DISCONNECT, + DBUS_ERR_NODEVICE, + DBUS_ERR_UNSUPPORTED, + DBUS_ERR_PENDING, + DBUS_ERR_NOMEM, + DBUS_ERR_TXFAIL, + DBUS_ERR_TXTIMEOUT, + DBUS_ERR_TXDROP, + DBUS_ERR_RXFAIL, + DBUS_ERR_RXDROP, + DBUS_ERR_TXCTLFAIL, + DBUS_ERR_RXCTLFAIL, + DBUS_ERR_REG_PARAM, + DBUS_STATUS_CANCELLED, + DBUS_ERR_NVRAM, + DBUS_JUMBO_NOMATCH, + DBUS_JUMBO_BAD_FORMAT, + DBUS_NVRAM_NONTXT +}; + +#define BCM_OTP_SIZE_43236 84 /* number of 16 bit values */ +#define BCM_OTP_SW_RGN_43236 24 /* start offset of SW config region */ +#define BCM_OTP_ADDR_43236 0x18000800 /* address of otp base */ + +#define ERR_CBMASK_TXFAIL 0x00000001 +#define ERR_CBMASK_RXFAIL 0x00000002 +#define ERR_CBMASK_ALL 0xFFFFFFFF + +#define DBUS_CBCTL_WRITE 0 +#define DBUS_CBCTL_READ 1 +#if defined(INTR_EP_ENABLE) +#define DBUS_CBINTR_POLL 2 +#endif /* defined(INTR_EP_ENABLE) */ + +#define DBUS_TX_RETRY_LIMIT 3 /* retries for failed txirb */ +#define DBUS_TX_TIMEOUT_INTERVAL 250 /* timeout for txirb complete, in ms */ + +#define DBUS_BUFFER_SIZE_TX 32000 +#define DBUS_BUFFER_SIZE_RX 24000 + +#define DBUS_BUFFER_SIZE_TX_NOAGG 2048 +#define DBUS_BUFFER_SIZE_RX_NOAGG 2048 + +/* DBUS types */ +enum { + DBUS_USB, + DBUS_SDIO, + DBUS_SPI, + DBUS_UNKNOWN +}; + +enum dbus_state { + DBUS_STATE_DL_PENDING, + DBUS_STATE_DL_DONE, + DBUS_STATE_UP, + DBUS_STATE_DOWN, + DBUS_STATE_PNP_FWDL, + DBUS_STATE_DISCONNECT, + DBUS_STATE_SLEEP +}; + +enum dbus_pnp_state { + DBUS_PNP_DISCONNECT, + DBUS_PNP_SLEEP, + DBUS_PNP_RESUME +}; + +enum dbus_file { + DBUS_FIRMWARE, + DBUS_NVFILE +}; + +typedef enum _DEVICE_SPEED { + INVALID_SPEED = -1, + LOW_SPEED = 1, /* USB 1.1: 1.5 Mbps */ + FULL_SPEED, /* USB 1.1: 12 Mbps */ + HIGH_SPEED, /* USB 2.0: 480 Mbps */ + SUPER_SPEED, /* USB 3.0: 4.8 Gbps */ +} DEVICE_SPEED; + +typedef struct { + int bustype; + int vid; + int pid; + int devid; + int chiprev; /* chip revsion number */ + int mtu; + int nchan; /* Data Channels */ + int has_2nd_bulk_in_ep; +} dbus_attrib_t; + +/* FIX: Account for errors related to DBUS; + * Let upper layer account for packets/bytes + */ +typedef struct { + uint32 rx_errors; + uint32 tx_errors; + uint32 rx_dropped; + uint32 tx_dropped; +} dbus_stats_t; + +/* + * Configurable BUS parameters + */ +enum { + DBUS_CONFIG_ID_RXCTL_DEFERRES = 1, + DBUS_CONFIG_ID_TXRXQUEUE +}; +typedef struct { + uint32 config_id; + union { + bool rxctl_deferrespok; + struct { + int maxrxq; + int rxbufsize; + int maxtxq; + int txbufsize; + } txrxqueue; + }; +} dbus_config_t; + +/* + * External Download Info + */ +typedef struct dbus_extdl { + uint8 *fw; + int fwlen; + uint8 *vars; + int varslen; +} dbus_extdl_t; + +struct dbus_callbacks; +struct exec_parms; + +typedef void *(*probe_cb_t)(void *arg, const char *desc, uint32 bustype, uint32 hdrlen); +typedef void (*disconnect_cb_t)(void *arg); +typedef void *(*exec_cb_t)(struct exec_parms *args); + +/* Client callbacks registered during dbus_attach() */ +typedef struct dbus_callbacks { + void (*send_complete)(void *cbarg, void *info, int status); + void (*recv_buf)(void *cbarg, uint8 *buf, int len); + void (*recv_pkt)(void *cbarg, void *pkt); + void (*txflowcontrol)(void *cbarg, bool onoff); + void (*errhandler)(void *cbarg, int err); + void (*ctl_complete)(void *cbarg, int type, int status); + void (*state_change)(void *cbarg, int state); + void *(*pktget)(void *cbarg, uint len, bool send); + void (*pktfree)(void *cbarg, void *p, bool send); +} dbus_callbacks_t; + +struct dbus_pub; +struct bcmstrbuf; +struct dbus_irb; +struct dbus_irb_rx; +struct dbus_irb_tx; +struct dbus_intf_callbacks; + +typedef struct { + void* (*attach)(struct dbus_pub *pub, void *cbarg, struct dbus_intf_callbacks *cbs); + void (*detach)(struct dbus_pub *pub, void *bus); + + int (*up)(void *bus); + int (*down)(void *bus); + int (*send_irb)(void *bus, struct dbus_irb_tx *txirb); + int (*recv_irb)(void *bus, struct dbus_irb_rx *rxirb); + int (*cancel_irb)(void *bus, struct dbus_irb_tx *txirb); + int (*send_ctl)(void *bus, uint8 *buf, int len); + int (*recv_ctl)(void *bus, uint8 *buf, int len); + int (*get_stats)(void *bus, dbus_stats_t *stats); + int (*get_attrib)(void *bus, dbus_attrib_t *attrib); + + int (*pnp)(void *bus, int evnt); + int (*remove)(void *bus); + int (*resume)(void *bus); + int (*suspend)(void *bus); + int (*stop)(void *bus); + int (*reset)(void *bus); + + /* Access to bus buffers directly */ + void *(*pktget)(void *bus, int len); + void (*pktfree)(void *bus, void *pkt); + + int (*iovar_op)(void *bus, const char *name, void *params, int plen, void *arg, int len, + bool set); + void (*dump)(void *bus, struct bcmstrbuf *strbuf); + int (*set_config)(void *bus, dbus_config_t *config); + int (*get_config)(void *bus, dbus_config_t *config); + + bool (*device_exists)(void *bus); + bool (*dlneeded)(void *bus); + int (*dlstart)(void *bus, uint8 *fw, int len); + int (*dlrun)(void *bus); + bool (*recv_needed)(void *bus); + + void *(*exec_rxlock)(void *bus, exec_cb_t func, struct exec_parms *args); + void *(*exec_txlock)(void *bus, exec_cb_t func, struct exec_parms *args); + + int (*tx_timer_init)(void *bus); + int (*tx_timer_start)(void *bus, uint timeout); + int (*tx_timer_stop)(void *bus); + + int (*sched_dpc)(void *bus); + int (*lock)(void *bus); + int (*unlock)(void *bus); + int (*sched_probe_cb)(void *bus); + + int (*shutdown)(void *bus); + + int (*recv_stop)(void *bus); + int (*recv_resume)(void *bus); + + int (*recv_irb_from_ep)(void *bus, struct dbus_irb_rx *rxirb, uint ep_idx); + + int (*readreg)(void *bus, uint32 regaddr, int datalen, uint32 *value); + + /* Add from the bottom */ +} dbus_intf_t; + +typedef struct dbus_pub { + struct osl_info *osh; + dbus_stats_t stats; + dbus_attrib_t attrib; + enum dbus_state busstate; + DEVICE_SPEED device_speed; + int ntxq, nrxq, rxsize; + void *bus; + struct shared_info *sh; + void *dev_info; +} dbus_pub_t; + +#define BUS_INFO(bus, type) (((type *) bus)->pub->bus) + +#define ALIGNED_LOCAL_VARIABLE(var, align) \ + uint8 buffer[SDALIGN+64]; \ + uint8 *var = (uint8 *)(((uintptr)&buffer[0]) & ~(align-1)) + align; + +/* + * Public Bus Function Interface + */ + +/* + * FIX: Is there better way to pass OS/Host handles to DBUS but still + * maintain common interface for all OS?? + * Under NDIS, param1 needs to be MiniportHandle + * For NDIS60, param2 is WdfDevice + * Under Linux, param1 and param2 are NULL; + */ +extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, + void *param1, void *param2); +extern int dbus_deregister(void); + +extern dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq, int ntxq, + void *cbarg, dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh); +extern void dbus_detach(dbus_pub_t *pub); + +extern int dbus_up(dbus_pub_t *pub); +extern int dbus_down(dbus_pub_t *pub); +extern int dbus_stop(dbus_pub_t *pub); +extern int dbus_shutdown(dbus_pub_t *pub); +extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on); + +extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); +extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info); +extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); +extern int dbus_send_ctl(dbus_pub_t *pub, uint8 *buf, int len); +extern int dbus_recv_ctl(dbus_pub_t *pub, uint8 *buf, int len); +extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); +extern int dbus_poll_intr(dbus_pub_t *pub); +extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats); +extern int dbus_get_attrib(dbus_pub_t *pub, dbus_attrib_t *attrib); +extern int dbus_get_device_speed(dbus_pub_t *pub); +extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config); +extern int dbus_get_config(dbus_pub_t *pub, dbus_config_t *config); +extern void * dbus_get_devinfo(dbus_pub_t *pub); + +extern void *dbus_pktget(dbus_pub_t *pub, int len); +extern void dbus_pktfree(dbus_pub_t *pub, void* pkt); + +extern int dbus_set_errmask(dbus_pub_t *pub, uint32 mask); +extern int dbus_pnp_sleep(dbus_pub_t *pub); +extern int dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload); +extern int dbus_pnp_disconnect(dbus_pub_t *pub); + +extern int dbus_iovar_op(dbus_pub_t *pub, const char *name, + void *params, int plen, void *arg, int len, bool set); + +extern void *dhd_dbus_txq(const dbus_pub_t *pub); +extern uint dhd_dbus_hdrlen(const dbus_pub_t *pub); + +/* + * Private Common Bus Interface + */ + +/* IO Request Block (IRB) */ +typedef struct dbus_irb { + struct dbus_irb *next; /* it's casted from dbus_irb_tx or dbus_irb_rx struct */ +} dbus_irb_t; + +typedef struct dbus_irb_rx { + struct dbus_irb irb; /* Must be first */ + uint8 *buf; + int buf_len; + int actual_len; + void *pkt; + void *info; + void *arg; +} dbus_irb_rx_t; + +typedef struct dbus_irb_tx { + struct dbus_irb irb; /* Must be first */ + uint8 *buf; + int len; + void *pkt; + int retry_count; + void *info; + void *arg; + void *send_buf; /* linear bufffer for LINUX when aggreagtion is enabled */ +} dbus_irb_tx_t; + +/* DBUS interface callbacks are different from user callbacks + * so, internally, different info can be passed to upper layer + */ +typedef struct dbus_intf_callbacks { + void (*send_irb_timeout)(void *cbarg, dbus_irb_tx_t *txirb); + void (*send_irb_complete)(void *cbarg, dbus_irb_tx_t *txirb, int status); + void (*recv_irb_complete)(void *cbarg, dbus_irb_rx_t *rxirb, int status); + void (*errhandler)(void *cbarg, int err); + void (*ctl_complete)(void *cbarg, int type, int status); + void (*state_change)(void *cbarg, int state); + bool (*isr)(void *cbarg, bool *wantdpc); + bool (*dpc)(void *cbarg, bool bounded); + void (*watchdog)(void *cbarg); + void *(*pktget)(void *cbarg, uint len, bool send); + void (*pktfree)(void *cbarg, void *p, bool send); + struct dbus_irb* (*getirb)(void *cbarg, bool send); + void (*rxerr_indicate)(void *cbarg, bool on); +} dbus_intf_callbacks_t; + +/* + * Porting: To support new bus, port these functions below + */ + +/* + * Bus specific Interface + * Implemented by dbus_usb.c/dbus_sdio.c + */ +extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, + dbus_intf_t **intf, void *param1, void *param2); +extern int dbus_bus_deregister(void); +extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp); + +/* + * Bus-specific and OS-specific Interface + * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c + */ +extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, + void *prarg, dbus_intf_t **intf, void *param1, void *param2); +extern int dbus_bus_osl_deregister(void); + +/* + * Bus-specific, OS-specific, HW-specific Interface + * Mainly for SDIO Host HW controller + */ +extern int dbus_bus_osl_hw_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, + void *prarg, dbus_intf_t **intf); +extern int dbus_bus_osl_hw_deregister(void); + +extern uint usbdev_bulkin_eps(void); +#if defined(BCM_REQUEST_FW) +extern void *dbus_get_fw_nvfile(int devid, uint8 **fw, int *fwlen, int type, + uint16 boardtype, uint16 boardrev); +extern void dbus_release_fw_nvfile(void *firmware); +#endif /* #if defined(BCM_REQUEST_FW) */ + + +#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) + /* Backward compatibility */ + typedef unsigned int gfp_t; + + #define dma_pool pci_pool + #define dma_pool_create(name, dev, size, align, alloc) \ + pci_pool_create(name, dev, size, align, alloc, GFP_DMA | GFP_ATOMIC) + #define dma_pool_destroy(pool) pci_pool_destroy(pool) + #define dma_pool_alloc(pool, flags, handle) pci_pool_alloc(pool, flags, handle) + #define dma_pool_free(pool, vaddr, addr) pci_pool_free(pool, vaddr, addr) + + #define dma_map_single(dev, addr, size, dir) pci_map_single(dev, addr, size, dir) + #define dma_unmap_single(dev, hnd, size, dir) pci_unmap_single(dev, hnd, size, dir) + #define DMA_FROM_DEVICE PCI_DMA_FROMDEVICE + #define DMA_TO_DEVICE PCI_DMA_TODEVICE +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ + +/* Availability of these functions varies (when present, they have two arguments) */ +#ifndef hc32_to_cpu + #define hc32_to_cpu(x) le32_to_cpu(x) + #define cpu_to_hc32(x) cpu_to_le32(x) + typedef unsigned int __hc32; +#else + #error Two-argument functions needed +#endif + +/* Private USB opcode base */ +#define EHCI_FASTPATH 0x31 +#define EHCI_SET_EP_BYPASS EHCI_FASTPATH +#define EHCI_SET_BYPASS_CB (EHCI_FASTPATH + 1) +#define EHCI_SET_BYPASS_DEV (EHCI_FASTPATH + 2) +#define EHCI_DUMP_STATE (EHCI_FASTPATH + 3) +#define EHCI_SET_BYPASS_POOL (EHCI_FASTPATH + 4) +#define EHCI_CLR_EP_BYPASS (EHCI_FASTPATH + 5) + +/* + * EHCI QTD structure (hardware and extension) + * NOTE that is does not need to (and does not) match its kernel counterpart + */ +#define EHCI_QTD_NBUFFERS 5 +#define EHCI_QTD_ALIGN 32 +#define EHCI_BULK_PACKET_SIZE 512 +#define EHCI_QTD_XACTERR_MAX 32 + +struct ehci_qtd { + /* Hardware map */ + volatile uint32_t qtd_next; + volatile uint32_t qtd_altnext; + volatile uint32_t qtd_status; +#define EHCI_QTD_GET_BYTES(x) (((x)>>16) & 0x7fff) +#define EHCI_QTD_IOC 0x00008000 +#define EHCI_QTD_GET_CERR(x) (((x)>>10) & 0x3) +#define EHCI_QTD_SET_CERR(x) ((x) << 10) +#define EHCI_QTD_GET_PID(x) (((x)>>8) & 0x3) +#define EHCI_QTD_SET_PID(x) ((x) << 8) +#define EHCI_QTD_ACTIVE 0x80 +#define EHCI_QTD_HALTED 0x40 +#define EHCI_QTD_BUFERR 0x20 +#define EHCI_QTD_BABBLE 0x10 +#define EHCI_QTD_XACTERR 0x08 +#define EHCI_QTD_MISSEDMICRO 0x04 + volatile uint32_t qtd_buffer[EHCI_QTD_NBUFFERS]; + volatile uint32_t qtd_buffer_hi[EHCI_QTD_NBUFFERS]; + + /* Implementation extension */ + dma_addr_t qtd_self; /* own hardware address */ + struct ehci_qtd *obj_next; /* software link to the next QTD */ + void *rpc; /* pointer to the rpc buffer */ + size_t length; /* length of the data in the buffer */ + void *buff; /* pointer to the reassembly buffer */ + int xacterrs; /* retry counter for qtd xact error */ +} __attribute__ ((aligned(EHCI_QTD_ALIGN))); + +#define EHCI_NULL __constant_cpu_to_le32(1) /* HW null pointer shall be odd */ + +#define SHORT_READ_Q(token) (EHCI_QTD_GET_BYTES(token) != 0 && EHCI_QTD_GET_PID(token) == 1) + +/* Queue Head */ +/* NOTE This structure is slightly different from the one in the kernel; but needs to stay + * compatible + */ +struct ehci_qh { + /* Hardware map */ + volatile uint32_t qh_link; + volatile uint32_t qh_endp; + volatile uint32_t qh_endphub; + volatile uint32_t qh_curqtd; + + /* QTD overlay */ + volatile uint32_t ow_next; + volatile uint32_t ow_altnext; + volatile uint32_t ow_status; + volatile uint32_t ow_buffer [EHCI_QTD_NBUFFERS]; + volatile uint32_t ow_buffer_hi [EHCI_QTD_NBUFFERS]; + + /* Extension (should match the kernel layout) */ + dma_addr_t unused0; + void *unused1; + struct list_head unused2; + struct ehci_qtd *dummy; + struct ehci_qh *unused3; + + struct ehci_hcd *unused4; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + struct kref unused5; + unsigned unused6; + + uint8_t unused7; + + /* periodic schedule info */ + uint8_t unused8; + uint8_t unused9; + uint8_t unused10; + uint16_t unused11; + uint16_t unused12; + uint16_t unused13; + struct usb_device *unused14; +#else + unsigned unused5; + + u8 unused6; + + /* periodic schedule info */ + u8 unused7; + u8 unused8; + u8 unused9; + unsigned short unused10; + unsigned short unused11; +#define NO_FRAME ((unsigned short)~0) +#ifdef EHCI_QUIRK_FIX + struct usb_device *unused12; +#endif /* EHCI_QUIRK_FIX */ +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ + struct ehci_qtd *first_qtd; + /* Link to the first QTD; this is an optimized equivalent of the qtd_list field */ + /* NOTE that ehci_qh in ehci.h shall reserve this word */ +} __attribute__ ((aligned(EHCI_QTD_ALIGN))); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +/* The corresponding structure in the kernel is used to get the QH */ +struct hcd_dev { /* usb_device.hcpriv points to this */ + struct list_head unused0; + struct list_head unused1; + + /* array of QH pointers */ + void *ep[32]; +}; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ + +int optimize_qtd_fill_with_rpc(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *rpc, + int token, int len); +int optimize_qtd_fill_with_data(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *data, + int token, int len); +int optimize_submit_async(struct ehci_qtd *qtd, int epn); +void inline optimize_ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma); +struct ehci_qtd *optimize_ehci_qtd_alloc(gfp_t flags); +void optimize_ehci_qtd_free(struct ehci_qtd *qtd); +void optimize_submit_rx_request(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd_in, void *buf); +#endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ + +void dbus_flowctrl_tx(void *dbi, bool on); +#endif /* __DBUS_H__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h new file mode 100644 index 000000000000..7d7f8c86e99c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h @@ -0,0 +1,2030 @@ +/* + * Custom OID/ioctl definitions for + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wlioctl_defs.h 403826 2013-05-22 16:40:55Z $ + */ + + +#ifndef wlioctl_defs_h +#define wlioctl_defs_h + + + + + +/* All builds use the new 11ac ratespec/chanspec */ +#undef D11AC_IOTYPES +#define D11AC_IOTYPES + +/* WL_RSPEC defines for rate information */ +#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */ +#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */ +#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */ +#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */ +#define WL_RSPEC_TXEXP_MASK 0x00000300 +#define WL_RSPEC_TXEXP_SHIFT 8 +#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ +#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ +#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ +#define WL_RSPEC_TXBF 0x00200000 /* bit indicates TXBF mode */ +#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ +#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ +#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ +#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */ +#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override both rate & mode */ + +/* WL_RSPEC_ENCODING field defs */ +#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */ +#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */ +#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */ + +/* WL_RSPEC_BW field defs */ +#define WL_RSPEC_BW_UNSPECIFIED 0 +#define WL_RSPEC_BW_20MHZ 0x00010000 +#define WL_RSPEC_BW_40MHZ 0x00020000 +#define WL_RSPEC_BW_80MHZ 0x00030000 +#define WL_RSPEC_BW_160MHZ 0x00040000 + +/* Legacy defines for the nrate iovar */ +#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ +#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ +#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ +#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */ +#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ +#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ +#define OLD_NRATE_SGI 0x00800000 /* sgi mode */ +#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ + +#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */ +#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */ +#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */ +#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */ + +#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ + +#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ +#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ + +#define IBSS_MED 15 /* Mediom in-bss congestion percentage */ +#define IBSS_HI 25 /* Hi in-bss congestion percentage */ +#define OBSS_MED 12 +#define OBSS_HI 25 +#define INTERFER_MED 5 +#define INTERFER_HI 10 + +#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */ +#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */ +#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */ +#define CCA_FLAGS_PREFER_1_6_11 0x10 +#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */ + +#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */ +#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */ +#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */ +#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */ +#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */ + +#define WL_STA_AID(a) ((a) &~ 0xc000) + +/* Flags for sta_info_t indicating properties of STA */ +#define WL_STA_BRCM 0x00000001 /* Running a Broadcom driver */ +#define WL_STA_WME 0x00000002 /* WMM association */ +#define WL_STA_NONERP 0x00000004 /* No ERP */ +#define WL_STA_AUTHE 0x00000008 /* Authenticated */ +#define WL_STA_ASSOC 0x00000010 /* Associated */ +#define WL_STA_AUTHO 0x00000020 /* Authorized */ +#define WL_STA_WDS 0x00000040 /* Wireless Distribution System */ +#define WL_STA_WDS_LINKUP 0x00000080 /* WDS traffic/probes flowing properly */ +#define WL_STA_PS 0x00000100 /* STA is in power save mode from AP's viewpoint */ +#define WL_STA_APSD_BE 0x00000200 /* APSD delv/trigger for AC_BE is default enabled */ +#define WL_STA_APSD_BK 0x00000400 /* APSD delv/trigger for AC_BK is default enabled */ +#define WL_STA_APSD_VI 0x00000800 /* APSD delv/trigger for AC_VI is default enabled */ +#define WL_STA_APSD_VO 0x00001000 /* APSD delv/trigger for AC_VO is default enabled */ +#define WL_STA_N_CAP 0x00002000 /* STA 802.11n capable */ +#define WL_STA_SCBSTATS 0x00004000 /* Per STA debug stats */ +#define WL_STA_AMPDU_CAP 0x00008000 /* STA AMPDU capable */ +#define WL_STA_AMSDU_CAP 0x00010000 /* STA AMSDU capable */ +#define WL_STA_MIMO_PS 0x00020000 /* mimo ps mode is enabled */ +#define WL_STA_MIMO_RTS 0x00040000 /* send rts in mimo ps mode */ +#define WL_STA_RIFS_CAP 0x00080000 /* rifs enabled */ +#define WL_STA_VHT_CAP 0x00100000 /* STA VHT(11ac) capable */ +#define WL_STA_WPS 0x00200000 /* WPS state */ + +#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ + +/* STA HT cap fields */ +#define WL_STA_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ +#define WL_STA_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ +#define WL_STA_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ +#define WL_STA_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ +#define WL_STA_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ +#define WL_STA_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ +#define WL_STA_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ +#define WL_STA_CAP_GF 0x0010 /* Greenfield preamble support */ +#define WL_STA_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ +#define WL_STA_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ +#define WL_STA_CAP_TX_STBC 0x0080 /* Tx STBC support */ +#define WL_STA_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ +#define WL_STA_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ +#define WL_STA_CAP_DELAYED_BA 0x0400 /* delayed BA support */ +#define WL_STA_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ +#define WL_STA_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ +#define WL_STA_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ +#define WL_STA_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ +#define WL_STA_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ + +#define WL_STA_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ +#define WL_STA_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ +#define WL_STA_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ +#define WL_STA_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ + +/* scb vht flags */ +#define WL_STA_VHT_LDPCCAP 0x0001 +#define WL_STA_SGI80 0x0002 +#define WL_STA_SGI160 0x0004 +#define WL_STA_VHT_TX_STBCCAP 0x0008 +#define WL_STA_VHT_RX_STBCCAP 0x0010 +#define WL_STA_SU_BEAMFORMER 0x0020 +#define WL_STA_SU_BEAMFORMEE 0x0040 +#define WL_STA_MU_BEAMFORMER 0x0080 +#define WL_STA_MU_BEAMFORMEE 0x0100 +#define WL_STA_VHT_TXOP_PS 0x0200 +#define WL_STA_HTC_VHT_CAP 0x0400 + +/* Values for TX Filter override mode */ +#define WLC_TXFILTER_OVERRIDE_DISABLED 0 +#define WLC_TXFILTER_OVERRIDE_ENABLED 1 + +#define WL_IOCTL_ACTION_GET 0x0 +#define WL_IOCTL_ACTION_SET 0x1 +#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e +#define WL_IOCTL_ACTION_OVL_RSV 0x20 +#define WL_IOCTL_ACTION_OVL 0x40 +#define WL_IOCTL_ACTION_MASK 0x7e +#define WL_IOCTL_ACTION_OVL_SHIFT 1 + +#define WL_BSSTYPE_INFRA 1 +#define WL_BSSTYPE_INDEP 0 +#define WL_BSSTYPE_ANY 2 + +/* Bitmask for scan_type */ +#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ +#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ +#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ +#define WL_SCANFLAGS_OFFCHAN 0x08 /* allow scanning/reporting off-channel APs */ +#define WL_SCANFLAGS_HOTSPOT 0x10 /* automatic ANQP to hotspot APs */ + +/* wl_iscan_results status values */ +#define WL_SCAN_RESULTS_SUCCESS 0 +#define WL_SCAN_RESULTS_PARTIAL 1 +#define WL_SCAN_RESULTS_PENDING 2 +#define WL_SCAN_RESULTS_ABORTED 3 +#define WL_SCAN_RESULTS_NO_MEM 4 + +#define SCANOL_ENABLED (1 << 0) +#define SCANOL_BCAST_SSID (1 << 1) +#define SCANOL_NOTIFY_BCAST_SSID (1 << 2) +#define SCANOL_RESULTS_PER_CYCLE (1 << 3) + +/* scan times in milliseconds */ +#define SCANOL_HOME_TIME 45 /* for home channel processing */ +#define SCANOL_ASSOC_TIME 20 /* dwell on a channel while associated */ +#define SCANOL_UNASSOC_TIME 40 /* dwell on a channel while unassociated */ +#define SCANOL_PASSIVE_TIME 110 /* listen on a channelfor passive scan */ +#define SCANOL_AWAY_LIMIT 100 /* max time to be away from home channel */ +#define SCANOL_IDLE_REST_TIME 40 +#define SCANOL_IDLE_REST_MULTIPLIER 0 +#define SCANOL_ACTIVE_REST_TIME 20 +#define SCANOL_ACTIVE_REST_MULTIPLIER 0 +#define SCANOL_CYCLE_IDLE_REST_TIME 300000 /* Idle Rest Time between Scan Cycle (msec) */ +#define SCANOL_CYCLE_IDLE_REST_MULTIPLIER 0 /* Idle Rest Time Multiplier */ +#define SCANOL_CYCLE_ACTIVE_REST_TIME 200 +#define SCANOL_CYCLE_ACTIVE_REST_MULTIPLIER 0 +#define SCANOL_MAX_REST_TIME 3600000 /* max rest time between scan cycle (msec) */ +#define SCANOL_CYCLE_DEFAULT 0 /* default for Max Scan Cycle, 0 = forever */ +#define SCANOL_CYCLE_MAX 864000 /* Max Scan Cycle */ + /* 10 sec/scan cycle => 100 days */ +#define SCANOL_NPROBES 2 /* for Active scan; send n probes on each channel */ +#define SCANOL_NPROBES_MAX 5 /* for Active scan; send n probes on each channel */ +#define SCANOL_SCAN_START_DLY 10 /* delay start of offload scan (sec) */ +#define SCANOL_SCAN_START_DLY_MAX 240 /* delay start of offload scan (sec) */ +#define SCANOL_MULTIPLIER_MAX 10 /* Max Multiplier */ +#define SCANOL_UNASSOC_TIME_MAX 100 /* max dwell on a channel while unassociated */ +#define SCANOL_PASSIVE_TIME_MAX 500 /* max listen on a channel for passive scan */ +#define SCANOL_SSID_MAX 16 /* max supported preferred SSID */ + +/* masks for channel and ssid count */ +#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff +#define WL_SCAN_PARAMS_NSSID_SHIFT 16 + +#define WL_SCAN_ACTION_START 1 +#define WL_SCAN_ACTION_CONTINUE 2 +#define WL_SCAN_ACTION_ABORT 3 + + +#define ANTENNA_NUM_1 1 /* total number of antennas to be used */ +#define ANTENNA_NUM_2 2 +#define ANTENNA_NUM_3 3 +#define ANTENNA_NUM_4 4 + +#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 */ + +/* interference source detection and identification mode */ +#define ITFR_MODE_DISABLE 0 /* disable feature */ +#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */ +#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */ + +/* bit definitions for flags in interference source report */ +#define ITFR_INTERFERENCED 1 /* interference detected */ +#define ITFR_HOME_CHANNEL 2 /* home channel has interference */ +#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */ + +#define WL_NUM_RPI_BINS 8 +#define WL_RM_TYPE_BASIC 1 +#define WL_RM_TYPE_CCA 2 +#define WL_RM_TYPE_RPI 3 + +#define WL_RM_FLAG_PARALLEL (1<<0) + +#define WL_RM_FLAG_LATE (1<<1) +#define WL_RM_FLAG_INCAPABLE (1<<2) +#define WL_RM_FLAG_REFUSED (1<<3) + +/* flags */ +#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ + +#define WLC_CIS_DEFAULT 0 /* built-in default */ +#define WLC_CIS_SROM 1 /* source is sprom */ +#define WLC_CIS_OTP 2 /* source is otp */ + +/* PCL - Power Control Loop */ +/* current gain setting is replaced by user input */ +#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ +#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ +/* current gain setting is maintained */ +#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ + +#define PLC_CMD_FAILOVER 1 +#define PLC_CMD_MAC_COST 2 +#define PLC_CMD_LINK_COST 3 +#define PLC_CMD_NODE_LIST 4 + +#define NODE_TYPE_UNKNOWN 0 /* Unknown link */ +#define NODE_TYPE_WIFI_ONLY 1 /* Pure Wireless STA node */ +#define NODE_TYPE_PLC_ONLY 2 /* Pure PLC only node */ +#define NODE_TYPE_WIFI_PLC 3 /* WiFi PLC capable node */ + +/* defines used by poweridx iovar - it controls power in a-band */ +/* current gain setting is maintained */ +#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ +#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ +#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ +#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ +/* value >= 0 causes + * - input to be set to that value + * - PCL to be off + */ + +#define BCM_MAC_STATUS_INDICATION (0x40010200L) + +/* Values for TX Filter override mode */ +#define WLC_TXFILTER_OVERRIDE_DISABLED 0 +#define WLC_TXFILTER_OVERRIDE_ENABLED 1 + +/* magic pattern used for mismatch driver and wl */ +#define WL_TXFIFO_SZ_MAGIC 0xa5a5 + +/* check this magic number */ +#define WLC_IOCTL_MAGIC 0x14e46c77 + +/* bss_info_cap_t flags */ +#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */ +#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */ +#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info received on channel (vs offchannel) */ +#define WL_BSS_FLAGS_HS20 0x08 /* hotspot 2.0 capable */ +#define WL_BSS_FLAGS_RSSI_INVALID 0x10 /* BSS contains invalid RSSI */ +#define WL_BSS_FLAGS_RSSI_INACCURATE 0x20 /* BSS contains inaccurate RSSI */ + +/* bssinfo flag for nbss_cap */ +#define VHT_BI_SGI_80MHZ 0x00000100 +#define VHT_BI_80MHZ 0x00000200 +#define VHT_BI_160MHZ 0x00000400 +#define VHT_BI_8080MHZ 0x00000800 + +/* reference to wl_ioctl_t struct used by usermode driver */ +#define ioctl_subtype set /* subtype param */ +#define ioctl_pid used /* pid param */ +#define ioctl_status needed /* status param */ + + +/* 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_OCB_MSDU 5 +#define CRYPTO_ALGO_AES_OCB_MPDU 6 +#if !defined(BCMCCX) && !defined(BCMEXTCCX) +#define CRYPTO_ALGO_NALG 7 +#else +#define CRYPTO_ALGO_CKIP 7 +#define CRYPTO_ALGO_CKIP_MMH 8 +#define CRYPTO_ALGO_WEP_MMH 9 +#define CRYPTO_ALGO_NALG 10 +#endif /* !BCMCCX && !BCMEXTCCX */ + +#define CRYPTO_ALGO_SMS4 11 +#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ +#define CRYPTO_ALGO_BIP 13 /* 802.11w BIP (aes cmac) */ + +#define CRYPTO_ALGO_AES_GCM 14 /* 128 bit GCM */ +#define CRYPTO_ALGO_AES_CCM256 15 /* 256 bit CCM */ +#define CRYPTO_ALGO_AES_GCM256 16 /* 256 bit GCM */ +#define CRYPTO_ALGO_BIP_CMAC256 17 /* 256 bit BIP CMAC */ +#define CRYPTO_ALGO_BIP_GMAC 18 /* 128 bit BIP GMAC */ +#define CRYPTO_ALGO_BIP_GMAC256 19 /* 256 bit BIP GMAC */ + +#define CRYPTO_ALGO_NONE CRYPTO_ALGO_OFF + +#define WSEC_GEN_MIC_ERROR 0x0001 +#define WSEC_GEN_REPLAY 0x0002 +#define WSEC_GEN_ICV_ERROR 0x0004 +#define WSEC_GEN_MFP_ACT_ERROR 0x0008 +#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 +#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 + +#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ +#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ +#if defined(BCMCCX) || defined(BCMEXTCCX) +#define WL_CKIP_KP (1 << 4) /* CMIC */ +#define WL_CKIP_MMH (1 << 5) /* CKIP */ +#else +#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ +#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ +#endif /* BCMCCX || BCMEXTCCX */ +#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ + +/* wireless security bitvec */ +#define WEP_ENABLED 0x0001 +#define TKIP_ENABLED 0x0002 +#define AES_ENABLED 0x0004 +#define WSEC_SWFLAG 0x0008 +#ifdef BCMCCX +#define CKIP_KP_ENABLED 0x0010 +#define CKIP_MIC_ENABLED 0x0020 +#endif /* BCMCCX */ +#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */ +#ifdef BCMWAPI_WPI +#define SMS4_ENABLED 0x0100 +#endif /* BCMWAPI_WPI */ + +/* wsec macros for operating on the above definitions */ +#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) +#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) +#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) + +#ifdef BCMCCX +#define WSEC_CKIP_KP_ENABLED(wsec) ((wsec) & CKIP_KP_ENABLED) +#define WSEC_CKIP_MIC_ENABLED(wsec) ((wsec) & CKIP_MIC_ENABLED) +#define WSEC_CKIP_ENABLED(wsec) ((wsec) & (CKIP_KP_ENABLED|CKIP_MIC_ENABLED)) + +#ifdef BCMWAPI_WPI +#define WSEC_ENABLED(wsec) \ + ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | \ + CKIP_MIC_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define WSEC_ENABLED(wsec) \ + ((wsec) & \ + (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | CKIP_MIC_ENABLED)) +#endif /* BCMWAPI_WPI */ +#else /* defined BCMCCX */ +#ifdef BCMWAPI_WPI +#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) +#endif /* BCMWAPI_WPI */ +#endif /* BCMCCX */ +#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) +#ifdef BCMWAPI_WAI +#define WSEC_SMS4_ENABLED(wsec) ((wsec) & SMS4_ENABLED) +#endif /* BCMWAPI_WAI */ + +#define MFP_CAPABLE 0x0200 +#define MFP_REQUIRED 0x0400 +#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ + +/* 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 */ +#if defined(BCMCCX) || defined(BCMEXTCCX) +#define WPA_AUTH_CCKM 0x0008 /* CCKM */ +#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ +#endif /* BCMCCX || BCMEXTCCX */ +/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ +#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ +#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ +#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */ +#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */ +#if defined(BCMWAPI_WAI) || defined(BCMWAPI_WPI) +#define WPA_AUTH_WAPI 0x0400 +#define WAPI_AUTH_NONE WPA_AUTH_NONE /* none (IBSS) */ +#define WAPI_AUTH_UNSPECIFIED 0x0400 /* over AS */ +#define WAPI_AUTH_PSK 0x0800 /* Pre-shared key */ +#endif /* BCMWAPI_WAI || BCMWAPI_WPI */ +#define WPA2_AUTH_MFP 0x1000 /* MFP (11w) in contrast to CCX */ +#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */ +#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */ +#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ + +/* pmkid */ +#define MAXPMKID 16 + +#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ +#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ +#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ +#if defined(LCNCONF) || defined(LCN40CONF) +#define WLC_SAMPLECOLLECT_MAXLEN 8192 /* Max Sample Collect buffer */ +#else +#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ +#endif +#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192 + +/* common ioctl definitions */ +#define WLC_GET_MAGIC 0 +#define WLC_GET_VERSION 1 +#define WLC_UP 2 +#define WLC_DOWN 3 +#define WLC_GET_LOOP 4 +#define WLC_SET_LOOP 5 +#define WLC_DUMP 6 +#define WLC_GET_MSGLEVEL 7 +#define WLC_SET_MSGLEVEL 8 +#define WLC_GET_PROMISC 9 +#define WLC_SET_PROMISC 10 +/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */ +#define WLC_GET_RATE 12 +#define WLC_GET_MAX_RATE 13 +#define WLC_GET_INSTANCE 14 +/* #define WLC_GET_FRAG 15 */ /* no longer supported */ +/* #define WLC_SET_FRAG 16 */ /* no longer supported */ +/* #define WLC_GET_RTS 17 */ /* no longer supported */ +/* #define WLC_SET_RTS 18 */ /* no longer supported */ +#define WLC_GET_INFRA 19 +#define WLC_SET_INFRA 20 +#define WLC_GET_AUTH 21 +#define WLC_SET_AUTH 22 +#define WLC_GET_BSSID 23 +#define WLC_SET_BSSID 24 +#define WLC_GET_SSID 25 +#define WLC_SET_SSID 26 +#define WLC_RESTART 27 +#define WLC_TERMINATED 28 +/* #define WLC_DUMP_SCB 28 */ /* no longer supported */ +#define WLC_GET_CHANNEL 29 +#define WLC_SET_CHANNEL 30 +#define WLC_GET_SRL 31 +#define WLC_SET_SRL 32 +#define WLC_GET_LRL 33 +#define WLC_SET_LRL 34 +#define WLC_GET_PLCPHDR 35 +#define WLC_SET_PLCPHDR 36 +#define WLC_GET_RADIO 37 +#define WLC_SET_RADIO 38 +#define WLC_GET_PHYTYPE 39 +#define WLC_DUMP_RATE 40 +#define WLC_SET_RATE_PARAMS 41 +#define WLC_GET_FIXRATE 42 +#define WLC_SET_FIXRATE 43 +/* #define WLC_GET_WEP 42 */ /* no longer supported */ +/* #define WLC_SET_WEP 43 */ /* no longer supported */ +#define WLC_GET_KEY 44 +#define WLC_SET_KEY 45 +#define WLC_GET_REGULATORY 46 +#define WLC_SET_REGULATORY 47 +#define WLC_GET_PASSIVE_SCAN 48 +#define WLC_SET_PASSIVE_SCAN 49 +#define WLC_SCAN 50 +#define WLC_SCAN_RESULTS 51 +#define WLC_DISASSOC 52 +#define WLC_REASSOC 53 +#define WLC_GET_ROAM_TRIGGER 54 +#define WLC_SET_ROAM_TRIGGER 55 +#define WLC_GET_ROAM_DELTA 56 +#define WLC_SET_ROAM_DELTA 57 +#define WLC_GET_ROAM_SCAN_PERIOD 58 +#define WLC_SET_ROAM_SCAN_PERIOD 59 +#define WLC_EVM 60 /* diag */ +#define WLC_GET_TXANT 61 +#define WLC_SET_TXANT 62 +#define WLC_GET_ANTDIV 63 +#define WLC_SET_ANTDIV 64 +/* #define WLC_GET_TXPWR 65 */ /* no longer supported */ +/* #define WLC_SET_TXPWR 66 */ /* no longer supported */ +#define WLC_GET_CLOSED 67 +#define WLC_SET_CLOSED 68 +#define WLC_GET_MACLIST 69 +#define WLC_SET_MACLIST 70 +#define WLC_GET_RATESET 71 +#define WLC_SET_RATESET 72 +/* #define WLC_GET_LOCALE 73 */ /* no longer supported */ +#define WLC_LONGTRAIN 74 +#define WLC_GET_BCNPRD 75 +#define WLC_SET_BCNPRD 76 +#define WLC_GET_DTIMPRD 77 +#define WLC_SET_DTIMPRD 78 +#define WLC_GET_SROM 79 +#define WLC_SET_SROM 80 +#define WLC_GET_WEP_RESTRICT 81 +#define WLC_SET_WEP_RESTRICT 82 +#define WLC_GET_COUNTRY 83 +#define WLC_SET_COUNTRY 84 +#define WLC_GET_PM 85 +#define WLC_SET_PM 86 +#define WLC_GET_WAKE 87 +#define WLC_SET_WAKE 88 +/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */ +#define WLC_GET_FORCELINK 90 /* ndis only */ +#define WLC_SET_FORCELINK 91 /* ndis only */ +#define WLC_FREQ_ACCURACY 92 /* diag */ +#define WLC_CARRIER_SUPPRESS 93 /* diag */ +#define WLC_GET_PHYREG 94 +#define WLC_SET_PHYREG 95 +#define WLC_GET_RADIOREG 96 +#define WLC_SET_RADIOREG 97 +#define WLC_GET_REVINFO 98 +#define WLC_GET_UCANTDIV 99 +#define WLC_SET_UCANTDIV 100 +#define WLC_R_REG 101 +#define WLC_W_REG 102 +/* #define WLC_DIAG_LOOPBACK 103 old tray diag */ +/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */ +#define WLC_GET_MACMODE 105 +#define WLC_SET_MACMODE 106 +#define WLC_GET_MONITOR 107 +#define WLC_SET_MONITOR 108 +#define WLC_GET_GMODE 109 +#define WLC_SET_GMODE 110 +#define WLC_GET_LEGACY_ERP 111 +#define WLC_SET_LEGACY_ERP 112 +#define WLC_GET_RX_ANT 113 +#define WLC_GET_CURR_RATESET 114 /* current rateset */ +#define WLC_GET_SCANSUPPRESS 115 +#define WLC_SET_SCANSUPPRESS 116 +#define WLC_GET_AP 117 +#define WLC_SET_AP 118 +#define WLC_GET_EAP_RESTRICT 119 +#define WLC_SET_EAP_RESTRICT 120 +#define WLC_SCB_AUTHORIZE 121 +#define WLC_SCB_DEAUTHORIZE 122 +#define WLC_GET_WDSLIST 123 +#define WLC_SET_WDSLIST 124 +#define WLC_GET_ATIM 125 +#define WLC_SET_ATIM 126 +#define WLC_GET_RSSI 127 +#define WLC_GET_PHYANTDIV 128 +#define WLC_SET_PHYANTDIV 129 +#define WLC_AP_RX_ONLY 130 +#define WLC_GET_TX_PATH_PWR 131 +#define WLC_SET_TX_PATH_PWR 132 +#define WLC_GET_WSEC 133 +#define WLC_SET_WSEC 134 +#define WLC_GET_PHY_NOISE 135 +#define WLC_GET_BSS_INFO 136 +#define WLC_GET_PKTCNTS 137 +#define WLC_GET_LAZYWDS 138 +#define WLC_SET_LAZYWDS 139 +#define WLC_GET_BANDLIST 140 + +#define WLC_GET_BAND 141 +#define WLC_SET_BAND 142 +#define WLC_SCB_DEAUTHENTICATE 143 +#define WLC_GET_SHORTSLOT 144 +#define WLC_GET_SHORTSLOT_OVERRIDE 145 +#define WLC_SET_SHORTSLOT_OVERRIDE 146 +#define WLC_GET_SHORTSLOT_RESTRICT 147 +#define WLC_SET_SHORTSLOT_RESTRICT 148 +#define WLC_GET_GMODE_PROTECTION 149 +#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 +#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 +#define WLC_UPGRADE 152 +/* #define WLC_GET_MRATE 153 */ /* no longer supported */ +/* #define WLC_SET_MRATE 154 */ /* no longer supported */ +#define WLC_GET_IGNORE_BCNS 155 +#define WLC_SET_IGNORE_BCNS 156 +#define WLC_GET_SCB_TIMEOUT 157 +#define WLC_SET_SCB_TIMEOUT 158 +#define WLC_GET_ASSOCLIST 159 +#define WLC_GET_CLK 160 +#define WLC_SET_CLK 161 +#define WLC_GET_UP 162 +#define WLC_OUT 163 +#define WLC_GET_WPA_AUTH 164 +#define WLC_SET_WPA_AUTH 165 +#define WLC_GET_UCFLAGS 166 +#define WLC_SET_UCFLAGS 167 +#define WLC_GET_PWRIDX 168 +#define WLC_SET_PWRIDX 169 +#define WLC_GET_TSSI 170 +#define WLC_GET_SUP_RATESET_OVERRIDE 171 +#define WLC_SET_SUP_RATESET_OVERRIDE 172 +/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */ +/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */ +/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */ +/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */ +/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */ +#define WLC_GET_PROTECTION_CONTROL 178 +#define WLC_SET_PROTECTION_CONTROL 179 +#define WLC_GET_PHYLIST 180 +#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */ +#define WLC_DECRYPT_STATUS 182 /* ndis only */ +#define WLC_GET_KEY_SEQ 183 +#define WLC_GET_SCAN_CHANNEL_TIME 184 +#define WLC_SET_SCAN_CHANNEL_TIME 185 +#define WLC_GET_SCAN_UNASSOC_TIME 186 +#define WLC_SET_SCAN_UNASSOC_TIME 187 +#define WLC_GET_SCAN_HOME_TIME 188 +#define WLC_SET_SCAN_HOME_TIME 189 +#define WLC_GET_SCAN_NPROBES 190 +#define WLC_SET_SCAN_NPROBES 191 +#define WLC_GET_PRB_RESP_TIMEOUT 192 +#define WLC_SET_PRB_RESP_TIMEOUT 193 +#define WLC_GET_ATTEN 194 +#define WLC_SET_ATTEN 195 +#define WLC_GET_SHMEM 196 /* diag */ +#define WLC_SET_SHMEM 197 /* diag */ +/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */ +/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */ +#define WLC_SET_WSEC_TEST 200 +#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 +#define WLC_TKIP_COUNTERMEASURES 202 +#define WLC_GET_PIOMODE 203 +#define WLC_SET_PIOMODE 204 +#define WLC_SET_ASSOC_PREFER 205 +#define WLC_GET_ASSOC_PREFER 206 +#define WLC_SET_ROAM_PREFER 207 +#define WLC_GET_ROAM_PREFER 208 +#define WLC_SET_LED 209 +#define WLC_GET_LED 210 +#define WLC_GET_INTERFERENCE_MODE 211 +#define WLC_SET_INTERFERENCE_MODE 212 +#define WLC_GET_CHANNEL_QA 213 +#define WLC_START_CHANNEL_QA 214 +#define WLC_GET_CHANNEL_SEL 215 +#define WLC_START_CHANNEL_SEL 216 +#define WLC_GET_VALID_CHANNELS 217 +#define WLC_GET_FAKEFRAG 218 +#define WLC_SET_FAKEFRAG 219 +#define WLC_GET_PWROUT_PERCENTAGE 220 +#define WLC_SET_PWROUT_PERCENTAGE 221 +#define WLC_SET_BAD_FRAME_PREEMPT 222 +#define WLC_GET_BAD_FRAME_PREEMPT 223 +#define WLC_SET_LEAP_LIST 224 +#define WLC_GET_LEAP_LIST 225 +#define WLC_GET_CWMIN 226 +#define WLC_SET_CWMIN 227 +#define WLC_GET_CWMAX 228 +#define WLC_SET_CWMAX 229 +#define WLC_GET_WET 230 +#define WLC_SET_WET 231 +#define WLC_GET_PUB 232 +/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */ +/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */ +#define WLC_GET_KEY_PRIMARY 235 +#define WLC_SET_KEY_PRIMARY 236 + + +/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */ +#define WLC_GET_ACI_ARGS 238 +#define WLC_SET_ACI_ARGS 239 +#define WLC_UNSET_CALLBACK 240 +#define WLC_SET_CALLBACK 241 +#define WLC_GET_RADAR 242 +#define WLC_SET_RADAR 243 +#define WLC_SET_SPECT_MANAGMENT 244 +#define WLC_GET_SPECT_MANAGMENT 245 +#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ +#define WLC_WDS_GET_WPA_SUP 247 +#define WLC_SET_CS_SCAN_TIMER 248 +#define WLC_GET_CS_SCAN_TIMER 249 +#define WLC_MEASURE_REQUEST 250 +#define WLC_INIT 251 +#define WLC_SEND_QUIET 252 +#define WLC_KEEPALIVE 253 +#define WLC_SEND_PWR_CONSTRAINT 254 +#define WLC_UPGRADE_STATUS 255 +#define WLC_CURRENT_PWR 256 +#define WLC_GET_SCAN_PASSIVE_TIME 257 +#define WLC_SET_SCAN_PASSIVE_TIME 258 +#define WLC_LEGACY_LINK_BEHAVIOR 259 +#define WLC_GET_CHANNELS_IN_COUNTRY 260 +#define WLC_GET_COUNTRY_LIST 261 +#define WLC_GET_VAR 262 /* get value of named variable */ +#define WLC_SET_VAR 263 /* set named variable to value */ +#define WLC_NVRAM_GET 264 /* deprecated */ +#define WLC_NVRAM_SET 265 +#define WLC_NVRAM_DUMP 266 +#define WLC_REBOOT 267 +#define WLC_SET_WSEC_PMK 268 +#define WLC_GET_AUTH_MODE 269 +#define WLC_SET_AUTH_MODE 270 +#define WLC_GET_WAKEENTRY 271 +#define WLC_SET_WAKEENTRY 272 +#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ +#define WLC_NVOTPW 274 +#define WLC_OTPW 275 +#define WLC_IOV_BLOCK_GET 276 +#define WLC_IOV_MODULES_GET 277 +#define WLC_SOFT_RESET 278 +#define WLC_GET_ALLOW_MODE 279 +#define WLC_SET_ALLOW_MODE 280 +#define WLC_GET_DESIRED_BSSID 281 +#define WLC_SET_DESIRED_BSSID 282 +#define WLC_DISASSOC_MYAP 283 +#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */ +#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */ +#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */ +#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */ +#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */ +#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */ +#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */ +#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */ +#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */ +#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */ +#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */ +#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */ +#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */ +#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */ +#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */ +#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */ +#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */ +#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */ +#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */ +#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */ +#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */ +#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */ +#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */ +#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */ +/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */ +#define WLC_GET_CMD 309 +/* #define WLC_LAST 310 */ /* Never used - can be reused */ +#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */ +#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */ +/* #define WLC_GET_WAI_RESTRICT 313 */ /* for WAPI, deprecated use iovar instead */ +/* #define WLC_SET_WAI_RESTRICT 314 */ /* for WAPI, deprecated use iovar instead */ +/* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */ +#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ +#define WLC_GET_NAT_STATE 317 +#define WLC_GET_TXBF_RATESET 318 +#define WLC_SET_TXBF_RATESET 319 +#define WLC_SCAN_CQ 320 +#define WLC_GET_RSSI_QDB 321 /* qdB portion of the RSSI */ + +#define WLC_LAST 322 +#ifndef EPICTRL_COOKIE +#define EPICTRL_COOKIE 0xABADCEDE +#endif + +/* vx wlc ioctl's offset */ +#define CMN_IOCTL_OFF 0x180 + +/* + * custom OID support + * + * 0xFF - implementation specific OID + * 0xE4 - first byte of Broadcom PCI vendor ID + * 0x14 - second byte of Broadcom PCI vendor ID + * 0xXX - the custom OID number + */ + +/* begin 0x1f values beyond the start of the ET driver range. */ +#define WL_OID_BASE 0xFFE41420 + +/* NDIS overrides */ +#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) +#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) +#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) +#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) +#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) +#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) +#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) + +/* EXT_STA Dongle suuport */ +#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) +#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) +#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) +#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) +#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) +#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) +#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) +#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) +#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) +#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) +#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) +#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) +#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) +#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) +#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) + +/* NAT filter driver support */ +#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG) +#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE) + +#define WL_DECRYPT_STATUS_SUCCESS 1 +#define WL_DECRYPT_STATUS_FAILURE 2 +#define WL_DECRYPT_STATUS_UNKNOWN 3 + +/* allows user-mode app to poll the status of USB image upgrade */ +#define WLC_UPGRADE_SUCCESS 0 +#define WLC_UPGRADE_PENDING 1 + +/* WLC_GET_AUTH, WLC_SET_AUTH values */ +#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ +#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ +#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ + +/* a large TX Power as an init value to factor out of MIN() calculations, + * keep low enough to fit in an int8, units are .25 dBm + */ +#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ + +/* "diag" iovar argument and error code */ +#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */ +#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */ +#define WL_DIAG_MEMORY 3 /* d11 memory test */ +#define WL_DIAG_LED 4 /* LED test */ +#define WL_DIAG_REG 5 /* d11/phy register test */ +#define WL_DIAG_SROM 6 /* srom read/crc test */ +#define WL_DIAG_DMA 7 /* DMA test */ +#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */ + +#define WL_DIAGERR_SUCCESS 0 +#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */ +#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */ +#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */ +#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */ +#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */ +#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */ +#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */ +#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */ +#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */ +#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */ + +#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */ +#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */ + +/* band types */ +#define WLC_BAND_AUTO 0 /* auto-select */ +#define WLC_BAND_5G 1 /* 5 Ghz */ +#define WLC_BAND_2G 2 /* 2.4 Ghz */ +#define WLC_BAND_ALL 3 /* all bands */ + +/* band range returned by band_range iovar */ +#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 + +#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4 +#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5 +#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6 +#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7 +#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8 + +#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 +#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 +#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 +#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 + +#define WL_CHAN_FREQ_RANGE_5G_4BAND 5 + +/* MAC list modes */ +#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */ +#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */ +#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */ + +/* + * 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 + +/* values for PLCPHdr_override */ +#define WLC_PLCP_AUTO -1 +#define WLC_PLCP_SHORT 0 +#define WLC_PLCP_LONG 1 + +/* values for g_protection_override and n_protection_override */ +#define WLC_PROTECTION_AUTO -1 +#define WLC_PROTECTION_OFF 0 +#define WLC_PROTECTION_ON 1 +#define WLC_PROTECTION_MMHDR_ONLY 2 +#define WLC_PROTECTION_CTS_ONLY 3 + +/* values for g_protection_control and n_protection_control */ +#define WLC_PROTECTION_CTL_OFF 0 +#define WLC_PROTECTION_CTL_LOCAL 1 +#define WLC_PROTECTION_CTL_OVERLAP 2 + +/* values for n_protection */ +#define WLC_N_PROTECTION_OFF 0 +#define WLC_N_PROTECTION_OPTIONAL 1 +#define WLC_N_PROTECTION_20IN40 2 +#define WLC_N_PROTECTION_MIXEDMODE 3 + +/* values for n_preamble_type */ +#define WLC_N_PREAMBLE_MIXEDMODE 0 +#define WLC_N_PREAMBLE_GF 1 +#define WLC_N_PREAMBLE_GF_BRCM 2 + +/* values for band specific 40MHz capabilities (deprecated) */ +#define WLC_N_BW_20ALL 0 +#define WLC_N_BW_40ALL 1 +#define WLC_N_BW_20IN2G_40IN5G 2 + +#define WLC_BW_20MHZ_BIT (1<<0) +#define WLC_BW_40MHZ_BIT (1<<1) +#define WLC_BW_80MHZ_BIT (1<<2) +#define WLC_BW_160MHZ_BIT (1<<3) + +/* Bandwidth capabilities */ +#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_160MHZ (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ + WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_UNRESTRICTED 0xFF + +#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) +#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) +#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) +#define WL_BW_CAP_160MHZ(bw_cap)(((bw_cap) & WLC_BW_160MHZ_BIT) ? TRUE : FALSE) + +/* values to force tx/rx chain */ +#define WLC_N_TXRX_CHAIN0 0 +#define WLC_N_TXRX_CHAIN1 1 + +/* bitflags for SGI support (sgi_rx iovar) */ +#define WLC_N_SGI_20 0x01 +#define WLC_N_SGI_40 0x02 +#define WLC_VHT_SGI_80 0x04 + +/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ +#define WLC_SGI_ALL 0x02 + +#define LISTEN_INTERVAL 10 +/* interference mitigation options */ +#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ +#define INTERFERE_NONE 0 /* off */ +#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */ +#define WLAN_MANUAL 2 /* ACI: no auto detection */ +#define WLAN_AUTO 3 /* ACI: auto detect */ +#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ +#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ + +/* interfernece mode bit-masks (ACPHY) */ +#define ACPHY_ACI_GLITCHBASED_DESENSE 1 /* bit 0 */ +#define ACPHY_ACI_HWACI_PKTGAINLMT 2 /* bit 1 */ +#define ACPHY_ACI_W2NB_PKTGAINLMT 4 /* bit 2 */ +#define ACPHY_ACI_PREEMPTION 8 /* bit 3 */ +#define ACPHY_ACI_MAX_MODE 15 + +/* AP environment */ +#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ +#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ +#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ +#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ + +#define TRIGGER_NOW 0 +#define TRIGGER_CRS 0x01 +#define TRIGGER_CRSDEASSERT 0x02 +#define TRIGGER_GOODFCS 0x04 +#define TRIGGER_BADFCS 0x08 +#define TRIGGER_BADPLCP 0x10 +#define TRIGGER_CRSGLITCH 0x20 + +#define WL_SAMPLEDATA_HEADER_TYPE 1 +#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ +#define WL_SAMPLEDATA_TYPE 2 +#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ +#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ + +/* WL_OTA START */ +#define WL_OTA_ARG_PARSE_BLK_SIZE 1200 +#define WL_OTA_TEST_MAX_NUM_RATE 30 +#define WL_OTA_TEST_MAX_NUM_SEQ 100 + +#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */ + +/* radar iovar SET defines */ +#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */ +#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */ +#define WL_RADAR_SIMULATED 2 /* force radar detector to declare + * detection once + */ +#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */ +#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 */ + +#ifndef WL_RSSI_ANT_MAX +#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ +#elif WL_RSSI_ANT_MAX != 4 +#error "WL_RSSI_ANT_MAX does not match" +#endif + +/* dfs_status iovar-related defines */ + +/* cac - channel availability check, + * ism - in-service monitoring + * csa - channel switching announcement + */ + +/* cac state values */ +#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */ +#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */ +#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */ +#define WL_DFS_CACSTATE_CSA 3 /* csa */ +#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */ +#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */ +#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */ +#define WL_DFS_CACSTATES 7 /* this many states exist */ + +/* Defines used with channel_bandwidth for curpower */ +#define WL_BW_20MHZ 0 +#define WL_BW_40MHZ 1 +#define WL_BW_80MHZ 2 +#define WL_BW_160MHZ 3 + +/* tx_power_t.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 +#define WL_TX_POWER_F_HT 0x10 +#define WL_TX_POWER_F_VHT 0x20 +#define WL_TX_POWER_F_OPENLOOP 0x40 + +/* Message levels */ +#define WL_ERROR_VAL 0x00000001 +#define WL_TRACE_VAL 0x00000002 +#define WL_PRHDRS_VAL 0x00000004 +#define WL_PRPKT_VAL 0x00000008 +#define WL_INFORM_VAL 0x00000010 +#define WL_TMP_VAL 0x00000020 +#define WL_OID_VAL 0x00000040 +#define WL_RATE_VAL 0x00000080 +#define WL_ASSOC_VAL 0x00000100 +#define WL_PRUSR_VAL 0x00000200 +#define WL_PS_VAL 0x00000400 +#define WL_TXPWR_VAL 0x00000800 /* retired in TOT on 6/10/2009 */ +#define WL_PORT_VAL 0x00001000 +#define WL_DUAL_VAL 0x00002000 +#define WL_WSEC_VAL 0x00004000 +#define WL_WSEC_DUMP_VAL 0x00008000 +#define WL_LOG_VAL 0x00010000 +#define WL_NRSSI_VAL 0x00020000 /* retired in TOT on 6/10/2009 */ +#define WL_LOFT_VAL 0x00040000 /* retired in TOT on 6/10/2009 */ +#define WL_REGULATORY_VAL 0x00080000 +#define WL_PHYCAL_VAL 0x00100000 /* retired in TOT on 6/10/2009 */ +#define WL_RADAR_VAL 0x00200000 /* retired in TOT on 6/10/2009 */ +#define WL_MPC_VAL 0x00400000 +#define WL_APSTA_VAL 0x00800000 +#define WL_DFS_VAL 0x01000000 +#define WL_BA_VAL 0x02000000 /* retired in TOT on 6/14/2010 */ +#define WL_ACI_VAL 0x04000000 +#define WL_MBSS_VAL 0x04000000 +#define WL_CAC_VAL 0x08000000 +#define WL_AMSDU_VAL 0x10000000 +#define WL_AMPDU_VAL 0x20000000 +#define WL_FFPLD_VAL 0x40000000 + +/* wl_msg_level is full. For new bits take the next one and AND with + * wl_msg_level2 in wl_dbg.h + */ +#define WL_DPT_VAL 0x00000001 +#define WL_SCAN_VAL 0x00000002 +#define WL_WOWL_VAL 0x00000004 +#define WL_COEX_VAL 0x00000008 +#define WL_RTDC_VAL 0x00000010 +#define WL_PROTO_VAL 0x00000020 +#define WL_BTA_VAL 0x00000040 +#define WL_CHANINT_VAL 0x00000080 +#define WL_WMF_VAL 0x00000100 +#define WL_P2P_VAL 0x00000200 +#define WL_ITFR_VAL 0x00000400 +#define WL_MCHAN_VAL 0x00000800 +#define WL_TDLS_VAL 0x00001000 +#define WL_MCNX_VAL 0x00002000 +#define WL_PROT_VAL 0x00004000 +#define WL_PSTA_VAL 0x00008000 +#define WL_TSO_VAL 0x00010000 +#define WL_TRF_MGMT_VAL 0x00020000 +#define WL_LPC_VAL 0x00040000 +#define WL_L2FILTER_VAL 0x00080000 +#define WL_TXBF_VAL 0x00100000 +#define WL_P2PO_VAL 0x00200000 +#define WL_TBTT_VAL 0x00400000 +#define WL_NIC_VAL 0x00800000 +#define WL_MQ_VAL 0x01000000 + +/* This level is currently used in Phoenix2 only */ +#define WL_SRSCAN_VAL 0x02000000 + +#define WL_WNM_VAL 0x04000000 +#define WL_PWRSEL_VAL 0x10000000 +#define WL_NET_DETECT_VAL 0x20000000 +#define WL_PCIE_VAL 0x40000000 + +/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier + * rather than a message-type of its own + */ +#define WL_TIMESTAMP_VAL 0x80000000 + +/* max # of leds supported by GPIO (gpio pin# == led index#) */ +#define WL_LED_NUMGPIO 32 /* gpio 0-31 */ + +/* led per-pin behaviors */ +#define WL_LED_OFF 0 /* always off */ +#define WL_LED_ON 1 /* always on */ +#define WL_LED_ACTIVITY 2 /* activity */ +#define WL_LED_RADIO 3 /* radio enabled */ +#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */ +#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */ +#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */ +#define WL_LED_WI1 7 +#define WL_LED_WI2 8 +#define WL_LED_WI3 9 +#define WL_LED_ASSOC 10 /* associated state indicator */ +#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */ +#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */ +#define WL_LED_WI4 13 +#define WL_LED_WI5 14 +#define WL_LED_BLINKSLOW 15 /* blink slow */ +#define WL_LED_BLINKMED 16 /* blink med */ +#define WL_LED_BLINKFAST 17 /* blink fast */ +#define WL_LED_BLINKCUSTOM 18 /* blink custom */ +#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */ +#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ + /* keep on for 300 sec */ +#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ +#define WL_LED_WI6 22 +#define WL_LED_WI7 23 +#define WL_LED_WI8 24 +#define WL_LED_NUMBEHAVIOR 25 + +/* led behavior numeric value format */ +#define WL_LED_BEH_MASK 0x7f /* behavior mask */ +#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */ + +/* number of bytes needed to define a proper bit mask for MAC event reporting */ +#define BCMIO_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#define BCMIO_NBBY 8 +#define WL_EVENTING_MASK_LEN 16 + + +/* join preference types */ +#define WL_JOIN_PREF_RSSI 1 /* by RSSI */ +#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */ +#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */ +#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */ +#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */ + +/* band preference */ +#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */ + +/* any multicast cipher suite */ +#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" + +/* 802.11h measurement types */ +#define WLC_MEASURE_TPC 1 +#define WLC_MEASURE_CHANNEL_BASIC 2 +#define WLC_MEASURE_CHANNEL_CCA 3 +#define WLC_MEASURE_CHANNEL_RPI 4 + +/* regulatory enforcement levels */ +#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */ +#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */ +#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */ +#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */ +/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE + * adoption is done regardless of capability spectrum_management + */ +#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */ + +#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */ +#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */ +#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */ +#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */ +#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */ +#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */ +#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */ + +/* BTC mode used by "btc_mode" iovar */ +#define WL_BTC_DISABLE 0 /* disable BT coexistence */ +#define WL_BTC_FULLTDM 1 /* full TDM COEX */ +#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ +#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ +#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ +#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ +#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ +#define WL_BTC_DEFAULT 8 /* set the default mode for the device */ +#define WL_INF_BTC_DISABLE 0 +#define WL_INF_BTC_ENABLE 1 +#define WL_INF_BTC_AUTO 3 + +/* BTC wire used by "btc_wire" iovar */ +#define WL_BTC_DEFWIRE 0 /* use default wire setting */ +#define WL_BTC_2WIRE 2 /* use 2-wire BTC */ +#define WL_BTC_3WIRE 3 /* use 3-wire BTC */ +#define WL_BTC_4WIRE 4 /* use 4-wire BTC */ + +/* BTC flags: BTC configuration that can be set by host */ +#define WL_BTC_FLAG_PREMPT (1 << 0) +#define WL_BTC_FLAG_BT_DEF (1 << 1) +#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2) +#define WL_BTC_FLAG_SIM_RSP (1 << 3) +#define WL_BTC_FLAG_PS_PROTECT (1 << 4) +#define WL_BTC_FLAG_SIM_TX_LP (1 << 5) +#define WL_BTC_FLAG_ECI (1 << 6) +#define WL_BTC_FLAG_LIGHT (1 << 7) +#define WL_BTC_FLAG_PARALLEL (1 << 8) + +/* maximum channels returned by the get valid channels iovar */ +#define WL_NUMCHANNELS 64 + +/* max number of chanspecs (used by the iovar to calc. buf space) */ +#define WL_NUMCHANSPECS 110 + +/* WDS link local endpoint WPA role */ +#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */ +#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ +#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ + +/* Base offset values */ +#define WL_PKT_FILTER_BASE_PKT 0 +#define WL_PKT_FILTER_BASE_END 1 +#define WL_PKT_FILTER_BASE_D11_H 2 /* May be removed */ +#define WL_PKT_FILTER_BASE_D11_D 3 /* May be removed */ +#define WL_PKT_FILTER_BASE_ETH_H 4 +#define WL_PKT_FILTER_BASE_ETH_D 5 +#define WL_PKT_FILTER_BASE_ARP_H 6 +#define WL_PKT_FILTER_BASE_ARP_D 7 /* May be removed */ +#define WL_PKT_FILTER_BASE_IP4_H 8 +#define WL_PKT_FILTER_BASE_IP4_D 9 +#define WL_PKT_FILTER_BASE_IP6_H 10 +#define WL_PKT_FILTER_BASE_IP6_D 11 +#define WL_PKT_FILTER_BASE_TCP_H 12 +#define WL_PKT_FILTER_BASE_TCP_D 13 /* May be removed */ +#define WL_PKT_FILTER_BASE_UDP_H 14 +#define WL_PKT_FILTER_BASE_UDP_D 15 +#define WL_PKT_FILTER_BASE_IP6_P 16 +#define WL_PKT_FILTER_BASE_COUNT 17 /* May be removed */ + +/* String mapping for bases that may be used by applications or debug */ +#define WL_PKT_FILTER_BASE_NAMES \ + { "START", WL_PKT_FILTER_BASE_PKT }, \ + { "END", WL_PKT_FILTER_BASE_END }, \ + { "ETH_H", WL_PKT_FILTER_BASE_ETH_H }, \ + { "ETH_D", WL_PKT_FILTER_BASE_ETH_D }, \ + { "D11_H", WL_PKT_FILTER_BASE_D11_H }, \ + { "D11_D", WL_PKT_FILTER_BASE_D11_D }, \ + { "ARP_H", WL_PKT_FILTER_BASE_ARP_H }, \ + { "IP4_H", WL_PKT_FILTER_BASE_IP4_H }, \ + { "IP4_D", WL_PKT_FILTER_BASE_IP4_D }, \ + { "IP6_H", WL_PKT_FILTER_BASE_IP6_H }, \ + { "IP6_D", WL_PKT_FILTER_BASE_IP6_D }, \ + { "IP6_P", WL_PKT_FILTER_BASE_IP6_P }, \ + { "TCP_H", WL_PKT_FILTER_BASE_TCP_H }, \ + { "TCP_D", WL_PKT_FILTER_BASE_TCP_D }, \ + { "UDP_H", WL_PKT_FILTER_BASE_UDP_H }, \ + { "UDP_D", WL_PKT_FILTER_BASE_UDP_D } + +/* Flags for a pattern list element */ +#define WL_PKT_FILTER_MFLAG_NEG 0x0001 + +/* + * Packet engine interface + */ + +#define WL_PKTENG_PER_TX_START 0x01 +#define WL_PKTENG_PER_TX_STOP 0x02 +#define WL_PKTENG_PER_RX_START 0x04 +#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 +#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 +#define WL_PKTENG_PER_RX_STOP 0x08 +#define WL_PKTENG_PER_MASK 0xff + +#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ + +#define WL_PKTENG_MAXPKTSZ 16384 /* max pktsz limit for pkteng */ + +#define NUM_80211b_RATES 4 +#define NUM_80211ag_RATES 8 +#define NUM_80211n_RATES 32 +#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) + +/* + * WOWL capability/override settings + */ +#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */ +#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */ +#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */ +#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */ +#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */ +#define WL_WOWL_TST (1 << 5) /* Wakeup after test */ +#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */ +#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */ +#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */ +#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */ +#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */ +#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */ +#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */ +#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */ +#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */ +#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */ +#define WL_WOWL_SCANOL (1 << 16) /* If the bit is set, scan offload is enabled */ +#define WL_WOWL_TCPKEEP_TIME (1 << 17) /* Wakeup on tcpkeep alive timeout */ +#define WL_WOWL_MDNS_CONFLICT (1 << 18) /* Wakeup on mDNS Conflict Resolution */ +#define WL_WOWL_MDNS_SERVICE (1 << 19) /* Wakeup on mDNS Service Connect */ +#define WL_WOWL_TCPKEEP_DATA (1 << 20) /* tcp keepalive got data */ +#define WL_WOWL_FW_HALT (1 << 21) /* Firmware died in wowl mode */ +#define WL_WOWL_ENAB_HWRADIO (1 << 22) /* Enable detection of radio button changes */ +#define WL_WOWL_MIC_FAIL (1 << 23) /* Offloads detected MIC failure(s) */ +#define WL_WOWL_LINKDOWN (1 << 31) /* Link Down indication in WoWL mode */ + +#define WL_WOWL_TCPKEEP (1 << 20) /* temp copy to satisfy automerger */ +#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ + +#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ +#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ + +#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ +#define MAGIC_PKT_NUM_MAC_ADDRS 16 + + +/* Overlap BSS Scan parameters default, minimum, maximum */ +#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */ +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */ +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */ +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */ +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */ +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */ +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */ + +#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */ + +#define WL_COEX_INFO_MASK 0x07 +#define WL_COEX_INFO_REQ 0x01 +#define WL_COEX_40MHZ_INTOLERANT 0x02 +#define WL_COEX_WIDTH20 0x04 + +#define WLC_RSSI_INVALID 0 /* invalid RSSI value */ + +#define MAX_RSSI_LEVELS 8 + +/* **** EXTLOG **** */ +#define EXTLOG_CUR_VER 0x0100 + +#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ + +/* log modules (bitmap) */ +#define LOG_MODULE_COMMON 0x0001 +#define LOG_MODULE_ASSOC 0x0002 +#define LOG_MODULE_EVENT 0x0004 +#define LOG_MODULE_MAX 3 /* Update when adding module */ + +/* log levels */ +#define WL_LOG_LEVEL_DISABLE 0 +#define WL_LOG_LEVEL_ERR 1 +#define WL_LOG_LEVEL_WARN 2 +#define WL_LOG_LEVEL_INFO 3 +#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */ + +/* flag */ +#define LOG_FLAG_EVENT 1 + +/* log arg_type */ +#define LOG_ARGTYPE_NULL 0 +#define LOG_ARGTYPE_STR 1 /* %s */ +#define LOG_ARGTYPE_INT 2 /* %d */ +#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */ +#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */ + +/* 802.11 Mgmt Packet flags */ +#define VNDR_IE_BEACON_FLAG 0x1 +#define VNDR_IE_PRBRSP_FLAG 0x2 +#define VNDR_IE_ASSOCRSP_FLAG 0x4 +#define VNDR_IE_AUTHRSP_FLAG 0x8 +#define VNDR_IE_PRBREQ_FLAG 0x10 +#define VNDR_IE_ASSOCREQ_FLAG 0x20 +#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ +#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ + +#if defined(WLP2P) +/* P2P Action Frames flags (spec ordered) */ +#define VNDR_IE_GONREQ_FLAG 0x001000 +#define VNDR_IE_GONRSP_FLAG 0x002000 +#define VNDR_IE_GONCFM_FLAG 0x004000 +#define VNDR_IE_INVREQ_FLAG 0x008000 +#define VNDR_IE_INVRSP_FLAG 0x010000 +#define VNDR_IE_DISREQ_FLAG 0x020000 +#define VNDR_IE_DISRSP_FLAG 0x040000 +#define VNDR_IE_PRDREQ_FLAG 0x080000 +#define VNDR_IE_PRDRSP_FLAG 0x100000 + +#define VNDR_IE_P2PAF_SHIFT 12 +#endif /* WLP2P */ + +/* channel interference measurement (chanim) related defines */ + +/* chanim mode */ +#define CHANIM_DISABLE 0 /* disabled */ +#define CHANIM_DETECT 1 /* detection only */ +#define CHANIM_EXT 2 /* external state machine */ +#define CHANIM_ACT 3 /* full internal state machine, detect + act */ +#define CHANIM_MODE_MAX 4 + +/* define for apcs reason code */ +#define APCS_INIT 0 +#define APCS_IOCTL 1 +#define APCS_CHANIM 2 +#define APCS_CSTIMER 3 +#define APCS_BTA 4 +#define APCS_TXDLY 5 +#define APCS_NONACSD 6 +#define APCS_DFS_REENTRY 7 +#define APCS_TXFAIL 8 +#define APCS_MAX 9 + +/* number of ACS record entries */ +#define CHANIM_ACS_RECORD 10 + +/* CHANIM */ +#define CCASTATS_TXDUR 0 +#define CCASTATS_INBSS 1 +#define CCASTATS_OBSS 2 +#define CCASTATS_NOCTG 3 +#define CCASTATS_NOPKT 4 +#define CCASTATS_DOZE 5 +#define CCASTATS_TXOP 6 +#define CCASTATS_GDTXDUR 7 +#define CCASTATS_BDTXDUR 8 +#define CCASTATS_MAX 9 + +#define WL_CHANIM_COUNT_ALL 0xff +#define WL_CHANIM_COUNT_ONE 0x1 + +/* ap tpc modes */ +#define AP_TPC_OFF 0 +#define AP_TPC_BSS_PWR 1 /* BSS power control */ +#define AP_TPC_AP_PWR 2 /* AP power control */ +#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ +#define AP_TPC_MAX_LINK_MARGIN 127 + +/* ap tpc modes */ +#define AP_TPC_OFF 0 +#define AP_TPC_BSS_PWR 1 /* BSS power control */ +#define AP_TPC_AP_PWR 2 /* AP power control */ +#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ +#define AP_TPC_MAX_LINK_MARGIN 127 + +/* state */ +#define WL_P2P_DISC_ST_SCAN 0 +#define WL_P2P_DISC_ST_LISTEN 1 +#define WL_P2P_DISC_ST_SEARCH 2 + +/* i/f type */ +#define WL_P2P_IF_CLIENT 0 +#define WL_P2P_IF_GO 1 +#define WL_P2P_IF_DYNBCN_GO 2 +#define WL_P2P_IF_DEV 3 + +/* count */ +#define WL_P2P_SCHED_RSVD 0 +#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */ + +#define WL_P2P_SCHED_FIXED_LEN 3 + +/* schedule type */ +#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */ +#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */ + +/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */ +#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */ +#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */ +/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ +#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */ +/* schedule option - WL_P2P_SCHED_TYPE_XXX */ +#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */ + +/* schedule option - WL_P2P_SCHED_TYPE_ABS */ +#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */ +#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */ +/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ +#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with + * start being an offset of the 'current' TSF + */ + +/* feature flags */ +#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */ +#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe + * requests + */ +#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */ + +/* 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 + +/* Proxy STA modes */ +#define PSTA_MODE_DISABLED 0 +#define PSTA_MODE_PROXY 1 +#define PSTA_MODE_REPEATER 2 + +/* op code in nat_cfg */ +#define NAT_OP_ENABLE 1 /* enable NAT on given interface */ +#define NAT_OP_DISABLE 2 /* disable NAT on given interface */ +#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */ + +/* NAT state */ +#define NAT_STATE_ENABLED 1 /* NAT is enabled */ +#define NAT_STATE_DISABLED 2 /* NAT is disabled */ + +#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */ +#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */ +#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */ +#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */ + +/* D0 Coalescing */ +#define IPV4_ARP_FILTER 0x0001 +#define IPV4_NETBT_FILTER 0x0002 +#define IPV4_LLMNR_FILTER 0x0004 +#define IPV4_SSDP_FILTER 0x0008 +#define IPV4_WSD_FILTER 0x0010 +#define IPV6_NETBT_FILTER 0x0200 +#define IPV6_LLMNR_FILTER 0x0400 +#define IPV6_SSDP_FILTER 0x0800 +#define IPV6_WSD_FILTER 0x1000 + +/* Network Offload Engine */ +#define NWOE_OL_ENABLE 0x00000001 + +/* + * Traffic management structures/defines. + */ + +/* Traffic management bandwidth parameters */ +#define TRF_MGMT_MAX_PRIORITIES 3 + +#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ +#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Don't shape traffic */ +#define TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC 0x0008 /* Manage traffic over our local subnet */ +#define TRF_MGMT_FLAG_FILTER_ON_MACADDR 0x0010 /* filter on MAC address */ +#define TRF_MGMT_FLAG_NO_RX 0x0020 /* do not apply fiters to rx packets */ + +#define TRF_FILTER_MAC_ADDR 0x0001 /* L2 filter use dst mac address for filtering */ +#define TRF_FILTER_IP_ADDR 0x0002 /* L3 filter use ip ddress for filtering */ +#define TRF_FILTER_L4 0x0004 /* L4 filter use tcp/udp for filtering */ +#define TRF_FILTER_DWM 0x0008 /* L3 filter use DSCP for filtering */ +#define TRF_FILTER_FAVORED 0x0010 /* Tag the packet FAVORED */ + +/* WNM/NPS subfeatures mask */ +#define WL_WNM_BSSTRANS 0x00000001 +#define WL_WNM_PROXYARP 0x00000002 +#define WL_WNM_MAXIDLE 0x00000004 +#define WL_WNM_TIMBC 0x00000008 +#define WL_WNM_TFS 0x00000010 +#define WL_WNM_SLEEP 0x00000020 +#define WL_WNM_DMS 0x00000040 +#define WL_WNM_FMS 0x00000080 +#define WL_WNM_NOTIF 0x00000100 +#define WL_WNM_MAX 0x00000200 + +#ifndef ETHER_MAX_DATA +#define ETHER_MAX_DATA 1500 +#endif /* ETHER_MAX_DATA */ + +/* Different discovery modes for dpt */ +#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */ +#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */ +#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */ + +/* different path selection values */ +#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */ +#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */ +#define DPT_PATHSEL_APPATH 2 /* always use AP path */ + +/* different ops for deny list */ +#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */ +#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */ + +/* different ops for manual end point */ +#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ +#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ +#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ + +/* flags to indicate DPT status */ +#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */ +#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */ +#define DPT_STATUS_FAILED 0x04 /* DPT link failed */ + +#ifdef WLTDLS +/* different ops for manual end point */ +#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ +#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ +#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ +#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ +#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ +#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ +#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ +#define TDLS_MANUAL_EP_WFD_TPQ 8 /* WiFi-Display Tunneled Probe reQuest */ + +/* modes */ +#define TDLS_WFD_IE_TX 0 +#define TDLS_WFD_IE_RX 1 +#define TDLS_WFD_PROBE_IE_TX 2 +#define TDLS_WFD_PROBE_IE_RX 3 +#endif /* WLTDLS */ + +/* define for flag */ +#define TSPEC_PENDING 0 /* TSPEC pending */ +#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ +#define TSPEC_REJECTED 2 /* TSPEC rejected */ +#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ +#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ + +#ifdef BCMCCX +/* "wlan_reason" iovar interface */ +#define WL_WLAN_ASSOC_REASON_NORMAL_NETWORK 0 /* normal WLAN network setup */ +#define WL_WLAN_ASSOC_REASON_ROAM_FROM_CELLULAR_NETWORK 1 /* roam from Cellular network */ +#define WL_WLAN_ASSOC_REASON_ROAM_FROM_LAN 2 /* roam from LAN */ +#define WL_WLAN_ASSOC_REASON_MAX 2 /* largest value allowed */ +#endif /* BCMCCX */ + +/* Software feature flag defines used by wlfeatureflag */ +#ifdef WLAFTERBURNER +#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ +#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ +#endif /* WLAFTERBURNER */ +#define WL_SWFL_NOHWRADIO 0x0004 +#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ +#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ + +#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ + +#define CSA_BROADCAST_ACTION_FRAME 0 /* csa broadcast action frame */ +#define CSA_UNICAST_ACTION_FRAME 1 /* csa unicast action frame */ + +/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER. + * + * (-100 < value < 0) value is used directly as a roaming trigger in dBm + * (0 <= value) value specifies a logical roaming trigger level from + * the list below + * + * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never + * the logical roam trigger value. + */ +#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */ +#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */ +#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */ +#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */ +#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */ + +#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */ + +/* Preferred Network Offload (PNO, formerly PFN) defines */ +#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ + +#define SORT_CRITERIA_BIT 0 +#define AUTO_NET_SWITCH_BIT 1 +#define ENABLE_BKGRD_SCAN_BIT 2 +#define IMMEDIATE_SCAN_BIT 3 +#define AUTO_CONNECT_BIT 4 +#define ENABLE_BD_SCAN_BIT 5 +#define ENABLE_ADAPTSCAN_BIT 6 +#define IMMEDIATE_EVENT_BIT 8 +#define SUPPRESS_SSID_BIT 9 +#define ENABLE_NET_OFFLOAD_BIT 10 + +#define SORT_CRITERIA_MASK 0x0001 +#define AUTO_NET_SWITCH_MASK 0x0002 +#define ENABLE_BKGRD_SCAN_MASK 0x0004 +#define IMMEDIATE_SCAN_MASK 0x0008 +#define AUTO_CONNECT_MASK 0x0010 + +#define ENABLE_BD_SCAN_MASK 0x0020 +#define ENABLE_ADAPTSCAN_MASK 0x00c0 +#define IMMEDIATE_EVENT_MASK 0x0100 +#define SUPPRESS_SSID_MASK 0x0200 +#define ENABLE_NET_OFFLOAD_MASK 0x0400 + +#define PFN_VERSION 2 +#define PFN_SCANRESULT_VERSION 1 +#define MAX_PFN_LIST_COUNT 16 + +#define PFN_COMPLETE 1 +#define PFN_INCOMPLETE 0 + +#define DEFAULT_BESTN 2 +#define DEFAULT_MSCAN 0 +#define DEFAULT_REPEAT 10 +#define DEFAULT_EXP 2 + +#define WL_PFN_SUPPRESSFOUND_MASK 0x08 +#define WL_PFN_SUPPRESSLOST_MASK 0x10 +#define WL_PFN_RSSI_MASK 0xff00 +#define WL_PFN_RSSI_SHIFT 8 + +#define WL_PFN_REPORT_ALLNET 0 +#define WL_PFN_REPORT_SSIDNET 1 +#define WL_PFN_REPORT_BSSIDNET 2 + +#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ +#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /* Remaining reserved for future use */ + +#define WL_PFN_HIDDEN_BIT 2 +#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ +#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ +#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ +#define WL_PFN_HIDDEN_MASK 0x4 +#define MAX_SSID_WHITELIST_NUM 4 +#define MAX_BSSID_PREF_LIST_NUM 32 +#define MAX_BSSID_BLACKLIST_NUM 32 + +/* TCP Checksum Offload error injection for testing */ +#define TOE_ERRTEST_TX_CSUM 0x00000001 +#define TOE_ERRTEST_RX_CSUM 0x00000002 +#define TOE_ERRTEST_RX_CSUM2 0x00000004 + +/* ARP Offload feature flags for arp_ol iovar */ +#define ARP_OL_AGENT 0x00000001 +#define ARP_OL_SNOOP 0x00000002 +#define ARP_OL_HOST_AUTO_REPLY 0x00000004 +#define ARP_OL_PEER_AUTO_REPLY 0x00000008 + +/* ARP Offload error injection */ +#define ARP_ERRTEST_REPLY_PEER 0x1 +#define ARP_ERRTEST_REPLY_HOST 0x2 + +#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ +#define ND_MULTIHOMING_MAX 10 /* Maximum local host IP addresses */ +#define ND_REQUEST_MAX 5 /* Max set of offload params */ + + +/* AOAC wake event flag */ +#define WAKE_EVENT_NLO_DISCOVERY_BIT 1 +#define WAKE_EVENT_AP_ASSOCIATION_LOST_BIT 2 +#define WAKE_EVENT_GTK_HANDSHAKE_ERROR_BIT 4 +#define WAKE_EVENT_4WAY_HANDSHAKE_REQUEST_BIT 8 + +#define MAX_NUM_WOL_PATTERN 16 /* LOGO requirements min 16 */ + +/* Packet filter operation mode */ +/* True: 1; False: 0 */ +#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 +/* Enable and disable pkt_filter as a whole */ +#define PKT_FILTER_MODE_DISABLE 2 +/* Cache first matched rx pkt(be queried by host later) */ +#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 +/* If pkt_filter is enabled and no filter is set, don't forward anything */ +#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 + +#ifdef DONGLEOVERLAYS +#define OVERLAY_IDX_MASK 0x000000ff +#define OVERLAY_IDX_SHIFT 0 +#define OVERLAY_FLAGS_MASK 0xffffff00 +#define OVERLAY_FLAGS_SHIFT 8 +/* overlay written to device memory immediately after loading the base image */ +#define OVERLAY_FLAG_POSTLOAD 0x100 +/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */ +#define OVERLAY_FLAG_DEFER_DL 0x200 +/* overlay downloaded prior to the host going to sleep */ +#define OVERLAY_FLAG_PRESLEEP 0x400 +#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 +#endif /* DONGLEOVERLAYS */ + +/* reuse two number in the sc/rc space */ +#define SMFS_CODE_MALFORMED 0xFFFE +#define SMFS_CODE_IGNORED 0xFFFD + +/* RFAWARE def */ +#define BCM_ACTION_RFAWARE 0x77 +#define BCM_ACTION_RFAWARE_DCS 0x01 + +/* DCS reason code define */ +#define BCM_DCS_IOVAR 0x1 +#define BCM_DCS_UNKNOWN 0xFF + + +#ifdef PROP_TXSTATUS +/* Bit definitions for tlv iovar */ +/* + * enable RSSI signals: + * WLFC_CTL_TYPE_RSSI + */ +#define WLFC_FLAGS_RSSI_SIGNALS 0x0001 + +/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals: + * + * WLFC_CTL_TYPE_MAC_OPEN + * WLFC_CTL_TYPE_MAC_CLOSE + * + * WLFC_CTL_TYPE_INTERFACE_OPEN + * WLFC_CTL_TYPE_INTERFACE_CLOSE + * + * WLFC_CTL_TYPE_MACDESC_ADD + * WLFC_CTL_TYPE_MACDESC_DEL + * + */ +#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002 + +/* enable (status, fifo_credit, mac_credit) signals + * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT + * WLFC_CTL_TYPE_TXSTATUS + * WLFC_CTL_TYPE_FIFO_CREDITBACK + */ +#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 + +#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 +#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 +#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 +#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040 +#define WLFC_FLAGS_PKT_STAMP_SIGNALS 0x0080 + +#endif /* PROP_TXSTATUS */ + +#define WL_TIMBC_STATUS_AP_UNKNOWN 255 /* AP status for internal use only */ + +#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ +#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ +#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ + +/* Definitions for Reliable Multicast */ +#define WL_RELMCAST_MAX_CLIENT 32 +#define WL_RELMCAST_FLAG_INBLACKLIST 1 +#define WL_RELMCAST_FLAG_ACTIVEACKER 2 +#define WL_RELMCAST_FLAG_RELMCAST 4 + +/* structures for proximity detection device role */ +#define WL_PROXD_MODE_DISABLE 0 +#define WL_PROXD_MODE_NEUTRAL 1 +#define WL_PROXD_MODE_INITIATOR 2 +#define WL_PROXD_MODE_TARGET 3 +#define WL_PROXD_RANDOM_WAKEUP 0x8000 + + +#ifdef NET_DETECT +#define NET_DETECT_MAX_WAKE_DATA_SIZE 2048 +#define NET_DETECT_MAX_PROFILES 16 +#define NET_DETECT_MAX_CHANNELS 50 +#endif /* NET_DETECT */ + +/* 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) +#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */ + +#define WL_SPURAVOID_OFF 0 +#define WL_SPURAVOID_ON1 1 +#define WL_SPURAVOID_ON2 2 + + +#define WL_4335_SPURAVOID_ON1 1 +#define WL_4335_SPURAVOID_ON2 2 +#define WL_4335_SPURAVOID_ON3 3 +#define WL_4335_SPURAVOID_ON4 4 +#define WL_4335_SPURAVOID_ON5 5 +#define WL_4335_SPURAVOID_ON6 6 +#define WL_4335_SPURAVOID_ON7 7 +#define WL_4335_SPURAVOID_ON8 8 +#define WL_4335_SPURAVOID_ON9 9 + +/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ +#define WL_TXPWR_OVERRIDE (1U<<31) +#define WL_TXPWR_NEG (1U<<30) + + +/* 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_LCN40 10 +#define WLC_PHY_TYPE_AC 11 +#define WLC_PHY_TYPE_NULL 0xf + +/* Values for PM */ +#define PM_OFF 0 +#define PM_MAX 1 +#define PM_FAST 2 +#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */ + +#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ + +/* fbt_cap: FBT assoc / reassoc modes. */ +#define WLC_FBT_CAP_DRV_4WAY_AND_REASSOC 1 /* Driver 4-way handshake & reassoc (WLFBT). */ + +/* monitor_promisc_level bits */ +#define WL_MONPROMISC_PROMISC 0x0001 +#define WL_MONPROMISC_CTRL 0x0002 +#define WL_MONPROMISC_FCS 0x0004 + +/* TCP Checksum Offload defines */ +#define TOE_TX_CSUM_OL 0x00000001 +#define TOE_RX_CSUM_OL 0x00000002 + +#endif /* wlioctl_defs_h */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h new file mode 100644 index 000000000000..2adfaf89bf1b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h @@ -0,0 +1,136 @@ +/* + * Definitions for ioctls to access DHD iovars. + * Based on wlioctl.h (for Broadcom 802.11abg driver). + * (Moves towards generic ioctls for BCM drivers/iovars.) + * + * Definitions subject to change without notice. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhdioctl.h 516345 2014-11-19 11:58:57Z $ + */ + +#ifndef _dhdioctl_h_ +#define _dhdioctl_h_ + +#include + + +/* require default structure packing */ +#define BWL_DEFAULT_PACKING +#include + + +/* Linux network driver ioctl encoding */ +typedef struct dhd_ioctl { + uint cmd; /* common ioctl definition */ + void *buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + bool set; /* get or set request (optional) */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ + uint driver; /* to identify target driver */ +} dhd_ioctl_t; + +/* Underlying BUS definition */ +enum { + BUS_TYPE_USB = 0, /* for USB dongles */ + BUS_TYPE_SDIO, /* for SDIO dongles */ + BUS_TYPE_PCIE /* for PCIE dongles */ +}; + +/* per-driver magic numbers */ +#define DHD_IOCTL_MAGIC 0x00444944 + +/* bump this number if you change the ioctl interface */ +#define DHD_IOCTL_VERSION 1 + +#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ +#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ + +/* common ioctl definitions */ +#define DHD_GET_MAGIC 0 +#define DHD_GET_VERSION 1 +#define DHD_GET_VAR 2 +#define DHD_SET_VAR 3 + +/* message levels */ +#define DHD_ERROR_VAL 0x0001 +#define DHD_TRACE_VAL 0x0002 +#define DHD_INFO_VAL 0x0004 +#define DHD_DATA_VAL 0x0008 +#define DHD_CTL_VAL 0x0010 +#define DHD_TIMER_VAL 0x0020 +#define DHD_HDRS_VAL 0x0040 +#define DHD_BYTES_VAL 0x0080 +#define DHD_INTR_VAL 0x0100 +#define DHD_LOG_VAL 0x0200 +#define DHD_GLOM_VAL 0x0400 +#define DHD_EVENT_VAL 0x0800 +#define DHD_BTA_VAL 0x1000 +#define DHD_ISCAN_VAL 0x2000 +#define DHD_ARPOE_VAL 0x4000 +#define DHD_REORDER_VAL 0x8000 +#define DHD_WL_VAL 0x10000 +#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */ +#define DHD_WL_VAL2 0x40000 +#define DHD_PNO_VAL 0x80000 +#define DHD_RTT_VAL 0x100000 + +#ifdef SDTEST +/* For pktgen iovar */ +typedef struct dhd_pktgen { + uint version; /* To allow structure change tracking */ + uint freq; /* Max ticks between tx/rx attempts */ + uint count; /* Test packets to send/rcv each attempt */ + uint print; /* Print counts every attempts */ + uint total; /* Total packets (or bursts) */ + uint minlen; /* Minimum length of packets to send */ + uint maxlen; /* Maximum length of packets to send */ + uint numsent; /* Count of test packets sent */ + uint numrcvd; /* Count of test packets received */ + uint numfail; /* Count of test send failures */ + uint mode; /* Test mode (type of test packets) */ + uint stop; /* Stop after this many tx failures */ +} dhd_pktgen_t; + +/* Version in case structure changes */ +#define DHD_PKTGEN_VERSION 2 + +/* Type of test packets to use */ +#define DHD_PKTGEN_ECHO 1 /* Send echo requests */ +#define DHD_PKTGEN_SEND 2 /* Send discard packets */ +#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */ +#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ +#endif /* SDTEST */ + +/* Enter idle immediately (no timeout) */ +#define DHD_IDLE_IMMEDIATE (-1) + +/* Values for idleclock iovar: other values are the sd_divisor to use when idle */ +#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */ +#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */ + + +/* require default structure packing */ +#include + +#endif /* _dhdioctl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h new file mode 100644 index 000000000000..3d1c087872d7 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 $ + * +*/ + +#ifndef _epivers_h_ +#define _epivers_h_ + +#define EPI_MAJOR_VERSION 1 + +#define EPI_MINOR_VERSION 141 + +#define EPI_RC_NUMBER 67 + +#define EPI_INCREMENTAL_NUMBER 28 + +#define EPI_BUILD_NUMBER 0 + +#define EPI_VERSION 1, 141, 67, 28 + +#define EPI_VERSION_NUM 0x018d431c + +#define EPI_VERSION_DEV 1.141.67 + +/* Driver Version String, ASCII, 32 chars max */ +#define EPI_VERSION_STR "1.141.67.28 (r)" + +#endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h new file mode 100644 index 000000000000..9e236d789f01 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h @@ -0,0 +1,36 @@ +/* + * HND SiliconBackplane PMU support. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hndpmu.h 431134 2013-10-22 18:25:42Z $ + */ + +#ifndef _hndpmu_h_ +#define _hndpmu_h_ + + +extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on, uint32* min_res_mask); +extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength); + +extern void si_pmu_minresmask_htavail_set(si_t *sih, osl_t *osh, bool set_clear); + +#endif /* _hndpmu_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h new file mode 100644 index 000000000000..eee716db5fcf --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h @@ -0,0 +1,88 @@ +/* + * HNDRTE arm trap handling. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hndrte_armtrap.h 261365 2011-05-24 20:42:23Z $ + */ + +#ifndef _hndrte_armtrap_h +#define _hndrte_armtrap_h + + +/* ARM trap handling */ + +/* Trap types defined by ARM (see arminc.h) */ + +/* Trap locations in lo memory */ +#define TRAP_STRIDE 4 +#define FIRST_TRAP TR_RST +#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) + +#if defined(__ARM_ARCH_4T__) +#define MAX_TRAP_TYPE (TR_FIQ + 1) +#elif defined(__ARM_ARCH_7M__) +#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) +#endif /* __ARM_ARCH_7M__ */ + +/* The trap structure is defined here as offsets for assembly */ +#define TR_TYPE 0x00 +#define TR_EPC 0x04 +#define TR_CPSR 0x08 +#define TR_SPSR 0x0c +#define TR_REGS 0x10 +#define TR_REG(n) (TR_REGS + (n) * 4) +#define TR_SP TR_REG(13) +#define TR_LR TR_REG(14) +#define TR_PC TR_REG(15) + +#define TRAP_T_SIZE 80 + +#ifndef _LANGUAGE_ASSEMBLY + +#include + +typedef struct _trap_struct { + uint32 type; + uint32 epc; + uint32 cpsr; + uint32 spsr; + uint32 r0; /* a1 */ + uint32 r1; /* a2 */ + uint32 r2; /* a3 */ + uint32 r3; /* a4 */ + uint32 r4; /* v1 */ + uint32 r5; /* v2 */ + uint32 r6; /* v3 */ + uint32 r7; /* v4 */ + uint32 r8; /* v5 */ + uint32 r9; /* sb/v6 */ + uint32 r10; /* sl/v7 */ + uint32 r11; /* fp/v8 */ + uint32 r12; /* ip */ + uint32 r13; /* sp */ + uint32 r14; /* lr */ + uint32 pc; /* r15 */ +} trap_t; + +#endif /* !_LANGUAGE_ASSEMBLY */ + +#endif /* _hndrte_armtrap_h */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h new file mode 100644 index 000000000000..7dcde5ff37cd --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h @@ -0,0 +1,69 @@ +/* + * Console support for hndrte. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hndrte_cons.h 427140 2013-10-02 18:07:07Z $ + */ +#ifndef _HNDRTE_CONS_H +#define _HNDRTE_CONS_H + +#include + +#define CBUF_LEN (128) + +#define LOG_BUF_LEN 1024 + +typedef struct { + uint32 buf; /* Can't be pointer on (64-bit) hosts */ + uint buf_size; + uint idx; + uint out_idx; /* output index */ +} hndrte_log_t; + +typedef struct { + /* 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. + */ + volatile uint vcons_in; + volatile 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. + */ + hndrte_log_t log; + + /* 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]; +} hndrte_cons_t; + +hndrte_cons_t *hndrte_get_active_cons_state(void); + +#endif /* _HNDRTE_CONS_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h new file mode 100644 index 000000000000..1dbe9c19e0ab --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h @@ -0,0 +1,282 @@ +/* + * Broadcom HND chip & on-chip-interconnect-related definitions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: hndsoc.h 432420 2013-10-28 14:14:02Z $ + */ + +#ifndef _HNDSOC_H +#define _HNDSOC_H + +/* Include the soci specific files */ +#include +#include + +/* + * SOC Interconnect Address Map. + * All regions may not exist on all chips. + */ +#define SI_SDRAM_BASE 0x00000000 /* Physical SDRAM */ +#define SI_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */ +#define SI_PCI_MEM_SZ (64 * 1024 * 1024) +#define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */ +#define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ +#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */ + +#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ + +#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ +#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ + +#ifndef SI_MAXCORES +#define SI_MAXCORES 32 /* NorthStar has more cores */ +#endif /* SI_MAXCORES */ + +#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ +#define SI_FASTRAM_SWAPPED 0x19800000 + +#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */ +#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */ +#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */ +#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */ +#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */ +#define SI_FLASH_WINDOW 0x01000000 /* Flash XIP Window */ + +#define SI_NS_NANDFLASH 0x1c000000 /* NorthStar NAND flash base */ +#define SI_NS_NORFLASH 0x1e000000 /* NorthStar NOR flash base */ +#define SI_NS_ROM 0xfffd0000 /* NorthStar ROM */ +#define SI_NS_FLASH_WINDOW 0x02000000 /* Flash XIP Window */ + +#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */ +#define SI_ARMCR4_ROM 0x000f0000 /* ARM Cortex-R4 ROM */ +#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */ +#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */ +#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */ +#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */ + +#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */ +#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */ +#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ +#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 + * (2 ZettaBytes), low 32 bits + */ +#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 + * (2 ZettaBytes), high 32 bits + */ +/* 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 ACPHY_CORE_ID 0x83b /* Dot11 ACPHY */ +#define PCIE2_CORE_ID 0x83c /* pci express Gen2 core */ +#define USB30D_CORE_ID 0x83d /* usb 3.0 device core */ +#define ARMCR4_CORE_ID 0x83e /* ARM CR4 CPU */ +#define GCI_CORE_ID 0x840 /* GCI Core */ +#define APB_BRIDGE_CORE_ID 0x135 /* APB bridge core ID */ +#define AXI_CORE_ID 0x301 /* AXI/GPV core ID */ +#define EROM_CORE_ID 0x366 /* EROM core ID */ +#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 + */ + +#define CC_4706_CORE_ID 0x500 /* chipcommon core */ +#define NS_PCIEG2_CORE_ID 0x501 /* PCIE Gen 2 core */ +#define NS_DMA_CORE_ID 0x502 /* DMA core */ +#define NS_SDIO3_CORE_ID 0x503 /* SDIO3 core */ +#define NS_USB20_CORE_ID 0x504 /* USB2.0 core */ +#define NS_USB30_CORE_ID 0x505 /* USB3.0 core */ +#define NS_A9JTAG_CORE_ID 0x506 /* ARM Cortex A9 JTAG core */ +#define NS_DDR23_CORE_ID 0x507 /* Denali DDR2/DDR3 memory controller */ +#define NS_ROM_CORE_ID 0x508 /* ROM core */ +#define NS_NAND_CORE_ID 0x509 /* NAND flash controller core */ +#define NS_QSPI_CORE_ID 0x50a /* SPI flash controller core */ +#define NS_CCB_CORE_ID 0x50b /* ChipcommonB core */ +#define SOCRAM_4706_CORE_ID 0x50e /* internal memory core */ +#define NS_SOCRAM_CORE_ID SOCRAM_4706_CORE_ID +#define ARMCA9_CORE_ID 0x510 /* ARM Cortex A9 core (ihost) */ +#define NS_IHOST_CORE_ID ARMCA9_CORE_ID /* ARM Cortex A9 core (ihost) */ +#define GMAC_COMMON_4706_CORE_ID 0x5dc /* Gigabit MAC core */ +#define GMAC_4706_CORE_ID 0x52d /* Gigabit MAC core */ +#define AMEMC_CORE_ID 0x52e /* DDR1/2 memory controller core */ +#define ALTA_CORE_ID 0x534 /* I2S core */ +#define DDR23_PHY_CORE_ID 0x5dd + +#define SI_PCI1_MEM 0x40000000 /* Host Mode sb2pcitranslation0 (64 MB) */ +#define SI_PCI1_CFG 0x44000000 /* Host Mode sb2pcitranslation1 (64 MB) */ +#define SI_PCIE1_DMA_H32 0xc0000000 /* PCIE Client Mode sb2pcitranslation2 + * (2 ZettaBytes), high 32 bits + */ +#define CC_4706B0_CORE_REV 0x8000001f /* chipcommon core */ +#define SOCRAM_4706B0_CORE_REV 0x80000005 /* internal memory core */ +#define GMAC_4706B0_CORE_REV 0x80000000 /* Gigabit MAC core */ + +/* There are TWO constants on all HND chips: SI_ENUM_BASE above, + * and chipcommon being the first core: + */ +#define SI_CC_IDX 0 +/* SOC Interconnect types (aka chip types) */ +#define SOCI_SB 0 +#define SOCI_AI 1 +#define SOCI_UBUS 2 +#define SOCI_NAI 3 + +/* 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 + +/* Norstar core status flags */ +#define SISF_NS_BOOTDEV_MASK 0x0003 /* ROM core */ +#define SISF_NS_BOOTDEV_NOR 0x0000 /* ROM core */ +#define SISF_NS_BOOTDEV_NAND 0x0001 /* ROM core */ +#define SISF_NS_BOOTDEV_ROM 0x0002 /* ROM core */ +#define SISF_NS_BOOTDEV_OFFLOAD 0x0003 /* ROM core */ +#define SISF_NS_SKUVEC_MASK 0x000c /* ROM core */ + +/* 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 */ +#define SI_PWR_CTL_ST 0x1e8 /* For memory clock gating */ + +/* 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_HQCLKREQ 0x00000040 /* HQ Clock Required */ +#define CCS_USBCLKREQ 0x00000100 /* USB Clock Req */ +#define CCS_SECICLKREQ 0x00000100 /* SECI Clock Req */ +#define CCS_ARMFASTCLOCKREQ 0x00000100 /* ARM CR4 fast clock request */ +#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: Backplane is running on ALP clock */ +#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */ +#define CCS_ARMFASTCLOCKSTATUS 0x01000000 /* Fast CPU clock is running */ +#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ +#define CCS_ERSRC_STS_SHIFT 24 + +#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */ +#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */ + +/* 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 */ + +/* A boot/binary may have an embedded block that describes its size */ +#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */ +#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */ +#define BISZ_MAGIC_IDX 0 /* Word 0: magic */ +#define BISZ_TXTST_IDX 1 /* 1: text start */ +#define BISZ_TXTEND_IDX 2 /* 2: text end */ +#define BISZ_DATAST_IDX 3 /* 3: data start */ +#define BISZ_DATAEND_IDX 4 /* 4: data end */ +#define BISZ_BSSST_IDX 5 /* 5: bss start */ +#define BISZ_BSSEND_IDX 6 /* 6: bss end */ +#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */ + +/* Boot/Kernel related defintion and functions */ +#define SOC_BOOTDEV_ROM 0x00000001 +#define SOC_BOOTDEV_PFLASH 0x00000002 +#define SOC_BOOTDEV_SFLASH 0x00000004 +#define SOC_BOOTDEV_NANDFLASH 0x00000008 + +#define SOC_KNLDEV_NORFLASH 0x00000002 +#define SOC_KNLDEV_NANDFLASH 0x00000004 + +#ifndef _LANGUAGE_ASSEMBLY +int soc_boot_dev(void *sih); +int soc_knl_dev(void *sih); +#endif /* _LANGUAGE_ASSEMBLY */ + +#endif /* _HNDSOC_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h new file mode 100644 index 000000000000..d586e5f8ba60 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h @@ -0,0 +1,688 @@ +/* + * Linux OS Independent Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: linux_osl.h 432719 2013-10-29 12:04:59Z $ + */ + +#ifndef _linux_osl_h_ +#define _linux_osl_h_ + +#include + +/* Linux Kernel: File Operations: start */ +extern void * osl_os_open_image(char * filename); +extern int osl_os_get_image_block(char * buf, int len, void * image); +extern void osl_os_close_image(void * image); +extern int osl_os_image_size(void *image); +/* Linux Kernel: File Operations: end */ + +#ifdef BCMDRIVER + +/* OSL initialization */ +#ifdef SHARED_OSL_CMN +extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag, void **osh_cmn); +#else +extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); +#endif /* SHARED_OSL_CMN */ + +extern void osl_detach(osl_t *osh); +extern int osl_static_mem_init(osl_t *osh, void *adapter); +extern int osl_static_mem_deinit(osl_t *osh, void *adapter); +extern void osl_set_bus_handle(osl_t *osh, void *bus_handle); +extern void* osl_get_bus_handle(osl_t *osh); + +/* Global ASSERT type */ +extern uint32 g_assert_type; + +/* ASSERT */ +#if defined(BCMASSERT_LOG) + #define ASSERT(exp) \ + do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) +extern void osl_assert(const char *exp, const char *file, int line); +#else + #ifdef __GNUC__ + #define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) + #if GCC_VERSION > 30100 + #define ASSERT(exp) do {} while (0) + #else + /* ASSERT could cause segmentation fault on GCC3.1, use empty instead */ + #define ASSERT(exp) + #endif /* GCC_VERSION > 30100 */ + #endif /* __GNUC__ */ +#endif + +/* microsecond delay */ +#define OSL_DELAY(usec) osl_delay(usec) +extern void osl_delay(uint usec); + +#define OSL_SLEEP(ms) osl_sleep(ms) +extern void osl_sleep(uint ms); + +#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ + osl_pcmcia_read_attr((osh), (offset), (buf), (size)) +#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ + osl_pcmcia_write_attr((osh), (offset), (buf), (size)) +extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); +extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size); + +/* PCI configuration space access macros */ +#define OSL_PCI_READ_CONFIG(osh, offset, size) \ + osl_pci_read_config((osh), (offset), (size)) +#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ + osl_pci_write_config((osh), (offset), (size), (val)) +extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); +extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); + +/* PCI device bus # and slot # */ +#define OSL_PCI_BUS(osh) osl_pci_bus(osh) +#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) +extern uint osl_pci_bus(osl_t *osh); +extern uint osl_pci_slot(osl_t *osh); +extern struct pci_dev *osl_pci_device(osl_t *osh); + +/* Pkttag flag should be part of public information */ +typedef struct { + bool pkttag; + bool mmbus; /* Bus supports memory-mapped register accesses */ + pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ + void *tx_ctx; /* Context to the callback function */ + void *unused[3]; +} osl_pubinfo_t; + +#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ + do { \ + ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ + ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ + } while (0) + + +/* host/bus architecture-specific byte swap */ +#define BUS_SWAP32(v) (v) + #define MALLOC(osh, size) osl_malloc((osh), (size)) + #define MALLOCZ(osh, size) osl_mallocz((osh), (size)) + #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) + #define MALLOCED(osh) osl_malloced((osh)) + #define MEMORY_LEFTOVER(osh) osl_check_memleak(osh) + extern void *osl_malloc(osl_t *osh, uint size); + extern void *osl_mallocz(osl_t *osh, uint size); + extern void osl_mfree(osl_t *osh, void *addr, uint size); + extern uint osl_malloced(osl_t *osh); + extern uint osl_check_memleak(osl_t *osh); + + +#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) +extern uint osl_malloc_failed(osl_t *osh); + +/* allocate/free shared (dma-able) consistent memory */ +#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() +#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ + osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) +#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ + osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) + +#define DMA_ALLOC_CONSISTENT_FORCE32(osh, size, align, tot, pap, dmah) \ + osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) +#define DMA_FREE_CONSISTENT_FORCE32(osh, va, size, pa, dmah) \ + osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) + +extern uint osl_dma_consistent_align(void); +extern void * +osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, uint *tot, dmaaddr_t *pap); +extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa); + +/* map/unmap direction */ +#define DMA_TX 1 /* TX direction for DMA */ +#define DMA_RX 2 /* RX direction for DMA */ + +/* map/unmap shared (dma-able) memory */ +#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ + osl_dma_unmap((osh), (pa), (size), (direction)) +extern dmaaddr_t osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, + hnddma_seg_map_t *txp_dmah); +extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); + +/* API for DMA addressing capability */ +#define OSL_DMADDRWIDTH(osh, addrwidth) ({BCM_REFERENCE(osh); BCM_REFERENCE(addrwidth);}) + + #define OSL_CACHE_FLUSH(va, len) BCM_REFERENCE(va) + #define OSL_CACHE_INV(va, len) BCM_REFERENCE(va) + #define OSL_PREFETCH(ptr) prefetch(ptr) + +/* register access macros */ + #include + #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(osl_get_bus_handle(osh), \ + (uintptr)(r), sizeof(*(r)), (v))) + #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(osl_get_bus_handle(osh), \ + (uintptr)(r), sizeof(*(r)))) + + #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ + mmap_op else bus_op + #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ + mmap_op : bus_op + +#define OSL_ERROR(bcmerror) osl_error(bcmerror) +extern int osl_error(int bcmerror); + +/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ +#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ + +#define OSH_NULL NULL + +/* + * BINOSL selects the slightly slower function-call-based binary compatible osl. + * Macros expand to calls to functions defined in linux_osl.c . + */ +#include /* use current 2.4.x calling conventions */ +#include /* for vsn/printf's */ +#include /* for mem*, str* */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) +#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) +#else +#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ +#define printf(fmt, args...) printk(fmt , ## args) +#include /* for vsn/printf's */ +#include /* for mem*, str* */ +/* bcopy's: Linux kernel doesn't provide these (anymore) */ +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) +#define bzero(b, len) memset((b), '\0', (len)) + +/* register access macros */ + +#define R_REG(osh, r) (\ + SELECT_BUS_READ(osh, \ + ({ \ + __typeof(*(r)) __osl_v; \ + switch (sizeof(*(r))) { \ + case sizeof(uint8): __osl_v = \ + readb((volatile uint8*)(r)); break; \ + case sizeof(uint16): __osl_v = \ + readw((volatile uint16*)(r)); break; \ + case sizeof(uint32): __osl_v = \ + readl((volatile uint32*)(r)); break; \ + } \ + __osl_v; \ + }), \ + OSL_READ_REG(osh, r)) \ +) + +#define W_REG(osh, r, v) do { \ + SELECT_BUS_WRITE(osh, \ + switch (sizeof(*(r))) { \ + case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ + case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ + case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ + }, \ + (OSL_WRITE_REG(osh, r, v))); \ + } while (0) + +#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) +#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) + +/* bcopy, bcmp, and bzero functions */ +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) +#define bzero(b, len) memset((b), '\0', (len)) + +/* uncached/cached virtual address */ +#define OSL_UNCACHED(va) ((void *)va) +#define OSL_CACHED(va) ((void *)va) + +#define OSL_PREF_RANGE_LD(va, sz) BCM_REFERENCE(va) +#define OSL_PREF_RANGE_ST(va, sz) BCM_REFERENCE(va) + +/* get processor cycle count */ +#if defined(__i386__) +#define OSL_GETCYCLES(x) rdtscl((x)) +#else +#define OSL_GETCYCLES(x) ((x) = 0) +#endif + +/* dereference an address that may cause a bus exception */ +#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) + +/* map/unmap physical to virtual I/O */ +#if !defined(CONFIG_MMC_MSM7X00A) +#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) +#else +#define REG_MAP(pa, size) (void *)(0) +#endif /* !defined(CONFIG_MMC_MSM7X00A */ +#define REG_UNMAP(va) iounmap((va)) + +/* shared (dma-able) memory access macros */ +#define R_SM(r) *(r) +#define W_SM(r, v) (*(r) = (v)) +#define BZERO_SM(r, len) memset((r), '\0', (len)) + +/* Because the non BINOSL implemenation of the PKT OSL routines are macros (for + * performance reasons), we need the Linux headers. + */ +#include /* use current 2.4.x calling conventions */ + +/* packet primitives */ +#define PKTGET(osh, len, send) osl_pktget((osh), (len)) +#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) +#define PKTLIST_DUMP(osh, buf) BCM_REFERENCE(osh) +#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) +#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) +#ifdef CONFIG_DHD_USE_STATIC_BUF +#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) +#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) +#else +#define PKTGET_STATIC PKTGET +#define PKTFREE_STATIC PKTFREE +#endif /* CONFIG_DHD_USE_STATIC_BUF */ +#define PKTDATA(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->data);}) +#define PKTLEN(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->len);}) +#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) +#define PKTEXPHEADROOM(osh, skb, b) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_realloc_headroom((struct sk_buff*)(skb), (b)); \ + }) +#define PKTTAILROOM(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_tailroom((struct sk_buff*)(skb)); \ + }) +#define PKTPADTAILROOM(osh, skb, padlen) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_pad((struct sk_buff*)(skb), (padlen)); \ + }) +#define PKTNEXT(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->next);}) +#define PKTSETNEXT(osh, skb, x) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)); \ + }) +#define PKTSETLEN(osh, skb, len) \ + ({ \ + BCM_REFERENCE(osh); \ + __skb_trim((struct sk_buff*)(skb), (len)); \ + }) +#define PKTPUSH(osh, skb, bytes) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_push((struct sk_buff*)(skb), (bytes)); \ + }) +#define PKTPULL(osh, skb, bytes) \ + ({ \ + BCM_REFERENCE(osh); \ + skb_pull((struct sk_buff*)(skb), (bytes)); \ + }) +#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) +#define PKTSETPOOL(osh, skb, x, y) BCM_REFERENCE(osh) +#define PKTPOOL(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) +#define PKTFREELIST(skb) PKTLINK(skb) +#define PKTSETFREELIST(skb, x) PKTSETLINK((skb), (x)) +#define PKTPTR(skb) (skb) +#define PKTID(skb) ({BCM_REFERENCE(skb); 0;}) +#define PKTSETID(skb, id) ({BCM_REFERENCE(skb); BCM_REFERENCE(id);}) +#define PKTSHRINK(osh, m) ({BCM_REFERENCE(osh); m;}) + + +#ifdef CTFPOOL +#define CTFPOOL_REFILL_THRESH 3 +typedef struct ctfpool { + void *head; + spinlock_t lock; + uint max_obj; + uint curr_obj; + uint obj_size; + uint refills; + uint fast_allocs; + uint fast_frees; + uint slow_allocs; +} ctfpool_t; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define FASTBUF (1 << 0) +#define PKTSETFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->pktc_flags) |= FASTBUF); \ + }) +#define PKTCLRFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->pktc_flags) &= (~FASTBUF)); \ + }) +#define PKTISFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->pktc_flags) & FASTBUF); \ + }) +#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->pktc_flags) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#define FASTBUF (1 << 16) +#define PKTSETFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF); \ + }) +#define PKTCLRFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)); \ + }) +#define PKTISFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->mac_len) & FASTBUF); \ + }) +#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) +#else +#define FASTBUF (1 << 0) +#define PKTSETFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->__unused) |= FASTBUF); \ + }) +#define PKTCLRFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)); \ + }) +#define PKTISFAST(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + ((((struct sk_buff*)(skb))->__unused) & FASTBUF); \ + }) +#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) +#endif /* 2.6.22 */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->ctfpool) +#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->ctfpool)->head) +#else +#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) +#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) +#endif + +extern void *osl_ctfpool_add(osl_t *osh); +extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); +extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); +extern void osl_ctfpool_cleanup(osl_t *osh); +extern void osl_ctfpool_stats(osl_t *osh, void *b); +#else /* CTFPOOL */ +#define PKTSETFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTISFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) +#endif /* CTFPOOL */ + +#define PKTSETCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTISCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) + +#ifdef HNDCTF + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define SKIPCT (1 << 2) +#define CHAINED (1 << 3) +#define PKTSETSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags |= SKIPCT); \ + }) +#define PKTCLRSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags &= (~SKIPCT)); \ + }) +#define PKTSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags & SKIPCT); \ + }) +#define PKTSETCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags |= CHAINED); \ + }) +#define PKTCLRCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->pktc_flags &= (~CHAINED)); \ + }) +#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->pktc_flags & CHAINED) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#define SKIPCT (1 << 18) +#define CHAINED (1 << 19) +#define PKTSETSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len |= SKIPCT); \ + }) +#define PKTCLRSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)); \ + }) +#define PKTSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len & SKIPCT); \ + }) +#define PKTSETCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len |= CHAINED); \ + }) +#define PKTCLRCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->mac_len &= (~CHAINED)); \ + }) +#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->mac_len & CHAINED) +#else /* 2.6.22 */ +#define SKIPCT (1 << 2) +#define CHAINED (1 << 3) +#define PKTSETSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused |= SKIPCT); \ + }) +#define PKTCLRSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)); \ + }) +#define PKTSKIPCT(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused & SKIPCT); \ + }) +#define PKTSETCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused |= CHAINED); \ + }) +#define PKTCLRCHAINED(osh, skb) \ + ({ \ + BCM_REFERENCE(osh); \ + (((struct sk_buff*)(skb))->__unused &= (~CHAINED)); \ + }) +#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->__unused & CHAINED) +#endif /* 2.6.22 */ +typedef struct ctf_mark { + uint32 value; +} ctf_mark_t; +#define CTF_MARK(m) (m.value) +#else /* HNDCTF */ +#define PKTSETSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define CTF_MARK(m) ({BCM_REFERENCE(m); 0;}) +#endif /* HNDCTF */ + +#ifdef BCMFA +#ifdef BCMFA_HW_HASH +#define PKTSETFAHIDX(skb, idx) (((struct sk_buff*)(skb))->napt_idx = idx) +#else +#define PKTSETFAHIDX(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) +#endif /* BCMFA_SW_HASH */ +#define PKTGETFAHIDX(skb) (((struct sk_buff*)(skb))->napt_idx) +#define PKTSETFADEV(skb, imp) (((struct sk_buff*)(skb))->dev = imp) +#define PKTSETRXDEV(skb) (((struct sk_buff*)(skb))->rxdev = ((struct sk_buff*)(skb))->dev) + +#define AUX_TCP_FIN_RST (1 << 0) +#define AUX_FREED (1 << 1) +#define PKTSETFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_TCP_FIN_RST) +#define PKTCLRFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_TCP_FIN_RST)) +#define PKTISFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_TCP_FIN_RST) +#define PKTSETFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_FREED) +#define PKTCLRFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_FREED)) +#define PKTISFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_FREED) +#define PKTISFABRIDGED(skb) PKTISFAAUX(skb) +#else +#define PKTISFAAUX(skb) ({BCM_REFERENCE(skb); FALSE;}) +#define PKTISFABRIDGED(skb) ({BCM_REFERENCE(skb); FALSE;}) +#define PKTISFAFREED(skb) ({BCM_REFERENCE(skb); FALSE;}) + +#define PKTCLRFAAUX(skb) BCM_REFERENCE(skb) +#define PKTSETFAFREED(skb) BCM_REFERENCE(skb) +#define PKTCLRFAFREED(skb) BCM_REFERENCE(skb) +#endif /* BCMFA */ + +extern void osl_pktfree(osl_t *osh, void *skb, bool send); +extern void *osl_pktget_static(osl_t *osh, uint len); +extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); + +extern void *osl_pkt_frmnative(osl_t *osh, void *skb); +extern void *osl_pktget(osl_t *osh, uint len); +extern void *osl_pktdup(osl_t *osh, void *skb); +extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); +#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), (struct sk_buff*)(skb)) +#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_t *)(osh), (pkt)) + +#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) +#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) +#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) +#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) +#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW) +#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \ + ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) +/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ +#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) + +#ifdef CONFIG_NF_CONNTRACK_MARK +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define PKTMARK(p) (((struct sk_buff *)(p))->mark) +#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->mark = (m) +#else /* !2.6.0 */ +#define PKTMARK(p) (((struct sk_buff *)(p))->nfmark) +#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->nfmark = (m) +#endif /* 2.6.0 */ +#else /* CONFIG_NF_CONNTRACK_MARK */ +#define PKTMARK(p) 0 +#define PKTSETMARK(p, m) +#endif /* CONFIG_NF_CONNTRACK_MARK */ + +#define PKTALLOCED(osh) osl_pktalloced(osh) +extern uint osl_pktalloced(osl_t *osh); + +#define DMA_MAP(osh, va, size, direction, p, dmah) \ + osl_dma_map((osh), (va), (size), (direction), (p), (dmah)) + +#ifdef PKTC +/* Use 8 bytes of skb tstamp field to store below info */ +struct chain_node { + struct sk_buff *link; + unsigned int flags:3, pkts:9, bytes:20; +}; + +#define CHAIN_NODE(skb) ((struct chain_node*)(((struct sk_buff*)skb)->pktc_cb)) + +#define PKTCSETATTR(s, f, p, b) ({CHAIN_NODE(s)->flags = (f); CHAIN_NODE(s)->pkts = (p); \ + CHAIN_NODE(s)->bytes = (b);}) +#define PKTCCLRATTR(s) ({CHAIN_NODE(s)->flags = CHAIN_NODE(s)->pkts = \ + CHAIN_NODE(s)->bytes = 0;}) +#define PKTCGETATTR(s) (CHAIN_NODE(s)->flags << 29 | CHAIN_NODE(s)->pkts << 20 | \ + CHAIN_NODE(s)->bytes) +#define PKTCCNT(skb) (CHAIN_NODE(skb)->pkts) +#define PKTCLEN(skb) (CHAIN_NODE(skb)->bytes) +#define PKTCGETFLAGS(skb) (CHAIN_NODE(skb)->flags) +#define PKTCSETFLAGS(skb, f) (CHAIN_NODE(skb)->flags = (f)) +#define PKTCCLRFLAGS(skb) (CHAIN_NODE(skb)->flags = 0) +#define PKTCFLAGS(skb) (CHAIN_NODE(skb)->flags) +#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c)) +#define PKTCINCRCNT(skb) (CHAIN_NODE(skb)->pkts++) +#define PKTCADDCNT(skb, c) (CHAIN_NODE(skb)->pkts += (c)) +#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l)) +#define PKTCADDLEN(skb, l) (CHAIN_NODE(skb)->bytes += (l)) +#define PKTCSETFLAG(skb, fb) (CHAIN_NODE(skb)->flags |= (fb)) +#define PKTCCLRFLAG(skb, fb) (CHAIN_NODE(skb)->flags &= ~(fb)) +#define PKTCLINK(skb) (CHAIN_NODE(skb)->link) +#define PKTSETCLINK(skb, x) (CHAIN_NODE(skb)->link = (struct sk_buff*)(x)) +#define FOREACH_CHAINED_PKT(skb, nskb) \ + for (; (skb) != NULL; (skb) = (nskb)) \ + if ((nskb) = (PKTISCHAINED(skb) ? PKTCLINK(skb) : NULL), \ + PKTSETCLINK((skb), NULL), 1) +#define PKTCFREE(osh, skb, send) \ +do { \ + void *nskb; \ + ASSERT((skb) != NULL); \ + FOREACH_CHAINED_PKT((skb), nskb) { \ + PKTCLRCHAINED((osh), (skb)); \ + PKTCCLRFLAGS((skb)); \ + PKTFREE((osh), (skb), (send)); \ + } \ +} while (0) +#define PKTCENQTAIL(h, t, p) \ +do { \ + if ((t) == NULL) { \ + (h) = (t) = (p); \ + } else { \ + PKTSETCLINK((t), (p)); \ + (t) = (p); \ + } \ +} while (0) +#endif /* PKTC */ + +#else /* ! BCMDRIVER */ + + +/* ASSERT */ + #define ASSERT(exp) do {} while (0) + +/* MALLOC and MFREE */ +#define MALLOC(o, l) malloc(l) +#define MFREE(o, p, l) free(p) +#include + +/* str* and mem* functions */ +#include + +/* *printf functions */ +#include + +/* bcopy, bcmp, and bzero */ +extern void bcopy(const void *src, void *dst, size_t len); +extern int bcmp(const void *b1, const void *b2, size_t len); +extern void bzero(void *b, size_t len); +#endif /* ! BCMDRIVER */ + +#endif /* _linux_osl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h b/drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h new file mode 100644 index 000000000000..f6e08bc85f14 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h @@ -0,0 +1,748 @@ +/* + * Linux-specific abstractions to gain some independence from linux kernel versions. + * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: linuxver.h 431983 2013-10-25 06:53:27Z $ + */ + +#ifndef _linuxver_h_ +#define _linuxver_h_ + +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +#include +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) +#include +#else +#include +#endif +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) +#include +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) +/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */ +#ifdef __UNDEF_NO_VERSION__ +#undef __NO_VERSION__ +#else +#define __NO_VERSION__ +#endif +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) +#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i") +#define module_param_string(_name_, _string_, _size_, _perm_) \ + MODULE_PARM(_string_, "c" __MODULE_STRING(_size_)) +#endif + +/* linux/malloc.h is deprecated, use linux/slab.h instead. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)) +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +#include +#else +#include +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) +#undef IP_TOS +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) */ +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)) +#include +#else +#include +#ifndef work_struct +#define work_struct tq_struct +#endif +#ifndef INIT_WORK +#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data)) +#endif +#ifndef schedule_work +#define schedule_work(_work) schedule_task((_work)) +#endif +#ifndef flush_scheduled_work +#define flush_scheduled_work() flush_scheduled_tasks() +#endif +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define DAEMONIZE(a) do { \ + allow_signal(SIGKILL); \ + allow_signal(SIGTERM); \ + } while (0) +#elif ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))) +#define DAEMONIZE(a) daemonize(a); \ + allow_signal(SIGKILL); \ + allow_signal(SIGTERM); +#else /* Linux 2.4 (w/o preemption patch) */ +#define RAISE_RX_SOFTIRQ() \ + cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) +#define DAEMONIZE(a) daemonize(); \ + do { if (a) \ + strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ + } while (0); +#endif /* LINUX_VERSION_CODE */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) +#else +#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) +#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ + (RHEL_MAJOR == 5)) +/* Exclude RHEL 5 */ +typedef void (*work_func_t)(void *work); +#endif +#endif /* >= 2.6.20 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +/* Some distributions have their own 2.6.x compatibility layers */ +#ifndef IRQ_NONE +typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) +#endif +#else +typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#define IRQF_SHARED SA_SHIRQ +#endif /* < 2.6.18 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) +#ifdef CONFIG_NET_RADIO +#define CONFIG_WIRELESS_EXT +#endif +#endif /* < 2.6.17 */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) +#include +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) +#include +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +#include +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) +#include +#endif +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ + + +#ifndef __exit +#define __exit +#endif +#ifndef __devexit +#define __devexit +#endif +#ifndef __devinit +# if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) +# define __devinit __init +# else +/* All devices are hotpluggable since linux 3.8.0 */ +# define __devinit +# endif +#endif /* !__devinit */ +#ifndef __devinitdata +#define __devinitdata +#endif +#ifndef __devexit_p +#define __devexit_p(x) x +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) + +#define pci_get_drvdata(dev) (dev)->sysdata +#define pci_set_drvdata(dev, value) (dev)->sysdata = (value) + +/* + * New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration + */ + +struct pci_device_id { + unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ + unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ + unsigned long driver_data; /* Data private to the driver */ +}; + +struct pci_driver { + struct list_head node; + char *name; + const struct pci_device_id *id_table; /* NULL if wants all devices */ + int (*probe)(struct pci_dev *dev, + const struct pci_device_id *id); /* New device inserted */ + void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug + * capable driver) + */ + void (*suspend)(struct pci_dev *dev); /* Device suspended */ + void (*resume)(struct pci_dev *dev); /* Device woken up */ +}; + +#define MODULE_DEVICE_TABLE(type, name) +#define PCI_ANY_ID (~0) + +/* compatpci.c */ +#define pci_module_init pci_register_driver +extern int pci_register_driver(struct pci_driver *drv); +extern void pci_unregister_driver(struct pci_driver *drv); + +#endif /* PCI registration */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) +#define pci_module_init pci_register_driver +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) +#ifdef MODULE +#define module_init(x) int init_module(void) { return x(); } +#define module_exit(x) void cleanup_module(void) { x(); } +#else +#define module_init(x) __initcall(x); +#define module_exit(x) __exitcall(x); +#endif +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) +#define WL_USE_NETDEV_OPS +#else +#undef WL_USE_NETDEV_OPS +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL) +#define WL_CONFIG_RFKILL +#else +#undef WL_CONFIG_RFKILL +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13)) +#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44)) +#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23)) +#define pci_enable_device(dev) do { } while (0) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)) +#define net_device device +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42)) + +/* + * DMA mapping + * + * See linux/Documentation/DMA-mapping.txt + */ + +#ifndef PCI_DMA_TODEVICE +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 +#endif + +typedef u32 dma_addr_t; + +/* Pure 2^n version of get_order */ +static inline int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC | GFP_DMA; + + ret = (void *)__get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} +static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, get_order(size)); +} +#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) +#define pci_unmap_single(cookie, address, size, dir) + +#endif /* DMA mapping */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)) + +#define dev_kfree_skb_any(a) dev_kfree_skb(a) +#define netif_down(dev) do { (dev)->start = 0; } while (0) + +/* pcmcia-cs provides its own netdevice compatibility layer */ +#ifndef _COMPAT_NETDEVICE_H + +/* + * SoftNet + * + * For pre-softnet kernels we need to tell the upper layer not to + * re-enter start_xmit() while we are in there. However softnet + * guarantees not to enter while we are in there so there is no need + * to do the netif_stop_queue() dance unless the transmit queue really + * gets stuck. This should also improve performance according to tests + * done by Aman Singla. + */ + +#define dev_kfree_skb_irq(a) dev_kfree_skb(a) +#define netif_wake_queue(dev) \ + do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0) +#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy) + +static inline void netif_start_queue(struct net_device *dev) +{ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; +} + +#define netif_queue_stopped(dev) (dev)->tbusy +#define netif_running(dev) (dev)->start + +#endif /* _COMPAT_NETDEVICE_H */ + +#define netif_device_attach(dev) netif_start_queue(dev) +#define netif_device_detach(dev) netif_stop_queue(dev) + +/* 2.4.x renamed bottom halves to tasklets */ +#define tasklet_struct tq_struct +static inline void tasklet_schedule(struct tasklet_struct *tasklet) +{ + queue_task(tasklet, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static inline void tasklet_init(struct tasklet_struct *tasklet, + void (*func)(unsigned long), + unsigned long data) +{ + tasklet->next = NULL; + tasklet->sync = 0; + tasklet->routine = (void (*)(void *))func; + tasklet->data = (void *)data; +} +#define tasklet_kill(tasklet) { do {} while (0); } + +/* 2.4.x introduced del_timer_sync() */ +#define del_timer_sync(timer) del_timer(timer) + +#else + +#define netif_down(dev) + +#endif /* SoftNet */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)) + +/* + * Emit code to initialise a tq_struct's routine and data pointers + */ +#define PREPARE_TQUEUE(_tq, _routine, _data) \ + do { \ + (_tq)->routine = _routine; \ + (_tq)->data = _data; \ + } while (0) + +/* + * Emit code to initialise all of a tq_struct + */ +#define INIT_TQUEUE(_tq, _routine, _data) \ + do { \ + INIT_LIST_HEAD(&(_tq)->list); \ + (_tq)->sync = 0; \ + PREPARE_TQUEUE((_tq), (_routine), (_data)); \ + } while (0) + +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) */ + +/* Power management related macro & routines */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) +#define PCI_SAVE_STATE(a, b) pci_save_state(a) +#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) +#else +#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) +#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) +static inline int +pci_save_state(struct pci_dev *dev, u32 *buffer) +{ + int i; + if (buffer) { + for (i = 0; i < 16; i++) + pci_read_config_dword(dev, i * 4, &buffer[i]); + } + return 0; +} + +static inline int +pci_restore_state(struct pci_dev *dev, u32 *buffer) +{ + int i; + + if (buffer) { + for (i = 0; i < 16; i++) + pci_write_config_dword(dev, i * 4, buffer[i]); + } + /* + * otherwise, write the context information we know from bootup. + * This works around a problem where warm-booting from Windows + * combined with a D3(hot)->D0 transition causes PCI config + * header data to be forgotten. + */ + else { + for (i = 0; i < 6; i ++) + pci_write_config_dword(dev, + PCI_BASE_ADDRESS_0 + (i * 4), + pci_resource_start(dev, i)); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + return 0; +} +#endif /* PCI power management */ + +/* Old cp0 access macros deprecated in 2.4.19 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19)) +#define read_c0_count() read_32bit_cp0_register(CP0_COUNT) +#endif + +/* Module refcount handled internally in 2.6.x */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) +#ifndef SET_MODULE_OWNER +#define SET_MODULE_OWNER(dev) do {} while (0) +#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define OLD_MOD_INC_USE_COUNT do {} while (0) +#define OLD_MOD_DEC_USE_COUNT do {} while (0) +#endif +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ +#ifndef SET_MODULE_OWNER +#define SET_MODULE_OWNER(dev) do {} while (0) +#endif +#ifndef MOD_INC_USE_COUNT +#define MOD_INC_USE_COUNT do {} while (0) +#endif +#ifndef MOD_DEC_USE_COUNT +#define MOD_DEC_USE_COUNT do {} while (0) +#endif +#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ + +#ifndef SET_NETDEV_DEV +#define SET_NETDEV_DEV(net, pdev) do {} while (0) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)) +#ifndef HAVE_FREE_NETDEV +#define free_netdev(dev) kfree(dev) +#endif +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +/* struct packet_type redefined in 2.6.x */ +#define af_packet_priv data +#endif + +/* suspend args */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) +#define DRV_SUSPEND_STATE_TYPE pm_message_t +#else +#define DRV_SUSPEND_STATE_TYPE uint32 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +#define CHECKSUM_HW CHECKSUM_PARTIAL +#endif + +typedef struct { + void *parent; /* some external entity that the thread supposed to work for */ + char *proc_name; + struct task_struct *p_task; + long thr_pid; + int prio; /* priority */ + struct semaphore sema; + int terminated; + struct completion completed; + spinlock_t spinlock; + int up_cnt; +} tsk_ctl_t; + + +/* requires tsk_ctl_t tsk argument, the caller's priv data is passed in owner ptr */ +/* note this macro assumes there may be only one context waiting on thread's completion */ +#ifdef DHD_DEBUG +#define DBG_THR(x) printk x +#else +#define DBG_THR(x) +#endif + +static inline bool binary_sema_down(tsk_ctl_t *tsk) +{ + if (down_interruptible(&tsk->sema) == 0) { + unsigned long flags = 0; + spin_lock_irqsave(&tsk->spinlock, flags); + if (tsk->up_cnt == 1) + tsk->up_cnt--; + else { + DBG_THR(("dhd_dpc_thread: Unexpected up_cnt %d\n", tsk->up_cnt)); + } + spin_unlock_irqrestore(&tsk->spinlock, flags); + return false; + } else + return true; +} + +static inline bool binary_sema_up(tsk_ctl_t *tsk) +{ + bool sem_up = false; + unsigned long flags = 0; + + spin_lock_irqsave(&tsk->spinlock, flags); + if (tsk->up_cnt == 0) { + tsk->up_cnt++; + sem_up = true; + } else if (tsk->up_cnt == 1) { + /* dhd_sched_dpc: dpc is alread up! */ + } else + DBG_THR(("dhd_sched_dpc: unexpected up cnt %d!\n", tsk->up_cnt)); + + spin_unlock_irqrestore(&tsk->spinlock, flags); + + if (sem_up) + up(&tsk->sema); + + return sem_up; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) +#else +#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) +#endif + +#define PROC_START(thread_func, owner, tsk_ctl, flags, name) \ +{ \ + sema_init(&((tsk_ctl)->sema), 0); \ + init_completion(&((tsk_ctl)->completed)); \ + (tsk_ctl)->parent = owner; \ + (tsk_ctl)->proc_name = name; \ + (tsk_ctl)->terminated = FALSE; \ + (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ + (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ + spin_lock_init(&((tsk_ctl)->spinlock)); \ + DBG_THR(("%s(): thread:%s:%lx started\n", __FUNCTION__, \ + (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ +} + +#define PROC_STOP(tsk_ctl) \ +{ \ + (tsk_ctl)->terminated = TRUE; \ + smp_wmb(); \ + up(&((tsk_ctl)->sema)); \ + wait_for_completion(&((tsk_ctl)->completed)); \ + DBG_THR(("%s(): thread:%s:%lx terminated OK\n", __FUNCTION__, \ + (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ + (tsk_ctl)->thr_pid = -1; \ +} + +/* ----------------------- */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) +#define KILL_PROC(nr, sig) \ +{ \ +struct task_struct *tsk; \ +struct pid *pid; \ +pid = find_get_pid((pid_t)nr); \ +tsk = pid_task(pid, PIDTYPE_PID); \ +if (tsk) send_sig(sig, tsk, 1); \ +} +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(2, 6, 30)) +#define KILL_PROC(pid, sig) \ +{ \ + struct task_struct *tsk; \ + tsk = find_task_by_vpid(pid); \ + if (tsk) send_sig(sig, tsk, 1); \ +} +#else +#define KILL_PROC(pid, sig) \ +{ \ + kill_proc(pid, sig, 1); \ +} +#endif +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#include +#include +#else +#include + +#define __wait_event_interruptible_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ + __ret; \ +}) + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ + +/* +For < 2.6.24, wl creates its own netdev but doesn't +align the priv area like the genuine alloc_netdev(). +Since netdev_priv() always gives us the aligned address, it will +not match our unaligned address for < 2.6.24 +*/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) +#define DEV_PRIV(dev) (dev->priv) +#else +#define DEV_PRIV(dev) netdev_priv(dev) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +#define WL_ISR(i, d, p) wl_isr((i), (d)) +#else +#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) +#endif /* < 2.6.20 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +#define netdev_priv(dev) dev->priv +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) +#define CAN_SLEEP() ((!in_atomic() && !irqs_disabled())) +#else +#define CAN_SLEEP() (FALSE) +#endif + +#define KMALLOC_FLAG (CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define RANDOM32 prandom_u32 +#else +#define RANDOM32 random32 +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define SRANDOM32(entropy) prandom_seed(entropy) +#else +#define SRANDOM32(entropy) srandom32(entropy) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ + +/* + * Overide latest kfifo functions with + * older version to work on older kernels + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) +#define kfifo_in_spinlocked(a, b, c, d) kfifo_put(a, (u8 *)b, c) +#define kfifo_out_spinlocked(a, b, c, d) kfifo_get(a, (u8 *)b, c) +#define kfifo_esize(a) 1 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)) && !defined(WL_COMPAT_WIRELESS) +#define kfifo_in_spinlocked(a, b, c, d) kfifo_in_locked(a, b, c, d) +#define kfifo_out_spinlocked(a, b, c, d) kfifo_out_locked(a, b, c, d) +#define kfifo_esize(a) 1 +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ + +#endif /* _linuxver_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h b/drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h new file mode 100644 index 000000000000..ab6668097ec0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h @@ -0,0 +1,77 @@ +/* + * Command line options parser. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: miniopt.h 241182 2011-02-17 21:50:03Z $ + */ + + +#ifndef MINI_OPT_H +#define MINI_OPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---- Include Files ---------------------------------------------------- */ +/* ---- Constants and Types ---------------------------------------------- */ + +#define MINIOPT_MAXKEY 128 /* Max options */ +typedef struct miniopt { + + /* These are persistent after miniopt_init() */ + const char* name; /* name for prompt in error strings */ + const char* flags; /* option chars that take no args */ + bool longflags; /* long options may be flags */ + bool opt_end; /* at end of options (passed a "--") */ + + /* These are per-call to miniopt() */ + + int consumed; /* number of argv entries cosumed in + * the most recent call to miniopt() + */ + bool positional; + bool good_int; /* 'val' member is the result of a sucessful + * strtol conversion of the option value + */ + char opt; + char key[MINIOPT_MAXKEY]; + char* valstr; /* positional param, or value for the option, + * or null if the option had + * no accompanying value + */ + uint uval; /* strtol translation of valstr */ + int val; /* strtol translation of valstr */ +} miniopt_t; + +void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); +int miniopt(miniopt_t *t, char **argv); + + +/* ---- Variable Externs ------------------------------------------------- */ +/* ---- Function Prototypes ---------------------------------------------- */ + + +#ifdef __cplusplus + } +#endif + +#endif /* MINI_OPT_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h b/drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h new file mode 100644 index 000000000000..6119bbba09a8 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h @@ -0,0 +1,77 @@ +/* + * Trace messages sent over HBUS + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: msgtrace.h 369735 2012-11-19 22:50:22Z $ + */ + +#ifndef _MSGTRACE_H +#define _MSGTRACE_H + +#ifndef _TYPEDEFS_H_ +#include +#endif + + +/* This marks the start of a packed structure section. */ +#include + +#define MSGTRACE_VERSION 1 + +/* Message trace header */ +typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { + uint8 version; + uint8 trace_type; +#define MSGTRACE_HDR_TYPE_MSG 0 +#define MSGTRACE_HDR_TYPE_LOG 1 + uint16 len; /* Len of the trace */ + uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost + * because of DMA error or a bus reset (ex: SDIO Func2) + */ + /* Msgtrace type only */ + uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */ + uint32 discarded_printf; /* Number of discarded printf because of trace overflow */ +} BWL_POST_PACKED_STRUCT msgtrace_hdr_t; + +#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t) + +/* The hbus driver generates traces when sending a trace message. This causes endless traces. + * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put. + * This prevents endless traces but generates hasardous lost of traces only in bus device code. + * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing + * hbus error traces. hbus error trace should not generates endless traces. + */ +extern bool msgtrace_hbus_trace; + +typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, + uint16 hdrlen, uint8 *buf, uint16 buflen); +extern void msgtrace_start(void); +extern void msgtrace_stop(void); +extern int msgtrace_sent(void); +extern void msgtrace_put(char *buf, int count); +extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send); +extern bool msgtrace_event_enabled(void); + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _MSGTRACE_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/osl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/osl.h new file mode 100644 index 000000000000..9a1f8a5960b0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/osl.h @@ -0,0 +1,142 @@ +/* + * OS Abstraction Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: osl.h 424562 2013-09-18 10:57:30Z $ + */ + +#ifndef _osl_h_ +#define _osl_h_ + +/* osl handle type forward declaration */ +typedef struct osl_info osl_t; +typedef struct osl_dmainfo osldma_t; + +#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ + +/* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ +typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); + +/* Drivers use REGOPSSET() to register register read/write funcitons */ +typedef unsigned int (*osl_rreg_fn_t)(void *ctx, volatile void *reg, unsigned int size); +typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, unsigned int size); + + +#include + +#ifndef PKTDBG_TRACE +#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) +#endif + +#define PKTCTFMAP(osh, p) BCM_REFERENCE(osh) + +/* -------------------------------------------------------------------------- +** Register manipulation macros. +*/ + +#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) + +#ifndef AND_REG +#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) +#endif /* !AND_REG */ + +#ifndef OR_REG +#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) +#endif /* !OR_REG */ + +#if !defined(OSL_SYSUPTIME) +#define OSL_SYSUPTIME() (0) +#define OSL_SYSUPTIME_SUPPORT FALSE +#else +#define OSL_SYSUPTIME_SUPPORT TRUE +#endif /* OSL_SYSUPTIME */ + +#if !defined(PKTC) && !defined(PKTC_DONGLE) +#define PKTCGETATTR(skb) (0) +#define PKTCSETATTR(skb, f, p, b) BCM_REFERENCE(skb) +#define PKTCCLRATTR(skb) BCM_REFERENCE(skb) +#define PKTCCNT(skb) (1) +#define PKTCLEN(skb) PKTLEN(NULL, skb) +#define PKTCGETFLAGS(skb) (0) +#define PKTCSETFLAGS(skb, f) BCM_REFERENCE(skb) +#define PKTCCLRFLAGS(skb) BCM_REFERENCE(skb) +#define PKTCFLAGS(skb) (0) +#define PKTCSETCNT(skb, c) BCM_REFERENCE(skb) +#define PKTCINCRCNT(skb) BCM_REFERENCE(skb) +#define PKTCADDCNT(skb, c) BCM_REFERENCE(skb) +#define PKTCSETLEN(skb, l) BCM_REFERENCE(skb) +#define PKTCADDLEN(skb, l) BCM_REFERENCE(skb) +#define PKTCSETFLAG(skb, fb) BCM_REFERENCE(skb) +#define PKTCCLRFLAG(skb, fb) BCM_REFERENCE(skb) +#define PKTCLINK(skb) NULL +#define PKTSETCLINK(skb, x) BCM_REFERENCE(skb) +#define FOREACH_CHAINED_PKT(skb, nskb) \ + for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) +#define PKTCFREE PKTFREE +#define PKTCENQTAIL(h, t, p) \ +do { \ + if ((t) == NULL) { \ + (h) = (t) = (p); \ + } \ +} while (0) +#endif /* !linux || !PKTC */ + +#if !defined(HNDCTF) && !defined(PKTC_TX_DONGLE) +#define PKTSETCHAINED(osh, skb) BCM_REFERENCE(osh) +#define PKTCLRCHAINED(osh, skb) BCM_REFERENCE(osh) +#define PKTISCHAINED(skb) FALSE +#endif + +/* Lbuf with fraglist */ +#define PKTFRAGPKTID(osh, lb) (0) +#define PKTSETFRAGPKTID(osh, lb, id) BCM_REFERENCE(osh) +#define PKTFRAGTOTNUM(osh, lb) (0) +#define PKTSETFRAGTOTNUM(osh, lb, tot) BCM_REFERENCE(osh) +#define PKTFRAGTOTLEN(osh, lb) (0) +#define PKTSETFRAGTOTLEN(osh, lb, len) BCM_REFERENCE(osh) +#define PKTFRAGIFINDEX(osh, lb) (0) +#define PKTSETFRAGIFINDEX(osh, lb, idx) BCM_REFERENCE(osh) + +/* in rx path, reuse totlen as used len */ +#define PKTFRAGUSEDLEN(osh, lb) (0) +#define PKTSETFRAGUSEDLEN(osh, lb, len) BCM_REFERENCE(osh) + +#define PKTFRAGLEN(osh, lb, ix) (0) +#define PKTSETFRAGLEN(osh, lb, ix, len) BCM_REFERENCE(osh) +#define PKTFRAGDATA_LO(osh, lb, ix) (0) +#define PKTSETFRAGDATA_LO(osh, lb, ix, addr) BCM_REFERENCE(osh) +#define PKTFRAGDATA_HI(osh, lb, ix) (0) +#define PKTSETFRAGDATA_HI(osh, lb, ix, addr) BCM_REFERENCE(osh) + +/* RX FRAG */ +#define PKTISRXFRAG(osh, lb) (0) +#define PKTSETRXFRAG(osh, lb) BCM_REFERENCE(osh) +#define PKTRESETRXFRAG(osh, lb) BCM_REFERENCE(osh) + +/* TX FRAG */ +#define PKTISTXFRAG(osh, lb) (0) +#define PKTSETTXFRAG(osh, lb) BCM_REFERENCE(osh) + +#define PKTISFRAG(osh, lb) (0) +#define PKTFRAGISCHAINED(osh, i) (0) + +#endif /* _osl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h new file mode 100644 index 000000000000..27e39b53e9eb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h @@ -0,0 +1,59 @@ +/* + * Declare directives for structure packing. No padding will be provided + * between the members of packed structures, and therefore, there is no + * guarantee that structure members will be aligned. + * + * Declaring packed structures is compiler specific. In order to handle all + * cases, packed structures should be delared as: + * + * #include + * + * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { + * some_struct_members; + * } BWL_POST_PACKED_STRUCT foobar_t; + * + * #include + * + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: packed_section_end.h 241182 2011-02-17 21:50:03Z $ + */ + + +/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h + * and undefined in packed_section_end.h. If it is NOT defined at this + * point, then there is a missing include of packed_section_start.h. + */ +#ifdef BWL_PACKED_SECTION + #undef BWL_PACKED_SECTION +#else + #error "BWL_PACKED_SECTION is NOT defined!" +#endif + + + + +/* Compiler-specific directives for structure packing are declared in + * packed_section_start.h. This marks the end of the structure packing section, + * so, undef them here. + */ +#undef BWL_PRE_PACKED_STRUCT +#undef BWL_POST_PACKED_STRUCT diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h new file mode 100644 index 000000000000..61c14a69401e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h @@ -0,0 +1,63 @@ +/* + * Declare directives for structure packing. No padding will be provided + * between the members of packed structures, and therefore, there is no + * guarantee that structure members will be aligned. + * + * Declaring packed structures is compiler specific. In order to handle all + * cases, packed structures should be delared as: + * + * #include + * + * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { + * some_struct_members; + * } BWL_POST_PACKED_STRUCT foobar_t; + * + * #include + * + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: packed_section_start.h 286783 2011-09-29 06:18:57Z $ + */ + + +/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h + * and undefined in packed_section_end.h. If it is already defined at this + * point, then there is a missing include of packed_section_end.h. + */ +#ifdef BWL_PACKED_SECTION + #error "BWL_PACKED_SECTION is already defined!" +#else + #define BWL_PACKED_SECTION +#endif + + + + +/* Declare compiler-specific directives for structure packing. */ +#if defined(__GNUC__) || defined(__lint) + #define BWL_PRE_PACKED_STRUCT + #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) +#elif defined(__CC_ARM) + #define BWL_PRE_PACKED_STRUCT __packed + #define BWL_POST_PACKED_STRUCT +#else + #error "Unknown compiler!" +#endif diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h b/drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h new file mode 100644 index 000000000000..99ebf063f345 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h @@ -0,0 +1,101 @@ +/* + * pcicfg.h: PCI configuration constants and structures. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: pcicfg.h 413666 2013-07-20 01:16:40Z $ + */ + +#ifndef _h_pcicfg_ +#define _h_pcicfg_ + +/* A structure for the config registers is nice, but in most + * systems the config space is not memory mapped, so we need + * field offsetts. :-( + */ +#define PCI_CFG_VID 0 +#define PCI_CFG_DID 2 +#define PCI_CFG_CMD 4 +#define PCI_CFG_STAT 6 +#define PCI_CFG_REV 8 +#define PCI_CFG_PROGIF 9 +#define PCI_CFG_SUBCL 0xa +#define PCI_CFG_BASECL 0xb +#define PCI_CFG_CLSZ 0xc +#define PCI_CFG_LATTIM 0xd +#define PCI_CFG_HDR 0xe +#define PCI_CFG_BIST 0xf +#define PCI_CFG_BAR0 0x10 +#define PCI_CFG_BAR1 0x14 +#define PCI_CFG_BAR2 0x18 +#define PCI_CFG_BAR3 0x1c +#define PCI_CFG_BAR4 0x20 +#define PCI_CFG_BAR5 0x24 +#define PCI_CFG_CIS 0x28 +#define PCI_CFG_SVID 0x2c +#define PCI_CFG_SSID 0x2e +#define PCI_CFG_ROMBAR 0x30 +#define PCI_CFG_CAPPTR 0x34 +#define PCI_CFG_INT 0x3c +#define PCI_CFG_PIN 0x3d +#define PCI_CFG_MINGNT 0x3e +#define PCI_CFG_MAXLAT 0x3f +#define PCI_CFG_DEVCTRL 0xd8 +#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */ +#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */ +#define PCI_SPROM_CONTROL 0x88 /* sprom property control */ +#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */ +#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */ +#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */ +#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */ +#define PCI_BACKPLANE_ADDR 0xa0 /* address an arbitrary location on the system backplane */ +#define PCI_BACKPLANE_DATA 0xa4 /* data at the location specified by above address */ +#define PCI_CLK_CTL_ST 0xa8 /* pci config space clock control/status (>=rev14) */ +#define PCI_BAR0_WIN2 0xac /* backplane addres space accessed by second 4KB of BAR0 */ +#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */ +#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */ +#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */ + +#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) /* bar0 + 2K accesses sprom shadow (in pci core) */ +#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */ +#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */ +#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) /* pci core SB registers are at the end of the + * 8KB window, so their address is the "regular" + * address plus 4K + */ +/* + * PCIE GEN2 changed some of the above locations for + * Bar0WrapperBase, SecondaryBAR0Window and SecondaryBAR0WrapperBase + * BAR0 maps 32K of register space +*/ +#define PCIE2_BAR0_WIN2 0x70 /* backplane addres space accessed by second 4KB of BAR0 */ +#define PCIE2_BAR0_CORE2_WIN 0x74 /* backplane addres space accessed by second 4KB of BAR0 */ +#define PCIE2_BAR0_CORE2_WIN2 0x78 /* backplane addres space accessed by second 4KB of BAR0 */ + +#define PCI_BAR0_WINSZ (16 * 1024) /* bar0 window size Match with corerev 13 */ +/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ +#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) /* bar0 + 8K accesses pci/pcie core registers */ +#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) /* bar0 + 12K accesses chipc core registers */ +#define PCI_16KBB0_WINSZ (16 * 1024) /* bar0 window size */ + + +#define PCI_CONFIG_SPACE_SIZE 256 +#endif /* _h_pcicfg_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h new file mode 100644 index 000000000000..e18cc6ef19d0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h @@ -0,0 +1,3814 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental types and constants relating to 802.11 + * + * $Id: 802.11.h 444070 2013-12-18 13:20:12Z $ + */ + +#ifndef _802_11_H_ +#define _802_11_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +#ifndef _NET_ETHERNET_H_ +#include +#endif + +#include + +/* This marks the start of a packed structure section. */ +#include + + +#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */ + +/* Generic 802.11 frame constants */ +#define DOT11_A3_HDR_LEN 24 /* d11 header length with A3 */ +#define DOT11_A4_HDR_LEN 30 /* d11 header length with A4 */ +#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN /* MAC header length */ +#define DOT11_FCS_LEN 4 /* d11 FCS length */ +#define DOT11_ICV_LEN 4 /* d11 ICV length */ +#define DOT11_ICV_AES_LEN 8 /* d11 ICV/AES length */ +#define DOT11_QOS_LEN 2 /* d11 QoS length */ +#define DOT11_HTC_LEN 4 /* d11 HT Control field length */ + +#define DOT11_KEY_INDEX_SHIFT 6 /* d11 key index shift */ +#define DOT11_IV_LEN 4 /* d11 IV length */ +#define DOT11_IV_TKIP_LEN 8 /* d11 IV TKIP length */ +#define DOT11_IV_AES_OCB_LEN 4 /* d11 IV/AES/OCB length */ +#define DOT11_IV_AES_CCM_LEN 8 /* d11 IV/AES/CCM length */ +#define DOT11_IV_MAX_LEN 8 /* maximum iv len for any encryption */ + +/* Includes MIC */ +#define DOT11_MAX_MPDU_BODY_LEN 2304 /* max MPDU body length */ +/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */ +#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ + DOT11_QOS_LEN + \ + DOT11_IV_AES_CCM_LEN + \ + DOT11_MAX_MPDU_BODY_LEN + \ + DOT11_ICV_LEN + \ + DOT11_FCS_LEN) /* d11 max MPDU length */ + +#define DOT11_MAX_SSID_LEN 32 /* d11 max ssid length */ + +/* dot11RTSThreshold */ +#define DOT11_DEFAULT_RTS_LEN 2347 /* d11 default RTS length */ +#define DOT11_MAX_RTS_LEN 2347 /* d11 max RTS length */ + +/* dot11FragmentationThreshold */ +#define DOT11_MIN_FRAG_LEN 256 /* d11 min fragmentation length */ +#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength + * of the attached PHY + */ +#define DOT11_DEFAULT_FRAG_LEN 2346 /* d11 default fragmentation length */ + +/* dot11BeaconPeriod */ +#define DOT11_MIN_BEACON_PERIOD 1 /* d11 min beacon period */ +#define DOT11_MAX_BEACON_PERIOD 0xFFFF /* d11 max beacon period */ + +/* dot11DTIMPeriod */ +#define DOT11_MIN_DTIM_PERIOD 1 /* d11 min DTIM period */ +#define DOT11_MAX_DTIM_PERIOD 0xFF /* d11 max DTIM period */ + +/* 802.2 LLC/SNAP header used by 802.11 per 802.1H */ +#define DOT11_LLC_SNAP_HDR_LEN 8 /* d11 LLC/SNAP header length */ +#define DOT11_OUI_LEN 3 /* d11 OUI length */ +BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 type; /* ethertype */ +} BWL_POST_PACKED_STRUCT; + +/* RFC1042 header used by 802.11 per 802.1H */ +#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) /* RCF1042 header length */ + +/* Generic 802.11 MAC header */ +/* + * N.B.: This struct reflects the full 4 address 802.11 MAC header. + * The fields are defined such that the shorter 1, 2, and 3 + * address headers just use the first k fields. + */ +BWL_PRE_PACKED_STRUCT struct dot11_header { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr a1; /* address 1 */ + struct ether_addr a2; /* address 2 */ + struct ether_addr a3; /* address 3 */ + uint16 seq; /* sequence control */ + struct ether_addr a4; /* address 4 */ +} BWL_POST_PACKED_STRUCT; + +/* Control frames */ + +BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr ta; /* transmitter address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_RTS_LEN 16 /* d11 RTS frame length */ + +BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_CTS_LEN 10 /* d11 CTS frame length */ + +BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACK_LEN 10 /* d11 ACK frame length */ + +BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { + uint16 fc; /* frame control */ + uint16 durid; /* AID */ + struct ether_addr bssid; /* receiver address, STA in AP */ + struct ether_addr ta; /* transmitter address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_PS_POLL_LEN 16 /* d11 PS poll frame length */ + +BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr bssid; /* transmitter address, STA in AP */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */ + +/* RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling +* category+OUI+vendor specific content ( this can be variable) +*/ +BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1040]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; + +/* generic vender specific action frame with variable length */ +BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; + +#define DOT11_ACTION_VS_HDR_LEN 6 + +#define BCM_ACTION_OUI_BYTE0 0x00 +#define BCM_ACTION_OUI_BYTE1 0x90 +#define BCM_ACTION_OUI_BYTE2 0x4c + +/* BA/BAR Control parameters */ +#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */ +#define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */ +#define DOT11_BA_CTL_POLICY_MASK 0x0001 /* ack policy mask */ + +#define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */ +#define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */ + +#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */ +#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */ + +#define DOT11_BA_CTL_TID_MASK 0xF000 /* tid mask */ +#define DOT11_BA_CTL_TID_SHIFT 12 /* tid shift */ + +/* control frame header (BA/BAR) */ +BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr ta; /* transmitter address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */ + +/* BAR frame payload */ +BWL_PRE_PACKED_STRUCT struct dot11_bar { + uint16 bar_control; /* BAR Control */ + uint16 seqnum; /* Starting Sequence control */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_BAR_LEN 4 /* BAR frame payload length */ + +#define DOT11_BA_BITMAP_LEN 128 /* bitmap length */ +#define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */ +/* BA frame payload */ +BWL_PRE_PACKED_STRUCT struct dot11_ba { + uint16 ba_control; /* BA Control */ + uint16 seqnum; /* Starting Sequence control */ + uint8 bitmap[DOT11_BA_BITMAP_LEN]; /* Block Ack Bitmap */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_BA_LEN 4 /* BA frame payload len (wo bitmap) */ + +/* Management frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_management_header { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr da; /* receiver address */ + struct ether_addr sa; /* transmitter address */ + struct ether_addr bssid; /* BSS ID */ + uint16 seq; /* sequence control */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_MGMT_HDR_LEN 24 /* d11 management header length */ + +/* Management frame payloads */ + +BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { + uint32 timestamp[2]; + uint16 beacon_interval; + uint16 capability; +} BWL_POST_PACKED_STRUCT; +#define DOT11_BCN_PRB_LEN 12 /* 802.11 beacon/probe frame fixed length */ +#define DOT11_BCN_PRB_FIXED_LEN 12 /* 802.11 beacon/probe frame fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_auth { + uint16 alg; /* algorithm */ + uint16 seq; /* sequence control */ + uint16 status; /* status code */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge IE */ + +BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { + uint16 capability; /* capability information */ + uint16 listen; /* listen interval */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_ASSOC_REQ_FIXED_LEN 4 /* length of assoc frame without info elts */ + +BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { + uint16 capability; /* capability information */ + uint16 listen; /* listen interval */ + struct ether_addr ap; /* Current AP address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_REASSOC_REQ_FIXED_LEN 10 /* length of assoc frame without info elts */ + +BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { + uint16 capability; /* capability information */ + uint16 status; /* status code */ + uint16 aid; /* association ID */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_ASSOC_RESP_FIXED_LEN 6 /* length of assoc resp frame without info elts */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_measure { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { + uint8 category; + uint8 action; + uint8 ch_width; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { + uint8 category; + uint8 action; + uint8 control; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { + uint8 category; + uint8 action; + uint16 id; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { + uint8 category; + uint8 action; + uint8 mode; +} BWL_POST_PACKED_STRUCT; + +#define SM_PWRSAVE_ENABLE 1 +#define SM_PWRSAVE_MODE 2 + +/* ************* 802.11h related definitions. ************* */ +BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { + uint8 id; + uint8 len; + uint8 power; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_power_cnst dot11_power_cnst_t; + +BWL_PRE_PACKED_STRUCT struct dot11_power_cap { + uint8 min; + uint8 max; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_power_cap dot11_power_cap_t; + +BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { + uint8 id; + uint8 len; + uint8 tx_pwr; + uint8 margin; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tpc_rep dot11_tpc_rep_t; +#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */ + +BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { + uint8 id; + uint8 len; + uint8 first_channel; + uint8 num_channels; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_supp_channels dot11_supp_channels_t; + +/* Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband + * offset for 40MHz operation. The possible 3 values are: + * 1 = above control channel + * 3 = below control channel + * 0 = no extension channel + */ +BWL_PRE_PACKED_STRUCT struct dot11_extch { + uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ + uint8 len; /* IE length */ + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extch dot11_extch_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; + uint8 type; /* type inidicates what follows */ + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; + +#define BRCM_EXTCH_IE_LEN 5 +#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ +#define DOT11_EXTCH_IE_LEN 1 +#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ +#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ +#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ +#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { + uint8 category; + uint8 action; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACTION_FRMHDR_LEN 2 + +/* CSA IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { + uint8 id; /* id DOT11_MNG_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 mode; /* mode 0 or 1 */ + uint8 channel; /* channel switch to */ + uint8 count; /* number of beacons before switching */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch dot11_chan_switch_ie_t; + +#define DOT11_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ +/* CSA mode - 802.11h-2003 $7.3.2.20 */ +#define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */ +#define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { + uint8 category; + uint8 action; + dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */ + dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */ +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_csa_body { + uint8 mode; /* mode 0 or 1 */ + uint8 reg; /* regulatory class */ + uint8 channel; /* channel switch to */ + uint8 count; /* number of beacons before switching */ +} BWL_POST_PACKED_STRUCT; + +/* 11n Extended Channel Switch IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { + uint8 id; /* id DOT11_MNG_EXT_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + struct dot11_csa_body b; /* body of the ie */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ext_csa dot11_ext_csa_ie_t; +#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { + uint8 category; + uint8 action; + dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { + uint8 category; + uint8 action; + struct dot11_csa_body b; /* body of the ie */ +} BWL_POST_PACKED_STRUCT; + +/* Wide Bandwidth Channel Switch IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 channel_width; /* new channel width */ + uint8 center_frequency_segment_0; /* center frequency segment 0 */ + uint8 center_frequency_segment_1; /* center frequency segment 1 */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; + +#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ + +/* Channel Switch Wrapper IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; + +/* VHT Transmit Power Envelope IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 transmit_power_info; + uint8 local_max_transmit_power_20; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; + +/* vht transmit power envelope IE length depends on channel width */ +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_40MHZ 1 +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_80MHZ 2 +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_160MHZ 3 + +BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { + uint8 id; + uint8 len; + uint8 info; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_coex dot11_obss_coex_t; +#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */ + +#define DOT11_OBSS_COEX_INFO_REQ 0x01 +#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 +#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 + +BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { + uint8 id; + uint8 len; + uint8 regclass; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; +#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */ + +BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { + uint8 id; + uint8 len; + uint8 cap[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extcap_ie dot11_extcap_ie_t; + +#define DOT11_EXTCAP_LEN_MAX 8 + +#define DOT11_EXTCAP_LEN_COEX 1 +#define DOT11_EXTCAP_LEN_BT 3 +#define DOT11_EXTCAP_LEN_IW 4 +#define DOT11_EXTCAP_LEN_SI 6 + +#define DOT11_EXTCAP_LEN_TDLS 5 +#define DOT11_11AC_EXTCAP_LEN_TDLS 8 + +#define DOT11_EXTCAP_LEN_FMS 2 +#define DOT11_EXTCAP_LEN_PROXY_ARP 2 +#define DOT11_EXTCAP_LEN_TFS 3 +#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 +#define DOT11_EXTCAP_LEN_TIMBC 3 +#define DOT11_EXTCAP_LEN_BSSTRANS 3 +#define DOT11_EXTCAP_LEN_DMS 4 +#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 +#define DOT11_EXTCAP_LEN_TDLS_WBW 8 +#define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8 + +BWL_PRE_PACKED_STRUCT struct dot11_extcap { + uint8 extcap[DOT11_EXTCAP_LEN_MAX]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extcap dot11_extcap_t; + +/* TDLS Capabilities */ +#define DOT11_TDLS_CAP_TDLS 37 /* TDLS support */ +#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ +#define DOT11_TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ +#define DOT11_TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ +#define DOT11_TDLS_CAP_PROH 38 /* TDLS prohibited */ +#define DOT11_TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ +#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 /* TDLS Wider Band-Width */ + +#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ + +/* 802.11h/802.11k Measurement Request/Report IEs */ +/* Measurement Type field */ +#define DOT11_MEASURE_TYPE_BASIC 0 /* d11 measurement basic type */ +#define DOT11_MEASURE_TYPE_CCA 1 /* d11 measurement CCA type */ +#define DOT11_MEASURE_TYPE_RPI 2 /* d11 measurement RPI type */ +#define DOT11_MEASURE_TYPE_CHLOAD 3 /* d11 measurement Channel Load type */ +#define DOT11_MEASURE_TYPE_NOISE 4 /* d11 measurement Noise Histogram type */ +#define DOT11_MEASURE_TYPE_BEACON 5 /* d11 measurement Beacon type */ +#define DOT11_MEASURE_TYPE_FRAME 6 /* d11 measurement Frame type */ +#define DOT11_MEASURE_TYPE_STAT 7 /* d11 measurement STA Statistics type */ +#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ +#define DOT11_MEASURE_TYPE_TXSTREAM 9 /* d11 measurement TX Stream type */ +#define DOT11_MEASURE_TYPE_PAUSE 255 /* d11 measurement pause type */ + +/* Measurement Request Modes */ +#define DOT11_MEASURE_MODE_PARALLEL (1<<0) /* d11 measurement parallel */ +#define DOT11_MEASURE_MODE_ENABLE (1<<1) /* d11 measurement enable */ +#define DOT11_MEASURE_MODE_REQUEST (1<<2) /* d11 measurement request */ +#define DOT11_MEASURE_MODE_REPORT (1<<3) /* d11 measurement report */ +#define DOT11_MEASURE_MODE_DUR (1<<4) /* d11 measurement dur mandatory */ +/* Measurement Report Modes */ +#define DOT11_MEASURE_MODE_LATE (1<<0) /* d11 measurement late */ +#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) /* d11 measurement incapable */ +#define DOT11_MEASURE_MODE_REFUSED (1<<2) /* d11 measurement refuse */ +/* Basic Measurement Map bits */ +#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) /* d11 measurement basic map BSS */ +#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) /* d11 measurement map OFDM */ +#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) /* d11 measurement map unknown */ +#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) /* d11 measurement map radar */ +#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) /* d11 measurement map unmeasuremnt */ + +BWL_PRE_PACKED_STRUCT struct dot11_meas_req { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 channel; + uint8 start_time[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_req dot11_meas_req_t; +#define DOT11_MNG_IE_MREQ_LEN 14 /* d11 measurement request IE length */ +/* length of Measure Request IE data not including variable len */ +#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 /* d11 measurement request IE fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + BWL_PRE_PACKED_STRUCT union + { + BWL_PRE_PACKED_STRUCT struct { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; + } BWL_POST_PACKED_STRUCT basic; + uint8 data[1]; + } BWL_POST_PACKED_STRUCT rep; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_rep dot11_meas_rep_t; + +/* length of Measure Report IE data not including variable len */ +#define DOT11_MNG_IE_MREP_FIXED_LEN 3 /* d11 measurement response IE fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; +#define DOT11_MEASURE_BASIC_REP_LEN 12 /* d11 measurement basic report length */ + +BWL_PRE_PACKED_STRUCT struct dot11_quiet { + uint8 id; + uint8 len; + uint8 count; /* TBTTs until beacon interval in quiet starts */ + uint8 period; /* Beacon intervals between periodic quiet periods ? */ + uint16 duration; /* Length of quiet period, in TU's */ + uint16 offset; /* TU's offset from TBTT in Count field */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_quiet dot11_quiet_t; + +BWL_PRE_PACKED_STRUCT struct chan_map_tuple { + uint8 channel; + uint8 map; +} BWL_POST_PACKED_STRUCT; +typedef struct chan_map_tuple chan_map_tuple_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { + uint8 id; + uint8 len; + uint8 eaddr[ETHER_ADDR_LEN]; + uint8 interval; + chan_map_tuple_t map[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; + +/* WME Elements */ +#define WME_OUI "\x00\x50\xf2" /* WME OUI */ +#define WME_OUI_LEN 3 +#define WME_OUI_TYPE 2 /* WME type */ +#define WME_TYPE 2 /* WME type, deprecated */ +#define WME_SUBTYPE_IE 0 /* Information Element */ +#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ +#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ +#define WME_VER 1 /* WME version */ + +/* WME Access Category Indices (ACIs) */ +#define AC_BE 0 /* Best Effort */ +#define AC_BK 1 /* Background */ +#define AC_VI 2 /* Video */ +#define AC_VO 3 /* Voice */ +#define AC_COUNT 4 /* number of ACs */ + +typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */ + +#define AC_BITMAP_NONE 0x0 /* No ACs */ +#define AC_BITMAP_ALL 0xf /* All ACs */ +#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) +#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) +#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) + +/* WME Information Element (IE) */ +BWL_PRE_PACKED_STRUCT struct wme_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_ie wme_ie_t; +#define WME_IE_LEN 7 /* WME IE length */ + +BWL_PRE_PACKED_STRUCT struct edcf_acparam { + uint8 ACI; + uint8 ECW; + uint16 TXOP; /* stored in network order (ls octet first) */ +} BWL_POST_PACKED_STRUCT; +typedef struct edcf_acparam edcf_acparam_t; + +/* WME Parameter Element (PE) */ +BWL_PRE_PACKED_STRUCT struct wme_param_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_param_ie wme_param_ie_t; +#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ + +/* QoS Info field for IE as sent from AP */ +#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ +#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ +#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ +#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ + +/* QoS Info field for IE as sent from STA */ +#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ +#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ +#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ +#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ +#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ +#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ +#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ +#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ +#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ +#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ +#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ +#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ + +/* ACI */ +#define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */ +#define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */ +#define EDCF_AIFSN_MASK 0x0f /* AIFSN mask */ +#define EDCF_ACM_MASK 0x10 /* ACM mask */ +#define EDCF_ACI_MASK 0x60 /* ACI mask */ +#define EDCF_ACI_SHIFT 5 /* ACI shift */ +#define EDCF_AIFSN_SHIFT 12 /* 4 MSB(0xFFF) in ifs_ctl for AC idx */ + +/* ECW */ +#define EDCF_ECW_MIN 0 /* cwmin/cwmax exponent minimum value */ +#define EDCF_ECW_MAX 15 /* cwmin/cwmax exponent maximum value */ +#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) +#define EDCF_ECWMIN_MASK 0x0f /* cwmin exponent form mask */ +#define EDCF_ECWMAX_MASK 0xf0 /* cwmax exponent form mask */ +#define EDCF_ECWMAX_SHIFT 4 /* cwmax exponent form shift */ + +/* TXOP */ +#define EDCF_TXOP_MIN 0 /* TXOP minimum value */ +#define EDCF_TXOP_MAX 65535 /* TXOP maximum value */ +#define EDCF_TXOP2USEC(txop) ((txop) << 5) + +/* Default BE ACI value for non-WME connection STA */ +#define NON_EDCF_AC_BE_ACI_STA 0x02 + +/* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */ +#define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */ +#define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */ +#define EDCF_AC_BE_TXOP_STA 0x0000 /* STA TXOP value for best effort AC */ +#define EDCF_AC_BK_ACI_STA 0x27 /* STA ACI value for background AC */ +#define EDCF_AC_BK_ECW_STA 0xA4 /* STA ECW value for background AC */ +#define EDCF_AC_BK_TXOP_STA 0x0000 /* STA TXOP value for background AC */ +#define EDCF_AC_VI_ACI_STA 0x42 /* STA ACI value for video AC */ +#define EDCF_AC_VI_ECW_STA 0x43 /* STA ECW value for video AC */ +#define EDCF_AC_VI_TXOP_STA 0x005e /* STA TXOP value for video AC */ +#define EDCF_AC_VO_ACI_STA 0x62 /* STA ACI value for audio AC */ +#define EDCF_AC_VO_ECW_STA 0x32 /* STA ECW value for audio AC */ +#define EDCF_AC_VO_TXOP_STA 0x002f /* STA TXOP value for audio AC */ + +/* Default EDCF parameters that AP uses; WMM draft Table 14 */ +#define EDCF_AC_BE_ACI_AP 0x03 /* AP ACI value for best effort AC */ +#define EDCF_AC_BE_ECW_AP 0x64 /* AP ECW value for best effort AC */ +#define EDCF_AC_BE_TXOP_AP 0x0000 /* AP TXOP value for best effort AC */ +#define EDCF_AC_BK_ACI_AP 0x27 /* AP ACI value for background AC */ +#define EDCF_AC_BK_ECW_AP 0xA4 /* AP ECW value for background AC */ +#define EDCF_AC_BK_TXOP_AP 0x0000 /* AP TXOP value for background AC */ +#define EDCF_AC_VI_ACI_AP 0x41 /* AP ACI value for video AC */ +#define EDCF_AC_VI_ECW_AP 0x43 /* AP ECW value for video AC */ +#define EDCF_AC_VI_TXOP_AP 0x005e /* AP TXOP value for video AC */ +#define EDCF_AC_VO_ACI_AP 0x61 /* AP ACI value for audio AC */ +#define EDCF_AC_VO_ECW_AP 0x32 /* AP ECW value for audio AC */ +#define EDCF_AC_VO_TXOP_AP 0x002f /* AP TXOP value for audio AC */ + +/* EDCA Parameter IE */ +BWL_PRE_PACKED_STRUCT struct edca_param_ie { + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} BWL_POST_PACKED_STRUCT; +typedef struct edca_param_ie edca_param_ie_t; +#define EDCA_PARAM_IE_LEN 18 /* EDCA Parameter IE length */ + +/* QoS Capability IE */ +BWL_PRE_PACKED_STRUCT struct qos_cap_ie { + uint8 qosinfo; +} BWL_POST_PACKED_STRUCT; +typedef struct qos_cap_ie qos_cap_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { + uint8 id; /* 11, DOT11_MNG_QBSS_LOAD_ID */ + uint8 length; + uint16 station_count; /* total number of STAs associated */ + uint8 channel_utilization; /* % of time, normalized to 255, QAP sensed medium busy */ + uint16 aac; /* available admission capacity */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; +#define BSS_LOAD_IE_SIZE 7 /* BSS load IE size */ + +/* nom_msdu_size */ +#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */ +#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */ + +/* surplus_bandwidth */ +/* Represented as 3 bits of integer, binary point, 13 bits fraction */ +#define INTEGER_SHIFT 13 /* integer shift */ +#define FRACTION_MASK 0x1FFF /* fraction mask */ + +/* Management Notification Frame */ +BWL_PRE_PACKED_STRUCT struct dot11_management_notification { + uint8 category; /* DOT11_ACTION_NOTIFICATION */ + uint8 action; + uint8 token; + uint8 status; + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */ + +/* Timeout Interval IE */ +BWL_PRE_PACKED_STRUCT struct ti_ie { + uint8 ti_type; + uint32 ti_val; +} BWL_POST_PACKED_STRUCT; +typedef struct ti_ie ti_ie_t; +#define TI_TYPE_REASSOC_DEADLINE 1 +#define TI_TYPE_KEY_LIFETIME 2 + +/* WME Action Codes */ +#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ +#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ +#define WME_DELTS_REQUEST 2 /* WME DELTS request */ + +/* WME Setup Response Status Codes */ +#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ +#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ +#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ + +/* Macro to take a pointer to a beacon or probe response + * body and return the char* pointer to the SSID info element + */ +#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) + +/* Authentication frame payload constants */ +#define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */ +#define DOT11_SHARED_KEY 1 /* d11 shared authentication */ +#define DOT11_FAST_BSS 2 /* d11 fast bss authentication */ +#define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */ + +/* Frame control macros */ +#define FC_PVER_MASK 0x3 /* PVER mask */ +#define FC_PVER_SHIFT 0 /* PVER shift */ +#define FC_TYPE_MASK 0xC /* type mask */ +#define FC_TYPE_SHIFT 2 /* type shift */ +#define FC_SUBTYPE_MASK 0xF0 /* subtype mask */ +#define FC_SUBTYPE_SHIFT 4 /* subtype shift */ +#define FC_TODS 0x100 /* to DS */ +#define FC_TODS_SHIFT 8 /* to DS shift */ +#define FC_FROMDS 0x200 /* from DS */ +#define FC_FROMDS_SHIFT 9 /* from DS shift */ +#define FC_MOREFRAG 0x400 /* more frag. */ +#define FC_MOREFRAG_SHIFT 10 /* more frag. shift */ +#define FC_RETRY 0x800 /* retry */ +#define FC_RETRY_SHIFT 11 /* retry shift */ +#define FC_PM 0x1000 /* PM */ +#define FC_PM_SHIFT 12 /* PM shift */ +#define FC_MOREDATA 0x2000 /* more data */ +#define FC_MOREDATA_SHIFT 13 /* more data shift */ +#define FC_WEP 0x4000 /* WEP */ +#define FC_WEP_SHIFT 14 /* WEP shift */ +#define FC_ORDER 0x8000 /* order */ +#define FC_ORDER_SHIFT 15 /* order shift */ + +/* sequence control macros */ +#define SEQNUM_SHIFT 4 /* seq. number shift */ +#define SEQNUM_MAX 0x1000 /* max seqnum + 1 */ +#define FRAGNUM_MASK 0xF /* frag. number mask */ + +/* Frame Control type/subtype defs */ + +/* FC Types */ +#define FC_TYPE_MNG 0 /* management type */ +#define FC_TYPE_CTL 1 /* control type */ +#define FC_TYPE_DATA 2 /* data type */ + +/* Management Subtypes */ +#define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */ +#define FC_SUBTYPE_ASSOC_RESP 1 /* assoc. response */ +#define FC_SUBTYPE_REASSOC_REQ 2 /* reassoc. request */ +#define FC_SUBTYPE_REASSOC_RESP 3 /* reassoc. response */ +#define FC_SUBTYPE_PROBE_REQ 4 /* probe request */ +#define FC_SUBTYPE_PROBE_RESP 5 /* probe response */ +#define FC_SUBTYPE_BEACON 8 /* beacon */ +#define FC_SUBTYPE_ATIM 9 /* ATIM */ +#define FC_SUBTYPE_DISASSOC 10 /* disassoc. */ +#define FC_SUBTYPE_AUTH 11 /* authentication */ +#define FC_SUBTYPE_DEAUTH 12 /* de-authentication */ +#define FC_SUBTYPE_ACTION 13 /* action */ +#define FC_SUBTYPE_ACTION_NOACK 14 /* action no-ack */ + +/* Control Subtypes */ +#define FC_SUBTYPE_CTL_WRAPPER 7 /* Control Wrapper */ +#define FC_SUBTYPE_BLOCKACK_REQ 8 /* Block Ack Req */ +#define FC_SUBTYPE_BLOCKACK 9 /* Block Ack */ +#define FC_SUBTYPE_PS_POLL 10 /* PS poll */ +#define FC_SUBTYPE_RTS 11 /* RTS */ +#define FC_SUBTYPE_CTS 12 /* CTS */ +#define FC_SUBTYPE_ACK 13 /* ACK */ +#define FC_SUBTYPE_CF_END 14 /* CF-END */ +#define FC_SUBTYPE_CF_END_ACK 15 /* CF-END ACK */ + +/* Data Subtypes */ +#define FC_SUBTYPE_DATA 0 /* Data */ +#define FC_SUBTYPE_DATA_CF_ACK 1 /* Data + CF-ACK */ +#define FC_SUBTYPE_DATA_CF_POLL 2 /* Data + CF-Poll */ +#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 /* Data + CF-Ack + CF-Poll */ +#define FC_SUBTYPE_NULL 4 /* Null */ +#define FC_SUBTYPE_CF_ACK 5 /* CF-Ack */ +#define FC_SUBTYPE_CF_POLL 6 /* CF-Poll */ +#define FC_SUBTYPE_CF_ACK_POLL 7 /* CF-Ack + CF-Poll */ +#define FC_SUBTYPE_QOS_DATA 8 /* QoS Data */ +#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 /* QoS Data + CF-Ack */ +#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 /* QoS Data + CF-Poll */ +#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 /* QoS Data + CF-Ack + CF-Poll */ +#define FC_SUBTYPE_QOS_NULL 12 /* QoS Null */ +#define FC_SUBTYPE_QOS_CF_POLL 14 /* QoS CF-Poll */ +#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 /* QoS CF-Ack + CF-Poll */ + +/* Data Subtype Groups */ +#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) +#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) +#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) +#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) +#define FC_SUBTYPE_ANY_PSPOLL(s) (((s) & 10) != 0) + +/* Type/Subtype Combos */ +#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */ + +#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) /* FC kind */ + +#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) /* Subtype from FC */ +#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) /* Type from FC */ + +#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) /* assoc. request */ +#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) /* assoc. response */ +#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) /* reassoc. request */ +#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) /* reassoc. response */ +#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) /* probe request */ +#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) /* probe response */ +#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) /* beacon */ +#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) /* disassoc */ +#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) /* authentication */ +#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) /* deauthentication */ +#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) /* action */ +#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) /* action no-ack */ + +#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) /* Control Wrapper */ +#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) /* Block Ack Req */ +#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) /* Block Ack */ +#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) /* PS poll */ +#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) /* RTS */ +#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) /* CTS */ +#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) /* ACK */ +#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) /* CF-END */ +#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) /* CF-END ACK */ + +#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) /* data */ +#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) /* null data */ +#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) /* data CF ACK */ +#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) /* QoS data */ +#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) /* QoS null */ + +/* QoS Control Field */ + +/* 802.1D Priority */ +#define QOS_PRIO_SHIFT 0 /* QoS priority shift */ +#define QOS_PRIO_MASK 0x0007 /* QoS priority mask */ +#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) /* QoS priority */ + +/* Traffic Identifier */ +#define QOS_TID_SHIFT 0 /* QoS TID shift */ +#define QOS_TID_MASK 0x000f /* QoS TID mask */ +#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) /* QoS TID */ + +/* End of Service Period (U-APSD) */ +#define QOS_EOSP_SHIFT 4 /* QoS End of Service Period shift */ +#define QOS_EOSP_MASK 0x0010 /* QoS End of Service Period mask */ +#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) /* Qos EOSP */ + +/* Ack Policy */ +#define QOS_ACK_NORMAL_ACK 0 /* Normal Ack */ +#define QOS_ACK_NO_ACK 1 /* No Ack (eg mcast) */ +#define QOS_ACK_NO_EXP_ACK 2 /* No Explicit Ack */ +#define QOS_ACK_BLOCK_ACK 3 /* Block Ack */ +#define QOS_ACK_SHIFT 5 /* QoS ACK shift */ +#define QOS_ACK_MASK 0x0060 /* QoS ACK mask */ +#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) /* QoS ACK */ + +/* A-MSDU flag */ +#define QOS_AMSDU_SHIFT 7 /* AMSDU shift */ +#define QOS_AMSDU_MASK 0x0080 /* AMSDU mask */ + +/* Management Frames */ + +/* Management Frame Constants */ + +/* Fixed fields */ +#define DOT11_MNG_AUTH_ALGO_LEN 2 /* d11 management auth. algo. length */ +#define DOT11_MNG_AUTH_SEQ_LEN 2 /* d11 management auth. seq. length */ +#define DOT11_MNG_BEACON_INT_LEN 2 /* d11 management beacon interval length */ +#define DOT11_MNG_CAP_LEN 2 /* d11 management cap. length */ +#define DOT11_MNG_AP_ADDR_LEN 6 /* d11 management AP address length */ +#define DOT11_MNG_LISTEN_INT_LEN 2 /* d11 management listen interval length */ +#define DOT11_MNG_REASON_LEN 2 /* d11 management reason length */ +#define DOT11_MNG_AID_LEN 2 /* d11 management AID length */ +#define DOT11_MNG_STATUS_LEN 2 /* d11 management status length */ +#define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */ + +/* DUR/ID field in assoc resp is 0xc000 | AID */ +#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ + +/* Reason Codes */ +#define DOT11_RC_RESERVED 0 /* d11 RC reserved */ +#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */ +#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */ +#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station + * is leaving (or has left) IBSS or ESS + */ +#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */ +#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle + * all currently associated stations + */ +#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from + * nonauthenticated station + */ +#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from + * nonassociated station + */ +#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is + * leaving (or has left) BSS + */ +#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is not + * authenticated with responding station + */ +#define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */ +#define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */ +/* 12 is unused */ + +/* 32-39 are QSTA specific reasons added in 11e */ +#define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */ +#define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */ +#define DOT11_RC_EXCESSIVE_FRAMES 34 /* excessive number of frames need ack */ +#define DOT11_RC_TX_OUTSIDE_TXOP 35 /* transmitting outside the limits of txop */ +#define DOT11_RC_LEAVING_QBSS 36 /* QSTA is leaving the QBSS (or restting) */ +#define DOT11_RC_BAD_MECHANISM 37 /* does not want to use the mechanism */ +#define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */ +#define DOT11_RC_TIMEOUT 39 /* timeout */ + +#define DOT11_RC_MAX 23 /* Reason codes > 23 are reserved */ + +#define DOT11_RC_TDLS_PEER_UNREACH 25 +#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 + +/* Status Codes */ +#define DOT11_SC_SUCCESS 0 /* Successful */ +#define DOT11_SC_FAILURE 1 /* Unspecified failure */ +#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but alternative */ + /* schedule provided */ +#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */ +#define DOT11_SC_TDLS_SEC_DISABLED 5 /* TDLS Security disabled */ +#define DOT11_SC_LIFETIME_REJ 6 /* Unacceptable lifetime */ +#define DOT11_SC_NOT_SAME_BSS 7 /* Not in same BSS */ +#define DOT11_SC_CAP_MISMATCH 10 /* Cannot support all requested + * capabilities in the Capability + * Information field + */ +#define DOT11_SC_REASSOC_FAIL 11 /* Reassociation denied due to inability + * to confirm that association exists + */ +#define DOT11_SC_ASSOC_FAIL 12 /* Association denied due to reason + * outside the scope of this standard + */ +#define DOT11_SC_AUTH_MISMATCH 13 /* Responding station does not support + * the specified authentication + * algorithm + */ +#define DOT11_SC_AUTH_SEQ 14 /* Received an Authentication frame + * with authentication transaction + * sequence number out of expected + * sequence + */ +#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of + * challenge failure + */ +#define DOT11_SC_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout + * waiting for next frame in sequence + */ +#define DOT11_SC_ASSOC_BUSY_FAIL 17 /* Association denied because AP is + * unable to handle additional + * associated stations + */ +#define DOT11_SC_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting + * station not supporting all of the + * data rates in the BSSBasicRateSet + * parameter + */ +#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting + * station not supporting the Short + * Preamble option + */ +#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting + * station not supporting the PBCC + * Modulation option + */ +#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting + * station not supporting the Channel + * Agility option + */ +#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum + * Management capability is required. + */ +#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info + * in the Power Cap element is + * unacceptable. + */ +#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info + * in the Supported Channel element is + * unacceptable + */ +#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting + * station not supporting the Short Slot + * Time option + */ +#define DOT11_SC_ASSOC_DSSSOFDM_REQUIRED 26 /* Association denied because requesting station + * does not support the DSSS-OFDM option + */ +#define DOT11_SC_ASSOC_HT_REQUIRED 27 /* Association denied because the requesting + * station does not support HT features + */ +#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 /* Association denied due to AP + * being unable to reach the R0 Key Holder + */ +#define DOT11_SC_ASSOC_TRY_LATER 30 /* Association denied temporarily, try again later + */ +#define DOT11_SC_ASSOC_MFP_VIOLATION 31 /* Association denied due to Robust Management + * frame policy violation + */ + +#define DOT11_SC_DECLINED 37 /* request declined */ +#define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ +#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */ +#define DOT11_SC_INVALID_AKMP 43 /* Association denied due to invalid AKMP */ +#define DOT11_SC_INVALID_RSNIE_CAP 45 /* invalid RSN IE capabilities */ +#define DOT11_SC_DLS_NOT_ALLOWED 48 /* DLS is not allowed in the BSS by policy */ +#define DOT11_SC_INVALID_PMKID 53 /* Association denied due to invalid PMKID */ +#define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */ +#define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */ + +#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 /* ad proto not supported */ +#define DOT11_SC_NO_OUTSTAND_REQ 60 /* no outstanding req */ +#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 /* no response from server */ +#define DOT11_SC_TIMEOUT 62 /* timeout */ +#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 /* query rsp too large */ +#define DOT11_SC_SERVER_UNREACHABLE 65 /* server unreachable */ + +#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ +#define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */ +#define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */ +#define DOT11_SC_ASSOC_VHT_REQUIRED 104 /* Association denied because the requesting + * station does not support VHT features. + */ + +#define DOT11_SC_TRANSMIT_FAILURE 79 /* transmission failure */ + +/* Info Elts, length of INFORMATION portion of Info Elts */ +#define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ +#define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */ + +/* TIM Info element has 3 bytes fixed info in INFORMATION field, + * followed by 1 to 251 bytes of Partial Virtual Bitmap + */ +#define DOT11_MNG_TIM_FIXED_LEN 3 /* d11 management TIM fixed length */ +#define DOT11_MNG_TIM_DTIM_COUNT 0 /* d11 management DTIM count */ +#define DOT11_MNG_TIM_DTIM_PERIOD 1 /* d11 management DTIM period */ +#define DOT11_MNG_TIM_BITMAP_CTL 2 /* d11 management TIM BITMAP control */ +#define DOT11_MNG_TIM_PVB 3 /* d11 management TIM PVB */ + +/* TLV defines */ +#define TLV_TAG_OFF 0 /* tag offset */ +#define TLV_LEN_OFF 1 /* length offset */ +#define TLV_HDR_LEN 2 /* header length */ +#define TLV_BODY_OFF 2 /* body offset */ +#define TLV_BODY_LEN_MAX 255 /* max body length */ + +/* Management Frame Information Element IDs */ +#define DOT11_MNG_SSID_ID 0 /* d11 management SSID id */ +#define DOT11_MNG_RATES_ID 1 /* d11 management rates id */ +#define DOT11_MNG_FH_PARMS_ID 2 /* d11 management FH parameter id */ +#define DOT11_MNG_DS_PARMS_ID 3 /* d11 management DS parameter id */ +#define DOT11_MNG_CF_PARMS_ID 4 /* d11 management CF parameter id */ +#define DOT11_MNG_TIM_ID 5 /* d11 management TIM id */ +#define DOT11_MNG_IBSS_PARMS_ID 6 /* d11 management IBSS parameter id */ +#define DOT11_MNG_COUNTRY_ID 7 /* d11 management country id */ +#define DOT11_MNG_HOPPING_PARMS_ID 8 /* d11 management hopping parameter id */ +#define DOT11_MNG_HOPPING_TABLE_ID 9 /* d11 management hopping table id */ +#define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */ +#define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */ +#define DOT11_MNG_EDCA_PARAM_ID 12 /* 11E EDCA Parameter id */ +#define DOT11_MNG_TSPEC_ID 13 /* d11 management TSPEC id */ +#define DOT11_MNG_TCLAS_ID 14 /* d11 management TCLAS id */ +#define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */ +#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */ +#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */ +#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */ +#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */ +#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */ +#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement */ +#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ +#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */ +#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */ +#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */ +#define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */ +#define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */ +#define DOT11_MNG_TCLAS_PROC_ID 44 /* d11 management TCLAS processing id */ +#define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */ +#define DOT11_MNG_QOS_CAP_ID 46 /* 11E QoS Capability id */ +#define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */ +#define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */ +#define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */ +#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */ +#define DOT11_MNG_NEIGHBOR_REP_ID 52 /* 11k & 11v Neighbor report id */ +#define DOT11_MNG_RCPI_ID 53 /* 11k RCPI */ +#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */ +#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */ +#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */ +#define DOT11_MNG_RDE_ID 57 /* 11r RIC Data Element id */ +#define DOT11_MNG_REGCLASS_ID 59 /* d11 management regulatory class id */ +#define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */ +#define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */ +#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */ +#define DOT11_MNG_BSS_AVR_ACCESS_DELAY_ID 63 /* 11k bss average access delay */ +#define DOT11_MNG_ANTENNA_ID 64 /* 11k antenna id */ +#define DOT11_MNG_RSNI_ID 65 /* 11k RSNI id */ +#define DOT11_MNG_MEASUREMENT_PILOT_TX_ID 66 /* 11k measurement pilot tx info id */ +#define DOT11_MNG_BSS_AVAL_ADMISSION_CAP_ID 67 /* 11k bss aval admission cap id */ +#define DOT11_MNG_BSS_AC_ACCESS_DELAY_ID 68 /* 11k bss AC access delay id */ +#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ +#define DOT11_MNG_TIME_ADVERTISE_ID 69 /* 11p time advertisement */ +#define DOT11_MNG_RRM_CAP_ID 70 /* 11k radio measurement capability */ +#define DOT11_MNG_MULTIPLE_BSSID_ID 71 /* 11k multiple BSSID id */ +#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 /* d11 mgmt OBSS Coexistence INFO */ +#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 /* d11 mgmt OBSS Intolerant Channel list */ +#define DOT11_MNG_HT_OBSS_ID 74 /* d11 mgmt OBSS HT info */ +#define DOT11_MNG_MMIE_ID 76 /* d11 mgmt MIC IE */ +#define DOT11_MNG_FMS_DESCR_ID 86 /* 11v FMS descriptor */ +#define DOT11_MNG_FMS_REQ_ID 87 /* 11v FMS request id */ +#define DOT11_MNG_FMS_RESP_ID 88 /* 11v FMS response id */ +#define DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID 90 /* 11v bss max idle id */ +#define DOT11_MNG_TFS_REQUEST_ID 91 /* 11v tfs request id */ +#define DOT11_MNG_TFS_RESPONSE_ID 92 /* 11v tfs response id */ +#define DOT11_MNG_WNM_SLEEP_MODE_ID 93 /* 11v wnm-sleep mode id */ +#define DOT11_MNG_TIMBC_REQ_ID 94 /* 11v TIM broadcast request id */ +#define DOT11_MNG_TIMBC_RESP_ID 95 /* 11v TIM broadcast response id */ +#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */ +#define DOT11_MNG_TIME_ZONE_ID 98 /* 11v time zone */ +#define DOT11_MNG_DMS_REQUEST_ID 99 /* 11v dms request id */ +#define DOT11_MNG_DMS_RESPONSE_ID 100 /* 11v dms response id */ +#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */ +#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */ +#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */ +#define DOT11_MNG_PTI_CONTROL_ID 105 /* 11z TDLS PTI Control IE */ +#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 /* 11z TDLS PU Buffer Status IE */ +#define DOT11_MNG_INTERWORKING_ID 107 /* 11u interworking */ +#define DOT11_MNG_ADVERTISEMENT_ID 108 /* 11u advertisement protocol */ +#define DOT11_MNG_EXP_BW_REQ_ID 109 /* 11u expedited bandwith request */ +#define DOT11_MNG_QOS_MAP_ID 110 /* 11u QoS map set */ +#define DOT11_MNG_ROAM_CONSORT_ID 111 /* 11u roaming consortium */ +#define DOT11_MNG_EMERGCY_ALERT_ID 112 /* 11u emergency alert identifier */ +#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */ +#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */ +#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */ +#define DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID 194 /* Wide BW Channel Switch IE */ +#define DOT11_MNG_VHT_TRANSMIT_POWER_ENVELOPE_ID 195 /* VHT transmit Power Envelope IE */ +#define DOT11_MNG_CHANNEL_SWITCH_WRAPPER_ID 196 /* Channel Switch Wrapper IE */ +#define DOT11_MNG_AID_ID 197 /* Association ID IE */ +#define DOT11_MNG_OPER_MODE_NOTIF_ID 199 /* d11 mgmt VHT oper mode notif */ + + +#define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */ +#define DOT11_MNG_PROPR_ID 221 +/* should start using this one instead of above two */ +#define DOT11_MNG_VS_ID 221 /* d11 management Vendor Specific IE */ + +/* Rate Defines */ + +/* Valid rates for the Supported Rates and Extended Supported Rates IEs. + * Encoding is the rate in 500kbps units, rouding up for fractional values. + * 802.11-2012, section 6.5.5.2, DATA_RATE parameter enumerates all the values. + * The rate values cover DSSS, HR/DSSS, ERP, and OFDM phy rates. + * The defines below do not cover the rates specific to 10MHz, {3, 4.5, 27}, + * and 5MHz, {1.5, 2.25, 3, 4.5, 13.5}, which are not supported by Broadcom devices. + */ + +#define DOT11_RATE_1M 2 /* 1 Mbps in 500kbps units */ +#define DOT11_RATE_2M 4 /* 2 Mbps in 500kbps units */ +#define DOT11_RATE_5M5 11 /* 5.5 Mbps in 500kbps units */ +#define DOT11_RATE_11M 22 /* 11 Mbps in 500kbps units */ +#define DOT11_RATE_6M 12 /* 6 Mbps in 500kbps units */ +#define DOT11_RATE_9M 18 /* 9 Mbps in 500kbps units */ +#define DOT11_RATE_12M 24 /* 12 Mbps in 500kbps units */ +#define DOT11_RATE_18M 36 /* 18 Mbps in 500kbps units */ +#define DOT11_RATE_24M 48 /* 24 Mbps in 500kbps units */ +#define DOT11_RATE_36M 72 /* 36 Mbps in 500kbps units */ +#define DOT11_RATE_48M 96 /* 48 Mbps in 500kbps units */ +#define DOT11_RATE_54M 108 /* 54 Mbps in 500kbps units */ +#define DOT11_RATE_MAX 108 /* highest rate (54 Mbps) in 500kbps units */ + +/* Supported Rates and Extended Supported Rates IEs + * The supported rates octets are defined a the MSB indicatin a Basic Rate + * and bits 0-6 as the rate value + */ +#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ +#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ + +/* BSS Membership Selector parameters + * 802.11-2012 and 802.11ac_D4.0 sec 8.4.2.3 + * These selector values are advertised in Supported Rates and Extended Supported Rates IEs + * in the supported rates list with the Basic rate bit set. + * Constants below include the basic bit. + */ +#define DOT11_BSS_MEMBERSHIP_HT 0xFF /* Basic 0x80 + 127, HT Required to join */ +#define DOT11_BSS_MEMBERSHIP_VHT 0xFE /* Basic 0x80 + 126, VHT Required to join */ + +/* ERP info element bit values */ +#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ +#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present + *in the BSS + */ +#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for + *ERP-OFDM frames + */ +#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, + * 1 == not allowed + */ +/* TS Delay element offset & size */ +#define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */ +#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ + +/* Capability Information Field */ +#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */ +#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */ +#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */ +#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */ +#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */ +#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */ +#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ +#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ +#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ +#define DOT11_CAP_QOS 0x0200 /* d11 cap. qos */ +#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ +#define DOT11_CAP_APSD 0x0800 /* d11 cap. apsd */ +#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ +#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ +#define DOT11_CAP_DELAY_BA 0x4000 /* d11 cap. delayed block ack */ +#define DOT11_CAP_IMMEDIATE_BA 0x8000 /* d11 cap. immediate block ack */ + +/* Extended capabilities IE bitfields */ +/* 20/40 BSS Coexistence Management support bit position */ +#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 +/* Extended Channel Switching support bit position */ +#define DOT11_EXT_CAP_EXT_CHAN_SWITCHING 2 +/* scheduled PSMP support bit position */ +#define DOT11_EXT_CAP_SPSMP 6 +/* Flexible Multicast Service */ +#define DOT11_EXT_CAP_FMS 11 +/* proxy ARP service support bit position */ +#define DOT11_EXT_CAP_PROXY_ARP 12 +/* Traffic Filter Service */ +#define DOT11_EXT_CAP_TFS 16 +/* WNM-Sleep Mode */ +#define DOT11_EXT_CAP_WNM_SLEEP 17 +/* TIM Broadcast service */ +#define DOT11_EXT_CAP_TIMBC 18 +/* BSS Transition Management support bit position */ +#define DOT11_EXT_CAP_BSSTRANS_MGMT 19 +/* Direct Multicast Service */ +#define DOT11_EXT_CAP_DMS 26 +/* Interworking support bit position */ +#define DOT11_EXT_CAP_IW 31 +/* service Interval granularity bit position and mask */ +#define DOT11_EXT_CAP_SI 41 +#define DOT11_EXT_CAP_SI_MASK 0x0E +/* WNM notification */ +#define DOT11_EXT_CAP_WNM_NOTIF 46 +/* Operating mode notification - VHT (11ac D3.0 - 8.4.2.29) */ +#define DOT11_EXT_CAP_OPER_MODE_NOTIF 62 + +/* VHT Operating mode bit fields - (11ac D3.0 - 8.4.1.50) */ +#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 +#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 +#define DOT11_OPER_MODE_RXNSS_SHIFT 4 +#define DOT11_OPER_MODE_RXNSS_MASK 0x70 +#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 +#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 + +#define DOT11_OPER_MODE(type, nss, chanw) (\ + ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ + DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ + (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ + ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ + DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) + +#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ + (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ + >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) +#define DOT11_OPER_MODE_RXNSS(mode) \ + ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ + >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) +#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ + (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ + >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) + +#define DOT11_OPER_MODE_20MHZ 0 +#define DOT11_OPER_MODE_40MHZ 1 +#define DOT11_OPER_MODE_80MHZ 2 +#define DOT11_OPER_MODE_160MHZ 3 +#define DOT11_OPER_MODE_8080MHZ 3 + +#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ) + +/* Operating mode information element 802.11ac D3.0 - 8.4.2.168 */ +BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { + uint8 mode; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; + +#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 + +/* Extended Capability Information Field */ +#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 /* 20/40 BSS Coexistence Management support */ + +/* + * Action Frame Constants + */ +#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action field */ +#define DOT11_ACTION_CAT_OFF 0 /* category offset */ +#define DOT11_ACTION_ACT_OFF 1 /* action offset */ + +/* Action Category field (sec 8.4.1.11) */ +#define DOT11_ACTION_CAT_ERR_MASK 0x80 /* category error mask */ +#define DOT11_ACTION_CAT_MASK 0x7F /* category mask */ +#define DOT11_ACTION_CAT_SPECT_MNG 0 /* category spectrum management */ +#define DOT11_ACTION_CAT_QOS 1 /* category QoS */ +#define DOT11_ACTION_CAT_DLS 2 /* category DLS */ +#define DOT11_ACTION_CAT_BLOCKACK 3 /* category block ack */ +#define DOT11_ACTION_CAT_PUBLIC 4 /* category public */ +#define DOT11_ACTION_CAT_RRM 5 /* category radio measurements */ +#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */ +#define DOT11_ACTION_CAT_HT 7 /* category for HT */ +#define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */ +#define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */ +#define DOT11_ACTION_CAT_WNM 10 /* category for WNM */ +#define DOT11_ACTION_CAT_UWNM 11 /* category for Unprotected WNM */ +#define DOT11_ACTION_NOTIFICATION 17 +#define DOT11_ACTION_CAT_VHT 21 /* VHT action */ +#define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */ +#define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */ + +/* Spectrum Management Action IDs (sec 7.4.1) */ +#define DOT11_SM_ACTION_M_REQ 0 /* d11 action measurement request */ +#define DOT11_SM_ACTION_M_REP 1 /* d11 action measurement response */ +#define DOT11_SM_ACTION_TPC_REQ 2 /* d11 action TPC request */ +#define DOT11_SM_ACTION_TPC_REP 3 /* d11 action TPC response */ +#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ +#define DOT11_SM_ACTION_EXT_CSA 5 /* d11 extened CSA for 11n */ + +/* HT action ids */ +#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ +#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ + +/* Public action ids */ +#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 /* 20/40 Coexistence Management action id */ +#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ +#define DOT11_PUB_ACTION_GAS_CB_REQ 12 /* GAS Comeback Request */ + +/* Block Ack action types */ +#define DOT11_BA_ACTION_ADDBA_REQ 0 /* ADDBA Req action frame type */ +#define DOT11_BA_ACTION_ADDBA_RESP 1 /* ADDBA Resp action frame type */ +#define DOT11_BA_ACTION_DELBA 2 /* DELBA action frame type */ + +/* ADDBA action parameters */ +#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 /* AMSDU supported under BA */ +#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 /* policy mask(ack vs delayed) */ +#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 /* policy shift */ +#define DOT11_ADDBA_PARAM_TID_MASK 0x003c /* tid mask */ +#define DOT11_ADDBA_PARAM_TID_SHIFT 2 /* tid shift */ +#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 /* buffer size mask */ +#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 /* buffer size shift */ + +#define DOT11_ADDBA_POLICY_DELAYED 0 /* delayed BA policy */ +#define DOT11_ADDBA_POLICY_IMMEDIATE 1 /* immediate BA policy */ + +/* Fast Transition action types */ +#define DOT11_FT_ACTION_FT_RESERVED 0 +#define DOT11_FT_ACTION_FT_REQ 1 /* FBT request - for over-the-DS FBT */ +#define DOT11_FT_ACTION_FT_RES 2 /* FBT response - for over-the-DS FBT */ +#define DOT11_FT_ACTION_FT_CON 3 /* FBT confirm - for OTDS with RRP */ +#define DOT11_FT_ACTION_FT_ACK 4 /* FBT ack */ + +/* DLS action types */ +#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */ +#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */ +#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */ + +/* Wireless Network Management (WNM) action types */ +#define DOT11_WNM_ACTION_EVENT_REQ 0 +#define DOT11_WNM_ACTION_EVENT_REP 1 +#define DOT11_WNM_ACTION_DIAG_REQ 2 +#define DOT11_WNM_ACTION_DIAG_REP 3 +#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 +#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 +#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6 +#define DOT11_WNM_ACTION_BSSTRANS_REQ 7 +#define DOT11_WNM_ACTION_BSSTRANS_RESP 8 +#define DOT11_WNM_ACTION_FMS_REQ 9 +#define DOT11_WNM_ACTION_FMS_RESP 10 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 +#define DOT11_WNM_ACTION_TFS_REQ 13 +#define DOT11_WNM_ACTION_TFS_RESP 14 +#define DOT11_WNM_ACTION_TFS_NOTIFY_REQ 15 +#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 +#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 +#define DOT11_WNM_ACTION_TIMBC_REQ 18 +#define DOT11_WNM_ACTION_TIMBC_RESP 19 +#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 +#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 +#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 +#define DOT11_WNM_ACTION_DMS_REQ 23 +#define DOT11_WNM_ACTION_DMS_RESP 24 +#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 +#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 +#define DOT11_WNM_ACTION_NOTFCTN_RESP 27 +#define DOT11_WNM_ACTION_TFS_NOTIFY_RESP 28 + +/* Unprotected Wireless Network Management (WNM) action types */ +#define DOT11_UWNM_ACTION_TIM 0 +#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 + +#define DOT11_MNG_COUNTRY_ID_LEN 3 + +/* VHT category action types - 802.11ac D3.0 - 8.5.23.1 */ +#define DOT11_VHT_ACTION_CBF 0 /* Compressed Beamforming */ +#define DOT11_VHT_ACTION_GID_MGMT 1 /* Group ID Management */ +#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 /* Operating mode notif'n */ + +/* DLS Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dls_req { + uint8 category; /* category of action frame (2) */ + uint8 action; /* DLS action: req (0) */ + struct ether_addr da; /* destination address */ + struct ether_addr sa; /* source address */ + uint16 cap; /* capability */ + uint16 timeout; /* timeout value */ + uint8 data[1]; /* IE:support rate, extend support rate, HT cap */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dls_req dot11_dls_req_t; +#define DOT11_DLS_REQ_LEN 18 /* Fixed length */ + +/* DLS response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { + uint8 category; /* category of action frame (2) */ + uint8 action; /* DLS action: req (0) */ + uint16 status; /* status code field */ + struct ether_addr da; /* destination address */ + struct ether_addr sa; /* source address */ + uint8 data[1]; /* optional: capability, rate ... */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dls_resp dot11_dls_resp_t; +#define DOT11_DLS_RESP_LEN 16 /* Fixed length */ + + +/* ************* 802.11v related definitions. ************* */ + +/* BSS Management Transition Query frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_query (6) */ + uint8 token; /* dialog token */ + uint8 reason; /* transition query reason */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_query dot11_bsstrans_query_t; +#define DOT11_BSSTRANS_QUERY_LEN 4 /* Fixed length */ + +/* BSS Management Transition Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_req (7) */ + uint8 token; /* dialog token */ + uint8 reqmode; /* transition request mode */ + uint16 disassoc_tmr; /* disassociation timer */ + uint8 validity_intrvl; /* validity interval */ + uint8 data[1]; /* optional: BSS term duration, ... */ + /* ...session info URL, candidate list */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_req dot11_bsstrans_req_t; +#define DOT11_BSSTRANS_REQ_LEN 7 /* Fixed length */ + +/* BSS Mgmt Transition Request Mode Field - 802.11v */ +#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01 +#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02 +#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04 +#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08 +#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10 + +/* BSS Management transition response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_resp (8) */ + uint8 token; /* dialog token */ + uint8 status; /* transition status */ + uint8 term_delay; /* validity interval */ + uint8 data[1]; /* optional: BSSID target, candidate list */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t; +#define DOT11_BSSTRANS_RESP_LEN 5 /* Fixed length */ + +/* BSS Mgmt Transition Response Status Field */ +#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0 +#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8 + + +/* BSS Max Idle Period element */ +BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { + uint8 id; /* 90, DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID */ + uint8 len; + uint16 max_idle_period; /* in unit of 1000 TUs */ + uint8 idle_opt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; +#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 /* bss max idle period IE size */ +#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 /* BSS max idle option */ + +/* TIM Broadcast request element */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { + uint8 id; /* 94, DOT11_MNG_TIMBC_REQ_ID */ + uint8 len; + uint8 interval; /* in unit of beacon interval */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; +#define DOT11_TIMBC_REQ_IE_LEN 1 /* Fixed length */ + +/* TIM Broadcast request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: DOT11_WNM_ACTION_TIMBC_REQ(18) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* TIM broadcast request element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req dot11_timbc_req_t; +#define DOT11_TIMBC_REQ_LEN 3 /* Fixed length */ + +/* TIM Broadcast response element */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { + uint8 id; /* 95, DOT11_MNG_TIM_BROADCAST_RESP_ID */ + uint8 len; + uint8 status; /* status of add request */ + uint8 interval; /* in unit of beacon interval */ + int32 offset; /* in unit of ms */ + uint16 high_rate; /* in unit of 0.5 Mb/s */ + uint16 low_rate; /* in unit of 0.5 Mb/s */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; +#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 /* Deny. Fixed length */ +#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 /* Accept. Fixed length */ + +#define DOT11_TIMBC_STATUS_ACCEPT 0 +#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 +#define DOT11_TIMBC_STATUS_DENY 2 +#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 +#define DOT11_TIMBC_STATUS_RESERVED 4 + +/* TIM Broadcast request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* action: DOT11_WNM_ACTION_TIMBC_RESP(19) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* TIM broadcast response element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp dot11_timbc_resp_t; +#define DOT11_TIMBC_RESP_LEN 3 /* Fixed length */ + +/* TIM element */ +BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { + uint8 id; /* 5, DOT11_MNG_TIM_ID */ + uint8 len; /* 4 - 255 */ + uint8 dtim_count; /* DTIM decrementing counter */ + uint8 dtim_period; /* DTIM period */ + uint8 bitmap_control; /* AID 0 + bitmap offset */ + uint8 pvb[1]; /* Partial Virtual Bitmap, variable length */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tim_ie dot11_tim_ie_t; +#define DOT11_TIM_IE_FIXED_LEN 3 /* Fixed length, without id and len */ +#define DOT11_TIM_IE_FIXED_TOTAL_LEN 5 /* Fixed length, with id and len */ + +/* TIM Broadcast frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc { + uint8 category; /* category of action frame (11) */ + uint8 action; /* action: TIM (0) */ + uint8 check_beacon; /* need to check-beacon */ + uint8 tsf[8]; /* Time Synchronization Function */ + dot11_tim_ie_t tim_ie; /* TIM element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc dot11_timbc_t; +#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) +#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) /* Fixed length */ +#define DOT11_TIMBC_LEN 11 /* Fixed length */ + +/* TCLAS frame classifier type */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { + uint8 type; + uint8 mask; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; +#define DOT11_TCLAS_FC_HDR_LEN 2 /* Fixed length */ + +#define DOT11_TCLAS_MASK_0 0x1 +#define DOT11_TCLAS_MASK_1 0x2 +#define DOT11_TCLAS_MASK_2 0x4 +#define DOT11_TCLAS_MASK_3 0x8 +#define DOT11_TCLAS_MASK_4 0x10 +#define DOT11_TCLAS_MASK_5 0x20 +#define DOT11_TCLAS_MASK_6 0x40 +#define DOT11_TCLAS_MASK_7 0x80 + +#define DOT11_TCLAS_FC_0_ETH 0 +#define DOT11_TCLAS_FC_1_IP 1 +#define DOT11_TCLAS_FC_2_8021Q 2 +#define DOT11_TCLAS_FC_3_OFFSET 3 +#define DOT11_TCLAS_FC_4_IP_HIGHER 4 +#define DOT11_TCLAS_FC_5_8021D 5 + +/* TCLAS frame classifier type 0 parameters for Ethernet */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { + uint8 type; + uint8 mask; + uint8 sa[ETHER_ADDR_LEN]; + uint8 da[ETHER_ADDR_LEN]; + uint16 eth_type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; +#define DOT11_TCLAS_FC_0_ETH_LEN 16 + +/* TCLAS frame classifier type 1 parameters for IPV4 */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { + uint8 type; + uint8 mask; + uint8 version; + uint32 src_ip; + uint32 dst_ip; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 protocol; + uint8 reserved; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; +#define DOT11_TCLAS_FC_1_IPV4_LEN 18 + +/* TCLAS frame classifier type 2 parameters for 802.1Q */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { + uint8 type; + uint8 mask; + uint16 tci; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; +#define DOT11_TCLAS_FC_2_8021Q_LEN 4 + +/* TCLAS frame classifier type 3 parameters for filter offset */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { + uint8 type; + uint8 mask; + uint16 offset; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; +#define DOT11_TCLAS_FC_3_FILTER_LEN 4 + +/* TCLAS frame classifier type 4 parameters for IPV4 is the same as TCLAS type 1 */ +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; +#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN + +/* TCLAS frame classifier type 4 parameters for IPV6 */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { + uint8 type; + uint8 mask; + uint8 version; + uint8 saddr[16]; + uint8 daddr[16]; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 nexthdr; + uint8 flow_lbl[3]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; +#define DOT11_TCLAS_FC_4_IPV6_LEN 44 + +/* TCLAS frame classifier type 5 parameters for 802.1D */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { + uint8 type; + uint8 mask; + uint8 pcp; + uint8 cfi; + uint16 vid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; +#define DOT11_TCLAS_FC_5_8021D_LEN 6 + +/* TCLAS frame classifier type parameters */ +BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { + uint8 data[1]; + dot11_tclas_fc_hdr_t hdr; + dot11_tclas_fc_0_eth_t t0_eth; + dot11_tclas_fc_1_ipv4_t t1_ipv4; + dot11_tclas_fc_2_8021q_t t2_8021q; + dot11_tclas_fc_3_filter_t t3_filter; + dot11_tclas_fc_4_ipv4_t t4_ipv4; + dot11_tclas_fc_4_ipv6_t t4_ipv6; + dot11_tclas_fc_5_8021d_t t5_8021d; +} BWL_POST_PACKED_STRUCT; +typedef union dot11_tclas_fc dot11_tclas_fc_t; + +#define DOT11_TCLAS_FC_MIN_LEN 4 /* Classifier Type 2 has the min size */ +#define DOT11_TCLAS_FC_MAX_LEN 254 + +/* TCLAS element */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { + uint8 id; /* 14, DOT11_MNG_TCLAS_ID */ + uint8 len; + uint8 user_priority; + dot11_tclas_fc_t fc; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_ie dot11_tclas_ie_t; +#define DOT11_TCLAS_IE_LEN 3 /* Fixed length, include id and len */ + +/* TCLAS processing element */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { + uint8 id; /* 44, DOT11_MNG_TCLAS_PROC_ID */ + uint8 len; + uint8 process; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; +#define DOT11_TCLAS_PROC_IE_LEN 3 /* Fixed length, include id and len */ + +#define DOT11_TCLAS_PROC_MATCHALL 0 /* All high level element need to match */ +#define DOT11_TCLAS_PROC_MATCHONE 1 /* One high level element need to match */ +#define DOT11_TCLAS_PROC_NONMATCH 2 /* Non match to any high level element */ + + +/* TSPEC element defined in 802.11 std section 8.4.2.32 - Not supported */ +#define DOT11_TSPEC_IE_LEN 57 /* Fixed length */ + +/* TFS request element */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { + uint8 id; /* 91, DOT11_MNG_TFS_REQUEST_ID */ + uint8 len; + uint8 tfs_id; + uint8 actcode; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; +#define DOT11_TFS_REQ_IE_LEN 2 /* Fixed length, without id and len */ + +/* TFS request action codes (bitfield) */ +#define DOT11_TFS_ACTCODE_DELETE 1 +#define DOT11_TFS_ACTCODE_NOTIFY 2 + +/* TFS request subelement IDs */ +#define DOT11_TFS_REQ_TFS_SE_ID 1 +#define DOT11_TFS_REQ_VENDOR_SE_ID 221 + +/* TFS subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { + uint8 sub_id; + uint8 len; + uint8 data[1]; /* TCLAS element(s) + optional TCLAS proc */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_se dot11_tfs_se_t; + + +/* TFS response element */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { + uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ + uint8 len; + uint8 tfs_id; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; +#define DOT11_TFS_RESP_IE_LEN 1 /* Fixed length, without id and len */ + +/* TFS response subelement IDs (same subelments, but different IDs than in TFS request */ +#define DOT11_TFS_RESP_TFS_STATUS_SE_ID 1 +#define DOT11_TFS_RESP_TFS_SE_ID 2 +#define DOT11_TFS_RESP_VENDOR_SE_ID 221 + +/* TFS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { + uint8 sub_id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ + uint8 len; + uint8 resp_st; + uint8 data[1]; /* Potential dot11_tfs_se_t included */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; +#define DOT11_TFS_STATUS_SE_LEN 1 /* Fixed length, without id and len */ + +/* Following Definition should be merged to FMS_TFS macro below */ +/* TFS Response status code. Identical to FMS Element status, without N/A */ +#define DOT11_TFS_STATUS_ACCEPT 0 +#define DOT11_TFS_STATUS_DENY_FORMAT 1 +#define DOT11_TFS_STATUS_DENY_RESOURCE 2 +#define DOT11_TFS_STATUS_DENY_POLICY 4 +#define DOT11_TFS_STATUS_DENY_UNSPECIFIED 5 +#define DOT11_TFS_STATUS_ALTPREF_POLICY 7 +#define DOT11_TFS_STATUS_ALTPREF_TCLAS_UNSUPP 14 + +/* FMS Element Status and TFS Response Status Definition */ +#define DOT11_FMS_TFS_STATUS_ACCEPT 0 +#define DOT11_FMS_TFS_STATUS_DENY_FORMAT 1 +#define DOT11_FMS_TFS_STATUS_DENY_RESOURCE 2 +#define DOT11_FMS_TFS_STATUS_DENY_MULTIPLE_DI 3 +#define DOT11_FMS_TFS_STATUS_DENY_POLICY 4 +#define DOT11_FMS_TFS_STATUS_DENY_UNSPECIFIED 5 +#define DOT11_FMS_TFS_STATUS_ALT_DIFF_DI 6 +#define DOT11_FMS_TFS_STATUS_ALT_POLICY 7 +#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_DI 8 +#define DOT11_FMS_TFS_STATUS_ALT_MCRATE 9 +#define DOT11_FMS_TFS_STATUS_TERM_POLICY 10 +#define DOT11_FMS_TFS_STATUS_TERM_RESOURCE 11 +#define DOT11_FMS_TFS_STATUS_TERM_HIGHER_PRIO 12 +#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_MDI 13 +#define DOT11_FMS_TFS_STATUS_ALT_TCLAS_UNSUPP 14 + +/* TFS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS request (13) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req dot11_tfs_req_t; +#define DOT11_TFS_REQ_LEN 3 /* Fixed length */ + +/* TFS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS request (14) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp dot11_tfs_resp_t; +#define DOT11_TFS_RESP_LEN 3 /* Fixed length */ + +/* TFS Management Notify frame request header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS notify request (15) */ + uint8 tfs_id_cnt; /* TFS IDs count */ + uint8 tfs_id[1]; /* Array of TFS IDs */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify_req dot11_tfs_notify_req_t; +#define DOT11_TFS_NOTIFY_REQ_LEN 3 /* Fixed length */ + +/* TFS Management Notify frame response header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS notify response (28) */ + uint8 tfs_id_cnt; /* TFS IDs count */ + uint8 tfs_id[1]; /* Array of TFS IDs */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify_resp dot11_tfs_notify_resp_t; +#define DOT11_TFS_NOTIFY_RESP_LEN 3 /* Fixed length */ + + +/* WNM-Sleep Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: wnm-sleep request (16) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; +#define DOT11_WNM_SLEEP_REQ_LEN 3 /* Fixed length */ + +/* WNM-Sleep Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: wnm-sleep request (17) */ + uint8 token; /* dialog token */ + uint16 key_len; /* key data length */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; +#define DOT11_WNM_SLEEP_RESP_LEN 5 /* Fixed length */ + +#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 +#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { + uint8 sub_id; + uint8 len; + uint16 key_info; + uint8 key_length; + uint8 rsc[8]; + uint8 key[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 /* without sub_id, len, and key */ +#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 /* without sub_id and len */ + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { + uint8 sub_id; + uint8 len; + uint16 key_id; + uint8 pn[6]; + uint8 key[16]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 /* Fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { + uint8 id; /* 93, DOT11_MNG_WNM_SLEEP_MODE_ID */ + uint8 len; + uint8 act_type; + uint8 resp_status; + uint16 interval; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; +#define DOT11_WNM_SLEEP_IE_LEN 4 /* Fixed length */ + +#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 +#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 + +#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 +#define DOT11_WNM_SLEEP_RESP_UPDATE 1 +#define DOT11_WNM_SLEEP_RESP_DENY 2 +#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 +#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 +#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 +#define DOT11_WNM_SLEEP_RESP_LAST 6 + +/* DMS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: dms request (23) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req dot11_dms_req_t; +#define DOT11_DMS_REQ_LEN 3 /* Fixed length */ + +/* DMS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: dms request (24) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp dot11_dms_resp_t; +#define DOT11_DMS_RESP_LEN 3 /* Fixed length */ + +/* DMS request element */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { + uint8 id; /* 99, DOT11_MNG_DMS_REQUEST_ID */ + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; +#define DOT11_DMS_REQ_IE_LEN 2 /* Fixed length */ + +/* DMS response element */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { + uint8 id; /* 100, DOT11_MNG_DMS_RESPONSE_ID */ + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; +#define DOT11_DMS_RESP_IE_LEN 2 /* Fixed length */ + +/* DMS request descriptor */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { + uint8 dms_id; + uint8 len; + uint8 type; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; +#define DOT11_DMS_REQ_DESC_LEN 3 /* Fixed length */ + +#define DOT11_DMS_REQ_TYPE_ADD 0 +#define DOT11_DMS_REQ_TYPE_REMOVE 1 +#define DOT11_DMS_REQ_TYPE_CHANGE 2 + +/* DMS response status */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { + uint8 dms_id; + uint8 len; + uint8 type; + uint16 lsc; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; +#define DOT11_DMS_RESP_STATUS_LEN 5 /* Fixed length */ + +#define DOT11_DMS_RESP_TYPE_ACCEPT 0 +#define DOT11_DMS_RESP_TYPE_DENY 1 +#define DOT11_DMS_RESP_TYPE_TERM 2 + +#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF + +/* FMS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: fms request (9) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_req dot11_fms_req_t; +#define DOT11_FMS_REQ_LEN 3 /* Fixed length */ + +/* FMS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: fms request (10) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_resp dot11_fms_resp_t; +#define DOT11_FMS_RESP_LEN 3 /* Fixed length */ + +/* FMS Descriptor element */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_desc { + uint8 id; + uint8 len; + uint8 num_fms_cnt; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_desc dot11_fms_desc_t; +#define DOT11_FMS_DESC_LEN 1 /* Fixed length */ + +#define DOT11_FMS_CNTR_MAX 0x8 +#define DOT11_FMS_CNTR_ID_MASK 0x7 +#define DOT11_FMS_CNTR_ID_SHIFT 0x0 +#define DOT11_FMS_CNTR_COUNT_MASK 0xf1 +#define DOT11_FMS_CNTR_SHIFT 0x3 + +/* FMS request element */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_req_ie { + uint8 id; + uint8 len; + uint8 fms_token; /* token used to identify fms stream set */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_req_ie dot11_fms_req_ie_t; +#define DOT11_FMS_REQ_IE_FIX_LEN 1 /* Fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_rate_id_field { + uint8 mask; + uint8 mcs_idx; + uint16 rate; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rate_id_field dot11_rate_id_field_t; +#define DOT11_RATE_ID_FIELD_MCS_SEL_MASK 0x7 +#define DOT11_RATE_ID_FIELD_MCS_SEL_OFFSET 0 +#define DOT11_RATE_ID_FIELD_RATETYPE_MASK 0x18 +#define DOT11_RATE_ID_FIELD_RATETYPE_OFFSET 3 +#define DOT11_RATE_ID_FIELD_LEN sizeof(dot11_rate_id_field_t) + +/* FMS request subelements */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_se { + uint8 sub_id; + uint8 len; + uint8 interval; + uint8 max_interval; + dot11_rate_id_field_t rate; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_se dot11_fms_se_t; +#define DOT11_FMS_REQ_SE_LEN 6 /* Fixed length */ + +#define DOT11_FMS_REQ_SE_ID_FMS 1 /* FMS subelement */ +#define DOT11_FMS_REQ_SE_ID_VS 221 /* Vendor Specific subelement */ + +/* FMS response element */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_resp_ie { + uint8 id; + uint8 len; + uint8 fms_token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_resp_ie dot11_fms_resp_ie_t; +#define DOT11_FMS_RESP_IE_FIX_LEN 1 /* Fixed length */ + +/* FMS status subelements */ +#define DOT11_FMS_STATUS_SE_ID_FMS 1 /* FMS Status */ +#define DOT11_FMS_STATUS_SE_ID_TCLAS 2 /* TCLAS Status */ +#define DOT11_FMS_STATUS_SE_ID_VS 221 /* Vendor Specific subelement */ + +/* FMS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_status_se { + uint8 sub_id; + uint8 len; + uint8 status; + uint8 interval; + uint8 max_interval; + uint8 fmsid; + uint8 counter; + dot11_rate_id_field_t rate; + uint8 mcast_addr[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_status_se dot11_fms_status_se_t; +#define DOT11_FMS_STATUS_SE_LEN 15 /* Fixed length */ + +/* TCLAS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_status_se { + uint8 sub_id; + uint8 len; + uint8 fmsid; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_status_se dot11_tclas_status_se_t; +#define DOT11_TCLAS_STATUS_SE_LEN 1 /* Fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_addba_req { + uint8 category; /* category of action frame (3) */ + uint8 action; /* action: addba req */ + uint8 token; /* identifier */ + uint16 addba_param_set; /* parameter set */ + uint16 timeout; /* timeout in seconds */ + uint16 start_seqnum; /* starting sequence number */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_req dot11_addba_req_t; +#define DOT11_ADDBA_REQ_LEN 9 /* length of addba req frame */ + +BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { + uint8 category; /* category of action frame (3) */ + uint8 action; /* action: addba resp */ + uint8 token; /* identifier */ + uint16 status; /* status of add request */ + uint16 addba_param_set; /* negotiated parameter set */ + uint16 timeout; /* negotiated timeout in seconds */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_resp dot11_addba_resp_t; +#define DOT11_ADDBA_RESP_LEN 9 /* length of addba resp frame */ + +/* DELBA action parameters */ +#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 /* initiator mask */ +#define DOT11_DELBA_PARAM_INIT_SHIFT 11 /* initiator shift */ +#define DOT11_DELBA_PARAM_TID_MASK 0xf000 /* tid mask */ +#define DOT11_DELBA_PARAM_TID_SHIFT 12 /* tid shift */ + +BWL_PRE_PACKED_STRUCT struct dot11_delba { + uint8 category; /* category of action frame (3) */ + uint8 action; /* action: addba req */ + uint16 delba_param_set; /* paarmeter set */ + uint16 reason; /* reason for dellba */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_delba dot11_delba_t; +#define DOT11_DELBA_LEN 6 /* length of delba frame */ + +/* SA Query action field value */ +#define SA_QUERY_REQUEST 0 +#define SA_QUERY_RESPONSE 1 + +/* ************* 802.11r related definitions. ************* */ + +/* Over-the-DS Fast Transition Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_ft_req { + uint8 category; /* category of action frame (6) */ + uint8 action; /* action: ft req */ + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_req dot11_ft_req_t; +#define DOT11_FT_REQ_FIXED_LEN 14 + +/* Over-the-DS Fast Transition Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_ft_res { + uint8 category; /* category of action frame (6) */ + uint8 action; /* action: ft resp */ + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint16 status; /* status code */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_res dot11_ft_res_t; +#define DOT11_FT_RES_FIXED_LEN 16 + +/* RDE RIC Data Element. */ +BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { + uint8 id; /* 11r, DOT11_MNG_RDE_ID */ + uint8 length; + uint8 rde_id; /* RDE identifier. */ + uint8 rd_count; /* Resource Descriptor Count. */ + uint16 status; /* Status Code. */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rde_ie dot11_rde_ie_t; + +/* 11r - Size of the RDE (RIC Data Element) IE, including TLV header. */ +#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) + + +/* ************* 802.11k related definitions. ************* */ + +/* Radio measurements enabled capability ie */ +#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ +#define RCPI_IE_LEN 1 +#define RSNI_IE_LEN 1 +BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { + uint8 cap[DOT11_RRM_CAP_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; + +/* Bitmap definitions for cap ie */ +#define DOT11_RRM_CAP_LINK 0 +#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 +#define DOT11_RRM_CAP_PARALLEL 2 +#define DOT11_RRM_CAP_REPEATED 3 +#define DOT11_RRM_CAP_BCN_PASSIVE 4 +#define DOT11_RRM_CAP_BCN_ACTIVE 5 +#define DOT11_RRM_CAP_BCN_TABLE 6 +#define DOT11_RRM_CAP_BCN_REP_COND 7 +#define DOT11_RRM_CAP_FM 8 +#define DOT11_RRM_CAP_CLM 9 +#define DOT11_RRM_CAP_NHM 10 +#define DOT11_RRM_CAP_SM 11 +#define DOT11_RRM_CAP_LCIM 12 +#define DOT11_RRM_CAP_LCIA 13 +#define DOT11_RRM_CAP_TSCM 14 +#define DOT11_RRM_CAP_TTSCM 15 +#define DOT11_RRM_CAP_AP_CHANREP 16 +#define DOT11_RRM_CAP_RMMIB 17 +/* bit18-bit26, not used for RRM_IOVAR */ +#define DOT11_RRM_CAP_MPTI 27 +#define DOT11_RRM_CAP_NBRTSFO 28 +#define DOT11_RRM_CAP_RCPI 29 +#define DOT11_RRM_CAP_RSNI 30 +#define DOT11_RRM_CAP_BSSAAD 31 +#define DOT11_RRM_CAP_BSSAAC 32 +#define DOT11_RRM_CAP_AI 33 + +/* Operating Class (formerly "Regulatory Class") definitions */ +#define DOT11_OP_CLASS_NONE 255 + +BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { + uint8 id; + uint8 len; + uint8 reg; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct do11_ap_chrep dot11_ap_chrep_t; + +/* Radio Measurements action ids */ +#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ +#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */ +#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */ +#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */ +#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */ +#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */ + +/* Generic radio measurement action frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_rm_action { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_action dot11_rm_action_t; +#define DOT11_RM_ACTION_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + uint16 reps; /* no. of repetitions */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq dot11_rmreq_t; +#define DOT11_RMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_ie dot11_rm_ie_t; +#define DOT11_RM_IE_LEN 5 + +/* Definitions for "mode" bits in rm req */ +#define DOT11_RMREQ_MODE_PARALLEL 1 +#define DOT11_RMREQ_MODE_ENABLE 2 +#define DOT11_RMREQ_MODE_REQUEST 4 +#define DOT11_RMREQ_MODE_REPORT 8 +#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */ + +/* Definitions for "mode" bits in rm rep */ +#define DOT11_RMREP_MODE_LATE 1 +#define DOT11_RMREP_MODE_INCAPABLE 2 +#define DOT11_RMREP_MODE_REFUSED 4 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 bcn_mode; + struct ether_addr bssid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; +#define DOT11_RMREQ_BCN_LEN 18 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 frame_info; + uint8 rcpi; + uint8 rsni; + struct ether_addr bssid; + uint8 antenna_id; + uint32 parent_tsf; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; +#define DOT11_RMREP_BCN_LEN 26 + +/* Beacon request measurement mode */ +#define DOT11_RMREQ_BCN_PASSIVE 0 +#define DOT11_RMREQ_BCN_ACTIVE 1 +#define DOT11_RMREQ_BCN_TABLE 2 + +/* Sub-element IDs for Beacon Request */ +#define DOT11_RMREQ_BCN_SSID_ID 0 +#define DOT11_RMREQ_BCN_REPINFO_ID 1 +#define DOT11_RMREQ_BCN_REPDET_ID 2 +#define DOT11_RMREQ_BCN_REQUEST_ID 10 +#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID + +/* Reporting Detail element definition */ +#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ +#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */ +#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */ + +/* Sub-element IDs for Beacon Report */ +#define DOT11_RMREP_BCN_FRM_BODY 1 + +/* Sub-element IDs for Frame Report */ +#define DOT11_RMREP_FRAME_COUNT_REPORT 1 + +/* Channel load request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; +#define DOT11_RMREQ_CHANLOAD_LEN 11 + +/* Channel load report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 channel_load; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; +#define DOT11_RMREP_CHANLOAD_LEN 13 + +/* Noise histogram request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; +#define DOT11_RMREQ_NOISE_LEN 11 + +/* Noise histogram report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 antid; + uint8 anpi; + uint8 ipi0_dens; + uint8 ipi1_dens; + uint8 ipi2_dens; + uint8 ipi3_dens; + uint8 ipi4_dens; + uint8 ipi5_dens; + uint8 ipi6_dens; + uint8 ipi7_dens; + uint8 ipi8_dens; + uint8 ipi9_dens; + uint8 ipi10_dens; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; +#define DOT11_RMREP_NOISE_LEN 25 + +/* Frame request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 req_type; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; +#define DOT11_RMREQ_FRAME_LEN 18 + +/* Frame report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; +#define DOT11_RMREP_FRAME_LEN 12 + +/* Frame report entry */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { + struct ether_addr ta; + struct ether_addr bssid; + uint8 phy_type; + uint8 avg_rcpi; + uint8 last_rsni; + uint8 last_rcpi; + uint8 ant_id; + uint16 frame_cnt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; +#define DOT11_RMREP_FRMENTRY_LEN 19 + +/* STA statistics request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + struct ether_addr peer; + uint16 interval; + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; +#define DOT11_RMREQ_STAT_LEN 16 + +/* STA statistics report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; + +/* Transmit stream/category measurement request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 interval; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 bin0_range; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; + +/* Transmit stream/category measurement report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { + uint32 starttime[2]; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 reason; + uint32 txmsdu_cnt; + uint32 msdu_discarded_cnt; + uint32 msdufailed_cnt; + uint32 msduretry_cnt; + uint32 cfpolls_lost_cnt; + uint32 avrqueue_delay; + uint32 avrtx_delay; + uint8 bin0_range; + uint32 bin0; + uint32 bin1; + uint32 bin2; + uint32 bin3; + uint32 bin4; + uint32 bin5; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; + +/* Measurement pause request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 pause_time; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; + + +/* Neighbor Report subelements ID (11k & 11v) */ +#define DOT11_NGBR_TSF_INFO_SE_ID 1 +#define DOT11_NGBR_CCS_SE_ID 2 +#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3 +#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4 +#define DOT11_NGBR_BEARING_SE_ID 5 + +/* Neighbor Report, BSS Transition Candidate Preference subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se { + uint8 sub_id; + uint8 len; + uint8 preference; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t; +#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1 + +/* Neighbor Report, BSS Termination Duration subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se { + uint8 sub_id; + uint8 len; + uint8 tsf[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t; +#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10 + +/* Neighbor Report BSSID Information Field */ +#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002 +#define DOT11_NGBR_BI_REACHABILTY 0x0003 +#define DOT11_NGBR_BI_SEC 0x0004 +#define DOT11_NGBR_BI_KEY_SCOPE 0x0008 +#define DOT11_NGBR_BI_CAP 0x03f0 +#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010 +#define DOT11_NGBR_BI_CAP_QOS 0x0020 +#define DOT11_NGBR_BI_CAP_APSD 0x0040 +#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080 +#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100 +#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200 +#define DOT11_NGBR_BI_MOBILITY 0x0400 +#define DOT11_NGBR_BI_HT 0x0800 + +/* Neighbor Report element (11k & 11v) */ +BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; /* Operating class */ + uint8 channel; + uint8 phytype; + uint8 data[1]; /* Variable size subelements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; +#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13 + + +/* MLME Enumerations */ +#define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ +#define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */ +#define DOT11_BSSTYPE_ANY 2 /* d11 any BSS type */ +#define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */ +#define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */ + +/* Link Measurement */ +BWL_PRE_PACKED_STRUCT struct dot11_lmreq { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + uint8 txpwr; /* Transmit Power Used */ + uint8 maxtxpwr; /* Max Transmit Power */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmreq dot11_lmreq_t; +#define DOT11_LMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_lmrep { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + dot11_tpc_rep_t tpc; /* TPC element */ + uint8 rxant; /* Receive Antenna ID */ + uint8 txant; /* Transmit Antenna ID */ + uint8 rcpi; /* RCPI */ + uint8 rsni; /* RSNI */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmrep dot11_lmrep_t; +#define DOT11_LMREP_LEN 11 + +/* 802.11 BRCM "Compromise" Pre N constants */ +#define PREN_PREAMBLE 24 /* green field preamble time */ +#define PREN_MM_EXT 12 /* extra mixed mode preamble time */ +#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ + +/* 802.11N PHY constants */ +#define RIFS_11N_TIME 2 /* NPHY RIFS time */ + +/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3 + * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 + */ +/* HT-SIG1 */ +#define HT_SIG1_MCS_MASK 0x00007F +#define HT_SIG1_CBW 0x000080 +#define HT_SIG1_HT_LENGTH 0xFFFF00 + +/* HT-SIG2 */ +#define HT_SIG2_SMOOTHING 0x000001 +#define HT_SIG2_NOT_SOUNDING 0x000002 +#define HT_SIG2_RESERVED 0x000004 +#define HT_SIG2_AGGREGATION 0x000008 +#define HT_SIG2_STBC_MASK 0x000030 +#define HT_SIG2_STBC_SHIFT 4 +#define HT_SIG2_FEC_CODING 0x000040 +#define HT_SIG2_SHORT_GI 0x000080 +#define HT_SIG2_ESS_MASK 0x000300 +#define HT_SIG2_ESS_SHIFT 8 +#define HT_SIG2_CRC 0x03FC00 +#define HT_SIG2_TAIL 0x1C0000 + +/* HT Timing-related parameters (802.11-2012, sec 20.3.6) */ +#define HT_T_LEG_PREAMBLE 16 +#define HT_T_L_SIG 4 +#define HT_T_SIG 8 +#define HT_T_LTF1 4 +#define HT_T_GF_LTF1 8 +#define HT_T_LTFs 4 +#define HT_T_STF 4 +#define HT_T_GF_STF 8 +#define HT_T_SYML 4 + +#define HT_N_SERVICE 16 /* bits in SERVICE field */ +#define HT_N_TAIL 6 /* tail bits per BCC encoder */ + +/* 802.11 A PHY constants */ +#define APHY_SLOT_TIME 9 /* APHY slot time */ +#define APHY_SIFS_TIME 16 /* APHY SIFS time */ +#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ +#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ +#define APHY_SIGNAL_TIME 4 /* APHY signal time */ +#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ +#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ +#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ +#define APHY_CWMIN 15 /* APHY cwmin */ + +/* 802.11 B PHY constants */ +#define BPHY_SLOT_TIME 20 /* BPHY slot time */ +#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ +#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ +#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ +#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ +#define BPHY_CWMIN 31 /* BPHY cwmin */ + +/* 802.11 G constants */ +#define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */ + +#define PHY_CWMAX 1023 /* PHY cwmax */ + +#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ + +/* 802.11 VHT constants */ + +typedef int vht_group_id_t; + +/* for VHT-A1 */ +/* SIG-A1 reserved bits */ +#define VHT_SIGA1_CONST_MASK 0x800004 + +#define VHT_SIGA1_BW_MASK 0x000003 +#define VHT_SIGA1_20MHZ_VAL 0x000000 +#define VHT_SIGA1_40MHZ_VAL 0x000001 +#define VHT_SIGA1_80MHZ_VAL 0x000002 +#define VHT_SIGA1_160MHZ_VAL 0x000003 + +#define VHT_SIGA1_STBC 0x000008 + +#define VHT_SIGA1_GID_MASK 0x0003f0 +#define VHT_SIGA1_GID_SHIFT 4 +#define VHT_SIGA1_GID_TO_AP 0x00 +#define VHT_SIGA1_GID_NOT_TO_AP 0x3f +#define VHT_SIGA1_GID_MAX_GID 0x3f + +#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 +#define VHT_SIGA1_NSTS_SHIFT 10 + +#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 +#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 + +#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 + +/* for VHT-A2 */ +#define VHT_SIGA2_GI_NONE 0x000000 +#define VHT_SIGA2_GI_SHORT 0x000001 +#define VHT_SIGA2_GI_W_MOD10 0x000002 +#define VHT_SIGA2_CODING_LDPC 0x000004 +#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 +#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 +#define VHT_SIGA2_MCS_SHIFT 4 + +#define VHT_SIGA2_B9_RESERVED 0x000200 +#define VHT_SIGA2_TAIL_MASK 0xfc0000 +#define VHT_SIGA2_TAIL_VALUE 0x000000 + +/* VHT Timing-related parameters (802.11ac D4.0, sec 22.3.6) */ +#define VHT_T_LEG_PREAMBLE 16 +#define VHT_T_L_SIG 4 +#define VHT_T_SIG_A 8 +#define VHT_T_LTF 4 +#define VHT_T_STF 4 +#define VHT_T_SIG_B 4 +#define VHT_T_SYML 4 + +#define VHT_N_SERVICE 16 /* bits in SERVICE field */ +#define VHT_N_TAIL 6 /* tail bits per BCC encoder */ + + +/* dot11Counters Table - 802.11 spec., Annex D */ +typedef struct d11cnt { + uint32 txfrag; /* dot11TransmittedFragmentCount */ + uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ + uint32 txfail; /* dot11FailedCount */ + uint32 txretry; /* dot11RetryCount */ + uint32 txretrie; /* dot11MultipleRetryCount */ + uint32 rxdup; /* dot11FrameduplicateCount */ + uint32 txrts; /* dot11RTSSuccessCount */ + uint32 txnocts; /* dot11RTSFailureCount */ + uint32 txnoack; /* dot11ACKFailureCount */ + uint32 rxfrag; /* dot11ReceivedFragmentCount */ + uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ + uint32 rxcrc; /* dot11FCSErrorCount */ + uint32 txfrmsnt; /* dot11TransmittedFrameCount */ + uint32 rxundec; /* dot11WEPUndecryptableCount */ +} d11cnt_t; + +#define BRCM_PROP_OUI "\x00\x90\x4C" + + +/* Action frame type for RWL */ +#define RWL_WIFI_DEFAULT 0 +#define RWL_WIFI_FIND_MY_PEER 9 /* Used while finding server */ +#define RWL_WIFI_FOUND_PEER 10 /* Server response to the client */ +#define RWL_ACTION_WIFI_FRAG_TYPE 85 /* Fragment indicator for receiver */ + +#define PROXD_AF_TYPE 11 /* Wifi proximity action frame type */ +#define BRCM_RELMACST_AF_TYPE 12 /* RMC action frame type */ + + +/* brcm syscap_ie cap */ +#define BRCM_SYSCAP_WET_TUNNEL 0x0100 /* Device with WET_TUNNEL support */ + +#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ + +/* BRCM info element */ +BWL_PRE_PACKED_STRUCT struct brcm_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; + uint8 ver; /* type/ver of this IE */ + uint8 assoc; /* # of assoc STAs */ + uint8 flags; /* misc flags */ + uint8 flags1; /* misc flags */ + uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ +} BWL_POST_PACKED_STRUCT; +typedef struct brcm_ie brcm_ie_t; +#define BRCM_IE_LEN 11 /* BRCM IE length */ +#define BRCM_IE_VER 2 /* BRCM IE version */ +#define BRCM_IE_LEGACY_AES_VER 1 /* BRCM IE legacy AES version */ + +/* brcm_ie flags */ +#define BRF_LZWDS 0x4 /* lazy wds enabled */ +#define BRF_BLOCKACK 0x8 /* BlockACK capable */ + +/* brcm_ie flags1 */ +#define BRF1_AMSDU 0x1 /* A-MSDU capable */ +#define BRF1_WMEPS 0x4 /* AP is capable of handling WME + PS w/o APSD */ +#define BRF1_PSOFIX 0x8 /* AP has fixed PS mode out-of-order packets */ +#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ +#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ +#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ +#define BRF1_DWDS 0x80 /* DWDS capable */ + +/* Vendor IE structure */ +BWL_PRE_PACKED_STRUCT struct vndr_ie { + uchar id; + uchar len; + uchar oui [3]; + uchar data [1]; /* Variable size data */ +} BWL_POST_PACKED_STRUCT; +typedef struct vndr_ie vndr_ie_t; + +#define VNDR_IE_HDR_LEN 2 /* id + len field */ +#define VNDR_IE_MIN_LEN 3 /* size of the oui field */ +#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) + +#define VNDR_IE_MAX_LEN 255 /* vendor IE max length, without ID and len */ + +/* BRCM PROP DEVICE PRIMARY MAC ADDRESS IE */ +BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { + uchar id; + uchar len; + uchar oui[3]; + uint8 type; /* type inidicates what follows */ + struct ether_addr ea; /* Device Primary MAC Adrress */ +} BWL_POST_PACKED_STRUCT; +typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; + +#define MEMBER_OF_BRCM_PROP_IE_LEN 10 /* IE max length */ +#define MEMBER_OF_BRCM_PROP_IE_HDRLEN (sizeof(member_of_brcm_prop_ie_t)) +#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 + +/* BRCM Reliable Multicast IE */ +BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; /* type inidicates what follows */ + struct ether_addr ea; /* The ack sender's MAC Adrress */ + struct ether_addr mcast_ea; /* The multicast MAC address */ + uint8 updtmo; /* time interval(second) for client to send null packet to report its rssi */ +} BWL_POST_PACKED_STRUCT; +typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; + +/* IE length */ +/* BRCM_PROP_IE_LEN = sizeof(relmcast_brcm_prop_ie_t)-((sizeof (id) + sizeof (len)))? */ +#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-(2*sizeof(uint8))) + +#define RELMCAST_BRCM_PROP_IE_TYPE 55 + +/* ************* HT definitions. ************* */ +#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ +#define MAX_MCS_NUM (128) /* max mcs number = 128 */ + +BWL_PRE_PACKED_STRUCT struct ht_cap_ie { + uint16 cap; + uint8 params; + uint8 supp_mcs[MCSSET_LEN]; + uint16 ext_htcap; + uint32 txbf_cap; + uint8 as_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_cap_ie ht_cap_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { + uint8 id; + uint8 len; + ht_cap_ie_t ht_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; + +/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ +/* the capability IE is primarily used to convey this nodes abilities */ +BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; + uint8 type; /* type inidicates what follows */ + ht_cap_ie_t cap_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; + +#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ +#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */ +#define HT_CAP_IE_TYPE 51 + +#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ +#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ +#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ +#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ +#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ +#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ +#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ +#define HT_CAP_GF 0x0010 /* Greenfield preamble support */ +#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ +#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ +#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */ +#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ +#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ +#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */ +#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ + +#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ +#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ +#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ +#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ + +#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ +#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ +#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ +#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ + + +#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 +#define HT_CAP_TXBF_CAP_NDP_TX 0x8 +#define HT_CAP_TXBF_CAP_NDP_RX 0x10 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 +#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 +#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 + +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 + +#define HT_CAP_TXBF_FB_TYPE_NONE 0 +#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 +#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 +#define HT_CAP_TXBF_FB_TYPE_BOTH 3 + +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400 +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15 + +#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ +#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ +/* Max AMSDU len - per spec */ +#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) + +#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */ +#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */ + +#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ +#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ +#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ + +/* HT/AMPDU specific define */ +#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */ +#define AMPDU_DENSITY_NONE 0 /* No density requirement */ +#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */ +#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */ +#define AMPDU_DENSITY_1_US 3 /* 1 us density */ +#define AMPDU_DENSITY_2_US 4 /* 2 us density */ +#define AMPDU_DENSITY_4_US 5 /* 4 us density */ +#define AMPDU_DENSITY_8_US 6 /* 8 us density */ +#define AMPDU_DENSITY_16_US 7 /* 16 us density */ +#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */ +#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */ +#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */ +#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */ + +/* AMPDU RX factors for VHT rates */ +#define AMPDU_RX_FACTOR_128K 4 /* max rcv ampdu len (128kb) */ +#define AMPDU_RX_FACTOR_256K 5 /* max rcv ampdu len (256kb) */ +#define AMPDU_RX_FACTOR_512K 6 /* max rcv ampdu len (512kb) */ +#define AMPDU_RX_FACTOR_1024K 7 /* max rcv ampdu len (1024kb) */ + +#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ +#define AMPDU_RX_FACTOR_BASE_PWR 13 /* ampdu factor base for rx len in power of 2 */ + +#define AMPDU_DELIMITER_LEN 4 /* length of ampdu delimiter */ +#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */ + +#define HT_CAP_EXT_PCO 0x0001 +#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 +#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 +#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 +#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 +#define HT_CAP_EXT_HTC 0x0400 +#define HT_CAP_EXT_RD_RESP 0x0800 + +BWL_PRE_PACKED_STRUCT struct ht_add_ie { + uint8 ctl_ch; /* control channel number */ + uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ + uint16 opmode; /* operation mode */ + uint16 misc_bits; /* misc bits */ + uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ +} BWL_POST_PACKED_STRUCT; +typedef struct ht_add_ie ht_add_ie_t; + +/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ +/* the additional IE is primarily used to convey the current BSS configuration */ +BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; + uint8 type; /* indicates what follows */ + ht_add_ie_t add_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_add_ie ht_prop_add_ie_t; + +#define HT_ADD_IE_LEN 22 +#define HT_ADD_IE_TYPE 52 + +/* byte1 defn's */ +#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ +#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */ + +/* opmode defn's */ +#define HT_OPMODE_MASK 0x0003 /* protection mode mask */ +#define HT_OPMODE_SHIFT 0 /* protection mode shift */ +#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */ +#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ +#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ +#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ +#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ +#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ +#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ + +/* misc_bites defn's */ +#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ +#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ +#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */ +#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ +#define HT_PCO_ACTIVE 0x0400 /* PCO active */ +#define HT_PCO_PHASE 0x0800 /* PCO phase */ +#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */ + +/* Tx Burst Limits */ +#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ +#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ + +/* Macros for opmode */ +#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + >> HT_OPMODE_SHIFT) +#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_MIXED) /* mixed mode present */ +#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_HT20IN40) /* 20MHz HT present */ +#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_OPTIONAL) /* Optional protection present */ +#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ + HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */ +#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ + == HT_OPMODE_NONGF) /* non-GF present */ +#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ + == DOT11N_TXBURST) /* Tx Burst present */ +#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ + == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ + +BWL_PRE_PACKED_STRUCT struct obss_params { + uint16 passive_dwell; + uint16 active_dwell; + uint16 bss_widthscan_interval; + uint16 passive_total; + uint16 active_total; + uint16 chanwidth_transition_dly; + uint16 activity_threshold; +} BWL_POST_PACKED_STRUCT; +typedef struct obss_params obss_params_t; + +BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { + uint8 id; + uint8 len; + obss_params_t obss_params; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_ie dot11_obss_ie_t; +#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */ + +/* HT control field */ +#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */ +#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */ +#define HT_CTRL_LA_MAI_SHIFT 2 +#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */ +#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */ +#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */ +#define HT_CTRL_LA_MFSI_SHIFT 6 +#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */ +#define HT_CTRL_LA_MFB_ASELC_SH 9 +#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */ +#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */ +#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */ +#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */ +#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */ +#define HT_CTRL_CSI_STEER_SHIFT 22 +#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */ +#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */ +#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */ +#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */ +#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */ +#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */ +#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */ + +/* ************* VHT definitions. ************* */ + +/* + * VHT Capabilites IE (sec 8.4.2.160) + */ + +BWL_PRE_PACKED_STRUCT struct vht_cap_ie { + uint32 vht_cap_info; + /* supported MCS set - 64 bit field */ + uint16 rx_mcs_map; + uint16 rx_max_rate; + uint16 tx_mcs_map; + uint16 tx_max_rate; +} BWL_POST_PACKED_STRUCT; +typedef struct vht_cap_ie vht_cap_ie_t; + +/* 4B cap_info + 8B supp_mcs */ +#define VHT_CAP_IE_LEN 12 + +/* VHT Capabilities Info field - 32bit - in VHT Cap IE */ +#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 +#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c +#define VHT_CAP_INFO_LDPC 0x00000010 +#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 +#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 +#define VHT_CAP_INFO_TX_STBC 0x00000080 +#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 +#define VHT_CAP_INFO_RX_STBC_SHIFT 8 +#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 +#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 +#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 +#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 +#define VHT_CAP_INFO_TXOPPS 0x00200000 +#define VHT_CAP_INFO_HTCVHT 0x00400000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 +#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 +#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 + +/* VHT Supported MCS Set - 64-bit - in VHT Cap IE */ +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_MCS_MAP_0_7 0 +#define VHT_CAP_MCS_MAP_0_8 1 +#define VHT_CAP_MCS_MAP_0_9 2 +#define VHT_CAP_MCS_MAP_NONE 3 +#define VHT_CAP_MCS_MAP_S 2 /* num bits for 1-stream */ +#define VHT_CAP_MCS_MAP_M 0x3 /* mask for 1-stream */ +/* assumes VHT_CAP_MCS_MAP_NONE is 3 and 2 bits are used for encoding */ +#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff +/* mcsmap with MCS0-9 for Nss = 3 */ +#define VHT_CAP_MCS_MAP_0_9_NSS3 \ + ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) + +#define VHT_CAP_MCS_MAP_NSS_MAX 8 + +/* get mcsmap with given mcs for given nss streams */ +#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ + do { \ + int i; \ + for (i = 1; i <= nss; i++) { \ + VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ + } \ + } while (0) + +/* Map the mcs code to mcs bit map */ +#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ + ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? 0xff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_8) ? 0x1ff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_9) ? 0x3ff : 0) + +/* Map the mcs bit map to mcs code */ +#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ + ((mcs_map == 0xff) ? VHT_CAP_MCS_MAP_0_7 : \ + (mcs_map == 0x1ff) ? VHT_CAP_MCS_MAP_0_8 : \ + (mcs_map == 0x3ff) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) + +/* VHT Capabilities Supported Channel Width */ +typedef enum vht_cap_chan_width { + VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, + VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, + VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 +} vht_cap_chan_width_t; + +/* VHT Capabilities Supported max MPDU LEN (sec 8.4.2.160.2) */ +typedef enum vht_cap_max_mpdu_len { + VHT_CAP_MPDU_MAX_4K = 0x00, + VHT_CAP_MPDU_MAX_8K = 0x01, + VHT_CAP_MPDU_MAX_11K = 0x02 +} vht_cap_max_mpdu_len_t; + +/* Maximum MPDU Length byte counts for the VHT Capabilities advertised limits */ +#define VHT_MPDU_LIMIT_4K 3895 +#define VHT_MPDU_LIMIT_8K 7991 +#define VHT_MPDU_LIMIT_11K 11454 + + +/* + * VHT Operation IE (sec 8.4.2.161) + */ + +BWL_PRE_PACKED_STRUCT struct vht_op_ie { + uint8 chan_width; + uint8 chan1; + uint8 chan2; + uint16 supp_mcs; /* same def as above in vht cap */ +} BWL_POST_PACKED_STRUCT; +typedef struct vht_op_ie vht_op_ie_t; + +/* 3B VHT Op info + 2B Basic MCS */ +#define VHT_OP_IE_LEN 5 + +typedef enum vht_op_chan_width { + VHT_OP_CHAN_WIDTH_20_40 = 0, + VHT_OP_CHAN_WIDTH_80 = 1, + VHT_OP_CHAN_WIDTH_160 = 2, + VHT_OP_CHAN_WIDTH_80_80 = 3 +} vht_op_chan_width_t; + +/* AID length */ +#define AID_IE_LEN 2 +/* + * BRCM vht features IE header + * The header if the fixed part of the IE + * On the 5GHz band this is the entire IE, + * on 2.4GHz the VHT IEs as defined in the 802.11ac + * specification follows + * + * + * VHT features rates bitmap. + * Bit0: 5G MCS 0-9 BW 160MHz + * Bit1: 5G MCS 0-9 support BW 80MHz + * Bit2: 5G MCS 0-9 support BW 20MHz + * Bit3: 2.4G MCS 0-9 support BW 20MHz + * Bits:4-7 Reserved for future use + * + */ +#define VHT_FEATURES_IE_TYPE 0x4 +BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { + uint8 oui[3]; + uint8 type; /* type of this IE = 4 */ + uint8 rate_mask; /* VHT rate mask */ +} BWL_POST_PACKED_STRUCT; +typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; + +/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ +#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) +#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ + (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) +#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ + do { \ + (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ + (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ + } while (0) +#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ + (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) + + +/* ************* WPA definitions. ************* */ +#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ +#define WPA_OUI_LEN 3 /* WPA OUI length */ +#define WPA_OUI_TYPE 1 +#define WPA_VERSION 1 /* WPA version */ +#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ +#define WPA2_OUI_LEN 3 /* WPA2 OUI length */ +#define WPA2_VERSION 1 /* WPA2 version */ +#define WPA2_VERSION_LEN 2 /* WAP2 version length */ + +/* ************* WPS definitions. ************* */ +#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */ +#define WPS_OUI_LEN 3 /* WPS OUI length */ +#define WPS_OUI_TYPE 4 + +/* ************* WFA definitions. ************* */ + +#ifdef P2P_IE_OVRD +#define WFA_OUI MAC_OUI +#else +#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */ +#endif /* P2P_IE_OVRD */ +#define WFA_OUI_LEN 3 /* WFA OUI length */ +#ifdef P2P_IE_OVRD +#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P +#else +#define WFA_OUI_TYPE_TPC 8 +#define WFA_OUI_TYPE_P2P 9 +#endif + +#define WFA_OUI_TYPE_TPC 8 +#ifdef WLTDLS +#define WFA_OUI_TYPE_TPQ 4 /* WFD Tunneled Probe ReQuest */ +#define WFA_OUI_TYPE_TPS 5 /* WFD Tunneled Probe ReSponse */ +#define WFA_OUI_TYPE_WFD 10 +#endif /* WTDLS */ +#define WFA_OUI_TYPE_HS20 0x10 + +/* RSN authenticated key managment suite */ +#define RSN_AKM_NONE 0 /* None (IBSS) */ +#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ +#define RSN_AKM_PSK 2 /* Pre-shared Key */ +#define RSN_AKM_FBT_1X 3 /* Fast Bss transition using 802.1X */ +#define RSN_AKM_FBT_PSK 4 /* Fast Bss transition using Pre-shared Key */ +#define RSN_AKM_MFP_1X 5 /* SHA256 key derivation, using 802.1X */ +#define RSN_AKM_MFP_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ +#define RSN_AKM_TPK 7 /* TPK(TDLS Peer Key) handshake */ + +/* Key related defines */ +#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */ +#define DOT11_MAX_IGTK_KEYS 2 +#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */ +#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */ +#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */ +#define DOT11_WPA_KEY_RSC_LEN 8 /* WPA RSC key len */ + +#define WEP1_KEY_SIZE 5 /* max size of any WEP key */ +#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */ +#define WEP128_KEY_SIZE 13 /* max size of any WEP key */ +#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */ +#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */ +#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */ +#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */ +#define TKIP_KEY_SIZE 32 /* size of any TKIP key, includs MIC keys */ +#define TKIP_TK_SIZE 16 +#define TKIP_MIC_KEY_SIZE 8 +#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */ +#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */ +#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX /* offset to Supplicant MIC RX key */ +#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX /* offset to Supplicant MIC TX key */ +#define AES_KEY_SIZE 16 /* size of AES key */ +#define AES_MIC_SIZE 8 /* size of AES MIC */ +#define BIP_KEY_SIZE 16 /* size of BIP key */ +#define BIP_MIC_SIZE 8 /* sizeof BIP MIC */ + +#define AES_GCM_MIC_SIZE 16 /* size of MIC for 128-bit GCM - .11adD9 */ + +#define AES256_KEY_SIZE 32 /* size of AES 256 key - .11acD5 */ +#define AES256_MIC_SIZE 16 /* size of MIC for 256 bit keys, incl BIP */ + +/* WCN */ +#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ +#define WCN_TYPE 4 /* WCN type */ + +#ifdef BCMWAPI_WPI +#define SMS4_KEY_LEN 16 +#define SMS4_WPI_CBC_MAC_LEN 16 +#endif + +/* 802.11r protocol definitions */ + +/* Mobility Domain IE */ +BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { + uint8 id; + uint8 len; + uint16 mdid; /* Mobility Domain Id */ + uint8 cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_mdid_ie dot11_mdid_ie_t; + +#define FBT_MDID_CAP_OVERDS 0x01 /* Fast Bss transition over the DS support */ +#define FBT_MDID_CAP_RRP 0x02 /* Resource request protocol support */ + +/* Fast Bss Transition IE */ +BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { + uint8 id; + uint8 len; + uint16 mic_control; /* Mic Control */ + uint8 mic[16]; + uint8 anonce[32]; + uint8 snonce[32]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_ie dot11_ft_ie_t; + +#define TIE_TYPE_RESERVED 0 +#define TIE_TYPE_REASSOC_DEADLINE 1 +#define TIE_TYPE_KEY_LIEFTIME 2 +#define TIE_TYPE_ASSOC_COMEBACK 3 +BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { + uint8 id; + uint8 len; + uint8 type; /* timeout interval type */ + uint32 value; /* timeout interval value */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timeout_ie dot11_timeout_ie_t; + +/* GTK ie */ +BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { + uint8 id; + uint8 len; + uint16 key_info; + uint8 key_len; + uint8 rsc[8]; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_gtk_ie dot11_gtk_ie_t; + +/* Management MIC ie */ +BWL_PRE_PACKED_STRUCT struct mmic_ie { + uint8 id; /* IE ID: DOT11_MNG_MMIE_ID */ + uint8 len; /* IE length */ + uint16 key_id; /* key id */ + uint8 ipn[6]; /* ipn */ + uint8 mic[16]; /* mic */ +} BWL_POST_PACKED_STRUCT; +typedef struct mmic_ie mmic_ie_t; + +#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" +#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" + +#ifdef BCMWAPI_WAI +#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */ +#define WAPI_VERSION 1 /* WAPI version */ +#define WAPI_VERSION_LEN 2 /* WAPI version length */ +#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */ +#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */ +#endif /* BCMWAPI_WAI */ + +/* ************* WMM Parameter definitions. ************* */ +#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */ +#define WMM_OUI_LEN 3 /* WMM OUI length */ +#define WMM_OUI_TYPE 2 /* WMM OUT type */ +#define WMM_VERSION 1 +#define WMM_VERSION_LEN 1 + +/* WMM OUI subtype */ +#define WMM_OUI_SUBTYPE_PARAMETER 1 +#define WMM_PARAMETER_IE_LEN 24 + +/* Link Identifier Element */ +BWL_PRE_PACKED_STRUCT struct link_id_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + struct ether_addr tdls_init_mac; + struct ether_addr tdls_resp_mac; +} BWL_POST_PACKED_STRUCT; +typedef struct link_id_ie link_id_ie_t; +#define TDLS_LINK_ID_IE_LEN 18 + +/* Link Wakeup Schedule Element */ +BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { + uint8 id; + uint8 len; + uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */ + uint32 interval; /* in ms bwtween the start of 2 Awake Windows */ + uint32 awake_win_slots; /* in backof slots, duration of Awake Window */ + uint32 max_wake_win; /* in ms, max duration of Awake Window */ + uint16 idle_cnt; /* number of consecutive Awake Windows */ +} BWL_POST_PACKED_STRUCT; +typedef struct wakeup_sch_ie wakeup_sch_ie_t; +#define TDLS_WAKEUP_SCH_IE_LEN 18 + +/* Channel Switch Timing Element */ +BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { + uint8 id; + uint8 len; + uint16 switch_time; /* in ms, time to switch channels */ + uint16 switch_timeout; /* in ms */ +} BWL_POST_PACKED_STRUCT; +typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; +#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 + +/* PTI Control Element */ +BWL_PRE_PACKED_STRUCT struct pti_control_ie { + uint8 id; + uint8 len; + uint8 tid; + uint16 seq_control; +} BWL_POST_PACKED_STRUCT; +typedef struct pti_control_ie pti_control_ie_t; +#define TDLS_PTI_CONTROL_IE_LEN 3 + +/* PU Buffer Status Element */ +BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { + uint8 id; + uint8 len; + uint8 status; +} BWL_POST_PACKED_STRUCT; +typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; +#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 +#define TDLS_PU_BUFFER_STATUS_AC_BK 1 +#define TDLS_PU_BUFFER_STATUS_AC_BE 2 +#define TDLS_PU_BUFFER_STATUS_AC_VI 4 +#define TDLS_PU_BUFFER_STATUS_AC_VO 8 + +/* TDLS Action Field Values */ +#define TDLS_SETUP_REQ 0 +#define TDLS_SETUP_RESP 1 +#define TDLS_SETUP_CONFIRM 2 +#define TDLS_TEARDOWN 3 +#define TDLS_PEER_TRAFFIC_IND 4 +#define TDLS_CHANNEL_SWITCH_REQ 5 +#define TDLS_CHANNEL_SWITCH_RESP 6 +#define TDLS_PEER_PSM_REQ 7 +#define TDLS_PEER_PSM_RESP 8 +#define TDLS_PEER_TRAFFIC_RESP 9 +#define TDLS_DISCOVERY_REQ 10 + +/* 802.11z TDLS Public Action Frame action field */ +#define TDLS_DISCOVERY_RESP 14 + +/* 802.11u GAS action frames */ +#define GAS_REQUEST_ACTION_FRAME 10 +#define GAS_RESPONSE_ACTION_FRAME 11 +#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 +#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 + +/* 802.11u interworking access network options */ +#define IW_ANT_MASK 0x0f +#define IW_INTERNET_MASK 0x10 +#define IW_ASRA_MASK 0x20 +#define IW_ESR_MASK 0x40 +#define IW_UESA_MASK 0x80 + +/* 802.11u interworking access network type */ +#define IW_ANT_PRIVATE_NETWORK 0 +#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 +#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 +#define IW_ANT_FREE_PUBLIC_NETWORK 3 +#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 +#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 +#define IW_ANT_TEST_NETWORK 14 +#define IW_ANT_WILDCARD_NETWORK 15 + +/* 802.11u advertisement protocol */ +#define ADVP_ANQP_PROTOCOL_ID 0 + +/* 802.11u advertisement protocol masks */ +#define ADVP_QRL_MASK 0x7f +#define ADVP_PAME_BI_MASK 0x80 + +/* 802.11u advertisement protocol values */ +#define ADVP_QRL_REQUEST 0x00 +#define ADVP_QRL_RESPONSE 0x7f +#define ADVP_PAME_BI_DEPENDENT 0x00 +#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK + +/* 802.11u ANQP information ID */ +#define ANQP_ID_QUERY_LIST 256 +#define ANQP_ID_CAPABILITY_LIST 257 +#define ANQP_ID_VENUE_NAME_INFO 258 +#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 +#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 +#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 +#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 +#define ANQP_ID_NAI_REALM_LIST 263 +#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 +#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 +#define ANQP_ID_AP_CIVIC_LOCATION 266 +#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 +#define ANQP_ID_DOMAIN_NAME_LIST 268 +#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 +#define ANQP_ID_EMERGENCY_NAI 271 +#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 + +/* 802.11u ANQP OUI */ +#define ANQP_OUI_SUBTYPE 9 + +/* 802.11u venue name */ +#define VENUE_LANGUAGE_CODE_SIZE 3 +#define VENUE_NAME_SIZE 255 + +/* 802.11u venue groups */ +#define VENUE_UNSPECIFIED 0 +#define VENUE_ASSEMBLY 1 +#define VENUE_BUSINESS 2 +#define VENUE_EDUCATIONAL 3 +#define VENUE_FACTORY 4 +#define VENUE_INSTITUTIONAL 5 +#define VENUE_MERCANTILE 6 +#define VENUE_RESIDENTIAL 7 +#define VENUE_STORAGE 8 +#define VENUE_UTILITY 9 +#define VENUE_VEHICULAR 10 +#define VENUE_OUTDOOR 11 + +/* 802.11u network authentication type indicator */ +#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 +#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 +#define NATI_HTTP_HTTPS_REDIRECTION 2 +#define NATI_DNS_REDIRECTION 3 + +/* 802.11u IP address type availability - IPv6 */ +#define IPA_IPV6_SHIFT 0 +#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) +#define IPA_IPV6_NOT_AVAILABLE 0x00 +#define IPA_IPV6_AVAILABLE 0x01 +#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 + +/* 802.11u IP address type availability - IPv4 */ +#define IPA_IPV4_SHIFT 2 +#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) +#define IPA_IPV4_NOT_AVAILABLE 0x00 +#define IPA_IPV4_PUBLIC 0x01 +#define IPA_IPV4_PORT_RESTRICT 0x02 +#define IPA_IPV4_SINGLE_NAT 0x03 +#define IPA_IPV4_DOUBLE_NAT 0x04 +#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 +#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 +#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 + +/* 802.11u NAI realm encoding */ +#define REALM_ENCODING_RFC4282 0 +#define REALM_ENCODING_UTF8 1 + +/* 802.11u IANA EAP method type numbers */ +#define REALM_EAP_TLS 13 +#define REALM_EAP_SIM 18 +#define REALM_EAP_TTLS 21 +#define REALM_EAP_AKA 23 +#define REALM_EAP_PSK 47 +#define REALM_EAP_AKAP 50 +#define REALM_EAP_EXPANDED 254 + +/* 802.11u authentication ID */ +#define REALM_EXPANDED_EAP 1 +#define REALM_NON_EAP_INNER_AUTHENTICATION 2 +#define REALM_INNER_AUTHENTICATION_EAP 3 +#define REALM_EXPANDED_INNER_EAP 4 +#define REALM_CREDENTIAL 5 +#define REALM_TUNNELED_EAP_CREDENTIAL 6 +#define REALM_VENDOR_SPECIFIC_EAP 221 + +/* 802.11u non-EAP inner authentication type */ +#define REALM_PAP 1 +#define REALM_CHAP 2 +#define REALM_MSCHAP 3 +#define REALM_MSCHAPV2 4 + +/* 802.11u credential type */ +#define REALM_SIM 1 +#define REALM_USIM 2 +#define REALM_NFC 3 +#define REALM_HARDWARE_TOKEN 4 +#define REALM_SOFTOKEN 5 +#define REALM_CERTIFICATE 6 +#define REALM_USERNAME_PASSWORD 7 +#define REALM_SERVER_SIDE 8 + +/* 802.11u 3GPP PLMN */ +#define G3PP_GUD_VERSION 0 +#define G3PP_PLMN_LIST_IE 0 + +/* hotspot2.0 indication element (vendor specific) */ +BWL_PRE_PACKED_STRUCT struct hs20_ie { + uint8 oui[3]; + uint8 type; + uint8 config; +} BWL_POST_PACKED_STRUCT; +typedef struct hs20_ie hs20_ie_t; +#define HS20_IE_LEN 5 /* HS20 IE length */ + +/* IEEE 802.11 Annex E */ +typedef enum { + DOT11_2GHZ_20MHZ_CLASS_12 = 81, /* Ch 1-11 */ + DOT11_5GHZ_20MHZ_CLASS_1 = 115, /* Ch 36-48 */ + DOT11_5GHZ_20MHZ_CLASS_2_DFS = 118, /* Ch 52-64 */ + DOT11_5GHZ_20MHZ_CLASS_3 = 124, /* Ch 149-161 */ + DOT11_5GHZ_20MHZ_CLASS_4_DFS = 121, /* Ch 100-140 */ + DOT11_5GHZ_20MHZ_CLASS_5 = 125, /* Ch 149-165 */ + DOT11_5GHZ_40MHZ_CLASS_22 = 116, /* Ch 36-44, lower */ + DOT11_5GHZ_40MHZ_CLASS_23_DFS = 119, /* Ch 52-60, lower */ + DOT11_5GHZ_40MHZ_CLASS_24_DFS = 122, /* Ch 100-132, lower */ + DOT11_5GHZ_40MHZ_CLASS_25 = 126, /* Ch 149-157, lower */ + DOT11_5GHZ_40MHZ_CLASS_27 = 117, /* Ch 40-48, upper */ + DOT11_5GHZ_40MHZ_CLASS_28_DFS = 120, /* Ch 56-64, upper */ + DOT11_5GHZ_40MHZ_CLASS_29_DFS = 123, /* Ch 104-136, upper */ + DOT11_5GHZ_40MHZ_CLASS_30 = 127, /* Ch 153-161, upper */ + DOT11_2GHZ_40MHZ_CLASS_32 = 83, /* Ch 1-7, lower */ + DOT11_2GHZ_40MHZ_CLASS_33 = 84, /* Ch 5-11, upper */ +} dot11_op_class_t; + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h new file mode 100644 index 000000000000..9de5616ab024 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h @@ -0,0 +1,45 @@ +/* + * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: 802.11_bta.h 382882 2013-02-04 23:24:31Z $ +*/ + +#ifndef _802_11_BTA_H_ +#define _802_11_BTA_H_ + +#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58" + +/* BT-AMP 802.11 PAL Protocols */ +#define BTA_PROT_L2CAP 1 +#define BTA_PROT_ACTIVITY_REPORT 2 +#define BTA_PROT_SECURITY 3 +#define BTA_PROT_LINK_SUPERVISION_REQUEST 4 +#define BTA_PROT_LINK_SUPERVISION_REPLY 5 + +/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */ +#define BTA_TYPE_ID_MAC_ADDRESS 1 +#define BTA_TYPE_ID_PREFERRED_CHANNELS 2 +#define BTA_TYPE_ID_CONNECTED_CHANNELS 3 +#define BTA_TYPE_ID_CAPABILITIES 4 +#define BTA_TYPE_ID_VERSION 5 +#endif /* _802_11_bta_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h new file mode 100644 index 000000000000..ded6b7612415 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h @@ -0,0 +1,138 @@ +/* + * 802.11e protocol header file + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: 802.11e.h 382883 2013-02-04 23:26:09Z $ + */ + +#ifndef _802_11e_H_ +#define _802_11e_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + + +/* WME Traffic Specification (TSPEC) element */ +#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ +#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ + +#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ +#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ +#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ +#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ + +BWL_PRE_PACKED_STRUCT struct tsinfo { + uint8 octets[3]; +} BWL_POST_PACKED_STRUCT; + +typedef struct tsinfo tsinfo_t; + +/* 802.11e TSPEC IE */ +typedef BWL_PRE_PACKED_STRUCT struct tspec { + uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ + uint8 type; /* WME_TYPE */ + uint8 subtype; /* WME_SUBTYPE_TSPEC */ + uint8 version; /* WME_VERSION */ + tsinfo_t tsinfo; /* TS Info bit field */ + uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ + uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ + uint32 min_srv_interval; /* Minimum Service Interval (us) */ + uint32 max_srv_interval; /* Maximum Service Interval (us) */ + uint32 inactivity_interval; /* Inactivity Interval (us) */ + uint32 suspension_interval; /* Suspension Interval (us) */ + uint32 srv_start_time; /* Service Start Time (us) */ + uint32 min_data_rate; /* Minimum Data Rate (bps) */ + uint32 mean_data_rate; /* Mean Data Rate (bps) */ + uint32 peak_data_rate; /* Peak Data Rate (bps) */ + uint32 max_burst_size; /* Maximum Burst Size (bytes) */ + uint32 delay_bound; /* Delay Bound (us) */ + uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ + uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ + uint16 medium_time; /* Medium Time (32 us/s periods) */ +} BWL_POST_PACKED_STRUCT tspec_t; + +#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ + +/* ts_info */ +/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ +#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ +#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ +#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ +#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ +#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ +#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ +#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ +#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ +#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ +#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ +#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ +#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ +/* TS info. user priority mask */ +#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) + +/* Macro to get/set bit(s) field in TSINFO */ +#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) +#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ + TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) +#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) +#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ + TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) + +#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ + ((id) << TS_INFO_TID_SHIFT)) +#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ + ((prio) << TS_INFO_USER_PRIO_SHIFT)) + +/* 802.11e QBSS Load IE */ +#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ +#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ + +#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */ + /* DEFVAL dot11ADDTSResponseTimeout = 1s */ + +/* 802.11e ADDTS status code */ +#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ +#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ +#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ +#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ +#ifdef BCMCCX +#define CCX_STATUS_ASSOC_DENIED_UNKNOWN 0xc8 /* unspecified QoS related failure */ +#define CCX_STATUS_ASSOC_DENIED_AP_POLICY 0xc9 /* TSPEC refused due to AP policy */ +#define CCX_STATUS_ASSOC_DENIED_NO_BW 0xca /* Assoc denied due to AP insufficient BW */ +#define CCX_STATUS_ASSOC_DENIED_BAD_PARAM 0xcb /* one or more TSPEC with invalid parameter */ +#endif /* BCMCCX */ + +/* 802.11e DELTS status code */ +#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ +#define DOT11E_STATUS_END_TS 37 /* END TS */ +#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ +#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ + + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11e_CAC_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h new file mode 100644 index 000000000000..efb390bfc09e --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental types and constants relating to 802.1D + * + * $Id: 802.1d.h 382882 2013-02-04 23:24:31Z $ + */ + +#ifndef _802_1_D_ +#define _802_1_D_ + +/* 802.1D priority defines */ +#define PRIO_8021D_NONE 2 /* None = - */ +#define PRIO_8021D_BK 1 /* BK - Background */ +#define PRIO_8021D_BE 0 /* BE - Best-effort */ +#define PRIO_8021D_EE 3 /* EE - Excellent-effort */ +#define PRIO_8021D_CL 4 /* CL - Controlled Load */ +#define PRIO_8021D_VI 5 /* Vi - Video */ +#define PRIO_8021D_VO 6 /* Vo - Voice */ +#define PRIO_8021D_NC 7 /* NC - Network Control */ +#define MAXPRIO 7 /* 0-7 */ +#define NUMPRIO (MAXPRIO + 1) + +#define ALLPRIO -1 /* All prioirty */ + +/* Converts prio to precedence since the numerical value of + * PRIO_8021D_BE and PRIO_8021D_NONE are swapped. + */ +#define PRIO2PREC(prio) \ + (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) + +#endif /* _802_1_D__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h new file mode 100644 index 000000000000..dc1626aa667a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental constants relating to 802.3 + * + * $Id: 802.3.h 417943 2013-08-13 07:54:04Z $ + */ + +#ifndef _802_3_h_ +#define _802_3_h_ + +/* This marks the start of a packed structure section. */ +#include + +#define SNAP_HDR_LEN 6 /* 802.3 SNAP header length */ +#define DOT3_OUI_LEN 3 /* 802.3 oui length */ + +BWL_PRE_PACKED_STRUCT struct dot3_mac_llc_snap_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ + uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ + uint16 length; /* frame length incl header */ + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[DOT3_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 type; /* ethertype */ +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include + +#endif /* #ifndef _802_3_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h new file mode 100644 index 000000000000..4947e533cb8a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h @@ -0,0 +1,113 @@ +/* + * Broadcom Ethernettype protocol definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmeth.h 642536 2016-06-09 02:32:26Z $ + */ + +/* + * Broadcom Ethernet protocol defines + */ + +#ifndef _BCMETH_H_ +#define _BCMETH_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +/* ETHER_TYPE_BRCM is defined in ethernet.h */ + +/* + * Following the 2byte BRCM ether_type is a 16bit BRCM subtype field + * in one of two formats: (only subtypes 32768-65535 are in use now) + * + * subtypes 0-32767: + * 8 bit subtype (0-127) + * 8 bit length in bytes (0-255) + * + * subtypes 32768-65535: + * 16 bit big-endian subtype + * 16 bit big-endian length in bytes (0-65535) + * + * length is the number of additional bytes beyond the 4 or 6 byte header + * + * Reserved values: + * 0 reserved + * 5-15 reserved for iLine protocol assignments + * 17-126 reserved, assignable + * 127 reserved + * 32768 reserved + * 32769-65534 reserved, assignable + * 65535 reserved + */ + +/* + * While adding the subtypes and their specific processing code make sure + * bcmeth_bcm_hdr_t is the first data structure in the user specific data structure definition + */ + +#define BCMILCP_SUBTYPE_RATE 1 +#define BCMILCP_SUBTYPE_LINK 2 +#define BCMILCP_SUBTYPE_CSA 3 +#define BCMILCP_SUBTYPE_LARQ 4 +#define BCMILCP_SUBTYPE_VENDOR 5 +#define BCMILCP_SUBTYPE_FLH 17 + +#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 +#define BCMILCP_SUBTYPE_CERT 32770 +#define BCMILCP_SUBTYPE_SES 32771 + + +#define BCMILCP_BCM_SUBTYPE_RESERVED 0 +#define BCMILCP_BCM_SUBTYPE_EVENT 1 +#define BCMILCP_BCM_SUBTYPE_SES 2 +/* + * The EAPOL type is not used anymore. Instead EAPOL messages are now embedded + * within BCMILCP_BCM_SUBTYPE_EVENT type messages + */ +/* #define BCMILCP_BCM_SUBTYPE_EAPOL 3 */ +#define BCMILCP_BCM_SUBTYPE_DPT 4 +#define BCMILCP_BCM_SUBTYPE_DNGLEVENT 5 + +#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 +#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 + +/* These fields are stored in network order */ +typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr +{ + uint16 subtype; /* Vendor specific..32769 */ + uint16 length; + uint8 version; /* Version is 0 */ + uint8 oui[3]; /* Broadcom OUI */ + /* user specific Data */ + uint16 usr_subtype; +} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; + + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _BCMETH_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h new file mode 100644 index 000000000000..352916ba33a8 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h @@ -0,0 +1,538 @@ +/* + * Broadcom Event protocol definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Dependencies: proto/bcmeth.h + * + * $Id: bcmevent.h 642536 2016-06-09 02:32:26Z $ + * + */ + +/* + * Broadcom Ethernet Events protocol defines + * + */ + +#ifndef _BCMEVENT_H_ +#define _BCMEVENT_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif +/* #include -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */ +#include +#include + +/* This marks the start of a packed structure section. */ +#include + +#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */ +#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */ + +/* flags */ +#define WLC_EVENT_MSG_LINK 0x01 /* link is up */ +#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */ +#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ +#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */ +#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */ + +/* these fields are stored in network order */ + +/* version 1 */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; + uint16 flags; /* see flags below */ + uint32 event_type; /* Message (see below) */ + uint32 status; /* Status code (see below) */ + uint32 reason; /* Reason code (if applicable) */ + uint32 auth_type; /* WLC_E_AUTH */ + uint32 datalen; /* data buf */ + struct ether_addr addr; /* Station address (if applicable) */ + char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ +} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; + +/* the current version */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; + uint16 flags; /* see flags below */ + uint32 event_type; /* Message (see below) */ + uint32 status; /* Status code (see below) */ + uint32 reason; /* Reason code (if applicable) */ + uint32 auth_type; /* WLC_E_AUTH */ + uint32 datalen; /* data buf */ + struct ether_addr addr; /* Station address (if applicable) */ + char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ + uint8 ifidx; /* destination OS i/f index */ + uint8 bsscfgidx; /* source bsscfg index */ +} BWL_POST_PACKED_STRUCT wl_event_msg_t; + +/* used by driver msgs */ +typedef BWL_PRE_PACKED_STRUCT struct bcm_event { + struct ether_header eth; + bcmeth_hdr_t bcm_hdr; + wl_event_msg_t event; + /* data portion follows */ +} BWL_POST_PACKED_STRUCT bcm_event_t; + +/* + * used by host event + * Note: If additional event types are added, it should come on is_wlc_event_frame() as well. + */ +typedef union bcm_event_msg_u { + wl_event_msg_t event; + bcm_dngl_event_msg_t dngl_event; + + /* add new event here */ +} bcm_event_msg_u_t; + +#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) + +/* Event messages */ +#define WLC_E_SET_SSID 0 /* indicates status of set SSID */ +#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */ +#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */ +#define WLC_E_AUTH 3 /* 802.11 AUTH request */ +#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */ +#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */ +#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */ +#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */ +#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */ +#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */ +#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */ +#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */ +#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */ +#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */ +#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */ +#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */ +#define WLC_E_LINK 16 /* generic link indication */ +#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */ +#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */ +#define WLC_E_ROAM 19 /* roam attempt occurred: indicate status & reason */ +#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */ +#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */ +#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */ +#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */ +#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */ +#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */ +#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */ +#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */ +#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */ +#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */ +#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */ +#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */ +#define WLC_E_ROAM_PREP 32 /* before attempting to roam */ +#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */ +#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */ +#define WLC_E_RESET_COMPLETE 35 +#define WLC_E_JOIN_START 36 +#define WLC_E_ROAM_START 37 +#define WLC_E_ASSOC_START 38 +#define WLC_E_IBSS_ASSOC 39 +#define WLC_E_RADIO 40 +#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */ +#define WLC_E_PROBREQ_MSG 44 /* probe request received */ +#define WLC_E_SCAN_CONFIRM_IND 45 +#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */ +#define WLC_E_COUNTRY_CODE_CHANGED 47 +#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */ +#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */ +#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */ +#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ +#define WLC_E_TRACE 52 +#define WLC_E_IF 54 /* I/F change (for dongle host notification) */ +#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */ +#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */ +/* PFN best network batching event, conflict/share with WLC_E_PFN_SCAN_COMPLETE */ +#define WLC_E_PFN_BEST_BATCHING 57 +#define WLC_E_EXTLOG_MSG 58 +#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */ +#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ +#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */ +#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */ +#define WLC_E_CHANNEL_ADOPTED 63 +#define WLC_E_AP_STARTED 64 /* AP started */ +#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */ +#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */ +#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */ +#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */ +#define WLC_E_ESCAN_RESULT 69 /* escan result event */ +#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */ +#define WLC_E_PROBRESP_MSG 71 /* probe response received */ +#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */ +#define WLC_E_DCS_REQUEST 73 +#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */ +#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH + * wl_event_rx_frame_data_t header + */ +#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */ +#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */ +#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */ +#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */ +#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */ +#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */ +#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */ +/* PFN BSSID network found event, conflict/share with WLC_E_PFN_SCAN_NONE */ +#define WLC_E_PFN_BSSID_NET_FOUND 82 +#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */ +/* PFN BSSID network lost event, conflict/share with WLC_E_PFN_SCAN_ALLGONE */ +#define WLC_E_PFN_BSSID_NET_LOST 83 +#define WLC_E_GTK_PLUMBED 84 +#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */ +#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */ +#define WLC_E_ASSOC_REQ_IE 87 +#define WLC_E_ASSOC_RESP_IE 88 +#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ +#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */ +#define WLC_E_AUTH_REQ 91 /* authentication request received */ +#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected/disconnected peer */ +#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */ +#define WLC_E_NATIVE 94 /* port-specific event and payload (e.g. NDIS) */ +#define WLC_E_PKTDELAY_IND 95 /* event for tx pkt delay suddently jump */ +#define WLC_E_PSTA_PRIMARY_INTF_IND 99 /* psta primary interface indication */ +#define WLC_E_NAN 100 /* NAN event */ +#define WLC_E_BEACON_FRAME_RX 101 +#define WLC_E_SERVICE_FOUND 102 /* desired service found */ +#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ +#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ +#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ +#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ +#define WLC_E_WNM_STA_SLEEP 107 /* WNM event to notify STA enter sleep mode */ +#define WLC_E_TXFAIL_THRESH 108 /* Indication of MAC tx failures (exhaustion of + * 802.11 retries) exceeding threshold(s) + */ +#define WLC_E_PROXD 109 /* Proximity Detection event */ +#define WLC_E_IBSS_COALESCE 110 /* IBSS Coalescing */ +#define WLC_E_AIBSS_TXFAIL 110 /* TXFAIL event for AIBSS, re using event 110 */ +#define WLC_E_CSA_START_IND 121 +#define WLC_E_CSA_DONE_IND 122 +#define WLC_E_CSA_FAILURE_IND 123 +#define WLC_E_CCA_CHAN_QUAL 124 /* CCA based channel quality report */ +#define WLC_E_BSSID 125 /* to report change in BSSID while roaming */ +#define WLC_E_TX_STAT_ERROR 126 /* tx error indication */ +#define WLC_E_BCMC_CREDIT_SUPPORT 127 /* credit check for BCMC supported */ +#define WLC_E_RSSI_LQM 133 /* Enhancement addition for WLC_E_RSSI */ +#define WLC_E_PFN_GSCAN_FULL_RESULT 134 /* Full probe/beacon (IEs etc) results */ +#define WLC_E_PFN_SWC 135 /* Significant change in rssi of bssids being tracked */ +#define WLC_E_PFN_SCAN_COMPLETE 138 /* PFN completed scan of network list */ +#define WLC_E_RMC_EVENT 139 /* RMC event */ +#define WLC_E_PFN_SSID_EXT 142 /* SSID EXT event */ +#define WLC_E_LAST 143 /* highest val + 1 for range checking */ + +#if (WLC_E_LAST > 143) +#error "WLC_E_LAST: Invalid value for last event; must be <= 140." +#endif /* WLC_E_LAST */ + + +/* validate if the event is proper and if valid copy event header to event */ +extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, + bcm_event_msg_u_t *out_event); + +/* Table of event name strings for UIs and debugging dumps */ +typedef struct { + uint event; + const char *name; +} bcmevent_name_t; + +extern const bcmevent_name_t bcmevent_names[]; +extern const int bcmevent_names_size; + +/* Event status codes */ +#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */ +#define WLC_E_STATUS_FAIL 1 /* operation failed */ +#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */ +#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */ +#define WLC_E_STATUS_ABORT 4 /* operation was aborted */ +#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */ +#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */ +#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */ +#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */ +#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */ +#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */ +#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */ +#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */ +#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */ +#ifdef BCMCCX +#define WLC_E_STATUS_CCXFASTRM 14 /* scan aborted due to CCX fast roam */ +#endif /* BCMCCX */ +#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */ +#define WLC_E_STATUS_ERROR 16 /* request failed due to error */ + +/* roam reason codes */ +#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */ +#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */ +#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ +#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ +#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ + +/* Roam codes used primarily by CCX */ +#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ +#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ +#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ +#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ +#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ +#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ +#define WLC_E_REASON_REQUESTED_ROAM 11 /* roamed due to BSS Mgmt Transition REQ by AP */ + +/* prune reason codes */ +#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ +#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ +#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ +#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ +#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ +#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ +#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ +#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ +#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ +#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ +#ifdef BCMCCX +#define WLC_E_PRUNE_CCXFAST_PREVAP 11 /* CCX FAST ROAM: prune previous AP */ +#endif /* def BCMCCX */ +#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ +#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ +#ifdef BCMCCX +#define WLC_E_PRUNE_CCXFAST_DROAM 14 /* CCX FAST ROAM: prune unqualified AP */ +#endif /* def BCMCCX */ +#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ +#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ +#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ +#ifdef BCMCCX +#define WLC_E_PRUNE_AP_BLOCKED 18 /* prune blocked AP */ +#define WLC_E_PRUNE_NO_DIAG_SUPPORT 19 /* prune due to diagnostic mode not supported */ +#endif /* BCMCCX */ + +/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */ +#define WLC_E_SUP_OTHER 0 /* Other reason */ +#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */ +#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */ +#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */ +#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */ +#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */ +#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */ +#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */ +#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */ +#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */ +#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */ +#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */ +#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */ +#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */ +#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */ +#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */ + +/* Event data for events that include frames received over the air */ +/* WLC_E_PROBRESP_MSG + * WLC_E_P2P_PROBREQ_MSG + * WLC_E_ACTION_FRAME_RX + */ +typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { + uint16 version; + uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */ + int32 rssi; + uint32 mactime; + uint32 rate; +} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; + +#define BCM_RX_FRAME_DATA_VERSION 1 + +/* WLC_E_IF event data */ +typedef struct wl_event_data_if { + uint8 ifidx; /* RTE virtual device index (for dongle) */ + uint8 opcode; /* see I/F opcode */ + uint8 reserved; /* bit mask (WLC_E_IF_FLAGS_XXX ) */ + uint8 bssidx; /* bsscfg index */ + uint8 role; /* see I/F role */ +} wl_event_data_if_t; + +/* opcode in WLC_E_IF event */ +#define WLC_E_IF_ADD 1 /* bsscfg add */ +#define WLC_E_IF_DEL 2 /* bsscfg delete */ +#define WLC_E_IF_CHANGE 3 /* bsscfg role change */ + +/* I/F role code in WLC_E_IF event */ +#define WLC_E_IF_ROLE_STA 0 /* Infra STA */ +#define WLC_E_IF_ROLE_AP 1 /* Access Point */ +#define WLC_E_IF_ROLE_WDS 2 /* WDS link */ +#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ +#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ + +/* WLC_E_RSSI event data */ +typedef struct wl_event_data_rssi { + int32 rssi; + int32 snr; + int32 noise; +} wl_event_data_rssi_t; + +/* WLC_E_IF flag */ +#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 /* no host I/F creation needed */ + +/* Reason codes for LINK */ +#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */ +#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */ +#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */ +#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */ + +/* reason codes for WLC_E_OVERLAY_REQ event */ +#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */ +#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */ + +/* reason codes for WLC_E_TDLS_PEER_EVENT event */ +#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */ +#define WLC_E_TDLS_PEER_CONNECTED 1 +#define WLC_E_TDLS_PEER_DISCONNECTED 2 + +#ifdef WLTDLS +/* TDLS Action Category code */ +#define TDLS_AF_CATEGORY 12 +/* Wi-Fi Display (WFD) Vendor Specific Category */ +/* used for WFD Tunneled Probe Request and Response */ +#define TDLS_VENDOR_SPECIFIC 127 +/* TDLS Action Field Values */ +#define TDLS_ACTION_SETUP_REQ 0 +#define TDLS_ACTION_SETUP_RESP 1 +#define TDLS_ACTION_SETUP_CONFIRM 2 +#define TDLS_ACTION_TEARDOWN 3 +#define WLAN_TDLS_SET_PROBE_WFD_IE 11 +#define WLAN_TDLS_SET_SETUP_WFD_IE 12 +#endif + +/* reason codes for WLC_E_RMC_EVENT event */ +#define WLC_E_REASON_RMC_NONE 0 +#define WLC_E_REASON_RMC_AR_LOST 1 +#define WLC_E_REASON_RMC_AR_NO_ACK 2 + + +/* GAS event data */ +typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { + uint16 channel; /* channel of GAS protocol */ + uint8 dialog_token; /* GAS dialog token */ + uint8 fragment_id; /* fragment id */ + uint16 status_code; /* status code on GAS completion */ + uint16 data_len; /* length of data to follow */ + uint8 data[1]; /* variable length specified by data_len */ +} BWL_POST_PACKED_STRUCT wl_event_gas_t; + +/* service discovery TLV */ +typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { + uint16 length; /* length of response_data */ + uint8 protocol; /* service protocol type */ + uint8 transaction_id; /* service transaction id */ + uint8 status_code; /* status code */ + uint8 data[1]; /* response data */ +} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; + +/* service discovery event data */ +typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { + uint16 channel; /* channel */ + uint8 count; /* number of tlvs */ + wl_sd_tlv_t tlv[1]; /* service discovery TLV */ +} BWL_POST_PACKED_STRUCT wl_event_sd_t; + +/* Reason codes for WLC_E_PROXD */ +#define WLC_E_PROXD_FOUND 1 /* Found a proximity device */ +#define WLC_E_PROXD_GONE 2 /* Lost a proximity device */ +#define WLC_E_PROXD_START 3 /* used by: target */ +#define WLC_E_PROXD_STOP 4 /* used by: target */ +#define WLC_E_PROXD_COMPLETED 5 /* used by: initiator completed */ +#define WLC_E_PROXD_ERROR 6 /* used by both initiator and target */ +#define WLC_E_PROXD_COLLECT_START 7 /* used by: target & initiator */ +#define WLC_E_PROXD_COLLECT_STOP 8 /* used by: target */ +#define WLC_E_PROXD_COLLECT_COMPLETED 9 /* used by: initiator completed */ +#define WLC_E_PROXD_COLLECT_ERROR 10 /* used by both initiator and target */ +#define WLC_E_PROXD_NAN_EVENT 11 /* used by both initiator and target */ + +/* proxd_event data */ +typedef struct ftm_sample { + uint32 value; /* RTT in ns */ + int8 rssi; /* RSSI */ +} ftm_sample_t; + +typedef BWL_PRE_PACKED_STRUCT struct proxd_event_data { + uint16 ver; /* version */ + uint16 mode; /* mode: target/initiator */ + uint16 method; /* method: rssi/TOF/AOA */ + uint8 err_code; /* error classification */ + uint8 TOF_type; /* one way or two way TOF */ + uint8 OFDM_frame_type; /* legacy or VHT */ + uint8 bandwidth; /* Bandwidth is 20, 40,80, MHZ */ + struct ether_addr peer_mac; /* (e.g for tgt:initiator's */ + uint32 distance; /* dst to tgt, units meter */ + uint32 meanrtt; /* mean delta */ + uint32 modertt; /* Mode delta */ + uint32 medianrtt; /* median RTT */ + uint32 sdrtt; /* Standard deviation of RTT */ + int gdcalcresult; /* Software or Hardware Kind of redundant, but if */ + /* frame type is VHT, then we should do it by hardware */ + int16 avg_rssi; /* avg rssi accroos the ftm frames */ + int16 validfrmcnt; /* Firmware's valid frame counts */ + char *peer_router_info; /* Peer router information if available in TLV, */ + /* We will add this field later */ + int32 var1; /* average of group delay */ + int32 var2; /* average of threshold crossing */ + int32 var3; /* difference between group delay and threshold crossing */ + /* raw Fine Time Measurements (ftm) data */ + uint16 ftm_unit; /* ftm cnt resolution in picoseconds , 6250ps - default */ + uint16 ftm_cnt; /* num of rtd measurments/length in the ftm buffer */ + ftm_sample_t ftm_buff[1]; /* 1 ... ftm_cnt */ +} BWL_POST_PACKED_STRUCT wl_proxd_event_data_t; + + +/* Video Traffic Interference Monitor Event */ +#define INTFER_EVENT_VERSION 1 +#define INTFER_STREAM_TYPE_NONTCP 1 +#define INTFER_STREAM_TYPE_TCP 2 +#define WLINTFER_STATS_NSMPLS 4 +typedef struct wl_intfer_event { + uint16 version; /* version */ + uint16 status; /* status */ + uint8 txfail_histo[WLINTFER_STATS_NSMPLS]; /* txfail histo */ +} wl_intfer_event_t; + +/* WLC_E_PSTA_PRIMARY_INTF_IND event data */ +typedef struct wl_psta_primary_intf_event { + struct ether_addr prim_ea; /* primary intf ether addr */ +} wl_psta_primary_intf_event_t; + +/* ********** NAN protocol events/subevents ********** */ +#define NAN_EVENT_BUFFER_SIZE 512 /* max size */ +/* nan application events to the host driver */ +enum nan_app_events { + WL_NAN_EVENT_START = 1, /* NAN cluster started */ + WL_NAN_EVENT_JOIN = 2, /* Joined to a NAN cluster */ + WL_NAN_EVENT_ROLE = 3, /* Role or State changed */ + WL_NAN_EVENT_SCAN_COMPLETE = 4, + WL_NAN_EVENT_DISCOVERY_RESULT = 5, + WL_NAN_EVENT_REPLIED = 6, + WL_NAN_EVENT_TERMINATED = 7, /* the instance ID will be present in the ev data */ + WL_NAN_EVENT_RECEIVE = 8, + WL_NAN_EVENT_STATUS_CHG = 9, /* generated on any change in nan_mac status */ + WL_NAN_EVENT_MERGE = 10, /* Merged to a NAN cluster */ + WL_NAN_EVENT_STOP = 11, /* NAN stopped */ + WL_NAN_EVENT_INVALID = 12, /* delimiter for max value */ +}; +#define IS_NAN_EVT_ON(var, evt) ((var & (1 << (evt-1))) != 0) +/* ******************* end of NAN section *************** */ + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _BCMEVENT_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h new file mode 100644 index 000000000000..f5ee807c1c96 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h @@ -0,0 +1,231 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental constants relating to IP Protocol + * + * $Id: bcmip.h 457888 2014-02-25 03:34:39Z $ + */ + +#ifndef _bcmip_h_ +#define _bcmip_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + + +/* IPV4 and IPV6 common */ +#define IP_VER_OFFSET 0x0 /* offset to version field */ +#define IP_VER_MASK 0xf0 /* version mask */ +#define IP_VER_SHIFT 4 /* version shift */ +#define IP_VER_4 4 /* version number for IPV4 */ +#define IP_VER_6 6 /* version number for IPV6 */ + +#define IP_VER(ip_body) \ + ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) + +#define IP_PROT_ICMP 0x1 /* ICMP protocol */ +#define IP_PROT_IGMP 0x2 /* IGMP protocol */ +#define IP_PROT_TCP 0x6 /* TCP protocol */ +#define IP_PROT_UDP 0x11 /* UDP protocol type */ +#define IP_PROT_ICMP6 0x3a /* ICMPv6 protocol type */ + +/* IPV4 field offsets */ +#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ +#define IPV4_TOS_OFFSET 1 /* type of service offset */ +#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ +#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ +#define IPV4_PROT_OFFSET 9 /* protocol type offset */ +#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ +#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ +#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ +#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ +#define IPV4_MIN_HEADER_LEN 20 /* Minimum size for an IP header (no options) */ + +/* IPV4 field decodes */ +#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ +#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ + +#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ +#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) + +#define IPV4_ADDR_LEN 4 /* IPV4 address length */ + +#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ + ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) + +#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ + ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) + +#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ +#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ + +#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) + +#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ +#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ + +#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ +#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ +#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ + +#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) + +#define IPV4_FRAG_RESV 0x8000 /* Reserved */ +#define IPV4_FRAG_DONT 0x4000 /* Don't fragment */ +#define IPV4_FRAG_MORE 0x2000 /* More fragments */ +#define IPV4_FRAG_OFFSET_MASK 0x1fff /* Fragment offset */ + +#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ + +/* IPV4 packet formats */ +BWL_PRE_PACKED_STRUCT struct ipv4_addr { + uint8 addr[IPV4_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct ipv4_hdr { + uint8 version_ihl; /* Version and Internet Header Length */ + uint8 tos; /* Type Of Service */ + uint16 tot_len; /* Number of bytes in packet (max 65535) */ + uint16 id; + uint16 frag; /* 3 flag bits and fragment offset */ + uint8 ttl; /* Time To Live */ + uint8 prot; /* Protocol */ + uint16 hdr_chksum; /* IP header checksum */ + uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ + uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ +} BWL_POST_PACKED_STRUCT; + +/* IPV6 field offsets */ +#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ +#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ +#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ +#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ +#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ + +/* IPV6 field decodes */ +#define IPV6_TRAFFIC_CLASS(ipv6_body) \ + (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ + ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) + +#define IPV6_FLOW_LABEL(ipv6_body) \ + (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ + (((uint8 *)(ipv6_body))[2] << 8) | \ + (((uint8 *)(ipv6_body))[3])) + +#define IPV6_PAYLOAD_LEN(ipv6_body) \ + ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ + ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) + +#define IPV6_NEXT_HDR(ipv6_body) \ + (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) + +#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) + +#define IPV6_ADDR_LEN 16 /* IPV6 address length */ + +/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ +#define IP_TOS46(ip_body) \ + (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ + IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) + +#define IP_DSCP46(ip_body) (IP_TOS46(ip_body) >> IPV4_TOS_DSCP_SHIFT); + +/* IPV6 extension headers (options) */ +#define IPV6_EXTHDR_HOP 0 +#define IPV6_EXTHDR_ROUTING 43 +#define IPV6_EXTHDR_FRAGMENT 44 +#define IPV6_EXTHDR_AUTH 51 +#define IPV6_EXTHDR_NONE 59 +#define IPV6_EXTHDR_DEST 60 + +#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ + ((prot) == IPV6_EXTHDR_ROUTING) || \ + ((prot) == IPV6_EXTHDR_FRAGMENT) || \ + ((prot) == IPV6_EXTHDR_AUTH) || \ + ((prot) == IPV6_EXTHDR_NONE) || \ + ((prot) == IPV6_EXTHDR_DEST)) + +#define IPV6_MIN_HLEN 40 + +#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) + +BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { + uint8 nexthdr; + uint8 hdrlen; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { + uint8 nexthdr; + uint8 rsvd; + uint16 frag_off; + uint32 ident; +} BWL_POST_PACKED_STRUCT; + +static INLINE int32 +ipv6_exthdr_len(uint8 *h, uint8 *proto) +{ + uint16 len = 0, hlen; + struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; + + while (IPV6_EXTHDR(eh->nexthdr)) { + if (eh->nexthdr == IPV6_EXTHDR_NONE) + return -1; + else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) + hlen = 8; + else if (eh->nexthdr == IPV6_EXTHDR_AUTH) + hlen = (eh->hdrlen + 2) << 2; + else + hlen = IPV6_EXTHDR_LEN(eh); + + len += hlen; + eh = (struct ipv6_exthdr *)(h + len); + } + + *proto = eh->nexthdr; + return len; +} + +#define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000) + +#define IPV4_MCAST_TO_ETHER_MCAST(ipv4, ether) \ +{ \ + ether[0] = 0x01; \ + ether[1] = 0x00; \ + ether[2] = 0x5E; \ + ether[3] = (ipv4 & 0x7f0000) >> 16; \ + ether[4] = (ipv4 & 0xff00) >> 8; \ + ether[5] = (ipv4 & 0xff); \ +} + +/* This marks the end of a packed structure section. */ +#include + +#define IPV4_ADDR_STR "%d.%d.%d.%d" +#define IPV4_ADDR_TO_STR(addr) ((uint32)addr & 0xff000000) >> 24, \ + ((uint32)addr & 0x00ff0000) >> 16, \ + ((uint32)addr & 0x0000ff00) >> 8, \ + ((uint32)addr & 0x000000ff) + +#endif /* _bcmip_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h new file mode 100644 index 000000000000..86226102e455 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental constants relating to Neighbor Discovery Protocol + * + * $Id: bcmipv6.h 399482 2013-04-30 09:24:37Z $ + */ + +#ifndef _bcmipv6_h_ +#define _bcmipv6_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +/* Extension headers */ +#define IPV6_EXT_HOP 0 +#define IPV6_EXT_ROUTE 43 +#define IPV6_EXT_FRAG 44 +#define IPV6_EXT_DEST 60 +#define IPV6_EXT_ESEC 50 +#define IPV6_EXT_AUTH 51 + +/* Minimum size (extension header "word" length) */ +#define IPV6_EXT_WORD 8 + +/* Offsets for most extension headers */ +#define IPV6_EXT_NEXTHDR 0 +#define IPV6_EXT_HDRLEN 1 + +/* Constants specific to fragmentation header */ +#define IPV6_FRAG_MORE_MASK 0x0001 +#define IPV6_FRAG_MORE_SHIFT 0 +#define IPV6_FRAG_OFFS_MASK 0xfff8 +#define IPV6_FRAG_OFFS_SHIFT 3 + +/* For icmpv6 */ +#define ICMPV6_HEADER_TYPE 0x3A +#define ICMPV6_PKT_TYPE_NS 135 +#define ICMPV6_PKT_TYPE_NA 136 + +#define ICMPV6_ND_OPT_TYPE_TARGET_MAC 2 +#define ICMPV6_ND_OPT_TYPE_SRC_MAC 1 + +#define ICMPV6_ND_OPT_LEN_LINKADDR 1 + +#define ICMPV6_ND_OPT_LEN_LINKADDR 1 + +#define IPV6_VERSION 6 +#define IPV6_HOP_LIMIT 255 + +#define IPV6_ADDR_NULL(a) ((a[0] | a[1] | a[2] | a[3] | a[4] | \ + a[5] | a[6] | a[7] | a[8] | a[9] | \ + a[10] | a[11] | a[12] | a[13] | \ + a[14] | a[15]) == 0) + +#define IPV6_ADDR_LOCAL(a) (((a[0] == 0xfe) && (a[1] & 0x80))? TRUE: FALSE) + +/* IPV6 address */ +BWL_PRE_PACKED_STRUCT struct ipv6_addr { + uint8 addr[16]; +} BWL_POST_PACKED_STRUCT; + + +/* ICMPV6 Header */ +BWL_PRE_PACKED_STRUCT struct icmp6_hdr { + uint8 icmp6_type; + uint8 icmp6_code; + uint16 icmp6_cksum; + BWL_PRE_PACKED_STRUCT union { + uint32 reserved; + BWL_PRE_PACKED_STRUCT struct nd_advt { + uint32 reserved1:5, + override:1, + solicited:1, + router:1, + reserved2:24; + } BWL_POST_PACKED_STRUCT nd_advt; + } BWL_POST_PACKED_STRUCT opt; +} BWL_POST_PACKED_STRUCT; + +/* Ipv6 Header Format */ +BWL_PRE_PACKED_STRUCT struct ipv6_hdr { + uint8 priority:4, + version:4; + uint8 flow_lbl[3]; + uint16 payload_len; + uint8 nexthdr; + uint8 hop_limit; + struct ipv6_addr saddr; + struct ipv6_addr daddr; +} BWL_POST_PACKED_STRUCT; + +/* Neighbor Advertisement/Solicitation Packet Structure */ +BWL_PRE_PACKED_STRUCT struct nd_msg { + struct icmp6_hdr icmph; + struct ipv6_addr target; +} BWL_POST_PACKED_STRUCT; + + +/* Neighibor Solicitation/Advertisement Optional Structure */ +BWL_PRE_PACKED_STRUCT struct nd_msg_opt { + uint8 type; + uint8 len; + uint8 mac_addr[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; + +/* Ipv6 Fragmentation Header */ +BWL_PRE_PACKED_STRUCT struct ipv6_frag { + uint8 nexthdr; + uint8 reserved; + uint16 frag_offset; + uint32 ident; +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include + +static const struct ipv6_addr all_node_ipv6_maddr = { + { 0xff, 0x2, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1 + }}; + +#define IPV6_ISMULTI(a) (a[0] == 0xff) + +#define IPV6_MCAST_TO_ETHER_MCAST(ipv6, ether) \ +{ \ + ether[0] = 0x33; \ + ether[1] = 0x33; \ + ether[2] = ipv6[12]; \ + ether[3] = ipv6[13]; \ + ether[4] = ipv6[14]; \ + ether[5] = ipv6[15]; \ +} + +#endif /* !defined(_bcmipv6_h_) */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h new file mode 100644 index 000000000000..850c5b4e8f2f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h @@ -0,0 +1,90 @@ +/* + * Fundamental constants relating to TCP Protocol + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bcmtcp.h 457888 2014-02-25 03:34:39Z $ + */ + +#ifndef _bcmtcp_h_ +#define _bcmtcp_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + + +#define TCP_SRC_PORT_OFFSET 0 /* TCP source port offset */ +#define TCP_DEST_PORT_OFFSET 2 /* TCP dest port offset */ +#define TCP_SEQ_NUM_OFFSET 4 /* TCP sequence number offset */ +#define TCP_ACK_NUM_OFFSET 8 /* TCP acknowledgement number offset */ +#define TCP_HLEN_OFFSET 12 /* HLEN and reserved bits offset */ +#define TCP_FLAGS_OFFSET 13 /* FLAGS and reserved bits offset */ +#define TCP_CHKSUM_OFFSET 16 /* TCP body checksum offset */ + +#define TCP_PORT_LEN 2 /* TCP port field length */ + +/* 8bit TCP flag field */ +#define TCP_FLAG_URG 0x20 +#define TCP_FLAG_ACK 0x10 +#define TCP_FLAG_PSH 0x08 +#define TCP_FLAG_RST 0x04 +#define TCP_FLAG_SYN 0x02 +#define TCP_FLAG_FIN 0x01 + +#define TCP_HLEN_MASK 0xf000 +#define TCP_HLEN_SHIFT 12 + +/* These fields are stored in network order */ +BWL_PRE_PACKED_STRUCT struct bcmtcp_hdr +{ + uint16 src_port; /* Source Port Address */ + uint16 dst_port; /* Destination Port Address */ + uint32 seq_num; /* TCP Sequence Number */ + uint32 ack_num; /* TCP Sequence Number */ + uint16 hdrlen_rsvd_flags; /* Header length, reserved bits and flags */ + uint16 tcpwin; /* TCP window */ + uint16 chksum; /* Segment checksum with pseudoheader */ + uint16 urg_ptr; /* Points to seq-num of byte following urg data */ +} BWL_POST_PACKED_STRUCT; + +#define TCP_MIN_HEADER_LEN 20 + +#define TCP_HDRLEN_MASK 0xf0 +#define TCP_HDRLEN_SHIFT 4 +#define TCP_HDRLEN(hdrlen) (((hdrlen) & TCP_HDRLEN_MASK) >> TCP_HDRLEN_SHIFT) + +#define TCP_FLAGS_MASK 0x1f +#define TCP_FLAGS(hdrlen) ((hdrlen) & TCP_FLAGS_MASK) + +/* This marks the end of a packed structure section. */ +#include + +/* To address round up by 32bit. */ +#define IS_TCPSEQ_GE(a, b) ((a - b) < NBITVAL(31)) /* a >= b */ +#define IS_TCPSEQ_LE(a, b) ((b - a) < NBITVAL(31)) /* a =< b */ +#define IS_TCPSEQ_GT(a, b) !IS_TCPSEQ_LE(a, b) /* a > b */ +#define IS_TCPSEQ_LT(a, b) !IS_TCPSEQ_GE(a, b) /* a < b */ + +#endif /* #ifndef _bcmtcp_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h new file mode 100644 index 000000000000..f1ea2909971c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h @@ -0,0 +1,441 @@ +/* + * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: bt_amp_hci.h 382882 2013-02-04 23:24:31Z $ +*/ + +#ifndef _bt_amp_hci_h +#define _bt_amp_hci_h + +/* This marks the start of a packed structure section. */ +#include + + +/* AMP HCI CMD packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd { + uint16 opcode; + uint8 plen; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT amp_hci_cmd_t; + +#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms) +#define HCI_CMD_DATA_SIZE 255 + +/* AMP HCI CMD opcode layout */ +#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF)) +#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F)) +#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF) + +/* AMP HCI command opcodes */ +#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001) +#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002) +#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003) +#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009) +#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A) +#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B) +#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035) +#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036) +#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037) +#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038) +#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039) +#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A) +#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B) +#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C) +#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067) +#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069) +#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A) +#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B) +#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003) +#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015) +#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016) +#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036) +#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037) +#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F) +#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061) +#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062) +#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063) +#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064) +#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065) +#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001) +#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002) +#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005) +#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A) + +/* AMP HCI command parameters */ +typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms { + uint8 plh; + uint8 offset[2]; /* length so far */ + uint8 max_remote[2]; +} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms { + uint8 plh; + uint8 offset[2]; + uint8 len[2]; + uint8 frag[1]; +} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms { + uint8 plh; + uint8 key_length; + uint8 key_type; + uint8 key[1]; +} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms { + uint8 plh; + uint8 reason; +} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms { + uint8 plh; + uint8 txflow[16]; + uint8 rxflow[16]; +} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec { + uint8 id; + uint8 service_type; + uint8 max_sdu[2]; + uint8 sdu_ia_time[4]; + uint8 access_latency[4]; + uint8 flush_timeout[4]; +} BWL_POST_PACKED_STRUCT ext_flow_spec_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms { + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms { + uint8 llh[2]; + uint8 txflow[16]; + uint8 rxflow[16]; +} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct plh_pad { + uint8 plh; + uint8 pad; +} BWL_POST_PACKED_STRUCT plh_pad_t; + +typedef BWL_PRE_PACKED_STRUCT union hci_handle { + uint16 bredr; + plh_pad_t amp; +} BWL_POST_PACKED_STRUCT hci_handle_t; + +typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms { + hci_handle_t handle; + uint8 timeout[2]; +} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms { + uint8 llh[2]; + uint8 befto[4]; +} BWL_POST_PACKED_STRUCT befto_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms { + uint8 plh; + uint8 srm; +} BWL_POST_PACKED_STRUCT srm_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms { + uint8 ld_aware; + uint8 ld[2]; + uint8 ld_opts; + uint8 l_opts; +} BWL_POST_PACKED_STRUCT ld_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms { + uint8 llh[2]; + uint8 packet_type; +} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t; + +/* Generic AMP extended flow spec service types */ +#define EFS_SVCTYPE_NO_TRAFFIC 0 +#define EFS_SVCTYPE_BEST_EFFORT 1 +#define EFS_SVCTYPE_GUARANTEED 2 + +/* AMP HCI event packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event { + uint8 ecode; + uint8 plen; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT amp_hci_event_t; + +#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms) + +/* AMP HCI event codes */ +#define HCI_Command_Complete 0x0E +#define HCI_Command_Status 0x0F +#define HCI_Flush_Occurred 0x11 +#define HCI_Enhanced_Flush_Complete 0x39 +#define HCI_Physical_Link_Complete 0x40 +#define HCI_Channel_Select 0x41 +#define HCI_Disconnect_Physical_Link_Complete 0x42 +#define HCI_Logical_Link_Complete 0x45 +#define HCI_Disconnect_Logical_Link_Complete 0x46 +#define HCI_Flow_Spec_Modify_Complete 0x47 +#define HCI_Number_of_Completed_Data_Blocks 0x48 +#define HCI_Short_Range_Mode_Change_Complete 0x4C +#define HCI_Status_Change_Event 0x4D +#define HCI_Vendor_Specific 0xFF + +/* AMP HCI event mask bit positions */ +#define HCI_Physical_Link_Complete_Event_Mask 0x0001 +#define HCI_Channel_Select_Event_Mask 0x0002 +#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004 +#define HCI_Logical_Link_Complete_Event_Mask 0x0020 +#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040 +#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080 +#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100 +#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000 +#define HCI_Status_Change_Event_Mask 0x2000 +#define HCI_All_Event_Mask 0x31e7 +/* AMP HCI event parameters */ +typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms { + uint8 status; + uint8 cmdpkts; + uint16 opcode; +} BWL_POST_PACKED_STRUCT cmd_status_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms { + uint8 cmdpkts; + uint16 opcode; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT cmd_complete_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms { + uint16 handle; +} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms { + uint8 status; + uint8 plh; +} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms { + uint8 status; + uint8 plh; + uint16 len; + uint8 frag[1]; +} BWL_POST_PACKED_STRUCT read_local_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms { + uint8 status; + uint8 AMP_status; + uint32 bandwidth; + uint32 gbandwidth; + uint32 latency; + uint32 PDU_size; + uint8 ctrl_type; + uint16 PAL_cap; + uint16 AMP_ASSOC_len; + uint32 max_flush_timeout; + uint32 be_flush_timeout; +} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms { + uint8 status; + uint16 llh; + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms { + uint8 status; + uint16 llh; + uint8 reason; +} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms { + uint8 status; + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms { + uint8 status; + uint16 llh; +} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms { + uint8 status; + uint8 plh; +} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms { + uint8 status; + uint8 plh; + uint8 reason; +} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms { + uint8 status; + hci_handle_t handle; + uint16 timeout; +} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms { + uint8 status; + uint16 timeout; +} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms { + uint8 status; + uint16 ACL_pkt_len; + uint16 data_block_len; + uint16 data_block_num; +} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct data_blocks { + uint16 handle; + uint16 pkts; + uint16 blocks; +} BWL_POST_PACKED_STRUCT data_blocks_t; + +typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms { + uint16 num_blocks; + uint8 num_handles; + data_blocks_t completed[1]; +} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms { + uint8 status; + uint32 befto; +} BWL_POST_PACKED_STRUCT befto_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms { + uint8 status; + uint8 plh; + uint8 srm; +} BWL_POST_PACKED_STRUCT srm_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms { + uint8 status; + uint8 llh[2]; + uint16 counter; +} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms { + uint8 status; + uint8 llh[2]; +} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms { + uint8 status; + hci_handle_t handle; + uint8 link_quality; +} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms { + uint8 status; + uint8 ld_aware; + uint8 ld[2]; + uint8 ld_opts; + uint8 l_opts; +} BWL_POST_PACKED_STRUCT ld_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms { + uint16 handle; +} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms { + uint8 len; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms { + uint8 status; + uint8 hci_version; + uint16 hci_revision; + uint8 pal_version; + uint16 mfg_name; + uint16 pal_subversion; +} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t; + +#define MAX_SUPPORTED_CMD_BYTE 64 +typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms { + uint8 status; + uint8 cmd[MAX_SUPPORTED_CMD_BYTE]; +} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms { + uint8 status; + uint8 amp_status; +} BWL_POST_PACKED_STRUCT status_change_evt_parms_t; + +/* AMP HCI error codes */ +#define HCI_SUCCESS 0x00 +#define HCI_ERR_ILLEGAL_COMMAND 0x01 +#define HCI_ERR_NO_CONNECTION 0x02 +#define HCI_ERR_MEMORY_FULL 0x07 +#define HCI_ERR_CONNECTION_TIMEOUT 0x08 +#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 +#define HCI_ERR_CONNECTION_EXISTS 0x0B +#define HCI_ERR_CONNECTION_DISALLOWED 0x0C +#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10 +#define HCI_ERR_UNSUPPORTED_VALUE 0x11 +#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 +#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16 +#define HCI_ERR_UNSPECIFIED 0x1F +#define HCI_ERR_UNIT_KEY_USED 0x26 +#define HCI_ERR_QOS_REJECTED 0x2D +#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 +#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39 +#define HCI_ERR_CHANNEL_MOVE 0xFF + +/* AMP HCI ACL Data packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data { + uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */ + uint16 dlen; /* data total length */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t; + +#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data) + +#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14) +#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12) + +#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff) +#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12) + +/* AMP Activity Report packet formats */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report { + uint8 ScheduleKnown; + uint8 NumReports; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t; + +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple { + uint32 StartTime; + uint32 Duration; + uint32 Periodicity; +} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t; + +#define HCI_AR_SCHEDULE_KNOWN 0x01 + + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _bt_amp_hci_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h new file mode 100644 index 000000000000..549566e58950 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h @@ -0,0 +1,98 @@ +/* + * Broadcom Event protocol definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Dependencies: proto/bcmeth.h + * + * $Id: dnglevent.h $ + * + */ + +/* + * Broadcom dngl Ethernet Events protocol defines + * + */ + +#ifndef _DNGLEVENT_H_ +#define _DNGLEVENT_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif +#include + +/* This marks the start of a packed structure section. */ +#include +#define BCM_DNGL_EVENT_MSG_VERSION 1 +#define DNGL_E_SOCRAM_IND 0x2 +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; /* Current version is 1 */ + uint16 reserved; /* reserved for any future extension */ + uint16 event_type; /* DNGL_E_SOCRAM_IND */ + uint16 datalen; /* Length of the event payload */ +} BWL_POST_PACKED_STRUCT bcm_dngl_event_msg_t; + +typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_event { + struct ether_header eth; + bcmeth_hdr_t bcm_hdr; + bcm_dngl_event_msg_t dngl_event; + /* data portion follows */ +} BWL_POST_PACKED_STRUCT bcm_dngl_event_t; + + +/* SOCRAM_IND type tags */ +#define SOCRAM_IND_ASSRT_TAG 0x1 +#define SOCRAM_IND_TAG_HEALTH_CHECK 0x2 +typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_socramind { + uint16 tag; /* data tag */ + uint16 length; /* data length */ + uint8 value[1]; /* data value with variable length specified by length */ +} BWL_POST_PACKED_STRUCT bcm_dngl_socramind_t; + +/* Health check top level module tags */ +#define HEALTH_CHECK_TOP_LEVEL_MODULE_PCIEDEV_RTE 1 +typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_healthcheck { + uint16 top_module_tag; /* top level module tag */ + uint16 top_module_len; /* Type of PCIE issue indication */ + uint8 value[1]; /* data value with variable length specified by length */ +} BWL_POST_PACKED_STRUCT bcm_dngl_healthcheck_t; + +#define HEALTH_CHECK_PCIEDEV_VERSION 1 +#define HEALTH_CHECK_PCIEDEV_FLAG_IN_D3_SHIFT 0 +#define HEALTH_CHECK_PCIEDEV_FLAG_IN_D3_FLAG 1 << HEALTH_CHECK_PCIEDEV_FLAG_IN_D3_SHIFT +/* PCIE Module TAGs */ +#define HEALTH_CHECK_PCIEDEV_INDUCED_IND 0x1 +#define HEALTH_CHECK_PCIEDEV_H2D_DMA_IND 0x2 +#define HEALTH_CHECK_PCIEDEV_D2H_DMA_IND 0x3 +typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_pcie_hc { + uint16 version; /* HEALTH_CHECK_PCIEDEV_VERSION */ + uint16 reserved; + uint16 pcie_err_ind_type; /* PCIE Module TAGs */ + uint16 pcie_flag; + uint32 pcie_control_reg; +} BWL_POST_PACKED_STRUCT bcm_dngl_pcie_hc_t; + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _DNGLEVENT_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h new file mode 100644 index 000000000000..ed3310cd37f9 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h @@ -0,0 +1,211 @@ +/* + * 802.1x EAPOL definitions + * + * See + * IEEE Std 802.1X-2001 + * IEEE 802.1X RADIUS Usage Guidelines + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: eapol.h 528449 2015-01-22 09:38:18Z $ + */ + +#ifndef _eapol_h_ +#define _eapol_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +#include + +/* EAPOL for 802.3/Ethernet */ +typedef BWL_PRE_PACKED_STRUCT struct { + struct ether_header eth; /* 802.3/Ethernet header */ + unsigned char version; /* EAPOL protocol version */ + unsigned char type; /* EAPOL type */ + unsigned short length; /* Length of body */ + unsigned char body[1]; /* Body (optional) */ +} BWL_POST_PACKED_STRUCT eapol_header_t; + +#define EAPOL_HEADER_LEN 18 + +typedef struct { + unsigned char version; /* EAPOL protocol version */ + unsigned char type; /* EAPOL type */ + unsigned short length; /* Length of body */ +} eapol_hdr_t; + +#define EAPOL_HDR_LEN 4 + +/* EAPOL version */ +#define WPA2_EAPOL_VERSION 2 +#define WPA_EAPOL_VERSION 1 +#define LEAP_EAPOL_VERSION 1 +#define SES_EAPOL_VERSION 1 + +/* EAPOL types */ +#define EAP_PACKET 0 +#define EAPOL_START 1 +#define EAPOL_LOGOFF 2 +#define EAPOL_KEY 3 +#define EAPOL_ASF 4 + +/* EAPOL-Key types */ +#define EAPOL_RC4_KEY 1 +#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ +#define EAPOL_WPA_KEY 254 /* WPA */ + +/* RC4 EAPOL-Key header field sizes */ +#define EAPOL_KEY_REPLAY_LEN 8 +#define EAPOL_KEY_IV_LEN 16 +#define EAPOL_KEY_SIG_LEN 16 + +/* RC4 EAPOL-Key */ +typedef BWL_PRE_PACKED_STRUCT struct { + unsigned char type; /* Key Descriptor Type */ + unsigned short length; /* Key Length (unaligned) */ + unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ + unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ + unsigned char index; /* Key Flags & Index */ + unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ + unsigned char key[1]; /* Key (optional) */ +} BWL_POST_PACKED_STRUCT eapol_key_header_t; + +#define EAPOL_KEY_HEADER_LEN 44 + +/* RC4 EAPOL-Key flags */ +#define EAPOL_KEY_FLAGS_MASK 0x80 +#define EAPOL_KEY_BROADCAST 0 +#define EAPOL_KEY_UNICAST 0x80 + +/* RC4 EAPOL-Key index */ +#define EAPOL_KEY_INDEX_MASK 0x7f + +/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ +#define EAPOL_WPA_KEY_REPLAY_LEN 8 +#define EAPOL_WPA_KEY_NONCE_LEN 32 +#define EAPOL_WPA_KEY_IV_LEN 16 +#define EAPOL_WPA_KEY_RSC_LEN 8 +#define EAPOL_WPA_KEY_ID_LEN 8 +#define EAPOL_WPA_KEY_MIC_LEN 16 +#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) +#define EAPOL_WPA_MAX_KEY_SIZE 32 + +/* WPA EAPOL-Key */ +typedef BWL_PRE_PACKED_STRUCT struct { + unsigned char type; /* Key Descriptor Type */ + unsigned short key_info; /* Key Information (unaligned) */ + unsigned short key_len; /* Key Length (unaligned) */ + unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ + unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ + unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ + unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ + unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ + unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ + unsigned short data_len; /* Key Data Length */ + unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ +} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t; + +#define EAPOL_WPA_KEY_LEN 95 + +/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ +#define WPA_KEY_DESC_V1 0x01 +#define WPA_KEY_DESC_V2 0x02 +#define WPA_KEY_DESC_V3 0x03 +#define WPA_KEY_PAIRWISE 0x08 +#define WPA_KEY_INSTALL 0x40 +#define WPA_KEY_ACK 0x80 +#define WPA_KEY_MIC 0x100 +#define WPA_KEY_SECURE 0x200 +#define WPA_KEY_ERROR 0x400 +#define WPA_KEY_REQ 0x800 + +#define WPA_KEY_DESC_V2_OR_V3 WPA_KEY_DESC_V2 + +/* WPA-only KEY KEY_INFO bits */ +#define WPA_KEY_INDEX_0 0x00 +#define WPA_KEY_INDEX_1 0x10 +#define WPA_KEY_INDEX_2 0x20 +#define WPA_KEY_INDEX_3 0x30 +#define WPA_KEY_INDEX_MASK 0x30 +#define WPA_KEY_INDEX_SHIFT 0x04 + +/* 802.11i/WPA2-only KEY KEY_INFO bits */ +#define WPA_KEY_ENCRYPTED_DATA 0x1000 + +/* Key Data encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 type; + uint8 length; + uint8 oui[3]; + uint8 subtype; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; + +#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 + +#define WPA2_KEY_DATA_SUBTYPE_GTK 1 +#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 +#define WPA2_KEY_DATA_SUBTYPE_MAC 3 +#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 +#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 + +/* GTK encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 flags; + uint8 reserved; + uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; + +#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 + +#define WPA2_GTK_INDEX_MASK 0x03 +#define WPA2_GTK_INDEX_SHIFT 0x00 + +#define WPA2_GTK_TRANSMIT 0x04 + +/* IGTK encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 key_id; + uint8 ipn[6]; + uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; + +#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8 + +/* STAKey encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 reserved[2]; + uint8 mac[ETHER_ADDR_LEN]; + uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t; + +#define WPA2_KEY_DATA_PAD 0xdd + + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _eapol_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h new file mode 100644 index 000000000000..68eb83f5330b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h @@ -0,0 +1,220 @@ +/* + * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: ethernet.h 403353 2013-05-20 14:05:33Z $ + */ + +#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ +#define _NET_ETHERNET_H_ + +#ifndef _TYPEDEFS_H_ +#include "typedefs.h" +#endif + +/* This marks the start of a packed structure section. */ +#include + + +/* + * The number of bytes in an ethernet (MAC) address. + */ +#define ETHER_ADDR_LEN 6 + +/* + * The number of bytes in the type field. + */ +#define ETHER_TYPE_LEN 2 + +/* + * The number of bytes in the trailing CRC field. + */ +#define ETHER_CRC_LEN 4 + +/* + * The length of the combined header. + */ +#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) + +/* + * The minimum packet length. + */ +#define ETHER_MIN_LEN 64 + +/* + * The minimum packet user data length. + */ +#define ETHER_MIN_DATA 46 + +/* + * The maximum packet length. + */ +#define ETHER_MAX_LEN 1518 + +/* + * The maximum packet user data length. + */ +#define ETHER_MAX_DATA 1500 + +/* ether types */ +#define ETHER_TYPE_MIN 0x0600 /* Anything less than MIN is a length */ +#define ETHER_TYPE_IP 0x0800 /* IP */ +#define ETHER_TYPE_ARP 0x0806 /* ARP */ +#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */ +#define ETHER_TYPE_IPV6 0x86dd /* IPv6 */ +#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */ +#define ETHER_TYPE_802_1X 0x888e /* 802.1x */ +#ifdef PLC +#define ETHER_TYPE_88E1 0x88e1 /* GIGLE */ +#define ETHER_TYPE_8912 0x8912 /* GIGLE */ +#define ETHER_TYPE_GIGLED 0xffff /* GIGLE */ +#endif /* PLC */ +#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */ +#define ETHER_TYPE_WAI 0x88b4 /* WAI */ +#define ETHER_TYPE_89_0D 0x890d /* 89-0d frame for TDLS */ + +#define ETHER_TYPE_PPP_SES 0x8864 /* PPPoE Session */ + +#define ETHER_TYPE_IAPP_L2_UPDATE 0x6 /* IAPP L2 update frame */ + +/* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */ +#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */ + +/* ether header */ +#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) /* dest address offset */ +#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) /* src address offset */ +#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) /* ether type offset */ + +/* + * A macro to validate a length with + */ +#define ETHER_IS_VALID_LEN(foo) \ + ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ + ((uint8 *)ea)[0] = 0x01; \ + ((uint8 *)ea)[1] = 0x00; \ + ((uint8 *)ea)[2] = 0x5e; \ + ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ + ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ + ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ +} + +#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ +/* + * Structure of a 10Mb/s Ethernet header. + */ +BWL_PRE_PACKED_STRUCT struct ether_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 ether_type; +} BWL_POST_PACKED_STRUCT; + +/* + * Structure of a 48-bit Ethernet address. + */ +BWL_PRE_PACKED_STRUCT struct ether_addr { + uint8 octet[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; +#endif /* !__INCif_etherh Quick and ugly hack for VxWorks */ + +/* + * Takes a pointer, set, test, clear, toggle locally admininistered + * address bit in the 48-bit Ethernet address. + */ +#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) +#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) +#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) +#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) + +/* Takes a pointer, marks unicast address bit in the MAC address */ +#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) + +/* + * Takes a pointer, returns true if a 48-bit multicast address + * (including broadcast, since it is all ones) + */ +#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) + + +/* compare two ethernet addresses - assumes the pointers can be referenced as shorts */ +#define eacmp(a, b) ((((const uint16 *)(a))[0] ^ ((const uint16 *)(b))[0]) | \ + (((const uint16 *)(a))[1] ^ ((const uint16 *)(b))[1]) | \ + (((const uint16 *)(a))[2] ^ ((const uint16 *)(b))[2])) + +#define ether_cmp(a, b) eacmp(a, b) + +/* copy an ethernet address - assumes the pointers can be referenced as shorts */ +#define eacopy(s, d) \ +do { \ + ((uint16 *)(d))[0] = ((const uint16 *)(s))[0]; \ + ((uint16 *)(d))[1] = ((const uint16 *)(s))[1]; \ + ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \ +} while (0) + +#define ether_copy(s, d) eacopy(s, d) + +/* Copy an ethernet address in reverse order */ +#define ether_rcopy(s, d) \ +do { \ + ((uint16 *)(d))[2] = ((uint16 *)(s))[2]; \ + ((uint16 *)(d))[1] = ((uint16 *)(s))[1]; \ + ((uint16 *)(d))[0] = ((uint16 *)(s))[0]; \ +} while (0) + + + +static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; +static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; +static const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; + +#define ETHER_ISBCAST(ea) ((((const uint8 *)(ea))[0] & \ + ((const uint8 *)(ea))[1] & \ + ((const uint8 *)(ea))[2] & \ + ((const uint8 *)(ea))[3] & \ + ((const uint8 *)(ea))[4] & \ + ((const uint8 *)(ea))[5]) == 0xff) +#define ETHER_ISNULLADDR(ea) ((((const uint8 *)(ea))[0] | \ + ((const uint8 *)(ea))[1] | \ + ((const uint8 *)(ea))[2] | \ + ((const uint8 *)(ea))[3] | \ + ((const uint8 *)(ea))[4] | \ + ((const uint8 *)(ea))[5]) == 0) + +#define ETHER_ISNULLDEST(da) ((((const uint16 *)(da))[0] | \ + ((const uint16 *)(da))[1] | \ + ((const uint16 *)(da))[2]) == 0) +#define ETHER_ISNULLSRC(sa) ETHER_ISNULLDEST(sa) + +#define ETHER_MOVE_HDR(d, s) \ +do { \ + struct ether_header t; \ + t = *(struct ether_header *)(s); \ + *(struct ether_header *)(d) = t; \ +} while (0) + +#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0) + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _NET_ETHERNET_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h new file mode 100644 index 000000000000..f7179b6a3cd4 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h @@ -0,0 +1,237 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental types and constants relating to WFA NAN + * (Neighbor Awareness Networking) + * + * $Id$ + */ +#ifndef _NAN_H_ +#define _NAN_H_ + +#include +#include + + +/* This marks the start of a packed structure section. */ +#include + +/* WiFi NAN OUI values */ +#define NAN_OUI WFA_OUI /* WiFi OUI */ +/* For oui_type field identifying the type and version of the NAN IE. */ +#define NAN_OUI_TYPE 0x13 /* Type/Version */ +/* IEEE 802.11 vendor specific information element. (Same as P2P_IE_ID.) */ +#define NAN_IE_ID 0xdd + +/* Same as P2P_PUB_AF_CATEGORY and DOT11_ACTION_CAT_PUBLIC */ +#define NAN_PUB_AF_CATEGORY 0x04 +/* IEEE 802.11 Public Action Frame Vendor Specific. (Same as P2P_PUB_AF_ACTION.) */ +#define NAN_PUB_AF_ACTION 0x09 +/* Number of octents in hash of service name. (Same as P2P_WFDS_HASH_LEN.) */ +#define NAN_SVC_HASH_LEN 6 +/* Size of fixed length part of nan_pub_act_frame_t before attributes. */ +#define NAN_PUB_ACT_FRAME_FIXED_LEN 6 +/* Number of octents in master rank value. */ +#define NAN_MASTER_RANK_LEN 8 +/* NAN public action frame header size */ +#define NAN_PUB_ACT_FRAME_HDR_SIZE (OFFSETOF(nan_pub_act_frame_t, data)) +/* NAN network ID */ +#define NAN_NETWORK_ID "\x51\x6F\x9A\x01\x00\x00" +/* Service Control Type length */ +#define NAN_SVC_CONTROL_TYPE_LEN 2 + +/* Attribute TLV header size */ +#define NAN_ATTR_ID_OFF 0 +#define NAN_ATTR_LEN_OFF 1 +#define NAN_ATTR_DATA_OFF 3 + +#define NAN_ATTR_ID_LEN 1 /* ID field length */ +#define NAN_ATTR_LEN_LEN 2 /* Length field length */ +#define NAN_ATTR_HDR_LEN 3 /* ID + 2-byte length field */ + +/* Vendor-specific public action frame for NAN */ +typedef BWL_PRE_PACKED_STRUCT struct nan_pub_act_frame_s { + /* NAN_PUB_AF_CATEGORY 0x04 */ + uint8 category_id; + /* NAN_PUB_AF_ACTION 0x09 */ + uint8 action_field; + /* NAN_OUI 0x50-6F-9A */ + uint8 oui[DOT11_OUI_LEN]; + /* NAN_OUI_TYPE 0x13 */ + uint8 oui_type; + /* One or more NAN Attributes follow */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT nan_pub_act_frame_t; + +/* NAN attributes as defined in the nan spec */ +enum { + NAN_ATTR_MASTER_IND = 0, + NAN_ATTR_CLUSTER = 1, + NAN_ATTR_SVC_ID_LIST = 2, + NAN_ATTR_SVC_DESCRIPTOR = 3, + NAN_ATTR_CONN_CAP = 4, + NAN_ATTR_INFRA = 5, + NAN_ATTR_P2P = 6, + NAN_ATTR_IBSS = 7, + NAN_ATTR_MESH = 8, + NAN_ATTR_FURTHER_NAN_SD = 9, + NAN_ATTR_FURTHER_AVAIL = 10, + NAN_ATTR_COUNTRY_CODE = 11, + NAN_ATTR_RANGING = 12, + NAN_ATTR_VENDOR_SPECIFIC = 221 +}; + +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ie_s { + uint8 id; /* IE ID: NAN_IE_ID 0xDD */ + uint8 len; /* IE length */ + uint8 oui[DOT11_OUI_LEN]; /* NAN_OUI 50:6F:9A */ + uint8 oui_type; /* NAN_OUI_TYPE 0x13 */ + uint8 attr[1]; /* var len attributes */ +} BWL_POST_PACKED_STRUCT wifi_nan_ie_t; + +#define NAN_IE_HDR_SIZE (OFFSETOF(wifi_nan_ie_t, attr)) + +/* master indication record */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_master_ind_attr_s { + uint8 id; + uint16 len; + uint8 master_preference; + uint8 random_factor; +} BWL_POST_PACKED_STRUCT wifi_nan_master_ind_attr_t; + +/* cluster attr record */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_cluster_attr_s { + uint8 id; + uint16 len; + uint8 amr[NAN_MASTER_RANK_LEN]; + uint8 hop_count; + /* Anchor Master Beacon Transmission Time */ + uint32 ambtt; +} BWL_POST_PACKED_STRUCT wifi_nan_cluster_attr_t; + +/* container for service ID records */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_id_attr_s { + uint8 id; + uint16 len; + uint8 svcid[NAN_SVC_HASH_LEN]; /* 6*len of srvc IDs */ +} BWL_POST_PACKED_STRUCT wifi_nan_svc_id_attr_t; + +/* service_control bitmap for wifi_nan_svc_descriptor_attr_t below */ +#define NAN_SC_PUBLISH 0x0 +#define NAN_SC_SUBSCRIBE 0x1 +#define NAN_SC_FOLLOWUP 0x2 +/* Set to 1 if a Matching Filter field is included in descriptors. */ +#define NAN_SC_MATCHING_FILTER_PRESENT 0x8 +/* Set to 1 if a Service Response Filter field is included in descriptors. */ +#define NAN_SC_SR_FILTER_PRESENT 0x10 +/* Set to 1 if a Service Info field is included in descriptors. */ +#define NAN_SC_SVC_INFO_PRESENT 0x20 +/* range is close proximity only */ +#define NAN_SC_RANGE_LIMITED 0x40 + +/* Service descriptor */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_descriptor_attr_s { + /* Attribute ID - 0x03. */ + uint8 id; + /* Length of the following fields in the attribute */ + uint16 len; + /* Hash of the Service Name */ + uint8 svc_hash[NAN_SVC_HASH_LEN]; + /* Publish or subscribe instance id */ + uint8 instance_id; + /* Requestor Instance ID */ + uint8 requestor_id; + /* Service Control Bitmask. Also determines what data follows. */ + uint8 svc_control; + /* Optional fields follow */ +} BWL_POST_PACKED_STRUCT wifi_nan_svc_descriptor_attr_t; + +/* IBSS attribute */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ibss_attr_s { + /* Attribute ID - 0x07. */ + uint8 id; + /* Length of the following fields in the attribute */ + uint16 len; + /* BSSID of the ibss */ + struct ether_addr bssid; + /* + map control:, bits: + [0-3]: Id for associated further avail map attribute + [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved + [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf? + [7] : reserved + */ + uint8 map_ctrl; + /* avail. intervals bitmap, var len */ + uint8 avail_bmp[1]; +} BWL_POST_PACKED_STRUCT wifi_nan_ibss_attr_t; + +/* Further Availability MAP attr */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_favail_attr_s { + /* Attribute ID - 0x0A. */ + uint8 id; + /* Length of the following fields in the attribute */ + uint16 len; + /* MAP id: val [0..15], values[16-255] reserved */ + uint8 map_id; + /* availibility entry, var len */ + uint8 avil_entry[1]; +} BWL_POST_PACKED_STRUCT wifi_nan_favail_attr_t; + +/* Further Availability MAP attr */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_s { + /* + entry control + [0-1]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; + [2:7] reserved + */ + uint8 entry_ctrl; + /* operating class: freq band etc IEEE 802.11 */ + uint8 opclass; + /* channel number */ + uint8 chan; + uint8 map_id; + /* avail bmp, var len */ + uint8 avail_bmp[1]; +} BWL_POST_PACKED_STRUCT wifi_nan_avail_entry_t; + +/* Map control Field */ +#define NAN_MAPCTRL_IDMASK 0x7 +#define NAN_MAPCTRL_DURSHIFT 3 +#define NAN_MAPCTRL_REPEAT 0x40 + +#define NAN_VENDOR_TYPE_RTT 0 + +/* Vendor Specific Attribute */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_vendor_attr_s { + uint8 id; /* 0xDD */ + uint16 len; /* IE length */ + uint8 oui[DOT11_OUI_LEN]; /* 00-90-4C */ + uint8 type; /* attribute type */ + uint8 attr[1]; /* var len attributes */ +} BWL_POST_PACKED_STRUCT wifi_nan_vendor_attr_t; + +#define NAN_VENDOR_HDR_SIZE (OFFSETOF(wifi_nan_vendor_attr_t, attr)) + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _NAN_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h new file mode 100644 index 000000000000..41c037274901 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h @@ -0,0 +1,608 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) + * + * $Id: p2p.h 444066 2013-12-18 12:49:24Z $ + */ + +#ifndef _P2P_H_ +#define _P2P_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif +#include +#include + +/* This marks the start of a packed structure section. */ +#include + + +/* WiFi P2P OUI values */ +#define P2P_OUI WFA_OUI /* WiFi P2P OUI */ +#define P2P_VER WFA_OUI_TYPE_P2P /* P2P version: 9=WiFi P2P v1.0 */ + +#define P2P_IE_ID 0xdd /* P2P IE element ID */ + +/* WiFi P2P IE */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { + uint8 id; /* IE ID: 0xDD */ + uint8 len; /* IE length */ + uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ + uint8 oui_type; /* Identifies P2P version: P2P_VER */ + uint8 subelts[1]; /* variable length subelements */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_ie wifi_p2p_ie_t; + +#define P2P_IE_FIXED_LEN 6 + +#define P2P_ATTR_ID_OFF 0 +#define P2P_ATTR_LEN_OFF 1 +#define P2P_ATTR_DATA_OFF 3 + +#define P2P_ATTR_ID_LEN 1 /* ID filed length */ +#define P2P_ATTR_LEN_LEN 2 /* length field length */ +#define P2P_ATTR_HDR_LEN 3 /* ID + 2-byte length field spec 1.02 */ + +/* P2P IE Subelement IDs from WiFi P2P Technical Spec 1.00 */ +#define P2P_SEID_STATUS 0 /* Status */ +#define P2P_SEID_MINOR_RC 1 /* Minor Reason Code */ +#define P2P_SEID_P2P_INFO 2 /* P2P Capability (capabilities info) */ +#define P2P_SEID_DEV_ID 3 /* P2P Device ID */ +#define P2P_SEID_INTENT 4 /* Group Owner Intent */ +#define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */ +#define P2P_SEID_CHANNEL 6 /* Listen channel */ +#define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */ +#define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */ +#define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */ +#define P2P_SEID_P2P_MGBTY 10 /* P2P Manageability */ +#define P2P_SEID_CHAN_LIST 11 /* Channel List */ +#define P2P_SEID_ABSENCE 12 /* Notice of Absence */ +#define P2P_SEID_DEV_INFO 13 /* Device Info */ +#define P2P_SEID_GROUP_INFO 14 /* Group Info */ +#define P2P_SEID_GROUP_ID 15 /* Group ID */ +#define P2P_SEID_P2P_IF 16 /* P2P Interface */ +#define P2P_SEID_OP_CHANNEL 17 /* Operating Channel */ +#define P2P_SEID_INVITE_FLAGS 18 /* Invitation Flags */ +#define P2P_SEID_VNDR 221 /* Vendor-specific subelement */ + +#define P2P_SE_VS_ID_SERVICES 0x1b + + +/* WiFi P2P IE subelement: P2P Capability (capabilities info) */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { + uint8 eltId; /* SE ID: P2P_SEID_P2P_INFO */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 dev; /* Device Capability Bitmap */ + uint8 group; /* Group Capability Bitmap */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; + +/* P2P Capability subelement's Device Capability Bitmap bit values */ +#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 /* Service Discovery */ +#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 /* Client Discoverability */ +#define P2P_CAPSE_DEV_CONCURRENT 0x4 /* Concurrent Operation */ +#define P2P_CAPSE_DEV_INFRA_MAN 0x8 /* P2P Infrastructure Managed */ +#define P2P_CAPSE_DEV_LIMIT 0x10 /* P2P Device Limit */ +#define P2P_CAPSE_INVITE_PROC 0x20 /* P2P Invitation Procedure */ + +/* P2P Capability subelement's Group Capability Bitmap bit values */ +#define P2P_CAPSE_GRP_OWNER 0x1 /* P2P Group Owner */ +#define P2P_CAPSE_PERSIST_GRP 0x2 /* Persistent P2P Group */ +#define P2P_CAPSE_GRP_LIMIT 0x4 /* P2P Group Limit */ +#define P2P_CAPSE_GRP_INTRA_BSS 0x8 /* Intra-BSS Distribution */ +#define P2P_CAPSE_GRP_X_CONNECT 0x10 /* Cross Connection */ +#define P2P_CAPSE_GRP_PERSISTENT 0x20 /* Persistent Reconnect */ +#define P2P_CAPSE_GRP_FORMATION 0x40 /* Group Formation */ + + +/* WiFi P2P IE subelement: Group Owner Intent */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { + uint8 eltId; /* SE ID: P2P_SEID_INTENT */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 intent; /* Intent Value 0...15 (0=legacy 15=master only) */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; + +/* WiFi P2P IE subelement: Configuration Timeout */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { + uint8 eltId; /* SE ID: P2P_SEID_CFG_TIMEOUT */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 go_tmo; /* GO config timeout in units of 10 ms */ + uint8 client_tmo; /* Client config timeout in units of 10 ms */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; + +/* WiFi P2P IE subelement: Listen Channel */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_listen_channel_se_s { + uint8 eltId; /* SE ID: P2P_SEID_CHANNEL */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 country[3]; /* Country String */ + uint8 op_class; /* Operating Class */ + uint8 channel; /* Channel */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_listen_channel_se_s wifi_p2p_listen_channel_se_t; + +/* WiFi P2P IE subelement: P2P Group BSSID */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_bssid_se_s { + uint8 eltId; /* SE ID: P2P_SEID_GRP_BSSID */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P group bssid */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; + +/* WiFi P2P IE subelement: P2P Group ID */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { + uint8 eltId; /* SE ID: P2P_SEID_GROUP_ID */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P device address */ + uint8 ssid[1]; /* ssid. device id. variable length */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; + +/* WiFi P2P IE subelement: P2P Interface */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { + uint8 eltId; /* SE ID: P2P_SEID_P2P_IF */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P device address */ + uint8 ifaddrs; /* P2P Interface Address count */ + uint8 ifaddr[1][6]; /* P2P Interface Address list */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; + +/* WiFi P2P IE subelement: Status */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { + uint8 eltId; /* SE ID: P2P_SEID_STATUS */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 status; /* Status Code: P2P_STATSE_* */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; + +/* Status subelement Status Code definitions */ +#define P2P_STATSE_SUCCESS 0 + /* Success */ +#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 + /* Failed, information currently unavailable */ +#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL + /* Old name for above in P2P spec 1.08 and older */ +#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 + /* Failed, incompatible parameters */ +#define P2P_STATSE_FAIL_LIMIT_REACHED 3 + /* Failed, limit reached */ +#define P2P_STATSE_FAIL_INVALID_PARAMS 4 + /* Failed, invalid parameters */ +#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 + /* Failed, unable to accomodate request */ +#define P2P_STATSE_FAIL_PROTO_ERROR 6 + /* Failed, previous protocol error or disruptive behaviour */ +#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 + /* Failed, no common channels */ +#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 + /* Failed, unknown P2P Group */ +#define P2P_STATSE_FAIL_INTENT 9 + /* Failed, both peers indicated Intent 15 in GO Negotiation */ +#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 + /* Failed, incompatible provisioning method */ +#define P2P_STATSE_FAIL_USER_REJECT 11 + /* Failed, rejected by user */ + +/* WiFi P2P IE attribute: Extended Listen Timing */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { + uint8 eltId; /* ID: P2P_SEID_EXT_TIMING */ + uint8 len[2]; /* length not including eltId, len fields */ + uint8 avail[2]; /* availibility period */ + uint8 interval[2]; /* availibility interval */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; + +#define P2P_EXT_MIN 10 /* minimum 10ms */ + +/* WiFi P2P IE subelement: Intended P2P Interface Address */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { + uint8 eltId; /* SE ID: P2P_SEID_INTINTADDR */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* intended P2P interface MAC address */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; + +/* WiFi P2P IE subelement: Channel */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { + uint8 eltId; /* SE ID: P2P_SEID_STATUS */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 band; /* Regulatory Class (band) */ + uint8 channel; /* Channel */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; + + +/* Channel Entry structure within the Channel List SE */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { + uint8 band; /* Regulatory Class (band) */ + uint8 num_channels; /* # of channels in the channel list */ + uint8 channels[WL_NUMCHANNELS]; /* Channel List */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; +#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 + +/* WiFi P2P IE subelement: Channel List */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { + uint8 eltId; /* SE ID: P2P_SEID_CHAN_LIST */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 country[3]; /* Country String */ + uint8 num_entries; /* # of channel entries */ + wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; + /* Channel Entry List */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; + +/* WiFi Primary Device Type structure */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_pri_devtype_s { + uint16 cat_id; /* Category ID */ + uint8 OUI[3]; /* WFA OUI: 0x0050F2 */ + uint8 oui_type; /* WPS_OUI_TYPE */ + uint16 sub_cat_id; /* Sub Category ID */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_pri_devtype_s wifi_p2p_pri_devtype_t; + +/* WiFi P2P Device Info Sub Element Primary Device Type Sub Category + * maximum values for each category + */ +#define P2P_DISE_SUBCATEGORY_MINVAL 1 +#define P2P_DISE_CATEGORY_COMPUTER 1 +#define P2P_DISE_SUBCATEGORY_COMPUTER_MAXVAL 8 +#define P2P_DISE_CATEGORY_INPUT_DEVICE 2 +#define P2P_DISE_SUBCATEGORY_INPUT_DEVICE_MAXVAL 9 +#define P2P_DISE_CATEGORY_PRINTER 3 +#define P2P_DISE_SUBCATEGORY_PRINTER_MAXVAL 5 +#define P2P_DISE_CATEGORY_CAMERA 4 +#define P2P_DISE_SUBCATEGORY_CAMERA_MAXVAL 4 +#define P2P_DISE_CATEGORY_STORAGE 5 +#define P2P_DISE_SUBCATEGORY_STORAGE_MAXVAL 1 +#define P2P_DISE_CATEGORY_NETWORK_INFRA 6 +#define P2P_DISE_SUBCATEGORY_NETWORK_INFRA_MAXVAL 4 +#define P2P_DISE_CATEGORY_DISPLAY 7 +#define P2P_DISE_SUBCATEGORY_DISPLAY_MAXVAL 4 +#define P2P_DISE_CATEGORY_MULTIMEDIA 8 +#define P2P_DISE_SUBCATEGORY_MULTIMEDIA_MAXVAL 6 +#define P2P_DISE_CATEGORY_GAMING 9 +#define P2P_DISE_SUBCATEGORY_GAMING_MAXVAL 5 +#define P2P_DISE_CATEGORY_TELEPHONE 10 +#define P2P_DISE_SUBCATEGORY_TELEPHONE_MAXVAL 5 +#define P2P_DISE_CATEGORY_AUDIO 11 +#define P2P_DISE_SUBCATEGORY_AUDIO_MAXVAL 6 + +/* WiFi P2P IE's Device Info subelement */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { + uint8 eltId; /* SE ID: P2P_SEID_DEVINFO */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P Device MAC address */ + uint16 wps_cfg_meths; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ + uint8 pri_devtype[8]; /* Primary Device Type */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; + +#define P2P_DEV_TYPE_LEN 8 + +/* WiFi P2P IE's Group Info subelement Client Info Descriptor */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { + uint8 len; + uint8 devaddr[ETHER_ADDR_LEN]; /* P2P Device Address */ + uint8 ifaddr[ETHER_ADDR_LEN]; /* P2P Interface Address */ + uint8 devcap; /* Device Capability */ + uint8 cfg_meths[2]; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ + uint8 pridt[P2P_DEV_TYPE_LEN]; /* Primary Device Type */ + uint8 secdts; /* Number of Secondary Device Types */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; + +/* WiFi P2P IE's Device ID subelement */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { + uint8 eltId; + uint8 len[2]; + struct ether_addr addr; /* P2P Device MAC address */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; + +/* WiFi P2P IE subelement: P2P Manageability */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { + uint8 eltId; /* SE ID: P2P_SEID_P2P_MGBTY */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mg_bitmap; /* manageability bitmap */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; +/* mg_bitmap field bit values */ +#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 /* AP supports Managed P2P Device */ + +/* WiFi P2P IE subelement: Group Info */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { + uint8 eltId; /* SE ID: P2P_SEID_GROUP_INFO */ + uint8 len[2]; /* SE length not including eltId, len fields */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; + +/* WiFi IE subelement: Operating Channel */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_op_channel_se_s { + uint8 eltId; /* SE ID: P2P_SEID_OP_CHANNEL */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 country[3]; /* Country String */ + uint8 op_class; /* Operating Class */ + uint8 channel; /* Channel */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_op_channel_se_s wifi_p2p_op_channel_se_t; + +/* WiFi IE subelement: INVITATION FLAGS */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_invite_flags_se_s { + uint8 eltId; /* SE ID: P2P_SEID_INVITE_FLAGS */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 flags; /* Flags */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_invite_flags_se_s wifi_p2p_invite_flags_se_t; + +/* WiFi P2P Action Frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { + uint8 category; /* P2P_AF_CATEGORY */ + uint8 OUI[3]; /* OUI - P2P_OUI */ + uint8 type; /* OUI Type - P2P_VER */ + uint8 subtype; /* OUI Subtype - P2P_AF_* */ + uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ + uint8 elts[1]; /* Variable length information elements. Max size = + * ACTION_FRAME_SIZE - sizeof(this structure) - 1 + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; +#define P2P_AF_CATEGORY 0x7f + +#define P2P_AF_FIXED_LEN 7 + +/* WiFi P2P Action Frame OUI Subtypes */ +#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ +#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ +#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ +#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ + + +/* WiFi P2P Public Action Frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { + uint8 category; /* P2P_PUB_AF_CATEGORY */ + uint8 action; /* P2P_PUB_AF_ACTION */ + uint8 oui[3]; /* P2P_OUI */ + uint8 oui_type; /* OUI type - P2P_VER */ + uint8 subtype; /* OUI subtype - P2P_TYPE_* */ + uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ + uint8 elts[1]; /* Variable length information elements. Max size = + * ACTION_FRAME_SIZE - sizeof(this structure) - 1 + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; +#define P2P_PUB_AF_FIXED_LEN 8 +#define P2P_PUB_AF_CATEGORY 0x04 +#define P2P_PUB_AF_ACTION 0x09 + +/* WiFi P2P Public Action Frame OUI Subtypes */ +#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ +#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ +#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ +#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ +#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ +#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ +#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ +#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ +#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ +#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ + +/* TODO: Stop using these obsolete aliases for P2P_PAF_GON_* */ +#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ +#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP +#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF + +/* WiFi P2P IE subelement: Notice of Absence */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { + uint8 cnt_type; /* Count/Type */ + uint32 duration; /* Duration */ + uint32 interval; /* Interval */ + uint32 start; /* Start Time */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { + uint8 eltId; /* Subelement ID */ + uint8 len[2]; /* Length */ + uint8 index; /* Index */ + uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ + wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; + +#define P2P_NOA_SE_FIXED_LEN 5 + +#define P2P_NOA_SE_MAX_DESC 2 /* max NoA descriptors in presence request */ + +/* cnt_type field values */ +#define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */ +#define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */ +#define P2P_NOA_DESC_TYPE_PREFERRED 1 /* preferred values */ +#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 /* acceptable limits */ + +/* ctw_ops_parms field values */ +#define P2P_NOA_CTW_MASK 0x7f +#define P2P_NOA_OPS_MASK 0x80 +#define P2P_NOA_OPS_SHIFT 7 + +#define P2P_CTW_MIN 10 /* minimum 10TU */ + +/* + * P2P Service Discovery related + */ +#define P2PSD_ACTION_CATEGORY 0x04 + /* Public action frame */ +#define P2PSD_ACTION_ID_GAS_IREQ 0x0a + /* Action value for GAS Initial Request AF */ +#define P2PSD_ACTION_ID_GAS_IRESP 0x0b + /* Action value for GAS Initial Response AF */ +#define P2PSD_ACTION_ID_GAS_CREQ 0x0c + /* Action value for GAS Comback Request AF */ +#define P2PSD_ACTION_ID_GAS_CRESP 0x0d + /* Action value for GAS Comback Response AF */ +#define P2PSD_AD_EID 0x6c + /* Advertisement Protocol IE ID */ +#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 + /* Query Response Length Limit 7 bits plus PAME-BI 1 bit */ +#define P2PSD_ADP_PROTO_ID 0x00 + /* Advertisement Protocol ID. Always 0 for P2P SD */ +#define P2PSD_GAS_OUI P2P_OUI + /* WFA OUI */ +#define P2PSD_GAS_OUI_SUBTYPE P2P_VER + /* OUI Subtype for GAS IE */ +#define P2PSD_GAS_NQP_INFOID 0xDDDD + /* NQP Query Info ID: 56797 */ +#define P2PSD_GAS_COMEBACKDEALY 0x00 + /* Not used in the Native GAS protocol */ + +/* Service Protocol Type */ +typedef enum p2psd_svc_protype { + SVC_RPOTYPE_ALL = 0, + SVC_RPOTYPE_BONJOUR = 1, + SVC_RPOTYPE_UPNP = 2, + SVC_RPOTYPE_WSD = 3, + SVC_RPOTYPE_VENDOR = 255 +} p2psd_svc_protype_t; + +/* Service Discovery response status code */ +typedef enum { + P2PSD_RESP_STATUS_SUCCESS = 0, + P2PSD_RESP_STATUS_PROTYPE_NA = 1, + P2PSD_RESP_STATUS_DATA_NA = 2, + P2PSD_RESP_STATUS_BAD_REQUEST = 3 +} p2psd_resp_status_t; + +/* Advertisement Protocol IE tuple field */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { + uint8 llm_pamebi; /* Query Response Length Limit bit 0-6, set to 0 plus + * Pre-Associated Message Exchange BSSID Independent bit 7, set to 0 + */ + uint8 adp_id; /* Advertisement Protocol ID: 0 for NQP Native Query Protocol */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; + +/* Advertisement Protocol IE */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { + uint8 id; /* IE ID: 0x6c - 108 */ + uint8 len; /* IE length */ + wifi_p2psd_adp_tpl_t adp_tpl; /* Advertisement Protocol Tuple field. Only one + * tuple is defined for P2P Service Discovery + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; + +/* NQP Vendor-specific Content */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { + uint8 oui_subtype; /* OUI Subtype: 0x09 */ + uint16 svc_updi; /* Service Update Indicator */ + uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request, + * wifi_p2psd_qresp_tlv_t type for service response + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; + +/* Service Request TLV */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { + uint16 len; /* Length: 5 plus size of Query Data */ + uint8 svc_prot; /* Service Protocol Type */ + uint8 svc_tscid; /* Service Transaction ID */ + uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; + +/* Query Request Frame, defined in generic format, instead of NQP specific */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { + uint16 info_id; /* Info ID: 0xDDDD */ + uint16 len; /* Length of service request TLV, 5 plus the size of request data */ + uint8 oui[3]; /* WFA OUI: 0x0050F2 */ + uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */ + +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; + +/* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qreq_len; /* Query Request Length */ + uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; + +/* Service Response TLV */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { + uint16 len; /* Length: 5 plus size of Query Data */ + uint8 svc_prot; /* Service Protocol Type */ + uint8 svc_tscid; /* Service Transaction ID */ + uint8 status; /* Value defined in Table 57 of P2P spec. */ + uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; + +/* Query Response Frame, defined in generic format, instead of NQP specific */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { + uint16 info_id; /* Info ID: 0xDDDD */ + uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */ + uint8 oui[3]; /* WFA OUI: 0x0050F2 */ + uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */ + +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; + +/* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { + uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ + uint16 cb_delay; /* GAS Comeback Delay */ + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qresp_len; /* Query Response Length */ + uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; + +/* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { + uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ + uint8 fragment_id; /* Fragmentation ID */ + uint16 cb_delay; /* GAS Comeback Delay */ + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qresp_len; /* Query Response Length */ + uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; + +/* Wi-Fi GAS Public Action Frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { + uint8 category; /* 0x04 Public Action Frame */ + uint8 action; /* 0x6c Advertisement Protocol */ + uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ + uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t + * or wifi_p2psd_gas_iresp_frame_t format + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _P2P_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h new file mode 100644 index 000000000000..35e8180d67dd --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h @@ -0,0 +1,75 @@ +/* + * SD-SPI Protocol Standard + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sdspi.h 382882 2013-02-04 23:24:31Z $ + */ +#ifndef _SD_SPI_H +#define _SD_SPI_H + +#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ +#define SPI_START_S 31 +#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ +#define SPI_DIR_S 30 +#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ +#define SPI_CMD_INDEX_S 24 +#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ +#define SPI_RW_S 23 +#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ +#define SPI_FUNC_S 20 +#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ +#define SPI_RAW_S 19 +#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ +#define SPI_STUFF_S 18 +#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ +#define SPI_BLKMODE_S 19 +#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ +#define SPI_OPCODE_S 18 +#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ +#define SPI_ADDR_S 1 +#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ +#define SPI_STUFF0_S 0 + +#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ +#define SPI_RSP_START_S 7 +#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ +#define SPI_RSP_PARAM_ERR_S 6 +#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ +#define SPI_RSP_RFU5_S 5 +#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ +#define SPI_RSP_FUNC_ERR_S 4 +#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ +#define SPI_RSP_CRC_ERR_S 3 +#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ +#define SPI_RSP_ILL_CMD_S 2 +#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ +#define SPI_RSP_RFU1_S 1 +#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ +#define SPI_RSP_IDLE_S 0 + +/* SD-SPI Protocol Definitions */ +#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ +#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ +#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ +#define SDSPI_START_BIT_MASK 0x80 + +#endif /* _SD_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h new file mode 100644 index 000000000000..fc6e13b6cd48 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h @@ -0,0 +1,95 @@ +/* + * 802.1Q VLAN protocol definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: vlan.h 382883 2013-02-04 23:26:09Z $ + */ + +#ifndef _vlan_h_ +#define _vlan_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +#ifndef VLAN_VID_MASK +#define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */ +#endif + +#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */ +#define VLAN_PRI_SHIFT 13 /* user priority */ + +#define VLAN_PRI_MASK 7 /* 3 bits of priority */ + +#define VLAN_TPID_OFFSET 12 /* offset of tag protocol id field */ +#define VLAN_TCI_OFFSET 14 /* offset of tag ctrl info field */ + +#define VLAN_TAG_LEN 4 +#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */ + +#define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */ + +struct vlan_header { + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ +}; + +struct ethervlan_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ + uint16 ether_type; +}; + +struct dot3_mac_llc_snapvlan_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ + uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ + uint16 length; /* frame length incl header */ + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[3]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ + uint16 ether_type; /* ethertype */ +}; + +#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) + + +/* This marks the end of a packed structure section. */ +#include + +#define ETHERVLAN_MOVE_HDR(d, s) \ +do { \ + struct ethervlan_header t; \ + t = *(struct ethervlan_header *)(s); \ + *(struct ethervlan_header *)(d) = t; \ +} while (0) + +#endif /* _vlan_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h new file mode 100644 index 000000000000..1a3ae0e8a6e1 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h @@ -0,0 +1,214 @@ +/* + * Fundamental types and constants relating to WPA + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wpa.h 384536 2013-02-12 04:13:09Z $ + */ + +#ifndef _proto_wpa_h_ +#define _proto_wpa_h_ + +#include +#include + + +/* This marks the start of a packed structure section. */ +#include + +/* Reason Codes */ + +/* 13 through 23 taken from IEEE Std 802.11i-2004 */ +#define DOT11_RC_INVALID_WPA_IE 13 /* Invalid info. element */ +#define DOT11_RC_MIC_FAILURE 14 /* Michael failure */ +#define DOT11_RC_4WH_TIMEOUT 15 /* 4-way handshake timeout */ +#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 /* Group key update timeout */ +#define DOT11_RC_WPA_IE_MISMATCH 17 /* WPA IE in 4-way handshake differs from + * (re-)assoc. request/probe response + */ +#define DOT11_RC_INVALID_MC_CIPHER 18 /* Invalid multicast cipher */ +#define DOT11_RC_INVALID_UC_CIPHER 19 /* Invalid unicast cipher */ +#define DOT11_RC_INVALID_AKMP 20 /* Invalid authenticated key management protocol */ +#define DOT11_RC_BAD_WPA_VERSION 21 /* Unsupported WPA version */ +#define DOT11_RC_INVALID_WPA_CAP 22 /* Invalid WPA IE capabilities */ +#define DOT11_RC_8021X_AUTH_FAIL 23 /* 802.1X authentication failure */ + +#define WPA2_PMKID_LEN 16 + +/* WPA IE fixed portion */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint8 tag; /* TAG */ + uint8 length; /* TAG length */ + uint8 oui[3]; /* IE OUI */ + uint8 oui_type; /* OUI type */ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT version; /* IE version */ +} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; +#define WPA_IE_OUITYPE_LEN 4 +#define WPA_IE_FIXED_LEN 8 +#define WPA_IE_TAG_FIXED_LEN 6 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 tag; /* TAG */ + uint8 length; /* TAG length */ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT version; /* IE version */ +} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; +#define WPA_RSN_IE_FIXED_LEN 4 +#define WPA_RSN_IE_TAG_FIXED_LEN 2 +typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; + +/* WPA suite/multicast suite */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint8 oui[3]; + uint8 type; +} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; +#define WPA_SUITE_LEN 4 + +/* WPA unicast suite list/key management suite list */ +typedef BWL_PRE_PACKED_STRUCT struct +{ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT count; + wpa_suite_t list[1]; +} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; +#define WPA_IE_SUITE_COUNT_LEN 2 +typedef BWL_PRE_PACKED_STRUCT struct +{ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT count; + wpa_pmkid_t list[1]; +} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; + +/* WPA cipher suites */ +#define WPA_CIPHER_NONE 0 /* None */ +#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */ +#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */ +#define WPA_CIPHER_AES_OCB 3 /* AES (OCB) */ +#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */ +#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */ +#define WPA_CIPHER_BIP 6 /* WEP (104-bit) */ +#define WPA_CIPHER_TPK 7 /* Group addressed traffic not allowed */ +#ifdef BCMCCX +#define WPA_CIPHER_CKIP 8 /* KP with no MIC */ +#define WPA_CIPHER_CKIP_MMH 9 /* KP with MIC ("CKIP/MMH", "CKIP+CMIC") */ +#define WPA_CIPHER_WEP_MMH 10 /* MIC with no KP ("WEP/MMH", "CMIC") */ + +#define IS_CCX_CIPHER(cipher) ((cipher) == WPA_CIPHER_CKIP || \ + (cipher) == WPA_CIPHER_CKIP_MMH || \ + (cipher) == WPA_CIPHER_WEP_MMH) +#endif + +#ifdef BCMWAPI_WAI +#define WAPI_CIPHER_NONE WPA_CIPHER_NONE +#define WAPI_CIPHER_SMS4 11 + +#define WAPI_CSE_WPI_SMS4 1 +#endif /* BCMWAPI_WAI */ + +#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ + (cipher) == WPA_CIPHER_WEP_40 || \ + (cipher) == WPA_CIPHER_WEP_104 || \ + (cipher) == WPA_CIPHER_TKIP || \ + (cipher) == WPA_CIPHER_AES_OCB || \ + (cipher) == WPA_CIPHER_AES_CCM || \ + (cipher) == WPA_CIPHER_TPK) + +#ifdef BCMWAPI_WAI +#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ + (cipher) == WAPI_CSE_WPI_SMS4) + +/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */ +#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ + WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) + +#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ + WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) +#endif /* BCMWAPI_WAI */ + +/* WPA TKIP countermeasures parameters */ +#define WPA_TKIP_CM_DETECT 60 /* multiple MIC failure window (seconds) */ +#define WPA_TKIP_CM_BLOCK 60 /* countermeasures active window (seconds) */ + +/* RSN IE defines */ +#define RSN_CAP_LEN 2 /* Length of RSN capabilities field (2 octets) */ + +/* RSN Capabilities defined in 802.11i */ +#define RSN_CAP_PREAUTH 0x0001 +#define RSN_CAP_NOPAIRWISE 0x0002 +#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C +#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 +#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 +#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 +#define RSN_CAP_1_REPLAY_CNTR 0 +#define RSN_CAP_2_REPLAY_CNTRS 1 +#define RSN_CAP_4_REPLAY_CNTRS 2 +#define RSN_CAP_16_REPLAY_CNTRS 3 +#define RSN_CAP_MFPR 0x0040 +#define RSN_CAP_MFPC 0x0080 +#define RSN_CAP_SPPC 0x0400 +#define RSN_CAP_SPPR 0x0800 + +/* WPA capabilities defined in 802.11i */ +#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS +#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS +#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT +#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK + +/* WPA capabilities defined in 802.11zD9.0 */ +#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) /* bit 9 */ + +/* WPA Specific defines */ +#define WPA_CAP_LEN RSN_CAP_LEN /* Length of RSN capabilities in RSN IE (2 octets) */ +#define WPA_PMKID_CNT_LEN 2 /* Length of RSN PMKID count (2 octests) */ + +#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH + +#define WPA2_PMKID_COUNT_LEN 2 + +#ifdef BCMWAPI_WAI +#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH + +/* Other WAI definition */ +#define WAPI_WAI_REQUEST 0x00F1 +#define WAPI_UNICAST_REKEY 0x00F2 +#define WAPI_STA_AGING 0x00F3 +#define WAPI_MUTIL_REKEY 0x00F4 +#define WAPI_STA_STATS 0x00F5 + +#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */ +#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */ +#endif /* BCMWAPI_WAI */ + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _proto_wpa_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h new file mode 100644 index 000000000000..e3d653ababe8 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h @@ -0,0 +1,379 @@ +/* + * WPS IE definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id$ + */ + +#ifndef _WPS_ +#define _WPS_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Data Element Definitions */ +#define WPS_ID_AP_CHANNEL 0x1001 +#define WPS_ID_ASSOC_STATE 0x1002 +#define WPS_ID_AUTH_TYPE 0x1003 +#define WPS_ID_AUTH_TYPE_FLAGS 0x1004 +#define WPS_ID_AUTHENTICATOR 0x1005 +#define WPS_ID_CONFIG_METHODS 0x1008 +#define WPS_ID_CONFIG_ERROR 0x1009 +#define WPS_ID_CONF_URL4 0x100A +#define WPS_ID_CONF_URL6 0x100B +#define WPS_ID_CONN_TYPE 0x100C +#define WPS_ID_CONN_TYPE_FLAGS 0x100D +#define WPS_ID_CREDENTIAL 0x100E +#define WPS_ID_DEVICE_NAME 0x1011 +#define WPS_ID_DEVICE_PWD_ID 0x1012 +#define WPS_ID_E_HASH1 0x1014 +#define WPS_ID_E_HASH2 0x1015 +#define WPS_ID_E_SNONCE1 0x1016 +#define WPS_ID_E_SNONCE2 0x1017 +#define WPS_ID_ENCR_SETTINGS 0x1018 +#define WPS_ID_ENCR_TYPE 0x100F +#define WPS_ID_ENCR_TYPE_FLAGS 0x1010 +#define WPS_ID_ENROLLEE_NONCE 0x101A +#define WPS_ID_FEATURE_ID 0x101B +#define WPS_ID_IDENTITY 0x101C +#define WPS_ID_IDENTITY_PROOF 0x101D +#define WPS_ID_KEY_WRAP_AUTH 0x101E +#define WPS_ID_KEY_IDENTIFIER 0x101F +#define WPS_ID_MAC_ADDR 0x1020 +#define WPS_ID_MANUFACTURER 0x1021 +#define WPS_ID_MSG_TYPE 0x1022 +#define WPS_ID_MODEL_NAME 0x1023 +#define WPS_ID_MODEL_NUMBER 0x1024 +#define WPS_ID_NW_INDEX 0x1026 +#define WPS_ID_NW_KEY 0x1027 +#define WPS_ID_NW_KEY_INDEX 0x1028 +#define WPS_ID_NEW_DEVICE_NAME 0x1029 +#define WPS_ID_NEW_PWD 0x102A +#define WPS_ID_OOB_DEV_PWD 0x102C +#define WPS_ID_OS_VERSION 0x102D +#define WPS_ID_POWER_LEVEL 0x102F +#define WPS_ID_PSK_CURRENT 0x1030 +#define WPS_ID_PSK_MAX 0x1031 +#define WPS_ID_PUBLIC_KEY 0x1032 +#define WPS_ID_RADIO_ENABLED 0x1033 +#define WPS_ID_REBOOT 0x1034 +#define WPS_ID_REGISTRAR_CURRENT 0x1035 +#define WPS_ID_REGISTRAR_ESTBLSHD 0x1036 +#define WPS_ID_REGISTRAR_LIST 0x1037 +#define WPS_ID_REGISTRAR_MAX 0x1038 +#define WPS_ID_REGISTRAR_NONCE 0x1039 +#define WPS_ID_REQ_TYPE 0x103A +#define WPS_ID_RESP_TYPE 0x103B +#define WPS_ID_RF_BAND 0x103C +#define WPS_ID_R_HASH1 0x103D +#define WPS_ID_R_HASH2 0x103E +#define WPS_ID_R_SNONCE1 0x103F +#define WPS_ID_R_SNONCE2 0x1040 +#define WPS_ID_SEL_REGISTRAR 0x1041 +#define WPS_ID_SERIAL_NUM 0x1042 +#define WPS_ID_SC_STATE 0x1044 +#define WPS_ID_SSID 0x1045 +#define WPS_ID_TOT_NETWORKS 0x1046 +#define WPS_ID_UUID_E 0x1047 +#define WPS_ID_UUID_R 0x1048 +#define WPS_ID_VENDOR_EXT 0x1049 +#define WPS_ID_VERSION 0x104A +#define WPS_ID_X509_CERT_REQ 0x104B +#define WPS_ID_X509_CERT 0x104C +#define WPS_ID_EAP_IDENTITY 0x104D +#define WPS_ID_MSG_COUNTER 0x104E +#define WPS_ID_PUBKEY_HASH 0x104F +#define WPS_ID_REKEY_KEY 0x1050 +#define WPS_ID_KEY_LIFETIME 0x1051 +#define WPS_ID_PERM_CFG_METHODS 0x1052 +#define WPS_ID_SEL_REG_CFG_METHODS 0x1053 +#define WPS_ID_PRIM_DEV_TYPE 0x1054 +#define WPS_ID_SEC_DEV_TYPE_LIST 0x1055 +#define WPS_ID_PORTABLE_DEVICE 0x1056 +#define WPS_ID_AP_SETUP_LOCKED 0x1057 +#define WPS_ID_APP_LIST 0x1058 +#define WPS_ID_EAP_TYPE 0x1059 +#define WPS_ID_INIT_VECTOR 0x1060 +#define WPS_ID_KEY_PROVIDED_AUTO 0x1061 +#define WPS_ID_8021X_ENABLED 0x1062 +#define WPS_ID_WEP_TRANSMIT_KEY 0x1064 +#define WPS_ID_REQ_DEV_TYPE 0x106A + +/* WSC 2.0, WFA Vendor Extension Subelements */ +#define WFA_VENDOR_EXT_ID "\x00\x37\x2A" +#define WPS_WFA_SUBID_VERSION2 0x00 +#define WPS_WFA_SUBID_AUTHORIZED_MACS 0x01 +#define WPS_WFA_SUBID_NW_KEY_SHAREABLE 0x02 +#define WPS_WFA_SUBID_REQ_TO_ENROLL 0x03 +#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME 0x04 + + +/* WCN-NET Windows Rally Vertical Pairing Vendor Extensions */ +#define MS_VENDOR_EXT_ID "\x00\x01\x37" +#define WPS_MS_ID_VPI 0x1001 /* Vertical Pairing Identifier TLV */ +#define WPS_MS_ID_TRANSPORT_UUID 0x1002 /* Transport UUID TLV */ + +/* Vertical Pairing Identifier TLV Definitions */ +#define WPS_MS_VPI_TRANSPORT_NONE 0x00 /* None */ +#define WPS_MS_VPI_TRANSPORT_DPWS 0x01 /* Devices Profile for Web Services */ +#define WPS_MS_VPI_TRANSPORT_UPNP 0x02 /* uPnP */ +#define WPS_MS_VPI_TRANSPORT_SDNWS 0x03 /* Secure Devices Profile for Web Services */ +#define WPS_MS_VPI_NO_PROFILE_REQ 0x00 /* Wi-Fi profile not requested. + * Not supported in Windows 7 + */ +#define WPS_MS_VPI_PROFILE_REQ 0x01 /* Wi-Fi profile requested. */ + +/* sizes of the fixed size elements */ +#define WPS_ID_AP_CHANNEL_S 2 +#define WPS_ID_ASSOC_STATE_S 2 +#define WPS_ID_AUTH_TYPE_S 2 +#define WPS_ID_AUTH_TYPE_FLAGS_S 2 +#define WPS_ID_AUTHENTICATOR_S 8 +#define WPS_ID_CONFIG_METHODS_S 2 +#define WPS_ID_CONFIG_ERROR_S 2 +#define WPS_ID_CONN_TYPE_S 1 +#define WPS_ID_CONN_TYPE_FLAGS_S 1 +#define WPS_ID_DEVICE_PWD_ID_S 2 +#define WPS_ID_ENCR_TYPE_S 2 +#define WPS_ID_ENCR_TYPE_FLAGS_S 2 +#define WPS_ID_FEATURE_ID_S 4 +#define WPS_ID_MAC_ADDR_S 6 +#define WPS_ID_MSG_TYPE_S 1 +#define WPS_ID_SC_STATE_S 1 +#define WPS_ID_RF_BAND_S 1 +#define WPS_ID_OS_VERSION_S 4 +#define WPS_ID_VERSION_S 1 +#define WPS_ID_SEL_REGISTRAR_S 1 +#define WPS_ID_SEL_REG_CFG_METHODS_S 2 +#define WPS_ID_REQ_TYPE_S 1 +#define WPS_ID_RESP_TYPE_S 1 +#define WPS_ID_AP_SETUP_LOCKED_S 1 + +/* WSC 2.0, WFA Vendor Extension Subelements */ +#define WPS_WFA_SUBID_VERSION2_S 1 +#define WPS_WFA_SUBID_NW_KEY_SHAREABLE_S 1 +#define WPS_WFA_SUBID_REQ_TO_ENROLL_S 1 +#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME_S 1 + +/* Association states */ +#define WPS_ASSOC_NOT_ASSOCIATED 0 +#define WPS_ASSOC_CONN_SUCCESS 1 +#define WPS_ASSOC_CONFIG_FAIL 2 +#define WPS_ASSOC_ASSOC_FAIL 3 +#define WPS_ASSOC_IP_FAIL 4 + +/* Authentication types */ +#define WPS_AUTHTYPE_OPEN 0x0001 +#define WPS_AUTHTYPE_WPAPSK 0x0002 /* Deprecated in WSC 2.0 */ +#define WPS_AUTHTYPE_SHARED 0x0004 /* Deprecated in WSC 2.0 */ +#define WPS_AUTHTYPE_WPA 0x0008 /* Deprecated in WSC 2.0 */ +#define WPS_AUTHTYPE_WPA2 0x0010 +#define WPS_AUTHTYPE_WPA2PSK 0x0020 + +/* Config methods */ +#define WPS_CONFMET_USBA 0x0001 /* Deprecated in WSC 2.0 */ +#define WPS_CONFMET_ETHERNET 0x0002 /* Deprecated in WSC 2.0 */ +#define WPS_CONFMET_LABEL 0x0004 +#define WPS_CONFMET_DISPLAY 0x0008 +#define WPS_CONFMET_EXT_NFC_TOK 0x0010 +#define WPS_CONFMET_INT_NFC_TOK 0x0020 +#define WPS_CONFMET_NFC_INTF 0x0040 +#define WPS_CONFMET_PBC 0x0080 +#define WPS_CONFMET_KEYPAD 0x0100 +/* WSC 2.0 */ +#define WPS_CONFMET_VIRT_PBC 0x0280 +#define WPS_CONFMET_PHY_PBC 0x0480 +#define WPS_CONFMET_VIRT_DISPLAY 0x2008 +#define WPS_CONFMET_PHY_DISPLAY 0x4008 + +/* WPS error messages */ +#define WPS_ERROR_NO_ERROR 0 +#define WPS_ERROR_OOB_INT_READ_ERR 1 +#define WPS_ERROR_DECRYPT_CRC_FAIL 2 +#define WPS_ERROR_CHAN24_NOT_SUPP 3 +#define WPS_ERROR_CHAN50_NOT_SUPP 4 +#define WPS_ERROR_SIGNAL_WEAK 5 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_NW_AUTH_FAIL 6 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_NW_ASSOC_FAIL 7 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_NO_DHCP_RESP 8 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_FAILED_DHCP_CONF 9 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_IP_ADDR_CONFLICT 10 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_FAIL_CONN_REGISTRAR 11 +#define WPS_ERROR_MULTI_PBC_DETECTED 12 +#define WPS_ERROR_ROGUE_SUSPECTED 13 +#define WPS_ERROR_DEVICE_BUSY 14 +#define WPS_ERROR_SETUP_LOCKED 15 +#define WPS_ERROR_MSG_TIMEOUT 16 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_REG_SESSION_TIMEOUT 17 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_DEV_PWD_AUTH_FAIL 18 + +/* Connection types */ +#define WPS_CONNTYPE_ESS 0x01 +#define WPS_CONNTYPE_IBSS 0x02 + +/* Device password ID */ +#define WPS_DEVICEPWDID_DEFAULT 0x0000 +#define WPS_DEVICEPWDID_USER_SPEC 0x0001 +#define WPS_DEVICEPWDID_MACHINE_SPEC 0x0002 +#define WPS_DEVICEPWDID_REKEY 0x0003 +#define WPS_DEVICEPWDID_PUSH_BTN 0x0004 +#define WPS_DEVICEPWDID_REG_SPEC 0x0005 + +/* Encryption type */ +#define WPS_ENCRTYPE_NONE 0x0001 +#define WPS_ENCRTYPE_WEP 0x0002 /* Deprecated in WSC 2.0 */ +#define WPS_ENCRTYPE_TKIP 0x0004 /* Deprecated in version 2.0. TKIP can only + * be advertised on the AP when Mixed Mode + * is enabled (Encryption Type is 0x000c). + */ +#define WPS_ENCRTYPE_AES 0x0008 + + +/* WPS Message Types */ +#define WPS_ID_BEACON 0x01 +#define WPS_ID_PROBE_REQ 0x02 +#define WPS_ID_PROBE_RESP 0x03 +#define WPS_ID_MESSAGE_M1 0x04 +#define WPS_ID_MESSAGE_M2 0x05 +#define WPS_ID_MESSAGE_M2D 0x06 +#define WPS_ID_MESSAGE_M3 0x07 +#define WPS_ID_MESSAGE_M4 0x08 +#define WPS_ID_MESSAGE_M5 0x09 +#define WPS_ID_MESSAGE_M6 0x0A +#define WPS_ID_MESSAGE_M7 0x0B +#define WPS_ID_MESSAGE_M8 0x0C +#define WPS_ID_MESSAGE_ACK 0x0D +#define WPS_ID_MESSAGE_NACK 0x0E +#define WPS_ID_MESSAGE_DONE 0x0F + +/* WSP private ID for local use */ +#define WPS_PRIVATE_ID_IDENTITY (WPS_ID_MESSAGE_DONE + 1) +#define WPS_PRIVATE_ID_WPS_START (WPS_ID_MESSAGE_DONE + 2) +#define WPS_PRIVATE_ID_FAILURE (WPS_ID_MESSAGE_DONE + 3) +#define WPS_PRIVATE_ID_FRAG (WPS_ID_MESSAGE_DONE + 4) +#define WPS_PRIVATE_ID_FRAG_ACK (WPS_ID_MESSAGE_DONE + 5) +#define WPS_PRIVATE_ID_EAPOL_START (WPS_ID_MESSAGE_DONE + 6) + + +/* Device Type categories for primary and secondary device types */ +#define WPS_DEVICE_TYPE_CAT_COMPUTER 1 +#define WPS_DEVICE_TYPE_CAT_INPUT_DEVICE 2 +#define WPS_DEVICE_TYPE_CAT_PRINTER 3 +#define WPS_DEVICE_TYPE_CAT_CAMERA 4 +#define WPS_DEVICE_TYPE_CAT_STORAGE 5 +#define WPS_DEVICE_TYPE_CAT_NW_INFRA 6 +#define WPS_DEVICE_TYPE_CAT_DISPLAYS 7 +#define WPS_DEVICE_TYPE_CAT_MM_DEVICES 8 +#define WPS_DEVICE_TYPE_CAT_GAME_DEVICES 9 +#define WPS_DEVICE_TYPE_CAT_TELEPHONE 10 +#define WPS_DEVICE_TYPE_CAT_AUDIO_DEVICES 11 /* WSC 2.0 */ + +/* Device Type sub categories for primary and secondary device types */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_PC 1 +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_SERVER 2 +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MEDIA_CTR 3 +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_UM_PC 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NOTEBOOK 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_DESKTOP 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MID 7 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NETBOOK 8 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_Keyboard 1 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_MOUSE 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_JOYSTICK 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_TRACKBALL 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_GAM_CTRL 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_REMOTE 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_TOUCHSCREEN 7 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_BIO_READER 8 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_BAR_READER 9 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_PRINTER 1 +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_SCANNER 2 +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_FAX 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_COPIER 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_ALLINONE 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_DGTL_STILL 1 +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_VIDEO_CAM 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_WEB_CAM 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_SECU_CAM 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_STOR_NAS 1 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_AP 1 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_ROUTER 2 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_SWITCH 3 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_GATEWAY 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_NW_BRIDGE 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_TV 1 +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PIC_FRAME 2 +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PROJECTOR 3 +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_MONITOR 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_MM_DAR 1 +#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVR 2 +#define WPS_DEVICE_TYPE_SUB_CAT_MM_MCX 3 +#define WPS_DEVICE_TYPE_SUB_CAT_MM_STB 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_MM_MS_ME 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVP 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX 1 +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX_360 2 +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PS 3 +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_GC 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PGD 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_WM 1 +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PSM 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PDM 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SSM 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SDM 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_TUNER 1 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_SPEAKERS 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_PMP 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HEADSET 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HPHONE 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_MPHONE 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HTS 7 /* WSC 2.0 */ + + +/* Device request/response type */ +#define WPS_MSGTYPE_ENROLLEE_INFO_ONLY 0x00 +#define WPS_MSGTYPE_ENROLLEE_OPEN_8021X 0x01 +#define WPS_MSGTYPE_REGISTRAR 0x02 +#define WPS_MSGTYPE_AP_WLAN_MGR 0x03 + +/* RF Band */ +#define WPS_RFBAND_24GHZ 0x01 +#define WPS_RFBAND_50GHZ 0x02 + +/* Simple Config state */ +#define WPS_SCSTATE_UNCONFIGURED 0x01 +#define WPS_SCSTATE_CONFIGURED 0x02 +#define WPS_SCSTATE_OFF 11 + +/* WPS Vendor extension key */ +#define WPS_OUI_HEADER_LEN 2 +#define WPS_OUI_HEADER_SIZE 4 +#define WPS_OUI_FIXED_HEADER_OFF 16 +#define WPS_WFA_SUBID_V2_OFF 3 +#define WPS_WFA_V2_OFF 5 + +#ifdef __cplusplus +} +#endif + +#endif /* _WPS_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h new file mode 100644 index 000000000000..00512bd0aa3a --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h @@ -0,0 +1,3304 @@ +/* + * SiliconBackplane Chipcommon core hardware definitions. + * + * The chipcommon core provides chip identification, SB control, + * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, + * GPIO interface, extbus, and support for serial and parallel flashes. + * + * $Id: sbchipc.h 527121 2015-01-16 03:22:32Z $ + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + */ + +#ifndef _SBCHIPC_H +#define _SBCHIPC_H + +#ifndef _LANGUAGE_ASSEMBLY + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif /* PAD */ + +typedef struct eci_prerev35 { + uint32 eci_output; + uint32 eci_control; + uint32 eci_inputlo; + uint32 eci_inputmi; + uint32 eci_inputhi; + uint32 eci_inputintpolaritylo; + uint32 eci_inputintpolaritymi; + uint32 eci_inputintpolarityhi; + uint32 eci_intmasklo; + uint32 eci_intmaskmi; + uint32 eci_intmaskhi; + uint32 eci_eventlo; + uint32 eci_eventmi; + uint32 eci_eventhi; + uint32 eci_eventmasklo; + uint32 eci_eventmaskmi; + uint32 eci_eventmaskhi; + uint32 PAD[3]; +} eci_prerev35_t; + +typedef struct eci_rev35 { + uint32 eci_outputlo; + uint32 eci_outputhi; + uint32 eci_controllo; + uint32 eci_controlhi; + uint32 eci_inputlo; + uint32 eci_inputhi; + uint32 eci_inputintpolaritylo; + uint32 eci_inputintpolarityhi; + uint32 eci_intmasklo; + uint32 eci_intmaskhi; + uint32 eci_eventlo; + uint32 eci_eventhi; + uint32 eci_eventmasklo; + uint32 eci_eventmaskhi; + uint32 eci_auxtx; + uint32 eci_auxrx; + uint32 eci_datatag; + uint32 eci_uartescvalue; + uint32 eci_autobaudctr; + uint32 eci_uartfifolevel; +} eci_rev35_t; + +typedef struct flash_config { + uint32 PAD[19]; + /* Flash struct configuration registers (0x18c) for BCM4706 (corerev = 31) */ + uint32 flashstrconfig; +} flash_config_t; + +typedef volatile struct { + uint32 chipid; /* 0x0 */ + uint32 capabilities; + uint32 corecontrol; /* corerev >= 1 */ + uint32 bist; + + /* OTP */ + uint32 otpstatus; /* 0x10, corerev >= 10 */ + uint32 otpcontrol; + uint32 otpprog; + uint32 otplayout; /* corerev >= 23 */ + + /* Interrupt control */ + uint32 intstatus; /* 0x20 */ + uint32 intmask; + + /* Chip specific regs */ + uint32 chipcontrol; /* 0x28, rev >= 11 */ + uint32 chipstatus; /* 0x2c, rev >= 11 */ + + /* Jtag Master */ + uint32 jtagcmd; /* 0x30, rev >= 10 */ + uint32 jtagir; + uint32 jtagdr; + uint32 jtagctrl; + + /* serial flash interface registers */ + uint32 flashcontrol; /* 0x40 */ + uint32 flashaddress; + uint32 flashdata; + uint32 otplayoutextension; /* rev >= 35 */ + + /* Silicon backplane configuration broadcast control */ + uint32 broadcastaddress; /* 0x50 */ + uint32 broadcastdata; + + /* gpio - cleared only by power-on-reset */ + uint32 gpiopullup; /* 0x58, corerev >= 20 */ + uint32 gpiopulldown; /* 0x5c, corerev >= 20 */ + uint32 gpioin; /* 0x60 */ + uint32 gpioout; /* 0x64 */ + uint32 gpioouten; /* 0x68 */ + uint32 gpiocontrol; /* 0x6C */ + uint32 gpiointpolarity; /* 0x70 */ + uint32 gpiointmask; /* 0x74 */ + + /* GPIO events corerev >= 11 */ + uint32 gpioevent; + uint32 gpioeventintmask; + + /* Watchdog timer */ + uint32 watchdog; /* 0x80 */ + + /* GPIO events corerev >= 11 */ + uint32 gpioeventintpolarity; + + /* GPIO based LED powersave registers corerev >= 16 */ + uint32 gpiotimerval; /* 0x88 */ + uint32 gpiotimeroutmask; + + /* clock control */ + uint32 clockcontrol_n; /* 0x90 */ + uint32 clockcontrol_sb; /* aka m0 */ + uint32 clockcontrol_pci; /* aka m1 */ + uint32 clockcontrol_m2; /* mii/uart/mipsref */ + uint32 clockcontrol_m3; /* cpu */ + uint32 clkdiv; /* corerev >= 3 */ + uint32 gpiodebugsel; /* corerev >= 28 */ + uint32 capabilities_ext; /* 0xac */ + + /* pll delay registers (corerev >= 4) */ + uint32 pll_on_delay; /* 0xb0 */ + uint32 fref_sel_delay; + uint32 slow_clk_ctl; /* 5 < corerev < 10 */ + uint32 PAD; + + /* Instaclock registers (corerev >= 10) */ + uint32 system_clk_ctl; /* 0xc0 */ + uint32 clkstatestretch; + uint32 PAD[2]; + + /* Indirect backplane access (corerev >= 22) */ + uint32 bp_addrlow; /* 0xd0 */ + uint32 bp_addrhigh; + uint32 bp_data; + uint32 PAD; + uint32 bp_indaccess; + /* SPI registers, corerev >= 37 */ + uint32 gsioctrl; + uint32 gsioaddress; + uint32 gsiodata; + + /* More clock dividers (corerev >= 32) */ + uint32 clkdiv2; + /* FAB ID (corerev >= 40) */ + uint32 otpcontrol1; + uint32 fabid; /* 0xf8 */ + + /* In AI chips, pointer to erom */ + uint32 eromptr; /* 0xfc */ + + /* ExtBus control registers (corerev >= 3) */ + uint32 pcmcia_config; /* 0x100 */ + uint32 pcmcia_memwait; + uint32 pcmcia_attrwait; + uint32 pcmcia_iowait; + uint32 ide_config; + uint32 ide_memwait; + uint32 ide_attrwait; + uint32 ide_iowait; + uint32 prog_config; + uint32 prog_waitcount; + uint32 flash_config; + uint32 flash_waitcount; + uint32 SECI_config; /* 0x130 SECI configuration */ + uint32 SECI_status; + uint32 SECI_statusmask; + uint32 SECI_rxnibchanged; + + uint32 PAD[20]; + + /* SROM interface (corerev >= 32) */ + uint32 sromcontrol; /* 0x190 */ + uint32 sromaddress; + uint32 sromdata; + uint32 PAD[1]; /* 0x19C */ + /* NAND flash registers for BCM4706 (corerev = 31) */ + uint32 nflashctrl; /* 0x1a0 */ + uint32 nflashconf; + uint32 nflashcoladdr; + uint32 nflashrowaddr; + uint32 nflashdata; + uint32 nflashwaitcnt0; /* 0x1b4 */ + uint32 PAD[2]; + + uint32 seci_uart_data; /* 0x1C0 */ + uint32 seci_uart_bauddiv; + uint32 seci_uart_fcr; + uint32 seci_uart_lcr; + uint32 seci_uart_mcr; + uint32 seci_uart_lsr; + uint32 seci_uart_msr; + uint32 seci_uart_baudadj; + /* Clock control and hardware workarounds (corerev >= 20) */ + uint32 clk_ctl_st; /* 0x1e0 */ + uint32 hw_war; + uint32 PAD[70]; + + /* UARTs */ + uint8 uart0data; /* 0x300 */ + uint8 uart0imr; + uint8 uart0fcr; + uint8 uart0lcr; + uint8 uart0mcr; + uint8 uart0lsr; + uint8 uart0msr; + uint8 uart0scratch; + uint8 PAD[248]; /* corerev >= 1 */ + + uint8 uart1data; /* 0x400 */ + uint8 uart1imr; + uint8 uart1fcr; + uint8 uart1lcr; + uint8 uart1mcr; + uint8 uart1lsr; + uint8 uart1msr; + uint8 uart1scratch; /* 0x407 */ + uint32 PAD[62]; + + /* save/restore, corerev >= 48 */ + uint32 sr_capability; /* 0x500 */ + uint32 sr_control0; /* 0x504 */ + uint32 sr_control1; /* 0x508 */ + uint32 gpio_control; /* 0x50C */ + uint32 PAD[60]; + + /* PMU registers (corerev >= 20) */ + /* Note: all timers driven by ILP clock are updated asynchronously to HT/ALP. + * The CPU must read them twice, compare, and retry if different. + */ + uint32 pmucontrol; /* 0x600 */ + uint32 pmucapabilities; + uint32 pmustatus; + uint32 res_state; + uint32 res_pending; + uint32 pmutimer; + uint32 min_res_mask; + uint32 max_res_mask; + uint32 res_table_sel; + uint32 res_dep_mask; + uint32 res_updn_timer; + uint32 res_timer; + uint32 clkstretch; + uint32 pmuwatchdog; + uint32 gpiosel; /* 0x638, rev >= 1 */ + uint32 gpioenable; /* 0x63c, rev >= 1 */ + uint32 res_req_timer_sel; + uint32 res_req_timer; + uint32 res_req_mask; + uint32 PAD; + uint32 chipcontrol_addr; /* 0x650 */ + uint32 chipcontrol_data; /* 0x654 */ + uint32 regcontrol_addr; + uint32 regcontrol_data; + uint32 pllcontrol_addr; + uint32 pllcontrol_data; + uint32 pmustrapopt; /* 0x668, corerev >= 28 */ + uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ + uint32 retention_ctl; /* 0x670 */ + uint32 PAD[3]; + uint32 retention_grpidx; /* 0x680 */ + uint32 retention_grpctl; /* 0x684 */ + uint32 PAD[94]; + uint16 sromotp[512]; /* 0x800 */ +#ifdef NFLASH_SUPPORT + /* Nand flash MLC controller registers (corerev >= 38) */ + uint32 nand_revision; /* 0xC00 */ + uint32 nand_cmd_start; + uint32 nand_cmd_addr_x; + uint32 nand_cmd_addr; + uint32 nand_cmd_end_addr; + uint32 nand_cs_nand_select; + uint32 nand_cs_nand_xor; + uint32 PAD; + uint32 nand_spare_rd0; + uint32 nand_spare_rd4; + uint32 nand_spare_rd8; + uint32 nand_spare_rd12; + uint32 nand_spare_wr0; + uint32 nand_spare_wr4; + uint32 nand_spare_wr8; + uint32 nand_spare_wr12; + uint32 nand_acc_control; + uint32 PAD; + uint32 nand_config; + uint32 PAD; + uint32 nand_timing_1; + uint32 nand_timing_2; + uint32 nand_semaphore; + uint32 PAD; + uint32 nand_devid; + uint32 nand_devid_x; + uint32 nand_block_lock_status; + uint32 nand_intfc_status; + uint32 nand_ecc_corr_addr_x; + uint32 nand_ecc_corr_addr; + uint32 nand_ecc_unc_addr_x; + uint32 nand_ecc_unc_addr; + uint32 nand_read_error_count; + uint32 nand_corr_stat_threshold; + uint32 PAD[2]; + uint32 nand_read_addr_x; + uint32 nand_read_addr; + uint32 nand_page_program_addr_x; + uint32 nand_page_program_addr; + uint32 nand_copy_back_addr_x; + uint32 nand_copy_back_addr; + uint32 nand_block_erase_addr_x; + uint32 nand_block_erase_addr; + uint32 nand_inv_read_addr_x; + uint32 nand_inv_read_addr; + uint32 PAD[2]; + uint32 nand_blk_wr_protect; + uint32 PAD[3]; + uint32 nand_acc_control_cs1; + uint32 nand_config_cs1; + uint32 nand_timing_1_cs1; + uint32 nand_timing_2_cs1; + uint32 PAD[20]; + uint32 nand_spare_rd16; + uint32 nand_spare_rd20; + uint32 nand_spare_rd24; + uint32 nand_spare_rd28; + uint32 nand_cache_addr; + uint32 nand_cache_data; + uint32 nand_ctrl_config; + uint32 nand_ctrl_status; +#endif /* NFLASH_SUPPORT */ + uint32 gci_corecaps0; /* GCI starting at 0xC00 */ + uint32 gci_corecaps1; + uint32 gci_corecaps2; + uint32 gci_corectrl; + uint32 gci_corestat; /* 0xC10 */ + uint32 gci_intstat; /* 0xC14 */ + uint32 gci_intmask; /* 0xC18 */ + uint32 gci_wakemask; /* 0xC1C */ + uint32 gci_levelintstat; /* 0xC20 */ + uint32 gci_eventintstat; /* 0xC24 */ + uint32 PAD[6]; + uint32 gci_indirect_addr; /* 0xC40 */ + uint32 gci_gpioctl; /* 0xC44 */ + uint32 gci_gpiostatus; + uint32 gci_gpiomask; /* 0xC4C */ + uint32 PAD; + uint32 gci_miscctl; /* 0xC54 */ + uint32 gci_gpiointmask; + uint32 gci_gpiowakemask; + uint32 gci_input[32]; /* C60 */ + uint32 gci_event[32]; /* CE0 */ + uint32 gci_output[4]; /* D60 */ + uint32 gci_control_0; /* 0xD70 */ + uint32 gci_control_1; /* 0xD74 */ + uint32 gci_level_polreg; /* 0xD78 */ + uint32 gci_levelintmask; /* 0xD7C */ + uint32 gci_eventintmask; /* 0xD80 */ + uint32 PAD[3]; + uint32 gci_inbandlevelintmask; /* 0xD90 */ + uint32 gci_inbandeventintmask; /* 0xD94 */ + uint32 PAD[2]; + uint32 gci_seciauxtx; /* 0xDA0 */ + uint32 gci_seciauxrx; /* 0xDA4 */ + uint32 gci_secitx_datatag; /* 0xDA8 */ + uint32 gci_secirx_datatag; /* 0xDAC */ + uint32 gci_secitx_datamask; /* 0xDB0 */ + uint32 gci_seciusef0tx_reg; /* 0xDB4 */ + uint32 gci_secif0tx_offset; /* 0xDB8 */ + uint32 gci_secif0rx_offset; /* 0xDBC */ + uint32 gci_secif1tx_offset; /* 0xDC0 */ + uint32 PAD[3]; + uint32 gci_uartescval; /* DD0 */ + uint32 PAD[3]; + uint32 gci_secibauddiv; /* DE0 */ + uint32 gci_secifcr; /* DE4 */ + uint32 gci_secilcr; /* DE8 */ + uint32 gci_secimcr; /* DEC */ + uint32 PAD[2]; + uint32 gci_baudadj; /* DF8 */ + uint32 PAD; + uint32 gci_chipctrl; /* 0xE00 */ + uint32 gci_chipsts; /* 0xE04 */ +} chipcregs_t; + +#endif /* _LANGUAGE_ASSEMBLY */ + + +#define CC_CHIPID 0 +#define CC_CAPABILITIES 4 +#define CC_CHIPST 0x2c +#define CC_EROMPTR 0xfc + +#define CC_OTPST 0x10 +#define CC_JTAGCMD 0x30 +#define CC_JTAGIR 0x34 +#define CC_JTAGDR 0x38 +#define CC_JTAGCTRL 0x3c +#define CC_GPIOPU 0x58 +#define CC_GPIOPD 0x5c +#define CC_GPIOIN 0x60 +#define CC_GPIOOUT 0x64 +#define CC_GPIOOUTEN 0x68 +#define CC_GPIOCTRL 0x6c +#define CC_GPIOPOL 0x70 +#define CC_GPIOINTM 0x74 +#define CC_WATCHDOG 0x80 +#define CC_CLKC_N 0x90 +#define CC_CLKC_M0 0x94 +#define CC_CLKC_M1 0x98 +#define CC_CLKC_M2 0x9c +#define CC_CLKC_M3 0xa0 +#define CC_CLKDIV 0xa4 +#define CC_SYS_CLK_CTL 0xc0 +#define CC_CLK_CTL_ST SI_CLK_CTL_ST +#define PMU_CTL 0x600 +#define PMU_CAP 0x604 +#define PMU_ST 0x608 +#define PMU_RES_STATE 0x60c +#define PMU_TIMER 0x614 +#define PMU_MIN_RES_MASK 0x618 +#define PMU_MAX_RES_MASK 0x61c +#define CC_CHIPCTL_ADDR 0x650 +#define CC_CHIPCTL_DATA 0x654 +#define PMU_REG_CONTROL_ADDR 0x658 +#define PMU_REG_CONTROL_DATA 0x65C +#define PMU_PLL_CONTROL_ADDR 0x660 +#define PMU_PLL_CONTROL_DATA 0x664 +#define CC_SROM_CTRL 0x190 +#define CC_SROM_OTP 0x800 /* SROM/OTP address space */ +#define CC_GCI_INDIRECT_ADDR_REG 0xC40 +#define CC_GCI_CHIP_CTRL_REG 0xE00 +#define CC_GCI_CC_OFFSET_2 2 +#define CC_GCI_CC_OFFSET_5 5 + +#define CHIPCTRLREG0 0x0 +#define CHIPCTRLREG1 0x1 +#define CHIPCTRLREG2 0x2 +#define CHIPCTRLREG3 0x3 +#define CHIPCTRLREG4 0x4 +#define CHIPCTRLREG5 0x5 +#define CHIPCTRLREG6 0x6 +#define REGCTRLREG4 0x4 +#define REGCTRLREG5 0x5 +#define REGCTRLREG6 0x6 +#define PMU_RES_STATE 0x60c +#define PMU_RES_PENDING 0x610 +#define PMU_TIMER 0x614 +#define MINRESMASKREG 0x618 +#define MAXRESMASKREG 0x61c +#define CHIPCTRLADDR 0x650 +#define CHIPCTRLDATA 0x654 +#define RSRCTABLEADDR 0x620 +#define PMU_RES_DEP_MASK 0x624 +#define RSRCUPDWNTIME 0x628 +#define PMUREG_RESREQ_MASK 0x68c +#define EXT_LPO_AVAIL 0x100 +#define LPO_SEL (1 << 0) +#define CC_EXT_LPO_PU 0x200000 +#define GC_EXT_LPO_PU 0x2 +#define CC_INT_LPO_PU 0x100000 +#define GC_INT_LPO_PU 0x1 +#define EXT_LPO_SEL 0x8 +#define INT_LPO_SEL 0x4 +#define ENABLE_FINE_CBUCK_CTRL (1 << 30) +#define REGCTRL5_PWM_AUTO_CTRL_MASK 0x007e0000 +#define REGCTRL5_PWM_AUTO_CTRL_SHIFT 17 +#define REGCTRL6_PWM_AUTO_CTRL_MASK 0x3fff0000 +#define REGCTRL6_PWM_AUTO_CTRL_SHIFT 16 + +#ifdef NFLASH_SUPPORT +/* NAND flash support */ +#define CC_NAND_REVISION 0xC00 +#define CC_NAND_CMD_START 0xC04 +#define CC_NAND_CMD_ADDR 0xC0C +#define CC_NAND_SPARE_RD_0 0xC20 +#define CC_NAND_SPARE_RD_4 0xC24 +#define CC_NAND_SPARE_RD_8 0xC28 +#define CC_NAND_SPARE_RD_C 0xC2C +#define CC_NAND_CONFIG 0xC48 +#define CC_NAND_DEVID 0xC60 +#define CC_NAND_DEVID_EXT 0xC64 +#define CC_NAND_INTFC_STATUS 0xC6C +#endif /* NFLASH_SUPPORT */ + +/* 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 */ +#define CC_CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */ +#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_ECI 0x20000000 /* ECI Present, rev >= 21 */ +#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */ +#define CC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */ + +#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ +#define CC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */ + +/* capabilities extension */ +#define CC_CAP_EXT_SECI_PRESENT 0x00000001 /* SECI present */ +#define CC_CAP_EXT_GCI_PRESENT 0x00000004 /* GCI present */ + +/* WL Channel Info to BT via GCI - bits 40 - 47 */ +#define GCI_WL_CHN_INFO_MASK (0xFF00) +/* PLL type */ +#define PLL_NONE 0x00000000 +#define PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */ +#define PLL_TYPE2 0x00020000 /* 48MHz, 4 dividers */ +#define PLL_TYPE3 0x00030000 /* 25MHz, 2 dividers */ +#define PLL_TYPE4 0x00008000 /* 48MHz, 4 dividers */ +#define PLL_TYPE5 0x00018000 /* 25MHz, 4 dividers */ +#define PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */ +#define PLL_TYPE7 0x00038000 /* 25MHz, 4 dividers */ + +/* ILP clock */ +#define ILP_CLOCK 32000 + +/* ALP clock on pre-PMU chips */ +#define ALP_CLOCK 20000000 + +#ifdef CFG_SIM +#define NS_ALP_CLOCK 84922 +#define NS_SLOW_ALP_CLOCK 84922 +#define NS_CPU_CLOCK 534500 +#define NS_SLOW_CPU_CLOCK 534500 +#define NS_SI_CLOCK 271750 +#define NS_SLOW_SI_CLOCK 271750 +#define NS_FAST_MEM_CLOCK 271750 +#define NS_MEM_CLOCK 271750 +#define NS_SLOW_MEM_CLOCK 271750 +#else +#define NS_ALP_CLOCK 125000000 +#define NS_SLOW_ALP_CLOCK 100000000 +#define NS_CPU_CLOCK 1000000000 +#define NS_SLOW_CPU_CLOCK 800000000 +#define NS_SI_CLOCK 250000000 +#define NS_SLOW_SI_CLOCK 200000000 +#define NS_FAST_MEM_CLOCK 800000000 +#define NS_MEM_CLOCK 533000000 +#define NS_SLOW_MEM_CLOCK 400000000 +#endif /* CFG_SIM */ + +/* HT clock */ +#define HT_CLOCK 80000000 + +/* corecontrol */ +#define CC_UARTCLKO 0x00000001 /* Drive UART with internal clock */ +#define CC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ +#define CC_ASYNCGPIO 0x00000004 /* 1=generate GPIO interrupt without backplane clock */ +#define CC_UARTCLKEN 0x00000008 /* enable UART Clock (corerev > = 21 */ + +/* 4321 chipcontrol */ +#define CHIPCTRL_4321A0_DEFAULT 0x3a4 +#define CHIPCTRL_4321A1_DEFAULT 0x0a4 +#define CHIPCTRL_4321_PLL_DOWN 0x800000 /* serdes PLL down override */ + +/* Fields in the otpstatus register in rev >= 21 */ +#define OTPS_OL_MASK 0x000000ff +#define OTPS_OL_MFG 0x00000001 /* manuf row is locked */ +#define OTPS_OL_OR1 0x00000002 /* otp redundancy row 1 is locked */ +#define OTPS_OL_OR2 0x00000004 /* otp redundancy row 2 is locked */ +#define OTPS_OL_GU 0x00000008 /* general use region is locked */ +#define OTPS_GUP_MASK 0x00000f00 +#define OTPS_GUP_SHIFT 8 +#define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */ +#define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */ +#define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */ +#define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */ +#define OTPS_READY 0x00001000 +#define OTPS_RV(x) (1 << (16 + (x))) /* redundancy entry valid */ +#define OTPS_RV_MASK 0x0fff0000 +#define OTPS_PROGOK 0x40000000 + +/* Fields in the otpcontrol register in rev >= 21 */ +#define OTPC_PROGSEL 0x00000001 +#define OTPC_PCOUNT_MASK 0x0000000e +#define OTPC_PCOUNT_SHIFT 1 +#define OTPC_VSEL_MASK 0x000000f0 +#define OTPC_VSEL_SHIFT 4 +#define OTPC_TMM_MASK 0x00000700 +#define OTPC_TMM_SHIFT 8 +#define OTPC_ODM 0x00000800 +#define OTPC_PROGEN 0x80000000 + +/* Fields in the 40nm otpcontrol register in rev >= 40 */ +#define OTPC_40NM_PROGSEL_SHIFT 0 +#define OTPC_40NM_PCOUNT_SHIFT 1 +#define OTPC_40NM_PCOUNT_WR 0xA +#define OTPC_40NM_PCOUNT_V1X 0xB +#define OTPC_40NM_REGCSEL_SHIFT 5 +#define OTPC_40NM_REGCSEL_DEF 0x4 +#define OTPC_40NM_PROGIN_SHIFT 8 +#define OTPC_40NM_R2X_SHIFT 10 +#define OTPC_40NM_ODM_SHIFT 11 +#define OTPC_40NM_DF_SHIFT 15 +#define OTPC_40NM_VSEL_SHIFT 16 +#define OTPC_40NM_VSEL_WR 0xA +#define OTPC_40NM_VSEL_V1X 0xA +#define OTPC_40NM_VSEL_R1X 0x5 +#define OTPC_40NM_COFAIL_SHIFT 30 + +#define OTPC1_CPCSEL_SHIFT 0 +#define OTPC1_CPCSEL_DEF 6 +#define OTPC1_TM_SHIFT 8 +#define OTPC1_TM_WR 0x84 +#define OTPC1_TM_V1X 0x84 +#define OTPC1_TM_R1X 0x4 + +/* Fields in otpprog in rev >= 21 and HND OTP */ +#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 /* HND OTP */ + +/* Fields in otplayout register */ +#define OTPL_HWRGN_OFF_MASK 0x00000FFF +#define OTPL_HWRGN_OFF_SHIFT 0 +#define OTPL_WRAP_REVID_MASK 0x00F80000 +#define OTPL_WRAP_REVID_SHIFT 19 +#define OTPL_WRAP_TYPE_MASK 0x00070000 +#define OTPL_WRAP_TYPE_SHIFT 16 +#define OTPL_WRAP_TYPE_65NM 0 +#define OTPL_WRAP_TYPE_40NM 1 +#define OTPL_ROW_SIZE_MASK 0x0000F000 +#define OTPL_ROW_SIZE_SHIFT 12 + +/* otplayout reg corerev >= 36 */ +#define OTP_CISFORMAT_NEW 0x80000000 + +/* 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 + +/* Opcodes for OTPP_OC field (40NM) */ +#define OTPPOC_READ_40NM 0 +#define OTPPOC_PROG_ENABLE_40NM 1 +#define OTPPOC_PROG_DISABLE_40NM 2 +#define OTPPOC_VERIFY_40NM 3 +#define OTPPOC_WORD_VERIFY_1_40NM 4 +#define OTPPOC_ROW_LOCK_40NM 5 +#define OTPPOC_STBY_40NM 6 +#define OTPPOC_WAKEUP_40NM 7 +#define OTPPOC_WORD_VERIFY_0_40NM 8 +#define OTPPOC_PRESCN_TEST_40NM 9 +#define OTPPOC_BIT_PROG_40NM 10 +#define OTPPOC_WORDPROG_40NM 11 +#define OTPPOC_BURNIN_40NM 12 +#define OTPPOC_AUTORELOAD_40NM 13 +#define OTPPOC_OVST_READ_40NM 14 +#define OTPPOC_OVST_PROG_40NM 15 + +/* Fields in otplayoutextension */ +#define OTPLAYOUTEXT_FUSE_MASK 0x3FF + + +/* Jtagm characteristics that appeared at a given corerev */ +#define JTAGM_CREV_OLD 10 /* Old command set, 16bit max IR */ +#define JTAGM_CREV_IRP 22 /* Able to do pause-ir */ +#define JTAGM_CREV_RTI 28 /* Able to do return-to-idle */ + +/* jtagcmd */ +#define JCMD_START 0x80000000 +#define JCMD_BUSY 0x80000000 +#define JCMD_STATE_MASK 0x60000000 +#define JCMD_STATE_TLR 0x00000000 /* Test-logic-reset */ +#define JCMD_STATE_PIR 0x20000000 /* Pause IR */ +#define JCMD_STATE_PDR 0x40000000 /* Pause DR */ +#define JCMD_STATE_RTI 0x60000000 /* Run-test-idle */ +#define JCMD0_ACC_MASK 0x0000f000 +#define JCMD0_ACC_IRDR 0x00000000 +#define JCMD0_ACC_DR 0x00001000 +#define JCMD0_ACC_IR 0x00002000 +#define JCMD0_ACC_RESET 0x00003000 +#define JCMD0_ACC_IRPDR 0x00004000 +#define JCMD0_ACC_PDR 0x00005000 +#define JCMD0_IRW_MASK 0x00000f00 +#define JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */ +#define JCMD_ACC_IRDR 0x00000000 +#define JCMD_ACC_DR 0x00010000 +#define JCMD_ACC_IR 0x00020000 +#define JCMD_ACC_RESET 0x00030000 +#define JCMD_ACC_IRPDR 0x00040000 +#define JCMD_ACC_PDR 0x00050000 +#define JCMD_ACC_PIR 0x00060000 +#define JCMD_ACC_IRDR_I 0x00070000 /* rev 28: return to run-test-idle */ +#define JCMD_ACC_DR_I 0x00080000 /* rev 28: return to run-test-idle */ +#define JCMD_IRW_MASK 0x00001f00 +#define JCMD_IRW_SHIFT 8 +#define JCMD_DRW_MASK 0x0000003f + +/* jtagctrl */ +#define JCTRL_FORCE_CLK 4 /* Force clock */ +#define JCTRL_EXT_EN 2 /* Enable external targets */ +#define JCTRL_EN 1 /* Enable Jtag master */ + +/* Fields in clkdiv */ +#define CLKD_SFLASH 0x0f000000 +#define CLKD_SFLASH_SHIFT 24 +#define CLKD_OTP 0x000f0000 +#define CLKD_OTP_SHIFT 16 +#define CLKD_JTAG 0x00000f00 +#define CLKD_JTAG_SHIFT 8 +#define CLKD_UART 0x000000ff + +#define CLKD2_SROM 0x00000003 + +/* intstatus/intmask */ +#define CI_GPIO 0x00000001 /* gpio intr */ +#define CI_EI 0x00000002 /* extif intr (corerev >= 3) */ +#define CI_TEMP 0x00000004 /* temp. ctrl intr (corerev >= 15) */ +#define CI_SIRQ 0x00000008 /* serial IRQ intr (corerev >= 15) */ +#define CI_ECI 0x00000010 /* eci intr (corerev >= 21) */ +#define CI_PMU 0x00000020 /* pmu intr (corerev >= 21) */ +#define CI_UART 0x00000040 /* uart intr (corerev >= 21) */ +#define CI_WDRESET 0x80000000 /* watchdog reset occurred */ + +/* slow_clk_ctl */ +#define SCC_SS_MASK 0x00000007 /* slow clock source mask */ +#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */ +#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */ +#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */ +#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ +#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, + * 0: LPO is enabled + */ +#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, + * 0: power logic control + */ +#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors + * PLL clock disable requests from core + */ +#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't + * disable crystal when appropriate + */ +#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ +#define SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ +#define SCC_CD_SHIFT 16 + +/* system_clk_ctl */ +#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */ +#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */ +#define SYCC_FP 0x00000004 /* ForcePLLOn */ +#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */ +#define SYCC_HR 0x00000010 /* Force HT */ +#define SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ +#define SYCC_CD_SHIFT 16 + +/* Indirect backplane access */ +#define BPIA_BYTEEN 0x0000000f +#define BPIA_SZ1 0x00000001 +#define BPIA_SZ2 0x00000003 +#define BPIA_SZ4 0x00000007 +#define BPIA_SZ8 0x0000000f +#define BPIA_WRITE 0x00000100 +#define BPIA_START 0x00000200 +#define BPIA_BUSY 0x00000200 +#define BPIA_ERROR 0x00000400 + +/* pcmcia/prog/flash_config */ +#define CF_EN 0x00000001 /* enable */ +#define CF_EM_MASK 0x0000000e /* mode */ +#define CF_EM_SHIFT 1 +#define CF_EM_FLASH 0 /* flash/asynchronous mode */ +#define CF_EM_SYNC 2 /* synchronous mode */ +#define CF_EM_PCMCIA 4 /* pcmcia mode */ +#define CF_DS 0x00000010 /* destsize: 0=8bit, 1=16bit */ +#define CF_BS 0x00000020 /* byteswap */ +#define CF_CD_MASK 0x000000c0 /* clock divider */ +#define CF_CD_SHIFT 6 +#define CF_CD_DIV2 0x00000000 /* backplane/2 */ +#define CF_CD_DIV3 0x00000040 /* backplane/3 */ +#define CF_CD_DIV4 0x00000080 /* backplane/4 */ +#define CF_CE 0x00000100 /* clock enable */ +#define CF_SB 0x00000200 /* size/bytestrobe (synch only) */ + +/* pcmcia_memwait */ +#define PM_W0_MASK 0x0000003f /* waitcount0 */ +#define PM_W1_MASK 0x00001f00 /* waitcount1 */ +#define PM_W1_SHIFT 8 +#define PM_W2_MASK 0x001f0000 /* waitcount2 */ +#define PM_W2_SHIFT 16 +#define PM_W3_MASK 0x1f000000 /* waitcount3 */ +#define PM_W3_SHIFT 24 + +/* pcmcia_attrwait */ +#define PA_W0_MASK 0x0000003f /* waitcount0 */ +#define PA_W1_MASK 0x00001f00 /* waitcount1 */ +#define PA_W1_SHIFT 8 +#define PA_W2_MASK 0x001f0000 /* waitcount2 */ +#define PA_W2_SHIFT 16 +#define PA_W3_MASK 0x1f000000 /* waitcount3 */ +#define PA_W3_SHIFT 24 + +/* pcmcia_iowait */ +#define PI_W0_MASK 0x0000003f /* waitcount0 */ +#define PI_W1_MASK 0x00001f00 /* waitcount1 */ +#define PI_W1_SHIFT 8 +#define PI_W2_MASK 0x001f0000 /* waitcount2 */ +#define PI_W2_SHIFT 16 +#define PI_W3_MASK 0x1f000000 /* waitcount3 */ +#define PI_W3_SHIFT 24 + +/* prog_waitcount */ +#define PW_W0_MASK 0x0000001f /* waitcount0 */ +#define PW_W1_MASK 0x00001f00 /* waitcount1 */ +#define PW_W1_SHIFT 8 +#define PW_W2_MASK 0x001f0000 /* waitcount2 */ +#define PW_W2_SHIFT 16 +#define PW_W3_MASK 0x1f000000 /* waitcount3 */ +#define PW_W3_SHIFT 24 + +#define PW_W0 0x0000000c +#define PW_W1 0x00000a00 +#define PW_W2 0x00020000 +#define PW_W3 0x01000000 + +/* flash_waitcount */ +#define FW_W0_MASK 0x0000003f /* waitcount0 */ +#define FW_W1_MASK 0x00001f00 /* waitcount1 */ +#define FW_W1_SHIFT 8 +#define FW_W2_MASK 0x001f0000 /* waitcount2 */ +#define FW_W2_SHIFT 16 +#define FW_W3_MASK 0x1f000000 /* waitcount3 */ +#define FW_W3_SHIFT 24 + +/* 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_OTPPRESENT 0x00000020 +#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 + +/* Fields in pmucontrol */ +#define PCTL_ILP_DIV_MASK 0xffff0000 +#define PCTL_ILP_DIV_SHIFT 16 +#define PCTL_LQ_REQ_EN 0x00008000 +#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 + +/* Retention Control */ +#define PMU_RCTL_CLK_DIV_SHIFT 0 +#define PMU_RCTL_CHAIN_LEN_SHIFT 12 +#define PMU_RCTL_MACPHY_DISABLE_SHIFT 26 +#define PMU_RCTL_MACPHY_DISABLE_MASK (1 << 26) +#define PMU_RCTL_LOGIC_DISABLE_SHIFT 27 +#define PMU_RCTL_LOGIC_DISABLE_MASK (1 << 27) +#define PMU_RCTL_MEMSLP_LOG_SHIFT 28 +#define PMU_RCTL_MEMSLP_LOG_MASK (1 << 28) +#define PMU_RCTL_MEMRETSLP_LOG_SHIFT 29 +#define PMU_RCTL_MEMRETSLP_LOG_MASK (1 << 29) + +/* Retention Group Control */ +#define PMU_RCTLGRP_CHAIN_LEN_SHIFT 0 +#define PMU_RCTLGRP_RMODE_ENABLE_SHIFT 14 +#define PMU_RCTLGRP_RMODE_ENABLE_MASK (1 << 14) +#define PMU_RCTLGRP_DFT_ENABLE_SHIFT 15 +#define PMU_RCTLGRP_DFT_ENABLE_MASK (1 << 15) +#define PMU_RCTLGRP_NSRST_DISABLE_SHIFT 16 +#define PMU_RCTLGRP_NSRST_DISABLE_MASK (1 << 16) +/* Retention Group Control special for 4334 */ +#define PMU4334_RCTLGRP_CHAIN_LEN_GRP0 338 +#define PMU4334_RCTLGRP_CHAIN_LEN_GRP1 315 +/* Retention Group Control special for 43341 */ +#define PMU43341_RCTLGRP_CHAIN_LEN_GRP0 366 +#define PMU43341_RCTLGRP_CHAIN_LEN_GRP1 330 + +/* Fields in clkstretch */ +#define CSTRETCH_HT 0xffff0000 +#define CSTRETCH_ALP 0x0000ffff + +/* gpiotimerval */ +#define GPIO_ONTIME_SHIFT 16 + +/* clockcontrol_n */ +#define CN_N1_MASK 0x3f /* n1 control */ +#define CN_N2_MASK 0x3f00 /* n2 control */ +#define CN_N2_SHIFT 8 +#define CN_PLLC_MASK 0xf0000 /* pll control */ +#define CN_PLLC_SHIFT 16 + +/* clockcontrol_sb/pci/uart */ +#define CC_M1_MASK 0x3f /* m1 control */ +#define CC_M2_MASK 0x3f00 /* m2 control */ +#define CC_M2_SHIFT 8 +#define CC_M3_MASK 0x3f0000 /* m3 control */ +#define CC_M3_SHIFT 16 +#define CC_MC_MASK 0x1f000000 /* mux control */ +#define CC_MC_SHIFT 24 + +/* N3M Clock control magic field values */ +#define CC_F6_2 0x02 /* A factor of 2 in */ +#define CC_F6_3 0x03 /* 6-bit fields like */ +#define CC_F6_4 0x05 /* N1, M1 or M3 */ +#define CC_F6_5 0x09 +#define CC_F6_6 0x11 +#define CC_F6_7 0x21 + +#define CC_F5_BIAS 5 /* 5-bit fields get this added */ + +#define CC_MC_BYPASS 0x08 +#define CC_MC_M1 0x04 +#define CC_MC_M1M2 0x02 +#define CC_MC_M1M2M3 0x01 +#define CC_MC_M1M3 0x11 + +/* Type 2 Clock control magic field values */ +#define CC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ +#define CC_T2M2_BIAS 3 /* m2 bias */ + +#define CC_T2MC_M1BYP 1 +#define CC_T2MC_M2BYP 2 +#define CC_T2MC_M3BYP 4 + +/* Type 6 Clock control magic field values */ +#define CC_T6_MMASK 1 /* bits of interest in m */ +#define CC_T6_M0 120000000 /* sb clock for m = 0 */ +#define CC_T6_M1 100000000 /* sb clock for m = 1 */ +#define SB2MIPS_T6(sb) (2 * (sb)) + +/* Common clock base */ +#define CC_CLOCK_BASE1 24000000 /* Half the clock freq */ +#define CC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLLs */ + +/* Clock control values for 200MHz in 5350 */ +#define CLKC_5350_N 0x0311 +#define CLKC_5350_M 0x04020009 + +/* Flash types in the chipcommon capabilities register */ +#define FLASH_NONE 0x000 /* No flash */ +#define SFLASH_ST 0x100 /* ST serial flash */ +#define SFLASH_AT 0x200 /* Atmel serial flash */ +#define NFLASH 0x300 +#define PFLASH 0x700 /* Parallel flash */ +#define QSPIFLASH_ST 0x800 +#define QSPIFLASH_AT 0x900 + +/* Bits in the ExtBus config registers */ +#define CC_CFG_EN 0x0001 /* Enable */ +#define CC_CFG_EM_MASK 0x000e /* Extif Mode */ +#define CC_CFG_EM_ASYNC 0x0000 /* Async/Parallel flash */ +#define CC_CFG_EM_SYNC 0x0002 /* Synchronous */ +#define CC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */ +#define CC_CFG_EM_IDE 0x0006 /* IDE */ +#define CC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */ +#define CC_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */ +#define CC_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */ +#define CC_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */ +#define CC_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */ + +/* ExtBus address space */ +#define CC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */ +#define CC_EB_PCMCIA_MEM 0x1a000000 /* PCMCIA 0 memory base address */ +#define CC_EB_PCMCIA_IO 0x1a200000 /* PCMCIA 0 I/O base address */ +#define CC_EB_PCMCIA_CFG 0x1a400000 /* PCMCIA 0 config base address */ +#define CC_EB_IDE 0x1a800000 /* IDE memory base */ +#define CC_EB_PCMCIA1_MEM 0x1a800000 /* PCMCIA 1 memory base address */ +#define CC_EB_PCMCIA1_IO 0x1aa00000 /* PCMCIA 1 I/O base address */ +#define CC_EB_PCMCIA1_CFG 0x1ac00000 /* PCMCIA 1 config base address */ +#define CC_EB_PROGIF 0x1b000000 /* ProgIF Async/Sync base address */ + + +/* Start/busy bit in flashcontrol */ +#define SFLASH_OPCODE 0x000000ff +#define SFLASH_ACTION 0x00000700 +#define SFLASH_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */ +#define SFLASH_START 0x80000000 +#define SFLASH_BUSY SFLASH_START + +/* flashcontrol action codes */ +#define SFLASH_ACT_OPONLY 0x0000 /* Issue opcode only */ +#define SFLASH_ACT_OP1D 0x0100 /* opcode + 1 data byte */ +#define SFLASH_ACT_OP3A 0x0200 /* opcode + 3 addr bytes */ +#define SFLASH_ACT_OP3A1D 0x0300 /* opcode + 3 addr & 1 data bytes */ +#define SFLASH_ACT_OP3A4D 0x0400 /* opcode + 3 addr & 4 data bytes */ +#define SFLASH_ACT_OP3A4X4D 0x0500 /* opcode + 3 addr, 4 don't care & 4 data bytes */ +#define SFLASH_ACT_OP3A1X4D 0x0700 /* opcode + 3 addr, 1 don't care & 4 data bytes */ + +/* flashcontrol action+opcodes for ST flashes */ +#define SFLASH_ST_WREN 0x0006 /* Write Enable */ +#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */ +#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */ +#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */ +#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */ +#define SFLASH_ST_PP 0x0302 /* Page Program */ +#define SFLASH_ST_SE 0x02d8 /* Sector Erase */ +#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */ +#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */ +#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */ +#define SFLASH_ST_CSA 0x1000 /* Keep chip select asserted */ +#define SFLASH_ST_SSE 0x0220 /* Sub-sector Erase */ + +#define SFLASH_MXIC_RDID 0x0390 /* Read Manufacture ID */ +#define SFLASH_MXIC_MFID 0xc2 /* MXIC Manufacture ID */ + +/* Status register bits for ST flashes */ +#define SFLASH_ST_WIP 0x01 /* Write In Progress */ +#define SFLASH_ST_WEL 0x02 /* Write Enable Latch */ +#define SFLASH_ST_BP_MASK 0x1c /* Block Protect */ +#define SFLASH_ST_BP_SHIFT 2 +#define SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */ + +/* flashcontrol action+opcodes for Atmel flashes */ +#define SFLASH_AT_READ 0x07e8 +#define SFLASH_AT_PAGE_READ 0x07d2 +#define SFLASH_AT_BUF1_READ +#define SFLASH_AT_BUF2_READ +#define SFLASH_AT_STATUS 0x01d7 +#define SFLASH_AT_BUF1_WRITE 0x0384 +#define SFLASH_AT_BUF2_WRITE 0x0387 +#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 +#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 +#define SFLASH_AT_BUF1_PROGRAM 0x0288 +#define SFLASH_AT_BUF2_PROGRAM 0x0289 +#define SFLASH_AT_PAGE_ERASE 0x0281 +#define SFLASH_AT_BLOCK_ERASE 0x0250 +#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 +#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 +#define SFLASH_AT_BUF1_LOAD 0x0253 +#define SFLASH_AT_BUF2_LOAD 0x0255 +#define SFLASH_AT_BUF1_COMPARE 0x0260 +#define SFLASH_AT_BUF2_COMPARE 0x0261 +#define SFLASH_AT_BUF1_REPROGRAM 0x0258 +#define SFLASH_AT_BUF2_REPROGRAM 0x0259 + +/* Status register bits for Atmel flashes */ +#define SFLASH_AT_READY 0x80 +#define SFLASH_AT_MISMATCH 0x40 +#define SFLASH_AT_ID_MASK 0x38 +#define SFLASH_AT_ID_SHIFT 3 + +/* SPI register bits, corerev >= 37 */ +#define GSIO_START 0x80000000 +#define GSIO_BUSY GSIO_START + +/* + * These are the UART port assignments, expressed as offsets from the base + * register. These assignments should hold for any serial port based on + * a 8250, 16450, or 16550(A). + */ + +#define UART_RX 0 /* In: Receive buffer (DLAB=0) */ +#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ +#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ +#define UART_IER 1 /* In/Out: Interrupt Enable Register (DLAB=0) */ +#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */ +#define UART_IIR 2 /* In: Interrupt Identity Register */ +#define UART_FCR 2 /* Out: FIFO Control Register */ +#define UART_LCR 3 /* Out: Line Control Register */ +#define UART_MCR 4 /* Out: Modem Control Register */ +#define UART_LSR 5 /* In: Line Status Register */ +#define UART_MSR 6 /* In: Modem Status Register */ +#define UART_SCR 7 /* I/O: Scratch Register */ +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ +#define UART_LCR_WLEN8 0x03 /* Word length: 8 bits */ +#define UART_MCR_OUT2 0x08 /* MCR GPIO out 2 */ +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ +#define UART_LSR_RX_FIFO 0x80 /* Receive FIFO error */ +#define UART_LSR_TDHR 0x40 /* Data-hold-register empty */ +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ +#define UART_LSR_BREAK 0x10 /* Break interrupt */ +#define UART_LSR_FRAMING 0x08 /* Framing error */ +#define UART_LSR_PARITY 0x04 /* Parity error */ +#define UART_LSR_OVERRUN 0x02 /* Overrun error */ +#define UART_LSR_RXRDY 0x01 /* Receiver ready */ +#define UART_FCR_FIFO_ENABLE 1 /* FIFO control register bit controlling FIFO enable/disable */ + +/* Interrupt Identity Register (IIR) bits */ +#define UART_IIR_FIFO_MASK 0xc0 /* IIR FIFO disable/enabled mask */ +#define UART_IIR_INT_MASK 0xf /* IIR interrupt ID source */ +#define UART_IIR_MDM_CHG 0x0 /* Modem status changed */ +#define UART_IIR_NOINT 0x1 /* No interrupt pending */ +#define UART_IIR_THRE 0x2 /* THR empty */ +#define UART_IIR_RCVD_DATA 0x4 /* Received data available */ +#define UART_IIR_RCVR_STATUS 0x6 /* Receiver status */ +#define UART_IIR_CHAR_TIME 0xc /* Character time */ + +/* Interrupt Enable Register (IER) bits */ +#define UART_IER_PTIME 128 /* Programmable THRE Interrupt Mode Enable */ +#define UART_IER_EDSSI 8 /* enable modem status interrupt */ +#define UART_IER_ELSI 4 /* enable receiver line status interrupt */ +#define UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */ +#define UART_IER_ERBFI 1 /* enable data available interrupt */ + +/* 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 + +/* 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 + +/* PMU Resource Request Timer registers */ +/* This is based on PmuRev0 */ +#define PRRT_TIME_MASK 0x03ff +#define PRRT_INTEN 0x0400 +#define PRRT_REQ_ACTIVE 0x0800 +#define PRRT_ALP_REQ 0x1000 +#define PRRT_HT_REQ 0x2000 +#define PRRT_HQ_REQ 0x4000 + +/* PMU resource bit position */ +#define PMURES_BIT(bit) (1 << (bit)) + +/* PMU resource number limit */ +#define PMURES_MAX_RESNUM 30 + +/* PMU chip control0 register */ +#define PMU_CHIPCTL0 0 +#define PMU43143_CC0_SDIO_DRSTR_OVR (1 << 31) /* sdio drive strength override enable */ + +/* clock req types */ +#define PMU_CC1_CLKREQ_TYPE_SHIFT 19 +#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT) + +#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0 +#define CLKREQ_TYPE_CONFIG_PUSHPULL 1 + +/* PMU chip control1 register */ +#define PMU_CHIPCTL1 1 +#define PMU_CC1_RXC_DLL_BYPASS 0x00010000 +#define PMU_CC1_ENABLE_BBPLL_PWR_DOWN 0x00000010 + +#define PMU_CC1_IF_TYPE_MASK 0x00000030 +#define PMU_CC1_IF_TYPE_RMII 0x00000000 +#define PMU_CC1_IF_TYPE_MII 0x00000010 +#define PMU_CC1_IF_TYPE_RGMII 0x00000020 + +#define PMU_CC1_SW_TYPE_MASK 0x000000c0 +#define PMU_CC1_SW_TYPE_EPHY 0x00000000 +#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040 +#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 +#define PMU_CC1_SW_TYPE_RGMII 0x000000c0 + +/* PMU chip control2 register */ +#define PMU_CHIPCTL2 2 +#define PMU_CC2_FORCE_SUBCORE_PWR_SWITCH_ON (1 << 18) +#define PMU_CC2_FORCE_PHY_PWR_SWITCH_ON (1 << 19) +#define PMU_CC2_FORCE_VDDM_PWR_SWITCH_ON (1 << 20) +#define PMU_CC2_FORCE_MEMLPLDO_PWR_SWITCH_ON (1 << 21) + +/* PMU chip control3 register */ +#define PMU_CHIPCTL3 3 + +/* PMU chip control6 register */ +#define PMU_CHIPCTL6 6 +#define PMU_CC6_ENABLE_CLKREQ_WAKEUP (1 << 4) +#define PMU_CC6_ENABLE_PMU_WAKEUP_ALP (1 << 6) + +#define PMU_CC3_ENABLE_SDIO_WAKEUP_SHIFT 19 +#define PMU_CC3_ENABLE_RF_SHIFT 22 +#define PMU_CC3_RF_DISABLE_IVALUE_SHIFT 23 + +/* PMU chip control5 register */ +#define PMU_CHIPCTL5 5 + +/* PMU chip control6 register */ +#define PMU_CHIPCTL6 6 +#define PMU_CC6_ENABLE_CLKREQ_WAKEUP (1 << 4) +#define PMU_CC6_ENABLE_PMU_WAKEUP_ALP (1 << 6) + +/* 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 */ +/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */ +#define PMU0_PLL0_PLLCTL0 0 +#define PMU0_PLL0_PC0_PDIV_MASK 1 +#define PMU0_PLL0_PC0_PDIV_FREQ 25000 +#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038 +#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3 +#define PMU0_PLL0_PC0_DIV_ARM_BASE 8 + +/* PC0_DIV_ARM for PLLOUT_ARM */ +#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0 +#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1 +#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2 +#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */ +#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4 +#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5 +#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6 +#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7 + +/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */ +#define PMU0_PLL0_PLLCTL1 1 +#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000 +#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28 +#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00 +#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8 +#define PMU0_PLL0_PC1_STOP_MOD 0x00000040 + +/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */ +#define PMU0_PLL0_PLLCTL2 2 +#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf +#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4 + +/* pllcontrol registers */ +/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ +#define PMU1_PLL0_PLLCTL0 0 +#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 +#define PMU1_PLL0_PC0_P1DIV_SHIFT 20 +#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 +#define PMU1_PLL0_PC0_P2DIV_SHIFT 24 + +/* mdiv */ +#define PMU1_PLL0_PLLCTL1 1 +#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff +#define PMU1_PLL0_PC1_M1DIV_SHIFT 0 +#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 +#define PMU1_PLL0_PC1_M2DIV_SHIFT 8 +#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 +#define PMU1_PLL0_PC1_M3DIV_SHIFT 16 +#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 +#define PMU1_PLL0_PC1_M4DIV_SHIFT 24 +#define PMU1_PLL0_PC1_M4DIV_BY_9 9 +#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12 +#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24 + +#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 +#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) +#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) + +/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ +#define PMU1_PLL0_PLLCTL2 2 +#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff +#define PMU1_PLL0_PC2_M5DIV_SHIFT 0 +#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc +#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12 +#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24 +#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 +#define PMU1_PLL0_PC2_M6DIV_SHIFT 8 +#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12 +#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24 +#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 +#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 +#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 +#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */ +#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 +#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 + +/* ndiv_frac */ +#define PMU1_PLL0_PLLCTL3 3 +#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff +#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 + +/* pll_ctrl */ +#define PMU1_PLL0_PLLCTL4 4 + +/* pll_ctrl, vco_rng, clkdrive_ch */ +#define PMU1_PLL0_PLLCTL5 5 +#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 +#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 + +#define PMU1_PLL0_PLLCTL6 6 +#define PMU1_PLL0_PLLCTL7 7 + +/* PMU rev 2 control words */ +#define PMU2_PHY_PLL_PLLCTL 4 +#define PMU2_SI_PLL_PLLCTL 10 + +/* PMU rev 2 */ +/* pllcontrol registers */ +/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ +#define PMU2_PLL_PLLCTL0 0 +#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 +#define PMU2_PLL_PC0_P1DIV_SHIFT 20 +#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 +#define PMU2_PLL_PC0_P2DIV_SHIFT 24 + +/* mdiv */ +#define PMU2_PLL_PLLCTL1 1 +#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff +#define PMU2_PLL_PC1_M1DIV_SHIFT 0 +#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 +#define PMU2_PLL_PC1_M2DIV_SHIFT 8 +#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 +#define PMU2_PLL_PC1_M3DIV_SHIFT 16 +#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000 +#define PMU2_PLL_PC1_M4DIV_SHIFT 24 + +/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ +#define PMU2_PLL_PLLCTL2 2 +#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff +#define PMU2_PLL_PC2_M5DIV_SHIFT 0 +#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 +#define PMU2_PLL_PC2_M6DIV_SHIFT 8 +#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 +#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 +#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 +#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20 + +/* ndiv_frac */ +#define PMU2_PLL_PLLCTL3 3 +#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff +#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 + +/* pll_ctrl */ +#define PMU2_PLL_PLLCTL4 4 + +/* pll_ctrl, vco_rng, clkdrive_ch */ +#define PMU2_PLL_PLLCTL5 5 +#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 +#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 +#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 +#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 +#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 +#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 +#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 +#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 +#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 +#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 +#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 +#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 + +/* PMU rev 5 (& 6) */ +#define PMU5_PLL_P1P2_OFF 0 +#define PMU5_PLL_P1_MASK 0x0f000000 +#define PMU5_PLL_P1_SHIFT 24 +#define PMU5_PLL_P2_MASK 0x00f00000 +#define PMU5_PLL_P2_SHIFT 20 +#define PMU5_PLL_M14_OFF 1 +#define PMU5_PLL_MDIV_MASK 0x000000ff +#define PMU5_PLL_MDIV_WIDTH 8 +#define PMU5_PLL_NM5_OFF 2 +#define PMU5_PLL_NDIV_MASK 0xfff00000 +#define PMU5_PLL_NDIV_SHIFT 20 +#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000 +#define PMU5_PLL_NDIV_MODE_SHIFT 17 +#define PMU5_PLL_FMAB_OFF 3 +#define PMU5_PLL_MRAT_MASK 0xf0000000 +#define PMU5_PLL_MRAT_SHIFT 28 +#define PMU5_PLL_ABRAT_MASK 0x08000000 +#define PMU5_PLL_ABRAT_SHIFT 27 +#define PMU5_PLL_FDIV_MASK 0x07ffffff +#define PMU5_PLL_PLLCTL_OFF 4 +#define PMU5_PLL_PCHI_OFF 5 +#define PMU5_PLL_PCHI_MASK 0x0000003f + +/* pmu XtalFreqRatio */ +#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF +#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 +#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 + +/* Divider allocation in 4716/47162/5356/5357 */ +#define PMU5_MAINPLL_CPU 1 +#define PMU5_MAINPLL_MEM 2 +#define PMU5_MAINPLL_SI 3 + +/* 4706 PMU */ +#define PMU4706_MAINPLL_PLL0 0 +#define PMU6_4706_PROCPLL_OFF 4 /* The CPU PLL */ +#define PMU6_4706_PROC_P2DIV_MASK 0x000f0000 +#define PMU6_4706_PROC_P2DIV_SHIFT 16 +#define PMU6_4706_PROC_P1DIV_MASK 0x0000f000 +#define PMU6_4706_PROC_P1DIV_SHIFT 12 +#define PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 +#define PMU6_4706_PROC_NDIV_INT_SHIFT 3 +#define PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 +#define PMU6_4706_PROC_NDIV_MODE_SHIFT 0 + +#define PMU7_PLL_PLLCTL7 7 +#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000 +#define PMU7_PLL_CTL7_M4DIV_SHIFT 24 +#define PMU7_PLL_CTL7_M4DIV_BY_6 6 +#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc +#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18 +#define PMU7_PLL_PLLCTL8 8 +#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff +#define PMU7_PLL_CTL8_M5DIV_SHIFT 0 +#define PMU7_PLL_CTL8_M5DIV_BY_8 8 +#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc +#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18 +#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00 +#define PMU7_PLL_CTL8_M6DIV_SHIFT 8 +#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc +#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18 +#define PMU7_PLL_PLLCTL11 11 +#define PMU7_PLL_PLLCTL11_MASK 0xffffff00 +#define PMU7_PLL_PLLCTL11_VAL 0x22222200 + +/* PMU rev 15 */ +#define PMU15_PLL_PLLCTL0 0 +#define PMU15_PLL_PC0_CLKSEL_MASK 0x00000003 +#define PMU15_PLL_PC0_CLKSEL_SHIFT 0 +#define PMU15_PLL_PC0_FREQTGT_MASK 0x003FFFFC +#define PMU15_PLL_PC0_FREQTGT_SHIFT 2 +#define PMU15_PLL_PC0_PRESCALE_MASK 0x00C00000 +#define PMU15_PLL_PC0_PRESCALE_SHIFT 22 +#define PMU15_PLL_PC0_KPCTRL_MASK 0x07000000 +#define PMU15_PLL_PC0_KPCTRL_SHIFT 24 +#define PMU15_PLL_PC0_FCNTCTRL_MASK 0x38000000 +#define PMU15_PLL_PC0_FCNTCTRL_SHIFT 27 +#define PMU15_PLL_PC0_FDCMODE_MASK 0x40000000 +#define PMU15_PLL_PC0_FDCMODE_SHIFT 30 +#define PMU15_PLL_PC0_CTRLBIAS_MASK 0x80000000 +#define PMU15_PLL_PC0_CTRLBIAS_SHIFT 31 + +#define PMU15_PLL_PLLCTL1 1 +#define PMU15_PLL_PC1_BIAS_CTLM_MASK 0x00000060 +#define PMU15_PLL_PC1_BIAS_CTLM_SHIFT 5 +#define PMU15_PLL_PC1_BIAS_CTLM_RST_MASK 0x00000040 +#define PMU15_PLL_PC1_BIAS_CTLM_RST_SHIFT 6 +#define PMU15_PLL_PC1_BIAS_SS_DIVR_MASK 0x0001FF80 +#define PMU15_PLL_PC1_BIAS_SS_DIVR_SHIFT 7 +#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_MASK 0x03FE0000 +#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_SHIFT 17 +#define PMU15_PLL_PC1_BIAS_INTG_BW_MASK 0x0C000000 +#define PMU15_PLL_PC1_BIAS_INTG_BW_SHIFT 26 +#define PMU15_PLL_PC1_BIAS_INTG_BYP_MASK 0x10000000 +#define PMU15_PLL_PC1_BIAS_INTG_BYP_SHIFT 28 +#define PMU15_PLL_PC1_OPENLP_EN_MASK 0x40000000 +#define PMU15_PLL_PC1_OPENLP_EN_SHIFT 30 + +#define PMU15_PLL_PLLCTL2 2 +#define PMU15_PLL_PC2_CTEN_MASK 0x00000001 +#define PMU15_PLL_PC2_CTEN_SHIFT 0 + +#define PMU15_PLL_PLLCTL3 3 +#define PMU15_PLL_PC3_DITHER_EN_MASK 0x00000001 +#define PMU15_PLL_PC3_DITHER_EN_SHIFT 0 +#define PMU15_PLL_PC3_DCOCTLSP_MASK 0xFE000000 +#define PMU15_PLL_PC3_DCOCTLSP_SHIFT 25 +#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_MASK 0x01 +#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_SHIFT 0 +#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_MASK 0x02 +#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_SHIFT 1 +#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_MASK 0x04 +#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_SHIFT 2 +#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_MASK 0x18 +#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_SHIFT 3 +#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_MASK 0x60 +#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_SHIFT 5 +#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV1 0 +#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV2 1 +#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV3 2 +#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV5 3 + +#define PMU15_PLL_PLLCTL4 4 +#define PMU15_PLL_PC4_FLLCLK1_DIV_MASK 0x00000007 +#define PMU15_PLL_PC4_FLLCLK1_DIV_SHIFT 0 +#define PMU15_PLL_PC4_FLLCLK2_DIV_MASK 0x00000038 +#define PMU15_PLL_PC4_FLLCLK2_DIV_SHIFT 3 +#define PMU15_PLL_PC4_FLLCLK3_DIV_MASK 0x000001C0 +#define PMU15_PLL_PC4_FLLCLK3_DIV_SHIFT 6 +#define PMU15_PLL_PC4_DBGMODE_MASK 0x00000E00 +#define PMU15_PLL_PC4_DBGMODE_SHIFT 9 +#define PMU15_PLL_PC4_FLL480_CTLSP_LK_MASK 0x00001000 +#define PMU15_PLL_PC4_FLL480_CTLSP_LK_SHIFT 12 +#define PMU15_PLL_PC4_FLL480_CTLSP_MASK 0x000FE000 +#define PMU15_PLL_PC4_FLL480_CTLSP_SHIFT 13 +#define PMU15_PLL_PC4_DINPOL_MASK 0x00100000 +#define PMU15_PLL_PC4_DINPOL_SHIFT 20 +#define PMU15_PLL_PC4_CLKOUT_PD_MASK 0x00200000 +#define PMU15_PLL_PC4_CLKOUT_PD_SHIFT 21 +#define PMU15_PLL_PC4_CLKDIV2_PD_MASK 0x00400000 +#define PMU15_PLL_PC4_CLKDIV2_PD_SHIFT 22 +#define PMU15_PLL_PC4_CLKDIV4_PD_MASK 0x00800000 +#define PMU15_PLL_PC4_CLKDIV4_PD_SHIFT 23 +#define PMU15_PLL_PC4_CLKDIV8_PD_MASK 0x01000000 +#define PMU15_PLL_PC4_CLKDIV8_PD_SHIFT 24 +#define PMU15_PLL_PC4_CLKDIV16_PD_MASK 0x02000000 +#define PMU15_PLL_PC4_CLKDIV16_PD_SHIFT 25 +#define PMU15_PLL_PC4_TEST_EN_MASK 0x04000000 +#define PMU15_PLL_PC4_TEST_EN_SHIFT 26 + +#define PMU15_PLL_PLLCTL5 5 +#define PMU15_PLL_PC5_FREQTGT_MASK 0x000FFFFF +#define PMU15_PLL_PC5_FREQTGT_SHIFT 0 +#define PMU15_PLL_PC5_DCOCTLSP_MASK 0x07F00000 +#define PMU15_PLL_PC5_DCOCTLSP_SHIFT 20 +#define PMU15_PLL_PC5_PRESCALE_MASK 0x18000000 +#define PMU15_PLL_PC5_PRESCALE_SHIFT 27 + +#define PMU15_PLL_PLLCTL6 6 +#define PMU15_PLL_PC6_FREQTGT_MASK 0x000FFFFF +#define PMU15_PLL_PC6_FREQTGT_SHIFT 0 +#define PMU15_PLL_PC6_DCOCTLSP_MASK 0x07F00000 +#define PMU15_PLL_PC6_DCOCTLSP_SHIFT 20 +#define PMU15_PLL_PC6_PRESCALE_MASK 0x18000000 +#define PMU15_PLL_PC6_PRESCALE_SHIFT 27 + +#define PMU15_FREQTGT_480_DEFAULT 0x19AB1 +#define PMU15_FREQTGT_492_DEFAULT 0x1A4F5 +#define PMU15_ARM_96MHZ 96000000 /* 96 Mhz */ +#define PMU15_ARM_98MHZ 98400000 /* 98.4 Mhz */ +#define PMU15_ARM_97MHZ 97000000 /* 97 Mhz */ + + +#define PMU17_PLLCTL2_NDIVTYPE_MASK 0x00000070 +#define PMU17_PLLCTL2_NDIVTYPE_SHIFT 4 + +#define PMU17_PLLCTL2_NDIV_MODE_INT 0 +#define PMU17_PLLCTL2_NDIV_MODE_INT1B8 1 +#define PMU17_PLLCTL2_NDIV_MODE_MASH111 2 +#define PMU17_PLLCTL2_NDIV_MODE_MASH111B8 3 + +#define PMU17_PLLCTL0_BBPLL_PWRDWN 0 +#define PMU17_PLLCTL0_BBPLL_DRST 3 +#define PMU17_PLLCTL0_BBPLL_DISBL_CLK 8 + +/* PLL usage in 4716/47162 */ +#define PMU4716_MAINPLL_PLL0 12 + +/* PLL usage in 4335 */ +#define PMU4335_PLL0_PC2_P1DIV_MASK 0x000f0000 +#define PMU4335_PLL0_PC2_P1DIV_SHIFT 16 +#define PMU4335_PLL0_PC2_NDIV_INT_MASK 0xff800000 +#define PMU4335_PLL0_PC2_NDIV_INT_SHIFT 23 +#define PMU4335_PLL0_PC1_MDIV2_MASK 0x0000ff00 +#define PMU4335_PLL0_PC1_MDIV2_SHIFT 8 + + +/* PLL usage in 5356/5357 */ +#define PMU5356_MAINPLL_PLL0 0 +#define PMU5357_MAINPLL_PLL0 0 + +/* 4716/47162 resources */ +#define RES4716_PROC_PLL_ON 0x00000040 +#define RES4716_PROC_HT_AVAIL 0x00000080 + +/* 4716/4717/4718 Chip specific ChipControl register bits */ +#define CCTRL_471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared w/ pflash */ + +/* 5357 Chip specific ChipControl register bits */ +/* 2nd - 32-bit reg */ +#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000 /* I2S pins enable */ +#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000 /* I2C/SPI pins enable */ + +/* 5354 resources */ +#define RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */ +#define RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */ +#define RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */ +#define RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ +#define RES5354_ILP_REQUEST 4 /* 0x00010 */ +#define RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */ +#define RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */ +#define RES5354_ROM_SWITCH 7 /* 0x00080 */ +#define RES5354_PA_REF_LDO 8 /* 0x00100 */ +#define RES5354_RADIO_LDO 9 /* 0x00200 */ +#define RES5354_AFE_LDO 10 /* 0x00400 */ +#define RES5354_PLL_LDO 11 /* 0x00800 */ +#define RES5354_BG_FILTBYP 12 /* 0x01000 */ +#define RES5354_TX_FILTBYP 13 /* 0x02000 */ +#define RES5354_RX_FILTBYP 14 /* 0x04000 */ +#define RES5354_XTAL_PU 15 /* 0x08000 */ +#define RES5354_XTAL_EN 16 /* 0x10000 */ +#define RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */ +#define RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */ +#define RES5354_BB_PLL_PU 19 /* 0x80000 */ + +/* 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 CCTRL5357_NFLASH (1<<16) /* Nandflash in ChipControl 1, bit 16 */ + +/* 43217 Chip specific ChipControl register bits */ +#define CCTRL43217_EXTPA_C0 (1<<13) /* core0 extPA in ChipControl 1, bit 13 */ +#define CCTRL43217_EXTPA_C1 (1<<8) /* core1 extPA in ChipControl 1, bit 8 */ + +/* 43228 Chip specific ChipControl register bits */ +#define CCTRL43228_EXTPA_C0 (1<<14) /* core1 extPA in ChipControl 1, bit 14 */ +#define CCTRL43228_EXTPA_C1 (1<<9) /* core0 extPA in ChipControl 1, bit 1 */ + +/* 4328 resources */ +#define RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */ +#define RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */ +#define RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */ +#define RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ +#define RES4328_ILP_REQUEST 4 /* 0x00010 */ +#define RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */ +#define RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */ +#define RES4328_ROM_SWITCH 7 /* 0x00080 */ +#define RES4328_PA_REF_LDO 8 /* 0x00100 */ +#define RES4328_RADIO_LDO 9 /* 0x00200 */ +#define RES4328_AFE_LDO 10 /* 0x00400 */ +#define RES4328_PLL_LDO 11 /* 0x00800 */ +#define RES4328_BG_FILTBYP 12 /* 0x01000 */ +#define RES4328_TX_FILTBYP 13 /* 0x02000 */ +#define RES4328_RX_FILTBYP 14 /* 0x04000 */ +#define RES4328_XTAL_PU 15 /* 0x08000 */ +#define RES4328_XTAL_EN 16 /* 0x10000 */ +#define RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */ +#define RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */ +#define RES4328_BB_PLL_PU 19 /* 0x80000 */ + +/* 4325 A0/A1 resources */ +#define RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */ +#define RES4325_CBUCK_BURST 1 /* 0x00000002 */ +#define RES4325_CBUCK_PWM 2 /* 0x00000004 */ +#define RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */ +#define RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */ +#define RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */ +#define RES4325_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4325_ABUCK_BURST 7 /* 0x00000080 */ +#define RES4325_ABUCK_PWM 8 /* 0x00000100 */ +#define RES4325_LNLDO1_PU 9 /* 0x00000200 */ +#define RES4325_OTP_PU 10 /* 0x00000400 */ +#define RES4325_LNLDO3_PU 11 /* 0x00000800 */ +#define RES4325_LNLDO4_PU 12 /* 0x00001000 */ +#define RES4325_XTAL_PU 13 /* 0x00002000 */ +#define RES4325_ALP_AVAIL 14 /* 0x00004000 */ +#define RES4325_RX_PWRSW_PU 15 /* 0x00008000 */ +#define RES4325_TX_PWRSW_PU 16 /* 0x00010000 */ +#define RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define RES4325_HT_AVAIL 21 /* 0x00200000 */ + +/* 4325 B0/C0 resources */ +#define RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */ +#define RES4325B0_CBUCK_BURST 2 /* 0x00000004 */ +#define RES4325B0_CBUCK_PWM 3 /* 0x00000008 */ +#define RES4325B0_CLDO_PU 4 /* 0x00000010 */ + +/* 4325 C1 resources */ +#define RES4325C1_LNLDO2_PU 12 /* 0x00001000 */ + +/* 4325 chip-specific ChipStatus register bits */ +#define CST4325_SPROM_OTP_SEL_MASK 0x00000003 +#define CST4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ +#define CST4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ +#define CST4325_OTP_SEL 2 /* OTP is powered up, no SPROM */ +#define CST4325_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ +#define CST4325_SDIO_USB_MODE_MASK 0x00000004 +#define CST4325_SDIO_USB_MODE_SHIFT 2 +#define CST4325_RCAL_VALID_MASK 0x00000008 +#define CST4325_RCAL_VALID_SHIFT 3 +#define CST4325_RCAL_VALUE_MASK 0x000001f0 +#define CST4325_RCAL_VALUE_SHIFT 4 +#define CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */ +#define CST4325_PMUTOP_2B_SHIFT 9 + +#define RES4329_RESERVED0 0 /* 0x00000001 */ +#define RES4329_CBUCK_LPOM 1 /* 0x00000002 */ +#define RES4329_CBUCK_BURST 2 /* 0x00000004 */ +#define RES4329_CBUCK_PWM 3 /* 0x00000008 */ +#define RES4329_CLDO_PU 4 /* 0x00000010 */ +#define RES4329_PALDO_PU 5 /* 0x00000020 */ +#define RES4329_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4329_RESERVED7 7 /* 0x00000080 */ +#define RES4329_RESERVED8 8 /* 0x00000100 */ +#define RES4329_LNLDO1_PU 9 /* 0x00000200 */ +#define RES4329_OTP_PU 10 /* 0x00000400 */ +#define RES4329_RESERVED11 11 /* 0x00000800 */ +#define RES4329_LNLDO2_PU 12 /* 0x00001000 */ +#define RES4329_XTAL_PU 13 /* 0x00002000 */ +#define RES4329_ALP_AVAIL 14 /* 0x00004000 */ +#define RES4329_RX_PWRSW_PU 15 /* 0x00008000 */ +#define RES4329_TX_PWRSW_PU 16 /* 0x00010000 */ +#define RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define RES4329_HT_AVAIL 21 /* 0x00200000 */ + +#define CST4329_SPROM_OTP_SEL_MASK 0x00000003 +#define CST4329_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ +#define CST4329_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ +#define CST4329_OTP_SEL 2 /* OTP is powered up, no SPROM */ +#define CST4329_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ +#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 +#define CST4329_SPI_SDIO_MODE_SHIFT 2 + +/* 4312 chip-specific ChipStatus register bits */ +#define CST4312_SPROM_OTP_SEL_MASK 0x00000003 +#define CST4312_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ +#define CST4312_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ +#define CST4312_OTP_SEL 2 /* OTP is powered up, no SPROM */ +#define CST4312_OTP_BAD 3 /* OTP is broken, SPROM is present */ + +/* 4312 resources (all PMU chips with little memory constraint) */ +#define RES4312_SWITCHER_BURST 0 /* 0x00000001 */ +#define RES4312_SWITCHER_PWM 1 /* 0x00000002 */ +#define RES4312_PA_REF_LDO 2 /* 0x00000004 */ +#define RES4312_CORE_LDO_BURST 3 /* 0x00000008 */ +#define RES4312_CORE_LDO_PWM 4 /* 0x00000010 */ +#define RES4312_RADIO_LDO 5 /* 0x00000020 */ +#define RES4312_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4312_BG_FILTBYP 7 /* 0x00000080 */ +#define RES4312_TX_FILTBYP 8 /* 0x00000100 */ +#define RES4312_RX_FILTBYP 9 /* 0x00000200 */ +#define RES4312_XTAL_PU 10 /* 0x00000400 */ +#define RES4312_ALP_AVAIL 11 /* 0x00000800 */ +#define RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */ +#define RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */ +#define RES4312_HT_AVAIL 14 /* 0x00004000 */ + +/* 4322 resources */ +#define RES4322_RF_LDO 0 +#define RES4322_ILP_REQUEST 1 +#define RES4322_XTAL_PU 2 +#define RES4322_ALP_AVAIL 3 +#define RES4322_SI_PLL_ON 4 +#define RES4322_HT_SI_AVAIL 5 +#define RES4322_PHY_PLL_ON 6 +#define RES4322_HT_PHY_AVAIL 7 +#define RES4322_OTP_PU 8 + +/* 4322 chip-specific ChipStatus register bits */ +#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020 +#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0 +#define CST4322_SPROM_OTP_SEL_SHIFT 6 +#define CST4322_NO_SPROM_OTP 0 /* no OTP, no SPROM */ +#define CST4322_SPROM_PRESENT 1 /* SPROM is present */ +#define CST4322_OTP_PRESENT 2 /* OTP is present */ +#define CST4322_PCI_OR_USB 0x00000100 +#define CST4322_BOOT_MASK 0x00000600 +#define CST4322_BOOT_SHIFT 9 +#define CST4322_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ +#define CST4322_BOOT_FROM_ROM 1 /* boot from ROM */ +#define CST4322_BOOT_FROM_FLASH 2 /* boot from FLASH */ +#define CST4322_BOOT_FROM_INVALID 3 +#define CST4322_ILP_DIV_EN 0x00000800 +#define CST4322_FLASH_TYPE_MASK 0x00001000 +#define CST4322_FLASH_TYPE_SHIFT 12 +#define CST4322_FLASH_TYPE_SHIFT_ST 0 /* ST serial FLASH */ +#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1 /* ATMEL flash */ +#define CST4322_ARM_TAP_SEL 0x00002000 +#define CST4322_RES_INIT_MODE_MASK 0x0000c000 +#define CST4322_RES_INIT_MODE_SHIFT 14 +#define CST4322_RES_INIT_MODE_ILPAVAIL 0 /* resinitmode: ILP available */ +#define CST4322_RES_INIT_MODE_ILPREQ 1 /* resinitmode: ILP request */ +#define CST4322_RES_INIT_MODE_ALPAVAIL 2 /* resinitmode: ALP available */ +#define CST4322_RES_INIT_MODE_HTAVAIL 3 /* resinitmode: HT available */ +#define CST4322_PCIPLLCLK_GATING 0x00010000 +#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 +#define CST4322_PCI_CARDBUS_MODE 0x00040000 + +/* 43224 chip-specific ChipControl register bits */ +#define CCTRL43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */ +#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */ +#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */ + +/* 43236 resources */ +#define RES43236_REGULATOR 0 +#define RES43236_ILP_REQUEST 1 +#define RES43236_XTAL_PU 2 +#define RES43236_ALP_AVAIL 3 +#define RES43236_SI_PLL_ON 4 +#define RES43236_HT_SI_AVAIL 5 + +/* 43236 chip-specific ChipControl register bits */ +#define CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */ +#define CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ +#define CCTRL43236_EXT_LNA (1<<2) /* 0 disable */ +#define CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ +#define CCTRL43236_GSIO (1<<4) /* 0 disable */ + +/* 43236 Chip specific ChipStatus register bits */ +#define CST43236_SFLASH_MASK 0x00000040 +#define CST43236_OTP_SEL_MASK 0x00000080 +#define CST43236_OTP_SEL_SHIFT 7 +#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 + +/* 43237 resources */ +#define RES43237_REGULATOR 0 +#define RES43237_ILP_REQUEST 1 +#define RES43237_XTAL_PU 2 +#define RES43237_ALP_AVAIL 3 +#define RES43237_SI_PLL_ON 4 +#define RES43237_HT_SI_AVAIL 5 + +/* 43237 chip-specific ChipControl register bits */ +#define CCTRL43237_BT_COEXIST (1<<0) /* 0 disable */ +#define CCTRL43237_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ +#define CCTRL43237_EXT_LNA (1<<2) /* 0 disable */ +#define CCTRL43237_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ +#define CCTRL43237_GSIO (1<<4) /* 0 disable */ + +/* 43237 Chip specific ChipStatus register bits */ +#define CST43237_SFLASH_MASK 0x00000040 +#define CST43237_OTP_SEL_MASK 0x00000080 +#define CST43237_OTP_SEL_SHIFT 7 +#define CST43237_HSIC_MASK 0x00000100 /* USB/HSIC */ +#define CST43237_BP_CLK 0x00000200 /* 120/96Mbps */ +#define CST43237_BOOT_MASK 0x00001800 +#define CST43237_BOOT_SHIFT 11 +#define CST43237_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ +#define CST43237_BOOT_FROM_ROM 1 /* boot from ROM */ +#define CST43237_BOOT_FROM_FLASH 2 /* boot from FLASH */ +#define CST43237_BOOT_FROM_INVALID 3 + +/* 43239 resources */ +#define RES43239_OTP_PU 9 +#define RES43239_MACPHY_CLKAVAIL 23 +#define RES43239_HT_AVAIL 24 + +/* 43239 Chip specific ChipStatus register bits */ +#define CST43239_SPROM_MASK 0x00000002 +#define CST43239_SFLASH_MASK 0x00000004 +#define CST43239_RES_INIT_MODE_SHIFT 7 +#define CST43239_RES_INIT_MODE_MASK 0x000001f0 +#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) /* SDIO || gSPI */ +#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15)) /* USB || USBDA */ +#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) /* SDIO */ +#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) /* gSPI */ + +/* 4324 resources */ +/* 43242 use same PMU as 4324 */ +#define RES4324_LPLDO_PU 0 +#define RES4324_RESET_PULLDN_DIS 1 +#define RES4324_PMU_BG_PU 2 +#define RES4324_HSIC_LDO_PU 3 +#define RES4324_CBUCK_LPOM_PU 4 +#define RES4324_CBUCK_PFM_PU 5 +#define RES4324_CLDO_PU 6 +#define RES4324_LPLDO2_LVM 7 +#define RES4324_LNLDO1_PU 8 +#define RES4324_LNLDO2_PU 9 +#define RES4324_LDO3P3_PU 10 +#define RES4324_OTP_PU 11 +#define RES4324_XTAL_PU 12 +#define RES4324_BBPLL_PU 13 +#define RES4324_LQ_AVAIL 14 +#define RES4324_WL_CORE_READY 17 +#define RES4324_ILP_REQ 18 +#define RES4324_ALP_AVAIL 19 +#define RES4324_PALDO_PU 20 +#define RES4324_RADIO_PU 21 +#define RES4324_SR_CLK_STABLE 22 +#define RES4324_SR_SAVE_RESTORE 23 +#define RES4324_SR_PHY_PWRSW 24 +#define RES4324_SR_PHY_PIC 25 +#define RES4324_SR_SUBCORE_PWRSW 26 +#define RES4324_SR_SUBCORE_PIC 27 +#define RES4324_SR_MEM_PM0 28 +#define RES4324_HT_AVAIL 29 +#define RES4324_MACPHY_CLKAVAIL 30 + +/* 4324 Chip specific ChipStatus register bits */ +#define CST4324_SPROM_MASK 0x00000080 +#define CST4324_SFLASH_MASK 0x00400000 +#define CST4324_RES_INIT_MODE_SHIFT 10 +#define CST4324_RES_INIT_MODE_MASK 0x00000c00 +#define CST4324_CHIPMODE_MASK 0x7 +#define CST4324_CHIPMODE_SDIOD(cs) ((~(cs)) & (1 << 2)) /* SDIO || gSPI */ +#define CST4324_CHIPMODE_USB20D(cs) (((cs) & CST4324_CHIPMODE_MASK) == 0x6) /* USB || USBDA */ + +/* 43242 Chip specific ChipStatus register bits */ +#define CST43242_SFLASH_MASK 0x00000008 +#define CST43242_SR_HALT (1<<25) +#define CST43242_SR_CHIP_STATUS_2 27 /* bit 27 */ + +/* 4331 resources */ +#define RES4331_REGULATOR 0 +#define RES4331_ILP_REQUEST 1 +#define RES4331_XTAL_PU 2 +#define RES4331_ALP_AVAIL 3 +#define RES4331_SI_PLL_ON 4 +#define RES4331_HT_SI_AVAIL 5 + +/* 4331 chip-specific ChipControl register bits */ +#define CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */ +#define CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ +#define CCTRL4331_EXT_LNA_G (1<<2) /* 0 disable */ +#define CCTRL4331_SPROM_GPIO13_15 (1<<3) /* sprom/gpio13-15 mux */ +#define CCTRL4331_EXTPA_EN (1<<4) /* 0 ext pa disable, 1 ext pa enabled */ +#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) /* set drive out GPIO_CLK on sprom_cs pin */ +#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) /* use sprom_cs pin as PCIE mdio interface */ +#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) /* aband extpa will be at gpio2/5 and sprom_dout */ +#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) /* override core control on pipe_AuxClkEnable */ +#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) /* override core control on pipe_AuxPowerDown */ +#define CCTRL4331_PCIE_AUXCLKEN (1<<10) /* pcie_auxclkenable */ +#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) /* pcie_pipe_pllpowerdown */ +#define CCTRL4331_EXTPA_EN2 (1<<12) /* 0 ext pa disable, 1 ext pa enabled */ +#define CCTRL4331_EXT_LNA_A (1<<13) /* 0 disable */ +#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */ +#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */ +#define CCTRL4331_EXTPA_ANA_EN (1<<24) /* 0 ext pa disable, 1 ext pa enabled */ + +/* 4331 Chip specific ChipStatus register bits */ +#define CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */ +#define CST4331_SPROM_OTP_SEL_MASK 0x00000006 +#define CST4331_SPROM_OTP_SEL_SHIFT 1 +#define CST4331_SPROM_PRESENT 0x00000002 +#define CST4331_OTP_PRESENT 0x00000004 +#define CST4331_LDO_RF 0x00000008 +#define CST4331_LDO_PAR 0x00000010 + +/* 4315 resource */ +#define RES4315_CBUCK_LPOM 1 /* 0x00000002 */ +#define RES4315_CBUCK_BURST 2 /* 0x00000004 */ +#define RES4315_CBUCK_PWM 3 /* 0x00000008 */ +#define RES4315_CLDO_PU 4 /* 0x00000010 */ +#define RES4315_PALDO_PU 5 /* 0x00000020 */ +#define RES4315_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4315_LNLDO1_PU 9 /* 0x00000200 */ +#define RES4315_OTP_PU 10 /* 0x00000400 */ +#define RES4315_LNLDO2_PU 12 /* 0x00001000 */ +#define RES4315_XTAL_PU 13 /* 0x00002000 */ +#define RES4315_ALP_AVAIL 14 /* 0x00004000 */ +#define RES4315_RX_PWRSW_PU 15 /* 0x00008000 */ +#define RES4315_TX_PWRSW_PU 16 /* 0x00010000 */ +#define RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define RES4315_HT_AVAIL 21 /* 0x00200000 */ + +/* 4315 chip-specific ChipStatus register bits */ +#define CST4315_SPROM_OTP_SEL_MASK 0x00000003 /* gpio [7:6], SDIO CIS selection */ +#define CST4315_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ +#define CST4315_SPROM_SEL 0x00000001 /* use SPROM, OTP is powered up */ +#define CST4315_OTP_SEL 0x00000002 /* use OTP, OTP is powered up */ +#define CST4315_OTP_PWRDN 0x00000003 /* use SPROM, OTP is powered down */ +#define CST4315_SDIO_MODE 0x00000004 /* gpio [8], sdio/usb mode */ +#define CST4315_RCAL_VALID 0x00000008 +#define CST4315_RCAL_VALUE_MASK 0x000001f0 +#define CST4315_RCAL_VALUE_SHIFT 4 +#define CST4315_PALDO_EXTPNP 0x00000200 /* PALDO is configured with external PNP */ +#define CST4315_CBUCK_MODE_MASK 0x00000c00 +#define CST4315_CBUCK_MODE_BURST 0x00000400 +#define CST4315_CBUCK_MODE_LPBURST 0x00000c00 + +/* 4319 resources */ +#define RES4319_CBUCK_LPOM 1 /* 0x00000002 */ +#define RES4319_CBUCK_BURST 2 /* 0x00000004 */ +#define RES4319_CBUCK_PWM 3 /* 0x00000008 */ +#define RES4319_CLDO_PU 4 /* 0x00000010 */ +#define RES4319_PALDO_PU 5 /* 0x00000020 */ +#define RES4319_ILP_REQUEST 6 /* 0x00000040 */ +#define RES4319_LNLDO1_PU 9 /* 0x00000200 */ +#define RES4319_OTP_PU 10 /* 0x00000400 */ +#define RES4319_LNLDO2_PU 12 /* 0x00001000 */ +#define RES4319_XTAL_PU 13 /* 0x00002000 */ +#define RES4319_ALP_AVAIL 14 /* 0x00004000 */ +#define RES4319_RX_PWRSW_PU 15 /* 0x00008000 */ +#define RES4319_TX_PWRSW_PU 16 /* 0x00010000 */ +#define RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define RES4319_HT_AVAIL 21 /* 0x00200000 */ + +/* 4319 chip-specific ChipStatus register bits */ +#define CST4319_SPI_CPULESSUSB 0x00000001 +#define CST4319_SPI_CLK_POL 0x00000002 +#define CST4319_SPI_CLK_PH 0x00000008 +#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 /* gpio [7:6], SDIO CIS selection */ +#define CST4319_SPROM_OTP_SEL_SHIFT 6 +#define CST4319_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ +#define CST4319_SPROM_SEL 0x00000040 /* use SPROM, OTP is powered up */ +#define CST4319_OTP_SEL 0x00000080 /* use OTP, OTP is powered up */ +#define CST4319_OTP_PWRDN 0x000000c0 /* use SPROM, OTP is powered down */ +#define CST4319_SDIO_USB_MODE 0x00000100 /* gpio [8], sdio/usb mode */ +#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 +#define CST4319_PALDO_EXTPNP 0x00010000 /* PALDO is configured with external PNP */ +#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 + +#define PMU1_PLL0_CHIPCTL0 0 +#define PMU1_PLL0_CHIPCTL1 1 +#define PMU1_PLL0_CHIPCTL2 2 +#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000 +#define CCTL_4319USB_XTAL_SEL_SHIFT 19 +#define CCTL_4319USB_48MHZ_PLL_SEL 1 +#define CCTL_4319USB_24MHZ_PLL_SEL 2 + +/* PMU resources for 4336 */ +#define RES4336_CBUCK_LPOM 0 +#define RES4336_CBUCK_BURST 1 +#define RES4336_CBUCK_LP_PWM 2 +#define RES4336_CBUCK_PWM 3 +#define RES4336_CLDO_PU 4 +#define RES4336_DIS_INT_RESET_PD 5 +#define RES4336_ILP_REQUEST 6 +#define RES4336_LNLDO_PU 7 +#define RES4336_LDO3P3_PU 8 +#define RES4336_OTP_PU 9 +#define RES4336_XTAL_PU 10 +#define RES4336_ALP_AVAIL 11 +#define RES4336_RADIO_PU 12 +#define RES4336_BG_PU 13 +#define RES4336_VREG1p4_PU_PU 14 +#define RES4336_AFE_PWRSW_PU 15 +#define RES4336_RX_PWRSW_PU 16 +#define RES4336_TX_PWRSW_PU 17 +#define RES4336_BB_PWRSW_PU 18 +#define RES4336_SYNTH_PWRSW_PU 19 +#define RES4336_MISC_PWRSW_PU 20 +#define RES4336_LOGEN_PWRSW_PU 21 +#define RES4336_BBPLL_PWRSW_PU 22 +#define RES4336_MACPHY_CLKAVAIL 23 +#define RES4336_HT_AVAIL 24 +#define RES4336_RSVD 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 + +/* 4336 Chip specific PMU ChipControl register bits */ +#define PCTL_4336_SERIAL_ENAB (1 << 24) + +/* 4330 resources */ +#define RES4330_CBUCK_LPOM 0 +#define RES4330_CBUCK_BURST 1 +#define RES4330_CBUCK_LP_PWM 2 +#define RES4330_CBUCK_PWM 3 +#define RES4330_CLDO_PU 4 +#define RES4330_DIS_INT_RESET_PD 5 +#define RES4330_ILP_REQUEST 6 +#define RES4330_LNLDO_PU 7 +#define RES4330_LDO3P3_PU 8 +#define RES4330_OTP_PU 9 +#define RES4330_XTAL_PU 10 +#define RES4330_ALP_AVAIL 11 +#define RES4330_RADIO_PU 12 +#define RES4330_BG_PU 13 +#define RES4330_VREG1p4_PU_PU 14 +#define RES4330_AFE_PWRSW_PU 15 +#define RES4330_RX_PWRSW_PU 16 +#define RES4330_TX_PWRSW_PU 17 +#define RES4330_BB_PWRSW_PU 18 +#define RES4330_SYNTH_PWRSW_PU 19 +#define RES4330_MISC_PWRSW_PU 20 +#define RES4330_LOGEN_PWRSW_PU 21 +#define RES4330_BBPLL_PWRSW_PU 22 +#define RES4330_MACPHY_CLKAVAIL 23 +#define RES4330_HT_AVAIL 24 +#define RES4330_5gRX_PWRSW_PU 25 +#define RES4330_5gTX_PWRSW_PU 26 +#define RES4330_5g_LOGEN_PWRSW_PU 27 + +/* 4330 chip-specific ChipStatus register bits */ +#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */ +#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */ +#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) /* SDIO */ +#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) /* gSPI */ +#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) /* USB packet-oriented */ +#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) /* USB Direct Access */ +#define CST4330_OTP_PRESENT 0x00000010 +#define CST4330_LPO_AUTODET_EN 0x00000020 +#define CST4330_ARMREMAP_0 0x00000040 +#define CST4330_SPROM_PRESENT 0x00000080 /* takes priority over OTP if both set */ +#define CST4330_ILPDIV_EN 0x00000100 +#define CST4330_LPO_SEL 0x00000200 +#define CST4330_RES_INIT_MODE_SHIFT 10 +#define CST4330_RES_INIT_MODE_MASK 0x00000c00 +#define CST4330_CBUCK_MODE_SHIFT 12 +#define CST4330_CBUCK_MODE_MASK 0x00003000 +#define CST4330_CBUCK_POWER_OK 0x00004000 +#define CST4330_BB_PLL_LOCKED 0x00008000 +#define SOCDEVRAM_BP_ADDR 0x1E000000 +#define SOCDEVRAM_ARM_ADDR 0x00800000 + +/* 4330 Chip specific PMU ChipControl register bits */ +#define PCTL_4330_SERIAL_ENAB (1 << 24) + +/* 4330 Chip specific ChipControl register bits */ +#define CCTRL_4330_GPIO_SEL 0x00000001 /* 1=select GPIOs to be muxed out */ +#define CCTRL_4330_ERCX_SEL 0x00000002 /* 1=select ERCX BT coex to be muxed out */ +#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004 /* SDIO: 1=configure GPIO0 for host wake */ +#define CCTRL_4330_JTAG_DISABLE 0x00000008 /* 1=disable JTAG interface on mux'd pins */ + +#define PMU_VREG0_ADDR 0 +#define PMU_VREG0_DISABLE_PULLD_BT_SHIFT 2 +#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 3 + +#define PMU_VREG4_ADDR 4 + +#define PMU_VREG4_CLDO_PWM_SHIFT 4 +#define PMU_VREG4_CLDO_PWM_MASK 0x7 + +#define PMU_VREG4_LPLDO1_SHIFT 15 +#define PMU_VREG4_LPLDO1_MASK 0x7 +#define PMU_VREG4_LPLDO1_1p20V 0 +#define PMU_VREG4_LPLDO1_1p15V 1 +#define PMU_VREG4_LPLDO1_1p10V 2 +#define PMU_VREG4_LPLDO1_1p25V 3 +#define PMU_VREG4_LPLDO1_1p05V 4 +#define PMU_VREG4_LPLDO1_1p00V 5 +#define PMU_VREG4_LPLDO1_0p95V 6 +#define PMU_VREG4_LPLDO1_0p90V 7 + +#define PMU_VREG4_LPLDO2_LVM_SHIFT 18 +#define PMU_VREG4_LPLDO2_LVM_MASK 0x7 +#define PMU_VREG4_LPLDO2_HVM_SHIFT 21 +#define PMU_VREG4_LPLDO2_HVM_MASK 0x7 +#define PMU_VREG4_LPLDO2_LVM_HVM_MASK 0x3f +#define PMU_VREG4_LPLDO2_1p00V 0 +#define PMU_VREG4_LPLDO2_1p15V 1 +#define PMU_VREG4_LPLDO2_1p20V 2 +#define PMU_VREG4_LPLDO2_1p10V 3 +#define PMU_VREG4_LPLDO2_0p90V 4 /* 4 - 7 is 0.90V */ + +#define PMU_VREG4_HSICLDO_BYPASS_SHIFT 27 +#define PMU_VREG4_HSICLDO_BYPASS_MASK 0x1 + +#define PMU_VREG5_ADDR 5 +#define PMU_VREG5_HSICAVDD_PD_SHIFT 6 +#define PMU_VREG5_HSICAVDD_PD_MASK 0x1 +#define PMU_VREG5_HSICDVDD_PD_SHIFT 11 +#define PMU_VREG5_HSICDVDD_PD_MASK 0x1 + +/* 4334 resources */ +#define RES4334_LPLDO_PU 0 +#define RES4334_RESET_PULLDN_DIS 1 +#define RES4334_PMU_BG_PU 2 +#define RES4334_HSIC_LDO_PU 3 +#define RES4334_CBUCK_LPOM_PU 4 +#define RES4334_CBUCK_PFM_PU 5 +#define RES4334_CLDO_PU 6 +#define RES4334_LPLDO2_LVM 7 +#define RES4334_LNLDO_PU 8 +#define RES4334_LDO3P3_PU 9 +#define RES4334_OTP_PU 10 +#define RES4334_XTAL_PU 11 +#define RES4334_WL_PWRSW_PU 12 +#define RES4334_LQ_AVAIL 13 +#define RES4334_LOGIC_RET 14 +#define RES4334_MEM_SLEEP 15 +#define RES4334_MACPHY_RET 16 +#define RES4334_WL_CORE_READY 17 +#define RES4334_ILP_REQ 18 +#define RES4334_ALP_AVAIL 19 +#define RES4334_MISC_PWRSW_PU 20 +#define RES4334_SYNTH_PWRSW_PU 21 +#define RES4334_RX_PWRSW_PU 22 +#define RES4334_RADIO_PU 23 +#define RES4334_WL_PMU_PU 24 +#define RES4334_VCO_LDO_PU 25 +#define RES4334_AFE_LDO_PU 26 +#define RES4334_RX_LDO_PU 27 +#define RES4334_TX_LDO_PU 28 +#define RES4334_HT_AVAIL 29 +#define RES4334_MACPHY_CLK_AVAIL 30 + +/* 4334 chip-specific ChipStatus register bits */ +#define CST4334_CHIPMODE_MASK 7 +#define CST4334_SDIO_MODE 0x00000000 +#define CST4334_SPI_MODE 0x00000004 +#define CST4334_HSIC_MODE 0x00000006 +#define CST4334_BLUSB_MODE 0x00000007 +#define CST4334_CHIPMODE_HSIC(cs) (((cs) & CST4334_CHIPMODE_MASK) == CST4334_HSIC_MODE) +#define CST4334_OTP_PRESENT 0x00000010 +#define CST4334_LPO_AUTODET_EN 0x00000020 +#define CST4334_ARMREMAP_0 0x00000040 +#define CST4334_SPROM_PRESENT 0x00000080 +#define CST4334_ILPDIV_EN_MASK 0x00000100 +#define CST4334_ILPDIV_EN_SHIFT 8 +#define CST4334_LPO_SEL_MASK 0x00000200 +#define CST4334_LPO_SEL_SHIFT 9 +#define CST4334_RES_INIT_MODE_MASK 0x00000C00 +#define CST4334_RES_INIT_MODE_SHIFT 10 + +/* 4334 Chip specific PMU ChipControl register bits */ +#define PCTL_4334_GPIO3_ENAB (1 << 3) + +/* 4334 Chip control */ +#define CCTRL4334_PMU_WAKEUP_GPIO1 (1 << 0) +#define CCTRL4334_PMU_WAKEUP_HSIC (1 << 1) +#define CCTRL4334_PMU_WAKEUP_AOS (1 << 2) +#define CCTRL4334_HSIC_WAKE_MODE (1 << 3) +#define CCTRL4334_HSIC_INBAND_GPIO1 (1 << 4) +#define CCTRL4334_HSIC_LDO_PU (1 << 23) + +/* 4334 Chip control 3 */ +#define CCTRL4334_BLOCK_EXTRNL_WAKE (1 << 4) +#define CCTRL4334_SAVERESTORE_FIX (1 << 5) + +/* 43341 Chip control 3 */ +#define CCTRL43341_BLOCK_EXTRNL_WAKE (1 << 13) +#define CCTRL43341_SAVERESTORE_FIX (1 << 14) +#define CCTRL43341_BT_ISO_SEL (1 << 16) + +/* 4334 Chip specific ChipControl1 register bits */ +#define CCTRL1_4334_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ +#define CCTRL1_4334_ERCX_SEL (1 << 1) /* 1=select ERCX BT coex to be muxed out */ +#define CCTRL1_4334_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ +#define CCTRL1_4334_JTAG_DISABLE (1 << 3) /* 1=disable JTAG interface on mux'd pins */ +#define CCTRL1_4334_UART_ON_4_5 (1 << 28) /* 1=UART_TX/UART_RX muxed on GPIO_4/5 (4334B0/1) */ + +/* 4324 Chip specific ChipControl1 register bits */ +#define CCTRL1_4324_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ +#define CCTRL1_4324_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ + +/* 43143 chip-specific ChipStatus register bits based on Confluence documentation */ +/* register contains strap values sampled during POR */ +#define CST43143_REMAP_TO_ROM (3 << 0) /* 00=Boot SRAM, 01=Boot ROM, 10=Boot SFLASH */ +#define CST43143_SDIO_EN (1 << 2) /* 0 = USB Enab, SDIO pins are GPIO or I2S */ +#define CST43143_SDIO_ISO (1 << 3) /* 1 = SDIO isolated */ +#define CST43143_USB_CPU_LESS (1 << 4) /* 1 = CPULess mode Enabled */ +#define CST43143_CBUCK_MODE (3 << 6) /* Indicates what controller mode CBUCK is in */ +#define CST43143_POK_CBUCK (1 << 8) /* 1 = 1.2V CBUCK voltage ready */ +#define CST43143_PMU_OVRSPIKE (1 << 9) +#define CST43143_PMU_OVRTEMP (0xF << 10) +#define CST43143_SR_FLL_CAL_DONE (1 << 14) +#define CST43143_USB_PLL_LOCKDET (1 << 15) +#define CST43143_PMU_PLL_LOCKDET (1 << 16) +#define CST43143_CHIPMODE_SDIOD(cs) (((cs) & CST43143_SDIO_EN) != 0) /* SDIO */ + +/* 43143 Chip specific ChipControl register bits */ +/* 00: SECI is disabled (JATG functional), 01: 2 wire, 10: 4 wire */ +#define CCTRL_43143_SECI (1<<0) +#define CCTRL_43143_BT_LEGACY (1<<1) +#define CCTRL_43143_I2S_MODE (1<<2) /* 0: SDIO enabled */ +#define CCTRL_43143_I2S_MASTER (1<<3) /* 0: I2S MCLK input disabled */ +#define CCTRL_43143_I2S_FULL (1<<4) /* 0: I2S SDIN and SPDIF_TX inputs disabled */ +#define CCTRL_43143_GSIO (1<<5) /* 0: sFlash enabled */ +#define CCTRL_43143_RF_SWCTRL_MASK (7<<6) /* 0: disabled */ +#define CCTRL_43143_RF_SWCTRL_0 (1<<6) +#define CCTRL_43143_RF_SWCTRL_1 (2<<6) +#define CCTRL_43143_RF_SWCTRL_2 (4<<6) +#define CCTRL_43143_RF_XSWCTRL (1<<9) /* 0: UART enabled */ +#define CCTRL_43143_HOST_WAKE0 (1<<11) /* 1: SDIO separate interrupt output from GPIO4 */ +#define CCTRL_43143_HOST_WAKE1 (1<<12) /* 1: SDIO separate interrupt output from GPIO16 */ + +/* 43143 resources, based on pmu_params.xls V1.19 */ +#define RES43143_EXT_SWITCHER_PWM 0 /* 0x00001 */ +#define RES43143_XTAL_PU 1 /* 0x00002 */ +#define RES43143_ILP_REQUEST 2 /* 0x00004 */ +#define RES43143_ALP_AVAIL 3 /* 0x00008 */ +#define RES43143_WL_CORE_READY 4 /* 0x00010 */ +#define RES43143_BBPLL_PWRSW_PU 5 /* 0x00020 */ +#define RES43143_HT_AVAIL 6 /* 0x00040 */ +#define RES43143_RADIO_PU 7 /* 0x00080 */ +#define RES43143_MACPHY_CLK_AVAIL 8 /* 0x00100 */ +#define RES43143_OTP_PU 9 /* 0x00200 */ +#define RES43143_LQ_AVAIL 10 /* 0x00400 */ + +#define PMU43143_XTAL_CORE_SIZE_MASK 0x3F + +/* 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 + +/* 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 */ +#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */ + +/* PMU respources for 4314 */ +#define RES4314_LPLDO_PU 0 +#define RES4314_PMU_SLEEP_DIS 1 +#define RES4314_PMU_BG_PU 2 +#define RES4314_CBUCK_LPOM_PU 3 +#define RES4314_CBUCK_PFM_PU 4 +#define RES4314_CLDO_PU 5 +#define RES4314_LPLDO2_LVM 6 +#define RES4314_WL_PMU_PU 7 +#define RES4314_LNLDO_PU 8 +#define RES4314_LDO3P3_PU 9 +#define RES4314_OTP_PU 10 +#define RES4314_XTAL_PU 11 +#define RES4314_WL_PWRSW_PU 12 +#define RES4314_LQ_AVAIL 13 +#define RES4314_LOGIC_RET 14 +#define RES4314_MEM_SLEEP 15 +#define RES4314_MACPHY_RET 16 +#define RES4314_WL_CORE_READY 17 +#define RES4314_ILP_REQ 18 +#define RES4314_ALP_AVAIL 19 +#define RES4314_MISC_PWRSW_PU 20 +#define RES4314_SYNTH_PWRSW_PU 21 +#define RES4314_RX_PWRSW_PU 22 +#define RES4314_RADIO_PU 23 +#define RES4314_VCO_LDO_PU 24 +#define RES4314_AFE_LDO_PU 25 +#define RES4314_RX_LDO_PU 26 +#define RES4314_TX_LDO_PU 27 +#define RES4314_HT_AVAIL 28 +#define RES4314_MACPHY_CLK_AVAIL 29 + +/* 4314 chip-specific ChipStatus register bits */ +#define CST4314_OTP_ENABLED 0x00200000 + +/* 43228 resources */ +#define RES43228_NOT_USED 0 +#define RES43228_ILP_REQUEST 1 +#define RES43228_XTAL_PU 2 +#define RES43228_ALP_AVAIL 3 +#define RES43228_PLL_EN 4 +#define RES43228_HT_PHY_AVAIL 5 + +/* 43228 chipstatus reg bits */ +#define CST43228_ILP_DIV_EN 0x1 +#define CST43228_OTP_PRESENT 0x2 +#define CST43228_SERDES_REFCLK_PADSEL 0x4 +#define CST43228_SDIO_MODE 0x8 +#define CST43228_SDIO_OTP_PRESENT 0x10 +#define CST43228_SDIO_RESET 0x20 + +/* 4706 chipstatus reg bits */ +#define CST4706_PKG_OPTION (1<<0) /* 0: full-featured package 1: low-cost package */ +#define CST4706_SFLASH_PRESENT (1<<1) /* 0: parallel, 1: serial flash is present */ +#define CST4706_SFLASH_TYPE (1<<2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */ +#define CST4706_MIPS_BENDIAN (1<<3) /* 0: little, 1: big endian */ +#define CST4706_PCIE1_DISABLE (1<<5) /* PCIE1 enable strap pin */ + +/* 4706 flashstrconfig reg bits */ +#define FLSTRCF4706_MASK 0x000000ff +#define FLSTRCF4706_SF1 0x00000001 /* 2nd serial flash present */ +#define FLSTRCF4706_PF1 0x00000002 /* 2nd parallel flash present */ +#define FLSTRCF4706_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */ +#define FLSTRCF4706_NF1 0x00000008 /* 2nd NAND flash present */ +#define FLSTRCF4706_1ST_MADDR_SEG_MASK 0x000000f0 /* Valid value mask */ +#define FLSTRCF4706_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */ +#define FLSTRCF4706_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */ + +/* 4360 Chip specific ChipControl register bits */ +#define CCTRL4360_I2C_MODE (1 << 0) +#define CCTRL4360_UART_MODE (1 << 1) +#define CCTRL4360_SECI_MODE (1 << 2) +#define CCTRL4360_BTSWCTRL_MODE (1 << 3) +#define CCTRL4360_DISCRETE_FEMCTRL_MODE (1 << 4) +#define CCTRL4360_DIGITAL_PACTRL_MODE (1 << 5) +#define CCTRL4360_BTSWCTRL_AND_DIGPA_PRESENT (1 << 6) +#define CCTRL4360_EXTRA_GPIO_MODE (1 << 7) +#define CCTRL4360_EXTRA_FEMCTRL_MODE (1 << 8) +#define CCTRL4360_BT_LGCY_MODE (1 << 9) +#define CCTRL4360_CORE2FEMCTRL4_ON (1 << 21) +#define CCTRL4360_SECI_ON_GPIO01 (1 << 24) + +/* 4360 Chip specific Regulator Control register bits */ +#define RCTRL4360_RFLDO_PWR_DOWN (1 << 1) + +/* 4360 PMU resources and chip status bits */ +#define RES4360_REGULATOR 0 +#define RES4360_ILP_AVAIL 1 +#define RES4360_ILP_REQ 2 +#define RES4360_XTAL_LDO_PU 3 +#define RES4360_XTAL_PU 4 +#define RES4360_ALP_AVAIL 5 +#define RES4360_BBPLLPWRSW_PU 6 +#define RES4360_HT_AVAIL 7 +#define RES4360_OTP_PU 8 + +#define CST4360_XTAL_40MZ 0x00000001 +#define CST4360_SFLASH 0x00000002 +#define CST4360_SPROM_PRESENT 0x00000004 +#define CST4360_SFLASH_TYPE 0x00000004 +#define CST4360_OTP_ENABLED 0x00000008 +#define CST4360_REMAP_ROM 0x00000010 +#define CST4360_RSRC_INIT_MODE_MASK 0x00000060 +#define CST4360_RSRC_INIT_MODE_SHIFT 5 +#define CST4360_ILP_DIVEN 0x00000080 +#define CST4360_MODE_USB 0x00000100 +#define CST4360_SPROM_SIZE_MASK 0x00000600 +#define CST4360_SPROM_SIZE_SHIFT 9 +#define CST4360_BBPLL_LOCK 0x00000800 +#define CST4360_AVBBPLL_LOCK 0x00001000 +#define CST4360_USBBBPLL_LOCK 0x00002000 +#define CST4360_RSRC_INIT_MODE(cs) ((cs & CST4360_RSRC_INIT_MODE_MASK) >> \ + CST4360_RSRC_INIT_MODE_SHIFT) + +#define CCTRL_4360_UART_SEL 0x2 + + +/* 43602 PMU resources based on pmu_params.xls version v0.95 */ +#define RES43602_LPLDO_PU 0 +#define RES43602_REGULATOR 1 +#define RES43602_PMU_SLEEP 2 +#define RES43602_RSVD_3 3 +#define RES43602_XTALLDO_PU 4 +#define RES43602_SERDES_PU 5 +#define RES43602_BBPLL_PWRSW_PU 6 +#define RES43602_SR_CLK_START 7 +#define RES43602_SR_PHY_PWRSW 8 +#define RES43602_SR_SUBCORE_PWRSW 9 +#define RES43602_XTAL_PU 10 +#define RES43602_PERST_OVR 11 +#define RES43602_SR_CLK_STABLE 12 +#define RES43602_SR_SAVE_RESTORE 13 +#define RES43602_SR_SLEEP 14 +#define RES43602_LQ_START 15 +#define RES43602_LQ_AVAIL 16 +#define RES43602_WL_CORE_RDY 17 +#define RES43602_ILP_REQ 18 +#define RES43602_ALP_AVAIL 19 +#define RES43602_RADIO_PU 20 +#define RES43602_RFLDO_PU 21 +#define RES43602_HT_START 22 +#define RES43602_HT_AVAIL 23 +#define RES43602_MACPHY_CLKAVAIL 24 +#define RES43602_PARLDO_PU 25 +#define RES43602_RSVD_26 26 + +/* 43602 chip status bits */ +#define CST43602_SPROM_PRESENT (1<<1) +#define CST43602_SPROM_SIZE (1<<10) /* 0 = 16K, 1 = 4K */ +#define CST43602_BBPLL_LOCK (1<<11) +#define CST43602_RF_LDO_OUT_OK (1<<15) /* RF LDO output OK */ + +#define PMU43602_CC2_FORCE_EXT_LPO (1 << 19) /* 1=ext LPO clock is the final LPO clock */ +#define PMU43602_CC2_XTAL32_SEL (1 << 30) /* 0=ext_clock, 1=xtal */ + +#define CC_SR1_43602_SR_ASM_ADDR (0x0) + +/* PLL CTL register values for open loop, used during S/R operation */ +#define PMU43602_PLL_CTL6_VAL 0x68000528 +#define PMU43602_PLL_CTL7_VAL 0x6 + +#define PMU43602_CC3_ARMCR4_DBG_CLK (1 << 29) + + +/* 43430 PMU resources based on pmu_params.xls */ +#define RES43430_LPLDO_PU 0 +#define RES43430_BG_PU 1 +#define RES43430_PMU_SLEEP 2 +#define RES43430_RSVD_3 3 +#define RES43430_CBUCK_LPOM_PU 4 +#define RES43430_CBUCK_PFM_PU 5 +#define RES43430_COLD_START_WAIT 6 +#define RES43430_RSVD_7 7 +#define RES43430_LNLDO_PU 8 +#define RES43430_RSVD_9 9 +#define RES43430_LDO3P3_PU 10 +#define RES43430_OTP_PU 11 +#define RES43430_XTAL_PU 12 +#define RES43430_SR_CLK_START 13 +#define RES43430_LQ_AVAIL 14 +#define RES43430_LQ_START 15 +#define RES43430_RSVD_16 16 +#define RES43430_WL_CORE_RDY 17 +#define RES43430_ILP_REQ 18 +#define RES43430_ALP_AVAIL 19 +#define RES43430_MINI_PMU 20 +#define RES43430_RADIO_PU 21 +#define RES43430_SR_CLK_STABLE 22 +#define RES43430_SR_SAVE_RESTORE 23 +#define RES43430_SR_PHY_PWRSW 24 +#define RES43430_SR_VDDM_PWRSW 25 +#define RES43430_SR_SUBCORE_PWRSW 26 +#define RES43430_SR_SLEEP 27 +#define RES43430_HT_START 28 +#define RES43430_HT_AVAIL 29 +#define RES43430_MACPHY_CLK_AVAIL 30 + +/* 43430 chip status bits */ +#define CST43430_SDIO_MODE 0x00000001 +#define CST43430_GSPI_MODE 0x00000002 +#define CST43430_RSRC_INIT_MODE_0 0x00000080 +#define CST43430_RSRC_INIT_MODE_1 0x00000100 +#define CST43430_SEL0_SDIO 0x00000200 +#define CST43430_SEL1_SDIO 0x00000400 +#define CST43430_SEL2_SDIO 0x00000800 +#define CST43430_BBPLL_LOCKED 0x00001000 +#define CST43430_DBG_INST_DETECT 0x00004000 +#define CST43430_CLB2WL_BT_READY 0x00020000 +#define CST43430_JTAG_MODE 0x00100000 +#define CST43430_HOST_IFACE 0x00400000 +#define CST43430_TRIM_EN 0x00800000 +#define CST43430_DIN_PACKAGE_OPTION 0x10000000 + +/* defines to detect active host interface in use */ +#define CHIP_HOSTIF_PCIEMODE 0x1 +#define CHIP_HOSTIF_USBMODE 0x2 +#define CHIP_HOSTIF_SDIOMODE 0x4 +#define CHIP_HOSTIF_PCIE(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_PCIEMODE) +#define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_USBMODE) +#define CHIP_HOSTIF_SDIO(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_SDIOMODE) + +/* 4335 resources */ +#define RES4335_LPLDO_PO 0 +#define RES4335_PMU_BG_PU 1 +#define RES4335_PMU_SLEEP 2 +#define RES4335_RSVD_3 3 +#define RES4335_CBUCK_LPOM_PU 4 +#define RES4335_CBUCK_PFM_PU 5 +#define RES4335_RSVD_6 6 +#define RES4335_RSVD_7 7 +#define RES4335_LNLDO_PU 8 +#define RES4335_XTALLDO_PU 9 +#define RES4335_LDO3P3_PU 10 +#define RES4335_OTP_PU 11 +#define RES4335_XTAL_PU 12 +#define RES4335_SR_CLK_START 13 +#define RES4335_LQ_AVAIL 14 +#define RES4335_LQ_START 15 +#define RES4335_RSVD_16 16 +#define RES4335_WL_CORE_RDY 17 +#define RES4335_ILP_REQ 18 +#define RES4335_ALP_AVAIL 19 +#define RES4335_MINI_PMU 20 +#define RES4335_RADIO_PU 21 +#define RES4335_SR_CLK_STABLE 22 +#define RES4335_SR_SAVE_RESTORE 23 +#define RES4335_SR_PHY_PWRSW 24 +#define RES4335_SR_VDDM_PWRSW 25 +#define RES4335_SR_SUBCORE_PWRSW 26 +#define RES4335_SR_SLEEP 27 +#define RES4335_HT_START 28 +#define RES4335_HT_AVAIL 29 +#define RES4335_MACPHY_CLKAVAIL 30 + +/* 4335 Chip specific ChipStatus register bits */ +#define CST4335_SPROM_MASK 0x00000020 +#define CST4335_SFLASH_MASK 0x00000040 +#define CST4335_RES_INIT_MODE_SHIFT 7 +#define CST4335_RES_INIT_MODE_MASK 0x00000180 +#define CST4335_CHIPMODE_MASK 0xF +#define CST4335_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ +#define CST4335_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ +#define CST4335_CHIPMODE_USB20D(cs) (((cs) & (1 << 2)) != 0) /* HSIC || USBDA */ +#define CST4335_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ + +/* 4335 Chip specific ChipControl1 register bits */ +#define CCTRL1_4335_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ +#define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ + +#define PATCHTBL_SIZE (0x800) +#define CR4_4335_RAM_BASE (0x180000) +#define CR4_4345_LT_C0_RAM_BASE (0x1b0000) +#define CR4_4345_GE_C0_RAM_BASE (0x198000) +#define CR4_4349_RAM_BASE (0x180000) +#define CR4_4350_RAM_BASE (0x180000) +#define CR4_4360_RAM_BASE (0x0) +#define CR4_43602_RAM_BASE (0x180000) + +/* 4335 chip OTP present & OTP select bits. */ +#define SPROM4335_OTP_SELECT 0x00000010 +#define SPROM4335_OTP_PRESENT 0x00000020 + +/* 4335 GCI specific bits. */ +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 +#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 + +/* SFLASH clkdev specific bits. */ +#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 +#define CC4335_SFLASH_CLKDIV_SHIFT 25 + +/* 4335 OTP bits for SFLASH. */ +#define CC4335_SROM_OTP_SFLASH 40 +#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 +#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 +#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C +#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 + + +/* 4335 chip OTP present & OTP select bits. */ +#define SPROM4335_OTP_SELECT 0x00000010 +#define SPROM4335_OTP_PRESENT 0x00000020 + +/* 4335 GCI specific bits. */ +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 +#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 + +/* SFLASH clkdev specific bits. */ +#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 +#define CC4335_SFLASH_CLKDIV_SHIFT 25 + +/* 4335 OTP bits for SFLASH. */ +#define CC4335_SROM_OTP_SFLASH 40 +#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 +#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 +#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C +#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 + +/* 4335 resources--END */ + +/* 4345 Chip specific ChipStatus register bits */ +#define CST4345_SPROM_MASK 0x00000020 +#define CST4345_SFLASH_MASK 0x00000040 +#define CST4345_RES_INIT_MODE_SHIFT 7 +#define CST4345_RES_INIT_MODE_MASK 0x00000180 +#define CST4345_CHIPMODE_MASK 0x4000F +#define CST4345_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ +#define CST4345_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ +#define CST4345_CHIPMODE_HSIC(cs) (((cs) & (1 << 2)) != 0) /* HSIC */ +#define CST4345_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ +#define CST4345_CHIPMODE_USB20D(cs) (((cs) & (1 << 18)) != 0) /* USBDA */ + +/* 4350 Chipcommon ChipStatus bits */ +#define CST4350_SDIO_MODE 0x00000001 +#define CST4350_HSIC20D_MODE 0x00000002 +#define CST4350_BP_ON_HSIC_CLK 0x00000004 +#define CST4350_PCIE_MODE 0x00000008 +#define CST4350_USB20D_MODE 0x00000010 +#define CST4350_USB30D_MODE 0x00000020 +#define CST4350_SPROM_PRESENT 0x00000040 +#define CST4350_RSRC_INIT_MODE_0 0x00000080 +#define CST4350_RSRC_INIT_MODE_1 0x00000100 +#define CST4350_SEL0_SDIO 0x00000200 +#define CST4350_SEL1_SDIO 0x00000400 +#define CST4350_SDIO_PAD_MODE 0x00000800 +#define CST4350_BBPLL_LOCKED 0x00001000 +#define CST4350_USBPLL_LOCKED 0x00002000 +#define CST4350_LINE_STATE 0x0000C000 +#define CST4350_SERDES_PIPE_PLLLOCK 0x00010000 +#define CST4350_BT_READY 0x00020000 +#define CST4350_SFLASH_PRESENT 0x00040000 +#define CST4350_CPULESS_ENABLE 0x00080000 +#define CST4350_STRAP_HOST_IFC_1 0x00100000 +#define CST4350_STRAP_HOST_IFC_2 0x00200000 +#define CST4350_STRAP_HOST_IFC_3 0x00400000 +#define CST4350_RAW_SPROM_PRESENT 0x00800000 +#define CST4350_APP_CLK_SWITCH_SEL_RDBACK 0x01000000 +#define CST4350_RAW_RSRC_INIT_MODE_0 0x02000000 +#define CST4350_SDIO_PAD_VDDIO 0x04000000 +#define CST4350_GSPI_MODE 0x08000000 +#define CST4350_PACKAGE_OPTION 0xF0000000 +#define CST4350_PACKAGE_SHIFT 28 + +/* package option for 4350 */ +#define CST4350_PACKAGE_WLCSP 0x0 +#define CST4350_PACKAGE_PCIE 0x1 +#define CST4350_PACKAGE_WLBGA 0x2 +#define CST4350_PACKAGE_DBG 0x3 +#define CST4350_PACKAGE_USB 0x4 +#define CST4350_PACKAGE_USB_HSIC 0x4 + +#define CST4350_PKG_MODE(cs) ((cs & CST4350_PACKAGE_OPTION) >> CST4350_PACKAGE_SHIFT) + +#define CST4350_PKG_WLCSP(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLCSP)) +#define CST4350_PKG_PCIE(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_PCIE)) +#define CST4350_PKG_WLBGA(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLBGA)) +#define CST4350_PKG_USB(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB)) +#define CST4350_PKG_USB_HSIC(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB_HSIC)) + +/* 4350C0 USB PACKAGE using raw_sprom_present to indicate 40mHz xtal */ +#define CST4350_PKG_USB_40M(cs) (cs & CST4350_RAW_SPROM_PRESENT) + +#define CST4350_CHIPMODE_SDIOD(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_SDIOD)) +#define CST4350_CHIPMODE_USB20D(cs) ((CST4350_IFC_MODE(cs)) == (CST4350_IFC_MODE_USB20D)) +#define CST4350_CHIPMODE_HSIC20D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC20D)) +#define CST4350_CHIPMODE_HSIC30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC30D)) +#define CST4350_CHIPMODE_USB30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D)) +#define CST4350_CHIPMODE_USB30D_WL(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D_WL)) +#define CST4350_CHIPMODE_PCIE(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_PCIE)) + +/* strap_host_ifc strap value */ +#define CST4350_HOST_IFC_MASK 0x00700000 +#define CST4350_HOST_IFC_SHIFT 20 + +/* host_ifc raw mode */ +#define CST4350_IFC_MODE_SDIOD 0x0 +#define CST4350_IFC_MODE_HSIC20D 0x1 +#define CST4350_IFC_MODE_HSIC30D 0x2 +#define CST4350_IFC_MODE_PCIE 0x3 +#define CST4350_IFC_MODE_USB20D 0x4 +#define CST4350_IFC_MODE_USB30D 0x5 +#define CST4350_IFC_MODE_USB30D_WL 0x6 +#define CST4350_IFC_MODE_USB30D_BT 0x7 + +#define CST4350_IFC_MODE(cs) ((cs & CST4350_HOST_IFC_MASK) >> CST4350_HOST_IFC_SHIFT) + +#define CST4350_CHIPMODE_SDIOD(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_SDIOD)) +#define CST4350_CHIPMODE_USB20D(cs) ((CST4350_IFC_MODE(cs)) == (CST4350_IFC_MODE_USB20D)) +#define CST4350_CHIPMODE_HSIC20D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC20D)) +#define CST4350_CHIPMODE_HSIC30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC30D)) +#define CST4350_CHIPMODE_USB30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D)) +#define CST4350_CHIPMODE_USB30D_WL(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D_WL)) +#define CST4350_CHIPMODE_PCIE(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_PCIE)) + +/* 4350 PMU resources */ +#define RES4350_LPLDO_PU 0 +#define RES4350_PMU_BG_PU 1 +#define RES4350_PMU_SLEEP 2 +#define RES4350_RSVD_3 3 +#define RES4350_CBUCK_LPOM_PU 4 +#define RES4350_CBUCK_PFM_PU 5 +#define RES4350_COLD_START_WAIT 6 +#define RES4350_RSVD_7 7 +#define RES4350_LNLDO_PU 8 +#define RES4350_XTALLDO_PU 9 +#define RES4350_LDO3P3_PU 10 +#define RES4350_OTP_PU 11 +#define RES4350_XTAL_PU 12 +#define RES4350_SR_CLK_START 13 +#define RES4350_LQ_AVAIL 14 +#define RES4350_LQ_START 15 +#define RES4350_RSVD_16 16 +#define RES4350_WL_CORE_RDY 17 +#define RES4350_ILP_REQ 18 +#define RES4350_ALP_AVAIL 19 +#define RES4350_MINI_PMU 20 +#define RES4350_RADIO_PU 21 +#define RES4350_SR_CLK_STABLE 22 +#define RES4350_SR_SAVE_RESTORE 23 +#define RES4350_SR_PHY_PWRSW 24 +#define RES4350_SR_VDDM_PWRSW 25 +#define RES4350_SR_SUBCORE_PWRSW 26 +#define RES4350_SR_SLEEP 27 +#define RES4350_HT_START 28 +#define RES4350_HT_AVAIL 29 +#define RES4350_MACPHY_CLKAVAIL 30 + +#define MUXENAB4350_UART_MASK (0x0000000f) +#define MUXENAB4350_UART_SHIFT 0 +#define MUXENAB4350_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ +#define MUXENAB4350_HOSTWAKE_SHIFT 4 + + +/* 4350 GCI function sel values */ +#define CC4350_FNSEL_HWDEF (0) +#define CC4350_FNSEL_SAMEASPIN (1) +#define CC4350_FNSEL_UART (2) +#define CC4350_FNSEL_SFLASH (3) +#define CC4350_FNSEL_SPROM (4) +#define CC4350_FNSEL_I2C (5) +#define CC4350_FNSEL_MISC0 (6) +#define CC4350_FNSEL_GCI (7) +#define CC4350_FNSEL_MISC1 (8) +#define CC4350_FNSEL_MISC2 (9) +#define CC4350_FNSEL_PWDOG (10) +#define CC4350_FNSEL_IND (12) +#define CC4350_FNSEL_PDN (13) +#define CC4350_FNSEL_PUP (14) +#define CC4350_FNSEL_TRISTATE (15) +#define CC4350C_FNSEL_UART (3) + + +/* 4350 GPIO */ +#define CC4350_PIN_GPIO_00 (0) +#define CC4350_PIN_GPIO_01 (1) +#define CC4350_PIN_GPIO_02 (2) +#define CC4350_PIN_GPIO_03 (3) +#define CC4350_PIN_GPIO_04 (4) +#define CC4350_PIN_GPIO_05 (5) +#define CC4350_PIN_GPIO_06 (6) +#define CC4350_PIN_GPIO_07 (7) +#define CC4350_PIN_GPIO_08 (8) +#define CC4350_PIN_GPIO_09 (9) +#define CC4350_PIN_GPIO_10 (10) +#define CC4350_PIN_GPIO_11 (11) +#define CC4350_PIN_GPIO_12 (12) +#define CC4350_PIN_GPIO_13 (13) +#define CC4350_PIN_GPIO_14 (14) +#define CC4350_PIN_GPIO_15 (15) + +#define CC2_4350_PHY_PWRSW_UPTIME_MASK (0xf << 0) +#define CC2_4350_PHY_PWRSW_UPTIME_SHIFT (0) +#define CC2_4350_VDDM_PWRSW_UPDELAY_MASK (0xf << 4) +#define CC2_4350_VDDM_PWRSW_UPDELAY_SHIFT (4) +#define CC2_4350_VDDM_PWRSW_UPTIME_MASK (0xf << 8) +#define CC2_4350_VDDM_PWRSW_UPTIME_SHIFT (8) +#define CC2_4350_SBC_PWRSW_DNDELAY_MASK (0x3 << 12) +#define CC2_4350_SBC_PWRSW_DNDELAY_SHIFT (12) +#define CC2_4350_PHY_PWRSW_DNDELAY_MASK (0x3 << 14) +#define CC2_4350_PHY_PWRSW_DNDELAY_SHIFT (14) +#define CC2_4350_VDDM_PWRSW_DNDELAY_MASK (0x3 << 16) +#define CC2_4350_VDDM_PWRSW_DNDELAY_SHIFT (16) +#define CC2_4350_VDDM_PWRSW_EN_MASK (1 << 20) +#define CC2_4350_VDDM_PWRSW_EN_SHIFT (20) +#define CC2_4350_MEMLPLDO_PWRSW_EN_MASK (1 << 21) +#define CC2_4350_MEMLPLDO_PWRSW_EN_SHIFT (21) +#define CC2_4350_SDIO_AOS_WAKEUP_MASK (1 << 24) +#define CC2_4350_SDIO_AOS_WAKEUP_SHIFT (24) + +/* Applies to 4335/4350/4345 */ +#define CC3_SR_CLK_SR_MEM_MASK (1 << 0) +#define CC3_SR_CLK_SR_MEM_SHIFT (0) +#define CC3_SR_BIT1_TBD_MASK (1 << 1) +#define CC3_SR_BIT1_TBD_SHIFT (1) +#define CC3_SR_ENGINE_ENABLE_MASK (1 << 2) +#define CC3_SR_ENGINE_ENABLE_SHIFT (2) +#define CC3_SR_BIT3_TBD_MASK (1 << 3) +#define CC3_SR_BIT3_TBD_SHIFT (3) +#define CC3_SR_MINDIV_FAST_CLK_MASK (0xF << 4) +#define CC3_SR_MINDIV_FAST_CLK_SHIFT (4) +#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_MASK (1 << 8) +#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_SHIFT (8) +#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_MASK (1 << 9) +#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_SHIFT (9) +#define CC3_SR_R23_SR_RISE_EDGE_TRIG_MASK (1 << 10) +#define CC3_SR_R23_SR_RISE_EDGE_TRIG_SHIFT (10) +#define CC3_SR_R23_SR_FALL_EDGE_TRIG_MASK (1 << 11) +#define CC3_SR_R23_SR_FALL_EDGE_TRIG_SHIFT (11) +#define CC3_SR_NUM_CLK_HIGH_MASK (0x7 << 12) +#define CC3_SR_NUM_CLK_HIGH_SHIFT (12) +#define CC3_SR_BIT15_TBD_MASK (1 << 15) +#define CC3_SR_BIT15_TBD_SHIFT (15) +#define CC3_SR_PHY_FUNC_PIC_MASK (1 << 16) +#define CC3_SR_PHY_FUNC_PIC_SHIFT (16) +#define CC3_SR_BIT17_19_TBD_MASK (0x7 << 17) +#define CC3_SR_BIT17_19_TBD_SHIFT (17) +#define CC3_SR_CHIP_TRIGGER_1_MASK (1 << 20) +#define CC3_SR_CHIP_TRIGGER_1_SHIFT (20) +#define CC3_SR_CHIP_TRIGGER_2_MASK (1 << 21) +#define CC3_SR_CHIP_TRIGGER_2_SHIFT (21) +#define CC3_SR_CHIP_TRIGGER_3_MASK (1 << 22) +#define CC3_SR_CHIP_TRIGGER_3_SHIFT (22) +#define CC3_SR_CHIP_TRIGGER_4_MASK (1 << 23) +#define CC3_SR_CHIP_TRIGGER_4_SHIFT (23) +#define CC3_SR_ALLOW_SBC_FUNC_PIC_MASK (1 << 24) +#define CC3_SR_ALLOW_SBC_FUNC_PIC_SHIFT (24) +#define CC3_SR_BIT25_26_TBD_MASK (0x3 << 25) +#define CC3_SR_BIT25_26_TBD_SHIFT (25) +#define CC3_SR_ALLOW_SBC_STBY_MASK (1 << 27) +#define CC3_SR_ALLOW_SBC_STBY_SHIFT (27) +#define CC3_SR_GPIO_MUX_MASK (0xF << 28) +#define CC3_SR_GPIO_MUX_SHIFT (28) + +/* Applies to 4335/4350/4345 */ +#define CC4_SR_INIT_ADDR_MASK (0x3FF0000) +#define CC4_4350_SR_ASM_ADDR (0x30) +#define CC4_4335_SR_ASM_ADDR (0x48) +#define CC4_4345_SR_ASM_ADDR (0x48) +#define CC4_SR_INIT_ADDR_SHIFT (16) + +#define CC4_4350_EN_SR_CLK_ALP_MASK (1 << 30) +#define CC4_4350_EN_SR_CLK_ALP_SHIFT (30) +#define CC4_4350_EN_SR_CLK_HT_MASK (1 << 31) +#define CC4_4350_EN_SR_CLK_HT_SHIFT (31) + +#define VREG4_4350_MEMLPDO_PU_MASK (1 << 31) +#define VREG4_4350_MEMLPDO_PU_SHIFT 31 + +#define CC6_4350_PCIE_CLKREQ_WAKEUP_MASK (1 << 4) +#define CC6_4350_PCIE_CLKREQ_WAKEUP_SHIFT (4) +#define CC6_4350_PMU_WAKEUP_ALPAVAIL_MASK (1 << 6) +#define CC6_4350_PMU_WAKEUP_ALPAVAIL_SHIFT (6) + +/* GCI chipcontrol register indices */ +#define CC_GCI_CHIPCTRL_00 (0) +#define CC_GCI_CHIPCTRL_01 (1) +#define CC_GCI_CHIPCTRL_02 (2) +#define CC_GCI_CHIPCTRL_03 (3) +#define CC_GCI_CHIPCTRL_04 (4) +#define CC_GCI_CHIPCTRL_05 (5) +#define CC_GCI_CHIPCTRL_06 (6) +#define CC_GCI_CHIPCTRL_07 (7) +#define CC_GCI_CHIPCTRL_08 (8) +#define CC_GCI_XTAL_BUFSTRG_NFC (0xff << 12) + +#define CC_GCI_06_JTAG_SEL_SHIFT 4 +#define CC_GCI_06_JTAG_SEL_MASK (1 << 4) + +#define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) + +/* 4345 PMU resources */ +#define RES4345_LPLDO_PU 0 +#define RES4345_PMU_BG_PU 1 +#define RES4345_PMU_SLEEP 2 +#define RES4345_HSICLDO_PU 3 +#define RES4345_CBUCK_LPOM_PU 4 +#define RES4345_CBUCK_PFM_PU 5 +#define RES4345_COLD_START_WAIT 6 +#define RES4345_RSVD_7 7 +#define RES4345_LNLDO_PU 8 +#define RES4345_XTALLDO_PU 9 +#define RES4345_LDO3P3_PU 10 +#define RES4345_OTP_PU 11 +#define RES4345_XTAL_PU 12 +#define RES4345_SR_CLK_START 13 +#define RES4345_LQ_AVAIL 14 +#define RES4345_LQ_START 15 +#define RES4345_PERST_OVR 16 +#define RES4345_WL_CORE_RDY 17 +#define RES4345_ILP_REQ 18 +#define RES4345_ALP_AVAIL 19 +#define RES4345_MINI_PMU 20 +#define RES4345_RADIO_PU 21 +#define RES4345_SR_CLK_STABLE 22 +#define RES4345_SR_SAVE_RESTORE 23 +#define RES4345_SR_PHY_PWRSW 24 +#define RES4345_SR_VDDM_PWRSW 25 +#define RES4345_SR_SUBCORE_PWRSW 26 +#define RES4345_SR_SLEEP 27 +#define RES4345_HT_START 28 +#define RES4345_HT_AVAIL 29 +#define RES4345_MACPHY_CLK_AVAIL 30 + +/* 4335 pins +* note: only the values set as default/used are added here. +*/ +#define CC4335_PIN_GPIO_00 (0) +#define CC4335_PIN_GPIO_01 (1) +#define CC4335_PIN_GPIO_02 (2) +#define CC4335_PIN_GPIO_03 (3) +#define CC4335_PIN_GPIO_04 (4) +#define CC4335_PIN_GPIO_05 (5) +#define CC4335_PIN_GPIO_06 (6) +#define CC4335_PIN_GPIO_07 (7) +#define CC4335_PIN_GPIO_08 (8) +#define CC4335_PIN_GPIO_09 (9) +#define CC4335_PIN_GPIO_10 (10) +#define CC4335_PIN_GPIO_11 (11) +#define CC4335_PIN_GPIO_12 (12) +#define CC4335_PIN_GPIO_13 (13) +#define CC4335_PIN_GPIO_14 (14) +#define CC4335_PIN_GPIO_15 (15) +#define CC4335_PIN_SDIO_CLK (16) +#define CC4335_PIN_SDIO_CMD (17) +#define CC4335_PIN_SDIO_DATA0 (18) +#define CC4335_PIN_SDIO_DATA1 (19) +#define CC4335_PIN_SDIO_DATA2 (20) +#define CC4335_PIN_SDIO_DATA3 (21) +#define CC4335_PIN_RF_SW_CTRL_6 (22) +#define CC4335_PIN_RF_SW_CTRL_7 (23) +#define CC4335_PIN_RF_SW_CTRL_8 (24) +#define CC4335_PIN_RF_SW_CTRL_9 (25) + +/* 4335 GCI function sel values +*/ +#define CC4335_FNSEL_HWDEF (0) +#define CC4335_FNSEL_SAMEASPIN (1) +#define CC4335_FNSEL_GPIO0 (2) +#define CC4335_FNSEL_GPIO1 (3) +#define CC4335_FNSEL_GCI0 (4) +#define CC4335_FNSEL_GCI1 (5) +#define CC4335_FNSEL_UART (6) +#define CC4335_FNSEL_SFLASH (7) +#define CC4335_FNSEL_SPROM (8) +#define CC4335_FNSEL_MISC0 (9) +#define CC4335_FNSEL_MISC1 (10) +#define CC4335_FNSEL_MISC2 (11) +#define CC4335_FNSEL_IND (12) +#define CC4335_FNSEL_PDN (13) +#define CC4335_FNSEL_PUP (14) +#define CC4335_FNSEL_TRI (15) + +/* 4345 pins +* note: only the values set as default/used are added here. +*/ +#define CC4345_PIN_GPIO_00 (0) +#define CC4345_PIN_GPIO_01 (1) +#define CC4345_PIN_GPIO_02 (2) +#define CC4345_PIN_GPIO_03 (3) +#define CC4345_PIN_GPIO_04 (4) +#define CC4345_PIN_GPIO_05 (5) +#define CC4345_PIN_GPIO_06 (6) +#define CC4345_PIN_GPIO_07 (7) +#define CC4345_PIN_GPIO_08 (8) +#define CC4345_PIN_GPIO_09 (9) +#define CC4345_PIN_GPIO_10 (10) +#define CC4345_PIN_GPIO_11 (11) +#define CC4345_PIN_GPIO_12 (12) +#define CC4345_PIN_GPIO_13 (13) +#define CC4345_PIN_GPIO_14 (14) +#define CC4345_PIN_GPIO_15 (15) +#define CC4345_PIN_GPIO_16 (16) +#define CC4345_PIN_SDIO_CLK (17) +#define CC4345_PIN_SDIO_CMD (18) +#define CC4345_PIN_SDIO_DATA0 (19) +#define CC4345_PIN_SDIO_DATA1 (20) +#define CC4345_PIN_SDIO_DATA2 (21) +#define CC4345_PIN_SDIO_DATA3 (22) +#define CC4345_PIN_RF_SW_CTRL_0 (23) +#define CC4345_PIN_RF_SW_CTRL_1 (24) +#define CC4345_PIN_RF_SW_CTRL_2 (25) +#define CC4345_PIN_RF_SW_CTRL_3 (26) +#define CC4345_PIN_RF_SW_CTRL_4 (27) +#define CC4345_PIN_RF_SW_CTRL_5 (28) +#define CC4345_PIN_RF_SW_CTRL_6 (29) +#define CC4345_PIN_RF_SW_CTRL_7 (30) +#define CC4345_PIN_RF_SW_CTRL_8 (31) +#define CC4345_PIN_RF_SW_CTRL_9 (32) + +/* 4345 GCI function sel values +*/ +#define CC4345_FNSEL_HWDEF (0) +#define CC4345_FNSEL_SAMEASPIN (1) +#define CC4345_FNSEL_GPIO0 (2) +#define CC4345_FNSEL_GPIO1 (3) +#define CC4345_FNSEL_GCI0 (4) +#define CC4345_FNSEL_GCI1 (5) +#define CC4345_FNSEL_UART (6) +#define CC4345_FNSEL_SFLASH (7) +#define CC4345_FNSEL_SPROM (8) +#define CC4345_FNSEL_MISC0 (9) +#define CC4345_FNSEL_MISC1 (10) +#define CC4345_FNSEL_MISC2 (11) +#define CC4345_FNSEL_IND (12) +#define CC4345_FNSEL_PDN (13) +#define CC4345_FNSEL_PUP (14) +#define CC4345_FNSEL_TRI (15) + +#define MUXENAB4345_UART_MASK (0x0000000f) +#define MUXENAB4345_UART_SHIFT 0 +#define MUXENAB4345_HOSTWAKE_MASK (0x000000f0) +#define MUXENAB4345_HOSTWAKE_SHIFT 4 + +/* GCI GPIO for function sel GCI-0/GCI-1 */ +#define CC_GCI_GPIO_0 (0) +#define CC_GCI_GPIO_1 (1) +#define CC_GCI_GPIO_2 (2) +#define CC_GCI_GPIO_3 (3) +#define CC_GCI_GPIO_4 (4) +#define CC_GCI_GPIO_5 (5) +#define CC_GCI_GPIO_6 (6) +#define CC_GCI_GPIO_7 (7) + +/* indicates Invalid GPIO, e.g. when PAD GPIO doesn't map to GCI GPIO */ +#define CC_GCI_GPIO_INVALID 0xFF + +/* find the 4 bit mask given the bit position */ +#define GCIMASK(pos) (((uint32)0xF) << pos) +/* get the value which can be used to directly OR with chipcontrol reg */ +#define GCIPOSVAL(val, pos) ((((uint32)val) << pos) & GCIMASK(pos)) +/* Extract nibble from a given position */ +#define GCIGETNBL(val, pos) ((val >> pos) & 0xF) + + +/* find the 8 bit mask given the bit position */ +#define GCIMASK_8B(pos) (((uint32)0xFF) << pos) +/* get the value which can be used to directly OR with chipcontrol reg */ +#define GCIPOSVAL_8B(val, pos) ((((uint32)val) << pos) & GCIMASK_8B(pos)) +/* Extract nibble from a given position */ +#define GCIGETNBL_8B(val, pos) ((val >> pos) & 0xFF) + +/* find the 4 bit mask given the bit position */ +#define GCIMASK_4B(pos) (((uint32)0xF) << pos) +/* get the value which can be used to directly OR with chipcontrol reg */ +#define GCIPOSVAL_4B(val, pos) ((((uint32)val) << pos) & GCIMASK_4B(pos)) +/* Extract nibble from a given position */ +#define GCIGETNBL_4B(val, pos) ((val >> pos) & 0xF) + + +#define GCI_INTSTATUS_GPIOINT (1 << 25) +#define GCI_INTSTATUS_GPIOWAKE (1 << 26) +#define GCI_INTMASK_GPIOINT (1 << 25) +#define GCI_INTMASK_GPIOWAKE (1 << 26) +#define GCI_WAKEMASK_GPIOINT (1 << 25) +#define GCI_WAKEMASK_GPIOWAKE (1 << 26) + + +/* 4335 MUX options. each nibble belongs to a setting. Non-zero value specifies a logic +* for now only UART for bootloader. +*/ +#define MUXENAB4335_UART_MASK (0x0000000f) + +#define MUXENAB4335_UART_SHIFT 0 +#define MUXENAB4335_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ +#define MUXENAB4335_HOSTWAKE_SHIFT 4 +#define MUXENAB4335_GETIX(val, name) \ + ((((val) & MUXENAB4335_ ## name ## _MASK) >> MUXENAB4335_ ## name ## _SHIFT) - 1) + +/* +* Maximum delay for the PMU state transition in us. +* This is an upper bound intended for spinwaits etc. +*/ +#define PMU_MAX_TRANSITION_DLY 15000 + +/* PMU resource up transition time in ILP cycles */ +#define PMURES_UP_TRANSITION 2 + + +/* SECI configuration */ +#define SECI_MODE_UART 0x0 +#define SECI_MODE_SECI 0x1 +#define SECI_MODE_LEGACY_3WIRE_BT 0x2 +#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3 +#define SECI_MODE_HALF_SECI 0x4 + +#define SECI_RESET (1 << 0) +#define SECI_RESET_BAR_UART (1 << 1) +#define SECI_ENAB_SECI_ECI (1 << 2) +#define SECI_ENAB_SECIOUT_DIS (1 << 3) +#define SECI_MODE_MASK 0x7 +#define SECI_MODE_SHIFT 4 /* (bits 5, 6, 7) */ +#define SECI_UPD_SECI (1 << 7) + +#define SECI_SIGNOFF_0 0xDB +#define SECI_SIGNOFF_1 0 + +/* seci clk_ctl_st bits */ +#define CLKCTL_STS_SECI_CLK_REQ (1 << 8) +#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24) + +#define SECI_UART_MSR_CTS_STATE (1 << 0) +#define SECI_UART_MSR_RTS_STATE (1 << 1) +#define SECI_UART_SECI_IN_STATE (1 << 2) +#define SECI_UART_SECI_IN2_STATE (1 << 3) + +/* SECI UART LCR/MCR register bits */ +#define SECI_UART_LCR_STOP_BITS (1 << 0) /* 0 - 1bit, 1 - 2bits */ +#define SECI_UART_LCR_PARITY_EN (1 << 1) +#define SECI_UART_LCR_PARITY (1 << 2) /* 0 - odd, 1 - even */ +#define SECI_UART_LCR_RX_EN (1 << 3) +#define SECI_UART_LCR_LBRK_CTRL (1 << 4) /* 1 => SECI_OUT held low */ +#define SECI_UART_LCR_TXO_EN (1 << 5) +#define SECI_UART_LCR_RTSO_EN (1 << 6) +#define SECI_UART_LCR_SLIPMODE_EN (1 << 7) +#define SECI_UART_LCR_RXCRC_CHK (1 << 8) +#define SECI_UART_LCR_TXCRC_INV (1 << 9) +#define SECI_UART_LCR_TXCRC_LSBF (1 << 10) +#define SECI_UART_LCR_TXCRC_EN (1 << 11) + +#define SECI_UART_MCR_TX_EN (1 << 0) +#define SECI_UART_MCR_PRTS (1 << 1) +#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2) +#define SECI_UART_MCR_HIGHRATE_EN (1 << 3) +#define SECI_UART_MCR_LOOPBK_EN (1 << 4) +#define SECI_UART_MCR_AUTO_RTS (1 << 5) +#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6) +#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7) +#define SECI_UART_MCR_XONOFF_RPT (1 << 9) + +/* WLAN channel numbers - used from wifi.h */ + +/* WLAN BW */ +#define ECI_BW_20 0x0 +#define ECI_BW_25 0x1 +#define ECI_BW_30 0x2 +#define ECI_BW_35 0x3 +#define ECI_BW_40 0x4 +#define ECI_BW_45 0x5 +#define ECI_BW_50 0x6 +#define ECI_BW_ALL 0x7 + +/* WLAN - number of antenna */ +#define WLAN_NUM_ANT1 TXANT_0 +#define WLAN_NUM_ANT2 TXANT_1 + +/* otpctrl1 0xF4 */ +#define OTPC_FORCE_PWR_OFF 0x02000000 +/* chipcommon s/r registers introduced with cc rev >= 48 */ +#define CC_SR_CTL0_ENABLE_MASK 0x1 +#define CC_SR_CTL0_ENABLE_SHIFT 0 +#define CC_SR_CTL0_EN_SR_ENG_CLK_SHIFT 1 /* sr_clk to sr_memory enable */ +#define CC_SR_CTL0_RSRC_TRIGGER_SHIFT 2 /* Rising edge resource trigger 0 to sr_engine */ +#define CC_SR_CTL0_MIN_DIV_SHIFT 6 /* Min division value for fast clk in sr_engine */ +#define CC_SR_CTL0_EN_SBC_STBY_SHIFT 16 /* Allow Subcore mem StandBy? */ +#define CC_SR_CTL0_EN_SR_ALP_CLK_MASK_SHIFT 18 +#define CC_SR_CTL0_EN_SR_HT_CLK_SHIFT 19 +#define CC_SR_CTL0_ALLOW_PIC_SHIFT 20 /* Allow pic to separate power domains */ +#define CC_SR_CTL0_MAX_SR_LQ_CLK_CNT_SHIFT 25 +#define CC_SR_CTL0_EN_MEM_DISABLE_FOR_SLEEP 30 + +#define ECI_INLO_PKTDUR_MASK 0x000000f0 /* [7:4] - 4 bits */ +#define ECI_INLO_PKTDUR_SHIFT 4 + +/* gci chip control bits */ +#define GCI_GPIO_CHIPCTRL_ENAB_IN_BIT 0 +#define GCI_GPIO_CHIPCTRL_ENAB_OP_BIT 1 +#define GCI_GPIO_CHIPCTRL_INVERT_BIT 2 +#define GCI_GPIO_CHIPCTRL_PULLUP_BIT 3 +#define GCI_GPIO_CHIPCTRL_PULLDN_BIT 4 +#define GCI_GPIO_CHIPCTRL_ENAB_BTSIG_BIT 5 +#define GCI_GPIO_CHIPCTRL_ENAB_OD_OP_BIT 6 +#define GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT 7 + +/* gci GPIO input status bits */ +#define GCI_GPIO_STS_VALUE_BIT 0 +#define GCI_GPIO_STS_POS_EDGE_BIT 1 +#define GCI_GPIO_STS_NEG_EDGE_BIT 2 +#define GCI_GPIO_STS_FAST_EDGE_BIT 3 +#define GCI_GPIO_STS_CLEAR 0xF + +#define GCI_GPIO_STS_VALUE (1 << GCI_GPIO_STS_VALUE_BIT) + +#endif /* _SBCHIPC_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h new file mode 100644 index 000000000000..8de9b0942577 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h @@ -0,0 +1,282 @@ +/* + * Broadcom SiliconBackplane hardware register definitions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbconfig.h 241182 2011-02-17 21:50:03Z $ + */ + +#ifndef _SBCONFIG_H +#define _SBCONFIG_H + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif + +/* enumeration in SB is based on the premise that cores are contiguos in the + * enumeration space. + */ +#define SB_BUS_SIZE 0x10000 /* Each bus gets 64Kbytes for cores */ +#define SB_BUS_BASE(b) (SI_ENUM_BASE + (b) * SB_BUS_SIZE) +#define SB_BUS_MAXCORES (SB_BUS_SIZE / SI_CORE_SIZE) /* Max cores per bus */ + +/* + * Sonics Configuration Space Registers. + */ +#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */ +#define SBCONFIGSIZE 256 /* sizeof (sbconfig_t) */ + +#define SBIPSFLAG 0x08 +#define SBTPSFLAG 0x18 +#define SBTMERRLOGA 0x48 /* sonics >= 2.3 */ +#define SBTMERRLOG 0x50 /* sonics >= 2.3 */ +#define SBADMATCH3 0x60 +#define SBADMATCH2 0x68 +#define SBADMATCH1 0x70 +#define SBIMSTATE 0x90 +#define SBINTVEC 0x94 +#define SBTMSTATELOW 0x98 +#define SBTMSTATEHIGH 0x9c +#define SBBWA0 0xa0 +#define SBIMCONFIGLOW 0xa8 +#define SBIMCONFIGHIGH 0xac +#define SBADMATCH0 0xb0 +#define SBTMCONFIGLOW 0xb8 +#define SBTMCONFIGHIGH 0xbc +#define SBBCONFIG 0xc0 +#define SBBSTATE 0xc8 +#define SBACTCNFG 0xd8 +#define SBFLAGST 0xe8 +#define SBIDLOW 0xf8 +#define SBIDHIGH 0xfc + +/* All the previous registers are above SBCONFIGOFF, but with Sonics 2.3, we have + * a few registers *below* that line. I think it would be very confusing to try + * and change the value of SBCONFIGOFF, so I'm definig them as absolute offsets here, + */ + +#define SBIMERRLOGA 0xea8 +#define SBIMERRLOG 0xeb0 +#define SBTMPORTCONNID0 0xed8 +#define SBTMPORTLOCK0 0xef8 + +#ifndef _LANGUAGE_ASSEMBLY + +typedef volatile struct _sbconfig { + uint32 PAD[2]; + uint32 sbipsflag; /* initiator port ocp slave flag */ + uint32 PAD[3]; + uint32 sbtpsflag; /* target port ocp slave flag */ + uint32 PAD[11]; + uint32 sbtmerrloga; /* (sonics >= 2.3) */ + uint32 PAD; + uint32 sbtmerrlog; /* (sonics >= 2.3) */ + uint32 PAD[3]; + uint32 sbadmatch3; /* address match3 */ + uint32 PAD; + uint32 sbadmatch2; /* address match2 */ + uint32 PAD; + uint32 sbadmatch1; /* address match1 */ + uint32 PAD[7]; + uint32 sbimstate; /* initiator agent state */ + uint32 sbintvec; /* interrupt mask */ + uint32 sbtmstatelow; /* target state */ + uint32 sbtmstatehigh; /* target state */ + uint32 sbbwa0; /* bandwidth allocation table0 */ + uint32 PAD; + uint32 sbimconfiglow; /* initiator configuration */ + uint32 sbimconfighigh; /* initiator configuration */ + uint32 sbadmatch0; /* address match0 */ + uint32 PAD; + uint32 sbtmconfiglow; /* target configuration */ + uint32 sbtmconfighigh; /* target configuration */ + uint32 sbbconfig; /* broadcast configuration */ + uint32 PAD; + uint32 sbbstate; /* broadcast state */ + uint32 PAD[3]; + uint32 sbactcnfg; /* activate configuration */ + uint32 PAD[3]; + uint32 sbflagst; /* current sbflags */ + uint32 PAD[3]; + uint32 sbidlow; /* identification */ + uint32 sbidhigh; /* identification */ +} sbconfig_t; + +#endif /* _LANGUAGE_ASSEMBLY */ + +/* sbipsflag */ +#define SBIPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */ +#define SBIPS_INT1_SHIFT 0 +#define SBIPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */ +#define SBIPS_INT2_SHIFT 8 +#define SBIPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */ +#define SBIPS_INT3_SHIFT 16 +#define SBIPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */ +#define SBIPS_INT4_SHIFT 24 + +/* sbtpsflag */ +#define SBTPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */ +#define SBTPS_F0EN0 0x40 /* interrupt is always sent on the backplane */ + +/* sbtmerrlog */ +#define SBTMEL_CM 0x00000007 /* command */ +#define SBTMEL_CI 0x0000ff00 /* connection id */ +#define SBTMEL_EC 0x0f000000 /* error code */ +#define SBTMEL_ME 0x80000000 /* multiple error */ + +/* sbimstate */ +#define SBIM_PC 0xf /* pipecount */ +#define SBIM_AP_MASK 0x30 /* arbitration policy */ +#define SBIM_AP_BOTH 0x00 /* use both timeslaces and token */ +#define SBIM_AP_TS 0x10 /* use timesliaces only */ +#define SBIM_AP_TK 0x20 /* use token only */ +#define SBIM_AP_RSV 0x30 /* reserved */ +#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 */ +#define SBTML_RESET 0x0001 /* reset */ +#define SBTML_REJ_MASK 0x0006 /* reject field */ +#define SBTML_REJ 0x0002 /* reject */ +#define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */ + +#define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */ + +/* sbtmstatehigh */ +#define SBTMH_SERR 0x0001 /* serror */ +#define SBTMH_INT 0x0002 /* interrupt */ +#define SBTMH_BUSY 0x0004 /* busy */ +#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ + +#define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */ + +/* sbbwa0 */ +#define SBBWA_TAB0_MASK 0xffff /* lookup table 0 */ +#define SBBWA_TAB1_MASK 0xffff /* lookup table 1 */ +#define SBBWA_TAB1_SHIFT 16 + +/* sbimconfiglow */ +#define SBIMCL_STO_MASK 0x7 /* service timeout */ +#define SBIMCL_RTO_MASK 0x70 /* request timeout */ +#define SBIMCL_RTO_SHIFT 4 +#define SBIMCL_CID_MASK 0xff0000 /* connection id */ +#define SBIMCL_CID_SHIFT 16 + +/* sbimconfighigh */ +#define SBIMCH_IEM_MASK 0xc /* inband error mode */ +#define SBIMCH_TEM_MASK 0x30 /* timeout error mode */ +#define SBIMCH_TEM_SHIFT 4 +#define SBIMCH_BEM_MASK 0xc0 /* bus error mode */ +#define SBIMCH_BEM_SHIFT 6 + +/* sbadmatch0 */ +#define SBAM_TYPE_MASK 0x3 /* address type */ +#define SBAM_AD64 0x4 /* reserved */ +#define SBAM_ADINT0_MASK 0xf8 /* type0 size */ +#define SBAM_ADINT0_SHIFT 3 +#define SBAM_ADINT1_MASK 0x1f8 /* type1 size */ +#define SBAM_ADINT1_SHIFT 3 +#define SBAM_ADINT2_MASK 0x1f8 /* type2 size */ +#define SBAM_ADINT2_SHIFT 3 +#define SBAM_ADEN 0x400 /* enable */ +#define SBAM_ADNEG 0x800 /* negative decode */ +#define SBAM_BASE0_MASK 0xffffff00 /* type0 base address */ +#define SBAM_BASE0_SHIFT 8 +#define SBAM_BASE1_MASK 0xfffff000 /* type1 base address for the core */ +#define SBAM_BASE1_SHIFT 12 +#define SBAM_BASE2_MASK 0xffff0000 /* type2 base address for the core */ +#define SBAM_BASE2_SHIFT 16 + +/* sbtmconfiglow */ +#define SBTMCL_CD_MASK 0xff /* clock divide */ +#define SBTMCL_CO_MASK 0xf800 /* clock offset */ +#define SBTMCL_CO_SHIFT 11 +#define SBTMCL_IF_MASK 0xfc0000 /* interrupt flags */ +#define SBTMCL_IF_SHIFT 18 +#define SBTMCL_IM_MASK 0x3000000 /* interrupt mode */ +#define SBTMCL_IM_SHIFT 24 + +/* sbtmconfighigh */ +#define SBTMCH_BM_MASK 0x3 /* busy mode */ +#define SBTMCH_RM_MASK 0x3 /* retry mode */ +#define SBTMCH_RM_SHIFT 2 +#define SBTMCH_SM_MASK 0x30 /* stop mode */ +#define SBTMCH_SM_SHIFT 4 +#define SBTMCH_EM_MASK 0x300 /* sb error mode */ +#define SBTMCH_EM_SHIFT 8 +#define SBTMCH_IM_MASK 0xc00 /* int mode */ +#define SBTMCH_IM_SHIFT 10 + +/* sbbconfig */ +#define SBBC_LAT_MASK 0x3 /* sb latency */ +#define SBBC_MAX0_MASK 0xf0000 /* maxccntr0 */ +#define SBBC_MAX0_SHIFT 16 +#define SBBC_MAX1_MASK 0xf00000 /* maxccntr1 */ +#define SBBC_MAX1_SHIFT 20 + +/* sbbstate */ +#define SBBS_SRD 0x1 /* st reg disable */ +#define SBBS_HRD 0x2 /* hold reg disable */ + +/* sbidlow */ +#define SBIDL_CS_MASK 0x3 /* config space */ +#define SBIDL_AR_MASK 0x38 /* # address ranges supported */ +#define SBIDL_AR_SHIFT 3 +#define SBIDL_SYNCH 0x40 /* sync */ +#define SBIDL_INIT 0x80 /* initiator */ +#define SBIDL_MINLAT_MASK 0xf00 /* minimum backplane latency */ +#define SBIDL_MINLAT_SHIFT 8 +#define SBIDL_MAXLAT 0xf000 /* maximum backplane latency */ +#define SBIDL_MAXLAT_SHIFT 12 +#define SBIDL_FIRST 0x10000 /* this initiator is first */ +#define SBIDL_CW_MASK 0xc0000 /* cycle counter width */ +#define SBIDL_CW_SHIFT 18 +#define SBIDL_TP_MASK 0xf00000 /* target ports */ +#define SBIDL_TP_SHIFT 20 +#define SBIDL_IP_MASK 0xf000000 /* initiator ports */ +#define SBIDL_IP_SHIFT 24 +#define SBIDL_RV_MASK 0xf0000000 /* sonics backplane revision code */ +#define SBIDL_RV_SHIFT 28 +#define SBIDL_RV_2_2 0x00000000 /* version 2.2 or earlier */ +#define SBIDL_RV_2_3 0x10000000 /* version 2.3 */ + +/* 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 + +#define SB_COMMIT 0xfd8 /* update buffered registers value */ + +/* vendor codes */ +#define SB_VEND_BCM 0x4243 /* Broadcom's SB vendor code */ + +#endif /* _SBCONFIG_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h new file mode 100644 index 000000000000..afe82680838f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h @@ -0,0 +1,416 @@ +/* + * Generic Broadcom Home Networking Division (HND) DMA engine HW interface + * This supports the following chips: BCM42xx, 44xx, 47xx . + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbhnddma.h 424099 2013-09-16 07:44:34Z $ + */ + +#ifndef _sbhnddma_h_ +#define _sbhnddma_h_ + +/* 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 */ + +/* dma registers per channel(xmt or rcv) */ +typedef volatile struct { + uint32 control; /* enable, et al */ + uint32 addr; /* descriptor ring base address (4K aligned) */ + uint32 ptr; /* last descriptor posted to chip */ + uint32 status; /* current active descriptor, et al */ +} dma32regs_t; + +typedef volatile struct { + dma32regs_t xmt; /* dma tx channel */ + dma32regs_t rcv; /* dma rx channel */ +} dma32regp_t; + +typedef volatile struct { /* diag access */ + uint32 fifoaddr; /* diag address */ + uint32 fifodatalow; /* low 32bits of data */ + uint32 fifodatahigh; /* high 32bits of data */ + uint32 pad; /* reserved */ +} dma32diag_t; + +/* + * DMA Descriptor + * Descriptors are only read by the hardware, never written back. + */ +typedef volatile struct { + uint32 ctrl; /* misc control bits & bufcount */ + uint32 addr; /* data buffer address */ +} dma32dd_t; + +/* + * Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page. + */ +#define D32RINGALIGN_BITS 12 +#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS) +#define D32RINGALIGN (1 << D32RINGALIGN_BITS) + +#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) + +/* transmit channel control */ +#define XC_XE ((uint32)1 << 0) /* transmit enable */ +#define XC_SE ((uint32)1 << 1) /* transmit suspend request */ +#define XC_LE ((uint32)1 << 2) /* loopback enable */ +#define XC_FL ((uint32)1 << 4) /* flush request */ +#define XC_MR_MASK 0x000001C0 /* Multiple outstanding reads */ +#define XC_MR_SHIFT 6 +#define XC_PD ((uint32)1 << 11) /* parity check disable */ +#define XC_AE ((uint32)3 << 16) /* address extension bits */ +#define XC_AE_SHIFT 16 +#define XC_BL_MASK 0x001C0000 /* BurstLen bits */ +#define XC_BL_SHIFT 18 +#define XC_PC_MASK 0x00E00000 /* Prefetch control */ +#define XC_PC_SHIFT 21 +#define XC_PT_MASK 0x03000000 /* Prefetch threshold */ +#define XC_PT_SHIFT 24 + +/* Multiple outstanding reads */ +#define DMA_MR_1 0 +#define DMA_MR_2 1 +#define DMA_MR_4 2 +#define DMA_MR_8 3 +#define DMA_MR_12 4 +#define DMA_MR_16 5 +#define DMA_MR_20 6 +#define DMA_MR_32 7 + +/* DMA Burst Length in bytes */ +#define DMA_BL_16 0 +#define DMA_BL_32 1 +#define DMA_BL_64 2 +#define DMA_BL_128 3 +#define DMA_BL_256 4 +#define DMA_BL_512 5 +#define DMA_BL_1024 6 + +/* Prefetch control */ +#define DMA_PC_0 0 +#define DMA_PC_4 1 +#define DMA_PC_8 2 +#define DMA_PC_16 3 +/* others: reserved */ + +/* Prefetch threshold */ +#define DMA_PT_1 0 +#define DMA_PT_2 1 +#define DMA_PT_4 2 +#define DMA_PT_8 3 + +/* transmit descriptor table pointer */ +#define XP_LD_MASK 0xfff /* last valid descriptor */ + +/* transmit channel status */ +#define XS_CD_MASK 0x0fff /* current descriptor pointer */ +#define XS_XS_MASK 0xf000 /* transmit state */ +#define XS_XS_SHIFT 12 +#define XS_XS_DISABLED 0x0000 /* disabled */ +#define XS_XS_ACTIVE 0x1000 /* active */ +#define XS_XS_IDLE 0x2000 /* idle wait */ +#define XS_XS_STOPPED 0x3000 /* stopped */ +#define XS_XS_SUSP 0x4000 /* suspend pending */ +#define XS_XE_MASK 0xf0000 /* transmit errors */ +#define XS_XE_SHIFT 16 +#define XS_XE_NOERR 0x00000 /* no error */ +#define XS_XE_DPE 0x10000 /* descriptor protocol error */ +#define XS_XE_DFU 0x20000 /* data fifo underrun */ +#define XS_XE_BEBR 0x30000 /* bus error on buffer read */ +#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */ +#define XS_AD_MASK 0xfff00000 /* active descriptor */ +#define XS_AD_SHIFT 20 + +/* receive channel control */ +#define RC_RE ((uint32)1 << 0) /* receive enable */ +#define RC_RO_MASK 0xfe /* receive frame offset */ +#define RC_RO_SHIFT 1 +#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */ +#define RC_SH ((uint32)1 << 9) /* separate rx header descriptor enable */ +#define RC_OC ((uint32)1 << 10) /* overflow continue */ +#define RC_PD ((uint32)1 << 11) /* parity check disable */ +#define RC_AE ((uint32)3 << 16) /* address extension bits */ +#define RC_AE_SHIFT 16 +#define RC_BL_MASK 0x001C0000 /* BurstLen bits */ +#define RC_BL_SHIFT 18 +#define RC_PC_MASK 0x00E00000 /* Prefetch control */ +#define RC_PC_SHIFT 21 +#define RC_PT_MASK 0x03000000 /* Prefetch threshold */ +#define RC_PT_SHIFT 24 + +/* receive descriptor table pointer */ +#define RP_LD_MASK 0xfff /* last valid descriptor */ + +/* receive channel status */ +#define RS_CD_MASK 0x0fff /* current descriptor pointer */ +#define RS_RS_MASK 0xf000 /* receive state */ +#define RS_RS_SHIFT 12 +#define RS_RS_DISABLED 0x0000 /* disabled */ +#define RS_RS_ACTIVE 0x1000 /* active */ +#define RS_RS_IDLE 0x2000 /* idle wait */ +#define RS_RS_STOPPED 0x3000 /* reserved */ +#define RS_RE_MASK 0xf0000 /* receive errors */ +#define RS_RE_SHIFT 16 +#define RS_RE_NOERR 0x00000 /* no error */ +#define RS_RE_DPE 0x10000 /* descriptor protocol error */ +#define RS_RE_DFO 0x20000 /* data fifo overflow */ +#define RS_RE_BEBW 0x30000 /* bus error on buffer write */ +#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */ +#define RS_AD_MASK 0xfff00000 /* active descriptor */ +#define RS_AD_SHIFT 20 + +/* fifoaddr */ +#define FA_OFF_MASK 0xffff /* offset */ +#define FA_SEL_MASK 0xf0000 /* select */ +#define FA_SEL_SHIFT 16 +#define FA_SEL_XDD 0x00000 /* transmit dma data */ +#define FA_SEL_XDP 0x10000 /* transmit dma pointers */ +#define FA_SEL_RDD 0x40000 /* receive dma data */ +#define FA_SEL_RDP 0x50000 /* receive dma pointers */ +#define FA_SEL_XFD 0x80000 /* transmit fifo data */ +#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */ +#define FA_SEL_RFD 0xc0000 /* receive fifo data */ +#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */ +#define FA_SEL_RSD 0xe0000 /* receive frame status data */ +#define FA_SEL_RSP 0xf0000 /* receive frame status pointers */ + +/* descriptor control flags */ +#define CTRL_BC_MASK 0x00001fff /* buffer byte count, real data len must <= 4KB */ +#define CTRL_AE ((uint32)3 << 16) /* address extension bits */ +#define CTRL_AE_SHIFT 16 +#define CTRL_PARITY ((uint32)3 << 18) /* parity bit */ +#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */ +#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */ +#define CTRL_EOF ((uint32)1 << 30) /* end of frame */ +#define CTRL_SOF ((uint32)1 << 31) /* start of frame */ + +/* control flags in the range [27:20] are core-specific and not defined here */ +#define CTRL_CORE_MASK 0x0ff00000 + +/* 64 bits addressing */ + +/* dma registers per channel(xmt or rcv) */ +typedef volatile struct { + uint32 control; /* enable, et al */ + uint32 ptr; /* last descriptor posted to chip */ + uint32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */ + uint32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */ + uint32 status0; /* current descriptor, xmt state */ + uint32 status1; /* active descriptor, xmt error */ +} dma64regs_t; + +typedef volatile struct { + dma64regs_t tx; /* dma64 tx channel */ + dma64regs_t rx; /* dma64 rx channel */ +} dma64regp_t; + +typedef volatile struct { /* diag access */ + uint32 fifoaddr; /* diag address */ + uint32 fifodatalow; /* low 32bits of data */ + uint32 fifodatahigh; /* high 32bits of data */ + uint32 pad; /* reserved */ +} dma64diag_t; + +/* + * DMA Descriptor + * Descriptors are only read by the hardware, never written back. + */ +typedef volatile struct { + uint32 ctrl1; /* misc control bits */ + uint32 ctrl2; /* buffer count and address extension */ + uint32 addrlow; /* memory address of the date buffer, bits 31:0 */ + uint32 addrhigh; /* memory address of the date buffer, bits 63:32 */ +} dma64dd_t; + +/* + * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss. + */ +#define D64RINGALIGN_BITS 13 +#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) +#define D64RINGBOUNDARY (1 << D64RINGALIGN_BITS) + +#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) + +/* for cores with large descriptor ring support, descriptor ring size can be up to 4096 */ +#define D64MAXDD_LARGE ((1 << 16) / sizeof (dma64dd_t)) + +/* for cores with large descriptor ring support (4k descriptors), descriptor ring cannot cross + * 64K boundary + */ +#define D64RINGBOUNDARY_LARGE (1 << 16) + +/* + * Default DMA Burstlen values for USBRev >= 12 and SDIORev >= 11. + * When this field contains the value N, the burst length is 2**(N + 4) bytes. + */ +#define D64_DEF_USBBURSTLEN 2 +#define D64_DEF_SDIOBURSTLEN 1 + + +#ifndef D64_USBBURSTLEN +#define D64_USBBURSTLEN DMA_BL_64 +#endif +#ifndef D64_SDIOBURSTLEN +#define D64_SDIOBURSTLEN DMA_BL_32 +#endif + +/* 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_MR_MASK 0x000001C0 /* Multiple outstanding reads */ +#define D64_XC_MR_SHIFT 6 +#define D64_XC_PD 0x00000800 /* parity check disable */ +#define D64_XC_AE 0x00030000 /* address extension bits */ +#define D64_XC_AE_SHIFT 16 +#define D64_XC_BL_MASK 0x001C0000 /* BurstLen bits */ +#define D64_XC_BL_SHIFT 18 +#define D64_XC_PC_MASK 0x00E00000 /* Prefetch control */ +#define D64_XC_PC_SHIFT 21 +#define D64_XC_PT_MASK 0x03000000 /* Prefetch threshold */ +#define D64_XC_PT_SHIFT 24 + +/* transmit descriptor table pointer */ +#define D64_XP_LD_MASK 0x00001fff /* last valid descriptor */ + +/* transmit channel status */ +#define D64_XS0_CD_MASK (di->d64_xs0_cd_mask) /* 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 (di->d64_xs1_ad_mask) /* 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 */ +#define D64_RC_RE 0x00000001 /* receive enable */ +#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */ +#define D64_RC_RO_SHIFT 1 +#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */ +#define D64_RC_SH 0x00000200 /* separate rx header descriptor enable */ +#define D64_RC_SHIFT 9 /* separate rx header descriptor enable */ +#define D64_RC_OC 0x00000400 /* overflow continue */ +#define D64_RC_PD 0x00000800 /* parity check disable */ +#define D64_RC_GE 0x00004000 /* Glom enable */ +#define D64_RC_AE 0x00030000 /* address extension bits */ +#define D64_RC_AE_SHIFT 16 +#define D64_RC_BL_MASK 0x001C0000 /* BurstLen bits */ +#define D64_RC_BL_SHIFT 18 +#define D64_RC_PC_MASK 0x00E00000 /* Prefetch control */ +#define D64_RC_PC_SHIFT 21 +#define D64_RC_PT_MASK 0x03000000 /* Prefetch threshold */ +#define D64_RC_PT_SHIFT 24 + +/* flags for dma controller */ +#define DMA_CTRL_PEN (1 << 0) /* partity enable */ +#define DMA_CTRL_ROC (1 << 1) /* rx overflow continue */ +#define DMA_CTRL_RXMULTI (1 << 2) /* allow rx scatter to multiple descriptors */ +#define DMA_CTRL_UNFRAMED (1 << 3) /* Unframed Rx/Tx data */ +#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) +#define DMA_CTRL_DMA_AVOIDANCE_WAR (1 << 5) /* DMA avoidance WAR for 4331 */ +#define DMA_CTRL_RXSINGLE (1 << 6) /* always single buffer */ + +/* receive descriptor table pointer */ +#define D64_RP_LD_MASK 0x00001fff /* last valid descriptor */ + +/* receive channel status */ +#define D64_RS0_CD_MASK (di->d64_rs0_cd_mask) /* 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_NOTPCIE ((uint32)1 << 18) /* buirst size control */ +#define D64_CTRL1_EOT ((uint32)1 << 28) /* end of descriptor table */ +#define D64_CTRL1_IOC ((uint32)1 << 29) /* interrupt on completion */ +#define D64_CTRL1_EOF ((uint32)1 << 30) /* end of frame */ +#define D64_CTRL1_SOF ((uint32)1 << 31) /* start of frame */ + +/* descriptor control flags 2 */ +#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count. real data len must <= 16KB */ +#define D64_CTRL2_AE 0x00030000 /* address extension bits */ +#define D64_CTRL2_AE_SHIFT 16 +#define D64_CTRL2_PARITY 0x00040000 /* parity bit */ + +/* 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, d11corerev >= 22 */ +#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */ + +/* receive frame status */ +typedef volatile struct { + uint16 len; + uint16 flags; +} dma_rxh_t; + +#endif /* _sbhnddma_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h new file mode 100644 index 000000000000..20bb1748273b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h @@ -0,0 +1,113 @@ +/* + * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbpcmcia.h 427964 2013-10-07 07:13:33Z $ + */ + +#ifndef _SBPCMCIA_H +#define _SBPCMCIA_H + +/* All the addresses that are offsets in attribute space are divided + * by two to account for the fact that odd bytes are invalid in + * attribute space and our read/write routines make the space appear + * as if they didn't exist. Still we want to show the original numbers + * as documented in the hnd_pcmcia core manual. + */ + +/* PCMCIA Function Configuration Registers */ +#define PCMCIA_FCR (0x700 / 2) + +#define FCR0_OFF 0 +#define FCR1_OFF (0x40 / 2) +#define FCR2_OFF (0x80 / 2) +#define FCR3_OFF (0xc0 / 2) + +#define PCMCIA_FCR0 (0x700 / 2) +#define PCMCIA_FCR1 (0x740 / 2) +#define PCMCIA_FCR2 (0x780 / 2) +#define PCMCIA_FCR3 (0x7c0 / 2) + +/* Standard PCMCIA FCR registers */ + +#define PCMCIA_COR 0 + +#define COR_RST 0x80 +#define COR_LEV 0x40 +#define COR_IRQEN 0x04 +#define COR_BLREN 0x01 +#define COR_FUNEN 0x01 + + +#define PCICIA_FCSR (2 / 2) +#define PCICIA_PRR (4 / 2) +#define PCICIA_SCR (6 / 2) +#define PCICIA_ESR (8 / 2) + + +#define PCM_MEMOFF 0x0000 +#define F0_MEMOFF 0x1000 +#define F1_MEMOFF 0x2000 +#define F2_MEMOFF 0x3000 +#define F3_MEMOFF 0x4000 + +/* Memory base in the function fcr's */ +#define MEM_ADDR0 (0x728 / 2) +#define MEM_ADDR1 (0x72a / 2) +#define MEM_ADDR2 (0x72c / 2) + +/* PCMCIA base plus Srom access in fcr0: */ +#define PCMCIA_ADDR0 (0x072e / 2) +#define PCMCIA_ADDR1 (0x0730 / 2) +#define PCMCIA_ADDR2 (0x0732 / 2) + +#define MEM_SEG (0x0734 / 2) +#define SROM_CS (0x0736 / 2) +#define SROM_DATAL (0x0738 / 2) +#define SROM_DATAH (0x073a / 2) +#define SROM_ADDRL (0x073c / 2) +#define SROM_ADDRH (0x073e / 2) +#define SROM_INFO2 (0x0772 / 2) /* Corerev >= 2 && <= 5 */ +#define SROM_INFO (0x07be / 2) /* Corerev >= 6 */ + +/* Values for srom_cs: */ +#define SROM_IDLE 0 +#define SROM_WRITE 1 +#define SROM_READ 2 +#define SROM_WEN 4 +#define SROM_WDS 7 +#define SROM_DONE 8 + +/* Fields in srom_info: */ +#define SRI_SZ_MASK 0x03 +#define SRI_BLANK 0x04 +#define SRI_OTP 0x80 + + +/* sbtmstatelow */ +#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */ +#define SBTML_INT_EN 0x20000 /* enable sb interrupt */ + +/* sbtmstatehigh */ +#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */ + +#endif /* _SBPCMCIA_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h new file mode 100644 index 000000000000..56e5f14fe34f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h @@ -0,0 +1,186 @@ +/* + * SDIO device core hardware definitions. + * sdio is a portion of the pcmcia core in core rev 3 - rev 8 + * + * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbsdio.h 383835 2013-02-07 23:32:39Z $ + */ + +#ifndef _SBSDIO_H +#define _SBSDIO_H + +#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */ + +/* function 1 miscellaneous registers */ +#define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */ +#define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */ +#define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */ +#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */ +#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */ +#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */ +#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */ +#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */ +#define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */ +#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */ + +/* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */ +#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */ +#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */ +#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */ +#define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */ +#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */ +#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */ +#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */ +#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */ +#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */ +#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */ +#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D /* MesBusyCtl at 0x1001D (rev 11) */ + +#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ +#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ + +/* Sdio Core Rev 12 */ +#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E +#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1 +#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0 +#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2 +#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1 +#define SBSDIO_FUNC1_SLEEPCSR 0x1001F +#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1 +#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0 +#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1 +#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2 +#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1 + +/* SBSDIO_SPROM_CS */ +#define SBSDIO_SPROM_IDLE 0 +#define SBSDIO_SPROM_WRITE 1 +#define SBSDIO_SPROM_READ 2 +#define SBSDIO_SPROM_WEN 4 +#define SBSDIO_SPROM_WDS 7 +#define SBSDIO_SPROM_DONE 8 + +/* SBSDIO_SPROM_INFO */ +#define SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */ +#define SROM_BLANK 0x04 /* depreciated in corerev 6 */ +#define SROM_OTP 0x80 /* OTP present */ + +/* SBSDIO_CHIP_CTRL */ +#define SBSDIO_CHIP_CTRL_XTAL 0x01 /* or'd with onchip xtal_pu, + * 1: power on oscillator + * (for 4318 only) + */ +/* SBSDIO_WATERMARK */ +#define SBSDIO_WATERMARK_MASK 0x7f /* number of words - 1 for sd device + * to wait before sending data to host + */ + +/* SBSDIO_MESBUSYCTRL */ +/* When RX FIFO has less entries than this & MBE is set + * => busy signal is asserted between data blocks. +*/ +#define SBSDIO_MESBUSYCTRL_MASK 0x7f +#define SBSDIO_MESBUSYCTRL_ENAB 0x80 /* Enable busy capability for MES access */ + +/* SBSDIO_DEVICE_CTL */ +#define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when + * receiving CMD53 + */ +#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is + * synchronous to the sdio clock + */ +#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host + * except the chipActive (rev 8) + */ +#define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put + * external pads in tri-state; requires + * sdio bus power cycle to clear (rev 9) + */ +#define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ +#define SBSDIO_DEVCTL_F2WM_ENAB 0x10 /* Enable F2 Watermark */ +#define SBSDIO_DEVCTL_NONDAT_PADS_ISO 0x20 /* Isolate sdio clk and cmd (non-data) */ + +/* SBSDIO_FUNC1_CHIPCLKCSR */ +#define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */ +#define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */ +#define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */ +#define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */ +#define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */ +#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */ +#define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */ +#define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */ +/* In rev8, actual avail bits followed original docs */ +#define SBSDIO_Rev8_HT_AVAIL 0x40 +#define SBSDIO_Rev8_ALP_AVAIL 0x80 +#define SBSDIO_CSR_MASK 0x1F + +#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))) + +/* SBSDIO_FUNC1_SDIOPULLUP */ +#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */ +#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */ +#define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */ +#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */ +#define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */ + +/* function 1 OCP space */ +#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */ +#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 +#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */ + +/* some duplication with sbsdpcmdev.h here */ +/* 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 */ +#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ + +/* direct(mapped) cis space */ +#define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ +#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */ +#define SBSDIO_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP CIS */ + +#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */ + +#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple, + * link bytes + */ + +/* indirect cis access (in sprom) */ +#define SBSDIO_SPROM_CIS_OFFSET 0x8 /* 8 control bytes first, CIS starts from + * 8th byte + */ + +#define SBSDIO_BYTEMODE_DATALEN_MAX 64 /* sdio byte mode: maximum length of one + * data comamnd + */ + +#define SBSDIO_CORE_ADDR_MASK 0x1FFFF /* sdio core function one address mask */ + +#endif /* _SBSDIO_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h new file mode 100644 index 000000000000..f24d0a3c4e76 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h @@ -0,0 +1,295 @@ +/* + * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific + * device core support + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbsdpcmdev.h 416730 2013-08-06 09:33:19Z $ + */ + +#ifndef _sbsdpcmdev_h_ +#define _sbsdpcmdev_h_ + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif /* PAD */ + + +typedef volatile struct { + dma64regs_t xmt; /* dma tx */ + uint32 PAD[2]; + dma64regs_t rcv; /* dma rx */ + uint32 PAD[2]; +} dma64p_t; + +/* dma64 sdiod corerev >= 1 */ +typedef volatile struct { + dma64p_t dma64regs[2]; + dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */ + uint32 PAD[92]; +} sdiodma64_t; + +/* dma32 sdiod corerev == 0 */ +typedef volatile struct { + dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ + dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */ + uint32 PAD[108]; +} sdiodma32_t; + +/* dma32 regs for pcmcia core */ +typedef volatile struct { + dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */ + dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */ + uint32 PAD[116]; +} pcmdma32_t; + +/* core registers */ +typedef volatile struct { + uint32 corecontrol; /* CoreControl, 0x000, rev8 */ + uint32 corestatus; /* CoreStatus, 0x004, rev8 */ + uint32 PAD[1]; + uint32 biststatus; /* BistStatus, 0x00c, rev8 */ + + /* PCMCIA access */ + uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */ + uint16 PAD[1]; + uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */ + uint16 PAD[1]; + uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */ + uint16 PAD[1]; + uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */ + uint16 PAD[1]; + + /* interrupt */ + uint32 intstatus; /* IntStatus, 0x020, rev8 */ + uint32 hostintmask; /* IntHostMask, 0x024, rev8 */ + uint32 intmask; /* IntSbMask, 0x028, rev8 */ + uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */ + uint32 sbintmask; /* SBIntMask, 0x030, rev8 */ + uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */ + uint32 PAD[2]; + uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */ + uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */ + uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */ + uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */ + + /* synchronized access to registers in SDIO clock domain */ + uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */ + uint32 PAD[3]; + + /* PCMCIA frame control */ + uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ + uint8 PAD[3]; + uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ + uint8 PAD[155]; + + /* interrupt batching control */ + uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */ + uint32 PAD[3]; + + /* counters */ + uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */ + uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */ + uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */ + uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */ + uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */ + uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */ + uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */ + uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */ + uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */ + uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */ + uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */ + uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */ + uint32 PAD[40]; + uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */ + uint32 PAD[7]; + + /* DMA engines */ + volatile union { + pcmdma32_t pcm32; + sdiodma32_t sdiod32; + sdiodma64_t sdiod64; + } dma; + + /* SDIO/PCMCIA CIS region */ + char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */ + + /* PCMCIA function control registers */ + char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */ + uint16 PAD[55]; + + /* PCMCIA backplane access */ + uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */ + uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */ + uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */ + uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */ + uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */ + uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */ + uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */ + uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */ + uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */ + uint16 PAD[31]; + + /* sprom "size" & "blank" info */ + uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */ + uint32 PAD[464]; + + /* Sonics SiliconBackplane registers */ + sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */ +} sdpcmd_regs_t; + +/* corecontrol */ +#define CC_CISRDY (1 << 0) /* CIS Ready */ +#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ +#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ +#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ +#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */ +#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */ + +/* corestatus */ +#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */ +#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */ +#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */ + +#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */ +#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */ +#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */ +#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */ + +/* 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 transitioned 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) /* DMA Errors */ +#define I_DMA (I_RI | I_XI | I_ERRORS) + +/* sbintstatus */ +#define I_SB_SERR (1 << 8) /* Backplane SError (write) */ +#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */ +#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */ + +/* sdioaccess */ +#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */ +#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */ +#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */ +#define SDA_WRITE 0x01000000 /* Write bit */ +#define SDA_READ 0x00000000 /* Write bit cleared for Read */ +#define SDA_BUSY 0x80000000 /* Busy bit */ + +/* sdioaccess-accessible register address spaces */ +#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */ +#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */ +#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */ +#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */ + +/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */ +#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */ +#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */ +#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */ +#define SDA_DEVICECONTROL 0x009 /* DeviceControl */ +#define SDA_SBADDRLOW 0x00a /* SbAddrLow */ +#define SDA_SBADDRMID 0x00b /* SbAddrMid */ +#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */ +#define SDA_FRAMECTRL 0x00d /* FrameCtrl */ +#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */ +#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */ +#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */ +#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */ +#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */ +#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */ + +/* SDA_F2WATERMARK */ +#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */ + +/* SDA_SBADDRLOW */ +#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */ + +/* SDA_SBADDRMID */ +#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */ + +/* SDA_SBADDRHIGH */ +#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */ + +/* 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) /* HW reports CRC error for write out of sync */ +#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */ + +/* pcmciaframectrl */ +#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */ +#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */ + +/* intrcvlazy */ +#define IRL_TO_MASK 0x00ffffff /* timeout */ +#define IRL_FC_MASK 0xff000000 /* frame count */ +#define IRL_FC_SHIFT 24 /* frame count */ + +/* rx header */ +typedef volatile struct { + uint16 len; + uint16 flags; +} sdpcmd_rxh_t; + +/* rx header flags */ +#define RXF_CRC 0x0001 /* CRC error detected */ +#define RXF_WOOS 0x0002 /* write frame out of sync */ +#define RXF_WF_TERM 0x0004 /* write frame terminated */ +#define RXF_ABORT 0x0008 /* write frame aborted */ +#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */ + +/* HW frame tag */ +#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ + +#define SDPCM_HWEXT_LEN 8 + +#endif /* _sbsdpcmdev_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h new file mode 100644 index 000000000000..1f4ab45b2e1c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h @@ -0,0 +1,200 @@ +/* + * BCM47XX Sonics SiliconBackplane embedded ram core + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbsocram.h 481592 2014-05-29 22:10:51Z $ + */ + +#ifndef _SBSOCRAM_H +#define _SBSOCRAM_H + +#ifndef _LANGUAGE_ASSEMBLY + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif /* PAD */ + +/* Memcsocram core registers */ +typedef volatile struct sbsocramregs { + uint32 coreinfo; + uint32 bwalloc; + uint32 extracoreinfo; + uint32 biststat; + uint32 bankidx; + uint32 standbyctrl; + + uint32 errlogstatus; /* rev 6 */ + uint32 errlogaddr; /* rev 6 */ + /* used for patching rev 3 & 5 */ + uint32 cambankidx; + uint32 cambankstandbyctrl; + uint32 cambankpatchctrl; + uint32 cambankpatchtblbaseaddr; + uint32 cambankcmdreg; + uint32 cambankdatareg; + uint32 cambankmaskreg; + uint32 PAD[1]; + uint32 bankinfo; /* corev 8 */ + uint32 bankpda; + uint32 PAD[14]; + uint32 extmemconfig; + uint32 extmemparitycsr; + uint32 extmemparityerrdata; + uint32 extmemparityerrcnt; + uint32 extmemwrctrlandsize; + uint32 PAD[84]; + uint32 workaround; + uint32 pwrctl; /* corerev >= 2 */ + uint32 PAD[133]; + uint32 sr_control; /* corerev >= 15 */ + uint32 sr_status; /* corerev >= 15 */ + uint32 sr_address; /* corerev >= 15 */ + uint32 sr_data; /* corerev >= 15 */ +} sbsocramregs_t; + +#endif /* _LANGUAGE_ASSEMBLY */ + +/* Register offsets */ +#define SR_COREINFO 0x00 +#define SR_BWALLOC 0x04 +#define SR_BISTSTAT 0x0c +#define SR_BANKINDEX 0x10 +#define SR_BANKSTBYCTL 0x14 +#define SR_PWRCTL 0x1e8 + +/* Coreinfo register */ +#define SRCI_PT_MASK 0x00070000 /* corerev >= 6; port type[18:16] */ +#define SRCI_PT_SHIFT 16 +/* port types : SRCI_PT__ */ +#define SRCI_PT_OCP_OCP 0 +#define SRCI_PT_AXI_OCP 1 +#define SRCI_PT_ARM7AHB_OCP 2 +#define SRCI_PT_CM3AHB_OCP 3 +#define SRCI_PT_AXI_AXI 4 +#define SRCI_PT_AHB_AXI 5 +/* corerev >= 3 */ +#define SRCI_LSS_MASK 0x00f00000 +#define SRCI_LSS_SHIFT 20 +#define SRCI_LRS_MASK 0x0f000000 +#define SRCI_LRS_SHIFT 24 + +/* In corerev 0, the memory size is 2 to the power of the + * base plus 16 plus to the contents of the memsize field plus 1. + */ +#define SRCI_MS0_MASK 0xf +#define SR_MS0_BASE 16 + +/* + * In corerev 1 the bank size is 2 ^ the bank size field plus 14, + * the memory size is number of banks times bank size. + * The same applies to rom size. + */ +#define SRCI_ROMNB_MASK 0xf000 +#define SRCI_ROMNB_SHIFT 12 +#define SRCI_ROMBSZ_MASK 0xf00 +#define SRCI_ROMBSZ_SHIFT 8 +#define SRCI_SRNB_MASK 0xf0 +#define SRCI_SRNB_SHIFT 4 +#define SRCI_SRBSZ_MASK 0xf +#define SRCI_SRBSZ_SHIFT 0 + +#define SR_BSZ_BASE 14 + +/* Standby control register */ +#define SRSC_SBYOVR_MASK 0x80000000 +#define SRSC_SBYOVR_SHIFT 31 +#define SRSC_SBYOVRVAL_MASK 0x60000000 +#define SRSC_SBYOVRVAL_SHIFT 29 +#define SRSC_SBYEN_MASK 0x01000000 /* rev >= 3 */ +#define SRSC_SBYEN_SHIFT 24 + +/* Power control register */ +#define SRPC_PMU_STBYDIS_MASK 0x00000010 /* rev >= 3 */ +#define SRPC_PMU_STBYDIS_SHIFT 4 +#define SRPC_STBYOVRVAL_MASK 0x00000008 +#define SRPC_STBYOVRVAL_SHIFT 3 +#define SRPC_STBYOVR_MASK 0x00000007 +#define SRPC_STBYOVR_SHIFT 0 + +/* Extra core capability register */ +#define SRECC_NUM_BANKS_MASK 0x000000F0 +#define SRECC_NUM_BANKS_SHIFT 4 +#define SRECC_BANKSIZE_MASK 0x0000000F +#define SRECC_BANKSIZE_SHIFT 0 + +#define SRECC_BANKSIZE(value) (1 << (value)) + +/* CAM bank patch control */ +#define SRCBPC_PATCHENABLE 0x80000000 + +#define SRP_ADDRESS 0x0001FFFC +#define SRP_VALID 0x8000 + +/* CAM bank command reg */ +#define SRCMD_WRITE 0x00020000 +#define SRCMD_READ 0x00010000 +#define SRCMD_DONE 0x80000000 + +#define SRCMD_DONE_DLY 1000 + +/* bankidx and bankinfo reg defines corerev >= 8 */ +#define SOCRAM_BANKINFO_SZMASK 0x7f +#define SOCRAM_BANKIDX_ROM_MASK 0x100 + +#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 +/* socram bankinfo memtype */ +#define SOCRAM_MEMTYPE_RAM 0 +#define SOCRAM_MEMTYPE_R0M 1 +#define SOCRAM_MEMTYPE_DEVRAM 2 + +#define SOCRAM_BANKINFO_REG 0x40 +#define SOCRAM_BANKIDX_REG 0x10 +#define SOCRAM_BANKINFO_STDBY_MASK 0x400 +#define SOCRAM_BANKINFO_STDBY_TIMER 0x800 + +/* bankinfo rev >= 10 */ +#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13 +#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000 +#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14 +#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000 +#define SOCRAM_BANKINFO_SLPSUPP_SHIFT 15 +#define SOCRAM_BANKINFO_SLPSUPP_MASK 0x8000 +#define SOCRAM_BANKINFO_RETNTRAM_SHIFT 16 +#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 +#define SOCRAM_BANKINFO_PDASZ_SHIFT 17 +#define SOCRAM_BANKINFO_PDASZ_MASK 0x003E0000 +#define SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT 24 +#define SOCRAM_BANKINFO_DEVRAMREMAP_MASK 0x01000000 + +/* extracoreinfo register */ +#define SOCRAM_DEVRAMBANK_MASK 0xF000 +#define SOCRAM_DEVRAMBANK_SHIFT 12 + +/* bank info to calculate bank size */ +#define SOCRAM_BANKINFO_SZBASE 8192 +#define SOCRAM_BANKSIZE_SHIFT 13 /* SOCRAM_BANKINFO_SZBASE */ + + +#endif /* _SBSOCRAM_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h new file mode 100644 index 000000000000..8b85c3593c82 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h @@ -0,0 +1,619 @@ +/* + * SDIO spec header file + * Protocol and standard (common) device definitions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sdio.h 416730 2013-08-06 09:33:19Z $ + */ + +#ifndef _SDIO_H +#define _SDIO_H + + +/* CCCR structure for function 0 */ +typedef volatile struct { + uint8 cccr_sdio_rev; /* RO, cccr and sdio revision */ + uint8 sd_rev; /* RO, sd spec revision */ + uint8 io_en; /* I/O enable */ + uint8 io_rdy; /* I/O ready reg */ + uint8 intr_ctl; /* Master and per function interrupt enable control */ + uint8 intr_status; /* RO, interrupt pending status */ + uint8 io_abort; /* read/write abort or reset all functions */ + uint8 bus_inter; /* bus interface control */ + uint8 capability; /* RO, card capability */ + + uint8 cis_base_low; /* 0x9 RO, common CIS base address, LSB */ + uint8 cis_base_mid; + uint8 cis_base_high; /* 0xB RO, common CIS base address, MSB */ + + /* suspend/resume registers */ + uint8 bus_suspend; /* 0xC */ + uint8 func_select; /* 0xD */ + uint8 exec_flag; /* 0xE */ + uint8 ready_flag; /* 0xF */ + + uint8 fn0_blk_size[2]; /* 0x10(LSB), 0x11(MSB) */ + + uint8 power_control; /* 0x12 (SDIO version 1.10) */ + + uint8 speed_control; /* 0x13 */ +} sdio_regs_t; + +/* SDIO Device CCCR offsets */ +#define SDIOD_CCCR_REV 0x00 +#define SDIOD_CCCR_SDREV 0x01 +#define SDIOD_CCCR_IOEN 0x02 +#define SDIOD_CCCR_IORDY 0x03 +#define SDIOD_CCCR_INTEN 0x04 +#define SDIOD_CCCR_INTPEND 0x05 +#define SDIOD_CCCR_IOABORT 0x06 +#define SDIOD_CCCR_BICTRL 0x07 +#define SDIOD_CCCR_CAPABLITIES 0x08 +#define SDIOD_CCCR_CISPTR_0 0x09 +#define SDIOD_CCCR_CISPTR_1 0x0A +#define SDIOD_CCCR_CISPTR_2 0x0B +#define SDIOD_CCCR_BUSSUSP 0x0C +#define SDIOD_CCCR_FUNCSEL 0x0D +#define SDIOD_CCCR_EXECFLAGS 0x0E +#define SDIOD_CCCR_RDYFLAGS 0x0F +#define SDIOD_CCCR_BLKSIZE_0 0x10 +#define SDIOD_CCCR_BLKSIZE_1 0x11 +#define SDIOD_CCCR_POWER_CONTROL 0x12 +#define SDIOD_CCCR_SPEED_CONTROL 0x13 +#define SDIOD_CCCR_UHSI_SUPPORT 0x14 +#define SDIOD_CCCR_DRIVER_STRENGTH 0x15 +#define SDIOD_CCCR_INTR_EXTN 0x16 + +/* Broadcom extensions (corerev >= 1) */ +#define SDIOD_CCCR_BRCM_CARDCAP 0xf0 +#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02 +#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04 +#define SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08 +#define SDIOD_CCCR_BRCM_CARDCTL 0xf1 +#define SDIOD_CCCR_BRCM_SEPINT 0xf2 + +/* cccr_sdio_rev */ +#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */ +#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */ +#define SDIO_SPEC_VERSION_3_0 0x40 /* SDIO spec version 3.0 */ + +/* sd_rev */ +#define SD_REV_PHY_MASK 0x0f /* SD format version number */ + +/* io_en */ +#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */ +#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */ + +/* io_rdys */ +#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */ +#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */ + +/* intr_ctl */ +#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */ +#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */ +#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */ + +/* intr_status */ +#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */ +#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */ + +/* io_abort */ +#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */ +#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */ + +/* bus_inter */ +#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */ +#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */ +#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */ +#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */ +#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */ +#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */ + +/* capability */ +#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */ +#define SDIO_CAP_LSC 0x40 /* low speed card */ +#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */ +#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */ +#define SDIO_CAP_SBS 0x08 /* support suspend/resume */ +#define SDIO_CAP_SRW 0x04 /* support read wait */ +#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */ +#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */ + +/* power_control */ +#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */ +#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */ + +/* speed_control (control device entry into high-speed clocking mode) */ +#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */ +#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */ +#define SDIO_SPEED_UHSI_DDR50 0x08 + +/* for setting bus speed in card: 0x13h */ +#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3) +#define SDIO_BUS_SPEED_UHSISEL_S 1 + +/* for getting bus speed cap in card: 0x14h */ +#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3) +#define SDIO_BUS_SPEED_UHSICAP_S 0 + +/* for getting driver type CAP in card: 0x15h */ +#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3) +#define SDIO_BUS_DRVR_TYPE_CAP_S 0 + +/* for setting driver type selection in card: 0x15h */ +#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2) +#define SDIO_BUS_DRVR_TYPE_SEL_S 4 + +/* for getting async int support in card: 0x16h */ +#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1) +#define SDIO_BUS_ASYNCINT_CAP_S 0 + +/* for setting async int selection in card: 0x16h */ +#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1) +#define SDIO_BUS_ASYNCINT_SEL_S 1 + +/* brcm sepint */ +#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */ +#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */ +#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */ + +/* FBR structure for function 1-7, FBR addresses and register offsets */ +typedef volatile struct { + uint8 devctr; /* device interface, CSA control */ + uint8 ext_dev; /* extended standard I/O device type code */ + uint8 pwr_sel; /* power selection support */ + uint8 PAD[6]; /* reserved */ + + uint8 cis_low; /* CIS LSB */ + uint8 cis_mid; + uint8 cis_high; /* CIS MSB */ + uint8 csa_low; /* code storage area, LSB */ + uint8 csa_mid; + uint8 csa_high; /* code storage area, MSB */ + uint8 csa_dat_win; /* data access window to function */ + + uint8 fnx_blk_size[2]; /* block size, little endian */ +} sdio_fbr_t; + +/* Maximum number of I/O funcs */ +#define SDIOD_MAX_FUNCS 8 +#define SDIOD_MAX_IOFUNCS 7 + +/* SDIO Device FBR Start Address */ +#define SDIOD_FBR_STARTADDR 0x100 + +/* SDIO Device FBR Size */ +#define SDIOD_FBR_SIZE 0x100 + +/* Macro to calculate FBR register base */ +#define SDIOD_FBR_BASE(n) ((n) * 0x100) + +/* Function register offsets */ +#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */ +#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */ +#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */ + +/* SDIO Function CIS ptr offset */ +#define SDIOD_FBR_CISPTR_0 0x09 +#define SDIOD_FBR_CISPTR_1 0x0A +#define SDIOD_FBR_CISPTR_2 0x0B + +/* Code Storage Area pointer */ +#define SDIOD_FBR_CSA_ADDR_0 0x0C +#define SDIOD_FBR_CSA_ADDR_1 0x0D +#define SDIOD_FBR_CSA_ADDR_2 0x0E +#define SDIOD_FBR_CSA_DATA 0x0F + +/* SDIO Function I/O Block Size */ +#define SDIOD_FBR_BLKSIZE_0 0x10 +#define SDIOD_FBR_BLKSIZE_1 0x11 + +/* devctr */ +#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */ +#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */ +#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */ +/* interface codes */ +#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */ +#define SDIOD_DIC_UART 1 +#define SDIOD_DIC_BLUETOOTH_A 2 +#define SDIOD_DIC_BLUETOOTH_B 3 +#define SDIOD_DIC_GPS 4 +#define SDIOD_DIC_CAMERA 5 +#define SDIOD_DIC_PHS 6 +#define SDIOD_DIC_WLAN 7 +#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */ + +/* pwr_sel */ +#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */ +#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */ + +/* misc defines */ +#define SDIO_FUNC_0 0 +#define SDIO_FUNC_1 1 +#define SDIO_FUNC_2 2 +#define SDIO_FUNC_3 3 +#define SDIO_FUNC_4 4 +#define SDIO_FUNC_5 5 +#define SDIO_FUNC_6 6 +#define SDIO_FUNC_7 7 + +#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */ +#define SD_CARD_TYPE_IO 1 /* IO only card */ +#define SD_CARD_TYPE_MEMORY 2 /* memory only card */ +#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */ + +#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */ +#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */ + +/* Card registers: status bit position */ +#define CARDREG_STATUS_BIT_OUTOFRANGE 31 +#define CARDREG_STATUS_BIT_COMCRCERROR 23 +#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22 +#define CARDREG_STATUS_BIT_ERROR 19 +#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12 +#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11 +#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10 +#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9 +#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4 + + + +#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */ +#define SD_CMD_SEND_OPCOND 1 +#define SD_CMD_MMC_SET_RCA 3 +#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */ +#define SD_CMD_SELECT_DESELECT_CARD 7 +#define SD_CMD_SEND_CSD 9 +#define SD_CMD_SEND_CID 10 +#define SD_CMD_STOP_TRANSMISSION 12 +#define SD_CMD_SEND_STATUS 13 +#define SD_CMD_GO_INACTIVE_STATE 15 +#define SD_CMD_SET_BLOCKLEN 16 +#define SD_CMD_READ_SINGLE_BLOCK 17 +#define SD_CMD_READ_MULTIPLE_BLOCK 18 +#define SD_CMD_WRITE_BLOCK 24 +#define SD_CMD_WRITE_MULTIPLE_BLOCK 25 +#define SD_CMD_PROGRAM_CSD 27 +#define SD_CMD_SET_WRITE_PROT 28 +#define SD_CMD_CLR_WRITE_PROT 29 +#define SD_CMD_SEND_WRITE_PROT 30 +#define SD_CMD_ERASE_WR_BLK_START 32 +#define SD_CMD_ERASE_WR_BLK_END 33 +#define SD_CMD_ERASE 38 +#define SD_CMD_LOCK_UNLOCK 42 +#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */ +#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */ +#define SD_CMD_APP_CMD 55 +#define SD_CMD_GEN_CMD 56 +#define SD_CMD_READ_OCR 58 +#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */ +#define SD_ACMD_SD_STATUS 13 +#define SD_ACMD_SEND_NUM_WR_BLOCKS 22 +#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23 +#define SD_ACMD_SD_SEND_OP_COND 41 +#define SD_ACMD_SET_CLR_CARD_DETECT 42 +#define SD_ACMD_SEND_SCR 51 + +/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */ +#define SD_IO_OP_READ 0 /* Read_Write: Read */ +#define SD_IO_OP_WRITE 1 /* Read_Write: Write */ +#define SD_IO_RW_NORMAL 0 /* no RAW */ +#define SD_IO_RW_RAW 1 /* RAW */ +#define SD_IO_BYTE_MODE 0 /* Byte Mode */ +#define SD_IO_BLOCK_MODE 1 /* BlockMode */ +#define SD_IO_FIXED_ADDRESS 0 /* fix Address */ +#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */ + +/* build SD_CMD_IO_RW_DIRECT Argument */ +#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \ + ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \ + (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF)) + +/* build SD_CMD_IO_RW_EXTENDED Argument */ +#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \ + ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \ + (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF)) + +/* SDIO response parameters */ +#define SD_RSP_NO_NONE 0 +#define SD_RSP_NO_1 1 +#define SD_RSP_NO_2 2 +#define SD_RSP_NO_3 3 +#define SD_RSP_NO_4 4 +#define SD_RSP_NO_5 5 +#define SD_RSP_NO_6 6 + + /* Modified R6 response (to CMD3) */ +#define SD_RSP_MR6_COM_CRC_ERROR 0x8000 +#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000 +#define SD_RSP_MR6_ERROR 0x2000 + + /* Modified R1 in R4 Response (to CMD5) */ +#define SD_RSP_MR1_SBIT 0x80 +#define SD_RSP_MR1_PARAMETER_ERROR 0x40 +#define SD_RSP_MR1_RFU5 0x20 +#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10 +#define SD_RSP_MR1_COM_CRC_ERROR 0x08 +#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04 +#define SD_RSP_MR1_RFU1 0x02 +#define SD_RSP_MR1_IDLE_STATE 0x01 + + /* R5 response (to CMD52 and CMD53) */ +#define SD_RSP_R5_COM_CRC_ERROR 0x80 +#define SD_RSP_R5_ILLEGAL_COMMAND 0x40 +#define SD_RSP_R5_IO_CURRENTSTATE1 0x20 +#define SD_RSP_R5_IO_CURRENTSTATE0 0x10 +#define SD_RSP_R5_ERROR 0x08 +#define SD_RSP_R5_RFU 0x04 +#define SD_RSP_R5_FUNC_NUM_ERROR 0x02 +#define SD_RSP_R5_OUT_OF_RANGE 0x01 + +#define SD_RSP_R5_ERRBITS 0xCB + + +/* ------------------------------------------------ + * SDIO Commands and responses + * + * I/O only commands are: + * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53 + * ------------------------------------------------ + */ + +/* SDIO Commands */ +#define SDIOH_CMD_0 0 +#define SDIOH_CMD_3 3 +#define SDIOH_CMD_5 5 +#define SDIOH_CMD_7 7 +#define SDIOH_CMD_11 11 +#define SDIOH_CMD_14 14 +#define SDIOH_CMD_15 15 +#define SDIOH_CMD_19 19 +#define SDIOH_CMD_52 52 +#define SDIOH_CMD_53 53 +#define SDIOH_CMD_59 59 + +/* SDIO Command Responses */ +#define SDIOH_RSP_NONE 0 +#define SDIOH_RSP_R1 1 +#define SDIOH_RSP_R2 2 +#define SDIOH_RSP_R3 3 +#define SDIOH_RSP_R4 4 +#define SDIOH_RSP_R5 5 +#define SDIOH_RSP_R6 6 + +/* + * SDIO Response Error flags + */ +#define SDIOH_RSP5_ERROR_FLAGS 0xCB + +/* ------------------------------------------------ + * SDIO Command structures. I/O only commands are: + * + * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53 + * ------------------------------------------------ + */ + +#define CMD5_OCR_M BITFIELD_MASK(24) +#define CMD5_OCR_S 0 + +#define CMD5_S18R_M BITFIELD_MASK(1) +#define CMD5_S18R_S 24 + +#define CMD7_RCA_M BITFIELD_MASK(16) +#define CMD7_RCA_S 16 + +#define CMD14_RCA_M BITFIELD_MASK(16) +#define CMD14_RCA_S 16 +#define CMD14_SLEEP_M BITFIELD_MASK(1) +#define CMD14_SLEEP_S 15 + +#define CMD_15_RCA_M BITFIELD_MASK(16) +#define CMD_15_RCA_S 16 + +#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52 + */ +#define CMD52_DATA_S 0 +#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ +#define CMD52_REG_ADDR_S 9 +#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */ +#define CMD52_RAW_S 27 +#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ +#define CMD52_FUNCTION_S 28 +#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ +#define CMD52_RW_FLAG_S 31 + + +#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */ +#define CMD53_BYTE_BLK_CNT_S 0 +#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ +#define CMD53_REG_ADDR_S 9 +#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */ +#define CMD53_OP_CODE_S 26 +#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */ +#define CMD53_BLK_MODE_S 27 +#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ +#define CMD53_FUNCTION_S 28 +#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ +#define CMD53_RW_FLAG_S 31 + +/* ------------------------------------------------------ + * SDIO Command Response structures for SD1 and SD4 modes + * ----------------------------------------------------- + */ +#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */ +#define RSP4_IO_OCR_S 0 + +#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */ +#define RSP4_S18A_S 24 + +#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */ +#define RSP4_STUFF_S 24 +#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */ +#define RSP4_MEM_PRESENT_S 27 +#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */ +#define RSP4_NUM_FUNCS_S 28 +#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */ +#define RSP4_CARD_READY_S 31 + +#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0] + */ +#define RSP6_STATUS_S 0 +#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */ +#define RSP6_IO_RCA_S 16 + +#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */ +#define RSP1_AKE_SEQ_ERROR_S 3 +#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ +#define RSP1_APP_CMD_S 5 +#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */ +#define RSP1_READY_FOR_DATA_S 8 +#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card + * when Cmd was received + */ +#define RSP1_CURR_STATE_S 9 +#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */ +#define RSP1_EARSE_RESET_S 13 +#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */ +#define RSP1_CARD_ECC_DISABLE_S 14 +#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */ +#define RSP1_WP_ERASE_SKIP_S 15 +#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits + * of CSD + */ +#define RSP1_CID_CSD_OVERW_S 16 +#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */ +#define RSP1_ERROR_S 19 +#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */ +#define RSP1_CC_ERROR_S 20 +#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed + * to correct data + */ +#define RSP1_CARD_ECC_FAILED_S 21 +#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */ +#define RSP1_ILLEGAL_CMD_S 22 +#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed + */ +#define RSP1_COM_CRC_ERROR_S 23 +#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */ +#define RSP1_LOCK_UNLOCK_FAIL_S 24 +#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */ +#define RSP1_CARD_LOCKED_S 25 +#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program + * write-protected blocks + */ +#define RSP1_WP_VIOLATION_S 26 +#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */ +#define RSP1_ERASE_PARAM_S 27 +#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */ +#define RSP1_ERASE_SEQ_ERR_S 28 +#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */ +#define RSP1_BLK_LEN_ERR_S 29 +#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */ +#define RSP1_ADDR_ERR_S 30 +#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */ +#define RSP1_OUT_OF_RANGE_S 31 + + +#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */ +#define RSP5_DATA_S 0 +#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */ +#define RSP5_FLAGS_S 8 +#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */ +#define RSP5_STUFF_S 16 + +/* ---------------------------------------------- + * SDIO Command Response structures for SPI mode + * ---------------------------------------------- + */ +#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */ +#define SPIRSP4_IO_OCR_S 0 +#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */ +#define SPIRSP4_STUFF_S 16 +#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */ +#define SPIRSP4_MEM_PRESENT_S 19 +#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */ +#define SPIRSP4_NUM_FUNCS_S 20 +#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */ +#define SPIRSP4_CARD_READY_S 23 +#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */ +#define SPIRSP4_IDLE_STATE_S 24 +#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ +#define SPIRSP4_ILLEGAL_CMD_S 26 +#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ +#define SPIRSP4_COM_CRC_ERROR_S 27 +#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error + */ +#define SPIRSP4_FUNC_NUM_ERROR_S 28 +#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ +#define SPIRSP4_PARAM_ERROR_S 30 +#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ +#define SPIRSP4_START_BIT_S 31 + +#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */ +#define SPIRSP5_DATA_S 16 +#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */ +#define SPIRSP5_IDLE_STATE_S 24 +#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ +#define SPIRSP5_ILLEGAL_CMD_S 26 +#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ +#define SPIRSP5_COM_CRC_ERROR_S 27 +#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error + */ +#define SPIRSP5_FUNC_NUM_ERROR_S 28 +#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ +#define SPIRSP5_PARAM_ERROR_S 30 +#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ +#define SPIRSP5_START_BIT_S 31 + +/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */ +#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error + */ +#define RSP6STAT_AKE_SEQ_ERROR_S 3 +#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ +#define RSP6STAT_APP_CMD_S 5 +#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data + * (buff empty) + */ +#define RSP6STAT_READY_FOR_DATA_S 8 +#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at + * Cmd reception + */ +#define RSP6STAT_CURR_STATE_S 9 +#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19 + */ +#define RSP6STAT_ERROR_S 13 +#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for + * card state Bit 22 + */ +#define RSP6STAT_ILLEGAL_CMD_S 14 +#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command + * failed Bit 23 + */ +#define RSP6STAT_COM_CRC_ERROR_S 15 + +#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ +#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE + +/* command issue options */ +#define CMD_OPTION_DEFAULT 0 +#define CMD_OPTION_TUNING 1 +#endif /* _SDIO_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h new file mode 100644 index 000000000000..62a5c4cc3179 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h @@ -0,0 +1,445 @@ +/* + * SDIO Host Controller Spec header file + * Register map and definitions for the Standard Host Controller + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sdioh.h 345499 2012-07-18 06:59:05Z $ + */ + +#ifndef _SDIOH_H +#define _SDIOH_H + +#define SD_SysAddr 0x000 +#define SD_BlockSize 0x004 +#define SD_BlockCount 0x006 +#define SD_Arg0 0x008 +#define SD_Arg1 0x00A +#define SD_TransferMode 0x00C +#define SD_Command 0x00E +#define SD_Response0 0x010 +#define SD_Response1 0x012 +#define SD_Response2 0x014 +#define SD_Response3 0x016 +#define SD_Response4 0x018 +#define SD_Response5 0x01A +#define SD_Response6 0x01C +#define SD_Response7 0x01E +#define SD_BufferDataPort0 0x020 +#define SD_BufferDataPort1 0x022 +#define SD_PresentState 0x024 +#define SD_HostCntrl 0x028 +#define SD_PwrCntrl 0x029 +#define SD_BlockGapCntrl 0x02A +#define SD_WakeupCntrl 0x02B +#define SD_ClockCntrl 0x02C +#define SD_TimeoutCntrl 0x02E +#define SD_SoftwareReset 0x02F +#define SD_IntrStatus 0x030 +#define SD_ErrorIntrStatus 0x032 +#define SD_IntrStatusEnable 0x034 +#define SD_ErrorIntrStatusEnable 0x036 +#define SD_IntrSignalEnable 0x038 +#define SD_ErrorIntrSignalEnable 0x03A +#define SD_CMD12ErrorStatus 0x03C +#define SD_Capabilities 0x040 +#define SD_Capabilities3 0x044 +#define SD_MaxCurCap 0x048 +#define SD_MaxCurCap_Reserved 0x04C +#define SD_ADMA_ErrStatus 0x054 +#define SD_ADMA_SysAddr 0x58 +#define SD_SlotInterruptStatus 0x0FC +#define SD_HostControllerVersion 0x0FE +#define SD_GPIO_Reg 0x100 +#define SD_GPIO_OE 0x104 +#define SD_GPIO_Enable 0x108 + +/* SD specific registers in PCI config space */ +#define SD_SlotInfo 0x40 + +/* HC 3.0 specific registers and offsets */ +#define SD3_HostCntrl2 0x03E +/* preset regsstart and count */ +#define SD3_PresetValStart 0x060 +#define SD3_PresetValCount 8 +/* preset-indiv regs */ +#define SD3_PresetVal_init 0x060 +#define SD3_PresetVal_default 0x062 +#define SD3_PresetVal_HS 0x064 +#define SD3_PresetVal_SDR12 0x066 +#define SD3_PresetVal_SDR25 0x068 +#define SD3_PresetVal_SDR50 0x06a +#define SD3_PresetVal_SDR104 0x06c +#define SD3_PresetVal_DDR50 0x06e +/* SDIO3.0 Revx specific Registers */ +#define SD3_Tuning_Info_Register 0x0EC +#define SD3_WL_BT_reset_register 0x0F0 + + +/* preset value indices */ +#define SD3_PRESETVAL_INITIAL_IX 0 +#define SD3_PRESETVAL_DESPEED_IX 1 +#define SD3_PRESETVAL_HISPEED_IX 2 +#define SD3_PRESETVAL_SDR12_IX 3 +#define SD3_PRESETVAL_SDR25_IX 4 +#define SD3_PRESETVAL_SDR50_IX 5 +#define SD3_PRESETVAL_SDR104_IX 6 +#define SD3_PRESETVAL_DDR50_IX 7 + +/* SD_Capabilities reg (0x040) */ +#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6) +#define CAP_TO_CLKFREQ_S 0 +#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1) +#define CAP_TO_CLKUNIT_S 7 +/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2 + bits are reserved. going ahead with 8 bits, as it is req for 3.0 +*/ +#define CAP_BASECLK_M BITFIELD_MASK(8) +#define CAP_BASECLK_S 8 +#define CAP_MAXBLOCK_M BITFIELD_MASK(2) +#define CAP_MAXBLOCK_S 16 +#define CAP_ADMA2_M BITFIELD_MASK(1) +#define CAP_ADMA2_S 19 +#define CAP_ADMA1_M BITFIELD_MASK(1) +#define CAP_ADMA1_S 20 +#define CAP_HIGHSPEED_M BITFIELD_MASK(1) +#define CAP_HIGHSPEED_S 21 +#define CAP_DMA_M BITFIELD_MASK(1) +#define CAP_DMA_S 22 +#define CAP_SUSPEND_M BITFIELD_MASK(1) +#define CAP_SUSPEND_S 23 +#define CAP_VOLT_3_3_M BITFIELD_MASK(1) +#define CAP_VOLT_3_3_S 24 +#define CAP_VOLT_3_0_M BITFIELD_MASK(1) +#define CAP_VOLT_3_0_S 25 +#define CAP_VOLT_1_8_M BITFIELD_MASK(1) +#define CAP_VOLT_1_8_S 26 +#define CAP_64BIT_HOST_M BITFIELD_MASK(1) +#define CAP_64BIT_HOST_S 28 + +#define SDIO_OCR_READ_FAIL (2) + + +#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1) +#define CAP_ASYNCINT_SUP_S 29 + +#define CAP_SLOTTYPE_M BITFIELD_MASK(2) +#define CAP_SLOTTYPE_S 30 + +#define CAP3_MSBits_OFFSET (32) +/* note: following are caps MSB32 bits. + So the bits start from 0, instead of 32. that is why + CAP3_MSBits_OFFSET is subtracted. +*/ +#define CAP3_SDR50_SUP_M BITFIELD_MASK(1) +#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET) + +#define CAP3_SDR104_SUP_M BITFIELD_MASK(1) +#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET) + +#define CAP3_DDR50_SUP_M BITFIELD_MASK(1) +#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET) + +/* for knowing the clk caps in a single read */ +#define CAP3_30CLKCAP_M BITFIELD_MASK(3) +#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET) + +#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1) +#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET) + +#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1) +#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET) + +#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1) +#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET) + +#define CAP3_RETUNING_TC_M BITFIELD_MASK(4) +#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET) + +#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1) +#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET) + +#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2) +#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET) + +#define CAP3_CLK_MULT_M BITFIELD_MASK(8) +#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET) + +#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2) +#define PRESET_DRIVR_SELECT_S 14 + +#define PRESET_CLK_DIV_M BITFIELD_MASK(10) +#define PRESET_CLK_DIV_S 0 + +/* SD_MaxCurCap reg (0x048) */ +#define CAP_CURR_3_3_M BITFIELD_MASK(8) +#define CAP_CURR_3_3_S 0 +#define CAP_CURR_3_0_M BITFIELD_MASK(8) +#define CAP_CURR_3_0_S 8 +#define CAP_CURR_1_8_M BITFIELD_MASK(8) +#define CAP_CURR_1_8_S 16 + +/* SD_SysAddr: Offset 0x0000, Size 4 bytes */ + +/* SD_BlockSize: Offset 0x004, Size 2 bytes */ +#define BLKSZ_BLKSZ_M BITFIELD_MASK(12) +#define BLKSZ_BLKSZ_S 0 +#define BLKSZ_BNDRY_M BITFIELD_MASK(3) +#define BLKSZ_BNDRY_S 12 + +/* SD_BlockCount: Offset 0x006, size 2 bytes */ + +/* SD_Arg0: Offset 0x008, size = 4 bytes */ +/* SD_TransferMode Offset 0x00C, size = 2 bytes */ +#define XFER_DMA_ENABLE_M BITFIELD_MASK(1) +#define XFER_DMA_ENABLE_S 0 +#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1) +#define XFER_BLK_COUNT_EN_S 1 +#define XFER_CMD_12_EN_M BITFIELD_MASK(1) +#define XFER_CMD_12_EN_S 2 +#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1) +#define XFER_DATA_DIRECTION_S 4 +#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1) +#define XFER_MULTI_BLOCK_S 5 + +/* SD_Command: Offset 0x00E, size = 2 bytes */ +/* resp_type field */ +#define RESP_TYPE_NONE 0 +#define RESP_TYPE_136 1 +#define RESP_TYPE_48 2 +#define RESP_TYPE_48_BUSY 3 +/* type field */ +#define CMD_TYPE_NORMAL 0 +#define CMD_TYPE_SUSPEND 1 +#define CMD_TYPE_RESUME 2 +#define CMD_TYPE_ABORT 3 + +#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */ +#define CMD_RESP_TYPE_S 0 +#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */ +#define CMD_CRC_EN_S 3 +#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */ +#define CMD_INDEX_EN_S 4 +#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */ +#define CMD_DATA_EN_S 5 +#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc + */ +#define CMD_TYPE_S 6 +#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */ +#define CMD_INDEX_S 8 + +/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */ +/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */ +/* SD_PresentState : Offset 0x024, size = 4 bytes */ +#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */ +#define PRES_CMD_INHIBIT_S 0 +#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */ +#define PRES_DAT_INHIBIT_S 1 +#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */ +#define PRES_DAT_BUSY_S 2 +#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */ +#define PRES_PRESENT_RSVD_S 3 +#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */ +#define PRES_WRITE_ACTIVE_S 8 +#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */ +#define PRES_READ_ACTIVE_S 9 +#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */ +#define PRES_WRITE_DATA_RDY_S 10 +#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */ +#define PRES_READ_DATA_RDY_S 11 +#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */ +#define PRES_CARD_PRESENT_S 16 +#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */ +#define PRES_CARD_STABLE_S 17 +#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */ +#define PRES_CARD_PRESENT_RAW_S 18 +#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */ +#define PRES_WRITE_ENABLED_S 19 +#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */ +#define PRES_DAT_SIGNAL_S 20 +#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */ +#define PRES_CMD_SIGNAL_S 24 + +/* SD_HostCntrl: Offset 0x028, size = 1 bytes */ +#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */ +#define HOST_LED_S 0 +#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */ +#define HOST_DATA_WIDTH_S 1 +#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */ +#define HOST_DMA_SEL_S 3 +#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */ +#define HOST_HI_SPEED_EN_S 2 + +/* Host Control2: */ +#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */ + +#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */ + +#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */ + +#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */ + +#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */ +#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */ + +#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */ + +#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */ +#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */ + +#define HOST_CONTR_VER_2 (1) +#define HOST_CONTR_VER_3 (2) + +/* misc defines */ +#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */ +#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */ + +/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */ +#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */ +#define PWR_BUS_EN_S 0 +#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */ +#define PWR_VOLTS_S 1 + +/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */ +#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */ +#define SW_RESET_ALL_S 0 +#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */ +#define SW_RESET_CMD_S 1 +#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */ +#define SW_RESET_DAT_S 2 + +/* SD_IntrStatus: Offset 0x030, size = 2 bytes */ +/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */ +#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */ +#define INTSTAT_CMD_COMPLETE_S 0 +#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1) +#define INTSTAT_XFER_COMPLETE_S 1 +#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1) +#define INTSTAT_BLOCK_GAP_EVENT_S 2 +#define INTSTAT_DMA_INT_M BITFIELD_MASK(1) +#define INTSTAT_DMA_INT_S 3 +#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1) +#define INTSTAT_BUF_WRITE_READY_S 4 +#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1) +#define INTSTAT_BUF_READ_READY_S 5 +#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1) +#define INTSTAT_CARD_INSERTION_S 6 +#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1) +#define INTSTAT_CARD_REMOVAL_S 7 +#define INTSTAT_CARD_INT_M BITFIELD_MASK(1) +#define INTSTAT_CARD_INT_S 8 +#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */ +#define INTSTAT_RETUNING_INT_S 12 +#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */ +#define INTSTAT_ERROR_INT_S 15 + +/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */ +/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */ +#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1) +#define ERRINT_CMD_TIMEOUT_S 0 +#define ERRINT_CMD_CRC_M BITFIELD_MASK(1) +#define ERRINT_CMD_CRC_S 1 +#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1) +#define ERRINT_CMD_ENDBIT_S 2 +#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1) +#define ERRINT_CMD_INDEX_S 3 +#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1) +#define ERRINT_DATA_TIMEOUT_S 4 +#define ERRINT_DATA_CRC_M BITFIELD_MASK(1) +#define ERRINT_DATA_CRC_S 5 +#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1) +#define ERRINT_DATA_ENDBIT_S 6 +#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1) +#define ERRINT_CURRENT_LIMIT_S 7 +#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1) +#define ERRINT_AUTO_CMD12_S 8 +#define ERRINT_VENDOR_M BITFIELD_MASK(4) +#define ERRINT_VENDOR_S 12 +#define ERRINT_ADMA_M BITFIELD_MASK(1) +#define ERRINT_ADMA_S 9 + +/* Also provide definitions in "normal" form to allow combined masks */ +#define ERRINT_CMD_TIMEOUT_BIT 0x0001 +#define ERRINT_CMD_CRC_BIT 0x0002 +#define ERRINT_CMD_ENDBIT_BIT 0x0004 +#define ERRINT_CMD_INDEX_BIT 0x0008 +#define ERRINT_DATA_TIMEOUT_BIT 0x0010 +#define ERRINT_DATA_CRC_BIT 0x0020 +#define ERRINT_DATA_ENDBIT_BIT 0x0040 +#define ERRINT_CURRENT_LIMIT_BIT 0x0080 +#define ERRINT_AUTO_CMD12_BIT 0x0100 +#define ERRINT_ADMA_BIT 0x0200 + +/* Masks to select CMD vs. DATA errors */ +#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\ + ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT) +#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\ + ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT) +#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS) + +/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */ +/* SD_ClockCntrl : Offset 0x02C , size = bytes */ +/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */ +/* SD_IntrStatus : Offset 0x030 , size = bytes */ +/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */ +/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */ +/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */ +/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */ +/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */ +/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */ +/* SD_Capabilities : Offset 0x040 , size = bytes */ +/* SD_MaxCurCap : Offset 0x048 , size = bytes */ +/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */ +/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */ +/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */ + +/* SDIO Host Control Register DMA Mode Definitions */ +#define SDIOH_SDMA_MODE 0 +#define SDIOH_ADMA1_MODE 1 +#define SDIOH_ADMA2_MODE 2 +#define SDIOH_ADMA2_64_MODE 3 + +#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ +#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ +#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ +#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ +#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ +#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ +#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ +#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ + +/* ADMA2 Descriptor Table Entry for 32-bit Address */ +typedef struct adma2_dscr_32b { + uint32 len_attr; + uint32 phys_addr; +} adma2_dscr_32b_t; + +/* ADMA1 Descriptor Table Entry */ +typedef struct adma1_dscr { + uint32 phys_addr_attr; +} adma1_dscr_t; + +#endif /* _SDIOH_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h new file mode 100644 index 000000000000..326b32d8dfb0 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h @@ -0,0 +1,58 @@ +/* + * Structure used by apps whose drivers access SDIO drivers. + * Pulled out separately so dhdu and wlu can both use it. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sdiovar.h 241182 2011-02-17 21:50:03Z $ + */ + +#ifndef _sdiovar_h_ +#define _sdiovar_h_ + +#include + +/* require default structure packing */ +#define BWL_DEFAULT_PACKING +#include + +typedef struct sdreg { + int func; + int offset; + int value; +} sdreg_t; + +/* Common msglevel constants */ +#define SDH_ERROR_VAL 0x0001 /* Error */ +#define SDH_TRACE_VAL 0x0002 /* Trace */ +#define SDH_INFO_VAL 0x0004 /* Info */ +#define SDH_DEBUG_VAL 0x0008 /* Debug */ +#define SDH_DATA_VAL 0x0010 /* Data */ +#define SDH_CTRL_VAL 0x0020 /* Control Regs */ +#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ +#define SDH_DMA_VAL 0x0080 /* DMA */ + +#define NUM_PREV_TRANSACTIONS 16 + + +#include + +#endif /* _sdiovar_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h b/drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h new file mode 100644 index 000000000000..19a18ee50a99 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h @@ -0,0 +1,440 @@ +/* + * Misc utility routines for accessing the SOC Interconnects + * of Broadcom HNBU chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: siutils.h 481592 2014-05-29 22:10:51Z $ + */ + +#ifndef _siutils_h_ +#define _siutils_h_ + + +#include +/* + * Data structure to export all chip specific common variables + * public (read-only) portion of siutils handle returned by si_attach()/si_kattach() + */ +struct si_pub { + uint socitype; /* SOCI_SB, SOCI_AI */ + + uint bustype; /* SI_BUS, PCI_BUS */ + 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 */ + uint32 cccaps; /* chip common capabilities */ + uint32 cccaps_ext; /* chip common capabilities extension */ + int pmurev; /* pmu core rev */ + uint32 pmucaps; /* pmu capabilities */ + uint boardtype; /* board type */ + uint boardrev; /* board rev */ + 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 */ + uint32 chipst; /* chip status */ + bool issim; /* chip is in simulation or emulation */ + uint socirev; /* SOC interconnect rev */ + bool pci_pr32414; + +}; + +/* for HIGH_ONLY driver, the si_t must be writable to allow states sync from BMAC to HIGH driver + * for monolithic driver, it is readonly to prevent accident change + */ +typedef const struct si_pub si_t; + + +/* + * 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. + */ +#define SI_OSH NULL /* Use for si_kattach when no osh is available */ + +#define BADIDX (SI_MAXCORES + 1) + +/* 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 + +#define ISSIM_ENAB(sih) FALSE + +/* PMU clock/power control */ +#if defined(BCMPMUCTL) +#define PMUCTL_ENAB(sih) (BCMPMUCTL) +#else +#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU) +#endif + +/* chipcommon clock/power control (exclusive with PMU's) */ +#if defined(BCMPMUCTL) && BCMPMUCTL +#define CCCTL_ENAB(sih) (0) +#define CCPLL_ENAB(sih) (0) +#else +#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL) +#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK) +#endif + +typedef void (*gpio_handler_t)(uint32 stat, void *arg); +typedef void (*gci_gpio_handler_t)(uint32 stat, void *arg); +/* External BT Coex enable mask */ +#define CC_BTCOEX_EN_MASK 0x01 +/* External PA enable mask */ +#define GPIO_CTRL_EPA_EN_MASK 0x40 +/* WL/BT control enable mask */ +#define GPIO_CTRL_5_6_EN_MASK 0x60 +#define GPIO_CTRL_7_6_EN_MASK 0xC0 +#define GPIO_OUT_7_EN_MASK 0x80 + + +/* CR4 specific defines used by the host driver */ +#define SI_CR4_CAP (0x04) +#define SI_CR4_BANKIDX (0x40) +#define SI_CR4_BANKINFO (0x44) +#define SI_CR4_BANKPDA (0x4C) + +#define ARMCR4_TCBBNB_MASK 0xf0 +#define ARMCR4_TCBBNB_SHIFT 4 +#define ARMCR4_TCBANB_MASK 0xf +#define ARMCR4_TCBANB_SHIFT 0 + +#define SICF_CPUHALT (0x0020) +#define ARMCR4_BSZ_MASK 0x3f +#define ARMCR4_BSZ_MULT 8192 + +/* === exported functions === */ +extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, + void *sdh, char **vars, uint *varsz); +extern si_t *si_kattach(osl_t *osh); +extern void si_detach(si_t *sih); +extern bool si_pci_war16165(si_t *sih); + +extern uint si_corelist(si_t *sih, uint coreid[]); +extern uint si_coreid(si_t *sih); +extern uint si_flag(si_t *sih); +extern uint si_flag_alt(si_t *sih); +extern uint si_intflag(si_t *sih); +extern uint si_coreidx(si_t *sih); +extern uint si_coreunit(si_t *sih); +extern uint si_corevendor(si_t *sih); +extern uint si_corerev(si_t *sih); +extern void *si_osh(si_t *sih); +extern void si_setosh(si_t *sih, osl_t *osh); +extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); +extern uint32 *si_corereg_addr(si_t *sih, uint coreidx, uint regoff); +extern void *si_coreregs(si_t *sih); +extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); +extern uint si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val); +extern void *si_wrapperregs(si_t *sih); +extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); +extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); +extern bool si_iscoreup(si_t *sih); +extern uint si_numcoreunits(si_t *sih, uint coreid); +extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); +extern void *si_setcoreidx(si_t *sih, uint coreidx); +extern void *si_setcore(si_t *sih, uint coreid, uint coreunit); +extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); +extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); +extern int si_numaddrspaces(si_t *sih); +extern uint32 si_addrspace(si_t *sih, uint asidx); +extern uint32 si_addrspacesize(si_t *sih, uint asidx); +extern void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); +extern int si_corebist(si_t *sih); +extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); +extern void si_core_disable(si_t *sih, uint32 bits); +extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); +extern uint si_chip_hostif(si_t *sih); +extern bool si_read_pmu_autopll(si_t *sih); +extern uint32 si_clock(si_t *sih); +extern uint32 si_alp_clock(si_t *sih); +extern uint32 si_ilp_clock(si_t *sih); +extern void si_pci_setup(si_t *sih, uint coremask); +extern void si_pcmcia_init(si_t *sih); +extern void si_setint(si_t *sih, int siflag); +extern bool si_backplane64(si_t *sih); +extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, + void *intrsenabled_fn, void *intr_arg); +extern void si_deregister_intr_callback(si_t *sih); +extern void si_clkctl_init(si_t *sih); +extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); +extern bool si_clkctl_cc(si_t *sih, uint mode); +extern int si_clkctl_xtal(si_t *sih, uint what, bool on); +extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); +extern void si_btcgpiowar(si_t *sih); +extern bool si_deviceremoved(si_t *sih); +extern uint32 si_socram_size(si_t *sih); +extern uint32 si_socdevram_size(si_t *sih); +extern uint32 si_socram_srmem_size(si_t *sih); +extern void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda); +extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect, uint8 *remap); +extern bool si_socdevram_pkg(si_t *sih); +extern bool si_socdevram_remap_isenb(si_t *sih); +extern uint32 si_socdevram_remap_size(si_t *sih); + +extern void si_watchdog(si_t *sih, uint ticks); +extern void si_watchdog_ms(si_t *sih, uint32 ms); +extern uint32 si_watchdog_msticks(void); +extern void *si_gpiosetcore(si_t *sih); +extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioin(si_t *sih); +extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); +extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); +extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); +extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); +extern uint32 si_gpio_int_enable(si_t *sih, bool enable); +extern void si_gci_enable_gpio(si_t *sih, uint8 gpio, uint32 mask, uint32 value); +extern uint8 si_gci_host_wake_gpio_init(si_t *sih); +extern void si_gci_host_wake_gpio_enable(si_t *sih, uint8 gpio, bool state); + +/* GPIO event handlers */ +extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg); +extern void si_gpio_handler_unregister(si_t *sih, void* gpioh); +extern void si_gpio_handler_process(si_t *sih); + +/* GCI interrupt handlers */ +extern void si_gci_handler_process(si_t *sih); + +/* GCI GPIO event handlers */ +extern void *si_gci_gpioint_handler_register(si_t *sih, uint8 gpio, uint8 sts, + gci_gpio_handler_t cb, void *arg); +extern void si_gci_gpioint_handler_unregister(si_t *sih, void* gci_i); + +/* Wake-on-wireless-LAN (WOWL) */ +extern bool si_pci_pmecap(si_t *sih); +struct osl_info; +extern bool si_pci_fastpmecap(struct osl_info *osh); +extern bool si_pci_pmestat(si_t *sih); +extern void si_pci_pmeclr(si_t *sih); +extern void si_pci_pmeen(si_t *sih); +extern void si_pci_pmestatclr(si_t *sih); +extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); +extern uint si_pcie_writereg(void *sih, uint addrtype, uint offset, uint val); + + +extern void si_sdio_init(si_t *sih); + +extern uint16 si_d11_devid(si_t *sih); +extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, + uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); + +#define si_eci(sih) 0 +static INLINE void * si_eci_init(si_t *sih) {return NULL;} +#define si_eci_notify_bt(sih, type, val) (0) +#define si_seci(sih) 0 +#define si_seci_upd(sih, a) do {} while (0) +static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} +static INLINE void * si_gci_init(si_t *sih) {return NULL;} +#define si_seci_down(sih) do {} while (0) +#define si_gci(sih) 0 + +/* OTP status */ +extern bool si_is_otp_disabled(si_t *sih); +extern bool si_is_otp_powered(si_t *sih); +extern void si_otp_power(si_t *sih, bool on, uint32* min_res_mask); + +/* SPROM availability */ +extern bool si_is_sprom_available(si_t *sih); +extern bool si_is_sprom_enabled(si_t *sih); +extern void si_sprom_enable(si_t *sih, bool enable); + +/* OTP/SROM CIS stuff */ +extern int si_cis_source(si_t *sih); +#define CIS_DEFAULT 0 +#define CIS_SROM 1 +#define CIS_OTP 2 + +/* Fab-id information */ +#define DEFAULT_FAB 0x0 /* Original/first fab used for this chip */ +#define CSM_FAB7 0x1 /* CSM Fab7 chip */ +#define TSMC_FAB12 0x2 /* TSMC Fab12/Fab14 chip */ +#define SMIC_FAB4 0x3 /* SMIC Fab4 chip */ + +extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw); +extern uint16 si_fabid(si_t *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 si_devpath(si_t *sih, char *path, int size); +/* Read variable with prepending the devpath to the name */ +extern char *si_getdevpathvar(si_t *sih, const char *name); +extern int si_getdevpathintvar(si_t *sih, const char *name); +extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const char *name); + + +extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); +extern uint8 si_pcieltrenable(si_t *sih, uint32 mask, uint32 val); +extern uint8 si_pcieobffenable(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcieltr_reg(si_t *sih, uint32 reg, uint32 mask, uint32 val); +extern uint32 si_pcieltrspacing_reg(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcieltrhysteresiscnt_reg(si_t *sih, uint32 mask, uint32 val); +extern void si_pcie_set_error_injection(si_t *sih, uint32 mode); +extern void si_pcie_set_L1substate(si_t *sih, uint32 substate); +extern uint32 si_pcie_get_L1substate(si_t *sih); +extern void si_war42780_clkreq(si_t *sih, bool clkreq); +extern void si_pci_down(si_t *sih); +extern void si_pci_up(si_t *sih); +extern void si_pci_sleep(si_t *sih); +extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); +extern void si_pcie_power_save_enable(si_t *sih, bool enable); +extern void si_pcie_extendL1timer(si_t *sih, bool extend); +extern int si_pci_fixcfg(si_t *sih); +extern void si_chippkg_set(si_t *sih, uint); + +extern void si_chipcontrl_btshd0_4331(si_t *sih, bool on); +extern void si_chipcontrl_restore(si_t *sih, uint32 val); +extern uint32 si_chipcontrl_read(si_t *sih); +extern void si_chipcontrl_epa4331(si_t *sih, bool on); +extern void si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl); +extern void si_chipcontrl_srom4360(si_t *sih, bool on); +/* Enable BT-COEX & Ex-PA for 4313 */ +extern void si_epa_4313war(si_t *sih); +extern void si_btc_enable_chipcontrol(si_t *sih); +/* BT/WL selection for 4313 bt combo >= P250 boards */ +extern void si_btcombo_p250_4313_war(si_t *sih); +extern void si_btcombo_43228_war(si_t *sih); +extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); +extern void si_pmu_synth_pwrsw_4313_war(si_t *sih); +extern uint si_pll_reset(si_t *sih); +/* === debug routines === */ + +extern bool si_taclear(si_t *sih, bool details); + + + +extern uint32 si_ccreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); +extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); +extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); +extern void si_pcie_set_request_size(si_t *sih, uint16 size); +extern uint16 si_pcie_get_request_size(si_t *sih); +extern void si_pcie_set_maxpayload_size(si_t *sih, uint16 size); +extern uint16 si_pcie_get_maxpayload_size(si_t *sih); +extern uint16 si_pcie_get_ssid(si_t *sih); +extern uint32 si_pcie_get_bar0(si_t *sih); +extern int si_pcie_configspace_cache(si_t *sih); +extern int si_pcie_configspace_restore(si_t *sih); +extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); + +char *si_getnvramflvar(si_t *sih, const char *name); + + +extern uint32 si_tcm_size(si_t *sih); +extern bool si_has_flops(si_t *sih); + +extern int si_set_sromctl(si_t *sih, uint32 value); +extern uint32 si_get_sromctl(si_t *sih); + +extern uint32 si_gci_direct(si_t *sih, uint offset, uint32 mask, uint32 val); +extern uint32 si_gci_indirect(si_t *sih, uint regidx, uint offset, uint32 mask, uint32 val); +extern uint32 si_gci_output(si_t *sih, uint reg, uint32 mask, uint32 val); +extern uint32 si_gci_input(si_t *sih, uint reg); +extern uint32 si_gci_int_enable(si_t *sih, bool enable); +extern void si_gci_reset(si_t *sih); +extern void si_ercx_init(si_t *sih); +extern void si_wci2_init(si_t *sih, uint baudrate); +extern void si_gci_seci_init(si_t *sih); +extern void si_gci_set_functionsel(si_t *sih, uint32 pin, uint8 fnsel); +extern uint8 si_gci_get_chipctrlreg_idx(uint32 pin, uint32 *regidx, uint32 *pos); +extern uint32 si_gci_chipcontrol(si_t *sih, uint reg, uint32 mask, uint32 val); +extern uint32 si_gci_chipstatus(si_t *sih, uint reg); +extern uint16 si_cc_get_reg16(uint32 reg_offs); +extern uint32 si_cc_get_reg32(uint32 reg_offs); +extern uint32 si_cc_set_reg32(uint32 reg_offs, uint32 val); +extern uint32 si_gci_preinit_upd_indirect(uint32 regidx, uint32 setval, uint32 mask); +extern uint8 si_enable_device_wake(si_t *sih, uint8 *wake_status, uint8 *cur_status); + +#define CHIPCTRLREG1 0x1 +#define CHIPCTRLREG2 0x2 +#define CHIPCTRLREG3 0x3 +#define CHIPCTRLREG4 0x4 +#define CHIPCTRLREG5 0x5 +#define MINRESMASKREG 0x618 +#define MAXRESMASKREG 0x61c +#define CHIPCTRLADDR 0x650 +#define CHIPCTRLDATA 0x654 +#define RSRCTABLEADDR 0x620 +#define RSRCUPDWNTIME 0x628 +#define PMUREG_RESREQ_MASK 0x68c + +void si_update_masks(si_t *sih); +void si_force_islanding(si_t *sih, bool enable); +extern uint32 si_pmu_res_req_timer_clr(si_t *sih); +extern void si_pmu_rfldo(si_t *sih, bool on); +extern void si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 spert_val); +extern void si_pcie_ltr_war(si_t *sih); + +/* Macro to enable clock gating changes in different cores */ +#define MEM_CLK_GATE_BIT 5 +#define GCI_CLK_GATE_BIT 18 + +#define USBAPP_CLK_BIT 0 +#define PCIE_CLK_BIT 3 +#define ARMCR4_DBG_CLK_BIT 4 +#define SAMPLE_SYNC_CLK_BIT 17 +#define PCIE_TL_CLK_BIT 18 +#define HQ_REQ_BIT 24 +#define PLL_DIV2_BIT_START 9 +#define PLL_DIV2_MASK (0x37 << PLL_DIV2_BIT_START) +#define PLL_DIV2_DIS_OP (0x37 << PLL_DIV2_BIT_START) + +#endif /* _siutils_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/spid.h b/drivers/net/wireless/bcmdhd_bcm43455/include/spid.h new file mode 100644 index 000000000000..b5d7b675748d --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/spid.h @@ -0,0 +1,165 @@ +/* + * SPI device spec header file + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: spid.h 358377 2012-09-23 11:30:22Z $ + */ + +#ifndef _SPI_H +#define _SPI_H + +/* + * Brcm SPI Device Register Map. + * + */ + +typedef volatile struct { + uint8 config; /* 0x00, len, endian, clock, speed, polarity, wakeup */ + uint8 response_delay; /* 0x01, read response delay in bytes (corerev < 3) */ + uint8 status_enable; /* 0x02, status-enable, intr with status, response_delay + * function selection, command/data error check + */ + uint8 reset_bp; /* 0x03, reset on wlan/bt backplane reset (corerev >= 1) */ + uint16 intr_reg; /* 0x04, Intr status register */ + uint16 intr_en_reg; /* 0x06, Intr mask register */ + uint32 status_reg; /* 0x08, RO, Status bits of last spi transfer */ + uint16 f1_info_reg; /* 0x0c, RO, enabled, ready for data transfer, blocksize */ + uint16 f2_info_reg; /* 0x0e, RO, enabled, ready for data transfer, blocksize */ + uint16 f3_info_reg; /* 0x10, RO, enabled, ready for data transfer, blocksize */ + uint32 test_read; /* 0x14, RO 0xfeedbead signature */ + uint32 test_rw; /* 0x18, RW */ + uint8 resp_delay_f0; /* 0x1c, read resp delay bytes for F0 (corerev >= 3) */ + uint8 resp_delay_f1; /* 0x1d, read resp delay bytes for F1 (corerev >= 3) */ + uint8 resp_delay_f2; /* 0x1e, read resp delay bytes for F2 (corerev >= 3) */ + uint8 resp_delay_f3; /* 0x1f, read resp delay bytes for F3 (corerev >= 3) */ +} spi_regs_t; + +/* SPI device register offsets */ +#define SPID_CONFIG 0x00 +#define SPID_RESPONSE_DELAY 0x01 +#define SPID_STATUS_ENABLE 0x02 +#define SPID_RESET_BP 0x03 /* (corerev >= 1) */ +#define SPID_INTR_REG 0x04 /* 16 bits - Interrupt status */ +#define SPID_INTR_EN_REG 0x06 /* 16 bits - Interrupt mask */ +#define SPID_STATUS_REG 0x08 /* 32 bits */ +#define SPID_F1_INFO_REG 0x0C /* 16 bits */ +#define SPID_F2_INFO_REG 0x0E /* 16 bits */ +#define SPID_F3_INFO_REG 0x10 /* 16 bits */ +#define SPID_TEST_READ 0x14 /* 32 bits */ +#define SPID_TEST_RW 0x18 /* 32 bits */ +#define SPID_RESP_DELAY_F0 0x1c /* 8 bits (corerev >= 3) */ +#define SPID_RESP_DELAY_F1 0x1d /* 8 bits (corerev >= 3) */ +#define SPID_RESP_DELAY_F2 0x1e /* 8 bits (corerev >= 3) */ +#define SPID_RESP_DELAY_F3 0x1f /* 8 bits (corerev >= 3) */ + +/* Bit masks for SPID_CONFIG device register */ +#define WORD_LENGTH_32 0x1 /* 0/1 16/32 bit word length */ +#define ENDIAN_BIG 0x2 /* 0/1 Little/Big Endian */ +#define CLOCK_PHASE 0x4 /* 0/1 clock phase delay */ +#define CLOCK_POLARITY 0x8 /* 0/1 Idle state clock polarity is low/high */ +#define HIGH_SPEED_MODE 0x10 /* 1/0 High Speed mode / Normal mode */ +#define INTR_POLARITY 0x20 /* 1/0 Interrupt active polarity is high/low */ +#define WAKE_UP 0x80 /* 0/1 Wake-up command from Host to WLAN */ + +/* Bit mask for SPID_RESPONSE_DELAY device register */ +#define RESPONSE_DELAY_MASK 0xFF /* Configurable rd response delay in multiples of 8 bits */ + +/* Bit mask for SPID_STATUS_ENABLE device register */ +#define STATUS_ENABLE 0x1 /* 1/0 Status sent/not sent to host after read/write */ +#define INTR_WITH_STATUS 0x2 /* 0/1 Do-not / do-interrupt if status is sent */ +#define RESP_DELAY_ALL 0x4 /* Applicability of resp delay to F1 or all func's read */ +#define DWORD_PKT_LEN_EN 0x8 /* Packet len denoted in dwords instead of bytes */ +#define CMD_ERR_CHK_EN 0x20 /* Command error check enable */ +#define DATA_ERR_CHK_EN 0x40 /* Data error check enable */ + +/* Bit mask for SPID_RESET_BP device register */ +#define RESET_ON_WLAN_BP_RESET 0x4 /* enable reset for WLAN backplane */ +#define RESET_ON_BT_BP_RESET 0x8 /* enable reset for BT backplane */ +#define RESET_SPI 0x80 /* reset the above enabled logic */ + +/* Bit mask for SPID_INTR_REG device register */ +#define DATA_UNAVAILABLE 0x0001 /* Requested data not available; Clear by writing a "1" */ +#define F2_F3_FIFO_RD_UNDERFLOW 0x0002 +#define F2_F3_FIFO_WR_OVERFLOW 0x0004 +#define COMMAND_ERROR 0x0008 /* Cleared by writing 1 */ +#define DATA_ERROR 0x0010 /* Cleared by writing 1 */ +#define F2_PACKET_AVAILABLE 0x0020 +#define F3_PACKET_AVAILABLE 0x0040 +#define F1_OVERFLOW 0x0080 /* Due to last write. Bkplane has pending write requests */ +#define MISC_INTR0 0x0100 +#define MISC_INTR1 0x0200 +#define MISC_INTR2 0x0400 +#define MISC_INTR3 0x0800 +#define MISC_INTR4 0x1000 +#define F1_INTR 0x2000 +#define F2_INTR 0x4000 +#define F3_INTR 0x8000 + +/* Bit mask for 32bit SPID_STATUS_REG device register */ +#define STATUS_DATA_NOT_AVAILABLE 0x00000001 +#define STATUS_UNDERFLOW 0x00000002 +#define STATUS_OVERFLOW 0x00000004 +#define STATUS_F2_INTR 0x00000008 +#define STATUS_F3_INTR 0x00000010 +#define STATUS_F2_RX_READY 0x00000020 +#define STATUS_F3_RX_READY 0x00000040 +#define STATUS_HOST_CMD_DATA_ERR 0x00000080 +#define STATUS_F2_PKT_AVAILABLE 0x00000100 +#define STATUS_F2_PKT_LEN_MASK 0x000FFE00 +#define STATUS_F2_PKT_LEN_SHIFT 9 +#define STATUS_F3_PKT_AVAILABLE 0x00100000 +#define STATUS_F3_PKT_LEN_MASK 0xFFE00000 +#define STATUS_F3_PKT_LEN_SHIFT 21 + +/* Bit mask for 16 bits SPID_F1_INFO_REG device register */ +#define F1_ENABLED 0x0001 +#define F1_RDY_FOR_DATA_TRANSFER 0x0002 +#define F1_MAX_PKT_SIZE 0x01FC + +/* Bit mask for 16 bits SPID_F2_INFO_REG device register */ +#define F2_ENABLED 0x0001 +#define F2_RDY_FOR_DATA_TRANSFER 0x0002 +#define F2_MAX_PKT_SIZE 0x3FFC + +/* Bit mask for 16 bits SPID_F3_INFO_REG device register */ +#define F3_ENABLED 0x0001 +#define F3_RDY_FOR_DATA_TRANSFER 0x0002 +#define F3_MAX_PKT_SIZE 0x3FFC + +/* Bit mask for 32 bits SPID_TEST_READ device register read in 16bit LE mode */ +#define TEST_RO_DATA_32BIT_LE 0xFEEDBEAD + +/* Maximum number of I/O funcs */ +#define SPI_MAX_IOFUNCS 4 + +#define SPI_MAX_PKT_LEN (2048*4) + +/* Misc defines */ +#define SPI_FUNC_0 0 +#define SPI_FUNC_1 1 +#define SPI_FUNC_2 2 +#define SPI_FUNC_3 3 + +#define WAIT_F2RXFIFORDY 100 +#define WAIT_F2RXFIFORDY_DELAY 20 + +#endif /* _SPI_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h b/drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h new file mode 100644 index 000000000000..5ea40e739e31 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h @@ -0,0 +1,92 @@ +/* + * TRX image file header format. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: trxhdr.h 349211 2012-08-07 09:45:24Z $ + */ + +#ifndef _TRX_HDR_H +#define _TRX_HDR_H + +#include + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ +#define TRX_MAX_LEN 0x3B0000 /* Max length */ +#define TRX_NO_HEADER 1 /* Do not write TRX header */ +#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ +#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ +#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ +#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ +#define TRX_BOOTLOADER 0x40 /* the image is a bootloader */ + +#define TRX_V1 1 +#define TRX_V1_MAX_OFFSETS 3 /* V1: Max number of individual files */ + +#ifndef BCMTRXV2 +#define TRX_VERSION TRX_V1 /* Version 1 */ +#define TRX_MAX_OFFSET TRX_V1_MAX_OFFSETS +#endif + +/* BMAC Host driver/application like bcmdl need to support both Ver 1 as well as + * Ver 2 of trx header. To make it generic, trx_header is structure is modified + * as below where size of "offsets" field will vary as per the TRX version. + * Currently, BMAC host driver and bcmdl are modified to support TRXV2 as well. + * To make sure, other applications like "dhdl" which are yet to be enhanced to support + * TRXV2 are not broken, new macro and structure defintion take effect only when BCMTRXV2 + * is defined. + */ +struct trx_header { + uint32 magic; /* "HDR0" */ + uint32 len; /* Length of file including header */ + uint32 crc32; /* 32-bit CRC from flag_version to end of file */ + uint32 flag_version; /* 0:15 flags, 16:31 version */ +#ifndef BCMTRXV2 + uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ +#else + uint32 offsets[1]; /* Offsets of partitions from start of header */ +#endif +}; + +#ifdef BCMTRXV2 +#define TRX_VERSION TRX_V2 /* Version 2 */ +#define TRX_MAX_OFFSET TRX_V2_MAX_OFFSETS + +#define TRX_V2 2 +/* V2: Max number of individual files + * To support SDR signature + Config data region + */ +#define TRX_V2_MAX_OFFSETS 5 +#define SIZEOF_TRXHDR_V1 (sizeof(struct trx_header)+(TRX_V1_MAX_OFFSETS-1)*sizeof(uint32)) +#define SIZEOF_TRXHDR_V2 (sizeof(struct trx_header)+(TRX_V2_MAX_OFFSETS-1)*sizeof(uint32)) +#define TRX_VER(trx) (trx->flag_version>>16) +#define ISTRX_V1(trx) (TRX_VER(trx) == TRX_V1) +#define ISTRX_V2(trx) (TRX_VER(trx) == TRX_V2) +/* For V2, return size of V2 size: others, return V1 size */ +#define SIZEOF_TRX(trx) (ISTRX_V2(trx) ? SIZEOF_TRXHDR_V2: SIZEOF_TRXHDR_V1) +#else +#define SIZEOF_TRX(trx) (sizeof(struct trx_header)) +#endif /* BCMTRXV2 */ + +/* Compatibility */ +typedef struct trx_header TRXHDR, *PTRXHDR; + +#endif /* _TRX_HDR_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h new file mode 100644 index 000000000000..0222b8824c5f --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h @@ -0,0 +1,344 @@ +/* + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * $Id: typedefs.h 453696 2014-02-06 01:10:20Z $ + */ + +#ifndef _TYPEDEFS_H_ +#define _TYPEDEFS_H_ + +#ifdef SITE_TYPEDEFS + +/* + * Define SITE_TYPEDEFS in the compile to include a site-specific + * typedef file "site_typedefs.h". + * + * If SITE_TYPEDEFS is not defined, then the code section below makes + * inferences about the compile environment based on defined symbols and + * possibly compiler pragmas. + * + * Following these two sections is the Default Typedefs section. + * This section is only processed if USE_TYPEDEF_DEFAULTS is + * defined. This section has a default set of typedefs and a few + * preprocessor symbols (TRUE, FALSE, NULL, ...). + */ + +#include "site_typedefs.h" + +#else + +/* + * Infer the compile environment based on preprocessor symbols and pragmas. + * Override type definitions as needed, and include configuration-dependent + * header files to define types. + */ + +#ifdef __cplusplus + +#define TYPEDEF_BOOL +#ifndef FALSE +#define FALSE false +#endif +#ifndef TRUE +#define TRUE true +#endif + +#else /* ! __cplusplus */ + + +#endif /* ! __cplusplus */ + +#if defined(__LP64__) +#define TYPEDEF_UINTPTR +typedef unsigned long long int uintptr; +#endif + + + + + +#if defined(_NEED_SIZE_T_) +typedef long unsigned int size_t; +#endif + + + + + +#if defined(__sparc__) +#define TYPEDEF_ULONG +#endif + + +/* + * If this is either a Linux hybrid build or the per-port code of a hybrid build + * then use the Linux header files to get some of the typedefs. Otherwise, define + * them entirely in this file. We can't always define the types because we get + * a duplicate typedef error; there is no way to "undefine" a typedef. + * We know when it's per-port code because each file defines LINUX_PORT at the top. + */ +#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) +#define TYPEDEF_UINT +#ifndef TARGETENV_android +#define TYPEDEF_USHORT +#define TYPEDEF_ULONG +#endif /* TARGETENV_android */ +#ifdef __KERNEL__ +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) +#define TYPEDEF_BOOL +#endif /* >= 2.6.19 */ +/* special detection for 2.6.18-128.7.1.0.1.el5 */ +#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) +#include +#ifdef noinline_for_stack +#define TYPEDEF_BOOL +#endif +#endif /* == 2.6.18 */ +#endif /* __KERNEL__ */ +#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ + + + + +/* Do not support the (u)int64 types with strict ansi for GNU C */ +#if defined(__GNUC__) && defined(__STRICT_ANSI__) +#define TYPEDEF_INT64 +#define TYPEDEF_UINT64 +#endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */ + +/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode + * for signed or unsigned + */ +#if defined(__ICL) + +#define TYPEDEF_INT64 + +#if defined(__STDC__) +#define TYPEDEF_UINT64 +#endif + +#endif /* __ICL */ + +#if !defined(__DJGPP__) + +/* pick up ushort & uint from standard types.h */ +#if defined(__KERNEL__) + +/* See note above */ +#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) +#include /* sys/types.h and linux/types.h are oil and water */ +#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ + +#else + + +#include + +#endif /* linux && __KERNEL__ */ + +#endif + + + +/* use the default typedefs in the next section of this file */ +#define USE_TYPEDEF_DEFAULTS + +#endif /* SITE_TYPEDEFS */ + + +/* + * Default Typedefs + */ + +#ifdef USE_TYPEDEF_DEFAULTS +#undef USE_TYPEDEF_DEFAULTS + +#ifndef TYPEDEF_BOOL +typedef /* @abstract@ */ unsigned char bool; +#endif + +/* define uchar, ushort, uint, ulong */ + +#ifndef TYPEDEF_UCHAR +typedef unsigned char uchar; +#endif + +#ifndef TYPEDEF_USHORT +typedef unsigned short ushort; +#endif + +#ifndef TYPEDEF_UINT +typedef unsigned int uint; +#endif + +#ifndef TYPEDEF_ULONG +typedef unsigned long ulong; +#endif + +/* define [u]int8/16/32/64, uintptr */ + +#ifndef TYPEDEF_UINT8 +typedef unsigned char uint8; +#endif + +#ifndef TYPEDEF_UINT16 +typedef unsigned short uint16; +#endif + +#ifndef TYPEDEF_UINT32 +typedef unsigned int uint32; +#endif + +#ifndef TYPEDEF_UINT64 +typedef unsigned long long uint64; +#endif + +#ifndef TYPEDEF_UINTPTR +typedef unsigned int uintptr; +#endif + +#ifndef TYPEDEF_INT8 +typedef signed char int8; +#endif + +#ifndef TYPEDEF_INT16 +typedef signed short int16; +#endif + +#ifndef TYPEDEF_INT32 +typedef signed int int32; +#endif + +#ifndef TYPEDEF_INT64 +typedef signed long long int64; +#endif + +/* define float32/64, float_t */ + +#ifndef TYPEDEF_FLOAT32 +typedef float float32; +#endif + +#ifndef TYPEDEF_FLOAT64 +typedef double float64; +#endif + +/* + * abstracted floating point type allows for compile time selection of + * single or double precision arithmetic. Compiling with -DFLOAT32 + * selects single precision; the default is double precision. + */ + +#ifndef TYPEDEF_FLOAT_T + +#if defined(FLOAT32) +typedef float32 float_t; +#else /* default to double precision floating point */ +typedef float64 float_t; +#endif + +#endif /* TYPEDEF_FLOAT_T */ + +/* define macro values */ + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 /* TRUE */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef OFF +#define OFF 0 +#endif + +#ifndef ON +#define ON 1 /* ON = 1 */ +#endif + +#define AUTO (-1) /* Auto = -1 */ + +/* define PTRSZ, INLINE */ + +#ifndef PTRSZ +#define PTRSZ sizeof(char*) +#endif + + +/* Detect compiler type. */ +#if defined(__GNUC__) || defined(__lint) + #define BWL_COMPILER_GNU +#elif defined(__CC_ARM) && __CC_ARM + #define BWL_COMPILER_ARMCC +#else + #error "Unknown compiler!" +#endif + + +#ifndef INLINE + #if defined(BWL_COMPILER_MICROSOFT) + #define INLINE __inline + #elif defined(BWL_COMPILER_GNU) + #define INLINE __inline__ + #elif defined(BWL_COMPILER_ARMCC) + #define INLINE __inline + #else + #define INLINE + #endif +#endif /* INLINE */ + +#undef TYPEDEF_BOOL +#undef TYPEDEF_UCHAR +#undef TYPEDEF_USHORT +#undef TYPEDEF_UINT +#undef TYPEDEF_ULONG +#undef TYPEDEF_UINT8 +#undef TYPEDEF_UINT16 +#undef TYPEDEF_UINT32 +#undef TYPEDEF_UINT64 +#undef TYPEDEF_UINTPTR +#undef TYPEDEF_INT8 +#undef TYPEDEF_INT16 +#undef TYPEDEF_INT32 +#undef TYPEDEF_INT64 +#undef TYPEDEF_FLOAT32 +#undef TYPEDEF_FLOAT64 +#undef TYPEDEF_FLOAT_T + +#endif /* USE_TYPEDEF_DEFAULTS */ + +/* Suppress unused parameter warning */ +#define UNUSED_PARAMETER(x) (void)(x) + +/* Avoid warning for discarded const or volatile qualifier in special cases (-Wcast-qual) */ +#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) + +/* + * Including the bcmdefs.h here, to make sure everyone including typedefs.h + * gets this automatically +*/ +#include +#endif /* _TYPEDEFS_H_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h new file mode 100644 index 000000000000..90624b6a5b48 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h @@ -0,0 +1,304 @@ +/* +* Copyright (C) 1999-2017, Broadcom Corporation +* +* Unless you and Broadcom execute a separate written software license +* agreement governing use of this software, this software is licensed to you +* under the terms of the GNU General Public License version 2 (the "GPL"), +* available at http://www.broadcom.com/licenses/GPLv2.php, with the +* following added to such license: +* +* As a special exception, the copyright holders of this software give you +* permission to link this software with independent modules, and to copy and +* distribute the resulting executable under terms of your choice, provided that +* you also meet, for each linked independent module, the terms and conditions of +* the license of that module. An independent module is a module which is not +* derived from this software. The special exception does not apply to any +* modifications of the software. +* +* Notwithstanding the above, under no circumstances may you combine this +* software in any way with any other Broadcom software provided under a license +* other than the GPL, without Broadcom's express prior written consent. +* $Id: wlfc_proto.h 431159 2013-10-22 19:40:51Z $ +* +*/ +#ifndef __wlfc_proto_definitions_h__ +#define __wlfc_proto_definitions_h__ + + /* Use TLV to convey WLFC information. + --------------------------------------------------------------------------- + | Type | Len | value | Description + --------------------------------------------------------------------------- + | 1 | 1 | (handle) | MAC OPEN + --------------------------------------------------------------------------- + | 2 | 1 | (handle) | MAC CLOSE + --------------------------------------------------------------------------- + | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn + --------------------------------------------------------------------------- + | 4 | 4+ | see pkttag comments | TXSTATUS + | | | TX status & timestamps | Present only when pkt timestamp is enabled + --------------------------------------------------------------------------- + | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] + --------------------------------------------------------------------------- + | 6 | 8 | (handle, ifid, MAC) | MAC ADD + --------------------------------------------------------------------------- + | 7 | 8 | (handle, ifid, MAC) | MAC DEL + --------------------------------------------------------------------------- + | 8 | 1 | (rssi) | RSSI - RSSI value for the packet. + --------------------------------------------------------------------------- + | 9 | 1 | (interface ID) | Interface OPEN + --------------------------------------------------------------------------- + | 10 | 1 | (interface ID) | Interface CLOSE + --------------------------------------------------------------------------- + | 11 | 8 | fifo credit returns map | FIFO credits back to the host + | | | | + | | | | -------------------------------------- + | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim | + | | | | -------------------------------------- + | | | | + --------------------------------------------------------------------------- + | 12 | 2 | MAC handle, | Host provides a bitmap of pending + | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn. + | | | | [host->firmware] + --------------------------------------------------------------------------- + | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific + | | | | MAC destination. + --------------------------------------------------------------------------- + | 15 | 12 | (pkttag, timestamps) | Send TX timestamp at reception from host + --------------------------------------------------------------------------- + | 16 | 12 | (pkttag, timestamps) | Send WLAN RX timestamp along with RX frame + --------------------------------------------------------------------------- + | 255 | N/A | N/A | FILLER - This is a special type + | | | | that has no length or value. + | | | | Typically used for padding. + --------------------------------------------------------------------------- + */ + +#define WLFC_CTL_TYPE_MAC_OPEN 1 +#define WLFC_CTL_TYPE_MAC_CLOSE 2 +#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3 +#define WLFC_CTL_TYPE_TXSTATUS 4 +#define WLFC_CTL_TYPE_PKTTAG 5 + +#define WLFC_CTL_TYPE_MACDESC_ADD 6 +#define WLFC_CTL_TYPE_MACDESC_DEL 7 +#define WLFC_CTL_TYPE_RSSI 8 + +#define WLFC_CTL_TYPE_INTERFACE_OPEN 9 +#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 + +#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11 + +#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12 +#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 +#define WLFC_CTL_TYPE_HOST_REORDER_RXPKTS 14 + + +#define WLFC_CTL_TYPE_TX_ENTRY_STAMP 15 +#define WLFC_CTL_TYPE_RX_STAMP 16 + +#define WLFC_CTL_TYPE_TRANS_ID 18 +#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 + + +#define WLFC_CTL_TYPE_FILLER 255 + +#define WLFC_CTL_VALUE_LEN_MACDESC 8 /* handle, interface, MAC */ + +#define WLFC_CTL_VALUE_LEN_MAC 1 /* MAC-handle */ +#define WLFC_CTL_VALUE_LEN_RSSI 1 + +#define WLFC_CTL_VALUE_LEN_INTERFACE 1 +#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2 + +#define WLFC_CTL_VALUE_LEN_TXSTATUS 4 +#define WLFC_CTL_VALUE_LEN_PKTTAG 4 + +#define WLFC_CTL_VALUE_LEN_SEQ 2 + +/* enough space to host all 4 ACs, bc/mc and atim fifo credit */ +#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6 + +#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ +#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ + + +#define WLFC_PKTFLAG_PKTFROMHOST 0x01 +#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 + +#define WL_TXSTATUS_STATUS_MASK 0xff /* allow 8 bits */ +#define WL_TXSTATUS_STATUS_SHIFT 24 + +#define WL_TXSTATUS_SET_STATUS(x, status) ((x) = \ + ((x) & ~(WL_TXSTATUS_STATUS_MASK << WL_TXSTATUS_STATUS_SHIFT)) | \ + (((status) & WL_TXSTATUS_STATUS_MASK) << WL_TXSTATUS_STATUS_SHIFT)) +#define WL_TXSTATUS_GET_STATUS(x) (((x) >> WL_TXSTATUS_STATUS_SHIFT) & \ + WL_TXSTATUS_STATUS_MASK) + +#define WL_TXSTATUS_GENERATION_MASK 1 /* allow 1 bit */ +#define WL_TXSTATUS_GENERATION_SHIFT 31 + +#define WL_TXSTATUS_SET_GENERATION(x, gen) ((x) = \ + ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ + (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT)) + +#define WL_TXSTATUS_GET_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ + WL_TXSTATUS_GENERATION_MASK) + +#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ +#define WL_TXSTATUS_FLAGS_SHIFT 27 + +#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ + ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ + (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT)) +#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \ + WL_TXSTATUS_FLAGS_MASK) + +#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ +#define WL_TXSTATUS_FIFO_SHIFT 24 + +#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ + ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ + (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) +#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) + +#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ +#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ + ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) +#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) + +#define WL_TXSTATUS_HSLOT_MASK 0xffff /* allow 16 bits */ +#define WL_TXSTATUS_HSLOT_SHIFT 8 + +#define WL_TXSTATUS_SET_HSLOT(x, hslot) ((x) = \ + ((x) & ~(WL_TXSTATUS_HSLOT_MASK << WL_TXSTATUS_HSLOT_SHIFT)) | \ + (((hslot) & WL_TXSTATUS_HSLOT_MASK) << WL_TXSTATUS_HSLOT_SHIFT)) +#define WL_TXSTATUS_GET_HSLOT(x) (((x) >> WL_TXSTATUS_HSLOT_SHIFT)& \ + WL_TXSTATUS_HSLOT_MASK) + +#define WL_TXSTATUS_FREERUNCTR_MASK 0xff /* allow 8 bits */ + +#define WL_TXSTATUS_SET_FREERUNCTR(x, ctr) ((x) = \ + ((x) & ~(WL_TXSTATUS_FREERUNCTR_MASK)) | \ + ((ctr) & WL_TXSTATUS_FREERUNCTR_MASK)) +#define WL_TXSTATUS_GET_FREERUNCTR(x) ((x)& WL_TXSTATUS_FREERUNCTR_MASK) + +#define WL_SEQ_FROMFW_MASK 0x1 /* allow 1 bit */ +#define WL_SEQ_FROMFW_SHIFT 13 +#define WL_SEQ_SET_FROMFW(x, val) ((x) = \ + ((x) & ~(WL_SEQ_FROMFW_MASK << WL_SEQ_FROMFW_SHIFT)) | \ + (((val) & WL_SEQ_FROMFW_MASK) << WL_SEQ_FROMFW_SHIFT)) +#define WL_SEQ_GET_FROMFW(x) (((x) >> WL_SEQ_FROMFW_SHIFT) & \ + WL_SEQ_FROMFW_MASK) + +#define WL_SEQ_FROMDRV_MASK 0x1 /* allow 1 bit */ +#define WL_SEQ_FROMDRV_SHIFT 12 +#define WL_SEQ_SET_FROMDRV(x, val) ((x) = \ + ((x) & ~(WL_SEQ_FROMDRV_MASK << WL_SEQ_FROMDRV_SHIFT)) | \ + (((val) & WL_SEQ_FROMDRV_MASK) << WL_SEQ_FROMDRV_SHIFT)) +#define WL_SEQ_GET_FROMDRV(x) (((x) >> WL_SEQ_FROMDRV_SHIFT) & \ + WL_SEQ_FROMDRV_MASK) + +#define WL_SEQ_NUM_MASK 0xfff /* allow 12 bit */ +#define WL_SEQ_NUM_SHIFT 0 +#define WL_SEQ_SET_NUM(x, val) ((x) = \ + ((x) & ~(WL_SEQ_NUM_MASK << WL_SEQ_NUM_SHIFT)) | \ + (((val) & WL_SEQ_NUM_MASK) << WL_SEQ_NUM_SHIFT)) +#define WL_SEQ_GET_NUM(x) (((x) >> WL_SEQ_NUM_SHIFT) & \ + WL_SEQ_NUM_MASK) + +/* 32 STA should be enough??, 6 bits; Must be power of 2 */ +#define WLFC_MAC_DESC_TABLE_SIZE 32 +#define WLFC_MAX_IFNUM 16 +#define WLFC_MAC_DESC_ID_INVALID 0xff + +/* b[7:5] -reuse guard, b[4:0] -value */ +#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f) + +#define WLFC_PKTFLAG_SET_PKTREQUESTED(x) (x) |= \ + (WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) + +#define WLFC_PKTFLAG_CLR_PKTREQUESTED(x) (x) &= \ + ~(WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) + + +#define WLFC_MAX_PENDING_DATALEN 120 + +/* host is free to discard the packet */ +#define WLFC_CTL_PKTFLAG_DISCARD 0 +/* D11 suppressed a packet */ +#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1 +/* WL firmware suppressed a packet because MAC is + already in PSMode (short time window) +*/ +#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2 +/* Firmware tossed this packet */ +#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3 +/* Firmware tossed after retries */ +#define WLFC_CTL_PKTFLAG_DISCARD_NOACK 4 + +#define WLFC_D11_STATUS_INTERPRET(txs) \ + (((txs)->status.suppr_ind != TX_STATUS_SUPR_NONE) ? \ + WLFC_CTL_PKTFLAG_D11SUPPRESS : \ + ((txs)->status.was_acked ? \ + WLFC_CTL_PKTFLAG_DISCARD : WLFC_CTL_PKTFLAG_DISCARD_NOACK)) + +#ifdef PROP_TXSTATUS_DEBUG +#define WLFC_DBGMESG(x) printf x +/* wlfc-breadcrumb */ +#define WLFC_BREADCRUMB(x) do {if ((x) == NULL) \ + {printf("WLFC: %s():%d:caller:%p\n", \ + __FUNCTION__, __LINE__, __builtin_return_address(0));}} while (0) +#define WLFC_PRINTMAC(banner, ea) do {printf("%s MAC: [%02x:%02x:%02x:%02x:%02x:%02x]\n", \ + banner, ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); } while (0) +#define WLFC_WHEREIS(s) printf("WLFC: at %s():%d, %s\n", __FUNCTION__, __LINE__, (s)) +#else +#define WLFC_DBGMESG(x) +#define WLFC_BREADCRUMB(x) +#define WLFC_PRINTMAC(banner, ea) +#define WLFC_WHEREIS(s) +#endif + +/* AMPDU host reorder packet flags */ +#define WLHOST_REORDERDATA_MAXFLOWS 256 +#define WLHOST_REORDERDATA_LEN 10 +#define WLHOST_REORDERDATA_TOTLEN (WLHOST_REORDERDATA_LEN + 1 + 1) /* +tag +len */ + +#define WLHOST_REORDERDATA_FLOWID_OFFSET 0 +#define WLHOST_REORDERDATA_MAXIDX_OFFSET 2 +#define WLHOST_REORDERDATA_FLAGS_OFFSET 4 +#define WLHOST_REORDERDATA_CURIDX_OFFSET 6 +#define WLHOST_REORDERDATA_EXPIDX_OFFSET 8 + +#define WLHOST_REORDERDATA_DEL_FLOW 0x01 +#define WLHOST_REORDERDATA_FLUSH_ALL 0x02 +#define WLHOST_REORDERDATA_CURIDX_VALID 0x04 +#define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 +#define WLHOST_REORDERDATA_NEW_HOLE 0x10 + +/* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ +#define WLFC_CTL_TRANS_ID_LEN 6 +#define WLFC_TYPE_TRANS_ID_LEN 6 + +#define WLFC_MODE_HANGER 1 /* use hanger */ +#define WLFC_MODE_AFQ 2 /* use afq */ +#define WLFC_IS_OLD_DEF(x) ((x & 1) || (x & 2)) + +#define WLFC_MODE_AFQ_SHIFT 2 /* afq bit */ +#define WLFC_SET_AFQ(x, val) ((x) = \ + ((x) & ~(1 << WLFC_MODE_AFQ_SHIFT)) | \ + (((val) & 1) << WLFC_MODE_AFQ_SHIFT)) +#define WLFC_GET_AFQ(x) (((x) >> WLFC_MODE_AFQ_SHIFT) & 1) + +#define WLFC_MODE_REUSESEQ_SHIFT 3 /* seq reuse bit */ +#define WLFC_SET_REUSESEQ(x, val) ((x) = \ + ((x) & ~(1 << WLFC_MODE_REUSESEQ_SHIFT)) | \ + (((val) & 1) << WLFC_MODE_REUSESEQ_SHIFT)) +#define WLFC_GET_REUSESEQ(x) (((x) >> WLFC_MODE_REUSESEQ_SHIFT) & 1) + +#define WLFC_MODE_REORDERSUPP_SHIFT 4 /* host reorder suppress pkt bit */ +#define WLFC_SET_REORDERSUPP(x, val) ((x) = \ + ((x) & ~(1 << WLFC_MODE_REORDERSUPP_SHIFT)) | \ + (((val) & 1) << WLFC_MODE_REORDERSUPP_SHIFT)) +#define WLFC_GET_REORDERSUPP(x) (((x) >> WLFC_MODE_REORDERSUPP_SHIFT) & 1) + +#endif /* __wlfc_proto_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h new file mode 100644 index 000000000000..df9eb598f902 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h @@ -0,0 +1,5858 @@ +/* + * Custom OID/ioctl definitions for + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wlioctl.h 598402 2015-11-09 13:36:35Z $ + */ + +#ifndef _wlioctl_h_ +#define _wlioctl_h_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + + +#ifndef INTF_NAME_SIZ +#define INTF_NAME_SIZ 16 +#endif + +/* Used to send ioctls over the transport pipe */ +typedef struct remote_ioctl { + cdc_ioctl_t msg; + uint32 data_len; + char intf_name[INTF_NAME_SIZ]; +} rem_ioctl_t; +#define REMOTE_SIZE sizeof(rem_ioctl_t) + +typedef struct { + uint32 num; + chanspec_t list[1]; +} chanspec_list_t; + +/* association decision information */ +typedef struct { + bool assoc_approved; /* (re)association approved */ + uint16 reject_reason; /* reason code for rejecting association */ + struct ether_addr da; + int64 sys_time; /* current system time */ +} assoc_decision_t; + +#define ACTION_FRAME_SIZE 1800 + +typedef struct wl_action_frame { + struct ether_addr da; + uint16 len; + uint32 packetId; + uint8 data[ACTION_FRAME_SIZE]; +} wl_action_frame_t; + +#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) + +typedef struct ssid_info +{ + uint8 ssid_len; /* the length of SSID */ + uint8 ssid[32]; /* SSID string */ +} ssid_info_t; + +typedef struct wl_af_params { + uint32 channel; + int32 dwell_time; + struct ether_addr BSSID; + wl_action_frame_t action_frame; +} wl_af_params_t; + +#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) + +#define MFP_TEST_FLAG_NORMAL 0 +#define MFP_TEST_FLAG_ANY_KEY 1 +typedef struct wl_sa_query { + uint32 flag; + uint8 action; + uint16 id; + struct ether_addr da; +} wl_sa_query_t; + +/* require default structure packing */ +#define BWL_DEFAULT_PACKING +#include + + + +/* Legacy structure to help keep backward compatible wl tool and tray app */ + +#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ + +typedef struct wl_bss_info_107 { + uint32 version; /* version field */ + uint32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; /* # rates in this set */ + uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + uint8 channel; /* Channel no. */ + uint16 atim_window; /* units are Kusec */ + uint8 dtim_period; /* DTIM period */ + int16 RSSI; /* receive signal strength (in dBm) */ + int8 phy_noise; /* noise (in dBm) */ + uint32 ie_length; /* byte length of Information Elements */ + /* variable length Information Elements */ +} wl_bss_info_107_t; + +/* + * Per-BSS information structure. + */ + +#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */ + +/* BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in wl_scan_results_t) + */ +typedef struct wl_bss_info_108 { + uint32 version; /* version field */ + uint32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; /* # rates in this set */ + uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + chanspec_t chanspec; /* chanspec for bss */ + uint16 atim_window; /* units are Kusec */ + uint8 dtim_period; /* DTIM period */ + int16 RSSI; /* receive signal strength (in dBm) */ + int8 phy_noise; /* noise (in dBm) */ + + uint8 n_cap; /* BSS is 802.11N Capable */ + uint32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ + uint8 ctl_ch; /* 802.11N BSS control channel number */ + uint32 reserved32[1]; /* Reserved for expansion of BSS properties */ + uint8 flags; /* flags */ + uint8 reserved[3]; /* Reserved for expansion of BSS properties */ + uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + + uint16 ie_offset; /* offset at which IEs start, from beginning */ + uint32 ie_length; /* byte length of Information Elements */ + /* Add new fields here */ + /* variable length Information Elements */ +} wl_bss_info_108_t; + +#define WL_BSS_INFO_VERSION 109 /* current version of wl_bss_info struct */ + +/* BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in wl_scan_results_t) + */ +typedef struct wl_bss_info { + uint32 version; /* version field */ + uint32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; /* # rates in this set */ + uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + chanspec_t chanspec; /* chanspec for bss */ + uint16 atim_window; /* units are Kusec */ + uint8 dtim_period; /* DTIM period */ + int16 RSSI; /* receive signal strength (in dBm) */ + int8 phy_noise; /* noise (in dBm) */ + + uint8 n_cap; /* BSS is 802.11N Capable */ + uint32 nbss_cap; /* 802.11N+AC BSS Capabilities */ + uint8 ctl_ch; /* 802.11N BSS control channel number */ + uint8 padding1[3]; /* explicit struct alignment padding */ + uint16 vht_rxmcsmap; /* VHT rx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ + uint16 vht_txmcsmap; /* VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ + uint8 flags; /* flags */ + uint8 vht_cap; /* BSS is vht capable */ + uint8 reserved[2]; /* Reserved for expansion of BSS properties */ + uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + + uint16 ie_offset; /* offset at which IEs start, from beginning */ + uint32 ie_length; /* byte length of Information Elements */ + int16 SNR; /* average SNR of during frame reception */ + /* Add new fields here */ + /* variable length Information Elements */ +} wl_bss_info_t; + +#define WL_GSCAN_BSS_INFO_VERSION 1 /* current version of wl_gscan_bss_info struct */ +#define WL_GSCAN_INFO_FIXED_FIELD_SIZE (sizeof(wl_gscan_bss_info_t) - sizeof(wl_bss_info_t)) + +typedef struct wl_gscan_bss_info { + uint32 timestamp[2]; + wl_bss_info_t info; + /* variable length Information Elements */ +} wl_gscan_bss_info_t; + + +typedef struct wl_bsscfg { + uint32 bsscfg_idx; + uint32 wsec; + uint32 WPA_auth; + uint32 wsec_index; + uint32 associated; + uint32 BSS; + uint32 phytest_on; + struct ether_addr prev_BSSID; + struct ether_addr BSSID; + uint32 targetbss_wpa2_flags; + uint32 assoc_type; + uint32 assoc_state; +} wl_bsscfg_t; + +typedef struct wl_if_add { + uint32 bsscfg_flags; + uint32 if_flags; + uint32 ap; + struct ether_addr mac_addr; +} wl_if_add_t; + +typedef struct wl_bss_config { + uint32 atim_window; + uint32 beacon_period; + uint32 chanspec; +} wl_bss_config_t; + +#define WL_BSS_USER_RADAR_CHAN_SELECT 0x1 /* User application will randomly select + * radar channel. + */ + +#define DLOAD_HANDLER_VER 1 /* Downloader version */ +#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ +#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ + +#define DL_CRC_NOT_INUSE 0x0001 + +/* generic download types & flags */ +enum { + DL_TYPE_UCODE = 1, + DL_TYPE_CLM = 2 +}; + +/* ucode type values */ +enum { + UCODE_FW, + INIT_VALS, + BS_INIT_VALS +}; + +struct wl_dload_data { + uint16 flag; + uint16 dload_type; + uint32 len; + uint32 crc; + uint8 data[1]; +}; +typedef struct wl_dload_data wl_dload_data_t; + +struct wl_ucode_info { + uint32 ucode_type; + uint32 num_chunks; + uint32 chunk_len; + uint32 chunk_num; + uint8 data_chunk[1]; +}; +typedef struct wl_ucode_info wl_ucode_info_t; + +struct wl_clm_dload_info { + uint32 ds_id; + uint32 clm_total_len; + uint32 num_chunks; + uint32 chunk_len; + uint32 chunk_offset; + uint8 data_chunk[1]; +}; +typedef struct wl_clm_dload_info wl_clm_dload_info_t; + +typedef struct wlc_ssid { + uint32 SSID_len; + uchar SSID[DOT11_MAX_SSID_LEN]; +} wlc_ssid_t; + +typedef struct wlc_ssid_ext { + bool hidden; + uint16 flags; + uint8 SSID_len; + int8 rssi_thresh; + uchar SSID[DOT11_MAX_SSID_LEN]; +} wlc_ssid_ext_t; + + +#define MAX_PREFERRED_AP_NUM 5 +typedef struct wlc_fastssidinfo { + uint32 SSID_channel[MAX_PREFERRED_AP_NUM]; + wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM]; +} wlc_fastssidinfo_t; + +typedef BWL_PRE_PACKED_STRUCT struct wnm_url { + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT wnm_url_t; + +typedef struct chan_scandata { + uint8 txpower; + uint8 pad; + chanspec_t channel; /* Channel num, bw, ctrl_sb and band */ + uint32 channel_mintime; + uint32 channel_maxtime; +} chan_scandata_t; + +typedef enum wl_scan_type { + EXTDSCAN_FOREGROUND_SCAN, + EXTDSCAN_BACKGROUND_SCAN, + EXTDSCAN_FORCEDBACKGROUND_SCAN +} wl_scan_type_t; + +#define WLC_EXTDSCAN_MAX_SSID 5 + +typedef struct wl_extdscan_params { + int8 nprobes; /* 0, passive, otherwise active */ + int8 split_scan; /* split scan */ + int8 band; /* band */ + int8 pad; + wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /* ssid list */ + uint32 tx_rate; /* in 500ksec units */ + wl_scan_type_t scan_type; /* enum */ + int32 channel_num; + chan_scandata_t channel_list[1]; /* list of chandata structs */ +} wl_extdscan_params_t; + +#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) + +#define WL_SCAN_PARAMS_SSID_MAX 10 + +typedef struct wl_scan_params { + wlc_ssid_t ssid; /* default: {0, ""} */ + struct ether_addr bssid; /* default: bcast */ + int8 bss_type; /* default: any, + * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT + */ + uint8 scan_type; /* flags, 0 use default */ + int32 nprobes; /* -1 use default, number of probes per channel */ + int32 active_time; /* -1 use default, dwell time per channel for + * active scanning + */ + int32 passive_time; /* -1 use default, dwell time per channel + * for passive scanning + */ + int32 home_time; /* -1 use default, dwell time for the home channel + * between channel scans + */ + int32 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 wlc_ssid_t array that + * follows channel_list, aligned for int32 (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 + */ + uint16 channel_list[1]; /* list of chanspecs */ +} wl_scan_params_t; + +/* size of wl_scan_params not including variable length array */ +#define WL_SCAN_PARAMS_FIXED_SIZE 64 + +#define ISCAN_REQ_VERSION 1 + +/* incremental scan struct */ +typedef struct wl_iscan_params { + uint32 version; + uint16 action; + uint16 scan_duration; + wl_scan_params_t params; +} wl_iscan_params_t; + +/* 3 fields + size of wl_scan_params, not including variable length array */ +#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) + +typedef struct wl_scan_results { + uint32 buflen; + uint32 version; + uint32 count; + wl_bss_info_t bss_info[1]; +} wl_scan_results_t; + +/* size of wl_scan_results not including variable length array */ +#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) + +/* Used in EXT_STA */ +#define DNGL_RXCTXT_SIZE 45 + + +#define ESCAN_REQ_VERSION 1 + +typedef struct wl_escan_params { + uint32 version; + uint16 action; + uint16 sync_id; + wl_scan_params_t params; +} wl_escan_params_t; + +#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) + +typedef struct wl_escan_result { + uint32 buflen; + uint32 version; + uint16 sync_id; + uint16 bss_count; + wl_bss_info_t bss_info[1]; +} wl_escan_result_t; + +#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) + +typedef struct wl_gscan_result { + uint32 buflen; + uint32 version; + wl_gscan_bss_info_t bss_info[1]; +} wl_gscan_result_t; + +#define WL_GSCAN_RESULTS_FIXED_SIZE (sizeof(wl_gscan_result_t) - sizeof(wl_gscan_bss_info_t)) + +/* incremental scan results struct */ +typedef struct wl_iscan_results { + uint32 status; + wl_scan_results_t results; +} wl_iscan_results_t; + +/* size of wl_iscan_results not including variable length array */ +#define WL_ISCAN_RESULTS_FIXED_SIZE \ + (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) + +#define SCANOL_PARAMS_VERSION 1 + +typedef struct scanol_params { + uint32 version; + uint32 flags; /* offload scanning flags */ + int32 active_time; /* -1 use default, dwell time per channel for active scanning */ + int32 passive_time; /* -1 use default, dwell time per channel for passive scanning */ + int32 idle_rest_time; /* -1 use default, time idle between scan cycle */ + int32 idle_rest_time_multiplier; + int32 active_rest_time; + int32 active_rest_time_multiplier; + int32 scan_cycle_idle_rest_time; + int32 scan_cycle_idle_rest_multiplier; + int32 scan_cycle_active_rest_time; + int32 scan_cycle_active_rest_multiplier; + int32 max_rest_time; + int32 max_scan_cycles; + int32 nprobes; /* -1 use default, number of probes per channel */ + int32 scan_start_delay; + uint32 nchannels; + uint32 ssid_count; + wlc_ssid_t ssidlist[1]; +} scanol_params_t; + +typedef struct wl_probe_params { + wlc_ssid_t ssid; + struct ether_addr bssid; + struct ether_addr mac; +} wl_probe_params_t; + +#define WL_MAXRATES_IN_SET 16 /* max # of rates in a rateset */ +typedef struct wl_rateset { + uint32 count; /* # rates in this set */ + uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ +} wl_rateset_t; + +typedef struct wl_rateset_args { + uint32 count; /* # rates in this set */ + uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ + uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ + uint16 vht_mcs[VHT_CAP_MCS_MAP_NSS_MAX]; /* supported mcs index bit map per nss */ +} wl_rateset_args_t; + +#define TXBF_RATE_MCS_ALL 4 +#define TXBF_RATE_VHT_ALL 4 +#define TXBF_RATE_OFDM_ALL 8 + +typedef struct wl_txbf_rateset { + uint8 txbf_rate_mcs[TXBF_RATE_MCS_ALL]; /* one for each stream */ + uint8 txbf_rate_mcs_bcm[TXBF_RATE_MCS_ALL]; /* one for each stream */ + uint16 txbf_rate_vht[TXBF_RATE_VHT_ALL]; /* one for each stream */ + uint16 txbf_rate_vht_bcm[TXBF_RATE_VHT_ALL]; /* one for each stream */ + uint8 txbf_rate_ofdm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ + uint8 txbf_rate_ofdm_bcm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ + uint8 txbf_rate_ofdm_cnt; + uint8 txbf_rate_ofdm_cnt_bcm; +} wl_txbf_rateset_t; + +#define OFDM_RATE_MASK 0x0000007f +typedef uint8 ofdm_rates_t; + +typedef struct wl_rates_info { + wl_rateset_t rs_tgt; + uint32 phy_type; + int32 bandtype; + uint8 cck_only; + uint8 rate_mask; + uint8 mcsallow; + uint8 bw; + uint8 txstreams; +} wl_rates_info_t; + +/* uint32 list */ +typedef struct wl_uint32_list { + /* in - # of elements, out - # of entries */ + uint32 count; + /* variable length uint32 list */ + uint32 element[1]; +} wl_uint32_list_t; + +/* used for association with a specific BSSID and chanspec list */ +typedef struct wl_assoc_params { + struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */ + uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, + * otherwise count of chanspecs in chanspec_list + * AND paired bssids following chanspec_list + * also, chanspec_num has to be set to zero + * for bssid list to be used + */ + int32 chanspec_num; /* 0: all available channels, + * otherwise count of chanspecs in chanspec_list + */ + chanspec_t chanspec_list[1]; /* list of chanspecs */ +} wl_assoc_params_t; + +#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) + +/* used for reassociation/roam to a specific BSSID and channel */ +typedef wl_assoc_params_t wl_reassoc_params_t; +#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE + +/* used for association to a specific BSSID and channel */ +typedef wl_assoc_params_t wl_join_assoc_params_t; +#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE + +/* used for join with or without a specific bssid and channel list */ +typedef struct wl_join_params { + wlc_ssid_t ssid; + wl_assoc_params_t params; /* optional field, but it must include the fixed portion + * of the wl_assoc_params_t struct when it does present. + */ +} wl_join_params_t; + +typedef struct wlc_roam_exp_params { + int8 a_band_boost_threshold; + int8 a_band_penalty_threshold; + uint8 a_band_boost_factor; + uint8 a_band_penalty_factor; + uint8 cur_bssid_boost; + int8 alert_roam_trigger_threshold; + uint16 a_band_max_boost; +} wlc_roam_exp_params_t; + +#define ROAM_EXP_CFG_VERSION 1 +#define ROAM_EXP_ENABLE_FLAG (1 << 0) +#define ROAM_EXP_CFG_PRESENT (1 << 1) +typedef struct wl_roam_exp_cfg { + uint8 version; + uint8 flags; + uint16 reserved; + wlc_roam_exp_params_t params; +} wl_roam_exp_cfg_t; + +typedef struct wl_bssid_pref_list { + struct ether_addr bssid; + /* Add this to modify rssi */ + int8 rssi_factor; + int8 flags; +} wl_bssid_pref_list_t; + +#define BSSID_PREF_LIST_VERSION 1 +#define ROAM_EXP_CLEAR_BSSID_PREF (1 << 0) +typedef struct wl_bssid_pref_cfg { + uint8 version; + uint8 flags; + uint16 count; + wl_bssid_pref_list_t bssids[1]; +} wl_bssid_pref_cfg_t; + +#define SSID_WHITELIST_VERSION 1 +#define ROAM_EXP_CLEAR_SSID_WHITELIST (1 << 0) +/* Roam SSID whitelist, ssids in this list are ok to */ +/* be considered as targets to join when considering a roam */ +typedef struct wl_ssid_whitelist { + uint8 version; + uint8 flags; + uint8 ssid_count; + uint8 reserved; + wlc_ssid_t ssids[1]; +} wl_ssid_whitelist_t; + +#define ROAM_EXP_EVENT_VERSION 1 +typedef struct wl_roam_exp_event { + uint8 version; + uint8 flags; + uint16 reserved; + wlc_ssid_t cur_ssid; +} wl_roam_exp_event_t; + +#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \ + WL_ASSOC_PARAMS_FIXED_SIZE) +/* scan params for extended join */ +typedef struct wl_join_scan_params { + uint8 scan_type; /* 0 use default, active or passive scan */ + int32 nprobes; /* -1 use default, number of probes per channel */ + int32 active_time; /* -1 use default, dwell time per channel for + * active scanning + */ + int32 passive_time; /* -1 use default, dwell time per channel + * for passive scanning + */ + int32 home_time; /* -1 use default, dwell time for the home channel + * between channel scans + */ +} wl_join_scan_params_t; + +/* extended join params */ +typedef struct wl_extjoin_params { + wlc_ssid_t ssid; /* {0, ""}: wildcard scan */ + wl_join_scan_params_t scan; + wl_join_assoc_params_t assoc; /* optional field, but it must include the fixed portion + * of the wl_join_assoc_params_t struct when it does + * present. + */ +} wl_extjoin_params_t; +#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \ + WL_JOIN_ASSOC_PARAMS_FIXED_SIZE) + +#define ANT_SELCFG_MAX 4 /* max number of antenna configurations */ +#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ +typedef struct { + uint8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ + uint8 num_antcfg; /* number of available antenna configurations */ +} wlc_antselcfg_t; + +typedef struct { + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 timestamp; /* second timestamp */ +} cca_congest_t; + +typedef struct { + chanspec_t chanspec; /* Which channel? */ + uint8 num_secs; /* How many secs worth of data */ + cca_congest_t secs[1]; /* Data */ +} cca_congest_channel_req_t; + +/* interference sources */ +enum interference_source { + ITFR_NONE = 0, /* interference */ + ITFR_PHONE, /* wireless phone */ + ITFR_VIDEO_CAMERA, /* wireless video camera */ + ITFR_MICROWAVE_OVEN, /* microwave oven */ + ITFR_BABY_MONITOR, /* wireless baby monitor */ + ITFR_BLUETOOTH, /* bluetooth */ + ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /* wireless camera or baby monitor */ + ITFR_BLUETOOTH_OR_BABY_MONITOR, /* bluetooth or baby monitor */ + ITFR_VIDEO_CAMERA_OR_PHONE, /* video camera or phone */ + ITFR_UNIDENTIFIED /* interference from unidentified source */ +}; + +/* structure for interference source report */ +typedef struct { + uint32 flags; /* flags. bit definitions below */ + uint32 source; /* last detected interference source */ + uint32 timestamp; /* second timestamp on interferenced flag change */ +} interference_source_rep_t; + +#define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ + + +typedef struct wl_country { + char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in + * the Country IE + */ + int32 rev; /* revision specifier for ccode + * on set, -1 indicates unspecified. + * on get, rev >= 0 + */ + char ccode[WLC_CNTRY_BUF_SZ]; /* nul-terminated built-in country code. + * variable length, but fixed size in + * struct allows simple allocation for + * expected country strings <= 3 chars. + */ +} wl_country_t; + +typedef struct wl_channels_in_country { + uint32 buflen; + uint32 band; + char country_abbrev[WLC_CNTRY_BUF_SZ]; + uint32 count; + uint32 channel[1]; +} wl_channels_in_country_t; + +typedef struct wl_country_list { + uint32 buflen; + uint32 band_set; + uint32 band; + uint32 count; + char country_abbrev[1]; +} wl_country_list_t; + +typedef struct wl_rm_req_elt { + int8 type; + int8 flags; + chanspec_t chanspec; + uint32 token; /* token for this measurement */ + uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ + uint32 tsf_l; /* TSF low 32-bits */ + uint32 dur; /* TUs */ +} wl_rm_req_elt_t; + +typedef struct wl_rm_req { + uint32 token; /* overall measurement set token */ + uint32 count; /* number of measurement requests */ + void *cb; /* completion callback function: may be NULL */ + void *cb_arg; /* arg to completion callback function */ + wl_rm_req_elt_t req[1]; /* variable length block of requests */ +} wl_rm_req_t; +#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) + +typedef struct wl_rm_rep_elt { + int8 type; + int8 flags; + chanspec_t chanspec; + uint32 token; /* token for this measurement */ + uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ + uint32 tsf_l; /* TSF low 32-bits */ + uint32 dur; /* TUs */ + uint32 len; /* byte length of data block */ + uint8 data[1]; /* variable length data block */ +} wl_rm_rep_elt_t; +#define WL_RM_REP_ELT_FIXED_LEN 24 /* length excluding data block */ + +#define WL_RPI_REP_BIN_NUM 8 +typedef struct wl_rm_rpi_rep { + uint8 rpi[WL_RPI_REP_BIN_NUM]; + int8 rpi_max[WL_RPI_REP_BIN_NUM]; +} wl_rm_rpi_rep_t; + +typedef struct wl_rm_rep { + uint32 token; /* overall measurement set token */ + uint32 len; /* length of measurement report block */ + wl_rm_rep_elt_t rep[1]; /* variable length block of reports */ +} wl_rm_rep_t; +#define WL_RM_REP_FIXED_LEN 8 + +#ifdef BCMCCX + +#define LEAP_USER_MAX 32 +#define LEAP_DOMAIN_MAX 32 +#define LEAP_PASSWORD_MAX 32 + +typedef struct wl_leap_info { + wlc_ssid_t ssid; + uint8 user_len; + uchar user[LEAP_USER_MAX]; + uint8 password_len; + uchar password[LEAP_PASSWORD_MAX]; + uint8 domain_len; + uchar domain[LEAP_DOMAIN_MAX]; +} wl_leap_info_t; + +typedef struct wl_leap_list { + uint32 buflen; + uint32 version; + uint32 count; + wl_leap_info_t leap_info[1]; +} wl_leap_list_t; +#endif /* BCMCCX */ + +typedef enum sup_auth_status { + /* Basic supplicant authentication states */ + WLC_SUP_DISCONNECTED = 0, + WLC_SUP_CONNECTING, + WLC_SUP_IDREQUIRED, + WLC_SUP_AUTHENTICATING, + WLC_SUP_AUTHENTICATED, + WLC_SUP_KEYXCHANGE, + WLC_SUP_KEYED, + WLC_SUP_TIMEOUT, + WLC_SUP_LAST_BASIC_STATE, + + /* Extended supplicant authentication states */ + /* Waiting to receive handshake msg M1 */ + WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, + /* Preparing to send handshake msg M2 */ + WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, + /* Waiting to receive handshake msg M3 */ + WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, + WLC_SUP_KEYXCHANGE_PREP_M4, /* Preparing to send handshake msg M4 */ + WLC_SUP_KEYXCHANGE_WAIT_G1, /* Waiting to receive handshake msg G1 */ + WLC_SUP_KEYXCHANGE_PREP_G2 /* Preparing to send handshake msg G2 */ +} sup_auth_status_t; + +typedef struct wl_wsec_key { + uint32 index; /* key index */ + uint32 len; /* key length */ + uint8 data[DOT11_MAX_KEY_SIZE]; /* key data */ + uint32 pad_1[18]; + uint32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ + uint32 flags; /* misc flags */ + uint32 pad_2[2]; + int pad_3; + int iv_initialized; /* has IV been initialized already? */ + int pad_4; + /* Rx IV */ + struct { + uint32 hi; /* upper 32 bits of IV */ + uint16 lo; /* lower 16 bits of IV */ + } rxiv; + uint32 pad_5[2]; + struct ether_addr ea; /* per station */ +} wl_wsec_key_t; + +#define WSEC_MIN_PSK_LEN 8 +#define WSEC_MAX_PSK_LEN 64 + +/* Flag for key material needing passhash'ing */ +#define WSEC_PASSPHRASE (1<<0) + +/* receptacle for WLC_SET_WSEC_PMK parameter */ +typedef struct { + ushort key_len; /* octets in key material */ + ushort flags; /* key handling qualification */ + uint8 key[WSEC_MAX_PSK_LEN]; /* PMK material */ +} wsec_pmk_t; + +typedef struct _pmkid { + struct ether_addr BSSID; + uint8 PMKID[WPA2_PMKID_LEN]; +} pmkid_t; + +typedef struct _pmkid_list { + uint32 npmkid; + pmkid_t pmkid[1]; +} pmkid_list_t; + +typedef struct _pmkid_cand { + struct ether_addr BSSID; + uint8 preauth; +} pmkid_cand_t; + +typedef struct _pmkid_cand_list { + uint32 npmkid_cand; + pmkid_cand_t pmkid_cand[1]; +} pmkid_cand_list_t; + +#define WL_STA_ANT_MAX 4 /* max possible rx antennas */ + +typedef struct wl_assoc_info { + uint32 req_len; + uint32 resp_len; + uint32 flags; + struct dot11_assoc_req req; + struct ether_addr reassoc_bssid; /* used in reassoc's */ + struct dot11_assoc_resp resp; +} wl_assoc_info_t; + +typedef struct wl_led_info { + uint32 index; /* led index */ + uint32 behavior; + uint8 activehi; +} wl_led_info_t; + + +/* srom read/write struct passed through ioctl */ +typedef struct { + uint byteoff; /* byte offset */ + uint nbytes; /* number of bytes */ + uint16 buf[1]; +} srom_rw_t; + +/* similar cis (srom or otp) struct [iovar: may not be aligned] */ +typedef struct { + uint32 source; /* cis source */ + uint32 byteoff; /* byte offset */ + uint32 nbytes; /* number of bytes */ + /* data follows here */ +} cis_rw_t; + +/* R_REG and W_REG struct passed through ioctl */ +typedef struct { + uint32 byteoff; /* byte offset of the field in d11regs_t */ + uint32 val; /* read/write value of the field */ + uint32 size; /* sizeof the field */ + uint band; /* band (optional) */ +} rw_reg_t; + +/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */ +/* PCL - Power Control Loop */ +typedef struct { + uint16 auto_ctrl; /* WL_ATTEN_XX */ + uint16 bb; /* Baseband attenuation */ + uint16 radio; /* Radio attenuation */ + uint16 txctl1; /* Radio TX_CTL1 value */ +} atten_t; + +/* Per-AC retry parameters */ +struct wme_tx_params_s { + uint8 short_retry; + uint8 short_fallback; + uint8 long_retry; + uint8 long_fallback; + uint16 max_rate; /* In units of 512 Kbps */ +}; + +typedef struct wme_tx_params_s wme_tx_params_t; + +#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) + +typedef struct wl_plc_nodelist { + uint32 count; /* Number of nodes */ + struct _node { + struct ether_addr ea; /* Node ether address */ + uint32 node_type; /* Node type */ + uint32 cost; /* PLC affinity */ + } node[1]; +} wl_plc_nodelist_t; + +typedef struct wl_plc_params { + uint32 cmd; /* Command */ + uint8 plc_failover; /* PLC failover control/status */ + struct ether_addr node_ea; /* Node ether address */ + uint32 cost; /* Link cost or mac cost */ +} wl_plc_params_t; + +/* Used to get specific link/ac parameters */ +typedef struct { + int32 ac; + uint8 val; + struct ether_addr ea; +} link_val_t; + + + +typedef struct { + uint16 ver; /* version of this struct */ + uint16 len; /* length in bytes of this structure */ + uint16 cap; /* sta's advertised capabilities */ + uint32 flags; /* flags defined below */ + uint32 idle; /* time since data pkt rx'd from sta */ + struct ether_addr ea; /* Station address */ + wl_rateset_t rateset; /* rateset in use */ + uint32 in; /* seconds elapsed since associated */ + uint32 listen_interval_inms; /* Min Listen interval in ms for this STA */ + uint32 tx_pkts; /* # of packets transmitted */ + uint32 tx_failures; /* # of packets failed */ + uint32 rx_ucast_pkts; /* # of unicast packets received */ + uint32 rx_mcast_pkts; /* # of multicast packets received */ + uint32 tx_rate; /* Rate of last successful tx frame */ + uint32 rx_rate; /* Rate of last successful rx frame */ + uint32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ + uint32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */ + uint32 tx_tot_pkts; /* # of tx pkts (ucast + mcast) */ + uint32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */ + uint32 tx_mcast_pkts; /* # of mcast pkts txed */ + uint64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */ + uint64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */ + uint64 tx_ucast_bytes; /* data bytes txed (ucast) */ + uint64 tx_mcast_bytes; /* # data bytes txed (mcast) */ + uint64 rx_ucast_bytes; /* data bytes recvd (ucast) */ + uint64 rx_mcast_bytes; /* data bytes recvd (mcast) */ + int8 rssi[WL_STA_ANT_MAX]; /* average rssi per antenna + * of data frames + */ + int8 nf[WL_STA_ANT_MAX]; /* per antenna noise floor */ + uint16 aid; /* association ID */ + uint16 ht_capabilities; /* advertised ht caps */ + uint16 vht_flags; /* converted vht flags */ + uint32 tx_pkts_retried; /* # of frames where a retry was necessary */ + uint32 tx_pkts_retry_exhausted; /* # of frames where a retry was + * exhausted + */ + int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /* Per antenna RSSI of last + * received data frame. + */ +} sta_info_t; + +#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts) + +#define WL_STA_VER 4 + +#define WLC_NUMRATES 16 /* max # of rates in a rateset */ + +typedef struct wlc_rateset { + uint32 count; /* number of rates in rates[] */ + uint8 rates[WLC_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */ + uint8 htphy_membership; /* HT PHY Membership */ + uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ + uint16 vht_mcsmap; /* supported vht mcs nss bit map */ +} wlc_rateset_t; + +/* Used to get specific STA parameters */ +typedef struct { + uint32 val; + struct ether_addr ea; +} scb_val_t; + +/* Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */ +typedef struct { + uint32 code; + scb_val_t ioctl_args; +} authops_t; + +/* channel encoding */ +typedef struct channel_info { + int hw_channel; + int target_channel; + int scan_channel; +} channel_info_t; + +/* For ioctls that take a list of MAC addresses */ +typedef struct maclist { + uint count; /* number of MAC addresses */ + struct ether_addr ea[1]; /* variable length array of MAC addresses */ +} maclist_t; + +/* get pkt count struct passed through ioctl */ +typedef struct get_pktcnt { + uint rx_good_pkt; + uint rx_bad_pkt; + uint tx_good_pkt; + uint tx_bad_pkt; + uint rx_ocast_good_pkt; /* unicast packets destined for others */ +} get_pktcnt_t; + +/* NINTENDO2 */ +#define LQ_IDX_MIN 0 +#define LQ_IDX_MAX 1 +#define LQ_IDX_AVG 2 +#define LQ_IDX_SUM 2 +#define LQ_IDX_LAST 3 +#define LQ_STOP_MONITOR 0 +#define LQ_START_MONITOR 1 + +/* Get averages RSSI, Rx PHY rate and SNR values */ +typedef struct { + int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */ + int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */ + int isvalid; /* Flag indicating whether above data is valid */ +} wl_lq_t; /* Link Quality */ + +typedef enum wl_wakeup_reason_type { + LCD_ON = 1, + LCD_OFF, + DRC1_WAKE, + DRC2_WAKE, + REASON_LAST +} wl_wr_type_t; + +typedef struct { +/* Unique filter id */ + uint32 id; + +/* stores the reason for the last wake up */ + uint8 reason; +} wl_wr_t; + +/* Get MAC specific rate histogram command */ +typedef struct { + struct ether_addr ea; /* MAC Address */ + uint8 ac_cat; /* Access Category */ + uint8 num_pkts; /* Number of packet entries to be averaged */ +} wl_mac_ratehisto_cmd_t; /* MAC Specific Rate Histogram command */ + +/* Get MAC rate histogram response */ +typedef struct { + uint32 rate[DOT11_RATE_MAX + 1]; /* Rates */ + uint32 mcs[WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX]; /* MCS counts */ + uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /* VHT counts */ + uint32 tsf_timer[2][2]; /* Start and End time for 8bytes value */ +} wl_mac_ratehisto_res_t; /* MAC Specific Rate Histogram Response */ + +/* Linux network driver ioctl encoding */ +typedef struct wl_ioctl { + uint cmd; /* common ioctl definition */ + void *buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + uint8 set; /* 1=set IOCTL; 0=query IOCTL */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ +} wl_ioctl_t; +#ifdef CONFIG_COMPAT +typedef struct compat_wl_ioctl { + uint cmd; /* common ioctl definition */ + uint32 buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + uint8 set; /* 1=set IOCTL; 0=query IOCTL */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ +} compat_wl_ioctl_t; +#endif /* CONFIG_COMPAT */ + + +/* + * Structure for passing hardware and software + * revision info up from the driver. + */ +typedef struct wlc_rev_info { + uint vendorid; /* PCI vendor id */ + uint deviceid; /* device id of chip */ + uint radiorev; /* radio revision */ + uint chiprev; /* chip revision */ + uint corerev; /* core revision */ + uint boardid; /* board identifier (usu. PCI sub-device id) */ + uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ + uint boardrev; /* board revision */ + uint driverrev; /* driver version */ + uint ucoderev; /* microcode version */ + uint bus; /* bus type */ + uint chipnum; /* chip number */ + uint phytype; /* phy type */ + uint phyrev; /* phy revision */ + uint anarev; /* anacore rev */ + uint chippkg; /* chip package info */ + uint nvramrev; /* nvram revision number */ +} wlc_rev_info_t; + +#define WL_REV_INFO_LEGACY_LENGTH 48 + +#define WL_BRAND_MAX 10 +typedef struct wl_instance_info { + uint instance; + char brand[WL_BRAND_MAX]; +} wl_instance_info_t; + +/* structure to change size of tx fifo */ +typedef struct wl_txfifo_sz { + uint16 magic; + uint16 fifo; + uint16 size; +} wl_txfifo_sz_t; + +/* Transfer info about an IOVar from the driver */ +/* Max supported IOV name size in bytes, + 1 for nul termination */ +#define WLC_IOV_NAME_LEN 30 +typedef struct wlc_iov_trx_s { + uint8 module; + uint8 type; + char name[WLC_IOV_NAME_LEN]; +} wlc_iov_trx_t; + +/* bump this number if you change the ioctl interface */ +#define WLC_IOCTL_VERSION 2 +#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1 + +#ifdef CONFIG_USBRNDIS_RETAIL +/* struct passed in for WLC_NDCONFIG_ITEM */ +typedef struct { + char *name; + void *param; +} ndconfig_item_t; +#endif + + +#define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[0] ... */ + +#define WL_PHY_PAVAR_VER 1 /* pavars version */ +#define WL_PHY_PAVARS2_NUM 3 /* a1, b0, b1 */ +typedef struct wl_pavars2 { + uint16 ver; /* version of this struct */ + uint16 len; /* len of this structure */ + uint16 inuse; /* driver return 1 for a1,b0,b1 in current band range */ + uint16 phy_type; /* phy type */ + uint16 bandrange; + uint16 chain; + uint16 inpa[WL_PHY_PAVARS2_NUM]; /* phy pavars for one band range */ +} wl_pavars2_t; + +typedef struct wl_po { + uint16 phy_type; /* Phy type */ + uint16 band; + uint16 cckpo; + uint32 ofdmpo; + uint16 mcspo[8]; +} wl_po_t; + +#define WL_NUM_RPCALVARS 5 /* number of rpcal vars */ + +typedef struct wl_rpcal { + uint16 value; + uint16 update; +} wl_rpcal_t; + +typedef struct wl_aci_args { + int enter_aci_thresh; /* Trigger level to start detecting ACI */ + int exit_aci_thresh; /* Trigger level to exit ACI mode */ + int usec_spin; /* microsecs to delay between rssi samples */ + int glitch_delay; /* interval between ACI scans when glitch count is consistently high */ + uint16 nphy_adcpwr_enter_thresh; /* ADC power to enter ACI mitigation mode */ + uint16 nphy_adcpwr_exit_thresh; /* ADC power to exit ACI mitigation mode */ + uint16 nphy_repeat_ctr; /* Number of tries per channel to compute power */ + uint16 nphy_num_samples; /* Number of samples to compute power on one channel */ + uint16 nphy_undetect_window_sz; /* num of undetects to exit ACI Mitigation mode */ + uint16 nphy_b_energy_lo_aci; /* low ACI power energy threshold for bphy */ + uint16 nphy_b_energy_md_aci; /* mid ACI power energy threshold for bphy */ + uint16 nphy_b_energy_hi_aci; /* high ACI power energy threshold for bphy */ + uint16 nphy_noise_noassoc_glitch_th_up; /* wl interference 4 */ + uint16 nphy_noise_noassoc_glitch_th_dn; + uint16 nphy_noise_assoc_glitch_th_up; + uint16 nphy_noise_assoc_glitch_th_dn; + uint16 nphy_noise_assoc_aci_glitch_th_up; + uint16 nphy_noise_assoc_aci_glitch_th_dn; + uint16 nphy_noise_assoc_enter_th; + uint16 nphy_noise_noassoc_enter_th; + uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; + uint16 nphy_noise_noassoc_crsidx_incr; + uint16 nphy_noise_assoc_crsidx_incr; + uint16 nphy_noise_crsidx_decr; +} wl_aci_args_t; + +#define WL_ACI_ARGS_LEGACY_LENGTH 16 /* bytes of pre NPHY aci args */ +#define WL_SAMPLECOLLECT_T_VERSION 2 /* version of wl_samplecollect_args_t struct */ +typedef struct wl_samplecollect_args { + /* version 0 fields */ + uint8 coll_us; + int cores; + /* add'l version 1 fields */ + uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */ + uint16 length; /* length of entire structure */ + int8 trigger; + uint16 timeout; + uint16 mode; + uint32 pre_dur; + uint32 post_dur; + uint8 gpio_sel; + uint8 downsamp; + uint8 be_deaf; + uint8 agc; /* loop from init gain and going down */ + uint8 filter; /* override high pass corners to lowest */ + /* add'l version 2 fields */ + uint8 trigger_state; + uint8 module_sel1; + uint8 module_sel2; + uint16 nsamps; + int bitStart; + uint32 gpioCapMask; +} wl_samplecollect_args_t; + +#define WL_SAMPLEDATA_T_VERSION 1 /* version of wl_samplecollect_args_t struct */ +/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */ +#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 + +typedef struct wl_sampledata { + uint16 version; /* structure version */ + uint16 size; /* size of structure */ + uint16 tag; /* Header/Data */ + uint16 length; /* data length */ + uint32 flag; /* bit def */ +} wl_sampledata_t; + + +/* WL_OTA START */ +/* OTA Test Status */ +enum { + WL_OTA_TEST_IDLE = 0, /* Default Idle state */ + WL_OTA_TEST_ACTIVE = 1, /* Test Running */ + WL_OTA_TEST_SUCCESS = 2, /* Successfully Finished Test */ + WL_OTA_TEST_FAIL = 3 /* Test Failed in the Middle */ +}; +/* OTA SYNC Status */ +enum { + WL_OTA_SYNC_IDLE = 0, /* Idle state */ + WL_OTA_SYNC_ACTIVE = 1, /* Waiting for Sync */ + WL_OTA_SYNC_FAIL = 2 /* Sync pkt not recieved */ +}; + +/* Various error states dut can get stuck during test */ +enum { + WL_OTA_SKIP_TEST_CAL_FAIL = 1, /* Phy calibration failed */ + WL_OTA_SKIP_TEST_SYNCH_FAIL = 2, /* Sync Packet not recieved */ + WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL = 3, /* Cmd flow file download failed */ + WL_OTA_SKIP_TEST_NO_TEST_FOUND = 4, /* No test found in Flow file */ + WL_OTA_SKIP_TEST_WL_NOT_UP = 5, /* WL UP failed */ + WL_OTA_SKIP_TEST_UNKNOWN_CALL /* Unintentional scheduling on ota test */ +}; + +/* Differentiator for ota_tx and ota_rx */ +enum { + WL_OTA_TEST_TX = 0, /* ota_tx */ + WL_OTA_TEST_RX = 1, /* ota_rx */ +}; + +/* Catch 3 modes of operation: 20Mhz, 40Mhz, 20 in 40 Mhz */ +enum { + WL_OTA_TEST_BW_20_IN_40MHZ = 0, /* 20 in 40 operation */ + WL_OTA_TEST_BW_20MHZ = 1, /* 20 Mhz operation */ + WL_OTA_TEST_BW_40MHZ = 2 /* full 40Mhz operation */ +}; +typedef struct ota_rate_info { + uint8 rate_cnt; /* Total number of rates */ + uint8 rate_val_mbps[WL_OTA_TEST_MAX_NUM_RATE]; /* array of rates from 1mbps to 130mbps */ + /* for legacy rates : ratein mbps * 2 */ + /* for HT rates : mcs index */ +} ota_rate_info_t; + +typedef struct ota_power_info { + int8 pwr_ctrl_on; /* power control on/off */ + int8 start_pwr; /* starting power/index */ + int8 delta_pwr; /* delta power/index */ + int8 end_pwr; /* end power/index */ +} ota_power_info_t; + +typedef struct ota_packetengine { + uint16 delay; /* Inter-packet delay */ + /* for ota_tx, delay is tx ifs in micro seconds */ + /* for ota_rx, delay is wait time in milliseconds */ + uint16 nframes; /* Number of frames */ + uint16 length; /* Packet length */ +} ota_packetengine_t; + +/* Test info vector */ +typedef struct wl_ota_test_args { + uint8 cur_test; /* test phase */ + uint8 chan; /* channel */ + uint8 bw; /* bandwidth */ + uint8 control_band; /* control band */ + uint8 stf_mode; /* stf mode */ + ota_rate_info_t rt_info; /* Rate info */ + ota_packetengine_t pkteng; /* packeteng info */ + uint8 txant; /* tx antenna */ + uint8 rxant; /* rx antenna */ + ota_power_info_t pwr_info; /* power sweep info */ + uint8 wait_for_sync; /* wait for sync or not */ +} wl_ota_test_args_t; + +typedef struct wl_ota_test_vector { + wl_ota_test_args_t test_arg[WL_OTA_TEST_MAX_NUM_SEQ]; /* Test argument struct */ + uint16 test_cnt; /* Total no of test */ + uint8 file_dwnld_valid; /* File successfully downloaded */ + uint8 sync_timeout; /* sync packet timeout */ + int8 sync_fail_action; /* sync fail action */ + struct ether_addr sync_mac; /* macaddress for sync pkt */ + struct ether_addr tx_mac; /* macaddress for tx */ + struct ether_addr rx_mac; /* macaddress for rx */ + int8 loop_test; /* dbg feature to loop the test */ +} wl_ota_test_vector_t; + + +/* struct copied back form dongle to host to query the status */ +typedef struct wl_ota_test_status { + int16 cur_test_cnt; /* test phase */ + int8 skip_test_reason; /* skip test reasoin */ + wl_ota_test_args_t test_arg; /* cur test arg details */ + uint16 test_cnt; /* total no of test downloaded */ + uint8 file_dwnld_valid; /* file successfully downloaded ? */ + uint8 sync_timeout; /* sync timeout */ + int8 sync_fail_action; /* sync fail action */ + struct ether_addr sync_mac; /* macaddress for sync pkt */ + struct ether_addr tx_mac; /* tx mac address */ + struct ether_addr rx_mac; /* rx mac address */ + uint8 test_stage; /* check the test status */ + int8 loop_test; /* Debug feature to puts test enfine in a loop */ + uint8 sync_status; /* sync status */ +} wl_ota_test_status_t; + +/* WL_OTA END */ + +/* wl_radar_args_t */ +typedef struct { + int npulses; /* required number of pulses at n * t_int */ + int ncontig; /* required number of pulses at t_int */ + int min_pw; /* minimum pulse width (20 MHz clocks) */ + int max_pw; /* maximum pulse width (20 MHz clocks) */ + uint16 thresh0; /* Radar detection, thresh 0 */ + uint16 thresh1; /* Radar detection, thresh 1 */ + uint16 blank; /* Radar detection, blank control */ + uint16 fmdemodcfg; /* Radar detection, fmdemod config */ + int npulses_lp; /* Radar detection, minimum long pulses */ + int min_pw_lp; /* Minimum pulsewidth for long pulses */ + int max_pw_lp; /* Maximum pulsewidth for long pulses */ + int min_fm_lp; /* Minimum fm for long pulses */ + int max_span_lp; /* Maximum deltat for long pulses */ + int min_deltat; /* Minimum spacing between pulses */ + int max_deltat; /* Maximum spacing between pulses */ + uint16 autocorr; /* Radar detection, autocorr on or off */ + uint16 st_level_time; /* Radar detection, start_timing level */ + uint16 t2_min; /* minimum clocks needed to remain in state 2 */ + uint32 version; /* version */ + uint32 fra_pulse_err; /* sample error margin for detecting French radar pulsed */ + int npulses_fra; /* Radar detection, minimum French pulses set */ + int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */ + int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */ + uint16 percal_mask; /* defines which period cal is masked from radar detection */ + int quant; /* quantization resolution to pulse positions */ + uint32 min_burst_intv_lp; /* minimum burst to burst interval for bin3 radar */ + uint32 max_burst_intv_lp; /* maximum burst to burst interval for bin3 radar */ + int nskip_rst_lp; /* number of skipped pulses before resetting lp buffer */ + int max_pw_tol; /* maximum tollerance allowed in detected pulse width for radar detection */ + uint16 feature_mask; /* 16-bit mask to specify enabled features */ +} wl_radar_args_t; + +#define WL_RADAR_ARGS_VERSION 2 + +typedef struct { + uint32 version; /* version */ + uint16 thresh0_20_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */ + uint16 thresh1_20_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */ + uint16 thresh0_40_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */ + uint16 thresh1_40_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */ + uint16 thresh0_80_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */ + uint16 thresh1_80_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */ + uint16 thresh0_20_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */ + uint16 thresh1_20_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */ + uint16 thresh0_40_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */ + uint16 thresh1_40_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */ + uint16 thresh0_80_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */ + uint16 thresh1_80_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */ +#ifdef WL11AC160 + uint16 thresh0_160_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */ + uint16 thresh1_160_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */ + uint16 thresh0_160_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */ + uint16 thresh1_160_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */ +#endif /* WL11AC160 */ +} wl_radar_thr_t; + +#define WL_RADAR_THR_VERSION 2 + +/* RSSI per antenna */ +typedef struct { + uint32 version; /* version field */ + uint32 count; /* number of valid antenna rssi */ + int8 rssi_ant[WL_RSSI_ANT_MAX]; /* rssi per antenna */ +} wl_rssi_ant_t; + +/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */ +typedef struct { + uint state; /* noted by WL_DFS_CACSTATE_XX. */ + uint duration; /* time spent in ms in state. */ + /* as dfs enters ISM state, it removes the operational channel from quiet channel + * list and notes the channel in channel_cleared. set to 0 if no channel is cleared + */ + chanspec_t chanspec_cleared; + /* chanspec cleared used to be a uint, add another to uint16 to maintain size */ + uint16 pad; +} wl_dfs_status_t; + +/* data structure used in 'radar_status' wl interface, which is use to query radar det status */ +typedef struct { + bool detected; + int count; + bool pretended; + uint32 radartype; + uint32 timenow; + uint32 timefromL; + int lp_csect_single; + int detected_pulse_index; + int nconsecq_pulses; + chanspec_t ch; + int pw[10]; + int intv[10]; + int fm[10]; +} wl_radar_status_t; + +#define NUM_PWRCTRL_RATES 12 + +typedef struct { + uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /* User set target */ + uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /* reg and local power limit */ + uint8 txpwr_local_max; /* local max according to the AP */ + uint8 txpwr_local_constraint; /* local constraint according to the AP */ + uint8 txpwr_chan_reg_max; /* Regulatory max for this channel */ + uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /* Latest target for 2.4 and 5 Ghz */ + uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ + uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /* On G phy, OFDM power offset */ + uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /* Max CCK power for this band (SROM) */ + uint8 txpwr_bphy_ofdm_max; /* Max OFDM power for this band (SROM) */ + uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /* Max power for A band (SROM) */ + int8 txpwr_antgain[2]; /* Ant gain for each band - from SROM */ + uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ +} tx_power_legacy_t; + +#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 + +typedef struct { + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint8 local_max; /* local max according to the AP */ + uint8 local_constraint; /* local constraint according to the AP */ + int8 antgain[2]; /* Ant gain for each band - from SROM */ + uint8 rf_cores; /* count of RF Cores being reported */ + uint8 est_Pout[4]; /* Latest tx power out estimate per RF + * chain without adjustment + */ + uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ + uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */ + uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */ + uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */ + uint8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */ +} tx_power_legacy2_t; + +/* TX Power index defines */ +#define WL_NUM_RATES_CCK 4 /* 1, 2, 5.5, 11 Mbps */ +#define WL_NUM_RATES_OFDM 8 /* 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */ +#define WL_NUM_RATES_MCS_1STREAM 8 /* MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */ +#define WL_NUM_RATES_EXTRA_VHT 2 /* Additional VHT 11AC rates */ +#define WL_NUM_RATES_VHT 10 +#define WL_NUM_RATES_MCS32 1 + +#define WLC_NUM_RATES_CCK WL_NUM_RATES_CCK +#define WLC_NUM_RATES_OFDM WL_NUM_RATES_OFDM +#define WLC_NUM_RATES_MCS_1_STREAM WL_NUM_RATES_MCS_1STREAM +#define WLC_NUM_RATES_MCS_2_STREAM WL_NUM_RATES_MCS_1STREAM +#define WLC_NUM_RATES_MCS32 WL_NUM_RATES_MCS32 +#define WL_TX_POWER_CCK_NUM WL_NUM_RATES_CCK +#define WL_TX_POWER_OFDM_NUM WL_NUM_RATES_OFDM +#define WL_TX_POWER_MCS_1_STREAM_NUM WL_NUM_RATES_MCS_1STREAM +#define WL_TX_POWER_MCS_2_STREAM_NUM WL_NUM_RATES_MCS_1STREAM +#define WL_TX_POWER_MCS_32_NUM WL_NUM_RATES_MCS32 + +#define WL_NUM_2x2_ELEMENTS 4 +#define WL_NUM_3x3_ELEMENTS 6 + +typedef struct { + uint16 ver; /* version of this struct */ + uint16 len; /* length in bytes of this structure */ + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint32 buflen; /* ppr buffer length */ + uint8 pprbuf[1]; /* Latest target power buffer */ +} wl_txppr_t; + +#define WL_TXPPR_VERSION 1 +#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) +#define TX_POWER_T_VERSION 44 + + +typedef struct tx_inst_power { + uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ + uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ +} tx_inst_power_t; + +#define WL_NUM_TXCHAIN_MAX 4 +typedef struct wl_txchain_pwr_offsets { + int8 offset[WL_NUM_TXCHAIN_MAX]; /* quarter dBm signed offset for each chain */ +} wl_txchain_pwr_offsets_t; +/* maximum channels returned by the get valid channels iovar */ +#define WL_NUMCHANNELS 64 + +/* + * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, + * a one-byte length, and a variable length value. RSSI type tuple must be present + * in the array. + * + * Types are defined in "join preference types" section. + * + * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple + * and must be set to zero. + * + * Values are defined below. + * + * 1. RSSI - 2 octets + * offset 0: reserved + * offset 1: reserved + * + * 2. WPA - 2 + 12 * n octets (n is # tuples defined below) + * offset 0: reserved + * offset 1: # of tuples + * offset 2: tuple 1 + * offset 14: tuple 2 + * ... + * offset 2 + 12 * (n - 1) octets: tuple n + * + * struct wpa_cfg_tuple { + * uint8 akm[DOT11_OUI_LEN+1]; akm suite + * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite + * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite + * }; + * + * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY. + * + * 3. BAND - 2 octets + * offset 0: reserved + * offset 1: see "band preference" and "band types" + * + * 4. BAND RSSI - 2 octets + * offset 0: band types + * offset 1: +ve RSSI boost value in dB + */ + +struct tsinfo_arg { + uint8 octets[3]; +}; + +#define NFIFO 6 /* # tx/rx fifopairs */ +#define NREINITREASONCOUNT 8 +#define REINITREASONIDX(_x) (((_x) < NREINITREASONCOUNT) ? (_x) : 0) + +#define WL_CNT_T_VERSION 10 /* current version of wl_cnt_t struct */ + +typedef struct { + uint16 version; /* see definition of WL_CNT_T_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txframe; /* tx data frames */ + uint32 txbyte; /* tx data bytes */ + uint32 txretrans; /* tx mac retransmits */ + uint32 txerror; /* tx data errors (derived: sum of others) */ + uint32 txctl; /* tx management frames */ + uint32 txprshort; /* tx short preamble frames */ + uint32 txserr; /* tx status errors */ + uint32 txnobuf; /* tx out of buffers errors */ + uint32 txnoassoc; /* tx discard because we're not associated */ + uint32 txrunt; /* tx runt frames */ + uint32 txchit; /* tx header cache hit (fastpath) */ + uint32 txcmiss; /* tx header cache miss (slowpath) */ + + /* transmit chip error counters */ + uint32 txuflo; /* tx fifo underflows */ + uint32 txphyerr; /* tx phy errors (indicated in tx status) */ + uint32 txphycrs; + + /* receive stat counters */ + uint32 rxframe; /* rx data frames */ + uint32 rxbyte; /* rx data bytes */ + uint32 rxerror; /* rx data errors (derived: sum of others) */ + uint32 rxctl; /* rx management frames */ + uint32 rxnobuf; /* rx out of buffers errors */ + uint32 rxnondata; /* rx non data frames in the data channel errors */ + uint32 rxbadds; /* rx bad DS errors */ + uint32 rxbadcm; /* rx bad control or management frames */ + uint32 rxfragerr; /* rx fragmentation errors */ + uint32 rxrunt; /* rx runt frames */ + uint32 rxgiant; /* rx giant frames */ + uint32 rxnoscb; /* rx no scb error */ + uint32 rxbadproto; /* rx invalid frames */ + uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ + uint32 rxbadda; /* rx frames tossed for invalid da */ + uint32 rxfilter; /* rx frames filtered out */ + + /* receive chip error counters */ + uint32 rxoflo; /* rx fifo overflow errors */ + uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ + + uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ + uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ + uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ + + /* misc counters */ + uint32 dmade; /* tx/rx dma descriptor errors */ + uint32 dmada; /* tx/rx dma data errors */ + uint32 dmape; /* tx/rx dma descriptor protocol errors */ + uint32 reset; /* reset count */ + uint32 tbtt; /* cnts the TBTT int's */ + uint32 txdmawar; + uint32 pkt_callback_reg_fail; /* callbacks register failure */ + + /* MAC counters: 32-bit version of d11.h's macstat_t */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txdnlfrm; /* Not used */ + uint32 txbcnfrm; /* beacons transmitted */ + uint32 txfunfl[6]; /* per-fifo tx underflows */ + uint32 rxtoolate; /* receive too late */ + uint32 txfbw; /* transmit at fallback bw (dynamic bw) */ + uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS + * or BCN) + */ + uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for + * driver enqueued frames + */ + uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ + uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ + uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not + * data/control/management + */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ + uint32 rxbadplcp; /* parity check of the PLCP header failed */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ + uint32 rxstrt; /* Number of received frames with a good PLCP + * (i.e. passing parity check) + */ + uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ + uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ + uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ + uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ + uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ + uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ + uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ + uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ + uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ + uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC + * (unlikely to see these) + */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from + * other BSS (WDS FRAME) + */ + uint32 rxbeaconobss; /* beacons received from other BSS */ + uint32 rxrsptmout; /* Number of response timeouts for transmitted frames + * expecting a response + */ + uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ + uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ + uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ + uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ + uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ + uint32 pmqovfl; /* Number of PMQ overflows */ + uint32 rxcgprqfrm; /* Number of received Probe requests that made it into + * the PRQ fifo + */ + uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ + uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did + * not get ACK + */ + uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ + uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ + * fifo because a probe response could not be sent out within + * the time limit defined in M_PRS_MAXTIME + */ + uint32 rxnack; /* obsolete */ + uint32 frmscons; /* obsolete */ + uint32 txnack; /* obsolete */ + uint32 rxback; /* blockack rxcnt */ + uint32 txback; /* blockack txcnt */ + + /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ + uint32 txfrag; /* dot11TransmittedFragmentCount */ + uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ + uint32 txfail; /* dot11FailedCount */ + uint32 txretry; /* dot11RetryCount */ + uint32 txretrie; /* dot11MultipleRetryCount */ + uint32 rxdup; /* dot11FrameduplicateCount */ + uint32 txrts; /* dot11RTSSuccessCount */ + uint32 txnocts; /* dot11RTSFailureCount */ + uint32 txnoack; /* dot11ACKFailureCount */ + uint32 rxfrag; /* dot11ReceivedFragmentCount */ + uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ + uint32 rxcrc; /* dot11FCSErrorCount */ + uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ + uint32 rxundec; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay; /* TKIPReplays */ + uint32 ccmpfmterr; /* CCMPFormatErrors */ + uint32 ccmpreplay; /* CCMPReplays */ + uint32 ccmpundec; /* CCMPDecryptErrors */ + uint32 fourwayfail; /* FourWayHandshakeFailures */ + uint32 wepundec; /* dot11WEPUndecryptableCount */ + uint32 wepicverr; /* dot11WEPICVErrorCount */ + uint32 decsuccess; /* DecryptSuccessCount */ + uint32 tkipicverr; /* TKIPICVErrorCount */ + uint32 wepexcluded; /* dot11WEPExcludedCount */ + + uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ + uint32 psmwds; /* Count PSM watchdogs */ + uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ + + /* MBSS counters, AP only */ + uint32 prq_entries_handled; /* PRQ entries read in */ + uint32 prq_undirected_entries; /* which were bcast bss & ssid */ + uint32 prq_bad_entries; /* which could not be translated to info */ + uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ + uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ + uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ + uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ + + /* per-rate receive stat counters */ + uint32 rx1mbps; /* packets rx at 1Mbps */ + uint32 rx2mbps; /* packets rx at 2Mbps */ + uint32 rx5mbps5; /* packets rx at 5.5Mbps */ + uint32 rx6mbps; /* packets rx at 6Mbps */ + uint32 rx9mbps; /* packets rx at 9Mbps */ + uint32 rx11mbps; /* packets rx at 11Mbps */ + uint32 rx12mbps; /* packets rx at 12Mbps */ + uint32 rx18mbps; /* packets rx at 18Mbps */ + uint32 rx24mbps; /* packets rx at 24Mbps */ + uint32 rx36mbps; /* packets rx at 36Mbps */ + uint32 rx48mbps; /* packets rx at 48Mbps */ + uint32 rx54mbps; /* packets rx at 54Mbps */ + uint32 rx108mbps; /* packets rx at 108mbps */ + uint32 rx162mbps; /* packets rx at 162mbps */ + uint32 rx216mbps; /* packets rx at 216 mbps */ + uint32 rx270mbps; /* packets rx at 270 mbps */ + uint32 rx324mbps; /* packets rx at 324 mbps */ + uint32 rx378mbps; /* packets rx at 378 mbps */ + uint32 rx432mbps; /* packets rx at 432 mbps */ + uint32 rx486mbps; /* packets rx at 486 mbps */ + uint32 rx540mbps; /* packets rx at 540 mbps */ + + /* pkteng rx frame stats */ + uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ + uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ + + uint32 rfdisable; /* count of radio disables */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 bphy_badplcp; + + uint32 txexptime; /* Tx frames suppressed due to timer expiration */ + + uint32 txmpdu_sgi; /* count for sgi transmit */ + uint32 rxmpdu_sgi; /* count for sgi received */ + uint32 txmpdu_stbc; /* count for stbc transmit */ + uint32 rxmpdu_stbc; /* count for stbc received */ + + uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay_mcst; /* TKIPReplays */ + uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ + uint32 ccmpreplay_mcst; /* CCMPReplays */ + uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ + uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ + uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ + uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ + uint32 decsuccess_mcst; /* DecryptSuccessCount */ + uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ + uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ + + uint32 dma_hang; /* count for dma hang */ + uint32 reinit; /* count for reinit */ + + uint32 pstatxucast; /* count of ucast frames xmitted on all psta assoc */ + uint32 pstatxnoassoc; /* count of txnoassoc frames xmitted on all psta assoc */ + uint32 pstarxucast; /* count of ucast frames received on all psta assoc */ + uint32 pstarxbcmc; /* count of bcmc frames received on all psta */ + uint32 pstatxbcmc; /* count of bcmc frames transmitted on all psta */ + + uint32 cso_passthrough; /* hw cso required but passthrough */ + uint32 cso_normal; /* hw cso hdr for normal process */ + uint32 chained; /* number of frames chained */ + uint32 chainedsz1; /* number of chain size 1 frames */ + uint32 unchained; /* number of frames not chained */ + uint32 maxchainsz; /* max chain size so far */ + uint32 currchainsz; /* current chain size */ + uint32 rxdrop20s; /* drop secondary cnt */ + uint32 pciereset; /* Secondary Bus Reset issued by driver */ + uint32 cfgrestore; /* configspace restore by driver */ + uint32 reinitreason[NREINITREASONCOUNT]; /* reinitreason counters; 0: Unknown reason */ + uint32 rxrtry; /* num of received packets with retry bit on */ +} wl_cnt_t; + +typedef struct { + uint16 version; /* see definition of WL_CNT_T_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txframe; /* tx data frames */ + uint32 txbyte; /* tx data bytes */ + uint32 txretrans; /* tx mac retransmits */ + uint32 txerror; /* tx data errors (derived: sum of others) */ + uint32 txctl; /* tx management frames */ + uint32 txprshort; /* tx short preamble frames */ + uint32 txserr; /* tx status errors */ + uint32 txnobuf; /* tx out of buffers errors */ + uint32 txnoassoc; /* tx discard because we're not associated */ + uint32 txrunt; /* tx runt frames */ + uint32 txchit; /* tx header cache hit (fastpath) */ + uint32 txcmiss; /* tx header cache miss (slowpath) */ + + /* transmit chip error counters */ + uint32 txuflo; /* tx fifo underflows */ + uint32 txphyerr; /* tx phy errors (indicated in tx status) */ + uint32 txphycrs; + + /* receive stat counters */ + uint32 rxframe; /* rx data frames */ + uint32 rxbyte; /* rx data bytes */ + uint32 rxerror; /* rx data errors (derived: sum of others) */ + uint32 rxctl; /* rx management frames */ + uint32 rxnobuf; /* rx out of buffers errors */ + uint32 rxnondata; /* rx non data frames in the data channel errors */ + uint32 rxbadds; /* rx bad DS errors */ + uint32 rxbadcm; /* rx bad control or management frames */ + uint32 rxfragerr; /* rx fragmentation errors */ + uint32 rxrunt; /* rx runt frames */ + uint32 rxgiant; /* rx giant frames */ + uint32 rxnoscb; /* rx no scb error */ + uint32 rxbadproto; /* rx invalid frames */ + uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ + uint32 rxbadda; /* rx frames tossed for invalid da */ + uint32 rxfilter; /* rx frames filtered out */ + + /* receive chip error counters */ + uint32 rxoflo; /* rx fifo overflow errors */ + uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ + + uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ + uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ + uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ + + /* misc counters */ + uint32 dmade; /* tx/rx dma descriptor errors */ + uint32 dmada; /* tx/rx dma data errors */ + uint32 dmape; /* tx/rx dma descriptor protocol errors */ + uint32 reset; /* reset count */ + uint32 tbtt; /* cnts the TBTT int's */ + uint32 txdmawar; + uint32 pkt_callback_reg_fail; /* callbacks register failure */ + + /* MAC counters: 32-bit version of d11.h's macstat_t */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txdnlfrm; /* Not used */ + uint32 txbcnfrm; /* beacons transmitted */ + uint32 txfunfl[6]; /* per-fifo tx underflows */ + uint32 rxtoolate; /* receive too late */ + uint32 txfbw; /* transmit at fallback bw (dynamic bw) */ + uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS + * or BCN) + */ + uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for + * driver enqueued frames + */ + uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ + uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ + uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not + * data/control/management + */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ + uint32 rxbadplcp; /* parity check of the PLCP header failed */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ + uint32 rxstrt; /* Number of received frames with a good PLCP + * (i.e. passing parity check) + */ + uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ + uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ + uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ + uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ + uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ + uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ + uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ + uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ + uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ + uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC + * (unlikely to see these) + */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from + * other BSS (WDS FRAME) + */ + uint32 rxbeaconobss; /* beacons received from other BSS */ + uint32 rxrsptmout; /* Number of response timeouts for transmitted frames + * expecting a response + */ + uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ + uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ + uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ + uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ + uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ + uint32 pmqovfl; /* Number of PMQ overflows */ + uint32 rxcgprqfrm; /* Number of received Probe requests that made it into + * the PRQ fifo + */ + uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ + uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did + * not get ACK + */ + uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ + uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ + * fifo because a probe response could not be sent out within + * the time limit defined in M_PRS_MAXTIME + */ + uint32 rxnack; + uint32 frmscons; + uint32 txnack; /* obsolete */ + uint32 rxback; /* blockack rxcnt */ + uint32 txback; /* blockack txcnt */ + + /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ + uint32 txfrag; /* dot11TransmittedFragmentCount */ + uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ + uint32 txfail; /* dot11FailedCount */ + uint32 txretry; /* dot11RetryCount */ + uint32 txretrie; /* dot11MultipleRetryCount */ + uint32 rxdup; /* dot11FrameduplicateCount */ + uint32 txrts; /* dot11RTSSuccessCount */ + uint32 txnocts; /* dot11RTSFailureCount */ + uint32 txnoack; /* dot11ACKFailureCount */ + uint32 rxfrag; /* dot11ReceivedFragmentCount */ + uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ + uint32 rxcrc; /* dot11FCSErrorCount */ + uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ + uint32 rxundec; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay; /* TKIPReplays */ + uint32 ccmpfmterr; /* CCMPFormatErrors */ + uint32 ccmpreplay; /* CCMPReplays */ + uint32 ccmpundec; /* CCMPDecryptErrors */ + uint32 fourwayfail; /* FourWayHandshakeFailures */ + uint32 wepundec; /* dot11WEPUndecryptableCount */ + uint32 wepicverr; /* dot11WEPICVErrorCount */ + uint32 decsuccess; /* DecryptSuccessCount */ + uint32 tkipicverr; /* TKIPICVErrorCount */ + uint32 wepexcluded; /* dot11WEPExcludedCount */ + + uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay_mcst; /* TKIPReplays */ + uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ + uint32 ccmpreplay_mcst; /* CCMPReplays */ + uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ + uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ + uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ + uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ + uint32 decsuccess_mcst; /* DecryptSuccessCount */ + uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ + uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ + + uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ + uint32 txexptime; /* Tx frames suppressed due to timer expiration */ + uint32 psmwds; /* Count PSM watchdogs */ + uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ + + /* MBSS counters, AP only */ + uint32 prq_entries_handled; /* PRQ entries read in */ + uint32 prq_undirected_entries; /* which were bcast bss & ssid */ + uint32 prq_bad_entries; /* which could not be translated to info */ + uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ + uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ + uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ + uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ + + /* per-rate receive stat counters */ + uint32 rx1mbps; /* packets rx at 1Mbps */ + uint32 rx2mbps; /* packets rx at 2Mbps */ + uint32 rx5mbps5; /* packets rx at 5.5Mbps */ + uint32 rx6mbps; /* packets rx at 6Mbps */ + uint32 rx9mbps; /* packets rx at 9Mbps */ + uint32 rx11mbps; /* packets rx at 11Mbps */ + uint32 rx12mbps; /* packets rx at 12Mbps */ + uint32 rx18mbps; /* packets rx at 18Mbps */ + uint32 rx24mbps; /* packets rx at 24Mbps */ + uint32 rx36mbps; /* packets rx at 36Mbps */ + uint32 rx48mbps; /* packets rx at 48Mbps */ + uint32 rx54mbps; /* packets rx at 54Mbps */ + uint32 rx108mbps; /* packets rx at 108mbps */ + uint32 rx162mbps; /* packets rx at 162mbps */ + uint32 rx216mbps; /* packets rx at 216 mbps */ + uint32 rx270mbps; /* packets rx at 270 mbps */ + uint32 rx324mbps; /* packets rx at 324 mbps */ + uint32 rx378mbps; /* packets rx at 378 mbps */ + uint32 rx432mbps; /* packets rx at 432 mbps */ + uint32 rx486mbps; /* packets rx at 486 mbps */ + uint32 rx540mbps; /* packets rx at 540 mbps */ + + /* pkteng rx frame stats */ + uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ + uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ + + uint32 rfdisable; /* count of radio disables */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 bphy_badplcp; + + uint32 txmpdu_sgi; /* count for sgi transmit */ + uint32 rxmpdu_sgi; /* count for sgi received */ + uint32 txmpdu_stbc; /* count for stbc transmit */ + uint32 rxmpdu_stbc; /* count for stbc received */ + + uint32 rxdrop20s; /* drop secondary cnt */ + +} wl_cnt_ver_six_t; + +#define WL_DELTA_STATS_T_VERSION 2 /* current version of wl_delta_stats_t struct */ + +typedef struct { + uint16 version; /* see definition of WL_DELTA_STATS_T_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txframe; /* tx data frames */ + uint32 txbyte; /* tx data bytes */ + uint32 txretrans; /* tx mac retransmits */ + uint32 txfail; /* tx failures */ + + /* receive stat counters */ + uint32 rxframe; /* rx data frames */ + uint32 rxbyte; /* rx data bytes */ + + /* per-rate receive stat counters */ + uint32 rx1mbps; /* packets rx at 1Mbps */ + uint32 rx2mbps; /* packets rx at 2Mbps */ + uint32 rx5mbps5; /* packets rx at 5.5Mbps */ + uint32 rx6mbps; /* packets rx at 6Mbps */ + uint32 rx9mbps; /* packets rx at 9Mbps */ + uint32 rx11mbps; /* packets rx at 11Mbps */ + uint32 rx12mbps; /* packets rx at 12Mbps */ + uint32 rx18mbps; /* packets rx at 18Mbps */ + uint32 rx24mbps; /* packets rx at 24Mbps */ + uint32 rx36mbps; /* packets rx at 36Mbps */ + uint32 rx48mbps; /* packets rx at 48Mbps */ + uint32 rx54mbps; /* packets rx at 54Mbps */ + uint32 rx108mbps; /* packets rx at 108mbps */ + uint32 rx162mbps; /* packets rx at 162mbps */ + uint32 rx216mbps; /* packets rx at 216 mbps */ + uint32 rx270mbps; /* packets rx at 270 mbps */ + uint32 rx324mbps; /* packets rx at 324 mbps */ + uint32 rx378mbps; /* packets rx at 378 mbps */ + uint32 rx432mbps; /* packets rx at 432 mbps */ + uint32 rx486mbps; /* packets rx at 486 mbps */ + uint32 rx540mbps; /* packets rx at 540 mbps */ + + /* phy stats */ + uint32 rxbadplcp; + uint32 rxcrsglitch; + uint32 bphy_rxcrsglitch; + uint32 bphy_badplcp; + +} wl_delta_stats_t; + +typedef struct { + uint32 packets; + uint32 bytes; +} wl_traffic_stats_t; + +typedef struct { + uint16 version; /* see definition of WL_WME_CNT_VERSION */ + uint16 length; /* length of entire structure */ + + wl_traffic_stats_t tx[AC_COUNT]; /* Packets transmitted */ + wl_traffic_stats_t tx_failed[AC_COUNT]; /* Packets dropped or failed to transmit */ + wl_traffic_stats_t rx[AC_COUNT]; /* Packets received */ + wl_traffic_stats_t rx_failed[AC_COUNT]; /* Packets failed to receive */ + + wl_traffic_stats_t forward[AC_COUNT]; /* Packets forwarded by AP */ + + wl_traffic_stats_t tx_expired[AC_COUNT]; /* packets dropped due to lifetime expiry */ + +} wl_wme_cnt_t; + +struct wl_msglevel2 { + uint32 low; + uint32 high; +}; + +typedef struct wl_mkeep_alive_pkt { + uint16 version; /* Version for mkeep_alive */ + uint16 length; /* length of fixed parameters in the structure */ + uint32 period_msec; + uint16 len_bytes; + uint8 keep_alive_id; /* 0 - 3 for N = 4 */ + uint8 data[1]; +} wl_mkeep_alive_pkt_t; + +#define WL_MKEEP_ALIVE_VERSION 1 +#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) +#define WL_MKEEP_ALIVE_PRECISION 500 + +/* TCP Keep-Alive conn struct */ +typedef struct wl_mtcpkeep_alive_conn_pkt { + struct ether_addr saddr; /* src mac address */ + struct ether_addr daddr; /* dst mac address */ + struct ipv4_addr sipaddr; /* source IP addr */ + struct ipv4_addr dipaddr; /* dest IP addr */ + uint16 sport; /* src port */ + uint16 dport; /* dest port */ + uint32 seq; /* seq number */ + uint32 ack; /* ACK number */ + uint16 tcpwin; /* TCP window */ +} wl_mtcpkeep_alive_conn_pkt_t; + +/* TCP Keep-Alive interval struct */ +typedef struct wl_mtcpkeep_alive_timers_pkt { + uint16 interval; /* interval timer */ + uint16 retry_interval; /* retry_interval timer */ + uint16 retry_count; /* retry_count */ +} wl_mtcpkeep_alive_timers_pkt_t; + +typedef struct wake_info { + uint32 wake_reason; + uint32 wake_info_len; /* size of packet */ + uchar packet[1]; +} wake_info_t; + +typedef struct wake_pkt { + uint32 wake_pkt_len; /* size of packet */ + uchar packet[1]; +} wake_pkt_t; + + +#define WL_MTCPKEEP_ALIVE_VERSION 1 + +#ifdef WLBA + +#define WLC_BA_CNT_VERSION 1 /* current version of wlc_ba_cnt_t */ + +/* block ack related stats */ +typedef struct wlc_ba_cnt { + uint16 version; /* WLC_BA_CNT_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txpdu; /* pdus sent */ + uint32 txsdu; /* sdus sent */ + uint32 txfc; /* tx side flow controlled packets */ + uint32 txfci; /* tx side flow control initiated */ + uint32 txretrans; /* retransmitted pdus */ + uint32 txbatimer; /* ba resend due to timer */ + uint32 txdrop; /* dropped packets */ + uint32 txaddbareq; /* addba req sent */ + uint32 txaddbaresp; /* addba resp sent */ + uint32 txdelba; /* delba sent */ + uint32 txba; /* ba sent */ + uint32 txbar; /* bar sent */ + uint32 txpad[4]; /* future */ + + /* receive side counters */ + uint32 rxpdu; /* pdus recd */ + uint32 rxqed; /* pdus buffered before sending up */ + uint32 rxdup; /* duplicate pdus */ + uint32 rxnobuf; /* pdus discarded due to no buf */ + uint32 rxaddbareq; /* addba req recd */ + uint32 rxaddbaresp; /* addba resp recd */ + uint32 rxdelba; /* delba recd */ + uint32 rxba; /* ba recd */ + uint32 rxbar; /* bar recd */ + uint32 rxinvba; /* invalid ba recd */ + uint32 rxbaholes; /* ba recd with holes */ + uint32 rxunexp; /* unexpected packets */ + uint32 rxpad[4]; /* future */ +} wlc_ba_cnt_t; +#endif /* WLBA */ + +/* structure for per-tid ampdu control */ +struct ampdu_tid_control { + uint8 tid; /* tid */ + uint8 enable; /* enable/disable */ +}; + +/* struct for per-tid, per-mode ampdu control */ +struct ampdu_tid_control_mode { + struct ampdu_tid_control control[NUMPRIO]; /* tid will be 0xff for not used element */ + char mode_name[8]; /* supported mode : AIBSS */ +}; + +/* structure for identifying ea/tid for sending addba/delba */ +struct ampdu_ea_tid { + struct ether_addr ea; /* Station address */ + uint8 tid; /* tid */ +}; +/* structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */ +struct ampdu_retry_tid { + uint8 tid; /* tid */ + uint8 retry; /* retry value */ +}; + +/* structure for dpt iovars */ +typedef struct dpt_iovar { + struct ether_addr ea; /* Station address */ + uint8 mode; /* mode: depends on iovar */ + uint32 pad; /* future */ +} dpt_iovar_t; + +#define DPT_FNAME_LEN 48 /* Max length of friendly name */ + +typedef struct dpt_status { + uint8 status; /* flags to indicate status */ + uint8 fnlen; /* length of friendly name */ + uchar name[DPT_FNAME_LEN]; /* friendly name */ + uint32 rssi; /* RSSI of the link */ + sta_info_t sta; /* sta info */ +} dpt_status_t; + +/* structure for dpt list */ +typedef struct dpt_list { + uint32 num; /* number of entries in struct */ + dpt_status_t status[1]; /* per station info */ +} dpt_list_t; + +/* structure for dpt friendly name */ +typedef struct dpt_fname { + uint8 len; /* length of friendly name */ + uchar name[DPT_FNAME_LEN]; /* friendly name */ +} dpt_fname_t; + +#define BDD_FNAME_LEN 32 /* Max length of friendly name */ +typedef struct bdd_fname { + uint8 len; /* length of friendly name */ + uchar name[BDD_FNAME_LEN]; /* friendly name */ +} bdd_fname_t; + +/* structure for addts arguments */ +/* For ioctls that take a list of TSPEC */ +struct tslist { + int count; /* number of tspecs */ + struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */ +}; + +#ifdef WLTDLS +/* structure for tdls iovars */ +typedef struct tdls_iovar { + struct ether_addr ea; /* Station address */ + uint8 mode; /* mode: depends on iovar */ + chanspec_t chanspec; + uint32 pad; /* future */ +} tdls_iovar_t; + +#define TDLS_WFD_IE_SIZE 512 +/* structure for tdls wfd ie */ +typedef struct tdls_wfd_ie_iovar { + struct ether_addr ea; /* Station address */ + uint8 mode; + uint16 length; + uint8 data[TDLS_WFD_IE_SIZE]; +} tdls_wfd_ie_iovar_t; +#endif /* WLTDLS */ + +/* structure for addts/delts arguments */ +typedef struct tspec_arg { + uint16 version; /* see definition of TSPEC_ARG_VERSION */ + uint16 length; /* length of entire structure */ + uint flag; /* bit field */ + /* TSPEC Arguments */ + struct tsinfo_arg tsinfo; /* TS Info bit field */ + uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ + uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ + uint min_srv_interval; /* Minimum Service Interval (us) */ + uint max_srv_interval; /* Maximum Service Interval (us) */ + uint inactivity_interval; /* Inactivity Interval (us) */ + uint suspension_interval; /* Suspension Interval (us) */ + uint srv_start_time; /* Service Start Time (us) */ + uint min_data_rate; /* Minimum Data Rate (bps) */ + uint mean_data_rate; /* Mean Data Rate (bps) */ + uint peak_data_rate; /* Peak Data Rate (bps) */ + uint max_burst_size; /* Maximum Burst Size (bytes) */ + uint delay_bound; /* Delay Bound (us) */ + uint min_phy_rate; /* Minimum PHY Rate (bps) */ + uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */ + uint16 medium_time; /* Medium Time (32 us/s periods) */ + uint8 dialog_token; /* dialog token */ +} tspec_arg_t; + +/* tspec arg for desired station */ +typedef struct tspec_per_sta_arg { + struct ether_addr ea; + struct tspec_arg ts; +} tspec_per_sta_arg_t; + +/* structure for max bandwidth for each access category */ +typedef struct wme_max_bandwidth { + uint32 ac[AC_COUNT]; /* max bandwidth for each access category */ +} wme_max_bandwidth_t; + +#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) + +/* current version of wl_tspec_arg_t struct */ +#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */ +#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */ +#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */ +#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */ + +#if defined(ANQPO_SUPPORT) +#define ANQPO_MAX_PFN_HS 16 +#define ANQPO_MAX_OI_LENGTH 8 +typedef struct { + uint8 length; + uint8 data[ANQPO_MAX_OI_LENGTH]; +} wl_anqpo_oi_t; + +#define ANQPO_MAX_OI 16 +typedef struct { + uint32 numOi; + wl_anqpo_oi_t oi[ANQPO_MAX_OI]; +} wl_anqpo_roaming_consortium_t; + +#define ANQPO_MAX_REALM_LENGTH 255 +typedef struct { + uint8 length; + uint8 data[ANQPO_MAX_REALM_LENGTH + 1]; /* null terminated */ +} wl_anqpo_realm_data_t; + +#define ANQPO_MCC_LENGTH 3 +#define ANQPO_MNC_LENGTH 3 +typedef struct { + char mcc[ANQPO_MCC_LENGTH + 1]; + char mnc[ANQPO_MNC_LENGTH + 1]; +} wl_anqpo_plmn_t; + +typedef struct { + uint32 version; + uint32 id; + wl_anqpo_plmn_t plmn; + wl_anqpo_realm_data_t realm; + wl_anqpo_roaming_consortium_t rc; +} wl_anqpo_pfn_hs_t; + +typedef struct { + bool is_clear; /* set to clear list (not used on GET) */ + uint16 count; /* number of preferred hotspot in list */ + wl_anqpo_pfn_hs_t hs[]; /* max ANQPO_MAX_PFN_HS */ +} wl_anqpo_pfn_hs_list_t; + +#endif /* ANQPO_SUPPORT */ + +#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80 +#define WLC_WOWL_MAX_KEEPALIVE 2 + +/* Packet lifetime configuration per ac */ +typedef struct wl_lifetime { + uint32 ac; /* access class */ + uint32 lifetime; /* Packet lifetime value in ms */ +} wl_lifetime_t; + +/* Channel Switch Announcement param */ +typedef struct wl_chan_switch { + uint8 mode; /* value 0 or 1 */ + uint8 count; /* count # of beacons before switching */ + chanspec_t chspec; /* chanspec */ + uint8 reg; /* regulatory class */ + uint8 frame_type; /* csa frame type, unicast or broadcast */ +} wl_chan_switch_t; + +enum { + PFN_LIST_ORDER, + PFN_RSSI +}; + +enum { + DISABLE, + ENABLE +}; + +enum { + OFF_ADAPT, + SMART_ADAPT, + STRICT_ADAPT, + SLOW_ADAPT +}; + +#define SORT_CRITERIA_BIT 0 +#define AUTO_NET_SWITCH_BIT 1 +#define ENABLE_BKGRD_SCAN_BIT 2 +#define IMMEDIATE_SCAN_BIT 3 +#define AUTO_CONNECT_BIT 4 +#define ENABLE_BD_SCAN_BIT 5 +#define ENABLE_ADAPTSCAN_BIT 6 +#define IMMEDIATE_EVENT_BIT 8 +#define SUPPRESS_SSID_BIT 9 +#define ENABLE_NET_OFFLOAD_BIT 10 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_BIT 11 + +#define SORT_CRITERIA_MASK 0x0001 +#define AUTO_NET_SWITCH_MASK 0x0002 +#define ENABLE_BKGRD_SCAN_MASK 0x0004 +#define IMMEDIATE_SCAN_MASK 0x0008 +#define AUTO_CONNECT_MASK 0x0010 + +#define ENABLE_BD_SCAN_MASK 0x0020 +#define ENABLE_ADAPTSCAN_MASK 0x00c0 +#define IMMEDIATE_EVENT_MASK 0x0100 +#define SUPPRESS_SSID_MASK 0x0200 +#define ENABLE_NET_OFFLOAD_MASK 0x0400 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_MASK 0x0800 + +#define PFN_VERSION 2 +#define PFN_SCANRESULT_VERSION 1 +#define MAX_PFN_LIST_COUNT 16 + +#define PFN_COMPLETE 1 +#define PFN_INCOMPLETE 0 + +#define DEFAULT_BESTN 2 +#define DEFAULT_MSCAN 0 +#define DEFAULT_REPEAT 10 +#define DEFAULT_EXP 2 + +#define PFN_PARTIAL_SCAN_BIT 0 +#define PFN_PARTIAL_SCAN_MASK 1 + +#define PFN_SWC_RSSI_WINDOW_MAX 8 +#define PFN_SWC_MAX_NUM_APS 16 +#define PFN_HOTLIST_MAX_NUM_APS 64 + +#define PFN_SWC_RSSI_WINDOW_MAX 8 +#define PFN_SWC_MAX_NUM_APS 16 +#define PFN_HOTLIST_MAX_NUM_APS 64 + +#define MAX_EPNO_HIDDEN_SSID 8 +#define MAX_WHITELIST_SSID 2 + +/* PFN network info structure */ +typedef struct wl_pfn_subnet_info { + struct ether_addr BSSID; + uint8 channel; /* channel number only */ + uint8 SSID_len; + uint8 SSID[32]; +} wl_pfn_subnet_info_t; + +typedef struct wl_pfn_net_info { + wl_pfn_subnet_info_t pfnsubnet; + int16 RSSI; /* receive signal strength (in dBm) */ + uint16 timestamp; /* age in seconds */ +} wl_pfn_net_info_t; + +typedef struct wl_pfn_lnet_info { + wl_pfn_subnet_info_t pfnsubnet; /* BSSID + channel + SSID len + SSID */ + uint16 flags; /* partial scan, etc */ + int16 RSSI; /* receive signal strength (in dBm) */ + uint32 timestamp; /* age in miliseconds */ + uint16 rtt0; /* estimated distance to this AP in centimeters */ + uint16 rtt1; /* standard deviation of the distance to this AP in centimeters */ +} wl_pfn_lnet_info_t; + +typedef struct wl_pfn_lscanresults { + uint32 version; + uint32 status; + uint32 count; + wl_pfn_lnet_info_t netinfo[1]; +} wl_pfn_lscanresults_t; + +typedef struct wl_pfn_scanresults { + uint32 version; + uint32 status; + uint32 count; + wl_pfn_net_info_t netinfo[1]; +} wl_pfn_scanresults_t; + +typedef struct wl_pfn_significant_net { + uint16 flags; + uint16 channel; + struct ether_addr BSSID; + int8 rssi[PFN_SWC_RSSI_WINDOW_MAX]; +} wl_pfn_significant_net_t; + +typedef struct wl_pfn_swc_results { + uint32 version; + uint32 pkt_count; + uint32 total_count; + wl_pfn_significant_net_t list[1]; +} wl_pfn_swc_results_t; + +/* PFN data structure */ +typedef struct wl_pfn_param { + int32 version; /* PNO parameters version */ + int32 scan_freq; /* Scan frequency */ + int32 lost_network_timeout; /* Timeout in sec. to declare + * discovered network as lost + */ + int16 flags; /* Bit field to control features + * of PFN such as sort criteria auto + * enable switch and background scan + */ + int16 rssi_margin; /* Margin to avoid jitter for choosing a + * PFN based on RSSI sort criteria + */ + uint8 bestn; /* number of best networks in each scan */ + uint8 mscan; /* number of scans recorded */ + uint8 repeat; /* Minimum number of scan intervals + *before scan frequency changes in adaptive scan + */ + uint8 exp; /* Exponent of 2 for maximum scan interval */ + int32 slow_freq; /* slow scan period */ +} wl_pfn_param_t; + +typedef struct wl_pfn_bssid { + struct ether_addr macaddr; + /* Bit4: suppress_lost, Bit3: suppress_found */ + uint16 flags; +} wl_pfn_bssid_t; + +typedef struct wl_pfn_significant_bssid { + struct ether_addr macaddr; + int8 rssi_low_threshold; + int8 rssi_high_threshold; +} wl_pfn_significant_bssid_t; + +#define WL_PFN_SUPPRESSFOUND_MASK 0x08 +#define WL_PFN_SUPPRESSLOST_MASK 0x10 +#define WL_PFN_RSSI_MASK 0xff00 +#define WL_PFN_RSSI_SHIFT 8 + +typedef struct wl_pfn_cfg { + uint32 reporttype; + int32 channel_num; + uint16 channel_list[WL_NUMCHANNELS]; + uint32 flags; +} wl_pfn_cfg_t; + +#define CH_BUCKET_REPORT_REGULAR 0 +#define CH_BUCKET_REPORT_FULL_RESULT 2 +#define CH_BUCKET_GSCAN 4 + +typedef struct wl_pfn_gscan_ch_bucket_cfg { + uint8 bucket_end_index; + uint8 bucket_freq_multiple; + uint8 flag; + uint8 reserved; + uint16 repeat; + uint16 max_freq_multiple; +} wl_pfn_gscan_ch_bucket_cfg_t; + +#define GSCAN_SEND_ALL_RESULTS_MASK (1 << 0) +#define GSCAN_CFG_FLAGS_ONLY_MASK (1 << 7) +#define WL_GSCAN_CFG_VERSION 2 +typedef struct wl_pfn_gscan_cfg { + uint16 version; + /* BIT0 1 = send probes/beacons to HOST + * BIT1 Reserved + * BIT2 Reserved + * Add any future flags here + * BIT7 1 = no other useful cfg sent + */ + uint8 flags; + /* Buffer filled threshold in % to generate an event */ + uint8 buffer_threshold; + /* No. of BSSIDs with "change" to generate an evt + * change - crosses rssi threshold/lost + */ + uint8 swc_nbssid_threshold; + /* Max=8 (for now) Size of rssi cache buffer */ + uint8 swc_rssi_window_size; + uint8 count_of_channel_buckets; + uint8 retry_threshold; + uint16 lost_ap_window; + wl_pfn_gscan_ch_bucket_cfg_t channel_bucket[1]; +} wl_pfn_gscan_cfg_t; + +#define WL_PFN_REPORT_ALLNET 0 +#define WL_PFN_REPORT_SSIDNET 1 +#define WL_PFN_REPORT_BSSIDNET 2 + +#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ +#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /* Remaining reserved for future use */ +#define WL_PFN_SSID_A_BAND_TRIG 0x20 +#define WL_PFN_SSID_BG_BAND_TRIG 0x40 +typedef struct wl_pfn { + wlc_ssid_t ssid; /* ssid name and its length */ + int32 flags; /* bit2: hidden */ + int32 infra; /* BSS Vs IBSS */ + int32 auth; /* Open Vs Closed */ + int32 wpa_auth; /* WPA type */ + int32 wsec; /* wsec value */ +} wl_pfn_t; + +typedef struct wl_pfn_list { + uint32 version; + uint32 enabled; + uint32 count; + wl_pfn_t pfn[1]; +} wl_pfn_list_t; + +#define PFN_SSID_EXT_VERSION 2 + +typedef struct wl_pfn_ext { + uint8 flags; + int8 rssi_thresh; /* RSSI threshold, track only if RSSI > threshold */ + uint16 wpa_auth; /* Match the wpa auth type defined in wlioctl_defs.h */ + uint8 ssid[DOT11_MAX_SSID_LEN]; + uint8 ssid_len; + uint8 pad; +} wl_pfn_ext_t; + +typedef struct wl_pfn_ext_list { + uint16 version; + uint16 count; + wl_pfn_ext_t pfn_ext[1]; +} wl_pfn_ext_list_t; + +#define WL_PFN_SSID_EXT_FOUND 0x1 +#define WL_PFN_SSID_EXT_LOST 0x2 +typedef struct wl_pfn_result_ssid { + uint8 flags; + int8 rssi; + /* channel number */ + uint16 channel; + /* Assume idx in order of cfg */ + uint16 index; + struct ether_addr bssid; +} wl_pfn_result_ssid_crc32_t; + +typedef struct wl_pfn_ssid_ext_result { + uint16 version; + uint16 count; + wl_pfn_result_ssid_crc32_t net[1]; +} wl_pfn_ssid_ext_result_t; + +#define PFN_EXT_AUTH_CODE_OPEN 1 /* open */ +#define PFN_EXT_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ +#define PFN_EXT_AUTH_CODE_EAPOL 4 /* any EAPOL */ + +#define WL_PFN_MAC_OUI_ONLY_MASK 1 +#define WL_PFN_SET_MAC_UNASSOC_MASK 2 +/* To configure pfn_macaddr */ +typedef struct wl_pfn_macaddr_cfg { + uint8 version; + uint8 flags; + struct ether_addr macaddr; +} wl_pfn_macaddr_cfg_t; +#define WL_PFN_MACADDR_CFG_VER 1 + +typedef BWL_PRE_PACKED_STRUCT struct pfn_olmsg_params_t { + wlc_ssid_t ssid; + uint32 cipher_type; + uint32 auth_type; + uint8 channels[4]; +} BWL_POST_PACKED_STRUCT pfn_olmsg_params; + +#define WL_PFN_HIDDEN_BIT 2 +#define WL_PFN_HIDDEN_MASK 0x4 + +#ifndef BESTN_MAX +#define BESTN_MAX 3 +#endif + +#ifndef MSCAN_MAX +#define MSCAN_MAX 90 +#endif + +/* Service discovery */ +typedef struct { + uint8 transaction_id; /* Transaction id */ + uint8 protocol; /* Service protocol type */ + uint16 query_len; /* Length of query */ + uint16 response_len; /* Length of response */ + uint8 qrbuf[1]; +} wl_p2po_qr_t; + +typedef struct { + uint16 period; /* extended listen period */ + uint16 interval; /* extended listen interval */ +} wl_p2po_listen_t; + +/* ANQP offload */ + +#define ANQPO_MAX_QUERY_SIZE 256 +typedef struct { + uint16 max_retransmit; /* ~0 use default, max retransmit on no ACK from peer */ + uint16 response_timeout; /* ~0 use default, msec to wait for resp after tx packet */ + uint16 max_comeback_delay; /* ~0 use default, max comeback delay in resp else fail */ + uint16 max_retries; /* ~0 use default, max retries on failure */ + uint16 query_len; /* length of ANQP query */ + uint8 query_data[1]; /* ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */ +} wl_anqpo_set_t; + +typedef struct { + uint16 channel; /* channel of the peer */ + struct ether_addr addr; /* addr of the peer */ +} wl_anqpo_peer_t; + +#define ANQPO_MAX_PEER_LIST 64 +typedef struct { + uint16 count; /* number of peers in list */ + wl_anqpo_peer_t peer[1]; /* max ANQPO_MAX_PEER_LIST */ +} wl_anqpo_peer_list_t; + +#define ANQPO_MAX_IGNORE_SSID 64 +typedef struct { + bool is_clear; /* set to clear list (not used on GET) */ + uint16 count; /* number of SSID in list */ + wlc_ssid_t ssid[1]; /* max ANQPO_MAX_IGNORE_SSID */ +} wl_anqpo_ignore_ssid_list_t; + +#define ANQPO_MAX_IGNORE_BSSID 64 +typedef struct { + bool is_clear; /* set to clear list (not used on GET) */ + uint16 count; /* number of addr in list */ + struct ether_addr bssid[1]; /* max ANQPO_MAX_IGNORE_BSSID */ +} wl_anqpo_ignore_bssid_list_t; + + +struct toe_ol_stats_t { + /* Num of tx packets that don't need to be checksummed */ + uint32 tx_summed; + + /* Num of tx packets where checksum is filled by offload engine */ + uint32 tx_iph_fill; + uint32 tx_tcp_fill; + uint32 tx_udp_fill; + uint32 tx_icmp_fill; + + /* Num of rx packets where toe finds out if checksum is good or bad */ + uint32 rx_iph_good; + uint32 rx_iph_bad; + uint32 rx_tcp_good; + uint32 rx_tcp_bad; + uint32 rx_udp_good; + uint32 rx_udp_bad; + uint32 rx_icmp_good; + uint32 rx_icmp_bad; + + /* Num of tx packets in which csum error is injected */ + uint32 tx_tcp_errinj; + uint32 tx_udp_errinj; + uint32 tx_icmp_errinj; + + /* Num of rx packets in which csum error is injected */ + uint32 rx_tcp_errinj; + uint32 rx_udp_errinj; + uint32 rx_icmp_errinj; +}; + +/* Arp offload statistic counts */ +struct arp_ol_stats_t { + uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ + uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ + + uint32 arp_table_entries; /* ARP table entries */ + uint32 arp_table_overflow; /* ARP table additions skipped due to overflow */ + + uint32 host_request; /* ARP requests from host */ + uint32 host_reply; /* ARP replies from host */ + uint32 host_service; /* ARP requests from host serviced by ARP Agent */ + + uint32 peer_request; /* ARP requests received from network */ + uint32 peer_request_drop; /* ARP requests from network that were dropped */ + uint32 peer_reply; /* ARP replies received from network */ + uint32 peer_reply_drop; /* ARP replies from network that were dropped */ + uint32 peer_service; /* ARP request from host serviced by ARP Agent */ +}; + +/* NS offload statistic counts */ +struct nd_ol_stats_t { + uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ + uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ + uint32 peer_request; /* NS requests received from network */ + uint32 peer_request_drop; /* NS requests from network that were dropped */ + uint32 peer_reply_drop; /* NA replies from network that were dropped */ + uint32 peer_service; /* NS request from host serviced by firmware */ +}; + +/* + * Keep-alive packet offloading. + */ + +/* NAT keep-alive packets format: specifies the re-transmission period, the packet + * length, and packet contents. + */ +typedef struct wl_keep_alive_pkt { + uint32 period_msec; /* Retransmission period (0 to disable packet re-transmits) */ + uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */ + uint8 data[1]; /* Variable length packet to transmit. Contents should include + * entire ethernet packet (enet header, IP header, UDP header, + * and UDP payload) in network byte order. + */ +} wl_keep_alive_pkt_t; + +#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) + + +/* + * Dongle pattern matching filter. + */ + +#define MAX_WAKE_PACKET_CACHE_BYTES 128 /* Maximum cached wake packet */ + +#define MAX_WAKE_PACKET_BYTES (DOT11_A3_HDR_LEN + \ + DOT11_QOS_LEN + \ + sizeof(struct dot11_llc_snap_header) + \ + ETHER_MAX_DATA) + +typedef struct pm_wake_packet { + uint32 status; /* Is the wake reason a packet (if all the other field's valid) */ + uint32 pattern_id; /* Pattern ID that matched */ + uint32 original_packet_size; + uint32 saved_packet_size; + uchar packet[MAX_WAKE_PACKET_CACHE_BYTES]; +} pm_wake_packet_t; + +/* Packet filter types. Currently, only pattern matching is supported. */ +typedef enum wl_pkt_filter_type { + WL_PKT_FILTER_TYPE_PATTERN_MATCH=0, /* Pattern matching filter */ + WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH=1, /* Magic packet match */ + WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH=2 /* A pattern list (match all to match filter) */ +} wl_pkt_filter_type_t; + +#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t + +/* String mapping for types that may be used by applications or debug */ +#define WL_PKT_FILTER_TYPE_NAMES \ + { "PATTERN", WL_PKT_FILTER_TYPE_PATTERN_MATCH }, \ + { "MAGIC", WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH }, \ + { "PATLIST", WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH } + +/* 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. + */ +typedef struct wl_pkt_filter_pattern { + uint32 offset; /* Offset within received packet to start pattern matching. + * Offset '0' is the first byte of the ethernet header. + */ + uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ + uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts + * at offset 0. Pattern immediately follows mask. + */ +} wl_pkt_filter_pattern_t; + +/* A pattern list is a numerically specified list of modified pattern structures. */ +typedef struct wl_pkt_filter_pattern_listel { + uint16 rel_offs; /* Offset to begin match (relative to 'base' below) */ + uint16 base_offs; /* Base for offset (defined below) */ + uint16 size_bytes; /* Size of mask/pattern */ + uint16 match_flags; /* Addition flags controlling the match */ + uint8 mask_and_data[1]; /* Variable length mask followed by data, each size_bytes */ +} wl_pkt_filter_pattern_listel_t; + +typedef struct wl_pkt_filter_pattern_list { + uint8 list_cnt; /* Number of elements in the list */ + uint8 PAD1[1]; /* Reserved (possible version: reserved) */ + uint16 totsize; /* Total size of this pattern list (includes this struct) */ + wl_pkt_filter_pattern_listel_t patterns[1]; /* Variable number of list elements */ +} wl_pkt_filter_pattern_list_t; + +/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ +typedef struct wl_pkt_filter { + uint32 id; /* Unique filter id, specified by app. */ + uint32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ + uint32 negate_match; /* Negate the result of filter matches */ + union { /* Filter definitions */ + wl_pkt_filter_pattern_t pattern; /* Pattern matching filter */ + wl_pkt_filter_pattern_list_t patlist; /* List of patterns to match */ + } u; +} wl_pkt_filter_t; + +/* IOVAR "tcp_keep_set" parameter. Used to install tcp keep_alive stuff. */ +typedef struct wl_tcp_keep_set { + uint32 val1; + uint32 val2; +} wl_tcp_keep_set_t; + +#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) +#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) +#define WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_list_t, patterns) +#define WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN \ + OFFSETOF(wl_pkt_filter_pattern_listel_t, mask_and_data) + +/* IOVAR "pkt_filter_enable" parameter. */ +typedef struct wl_pkt_filter_enable { + uint32 id; /* Unique filter id */ + uint32 enable; /* Enable/disable bool */ +} wl_pkt_filter_enable_t; + +/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ +typedef struct wl_pkt_filter_list { + uint32 num; /* Number of installed packet filters */ + wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */ +} wl_pkt_filter_list_t; + +#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) + +/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ +typedef struct wl_pkt_filter_stats { + uint32 num_pkts_matched; /* # filter matches for specified filter id */ + uint32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */ + uint32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ +} wl_pkt_filter_stats_t; + +/* IOVAR "pkt_filter_ports" parameter. Configure TCP/UDP port filters. */ +typedef struct wl_pkt_filter_ports { + uint8 version; /* Be proper */ + uint8 reserved; /* Be really proper */ + uint16 count; /* Number of ports following */ + /* End of fixed data */ + uint16 ports[1]; /* Placeholder for ports[] */ +} wl_pkt_filter_ports_t; + +#define WL_PKT_FILTER_PORTS_FIXED_LEN OFFSETOF(wl_pkt_filter_ports_t, ports) + +#define WL_PKT_FILTER_PORTS_VERSION 0 +#define WL_PKT_FILTER_PORTS_MAX 128 + +#define RSN_KCK_LENGTH 16 +#define RSN_KEK_LENGTH 16 +#define RSN_REPLAY_LEN 8 +typedef struct _gtkrefresh { + uchar KCK[RSN_KCK_LENGTH]; + uchar KEK[RSN_KEK_LENGTH]; + uchar ReplayCounter[RSN_REPLAY_LEN]; +} gtk_keyinfo_t, *pgtk_keyinfo_t; + +/* Sequential Commands ioctl */ +typedef struct wl_seq_cmd_ioctl { + uint32 cmd; /* common ioctl definition */ + uint32 len; /* length of user buffer */ +} wl_seq_cmd_ioctl_t; + +#define WL_SEQ_CMD_ALIGN_BYTES 4 + +/* These are the set of get IOCTLs that should be allowed when using + * IOCTL sequence commands. These are issued implicitly by wl.exe each time + * it is invoked. We never want to buffer these, or else wl.exe will stop working. + */ +#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ + (((cmd) == WLC_GET_MAGIC) || \ + ((cmd) == WLC_GET_VERSION) || \ + ((cmd) == WLC_GET_AP) || \ + ((cmd) == WLC_GET_INSTANCE)) + +typedef struct wl_pkteng { + uint32 flags; + uint32 delay; /* Inter-packet delay */ + uint32 nframes; /* Number of frames */ + uint32 length; /* Packet length */ + uint8 seqno; /* Enable/disable sequence no. */ + struct ether_addr dest; /* Destination address */ + struct ether_addr src; /* Source address */ +} wl_pkteng_t; + +typedef struct wl_pkteng_stats { + uint32 lostfrmcnt; /* RX PER test: no of frames lost (skip seqno) */ + int32 rssi; /* RSSI */ + int32 snr; /* signal to noise ratio */ + uint16 rxpktcnt[NUM_80211_RATES+1]; + uint8 rssi_qdb; /* qdB portion of the computed rssi */ +} wl_pkteng_stats_t; + + +typedef enum { + wowl_pattern_type_bitmap = 0, + wowl_pattern_type_arp, + wowl_pattern_type_na +} wowl_pattern_type_t; + +typedef struct wl_wowl_pattern { + uint32 masksize; /* Size of the mask in #of bytes */ + uint32 offset; /* Pattern byte offset in packet */ + uint32 patternoffset; /* Offset of start of pattern in the structure */ + uint32 patternsize; /* Size of the pattern itself in #of bytes */ + uint32 id; /* id */ + uint32 reasonsize; /* Size of the wakeup reason code */ + wowl_pattern_type_t type; /* Type of pattern */ + /* Mask follows the structure above */ + /* Pattern follows the mask is at 'patternoffset' from the start */ +} wl_wowl_pattern_t; + +typedef struct wl_wowl_pattern_list { + uint count; + wl_wowl_pattern_t pattern[1]; +} wl_wowl_pattern_list_t; + +typedef struct wl_wowl_wakeind { + uint8 pci_wakeind; /* Whether PCI PMECSR PMEStatus bit was set */ + uint32 ucode_wakeind; /* What wakeup-event indication was set by ucode */ +} wl_wowl_wakeind_t; + +typedef struct { + uint32 pktlen; /* size of packet */ + void *sdu; +} tcp_keepalive_wake_pkt_infop_t; + +/* per AC rate control related data structure */ +typedef struct wl_txrate_class { + uint8 init_rate; + uint8 min_rate; + uint8 max_rate; +} wl_txrate_class_t; + +/* structure for Overlap BSS scan arguments */ +typedef struct wl_obss_scan_arg { + int16 passive_dwell; + int16 active_dwell; + int16 bss_widthscan_interval; + int16 passive_total; + int16 active_total; + int16 chanwidth_transition_delay; + int16 activity_threshold; +} wl_obss_scan_arg_t; + +#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) + +/* RSSI event notification configuration. */ +typedef struct wl_rssi_event { + uint32 rate_limit_msec; /* # of events posted to application will be limited to + * one per specified period (0 to disable rate limit). + */ + uint8 num_rssi_levels; /* Number of entries in rssi_levels[] below */ + int8 rssi_levels[MAX_RSSI_LEVELS]; /* Variable number of RSSI levels. An event + * will be posted each time the RSSI of received + * beacons/packets crosses a level. + */ +} wl_rssi_event_t; + +#define RSSI_MONITOR_VERSION 1 +#define RSSI_MONITOR_STOP (1 << 0) +typedef struct wl_rssi_monitor_cfg { + uint8 version; + uint8 flags; + int8 max_rssi; + int8 min_rssi; +} wl_rssi_monitor_cfg_t; + +typedef struct wl_rssi_monitor_evt { + uint8 version; + int8 cur_rssi; + uint16 pad; +} wl_rssi_monitor_evt_t; + +typedef struct wl_action_obss_coex_req { + uint8 info; + uint8 num; + uint8 ch_list[1]; +} wl_action_obss_coex_req_t; + + +/* IOVar parameter block for small MAC address array with type indicator */ +#define WL_IOV_MAC_PARAM_LEN 4 + +#define WL_IOV_PKTQ_LOG_PRECS 16 + +typedef struct { + uint32 num_addrs; + char addr_type[WL_IOV_MAC_PARAM_LEN]; + struct ether_addr ea[WL_IOV_MAC_PARAM_LEN]; +} wl_iov_mac_params_t; + +/* This is extra info that follows wl_iov_mac_params_t */ +typedef struct { + uint32 addr_info[WL_IOV_MAC_PARAM_LEN]; +} wl_iov_mac_extra_params_t; + +/* Combined structure */ +typedef struct { + wl_iov_mac_params_t params; + wl_iov_mac_extra_params_t extra_params; +} wl_iov_mac_full_params_t; + +/* Parameter block for PKTQ_LOG statistics */ +#define PKTQ_LOG_COUNTERS_V4 \ + /* packets requested to be stored */ \ + uint32 requested; \ + /* packets stored */ \ + uint32 stored; \ + /* packets saved, because a lowest priority queue has given away one packet */ \ + uint32 saved; \ + /* packets saved, because an older packet from the same queue has been dropped */ \ + uint32 selfsaved; \ + /* packets dropped, because pktq is full with higher precedence packets */ \ + uint32 full_dropped; \ + /* packets dropped because pktq per that precedence is full */ \ + uint32 dropped; \ + /* packets dropped, in order to save one from a queue of a highest priority */ \ + uint32 sacrificed; \ + /* packets droped because of hardware/transmission error */ \ + uint32 busy; \ + /* packets re-sent because they were not received */ \ + uint32 retry; \ + /* packets retried again (ps pretend) prior to moving power save mode */ \ + uint32 ps_retry; \ + /* suppressed packet count */ \ + uint32 suppress; \ + /* packets finally dropped after retry limit */ \ + uint32 retry_drop; \ + /* the high-water mark of the queue capacity for packets - goes to zero as queue fills */ \ + uint32 max_avail; \ + /* the high-water mark of the queue utilisation for packets - ('inverse' of max_avail) */ \ + uint32 max_used; \ + /* the maximum capacity of the queue */ \ + uint32 queue_capacity; \ + /* count of rts attempts that failed to receive cts */ \ + uint32 rtsfail; \ + /* count of packets sent (acked) successfully */ \ + uint32 acked; \ + /* running total of phy rate of packets sent successfully */ \ + uint32 txrate_succ; \ + /* running total of phy 'main' rate */ \ + uint32 txrate_main; \ + /* actual data transferred successfully */ \ + uint32 throughput; \ + /* time difference since last pktq_stats */ \ + uint32 time_delta; + +typedef struct { + PKTQ_LOG_COUNTERS_V4 +} pktq_log_counters_v04_t; + +/* v5 is the same as V4 with extra parameter */ +typedef struct { + PKTQ_LOG_COUNTERS_V4 + /* cumulative time to transmit */ + uint32 airtime; +} pktq_log_counters_v05_t; + +typedef struct { + uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; + pktq_log_counters_v04_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; + uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; + uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; + char headings[1]; +} pktq_log_format_v04_t; + +typedef struct { + uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; + pktq_log_counters_v05_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; + uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; + uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; + char headings[1]; +} pktq_log_format_v05_t; + + +typedef struct { + uint32 version; + wl_iov_mac_params_t params; + union { + pktq_log_format_v04_t v04; + pktq_log_format_v05_t v05; + } pktq_log; +} wl_iov_pktq_log_t; + +/* PKTQ_LOG_AUTO, PKTQ_LOG_DEF_PREC flags introduced in v05, they are ignored by v04 */ +#define PKTQ_LOG_AUTO (1 << 31) +#define PKTQ_LOG_DEF_PREC (1 << 30) + +/* + * SCB_BS_DATA iovar definitions start. + */ +#define SCB_BS_DATA_STRUCT_VERSION 1 + +/* The actual counters maintained for each station */ +typedef BWL_PRE_PACKED_STRUCT struct { + /* The following counters are a subset of what pktq_stats provides per precedence. */ + uint32 retry; /* packets re-sent because they were not received */ + uint32 retry_drop; /* packets finally dropped after retry limit */ + uint32 rtsfail; /* count of rts attempts that failed to receive cts */ + uint32 acked; /* count of packets sent (acked) successfully */ + uint32 txrate_succ; /* running total of phy rate of packets sent successfully */ + uint32 txrate_main; /* running total of phy 'main' rate */ + uint32 throughput; /* actual data transferred successfully */ + uint32 time_delta; /* time difference since last pktq_stats */ + uint32 airtime; /* cumulative total medium access delay in useconds */ +} BWL_POST_PACKED_STRUCT iov_bs_data_counters_t; + +/* The structure for individual station information. */ +typedef BWL_PRE_PACKED_STRUCT struct { + struct ether_addr station_address; /* The station MAC address */ + uint16 station_flags; /* Bit mask of flags, for future use. */ + iov_bs_data_counters_t station_counters; /* The actual counter values */ +} BWL_POST_PACKED_STRUCT iov_bs_data_record_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 structure_version; /* Structure version number (for wl/wlu matching) */ + uint16 structure_count; /* Number of iov_bs_data_record_t records following */ + iov_bs_data_record_t structure_record[1]; /* 0 - structure_count records */ +} BWL_POST_PACKED_STRUCT iov_bs_data_struct_t; + +/* Bitmask of options that can be passed in to the iovar. */ +enum { + SCB_BS_DATA_FLAG_NO_RESET = (1<<0) /* Do not clear the counters after reading */ +}; +/* + * SCB_BS_DATA iovar definitions end. + */ + +typedef struct wlc_extlog_cfg { + int max_number; + uint16 module; /* bitmap */ + uint8 level; + uint8 flag; + uint16 version; +} wlc_extlog_cfg_t; + +typedef struct log_record { + uint32 time; + uint16 module; + uint16 id; + uint8 level; + uint8 sub_unit; + uint8 seq_num; + int32 arg; + char str[MAX_ARGSTR_LEN]; +} log_record_t; + +typedef struct wlc_extlog_req { + uint32 from_last; + uint32 num; +} wlc_extlog_req_t; + +typedef struct wlc_extlog_results { + uint16 version; + uint16 record_len; + uint32 num; + log_record_t logs[1]; +} wlc_extlog_results_t; + +typedef struct log_idstr { + uint16 id; + uint16 flag; + uint8 arg_type; + const char *fmt_str; +} log_idstr_t; + +#define FMTSTRF_USER 1 + +/* flat ID definitions + * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will + * affect backward compatibility with pre-existing apps + */ +typedef enum { + FMTSTR_DRIVER_UP_ID = 0, + FMTSTR_DRIVER_DOWN_ID = 1, + FMTSTR_SUSPEND_MAC_FAIL_ID = 2, + FMTSTR_NO_PROGRESS_ID = 3, + FMTSTR_RFDISABLE_ID = 4, + FMTSTR_REG_PRINT_ID = 5, + FMTSTR_EXPTIME_ID = 6, + FMTSTR_JOIN_START_ID = 7, + FMTSTR_JOIN_COMPLETE_ID = 8, + FMTSTR_NO_NETWORKS_ID = 9, + FMTSTR_SECURITY_MISMATCH_ID = 10, + FMTSTR_RATE_MISMATCH_ID = 11, + FMTSTR_AP_PRUNED_ID = 12, + FMTSTR_KEY_INSERTED_ID = 13, + FMTSTR_DEAUTH_ID = 14, + FMTSTR_DISASSOC_ID = 15, + FMTSTR_LINK_UP_ID = 16, + FMTSTR_LINK_DOWN_ID = 17, + FMTSTR_RADIO_HW_OFF_ID = 18, + FMTSTR_RADIO_HW_ON_ID = 19, + FMTSTR_EVENT_DESC_ID = 20, + FMTSTR_PNP_SET_POWER_ID = 21, + FMTSTR_RADIO_SW_OFF_ID = 22, + FMTSTR_RADIO_SW_ON_ID = 23, + FMTSTR_PWD_MISMATCH_ID = 24, + FMTSTR_FATAL_ERROR_ID = 25, + FMTSTR_AUTH_FAIL_ID = 26, + FMTSTR_ASSOC_FAIL_ID = 27, + FMTSTR_IBSS_FAIL_ID = 28, + FMTSTR_EXTAP_FAIL_ID = 29, + FMTSTR_MAX_ID +} log_fmtstr_id_t; + +#ifdef DONGLEOVERLAYS +typedef struct { + uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */ + uint32 offset; /* offset into overlay region to write code */ + uint32 len; /* overlay code len */ + /* overlay code follows this struct */ +} wl_ioctl_overlay_t; +#endif /* DONGLEOVERLAYS */ + +/* 11k Neighbor Report element */ +typedef struct nbr_element { + uint8 id; + uint8 len; + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; + uint8 channel; + uint8 phytype; + uint8 pad; +} nbr_element_t; + +typedef enum event_msgs_ext_command { + EVENTMSGS_NONE = 0, + EVENTMSGS_SET_BIT = 1, + EVENTMSGS_RESET_BIT = 2, + EVENTMSGS_SET_MASK = 3 +} event_msgs_ext_command_t; + +#define EVENTMSGS_VER 1 +#define EVENTMSGS_EXT_STRUCT_SIZE OFFSETOF(eventmsgs_ext_t, mask[0]) + +/* len- for SET it would be mask size from the application to the firmware */ +/* for GET it would be actual firmware mask size */ +/* maxgetsize - is only used for GET. indicate max mask size that the */ +/* application can read from the firmware */ +typedef struct eventmsgs_ext +{ + uint8 ver; + uint8 command; + uint8 len; + uint8 maxgetsize; + uint8 mask[1]; +} eventmsgs_ext_t; +/* no default structure packing */ +#include + +typedef struct keepalives_max_idle { + uint16 keepalive_count; /* nmbr of keepalives per bss_max_idle period */ + uint8 mkeepalive_index; /* mkeepalive_index for keepalive frame to be used */ + uint8 PAD; /* to align next field */ + uint16 max_interval; /* seconds */ +} keepalives_max_idle_t; + +#define PM_IGNORE_BCMC_PROXY_ARP (1 << 0) +#define PM_IGNORE_BCMC_ALL_DMS_ACCEPTED (1 << 1) + +/* require strict packing */ +#include + + +/* Structures and constants used for "vndr_ie" IOVar interface */ +#define VNDR_IE_CMD_LEN 4 /* length of the set command string: + * "add", "del" (+ NUL) + */ + +#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ + vndr_ie_t vndr_ie_data; /* vendor IE data */ +} BWL_POST_PACKED_STRUCT vndr_ie_info_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + int iecount; /* number of entries in the vndr_ie_list[] array */ + vndr_ie_info_t vndr_ie_list[1]; /* variable size list of vndr_ie_info_t structs */ +} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + char cmd[VNDR_IE_CMD_LEN]; /* vndr_ie IOVar set command : "add", "del" + NUL */ + vndr_ie_buf_t vndr_ie_buffer; /* buffer containing Vendor IE list information */ +} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; + +/* tag_ID/length/value_buffer tuple */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 id; + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT tlv_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ + tlv_t ie_data; /* IE data */ +} BWL_POST_PACKED_STRUCT ie_info_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + int iecount; /* number of entries in the ie_list[] array */ + ie_info_t ie_list[1]; /* variable size list of ie_info_t structs */ +} BWL_POST_PACKED_STRUCT ie_buf_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + char cmd[VNDR_IE_CMD_LEN]; /* ie IOVar set command : "add" + NUL */ + ie_buf_t ie_buffer; /* buffer containing IE list information */ +} BWL_POST_PACKED_STRUCT ie_setbuf_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ + uint8 id; /* IE type */ +} BWL_POST_PACKED_STRUCT ie_getbuf_t; + +/* structures used to define format of wps ie data from probe requests */ +/* passed up to applications via iovar "prbreq_wpsie" */ +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr { + struct ether_addr staAddr; + uint16 ieLen; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t; + +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { + sta_prbreq_wps_ie_hdr_t hdr; + uint8 ieData[1]; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; + +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { + uint32 totLen; + uint8 ieDataList[1]; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; + + +#ifdef WLMEDIA_TXFAILEVENT +typedef BWL_PRE_PACKED_STRUCT struct { + char dest[ETHER_ADDR_LEN]; /* destination MAC */ + uint8 prio; /* Packet Priority */ + uint8 flags; /* Flags */ + uint32 tsf_l; /* TSF timer low */ + uint32 tsf_h; /* TSF timer high */ + uint16 rates; /* Main Rates */ + uint16 txstatus; /* TX Status */ +} BWL_POST_PACKED_STRUCT txfailinfo_t; +#endif /* WLMEDIA_TXFAILEVENT */ + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint8 local_max; /* local max according to the AP */ + uint8 local_constraint; /* local constraint according to the AP */ + int8 antgain[2]; /* Ant gain for each band - from SROM */ + uint8 rf_cores; /* count of RF Cores being reported */ + uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ + uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain w/o adjustment */ + uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ + uint8 tx_power_max[4]; /* Maximum target power among all rates */ + uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ + int8 clm_limits[WL_NUMRATES]; /* regulatory limits - 20, 40 or 80MHz */ + int8 clm_limits_subchan1[WL_NUMRATES]; /* regulatory limits - 20in40 or 40in80 */ + int8 clm_limits_subchan2[WL_NUMRATES]; /* regulatory limits - 20in80MHz */ + int8 sar; /* SAR limit for display by wl executable */ + int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ + uint8 version; /* Version of the data format wlu <--> driver */ + uint8 display_core; /* Displayed curpower core */ + int8 target_offsets[4]; /* Target power offsets for current rate per core */ + uint32 last_tx_ratespec; /* Ratespec for last transmition */ + uint user_target; /* user limit */ + uint32 board_limit_len; /* length of board limit buffer */ + uint32 target_len; /* length of target power buffer */ + int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; + uint8 pprdata[1]; /* ppr serialization buffer */ +} BWL_POST_PACKED_STRUCT tx_pwr_rpt_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + struct ipv4_addr ipv4_addr; + struct ether_addr nexthop; +} BWL_POST_PACKED_STRUCT ibss_route_entry_t; +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 num_entry; + ibss_route_entry_t route_entry[1]; +} BWL_POST_PACKED_STRUCT ibss_route_tbl_t; + +#define MAX_IBSS_ROUTE_TBL_ENTRY 64 + +#define TXPWR_TARGET_VERSION 0 +typedef BWL_PRE_PACKED_STRUCT struct { + int32 version; /* version number */ + chanspec_t chanspec; /* txpwr report for this channel */ + int8 txpwr[WL_STA_ANT_MAX]; /* Max tx target power, in qdb */ + uint8 rf_cores; /* count of RF Cores being reported */ +} BWL_POST_PACKED_STRUCT txpwr_target_max_t; + +#define BSS_PEER_INFO_PARAM_CUR_VER 0 +/* Input structure for IOV_BSS_PEER_INFO */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + struct ether_addr ea; /* peer MAC address */ +} BWL_POST_PACKED_STRUCT bss_peer_info_param_t; + +#define BSS_PEER_INFO_CUR_VER 0 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + struct ether_addr ea; + int32 rssi; + uint32 tx_rate; /* current tx rate */ + uint32 rx_rate; /* current rx rate */ + wl_rateset_t rateset; /* rateset in use */ + uint32 age; /* age in seconds */ +} BWL_POST_PACKED_STRUCT bss_peer_info_t; + +#define BSS_PEER_LIST_INFO_CUR_VER 0 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 bss_peer_info_len; /* length of bss_peer_info_t */ + uint32 count; /* number of peer info */ + bss_peer_info_t peer_info[1]; /* peer info */ +} BWL_POST_PACKED_STRUCT bss_peer_list_info_t; + +#define BSS_PEER_LIST_INFO_FIXED_LEN OFFSETOF(bss_peer_list_info_t, peer_info) + +#define AIBSS_BCN_FORCE_CONFIG_VER_0 0 + +/* structure used to configure AIBSS beacon force xmit */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 len; + uint32 initial_min_bcn_dur; /* dur in ms to check a bcn in bcn_flood period */ + uint32 min_bcn_dur; /* dur in ms to check a bcn after bcn_flood period */ + uint32 bcn_flood_dur; /* Initial bcn xmit period in ms */ +} BWL_POST_PACKED_STRUCT aibss_bcn_force_config_t; + +#define AIBSS_TXFAIL_CONFIG_VER_0 0 + +/* structure used to configure aibss tx fail event */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 len; + uint32 bcn_timeout; /* dur in seconds to receive 1 bcn */ + uint32 max_tx_retry; /* no of consecutive no acks to send txfail event */ +} BWL_POST_PACKED_STRUCT aibss_txfail_config_t; + +/* no strict structure packing */ +#include + + /* Global ASSERT Logging */ +#define ASSERTLOG_CUR_VER 0x0100 +#define MAX_ASSRTSTR_LEN 64 + + typedef struct assert_record { + uint32 time; + uint8 seq_num; + char str[MAX_ASSRTSTR_LEN]; + } assert_record_t; + + typedef struct assertlog_results { + uint16 version; + uint16 record_len; + uint32 num; + assert_record_t logs[1]; + } assertlog_results_t; + +#define LOGRRC_FIX_LEN 8 +#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) + +#ifdef BCMWAPI_WAI +#define IV_LEN 16 + struct wapi_sta_msg_t + { + uint16 msg_type; + uint16 datalen; + uint8 vap_mac[6]; + uint8 reserve_data1[2]; + uint8 sta_mac[6]; + uint8 reserve_data2[2]; + uint8 gsn[IV_LEN]; + uint8 wie[256]; + }; +#endif /* BCMWAPI_WAI */ + + /* chanim acs record */ + typedef struct { + bool valid; + uint8 trigger; + chanspec_t selected_chspc; + int8 bgnoise; + uint32 glitch_cnt; + uint8 ccastats; + uint timestamp; + } chanim_acs_record_t; + + typedef struct { + chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; + uint8 count; + uint timestamp; + } wl_acs_record_t; + + typedef struct chanim_stats { + uint32 glitchcnt; /* normalized as per second count */ + uint32 badplcp; /* normalized as per second count */ + uint8 ccastats[CCASTATS_MAX]; /* normalized as 0-255 */ + int8 bgnoise; /* background noise level (in dBm) */ + chanspec_t chanspec; + uint32 timestamp; + uint32 bphy_glitchcnt; /* normalized as per second count */ + uint32 bphy_badplcp; /* normalized as per second count */ + uint8 chan_idle; /* normalized as 0~255 */ + } chanim_stats_t; + +#define WL_CHANIM_STATS_VERSION 2 + +typedef struct { + uint32 buflen; + uint32 version; + uint32 count; + chanim_stats_t stats[1]; +} wl_chanim_stats_t; + +#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats) + +/* Noise measurement metrics. */ +#define NOISE_MEASURE_KNOISE 0x1 + +/* scb probe parameter */ +typedef struct { + uint32 scb_timeout; + uint32 scb_activity_time; + uint32 scb_max_probe; +} wl_scb_probe_t; + +/* structure/defines for selective mgmt frame (smf) stats support */ + +#define SMFS_VERSION 1 +/* selected mgmt frame (smf) stats element */ +typedef struct wl_smfs_elem { + uint32 count; + uint16 code; /* SC or RC code */ +} wl_smfs_elem_t; + +typedef struct wl_smf_stats { + uint32 version; + uint16 length; /* reserved for future usage */ + uint8 type; + uint8 codetype; + uint32 ignored_cnt; + uint32 malformed_cnt; + uint32 count_total; /* count included the interested group */ + wl_smfs_elem_t elem[1]; +} wl_smf_stats_t; + +#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); + +enum { + SMFS_CODETYPE_SC, + SMFS_CODETYPE_RC +}; + +typedef enum smfs_type { + SMFS_TYPE_AUTH, + SMFS_TYPE_ASSOC, + SMFS_TYPE_REASSOC, + SMFS_TYPE_DISASSOC_TX, + SMFS_TYPE_DISASSOC_RX, + SMFS_TYPE_DEAUTH_TX, + SMFS_TYPE_DEAUTH_RX, + SMFS_TYPE_MAX +} smfs_type_t; + +#ifdef PHYMON + +#define PHYMON_VERSION 1 + +typedef struct wl_phycal_core_state { + /* Tx IQ/LO calibration coeffs */ + int16 tx_iqlocal_a; + int16 tx_iqlocal_b; + int8 tx_iqlocal_ci; + int8 tx_iqlocal_cq; + int8 tx_iqlocal_di; + int8 tx_iqlocal_dq; + int8 tx_iqlocal_ei; + int8 tx_iqlocal_eq; + int8 tx_iqlocal_fi; + int8 tx_iqlocal_fq; + + /* Rx IQ calibration coeffs */ + int16 rx_iqcal_a; + int16 rx_iqcal_b; + + uint8 tx_iqlocal_pwridx; /* Tx Power Index for Tx IQ/LO calibration */ + uint32 papd_epsilon_table[64]; /* PAPD epsilon table */ + int16 papd_epsilon_offset; /* PAPD epsilon offset */ + uint8 curr_tx_pwrindex; /* Tx power index */ + int8 idle_tssi; /* Idle TSSI */ + int8 est_tx_pwr; /* Estimated Tx Power (dB) */ + int8 est_rx_pwr; /* Estimated Rx Power (dB) from RSSI */ + uint16 rx_gaininfo; /* Rx gain applied on last Rx pkt */ + uint16 init_gaincode; /* initgain required for ACI */ + int8 estirr_tx; + int8 estirr_rx; + +} wl_phycal_core_state_t; + +typedef struct wl_phycal_state { + int version; + int8 num_phy_cores; /* number of cores */ + int8 curr_temperature; /* on-chip temperature sensor reading */ + chanspec_t chspec; /* channspec for this state */ + bool aci_state; /* ACI state: ON/OFF */ + uint16 crsminpower; /* crsminpower required for ACI */ + uint16 crsminpowerl; /* crsminpowerl required for ACI */ + uint16 crsminpoweru; /* crsminpoweru required for ACI */ + wl_phycal_core_state_t phycal_core[1]; +} wl_phycal_state_t; + +#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) +#endif /* PHYMON */ + +/* discovery state */ +typedef struct wl_p2p_disc_st { + uint8 state; /* see state */ + chanspec_t chspec; /* valid in listen state */ + uint16 dwell; /* valid in listen state, in ms */ +} wl_p2p_disc_st_t; + +/* scan request */ +typedef struct wl_p2p_scan { + uint8 type; /* 'S' for WLC_SCAN, 'E' for "escan" */ + uint8 reserved[3]; + /* scan or escan parms... */ +} wl_p2p_scan_t; + +/* i/f request */ +typedef struct wl_p2p_if { + struct ether_addr addr; + uint8 type; /* see i/f type */ + chanspec_t chspec; /* for p2p_ifadd GO */ +} wl_p2p_if_t; + +/* i/f query */ +typedef struct wl_p2p_ifq { + uint bsscfgidx; + char ifname[BCM_MSG_IFNAME_MAX]; +} wl_p2p_ifq_t; + +/* OppPS & CTWindow */ +typedef struct wl_p2p_ops { + uint8 ops; /* 0: disable 1: enable */ + uint8 ctw; /* >= 10 */ +} wl_p2p_ops_t; + +/* absence and presence request */ +typedef struct wl_p2p_sched_desc { + uint32 start; + uint32 interval; + uint32 duration; + uint32 count; /* see count */ +} wl_p2p_sched_desc_t; + +typedef struct wl_p2p_sched { + uint8 type; /* see schedule type */ + uint8 action; /* see schedule action */ + uint8 option; /* see schedule option */ + wl_p2p_sched_desc_t desc[1]; +} wl_p2p_sched_t; + +typedef struct wl_bcmdcs_data { + uint reason; + chanspec_t chspec; +} wl_bcmdcs_data_t; + + +/* NAT configuration */ +typedef struct { + uint32 ipaddr; /* interface ip address */ + uint32 ipaddr_mask; /* interface ip address mask */ + uint32 ipaddr_gateway; /* gateway ip address */ + uint8 mac_gateway[6]; /* gateway mac address */ + uint32 ipaddr_dns; /* DNS server ip address, valid only for public if */ + uint8 mac_dns[6]; /* DNS server mac address, valid only for public if */ + uint8 GUID[38]; /* interface GUID */ +} nat_if_info_t; + +typedef struct { + uint op; /* operation code */ + bool pub_if; /* set for public if, clear for private if */ + nat_if_info_t if_info; /* interface info */ +} nat_cfg_t; + +typedef struct { + int state; /* NAT state returned */ +} nat_state_t; + + +#define BTA_STATE_LOG_SZ 64 + +/* BTAMP Statemachine states */ +enum { + HCIReset = 1, + HCIReadLocalAMPInfo, + HCIReadLocalAMPASSOC, + HCIWriteRemoteAMPASSOC, + HCICreatePhysicalLink, + HCIAcceptPhysicalLinkRequest, + HCIDisconnectPhysicalLink, + HCICreateLogicalLink, + HCIAcceptLogicalLink, + HCIDisconnectLogicalLink, + HCILogicalLinkCancel, + HCIAmpStateChange, + HCIWriteLogicalLinkAcceptTimeout +}; + +typedef struct flush_txfifo { + uint32 txfifobmp; + uint32 hwtxfifoflush; + struct ether_addr ea; +} flush_txfifo_t; + +enum { + SPATIAL_MODE_2G_IDX = 0, + SPATIAL_MODE_5G_LOW_IDX, + SPATIAL_MODE_5G_MID_IDX, + SPATIAL_MODE_5G_HIGH_IDX, + SPATIAL_MODE_5G_UPPER_IDX, + SPATIAL_MODE_MAX_IDX +}; + +#define WLC_TXCORE_MAX 4 /* max number of txcore supports */ +#define WLC_SUBBAND_MAX 4 /* max number of sub-band supports */ +typedef struct { + uint8 band2g[WLC_TXCORE_MAX]; + uint8 band5g[WLC_SUBBAND_MAX][WLC_TXCORE_MAX]; +} sar_limit_t; + +/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ +typedef struct wl_mempool_stats { + int num; /* Number of memory pools */ + bcm_mp_stats_t s[1]; /* Variable array of memory pool stats. */ +} wl_mempool_stats_t; + +typedef struct { + uint32 ipaddr; + uint32 ipaddr_netmask; + uint32 ipaddr_gateway; +} nwoe_ifconfig_t; + +/* Traffic management priority classes */ +typedef enum trf_mgmt_priority_class { + trf_mgmt_priority_low = 0, /* Maps to 802.1p BK */ + trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ + trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ + trf_mgmt_priority_nochange = 3, /* do not update the priority */ + trf_mgmt_priority_invalid = (trf_mgmt_priority_nochange + 1) +} trf_mgmt_priority_class_t; + +/* Traffic management configuration parameters */ +typedef struct trf_mgmt_config { + uint32 trf_mgmt_enabled; /* 0 - disabled, 1 - enabled */ + uint32 flags; /* See TRF_MGMT_FLAG_xxx defines */ + uint32 host_ip_addr; /* My IP address to determine subnet */ + uint32 host_subnet_mask; /* My subnet mask */ + uint32 downlink_bandwidth; /* In units of kbps */ + uint32 uplink_bandwidth; /* In units of kbps */ + uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed tx bandwidth */ + uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed rx bandwidth */ +} trf_mgmt_config_t; + +/* Traffic management filter */ +typedef struct trf_mgmt_filter { + struct ether_addr dst_ether_addr; /* His L2 address */ + uint32 dst_ip_addr; /* His IP address */ + uint16 dst_port; /* His L4 port */ + uint16 src_port; /* My L4 port */ + uint16 prot; /* L4 protocol (only TCP or UDP) */ + uint16 flags; /* TBD. For now, this must be zero. */ + trf_mgmt_priority_class_t priority; /* Priority for filtered packets */ + uint32 dscp; /* DSCP */ +} trf_mgmt_filter_t; + +/* Traffic management filter list (variable length) */ +typedef struct trf_mgmt_filter_list { + uint32 num_filters; + trf_mgmt_filter_t filter[1]; +} trf_mgmt_filter_list_t; + +/* Traffic management global info used for all queues */ +typedef struct trf_mgmt_global_info { + uint32 maximum_bytes_per_second; + uint32 maximum_bytes_per_sampling_period; + uint32 total_bytes_consumed_per_second; + uint32 total_bytes_consumed_per_sampling_period; + uint32 total_unused_bytes_per_sampling_period; +} trf_mgmt_global_info_t; + +/* Traffic management shaping info per priority queue */ +typedef struct trf_mgmt_shaping_info { + uint32 gauranteed_bandwidth_percentage; + uint32 guaranteed_bytes_per_second; + uint32 guaranteed_bytes_per_sampling_period; + uint32 num_bytes_produced_per_second; + uint32 num_bytes_consumed_per_second; + uint32 num_queued_packets; /* Number of packets in queue */ + uint32 num_queued_bytes; /* Number of bytes in queue */ +} trf_mgmt_shaping_info_t; + +/* Traffic management shaping info array */ +typedef struct trf_mgmt_shaping_info_array { + trf_mgmt_global_info_t tx_global_shaping_info; + trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; + trf_mgmt_global_info_t rx_global_shaping_info; + trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; +} trf_mgmt_shaping_info_array_t; + + +/* Traffic management statistical counters */ +typedef struct trf_mgmt_stats { + uint32 num_processed_packets; /* Number of packets processed */ + uint32 num_processed_bytes; /* Number of bytes processed */ + uint32 num_discarded_packets; /* Number of packets discarded from queue */ +} trf_mgmt_stats_t; + +/* Traffic management statisics array */ +typedef struct trf_mgmt_stats_array { + trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; + trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; +} trf_mgmt_stats_array_t; + +typedef struct powersel_params { + /* LPC Params exposed via IOVAR */ + int32 tp_ratio_thresh; /* Throughput ratio threshold */ + uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ + uint8 pwr_stab_thresh; /* Number of successes before power step down */ + uint8 pwr_sel_exp_time; /* Time lapse for expiry of database */ +} powersel_params_t; + +typedef struct lpc_params { + /* LPC Params exposed via IOVAR */ + uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ + uint8 pwr_stab_thresh; /* Number of successes before power step down */ + uint8 lpc_exp_time; /* Time lapse for expiry of database */ + uint8 pwrup_slow_step; /* Step size for slow step up */ + uint8 pwrup_fast_step; /* Step size for fast step up */ + uint8 pwrdn_slow_step; /* Step size for slow step down */ +} lpc_params_t; + +/* tx pkt delay statistics */ +#define SCB_RETRY_SHORT_DEF 7 /* Default Short retry Limit */ +#define WLPKTDLY_HIST_NBINS 16 /* number of bins used in the Delay histogram */ + +/* structure to store per-AC delay statistics */ +typedef struct scb_delay_stats { + uint32 txmpdu_lost; /* number of MPDUs lost */ + uint32 txmpdu_cnt[SCB_RETRY_SHORT_DEF]; /* retry times histogram */ + uint32 delay_sum[SCB_RETRY_SHORT_DEF]; /* cumulative packet latency */ + uint32 delay_min; /* minimum packet latency observed */ + uint32 delay_max; /* maximum packet latency observed */ + uint32 delay_avg; /* packet latency average */ + uint32 delay_hist[WLPKTDLY_HIST_NBINS]; /* delay histogram */ +} scb_delay_stats_t; + +/* structure for txdelay event */ +typedef struct txdelay_event { + uint8 status; + int rssi; + chanim_stats_t chanim_stats; + scb_delay_stats_t delay_stats[AC_COUNT]; +} txdelay_event_t; + +/* structure for txdelay parameters */ +typedef struct txdelay_params { + uint16 ratio; /* Avg Txdelay Delta */ + uint8 cnt; /* Sample cnt */ + uint8 period; /* Sample period */ + uint8 tune; /* Debug */ +} txdelay_params_t; + +enum { + WNM_SERVICE_DMS = 1, + WNM_SERVICE_FMS = 2, + WNM_SERVICE_TFS = 3 +}; + +/* Definitions for WNM/NPS TCLAS */ +typedef struct wl_tclas { + uint8 user_priority; + uint8 fc_len; + dot11_tclas_fc_t fc; +} wl_tclas_t; + +#define WL_TCLAS_FIXED_SIZE OFFSETOF(wl_tclas_t, fc) + +typedef struct wl_tclas_list { + uint32 num; + wl_tclas_t tclas[1]; +} wl_tclas_list_t; + +/* Definitions for WNM/NPS Traffic Filter Service */ +typedef struct wl_tfs_req { + uint8 tfs_id; + uint8 tfs_actcode; + uint8 tfs_subelem_id; + uint8 send; +} wl_tfs_req_t; + +typedef struct wl_tfs_filter { + uint8 status; /* Status returned by the AP */ + uint8 tclas_proc; /* TCLAS processing value (0:and, 1:or) */ + uint8 tclas_cnt; /* count of all wl_tclas_t in tclas array */ + uint8 tclas[1]; /* VLA of wl_tclas_t */ +} wl_tfs_filter_t; +#define WL_TFS_FILTER_FIXED_SIZE OFFSETOF(wl_tfs_filter_t, tclas) + +typedef struct wl_tfs_fset { + struct ether_addr ea; /* Address of AP/STA involved with this filter set */ + uint8 tfs_id; /* TFS ID field chosen by STA host */ + uint8 status; /* Internal status TFS_STATUS_xxx */ + uint8 actcode; /* Action code DOT11_TFS_ACTCODE_xxx */ + uint8 token; /* Token used in last request frame */ + uint8 notify; /* Notify frame sent/received because of this set */ + uint8 filter_cnt; /* count of all wl_tfs_filter_t in filter array */ + uint8 filter[1]; /* VLA of wl_tfs_filter_t */ +} wl_tfs_fset_t; +#define WL_TFS_FSET_FIXED_SIZE OFFSETOF(wl_tfs_fset_t, filter) + +enum { + TFS_STATUS_DISABLED = 0, /* TFS filter set disabled by user */ + TFS_STATUS_DISABLING = 1, /* Empty request just sent to AP */ + TFS_STATUS_VALIDATED = 2, /* Filter set validated by AP (but maybe not enabled!) */ + TFS_STATUS_VALIDATING = 3, /* Filter set just sent to AP */ + TFS_STATUS_NOT_ASSOC = 4, /* STA not associated */ + TFS_STATUS_NOT_SUPPORT = 5, /* TFS not supported by AP */ + TFS_STATUS_DENIED = 6, /* Filter set refused by AP (=> all sets are disabled!) */ +}; + +typedef struct wl_tfs_status { + uint8 fset_cnt; /* count of all wl_tfs_fset_t in fset array */ + wl_tfs_fset_t fset[1]; /* VLA of wl_tfs_fset_t */ +} wl_tfs_status_t; + +typedef struct wl_tfs_set { + uint8 send; /* Immediatly register registered sets on AP side */ + uint8 tfs_id; /* ID of a specific set (existing or new), or nul for all */ + uint8 actcode; /* Action code for this filter set */ + uint8 tclas_proc; /* TCLAS processing operator for this filter set */ +} wl_tfs_set_t; + +typedef struct wl_tfs_term { + uint8 del; /* Delete internal set once confirmation received */ + uint8 tfs_id; /* ID of a specific set (existing), or nul for all */ +} wl_tfs_term_t; + + +#define DMS_DEP_PROXY_ARP (1 << 0) + +/* Definitions for WNM/NPS Directed Multicast Service */ +enum { + DMS_STATUS_DISABLED = 0, /* DMS desc disabled by user */ + DMS_STATUS_ACCEPTED = 1, /* Request accepted by AP */ + DMS_STATUS_NOT_ASSOC = 2, /* STA not associated */ + DMS_STATUS_NOT_SUPPORT = 3, /* DMS not supported by AP */ + DMS_STATUS_DENIED = 4, /* Request denied by AP */ + DMS_STATUS_TERM = 5, /* Request terminated by AP */ + DMS_STATUS_REMOVING = 6, /* Remove request just sent */ + DMS_STATUS_ADDING = 7, /* Add request just sent */ + DMS_STATUS_ERROR = 8, /* Non compliant AP behvior */ + DMS_STATUS_IN_PROGRESS = 9, /* Request just sent */ + DMS_STATUS_REQ_MISMATCH = 10 /* Conditions for sending DMS req not met */ +}; + +typedef struct wl_dms_desc { + uint8 user_id; + uint8 status; + uint8 token; + uint8 dms_id; + uint8 tclas_proc; + uint8 mac_len; /* length of all ether_addr in data array, 0 if STA */ + uint8 tclas_len; /* length of all wl_tclas_t in data array */ + uint8 data[1]; /* VLA of 'ether_addr' and 'wl_tclas_t' (in this order ) */ +} wl_dms_desc_t; + +#define WL_DMS_DESC_FIXED_SIZE OFFSETOF(wl_dms_desc_t, data) + +typedef struct wl_dms_status { + uint32 cnt; + wl_dms_desc_t desc[1]; +} wl_dms_status_t; + +typedef struct wl_dms_set { + uint8 send; + uint8 user_id; + uint8 tclas_proc; +} wl_dms_set_t; + +typedef struct wl_dms_term { + uint8 del; + uint8 user_id; +} wl_dms_term_t; + +typedef struct wl_service_term { + uint8 service; + union { + wl_dms_term_t dms; + } u; +} wl_service_term_t; + +/* Definitions for WNM/NPS BSS Transistion */ +typedef struct wl_bsstrans_req { + uint16 tbtt; /* time of BSS to end of life, in unit of TBTT */ + uint16 dur; /* time of BSS to keep off, in unit of minute */ + uint8 reqmode; /* request mode of BSS transition request */ + uint8 unicast; /* request by unicast or by broadcast */ +} wl_bsstrans_req_t; + +enum { + BSSTRANS_RESP_AUTO = 0, /* Currently equivalent to ENABLE */ + BSSTRANS_RESP_DISABLE = 1, /* Never answer BSS Trans Req frames */ + BSSTRANS_RESP_ENABLE = 2, /* Always answer Req frames with preset data */ + BSSTRANS_RESP_WAIT = 3, /* Send ind, wait and/or send preset data (NOT IMPL) */ + BSSTRANS_RESP_IMMEDIATE = 4 /* After an ind, set data and send resp (NOT IMPL) */ +}; + +typedef struct wl_bsstrans_resp { + uint8 policy; + uint8 status; + uint8 delay; + struct ether_addr target; +} wl_bsstrans_resp_t; + +/* "wnm_bsstrans_resp" argument programming behavior after BSSTRANS Req reception */ +enum { + WL_BSSTRANS_RESP_ROAM_ALWAYS = 0, /* Roam (or disassociate) in all cases */ + WL_BSSTRANS_RESP_ROAM_IF_MODE = 1, /* Roam only if requested by Request Mode field */ + WL_BSSTRANS_RESP_ROAM_IF_PREF = 2, /* Roam only if Preferred BSS provided */ + WL_BSSTRANS_RESP_WAIT = 3 /* Wait for deauth and send Accepted status */ +}; + +/* Definitions for WNM/NPS TIM Broadcast */ +typedef struct wl_timbc_offset { + int16 offset; /* offset in us */ + uint16 fix_intv; /* override interval sent from STA */ + uint16 rate_override; /* use rate override to send high rate TIM broadcast frame */ + uint8 tsf_present; /* show timestamp in TIM broadcast frame */ +} wl_timbc_offset_t; + +typedef struct wl_timbc_set { + uint8 interval; /* Interval in DTIM wished or required. */ + uint8 flags; /* Bitfield described below */ + uint16 rate_min; /* Minimum rate required for High/Low TIM frames. Optionnal */ + uint16 rate_max; /* Maximum rate required for High/Low TIM frames. Optionnal */ +} wl_timbc_set_t; + +enum { + WL_TIMBC_SET_TSF_REQUIRED = 1, /* Enable TIMBC only if TSF in TIM frames */ + WL_TIMBC_SET_NO_OVERRIDE = 2, /* ... if AP does not override interval */ + WL_TIMBC_SET_PROXY_ARP = 4, /* ... if AP support Proxy ARP */ + WL_TIMBC_SET_DMS_ACCEPTED = 8 /* ... if all DMS desc have been accepted */ +}; + +typedef struct wl_timbc_status { + uint8 status_sta; /* Status from internal state machine (check below) */ + uint8 status_ap; /* From AP response frame (check 8.4.2.86 from 802.11) */ + uint8 interval; + uint8 pad; + int32 offset; + uint16 rate_high; + uint16 rate_low; +} wl_timbc_status_t; + +enum { + WL_TIMBC_STATUS_DISABLE = 0, /* TIMBC disabled by user */ + WL_TIMBC_STATUS_REQ_MISMATCH = 1, /* AP settings do no match user requirements */ + WL_TIMBC_STATUS_NOT_ASSOC = 2, /* STA not associated */ + WL_TIMBC_STATUS_NOT_SUPPORT = 3, /* TIMBC not supported by AP */ + WL_TIMBC_STATUS_DENIED = 4, /* Req to disable TIMBC sent to AP */ + WL_TIMBC_STATUS_ENABLE = 5 /* TIMBC enabled */ +}; + +/* Definitions for PM2 Dynamic Fast Return To Sleep */ +typedef struct wl_pm2_sleep_ret_ext { + uint8 logic; /* DFRTS logic: see WL_DFRTS_LOGIC_* below */ + uint16 low_ms; /* Low FRTS timeout */ + uint16 high_ms; /* High FRTS timeout */ + uint16 rx_pkts_threshold; /* switching threshold: # rx pkts */ + uint16 tx_pkts_threshold; /* switching threshold: # tx pkts */ + uint16 txrx_pkts_threshold; /* switching threshold: # (tx+rx) pkts */ + uint32 rx_bytes_threshold; /* switching threshold: # rx bytes */ + uint32 tx_bytes_threshold; /* switching threshold: # tx bytes */ + uint32 txrx_bytes_threshold; /* switching threshold: # (tx+rx) bytes */ +} wl_pm2_sleep_ret_ext_t; + +#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ +#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ +#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ + +/* Values for the passive_on_restricted_mode iovar. When set to non-zero, this iovar + * disables automatic conversions of a channel from passively scanned to + * actively scanned. These values only have an effect for country codes such + * as XZ where some 5 GHz channels are defined to be passively scanned. + */ +#define WL_PASSACTCONV_DISABLE_NONE 0 /* Enable permanent and temporary conversions */ +#define WL_PASSACTCONV_DISABLE_ALL 1 /* Disable permanent and temporary conversions */ +#define WL_PASSACTCONV_DISABLE_PERM 2 /* Disable only permanent conversions */ + +/* Definitions for Reliable Multicast */ +#define WL_RMC_CNT_VERSION 1 +#define WL_RMC_MAX_CLIENT 32 +#define WL_RMC_FLAG_INBLACKLIST 1 +#define WL_RMC_FLAG_ACTIVEACKER 2 +#define WL_RMC_FLAG_RELMCAST 4 +#define WL_RMC_MAX_TABLE_ENTRY 4 + +#define WL_RMC_VER 1 +#define WL_RMC_INDEX_ACK_ALL 255 +#define WL_RMC_NUM_OF_MC_STREAMS 4 +#define WL_RMC_MAX_TRS_PER_GROUP 1 +#define WL_RMC_MAX_TRS_IN_ACKALL 1 +#define WL_RMC_ACK_MCAST0 0x02 +#define WL_RMC_ACK_MCAST_ALL 0x01 +#define WL_RMC_ACTF_TIME_MIN 300 /* time in ms */ +#define WL_RMC_ACTF_TIME_MAX 20000 /* time in ms */ +#define WL_RMC_ARTMO_MIN 350 /* time in ms */ +#define WL_RMC_ARTMO_MAX 40000 /* time in ms */ + +/* RMC events in action frames */ +enum rmc_opcodes { + RELMCAST_ENTRY_OP_DISABLE = 0, /* Disable multi-cast group */ + RELMCAST_ENTRY_OP_DELETE = 1, /* Delete multi-cast group */ + RELMCAST_ENTRY_OP_ENABLE = 2, /* Enable multi-cast group */ + RELMCAST_ENTRY_OP_ACK_ALL = 3 /* Enable ACK ALL bit in AMT */ +}; + +/* RMC operational modes */ +enum rmc_modes { + WL_RMC_MODE_RECEIVER = 0, /* Receiver mode by default */ + WL_RMC_MODE_TRANSMITTER = 1, /* Transmitter mode using wl ackreq */ + WL_RMC_MODE_INITIATOR = 2 /* Initiator mode using wl ackreq */ +}; + +/* Each RMC mcast client info */ +typedef struct wl_relmcast_client { + uint8 flag; /* status of client such as AR, R, or blacklisted */ + int16 rssi; /* rssi value of RMC client */ + struct ether_addr addr; /* mac address of RMC client */ +} wl_relmcast_client_t; + +/* RMC Counters */ +typedef struct wl_rmc_cnts { + uint16 version; /* see definition of WL_CNT_T_VERSION */ + uint16 length; /* length of entire structure */ + uint16 dupcnt; /* counter for duplicate rmc MPDU */ + uint16 ackreq_err; /* counter for wl ackreq error */ + uint16 af_tx_err; /* error count for action frame transmit */ + uint16 null_tx_err; /* error count for rmc null frame transmit */ + uint16 af_unicast_tx_err; /* error count for rmc unicast frame transmit */ + uint16 mc_no_amt_slot; /* No mcast AMT entry available */ + uint16 mc_no_glb_slot; /* No mcast entry available in global table */ + uint16 mc_not_mirrored; /* mcast group is not mirrored */ + uint16 mc_existing_tr; /* mcast group is already taken by transmitter */ + uint16 mc_exist_in_amt; /* mcast group is already programmed in amt */ + uint16 mc_not_exist_in_gbl; /* mcast group is not in global table */ + uint16 mc_not_exist_in_amt; /* mcast group is not in AMT table */ + uint16 mc_utilized; /* mcast addressed is already taken */ + uint16 mc_taken_other_tr; /* multi-cast addressed is already taken */ + uint32 rmc_rx_frames_mac; /* no of mc frames received from mac */ + uint32 rmc_tx_frames_mac; /* no of mc frames transmitted to mac */ + uint32 mc_null_ar_cnt; /* no. of times NULL AR is received */ + uint32 mc_ar_role_selected; /* no. of times took AR role */ + uint32 mc_ar_role_deleted; /* no. of times AR role cancelled */ + uint32 mc_noacktimer_expired; /* no. of times noack timer expired */ +} wl_rmc_cnts_t; + +/* RMC Status */ +typedef struct wl_relmcast_st { + uint8 ver; /* version of RMC */ + uint8 num; /* number of clients detected by transmitter */ + wl_relmcast_client_t clients[WL_RMC_MAX_CLIENT]; + uint16 err; /* error status (used in infra) */ + uint16 actf_time; /* action frame time period */ +} wl_relmcast_status_t; + +/* Entry for each STA/node */ +typedef struct wl_rmc_entry { + /* operation on multi-cast entry such add, + * delete, ack-all + */ + int8 flag; + struct ether_addr addr; /* multi-cast group mac address */ +} wl_rmc_entry_t; + +/* RMC table */ +typedef struct wl_rmc_entry_table { + uint8 index; /* index to a particular mac entry in table */ + uint8 opcode; /* opcodes or operation on entry */ + wl_rmc_entry_t entry[WL_RMC_MAX_TABLE_ENTRY]; +} wl_rmc_entry_table_t; + +/* Transmitter Info */ +typedef struct wl_rmc_trans_info { + struct ether_addr addr; /* transmitter mac */ + uint32 time_val; /* timer val in case aging of entry is required */ + uint16 seq; /* last seq number of packet received from transmitter */ + uint16 artmo; +} wl_rmc_trans_info_t; + +/* Multicast Group */ +typedef struct wl_rmc_grp_entry { + struct ether_addr mcaddr; /* multi-cast group mac */ + struct ether_addr ar; /* active receiver for the group */ + wl_rmc_trans_info_t tr_info[WL_RMC_MAX_TRS_PER_GROUP]; +} wl_rmc_grp_entry_t; + +/* RMC ACKALL Table */ +typedef struct wl_rmc_ackall_entry { + struct ether_addr ar; /* active receiver for the entry */ + wl_rmc_trans_info_t tr_info[WL_RMC_NUM_OF_MC_STREAMS]; +} wl_rmc_ackall_entry_t; + +/* RMC Peers Table */ +typedef struct wl_rmc_gbl_table { + uint8 activeMask; /* mask to denote the entry(s) that are active */ + wl_rmc_ackall_entry_t ackAll; /* structure to keep info related to ACK all */ + wl_rmc_grp_entry_t mc_entry[WL_RMC_NUM_OF_MC_STREAMS]; +} wl_rmc_gbl_table_t; + +/* To update vendor specific ie for RMC */ +typedef struct wl_rmc_vsie { + uint8 oui[DOT11_OUI_LEN]; + uint16 payload; /* IE Data Payload */ +} wl_rmc_vsie_t; + +/* structures & defines for proximity detection */ +enum proxd_method { + PROXD_UNDEFINED_METHOD = 0, + PROXD_RSSI_METHOD = 1, + PROXD_TOF_METHOD = 2 +}; + +/* structures for proximity detection device role */ +#define WL_PROXD_MODE_DISABLE 0 +#define WL_PROXD_MODE_NEUTRAL 1 +#define WL_PROXD_MODE_INITIATOR 2 +#define WL_PROXD_MODE_TARGET 3 + +#define WL_PROXD_ACTION_STOP 0 +#define WL_PROXD_ACTION_START 1 + +#define WL_PROXD_FLAG_TARGET_REPORT 0x1 +#define WL_PROXD_FLAG_REPORT_FAILURE 0x2 +#define WL_PROXD_FLAG_INITIATOR_REPORT 0x4 +#define WL_PROXD_FLAG_NOCHANSWT 0x8 +#define WL_PROXD_FLAG_NETRUAL 0x10 +#define WL_PROXD_FLAG_INITIATOR_RPTRTT 0x20 +#define WL_PROXD_FLAG_ONEWAY 0x40 +#define WL_PROXD_FLAG_SEQ_EN 0x80 + +#define WL_PROXD_RANDOM_WAKEUP 0x8000 + +typedef struct wl_proxd_iovar { + uint16 method; /* Proxmity Detection method */ + uint16 mode; /* Mode (neutral, initiator, target) */ +} wl_proxd_iovar_t; + +/* + * structures for proximity detection parameters + * consists of two parts, common and method specific params + * common params should be placed at the beginning + */ + +/* require strict packing */ +#include + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_common { + chanspec_t chanspec; /* channel spec */ + int16 tx_power; /* tx power of Proximity Detection(PD) frames (in dBm) */ + uint16 tx_rate; /* tx rate of PD rames (in 500kbps units) */ + uint16 timeout; /* timeout value */ + uint16 interval; /* interval between neighbor finding attempts (in TU) */ + uint16 duration; /* duration of neighbor finding attempts (in ms) */ +} BWL_POST_PACKED_STRUCT wl_proxd_params_common_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_rssi_method { + chanspec_t chanspec; /* chanspec for home channel */ + int16 tx_power; /* tx power of Proximity Detection frames (in dBm) */ + uint16 tx_rate; /* tx rate of PD frames, 500kbps units */ + uint16 timeout; /* state machine wait timeout of the frames (in ms) */ + uint16 interval; /* interval between neighbor finding attempts (in TU) */ + uint16 duration; /* duration of neighbor finding attempts (in ms) */ + /* method specific ones go after this line */ + int16 rssi_thresh; /* RSSI threshold (in dBm) */ + uint16 maxconvergtmo; /* max wait converge timeout (in ms) */ +} wl_proxd_params_rssi_method_t; + +#define Q1_NS 25 /* Q1 time units */ + +#define TOF_BW_NUM 3 /* number of bandwidth that the TOF can support */ +#define TOF_BW_SEQ_NUM (TOF_BW_NUM+2) /* number of total index */ +enum tof_bw_index { + TOF_BW_20MHZ_INDEX = 0, + TOF_BW_40MHZ_INDEX = 1, + TOF_BW_80MHZ_INDEX = 2, + TOF_BW_SEQTX_INDEX = 3, + TOF_BW_SEQRX_INDEX = 4 +}; + +#define BANDWIDTH_BASE 20 /* base value of bandwidth */ +#define TOF_BW_20MHZ (BANDWIDTH_BASE << TOF_BW_20MHZ_INDEX) +#define TOF_BW_40MHZ (BANDWIDTH_BASE << TOF_BW_40MHZ_INDEX) +#define TOF_BW_80MHZ (BANDWIDTH_BASE << TOF_BW_80MHZ_INDEX) +#define TOF_BW_10MHZ 10 + +#define NFFT_BASE 64 /* base size of fft */ +#define TOF_NFFT_20MHZ (NFFT_BASE << TOF_BW_20MHZ_INDEX) +#define TOF_NFFT_40MHZ (NFFT_BASE << TOF_BW_40MHZ_INDEX) +#define TOF_NFFT_80MHZ (NFFT_BASE << TOF_BW_80MHZ_INDEX) + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_method { + chanspec_t chanspec; /* chanspec for home channel */ + int16 tx_power; /* tx power of Proximity Detection(PD) frames (in dBm) */ + uint16 tx_rate; /* tx rate of PD rames (in 500kbps units) */ + uint16 timeout; /* state machine wait timeout of the frames (in ms) */ + uint16 interval; /* interval between neighbor finding attempts (in TU) */ + uint16 duration; /* duration of neighbor finding attempts (in ms) */ + /* specific for the method go after this line */ + struct ether_addr tgt_mac; /* target mac addr for TOF method */ + uint16 ftm_cnt; /* number of the frames txed by initiator */ + uint16 retry_cnt; /* number of retransmit attampts for ftm frames */ + int16 vht_rate; /* ht or vht rate */ + /* add more params required for other methods can be added here */ +} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_method_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_tune { + uint32 Ki; /* h/w delay K factor for initiator */ + uint32 Kt; /* h/w delay K factor for target */ + int16 vhtack; /* enable/disable VHT ACK */ + int16 N_log2[TOF_BW_SEQ_NUM]; /* simple threshold crossing */ + int16 w_offset[TOF_BW_NUM]; /* offset of threshold crossing window(per BW) */ + int16 w_len[TOF_BW_NUM]; /* length of threshold crossing window(per BW) */ + int32 maxDT; /* max time difference of T4/T1 or T3/T2 */ + int32 minDT; /* min time difference of T4/T1 or T3/T2 */ + uint8 totalfrmcnt; /* total count of transfered measurement frames */ + uint16 rsv_media; /* reserve media value for TOF */ + uint32 flags; /* flags */ + uint8 core; /* core to use for tx */ + uint8 setflags; /* set flags of K, N. S values */ + int16 N_scale[TOF_BW_SEQ_NUM]; /* simple threshold crossing */ + uint8 sw_adj; /* enable sw assisted timestamp adjustment */ + uint8 hw_adj; /* enable hw assisted timestamp adjustment */ + uint8 seq_en; /* enable ranging sequence */ + uint8 ftm_cnt[TOF_BW_SEQ_NUM]; /* number of ftm frames based on bandwidth */ + int16 N_log2_2g; /* simple threshold crossing for 2g channel */ + int16 N_scale_2g; /* simple threshold crossing for 2g channel */ +} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_tune_t; + +typedef struct wl_proxd_params_iovar { + uint16 method; /* Proxmity Detection method */ + union { + /* common params for pdsvc */ + wl_proxd_params_common_t cmn_params; /* common parameters */ + /* method specific */ + wl_proxd_params_rssi_method_t rssi_params; /* RSSI method parameters */ + wl_proxd_params_tof_method_t tof_params; /* TOF meothod parameters */ + /* tune parameters */ + wl_proxd_params_tof_tune_t tof_tune; /* TOF tune parameters */ + } u; /* Method specific optional parameters */ +} wl_proxd_params_iovar_t; + +#define PROXD_COLLECT_GET_STATUS 0 +#define PROXD_COLLECT_SET_STATUS 1 +#define PROXD_COLLECT_QUERY_HEADER 2 +#define PROXD_COLLECT_QUERY_DATA 3 +#define PROXD_COLLECT_QUERY_DEBUG 4 +#define PROXD_COLLECT_REMOTE_REQUEST 5 + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_query { + uint32 method; /* method */ + uint8 request; /* Query request. */ + uint8 status; /* 0 -- disable, 1 -- enable collection, */ + /* 2 -- enable collection & debug */ + uint16 index; /* The current frame index [0 to total_frames - 1]. */ + uint16 mode; /* Initiator or Target */ + bool busy; /* tof sm is busy */ + bool remote; /* Remote collect data */ +} BWL_POST_PACKED_STRUCT wl_proxd_collect_query_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_header { + uint16 total_frames; /* The totral frames for this collect. */ + uint16 nfft; /* nfft value */ + uint16 bandwidth; /* bandwidth */ + uint16 channel; /* channel number */ + uint32 chanspec; /* channel spec */ + uint32 fpfactor; /* avb timer value factor */ + uint16 fpfactor_shift; /* avb timer value shift bits */ + int32 distance; /* distance calculated by fw */ + uint32 meanrtt; /* mean of RTTs */ + uint32 modertt; /* mode of RTTs */ + uint32 medianrtt; /* median of RTTs */ + uint32 sdrtt; /* standard deviation of RTTs */ + uint32 clkdivisor; /* clock divisor */ + uint16 chipnum; /* chip type */ + uint8 chiprev; /* chip revision */ + uint8 phyver; /* phy version */ + struct ether_addr loaclMacAddr; /* local mac address */ + struct ether_addr remoteMacAddr; /* remote mac address */ + wl_proxd_params_tof_tune_t params; +} BWL_POST_PACKED_STRUCT wl_proxd_collect_header_t; + +/* ********************** NAN wl interface struct types and defs ******************** */ + +#define WL_NAN_IOCTL_VERSION 0x1 + +/* wl_nan_sub_cmd may also be used in dhd */ +typedef struct wl_nan_sub_cmd wl_nan_sub_cmd_t; +typedef int (cmd_handler_t)(void *wl, const wl_nan_sub_cmd_t *cmd, char **argv); +/* nan cmd list entry */ +struct wl_nan_sub_cmd { + char *name; + uint8 version; /* cmd version */ + uint16 id; /* id for the dongle f/w switch/case */ + uint16 type; /* base type of argument */ + cmd_handler_t *handler; /* cmd handler */ +}; + +/* container for nan iovtls & events */ +typedef BWL_PRE_PACKED_STRUCT struct wl_nan_ioc { + uint16 version; /* interface command or event version */ + uint16 id; /* nan ioctl cmd ID */ + uint16 len; /* total length of all tlv records in data[] */ + uint8 data [1]; /* var len payload of bcm_xtlv_t type */ +} BWL_POST_PACKED_STRUCT wl_nan_ioc_t; + +typedef struct wl_nan_status { + uint8 inited; + uint8 joined; + uint8 role; + uint8 hop_count; + uint32 chspec; + uint8 amr[8]; /* Anchor Master Rank */ + uint32 cnt_pend_txfrm; /* pending TX frames */ + uint32 cnt_bcn_tx; /* TX disc/sync beacon count */ + uint32 cnt_bcn_rx; /* RX disc/sync beacon count */ + uint32 cnt_svc_disc_tx; /* TX svc disc frame count */ + uint32 cnt_svc_disc_rx; /* RX svc disc frame count */ + struct ether_addr cid; +} wl_nan_status_t; + +/* various params and ctl swithce for nan_debug instance */ +typedef struct nan_debug_params { + uint8 enabled; /* runtime debuging enabled */ + uint8 collect; /* enables debug svc sdf monitor mode */ + uint16 cmd; /* debug cmd to perform a debug action */ + uint32 msglevel; /* msg level if enabled */ + uint16 status; +} nan_debug_params_t; + + +/* nan passive scan params */ +#define NAN_SCAN_MAX_CHCNT 8 +typedef BWL_PRE_PACKED_STRUCT struct nan_scan_params { + uint16 scan_time; + uint16 home_time; + uint16 ms_intvl; /* interval between merge scan */ + uint16 ms_dur; /* duration of merge scan */ + uint16 chspec_num; + chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /* act. used 3, 5 rfu */ +} BWL_POST_PACKED_STRUCT nan_scan_params_t; + +enum wl_nan_role { + WL_NAN_ROLE_AUTO = 0, + WL_NAN_ROLE_NON_MASTER_NON_SYNC = 1, + WL_NAN_ROLE_NON_MASTER_SYNC = 2, + WL_NAN_ROLE_MASTER = 3, + WL_NAN_ROLE_ANCHOR_MASTER = 4 +}; +#define NAN_MASTER_RANK_LEN 8 +/* nan cmd IDs */ +enum wl_nan_cmds { + /* nan cfg /disc & dbg ioctls */ + WL_NAN_CMD_ENABLE = 1, + WL_NAN_CMD_ATTR = 2, + WL_NAN_CMD_NAN_JOIN = 3, + WL_NAN_CMD_LEAVE = 4, + WL_NAN_CMD_MERGE = 5, + WL_NAN_CMD_STATUS = 6, + /* discovery engine commands */ + WL_NAN_CMD_PUBLISH = 20, + WL_NAN_CMD_SUBSCRIBE = 21, + WL_NAN_CMD_CANCEL_PUBLISH = 22, + WL_NAN_CMD_CANCEL_SUBSCRIBE = 23, + WL_NAN_CMD_TRANSMIT = 24, + WL_NAN_CMD_CONNECTION = 25, + WL_NAN_CMD_SHOW = 26, + WL_NAN_CMD_STOP = 27, /* stop nan for a given cluster ID */ + /* nan debug iovars & cmds */ + WL_NAN_CMD_SCAN_PARAMS = 46, + WL_NAN_CMD_SCAN = 47, + WL_NAN_CMD_SCAN_RESULTS = 48, + WL_NAN_CMD_EVENT_MASK = 49, + WL_NAN_CMD_EVENT_CHECK = 50, + + WL_NAN_CMD_DEBUG = 60, + WL_NAN_CMD_TEST1 = 61, + WL_NAN_CMD_TEST2 = 62, + WL_NAN_CMD_TEST3 = 63 +}; + +/* + * tlv IDs uniquely identifies cmd parameters + * packed into wl_nan_ioc_t container + */ +enum wl_nan_cmd_xtlv_id { + /* 0x00 ~ 0xFF: standard TLV ID whose data format is the same as NAN attribute TLV */ + WL_NAN_XTLV_ZERO = 0, /* used as tlv buf end marker */ +#ifdef NAN_STD_TLV /* rfu, don't use yet */ + WL_NAN_XTLV_MASTER_IND = 1, /* == NAN_ATTR_MASTER_IND, */ + WL_NAN_XTLV_CLUSTER = 2, /* == NAN_ATTR_CLUSTER, */ + WL_NAN_XTLV_VENDOR = 221, /* == NAN_ATTR_VENDOR, */ +#endif + /* 0x02 ~ 0xFF: reserved. In case to use with the same data format as NAN attribute TLV */ + /* 0x100 ~ : private TLV ID defined just for NAN command */ + /* common types */ + WL_NAN_XTLV_BUFFER = 0x101, /* generic type, function depends on cmd context */ + WL_NAN_XTLV_MAC_ADDR = 0x102, /* used in various cmds */ + WL_NAN_XTLV_REASON = 0x103, + WL_NAN_XTLV_ENABLE = 0x104, + /* explicit types, primarily for discovery engine iovars */ + WL_NAN_XTLV_SVC_PARAMS = 0x120, /* Contains required params: wl_nan_disc_params_t */ + WL_NAN_XTLV_MATCH_RX = 0x121, /* Matching filter to evaluate on receive */ + WL_NAN_XTLV_MATCH_TX = 0x122, /* Matching filter to send */ + WL_NAN_XTLV_SVC_INFO = 0x123, /* Service specific info */ + WL_NAN_XTLV_SVC_NAME = 0x124, /* Optional UTF-8 service name, for debugging. */ + WL_NAN_XTLV_INSTANCE_ID = 0x125, /* Identifies unique publish or subscribe instance */ + WL_NAN_XTLV_PRIORITY = 0x126, /* used in transmit cmd context */ + WL_NAN_XTLV_REQUESTOR_ID = 0x127, /* Requestor instance ID */ + WL_NAN_XTLV_VNDR = 0x128, /* Vendor specific attribute */ + /* explicit types, primarily for NAN MAC iovars */ + WL_NAN_XTLV_DW_LEN = 0x140, /* discovery win length */ + WL_NAN_XTLV_BCN_INTERVAL = 0x141, /* beacon interval, both sync and descovery bcns? */ + WL_NAN_XTLV_CLUSTER_ID = 0x142, + WL_NAN_XTLV_IF_ADDR = 0x143, + WL_NAN_XTLV_MC_ADDR = 0x144, + WL_NAN_XTLV_ROLE = 0x145, + WL_NAN_XTLV_START = 0x146, + + WL_NAN_XTLV_MASTER_PREF = 0x147, + WL_NAN_XTLV_DW_INTERVAL = 0x148, + WL_NAN_XTLV_PTBTT_OVERRIDE = 0x149, + /* nan status command xtlvs */ + WL_NAN_XTLV_MAC_INITED = 0x14a, + WL_NAN_XTLV_MAC_ENABLED = 0x14b, + WL_NAN_XTLV_MAC_CHANSPEC = 0x14c, + WL_NAN_XTLV_MAC_AMR = 0x14d, /* anchormaster rank u8 amr[8] */ + WL_NAN_XTLV_MAC_HOPCNT = 0x14e, + WL_NAN_XTLV_MAC_AMBTT = 0x14f, + WL_NAN_XTLV_MAC_TXRATE = 0x150, + WL_NAN_XTLV_MAC_STATUS = 0x151, /* xtlv payload is nan_status_t */ + WL_NAN_XTLV_NAN_SCANPARAMS = 0x152, /* payload is nan_scan_params_t */ + WL_NAN_XTLV_DEBUGPARAMS = 0x153, /* payload is nan_scan_params_t */ + WL_NAN_XTLV_SUBSCR_ID = 0x154, /* subscriber id */ + WL_NAN_XTLV_PUBLR_ID = 0x155, /* publisher id */ + WL_NAN_XTLV_EVENT_MASK = 0x156, + WL_NAN_XTLV_MERGE = 0x157 +}; + +/* Flag bits for Publish and Subscribe (wl_nan_disc_params_t flags) */ +#define WL_NAN_RANGE_LIMITED 0x0040 +/* Bits specific to Publish */ +/* Unsolicited transmissions */ +#define WL_NAN_PUB_UNSOLICIT 0x1000 +/* Solicited transmissions */ +#define WL_NAN_PUB_SOLICIT 0x2000 +#define WL_NAN_PUB_BOTH 0x3000 +/* Set for broadcast solicited transmission + * Do not set for unicast solicited transmission + */ +#define WL_NAN_PUB_BCAST 0x4000 +/* Generate event on each solicited transmission */ +#define WL_NAN_PUB_EVENT 0x8000 +/* Used for one-time solicited Publish functions to indicate transmision occurred */ +#define WL_NAN_PUB_SOLICIT_PENDING 0x10000 +/* Follow-up frames */ +#define WL_NAN_FOLLOWUP 0x20000 +/* Bits specific to Subscribe */ +/* Active subscribe mode (Leave unset for passive) */ +#define WL_NAN_SUB_ACTIVE 0x1000 + +/* Special values for time to live (ttl) parameter */ +#define WL_NAN_TTL_UNTIL_CANCEL 0xFFFFFFFF +/* Publish - runs until first transmission + * Subscribe - runs until first DiscoveryResult event + */ +#define WL_NAN_TTL_FIRST 0 + +/* The service hash (service id) is exactly this many bytes. */ +#define WL_NAN_SVC_HASH_LEN 6 + +/* Instance ID type (unique identifier) */ +typedef uint8 wl_nan_instance_id_t; + +/* Mandatory parameters for publish/subscribe iovars - NAN_TLV_SVC_PARAMS */ +typedef struct wl_nan_disc_params_s { + /* Periodicity of unsolicited/query transmissions, in DWs */ + uint32 period; + /* Time to live in DWs */ + uint32 ttl; + /* Flag bits */ + uint32 flags; + /* Publish or subscribe service id, i.e. hash of the service name */ + uint8 svc_hash[WL_NAN_SVC_HASH_LEN]; + /* Publish or subscribe id */ + wl_nan_instance_id_t instance_id; +} wl_nan_disc_params_t; + +/* +* desovery interface event structures * +*/ + +/* NAN Ranging */ + +/* Bit defines for global flags */ +#define WL_NAN_RANGING_ENABLE 1 /* enable RTT */ +#define WL_NAN_RANGING_RANGED 2 /* Report to host if ranged as target */ +typedef struct nan_ranging_config { + uint32 chanspec; /* Ranging chanspec */ + uint16 timeslot; /* NAN RTT start time slot 1-511 */ + uint16 duration; /* NAN RTT duration in ms */ + struct ether_addr allow_mac; /* peer initiated ranging: the allowed peer mac + * address, a unicast (for one peer) or + * a broadcast for all. Setting it to all zeros + * means responding to none,same as not setting + * the flag bit NAN_RANGING_RESPOND + */ + uint16 flags; +} wl_nan_ranging_config_t; + +/* list of peers for self initiated ranging */ +/* Bit defines for per peer flags */ +#define WL_NAN_RANGING_REPORT (1<<0) /* Enable reporting range to target */ +typedef struct nan_ranging_peer { + uint32 chanspec; /* desired chanspec for this peer */ + uint32 abitmap; /* available bitmap */ + struct ether_addr ea; /* peer MAC address */ + uint8 frmcnt; /* frame count */ + uint8 retrycnt; /* retry count */ + uint16 flags; /* per peer flags, report or not */ +} wl_nan_ranging_peer_t; +typedef struct nan_ranging_list { + uint8 count; /* number of MAC addresses */ + uint8 num_peers_done; /* host set to 0, when read, shows number of peers + * completed, success or fail + */ + uint8 num_dws; /* time period to do the ranging, specified in dws */ + uint8 reserve; /* reserved field */ + wl_nan_ranging_peer_t rp[1]; /* variable length array of peers */ +} wl_nan_ranging_list_t; + +/* ranging results, a list for self initiated ranging and one for peer initiated ranging */ +/* There will be one structure for each peer */ +#define WL_NAN_RANGING_STATUS_SUCCESS 1 +#define WL_NAN_RANGING_STATUS_FAIL 2 +#define WL_NAN_RANGING_STATUS_TIMEOUT 3 +#define WL_NAN_RANGING_STATUS_ABORT 4 /* with partial results if sounding count > 0 */ +typedef struct nan_ranging_result { + uint8 status; /* 1: Success, 2: Fail 3: Timeout 4: Aborted */ + uint8 sounding_count; /* number of measurements completed (0 = failure) */ + struct ether_addr ea; /* initiator MAC address */ + uint32 chanspec; /* Chanspec where the ranging was done */ + uint32 timestamp; /* 32bits of the TSF timestamp ranging was completed at */ + uint32 distance; /* mean distance in meters expressed as Q4 number. + * Only valid when sounding_count > 0. Examples: + * 0x08 = 0.5m + * 0x10 = 1m + * 0x18 = 1.5m + * set to 0xffffffff to indicate invalid number + */ + int32 rtt_var; /* standard deviation in 10th of ns of RTTs measured. + * Only valid when sounding_count > 0 + */ + struct ether_addr tgtea; /* target MAC address */ +} wl_nan_ranging_result_t; +typedef struct nan_ranging_event_data { + uint8 mode; /* 1: Result of host initiated ranging */ + /* 2: Result of peer initiated ranging */ + uint8 reserved; + uint8 success_count; /* number of peers completed successfully */ + uint8 count; /* number of peers in the list */ + wl_nan_ranging_result_t rr[1]; /* variable array of ranging peers */ +} wl_nan_ranging_event_data_t; + +/* ********************* end of NAN section ******************************** */ + +#define RSSI_THRESHOLD_SIZE 16 +#define MAX_IMP_RESP_SIZE 256 + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_rssi_bias { + int32 version; /* version */ + int32 threshold[RSSI_THRESHOLD_SIZE]; /* threshold */ + int32 peak_offset; /* peak offset */ + int32 bias; /* rssi bias */ + int32 gd_delta; /* GD - GD_ADJ */ + int32 imp_resp[MAX_IMP_RESP_SIZE]; /* (Hi*Hi)+(Hr*Hr) */ +} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_rssi_bias_avg { + int32 avg_threshold[RSSI_THRESHOLD_SIZE]; /* avg threshold */ + int32 avg_peak_offset; /* avg peak offset */ + int32 avg_rssi; /* avg rssi */ + int32 avg_bias; /* avg bias */ +} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_avg_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_info { + uint16 type; /* type: 0 channel table, 1 channel smoothing table, 2 and 3 seq */ + uint16 index; /* The current frame index, from 1 to total_frames. */ + uint16 tof_cmd; /* M_TOF_CMD */ + uint16 tof_rsp; /* M_TOF_RSP */ + uint16 tof_avb_rxl; /* M_TOF_AVB_RX_L */ + uint16 tof_avb_rxh; /* M_TOF_AVB_RX_H */ + uint16 tof_avb_txl; /* M_TOF_AVB_TX_L */ + uint16 tof_avb_txh; /* M_TOF_AVB_TX_H */ + uint16 tof_id; /* M_TOF_ID */ + uint8 tof_frame_type; + uint8 tof_frame_bw; + int8 tof_rssi; + int32 tof_cfo; + int32 gd_adj_ns; /* gound delay */ + int32 gd_h_adj_ns; /* group delay + threshold crossing */ +#ifdef RSSI_REFINE + wl_proxd_rssi_bias_t rssi_bias; /* RSSI refinement info */ +#endif + int16 nfft; /* number of samples stored in H */ + +} BWL_POST_PACKED_STRUCT wl_proxd_collect_info_t; + +#define k_tof_collect_H_pad 1 +#define k_tof_collect_H_size (256+16+k_tof_collect_H_pad) +#define k_tof_collect_Hraw_size (2*k_tof_collect_H_size) +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_data { + wl_proxd_collect_info_t info; + uint32 H[k_tof_collect_H_size]; /* raw data read from phy used to adjust timestamps */ + +} BWL_POST_PACKED_STRUCT wl_proxd_collect_data_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_debug_data { + uint8 count; /* number of packets */ + uint8 stage; /* state machone stage */ + uint8 received; /* received or txed */ + uint8 paket_type; /* packet type */ + uint8 category; /* category field */ + uint8 action; /* action field */ + uint8 token; /* token number */ + uint8 follow_token; /* following token number */ + uint16 index; /* index of the packet */ + uint16 tof_cmd; /* M_TOF_CMD */ + uint16 tof_rsp; /* M_TOF_RSP */ + uint16 tof_avb_rxl; /* M_TOF_AVB_RX_L */ + uint16 tof_avb_rxh; /* M_TOF_AVB_RX_H */ + uint16 tof_avb_txl; /* M_TOF_AVB_TX_L */ + uint16 tof_avb_txh; /* M_TOF_AVB_TX_H */ + uint16 tof_id; /* M_TOF_ID */ + uint16 tof_status0; /* M_TOF_STATUS_0 */ + uint16 tof_status2; /* M_TOF_STATUS_2 */ + uint16 tof_chsm0; /* M_TOF_CHNSM_0 */ + uint16 tof_phyctl0; /* M_TOF_PHYCTL0 */ + uint16 tof_phyctl1; /* M_TOF_PHYCTL1 */ + uint16 tof_phyctl2; /* M_TOF_PHYCTL2 */ + uint16 tof_lsig; /* M_TOF_LSIG */ + uint16 tof_vhta0; /* M_TOF_VHTA0 */ + uint16 tof_vhta1; /* M_TOF_VHTA1 */ + uint16 tof_vhta2; /* M_TOF_VHTA2 */ + uint16 tof_vhtb0; /* M_TOF_VHTB0 */ + uint16 tof_vhtb1; /* M_TOF_VHTB1 */ + uint16 tof_apmductl; /* M_TOF_AMPDU_CTL */ + uint16 tof_apmdudlim; /* M_TOF_AMPDU_DLIM */ + uint16 tof_apmdulen; /* M_TOF_AMPDU_LEN */ +} BWL_POST_PACKED_STRUCT wl_proxd_debug_data_t; + +/* version of the wl_wsec_info structure */ +#define WL_WSEC_INFO_VERSION 0x01 + +/* start enum value for BSS properties */ +#define WL_WSEC_INFO_BSS_BASE 0x0100 + +/* size of len and type fields of wl_wsec_info_tlv_t struct */ +#define WL_WSEC_INFO_TLV_HDR_LEN OFFSETOF(wl_wsec_info_tlv_t, data) + +/* Allowed wl_wsec_info properties; not all of them may be supported. */ +typedef enum { + WL_WSEC_INFO_NONE = 0, + WL_WSEC_INFO_MAX_KEYS = 1, + WL_WSEC_INFO_NUM_KEYS = 2, + WL_WSEC_INFO_NUM_HW_KEYS = 3, + WL_WSEC_INFO_MAX_KEY_IDX = 4, + WL_WSEC_INFO_NUM_REPLAY_CNTRS = 5, + WL_WSEC_INFO_SUPPORTED_ALGOS = 6, + WL_WSEC_INFO_MAX_KEY_LEN = 7, + WL_WSEC_INFO_FLAGS = 8, + /* add global/per-wlc properties above */ + WL_WSEC_INFO_BSS_FLAGS = (WL_WSEC_INFO_BSS_BASE + 1), + WL_WSEC_INFO_BSS_WSEC = (WL_WSEC_INFO_BSS_BASE + 2), + WL_WSEC_INFO_BSS_TX_KEY_ID = (WL_WSEC_INFO_BSS_BASE + 3), + WL_WSEC_INFO_BSS_ALGO = (WL_WSEC_INFO_BSS_BASE + 4), + WL_WSEC_INFO_BSS_KEY_LEN = (WL_WSEC_INFO_BSS_BASE + 5), + /* add per-BSS properties above */ + WL_WSEC_INFO_MAX = 0xffff +} wl_wsec_info_type_t; + +/* tlv used to return wl_wsec_info properties */ +typedef struct { + uint16 type; + uint16 len; /* data length */ + uint8 data[1]; /* data follows */ +} wl_wsec_info_tlv_t; + +/* input/output data type for wsec_info iovar */ +typedef struct wl_wsec_info { + uint8 version; /* structure version */ + uint8 pad[2]; + uint8 num_tlvs; + wl_wsec_info_tlv_t tlvs[1]; /* tlv data follows */ +} wl_wsec_info_t; + +/* no default structure packing */ +#include + +enum rssi_reason { + RSSI_REASON_UNKNOW = 0, + RSSI_REASON_LOWRSSI = 1, + RSSI_REASON_NSYC = 2, + RSSI_REASON_TIMEOUT = 3 +}; + +enum tof_reason { + TOF_REASON_OK = 0, + TOF_REASON_REQEND = 1, + TOF_REASON_TIMEOUT = 2, + TOF_REASON_NOACK = 3, + TOF_REASON_INVALIDAVB = 4, + TOF_REASON_INITIAL = 5, + TOF_REASON_ABORT = 6 +}; + +enum rssi_state { + RSSI_STATE_POLL = 0, + RSSI_STATE_TPAIRING = 1, + RSSI_STATE_IPAIRING = 2, + RSSI_STATE_THANDSHAKE = 3, + RSSI_STATE_IHANDSHAKE = 4, + RSSI_STATE_CONFIRMED = 5, + RSSI_STATE_PIPELINE = 6, + RSSI_STATE_NEGMODE = 7, + RSSI_STATE_MONITOR = 8, + RSSI_STATE_LAST = 9 +}; + +enum tof_state { + TOF_STATE_IDLE = 0, + TOF_STATE_IWAITM = 1, + TOF_STATE_TWAITM = 2, + TOF_STATE_ILEGACY = 3, + TOF_STATE_IWAITCL = 4, + TOF_STATE_TWAITCL = 5, + TOF_STATE_ICONFIRM = 6, + TOF_STATE_IREPORT = 7 +}; + +enum tof_mode_type { + TOF_LEGACY_UNKNOWN = 0, + TOF_LEGACY_AP = 1, + TOF_NONLEGACY_AP = 2 +}; + +enum tof_way_type { + TOF_TYPE_ONE_WAY = 0, + TOF_TYPE_TWO_WAY = 1, + TOF_TYPE_REPORT = 2 +}; + +enum tof_rate_type { + TOF_FRAME_RATE_VHT = 0, + TOF_FRAME_RATE_LEGACY = 1 +}; + +#define TOF_ADJ_TYPE_NUM 4 /* number of assisted timestamp adjustment */ +enum tof_adj_mode { + TOF_ADJ_SOFTWARE = 0, + TOF_ADJ_HARDWARE = 1, + TOF_ADJ_SEQ = 2, + TOF_ADJ_NONE = 3 +}; + +#define FRAME_TYPE_NUM 4 /* number of frame type */ +enum frame_type { + FRAME_TYPE_CCK = 0, + FRAME_TYPE_OFDM = 1, + FRAME_TYPE_11N = 2, + FRAME_TYPE_11AC = 3 +}; + +typedef struct wl_proxd_status_iovar { + uint16 method; /* method */ + uint8 mode; /* mode */ + uint8 peermode; /* peer mode */ + uint8 state; /* state */ + uint8 reason; /* reason code */ + uint32 distance; /* distance */ + uint32 txcnt; /* tx pkt counter */ + uint32 rxcnt; /* rx pkt counter */ + struct ether_addr peer; /* peer mac address */ + int8 avg_rssi; /* average rssi */ + int8 hi_rssi; /* highest rssi */ + int8 low_rssi; /* lowest rssi */ + uint32 dbgstatus; /* debug status */ + uint16 frame_type_cnt[FRAME_TYPE_NUM]; /* frame types */ + uint8 adj_type_cnt[TOF_ADJ_TYPE_NUM]; /* adj types HW/SW */ +} wl_proxd_status_iovar_t; + +#ifdef NET_DETECT +typedef struct net_detect_adapter_features { + bool wowl_enabled; + bool net_detect_enabled; + bool nlo_enabled; +} net_detect_adapter_features_t; + +typedef enum net_detect_bss_type { + nd_bss_any = 0, + nd_ibss, + nd_ess +} net_detect_bss_type_t; + +typedef struct net_detect_profile { + wlc_ssid_t ssid; + net_detect_bss_type_t bss_type; /* Ignore for now since Phase 1 is only for ESS */ + uint32 cipher_type; /* DOT11_CIPHER_ALGORITHM enumeration values */ + uint32 auth_type; /* DOT11_AUTH_ALGORITHM enumeration values */ +} net_detect_profile_t; + +typedef struct net_detect_profile_list { + uint32 num_nd_profiles; + net_detect_profile_t nd_profile[0]; +} net_detect_profile_list_t; + +typedef struct net_detect_config { + bool nd_enabled; + uint32 scan_interval; + uint32 wait_period; + bool wake_if_connected; + bool wake_if_disconnected; + net_detect_profile_list_t nd_profile_list; +} net_detect_config_t; + +typedef enum net_detect_wake_reason { + nd_reason_unknown, + nd_net_detected, + nd_wowl_event, + nd_ucode_error +} net_detect_wake_reason_t; + +typedef struct net_detect_wake_data { + net_detect_wake_reason_t nd_wake_reason; + uint32 nd_wake_date_length; + uint8 nd_wake_data[0]; /* Wake data (currently unused) */ +} net_detect_wake_data_t; + +#endif /* NET_DETECT */ + +typedef struct bcnreq { + uint8 bcn_mode; + int dur; + int channel; + struct ether_addr da; + uint16 random_int; + wlc_ssid_t ssid; + uint16 reps; +} bcnreq_t; + +typedef struct rrmreq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + uint16 reps; +} rrmreq_t; + +typedef struct framereq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + struct ether_addr ta; + uint16 reps; +} framereq_t; + +typedef struct statreq { + struct ether_addr da; + struct ether_addr peer; + uint16 random_int; + uint16 dur; + uint8 group_id; + uint16 reps; +} statreq_t; + +typedef struct wlc_l2keepalive_ol_params { + uint8 flags; + uint8 prio; + uint16 period_ms; +} wlc_l2keepalive_ol_params_t; + +typedef struct wlc_dwds_config { + uint32 enable; + uint32 mode; /* STA/AP interface */ + struct ether_addr ea; +} wlc_dwds_config_t; + +typedef struct wl_el_set_params_s { + uint8 set; /* Set number */ + uint32 size; /* Size to make/expand */ +} wl_el_set_params_t; + +typedef struct wl_el_tag_params_s { + uint16 tag; + uint8 set; + uint8 flags; +} wl_el_tag_params_t; + +/* Video Traffic Interference Monitor config */ +#define INTFER_VERSION 1 +typedef struct wl_intfer_params { + uint16 version; /* version */ + uint8 period; /* sample period */ + uint8 cnt; /* sample cnt */ + uint8 txfail_thresh; /* non-TCP txfail threshold */ + uint8 tcptxfail_thresh; /* tcptxfail threshold */ +} wl_intfer_params_t; + +typedef struct wl_staprio_cfg { + struct ether_addr ea; /* mac addr */ + uint8 prio; /* scb priority */ +} wl_staprio_cfg_t; + +typedef enum wl_stamon_cfg_cmd_type { + STAMON_CFG_CMD_DEL = 0, + STAMON_CFG_CMD_ADD = 1 +} wl_stamon_cfg_cmd_type_t; + +typedef struct wlc_stamon_sta_config { + wl_stamon_cfg_cmd_type_t cmd; /* 0 - delete, 1 - add */ + struct ether_addr ea; +} wlc_stamon_sta_config_t; + +/* Received Beacons lengths information */ +#define WL_LAST_BCNS_INFO_FIXED_LEN OFFSETOF(wlc_bcn_len_hist_t, bcnlen_ring) +typedef struct wlc_bcn_len_hist { + uint16 ver; /* version field */ + uint16 cur_index; /* current pointed index in ring buffer */ + uint32 max_bcnlen; /* Max beacon length received */ + uint32 min_bcnlen; /* Min beacon length received */ + uint32 ringbuff_len; /* Length of the ring buffer 'bcnlen_ring' */ + uint32 bcnlen_ring[1]; /* ring buffer storing received beacon lengths */ +} wlc_bcn_len_hist_t; + +/* WDS net interface types */ +#define WL_WDSIFTYPE_NONE 0x0 /* The interface type is neither WDS nor DWDS. */ +#define WL_WDSIFTYPE_WDS 0x1 /* The interface is WDS type. */ +#define WL_WDSIFTYPE_DWDS 0x2 /* The interface is DWDS type. */ + +typedef struct wl_bssload_static { + bool is_static; + uint16 sta_count; + uint8 chan_util; + uint16 aac; +} wl_bssload_static_t; + + +#define WL_IF_STATS_T_VERSION 1 /* current version of wl_if_stats structure */ + +/* per interface counters */ +typedef struct wl_if_stats { + uint16 version; /* version of the structure */ + uint16 length; /* length of the entire structure */ + uint32 PAD; /* padding */ + + /* transmit stat counters */ + uint64 txframe; /* tx data frames */ + uint64 txbyte; /* tx data bytes */ + uint64 txerror; /* tx data errors (derived: sum of others) */ + uint64 txnobuf; /* tx out of buffer errors */ + uint64 txrunt; /* tx runt frames */ + uint64 txfail; /* tx failed frames */ + uint64 txretry; /* tx retry frames */ + uint64 txretrie; /* tx multiple retry frames */ + uint64 txfrmsnt; /* tx sent frames */ + uint64 txmulti; /* tx mulitcast sent frames */ + uint64 txfrag; /* tx fragments sent */ + + /* receive stat counters */ + uint64 rxframe; /* rx data frames */ + uint64 rxbyte; /* rx data bytes */ + uint64 rxerror; /* rx data errors (derived: sum of others) */ + uint64 rxnobuf; /* rx out of buffer errors */ + uint64 rxrunt; /* rx runt frames */ + uint64 rxfragerr; /* rx fragment errors */ + uint64 rxmulti; /* rx multicast frames */ + + uint64 txexptime; /* DATA Tx frames suppressed due to timer expiration */ + uint64 txrts; /* RTS/CTS succeeeded count */ + uint64 txnocts; /* RTS/CTS faled count */ +} +wl_if_stats_t; + +/* require strict packing */ +#include +#define WL_PROXD_API_VERSION 0x0300 /* version 3.0 */ + +/* proximity detection methods */ +enum { + WL_PROXD_METHOD_NONE = 0, + WL_PROXD_METHOD_RSVD1 = 1, /* backward compatibility - RSSI, not supported */ + WL_PROXD_METHOD_TOF = 2, /* 11v+BCM proprietary */ + WL_PROXD_METHOD_RSVD2 = 3, /* 11v only - if needed */ + WL_PROXD_METHOD_FTM = 4, /* IEEE rev mc/2014 */ + WL_PROXD_METHOD_MAX +}; +typedef int16 wl_proxd_method_t; + +/* global and method configuration flags */ +enum { + WL_PROXD_FLAG_NONE = 0x00000000, + WL_PROXD_FLAG_RX_ENABLED = 0x00000001, /* respond to requests */ + WL_PROXD_FLAG_RX_RANGE_REQ = 0x00000002, /* 11mc range requests enabled */ + WL_PROXD_FLAG_TX_LCI = 0x00000004, /* transmit location, if available */ + WL_PROXD_FLAG_TX_CIVIC = 0x00000008, /* tx civic loc, if available */ + WL_PROXD_FLAG_RX_AUTO_BURST = 0x00000010, /* respond to requests w/o host action */ + WL_PROXD_FLAG_TX_AUTO_BURST = 0x00000020, /* continue requests w/o host action */ + WL_PROXD_FLAG_ALL = 0xffffffff +}; +typedef uint32 wl_proxd_flags_t; + +/* session flags */ +enum { + WL_PROXD_SESSION_FLAG_NONE = 0x00000000, /* no flags */ + WL_PROXD_SESSION_FLAG_INITIATOR = 0x00000001, /* local device is initiator */ + WL_PROXD_SESSION_FLAG_TARGET = 0x00000002, /* local device is target */ + WL_PROXD_SESSION_FLAG_ONE_WAY = 0x00000004, /* (initiated) 1-way rtt */ + WL_PROXD_SESSION_FLAG_AUTO_BURST = 0x00000008, /* created w/ rx_auto_burst */ + WL_PROXD_SESSION_FLAG_PERSIST = 0x00000010, /* good until cancelled */ + WL_PROXD_SESSION_FLAG_RTT_DETAIL = 0x00000020, /* rtt detail in results */ + WL_PROXD_SESSION_FLAG_TOF_COMPAT = 0x00000040, /* TOF compatibility - TBD */ + WL_PROXD_SESSION_FLAG_AOA = 0x00000080, /* AOA along w/ RTT */ + WL_PROXD_SESSION_FLAG_RX_AUTO_BURST = 0x00000100, /* Same as proxd flags above */ + WL_PROXD_SESSION_FLAG_TX_AUTO_BURST = 0x00000200, /* Same as proxd flags above */ + WL_PROXD_SESSION_FLAG_NAN_BSS = 0x00000400, /* Use NAN BSS, if applicable */ + WL_PROXD_SESSION_FLAG_TS1 = 0x00000800, /* e.g. FTM1 - cap or rx */ + WL_PROXD_SESSION_FLAG_REPORT_FAILURE = 0x00002000, /* report failure to target */ + WL_PROXD_SESSION_FLAG_INITIATOR_RPT = 0x00004000, /* report distance to target */ + WL_PROXD_SESSION_FLAG_NOCHANSWT = 0x00008000, /* No channel switching */ + WL_PROXD_SESSION_FLAG_NETRUAL = 0x00010000, /* netrual mode */ + WL_PROXD_SESSION_FLAG_SEQ_EN = 0x00020000, /* Toast */ + WL_PROXD_SESSION_FLAG_NO_PARAM_OVRD = 0x00040000, /* no param override from target */ + WL_PROXD_SESSION_FLAG_ASAP = 0x00080000, /* ASAP session */ + WL_PROXD_SESSION_FLAG_REQ_LCI = 0x00100000, /* transmit LCI req */ + WL_PROXD_SESSION_FLAG_REQ_CIV = 0x00200000, /* transmit civic loc req */ + WL_PROXD_SESSION_FLAG_COLLECT = 0x80000000, /* debug - collect */ + WL_PROXD_SESSION_FLAG_ALL = 0xffffffff +}; +typedef uint32 wl_proxd_session_flags_t; + +/* time units - mc supports up to 0.1ns resolution */ +enum { + WL_PROXD_TMU_TU = 0, /* 1024us */ + WL_PROXD_TMU_SEC = 1, + WL_PROXD_TMU_MILLI_SEC = 2, + WL_PROXD_TMU_MICRO_SEC = 3, + WL_PROXD_TMU_NANO_SEC = 4, + WL_PROXD_TMU_PICO_SEC = 5 +}; +typedef int16 wl_proxd_tmu_t; + +/* time interval e.g. 10ns */ +typedef struct wl_proxd_intvl { + uint32 intvl; + wl_proxd_tmu_t tmu; + uint8 pad[2]; +} wl_proxd_intvl_t; + +/* commands that can apply to proxd, method or a session */ +enum { + WL_PROXD_CMD_NONE = 0, + WL_PROXD_CMD_GET_VERSION = 1, + WL_PROXD_CMD_ENABLE = 2, + WL_PROXD_CMD_DISABLE = 3, + WL_PROXD_CMD_CONFIG = 4, + WL_PROXD_CMD_START_SESSION = 5, + WL_PROXD_CMD_BURST_REQUEST = 6, + WL_PROXD_CMD_STOP_SESSION = 7, + WL_PROXD_CMD_DELETE_SESSION = 8, + WL_PROXD_CMD_GET_RESULT = 9, + WL_PROXD_CMD_GET_INFO = 10, + WL_PROXD_CMD_GET_STATUS = 11, + WL_PROXD_CMD_GET_SESSIONS = 12, + WL_PROXD_CMD_GET_COUNTERS = 13, + WL_PROXD_CMD_CLEAR_COUNTERS = 14, + WL_PROXD_CMD_COLLECT = 15, + WL_PROXD_CMD_TUNE = 16, + WL_PROXD_CMD_DUMP = 17, + WL_PROXD_CMD_START_RANGING = 18, + WL_PROXD_CMD_STOP_RANGING = 19, + WL_PROXD_CMD_GET_RANGING_INFO = 20, + WL_PROXD_CMD_MAX +}; +typedef int16 wl_proxd_cmd_t; + +/* session ids: + * id 0 is reserved + * ids 1..0x7fff - allocated by host/app + * 0x8000-0xffff - allocated by firmware, used for auto/rx + */ +enum { + WL_PROXD_SESSION_ID_GLOBAL = 0 +}; + +#define WL_PROXD_SID_HOST_MAX 0x7fff +#define WL_PROXD_SID_HOST_ALLOC(_sid) ((_sid) > 0 && (_sid) <= WL_PROXD_SID_HOST_MAX) + +/* maximum number sessions that can be allocated, may be less if tunable */ +#define WL_PROXD_MAX_SESSIONS 16 + +typedef uint16 wl_proxd_session_id_t; + +/* status - TBD BCME_ vs proxd status - range reserved for BCME_ */ +enum { + WL_PROXD_E_INCOMPLETE = -1044, + WL_PROXD_E_OVERRIDDEN = -1043, + WL_PROXD_E_ASAP_FAILED = -1042, + WL_PROXD_E_NOTSTARTED = -1041, + WL_PROXD_E_INVALIDAVB = -1040, + WL_PROXD_E_INCAPABLE = -1039, + WL_PROXD_E_MISMATCH = -1038, + WL_PROXD_E_DUP_SESSION = -1037, + WL_PROXD_E_REMOTE_FAIL = -1036, + WL_PROXD_E_REMOTE_INCAPABLE = -1035, + WL_PROXD_E_SCHED_FAIL = -1034, + WL_PROXD_E_PROTO = -1033, + WL_PROXD_E_EXPIRED = -1032, + WL_PROXD_E_TIMEOUT = -1031, + WL_PROXD_E_NOACK = -1030, + WL_PROXD_E_DEFERRED = -1029, + WL_PROXD_E_INVALID_SID = -1028, + WL_PROXD_E_REMOTE_CANCEL = -1027, + WL_PROXD_E_CANCELED = -1026, /* local */ + WL_PROXD_E_INVALID_SESSION = -1025, + WL_PROXD_E_BAD_STATE = -1024, + WL_PROXD_E_ERROR = -1, + WL_PROXD_E_OK = 0 +}; +typedef int32 wl_proxd_status_t; + +/* session states */ +enum { + WL_PROXD_SESSION_STATE_NONE = 0, + WL_PROXD_SESSION_STATE_CREATED = 1, + WL_PROXD_SESSION_STATE_CONFIGURED = 2, + WL_PROXD_SESSION_STATE_STARTED = 3, + WL_PROXD_SESSION_STATE_DELAY = 4, + WL_PROXD_SESSION_STATE_USER_WAIT = 5, + WL_PROXD_SESSION_STATE_SCHED_WAIT = 6, + WL_PROXD_SESSION_STATE_BURST = 7, + WL_PROXD_SESSION_STATE_STOPPING = 8, + WL_PROXD_SESSION_STATE_ENDED = 9, + WL_PROXD_SESSION_STATE_DESTROYING = -1 +}; +typedef int16 wl_proxd_session_state_t; + +/* RTT sample flags */ +enum { + WL_PROXD_RTT_SAMPLE_NONE = 0x00, + WL_PROXD_RTT_SAMPLE_DISCARD = 0x01 +}; +typedef uint8 wl_proxd_rtt_sample_flags_t; + +typedef struct wl_proxd_rtt_sample { + uint8 id; /* id for the sample - non-zero */ + wl_proxd_rtt_sample_flags_t flags; + int16 rssi; + wl_proxd_intvl_t rtt; /* round trip time */ + uint32 ratespec; +} wl_proxd_rtt_sample_t; + +/* result flags */ +enum { + WL_PRXOD_RESULT_FLAG_NONE = 0x0000, + WL_PROXD_RESULT_FLAG_NLOS = 0x0001, /* LOS - if available */ + WL_PROXD_RESULT_FLAG_LOS = 0x0002, /* NLOS - if available */ + WL_PROXD_RESULT_FLAG_FATAL = 0x0004, /* Fatal error during burst */ + WL_PROXD_RESULT_FLAG_ALL = 0xffff +}; +typedef int16 wl_proxd_result_flags_t; + +/* rtt measurement result */ +typedef struct wl_proxd_rtt_result { + wl_proxd_session_id_t sid; + wl_proxd_result_flags_t flags; + wl_proxd_status_t status; + struct ether_addr peer; + wl_proxd_session_state_t state; /* current state */ + union { + wl_proxd_intvl_t retry_after; /* hint for errors */ + wl_proxd_intvl_t burst_duration; /* burst duration */ + } u; + wl_proxd_rtt_sample_t avg_rtt; + uint32 avg_dist; /* 1/256m units */ + uint16 sd_rtt; /* RTT standard deviation */ + uint8 num_valid_rtt; /* valid rtt cnt */ + uint8 num_ftm; /* actual num of ftm cnt */ + uint16 burst_num; /* in a session */ + uint16 num_rtt; /* 0 if no detail */ + wl_proxd_rtt_sample_t rtt[1]; /* variable */ +} wl_proxd_rtt_result_t; + +/* aoa measurement result */ +typedef struct wl_proxd_aoa_result { + wl_proxd_session_id_t sid; + wl_proxd_result_flags_t flags; + wl_proxd_status_t status; + struct ether_addr peer; + wl_proxd_session_state_t state; + uint16 burst_num; + uint8 pad[2]; + /* wl_proxd_aoa_sample_t sample_avg; TBD */ +} BWL_POST_PACKED_STRUCT wl_proxd_aoa_result_t; + +/* global stats */ +typedef struct wl_proxd_counters { + uint32 tx; /* tx frame count */ + uint32 rx; /* rx frame count */ + uint32 burst; /* total number of burst */ + uint32 sessions; /* total number of sessions */ + uint32 max_sessions; /* max concurrency */ + uint32 sched_fail; /* scheduling failures */ + uint32 timeouts; /* timeouts */ + uint32 protoerr; /* protocol errors */ + uint32 noack; /* tx w/o ack */ + uint32 txfail; /* any tx falure */ + uint32 lci_req_tx; /* tx LCI requests */ + uint32 lci_req_rx; /* rx LCI requests */ + uint32 lci_rep_tx; /* tx LCI reports */ + uint32 lci_rep_rx; /* rx LCI reports */ + uint32 civic_req_tx; /* tx civic requests */ + uint32 civic_req_rx; /* rx civic requests */ + uint32 civic_rep_tx; /* tx civic reports */ + uint32 civic_rep_rx; /* rx civic reports */ + uint32 rctx; /* ranging contexts created */ + uint32 rctx_done; /* count of ranging done */ +} wl_proxd_counters_t; + +typedef struct wl_proxd_counters wl_proxd_session_counters_t; + +enum { + WL_PROXD_CAP_NONE = 0x0000, + WL_PROXD_CAP_ALL = 0xffff +}; +typedef int16 wl_proxd_caps_t; + +/* method capabilities */ +enum { + WL_PROXD_FTM_CAP_NONE = 0x0000, + WL_PROXD_FTM_CAP_FTM1 = 0x0001 +}; +typedef uint16 wl_proxd_ftm_caps_t; + +typedef struct BWL_PRE_PACKED_STRUCT wl_proxd_tlv_id_list { + uint16 num_ids; + uint16 ids[1]; +} BWL_POST_PACKED_STRUCT wl_proxd_tlv_id_list_t; + +typedef struct wl_proxd_session_id_list { + uint16 num_ids; + wl_proxd_session_id_t ids[1]; +} wl_proxd_session_id_list_t; + +/* tlvs returned for get_info on ftm method + * configuration: + * proxd flags + * event mask + * debug mask + * session defaults (session tlvs) + * status tlv - not supported for ftm method + * info tlv + */ +typedef struct wl_proxd_ftm_info { + wl_proxd_ftm_caps_t caps; + uint16 max_sessions; + uint16 num_sessions; + uint16 rx_max_burst; +} wl_proxd_ftm_info_t; + +/* tlvs returned for get_info on session + * session config (tlvs) + * session info tlv + */ +typedef struct wl_proxd_ftm_session_info { + uint16 sid; + uint8 bss_index; + uint8 pad; + struct ether_addr bssid; + wl_proxd_session_state_t state; + wl_proxd_status_t status; + uint16 burst_num; +} wl_proxd_ftm_session_info_t; + +typedef struct wl_proxd_ftm_session_status { + uint16 sid; + wl_proxd_session_state_t state; + wl_proxd_status_t status; + uint16 burst_num; +} wl_proxd_ftm_session_status_t; + +/* rrm range request */ +typedef struct wl_proxd_range_req { + uint16 num_repeat; + uint16 init_delay_range; /* in TUs */ + uint8 pad; + uint8 num_nbr; /* number of (possible) neighbors */ + nbr_element_t nbr[1]; +} wl_proxd_range_req_t; + +#define WL_PROXD_LCI_LAT_OFF 0 +#define WL_PROXD_LCI_LONG_OFF 5 +#define WL_PROXD_LCI_ALT_OFF 10 + +#define WL_PROXD_LCI_GET_LAT(_lci, _lat, _lat_err) { \ + unsigned _off = WL_PROXD_LCI_LAT_OFF; \ + _lat_err = (_lci)->data[(_off)] & 0x3f; \ + _lat = (_lci)->data[(_off)+1]; \ + _lat |= (_lci)->data[(_off)+2] << 8; \ + _lat |= (_lci)->data[_(_off)+3] << 16; \ + _lat |= (_lci)->data[(_off)+4] << 24; \ + _lat <<= 2; \ + _lat |= (_lci)->data[(_off)] >> 6; \ +} + +#define WL_PROXD_LCI_GET_LONG(_lci, _lcilong, _long_err) { \ + unsigned _off = WL_PROXD_LCI_LONG_OFF; \ + _long_err = (_lci)->data[(_off)] & 0x3f; \ + _lcilong = (_lci)->data[(_off)+1]; \ + _lcilong |= (_lci)->data[(_off)+2] << 8; \ + _lcilong |= (_lci)->data[_(_off)+3] << 16; \ + _lcilong |= (_lci)->data[(_off)+4] << 24; \ + __lcilong <<= 2; \ + _lcilong |= (_lci)->data[(_off)] >> 6; \ +} + +#define WL_PROXD_LCI_GET_ALT(_lci, _alt_type, _alt, _alt_err) { \ + unsigned _off = WL_PROXD_LCI_ALT_OFF; \ + _alt_type = (_lci)->data[_off] & 0x0f; \ + _alt_err = (_lci)->data[(_off)] >> 4; \ + _alt_err |= ((_lci)->data[(_off)+1] & 0x03) << 4; \ + _alt = (_lci)->data[(_off)+2]; \ + _alt |= (_lci)->data[(_off)+3] << 8; \ + _alt |= (_lci)->data[_(_off)+4] << 16; \ + _alt <<= 6; \ + _alt |= (_lci)->data[(_off) + 1] >> 2; \ +} + +#define WL_PROXD_LCI_VERSION(_lci) ((_lci)->data[15] >> 6) + +/* availability. advertising mechanism bss specific */ +/* availablity flags */ +enum { + WL_PROXD_AVAIL_NONE = 0, + WL_PROXD_AVAIL_NAN_PUBLISHED = 0x0001, + WL_PROXD_AVAIL_SCHEDULED = 0x0002 /* scheduled by proxd */ +}; +typedef int16 wl_proxd_avail_flags_t; + +/* time reference */ +enum { + WL_PROXD_TREF_NONE = 0, + WL_PROXD_TREF_DEV_TSF = 1, + WL_PROXD_TREF_NAN_DW = 2, + WL_PROXD_TREF_TBTT = 3, + WL_PROXD_TREF_MAX /* last entry */ +}; +typedef int16 wl_proxd_time_ref_t; + +/* proxd channel-time slot */ +typedef struct { + wl_proxd_intvl_t start; /* from ref */ + wl_proxd_intvl_t duration; /* from start */ + uint32 chanspec; +} wl_proxd_time_slot_t; + +/* availability. advertising mechanism bss specific */ +typedef struct wl_proxd_avail { + wl_proxd_avail_flags_t flags; /* for query only */ + wl_proxd_time_ref_t time_ref; + uint16 max_slots; /* for query only */ + uint16 num_slots; + wl_proxd_time_slot_t slots[1]; +} wl_proxd_avail_t; + +/* collect support TBD */ + +/* debugging */ +enum { + WL_PROXD_DEBUG_NONE = 0x00000000, + WL_PROXD_DEBUG_LOG = 0x00000001, + WL_PROXD_DEBUG_IOV = 0x00000002, + WL_PROXD_DEBUG_EVENT = 0x00000004, + WL_PROXD_DEBUG_SESSION = 0x00000008, + WL_PROXD_DEBUG_PROTO = 0x00000010, + WL_PROXD_DEBUG_SCHED = 0x00000020, + WL_PROXD_DEBUG_RANGING = 0x00000040, + WL_PROXD_DEBUG_ALL = 0xffffffff +}; +typedef uint32 wl_proxd_debug_mask_t; + +/* tlv IDs - data length 4 bytes unless overridden by type, alignment 32 bits */ +enum { + WL_PROXD_TLV_ID_NONE = 0, + WL_PROXD_TLV_ID_METHOD = 1, + WL_PROXD_TLV_ID_FLAGS = 2, + WL_PROXD_TLV_ID_CHANSPEC = 3, /* note: uint32 */ + WL_PROXD_TLV_ID_TX_POWER = 4, + WL_PROXD_TLV_ID_RATESPEC = 5, + WL_PROXD_TLV_ID_BURST_DURATION = 6, /* intvl - length of burst */ + WL_PROXD_TLV_ID_BURST_PERIOD = 7, /* intvl - between bursts */ + WL_PROXD_TLV_ID_BURST_FTM_SEP = 8, /* intvl - between FTMs */ + WL_PROXD_TLV_ID_BURST_NUM_FTM = 9, /* uint16 - per burst */ + WL_PROXD_TLV_ID_NUM_BURST = 10, /* uint16 */ + WL_PROXD_TLV_ID_FTM_RETRIES = 11, /* uint16 at FTM level */ + WL_PROXD_TLV_ID_BSS_INDEX = 12, /* uint8 */ + WL_PROXD_TLV_ID_BSSID = 13, + WL_PROXD_TLV_ID_INIT_DELAY = 14, /* intvl - optional, non-standalone only */ + WL_PROXD_TLV_ID_BURST_TIMEOUT = 15, /* expect response within - intvl */ + WL_PROXD_TLV_ID_EVENT_MASK = 16, /* interested events - in/out */ + WL_PROXD_TLV_ID_FLAGS_MASK = 17, /* interested flags - in only */ + WL_PROXD_TLV_ID_PEER_MAC = 18, /* mac address of peer */ + WL_PROXD_TLV_ID_FTM_REQ = 19, /* dot11_ftm_req */ + WL_PROXD_TLV_ID_LCI_REQ = 20, + WL_PROXD_TLV_ID_LCI = 21, + WL_PROXD_TLV_ID_CIVIC_REQ = 22, + WL_PROXD_TLV_ID_CIVIC = 23, + WL_PROXD_TLV_ID_AVAIL = 24, + WL_PROXD_TLV_ID_SESSION_FLAGS = 25, + WL_PROXD_TLV_ID_SESSION_FLAGS_MASK = 26, /* in only */ + WL_PROXD_TLV_ID_RX_MAX_BURST = 27, /* uint16 - limit bursts per session */ + WL_PROXD_TLV_ID_RANGING_INFO = 28, /* ranging info */ + WL_PROXD_TLV_ID_RANGING_FLAGS = 29, /* uint16 */ + WL_PROXD_TLV_ID_RANGING_FLAGS_MASK = 30, /* uint16, in only */ + /* 31 - 34 reserved for other feature */ + WL_PROXD_TLV_ID_FTM_REQ_RETRIES = 35, /* uint16 FTM request retries */ + + /* output - 512 + x */ + WL_PROXD_TLV_ID_STATUS = 512, + WL_PROXD_TLV_ID_COUNTERS = 513, + WL_PROXD_TLV_ID_INFO = 514, + WL_PROXD_TLV_ID_RTT_RESULT = 515, + WL_PROXD_TLV_ID_AOA_RESULT = 516, + WL_PROXD_TLV_ID_SESSION_INFO = 517, + WL_PROXD_TLV_ID_SESSION_STATUS = 518, + WL_PROXD_TLV_ID_SESSION_ID_LIST = 519, + + /* debug tlvs can be added starting 1024 */ + WL_PROXD_TLV_ID_DEBUG_MASK = 1024, + WL_PROXD_TLV_ID_COLLECT = 1025, /* output only */ + WL_PROXD_TLV_ID_STRBUF = 1026, + + WL_PROXD_TLV_ID_MAX +}; + +typedef struct wl_proxd_tlv { + uint16 id; + uint16 len; + uint8 data[1]; +} wl_proxd_tlv_t; + +/* proxd iovar - applies to proxd, method or session */ +typedef struct wl_proxd_iov { + uint16 version; + uint16 len; + wl_proxd_cmd_t cmd; + wl_proxd_method_t method; + wl_proxd_session_id_t sid; + uint8 pad[2]; + wl_proxd_tlv_t tlvs[1]; /* variable */ +} wl_proxd_iov_t; + +#define WL_PROXD_IOV_HDR_SIZE OFFSETOF(wl_proxd_iov_t, tlvs) + +/* The following event definitions may move to bcmevent.h, but sharing proxd types + * across needs more invasive changes unrelated to proxd + */ +enum { + WL_PROXD_EVENT_NONE = 0, /* not an event, reserved */ + WL_PROXD_EVENT_SESSION_CREATE = 1, + WL_PROXD_EVENT_SESSION_START = 2, + WL_PROXD_EVENT_FTM_REQ = 3, + WL_PROXD_EVENT_BURST_START = 4, + WL_PROXD_EVENT_BURST_END = 5, + WL_PROXD_EVENT_SESSION_END = 6, + WL_PROXD_EVENT_SESSION_RESTART = 7, + WL_PROXD_EVENT_BURST_RESCHED = 8, /* burst rescheduled - e.g. partial TSF */ + WL_PROXD_EVENT_SESSION_DESTROY = 9, + WL_PROXD_EVENT_RANGE_REQ = 10, + WL_PROXD_EVENT_FTM_FRAME = 11, + WL_PROXD_EVENT_DELAY = 12, + WL_PROXD_EVENT_VS_INITIATOR_RPT = 13, /* (target) rx initiator-report */ + WL_PROXD_EVENT_RANGING = 14, + + WL_PROXD_EVENT_MAX +}; +typedef int16 wl_proxd_event_type_t; + +/* proxd event mask - upto 32 events for now */ +typedef uint32 wl_proxd_event_mask_t; + +#define WL_PROXD_EVENT_MASK_ALL 0xfffffffe +#define WL_PROXD_EVENT_MASK_EVENT(_event_type) (1 << (_event_type)) +#define WL_PROXD_EVENT_ENABLED(_mask, _event_type) (\ + ((_mask) & WL_PROXD_EVENT_MASK_EVENT(_event_type)) != 0) + +/* proxd event - applies to proxd, method or session */ +typedef struct wl_proxd_event { + uint16 version; + uint16 len; + wl_proxd_event_type_t type; + wl_proxd_method_t method; + wl_proxd_session_id_t sid; + uint8 pad[2]; + wl_proxd_tlv_t tlvs[1]; /* variable */ +} wl_proxd_event_t; + +enum { + WL_PROXD_RANGING_STATE_NONE = 0, + WL_PROXD_RANGING_STATE_NOTSTARTED = 1, + WL_PROXD_RANGING_STATE_INPROGRESS = 2, + WL_PROXD_RANGING_STATE_DONE = 3 +}; +typedef int16 wl_proxd_ranging_state_t; + +/* proxd ranging flags */ +enum { + WL_PROXD_RANGING_FLAG_NONE = 0x0000, /* no flags */ + WL_PROXD_RANGING_FLAG_DEL_SESSIONS_ON_STOP = 0x0001, + WL_PROXD_RANGING_FLAG_ALL = 0xffff +}; +typedef uint16 wl_proxd_ranging_flags_t; + +struct wl_proxd_ranging_info { + wl_proxd_status_t status; + wl_proxd_ranging_state_t state; + wl_proxd_ranging_flags_t flags; + uint16 num_sids; + uint16 num_done; +}; +typedef struct wl_proxd_ranging_info wl_proxd_ranging_info_t; + +/* end proxd definitions */ +/* no default structure packing */ +#include +#endif /* _wlioctl_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c b/drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c new file mode 100644 index 000000000000..0bd42de1f62b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c @@ -0,0 +1,1352 @@ +/* + * Linux OS Independent Layer + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: linux_osl.c 548460 2015-04-13 08:55:51Z $ + */ + +#define LINUX_PORT + +#include +#include +#include +#include + + +#include +#include +#include +#include + + + +#include + +#define PCI_CFG_RETRY 10 + +#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ +#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ +#define DUMPBUFSZ 1024 + +#ifdef CONFIG_DHD_USE_STATIC_BUF +#define DHD_SKB_HDRSIZE 336 +#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) +#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) +#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) + +#ifdef CUSTOMER_HW5 +#define STATIC_BUF_MAX_NUM 1 +#else +#define STATIC_BUF_MAX_NUM 16 +#endif /* CUSTOMER_HW5 */ +#define STATIC_BUF_SIZE (PAGE_SIZE*2) +#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) + +typedef struct bcm_static_buf { + spinlock_t static_lock; + unsigned char *buf_ptr; + unsigned char buf_use[STATIC_BUF_MAX_NUM]; +} bcm_static_buf_t; + +static bcm_static_buf_t *bcm_static_buf = 0; + +#define STATIC_PKT_MAX_NUM 8 +#if defined(ENHANCED_STATIC_BUF) +#define STATIC_PKT_4PAGE_NUM 1 +#define DHD_SKB_MAX_BUFSIZE DHD_SKB_4PAGE_BUFSIZE +#else +#define STATIC_PKT_4PAGE_NUM 0 +#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE +#endif /* ENHANCED_STATIC_BUF */ + +typedef struct bcm_static_pkt { + struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM]; + struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM]; +#ifdef ENHANCED_STATIC_BUF + struct sk_buff *skb_16k; +#endif + struct semaphore osl_pkt_sem; + unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM]; +} bcm_static_pkt_t; + +static bcm_static_pkt_t *bcm_static_skb = 0; + +void* wifi_platform_prealloc(void *adapter, int section, unsigned long size); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + +typedef struct bcm_mem_link { + struct bcm_mem_link *prev; + struct bcm_mem_link *next; + uint size; + int line; + void *osh; + char file[BCM_MEM_FILENAME_LEN]; +} bcm_mem_link_t; + +struct osl_cmn_info { + atomic_t malloced; + atomic_t pktalloced; /* Number of allocated packet buffers */ + spinlock_t dbgmem_lock; + bcm_mem_link_t *dbgmem_list; + spinlock_t pktalloc_lock; + atomic_t refcount; /* Number of references to this shared structure. */ +}; +typedef struct osl_cmn_info osl_cmn_t; + +struct osl_info { + osl_pubinfo_t pub; +#ifdef CTFPOOL + ctfpool_t *ctfpool; +#endif /* CTFPOOL */ + uint magic; + void *pdev; + uint failed; + uint bustype; + osl_cmn_t *cmn; /* Common OSL related data shred between two OSH's */ + + void *bus_handle; +}; + +#define OSL_PKTTAG_CLEAR(p) \ +do { \ + struct sk_buff *s = (struct sk_buff *)(p); \ + ASSERT(OSL_PKTTAG_SZ == 32); \ + *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ + *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ + *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ + *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ +} while (0) + +/* PCMCIA attribute space access macros */ + +/* Global ASSERT type flag */ +uint32 g_assert_type = FALSE; + +static int16 linuxbcmerrormap[] = +{ 0, /* 0 */ + -EINVAL, /* BCME_ERROR */ + -EINVAL, /* BCME_BADARG */ + -EINVAL, /* BCME_BADOPTION */ + -EINVAL, /* BCME_NOTUP */ + -EINVAL, /* BCME_NOTDOWN */ + -EINVAL, /* BCME_NOTAP */ + -EINVAL, /* BCME_NOTSTA */ + -EINVAL, /* BCME_BADKEYIDX */ + -EINVAL, /* BCME_RADIOOFF */ + -EINVAL, /* BCME_NOTBANDLOCKED */ + -EINVAL, /* BCME_NOCLK */ + -EINVAL, /* BCME_BADRATESET */ + -EINVAL, /* BCME_BADBAND */ + -E2BIG, /* BCME_BUFTOOSHORT */ + -E2BIG, /* BCME_BUFTOOLONG */ + -EBUSY, /* BCME_BUSY */ + -EINVAL, /* BCME_NOTASSOCIATED */ + -EINVAL, /* BCME_BADSSIDLEN */ + -EINVAL, /* BCME_OUTOFRANGECHAN */ + -EINVAL, /* BCME_BADCHAN */ + -EFAULT, /* BCME_BADADDR */ + -ENOMEM, /* BCME_NORESOURCE */ + -EOPNOTSUPP, /* BCME_UNSUPPORTED */ + -EMSGSIZE, /* BCME_BADLENGTH */ + -EINVAL, /* BCME_NOTREADY */ + -EPERM, /* BCME_EPERM */ + -ENOMEM, /* BCME_NOMEM */ + -EINVAL, /* BCME_ASSOCIATED */ + -ERANGE, /* BCME_RANGE */ + -EINVAL, /* BCME_NOTFOUND */ + -EINVAL, /* BCME_WME_NOT_ENABLED */ + -EINVAL, /* BCME_TSPEC_NOTFOUND */ + -EINVAL, /* BCME_ACM_NOTSUPPORTED */ + -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ + -EIO, /* BCME_SDIO_ERROR */ + -ENODEV, /* BCME_DONGLE_DOWN */ + -EINVAL, /* BCME_VERSION */ + -EIO, /* BCME_TXFAIL */ + -EIO, /* BCME_RXFAIL */ + -ENODEV, /* BCME_NODEVICE */ + -EINVAL, /* BCME_NMODE_DISABLED */ + -ENODATA, /* BCME_NONRESIDENT */ + -EINVAL, /* BCME_SCANREJECT */ + -EINVAL, /* BCME_USAGE_ERROR */ + -EIO, /* BCME_IOCTL_ERROR */ + -EIO, /* BCME_SERIAL_PORT_ERR */ + -EOPNOTSUPP, /* BCME_DISABLED, BCME_NOTENABLED */ + -EIO, /* BCME_DECERR */ + -EIO, /* BCME_ENCERR */ + -EIO, /* BCME_MICERR */ + -ERANGE, /* BCME_REPLAY */ + -EINVAL, /* BCME_IE_NOTFOUND */ + +/* When an new error code is added to bcmutils.h, add os + * specific error translation here as well + */ +/* check if BCME_LAST changed since the last time this function was updated */ +#if BCME_LAST != -52 +#error "You need to add a OS error translation in the linuxbcmerrormap \ + for new error code defined in bcmutils.h" +#endif +}; + +/* translate bcmerrors into linux errors */ +int +osl_error(int bcmerror) +{ + if (bcmerror > 0) + bcmerror = 0; + else if (bcmerror < BCME_LAST) + bcmerror = BCME_ERROR; + + /* Array bounds covered by ASSERT in osl_attach */ + return linuxbcmerrormap[-bcmerror]; +} +#ifdef SHARED_OSL_CMN +osl_t * +osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn) +{ +#else +osl_t * +osl_attach(void *pdev, uint bustype, bool pkttag) +{ + void **osl_cmn = NULL; +#endif /* SHARED_OSL_CMN */ + osl_t *osh; + gfp_t flags; + + flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; + if (!(osh = kmalloc(sizeof(osl_t), flags))) + return osh; + + ASSERT(osh); + + bzero(osh, sizeof(osl_t)); + + if (osl_cmn == NULL || *osl_cmn == NULL) { + if (!(osh->cmn = kmalloc(sizeof(osl_cmn_t), flags))) { + kfree(osh); + return NULL; + } + bzero(osh->cmn, sizeof(osl_cmn_t)); + if (osl_cmn) + *osl_cmn = osh->cmn; + atomic_set(&osh->cmn->malloced, 0); + osh->cmn->dbgmem_list = NULL; + spin_lock_init(&(osh->cmn->dbgmem_lock)); + + spin_lock_init(&(osh->cmn->pktalloc_lock)); + + } else { + osh->cmn = *osl_cmn; + } + atomic_add(1, &osh->cmn->refcount); + + /* Check that error map has the right number of entries in it */ + ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); + + osh->failed = 0; + osh->pdev = pdev; + osh->pub.pkttag = pkttag; + osh->bustype = bustype; + osh->magic = OS_HANDLE_MAGIC; + + switch (bustype) { + case PCI_BUS: + case SI_BUS: + case PCMCIA_BUS: + osh->pub.mmbus = TRUE; + break; + case JTAG_BUS: + case SDIO_BUS: + case USB_BUS: + case SPI_BUS: + case RPC_BUS: + osh->pub.mmbus = FALSE; + break; + default: + ASSERT(FALSE); + break; + } + + + + return osh; +} + +int osl_static_mem_init(osl_t *osh, void *adapter) +{ +#if defined(CONFIG_DHD_USE_STATIC_BUF) + if (!bcm_static_buf && adapter) { + if (!(bcm_static_buf = (bcm_static_buf_t *)wifi_platform_prealloc(adapter, + 3, STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) { + printk("can not alloc static buf!\n"); + bcm_static_skb = NULL; + ASSERT(osh->magic == OS_HANDLE_MAGIC); + kfree(osh); + return -ENOMEM; + } + else + printk("alloc static buf at %p!\n", bcm_static_buf); + + spin_lock_init(&bcm_static_buf->static_lock); + + bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; + } + + if (!bcm_static_skb && adapter) { + int i; + void *skb_buff_ptr = 0; + bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); +#ifdef CUSTOMER_HW5 + /* The SKB static buffer ID is defined as latest id of dhd_prealloc_index + * + 1 in dhd.h + */ + skb_buff_ptr = wifi_platform_prealloc(adapter, 14, 0); +#else + skb_buff_ptr = wifi_platform_prealloc(adapter, 4, 0); +#endif /* CUSTOMER_HW5 */ + if (!skb_buff_ptr) { + printk("cannot alloc static buf!\n"); + bcm_static_buf = NULL; + bcm_static_skb = NULL; + ASSERT(osh->magic == OS_HANDLE_MAGIC); + kfree(osh); + return -ENOMEM; + } + + bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * + (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM)); + for (i = 0; i < STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM; i++) + bcm_static_skb->pkt_use[i] = 0; + + sema_init(&bcm_static_skb->osl_pkt_sem, 1); + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + + return 0; +} + +void osl_set_bus_handle(osl_t *osh, void *bus_handle) +{ + osh->bus_handle = bus_handle; +} + +void* osl_get_bus_handle(osl_t *osh) +{ + return osh->bus_handle; +} + +void +osl_detach(osl_t *osh) +{ + if (osh == NULL) + return; + + ASSERT(osh->magic == OS_HANDLE_MAGIC); + atomic_sub(1, &osh->cmn->refcount); + if (atomic_read(&osh->cmn->refcount) == 0) { + kfree(osh->cmn); + } + kfree(osh); +} + +int osl_static_mem_deinit(osl_t *osh, void *adapter) +{ +#ifdef CONFIG_DHD_USE_STATIC_BUF + if (bcm_static_buf) { + bcm_static_buf = 0; + } + if (bcm_static_skb) { + bcm_static_skb = 0; + } +#endif + return 0; +} + +static struct sk_buff *osl_alloc_skb(osl_t *osh, unsigned int len) +{ + struct sk_buff *skb; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) + gfp_t flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; +#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_ZONE_DMA) + flags |= GFP_ATOMIC; +#endif + skb = __dev_alloc_skb(len, flags); +#else + skb = dev_alloc_skb(len); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) */ + return skb; +} + +#ifdef CTFPOOL + +#ifdef CTFPOOL_SPINLOCK +#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_irqsave(&(ctfpool)->lock, flags) +#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_irqrestore(&(ctfpool)->lock, flags) +#else +#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_bh(&(ctfpool)->lock) +#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_bh(&(ctfpool)->lock) +#endif /* CTFPOOL_SPINLOCK */ +/* + * Allocate and add an object to packet pool. + */ +void * +osl_ctfpool_add(osl_t *osh) +{ + struct sk_buff *skb; +#ifdef CTFPOOL_SPINLOCK + unsigned long flags; +#endif /* CTFPOOL_SPINLOCK */ + + if ((osh == NULL) || (osh->ctfpool == NULL)) + return NULL; + + CTFPOOL_LOCK(osh->ctfpool, flags); + ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj); + + /* No need to allocate more objects */ + if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) { + CTFPOOL_UNLOCK(osh->ctfpool, flags); + return NULL; + } + + /* Allocate a new skb and add it to the ctfpool */ + skb = osl_alloc_skb(osh, osh->ctfpool->obj_size); + if (skb == NULL) { + printf("%s: skb alloc of len %d failed\n", __FUNCTION__, + osh->ctfpool->obj_size); + CTFPOOL_UNLOCK(osh->ctfpool, flags); + return NULL; + } + + /* Add to ctfpool */ + skb->next = (struct sk_buff *)osh->ctfpool->head; + osh->ctfpool->head = skb; + osh->ctfpool->fast_frees++; + osh->ctfpool->curr_obj++; + + /* Hijack a skb member to store ptr to ctfpool */ + CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool; + + /* Use bit flag to indicate skb from fast ctfpool */ + PKTFAST(osh, skb) = FASTBUF; + + CTFPOOL_UNLOCK(osh->ctfpool, flags); + + return skb; +} + +/* + * Add new objects to the pool. + */ +void +osl_ctfpool_replenish(osl_t *osh, uint thresh) +{ + if ((osh == NULL) || (osh->ctfpool == NULL)) + return; + + /* Do nothing if no refills are required */ + while ((osh->ctfpool->refills > 0) && (thresh--)) { + osl_ctfpool_add(osh); + osh->ctfpool->refills--; + } +} + +/* + * Initialize the packet pool with specified number of objects. + */ +int32 +osl_ctfpool_init(osl_t *osh, uint numobj, uint size) +{ + gfp_t flags; + + flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; + osh->ctfpool = kzalloc(sizeof(ctfpool_t), flags); + ASSERT(osh->ctfpool); + + osh->ctfpool->max_obj = numobj; + osh->ctfpool->obj_size = size; + + spin_lock_init(&osh->ctfpool->lock); + + while (numobj--) { + if (!osl_ctfpool_add(osh)) + return -1; + osh->ctfpool->fast_frees--; + } + + return 0; +} + +/* + * Cleanup the packet pool objects. + */ +void +osl_ctfpool_cleanup(osl_t *osh) +{ + struct sk_buff *skb, *nskb; +#ifdef CTFPOOL_SPINLOCK + unsigned long flags; +#endif /* CTFPOOL_SPINLOCK */ + + if ((osh == NULL) || (osh->ctfpool == NULL)) + return; + + CTFPOOL_LOCK(osh->ctfpool, flags); + + skb = osh->ctfpool->head; + + while (skb != NULL) { + nskb = skb->next; + dev_kfree_skb(skb); + skb = nskb; + osh->ctfpool->curr_obj--; + } + + ASSERT(osh->ctfpool->curr_obj == 0); + osh->ctfpool->head = NULL; + CTFPOOL_UNLOCK(osh->ctfpool, flags); + + kfree(osh->ctfpool); + osh->ctfpool = NULL; +} + +void +osl_ctfpool_stats(osl_t *osh, void *b) +{ + struct bcmstrbuf *bb; + + if ((osh == NULL) || (osh->ctfpool == NULL)) + return; + +#ifdef CONFIG_DHD_USE_STATIC_BUF + if (bcm_static_buf) { + bcm_static_buf = 0; + } + if (bcm_static_skb) { + bcm_static_skb = 0; + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + + bb = b; + + ASSERT((osh != NULL) && (bb != NULL)); + + bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n", + osh->ctfpool->max_obj, osh->ctfpool->obj_size, + osh->ctfpool->curr_obj, osh->ctfpool->refills); + bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n", + osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees, + osh->ctfpool->slow_allocs); +} + +static inline struct sk_buff * +osl_pktfastget(osl_t *osh, uint len) +{ + struct sk_buff *skb; +#ifdef CTFPOOL_SPINLOCK + unsigned long flags; +#endif /* CTFPOOL_SPINLOCK */ + + /* Try to do fast allocate. Return null if ctfpool is not in use + * or if there are no items in the ctfpool. + */ + if (osh->ctfpool == NULL) + return NULL; + + CTFPOOL_LOCK(osh->ctfpool, flags); + if (osh->ctfpool->head == NULL) { + ASSERT(osh->ctfpool->curr_obj == 0); + osh->ctfpool->slow_allocs++; + CTFPOOL_UNLOCK(osh->ctfpool, flags); + return NULL; + } + + if (len > osh->ctfpool->obj_size) { + CTFPOOL_UNLOCK(osh->ctfpool, flags); + return NULL; + } + + ASSERT(len <= osh->ctfpool->obj_size); + + /* Get an object from ctfpool */ + skb = (struct sk_buff *)osh->ctfpool->head; + osh->ctfpool->head = (void *)skb->next; + + osh->ctfpool->fast_allocs++; + osh->ctfpool->curr_obj--; + ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head); + CTFPOOL_UNLOCK(osh->ctfpool, flags); + + /* Init skb struct */ + skb->next = skb->prev = NULL; + skb->data = skb->head + 16; + skb->tail = skb->head + 16; + skb->len = 0; + skb->cloned = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) + skb->list = NULL; +#endif + atomic_set(&skb->users, 1); + + PKTSETCLINK(skb, NULL); + PKTCCLRATTR(skb); + PKTFAST(osh, skb) &= ~(CTFBUF | SKIPCT | CHAINED); + + return skb; +} +#endif /* CTFPOOL */ +/* Convert a driver packet to native(OS) packet + * In the process, packettag is zeroed out before sending up + * IP code depends on skb->cb to be setup correctly with various options + * In our case, that means it should be 0 + */ +struct sk_buff * BCMFASTPATH +osl_pkt_tonative(osl_t *osh, void *pkt) +{ + struct sk_buff *nskb; + + if (osh->pub.pkttag) + OSL_PKTTAG_CLEAR(pkt); + + /* Decrement the packet counter */ + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { + atomic_sub(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced); + + } + return (struct sk_buff *)pkt; +} + +/* Convert a native(OS) packet to driver packet. + * In the process, native packet is destroyed, there is no copying + * Also, a packettag is zeroed out + */ +void * BCMFASTPATH +osl_pkt_frmnative(osl_t *osh, void *pkt) +{ + struct sk_buff *nskb; + + if (osh->pub.pkttag) + OSL_PKTTAG_CLEAR(pkt); + + /* Increment the packet counter */ + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { + atomic_add(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced); + + } + return (void *)pkt; +} + +/* Return a new packet. zero out pkttag */ +void * BCMFASTPATH +osl_pktget(osl_t *osh, uint len) +{ + struct sk_buff *skb; + +#ifdef CTFPOOL + /* Allocate from local pool */ + skb = osl_pktfastget(osh, len); + if ((skb != NULL) || ((skb = osl_alloc_skb(osh, len)) != NULL)) { +#else /* CTFPOOL */ + if ((skb = osl_alloc_skb(osh, len))) { +#endif /* CTFPOOL */ + skb->tail += len; + skb->len += len; + skb->priority = 0; + + atomic_inc(&osh->cmn->pktalloced); + } + + return ((void*) skb); +} + +#ifdef CTFPOOL +static inline void +osl_pktfastfree(osl_t *osh, struct sk_buff *skb) +{ + ctfpool_t *ctfpool; +#ifdef CTFPOOL_SPINLOCK + unsigned long flags; +#endif /* CTFPOOL_SPINLOCK */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) + skb->tstamp.tv.sec = 0; +#else + skb->stamp.tv_sec = 0; +#endif + + /* We only need to init the fields that we change */ + skb->dev = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + skb->dst = NULL; +#endif + OSL_PKTTAG_CLEAR(skb); + skb->ip_summed = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + skb_orphan(skb); +#else + skb->destructor = NULL; +#endif + + ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); + ASSERT(ctfpool != NULL); + + /* Add object to the ctfpool */ + CTFPOOL_LOCK(ctfpool, flags); + skb->next = (struct sk_buff *)ctfpool->head; + ctfpool->head = (void *)skb; + + ctfpool->fast_frees++; + ctfpool->curr_obj++; + + ASSERT(ctfpool->curr_obj <= ctfpool->max_obj); + CTFPOOL_UNLOCK(ctfpool, flags); +} +#endif /* CTFPOOL */ + +/* Free the driver packet. Free the tag if present */ +void BCMFASTPATH +osl_pktfree(osl_t *osh, void *p, bool send) +{ + struct sk_buff *skb, *nskb; + if (osh == NULL) + return; + + skb = (struct sk_buff*) p; + + if (send && osh->pub.tx_fn) + osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); + + PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE); + + /* perversion: we use skb->next to chain multi-skb packets */ + while (skb) { + nskb = skb->next; + skb->next = NULL; + + + +#ifdef CTFPOOL + if (PKTISFAST(osh, skb)) { + if (atomic_read(&skb->users) == 1) + smp_rmb(); + else if (!atomic_dec_and_test(&skb->users)) + goto next_skb; + osl_pktfastfree(osh, skb); + } else +#endif + { + 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); + } +#ifdef CTFPOOL +next_skb: +#endif + atomic_dec(&osh->cmn->pktalloced); + skb = nskb; + } +} + +#ifdef CONFIG_DHD_USE_STATIC_BUF +void* +osl_pktget_static(osl_t *osh, uint len) +{ + int i = 0; + struct sk_buff *skb; + + if (len > DHD_SKB_MAX_BUFSIZE) { + printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len); + return osl_pktget(osh, len); + } + + down(&bcm_static_skb->osl_pkt_sem); + + if (len <= DHD_SKB_1PAGE_BUFSIZE) { + for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { + if (bcm_static_skb->pkt_use[i] == 0) + break; + } + + if (i != STATIC_PKT_MAX_NUM) { + bcm_static_skb->pkt_use[i] = 1; + + skb = bcm_static_skb->skb_4k[i]; +#ifdef NET_SKBUFF_DATA_USES_OFFSET + skb_set_tail_pointer(skb, len); +#else + skb->tail = skb->data + len; +#endif /* NET_SKBUFF_DATA_USES_OFFSET */ + skb->len = len; + + up(&bcm_static_skb->osl_pkt_sem); + return skb; + } + } + + if (len <= DHD_SKB_2PAGE_BUFSIZE) { + for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { + if (bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] + == 0) + break; + } + + if (i != STATIC_PKT_MAX_NUM) { + bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 1; + skb = bcm_static_skb->skb_8k[i]; +#ifdef NET_SKBUFF_DATA_USES_OFFSET + skb_set_tail_pointer(skb, len); +#else + skb->tail = skb->data + len; +#endif /* NET_SKBUFF_DATA_USES_OFFSET */ + skb->len = len; + + up(&bcm_static_skb->osl_pkt_sem); + return skb; + } + } + +#if defined(ENHANCED_STATIC_BUF) + if (bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] == 0) { + bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 1; + + skb = bcm_static_skb->skb_16k; +#ifdef NET_SKBUFF_DATA_USES_OFFSET + skb_set_tail_pointer(skb, len); +#else + skb->tail = skb->data + len; +#endif /* NET_SKBUFF_DATA_USES_OFFSET */ + skb->len = len; + + up(&bcm_static_skb->osl_pkt_sem); + return skb; + } +#endif /* ENHANCED_STATIC_BUF */ + + up(&bcm_static_skb->osl_pkt_sem); + printk("%s: all static pkt in use!\n", __FUNCTION__); + return osl_pktget(osh, len); +} + +void +osl_pktfree_static(osl_t *osh, void *p, bool send) +{ + int i; + if (!bcm_static_skb) { + osl_pktfree(osh, p, send); + return; + } + + down(&bcm_static_skb->osl_pkt_sem); + for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { + if (p == bcm_static_skb->skb_4k[i]) { + bcm_static_skb->pkt_use[i] = 0; + up(&bcm_static_skb->osl_pkt_sem); + return; + } + } + + for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { + if (p == bcm_static_skb->skb_8k[i]) { + bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0; + up(&bcm_static_skb->osl_pkt_sem); + return; + } + } +#ifdef ENHANCED_STATIC_BUF + if (p == bcm_static_skb->skb_16k) { + bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 0; + up(&bcm_static_skb->osl_pkt_sem); + return; + } +#endif + up(&bcm_static_skb->osl_pkt_sem); + osl_pktfree(osh, p, send); +} +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + +uint32 +osl_pci_read_config(osl_t *osh, uint offset, uint size) +{ + uint val = 0; + uint retry = PCI_CFG_RETRY; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + /* only 4byte access supported */ + ASSERT(size == 4); + + do { + pci_read_config_dword(osh->pdev, offset, &val); + if (val != 0xffffffff) + break; + } while (retry--); + + + return (val); +} + +void +osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) +{ + uint retry = PCI_CFG_RETRY; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + /* only 4byte access supported */ + ASSERT(size == 4); + + do { + pci_write_config_dword(osh->pdev, offset, val); + if (offset != PCI_BAR0_WIN) + break; + if (osl_pci_read_config(osh, offset, size) == val) + break; + } while (retry--); + +} + +/* return bus # for the pci device pointed by osh->pdev */ +uint +osl_pci_bus(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + + return ((struct pci_dev *)osh->pdev)->bus->number; +} + +/* return slot # for the pci device pointed by osh->pdev */ +uint +osl_pci_slot(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + +#if 0 > KERNEL_VERSION(2, 6, 35) + return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn) + 1; +#else + return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); +#endif +} + +/* return the pci device pointed by osh->pdev */ +struct pci_dev * +osl_pci_device(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + + return osh->pdev; +} + +static void +osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) +{ +} + +void +osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size) +{ + osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE); +} + +void +osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) +{ + osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); +} + +void * +osl_malloc(osl_t *osh, uint size) +{ + void *addr; + gfp_t flags; + + /* only ASSERT if osh is defined */ + if (osh) + ASSERT(osh->magic == OS_HANDLE_MAGIC); +#ifdef CONFIG_DHD_USE_STATIC_BUF + if (bcm_static_buf) + { + unsigned long irq_flags; + int i = 0; + if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE)) + { + spin_lock_irqsave(&bcm_static_buf->static_lock, irq_flags); + + for (i = 0; i < STATIC_BUF_MAX_NUM; i++) + { + if (bcm_static_buf->buf_use[i] == 0) + break; + } + + if (i == STATIC_BUF_MAX_NUM) + { + spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); + printk("all static buff in use!\n"); + goto original; + } + + bcm_static_buf->buf_use[i] = 1; + spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); + + bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size); + if (osh) + atomic_add(size, &osh->cmn->malloced); + + return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i)); + } + } +original: +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + + flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; + if ((addr = kmalloc(size, flags)) == NULL) { + if (osh) + osh->failed++; + return (NULL); + } + if (osh && osh->cmn) + atomic_add(size, &osh->cmn->malloced); + + return (addr); +} + +void * +osl_mallocz(osl_t *osh, uint size) +{ + void *ptr; + + ptr = osl_malloc(osh, size); + + if (ptr != NULL) { + bzero(ptr, size); + } + + return ptr; +} + +void +osl_mfree(osl_t *osh, void *addr, uint size) +{ +#ifdef CONFIG_DHD_USE_STATIC_BUF + unsigned long flags; + + if (bcm_static_buf) + { + if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr + <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN))) + { + int buf_idx = 0; + + buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE; + + spin_lock_irqsave(&bcm_static_buf->static_lock, flags); + bcm_static_buf->buf_use[buf_idx] = 0; + spin_unlock_irqrestore(&bcm_static_buf->static_lock, flags); + + if (osh && osh->cmn) { + ASSERT(osh->magic == OS_HANDLE_MAGIC); + atomic_sub(size, &osh->cmn->malloced); + } + return; + } + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + if (osh && osh->cmn) { + ASSERT(osh->magic == OS_HANDLE_MAGIC); + + ASSERT(size <= osl_malloced(osh)); + + atomic_sub(size, &osh->cmn->malloced); + } + kfree(addr); +} + +uint +osl_check_memleak(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + if (atomic_read(&osh->cmn->refcount) == 1) + return (atomic_read(&osh->cmn->malloced)); + else + return 0; +} + +uint +osl_malloced(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + return (atomic_read(&osh->cmn->malloced)); +} + +uint +osl_malloc_failed(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + return (osh->failed); +} + + +uint +osl_dma_consistent_align(void) +{ + return (PAGE_SIZE); +} + +void* +osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, dmaaddr_t *pap) +{ + void *va; + uint16 align = (1 << align_bits); + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) + size += align; + *alloced = size; + + { + dma_addr_t pap_lin; + va = pci_alloc_consistent(osh->pdev, size, &pap_lin); + *pap = (dmaaddr_t)pap_lin; + } + return va; +} + +void +osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); +} + +dmaaddr_t BCMFASTPATH +osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah) +{ + int dir; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + + + return (pci_map_single(osh->pdev, va, size, dir)); +} + +void BCMFASTPATH +osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) +{ + int dir; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + pci_unmap_single(osh->pdev, (uint32)pa, size, dir); +} + + +#if defined(BCMASSERT_LOG) +void +osl_assert(const char *exp, const char *file, int line) +{ + char tempbuf[256]; + const char *basename; + + basename = strrchr(file, '/'); + /* skip the '/' */ + if (basename) + basename++; + + if (!basename) + basename = file; + +#ifdef BCMASSERT_LOG + snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", + exp, basename, line); + printk("%s", tempbuf); +#endif /* BCMASSERT_LOG */ + + +} +#endif + +void +osl_delay(uint usec) +{ + uint d; + + while (usec > 0) { + d = MIN(usec, 1000); + udelay(d); + usec -= d; + } +} + +void +osl_sleep(uint ms) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + if (ms < 20) + usleep_range(ms*1000, ms*1000 + 1000); + else +#endif + msleep(ms); +} + + + +/* Clone a packet. + * The pkttag contents are NOT cloned. + */ +void * +osl_pktdup(osl_t *osh, void *skb) +{ + void * p; + + ASSERT(!PKTISCHAINED(skb)); + + /* clear the CTFBUF flag if set and map the rest of the buffer + * before cloning. + */ + PKTCTFMAP(osh, skb); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + if ((p = pskb_copy((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) +#else + if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) +#endif + return NULL; + +#ifdef CTFPOOL + if (PKTISFAST(osh, skb)) { + ctfpool_t *ctfpool; + + /* if the buffer allocated from ctfpool is cloned then + * we can't be sure when it will be freed. since there + * is a chance that we will be losing a buffer + * from our pool, we increment the refill count for the + * object to be alloced later. + */ + ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); + ASSERT(ctfpool != NULL); + PKTCLRFAST(osh, p); + PKTCLRFAST(osh, skb); + ctfpool->refills++; + } +#endif /* CTFPOOL */ + + /* Clear PKTC context */ + PKTSETCLINK(p, NULL); + PKTCCLRFLAGS(p); + PKTCSETCNT(p, 1); + PKTCSETLEN(p, PKTLEN(osh, skb)); + + /* skb_clone copies skb->cb.. we don't want that */ + if (osh->pub.pkttag) + OSL_PKTTAG_CLEAR(p); + + /* Increment the packet counter */ + atomic_inc(&osh->cmn->pktalloced); + return (p); +} + + + +/* + * OSLREGOPS specifies the use of osl_XXX routines to be used for register access + */ + +/* + * BINOSL selects the slightly slower function-call-based binary compatible osl. + */ + +uint +osl_pktalloced(osl_t *osh) +{ + if (atomic_read(&osh->cmn->refcount) == 1) + return (atomic_read(&osh->cmn->pktalloced)); + else + return 0; +} + +/* Linux Kernel: File Operations: start */ +void * +osl_os_open_image(char *filename) +{ + struct file *fp; + + fp = filp_open(filename, O_RDONLY, 0); + /* + * 2.6.11 (FC4) supports filp_open() but later revs don't? + * Alternative: + * fp = open_namei(AT_FDCWD, filename, O_RD, 0); + * ??? + */ + if (IS_ERR(fp)) + fp = NULL; + + return fp; +} + +int +osl_os_get_image_block(char *buf, int len, void *image) +{ + struct file *fp = (struct file *)image; + int rdlen; + + if (!image) + return 0; + + rdlen = kernel_read(fp, fp->f_pos, buf, len); + if (rdlen > 0) + fp->f_pos += rdlen; + + return rdlen; +} + +void +osl_os_close_image(void *image) +{ + if (image) + filp_close((struct file *)image, NULL); +} + +int +osl_os_image_size(void *image) +{ + int len = 0, curroffset; + + if (image) { + /* store the current offset */ + curroffset = generic_file_llseek(image, 0, 1); + /* goto end of file to get length */ + len = generic_file_llseek(image, 0, 2); + /* restore back the offset */ + generic_file_llseek(image, curroffset, 0); + } + return len; +} + +/* Linux Kernel: File Operations: end */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/sbutils.c b/drivers/net/wireless/bcmdhd_bcm43455/sbutils.c new file mode 100644 index 000000000000..c0364f608466 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/sbutils.c @@ -0,0 +1,1063 @@ +/* + * Misc utility routines for accessing chip-specific features + * of the SiliconBackplane-based Broadcom chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: sbutils.c 431423 2013-10-23 16:07:35Z $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "siutils_priv.h" + + +/* local prototypes */ +static uint _sb_coreidx(si_info_t *sii, uint32 sba); +static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, + uint ncores); +static uint32 _sb_coresba(si_info_t *sii); +static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); +#define SET_SBREG(sii, r, mask, val) \ + W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) +#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) + +/* sonicsrev */ +#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) +#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT) + +#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr)) +#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v)) +#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v))) +#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v))) + +static uint32 +sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) +{ + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint8 tmp; + uint32 val, intr_val = 0; + + + /* + * compact flash only has 11 bits address, while we needs 12 bits address. + * MEM_SEG will be OR'd with other 11 bits address in hardware, + * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). + * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special + */ + if (PCMCIA(sii)) { + INTR_OFF(sii, intr_val); + tmp = 1; + OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); + sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ + } + + val = R_REG(sii->osh, sbr); + + if (PCMCIA(sii)) { + tmp = 0; + OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); + INTR_RESTORE(sii, intr_val); + } + + return (val); +} + +static void +sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) +{ + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint8 tmp; + volatile uint32 dummy; + uint32 intr_val = 0; + + + /* + * compact flash only has 11 bits address, while we needs 12 bits address. + * MEM_SEG will be OR'd with other 11 bits address in hardware, + * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). + * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special + */ + if (PCMCIA(sii)) { + INTR_OFF(sii, intr_val); + tmp = 1; + OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); + sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ + } + + if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { + dummy = R_REG(sii->osh, sbr); + BCM_REFERENCE(dummy); + W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); + dummy = R_REG(sii->osh, sbr); + BCM_REFERENCE(dummy); + W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); + } else + W_REG(sii->osh, sbr, v); + + if (PCMCIA(sii)) { + tmp = 0; + OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); + INTR_RESTORE(sii, intr_val); + } +} + +uint +sb_coreid(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); +} + +uint +sb_intflag(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + void *corereg; + sbconfig_t *sb; + uint origidx, intflag, intr_val = 0; + + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + corereg = si_setcore(sih, CC_CORE_ID, 0); + ASSERT(corereg != NULL); + sb = REGS2SB(corereg); + intflag = R_SBREG(sii, &sb->sbflagst); + sb_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); + + return intflag; +} + +uint +sb_flag(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK; +} + +void +sb_setint(si_t *sih, int siflag) +{ + si_info_t *sii; + sbconfig_t *sb; + uint32 vec; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + if (siflag == -1) + vec = 0; + else + vec = 1 << siflag; + W_SBREG(sii, &sb->sbintvec, vec); +} + +/* return core index of the core with address 'sba' */ +static uint +_sb_coreidx(si_info_t *sii, uint32 sba) +{ + uint i; + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + for (i = 0; i < sii->numcores; i ++) + if (sba == cores_info->coresba[i]) + return i; + return BADIDX; +} + +/* return core address of the current core */ +static uint32 +_sb_coresba(si_info_t *sii) +{ + uint32 sbaddr; + + + switch (BUSTYPE(sii->pub.bustype)) { + case SI_BUS: { + sbconfig_t *sb = REGS2SB(sii->curmap); + sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0)); + break; + } + + case PCI_BUS: + sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + break; + + case PCMCIA_BUS: { + uint8 tmp = 0; + OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); + sbaddr = (uint32)tmp << 12; + OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); + sbaddr |= (uint32)tmp << 16; + OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); + sbaddr |= (uint32)tmp << 24; + break; + } + + case SPI_BUS: + case SDIO_BUS: + sbaddr = (uint32)(uintptr)sii->curmap; + break; + + + default: + sbaddr = BADCOREADDR; + break; + } + + return sbaddr; +} + +uint +sb_corevendor(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); +} + +uint +sb_corerev(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + uint sbidh; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + sbidh = R_SBREG(sii, &sb->sbidhigh); + + return (SBCOREREV(sbidh)); +} + +/* set core-specific control flags */ +void +sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii; + sbconfig_t *sb; + uint32 w; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + ASSERT((val & ~mask) == 0); + + /* mask and set */ + w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | + (val << SBTML_SICF_SHIFT); + W_SBREG(sii, &sb->sbtmstatelow, w); +} + +/* set/clear core-specific control flags */ +uint32 +sb_core_cflags(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii; + sbconfig_t *sb; + uint32 w; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + ASSERT((val & ~mask) == 0); + + /* mask and set */ + if (mask || val) { + w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | + (val << SBTML_SICF_SHIFT); + W_SBREG(sii, &sb->sbtmstatelow, w); + } + + /* return the new value + * for write operation, the following readback ensures the completion of write opration. + */ + return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT); +} + +/* set/clear core-specific status flags */ +uint32 +sb_core_sflags(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii; + sbconfig_t *sb; + uint32 w; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + ASSERT((val & ~mask) == 0); + ASSERT((mask & ~SISF_CORE_BITS) == 0); + + /* mask and set */ + if (mask || val) { + w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) | + (val << SBTMH_SISF_SHIFT); + W_SBREG(sii, &sb->sbtmstatehigh, w); + } + + /* return the new value */ + return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT); +} + +bool +sb_iscoreup(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + return ((R_SBREG(sii, &sb->sbtmstatelow) & + (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == + (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); +} + +/* + * 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 fidleing with interrupts or core switches are needed. + * + * Also, when using pci/pcie, we can optimize away the core switching for pci registers + * and (on newer pci cores) chipcommon registers. + */ +uint +sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) +{ + uint origidx = 0; + uint32 *r = NULL; + uint w; + uint intr_val = 0; + bool fast = FALSE; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + ASSERT(GOODIDX(coreidx)); + ASSERT(regoff < SI_CORE_SIZE); + ASSERT((val & ~mask) == 0); + + if (coreidx >= SI_MAXCORES) + return 0; + + if (BUSTYPE(sii->pub.bustype) == SI_BUS) { + /* If internal bus, we can always get at everything */ + fast = TRUE; + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + + fast = TRUE; + r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (uint32 *)((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 = si_coreidx(&sii->pub); + + /* switch core */ + r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff); + } + ASSERT(r != NULL); + + /* mask and set */ + if (mask || val) { + if (regoff >= SBCONFIGOFF) { + w = (R_SBREG(sii, r) & ~mask) | val; + W_SBREG(sii, r, w); + } else { + w = (R_REG(sii->osh, r) & ~mask) | val; + W_REG(sii->osh, r, w); + } + } + + /* readback */ + if (regoff >= SBCONFIGOFF) + w = R_SBREG(sii, r); + else { + if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) && + (coreidx == SI_CC_IDX) && + (regoff == OFFSETOF(chipcregs_t, watchdog))) { + w = val; + } else + w = R_REG(sii->osh, r); + } + + if (!fast) { + /* restore core index */ + if (origidx != coreidx) + sb_setcoreidx(&sii->pub, origidx); + + INTR_RESTORE(sii, intr_val); + } + + return (w); +} + +/* + * If there is no need for fiddling with interrupts or core switches (typically silicon + * back plane registers, pci registers and chipcommon registers), this function + * returns the register offset on this core to a mapped address. This address can + * be used for W_REG/R_REG directly. + * + * For accessing registers that would need a core switch, this function will return + * NULL. + */ +uint32 * +sb_corereg_addr(si_t *sih, uint coreidx, uint regoff) +{ + uint32 *r = NULL; + bool fast = FALSE; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + ASSERT(GOODIDX(coreidx)); + ASSERT(regoff < SI_CORE_SIZE); + + if (coreidx >= SI_MAXCORES) + return 0; + + if (BUSTYPE(sii->pub.bustype) == SI_BUS) { + /* If internal bus, we can always get at everything */ + fast = TRUE; + /* map if does not exist */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff); + } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + + if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + + fast = TRUE; + r = (uint32 *)((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 = (uint32 *)((char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (uint32 *)((char *)sii->curmap + + ((regoff >= SBCONFIGOFF) ? + PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + + regoff); + } + } + + if (!fast) + return 0; + + return (r); +} + +/* Scan the enumeration space to find all cores starting from the given + * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' + * is the default core address at chip POR time and 'regs' is the virtual + * address that the default core is mapped at. 'ncores' is the number of + * cores expected on bus 'sbba'. It returns the total number of cores + * starting from bus 'sbba', inclusive. + */ +#define SB_MAXBUSES 2 +static uint +_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores) +{ + uint next; + uint ncc = 0; + uint i; + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + if (bus >= SB_MAXBUSES) { + SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus)); + return 0; + } + SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores)); + + /* Scan all cores on the bus starting from core 0. + * Core addresses must be contiguous on each bus. + */ + for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { + cores_info->coresba[next] = sbba + (i * SI_CORE_SIZE); + + /* keep and reuse the initial register mapping */ + if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (cores_info->coresba[next] == sba)) { + SI_VMSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next)); + cores_info->regs[next] = regs; + } + + /* change core to 'next' and read its coreid */ + sii->curmap = _sb_setcoreidx(sii, next); + sii->curidx = next; + + cores_info->coreid[next] = sb_coreid(&sii->pub); + + /* core specific processing... */ + /* chipc provides # cores */ + if (cores_info->coreid[next] == CC_CORE_ID) { + chipcregs_t *cc = (chipcregs_t *)sii->curmap; + uint32 ccrev = sb_corerev(&sii->pub); + + /* determine numcores - this is the total # cores in the chip */ + if (((ccrev == 4) || (ccrev >= 6))) { + ASSERT(cc); + numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> + CID_CC_SHIFT; + } else { + /* Older chips */ + uint chip = CHIPID(sii->pub.chip); + + if (chip == BCM4306_CHIP_ID) /* < 4306c0 */ + numcores = 6; + else if (chip == BCM4704_CHIP_ID) + numcores = 9; + else if (chip == BCM5365_CHIP_ID) + numcores = 7; + else { + SI_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", + chip)); + ASSERT(0); + numcores = 1; + } + } + SI_VMSG(("_sb_scan: there are %u cores in the chip %s\n", numcores, + sii->pub.issim ? "QT" : "")); + } + /* scan bridged SB(s) and add results to the end of the list */ + else if (cores_info->coreid[next] == OCP_CORE_ID) { + sbconfig_t *sb = REGS2SB(sii->curmap); + uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); + uint nsbcc; + + sii->numcores = next + 1; + + if ((nsbba & 0xfff00000) != SI_ENUM_BASE) + continue; + nsbba &= 0xfffff000; + if (_sb_coreidx(sii, nsbba) != BADIDX) + continue; + + nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16; + nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc); + if (sbba == SI_ENUM_BASE) + numcores -= nsbcc; + ncc += nsbcc; + } + } + + SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba)); + + sii->numcores = i + ncc; + return sii->numcores; +} + +/* scan the sb enumerated space to identify all cores */ +void +sb_scan(si_t *sih, void *regs, uint devid) +{ + uint32 origsba; + sbconfig_t *sb; + si_info_t *sii = SI_INFO(sih); + + sb = REGS2SB(sii->curmap); + + sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; + + /* Save the current core info and validate it later till we know + * for sure what is good and what is bad. + */ + origsba = _sb_coresba(sii); + + /* scan all SB(s) starting from SI_ENUM_BASE */ + sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1); +} + +/* + * 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 * +sb_setcoreidx(si_t *sih, uint coreidx) +{ + si_info_t *sii = SI_INFO(sih); + + if (coreidx >= sii->numcores) + return (NULL); + + /* + * If the user has provided an interrupt mask enabled function, + * then assert interrupts are disabled before switching the core. + */ + ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); + + sii->curmap = _sb_setcoreidx(sii, coreidx); + sii->curidx = coreidx; + + return (sii->curmap); +} + +/* This function changes the logical "focus" to the indicated core. + * Return the current core's virtual address. + */ +static void * +_sb_setcoreidx(si_info_t *sii, uint coreidx) +{ + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint32 sbaddr = cores_info->coresba[coreidx]; + void *regs; + + switch (BUSTYPE(sii->pub.bustype)) { + case SI_BUS: + /* map new one */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + regs = cores_info->regs[coreidx]; + break; + + case PCI_BUS: + /* point bar0 window */ + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr); + regs = sii->curmap; + break; + + case PCMCIA_BUS: { + uint8 tmp = (sbaddr >> 12) & 0x0f; + OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); + tmp = (sbaddr >> 16) & 0xff; + OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); + tmp = (sbaddr >> 24) & 0xff; + OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); + regs = sii->curmap; + break; + } + case SPI_BUS: + case SDIO_BUS: + /* map new one */ + if (!cores_info->regs[coreidx]) { + cores_info->regs[coreidx] = (void *)(uintptr)sbaddr; + ASSERT(GOODREGS(cores_info->regs[coreidx])); + } + regs = cores_info->regs[coreidx]; + break; + + + default: + ASSERT(0); + regs = NULL; + break; + } + + return regs; +} + +/* Return the address of sbadmatch0/1/2/3 register */ +static volatile uint32 * +sb_admatch(si_info_t *sii, uint asidx) +{ + sbconfig_t *sb; + volatile uint32 *addrm; + + sb = REGS2SB(sii->curmap); + + switch (asidx) { + case 0: + addrm = &sb->sbadmatch0; + break; + + case 1: + addrm = &sb->sbadmatch1; + break; + + case 2: + addrm = &sb->sbadmatch2; + break; + + case 3: + addrm = &sb->sbadmatch3; + break; + + default: + SI_ERROR(("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx)); + return 0; + } + + return (addrm); +} + +/* Return the number of address spaces in current core */ +int +sb_numaddrspaces(si_t *sih) +{ + si_info_t *sii; + sbconfig_t *sb; + + sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + /* + 1 because of enumeration space */ + return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1; +} + +/* Return the address of the nth address space in the current core */ +uint32 +sb_addrspace(si_t *sih, uint asidx) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + + return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx)))); +} + +/* Return the size of the nth address space in the current core */ +uint32 +sb_addrspacesize(si_t *sih, uint asidx) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + + return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx)))); +} + + +/* do buffered registers update */ +void +sb_commit(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + + origidx = sii->curidx; + ASSERT(GOODIDX(origidx)); + + INTR_OFF(sii, intr_val); + + /* switch over to chipcommon core if there is one, else use pci */ + if (sii->pub.ccrev != NOREV) { + chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + ASSERT(ccregs != NULL); + + /* do the buffer registers update */ + W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT); + W_REG(sii->osh, &ccregs->broadcastdata, 0x0); + } else + ASSERT(0); + + /* restore core index */ + sb_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); +} + +void +sb_core_disable(si_t *sih, uint32 bits) +{ + si_info_t *sii; + volatile uint32 dummy; + sbconfig_t *sb; + + sii = SI_INFO(sih); + + ASSERT(GOODREGS(sii->curmap)); + sb = REGS2SB(sii->curmap); + + /* if core is already in reset, just return */ + if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET) + return; + + /* if clocks are not enabled, put into reset and return */ + if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0) + goto disable; + + /* set target reject and spin until busy is clear (preserve core-specific bits) */ + OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000); + if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY) + SI_ERROR(("%s: target state still busy\n", __FUNCTION__)); + + if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) { + OR_SBREG(sii, &sb->sbimstate, SBIM_RJ); + dummy = R_SBREG(sii, &sb->sbimstate); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000); + } + + /* set reset and reject while enabling the clocks */ + W_SBREG(sii, &sb->sbtmstatelow, + (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | + SBTML_REJ | SBTML_RESET)); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(10); + + /* don't forget to clear the initiator reject bit */ + if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) + AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ); + +disable: + /* leave reset and reject asserted */ + W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET)); + OSL_DELAY(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 +sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) +{ + si_info_t *sii; + sbconfig_t *sb; + volatile uint32 dummy; + + sii = SI_INFO(sih); + ASSERT(GOODREGS(sii->curmap)); + sb = REGS2SB(sii->curmap); + + /* + * Must do the disable sequence first to work for arbitrary current core state. + */ + sb_core_disable(sih, (bits | resetbits)); + + /* + * Now do the initialization sequence. + */ + + /* set reset while enabling the clock and forcing them on throughout the core */ + W_SBREG(sii, &sb->sbtmstatelow, + (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | + SBTML_RESET)); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + + if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) { + W_SBREG(sii, &sb->sbtmstatehigh, 0); + } + if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) { + AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); + } + + /* clear reset and allow it to propagate throughout the core */ + W_SBREG(sii, &sb->sbtmstatelow, + ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(1); + + /* leave clock enabled */ + W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); + dummy = R_SBREG(sii, &sb->sbtmstatelow); + BCM_REFERENCE(dummy); + OSL_DELAY(1); +} + +/* + * Set the initiator timeout for the "master core". + * The master core is defined to be the core in control + * of the chip and so it issues accesses to non-memory + * locations (Because of dma *any* core can access memeory). + * + * The routine uses the bus to decide who is the master: + * SI_BUS => mips + * JTAG_BUS => chipc + * PCI_BUS => pci or pcie + * PCMCIA_BUS => pcmcia + * SDIO_BUS => pcmcia + * + * This routine exists so callers can disable initiator + * timeouts so accesses to very slow devices like otp + * won't cause an abort. The routine allows arbitrary + * settings of the service and request timeouts, though. + * + * Returns the timeout state before changing it or -1 + * on error. + */ + +#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK) + +uint32 +sb_set_initiator_to(si_t *sih, uint32 to, uint idx) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + uint32 tmp, ret = 0xffffffff; + sbconfig_t *sb; + + + if ((to & ~TO_MASK) != 0) + return ret; + + /* Figure out the master core */ + if (idx == BADIDX) { + switch (BUSTYPE(sii->pub.bustype)) { + case PCI_BUS: + idx = sii->pub.buscoreidx; + break; + case JTAG_BUS: + idx = SI_CC_IDX; + break; + case PCMCIA_BUS: + case SDIO_BUS: + idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0); + break; + case SI_BUS: + idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0); + break; + default: + ASSERT(0); + } + if (idx == BADIDX) + return ret; + } + + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + sb = REGS2SB(sb_setcoreidx(sih, idx)); + + tmp = R_SBREG(sii, &sb->sbimconfiglow); + ret = tmp & TO_MASK; + W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to); + + sb_commit(sih); + sb_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); + return ret; +} + +uint32 +sb_base(uint32 admatch) +{ + uint32 base; + uint type; + + type = admatch & SBAM_TYPE_MASK; + ASSERT(type < 3); + + base = 0; + + if (type == 0) { + base = admatch & SBAM_BASE0_MASK; + } else if (type == 1) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + base = admatch & SBAM_BASE1_MASK; + } else if (type == 2) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + base = admatch & SBAM_BASE2_MASK; + } + + return (base); +} + +uint32 +sb_size(uint32 admatch) +{ + uint32 size; + uint type; + + type = admatch & SBAM_TYPE_MASK; + ASSERT(type < 3); + + size = 0; + + if (type == 0) { + size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); + } else if (type == 1) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1); + } else if (type == 2) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1); + } + + return (size); +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/siutils.c b/drivers/net/wireless/bcmdhd_bcm43455/siutils.c new file mode 100644 index 000000000000..822161a5fbe7 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/siutils.c @@ -0,0 +1,2839 @@ +/* + * Misc utility routines for accessing chip-specific features + * of the SiliconBackplane-based Broadcom chips. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: siutils.c 527126 2015-01-16 03:33:51Z $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BCM_SDRBL +#include +#endif /* BCM_SDRBL */ + +#include "siutils_priv.h" + +/* local prototypes */ +static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, + uint bustype, void *sdh, char **vars, uint *varsz); +static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); +static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, + uint *origidx, void *regs); + + + +/* global variable to indicate reservation/release of gpio's */ +static uint32 si_gpioreservation = 0; + +/* global flag to prevent shared resources from being initialized multiple times in si_attach() */ + +int do_4360_pcie2_war = 0; + +/* global kernel resource */ +static si_info_t ksii; +static si_cores_info_t ksii_cores_info; + +/** + * Allocate an si handle. This function may be called multiple times. + * + * devid - pci device id (used to determine chip#) + * osh - opaque OS handle + * regs - virtual address of initial core registers + * bustype - pci/pcmcia/sb/sdio/etc + * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this + * function set 'vars' to NULL, making dereferencing of this parameter undesired. + * varsz - pointer to int to return the size of the vars + */ +si_t * +si_attach(uint devid, osl_t *osh, void *regs, + uint bustype, void *sdh, char **vars, uint *varsz) +{ + si_info_t *sii; + si_cores_info_t *cores_info; + /* alloc si_info_t */ + if ((sii = MALLOCZ(osh, sizeof (si_info_t))) == NULL) { + SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); + return (NULL); + } + + /* alloc si_cores_info_t */ + if ((cores_info = (si_cores_info_t *)MALLOCZ(osh, sizeof (si_cores_info_t))) == NULL) { + SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); + MFREE(osh, sii, sizeof(si_info_t)); + return (NULL); + } + sii->cores_info = cores_info; + + if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { + MFREE(osh, sii, sizeof(si_info_t)); + MFREE(osh, cores_info, sizeof(si_cores_info_t)); + return (NULL); + } + sii->vars = vars ? *vars : NULL; + sii->varsz = varsz ? *varsz : 0; + + return (si_t *)sii; +} + + +static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */ + +/** generic kernel variant of si_attach() */ +si_t * +si_kattach(osl_t *osh) +{ + static bool ksii_attached = FALSE; + si_cores_info_t *cores_info; + + if (!ksii_attached) { + void *regs = NULL; + regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); + cores_info = (si_cores_info_t *)&ksii_cores_info; + ksii.cores_info = cores_info; + + ASSERT(osh); + if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, + SI_BUS, NULL, + osh != SI_OSH ? &(ksii.vars) : NULL, + osh != SI_OSH ? &(ksii.varsz) : NULL) == NULL) { + SI_ERROR(("si_kattach: si_doattach failed\n")); + REG_UNMAP(regs); + return NULL; + } + REG_UNMAP(regs); + + /* save ticks normalized to ms for si_watchdog_ms() */ + if (PMUCTL_ENAB(&ksii.pub)) { + /* based on 32KHz ILP clock */ + wd_msticks = 32; + } else { + wd_msticks = ALP_CLOCK / 1000; + } + + ksii_attached = TRUE; + SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n", + ksii.pub.ccrev, wd_msticks)); + } + + return &ksii.pub; +} + + +static bool +si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) +{ + /* need to set memseg flag for CF card first before any sb registers access */ + if (BUSTYPE(bustype) == PCMCIA_BUS) + sii->memseg = TRUE; + + + if (BUSTYPE(bustype) == SDIO_BUS) { + int err; + uint8 clkset; + + /* Try forcing SDIO core to do ALPAvail request only */ + clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); + if (!err) { + uint8 clkval; + + /* If register supported, wait for ALPAvail and then force ALP */ + clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); + if ((clkval & ~SBSDIO_AVBITS) == clkset) { + SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), + PMU_MAX_TRANSITION_DLY); + if (!SBSDIO_ALPAV(clkval)) { + SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", + clkval)); + return FALSE; + } + clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + clkset, &err); + OSL_DELAY(65); + } + } + + /* Also, disable the extra SDIO pull-ups */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); + } + + + return TRUE; +} + +static bool +si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, + uint *origidx, void *regs) +{ + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + bool pci, pcie, pcie_gen2 = FALSE; + uint i; + uint pciidx, pcieidx, pcirev, pcierev; + + cc = si_setcoreidx(&sii->pub, SI_CC_IDX); + ASSERT((uintptr)cc); + + /* get chipcommon rev */ + sii->pub.ccrev = (int)si_corerev(&sii->pub); + + /* get chipcommon chipstatus */ + if (sii->pub.ccrev >= 11) + sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); + + /* get chipcommon capabilites */ + sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); + /* get chipcommon extended capabilities */ + + if (sii->pub.ccrev >= 35) + sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); + + /* get pmu rev and caps */ + if (sii->pub.cccaps & CC_CAP_PMU) { + sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); + sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; + } + + SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", + sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, + sii->pub.pmucaps)); + + /* figure out bus/orignal core idx */ + sii->pub.buscoretype = NODEV_CORE_ID; + sii->pub.buscorerev = (uint)NOREV; + sii->pub.buscoreidx = BADIDX; + + pci = pcie = FALSE; + pcirev = pcierev = (uint)NOREV; + pciidx = pcieidx = BADIDX; + + for (i = 0; i < sii->numcores; i++) { + uint cid, crev; + + si_setcoreidx(&sii->pub, i); + cid = si_coreid(&sii->pub); + crev = si_corerev(&sii->pub); + + /* Display cores found */ + SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", + i, cid, crev, cores_info->coresba[i], cores_info->regs[i])); + + if (BUSTYPE(bustype) == SI_BUS) { + /* now look at the chipstatus register to figure the pacakge */ + /* for SDIO but downloaded on PCIE dev */ + if (cid == PCIE2_CORE_ID) { + if ((CHIPID(sii->pub.chip) == BCM43602_CHIP_ID) || + ((CHIPID(sii->pub.chip) == BCM4345_CHIP_ID || + CHIPID(sii->pub.chip) == BCM43454_CHIP_ID) && + CST4345_CHIPMODE_PCIE(sii->pub.chipst))) { + pcieidx = i; + pcierev = crev; + pcie = TRUE; + pcie_gen2 = TRUE; + } + } + + } + else if (BUSTYPE(bustype) == PCI_BUS) { + if (cid == PCI_CORE_ID) { + pciidx = i; + pcirev = crev; + pci = TRUE; + } else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) { + pcieidx = i; + pcierev = crev; + pcie = TRUE; + if (cid == PCIE2_CORE_ID) + pcie_gen2 = TRUE; + } + } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && + (cid == PCMCIA_CORE_ID)) { + sii->pub.buscorerev = crev; + sii->pub.buscoretype = cid; + sii->pub.buscoreidx = i; + } + else if (((BUSTYPE(bustype) == SDIO_BUS) || + (BUSTYPE(bustype) == SPI_BUS)) && + ((cid == PCMCIA_CORE_ID) || + (cid == SDIOD_CORE_ID))) { + sii->pub.buscorerev = crev; + sii->pub.buscoretype = cid; + sii->pub.buscoreidx = i; + } + + /* find the core idx before entering this func. */ + if ((savewin && (savewin == cores_info->coresba[i])) || + (regs == cores_info->regs[i])) + *origidx = i; + } + +#if defined(PCIE_FULL_DONGLE) + pci = FALSE; +#endif + if (pci) { + sii->pub.buscoretype = PCI_CORE_ID; + sii->pub.buscorerev = pcirev; + sii->pub.buscoreidx = pciidx; + } else if (pcie) { + if (pcie_gen2) + sii->pub.buscoretype = PCIE2_CORE_ID; + else + sii->pub.buscoretype = PCIE_CORE_ID; + sii->pub.buscorerev = pcierev; + sii->pub.buscoreidx = pcieidx; + } + + SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, + sii->pub.buscorerev)); + + if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && + (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3)) + OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); + + + /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was + * already running. + */ + if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { + if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || + si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) + si_core_disable(&sii->pub, 0); + } + + /* return to the original core */ + si_setcoreidx(&sii->pub, *origidx); + + return TRUE; +} + + + + +/** + * Allocate an si handle. This function may be called multiple times. + * + * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this + * function set 'vars' to NULL. + */ +static si_info_t * +si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, + uint bustype, void *sdh, char **vars, uint *varsz) +{ + struct si_pub *sih = &sii->pub; + uint32 w, savewin; + chipcregs_t *cc; + char *pvars = NULL; + uint origidx; +#if !defined(_CFEZ_) || defined(CFG_WL) +#endif + + ASSERT(GOODREGS(regs)); + + savewin = 0; + + sih->buscoreidx = BADIDX; + + sii->curmap = regs; + sii->sdh = sdh; + sii->osh = osh; + + + /* check to see if we are a si core mimic'ing a pci core */ + if ((bustype == PCI_BUS) && + (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(uint32)) == 0xffffffff)) { + SI_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SI " + "devid:0x%x\n", __FUNCTION__, devid)); + bustype = SI_BUS; + } + + /* find Chipcommon address */ + if (bustype == PCI_BUS) { + savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) + savewin = SI_ENUM_BASE; + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); + if (!regs) + return NULL; + cc = (chipcregs_t *)regs; + } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { + cc = (chipcregs_t *)sii->curmap; + } else { + cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); + } + + sih->bustype = bustype; + if (bustype != BUSTYPE(bustype)) { + SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", + bustype, BUSTYPE(bustype))); + return NULL; + } + + /* bus/core/clk setup for register access */ + if (!si_buscore_prep(sii, bustype, devid, sdh)) { + SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); + 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. + */ + if (!cc) { + SI_ERROR(("%s: chipcommon register space is null \n", __FUNCTION__)); + return NULL; + } + w = R_REG(osh, &cc->chipid); + if ((w & 0xfffff) == 148277) w -= 65532; + sih->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; + + if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && + (sih->chippkg != BCM4329_289PIN_PKG_ID)) { + sih->chippkg = BCM4329_182PIN_PKG_ID; + } + sih->issim = IS_SIM(sih->chippkg); + + /* scan for cores */ + if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { + SI_MSG(("Found chip type SB (0x%08x)\n", w)); + sb_scan(&sii->pub, regs, devid); + } else if ((CHIPTYPE(sii->pub.socitype) == SOCI_AI) || + (CHIPTYPE(sii->pub.socitype) == SOCI_NAI)) { + if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) + SI_MSG(("Found chip type AI (0x%08x)\n", w)); + else + SI_MSG(("Found chip type NAI (0x%08x)\n", w)); + /* pass chipc address instead of original core base */ + ai_scan(&sii->pub, (void *)(uintptr)cc, devid); + } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { + SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip)); + /* pass chipc address instead of original core base */ + ub_scan(&sii->pub, (void *)(uintptr)cc, devid); + } else { + SI_ERROR(("Found chip of unknown type (0x%08x)\n", w)); + return NULL; + } + /* no cores found, bail out */ + if (sii->numcores == 0) { + SI_ERROR(("si_doattach: could not find any cores\n")); + return NULL; + } + /* bus/core/clk setup */ + origidx = SI_CC_IDX; + if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { + SI_ERROR(("si_doattach: si_buscore_setup failed\n")); + goto exit; + } + +#if !defined(_CFEZ_) || defined(CFG_WL) + if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) + >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | + CST4322_SPROM_PRESENT))) { + SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__)); + return NULL; + } + + /* assume current core is CC */ + if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || + CHIPID(sih->chip) == BCM43235_CHIP_ID || + CHIPID(sih->chip) == BCM43234_CHIP_ID || + CHIPID(sih->chip) == BCM43238_CHIP_ID) && + (CHIPREV(sii->pub.chiprev) <= 2))) { + + if ((cc->chipstatus & CST43236_BP_CLK) != 0) { + uint clkdiv; + clkdiv = R_REG(osh, &cc->clkdiv); + /* otp_clk_div is even number, 120/14 < 9mhz */ + clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); + W_REG(osh, &cc->clkdiv, clkdiv); + SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv)); + } + OSL_DELAY(10); + } + + if (bustype == PCI_BUS) { + + } +#endif +#ifdef BCM_SDRBL + /* 4360 rom bootloader in PCIE case, if the SDR is enabled, But preotection is + * not turned on, then we want to hold arm in reset. + * Bottomline: In sdrenable case, we allow arm to boot only when protection is + * turned on. + */ + if (CHIP_HOSTIF_PCIE(&(sii->pub))) { + uint32 sflags = si_arm_sflags(&(sii->pub)); + + /* If SDR is enabled but protection is not turned on + * then we want to force arm to WFI. + */ + if ((sflags & (SISF_SDRENABLE | SISF_TCMPROT)) == SISF_SDRENABLE) { + disable_arm_irq(); + while (1) { + hnd_cpu_wait(sih); + } + } + } +#endif /* BCM_SDRBL */ + + pvars = NULL; + BCM_REFERENCE(pvars); + + + + if (sii->pub.ccrev >= 20) { + uint32 gpiopullup = 0, gpiopulldown = 0; + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + ASSERT(cc != NULL); + + /* 4314/43142 has pin muxing, don't clear gpio bits */ + if ((CHIPID(sih->chip) == BCM4314_CHIP_ID) || + (CHIPID(sih->chip) == BCM43142_CHIP_ID)) { + gpiopullup |= 0x402e0; + gpiopulldown |= 0x20500; + } + + W_REG(osh, &cc->gpiopullup, gpiopullup); + W_REG(osh, &cc->gpiopulldown, gpiopulldown); + si_setcoreidx(sih, origidx); + } + + + /* clear any previous epidiag-induced target abort */ + ASSERT(!si_taclear(sih, FALSE)); + + + return (sii); + +exit: + + return NULL; +} + +/** may be called with core in reset */ +void +si_detach(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint idx; + + + if (BUSTYPE(sih->bustype) == SI_BUS) + for (idx = 0; idx < SI_MAXCORES; idx++) + if (cores_info->regs[idx]) { + REG_UNMAP(cores_info->regs[idx]); + cores_info->regs[idx] = NULL; + } + + +#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) + if (cores_info != &ksii_cores_info) +#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ + MFREE(sii->osh, cores_info, sizeof(si_cores_info_t)); + +#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) + if (sii != &ksii) +#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ + MFREE(sii->osh, sii, sizeof(si_info_t)); +} + +void * +si_osh(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + return sii->osh; +} + +void +si_setosh(si_t *sih, osl_t *osh) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + if (sii->osh != NULL) { + SI_ERROR(("osh is already set....\n")); + ASSERT(!sii->osh); + } + sii->osh = osh; +} + +/** register driver interrupt disabling and restoring callback functions */ +void +si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, + void *intrsenabled_fn, void *intr_arg) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + sii->intr_arg = intr_arg; + sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn; + sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn; + sii->intrsenabled_fn = (si_intrsenabled_t)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 = cores_info->coreid[sii->curidx]; +} + +void +si_deregister_intr_callback(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + sii->intrsoff_fn = NULL; +} + +uint +si_intflag(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_intflag(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return R_REG(sii->osh, ((uint32 *)(uintptr) + (sii->oob_router + OOB_STATUSA))); + else { + ASSERT(0); + return 0; + } +} + +uint +si_flag(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_flag(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_flag(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_flag(sih); + else { + ASSERT(0); + return 0; + } +} + +uint +si_flag_alt(si_t *sih) +{ + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_flag_alt(sih); + else { + ASSERT(0); + return 0; + } +} + +void +si_setint(si_t *sih, int siflag) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + sb_setint(sih, siflag); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_setint(sih, siflag); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_setint(sih, siflag); + else + ASSERT(0); +} + +uint +si_coreid(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + return cores_info->coreid[sii->curidx]; +} + +uint +si_coreidx(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + return sii->curidx; +} + +/** return the core-type instantiation # of the current core */ +uint +si_coreunit(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint idx; + uint coreid; + uint coreunit; + uint i; + + coreunit = 0; + + idx = sii->curidx; + + ASSERT(GOODREGS(sii->curmap)); + coreid = si_coreid(sih); + + /* count the cores of our type */ + for (i = 0; i < idx; i++) + if (cores_info->coreid[i] == coreid) + coreunit++; + + return (coreunit); +} + +uint +si_corevendor(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_corevendor(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_corevendor(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_corevendor(sih); + else { + ASSERT(0); + return 0; + } +} + +bool +si_backplane64(si_t *sih) +{ + return ((sih->cccaps & CC_CAP_BKPLN64) != 0); +} + +uint +si_corerev(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_corerev(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_corerev(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_corerev(sih); + else { + ASSERT(0); + return 0; + } +} + +/** return index of coreid or BADIDX if not found */ +uint +si_findcoreidx(si_t *sih, uint coreid, uint coreunit) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint found; + uint i; + + + found = 0; + + for (i = 0; i < sii->numcores; i++) + if (cores_info->coreid[i] == coreid) { + if (found == coreunit) + return (i); + found++; + } + + return (BADIDX); +} + +/** return total coreunit of coreid or zero if not found */ +uint +si_numcoreunits(si_t *sih, uint coreid) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint found; + uint i; + + found = 0; + + for (i = 0; i < sii->numcores; i++) + if (cores_info->coreid[i] == coreid) { + found++; + } + + return (found == 0? 0:found); +} + +/** return list of found cores */ +uint +si_corelist(si_t *sih, uint coreid[]) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + bcopy((uchar*)cores_info->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); + return (sii->numcores); +} + +/** return current wrapper mapping */ +void * +si_wrapperregs(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + ASSERT(GOODREGS(sii->curwrap)); + + return (sii->curwrap); +} + +/** return current register mapping */ +void * +si_coreregs(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + ASSERT(GOODREGS(sii->curmap)); + + return (sii->curmap); +} + +/** + * 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 * +si_setcore(si_t *sih, uint coreid, uint coreunit) +{ + uint idx; + + idx = si_findcoreidx(sih, coreid, coreunit); + if (!GOODIDX(idx)) + return (NULL); + + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_setcoreidx(sih, idx); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_setcoreidx(sih, idx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_setcoreidx(sih, idx); + else { + ASSERT(0); + return NULL; + } +} + +void * +si_setcoreidx(si_t *sih, uint coreidx) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_setcoreidx(sih, coreidx); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_setcoreidx(sih, coreidx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_setcoreidx(sih, coreidx); + else { + ASSERT(0); + return NULL; + } +} + +/** Turn off interrupt as required by sb_setcore, before switch core */ +void * +si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) +{ + void *cc; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + 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 (void *)CCREGS_FAST(sii); + else if (coreid == sih->buscoretype) + return (void *)PCIEREGS(sii); + } + INTR_OFF(sii, *intr_val); + *origidx = sii->curidx; + cc = si_setcore(sih, coreid, 0); + ASSERT(cc != NULL); + + return cc; +} + +/* restore coreidx and restore interrupt */ +void +si_restore_core(si_t *sih, uint coreid, uint intr_val) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) + return; + + si_setcoreidx(sih, coreid); + INTR_RESTORE(sii, intr_val); +} + +int +si_numaddrspaces(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_numaddrspaces(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_numaddrspaces(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_numaddrspaces(sih); + else { + ASSERT(0); + return 0; + } +} + +uint32 +si_addrspace(si_t *sih, uint asidx) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_addrspace(sih, asidx); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_addrspace(sih, asidx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_addrspace(sih, asidx); + else { + ASSERT(0); + return 0; + } +} + +uint32 +si_addrspacesize(si_t *sih, uint asidx) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_addrspacesize(sih, asidx); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_addrspacesize(sih, asidx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_addrspacesize(sih, asidx); + else { + ASSERT(0); + return 0; + } +} + +void +si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) +{ + /* Only supported for SOCI_AI */ + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_coreaddrspaceX(sih, asidx, addr, size); + else + *size = 0; +} + +uint32 +si_core_cflags(si_t *sih, uint32 mask, uint32 val) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_core_cflags(sih, mask, val); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_core_cflags(sih, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_core_cflags(sih, mask, val); + else { + ASSERT(0); + return 0; + } +} + +void +si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + sb_core_cflags_wo(sih, mask, val); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_core_cflags_wo(sih, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_core_cflags_wo(sih, mask, val); + else + ASSERT(0); +} + +uint32 +si_core_sflags(si_t *sih, uint32 mask, uint32 val) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_core_sflags(sih, mask, val); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_core_sflags(sih, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_core_sflags(sih, mask, val); + else { + ASSERT(0); + return 0; + } +} + +bool +si_iscoreup(si_t *sih) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_iscoreup(sih); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_iscoreup(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_iscoreup(sih); + else { + ASSERT(0); + return FALSE; + } +} + +uint +si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) +{ + /* only for AI back plane chips */ + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return (ai_wrap_reg(sih, offset, mask, val)); + return 0; +} + +uint +si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_corereg(sih, coreidx, regoff, mask, val); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_corereg(sih, coreidx, regoff, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_corereg(sih, coreidx, regoff, mask, val); + else { + ASSERT(0); + return 0; + } +} + +/* + * If there is no need for fiddling with interrupts or core switches (typically silicon + * back plane registers, pci registers and chipcommon registers), this function + * returns the register offset on this core to a mapped address. This address can + * be used for W_REG/R_REG directly. + * + * For accessing registers that would need a core switch, this function will return + * NULL. + */ +uint32 * +si_corereg_addr(si_t *sih, uint coreidx, uint regoff) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_corereg_addr(sih, coreidx, regoff); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_corereg_addr(sih, coreidx, regoff); + else { + return 0; + } +} + +void +si_core_disable(si_t *sih, uint32 bits) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + sb_core_disable(sih, bits); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_core_disable(sih, bits); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_core_disable(sih, bits); +} + +void +si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + sb_core_reset(sih, bits, resetbits); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + ai_core_reset(sih, bits, resetbits); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_core_reset(sih, bits, resetbits); +} + +/** Run bist on current core. Caller needs to take care of core-specific bist hazards */ +int +si_corebist(si_t *sih) +{ + uint32 cflags; + int result = 0; + + /* Read core control flags */ + cflags = si_core_cflags(sih, 0, 0); + + /* Set bist & fgc */ + si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); + + /* Wait for bist done */ + SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); + + if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) + result = BCME_ERROR; + + /* Reset core control flags */ + si_core_cflags(sih, 0xffff, cflags); + + return result; +} + +static uint32 +factor6(uint32 x) +{ + switch (x) { + case CC_F6_2: return 2; + case CC_F6_3: return 3; + case CC_F6_4: return 4; + case CC_F6_5: return 5; + case CC_F6_6: return 6; + case CC_F6_7: return 7; + default: return 0; + } +} + +/** calculate the speed the SI would run at given a set of clockcontrol values */ +uint32 +si_clock_rate(uint32 pll_type, uint32 n, uint32 m) +{ + uint32 n1, n2, clock, m1, m2, m3, mc; + + n1 = n & CN_N1_MASK; + n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; + + if (pll_type == PLL_TYPE6) { + if (m & CC_T6_MMASK) + return CC_T6_M1; + else + return CC_T6_M0; + } else if ((pll_type == PLL_TYPE1) || + (pll_type == PLL_TYPE3) || + (pll_type == PLL_TYPE4) || + (pll_type == PLL_TYPE7)) { + n1 = factor6(n1); + n2 += CC_F5_BIAS; + } else if (pll_type == PLL_TYPE2) { + n1 += CC_T2_BIAS; + n2 += CC_T2_BIAS; + ASSERT((n1 >= 2) && (n1 <= 7)); + ASSERT((n2 >= 5) && (n2 <= 23)); + } else if (pll_type == PLL_TYPE5) { + return (100000000); + } else + ASSERT(0); + /* PLL types 3 and 7 use BASE2 (25Mhz) */ + if ((pll_type == PLL_TYPE3) || + (pll_type == PLL_TYPE7)) { + clock = CC_CLOCK_BASE2 * n1 * n2; + } else + clock = CC_CLOCK_BASE1 * n1 * n2; + + if (clock == 0) + return 0; + + m1 = m & CC_M1_MASK; + m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; + m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; + mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; + + if ((pll_type == PLL_TYPE1) || + (pll_type == PLL_TYPE3) || + (pll_type == PLL_TYPE4) || + (pll_type == PLL_TYPE7)) { + m1 = factor6(m1); + if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) + m2 += CC_F5_BIAS; + else + m2 = factor6(m2); + m3 = factor6(m3); + + switch (mc) { + case CC_MC_BYPASS: return (clock); + case CC_MC_M1: return (clock / m1); + case CC_MC_M1M2: return (clock / (m1 * m2)); + case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3)); + case CC_MC_M1M3: return (clock / (m1 * m3)); + default: return (0); + } + } else { + ASSERT(pll_type == PLL_TYPE2); + + m1 += CC_T2_BIAS; + m2 += CC_T2M2_BIAS; + m3 += CC_T2_BIAS; + ASSERT((m1 >= 2) && (m1 <= 7)); + ASSERT((m2 >= 3) && (m2 <= 10)); + ASSERT((m3 >= 2) && (m3 <= 7)); + + if ((mc & CC_T2MC_M1BYP) == 0) + clock /= m1; + if ((mc & CC_T2MC_M2BYP) == 0) + clock /= m2; + if ((mc & CC_T2MC_M3BYP) == 0) + clock /= m3; + + return (clock); + } +} + +/** + * Some chips could have multiple host interfaces, however only one will be active. + * For a given chip. Depending pkgopt and cc_chipst return the active host interface. + */ +uint +si_chip_hostif(si_t *sih) +{ + uint hosti = 0; + + switch (CHIPID(sih->chip)) { + + case BCM43602_CHIP_ID: + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + case BCM4360_CHIP_ID: + /* chippkg bit-0 == 0 is PCIE only pkgs + * chippkg bit-0 == 1 has both PCIE and USB cores enabled + */ + if ((sih->chippkg & 0x1) && (sih->chipst & CST4360_MODE_USB)) + hosti = CHIP_HOSTIF_USBMODE; + else + hosti = CHIP_HOSTIF_PCIEMODE; + + break; + + case BCM4335_CHIP_ID: + /* TBD: like in 4360, do we need to check pkg? */ + if (CST4335_CHIPMODE_USB20D(sih->chipst)) + hosti = CHIP_HOSTIF_USBMODE; + else if (CST4335_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + case BCM4345_CHIP_ID: + case BCM43454_CHIP_ID: + if (CST4345_CHIPMODE_USB20D(sih->chipst) || CST4345_CHIPMODE_HSIC(sih->chipst)) + hosti = CHIP_HOSTIF_USBMODE; + else if (CST4345_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else if (CST4345_CHIPMODE_PCIE(sih->chipst)) + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM4356_CHIP_ID: + case BCM43556_CHIP_ID: + case BCM43558_CHIP_ID: + case BCM43566_CHIP_ID: + case BCM43568_CHIP_ID: + case BCM43569_CHIP_ID: + if (CST4350_CHIPMODE_USB20D(sih->chipst) || + CST4350_CHIPMODE_HSIC20D(sih->chipst) || + CST4350_CHIPMODE_USB30D(sih->chipst) || + CST4350_CHIPMODE_USB30D_WL(sih->chipst) || + CST4350_CHIPMODE_HSIC30D(sih->chipst)) + hosti = CHIP_HOSTIF_USBMODE; + else if (CST4350_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else if (CST4350_CHIPMODE_PCIE(sih->chipst)) + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + default: + break; + } + + return hosti; +} + + +/** set chip watchdog reset timer to fire in 'ticks' */ +void +si_watchdog(si_t *sih, uint ticks) +{ + uint nb, maxt; + + if (PMUCTL_ENAB(sih)) { + +#if !defined(_CFEZ_) || defined(CFG_WL) + if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && + (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); + si_setcore(sih, USB20D_CORE_ID, 0); + si_core_disable(sih, 1); + si_setcore(sih, CC_CORE_ID, 0); + } +#endif + + nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); + /* The mips compiler uses the sllv instruction, + * so we specially handle the 32-bit case. + */ + if (nb == 32) + maxt = 0xffffffff; + else + maxt = ((1 << nb) - 1); + + if (ticks == 1) + ticks = 2; + else if (ticks > maxt) + ticks = maxt; + + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks); + } else { + maxt = (1 << 28) - 1; + if (ticks > maxt) + ticks = maxt; + + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); + } +} + +/** trigger watchdog reset after ms milliseconds */ +void +si_watchdog_ms(si_t *sih, uint32 ms) +{ + si_watchdog(sih, wd_msticks * ms); +} + +uint32 si_watchdog_msticks(void) +{ + return wd_msticks; +} + +bool +si_taclear(si_t *sih, bool details) +{ + return FALSE; +} + + + +/** return the slow clock source - LPO, XTAL, or PCI */ +static uint +si_slowclk_src(si_info_t *sii) +{ + chipcregs_t *cc; + + ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); + + if (sii->pub.ccrev < 6) { + if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && + (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) & + PCI_CFG_GPIO_SCS)) + return (SCC_SS_PCI); + else + return (SCC_SS_XTAL); + } else if (sii->pub.ccrev < 10) { + cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); + ASSERT(cc); + return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); + } else /* Insta-clock */ + return (SCC_SS_XTAL); +} + +/** return the ILP (slowclock) min or max frequency */ +static uint +si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) +{ + uint32 slowclk; + uint div; + + ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); + + /* shouldn't be here unless we've established the chip has dynamic clk control */ + ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); + + slowclk = si_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(sii->osh, &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 + ASSERT(0); + } else { + /* Chipc rev 10 is InstaClock */ + div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; + div = 4 * (div + 1); + return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); + } + return (0); +} + +static void +si_clkctl_setdelay(si_info_t *sii, void *chipcregs) +{ + chipcregs_t *cc = (chipcregs_t *)chipcregs; + 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 = si_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 = si_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(sii->osh, &cc->pll_on_delay, pll_on_delay); + W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); +} + +/** initialize power control delay registers */ +void +si_clkctl_init(si_t *sih) +{ + si_info_t *sii; + uint origidx = 0; + chipcregs_t *cc; + bool fast; + + if (!CCCTL_ENAB(sih)) + return; + + sii = SI_INFO(sih); + fast = SI_FAST(sii); + if (!fast) { + origidx = sii->curidx; + if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) + return; + } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) + return; + ASSERT(cc != NULL); + + /* set all Instaclk chip ILP to 1 MHz */ + if (sih->ccrev >= 10) + SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, + (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); + + si_clkctl_setdelay(sii, (void *)(uintptr)cc); + + OSL_DELAY(20000); + + if (!fast) + si_setcoreidx(sih, origidx); +} + + +/** change logical "focus" to the gpio core for optimized access */ +void * +si_gpiosetcore(si_t *sih) +{ + return (si_setcoreidx(sih, SI_CC_IDX)); +} + +/** + * mask & set gpiocontrol bits. + * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin. + * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated + * to some chip-specific purpose. + */ +uint32 +si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + regoff = 0; + + /* gpios could be shared on router platforms + * ignore reservation if it's high priority (e.g., test apps) + */ + if ((priority != GPIO_HI_PRIORITY) && + (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpiocontrol); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/** mask&set gpio output enable bits */ +uint32 +si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + regoff = 0; + + /* gpios could be shared on router platforms + * ignore reservation if it's high priority (e.g., test apps) + */ + if ((priority != GPIO_HI_PRIORITY) && + (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpioouten); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/** mask&set gpio output bits */ +uint32 +si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + regoff = 0; + + /* gpios could be shared on router platforms + * ignore reservation if it's high priority (e.g., test apps) + */ + if ((priority != GPIO_HI_PRIORITY) && + (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpioout); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/** reserve one gpio */ +uint32 +si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) +{ + /* only cores on SI_BUS share GPIO's and only applcation users need to + * reserve/release GPIO + */ + if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { + ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); + return 0xffffffff; + } + /* make sure only one bit is set */ + if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { + ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); + return 0xffffffff; + } + + /* already reserved */ + if (si_gpioreservation & gpio_bitmask) + return 0xffffffff; + /* set reservation */ + si_gpioreservation |= gpio_bitmask; + + return si_gpioreservation; +} + +/** + * release one gpio. + * + * releasing the gpio doesn't change the current value on the GPIO last write value + * persists till someone overwrites it. + */ +uint32 +si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) +{ + /* only cores on SI_BUS share GPIO's and only applcation users need to + * reserve/release GPIO + */ + if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { + ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); + return 0xffffffff; + } + /* make sure only one bit is set */ + if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { + ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); + return 0xffffffff; + } + + /* already released */ + if (!(si_gpioreservation & gpio_bitmask)) + return 0xffffffff; + + /* clear reservation */ + si_gpioreservation &= ~gpio_bitmask; + + return si_gpioreservation; +} + +/* return the current gpioin register value */ +uint32 +si_gpioin(si_t *sih) +{ + uint regoff; + + regoff = OFFSETOF(chipcregs_t, gpioin); + return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0)); +} + +/* mask&set gpio interrupt polarity bits */ +uint32 +si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + /* gpios could be shared on router platforms */ + if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpiointpolarity); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/* mask&set gpio interrupt mask bits */ +uint32 +si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) +{ + uint regoff; + + /* gpios could be shared on router platforms */ + if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + mask = priority ? (si_gpioreservation & mask) : + ((si_gpioreservation | mask) & ~(si_gpioreservation)); + val &= mask; + } + + regoff = OFFSETOF(chipcregs_t, gpiointmask); + return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); +} + +/* assign the gpio to an led */ +uint32 +si_gpioled(si_t *sih, uint32 mask, uint32 val) +{ + if (sih->ccrev < 16) + return 0xffffffff; + + /* gpio led powersave reg */ + return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); +} + +/* mask&set gpio timer val */ +uint32 +si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) +{ + if (sih->ccrev < 16) + return 0xffffffff; + + return (si_corereg(sih, SI_CC_IDX, + OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); +} + +uint32 +si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) +{ + uint offs; + + if (sih->ccrev < 20) + return 0xffffffff; + + offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); + return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); +} + +uint32 +si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) +{ + uint offs; + + if (sih->ccrev < 11) + return 0xffffffff; + + if (regtype == GPIO_REGEVT) + offs = OFFSETOF(chipcregs_t, gpioevent); + else if (regtype == GPIO_REGEVT_INTMSK) + offs = OFFSETOF(chipcregs_t, gpioeventintmask); + else if (regtype == GPIO_REGEVT_INTPOL) + offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); + else + return 0xffffffff; + + return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); +} + +void * +si_gpio_handler_register(si_t *sih, uint32 event, + bool level, gpio_handler_t cb, void *arg) +{ + si_info_t *sii = SI_INFO(sih); + gpioh_item_t *gi; + + ASSERT(event); + ASSERT(cb != NULL); + + if (sih->ccrev < 11) + return NULL; + + if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL) + return NULL; + + bzero(gi, sizeof(gpioh_item_t)); + gi->event = event; + gi->handler = cb; + gi->arg = arg; + gi->level = level; + + gi->next = sii->gpioh_head; + sii->gpioh_head = gi; + + return (void *)(gi); +} + +void +si_gpio_handler_unregister(si_t *sih, void *gpioh) +{ + si_info_t *sii = SI_INFO(sih); + gpioh_item_t *p, *n; + + if (sih->ccrev < 11) + return; + + ASSERT(sii->gpioh_head != NULL); + if ((void*)sii->gpioh_head == gpioh) { + sii->gpioh_head = sii->gpioh_head->next; + MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); + return; + } else { + p = sii->gpioh_head; + n = p->next; + while (n) { + if ((void*)n == gpioh) { + p->next = n->next; + MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); + return; + } + p = n; + n = n->next; + } + } + + ASSERT(0); /* Not found in list */ +} + +void +si_gpio_handler_process(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + gpioh_item_t *h; + uint32 level = si_gpioin(sih); + uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0); + uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); + uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0); + + for (h = sii->gpioh_head; h != NULL; h = h->next) { + if (h->handler) { + uint32 status = (h->level ? level : edge) & h->event; + uint32 polarity = (h->level ? levelp : edgep) & h->event; + + /* polarity bitval is opposite of status bitval */ + if (status ^ polarity) + h->handler(status, h->arg); + } + } + + si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ +} + +uint32 +si_gpio_int_enable(si_t *sih, bool enable) +{ + uint offs; + + if (sih->ccrev < 11) + return 0xffffffff; + + offs = OFFSETOF(chipcregs_t, intmask); + return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); +} + + +/** Return the size of the specified SOCRAM bank */ +static uint +socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) +{ + uint banksize, bankinfo; + uint bankidx = idx | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + + ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); + + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); + return banksize; +} + +void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 16) { + W_REG(sii->osh, ®s->bankidx, bankidx); + W_REG(sii->osh, ®s->bankpda, bankpda); + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); +} + +void +si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect, uint8 *remap) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + if (!set) + *enable = *protect = *remap = 0; + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 10) { + uint32 extcinfo; + uint8 nb; + uint8 i; + uint32 bankidx, bankinfo; + + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); + for (i = 0; i < nb; i++) { + bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + if (set) { + bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; + bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; + bankinfo &= ~SOCRAM_BANKINFO_DEVRAMREMAP_MASK; + if (*enable) { + bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); + if (*protect) + bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); + if ((corerev >= 16) && *remap) + bankinfo |= + (1 << SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT); + } + W_REG(sii->osh, ®s->bankinfo, bankinfo); + } + else if (i == 0) { + if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { + *enable = 1; + if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) + *protect = 1; + if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) + *remap = 1; + } + } + } + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); +} + +bool +si_socdevram_remap_isenb(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + sbsocramregs_t *regs; + bool wasup, remap = FALSE; + uint corerev; + uint32 extcinfo; + uint8 nb; + uint8 i; + uint32 bankidx, bankinfo; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 16) { + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); + for (i = 0; i < nb; i++) { + bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { + remap = TRUE; + break; + } + } + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + return remap; +} + +bool +si_socdevram_pkg(si_t *sih) +{ + if (si_socdevram_size(sih) > 0) + return TRUE; + else + return FALSE; +} + +uint32 +si_socdevram_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + uint32 memsize = 0; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 10) { + uint32 extcinfo; + uint8 nb; + uint8 i; + + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); + for (i = 0; i < nb; i++) + memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + +uint32 +si_socdevram_remap_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + uint32 memsize = 0, banksz; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + uint32 extcinfo; + uint8 nb; + uint8 i; + uint32 bankidx, bankinfo; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 16) { + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); + + /* + * FIX: A0 Issue: Max addressable is 512KB, instead 640KB + * Only four banks are accessible to ARM + */ + if ((corerev == 16) && (nb == 5)) + nb = 4; + + for (i = 0; i < nb; i++) { + bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { + banksz = socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); + memsize += banksz; + } else { + /* Account only consecutive banks for now */ + break; + } + } + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + +/** Return the RAM size of the SOCRAM core */ +uint32 +si_socram_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + + sbsocramregs_t *regs; + bool wasup; + uint corerev; + uint32 coreinfo; + uint memsize = 0; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + corerev = si_corerev(sih); + coreinfo = R_REG(sii->osh, ®s->coreinfo); + + /* Calculate size from coreinfo based on rev */ + if (corerev == 0) + memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); + else if (corerev < 3) { + memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); + memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + } else if ((corerev <= 7) || (corerev == 12)) { + uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + uint bsz = (coreinfo & SRCI_SRBSZ_MASK); + uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; + if (lss != 0) + nb --; + memsize = nb * (1 << (bsz + SR_BSZ_BASE)); + if (lss != 0) + memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); + } else { + uint8 i; + uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + for (i = 0; i < nb; i++) + memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + + +/** Return the TCM-RAM size of the ARMCR4 core. */ +uint32 +si_tcm_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + uint8 *regs; + bool wasup; + uint32 corecap; + uint memsize = 0; + uint32 nab = 0; + uint32 nbb = 0; + uint32 totb = 0; + uint32 bxinfo = 0; + uint32 idx = 0; + uint32 *arm_cap_reg; + uint32 *arm_bidx; + uint32 *arm_binfo; + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to CR4 core */ + if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0))) + goto done; + + /* Get info for determining size. If in reset, come out of reset, + * but remain in halt + */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT); + + arm_cap_reg = (uint32 *)(regs + SI_CR4_CAP); + corecap = R_REG(sii->osh, arm_cap_reg); + + nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; + nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; + totb = nab + nbb; + + arm_bidx = (uint32 *)(regs + SI_CR4_BANKIDX); + arm_binfo = (uint32 *)(regs + SI_CR4_BANKINFO); + for (idx = 0; idx < totb; idx++) { + W_REG(sii->osh, arm_bidx, idx); + + bxinfo = R_REG(sii->osh, arm_binfo); + memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + +bool +si_has_flops(si_t *sih) +{ + uint origidx, cr4_rev; + + /* Find out CR4 core revision */ + origidx = si_coreidx(sih); + if (si_setcore(sih, ARMCR4_CORE_ID, 0)) { + cr4_rev = si_corerev(sih); + si_setcoreidx(sih, origidx); + + if (cr4_rev == 1 || cr4_rev >= 3) + return TRUE; + } + return FALSE; +} + +uint32 +si_socram_srmem_size(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + + sbsocramregs_t *regs; + bool wasup; + uint corerev; + uint32 coreinfo; + uint memsize = 0; + + if ((CHIPID(sih->chip) == BCM4334_CHIP_ID) && (CHIPREV(sih->chiprev) < 2)) { + return (32 * 1024); + } + + if (CHIPID(sih->chip) == BCM43430_CHIP_ID) { + return (64 * 1024); + } + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + corerev = si_corerev(sih); + coreinfo = R_REG(sii->osh, ®s->coreinfo); + + /* Calculate size from coreinfo based on rev */ + if (corerev >= 16) { + uint8 i; + uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + for (i = 0; i < nb; i++) { + W_REG(sii->osh, ®s->bankidx, i); + if (R_REG(sii->osh, ®s->bankinfo) & SOCRAM_BANKINFO_RETNTRAM_MASK) + memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); + } + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + + +#if !defined(_CFEZ_) || defined(CFG_WL) +void +si_btcgpiowar(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint origidx; + uint intr_val = 0; + chipcregs_t *cc; + + /* Make sure that there is ChipCommon core present && + * UART_TX is strapped to 1 + */ + if (!(sih->cccaps & CC_CAP_UARTGPIO)) + return; + + /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */ + INTR_OFF(sii, intr_val); + + origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + ASSERT(cc != NULL); + + W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04); + + /* restore the original index */ + si_setcoreidx(sih, origidx); + + INTR_RESTORE(sii, intr_val); +} + +void +si_chipcontrl_btshd0_4331(si_t *sih, bool on) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + chipcregs_t *cc; + uint origidx; + uint32 val; + uint intr_val = 0; + + INTR_OFF(sii, intr_val); + + origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + val = R_REG(sii->osh, &cc->chipcontrol); + + /* bt_shd0 controls are same for 4331 chiprevs 0 and 1, packages 12x9 and 12x12 */ + if (on) { + /* Enable bt_shd0 on gpio4: */ + val |= (CCTRL4331_BT_SHD0_ON_GPIO4); + W_REG(sii->osh, &cc->chipcontrol, val); + } else { + val &= ~(CCTRL4331_BT_SHD0_ON_GPIO4); + W_REG(sii->osh, &cc->chipcontrol, val); + } + + /* restore the original index */ + si_setcoreidx(sih, origidx); + + INTR_RESTORE(sii, intr_val); +} + +void +si_chipcontrl_restore(si_t *sih, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + W_REG(sii->osh, &cc->chipcontrol, val); + si_setcoreidx(sih, origidx); +} + +uint32 +si_chipcontrl_read(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + uint32 val; + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + val = R_REG(sii->osh, &cc->chipcontrol); + si_setcoreidx(sih, origidx); + return val; +} + +void +si_chipcontrl_epa4331(si_t *sih, bool on) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + uint32 val; + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + val = R_REG(sii->osh, &cc->chipcontrol); + + if (on) { + if (sih->chippkg == 9 || sih->chippkg == 0xb) { + val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); + /* Ext PA Controls for 4331 12x9 Package */ + W_REG(sii->osh, &cc->chipcontrol, val); + } else { + /* Ext PA Controls for 4331 12x12 Package */ + if (sih->chiprev > 0) { + W_REG(sii->osh, &cc->chipcontrol, val | + (CCTRL4331_EXTPA_EN) | (CCTRL4331_EXTPA_EN2)); + } else { + W_REG(sii->osh, &cc->chipcontrol, val | (CCTRL4331_EXTPA_EN)); + } + } + } else { + val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_EN2 | CCTRL4331_EXTPA_ON_GPIO2_5); + W_REG(sii->osh, &cc->chipcontrol, val); + } + + si_setcoreidx(sih, origidx); +} + +/** switch muxed pins, on: SROM, off: FEMCTRL. Called for a family of ac chips, not just 4360. */ +void +si_chipcontrl_srom4360(si_t *sih, bool on) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + uint32 val; + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + val = R_REG(sii->osh, &cc->chipcontrol); + + if (on) { + val &= ~(CCTRL4360_SECI_MODE | + CCTRL4360_BTSWCTRL_MODE | + CCTRL4360_EXTRA_FEMCTRL_MODE | + CCTRL4360_BT_LGCY_MODE | + CCTRL4360_CORE2FEMCTRL4_ON); + + W_REG(sii->osh, &cc->chipcontrol, val); + } else { + } + + si_setcoreidx(sih, origidx); +} + +void +si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl) +{ + si_info_t *sii; + chipcregs_t *cc; + uint origidx; + uint32 val; + bool sel_chip; + + sel_chip = (CHIPID(sih->chip) == BCM4331_CHIP_ID) || + (CHIPID(sih->chip) == BCM43431_CHIP_ID); + sel_chip &= ((sih->chippkg == 9 || sih->chippkg == 0xb)); + + if (!sel_chip) + return; + + sii = SI_INFO(sih); + origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + val = R_REG(sii->osh, &cc->chipcontrol); + + if (enter_wowl) { + val |= CCTRL4331_EXTPA_EN; + W_REG(sii->osh, &cc->chipcontrol, val); + } else { + val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); + W_REG(sii->osh, &cc->chipcontrol, val); + } + si_setcoreidx(sih, origidx); +} +#endif + +uint +si_pll_reset(si_t *sih) +{ + uint err = 0; + + return (err); +} + +/** Enable BT-COEX & Ex-PA for 4313 */ +void +si_epa_4313war(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + /* EPA Fix */ + W_REG(sii->osh, &cc->gpiocontrol, + R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); + + si_setcoreidx(sih, origidx); +} + +void +si_clk_pmu_htavail_set(si_t *sih, bool set_clear) +{ +} + +/** Re-enable synth_pwrsw resource in min_res_mask for 4313 */ +void +si_pmu_synth_pwrsw_4313_war(si_t *sih) +{ +} + +/** WL/BT control for 4313 btcombo boards >= P250 */ +void +si_btcombo_p250_4313_war(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + W_REG(sii->osh, &cc->gpiocontrol, + R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_5_6_EN_MASK); + + W_REG(sii->osh, &cc->gpioouten, + R_REG(sii->osh, &cc->gpioouten) | GPIO_CTRL_5_6_EN_MASK); + + si_setcoreidx(sih, origidx); +} +void +si_btc_enable_chipcontrol(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + /* BT fix */ + W_REG(sii->osh, &cc->chipcontrol, + R_REG(sii->osh, &cc->chipcontrol) | CC_BTCOEX_EN_MASK); + + si_setcoreidx(sih, origidx); +} +void +si_btcombo_43228_war(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + + W_REG(sii->osh, &cc->gpioouten, GPIO_CTRL_7_6_EN_MASK); + W_REG(sii->osh, &cc->gpioout, GPIO_OUT_7_EN_MASK); + + si_setcoreidx(sih, origidx); +} + +/** check if the device is removed */ +bool +si_deviceremoved(si_t *sih) +{ + uint32 w; + + switch (BUSTYPE(sih->bustype)) { + case PCI_BUS: + ASSERT(SI_INFO(sih)->osh != NULL); + w = OSL_PCI_READ_CONFIG(SI_INFO(sih)->osh, PCI_CFG_VID, sizeof(uint32)); + if ((w & 0xFFFF) != VENDOR_BROADCOM) + return TRUE; + break; + } + return FALSE; +} + +bool +si_is_sprom_available(si_t *sih) +{ + if (sih->ccrev >= 31) { + si_info_t *sii; + uint origidx; + chipcregs_t *cc; + uint32 sromctrl; + + if ((sih->cccaps & CC_CAP_SROM) == 0) + return FALSE; + + sii = SI_INFO(sih); + origidx = sii->curidx; + cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT(cc); + sromctrl = R_REG(sii->osh, &cc->sromcontrol); + si_setcoreidx(sih, origidx); + return (sromctrl & SRC_PRESENT); + } + + switch (CHIPID(sih->chip)) { + case BCM4312_CHIP_ID: + return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL); + case BCM4325_CHIP_ID: + return (sih->chipst & CST4325_SPROM_SEL) != 0; + case BCM4322_CHIP_ID: case BCM43221_CHIP_ID: case BCM43231_CHIP_ID: + case BCM43222_CHIP_ID: case BCM43111_CHIP_ID: case BCM43112_CHIP_ID: + case BCM4342_CHIP_ID: { + uint32 spromotp; + spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >> + CST4322_SPROM_OTP_SEL_SHIFT; + return (spromotp & CST4322_SPROM_PRESENT) != 0; + } + case BCM4329_CHIP_ID: + return (sih->chipst & CST4329_SPROM_SEL) != 0; + case BCM4315_CHIP_ID: + return (sih->chipst & CST4315_SPROM_SEL) != 0; + case BCM4319_CHIP_ID: + return (sih->chipst & CST4319_SPROM_SEL) != 0; + case BCM4336_CHIP_ID: + case BCM43362_CHIP_ID: + return (sih->chipst & CST4336_SPROM_PRESENT) != 0; + case BCM4330_CHIP_ID: + return (sih->chipst & CST4330_SPROM_PRESENT) != 0; + case BCM4313_CHIP_ID: + return (sih->chipst & CST4313_SPROM_PRESENT) != 0; + case BCM4331_CHIP_ID: + case BCM43431_CHIP_ID: + return (sih->chipst & CST4331_SPROM_PRESENT) != 0; + case BCM43239_CHIP_ID: + return ((sih->chipst & CST43239_SPROM_MASK) && + !(sih->chipst & CST43239_SFLASH_MASK)); + case BCM4324_CHIP_ID: + case BCM43242_CHIP_ID: + return ((sih->chipst & CST4324_SPROM_MASK) && + !(sih->chipst & CST4324_SFLASH_MASK)); + case BCM4335_CHIP_ID: + case BCM4345_CHIP_ID: + case BCM43454_CHIP_ID: + return ((sih->chipst & CST4335_SPROM_MASK) && + !(sih->chipst & CST4335_SFLASH_MASK)); + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM4356_CHIP_ID: + case BCM43556_CHIP_ID: + case BCM43558_CHIP_ID: + case BCM43566_CHIP_ID: + case BCM43568_CHIP_ID: + case BCM43569_CHIP_ID: + return (sih->chipst & CST4350_SPROM_PRESENT) != 0; + case BCM43602_CHIP_ID: + return (sih->chipst & CST43602_SPROM_PRESENT) != 0; + case BCM43131_CHIP_ID: + case BCM43217_CHIP_ID: + case BCM43227_CHIP_ID: + case BCM43228_CHIP_ID: + case BCM43428_CHIP_ID: + return (sih->chipst & CST43228_OTP_PRESENT) != CST43228_OTP_PRESENT; + default: + return TRUE; + } +} + + +uint32 si_get_sromctl(si_t *sih) +{ + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + uint32 sromctl; + osl_t *osh = si_osh(sih); + + cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT((uintptr)cc); + + sromctl = R_REG(osh, &cc->sromcontrol); + + /* return to the original core */ + si_setcoreidx(sih, origidx); + return sromctl; +} + +int si_set_sromctl(si_t *sih, uint32 value) +{ + chipcregs_t *cc; + uint origidx = si_coreidx(sih); + osl_t *osh = si_osh(sih); + + cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT((uintptr)cc); + + /* get chipcommon rev */ + if (si_corerev(sih) < 32) + return BCME_UNSUPPORTED; + + W_REG(osh, &cc->sromcontrol, value); + + /* return to the original core */ + si_setcoreidx(sih, origidx); + return BCME_OK; + +} + +uint +si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val) +{ + uint origidx; + uint ret_val; + + origidx = si_coreidx(sih); + + si_setcoreidx(sih, coreidx); + + ret_val = si_wrapperreg(sih, offset, mask, val); + + /* return to the original core */ + si_setcoreidx(sih, origidx); + return ret_val; +} + + +/* cleanup the hndrte timer from the host when ARM is been halted + * without a chance for ARM cleanup its resources + * If left not cleanup, Intr from a software timer can still + * request HT clk when ARM is halted. + */ +uint32 +si_pmu_res_req_timer_clr(si_t *sih) +{ + uint32 mask; + + mask = PRRT_REQ_ACTIVE | PRRT_INTEN; + if (CHIPID(sih->chip) != BCM4328_CHIP_ID) + mask <<= 14; + /* clear mask bits */ + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, res_req_timer), mask, 0); + /* readback to ensure write completes */ + return si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, res_req_timer), 0, 0); +} + +/** turn on/off rfldo */ +void +si_pmu_rfldo(si_t *sih, bool on) +{ +} + +#ifdef SURVIVE_PERST_ENAB +static uint32 +si_pcie_survive_perst(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + + if (!PCIE(sii)) + return (0); + + return pcie_survive_perst(sii->pch, mask, val); +} + +static void +si_watchdog_reset(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint32 origidx, i; + + origidx = si_coreidx(sih); + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + /* issue a watchdog reset */ + W_REG(sii->osh, &cc->pmuwatchdog, 2); + /* do busy wait for 20ms */ + for (i = 0; i < 2000; i++) { + OSL_DELAY(10); + } + si_setcoreidx(sih, origidx); +} +#endif /* SURVIVE_PERST_ENAB */ + +void +si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 sperst_val) +{ +#ifdef SURVIVE_PERST_ENAB + if (BUSTYPE(sih->bustype) != PCI_BUS) + return; + + if ((CHIPID(sih->chip) != BCM4360_CHIP_ID && CHIPID(sih->chip) != BCM4352_CHIP_ID) || + (CHIPREV(sih->chiprev) >= 4)) + return; + + if (reset) { + si_info_t *sii = SI_INFO(sih); + uint32 bar0win, bar0win_after; + + /* save the bar0win */ + bar0win = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + + si_watchdog_reset(sih); + + bar0win_after = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + if (bar0win_after != bar0win) { + SI_ERROR(("%s: bar0win before %08x, bar0win after %08x\n", + __FUNCTION__, bar0win, bar0win_after)); + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32), bar0win); + } + } + if (sperst_mask) { + /* enable survive perst */ + si_pcie_survive_perst(sih, sperst_mask, sperst_val); + } +#endif /* SURVIVE_PERST_ENAB */ +} + +void +si_pcie_ltr_war(si_t *sih) +{ +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h b/drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h new file mode 100644 index 000000000000..e553ce355404 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h @@ -0,0 +1,272 @@ +/* + * Include file private to the SOC Interconnect support files. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: siutils_priv.h 431423 2013-10-23 16:07:35Z $ + */ + +#ifndef _siutils_priv_h_ +#define _siutils_priv_h_ + +#define SI_ERROR(args) + +#define SI_MSG(args) + +#ifdef BCMDBG_SI +#define SI_VMSG(args) printf args +#else +#define SI_VMSG(args) +#endif + +#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) + +typedef uint32 (*si_intrsoff_t)(void *intr_arg); +typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg); +typedef bool (*si_intrsenabled_t)(void *intr_arg); + +typedef struct gpioh_item { + void *arg; + bool level; + gpio_handler_t handler; + uint32 event; + struct gpioh_item *next; +} gpioh_item_t; + + +#define SI_GPIO_MAX 16 + +typedef struct gci_gpio_item { + void *arg; + uint8 gci_gpio; + uint8 status; + gci_gpio_handler_t handler; + struct gci_gpio_item *next; +} gci_gpio_item_t; + + +typedef struct si_cores_info { + void *regs[SI_MAXCORES]; /* other regs va */ + + uint coreid[SI_MAXCORES]; /* id of each core */ + uint32 coresba[SI_MAXCORES]; /* backplane address of each core */ + void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */ + uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */ + uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */ + uint32 coresba2_size[SI_MAXCORES]; /* second address space size */ + + void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ + uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ + + uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */ + uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */ +} si_cores_info_t; + +/* misc si info needed by some of the routines */ +typedef struct si_info { + struct si_pub pub; /* back plane public state (must be first field) */ + + void *osh; /* osl os handle */ + void *sdh; /* bcmsdh handle */ + + uint dev_coreid; /* the core provides driver functions */ + void *intr_arg; /* interrupt callback function arg */ + si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ + si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ + si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ + + void *pch; /* PCI/E core handle */ + + gpioh_item_t *gpioh_head; /* GPIO event handlers list */ + + bool memseg; /* flag to toggle MEM_SEG register */ + + char *vars; + uint varsz; + + void *curmap; /* current regs va */ + + uint curidx; /* current core index */ + uint numcores; /* # discovered cores */ + + void *curwrap; /* current wrapper va */ + + uint32 oob_router; /* oob router registers for axi */ + + void *cores_info; + gci_gpio_item_t *gci_gpio_head; /* gci gpio interrupts head */ +} si_info_t; + + +#define SI_INFO(sih) ((si_info_t *)(uintptr)sih) + +#define GOODCOREADDR(x, b) (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ + ISALIGNED((x), SI_CORE_SIZE)) +#define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE)) +#define BADCOREADDR 0 +#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES) +#define NOREV -1 /* Invalid rev */ + +#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ + ((si)->pub.buscoretype == PCI_CORE_ID)) + +#define PCIE_GEN1(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ + ((si)->pub.buscoretype == PCIE_CORE_ID)) + +#define PCIE_GEN2(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ + ((si)->pub.buscoretype == PCIE2_CORE_ID)) + +#define PCIE(si) (PCIE_GEN1(si) || PCIE_GEN2(si)) + +#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE)) + +/* Newer chips can access PCI/PCIE and CC core without requiring to change + * PCI BAR0 WIN + */ +#define SI_FAST(si) (PCIE(si) || (PCI(si) && ((si)->pub.buscorerev >= 13))) + +#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET)) +#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET)) + +/* + * 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 && (cores_info)->coreid[(si)->curidx] == (si)->dev_coreid) { \ + intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); } +#define INTR_RESTORE(si, intr_val) \ + if ((si)->intrsrestore_fn && (cores_info)->coreid[(si)->curidx] == (si)->dev_coreid) { \ + (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } + +/* 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 */ + +/* Force fast clock for 4360b0 */ +#define PCI_FORCEHT(si) \ + (((PCIE_GEN1(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \ + ((PCI(si) || PCIE_GEN1(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \ + (PCIE_GEN1(si) && (si->pub.chip == BCM4716_CHIP_ID)) || \ + (PCIE_GEN1(si) && (si->pub.chip == BCM4748_CHIP_ID))) + +/* GPIO Based LED powersave defines */ +#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ +#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ + +#ifndef DEFAULT_GPIOTIMERVAL +#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) +#endif + +/* Silicon Backplane externs */ +extern void sb_scan(si_t *sih, void *regs, uint devid); +extern uint sb_coreid(si_t *sih); +extern uint sb_intflag(si_t *sih); +extern uint sb_flag(si_t *sih); +extern void sb_setint(si_t *sih, int siflag); +extern uint sb_corevendor(si_t *sih); +extern uint sb_corerev(si_t *sih); +extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); +extern uint32 *sb_corereg_addr(si_t *sih, uint coreidx, uint regoff); +extern bool sb_iscoreup(si_t *sih); +extern void *sb_setcoreidx(si_t *sih, uint coreidx); +extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val); +extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); +extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val); +extern void sb_commit(si_t *sih); +extern uint32 sb_base(uint32 admatch); +extern uint32 sb_size(uint32 admatch); +extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); +extern void sb_core_disable(si_t *sih, uint32 bits); +extern uint32 sb_addrspace(si_t *sih, uint asidx); +extern uint32 sb_addrspacesize(si_t *sih, uint asidx); +extern int sb_numaddrspaces(si_t *sih); + +extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); + +extern bool sb_taclear(si_t *sih, bool details); + + +/* Wake-on-wireless-LAN (WOWL) */ +extern bool sb_pci_pmecap(si_t *sih); +struct osl_info; +extern bool sb_pci_fastpmecap(struct osl_info *osh); +extern bool sb_pci_pmeclr(si_t *sih); +extern void sb_pci_pmeen(si_t *sih); +extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset); + +/* AMBA Interconnect exported externs */ +extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, + void *sdh, char **vars, uint *varsz); +extern si_t *ai_kattach(osl_t *osh); +extern void ai_scan(si_t *sih, void *regs, uint devid); + +extern uint ai_flag(si_t *sih); +extern uint ai_flag_alt(si_t *sih); +extern void ai_setint(si_t *sih, int siflag); +extern uint ai_coreidx(si_t *sih); +extern uint ai_corevendor(si_t *sih); +extern uint ai_corerev(si_t *sih); +extern uint32 *ai_corereg_addr(si_t *sih, uint coreidx, uint regoff); +extern bool ai_iscoreup(si_t *sih); +extern void *ai_setcoreidx(si_t *sih, uint coreidx); +extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val); +extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); +extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val); +extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); +extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits); +extern void ai_core_disable(si_t *sih, uint32 bits); +extern int ai_numaddrspaces(si_t *sih); +extern uint32 ai_addrspace(si_t *sih, uint asidx); +extern uint32 ai_addrspacesize(si_t *sih, uint asidx); +extern void ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); +extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val); + + + +#define ub_scan(a, b, c) do {} while (0) +#define ub_flag(a) (0) +#define ub_setint(a, b) do {} while (0) +#define ub_coreidx(a) (0) +#define ub_corevendor(a) (0) +#define ub_corerev(a) (0) +#define ub_iscoreup(a) (0) +#define ub_setcoreidx(a, b) (0) +#define ub_core_cflags(a, b, c) (0) +#define ub_core_cflags_wo(a, b, c) do {} while (0) +#define ub_core_sflags(a, b, c) (0) +#define ub_corereg(a, b, c, d, e) (0) +#define ub_core_reset(a, b, c) do {} while (0) +#define ub_core_disable(a, b) do {} while (0) +#define ub_numaddrspaces(a) (0) +#define ub_addrspace(a, b) (0) +#define ub_addrspacesize(a, b) (0) +#define ub_view(a, b) do {} while (0) +#define ub_dumpregs(a, b) do {} while (0) + +#endif /* _siutils_priv_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h b/drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h new file mode 100644 index 000000000000..93d1d2eb208b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h @@ -0,0 +1,176 @@ +/* + * Name: uamp_api.h + * + * Description: Universal AMP API + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: uamp_api.h 294267 2011-11-04 23:41:52Z $ + * + */ +#ifndef UAMP_API_H +#define UAMP_API_H + + +#include "typedefs.h" + + +/***************************************************************************** +** Constant and Type Definitions +****************************************************************************** +*/ + +#define BT_API + +/* Types. */ +typedef bool BOOLEAN; +typedef uint8 UINT8; +typedef uint16 UINT16; + + +/* UAMP identifiers */ +#define UAMP_ID_1 1 +#define UAMP_ID_2 2 +typedef UINT8 tUAMP_ID; + +/* UAMP event ids (used by UAMP_CBACK) */ +#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */ +#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */ +#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */ +typedef UINT8 tUAMP_EVT; + + +/* UAMP Channels */ +#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */ +#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */ +#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */ +typedef UINT8 tUAMP_CH; + +/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */ +typedef union { + tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */ +} tUAMP_EVT_DATA; + + +/***************************************************************************** +** +** Function: UAMP_CBACK +** +** Description: Callback for events. Register callback using UAMP_Init. +** +** Parameters amp_id: AMP device identifier that generated the event +** amp_evt: event id +** p_amp_evt_data: pointer to event-specific data +** +****************************************************************************** +*/ +typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data); + +/***************************************************************************** +** external function declarations +****************************************************************************** +*/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** +** Function: UAMP_Init +** +** Description: Initialize UAMP driver +** +** Parameters p_cback: Callback function for UAMP event notification +** +****************************************************************************** +*/ +BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback); + + +/***************************************************************************** +** +** Function: UAMP_Open +** +** Description: Open connection to local AMP device. +** +** Parameters app_id: Application specific AMP identifer. This value +** will be included in AMP messages sent to the +** BTU task, to identify source of the message +** +****************************************************************************** +*/ +BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id); + +/***************************************************************************** +** +** Function: UAMP_Close +** +** Description: Close connection to local AMP device. +** +** Parameters app_id: Application specific AMP identifer. +** +****************************************************************************** +*/ +BT_API void UAMP_Close(tUAMP_ID amp_id); + + +/***************************************************************************** +** +** Function: UAMP_Write +** +** Description: Send buffer to AMP device. Frees GKI buffer when done. +** +** +** Parameters: app_id: AMP identifer. +** p_buf: pointer to buffer to write +** num_bytes: number of bytes to write +** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD +** +** Returns: number of bytes written +** +****************************************************************************** +*/ +BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel); + +/***************************************************************************** +** +** Function: UAMP_Read +** +** Description: Read incoming data from AMP. Call after receiving a +** UAMP_EVT_RX_READY callback event. +** +** Parameters: app_id: AMP identifer. +** p_buf: pointer to buffer for holding incoming AMP data +** buf_size: size of p_buf +** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT +** +** Returns: number of bytes read +** +****************************************************************************** +*/ +BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel); + +#ifdef __cplusplus +} +#endif + +#endif /* UAMP_API_H */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c new file mode 100644 index 000000000000..5924e82e83f8 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c @@ -0,0 +1,2340 @@ +/* + * Linux cfg80211 driver - Android related functions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_android.c 701450 2017-05-25 02:10:23Z $ + */ + +#include +#include +#include +#ifdef CONFIG_COMPAT +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef PNO_SUPPORT +#include +#endif +#include +#ifdef WL_CFG80211 +#include +#endif +#ifdef WL_NAN +#include +#endif /* WL_NAN */ + +/* + * Android private command strings, PLEASE define new private commands here + * so they can be updated easily in the future (if needed) + */ + +#define CMD_START "START" +#define CMD_STOP "STOP" +#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" +#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" +#define CMD_RSSI "RSSI" +#define CMD_LINKSPEED "LINKSPEED" +#define CMD_RXFILTER_START "RXFILTER-START" +#define CMD_RXFILTER_STOP "RXFILTER-STOP" +#define CMD_RXFILTER_ADD "RXFILTER-ADD" +#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" +#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" +#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" +#define CMD_BTCOEXMODE "BTCOEXMODE" +#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" +#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" +#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" +#define CMD_SETFWPATH "SETFWPATH" +#define CMD_SETBAND "SETBAND" +#define CMD_GETBAND "GETBAND" +#define CMD_COUNTRY "COUNTRY" +#define CMD_P2P_SET_NOA "P2P_SET_NOA" +#if !defined WL_ENABLE_P2P_IF +#define CMD_P2P_GET_NOA "P2P_GET_NOA" +#endif /* WL_ENABLE_P2P_IF */ +#define CMD_P2P_SD_OFFLOAD "P2P_SD_" +#define CMD_P2P_SET_PS "P2P_SET_PS" +#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" +#define CMD_SETROAMMODE "SETROAMMODE" +#define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA" +#define CMD_MIRACAST "MIRACAST" +#define CMD_NAN "NAN_" + +#if defined(WL_SUPPORT_AUTO_CHANNEL) +#define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS" +#endif /* WL_SUPPORT_AUTO_CHANNEL */ + +#ifdef WLFBT +#define CMD_GET_FTKEY "GET_FTKEY" +#endif +#define CMD_KEEP_ALIVE "KEEPALIVE" + + +/* CCX Private Commands */ +#ifdef BCMCCX +#define CMD_GETCCKM_RN "get cckm_rn" +#define CMD_SETCCKM_KRK "set cckm_krk" +#define CMD_GET_ASSOC_RES_IES "get assoc_res_ies" +#endif + +#ifdef PNO_SUPPORT +#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" +#define CMD_PNOSETUP_SET "PNOSETUP " +#define CMD_PNOENABLE_SET "PNOFORCE" +#define CMD_PNODEBUG_SET "PNODEBUG" +#define CMD_WLS_BATCHING "WLS_BATCHING" +#endif /* PNO_SUPPORT */ + +#define CMD_OKC_SET_PMK "SET_PMK" +#define CMD_OKC_ENABLE "OKC_ENABLE" + +#define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER" + + +#ifdef WLAIBSS +#define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT" +#define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO" +#define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL" +#define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE" +#define CMD_SETIBSSAMPDU "SETIBSSAMPDU" +#define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE" +#endif /* WLAIBSS */ + +#define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD" + +/* miracast related definition */ +#define MIRACAST_MODE_OFF 0 +#define MIRACAST_MODE_SOURCE 1 +#define MIRACAST_MODE_SINK 2 + +#ifndef MIRACAST_AMPDU_SIZE +#define MIRACAST_AMPDU_SIZE 8 +#endif + +#ifndef MIRACAST_MCHAN_ALGO +#define MIRACAST_MCHAN_ALGO 1 +#endif + +#ifndef MIRACAST_MCHAN_BW +#define MIRACAST_MCHAN_BW 25 +#endif + +#ifdef CHANGE_SCAN_TIME +static int miracast_scan_time[3][2] = { + { WLC_GET_SCAN_CHANNEL_TIME, 20 }, + { WLC_GET_SCAN_UNASSOC_TIME, 20 }, + { WLC_GET_SCAN_PASSIVE_TIME, 40 } + }; +#endif + +#ifdef CONNECTION_STATISTICS +#define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS" + +struct connection_stats { + u32 txframe; + u32 txbyte; + u32 txerror; + u32 rxframe; + u32 rxbyte; + u32 txfail; + u32 txretry; + u32 txretrie; + u32 txrts; + u32 txnocts; + u32 txexptime; + u32 txrate; + u8 chan_idle; +}; +#endif /* CONNECTION_STATISTICS */ + +static LIST_HEAD(miracast_resume_list); +static u8 miracast_cur_mode; + +struct io_cfg { + s8 *iovar; + s32 param; + u32 ioctl; + void *arg; + u32 len; + struct list_head list; +}; + +typedef struct _android_wifi_priv_cmd { + char *buf; + int used_len; + int total_len; +} android_wifi_priv_cmd; + +#ifdef CONFIG_COMPAT +typedef struct _compat_android_wifi_priv_cmd { + compat_caddr_t buf; + int used_len; + int total_len; +} compat_android_wifi_priv_cmd; +#endif /* CONFIG_COMPAT */ + +#if defined(BCMFW_ROAM_ENABLE) +#define CMD_SET_ROAMPREF "SET_ROAMPREF" + +#define MAX_NUM_SUITES 10 +#define WIDTH_AKM_SUITE 8 +#define JOIN_PREF_RSSI_LEN 0x02 +#define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */ +#define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */ +#define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */ +#define JOIN_PREF_MAX_WPA_TUPLES 16 +#define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \ + (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES)) +#endif /* BCMFW_ROAM_ENABLE */ + + +/** + * Extern function declarations (TODO: move them to dhd_linux.h) + */ +int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); +int dhd_dev_init_ioctl(struct net_device *dev); +#ifdef WL_CFG80211 +int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); +int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command); +#else +int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) +{ return 0; } +int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) +{ return 0; } +int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) +{ return 0; } +int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) +{ return 0; } +#endif /* WK_CFG80211 */ + + +#ifdef ENABLE_4335BT_WAR +extern int bcm_bt_lock(int cookie); +extern void bcm_bt_unlock(int cookie); +static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ +#endif /* ENABLE_4335BT_WAR */ + +extern bool ap_fw_loaded; +#if defined(CUSTOMER_HW2) +extern char iface_name[IFNAMSIZ]; +#endif + +/** + * Local (static) functions and variables + */ + +/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first + * time (only) in dhd_open, subsequential wifi on will be handled by + * wl_android_wifi_on + */ +static int g_wifi_on = TRUE; + +/** + * Local (static) function definitions + */ +static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) +{ + int link_speed; + int bytes_written; + int error; + + error = wldev_get_link_speed(net, &link_speed); + if (error) + return -1; + + /* Convert Kbps to Android Mbps */ + link_speed = link_speed / 1000; + bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); + DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); + return bytes_written; +} + +static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) +{ + wlc_ssid_t ssid = {0}; + int rssi; + int bytes_written = 0; + int error; + + error = wldev_get_rssi(net, &rssi); + if (error) + return -1; + + error = wldev_get_ssid(net, &ssid); + if (error) + return -1; + if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { + DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); + } else if (total_len <= ssid.SSID_len) { + return -ENOMEM; + } else { + memcpy(command, ssid.SSID, ssid.SSID_len); + bytes_written = ssid.SSID_len; + } + + if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1)) + return -ENOMEM; + + bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written, + " rssi %d", rssi); + command[bytes_written] = '\0'; + + DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); + return bytes_written; +} + +static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) +{ + int suspend_flag; + int ret_now; + int ret = 0; + + suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; + + if (suspend_flag != 0) + suspend_flag = 1; + ret_now = net_os_set_suspend_disable(dev, suspend_flag); + + if (ret_now != suspend_flag) { + if (!(ret = net_os_set_suspend(dev, ret_now, 1))) + DHD_INFO(("%s: Suspend Flag %d -> %d\n", + __FUNCTION__, ret_now, suspend_flag)); + else + DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); + } + return ret; +} + +static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) +{ + int ret = 0; + +#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) + int suspend_flag; + + suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; + if (suspend_flag != 0) + suspend_flag = 1; + + if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) + DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag)); + else + DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); +#endif + + return ret; +} + +static int wl_android_get_band(struct net_device *dev, char *command, int total_len) +{ + uint band; + int bytes_written; + int error; + + error = wldev_get_band(dev, &band); + if (error) + return -1; + bytes_written = snprintf(command, total_len, "Band %d", band); + return bytes_written; +} + + +#ifdef PNO_SUPPORT +#define PNO_PARAM_SIZE 50 +#define VALUE_SIZE 50 +#define LIMIT_STR_FMT ("%50s %50s") +static int +wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) +{ + int err = BCME_OK; + uint i, tokens; + char *pos, *pos2, *token, *token2, *delim; + char param[PNO_PARAM_SIZE], value[VALUE_SIZE]; + struct dhd_pno_batch_params batch_params; + DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + if (total_len < strlen(CMD_WLS_BATCHING)) { + DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); + err = BCME_ERROR; + goto exit; + } + pos = command + strlen(CMD_WLS_BATCHING) + 1; + memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params)); + + if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) { + pos += strlen(PNO_BATCHING_SET) + 1; + while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) { + memset(param, 0, sizeof(param)); + memset(value, 0, sizeof(value)); + if (token == NULL || !*token) + break; + if (*token == '\0') + continue; + delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER); + if (delim != NULL) + *delim = ' '; + + tokens = sscanf(token, LIMIT_STR_FMT, param, value); + if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) { + batch_params.scan_fr = simple_strtol(value, NULL, 0); + DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr)); + } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) { + batch_params.bestn = simple_strtol(value, NULL, 0); + DHD_PNO(("bestn : %d\n", batch_params.bestn)); + } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) { + batch_params.mscan = simple_strtol(value, NULL, 0); + DHD_PNO(("mscan : %d\n", batch_params.mscan)); + } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) { + i = 0; + pos2 = value; + tokens = sscanf(value, "<%s>", value); + if (tokens != 1) { + err = BCME_ERROR; + DHD_ERROR(("%s : invalid format for channel" + " <> params\n", __FUNCTION__)); + goto exit; + } + while ((token2 = strsep(&pos2, + PNO_PARAM_CHANNEL_DELIMETER)) != NULL) { + if (token2 == NULL || !*token2) + break; + if (*token2 == '\0') + continue; + if (*token2 == 'A' || *token2 == 'B') { + batch_params.band = (*token2 == 'A')? + WLC_BAND_5G : WLC_BAND_2G; + DHD_PNO(("band : %s\n", + (*token2 == 'A')? "A" : "B")); + } else { + if ((batch_params.nchan >= WL_NUMCHANNELS) || + (i >= WL_NUMCHANNELS)) { + DHD_ERROR(("Too many nchan %d\n", + batch_params.nchan)); + err = BCME_BUFTOOSHORT; + goto exit; + } + batch_params.chan_list[i++] = + simple_strtol(token2, NULL, 0); + batch_params.nchan++; + DHD_PNO(("channel :%d\n", + batch_params.chan_list[i-1])); + } + } + } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) { + batch_params.rtt = simple_strtol(value, NULL, 0); + DHD_PNO(("rtt : %d\n", batch_params.rtt)); + } else { + DHD_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param)); + err = BCME_ERROR; + goto exit; + } + } + err = dhd_dev_pno_set_for_batch(dev, &batch_params); + if (err < 0) { + DHD_ERROR(("failed to configure batch scan\n")); + } else { + memset(command, 0, total_len); + err = sprintf(command, "%d", err); + } + } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) { + err = dhd_dev_pno_get_for_batch(dev, command, total_len); + if (err < 0) { + DHD_ERROR(("failed to getting batching results\n")); + } else { + err = strlen(command); + } + } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) { + err = dhd_dev_pno_stop_for_batch(dev); + if (err < 0) { + DHD_ERROR(("failed to stop batching scan\n")); + } else { + memset(command, 0, total_len); + err = sprintf(command, "OK"); + } + } else { + DHD_ERROR(("%s : unknown command\n", __FUNCTION__)); + err = BCME_ERROR; + goto exit; + } +exit: + return err; +} +#ifndef WL_SCHED_SCAN +static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) +{ + wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; + int res = -1; + int nssid = 0; + cmd_tlv_t *cmd_tlv_temp; + char *str_ptr; + int tlv_size_left; + int pno_time = 0; + int pno_repeat = 0; + int pno_freq_expo_max = 0; + +#ifdef PNO_SET_DEBUG + int i; + char pno_in_example[] = { + 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', + 'S', '1', '2', '0', + 'S', + 0x05, + 'd', 'l', 'i', 'n', 'k', + 'S', + 0x04, + 'G', 'O', 'O', 'G', + 'T', + '0', 'B', + 'R', + '2', + 'M', + '2', + 0x00 + }; +#endif /* PNO_SET_DEBUG */ + DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + + if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { + DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); + goto exit_proc; + } +#ifdef PNO_SET_DEBUG + memcpy(command, pno_in_example, sizeof(pno_in_example)); + total_len = sizeof(pno_in_example); +#endif + str_ptr = command + strlen(CMD_PNOSETUP_SET); + tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); + + cmd_tlv_temp = (cmd_tlv_t *)str_ptr; + memset(ssids_local, 0, sizeof(ssids_local)); + + if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && + (cmd_tlv_temp->version == PNO_TLV_VERSION) && + (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) { + + str_ptr += sizeof(cmd_tlv_t); + tlv_size_left -= sizeof(cmd_tlv_t); + + if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local, + MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { + DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); + goto exit_proc; + } else { + if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { + DHD_ERROR(("%s scan duration corrupted field size %d\n", + __FUNCTION__, tlv_size_left)); + goto exit_proc; + } + str_ptr++; + pno_time = simple_strtoul(str_ptr, &str_ptr, 16); + DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); + + if (str_ptr[0] != 0) { + if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { + DHD_ERROR(("%s pno repeat : corrupted field\n", + __FUNCTION__)); + goto exit_proc; + } + str_ptr++; + pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); + DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); + if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { + DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", + __FUNCTION__)); + goto exit_proc; + } + str_ptr++; + pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); + DHD_PNO(("%s: pno_freq_expo_max=%d\n", + __FUNCTION__, pno_freq_expo_max)); + } + } + } else { + DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); + goto exit_proc; + } + + res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat, + pno_freq_expo_max, NULL, 0); +exit_proc: + return res; +} +#endif /* !WL_SCHED_SCAN */ +#endif /* PNO_SUPPORT */ + +static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) +{ + int ret; + int bytes_written = 0; + + ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command); + if (ret) + return 0; + bytes_written = sizeof(struct ether_addr); + return bytes_written; +} + +#ifdef BCMCCX +static int wl_android_get_cckm_rn(struct net_device *dev, char *command) +{ + int error, rn; + + WL_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name)); + + error = wldev_iovar_getint(dev, "cckm_rn", &rn); + if (unlikely(error)) { + WL_ERR(("wl_android_get_cckm_rn error (%d)\n", error)); + return -1; + } + memcpy(command, &rn, sizeof(int)); + + return sizeof(int); +} + +static int wl_android_set_cckm_krk(struct net_device *dev, char *command) +{ + int error; + unsigned char key[16]; + static char iovar_buf[WLC_IOCTL_MEDLEN]; + + WL_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name)); + + memset(iovar_buf, 0, sizeof(iovar_buf)); + memcpy(key, command+strlen("set cckm_krk")+1, 16); + + error = wldev_iovar_setbuf(dev, "cckm_krk", key, sizeof(key), + iovar_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(error)) + { + WL_ERR((" cckm_krk set error (%d)\n", error)); + return -1; + } + return 0; +} + +static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command) +{ + int error; + u8 buf[WL_ASSOC_INFO_MAX]; + wl_assoc_info_t assoc_info; + u32 resp_ies_len = 0; + int bytes_written = 0; + + WL_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name)); + + error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf, WL_ASSOC_INFO_MAX, NULL); + if (unlikely(error)) { + WL_ERR(("could not get assoc info (%d)\n", error)); + return -1; + } + + memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t)); + assoc_info.req_len = htod32(assoc_info.req_len); + assoc_info.resp_len = htod32(assoc_info.resp_len); + assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.resp_len) { + resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + } + + /* first 4 bytes are ie len */ + memcpy(command, &resp_ies_len, sizeof(u32)); + bytes_written = sizeof(u32); + + /* get the association resp IE's if there are any */ + if (resp_ies_len) { + error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0, + buf, WL_ASSOC_INFO_MAX, NULL); + if (unlikely(error)) { + WL_ERR(("could not get assoc resp_ies (%d)\n", error)); + return -1; + } + + memcpy(command+sizeof(u32), buf, resp_ies_len); + bytes_written += resp_ies_len; + } + return bytes_written; +} + +#endif /* BCMCCX */ + +int +wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist) +{ + int i, j, match; + int ret = 0; + char mac_buf[MAX_NUM_OF_ASSOCLIST * + sizeof(struct ether_addr) + sizeof(uint)] = {0}; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; + + /* set filtering mode */ + if ((ret = wldev_ioctl(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode), true)) != 0) { + DHD_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret)); + return ret; + } + if (macmode != MACLIST_MODE_DISABLED) { + /* set the MAC filter list */ + if ((ret = wldev_ioctl(dev, WLC_SET_MACLIST, maclist, + sizeof(int) + sizeof(struct ether_addr) * maclist->count, true)) != 0) { + DHD_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret)); + return ret; + } + /* get the current list of associated STAs */ + assoc_maclist->count = MAX_NUM_OF_ASSOCLIST; + if ((ret = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, + sizeof(mac_buf), false)) != 0) { + DHD_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret)); + return ret; + } + /* do we have any STA associated? */ + if (assoc_maclist->count) { + /* iterate each associated STA */ + for (i = 0; i < assoc_maclist->count; i++) { + match = 0; + /* compare with each entry */ + for (j = 0; j < maclist->count; j++) { + DHD_INFO(("%s : associated="MACDBG " list="MACDBG "\n", + __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet), + MAC2STRDBG(maclist->ea[j].octet))); + if (memcmp(assoc_maclist->ea[i].octet, + maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) { + match = 1; + break; + } + } + /* do conditional deauth */ + /* "if not in the allow list" or "if in the deny list" */ + if ((macmode == MACLIST_MODE_ALLOW && !match) || + (macmode == MACLIST_MODE_DENY && match)) { + scb_val_t scbval; + + scbval.val = htod32(1); + memcpy(&scbval.ea, &assoc_maclist->ea[i], + ETHER_ADDR_LEN); + if ((ret = wldev_ioctl(dev, + WLC_SCB_DEAUTHENTICATE_FOR_REASON, + &scbval, sizeof(scb_val_t), true)) != 0) + DHD_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n", + __FUNCTION__, ret)); + } + } + } + } + return ret; +} + +/* + * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2 + * + */ +static int +wl_android_set_mac_address_filter(struct net_device *dev, const char* str) +{ + int i; + int ret = 0; + int macnum = 0; + int macmode = MACLIST_MODE_DISABLED; + struct maclist *list; + char eabuf[ETHER_ADDR_STR_LEN]; + + /* string should look like below (macmode/macnum/maclist) */ + /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */ + + /* get the MAC filter mode */ + macmode = bcm_atoi(strsep((char**)&str, " ")); + + if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) { + DHD_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode)); + return -1; + } + + macnum = bcm_atoi(strsep((char**)&str, " ")); + if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { + DHD_ERROR(("%s : invalid number of MAC address entries %d\n", + __FUNCTION__, macnum)); + return -1; + } + /* allocate memory for the MAC list */ + list = (struct maclist*)kmalloc(sizeof(int) + + sizeof(struct ether_addr) * macnum, GFP_KERNEL); + if (!list) { + DHD_ERROR(("%s : failed to allocate memory\n", __FUNCTION__)); + return -1; + } + /* prepare the MAC list */ + list->count = htod32(macnum); + bzero((char *)eabuf, ETHER_ADDR_STR_LEN); + for (i = 0; i < list->count; i++) { + strncpy(eabuf, strsep((char**)&str, " "), ETHER_ADDR_STR_LEN - 1); + if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) { + DHD_ERROR(("%s : mac parsing err index=%d, addr=%s\n", + __FUNCTION__, i, eabuf)); + list->count--; + break; + } + DHD_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf)); + } + /* set the list */ + if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0) + DHD_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); + + kfree(list); + + return 0; +} + +/** + * Global function definitions (declared in wl_android.h) + */ + +int wl_android_wifi_on(struct net_device *dev) +{ + int ret = 0; + int retry = POWERUP_MAX_RETRY; + + DHD_ERROR(("%s in\n", __FUNCTION__)); + if (!dev) { + DHD_ERROR(("%s: dev is null\n", __FUNCTION__)); + return -EINVAL; + } + + dhd_net_if_lock(dev); + if (!g_wifi_on) { + do { + dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY); + ret = dhd_net_bus_resume(dev, 0); + if (ret == 0) + break; + DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n", + retry+1)); + dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); + } while (retry-- >= 0); + if (ret != 0) { + DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n")); + goto exit; + } + ret = dhd_net_bus_devreset(dev, FALSE); + dhd_net_bus_resume(dev, 1); + if (!ret) { + if (dhd_dev_init_ioctl(dev) < 0) + ret = -EFAULT; + } + g_wifi_on = TRUE; + } + +exit: + dhd_net_if_unlock(dev); + + return ret; +} + +int wl_android_wifi_off(struct net_device *dev) +{ + int ret = 0; + + DHD_ERROR(("%s in\n", __FUNCTION__)); + if (!dev) { + DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); + return -EINVAL; + } + + dhd_net_if_lock(dev); + if (g_wifi_on) { + ret = dhd_net_bus_devreset(dev, TRUE); + dhd_net_bus_suspend(dev); + dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); + g_wifi_on = FALSE; + } + dhd_net_if_unlock(dev); + + return ret; +} + +static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len) +{ + if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN) + return -1; + return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1); +} + +#ifdef CONNECTION_STATISTICS +static int +wl_chanim_stats(struct net_device *dev, u8 *chan_idle) +{ + int err; + wl_chanim_stats_t *list; + /* Parameter _and_ returned buffer of chanim_stats. */ + wl_chanim_stats_t param; + u8 result[WLC_IOCTL_SMLEN]; + chanim_stats_t *stats; + + memset(¶m, 0, sizeof(param)); + + param.buflen = htod32(sizeof(wl_chanim_stats_t)); + param.count = htod32(WL_CHANIM_COUNT_ONE); + + if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)¶m, sizeof(wl_chanim_stats_t), + (char*)result, sizeof(result), 0)) < 0) { + WL_ERR(("Failed to get chanim results %d \n", err)); + return err; + } + + list = (wl_chanim_stats_t*)result; + + list->buflen = dtoh32(list->buflen); + list->version = dtoh32(list->version); + list->count = dtoh32(list->count); + + if (list->buflen == 0) { + list->version = 0; + list->count = 0; + } else if (list->version != WL_CHANIM_STATS_VERSION) { + WL_ERR(("Sorry, firmware has wl_chanim_stats version %d " + "but driver supports only version %d.\n", + list->version, WL_CHANIM_STATS_VERSION)); + list->buflen = 0; + list->count = 0; + } + + stats = list->stats; + stats->glitchcnt = dtoh32(stats->glitchcnt); + stats->badplcp = dtoh32(stats->badplcp); + stats->chanspec = dtoh16(stats->chanspec); + stats->timestamp = dtoh32(stats->timestamp); + stats->chan_idle = dtoh32(stats->chan_idle); + + WL_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n", + stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle, + stats->timestamp)); + + *chan_idle = stats->chan_idle; + + return (err); +} + +static int +wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len) +{ + wl_cnt_t* cnt = NULL; +#ifndef DISABLE_IF_COUNTERS + wl_if_stats_t* if_stats = NULL; +#endif /* DISABLE_IF_COUNTERS */ + + int link_speed = 0; + struct connection_stats *output; + unsigned int bufsize = 0; + int bytes_written = -1; + int ret = 0; + + WL_INFO(("%s: enter Get Connection Stats\n", __FUNCTION__)); + + if (total_len <= 0) { + WL_ERR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len)); + goto error; + } + + bufsize = total_len; + if (bufsize < sizeof(struct connection_stats)) { + WL_ERR(("%s: not enough buffer size, provided=%u, requires=%zu\n", + __FUNCTION__, bufsize, + sizeof(struct connection_stats))); + goto error; + } + + output = (struct connection_stats *)command; + +#ifndef DISABLE_IF_COUNTERS + if ((if_stats = kmalloc(sizeof(*if_stats), GFP_KERNEL)) == NULL) { + WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); + goto error; + } + ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0, + (char *)if_stats, sizeof(*if_stats), NULL); + if (ret) { + WL_ERR(("%s: if_counters not supported ret=%d\n", + __FUNCTION__, ret)); + + /* In case if_stats IOVAR is not supported, get information from counters. */ +#endif /* DISABLE_IF_COUNTERS */ + if ((cnt = kmalloc(sizeof(*cnt), GFP_KERNEL)) == NULL) { + WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); + goto error; + } + + ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, + (char *)cnt, sizeof(wl_cnt_t), NULL); + if (ret) { + WL_ERR(("%s: wldev_iovar_getbuf() failed, ret=%d\n", + __FUNCTION__, ret)); + goto error; + } + + if (dtoh16(cnt->version) > WL_CNT_T_VERSION) { + WL_ERR(("%s: incorrect version of wl_cnt_t, expected=%u got=%u\n", + __FUNCTION__, WL_CNT_T_VERSION, cnt->version)); + goto error; + } + + output->txframe = dtoh32(cnt->txframe); + output->txbyte = dtoh32(cnt->txbyte); + output->txerror = dtoh32(cnt->txerror); + output->rxframe = dtoh32(cnt->rxframe); + output->rxbyte = dtoh32(cnt->rxbyte); + output->txfail = dtoh32(cnt->txfail); + output->txretry = dtoh32(cnt->txretry); + output->txretrie = dtoh32(cnt->txretrie); + output->txrts = dtoh32(cnt->txrts); + output->txnocts = dtoh32(cnt->txnocts); + output->txexptime = dtoh32(cnt->txexptime); +#ifndef DISABLE_IF_COUNTERS + } else { + /* Populate from if_stats. */ + if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) { + WL_ERR(("%s: incorrect version of wl_if_stats_t, expected=%u got=%u\n", + __FUNCTION__, WL_IF_STATS_T_VERSION, if_stats->version)); + goto error; + } + + output->txframe = (uint32)dtoh64(if_stats->txframe); + output->txbyte = (uint32)dtoh64(if_stats->txbyte); + output->txerror = (uint32)dtoh64(if_stats->txerror); + output->rxframe = (uint32)dtoh64(if_stats->rxframe); + output->rxbyte = (uint32)dtoh64(if_stats->rxbyte); + output->txfail = (uint32)dtoh64(if_stats->txfail); + output->txretry = (uint32)dtoh64(if_stats->txretry); + output->txretrie = (uint32)dtoh64(if_stats->txretrie); + if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) { + output->txexptime = (uint32)dtoh64(if_stats->txexptime); + output->txrts = (uint32)dtoh64(if_stats->txrts); + output->txnocts = (uint32)dtoh64(if_stats->txnocts); + } else { + output->txexptime = 0; + output->txrts = 0; + output->txnocts = 0; + } + } +#endif /* DISABLE_IF_COUNTERS */ + + /* link_speed is in kbps */ + ret = wldev_get_link_speed(dev, &link_speed); + if (ret || link_speed < 0) { + WL_ERR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n", + __FUNCTION__, ret, link_speed)); + goto error; + } + output->txrate = link_speed; + + /* Channel idle ratio. */ + if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) { + output->chan_idle = 0; + }; + + bytes_written = sizeof(struct connection_stats); + +error: +#ifndef DISABLE_IF_COUNTERS + if (if_stats) { + kfree(if_stats); + } +#endif /* DISABLE_IF_COUNTERS */ + if (cnt) { + kfree(cnt); + } + + return bytes_written; +} +#endif /* CONNECTION_STATISTICS */ + +static int +wl_android_set_pmk(struct net_device *dev, char *command, int total_len) +{ + uchar pmk[33]; + int error = 0; + char smbuf[WLC_IOCTL_SMLEN]; +#ifdef OKC_DEBUG + int i = 0; +#endif + + bzero(pmk, sizeof(pmk)); + memcpy((char *)pmk, command + strlen("SET_PMK "), 32); + error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL); + if (error) { + DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error)); + } +#ifdef OKC_DEBUG + DHD_ERROR(("PMK is ")); + for (i = 0; i < 32; i++) + DHD_ERROR(("%02X ", pmk[i])); + + DHD_ERROR(("\n")); +#endif + return error; +} + +static int +wl_android_okc_enable(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + char okc_enable = 0; + + okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0'; + error = wldev_iovar_setint(dev, "okc_enable", okc_enable); + if (error) { + DHD_ERROR(("Failed to %s OKC, error = %d\n", + okc_enable ? "enable" : "disable", error)); + } + + wldev_iovar_setint(dev, "ccx_enable", 0); + + return error; +} + + + +int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + int mode = 0; + + if (sscanf(command, "%*s %d", &mode) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + error = wldev_iovar_setint(dev, "roam_off", mode); + if (error) { + DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n", + __FUNCTION__, mode, error)); + return -1; + } + else + DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n", + __FUNCTION__, mode, error)); + return 0; +} + +int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len) +{ + char ie_buf[VNDR_IE_MAX_LEN]; + char *ioctl_buf = NULL; + char hex[] = "XX"; + char *pcmd = NULL; + int ielen = 0, datalen = 0, idx = 0, tot_len = 0; + vndr_ie_setbuf_t *vndr_ie = NULL; + s32 iecount; + uint32 pktflag; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + s32 err = BCME_OK; + + /* Check the VSIE (Vendor Specific IE) which was added. + * If exist then send IOVAR to delete it + */ + if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) { + return -EINVAL; + } + + pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1; + for (idx = 0; idx < DOT11_OUI_LEN; idx++) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16); + } + pcmd++; + while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16); + datalen++; + } + tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1); + vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags); + if (!vndr_ie) { + WL_ERR(("IE memory alloc failed\n")); + return -ENOMEM; + } + /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ + strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1); + vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Set the IE count - the buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32)); + + /* Set packet flag to indicate that BEACON's will contain this IE */ + pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG); + memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, + sizeof(u32)); + /* Set the IE ID */ + vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID; + + memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf, + DOT11_OUI_LEN); + memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, + &ie_buf[DOT11_OUI_LEN], datalen); + + ielen = DOT11_OUI_LEN + datalen; + vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen; + + ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + if (vndr_ie) { + kfree(vndr_ie); + } + return -ENOMEM; + } + memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */ + err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + + + if (err != BCME_OK) { + err = -EINVAL; + if (vndr_ie) { + kfree(vndr_ie); + } + } + else { + /* do NOT free 'vndr_ie' for the next process */ + wl_cfg80211_ibss_vsie_set_buffer(vndr_ie, tot_len); + } + + if (ioctl_buf) { + kfree(ioctl_buf); + } + + return err; +} + +#if defined(BCMFW_ROAM_ENABLE) +static int +wl_android_set_roampref(struct net_device *dev, char *command, int total_len) +{ + int error = 0; + char smbuf[WLC_IOCTL_SMLEN]; + uint8 buf[MAX_BUF_SIZE]; + uint8 *pref = buf; + char *pcmd; + int num_ucipher_suites = 0; + int num_akm_suites = 0; + wpa_suite_t ucipher_suites[MAX_NUM_SUITES]; + wpa_suite_t akm_suites[MAX_NUM_SUITES]; + int num_tuples = 0; + int total_bytes = 0; + int total_len_left; + int i, j; + char hex[] = "XX"; + + pcmd = command + strlen(CMD_SET_ROAMPREF) + 1; + total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1; + + num_akm_suites = simple_strtoul(pcmd, NULL, 16); + if (num_akm_suites > MAX_NUM_SUITES) { + DHD_ERROR(("too many AKM suites = %d\n", num_akm_suites)); + return -1; + } + + /* Increment for number of AKM suites field + space */ + pcmd += 3; + total_len_left -= 3; + + /* check to make sure pcmd does not overrun */ + if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE)) + return -1; + + memset(buf, 0, sizeof(buf)); + memset(akm_suites, 0, sizeof(akm_suites)); + memset(ucipher_suites, 0, sizeof(ucipher_suites)); + + /* Save the AKM suites passed in the command */ + for (i = 0; i < num_akm_suites; i++) { + /* Store the MSB first, as required by join_pref */ + for (j = 0; j < 4; j++) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + buf[j] = (uint8)simple_strtoul(hex, NULL, 16); + } + memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32)); + } + + total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); + num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); + /* Increment for number of cipher suites field + space */ + pcmd += 3; + total_len_left -= 3; + + if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE)) + return -1; + + /* Save the cipher suites passed in the command */ + for (i = 0; i < num_ucipher_suites; i++) { + /* Store the MSB first, as required by join_pref */ + for (j = 0; j < 4; j++) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + buf[j] = (uint8)simple_strtoul(hex, NULL, 16); + } + memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32)); + } + + /* Join preference for RSSI + * Type : 1 byte (0x01) + * Length : 1 byte (0x02) + * Value : 2 bytes (reserved) + */ + *pref++ = WL_JOIN_PREF_RSSI; + *pref++ = JOIN_PREF_RSSI_LEN; + *pref++ = 0; + *pref++ = 0; + + /* Join preference for WPA + * Type : 1 byte (0x02) + * Length : 1 byte (not used) + * Value : (variable length) + * reserved: 1 byte + * count : 1 byte (no of tuples) + * Tuple1 : 12 bytes + * akm[4] + * ucipher[4] + * mcipher[4] + * Tuple2 : 12 bytes + * Tuplen : 12 bytes + */ + num_tuples = num_akm_suites * num_ucipher_suites; + if (num_tuples != 0) { + if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) { + *pref++ = WL_JOIN_PREF_WPA; + *pref++ = 0; + *pref++ = 0; + *pref++ = (uint8)num_tuples; + total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + + (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples); + } else { + DHD_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__)); + return -1; + } + } else { + /* No WPA config, configure only RSSI preference */ + total_bytes = JOIN_PREF_RSSI_SIZE; + } + + /* akm-ucipher-mcipher tuples in the format required for join_pref */ + for (i = 0; i < num_ucipher_suites; i++) { + for (j = 0; j < num_akm_suites; j++) { + memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN); + pref += WPA_SUITE_LEN; + memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN); + pref += WPA_SUITE_LEN; + /* Set to 0 to match any available multicast cipher */ + memset(pref, 0, WPA_SUITE_LEN); + pref += WPA_SUITE_LEN; + } + } + + prhex("join pref", (uint8 *)buf, total_bytes); + error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL); + if (error) { + DHD_ERROR(("Failed to set join_pref, error = %d\n", error)); + } + return error; +} +#endif /* defined(BCMFW_ROAM_ENABLE */ + +static int +wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config) +{ + struct io_cfg *resume_cfg; + s32 ret; + + resume_cfg = kzalloc(sizeof(struct io_cfg), GFP_KERNEL); + if (!resume_cfg) + return -ENOMEM; + + if (config->iovar) { + ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param); + if (ret) { + DHD_ERROR(("%s: Failed to get current %s value\n", + __FUNCTION__, config->iovar)); + goto error; + } + + ret = wldev_iovar_setint(dev, config->iovar, config->param); + if (ret) { + DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, + config->iovar, config->param)); + goto error; + } + + resume_cfg->iovar = config->iovar; + } else { + resume_cfg->arg = kzalloc(config->len, GFP_KERNEL); + if (!resume_cfg->arg) { + ret = -ENOMEM; + goto error; + } + ret = wldev_ioctl(dev, config->ioctl, resume_cfg->arg, config->len, false); + if (ret) { + DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__, + config->ioctl)); + goto error; + } + ret = wldev_ioctl(dev, config->ioctl + 1, config->arg, config->len, true); + if (ret) { + DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, + config->iovar, config->param)); + goto error; + } + if (config->ioctl + 1 == WLC_SET_PM) + wl_cfg80211_update_power_mode(dev); + resume_cfg->ioctl = config->ioctl; + resume_cfg->len = config->len; + } + + list_add(&resume_cfg->list, head); + + return 0; +error: + kfree(resume_cfg->arg); + kfree(resume_cfg); + return ret; +} + +static void +wl_android_iolist_resume(struct net_device *dev, struct list_head *head) +{ + struct io_cfg *config; + struct list_head *cur, *q; + s32 ret = 0; + + list_for_each_safe(cur, q, head) { + config = list_entry(cur, struct io_cfg, list); + if (config->iovar) { + if (!ret) + ret = wldev_iovar_setint(dev, config->iovar, + config->param); + } else { + if (!ret) + ret = wldev_ioctl(dev, config->ioctl + 1, + config->arg, config->len, true); + if (config->ioctl + 1 == WLC_SET_PM) + wl_cfg80211_update_power_mode(dev); + kfree(config->arg); + } + list_del(cur); + kfree(config); + } +} + +static int +wl_android_set_miracast(struct net_device *dev, char *command, int total_len) +{ + int mode, val = 0; + int ret = 0; + struct io_cfg config; +#ifdef CHANGE_SCAN_TIME + int i; +#endif + + if (sscanf(command, "%*s %d", &mode) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + DHD_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode)); + + if (miracast_cur_mode == mode) + return 0; + + wl_android_iolist_resume(dev, &miracast_resume_list); + miracast_cur_mode = MIRACAST_MODE_OFF; + + switch (mode) { + case MIRACAST_MODE_SOURCE: + /* setting mchan_algo to platform specific value */ + config.iovar = "mchan_algo"; + + ret = wldev_ioctl(dev, WLC_GET_BCNPRD, &val, sizeof(int), false); + if (!ret && val > 100) { + config.param = 0; + DHD_ERROR(("%s: Connected station's beacon interval: " + "%d and set mchan_algo to %d \n", + __FUNCTION__, val, config.param)); + } + else { + config.param = MIRACAST_MCHAN_ALGO; + } + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + + /* setting mchan_bw to platform specific value */ + config.iovar = "mchan_bw"; + config.param = MIRACAST_MCHAN_BW; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + + /* setting apmdu to platform specific value */ + config.iovar = "ampdu_mpdu"; + config.param = MIRACAST_AMPDU_SIZE; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + /* FALLTROUGH */ + /* Source mode shares most configurations with sink mode. + * Fall through here to avoid code duplication + */ + case MIRACAST_MODE_SINK: + /* disable internal roaming */ + config.iovar = "roam_off"; + config.param = 1; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + /* tunr off pm */ + val = 0; + config.iovar = NULL; + config.ioctl = WLC_GET_PM; + config.arg = &val; + config.len = sizeof(int); + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + +#ifdef CHANGE_SCAN_TIME + for (int i = 0; i < sizeof(miracast_scan_time) / sizeof(miracast_scan_time[0]); i++) { + config.iovar = NULL; + config.ioctl = miracast_scan_time[i][0]; + config.arg = &miracast_scan_time[i][1]; + config.len = sizeof(int); + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) { + goto resume; + } + } +#endif + + break; + case MIRACAST_MODE_OFF: + default: + break; + } + miracast_cur_mode = mode; + + return 0; + +resume: + DHD_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret)); + wl_android_iolist_resume(dev, &miracast_resume_list); + return ret; +} + +#define NETLINK_OXYGEN 30 +#define AIBSS_BEACON_TIMEOUT 10 + +static struct sock *nl_sk = NULL; + +static void wl_netlink_recv(struct sk_buff *skb) +{ + WL_ERR(("netlink_recv called\n")); +} + +static int wl_netlink_init(void) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct netlink_kernel_cfg cfg = { + .input = wl_netlink_recv, + }; +#endif + + if (nl_sk != NULL) { + WL_ERR(("nl_sk already exist\n")); + return BCME_ERROR; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, + 0, wl_netlink_recv, NULL, THIS_MODULE); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg); +#else + nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg); +#endif + + if (nl_sk == NULL) { + WL_ERR(("nl_sk is not ready\n")); + return BCME_ERROR; + } + + return BCME_OK; +} + +static void wl_netlink_deinit(void) +{ + if (nl_sk) { + netlink_kernel_release(nl_sk); + nl_sk = NULL; + } +} + +s32 +wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size) +{ + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh = NULL; + int ret = -1; + + if (nl_sk == NULL) { + WL_ERR(("nl_sk was not initialized\n")); + goto nlmsg_failure; + } + + skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC); + if (skb == NULL) { + WL_ERR(("failed to allocate memory\n")); + goto nlmsg_failure; + } + + nlh = nlmsg_put(skb, 0, 0, 0, size, 0); + if (nlh == NULL) { + WL_ERR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n", + skb_tailroom(skb), nlmsg_total_size(size))); + dev_kfree_skb(skb); + goto nlmsg_failure; + } + + memcpy(nlmsg_data(nlh), data, size); + nlh->nlmsg_seq = seq; + nlh->nlmsg_type = type; + + /* netlink_unicast() takes ownership of the skb and frees it itself. */ + ret = netlink_unicast(nl_sk, skb, pid, 0); + WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret)); + +nlmsg_failure: + return ret; +} + +#ifdef WLAIBSS +static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len) +{ + int err = 0; + int retry = 0; + int pid = 0; + aibss_txfail_config_t txfail_config = {0, 0, 0, 0}; + char smbuf[WLC_IOCTL_SMLEN]; + + if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) { + WL_ERR(("Failed to get Parameter from : %s\n", command)); + return -1; + } + + /* set pid, and if the event was happened, let's send a notification through netlink */ + wl_cfg80211_set_txfail_pid(pid); + + /* If retry value is 0, it disables the functionality for TX Fail. */ + if (retry > 0) { + txfail_config.max_tx_retry = retry; + txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */ + } + txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0; + txfail_config.len = sizeof(txfail_config); + + err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config, + sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL); + WL_DBG(("retry=%d, pid=%d, err=%d\n", retry, pid, err)); + + return ((err == 0)?total_len:err); +} + +static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command, + int total_len, bool bAll) +{ + int error; + int bytes_written = 0; + void *buf = NULL; + bss_peer_list_info_t peer_list_info; + bss_peer_info_t *peer_info; + int i; + bool found = false; + struct ether_addr mac_ea; + + WL_DBG(("get ibss peer info(%s)\n", bAll?"true":"false")); + + if (!bAll) { + if (sscanf (command, "GETIBSSPEERINFO %02x:%02x:%02x:%02x:%02x:%02x", + (unsigned int *)&mac_ea.octet[0], (unsigned int *)&mac_ea.octet[1], + (unsigned int *)&mac_ea.octet[2], (unsigned int *)&mac_ea.octet[3], + (unsigned int *)&mac_ea.octet[4], (unsigned int *)&mac_ea.octet[5]) != 6) { + WL_DBG(("invalid MAC address\n")); + return -1; + } + } + + if ((buf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL)) == NULL) { + WL_ERR(("kmalloc failed\n")); + return -1; + } + + error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL); + if (unlikely(error)) { + WL_ERR(("could not get ibss peer info (%d)\n", error)); + kfree(buf); + return -1; + } + + memcpy(&peer_list_info, buf, sizeof(peer_list_info)); + peer_list_info.version = htod16(peer_list_info.version); + peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len); + peer_list_info.count = htod32(peer_list_info.count); + + WL_DBG(("ver:%d, len:%d, count:%d\n", peer_list_info.version, + peer_list_info.bss_peer_info_len, peer_list_info.count)); + + if (peer_list_info.count > 0) { + if (bAll) + bytes_written += sprintf(&command[bytes_written], "%u ", + peer_list_info.count); + + peer_info = (bss_peer_info_t *) ((void *)buf + BSS_PEER_LIST_INFO_FIXED_LEN); + + + for (i = 0; i < peer_list_info.count; i++) { + + WL_DBG(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi, + peer_info->tx_rate, peer_info->rx_rate)); + + if (!bAll && + memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) { + found = true; + } + + if (bAll || found) { + bytes_written += sprintf(&command[bytes_written], MACF, + ETHER_TO_MACF(peer_info->ea)); + bytes_written += sprintf(&command[bytes_written], " %u %d ", + peer_info->tx_rate/1000, peer_info->rssi); + } + + if (found) + break; + + peer_info = (bss_peer_info_t *)((void *)peer_info+sizeof(bss_peer_info_t)); + } + } + else { + WL_ERR(("could not get ibss peer info : no item\n")); + } + bytes_written += sprintf(&command[bytes_written], "%s", "\0"); + + WL_DBG(("command(%u):%s\n", total_len, command)); + WL_DBG(("bytes_written:%d\n", bytes_written)); + + kfree(buf); + return bytes_written; +} + +int wl_android_set_ibss_routetable(struct net_device *dev, char *command, int total_len) +{ + + char *pcmd = command; + char *str = NULL; + + ibss_route_tbl_t *route_tbl = NULL; + char *ioctl_buf = NULL; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + s32 err = BCME_OK; + uint32 route_tbl_len; + uint32 entries; + char *endptr; + uint32 i = 0; + struct ipv4_addr dipaddr; + struct ether_addr ea; + + route_tbl_len = sizeof(ibss_route_tbl_t) + + (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t); + route_tbl = (ibss_route_tbl_t *)kzalloc(route_tbl_len, kflags); + if (!route_tbl) { + WL_ERR(("Route TBL alloc failed\n")); + return -ENOMEM; + } + ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + if (route_tbl) { + kfree(route_tbl); + } + return -ENOMEM; + } + memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); + + /* drop command */ + str = bcmstrtok(&pcmd, " ", NULL); + + /* get count */ + str = bcmstrtok(&pcmd, " ", NULL); + if (!str) { + WL_ERR(("Invalid number parameter %s\n", str)); + err = -EINVAL; + goto exit; + } + entries = bcm_strtoul(str, &endptr, 0); + if (*endptr != '\0') { + WL_ERR(("Invalid number parameter %s\n", str)); + err = -EINVAL; + goto exit; + } + WL_INFO(("Routing table count:%d\n", entries)); + route_tbl->num_entry = entries; + + for (i = 0; i < entries; i++) { + str = bcmstrtok(&pcmd, " ", NULL); + if (!str || !bcm_atoipv4(str, &dipaddr)) { + WL_ERR(("Invalid ip string %s\n", str)); + err = -EINVAL; + goto exit; + } + + + str = bcmstrtok(&pcmd, " ", NULL); + if (!str || !bcm_ether_atoe(str, &ea)) { + WL_ERR(("Invalid ethernet string %s\n", str)); + err = -EINVAL; + goto exit; + } + bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN); + bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN); + } + + route_tbl_len = sizeof(ibss_route_tbl_t) + + ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t)); + err = wldev_iovar_setbuf(dev, "ibss_route_tbl", + route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (err != BCME_OK) { + WL_ERR(("Fail to set iovar %d\n", err)); + err = -EINVAL; + } + +exit: + if (route_tbl) + kfree(route_tbl); + if (ioctl_buf) + kfree(ioctl_buf); + return err; + +} + +int wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len) +{ + char *pcmd = command; + char *str = NULL, *endptr = NULL; + int category[4]; + int tid2category[NUMPRIO] = {2, 3, 3, 2, 1, 1, 0, 0}; + struct ampdu_tid_control_mode control; + char smbuf[WLC_IOCTL_SMLEN]; + int idx; + int err = 0; + + WL_DBG(("set ibss ampdu:%s\n", command)); + + /* acquire parameters */ + /* drop command */ + str = bcmstrtok(&pcmd, " ", NULL); + + for (idx = 0; idx < 4; idx++) { + str = bcmstrtok(&pcmd, " ", NULL); + if (!str) { + WL_ERR(("Invalid parameter : %s\n", pcmd)); + return -EINVAL; + } + category[idx] = bcm_strtoul(str, &endptr, 0); + if (*endptr != '\0') { + WL_ERR(("Invalid number format %s\n", str)); + return -EINVAL; + } + } + sprintf(control.mode_name, "AIBSS"); + for (idx = 0; idx < NUMPRIO; idx++) { + control.control[idx].tid = idx; + control.control[idx].enable = category[tid2category[idx]]; + } + + err = wldev_iovar_setbuf(dev, "ampdu_tid_mode", (void *) &control, + sizeof(struct ampdu_tid_control_mode), smbuf, WLC_IOCTL_SMLEN, NULL); + return ((err == 0)?total_len:err); +} + +int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len) +{ + char *pcmd = command; + char *str = NULL; + int txchain, rxchain; + int err = 0; + + WL_DBG(("set ibss antenna:%s\n", command)); + + /* acquire parameters */ + /* drop command */ + str = bcmstrtok(&pcmd, " ", NULL); + + /* TX chain */ + str = bcmstrtok(&pcmd, " ", NULL); + if (!str) { + WL_ERR(("Invalid parameter : %s\n", pcmd)); + return -EINVAL; + } + txchain = bcm_atoi(str); + + /* RX chain */ + str = bcmstrtok(&pcmd, " ", NULL); + if (!str) { + WL_ERR(("Invalid parameter : %s\n", pcmd)); + return -EINVAL; + } + rxchain = bcm_atoi(str); + + err = wldev_iovar_setint(dev, "txchain", txchain); + if (err != 0) + return err; + err = wldev_iovar_setint(dev, "rxchain", rxchain); + return ((err == 0)?total_len:err); +} +#endif /* WLAIBSS */ + +int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len) +{ + wl_mkeep_alive_pkt_t mkeep_alive_pkt; + int ret; + uint period_msec = 0; + char *buf; + + if (extra == NULL) + { + DHD_ERROR(("%s: extra is NULL\n", __FUNCTION__)); + return -1; + } + if (sscanf(extra, "%d", &period_msec) != 1) + { + DHD_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__)); + return -EINVAL; + } + DHD_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec)); + + memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); + + mkeep_alive_pkt.period_msec = period_msec; + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + + /* Setup keep alive zero for null packet generation */ + mkeep_alive_pkt.keep_alive_id = 0; + mkeep_alive_pkt.len_bytes = 0; + + buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + if (!buf) { + DHD_ERROR(("%s: buffer alloc failed\n", __FUNCTION__)); + return BCME_NOMEM; + } + ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt, + WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL); + if (ret < 0) + DHD_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret)); + else + DHD_TRACE(("%s:keep_alive set ok\n", __FUNCTION__)); + kfree(buf); + return ret; +} + +int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) +{ +#define PRIVATE_COMMAND_MAX_LEN 8192 +#define PRIVATE_COMMAND_DEF_LEN 4096 + int ret = 0; + char *command = NULL; + int bytes_written = 0; + android_wifi_priv_cmd priv_cmd; + int buf_size = 0; + + net_os_wake_lock(net); + + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto exit; + } + + if (!ifr->ifr_data) { + ret = -EINVAL; + goto exit; + } + +#ifdef CONFIG_COMPAT + if (is_compat_task()) { + compat_android_wifi_priv_cmd compat_priv_cmd; + if (copy_from_user(&compat_priv_cmd, ifr->ifr_data, + sizeof(compat_android_wifi_priv_cmd))) { + ret = -EFAULT; + goto exit; + + } + priv_cmd.buf = compat_ptr(compat_priv_cmd.buf); + priv_cmd.used_len = compat_priv_cmd.used_len; + priv_cmd.total_len = compat_priv_cmd.total_len; + } else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) { + ret = -EFAULT; + goto exit; + } + } + if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) { + DHD_ERROR(("%s: invalid length of private command : %d\n", + __FUNCTION__, priv_cmd.total_len)); + ret = -EINVAL; + goto exit; + } + + buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN); + command = kmalloc((buf_size + 1), GFP_KERNEL); + + if (!command) + { + DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__)); + ret = -ENOMEM; + goto exit; + } + if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { + ret = -EFAULT; + goto exit; + } + command[priv_cmd.total_len] = '\0'; + + DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); + + if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { + DHD_INFO(("%s, Received regular START command\n", __FUNCTION__)); + bytes_written = wl_android_wifi_on(net); + } + else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) { + bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len); + } + + if (!g_wifi_on) { + DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n", + __FUNCTION__, command, ifr->ifr_name)); + ret = 0; + goto exit; + } + + if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) { + bytes_written = wl_android_wifi_off(net); + } + else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { + /* TBD: SCAN-ACTIVE */ + } + else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) { + /* TBD: SCAN-PASSIVE */ + } + else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) { + bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { + bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len); + } +#ifdef PKT_FILTER_SUPPORT + else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) { + bytes_written = net_os_enable_packet_filter(net, 1); + } + else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) { + bytes_written = net_os_enable_packet_filter(net, 0); + } + else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) { + int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; + bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num); + } + else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) { + int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; + bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); + } +#endif /* PKT_FILTER_SUPPORT */ + else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { + /* TBD: BTCOEXSCAN-START */ + } + else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) { + /* TBD: BTCOEXSCAN-STOP */ + } + else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { +#ifdef WL_CFG80211 + void *dhdp = wl_cfg80211_get_dhdp(); + bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command); +#else +#ifdef PKT_FILTER_SUPPORT + uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; + + if (mode == 1) + net_os_enable_packet_filter(net, 0); /* DHCP starts */ + else + net_os_enable_packet_filter(net, 1); /* DHCP ends */ +#endif /* PKT_FILTER_SUPPORT */ +#endif /* WL_CFG80211 */ + } + else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { + bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { + bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { + uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; + bytes_written = wldev_set_band(net, band); + } + else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { + bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); + } +#ifdef WL_CFG80211 + /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ + else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { + char *country_code = command + strlen(CMD_COUNTRY) + 1; +#ifdef CUSTOMER_HW5 + /* Customer_hw5 want to keep connections */ + bytes_written = wldev_set_country(net, country_code, true, false); +#else + bytes_written = wldev_set_country(net, country_code, true, true); +#endif + } +#endif /* WL_CFG80211 */ + + +#ifdef PNO_SUPPORT + else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { + bytes_written = dhd_dev_pno_stop_for_ssid(net); + } +#ifndef WL_SCHED_SCAN + else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { + bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len); + } +#endif /* !WL_SCHED_SCAN */ + else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { + int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; + bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net); + } + else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) { + bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len); + } +#endif /* PNO_SUPPORT */ + else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { + bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) { + int skip = strlen(CMD_P2P_SET_NOA) + 1; + bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, + priv_cmd.total_len - skip); + } +#ifdef WL_NAN + else if (strnicmp(command, CMD_NAN, strlen(CMD_NAN)) == 0) { + bytes_written = wl_cfg80211_nan_cmd_handler(net, command, + priv_cmd.total_len); + } +#endif /* WL_NAN */ +#if !defined WL_ENABLE_P2P_IF + else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { + bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); + } +#endif /* WL_ENABLE_P2P_IF */ + else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { + int skip = strlen(CMD_P2P_SET_PS) + 1; + bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, + priv_cmd.total_len - skip); + } +#ifdef WL_CFG80211 + else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE, + strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) { + int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3; + bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, + priv_cmd.total_len - skip, *(command + skip - 2) - '0'); + } +#ifdef WLFBT + else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) { + wl_cfg80211_get_fbt_key(command); + bytes_written = FBT_KEYLEN; + } +#endif /* WLFBT */ +#endif /* WL_CFG80211 */ + else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) + bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) + bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); +#ifdef BCMCCX + else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) { + bytes_written = wl_android_get_cckm_rn(net, command); + } + else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) { + bytes_written = wl_android_set_cckm_krk(net, command); + } + else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) { + bytes_written = wl_android_get_assoc_res_ies(net, command); + } +#endif /* BCMCCX */ +#if defined(WL_SUPPORT_AUTO_CHANNEL) + else if (strnicmp(command, CMD_GET_BEST_CHANNELS, + strlen(CMD_GET_BEST_CHANNELS)) == 0) { + bytes_written = wl_cfg80211_get_best_channels(net, command, + priv_cmd.total_len); + } +#endif /* WL_SUPPORT_AUTO_CHANNEL */ + else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) { + int skip = strlen(CMD_HAPD_MAC_FILTER) + 1; + wl_android_set_mac_address_filter(net, (const char*)command+skip); + } + else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0) + bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len); +#if defined(BCMFW_ROAM_ENABLE) + else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) { + bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len); + } +#endif /* BCMFW_ROAM_ENABLE */ + else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) + bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0) + bytes_written = wl_android_set_ibss_beacon_ouidata(net, + command, priv_cmd.total_len); +#ifdef WLAIBSS + else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT, + strlen(CMD_SETIBSSTXFAILEVENT)) == 0) + bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL, + strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0) + bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, + TRUE); + else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO, + strlen(CMD_GET_IBSS_PEER_INFO)) == 0) + bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, + FALSE); + else if (strnicmp(command, CMD_SETIBSSROUTETABLE, + strlen(CMD_SETIBSSROUTETABLE)) == 0) + bytes_written = wl_android_set_ibss_routetable(net, command, + priv_cmd.total_len); + else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0) + bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0) + bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len); +#endif /* WLAIBSS */ + else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) { + int skip = strlen(CMD_KEEP_ALIVE) + 1; + bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip); + } + else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) { + int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0'; + bytes_written = wl_cfg80211_enable_roam_offload(net, enable); + } +#ifdef CONNECTION_STATISTICS + else if (strnicmp(command, CMD_GET_CONNECTION_STATS, + strlen(CMD_GET_CONNECTION_STATS)) == 0) { + bytes_written = wl_android_get_connection_stats(net, command, + priv_cmd.total_len); + } +#endif + else { + DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); + bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); + } + + if (bytes_written >= 0) { + if ((bytes_written == 0) && (priv_cmd.total_len > 0)) + command[0] = '\0'; + if (bytes_written >= priv_cmd.total_len) { + DHD_ERROR(("%s: err. bytes_written:%d >= buf_size:%d \n", + __FUNCTION__, bytes_written, buf_size)); + ret = BCME_BUFTOOSHORT; + goto exit; + } + bytes_written++; + priv_cmd.used_len = bytes_written; + if (copy_to_user(priv_cmd.buf, command, bytes_written)) { + DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); + ret = -EFAULT; + } + } + else { + ret = bytes_written; + } + +exit: + net_os_wake_unlock(net); + kfree(command); + + return ret; +} + +int wl_android_init(void) +{ + int ret = 0; + +#ifdef ENABLE_INSMOD_NO_FW_LOAD + dhd_download_fw_on_driverload = FALSE; +#endif /* ENABLE_INSMOD_NO_FW_LOAD */ +#if defined(CUSTOMER_HW2) + if (!iface_name[0]) { + memset(iface_name, 0, IFNAMSIZ); + bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); + } +#endif + + wl_netlink_init(); + + return ret; +} + +int wl_android_exit(void) +{ + int ret = 0; + struct io_cfg *cur, *q; + + wl_netlink_deinit(); + + list_for_each_entry_safe(cur, q, &miracast_resume_list, list) { + list_del(&cur->list); + kfree(cur); + } + + return ret; +} + +void wl_android_post_init(void) +{ + +#ifdef ENABLE_4335BT_WAR + bcm_bt_unlock(lock_cookie_wifi); + printk("%s: btlock released\n", __FUNCTION__); +#endif /* ENABLE_4335BT_WAR */ + + if (!dhd_download_fw_on_driverload) + g_wifi_on = FALSE; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.h new file mode 100644 index 000000000000..fb3cba9cf17b --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.h @@ -0,0 +1,72 @@ +/* + * Linux cfg80211 driver - Android related functions + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_android.h 516345 2014-11-19 11:58:57Z $ + */ + +#include +#include +#include + +/* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL + * automatically + */ +#if defined(WL_NAN) +#define WL_GENL +#endif + + + +/** + * Android platform dependent functions, feel free to add Android specific functions here + * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd + * or cfg, define them as static in wl_android.c + */ + +/** + * wl_android_init will be called from module init function (dhd_module_init now), similarly + * wl_android_exit will be called from module exit function (dhd_module_cleanup now) + */ +int wl_android_init(void); +int wl_android_exit(void); +void wl_android_post_init(void); +int wl_android_wifi_on(struct net_device *dev); +int wl_android_wifi_off(struct net_device *dev); +int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); + +s32 wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size); + +/* hostap mac mode */ +#define MACLIST_MODE_DISABLED 0 +#define MACLIST_MODE_DENY 1 +#define MACLIST_MODE_ALLOW 2 + +/* max number of assoc list */ +#define MAX_NUM_OF_ASSOCLIST 64 + +/* max number of mac filter list + * restrict max number to 10 as maximum cmd string size is 255 + */ +#define MAX_NUM_MAC_FILT 10 + +int wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist); diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c new file mode 100644 index 000000000000..3e100e3730b3 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -0,0 +1,13198 @@ +/* + * Linux cfg80211 driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.c 701450 2017-05-25 02:10:23Z $ + */ +/* */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef PNO_SUPPORT +#include +#endif /* PNO_SUPPORT */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef WL_NAN +#include +#endif /* WL_NAN */ +#ifdef PROP_TXSTATUS +#include +#endif + +#include +#ifdef WL11U +#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) +#error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \ + according to Kernel version and is supported only in Android-JB +#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ +#endif /* WL11U */ + +#ifdef BCMWAPI_WPI +/* these items should evetually go into wireless.h of the linux system headfile dir */ +#ifndef IW_ENCODE_ALG_SM4 +#define IW_ENCODE_ALG_SM4 0x20 +#endif + +#ifndef IW_AUTH_WAPI_ENABLED +#define IW_AUTH_WAPI_ENABLED 0x20 +#endif + +#ifndef IW_AUTH_WAPI_VERSION_1 +#define IW_AUTH_WAPI_VERSION_1 0x00000008 +#endif + +#ifndef IW_AUTH_CIPHER_SMS4 +#define IW_AUTH_CIPHER_SMS4 0x00000020 +#endif + +#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK +#define IW_AUTH_KEY_MGMT_WAPI_PSK 4 +#endif + +#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT +#define IW_AUTH_KEY_MGMT_WAPI_CERT 8 +#endif +#endif /* BCMWAPI_WPI */ + +#ifdef BCMWAPI_WPI +#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) +#endif /* BCMWAPI_WPI */ + +static struct device *cfg80211_parent_dev = NULL; +/* g_bcm_cfg should be static. Do not change */ +static struct bcm_cfg80211 *g_bcm_cfg = NULL; +u32 wl_dbg_level = WL_DBG_ERR; + +#define MAX_WAIT_TIME 1500 + +#ifdef VSDB +/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */ +#define DEFAULT_SLEEP_TIME_VSDB 120 +#define OFF_CHAN_TIME_THRESHOLD_MS 200 +#define AF_RETRY_DELAY_TIME 40 + +/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */ +#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \ + do { \ + if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \ + wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \ + OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \ + } \ + } while (0) +#else /* VSDB */ +/* if not VSDB, do nothing */ +#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) +#endif /* VSDB */ + +#ifdef WL_CFG80211_SYNC_GON +#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) \ + (wl_get_drv_status_all(cfg, SENDING_ACT_FRM) || \ + wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) +#else +#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) wl_get_drv_status_all(cfg, SENDING_ACT_FRM) +#endif /* WL_CFG80211_SYNC_GON */ +#define WL_IS_P2P_DEV_EVENT(e) ((e->emsg.ifidx == 0) && \ + (e->emsg.bsscfgidx == P2PAPI_BSSCFG_DEVICE)) + +#define DNGL_FUNC(func, parameters) func parameters +#define COEX_DHCP + +#define WLAN_EID_SSID 0 +#define CH_MIN_5G_CHANNEL 34 +#define CH_MIN_2G_CHANNEL 1 + +#ifdef WLAIBSS +enum abiss_event_type { + AIBSS_EVENT_TXFAIL +}; +#endif + +enum rmc_event_type { + RMC_EVENT_NONE, + RMC_EVENT_LEADER_CHECK_FAIL +}; + +/* This is to override regulatory domains defined in cfg80211 module (reg.c) + * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN + * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165). + * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels. + * All the chnages in world regulatory domain are to be done here. + */ +static const struct ieee80211_regdomain brcm_regdom = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + /* IEEE 802.11b/g, channels 1..11 */ + REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), + /* If any */ + /* IEEE 802.11 channel 14 - Only JP enables + * this and for 802.11b only + */ + REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), + /* IEEE 802.11a, channel 36..64 */ + REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), + /* IEEE 802.11a, channel 100..165 */ + REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) +/* + * Possible interface combinations supported by driver + * + * ADHOC Mode - #ADHOC <= 1 on channels = 1 + * SoftAP Mode - #AP <= 1 on channels = 1 + * STA + P2P Mode - #STA <= 2, #{P2P-GO, P2P-client} <= 1, #P2P-device <= 1 + * on channels = 2 + */ +static const struct ieee80211_iface_limit common_if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, + { + /* + * During P2P-GO removal, P2P-GO is first changed to STA and later only + * removed. So setting maximum possible number of STA interfaces according + * to kernel version. + * + * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x) + * linux-3.8 and above - max:2 (wlan0 + group removal of p2p-wlan0-x) + */ +#ifdef WL_ENABLE_P2P_IF + .max = 3, +#else + .max = 2, +#endif /* WL_ENABLE_P2P_IF */ + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +#if defined(WL_CFG80211_P2P_DEV_IF) + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +#endif /* WL_CFG80211_P2P_DEV_IF */ + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC), + }, +}; +#ifdef BCM4330_CHIP +#define NUM_DIFF_CHANNELS 1 +#else +#define NUM_DIFF_CHANNELS 2 +#endif +static const struct ieee80211_iface_combination +common_iface_combinations[] = { + { + .num_different_channels = NUM_DIFF_CHANNELS, + .max_interfaces = 4, + .limits = common_if_limits, + .n_limits = ARRAY_SIZE(common_if_limits), + }, +}; +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ + +/* Data Element Definitions */ +#define WPS_ID_CONFIG_METHODS 0x1008 +#define WPS_ID_REQ_TYPE 0x103A +#define WPS_ID_DEVICE_NAME 0x1011 +#define WPS_ID_VERSION 0x104A +#define WPS_ID_DEVICE_PWD_ID 0x1012 +#define WPS_ID_REQ_DEV_TYPE 0x106A +#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053 +#define WPS_ID_PRIM_DEV_TYPE 0x1054 + +/* Device Password ID */ +#define DEV_PW_DEFAULT 0x0000 +#define DEV_PW_USER_SPECIFIED 0x0001, +#define DEV_PW_MACHINE_SPECIFIED 0x0002 +#define DEV_PW_REKEY 0x0003 +#define DEV_PW_PUSHBUTTON 0x0004 +#define DEV_PW_REGISTRAR_SPECIFIED 0x0005 + +/* Config Methods */ +#define WPS_CONFIG_USBA 0x0001 +#define WPS_CONFIG_ETHERNET 0x0002 +#define WPS_CONFIG_LABEL 0x0004 +#define WPS_CONFIG_DISPLAY 0x0008 +#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010 +#define WPS_CONFIG_INT_NFC_TOKEN 0x0020 +#define WPS_CONFIG_NFC_INTERFACE 0x0040 +#define WPS_CONFIG_PUSHBUTTON 0x0080 +#define WPS_CONFIG_KEYPAD 0x0100 +#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280 +#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480 +#define WPS_CONFIG_VIRT_DISPLAY 0x2008 +#define WPS_CONFIG_PHY_DISPLAY 0x4008 + +#define PM_BLOCK 1 +#define PM_ENABLE 0 + +#ifdef BCMCCX +#ifndef WLAN_AKM_SUITE_CCKM +#define WLAN_AKM_SUITE_CCKM 0x00409600 +#endif +#define DOT11_LEAP_AUTH 0x80 /* LEAP auth frame paylod constants */ +#endif /* BCMCCX */ + +#ifdef MFP +#define WL_AKM_SUITE_MFP_1X 0x000FAC05 +#define WL_AKM_SUITE_MFP_PSK 0x000FAC06 +#define WL_MFP_CAPABLE 0x1 +#define WL_MFP_REQUIRED 0x2 +#endif /* MFP */ + +#ifndef IBSS_COALESCE_ALLOWED +#define IBSS_COALESCE_ALLOWED 0 +#endif + +#ifndef IBSS_INITIAL_SCAN_ALLOWED +#define IBSS_INITIAL_SCAN_ALLOWED 0 +#endif + +#define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */ +/* + * cfg80211_ops api/callback list + */ +static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, + const struct ether_addr *sa, const struct ether_addr *bssid, + u8 **pheader, u32 *body_len, u8 *pbody); +static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request, + struct cfg80211_ssid *this_ssid); +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); +#else +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request); +#endif /* WL_CFG80211_P2P_DEV_IF */ +static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); +static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params); +static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev); +static s32 wl_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, u8 *mac, + struct station_info *sinfo); +static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, bool enabled, + s32 timeout); +static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code); +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 mbm); +#else +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, s32 dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, s32 *dbm); +#else +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ +static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_idx, bool unicast, bool multicast); +static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + struct key_params *params); +static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr); +static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + void *cookie, void (*callback) (void *cookie, + struct key_params *params)); +static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx); +static s32 wl_cfg80211_resume(struct wiphy *wiphy); +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) +static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + bcm_struct_cfgdev *cfgdev, u64 cookie); +static s32 wl_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *ndev, u8* mac_addr); +static s32 wl_cfg80211_change_station(struct wiphy *wiphy, + struct net_device *dev, u8 *mac, struct station_parameters *params); +#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) +static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); +#else +static s32 wl_cfg80211_suspend(struct wiphy *wiphy); +#endif +static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa); +static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa); +static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, + struct net_device *dev); +static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg); +#if defined(WL_ABORT_SCAN) +static void wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *dev); +#endif /* WL_ABORT_SCAN */ +static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, + struct net_device *ndev, bool aborted, bool fw_abort); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) +#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) +static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, + u32 peer_capability, const u8 *data, size_t len); +#else +static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data, + size_t len); +#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ +static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, enum nl80211_tdls_operation oper); +#endif +#ifdef WL_SCHED_SCAN +static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev); +#endif + +/* + * event & event Q handlers for cfg80211 interfaces + */ +static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg); +static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg); +static s32 wl_event_handler(void *data); +static void wl_init_eq(struct bcm_cfg80211 *cfg); +static void wl_flush_eq(struct bcm_cfg80211 *cfg); +static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg); +static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags); +static void wl_init_eq_lock(struct bcm_cfg80211 *cfg); +static void wl_init_event_handler(struct bcm_cfg80211 *cfg); +static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg); +static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type, + const wl_event_msg_t *msg, void *data); +static void wl_put_event(struct wl_event_q *e); +static void wl_wakeup_event(struct bcm_cfg80211 *cfg); +static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data, bool completed); +static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#ifdef WL_SCHED_SCAN +static s32 +wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +#endif /* WL_SCHED_SCAN */ +#ifdef PNO_SUPPORT +static s32 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* PNO_SUPPORT */ +#ifdef GSCAN_SUPPORT +static s32 wl_notify_gscan_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* GSCAN_SUPPORT */ +#ifdef RSSI_MONITOR_SUPPORT +static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* RSSI_MONITOR_SUPPORT */ +static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, + enum wl_status state, bool set); + +#ifdef DHD_LOSSLESS_ROAMING +static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg); +#endif /* DHD_LOSSLESS_ROAMING */ + + +#ifdef WLTDLS +static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* WLTDLS */ +/* + * register/deregister parent device + */ +static void wl_cfg80211_clear_parent_dev(void); + +/* + * ioctl utilites + */ + +/* + * cfg80211 set_wiphy_params utilities + */ +static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); +static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold); +static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); + +/* + * cfg profile utilities + */ +static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data, s32 item); +static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item); +static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev); + +/* + * cfg80211 connect utilites + */ +static s32 wl_set_wpa_version(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_auth_type(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_set_cipher(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_key_mgmt(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_set_sharedkey(struct net_device *dev, + struct cfg80211_connect_params *sme); +#ifdef BCMWAPI_WPI +static s32 wl_set_set_wapi_ie(struct net_device *dev, + struct cfg80211_connect_params *sme); +#endif +static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev); +static void wl_ch_to_chanspec(int ch, + struct wl_join_params *join_params, size_t *join_params_size); + +/* + * information element utilities + */ +static void wl_rst_ie(struct bcm_cfg80211 *cfg); +static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v); +static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam); +static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size); +static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size); +static u32 wl_get_ielen(struct bcm_cfg80211 *cfg); +#ifdef MFP +static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa); +#endif + +#ifdef WL11U +bcm_tlv_t * +wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); +static s32 +wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, + uint8 ie_id, uint8 *data, uint8 data_len); +#endif /* WL11U */ + +static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data); +static void wl_free_wdev(struct bcm_cfg80211 *cfg); +#ifdef CONFIG_CFG80211_INTERNAL_REGDB +static int +wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); +#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ + +static s32 wl_inform_bss(struct bcm_cfg80211 *cfg); +static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam); +static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam); +static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); +s32 wl_cfg80211_channel_to_freq(u32 channel); + + +static void wl_cfg80211_work_handler(struct work_struct *work); +static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, + struct key_params *params); +/* + * key indianess swap utilities + */ +static void swap_key_from_BE(struct wl_wsec_key *key); +static void swap_key_to_BE(struct wl_wsec_key *key); + +/* + * bcm_cfg80211 memory init/deinit utilities + */ +static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg); +static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg); + +static void wl_delay(u32 ms); + +/* + * ibss mode utilities + */ +static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev); +static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg); + +/* + * link up/down , default configuration utilities + */ +static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg); +static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg); +static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); +static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, + struct net_device *ndev); +static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); +static void wl_link_up(struct bcm_cfg80211 *cfg); +static void wl_link_down(struct bcm_cfg80211 *cfg); +static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype); +static void wl_init_conf(struct wl_conf *conf); +static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info, + struct net_device* ndev); + +int wl_cfg80211_get_ioctl_version(void); + +/* + * find most significant bit set + */ +static __used u32 wl_find_msb(u16 bit16); + +/* + * rfkill support + */ +static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup); +static int wl_rfkill_set(void *data, bool blocked); +#ifdef DEBUGFS_CFG80211 +static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg); +static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg); +#endif + +static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel, + int nprobes, int *out_params_size); +static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role); + +#ifdef WL_CFG80211_ACL +/* ACL */ +static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, + const struct cfg80211_acl_data *acl); +#endif /* WL_CFG80211_ACL */ + +/* + * Some external functions, TODO: move them to dhd_linux.h + */ +int dhd_add_monitor(char *name, struct net_device **new_ndev); +int dhd_del_monitor(struct net_device *ndev); +int dhd_monitor_init(void *dhd_pub); +int dhd_monitor_uninit(void); +int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); + + +static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const struct ether_addr *bssid); + + +#ifdef RSSI_OFFSET +static s32 wl_rssi_offset(s32 rssi) +{ + rssi += RSSI_OFFSET; + if (rssi > 0) + rssi = 0; + return rssi; +} +#else +#define wl_rssi_offset(x) x +#endif + +#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ + (akm) == RSN_AKM_UNSPECIFIED || \ + (akm) == RSN_AKM_PSK) + + +extern int dhd_wait_pend8021x(struct net_device *dev); +#ifdef PROP_TXSTATUS_VSDB +extern int disable_proptx; +#endif /* PROP_TXSTATUS_VSDB */ + +#if (WL_DBG_LEVEL > 0) +#define WL_DBG_ESTR_MAX 50 +static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { + "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND", + "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC", + "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END", + "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM", + "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH", + "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND", + "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", + "PFN_NET_LOST", + "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", + "IBSS_ASSOC", + "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT", + "PROBREQ_MSG", + "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", + "EXCEEDED_MEDIUM_TIME", "ICV_ERROR", + "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE", + "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE", + "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG", + "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND", + "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED", + "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT", + "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE", + "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP", + "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE" +}; +#endif /* WL_DBG_LEVEL */ + +#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(DOT11_RATE_1M, 0), + RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_6M, 0), + RATETAB_ENT(DOT11_RATE_9M, 0), + RATETAB_ENT(DOT11_RATE_12M, 0), + RATETAB_ENT(DOT11_RATE_18M, 0), + RATETAB_ENT(DOT11_RATE_24M, 0), + RATETAB_ENT(DOT11_RATE_36M, 0), + RATETAB_ENT(DOT11_RATE_48M, 0), + RATETAB_ENT(DOT11_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(144, 0), + CHAN5G(149, 0), CHAN5G(153, 0), + CHAN5G(157, 0), CHAN5G(161, 0), + CHAN5G(165, 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 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, +#ifdef BCMWAPI_WPI + WLAN_CIPHER_SUITE_SMS4, +#endif +#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK) + WLAN_CIPHER_SUITE_PMK, +#endif +}; + + +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) +static int maxrxpktglom = 0; +#endif + +/* IOCtl version read from targeted driver */ +static int ioctl_version; +#ifdef DEBUGFS_CFG80211 +#define S_SUBLOGLEVEL 20 +static const struct { + u32 log_level; + char *sublogname; +} sublogname_map[] = { + {WL_DBG_ERR, "ERR"}, + {WL_DBG_INFO, "INFO"}, + {WL_DBG_DBG, "DBG"}, + {WL_DBG_SCAN, "SCAN"}, + {WL_DBG_TRACE, "TRACE"}, + {WL_DBG_P2P_ACTION, "P2PACTION"} +}; +#endif + + +static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg, bool add_remove, + enum wl_handler_del_type type) +{ + if (cfg == NULL) + return; + + if (cfg->pm_enable_work_on) { + if (add_remove) { + schedule_delayed_work(&cfg->pm_enable_work, + msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); + } else { + cancel_delayed_work_sync(&cfg->pm_enable_work); + switch (type) { + case WL_HANDLER_MAINTAIN: + schedule_delayed_work(&cfg->pm_enable_work, + msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); + break; + case WL_HANDLER_PEND: + schedule_delayed_work(&cfg->pm_enable_work, + msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT*2)); + break; + case WL_HANDLER_DEL: + default: + cfg->pm_enable_work_on = false; + break; + } + } + } +} + +/* Return a new chanspec given a legacy chanspec + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_from_legacy(chanspec_t legacy_chspec) +{ + chanspec_t chspec; + + /* get the channel number */ + chspec = LCHSPEC_CHANNEL(legacy_chspec); + + /* convert the band */ + if (LCHSPEC_IS2G(legacy_chspec)) { + chspec |= WL_CHANSPEC_BAND_2G; + } else { + chspec |= WL_CHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (LCHSPEC_IS20(legacy_chspec)) { + chspec |= WL_CHANSPEC_BW_20; + } else { + chspec |= WL_CHANSPEC_BW_40; + if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { + chspec |= WL_CHANSPEC_CTL_SB_L; + } else { + chspec |= WL_CHANSPEC_CTL_SB_U; + } + } + + if (wf_chspec_malformed(chspec)) { + WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", + chspec)); + return INVCHANSPEC; + } + + return chspec; +} + +/* Return a legacy chanspec given a new chanspec + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_to_legacy(chanspec_t chspec) +{ + chanspec_t lchspec; + + if (wf_chspec_malformed(chspec)) { + WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", + chspec)); + return INVCHANSPEC; + } + + /* get the channel number */ + lchspec = CHSPEC_CHANNEL(chspec); + + /* convert the band */ + if (CHSPEC_IS2G(chspec)) { + lchspec |= WL_LCHANSPEC_BAND_2G; + } else { + lchspec |= WL_LCHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (CHSPEC_IS20(chspec)) { + lchspec |= WL_LCHANSPEC_BW_20; + lchspec |= WL_LCHANSPEC_CTL_SB_NONE; + } else if (CHSPEC_IS40(chspec)) { + lchspec |= WL_LCHANSPEC_BW_40; + if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { + lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; + } else { + lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; + } + } else { + /* cannot express the bandwidth */ + char chanbuf[CHANSPEC_STR_LEN]; + WL_ERR(( + "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " + "to pre-11ac format\n", + wf_chspec_ntoa(chspec, chanbuf), chspec)); + return INVCHANSPEC; + } + + return lchspec; +} + +/* given a chanspec value, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +chanspec_t +wl_chspec_host_to_driver(chanspec_t chanspec) +{ + if (ioctl_version == 1) { + chanspec = wl_chspec_to_legacy(chanspec); + if (chanspec == INVCHANSPEC) { + return chanspec; + } + } + chanspec = htodchanspec(chanspec); + + return chanspec; +} + +/* given a channel value, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +chanspec_t +wl_ch_host_to_driver(u16 channel) +{ + + chanspec_t chanspec; + + chanspec = channel & WL_CHANSPEC_CHAN_MASK; + + if (channel <= 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; + + return wl_chspec_host_to_driver(chanspec); +} + +/* given a chanspec value from the driver, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_driver_to_host(chanspec_t chanspec) +{ + chanspec = dtohchanspec(chanspec); + if (ioctl_version == 1) { + chanspec = wl_chspec_from_legacy(chanspec); + } + + return chanspec; +} + +/* + * convert ASCII string to MAC address (colon-delimited format) + * eg: 00:11:22:33:44:55 + */ +int +wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n) +{ + char *c = NULL; + int count = 0; + + memset(n, 0, ETHER_ADDR_LEN); + for (;;) { + n->octet[count++] = (uint8)simple_strtoul(a, &c, 16); + if (!*c++ || count == ETHER_ADDR_LEN) + break; + a = c; + } + return (count == ETHER_ADDR_LEN); +} + +/* convert hex string buffer to binary */ +int +wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str) +{ + int count, slen; + int hvalue; + char tmp[3] = {0}; + char *ptr = str, *endp = NULL; + + if (!data || !str || !dlen) { + WL_DBG((" passed buffer is empty \n")); + return 0; + } + + slen = strlen(str); + if (dlen * 2 < slen) { + WL_DBG((" destination buffer too short \n")); + return 0; + } + + if (slen % 2) { + WL_DBG((" source buffer is of odd length \n")); + return 0; + } + + for (count = 0; count < slen; count += 2) { + memcpy(tmp, ptr, 2); + hvalue = simple_strtol(tmp, &endp, 16); + if (*endp != '\0') { + WL_DBG((" non hexadecimal character encountered \n")); + return 0; + } + *data++ = (unsigned char)hvalue; + ptr += 2; + } + + return (slen / 2); +} + +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes +wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_AP_VLAN] = { + /* copy AP */ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, +#if defined(WL_CFG80211_P2P_DEV_IF) + [NL80211_IFTYPE_P2P_DEVICE] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, +#endif /* WL_CFG80211_P2P_DEV_IF */ +}; + +static void swap_key_from_BE(struct wl_wsec_key *key) +{ + key->index = htod32(key->index); + key->len = htod32(key->len); + key->algo = htod32(key->algo); + key->flags = htod32(key->flags); + key->rxiv.hi = htod32(key->rxiv.hi); + key->rxiv.lo = htod16(key->rxiv.lo); + key->iv_initialized = htod32(key->iv_initialized); +} + +static void swap_key_to_BE(struct wl_wsec_key *key) +{ + key->index = dtoh32(key->index); + key->len = dtoh32(key->len); + key->algo = dtoh32(key->algo); + key->flags = dtoh32(key->flags); + key->rxiv.hi = dtoh32(key->rxiv.hi); + key->rxiv.lo = dtoh16(key->rxiv.lo); + key->iv_initialized = dtoh32(key->iv_initialized); +} + +/* Dump the contents of the encoded wps ie buffer and get pbc value */ +static void +wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) +{ + #define WPS_IE_FIXED_LEN 6 + u16 len; + u8 *subel = NULL; + u16 subelt_id; + u16 subelt_len; + u16 val; + u8 *valptr = (uint8*) &val; + if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) { + WL_ERR(("invalid argument : NULL\n")); + return; + } + len = (u16)wps_ie[TLV_LEN_OFF]; + + if (len > wps_ie_len) { + WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len)); + return; + } + WL_DBG(("wps_ie len=%d\n", len)); + len -= 4; /* for the WPS IE's OUI, oui_type fields */ + subel = wps_ie + WPS_IE_FIXED_LEN; + while (len >= 4) { /* must have attr id, attr len fields */ + valptr[0] = *subel++; + valptr[1] = *subel++; + subelt_id = HTON16(val); + + valptr[0] = *subel++; + valptr[1] = *subel++; + subelt_len = HTON16(val); + + len -= 4; /* for the attr id, attr len fields */ + + if (len < subelt_len) { + WL_ERR(("not enough data, len %d, subelt_len %d\n", len, + subelt_len)); + break; + } + len -= subelt_len; /* for the remaining fields in this attribute */ + + WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n", + subel, subelt_id, subelt_len)); + + if (subelt_id == WPS_ID_VERSION) { + WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel)); + } else if (subelt_id == WPS_ID_REQ_TYPE) { + WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel)); + } else if (subelt_id == WPS_ID_CONFIG_METHODS) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val))); + } else if (subelt_id == WPS_ID_DEVICE_NAME) { + char devname[100]; + int namelen = MIN(subelt_len, (sizeof(devname) - 1)); + + if (namelen) { + memcpy(devname, subel, namelen); + devname[namelen] = '\0'; + /* Printing len as rx'ed in the IE */ + WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n", + devname, subelt_len)); + } + } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val))); + *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false; + } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val))); + valptr[0] = *(subel + 6); + valptr[1] = *(subel + 7); + WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val))); + } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val))); + valptr[0] = *(subel + 6); + valptr[1] = *(subel + 7); + WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val))); + } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS" + ": cat=%u\n", HTON16(val))); + } else { + WL_DBG((" unknown attr 0x%x\n", subelt_id)); + } + + subel += subelt_len; + } +} + +s32 wl_set_tx_power(struct net_device *dev, + enum nl80211_tx_power_setting type, s32 dbm) +{ + s32 err = 0; + s32 disable = 0; + s32 txpwrqdbm; + struct bcm_cfg80211 *cfg = g_bcm_cfg; +#ifdef TEST_TX_POWER_CONTROL + char *tmppwr_str; +#endif /* TEST_TX_POWER_CONTROL */ + + /* Make sure radio is off or on as far as software is concerned */ + disable = WL_RADIO_SW_DISABLE << 16; + disable = htod32(disable); + err = wldev_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable), true); + if (unlikely(err)) { + WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); + return err; + } + + if (dbm > 0xffff) + dbm = 0xffff; + txpwrqdbm = dbm * 4; +#ifdef SUPPORT_WL_TXPOWER + if (type == NL80211_TX_POWER_AUTOMATIC) { + txpwrqdbm = 127; +#ifdef TEST_TX_POWER_CONTROL + err = wldev_iovar_setint(dev, "qtxpower", txpwrqdbm); + if (unlikely(err)) + WL_ERR(("qtxpower error (%d)\n", err)); + else + WL_ERR(("mW=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm)); + + tmppwr_str = kzalloc(0x71a, GFP_KERNEL); + if (!tmppwr_str) { + WL_ERR(("tmppwr memory alloc failed\n")); + } else { + err = wldev_iovar_getbuf(dev, "curpower", NULL, 0, tmppwr_str, 0x71a, NULL); + if (unlikely(err)) { + WL_ERR(("curpower error (%d)\n", err)); + } + kfree(tmppwr_str); + } +#endif /* TEST_TX_POWER_CONTROL */ + } else { + txpwrqdbm |= WL_TXPWR_OVERRIDE; + } +#endif /* SUPPORT_WL_TXPOWER */ + + err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm, + sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, + &cfg->ioctl_buf_sync); + + if (unlikely(err)) + WL_ERR(("qtxpower error (%d)\n", err)); + else + WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm)); + + return err; +} + +s32 wl_get_tx_power(struct net_device *dev, s32 *dbm) +{ + s32 err = 0; + s32 txpwrdbm; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + err = wldev_iovar_getint(dev, "qtxpower", &txpwrdbm); + err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower", + NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + memcpy(&txpwrdbm, cfg->ioctl_buf, sizeof(txpwrdbm)); + txpwrdbm = dtoh32(txpwrdbm); + *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4; + + WL_INFO(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm)); + + return err; +} + +static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) +{ + chanspec_t chspec; + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + struct ether_addr bssid; + struct wl_bss_info *bss = NULL; + char *buf; + + memset(&bssid, 0, sizeof(bssid)); + if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { + /* STA interface is not associated. So start the new interface on a temp + * channel . Later proper channel will be applied by the above framework + * via set_channel (cfg80211 API). + */ + WL_DBG(("Not associated. Return a temp channel. \n")); + return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); + } + + buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!buf) { + WL_ERR(("buf alloc failed. use temp channel\n")); + return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); + } + + *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX); + if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, buf, + WL_EXTRA_BUF_MAX, false))) { + WL_ERR(("Failed to get associated bss info, use temp channel \n")); + chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); + } + else { + bss = (wl_bss_info_t *) (buf + 4); + chspec = bss->chanspec; + + WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec)); + } + + kfree(buf); + return chspec; +} + +static bcm_struct_cfgdev * +wl_cfg80211_add_monitor_if(char *name) +{ +#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) + WL_INFO(("wl_cfg80211_add_monitor_if: No more support monitor interface\n")); + return ERR_PTR(-EOPNOTSUPP); +#else + struct net_device* ndev = NULL; + + dhd_add_monitor(name, &ndev); + WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); + return ndev_to_cfgdev(ndev); +#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */ +} + +static bcm_struct_cfgdev * +wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, +#if defined(WL_CFG80211_P2P_DEV_IF) + const char *name, +#else + char *name, +#endif /* WL_CFG80211_P2P_DEV_IF */ + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + s32 err; + s32 timeout = -1; + s32 wlif_type = -1; + s32 mode = 0; + s32 val = 0; + s32 dhd_mode = 0; + chanspec_t chspec; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *primary_ndev; + struct net_device *new_ndev; + struct ether_addr primary_mac; +#ifdef PROP_TXSTATUS_VSDB + s32 up = 1; + dhd_pub_t *dhd; + bool enabled; +#endif /* PROP_TXSTATUS_VSDB */ + + if (!cfg) + return ERR_PTR(-EINVAL); + +#ifdef PROP_TXSTATUS_VSDB + dhd = (dhd_pub_t *)(cfg->pub); +#endif /* PROP_TXSTATUS_VSDB */ + + + /* Use primary I/F for sending cmds down to firmware */ + primary_ndev = bcmcfg_to_prmry_ndev(cfg); + + if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) { + WL_ERR(("device is not ready\n")); + return ERR_PTR(-ENODEV); + } + + WL_DBG(("if name: %s, type: %d\n", name, type)); + switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + WL_ERR(("Unsupported interface type\n")); + mode = WL_MODE_IBSS; + return NULL; + case NL80211_IFTYPE_MONITOR: + return wl_cfg80211_add_monitor_if((char *)name); +#if defined(WL_CFG80211_P2P_DEV_IF) + case NL80211_IFTYPE_P2P_DEVICE: + return wl_cfgp2p_add_p2p_disc_if(cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + wlif_type = WL_P2P_IF_CLIENT; + mode = WL_MODE_BSS; + break; + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP: + wlif_type = WL_P2P_IF_GO; + mode = WL_MODE_AP; + break; + default: + WL_ERR(("Unsupported interface type\n")); + return NULL; + break; + } + + if (!name) { + WL_ERR(("name is NULL\n")); + return NULL; + } + if (cfg->p2p_supported && (wlif_type != -1)) { + ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */ + +#ifdef PROP_TXSTATUS_VSDB + if (!dhd) + return ERR_PTR(-ENODEV); +#endif /* PROP_TXSTATUS_VSDB */ + if (!cfg->p2p) + return ERR_PTR(-ENODEV); + + if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { + p2p_on(cfg) = true; + wl_cfgp2p_set_firm_p2p(cfg); + wl_cfgp2p_init_discovery(cfg); + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &cfg->p2p->dev_addr, &cfg->p2p->int_addr); + } + + memset(cfg->p2p->vir_ifname, 0, IFNAMSIZ); + strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1); + + wl_cfg80211_scan_abort(cfg); +#ifdef PROP_TXSTATUS_VSDB + if (!cfg->wlfc_on && !disable_proptx) { + dhd_wlfc_get_enable(dhd, &enabled); + if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) { + dhd_wlfc_init(dhd); + err = wldev_ioctl(primary_ndev, WLC_UP, &up, sizeof(s32), true); + if (err < 0) + WL_ERR(("WLC_UP return err:%d\n", err)); + } + cfg->wlfc_on = true; + } +#endif /* PROP_TXSTATUS_VSDB */ + + /* In concurrency case, STA may be already associated in a particular channel. + * so retrieve the current channel of primary interface and then start the virtual + * interface on that. + */ + chspec = wl_cfg80211_get_shared_freq(wiphy); + + /* For P2P mode, use P2P-specific driver features to create the + * bss: "cfg p2p_ifadd" + */ + wl_set_p2p_status(cfg, IF_ADDING); + memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); + if (wlif_type == WL_P2P_IF_GO) + wldev_iovar_setint(primary_ndev, "mpc", 0); + err = wl_cfgp2p_ifadd(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec); + if (unlikely(err)) { + wl_clr_p2p_status(cfg, IF_ADDING); + WL_ERR((" virtual iface add failed (%d) \n", err)); + return ERR_PTR(-ENOMEM); + } + + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + (wl_get_p2p_status(cfg, IF_ADDING) == false), + msecs_to_jiffies(MAX_WAIT_TIME)); + + if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) { + struct wireless_dev *vwdev; + int pm_mode = PM_ENABLE; + wl_if_event_info *event = &cfg->if_event_info; + + /* IF_ADD event has come back, we can proceed to to register + * the new interface now, use the interface name provided by caller (thus + * ignore the one from wlc) + */ + strncpy(cfg->if_event_info.name, name, IFNAMSIZ - 1); + new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname, + event->mac, event->bssidx); + if (new_ndev == NULL) + goto fail; + + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = new_ndev; + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = event->bssidx; + vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); + if (unlikely(!vwdev)) { + WL_ERR(("Could not allocate wireless device\n")); + goto fail; + } + vwdev->wiphy = cfg->wdev->wiphy; + WL_INFO(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname)); + vwdev->iftype = type; + vwdev->netdev = new_ndev; + new_ndev->ieee80211_ptr = vwdev; + SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy)); + wl_set_drv_status(cfg, READY, new_ndev); + cfg->p2p->vif_created = true; + wl_set_mode_by_netdev(cfg, new_ndev, mode); + + if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) { + wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev); + goto fail; + } + wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode); + val = 1; + /* Disable firmware roaming for P2P interface */ + wldev_iovar_setint(new_ndev, "roam_off", val); + + if (mode != WL_MODE_AP) + wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1); + + WL_ERR((" virtual interface(%s) is " + "created net attach done\n", cfg->p2p->vir_ifname)); + if (mode == WL_MODE_AP) + wl_set_drv_status(cfg, CONNECTED, new_ndev); + if (type == NL80211_IFTYPE_P2P_CLIENT) + dhd_mode = DHD_FLAG_P2P_GC_MODE; + else if (type == NL80211_IFTYPE_P2P_GO) + dhd_mode = DHD_FLAG_P2P_GO_MODE; + DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode)); + /* reinitialize completion to clear previous count */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) + INIT_COMPLETION(cfg->iface_disable); +#else + init_completion(&cfg->iface_disable); +#endif + return ndev_to_cfgdev(new_ndev); + } else { + wl_clr_p2p_status(cfg, IF_ADDING); + WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname)); + memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ); + cfg->p2p->vif_created = false; +#ifdef PROP_TXSTATUS_VSDB + dhd_wlfc_get_enable(dhd, &enabled); + if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) { + dhd_wlfc_deinit(dhd); + cfg->wlfc_on = false; + } +#endif /* PROP_TXSTATUS_VSDB */ + } + } + +fail: + if (wlif_type == WL_P2P_IF_GO) + wldev_iovar_setint(primary_ndev, "mpc", 1); + return ERR_PTR(-ENODEV); +} + +static s32 +wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) +{ + struct net_device *dev = NULL; + struct ether_addr p2p_mac; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 timeout = -1; + s32 ret = 0; + s32 index = -1; + WL_DBG(("Enter\n")); + +#if defined(WL_CFG80211_P2P_DEV_IF) + if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { + return wl_cfgp2p_del_p2p_disc_if(cfgdev, cfg); + } +#endif /* WL_CFG80211_P2P_DEV_IF */ + dev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (wl_cfgp2p_find_idx(cfg, dev, &index) != BCME_OK) { + WL_ERR(("Find p2p index from ndev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (cfg->p2p_supported) { + memcpy(p2p_mac.octet, cfg->p2p->int_addr.octet, ETHER_ADDR_LEN); + + /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases + */ + WL_DBG(("P2P: GO_NEG_PHASE status cleared ")); + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + if (cfg->p2p->vif_created) { + if (wl_get_drv_status(cfg, SCANNING, dev)) { + wl_notify_escan_complete(cfg, dev, true, true); + } + wldev_iovar_setint(dev, "mpc", 1); + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + + /* for GC */ + if (wl_get_drv_status(cfg, DISCONNECTING, dev) && + (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)) { + WL_ERR(("Wait for Link Down event for GC !\n")); + wait_for_completion_timeout + (&cfg->iface_disable, msecs_to_jiffies(500)); + } + + memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); + wl_set_p2p_status(cfg, IF_DELETING); + DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg)); + + /* for GO */ + if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); + /* disable interface before bsscfg free */ + ret = wl_cfgp2p_ifdisable(cfg, &p2p_mac); + /* if fw doesn't support "ifdis", + do not wait for link down of ap mode + */ + if (ret == 0) { + WL_ERR(("Wait for Link Down event for GO !!!\n")); + wait_for_completion_timeout(&cfg->iface_disable, + msecs_to_jiffies(500)); + } else if (ret != BCME_UNSUPPORTED) { + msleep(300); + } + } + wl_cfgp2p_clear_management_ie(cfg, index); + + if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) + wldev_iovar_setint(dev, "buf_key_b4_m4", 0); + + /* delete interface after link down */ + ret = wl_cfgp2p_ifdel(cfg, &p2p_mac); + + if (ret != BCME_OK) { + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + + WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n", + ret, ndev->name)); + #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID) + #ifdef CONFIG_BCM_WLAN_RAMDUMP + bcm_add_crash_reason(((dhd_pub_t *)(cfg->pub))->crash_reason, + ("p2p_ifdel failed, error %d, sent HANG event to %s\n", + ret, ndev->name); + #endif /* CONFIG_BCM_WLAN_RAMDUMP */ + net_os_send_hang_message(ndev); + #endif + } else { + /* Wait for IF_DEL operation to be finished */ + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + (wl_get_p2p_status(cfg, IF_DELETING) == false), + msecs_to_jiffies(MAX_WAIT_TIME)); + if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) && + cfg->if_event_info.valid) { + + WL_DBG(("IFDEL operation done\n")); + wl_cfg80211_handle_ifdel(cfg, &cfg->if_event_info, dev); + } else { + WL_ERR(("IFDEL didn't complete properly\n")); + } + } + + ret = dhd_del_monitor(dev); + if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL((dhd_pub_t *)(cfg->pub)); + } + } + } + return ret; +} + +static s32 +wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + s32 ap = 0; + s32 infra = 0; + s32 ibss = 0; + s32 wlif_type; + s32 mode = 0; + s32 err = BCME_OK; + chanspec_t chspec; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + WL_DBG(("Enter type %d\n", type)); + switch (type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + ap = 1; + WL_ERR(("type (%d) : currently we do not support this type\n", + type)); + break; + case NL80211_IFTYPE_ADHOC: + mode = WL_MODE_IBSS; + ibss = 1; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + mode = WL_MODE_BSS; + infra = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + mode = WL_MODE_AP; + ap = 1; + break; + default: + return -EINVAL; + } + if (!dhd) + return -EINVAL; + if (ap) { + wl_set_mode_by_netdev(cfg, ndev, mode); + if (cfg->p2p_supported && cfg->p2p->vif_created) { + WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", cfg->p2p->vif_created, + p2p_on(cfg))); + wldev_iovar_setint(ndev, "mpc", 0); + wl_notify_escan_complete(cfg, ndev, true, true); + + /* In concurrency case, STA may be already associated in a particular + * channel. so retrieve the current channel of primary interface and + * then start the virtual interface on that. + */ + chspec = wl_cfg80211_get_shared_freq(wiphy); + + wlif_type = WL_P2P_IF_GO; + WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", + ndev->name, ap, infra, type)); + wl_set_p2p_status(cfg, IF_CHANGING); + wl_clr_p2p_status(cfg, IF_CHANGED); + wl_cfgp2p_ifchange(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec); + wait_event_interruptible_timeout(cfg->netif_change_event, + (wl_get_p2p_status(cfg, IF_CHANGED) == true), + msecs_to_jiffies(MAX_WAIT_TIME)); + wl_set_mode_by_netdev(cfg, ndev, mode); + dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE; + dhd->op_mode |= DHD_FLAG_P2P_GO_MODE; + wl_clr_p2p_status(cfg, IF_CHANGING); + wl_clr_p2p_status(cfg, IF_CHANGED); + if (mode == WL_MODE_AP) + wl_set_drv_status(cfg, CONNECTED, ndev); + } else if (ndev == bcmcfg_to_prmry_ndev(cfg) && + !wl_get_drv_status(cfg, AP_CREATED, ndev)) { + wl_set_drv_status(cfg, AP_CREATING, ndev); + if (!cfg->ap_info && + !(cfg->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) { + WL_ERR(("struct ap_saved_ie allocation failed\n")); + return -ENOMEM; + } + } else { + WL_ERR(("Cannot change the interface for GO or SOFTAP\n")); + return -EINVAL; + } + } else { + WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA")); + } + + if (ibss) { + infra = 0; + wl_set_mode_by_netdev(cfg, ndev, mode); + err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET Adhoc error %d\n", err)); + return -EINVAL; + } + } + + ndev->ieee80211_ptr->iftype = type; + return 0; +} + +s32 +wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd") + * redirect the IF_ADD event to ifchange as it is not a real "new" interface + */ + if (wl_get_p2p_status(cfg, IF_CHANGING)) + return wl_cfg80211_notify_ifchange(ifidx, name, mac, bssidx); + + /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */ + if (wl_get_p2p_status(cfg, IF_ADDING)) { + wl_if_event_info *if_event_info = &cfg->if_event_info; + + if_event_info->valid = TRUE; + if_event_info->ifidx = ifidx; + if_event_info->bssidx = bssidx; + strncpy(if_event_info->name, name, IFNAMSIZ); + if_event_info->name[IFNAMSIZ] = '\0'; + if (mac) + memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN); + + wl_clr_p2p_status(cfg, IF_ADDING); + wake_up_interruptible(&cfg->netif_change_event); + return BCME_OK; + } + + return BCME_ERROR; +} + +s32 +wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + wl_if_event_info *if_event_info = &cfg->if_event_info; + + if (wl_get_p2p_status(cfg, IF_DELETING)) { + if_event_info->valid = TRUE; + if_event_info->ifidx = ifidx; + if_event_info->bssidx = bssidx; + wl_clr_p2p_status(cfg, IF_DELETING); + wake_up_interruptible(&cfg->netif_change_event); + return BCME_OK; + } + + return BCME_ERROR; +} + +s32 +wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (wl_get_p2p_status(cfg, IF_CHANGING)) { + wl_set_p2p_status(cfg, IF_CHANGED); + wake_up_interruptible(&cfg->netif_change_event); + return BCME_OK; + } + + return BCME_ERROR; +} + +static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info, + struct net_device* ndev) +{ + s32 type = -1; + s32 bssidx = -1; +#ifdef PROP_TXSTATUS_VSDB + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + bool enabled; +#endif /* PROP_TXSTATUS_VSDB */ + + bssidx = if_event_info->bssidx; + if (bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION)) { + WL_ERR(("got IF_DEL for if %d, not owned by cfg driver\n", bssidx)); + return BCME_ERROR; + } + + if (p2p_is_on(cfg) && cfg->p2p->vif_created) { + + if (cfg->scan_request && (cfg->escan_info.ndev == ndev)) { + /* Abort any pending scan requests */ + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + WL_DBG(("ESCAN COMPLETED\n")); + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, false); + } + + memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ); + if (wl_cfgp2p_find_type(cfg, bssidx, &type) != BCME_OK) { + WL_ERR(("Find p2p type from bssidx(%d) failed\n", bssidx)); + return BCME_ERROR; + } + wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, type)); + wl_to_p2p_bss_ndev(cfg, type) = NULL; + wl_to_p2p_bss_bssidx(cfg, type) = WL_INVALID; + cfg->p2p->vif_created = false; + +#ifdef PROP_TXSTATUS_VSDB + dhd_wlfc_get_enable(dhd, &enabled); + if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) { + dhd_wlfc_deinit(dhd); + cfg->wlfc_on = false; + } +#endif /* PROP_TXSTATUS_VSDB */ + } + + wl_cfg80211_remove_if(cfg, if_event_info->ifidx, ndev); + return BCME_OK; +} + +/* Find listen channel */ +static s32 wl_find_listen_channel(struct bcm_cfg80211 *cfg, + const u8 *ie, u32 ie_len) +{ + wifi_p2p_ie_t *p2p_ie; + u8 *end, *pos; + s32 listen_channel; + + pos = (u8 *)ie; + p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len); + + if (p2p_ie == NULL) + return 0; + + pos = p2p_ie->subelts; + end = p2p_ie->subelts + (p2p_ie->len - 4); + + CFGP2P_DBG((" found p2p ie ! lenth %d \n", + p2p_ie->len)); + + while (pos < end) { + uint16 attr_len; + if (pos + 2 >= end) { + CFGP2P_DBG((" -- Invalid P2P attribute")); + return 0; + } + attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0])); + + if (pos + 3 + attr_len > end) { + CFGP2P_DBG(("P2P: Attribute underflow " + "(len=%u left=%d)", + attr_len, (int) (end - pos - 3))); + return 0; + } + + /* if Listen Channel att id is 6 and the vailue is valid, + * return the listen channel + */ + if (pos[0] == 6) { + /* listen channel subel length format + * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num) + */ + listen_channel = pos[1 + 2 + 3 + 1]; + + if (listen_channel == SOCIAL_CHAN_1 || + listen_channel == SOCIAL_CHAN_2 || + listen_channel == SOCIAL_CHAN_3) { + CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel)); + return listen_channel; + } + } + pos += 3 + attr_len; + } + return 0; +} + +static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) +{ + u32 n_ssids; + u32 n_channels; + u16 channel; + chanspec_t chanspec; + s32 i = 0, j = 0, offset; + char *ptr; + wlc_ssid_t ssid; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + params->bss_type = DOT11_BSSTYPE_ANY; + params->scan_type = 0; + params->nprobes = -1; + params->active_time = -1; + params->passive_time = -1; + params->home_time = -1; + params->channel_num = 0; + memset(¶ms->ssid, 0, sizeof(wlc_ssid_t)); + + WL_SCAN(("Preparing Scan request\n")); + WL_SCAN(("nprobes=%d\n", params->nprobes)); + WL_SCAN(("active_time=%d\n", params->active_time)); + WL_SCAN(("passive_time=%d\n", params->passive_time)); + WL_SCAN(("home_time=%d\n", params->home_time)); + WL_SCAN(("scan_type=%d\n", params->scan_type)); + + params->nprobes = htod32(params->nprobes); + params->active_time = htod32(params->active_time); + params->passive_time = htod32(params->passive_time); + params->home_time = htod32(params->home_time); + + /* if request is null just exit so it will be all channel broadcast scan */ + if (!request) + return; + + n_ssids = request->n_ssids; + n_channels = request->n_channels; + + /* Copy channel array if applicable */ + WL_SCAN(("### List of channelspecs to scan ###\n")); + if (n_channels > 0) { + for (i = 0; i < n_channels; i++) { + chanspec = 0; + channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); + /* SKIP DFS channels for Secondary interface */ + if ((cfg->escan_info.ndev != bcmcfg_to_prmry_ndev(cfg)) && + (request->channels[i]->flags & +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) +#else + (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR))) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */ + continue; + + if (request->channels[i]->band == IEEE80211_BAND_2GHZ) { + chanspec |= WL_CHANSPEC_BAND_2G; + } else { + chanspec |= WL_CHANSPEC_BAND_5G; + } + + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + params->channel_list[j] = channel; + params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK; + params->channel_list[j] |= chanspec; + WL_SCAN(("Chan : %d, Channel spec: %x \n", + channel, params->channel_list[j])); + params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]); + j++; + } + } else { + WL_SCAN(("Scanning all channels\n")); + } + n_channels = j; + /* Copy ssid array if applicable */ + WL_SCAN(("### List of SSIDs to scan ###\n")); + if (n_ssids > 0) { + offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); + offset = roundup(offset, sizeof(u32)); + ptr = (char*)params + offset; + for (i = 0; i < n_ssids; i++) { + memset(&ssid, 0, sizeof(wlc_ssid_t)); + ssid.SSID_len = MIN(request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN); + memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); + if (!ssid.SSID_len) + WL_SCAN(("%d: Broadcast scan\n", i)); + else + WL_SCAN(("%d: scan for %s size =%d\n", i, + ssid.SSID, ssid.SSID_len)); + memcpy(ptr, &ssid, sizeof(wlc_ssid_t)); + ptr += sizeof(wlc_ssid_t); + } + } else { + WL_SCAN(("Broadcast scan\n")); + } + /* Adding mask to channel numbers */ + params->channel_num = + htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | + (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); + + if (n_channels == 1) { + params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS); + } +} + +static s32 +wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) +{ + wl_uint32_list_t *list; + s32 err = BCME_OK; + if (valid_chan_list == NULL || size <= 0) + return -ENOMEM; + + memset(valid_chan_list, 0, size); + list = (wl_uint32_list_t *)(void *) valid_chan_list; + list->count = htod32(WL_NUMCHANNELS); + err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false); + if (err != 0) { + WL_ERR(("get channels failed with %d\n", err)); + } + + return err; +} + +#if defined(USE_INITIAL_SHORT_DWELL_TIME) +#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40 +bool g_first_broadcast_scan = TRUE; +#endif + +static s32 +wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, + struct cfg80211_scan_request *request, uint16 action) +{ + s32 err = BCME_OK; + u32 n_channels; + u32 n_ssids; + s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); + wl_escan_params_t *params = NULL; + u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)]; + u32 num_chans = 0; + s32 channel; + s32 n_valid_chan; + s32 search_state = WL_P2P_DISC_ST_SCAN; + u32 i, j, n_nodfs = 0; + u16 *default_chan_list = NULL; + wl_uint32_list_t *list; + struct net_device *dev = NULL; +#if defined(USE_INITIAL_SHORT_DWELL_TIME) + bool is_first_init_2g_scan = false; +#endif + p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN; + + WL_DBG(("Enter \n")); + + /* scan request can come with empty request : perform all default scan */ + if (!cfg) { + err = -EINVAL; + goto exit; + } + if (!cfg->p2p_supported || !p2p_scan(cfg)) { + /* LEGACY SCAN TRIGGER */ + WL_SCAN((" LEGACY E-SCAN START\n")); + +#if defined(USE_INITIAL_SHORT_DWELL_TIME) + if (!request) { + err = -EINVAL; + goto exit; + } + if (ndev == bcmcfg_to_prmry_ndev(cfg) && g_first_broadcast_scan == true) { + is_first_init_2g_scan = true; + g_first_broadcast_scan = false; + } +#endif + + /* if scan request is not empty parse scan request paramters */ + if (request != NULL) { + n_channels = request->n_channels; + n_ssids = request->n_ssids; + if (n_channels % 2) + /* If n_channels is odd, add a padd of u16 */ + params_size += sizeof(u16) * (n_channels + 1); + else + params_size += sizeof(u16) * n_channels; + + /* Allocate space for populating ssids in wl_escan_params_t struct */ + params_size += sizeof(struct wlc_ssid) * n_ssids; + } + params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); + if (params == NULL) { + err = -ENOMEM; + goto exit; + } + wl_scan_prep(¶ms->params, request); + +#if defined(USE_INITIAL_SHORT_DWELL_TIME) + /* Override active_time to reduce scan time if it's first bradcast scan. */ + if (is_first_init_2g_scan) + params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; +#endif + + params->version = htod32(ESCAN_REQ_VERSION); + params->action = htod16(action); + wl_escan_set_sync_id(params->sync_id, cfg); + wl_escan_set_type(cfg, WL_SCANTYPE_LEGACY); + if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { + WL_ERR(("ioctl buffer length not sufficient\n")); + kfree(params); + err = -ENOMEM; + goto exit; + } + err = wldev_iovar_setbuf(ndev, "escan", params, params_size, + cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(err)) { + if (err == BCME_EPERM) + /* Scan Not permitted at this point of time */ + WL_DBG((" Escan not permitted at this time (%d)\n", err)); + else + WL_ERR((" Escan set error (%d)\n", err)); + } + kfree(params); + } + else if (p2p_is_on(cfg) && p2p_scan(cfg)) { + /* P2P SCAN TRIGGER */ + s32 _freq = 0; + n_nodfs = 0; + if (request && request->n_channels) { + num_chans = request->n_channels; + WL_SCAN((" chann number : %d\n", num_chans)); + default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), + GFP_KERNEL); + if (default_chan_list == NULL) { + WL_ERR(("channel list allocation failed \n")); + err = -ENOMEM; + goto exit; + } + if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { + list = (wl_uint32_list_t *) chan_buf; + n_valid_chan = dtoh32(list->count); + if (n_valid_chan > WL_NUMCHANNELS) { + WL_ERR(("wrong n_valid_chan:%d\n", n_valid_chan)); + kfree(default_chan_list); + err = -EINVAL; + goto exit; + } + + for (i = 0; i < num_chans; i++) + { + _freq = request->channels[i]->center_freq; + channel = ieee80211_frequency_to_channel(_freq); + + /* ignore DFS channels */ + if (request->channels[i]->flags & +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + (IEEE80211_CHAN_NO_IR + | IEEE80211_CHAN_RADAR)) +#else + (IEEE80211_CHAN_RADAR +#ifdef CUSTOMER_HW5 + | 0)) +#else + | IEEE80211_CHAN_PASSIVE_SCAN)) +#endif /* CUSTOMER_HW5 */ +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ + continue; + + for (j = 0; j < n_valid_chan; j++) { + /* allows only supported channel on + * current reguatory + */ + if (n_nodfs >= num_chans) { + break; + } + if (channel == (dtoh32(list->element[j]))) { + default_chan_list[n_nodfs++] = + channel; + } + } + + } + } + if (num_chans == SOCIAL_CHAN_CNT && ( + (default_chan_list[0] == SOCIAL_CHAN_1) && + (default_chan_list[1] == SOCIAL_CHAN_2) && + (default_chan_list[2] == SOCIAL_CHAN_3))) { + /* SOCIAL CHANNELS 1, 6, 11 */ + search_state = WL_P2P_DISC_ST_SEARCH; + p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; + WL_INFO(("P2P SEARCH PHASE START \n")); + } else if ((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) && + (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) { + /* If you are already a GO, then do SEARCH only */ + WL_INFO(("Already a GO. Do SEARCH Only")); + search_state = WL_P2P_DISC_ST_SEARCH; + num_chans = n_nodfs; + p2p_scan_purpose = P2P_SCAN_NORMAL; + + } else if (num_chans == 1) { + p2p_scan_purpose = P2P_SCAN_CONNECT_TRY; + } else if (num_chans == SOCIAL_CHAN_CNT + 1) { + /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by + * the supplicant + */ + p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; + } else { + WL_INFO(("P2P SCAN STATE START \n")); + num_chans = n_nodfs; + p2p_scan_purpose = P2P_SCAN_NORMAL; + } + } else { + err = -EINVAL; + goto exit; + } + err = wl_cfgp2p_escan(cfg, ndev, cfg->active_scan, num_chans, default_chan_list, + search_state, action, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE), NULL, + p2p_scan_purpose); + + if (!err) + cfg->p2p->search_state = search_state; + + kfree(default_chan_list); + } +exit: + if (unlikely(err)) { + /* Don't print Error incase of Scan suppress */ + if ((err == BCME_EPERM) && cfg->scan_suppressed) + WL_DBG(("Escan failed: Scan Suppressed \n")); + else + WL_ERR(("error (%d)\n", err)); + } + return err; +} + + +static s32 +wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) +{ + s32 err = BCME_OK; + s32 passive_scan; + wl_scan_results_t *results; + WL_SCAN(("Enter \n")); + mutex_lock(&cfg->usr_sync); + + results = wl_escan_get_buf(cfg, FALSE); + results->version = 0; + results->count = 0; + results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; + + cfg->escan_info.ndev = ndev; + cfg->escan_info.wiphy = wiphy; + cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING; + passive_scan = cfg->active_scan ? 0 : 1; + err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan), true); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + goto exit; + } + + err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START); +exit: + mutex_unlock(&cfg->usr_sync); + return err; +} + +static s32 +__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request, + struct cfg80211_ssid *this_ssid) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct cfg80211_ssid *ssids; + struct ether_addr primary_mac; + bool p2p_ssid; +#ifdef WL11U + bcm_tlv_t *interworking_ie; +#endif + s32 err = 0; + s32 bssidx = -1; + s32 i; + + unsigned long flags; + static s32 busy_count = 0; +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + struct net_device *remain_on_channel_ndev = NULL; +#endif + + dhd_pub_t *dhd; + + dhd = (dhd_pub_t *)(cfg->pub); + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { + WL_ERR(("Invalid Scan Command at SoftAP mode\n")); + return -EINVAL; + } + + ndev = ndev_to_wlc_ndev(ndev, cfg); + + if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) { + WL_ERR(("Sending Action Frames. Try it again.\n")); + return -EAGAIN; + } + + WL_DBG(("Enter wiphy (%p)\n", wiphy)); + if (wl_get_drv_status_all(cfg, SCANNING)) { + if (cfg->scan_request == NULL) { + wl_clr_drv_status_all(cfg, SCANNING); + WL_DBG(("<<<<<<<<<<>>>>>>>>>>\n")); + } else { + WL_ERR(("Scanning already\n")); + return -EAGAIN; + } + } + if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) { + WL_ERR(("Scanning being aborted\n")); + return -EAGAIN; + } + if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { + WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); + return -EOPNOTSUPP; + } +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg); + if (remain_on_channel_ndev) { + WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n")); + wl_notify_escan_complete(cfg, remain_on_channel_ndev, true, true); + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + + + /* Arm scan timeout timer */ + mod_timer(&cfg->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); + if (request) { /* scan bss */ + ssids = request->ssids; + p2p_ssid = false; + for (i = 0; i < request->n_ssids; i++) { + if (ssids[i].ssid_len && + IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { + p2p_ssid = true; + break; + } + } + if (p2p_ssid) { + if (cfg->p2p_supported) { + /* p2p scan trigger */ + if (p2p_on(cfg) == false) { + /* p2p on at the first time */ + p2p_on(cfg) = true; + wl_cfgp2p_set_firm_p2p(cfg); + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &cfg->p2p->dev_addr, &cfg->p2p->int_addr); + } + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); + p2p_scan(cfg) = true; + } + } else { + /* legacy scan trigger + * So, we have to disable p2p discovery if p2p discovery is on + */ + if (cfg->p2p_supported) { + p2p_scan(cfg) = false; + /* If Netdevice is not equals to primary and p2p is on + * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. + */ + + if (p2p_scan(cfg) == false) { + if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { + err = wl_cfgp2p_discover_enable_search(cfg, + false); + if (unlikely(err)) { + goto scan_out; + } + + } + } + } + if (!cfg->p2p_supported || !p2p_scan(cfg)) { + + if (wl_cfgp2p_find_idx(cfg, ndev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from ndev(%p) failed\n", + ndev)); + err = BCME_ERROR; + goto scan_out; + } +#ifdef WL11U + if ((interworking_ie = wl_cfg80211_find_interworking_ie( + (u8 *)request->ie, request->ie_len)) != NULL) { + err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, + VNDR_IE_CUSTOM_FLAG, interworking_ie->id, + interworking_ie->data, interworking_ie->len); + + if (unlikely(err)) { + goto scan_out; + } + } else if (cfg->iw_ie_len != 0) { + /* we have to clear IW IE and disable gratuitous APR */ + wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, + VNDR_IE_CUSTOM_FLAG, + DOT11_MNG_INTERWORKING_ID, + 0, 0); + + wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, + bssidx); + cfg->iw_ie_len = 0; + memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN); + + cfg->wl11u = FALSE; + /* we don't care about error */ + } +#endif /* WL11U */ + err = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, + VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, + request->ie_len); + + if (unlikely(err)) { + goto scan_out; + } + + } + } + } else { /* scan in ibss */ + ssids = this_ssid; + } + + if (request && !p2p_scan(cfg)) { + WL_TRACE_HW4(("START SCAN\n")); + } + + cfg->scan_request = request; + wl_set_drv_status(cfg, SCANNING, ndev); + + if (cfg->p2p_supported) { + if (p2p_on(cfg) && p2p_scan(cfg)) { + + /* find my listen channel */ + cfg->afx_hdl->my_listen_chan = + wl_find_listen_channel(cfg, request->ie, + request->ie_len); + err = wl_cfgp2p_enable_discovery(cfg, ndev, + request->ie, request->ie_len); + + if (unlikely(err)) { + goto scan_out; + } + } + } + err = wl_do_escan(cfg, wiphy, ndev, request); + if (likely(!err)) + goto scan_success; + else + goto scan_out; + +scan_success: + busy_count = 0; + + return 0; + +scan_out: + if (err == BCME_BUSY || err == BCME_NOTREADY) { + WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY)); + err = -EBUSY; + } + +#define SCAN_EBUSY_RETRY_LIMIT 10 + if (err == -EBUSY) { + if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) { + struct ether_addr bssid; + s32 ret = 0; + busy_count = 0; + WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n", + wl_get_drv_status(cfg, SCANNING, ndev), + wl_get_drv_status(cfg, SCAN_ABORTING, ndev), + wl_get_drv_status(cfg, CONNECTING, ndev), + wl_get_drv_status(cfg, CONNECTED, ndev), + wl_get_drv_status(cfg, DISCONNECTING, ndev), + wl_get_drv_status(cfg, AP_CREATING, ndev), + wl_get_drv_status(cfg, AP_CREATED, ndev), + wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev), + wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev))); + + bzero(&bssid, sizeof(bssid)); + if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID, + &bssid, ETHER_ADDR_LEN, false)) == 0) + WL_ERR(("FW is connected with " MACDBG "/n", + MAC2STRDBG(bssid.octet))); + else + WL_ERR(("GET BSSID failed with %d\n", ret)); + + wl_cfg80211_scan_abort(cfg); + + } + } else { + busy_count = 0; + } + + wl_clr_drv_status(cfg, SCANNING, ndev); + if (timer_pending(&cfg->scan_timeout)) + del_timer_sync(&cfg->scan_timeout); + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + cfg->scan_request = NULL; + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + return err; +} + +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +#else +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) +#endif /* WL_CFG80211_P2P_DEV_IF */ +{ + s32 err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); +#if defined(WL_CFG80211_P2P_DEV_IF) + struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ + + WL_DBG(("Enter \n")); + RETURN_EIO_IF_NOT_UP(cfg); + + err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); + if (unlikely(err)) { + if ((err == BCME_EPERM) && cfg->scan_suppressed) + WL_DBG(("scan not permitted at this time (%d)\n", err)); + else + WL_ERR(("scan error (%d)\n", err)); + return err; + } + + return err; +} + +static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) +{ + s32 err = 0; + + err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) +{ + s32 err = 0; + + err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) +{ + s32 err = 0; + u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); + + retry = htod32(retry); + err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true); + if (unlikely(err)) { + WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); + return err; + } + return err; +} + +static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; + + RETURN_EIO_IF_NOT_UP(cfg); + WL_DBG(("Enter\n")); + if (changed & WIPHY_PARAM_RTS_THRESHOLD && + (cfg->conf->rts_threshold != wiphy->rts_threshold)) { + cfg->conf->rts_threshold = wiphy->rts_threshold; + err = wl_set_rts(ndev, cfg->conf->rts_threshold); + if (err != BCME_OK) + return err; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD && + (cfg->conf->frag_threshold != wiphy->frag_threshold)) { + cfg->conf->frag_threshold = wiphy->frag_threshold; + err = wl_set_frag(ndev, cfg->conf->frag_threshold); + if (err != BCME_OK) + return err; + } + if (changed & WIPHY_PARAM_RETRY_LONG && + (cfg->conf->retry_long != wiphy->retry_long)) { + cfg->conf->retry_long = wiphy->retry_long; + err = wl_set_retry(ndev, cfg->conf->retry_long, true); + if (err != BCME_OK) + return err; + } + if (changed & WIPHY_PARAM_RETRY_SHORT && + (cfg->conf->retry_short != wiphy->retry_short)) { + cfg->conf->retry_short = wiphy->retry_short; + err = wl_set_retry(ndev, cfg->conf->retry_short, false); + if (err != BCME_OK) { + return err; + } + } + + return err; +} +static chanspec_t +channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + u8 *buf = NULL; + wl_uint32_list_t *list; + int err = BCME_OK; + chanspec_t c = 0, ret_c = 0; + int bw = 0, tmp_bw = 0; + int i; + u32 tmp_c, sb; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; +#define LOCAL_BUF_SIZE 1024 + buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags); + if (!buf) { + WL_ERR(("buf memory alloc failed\n")); + goto exit; + } + err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, + 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync); + if (err != BCME_OK) { + WL_ERR(("get chanspecs failed with %d\n", err)); + goto exit; + } + + list = (wl_uint32_list_t *)(void *)buf; + for (i = 0; i < dtoh32(list->count); i++) { + c = dtoh32(list->element[i]); + if (channel <= CH_MAX_2G_CHANNEL) { + if (!CHSPEC_IS20(c)) + continue; + if (channel == CHSPEC_CHANNEL(c)) { + ret_c = c; + bw = 20; + goto exit; + } + } + if (CHSPEC_IS20(c)) { + tmp_c = CHSPEC_CHANNEL(c); + tmp_bw = WLC_BW_CAP_20MHZ; + } + else if (CHSPEC_IS40(c)) { + tmp_c = CHSPEC_CHANNEL(c); + if (CHSPEC_SB_UPPER(c)) { + tmp_c += CH_10MHZ_APART; + } else { + tmp_c -= CH_10MHZ_APART; + } + tmp_bw = WLC_BW_CAP_40MHZ; + } + else { + tmp_c = CHSPEC_CHANNEL(c); + sb = c & WL_CHANSPEC_CTL_SB_MASK; + if (sb == WL_CHANSPEC_CTL_SB_LL) { + tmp_c -= (CH_10MHZ_APART + CH_20MHZ_APART); + } else if (sb == WL_CHANSPEC_CTL_SB_LU) { + tmp_c -= CH_10MHZ_APART; + } else if (sb == WL_CHANSPEC_CTL_SB_UL) { + tmp_c += CH_10MHZ_APART; + } else { + /* WL_CHANSPEC_CTL_SB_UU */ + tmp_c += (CH_10MHZ_APART + CH_20MHZ_APART); + } + tmp_bw = WLC_BW_CAP_80MHZ; + } + if (tmp_c != channel) + continue; + + if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) { + bw = tmp_bw; + ret_c = c; + if (bw == bw_cap) + goto exit; + } + } +exit: + if (buf) + kfree(buf); +#undef LOCAL_BUF_SIZE + WL_INFO(("return chanspec %x %d\n", ret_c, bw)); + return ret_c; +} + +void +wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (cfg != NULL && ibss_vsie != NULL) { + if (cfg->ibss_vsie != NULL) { + kfree(cfg->ibss_vsie); + } + cfg->ibss_vsie = ibss_vsie; + cfg->ibss_vsie_len = ibss_vsie_len; + } +} + +static void +wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg) +{ + /* free & initiralize VSIE (Vendor Specific IE) */ + if (cfg->ibss_vsie != NULL) { + kfree(cfg->ibss_vsie); + cfg->ibss_vsie = NULL; + cfg->ibss_vsie_len = 0; + } +} + +s32 +wl_cfg80211_ibss_vsie_delete(struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + char *ioctl_buf = NULL; + s32 ret = BCME_OK; + + if (cfg != NULL && cfg->ibss_vsie != NULL) { + ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + return -ENOMEM; + } + + /* change the command from "add" to "del" */ + strncpy(cfg->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1); + cfg->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + ret = wldev_iovar_setbuf(dev, "ie", + cfg->ibss_vsie, cfg->ibss_vsie_len, + ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + WL_ERR(("ret=%d\n", ret)); + + if (ret == BCME_OK) { + /* free & initiralize VSIE */ + kfree(cfg->ibss_vsie); + cfg->ibss_vsie = NULL; + cfg->ibss_vsie_len = 0; + } + + if (ioctl_buf) { + kfree(ioctl_buf); + } + } + + return ret; +} + +static s32 +wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct cfg80211_bss *bss; + struct ieee80211_channel *chan; + struct wl_join_params join_params; + int scan_suppress; + struct cfg80211_ssid ssid; + s32 scan_retry = 0; + s32 err = 0; + size_t join_params_size; + chanspec_t chanspec = 0; + u32 param[2] = {0, 0}; + u32 bw_cap = 0; + + WL_TRACE(("In\n")); + RETURN_EIO_IF_NOT_UP(cfg); + WL_INFO(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid))); + if (!params->ssid || params->ssid_len <= 0 || + params->ssid_len > DOT11_MAX_SSID_LEN) { + WL_ERR(("Invalid parameter\n")); + return -EINVAL; + } +#if defined(WL_CFG80211_P2P_DEV_IF) + chan = params->chandef.chan; +#else + chan = params->channel; +#endif /* WL_CFG80211_P2P_DEV_IF */ + if (chan) + cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); + if (wl_get_drv_status(cfg, CONNECTED, dev)) { + struct wlc_ssid *ssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID); + u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID); + u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN); + if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) && + (memcmp(params->ssid, ssid->SSID, ssid->SSID_len) == 0) && + (*channel == cfg->channel))) { + WL_ERR(("Connection already existed to " MACDBG "\n", + MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID)))); + return -EISCONN; + } + WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n", + ssid->SSID, MAC2STRDBG(bssid))); + } + + /* remove the VSIE */ + wl_cfg80211_ibss_vsie_delete(dev); + + bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); + if (!bss) { + if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) { + memcpy(ssid.ssid, params->ssid, params->ssid_len); + ssid.ssid_len = params->ssid_len; + do { + if (unlikely + (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == + -EBUSY)) { + wl_delay(150); + } else { + break; + } + } while (++scan_retry < WL_SCAN_RETRY_MAX); + + /* rtnl lock code is removed here. don't see why rtnl lock + * needs to be released. + */ + + /* wait 4 secons till scan done.... */ + schedule_timeout_interruptible(msecs_to_jiffies(4000)); + + bss = cfg80211_get_ibss(wiphy, NULL, + params->ssid, params->ssid_len); + } + } + if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) || + ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid && + !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) { + cfg->ibss_starter = false; + WL_DBG(("Found IBSS\n")); + } else { + cfg->ibss_starter = true; + } + if (chan) { + if (chan->band == IEEE80211_BAND_5GHZ) + param[0] = WLC_BAND_5G; + else if (chan->band == IEEE80211_BAND_2GHZ) + param[0] = WLC_BAND_2G; + err = wldev_iovar_getint(dev, "bw_cap", param); + if (unlikely(err)) { + WL_ERR(("Get bw_cap Failed (%d)\n", err)); + return err; + } + bw_cap = param[0]; + chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap); + } + /* + * Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ + memset(&join_params, 0, sizeof(join_params)); + memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, + params->ssid_len); + join_params.ssid.SSID_len = htod32(params->ssid_len); + if (params->bssid) { + memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN); + err = wldev_ioctl(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid, + ETHER_ADDR_LEN, true); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + } else + memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); + wldev_iovar_setint(dev, "ibss_coalesce_allowed", IBSS_COALESCE_ALLOWED); + + if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { + scan_suppress = TRUE; + /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */ + err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, + &scan_suppress, sizeof(int), true); + if (unlikely(err)) { + WL_ERR(("Scan Suppress Setting Failed (%d)\n", err)); + return err; + } + } + + join_params.params.chanspec_list[0] = chanspec; + join_params.params.chanspec_num = 1; + wldev_iovar_setint(dev, "chanspec", chanspec); + join_params_size = sizeof(join_params); + + /* Disable Authentication, IBSS will add key if it required */ + wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED); + wldev_iovar_setint(dev, "wsec", 0); + +#ifdef WLAIBSS + /* Enable custom ibss features */ + err = wldev_iovar_setint(dev, "aibss", TRUE); + + if (unlikely(err)) { + WL_ERR(("Enable custom IBSS mode failed (%d)\n", err)); + return err; + } +#endif /* WLAIBSS */ + + err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, + join_params_size, true); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + + if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { + scan_suppress = FALSE; + /* Reset the SCAN SUPPRESS Flag */ + err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, + &scan_suppress, sizeof(int), true); + if (unlikely(err)) { + WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err)); + return err; + } + } + wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); + wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN); +#ifdef WLAIBSS + cfg->aibss_txfail_seq = 0; /* initialize the sequence */ +#endif /* WLAIBSS */ + cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */ + return err; +} + +static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + scb_val_t scbval; + u8 *curbssid; + + RETURN_EIO_IF_NOT_UP(cfg); + wl_link_down(cfg); + + WL_ERR(("Leave IBSS\n")); + curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); + wl_set_drv_status(cfg, DISCONNECTING, dev); + scbval.val = 0; + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), true); + if (unlikely(err)) { + wl_clr_drv_status(cfg, DISCONNECTING, dev); + WL_ERR(("error(%d)\n", err)); + return err; + } + + /* remove the VSIE */ + wl_cfg80211_ibss_vsie_delete(dev); + + return err; +} + +#ifdef MFP +static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa) +{ + u16 suite_count; + wpa_suite_mcast_t *mcast; + wpa_suite_ucast_t *ucast; + u16 len; + wpa_suite_auth_key_mgmt_t *mgmt; + + if (!wpa2ie) + return -1; + + len = wpa2ie->len; + mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; + if ((len -= WPA_SUITE_LEN) <= 0) + return BCME_BADLEN; + ucast = (wpa_suite_ucast_t *)&mcast[1]; + suite_count = ltoh16_ua(&ucast->count); + if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || + (len -= (WPA_IE_SUITE_COUNT_LEN + + (WPA_SUITE_LEN * suite_count))) <= 0) + return BCME_BADLEN; + + mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; + suite_count = ltoh16_ua(&mgmt->count); + + if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || + (len -= (WPA_IE_SUITE_COUNT_LEN + + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { + capa[0] = *(u8 *)&mgmt->list[suite_count]; + capa[1] = *((u8 *)&mgmt->list[suite_count] + 1); + } else + return BCME_BADLEN; + + return 0; +} +#endif /* MFP */ + +static s32 +wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + s32 val = 0; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) + val = WPA_AUTH_PSK | +#ifdef BCMCCX + WPA_AUTH_CCKM | +#endif + WPA_AUTH_UNSPECIFIED; + else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) + val = WPA2_AUTH_PSK| +#ifdef BCMCCX + WPA2_AUTH_CCKM | +#endif + WPA2_AUTH_UNSPECIFIED; + else + val = WPA_AUTH_DISABLED; + + if (is_wps_conn(sme)) + val = WPA_AUTH_DISABLED; + +#ifdef BCMWAPI_WPI + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { + WL_DBG((" * wl_set_wpa_version, set wpa_auth" + " to WPA_AUTH_WAPI 0x400")); + val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED; + } +#endif + WL_DBG(("setting wpa_auth to 0x%0x\n", val)); + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); + if (unlikely(err)) { + WL_ERR(("set wpa_auth failed (%d)\n", err)); + return err; + } + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + sec->wpa_versions = sme->crypto.wpa_versions; + return err; +} + +#ifdef BCMWAPI_WPI +static s32 +wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + WL_DBG((" %s \n", __FUNCTION__)); + + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { + err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", sme->ie, sme->ie_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + if (unlikely(err)) { + WL_ERR(("===> set_wapi_ie Error (%d)\n", err)); + return err; + } + } else + WL_DBG((" * skip \n")); + return err; +} +#endif /* BCMWAPI_WPI */ + +static s32 +wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + s32 val = 0; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + val = WL_AUTH_OPEN_SYSTEM; + WL_DBG(("open system\n")); + break; + case NL80211_AUTHTYPE_SHARED_KEY: + val = WL_AUTH_SHARED_KEY; + WL_DBG(("shared key\n")); + break; + case NL80211_AUTHTYPE_AUTOMATIC: + val = WL_AUTH_OPEN_SHARED; + WL_DBG(("automatic\n")); + break; +#ifdef BCMCCX + case NL80211_AUTHTYPE_NETWORK_EAP: + WL_DBG(("network eap\n")); + val = DOT11_LEAP_AUTH; + break; +#endif + default: + val = 2; + WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); + break; + } + + err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); + if (unlikely(err)) { + WL_ERR(("set auth failed (%d)\n", err)); + return err; + } + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + sec->auth_type = sme->auth_type; + return err; +} + +static s32 +wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + s32 pval = 0; + s32 gval = 0; + s32 err = 0; + s32 wsec_val = 0; +#ifdef MFP + s32 mfp = 0; + bcm_tlv_t *wpa2_ie; + u8 rsn_cap[2]; +#endif /* MFP */ + +#ifdef BCMWAPI_WPI + s32 val = 0; +#endif + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + 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: + case WLAN_CIPHER_SUITE_AES_CMAC: + pval = AES_ENABLED; + break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + val = SMS4_ENABLED; + pval = SMS4_ENABLED; + break; +#endif + 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; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + val = SMS4_ENABLED; + gval = SMS4_ENABLED; + break; +#endif + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } + + WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); + + if (is_wps_conn(sme)) { + if (sme->privacy) + err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + else + /* WPS-2.0 allows no security */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); + } else { +#ifdef BCMWAPI_WPI + if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) { + WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED")); + err = wldev_iovar_setint_bsscfg(dev, "wsec", val, bssidx); + } else { +#endif + WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); + wsec_val = pval | gval; + +#ifdef MFP + if (pval == AES_ENABLED) { + if (((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, + DOT11_MNG_RSN_ID)) != NULL) && + (wl_cfg80211_get_rsn_capa(wpa2_ie, rsn_cap) == 0)) { + + if (rsn_cap[0] & RSN_CAP_MFPC) { + /* MFP Capability advertised by supplicant. Check + * whether MFP is supported in the firmware + */ + if ((err = wldev_iovar_getint_bsscfg(dev, + "mfp", &mfp, bssidx)) < 0) { + WL_ERR(("Get MFP failed! " + "Check MFP support in FW \n")); + return -1; + } + + if ((sme->crypto.n_akm_suites == 1) && + ((sme->crypto.akm_suites[0] == + WL_AKM_SUITE_MFP_PSK) || + (sme->crypto.akm_suites[0] == + WL_AKM_SUITE_MFP_1X))) { + wsec_val |= MFP_SHA256; + } else if (sme->crypto.n_akm_suites > 1) { + WL_ERR(("Multiple AKM Specified \n")); + return -EINVAL; + } + + wsec_val |= MFP_CAPABLE; + if (rsn_cap[0] & RSN_CAP_MFPR) + wsec_val |= MFP_REQUIRED; + if (rsn_cap[0] & RSN_CAP_MFPR) + mfp = WL_MFP_REQUIRED; + else + mfp = WL_MFP_CAPABLE; + + err = wldev_iovar_setint_bsscfg(dev, "mfp", + mfp, bssidx); + } + } + } +#endif /* MFP */ + WL_DBG((" Set WSEC to fW 0x%x \n", wsec_val)); + err = wldev_iovar_setint_bsscfg(dev, "wsec", + wsec_val, bssidx); +#ifdef BCMWAPI_WPI + } +#endif + } + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; + sec->cipher_group = sme->crypto.cipher_group; + + return err; +} + +static s32 +wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + s32 val = 0; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + if (sme->crypto.n_akm_suites) { + err = wldev_iovar_getint(dev, "wpa_auth", &val); + if (unlikely(err)) { + WL_ERR(("could not get wpa_auth (%d)\n", err)); + return err; + } + if (val & (WPA_AUTH_PSK | +#ifdef BCMCCX + WPA_AUTH_CCKM | +#endif + 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; +#ifdef BCMCCX + case WLAN_AKM_SUITE_CCKM: + val = WPA_AUTH_CCKM; + break; +#endif + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } else if (val & (WPA2_AUTH_PSK | +#ifdef BCMCCX + WPA2_AUTH_CCKM | +#endif + WPA2_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA2_AUTH_UNSPECIFIED; + break; +#ifdef MFP + case WL_AKM_SUITE_MFP_1X: + val = WPA2_AUTH_UNSPECIFIED; + break; + case WL_AKM_SUITE_MFP_PSK: + val = WPA2_AUTH_PSK; + break; +#endif + case WLAN_AKM_SUITE_PSK: + val = WPA2_AUTH_PSK; + break; +#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X) + case WLAN_AKM_SUITE_FT_8021X: + val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; + break; +#endif +#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK) + case WLAN_AKM_SUITE_FT_PSK: + val = WPA2_AUTH_PSK | WPA2_AUTH_FT; + break; +#endif +#ifdef BCMCCX + case WLAN_AKM_SUITE_CCKM: + val = WPA2_AUTH_CCKM; + break; +#endif + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } +#ifdef BCMWAPI_WPI + else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_WAPI_CERT: + val = WAPI_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_WAPI_PSK: + val = WAPI_AUTH_PSK; + break; + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } +#endif + WL_DBG(("setting wpa_auth to %d\n", val)); + + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); + if (unlikely(err)) { + WL_ERR(("could not set wpa_auth (%d)\n", err)); + return err; + } + } + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + sec->wpa_auth = sme->crypto.akm_suites[0]; + + return err; +} + +static s32 +wl_set_set_sharedkey(struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_security *sec; + struct wl_wsec_key key; + s32 val; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + WL_DBG(("key len (%d)\n", sme->key_len)); + if (sme->key_len) { + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", + sec->wpa_versions, sec->cipher_pairwise)); + if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | +#ifdef BCMWAPI_WPI + NL80211_WPA_VERSION_2 | NL80211_WAPI_VERSION_1)) && +#else + NL80211_WPA_VERSION_2)) && +#endif + (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | +#ifdef BCMWAPI_WPI + WLAN_CIPHER_SUITE_WEP104 | WLAN_CIPHER_SUITE_SMS4))) +#else + WLAN_CIPHER_SUITE_WEP104))) +#endif + { + memset(&key, 0, sizeof(key)); + key.len = (u32) sme->key_len; + key.index = (u32) sme->key_idx; + if (unlikely(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 = WL_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; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + break; +#endif + default: + WL_ERR(("Invalid algorithm (%d)\n", + sme->crypto.ciphers_pairwise[0])); + return -EINVAL; + } + /* Set the new key/index */ + WL_DBG(("key length (%d) key index (%d) algo (%d)\n", + key.len, key.index, key.algo)); + WL_DBG(("key \"%s\"\n", key.data)); + swap_key_from_BE(&key); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { + WL_DBG(("set auth_type to shared key\n")); + val = WL_AUTH_SHARED_KEY; /* shared key */ + err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); + if (unlikely(err)) { + WL_ERR(("set auth failed (%d)\n", err)); + return err; + } + } + } + } + return err; +} + +#if defined(ESCAN_RESULT_PATCH) +static u8 connect_req_bssid[6]; +static u8 broad_bssid[6]; +#endif /* ESCAN_RESULT_PATCH */ + + + +#if defined(CONFIG_TCPACK_FASTTX) +static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd) +{ + u32 chanspec = 0; + bool isvht80 = 0; + + if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK) + chanspec = wl_chspec_driver_to_host(chanspec); + + isvht80 = chanspec & WL_CHANSPEC_BW_80; + WL_INFO(("%s: chanspec(%x:%d)\n", __FUNCTION__, chanspec, isvht80)); + + return isvht80; +} +#endif + +static s32 +wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct ieee80211_channel *chan = sme->channel; + wl_extjoin_params_t *ext_join_params; + struct wl_join_params join_params; + size_t join_params_size; +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + s32 roam_trigger[2] = {0, 0}; +#endif /* ROAM_AP_ENV_DETECTION */ + s32 err = 0; + wpa_ie_fixed_t *wpa_ie; + bcm_tlv_t *wpa2_ie; + u8* wpaie = 0; + u32 wpaie_len = 0; + u32 chan_cnt = 0; + struct ether_addr bssid; + s32 bssidx; + int ret; + int wait_cnt; + + WL_DBG(("In\n")); + + if (unlikely(!sme->ssid)) { + WL_ERR(("Invalid ssid\n")); + return -EOPNOTSUPP; + } + + if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) { + WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n", + sme->ssid, sme->ssid_len)); + return -EINVAL; + } + + RETURN_EIO_IF_NOT_UP(cfg); + + /* + * Cancel ongoing scan to sync up with sme state machine of cfg80211. + */ +#if !defined(ESCAN_RESULT_PATCH) + if (cfg->scan_request) { + wl_notify_escan_complete(cfg, dev, true, true); + } +#endif +#ifdef WL_SCHED_SCAN + if (cfg->sched_scan_req) { + wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg)); + } +#endif +#if defined(ESCAN_RESULT_PATCH) + if (sme->bssid) + memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); + else + bzero(connect_req_bssid, ETHER_ADDR_LEN); + bzero(broad_bssid, ETHER_ADDR_LEN); +#endif +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) + maxrxpktglom = 0; +#endif + bzero(&bssid, sizeof(bssid)); + if (!wl_get_drv_status(cfg, CONNECTED, dev)&& + (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { + if (!ETHER_ISNULLADDR(&bssid)) { + scb_val_t scbval; + wl_set_drv_status(cfg, DISCONNECTING, dev); + scbval.val = DOT11_RC_DISASSOC_LEAVING; + memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + + WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n", + MAC2STRDBG(bssid.octet))); + err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), true); + if (unlikely(err)) { + wl_clr_drv_status(cfg, DISCONNECTING, dev); + WL_ERR(("error (%d)\n", err)); + return err; + } + wait_cnt = 500/10; + while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) { + WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", + wait_cnt)); + wait_cnt--; + OSL_SLEEP(10); + } + } else + WL_DBG(("Currently not associated!\n")); + } else { + /* if status is DISCONNECTING, wait for disconnection terminated max 500 ms */ + wait_cnt = 500/10; + while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) { + WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt)); + wait_cnt--; + OSL_SLEEP(10); + } + } + + /* Clean BSSID */ + bzero(&bssid, sizeof(bssid)); + if (!wl_get_drv_status(cfg, DISCONNECTING, dev)) + wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID); + + if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) { + /* we only allow to connect using virtual interface in case of P2P */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); + } else if (dev == bcmcfg_to_prmry_ndev(cfg)) { + /* find the RSN_IE */ + if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE is found\n")); + } + /* find the WPA_IE */ + if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, + sme->ie_len)) != NULL) { + WL_DBG((" WPA IE is found\n")); + } + if (wpa_ie != NULL || wpa2_ie != NULL) { + wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; + wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; + wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; + wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + } else { + wldev_iovar_setbuf(dev, "wpaie", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + } + + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len); + if (unlikely(err)) { + return err; + } + } +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + if (dhd->roam_env_detection) { + bool is_roamtrig_reset = TRUE; + bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection", + AP_ENV_DETECT_NOT_USED) == BCME_OK); + if (is_roamtrig_reset && is_roam_env_ok) { + roam_trigger[0] = WL_AUTO_ROAM_TRIGGER; + roam_trigger[1] = WLC_BAND_ALL; + err = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), true); + if (unlikely(err)) { + WL_ERR((" failed to restore roam_trigger for auto env" + " detection\n")); + } + } + } +#endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */ + if (chan) { + cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); + chan_cnt = 1; + WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel, + chan->center_freq, chan_cnt)); + } else + cfg->channel = 0; +#ifdef BCMWAPI_WPI + WL_DBG(("1. enable wapi auth\n")); + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { + WL_DBG(("2. set wapi ie \n")); + err = wl_set_set_wapi_ie(dev, sme); + if (unlikely(err)) + return err; + } else + WL_DBG(("2. Not wapi ie \n")); +#endif + WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); + WL_DBG(("3. set wapi version \n")); + err = wl_set_wpa_version(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid wpa_version\n")); + return err; + } +#ifdef BCMWAPI_WPI + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) + WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n")); + else { + WL_DBG(("4. wl_set_auth_type\n")); +#endif + err = wl_set_auth_type(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid auth type\n")); + return err; + } +#ifdef BCMWAPI_WPI + } +#endif + + err = wl_set_set_cipher(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid ciper\n")); + return err; + } + + err = wl_set_key_mgmt(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid key mgmt\n")); + return err; + } + + err = wl_set_set_sharedkey(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid shared key\n")); + return err; + } + + /* + * Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ + join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + + chan_cnt * sizeof(chanspec_t); + ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL); + if (ext_join_params == NULL) { + err = -ENOMEM; + wl_clr_drv_status(cfg, CONNECTING, dev); + goto exit; + } + ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); + memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); + wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID); + ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); + /* increate dwell time to receive probe response or detect Beacon + * from target AP at a noisy air only during connect command + */ + ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1; + ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1; + /* Set up join scan parameters */ + ext_join_params->scan.scan_type = -1; + ext_join_params->scan.nprobes = chan_cnt ? + (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1; + ext_join_params->scan.home_time = -1; + + if (sme->bssid) + memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN); + else + memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN); + ext_join_params->assoc.chanspec_num = chan_cnt; + if (chan_cnt) { + u16 channel, band, bw, ctl_sb; + chanspec_t chspec; + channel = cfg->channel; + band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G + : WL_CHANSPEC_BAND_5G; + bw = WL_CHANSPEC_BW_20; + ctl_sb = WL_CHANSPEC_CTL_SB_NONE; + chspec = (channel | band | bw | ctl_sb); + ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + ext_join_params->assoc.chanspec_list[0] |= chspec; + ext_join_params->assoc.chanspec_list[0] = + wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); + } + ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); + if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { + WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID, + ext_join_params->ssid.SSID_len)); + } + wl_set_drv_status(cfg, CONNECTING, dev); + + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + kfree(ext_join_params); + return BCME_ERROR; + } + err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + WL_ERR(("Connectting with" MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n", + MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), cfg->channel, + ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len)); + + kfree(ext_join_params); + if (err) { + wl_clr_drv_status(cfg, CONNECTING, dev); + if (err == BCME_UNSUPPORTED) { + WL_DBG(("join iovar is not supported\n")); + goto set_ssid; + } else { + WL_ERR(("error (%d)\n", err)); + goto exit; + } + } else + goto exit; + +set_ssid: + memset(&join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params.ssid); + + join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len); + memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); + join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); + wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); + if (sme->bssid) + memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); + else + memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); + + wl_ch_to_chanspec(cfg->channel, &join_params, &join_params_size); + WL_DBG(("join_param_size %zu\n", join_params_size)); + + if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { + WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, + join_params.ssid.SSID_len)); + } + wl_set_drv_status(cfg, CONNECTING, dev); + err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true); + if (err) { + WL_ERR(("error (%d)\n", err)); + wl_clr_drv_status(cfg, CONNECTING, dev); + } +exit: + return err; +} + +static s32 +wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + scb_val_t scbval; + bool act = false; + s32 err = 0; + u8 *curbssid; + WL_ERR(("Reason %d\n", reason_code)); + RETURN_EIO_IF_NOT_UP(cfg); + act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT); + curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); + if (act) { + /* + * Cancel ongoing scan to sync up with sme state machine of cfg80211. + */ +#if !defined(ESCAN_RESULT_PATCH) + /* Let scan aborted by F/W */ + if (cfg->scan_request) { + wl_notify_escan_complete(cfg, dev, true, true); + } +#endif /* ESCAN_RESULT_PATCH */ + wl_set_drv_status(cfg, DISCONNECTING, dev); + scbval.val = reason_code; + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), true); + if (unlikely(err)) { + wl_clr_drv_status(cfg, DISCONNECTING, dev); + WL_ERR(("error (%d)\n", err)); + return err; + } + } + + return err; +} + +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 mbm) +#else +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, s32 dbm) +#endif /* WL_CFG80211_P2P_DEV_IF */ +{ + + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; +#if defined(WL_CFG80211_P2P_DEV_IF) + s32 dbm = MBM_TO_DBM(mbm); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \ + defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES) + dbm = MBM_TO_DBM(dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ + + RETURN_EIO_IF_NOT_UP(cfg); + switch (type) { + case NL80211_TX_POWER_AUTOMATIC: + break; + case NL80211_TX_POWER_LIMITED: + if (dbm < 0) { + WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n")); + return -EINVAL; + } + break; + case NL80211_TX_POWER_FIXED: + if (dbm < 0) { + WL_ERR(("TX_POWER_FIXED - dbm is negative..\n")); + return -EINVAL; + } + break; + } + + err = wl_set_tx_power(ndev, type, dbm); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + cfg->conf->tx_power = dbm; + + return err; +} + +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, s32 *dbm) +#else +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +#endif /* WL_CFG80211_P2P_DEV_IF */ +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; + + RETURN_EIO_IF_NOT_UP(cfg); + err = wl_get_tx_power(ndev, dbm); + if (unlikely(err)) + WL_ERR(("error (%d)\n", err)); + + return err; +} + +static s32 +wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool unicast, bool multicast) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + u32 index; + s32 wsec; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + WL_DBG(("key index (%d)\n", key_idx)); + RETURN_EIO_IF_NOT_UP(cfg); + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); + if (unlikely(err)) { + WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); + return err; + } + if (wsec == WEP_ENABLED) { + /* Just select a new current key */ + index = (u32) key_idx; + index = htod32(index); + err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, + sizeof(index), true); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + } + } + return err; +} + +static s32 +wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, struct key_params *params) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct wl_wsec_key key; + s32 err = 0; + s32 bssidx; + s32 mode = wl_get_mode_by_netdev(cfg, dev); + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + memset(&key, 0, sizeof(key)); + key.index = (u32) key_idx; + + if (!ETHER_ISMULTI(mac_addr)) + memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); + key.len = (u32) params->key_len; + + /* check for key index change */ + if (key.len == 0) { + /* key delete */ + swap_key_from_BE(&key); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("key delete error (%d)\n", err)); + return err; + } + } else { + if (key.len > sizeof(key.data)) { + WL_ERR(("Invalid key length (%d)\n", key.len)); + return -EINVAL; + } + WL_DBG(("Setting the key index %d\n", key.index)); + memcpy(key.data, params->key, key.len); + + if ((mode == WL_MODE_BSS) && + (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_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + break; + case WLAN_CIPHER_SUITE_TKIP: + key.algo = CRYPTO_ALGO_TKIP; + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + case WLAN_CIPHER_SUITE_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); + break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); + break; +#endif + default: + WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); + return -EINVAL; + } + swap_key_from_BE(&key); + /* need to guarantee EAPOL 4/4 send out before set key */ + dhd_wait_pend8021x(dev); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + } + return err; +} + +int +wl_cfg80211_enable_roam_offload(struct net_device *dev, bool enable) +{ + int err; + wl_eventmsg_buf_t ev_buf; + + if (dev != bcmcfg_to_prmry_ndev(g_bcm_cfg)) { + /* roam offload is only for the primary device */ + return -1; + } + err = wldev_iovar_setint(dev, "roam_offload", (int)enable); + if (err) + return err; + + bzero(&ev_buf, sizeof(wl_eventmsg_buf_t)); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable); + wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable); + err = wl_cfg80211_apply_eventbuffer(dev, g_bcm_cfg, &ev_buf); + if (!err) { + g_bcm_cfg->roam_offload = enable; + } + return err; +} + +static s32 +wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + struct wl_wsec_key key; + s32 val = 0; + s32 wsec = 0; + s32 err = 0; + u8 keybuf[8]; + s32 bssidx = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 mode = wl_get_mode_by_netdev(cfg, dev); + WL_DBG(("key index (%d)\n", key_idx)); + RETURN_EIO_IF_NOT_UP(cfg); + + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + if (mac_addr && + ((params->cipher != WLAN_CIPHER_SUITE_WEP40) && + (params->cipher != WLAN_CIPHER_SUITE_WEP104))) { + wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); + goto exit; + } + memset(&key, 0, sizeof(key)); + + key.len = (u32) params->key_len; + key.index = (u32) key_idx; + + if (unlikely(key.len > sizeof(key.data))) { + WL_ERR(("Too long key length (%u)\n", key.len)); + return -EINVAL; + } + memcpy(key.data, params->key, key.len); + + key.flags = WL_PRIMARY_KEY; + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + val = WEP_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + val = WEP_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + break; + case WLAN_CIPHER_SUITE_TKIP: + key.algo = CRYPTO_ALGO_TKIP; + val = TKIP_ENABLED; + /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ + if (mode == WL_MODE_BSS) { + bcopy(&key.data[24], keybuf, sizeof(keybuf)); + bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); + bcopy(keybuf, &key.data[16], sizeof(keybuf)); + } + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key.algo = CRYPTO_ALGO_AES_CCM; + val = AES_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + case WLAN_CIPHER_SUITE_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + val = AES_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); + break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); + val = SMS4_ENABLED; + break; +#endif /* BCMWAPI_WPI */ +#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK) + case WLAN_CIPHER_SUITE_PMK: { + int j; + wsec_pmk_t pmk; + char keystring[WSEC_MAX_PSK_LEN + 1]; + char* charptr = keystring; + uint len; + struct wl_security *sec; + + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + if (sec->wpa_auth == WLAN_AKM_SUITE_8021X) { + err = wldev_iovar_setbuf(dev, "okc_info_pmk", params->key, + WSEC_MAX_PSK_LEN / 2, keystring, sizeof(keystring), NULL); + if (err) { + /* could fail in case that 'okc' is not supported */ + WL_INFO(("Setting 'okc_info_pmk' failed, err=%d\n", err)); + } + } + /* copy the raw hex key to the appropriate format */ + for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { + sprintf(charptr, "%02x", params->key[j]); + charptr += 2; + } + len = strlen(keystring); + pmk.key_len = htod16(len); + bcopy(keystring, pmk.key, len); + pmk.flags = htod16(WSEC_PASSPHRASE); + + err = wldev_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk), true); + if (err) + return err; + } break; +#endif /* WLFBT && WLAN_CIPHER_SUITE_PMK */ + default: + WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); + return -EINVAL; + } + + /* Set the new key/index */ + if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) { + WL_ERR(("IBSS KEY setted\n")); + wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE); + } + swap_key_from_BE(&key); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, + WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + +exit: + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); + if (unlikely(err)) { + WL_ERR(("get wsec error (%d)\n", err)); + return err; + } + + wsec |= val; + err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); + if (unlikely(err)) { + WL_ERR(("set wsec error (%d)\n", err)); + return err; + } + + return err; +} + +static s32 +wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr) +{ + struct wl_wsec_key key; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + WL_DBG(("Enter\n")); + +#ifndef IEEE80211W + if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) + return -EINVAL; +#endif + + RETURN_EIO_IF_NOT_UP(cfg); + memset(&key, 0, sizeof(key)); + + key.flags = WL_PRIMARY_KEY; + key.algo = CRYPTO_ALGO_OFF; + key.index = (u32) key_idx; + + WL_DBG(("key index (%d)\n", key_idx)); + /* Set the new key/index */ + swap_key_from_BE(&key); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, + WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + if (err == -EINVAL) { + if (key.index >= DOT11_MAX_DEFAULT_KEYS) { + /* we ignore this key index in this case */ + WL_DBG(("invalid key index (%d)\n", key_idx)); + } + } else { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + } + return err; + } + return err; +} + +static s32 +wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback) (void *cookie, struct key_params * params)) +{ + struct key_params params; + struct wl_wsec_key key; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct wl_security *sec; + s32 wsec; + s32 err = 0; + s32 bssidx; + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + WL_DBG(("key index (%d)\n", key_idx)); + RETURN_EIO_IF_NOT_UP(cfg); + memset(&key, 0, sizeof(key)); + key.index = key_idx; + swap_key_to_BE(&key); + memset(¶ms, 0, sizeof(params)); + params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); + memcpy(params.key, key.data, params.key_len); + + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); + if (unlikely(err)) { + WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); + return err; + } + switch (wsec & ~SES_OW_ENABLED) { + case WEP_ENABLED: + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { + params.cipher = WLAN_CIPHER_SUITE_WEP40; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { + params.cipher = WLAN_CIPHER_SUITE_WEP104; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + } + break; + case TKIP_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_TKIP; + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case AES_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); + break; +#endif + default: + WL_ERR(("Invalid algo (0x%x)\n", wsec)); + return -EINVAL; + } + + callback(cookie, ¶ms); + return err; +} + +static s32 +wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx) +{ +#ifdef MFP + return 0; +#else + WL_INFO(("Not supported\n")); + return -EOPNOTSUPP; +#endif /* MFP */ +} + +static s32 +wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + scb_val_t scb_val; + s32 rssi; + s32 rate; + s32 err = 0; + sta_info_t *sta; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + s8 eabuf[ETHER_ADDR_STR_LEN]; +#endif + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + RETURN_EIO_IF_NOT_UP(cfg); + if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { + err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, + ETHER_ADDR_LEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); + if (err < 0) { + WL_ERR(("GET STA INFO failed, %d\n", err)); + return err; + } + sinfo->filled = STATION_INFO_INACTIVE_TIME; + sta = (sta_info_t *)cfg->ioctl_buf; + sta->len = dtoh16(sta->len); + sta->cap = dtoh16(sta->cap); + sta->flags = dtoh32(sta->flags); + sta->idle = dtoh32(sta->idle); + sta->in = dtoh32(sta->in); + sinfo->inactive_time = sta->idle * 1000; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (sta->flags & WL_STA_ASSOC) { + sinfo->filled |= STATION_INFO_CONNECTED_TIME; + sinfo->connected_time = sta->in; + } + WL_INFO(("STA %s : idle time : %d sec, connected time :%d ms\n", + bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time, + sta->idle * 1000)); +#endif + } else if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS || + wl_get_mode_by_netdev(cfg, dev) == WL_MODE_IBSS) { + get_pktcnt_t pktcnt; + u8 *curmacp; + + if (cfg->roam_offload) { + struct ether_addr bssid; + memset(&bssid, 0, sizeof(bssid)); + err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + if (err) { + WL_ERR(("Failed to get current BSSID\n")); + } else { + if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) { + /* roaming is detected */ + err = wl_cfg80211_delayed_roam(cfg, dev, &bssid); + if (err) + WL_ERR(("Failed to handle the delayed roam, " + "err=%d", err)); + mac = (u8 *)bssid.octet; + } + } + } + if (!wl_get_drv_status(cfg, CONNECTED, dev) || + (dhd_is_associated(dhd, NULL, &err) == FALSE)) { + WL_ERR(("NOT assoc\n")); + if (err == -ERESTARTSYS) + return err; + err = -ENODEV; + return err; + } + curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID); + if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { + WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n", + MAC2STRDBG(mac), MAC2STRDBG(curmacp))); + } + + /* Report the current tx rate */ + rate = 0; + err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); + if (err) { + WL_ERR(("Could not get rate (%d)\n", err)); + } else { +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) + int rxpktglom; +#endif + rate = dtoh32(rate); + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = rate * 5; + WL_DBG(("Rate %d Mbps\n", (rate / 2))); +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) + rxpktglom = ((rate/2) > 150) ? 20 : 10; + + if (maxrxpktglom != rxpktglom) { + maxrxpktglom = rxpktglom; + WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2), + maxrxpktglom)); + err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom", + (char*)&maxrxpktglom, 4, cfg->ioctl_buf, + WLC_IOCTL_MAXLEN, NULL); + if (err < 0) { + WL_ERR(("set bus:maxtxpktglom failed, %d\n", err)); + } + } +#endif + } + + memset(&scb_val, 0, sizeof(scb_val)); + scb_val.val = 0; + err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, + sizeof(scb_val_t), false); + if (err) { + WL_ERR(("Could not get rssi (%d)\n", err)); + goto get_station_err; + } + rssi = wl_rssi_offset(dtoh32(scb_val.val)); + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = rssi; + WL_DBG(("RSSI %d dBm\n", rssi)); + memset(&pktcnt, 0, sizeof(pktcnt)); + err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt, + sizeof(pktcnt), false); + if (!err) { + sinfo->filled |= (STATION_INFO_RX_PACKETS | + STATION_INFO_RX_DROP_MISC | + STATION_INFO_TX_PACKETS | + STATION_INFO_TX_FAILED); + sinfo->rx_packets = pktcnt.rx_good_pkt; + sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt; + sinfo->tx_packets = pktcnt.tx_good_pkt; + sinfo->tx_failed = pktcnt.tx_bad_pkt; + } +get_station_err: + if (err && (err != -ERESTARTSYS)) { + /* Disconnect due to zero BSSID or error to get RSSI */ + WL_ERR(("force cfg80211_disconnected: %d\n", err)); + wl_clr_drv_status(cfg, CONNECTED, dev); + cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL); + wl_link_down(cfg); + } + } + else { + WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev))); + } + + return err; +} + +static s32 +wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, s32 timeout) +{ + s32 pm; + s32 err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev); + + RETURN_EIO_IF_NOT_UP(cfg); + WL_DBG(("Enter\n")); + if (cfg->p2p_net == dev || _net_info == NULL || cfg->vsdb_mode || + !wl_get_drv_status(cfg, CONNECTED, dev)) { + return err; + } + + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_PEND); + + pm = enabled ? PM_FAST : PM_OFF; + if (_net_info->pm_block) { + WL_ERR(("%s:Do not enable the power save for pm_block %d\n", + dev->name, _net_info->pm_block)); + pm = PM_OFF; + } + pm = htod32(pm); + WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled"))); + err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true); + if (unlikely(err)) { + if (err == -ENODEV) + WL_DBG(("net_device is not ready yet\n")); + else + WL_ERR(("error (%d)\n", err)); + return err; + } + wl_cfg80211_update_power_mode(dev); + return err; +} + +void wl_cfg80211_update_power_mode(struct net_device *dev) +{ + int err, pm = -1; + + err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), false); + if (err) + WL_ERR(("%s:error (%d)\n", __FUNCTION__, err)); + else if (pm != -1 && dev->ieee80211_ptr) + dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true; +} + +static __used u32 wl_find_msb(u16 bit16) +{ + u32 ret = 0; + + if (bit16 & 0xff00) { + ret += 8; + bit16 >>= 8; + } + + if (bit16 & 0xf0) { + ret += 4; + bit16 >>= 4; + } + + if (bit16 & 0xc) { + ret += 2; + bit16 >>= 2; + } + + if (bit16 & 2) + ret += bit16 & 2; + else if (bit16) + ret += bit16; + + return ret; +} + +static s32 wl_cfg80211_resume(struct wiphy *wiphy) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; + + if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) { + WL_INFO(("device is not ready\n")); + return 0; + } + + return err; +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) +static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) +#else +static s32 wl_cfg80211_suspend(struct wiphy *wiphy) +#endif +{ +#ifdef DHD_CLEAR_ON_SUSPEND + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_info *iter, *next; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + unsigned long flags; + if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) { + WL_INFO(("device is not ready : status (%d)\n", + (int)cfg->status)); + return 0; + } + for_each_ndev(cfg, iter, next) + wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + if (cfg->scan_request) { + cfg80211_scan_done(cfg->scan_request, true); + cfg->scan_request = NULL; + } + for_each_ndev(cfg, iter, next) { + wl_clr_drv_status(cfg, SCANNING, iter->ndev); + wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev); + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + for_each_ndev(cfg, iter, next) { + if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) { + wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false); + } + } +#endif /* DHD_CLEAR_ON_SUSPEND */ + return 0; +} + +static s32 +wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, + s32 err) +{ + int i, j; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); + + if (!pmk_list) { + printk("pmk_list is NULL\n"); + return -EINVAL; + } + /* pmk list is supported only for STA interface i.e. primary interface + * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init + */ + if (primary_dev != dev) { + WL_INFO(("Not supporting Flushing pmklist on virtual" + " interfaces than primary interface\n")); + return err; + } + + WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid)); + for (i = 0; i < pmk_list->pmkids.npmkid; i++) { + WL_DBG(("PMKID[%d]: %pM =\n", i, + &pmk_list->pmkids.pmkid[i].BSSID)); + for (j = 0; j < WPA2_PMKID_LEN; j++) { + WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j])); + } + } + if (likely(!err)) { + err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, + sizeof(*pmk_list), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + } + + return err; +} + +static s32 +wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + int i; + + RETURN_EIO_IF_NOT_UP(cfg); + for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++) + if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN)) + break; + if (i < WL_NUM_PMKIDS_MAX) { + memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, + ETHER_ADDR_LEN); + memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, + WPA2_PMKID_LEN); + if (i == cfg->pmk_list->pmkids.npmkid) + cfg->pmk_list->pmkids.npmkid++; + } else { + err = -EINVAL; + } + WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", + &cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].BSSID)); + for (i = 0; i < WPA2_PMKID_LEN; i++) { + WL_DBG(("%02x\n", + cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1]. + PMKID[i])); + } + + err = wl_update_pmklist(dev, cfg->pmk_list, err); + + return err; +} + +static s32 +wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct _pmkid_list pmkid = {0}; + s32 err = 0; + int i; + + RETURN_EIO_IF_NOT_UP(cfg); + memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); + memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); + + WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", + &pmkid.pmkid[0].BSSID)); + for (i = 0; i < WPA2_PMKID_LEN; i++) { + WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i])); + } + + for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++) + if (!memcmp + (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN)) + break; + + if ((cfg->pmk_list->pmkids.npmkid > 0) && + (i < cfg->pmk_list->pmkids.npmkid)) { + memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t)); + for (; i < (cfg->pmk_list->pmkids.npmkid - 1); i++) { + memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, + &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID, + ETHER_ADDR_LEN); + memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, + &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID, + WPA2_PMKID_LEN); + } + cfg->pmk_list->pmkids.npmkid--; + } else { + err = -EINVAL; + } + + err = wl_update_pmklist(dev, cfg->pmk_list, err); + + return err; + +} + +static s32 +wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + RETURN_EIO_IF_NOT_UP(cfg); + memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list)); + err = wl_update_pmklist(dev, cfg->pmk_list, err); + return err; + +} + +static wl_scan_params_t * +wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) +{ + wl_scan_params_t *params; + int params_size; + int num_chans; + + *out_params_size = 0; + + /* Our scan params only need space for 1 channel and 0 ssids */ + params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); + params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); + if (params == NULL) { + WL_ERR(("mem alloc failed (%d bytes)\n", params_size)); + return params; + } + memset(params, 0, params_size); + params->nprobes = nprobes; + + num_chans = (channel == 0) ? 0 : 1; + + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + params->bss_type = DOT11_BSSTYPE_ANY; + params->scan_type = DOT11_SCANTYPE_ACTIVE; + params->nprobes = htod32(1); + params->active_time = htod32(-1); + params->passive_time = htod32(-1); + params->home_time = htod32(10); + if (channel == -1) + params->channel_list[0] = htodchanspec(channel); + else + params->channel_list[0] = wl_ch_host_to_driver(channel); + + /* Our scan params have 1 channel and 0 ssids */ + params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | + (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); + + *out_params_size = params_size; /* rtn size to the caller */ + return params; +} + +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel *channel, unsigned int duration, u64 *cookie) +#else +static s32 +wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel * channel, + enum nl80211_channel_type channel_type, + unsigned int duration, u64 *cookie) +#endif /* WL_CFG80211_P2P_DEV_IF */ +{ + s32 target_channel; + u32 id; + s32 err = BCME_OK; + struct ether_addr primary_mac; + struct net_device *ndev = NULL; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n", + ieee80211_frequency_to_channel(channel->center_freq), + duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO")); + + if (!cfg->p2p) { + WL_ERR(("cfg->p2p is not initialized\n")); + err = BCME_ERROR; + goto exit; + } + +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (wl_get_drv_status_all(cfg, SCANNING)) { + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); + } +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + + target_channel = ieee80211_frequency_to_channel(channel->center_freq); + memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel)); +#if defined(WL_ENABLE_P2P_IF) + cfg->remain_on_chan_type = channel_type; +#endif /* WL_ENABLE_P2P_IF */ + id = ++cfg->last_roc_id; + if (id == 0) + id = ++cfg->last_roc_id; + *cookie = id; + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (wl_get_drv_status(cfg, SCANNING, ndev)) { + struct timer_list *_timer; + WL_DBG(("scan is running. go to fake listen state\n")); + + wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); + + if (timer_pending(&cfg->p2p->listen_timer)) { + WL_DBG(("cancel current listen timer \n")); + del_timer_sync(&cfg->p2p->listen_timer); + } + + _timer = &cfg->p2p->listen_timer; + wl_clr_p2p_status(cfg, LISTEN_EXPIRED); + + INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0); + + err = BCME_OK; + goto exit; + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +#ifdef WL_CFG80211_SYNC_GON + if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { + /* do not enter listen mode again if we are in listen mode already for next af. + * remain on channel completion will be returned by waiting next af completion. + */ +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); +#else + wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + goto exit; + } +#endif /* WL_CFG80211_SYNC_GON */ + if (cfg->p2p && !cfg->p2p->on) { + /* In case of p2p_listen command, supplicant send remain_on_channel + * without turning on P2P + */ + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr, &cfg->p2p->int_addr); + p2p_on(cfg) = true; + } + + if (p2p_is_on(cfg)) { + err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0); + if (unlikely(err)) { + goto exit; + } +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + err = wl_cfgp2p_discover_listen(cfg, target_channel, duration); + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (err == BCME_OK) { + wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); + } else { + /* if failed, firmware may be internal scanning state. + * so other scan request shall not abort it + */ + wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant + * and expire timer will send a completion to the upper layer + */ + err = BCME_OK; + } + +exit: + if (err == BCME_OK) { + WL_INFO(("Success\n")); +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_ready_on_channel(cfgdev, *cookie, channel, + duration, GFP_KERNEL); +#else + cfg80211_ready_on_channel(cfgdev, *cookie, channel, + channel_type, duration, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ + } else { + WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); + } + return err; +} + +static s32 +wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + bcm_struct_cfgdev *cfgdev, u64 cookie) +{ + s32 err = 0; + +#if defined(WL_CFG80211_P2P_DEV_IF) + if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { + WL_DBG((" enter ) on P2P dedicated discover interface\n")); + } +#else + WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex)); +#endif /* WL_CFG80211_P2P_DEV_IF */ + return err; +} + +static void +wl_cfg80211_afx_handler(struct work_struct *work) +{ + struct afx_hdl *afx_instance; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + s32 ret = BCME_OK; + + afx_instance = container_of(work, struct afx_hdl, work); + if (afx_instance != NULL && cfg->afx_hdl->is_active) { + if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) { + ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan, + (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */ + } else { + ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev, + cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan, + NULL); + } + if (unlikely(ret != BCME_OK)) { + WL_ERR(("ERROR occurred! returned value is (%d)\n", ret)); + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) + complete(&cfg->act_frm_scan); + } + } +} + +static s32 +wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev) +{ + u32 max_retry = WL_CHANNEL_SYNC_RETRY; + + if (dev == NULL) + return -1; + + WL_DBG((" enter ) \n")); + + wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev); + cfg->afx_hdl->is_active = TRUE; + + /* Loop to wait until we find a peer's channel or the + * pending action frame tx is cancelled. + */ + while ((cfg->afx_hdl->retry < max_retry) && + (cfg->afx_hdl->peer_chan == WL_INVALID)) { + cfg->afx_hdl->is_listen = FALSE; + wl_set_drv_status(cfg, SCANNING, dev); + WL_DBG(("Scheduling the action frame for sending.. retry %d\n", + cfg->afx_hdl->retry)); + /* search peer on peer's listen channel */ + schedule_work(&cfg->afx_hdl->work); + wait_for_completion_timeout(&cfg->act_frm_scan, + msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); + + if ((cfg->afx_hdl->peer_chan != WL_INVALID) || + !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) + break; + + if (cfg->afx_hdl->my_listen_chan) { + WL_DBG(("Scheduling Listen peer in my listen channel = %d\n", + cfg->afx_hdl->my_listen_chan)); + /* listen on my listen channel */ + cfg->afx_hdl->is_listen = TRUE; + schedule_work(&cfg->afx_hdl->work); + wait_for_completion_timeout(&cfg->act_frm_scan, + msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); + } + if ((cfg->afx_hdl->peer_chan != WL_INVALID) || + !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) + break; + + cfg->afx_hdl->retry++; + + WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg); + } + + cfg->afx_hdl->is_active = FALSE; + + wl_clr_drv_status(cfg, SCANNING, dev); + wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev); + + return (cfg->afx_hdl->peer_chan); +} + +struct p2p_config_af_params { + s32 max_tx_retry; /* max tx retry count if tx no ack */ + /* To make sure to send successfully action frame, we have to turn off mpc + * 0: off, 1: on, (-1): do nothing + */ + s32 mpc_onoff; +#ifdef WL_CFG80211_SYNC_GON + bool extra_listen; +#endif + bool search_channel; /* 1: search peer's channel to send af */ +}; + +static s32 +wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, + wl_action_frame_t *action_frame, wl_af_params_t *af_params, + struct p2p_config_af_params *config_af_params) +{ + s32 err = BCME_OK; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + wifi_p2p_pub_act_frame_t *act_frm = + (wifi_p2p_pub_act_frame_t *) (action_frame->data); + + /* initialize default value */ +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = true; +#endif + config_af_params->search_channel = false; + config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; + config_af_params->mpc_onoff = -1; + cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; + + switch (act_frm->subtype) { + case P2P_PAF_GON_REQ: { + WL_DBG(("P2P: GO_NEG_PHASE status set \n")); + wl_set_p2p_status(cfg, GO_NEG_PHASE); + + config_af_params->mpc_onoff = 0; + config_af_params->search_channel = true; + cfg->next_af_subtype = act_frm->subtype + 1; + + /* increase dwell time to wait for RESP frame */ + af_params->dwell_time = WL_MED_DWELL_TIME; + + break; + } + case P2P_PAF_GON_RSP: { + cfg->next_af_subtype = act_frm->subtype + 1; + /* increase dwell time to wait for CONF frame */ + af_params->dwell_time = WL_MED_DWELL_TIME + 100; + break; + } + case P2P_PAF_GON_CONF: { + /* If we reached till GO Neg confirmation reset the filter */ + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + + /* turn on mpc again if go nego is done */ + config_af_params->mpc_onoff = 1; + + /* minimize dwell time */ + af_params->dwell_time = WL_MIN_DWELL_TIME; + +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + } + case P2P_PAF_INVITE_REQ: { + config_af_params->search_channel = true; + cfg->next_af_subtype = act_frm->subtype + 1; + + /* increase dwell time */ + af_params->dwell_time = WL_MED_DWELL_TIME; + break; + } + case P2P_PAF_INVITE_RSP: + /* minimize dwell time */ + af_params->dwell_time = WL_MIN_DWELL_TIME; +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + case P2P_PAF_DEVDIS_REQ: { + if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0], + action_frame->len)) { + config_af_params->search_channel = true; + } + + cfg->next_af_subtype = act_frm->subtype + 1; + /* maximize dwell time to wait for RESP frame */ + af_params->dwell_time = WL_LONG_DWELL_TIME; + break; + } + case P2P_PAF_DEVDIS_RSP: + /* minimize dwell time */ + af_params->dwell_time = WL_MIN_DWELL_TIME; +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + case P2P_PAF_PROVDIS_REQ: { + if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0], + action_frame->len)) { + config_af_params->search_channel = true; + } + + config_af_params->mpc_onoff = 0; + cfg->next_af_subtype = act_frm->subtype + 1; + /* increase dwell time to wait for RESP frame */ + af_params->dwell_time = WL_MED_DWELL_TIME; + break; + } + case P2P_PAF_PROVDIS_RSP: { + cfg->next_af_subtype = P2P_PAF_GON_REQ; + af_params->dwell_time = WL_MIN_DWELL_TIME; +#ifdef WL_CFG80211_SYNC_GON + config_af_params->extra_listen = false; +#endif /* WL_CFG80211_SYNC_GON */ + break; + } + default: + WL_DBG(("Unknown p2p pub act frame subtype: %d\n", + act_frm->subtype)); + err = BCME_BADARG; + } + return err; +} + +#ifdef WL11U +static bool +wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params, + void *frame, u16 frame_len) +{ + struct wl_scan_results *bss_list; + struct wl_bss_info *bi = NULL; + bool result = false; + s32 i; + chanspec_t chanspec; + + /* If DFS channel is 52~148, check to block it or not */ + if (af_params && + (af_params->channel >= 52 && af_params->channel <= 148)) { + if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) { + bss_list = cfg->bss_list; + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + chanspec = wl_chspec_driver_to_host(bi->chanspec); + if (CHSPEC_IS5G(chanspec) && + ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec)) + == af_params->channel)) { + result = true; /* do not block the action frame */ + break; + } + } + } + } + else { + result = true; + } + + WL_DBG(("result=%s", result?"true":"false")); + return result; +} +#endif /* WL11U */ + + +static bool +wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, + bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params, + wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) +{ +#ifdef WL11U + struct net_device *ndev = NULL; +#endif /* WL11U */ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + bool ack = false; + u8 category, action; + s32 tx_retry; + struct p2p_config_af_params config_af_params; +#ifdef VSDB + ulong off_chan_started_jiffies = 0; +#endif + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + + + /* Add the default dwell time + * Dwell time to stay off-channel to wait for a response action frame + * after transmitting an GO Negotiation action frame + */ + af_params->dwell_time = WL_DWELL_TIME; + +#ifdef WL11U +#if defined(WL_CFG80211_P2P_DEV_IF) + ndev = dev; +#else + ndev = ndev_to_cfgdev(cfgdev); +#endif /* WL_CFG80211_P2P_DEV_IF */ +#endif /* WL11U */ + + category = action_frame->data[DOT11_ACTION_CAT_OFF]; + action = action_frame->data[DOT11_ACTION_ACT_OFF]; + + /* initialize variables */ + tx_retry = 0; + cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; + config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY; + config_af_params.mpc_onoff = -1; + config_af_params.search_channel = false; +#ifdef WL_CFG80211_SYNC_GON + config_af_params.extra_listen = false; +#endif + + /* config parameters */ + /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */ + if (category == DOT11_ACTION_CAT_PUBLIC) { + if ((action == P2P_PUB_AF_ACTION) && + (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) { + /* p2p public action frame process */ + if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy, + action_frame, af_params, &config_af_params)) { + WL_DBG(("Unknown subtype.\n")); + } + + } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) { + /* service discovery process */ + if (action == P2PSD_ACTION_ID_GAS_IREQ || + action == P2PSD_ACTION_ID_GAS_CREQ) { + /* configure service discovery query frame */ + + config_af_params.search_channel = true; + + /* save next af suptype to cancel remained dwell time */ + cfg->next_af_subtype = action + 1; + + af_params->dwell_time = WL_MED_DWELL_TIME; + } else if (action == P2PSD_ACTION_ID_GAS_IRESP || + action == P2PSD_ACTION_ID_GAS_CRESP) { + /* configure service discovery response frame */ + af_params->dwell_time = WL_MIN_DWELL_TIME; + } else { + WL_DBG(("Unknown action type: %d\n", action)); + } + } else { + WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n", + category, action, action_frame_len)); + } + } else if (category == P2P_AF_CATEGORY) { + /* do not configure anything. it will be sent with a default configuration */ + } else { + WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n", + category, action)); + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { + wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev); + return false; + } + } + + /* To make sure to send successfully action frame, we have to turn off mpc */ + if (config_af_params.mpc_onoff == 0) { + wldev_iovar_setint(dev, "mpc", 0); + } + + /* validate channel and p2p ies */ + if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) && + wl_to_p2p_bss_saved_ie(cfg, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { + config_af_params.search_channel = true; + } else { + config_af_params.search_channel = false; + } +#ifdef WL11U + if (ndev == bcmcfg_to_prmry_ndev(cfg)) + config_af_params.search_channel = false; +#endif /* WL11U */ + +#ifdef VSDB + /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ + if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { + OSL_SLEEP(50); + } +#endif + + /* if scan is ongoing, abort current scan. */ + if (wl_get_drv_status_all(cfg, SCANNING)) { + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); + } + + /* Abort P2P listen */ + if (discover_cfgdev(cfgdev, cfg)) { + if (cfg->p2p_supported && cfg->p2p) { + wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + } + } + +#ifdef WL11U + /* handling DFS channel exceptions */ + if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) { + return false; /* the action frame was blocked */ + } +#endif /* WL11U */ + + /* set status and destination address before sending af */ + if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { + /* set this status to cancel the remained dwell time in rx process */ + wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev); + } + wl_set_drv_status(cfg, SENDING_ACT_FRM, dev); + memcpy(cfg->afx_hdl->tx_dst_addr.octet, + af_params->action_frame.da.octet, + sizeof(cfg->afx_hdl->tx_dst_addr.octet)); + + /* save af_params for rx process */ + cfg->afx_hdl->pending_tx_act_frm = af_params; + + /* search peer's channel */ + if (config_af_params.search_channel) { + /* initialize afx_hdl */ + if (wl_cfgp2p_find_idx(cfg, dev, &cfg->afx_hdl->bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + goto exit; + } + cfg->afx_hdl->dev = dev; + cfg->afx_hdl->retry = 0; + cfg->afx_hdl->peer_chan = WL_INVALID; + + if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) { + WL_ERR(("couldn't find peer's channel.\n")); + wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, + af_params->channel); + goto exit; + } + + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + /* + * Abort scan even for VSDB scenarios. Scan gets aborted in firmware + * but after the check of piggyback algorithm. + * To take care of current piggback algo, lets abort the scan here itself. + */ + wl_notify_escan_complete(cfg, dev, true, true); + /* Suspend P2P discovery's search-listen to prevent it from + * starting a scan or changing the channel. + */ + wl_cfgp2p_discover_enable_search(cfg, false); + + /* update channel */ + af_params->channel = cfg->afx_hdl->peer_chan; + } + +#ifdef VSDB + off_chan_started_jiffies = jiffies; +#endif /* VSDB */ + + wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel); + + wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true); + + /* Now send a tx action frame */ + ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true; + + /* if failed, retry it. tx_retry_max value is configure by .... */ + while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) { +#ifdef VSDB + if (af_params->channel) { + if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) > + OFF_CHAN_TIME_THRESHOLD_MS) { + WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg); + off_chan_started_jiffies = jiffies; + } else + OSL_SLEEP(AF_RETRY_DELAY_TIME); + } +#endif /* VSDB */ + ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? + false : true; + } + + if (ack == false) { + WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry)); + } + WL_DBG(("Complete to send action frame\n")); +exit: + /* Clear SENDING_ACT_FRM after all sending af is done */ + wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev); + +#ifdef WL_CFG80211_SYNC_GON + /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. + * if we coundn't get the next action response frame and dongle does not keep + * the dwell time, go to listen state again to get next action response frame. + */ + if (ack && config_af_params.extra_listen && + wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) && + cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) { + s32 extar_listen_time; + + extar_listen_time = af_params->dwell_time - + jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies); + + if (extar_listen_time > 50) { + wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev); + WL_DBG(("Wait more time! actual af time:%d," + "calculated extar listen:%d\n", + af_params->dwell_time, extar_listen_time)); + if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel, + extar_listen_time + 100) == BCME_OK) { + wait_for_completion_timeout(&cfg->wait_next_af, + msecs_to_jiffies(extar_listen_time + 100 + 300)); + } + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev); + } + } +#endif /* WL_CFG80211_SYNC_GON */ + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev); + + if (cfg->afx_hdl->pending_tx_act_frm) + cfg->afx_hdl->pending_tx_act_frm = NULL; + + WL_INFO(("-- sending Action Frame is %s, listen chan: %d\n", + (ack) ? "Succeeded!!":"Failed!!", cfg->afx_hdl->my_listen_chan)); + + + /* if all done, turn mpc on again */ + if (config_af_params.mpc_onoff == 1) { + wldev_iovar_setint(dev, "mpc", 1); + } + + return ack; +} + +#define MAX_NUM_OF_ASSOCIATED_DEV 64 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +static s32 +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +#else +static s32 +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel *channel, bool offchan, +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0)) + enum nl80211_channel_type channel_type, + bool channel_type_valid, +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) */ + unsigned int wait, const u8* buf, size_t len, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + bool no_cck, +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) + bool dont_wait_for_ack, +#endif + u64 *cookie) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ +{ + wl_action_frame_t *action_frame; + wl_af_params_t *af_params; + scb_val_t scb_val; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + struct ieee80211_channel *channel = params->chan; + const u8 *buf = params->buf; + size_t len = params->len; +#endif + const struct ieee80211_mgmt *mgmt; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *dev = NULL; + s32 err = BCME_OK; + s32 bssidx = 0; + u32 id; + bool ack = false; + s8 eabuf[ETHER_ADDR_STR_LEN]; + + WL_DBG(("Enter \n")); + + dev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */ + if (discover_cfgdev(cfgdev, cfg)) { + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + } + else { + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + } + + WL_DBG(("TX target bssidx=%d\n", bssidx)); + + if (p2p_is_on(cfg)) { + /* Suspend P2P discovery search-listen to prevent it from changing the + * channel. + */ + if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) { + WL_ERR(("Can not disable discovery mode\n")); + return -EFAULT; + } + } + *cookie = 0; + id = cfg->send_action_id++; + if (id == 0) + id = cfg->send_action_id++; + *cookie = id; + mgmt = (const struct ieee80211_mgmt *)buf; + if (ieee80211_is_mgmt(mgmt->frame_control)) { + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + s32 ie_len = len - ie_offset; + if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); + cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); + goto exit; + } else if (ieee80211_is_disassoc(mgmt->frame_control) || + ieee80211_is_deauth(mgmt->frame_control)) { + char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * + sizeof(struct ether_addr) + sizeof(uint)] = {0}; + int num_associated = 0; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; + if (!bcmp((const uint8 *)BSSID_BROADCAST, + (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) { + assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; + err = wldev_ioctl(dev, WLC_GET_ASSOCLIST, + assoc_maclist, sizeof(mac_buf), false); + if (err < 0) + WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); + else + num_associated = assoc_maclist->count; + } + memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); + scb_val.val = mgmt->u.disassoc.reason_code; + err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t), true); + if (err < 0) + WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err)); + WL_ERR(("Disconnect STA : %s scb_val.val %d\n", + bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), + scb_val.val)); + + if (num_associated > 0 && ETHER_ISBCAST(mgmt->da)) + wl_delay(400); + + cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); + goto exit; + + } else if (ieee80211_is_action(mgmt->frame_control)) { + /* Abort the dwell time of any previous off-channel + * action frame that may be still in effect. Sending + * off-channel action frames relies on the driver's + * scan engine. If a previous off-channel action frame + * tx is still in progress (including the dwell time), + * then this new action frame will not be sent out. + */ +/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary. + * And previous off-channel action frame must be ended before new af tx. + */ +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_notify_escan_complete(cfg, dev, true, true); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + } + + } else { + WL_ERR(("Driver only allows MGMT packet type\n")); + goto exit; + } + + af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); + + if (af_params == NULL) + { + WL_ERR(("unable to allocate frame\n")); + return -ENOMEM; + } + + action_frame = &af_params->action_frame; + + /* Add the packet Id */ + action_frame->packetId = *cookie; + WL_DBG(("action frame %d\n", action_frame->packetId)); + /* Add BSSID */ + memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); + memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN); + + /* Add the length exepted for 802.11 header */ + action_frame->len = len - DOT11_MGMT_HDR_LEN; + WL_DBG(("action_frame->len: %d\n", action_frame->len)); + + /* Add the channel */ + af_params->channel = + ieee80211_frequency_to_channel(channel->center_freq); + /* Save listen_chan for searching common channel */ + cfg->afx_hdl->peer_listen_chan = af_params->channel; + WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan)); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + af_params->dwell_time = params->wait; +#else + af_params->dwell_time = wait; +#endif + + memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); + + ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params, + action_frame, action_frame->len, bssidx); + cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL); + + kfree(af_params); +exit: + return err; +} + + +static void +wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + u16 frame_type, bool reg) +{ + + WL_DBG(("frame_type: %x, reg: %d\n", frame_type, reg)); + + if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) + return; + + return; +} + + +static s32 +wl_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + s32 err = 0; + s32 ap_isolate = 0; +#if defined(SUPPORT_HOSTAPD_BGN_MODE) + dhd_pub_t *dhd; + s32 gmode = -1, nmode = -1; + s32 gmode_prev = -1, nmode_prev = -1; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); +#if defined(WL_ENABLE_P2P_IF) + if (cfg->p2p_net == dev) + dev = bcmcfg_to_prmry_ndev(cfg); +#endif + dhd = (dhd_pub_t *)(cfg->pub); +#endif /* SUPPORT_HOSTAPD_BGN_MODE */ + + if (params->use_cts_prot >= 0) { + } + + if (params->use_short_preamble >= 0) { + } + + if (params->use_short_slot_time >= 0) { + } + + if (params->basic_rates) { +#if defined(SUPPORT_HOSTAPD_BGN_MODE) + switch ((int)(params->basic_rates[params->basic_rates_len -1])) { + case 22: /* B only , rate 11 */ + gmode = 0; + nmode = 0; + break; + case 108: /* G only , rate 54 */ + gmode = 2; + nmode = 0; + break; + default: + gmode = -1; + nmode = -1; + break; + } +#endif /* SUPPORT_HOSTAPD_BGN_MODE */ + } + + if (params->ap_isolate >= 0) { + ap_isolate = params->ap_isolate; + err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate); + if (unlikely(err)) + { + WL_ERR(("set ap_isolate Error (%d)\n", err)); + } + } + + if (params->ht_opmode >= 0) { +#if defined(SUPPORT_HOSTAPD_BGN_MODE) + nmode = 1; + gmode = 1; + } else { + nmode = 0; +#endif /* SUPPORT_HOSTAPD_BGN_MODE */ + } + +#if defined(SUPPORT_HOSTAPD_BGN_MODE) + err = wldev_iovar_getint(dev, "nmode", &nmode_prev); + if (unlikely(err)) { + WL_ERR(("error reading nmode (%d)\n", err)); + } + if (nmode == nmode_prev) { + nmode = -1; + } + err = wldev_ioctl(dev, WLC_GET_GMODE, &gmode_prev, sizeof(gmode_prev), 0); + if (unlikely(err)) { + WL_ERR(("error reading gmode (%d)\n", err)); + } + if (gmode == gmode_prev) { + gmode = -1; + } + + if (((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) == DHD_FLAG_HOSTAP_MODE) && + ((gmode > -1) || (nmode > -1))) { + s32 val = 0; + + err = wldev_ioctl(dev, WLC_DOWN, &val, sizeof(s32), true); + if (unlikely(err)) + WL_ERR(("WLC_DOWN command failed:[%d]\n", err)); + + if (nmode > -1) { + err = wldev_iovar_setint(dev, "nmode", nmode); + if (unlikely(err)) + WL_ERR(("nmode command failed:mode[%d]:err[%d]\n", nmode, err)); + } + + if (gmode > -1) { + err = wldev_ioctl(dev, WLC_SET_GMODE, &gmode, sizeof(s32), true); + if (unlikely(err)) + WL_ERR(("WLC_SET_GMODE command failed:mode[%d]:err[%d]\n", + gmode, err)); + } + + val = 0; + err = wldev_ioctl(dev, WLC_UP, &val, sizeof(s32), true); + if (unlikely(err)) + WL_ERR(("WLC_UP command failed:err[%d]\n", err)); + + } +#endif /* SUPPORT_HOSTAPD_BGN_MODE */ + + return 0; +} + +static s32 +wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, +#ifdef WL_SUPPORT_CHAN_BW + enum nl80211_chan_width chan_width) +#else + enum nl80211_channel_type channel_type) +#endif /* WL_SUPPORT_CHAN_BW */ +{ + s32 _chan; + chanspec_t chspec = 0; + chanspec_t fw_chspec = 0; + u32 bw = WL_CHANSPEC_BW_20; + + s32 err = BCME_OK; + s32 bw_cap = 0; + struct { + u32 band; + u32 bw_cap; + } param = {0, 0}; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + dev = ndev_to_wlc_ndev(dev, cfg); + _chan = ieee80211_frequency_to_channel(chan->center_freq); +#ifdef WL_SUPPORT_CHAN_BW + WL_ERR(("netdev_ifidx(%d), chan_width(%d) target channel(%d) \n", + dev->ifindex, chan_width, _chan)); + + switch (chan_width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + bw = WL_CHANSPEC_BW_20; + goto set_channel; + case NL80211_CHAN_WIDTH_40: + bw = WL_CHANSPEC_BW_40; + goto set_channel; + case NL80211_CHAN_WIDTH_80: + bw = WL_CHANSPEC_BW_80; + goto set_channel; + default: + WL_ERR(("chanwidth not defined")); + return BCME_ERROR; + } +#else + WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", + dev->ifindex, channel_type, _chan)); +#endif /* WL_SUPPORT_CHAN_BW */ + + + if (chan->band == IEEE80211_BAND_5GHZ) { + param.band = WLC_BAND_5G; + err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), + cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); + if (err) { + if (err != BCME_UNSUPPORTED) { + WL_ERR(("bw_cap failed, %d\n", err)); + return err; + } else { + err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); + if (err) { + WL_ERR(("error get mimo_bw_cap (%d)\n", err)); + } + if (bw_cap != WLC_N_BW_20ALL) + bw = WL_CHANSPEC_BW_40; + } + } else { + if (WL_BW_CAP_80MHZ(cfg->ioctl_buf[0])) + bw = WL_CHANSPEC_BW_80; + else if (WL_BW_CAP_40MHZ(cfg->ioctl_buf[0])) + bw = WL_CHANSPEC_BW_40; + else + bw = WL_CHANSPEC_BW_20; + + } + + } else if (chan->band == IEEE80211_BAND_2GHZ) + bw = WL_CHANSPEC_BW_20; +set_channel: + chspec = wf_channel2chspec(_chan, bw); + if (wf_chspec_valid(chspec)) { + fw_chspec = wl_chspec_host_to_driver(chspec); + if (fw_chspec != INVCHANSPEC) { + if ((err = wldev_iovar_setint(dev, "chanspec", + fw_chspec)) == BCME_BADCHAN) { + if (bw == WL_CHANSPEC_BW_80) + goto change_bw; + err = wldev_ioctl(dev, WLC_SET_CHANNEL, + &_chan, sizeof(_chan), true); + if (err < 0) { + WL_ERR(("WLC_SET_CHANNEL error %d" + "chip may not be supporting this channel\n", err)); + } + } else if (err) { + WL_ERR(("failed to set chanspec error %d\n", err)); + } + } else { + WL_ERR(("failed to convert host chanspec to fw chanspec\n")); + err = BCME_ERROR; + } + } else { +change_bw: + if (bw == WL_CHANSPEC_BW_80) + bw = WL_CHANSPEC_BW_40; + else if (bw == WL_CHANSPEC_BW_40) + bw = WL_CHANSPEC_BW_20; + else + bw = 0; + if (bw) + goto set_channel; + WL_ERR(("Invalid chanspec 0x%x\n", chspec)); + err = BCME_ERROR; + } + return err; +} + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +struct net_device * +wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg) +{ + struct net_info *_net_info, *next; + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (_net_info->ndev && + test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state)) + return _net_info->ndev; + } + return NULL; +} +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +static s32 +wl_validate_opensecurity(struct net_device *dev, s32 bssidx) +{ + s32 err = BCME_OK; + + /* set auth */ + err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx); + if (err < 0) { + WL_ERR(("auth error %d\n", err)); + return BCME_ERROR; + } + /* set wsec */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); + if (err < 0) { + WL_ERR(("wsec error %d\n", err)); + return BCME_ERROR; + } + + /* set upper-layer auth */ + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WPA_AUTH_NONE, bssidx); + if (err < 0) { + WL_ERR(("wpa_auth error %d\n", err)); + return BCME_ERROR; + } + + return 0; +} + +static s32 +wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) +{ + s32 len = 0; + s32 err = BCME_OK; + u16 auth = 0; /* d11 open authentication */ + u32 wsec; + u32 pval = 0; + u32 gval = 0; + u32 wpa_auth = 0; + wpa_suite_mcast_t *mcast; + wpa_suite_ucast_t *ucast; + wpa_suite_auth_key_mgmt_t *mgmt; + wpa_pmkid_list_t *pmkid; + int cnt = 0; +#ifdef MFP + int mfp = 0; + struct bcm_cfg80211 *cfg = g_bcm_cfg; +#endif /* MFP */ + + u16 suite_count; + u8 rsn_cap[2]; + u32 wme_bss_disable; + + if (wpa2ie == NULL) + goto exit; + + WL_DBG(("Enter \n")); + len = wpa2ie->len - WPA2_VERSION_LEN; + /* check the mcast cipher */ + mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; + switch (mcast->type) { + case WPA_CIPHER_NONE: + gval = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + gval = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + gval = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + gval = AES_ENABLED; + break; +#ifdef BCMWAPI_WPI + case WAPI_CIPHER_SMS4: + gval = SMS4_ENABLED; + break; +#endif + default: + WL_ERR(("No Security Info\n")); + break; + } + if ((len -= WPA_SUITE_LEN) <= 0) + return BCME_BADLEN; + + /* check the unicast cipher */ + ucast = (wpa_suite_ucast_t *)&mcast[1]; + suite_count = ltoh16_ua(&ucast->count); + switch (ucast->list[0].type) { + case WPA_CIPHER_NONE: + pval = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + pval = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + pval = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + pval = AES_ENABLED; + break; +#ifdef BCMWAPI_WPI + case WAPI_CIPHER_SMS4: + pval = SMS4_ENABLED; + break; +#endif + default: + WL_ERR(("No Security Info\n")); + } + if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0) + return BCME_BADLEN; + + /* FOR WPS , set SEC_OW_ENABLED */ + wsec = (pval | gval | SES_OW_ENABLED); + /* check the AKM */ + mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; + suite_count = cnt = ltoh16_ua(&mgmt->count); + while (cnt--) { + switch (mgmt->list[cnt].type) { + case RSN_AKM_NONE: + wpa_auth = WPA_AUTH_NONE; + break; + case RSN_AKM_UNSPECIFIED: + wpa_auth = WPA2_AUTH_UNSPECIFIED; + break; + case RSN_AKM_PSK: + wpa_auth = WPA2_AUTH_PSK; + break; +#ifdef MFP + case RSN_AKM_MFP_PSK: + wpa_auth |= WPA2_AUTH_PSK; + wsec |= MFP_SHA256; + break; + case RSN_AKM_MFP_1X: + wpa_auth |= WPA2_AUTH_UNSPECIFIED; + wsec |= MFP_SHA256; + break; +#endif /* MFP */ + + default: + WL_ERR(("No Key Mgmt Info\n")); + } + } + + if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { + rsn_cap[0] = *(u8 *)&mgmt->list[suite_count]; + rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1); + + if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) { + wme_bss_disable = 0; + } else { + wme_bss_disable = 1; + } +#ifdef MFP + if (rsn_cap[0] & RSN_CAP_MFPR) { + WL_DBG(("MFP Required \n")); + mfp = WL_MFP_REQUIRED; + } else if (rsn_cap[0] & RSN_CAP_MFPC) { + WL_DBG(("MFP Capable \n")); + mfp = WL_MFP_CAPABLE; + } +#endif /* MFP */ + + /* set wme_bss_disable to sync RSN Capabilities */ + err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx); + if (err < 0) { + WL_ERR(("wme_bss_disable error %d\n", err)); + return BCME_ERROR; + } + } else { + WL_DBG(("There is no RSN Capabilities. remained len %d\n", len)); + } + + len -= RSN_CAP_LEN; + if (len >= WPA2_PMKID_COUNT_LEN) { + pmkid = (wpa_pmkid_list_t *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN); + cnt = ltoh16_ua(&pmkid->count); + if (cnt != 0) { + WL_ERR(("AP has non-zero PMKID count. Wrong!\n")); + return BCME_ERROR; + } + /* since PMKID cnt is known to be 0 for AP, */ + /* so don't bother to send down this info to firmware */ + } + +#ifdef MFP + len -= WPA2_PMKID_COUNT_LEN; + if (len >= WPA_SUITE_LEN) { + err = wldev_iovar_setbuf_bsscfg(dev, "bip", + (void *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN), + WPA_SUITE_LEN, + cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync); + if (err < 0) { + WL_ERR(("bip set error %d\n", err)); + } + } +#endif + + /* set auth */ + err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); + if (err < 0) { + WL_ERR(("auth error %d\n", err)); + return BCME_ERROR; + } + /* set wsec */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); + if (err < 0) { + WL_ERR(("wsec error %d\n", err)); + return BCME_ERROR; + } +#ifdef MFP + if (mfp) { + /* This needs to go after wsec otherwise the wsec command will + * overwrite the values set by MFP + */ + if ((err = wldev_iovar_setint_bsscfg(dev, "mfp", mfp, bssidx)) < 0) { + WL_ERR(("MFP Setting failed. ret = %d \n", err)); + return err; + } + } +#endif /* MFP */ + /* set upper-layer auth */ + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); + if (err < 0) { + WL_ERR(("wpa_auth error %d\n", err)); + return BCME_ERROR; + } +exit: + return 0; +} + +static s32 +wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) +{ + wpa_suite_mcast_t *mcast; + wpa_suite_ucast_t *ucast; + wpa_suite_auth_key_mgmt_t *mgmt; + u16 auth = 0; /* d11 open authentication */ + u16 count; + s32 err = BCME_OK; + s32 len = 0; + u32 i; + u32 wsec; + u32 pval = 0; + u32 gval = 0; + u32 wpa_auth = 0; + u32 tmp = 0; + + if (wpaie == NULL) + goto exit; + WL_DBG(("Enter \n")); + len = wpaie->length; /* value length */ + len -= WPA_IE_TAG_FIXED_LEN; + /* check for multicast cipher suite */ + if (len < WPA_SUITE_LEN) { + WL_INFO(("no multicast cipher suite\n")); + goto exit; + } + + /* pick up multicast cipher */ + mcast = (wpa_suite_mcast_t *)&wpaie[1]; + len -= WPA_SUITE_LEN; + if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) { + if (IS_WPA_CIPHER(mcast->type)) { + tmp = 0; + switch (mcast->type) { + case WPA_CIPHER_NONE: + tmp = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + tmp = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + tmp = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + tmp = AES_ENABLED; + break; + default: + WL_ERR(("No Security Info\n")); + } + gval |= tmp; + } + } + /* Check for unicast suite(s) */ + if (len < WPA_IE_SUITE_COUNT_LEN) { + WL_INFO(("no unicast suite\n")); + goto exit; + } + /* walk thru unicast cipher list and pick up what we recognize */ + ucast = (wpa_suite_ucast_t *)&mcast[1]; + count = ltoh16_ua(&ucast->count); + len -= WPA_IE_SUITE_COUNT_LEN; + for (i = 0; i < count && len >= WPA_SUITE_LEN; + i++, len -= WPA_SUITE_LEN) { + if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { + if (IS_WPA_CIPHER(ucast->list[i].type)) { + tmp = 0; + switch (ucast->list[i].type) { + case WPA_CIPHER_NONE: + tmp = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + tmp = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + tmp = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + tmp = AES_ENABLED; + break; + default: + WL_ERR(("No Security Info\n")); + } + pval |= tmp; + } + } + } + len -= (count - i) * WPA_SUITE_LEN; + /* Check for auth key management suite(s) */ + if (len < WPA_IE_SUITE_COUNT_LEN) { + WL_INFO((" no auth key mgmt suite\n")); + goto exit; + } + /* walk thru auth management suite list and pick up what we recognize */ + mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count]; + count = ltoh16_ua(&mgmt->count); + len -= WPA_IE_SUITE_COUNT_LEN; + for (i = 0; i < count && len >= WPA_SUITE_LEN; + i++, len -= WPA_SUITE_LEN) { + if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { + if (IS_WPA_AKM(mgmt->list[i].type)) { + tmp = 0; + switch (mgmt->list[i].type) { + case RSN_AKM_NONE: + tmp = WPA_AUTH_NONE; + break; + case RSN_AKM_UNSPECIFIED: + tmp = WPA_AUTH_UNSPECIFIED; + break; + case RSN_AKM_PSK: + tmp = WPA_AUTH_PSK; + break; + default: + WL_ERR(("No Key Mgmt Info\n")); + } + wpa_auth |= tmp; + } + } + + } + /* FOR WPS , set SEC_OW_ENABLED */ + wsec = (pval | gval | SES_OW_ENABLED); + /* set auth */ + err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); + if (err < 0) { + WL_ERR(("auth error %d\n", err)); + return BCME_ERROR; + } + /* set wsec */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); + if (err < 0) { + WL_ERR(("wsec error %d\n", err)); + return BCME_ERROR; + } + /* set upper-layer auth */ + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); + if (err < 0) { + WL_ERR(("wpa_auth error %d\n", err)); + return BCME_ERROR; + } +exit: + return 0; +} + + +static s32 +wl_cfg80211_bcn_validate_sec( + struct net_device *dev, + struct parsed_ies *ies, + u32 dev_role, + s32 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) { + /* For P2P GO, the sec type is WPA2-PSK */ + WL_DBG(("P2P GO: validating wpa2_ie")); + if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0) + return BCME_ERROR; + + } else if (dev_role == NL80211_IFTYPE_AP) { + + WL_DBG(("SoftAP: validating security")); + /* If wpa2_ie or wpa_ie is present validate it */ + + if ((ies->wpa2_ie || ies->wpa_ie) && + ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || + wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) { + cfg->ap_info->security_mode = false; + return BCME_ERROR; + } + + cfg->ap_info->security_mode = true; + if (cfg->ap_info->rsn_ie) { + kfree(cfg->ap_info->rsn_ie); + cfg->ap_info->rsn_ie = NULL; + } + if (cfg->ap_info->wpa_ie) { + kfree(cfg->ap_info->wpa_ie); + cfg->ap_info->wpa_ie = NULL; + } + if (cfg->ap_info->wps_ie) { + kfree(cfg->ap_info->wps_ie); + cfg->ap_info->wps_ie = NULL; + } + if (ies->wpa_ie != NULL) { + /* WPAIE */ + cfg->ap_info->rsn_ie = NULL; + cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, + ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else if (ies->wpa2_ie != NULL) { + /* RSNIE */ + cfg->ap_info->wpa_ie = NULL; + cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, + ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } + if (!ies->wpa2_ie && !ies->wpa_ie) { + wl_validate_opensecurity(dev, bssidx); + cfg->ap_info->security_mode = false; + } + + if (ies->wps_ie) { + cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); + } + } + + return 0; + +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +static s32 wl_cfg80211_bcn_set_params( + struct cfg80211_ap_settings *info, + struct net_device *dev, + u32 dev_role, s32 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + s32 err = BCME_OK; + + WL_DBG(("interval (%d) \ndtim_period (%d) \n", + info->beacon_interval, info->dtim_period)); + + if (info->beacon_interval) { + if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, + &info->beacon_interval, sizeof(s32), true)) < 0) { + WL_ERR(("Beacon Interval Set Error, %d\n", err)); + return err; + } + } + + if (info->dtim_period) { + if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, + &info->dtim_period, sizeof(s32), true)) < 0) { + WL_ERR(("DTIM Interval Set Error, %d\n", err)); + return err; + } + } + + if ((info->ssid) && (info->ssid_len > 0) && + (info->ssid_len <= DOT11_MAX_SSID_LEN)) { + WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len)); + if (dev_role == NL80211_IFTYPE_AP) { + /* Store the hostapd SSID */ + memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); + memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len); + cfg->hostapd_ssid.SSID_len = info->ssid_len; + } else { + /* P2P GO */ + memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); + memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len); + cfg->p2p->ssid.SSID_len = info->ssid_len; + } + } + + if (info->hidden_ssid) { + if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) + WL_ERR(("failed to set hidden : %d\n", err)); + WL_ERR(("hidden_ssid_enum_val: %d \n", info->hidden_ssid)); + } + + return err; +} +#endif + +static s32 +wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies) +{ + s32 err = BCME_OK; + + memset(ies, 0, sizeof(struct parsed_ies)); + + /* find the WPSIE */ + if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) { + WL_DBG(("WPSIE in beacon \n")); + ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; + } else { + WL_ERR(("No WPSIE in beacon \n")); + } + + /* find the RSN_IE */ + if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE found\n")); + ies->wpa2_ie_len = ies->wpa2_ie->len; + } + + /* find the WPA_IE */ + if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) { + WL_DBG((" WPA found\n")); + ies->wpa_ie_len = ies->wpa_ie->length; + } + + return err; + +} + +static s32 +wl_cfg80211_bcn_bringup_ap( + struct net_device *dev, + struct parsed_ies *ies, + u32 dev_role, s32 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wl_join_params join_params; + bool is_bssup = false; + s32 infra = 1; + s32 join_params_size = 0; + s32 ap = 1; +#ifdef DISABLE_11H_SOFTAP + s32 spect = 0; +#endif /* DISABLE_11H_SOFTAP */ + s32 err = BCME_OK; + + WL_DBG(("Enter dev_role: %d\n", dev_role)); + + /* Common code for SoftAP and P2P GO */ + wldev_iovar_setint(dev, "mpc", 0); + + if (dev_role == NL80211_IFTYPE_P2P_GO) { + is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); + if (!is_bssup && (ies->wpa2_ie != NULL)) { + + err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + goto exit; + } + + err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid, + sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &cfg->ioctl_buf_sync); + if (err < 0) { + WL_ERR(("GO SSID setting error %d\n", err)); + goto exit; + } + + /* Do abort scan before creating GO */ + wl_cfg80211_scan_abort(cfg); + + if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) { + WL_ERR(("GO Bring up error %d\n", err)); + goto exit; + } + } else + WL_DBG(("Bss is already up\n")); + } else if ((dev_role == NL80211_IFTYPE_AP) && + (wl_get_drv_status(cfg, AP_CREATING, dev))) { + /* Device role SoftAP */ + err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); + if (err < 0) { + WL_ERR(("WLC_DOWN error %d\n", err)); + goto exit; + } + err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + goto exit; + } + if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { + WL_ERR(("setting AP mode failed %d \n", err)); + goto exit; + } +#ifdef DISABLE_11H_SOFTAP + err = wldev_ioctl(dev, WLC_SET_SPECT_MANAGMENT, + &spect, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET SPECT_MANAGMENT error %d\n", err)); + goto exit; + } +#endif /* DISABLE_11H_SOFTAP */ + + err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + goto exit; + } + + memset(&join_params, 0, sizeof(join_params)); + /* join parameters starts with ssid */ + join_params_size = sizeof(join_params.ssid); + join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len, + (uint32)DOT11_MAX_SSID_LEN); + memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID, + join_params.ssid.SSID_len); + join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); + + /* create softap */ + if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, + join_params_size, true)) == 0) { + WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID)); + wl_clr_drv_status(cfg, AP_CREATING, dev); + wl_set_drv_status(cfg, AP_CREATED, dev); + } + } + + +exit: + return err; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +s32 +wl_cfg80211_parse_ap_ies( + struct net_device *dev, + struct cfg80211_beacon_data *info, + struct parsed_ies *ies) +{ + struct parsed_ies prb_ies; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + u8 *vndr = NULL; + u32 vndr_ie_len = 0; + s32 err = BCME_OK; + + /* Parse Beacon IEs */ + if (wl_cfg80211_parse_ies((u8 *)info->tail, + info->tail_len, ies) < 0) { + WL_ERR(("Beacon get IEs failed \n")); + err = -EINVAL; + goto fail; + } + + vndr = (u8 *)info->proberesp_ies; + vndr_ie_len = info->proberesp_ies_len; + + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { + /* SoftAP mode */ + struct ieee80211_mgmt *mgmt; + mgmt = (struct ieee80211_mgmt *)info->probe_resp; + if (mgmt != NULL) { + vndr = (u8 *)&mgmt->u.probe_resp.variable; + vndr_ie_len = info->probe_resp_len - + offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + } + } + + /* Parse Probe Response IEs */ + if (wl_cfg80211_parse_ies(vndr, vndr_ie_len, &prb_ies) < 0) { + WL_ERR(("PROBE RESP get IEs failed \n")); + err = -EINVAL; + } + +fail: + + return err; +} + +s32 +wl_cfg80211_set_ies( + struct net_device *dev, + struct cfg80211_beacon_data *info, + s32 bssidx) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + u8 *vndr = NULL; + u32 vndr_ie_len = 0; + s32 err = BCME_OK; + + /* Set Beacon IEs to FW */ + if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_BEACON_FLAG, (u8 *)info->tail, + info->tail_len)) < 0) { + WL_ERR(("Set Beacon IE Failed \n")); + } else { + WL_DBG(("Applied Vndr IEs for Beacon \n")); + } + + vndr = (u8 *)info->proberesp_ies; + vndr_ie_len = info->proberesp_ies_len; + + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { + /* SoftAP mode */ + struct ieee80211_mgmt *mgmt; + mgmt = (struct ieee80211_mgmt *)info->probe_resp; + if (mgmt != NULL) { + vndr = (u8 *)&mgmt->u.probe_resp.variable; + vndr_ie_len = info->probe_resp_len - + offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + } + } + + /* Set Probe Response IEs to FW */ + if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) { + WL_ERR(("Set Probe Resp IE Failed \n")); + } else { + WL_DBG(("Applied Vndr IEs for Probe Resp \n")); + } + + return err; +} +#endif + +static s32 wl_cfg80211_hostapd_sec( + struct net_device *dev, + struct parsed_ies *ies, + s32 bssidx) +{ + bool update_bss = 0; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + + if (ies->wps_ie) { + if (cfg->ap_info->wps_ie && + memcmp(cfg->ap_info->wps_ie, ies->wps_ie, ies->wps_ie_len)) { + WL_DBG((" WPS IE is changed\n")); + kfree(cfg->ap_info->wps_ie); + cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); + } else if (cfg->ap_info->wps_ie == NULL) { + WL_DBG((" WPS IE is added\n")); + cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); + } + + if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) { + if (!cfg->ap_info->security_mode) { + /* change from open mode to security mode */ + update_bss = true; + if (ies->wpa_ie != NULL) { + cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, + ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else { + cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, + ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } + } else if (cfg->ap_info->wpa_ie) { + /* change from WPA2 mode to WPA mode */ + if (ies->wpa_ie != NULL) { + update_bss = true; + kfree(cfg->ap_info->rsn_ie); + cfg->ap_info->rsn_ie = NULL; + cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie, + ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else if (memcmp(cfg->ap_info->rsn_ie, + ies->wpa2_ie, ies->wpa2_ie->len + + WPA_RSN_IE_TAG_FIXED_LEN)) { + update_bss = true; + kfree(cfg->ap_info->rsn_ie); + cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, + ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + cfg->ap_info->wpa_ie = NULL; + } + } + if (update_bss) { + cfg->ap_info->security_mode = true; + wl_cfgp2p_bss(cfg, dev, bssidx, 0); + if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || + wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) { + return BCME_ERROR; + } + wl_cfgp2p_bss(cfg, dev, bssidx, 1); + } + } + } else { + WL_ERR(("No WPSIE in beacon \n")); + } + return 0; +} + +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) +static s32 +wl_cfg80211_del_station( + struct wiphy *wiphy, + struct net_device *ndev, + u8* mac_addr) +{ + struct net_device *dev; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + scb_val_t scb_val; + s8 eabuf[ETHER_ADDR_STR_LEN]; + int err; + char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * + sizeof(struct ether_addr) + sizeof(uint)] = {0}; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; + int num_associated = 0; + + WL_DBG(("Entry\n")); + if (mac_addr == NULL) { + WL_DBG(("mac_addr is NULL ignore it\n")); + return 0; + } + + dev = ndev_to_wlc_ndev(ndev, cfg); + + if (p2p_is_on(cfg)) { + /* Suspend P2P discovery search-listen to prevent it from changing the + * channel. + */ + if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) { + WL_ERR(("Can not disable discovery mode\n")); + return -EFAULT; + } + } + + assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; + err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST, + assoc_maclist, sizeof(mac_buf), false); + if (err < 0) + WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); + else + num_associated = assoc_maclist->count; + + memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN); + scb_val.val = DOT11_RC_DEAUTH_LEAVING; + err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t), true); + if (err < 0) + WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err)); + WL_ERR(("Disconnect STA : %s scb_val.val %d\n", + bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf), + scb_val.val)); + + if (num_associated > 0 && ETHER_ISBCAST(mac_addr)) + wl_delay(400); + + return 0; +} + +static s32 +wl_cfg80211_change_station( + struct wiphy *wiphy, + struct net_device *dev, + u8 *mac, + struct station_parameters *params) +{ + int err; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); + + /* Processing only authorize/de-authorize flag for now */ + if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) + return -ENOTSUPP; + + if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) { + err = wldev_ioctl(primary_ndev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN, true); + if (err) + WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err)); + return err; + } + + err = wldev_ioctl(primary_ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true); + if (err) + WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err)); +#ifdef DHD_LOSSLESS_ROAMING + wl_del_roam_timeout(cfg); +#endif /* DHD_LOSSLESS_ROAMING */ + return err; +} +#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +static s32 +wl_cfg80211_start_ap( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *info) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = BCME_OK; + struct parsed_ies ies; + s32 bssidx = 0; + u32 dev_role = 0; + + WL_DBG(("Enter \n")); + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + WL_DBG(("Start AP req on primary iface: Softap\n")); + dev_role = NL80211_IFTYPE_AP; + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == cfg->p2p_net) { + /* Group Add request on p2p0 */ + WL_DBG(("Start AP req on P2P iface: GO\n")); + dev = bcmcfg_to_prmry_ndev(cfg); + dev_role = NL80211_IFTYPE_P2P_GO; + } +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (p2p_is_on(cfg) && + (bssidx == wl_to_p2p_bss_bssidx(cfg, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + WL_DBG(("Start AP req on P2P connection iface\n")); + } + + if (!check_dev_role_integrity(cfg, dev_role)) + goto fail; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + if ((err = wl_cfg80211_set_channel(wiphy, dev, + dev->ieee80211_ptr->preset_chandef.chan, +#ifdef WL_SUPPORT_CHAN_BW + dev->ieee80211_ptr->preset_chandef.width) < 0)) { +#else + NL80211_CHAN_HT20) < 0)) { +#endif /* WL_SUPPORT_CHAN_BW */ + WL_ERR(("Set channel failed \n")); + goto fail; + } +#endif + + if ((err = wl_cfg80211_bcn_set_params(info, dev, + dev_role, bssidx)) < 0) { + WL_ERR(("Beacon params set failed \n")); + goto fail; + } + + /* Parse IEs */ + if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) { + WL_ERR(("Set IEs failed \n")); + goto fail; + } + + if ((wl_cfg80211_bcn_validate_sec(dev, &ies, + dev_role, bssidx)) < 0) + { + WL_ERR(("Beacon set security failed \n")); + goto fail; + } + + if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, + dev_role, bssidx)) < 0) { + WL_ERR(("Beacon bring up AP/GO failed \n")); + goto fail; + } + + WL_DBG(("** AP/GO Created **\n")); + +#ifdef WL_CFG80211_ACL + /* Enfoce Admission Control. */ + if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) { + WL_ERR(("Set ACL failed\n")); + } +#endif /* WL_CFG80211_ACL */ + + /* Set IEs to FW */ + if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0) + WL_ERR(("Set IEs failed \n")); + + /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ + if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) { + bool pbc = 0; + wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); + if (pbc) { + WL_DBG(("set WLC_E_PROBREQ_MSG\n")); + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + } + } + +fail: + if (err) { + WL_ERR(("ADD/SET beacon failed\n")); + wldev_iovar_setint(dev, "mpc", 1); + } + + return err; +} + +static s32 +wl_cfg80211_stop_ap( + struct wiphy *wiphy, + struct net_device *dev) +{ + int err = 0; + u32 dev_role = 0; + int infra = 0; + int ap = 0; + s32 bssidx = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + WL_DBG(("Enter \n")); + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + dev_role = NL80211_IFTYPE_AP; + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == cfg->p2p_net) { + /* Group Add request on p2p0 */ + dev = bcmcfg_to_prmry_ndev(cfg); + dev_role = NL80211_IFTYPE_P2P_GO; + } +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (p2p_is_on(cfg) && + (bssidx == wl_to_p2p_bss_bssidx(cfg, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + } + + if (!check_dev_role_integrity(cfg, dev_role)) + goto exit; + + if (dev_role == NL80211_IFTYPE_AP) { + /* SoftAp on primary Interface. + * Shut down AP and turn on MPC + */ + if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { + WL_ERR(("setting AP mode failed %d \n", err)); + err = -ENOTSUPP; + goto exit; + } + err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + err = -ENOTSUPP; + goto exit; + } + + err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + err = -EINVAL; + goto exit; + } + + wl_clr_drv_status(cfg, AP_CREATED, dev); + /* Turn on the MPC */ + wldev_iovar_setint(dev, "mpc", 1); + if (cfg->ap_info) { + kfree(cfg->ap_info->wpa_ie); + kfree(cfg->ap_info->rsn_ie); + kfree(cfg->ap_info->wps_ie); + kfree(cfg->ap_info); + cfg->ap_info = NULL; + } + } else { + WL_DBG(("Stopping P2P GO \n")); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub), + DHD_EVENT_TIMEOUT_MS*3); + DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub)); + } + +exit: + return err; +} + +static s32 +wl_cfg80211_change_beacon( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *info) +{ + s32 err = BCME_OK; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct parsed_ies ies; + u32 dev_role = 0; + s32 bssidx = 0; + bool pbc = 0; + + WL_DBG(("Enter \n")); + + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + dev_role = NL80211_IFTYPE_AP; + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == cfg->p2p_net) { + /* Group Add request on p2p0 */ + dev = bcmcfg_to_prmry_ndev(cfg); + dev_role = NL80211_IFTYPE_P2P_GO; + } +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (p2p_is_on(cfg) && + (bssidx == wl_to_p2p_bss_bssidx(cfg, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + } + + if (!check_dev_role_integrity(cfg, dev_role)) + goto fail; + + /* Parse IEs */ + if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) { + WL_ERR(("Parse IEs failed \n")); + goto fail; + } + + /* Set IEs to FW */ + if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) { + WL_ERR(("Set IEs failed \n")); + goto fail; + } + + if (dev_role == NL80211_IFTYPE_AP) { + if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { + WL_ERR(("Hostapd update sec failed \n")); + err = -EINVAL; + goto fail; + } + /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ + if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) { + wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); + WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc)); + if (pbc) + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + else + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); + } + } + +fail: + return err; +} +#else +static s32 +wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + s32 err = BCME_OK; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 ie_offset = 0; + s32 bssidx = 0; + u32 dev_role = NL80211_IFTYPE_AP; + struct parsed_ies ies; + bcm_tlv_t *ssid_ie; + bool pbc = 0; + WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", + info->interval, info->dtim_period, info->head_len, info->tail_len)); + + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + dev_role = NL80211_IFTYPE_AP; + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == cfg->p2p_net) { + /* Group Add request on p2p0 */ + dev = bcmcfg_to_prmry_ndev(cfg); + dev_role = NL80211_IFTYPE_P2P_GO; + } +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + if (p2p_is_on(cfg) && + (bssidx == wl_to_p2p_bss_bssidx(cfg, + P2PAPI_BSSCFG_CONNECTION))) { + dev_role = NL80211_IFTYPE_P2P_GO; + } + + if (!check_dev_role_integrity(cfg, dev_role)) + goto fail; + + ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + /* find the SSID */ + if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], + info->head_len - ie_offset, + DOT11_MNG_SSID_ID)) != NULL) { + if (dev_role == NL80211_IFTYPE_AP) { + /* Store the hostapd SSID */ + memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); + cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN); + memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data, + cfg->hostapd_ssid.SSID_len); + } else { + /* P2P GO */ + memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); + cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN); + memcpy(cfg->p2p->ssid.SSID, ssid_ie->data, + cfg->p2p->ssid.SSID_len); + } + } + + if (wl_cfg80211_parse_ies((u8 *)info->tail, + info->tail_len, &ies) < 0) { + WL_ERR(("Beacon get IEs failed \n")); + err = -EINVAL; + goto fail; + } + + if (wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + VNDR_IE_BEACON_FLAG, (u8 *)info->tail, + info->tail_len) < 0) { + WL_ERR(("Beacon set IEs failed \n")); + goto fail; + } else { + WL_DBG(("Applied Vndr IEs for Beacon \n")); + } + if (!wl_cfgp2p_bss_isup(dev, bssidx) && + (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx) < 0)) + { + WL_ERR(("Beacon set security failed \n")); + goto fail; + } + + /* Set BI and DTIM period */ + if (info->interval) { + if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, + &info->interval, sizeof(s32), true)) < 0) { + WL_ERR(("Beacon Interval Set Error, %d\n", err)); + return err; + } + } + if (info->dtim_period) { + if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, + &info->dtim_period, sizeof(s32), true)) < 0) { + WL_ERR(("DTIM Interval Set Error, %d\n", err)); + return err; + } + } + + if (wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx) < 0) { + WL_ERR(("Beacon bring up AP/GO failed \n")); + goto fail; + } + + if (wl_get_drv_status(cfg, AP_CREATED, dev)) { + /* Soft AP already running. Update changed params */ + if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { + WL_ERR(("Hostapd update sec failed \n")); + err = -EINVAL; + goto fail; + } + } + + /* Enable Probe Req filter */ + if (((dev_role == NL80211_IFTYPE_P2P_GO) || + (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) { + wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); + if (pbc) + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + } + + WL_DBG(("** ADD/SET beacon done **\n")); + +fail: + if (err) { + WL_ERR(("ADD/SET beacon failed\n")); + wldev_iovar_setint(dev, "mpc", 1); + } + return err; + +} +#endif + +#ifdef WL_SCHED_SCAN +#define PNO_TIME 120 +#define PNO_REPEAT 2 +#define PNO_FREQ_EXPO_MAX 1 +static bool +is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count) +{ + int i; + + if (!ssid || !ssid_list) + return FALSE; + + for (i = 0; i < count; i++) { + if (ssid->ssid_len == ssid_list[i].ssid_len) { + if (strncmp(ssid->ssid, ssid_list[i].ssid, ssid->ssid_len) == 0) + return TRUE; + } + } + return FALSE; +} + +static int +wl_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *request) +{ + ushort pno_time = PNO_TIME; + int pno_repeat = PNO_REPEAT; + int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; + wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct cfg80211_ssid *ssid = NULL; + struct cfg80211_ssid *hidden_ssid_list = NULL; + int ssid_cnt = 0; + int i; + int ret = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + s32 rssi_thold = 0; +#endif /* KERNEL_VER >= 3.6 */ + + if (!request) { + WL_ERR(("Sched scan request was NULL\n")); + return -EINVAL; + } + + WL_DBG(("Enter \n")); + WL_ERR((">>> SCHED SCAN START\n")); + WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n", + request->n_match_sets, request->n_ssids)); + WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n", + request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max)); + + + if (!request->n_ssids || !request->n_match_sets) { + WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids)); + return -EINVAL; + } + + memset(&ssids_local, 0, sizeof(ssids_local)); + + if (request->n_ssids > 0) + hidden_ssid_list = request->ssids; + + for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) { + ssid = &request->match_sets[i].ssid; + /* No need to include null ssid */ + if (ssid->ssid_len) { + ssids_local[ssid_cnt].SSID_len = MIN(ssid->ssid_len, + (uint32)DOT11_MAX_SSID_LEN); + memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid, + ssids_local[ssid_cnt].SSID_len); + if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) { + ssids_local[ssid_cnt].hidden = TRUE; + WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid)); + } else { + ssids_local[ssid_cnt].hidden = FALSE; + WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid->ssid)); + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + rssi_thold = request->match_sets[i].rssi_thold; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + rssi_thold = request->rssi_thold; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + if (rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) { + ssids_local[ssid_cnt].rssi_thresh = (int8)rssi_thold; + } +#endif /* KERNEL_VER >= 3.6 */ + ssid_cnt++; + } + } + + if (ssid_cnt) { + if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, ssid_cnt, pno_time, + pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) { + WL_ERR(("PNO setup failed!! ret=%d \n", ret)); + return -EINVAL; + } + cfg->sched_scan_req = request; + } else { + return -EINVAL; + } + + return 0; +} + +static int +wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + WL_DBG(("Enter \n")); + WL_PNO((">>> SCHED SCAN STOP\n")); + + if (dhd_dev_pno_stop_for_ssid(dev) < 0) + WL_ERR(("PNO Stop for SSID failed")); + + if (cfg->scan_request && cfg->sched_scan_running) { + WL_PNO((">>> Sched scan running. Aborting it..\n")); + wl_notify_escan_complete(cfg, dev, true, true); + } + + cfg->sched_scan_req = NULL; + cfg->sched_scan_running = FALSE; + + return 0; +} +#endif /* WL_SCHED_SCAN */ + +static struct cfg80211_ops wl_cfg80211_ops = { + .add_virtual_intf = wl_cfg80211_add_virtual_iface, + .del_virtual_intf = wl_cfg80211_del_virtual_iface, + .change_virtual_intf = wl_cfg80211_change_virtual_iface, +#if defined(WL_CFG80211_P2P_DEV_IF) + .start_p2p_device = wl_cfgp2p_start_p2p_device, + .stop_p2p_device = wl_cfgp2p_stop_p2p_device, +#endif /* WL_CFG80211_P2P_DEV_IF */ + .scan = wl_cfg80211_scan, + .set_wiphy_params = wl_cfg80211_set_wiphy_params, + .join_ibss = wl_cfg80211_join_ibss, + .leave_ibss = wl_cfg80211_leave_ibss, + .get_station = wl_cfg80211_get_station, + .set_tx_power = wl_cfg80211_set_tx_power, + .get_tx_power = wl_cfg80211_get_tx_power, + .add_key = wl_cfg80211_add_key, + .del_key = wl_cfg80211_del_key, + .get_key = wl_cfg80211_get_key, + .set_default_key = wl_cfg80211_config_default_key, + .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key, + .set_power_mgmt = wl_cfg80211_set_power_mgmt, + .connect = wl_cfg80211_connect, + .disconnect = wl_cfg80211_disconnect, + .suspend = wl_cfg80211_suspend, + .resume = wl_cfg80211_resume, + .set_pmksa = wl_cfg80211_set_pmksa, + .del_pmksa = wl_cfg80211_del_pmksa, + .flush_pmksa = wl_cfg80211_flush_pmksa, + .remain_on_channel = wl_cfg80211_remain_on_channel, + .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel, + .mgmt_tx = wl_cfg80211_mgmt_tx, + .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, + .change_bss = wl_cfg80211_change_bss, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + .set_channel = wl_cfg80211_set_channel, +#endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) + .set_beacon = wl_cfg80211_add_set_beacon, + .add_beacon = wl_cfg80211_add_set_beacon, +#else + .change_beacon = wl_cfg80211_change_beacon, + .start_ap = wl_cfg80211_start_ap, + .stop_ap = wl_cfg80211_stop_ap, +#endif +#ifdef WL_SCHED_SCAN + .sched_scan_start = wl_cfg80211_sched_scan_start, + .sched_scan_stop = wl_cfg80211_sched_scan_stop, +#endif /* WL_SCHED_SCAN */ +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) + .del_station = wl_cfg80211_del_station, + .change_station = wl_cfg80211_change_station, + .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, +#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) + .tdls_mgmt = wl_cfg80211_tdls_mgmt, + .tdls_oper = wl_cfg80211_tdls_oper, +#endif +#ifdef WL_CFG80211_ACL + .set_mac_acl = wl_cfg80211_set_mac_acl, +#endif /* WL_CFG80211_ACL */ +#if defined(WL_ABORT_SCAN) + .abort_scan = wl_cfg80211_abort_scan, +#endif /* WL_ABORT_SCAN */ + CFG80211_TESTMODE_CMD(dhd_cfg80211_testmode_cmd) +}; + +s32 wl_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; + case WL_MODE_AP: + return NL80211_IFTYPE_AP; + default: + return NL80211_IFTYPE_UNSPECIFIED; + } + + return err; +} + +#ifdef CONFIG_CFG80211_INTERNAL_REGDB +static int +wl_cfg80211_reg_notifier( + struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy); + int ret = 0; + + if (!request || !cfg) { + WL_ERR(("Invalid arg\n")); + return -EINVAL; + } + + WL_DBG(("ccode: %c%c Initiator: %d\n", + request->alpha2[0], request->alpha2[1], request->initiator)); + + /* We support only REGDOM_SET_BY_USER as of now */ + if ((request->initiator != NL80211_REGDOM_SET_BY_USER) && + (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) { + WL_ERR(("reg_notifier for intiator:%d not supported : set default\n", + request->initiator)); + /* in case of no supported country by regdb + lets driver setup platform default Locale + */ + } + + WL_ERR(("Set country code %c%c from %s\n", + request->alpha2[0], request->alpha2[1], + ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User"))); + + if ((ret = wldev_set_country(bcmcfg_to_prmry_ndev(cfg), request->alpha2, + false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false))) < 0) { + WL_ERR(("set country Failed :%d\n", ret)); + } + + return ret; +} +#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ + +#ifdef CONFIG_PM +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +static const struct wiphy_wowlan_support brcm_wowlan_support = { + .flags = WIPHY_WOWLAN_ANY, +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static struct cfg80211_wowlan brcm_wowlan_config = { + .disconnect = true, + .gtk_rekey_failure = true, + .eap_identity_req = true, + .four_way_handshake = true, +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ +#endif /* CONFIG_PM */ + +static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context) +{ + s32 err = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + dhd_pub_t *dhd = (dhd_pub_t *)context; + BCM_REFERENCE(dhd); + + if (!dhd) { + WL_ERR(("DHD is NULL!!")); + err = -ENODEV; + return err; + } +#endif + + wdev->wiphy = + wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211)); + if (unlikely(!wdev->wiphy)) { + WL_ERR(("Couldn not allocate wiphy device\n")); + err = -ENOMEM; + return err; + } + set_wiphy_dev(wdev->wiphy, sdiofunc_dev); + wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; + /* Report how many SSIDs Driver can support per Scan request */ + wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; + wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; +#ifdef WL_SCHED_SCAN + wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; + wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; + wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; +#endif /* WL_SCHED_SCAN */ + wdev->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC) +#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_MONITOR) +#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) +#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_P2P_DEVICE) +#endif /* WL_CFG80211_P2P_DEV_IF */ + | BIT(NL80211_IFTYPE_AP); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) + WL_DBG(("Setting interface combinations for common mode\n")); + wdev->wiphy->iface_combinations = common_iface_combinations; + wdev->wiphy->n_iface_combinations = + ARRAY_SIZE(common_iface_combinations); +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ + + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + + 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->max_remain_on_channel_duration = 5000; + wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes; +#ifndef WL_POWERSAVE_DISABLED + wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; +#else + wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; +#endif /* !WL_POWERSAVE_DISABLED */ + wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | + WIPHY_FLAG_4ADDR_AP | +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) + WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | +#endif + WIPHY_FLAG_4ADDR_STATION; +#if (defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && (LINUX_VERSION_CODE >= \ + KERNEL_VERSION(3, 2, 0)) + /* Please use supplicant ver >= 76 if FW_ROAM is enabled + * If driver advertises FW_ROAM, older supplicant wouldn't + * send the BSSID & Freq in the connect req command. This + * will delay the ASSOC as the FW need to do a full scan + * before attempting to connect. Supplicant >=76 has patch + * to allow bssid & freq to be sent down to driver even if + * FW ROAM is advertised. + */ + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) + wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_OFFCHAN_TX; +#endif +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 4, 0)) + /* From 3.4 kernel ownards AP_SME flag can be advertised + * to remove the patch from supplicant + */ + wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; + +#ifdef WL_CFG80211_ACL + /* Configure ACL capabilities. */ + wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + /* Supplicant distinguish between the SoftAP mode and other + * modes (e.g. P2P, WPS, HS2.0) when it builds the probe + * response frame from Supplicant MR1 and Kernel 3.4.0 or + * later version. To add Vendor specific IE into the + * probe response frame in case of SoftAP mode, + * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable. + */ + if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) { + wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + wdev->wiphy->probe_resp_offload = 0; + } +#endif +#endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */ + +#ifdef CONFIG_CFG80211_INTERNAL_REGDB + wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier; +#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; +#endif + +#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF) + /* + * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the + * disconnection of connected network before suspend. So a dummy wowlan + * filter is configured for kernels linux-3.8 and above. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + wdev->wiphy->wowlan = &brcm_wowlan_support; + + /* If this is not provided cfg stack will get disconnect + * during suspend. + */ + wdev->wiphy->wowlan_config = &brcm_wowlan_config; +#else + wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ +#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */ + + WL_DBG(("Registering custom regulatory)\n")); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; +#else + wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; +#endif + wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) + WL_ERR(("Registering Vendor80211)\n")); + err = wl_cfgvendor_attach(wdev->wiphy); + if (unlikely(err < 0)) { + WL_ERR(("Couldn not attach vendor commands (%d)\n", err)); + } +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ + + + /* Now we can register wiphy with cfg80211 module */ + err = wiphy_register(wdev->wiphy); + if (unlikely(err < 0)) { + WL_ERR(("Couldn not register wiphy device (%d)\n", err)); + wiphy_free(wdev->wiphy); + } + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS) + wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS; +#endif + + return err; +} + +static void wl_free_wdev(struct bcm_cfg80211 *cfg) +{ + struct wireless_dev *wdev = cfg->wdev; + struct wiphy *wiphy; + if (!wdev) { + WL_ERR(("wdev is invalid\n")); + return; + } + wiphy = wdev->wiphy; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) + wl_cfgvendor_detach(wdev->wiphy); +#endif /* if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ + + wiphy_unregister(wdev->wiphy); + wdev->wiphy->dev.parent = NULL; + + wl_delete_all_netinfo(cfg); + wiphy_free(wiphy); + /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg", + * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! + */ +} + +static s32 wl_inform_bss(struct bcm_cfg80211 *cfg) +{ + struct wl_scan_results *bss_list; + struct wl_bss_info *bi = NULL; /* must be initialized */ + s32 err = 0; + s32 i; + + bss_list = cfg->bss_list; + WL_DBG(("scanned AP count (%d)\n", bss_list->count)); + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + err = wl_inform_single_bss(cfg, bi, false); + if (unlikely(err)) + break; + } + return err; +} + +static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam) +{ + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct ieee80211_mgmt *mgmt; + struct ieee80211_channel *channel; + struct ieee80211_supported_band *band; + struct wl_cfg80211_bss_info *notif_bss_info; + struct wl_scan_req *sr = wl_to_sr(cfg); + struct beacon_proberesp *beacon_proberesp; + struct cfg80211_bss *cbss = NULL; + s32 mgmt_type; + s32 signal; + u32 freq; + s32 err = 0; + gfp_t aflags; + + if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { + WL_DBG(("Beacon is larger than buffer. Discarding\n")); + return err; + } + aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) + - sizeof(u8) + WL_BSS_INFO_MAX, aflags); + if (unlikely(!notif_bss_info)) { + WL_ERR(("notif_bss_info alloc failed\n")); + return -ENOMEM; + } + mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; + notif_bss_info->channel = + bi->ctl_ch ? bi->ctl_ch : wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); + + if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (!band) { + WL_ERR(("No valid band")); + kfree(notif_bss_info); + return -EINVAL; + } + notif_bss_info->rssi = wl_rssi_offset(dtoh16(bi->RSSI)); + memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); + mgmt_type = cfg->active_scan ? + IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; + if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type); + } + beacon_proberesp = cfg->active_scan ? + (struct beacon_proberesp *)&mgmt->u.probe_resp : + (struct beacon_proberesp *)&mgmt->u.beacon; + beacon_proberesp->timestamp = 0; + beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); + beacon_proberesp->capab_info = cpu_to_le16(bi->capability); + wl_rst_ie(cfg); + wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, roam); + wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length); + wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX - + offsetof(struct wl_cfg80211_bss_info, frame_buf)); + notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, + u.beacon.variable) + wl_get_ielen(cfg); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) + freq = ieee80211_channel_to_frequency(notif_bss_info->channel); + (void)band->band; +#else + freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); +#endif + if (freq == 0) { + WL_ERR(("Invalid channel, fail to chcnage channel to freq\n")); + kfree(notif_bss_info); + return -EINVAL; + } + channel = ieee80211_get_channel(wiphy, freq); + if (unlikely(!channel)) { + WL_ERR(("ieee80211_get_channel error\n")); + kfree(notif_bss_info); + return -EINVAL; + } + WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM" + "mgmt_type %d frame_len %d\n", bi->SSID, + notif_bss_info->rssi, notif_bss_info->channel, + mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type, + notif_bss_info->frame_len)); + + signal = notif_bss_info->rssi * 100; + if (!mgmt->u.probe_resp.timestamp) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) + struct timespec ts; + get_monotonic_boottime(&ts); + mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) + + ts.tv_nsec / 1000; +#else + struct timeval tv; + do_gettimeofday(&tv); + mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000) + + tv.tv_usec; +#endif + } + + + cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, + le16_to_cpu(notif_bss_info->frame_len), signal, aflags); + if (unlikely(!cbss)) { + WL_ERR(("cfg80211_inform_bss_frame error\n")); + kfree(notif_bss_info); + return -EINVAL; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + cfg80211_put_bss(wiphy, cbss); +#else + cfg80211_put_bss(cbss); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ + kfree(notif_bss_info); + return err; +} + +static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev) +{ + u32 event = ntoh32(e->event_type); + u32 status = ntoh32(e->status); + u16 flags = ntoh16(e->flags); + + WL_DBG(("event %d, status %d flags %x\n", event, status, flags)); + if (event == WLC_E_SET_SSID) { + if (status == WLC_E_STATUS_SUCCESS) { + if (!wl_is_ibssmode(cfg, ndev)) + return true; + } + } else if (event == WLC_E_LINK) { + if (flags & WLC_EVENT_MSG_LINK) + return true; + } + + WL_DBG(("wl_is_linkup false\n")); + return false; +} + +static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e) +{ + u32 event = ntoh32(e->event_type); + u16 flags = ntoh16(e->flags); + + if (event == WLC_E_DEAUTH_IND || + event == WLC_E_DISASSOC_IND || + event == WLC_E_DISASSOC || + event == WLC_E_DEAUTH) { +#if (WL_DBG_LEVEL > 0) + WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); +#endif /* (WL_DBG_LEVEL > 0) */ + return true; + } else if (event == WLC_E_LINK) { + if (!(flags & WLC_EVENT_MSG_LINK)) { +#if (WL_DBG_LEVEL > 0) + WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); +#endif /* (WL_DBG_LEVEL > 0) */ + return true; + } + } + + return false; +} + +static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e) +{ + u32 event = ntoh32(e->event_type); + u32 status = ntoh32(e->status); + + if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) + return true; + if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) + return true; + + return false; +} + +/* The mainline kernel >= 3.2.0 has support for indicating new/del station + * to AP/P2P GO via events. If this change is backported to kernel for which + * this driver is being built, then define WL_CFG80211_STA_EVENT. You + * should use this new/del sta event mechanism for BRCM supplicant >= 22. + */ +static s32 +wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + u32 event = ntoh32(e->event_type); + u32 reason = ntoh32(e->reason); + u32 len = ntoh32(e->datalen); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) + bool isfree = false; + u8 *mgmt_frame; + u8 bsscfgidx = e->bsscfgidx; + s32 freq; + s32 channel; + u8 *body = NULL; + u16 fc = 0; + + struct ieee80211_supported_band *band; + struct ether_addr da; + struct ether_addr bssid; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + channel_info_t ci; +#else + struct station_info sinfo; +#endif + + WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason)); + /* if link down, bsscfg is disabled. */ + if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS && + wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) { + wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false); + WL_INFO(("AP mode link down !! \n")); + complete(&cfg->iface_disable); + return 0; + } + + if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) { + WL_ERR(("event %s(%d) status %d reason %d\n", + bcmevent_names[event].name, event, ntoh32(e->status), reason)); + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) + WL_DBG(("Enter \n")); + if (!len && (event == WLC_E_DEAUTH)) { + len = 2; /* reason code field */ + data = &reason; + } + if (len) { + body = kzalloc(len, GFP_KERNEL); + + if (body == NULL) { + WL_ERR(("wl_notify_connect_status: Failed to allocate body\n")); + return WL_INVALID; + } + } + memset(&bssid, 0, ETHER_ADDR_LEN); + WL_DBG(("Enter event %d ndev %p\n", event, ndev)); + if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) { + kfree(body); + return WL_INVALID; + } + if (len) + memcpy(body, data, len); + + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); + memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); + memset(&bssid, 0, sizeof(bssid)); + err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + switch (event) { + case WLC_E_ASSOC_IND: + fc = FC_ASSOC_REQ; + break; + case WLC_E_REASSOC_IND: + fc = FC_REASSOC_REQ; + break; + case WLC_E_DISASSOC_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH: + fc = FC_DISASSOC; + break; + default: + fc = 0; + goto exit; + } + + memset(&ci, 0, sizeof(ci)); + if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { + kfree(body); + return err; + } + + channel = dtoh32(ci.hw_channel); + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (!band) { + WL_ERR(("No valid band")); + if (body) + kfree(body); + return -EINVAL; + } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) + freq = ieee80211_channel_to_frequency(channel); + (void)band->band; +#else + freq = ieee80211_channel_to_frequency(channel, band->band); +#endif + + err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, + &mgmt_frame, &len, body); + if (err < 0) + goto exit; + isfree = true; + + if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); +#endif + } else if (event == WLC_E_DISASSOC_IND) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); +#endif + } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); +#endif + } + +exit: + if (isfree) + kfree(mgmt_frame); + if (body) + kfree(body); +#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ + sinfo.filled = 0; + if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && + reason == DOT11_SC_SUCCESS) { + sinfo.filled = STATION_INFO_ASSOC_REQ_IES; + if (!data) { + WL_ERR(("No IEs present in ASSOC/REASSOC_IND")); + return -EINVAL; + } + sinfo.assoc_req_ies = data; + sinfo.assoc_req_ies_len = len; + cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); + } else if (event == WLC_E_DISASSOC_IND) { + cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); + } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { + cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); + } +#endif + return err; +} + +static s32 +wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e) +{ + u32 reason = ntoh32(e->reason); + u32 event = ntoh32(e->event_type); + struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); + WL_DBG(("event type : %d, reason : %d\n", event, reason)); + if (sec) { + switch (event) { + case WLC_E_ASSOC: + case WLC_E_AUTH: + sec->auth_assoc_res_status = reason; + default: + break; + } + } else + WL_ERR(("sec is NULL\n")); + return 0; +} + +static s32 +wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + u32 event = ntoh32(e->event_type); + u16 flags = ntoh16(e->flags); + u32 status = ntoh32(e->status); + bool active; + + if (event == WLC_E_JOIN) { + WL_DBG(("joined in IBSS network\n")); + } + if (event == WLC_E_START) { + WL_DBG(("started IBSS network\n")); + } + if (event == WLC_E_JOIN || event == WLC_E_START || + (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) { + if (wl_get_drv_status(cfg, CONNECTED, ndev)) { + /* ROAM or Redundant */ + u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) { + WL_DBG(("IBSS connected event from same BSSID(" + MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid))); + return err; + } + WL_INFO(("IBSS BSSID is changed from " MACDBG " to " MACDBG "\n", + MAC2STRDBG(cur_bssid), MAC2STRDBG((u8 *)&e->addr))); + wl_get_assoc_ies(cfg, ndev); + wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + wl_update_bss_info(cfg, ndev, false); + cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); + } + else { + /* New connection */ + WL_INFO(("IBSS connected to " MACDBG "\n", MAC2STRDBG((u8 *)&e->addr))); + wl_link_up(cfg); + wl_get_assoc_ies(cfg, ndev); + wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + wl_update_bss_info(cfg, ndev, false); + cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); + wl_set_drv_status(cfg, CONNECTED, ndev); + active = true; + wl_update_prof(cfg, ndev, NULL, (void *)&active, WL_PROF_ACT); + } + } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) || + event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) { + wl_clr_drv_status(cfg, CONNECTED, ndev); + wl_link_down(cfg); + wl_init_prof(cfg, ndev); + } + else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) { + WL_DBG(("no action - join fail (IBSS mode)\n")); + } + else { + WL_DBG(("no action (IBSS mode)\n")); +} + return err; +} + +static s32 +wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + bool act; + struct net_device *ndev = NULL; + s32 err = 0; + u32 event = ntoh32(e->event_type); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { + err = wl_notify_connect_status_ap(cfg, ndev, e, data); + } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS) { + err = wl_notify_connect_status_ibss(cfg, ndev, e, data); + } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) { + WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", + ntoh32(e->event_type), ntoh32(e->status), ndev)); + if (event == WLC_E_ASSOC || event == WLC_E_AUTH) { + wl_get_auth_assoc_status(cfg, ndev, e); + return 0; + } + if (wl_is_linkup(cfg, e, ndev)) { + wl_link_up(cfg); + act = true; + if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) { +#ifdef DHD_LOSSLESS_ROAMING + bool is_connected = wl_get_drv_status(cfg, CONNECTED, ndev); +#endif /* DHD_LOSSLESS_ROAMING */ + printk("wl_bss_connect_done succeeded with " MACDBG "\n", + MAC2STRDBG((u8*)(&e->addr))); + wl_bss_connect_done(cfg, ndev, e, data, true); + WL_DBG(("joined in BSS network \"%s\"\n", + ((struct wlc_ssid *) + wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID)); +#ifdef DHD_LOSSLESS_ROAMING + if (event == WLC_E_LINK && is_connected && + !cfg->roam_offload) { + wl_bss_roaming_done(cfg, ndev, e, data); + } +#endif /* DHD_LOSSLESS_ROAMING */ + } + wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); + wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + + } else if (wl_is_linkdown(cfg, e)) { +#ifdef DHD_LOSSLESS_ROAMING + wl_del_roam_timeout(cfg); +#endif /* DHD_LOSSLESS_ROAMING */ + if (cfg->scan_request) + wl_notify_escan_complete(cfg, ndev, true, true); + if (wl_get_drv_status(cfg, CONNECTED, ndev)) { + scb_val_t scbval; + u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + s32 reason = 0; + if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) + reason = ntoh32(e->reason); + /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ + reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; + + printk("link down if %s may call cfg80211_disconnected. " + "event : %d, reason=%d from " MACDBG "\n", + ndev->name, event, ntoh32(e->reason), + MAC2STRDBG((u8*)(&e->addr))); + if (!cfg->roam_offload && + memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) { + WL_ERR(("BSSID of event is not the connected BSSID" + "(ignore it) cur: " MACDBG " event: " MACDBG"\n", + MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr)))); + return 0; + } + wl_clr_drv_status(cfg, CONNECTED, ndev); + if (! wl_get_drv_status(cfg, DISCONNECTING, ndev)) { + /* To make sure disconnect, explictly send dissassoc + * for BSSID 00:00:00:00:00:00 issue + */ + scbval.val = WLAN_REASON_DEAUTH_LEAVING; + + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), true); + if (err < 0) { + WL_ERR(("WLC_DISASSOC error %d\n", err)); + err = 0; + } + cfg80211_disconnected(ndev, reason, NULL, 0, GFP_KERNEL); + wl_link_down(cfg); + wl_init_prof(cfg, ndev); + } + } + else if (wl_get_drv_status(cfg, CONNECTING, ndev)) { + printk("link down, during connecting\n"); +#ifdef ESCAN_RESULT_PATCH + if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) || + (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) || + (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0)) + /* In case this event comes while associating another AP */ +#endif /* ESCAN_RESULT_PATCH */ + wl_bss_connect_done(cfg, ndev, e, data, false); + } + wl_clr_drv_status(cfg, DISCONNECTING, ndev); + + /* if link down, bsscfg is diabled */ + if (ndev != bcmcfg_to_prmry_ndev(cfg)) + complete(&cfg->iface_disable); + + } else if (wl_is_nonetwork(cfg, e)) { + printk("connect failed event=%d e->status %d e->reason %d \n", + event, (int)ntoh32(e->status), (int)ntoh32(e->reason)); + /* Clean up any pending scan request */ + if (cfg->scan_request) + wl_notify_escan_complete(cfg, ndev, true, true); + if (wl_get_drv_status(cfg, CONNECTING, ndev)) + wl_bss_connect_done(cfg, ndev, e, data, false); + } else { + WL_DBG(("%s nothing\n", __FUNCTION__)); + } + } + else { + WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev))); + } + return err; +} + +void wl_cfg80211_set_rmc_pid(int pid) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + if (pid > 0) + cfg->rmc_event_pid = pid; + WL_DBG(("set pid for rmc event : pid=%d\n", pid)); +} + +#ifdef WLAIBSS +void wl_cfg80211_set_txfail_pid(int pid) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + if (pid > 0) + cfg->aibss_txfail_pid = pid; + WL_DBG(("set pid for aibss fail event : pid=%d\n", pid)); +} + +static s32 +wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + u32 evt = ntoh32(e->event_type); + int ret = -1; + + if (cfg->aibss_txfail_pid != 0) { + ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL, + cfg->aibss_txfail_seq++, (void *)&e->addr, ETHER_ADDR_LEN); + } + + WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n", + evt, cfg->aibss_txfail_pid, ret, ETHERP_TO_MACF(&e->addr))); + return ret; +} +#endif /* WLAIBSS */ + +static s32 +wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + u32 evt = ntoh32(e->event_type); + u32 reason = ntoh32(e->reason); + int ret = -1; + + switch (reason) { + case WLC_E_REASON_RMC_AR_LOST: + case WLC_E_REASON_RMC_AR_NO_ACK: + if (cfg->rmc_event_pid != 0) { + ret = wl_netlink_send_msg(cfg->rmc_event_pid, + RMC_EVENT_LEADER_CHECK_FAIL, + cfg->rmc_event_seq++, NULL, 0); + } + break; + default: + break; + } + WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret)); + return ret; +} + +#ifdef RSSI_MONITOR_SUPPORT +static s32 +wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ +#if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT) + u32 datalen = be32_to_cpu(e->datalen); + struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + + if (datalen) { + wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data; + if (evt_data->version == RSSI_MONITOR_VERSION) { + dhd_rssi_monitor_evt_t monitor_data; + monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION; + monitor_data.cur_rssi = evt_data->cur_rssi; + memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN); + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_RSSI_MONITOR_EVENT, + &monitor_data, sizeof(monitor_data)); + } else { + WL_ERR(("Version mismatch %d, expected %d", evt_data->version, + RSSI_MONITOR_VERSION)); + } + } +#endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */ + return BCME_OK; +} +#endif /* RSSI_MONITOR_SUPPORT */ + +static s32 +wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + bool act; + struct net_device *ndev = NULL; + s32 err = 0; + u32 event = be32_to_cpu(e->event_type); + u32 status = be32_to_cpu(e->status); +#ifdef DHD_LOSSLESS_ROAMING + struct wl_security *sec; +#endif + WL_DBG(("Enter \n")); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) { + wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false); + cfg->disable_roam_event = TRUE; + } + + if ((cfg->disable_roam_event) && (event == WLC_E_ROAM)) + return err; + + if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) { + if (wl_get_drv_status(cfg, CONNECTED, ndev)) { +#ifdef DHD_LOSSLESS_ROAMING + if (cfg->roam_offload) { + wl_bss_roaming_done(cfg, ndev, e, data); + wl_del_roam_timeout(cfg); + } + else { + sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); + /* In order to reduce roaming delay, wl_bss_roaming_done is + * early called with WLC_E_LINK event. It is called from + * here only if WLC_E_LINK event is blocked for specific + * security type. + */ + if (IS_AKM_SUITE_FT(sec)) { + wl_bss_roaming_done(cfg, ndev, e, data); + } + /* Roam timer is deleted mostly from wl_cfg80211_change_station + * after roaming is finished successfully. We need to delete + * the timer from here only for some security types that aren't + * using wl_cfg80211_change_station to authorize SCB + */ + if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) { + wl_del_roam_timeout(cfg); + } + } +#else /* DHD_LOSSLESS_ROAMING */ + wl_bss_roaming_done(cfg, ndev, e, data); +#endif /* DHD_LOSSLESS_ROAMING */ + } else { + wl_bss_connect_done(cfg, ndev, e, data, true); + } + act = true; + wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); + wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + } +#ifdef DHD_LOSSLESS_ROAMING + else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) { + wl_del_roam_timeout(cfg); + } +#endif /* DHD_LOSSLESS_ROAMING */ + + return err; +} + +#ifdef DHD_LOSSLESS_ROAMING +static s32 +wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + struct wl_security *sec; + struct net_device *ndev; + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); + /* Disable Lossless Roaming for specific AKM suite + * Any other AKM suite can be added below if transition time + * is delayed because of Lossless Roaming + * and it causes any certication failure + */ + if (IS_AKM_SUITE_FT(sec)) { + return err; + } + + dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC; + /* Restore flow control */ + dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF); + + mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS)); + + return err; +} +#endif /* DHD_LOSSLESS_ROAMING */ + +static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + wl_assoc_info_t assoc_info; + struct wl_connect_info *conn_info = wl_to_conn(cfg); + s32 err = 0; + + WL_DBG(("Enter \n")); + err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); + if (unlikely(err)) { + WL_ERR(("could not get assoc info (%d)\n", err)); + return err; + } + memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t)); + assoc_info.req_len = htod32(assoc_info.req_len); + assoc_info.resp_len = htod32(assoc_info.resp_len); + assoc_info.flags = htod32(assoc_info.flags); + if (conn_info->req_ie_len) { + conn_info->req_ie_len = 0; + bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); + } + if (conn_info->resp_ie_len) { + conn_info->resp_ie_len = 0; + bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); + } + if (assoc_info.req_len) { + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); + if (unlikely(err)) { + WL_ERR(("could not get assoc req (%d)\n", err)); + return err; + } + conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); + if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { + conn_info->req_ie_len -= ETHER_ADDR_LEN; + } + if (conn_info->req_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); + else { + WL_ERR(("IE size %d above max %d size \n", + conn_info->req_ie_len, MAX_REQ_LINE)); + return err; + } + } else { + conn_info->req_ie_len = 0; + } + if (assoc_info.resp_len) { + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); + if (unlikely(err)) { + WL_ERR(("could not get assoc resp (%d)\n", err)); + return err; + } + conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); + if (conn_info->resp_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); + else { + WL_ERR(("IE size %d above max %d size \n", + conn_info->resp_ie_len, MAX_REQ_LINE)); + return err; + } + } else { + conn_info->resp_ie_len = 0; + } + WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, + conn_info->resp_ie_len)); + + return err; +} + +static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, + size_t *join_params_size) +{ + chanspec_t chanspec = 0; + if (ch != 0) { + join_params->params.chanspec_num = 1; + join_params->params.chanspec_list[0] = ch; + + if (join_params->params.chanspec_list[0] <= 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 += WL_ASSOC_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(chanspec_t); + + join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + join_params->params.chanspec_list[0] |= chanspec; + join_params->params.chanspec_list[0] = + wl_chspec_host_to_driver(join_params->params.chanspec_list[0]); + + join_params->params.chanspec_num = + htod32(join_params->params.chanspec_num); + WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n", + join_params->params.chanspec_list[0], + join_params->params.chanspec_num)); + } +} + +static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam) +{ + struct cfg80211_bss *bss; + struct wl_bss_info *bi; + struct wlc_ssid *ssid; + struct bcm_tlv *tim; + s32 beacon_interval; + s32 dtim_period; + size_t ie_len; + u8 *ie; + u8 *curbssid; + s32 err = 0; + struct wiphy *wiphy; + u32 channel; + char *buf; + + wiphy = bcmcfg_to_wiphy(cfg); + + ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID); + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + bss = cfg80211_get_bss(wiphy, NULL, curbssid, + ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + + mutex_lock(&cfg->usr_sync); + + buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_ATOMIC); + if (!buf) { + WL_ERR(("buffer alloc failed.\n")); + return BCME_NOMEM; + } + *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX); + err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, + buf, WL_EXTRA_BUF_MAX, false); + if (unlikely(err)) { + WL_ERR(("Could not get bss info %d\n", err)); + goto update_bss_info_out; + } + bi = (wl_bss_info_t *)(buf + 4); + channel = bi->ctl_ch ? bi->ctl_ch : + CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); + wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN); + + if (!bss) { + WL_DBG(("Could not find the AP\n")); + if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) { + WL_ERR(("Bssid doesn't match\n")); + err = -EIO; + goto update_bss_info_out; + } + err = wl_inform_single_bss(cfg, bi, roam); + if (unlikely(err)) + goto update_bss_info_out; + + ie = ((u8 *)bi) + bi->ie_offset; + ie_len = bi->ie_length; + beacon_interval = cpu_to_le16(bi->beacon_period); + } else { + WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); +#if defined(WL_CFG80211_P2P_DEV_IF) + ie = (u8 *)bss->ies->data; + ie_len = bss->ies->len; +#else + ie = bss->information_elements; + ie_len = bss->len_information_elements; +#endif /* WL_CFG80211_P2P_DEV_IF */ + beacon_interval = bss->beacon_interval; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + cfg80211_put_bss(wiphy, bss); +#else + cfg80211_put_bss(bss); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ + } + + tim = bcm_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. + */ + dtim_period = 0; + err = wldev_ioctl(ndev, WLC_GET_DTIMPRD, + &dtim_period, sizeof(dtim_period), false); + if (unlikely(err)) { + WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); + goto update_bss_info_out; + } + } + + wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT); + wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); + +update_bss_info_out: + if (unlikely(err)) { + WL_ERR(("Failed with error %d\n", err)); + } + + kfree(buf); + mutex_unlock(&cfg->usr_sync); + return err; +} + +static s32 +wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + struct wl_connect_info *conn_info = wl_to_conn(cfg); + s32 err = 0; + u8 *curbssid; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct ieee80211_supported_band *band; + struct ieee80211_channel *notify_channel = NULL; + u32 *channel; + u32 freq; +#endif + +#ifdef WLFBT + uint32 data_len = 0; + if (data) + data_len = ntoh32(e->datalen); +#endif /* WLFBT */ + + wl_get_assoc_ies(cfg, ndev); + wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + wl_update_bss_info(cfg, ndev, true); + wl_update_pmklist(ndev, cfg->pmk_list, err); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) + /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */ + channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN); + 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); +#endif +#ifdef WLFBT + /* back up the given FBT key for the further supplicant request, + * currently not checking the FBT is enabled for current BSS in DHD, + * because the supplicant decides to take it or not. + */ + if (data && (data_len == FBT_KEYLEN)) { + memcpy(cfg->fbt_key, data, FBT_KEYLEN); + } +#endif /* WLFBT */ + printk("wl_bss_roaming_done succeeded to " MACDBG "\n", + MAC2STRDBG((u8*)(&e->addr))); + + cfg80211_roamed(ndev, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) + notify_channel, +#endif + curbssid, + conn_info->req_ie, conn_info->req_ie_len, + conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); + WL_DBG(("Report roaming result\n")); + + wl_set_drv_status(cfg, CONNECTED, ndev); + + return err; +} + +static s32 +wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data, bool completed) +{ + struct wl_connect_info *conn_info = wl_to_conn(cfg); + struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); +#if (defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)) + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif + s32 err = 0; + u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + if (!sec) { + WL_ERR(("sec is NULL\n")); + return -ENODEV; + } + WL_DBG((" enter\n")); +#ifdef ESCAN_RESULT_PATCH + if (wl_get_drv_status(cfg, CONNECTED, ndev)) { + if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) { + WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n", + ntoh32(e->event_type), ntoh32(e->status))); + return err; + } + } + if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 && + memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) { + WL_DBG(("copy bssid\n")); + memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); + } + +#else + if (cfg->scan_request) { + wl_notify_escan_complete(cfg, ndev, true, true); + } +#endif /* ESCAN_RESULT_PATCH */ + if (wl_get_drv_status(cfg, CONNECTING, ndev)) { + wl_cfg80211_scan_abort(cfg); + wl_clr_drv_status(cfg, CONNECTING, ndev); + if (completed) { + wl_get_assoc_ies(cfg, ndev); + wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + wl_update_bss_info(cfg, ndev, false); + wl_update_pmklist(ndev, cfg->pmk_list, err); + wl_set_drv_status(cfg, CONNECTED, ndev); +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + if (dhd->roam_env_detection) + wldev_iovar_setint(ndev, "roam_env_detection", + AP_ENV_INDETERMINATE); +#endif /* ROAM_AP_ENV_DETECTION */ + if (ndev != bcmcfg_to_prmry_ndev(cfg)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + init_completion(&cfg->iface_disable); +#else + /* reinitialize completion to clear previous count */ + INIT_COMPLETION(cfg->iface_disable); +#endif + } + + } + cfg80211_connect_result(ndev, + curbssid, + conn_info->req_ie, + conn_info->req_ie_len, + conn_info->resp_ie, + conn_info->resp_ie_len, + completed ? WLAN_STATUS_SUCCESS : + (sec->auth_assoc_res_status) ? + sec->auth_assoc_res_status : + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + if (completed) + WL_INFO(("Report connect result - connection succeeded\n")); + else + WL_ERR(("Report connect result - connection failed\n")); + } +#ifdef CONFIG_TCPACK_FASTTX + if (wl_get_chan_isvht80(ndev, dhd)) + wldev_iovar_setint(ndev, "tcpack_fast_tx", 0); + else + wldev_iovar_setint(ndev, "tcpack_fast_tx", 1); +#endif /* CONFIG_TCPACK_FASTTX */ + + return err; +} + +static s32 +wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct net_device *ndev = NULL; + u16 flags = ntoh16(e->flags); + enum nl80211_key_type key_type; + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + mutex_lock(&cfg->usr_sync); + if (flags & WLC_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); + mutex_unlock(&cfg->usr_sync); + + return 0; +} + +#ifdef PNO_SUPPORT +static s32 +wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct net_device *ndev = NULL; +#ifdef GSCAN_SUPPORT + void *ptr; + int send_evt_bytes = 0; + u32 event = be32_to_cpu(e->event_type); + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); +#endif /* GSCAN_SUPPORT */ + + WL_ERR((">>> PNO Event\n")); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + +#ifdef GSCAN_SUPPORT + ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes); + if (ptr) { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes); + kfree(ptr); + } + if (!dhd_dev_is_legacy_pno_enabled(ndev)) + return 0; +#endif /* GSCAN_SUPPORT */ + +#ifndef WL_SCHED_SCAN + mutex_lock(&cfg->usr_sync); + /* TODO: Use cfg80211_sched_scan_results(wiphy); */ + cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + mutex_unlock(&cfg->usr_sync); +#else + /* If cfg80211 scheduled scan is supported, report the pno results via sched + * scan results + */ + wl_notify_sched_scan_results(cfg, ndev, e, data); +#endif /* WL_SCHED_SCAN */ + return 0; +} +#endif /* PNO_SUPPORT */ + +#ifdef GSCAN_SUPPORT +static s32 +wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + u32 event = be32_to_cpu(e->event_type); + void *ptr; + int send_evt_bytes = 0; + int batch_event_result_dummy = 0; + struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + u32 len = ntoh32(e->datalen); + + switch (event) { + case WLC_E_PFN_SWC: + ptr = dhd_dev_swc_scan_event(ndev, data, &send_evt_bytes); + if (send_evt_bytes) { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_GSCAN_SIGNIFICANT_EVENT, ptr, send_evt_bytes); + kfree(ptr); + } else + err = -ENOMEM; + break; + case WLC_E_PFN_BEST_BATCHING: + err = dhd_dev_retrieve_batch_scan(ndev); + if (err < 0) { + WL_ERR(("Batch retrieval already in progress %d\n", err)); + } else { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_GSCAN_BATCH_SCAN_EVENT, + &batch_event_result_dummy, sizeof(int)); + } + break; + case WLC_E_PFN_SCAN_COMPLETE: + batch_event_result_dummy = WIFI_SCAN_COMPLETE; + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_SCAN_COMPLETE_EVENT, + &batch_event_result_dummy, sizeof(int)); + break; + case WLC_E_PFN_BSSID_NET_FOUND: + ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes, + HOTLIST_FOUND); + if (ptr) { + wl_cfgvendor_send_hotlist_event(wiphy, ndev, + ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT); + dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_FOUND); + } else { + err = -ENOMEM; + } + break; + case WLC_E_PFN_BSSID_NET_LOST: + /* WLC_E_PFN_BSSID_NET_LOST is conflict shared with WLC_E_PFN_SCAN_ALLGONE + * We currently do not use WLC_E_PFN_SCAN_ALLGONE, so if we get it, ignore + */ + if (len) { + ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes, + HOTLIST_LOST); + if (ptr) { + wl_cfgvendor_send_hotlist_event(wiphy, ndev, + ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT); + dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_LOST); + } else { + err = -ENOMEM; + } + } else { + err = -EINVAL; + } + break; + case WLC_E_PFN_GSCAN_FULL_RESULT: + ptr = dhd_dev_process_full_gscan_result(ndev, data, &send_evt_bytes); + if (ptr) { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes); + kfree(ptr); + } else { + err = -ENOMEM; + } + break; + case WLC_E_PFN_SSID_EXT: + ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes); + if (ptr) { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes); + kfree(ptr); + } else { + err = -ENOMEM; + } + break; +#ifdef ANQPO_SUPPORT + case WLC_E_PFN_NET_FOUND: + ptr = dhd_dev_process_anqpo_result(ndev, data, event, &len); + if (ptr) { + wl_cfgvendor_send_async_event(wiphy, ndev, + GOOGLE_PNO_HOTSPOT_FOUND_EVENT, ptr, len); + kfree(ptr); + } else + err = -ENOMEM; + break; +#endif /* ANQPO_SUPPORT */ + default: + WL_ERR(("Unknown event %d\n", event)); + break; + } + return err; +} +#endif /* GSCAN_SUPPORT */ + +static s32 +wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct channel_info channel_inform; + struct wl_scan_results *bss_list; + struct net_device *ndev = NULL; + u32 len = WL_SCAN_BUF_MAX; + s32 err = 0; + unsigned long flags; + + WL_DBG(("Enter \n")); + if (!wl_get_drv_status(cfg, SCANNING, ndev)) { + WL_ERR(("scan is not ready \n")); + return err; + } + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + mutex_lock(&cfg->usr_sync); + wl_clr_drv_status(cfg, SCANNING, ndev); + memset(&channel_inform, 0, sizeof(channel_inform)); + err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, + sizeof(channel_inform), false); + if (unlikely(err)) { + WL_ERR(("scan busy (%d)\n", err)); + goto scan_done_out; + } + channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); + if (unlikely(channel_inform.scan_channel)) { + + WL_DBG(("channel_inform.scan_channel (%d)\n", + channel_inform.scan_channel)); + } + cfg->bss_list = cfg->scan_results; + bss_list = cfg->bss_list; + memset(bss_list, 0, len); + bss_list->buflen = htod32(len); + err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false); + if (unlikely(err) && unlikely(!cfg->scan_suppressed)) { + WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); + err = -EINVAL; + goto scan_done_out; + } + bss_list->buflen = dtoh32(bss_list->buflen); + bss_list->version = dtoh32(bss_list->version); + bss_list->count = dtoh32(bss_list->count); + + err = wl_inform_bss(cfg); + +scan_done_out: + del_timer_sync(&cfg->scan_timeout); + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + if (cfg->scan_request) { + cfg80211_scan_done(cfg->scan_request, false); + cfg->scan_request = NULL; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + WL_DBG(("cfg80211_scan_done\n")); + mutex_unlock(&cfg->usr_sync); + return err; +} + +static s32 +wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, + const struct ether_addr *sa, const struct ether_addr *bssid, + u8 **pheader, u32 *body_len, u8 *pbody) +{ + struct dot11_management_header *hdr; + u32 totlen = 0; + s32 err = 0; + u8 *offset; + u32 prebody_len = *body_len; + switch (fc) { + case FC_ASSOC_REQ: + /* capability , listen interval */ + totlen = DOT11_ASSOC_REQ_FIXED_LEN; + *body_len += DOT11_ASSOC_REQ_FIXED_LEN; + break; + + case FC_REASSOC_REQ: + /* capability, listen inteval, ap address */ + totlen = DOT11_REASSOC_REQ_FIXED_LEN; + *body_len += DOT11_REASSOC_REQ_FIXED_LEN; + break; + } + totlen += DOT11_MGMT_HDR_LEN + prebody_len; + *pheader = kzalloc(totlen, GFP_KERNEL); + if (*pheader == NULL) { + WL_ERR(("memory alloc failed \n")); + return -ENOMEM; + } + hdr = (struct dot11_management_header *) (*pheader); + hdr->fc = htol16(fc); + hdr->durid = 0; + hdr->seq = 0; + offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len); + bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN); + bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN); + bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN); + if ((pbody != NULL) && prebody_len) + bcopy((const char*)pbody, offset, prebody_len); + *body_len = totlen; + return err; +} + + +void +wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + if (timer_pending(&cfg->p2p->listen_timer)) { + del_timer_sync(&cfg->p2p->listen_timer); + } + if (cfg->afx_hdl != NULL) { + if (cfg->afx_hdl->dev != NULL) { + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev); + } + cfg->afx_hdl->peer_chan = WL_INVALID; + } + complete(&cfg->act_frm_scan); + WL_DBG(("*** Wake UP ** Working afx searching is cleared\n")); + } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) { + if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) || + wl_get_p2p_status(cfg, ACTION_TX_NOACK))) + wl_set_p2p_status(cfg, ACTION_TX_COMPLETED); + + WL_DBG(("*** Wake UP ** abort actframe iovar\n")); + /* if channel is not zero, "actfame" uses off channel scan. + * So abort scan for off channel completion. + */ + if (cfg->af_sent_channel) + wl_cfg80211_scan_abort(cfg); + } +#ifdef WL_CFG80211_SYNC_GON + else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { + WL_DBG(("*** Wake UP ** abort listen for next af frame\n")); + /* So abort scan to cancel listen */ + wl_cfg80211_scan_abort(cfg); + } +#endif /* WL_CFG80211_SYNC_GON */ +} + + +int wl_cfg80211_get_ioctl_version(void) +{ + return ioctl_version; +} + +static s32 +wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct ieee80211_supported_band *band; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct ether_addr da; + struct ether_addr bssid; + bool isfree = false; + s32 err = 0; + s32 freq; + struct net_device *ndev = NULL; + wifi_p2p_pub_act_frame_t *act_frm = NULL; + wifi_p2p_action_frame_t *p2p_act_frm = NULL; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; + wl_event_rx_frame_data_t *rxframe = + (wl_event_rx_frame_data_t*)data; + u32 event = ntoh32(e->event_type); + u8 *mgmt_frame; + u8 bsscfgidx = e->bsscfgidx; + u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); + u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); + + memset(&bssid, 0, ETHER_ADDR_LEN); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (!band) { + WL_ERR(("No valid band")); + return -EINVAL; + } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) + freq = ieee80211_channel_to_frequency(channel); + (void)band->band; +#else + freq = ieee80211_channel_to_frequency(channel, band->band); +#endif + if (event == WLC_E_ACTION_FRAME_RX) { + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); + + memset(&bssid, 0, sizeof(bssid)); + err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + if (err < 0) + WL_ERR(("WLC_GET_BSSID error %d\n", err)); + memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); + err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, + &mgmt_frame, &mgmt_frame_len, + (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); + if (err < 0) { + WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n", + mgmt_frame_len, channel, freq)); + goto exit; + } + isfree = true; + if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + act_frm = (wifi_p2p_pub_act_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + p2p_act_frm = (wifi_p2p_action_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + (void) p2p_act_frm; + } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) { + if (cfg->next_af_subtype == sd_act_frm->action) { + WL_DBG(("We got a right next frame of SD!(%d)\n", + sd_act_frm->action)); + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); + + /* Stop waiting for next AF. */ + wl_stop_wait_next_action_frame(cfg, ndev); + } + } + (void) sd_act_frm; +#ifdef WLTDLS + } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) { + WL_DBG((" TDLS Action Frame Received type = %d \n", + mgmt_frame[DOT11_MGMT_HDR_LEN + 1])); + + if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) { + cfg->tdls_mgmt_frame = mgmt_frame; + cfg->tdls_mgmt_frame_len = mgmt_frame_len; + cfg->tdls_mgmt_freq = freq; + return 0; + } + + } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_VENDOR_SPECIFIC) { + WL_DBG((" TDLS Vendor Specific Received type \n")); +#endif + } else { + + if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { + u8 action = 0; + if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) { + WL_DBG(("Recived action is not public action frame\n")); + } else if (cfg->next_af_subtype == action) { + WL_DBG(("Recived action is the waiting action(%d)\n", + action)); + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); + + /* Stop waiting for next AF. */ + wl_stop_wait_next_action_frame(cfg, ndev); + } + } + } + + if (act_frm) { + + if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) { + if (cfg->next_af_subtype == act_frm->subtype) { + WL_DBG(("We got a right next frame!(%d)\n", + act_frm->subtype)); + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); + + if (cfg->next_af_subtype == P2P_PAF_GON_CONF) { + OSL_SLEEP(20); + } + + /* Stop waiting for next AF. */ + wl_stop_wait_next_action_frame(cfg, ndev); + } + } + } + + wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel); + /* + * After complete GO Negotiation, roll back to mpc mode + */ + if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || + (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { + wldev_iovar_setint(ndev, "mpc", 1); + } + if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + } + } else if (event == WLC_E_PROBREQ_MSG) { + + /* Handle probe reqs frame + * WPS-AP certification 4.2.13 + */ + struct parsed_ies prbreq_ies; + u32 prbreq_ie_len = 0; + bool pbc = 0; + + WL_DBG((" Event WLC_E_PROBREQ_MSG received\n")); + mgmt_frame = (u8 *)(data); + mgmt_frame_len = ntoh32(e->datalen); + + prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN; + + /* Parse prob_req IEs */ + if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN], + prbreq_ie_len, &prbreq_ies) < 0) { + WL_ERR(("Prob req get IEs failed\n")); + return 0; + } + if (prbreq_ies.wps_ie != NULL) { + wl_validate_wps_ie((char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc); + WL_DBG((" wps_ie exist pbc = %d\n", pbc)); + /* if pbc method, send prob_req mgmt frame to upper layer */ + if (!pbc) + return 0; + } else + return 0; + } else { + mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); + + /* wpa supplicant use probe request event for restarting another GON Req. + * but it makes GON Req repetition. + * so if src addr of prb req is same as my target device, + * do not send probe request event during sending action frame. + */ + if (event == WLC_E_P2P_PROBREQ_MSG) { + WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ? + "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG")); + + + /* Filter any P2P probe reqs arriving during the + * GO-NEG Phase + */ + if (cfg->p2p && + wl_get_p2p_status(cfg, GO_NEG_PHASE)) { + WL_DBG(("Filtering P2P probe_req while " + "being in GO-Neg state\n")); + return 0; + } + } + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ + defined(WL_COMPAT_WIRELESS) + cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); +#endif /* LINUX_VERSION >= VERSION(3, 13, 0) */ + + WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", + mgmt_frame_len, ntoh32(e->datalen), channel, freq)); +exit: + if (isfree) + kfree(mgmt_frame); + return 0; +} + +#ifdef WL_SCHED_SCAN +/* If target scan is not reliable, set the below define to "1" to do a + * full escan + */ +#define FULL_ESCAN_ON_PFN_NET_FOUND 0 +static s32 +wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + wl_pfn_net_info_t *netinfo, *pnetinfo; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + int err = 0; + struct cfg80211_scan_request *request = NULL; + struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; + struct ieee80211_channel *channel = NULL; + int channel_req = 0; + int band = 0; + struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; + int n_pfn_results = pfn_result->count; + + WL_DBG(("Enter\n")); + + if ((e->event_type == WLC_E_PFN_NET_LOST) || !data) { + WL_PNO(("Do Nothing %d\n", e->event_type)); + return 0; + } + if (pfn_result->version != PFN_SCANRESULT_VERSION) { + WL_ERR(("Incorrect version %d, expected %d\n", pfn_result->version, + PFN_SCANRESULT_VERSION)); + return 0; + } + WL_PNO((">>> PFN NET FOUND event. count:%d \n", n_pfn_results)); + if (n_pfn_results > 0) { + int i; + + if (n_pfn_results > MAX_PFN_LIST_COUNT) + n_pfn_results = MAX_PFN_LIST_COUNT; + pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) + - sizeof(wl_pfn_net_info_t)); + + memset(&ssid, 0x00, sizeof(ssid)); + + request = kzalloc(sizeof(*request) + + sizeof(*request->channels) * n_pfn_results, + GFP_KERNEL); + channel = (struct ieee80211_channel *)kzalloc( + (sizeof(struct ieee80211_channel) * n_pfn_results), + GFP_KERNEL); + if (!request || !channel) { + WL_ERR(("No memory")); + err = -ENOMEM; + goto out_err; + } + + request->wiphy = wiphy; + + for (i = 0; i < n_pfn_results; i++) { + netinfo = &pnetinfo[i]; + if (!netinfo) { + WL_ERR(("Invalid netinfo ptr. index:%d", i)); + err = -EINVAL; + goto out_err; + } + WL_PNO((">>> SSID:%s Channel:%d \n", + netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel)); + /* PFN result doesn't have all the info which are required by the supplicant + * (For e.g IEs) Do a target Escan so that sched scan results are reported + * via wl_inform_single_bss in the required format. Escan does require the + * scan request in the form of cfg80211_scan_request. For timebeing, create + * cfg80211_scan_request one out of the received PNO event. + */ + ssid[i].ssid_len = MIN(netinfo->pfnsubnet.SSID_len, DOT11_MAX_SSID_LEN); + memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, ssid[i].ssid_len); + request->n_ssids++; + + channel_req = netinfo->pfnsubnet.channel; + band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ + : NL80211_BAND_5GHZ; + channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); + channel[i].band = band; + channel[i].flags |= IEEE80211_CHAN_NO_HT40; + request->channels[i] = &channel[i]; + request->n_channels++; + } + + /* assign parsed ssid array */ + if (request->n_ssids) + request->ssids = &ssid[0]; + + if (wl_get_drv_status_all(cfg, SCANNING)) { + /* Abort any on-going scan */ + wl_notify_escan_complete(cfg, ndev, true, true); + } + + if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { + WL_PNO((">>> P2P discovery was ON. Disabling it\n")); + err = wl_cfgp2p_discover_enable_search(cfg, false); + if (unlikely(err)) { + wl_clr_drv_status(cfg, SCANNING, ndev); + goto out_err; + } + p2p_scan(cfg) = false; + } + + wl_set_drv_status(cfg, SCANNING, ndev); +#if FULL_ESCAN_ON_PFN_NET_FOUND + WL_PNO((">>> Doing Full ESCAN on PNO event\n")); + err = wl_do_escan(cfg, wiphy, ndev, NULL); +#else + WL_PNO((">>> Doing targeted ESCAN on PNO event\n")); + err = wl_do_escan(cfg, wiphy, ndev, request); +#endif + if (err) { + wl_clr_drv_status(cfg, SCANNING, ndev); + goto out_err; + } + cfg->sched_scan_running = TRUE; + } + else { + WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); + } +out_err: + if (request) + kfree(request); + if (channel) + kfree(channel); + return err; +} +#endif /* WL_SCHED_SCAN */ + +static void wl_init_conf(struct wl_conf *conf) +{ + WL_DBG(("Enter \n")); + 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 wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + unsigned long flags; + struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); + + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + memset(profile, 0, sizeof(struct wl_profile)); + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); +} + +static void wl_init_event_handler(struct bcm_cfg80211 *cfg) +{ + memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler)); + + cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; + cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; + cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; + cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; + cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; + cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; + cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; + cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; + cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; + cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_START] = wl_notify_connect_status; +#ifdef PNO_SUPPORT + cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; +#endif /* PNO_SUPPORT */ +#ifdef GSCAN_SUPPORT + cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; + cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event; +#ifdef ANQPO_SUPPORT + cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event; +#endif /* ANQPO_SUPPORT */ +#endif /* GSCAN_SUPPORT */ +#ifdef RSSI_MONITOR_SUPPORT + cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event; +#endif /* RSSI_MONITOR_SUPPORT */ +#ifdef WLTDLS + cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler; +#endif /* WLTDLS */ + cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status; +#ifdef WLAIBSS + cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail; +#endif /* WLAIBSS */ + cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status; +#ifdef WL_NAN + cfg->evt_handler[WLC_E_NAN] = wl_cfgnan_notify_nan_status; + cfg->evt_handler[WLC_E_PROXD] = wl_cfgnan_notify_proxd_status; +#endif /* WL_NAN */ +#ifdef DHD_LOSSLESS_ROAMING + cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status; +#endif + +} + +#if defined(STATIC_WL_PRIV_STRUCT) +static void +wl_init_escan_result_buf(struct bcm_cfg80211 *cfg) +{ + cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub, DHD_PREALLOC_WIPHY_ESCAN0, 0); + bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE); +} + +static void +wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg) +{ + cfg->escan_info.escan_buf = NULL; + +} +#endif /* STATIC_WL_PRIV_STRUCT */ + +static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg) +{ + WL_DBG(("Enter \n")); + cfg->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); + if (unlikely(!cfg->scan_results)) { + WL_ERR(("Scan results alloc failed\n")); + goto init_priv_mem_out; + } + cfg->conf = (void *)kzalloc(sizeof(*cfg->conf), GFP_KERNEL); + if (unlikely(!cfg->conf)) { + WL_ERR(("wl_conf alloc failed\n")); + goto init_priv_mem_out; + } + cfg->scan_req_int = + (void *)kzalloc(sizeof(*cfg->scan_req_int), GFP_KERNEL); + if (unlikely(!cfg->scan_req_int)) { + WL_ERR(("Scan req alloc failed\n")); + goto init_priv_mem_out; + } + cfg->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); + if (unlikely(!cfg->ioctl_buf)) { + WL_ERR(("Ioctl buf alloc failed\n")); + goto init_priv_mem_out; + } + cfg->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); + if (unlikely(!cfg->escan_ioctl_buf)) { + WL_ERR(("Ioctl buf alloc failed\n")); + goto init_priv_mem_out; + } + cfg->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (unlikely(!cfg->extra_buf)) { + WL_ERR(("Extra buf alloc failed\n")); + goto init_priv_mem_out; + } + cfg->pmk_list = (void *)kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL); + if (unlikely(!cfg->pmk_list)) { + WL_ERR(("pmk list alloc failed\n")); + goto init_priv_mem_out; + } + cfg->sta_info = (void *)kzalloc(sizeof(*cfg->sta_info), GFP_KERNEL); + if (unlikely(!cfg->sta_info)) { + WL_ERR(("sta info alloc failed\n")); + goto init_priv_mem_out; + } + +#if defined(STATIC_WL_PRIV_STRUCT) + cfg->conn_info = (void *)kzalloc(sizeof(*cfg->conn_info), GFP_KERNEL); + if (unlikely(!cfg->conn_info)) { + WL_ERR(("cfg->conn_info alloc failed\n")); + goto init_priv_mem_out; + } + cfg->ie = (void *)kzalloc(sizeof(*cfg->ie), GFP_KERNEL); + if (unlikely(!cfg->ie)) { + WL_ERR(("cfg->ie alloc failed\n")); + goto init_priv_mem_out; + } + wl_init_escan_result_buf(cfg); +#endif /* STATIC_WL_PRIV_STRUCT */ + cfg->afx_hdl = (void *)kzalloc(sizeof(*cfg->afx_hdl), GFP_KERNEL); + if (unlikely(!cfg->afx_hdl)) { + WL_ERR(("afx hdl alloc failed\n")); + goto init_priv_mem_out; + } else { + init_completion(&cfg->act_frm_scan); + init_completion(&cfg->wait_next_af); + + INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler); + } + return 0; + +init_priv_mem_out: + wl_deinit_priv_mem(cfg); + + return -ENOMEM; +} + +static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg) +{ + kfree(cfg->scan_results); + cfg->scan_results = NULL; + kfree(cfg->conf); + cfg->conf = NULL; + kfree(cfg->scan_req_int); + cfg->scan_req_int = NULL; + kfree(cfg->ioctl_buf); + cfg->ioctl_buf = NULL; + kfree(cfg->escan_ioctl_buf); + cfg->escan_ioctl_buf = NULL; + kfree(cfg->extra_buf); + cfg->extra_buf = NULL; + kfree(cfg->pmk_list); + cfg->pmk_list = NULL; + kfree(cfg->sta_info); + cfg->sta_info = NULL; +#if defined(STATIC_WL_PRIV_STRUCT) + kfree(cfg->conn_info); + cfg->conn_info = NULL; + kfree(cfg->ie); + cfg->ie = NULL; + wl_deinit_escan_result_buf(cfg); +#endif /* STATIC_WL_PRIV_STRUCT */ + if (cfg->afx_hdl) { + cancel_work_sync(&cfg->afx_hdl->work); + kfree(cfg->afx_hdl); + cfg->afx_hdl = NULL; + } + + if (cfg->ap_info) { + kfree(cfg->ap_info->wpa_ie); + kfree(cfg->ap_info->rsn_ie); + kfree(cfg->ap_info->wps_ie); + kfree(cfg->ap_info); + cfg->ap_info = NULL; + } +#ifdef WLTDLS + if (cfg->tdls_mgmt_frame) { + kfree(cfg->tdls_mgmt_frame); + cfg->tdls_mgmt_frame = NULL; + } +#endif /* WLTDLS */ +} + +static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg) +{ + int ret = 0; + WL_DBG(("Enter \n")); + + /* Do not use DHD in cfg driver */ + cfg->event_tsk.thr_pid = -1; + + PROC_START(wl_event_handler, cfg, &cfg->event_tsk, 0, "wl_event_handler"); + if (cfg->event_tsk.thr_pid < 0) + ret = -ENOMEM; + return ret; +} + +static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg) +{ + if (cfg->event_tsk.thr_pid >= 0) + PROC_STOP(&cfg->event_tsk); +} + +static void wl_scan_timeout(unsigned long data) +{ + wl_event_msg_t msg; + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; + + if (!(cfg->scan_request)) { + WL_ERR(("timer expired but no scan request\n")); + return; + } + bzero(&msg, sizeof(wl_event_msg_t)); + WL_ERR(("timer expired\n")); + msg.event_type = hton32(WLC_E_ESCAN_RESULT); + msg.status = hton32(WLC_E_STATUS_TIMEOUT); + msg.reason = 0xFFFFFFFF; + wl_cfg80211_event(bcmcfg_to_prmry_ndev(cfg), &msg, NULL); +} + +#ifdef DHD_LOSSLESS_ROAMING +static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + + /* restore prec_map to ALLPRIO */ + dhdp->dequeue_prec_map = ALLPRIO; + if (timer_pending(&cfg->roam_timeout)) { + del_timer_sync(&cfg->roam_timeout); + } + +} + +static void wl_roam_timeout(unsigned long data) +{ + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + + WL_ERR(("roam timer expired\n")); + + /* restore prec_map to ALLPRIO */ + dhdp->dequeue_prec_map = ALLPRIO; +} + +#endif /* DHD_LOSSLESS_ROAMING */ + +static s32 +wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, + unsigned long state, + void *ndev) +{ + struct net_device *dev = ndev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + WL_DBG(("Enter \n")); + + if (!wdev || !cfg || dev == bcmcfg_to_prmry_ndev(cfg)) + return NOTIFY_DONE; + + switch (state) { + case NETDEV_DOWN: + { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) + int max_wait_timeout = 2; + int max_wait_count = 100; + int refcnt = 0; + unsigned long limit = jiffies + max_wait_timeout * HZ; + while (work_pending(&wdev->cleanup_work)) { + if (refcnt%5 == 0) { + WL_ERR(("[NETDEV_DOWN] wait for " + "complete of cleanup_work" + " (%d th)\n", refcnt)); + } + if (!time_before(jiffies, limit)) { + WL_ERR(("[NETDEV_DOWN] cleanup_work" + " of CFG80211 is not" + " completed in %d sec\n", + max_wait_timeout)); + break; + } + if (refcnt >= max_wait_count) { + WL_ERR(("[NETDEV_DOWN] cleanup_work" + " of CFG80211 is not" + " completed in %d loop\n", + max_wait_count)); + break; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(100); + set_current_state(TASK_RUNNING); + refcnt++; + } +#endif /* LINUX_VERSION < VERSION(3, 13, 0) */ + break; + } + + case NETDEV_UNREGISTER: + /* after calling list_del_rcu(&wdev->list) */ + wl_dealloc_netinfo(cfg, ndev); + break; + case NETDEV_GOING_DOWN: + /* At NETDEV_DOWN state, wdev_cleanup_work work will be called. + * In front of door, the function checks + * whether current scan is working or not. + * If the scanning is still working, wdev_cleanup_work call WARN_ON and + * make the scan done forcibly. + */ + if (wl_get_drv_status(cfg, SCANNING, dev)) + wl_notify_escan_complete(cfg, dev, true, true); + break; + } + return NOTIFY_DONE; +} +static struct notifier_block wl_cfg80211_netdev_notifier = { + .notifier_call = wl_cfg80211_netdev_notifier_call, +}; +/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be + * created in kernel notifier link list (with 'next' pointing to itself) + */ +static bool wl_cfg80211_netdev_notifier_registered = FALSE; + +static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg) +{ + wl_scan_params_t *params = NULL; + s32 params_size = 0; + s32 err = BCME_OK; + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + if (!in_atomic()) { + /* Our scan params only need space for 1 channel and 0 ssids */ + params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); + if (params == NULL) { + WL_ERR(("scan params allocation failed \n")); + err = -ENOMEM; + } else { + /* Do a scan abort to stop the driver's scan engine */ + err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); + if (err < 0) { + WL_ERR(("scan abort failed \n")); + } + kfree(params); + } + } +} + +#if defined(WL_ABORT_SCAN) +static void wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + if (cfg == NULL) { + WL_ERR(("Parsing parameter failed\n")); + return; + } + wl_cfg80211_scan_abort(cfg); +} +#endif /* WL_ABORT_SCAN */ + +static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, + struct net_device *ndev, + bool aborted, bool fw_abort) +{ + s32 err = BCME_OK; + unsigned long flags; + struct net_device *dev; + + WL_DBG(("Enter \n")); + if (!ndev) { + WL_ERR(("ndev is null\n")); + err = BCME_ERROR; + return err; + } + + if (cfg->escan_info.ndev != ndev) { + WL_ERR(("ndev is different %p %p\n", cfg->escan_info.ndev, ndev)); + err = BCME_ERROR; + return err; + } + + if (cfg->scan_request) { + dev = bcmcfg_to_prmry_ndev(cfg); +#if defined(WL_ENABLE_P2P_IF) + if (cfg->scan_request->dev != cfg->p2p_net) + dev = cfg->scan_request->dev; +#endif /* WL_ENABLE_P2P_IF */ + } + else { + WL_DBG(("cfg->scan_request is NULL may be internal scan." + "doing scan_abort for ndev %p primary %p", + ndev, bcmcfg_to_prmry_ndev(cfg))); + dev = ndev; + } + if (fw_abort && !in_atomic()) + wl_cfg80211_scan_abort(cfg); + if (timer_pending(&cfg->scan_timeout)) + del_timer_sync(&cfg->scan_timeout); +#if defined(ESCAN_RESULT_PATCH) + if (likely(cfg->scan_request)) { + cfg->bss_list = wl_escan_get_buf(cfg, aborted); + wl_inform_bss(cfg); + } +#endif /* ESCAN_RESULT_PATCH */ + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); +#ifdef WL_SCHED_SCAN + if (cfg->sched_scan_req && !cfg->scan_request) { + WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n")); + if (!aborted) + cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy); + cfg->sched_scan_running = FALSE; + cfg->sched_scan_req = NULL; + } +#endif /* WL_SCHED_SCAN */ + if (likely(cfg->scan_request)) { + cfg80211_scan_done(cfg->scan_request, aborted); + cfg->scan_request = NULL; + } + if (p2p_is_on(cfg)) + wl_clr_p2p_status(cfg, SCANNING); + wl_clr_drv_status(cfg, SCANNING, dev); + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + return err; +} + +static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 err = BCME_OK; + s32 status = ntoh32(e->status); + wl_bss_info_t *bi; + wl_escan_result_t *escan_result; + wl_bss_info_t *bss = NULL; + wl_scan_results_t *list; + wifi_p2p_ie_t * p2p_ie; + struct net_device *ndev = NULL; + u32 bi_length; + u32 i; + u8 *p2p_dev_addr = NULL; + + WL_DBG((" enter event type : %d, status : %d \n", + ntoh32(e->event_type), ntoh32(e->status))); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + mutex_lock(&cfg->usr_sync); + /* P2P SCAN is coming from primary interface */ + if (wl_get_p2p_status(cfg, SCANNING)) { + if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) + ndev = cfg->afx_hdl->dev; + else + ndev = cfg->escan_info.ndev; + + } + if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) { + WL_ERR(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n", + ndev, wl_get_drv_status(cfg, SCANNING, ndev), + ntoh32(e->event_type), ntoh32(e->status))); + goto exit; + } + escan_result = (wl_escan_result_t *)data; + + if (status == WLC_E_STATUS_PARTIAL) { + WL_INFO(("WLC_E_STATUS_PARTIAL \n")); + if (!escan_result) { + WL_ERR(("Invalid escan result (NULL pointer)\n")); + goto exit; + } + if (dtoh16(escan_result->bss_count) != 1) { + WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); + goto exit; + } + bi = escan_result->bss_info; + if (!bi) { + WL_ERR(("Invalid escan bss info (NULL pointer)\n")); + goto exit; + } + bi_length = dtoh32(bi->length); + if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { + WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); + goto exit; + } + if (wl_escan_check_sync_id(status, escan_result->sync_id, + cfg->escan_info.cur_sync_id) < 0) + goto exit; + + if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { + if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { + WL_DBG(("Ignoring IBSS result\n")); + goto exit; + } + } + + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); + if (p2p_dev_addr && !memcmp(p2p_dev_addr, + cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) { + s32 channel = wf_chspec_ctlchan( + wl_chspec_driver_to_host(bi->chanspec)); + + if ((channel > MAXCHANNEL) || (channel <= 0)) + channel = WL_INVALID; + else + WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found," + " channel : %d\n", + MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet), + channel)); + + wl_clr_p2p_status(cfg, SCANNING); + cfg->afx_hdl->peer_chan = channel; + complete(&cfg->act_frm_scan); + goto exit; + } + + } else { + int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; + list = wl_escan_get_buf(cfg, FALSE); + if (scan_req_match(cfg)) { + /* p2p scan && allow only probe response */ + if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) && + (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) + goto exit; + if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, + bi->ie_length)) == NULL) { + WL_ERR(("Couldn't find P2PIE in probe" + " response/beacon\n")); + goto exit; + } + } + for (i = 0; i < list->count; i++) { + bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) + : list->bss_info; + + if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && + (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec)) + == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) && + bi->SSID_len == bss->SSID_len && + !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { + + /* do not allow beacon data to update + *the data recd from a probe response + */ + if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) && + (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) + goto exit; + + WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d" + " flags 0x%x, new: RSSI %d flags 0x%x\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), i, + bss->RSSI, bss->flags, bi->RSSI, bi->flags)); + + if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == + (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) { + /* preserve max RSSI if the measurements are + * both on-channel or both off-channel + */ + WL_SCAN(("%s("MACDBG"), same onchan" + ", RSSI: prev %d new %d\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + bss->RSSI, bi->RSSI)); + bi->RSSI = MAX(bss->RSSI, bi->RSSI); + } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && + (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { + /* preserve the on-channel rssi measurement + * if the new measurement is off channel + */ + WL_SCAN(("%s("MACDBG"), prev onchan" + ", RSSI: prev %d new %d\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + bss->RSSI, bi->RSSI)); + bi->RSSI = bss->RSSI; + bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; + } + if (dtoh32(bss->length) != bi_length) { + u32 prev_len = dtoh32(bss->length); + + WL_SCAN(("bss info replacement" + " is occured(bcast:%d->probresp%d)\n", + bss->ie_length, bi->ie_length)); + WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + prev_len, bi_length)); + + if (list->buflen - prev_len + bi_length + > ESCAN_BUF_SIZE) { + WL_ERR(("Buffer is too small: keep the" + " previous result of this AP\n")); + /* Only update RSSI */ + bss->RSSI = bi->RSSI; + bss->flags |= (bi->flags + & WL_BSS_FLAGS_RSSI_ONCHANNEL); + goto exit; + } + + if (i < list->count - 1) { + /* memory copy required by this case only */ + memmove((u8 *)bss + bi_length, + (u8 *)bss + prev_len, + list->buflen - cur_len - prev_len); + } + list->buflen -= prev_len; + list->buflen += bi_length; + } + list->version = dtoh32(bi->version); + memcpy((u8 *)bss, (u8 *)bi, bi_length); + goto exit; + } + cur_len += dtoh32(bss->length); + } + if (bi_length > ESCAN_BUF_SIZE - list->buflen) { + WL_ERR(("Buffer is too small: ignoring\n")); + goto exit; + } + + memcpy(&(((char *)list)[list->buflen]), bi, bi_length); + list->version = dtoh32(bi->version); + list->buflen += bi_length; + list->count++; + + /* + * !Broadcast && number of ssid = 1 && number of channels =1 + * means specific scan to association + */ + if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) { + WL_ERR(("P2P assoc scan fast aborted.\n")); + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false, true); + goto exit; + } + } + + } + else if (status == WLC_E_STATUS_SUCCESS) { + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id, + escan_result->sync_id); + + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + WL_INFO(("ACTION FRAME SCAN DONE\n")); + wl_clr_p2p_status(cfg, SCANNING); + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + if (cfg->afx_hdl->peer_chan == WL_INVALID) + complete(&cfg->act_frm_scan); + } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { + WL_INFO(("ESCAN COMPLETED\n")); + cfg->bss_list = wl_escan_get_buf(cfg, FALSE); + if (!scan_req_match(cfg)) { + WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n", + cfg->bss_list->count)); + } + wl_inform_bss(cfg); + wl_notify_escan_complete(cfg, ndev, false, false); + } + wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); + } +#ifdef GSCAN_SUPPORT + else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN)) { + if (status == WLC_E_STATUS_NEWSCAN) { + WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); + WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, + escan_result->bss_count)); + } +#else + else if (status == WLC_E_STATUS_ABORT) { +#endif /* GSCAN_SUPPORT */ + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_print_sync_id(status, escan_result->sync_id, + cfg->escan_info.cur_sync_id); + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + WL_INFO(("ACTION FRAME SCAN DONE\n")); + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + wl_clr_p2p_status(cfg, SCANNING); + if (cfg->afx_hdl->peer_chan == WL_INVALID) + complete(&cfg->act_frm_scan); + } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { + WL_INFO(("ESCAN ABORTED\n")); + cfg->bss_list = wl_escan_get_buf(cfg, TRUE); + if (!scan_req_match(cfg)) { + WL_TRACE_HW4(("SCAN ABORTED: scanned AP count=%d\n", + cfg->bss_list->count)); + } + wl_inform_bss(cfg); + wl_notify_escan_complete(cfg, ndev, true, false); + } + wl_escan_increment_sync_id(cfg, SCAN_BUF_CNT); + } else if (status == WLC_E_STATUS_NEWSCAN) { + WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); + WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, + escan_result->bss_count)); + } else if (status == WLC_E_STATUS_TIMEOUT) { + WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request)); + WL_ERR(("reason[0x%x]\n", e->reason)); + if (e->reason == 0xFFFFFFFF) { + wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); + } + } else { + WL_ERR(("unexpected Escan Event %d : abort\n", status)); + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_print_sync_id(status, escan_result->sync_id, + cfg->escan_info.cur_sync_id); + if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + WL_INFO(("ACTION FRAME SCAN DONE\n")); + wl_clr_p2p_status(cfg, SCANNING); + wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); + if (cfg->afx_hdl->peer_chan == WL_INVALID) + complete(&cfg->act_frm_scan); + } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { + cfg->bss_list = wl_escan_get_buf(cfg, TRUE); + if (!scan_req_match(cfg)) { + WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): " + "scanned AP count=%d\n", + cfg->bss_list->count)); + } + wl_inform_bss(cfg); + wl_notify_escan_complete(cfg, ndev, true, false); + } + wl_escan_increment_sync_id(cfg, 2); + } +exit: + mutex_unlock(&cfg->usr_sync); + return err; +} + +static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable) +{ + u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED); + struct net_info *iter, *next; + int err; + + if (!cfg->roamoff_on_concurrent) + return; + if (enable && connected_cnt > 1) { + for_each_ndev(cfg, iter, next) { + /* Save the current roam setting */ + if ((err = wldev_iovar_getint(iter->ndev, "roam_off", + (s32 *)&iter->roam_off)) != BCME_OK) { + WL_ERR(("%s:Failed to get current roam setting err %d\n", + iter->ndev->name, err)); + continue; + } + if ((err = wldev_iovar_setint(iter->ndev, "roam_off", 1)) != BCME_OK) { + WL_ERR((" %s:failed to set roam_off : %d\n", + iter->ndev->name, err)); + } + } + } + else if (!enable) { + for_each_ndev(cfg, iter, next) { + if (iter->roam_off != WL_INVALID) { + if ((err = wldev_iovar_setint(iter->ndev, "roam_off", + iter->roam_off)) == BCME_OK) + iter->roam_off = WL_INVALID; + else { + WL_ERR((" %s:failed to set roam_off : %d\n", + iter->ndev->name, err)); + } + } + } + } + return; +} + +static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg) +{ + struct net_info *iter, *next; + u32 ctl_chan = 0; + u32 chanspec = 0; + u32 pre_ctl_chan = 0; + u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED); + cfg->vsdb_mode = false; + + if (connected_cnt <= 1) { + return; + } + for_each_ndev(cfg, iter, next) { + chanspec = 0; + ctl_chan = 0; + if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) { + if (wldev_iovar_getint(iter->ndev, "chanspec", + (s32 *)&chanspec) == BCME_OK) { + chanspec = wl_chspec_driver_to_host(chanspec); + ctl_chan = wf_chspec_ctlchan(chanspec); + wl_update_prof(cfg, iter->ndev, NULL, + &ctl_chan, WL_PROF_CHAN); + } + if (!cfg->vsdb_mode) { + if (!pre_ctl_chan && ctl_chan) + pre_ctl_chan = ctl_chan; + else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) { + cfg->vsdb_mode = true; + } + } + } + } + WL_ERR(("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel")); + return; +} + +static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, + enum wl_status state, bool set) +{ + s32 pm = PM_FAST; + s32 err = BCME_OK; + u32 mode; + u32 chan = 0; + struct net_info *iter, *next; + struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); + WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n", + state, set, _net_info->pm_restore, _net_info->ndev->name)); + + if (state != WL_STATUS_CONNECTED) + return 0; + mode = wl_get_mode_by_netdev(cfg, _net_info->ndev); + if (set) { + wl_cfg80211_concurrent_roam(cfg, 1); + + if (mode == WL_MODE_AP) { + + if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false)) + WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); + } + wl_cfg80211_determine_vsdb_mode(cfg); + if (cfg->vsdb_mode || _net_info->pm_block) { + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_MAINTAIN); + /* save PM_FAST in _net_info to restore this + * if _net_info->pm_block is false + */ + if (!_net_info->pm_block && (mode == WL_MODE_BSS)) { + _net_info->pm = PM_FAST; + _net_info->pm_restore = true; + } + pm = PM_OFF; + for_each_ndev(cfg, iter, next) { + if (iter->pm_restore) + continue; + /* Save the current power mode */ + iter->pm = 0; + err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, + sizeof(iter->pm), false); + WL_DBG(("%s:power save %s\n", iter->ndev->name, + iter->pm ? "enabled" : "disabled")); + if (!err && iter->pm) { + iter->pm_restore = true; + } + + } + for_each_ndev(cfg, iter, next) { + if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, + sizeof(pm), true)) != 0) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); + wl_cfg80211_update_power_mode(iter->ndev); + } + } + } else { + /* add PM Enable timer to go to power save mode + * if supplicant control pm mode, it will be cleared or + * updated by wl_cfg80211_set_power_mgmt() if not - for static IP & HW4 P2P, + * PM will be configured when timer expired + */ + + /* + * before calling pm_enable_timer, we need to set PM -1 for all ndev + */ + pm = PM_OFF; + + for_each_ndev(cfg, iter, next) { + if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, + sizeof(pm), true)) != 0) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); + } + } + + if (cfg->pm_enable_work_on) { + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + } + + cfg->pm_enable_work_on = true; + wl_add_remove_pm_enable_work(cfg, TRUE, WL_HANDLER_NOTUSE); + } +#if defined(WLTDLS) +#if defined(DISABLE_TDLS_IN_P2P) + if (cfg->vsdb_mode || p2p_is_on(cfg)) +#else + if (cfg->vsdb_mode) +#endif /* defined(DISABLE_TDLS_IN_P2P) */ + { + + err = wldev_iovar_setint(primary_dev, "tdls_enable", 0); + } +#endif /* defined(WLTDLS) */ + } + else { /* clear */ + chan = 0; + /* clear chan information when the net device is disconnected */ + wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); + wl_cfg80211_determine_vsdb_mode(cfg); + for_each_ndev(cfg, iter, next) { + if (iter->pm_restore && iter->pm) { + WL_DBG(("%s:restoring power save %s\n", + iter->ndev->name, (iter->pm ? "enabled" : "disabled"))); + err = wldev_ioctl(iter->ndev, + WLC_SET_PM, &iter->pm, sizeof(iter->pm), true); + if (unlikely(err)) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error(%d)\n", iter->ndev->name, err)); + break; + } + iter->pm_restore = 0; + wl_cfg80211_update_power_mode(iter->ndev); + } + } + wl_cfg80211_concurrent_roam(cfg, 0); +#if defined(WLTDLS) + if (!cfg->vsdb_mode) { + err = wldev_iovar_setint(primary_dev, "tdls_enable", 1); + } +#endif /* defined(WLTDLS) */ + } + return err; +} +static s32 wl_init_scan(struct bcm_cfg80211 *cfg) +{ + int err = 0; + + cfg->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_init_sync_id(cfg); + + /* Init scan_timeout timer */ + init_timer(&cfg->scan_timeout); + cfg->scan_timeout.data = (unsigned long) cfg; + cfg->scan_timeout.function = wl_scan_timeout; + + return err; +} + +#ifdef DHD_LOSSLESS_ROAMING +static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg) +{ + int err = 0; + + /* Init roam timer */ + init_timer(&cfg->roam_timeout); + cfg->roam_timeout.data = (unsigned long) cfg; + cfg->roam_timeout.function = wl_roam_timeout; + + return err; +} +#endif /* DHD_LOSSLESS_ROAMING */ + +static s32 wl_init_priv(struct bcm_cfg80211 *cfg) +{ + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + s32 err = 0; + + cfg->scan_request = NULL; + cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); + cfg->roam_on = false; + cfg->active_scan = true; + cfg->rf_blocked = false; + cfg->vsdb_mode = false; + cfg->wlfc_on = false; + cfg->roamoff_on_concurrent = true; + cfg->disable_roam_event = false; + /* register interested state */ + set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state); + spin_lock_init(&cfg->cfgdrv_lock); + mutex_init(&cfg->ioctl_buf_sync); + init_waitqueue_head(&cfg->netif_change_event); + init_completion(&cfg->send_af_done); + init_completion(&cfg->iface_disable); + wl_init_eq(cfg); + err = wl_init_priv_mem(cfg); + if (err) + return err; + if (wl_create_event_handler(cfg)) + return -ENOMEM; + wl_init_event_handler(cfg); + mutex_init(&cfg->usr_sync); + mutex_init(&cfg->event_sync); + err = wl_init_scan(cfg); + if (err) + return err; +#ifdef DHD_LOSSLESS_ROAMING + err = wl_init_roam_timeout(cfg); + if (err) { + return err; + } +#endif /* DHD_LOSSLESS_ROAMING */ + + wl_init_conf(cfg->conf); + wl_init_prof(cfg, ndev); + wl_link_down(cfg); + DNGL_FUNC(dhd_cfg80211_init, (cfg)); + + return err; +} + +static void wl_deinit_priv(struct bcm_cfg80211 *cfg) +{ + DNGL_FUNC(dhd_cfg80211_deinit, (cfg)); + wl_destroy_event_handler(cfg); + wl_flush_eq(cfg); + wl_link_down(cfg); + del_timer_sync(&cfg->scan_timeout); +#ifdef DHD_LOSSLESS_ROAMING + del_timer_sync(&cfg->roam_timeout); +#endif + wl_deinit_priv_mem(cfg); + if (wl_cfg80211_netdev_notifier_registered) { + wl_cfg80211_netdev_notifier_registered = FALSE; + unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); + } +} + +#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) +static s32 wl_cfg80211_attach_p2p(void) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + WL_TRACE(("Enter \n")); + + if (wl_cfgp2p_register_ndev(cfg) < 0) { + WL_ERR(("P2P attach failed. \n")); + return -ENODEV; + } + + return 0; +} + +static s32 wl_cfg80211_detach_p2p(void) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct wireless_dev *wdev; + + WL_DBG(("Enter \n")); + if (!cfg) { + WL_ERR(("Invalid Ptr\n")); + return -EINVAL; + } else + wdev = cfg->p2p_wdev; + +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT + if (!wdev) { + WL_ERR(("Invalid Ptr\n")); + return -EINVAL; + } +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + + wl_cfgp2p_unregister_ndev(cfg); + + cfg->p2p_wdev = NULL; + cfg->p2p_net = NULL; +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT + WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev)); + kfree(wdev); +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + + return 0; +} +#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ + +s32 wl_cfg80211_attach_post(struct net_device *ndev) +{ + struct bcm_cfg80211 * cfg = NULL; + s32 err = 0; + s32 ret = 0; + WL_TRACE(("In\n")); + if (unlikely(!ndev)) { + WL_ERR(("ndev is invaild\n")); + return -ENODEV; + } + cfg = g_bcm_cfg; + if (unlikely(!cfg)) { + WL_ERR(("cfg is invaild\n")); + return -EINVAL; + } + if (!wl_get_drv_status(cfg, READY, ndev)) { + if (cfg->wdev) { + ret = wl_cfgp2p_supported(cfg, ndev); + if (ret > 0) { +#if !defined(WL_ENABLE_P2P_IF) + cfg->wdev->wiphy->interface_modes |= + (BIT(NL80211_IFTYPE_P2P_CLIENT)| + BIT(NL80211_IFTYPE_P2P_GO)); +#endif /* !WL_ENABLE_P2P_IF */ + if ((err = wl_cfgp2p_init_priv(cfg)) != 0) + goto fail; + +#if defined(WL_ENABLE_P2P_IF) + if (cfg->p2p_net) { + /* Update MAC addr for p2p0 interface here. */ + memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); + cfg->p2p_net->dev_addr[0] |= 0x02; + WL_ERR(("%s: p2p_dev_addr="MACDBG "\n", + cfg->p2p_net->name, + MAC2STRDBG(cfg->p2p_net->dev_addr))); + } else { + WL_ERR(("p2p_net not yet populated." + " Couldn't update the MAC Address for p2p0 \n")); + return -ENODEV; + } +#endif /* WL_ENABLE_P2P_IF */ + cfg->p2p_supported = true; + } else if (ret == 0) { + if ((err = wl_cfgp2p_init_priv(cfg)) != 0) + goto fail; + } else { + /* SDIO bus timeout */ + err = -ENODEV; + goto fail; + } + } + } + wl_set_drv_status(cfg, READY, ndev); +fail: + return err; +} + +s32 wl_cfg80211_attach(struct net_device *ndev, void *context) +{ + struct wireless_dev *wdev; + struct bcm_cfg80211 *cfg; + s32 err = 0; + struct device *dev; + + WL_TRACE(("In\n")); + if (!ndev) { + WL_ERR(("ndev is invaild\n")); + return -ENODEV; + } + WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev())); + dev = wl_cfg80211_get_parent_dev(); + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return -ENOMEM; + } + err = wl_setup_wiphy(wdev, dev, context); + if (unlikely(err)) { + kfree(wdev); + return -ENOMEM; + } + wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); + cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy); + cfg->wdev = wdev; + cfg->pub = context; + INIT_LIST_HEAD(&cfg->net_list); + ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); + wdev->netdev = ndev; + cfg->state_notifier = wl_notifier_change_state; + err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE); + if (err) { + WL_ERR(("Failed to alloc net_info (%d)\n", err)); + goto cfg80211_attach_out; + } + err = wl_init_priv(cfg); + if (err) { + WL_ERR(("Failed to init iwm_priv (%d)\n", err)); + goto cfg80211_attach_out; + } + + err = wl_setup_rfkill(cfg, TRUE); + if (err) { + WL_ERR(("Failed to setup rfkill %d\n", err)); + goto cfg80211_attach_out; + } +#ifdef DEBUGFS_CFG80211 + err = wl_setup_debugfs(cfg); + if (err) { + WL_ERR(("Failed to setup debugfs %d\n", err)); + goto cfg80211_attach_out; + } +#endif + if (!wl_cfg80211_netdev_notifier_registered) { + wl_cfg80211_netdev_notifier_registered = TRUE; + err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); + if (err) { + wl_cfg80211_netdev_notifier_registered = FALSE; + WL_ERR(("Failed to register notifierl %d\n", err)); + goto cfg80211_attach_out; + } + } +#if defined(COEX_DHCP) + cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev); + if (!cfg->btcoex_info) + goto cfg80211_attach_out; +#endif + + g_bcm_cfg = cfg; + +#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) + err = wl_cfg80211_attach_p2p(); + if (err) + goto cfg80211_attach_out; +#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ + + return err; + +cfg80211_attach_out: + wl_setup_rfkill(cfg, FALSE); + wl_free_wdev(cfg); + return err; +} + +void wl_cfg80211_detach(void *para) +{ + struct bcm_cfg80211 *cfg; + + (void)para; + cfg = g_bcm_cfg; + + WL_TRACE(("In\n")); + + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + +#if defined(COEX_DHCP) + wl_cfg80211_btcoex_deinit(); + cfg->btcoex_info = NULL; +#endif + + wl_setup_rfkill(cfg, FALSE); +#ifdef DEBUGFS_CFG80211 + wl_free_debugfs(cfg); +#endif + if (cfg->p2p_supported) { + if (timer_pending(&cfg->p2p->listen_timer)) + del_timer_sync(&cfg->p2p->listen_timer); + wl_cfgp2p_deinit_priv(cfg); + } + + if (timer_pending(&cfg->scan_timeout)) + del_timer_sync(&cfg->scan_timeout); +#ifdef DHD_LOSSLESS_ROAMING + if (timer_pending(&cfg->roam_timeout)) { + del_timer_sync(&cfg->roam_timeout); + } +#endif /* DHD_LOSSLESS_ROAMING */ + +#if defined(WL_CFG80211_P2P_DEV_IF) + wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) + wl_cfg80211_detach_p2p(); +#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ + + wl_cfg80211_ibss_vsie_free(cfg); + wl_deinit_priv(cfg); + g_bcm_cfg = NULL; + wl_cfg80211_clear_parent_dev(); + wl_free_wdev(cfg); + /* PLEASE do NOT call any function after wl_free_wdev, the driver's private + * structure "cfg", which is the private part of wiphy, has been freed in + * wl_free_wdev !!!!!!!!!!! + */ +} + +static void wl_wakeup_event(struct bcm_cfg80211 *cfg) +{ + if (cfg->event_tsk.thr_pid >= 0) { + DHD_OS_WAKE_LOCK(cfg->pub); + up(&cfg->event_tsk.sema); + } +} + +static s32 wl_event_handler(void *data) +{ + struct bcm_cfg80211 *cfg = NULL; + struct wl_event_q *e; + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + bcm_struct_cfgdev *cfgdev = NULL; + + cfg = (struct bcm_cfg80211 *)tsk->parent; + + WL_ERR(("tsk Enter, tsk = 0x%p\n", tsk)); + + while (down_interruptible (&tsk->sema) == 0) { + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + DHD_OS_WAKE_UNLOCK(cfg->pub); + break; + } + while ((e = wl_deq_event(cfg))) { + WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx)); + /* All P2P device address related events comes on primary interface since + * there is no corresponding bsscfg for P2P interface. Map it to p2p0 + * interface. + */ +#if defined(WL_CFG80211_P2P_DEV_IF) + if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_wdev)) { + cfgdev = bcmcfg_to_p2p_wdev(cfg); + } else { + struct net_device *ndev = NULL; + + ndev = dhd_idx2net((struct dhd_pub *)(cfg->pub), e->emsg.ifidx); + if (ndev) + cfgdev = ndev_to_wdev(ndev); + } +#elif defined(WL_ENABLE_P2P_IF) + if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_net)) { + cfgdev = cfg->p2p_net; + } else { + cfgdev = dhd_idx2net((struct dhd_pub *)(cfg->pub), + e->emsg.ifidx); + } +#endif /* WL_CFG80211_P2P_DEV_IF */ + + if (!cfgdev) { +#if defined(WL_CFG80211_P2P_DEV_IF) + cfgdev = bcmcfg_to_prmry_wdev(cfg); +#elif defined(WL_ENABLE_P2P_IF) + cfgdev = bcmcfg_to_prmry_ndev(cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ + } + if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) { + dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub); + if (dhd->busstate == DHD_BUS_DOWN) { + WL_ERR((": BUS is DOWN.\n")); + } else + cfg->evt_handler[e->etype](cfg, cfgdev, &e->emsg, e->edata); + } else { + WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); + } + wl_put_event(e); + } + DHD_OS_WAKE_UNLOCK(cfg->pub); + } + WL_ERR(("was terminated\n")); + complete_and_exit(&tsk->completed, 0); + return 0; +} + +void +wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) +{ + u32 event_type = ntoh32(e->event_type); + struct bcm_cfg80211 *cfg = g_bcm_cfg; + +#if (WL_DBG_LEVEL > 0) + s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? + wl_dbg_estr[event_type] : (s8 *) "Unknown"; + WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); +#endif /* (WL_DBG_LEVEL > 0) */ + + if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) { + WL_ERR(("during IF change, ignore event %d\n", event_type)); + return; + } + + if (ndev != bcmcfg_to_prmry_ndev(cfg) && cfg->p2p_supported) { + if (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) && +#if defined(WL_ENABLE_P2P_IF) + (ndev != (cfg->p2p_net ? cfg->p2p_net : + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE))) && +#else + (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE)) && +#endif /* WL_ENABLE_P2P_IF */ + TRUE) { + WL_ERR(("ignore event %d, not interested\n", event_type)); + return; + } + } + + if (event_type == WLC_E_PFN_NET_FOUND) { + WL_DBG((" PNOEVENT: PNO_NET_FOUND\n")); + } + else if (event_type == WLC_E_PFN_NET_LOST) { + WL_DBG((" PNOEVENT: PNO_NET_LOST\n")); + } + + if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) + wl_wakeup_event(cfg); +} + +static void wl_init_eq(struct bcm_cfg80211 *cfg) +{ + wl_init_eq_lock(cfg); + INIT_LIST_HEAD(&cfg->eq_list); +} + +static void wl_flush_eq(struct bcm_cfg80211 *cfg) +{ + struct wl_event_q *e; + unsigned long flags; + + flags = wl_lock_eq(cfg); + while (!list_empty(&cfg->eq_list)) { + e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list); + list_del(&e->eq_list); + kfree(e); + } + wl_unlock_eq(cfg, flags); +} + +/* +* retrieve first queued event from head +*/ + +static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg) +{ + struct wl_event_q *e = NULL; + unsigned long flags; + + flags = wl_lock_eq(cfg); + if (likely(!list_empty(&cfg->eq_list))) { + e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list); + list_del(&e->eq_list); + } + wl_unlock_eq(cfg, flags); + + return e; +} + +/* + * push event to tail of the queue + */ + +static s32 +wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event, + const wl_event_msg_t *msg, void *data) +{ + struct wl_event_q *e; + s32 err = 0; + uint32 evtq_size; + uint32 data_len; + unsigned long flags; + gfp_t aflags; + + data_len = 0; + if (data) + data_len = ntoh32(msg->datalen); + evtq_size = sizeof(struct wl_event_q) + data_len; + aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + e = kzalloc(evtq_size, aflags); + if (unlikely(!e)) { + WL_ERR(("event alloc failed\n")); + return -ENOMEM; + } + e->etype = event; + memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); + if (data) + memcpy(e->edata, data, data_len); + flags = wl_lock_eq(cfg); + list_add_tail(&e->eq_list, &cfg->eq_list); + wl_unlock_eq(cfg, flags); + + return err; +} + +static void wl_put_event(struct wl_event_q *e) +{ + kfree(e); +} + +static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype) +{ + s32 infra = 0; + s32 err = 0; + s32 mode = 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: + mode = WL_MODE_IBSS; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + mode = WL_MODE_BSS; + infra = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + mode = WL_MODE_AP; + infra = 1; + break; + default: + err = -EINVAL; + WL_ERR(("invalid type (%d)\n", iftype)); + return err; + } + infra = htod32(infra); + err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true); + if (unlikely(err)) { + WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); + return err; + } + + wl_set_mode_by_netdev(cfg, ndev, mode); + + return 0; +} + +void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set) +{ + if (!ev || (event > WLC_E_LAST)) + return; + + if (ev->num < MAX_EVENT_BUF_NUM) { + ev->event[ev->num].type = event; + ev->event[ev->num].set = set; + ev->num++; + } else { + WL_ERR(("evenbuffer doesn't support > %u events. Update" + " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM)); + ASSERT(0); + } +} + +s32 wl_cfg80211_apply_eventbuffer( + struct net_device *ndev, + struct bcm_cfg80211 *cfg, + wl_eventmsg_buf_t *ev) +{ + char eventmask[WL_EVENTING_MASK_LEN]; + int i, ret = 0; + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + if (!ev || (!ev->num)) + return -EINVAL; + + mutex_lock(&cfg->event_sync); + + /* Read event_msgs mask */ + ret = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL); + if (unlikely(ret)) { + WL_ERR(("Get event_msgs error (%d)\n", ret)); + goto exit; + } + memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); + + /* apply the set bits */ + for (i = 0; i < ev->num; i++) { + if (ev->event[i].set) + setbit(eventmask, ev->event[i].type); + else + clrbit(eventmask, ev->event[i].type); + } + + /* Write updated Event mask */ + ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf, + sizeof(iovbuf), NULL); + if (unlikely(ret)) { + WL_ERR(("Set event_msgs error (%d)\n", ret)); + } + +exit: + mutex_unlock(&cfg->event_sync); + return ret; +} + +s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) +{ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + s8 eventmask[WL_EVENTING_MASK_LEN]; + s32 err = 0; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (!ndev || !cfg) + return -ENODEV; + + mutex_lock(&cfg->event_sync); + + /* Setup event_msgs */ + err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL); + if (unlikely(err)) { + WL_ERR(("Get event_msgs error (%d)\n", err)); + goto eventmsg_out; + } + memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); + if (add) { + setbit(eventmask, event); + } else { + clrbit(eventmask, event); + } + err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, + sizeof(iovbuf), NULL); + if (unlikely(err)) { + WL_ERR(("Set event_msgs error (%d)\n", err)); + goto eventmsg_out; + } + +eventmsg_out: + mutex_unlock(&cfg->event_sync); + return err; +} + +static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) +{ + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + struct ieee80211_channel *band_chan_arr = NULL; + wl_uint32_list_t *list; + u32 i, j, index, n_2g, n_5g, band, channel, array_size; + u32 *n_cnt = NULL; + chanspec_t c = 0; + s32 err = BCME_OK; + bool update; + bool ht40_allowed; + u8 *pbuf = NULL; + bool dfs_radar_disabled = FALSE; + +#define LOCAL_BUF_LEN 1024 + pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); + + if (pbuf == NULL) { + WL_ERR(("failed to allocate local buf\n")); + return -ENOMEM; + } + + err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, + 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync); + if (err != 0) { + WL_ERR(("get chanspecs failed with %d\n", err)); + kfree(pbuf); + return err; + } +#undef LOCAL_BUF_LEN + + list = (wl_uint32_list_t *)(void *)pbuf; + band = array_size = n_2g = n_5g = 0; + for (i = 0; i < dtoh32(list->count); i++) { + index = 0; + update = false; + ht40_allowed = false; + c = (chanspec_t)dtoh32(list->element[i]); + c = wl_chspec_driver_to_host(c); + channel = CHSPEC_CHANNEL(c); + if (CHSPEC_IS40(c)) { + if (CHSPEC_SB_UPPER(c)) + channel += CH_10MHZ_APART; + else + channel -= CH_10MHZ_APART; + } else if (CHSPEC_IS80(c)) { + WL_DBG(("HT80 center channel : %d\n", channel)); + continue; + } + if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) && + (channel <= CH_MAX_2G_CHANNEL)) { + band_chan_arr = __wl_2ghz_channels; + array_size = ARRAYSIZE(__wl_2ghz_channels); + n_cnt = &n_2g; + band = IEEE80211_BAND_2GHZ; + ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; + } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) { + band_chan_arr = __wl_5ghz_a_channels; + array_size = ARRAYSIZE(__wl_5ghz_a_channels); + n_cnt = &n_5g; + band = IEEE80211_BAND_5GHZ; + ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; + } else { + WL_ERR(("Invalid channel Sepc. 0x%x.\n", c)); + continue; + } + if (!ht40_allowed && CHSPEC_IS40(c)) + continue; + for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { + if (band_chan_arr[j].hw_value == channel) { + update = true; + break; + } + } + if (update) + index = j; + else + index = *n_cnt; + if (index < array_size) { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) + band_chan_arr[index].center_freq = + ieee80211_channel_to_frequency(channel); +#else + band_chan_arr[index].center_freq = + ieee80211_channel_to_frequency(channel, band); +#endif + band_chan_arr[index].hw_value = channel; + band_chan_arr[index].beacon_found = false; + + if (CHSPEC_IS40(c) && ht40_allowed) { + /* assuming the order is HT20, HT40 Upper, + * HT40 lower from chanspecs + */ + u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; + if (CHSPEC_SB_UPPER(c)) { + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags &= + ~IEEE80211_CHAN_NO_HT40; + band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; + } else { + /* It should be one of + * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS + */ + band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags |= + IEEE80211_CHAN_NO_HT40MINUS; + } + } else { + band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; + if (!dfs_radar_disabled) { + if (band == IEEE80211_BAND_2GHZ) + channel |= WL_CHANSPEC_BAND_2G; + else + channel |= WL_CHANSPEC_BAND_5G; + channel |= WL_CHANSPEC_BW_20; + channel = wl_chspec_host_to_driver(channel); + err = wldev_iovar_getint(dev, "per_chan_info", &channel); + if (!err) { + if (channel & WL_CHAN_RADAR) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + band_chan_arr[index].flags |= + (IEEE80211_CHAN_RADAR + | IEEE80211_CHAN_NO_IBSS); +#else + band_chan_arr[index].flags |= + IEEE80211_CHAN_RADAR; +#endif + } + + if (channel & WL_CHAN_PASSIVE) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + band_chan_arr[index].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; +#else + band_chan_arr[index].flags |= + IEEE80211_CHAN_NO_IR; +#endif + } else if (err == BCME_UNSUPPORTED) { + dfs_radar_disabled = TRUE; + WL_ERR(("does not support per_chan_info\n")); + } + } + } + if (!update) + (*n_cnt)++; + } + + } + __wl_band_2ghz.n_channels = n_2g; + __wl_band_5ghz_a.n_channels = n_5g; + kfree(pbuf); + return err; +} + +s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) +{ + struct wiphy *wiphy; + struct net_device *dev; + u32 bandlist[3]; + u32 nband = 0; + u32 i = 0; + s32 err = 0; + s32 index = 0; + s32 nmode = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) + u32 j = 0; + s32 vhtmode = 0; + s32 txstreams = 0; + s32 rxstreams = 0; + s32 ldpc_cap = 0; + s32 stbc_rx = 0; + s32 stbc_tx = 0; + s32 txbf_bfe_cap = 0; + s32 txbf_bfr_cap = 0; +#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ + bool rollback_lock = false; + s32 bw_cap = 0; + s32 cur_band = -1; + struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, }; + + if (cfg == NULL) { + cfg = g_bcm_cfg; + mutex_lock(&cfg->usr_sync); + rollback_lock = true; + } + dev = bcmcfg_to_prmry_ndev(cfg); + + memset(bandlist, 0, sizeof(bandlist)); + err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist, + sizeof(bandlist), false); + if (unlikely(err)) { + WL_ERR(("error read bandlist (%d)\n", err)); + goto end_bands; + } + err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band, + sizeof(s32), false); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + goto end_bands; + } + + err = wldev_iovar_getint(dev, "nmode", &nmode); + if (unlikely(err)) { + WL_ERR(("error reading nmode (%d)\n", err)); + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) + err = wldev_iovar_getint(dev, "vhtmode", &vhtmode); + if (unlikely(err)) { + WL_ERR(("error reading vhtmode (%d)\n", err)); + } + + if (vhtmode) { + err = wldev_iovar_getint(dev, "txstreams", &txstreams); + if (unlikely(err)) { + WL_ERR(("error reading txstreams (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "rxstreams", &rxstreams); + if (unlikely(err)) { + WL_ERR(("error reading rxstreams (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap); + if (unlikely(err)) { + WL_ERR(("error reading ldpc_cap (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx); + if (unlikely(err)) { + WL_ERR(("error reading stbc_rx (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx); + if (unlikely(err)) { + WL_ERR(("error reading stbc_tx (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap); + if (unlikely(err)) { + WL_ERR(("error reading txbf_bfe_cap (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap); + if (unlikely(err)) { + WL_ERR(("error reading txbf_bfr_cap (%d)\n", err)); + } + } +#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ + + /* For nmode and vhtmode check bw cap */ + if (nmode || +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) + vhtmode || +#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ + 0) { + err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); + if (unlikely(err)) { + WL_ERR(("error get mimo_bw_cap (%d)\n", err)); + } + } + + err = wl_construct_reginfo(cfg, bw_cap); + if (err) { + WL_ERR(("wl_construct_reginfo() fails err=%d\n", err)); + if (err != BCME_UNSUPPORTED) + goto end_bands; + err = 0; + } + wiphy = bcmcfg_to_wiphy(cfg); + nband = bandlist[0]; + + for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { + index = -1; + if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) { + bands[IEEE80211_BAND_5GHZ] = + &__wl_band_5ghz_a; + index = IEEE80211_BAND_5GHZ; + if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G)) + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) + /* VHT capabilities. */ + if (vhtmode) { + /* Supported */ + bands[index]->vht_cap.vht_supported = TRUE; + + for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) { + /* TX stream rates. */ + if (j <= txstreams) { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, + bands[index]->vht_cap.vht_mcs.tx_mcs_map); + } else { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, + bands[index]->vht_cap.vht_mcs.tx_mcs_map); + } + + /* RX stream rates. */ + if (j <= rxstreams) { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, + bands[index]->vht_cap.vht_mcs.rx_mcs_map); + } else { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, + bands[index]->vht_cap.vht_mcs.rx_mcs_map); + } + } + + + /* Capabilities */ + /* 80 MHz is mandatory */ + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SHORT_GI_80; + + if (WL_BW_CAP_160MHZ(bw_cap)) { + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SHORT_GI_160; + } + + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + + if (ldpc_cap) + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_RXLDPC; + + if (stbc_tx) + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_TXSTBC; + + if (stbc_rx) + bands[index]->vht_cap.cap |= + (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT); + + if (txbf_bfe_cap) + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + + if (txbf_bfr_cap) { + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + } + + if (txbf_bfe_cap || txbf_bfr_cap) { + bands[index]->vht_cap.cap |= + (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT); + bands[index]->vht_cap.cap |= + ((txstreams - 1) << + VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT); + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; + } + + /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */ + bands[index]->vht_cap.cap |= + (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT); + WL_INFO(("%s band[%d] vht_enab=%d vht_cap=%08x " + "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n", + __FUNCTION__, index, + bands[index]->vht_cap.vht_supported, + bands[index]->vht_cap.cap, + bands[index]->vht_cap.vht_mcs.rx_mcs_map, + bands[index]->vht_cap.vht_mcs.tx_mcs_map)); + } +#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ + } + else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { + bands[IEEE80211_BAND_2GHZ] = + &__wl_band_2ghz; + index = IEEE80211_BAND_2GHZ; + if (bw_cap == WLC_N_BW_40ALL) + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + } + + if ((index >= 0) && nmode) { + bands[index]->ht_cap.cap |= + (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); + bands[index]->ht_cap.ht_supported = TRUE; + bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + /* An HT shall support all EQM rates for one spatial stream */ + bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; + } + + } + + wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; + wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; + + /* check if any bands populated otherwise makes 2Ghz as default */ + if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL && + wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) { + /* Setup 2Ghz band as default */ + wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + } + + if (notify) + wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); + + end_bands: + if (rollback_lock) + mutex_unlock(&cfg->usr_sync); + return err; +} + +static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) +{ + s32 err = 0; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + struct wireless_dev *wdev = ndev->ieee80211_ptr; + + WL_DBG(("In\n")); + + err = dhd_config_dongle(cfg); + if (unlikely(err)) + return err; + + err = wl_config_ifmode(cfg, ndev, wdev->iftype); + if (unlikely(err && err != -EINPROGRESS)) { + WL_ERR(("wl_config_ifmode failed\n")); + if (err == -1) { + WL_ERR(("return error %d\n", err)); + return err; + } + } + err = wl_update_wiphybands(cfg, true); + if (unlikely(err)) { + WL_ERR(("wl_update_wiphybands failed\n")); + if (err == -1) { + WL_ERR(("return error %d\n", err)); + return err; + } + } + + err = dhd_monitor_init(cfg->pub); + + INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler); + wl_set_drv_status(cfg, READY, ndev); + return err; +} + +static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) +{ + s32 err = 0; + unsigned long flags; + struct net_info *iter, *next; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); +#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \ + defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP) + struct net_device *p2p_net = cfg->p2p_net; +#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) || !PLATFORM_SLP */ + u32 bssidx = 0; +#ifdef PROP_TXSTATUS_VSDB + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif /* PROP_TXSTATUS_VSDB */ + WL_DBG(("In\n")); + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + +#ifdef WL_NAN + wl_cfgnan_stop_handler(ndev, g_bcm_cfg, NULL, NULL); +#endif /* WL_NAN */ + + if (cfg->p2p_supported) { + wl_clr_p2p_status(cfg, GO_NEG_PHASE); +#ifdef PROP_TXSTATUS_VSDB + if (cfg->p2p->vif_created) { + bool enabled = false; + dhd_wlfc_get_enable(dhd, &enabled); + if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && + dhd->op_mode != DHD_FLAG_IBSS_MODE) { + dhd_wlfc_deinit(dhd); + cfg->wlfc_on = false; + } + } +#endif /* PROP_TXSTATUS_VSDB */ + } + + + /* If primary BSS is operational (for e.g SoftAP), bring it down */ + if (!(wl_cfgp2p_find_idx(cfg, ndev, &bssidx)) && + wl_cfgp2p_bss_isup(ndev, bssidx)) { + if (wl_cfgp2p_bss(cfg, ndev, bssidx, 0) < 0) + WL_ERR(("BSS down failed \n")); + } + + /* Check if cfg80211 interface is already down */ + if (!wl_get_drv_status(cfg, READY, ndev)) + return err; /* it is even not ready */ + for_each_ndev(cfg, iter, next) + wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); + + + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + if (cfg->scan_request) { + cfg80211_scan_done(cfg->scan_request, true); + cfg->scan_request = NULL; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + for_each_ndev(cfg, iter, next) { + wl_clr_drv_status(cfg, READY, iter->ndev); + wl_clr_drv_status(cfg, SCANNING, iter->ndev); + wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev); + wl_clr_drv_status(cfg, CONNECTING, iter->ndev); + wl_clr_drv_status(cfg, CONNECTED, iter->ndev); + wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev); + wl_clr_drv_status(cfg, AP_CREATED, iter->ndev); + wl_clr_drv_status(cfg, AP_CREATING, iter->ndev); + } + bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype = + NL80211_IFTYPE_STATION; +#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \ + defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP) + if (p2p_net) + dev_close(p2p_net); +#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) || !PLATFORM_SLP */ + DNGL_FUNC(dhd_cfg80211_down, (cfg)); + wl_flush_eq(cfg); + wl_link_down(cfg); + if (cfg->p2p_supported) + wl_cfgp2p_down(cfg); + +#ifdef DHD_LOSSLESS_ROAMING + if (timer_pending(&cfg->roam_timeout)) { + del_timer_sync(&cfg->roam_timeout); + } +#endif /* DHD_LOSSLESS_ROAMING */ + + if (cfg->ap_info) { + kfree(cfg->ap_info->wpa_ie); + kfree(cfg->ap_info->rsn_ie); + kfree(cfg->ap_info->wps_ie); + kfree(cfg->ap_info); + cfg->ap_info = NULL; + } + dhd_monitor_uninit(); + +#ifdef WL11U + /* Clear interworking element. */ + if (cfg->wl11u) { + cfg->wl11u = FALSE; + cfg->iw_ie_len = 0; + memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN); + } +#endif /* WL11U */ + + return err; +} + +s32 wl_cfg80211_up(void *para) +{ + struct bcm_cfg80211 *cfg; + s32 err = 0; + int val = 1; + dhd_pub_t *dhd; + + (void)para; + WL_DBG(("In\n")); + cfg = g_bcm_cfg; + + if ((err = wldev_ioctl(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val, + sizeof(int), false) < 0)) { + WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err)); + return err; + } + val = dtoh32(val); + if (val != WLC_IOCTL_VERSION && val != 1) { + WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n", + val, WLC_IOCTL_VERSION)); + return BCME_VERSION; + } + ioctl_version = val; + WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version)); + + mutex_lock(&cfg->usr_sync); + dhd = (dhd_pub_t *)(cfg->pub); + if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { + err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg)); + if (unlikely(err)) + return err; + } + err = __wl_cfg80211_up(cfg); + if (unlikely(err)) + WL_ERR(("__wl_cfg80211_up failed\n")); + mutex_unlock(&cfg->usr_sync); + return err; +} + +/* Private Event to Supplicant with indication that chip hangs */ +int wl_cfg80211_hang(struct net_device *dev, u16 reason) +{ + struct bcm_cfg80211 *cfg; + cfg = g_bcm_cfg; + + WL_ERR(("In : chip crash eventing\n")); + wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); + cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL); + if (cfg != NULL) { + wl_link_down(cfg); + } + return 0; +} + +s32 wl_cfg80211_down(void *para) +{ + struct bcm_cfg80211 *cfg; + s32 err = 0; + + (void)para; + WL_DBG(("In\n")); + cfg = g_bcm_cfg; + mutex_lock(&cfg->usr_sync); + err = __wl_cfg80211_down(cfg); + mutex_unlock(&cfg->usr_sync); + + return err; +} + +static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item) +{ + unsigned long flags; + void *rptr = NULL; + struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); + + if (!profile) + return NULL; + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + switch (item) { + case WL_PROF_SEC: + rptr = &profile->sec; + break; + case WL_PROF_ACT: + rptr = &profile->active; + break; + case WL_PROF_BSSID: + rptr = profile->bssid; + break; + case WL_PROF_SSID: + rptr = &profile->ssid; + break; + case WL_PROF_CHAN: + rptr = &profile->channel; + break; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + if (!rptr) + WL_ERR(("invalid item (%d)\n", item)); + return rptr; +} + +static s32 +wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e, void *data, s32 item) +{ + s32 err = 0; + struct wlc_ssid *ssid; + unsigned long flags; + struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); + + if (!profile) + return WL_INVALID; + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); + switch (item) { + case WL_PROF_SSID: + ssid = (wlc_ssid_t *) data; + memset(profile->ssid.SSID, 0, + sizeof(profile->ssid.SSID)); + profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN); + memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len); + break; + case WL_PROF_BSSID: + if (data) + memcpy(profile->bssid, data, ETHER_ADDR_LEN); + else + memset(profile->bssid, 0, ETHER_ADDR_LEN); + break; + case WL_PROF_SEC: + memcpy(&profile->sec, data, sizeof(profile->sec)); + break; + case WL_PROF_ACT: + profile->active = *(bool *)data; + break; + case WL_PROF_BEACONINT: + profile->beacon_interval = *(u16 *)data; + break; + case WL_PROF_DTIMPERIOD: + profile->dtim_period = *(u8 *)data; + break; + case WL_PROF_CHAN: + profile->channel = *(u32*)data; + break; + default: + err = -EOPNOTSUPP; + break; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + if (err == -EOPNOTSUPP) + WL_ERR(("unsupported item (%d)\n", item)); + + return err; +} + +void wl_cfg80211_dbg_level(u32 level) +{ + /* + * prohibit to change debug level + * by insmod parameter. + * eventually debug level will be configured + * in compile time by using CONFIG_XXX + */ + /* wl_dbg_level = level; */ +} + +static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS; +} + +static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg) +{ + return cfg->ibss_starter; +} + +static void wl_rst_ie(struct bcm_cfg80211 *cfg) +{ + struct wl_ie *ie = wl_to_ie(cfg); + + ie->offset = 0; +} + +static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v) +{ + struct wl_ie *ie = wl_to_ie(cfg); + s32 err = 0; + + if (unlikely(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; +} + +static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam) +{ + u8 *ssidie; + int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); + int32 remaining_ie_buf_len, available_buffer_len; + ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); + + /* ERROR out if + * 1. No ssid IE is FOUND or + * 2. New ssid length is > what was allocated for existing ssid (as + * we do not want to overwrite the rest of the IEs) or + * 3. If in case of erroneous buffer input where ssid length doesnt match the space + * allocated to it. + */ + if (!ssidie) { + return; + } + available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream); + remaining_ie_buf_len = available_buffer_len - (int)ssidie[1]; + if ((ssid_len > ssidie[1]) || + (ssidie[1] > available_buffer_len)) { + return; + } + + if (ssidie[1] != ssid_len) { + if (ssidie[1]) { + WL_ERR(("%s: Wrong SSID len: %d != %d\n", + __FUNCTION__, ssidie[1], bi->SSID_len)); + } + if (roam) { + WL_ERR(("Changing the SSID Info.\n")); + memmove(ssidie + ssid_len + 2, + (ssidie + 2) + ssidie[1], + remaining_ie_buf_len); + memcpy(ssidie + 2, bi->SSID, ssid_len); + *ie_size = *ie_size + ssid_len - ssidie[1]; + ssidie[1] = ssid_len; + } + return; + } + if (*(ssidie + 2) == '\0') + memcpy(ssidie + 2, bi->SSID, ssid_len); + return; +} + +static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size) +{ + struct wl_ie *ie = wl_to_ie(cfg); + s32 err = 0; + + if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { + WL_ERR(("ei_stream crosses buffer boundary\n")); + return -ENOSPC; + } + memcpy(&ie->buf[ie->offset], ie_stream, ie_size); + ie->offset += ie_size; + + return err; +} + +static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size) +{ + struct wl_ie *ie = wl_to_ie(cfg); + s32 err = 0; + + if (unlikely(ie->offset > dst_size)) { + WL_ERR(("dst_size is not enough\n")); + return -ENOSPC; + } + memcpy(dst, &ie->buf[0], ie->offset); + + return err; +} + +static u32 wl_get_ielen(struct bcm_cfg80211 *cfg) +{ + struct wl_ie *ie = wl_to_ie(cfg); + + return ie->offset; +} + +static void wl_link_up(struct bcm_cfg80211 *cfg) +{ + cfg->link_up = true; +} + +static void wl_link_down(struct bcm_cfg80211 *cfg) +{ + struct wl_connect_info *conn_info = wl_to_conn(cfg); + + WL_DBG(("In\n")); + cfg->link_up = false; + conn_info->req_ie_len = 0; + conn_info->resp_ie_len = 0; +} + +static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg) +{ + unsigned long flags; + + spin_lock_irqsave(&cfg->eq_lock, flags); + return flags; +} + +static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags) +{ + spin_unlock_irqrestore(&cfg->eq_lock, flags); +} + +static void wl_init_eq_lock(struct bcm_cfg80211 *cfg) +{ + spin_lock_init(&cfg->eq_lock); +} + +static void wl_delay(u32 ms) +{ + if (in_atomic() || (ms < jiffies_to_msecs(1))) { + OSL_DELAY(ms*1000); + } else { + OSL_SLEEP(ms); + } +} + +s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + struct ether_addr p2pif_addr; + struct ether_addr primary_mac; + if (!cfg->p2p) + return -1; + if (!p2p_is_on(cfg)) { + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); + } else { + memcpy(p2pdev_addr->octet, + cfg->p2p->dev_addr.octet, ETHER_ADDR_LEN); + } + + + return 0; +} +s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) +{ + struct bcm_cfg80211 *cfg; + + cfg = g_bcm_cfg; + + return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len); +} + +s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) +{ + struct bcm_cfg80211 *cfg; + cfg = g_bcm_cfg; + + return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len); +} + +s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) +{ + struct bcm_cfg80211 *cfg; + cfg = g_bcm_cfg; + + return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len); +} + +s32 wl_cfg80211_channel_to_freq(u32 channel) +{ + int freq = 0; + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) + freq = ieee80211_channel_to_frequency(channel); +#else + { + u16 band = 0; + if (channel <= CH_MAX_2G_CHANNEL) + band = IEEE80211_BAND_2GHZ; + else + band = IEEE80211_BAND_5GHZ; + freq = ieee80211_channel_to_frequency(channel, band); + } +#endif + return freq; +} + + +#ifdef WLTDLS +static s32 +wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) { + + struct net_device *ndev = NULL; + u32 reason = ntoh32(e->reason); + s8 *msg = NULL; + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + switch (reason) { + case WLC_E_TDLS_PEER_DISCOVERED : + msg = " TDLS PEER DISCOVERD "; + break; + case WLC_E_TDLS_PEER_CONNECTED : + if (cfg->tdls_mgmt_frame) { + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) + cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0, + cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, + GFP_ATOMIC); + #else + cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, + cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, + GFP_ATOMIC); + #endif + } + msg = " TDLS PEER CONNECTED "; + break; + case WLC_E_TDLS_PEER_DISCONNECTED : + if (cfg->tdls_mgmt_frame) { + kfree(cfg->tdls_mgmt_frame); + cfg->tdls_mgmt_frame = NULL; + cfg->tdls_mgmt_freq = 0; + } + msg = "TDLS PEER DISCONNECTED "; + break; + } + if (msg) { + WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((u8*)(&e->addr)), + (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary")); + } + return 0; + +} +#endif /* WLTDLS */ + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) +static s32 +#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) +wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, + u32 peer_capability, const u8 *data, size_t len) +#else +wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data, + size_t len) +#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ +{ + s32 ret = 0; +#ifdef WLTDLS + struct bcm_cfg80211 *cfg; + tdls_wfd_ie_iovar_t info; + memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t)); + cfg = g_bcm_cfg; + +#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) + /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10 + * and that cuases build error + */ + BCM_REFERENCE(peer_capability); +#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ + + switch (action_code) { + /* We need to set TDLS Wifi Display IE to firmware + * using tdls_wfd_ie iovar + */ + case WLAN_TDLS_SET_PROBE_WFD_IE: + info.mode = TDLS_WFD_PROBE_IE_TX; + memcpy(&info.data, data, len); + info.length = len; + break; + case WLAN_TDLS_SET_SETUP_WFD_IE: + info.mode = TDLS_WFD_IE_TX; + memcpy(&info.data, data, len); + info.length = len; + break; + default: + WL_ERR(("Unsupported action code : %d\n", action_code)); + goto out; + } + + ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (ret) { + WL_ERR(("tdls_wfd_ie error %d\n", ret)); + } +out: +#endif /* WLTDLS */ + return ret; +} + +static s32 +wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, enum nl80211_tdls_operation oper) +{ + s32 ret = 0; +#ifdef WLTDLS + struct bcm_cfg80211 *cfg; + tdls_iovar_t info; + cfg = g_bcm_cfg; + memset(&info, 0, sizeof(tdls_iovar_t)); + if (peer) + memcpy(&info.ea, peer, ETHER_ADDR_LEN); + switch (oper) { + case NL80211_TDLS_DISCOVERY_REQ: + /* turn on TDLS */ + ret = dhd_tdls_enable(dev, true, false, NULL); + if (ret < 0) + return ret; + /* If the discovery request is broadcast then we need to set + * info.mode to Tunneled Probe Request + */ + if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) { + info.mode = TDLS_MANUAL_EP_WFD_TPQ; + } + else { + info.mode = TDLS_MANUAL_EP_DISCOVERY; + } + break; + case NL80211_TDLS_SETUP: + /* auto mode on */ + ret = dhd_tdls_enable(dev, true, true, (struct ether_addr *)peer); + if (ret < 0) + return ret; + break; + case NL80211_TDLS_TEARDOWN: + info.mode = TDLS_MANUAL_EP_DELETE; + /* auto mode off */ + ret = dhd_tdls_enable(dev, true, false, (struct ether_addr *)peer); + if (ret < 0) + return ret; + break; + default: + WL_ERR(("Unsupported operation : %d\n", oper)); + goto out; + } + if (info.mode) { + ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (ret) { + WL_ERR(("tdls_endpoint error %d\n", ret)); + } + } +out: +#endif /* WLTDLS */ + return ret; +} +#endif + +s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, + enum wl_management_type type) +{ + struct bcm_cfg80211 *cfg; + struct net_device *ndev = NULL; + struct ether_addr primary_mac; + s32 ret = 0; + s32 bssidx = 0; + s32 pktflag = 0; + cfg = g_bcm_cfg; + + if (wl_get_drv_status(cfg, AP_CREATING, net)) { + /* Vendor IEs should be set to FW + * after SoftAP interface is brought up + */ + goto exit; + } else if (wl_get_drv_status(cfg, AP_CREATED, net)) { + ndev = net; + bssidx = 0; + } else if (cfg->p2p) { + net = ndev_to_wlc_ndev(net, cfg); + if (!cfg->p2p->on) { + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr, + &cfg->p2p->int_addr); + /* In case of p2p_listen command, supplicant send remain_on_channel + * without turning on P2P + */ + + p2p_on(cfg) = true; + ret = wl_cfgp2p_enable_discovery(cfg, net, NULL, 0); + + if (unlikely(ret)) { + goto exit; + } + } + if (net != bcmcfg_to_prmry_ndev(cfg)) { + if (wl_get_mode_by_netdev(cfg, net) == WL_MODE_AP) { + ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION); + } + } else { + ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + } + } + if (ndev != NULL) { + switch (type) { + case WL_BEACON: + pktflag = VNDR_IE_BEACON_FLAG; + break; + case WL_PROBE_RESP: + pktflag = VNDR_IE_PRBRSP_FLAG; + break; + case WL_ASSOC_RESP: + pktflag = VNDR_IE_ASSOCRSP_FLAG; + break; + } + if (pktflag) + ret = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, pktflag, buf, len); + } +exit: + return ret; +} + +#ifdef WL_SUPPORT_AUTO_CHANNEL +static s32 +wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev) +{ + u32 val = 0; + s32 ret = BCME_ERROR; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + /* Disable mpc, to avoid automatic interface down. */ + val = 0; + + ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, + sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, + &cfg->ioctl_buf_sync); + if (ret < 0) { + WL_ERR(("set 'mpc' failed, error = %d\n", ret)); + goto done; + } + + /* Set interface up, explicitly. */ + val = 1; + + ret = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true); + if (ret < 0) { + WL_ERR(("set interface up failed, error = %d\n", ret)); + goto done; + } + + /* Stop all scan explicitly, till auto channel selection complete. */ + wl_set_drv_status(cfg, SCANNING, ndev); + if (cfg->escan_info.ndev == NULL) { + ret = BCME_OK; + goto done; + } + ret = wl_notify_escan_complete(cfg, ndev, true, true); + if (ret < 0) { + WL_ERR(("set scan abort failed, error = %d\n", ret)); + goto done; + } + +done: + return ret; +} + +static bool +wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec) +{ + bool valid = false; + + if (ioctl_version != 1) { + if ((chanspec = wl_chspec_to_legacy(chanspec)) == INVCHANSPEC) { + return valid; + } + } + + /* channel 1 to 14 */ + if ((chanspec >= 0x2b01) && (chanspec <= 0x2b0e)) { + valid = true; + } + /* channel 36 to 48 */ + else if ((chanspec >= 0x1b24) && (chanspec <= 0x1b30)) { + valid = true; + } + /* channel 149 to 161 */ + else if ((chanspec >= 0x1b95) && (chanspec <= 0x1ba1)) { + valid = true; + } + else { + valid = false; + WL_INFO(("invalid P2P chanspec, channel = %d, chanspec = %04x\n", + CHSPEC_CHANNEL(chanspec), chanspec)); + } + + return valid; +} + +static s32 +wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen) +{ + s32 ret = BCME_ERROR; + struct bcm_cfg80211 *cfg = NULL; + chanspec_t chanspec = 0; + + cfg = g_bcm_cfg; + + /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */ + chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 | + WL_CHANSPEC_CTL_SB_NONE); + chanspec = wl_chspec_host_to_driver(chanspec); + + ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, + sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync); + if (ret < 0) { + WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); + } + + return ret; +} + +static s32 +wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen) +{ + u32 channel = 0; + s32 ret = BCME_ERROR; + s32 i = 0; + s32 j = 0; + struct bcm_cfg80211 *cfg = NULL; + wl_uint32_list_t *list = NULL; + chanspec_t chanspec = 0; + + cfg = g_bcm_cfg; + + /* Restrict channels to 5GHz, 20MHz BW, no SB. */ + chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 | + WL_CHANSPEC_CTL_SB_NONE); + chanspec = wl_chspec_host_to_driver(chanspec); + + ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, + sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync); + if (ret < 0) { + WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); + goto done; + } + + list = (wl_uint32_list_t *)buf; + /* Skip DFS and inavlid P2P channel. */ + for (i = 0, j = 0; i < dtoh32(list->count); i++) { + chanspec = (chanspec_t) dtoh32(list->element[i]); + channel = CHSPEC_CHANNEL(chanspec); + + ret = wldev_iovar_getint(ndev, "per_chan_info", &channel); + if (ret < 0) { + WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret)); + goto done; + } + + if (CHANNEL_IS_RADAR(channel) || + !(wl_cfg80211_valid_chanspec_p2p(chanspec))) { + continue; + } else { + list->element[j] = list->element[i]; + } + + j++; + } + + list->count = j; + +done: + return ret; +} + +static s32 +wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen, + int *channel) +{ + s32 ret = BCME_ERROR; + int chosen = 0; + int retry = 0; + + /* Start auto channel selection scan. */ + ret = wldev_ioctl(ndev, WLC_START_CHANNEL_SEL, buf, buflen, true); + if (ret < 0) { + WL_ERR(("can't start auto channel scan, error = %d\n", ret)); + *channel = 0; + goto done; + } + + /* Wait for auto channel selection, worst case possible delay is 5250ms. */ + retry = CHAN_SEL_RETRY_COUNT; + + while (retry--) { + OSL_SLEEP(CHAN_SEL_IOCTL_DELAY); + chosen = 0; + ret = wldev_ioctl(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), + false); + if ((ret == 0) && (dtoh32(chosen) != 0)) { + *channel = (u16)(chosen & 0x00FF); + WL_INFO(("selected channel = %d\n", *channel)); + break; + } + WL_INFO(("attempt = %d, ret = %d, chosen = %d\n", + (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen))); + } + + if (retry <= 0) { + WL_ERR(("failure, auto channel selection timed out\n")); + *channel = 0; + ret = BCME_ERROR; + } + +done: + return ret; +} + +static s32 +wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev) +{ + u32 val = 0; + s32 ret = BCME_ERROR; + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + /* Clear scan stop driver status. */ + wl_clr_drv_status(cfg, SCANNING, ndev); + + /* Enable mpc back to 1, irrespective of initial state. */ + val = 1; + + ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, + sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, + &cfg->ioctl_buf_sync); + if (ret < 0) { + WL_ERR(("set 'mpc' failed, error = %d\n", ret)); + } + + return ret; +} + +s32 +wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len) +{ + int channel = 0; + s32 ret = BCME_ERROR; + u8 *buf = NULL; + char *pos = cmd; + struct bcm_cfg80211 *cfg = NULL; + struct net_device *ndev = NULL; + + memset(cmd, 0, total_len); + + buf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL); + if (buf == NULL) { + WL_ERR(("failed to allocate chanspec buffer\n")); + return -ENOMEM; + } + + /* + * Always use primary interface, irrespective of interface on which + * command came. + */ + cfg = g_bcm_cfg; + ndev = bcmcfg_to_prmry_ndev(cfg); + + /* + * Make sure that FW and driver are in right state to do auto channel + * selection scan. + */ + ret = wl_cfg80211_set_auto_channel_scan_state(ndev); + if (ret < 0) { + WL_ERR(("can't set auto channel scan state, error = %d\n", ret)); + goto done; + } + + /* Best channel selection in 2.4GHz band. */ + ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); + if (ret < 0) { + WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret)); + goto done; + } + + ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, + &channel); + if (ret < 0) { + WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret)); + goto done; + } + + if (CHANNEL_IS_2G(channel)) { + channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); + } else { + WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel)); + channel = 0; + } + + sprintf(pos, "%04d ", channel); + pos += 5; + + /* Best channel selection in 5GHz band. */ + ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); + if (ret < 0) { + WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret)); + goto done; + } + + ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, + &channel); + if (ret < 0) { + WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret)); + goto done; + } + + if (CHANNEL_IS_5G(channel)) { + channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); + } else { + WL_ERR(("invalid 5GHz channel, channel = %d\n", channel)); + channel = 0; + } + + sprintf(pos, "%04d ", channel); + pos += 5; + + /* Set overall best channel same as 5GHz best channel. */ + sprintf(pos, "%04d ", channel); + pos += 5; + +done: + if (NULL != buf) { + kfree(buf); + } + + /* Restore FW and driver back to normal state. */ + ret = wl_cfg80211_restore_auto_channel_scan_state(ndev); + if (ret < 0) { + WL_ERR(("can't restore auto channel scan state, error = %d\n", ret)); + } + + return (pos - cmd); +} +#endif /* WL_SUPPORT_AUTO_CHANNEL */ + +static const struct rfkill_ops wl_rfkill_ops = { + .set_block = wl_rfkill_set +}; + +static int wl_rfkill_set(void *data, bool blocked) +{ + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; + + WL_DBG(("Enter \n")); + WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked")); + + if (!cfg) + return -EINVAL; + + cfg->rf_blocked = blocked; + + return 0; +} + +static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup) +{ + s32 err = 0; + + WL_DBG(("Enter \n")); + if (!cfg) + return -EINVAL; + if (setup) { + cfg->rfkill = rfkill_alloc("brcmfmac-wifi", + wl_cfg80211_get_parent_dev(), + RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg); + + if (!cfg->rfkill) { + err = -ENOMEM; + goto err_out; + } + + err = rfkill_register(cfg->rfkill); + + if (err) + rfkill_destroy(cfg->rfkill); + } else { + if (!cfg->rfkill) { + err = -ENOMEM; + goto err_out; + } + + rfkill_unregister(cfg->rfkill); + rfkill_destroy(cfg->rfkill); + } + +err_out: + return err; +} + +#ifdef DEBUGFS_CFG80211 +/** +* Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level +* to turn on SCAN and DBG log. +* To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level +* To see current setting of debug level, +* cat /sys/kernel/debug/dhd/debug_level +*/ +static ssize_t +wl_debuglevel_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL]; + char *params, *token, *colon; + uint i, tokens, log_on = 0; + memset(tbuf, 0, sizeof(tbuf)); + memset(sublog, 0, sizeof(sublog)); + if (copy_from_user(&tbuf, userbuf, min_t(size_t, sizeof(tbuf), count))) + return -EFAULT; + + params = &tbuf[0]; + colon = strchr(params, '\n'); + if (colon != NULL) + *colon = '\0'; + while ((token = strsep(¶ms, " ")) != NULL) { + memset(sublog, 0, sizeof(sublog)); + if (token == NULL || !*token) + break; + if (*token == '\0') + continue; + colon = strchr(token, ':'); + if (colon != NULL) { + *colon = ' '; + } + tokens = sscanf(token, "%s %u", sublog, &log_on); + if (colon != NULL) + *colon = ':'; + + if (tokens == 2) { + for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { + if (!strncmp(sublog, sublogname_map[i].sublogname, + strlen(sublogname_map[i].sublogname))) { + if (log_on) + wl_dbg_level |= + (sublogname_map[i].log_level); + else + wl_dbg_level &= + ~(sublogname_map[i].log_level); + } + } + } else + WL_ERR(("%s: can't parse '%s' as a " + "SUBMODULE:LEVEL (%d tokens)\n", + tbuf, token, tokens)); + + + } + return count; +} + +static ssize_t +wl_debuglevel_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + char *param; + char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)]; + uint i; + memset(tbuf, 0, sizeof(tbuf)); + param = &tbuf[0]; + for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { + param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ", + sublogname_map[i].sublogname, + (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0); + } + *param = '\n'; + return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0])); + +} +static const struct file_operations fops_debuglevel = { + .open = NULL, + .write = wl_debuglevel_write, + .read = wl_debuglevel_read, + .owner = THIS_MODULE, + .llseek = NULL, +}; + +static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg) +{ + s32 err = 0; + struct dentry *_dentry; + if (!cfg) + return -EINVAL; + cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!cfg->debugfs || IS_ERR(cfg->debugfs)) { + if (cfg->debugfs == ERR_PTR(-ENODEV)) + WL_ERR(("Debugfs is not enabled on this kernel\n")); + else + WL_ERR(("Can not create debugfs directory\n")); + cfg->debugfs = NULL; + goto exit; + + } + _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR, + cfg->debugfs, cfg, &fops_debuglevel); + if (!_dentry || IS_ERR(_dentry)) { + WL_ERR(("failed to create debug_level debug file\n")); + wl_free_debugfs(cfg); + } +exit: + return err; +} +static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg) +{ + if (!cfg) + return -EINVAL; + if (cfg->debugfs) + debugfs_remove_recursive(cfg->debugfs); + cfg->debugfs = NULL; + return 0; +} +#endif /* DEBUGFS_CFG80211 */ + +struct device *wl_cfg80211_get_parent_dev(void) +{ + return cfg80211_parent_dev; +} + +void wl_cfg80211_set_parent_dev(void *dev) +{ + cfg80211_parent_dev = dev; +} + +static void wl_cfg80211_clear_parent_dev(void) +{ + cfg80211_parent_dev = NULL; +} + +void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac) +{ + wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr", NULL, + 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync); + memcpy(mac->octet, cfg->ioctl_buf, ETHER_ADDR_LEN); +} +static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + if (((dev_role == NL80211_IFTYPE_AP) && + !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) || + ((dev_role == NL80211_IFTYPE_P2P_GO) && + !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE))) + { + WL_ERR(("device role select failed\n")); + return false; + } + return true; +} + +int wl_cfg80211_do_driver_init(struct net_device *net) +{ + struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net); + + if (!cfg || !cfg->wdev) + return -EINVAL; + + if (dhd_do_driver_init(cfg->wdev->netdev) < 0) + return -1; + + return 0; +} + +void wl_cfg80211_enable_trace(bool set, u32 level) +{ + if (set) + wl_dbg_level = level & WL_DBG_LEVEL; + else + wl_dbg_level |= (WL_DBG_LEVEL & level); +} +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) +static s32 +wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + bcm_struct_cfgdev *cfgdev, u64 cookie) +{ + /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION + * is passed with CMD_FRAME. This callback is supposed to cancel + * the OFFCHANNEL Wait. Since we are already taking care of that + * with the tx_mgmt logic, do nothing here. + */ + + return 0; +} +#endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */ + +#ifdef WL11U +bcm_tlv_t * +wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) { + return (bcm_tlv_t *)ie; + } + return NULL; +} + + +static s32 +wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, + uint8 ie_id, uint8 *data, uint8 data_len) +{ + s32 err = BCME_OK; + s32 buf_len; + s32 iecount; + ie_setbuf_t *ie_setbuf; + + if (ie_id != DOT11_MNG_INTERWORKING_ID) + return BCME_UNSUPPORTED; + + /* access network options (1 octet) is the mandatory field */ + if (!data || data_len == 0 || data_len > IW_IES_MAX_BUF_LEN) { + WL_ERR(("wrong interworking IE (len=%d)\n", data_len)); + return BCME_BADARG; + } + + /* Validate the pktflag parameter */ + if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | + VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | + VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| + VNDR_IE_CUSTOM_FLAG))) { + WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag)); + return -1; + } + + /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ + pktflag = htod32(pktflag); + + buf_len = sizeof(ie_setbuf_t) + data_len - 1; + ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); + + if (!ie_setbuf) { + WL_ERR(("Error allocating buffer for IE\n")); + return -ENOMEM; + } + + if (cfg->iw_ie_len == data_len && !memcmp(cfg->iw_ie, data, data_len)) { + WL_ERR(("Previous IW IE is equals to current IE\n")); + err = BCME_OK; + goto exit; + } + + strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); + ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); + memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); + + /* Now, add the IE to the buffer */ + ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; + + /* if already set with previous values, delete it first */ + if (cfg->iw_ie_len != 0) { + WL_DBG(("Different IW_IE was already set. clear first\n")); + + ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; + + err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + if (err != BCME_OK) + goto exit; + } + + ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; + memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); + + err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + if (err == BCME_OK) { + memcpy(cfg->iw_ie, data, data_len); + cfg->iw_ie_len = data_len; + cfg->wl11u = TRUE; + + err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); + } + +exit: + if (ie_setbuf) + kfree(ie_setbuf); + return err; +} +#endif /* WL11U */ + + + +int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev) +{ + struct bcm_cfg80211 *cfg = NULL; + struct net_device *ndev = NULL; + unsigned long flags; + int clear_flag = 0; + int ret = 0; + + WL_TRACE(("Enter\n")); + + cfg = g_bcm_cfg; + if (!cfg) + return -EINVAL; + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + spin_lock_irqsave(&cfg->cfgdrv_lock, flags); +#ifdef WL_CFG80211_P2P_DEV_IF + if (cfg->scan_request && cfg->scan_request->wdev == cfgdev) { +#else + if (cfg->scan_request && cfg->scan_request->dev == cfgdev) { +#endif + cfg80211_scan_done(cfg->scan_request, true); + cfg->scan_request = NULL; + clear_flag = 1; + } + spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); + + if (clear_flag) + wl_clr_drv_status(cfg, SCANNING, ndev); + + return ret; +} + +bool wl_cfg80211_is_vsdb_mode(void) +{ + return (g_bcm_cfg && g_bcm_cfg->vsdb_mode); +} + +void* wl_cfg80211_get_dhdp() +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + return cfg->pub; +} + +bool wl_cfg80211_is_p2p_active(void) +{ + return (g_bcm_cfg && g_bcm_cfg->p2p); +} + +static void wl_cfg80211_work_handler(struct work_struct * work) +{ + struct bcm_cfg80211 *cfg = NULL; + struct net_info *iter, *next; + s32 err = BCME_OK; + s32 pm = PM_FAST; + + cfg = container_of(work, struct bcm_cfg80211, pm_enable_work.work); + WL_DBG(("Enter \n")); + if (cfg->pm_enable_work_on) { + cfg->pm_enable_work_on = false; + for_each_ndev(cfg, iter, next) { + if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) || + (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS)) + continue; + if (iter->ndev) { + if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, + &pm, sizeof(pm), true)) != 0) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); + } else + wl_cfg80211_update_power_mode(iter->ndev); + } + } + } +} + +u8 +wl_get_action_category(void *frame, u32 frame_len) +{ + u8 category; + u8 *ptr = (u8 *)frame; + if (frame == NULL) + return DOT11_ACTION_CAT_ERR_MASK; + if (frame_len < DOT11_ACTION_HDR_LEN) + return DOT11_ACTION_CAT_ERR_MASK; + category = ptr[DOT11_ACTION_CAT_OFF]; + WL_INFO(("Action Category: %d\n", category)); + return category; +} + +int +wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action) +{ + u8 *ptr = (u8 *)frame; + if (frame == NULL || ret_action == NULL) + return BCME_ERROR; + if (frame_len < DOT11_ACTION_HDR_LEN) + return BCME_ERROR; + if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len)) + return BCME_ERROR; + *ret_action = ptr[DOT11_ACTION_ACT_OFF]; + WL_INFO(("Public Action : %d\n", *ret_action)); + return BCME_OK; +} + +static int +wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const struct ether_addr *bssid) +{ + s32 err; + wl_event_msg_t e; + + bzero(&e, sizeof(e)); + e.event_type = cpu_to_be32(WLC_E_ROAM); + memcpy(&e.addr, bssid, ETHER_ADDR_LEN); + /* trigger the roam event handler */ + err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL); + + return err; +} + +#ifdef WLFBT +void +wl_cfg80211_get_fbt_key(uint8 *key) +{ + memcpy(key, g_bcm_cfg->fbt_key, FBT_KEYLEN); +} +#endif /* WLFBT */ + +#ifdef WL_CFG80211_ACL +static int +wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, + const struct cfg80211_acl_data *acl) +{ + int i; + int ret = 0; + int macnum = 0; + int macmode = MACLIST_MODE_DISABLED; + struct maclist *list; + + /* get the MAC filter mode */ + if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) { + macmode = MACLIST_MODE_ALLOW; + } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED && + acl->n_acl_entries) { + macmode = MACLIST_MODE_DENY; + } + + /* if acl == NULL, macmode is still disabled.. */ + if (macmode == MACLIST_MODE_DISABLED) { + if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0) + WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); + + return ret; + } + + macnum = acl->n_acl_entries; + if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { + WL_ERR(("%s : invalid number of MAC address entries %d\n", + __FUNCTION__, macnum)); + return -1; + } + + /* allocate memory for the MAC list */ + list = (struct maclist*)kmalloc(sizeof(int) + + sizeof(struct ether_addr) * macnum, GFP_KERNEL); + if (!list) { + WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__)); + return -1; + } + + /* prepare the MAC list */ + list->count = htod32(macnum); + for (i = 0; i < macnum; i++) { + memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN); + } + /* set the list */ + if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0) + WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); + + kfree(list); + + return ret; +} +#endif /* WL_CFG80211_ACL */ + +#ifdef WL_NAN +int +wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd, int cmd_len) +{ + return wl_cfgnan_cmd_handler(ndev, g_bcm_cfg, cmd, cmd_len); +} +#endif /* WL_NAN */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h new file mode 100644 index 000000000000..069eda344e49 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h @@ -0,0 +1,1016 @@ +/* + * Linux cfg80211 driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.h 596861 2015-11-03 08:54:58Z $ + */ + +#ifndef _wl_cfg80211_h_ +#define _wl_cfg80211_h_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct wl_conf; +struct wl_iface; +struct bcm_cfg80211; +struct wl_security; +struct wl_ibss; + + +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh64(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) + +#define WL_DBG_NONE 0 +#define WL_DBG_P2P_ACTION (1 << 5) +#define WL_DBG_TRACE (1 << 4) +#define WL_DBG_SCAN (1 << 3) +#define WL_DBG_DBG (1 << 2) +#define WL_DBG_INFO (1 << 1) +#define WL_DBG_ERR (1 << 0) + +/* 0 invalidates all debug messages. default is 1 */ +#define WL_DBG_LEVEL 0xFF + +#define CFG80211_ERROR_TEXT "CFG80211-ERROR) " + +#if defined(DHD_DEBUG) +#define WL_ERR(args) \ +do { \ + if (wl_dbg_level & WL_DBG_ERR) { \ + printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ + printk args; \ + } \ +} while (0) +#else /* defined(DHD_DEBUG) */ +#define WL_ERR(args) \ +do { \ + if ((wl_dbg_level & WL_DBG_ERR) && net_ratelimit()) { \ + printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ + printk args; \ + } \ +} while (0) +#endif /* defined(DHD_DEBUG) */ + +#ifdef WL_INFO +#undef WL_INFO +#endif +#define WL_INFO(args) \ +do { \ + if (wl_dbg_level & WL_DBG_INFO) { \ + printk(KERN_INFO "CFG80211-INFO) %s : ", __func__); \ + printk args; \ + } \ +} while (0) +#ifdef WL_SCAN +#undef WL_SCAN +#endif +#define WL_SCAN(args) \ +do { \ + if (wl_dbg_level & WL_DBG_SCAN) { \ + printk(KERN_INFO "CFG80211-SCAN) %s :", __func__); \ + printk args; \ + } \ +} while (0) +#ifdef WL_TRACE +#undef WL_TRACE +#endif +#define WL_TRACE(args) \ +do { \ + if (wl_dbg_level & WL_DBG_TRACE) { \ + printk(KERN_INFO "CFG80211-TRACE) %s :", __func__); \ + printk args; \ + } \ +} while (0) +#ifdef WL_TRACE_HW4 +#undef WL_TRACE_HW4 +#endif +#define WL_TRACE_HW4 WL_TRACE +#if (WL_DBG_LEVEL > 0) +#define WL_DBG(args) \ +do { \ + if (wl_dbg_level & WL_DBG_DBG) { \ + printk(KERN_DEBUG "CFG80211-DEBUG) %s :", __func__); \ + printk args; \ + } \ +} while (0) +#else /* !(WL_DBG_LEVEL > 0) */ +#define WL_DBG(args) +#endif /* (WL_DBG_LEVEL > 0) */ +#define WL_PNO(x) +#define WL_SD(x) + + +#define WL_SCAN_RETRY_MAX 3 +#define WL_NUM_PMKIDS_MAX MAXPMKID +#define WL_SCAN_BUF_MAX (1024 * 8) +#define WL_TLV_INFO_MAX 1500 +#define WL_SCAN_IE_LEN_MAX 2048 +#define WL_BSS_INFO_MAX 2048 +#define WL_ASSOC_INFO_MAX 512 +#define WL_IOCTL_LEN_MAX 2048 +#define WL_EXTRA_BUF_MAX 2048 +#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) +#define WL_AP_MAX 256 +#define WL_FILE_NAME_MAX 256 +#define WL_DWELL_TIME 200 +#define WL_MED_DWELL_TIME 400 +#define WL_MIN_DWELL_TIME 100 +#define WL_LONG_DWELL_TIME 1000 +#define IFACE_MAX_CNT 2 +#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 +#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 +#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 +#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 +#define WL_AF_TX_MAX_RETRY 5 + +#define WL_AF_SEARCH_TIME_MAX 450 +#define WL_AF_TX_EXTRA_TIME_MAX 200 + +#define WL_SCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */ +#define WL_CHANNEL_SYNC_RETRY 5 +#define WL_INVALID -1 + +#ifdef DHD_LOSSLESS_ROAMING +#define WL_ROAM_TIMEOUT_MS 1000 /* Roam timeout */ +#endif /* DHD_LOSSLESS_ROAMING */ + +/* Bring down SCB Timeout to 20secs from 60secs default */ +#ifndef WL_SCB_TIMEOUT +#define WL_SCB_TIMEOUT 20 +#endif + +/* SCAN_SUPPRESS timer values in ms */ +#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */ +#define WL_SCAN_SUPPRESS_RETRY 3000 + +#define WL_PM_ENABLE_TIMEOUT 10000 + +#ifdef WLAIBSS +/* Custom AIBSS beacon parameters */ +#define AIBSS_INITIAL_MIN_BCN_DUR 500 +#define AIBSS_MIN_BCN_DUR 5000 +#define AIBSS_BCN_FLOOD_DUR 5000 +#endif /* WLAIBSS */ + +/* driver status */ +enum wl_status { + WL_STATUS_READY = 0, + WL_STATUS_SCANNING, + WL_STATUS_SCAN_ABORTING, + WL_STATUS_CONNECTING, + WL_STATUS_CONNECTED, + WL_STATUS_DISCONNECTING, + WL_STATUS_AP_CREATING, + WL_STATUS_AP_CREATED, + /* whole sending action frame procedure: + * includes a) 'finding common channel' for public action request frame + * and b) 'sending af via 'actframe' iovar' + */ + WL_STATUS_SENDING_ACT_FRM, + /* find a peer to go to a common channel before sending public action req frame */ + WL_STATUS_FINDING_COMMON_CHANNEL, + /* waiting for next af to sync time of supplicant. + * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN + */ + WL_STATUS_WAITING_NEXT_ACT_FRM, +#ifdef WL_CFG80211_SYNC_GON + /* go to listen state to wait for next af after SENDING_ACT_FRM */ + WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN, +#endif /* WL_CFG80211_SYNC_GON */ + /* it will be set when upper layer requests listen and succeed in setting listen mode. + * if set, other scan request can abort current listen state + */ + WL_STATUS_REMAINING_ON_CHANNEL, +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + /* it's fake listen state to keep current scan state. + * it will be set when upper layer requests listen but scan is running. then just run + * a expire timer without actual listen state. + * if set, other scan request does not need to abort scan. + */ + WL_STATUS_FAKE_REMAINING_ON_CHANNEL +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ +}; + +/* wi-fi mode */ +enum wl_mode { + WL_MODE_BSS, + WL_MODE_IBSS, + WL_MODE_AP +}; + +/* driver profile list */ +enum wl_prof_list { + WL_PROF_MODE, + WL_PROF_SSID, + WL_PROF_SEC, + WL_PROF_IBSS, + WL_PROF_BAND, + WL_PROF_CHAN, + WL_PROF_BSSID, + WL_PROF_ACT, + WL_PROF_BEACONINT, + WL_PROF_DTIMPERIOD +}; + +/* donlge escan state */ +enum wl_escan_state { + WL_ESCAN_STATE_IDLE, + WL_ESCAN_STATE_SCANING +}; +/* fw downloading status */ +enum wl_fw_status { + WL_FW_LOADING_DONE, + WL_NVRAM_LOADING_DONE +}; + +enum wl_management_type { + WL_BEACON = 0x1, + WL_PROBE_RESP = 0x2, + WL_ASSOC_RESP = 0x4 +}; + +enum wl_handler_del_type { + WL_HANDLER_NOTUSE, + WL_HANDLER_DEL, + WL_HANDLER_MAINTAIN, + WL_HANDLER_PEND +}; + +/* beacon / probe_response */ +struct beacon_proberesp { + __le64 timestamp; + __le16 beacon_int; + __le16 capab_info; + u8 variable[0]; +} __attribute__ ((packed)); + +/* driver configuration */ +struct wl_conf { + u32 frag_threshold; + u32 rts_threshold; + u32 retry_short; + u32 retry_long; + s32 tx_power; + struct ieee80211_channel channel; +}; + +typedef s32(*EVENT_HANDLER) (struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); + +/* bss inform structure for cfg80211 interface */ +struct wl_cfg80211_bss_info { + u16 band; + u16 channel; + s16 rssi; + u16 frame_len; + u8 frame_buf[1]; +}; + +/* basic structure of scan request */ +struct wl_scan_req { + struct wlc_ssid ssid; +}; + +/* basic structure of information element */ +struct wl_ie { + u16 offset; + u8 buf[WL_TLV_INFO_MAX]; +}; + +/* event queue for cfg80211 main event */ +struct wl_event_q { + struct list_head eq_list; + u32 etype; + wl_event_msg_t emsg; + s8 edata[1]; +}; + +/* security information with currently associated ap */ +struct wl_security { + u32 wpa_versions; + u32 auth_type; + u32 cipher_pairwise; + u32 cipher_group; + u32 wpa_auth; + u32 auth_assoc_res_status; +}; + +/* ibss information for currently joined ibss network */ +struct wl_ibss { + u8 beacon_interval; /* in millisecond */ + u8 atim; /* in millisecond */ + s8 join_only; + u8 band; + u8 channel; +}; + +/* cfg driver profile */ +struct wl_profile { + u32 mode; + s32 band; + u32 channel; + struct wlc_ssid ssid; + struct wl_security sec; + struct wl_ibss ibss; + u8 bssid[ETHER_ADDR_LEN]; + u16 beacon_interval; + u8 dtim_period; + bool active; +}; + +struct net_info { + struct net_device *ndev; + struct wireless_dev *wdev; + struct wl_profile profile; + s32 mode; + s32 roam_off; + unsigned long sme_state; + bool pm_restore; + bool pm_block; + s32 pm; + struct list_head list; /* list of all net_info structure */ +}; + +/* association inform */ +#define MAX_REQ_LINE 1024 +struct wl_connect_info { + u8 req_ie[MAX_REQ_LINE]; + s32 req_ie_len; + u8 resp_ie[MAX_REQ_LINE]; + s32 resp_ie_len; +}; + +/* firmware /nvram downloading controller */ +struct wl_fw_ctrl { + const struct firmware *fw_entry; + unsigned long status; + u32 ptr; + s8 fw_name[WL_FILE_NAME_MAX]; + s8 nvram_name[WL_FILE_NAME_MAX]; +}; + +/* assoc ie length */ +struct wl_assoc_ielen { + u32 req_len; + u32 resp_len; +}; + +/* wpa2 pmk list */ +struct wl_pmk_list { + pmkid_list_t pmkids; + pmkid_t foo[MAXPMKID - 1]; +}; + + +#define ESCAN_BUF_SIZE (64 * 1024) + +struct escan_info { + u32 escan_state; +#if defined(STATIC_WL_PRIV_STRUCT) +#ifndef CONFIG_DHD_USE_STATIC_BUF +#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + u8 *escan_buf; +#else + u8 escan_buf[ESCAN_BUF_SIZE]; +#endif /* STATIC_WL_PRIV_STRUCT */ + struct wiphy *wiphy; + struct net_device *ndev; +}; + +struct ap_info { +/* Structure to hold WPS, WPA IEs for a AP */ + u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN]; + u8 beacon_ie[VNDR_IES_MAX_BUF_LEN]; + u8 assoc_res_ie[VNDR_IES_MAX_BUF_LEN]; + u32 probe_res_ie_len; + u32 beacon_ie_len; + u32 assoc_res_ie_len; + u8 *wpa_ie; + u8 *rsn_ie; + u8 *wps_ie; + bool security_mode; +}; + +struct sta_info { + /* Structure to hold WPS IE for a STA */ + u8 probe_req_ie[VNDR_IES_BUF_LEN]; + u8 assoc_req_ie[VNDR_IES_BUF_LEN]; + u32 probe_req_ie_len; + u32 assoc_req_ie_len; +}; + +struct afx_hdl { + wl_af_params_t *pending_tx_act_frm; + struct ether_addr tx_dst_addr; + struct net_device *dev; + struct work_struct work; + u32 bssidx; + u32 retry; + s32 peer_chan; + s32 peer_listen_chan; /* search channel: configured by upper layer */ + s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */ + bool is_listen; + bool ack_recv; + bool is_active; +}; + +struct parsed_ies { + wpa_ie_fixed_t *wps_ie; + u32 wps_ie_len; + wpa_ie_fixed_t *wpa_ie; + u32 wpa_ie_len; + bcm_tlv_t *wpa2_ie; + u32 wpa2_ie_len; +}; + + +#ifdef WL11U +/* Max length of Interworking element */ +#define IW_IES_MAX_BUF_LEN 9 +#endif +#ifdef WLFBT +#define FBT_KEYLEN 32 +#endif +#define MAX_EVENT_BUF_NUM 16 +typedef struct wl_eventmsg_buf { + u16 num; + struct { + u16 type; + bool set; + } event [MAX_EVENT_BUF_NUM]; +} wl_eventmsg_buf_t; + +typedef struct wl_if_event_info { + bool valid; + int ifidx; + int bssidx; + uint8 mac[ETHER_ADDR_LEN]; + char name[IFNAMSIZ+1]; +} wl_if_event_info; + +/* private data of cfg80211 interface */ +struct bcm_cfg80211 { + struct wireless_dev *wdev; /* representing cfg cfg80211 device */ + + struct wireless_dev *p2p_wdev; /* representing cfg cfg80211 device for P2P */ + struct net_device *p2p_net; /* reference to p2p0 interface */ + + struct wl_conf *conf; + struct cfg80211_scan_request *scan_request; /* scan request object */ + EVENT_HANDLER evt_handler[WLC_E_LAST]; + struct list_head eq_list; /* used for event queue */ + struct list_head net_list; /* used for struct net_info */ + spinlock_t eq_lock; /* for event queue synchronization */ + spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ + struct completion act_frm_scan; + struct completion iface_disable; + struct completion wait_next_af; + struct mutex usr_sync; /* maily for up/down synchronization */ + struct wl_scan_results *bss_list; + struct wl_scan_results *scan_results; + + /* scan request object for internal purpose */ + struct wl_scan_req *scan_req_int; + /* information element object for internal purpose */ +#if defined(STATIC_WL_PRIV_STRUCT) + struct wl_ie *ie; +#else + struct wl_ie ie; +#endif + + /* association information container */ +#if defined(STATIC_WL_PRIV_STRUCT) + struct wl_connect_info *conn_info; +#else + struct wl_connect_info conn_info; +#endif +#ifdef DEBUGFS_CFG80211 + struct dentry *debugfs; +#endif /* DEBUGFS_CFG80211 */ + struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ + tsk_ctl_t event_tsk; /* task of main event handler thread */ + void *pub; + u32 iface_cnt; + u32 channel; /* current channel */ + u32 af_sent_channel; /* channel action frame is sent */ + /* next af subtype to cancel the remained dwell time in rx process */ + u8 next_af_subtype; +#ifdef WL_CFG80211_SYNC_GON + ulong af_tx_sent_jiffies; +#endif /* WL_CFG80211_SYNC_GON */ + struct escan_info escan_info; /* escan information */ + bool active_scan; /* current scan mode */ + bool ibss_starter; /* indicates this sta is ibss starter */ + bool link_up; /* link/connection up flag */ + + /* indicate whether chip to support power save mode */ + bool pwr_save; + bool roam_on; /* on/off switch for self-roaming */ + bool scan_tried; /* indicates if first scan attempted */ + bool wlfc_on; + bool vsdb_mode; + bool roamoff_on_concurrent; + u8 *ioctl_buf; /* ioctl buffer */ + struct mutex ioctl_buf_sync; + u8 *escan_ioctl_buf; + u8 *extra_buf; /* maily to grab assoc information */ + struct dentry *debugfsdir; + struct rfkill *rfkill; + bool rf_blocked; + struct ieee80211_channel remain_on_chan; + enum nl80211_channel_type remain_on_chan_type; + u64 send_action_id; + u64 last_roc_id; + wait_queue_head_t netif_change_event; + wl_if_event_info if_event_info; + struct completion send_af_done; + struct afx_hdl *afx_hdl; + struct ap_info *ap_info; + struct sta_info *sta_info; + struct p2p_info *p2p; + bool p2p_supported; + void *btcoex_info; + struct timer_list scan_timeout; /* Timer for catch scan event timeout */ + s32(*state_notifier) (struct bcm_cfg80211 *cfg, + struct net_info *_net_info, enum wl_status state, bool set); + unsigned long interrested_state; + wlc_ssid_t hostapd_ssid; +#ifdef WL11U + bool wl11u; + u8 iw_ie[IW_IES_MAX_BUF_LEN]; + u32 iw_ie_len; +#endif /* WL11U */ + bool sched_scan_running; /* scheduled scan req status */ +#ifdef WL_SCHED_SCAN + struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ +#endif /* WL_SCHED_SCAN */ + bool scan_suppressed; + struct timer_list scan_supp_timer; + struct work_struct wlan_work; + struct mutex event_sync; /* maily for up/down synchronization */ + bool disable_roam_event; + bool pm_enable_work_on; + struct delayed_work pm_enable_work; + vndr_ie_setbuf_t *ibss_vsie; /* keep the VSIE for IBSS */ + int ibss_vsie_len; +#ifdef WLAIBSS + u32 aibss_txfail_pid; + u32 aibss_txfail_seq; +#endif /* WLAIBSS */ + u32 rmc_event_pid; + u32 rmc_event_seq; + bool roam_offload; +#ifdef WLFBT + uint8 fbt_key[FBT_KEYLEN]; +#endif + bool nan_enable; +#ifdef WLTDLS + u8 *tdls_mgmt_frame; + u32 tdls_mgmt_frame_len; + s32 tdls_mgmt_freq; +#endif /* WLTDLS */ + bool nan_running; + bool need_wait_afrx; +#ifdef DHD_LOSSLESS_ROAMING + struct timer_list roam_timeout; +#endif /* DHD_LOSSLESS_ROAMING */ +}; + + +static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) +{ + return bss = bss ? + (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; +} +static inline s32 +wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev, + struct wireless_dev * wdev, s32 mode, bool pm_block) +{ + struct net_info *_net_info; + s32 err = 0; + if (cfg->iface_cnt == IFACE_MAX_CNT) + return -ENOMEM; + _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL); + if (!_net_info) + err = -ENOMEM; + else { + _net_info->mode = mode; + _net_info->ndev = ndev; + _net_info->wdev = wdev; + _net_info->pm_restore = 0; + _net_info->pm = 0; + _net_info->pm_block = pm_block; + _net_info->roam_off = WL_INVALID; + cfg->iface_cnt++; + list_add(&_net_info->list, &cfg->net_list); + } + return err; +} +static inline void +wl_dealloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) { + list_del(&_net_info->list); + cfg->iface_cnt--; + kfree(_net_info); + } + } + +} +static inline void +wl_delete_all_netinfo(struct bcm_cfg80211 *cfg) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + list_del(&_net_info->list); + if (_net_info->wdev) + kfree(_net_info->wdev); + kfree(_net_info); + } + cfg->iface_cnt = 0; +} +static inline u32 +wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status) + +{ + struct net_info *_net_info, *next; + u32 cnt = 0; + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (_net_info->ndev && + test_bit(status, &_net_info->sme_state)) + cnt++; + } + return cnt; +} +static inline void +wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op) +{ + struct net_info *_net_info, *next; + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + switch (op) { + case 1: + return; /* set all status is not allowed */ + case 2: + clear_bit(status, &_net_info->sme_state); + if (cfg->state_notifier && + test_bit(status, &(cfg->interrested_state))) + cfg->state_notifier(cfg, _net_info, status, false); + break; + case 4: + return; /* change all status is not allowed */ + default: + return; /* unknown operation */ + } + } +} +static inline void +wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, + struct net_device *ndev, u32 op) +{ + + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) { + switch (op) { + case 1: + set_bit(status, &_net_info->sme_state); + if (cfg->state_notifier && + test_bit(status, &(cfg->interrested_state))) + cfg->state_notifier(cfg, _net_info, status, true); + break; + case 2: + clear_bit(status, &_net_info->sme_state); + if (cfg->state_notifier && + test_bit(status, &(cfg->interrested_state))) + cfg->state_notifier(cfg, _net_info, status, false); + break; + case 4: + change_bit(status, &_net_info->sme_state); + break; + } + } + + } + +} + +static inline u32 +wl_get_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, + struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return test_bit(status, &_net_info->sme_state); + } + return 0; +} + +static inline s32 +wl_get_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return _net_info->mode; + } + return -1; +} + + +static inline void +wl_set_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev, + s32 mode) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + _net_info->mode = mode; + } +} +static inline struct wl_profile * +wl_get_profile_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return &_net_info->profile; + } + return NULL; +} +static inline struct net_info * +wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return _net_info; + } + return NULL; +} +#define bcmcfg_to_wiphy(cfg) (cfg->wdev->wiphy) +#define bcmcfg_to_prmry_ndev(cfg) (cfg->wdev->netdev) +#define bcmcfg_to_prmry_wdev(cfg) (cfg->wdev) +#define bcmcfg_to_p2p_wdev(cfg) (cfg->p2p_wdev) +#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) +#define ndev_to_wdev(ndev) (ndev->ieee80211_ptr) +#define wdev_to_ndev(wdev) (wdev->netdev) + +#if defined(WL_ENABLE_P2P_IF) +#define ndev_to_wlc_ndev(ndev, cfg) ((ndev == cfg->p2p_net) ? \ + bcmcfg_to_prmry_ndev(cfg) : ndev) +#else +#define ndev_to_wlc_ndev(ndev, cfg) (ndev) +#endif /* WL_ENABLE_P2P_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define wdev_to_wlc_ndev(wdev, cfg) \ + ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) ? \ + bcmcfg_to_prmry_ndev(cfg) : wdev_to_ndev(wdev)) +#define cfgdev_to_wlc_ndev(cfgdev, cfg) wdev_to_wlc_ndev(cfgdev, cfg) +#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_wdev(cfg) +#elif defined(WL_ENABLE_P2P_IF) +#define cfgdev_to_wlc_ndev(cfgdev, cfg) ndev_to_wlc_ndev(cfgdev, cfg) +#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_ndev(cfg) +#else +#define cfgdev_to_wlc_ndev(cfgdev, cfg) (cfgdev) +#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) (cfgdev) +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define ndev_to_cfgdev(ndev) ndev_to_wdev(ndev) +#define discover_cfgdev(cfgdev, cfg) (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) +#else +#define ndev_to_cfgdev(ndev) (ndev) +#define discover_cfgdev(cfgdev, cfg) (cfgdev == cfg->p2p_net) +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \ + (cfg->scan_request->wdev == cfg->p2p_wdev)) ? true : false) +#elif defined(WL_ENABLE_P2P_IF) +#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \ + (cfg->scan_request->dev == cfg->p2p_net)) ? true : false) +#else +#define scan_req_match(cfg) (((cfg) && p2p_is_on(cfg) && p2p_scan(cfg)) ? \ + true : false) +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#define wl_to_sr(w) (w->scan_req_int) +#if defined(STATIC_WL_PRIV_STRUCT) +#define wl_to_ie(w) (w->ie) +#define wl_to_conn(w) (w->conn_info) +#else +#define wl_to_ie(w) (&w->ie) +#define wl_to_conn(w) (&w->conn_info) +#endif +#define wiphy_from_scan(w) (w->escan_info.wiphy) +#define wl_get_drv_status_all(cfg, stat) \ + (wl_get_status_all(cfg, WL_STATUS_ ## stat)) +#define wl_get_drv_status(cfg, stat, ndev) \ + (wl_get_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev)) +#define wl_set_drv_status(cfg, stat, ndev) \ + (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 1)) +#define wl_clr_drv_status(cfg, stat, ndev) \ + (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 2)) +#define wl_clr_drv_status_all(cfg, stat) \ + (wl_set_status_all(cfg, WL_STATUS_ ## stat, 2)) +#define wl_chg_drv_status(cfg, stat, ndev) \ + (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 4)) + +#define for_each_bss(list, bss, __i) \ + for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) + +#define for_each_ndev(cfg, iter, next) \ + list_for_each_entry_safe(iter, next, &cfg->net_list, list) + + +/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0. + * In addtion to that, wpa_version is WPA_VERSION_1 + */ +#define is_wps_conn(_sme) \ + ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \ + (!_sme->crypto.n_ciphers_pairwise) && \ + (!_sme->crypto.cipher_group)) + +#ifdef WLFBT +#if defined(WLAN_AKM_SUITE_FT_8021X) && defined(WLAN_AKM_SUITE_FT_PSK) +#define IS_AKM_SUITE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_8021X || \ + sec->wpa_auth == WLAN_AKM_SUITE_FT_PSK) +#elif defined(WLAN_AKM_SUITE_FT_8021X) +#define IS_AKM_SUITE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_8021X) +#elif defined(WLAN_AKM_SUITE_FT_PSK) +#define IS_AKM_SUITE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_PSK) +#else +#define IS_AKM_SUITE_FT(sec) false +#endif /* WLAN_AKM_SUITE_FT_8021X && WLAN_AKM_SUITE_FT_PSK */ +#else +#define IS_AKM_SUITE_FT(sec) false +#endif /* WLFBT */ + +#ifdef BCMCCX +#define IS_AKM_SUITE_CCKM(sec) (sec->wpa_auth == WLAN_AKM_SUITE_CCKM) +#else +#define IS_AKM_SUITE_CCKM(sec) false +#endif /* BCMCCX */ + +extern s32 wl_cfg80211_attach(struct net_device *ndev, void *context); +extern s32 wl_cfg80211_attach_post(struct net_device *ndev); +extern void wl_cfg80211_detach(void *para); + +extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, + void *data); +void wl_cfg80211_set_parent_dev(void *dev); +struct device *wl_cfg80211_get_parent_dev(void); + +extern s32 wl_cfg80211_up(void *para); +extern s32 wl_cfg80211_down(void *para); +extern s32 wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx); +extern s32 wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx); +extern s32 wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx); +extern struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, + uint8 *mac, uint8 bssidx); +extern int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev); +extern int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev); +extern int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev); +extern bool wl_cfg80211_is_vsdb_mode(void); +extern void* wl_cfg80211_get_dhdp(void); +extern bool wl_cfg80211_is_p2p_active(void); +extern void wl_cfg80211_dbg_level(u32 level); +extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); +extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len); +extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); +extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, + enum wl_management_type type); +extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); + +/* btcoex functions */ +void* wl_cfg80211_btcoex_init(struct net_device *ndev); +void wl_cfg80211_btcoex_deinit(void); + +#ifdef WL_SUPPORT_AUTO_CHANNEL +#define CHANSPEC_BUF_SIZE 1024 +#define CHAN_SEL_IOCTL_DELAY 300 +#define CHAN_SEL_RETRY_COUNT 15 +#define CHANNEL_IS_RADAR(channel) (((channel & WL_CHAN_RADAR) || \ + (channel & WL_CHAN_PASSIVE)) ? true : false) +#define CHANNEL_IS_2G(channel) (((channel >= 1) && (channel <= 14)) ? \ + true : false) +#define CHANNEL_IS_5G(channel) (((channel >= 36) && (channel <= 165)) ? \ + true : false) +extern s32 wl_cfg80211_get_best_channels(struct net_device *dev, char* command, + int total_len); +#endif /* WL_SUPPORT_AUTO_CHANNEL */ + +extern int wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n); +extern int wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str); +extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); +extern s32 wl_mode_to_nl80211_iftype(s32 mode); +int wl_cfg80211_do_driver_init(struct net_device *net); +void wl_cfg80211_enable_trace(bool set, u32 level); +extern s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify); +extern s32 wl_cfg80211_if_is_group_owner(void); +extern chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec); +extern chanspec_t wl_ch_host_to_driver(u16 channel); +extern s32 wl_set_tx_power(struct net_device *dev, + enum nl80211_tx_power_setting type, s32 dbm); +extern s32 wl_get_tx_power(struct net_device *dev, s32 *dbm); +extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); +extern void wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev); +extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set); +extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, + struct bcm_cfg80211 *cfg, wl_eventmsg_buf_t *ev); +extern void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac); +extern void wl_cfg80211_update_power_mode(struct net_device *dev); +#define SCAN_BUF_CNT 2 +#define SCAN_BUF_NEXT 1 +#define WL_SCANTYPE_LEGACY 0x1 +#define WL_SCANTYPE_P2P 0x2 +#define wl_escan_set_sync_id(a, b) ((a) = htod16(0x1234)) +#define wl_escan_set_type(a, b) +#define wl_escan_get_buf(a, b) ((wl_scan_results_t *) (a)->escan_info.escan_buf) +#define wl_escan_check_sync_id(a, b, c) 0 +#define wl_escan_print_sync_id(a, b, c) +#define wl_escan_increment_sync_id(a, b) +#define wl_escan_init_sync_id(a) + +extern void wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len); +extern s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev); +#ifdef WLAIBSS +extern void wl_cfg80211_set_txfail_pid(int pid); +#endif /* WLAIBSS */ +extern void wl_cfg80211_set_rmc_pid(int pid); + +#ifdef WLFBT +extern void wl_cfg80211_get_fbt_key(uint8 *key); +#endif + +/* Action frame specific functions */ +extern u8 wl_get_action_category(void *frame, u32 frame_len); +extern int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action); + +extern int wl_cfg80211_enable_roam_offload(struct net_device *dev, bool enable); +#ifdef WL_NAN +extern int wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd, + int cmd_len); +#endif /* WL_NAN */ + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +struct net_device *wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +extern int wl_cfg80211_get_ioctl_version(void); + +#define RETURN_EIO_IF_NOT_UP(wlpriv) \ + do { \ + struct net_device *checkSysUpNDev = bcmcfg_to_prmry_ndev(wlpriv); \ + if (unlikely(!wl_get_drv_status(wlpriv, READY, checkSysUpNDev))) { \ + WL_INFO(("device is not ready\n")); \ + return -EIO; \ + } \ + } while (0) + +#endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c new file mode 100644 index 000000000000..9ed1748463ab --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c @@ -0,0 +1,551 @@ +/* + * Linux cfg80211 driver - Dongle Host Driver (DHD) related + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg_btcoex.c 701450 2017-05-25 02:10:23Z $ + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PKT_FILTER_SUPPORT +extern uint dhd_pkt_filter_enable; +extern uint dhd_master_mode; +extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); +#endif + +struct btcoex_info { + struct timer_list timer; + u32 timer_ms; + u32 timer_on; + u32 ts_dhcp_start; /* ms ts ecord time stats */ + u32 ts_dhcp_ok; /* ms ts ecord time stats */ + bool dhcp_done; /* flag, indicates that host done with + * dhcp before t1/t2 expiration + */ + s32 bt_state; + struct work_struct work; + struct net_device *dev; +}; + +static struct btcoex_info *btcoex_info_loc = NULL; + +/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ + +/* use New SCO/eSCO smart YG suppression */ +#define BT_DHCP_eSCO_FIX +/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ +#define BT_DHCP_USE_FLAGS +/* T1 start SCO/ESCo priority suppression */ +#define BT_DHCP_OPPR_WIN_TIME 2500 +/* T2 turn off SCO/SCO supperesion is (timeout) */ +#define BT_DHCP_FLAG_FORCE_TIME 5500 + +enum wl_cfg80211_btcoex_status { + BT_DHCP_IDLE, + BT_DHCP_START, + BT_DHCP_OPPR_WIN, + BT_DHCP_FLAG_FORCE_TIMEOUT +}; + +/* + * get named driver variable to uint register value and return error indication + * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) + */ +static int +dev_wlc_intvar_get_reg(struct net_device *dev, char *name, + uint reg, int *retval) +{ + union { + char buf[WLC_IOCTL_SMLEN]; + int val; + } var; + int error; + + memset(&var, 0, sizeof(var)); + error = bcm_mkiovar(name, (char *)(®), sizeof(reg), (char *)(&var), sizeof(var.buf)); + if (error == 0) { + return BCME_BUFTOOSHORT; + } + error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); + + *retval = dtoh32(var.val); + return (error); +} + +static int +dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) +{ + char ioctlbuf_local[WLC_IOCTL_SMLEN]; + int ret; + + memset(ioctlbuf_local, 0, sizeof(ioctlbuf_local)); + ret = bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); + if (ret == 0) + return BCME_BUFTOOSHORT; + return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); +} +/* +get named driver variable to uint register value and return error indication +calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) +*/ +static int +dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) +{ + char reg_addr[8]; + + memset(reg_addr, 0, sizeof(reg_addr)); + memcpy((char *)®_addr[0], (char *)addr, 4); + memcpy((char *)®_addr[4], (char *)val, 4); + + return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); +} + +static bool btcoex_is_sco_active(struct net_device *dev) +{ + int ioc_res = 0; + bool res = FALSE; + int sco_id_cnt = 0; + int param27; + int i; + + for (i = 0; i < 12; i++) { + + ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); + + WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27)); + + if (ioc_res < 0) { + WL_ERR(("ioc read btc params error\n")); + break; + } + + if ((param27 & 0x6) == 2) { /* count both sco & esco */ + sco_id_cnt++; + } + + if (sco_id_cnt > 2) { + WL_TRACE(("sco/esco detected, pkt id_cnt:%d samples:%d\n", + sco_id_cnt, i)); + res = TRUE; + break; + } + + OSL_SLEEP(5); + } + + return res; +} + +#if defined(BT_DHCP_eSCO_FIX) +/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ +static int set_btc_esco_params(struct net_device *dev, bool trump_sco) +{ + static bool saved_status = FALSE; + + char buf_reg50va_dhcp_on[8] = + { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; + char buf_reg51va_dhcp_on[8] = + { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg64va_dhcp_on[8] = + { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg65va_dhcp_on[8] = + { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg71va_dhcp_on[8] = + { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + uint32 regaddr; + static uint32 saved_reg50; + static uint32 saved_reg51; + static uint32 saved_reg64; + static uint32 saved_reg65; + static uint32 saved_reg71; + + if (trump_sco) { + /* this should reduce eSCO agressive retransmit + * w/o breaking it + */ + + /* 1st save current */ + WL_TRACE(("Do new SCO/eSCO coex algo {save &" + "override}\n")); + if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { + saved_status = TRUE; + WL_TRACE(("saved bt_params[50,51,64,65,71]:" + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + saved_reg50, saved_reg51, + saved_reg64, saved_reg65, saved_reg71)); + } else { + WL_ERR((":%s: save btc_params failed\n", + __FUNCTION__)); + saved_status = FALSE; + return -1; + } + + WL_TRACE(("override with [50,51,64,65,71]:" + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + *(u32 *)(buf_reg50va_dhcp_on+4), + *(u32 *)(buf_reg51va_dhcp_on+4), + *(u32 *)(buf_reg64va_dhcp_on+4), + *(u32 *)(buf_reg65va_dhcp_on+4), + *(u32 *)(buf_reg71va_dhcp_on+4))); + + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg50va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg51va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg64va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg65va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg71va_dhcp_on[0], 8); + + saved_status = TRUE; + } else if (saved_status) { + /* restore previously saved bt params */ + WL_TRACE(("Do new SCO/eSCO coex algo {save &" + "override}\n")); + + regaddr = 50; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg50); + regaddr = 51; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg51); + regaddr = 64; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg64); + regaddr = 65; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg65); + regaddr = 71; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg71); + + WL_TRACE(("restore bt_params[50,51,64,65,71]:" + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + saved_reg50, saved_reg51, saved_reg64, + saved_reg65, saved_reg71)); + + saved_status = FALSE; + } else { + WL_ERR((":%s att to restore not saved BTCOEX params\n", + __FUNCTION__)); + return -1; + } + return 0; +} +#endif /* BT_DHCP_eSCO_FIX */ + +static void +wl_cfg80211_bt_setflag(struct net_device *dev, bool set) +{ +#if defined(BT_DHCP_USE_FLAGS) + char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; + char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; +#endif + + +#if defined(BT_DHCP_eSCO_FIX) + /* set = 1, save & turn on 0 - off & restore prev settings */ + set_btc_esco_params(dev, set); +#endif + +#if defined(BT_DHCP_USE_FLAGS) + WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); + if (set == TRUE) + /* Forcing bt_flag7 */ + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_dhcp_on[0], + sizeof(buf_flag7_dhcp_on)); + else + /* Restoring default bt flag7 */ + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_default[0], + sizeof(buf_flag7_default)); +#endif +} + +static void wl_cfg80211_bt_timerfunc(ulong data) +{ + struct btcoex_info *bt_local = (struct btcoex_info *)data; + WL_TRACE(("Enter\n")); + bt_local->timer_on = 0; + schedule_work(&bt_local->work); +} + +static void wl_cfg80211_bt_handler(struct work_struct *work) +{ + struct btcoex_info *btcx_inf; + + btcx_inf = container_of(work, struct btcoex_info, work); + + if (btcx_inf->timer_on) { + btcx_inf->timer_on = 0; + del_timer_sync(&btcx_inf->timer); + } + + switch (btcx_inf->bt_state) { + case BT_DHCP_START: + /* DHCP started + * provide OPPORTUNITY window to get DHCP address + */ + WL_TRACE(("bt_dhcp stm: started \n")); + + btcx_inf->bt_state = BT_DHCP_OPPR_WIN; + mod_timer(&btcx_inf->timer, + jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); + btcx_inf->timer_on = 1; + break; + + case BT_DHCP_OPPR_WIN: + if (btcx_inf->dhcp_done) { + WL_TRACE(("DHCP Done before T1 expiration\n")); + goto btc_coex_idle; + } + + /* DHCP is not over yet, start lowering BT priority + * enforce btc_params + flags if necessary + */ + WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME)); + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); + btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; + mod_timer(&btcx_inf->timer, + jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); + btcx_inf->timer_on = 1; + break; + + case BT_DHCP_FLAG_FORCE_TIMEOUT: + if (btcx_inf->dhcp_done) { + WL_TRACE(("DHCP Done before T2 expiration\n")); + } else { + /* Noo dhcp during T1+T2, restore BT priority */ + WL_TRACE(("DHCP wait interval T2:%d msec expired\n", + BT_DHCP_FLAG_FORCE_TIME)); + } + + /* Restoring default bt priority */ + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); +btc_coex_idle: + btcx_inf->bt_state = BT_DHCP_IDLE; + btcx_inf->timer_on = 0; + break; + + default: + WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state)); + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); + btcx_inf->bt_state = BT_DHCP_IDLE; + btcx_inf->timer_on = 0; + break; + } + + net_os_wake_unlock(btcx_inf->dev); +} + +void* wl_cfg80211_btcoex_init(struct net_device *ndev) +{ + struct btcoex_info *btco_inf = NULL; + + btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); + if (!btco_inf) + return NULL; + + btco_inf->bt_state = BT_DHCP_IDLE; + btco_inf->ts_dhcp_start = 0; + btco_inf->ts_dhcp_ok = 0; + /* Set up timer for BT */ + btco_inf->timer_ms = 10; + init_timer(&btco_inf->timer); + btco_inf->timer.data = (ulong)btco_inf; + btco_inf->timer.function = wl_cfg80211_bt_timerfunc; + + btco_inf->dev = ndev; + + INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); + + btcoex_info_loc = btco_inf; + return btco_inf; +} + +void wl_cfg80211_btcoex_deinit() +{ + if (!btcoex_info_loc) + return; + + if (btcoex_info_loc->timer_on) { + btcoex_info_loc->timer_on = 0; + del_timer_sync(&btcoex_info_loc->timer); + } + + cancel_work_sync(&btcoex_info_loc->work); + + kfree(btcoex_info_loc); +} + +int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command) +{ + + struct btcoex_info *btco_inf = btcoex_info_loc; + char powermode_val = 0; + char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; + char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; + char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; + + uint32 regaddr; + static uint32 saved_reg66; + static uint32 saved_reg41; + static uint32 saved_reg68; + static bool saved_status = FALSE; + + char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; + + /* Figure out powermode 1 or o command */ + strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); + + if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { + WL_TRACE_HW4(("DHCP session starts\n")); + + +#ifdef PKT_FILTER_SUPPORT + dhd->dhcp_in_progress = 1; + + if (dhd->early_suspended) { + WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n")); + dhd_enable_packet_filter(0, dhd); + } +#endif + + /* Retrieve and saved orig regs value */ + if ((saved_status == FALSE) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { + saved_status = TRUE; + WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", + saved_reg66, saved_reg41, saved_reg68)); + + /* Disable PM mode during dhpc session */ + + /* Disable PM mode during dhpc session */ + /* Start BT timer only for SCO connection */ + if (btcoex_is_sco_active(dev)) { + /* btc_params 66 */ + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg66va_dhcp_on[0], + sizeof(buf_reg66va_dhcp_on)); + /* btc_params 41 0x33 */ + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg41va_dhcp_on[0], + sizeof(buf_reg41va_dhcp_on)); + /* btc_params 68 0x190 */ + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg68va_dhcp_on[0], + sizeof(buf_reg68va_dhcp_on)); + saved_status = TRUE; + + btco_inf->bt_state = BT_DHCP_START; + btco_inf->timer_on = 1; + mod_timer(&btco_inf->timer, btco_inf->timer.expires); + WL_TRACE(("enable BT DHCP Timer\n")); + } + } + else if (saved_status == TRUE) { + WL_ERR(("was called w/o DHCP OFF. Continue\n")); + } + } + else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { + + + +#ifdef PKT_FILTER_SUPPORT + dhd->dhcp_in_progress = 0; + WL_TRACE_HW4(("DHCP is complete \n")); + + /* Enable packet filtering */ + if (dhd->early_suspended) { + WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); + dhd_enable_packet_filter(1, dhd); + } +#endif /* PKT_FILTER_SUPPORT */ + + /* Restoring PM mode */ + + /* Stop any bt timer because DHCP session is done */ + WL_TRACE(("disable BT DHCP Timer\n")); + if (btco_inf->timer_on) { + btco_inf->timer_on = 0; + del_timer_sync(&btco_inf->timer); + + if (btco_inf->bt_state != BT_DHCP_IDLE) { + /* need to restore original btc flags & extra btc params */ + WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state)); + /* wake up btcoex thread to restore btlags+params */ + schedule_work(&btco_inf->work); + } + } + + /* Restoring btc_flag paramter anyway */ + if (saved_status == TRUE) + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); + + /* Restore original values */ + if (saved_status == TRUE) { + regaddr = 66; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg66); + regaddr = 41; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg41); + regaddr = 68; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg68); + + WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", + saved_reg66, saved_reg41, saved_reg68)); + } + saved_status = FALSE; + + } + else { + WL_ERR(("Unkwown yet power setting, ignored\n")); + } + + snprintf(command, 3, "OK"); + + return (strlen("OK")); +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c new file mode 100644 index 000000000000..723211896d50 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c @@ -0,0 +1,1856 @@ +/* + * Neighbor Awareness Networking + * + * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgnan.c 487532 2014-06-26 05:09:36Z $ + */ + +/** + * @file + * @brief + * NAN (Neighbor Awareness Networking) is to provide a low-power mechanism + * that will run in the background to make the devices neighbor aware. NAN + * enables mobile devices to efficiently discover devices and services in + * their proximity. The purpose of NAN is only to discover device and its + * services. Then it is handed over to post NAN discovery and connection + * is established using the actual service data channel (e.g., WLAN + * infrastructure, P2P, IBSS, etc.) + */ + + +#include +#include +#include +#include + +#include +#include +#include + +#ifdef WL_NAN_DEBUG +static u8 g_nan_debug = true; +#else +static u8 g_nan_debug = false; +#endif /* WL_NAN_DEBUG */ + +static nan_cmd_t nan_cmds [] = { + { "NAN_START", wl_cfgnan_start_handler }, + { "NAN_STOP", wl_cfgnan_stop_handler }, + { "NAN_SUPPORT", wl_cfgnan_support_handler }, + { "NAN_STATUS", wl_cfgnan_status_handler }, + { "NAN_PUBLISH", wl_cfgnan_pub_handler }, + { "NAN_SUBSCRIBE", wl_cfgnan_sub_handler }, + { "NAN_CANCEL_PUBLISH", wl_cfgnan_cancel_pub_handler }, + { "NAN_CANCEL_SUBSCRIBE", wl_cfgnan_cancel_sub_handler }, + { "NAN_TRANSMIT", wl_cfgnan_transmit_handler }, + { "NAN_SET_CONFIG", wl_cfgnan_set_config_handler }, + { "NAN_GET_CONFIG", NULL }, + { "NAN_RTT_CONFIG", wl_cfgnan_rtt_config_handler }, + { "NAN_RTT_FIND", wl_cfgnan_rtt_find_handler }, + { "NAN_DEBUG", wl_cfgnan_debug_handler }, + { NULL, NULL }, +}; + +static nan_config_attr_t nan_config_attrs [] = { + { "ATTR_MASTER", WL_NAN_XTLV_MASTER_PREF }, + { "ATTR_ID", WL_NAN_XTLV_CLUSTER_ID }, + { "ATTR_ADDR", WL_NAN_XTLV_IF_ADDR }, + { "ATTR_ROLE", WL_NAN_XTLV_ROLE }, + { "ATTR_BCN_INT", WL_NAN_XTLV_BCN_INTERVAL }, + { "ATTR_CHAN", WL_NAN_XTLV_MAC_CHANSPEC }, + { "ATTR_TX_RATE", WL_NAN_XTLV_MAC_TXRATE }, + { "ATTR_DW_LEN", WL_NAN_XTLV_DW_LEN }, + { {0}, 0 } +}; + +static char nan_event_str[][NAN_EVENT_STR_MAX_LEN] = { + "NAN-INVALID", + "NAN-STARTED", + "NAN-JOINED", + "NAN-ROLE-CHANGE", + "NAN-SCAN-COMPLETE", + "NAN-SDF-RX", + "NAN-REPLIED", + "NAN-TERMINATED", + "NAN-FOLLOWUP-RX", + "NAN-STATUS-CHANGE", + "NAN-MERGED", + "NAN-STOPPED" + "NAN-INVALID", +}; + +static char nan_event_name[][NAN_EVENT_NAME_MAX_LEN] = { + "WL_NAN_EVENT_INVALID", + "WL_NAN_EVENT_START", + "WL_NAN_EVENT_JOIN", + "WL_NAN_EVENT_ROLE", + "WL_NAN_EVENT_SCAN_COMPLETE", + "WL_NAN_EVENT_DISCOVERY_RESULT", + "WL_NAN_EVENT_REPLIED", + "WL_NAN_EVENT_TERMINATED", + "WL_NAN_EVENT_RECEIVE", + "WL_NAN_EVENT_STATUS_CHG", + "WL_NAN_EVENT_MERGE", + "WL_NAN_EVENT_STOP", + "WL_NAN_EVENT_INVALID" +}; + +int +wl_cfgnan_set_vars_cbfn(void *ctx, uint8 *buf, uint16 type, uint16 len) +{ + wl_nan_tlv_data_t *ndata = ((wl_nan_tlv_data_t *)(ctx)); + int ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + WL_DBG((" enter, xtlv_type: 0x%x \n", type)); + + switch (type) { + case WL_NAN_XTLV_ENABLE: + memcpy(&ndata->enabled, buf, len); + break; + case WL_NAN_XTLV_MASTER_PREF: + /* + * master role and preference mac has them as two u8's, + * + * masterpref: val & 0x0ff + * rnd_factor: val >> 8 + */ + memcpy(&ndata->master_pref, buf, len); + break; + case WL_NAN_XTLV_IF_ADDR: + memcpy(&ndata->mac_addr, buf, len); + break; + case WL_NAN_XTLV_CLUSTER_ID: + memcpy(&ndata->clus_id, buf, len); + break; + case WL_NAN_XTLV_ROLE: + /* nan device role, master, master-sync nosync etc */ + memcpy(&ndata->dev_role, buf, len); + break; + case WL_NAN_XTLV_MAC_CHANSPEC: + memcpy(&ndata->chanspec, buf, len); + if (wf_chspec_valid(ndata->chanspec)) { + wf_chspec_ntoa(ndata->chanspec, buf); + WL_DBG((" chanspec: %s 0x%x \n", buf, ndata->chanspec)); + } else { + WL_DBG((" chanspec: 0x%x is not valid \n", ndata->chanspec)); + } + break; + case WL_NAN_XTLV_MAC_AMR: + memcpy(&ndata->amr, buf, len); + break; + case WL_NAN_XTLV_MAC_AMBTT: + memcpy(&ndata->ambtt, buf, len); + break; + case WL_NAN_XTLV_MAC_HOPCNT: + memcpy(&ndata->hop_count, buf, len); + break; + case WL_NAN_XTLV_INSTANCE_ID: + memcpy(&ndata->inst_id, buf, len); + break; + case WL_NAN_XTLV_SVC_NAME: + memcpy(&ndata->svc_name, buf, len); + break; + case WL_NAN_XTLV_SVC_PARAMS: + memcpy(&ndata->params, buf, len); + break; + case WL_NAN_XTLV_MAC_STATUS: + memcpy(&ndata->nstatus, buf, len); + break; + case WL_NAN_XTLV_PUBLR_ID: + memcpy(&ndata->pub_id, buf, len); + break; + case WL_NAN_XTLV_SUBSCR_ID: + memcpy(&ndata->sub_id, buf, len); + break; + case WL_NAN_XTLV_MAC_ADDR: + memcpy(&ndata->mac_addr, buf, len); + break; + case WL_NAN_XTLV_VNDR: + ndata->vend_info.dlen = len; + ndata->vend_info.data = kzalloc(ndata->vend_info.dlen, kflags); + if (!ndata->vend_info.data) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + if (ndata->vend_info.data && ndata->vend_info.dlen) { + memcpy(ndata->vend_info.data, buf, len); + } + break; + case WL_NAN_XTLV_SVC_INFO: + ndata->svc_info.dlen = len; + ndata->svc_info.data = kzalloc(ndata->svc_info.dlen, kflags); + if (!ndata->svc_info.data) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + if (ndata->svc_info.data && ndata->svc_info.dlen) { + memcpy(&ndata->svc_info.data, buf, len); + } + break; + case WL_NAN_XTLV_PEER_INSTANCE_ID: + memcpy(&ndata->peer_inst_id, buf, len); + break; + case WL_NAN_XTLV_NAN_SCANPARAMS: + memcpy(&ndata->scan_params, buf, len); + break; + case WL_NAN_XTLV_ZERO: + /* don't parse empty space in the buffer */ + ret = BCME_ERROR; + break; + + default: + break; + } + +fail: + return ret; +} + +int +wl_cfgnan_enable_events(struct net_device *ndev, struct bcm_cfg80211 *cfg) +{ + wl_nan_ioc_t *nanioc = NULL; + uint8 *pxtlv; + u32 event_mask = 0; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + ret = wl_add_remove_eventmsg(ndev, WLC_E_NAN, true); + if (unlikely(ret)) { + WL_ERR((" nan event enable failed, error = %d \n", ret)); + goto fail; + } + if (g_nan_debug) { + /* enable all nan events */ + event_mask = NAN_EVENT_MASK_ALL; + } else { + /* enable only selected nan events to avoid unnecessary host wake up */ + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_START); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_JOIN); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_DISCOVERY_RESULT); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_RECEIVE); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_TERMINATED); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_STOP); + event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_CLEAR_BIT); + event_mask = htod32(event_mask); + } + + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_EVENT_MASK); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_EVENT_MASK, + sizeof(event_mask), &event_mask, BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan event selective enable failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan event selective enable successful \n")); + } + + ret = wl_add_remove_eventmsg(ndev, WLC_E_PROXD, true); + if (unlikely(ret)) { + WL_ERR((" proxd event enable failed, error = %d \n", ret)); + goto fail; + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_enable_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + uint8 *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + uint8 val; + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan 1 + * + * wpa_cli: DRIVER NAN_ENABLE + */ + + /* nan enable */ + val = 1; + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_ENABLE); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE, + sizeof(val), &val, BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan enable failed, error = %d \n", ret)); + goto fail; + } else { + cfg->nan_enable = true; + WL_DBG((" nan enable successful \n")); + } + + /* enable nan events */ + ret = wl_cfgnan_enable_events(ndev, cfg); + if (unlikely(ret)) { + goto fail; + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_start_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + struct ether_addr cluster_id = ether_null; + uint8 *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + uint8 val; + + if (cfg->nan_enable != true) { + ret = wl_cfgnan_enable_handler(ndev, cfg, cmd, cmd_data); + if (unlikely(ret)) { + goto fail; + } + } + + /* + * command to test + * + * wl: wl nan join -start + * + * wpa_cli: DRIVER NAN_START + */ + + /* nan join */ + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + val = 1; + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_NAN_JOIN); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, + ETHER_ADDR_LEN, &cluster_id, BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_START, + sizeof(val), &val, BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan join failed, error = %d \n", ret)); + goto fail; + } + + WL_DBG((" nan join successful \n")); + cfg->nan_running = true; + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_stop_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + struct ether_addr cluster_id = ether_null; + uint8 *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + uint8 nan_enable = FALSE; + + /* + * command to test + * + * wl: wl nan stop + * wl nan 0 + * + * wpa_cli: DRIVER NAN_STOP + */ + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + if (cfg->nan_running == true) { + /* nan stop */ + + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_STOP); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, + ETHER_ADDR_LEN, &cluster_id, BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan stop failed, error = %d \n", ret)); + goto fail; + } else { + cfg->nan_running = false; + WL_DBG((" nan stop successful \n")); + } + } + + /* nan disable */ + if (cfg->nan_enable == true) { + memset(nanioc, 0, nanioc_size); + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_ENABLE); + pxtlv = nanioc->data; + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE, + sizeof(nan_enable), &nan_enable, BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan disable failed, error = %d \n", ret)); + goto fail; + } else { + cfg->nan_enable = false; + WL_DBG((" nan disable successful \n")); + } + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_support_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + uint8 *pxtlv; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan + * + * wpa_cli: DRIVER NAN_SUPPORT + */ + + /* nan support */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_ENABLE); + pxtlv = nanioc->data; + nanioc->len = htod16(BCM_XTLV_HDR_SIZE + 1); + nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); + ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); + if (unlikely(ret)) { + WL_ERR((" nan is not supported, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan is supported \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_status_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + wl_nan_ioc_t *ioc_ret = NULL; + void *pxtlv; + char *ptr = cmd; + wl_nan_tlv_data_t tlv_data; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan status + * + * wpa_cli: DRIVER NAN_STATUS + */ + + /* nan status */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_STATUS); + pxtlv = nanioc->data; + nanioc->len = NAN_IOCTL_BUF_SIZE; + nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); + ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan status failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan status successful \n")); + } + + /* unpack the tlvs */ + memset(&tlv_data, 0, sizeof(tlv_data)); + ioc_ret = (wl_nan_ioc_t *)cfg->ioctl_buf; + if (g_nan_debug) { + prhex(" nanioc->data: ", (uint8 *)ioc_ret->data, ioc_ret->len); + } + bcm_unpack_xtlv_buf(&tlv_data, ioc_ret->data, ioc_ret->len, + BCM_XTLV_OPTION_ALIGN32, wl_cfgnan_set_vars_cbfn); + + ptr += sprintf(ptr, ROLE_PREFIX"%d", tlv_data.dev_role); + ptr += sprintf(ptr, " " AMR_PREFIX); + ptr += bcm_format_hex(ptr, tlv_data.amr, NAN_MASTER_RANK_LEN); + ptr += sprintf(ptr, " " CLUS_ID_PREFIX MACF, ETHER_TO_MACF(tlv_data.clus_id)); + ptr += sprintf(ptr, " " AMBTT_PREFIX"0x%x", tlv_data.ambtt); + ptr += sprintf(ptr, " " HOP_COUNT_PREFIX"%d", tlv_data.hop_count); + + /* nan scan param */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_SCAN_PARAMS); + pxtlv = nanioc->data; + nanioc->len = NAN_IOCTL_BUF_SIZE; + nanioc_size = sizeof(wl_nan_ioc_t) + sizeof(bcm_xtlv_t); + ret = wldev_iovar_getbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan scan params failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan scan params successful \n")); + } + + /* unpack the tlvs */ + memset(&tlv_data, 0, sizeof(tlv_data)); + ioc_ret = (wl_nan_ioc_t *)cfg->ioctl_buf; + ASSERT(ioc_ret != NULL); + if (g_nan_debug) { + prhex(" nanioc->data: ", (uint8 *)ioc_ret->data, ioc_ret->len); + } + bcm_unpack_xtlv_buf(&tlv_data, ioc_ret->data, ioc_ret->len, + BCM_XTLV_OPTION_ALIGN32, wl_cfgnan_set_vars_cbfn); + + ptr += sprintf(ptr, " " SCAN_PERIOD_PREFIX"%d", + tlv_data.scan_params.ms_dur); + ptr += sprintf(ptr, " " SCAN_INTERVAL_PREFIX"%d", + tlv_data.scan_params.ms_intvl*512); + + WL_DBG((" formatted string for userspace: %s, len: %zu \n", + cmd, strlen(cmd))); + +fail: + if (nanioc) { + kfree(nanioc); + } + if (tlv_data.svc_info.data) { + kfree(tlv_data.svc_info.data); + tlv_data.svc_info.data = NULL; + tlv_data.svc_info.dlen = 0; + } + if (tlv_data.vend_info.data) { + kfree(tlv_data.vend_info.data); + tlv_data.vend_info.data = NULL; + tlv_data.vend_info.dlen = 0; + } + + return ret; +} + +/* + * packs user data (in hex string) into tlv record + * advances tlv pointer to next xtlv slot + * buflen is used for tlv_buf space check + */ +static int +get_ie_data(uchar *data_str, uchar *ie_data, int len) +{ + uchar *src, *dest; + uchar val; + int idx; + char hexstr[3]; + + src = data_str; + dest = ie_data; + + for (idx = 0; idx < len; idx++) { + hexstr[0] = src[0]; + hexstr[1] = src[1]; + hexstr[2] = '\0'; + +#ifdef BCMDRIVER + val = (uchar) simple_strtoul(hexstr, NULL, 16); +#else + val = (uchar) strtoul(hexstr, NULL, 16); +#endif + + *dest++ = val; + src += 2; + } + + return 0; +} + +int +wl_cfgnan_pub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + wl_nan_disc_params_t params; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + uint8 *pxtlv; + u16 start, end; + uchar *buf = NULL; + + /* + * proceed only if mandatory arguments are present - publisher id, + * service hash + */ + if ((!cmd_data->pub_id) || (!cmd_data->svc_hash.data) || + (!cmd_data->svc_hash.dlen)) { + WL_ERR((" mandatory arguments are not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan publish 10 NAN123 -info + * DRIVER NAN_PUBLISH PUB_ID=10 SVC_HASH=NAN123 + * SVC_INFO= PUB_PR=1 PUB_INT=0xffffffff + */ + + /* nan publish */ + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_PUBLISH); + pxtlv = nanioc->data; + + /* disovery parameters */ + if (cmd_data->pub_pr) { + params.period = cmd_data->pub_pr; + } else { + params.period = 1; + } + if (cmd_data->pub_int) { + params.ttl = cmd_data->pub_int; + } else { + params.ttl = WL_NAN_TTL_UNTIL_CANCEL; + } + params.flags = 0; + if (cmd_data->flags & WL_NAN_PUB_UNSOLICIT) { + params.flags |= WL_NAN_PUB_UNSOLICIT; + WL_DBG((" nan publish type - unsolicited\n")); + } + if (cmd_data->flags & WL_NAN_PUB_SOLICIT) { + params.flags |= WL_NAN_PUB_SOLICIT; + WL_DBG((" nan publish type - solicited\n")); + } + if (!params.flags) { + params.flags = WL_NAN_PUB_BOTH; /* default. */ + } + params.instance_id = (wl_nan_instance_id_t)cmd_data->pub_id; + memcpy((char *)params.svc_hash, cmd_data->svc_hash.data, + cmd_data->svc_hash.dlen); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_SVC_PARAMS, + sizeof(params), ¶ms, BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { + uint16 len = cmd_data->svc_info.dlen/2; + + WL_DBG((" optional svc_info present, pack it \n")); + buf = kzalloc(len, kflags); + if (!buf) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + if (get_ie_data((uchar*)cmd_data->svc_info.data, buf, len)) { + goto fail; + } + + ret = bcm_pack_xtlv_entry(&pxtlv, + &end, WL_NAN_XTLV_SVC_INFO, len, buf, BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + } + + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan publish failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan publish successful \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + if (buf) { + kfree(buf); + } + + return ret; +} + +int +wl_cfgnan_sub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + bcm_xtlvbuf_t tbuf; + wl_nan_disc_params_t params; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + /* + * proceed only if mandatory arguments are present - subscriber id, + * service hash + */ + if ((!cmd_data->sub_id) || (!cmd_data->svc_hash.data) || + (!cmd_data->svc_hash.dlen)) { + WL_ERR((" mandatory arguments are not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + bcm_xtlv_buf_init(&tbuf, nanioc->data, + BCM_XTLV_HDR_SIZE + sizeof(params), BCM_XTLV_OPTION_ALIGN32); + + /* + * command to test + * + * wl: wl nan subscribe 10 NAN123 + * + * wpa_cli: DRIVER NAN_SUBSCRIBE SUB_ID=10 SVC_HASH=NAN123 + */ + + /* nan subscribe */ + params.period = 1; + params.ttl = WL_NAN_TTL_UNTIL_CANCEL; + params.flags = 0; + if (cmd_data->flags & WL_NAN_SUB_ACTIVE) { + params.flags = WL_NAN_SUB_ACTIVE; + WL_DBG((" nan subscribe type - Active\n")); + } + params.instance_id = (wl_nan_instance_id_t)cmd_data->sub_id; + memcpy((char *)params.svc_hash, cmd_data->svc_hash.data, + cmd_data->svc_hash.dlen); + bcm_xtlv_put_data(&tbuf, WL_NAN_XTLV_SVC_PARAMS, ¶ms, sizeof(params)); + + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_SUBSCRIBE); + nanioc->len = htod16(bcm_xtlv_buf_len(&tbuf)); + nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(&tbuf); + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan subscribe failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan subscribe successful \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_cancel_pub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + bcm_xtlvbuf_t tbuf; + wl_nan_disc_params_t params; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + /* proceed only if mandatory argument is present - publisher id */ + if (!cmd_data->pub_id) { + WL_ERR((" mandatory argument is not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + bcm_xtlv_buf_init(&tbuf, nanioc->data, + BCM_XTLV_HDR_SIZE + sizeof(params), BCM_XTLV_OPTION_ALIGN32); + + /* + * command to test + * + * wl: wl nan cancel_publish 10 + * + * wpa_cli: DRIVER NAN_CANCEL_PUBLISH PUB_ID=10 + */ + + bcm_xtlv_put_data(&tbuf, WL_NAN_XTLV_INSTANCE_ID, &cmd_data->pub_id, + sizeof(wl_nan_instance_id_t)); + + /* nan cancel publish */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_CANCEL_PUBLISH); + nanioc->len = htod16(bcm_xtlv_buf_len(&tbuf)); + nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(&tbuf); + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan cancel publish failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan cancel publish successful \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_cancel_sub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + bcm_xtlvbuf_t tbuf; + wl_nan_disc_params_t params; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + /* proceed only if mandatory argument is present - subscriber id */ + if (!cmd_data->sub_id) { + WL_ERR((" mandatory argument is not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + bcm_xtlv_buf_init(&tbuf, nanioc->data, + BCM_XTLV_HDR_SIZE + sizeof(params), BCM_XTLV_OPTION_ALIGN32); + + /* + * command to test + * + * wl: wl nan cancel_subscribe 10 + * + * wpa_cli: DRIVER NAN_CANCEL_SUBSCRIBE PUB_ID=10 + */ + + bcm_xtlv_put_data(&tbuf, WL_NAN_XTLV_INSTANCE_ID, &cmd_data->sub_id, + sizeof(wl_nan_instance_id_t)); + + /* nan cancel subscribe */ + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_CANCEL_SUBSCRIBE); + nanioc->len = htod16(bcm_xtlv_buf_len(&tbuf)); + nanioc_size = sizeof(wl_nan_ioc_t) + bcm_xtlv_buf_len(&tbuf); + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan cancel subscribe failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan cancel subscribe successful \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_transmit_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + uint8 *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + uchar *buf = NULL; + + /* + * proceed only if mandatory arguments are present - subscriber id, + * publisher id, mac address + */ + if ((!cmd_data->sub_id) || (!cmd_data->pub_id) || + ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) { + WL_ERR((" mandatory arguments are not present \n")); + return -EINVAL; + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan trasnmit -info + * + * wpa_cli: DRIVER NAN_TRANSMIT SUB_ID= PUB_ID= + * MAC_ADDR= SVC_INFO= + */ + + /* nan transmit */ + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_TRANSMIT); + pxtlv = nanioc->data; + + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_INSTANCE_ID, + sizeof(cmd_data->local_id), &cmd_data->local_id, + BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_REQUESTOR_ID, + sizeof(cmd_data->remote_id), &cmd_data->remote_id, + BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_ADDR, + ETHER_ADDR_LEN, &cmd_data->mac_addr.octet, + BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { + uint16 len = cmd_data->svc_info.dlen/2; + + WL_DBG((" optional svc_info present, pack it \n")); + buf = kzalloc(len, kflags); + if (!buf) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + if (get_ie_data((uchar*)cmd_data->svc_info.data, buf, len)) { + goto fail; + } + + ret = bcm_pack_xtlv_entry(&pxtlv, + &end, WL_NAN_XTLV_SVC_INFO, len, buf, + BCM_XTLV_OPTION_ALIGN32); + if (unlikely(ret)) { + goto fail; + } + } + + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan transmit failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan transmit successful \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + if (buf) { + kfree(buf); + } + + return ret; +} + +int +wl_cfgnan_set_config_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ioc_t *nanioc = NULL; + uint8 *pxtlv; + s32 ret = BCME_OK; + u16 start, end; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; + + if (cfg->nan_running == true) { + WL_ERR((" Stop nan (NAN_STOP) before issuing NAN_CONFIG command\n")); + return BCME_ERROR; + } + + if (cfg->nan_enable != true) { + ret = wl_cfgnan_enable_handler(ndev, cfg, cmd, cmd_data); + if (unlikely(ret)) { + goto fail; + } + } + + nanioc = kzalloc(nanioc_size, kflags); + if (!nanioc) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl nan (wl nan role 1) + * + * wpa_cli: DRIVER NAN_CONFIG_SET ATTR= ... + * + * wpa_cli: DRIVER NAN_SET_CONFIG ATTR=ATTR_ROLE ROLE=1 + */ + + /* nan set config */ + start = end = NAN_IOCTL_BUF_SIZE; + nanioc->version = htod16(WL_NAN_IOCTL_VERSION); + nanioc->id = htod16(WL_NAN_CMD_ATTR); + pxtlv = nanioc->data; + + switch (cmd_data->attr.type) { + case WL_NAN_XTLV_ROLE: + WL_DBG((" set nan ROLE = %#x\n", cmd_data->role)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ROLE, + sizeof(cmd_data->role), &cmd_data->role, + BCM_XTLV_OPTION_ALIGN32); + break; + case WL_NAN_XTLV_MASTER_PREF: + WL_DBG((" set nan MASTER PREF = %#x\n", cmd_data->master_pref)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MASTER_PREF, + sizeof(cmd_data->master_pref), &cmd_data->master_pref, + BCM_XTLV_OPTION_ALIGN32); + break; + case WL_NAN_XTLV_DW_LEN: + WL_DBG((" set nan DW LEN = %#x\n", cmd_data->dw_len)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_DW_LEN, + sizeof(cmd_data->dw_len), &cmd_data->dw_len, + BCM_XTLV_OPTION_ALIGN32); + break; + case WL_NAN_XTLV_CLUSTER_ID: + WL_DBG((" set nan CLUSTER ID ")); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, + sizeof(cmd_data->clus_id), &cmd_data->clus_id, + BCM_XTLV_OPTION_ALIGN32); + break; + case WL_NAN_XTLV_IF_ADDR: + WL_DBG((" set nan IFADDR ")); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_IF_ADDR, + sizeof(cmd_data->if_addr), &cmd_data->if_addr, + BCM_XTLV_OPTION_ALIGN32); + break; + case WL_NAN_XTLV_MAC_CHANSPEC: + WL_DBG((" set nan CHANSPEC = %#x\n", cmd_data->chanspec)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_CHANSPEC, + sizeof(cmd_data->chanspec), &cmd_data->chanspec, + BCM_XTLV_OPTION_ALIGN32); + break; + case WL_NAN_XTLV_BCN_INTERVAL: + WL_DBG((" set nan BCN_INTERVAL = %#x\n", cmd_data->beacon_int)); + ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_BCN_INTERVAL, + sizeof(cmd_data->beacon_int), &cmd_data->beacon_int, + BCM_XTLV_OPTION_ALIGN32); + break; + case WL_NAN_XTLV_MAC_TXRATE: + default: + ret = -EINVAL; + break; + } + if (unlikely(ret)) { + WL_ERR((" unsupported attribute, attr = %s (%d) \n", + cmd_data->attr.name, cmd_data->attr.type)); + goto fail; + } + + nanioc->len = start - end; + nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; + ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan set config failed, error = %d \n", ret)); + goto fail; + } else { + WL_DBG((" nan set config successful \n")); + } + +fail: + if (nanioc) { + kfree(nanioc); + } + + return ret; +} + +int +wl_cfgnan_rtt_config_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + wl_nan_ranging_config_t rtt_config; + s32 ret = BCME_OK; + + /* proceed only if mandatory argument is present - channel */ + if (!cmd_data->chanspec) { + WL_ERR((" mandatory argument is not present \n")); + return -EINVAL; + } + + /* + * command to test + * + * wl: wl proxd_nancfg 44/80 128 32 ff:ff:ff:ff:ff:ff 1 + * + * wpa_cli: DRIVER NAN_RTT_CONFIG CHAN=44/80 + */ + + memset(&rtt_config, 0, sizeof(wl_nan_ranging_config_t)); + rtt_config.chanspec = cmd_data->chanspec; + rtt_config.timeslot = 128; + rtt_config.duration = 32; + memcpy(&rtt_config.allow_mac, ðer_bcast, ETHER_ADDR_LEN); + rtt_config.flags = 1; + + ret = wldev_iovar_setbuf(ndev, "proxd_nancfg", &rtt_config, + sizeof(wl_nan_ranging_config_t), cfg->ioctl_buf, + WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan rtt config failed, error = %d \n", ret)); + } else { + WL_DBG((" nan rtt config successful \n")); + } + + return ret; +} + +int +wl_cfgnan_rtt_find_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + void *iovbuf; + wl_nan_ranging_list_t *rtt_list; + s32 iovbuf_size = NAN_RTT_IOVAR_BUF_SIZE; + s32 ret = BCME_OK; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + /* + * proceed only if mandatory arguments are present - channel, bitmap, + * mac address + */ + if ((!cmd_data->chanspec) || (!cmd_data->bmap) || + ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) { + WL_ERR((" mandatory arguments are not present \n")); + return -EINVAL; + } + + iovbuf = kzalloc(iovbuf_size, kflags); + if (!iovbuf) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + /* + * command to test + * + * wl: wl proxd_nanfind 1 44/80 0x300 5 6 1 + * + * wpa_cli: DRIVER NAN_RTT_FIND MAC_ADDR= CHAN=44/80 BMAP=0x300 + * + */ + rtt_list = (wl_nan_ranging_list_t *)iovbuf; + rtt_list->count = 1; + rtt_list->num_peers_done = 0; + rtt_list->num_dws = 1; + rtt_list->rp[0].chanspec = cmd_data->chanspec; + memcpy(&rtt_list->rp[0].ea, &cmd_data->mac_addr, + sizeof(struct ether_addr)); + rtt_list->rp[0].abitmap = cmd_data->bmap; + rtt_list->rp[0].frmcnt = 5; + rtt_list->rp[0].retrycnt = 6; + rtt_list->rp[0].flags = 1; + + iovbuf_size = sizeof(wl_nan_ranging_list_t) + + sizeof(wl_nan_ranging_peer_t); + ret = wldev_iovar_setbuf(ndev, "proxd_nanfind", iovbuf, + iovbuf_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + WL_ERR((" nan rtt find failed, error = %d \n", ret)); + } else { + WL_DBG((" nan rtt find successful \n")); + } + + if (iovbuf) { + kfree(iovbuf); + } + + return ret; +} + +int +wl_cfgnan_debug_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) +{ + /* + * command to test + * + * wpa_cli: DRIVER NAN_DEBUG DEBUG=1 + * + */ + + g_nan_debug = cmd_data->debug_flag; + + /* reconfigure nan events */ + return wl_cfgnan_enable_events(ndev, cfg); +} + +static int wl_cfgnan_config_attr(char *buf, nan_config_attr_t *attr) +{ + s32 ret = BCME_OK; + nan_config_attr_t *nanc = NULL; + + /* only one attribute at a time */ + for (nanc = &nan_config_attrs[0]; strlen(nanc->name) != 0; nanc++) { + if (!strncmp(nanc->name, buf, strlen(nanc->name))) { + strncpy((char *)attr->name, buf, strlen(nanc->name)); + attr->type = nanc->type; + ret = strlen(nanc->name); + break; + } + } + + return ret; +} + +static int wl_cfgnan_parse_args(char *buf, nan_cmd_data_t *cmd_data) +{ + s32 ret = BCME_OK; + char *token = buf; + char delim[] = " "; + + while ((buf != NULL) && (token != NULL)) { + if (!strncmp(buf, PUB_ID_PREFIX, strlen(PUB_ID_PREFIX))) { + buf += strlen(PUB_ID_PREFIX); + token = strsep(&buf, delim); + cmd_data->pub_id = simple_strtoul(token, NULL, 10); + if (NAN_INVALID_ID(cmd_data->pub_id)) { + WL_ERR((" invalid publisher id, pub_id = %d \n", + cmd_data->pub_id)); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, SUB_ID_PREFIX, strlen(SUB_ID_PREFIX))) { + buf += strlen(SUB_ID_PREFIX); + token = strsep(&buf, delim); + cmd_data->sub_id = simple_strtoul(token, NULL, 10); + if (NAN_INVALID_ID(cmd_data->sub_id)) { + WL_ERR((" invalid subscriber id, sub_id = %d \n", + cmd_data->sub_id)); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, MAC_ADDR_PREFIX, strlen(MAC_ADDR_PREFIX))) { + buf += strlen(MAC_ADDR_PREFIX); + token = strsep(&buf, delim); + if (!wl_cfg80211_ether_atoe(token, &cmd_data->mac_addr)) { + WL_ERR((" invalid mac address, mac_addr = "MACDBG "\n", + MAC2STRDBG(cmd_data->mac_addr.octet))); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, SVC_HASH_PREFIX, strlen(SVC_HASH_PREFIX))) { + buf += strlen(SVC_HASH_PREFIX); + token = strsep(&buf, delim); + cmd_data->svc_hash.data = token; + cmd_data->svc_hash.dlen = WL_NAN_SVC_HASH_LEN; + } else if (!strncmp(buf, SVC_INFO_PREFIX, strlen(SVC_INFO_PREFIX))) { + buf += strlen(SVC_INFO_PREFIX); + token = strsep(&buf, delim); + cmd_data->svc_info.data = token; + cmd_data->svc_info.dlen = strlen(token); + } else if (!strncmp(buf, CHAN_PREFIX, strlen(CHAN_PREFIX))) { + buf += strlen(CHAN_PREFIX); + token = strsep(&buf, delim); + cmd_data->chanspec = wf_chspec_aton(token); + cmd_data->chanspec = wl_chspec_host_to_driver(cmd_data->chanspec); + if (NAN_INVALID_CHANSPEC(cmd_data->chanspec)) { + WL_ERR((" invalid chanspec, chanspec = 0x%04x \n", + cmd_data->chanspec)); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, BITMAP_PREFIX, strlen(BITMAP_PREFIX))) { + buf += strlen(BITMAP_PREFIX); + token = strsep(&buf, delim); + cmd_data->bmap = simple_strtoul(token, NULL, 16); + } else if (!strncmp(buf, ATTR_PREFIX, strlen(ATTR_PREFIX))) { + buf += strlen(ATTR_PREFIX); + token = strsep(&buf, delim); + if (!wl_cfgnan_config_attr(token, &cmd_data->attr)) { + WL_ERR((" invalid attribute, attr = %s \n", + cmd_data->attr.name)); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, ROLE_PREFIX, strlen(ROLE_PREFIX))) { + buf += strlen(ROLE_PREFIX); + token = strsep(&buf, delim); + cmd_data->role = simple_strtoul(token, NULL, 10); + if (NAN_INVALID_ROLE(cmd_data->role)) { + WL_ERR((" invalid role, role = %d \n", cmd_data->role)); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, MASTER_PREF_PREFIX, + strlen(MASTER_PREF_PREFIX))) { + buf += strlen(MASTER_PREF_PREFIX); + token = strsep(&buf, delim); + cmd_data->master_pref = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, CLUS_ID_PREFIX, strlen(CLUS_ID_PREFIX))) { + buf += strlen(CLUS_ID_PREFIX); + token = strsep(&buf, delim); + if (!wl_cfg80211_ether_atoe(token, &cmd_data->clus_id)) { + WL_ERR((" invalid cluster id, CLUS_ID = "MACDBG "\n", + MAC2STRDBG(cmd_data->clus_id.octet))); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, IF_ADDR_PREFIX, strlen(IF_ADDR_PREFIX))) { + buf += strlen(IF_ADDR_PREFIX); + token = strsep(&buf, delim); + if (!wl_cfg80211_ether_atoe(token, &cmd_data->if_addr)) { + WL_ERR((" invalid cluster id, IF_ADDR = "MACDBG "\n", + MAC2STRDBG(cmd_data->if_addr.octet))); + ret = -EINVAL; + goto fail; + } + } else if (!strncmp(buf, BCN_INTERVAL_PREFIX, + strlen(BCN_INTERVAL_PREFIX))) { + buf += strlen(BCN_INTERVAL_PREFIX); + token = strsep(&buf, delim); + cmd_data->beacon_int = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, PUB_PR_PREFIX, strlen(PUB_PR_PREFIX))) { + buf += strlen(PUB_PR_PREFIX); + token = strsep(&buf, delim); + cmd_data->pub_pr = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, PUB_INT_PREFIX, strlen(PUB_INT_PREFIX))) { + buf += strlen(PUB_INT_PREFIX); + token = strsep(&buf, delim); + cmd_data->pub_int = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, DW_LEN_PREFIX, strlen(DW_LEN_PREFIX))) { + buf += strlen(DW_LEN_PREFIX); + token = strsep(&buf, delim); + cmd_data->dw_len = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, DEBUG_PREFIX, strlen(DEBUG_PREFIX))) { + buf += strlen(DEBUG_PREFIX); + token = strsep(&buf, delim); + cmd_data->debug_flag = simple_strtoul(token, NULL, 10); + } else if (!strncmp(buf, ACTIVE_OPTION, strlen(ACTIVE_OPTION))) { + buf += strlen(ACTIVE_OPTION); + token = strsep(&buf, delim); + cmd_data->flags |= WL_NAN_SUB_ACTIVE; + } else if (!strncmp(buf, SOLICITED_OPTION, strlen(SOLICITED_OPTION))) { + buf += strlen(SOLICITED_OPTION); + token = strsep(&buf, delim); + cmd_data->flags |= WL_NAN_PUB_SOLICIT; + } else if (!strncmp(buf, UNSOLICITED_OPTION, strlen(UNSOLICITED_OPTION))) { + buf += strlen(UNSOLICITED_OPTION); + token = strsep(&buf, delim); + cmd_data->flags |= WL_NAN_PUB_UNSOLICIT; + } else { + WL_ERR((" unknown token, token = %s, buf = %s \n", token, buf)); + ret = -EINVAL; + goto fail; + } + } + +fail: + return ret; +} + +int +wl_cfgnan_cmd_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, + char *cmd, int cmd_len) +{ + nan_cmd_data_t cmd_data; + u8 *buf = cmd; + u8 *cmd_name = NULL; + nan_cmd_t *nanc = NULL; + int buf_len = 0; + int ret = BCME_OK; + + cmd_name = strsep((char **)&buf, " "); + if (buf) { + buf_len = strlen(buf); + } + + WL_DBG((" cmd_name: %s, buf_len: %d, buf: %s \n", cmd_name, buf_len, buf)); + + memset(&cmd_data, 0, sizeof(nan_cmd_data_t)); + ret = wl_cfgnan_parse_args(buf, &cmd_data); + if (unlikely(ret)) { + WL_ERR((" argument parsing failed with error (%d), buf = %s \n", + ret, buf)); + goto fail; + } + + for (nanc = nan_cmds; nanc->name; nanc++) { + if (strncmp(nanc->name, cmd_name, strlen(nanc->name)) == 0) { + ret = (*nanc->func)(ndev, cfg, cmd, &cmd_data); + if (ret < BCME_OK) { + WL_ERR((" command (%s) failed with error (%d) \n", + cmd_name, ret)); + } + } + } + +fail: + return ret; +} + +s32 +wl_cfgnan_notify_proxd_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data) +{ + s32 ret = BCME_OK; + wl_nan_ranging_event_data_t *rdata; + s32 status; + u16 data_len; + s32 event_type; + s32 event_num; + u8 *buf = NULL; + u32 buf_len; + u8 *ptr; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + s32 i; + + if (!event || !data) { + WL_ERR((" event data is NULL \n")); + return -EINVAL; + } + + status = ntoh32(event->reason); + event_type = ntoh32(event->event_type); + event_num = ntoh32(event->reason); + data_len = ntoh32(event->datalen); + + WL_DBG((" proxd event: type: %d num: %d len: %d \n", + event_type, event_num, data_len)); + + if (NAN_INVALID_PROXD_EVENT(event_num)) { + WL_ERR((" unsupported event, num: %d \n", event_num)); + return -EINVAL; + } + + if (g_nan_debug) { + WL_DBG((" event name: WLC_E_PROXD_NAN_EVENT \n")); + WL_DBG((" event data: \n")); + prhex(NULL, data, data_len); + } + + if (data_len < sizeof(wl_nan_ranging_event_data_t)) { + WL_ERR((" wrong data len \n")); + return -EINVAL; + } + + rdata = (wl_nan_ranging_event_data_t *)data; + + WL_DBG((" proxd event: count:%d success_count:%d mode:%d \n", + rdata->count, rdata->success_count, rdata->mode)); + + if (g_nan_debug) { + prhex(" event data: ", data, data_len); + } + + buf_len = NAN_IOCTL_BUF_SIZE; + buf = kzalloc(buf_len, kflags); + if (!buf) { + WL_ERR((" memory allocation failed \n")); + return -ENOMEM; + } + + for (i = 0; i < rdata->count; i++) { + if (&rdata->rr[i] == NULL) { + ret = -EINVAL; + goto fail; + } + + ptr = buf; + WL_DBG((" ranging data for mac:"MACDBG" \n", + MAC2STRDBG(rdata->rr[i].ea.octet))); + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " MAC_ADDR_PREFIX MACF + " "STATUS_PREFIX"%s", EVENT_RTT_STATUS_STR, + ETHER_TO_MACF(rdata->rr[i].ea), (rdata->rr[i].status == 1) ? + "success" : "fail"); + + if (rdata->rr[i].status == 1) { + /* add tsf and distance only if status is success */ + ptr += sprintf(ptr, " "TIMESTAMP_PREFIX"0x%x " + DISTANCE_PREFIX"%d.%04d", rdata->rr[i].timestamp, + rdata->rr[i].distance >> 4, + ((rdata->rr[i].distance & 0x0f) * 625)); + } + + } + +fail: + if (buf) { + kfree(buf); + } + + return ret; +} + +s32 +wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data) +{ + s32 ret = BCME_OK; + u16 data_len; + u32 event_num; + s32 event_type; + nan_event_hdr_t nan_hdr; + wl_nan_tlv_data_t tlv_data; + u8 *buf = NULL; + u32 buf_len; + u8 *ptr; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + if (!event || !data) { + WL_ERR((" event data is NULL \n")); + return -EINVAL; + } + + event_type = ntoh32(event->event_type); + event_num = ntoh32(event->reason); + data_len = ntoh32(event->datalen); + memset(&nan_hdr, 0, sizeof(nan_event_hdr_t)); + nan_hdr.event_subtype = event_num; + + WL_DBG((" nan event: type: %d num: %d len: %d \n", + event_type, event_num, data_len)); + + if (NAN_INVALID_EVENT(event_num)) { + WL_ERR((" unsupported event, num: %d \n", event_num)); + return -EINVAL; + } + + if (g_nan_debug) { + WL_DBG((" event name: %s \n", nan_event_name[event_num])); + WL_DBG((" event data: \n")); + prhex(NULL, data, data_len); + } + + /* unpack the tlvs */ + memset(&tlv_data, 0, sizeof(wl_nan_tlv_data_t)); + bcm_unpack_xtlv_buf(&tlv_data, data, data_len, + BCM_XTLV_OPTION_ALIGN32, wl_cfgnan_set_vars_cbfn); + + /* + * send as preformatted hex string + * + * EVENT_NAN + */ + + buf_len = NAN_IOCTL_BUF_SIZE; + buf = ptr = kzalloc(buf_len, kflags); + if (!buf) { + WL_ERR((" memory allocation failed \n")); + ret = -ENOMEM; + goto fail; + } + + switch (event_num) { + case WL_NAN_EVENT_START: + case WL_NAN_EVENT_JOIN: + case WL_NAN_EVENT_STOP: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, + nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; + case WL_NAN_EVENT_ROLE: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s "ROLE_PREFIX "%d " + CLUS_ID_PREFIX MACF, nan_event_str[event_num], + tlv_data.nstatus.role, ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; + case WL_NAN_EVENT_DISCOVERY_RESULT: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " + SUB_ID_PREFIX"%d " MAC_ADDR_PREFIX MACF, + nan_event_str[event_num], tlv_data.pub_id, tlv_data.sub_id, + ETHER_TO_MACF(tlv_data.mac_addr)); + if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) { + WL_DBG((" service info present \n")); + if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) { + WL_ERR((" service info length = %d\n", + tlv_data.svc_info.dlen)); + WL_ERR((" insufficent buffer to copy service info \n")); + ret = -EOVERFLOW; + goto fail; + } + ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX); + ptr += bcm_format_hex(ptr, tlv_data.svc_info.data, + tlv_data.svc_info.dlen); + } else { + WL_DBG((" service info not present \n")); + } + + if (tlv_data.vend_info.data && tlv_data.vend_info.dlen) { + struct ether_addr *ea; + u8 *temp_data = tlv_data.vend_info.data; + uint32 bitmap; + u16 dlen = tlv_data.vend_info.dlen; + chanspec_t chanspec; + uint8 mapcontrol; + uint8 proto; + + WL_DBG((" vendor info present \n")); + if ((*temp_data != NAN_ATTR_VENDOR_SPECIFIC) || + (dlen < NAN_VENDOR_HDR_SIZE)) { + WL_ERR((" error in vendor info attribute \n")); + ret = -EINVAL; + goto fail; + } else { + WL_DBG((" vendor info not present \n")); + } + + if (*(temp_data + 6) == NAN_VENDOR_TYPE_RTT) { + temp_data += NAN_VENDOR_HDR_SIZE; + ea = (struct ether_addr *)temp_data; + temp_data += ETHER_ADDR_LEN; + mapcontrol = *temp_data++; + proto = *temp_data++; + bitmap = *(uint32 *)temp_data; + temp_data += 4; + chanspec = *(chanspec_t *)temp_data; + ptr += sprintf(ptr, " "BITMAP_PREFIX"0x%x "CHAN_PREFIX"%d/%s", + bitmap, wf_chspec_ctlchan(chanspec), + wf_chspec_to_bw_str(chanspec)); + WL_DBG((" bitmap: 0x%x channel: %d bandwidth: %s \n", bitmap, + wf_chspec_ctlchan(chanspec), + wf_chspec_to_bw_str(chanspec))); + } + } + break; + case WL_NAN_EVENT_REPLIED: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " + MAC_ADDR_PREFIX MACF, nan_event_str[event_num], + tlv_data.pub_id, ETHER_TO_MACF(tlv_data.mac_addr)); + break; + case WL_NAN_EVENT_TERMINATED: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d ", + nan_event_str[event_num], tlv_data.pub_id); + break; + case WL_NAN_EVENT_RECEIVE: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d " + MAC_ADDR_PREFIX MACF, nan_event_str[event_num], + tlv_data.pub_id, ETHER_TO_MACF(tlv_data.mac_addr)); + if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) { + WL_DBG((" service info present \n")); + if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) { + WL_ERR((" service info length = %d\n", + tlv_data.svc_info.dlen)); + WL_ERR((" insufficent buffer to copy service info \n")); + ret = -EOVERFLOW; + goto fail; + } + ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX); + ptr += bcm_format_hex(ptr, tlv_data.svc_info.data, + tlv_data.svc_info.dlen); + } else { + WL_DBG((" service info not present \n")); + } + break; + case WL_NAN_EVENT_SCAN_COMPLETE: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, + nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; + case WL_NAN_EVENT_STATUS_CHG: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, + nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; + case WL_NAN_EVENT_MERGE: + ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF, + nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid)); + break; + default: + WL_ERR((" unknown event \n")); + break; + } + + +fail: + if (buf) { + kfree(buf); + } + if (tlv_data.svc_info.data) { + kfree(tlv_data.svc_info.data); + tlv_data.svc_info.data = NULL; + tlv_data.svc_info.dlen = 0; + } + if (tlv_data.vend_info.data) { + kfree(tlv_data.vend_info.data); + tlv_data.vend_info.data = NULL; + tlv_data.vend_info.dlen = 0; + } + + return ret; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h new file mode 100644 index 000000000000..44484eba1d68 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h @@ -0,0 +1,189 @@ +/* + * Neighbor Awareness Networking + * + * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgnan.h 487532 2014-06-26 05:09:36Z $ + */ + +#ifndef _wl_cfgnan_h_ +#define _wl_cfgnan_h_ + +#define NAN_IOCTL_BUF_SIZE 512 +#define NAN_EVENT_STR_MAX_LEN 30 +#define NAN_EVENT_NAME_MAX_LEN 40 +#define NAN_CONFIG_ATTR_MAX_LEN 24 +#define NAN_RTT_IOVAR_BUF_SIZE 1024 +#define WL_NAN_EVENT_CLEAR_BIT 32 +#define NAN_EVENT_MASK_ALL 0x7fffffff + +#define NAN_INVALID_ID(id) ((id > 255) ? true : false) +#define NAN_INVALID_ROLE(role) ((role > WL_NAN_ROLE_ANCHOR_MASTER) ? true : false) +#define NAN_INVALID_CHANSPEC(chanspec) ((chanspec == INVCHANSPEC) || \ + (chanspec == 0) ? true : false) +#define NAN_INVALID_EVENT(num) (((num < WL_NAN_EVENT_START) || \ + (num >= WL_NAN_EVENT_INVALID)) ? true : false) +#define NAN_INVALID_PROXD_EVENT(num) ((num != WLC_E_PROXD_NAN_EVENT) ? \ + true : false) +#define NAN_EVENT_BIT(event) (1U << (event - WL_NAN_EVENT_START)) + +#define SUPP_EVENT_PREFIX "CTRL-EVENT-" +#define EVENT_RTT_STATUS_STR "NAN-RTT-STATUS" + +#define TIMESTAMP_PREFIX "TSF=" /* timestamp */ +#define AMR_PREFIX "AMR=" /* anchor master rank */ +#define DISTANCE_PREFIX "DIST=" /* distance */ +#define ATTR_PREFIX "ATTR=" /* attribute */ +#define ROLE_PREFIX "ROLE=" /* role */ +#define CHAN_PREFIX "CHAN=" /* channel */ +#define BITMAP_PREFIX "BMAP=" /* bitmap */ +#define DEBUG_PREFIX "DEBUG=" /* debug enable/disable flag */ +#define DW_LEN_PREFIX "DW_LEN=" /* discovery window length */ +#define DW_INT_PREFIX "DW_INT=" /* discovery window interval */ +#define STATUS_PREFIX "STATUS=" /* status */ +#define PUB_ID_PREFIX "PUB_ID=" /* publisher id */ +#define SUB_ID_PREFIX "SUB_ID=" /* subscriber id */ +#define PUB_PR_PREFIX "PUB_PR=" /* publish period */ +#define PUB_INT_PREFIX "PUB_INT=" /* publish interval (ttl) */ +#define CLUS_ID_PREFIX "CLUS_ID=" /* cluster id */ +#define IF_ADDR_PREFIX "IF_ADDR=" /* IF address */ +#define MAC_ADDR_PREFIX "MAC_ADDR=" /* mac address */ +#define SVC_HASH_PREFIX "SVC_HASH=" /* service hash */ +#define SVC_INFO_PREFIX "SVC_INFO=" /* service information */ +#define HOP_COUNT_PREFIX "HOP_COUNT=" /* hop count */ +#define MASTER_PREF_PREFIX "MASTER_PREF=" /* master preference */ +#define ACTIVE_OPTION "ACTIVE" /* Active Subscribe. */ +#define SOLICITED_OPTION "SOLICITED" /* Solicited Publish. */ +#define UNSOLICITED_OPTION "UNSOLICITED" /* Unsolicited Publish. */ +/* anchor master beacon transmission time */ +#define AMBTT_PREFIX "AMBTT=" +/* passive scan period for cluster merge */ +#define SCAN_PERIOD_PREFIX "SCAN_PERIOD=" +/* passive scan interval for cluster merge */ +#define SCAN_INTERVAL_PREFIX "SCAN_INTERVAL=" +#define BCN_INTERVAL_PREFIX "BCN_INTERVAL=" + +typedef struct nan_str_data { + u8 *data; + u32 dlen; +} nan_str_data_t; + +typedef struct nan_config_attr { + char name[NAN_CONFIG_ATTR_MAX_LEN]; /* attribute name */ + u16 type; /* attribute xtlv type */ +} nan_config_attr_t; + +typedef struct nan_cmd_data { + nan_config_attr_t attr; /* set config attributes */ + nan_str_data_t svc_hash; /* service hash */ + nan_str_data_t svc_info; /* service information */ + struct ether_addr mac_addr; /* mac address */ + struct ether_addr clus_id; /* cluster id */ + struct ether_addr if_addr; /* if addr */ + u32 beacon_int; /* beacon interval */ + u32 pub_int; /* publish interval (ttl) */ + u32 pub_pr; /* publish period */ + u32 bmap; /* bitmap */ + u32 role; /* role */ + u16 pub_id; /* publisher id */ + u16 sub_id; /* subscriber id */ + uint32 flags; /* Flag bits */ + u16 dw_len; /* discovery window length */ + u16 master_pref; /* master preference */ + chanspec_t chanspec; /* channel */ + u8 debug_flag; /* debug enable/disable flag */ +} nan_cmd_data_t; + +typedef int (nan_func_t)(struct net_device *ndev, struct bcm_cfg80211 *cfg, + char *cmd, nan_cmd_data_t *cmd_data); + +typedef struct nan_cmd { + const char *name; /* command name */ + nan_func_t *func; /* command hadler */ +} nan_cmd_t; + +typedef struct nan_event_hdr { + u16 event_subtype; + u32 flags; /* future use */ +} nan_event_hdr_t; + +typedef struct wl_nan_tlv_data { + wl_nan_status_t nstatus; /* status data */ + wl_nan_disc_params_t params; /* discovery parameters */ + struct ether_addr mac_addr; /* peer mac address */ + struct ether_addr clus_id; /* cluster id */ + nan_str_data_t svc_info; /* service info */ + nan_str_data_t vend_info; /* vendor info */ + /* anchor master beacon transmission time */ + u32 ambtt; + u32 dev_role; /* device role */ + u16 inst_id; /* instance id */ + u16 pub_id; /* publisher id */ + u16 sub_id; /* subscriber id */ + u16 master_pref; /* master preference */ + chanspec_t chanspec; /* channel */ + u8 amr[NAN_MASTER_RANK_LEN]; /* anchor master role */ + u8 svc_name[WL_NAN_SVC_HASH_LEN]; /* service name */ + u8 hop_count; /* hop count */ + u8 enabled; /* nan status flag */ + nan_scan_params_t scan_params; /* scan_param */ +} wl_nan_tlv_data_t; + +extern int wl_cfgnan_set_vars_cbfn(void *ctx, uint8 *tlv_buf, + uint16 type, uint16 len); +extern int wl_cfgnan_enable_events(struct net_device *ndev, + struct bcm_cfg80211 *cfg); +extern int wl_cfgnan_start_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_stop_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_support_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_status_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_pub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_sub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_cancel_pub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_cancel_sub_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_transmit_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_set_config_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_rtt_config_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_rtt_find_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_debug_handler(struct net_device *ndev, + struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data); +extern int wl_cfgnan_cmd_handler(struct net_device *dev, + struct bcm_cfg80211 *cfg, char *cmd, int cmd_len); +extern s32 wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +extern s32 wl_cfgnan_notify_proxd_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); + +#endif /* _wl_cfgnan_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c new file mode 100644 index 000000000000..c00171f392fb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c @@ -0,0 +1,2725 @@ +/* + * Linux cfgp2p driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgp2p.c 531064 2015-02-02 07:59:42Z $ + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static s8 scanparambuf[WLC_IOCTL_SMLEN]; +static s8 g_mgmt_ie_buf[2048]; +static bool +wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); + +static u32 +wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag, + s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd); +static s32 wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, + struct wireless_dev *wdev, bool notify); + +#if defined(WL_ENABLE_P2P_IF) +static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); +static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); +static int wl_cfgp2p_if_open(struct net_device *net); +static int wl_cfgp2p_if_stop(struct net_device *net); + +static const struct net_device_ops wl_cfgp2p_if_ops = { + .ndo_open = wl_cfgp2p_if_open, + .ndo_stop = wl_cfgp2p_if_stop, + .ndo_do_ioctl = wl_cfgp2p_do_ioctl, + .ndo_start_xmit = wl_cfgp2p_start_xmit, +}; +#endif /* WL_ENABLE_P2P_IF */ + +#if defined(WL_NEWCFG_PRIVCMD_SUPPORT) +static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); +static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); + +static int wl_cfgp2p_if_dummy(struct net_device *net) +{ + return 0; +} + +static const struct net_device_ops wl_cfgp2p_if_ops = { + .ndo_open = wl_cfgp2p_if_dummy, + .ndo_stop = wl_cfgp2p_if_dummy, + .ndo_do_ioctl = wl_cfgp2p_do_ioctl, + .ndo_start_xmit = wl_cfgp2p_start_xmit, +}; +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + +bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + + if (frame == NULL) + return false; + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1) + return false; + + if (pact_frm->category == P2P_PUB_AF_CATEGORY && + pact_frm->action == P2P_PUB_AF_ACTION && + pact_frm->oui_type == P2P_VER && + memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) { + return true; + } + + return false; +} + +bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) +{ + wifi_p2p_action_frame_t *act_frm; + + if (frame == NULL) + return false; + act_frm = (wifi_p2p_action_frame_t *)frame; + if (frame_len < sizeof(wifi_p2p_action_frame_t) -1) + return false; + + if (act_frm->category == P2P_AF_CATEGORY && + act_frm->type == P2P_VER && + memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) { + return true; + } + + return false; +} + +#define GAS_RESP_LEN 2 +#define DOUBLE_TLV_BODY_OFF 4 +#define GAS_RESP_OFFSET 4 +#define GAS_CRESP_OFFSET 5 + +bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len) +{ + bcm_tlv_t *ie = (bcm_tlv_t *)data; + u8 *frame = NULL; + u16 id, flen; + + /* Skipped first ANQP Element, if frame has anqp elemnt */ + ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID); + + if (ie == NULL) + return false; + + frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN; + id = ((u16) (((frame)[1] << 8) | (frame)[0])); + flen = ((u16) (((frame)[3] << 8) | (frame)[2])); + + /* If the contents match the OUI and the type */ + if (flen >= WFA_OUI_LEN + 1 && + id == P2PSD_GAS_NQP_INFOID && + !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) && + subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) { + return true; + } + + return false; +} + +bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) +{ + + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; + + if (frame == NULL) + return false; + + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; + if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)) + return false; + if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) + return false; + + if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) + return true; + else + return false; +} +void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + wifi_p2p_action_frame_t *act_frm; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; + if (!frame || frame_len <= 2) + return; + + if (wl_cfgp2p_is_pub_action(frame, frame_len)) { + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + switch (pact_frm->subtype) { + case P2P_PAF_GON_REQ: + CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_GON_RSP: + CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_GON_CONF: + CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_INVITE_REQ: + CFGP2P_ACTION(("%s P2P Invitation Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_INVITE_RSP: + CFGP2P_ACTION(("%s P2P Invitation Response Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_DEVDIS_REQ: + CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_DEVDIS_RSP: + CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_PROVDIS_REQ: + CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_PAF_PROVDIS_RSP: + CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + default: + CFGP2P_ACTION(("%s Unknown P2P Public Action Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + + } + + } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) { + act_frm = (wifi_p2p_action_frame_t *)frame; + switch (act_frm->subtype) { + case P2P_AF_NOTICE_OF_ABSENCE: + CFGP2P_ACTION(("%s P2P Notice of Absence Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_AF_PRESENCE_REQ: + CFGP2P_ACTION(("%s P2P Presence Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_AF_PRESENCE_RSP: + CFGP2P_ACTION(("%s P2P Presence Response Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + case P2P_AF_GO_DISC_REQ: + CFGP2P_ACTION(("%s P2P Discoverability Request Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + break; + default: + CFGP2P_ACTION(("%s Unknown P2P Action Frame," + " channel=%d\n", (tx)? "TX": "RX", channel)); + } + + } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; + switch (sd_act_frm->action) { + case P2PSD_ACTION_ID_GAS_IREQ: + CFGP2P_ACTION(("%s P2P GAS Initial Request," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + break; + case P2PSD_ACTION_ID_GAS_IRESP: + CFGP2P_ACTION(("%s P2P GAS Initial Response," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + break; + case P2PSD_ACTION_ID_GAS_CREQ: + CFGP2P_ACTION(("%s P2P GAS Comback Request," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + break; + case P2PSD_ACTION_ID_GAS_CRESP: + CFGP2P_ACTION(("%s P2P GAS Comback Response," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + break; + default: + CFGP2P_ACTION(("%s Unknown P2P GAS Frame," + " channel=%d\n", (tx)? "TX" : "RX", channel)); + } + + + } +} + +/* + * Initialize variables related to P2P + * + */ +s32 +wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg) +{ + if (!(cfg->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) { + CFGP2P_ERR(("struct p2p_info allocation failed\n")); + return -ENOMEM; + } +#define INIT_IE(IE_TYPE, BSS_TYPE) \ + do { \ + memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ + sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ + wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ + } while (0); + + INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE); + INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE); + INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE); + INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE); + INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE); + INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION); +#undef INIT_IE + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg); + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0; + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = NULL; + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = 0; + return BCME_OK; + +} +/* + * Deinitialize variables related to P2P + * + */ +void +wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg) +{ + CFGP2P_DBG(("In\n")); + if (cfg->p2p) { + kfree(cfg->p2p); + cfg->p2p = NULL; + } + cfg->p2p_supported = 0; +} +/* + * Set P2P functions into firmware + */ +s32 +wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg) +{ + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } }; + s32 ret = BCME_OK; + s32 val = 0; + /* Do we have to check whether APSTA is enabled or not ? */ + ret = wldev_iovar_getint(ndev, "apsta", &val); + if (ret < 0) { + CFGP2P_ERR(("get apsta error %d\n", ret)); + return ret; + } + if (val == 0) { + val = 1; + ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); + if (ret < 0) { + CFGP2P_ERR(("WLC_DOWN error %d\n", ret)); + return ret; + } + wldev_iovar_setint(ndev, "apsta", val); + ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); + if (ret < 0) { + CFGP2P_ERR(("WLC_UP error %d\n", ret)); + return ret; + } + } + + /* In case of COB type, firmware has default mac address + * After Initializing firmware, we have to set current mac address to + * firmware for P2P device address + */ + ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr, + sizeof(null_eth_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &cfg->ioctl_buf_sync); + if (ret && ret != BCME_UNSUPPORTED) { + CFGP2P_ERR(("failed to update device address ret %d\n", ret)); + } + return ret; +} + +/* Create a new P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to create + * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT + * @chspec : chspec to use if creating a GO BSS. + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, + chanspec_t chspec) +{ + wl_p2p_if_t ifreq; + s32 err; + u32 scb_timeout = WL_SCB_TIMEOUT; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + + ifreq.type = if_type; + ifreq.chspec = chspec; + memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); + + CFGP2P_DBG(("---cfg p2p_ifadd "MACDBG" %s %u\n", + MAC2STRDBG(ifreq.addr.octet), + (if_type == WL_P2P_IF_GO) ? "go" : "client", + (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); + + err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (unlikely(err < 0)) + printk("'cfg p2p_ifadd' error %d\n", err); + else if (if_type == WL_P2P_IF_GO) { + err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); + if (unlikely(err < 0)) + printk("'cfg scb_timeout' error %d\n", err); + } + return err; +} + +/* Disable a P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to disable + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac) +{ + s32 ret; + struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); + + CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdis "MACDBG"\n", + netdev->ifindex, MAC2STRDBG(mac->octet))); + ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(ret < 0)) { + printk("'cfg p2p_ifdis' error %d\n", ret); + } + return ret; +} + +/* Delete a P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to delete + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac) +{ + s32 ret; + struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); + + CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdel "MACDBG"\n", + netdev->ifindex, MAC2STRDBG(mac->octet))); + ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(ret < 0)) { + printk("'cfg p2p_ifdel' error %d\n", ret); + } + return ret; +} + +/* Change a P2P Role. + * Parameters: + * @mac : MAC address of the BSS to change a role + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, + chanspec_t chspec) +{ + wl_p2p_if_t ifreq; + s32 err; + u32 scb_timeout = WL_SCB_TIMEOUT; + + struct net_device *netdev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); + + ifreq.type = if_type; + ifreq.chspec = chspec; + memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); + + CFGP2P_INFO(("---cfg p2p_ifchange "MACDBG" %s %u" + " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet), + (if_type == WL_P2P_IF_GO) ? "go" : "client", + (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT, + ifreq.chspec)); + + err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (unlikely(err < 0)) { + printk("'cfg p2p_ifupd' error %d\n", err); + } else if (if_type == WL_P2P_IF_GO) { + err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); + if (unlikely(err < 0)) + printk("'cfg scb_timeout' error %d\n", err); + } + return err; +} + + +/* Get the index of a created P2P BSS. + * Parameters: + * @mac : MAC address of the created BSS + * @index : output: index of created BSS + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index) +{ + s32 ret; + u8 getbuf[64]; + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + + CFGP2P_INFO(("---cfg p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet))); + + ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, + sizeof(getbuf), wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY), NULL); + + if (ret == 0) { + memcpy(index, getbuf, sizeof(s32)); + CFGP2P_INFO(("---cfg p2p_if ==> %d\n", *index)); + } + + return ret; +} + +static s32 +wl_cfgp2p_set_discovery(struct bcm_cfg80211 *cfg, s32 on) +{ + s32 ret = BCME_OK; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + CFGP2P_DBG(("enter\n")); + + ret = wldev_iovar_setint(ndev, "p2p_disc", on); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret)); + } + + return ret; +} + +/* Set the WL driver's P2P mode. + * Parameters : + * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}. + * @channel : the channel to listen + * @listen_ms : the time (milli seconds) to wait + * @bssidx : bss index for BSSCFG + * Returns 0 if success + */ + +s32 +wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, u32 channel, u16 listen_ms, int bssidx) +{ + wl_p2p_disc_st_t discovery_mode; + s32 ret; + struct net_device *dev; + CFGP2P_DBG(("enter\n")); + + if (unlikely(bssidx == WL_INVALID)) { + CFGP2P_ERR((" %d index out of range\n", bssidx)); + return -1; + } + + dev = wl_cfgp2p_find_ndev(cfg, bssidx); + if (unlikely(dev == NULL)) { + CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx)); + return BCME_NOTFOUND; + } + + /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */ + discovery_mode.state = mode; + discovery_mode.chspec = wl_ch_host_to_driver(channel); + discovery_mode.dwell = listen_ms; + ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode, + sizeof(discovery_mode), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &cfg->ioctl_buf_sync); + + return ret; +} + +/* Get the index of the P2P Discovery BSS */ +static s32 +wl_cfgp2p_get_disc_idx(struct bcm_cfg80211 *cfg, s32 *index) +{ + s32 ret; + struct net_device *dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); + + ret = wldev_iovar_getint(dev, "p2p_dev", index); + CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret)); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("'p2p_dev' error %d\n", ret)); + return ret; + } + return ret; +} + +s32 +wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg) +{ + + s32 index = 0; + s32 ret = BCME_OK; + + CFGP2P_DBG(("enter\n")); + + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) != 0) { + CFGP2P_ERR(("do nothing, already initialized\n")); + return ret; + } + + ret = wl_cfgp2p_set_discovery(cfg, 1); + if (ret < 0) { + CFGP2P_ERR(("set discover error\n")); + return ret; + } + /* Enable P2P Discovery in the WL Driver */ + ret = wl_cfgp2p_get_disc_idx(cfg, &index); + + if (ret < 0) { + return ret; + } + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = index; + + /* Set the initial discovery state to SCAN */ + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + + if (unlikely(ret != 0)) { + CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); + wl_cfgp2p_set_discovery(cfg, 0); + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0; + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; + return 0; + } + return ret; +} + +/* Deinitialize P2P Discovery + * Parameters : + * @cfg : wl_private data + * Returns 0 if succes + */ +static s32 +wl_cfgp2p_deinit_discovery(struct bcm_cfg80211 *cfg) +{ + s32 ret = BCME_OK; + CFGP2P_DBG(("enter\n")); + + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) == 0) { + CFGP2P_ERR(("do nothing, not initialized\n")); + return -1; + } + /* Set the discovery state to SCAN */ + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */ + ret = wl_cfgp2p_set_discovery(cfg, 0); + + /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver + * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery + * BSS. + */ + + /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we + * have no discovery BSS. + */ + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = WL_INVALID; + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; + + return ret; + +} +/* Enable P2P Discovery + * Parameters: + * @cfg : wl_private data + * @ie : probe request ie (WPS IE + P2P IE) + * @ie_len : probe request ie length + * Returns 0 if success. + */ +s32 +wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, + const u8 *ie, u32 ie_len) +{ + s32 ret = BCME_OK; + s32 bssidx; + + if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { + CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n")); + goto set_ie; + } + + wl_set_p2p_status(cfg, DISCOVERY_ON); + + CFGP2P_DBG(("enter\n")); + + ret = wl_cfgp2p_init_discovery(cfg); + if (unlikely(ret < 0)) { + CFGP2P_ERR((" init discovery error %d\n", ret)); + goto exit; + } + /* Set wsec to any non-zero value in the discovery bsscfg to ensure our + * P2P probe responses have the privacy bit set in the 802.11 WPA IE. + * Some peer devices may not initiate WPS with us if this bit is not set. + */ + ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), + "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + if (unlikely(ret < 0)) { + CFGP2P_ERR((" wsec error %d\n", ret)); + } +set_ie: + if (ie_len) { + if (bcmcfg_to_prmry_ndev(cfg) == dev) { + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + } else if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + + ret = wl_cfgp2p_set_management_ie(cfg, dev, + bssidx, + VNDR_IE_PRBREQ_FLAG, ie, ie_len); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("set probreq ie occurs error %d\n", ret)); + goto exit; + } + } +exit: + return ret; +} + +/* Disable P2P Discovery + * Parameters: + * @cfg : wl_private_data + * Returns 0 if success. + */ +s32 +wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg) +{ + s32 ret = BCME_OK; + CFGP2P_DBG((" enter\n")); + wl_clr_p2p_status(cfg, DISCOVERY_ON); + + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) == 0) { + CFGP2P_ERR((" do nothing, not initialized\n")); + goto exit; + } + + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + + if (unlikely(ret < 0)) { + + CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); + } + /* Do a scan abort to stop the driver's scan engine in case it is still + * waiting out an action frame tx dwell time. + */ + wl_clr_p2p_status(cfg, DISCOVERY_ON); + ret = wl_cfgp2p_deinit_discovery(cfg); + +exit: + return ret; +} + +s32 +wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, + u32 num_chans, u16 *channels, + s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, + p2p_scan_purpose_t p2p_scan_purpose) +{ + s32 ret = BCME_OK; + s32 memsize; + s32 eparams_size; + u32 i; + s8 *memblk; + wl_p2p_scan_t *p2p_params; + wl_escan_params_t *eparams; + wlc_ssid_t ssid; + /* Scan parameters */ +#define P2PAPI_SCAN_NPROBES 1 +#define P2PAPI_SCAN_DWELL_TIME_MS 80 +#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 +#define P2PAPI_SCAN_HOME_TIME_MS 60 +#define P2PAPI_SCAN_NPROBS_TIME_MS 30 +#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 + + struct net_device *pri_dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); + /* Allocate scan params which need space for 3 channels and 0 ssids */ + eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + + OFFSETOF(wl_escan_params_t, params)) + + num_chans * sizeof(eparams->params.channel_list[0]); + + memsize = sizeof(wl_p2p_scan_t) + eparams_size; + memblk = scanparambuf; + if (memsize > sizeof(scanparambuf)) { + CFGP2P_ERR((" scanpar buf too small (%u > %zu)\n", + memsize, sizeof(scanparambuf))); + return -1; + } + memset(memblk, 0, memsize); + memset(cfg->ioctl_buf, 0, WLC_IOCTL_MAXLEN); + if (search_state == WL_P2P_DISC_ST_SEARCH) { + /* + * If we in SEARCH STATE, we don't need to set SSID explictly + * because dongle use P2P WILDCARD internally by default + */ + wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx); + /* use null ssid */ + ssid.SSID_len = 0; + memset(&ssid.SSID, 0, sizeof(ssid.SSID)); + } else if (search_state == WL_P2P_DISC_ST_SCAN) { + /* SCAN STATE 802.11 SCAN + * WFD Supplicant has p2p_find command with (type=progressive, type= full) + * So if P2P_find command with type=progressive, + * we have to set ssid to P2P WILDCARD because + * we just do broadcast scan unless setting SSID + */ + wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); + /* use wild card ssid */ + ssid.SSID_len = WL_P2P_WILDCARD_SSID_LEN; + memset(&ssid.SSID, 0, sizeof(ssid.SSID)); + memcpy(&ssid.SSID, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN); + } else { + CFGP2P_ERR((" invalid search state %d\n", search_state)); + return -1; + } + + + /* Fill in the P2P scan structure at the start of the iovar param block */ + p2p_params = (wl_p2p_scan_t*) memblk; + p2p_params->type = 'E'; + /* Fill in the Scan structure that follows the P2P scan structure */ + eparams = (wl_escan_params_t*) (p2p_params + 1); + eparams->params.bss_type = DOT11_BSSTYPE_ANY; + if (active) + eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE; + else + eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE; + + if (tx_dst_addr == NULL) + memcpy(&eparams->params.bssid, ðer_bcast, ETHER_ADDR_LEN); + else + memcpy(&eparams->params.bssid, tx_dst_addr, ETHER_ADDR_LEN); + + if (ssid.SSID_len) + memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); + + eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); + + switch (p2p_scan_purpose) { + case P2P_SCAN_SOCIAL_CHANNEL: + eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); + break; + case P2P_SCAN_AFX_PEER_NORMAL: + case P2P_SCAN_AFX_PEER_REDUCED: + eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); + break; + case P2P_SCAN_CONNECT_TRY: + eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + break; + default : + if (wl_get_drv_status_all(cfg, CONNECTED)) + eparams->params.active_time = -1; + else + eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); + break; + } + + if (p2p_scan_purpose == P2P_SCAN_CONNECT_TRY) + eparams->params.nprobes = htod32(eparams->params.active_time / + WL_SCAN_JOIN_PROBE_INTERVAL_MS); + else + eparams->params.nprobes = htod32((eparams->params.active_time / + P2PAPI_SCAN_NPROBS_TIME_MS)); + + + if (eparams->params.nprobes <= 0) + eparams->params.nprobes = 1; + CFGP2P_DBG(("nprobes # %d, active_time %d\n", + eparams->params.nprobes, eparams->params.active_time)); + eparams->params.passive_time = htod32(-1); + eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | + (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); + + for (i = 0; i < num_chans; i++) { + eparams->params.channel_list[i] = wl_ch_host_to_driver(channels[i]); + } + eparams->version = htod32(ESCAN_REQ_VERSION); + eparams->action = htod16(action); + wl_escan_set_sync_id(eparams->sync_id, cfg); + wl_escan_set_type(cfg, WL_SCANTYPE_P2P); + CFGP2P_INFO(("SCAN CHANNELS : ")); + + for (i = 0; i < num_chans; i++) { + if (i == 0) CFGP2P_INFO(("%d", channels[i])); + else CFGP2P_INFO((",%d", channels[i])); + } + + CFGP2P_INFO(("\n")); + + ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan", + memblk, memsize, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + if (ret == BCME_OK) + wl_set_p2p_status(cfg, SCANNING); + return ret; +} + +/* search function to reach at common channel to send action frame + * Parameters: + * @cfg : wl_private data + * @ndev : net device for bssidx + * @bssidx : bssidx for BSS + * Returns 0 if success. + */ +s32 +wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, + s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr) +{ + s32 ret = 0; + u32 chan_cnt = 0; + u16 *default_chan_list = NULL; + p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_AFX_PEER_NORMAL; + if (!p2p_is_on(cfg) || ndev == NULL || bssidx == WL_INVALID) + return -BCME_ERROR; + WL_TRACE_HW4((" Enter\n")); + if (bssidx == wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY)) + bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); + if (channel) + chan_cnt = AF_PEER_SEARCH_CNT; + else + chan_cnt = SOCIAL_CHAN_CNT; + default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL); + if (default_chan_list == NULL) { + CFGP2P_ERR(("channel list allocation failed \n")); + ret = -ENOMEM; + goto exit; + } + if (channel) { + u32 i; + /* insert same channel to the chan_list */ + for (i = 0; i < chan_cnt; i++) { + default_chan_list[i] = channel; + } + } else { + default_chan_list[0] = SOCIAL_CHAN_1; + default_chan_list[1] = SOCIAL_CHAN_2; + default_chan_list[2] = SOCIAL_CHAN_3; + } + ret = wl_cfgp2p_escan(cfg, ndev, true, chan_cnt, + default_chan_list, WL_P2P_DISC_ST_SEARCH, + WL_SCAN_ACTION_START, bssidx, NULL, p2p_scan_purpose); + kfree(default_chan_list); +exit: + return ret; +} + +/* Check whether pointed-to IE looks like WPA. */ +#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) +/* Check whether pointed-to IE looks like WPS. */ +#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) +/* Check whether the given IE looks like WFA P2P IE. */ +#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) +/* Check whether the given IE looks like WFA WFDisplay IE. */ +#ifndef WFA_OUI_TYPE_WFD +#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ +#endif +#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) + +static s32 +wl_cfgp2p_parse_vndr_ies(u8 *parse, u32 len, + struct parsed_vndr_ies *vndr_ies) +{ + s32 err = BCME_OK; + vndr_ie_t *vndrie; + bcm_tlv_t *ie; + struct parsed_vndr_ie_info *parsed_info; + u32 count = 0; + s32 remained_len; + + remained_len = (s32)len; + memset(vndr_ies, 0, sizeof(*vndr_ies)); + + WL_INFO(("---> len %d\n", len)); + ie = (bcm_tlv_t *) parse; + if (!bcm_valid_tlv(ie, remained_len)) + ie = NULL; + while (ie) { + if (count >= MAX_VNDR_IE_NUMBER) + break; + if (ie->id == DOT11_MNG_VS_ID) { + vndrie = (vndr_ie_t *) ie; + /* len should be bigger than OUI length + one data length at least */ + if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) { + CFGP2P_ERR(("%s: invalid vndr ie. length is too small %d\n", + __FUNCTION__, vndrie->len)); + goto end; + } + /* if wpa or wme ie, do not add ie */ + if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) && + ((vndrie->data[0] == WPA_OUI_TYPE) || + (vndrie->data[0] == WME_OUI_TYPE))) { + CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n")); + goto end; + } + + parsed_info = &vndr_ies->ie_info[count++]; + + /* save vndr ie information */ + parsed_info->ie_ptr = (char *)vndrie; + parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN); + memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t)); + + vndr_ies->count = count; + + CFGP2P_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x \n", + parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1], + parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0])); + } +end: + ie = bcm_next_tlv(ie, &remained_len); + } + return err; +} + + +/* Delete and Set a management vndr ie to firmware + * Parameters: + * @cfg : wl_private data + * @ndev : net device for bssidx + * @bssidx : bssidx for BSS + * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, + * VNDR_IE_ASSOCREQ_FLAG) + * @ie : VNDR IE (such as P2P IE , WPS IE) + * @ie_len : VNDR IE Length + * Returns 0 if success. + */ + +s32 +wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, + s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) +{ + s32 ret = BCME_OK; + u8 *curr_ie_buf = NULL; + u8 *mgmt_ie_buf = NULL; + u32 mgmt_ie_buf_len = 0; + u32 *mgmt_ie_len = 0; + u32 del_add_ie_buf_len = 0; + u32 total_ie_buf_len = 0; + u32 parsed_ie_buf_len = 0; + struct parsed_vndr_ies old_vndr_ies; + struct parsed_vndr_ies new_vndr_ies; + s32 i; + u8 *ptr; + s32 type = -1; + s32 remained_buf_len; +#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie) +#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie_len) + memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf)); + curr_ie_buf = g_mgmt_ie_buf; + CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag)); + if (cfg->p2p != NULL) { + if (wl_cfgp2p_find_type(cfg, bssidx, &type)) { + CFGP2P_ERR(("cannot find type from bssidx : %d\n", bssidx)); + return BCME_ERROR; + } + + switch (pktflag) { + case VNDR_IE_PRBREQ_FLAG : + mgmt_ie_buf = IE_TYPE(probe_req, type); + mgmt_ie_len = &IE_TYPE_LEN(probe_req, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, type)); + break; + case VNDR_IE_PRBRSP_FLAG : + mgmt_ie_buf = IE_TYPE(probe_res, type); + mgmt_ie_len = &IE_TYPE_LEN(probe_res, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, type)); + break; + case VNDR_IE_ASSOCREQ_FLAG : + mgmt_ie_buf = IE_TYPE(assoc_req, type); + mgmt_ie_len = &IE_TYPE_LEN(assoc_req, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, type)); + break; + case VNDR_IE_ASSOCRSP_FLAG : + mgmt_ie_buf = IE_TYPE(assoc_res, type); + mgmt_ie_len = &IE_TYPE_LEN(assoc_res, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, type)); + break; + case VNDR_IE_BEACON_FLAG : + mgmt_ie_buf = IE_TYPE(beacon, type); + mgmt_ie_len = &IE_TYPE_LEN(beacon, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, type)); + break; + default: + mgmt_ie_buf = NULL; + mgmt_ie_len = NULL; + CFGP2P_ERR(("not suitable type\n")); + return BCME_ERROR; + } + } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { + if (cfg->ap_info == NULL) { + CFGP2P_ERR(("hostapd ap_info null ptr refrence while setting IE\n")); + return BCME_ERROR; + + } + switch (pktflag) { + case VNDR_IE_PRBRSP_FLAG : + mgmt_ie_buf = cfg->ap_info->probe_res_ie; + mgmt_ie_len = &cfg->ap_info->probe_res_ie_len; + mgmt_ie_buf_len = sizeof(cfg->ap_info->probe_res_ie); + break; + case VNDR_IE_BEACON_FLAG : + mgmt_ie_buf = cfg->ap_info->beacon_ie; + mgmt_ie_len = &cfg->ap_info->beacon_ie_len; + mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie); + break; + case VNDR_IE_ASSOCRSP_FLAG : + /* WPS-AP WSC2.0 assoc res includes wps_ie */ + mgmt_ie_buf = cfg->ap_info->assoc_res_ie; + mgmt_ie_len = &cfg->ap_info->assoc_res_ie_len; + mgmt_ie_buf_len = sizeof(cfg->ap_info->assoc_res_ie); + break; + default: + mgmt_ie_buf = NULL; + mgmt_ie_len = NULL; + CFGP2P_ERR(("not suitable type\n")); + return BCME_ERROR; + } + bssidx = 0; + } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) { + switch (pktflag) { + case VNDR_IE_PRBREQ_FLAG : + mgmt_ie_buf = cfg->sta_info->probe_req_ie; + mgmt_ie_len = &cfg->sta_info->probe_req_ie_len; + mgmt_ie_buf_len = sizeof(cfg->sta_info->probe_req_ie); + break; + case VNDR_IE_ASSOCREQ_FLAG : + mgmt_ie_buf = cfg->sta_info->assoc_req_ie; + mgmt_ie_len = &cfg->sta_info->assoc_req_ie_len; + mgmt_ie_buf_len = sizeof(cfg->sta_info->assoc_req_ie); + break; + default: + mgmt_ie_buf = NULL; + mgmt_ie_len = NULL; + CFGP2P_ERR(("not suitable type\n")); + return BCME_ERROR; + } + bssidx = 0; + } else { + CFGP2P_ERR(("not suitable type\n")); + return BCME_ERROR; + } + + if (vndr_ie_len > mgmt_ie_buf_len) { + CFGP2P_ERR(("extra IE size too big\n")); + ret = -ENOMEM; + } else { + /* parse and save new vndr_ie in curr_ie_buff before comparing it */ + if (vndr_ie && vndr_ie_len && curr_ie_buf) { + ptr = curr_ie_buf; + + wl_cfgp2p_parse_vndr_ies((u8*)vndr_ie, + vndr_ie_len, &new_vndr_ies); + + for (i = 0; i < new_vndr_ies.count; i++) { + struct parsed_vndr_ie_info *vndrie_info = + &new_vndr_ies.ie_info[i]; + + memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr, + vndrie_info->ie_len); + parsed_ie_buf_len += vndrie_info->ie_len; + } + } + + if (mgmt_ie_buf != NULL) { + if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && + (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { + CFGP2P_INFO(("Previous mgmt IE is equals to current IE")); + goto exit; + } + + /* parse old vndr_ie */ + wl_cfgp2p_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, + &old_vndr_ies); + + /* make a command to delete old ie */ + for (i = 0; i < old_vndr_ies.count; i++) { + struct parsed_vndr_ie_info *vndrie_info = + &old_vndr_ies.ie_info[i]; + + CFGP2P_INFO(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", + vndrie_info->vndrie.id, vndrie_info->vndrie.len, + vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2])); + + del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, + pktflag, vndrie_info->vndrie.oui, + vndrie_info->vndrie.id, + vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, + vndrie_info->ie_len - VNDR_IE_FIXED_LEN, + "del"); + + curr_ie_buf += del_add_ie_buf_len; + total_ie_buf_len += del_add_ie_buf_len; + } + } + + *mgmt_ie_len = 0; + /* Add if there is any extra IE */ + if (mgmt_ie_buf && parsed_ie_buf_len) { + ptr = mgmt_ie_buf; + + remained_buf_len = mgmt_ie_buf_len; + + /* make a command to add new ie */ + for (i = 0; i < new_vndr_ies.count; i++) { + struct parsed_vndr_ie_info *vndrie_info = + &new_vndr_ies.ie_info[i]; + + CFGP2P_INFO(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n", + vndrie_info->vndrie.id, vndrie_info->vndrie.len, + vndrie_info->ie_len - 2, + vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2])); + + del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, + pktflag, vndrie_info->vndrie.oui, + vndrie_info->vndrie.id, + vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, + vndrie_info->ie_len - VNDR_IE_FIXED_LEN, + "add"); + + /* verify remained buf size before copy data */ + if (remained_buf_len >= vndrie_info->ie_len) { + remained_buf_len -= vndrie_info->ie_len; + } else { + CFGP2P_ERR(("no space in mgmt_ie_buf: pktflag = %d, " + "found vndr ies # = %d(cur %d), remained len %d, " + "cur mgmt_ie_len %d, new ie len = %d\n", + pktflag, new_vndr_ies.count, i, remained_buf_len, + *mgmt_ie_len, vndrie_info->ie_len)); + break; + } + + /* save the parsed IE in cfg struct */ + memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, + vndrie_info->ie_len); + *mgmt_ie_len += vndrie_info->ie_len; + + curr_ie_buf += del_add_ie_buf_len; + total_ie_buf_len += del_add_ie_buf_len; + } + } + if (total_ie_buf_len) { + ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, + total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &cfg->ioctl_buf_sync); + if (ret) + CFGP2P_ERR(("vndr ie set error : %d\n", ret)); + } + } +#undef IE_TYPE +#undef IE_TYPE_LEN +exit: + return ret; +} + +/* Clear the manament IE buffer of BSSCFG + * Parameters: + * @cfg : wl_private data + * @bssidx : bssidx for BSS + * + * Returns 0 if success. + */ +s32 +wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx) +{ + + s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, + VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG}; + s32 index = -1; + s32 type = -1; + struct net_device *ndev = wl_cfgp2p_find_ndev(cfg, bssidx); +#define INIT_IE(IE_TYPE, BSS_TYPE) \ + do { \ + memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ + sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ + wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ + } while (0); + + if (bssidx < 0 || ndev == NULL) { + CFGP2P_ERR(("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev")); + return BCME_BADARG; + } + + if (wl_cfgp2p_find_type(cfg, bssidx, &type)) { + CFGP2P_ERR(("invalid argument\n")); + return BCME_BADARG; + } + for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) { + /* clean up vndr ies in dongle */ + wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, vndrie_flag[index], NULL, 0); + } + INIT_IE(probe_req, type); + INIT_IE(probe_res, type); + INIT_IE(assoc_req, type); + INIT_IE(assoc_res, type); + INIT_IE(beacon, type); + return BCME_OK; +} + + +/* Is any of the tlvs the expected entry? If + * not update the tlvs buffer pointer/length. + */ +static bool +wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type) +{ + /* If the contents match the OUI and the type */ + if (ie[TLV_LEN_OFF] >= oui_len + 1 && + !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && + type == ie[TLV_BODY_OFF + oui_len]) { + return TRUE; + } + + if (tlvs == NULL) + return FALSE; + /* point to the next ie */ + ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; + /* calculate the length of the rest of the buffer */ + *tlvs_len -= (int)(ie - *tlvs); + /* update the pointer to the start of the buffer */ + *tlvs = ie; + + return FALSE; +} + +wpa_ie_fixed_t * +wl_cfgp2p_find_wpaie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) { + return (wpa_ie_fixed_t *)ie; + } + } + return NULL; +} + +wpa_ie_fixed_t * +wl_cfgp2p_find_wpsie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) { + return (wpa_ie_fixed_t *)ie; + } + } + return NULL; +} + +wifi_p2p_ie_t * +wl_cfgp2p_find_p2pie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) { + return (wifi_p2p_ie_t *)ie; + } + } + return NULL; +} + +wifi_wfd_ie_t * +wl_cfgp2p_find_wfdie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) { + return (wifi_wfd_ie_t *)ie; + } + } + return NULL; +} +static u32 +wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag, + s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd) +{ + vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */ + s32 iecount; + u32 data_offset; + + /* Validate the pktflag parameter */ + if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | + VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | + VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) { + CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag)); + return -1; + } + + /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ + strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1); + hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Set the IE count - the buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32)); + + /* Copy packet flags that indicate which packets will contain this IE */ + pktflag = htod32(pktflag); + memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, + sizeof(u32)); + + /* Add the IE ID to the buffer */ + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; + + /* Add the IE length to the buffer */ + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = + (uint8) VNDR_IE_MIN_LEN + datalen; + + /* Add the IE OUI to the buffer */ + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0]; + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1]; + hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2]; + + /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */ + memcpy(iebuf, &hdr, sizeof(hdr) - 1); + + /* Copy the IE data to the IE buffer */ + data_offset = + (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] - + (u8*)&hdr; + memcpy(iebuf + data_offset, data, datalen); + return data_offset + datalen; + +} + +/* + * Search the bssidx based on dev argument + * Parameters: + * @cfg : wl_private data + * @ndev : net device to search bssidx + * @bssidx : output arg to store bssidx of the bsscfg of firmware. + * Returns error + */ +s32 +wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *bssidx) +{ + u32 i; + if (ndev == NULL || bssidx == NULL) { + CFGP2P_ERR((" argument is invalid\n")); + return BCME_BADARG; + } + if (!cfg->p2p_supported) { + *bssidx = P2PAPI_BSSCFG_PRIMARY; + return BCME_OK; + } + /* we cannot find the bssidx of DISCOVERY BSS + * because the ndev is same with ndev of PRIMARY BSS. + */ + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + if (ndev == wl_to_p2p_bss_ndev(cfg, i)) { + *bssidx = wl_to_p2p_bss_bssidx(cfg, i); + return BCME_OK; + } + } + return BCME_BADARG; +} +struct net_device * +wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx) +{ + u32 i; + struct net_device *ndev = NULL; + if (bssidx < 0) { + CFGP2P_ERR((" bsscfg idx is invalid\n")); + goto exit; + } + + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) { + ndev = wl_to_p2p_bss_ndev(cfg, i); + break; + } + } + +exit: + return ndev; +} +/* + * Search the driver array idx based on bssidx argument + * Parameters: + * @cfg : wl_private data + * @bssidx : bssidx which indicate bsscfg->idx of firmware. + * @type : output arg to store array idx of p2p->bss. + * Returns error + */ + +s32 +wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type) +{ + u32 i; + if (bssidx < 0 || type == NULL) { + CFGP2P_ERR((" argument is invalid\n")); + goto exit; + } + + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) { + *type = i; + return BCME_OK; + } + } + +exit: + return BCME_BADARG; +} + +/* + * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE + */ +s32 +wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 ret = BCME_OK; + struct net_device *ndev = NULL; + + if (!cfg || !cfg->p2p) + return BCME_ERROR; + + CFGP2P_DBG((" Enter\n")); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (wl_get_p2p_status(cfg, LISTEN_EXPIRED) == 0) { + wl_set_p2p_status(cfg, LISTEN_EXPIRED); + if (timer_pending(&cfg->p2p->listen_timer)) { + del_timer_sync(&cfg->p2p->listen_timer); + } + + if (cfg->afx_hdl->is_listen == TRUE && + wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { + WL_DBG(("Listen DONE for action frame\n")); + complete(&cfg->act_frm_scan); + } +#ifdef WL_CFG80211_SYNC_GON + else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, ndev); + WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n", + jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies))); + + if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) + wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); + + complete(&cfg->wait_next_af); + } +#endif /* WL_CFG80211_SYNC_GON */ + +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL)) { +#else + if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL) || + wl_get_drv_status_all(cfg, FAKE_REMAINING_ON_CHANNEL)) { +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + WL_DBG(("Listen DONE for ramain on channel expired\n")); + wl_clr_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_clr_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + if (ndev && (ndev->ieee80211_ptr != NULL)) { +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id, + &cfg->remain_on_chan, GFP_KERNEL); +#else + cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id, + &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ + } + } + if (wl_add_remove_eventmsg(bcmcfg_to_prmry_ndev(cfg), + WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) { + CFGP2P_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); + } + } else + wl_clr_p2p_status(cfg, LISTEN_EXPIRED); + + return ret; + +} + +/* + * Timer expire callback function for LISTEN + * We can't report cfg80211_remain_on_channel_expired from Timer ISR context, + * so lets do it from thread context. + */ +void +wl_cfgp2p_listen_expired(unsigned long data) +{ + wl_event_msg_t msg; + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *) data; + CFGP2P_DBG((" Enter\n")); + bzero(&msg, sizeof(wl_event_msg_t)); + msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); +#if defined(WL_ENABLE_P2P_IF) + wl_cfg80211_event(cfg->p2p_net ? cfg->p2p_net : + wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, NULL); +#else + wl_cfg80211_event(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, + NULL); +#endif /* WL_ENABLE_P2P_IF */ +} +/* + * Routine for cancelling the P2P LISTEN + */ +static s32 +wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, + struct wireless_dev *wdev, bool notify) +{ + WL_DBG(("Enter \n")); + /* Irrespective of whether timer is running or not, reset + * the LISTEN state. + */ + if (timer_pending(&cfg->p2p->listen_timer)) { + del_timer_sync(&cfg->p2p->listen_timer); + if (notify) { +#if defined(WL_CFG80211_P2P_DEV_IF) + if (wdev) + cfg80211_remain_on_channel_expired(wdev, cfg->last_roc_id, + &cfg->remain_on_chan, GFP_KERNEL); +#else + if (ndev && ndev->ieee80211_ptr) + cfg80211_remain_on_channel_expired(ndev, cfg->last_roc_id, + &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ + } + } + return 0; +} +/* + * Do a P2P Listen on the given channel for the given duration. + * A listen consists of sitting idle and responding to P2P probe requests + * with a P2P probe response. + * + * This fn assumes dongle p2p device discovery is already enabled. + * Parameters : + * @cfg : wl_private data + * @channel : channel to listen + * @duration_ms : the time (milli seconds) to wait + */ +s32 +wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms) +{ +#define EXTRA_DELAY_TIME 100 + s32 ret = BCME_OK; + struct timer_list *_timer; + s32 extra_delay; + struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); + + CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms)); + if (unlikely(wl_get_p2p_status(cfg, DISCOVERY_ON) == 0)) { + + CFGP2P_ERR((" Discovery is not set, so we have noting to do\n")); + + ret = BCME_NOTREADY; + goto exit; + } + if (timer_pending(&cfg->p2p->listen_timer)) { + CFGP2P_DBG(("previous LISTEN is not completed yet\n")); + goto exit; + + } +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + else + wl_clr_p2p_status(cfg, LISTEN_EXPIRED); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) { + CFGP2P_ERR((" failed to set WLC_E_P2P_PROPREQ_MSG\n")); + } + + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + _timer = &cfg->p2p->listen_timer; + + /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , + * otherwise we will wait up to duration_ms + 100ms + duration / 10 + */ + if (ret == BCME_OK) { + extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10); + } else { + /* if failed to set listen, it doesn't need to wait whole duration. */ + duration_ms = 100 + duration_ms / 20; + extra_delay = 0; + } + + INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_clr_p2p_status(cfg, LISTEN_EXPIRED); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +#undef EXTRA_DELAY_TIME +exit: + return ret; +} + + +s32 +wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable) +{ + s32 ret = BCME_OK; + CFGP2P_DBG((" Enter\n")); + if (!wl_get_p2p_status(cfg, DISCOVERY_ON)) { + + CFGP2P_DBG((" do nothing, discovery is off\n")); + return ret; + } + if (wl_get_p2p_status(cfg, SEARCH_ENABLED) == enable) { + CFGP2P_DBG(("already : %d\n", enable)); + return ret; + } + + wl_chg_p2p_status(cfg, SEARCH_ENABLED); + /* When disabling Search, reset the WL driver's p2p discovery state to + * WL_P2P_DISC_ST_SCAN. + */ + if (!enable) { + wl_clr_p2p_status(cfg, SCANNING); + ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + } + + return ret; +} + +/* + * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE + */ +s32 +wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 ret = BCME_OK; + u32 event_type = ntoh32(e->event_type); + u32 status = ntoh32(e->status); + struct net_device *ndev = NULL; + CFGP2P_DBG((" Enter\n")); + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) { + if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { + + CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); + if (status == WLC_E_STATUS_SUCCESS) { + wl_set_p2p_status(cfg, ACTION_TX_COMPLETED); + CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n")); + if (!cfg->need_wait_afrx && cfg->af_sent_channel) { + CFGP2P_DBG(("no need to wait next AF.\n")); + wl_stop_wait_next_action_frame(cfg, ndev); + } + } + else if (!wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { + wl_set_p2p_status(cfg, ACTION_TX_NOACK); + CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); + wl_stop_wait_next_action_frame(cfg, ndev); + } + } else { + CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," + "status : %d\n", status)); + + if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) + complete(&cfg->send_af_done); + } + } + return ret; +} +/* Send an action frame immediately without doing channel synchronization. + * + * This function does not wait for a completion event before returning. + * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action + * frame is transmitted. + * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an + * 802.11 ack has been received for the sent action frame. + */ +s32 +wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, + wl_af_params_t *af_params, s32 bssidx) +{ + s32 ret = BCME_OK; + s32 evt_ret = BCME_OK; + s32 timeout = 0; + wl_eventmsg_buf_t buf; + + + CFGP2P_INFO(("\n")); + CFGP2P_INFO(("channel : %u , dwell time : %u\n", + af_params->channel, af_params->dwell_time)); + + wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED); + wl_clr_p2p_status(cfg, ACTION_TX_NOACK); + + bzero(&buf, sizeof(wl_eventmsg_buf_t)); + wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true); + wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true); + if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) + return evt_ret; + + cfg->af_sent_channel = af_params->channel; +#ifdef WL_CFG80211_SYNC_GON + cfg->af_tx_sent_jiffies = jiffies; +#endif /* WL_CFG80211_SYNC_GON */ + + ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + if (ret < 0) { + CFGP2P_ERR((" sending action frame is failed\n")); + goto exit; + } + + timeout = wait_for_completion_timeout(&cfg->send_af_done, + msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX)); + + if (timeout >= 0 && wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { + CFGP2P_INFO(("tx action frame operation is completed\n")); + ret = BCME_OK; + } else if (ETHER_ISBCAST(&cfg->afx_hdl->tx_dst_addr)) { + CFGP2P_INFO(("bcast tx action frame operation is completed\n")); + ret = BCME_OK; + } else { + ret = BCME_ERROR; + CFGP2P_INFO(("tx action frame operation is failed\n")); + } + /* clear status bit for action tx */ + wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED); + wl_clr_p2p_status(cfg, ACTION_TX_NOACK); + +exit: + CFGP2P_INFO((" via act frame iovar : status = %d\n", ret)); + + bzero(&buf, sizeof(wl_eventmsg_buf_t)); + wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false); + wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false); + if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) { + WL_ERR(("TX frame events revert back failed \n")); + return evt_ret; + } + + return ret; +} + +/* Generate our P2P Device Address and P2P Interface Address from our primary + * MAC address. + */ +void +wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, + struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr) +{ + memset(out_dev_addr, 0, sizeof(*out_dev_addr)); + memset(out_int_addr, 0, sizeof(*out_int_addr)); + + /* Generate the P2P Device Address. This consists of the device's + * primary MAC address with the locally administered bit set. + */ + memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr)); + out_dev_addr->octet[0] |= 0x02; + + /* Generate the P2P Interface Address. If the discovery and connection + * BSSCFGs need to simultaneously co-exist, then this address must be + * different from the P2P Device Address. + */ + memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr)); + out_int_addr->octet[4] ^= 0x80; + +} + +/* P2P IF Address change to Virtual Interface MAC Address */ +void +wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id) +{ + wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf; + u16 len = ie->len; + u8 *subel; + u8 subelt_id; + u16 subelt_len; + CFGP2P_DBG((" Enter\n")); + + /* Point subel to the P2P IE's subelt field. + * Subtract the preceding fields (id, len, OUI, oui_type) from the length. + */ + subel = ie->subelts; + len -= 4; /* exclude OUI + OUI_TYPE */ + + while (len >= 3) { + /* attribute id */ + subelt_id = *subel; + subel += 1; + len -= 1; + + /* 2-byte little endian */ + subelt_len = *subel++; + subelt_len |= *subel++ << 8; + + len -= 2; + len -= subelt_len; /* for the remaining subelt fields */ + + if (subelt_id == element_id) { + if (subelt_id == P2P_SEID_INTINTADDR) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n")); + } else if (subelt_id == P2P_SEID_DEV_ID) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("Device ID ATTR FOUND\n")); + } else if (subelt_id == P2P_SEID_DEV_INFO) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("Device INFO ATTR FOUND\n")); + } else if (subelt_id == P2P_SEID_GROUP_ID) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("GROUP ID ATTR FOUND\n")); + } return; + } else { + CFGP2P_DBG(("OTHER id : %d\n", subelt_id)); + } + subel += subelt_len; + } +} +/* + * Check if a BSS is up. + * This is a common implementation called by most OSL implementations of + * p2posl_bss_isup(). DO NOT call this function directly from the + * common code -- call p2posl_bss_isup() instead to allow the OSL to + * override the common implementation if necessary. + */ +bool +wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) +{ + s32 result, val; + bool isup = false; + s8 getbuf[64]; + + /* Check if the BSS is up */ + *(int*)getbuf = -1; + result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, + sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL); + if (result != 0) { + CFGP2P_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result)); + CFGP2P_ERR(("NOTE: this ioctl error is normal " + "when the BSS has not been created yet.\n")); + } else { + val = *(int*)getbuf; + val = dtoh32(val); + CFGP2P_INFO(("---cfg bss -C %d ==> %d\n", bsscfg_idx, val)); + isup = (val ? TRUE : FALSE); + } + return isup; +} + + +/* Bring up or down a BSS */ +s32 +wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up) +{ + s32 ret = BCME_OK; + s32 val = up ? 1 : 0; + + struct { + s32 cfg; + s32 val; + } bss_setbuf; + + bss_setbuf.cfg = htod32(bsscfg_idx); + bss_setbuf.val = htod32(val); + CFGP2P_INFO(("---cfg bss -C %d %s\n", bsscfg_idx, up ? "up" : "down")); + ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (ret != 0) { + CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret)); + } + + return ret; +} + +/* Check if 'p2p' is supported in the driver */ +s32 +wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + s32 ret = BCME_OK; + s32 p2p_supported = 0; + ret = wldev_iovar_getint(ndev, "p2p", + &p2p_supported); + if (ret < 0) { + if (ret == BCME_UNSUPPORTED) { + CFGP2P_INFO(("p2p is unsupported\n")); + return 0; + } else { + CFGP2P_ERR(("cfg p2p error %d\n", ret)); + return ret; + } + } + if (p2p_supported == 1) { + CFGP2P_INFO(("p2p is supported\n")); + } else { + CFGP2P_INFO(("p2p is unsupported\n")); + p2p_supported = 0; + } + return p2p_supported; +} +/* Cleanup P2P resources */ +s32 +wl_cfgp2p_down(struct bcm_cfg80211 *cfg) +{ + struct net_device *ndev = NULL; + struct wireless_dev *wdev = NULL; + s32 i = 0, index = -1; + +#if defined(WL_CFG80211_P2P_DEV_IF) + ndev = bcmcfg_to_prmry_ndev(cfg); + wdev = bcmcfg_to_p2p_wdev(cfg); +#elif defined(WL_ENABLE_P2P_IF) + ndev = cfg->p2p_net ? cfg->p2p_net : bcmcfg_to_prmry_ndev(cfg); + wdev = ndev_to_wdev(ndev); +#endif /* WL_CFG80211_P2P_DEV_IF */ + + wl_cfgp2p_cancel_listen(cfg, ndev, wdev, TRUE); + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + index = wl_to_p2p_bss_bssidx(cfg, i); + if (index != WL_INVALID) + wl_cfgp2p_clear_management_ie(cfg, index); + } + wl_cfgp2p_deinit_priv(cfg); + return 0; +} +s32 +wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len) +{ + s32 ret = -1; + int count, start, duration; + wl_p2p_sched_t dongle_noa; + + CFGP2P_DBG((" Enter\n")); + + memset(&dongle_noa, 0, sizeof(dongle_noa)); + + if (cfg->p2p && cfg->p2p->vif_created) { + + cfg->p2p->noa.desc[0].start = 0; + + sscanf(buf, "%10d %10d %10d", &count, &start, &duration); + CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n", + count, start, duration)); + if (count != -1) + cfg->p2p->noa.desc[0].count = count; + + /* supplicant gives interval as start */ + if (start != -1) + cfg->p2p->noa.desc[0].interval = start; + + if (duration != -1) + cfg->p2p->noa.desc[0].duration = duration; + + if (cfg->p2p->noa.desc[0].count < 255 && cfg->p2p->noa.desc[0].count > 1) { + cfg->p2p->noa.desc[0].start = 0; + dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; + dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; + dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; + } + else if (cfg->p2p->noa.desc[0].count == 1) { + cfg->p2p->noa.desc[0].start = 200; + dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS; + dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF; + dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; + } + else if (cfg->p2p->noa.desc[0].count == 0) { + cfg->p2p->noa.desc[0].start = 0; + dongle_noa.action = WL_P2P_SCHED_ACTION_RESET; + } + else { + /* Continuous NoA interval. */ + dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; + dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; + if ((cfg->p2p->noa.desc[0].interval == 102) || + (cfg->p2p->noa.desc[0].interval == 100)) { + cfg->p2p->noa.desc[0].start = 100 - + cfg->p2p->noa.desc[0].duration; + dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT; + } + else { + dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; + } + } + /* Put the noa descriptor in dongle format for dongle */ + dongle_noa.desc[0].count = htod32(cfg->p2p->noa.desc[0].count); + if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) { + dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start); + dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration); + } + else { + dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start*1000); + dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration*1000); + } + dongle_noa.desc[0].interval = htod32(cfg->p2p->noa.desc[0].interval*1000); + + ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION), + "p2p_noa", &dongle_noa, sizeof(dongle_noa), cfg->ioctl_buf, + WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + + if (ret < 0) { + CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret)); + } + } + else { + CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n")); + } + return ret; +} +s32 +wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int buf_len) +{ + + wifi_p2p_noa_desc_t *noa_desc; + int len = 0, i; + char _buf[200]; + + CFGP2P_DBG((" Enter\n")); + buf[0] = '\0'; + if (cfg->p2p && cfg->p2p->vif_created) { + if (cfg->p2p->noa.desc[0].count || cfg->p2p->ops.ops) { + _buf[0] = 1; /* noa index */ + _buf[1] = (cfg->p2p->ops.ops ? 0x80: 0) | + (cfg->p2p->ops.ctw & 0x7f); /* ops + ctw */ + len += 2; + if (cfg->p2p->noa.desc[0].count) { + noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len]; + noa_desc->cnt_type = cfg->p2p->noa.desc[0].count; + noa_desc->duration = cfg->p2p->noa.desc[0].duration; + noa_desc->interval = cfg->p2p->noa.desc[0].interval; + noa_desc->start = cfg->p2p->noa.desc[0].start; + len += sizeof(wifi_p2p_noa_desc_t); + } + if (buf_len <= len * 2) { + CFGP2P_ERR(("ERROR: buf_len %d in not enough for" + "returning noa in string format\n", buf_len)); + return -1; + } + /* We have to convert the buffer data into ASCII strings */ + for (i = 0; i < len; i++) { + snprintf(buf, 3, "%02x", _buf[i]); + buf += 2; + } + buf[i*2] = '\0'; + } + } + else { + CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n")); + return -1; + } + return len * 2; +} +s32 +wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len) +{ + int ps, ctw; + int ret = -1; + s32 legacy_ps; + struct net_device *dev; + + CFGP2P_DBG((" Enter\n")); + if (cfg->p2p && cfg->p2p->vif_created) { + sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw); + CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw)); + dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION); + if (ctw != -1) { + cfg->p2p->ops.ctw = ctw; + ret = 0; + } + if (ps != -1) { + cfg->p2p->ops.ops = ps; + ret = wldev_iovar_setbuf(dev, + "p2p_ops", &cfg->p2p->ops, sizeof(cfg->p2p->ops), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (ret < 0) { + CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret)); + } + } + + if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) { + ret = wldev_ioctl(dev, + WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true); + if (unlikely(ret)) + CFGP2P_ERR(("error (%d)\n", ret)); + wl_cfg80211_update_power_mode(dev); + } + else + CFGP2P_ERR(("ilegal setting\n")); + } + else { + CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n")); + ret = -1; + } + return ret; +} + +u8 * +wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) +{ + wifi_p2p_ie_t *ie = NULL; + u16 len = 0; + u8 *subel; + u8 subelt_id; + u16 subelt_len; + + if (!buf) { + WL_ERR(("P2P IE not present")); + return 0; + } + + ie = (wifi_p2p_ie_t*) buf; + len = ie->len; + + /* Point subel to the P2P IE's subelt field. + * Subtract the preceding fields (id, len, OUI, oui_type) from the length. + */ + subel = ie->subelts; + len -= 4; /* exclude OUI + OUI_TYPE */ + + while (len >= 3) { + /* attribute id */ + subelt_id = *subel; + subel += 1; + len -= 1; + + /* 2-byte little endian */ + subelt_len = *subel++; + subelt_len |= *subel++ << 8; + + len -= 2; + len -= subelt_len; /* for the remaining subelt fields */ + + if (subelt_id == element_id) { + /* This will point to start of subelement attrib after + * attribute id & len + */ + return subel; + } + + /* Go to next subelement */ + subel += subelt_len; + } + + /* Not Found */ + return NULL; +} + +#define P2P_GROUP_CAPAB_GO_BIT 0x01 + +u8* +wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib) +{ + bcm_tlv_t *ie; + u8* pAttrib; + + CFGP2P_INFO(("Starting parsing parse %p attrib %d remaining len %d ", parse, attrib, len)); + while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len) == TRUE) { + /* Have the P2p ie. Now check for attribute */ + if ((pAttrib = wl_cfgp2p_retreive_p2pattrib(parse, attrib)) != NULL) { + CFGP2P_INFO(("P2P attribute %d was found at parse %p", + attrib, parse)); + return pAttrib; + } + else { + parse += (ie->len + TLV_HDR_LEN); + len -= (ie->len + TLV_HDR_LEN); + CFGP2P_INFO(("P2P Attribute %d not found Moving parse" + " to %p len to %d", attrib, parse, len)); + } + } + else { + /* It was not p2p IE. parse will get updated automatically to next TLV */ + CFGP2P_INFO(("IT was NOT P2P IE parse %p len %d", parse, len)); + } + } + CFGP2P_ERR(("P2P attribute %d was NOT found", attrib)); + return NULL; +} + +u8 * +wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) +{ + u8 *capability = NULL; + bool p2p_go = 0; + u8 *ptr = NULL; + + if ((capability = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, + bi->ie_length, P2P_SEID_P2P_INFO)) == NULL) { + WL_ERR(("P2P Capability attribute not found")); + return NULL; + } + + /* Check Group capability for Group Owner bit */ + p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT; + if (!p2p_go) { + return bi->BSSID.octet; + } + + /* In probe responses, DEVICE INFO attribute will be present */ + if (!(ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, + bi->ie_length, P2P_SEID_DEV_INFO))) { + /* If DEVICE_INFO is not found, this might be a beacon frame. + * check for DEVICE_ID in the beacon frame. + */ + ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, + bi->ie_length, P2P_SEID_DEV_ID); + } + + if (!ptr) + WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE ")); + + return ptr; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +static void +wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) +{ + snprintf(info->driver, sizeof(info->driver), "p2p"); + snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0)); +} + +struct ethtool_ops cfgp2p_ethtool_ops = { + .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + +#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) +s32 +wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg) +{ + int ret = 0; + struct net_device* net = NULL; +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT + struct wireless_dev *wdev = NULL; +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; + + if (cfg->p2p_net) { + CFGP2P_ERR(("p2p_net defined already.\n")); + return -EINVAL; + } + + /* Allocate etherdev, including space for private structure */ + if (!(net = alloc_etherdev(sizeof(struct bcm_cfg80211 *)))) { + CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); + return -ENODEV; + } + +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + free_netdev(net); + return -ENOMEM; + } +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + + strncpy(net->name, "p2p%d", sizeof(net->name) - 1); + net->name[IFNAMSIZ - 1] = '\0'; + + /* Copy the reference to bcm_cfg80211 */ + memcpy((void *)netdev_priv(net), &cfg, sizeof(struct bcm_cfg80211 *)); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + ASSERT(!net->open); + net->do_ioctl = wl_cfgp2p_do_ioctl; + net->hard_start_xmit = wl_cfgp2p_start_xmit; + net->open = wl_cfgp2p_if_open; + net->stop = wl_cfgp2p_if_stop; +#else + ASSERT(!net->netdev_ops); + net->netdev_ops = &wl_cfgp2p_if_ops; +#endif + + /* Register with a dummy MAC addr */ + memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); + +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT + wdev->wiphy = cfg->wdev->wiphy; + + wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); + + net->ieee80211_ptr = wdev; +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + net->ethtool_ops = &cfgp2p_ethtool_ops; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ + +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT + SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy)); + + /* Associate p2p0 network interface with new wdev */ + wdev->netdev = net; +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + + ret = register_netdev(net); + if (ret) { + CFGP2P_ERR((" register_netdevice failed (%d)\n", ret)); + free_netdev(net); +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT + kfree(wdev); +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + return -ENODEV; + } + + /* store p2p net ptr for further reference. Note that iflist won't have this + * entry as there corresponding firmware interface is a "Hidden" interface. + */ +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT + cfg->p2p_wdev = wdev; +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + cfg->p2p_net = net; + + printk("%s: P2P Interface Registered\n", net->name); + + return ret; +} + +s32 +wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg) +{ + + if (!cfg || !cfg->p2p_net) { + CFGP2P_ERR(("Invalid Ptr\n")); + return -EINVAL; + } + + unregister_netdev(cfg->p2p_net); + free_netdev(cfg->p2p_net); + + return 0; +} + +static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + + if (skb) + { + CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n", + ndev->name)); + dev_kfree_skb_any(skb); + } + + return 0; +} + +static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd) +{ + int ret = 0; + struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net); + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + + /* There is no ifidx corresponding to p2p0 in our firmware. So we should + * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs. + * For Android PRIV CMD handling map it to primary I/F + */ + if (cmd == SIOCDEVPRIVATE+1) { + ret = wl_android_priv_cmd(ndev, ifr, cmd); + + } else { + CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n", + __FUNCTION__, cmd)); + return -1; + } + + return ret; +} +#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ + + +#if defined(WL_ENABLE_P2P_IF) +static int wl_cfgp2p_if_open(struct net_device *net) +{ + struct wireless_dev *wdev = net->ieee80211_ptr; + + if (!wdev || !wl_cfg80211_is_p2p_active()) + return -EINVAL; + WL_TRACE(("Enter\n")); +#if !defined(WL_IFACE_COMB_NUM_CHANNELS) + /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, + * do it here. This will make sure that in concurrent mode, supplicant + * is not dependent on a particular order of interface initialization. + * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N + * -iwlan0. + */ + wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO)); +#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ + wl_cfg80211_do_driver_init(net); + + + return 0; +} + +static int wl_cfgp2p_if_stop(struct net_device *net) +{ + struct wireless_dev *wdev = net->ieee80211_ptr; + + if (!wdev) + return -EINVAL; + + wl_cfg80211_scan_stop(net); + +#if !defined(WL_IFACE_COMB_NUM_CHANNELS) + wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) + & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| + BIT(NL80211_IFTYPE_P2P_GO))); +#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ + + + return 0; +} + +bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops) +{ + return (if_ops == &wl_cfgp2p_if_ops); +} +#endif /* WL_ENABLE_P2P_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +struct wireless_dev * +wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg) +{ + struct wireless_dev *wdev = NULL; + struct ether_addr primary_mac; + + if (!cfg) + return ERR_PTR(-EINVAL); + + WL_TRACE(("Enter\n")); + + if (cfg->p2p_wdev) { + CFGP2P_ERR(("p2p_wdev defined already.\n")); + wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); + CFGP2P_ERR(("p2p_wdev deleted.\n")); + } + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return ERR_PTR(-ENOMEM); + } + + memset(&primary_mac, 0, sizeof(primary_mac)); + get_primary_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &cfg->p2p->dev_addr, &cfg->p2p->int_addr); + + wdev->wiphy = cfg->wdev->wiphy; + wdev->iftype = NL80211_IFTYPE_P2P_DEVICE; + memcpy(wdev->address, &cfg->p2p->dev_addr, ETHER_ADDR_LEN); + +#if defined(WL_NEWCFG_PRIVCMD_SUPPORT) + if (cfg->p2p_net) + memcpy(cfg->p2p_net->dev_addr, &cfg->p2p->dev_addr, ETHER_ADDR_LEN); +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ + + /* store p2p wdev ptr for further reference. */ + cfg->p2p_wdev = wdev; + + CFGP2P_ERR(("P2P interface registered\n")); + + return wdev; +} + +int +wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + if (!cfg) + return -EINVAL; + + WL_TRACE(("Enter\n")); + + ret = wl_cfgp2p_set_firm_p2p(cfg); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("Set P2P in firmware failed, ret=%d\n", ret)); + goto exit; + } + + ret = wl_cfgp2p_enable_discovery(cfg, bcmcfg_to_prmry_ndev(cfg), NULL, 0); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P enable discovery failed, ret=%d\n", ret)); + goto exit; + } + + p2p_on(cfg) = true; + + CFGP2P_DBG(("P2P interface started\n")); + +exit: + return ret; +} + +void +wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + if (!cfg) + return; + + WL_TRACE(("Enter\n")); + + ret = wl_cfg80211_scan_stop(wdev); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret)); + } + + if (!cfg->p2p) + return; + + ret = wl_cfgp2p_disable_discovery(cfg); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret)); + } + + p2p_on(cfg) = false; + + CFGP2P_DBG(("P2P interface stopped\n")); + + return; +} + +int +wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg) +{ + bool rollback_lock = false; + + if (!wdev) + return -EINVAL; + + WL_TRACE(("Enter\n")); + + if (!rtnl_is_locked()) { + rtnl_lock(); + rollback_lock = true; + } + + cfg80211_unregister_wdev(wdev); + + if (rollback_lock) + rtnl_unlock(); + + kfree(wdev); + + if (cfg) + cfg->p2p_wdev = NULL; + + CFGP2P_ERR(("P2P interface unregistered\n")); + + return 0; +} +#endif /* WL_CFG80211_P2P_DEV_IF */ + +void +wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + int status = 0; + + if (!frame || (frame_len < (sizeof(*pact_frm) + WL_P2P_AF_STATUS_OFFSET - 1))) { + return; + } + + if (wl_cfgp2p_is_pub_action(frame, frame_len)) { + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + if (pact_frm->subtype == P2P_PAF_GON_RSP && tx) { + CFGP2P_ACTION(("Check TX P2P Group Owner Negotiation Rsp Frame status\n")); + status = pact_frm->elts[WL_P2P_AF_STATUS_OFFSET]; + if (status) { + cfg->need_wait_afrx = false; + return; + } + } + } + + cfg->need_wait_afrx = true; + return; +} + +int +wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request) +{ + if (request && (request->n_ssids == 1) && + (request->n_channels == 1) && + IS_P2P_SSID(request->ssids[0].ssid, WL_P2P_WILDCARD_SSID_LEN) && + (request->ssids[0].ssid_len > WL_P2P_WILDCARD_SSID_LEN)) { + return true; + } + return false; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h new file mode 100644 index 000000000000..cca3f7b339cb --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h @@ -0,0 +1,416 @@ +/* + * Linux cfgp2p driver + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgp2p.h 528496 2015-01-22 10:52:40Z $ + */ +#ifndef _wl_cfgp2p_h_ +#define _wl_cfgp2p_h_ +#include +#include + +struct bcm_cfg80211; +extern u32 wl_dbg_level; + +typedef struct wifi_p2p_ie wifi_wfd_ie_t; +/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not + * confuse this with a bsscfg index. This value is an index into the + * saved_ie[] array of structures which in turn contains a bsscfg index field. + */ +typedef enum { + P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ + P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ + P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ + P2PAPI_BSSCFG_MAX +} p2p_bsscfg_type_t; + +typedef enum { + P2P_SCAN_PURPOSE_MIN, + P2P_SCAN_SOCIAL_CHANNEL, /* scan for social channel */ + P2P_SCAN_AFX_PEER_NORMAL, /* scan for action frame search */ + P2P_SCAN_AFX_PEER_REDUCED, /* scan for action frame search with short time */ + P2P_SCAN_DURING_CONNECTED, /* scan during connected status */ + P2P_SCAN_CONNECT_TRY, /* scan for connecting */ + P2P_SCAN_NORMAL, /* scan during not-connected status */ + P2P_SCAN_PURPOSE_MAX +} p2p_scan_purpose_t; + +/* vendor ies max buffer length for probe response or beacon */ +#define VNDR_IES_MAX_BUF_LEN 1400 +/* normal vendor ies buffer length */ +#define VNDR_IES_BUF_LEN 512 + +/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */ +struct p2p_saved_ie { + u8 p2p_probe_req_ie[VNDR_IES_BUF_LEN]; + u8 p2p_probe_res_ie[VNDR_IES_MAX_BUF_LEN]; + u8 p2p_assoc_req_ie[VNDR_IES_BUF_LEN]; + u8 p2p_assoc_res_ie[VNDR_IES_BUF_LEN]; + u8 p2p_beacon_ie[VNDR_IES_MAX_BUF_LEN]; + u32 p2p_probe_req_ie_len; + u32 p2p_probe_res_ie_len; + u32 p2p_assoc_req_ie_len; + u32 p2p_assoc_res_ie_len; + u32 p2p_beacon_ie_len; +}; + +struct p2p_bss { + u32 bssidx; + struct net_device *dev; + struct p2p_saved_ie saved_ie; + void *private_data; +}; + +struct p2p_info { + bool on; /* p2p on/off switch */ + bool scan; + int16 search_state; + bool vif_created; + s8 vir_ifname[IFNAMSIZ]; + unsigned long status; + struct ether_addr dev_addr; + struct ether_addr int_addr; + struct p2p_bss bss[P2PAPI_BSSCFG_MAX]; + struct timer_list listen_timer; + wl_p2p_sched_t noa; + wl_p2p_ops_t ops; + wlc_ssid_t ssid; +}; + +#define MAX_VNDR_IE_NUMBER 5 + +struct parsed_vndr_ie_info { + char *ie_ptr; + u32 ie_len; /* total length including id & length field */ + vndr_ie_t vndrie; +}; + +struct parsed_vndr_ies { + u32 count; + struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; +}; + +/* dongle status */ +enum wl_cfgp2p_status { + WLP2P_STATUS_DISCOVERY_ON = 0, + WLP2P_STATUS_SEARCH_ENABLED, + WLP2P_STATUS_IF_ADDING, + WLP2P_STATUS_IF_DELETING, + WLP2P_STATUS_IF_CHANGING, + WLP2P_STATUS_IF_CHANGED, + WLP2P_STATUS_LISTEN_EXPIRED, + WLP2P_STATUS_ACTION_TX_COMPLETED, + WLP2P_STATUS_ACTION_TX_NOACK, + WLP2P_STATUS_SCANNING, + WLP2P_STATUS_GO_NEG_PHASE, + WLP2P_STATUS_DISC_IN_PROGRESS +}; + + +#define wl_to_p2p_bss_ndev(cfg, type) ((cfg)->p2p->bss[type].dev) +#define wl_to_p2p_bss_bssidx(cfg, type) ((cfg)->p2p->bss[type].bssidx) +#define wl_to_p2p_bss_saved_ie(cfg, type) ((cfg)->p2p->bss[type].saved_ie) +#define wl_to_p2p_bss_private(cfg, type) ((cfg)->p2p->bss[type].private_data) +#define wl_to_p2p_bss(cfg, type) ((cfg)->p2p->bss[type]) +#define wl_get_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ + test_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) +#define wl_set_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ + set_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) +#define wl_clr_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ + clear_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) +#define wl_chg_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \ + change_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status)) +#define p2p_on(cfg) ((cfg)->p2p->on) +#define p2p_scan(cfg) ((cfg)->p2p->scan) +#define p2p_is_on(cfg) ((cfg)->p2p && (cfg)->p2p->on) + +/* dword align allocation */ +#define WLC_IOCTL_MAXLEN 8192 + +#define CFGP2P_ERROR_TEXT "CFGP2P-ERROR) " + + +#define CFGP2P_ERR(args) \ + do { \ + if (wl_dbg_level & WL_DBG_ERR) { \ + printk(KERN_INFO CFGP2P_ERROR_TEXT "%s : ", __func__); \ + printk args; \ + } \ + } while (0) +#define CFGP2P_INFO(args) \ + do { \ + if (wl_dbg_level & WL_DBG_INFO) { \ + printk(KERN_INFO "CFGP2P-INFO) %s : ", __func__); \ + printk args; \ + } \ + } while (0) +#define CFGP2P_DBG(args) \ + do { \ + if (wl_dbg_level & WL_DBG_DBG) { \ + printk(KERN_DEBUG "CFGP2P-DEBUG) %s :", __func__); \ + printk args; \ + } \ + } while (0) + +#define CFGP2P_ACTION(args) \ + do { \ + if (wl_dbg_level & WL_DBG_P2P_ACTION) { \ + printk(KERN_DEBUG "CFGP2P-ACTION) %s :", __func__); \ + printk args; \ + } \ + } while (0) +#define INIT_TIMER(timer, func, duration, extra_delay) \ + do { \ + init_timer(timer); \ + timer->function = func; \ + timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ + timer->data = (unsigned long) cfg; \ + add_timer(timer); \ + } while (0); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_CFG80211_P2P_DEV_IF) +#define WL_CFG80211_P2P_DEV_IF + +#ifdef WL_ENABLE_P2P_IF +#undef WL_ENABLE_P2P_IF +#endif + +#ifdef WL_SUPPORT_BACKPORTED_KPATCHES +#undef WL_SUPPORT_BACKPORTED_KPATCHES +#endif +#endif /* (LINUX_VERSION >= VERSION(3, 8, 0)) */ + +#ifndef WL_CFG80211_P2P_DEV_IF +#ifdef WL_NEWCFG_PRIVCMD_SUPPORT +#undef WL_NEWCFG_PRIVCMD_SUPPORT +#endif +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#if defined(WL_ENABLE_P2P_IF) && (defined(WL_CFG80211_P2P_DEV_IF) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))) +#error Disable 'WL_ENABLE_P2P_IF', if 'WL_CFG80211_P2P_DEV_IF' is enabled \ + or kernel version is 3.8.0 or above +#endif /* WL_ENABLE_P2P_IF && (WL_CFG80211_P2P_DEV_IF || (LINUX_VERSION >= VERSION(3, 8, 0))) */ + +#if !defined(WLP2P) && (defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)) +#error WLP2P not defined +#endif /* !WLP2P && (WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF) */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define bcm_struct_cfgdev struct wireless_dev +#else +#define bcm_struct_cfgdev struct net_device +#endif /* WL_CFG80211_P2P_DEV_IF */ + +extern void +wl_cfgp2p_listen_expired(unsigned long data); +extern bool +wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len); +extern void +wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel); +extern s32 +wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg); +extern void +wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg); +extern s32 +wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg); +extern s32 +wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, + u32 channel, u16 listen_ms, int bssidx); +extern s32 +wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, + chanspec_t chspec); +extern s32 +wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac); +extern s32 +wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac); +extern s32 +wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, chanspec_t chspec); + +extern s32 +wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index); + +extern s32 +wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg); +extern s32 +wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *ie, + u32 ie_len); +extern s32 +wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg); +extern s32 +wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, u32 num_chans, + u16 *channels, + s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, + p2p_scan_purpose_t p2p_scan_purpose); + +extern s32 +wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, + s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr); + +extern wpa_ie_fixed_t * +wl_cfgp2p_find_wpaie(u8 *parse, u32 len); + +extern wpa_ie_fixed_t * +wl_cfgp2p_find_wpsie(u8 *parse, u32 len); + +extern wifi_p2p_ie_t * +wl_cfgp2p_find_p2pie(u8 *parse, u32 len); + +extern wifi_wfd_ie_t * +wl_cfgp2p_find_wfdie(u8 *parse, u32 len); +extern s32 +wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, + s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len); +extern s32 +wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx); + +extern s32 +wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *index); +extern struct net_device * +wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx); +extern s32 +wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type); + + +extern s32 +wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +extern s32 +wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms); + +extern s32 +wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable); + +extern s32 +wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); + +extern s32 +wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, + wl_af_params_t *af_params, s32 bssidx); + +extern void +wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr, + struct ether_addr *out_int_addr); + +extern void +wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); +extern bool +wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); + +extern s32 +wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up); + + +extern s32 +wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev); + +extern s32 +wl_cfgp2p_down(struct bcm_cfg80211 *cfg); + +extern s32 +wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); + +extern s32 +wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); + +extern s32 +wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len); + +extern u8 * +wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id); + +extern u8* +wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib); + +extern u8 * +wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length); + +extern s32 +wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg); + +extern s32 +wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg); + +extern bool +wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops); + +#if defined(WL_CFG80211_P2P_DEV_IF) +extern struct wireless_dev * +wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg); + +extern int +wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); + +extern void +wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); + +extern int +wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ + +extern void +wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx); + +extern int +wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request); + +/* WiFi Direct */ +#define SOCIAL_CHAN_1 1 +#define SOCIAL_CHAN_2 6 +#define SOCIAL_CHAN_3 11 +#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ + (channel == SOCIAL_CHAN_2) || \ + (channel == SOCIAL_CHAN_3)) +#define SOCIAL_CHAN_CNT 3 +#define AF_PEER_SEARCH_CNT 2 +#define WL_P2P_WILDCARD_SSID "DIRECT-" +#define WL_P2P_WILDCARD_SSID_LEN 7 +#define WL_P2P_INTERFACE_PREFIX "p2p" +#define WL_P2P_TEMP_CHAN 11 +#define WL_P2P_AF_STATUS_OFFSET 9 + +/* If the provision discovery is for JOIN operations, + * or the device discoverablity frame is destined to GO + * then we need not do an internal scan to find GO. + */ +#define IS_ACTPUB_WITHOUT_GROUP_ID(p2p_ie, len) \ + (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL) + +#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ + ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ + (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) + +#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \ + ((subtype == P2P_PAF_GON_CONF) || \ + (subtype == P2P_PAF_INVITE_RSP) || \ + (subtype == P2P_PAF_PROVDIS_RSP))) +#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) +#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \ + (len == WL_P2P_WILDCARD_SSID_LEN)) +#endif /* _wl_cfgp2p_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c new file mode 100644 index 000000000000..38469c905fa2 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c @@ -0,0 +1,2455 @@ +/* + * Linux cfg80211 Vendor Extension Code + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgvendor.c 455257 2014-02-13 08:10:24Z $ +*/ + +/* + * New vendor interface additon to nl80211/cfg80211 to allow vendors + * to implement proprietary features over the cfg80211 stack. +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef PNO_SUPPORT +#include +#endif /* PNO_SUPPORT */ +#ifdef RTT_SUPPORT +#include +#endif /* RTT_SUPPORT */ +#ifdef RTT_SUPPORT +#include +#endif /* RTT_SUPPORT */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef PROP_TXSTATUS +#include +#endif +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) +/* + * This API is to be used for asynchronous vendor events. This + * shouldn't be used in response to a vendor command from its + * do_it handler context (instead wl_cfgvendor_send_cmd_reply should + * be used). + */ +int wl_cfgvendor_send_async_event(struct wiphy *wiphy, + struct net_device *dev, int event_id, const void *data, int len) +{ + u16 kflags; + struct sk_buff *skb; + + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags); + if (!skb) { + WL_ERR(("skb alloc failed")); + return -ENOMEM; + } + + /* Push the data to the skb */ + nla_put_nohdr(skb, len, data); + + cfg80211_vendor_event(skb, kflags); + + return 0; +} + +static int wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy, + struct net_device *dev, const void *data, int len) +{ + struct sk_buff *skb; + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + return -ENOMEM; + } + + /* Push the data to the skb */ + nla_put_nohdr(skb, len, data); + + return cfg80211_vendor_cmd_reply(skb); +} + +static int wl_cfgvendor_get_feature_set(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int reply; + + reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg)); + + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + &reply, sizeof(int)); + + if (unlikely(err)) + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + + return err; +} + +static int wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct sk_buff *skb; + int *reply; + int num, mem_needed, i; + + reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), &num); + + if (!reply) { + WL_ERR(("Could not get feature list matrix\n")); + err = -EINVAL; + return err; + } + + mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * num) + + ATTRIBUTE_U32_LEN; + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + err = -ENOMEM; + goto exit; + } + + nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, num); + for (i = 0; i < num; i++) { + nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply[i]); + } + + err = cfg80211_vendor_cmd_reply(skb); + + if (unlikely(err)) + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); +exit: + kfree(reply); + return err; +} + +static int +wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + uint8 random_mac_oui[DOT11_OUI_LEN]; + + type = nla_type(data); + + if (type == ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI) { + memcpy(random_mac_oui, nla_data(data), DOT11_OUI_LEN); + + err = dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg), random_mac_oui); + + if (unlikely(err)) + WL_ERR(("Bad OUI, could not set:%d \n", err)); + + } else { + err = -1; + } + + return err; +} + +#ifdef GSCAN_SUPPORT +int +wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, + struct net_device *dev, void *data, int len, wl_vendor_event_t event) +{ + u16 kflags; + const void *ptr; + struct sk_buff *skb; + int malloc_len, total, iter_cnt_to_send, cnt; + gscan_results_cache_t *cache = (gscan_results_cache_t *)data; + + total = len/sizeof(wifi_gscan_result_t); + while (total > 0) { + malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD; + if (malloc_len > NLMSG_DEFAULT_SIZE) { + malloc_len = NLMSG_DEFAULT_SIZE; + } + iter_cnt_to_send = + (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t); + total = total - iter_cnt_to_send; + + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags); + if (!skb) { + WL_ERR(("skb alloc failed")); + return -ENOMEM; + } + + while (cache && iter_cnt_to_send) { + ptr = (const void *) &cache->results[cache->tot_consumed]; + + if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) { + cnt = iter_cnt_to_send; + } else { + cnt = (cache->tot_count - cache->tot_consumed); + } + + iter_cnt_to_send -= cnt; + cache->tot_consumed += cnt; + /* Push the data to the skb */ + nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr); + if (cache->tot_consumed == cache->tot_count) { + cache = cache->next; + } + + } + + cfg80211_vendor_event(skb, kflags); + } + + return 0; +} + +static int +wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pno_gscan_capabilities_t *reply = NULL; + uint32 reply_len = 0; + + + reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GET_CAPABILITIES, NULL, &reply_len); + if (!reply) { + WL_ERR(("Could not get capabilities\n")); + err = -EINVAL; + return err; + } + + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + reply, reply_len); + + if (unlikely(err)) { + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + } + + kfree(reply); + return err; +} + +static int +wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0, type, band; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + uint16 *reply = NULL; + uint32 reply_len = 0, num_channels, mem_needed; + struct sk_buff *skb; + + type = nla_type(data); + + if (type == GSCAN_ATTRIBUTE_BAND) { + band = nla_get_u32(data); + } else { + return -EINVAL; + } + + reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len); + + if (!reply) { + WL_ERR(("Could not get channel list\n")); + err = -EINVAL; + return err; + } + num_channels = reply_len/ sizeof(uint32); + mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2); + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + err = -ENOMEM; + goto exit; + } + + nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels); + nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply); + + err = cfg80211_vendor_cmd_reply(skb); + + if (unlikely(err)) { + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + } +exit: + kfree(reply); + return err; +} + +static int +wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_results_cache_t *results, *iter; + uint32 reply_len, complete = 1; + int32 mem_needed, num_results_iter; + wifi_gscan_result_t *ptr; + uint16 num_scan_ids, num_results; + struct sk_buff *skb; + struct nlattr *scan_hdr, *complete_flag; + + err = dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg)); + if (err != BCME_OK) + return -EBUSY; + + err = dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); + if (err != BCME_OK) { + WL_ERR(("Can't obtain lock to access batch results %d\n", err)); + return -EBUSY; + } + results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len); + + if (!results) { + WL_ERR(("No results to send %d\n", err)); + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + results, 0); + + if (unlikely(err)) + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); + return err; + } + num_scan_ids = reply_len & 0xFFFF; + num_results = (reply_len & 0xFFFF0000) >> 16; + mem_needed = (num_results * sizeof(wifi_gscan_result_t)) + + (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) + + VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN; + + if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) { + mem_needed = (int32)NLMSG_DEFAULT_SIZE; + } + + WL_TRACE(("complete %d mem_needed %d max_mem %d\n", complete, mem_needed, + (int)NLMSG_DEFAULT_SIZE)); + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); + return -ENOMEM; + } + iter = results; + complete_flag = nla_reserve(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, + sizeof(complete)); + mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD); + + while (iter) { + num_results_iter = (mem_needed - (int32)GSCAN_BATCH_RESULT_HDR_LEN); + num_results_iter /= ((int32)sizeof(wifi_gscan_result_t)); + if (num_results_iter <= 0 || + ((iter->tot_count - iter->tot_consumed) > num_results_iter)) { + break; + } + scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS); + /* no more room? we are done then (for now) */ + if (scan_hdr == NULL) { + complete = 0; + break; + } + nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id); + nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag); + num_results_iter = iter->tot_count - iter->tot_consumed; + + nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter); + if (num_results_iter) { + ptr = &iter->results[iter->tot_consumed]; + iter->tot_consumed += num_results_iter; + nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, + num_results_iter * sizeof(wifi_gscan_result_t), ptr); + } + nla_nest_end(skb, scan_hdr); + mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN + + (num_results_iter * sizeof(wifi_gscan_result_t)); + iter = iter->next; + } + /* Returns TRUE if all result consumed */ + complete = dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg)); + memcpy(nla_data(complete_flag), &complete, sizeof(complete)); + dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg)); + return cfg80211_vendor_cmd_reply(skb); +} + +static int +wl_cfgvendor_initiate_gscan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type, tmp = len; + int run = 0xFF; + int flush = 0; + const struct nlattr *iter; + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE) + run = nla_get_u32(iter); + else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE) + flush = nla_get_u32(iter); + } + + if (run != 0xFF) { + err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush); + + if (unlikely(err)) { + WL_ERR(("Could not run gscan:%d \n", err)); + } + return err; + } else { + return -EINVAL; + } + + +} + +static int +wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + bool real_time = FALSE; + + type = nla_type(data); + + if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) { + real_time = nla_get_u32(data); + + err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time); + + if (unlikely(err)) { + WL_ERR(("Could not run gscan:%d \n", err)); + } + + } else { + err = -EINVAL; + } + + return err; +} + +static int +wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev, + gscan_scan_params_t *scan_param, int num) +{ + struct dhd_pno_gscan_channel_bucket *ch_bucket; + int k = 0; + int type, err = 0, rem; + const struct nlattr *cur, *next; + + nla_for_each_nested(cur, prev, rem) { + type = nla_type(cur); + ch_bucket = scan_param->channel_bucket; + + switch (type) { + case GSCAN_ATTRIBUTE_BUCKET_ID: + break; + case GSCAN_ATTRIBUTE_BUCKET_PERIOD: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + + ch_bucket[num].bucket_freq_multiple = + nla_get_u32(cur)/1000; + break; + case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].num_channels = + nla_get_u32(cur); + if (ch_bucket[num].num_channels > + GSCAN_MAX_CHANNELS_IN_BUCKET) { + WL_ERR(("channel range:%d,bucket:%d\n", + ch_bucket[num].num_channels, + num)); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_BUCKET_CHANNELS: + nla_for_each_nested(next, cur, rem) { + if (k >= + GSCAN_MAX_CHANNELS_IN_BUCKET) { + break; + } + if (nla_len(next) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].chan_list[k] = + nla_get_u32(next); + k++; + } + break; + case GSCAN_ATTRIBUTE_BUCKETS_BAND: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].band = (uint16) + nla_get_u32(cur); + break; + case GSCAN_ATTRIBUTE_REPORT_EVENTS: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].report_flag = (uint8) + nla_get_u32(cur); + break; + case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].repeat = (uint16) + nla_get_u32(cur); + break; + case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD: + if (nla_len(cur) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + ch_bucket[num].bucket_max_multiple = + nla_get_u32(cur)/1000; + break; + default: + WL_ERR(("bucket attribute type error %d\n", + type)); + err = -EINVAL; + goto exit; + } + } + +exit: + return err; +} + + +static int +wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_scan_params_t *scan_param; + int j = 0; + int type, tmp; + const struct nlattr *iter; + + scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL); + if (!scan_param) { + WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n")); + err = -EINVAL; + return err; + + } + + scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC; + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + + if (j >= GSCAN_MAX_CH_BUCKETS) { + break; + } + + switch (type) { + case GSCAN_ATTRIBUTE_BASE_PERIOD: + if (nla_len(iter) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + scan_param->scan_fr = nla_get_u32(iter)/1000; + break; + case GSCAN_ATTRIBUTE_NUM_BUCKETS: + if (nla_len(iter) != sizeof(uint32)) { + err = -EINVAL; + goto exit; + } + scan_param->nchannel_buckets = nla_get_u32(iter); + if (scan_param->nchannel_buckets >= + GSCAN_MAX_CH_BUCKETS) { + WL_ERR(("ncha_buck out of range %d\n", + scan_param->nchannel_buckets)); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_CH_BUCKET_1: + case GSCAN_ATTRIBUTE_CH_BUCKET_2: + case GSCAN_ATTRIBUTE_CH_BUCKET_3: + case GSCAN_ATTRIBUTE_CH_BUCKET_4: + case GSCAN_ATTRIBUTE_CH_BUCKET_5: + case GSCAN_ATTRIBUTE_CH_BUCKET_6: + case GSCAN_ATTRIBUTE_CH_BUCKET_7: + err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j); + if (err < 0) { + WL_ERR(("set_scan_cfg_buck error:%d\n", err)); + goto exit; + } + j++; + break; + default: + WL_ERR(("Unknown type %d\n", type)); + err = -EINVAL; + goto exit; + } + } + + err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_SCAN_CFG_ID, scan_param, 0); + + if (err < 0) { + WL_ERR(("Could not set GSCAN scan cfg\n")); + err = -EINVAL; + } + +exit: + kfree(scan_param); + return err; + +} + +static int +wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_hotlist_scan_params_t *hotlist_params; + int tmp, tmp1, tmp2, type, j = 0, dummy; + const struct nlattr *outer, *inner = NULL, *iter; + uint8 flush = 0; + struct bssid_t *pbssid; + + if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) { + WL_ERR(("buffer length :%d wrong - bail out.\n", len)); + return -EINVAL; + } + hotlist_params = kzalloc(sizeof(*hotlist_params) + + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)), + GFP_KERNEL); + + if (!hotlist_params) { + WL_ERR(("Cannot Malloc memory.\n")); + return -ENOMEM; + } + + hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT; + + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS: + pbssid = hotlist_params->bssid; + nla_for_each_nested(outer, iter, tmp) { + nla_for_each_nested(inner, outer, tmp1) { + type = nla_type(inner); + + switch (type) { + case GSCAN_ATTRIBUTE_BSSID: + if (nla_len(inner) != sizeof(pbssid[j].macaddr)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + memcpy(&(pbssid[j].macaddr), + nla_data(inner), + sizeof(pbssid[j].macaddr)); + break; + case GSCAN_ATTRIBUTE_RSSI_LOW: + if (nla_len(inner) != sizeof(uint8)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + pbssid[j].rssi_reporting_threshold = + (int8)nla_get_u8(inner); + break; + case GSCAN_ATTRIBUTE_RSSI_HIGH: + if (nla_len(inner) != sizeof(uint8)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + dummy = (int8)nla_get_u8(inner); + break; + default: + WL_ERR(("ATTR unknown %d\n", type)); + err = -EINVAL; + goto exit; + } + } + if (++j >= PFN_SWC_MAX_NUM_APS) { + WL_ERR(("cap hotlist max:%d\n", j)); + break; + } + } + hotlist_params->nbssid = j; + break; + case GSCAN_ATTRIBUTE_HOTLIST_FLUSH: + if (nla_len(iter) != sizeof(uint8)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + flush = nla_get_u8(iter); + break; + case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: + if (nla_len(iter) != sizeof(uint32)) { + WL_ERR(("type:%d length:%d not matching.\n", + type, nla_len(inner))); + err = -EINVAL; + goto exit; + } + hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter); + break; + default: + WL_ERR(("Unknown type %d\n", type)); + err = -EINVAL; + goto exit; + } + } + + if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) { + WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err)); + err = -EINVAL; + goto exit; + } +exit: + kfree(hotlist_params); + return err; +} + +#ifdef EPNO_SUPPORT +static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_epno_params_t *epno_params; + int tmp, tmp1, tmp2, type, num = 0; + const struct nlattr *outer, *inner, *iter; + uint8 flush = 0, i = 0; + uint16 num_visible_ssid = 0; + + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_EPNO_SSID_LIST: + nla_for_each_nested(outer, iter, tmp) { + epno_params = (dhd_epno_params_t *) + dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_GET_EPNO_SSID_ELEM, NULL, &num); + if (!epno_params) { + WL_ERR(("Failed to get SSID LIST buffer\n")); + err = -ENOMEM; + goto exit; + } + i++; + nla_for_each_nested(inner, outer, tmp1) { + type = nla_type(inner); + + switch (type) { + case GSCAN_ATTRIBUTE_EPNO_SSID: + memcpy(epno_params->ssid, + nla_data(inner), + DOT11_MAX_SSID_LEN); + break; + case GSCAN_ATTRIBUTE_EPNO_SSID_LEN: + len = nla_get_u8(inner); + if (len < DOT11_MAX_SSID_LEN) { + epno_params->ssid_len = len; + } else { + WL_ERR(("SSID toolong %d\n", + len)); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_EPNO_RSSI: + epno_params->rssi_thresh = + (int8) nla_get_u32(inner); + break; + case GSCAN_ATTRIBUTE_EPNO_FLAGS: + epno_params->flags = + nla_get_u8(inner); + if (!(epno_params->flags & + DHD_PNO_USE_SSID)) + num_visible_ssid++; + break; + case GSCAN_ATTRIBUTE_EPNO_AUTH: + epno_params->auth = + nla_get_u8(inner); + break; + } + } + } + break; + case GSCAN_ATTRIBUTE_EPNO_SSID_NUM: + num = nla_get_u8(iter); + break; + case GSCAN_ATTRIBUTE_EPNO_FLUSH: + flush = nla_get_u8(iter); + dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_EPNO_CFG_ID, NULL, flush); + break; + default: + WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); + err = -EINVAL; + goto exit; + } + + } + if (i != num) { + WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__, + num, i)); + err = -EINVAL; + } +exit: + /* Flush all configs if error condition */ + flush = (err < 0) ? TRUE: FALSE; + dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_EPNO_CFG_ID, &num_visible_ssid, flush); + return err; +} +#endif /* EPNO_SUPPORT */ + +#ifdef ANQPO_SUPPORT +static int wl_cfgvendor_gscan_anqpo_config(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = BCME_ERROR, rem, type, malloc_size, i = 0; + uint32 hs_list_size = 0; + int j, k, num_oi, oi_len; + wifi_passpoint_network *hs_list = NULL, *src_hs; + wl_anqpo_pfn_hs_list_t *anqpo_hs_list; + wl_anqpo_pfn_hs_t *dst_hs; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int tmp, tmp1; + const struct nlattr *outer, *inner, *iter; + static char iovar_buf[WLC_IOCTL_MAXLEN]; + char *rcid; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_ANQPO_HS_LIST: + if (hs_list) { + err = -EINVAL; + goto exit; + } + if (hs_list_size > GSCAN_ANQPO_MAX_HS_LIST_SIZE) { + err = -EINVAL; + goto exit; + } + if (hs_list_size > 0) { + hs_list = kmalloc(hs_list_size * + sizeof(wifi_passpoint_network), GFP_KERNEL); + if (!hs_list) { + WL_ERR(("%s: failed to allocate hs_list\n", + __func__)); + return -ENOMEM; + } + } + nla_for_each_nested(outer, iter, tmp) { + if (i == hs_list_size) + break; + + nla_for_each_nested(inner, outer, tmp1) { + type = nla_type(inner); + + switch (type) { + case GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID: + if (nla_len(inner) != sizeof(hs_list[i].id)) { + err = -EINVAL; + goto exit; + } + hs_list[i].id = nla_get_u32(inner); + WL_DBG(("%s: net id: %d\n", __func__, + hs_list[i].id)); + break; + case GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM: + if (nla_len(inner) != sizeof(hs_list[i].realm)) { + err = -EINVAL; + goto exit; + } + memcpy(hs_list[i].realm, nla_data(inner), + sizeof(hs_list[i].realm)); + WL_DBG(("%s: realm: %s\n", __func__, + hs_list[i].realm)); + break; + case GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID: + if (nla_len(inner) != + sizeof(hs_list[i].roamingConsortiumIds)) { + err = -EINVAL; + goto exit; + } + memcpy(hs_list[i].roamingConsortiumIds, + nla_data(inner), + sizeof(hs_list[i].roamingConsortiumIds)); + break; + case GSCAN_ATTRIBUTE_ANQPO_HS_PLMN: + if (nla_len(inner) != sizeof(hs_list[i].plmn)) { + err = -EINVAL; + goto exit; + } + memcpy(hs_list[i].plmn, nla_data(inner), + sizeof(hs_list[i].plmn)); + WL_DBG(("%s: plmn: %c %c %c\n", __func__, + hs_list[i].plmn[0], hs_list[i].plmn[1], + hs_list[i].plmn[2])); + break; + } + } + i++; + } + break; + case GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE: + if (nla_len(iter) != sizeof(hs_list_size)) { + err = -EINVAL; + goto exit; + } + hs_list_size = nla_get_u32(iter); + if ((hs_list_size == 0) || + (hs_list_size > GSCAN_ANQPO_MAX_HS_LIST_SIZE)) { + WL_ERR(("%s: ANQPO: %d\n", __func__, hs_list_size)); + err = -EINVAL; + goto exit; + } + WL_DBG(("%s: ANQPO: %d\n", __func__, hs_list_size)); + break; + default: + WL_ERR(("Unknown type: %d\n", type)); + err = -EINVAL; + goto exit; + } + } + + malloc_size = OFFSETOF(wl_anqpo_pfn_hs_list_t, hs) + + (hs_list_size * (sizeof(wl_anqpo_pfn_hs_t))); + anqpo_hs_list = (wl_anqpo_pfn_hs_list_t *)kmalloc(malloc_size, GFP_KERNEL); + if (anqpo_hs_list == NULL) { + WL_ERR(("failed to allocate anqpo_hs_list\n")); + err = -ENOMEM; + goto exit; + } + anqpo_hs_list->count = hs_list_size; + anqpo_hs_list->is_clear = (hs_list_size == 0) ? TRUE : FALSE; + + if ((hs_list_size > 0) && (NULL != hs_list)) { + src_hs = hs_list; + dst_hs = &anqpo_hs_list->hs[0]; + for (i = 0; i < hs_list_size; i++, src_hs++, dst_hs++) { + num_oi = 0; + dst_hs->id = src_hs->id; + dst_hs->realm.length = strlen(src_hs->realm)+1; + memcpy(dst_hs->realm.data, src_hs->realm, dst_hs->realm.length); + memcpy(dst_hs->plmn.mcc, src_hs->plmn, ANQPO_MCC_LENGTH); + memcpy(dst_hs->plmn.mnc, src_hs->plmn, ANQPO_MCC_LENGTH); + for (j = 0; j < ANQPO_MAX_PFN_HS; j++) { + oi_len = 0; + if (0 != src_hs->roamingConsortiumIds[j]) { + num_oi++; + rcid = (char *)&src_hs->roamingConsortiumIds[j]; + for (k = 0; k < ANQPO_MAX_OI_LENGTH; k++) + if (0 != rcid[k]) oi_len++; + + dst_hs->rc.oi[j].length = oi_len; + memcpy(dst_hs->rc.oi[j].data, rcid, oi_len); + } + } + dst_hs->rc.numOi = num_oi; + } + } + + err = wldev_iovar_setbuf(bcmcfg_to_prmry_ndev(cfg), "anqpo_pfn_hs_list", + anqpo_hs_list, malloc_size, iovar_buf, WLC_IOCTL_MAXLEN, NULL); + + kfree(anqpo_hs_list); +exit: + kfree(hs_list); + return err; +} +#endif /* ANQPO_SUPPORT */ + +static int +wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0, tmp, type; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_batch_params_t batch_param; + const struct nlattr *iter; + + batch_param.mscan = batch_param.bestn = 0; + batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET; + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + + switch (type) { + case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN: + batch_param.bestn = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE: + batch_param.mscan = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_REPORT_THRESHOLD: + batch_param.buffer_threshold = nla_get_u32(iter); + break; + default: + WL_ERR(("Unknown type %d\n", type)); + break; + } + } + + if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_BATCH_SCAN_CFG_ID, + &batch_param, 0) < 0) { + WL_ERR(("Could not set batch cfg\n")); + err = -EINVAL; + return err; + } + + return err; +} + +static int +wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + gscan_swc_params_t *significant_params; + int tmp, tmp1, tmp2, type, j = 0; + const struct nlattr *outer, *inner, *iter; + uint8 flush = 0; + wl_pfn_significant_bssid_t *bssid; + + significant_params = (gscan_swc_params_t *) kzalloc(len, GFP_KERNEL); + if (!significant_params) { + WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes \n", len)); + return -ENOMEM; + } + + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + + switch (type) { + case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH: + flush = nla_get_u8(iter); + break; + case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE: + significant_params->rssi_window = nla_get_u16(iter); + break; + case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: + significant_params->lost_ap_window = nla_get_u16(iter); + break; + case GSCAN_ATTRIBUTE_MIN_BREACHING: + significant_params->swc_threshold = nla_get_u16(iter); + break; + case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS: + bssid = significant_params->bssid_elem_list; + nla_for_each_nested(outer, iter, tmp) { + nla_for_each_nested(inner, outer, tmp1) { + switch (nla_type(inner)) { + case GSCAN_ATTRIBUTE_BSSID: + memcpy(&(bssid[j].macaddr), + nla_data(inner), + ETHER_ADDR_LEN); + break; + case GSCAN_ATTRIBUTE_RSSI_HIGH: + bssid[j].rssi_high_threshold + = (int8) nla_get_u8(inner); + break; + case GSCAN_ATTRIBUTE_RSSI_LOW: + bssid[j].rssi_low_threshold + = (int8) nla_get_u8(inner); + break; + default: + WL_ERR(("ATTR unknown %d\n", + type)); + break; + } + } + j++; + } + break; + default: + WL_ERR(("Unknown type %d\n", type)); + break; + } + } + significant_params->nbssid = j; + + if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), + DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, + significant_params, flush) < 0) { + WL_ERR(("Could not set GSCAN significant cfg\n")); + err = -EINVAL; + goto exit; + } +exit: + kfree(significant_params); + return err; +} + +static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = -EINVAL; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + uint32 lazy_roam_enable_flag; + + type = nla_type(data); + + if (type == GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE) { + lazy_roam_enable_flag = nla_get_u32(data); + + err = dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg), + lazy_roam_enable_flag); + + if (unlikely(err)) + WL_ERR(("Could not enable lazy roam:%d \n", err)); + + } + return err; +} + +static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0, tmp, type; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + wlc_roam_exp_params_t roam_param; + const struct nlattr *iter; + + memset(&roam_param, 0, sizeof(roam_param)); + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + + switch (type) { + case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD: + roam_param.a_band_boost_threshold = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD: + roam_param.a_band_penalty_threshold = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR: + roam_param.a_band_boost_factor = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR: + roam_param.a_band_penalty_factor = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST: + roam_param.a_band_max_boost = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS: + roam_param.cur_bssid_boost = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER: + roam_param.alert_roam_trigger_threshold = nla_get_u32(iter); + break; + } + } + + if (dhd_dev_set_lazy_roam_cfg(bcmcfg_to_prmry_ndev(cfg), &roam_param) < 0) { + WL_ERR(("Could not set batch cfg\n")); + err = -EINVAL; + } + return err; +} + +/* small helper function */ +static wl_bssid_pref_cfg_t * +create_bssid_pref_cfg(uint32 num) +{ + uint32 mem_needed; + wl_bssid_pref_cfg_t *bssid_pref; + + mem_needed = sizeof(wl_bssid_pref_cfg_t); + if (num) + mem_needed += (num - 1) * sizeof(wl_bssid_pref_list_t); + bssid_pref = (wl_bssid_pref_cfg_t *) kmalloc(mem_needed, GFP_KERNEL); + return bssid_pref; +} + +static int +wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + wl_bssid_pref_cfg_t *bssid_pref = NULL; + wl_bssid_pref_list_t *bssids; + int tmp, tmp1, tmp2, type; + const struct nlattr *outer, *inner, *iter; + uint32 flush = 0, i = 0, num = 0; + + /* Assumption: NUM attribute must come first */ + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_NUM_BSSID: + num = nla_get_u32(iter); + if (num > MAX_BSSID_PREF_LIST_NUM) { + WL_ERR(("Too many Preferred BSSIDs!\n")); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH: + flush = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_BSSID_PREF_LIST: + if (!num) + return -EINVAL; + if ((bssid_pref = create_bssid_pref_cfg(num)) == NULL) { + WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__)); + err = -ENOMEM; + goto exit; + } + bssid_pref->count = num; + bssids = bssid_pref->bssids; + nla_for_each_nested(outer, iter, tmp) { + if (i >= num) { + WL_ERR(("CFGs don't seem right!\n")); + err = -EINVAL; + goto exit; + } + nla_for_each_nested(inner, outer, tmp1) { + type = nla_type(inner); + switch (type) { + case GSCAN_ATTRIBUTE_BSSID_PREF: + memcpy(&(bssids[i].bssid), + nla_data(inner), ETHER_ADDR_LEN); + /* not used for now */ + bssids[i].flags = 0; + break; + case GSCAN_ATTRIBUTE_RSSI_MODIFIER: + bssids[i].rssi_factor = + (int8) nla_get_u32(inner); + break; + } + } + i++; + } + break; + default: + WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); + break; + } + } + + if (!bssid_pref) { + /* What if only flush is desired? */ + if (flush) { + if ((bssid_pref = create_bssid_pref_cfg(0)) == NULL) { + WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__)); + err = -ENOMEM; + goto exit; + } + bssid_pref->count = 0; + } else { + err = -EINVAL; + goto exit; + } + } + err = dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg), + bssid_pref, flush); +exit: + kfree(bssid_pref); + return err; +} + + +static int +wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + maclist_t *blacklist = NULL; + int err = 0; + int type, tmp; + const struct nlattr *iter; + uint32 mem_needed = 0, flush = 0, i = 0, num = 0; + + /* Assumption: NUM attribute must come first */ + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_NUM_BSSID: + num = nla_get_u32(iter); + if (num > MAX_BSSID_BLACKLIST_NUM) { + WL_ERR(("Too many Blacklist BSSIDs!\n")); + err = -EINVAL; + goto exit; + } + break; + case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH: + flush = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_BLACKLIST_BSSID: + if (num) { + if (!blacklist) { + mem_needed = sizeof(maclist_t) + + sizeof(struct ether_addr) * (num - 1); + blacklist = (maclist_t *) + kmalloc(mem_needed, GFP_KERNEL); + if (!blacklist) { + WL_ERR(("%s: Can't malloc %d bytes\n", + __FUNCTION__, mem_needed)); + err = -ENOMEM; + goto exit; + } + blacklist->count = num; + } + if (i >= num) { + WL_ERR(("CFGs don't seem right!\n")); + err = -EINVAL; + goto exit; + } + memcpy(&(blacklist->ea[i]), + nla_data(iter), ETHER_ADDR_LEN); + i++; + } + break; + default: + WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); + break; + } + } + err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg), + blacklist, mem_needed, flush); +exit: + kfree(blacklist); + return err; +} + +static int +wl_cfgvendor_set_ssid_whitelist(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + wl_ssid_whitelist_t *ssid_whitelist = NULL; + wlc_ssid_t *ssid_elem; + int tmp, tmp2, mem_needed = 0, type; + const struct nlattr *inner, *iter; + uint32 flush = 0, i = 0, num = 0; + + /* Assumption: NUM attribute must come first */ + nla_for_each_attr(iter, data, len, tmp2) { + type = nla_type(iter); + switch (type) { + case GSCAN_ATTRIBUTE_NUM_WL_SSID: + num = nla_get_u32(iter); + if (num > MAX_SSID_WHITELIST_NUM) { + WL_ERR(("Too many WL SSIDs!\n")); + err = -EINVAL; + goto exit; + } + mem_needed = sizeof(wl_ssid_whitelist_t); + if (num) + mem_needed += (num - 1) * sizeof(ssid_info_t); + ssid_whitelist = (wl_ssid_whitelist_t *) + kzalloc(mem_needed, GFP_KERNEL); + if (ssid_whitelist == NULL) { + WL_ERR(("%s: Can't malloc %d bytes\n", + __FUNCTION__, mem_needed)); + err = -ENOMEM; + goto exit; + } + ssid_whitelist->ssid_count = num; + break; + case GSCAN_ATTRIBUTE_WL_SSID_FLUSH: + flush = nla_get_u32(iter); + break; + case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM: + if (!num || !ssid_whitelist) { + WL_ERR(("num ssid is not set!\n")); + return -EINVAL; + } + if (i >= num) { + WL_ERR(("CFGs don't seem right!\n")); + err = -EINVAL; + goto exit; + } + ssid_elem = &ssid_whitelist->ssids[i]; + nla_for_each_nested(inner, iter, tmp) { + type = nla_type(inner); + switch (type) { + case GSCAN_ATTRIBUTE_WHITELIST_SSID: + memcpy(ssid_elem->SSID, + nla_data(inner), + DOT11_MAX_SSID_LEN); + break; + case GSCAN_ATTRIBUTE_WL_SSID_LEN: + ssid_elem->SSID_len = (uint8) + nla_get_u32(inner); + break; + } + } + i++; + break; + default: + WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); + break; + } + } + + err = dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg), + ssid_whitelist, mem_needed, flush); +exit: + kfree(ssid_whitelist); + return err; +} +#endif /* GSCAN_SUPPORT */ + +#ifdef RSSI_MONITOR_SUPPORT +static int +wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0, tmp, type, start = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int8 max_rssi = 0, min_rssi = 0; + const struct nlattr *iter; + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + switch (type) { + case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI: + max_rssi = (int8) nla_get_u32(iter); + break; + case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI: + min_rssi = (int8) nla_get_u32(iter); + break; + case RSSI_MONITOR_ATTRIBUTE_START: + start = nla_get_u32(iter); + } + } + + if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg), + start, max_rssi, min_rssi) < 0) { + WL_ERR(("Could not set rssi monitor cfg\n")); + err = -EINVAL; + } + return err; +} +#endif /* RSSI_MONITOR_SUPPORT */ + +#ifdef RTT_SUPPORT +void +wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data) +{ + struct wireless_dev *wdev = (struct wireless_dev *)ctx; + struct wiphy *wiphy; + struct sk_buff *skb; + uint32 complete = 0; + gfp_t kflags; + rtt_result_t *rtt_result; + rtt_results_header_t *rtt_header; + struct list_head *rtt_cache_list; + struct nlattr *rtt_nl_hdr; + wiphy = wdev->wiphy; + + WL_DBG(("In\n")); + /* Push the data to the skb */ + if (!rtt_data) { + WL_ERR(("rtt_data is NULL\n")); + goto exit; + } + rtt_cache_list = (struct list_head *)rtt_data; + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + list_for_each_entry(rtt_header, rtt_cache_list, list) { + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_event_alloc(wiphy, rtt_header->result_tot_len + 100, + GOOGLE_RTT_COMPLETE_EVENT, kflags); + if (!skb) { + WL_ERR(("skb alloc failed")); + goto exit; + } + if (list_is_last(&rtt_header->list, rtt_cache_list)) { + complete = 1; + } + nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, complete); + rtt_nl_hdr = nla_nest_start(skb, RTT_ATTRIBUTE_RESULTS_PER_TARGET); + if (!rtt_nl_hdr) { + WL_ERR(("rtt_nl_hdr is NULL\n")); + break; + } + nla_put(skb, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN, &rtt_header->peer_mac); + nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_CNT, rtt_header->result_cnt); + list_for_each_entry(rtt_result, &rtt_header->result_list, list) { + nla_put(skb, RTT_ATTRIBUTE_RESULT, + rtt_result->report_len, &rtt_result->report); + } + nla_nest_end(skb, rtt_nl_hdr); + cfg80211_vendor_event(skb, kflags); + } +exit: + return; +} + +static int +wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) { + int err = 0, rem, rem1, rem2, type; + int target_cnt; + rtt_config_params_t rtt_param; + rtt_target_info_t* rtt_target = NULL; + const struct nlattr *iter, *iter1, *iter2; + int8 eabuf[ETHER_ADDR_STR_LEN]; + int8 chanbuf[CHANSPEC_STR_LEN]; + int32 feature_set = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + rtt_capabilities_t capability; + feature_set = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg)); + + WL_DBG(("In\n")); + err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt); + if (err < 0) { + WL_ERR(("failed to register rtt_noti_callback\n")); + goto exit; + } + err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability); + if (err < 0) { + WL_ERR(("failed to get the capability\n")); + goto exit; + } + memset(&rtt_param, 0, sizeof(rtt_param)); + if (len <= 0) { + WL_ERR(("Length of the nlattr is not valid len : %d\n", len)); + err = BCME_ERROR; + goto exit; + } + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case RTT_ATTRIBUTE_TARGET_CNT: + target_cnt = nla_get_u8(iter); + if ((target_cnt <= 0) || (target_cnt > RTT_MAX_TARGET_CNT)) { + WL_ERR(("target_cnt is not valid : %d\n", + target_cnt)); + err = BCME_RANGE; + goto exit; + } + rtt_param.rtt_target_cnt = target_cnt; + rtt_param.target_info = kzalloc(TARGET_INFO_SIZE(target_cnt), GFP_KERNEL); + if (rtt_param.target_info == NULL) { + WL_ERR(("failed to allocate target info for (%d)\n", target_cnt)); + err = BCME_NOMEM; + goto exit; + } + break; + case RTT_ATTRIBUTE_TARGET_INFO: + /* Added this variable for safe check to avoid crash + * incase the caller did not respect the order + */ + if (rtt_param.target_info == NULL) { + WL_ERR(("rtt_target_info is NULL\n")); + err = BCME_NOMEM; + goto exit; + } + rtt_target = rtt_param.target_info; + nla_for_each_nested(iter1, iter, rem1) { + nla_for_each_nested(iter2, iter1, rem2) { + type = nla_type(iter2); + switch (type) { + case RTT_ATTRIBUTE_TARGET_MAC: + memcpy(&rtt_target->addr, nla_data(iter2), + ETHER_ADDR_LEN); + break; + case RTT_ATTRIBUTE_TARGET_TYPE: + rtt_target->type = nla_get_u8(iter2); + if (rtt_target->type == RTT_INVALID || + (rtt_target->type == RTT_ONE_WAY && + !capability.rtt_one_sided_supported)) { + WL_ERR(("doesn't support RTT type" + " : %d\n", + rtt_target->type)); + err = -EINVAL; + goto exit; + } + break; + case RTT_ATTRIBUTE_TARGET_PEER: + rtt_target->peer = nla_get_u8(iter2); + break; + case RTT_ATTRIBUTE_TARGET_CHAN: + memcpy(&rtt_target->channel, nla_data(iter2), + sizeof(rtt_target->channel)); + break; + case RTT_ATTRIBUTE_TARGET_INTERVAL: + rtt_target->interval = nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_NUM_BURST: + rtt_target->num_burst = nla_get_u32(iter2); + if (!(rtt_target->num_burst == 1 || + ISPOWEROF2(rtt_target->num_burst))) { + WL_ERR(("%d value must be power of 2" + " or 1\n", + rtt_target->num_burst)); + err = -EINVAL; + goto exit; + } + break; + case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST: + rtt_target->num_frames_per_burst = + nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM: + rtt_target->num_retries_per_ftm = + nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR: + rtt_target->num_retries_per_ftmr = + nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_LCI: + rtt_target->LCI_request = nla_get_u8(iter2); + break; + case RTT_ATTRIBUTE_TARGET_LCR: + rtt_target->LCI_request = nla_get_u8(iter2); + break; + case RTT_ATTRIBUTE_TARGET_BURST_TIMEOUT: + rtt_target->burst_timeout = nla_get_u32(iter2); + break; + case RTT_ATTRIBUTE_TARGET_BW: + rtt_target->bw = nla_get_u8(iter2); + } + } + /* convert to chanspec value */ + rtt_target->chanspec = + dhd_rtt_convert_to_chspec(rtt_target->channel); + if (rtt_target->chanspec == 0) { + WL_ERR(("Channel is not valid \n")); + err = -EINVAL; + goto exit; + } + WL_INFO(("Target addr %s, Channel : %s for RTT \n", + bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, + eabuf), + wf_chspec_ntoa(rtt_target->chanspec, chanbuf))); + rtt_target++; + } + break; + } + } + WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt)); + if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) { + WL_ERR(("Could not set RTT configuration\n")); + err = -EINVAL; + } +exit: + /* free the target info list */ + if (rtt_param.target_info) { + kfree(rtt_param.target_info); + rtt_param.target_info = NULL; + } + return err; +} + +static int +wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) +{ + int err = 0, rem, type, target_cnt = 0; + int target_cnt_chk = 0; + const struct nlattr *iter; + struct ether_addr *mac_list = NULL, *mac_addr = NULL; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + if (len <= 0) { + WL_ERR(("Length of nlattr is not valid len : %d\n", len)); + err = -EINVAL; + goto exit; + } + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case RTT_ATTRIBUTE_TARGET_CNT: + if (mac_list != NULL) { + WL_ERR(("mac_list is not NULL\n")); + err = -EINVAL; + goto exit; + } + target_cnt = nla_get_u8(iter); + if ((target_cnt > 0) && (target_cnt < RTT_MAX_TARGET_CNT)) { + mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN, + GFP_KERNEL); + if (mac_list == NULL) { + WL_ERR(("failed to allocate mem for mac list\n")); + err = -EINVAL; + goto exit; + } + mac_addr = &mac_list[0]; + } else { + /* cancel the current whole RTT process */ + goto cancel; + } + break; + case RTT_ATTRIBUTE_TARGET_MAC: + if (mac_addr) { + memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN); + target_cnt_chk++; + if (target_cnt_chk > target_cnt) { + WL_ERR(("over target count\n")); + err = -EINVAL; + goto exit; + } + break; + } else { + WL_ERR(("mac_list is NULL\n")); + err = -EINVAL; + goto exit; + } + } + } +cancel: + if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) { + WL_ERR(("Could not cancel RTT configuration\n")); + err = -EINVAL; + } + +exit: + if (mac_list) { + kfree(mac_list); + } + return err; +} +static int +wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + rtt_capabilities_t capability; + + err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability); + if (unlikely(err)) { + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + goto exit; + } + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + &capability, sizeof(capability)); + + if (unlikely(err)) { + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + } +exit: + return err; +} + +#endif /* RTT_SUPPORT */ + +#if defined(KEEP_ALIVE) +static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) +{ + /* max size of IP packet for keep alive */ + const int MKEEP_ALIVE_IP_PKT_MAX = 256; + + int ret = BCME_OK, rem, type; + u8 mkeep_alive_id = 0; + u8 *ip_pkt = NULL; + u16 ip_pkt_len = 0; + u8 src_mac[ETHER_ADDR_LEN]; + u8 dst_mac[ETHER_ADDR_LEN]; + u32 period_msec = 0; + const struct nlattr *iter; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhd_pub = cfg->pub; + gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case MKEEP_ALIVE_ATTRIBUTE_ID: + mkeep_alive_id = nla_get_u8(iter); + break; + case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN: + ip_pkt_len = nla_get_u16(iter); + if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) { + ret = BCME_BADARG; + goto exit; + } + break; + case MKEEP_ALIVE_ATTRIBUTE_IP_PKT: + ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags); + if (ip_pkt == NULL) { + ret = BCME_NOMEM; + WL_ERR(("Failed to allocate mem for ip packet\n")); + goto exit; + } + memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len); + break; + case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR: + memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN); + break; + case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR: + memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN); + break; + case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC: + period_msec = nla_get_u32(iter); + break; + default: + WL_ERR(("Unknown type: %d\n", type)); + ret = BCME_BADARG; + goto exit; + } + } + + ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac, + dst_mac, period_msec); + if (ret < 0) { + WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret)); + } + +exit: + if (ip_pkt) { + kfree(ip_pkt); + } + + return ret; +} + +static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) +{ + int ret = BCME_OK, rem, type; + u8 mkeep_alive_id = 0; + const struct nlattr *iter; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhd_pub = cfg->pub; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case MKEEP_ALIVE_ATTRIBUTE_ID: + mkeep_alive_id = nla_get_u8(iter); + break; + default: + WL_ERR(("Unknown type: %d\n", type)); + ret = BCME_BADARG; + break; + } + } + + ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id); + if (ret < 0) { + WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret)); + } + + return ret; +} +#endif /* defined(KEEP_ALIVE) */ + +static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int err = 0; + int data_len = 0; + + WL_INFO(("%s: Enter \n", __func__)); + + if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) { + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + data_len = strlen(cfg->ioctl_buf); + cfg->ioctl_buf[data_len] = '\0'; + } + + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + cfg->ioctl_buf, data_len+1); + if (unlikely(err)) + WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + else + WL_INFO(("Vendor Command reply sent successfully!\n")); + + return err; +} + +#ifdef LINKSTAT_SUPPORT +#define NUM_RATE 32 +#define NUM_PEER 1 +#define NUM_CHAN 11 +static int +wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + char *iovar_buf = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int err = 0; + wifi_iface_stat *iface; + wifi_radio_stat *radio; + wl_wme_cnt_t *wl_wme_cnt; + wl_cnt_t *wl_cnt; + char *output; +#ifdef LINKSTAT_V2 + int i = 0; + wifi_radio_stat_v2 *p_radio_stat_v2 = NULL; + wifi_rate_stat_v2 *p_wifi_rate_stat_v2 = NULL; + wifi_rate_stat *p_wifi_rate_stat = NULL; +#endif /* LINKSTAT_V2 */ + + int radstat_buflen = sizeof(wifi_radio_stat) + NUM_CHAN * sizeof(wifi_channel_stat); + int iface_buflen = sizeof(wifi_iface_stat) + NUM_PEER * sizeof(wifi_peer_info); + int ratestat_buflen = NUM_RATE * sizeof(wifi_rate_stat); + + WL_TRACE(("%s: Enter \n", __FUNCTION__)); + + RETURN_EIO_IF_NOT_UP(cfg); + + iovar_buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL); + if (unlikely(!iovar_buf)) { + WL_ERR(("%s: link stats buf alloc fails\n", __FUNCTION__)); + return -ENOMEM; + } + + ASSERT((radstat_buflen + iface_buflen + ratestat_buflen) <= + (sizeof(char) * WLC_IOCTL_MAXLEN)); + + output = iovar_buf; + radio = (wifi_radio_stat *)output; + + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("%s: ioctl error(%d) for radiostat - size = %zu\n", + __FUNCTION__, err, sizeof(wifi_radio_stat))); + goto exit; + } + +#ifdef LINKSTAT_V2 + p_radio_stat_v2 = (wifi_radio_stat_v2 *)cfg->ioctl_buf; + memcpy(output, &(p_radio_stat_v2->radio), sizeof(wifi_radio_stat)); +#else + memcpy(output, cfg->ioctl_buf, sizeof(wifi_radio_stat)); +#endif /* LINKSTAT_V2 */ + radio->num_channels = NUM_CHAN; + output += radstat_buflen; + + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "wme_counters", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("%s: ioctl error(%d) for wme_counters\n", __FUNCTION__, err)); + goto exit; + } + wl_wme_cnt = (wl_wme_cnt_t *)cfg->ioctl_buf; + iface = (wifi_iface_stat *)output; + + iface->ac[WIFI_AC_VO].ac = WIFI_AC_VO; + iface->ac[WIFI_AC_VO].tx_mpdu = wl_wme_cnt->tx[AC_VO].packets; + iface->ac[WIFI_AC_VO].rx_mpdu = wl_wme_cnt->rx[AC_VO].packets; + iface->ac[WIFI_AC_VO].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VO].packets; + + iface->ac[WIFI_AC_VI].ac = WIFI_AC_VI; + iface->ac[WIFI_AC_VI].tx_mpdu = wl_wme_cnt->tx[AC_VI].packets; + iface->ac[WIFI_AC_VI].rx_mpdu = wl_wme_cnt->rx[AC_VI].packets; + iface->ac[WIFI_AC_VI].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VI].packets; + + iface->ac[WIFI_AC_BE].ac = WIFI_AC_BE; + iface->ac[WIFI_AC_BE].tx_mpdu = wl_wme_cnt->tx[AC_BE].packets; + iface->ac[WIFI_AC_BE].rx_mpdu = wl_wme_cnt->rx[AC_BE].packets; + iface->ac[WIFI_AC_BE].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BE].packets; + + iface->ac[WIFI_AC_BK].ac = WIFI_AC_BK; + iface->ac[WIFI_AC_BK].tx_mpdu = wl_wme_cnt->tx[AC_BK].packets; + iface->ac[WIFI_AC_BK].rx_mpdu = wl_wme_cnt->rx[AC_BK].packets; + iface->ac[WIFI_AC_BK].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BK].packets; + + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("%s: ioctl error(%d) for counters - size = %zu\n", + __FUNCTION__, err, sizeof(wl_cnt_t))); + goto exit; + } + wl_cnt = (wl_cnt_t *)cfg->ioctl_buf; + iface->ac[WIFI_AC_BE].retries = wl_cnt->txretry; + iface->beacon_rx = wl_cnt->rxbeaconmbss; + + err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &iface->rssi_mgmt); + if (unlikely(err)) { + WL_ERR(("%s: get_rssi error(%d)\n", __FUNCTION__, err)); + goto exit; + } + + iface->num_peers = NUM_PEER; + iface->peer_info->num_rate = NUM_RATE; + + output = (char *)iface + iface_buflen; + + err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("%s: ioctl error(%d) for ratestat - size = %d\n", + __FUNCTION__, err, ratestat_buflen)); + goto exit; + } +#ifdef LINKSTAT_V2 + /* ratestat structure is mismatched with android framework need to recompose it */ + for (i = 0; i < NUM_RATE; i++) { + p_wifi_rate_stat_v2 = + (wifi_rate_stat_v2 *)(cfg->ioctl_buf + i*sizeof(wifi_rate_stat_v2)); + + /* transform wifi_rate_v2 to wifi_rate */ + p_wifi_rate_stat = (wifi_rate_stat *)output; + p_wifi_rate_stat->rate.preamble = p_wifi_rate_stat_v2->rate.preamble; + p_wifi_rate_stat->rate.nss = p_wifi_rate_stat_v2->rate.nss; + p_wifi_rate_stat->rate.bw = p_wifi_rate_stat_v2->rate.bw; + p_wifi_rate_stat->rate.rateMcsIdx = p_wifi_rate_stat_v2->rate.rateMcsIdx; + p_wifi_rate_stat->rate.bitrate = p_wifi_rate_stat_v2->rate.bitrate; + p_wifi_rate_stat->tx_mpdu = p_wifi_rate_stat_v2->tx_mpdu; + p_wifi_rate_stat->rx_mpdu = p_wifi_rate_stat_v2->rx_mpdu; + p_wifi_rate_stat->mpdu_lost = p_wifi_rate_stat_v2->mpdu_lost; + p_wifi_rate_stat->retries = p_wifi_rate_stat_v2->retries; + p_wifi_rate_stat->retries_short = p_wifi_rate_stat_v2->retries_short; + p_wifi_rate_stat->retries_long = p_wifi_rate_stat_v2->retries_long; + + output += sizeof(wifi_rate_stat); + } +#else + memcpy(output, cfg->ioctl_buf, ratestat_buflen); +#endif /* LINKSTAT_V2 */ + if (unlikely(radio->num_channels != NUM_CHAN)) { + WL_ERR(("%s: error! num_channels corrupted. value=%d \n", + __FUNCTION__, (int)radio->num_channels)); + goto exit; + } + err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), + iovar_buf, radstat_buflen + iface_buflen + ratestat_buflen); + if (unlikely(err)) { + WL_ERR(("%s: Vendor Command reply failed ret:%d \n", __FUNCTION__, err)); + } + +exit: + if (iovar_buf) { + kfree(iovar_buf); + } + + return err; +} +#endif /* LINKSTAT_SUPPORT */ + +static int wl_cfgvendor_set_country(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = BCME_ERROR, rem, type; + char country_code[WLC_CNTRY_BUF_SZ] = {0}; + const struct nlattr *iter; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case ANDR_WIFI_ATTRIBUTE_COUNTRY: + memcpy(country_code, nla_data(iter), + MIN(nla_len(iter), WLC_CNTRY_BUF_SZ)); + break; + default: + WL_ERR(("Unknown type: %d\n", type)); + return err; + } + } + + err = wldev_set_country(wdev->netdev, country_code, true, true); + if (err < 0) { + WL_ERR(("Set country failed ret:%d\n", err)); + } + + return err; +} + +static const struct wiphy_vendor_command wl_vendor_cmds [] = { + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_PRIV_STR + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_priv_string_handler + }, +#ifdef GSCAN_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_get_capabilities + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_scan_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_batch_scan_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_initiate_gscan + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_enable_full_scan_result + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_HOTLIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_hotlist_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_significant_change_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_get_batch_results + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_get_channel_list + }, +#endif /* GSCAN_SUPPORT */ +#ifdef RTT_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_SET_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_set_config + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_CANCEL_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_cancel_config + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_GETCAPABILITY + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_get_capability + }, +#endif /* RTT_SUPPORT */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_get_feature_set + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_get_feature_set_matrix + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_RANDOM_MAC_OUI + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_rand_mac_oui + }, +#ifdef LINKSTAT_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = LSTATS_SUBCMD_GET_INFO + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_lstats_get_info + }, +#endif /* LINKSTAT_SUPPORT */ +#ifdef KEEP_ALIVE + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_start_mkeep_alive + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_stop_mkeep_alive + }, +#endif /* KEEP_ALIVE */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_SET_COUNTRY + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_country + }, +#ifdef GSCAN_SUPPORT +#ifdef EPNO_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_epno_cfg + + }, +#endif /* EPNO_SUPPORT */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_ssid_whitelist + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_lazy_roam_cfg + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_enable_lazy_roam + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_BSSID_PREF + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_bssid_pref + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_bssid_blacklist + }, +#ifdef ANQPO_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_ANQPO_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_anqpo_config + }, +#endif /* ANQPO_SUPPORT */ +#endif /* GSCAN_SUPPORT */ +#ifdef RSSI_MONITOR_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_rssi_monitor + }, +#endif /* RSSI_MONITOR_SUPPORT */ +}; + +static const struct nl80211_vendor_cmd_info wl_vendor_events [] = { + { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC }, + { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR }, +#ifdef GSCAN_SUPPORT + { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT }, + { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT }, + { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT }, + { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT }, +#endif /* GSCAN_SUPPORT */ + { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT }, +#ifdef GSCAN_SUPPORT + { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT }, + { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT }, + { OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT }, +#endif /* GSCAN_SUPPORT */ + { OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT }, + { OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT }, +#ifdef ANQPO_SUPPORT + { OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT }, +#endif /* ANQPO_SUPPORT */ + { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT }, +#ifdef KEEP_ALIVE + { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT }, +#endif /* KEEP_ALIVE */ +}; + +int wl_cfgvendor_attach(struct wiphy *wiphy) +{ + + WL_INFO(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n", + NL80211_CMD_VENDOR)); + + wiphy->vendor_commands = wl_vendor_cmds; + wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds); + wiphy->vendor_events = wl_vendor_events; + wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events); + + return 0; +} + +int wl_cfgvendor_detach(struct wiphy *wiphy) +{ + WL_INFO(("Vendor: Unregister BRCM cfg80211 vendor interface \n")); + + wiphy->vendor_commands = NULL; + wiphy->vendor_events = NULL; + wiphy->n_vendor_commands = 0; + wiphy->n_vendor_events = 0; + + return 0; +} +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h new file mode 100644 index 000000000000..a352a9b1415d --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h @@ -0,0 +1,359 @@ +/* + * Linux cfg80211 Vendor Extension Code + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfgvendor.h 455257 2014-02-13 08:10:24Z $ + */ + +/* + * New vendor interface additon to nl80211/cfg80211 to allow vendors + * to implement proprietary features over the cfg80211 stack. + */ + +#ifndef _wl_cfgvendor_h_ +#define _wl_cfgvendor_h_ + +#define OUI_BRCM 0x001018 +#define OUI_GOOGLE 0x001A11 +#define BRCM_VENDOR_SUBCMD_PRIV_STR 1 +#define ATTRIBUTE_U32_LEN (NLA_HDRLEN + 4) +#define VENDOR_ID_OVERHEAD ATTRIBUTE_U32_LEN +#define VENDOR_SUBCMD_OVERHEAD ATTRIBUTE_U32_LEN +#define VENDOR_DATA_OVERHEAD (NLA_HDRLEN) + +#define SCAN_RESULTS_COMPLETE_FLAG_LEN ATTRIBUTE_U32_LEN +#define SCAN_INDEX_HDR_LEN (NLA_HDRLEN) +#define SCAN_ID_HDR_LEN ATTRIBUTE_U32_LEN +#define SCAN_FLAGS_HDR_LEN ATTRIBUTE_U32_LEN +#define GSCAN_NUM_RESULTS_HDR_LEN ATTRIBUTE_U32_LEN +#define GSCAN_RESULTS_HDR_LEN (NLA_HDRLEN) +#define GSCAN_BATCH_RESULT_HDR_LEN (SCAN_INDEX_HDR_LEN + SCAN_ID_HDR_LEN + \ + SCAN_FLAGS_HDR_LEN + \ + GSCAN_NUM_RESULTS_HDR_LEN + \ + GSCAN_RESULTS_HDR_LEN) + +#define VENDOR_REPLY_OVERHEAD (VENDOR_ID_OVERHEAD + \ + VENDOR_SUBCMD_OVERHEAD + \ + VENDOR_DATA_OVERHEAD) + +typedef enum { + /* don't use 0 as a valid subcommand */ + VENDOR_NL80211_SUBCMD_UNSPECIFIED, + + /* define all vendor startup commands between 0x0 and 0x0FFF */ + VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001, + VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF, + + /* define all GScan related commands between 0x1000 and 0x10FF */ + ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000, + ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF, + + /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */ + ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100, + ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF, + + /* define all RTT related commands between 0x1100 and 0x11FF */ + ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100, + ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF, + + ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200, + ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF, + + ANDROID_NL80211_SUBCMD_TDLS_RANGE_START = 0x1300, + ANDROID_NL80211_SUBCMD_TDLS_RANGE_END = 0x13FF, + + /* define all wifi calling related commands between 0x1600 and 0x16FF */ + ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600, + ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF, + + /* This is reserved for future usage */ + +} ANDROID_VENDOR_SUB_COMMAND; + +enum andr_vendor_subcmd { + GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START, + GSCAN_SUBCMD_SET_CONFIG, + GSCAN_SUBCMD_SET_SCAN_CONFIG, + GSCAN_SUBCMD_ENABLE_GSCAN, + GSCAN_SUBCMD_GET_SCAN_RESULTS, + GSCAN_SUBCMD_SCAN_RESULTS, + GSCAN_SUBCMD_SET_HOTLIST, + GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, + GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, + GSCAN_SUBCMD_GET_CHANNEL_LIST, + ANDR_WIFI_SUBCMD_GET_FEATURE_SET, + ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, + ANDR_WIFI_RANDOM_MAC_OUI, + ANDR_WIFI_NODFS_CHANNELS, + ANDR_WIFI_SET_COUNTRY, + GSCAN_SUBCMD_SET_EPNO_SSID, + WIFI_SUBCMD_SET_SSID_WHITELIST, + WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS, + WIFI_SUBCMD_ENABLE_LAZY_ROAM, + WIFI_SUBCMD_SET_BSSID_PREF, + WIFI_SUBCMD_SET_BSSID_BLACKLIST, + GSCAN_SUBCMD_ANQPO_CONFIG, + WIFI_SUBCMD_SET_RSSI_MONITOR, + RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, + RTT_SUBCMD_CANCEL_CONFIG, + RTT_SUBCMD_GETCAPABILITY, + + LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START, + + WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START, + WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE, + + /* Add more sub commands here */ + VENDOR_SUBCMD_MAX +}; + +enum gscan_attributes { + GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, + GSCAN_ATTRIBUTE_BASE_PERIOD, + GSCAN_ATTRIBUTE_BUCKETS_BAND, + GSCAN_ATTRIBUTE_BUCKET_ID, + GSCAN_ATTRIBUTE_BUCKET_PERIOD, + GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, + GSCAN_ATTRIBUTE_BUCKET_CHANNELS, + GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, + GSCAN_ATTRIBUTE_REPORT_THRESHOLD, + GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, + GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND, + + GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, + GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, + GSCAN_ATTRIBUTE_FLUSH_FEATURE, + GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS, + GSCAN_ATTRIBUTE_REPORT_EVENTS, + /* remaining reserved for additional attributes */ + GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, + GSCAN_ATTRIBUTE_FLUSH_RESULTS, + GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ + GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ + GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ + GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ + GSCAN_ATTRIBUTE_NUM_CHANNELS, + GSCAN_ATTRIBUTE_CHANNEL_LIST, + + /* remaining reserved for additional attributes */ + + GSCAN_ATTRIBUTE_SSID = 40, + GSCAN_ATTRIBUTE_BSSID, + GSCAN_ATTRIBUTE_CHANNEL, + GSCAN_ATTRIBUTE_RSSI, + GSCAN_ATTRIBUTE_TIMESTAMP, + GSCAN_ATTRIBUTE_RTT, + GSCAN_ATTRIBUTE_RTTSD, + + /* remaining reserved for additional attributes */ + + GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, + GSCAN_ATTRIBUTE_RSSI_LOW, + GSCAN_ATTRIBUTE_RSSI_HIGH, + GSCAN_ATTRIBUTE_HOSTLIST_BSSID_ELEM, + GSCAN_ATTRIBUTE_HOTLIST_FLUSH, + + /* remaining reserved for additional attributes */ + GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, + GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, + GSCAN_ATTRIBUTE_MIN_BREACHING, + GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, + GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, + /* EPNO */ + GSCAN_ATTRIBUTE_EPNO_SSID_LIST = 70, + GSCAN_ATTRIBUTE_EPNO_SSID, + GSCAN_ATTRIBUTE_EPNO_SSID_LEN, + GSCAN_ATTRIBUTE_EPNO_RSSI, + GSCAN_ATTRIBUTE_EPNO_FLAGS, + GSCAN_ATTRIBUTE_EPNO_AUTH, + GSCAN_ATTRIBUTE_EPNO_SSID_NUM, + GSCAN_ATTRIBUTE_EPNO_FLUSH, + + /* Roam SSID Whitelist and BSSID pref */ + GSCAN_ATTRIBUTE_WHITELIST_SSID = 80, + GSCAN_ATTRIBUTE_NUM_WL_SSID, + GSCAN_ATTRIBUTE_WL_SSID_LEN, + GSCAN_ATTRIBUTE_WL_SSID_FLUSH, + GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM, + GSCAN_ATTRIBUTE_NUM_BSSID, + GSCAN_ATTRIBUTE_BSSID_PREF_LIST, + GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH, + GSCAN_ATTRIBUTE_BSSID_PREF, + GSCAN_ATTRIBUTE_RSSI_MODIFIER, + + + /* Roam cfg */ + GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD = 90, + GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD, + GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR, + GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR, + GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST, + GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS, + GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER, + GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE, + + /* BSSID blacklist */ + GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH = 100, + GSCAN_ATTRIBUTE_BLACKLIST_BSSID, + + GSCAN_ATTRIBUTE_ANQPO_HS_LIST = 110, + GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, + GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, + GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, + GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID, + GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, + + /* Adaptive scan attributes */ + GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 120, + GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD, + + GSCAN_ATTRIBUTE_MAX +}; + +enum gscan_bucket_attributes { + GSCAN_ATTRIBUTE_CH_BUCKET_1, + GSCAN_ATTRIBUTE_CH_BUCKET_2, + GSCAN_ATTRIBUTE_CH_BUCKET_3, + GSCAN_ATTRIBUTE_CH_BUCKET_4, + GSCAN_ATTRIBUTE_CH_BUCKET_5, + GSCAN_ATTRIBUTE_CH_BUCKET_6, + GSCAN_ATTRIBUTE_CH_BUCKET_7 +}; + +enum gscan_ch_attributes { + GSCAN_ATTRIBUTE_CH_ID_1, + GSCAN_ATTRIBUTE_CH_ID_2, + GSCAN_ATTRIBUTE_CH_ID_3, + GSCAN_ATTRIBUTE_CH_ID_4, + GSCAN_ATTRIBUTE_CH_ID_5, + GSCAN_ATTRIBUTE_CH_ID_6, + GSCAN_ATTRIBUTE_CH_ID_7 +}; + +enum rtt_attributes { + RTT_ATTRIBUTE_TARGET_CNT, + RTT_ATTRIBUTE_TARGET_INFO, + RTT_ATTRIBUTE_TARGET_MAC, + RTT_ATTRIBUTE_TARGET_TYPE, + RTT_ATTRIBUTE_TARGET_PEER, + RTT_ATTRIBUTE_TARGET_CHAN, + RTT_ATTRIBUTE_TARGET_INTERVAL, + RTT_ATTRIBUTE_TARGET_NUM_BURST, + RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, + RTT_ATTRIBUTE_TARGET_LCI, + RTT_ATTRIBUTE_TARGET_LCR, + RTT_ATTRIBUTE_TARGET_BURST_TIMEOUT, + RTT_ATTRIBUTE_TARGET_PREAMBLE, + RTT_ATTRIBUTE_TARGET_BW, + RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, + RTT_ATTRIBUTE_RESULTS_PER_TARGET, + RTT_ATTRIBUTE_RESULT_CNT, + RTT_ATTRIBUTE_RESULT +}; + +enum wifi_rssi_monitor_attr { + RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, + RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, + RSSI_MONITOR_ATTRIBUTE_START +}; + +typedef enum wl_vendor_event { + BRCM_VENDOR_EVENT_UNSPEC, + BRCM_VENDOR_EVENT_PRIV_STR, + GOOGLE_GSCAN_SIGNIFICANT_EVENT, + GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT, + GOOGLE_GSCAN_BATCH_SCAN_EVENT, + GOOGLE_SCAN_FULL_RESULTS_EVENT, + GOOGLE_RTT_COMPLETE_EVENT, + GOOGLE_SCAN_COMPLETE_EVENT, + GOOGLE_GSCAN_GEOFENCE_LOST_EVENT, + GOOGLE_SCAN_EPNO_EVENT, + GOOGLE_DEBUG_RING_EVENT, + GOOGLE_FW_DUMP_EVENT, + GOOGLE_PNO_HOTSPOT_FOUND_EVENT, + GOOGLE_RSSI_MONITOR_EVENT, + GOOGLE_MKEEP_ALIVE_EVENT +} wl_vendor_event_t; + +enum andr_wifi_attr { + ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, + ANDR_WIFI_ATTRIBUTE_FEATURE_SET, + ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI, + ANDR_WIFI_ATTRIBUTE_NODFS_SET, + ANDR_WIFI_ATTRIBUTE_COUNTRY +}; + +typedef enum wl_vendor_gscan_attribute { + ATTR_START_GSCAN, + ATTR_STOP_GSCAN, + ATTR_SET_SCAN_BATCH_CFG_ID, /* set batch scan params */ + ATTR_SET_SCAN_GEOFENCE_CFG_ID, /* set list of bssids to track */ + ATTR_SET_SCAN_SIGNIFICANT_CFG_ID, /* set list of bssids, rssi threshold etc.. */ + ATTR_SET_SCAN_CFG_ID, /* set common scan config params here */ + ATTR_GET_GSCAN_CAPABILITIES_ID, + /* Add more sub commands here */ + ATTR_GSCAN_MAX +} wl_vendor_gscan_attribute_t; + +typedef enum gscan_batch_attribute { + ATTR_GSCAN_BATCH_BESTN, + ATTR_GSCAN_BATCH_MSCAN, + ATTR_GSCAN_BATCH_BUFFER_THRESHOLD +} gscan_batch_attribute_t; + +typedef enum gscan_geofence_attribute { + ATTR_GSCAN_NUM_HOTLIST_BSSID, + ATTR_GSCAN_HOTLIST_BSSID +} gscan_geofence_attribute_t; + +typedef enum gscan_complete_event { + WIFI_SCAN_BUFFER_FULL, + WIFI_SCAN_COMPLETE +} gscan_complete_event_t; + +enum mkeep_alive_attributes { + MKEEP_ALIVE_ATTRIBUTE_ID, + MKEEP_ALIVE_ATTRIBUTE_IP_PKT, + MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, + MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, + MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, + MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC +}; + +/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */ +#define BRCM_VENDOR_SCMD_CAPA "cap" + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) +extern int wl_cfgvendor_attach(struct wiphy *wiphy); +extern int wl_cfgvendor_detach(struct wiphy *wiphy); +extern int wl_cfgvendor_send_async_event(struct wiphy *wiphy, + struct net_device *dev, int event_id, const void *data, int len); +extern int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, + struct net_device *dev, void *data, int len, wl_vendor_event_t event); +#else +static INLINE int cfgvendor_attach(struct wiphy *wiphy) { return 0; } +static INLINE int cfgvendor_detach(struct wiphy *wiphy) { return 0; } +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ + +#endif /* _wl_cfgvendor_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h new file mode 100644 index 000000000000..02d653e4e1d6 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h @@ -0,0 +1,67 @@ +/* + * Minimal debug/trace/assert driver definitions for + * Broadcom 802.11 Networking Adapter. + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_dbg.h 430628 2013-10-19 04:07:25Z $ + */ + + +#ifndef _wl_dbg_h_ +#define _wl_dbg_h_ + +/* wl_msg_level is a bit vector with defs in wlioctl.h */ +extern uint32 wl_msg_level; +extern uint32 wl_msg_level2; + +#define WL_TIMESTAMP() + +#define WL_PRINT(args) do { WL_TIMESTAMP(); printf args; } while (0) + +#if defined(EVENT_LOG_COMPILE) && defined(WLMSG_SRSCAN) +#define _WL_SRSCAN(fmt, ...) EVENT_LOG(EVENT_LOG_TAG_SRSCAN, fmt, ##__VA_ARGS__) +#define WL_SRSCAN(args) _WL_SRSCAN args +#else +#define WL_SRSCAN(args) +#endif + + +/* To disable a message completely ... until you need it again */ +#define WL_NONE(args) + +#define WL_ERROR(args) +#define WL_TRACE(args) +#define WL_APSTA_UPDN(args) +#define WL_APSTA_RX(args) +#ifdef WLMSG_WSEC +#define WL_WSEC(args) WL_PRINT(args) +#define WL_WSEC_DUMP(args) WL_PRINT(args) +#else +#define WL_WSEC(args) +#define WL_WSEC_DUMP(args) +#endif +#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0) +#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL) + +extern uint32 wl_msg_level; +extern uint32 wl_msg_level2; +#endif /* _wl_dbg_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c new file mode 100644 index 000000000000..a15c132b7dff --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c @@ -0,0 +1,403 @@ +/* + * Broadcom Dongle Host Driver (DHD), Linux monitor network interface + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_linux_mon.c 425343 2013-09-23 23:04:47Z $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef enum monitor_states +{ + MONITOR_STATE_DEINIT = 0x0, + MONITOR_STATE_INIT = 0x1, + MONITOR_STATE_INTERFACE_ADDED = 0x2, + MONITOR_STATE_INTERFACE_DELETED = 0x4 +} monitor_states_t; +int dhd_add_monitor(char *name, struct net_device **new_ndev); +extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); +int dhd_del_monitor(struct net_device *ndev); +int dhd_monitor_init(void *dhd_pub); +int dhd_monitor_uninit(void); + +/** + * Local declarations and defintions (not exposed) + */ +#ifndef DHD_MAX_IFS +#define DHD_MAX_IFS 16 +#endif +#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__) +#define MON_TRACE MON_PRINT + +typedef struct monitor_interface { + int radiotap_enabled; + struct net_device* real_ndev; /* The real interface that the monitor is on */ + struct net_device* mon_ndev; +} monitor_interface; + +typedef struct dhd_linux_monitor { + void *dhd_pub; + monitor_states_t monitor_state; + monitor_interface mon_if[DHD_MAX_IFS]; + struct mutex lock; /* lock to protect mon_if */ +} dhd_linux_monitor_t; + +static dhd_linux_monitor_t g_monitor; + +static struct net_device* lookup_real_netdev(char *name); +static monitor_interface* ndev_to_monif(struct net_device *ndev); +static int dhd_mon_if_open(struct net_device *ndev); +static int dhd_mon_if_stop(struct net_device *ndev); +static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev); +static void dhd_mon_if_set_multicast_list(struct net_device *ndev); +static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr); + +static const struct net_device_ops dhd_mon_if_ops = { + .ndo_open = dhd_mon_if_open, + .ndo_stop = dhd_mon_if_stop, + .ndo_start_xmit = dhd_mon_if_subif_start_xmit, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + .ndo_set_rx_mode = dhd_mon_if_set_multicast_list, +#else + .ndo_set_multicast_list = dhd_mon_if_set_multicast_list, +#endif + .ndo_set_mac_address = dhd_mon_if_change_mac, +}; + +/** + * Local static function defintions + */ + +/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0" + * "p2p-eth0-0" is a match for "mon.p2p-eth0-0") + */ +static struct net_device* lookup_real_netdev(char *name) +{ + struct net_device *ndev_found = NULL; + + int i; + int len = 0; + int last_name_len = 0; + struct net_device *ndev; + + /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0", + * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon + * iface would be mon-p2p0-0. + */ + for (i = 0; i < DHD_MAX_IFS; i++) { + ndev = dhd_idx2net(g_monitor.dhd_pub, i); + + /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it + * it matches, then this netdev is the corresponding real_netdev. + */ + if (ndev && strstr(ndev->name, "p2p-p2p0")) { + len = strlen("p2p"); + } else { + /* if p2p- is not present, then the IFNAMSIZ have reached and name + * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x + */ + len = 0; + } + if (ndev && strstr(name, (ndev->name + len))) { + if (strlen(ndev->name) > last_name_len) { + ndev_found = ndev; + last_name_len = strlen(ndev->name); + } + } + } + + return ndev_found; +} + +static monitor_interface* ndev_to_monif(struct net_device *ndev) +{ + int i; + + for (i = 0; i < DHD_MAX_IFS; i++) { + if (g_monitor.mon_if[i].mon_ndev == ndev) + return &g_monitor.mon_if[i]; + } + + return NULL; +} + +static int dhd_mon_if_open(struct net_device *ndev) +{ + int ret = 0; + + MON_PRINT("enter\n"); + return ret; +} + +static int dhd_mon_if_stop(struct net_device *ndev) +{ + int ret = 0; + + MON_PRINT("enter\n"); + return ret; +} + +static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int ret = 0; + int rtap_len; + int qos_len = 0; + int dot11_hdr_len = 24; + int snap_len = 6; + unsigned char *pdata; + unsigned short frame_ctl; + unsigned char src_mac_addr[6]; + unsigned char dst_mac_addr[6]; + struct ieee80211_hdr *dot11_hdr; + struct ieee80211_radiotap_header *rtap_hdr; + monitor_interface* mon_if; + + MON_PRINT("enter\n"); + + mon_if = ndev_to_monif(ndev); + if (mon_if == NULL || mon_if->real_ndev == NULL) { + MON_PRINT(" cannot find matched net dev, skip the packet\n"); + goto fail; + } + + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) + goto fail; + + rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; + if (unlikely(rtap_hdr->it_version)) + goto fail; + + rtap_len = ieee80211_get_radiotap_len(skb->data); + if (unlikely(skb->len < rtap_len)) + goto fail; + + MON_PRINT("radiotap len (should be 14): %d\n", rtap_len); + + /* Skip the ratio tap header */ + skb_pull(skb, rtap_len); + + dot11_hdr = (struct ieee80211_hdr *)skb->data; + frame_ctl = le16_to_cpu(dot11_hdr->frame_control); + /* Check if the QoS bit is set */ + if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { + /* Check if this ia a Wireless Distribution System (WDS) frame + * which has 4 MAC addresses + */ + if (dot11_hdr->frame_control & 0x0080) + qos_len = 2; + if ((dot11_hdr->frame_control & 0x0300) == 0x0300) + dot11_hdr_len += 6; + + memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); + memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); + + /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for + * for two MAC addresses + */ + skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); + pdata = (unsigned char*)skb->data; + memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); + memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); + PKTSETPRIO(skb, 0); + + MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); + + /* Use the real net device to transmit the packet */ + ret = dhd_start_xmit(skb, mon_if->real_ndev); + + return ret; + } +fail: + dev_kfree_skb(skb); + return 0; +} + +static void dhd_mon_if_set_multicast_list(struct net_device *ndev) +{ + monitor_interface* mon_if; + + mon_if = ndev_to_monif(ndev); + if (mon_if == NULL || mon_if->real_ndev == NULL) { + MON_PRINT(" cannot find matched net dev, skip the packet\n"); + } else { + MON_PRINT("enter, if name: %s, matched if name %s\n", + ndev->name, mon_if->real_ndev->name); + } +} + +static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) +{ + int ret = 0; + monitor_interface* mon_if; + + mon_if = ndev_to_monif(ndev); + if (mon_if == NULL || mon_if->real_ndev == NULL) { + MON_PRINT(" cannot find matched net dev, skip the packet\n"); + } else { + MON_PRINT("enter, if name: %s, matched if name %s\n", + ndev->name, mon_if->real_ndev->name); + } + return ret; +} + +/** + * Global function definitions (declared in dhd_linux_mon.h) + */ + +int dhd_add_monitor(char *name, struct net_device **new_ndev) +{ + int i; + int idx = -1; + int ret = 0; + struct net_device* ndev = NULL; + dhd_linux_monitor_t **dhd_mon; + + mutex_lock(&g_monitor.lock); + + MON_TRACE("enter, if name: %s\n", name); + if (!name || !new_ndev) { + MON_PRINT("invalid parameters\n"); + ret = -EINVAL; + goto out; + } + + /* + * Find a vacancy + */ + for (i = 0; i < DHD_MAX_IFS; i++) + if (g_monitor.mon_if[i].mon_ndev == NULL) { + idx = i; + break; + } + if (idx == -1) { + MON_PRINT("exceeds maximum interfaces\n"); + ret = -EFAULT; + goto out; + } + + ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*)); + if (!ndev) { + MON_PRINT("failed to allocate memory\n"); + ret = -ENOMEM; + goto out; + } + + ndev->type = ARPHRD_IEEE80211_RADIOTAP; + strncpy(ndev->name, name, IFNAMSIZ); + ndev->name[IFNAMSIZ - 1] = 0; + ndev->netdev_ops = &dhd_mon_if_ops; + + ret = register_netdevice(ndev); + if (ret) { + MON_PRINT(" register_netdevice failed (%d)\n", ret); + goto out; + } + + *new_ndev = ndev; + g_monitor.mon_if[idx].radiotap_enabled = TRUE; + g_monitor.mon_if[idx].mon_ndev = ndev; + g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name); + dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev); + *dhd_mon = &g_monitor; + g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED; + MON_PRINT("net device returned: 0x%p\n", ndev); + MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name); + +out: + if (ret && ndev) + free_netdev(ndev); + + mutex_unlock(&g_monitor.lock); + return ret; + +} + +int dhd_del_monitor(struct net_device *ndev) +{ + int i; + if (!ndev) + return -EINVAL; + mutex_lock(&g_monitor.lock); + for (i = 0; i < DHD_MAX_IFS; i++) { + if (g_monitor.mon_if[i].mon_ndev == ndev || + g_monitor.mon_if[i].real_ndev == ndev) { + + g_monitor.mon_if[i].real_ndev = NULL; + unregister_netdevice(g_monitor.mon_if[i].mon_ndev); + free_netdev(g_monitor.mon_if[i].mon_ndev); + g_monitor.mon_if[i].mon_ndev = NULL; + g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED; + break; + } + } + + if (g_monitor.monitor_state != MONITOR_STATE_INTERFACE_DELETED) + MON_PRINT("IF not found in monitor array, is this a monitor IF? 0x%p\n", ndev); + mutex_unlock(&g_monitor.lock); + + return 0; +} + +int dhd_monitor_init(void *dhd_pub) +{ + if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) { + g_monitor.dhd_pub = dhd_pub; + mutex_init(&g_monitor.lock); + g_monitor.monitor_state = MONITOR_STATE_INIT; + } + return 0; +} + +int dhd_monitor_uninit(void) +{ + int i; + struct net_device *ndev; + mutex_lock(&g_monitor.lock); + if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) { + for (i = 0; i < DHD_MAX_IFS; i++) { + ndev = g_monitor.mon_if[i].mon_ndev; + if (ndev) { + unregister_netdevice(ndev); + free_netdev(ndev); + g_monitor.mon_if[i].real_ndev = NULL; + g_monitor.mon_if[i].mon_ndev = NULL; + } + } + g_monitor.monitor_state = MONITOR_STATE_DEINIT; + } + mutex_unlock(&g_monitor.lock); + return 0; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c new file mode 100644 index 000000000000..957640888266 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c @@ -0,0 +1,304 @@ +/* + * Linux roam cache + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_roam.c 459591 2014-03-04 08:53:45Z $ + */ + +#include +#include +#include +#include +#include +#ifdef WL_CFG80211 +#include +#endif +#include + +#define MAX_ROAM_CACHE 100 +#define MAX_CHANNEL_LIST 20 +#define MAX_SSID_BUFSIZE 36 + +#define ROAMSCAN_MODE_NORMAL 0 +#define ROAMSCAN_MODE_WES 1 + +typedef struct { + chanspec_t chanspec; + int ssid_len; + char ssid[MAX_SSID_BUFSIZE]; +} roam_channel_cache; + +typedef struct { + int n; + chanspec_t channels[MAX_CHANNEL_LIST]; +} channel_list_t; + +static int n_roam_cache = 0; +static int roam_band = WLC_BAND_AUTO; +static roam_channel_cache roam_cache[MAX_ROAM_CACHE]; +static uint band2G, band5G, band_bw; + +void init_roam(int ioctl_ver) +{ +#ifdef D11AC_IOTYPES + if (ioctl_ver == 1) { + /* legacy chanspec */ + band2G = WL_LCHANSPEC_BAND_2G; + band5G = WL_LCHANSPEC_BAND_5G; + band_bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE; + } else { + band2G = WL_CHANSPEC_BAND_2G; + band5G = WL_CHANSPEC_BAND_5G; + band_bw = WL_CHANSPEC_BW_20; + } +#else + band2G = WL_CHANSPEC_BAND_2G; + band5G = WL_CHANSPEC_BAND_5G; + band_bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; +#endif /* D11AC_IOTYPES */ + + n_roam_cache = 0; + roam_band = WLC_BAND_AUTO; +} + + +void set_roam_band(int band) +{ + roam_band = band; +} + +void reset_roam_cache(void) +{ + + n_roam_cache = 0; +} + +void add_roam_cache(wl_bss_info_t *bi) +{ + int i; + uint8 channel; + + + if (n_roam_cache >= MAX_ROAM_CACHE) + return; + + for (i = 0; i < n_roam_cache; i++) { + if ((roam_cache[i].ssid_len == bi->SSID_len) && + (roam_cache[i].chanspec == bi->chanspec) && + (memcmp(roam_cache[i].ssid, bi->SSID, bi->SSID_len) == 0)) { + /* identical one found, just return */ + return; + } + } + + roam_cache[n_roam_cache].ssid_len = bi->SSID_len; + channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch; + WL_DBG(("CHSPEC 0x%X %d, CTL %d\n", + bi->chanspec, CHSPEC_CHANNEL(bi->chanspec), bi->ctl_ch)); + roam_cache[n_roam_cache].chanspec = + (channel <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw | channel; + memcpy(roam_cache[n_roam_cache].ssid, bi->SSID, bi->SSID_len); + + n_roam_cache++; +} + +static bool is_duplicated_channel(const chanspec_t *channels, int n_channels, chanspec_t new) +{ + int i; + + for (i = 0; i < n_channels; i++) { + if (channels[i] == new) + return TRUE; + } + + return FALSE; +} + +int get_roam_channel_list(int target_chan, + chanspec_t *channels, const wlc_ssid_t *ssid, int ioctl_ver) +{ + int i, n = 1; + + /* first index is filled with the given target channel */ + channels[0] = (target_chan & WL_CHANSPEC_CHAN_MASK) | + (target_chan <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw; + + WL_DBG((" %s: %03d 0x%04X\n", __FUNCTION__, target_chan, channels[0])); + + + for (i = 0; i < n_roam_cache; i++) { + chanspec_t ch = roam_cache[i].chanspec; + bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch); + bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch); + bool band_match = ((roam_band == WLC_BAND_AUTO) || + ((roam_band == WLC_BAND_2G) && is_2G) || + ((roam_band == WLC_BAND_5G) && is_5G)); + + ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw; + if ((roam_cache[i].ssid_len == ssid->SSID_len) && + band_match && !is_duplicated_channel(channels, n, ch) && + (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) { + /* match found, add it */ + WL_DBG((" %s: %03d(0x%04X)\n", __FUNCTION__, + CHSPEC_CHANNEL(ch), ch)); + channels[n++] = ch; + } + } + + return n; +} + + +void print_roam_cache(void) +{ + int i; + + WL_DBG((" %d cache\n", n_roam_cache)); + + for (i = 0; i < n_roam_cache; i++) { + roam_cache[i].ssid[roam_cache[i].ssid_len] = 0; + WL_DBG(("0x%02X %02d %s\n", roam_cache[i].chanspec, + roam_cache[i].ssid_len, roam_cache[i].ssid)); + } +} + +static void add_roamcache_channel(channel_list_t *channels, chanspec_t ch) +{ + int i; + + if (channels->n >= MAX_CHANNEL_LIST) /* buffer full */ + return; + + for (i = 0; i < channels->n; i++) { + if (channels->channels[i] == ch) /* already in the list */ + return; + } + + channels->channels[i] = ch; + channels->n++; + + WL_DBG((" RCC: %02d 0x%04X\n", + ch & WL_CHANSPEC_CHAN_MASK, ch)); +} + +void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver) +{ + int error, i, prev_channels; + channel_list_t channel_list; + char iobuf[WLC_IOCTL_SMLEN]; + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + wlc_ssid_t ssid; + + + if (!wl_get_drv_status(cfg, CONNECTED, dev)) { + WL_DBG(("Not associated\n")); + return; + } + + /* need to read out the current cache list + as the firmware may change dynamically + */ + error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0, + (void *)&channel_list, sizeof(channel_list), NULL); + + WL_DBG(("%d AP, %d cache item(s), err=%d\n", n_roam_cache, channel_list.n, error)); + + error = wldev_get_ssid(dev, &ssid); + if (error) { + WL_ERR(("Failed to get SSID, err=%d\n", error)); + return; + } + + prev_channels = channel_list.n; + for (i = 0; i < n_roam_cache; i++) { + chanspec_t ch = roam_cache[i].chanspec; + bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch); + bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch); + bool band_match = ((roam_band == WLC_BAND_AUTO) || + ((roam_band == WLC_BAND_2G) && is_2G) || + ((roam_band == WLC_BAND_5G) && is_5G)); + + if ((roam_cache[i].ssid_len == ssid.SSID_len) && + band_match && (memcmp(roam_cache[i].ssid, ssid.SSID, ssid.SSID_len) == 0)) { + /* match found, add it */ + ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw; + add_roamcache_channel(&channel_list, ch); + } + } + if (prev_channels != channel_list.n) { + /* channel list updated */ + error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list, + sizeof(channel_list), iobuf, sizeof(iobuf), NULL); + if (error) { + WL_ERR(("Failed to update roamscan channels, error = %d\n", error)); + } + } +} + +void wl_update_roamscan_cache_by_band(struct net_device *dev, int band) +{ + int i, error, ioctl_ver, wes_mode; + channel_list_t chanlist_before, chanlist_after; + char iobuf[WLC_IOCTL_SMLEN]; + + roam_band = band; + if (band == WLC_BAND_AUTO) + return; + + error = wldev_iovar_getint(dev, "roamscan_mode", &wes_mode); + if (error) { + WL_ERR(("Failed to get roamscan mode, error = %d\n", error)); + return; + } + /* in case of WES mode, then skip the update */ + if (wes_mode) + return; + + error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0, + (void *)&chanlist_before, sizeof(channel_list_t), NULL); + if (error) { + WL_ERR(("Failed to get roamscan channels, error = %d\n", error)); + return; + } + ioctl_ver = wl_cfg80211_get_ioctl_version(); + chanlist_after.n = 0; + /* filtering by the given band */ + for (i = 0; i < chanlist_before.n; i++) { + chanspec_t chspec = chanlist_before.channels[i]; + bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(chspec) : CHSPEC_IS2G(chspec); + bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(chspec) : CHSPEC_IS5G(chspec); + bool band_match = ((band == WLC_BAND_2G) && is_2G) || + ((band == WLC_BAND_5G) && is_5G); + if (band_match) { + chanlist_after.channels[chanlist_after.n++] = chspec; + } + } + + if (chanlist_before.n == chanlist_after.n) + return; + + error = wldev_iovar_setbuf(dev, "roamscan_channels", &chanlist_after, + sizeof(channel_list_t), iobuf, sizeof(iobuf), NULL); + if (error) { + WL_ERR(("Failed to update roamscan channels, error = %d\n", error)); + } +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c new file mode 100644 index 000000000000..08a5ecaf6560 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c @@ -0,0 +1,421 @@ +/* + * Common function shared by Linux WEXT, cfg80211 and p2p drivers + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wldev_common.c 701450 2017-05-25 02:10:23Z $ + */ + +#include +#include +#include +#include + +#include +#include + +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) + +#define WLDEV_ERROR(args) \ + do { \ + printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__); \ + printk args; \ + } while (0) + +extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd); + +s32 wldev_ioctl( + struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) +{ + s32 ret = 0; + struct wl_ioctl ioc; + + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + ioc.set = set; + + ret = dhd_ioctl_entry_local(dev, &ioc, cmd); + + return ret; +} + +/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be + * taken care of in dhd_ioctl_entry. Internal use only, not exposed to + * wl_iw, wl_cfg80211 and wl_cfgp2p + */ +static s32 wldev_mkiovar( + s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, u32 buflen) +{ + s32 iolen = 0; + + iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen); + return iolen; +} + +s32 wldev_iovar_getbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) +{ + s32 ret = 0; + if (buf_sync) { + mutex_lock(buf_sync); + } + if (buf && (buflen > 0)) { + /* initialize the response buffer */ + memset(buf, 0, buflen); + } else { + ret = BCME_BADARG; + goto exit; + } + ret = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); + if (!ret) { + ret = BCME_BUFTOOSHORT; + goto exit; + } + + ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); + +exit: + if (buf_sync) + mutex_unlock(buf_sync); + return ret; +} + + +s32 wldev_iovar_setbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) +{ + s32 ret = 0; + s32 iovar_len; + if (buf_sync) { + mutex_lock(buf_sync); + } + if (buf && (buflen > 0)) { + /* initialize the response buffer */ + memset(buf, 0, buflen); + } else { + ret = BCME_BADARG; + goto exit; + } + iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); + if (iovar_len > 0) + ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + else + ret = BCME_BUFTOOSHORT; + +exit: + if (buf_sync) + mutex_unlock(buf_sync); + return ret; +} + +s32 wldev_iovar_setint( + struct net_device *dev, s8 *iovar, s32 val) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + + val = htod32(val); + return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf, + sizeof(iovar_buf), NULL); +} + + +s32 wldev_iovar_getint( + struct net_device *dev, s8 *iovar, s32 *pval) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + s32 err; + + err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf, + sizeof(iovar_buf), NULL); + if (err == 0) + { + memcpy(pval, iovar_buf, sizeof(*pval)); + *pval = dtoh32(*pval); + } + return err; +} + +/** Format a bsscfg indexed iovar buffer. The bsscfg index will be + * taken care of in dhd_ioctl_entry. Internal use only, not exposed to + * wl_iw, wl_cfg80211 and wl_cfgp2p + */ +s32 wldev_mkiovar_bsscfg( + const s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, s32 buflen, s32 bssidx) +{ + const s8 *prefix = "bsscfg:"; + s8 *p; + u32 prefixlen; + u32 namelen; + u32 iolen; + + /* initialize buffer */ + if (!iovar_buf || buflen == 0) + return BCME_BADARG; + memset(iovar_buf, 0, buflen); + + if (bssidx == 0) { + return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen, + (s8 *) iovar_buf, buflen); + } + + prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ + namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */ + iolen = prefixlen + namelen + sizeof(u32) + paramlen; + + if (buflen < 0 || iolen > (u32)buflen) + { + WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__)); + return BCME_BUFTOOSHORT; + } + + p = (s8 *)iovar_buf; + + /* copy prefix, no null */ + memcpy(p, prefix, prefixlen); + p += prefixlen; + + /* copy iovar name including null */ + memcpy(p, iovar_name, namelen); + p += namelen; + + /* bss config index as first param */ + bssidx = htod32(bssidx); + memcpy(p, &bssidx, sizeof(u32)); + p += sizeof(u32); + + /* parameter buffer follows */ + if (paramlen) + memcpy(p, param, paramlen); + + return iolen; + +} + +s32 wldev_iovar_getbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) +{ + s32 ret = 0; + if (buf_sync) { + mutex_lock(buf_sync); + } + + wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); + ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); + if (buf_sync) { + mutex_unlock(buf_sync); + } + return ret; + +} + +s32 wldev_iovar_setbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) +{ + s32 ret = 0; + s32 iovar_len; + if (buf_sync) { + mutex_lock(buf_sync); + } + iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); + if (iovar_len > 0) + ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + else { + ret = BCME_BUFTOOSHORT; + } + + if (buf_sync) { + mutex_unlock(buf_sync); + } + return ret; +} + +s32 wldev_iovar_setint_bsscfg( + struct net_device *dev, s8 *iovar, s32 val, s32 bssidx) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + + val = htod32(val); + + return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, + sizeof(iovar_buf), bssidx, NULL); +} + + +s32 wldev_iovar_getint_bsscfg( + struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + s32 err; + + err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf, + sizeof(iovar_buf), bssidx, NULL); + if (err == 0) + { + memcpy(pval, iovar_buf, sizeof(*pval)); + *pval = dtoh32(*pval); + } + return err; +} + +int wldev_get_link_speed( + struct net_device *dev, int *plink_speed) +{ + int error; + + if (!plink_speed) + return -ENOMEM; + *plink_speed = 0; + error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0); + if (unlikely(error)) + return error; + + /* Convert internal 500Kbps to Kbps */ + *plink_speed *= 500; + return error; +} + +int wldev_get_rssi( + struct net_device *dev, int *prssi) +{ + scb_val_t scb_val; + int error; + + if (!prssi) + return -ENOMEM; + bzero(&scb_val, sizeof(scb_val_t)); + + error = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); + if (unlikely(error)) + return error; + + *prssi = dtoh32(scb_val.val); + return error; +} + +int wldev_get_ssid( + struct net_device *dev, wlc_ssid_t *pssid) +{ + int error; + + if (!pssid) + return -ENOMEM; + memset(pssid, 0, sizeof(wlc_ssid_t)); + error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0); + if (unlikely(error)) + return error; + pssid->SSID_len = dtoh32(pssid->SSID_len); + return error; +} + +int wldev_get_band( + struct net_device *dev, uint *pband) +{ + int error; + + *pband = 0; + error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0); + return error; +} + +int wldev_set_band( + struct net_device *dev, uint band) +{ + int error = -1; + + if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { + error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true); + if (!error) + dhd_bus_band_set(dev, band); + } + return error; +} + +int wldev_set_country( + struct net_device *dev, char *country_code, bool notify, bool user_enforced) +{ + int error = -1; + wl_country_t cspec = {{0}, 0, {0}}; + scb_val_t scbval; + char smbuf[WLC_IOCTL_SMLEN]; + + if (!country_code) + return error; + + bzero(&scbval, sizeof(scb_val_t)); + error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL); + if (error < 0) { + WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error)); + return error; + } + + if ((error < 0) || + (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { + + if (user_enforced) { + bzero(&scbval, sizeof(scb_val_t)); + error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); + if (error < 0) { + WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", + __FUNCTION__, error)); + return error; + } + } +#ifdef CUSTOMER_HW5 + else { + if (dhd_is_p2p_connection(dev)) { + WLDEV_ERROR(("Skip to set country code for preventing " + "p2p disconnection\n")); + return -1; + } + } +#endif /* CUSTOMER_HW5 */ + + cspec.rev = -1; + memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); + memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); + dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec); + error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), + smbuf, sizeof(smbuf), NULL); + if (error < 0) { + WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", + __FUNCTION__, country_code, cspec.ccode, cspec.rev)); + return error; + } + dhd_bus_country_set(dev, &cspec, notify); + WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", + __FUNCTION__, country_code, cspec.ccode, cspec.rev)); + } + return 0; +} diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h new file mode 100644 index 000000000000..d1746dd0d9cc --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h @@ -0,0 +1,120 @@ +/* + * Common function shared by Linux WEXT, cfg80211 and p2p drivers + * + * Copyright (C) 1999-2017, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wldev_common.h 684925 2017-02-15 01:55:31Z $ + */ +#ifndef __WLDEV_COMMON_H__ +#define __WLDEV_COMMON_H__ + +#include + +/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or + * netdev_ops->ndo_do_ioctl in new kernels) + * @dev: the net_device handle + */ +s32 wldev_ioctl( + struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); + +/** Retrieve named IOVARs, this function calls wl_dev_ioctl with + * WLC_GET_VAR IOCTL code + */ +s32 wldev_iovar_getbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); + +/** Set named IOVARs, this function calls wl_dev_ioctl with + * WLC_SET_VAR IOCTL code + */ +s32 wldev_iovar_setbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); + +s32 wldev_iovar_setint( + struct net_device *dev, s8 *iovar, s32 val); + +s32 wldev_iovar_getint( + struct net_device *dev, s8 *iovar, s32 *pval); + +/** The following function can be implemented if there is a need for bsscfg + * indexed IOVARs + */ + +s32 wldev_mkiovar_bsscfg( + const s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, s32 buflen, s32 bssidx); + +/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with + * WLC_GET_VAR IOCTL code + */ +s32 wldev_iovar_getbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, + void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); + +/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with + * WLC_SET_VAR IOCTL code + */ +s32 wldev_iovar_setbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, + void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); + +s32 wldev_iovar_getint_bsscfg( + struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx); + +s32 wldev_iovar_setint_bsscfg( + struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); + +extern int dhd_net_set_fw_path(struct net_device *dev, char *fw); +extern int dhd_net_bus_suspend(struct net_device *dev); +extern int dhd_net_bus_resume(struct net_device *dev, uint8 stage); +extern int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, + unsigned long delay_msec); +extern void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, + wl_country_t *cspec); +extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify); +extern void dhd_bus_band_set(struct net_device *dev, uint band); +extern int wldev_set_country(struct net_device *dev, char *country_code, bool notify, + bool user_enforced); +extern int net_os_wake_lock(struct net_device *dev); +extern int net_os_wake_unlock(struct net_device *dev); +extern int net_os_wake_lock_timeout(struct net_device *dev); +extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); +extern int net_os_set_dtim_skip(struct net_device *dev, int val); +extern int net_os_set_suspend_disable(struct net_device *dev, int val); +extern int net_os_set_suspend(struct net_device *dev, int val, int force); +extern int wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, + int max, int *bytes_left); + +/* Get the link speed from dongle, speed is in kpbs */ +int wldev_get_link_speed(struct net_device *dev, int *plink_speed); + +int wldev_get_rssi(struct net_device *dev, int *prssi); + +int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid); + +int wldev_get_band(struct net_device *dev, uint *pband); + +int wldev_set_band(struct net_device *dev, uint band); +#ifdef CUSTOMER_HW5 +extern bool dhd_is_p2p_connection(struct net_device *ndev); +#endif +#endif /* __WLDEV_COMMON_H__ */ -- GitLab From 68d0eb78e2c58e433f7cd61b526c4689a07b5f30 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Thu, 7 Sep 2017 00:22:54 +0300 Subject: [PATCH 203/528] drivers: wireless: bcm43455: Update to 1.141.67.29 * Sony package version: 34.3.A.0.228 (Xperia X) - Security fix: - CVE-2017-0705 A-34973477 Added a boundary check in the handling of gscan attribute for significant change bssids - CVE-2017-0706 A-35195787 Added a length check of tx mgmt frame Signed-off-by: Andrey Cherepkov (cherry picked from commit 64f4f5355764a4ad4809f0f93bf48037724dd509) --- .../bcmdhd_bcm43455/include/epivers.h | 8 ++--- .../wireless/bcmdhd_bcm43455/wl_cfg80211.c | 7 +++- .../wireless/bcmdhd_bcm43455/wl_cfgvendor.c | 35 ++++++++++++++++--- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h index 3d1c087872d7..4f25e0d6067e 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h @@ -32,17 +32,17 @@ #define EPI_RC_NUMBER 67 -#define EPI_INCREMENTAL_NUMBER 28 +#define EPI_INCREMENTAL_NUMBER 29 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 141, 67, 28 +#define EPI_VERSION 1, 141, 67, 29 -#define EPI_VERSION_NUM 0x018d431c +#define EPI_VERSION_NUM 0x018d431d #define EPI_VERSION_DEV 1.141.67 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.141.67.28 (r)" +#define EPI_VERSION_STR "1.141.67.29 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index 3e100e3730b3..db2c198a1926 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 701450 2017-05-25 02:10:23Z $ + * $Id: wl_cfg80211.c 704367 2017-06-13 09:05:24Z $ */ /* */ #include @@ -5593,6 +5593,11 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, WL_DBG(("Enter \n")); + if (len > ACTION_FRAME_SIZE) { + WL_ERR(("bad length:%zu\n", len)); + return BCME_BADLEN; + } + dev = cfgdev_to_wlc_ndev(cfgdev, cfg); /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c index 38469c905fa2..dcb9f3560e1a 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c @@ -1109,11 +1109,14 @@ wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy, const struct nlattr *outer, *inner, *iter; uint8 flush = 0; wl_pfn_significant_bssid_t *bssid; + uint16 num_bssid = 0; + uint16 max_buf_size = sizeof(gscan_swc_params_t) + + sizeof(wl_pfn_significant_bssid_t) * (PFN_SWC_MAX_NUM_APS - 1); - significant_params = (gscan_swc_params_t *) kzalloc(len, GFP_KERNEL); + significant_params = kzalloc(max_buf_size, GFP_KERNEL); if (!significant_params) { - WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes \n", len)); - return -ENOMEM; + WL_ERR(("Cannot Malloc mem size:%d\n", max_buf_size)); + return BCME_NOMEM; } nla_for_each_attr(iter, data, len, tmp2) { @@ -1132,9 +1135,27 @@ wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy, case GSCAN_ATTRIBUTE_MIN_BREACHING: significant_params->swc_threshold = nla_get_u16(iter); break; + case GSCAN_ATTRIBUTE_NUM_BSSID: + num_bssid = nla_get_u16(iter); + if (num_bssid > PFN_SWC_MAX_NUM_APS) { + WL_ERR(("ovar max SWC bssids:%d\n", + num_bssid)); + err = BCME_BADARG; + goto exit; + } + break; case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS: + if (num_bssid == 0) { + WL_ERR(("num_bssid : 0\n")); + err = BCME_BADARG; + goto exit; + } bssid = significant_params->bssid_elem_list; nla_for_each_nested(outer, iter, tmp) { + if (j >= num_bssid) { + j++; + break; + } nla_for_each_nested(inner, outer, tmp1) { switch (nla_type(inner)) { case GSCAN_ATTRIBUTE_BSSID: @@ -1164,13 +1185,19 @@ wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy, break; } } + if (j != num_bssid) { + WL_ERR(("swc bssids count:%d not matched to num_bssid:%d\n", + j, num_bssid)); + err = BCME_BADARG; + goto exit; + } significant_params->nbssid = j; if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, significant_params, flush) < 0) { WL_ERR(("Could not set GSCAN significant cfg\n")); - err = -EINVAL; + err = BCME_ERROR; goto exit; } exit: -- GitLab From 6c30555818ad917b7905f41e346367240eb09cf7 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Thu, 5 Oct 2017 23:51:24 +0300 Subject: [PATCH 204/528] drivers: wireless: bcm43455: Update to 1.141.67.30 * Sony package version: 34.3.A.0.238 (Xperia X) - Security fix: - CVE-2017-0786 A-37351060 Added boundary check in wl_escan_handler() - CVE-2017-0787 A-37722970 Added boundary check in dhd_pno_process_epno_result() - CVE-2017-0788 A-37722328 Added boundary check in dhd_handle_hotlist_scan_evt() - CVE-2017-0789 A-37685267 Removed unused SWC feature - CVE-2017-0790 A-37357704 Added boundary check in dhd_process_full_gscan_result() - CVE-2017-0791 A-37306719 Added event length check in wl_notify_rx_mgmt_frame() - CVE-2017-0792 A-37305578 Added event length check in dhd_rtt_event_handler() - V2017070601 Added P2P IE length check in parsing routine Signed-off-by: Andrey Cherepkov (cherry picked from commit 01d041473e97bfba9be69a2883539c282c7a52f3) --- .../net/wireless/bcmdhd_bcm43455/bcmevent.c | 3 +- .../wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c | 72 +---- .../net/wireless/bcmdhd_bcm43455/dhd_linux.c | 15 +- .../net/wireless/bcmdhd_bcm43455/dhd_pno.c | 269 +++--------------- .../net/wireless/bcmdhd_bcm43455/dhd_pno.h | 49 +--- .../net/wireless/bcmdhd_bcm43455/dhd_rtt.c | 34 ++- .../bcmdhd_bcm43455/include/epivers.h | 8 +- .../bcmdhd_bcm43455/include/wlioctl.h | 6 +- .../wireless/bcmdhd_bcm43455/wl_cfg80211.c | 65 +++-- .../net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c | 7 +- .../wireless/bcmdhd_bcm43455/wl_cfgvendor.c | 115 -------- 11 files changed, 137 insertions(+), 506 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c index aefbd763ece1..1447d2baa983 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmevent.c 696097 2017-04-25 09:26:01Z $ + * $Id: bcmevent.c 718508 2017-08-31 02:48:38Z $ */ #include @@ -154,7 +154,6 @@ const bcmevent_name_t bcmevent_names[] = { BCMEVENT_NAME(WLC_E_TXFAIL_THRESH), #ifdef GSCAN_SUPPORT BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT), - BCMEVENT_NAME(WLC_E_PFN_SWC), #endif /* GSCAN_SUPPORT */ BCMEVENT_NAME(WLC_E_RMC_EVENT), #ifdef GSCAN_SUPPORT diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c index 2488cfbc78c5..b2a8e8087d8d 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc.c 457662 2014-02-24 15:07:28Z $ + * $Id: bcmsdh_sdmmc.c 710227 2017-07-12 08:09:07Z $ */ #include @@ -406,8 +406,6 @@ const bcm_iovar_t sdioh_iovars[] = { {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, - {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, @@ -607,74 +605,6 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, int_val = (int32)0; bcopy(&int_val, arg, val_size); break; - - case IOV_GVAL(IOV_HOSTREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - - if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { - sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); - bcmerror = BCME_BADARG; - break; - } - - sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__, - (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), - sd_ptr->offset)); - if (sd_ptr->offset & 1) - int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */ - else if (sd_ptr->offset & 2) - int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */ - else - int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */ - - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_HOSTREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - - if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { - sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); - bcmerror = BCME_BADARG; - break; - } - - sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value, - (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), - sd_ptr->offset)); - break; - } - - case IOV_GVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = 0; - - if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - - int_val = (int)data; - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = (uint8)sd_ptr->value; - - if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - } - default: bcmerror = BCME_UNSUPPORTED; break; diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c index b711dd781e9a..c4f6a6461c20 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c @@ -23,7 +23,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 701450 2017-05-25 02:10:23Z $ + * $Id: dhd_linux.c 718508 2017-08-31 02:48:38Z $ */ #include @@ -4821,7 +4821,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef GSCAN_SUPPORT setbit(eventmask_msg->mask, WLC_E_PFN_GSCAN_FULL_RESULT); setbit(eventmask_msg->mask, WLC_E_PFN_SCAN_COMPLETE); - setbit(eventmask_msg->mask, WLC_E_PFN_SWC); setbit(eventmask_msg->mask, WLC_E_PFN_SSID_EXT); #endif /* GSCAN_SUPPORT */ @@ -6790,14 +6789,6 @@ int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time_f return (dhd_pno_enable_full_scan_result(&dhd->pub, real_time_flag)); } -/* Linux wrapper to call common dhd_handle_swc_evt */ -void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_handle_swc_evt(&dhd->pub, data, send_evt_bytes)); -} - /* Linux wrapper to call common dhd_handle_hotlist_scan_evt */ void * dhd_dev_hotlist_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes, hotlist_type_t type) @@ -6809,11 +6800,11 @@ void * dhd_dev_hotlist_scan_event(struct net_device *dev, /* Linux wrapper to call common dhd_process_full_gscan_result */ void * dhd_dev_process_full_gscan_result(struct net_device *dev, -const void *data, int *send_evt_bytes) +const void *data, uint32 len, int *send_evt_bytes) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_process_full_gscan_result(&dhd->pub, data, send_evt_bytes)); + return (dhd_process_full_gscan_result(&dhd->pub, data, len, send_evt_bytes)); } void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c index d9470d5d2b87..5f91924c2580 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c @@ -52,6 +52,7 @@ #ifdef GSCAN_SUPPORT #include #endif /* GSCAN_SUPPORT */ +#include #ifdef __BIG_ENDIAN #include @@ -95,6 +96,10 @@ #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") #define TIME_MIN_DIFF 5 +#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) +#define EVENT_MAX_NETCNT \ + ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_t)) \ + / sizeof(wl_pfn_net_info_t) + 1) static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state); @@ -965,32 +970,6 @@ exit: return err; } -#ifdef GSCAN_SUPPORT - static int -_dhd_pno_add_significant_bssid(dhd_pub_t *dhd, - wl_pfn_significant_bssid_t *p_pfn_significant_bssid, int nbssid) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - - if (!nbssid) { - err = BCME_ERROR; - goto exit; - } - - NULL_CHECK(p_pfn_significant_bssid, "bssid list is NULL", err); - - err = dhd_iovar(dhd, 0, "pfn_add_swc_bssid", (char *)p_pfn_significant_bssid, - sizeof(wl_pfn_significant_bssid_t) * nbssid, NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_significant_bssid %d\n", __FUNCTION__, err)); - goto exit; - } -exit: - return err; -} -#endif /* GSCAN_SUPPORT */ - int dhd_pno_stop_for_ssid(dhd_pub_t *dhd) { @@ -1633,19 +1612,6 @@ static void dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params, _params->params_gscan.nbssid_hotlist = 0; DHD_PNO(("Flush Hotlist Config\n")); } - if (flags & GSCAN_FLUSH_SIGNIFICANT_CFG) { - dhd_pno_significant_bssid_t *iter, *next; - - if (_params->params_gscan.nbssid_significant_change > 0) { - list_for_each_entry_safe(iter, next, - &_params->params_gscan.significant_bssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - _params->params_gscan.nbssid_significant_change = 0; - DHD_PNO(("Flush Significant Change Config\n")); - } if (flags & GSCAN_FLUSH_EPNO_CFG) { dhd_epno_params_t *iter, *next; @@ -1791,8 +1757,10 @@ dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX; ptr->max_scan_reporting_threshold = 100; - ptr->max_hotlist_aps = PFN_HOTLIST_MAX_NUM_APS; - ptr->max_significant_wifi_change_aps = PFN_SWC_MAX_NUM_APS; + ptr->max_hotlist_bssids = PFN_HOTLIST_MAX_NUM_APS; + ptr->max_hotlist_ssids = 0; + ptr->max_significant_wifi_change_aps = 0; + ptr->max_bssid_history_entries = 0; ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; ptr->max_white_list_ssid = MAX_WHITELIST_SSID; @@ -1966,62 +1934,6 @@ dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, _params->params_gscan.lost_ap_window = ptr->lost_ap_window; } break; - case DHD_PNO_SIGNIFICANT_SCAN_CFG_ID: - { - gscan_swc_params_t *ptr = (gscan_swc_params_t *)buf; - dhd_pno_significant_bssid_t *_pno_significant_change_bssid; - wl_pfn_significant_bssid_t *significant_bssid_ptr; - - if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, - GSCAN_FLUSH_SIGNIFICANT_CFG); - } - - if (!ptr->nbssid) - break; - - if (!_params->params_gscan.nbssid_significant_change) - INIT_LIST_HEAD( - &_params->params_gscan.significant_bssid_list); - - if ((_params->params_gscan.nbssid_significant_change + - ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { - DHD_ERROR(("Excessive number of SWC APs programmed %d\n", - (_params->params_gscan.nbssid_significant_change + - ptr->nbssid))); - err = BCME_RANGE; - goto exit; - } - - for (i = 0, significant_bssid_ptr = ptr->bssid_elem_list; - i < ptr->nbssid; i++, significant_bssid_ptr++) { - _pno_significant_change_bssid = - kzalloc(sizeof(dhd_pno_significant_bssid_t), - GFP_KERNEL); - - if (!_pno_significant_change_bssid) { - DHD_ERROR(("SWC bssidptr is NULL, cannot kalloc " - "%zd bytes", - sizeof(dhd_pno_significant_bssid_t))); - err = BCME_NOMEM; - goto exit; - } - memcpy(&_pno_significant_change_bssid->BSSID, - &significant_bssid_ptr->macaddr, ETHER_ADDR_LEN); - _pno_significant_change_bssid->rssi_low_threshold = - significant_bssid_ptr->rssi_low_threshold; - _pno_significant_change_bssid->rssi_high_threshold = - significant_bssid_ptr->rssi_high_threshold; - list_add_tail(&_pno_significant_change_bssid->list, - &_params->params_gscan.significant_bssid_list); - } - - _params->params_gscan.swc_nbssid_threshold = ptr->swc_threshold; - _params->params_gscan.swc_rssi_window_size = ptr->rssi_window; - _params->params_gscan.lost_ap_window = ptr->lost_ap_window; - _params->params_gscan.nbssid_significant_change += ptr->nbssid; - } - break; case DHD_PNO_SCAN_CFG_ID: { int i, k; @@ -2139,7 +2051,6 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL; wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL; - wl_pfn_significant_bssid_t *p_pfn_significant_bssid = NULL; wl_pfn_bssid_t *p_pfn_bssid = NULL; wlc_ssid_ext_t *pssid_list = NULL; dhd_pno_params_t *params_legacy; @@ -2216,7 +2127,7 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); - pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOC(dhd->osh, gscan_param_size); + pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size); if (!pfn_gscan_cfg_t) { DHD_ERROR(("%s: failed to malloc memory of size %d\n", @@ -2231,15 +2142,6 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) } else { pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; } - if (gscan_params->nbssid_significant_change) { - pfn_gscan_cfg_t->swc_nbssid_threshold = gscan_params->swc_nbssid_threshold; - pfn_gscan_cfg_t->swc_rssi_window_size = gscan_params->swc_rssi_window_size; - pfn_gscan_cfg_t->lost_ap_window = gscan_params->lost_ap_window; - } else { - pfn_gscan_cfg_t->swc_nbssid_threshold = 0; - pfn_gscan_cfg_t->swc_rssi_window_size = 0; - pfn_gscan_cfg_t->lost_ap_window = 0; - } pfn_gscan_cfg_t->flags = (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); @@ -2277,37 +2179,6 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) __FUNCTION__, err)); goto exit; } - if (gscan_params->nbssid_significant_change) { - dhd_pno_significant_bssid_t *iter, *next; - - p_pfn_significant_bssid = kzalloc(sizeof(wl_pfn_significant_bssid_t) * - gscan_params->nbssid_significant_change, GFP_KERNEL); - if (p_pfn_significant_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate memory %zd\n", __FUNCTION__, - sizeof(wl_pfn_significant_bssid_t) * - gscan_params->nbssid_significant_change)); - err = BCME_NOMEM; - goto exit; - } - i = 0; - /* convert dhd_pno_significant_bssid_t to wl_pfn_significant_bssid_t */ - list_for_each_entry_safe(iter, next, &gscan_params->significant_bssid_list, list) { - p_pfn_significant_bssid[i].rssi_low_threshold = iter->rssi_low_threshold; - p_pfn_significant_bssid[i].rssi_high_threshold = iter->rssi_high_threshold; - memcpy(&p_pfn_significant_bssid[i].macaddr, &iter->BSSID, ETHER_ADDR_LEN); - i++; - } - - DHD_PNO(("nbssid_significant_change %d \n", - gscan_params->nbssid_significant_change)); - err = _dhd_pno_add_significant_bssid(dhd, p_pfn_significant_bssid, - gscan_params->nbssid_significant_change); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_add_significant_bssid(err :%d)\n", - __FUNCTION__, err)); - goto exit; - } - } if (gscan_params->nbssid_hotlist) { struct dhd_pno_bssid *iter, *next; @@ -2367,7 +2238,6 @@ exit: } } kfree(pssid_list); - kfree(p_pfn_significant_bssid); kfree(p_pfn_bssid); if (pfn_gscan_cfg_t) { MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size); @@ -3604,87 +3474,6 @@ dhd_retreive_batch_scan_results(dhd_pub_t *dhd) return err; } -/* Handle Significant WiFi Change (SWC) event from FW - * Send event to HAL when all results arrive from FW - */ -void * -dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes) -{ - void *ptr = NULL; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - struct dhd_pno_swc_evt_param *params; - wl_pfn_swc_results_t *results = (wl_pfn_swc_results_t *)event_data; - wl_pfn_significant_net_t *change_array; - int i; - - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - params = &(gscan_params->param_significant); - - if (!results->total_count) { - *send_evt_bytes = 0; - return ptr; - } - - if (!params->results_rxed_so_far) { - if (!params->change_array) { - params->change_array = (wl_pfn_significant_net_t *) - kmalloc(sizeof(wl_pfn_significant_net_t) * results->total_count, - GFP_KERNEL); - - if (!params->change_array) { - DHD_ERROR(("%s Cannot Malloc %zd bytes!!\n", __FUNCTION__, - sizeof(wl_pfn_significant_net_t) * results->total_count)); - *send_evt_bytes = 0; - return ptr; - } - } else { - DHD_ERROR(("RX'ed WLC_E_PFN_SWC evt from FW, previous evt not complete!!")); - *send_evt_bytes = 0; - return ptr; - } - } - - DHD_PNO(("%s: pkt_count %d total_count %d\n", __FUNCTION__, - results->pkt_count, results->total_count)); - - for (i = 0; i < results->pkt_count; i++) { - DHD_PNO(("\t %02x:%02x:%02x:%02x:%02x:%02x\n", - results->list[i].BSSID.octet[0], - results->list[i].BSSID.octet[1], - results->list[i].BSSID.octet[2], - results->list[i].BSSID.octet[3], - results->list[i].BSSID.octet[4], - results->list[i].BSSID.octet[5])); - } - - change_array = ¶ms->change_array[params->results_rxed_so_far]; - if ((params->results_rxed_so_far + results->pkt_count) <= results->total_count) { - memcpy(change_array, results->list, - sizeof(wl_pfn_significant_net_t) * results->pkt_count); - params->results_rxed_so_far += results->pkt_count; - } else { - /* In case of spurious event or invalid data send hang event */ - dhd_os_send_hang_message(dhd); - } - - if (params->results_rxed_so_far == results->total_count) { - params->results_rxed_so_far = 0; - *send_evt_bytes = sizeof(wl_pfn_significant_net_t) * results->total_count; - /* Pack up change buffer to send up and reset - * results_rxed_so_far, after its done. - */ - ptr = (void *) params->change_array; - /* expecting the callee to free this mem chunk */ - params->change_array = NULL; - } - else { - *send_evt_bytes = 0; - } - - return ptr; -} - void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) { @@ -3714,7 +3503,7 @@ dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) } void * -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size) { wl_bss_info_t *bi = NULL; wl_gscan_result_t *gscan_result; @@ -3723,6 +3512,8 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) uint8 channel; uint32 mem_needed; struct timespec ts; + u32 bi_ie_length = 0; + u32 bi_ie_offset = 0; *size = 0; @@ -3732,6 +3523,14 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); goto exit; } + if ((len < sizeof(*gscan_result)) || + (len < dtoh32(gscan_result->buflen)) || + (dtoh32(gscan_result->buflen) > + (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { + DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__, + dtoh32(gscan_result->buflen))); + goto exit; + } if (!gscan_result->bss_info) { DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); goto exit; @@ -3743,12 +3542,19 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } + bi_ie_offset = dtoh32(bi->ie_offset); + bi_ie_length = dtoh32(bi->ie_length); + if ((bi_ie_offset + bi_ie_length) > bi_length) { + DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n", + __FUNCTION__, bi_ie_length, bi_ie_offset)); + goto exit; + } if (bi->SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", bi->SSID_len)); - bi->SSID_len = DOT11_MAX_SSID_LEN; + DHD_ERROR(("%s: Invalid SSID length:%u\n", __FUNCTION__, bi->SSID_len)); + goto exit; } - mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi->ie_length; + mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi_ie_length; result = kmalloc(mem_needed, GFP_KERNEL); if (!result) { @@ -3770,9 +3576,9 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) result->ts = (uint64) TIMESPEC_TO_US(ts); result->beacon_period = dtoh16(bi->beacon_period); result->capability = dtoh16(bi->capability); - result->ie_length = dtoh32(bi->ie_length); + result->ie_length = bi_ie_length; memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN); - memcpy(result->ie_data, ((uint8 *)bi + bi->ie_offset), bi->ie_length); + memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length); *size = mem_needed; exit: return result; @@ -3836,6 +3642,12 @@ dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int wl_pfn_net_info_t *net; if (pfn_result->version != PFN_SCANRESULT_VERSION) { + /* Check if count of pfn results is corrupted */ + if (pfn_result->count > EVENT_MAX_NETCNT) { + DHD_ERROR(("%s event %d: pfn results count %d" + "exceeds the max limit\n", __FUNCTION__, event, pfn_result->count)); + return NULL; + } DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, pfn_result->version, PFN_SCANRESULT_VERSION)); return NULL; @@ -3956,7 +3768,8 @@ void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *s int malloc_size = 0, i, total = 0; gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - if (!results->count) { + if (!results->count || (results->count > EVENT_MAX_NETCNT)) { + DHD_ERROR(("%s: wrong result count:%d\n", __FUNCTION__, results->count)); *send_evt_bytes = 0; return ptr; } diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h index cf7fa9fbdb4e..361c5cecd34d 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h @@ -363,16 +363,18 @@ typedef struct { #endif /* ANQPO_SUPPORT */ typedef struct dhd_pno_gscan_capabilities { - int max_scan_cache_size; - int max_scan_buckets; - int max_ap_cache_per_scan; - int max_rssi_sample_size; - int max_scan_reporting_threshold; - int max_hotlist_aps; - int max_significant_wifi_change_aps; - int max_epno_ssid_crc32; - int max_epno_hidden_ssid; - int max_white_list_ssid; + int max_scan_cache_size; + int max_scan_buckets; + int max_ap_cache_per_scan; + int max_rssi_sample_size; + int max_scan_reporting_threshold; + int max_hotlist_bssids; + int max_hotlist_ssids; + int max_significant_wifi_change_aps; + int max_bssid_history_entries; + int max_epno_ssid_crc32; + int max_epno_hidden_ssid; + int max_white_list_ssid; } dhd_pno_gscan_capabilities_t; struct dhd_pno_gscan_params { @@ -431,26 +433,6 @@ typedef struct gscan_hotlist_scan_params { struct bssid_t bssid[1]; /* n bssids to follow */ } gscan_hotlist_scan_params_t; -/* SWC (Significant WiFi Change) params */ -typedef struct gscan_swc_params { - /* Rssi averaging window size */ - uint8 rssi_window; - /* Number of scans that the AP has to be absent before - * being declared LOST - */ - uint8 lost_ap_window; - /* if x Aps have a significant change generate an event. */ - uint8 swc_threshold; - uint8 nbssid; - wl_pfn_significant_bssid_t bssid_elem_list[1]; -} gscan_swc_params_t; - -typedef struct dhd_pno_significant_bssid { - struct ether_addr BSSID; - int8 rssi_low_threshold; - int8 rssi_high_threshold; - struct list_head list; -} dhd_pno_significant_bssid_t; #endif /* GSCAN_SUPPORT */ typedef union dhd_pno_params { struct dhd_pno_legacy_params params_legacy; @@ -511,13 +493,11 @@ int dhd_dev_pno_lock_access_batch_results(struct net_device *dev); void dhd_dev_pno_unlock_access_batch_results(struct net_device *dev); extern int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush); extern int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time); -extern void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, - int *send_evt_bytes); int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes, hotlist_type_t type); void * dhd_dev_process_full_gscan_result(struct net_device *dev, - const void *data, int *send_evt_bytes); + const void *data, uint32 len, int *send_evt_bytes); extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); @@ -563,11 +543,10 @@ extern int dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush); extern int dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag); extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *buf); extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); -extern void *dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes); extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, hotlist_type_t type); extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, - int *send_evt_bytes); + uint32 len, int *send_evt_bytes); extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c index 2614ceb7dae4..d1d29dea61be 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c @@ -1537,19 +1537,37 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) gfp_t kflags; bool is_new = TRUE; + DHD_RTT(("Enter %s \n", __FUNCTION__)); NULL_CHECK(dhd, "dhd is NULL", ret); + +#ifdef WL_CFG80211 rtt_status = GET_RTTSTATE(dhd); NULL_CHECK(rtt_status, "rtt_status is NULL", ret); - event_type = ntoh32_ua((void *)&event->event_type); - - if (event_type != WLC_E_PROXD) { - goto exit; - } if (RTT_IS_STOPPED(rtt_status)) { /* Ignore the Proxd event */ + DHD_RTT((" event handler rtt is stopped \n")); goto exit; } +#endif /* WL_CFG80211 */ + if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) { + DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__, + ntoh32_ua((void *)&event->datalen))); + ret = -EINVAL; + goto exit; + } + event_type = ntoh32_ua((void *)&event->event_type); + if (event_type != WLC_E_PROXD) { + DHD_ERROR((" failed event \n")); + ret = -EINVAL; + goto exit; + } + + if (!event_data) { + DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); + ret = -EINVAL; + goto exit; + } p_event = (wl_proxd_event_t *) event_data; version = ltoh16(p_event->version); if (version < WL_PROXD_API_VERSION) { @@ -1569,9 +1587,15 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) p_loginfo = ftm_get_event_type_loginfo(event_type); if (p_loginfo == NULL) { DHD_ERROR(("receive an invalid FTM event %d\n", event_type)); + ret = -EINVAL; goto exit; /* ignore this event */ } /* get TLVs len, skip over event header */ + if (ltoh16(p_event->len) < OFFSETOF(wl_proxd_event_t, tlvs)) { + DHD_ERROR(("invalid FTM event length:%d\n", ltoh16(p_event->len))); + ret = -EINVAL; + goto exit; + } tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs); DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n", p_loginfo->text, diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h index 4f25e0d6067e..99277f8b9fb9 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h @@ -32,17 +32,17 @@ #define EPI_RC_NUMBER 67 -#define EPI_INCREMENTAL_NUMBER 29 +#define EPI_INCREMENTAL_NUMBER 30 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 141, 67, 29 +#define EPI_VERSION 1, 141, 67, 30 -#define EPI_VERSION_NUM 0x018d431d +#define EPI_VERSION_NUM 0x018d431e #define EPI_VERSION_DEV 1.141.67 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.141.67.29 (r)" +#define EPI_VERSION_STR "1.141.67.30 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h index df9eb598f902..cec5d1eb5672 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wlioctl.h 598402 2015-11-09 13:36:35Z $ + * $Id: wlioctl.h 718508 2017-08-31 02:48:38Z $ */ #ifndef _wlioctl_h_ @@ -2550,10 +2550,6 @@ enum { #define PFN_SWC_MAX_NUM_APS 16 #define PFN_HOTLIST_MAX_NUM_APS 64 -#define PFN_SWC_RSSI_WINDOW_MAX 8 -#define PFN_SWC_MAX_NUM_APS 16 -#define PFN_HOTLIST_MAX_NUM_APS 64 - #define MAX_EPNO_HIDDEN_SSID 8 #define MAX_WHITELIST_SSID 2 diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index db2c198a1926..85d6aea376b9 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 704367 2017-06-13 09:05:24Z $ + * $Id: wl_cfg80211.c 718508 2017-08-31 02:48:38Z $ */ /* */ #include @@ -8944,15 +8944,6 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, u32 len = ntoh32(e->datalen); switch (event) { - case WLC_E_PFN_SWC: - ptr = dhd_dev_swc_scan_event(ndev, data, &send_evt_bytes); - if (send_evt_bytes) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_GSCAN_SIGNIFICANT_EVENT, ptr, send_evt_bytes); - kfree(ptr); - } else - err = -ENOMEM; - break; case WLC_E_PFN_BEST_BATCHING: err = dhd_dev_retrieve_batch_scan(ndev); if (err < 0) { @@ -8999,7 +8990,7 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } break; case WLC_E_PFN_GSCAN_FULL_RESULT: - ptr = dhd_dev_process_full_gscan_result(ndev, data, &send_evt_bytes); + ptr = dhd_dev_process_full_gscan_result(ndev, data, len, &send_evt_bytes); if (ptr) { wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes); @@ -9201,14 +9192,25 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wifi_p2p_pub_act_frame_t *act_frm = NULL; wifi_p2p_action_frame_t *p2p_act_frm = NULL; wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; - wl_event_rx_frame_data_t *rxframe = - (wl_event_rx_frame_data_t*)data; - u32 event = ntoh32(e->event_type); + wl_event_rx_frame_data_t *rxframe; + u32 event; u8 *mgmt_frame; - u8 bsscfgidx = e->bsscfgidx; - u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); - u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); - + u8 bsscfgidx; + u32 mgmt_frame_len; + u16 channel; + if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) { + WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen))); + return -EINVAL; + } + mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); + event = ntoh32(e->event_type); + bsscfgidx = e->bsscfgidx; + rxframe = (wl_event_rx_frame_data_t *)data; + if (!rxframe) { + WL_ERR(("rxframe: NULL\n")); + return -EINVAL; + } + channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK); memset(&bssid, 0, ETHER_ADDR_LEN); ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); @@ -9346,7 +9348,10 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_DBG((" Event WLC_E_PROBREQ_MSG received\n")); mgmt_frame = (u8 *)(data); mgmt_frame_len = ntoh32(e->datalen); - + if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) { + WL_ERR(("wrong datalen:%d\n", mgmt_frame_len)); + return -EINVAL; + } prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN; /* Parse prob_req IEs */ @@ -9586,7 +9591,6 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event; @@ -10037,6 +10041,11 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("Invalid escan result (NULL pointer)\n")); goto exit; } + if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) || + (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) { + WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen))); + goto exit; + } if (dtoh16(escan_result->bss_count) != 1) { WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); goto exit; @@ -11925,7 +11934,7 @@ static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *i { u8 *ssidie; int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); - int32 remaining_ie_buf_len, available_buffer_len; + int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len; ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); /* ERROR out if @@ -11940,24 +11949,28 @@ static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *i } available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream); remaining_ie_buf_len = available_buffer_len - (int)ssidie[1]; - if ((ssid_len > ssidie[1]) || - (ssidie[1] > available_buffer_len)) { + unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size); + if (ssidie[1] > available_buffer_len) { + WL_ERR(("%s: skip wl_update_hidden_ap_ie : overflow\n", __FUNCTION__)); return; } if (ssidie[1] != ssid_len) { if (ssidie[1]) { - WL_ERR(("%s: Wrong SSID len: %d != %d\n", + WL_INFO(("%s: Wrong SSID len: %d != %d\n", __FUNCTION__, ssidie[1], bi->SSID_len)); } - if (roam) { - WL_ERR(("Changing the SSID Info.\n")); + if ((roam && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) { + WL_INFO(("Changing the SSID Info.\n")); memmove(ssidie + ssid_len + 2, (ssidie + 2) + ssidie[1], remaining_ie_buf_len); memcpy(ssidie + 2, bi->SSID, ssid_len); *ie_size = *ie_size + ssid_len - ssidie[1]; ssidie[1] = ssid_len; + } else if (ssid_len < ssidie[1]) { + WL_ERR(("%s: Invalid SSID len: %d < %d\n", + __FUNCTION__, ssidie[1], bi->SSID_len)); } return; } diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c index c00171f392fb..f7b8c2b99ee5 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfgp2p.c 531064 2015-02-02 07:59:42Z $ + * $Id: wl_cfgp2p.c 711630 2017-07-19 04:16:07Z $ * */ #include @@ -2290,8 +2290,9 @@ wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib) return pAttrib; } else { - parse += (ie->len + TLV_HDR_LEN); - len -= (ie->len + TLV_HDR_LEN); + /* move to next IE */ + len -= (u32)((u8 *)ie + TLV_HDR_LEN + ie->len - parse); + parse = (uint8 *)ie + TLV_HDR_LEN + ie->len; CFGP2P_INFO(("P2P Attribute %d not found Moving parse" " to %p len to %d", attrib, parse, len)); } diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c index dcb9f3560e1a..d1b5543b07e8 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c @@ -1098,113 +1098,6 @@ wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy, return err; } -static int -wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_swc_params_t *significant_params; - int tmp, tmp1, tmp2, type, j = 0; - const struct nlattr *outer, *inner, *iter; - uint8 flush = 0; - wl_pfn_significant_bssid_t *bssid; - uint16 num_bssid = 0; - uint16 max_buf_size = sizeof(gscan_swc_params_t) + - sizeof(wl_pfn_significant_bssid_t) * (PFN_SWC_MAX_NUM_APS - 1); - - significant_params = kzalloc(max_buf_size, GFP_KERNEL); - if (!significant_params) { - WL_ERR(("Cannot Malloc mem size:%d\n", max_buf_size)); - return BCME_NOMEM; - } - - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - - switch (type) { - case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH: - flush = nla_get_u8(iter); - break; - case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE: - significant_params->rssi_window = nla_get_u16(iter); - break; - case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: - significant_params->lost_ap_window = nla_get_u16(iter); - break; - case GSCAN_ATTRIBUTE_MIN_BREACHING: - significant_params->swc_threshold = nla_get_u16(iter); - break; - case GSCAN_ATTRIBUTE_NUM_BSSID: - num_bssid = nla_get_u16(iter); - if (num_bssid > PFN_SWC_MAX_NUM_APS) { - WL_ERR(("ovar max SWC bssids:%d\n", - num_bssid)); - err = BCME_BADARG; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS: - if (num_bssid == 0) { - WL_ERR(("num_bssid : 0\n")); - err = BCME_BADARG; - goto exit; - } - bssid = significant_params->bssid_elem_list; - nla_for_each_nested(outer, iter, tmp) { - if (j >= num_bssid) { - j++; - break; - } - nla_for_each_nested(inner, outer, tmp1) { - switch (nla_type(inner)) { - case GSCAN_ATTRIBUTE_BSSID: - memcpy(&(bssid[j].macaddr), - nla_data(inner), - ETHER_ADDR_LEN); - break; - case GSCAN_ATTRIBUTE_RSSI_HIGH: - bssid[j].rssi_high_threshold - = (int8) nla_get_u8(inner); - break; - case GSCAN_ATTRIBUTE_RSSI_LOW: - bssid[j].rssi_low_threshold - = (int8) nla_get_u8(inner); - break; - default: - WL_ERR(("ATTR unknown %d\n", - type)); - break; - } - } - j++; - } - break; - default: - WL_ERR(("Unknown type %d\n", type)); - break; - } - } - if (j != num_bssid) { - WL_ERR(("swc bssids count:%d not matched to num_bssid:%d\n", - j, num_bssid)); - err = BCME_BADARG; - goto exit; - } - significant_params->nbssid = j; - - if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, - significant_params, flush) < 0) { - WL_ERR(("Could not set GSCAN significant cfg\n")); - err = BCME_ERROR; - goto exit; - } -exit: - kfree(significant_params); - return err; -} - static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { @@ -2238,14 +2131,6 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = { .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = wl_cfgvendor_hotlist_cfg }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_significant_change_cfg - }, { { .vendor_id = OUI_GOOGLE, -- GitLab From a1a4a95d5dd1dab6666178e09f4e8316475f8cf7 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Sat, 3 Mar 2018 08:58:47 +0300 Subject: [PATCH 205/528] drivers: wireless: bcm43455: Update to 1.141.67.32 * Sony package version: 34.4.A.2.19 (Xperia X) Signed-off-by: Andrey Cherepkov (cherry picked from commit 5625f0064a9b34c50b44f48136f0aa81a2bbc957) --- .../net/wireless/bcmdhd_bcm43455/dhd_common.c | 40 ++++---- .../bcmdhd_bcm43455/include/epivers.h | 8 +- .../net/wireless/bcmdhd_bcm43455/wl_android.c | 4 +- .../wireless/bcmdhd_bcm43455/wl_cfgvendor.c | 93 +++++++++++++------ 4 files changed, 91 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c index d141eb539c2c..44de43fb6bae 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c 701450 2017-05-25 02:10:23Z $ + * $Id: dhd_common.c 732203 2017-11-16 05:18:28Z $ */ #include #include @@ -2106,13 +2106,18 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte { char* str; int idx = 0; + uint8 len; if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; + return BCME_BADARG; } str = *list_str; while (*bytes_left > 0) { + if (idx >= max) { + DHD_ERROR(("%s number of SSIDs more than %d\n", __FUNCTION__, idx)); + return BCME_BADARG; + } if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { *list_str = str; @@ -2122,9 +2127,14 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte /* Get proper CSCAN_TLV_TYPE_SSID_IE */ *bytes_left -= 1; + if (*bytes_left == 0) { + DHD_ERROR(("%s no length field.\n", __FUNCTION__)); + return BCME_BADARG; + } str += 1; ssid[idx].rssi_thresh = 0; - if (str[0] == 0) { + len = str[0]; + if (len == 0) { /* Broadcast SSID */ ssid[idx].SSID_len = 0; memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); @@ -2132,20 +2142,17 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte str += 1; DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); - } - else if (str[0] <= DOT11_MAX_SSID_LEN) { + } else if (len <= DOT11_MAX_SSID_LEN) { /* Get proper SSID size */ - ssid[idx].SSID_len = str[0]; + ssid[idx].SSID_len = len; *bytes_left -= 1; - str += 1; - /* Get SSID */ if (ssid[idx].SSID_len > *bytes_left) { DHD_ERROR(("%s out of memory range len=%d but left=%d\n", __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); - return -1; + return BCME_BADARG; } - + str += 1; memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); *bytes_left -= ssid[idx].SSID_len; @@ -2154,16 +2161,11 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte DHD_TRACE(("%s :size=%d left=%d\n", (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); + } else { + DHD_ERROR(("### SSID size more than %d\n", str[0])); + return BCME_BADARG; } - else { - DHD_ERROR(("### SSID size more that %d\n", str[0])); - return -1; - } - - if (idx++ > max) { - DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); - return -1; - } + idx++; } *list_str = str; diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h index 99277f8b9fb9..caa82f18aed9 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h @@ -32,17 +32,17 @@ #define EPI_RC_NUMBER 67 -#define EPI_INCREMENTAL_NUMBER 30 +#define EPI_INCREMENTAL_NUMBER 32 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 141, 67, 30 +#define EPI_VERSION 1, 141, 67, 32 -#define EPI_VERSION_NUM 0x018d431e +#define EPI_VERSION_NUM 0x018d4320 #define EPI_VERSION_DEV 1.141.67 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.141.67.30 (r)" +#define EPI_VERSION_STR "1.141.67.32 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c index 5924e82e83f8..b5d8a683c1da 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_android.c 701450 2017-05-25 02:10:23Z $ + * $Id: wl_android.c 736234 2017-12-14 04:22:25Z $ */ #include @@ -378,7 +378,7 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) int err = BCME_OK; uint i, tokens; char *pos, *pos2, *token, *token2, *delim; - char param[PNO_PARAM_SIZE], value[VALUE_SIZE]; + char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1]; struct dhd_pno_batch_params batch_params; DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); if (total_len < strlen(CMD_WLS_BATCHING)) { diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c index d1b5543b07e8..5dcc1ddc4948 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c @@ -1278,53 +1278,88 @@ wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, int err = 0; int type, tmp; const struct nlattr *iter; - uint32 mem_needed = 0, flush = 0, i = 0, num = 0; + uint32 mem_needed = 0, flush = 0, num = 0; /* Assumption: NUM attribute must come first */ nla_for_each_attr(iter, data, len, tmp) { type = nla_type(iter); switch (type) { case GSCAN_ATTRIBUTE_NUM_BSSID: + if (num != 0) { + WL_ERR(("attempt to change BSSID num\n")); + err = -EINVAL; + goto exit; + } + if (nla_len(iter) != sizeof(uint32)) { + WL_ERR(("not matching nla_len.\n")); + err = -EINVAL; + goto exit; + } num = nla_get_u32(iter); - if (num > MAX_BSSID_BLACKLIST_NUM) { - WL_ERR(("Too many Blacklist BSSIDs!\n")); + if (num == 0 || num > MAX_BSSID_BLACKLIST_NUM) { + WL_ERR(("wrong BSSID count:%d\n", num)); err = -EINVAL; goto exit; } + if (!blacklist) { + mem_needed = OFFSETOF(maclist_t, ea) + + sizeof(struct ether_addr) * (num); + blacklist = (maclist_t *) + kzalloc(mem_needed, GFP_KERNEL); + if (!blacklist) { + WL_ERR(("kzalloc failed.\n")); + err = -ENOMEM; + goto exit; + } + } break; case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH: + if (nla_len(iter) != sizeof(uint32)) { + WL_ERR(("not matching nla_len.\n")); + err = -EINVAL; + goto exit; + } flush = nla_get_u32(iter); + if (flush != 1) { + WL_ERR(("flush arg is worng:%d\n", flush)); + err = -EINVAL; + goto exit; + } break; case GSCAN_ATTRIBUTE_BLACKLIST_BSSID: - if (num) { - if (!blacklist) { - mem_needed = sizeof(maclist_t) + - sizeof(struct ether_addr) * (num - 1); - blacklist = (maclist_t *) - kmalloc(mem_needed, GFP_KERNEL); - if (!blacklist) { - WL_ERR(("%s: Can't malloc %d bytes\n", - __FUNCTION__, mem_needed)); - err = -ENOMEM; - goto exit; - } - blacklist->count = num; - } - if (i >= num) { - WL_ERR(("CFGs don't seem right!\n")); - err = -EINVAL; - goto exit; - } - memcpy(&(blacklist->ea[i]), - nla_data(iter), ETHER_ADDR_LEN); - i++; + if (num == 0 || !blacklist) { + WL_ERR(("number of BSSIDs not received.\n")); + err = -EINVAL; + goto exit; } + if (nla_len(iter) != ETHER_ADDR_LEN) { + WL_ERR(("not matching nla_len.\n")); + err = -EINVAL; + goto exit; + } + if (blacklist->count >= num) { + WL_ERR(("too many BSSIDs than expected:%d\n", + blacklist->count)); + err = -EINVAL; + goto exit; + } + memcpy(&(blacklist->ea[blacklist->count]), nla_data(iter), + ETHER_ADDR_LEN); + blacklist->count++; break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - break; - } + default: + WL_ERR(("No such attribute:%d\n", type)); + break; + } + } + + if (blacklist && (blacklist->count != num)) { + WL_ERR(("not matching bssid count:%d to expected:%d\n", + blacklist->count, num)); + err = -EINVAL; + goto exit; } + err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg), blacklist, mem_needed, flush); exit: -- GitLab From 0631e5f585cd43a15afb1f4f0eeb24e3a3839916 Mon Sep 17 00:00:00 2001 From: zachariasmaladroit Date: Mon, 2 Oct 2017 01:30:41 +0200 Subject: [PATCH 206/528] drivers: wireless: bcm43455: Fix direct references to HZ inspired by work from humberos, kudos! Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit a024d34729754b610b1db8edbfadd51c4cde7713) --- drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c | 4 ++-- drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h | 2 +- drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c index c4f6a6461c20..b048b8434e38 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c @@ -5861,7 +5861,7 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); #endif timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); @@ -6233,7 +6233,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); #else - int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; + int timeout = IOCTL_RESP_TIMEOUT * msecs_to_jiffies(1); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ dhd_os_sdunlock(dhd); diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h index d586e5f8ba60..9b844be2c953 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h @@ -199,7 +199,7 @@ extern int osl_error(int bcmerror); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) #define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) #else -#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#define OSL_SYSUPTIME() ((uint32)jiffies * msecs_to_jiffies(1)) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ #define printf(fmt, args...) printk(fmt , ## args) #include /* for vsn/printf's */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index 85d6aea376b9..4973c96959dd 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -9841,7 +9841,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, int max_wait_timeout = 2; int max_wait_count = 100; int refcnt = 0; - unsigned long limit = jiffies + max_wait_timeout * HZ; + unsigned long limit = jiffies + max_wait_timeout * msecs_to_jiffies(1000); while (work_pending(&wdev->cleanup_work)) { if (refcnt%5 == 0) { WL_ERR(("[NETDEV_DOWN] wait for " -- GitLab From b4304eb57caa67435e51d479b70bc67c1f2f33d6 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 24 Oct 2017 13:30:13 +0300 Subject: [PATCH 207/528] drivers: wireless: bcm43455: fix warning: initialization from incompatible pointer type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c:7459:17: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types] .del_station = wl_cfg80211_del_station, ^~~~~~~~~~~~~~~~~~~~~~~ drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c:7459:17: note: (near initialization for ‘wl_cfg80211_ops.del_station’) Fix warning due to patch: 1d2389ba93 ("cfg80211: Convert del_station() callback to use a param struct") Signed-off-by: Andrey Cherepkov (cherry picked from commit 0edc83e56a432dbb5fa3a9a8b96a6aadcac4c95b) --- drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index 4973c96959dd..d0a3fb448c3e 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -378,8 +378,9 @@ static s32 wl_cfg80211_resume(struct wiphy *wiphy); 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); -static s32 wl_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *ndev, u8* mac_addr); +static s32 wl_cfg80211_del_station( + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params); static s32 wl_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ @@ -6796,9 +6797,8 @@ static s32 wl_cfg80211_hostapd_sec( 2, 0)) static s32 wl_cfg80211_del_station( - struct wiphy *wiphy, - struct net_device *ndev, - u8* mac_addr) + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params) { struct net_device *dev; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -6810,6 +6810,8 @@ wl_cfg80211_del_station( struct maclist *assoc_maclist = (struct maclist *)mac_buf; int num_associated = 0; + const u8 *mac_addr = params->mac; + WL_DBG(("Entry\n")); if (mac_addr == NULL) { WL_DBG(("mac_addr is NULL ignore it\n")); -- GitLab From 6aeb7ac6b10d9e280c791b316f94b83f75575b4b Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Sun, 7 Jan 2018 10:25:18 +0300 Subject: [PATCH 208/528] drivers: wireless: bcm43455: fix warning "tautological compare" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /drivers/net/wireless/bcmdhd_suzuran/siutils.c: In function ‘si_doattach’: /drivers/net/wireless/bcmdhd_suzuran/siutils.c:404:14: warning: self-comparison always evaluates to false [-Wtautological-compare] if (bustype != BUSTYPE(bustype)) { ^~ Signed-off-by: Andrey Cherepkov (cherry picked from commit 95827c58a995ee23b7da22897ca47534250e505b) --- drivers/net/wireless/bcmdhd_bcm43455/siutils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/siutils.c b/drivers/net/wireless/bcmdhd_bcm43455/siutils.c index 822161a5fbe7..64c2ba14b607 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/siutils.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/siutils.c @@ -401,12 +401,13 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, } sih->bustype = bustype; +#ifdef BCMBUSTYPE if (bustype != BUSTYPE(bustype)) { SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); return NULL; } - +#endif /* bus/core/clk setup for register access */ if (!si_buscore_prep(sii, bustype, devid, sdh)) { SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); -- GitLab From a4cf7a54df99c5b9568da8330f4d85e82c095302 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Mon, 3 Aug 2015 16:41:42 -0700 Subject: [PATCH 209/528] drivers: wireless: bcm43455: fix for watch dog issue in wifi connect test Bug => 22666437 fix for watchdog issue in fast switching APs. preventing numerous escan result which trigger watchdog. Change-Id: I835401008a644290df947e4bab1cedbd1599f6e6 Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit 23228a2aecb76df08fcbe78afc2cd489eeff3c96) --- drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index d0a3fb448c3e..35f16a6e9a29 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -10234,16 +10234,7 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); } -#ifdef GSCAN_SUPPORT - else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN)) { - if (status == WLC_E_STATUS_NEWSCAN) { - WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, - escan_result->bss_count)); - } -#else else if (status == WLC_E_STATUS_ABORT) { -#endif /* GSCAN_SUPPORT */ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; wl_escan_print_sync_id(status, escan_result->sync_id, cfg->escan_info.cur_sync_id); -- GitLab From b6a77ad44c2f070d5a2cde17a92fe03a433cbccd Mon Sep 17 00:00:00 2001 From: Ashwin Date: Fri, 16 Oct 2015 15:53:47 -0700 Subject: [PATCH 210/528] drivers: wireless: bcm43455: add a NULL check Check if the gscan result buffer was succesfully allocated Bug: 24469238 Change-Id: I1e896faed42ce53bc36ada449cc4e1c975830159 Signed-off-by: Ashwin Signed-off-by: Andrey Cherepkov (cherry picked from commit 0c39e0b29d5384e3e41e03bf703b1aea0ad8f026) --- drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c index 5f91924c2580..0c74d7021218 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c @@ -2607,6 +2607,12 @@ _dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) } plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + if (!plbestnet) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, + PNO_BESTNET_LEN)); + err = BCME_NOMEM; + goto exit; + } mutex_lock(&_pno_state->pno_mutex); -- GitLab From 313143c6d60b7c0ecd9bc80a283331a0807810b4 Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Sat, 5 Mar 2016 19:51:40 -0800 Subject: [PATCH 211/528] drivers: wireless: bcm43455: Fix CONFIG_HZ dependency in wifi driver Sleep for HZ jiffies, not 100. Bug: 27419732 Change-Id: I9717f2b539a7fe2e2ba2cd6c3fd231f987ec38a4 Signed-off-by: Tim Murray Signed-off-by: Andrey Cherepkov (cherry picked from commit c115ce5acb8776552653732b95885fa5e9960237) --- drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index 35f16a6e9a29..1deab30f15ba 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -9865,7 +9865,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100); + (void)schedule_timeout(HZ); set_current_state(TASK_RUNNING); refcnt++; } -- GitLab From 7048f2933c40747a3beba28c77d396c5b8ee204b Mon Sep 17 00:00:00 2001 From: Mir Ali Date: Mon, 20 Jun 2016 15:23:42 +0530 Subject: [PATCH 212/528] drivers: wireless: bcm43455: Check to avoid sending Disassoc in unassociated state The change is meant to send a Disassoc request only in the connected state thereby handling the case of a erroneous Diassoc from firmware BUG=28336924 Signed-off-by: Mir Ali Signed-off-by: Andrey Cherepkov (cherry picked from commit 5a75e9f02df6e6f239adc189c49ed37106b260ad) --- drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c index 08a5ecaf6560..f57cce3c7c79 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c @@ -31,6 +31,7 @@ #include #include +#include #define htod32(i) (i) #define htod16(i) (i) @@ -369,6 +370,9 @@ int wldev_set_country( wl_country_t cspec = {{0}, 0, {0}}; scb_val_t scbval; char smbuf[WLC_IOCTL_SMLEN]; + struct wireless_dev *wdev = ndev_to_wdev(dev); + struct wiphy *wiphy = wdev->wiphy; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); if (!country_code) return error; @@ -383,7 +387,7 @@ int wldev_set_country( if ((error < 0) || (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { - if (user_enforced) { + if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) { bzero(&scbval, sizeof(scb_val_t)); error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); if (error < 0) { -- GitLab From 132f937ac41836b293a8cfbbc6b203041e67864a Mon Sep 17 00:00:00 2001 From: Insun Song Date: Thu, 14 Jul 2016 14:49:48 -0700 Subject: [PATCH 213/528] drivers: wireless: bcm43455: add boundary check while getting channel spec Adding check for chanspec-list count. If count is over than maximum, then cancel current process and immediately return. This will also prevent kernel panic once caused by watchdog timeout. Bug=29863589 Change-Id: Ib2de9d71ca39c3fd97a7d684db9925940904e404 Signed-off-by: Insun Song Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit 46e93790d2284431e1fb9428da290a7795983194) --- drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index 1deab30f15ba..78081df71a87 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -11204,6 +11204,13 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) #undef LOCAL_BUF_LEN list = (wl_uint32_list_t *)(void *)pbuf; + + if ((list) && (dtoh32(list->count) > htod32(WL_NUMCHANSPECS))) { + WL_ERR(("Invalid channel list : %d\n", dtoh32(list->count))); + kfree(pbuf); + return INVCHANSPEC; + } + band = array_size = n_2g = n_5g = 0; for (i = 0; i < dtoh32(list->count); i++) { index = 0; -- GitLab From 0cbf3beaebef8113fb49d2a9b8f32b4f51b30efd Mon Sep 17 00:00:00 2001 From: Insun Song Date: Tue, 25 Oct 2016 13:33:18 -0700 Subject: [PATCH 214/528] drivers: wireless: bcm43455: fix buffer overrun in private command path buffer overrun case found when length parameter manipulated. 1. if input parameter buffer length is less than 4k, then allocate 4k by default. It help to get enough margin for output string overwritten. 2. added additional length check not to override user space allocated buffer size. Bug=29000183 Change-Id: I0c15d764c1648920f0214ec47ada689ca44ebfba Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit 6d460bc3dd2d18af281f388d8ab023107d34adb3) --- .../net/wireless/bcmdhd_bcm43455/wl_android.c | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c index b5d8a683c1da..e7f6e9e83386 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c @@ -294,19 +294,22 @@ static int wl_android_get_rssi(struct net_device *net, char *command, int total_ return -1; if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); - } else if (total_len <= ssid.SSID_len) { - return -ENOMEM; } else { - memcpy(command, ssid.SSID, ssid.SSID_len); - bytes_written = ssid.SSID_len; + if (total_len > ssid.SSID_len) { + memcpy(command, ssid.SSID, ssid.SSID_len); + bytes_written = ssid.SSID_len; + } else { + return BCME_ERROR; + } } - if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1)) - return -ENOMEM; - - bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written, + if ((total_len - bytes_written) >= (strlen(" rssi -XXX") + 1)) { + bytes_written += snprintf(&command[bytes_written], total_len - bytes_written, " rssi %d", rssi); - command[bytes_written] = '\0'; + command[bytes_written] = '\0'; + } else { + return BCME_ERROR; + } DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); return bytes_written; @@ -2015,13 +2018,18 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) } } if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) { - DHD_ERROR(("%s: invalid length of private command : %d\n", + DHD_ERROR(("%s: invalid length of private command : %d \n", __FUNCTION__, priv_cmd.total_len)); ret = -EINVAL; goto exit; } - buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN); + if (priv_cmd.total_len < PRIVATE_COMMAND_DEF_LEN) { + buf_size = PRIVATE_COMMAND_DEF_LEN; + } else { + buf_size = priv_cmd.total_len; + } + command = kmalloc((buf_size + 1), GFP_KERNEL); if (!command) @@ -2263,19 +2271,22 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) #endif else { DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); - bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); + snprintf(command, 5, "FAIL"); + bytes_written = strlen("FAIL"); } if (bytes_written >= 0) { - if ((bytes_written == 0) && (priv_cmd.total_len > 0)) + if ((bytes_written == 0) && (priv_cmd.total_len > 0)) { command[0] = '\0'; + } if (bytes_written >= priv_cmd.total_len) { - DHD_ERROR(("%s: err. bytes_written:%d >= buf_size:%d \n", - __FUNCTION__, bytes_written, buf_size)); + DHD_ERROR(("%s: not enough for output. bytes_written:%d >= total_len:%d \n", + __FUNCTION__, bytes_written, priv_cmd.total_len)); ret = BCME_BUFTOOSHORT; goto exit; + } else { + bytes_written++; } - bytes_written++; priv_cmd.used_len = bytes_written; if (copy_to_user(priv_cmd.buf, command, bytes_written)) { DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); @@ -2288,7 +2299,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) exit: net_os_wake_unlock(net); - kfree(command); + if (command) { + kfree(command); + } return ret; } -- GitLab From 51bd6b990a07ab4d4559016cdf7f69241205078f Mon Sep 17 00:00:00 2001 From: Insun Song Date: Tue, 31 Jan 2017 16:18:40 -0800 Subject: [PATCH 215/528] drivers: wireless: bcm43455: fix buffer overrun in wl_android_set_roampref added boundary check not to override allocated buffer. Specially when user input corrupted or manipulated. Bug: 34469904 Change-Id: Id6196da10111517696eda5f186b1e2dd19f66085 Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit 5bb5e2a6b52ba736f23f5b31615cb31fa68c50a8) --- drivers/net/wireless/bcmdhd_bcm43455/wl_android.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c index e7f6e9e83386..a7ac9103077a 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c @@ -1289,6 +1289,10 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); + if (num_ucipher_suites > MAX_NUM_SUITES) { + DHD_ERROR(("too many UCIPHER suites = %d\n", num_ucipher_suites)); + return -1; + } /* Increment for number of cipher suites field + space */ pcmd += 3; total_len_left -= 3; -- GitLab From 5e250c55c7120e4a6baed2fee7e28bb00b857b72 Mon Sep 17 00:00:00 2001 From: Joe Maples Date: Mon, 1 May 2017 09:47:29 -0500 Subject: [PATCH 216/528] drivers: wireless: bcm43455: We get it, negative 30 is invalid Stop log spam when return value is -30 Signed-off-by: Joe Maples Signed-off-by: Andrey Cherepkov (cherry picked from commit 6c468b3554cfdc03cc7ed35df63dc49e9e4c683a) --- drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c index 44de43fb6bae..7b996e6a9b45 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c @@ -1217,7 +1217,7 @@ wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu) int ret; ret = is_wlc_event_frame(pktdata, pktlen, 0, evu); - if (ret != BCME_OK) { + if (ret != BCME_OK && ret != -30) { DHD_ERROR(("%s: Invalid event frame, err = %d\n", __FUNCTION__, ret)); } -- GitLab From 6354a359f50970c9325d77f7f1da844616c5e0d4 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Wed, 3 May 2017 16:20:41 -0700 Subject: [PATCH 217/528] drivers: wireless: bcm43455: adding boundary check in wl_cfg80211_mgmt_tx added boundary check for user-input parameter not to corrupt kernel memmory. Bug: 35195787 Change-Id: Ia497feae5f502c9a650e50a39fd0620fa976d908 Signed-off-by: Insun Song Signed-off-by: Joe Maples Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit 91a15fe3cfd6faef5c8f1cc9382f08efa70d3f5c) --- drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index 78081df71a87..dd5fb0275d80 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -5594,7 +5594,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, WL_DBG(("Enter \n")); - if (len > ACTION_FRAME_SIZE) { + if (len > (ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN)) { WL_ERR(("bad length:%zu\n", len)); return BCME_BADLEN; } -- GitLab From 8132c3ef1159e231c4b48f9469feb7b879d26570 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Fri, 19 May 2017 17:34:10 -0700 Subject: [PATCH 218/528] drivers: wireless: bcm43455: fix RTT report of providing wrong information adding exception handling for RX rate/bitrate translation in RTT report. The missing error check resulted in wrong interpretation and it caused legacy HAL layer crash. Bug:37505450 Change-Id: I088e20d882b76afd8c8ba5db0390de4df57fd7ea Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit 0ea159220200e4377a3eac77f3e29f88f50134c8) --- .../net/wireless/bcmdhd_bcm43455/dhd_rtt.c | 33 +++++++++++++++---- .../net/wireless/bcmdhd_bcm43455/dhd_rtt.h | 8 +++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c index d1d29dea61be..b80fffe86ae1 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c @@ -448,7 +448,7 @@ rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) int rate_rspec2rate(uint32 rspec) { - int rate = -1; + int rate = 0; if (RSPEC_ISLEGACY(rspec)) { rate = 500 * (rspec & WL_RSPEC_RATE_MASK); @@ -474,7 +474,7 @@ rate_rspec2rate(uint32 rspec) ASSERT(0); } - return (rate == 0) ? -1 : rate; + return rate; } char resp_buf[WLC_IOCTL_SMLEN]; @@ -1387,17 +1387,38 @@ static wifi_rate_t dhd_rtt_convert_rate_to_host(uint32 rspec) { wifi_rate_t host_rate; - if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { + uint32 bandwidth; + memset(&host_rate, 0, sizeof(wifi_rate_t)); + if (RSPEC_ISLEGACY(rspec)) { host_rate.preamble = 0; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { + } else if (RSPEC_ISHT(rspec)) { host_rate.preamble = 2; host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { + } else if (RSPEC_ISVHT(rspec)) { host_rate.preamble = 3; host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; } - host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1; + + bandwidth = RSPEC_BW(rspec); + switch (bandwidth) { + case WL_RSPEC_BW_20MHZ: + host_rate.bw = RTT_RATE_20M; + break; + case WL_RSPEC_BW_40MHZ: + host_rate.bw = RTT_RATE_40M; + break; + case WL_RSPEC_BW_80MHZ: + host_rate.bw = RTT_RATE_80M; + break; + case WL_RSPEC_BW_160MHZ: + host_rate.bw = RTT_RATE_160M; + break; + default: + host_rate.bw = RTT_RATE_20M; + break; + } + host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); return host_rate; diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h index 308f657391a5..08216dbc8d08 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h @@ -128,6 +128,14 @@ enum { RTT_BW_80 = BIT(4), RTT_BW_160 = BIT(5) }; + +enum rtt_rate_bw { + RTT_RATE_20M, + RTT_RATE_40M, + RTT_RATE_80M, + RTT_RATE_160M +}; + #define FTM_MAX_NUM_BURST_EXP 14 #define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) #define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) -- GitLab From e34daacc2872989f3422612133888bc4a0895a18 Mon Sep 17 00:00:00 2001 From: Gautam Date: Fri, 28 Jul 2017 01:32:39 +0200 Subject: [PATCH 219/528] drivers: wireless: bcm43455: Disable debug trace event WLC_E_TRACE WLC_E_TRACE event is not required when device goes to suspend. This event is for debugging purpose and can be enabled back using wlutil command. BUG:24270601 Change-Id: Ic28cf5c0f88c831537c5e6c0b6b727c33de281b1 Signed-off-by: Gautam apply to both bcmdhd for kitakami Signed-off-by: zachariasmaladroit Signed-off-by: Andrey Cherepkov (cherry picked from commit 502bc6fb6a0fea324e6452aadb9d7fc468ad097d) --- drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c index b048b8434e38..5f0a4ef5907c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c @@ -4784,7 +4784,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLAIBSS setbit(eventmask, WLC_E_AIBSS_TXFAIL); #endif /* WLAIBSS */ +#ifdef SHOW_LOGTRACE setbit(eventmask, WLC_E_TRACE); +#else + clrbit(eventmask, WLC_E_TRACE); +#endif /* SHOW_LOGTRACE */ #ifdef DHD_LOSSLESS_ROAMING setbit(eventmask, WLC_E_ROAM_PREP); #endif /* DHD_LOSSLESS_ROAMING */ -- GitLab From 14efafacdc4a4ccf3f4fb18ec520aa9998ed0b81 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Mon, 11 Dec 2017 22:32:41 +0300 Subject: [PATCH 220/528] drivers: wireless: bcm43455: Add ability to pass flags to get_country_code Change-Id: Ifff040c88c2e268cf67293b51c5bcda1c5b15910 Signed-off-by: Dmitry Shmidt Signed-off-by: Andrey Cherepkov (cherry picked from commit 7e5ce667841056ea898b2916074bffe6d67d57de) --- drivers/net/wireless/bcmdhd_bcm43455/dhd.h | 15 ++++++++- .../bcmdhd_bcm43455/dhd_custom_gpio.c | 9 ++++++ .../net/wireless/bcmdhd_bcm43455/dhd_linux.c | 24 ++++++++++++++ .../net/wireless/bcmdhd_bcm43455/dhd_linux.h | 25 +++++++++++++++ .../bcmdhd_bcm43455/dhd_linux_platdev.c | 18 +++++------ .../wireless/bcmdhd_bcm43455/wl_cfgvendor.c | 32 +++++++++++++++++++ 6 files changed, 112 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd.h index 743fa9c40863..454f6f58c0b2 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd.h @@ -263,6 +263,10 @@ typedef struct dhd_pub { int pktfilter_count; wl_country_t dhd_cspec; /* Current Locale info */ +#ifdef CUSTOM_FORCE_NODFS_FLAG + uint dhd_cflags; +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + bool force_country_change; char eventmask[WL_EVENTING_MASK_LEN]; int op_mode; /* STA, HostAPD, WFD, SoftAP */ @@ -584,6 +588,9 @@ extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); extern int dhd_dev_get_feature_set(struct net_device *dev); extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); +#ifdef CUSTOM_FORCE_NODFS_FLAG +extern int dhd_dev_set_nodfs(struct net_device *dev, uint nodfs); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ extern int dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui); extern int dhd_set_rand_mac_oui(dhd_pub_t *dhd); @@ -641,7 +648,13 @@ extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff); extern int somc_get_mac_address(unsigned char *buf); #endif /* GET_CUSTOM_MAC_ENABLE */ extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf); -extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec); +#ifdef CUSTOM_FORCE_NODFS_FLAG +extern void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec, u32 flags); +#else +extern void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c index d45598994a6a..1116cee10913 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c @@ -546,7 +546,12 @@ const struct cntry_locales_custom translate_custom_table[] = { * input : ISO 3166-1 country abbreviation * output: customized cspec */ +#ifdef CUSTOM_FORCE_NODFS_FLAG +void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec, u32 flags) +#else void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec) +#endif /* CUSTOM_FORCE_NODFS_FLAG */ { #if 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))) @@ -555,7 +560,11 @@ void get_customized_country_code(void *adapter, char *country_iso_code, wl_count if (!cspec) return; +#ifdef CUSTOM_FORCE_NODFS_FLAG + cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code, flags); +#else cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ if (cloc_ptr) { strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); cspec->rev = cloc_ptr->custom_locale_rev; diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c index 5f0a4ef5907c..2e6676346388 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c @@ -3594,6 +3594,10 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #ifdef GET_CUSTOM_MAC_ENABLE wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet); #endif /* GET_CUSTOM_MAC_ENABLE */ +#ifdef CUSTOM_FORCE_NODFS_FLAG + dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; + dhd->pub.force_country_change = TRUE; +#endif #ifdef CUSTOM_COUNTRY_CODE cloc_ptr = wifi_platform_get_country_code(dhd->adapter, dhd->pub.dhd_cspec.ccode); if (cloc_ptr) { @@ -6557,6 +6561,21 @@ dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num) return ret; } +#ifdef CUSTOM_FORCE_NODFS_FLAG +int +dhd_dev_set_nodfs(struct net_device *dev, u32 nodfs) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (nodfs) + dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; + else + dhd->pub.dhd_cflags &= ~WLAN_PLAT_NODFS_FLAG; + dhd->pub.force_country_change = TRUE; + return 0; +} +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + #ifdef PNO_SUPPORT /* Linux wrapper to call common dhd_pno_stop_for_ssid */ int @@ -7274,7 +7293,12 @@ void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_c wl_country_t *cspec) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); +#ifdef CUSTOM_FORCE_NODFS_FLAG + get_customized_country_code(dhd->adapter, country_iso_code, cspec, + dhd->pub.dhd_cflags); +#else get_customized_country_code(dhd->adapter, country_iso_code, cspec); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ } void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) { diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h index af6517b8de7b..5129d8d1225b 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h @@ -37,6 +37,27 @@ #include #include +#if defined(CONFIG_WIFI_CONTROL_FUNC) +#include +#endif +#ifdef CUSTOM_FORCE_NODFS_FLAG +#define WLAN_PLAT_NODFS_FLAG 0x01 +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +#if !defined(CONFIG_WIFI_CONTROL_FUNC) +struct wifi_platform_data { + int (*set_power)(int val); + int (*set_reset)(int val); + int (*set_carddetect)(int val); + void *(*mem_prealloc)(int section, unsigned long size); + int (*get_mac_addr)(unsigned char *buf); +#ifdef CUSTOM_FORCE_NODFS_FLAG + void *(*get_country_code)(char *ccode, u32 flags); +#else + void *(*get_country_code)(char *ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +}; +#endif /* CONFIG_WIFI_CONTROL_FUNC */ + #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ typedef struct wifi_adapter_info { @@ -64,7 +85,11 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present); int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr); int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf); +#ifdef CUSTOM_FORCE_NODFS_FLAG +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags); +#else void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size); void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter); diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c index a25ce6f51beb..447578a0439c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c @@ -47,16 +47,6 @@ #ifdef CONFIG_SOMC_WIFI_CONTROL #include #endif /* CONFIG_SOMC_WIFI_CONTROL */ -#if !defined(CONFIG_WIFI_CONTROL_FUNC) -struct wifi_platform_data { - int (*set_power)(int val); - int (*set_reset)(int val); - int (*set_carddetect)(int val); - void *(*mem_prealloc)(int section, unsigned long size); - int (*get_mac_addr)(unsigned char *buf); - void *(*get_country_code)(char *ccode); -}; -#endif /* CONFIG_WIFI_CONTROL_FUNC */ #define WIFI_PLAT_NAME "bcmdhd_wlan" #define WIFI_PLAT_NAME2 "bcm4329_wlan" @@ -239,7 +229,11 @@ int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf) #endif } +#ifdef CUSTOM_FORCE_NODFS_FLAG +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags) +#else void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) +#endif /* CUSTOM_FORCE_NODFS_FLAG */ { /* get_country_code was added after 2.6.39 */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) @@ -251,7 +245,11 @@ void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) DHD_TRACE(("%s\n", __FUNCTION__)); if (plat_data->get_country_code) { +#ifdef CUSTOM_FORCE_NODFS_FLAG /* CUSTOM_COUNTRY_CODE */ + return plat_data->get_country_code(ccode, flags); +#else return plat_data->get_country_code(ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ } #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c index 5dcc1ddc4948..8449e39c276d 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c @@ -213,6 +213,27 @@ wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy, return err; } +#ifdef CUSTOM_FORCE_NODFS_FLAG +static int +wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + u32 nodfs; + + type = nla_type(data); + if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) { + nodfs = nla_get_u32(data); + err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs); + } else { + err = -1; + } + return err; +} +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + #ifdef GSCAN_SUPPORT int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, @@ -2233,6 +2254,17 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = { .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = wl_cfgvendor_set_rand_mac_oui }, +#ifdef CUSTOM_FORCE_NODFS_FLAG + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_NODFS_CHANNELS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_nodfs_flag + + }, +#endif /* CUSTOM_FORCE_NODFS_FLAG */ #ifdef LINKSTAT_SUPPORT { { -- GitLab From 9b5ce0decacd655a12cc6fc4f38bdbd1d188b63d Mon Sep 17 00:00:00 2001 From: Insun Song Date: Wed, 3 Jan 2018 13:57:12 -0800 Subject: [PATCH 221/528] drivers: wireless: bcm43455: fix integer overflow in wl_get_assoc_ies integer overflow case found where signed integer variable converted to unsigned one without proper bounds checking. Then this would result in kernel memory corruption by OOB write. CVE-2017-13292 Bug: 70722061 Change-Id: Idb1aa16ae1bae9c3f601e6688cd263fa95a93bdf Signed-off-by: Insun Song Signed-off-by: Andrey Cherepkov (cherry picked from commit aaa8556bd3cf32a67f47ebd92f662bf41fd529bb) --- .../wireless/bcmdhd_bcm43455/wl_cfg80211.c | 76 ++++++++++++------- .../wireless/bcmdhd_bcm43455/wl_cfg80211.h | 6 +- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index dd5fb0275d80..e4e1fc8cde2d 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -8526,6 +8526,32 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.req_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.req_len > 0) && + (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0)))) { + err = BCME_BADLEN; + goto exit; + } + if (assoc_info.resp_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.resp_len > 0) && + (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -8534,48 +8560,42 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) conn_info->resp_ie_len = 0; bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); } + if (assoc_info.req_len) { - err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - return err; + goto exit; } - conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); + conn_info->req_ie_len = assoc_info.req_len - + sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - if (conn_info->req_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->req_ie_len, MAX_REQ_LINE)); - return err; - } - } else { - conn_info->req_ie_len = 0; + memcpy(conn_info->req_ie, cfg->extra_buf, + conn_info->req_ie_len); } + if (assoc_info.resp_len) { - err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - return err; - } - conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); - if (conn_info->resp_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->resp_ie_len, MAX_REQ_LINE)); - return err; + goto exit; } - } else { - conn_info->resp_ie_len = 0; + conn_info->resp_ie_len = + assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + memcpy(conn_info->resp_ie, cfg->extra_buf, + conn_info->resp_ie_len); } - WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, - conn_info->resp_ie_len)); +exit: + if (err) { + WL_ERR(("err:%d assoc-req:%u,resp:%u conn-req:%u,resp:%u\n", + err, assoc_info.req_len, assoc_info.resp_len, + conn_info->req_ie_len, conn_info->resp_ie_len)); + } return err; } diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h index 069eda344e49..d62792b0d2e5 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h @@ -364,12 +364,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024 +#define MAX_REQ_LINE 1024u struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - s32 req_ie_len; + u32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - s32 resp_ie_len; + u32 resp_ie_len; }; /* firmware /nvram downloading controller */ -- GitLab From 79017c26909bec0cbfe1d603953d263a8a6c3cb0 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 29 May 2018 21:47:41 +0300 Subject: [PATCH 222/528] Revert "drivers: wireless: bcm43455: fix integer overflow in wl_get_assoc_ies" This reverts commit 07ea1e5e45. This fix is present in 1.141.67.33. (cherry picked from commit f0628aa0417f76e7c1711ebc4f8df78e4b9ff4b8) --- .../wireless/bcmdhd_bcm43455/wl_cfg80211.c | 76 +++++++------------ .../wireless/bcmdhd_bcm43455/wl_cfg80211.h | 6 +- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index e4e1fc8cde2d..dd5fb0275d80 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -8526,32 +8526,6 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); - - if (assoc_info.req_len > - (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + - ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? - ETHER_ADDR_LEN : 0))) { - err = BCME_BADLEN; - goto exit; - } - if ((assoc_info.req_len > 0) && - (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + - ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? - ETHER_ADDR_LEN : 0)))) { - err = BCME_BADLEN; - goto exit; - } - if (assoc_info.resp_len > - (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { - err = BCME_BADLEN; - goto exit; - } - if ((assoc_info.resp_len > 0) && - (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { - err = BCME_BADLEN; - goto exit; - } - if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -8560,42 +8534,48 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) conn_info->resp_ie_len = 0; bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); } - if (assoc_info.req_len) { - err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, - cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - goto exit; + return err; } - conn_info->req_ie_len = assoc_info.req_len - - sizeof(struct dot11_assoc_req); + conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - memcpy(conn_info->req_ie, cfg->extra_buf, - conn_info->req_ie_len); + if (conn_info->req_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); + else { + WL_ERR(("IE size %d above max %d size \n", + conn_info->req_ie_len, MAX_REQ_LINE)); + return err; + } + } else { + conn_info->req_ie_len = 0; } - if (assoc_info.resp_len) { - err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, - cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, + WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - goto exit; + return err; + } + conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); + if (conn_info->resp_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); + else { + WL_ERR(("IE size %d above max %d size \n", + conn_info->resp_ie_len, MAX_REQ_LINE)); + return err; } - conn_info->resp_ie_len = - assoc_info.resp_len - sizeof(struct dot11_assoc_resp); - memcpy(conn_info->resp_ie, cfg->extra_buf, - conn_info->resp_ie_len); + } else { + conn_info->resp_ie_len = 0; } + WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, + conn_info->resp_ie_len)); -exit: - if (err) { - WL_ERR(("err:%d assoc-req:%u,resp:%u conn-req:%u,resp:%u\n", - err, assoc_info.req_len, assoc_info.resp_len, - conn_info->req_ie_len, conn_info->resp_ie_len)); - } return err; } diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h index d62792b0d2e5..069eda344e49 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h @@ -364,12 +364,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024u +#define MAX_REQ_LINE 1024 struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - u32 req_ie_len; + s32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - u32 resp_ie_len; + s32 resp_ie_len; }; /* firmware /nvram downloading controller */ -- GitLab From dcc3ad2d84500c5e44e6a36dcca7c01467ed010a Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 29 May 2018 22:17:41 +0300 Subject: [PATCH 223/528] drivers: wireless: bcm43455: add Makefile for Nougat (cherry picked from commit d3cbcce70ec1a7837349fa9f9c609529a9533f6d) --- .../net/wireless/bcmdhd_bcm43455/Makefile.N | 414 ++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/Makefile.N diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Makefile.N b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.N new file mode 100644 index 000000000000..b2d2f597ad78 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.N @@ -0,0 +1,414 @@ +# bcmdhd + +##################### +# SDIO Basic feature +##################### +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ + -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ + -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ + -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ + -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ + -DCONFIG_DTS + +#################### +# Common feature +#################### +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 +# For Kernel ver > 3.6 or Kernel Patch required +DHDCFLAGS += -DWL_SUPPORT_CHAN_BW + +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# DPC priority +#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# idle count +DHDCFLAGS += -DDHD_USE_IDLECOUNT + +# custom specific value define +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# set keep alive period +ifneq ($(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING),) +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=$(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING) +else +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 +endif +# set roam setting values +DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 +DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +# SKB TAILPAD to avoid out of boundary memory access +DHDCFLAGS += -DDHDENABLE_TAILPAD + +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS + +DHDCFLAGS += -DSUPPORT_P2P_GO_PS + +# Disable TXBF sending +DHDCFLAGS += -DDISABLE_TXBFR + +DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + +# Disable to delay link down event +DHDCFLAGS += -DDISABLE_BCN_DLY + +############################## +# Android Platform Definition +############################## +BCM_SRC_DIR := ./ + +############################### +# Android M +############################### +DHDCFLAGS += -DWL_ENABLE_P2P_IF + +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS +# To support p2p private command on kernel 3.8 or above +DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT + +ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD +endif + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +ifneq ($(CONFIG_BCM4339),) +# To support GSCAN +#DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o +endif + +ifneq ($(CONFIG_BCM43455),) +# To support RTT +DHDCFLAGS += -DRTT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT +# To support ePNO +DHDCFLAGS += -DEPNO_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support Rssi Monitor +DHDCFLAGS += -DRSSI_MONITOR_SUPPORT +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT +# To support ANQPO - GSCAN must be supported +DHDCFLAGS += -DANQPO_SUPPORT + +# Extra file list for Android M, SOMC +ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o bcmxtlv.o +endif + +ifneq ($(CONFIG_BCM4354),) +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Android M +ANDROID_OFILES := wl_cfgvendor.o +endif + + +######################### +# Chip dependent feature +######################### +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DSDIO_CRC_ERROR_FIX + +# tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DREPEAT_READFRAME + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +# DRIVER_TYPE = y +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # for 4339 only currently - need test for 4354, 43455 + DHDCFLAGS += -DDHD_LOSSLESS_ROAMING + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM43455),) + DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM43455),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + + # Radio_stat v2 - data structure is updated + DHDCFLAGS += -DLINKSTAT_V2 + + DHDCFLAGS += -DWL_ABORT_SCAN +endif + +# Read custom mac address function +DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE + +# Default Beacon timeout +ifneq ($(CONFIG_SOMC_WLAN_BCN_TIMEOUT),) + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=$(CONFIG_SOMC_WLAN_BCN_TIMEOUT) +else + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=3 +endif + +# The number of the maximum devices which phone can associate +DHDCFLAGS += -DSOMC_MAX_ASSOC_NUM=10 + +# Default Listen Interval in Beacons +ifneq ($(CONFIG_SOMC_WLAN_LISTEN_INTERVAL),) + DHDCFLAGS += -DCUSTOM_LISTEN_INTERVAL=$(CONFIG_SOMC_WLAN_LISTEN_INTERVAL) +endif + +# WAPI +DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI + +# Set the number of probe requests per channel +ifneq ($(CONFIG_SOMC_WLAN_SCAN_NPROBES),) + DHDCFLAGS += -DSOMC_WLAN_SCAN_NPROBES=$(CONFIG_SOMC_WLAN_SCAN_NPROBES) +endif + +# Set default nvram path +ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) + DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" +endif + +# Change scan time +ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) + DHDCFLAGS += -DCHANGE_SCAN_TIME +endif + +# Get country code +#DHDCFLAGS += -DCUSTOM_FORCE_NODFS_FLAG + +# Enable to use Ukraine CODE (UA/999) +DHDCFLAGS += -DENABLE_80211AC_FOR_UA + +#EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +MODNAME := wlan + +DHDOFILES := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o \ + dhd_linux_wq.o aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o \ + hndpmu.o linux_osl.o sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o \ + dhd_somc_custom.o + +DHDOFILES += $(ANDROID_OFILES) + +# Module information used by KBuild framework +obj-$(CONFIG_BCMDHD_BCM43455) += $(MODNAME).o + +$(MODNAME)-objs := $(DHDOFILES) -- GitLab From 32577f7a81eb28fe9d081e973c33a456d6e35e77 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 29 May 2018 21:52:47 +0300 Subject: [PATCH 224/528] drivers: wireless: bcm43455: Add Release Note 1.141.67.33 (cherry picked from commit 96f3c0fd184e95bf0a599a74a10755d7cd94ff64) --- .../bcmdhd_bcm43455/ChangeLog/ReleaseNote.txt | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 drivers/net/wireless/bcmdhd_bcm43455/ChangeLog/ReleaseNote.txt diff --git a/drivers/net/wireless/bcmdhd_bcm43455/ChangeLog/ReleaseNote.txt b/drivers/net/wireless/bcmdhd_bcm43455/ChangeLog/ReleaseNote.txt new file mode 100644 index 000000000000..ca34a2729aa1 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/ChangeLog/ReleaseNote.txt @@ -0,0 +1,221 @@ +DHD 1.141.X Release for BCM4339, 4354, 43455 SDIO Projects. + +-------------------------------- +Change History +-------------------------------- +DHD 1.141.67.33 - 2018-03-09 + - CVE-2017-13292 A-70722061 Fix integer overflow in wl_get_assoc_ies + - CVE-2017-13303 A-71359108 Remove obsoleted wl_cfgvendor_priv_string_handler + +DHD 1.141.67.32 - 2017-12-14 + - Fixed buffer overrun issue in wl_parse_ssid_list_tlv() + - Fixed parsing issue on wl_parse_ssid_list_tlv() for PNO setup + - Fixed memory leak in PNO + - Fixed potential buffer overflow + - Fixed missed SSID/MAC filtering in log for security reason + +DHD 1.141.67.30 - 2017.8.31 + - Security fix + - CVE-2017-0786 A-37351060 Added boundary check in wl_escan_handler() + - CVE-2017-0787 A-37722970 Added boundary check in dhd_pno_process_epno_result() + - CVE-2017-0788 A-37722328 Added boundary check in dhd_handle_hotlist_scan_evt() + - CVE-2017-0789 A-37685267 Removed unused SWC feature + - CVE-2017-0790 A-37357704 Added boundary check in dhd_process_full_gscan_result() + - CVE-2017-0791 A-37306719 Added event length check in wl_notify_rx_mgmt_frame() + - CVE-2017-0792 A-37305578 Added event length check in dhd_rtt_event_handler() + - V2017070601 Added P2P IE length check in parsing routine + +DHD 1.141.67.29 - 2017.6.27 + - Security fix + - CVE-2017-0705 A-34973477 Added a boundary check in the handling of gscan attribute for significant change bssids + - CVE-2017-0706 A-35195787 Added a length check of tx mgmt frame + +DHD 1.141.67.28 - 2017.5.26 + - Security fix + - CVE-2017-0633 Enhanced buffer usage in IOCTL path + - CVE-2016-0802 Code enhancement for prevention of overflow + +DHD 1.141.67.27 - 2017.3.24 + - Google security fix + - Fix buffer overrun in wl_cfg80211_add_iw_ie, CVE-2017-0567, A-32125310. + - Fix buffer overrun in wl_run_escan, CVE-2017-0568, A-34197514. + - Fix buffer overrun in dhd_wlfc_reorderinfo_indicate, CVE-2017-0571, A-34203305. + - Fix buffer overrun in dhd_pno_process_anqpo_result, CVE-2017-0572, A-34198931. + - Prevent stack overflow related with AKM suite count, CVE-2017-0573, A-34469904. + +DHD 1.141.67.26 - 2017.2.24 + - Google security fix - Prevent buffer overflow of "default_chan_list" in wl_run_escan(). + - Google security fix - Check a "results->pkt_count" length not to exceed allocated memory length. + - Google security fix - Removing the unused WEXT file, A-32124445 + +DHD 1.141.67.25 - 2017.1.24 + - Google Security Patch - fix possible use-after-free case, A-32838767 + +DHD 1.141.67.24 - 2016.12.30 + - Fix for PMF AP Connectivity issue [CASE# 1097627] + - Fix for p2p disconnection when switching AP [CASE# 1095787] + - Google Security - Elevation of privilege vulnerability in Broadcom Wi-Fi driver + *A-32174590 + *A-32219255 + *A-32219453 + *A-29000183 + *A-32474971 + (A-24739315 / A-32219121 / A-31822524 is not needed for 43455) + +DHD 1.141.67.23 - 2016.09.09 + - Google security fix.(ANDROID-29009982) + +DHD 1.141.67.22 - 2016.07.08 + - Google security enhancement of previous vulnerability fix.(ANDROID-26492805) + +DHD 1.141.67.21 - 2016.05.20 + - Android security fixes.(ANDROID-26425765, ANDROID-26571522) + - Fix a buffer overwrite in dev_wlc_bufvar_set(). [CASE# 1021341] + - Changing copyright of driver files to open copyright. [CASE# 1044970] + +DHD 1.141.67.20 - 2016.03.21 + - Fix extra vulnerabilities reported by google. + +DHD 1.141.67.19 - 2016.02.22 + - Fix vulnerabilities reported by google - validate remaining space in WPS IE. + +DHD 1.141.67.18 - 2016.01.12 + - Avoiding corner case accessing suspended sd host unexpectedly. [CASE# 1003434] + - Fixing P2P group add issue in 5GHz. [CASE# 1005073] + - Ethernet type security vulnerability fix in DHD. + - Fixes potential buffer overflow when parsing WPS_ID_DEVICE_NAME and in sched scan result handler. + +DHD 1.141.67.17 - 2015.12.08 + - Fix host memory corruption problem related with linkstat. [CASE# 999609, 999642], Kitakami R2.1 43455, Loire 43455 + - Porting scan_abort feature from Kernel. [CASE# 998204], Loire 43455 + +DHD 1.141.67.16 - 2015.11.20 + - Enabled Gscan in the Makefile for Shinano R2.2 4354 + - Disable Lossless Roaming for FT over DS and FT over Air for Shinano R2 4339 + - Fix build failure with lower version of kernel + +DHD 1.141.67.15 - 2015.11.10 + - Additional Android M updates for Loire + - 11mc ftm + - ePNO + - RSSI Monitoring + - ANQP offload + +DHD 1.141.67.14 - 2015.11.04 + - Android M updates + - Add mkeep_alive feature + - 5GHz Softap + - Gscan Updates + - LinkStat DHD Updates + +DHD 1.141.67.13 - 2015.08.17 + - Not to forward BRCM event as a network pkt '0x886c' [CASE# 952625], Shinano 2.1, Kitakami R2,43455 + +DHD 1.141.67.12 - 2015.07.15 + - Add srl/lrl value setting in Softap, fix the issue not set properly. [CASE# 912911, 930776], Shinano 2.1, Kitakami R2,43455 + - Fix for P2P TA issue[ CASE#943732], Kitakami R2, 43455 + - Fix for linkstat buffer corruption causing android framework crash [CASE # 940151], Shinano R2.1(4354), Kitakami R2, 43455 + +DHD 1.141.67.11 - 2015.07.08 + - 4-way handshake delayed when roaming due to uplink traffic (Shinano 2.1 BCM4339 CASE#886484) + - Add bcn_to_dly iovar to control link_down event,(Kitakami R2 43455 CASE#912211) + - GSCAN fix only for Kitakami R2 43455 + +DHD 1.141.67.10 - 2015.05.29 + - Add DHD flag to disable 11N proprietary rates. (Kitakami R2 43455 CASE#927300) + - Disable TX Beamforming (tx only). (Kitakami R2 43455 CASE#925270) + +DHD 1.141.67.9 - 2015.04.30 + - TDLS mgmt build error fix CASE#844655 (CASE#911280) + +DHD 1.141.67.8 - 2015.04.14 + - Firmware not responding (when running batch scan while in dhcp negotiation (CASE#907419) + - Question regarding a huge kmalloc barely used (CASE#903335) + - Code questions (CASE#896789) + - WL_VENDOR_EXT_SUPPORT definition (CASE#901912) + - Release wake lock("wlan_wake") when terminating event thread + +DHD 1.141.67.7 - 2015.03.13 + - Use if_counters for connection statistics per interface when available, CSP:892522, Only available in Kitakami R2 43455. + - Fix for ARP stuck issue in multihoming CSP:895926 + +DHD 1.141.67.6 - 2015.02.03 + - Support for 43455. + - Support for 64 bits host system. + - Update some copyright notices. + - Fix for driver fails to load if previous instance of wpa_supplicant did not terminate properly. + - Reduce P2P connection time. + +DHD 1.141.67.5 - 2015.01.09 + - Fill the vht_cap field of ieee80211_supported_band(Wrong Max link rate for VHT), CSP #862670 + - Reset beacon found status whenever regulatory domain settings are changed, CSP #868771 + - Allow to scan for p2p on passive channel, CSP #868771 + - Fix trap in dhd_free(), CSP #874320 + - Creating P2P group in available bandwidths in passive channels on 5GHz region, CSP #830497 + +DHD 1.141.67.4 - 2014.12.5 + - Fix build errors caused by Android L updates + - Fix some warning and potential build error with Kernel 3.8 above. + +DHD 1.141.67.3 - 2014.11.20 (Google L support) + - Including android Google L adaptation code + (Gscan, Linkstat, Private PNO and RTT which can be selectable in Makefie) + - Makefile(Google Android L), Makefile.kk (for Kitkat) + - Enable Dongle memory dump feature. + - Increase max nvram buffer size. + +DHD 1.141.67.2 - 2014.09.05 + - Fix for WFA PMF_AP certification. CSP #824822 + - Netif packet counters are not updated in wlfc flow control + - Adding check routine , wakelock, during softap + - WiFi Direct Certification 5.1.20 change GAS frame handling + - hostapd ap_info null ptr check added + +DHD 1.141.67.1 - 2014.07.28 + - Update Ccode translate table for SOMC + - Don't use wlfc info exchange when a device is asleep on SDIO + - Increase MAX_CNTL_TX_TIMEOUT to 3 from 2 by specifying it in Makefile. CSP # 800769 + +DHD 1.141.67 - 2014.07.09 + - Keep connection while regulatory code change - CSP #803478 + - Including action code for tunneled prob req to set wfd ie. CSP # 809533 + - MAX_KSO_ATTEMPTS changed to 64, same as R1's + - Prevent running wl_event_handler while HANG is occurred + - Fix for hostapd buffer free + +DHD 1.141.65 - 2014.06.05 + - Fix mmc error at re-loading dhd driver CSP#779847 + - Add supports for tdls management frames CSP#778769 + - P2P fails after a driver stop / start in the kernel 3.10 + - Increase assoc_retry_max from 3 to 7 to increase a connection rate in very noisy environmnet. + - Added definition SUPPORT_P2P_GO_PS in checking bus_sleep code + - Fix multi-AC detection logic to look at rx packets as well as tx packets + +DHD 1.141.60 - 2014.05.16 + - CSP 791385, tdls auto enable delete in Makefile + - CSP 796606, SOFTAP WPS tethering issue fixed + - CSP:779847 Fix mmc error at re-loading dhd driver + - CSP:793836 Fix for coverity issue + - CSP:770822 Add driver private command to recover link quality + - CSP: 790918 bcn_timeout value change to 8 when VSDB or roaming are enabled + - Deleting set IRQF_TRIGGER_MASK for preventing clear setting of board configuration + - Use CONFIG_COMAT method to make 32-bit ioctl working with 64-bit kernel + - Protect the cfg->ioctl_buf against the wl_set_tx_power/wl_get_tx_power function + - Add check bus sleep check code in dhdsdio_suspend + - Fixed getting chanspec value when handling DFS channels + - Add KSO_ENAB check code in dhd_bcmsdh_send_buf function + - Dynamic change thread priority, policy by use sysfs. value path is /sys/class/net/wlan0/dpc_prio + - Packet was freed before both proptxstatus and txcomplete finished + - Fix chanspec mismatch + - Fix multicast recive in P2P mode + - Kernel 3.14 support + - Remove the duplicated kfree of ndev->ieee80211_ptr pointer in wl_dealloc_netinfo + - Prevent the RTNL assertion when calling the cfg80211_unregister_wdev function while dhd_module_cleanup + - Remove the kernel version dependency in case of using wl_cfg80211_remove_if in wl_cfg80211_handle_ifdel function. + - Country/Revision is not initialized after Wi-Fi off->on + - Fix the incorrect channel extraction from chanspec when 0 is given as a control channel while scanning + - Supporting WNM Notification for HS20 REL2 + - Applying Interaction with MFP by Spec HS2.0 REL2 + +2014.03.19 - DHD 1.141.48 + - Initial Release for Shinano R2, BCM4339 & BCM4354 -- GitLab From beb6b46afc604195c94be04f7a869712e6c060bf Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Tue, 29 May 2018 21:52:53 +0300 Subject: [PATCH 225/528] drivers: wireless: bcm43455: Update to 1.141.67.33 * Sony package version: 34.4.A.2.70 (Xperia X) - Security fix: - CVE-2017-13292 A-70722061 Fix integer overflow in wl_get_assoc_ies - CVE-2017-13303 A-71359108 Remove obsoleted wl_cfgvendor_priv_string_handler Signed-off-by: Andrey Cherepkov (cherry picked from commit 6af9885c81bb764862192696ffefc11ad23c8717) --- .../net/wireless/bcmdhd_bcm43455/aiutils.c | 2 +- .../net/wireless/bcmdhd_bcm43455/bcmevent.c | 2 +- drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c | 2 +- .../wireless/bcmdhd_bcm43455/bcmsdh_linux.c | 2 +- .../wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c | 2 +- .../bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c | 2 +- .../wireless/bcmdhd_bcm43455/bcmsdspi_linux.c | 2 +- .../net/wireless/bcmdhd_bcm43455/bcmspibrcm.c | 2 +- .../net/wireless/bcmdhd_bcm43455/bcmutils.c | 2 +- .../bcmdhd_bcm43455/bcmwifi_channels.c | 2 +- .../bcmdhd_bcm43455/bcmwifi_channels.h | 2 +- .../wireless/bcmdhd_bcm43455/bcmwifi_rates.h | 2 +- .../net/wireless/bcmdhd_bcm43455/bcmxtlv.c | 2 +- drivers/net/wireless/bcmdhd_bcm43455/dhd.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_bta.c | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_bta.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_bus.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_cdc.c | 2 +- .../wireless/bcmdhd_bcm43455/dhd_cfg80211.c | 2 +- .../wireless/bcmdhd_bcm43455/dhd_cfg80211.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_common.c | 2 +- .../bcmdhd_bcm43455/dhd_custom_gpio.c | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_dbg.h | 2 +- drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c | 2 +- drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_linux.c | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_linux.h | 2 +- .../bcmdhd_bcm43455/dhd_linux_platdev.c | 2 +- .../bcmdhd_bcm43455/dhd_linux_sched.c | 2 +- .../wireless/bcmdhd_bcm43455/dhd_linux_wq.c | 2 +- .../wireless/bcmdhd_bcm43455/dhd_linux_wq.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_pno.c | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_pno.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_proto.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_sdio.c | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_wlfc.c | 2 +- .../net/wireless/bcmdhd_bcm43455/dhd_wlfc.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dngl_stats.h | 2 +- .../net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h | 2 +- drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c | 2 +- .../wireless/bcmdhd_bcm43455/include/Makefile | 2 +- .../wireless/bcmdhd_bcm43455/include/aidmp.h | 2 +- .../bcmdhd_bcm43455/include/bcm_cfg.h | 2 +- .../bcmdhd_bcm43455/include/bcm_mpool_pub.h | 2 +- .../wireless/bcmdhd_bcm43455/include/bcmcdc.h | 2 +- .../bcmdhd_bcm43455/include/bcmdefs.h | 2 +- .../bcmdhd_bcm43455/include/bcmdevs.h | 2 +- .../bcmdhd_bcm43455/include/bcmendian.h | 2 +- .../bcmdhd_bcm43455/include/bcmnvram.h | 2 +- .../bcmdhd_bcm43455/include/bcmpcispi.h | 2 +- .../bcmdhd_bcm43455/include/bcmperf.h | 2 +- .../bcmdhd_bcm43455/include/bcmsdbus.h | 2 +- .../wireless/bcmdhd_bcm43455/include/bcmsdh.h | 2 +- .../bcmdhd_bcm43455/include/bcmsdh_sdmmc.h | 2 +- .../bcmdhd_bcm43455/include/bcmsdpcm.h | 2 +- .../bcmdhd_bcm43455/include/bcmsdspi.h | 2 +- .../bcmdhd_bcm43455/include/bcmsdstd.h | 2 +- .../wireless/bcmdhd_bcm43455/include/bcmspi.h | 2 +- .../bcmdhd_bcm43455/include/bcmspibrcm.h | 2 +- .../bcmdhd_bcm43455/include/bcmsrom_fmt.h | 2 +- .../bcmdhd_bcm43455/include/bcmsrom_tbl.h | 2 +- .../bcmdhd_bcm43455/include/bcmutils.h | 2 +- .../bcmdhd_bcm43455/include/brcm_nl80211.h | 2 +- .../wireless/bcmdhd_bcm43455/include/dbus.h | 2 +- .../include/devctrl_if/wlioctl_defs.h | 2 +- .../bcmdhd_bcm43455/include/dhdioctl.h | 2 +- .../bcmdhd_bcm43455/include/epivers.h | 10 +-- .../wireless/bcmdhd_bcm43455/include/hndpmu.h | 2 +- .../bcmdhd_bcm43455/include/hndrte_armtrap.h | 2 +- .../bcmdhd_bcm43455/include/hndrte_cons.h | 2 +- .../wireless/bcmdhd_bcm43455/include/hndsoc.h | 2 +- .../bcmdhd_bcm43455/include/linux_osl.h | 2 +- .../bcmdhd_bcm43455/include/linuxver.h | 2 +- .../bcmdhd_bcm43455/include/miniopt.h | 2 +- .../bcmdhd_bcm43455/include/msgtrace.h | 2 +- .../wireless/bcmdhd_bcm43455/include/osl.h | 2 +- .../include/packed_section_end.h | 2 +- .../include/packed_section_start.h | 2 +- .../wireless/bcmdhd_bcm43455/include/pcicfg.h | 2 +- .../bcmdhd_bcm43455/include/proto/802.11.h | 2 +- .../include/proto/802.11_bta.h | 2 +- .../bcmdhd_bcm43455/include/proto/802.11e.h | 2 +- .../bcmdhd_bcm43455/include/proto/802.1d.h | 2 +- .../bcmdhd_bcm43455/include/proto/802.3.h | 2 +- .../bcmdhd_bcm43455/include/proto/bcmeth.h | 2 +- .../bcmdhd_bcm43455/include/proto/bcmevent.h | 2 +- .../bcmdhd_bcm43455/include/proto/bcmip.h | 2 +- .../bcmdhd_bcm43455/include/proto/bcmipv6.h | 2 +- .../bcmdhd_bcm43455/include/proto/bcmtcp.h | 2 +- .../include/proto/bt_amp_hci.h | 2 +- .../bcmdhd_bcm43455/include/proto/dnglevent.h | 2 +- .../bcmdhd_bcm43455/include/proto/eapol.h | 2 +- .../bcmdhd_bcm43455/include/proto/ethernet.h | 2 +- .../bcmdhd_bcm43455/include/proto/nan.h | 2 +- .../bcmdhd_bcm43455/include/proto/p2p.h | 2 +- .../bcmdhd_bcm43455/include/proto/sdspi.h | 2 +- .../bcmdhd_bcm43455/include/proto/vlan.h | 2 +- .../bcmdhd_bcm43455/include/proto/wpa.h | 2 +- .../bcmdhd_bcm43455/include/proto/wps.h | 2 +- .../bcmdhd_bcm43455/include/sbchipc.h | 2 +- .../bcmdhd_bcm43455/include/sbconfig.h | 2 +- .../bcmdhd_bcm43455/include/sbhnddma.h | 2 +- .../bcmdhd_bcm43455/include/sbpcmcia.h | 2 +- .../wireless/bcmdhd_bcm43455/include/sbsdio.h | 2 +- .../bcmdhd_bcm43455/include/sbsdpcmdev.h | 2 +- .../bcmdhd_bcm43455/include/sbsocram.h | 2 +- .../wireless/bcmdhd_bcm43455/include/sdio.h | 2 +- .../wireless/bcmdhd_bcm43455/include/sdioh.h | 2 +- .../bcmdhd_bcm43455/include/sdiovar.h | 2 +- .../bcmdhd_bcm43455/include/siutils.h | 2 +- .../wireless/bcmdhd_bcm43455/include/spid.h | 2 +- .../wireless/bcmdhd_bcm43455/include/trxhdr.h | 2 +- .../bcmdhd_bcm43455/include/typedefs.h | 2 +- .../bcmdhd_bcm43455/include/wlfc_proto.h | 2 +- .../bcmdhd_bcm43455/include/wlioctl.h | 2 +- .../net/wireless/bcmdhd_bcm43455/linux_osl.c | 2 +- .../net/wireless/bcmdhd_bcm43455/sbutils.c | 2 +- .../net/wireless/bcmdhd_bcm43455/siutils.c | 2 +- .../wireless/bcmdhd_bcm43455/siutils_priv.h | 2 +- .../net/wireless/bcmdhd_bcm43455/uamp_api.h | 2 +- .../net/wireless/bcmdhd_bcm43455/wl_android.c | 2 +- .../net/wireless/bcmdhd_bcm43455/wl_android.h | 2 +- .../wireless/bcmdhd_bcm43455/wl_cfg80211.c | 64 +++++++++++-------- .../wireless/bcmdhd_bcm43455/wl_cfg80211.h | 10 +-- .../wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c | 2 +- .../net/wireless/bcmdhd_bcm43455/wl_cfgnan.c | 2 +- .../net/wireless/bcmdhd_bcm43455/wl_cfgnan.h | 2 +- .../net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c | 2 +- .../net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h | 2 +- .../wireless/bcmdhd_bcm43455/wl_cfgvendor.c | 40 +----------- .../wireless/bcmdhd_bcm43455/wl_cfgvendor.h | 5 +- drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h | 2 +- .../wireless/bcmdhd_bcm43455/wl_linux_mon.c | 2 +- .../net/wireless/bcmdhd_bcm43455/wl_roam.c | 2 +- .../wireless/bcmdhd_bcm43455/wldev_common.c | 2 +- .../wireless/bcmdhd_bcm43455/wldev_common.h | 2 +- 136 files changed, 180 insertions(+), 211 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/aiutils.c b/drivers/net/wireless/bcmdhd_bcm43455/aiutils.c index 54a0376747c5..e1f833ad28be 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/aiutils.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/aiutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c index 1447d2baa983..3f9f8390424a 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c @@ -1,7 +1,7 @@ /* * bcmevent read-only data shared by kernel or app layers * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c index 98e561b6c3b3..ea4edda2c8b3 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c @@ -2,7 +2,7 @@ * BCMSDH interface glue * implement bcmsdh API for SDIOH driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c index e57a2cfa1869..5cab16b98d93 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c @@ -1,7 +1,7 @@ /* * SDIO access interface for drivers - linux specific (pci only) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c index b2a8e8087d8d..87aaeee7c10f 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c index 17c42b4f7ac4..27a48afb523b 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c index 5f152518cd8e..689115a51b6f 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c @@ -1,7 +1,7 @@ /* * Broadcom SPI Host Controller Driver - Linux Per-port * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c index 19cd1828eaf5..da16dccf71aa 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c @@ -1,7 +1,7 @@ /* * Broadcom BCMSDH to gSPI Protocol Conversion Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c index 6b1a5f7c0d42..0f1631300f95 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c index 4cc23b825abf..33ec4f8db860 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c @@ -3,7 +3,7 @@ * Contents are wifi-specific, used by any kernel or app-level * software that might want wifi things as it grows. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h index 9defecab9993..82d59f47ba51 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h @@ -3,7 +3,7 @@ * This header file housing the define and function prototype use by * both the wl driver, tools & Apps. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h index 9a29f929361c..40852cb02b29 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h @@ -1,7 +1,7 @@ /* * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c index 3f8e67cd5cf6..2312c94c4187 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd.h index 454f6f58c0b2..8156ad66c11c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2013 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c index 62b78e61d309..e2a891c1e2f8 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c @@ -1,7 +1,7 @@ /* * BT-AMP support routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h index 0c5e9de534e9..000d4eee6a51 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h @@ -1,7 +1,7 @@ /* * BT-AMP support routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h index 14515e12b1e7..0887b0ee9bdf 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c index 00d4821d7e5e..153cffbce0b7 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c @@ -1,7 +1,7 @@ /* * DHD Protocol Module for CDC and BDC. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c index ed3a7690b342..bac72e4d560f 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h index a160571ad8c9..fbc10f211adc 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c index 7b996e6a9b45..0398aba3ebdb 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), common DHD core. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c index 1116cee10913..dcb4e1771d93 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c @@ -1,6 +1,6 @@ /* * Customer code to add GPIO control during WLAN start/stop -* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2013 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h index 796d5598acd1..8216dba67297 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h @@ -1,7 +1,7 @@ /* * Debug/trace/assert driver definitions for Dongle Host Driver. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c index b7760c5cd1bb..06167ab86cf8 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c @@ -1,7 +1,7 @@ /* * IP Packet Parser Module. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h index 08765033c0be..62ce6b5700ff 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h @@ -3,7 +3,7 @@ * * Provides type definitions and function prototypes used to parse ip packet. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c index 2e6676346388..ac136f6867f6 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface * Basically selected code segments from usb-cdc.c and usb-rndis.c * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2014 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h index 5129d8d1225b..e97929afe083 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h @@ -1,7 +1,7 @@ /* * DHD Linux header file (dhd_linux exports for cfg80211 and other components) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c index 447578a0439c..3dca697c1f17 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c @@ -1,7 +1,7 @@ /* * Linux platform device for DHD WLAN adapter * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2013 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c index 4b62ee40c2f1..a24b32124fba 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c @@ -1,7 +1,7 @@ /* * Expose some of the kernel scheduler routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c index ea4d567b1941..bd0b7afad022 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Generic work queue framework * Generic interface to handle dhd deferred work events * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h index 1066250b2824..66f237fb7002 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Generic work queue framework * Generic interface to handle dhd deferred work events * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c index 0c74d7021218..ea97317f040c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD) * Prefered Network Offload and Wi-Fi Location Service(WLS) code. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h index 361c5cecd34d..62425da6c1e6 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h @@ -1,7 +1,7 @@ /* * Header file of Broadcom Dongle Host Driver (DHD) * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h index 6b95755938bb..61b95d13a747 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c index 44ec2b607ab8..f04512680089 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c @@ -1,7 +1,7 @@ /* * DHD Bus Module for SDIO * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2014 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c index 52700ac94ff9..1152ce9dfd23 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c @@ -1,7 +1,7 @@ /* * DHD PROP_TXSTATUS Module. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h index ee5d00489bd5..347c1bcbea46 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h b/drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h index 73024f1e4274..cd499133dcc7 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h @@ -2,7 +2,7 @@ * Common stats definitions for clients of dongle * ports * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h index f5f5148cd5b3..74047430fff4 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h @@ -1,7 +1,7 @@ /* * Dongle WL Header definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c b/drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c index 31fcf91f0223..cfbbea8a854c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing PMU corerev specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/Makefile b/drivers/net/wireless/bcmdhd_bcm43455/include/Makefile index 797ee2563e33..3b8291471203 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/Makefile +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/Makefile @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (C) 1999-2017, Broadcom Corporation +# Copyright (C) 1999-2018, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h b/drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h index 831865dd8817..cc4fe830c965 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h @@ -1,7 +1,7 @@ /* * Broadcom AMBA Interconnect definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h index 7c6e70f449ef..fe1622268957 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h @@ -1,7 +1,7 @@ /* * BCM common config options * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h index b05ba3704aeb..bbb4e6699b73 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h @@ -35,7 +35,7 @@ * and instrumentation on top of the heap, without modifying the heap * allocation implementation. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h index c93b6f619b20..3759e362f1be 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h index 15c00f718a31..d7a14c094aa5 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h @@ -1,7 +1,7 @@ /* * Misc system wide definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h index ebc57c71d56f..d950bc71355e 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h @@ -1,7 +1,7 @@ /* * Broadcom device-specific manifest constants. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h index 970989e38f6b..3e783eae32be 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h @@ -1,7 +1,7 @@ /* * Byte order utilities * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h index 3fbc303bd528..e4b785c84f4c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h @@ -1,7 +1,7 @@ /* * NVRAM variable manipulation * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h index d4781abb982a..49790c24ae22 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h @@ -1,7 +1,7 @@ /* * Broadcom PCI-SPI Host Controller Register Definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h index 84c232f8a059..9cc62882fe40 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h @@ -1,7 +1,7 @@ /* * Performance counters software interface. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h index 4d4634ba6585..267c974cb33d 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h @@ -2,7 +2,7 @@ * Definitions for API from sdio common code (bcmsdh) to individual * host controller drivers. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h index 099120a34d60..9946acfb7ea2 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h @@ -3,7 +3,7 @@ * export functions to client drivers * abstract OS and BUS specific details of SDIO * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h index 5ad8ae077270..c98171fd3015 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h index 2bfac6693ec4..9c9c32e1ed24 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h @@ -2,7 +2,7 @@ * Broadcom SDIO/PCMCIA * Software-specific definitions shared between device and host side * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h index 1fc1fd4eef6b..559a7c2bb630 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h index 9edb37286712..318a6a8fc85d 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h index 193dc8e0c9ca..0b4d7bdb6d6d 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h @@ -1,7 +1,7 @@ /* * Broadcom SPI Low-Level Hardware Driver API * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h index c81e6049ae03..833fd261705d 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h index 1baebcdf90bb..3e485d519581 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h @@ -1,7 +1,7 @@ /* * SROM format definition. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h index c8335b56eb5f..be43a7c5ef18 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h @@ -1,7 +1,7 @@ /* * Table that encodes the srom formats for PCI/PCIe NICs. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h index 1743d1f8e927..1103739f30f2 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h @@ -1,7 +1,7 @@ /* * Misc useful os-independent macros and functions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h index edb22d53ea84..f17c05d52521 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h @@ -1,7 +1,7 @@ /* * Definitions for nl80211 testmode access to host driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h b/drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h index fe898da34ac9..80ef80bd97e9 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h @@ -2,7 +2,7 @@ * Dongle BUS interface Abstraction layer * target serial buses like USB, SDIO, SPI, etc. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h index 7d7f8c86e99c..6001a497ce81 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h index 2adfaf89bf1b..cffb2f3b1de4 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h @@ -5,7 +5,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h index caa82f18aed9..d60c79139364 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -32,17 +32,17 @@ #define EPI_RC_NUMBER 67 -#define EPI_INCREMENTAL_NUMBER 32 +#define EPI_INCREMENTAL_NUMBER 33 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 141, 67, 32 +#define EPI_VERSION 1, 141, 67, 33 -#define EPI_VERSION_NUM 0x018d4320 +#define EPI_VERSION_NUM 0x018d4321 #define EPI_VERSION_DEV 1.141.67 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.141.67.32 (r)" +#define EPI_VERSION_STR "1.141.67.33 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h index 9e236d789f01..a22f39bbf831 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h @@ -1,7 +1,7 @@ /* * HND SiliconBackplane PMU support. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h index eee716db5fcf..5c305023d629 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h @@ -1,7 +1,7 @@ /* * HNDRTE arm trap handling. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h index 7dcde5ff37cd..40731bf78102 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h @@ -1,7 +1,7 @@ /* * Console support for hndrte. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h index 1dbe9c19e0ab..948f9af92149 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h @@ -1,7 +1,7 @@ /* * Broadcom HND chip & on-chip-interconnect-related definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h index 9b844be2c953..228e231a9955 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h b/drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h index f6e08bc85f14..363fb5caa7f5 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h @@ -2,7 +2,7 @@ * Linux-specific abstractions to gain some independence from linux kernel versions. * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h b/drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h index ab6668097ec0..722e5737564a 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h @@ -1,7 +1,7 @@ /* * Command line options parser. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h b/drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h index 6119bbba09a8..4105585989a4 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h @@ -1,7 +1,7 @@ /* * Trace messages sent over HBUS * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/osl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/osl.h index 9a1f8a5960b0..7a101e506e88 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/osl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/osl.h @@ -1,7 +1,7 @@ /* * OS Abstraction Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h index 27e39b53e9eb..cad72104470b 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h @@ -15,7 +15,7 @@ * #include * * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h index 61c14a69401e..18f48270fa8c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h @@ -15,7 +15,7 @@ * #include * * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h b/drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h index 99ebf063f345..13774d0e510c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h @@ -1,7 +1,7 @@ /* * pcicfg.h: PCI configuration constants and structures. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h index e18cc6ef19d0..a501d8206f87 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h index 9de5616ab024..7b9baf3c6550 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h @@ -1,7 +1,7 @@ /* * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h index ded6b7612415..879fa84f3168 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h @@ -1,7 +1,7 @@ /* * 802.11e protocol header file * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h index efb390bfc09e..ceddd5c767d0 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h index dc1626aa667a..e7728e307f0b 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h index 4947e533cb8a..8611c682791c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h @@ -1,7 +1,7 @@ /* * Broadcom Ethernettype protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h index 352916ba33a8..006213bfff73 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h @@ -1,7 +1,7 @@ /* * Broadcom Event protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h index f5ee807c1c96..a95a6131324e 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h index 86226102e455..42068ef5ebc9 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h index 850c5b4e8f2f..2be771af44e7 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to TCP Protocol * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h index f1ea2909971c..096794592a8e 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h @@ -1,7 +1,7 @@ /* * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h index 549566e58950..d6a84f24fbc2 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h @@ -1,7 +1,7 @@ /* * Broadcom Event protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h index ed3310cd37f9..7b012eecb110 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h @@ -5,7 +5,7 @@ * IEEE Std 802.1X-2001 * IEEE 802.1X RADIUS Usage Guidelines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h index 68eb83f5330b..3542492743ec 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h @@ -1,7 +1,7 @@ /* * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h index f7179b6a3cd4..0c2d922a6d77 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h index 41c037274901..0ae7ef47e7bf 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h index 35e8180d67dd..98af94328abf 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Standard * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h index fc6e13b6cd48..643a73a76a4b 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h @@ -1,7 +1,7 @@ /* * 802.1Q VLAN protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h index 1a3ae0e8a6e1..147016f3730f 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to WPA * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h index e3d653ababe8..aa3d19a38236 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h @@ -1,7 +1,7 @@ /* * WPS IE definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h index 00512bd0aa3a..51a07435bd51 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h @@ -7,7 +7,7 @@ * * $Id: sbchipc.h 527121 2015-01-16 03:22:32Z $ * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h index 8de9b0942577..569b0c9b731e 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h @@ -1,7 +1,7 @@ /* * Broadcom SiliconBackplane hardware register definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h index afe82680838f..43ec49c47a39 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h @@ -2,7 +2,7 @@ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface * This supports the following chips: BCM42xx, 44xx, 47xx . * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h index 20bb1748273b..27d2f83f7c0a 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h @@ -1,7 +1,7 @@ /* * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h index 56e5f14fe34f..cca84bc18f28 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h @@ -4,7 +4,7 @@ * * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h index f24d0a3c4e76..958436e3c45e 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h @@ -2,7 +2,7 @@ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific * device core support * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h index 1f4ab45b2e1c..f9bfa969dc1b 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h @@ -1,7 +1,7 @@ /* * BCM47XX Sonics SiliconBackplane embedded ram core * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h index 8b85c3593c82..4b9573953bdf 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h @@ -2,7 +2,7 @@ * SDIO spec header file * Protocol and standard (common) device definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h index 62a5c4cc3179..754e01f6d6db 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h @@ -2,7 +2,7 @@ * SDIO Host Controller Spec header file * Register map and definitions for the Standard Host Controller * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h index 326b32d8dfb0..734a17d6a34c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h @@ -2,7 +2,7 @@ * Structure used by apps whose drivers access SDIO drivers. * Pulled out separately so dhdu and wlu can both use it. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h b/drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h index 19a18ee50a99..5ea12f196284 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h @@ -2,7 +2,7 @@ * Misc utility routines for accessing the SOC Interconnects * of Broadcom HNBU chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/spid.h b/drivers/net/wireless/bcmdhd_bcm43455/include/spid.h index b5d7b675748d..87d8291c1987 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/spid.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/spid.h @@ -1,7 +1,7 @@ /* * SPI device spec header file * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h b/drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h index 5ea40e739e31..3cd08f8e1686 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h @@ -1,7 +1,7 @@ /* * TRX image file header format. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h index 0222b8824c5f..236b22862049 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h index 90624b6a5b48..4355e72a3e29 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h index cec5d1eb5672..226d38a2bcd8 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c b/drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c index 0bd42de1f62b..03d490dc8da2 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/sbutils.c b/drivers/net/wireless/bcmdhd_bcm43455/sbutils.c index c0364f608466..a625d65993d3 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/sbutils.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/sbutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/siutils.c b/drivers/net/wireless/bcmdhd_bcm43455/siutils.c index 64c2ba14b607..bf91a266e74b 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/siutils.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/siutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h b/drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h index e553ce355404..1712409c7d70 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h @@ -1,7 +1,7 @@ /* * Include file private to the SOC Interconnect support files. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h b/drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h index 93d1d2eb208b..01935148ee9b 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h @@ -3,7 +3,7 @@ * * Description: Universal AMP API * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c index a7ac9103077a..8c62fe4545b6 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2015 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.h index fb3cba9cf17b..1045e6ea2e32 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_android.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index dd5fb0275d80..cff5b0b42ac4 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2015 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 718508 2017-08-31 02:48:38Z $ + * $Id: wl_cfg80211.c 751081 2018-03-09 08:06:41Z $ */ /* */ #include @@ -8526,6 +8526,27 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.req_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.req_len > 0) && + (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0)))) { + err = BCME_BADLEN; + goto exit; + } + if (assoc_info.resp_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.resp_len > 0) && (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -8536,45 +8557,34 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) } if (assoc_info.req_len) { err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + assoc_info.req_len, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - return err; + goto exit; } conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - if (conn_info->req_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->req_ie_len, MAX_REQ_LINE)); - return err; - } - } else { - conn_info->req_ie_len = 0; + memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); } if (assoc_info.resp_len) { err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + assoc_info.resp_len, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - return err; - } - conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); - if (conn_info->resp_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->resp_ie_len, MAX_REQ_LINE)); - return err; + goto exit; } - } else { - conn_info->resp_ie_len = 0; + conn_info->resp_ie_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); + } + +exit: + if (err) { + WL_ERR(("err:%d, assoc_info-req:%u,resp:%u conn_info-req:%u,resp:%u\n", + err, assoc_info.req_len, assoc_info.resp_len, + conn_info->req_ie_len, conn_info->resp_ie_len)); } - WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, - conn_info->resp_ie_len)); return err; } diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h index 069eda344e49..08a8c258e0f1 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.h 596861 2015-11-03 08:54:58Z $ + * $Id: wl_cfg80211.h 751081 2018-03-09 08:06:41Z $ */ #ifndef _wl_cfg80211_h_ @@ -364,12 +364,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024 +#define MAX_REQ_LINE 1024u struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - s32 req_ie_len; + u32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - s32 resp_ie_len; + u32 resp_ie_len; }; /* firmware /nvram downloading controller */ diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c index 9ed1748463ab..eb02ffaf2b1c 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c index 723211896d50..974548ae33c3 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c @@ -3,7 +3,7 @@ * * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h index 44484eba1d68..bec3b72be0b0 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h @@ -3,7 +3,7 @@ * * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c index f7b8c2b99ee5..d6c063f22656 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c @@ -1,7 +1,7 @@ /* * Linux cfgp2p driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h index cca3f7b339cb..40fa2a169708 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h @@ -1,7 +1,7 @@ /* * Linux cfgp2p driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c index 8449e39c276d..114c68d26db7 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 Vendor Extension Code * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -1908,36 +1908,6 @@ static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_de } #endif /* defined(KEEP_ALIVE) */ -static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int err = 0; - int data_len = 0; - - WL_INFO(("%s: Enter \n", __func__)); - - if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) { - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - data_len = strlen(cfg->ioctl_buf); - cfg->ioctl_buf[data_len] = '\0'; - } - - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - cfg->ioctl_buf, data_len+1); - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - else - WL_INFO(("Vendor Command reply sent successfully!\n")); - - return err; -} - #ifdef LINKSTAT_SUPPORT #define NUM_RATE 32 #define NUM_PEER 1 @@ -2130,14 +2100,6 @@ static int wl_cfgvendor_set_country(struct wiphy *wiphy, } static const struct wiphy_vendor_command wl_vendor_cmds [] = { - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_PRIV_STR - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_priv_string_handler - }, #ifdef GSCAN_SUPPORT { { diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h index a352a9b1415d..2212ec3beae9 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 Vendor Extension Code * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -341,9 +341,6 @@ enum mkeep_alive_attributes { MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC }; -/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */ -#define BRCM_VENDOR_SCMD_CAPA "cap" - #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) extern int wl_cfgvendor_attach(struct wiphy *wiphy); extern int wl_cfgvendor_detach(struct wiphy *wiphy); diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h index 02d653e4e1d6..e41c479a0835 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h @@ -2,7 +2,7 @@ * Minimal debug/trace/assert driver definitions for * Broadcom 802.11 Networking Adapter. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c index a15c132b7dff..271dfc250a03 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), Linux monitor network interface * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c index 957640888266..50180753ad77 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c @@ -1,7 +1,7 @@ /* * Linux roam cache * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c index f57cce3c7c79..decaf3560d42 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c @@ -1,7 +1,7 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h index d1746dd0d9cc..07f3d56b4cb2 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h @@ -1,7 +1,7 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you -- GitLab From a4775329836cd4bf89725e441ef1fbf16d8d4d10 Mon Sep 17 00:00:00 2001 From: Lior David Date: Mon, 16 Oct 2017 20:39:31 +0300 Subject: [PATCH 226/528] wil6210: fix length check in __wmi_send The current length check: sizeof(cmd) + len > r->entry_size will allow very large values of len (> U16_MAX - sizeof(cmd)) and can cause a buffer overflow. Fix the check to cover this case. In addition, ensure the mailbox entry_size is not too small, since this can also bypass the above check. Change-Id: Iecb4f53ef05da0e015bc954b57b0e40debb7c8b7 Signed-off-by: Lior David (cherry picked from commit 9379bc70c7fa53a535dcdbb85425c58098ec7b6b) --- drivers/net/wireless/ath/wil6210/interrupt.c | 22 +++++++++++++++++++- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 28ffc18466c4..1b096c5464c2 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -342,6 +342,25 @@ static void wil_cache_mbox_regs(struct wil6210_priv *wil) wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); } +static bool wil_validate_mbox_regs(struct wil6210_priv *wil) +{ + size_t min_size = sizeof(struct wil6210_mbox_hdr) + + sizeof(struct wil6210_mbox_hdr_wmi); + + if (wil->mbox_ctl.rx.entry_size < min_size) { + wil_err(wil, "rx mbox entry too small (%d)\n", + wil->mbox_ctl.rx.entry_size); + return false; + } + if (wil->mbox_ctl.tx.entry_size < min_size) { + wil_err(wil, "tx mbox entry too small (%d)\n", + wil->mbox_ctl.tx.entry_size); + return false; + } + + return true; +} + static irqreturn_t wil6210_irq_misc(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -372,7 +391,8 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) if (isr & ISR_MISC_FW_READY) { wil_dbg_irq(wil, "IRQ: FW ready\n"); wil_cache_mbox_regs(wil); - set_bit(wil_status_reset_done, wil->status); + if (wil_validate_mbox_regs(wil)) + set_bit(wil_status_reset_done, wil->status); /** * Actual FW ready indicated by the * WMI_FW_READY_EVENTID diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c6574f22a3cf..7cfe6bb6c9d3 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -203,7 +203,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) void __iomem *head = wmi_addr(wil, r->head); uint retry; - if (sizeof(cmd) + len > r->entry_size) { + if (len > r->entry_size - sizeof(cmd)) { wil_err(wil, "WMI size too large: %d bytes, max is %d\n", (int)(sizeof(cmd) + len), r->entry_size); return -ERANGE; -- GitLab From 0bb045faef3d1729e69959d36060fa0b599f8b09 Mon Sep 17 00:00:00 2001 From: Lior David Date: Tue, 17 Oct 2017 14:18:17 +0300 Subject: [PATCH 227/528] wil6210: missing length check in wmi_set_ie Add a length check in wmi_set_ie to detect unsigned integer overflow. Change-Id: Id1ec6a6218f3fe6e00cc3f9a8e674f8f843273f2 Signed-off-by: Lior David (cherry picked from commit 60377538b1ff636d5a37b5ad5e7b78e215dd379a) --- drivers/net/wireless/ath/wil6210/wmi.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 7cfe6bb6c9d3..df9017c5c390 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1030,10 +1030,18 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) { int rc; u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; - struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); + struct wmi_set_appie_cmd *cmd; - if (!cmd) - return -ENOMEM; + if (len < ie_len) { + rc = -EINVAL; + goto out; + } + + cmd = kzalloc(len, GFP_KERNEL); + if (!cmd) { + rc = -ENOMEM; + goto out; + } if (!ie) ie_len = 0; @@ -1044,6 +1052,7 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len); kfree(cmd); +out: return rc; } -- GitLab From da194f8fbba5792f2ed9e2f7d0cc89c91a125573 Mon Sep 17 00:00:00 2001 From: Lior David Date: Tue, 17 Oct 2017 15:44:26 +0300 Subject: [PATCH 228/528] wil6210: missing length check in wil_cfg80211_mgmt_tx Add a length check in wil_cfg80211_mgmt_tx to detect unsigned integer overflow. Change-Id: I37f988481433a2e1238831980715aef32aa89a85 Signed-off-by: Lior David (cherry picked from commit efd25bb7f1a713446d5caade1470a311a5fa5221) --- drivers/net/wireless/ath/wil6210/cfg80211.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 390d088ebdae..739a262e3ebf 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -517,6 +517,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { + size_t total; struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; bool tx_status = false; @@ -530,7 +531,11 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, if (len < sizeof(struct ieee80211_mgmt)) return -EINVAL; - cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); + total = sizeof(*cmd) + len; + if (total < len) + return -EINVAL; + + cmd = kmalloc(total, GFP_KERNEL); if (!cmd) { rc = -ENOMEM; goto out; @@ -540,7 +545,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, cmd->len = cpu_to_le16(len); memcpy(cmd->payload, buf, len); - rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, + rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, total, WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); if (rc == 0) tx_status = !evt.evt.status; -- GitLab From c8c2a59be9f0aae3ec3b8d221423111f72c71ef2 Mon Sep 17 00:00:00 2001 From: Hardik Kantilal Patel Date: Wed, 18 Feb 2015 05:07:08 -0800 Subject: [PATCH 229/528] wcnss: Add support to read the Battery voltage Get Battery voltage from vadc at boot time. If Battery voltage is less then 3.5V then configure VDD_PA with 3.0V instead of 3.3V. Send indication of current battery voltage to WCNSS FW. Change-Id: I5470f218c8e136ed12d9aa0b9892a9b53ea6d9f4 CRs-Fixed: 794209 Signed-off-by: Hardik Kantilal Patel (cherry picked from commit 4f5ba367c0cb28ab296cfd4f4a6f2d1c4f791657) --- .../devicetree/bindings/wcnss/wcnss-wlan.txt | 1 + drivers/net/wireless/wcnss/wcnss_vreg.c | 38 +++++++++- drivers/net/wireless/wcnss/wcnss_wlan.c | 72 +++++++++++++++++-- include/linux/wcnss_wlan.h | 6 ++ 4 files changed, 109 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index 5a49e6c9cff2..2a6cf09d3223 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -26,6 +26,7 @@ Required properties: - qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF - qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem - qcom,wcnss-adc_tm: ADC handle for vbatt notification APIs. +- qcom,wcnss-vadc: VADC handle for battery voltage notification APIs. - pinctrl- : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt - pinctrl-names : Names corresponding to the numbered pinctrl states - clocks: from common clock binding: handle to xo and rf_clk clocks. diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c index a581cb07a920..bbc161967c46 100644 --- a/drivers/net/wireless/wcnss/wcnss_vreg.c +++ b/drivers/net/wireless/wcnss/wcnss_vreg.c @@ -69,15 +69,16 @@ DEFINE_LED_TRIGGER(wlan_indication_led); #define VREG_SET_VOLTAGE_MASK 0x0002 #define VREG_OPTIMUM_MODE_MASK 0x0004 #define VREG_ENABLE_MASK 0x0008 +#define VDD_PA "qcom,iris-vddpa" #define WCNSS_INVALID_IRIS_REG 0xbaadbaad struct vregs_info { const char * const name; int state; - const int nominal_min; - const int low_power_min; - const int max_voltage; + int nominal_min; + int low_power_min; + int max_voltage; const int uA_load; struct regulator *regulator; }; @@ -469,6 +470,14 @@ fail: static void wcnss_vregs_off(struct vregs_info regulators[], uint size) { int i, rc = 0; + struct wcnss_wlan_config *cfg; + + cfg = wcnss_get_wlan_config(); + + if (!cfg) { + pr_err("Faild to get WLAN configuration\n"); + return; + } /* Regulators need to be turned off in the reverse order */ for (i = (size-1); i >= 0; i--) { @@ -486,6 +495,13 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size) /* Set voltage to lowest level */ if (regulators[i].state & VREG_SET_VOLTAGE_MASK) { + + if (cfg->vbatt < WCNSS_VBATT_THRESHOLD + && !memcmp(regulators[i].name, + VDD_PA, sizeof(VDD_PA))) { + regulators[i].max_voltage = WCNSS_VBATT_LOW; + } + rc = regulator_set_voltage(regulators[i].regulator, regulators[i].low_power_min, regulators[i].max_voltage); @@ -515,6 +531,14 @@ static int wcnss_vregs_on(struct device *dev, struct vregs_info regulators[], uint size) { int i, rc = 0, reg_cnt; + struct wcnss_wlan_config *cfg; + + cfg = wcnss_get_wlan_config(); + + if (!cfg) { + pr_err("Faild to get WLAN configuration\n"); + return -EINVAL; + } for (i = 0; i < size; i++) { /* Get regulator source */ @@ -531,6 +555,14 @@ static int wcnss_vregs_on(struct device *dev, /* Set voltage to nominal. Exclude swtiches e.g. LVS */ if ((regulators[i].nominal_min || regulators[i].max_voltage) && (reg_cnt > 0)) { + + if (cfg->vbatt < WCNSS_VBATT_THRESHOLD + && !memcmp(regulators[i].name, + VDD_PA, sizeof(VDD_PA))) { + regulators[i].nominal_min = WCNSS_VBATT_INITIAL; + regulators[i].max_voltage = WCNSS_VBATT_LOW; + } + rc = regulator_set_voltage(regulators[i].regulator, regulators[i].nominal_min, regulators[i].max_voltage); diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index a984d76846a2..52918be25a39 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -180,10 +180,6 @@ static DEFINE_SPINLOCK(reg_spinlock); #define MCU_FDBR_FDAHB_TIMEOUT_OFFSET 0x3ac #define WCNSS_DEF_WLAN_RX_BUFF_COUNT 1024 -#define WCNSS_VBATT_THRESHOLD 3500000 -#define WCNSS_VBATT_GUARD 20000 -#define WCNSS_VBATT_HIGH 3700000 -#define WCNSS_VBATT_LOW 3300000 #define WCNSS_CTRL_CHANNEL "WCNSS_CTRL" #define WCNSS_MAX_FRAME_SIZE (4*1024) @@ -388,6 +384,7 @@ static struct { struct work_struct wcnss_pm_config_work; struct work_struct wcnssctrl_nvbin_dnld_work; struct work_struct wcnssctrl_rx_work; + struct work_struct wcnss_vadc_work; struct wake_lock wcnss_wake_lock; void __iomem *msm_wcnss_base; void __iomem *riva_ccu_base; @@ -422,6 +419,7 @@ static struct { wait_queue_head_t read_wait; struct qpnp_adc_tm_btm_param vbat_monitor_params; struct qpnp_adc_tm_chip *adc_tm_dev; + struct qpnp_vadc_chip *vadc_dev; struct mutex vbat_monitor_mutex; u16 unsafe_ch_count; u16 unsafe_ch_list[WCNSS_MAX_CH_NUM]; @@ -1293,7 +1291,8 @@ static void wcnss_smd_notify_event(void *data, unsigned int event) schedule_work(&penv->wcnss_pm_config_work); cancel_delayed_work(&penv->wcnss_pm_qos_del_req); schedule_delayed_work(&penv->wcnss_pm_qos_del_req, 0); - + if (penv->wlan_config.is_pronto_v3 && (penv->vadc_dev)) + schedule_work(&penv->wcnss_vadc_work); break; case SMD_EVENT_CLOSE: @@ -1876,6 +1875,30 @@ static int wcnss_smd_tx(void *data, int len) return ret; } +static int wcnss_get_battery_volt(int *result_uv) +{ + int rc = -1; + struct qpnp_vadc_result adc_result; + + if (!penv->vadc_dev) { + pr_err("wcnss: not setting up vadc\n"); + return rc; + } + + rc = qpnp_vadc_read(penv->vadc_dev, VBAT_SNS, &adc_result); + if (rc) { + pr_err("error reading adc channel = %d, rc = %d\n", + VBAT_SNS, rc); + return rc; + } + + pr_info("Battery mvolts phy=%lld meas=0x%llx\n", adc_result.physical, + adc_result.measurement); + *result_uv = (int)adc_result.physical; + + return 0; +} + static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx) { mutex_lock(&penv->vbat_monitor_mutex); @@ -1938,6 +1961,27 @@ static int wcnss_setup_vbat_monitoring(void) return rc; } +static void wcnss_send_vbatt_indication(struct work_struct *work) +{ + struct vbatt_message vbatt_msg; + int ret = 0; + + vbatt_msg.hdr.msg_type = WCNSS_VBATT_LEVEL_IND; + vbatt_msg.hdr.msg_len = sizeof(struct vbatt_message); + vbatt_msg.vbatt.threshold = WCNSS_VBATT_THRESHOLD; + + mutex_lock(&penv->vbat_monitor_mutex); + vbatt_msg.vbatt.curr_volt = penv->wlan_config.vbatt; + mutex_unlock(&penv->vbat_monitor_mutex); + pr_debug("wcnss: send curr_volt: %d to FW\n", + vbatt_msg.vbatt.curr_volt); + + ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len); + if (ret < 0) + pr_err("wcnss: smd tx failed\n"); + return; +} + static void wcnss_update_vbatt(struct work_struct *work) { struct vbatt_message vbatt_msg; @@ -2663,6 +2707,7 @@ static int wcnss_trigger_config(struct platform_device *pdev) { int ret; + int rc; struct qcom_wcnss_opts *pdata; struct resource *res; int is_pronto_vt; @@ -3000,6 +3045,23 @@ wcnss_trigger_config(struct platform_device *pdev) penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED; } + if (penv->wlan_config.is_pronto_v3) { + penv->vadc_dev = qpnp_get_vadc(&penv->pdev->dev, "wcnss"); + + if (IS_ERR(penv->vadc_dev)) { + pr_err("%s: vadc get failed\n", __func__); + penv->vadc_dev = NULL; + } else { + rc = wcnss_get_battery_volt(&penv->wlan_config.vbatt); + INIT_WORK(&penv->wcnss_vadc_work, + wcnss_send_vbatt_indication); + + if (rc < 0) + pr_err("Failed to get battery voltage with error= %d\n", + rc); + } + } + do { /* trigger initialization of the WCNSS */ penv->pil = subsystem_get(WCNSS_PIL_DEVICE); diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 9bcb9a414ce7..88d97abfbea2 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -34,6 +34,7 @@ struct wcnss_wlan_config { int is_pronto_v4; void __iomem *msm_wcnss_base; int iris_id; + int vbatt; }; enum { @@ -51,6 +52,11 @@ enum { WCNSS_WLAN_MAX_GPIO, }; +#define WCNSS_VBATT_THRESHOLD 3500000 +#define WCNSS_VBATT_GUARD 20000 +#define WCNSS_VBATT_HIGH 3700000 +#define WCNSS_VBATT_LOW 3300000 +#define WCNSS_VBATT_INITIAL 3000000 #define WCNSS_WLAN_IRQ_INVALID -1 #define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1 #define HAVE_WCNSS_RESET_INTR 1 -- GitLab From 273040a8e9d01454c04044e0917c45180befc5d4 Mon Sep 17 00:00:00 2001 From: Hardik Kantilal Patel Date: Mon, 13 Apr 2015 09:46:17 -0700 Subject: [PATCH 230/528] wcnss: Add level based voting As per new policy level base voting required for vddmx and vddcx voltage regulator. Added level based voting support for CX and MX rail. CRs-Fixed: 821636 Change-Id: Ifbe24bf898de2bc671af836206b9cc8baadcb45b Signed-off-by: Hardik Kantilal Patel (cherry picked from commit 07cee9cca5c7b61b3ee4766c9589d2c2083c7470) --- drivers/net/wireless/wcnss/wcnss_vreg.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c index bbc161967c46..8ddad28b2c83 100644 --- a/drivers/net/wireless/wcnss/wcnss_vreg.c +++ b/drivers/net/wireless/wcnss/wcnss_vreg.c @@ -157,6 +157,18 @@ static struct vregs_info pronto_vregs_pronto_v3[] = { 1800000, 0, NULL}, }; +/* WCNSS regulators for Pronto v4 hardware */ +static struct vregs_info pronto_vregs_pronto_v4[] = { + {"qcom,pronto-vddmx", VREG_NULL_CONFIG, RPM_REGULATOR_LEVEL_TURBO, + RPM_REGULATOR_LEVEL_NONE, RPM_REGULATOR_LEVEL_TURBO, + 0, NULL}, + {"qcom,pronto-vddcx", VREG_NULL_CONFIG, RPM_REGULATOR_LEVEL_NOM, + RPM_REGULATOR_LEVEL_NONE, RPM_REGULATOR_LEVEL_TURBO, + 0, NULL}, + {"qcom,pronto-vddpx", VREG_NULL_CONFIG, 1800000, 0, + 1800000, 0, NULL}, +}; + struct host_driver { char name[20]; @@ -612,7 +624,8 @@ static void wcnss_iris_vregs_off(enum wcnss_hw_type hw_type, wcnss_vregs_off(iris_vregs_riva, ARRAY_SIZE(iris_vregs_riva)); break; case WCNSS_PRONTO_HW: - if (cfg->is_pronto_vt || cfg->is_pronto_v3) { + if (cfg->is_pronto_vt || cfg->is_pronto_v3 + || cfg->is_pronto_v4) { wcnss_vregs_off(iris_vregs_pronto_v2, ARRAY_SIZE(iris_vregs_pronto_v2)); } else { @@ -638,7 +651,8 @@ static int wcnss_iris_vregs_on(struct device *dev, ARRAY_SIZE(iris_vregs_riva)); break; case WCNSS_PRONTO_HW: - if (cfg->is_pronto_vt || cfg->is_pronto_v3) { + if (cfg->is_pronto_vt || cfg->is_pronto_v3 + || cfg->is_pronto_v4) { ret = wcnss_vregs_on(dev, iris_vregs_pronto_v2, ARRAY_SIZE(iris_vregs_pronto_v2)); } else { @@ -666,6 +680,9 @@ static void wcnss_core_vregs_off(enum wcnss_hw_type hw_type, } else if (cfg->is_pronto_v3) { wcnss_vregs_off(pronto_vregs_pronto_v3, ARRAY_SIZE(pronto_vregs_pronto_v3)); + } else if (cfg->is_pronto_v4) { + wcnss_vregs_off(pronto_vregs_pronto_v4, + ARRAY_SIZE(pronto_vregs_pronto_v4)); } else { wcnss_vregs_off(pronto_vregs, ARRAY_SIZE(pronto_vregs)); @@ -694,6 +711,9 @@ static int wcnss_core_vregs_on(struct device *dev, } else if (cfg->is_pronto_v3) { ret = wcnss_vregs_on(dev, pronto_vregs_pronto_v3, ARRAY_SIZE(pronto_vregs_pronto_v3)); + } else if (cfg->is_pronto_v4) { + ret = wcnss_vregs_on(dev, pronto_vregs_pronto_v4, + ARRAY_SIZE(pronto_vregs_pronto_v4)); } else { ret = wcnss_vregs_on(dev, pronto_vregs, ARRAY_SIZE(pronto_vregs)); -- GitLab From f5476a15dbdbe18a5f2ef77a20058d65706833f9 Mon Sep 17 00:00:00 2001 From: Hardik Kantilal Patel Date: Tue, 16 Jun 2015 03:26:36 -0700 Subject: [PATCH 231/528] wcnss: Add VBATT support - Add ADC entry for wcnss which is use to listen low vbatt notification from ADC. - Prevent sending vbatt notification to FW incase of ADC channel not present. CRs-Fixed: 855069 Change-Id: If53a2d2089f292cbd87418d0a451bd11a0c95322 Signed-off-by: Hardik Kantilal Patel (cherry picked from commit 58ad32726a5858b256c884dee7e169d1f954275b) --- .../devicetree/bindings/wcnss/wcnss-wlan.txt | 2 ++ drivers/net/wireless/wcnss/wcnss_wlan.c | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index 2a6cf09d3223..6423374b6640 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -57,6 +57,8 @@ in TX data path. 6 - GPIO strength value - qcom,wlan-indication-enabled: boolean flag to determine if WLAN indication-LED will be turned on/off when WLAN is enabled/disabled respectively. +- qcom,has-vsys-adc-channel: boolean flag to determine which ADC HW channel need +to use for VBATT feature. Example: diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 52918be25a39..b68d295add22 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -369,6 +369,7 @@ static struct { int triggered; int smd_channel_ready; u32 wlan_rx_buff_count; + int is_vsys_adc_channel; smd_channel_t *smd_ch; unsigned char wcnss_version[WCNSS_VERSION_LEN]; unsigned char fw_major; @@ -1901,6 +1902,8 @@ static int wcnss_get_battery_volt(int *result_uv) static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx) { + int rc = 0; + mutex_lock(&penv->vbat_monitor_mutex); cancel_delayed_work_sync(&penv->vbatt_work); @@ -1928,9 +1931,15 @@ static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx) penv->vbat_monitor_params.low_thr, penv->vbat_monitor_params.high_thr); - qpnp_adc_tm_channel_measure(penv->adc_tm_dev, + rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev, &penv->vbat_monitor_params); - schedule_delayed_work(&penv->vbatt_work, msecs_to_jiffies(2000)); + + if (rc) + pr_err("%s: tm setup failed: %d\n", __func__, rc); + else + schedule_delayed_work(&penv->vbatt_work, + msecs_to_jiffies(2000)); + mutex_unlock(&penv->vbat_monitor_mutex); } @@ -1945,7 +1954,12 @@ static int wcnss_setup_vbat_monitoring(void) penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD; penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD; penv->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE; - penv->vbat_monitor_params.channel = VBAT_SNS; + + if (penv->is_vsys_adc_channel) + penv->vbat_monitor_params.channel = VSYS; + else + penv->vbat_monitor_params.channel = VBAT_SNS; + penv->vbat_monitor_params.btm_ctx = (void *)penv; penv->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S; penv->vbat_monitor_params.threshold_notification = &wcnss_notify_vbat; @@ -1956,7 +1970,7 @@ static int wcnss_setup_vbat_monitoring(void) rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev, &penv->vbat_monitor_params); if (rc) - pr_err("wcnss: tm setup failed: %d\n", rc); + pr_err("%s: tm setup failed: %d\n", __func__, rc); return rc; } @@ -2726,6 +2740,9 @@ wcnss_trigger_config(struct platform_device *pdev) is_pronto_v4 = of_property_read_bool(pdev->dev.of_node, "qcom,is-pronto-v4"); + penv->is_vsys_adc_channel = of_property_read_bool(pdev->dev.of_node, + "qcom,has-vsys-adc-channel"); + if (of_property_read_u32(pdev->dev.of_node, "qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) { penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT; -- GitLab From b311dfcdacd216a1ee97dc1516ae00b8931eb78f Mon Sep 17 00:00:00 2001 From: Anand N Sunkad Date: Mon, 2 Nov 2015 19:06:58 +0530 Subject: [PATCH 232/528] wcnss: configure pc disable latency Configure PC disable latency value for 8976 target when pm_qos request to disable power collapse for DDR during SSR and coldboot. CRs-Fixed: 914674 Change-Id: I65a2ca8b4a94a337195e8c4e8e4743e38f57197e Signed-off-by: Anand N Sunkad (cherry picked from commit d8ad86c8b4cc06ac0c31b99506d4ac9c3154f4d5) --- Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt | 2 ++ drivers/net/wireless/wcnss/wcnss_wlan.c | 9 ++++++++- include/linux/wcnss_wlan.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index 6423374b6640..a1abf22752f2 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -59,6 +59,8 @@ in TX data path. will be turned on/off when WLAN is enabled/disabled respectively. - qcom,has-vsys-adc-channel: boolean flag to determine which ADC HW channel need to use for VBATT feature. +- qcom,pc-disable-latency: is a configurable value to configure +pc disable latency value. Example: diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index b68d295add22..1c22cb4f7d0b 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -1261,7 +1261,8 @@ void wcnss_disable_pc_add_req(void) if (!penv->pc_disabled) { wcnss_pm_qos_add_request(); wcnss_prevent_suspend(); - wcnss_pm_qos_update_request(WCNSS_DISABLE_PC_LATENCY); + wcnss_pm_qos_update_request(penv->wlan_config. + pc_disable_latency); penv->pc_disabled = 1; } mutex_unlock(&penv->pm_qos_mutex); @@ -2748,6 +2749,12 @@ wcnss_trigger_config(struct platform_device *pdev) penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT; } + if (of_property_read_u32(pdev->dev.of_node, + "qcom,pc-disable-latency", + &penv->wlan_config.pc_disable_latency)) { + penv->wlan_config.pc_disable_latency = WCNSS_DISABLE_PC_LATENCY; + } + /* make sure we are only triggered once */ if (penv->triggered) return 0; diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 88d97abfbea2..e4c0b5686b34 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -35,6 +35,7 @@ struct wcnss_wlan_config { void __iomem *msm_wcnss_base; int iris_id; int vbatt; + int pc_disable_latency; }; enum { -- GitLab From 9bb998bc6bf530faacd5fc3eaf69452d9c450fce Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Wed, 2 Dec 2015 16:01:30 +0530 Subject: [PATCH 233/528] wcnss: Fix compilation issue for wcnss crypto module Compile wcnss crypto module independent of CNSS/WCNSS config. CRs-Fixed: 944529 Change-Id: Ib9f997fd4f6c7fd32aaeeb5f057c21a6b5d061eb Signed-off-by: Sunkad, Anand Ningappa Signed-off-by: Sarada Prasanna Garnayak (cherry picked from commit a6f438f02331106bac4544e4dee7d6a6e7c6a901) --- drivers/net/wireless/cnss/Makefile | 2 -- drivers/net/wireless/cnss_prealloc/Makefile | 3 ++- drivers/net/wireless/wcnss/Makefile | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/cnss/Makefile b/drivers/net/wireless/cnss/Makefile index ff670f14dde3..158ccc9a0864 100644 --- a/drivers/net/wireless/cnss/Makefile +++ b/drivers/net/wireless/cnss/Makefile @@ -1,6 +1,4 @@ # Makefile for CNSS platform driver -cnsscore-objs += ../wcnss/qcomwlan_secif.o obj-$(CONFIG_CNSS_PCI) += cnss_pci.o obj-y += cnss_common.o -obj-y += cnsscore.o diff --git a/drivers/net/wireless/cnss_prealloc/Makefile b/drivers/net/wireless/cnss_prealloc/Makefile index 0adbd4206e9c..a93da4900470 100644 --- a/drivers/net/wireless/cnss_prealloc/Makefile +++ b/drivers/net/wireless/cnss_prealloc/Makefile @@ -1 +1,2 @@ -obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc.o +cnssprealloccore-objs += cnss_prealloc.o ../wcnss/qcomwlan_secif.o +obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnssprealloccore.o diff --git a/drivers/net/wireless/wcnss/Makefile b/drivers/net/wireless/wcnss/Makefile index 11fa673e056f..072fef85044d 100644 --- a/drivers/net/wireless/wcnss/Makefile +++ b/drivers/net/wireless/wcnss/Makefile @@ -1,6 +1,6 @@ # Makefile for WCNSS triple-play driver -wcnsscore-objs += wcnss_wlan.o qcomwlan_secif.o wcnss_vreg.o +wcnsscore-objs += wcnss_wlan.o wcnss_vreg.o obj-$(CONFIG_WCNSS_CORE) += wcnsscore.o -- GitLab From 101c6f20b386b4a6ec6c69979d03be54d32bb89a Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Thu, 10 Dec 2015 17:05:06 +0530 Subject: [PATCH 234/528] net: wireless: decouple cnss crypto from cnss memory pre-alloc The cnss crypto add support for wlan host driver for security Protocol and cipher key generation where cnss memory pre-alloc feature enable wlan driver to use pre allocated memory for its internal usage and release it to back to pre-allocated pool. Decouple cnss crypto from cnss memory pre-alloc and add kernel config flag for this crypto module compilation and update the defconfig of required targets. CRs-Fixed: 949992 Change-Id: If34819fd76076ba522a9a42ac41fdae1f541f5c8 Signed-off-by: Sarada Prasanna Garnayak (cherry picked from commit 090ccc7ea37ebdca427d35cbcc9fc34353d4a08d) --- drivers/net/wireless/Kconfig | 9 +++++++++ drivers/net/wireless/Makefile | 1 + drivers/net/wireless/cnss/Kconfig | 1 + drivers/net/wireless/cnss_crypto/Makefile | 1 + .../cnss_secif.c} | 16 +++++++--------- drivers/net/wireless/cnss_prealloc/Makefile | 3 +-- 6 files changed, 20 insertions(+), 11 deletions(-) create mode 100644 drivers/net/wireless/cnss_crypto/Makefile rename drivers/net/wireless/{wcnss/qcomwlan_secif.c => cnss_crypto/cnss_secif.c} (93%) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 2de6d6bc0f14..c635b9e48882 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -295,6 +295,7 @@ config WCNSS_CORE select WEXT_PRIV select WEXT_CORE select WEXT_SPY + select CNSS_CRYPTO ---help--- Core driver for the Qualcomm WCNSS triple play connectivity subsystem @@ -319,6 +320,14 @@ config WCNSS_REGISTER_DUMP_ON_BITE register access failures. So this feature is to enable/disable the register dump on WCNSS WDOG bite. +config CNSS_CRYPTO + tristate "Enable CNSS crypto support" + ---help--- + Add crypto support for the WLAN driver module. + This feature enable wlan driver to use the crypto APIs exported + from cnss platform driver. This crypto APIs used to generate cipher + key and add support for the WLAN driver module security protocol. + config BCMDHD_PCIE bool "PCIe bus interface support" depends on PCI diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 8a5615248bc7..702f1241d143 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -68,3 +68,4 @@ obj-$(CONFIG_WCNSS_CORE) += wcnss/ obj-$(CONFIG_CNSS_SDIO) += cnss/cnss_sdio.o obj-$(CONFIG_CNSS) += cnss/ obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/ +obj-$(CONFIG_CNSS_CRYPTO) += cnss_crypto/ diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig index 99dab03299b9..55eebecca964 100644 --- a/drivers/net/wireless/cnss/Kconfig +++ b/drivers/net/wireless/cnss/Kconfig @@ -3,6 +3,7 @@ config CNSS select CRYPTO select CRYPTO_HASH select CRYPTO_BLKCIPHER + select CNSS_CRYPTO ---help--- This module adds support for the CNSS connectivity subsystem used for wifi devices based on the QCA AR6320 chipset. diff --git a/drivers/net/wireless/cnss_crypto/Makefile b/drivers/net/wireless/cnss_crypto/Makefile new file mode 100644 index 000000000000..cfe0285eb31e --- /dev/null +++ b/drivers/net/wireless/cnss_crypto/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CNSS_CRYPTO) += cnss_secif.o diff --git a/drivers/net/wireless/wcnss/qcomwlan_secif.c b/drivers/net/wireless/cnss_crypto/cnss_secif.c similarity index 93% rename from drivers/net/wireless/wcnss/qcomwlan_secif.c rename to drivers/net/wireless/cnss_crypto/cnss_secif.c index 381943a6d911..24202d3a7c58 100644 --- a/drivers/net/wireless/wcnss/qcomwlan_secif.c +++ b/drivers/net/wireless/cnss_crypto/cnss_secif.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, 2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -91,7 +91,6 @@ static inline void leftshift_onebit(const u8 *input, u8 *output) output[i] |= overflow; overflow = (input[i] & 0x80) ? 1 : 0; } - return; } static void generate_subkey(struct crypto_cipher *tfm, u8 *k1, u8 *k2) @@ -136,7 +135,6 @@ static inline void padding(u8 *lastb, u8 *pad, u16 length) } } - void wcnss_wlan_cmac_calc_mic(struct crypto_cipher *tfm, u8 *m, u16 length, u8 *mac) { @@ -144,21 +142,21 @@ void wcnss_wlan_cmac_calc_mic(struct crypto_cipher *tfm, u8 *m, u8 m_last[AES_BLOCK_SIZE], padded[AES_BLOCK_SIZE]; u8 k1[AES_KEYSIZE_128], k2[AES_KEYSIZE_128]; int cmpBlk; - int i, nBlocks = (length + 15)/AES_BLOCK_SIZE; + int i, nblocks = (length + 15) / AES_BLOCK_SIZE; generate_subkey(tfm, k1, k2); - if (nBlocks == 0) { - nBlocks = 1; + if (nblocks == 0) { + nblocks = 1; cmpBlk = 0; } else { cmpBlk = ((length % AES_BLOCK_SIZE) == 0) ? 1 : 0; } if (cmpBlk) { /* Last block is complete block */ - xor_128(&m[AES_BLOCK_SIZE * (nBlocks - 1)], k1, m_last); + xor_128(&m[AES_BLOCK_SIZE * (nblocks - 1)], k1, m_last); } else { /* Last block is not complete block */ - padding(&m[AES_BLOCK_SIZE * (nBlocks - 1)], padded, + padding(&m[AES_BLOCK_SIZE * (nblocks - 1)], padded, length % AES_BLOCK_SIZE); xor_128(padded, k2, m_last); } @@ -166,7 +164,7 @@ void wcnss_wlan_cmac_calc_mic(struct crypto_cipher *tfm, u8 *m, for (i = 0; i < AES_BLOCK_SIZE; i++) x[i] = 0; - for (i = 0; i < (nBlocks - 1); i++) { + for (i = 0; i < (nblocks - 1); i++) { xor_128(x, &m[AES_BLOCK_SIZE * i], y); /* y = Mi (+) x */ crypto_cipher_encrypt_one(tfm, x, y); /* x = AES-128(KEY, y) */ } diff --git a/drivers/net/wireless/cnss_prealloc/Makefile b/drivers/net/wireless/cnss_prealloc/Makefile index a93da4900470..0adbd4206e9c 100644 --- a/drivers/net/wireless/cnss_prealloc/Makefile +++ b/drivers/net/wireless/cnss_prealloc/Makefile @@ -1,2 +1 @@ -cnssprealloccore-objs += cnss_prealloc.o ../wcnss/qcomwlan_secif.o -obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnssprealloccore.o +obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc.o -- GitLab From 1e8f797731378c1acdd607e7d881d6e956afd49b Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Thu, 31 Dec 2015 16:32:02 +0530 Subject: [PATCH 235/528] net: wireless: add conditional compilation flag for cnss Refactor cnss wlan module for PCIe and SDIO based interface wlan module. Add config flag CONFIG_CNSS for the cnss wlan module compilation. CRs-Fixed: 957132 Change-Id: I5043b8024b5cc342325b126fa4ccd7d76b0f8540 Signed-off-by: Sarada Prasanna Garnayak (cherry picked from commit f358a12f7dbaec00c480f877ce311160533f2189) --- drivers/net/wireless/Makefile | 1 - drivers/net/wireless/cnss/Kconfig | 1 + drivers/net/wireless/cnss/Makefile | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 702f1241d143..3890ef3526db 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -65,7 +65,6 @@ obj-$(CONFIG_BRCMSMAC) += brcm80211/ obj-$(CONFIG_LIBRA_SDIOIF) += libra/ obj-$(CONFIG_WCNSS_CORE) += wcnss/ -obj-$(CONFIG_CNSS_SDIO) += cnss/cnss_sdio.o obj-$(CONFIG_CNSS) += cnss/ obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/ obj-$(CONFIG_CNSS_CRYPTO) += cnss_crypto/ diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig index 55eebecca964..f5032045df49 100644 --- a/drivers/net/wireless/cnss/Kconfig +++ b/drivers/net/wireless/cnss/Kconfig @@ -25,6 +25,7 @@ config CNSS_PCI config CNSS_SDIO tristate "Flag to enable platform driver for SIDO based wifi device" + select CNSS depends on MMC_SDHCI depends on MMC_SDHCI_MSM ---help--- diff --git a/drivers/net/wireless/cnss/Makefile b/drivers/net/wireless/cnss/Makefile index 158ccc9a0864..4401158fe888 100644 --- a/drivers/net/wireless/cnss/Makefile +++ b/drivers/net/wireless/cnss/Makefile @@ -1,4 +1,5 @@ # Makefile for CNSS platform driver obj-$(CONFIG_CNSS_PCI) += cnss_pci.o -obj-y += cnss_common.o +obj-$(CONFIG_CNSS_SDIO) += cnss_sdio.o +obj-$(CONFIG_CNSS) += cnss_common.o -- GitLab From b5120877425b63070921f90652f6a510f4692ca0 Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Tue, 16 Feb 2016 12:24:11 -0800 Subject: [PATCH 236/528] cnss_prealloc: Dump the call stack if there is no memory available Dump the call stack if there is no memory available from the prealloc pool in order to get the source of the memory allocation. Change-Id: I0b523e82638410ea679f1d9d3f4bb56703ed9100 Signed-off-by: Yue Ma (cherry picked from commit bb9a6cce2304e7ce6cb518ca30f8bae4548a164b) --- drivers/net/wireless/cnss_prealloc/cnss_prealloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c index f666bf841e3f..b731926c0189 100644 --- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c +++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c @@ -170,6 +170,7 @@ void *wcnss_prealloc_get(unsigned int size) pr_err("wcnss: %s: prealloc not available for size: %d\n", __func__, size); + WARN_ON(1); return NULL; } -- GitLab From 7d4e1a37f2765e33e361f3994243954ed184ccf4 Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Fri, 1 Dec 2017 15:29:54 +0530 Subject: [PATCH 237/528] wcnss: fix the potential buffer overflow in wlan ctrl data process Validate the userspace wlan control cmd data, info and length before copy into wcnss driver buffer. Avoid unnecessary string manipulation and use kernel defined format specifier to print wlan MAC address. CRs-Fixed: 2149331 Change-Id: Ib59fdcc0e6b84cdd73972dcb62b2c05e4741f5f7 Signed-off-by: Yuanyuan Liu Signed-off-by: Sarada Prasanna Garnayak Signed-off-by: Yasir Malik [Resolved trivial merge conflicts] Signed-off-by: Andrey Cherepkov (cherry picked from commit a11692a479a174ee733a42d4e262931a9b6643fc) --- drivers/net/wireless/wcnss/wcnss_wlan.c | 87 ++++++++++++------------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 1c22cb4f7d0b..d4725d24f575 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -188,6 +188,7 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_MAX_CMD_LEN (128) #define WCNSS_MIN_CMD_LEN (3) #define WCNSS_MIN_SERIAL_LEN (6) +#define WCNSS_CMD_INFO_LEN 2 /* control messages from userspace */ #define WCNSS_USR_CTRL_MSG_START 0x00000000 @@ -464,11 +465,7 @@ static ssize_t wcnss_wlan_macaddr_store(struct device *dev, (char *)&macAddr[index], sizeof(char)); } - pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); - + pr_info("%s: Write MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr); return count; } @@ -478,10 +475,7 @@ static ssize_t wcnss_wlan_macaddr_show(struct device *dev, if (!penv) return -ENODEV; - return scnprintf(buf, PAGE_SIZE, SHOW_MAC_ADDRESS_STR, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + return scnprintf(buf, PAGE_SIZE, "%pM\n", penv->wlan_nv_macAddr); } static DEVICE_ATTR(wcnss_mac_addr, S_IRUSR | S_IWUSR, @@ -1680,10 +1674,8 @@ int wcnss_get_wlan_mac_address(char mac_addr[WLAN_MAC_ADDR_SIZE]) return -ENODEV; memcpy(mac_addr, penv->wlan_nv_macAddr, WLAN_MAC_ADDR_SIZE); - pr_debug("%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + pr_debug("%s: Get MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr); + return 0; } EXPORT_SYMBOL(wcnss_get_wlan_mac_address); @@ -2646,66 +2638,67 @@ static int wcnss_ctrl_open(struct inode *inode, struct file *file) return rc; } - -void process_usr_ctrl_cmd(u8 *buf, size_t len) +static ssize_t wcnss_ctrl_write(struct file *fp, const char __user + *user_buffer, size_t count, loff_t *position) { - u16 cmd = buf[0] << 8 | buf[1]; + int rc = 0; + u16 cmd; + u8 buf[WCNSS_MAX_CMD_LEN]; - switch (cmd) { + if (!penv || !penv->ctrl_device_opened || + WCNSS_MAX_CMD_LEN < count || WCNSS_MIN_CMD_LEN > count) + return -EFAULT; + mutex_lock(&penv->ctrl_lock); + rc = copy_from_user(buf, user_buffer, count); + if (rc) { + pr_err("%s: Failed to copy ctrl data\n", __func__); + goto exit; + } + + cmd = buf[0] << 8 | buf[1]; + switch (cmd) { case WCNSS_USR_SERIAL_NUM: - if (WCNSS_MIN_SERIAL_LEN > len) { + if (WCNSS_MIN_SERIAL_LEN > count) { pr_err("%s: Invalid serial number\n", __func__); - return; + rc = -EINVAL; + goto exit; } penv->serial_number = buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5]; break; case WCNSS_USR_HAS_CAL_DATA: - if (1 < buf[2]) - pr_err("%s: Invalid data for cal %d\n", __func__, - buf[2]); + if (buf[2] > 1) { + pr_err("%s: Invalid cal data %d\n", __func__, buf[2]); + rc = -EINVAL; + goto exit; + } has_calibrated_data = buf[2]; break; case WCNSS_USR_WLAN_MAC_ADDR: - memcpy(&penv->wlan_nv_macAddr, &buf[2], - sizeof(penv->wlan_nv_macAddr)); + if ((count - WCNSS_CMD_INFO_LEN) != WLAN_MAC_ADDR_SIZE) { + pr_err("%s: Invalid Mac addr %d\n", __func__, buf[2]); + rc = -EINVAL; + goto exit; + } - pr_debug("%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + memcpy(&penv->wlan_nv_macAddr, &buf[2], + sizeof(penv->wlan_nv_macAddr)); + pr_debug("%s:MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr); break; - default: pr_err("%s: Invalid command %d\n", __func__, cmd); + rc = -EINVAL; break; } -} - -static ssize_t wcnss_ctrl_write(struct file *fp, const char __user - *user_buffer, size_t count, loff_t *position) -{ - int rc = 0; - u8 buf[WCNSS_MAX_CMD_LEN]; - - if (!penv || !penv->ctrl_device_opened || WCNSS_MAX_CMD_LEN < count - || WCNSS_MIN_CMD_LEN > count) - return -EFAULT; - - mutex_lock(&penv->ctrl_lock); - rc = copy_from_user(buf, user_buffer, count); - if (0 == rc) - process_usr_ctrl_cmd(buf, count); +exit: mutex_unlock(&penv->ctrl_lock); - return rc; } - static const struct file_operations wcnss_ctrl_fops = { .owner = THIS_MODULE, .open = wcnss_ctrl_open, -- GitLab From 7895a3c9edd83e1af32435cbf9b4b2c5cc8d640c Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Mon, 24 Apr 2017 08:40:28 +0800 Subject: [PATCH 238/528] rndis_wlan: add return value validation [ Upstream commit 9dc7efd3978aa67ae598129d2a3f240b390ce508 ] Function create_singlethread_workqueue() will return a NULL pointer if there is no enough memory, and its return value should be validated before using. However, in function rndis_wlan_bind(), its return value is not checked. This may cause NULL dereference bugs. This patch fixes it. Signed-off-by: Pan Bian Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 6818b16ed7491eb5d853ed504c7b4faed7830759) --- drivers/net/wireless/rndis_wlan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 1b7117e4c84d..9f33ff03e604 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -3423,6 +3423,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); + if (!priv->workqueue) { + wiphy_free(wiphy); + return -ENOMEM; + } INIT_WORK(&priv->work, rndis_wlan_worker); INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); -- GitLab From f722bf812f44219cf12a17cf7d6deb83cbd2f05e Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Sun, 23 Dec 2018 22:34:29 +0300 Subject: [PATCH 239/528] drivers: wireless: bcm43455: Fix -Wmisleading-indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c: In function ‘dhd_bus_devreset’: /drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c:8146:6: warning: this ‘else’ clause does not guard... [-Wmisleading-indentation] } else ^~~~ /drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c:8149:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘else’ dhd_os_sdunlock(dhdp); ^~~~~~~~~~~~~~~ /drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c: In function ‘wl_cfg80211_mgmt_tx’:/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c:5636:4: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation] if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) ^~/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c:5638:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’ wl_cfgp2p_set_management_ie(cfg, dev, bssidx, ^~~~~~~~~~~~~~~~~~~~~~~~~~~ (cherry picked from commit 14efd9f2157171f5e47692c09ac161e926c61d40) --- drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c | 2 +- drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c index f04512680089..5faca9c508d7 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c @@ -8146,7 +8146,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) } else bcmerror = BCME_SDIO_ERROR; - dhd_os_sdunlock(dhdp); + dhd_os_sdunlock(dhdp); } else { bcmerror = BCME_SDIO_ERROR; DHD_INFO(("%s called when dongle is not in reset\n", diff --git a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index cff5b0b42ac4..3787c351d908 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -5635,7 +5635,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, s32 ie_len = len - ie_offset; if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + wl_cfgp2p_set_management_ie(cfg, dev, bssidx, VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); goto exit; -- GitLab From 2c1d97c87185b9ce679965da9519e381fdc6ff23 Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Sun, 23 Dec 2018 22:33:57 +0300 Subject: [PATCH 240/528] drivers: wireless: bcm4356: Fix -Wmisleading-indentation (cherry picked from commit 05ab18b7dee8e2002259bdfc54817da157865948) --- drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c | 2 +- drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c index 14f9d57f8b39..179a1dfe0735 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c @@ -8101,7 +8101,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) } else bcmerror = BCME_SDIO_ERROR; - dhd_os_sdunlock(dhdp); + dhd_os_sdunlock(dhdp); } else { bcmerror = BCME_SDIO_ERROR; DHD_INFO(("%s called when dongle is not in reset\n", diff --git a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c index eb08e1b359d3..7a806d96a41a 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -6344,7 +6344,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, s32 ie_len = len - ie_offset; if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + wl_cfgp2p_set_management_ie(cfg, dev, bssidx, VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); goto exit; -- GitLab From 1a2a341b71db3c5985655384de7a6873f430ed3f Mon Sep 17 00:00:00 2001 From: Eyal Reizer Date: Mon, 28 May 2018 11:36:42 +0300 Subject: [PATCH 241/528] wlcore: sdio: check for valid platform device data before suspend [ Upstream commit 6e91d48371e79862ea2c05867aaebe4afe55a865 ] the wl pointer can be null In case only wlcore_sdio is probed while no WiLink module is successfully probed, as in the case of mounting a wl12xx module while using a device tree file configured with wl18xx related settings. In this case the system was crashing in wl1271_suspend() as platform device data is not set. Make sure wl the pointer is valid before using it. Signed-off-by: Eyal Reizer Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 859de7698f8b049123a4f50310b99b43f4c4caa7) --- drivers/net/wireless/ti/wlcore/sdio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 29ef2492951f..c2bf68c359a9 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -348,6 +348,11 @@ static int wl1271_suspend(struct device *dev) mmc_pm_flag_t sdio_flags; int ret = 0; + if (!wl) { + dev_err(dev, "no wilink module was probed\n"); + goto out; + } + dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", wl->wow_enabled); -- GitLab From 9b7b38dfe159a89424d2946d422c09f68ae26ac2 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Thu, 24 May 2018 19:18:27 +0530 Subject: [PATCH 242/528] mwifiex: handle race during mwifiex_usb_disconnect [ Upstream commit b817047ae70c0bd67b677b65d0d69d72cd6e9728 ] Race condition is observed during rmmod of mwifiex_usb: 1. The rmmod thread will call mwifiex_usb_disconnect(), download SHUTDOWN command and do wait_event_interruptible_timeout(), waiting for response. 2. The main thread will handle the response and will do a wake_up_interruptible(), unblocking rmmod thread. 3. On getting unblocked, rmmod thread will make rx_cmd.urb = NULL in mwifiex_usb_free(). 4. The main thread will try to resubmit rx_cmd.urb in mwifiex_usb_submit_rx_urb(), which is NULL. To fix, wait for main thread to complete before calling mwifiex_usb_free(). Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 5030e49a93c200f8fd0398b4e8ca822157a544de) --- drivers/net/wireless/mwifiex/usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 923e348dda70..5d4f85a1a4ed 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -550,6 +550,9 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) MWIFIEX_FUNC_SHUTDOWN); } + if (adapter->workqueue) + flush_workqueue(adapter->workqueue); + mwifiex_usb_free(card); dev_dbg(adapter->dev, "%s: removing card\n", __func__); -- GitLab From 2de1de366b3a804ab947a8934a0ad874fbab3ef2 Mon Sep 17 00:00:00 2001 From: Mike B Date: Tue, 23 Mar 2021 17:43:44 +0100 Subject: [PATCH 243/528] arm64: config: kitakami - reflect changes to wifi --- arch/arm64/configs/kitakami_ivy_defconfig | 2 ++ arch/arm64/configs/kitakami_karin_defconfig | 3 ++- arch/arm64/configs/kitakami_karin_windy_defconfig | 2 ++ arch/arm64/configs/kitakami_satsuki_defconfig | 3 ++- arch/arm64/configs/kitakami_sumire_defconfig | 2 ++ 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/kitakami_ivy_defconfig b/arch/arm64/configs/kitakami_ivy_defconfig index 548a432ac2ce..dfb6fd7331f0 100644 --- a/arch/arm64/configs/kitakami_ivy_defconfig +++ b/arch/arm64/configs/kitakami_ivy_defconfig @@ -270,6 +270,8 @@ CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y CONFIG_SOMC_WIFI_CONTROL=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD=y CONFIG_BCM4356=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" diff --git a/arch/arm64/configs/kitakami_karin_defconfig b/arch/arm64/configs/kitakami_karin_defconfig index 4e9eeac476fe..b2c64ff0381e 100644 --- a/arch/arm64/configs/kitakami_karin_defconfig +++ b/arch/arm64/configs/kitakami_karin_defconfig @@ -266,8 +266,9 @@ CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y CONFIG_SOMC_WIFI_CONTROL=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=y -CONFIG_BCMDHD=y CONFIG_BCM4356=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" CONFIG_CLD_LL_CORE=y diff --git a/arch/arm64/configs/kitakami_karin_windy_defconfig b/arch/arm64/configs/kitakami_karin_windy_defconfig index f96f41e7a804..022175f13bee 100644 --- a/arch/arm64/configs/kitakami_karin_windy_defconfig +++ b/arch/arm64/configs/kitakami_karin_windy_defconfig @@ -268,6 +268,8 @@ CONFIG_ATH_CARDS=y CONFIG_WIL6210=y CONFIG_BCMDHD=y CONFIG_BCM4356=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" CONFIG_CLD_LL_CORE=y diff --git a/arch/arm64/configs/kitakami_satsuki_defconfig b/arch/arm64/configs/kitakami_satsuki_defconfig index 64778f4cfd95..3aabd0ea8d40 100644 --- a/arch/arm64/configs/kitakami_satsuki_defconfig +++ b/arch/arm64/configs/kitakami_satsuki_defconfig @@ -283,7 +283,8 @@ CONFIG_SOMC_WIFI_CONTROL=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=y CONFIG_BCMDHD=y -CONFIG_BCM4356=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" CONFIG_CLD_LL_CORE=y diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index d8eca1c5bfdc..da865d48c753 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -284,6 +284,8 @@ CONFIG_ATH_CARDS=y CONFIG_WIL6210=y CONFIG_BCMDHD=y CONFIG_BCM4356=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" CONFIG_CLD_LL_CORE=y -- GitLab From 9d7238dfc7fecb3f6181c37694b9f2e163b0159a Mon Sep 17 00:00:00 2001 From: Mike B Date: Tue, 23 Mar 2021 18:01:25 +0100 Subject: [PATCH 244/528] bcm43455: Disable BCM4354 --- drivers/net/wireless/bcmdhd_bcm43455/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig index 37e9a097bd72..81fd573fe9b5 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -config BCM4354 - bool "Broadcom 4354 wireless card support" - depends on BCMDHD - ---help--- - This module adds support for wireless adapters based on - Broadcom 4354 chipset. +#config BCM4354 +# bool "Broadcom 4354 wireless card support" +# depends on BCMDHD +# ---help--- +# This module adds support for wireless adapters based on +# Broadcom 4354 chipset. config BCM43455 bool "Broadcom 43455 wireless cards support" -- GitLab From 268f973df197de93dc4dc6f8ce8dbb34e6be113a Mon Sep 17 00:00:00 2001 From: GreyLeshy Date: Wed, 27 Jun 2018 21:47:12 +0300 Subject: [PATCH 245/528] arm64/configs: Add BCMDHD for devices (cherry picked from commit b207ef4f3d1de190a41c4c49d45be427adb05dd6) --- arch/arm64/configs/diffconfig/ivy_diffconfig | 6 ++++++ arch/arm64/configs/diffconfig/ivy_dsds_diffconfig | 6 ++++++ arch/arm64/configs/diffconfig/karin_diffconfig | 6 ++++++ .../configs/diffconfig/karin_windy_diffconfig | 14 ++++++++++++++ arch/arm64/configs/diffconfig/satsuki_diffconfig | 6 ++++++ .../configs/diffconfig/satsuki_dsds_diffconfig | 6 ++++++ arch/arm64/configs/diffconfig/sumire_diffconfig | 6 ++++++ .../configs/diffconfig/sumire_dsds_diffconfig | 6 ++++++ arch/arm64/configs/diffconfig/suzuran_diffconfig | 5 +++++ arch/arm64/configs/kitakami_ivy_defconfig | 2 -- arch/arm64/configs/kitakami_karin_defconfig | 3 +-- arch/arm64/configs/kitakami_karin_windy_defconfig | 2 -- arch/arm64/configs/kitakami_sumire_defconfig | 6 ++---- 13 files changed, 64 insertions(+), 10 deletions(-) diff --git a/arch/arm64/configs/diffconfig/ivy_diffconfig b/arch/arm64/configs/diffconfig/ivy_diffconfig index 178a4fa90905..9371a74cd0d6 100644 --- a/arch/arm64/configs/diffconfig/ivy_diffconfig +++ b/arch/arm64/configs/diffconfig/ivy_diffconfig @@ -16,3 +16,9 @@ CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y # CONFIG_CNSS is not set # CONFIG_CNSS_PCI is not set +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig b/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig index a6bfe8cdb107..8d58fc97a159 100644 --- a/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig +++ b/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig @@ -14,3 +14,9 @@ CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y # CONFIG_CNSS is not set # CONFIG_CNSS_PCI is not set +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/karin_diffconfig b/arch/arm64/configs/diffconfig/karin_diffconfig index 5db93b663037..8a7470dfc1e1 100644 --- a/arch/arm64/configs/diffconfig/karin_diffconfig +++ b/arch/arm64/configs/diffconfig/karin_diffconfig @@ -9,3 +9,9 @@ CONFIG_PLUG_DET_TH_MID=y CONFIG_TOUCHSCREEN_MAXIM_STI=y # CONFIG_CNSS is not set # CONFIG_CNSS_PCI is not set +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/karin_windy_diffconfig b/arch/arm64/configs/diffconfig/karin_windy_diffconfig index dbab55d34f79..df80509fa4be 100644 --- a/arch/arm64/configs/diffconfig/karin_windy_diffconfig +++ b/arch/arm64/configs/diffconfig/karin_windy_diffconfig @@ -8,3 +8,17 @@ CONFIG_NFC_PN547=y CONFIG_TOUCHSCREEN_MAXIM_STI=y # CONFIG_CNSS is not set # CONFIG_CNSS_PCI is not set +<<<<<<< HEAD +======= +# CONFIG_ANDROID_LOW_MEMORY_KILLER is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER_STATS is not set +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +>>>>>>> b207ef4f3d1d (arm64/configs: Add BCMDHD for devices) diff --git a/arch/arm64/configs/diffconfig/satsuki_diffconfig b/arch/arm64/configs/diffconfig/satsuki_diffconfig index 26e4d064abe6..8d9e3caf9267 100644 --- a/arch/arm64/configs/diffconfig/satsuki_diffconfig +++ b/arch/arm64/configs/diffconfig/satsuki_diffconfig @@ -18,3 +18,9 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/satsuki_dsds_diffconfig b/arch/arm64/configs/diffconfig/satsuki_dsds_diffconfig index d207ba2dff99..09fab20f298d 100644 --- a/arch/arm64/configs/diffconfig/satsuki_dsds_diffconfig +++ b/arch/arm64/configs/diffconfig/satsuki_dsds_diffconfig @@ -16,3 +16,9 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/sumire_diffconfig b/arch/arm64/configs/diffconfig/sumire_diffconfig index 4247ee48d540..2334f67a80a2 100644 --- a/arch/arm64/configs/diffconfig/sumire_diffconfig +++ b/arch/arm64/configs/diffconfig/sumire_diffconfig @@ -18,3 +18,9 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/sumire_dsds_diffconfig b/arch/arm64/configs/diffconfig/sumire_dsds_diffconfig index 4b3398f1adc9..4cdc5601ce29 100644 --- a/arch/arm64/configs/diffconfig/sumire_dsds_diffconfig +++ b/arch/arm64/configs/diffconfig/sumire_dsds_diffconfig @@ -14,3 +14,9 @@ CONFIG_LZ4_DECOMPRESS=y CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/suzuran_diffconfig b/arch/arm64/configs/diffconfig/suzuran_diffconfig index c24925483d17..27244563419e 100644 --- a/arch/arm64/configs/diffconfig/suzuran_diffconfig +++ b/arch/arm64/configs/diffconfig/suzuran_diffconfig @@ -15,4 +15,9 @@ CONFIG_LZ4_DECOMPRESS=y CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y +CONFIG_BCMDHD_BCM43455=y # CONFIG_BCMDHD_PCIE is not set +CONFIG_BCMDHD=y +CONFIG_BCM43455=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/kitakami_ivy_defconfig b/arch/arm64/configs/kitakami_ivy_defconfig index dfb6fd7331f0..548a432ac2ce 100644 --- a/arch/arm64/configs/kitakami_ivy_defconfig +++ b/arch/arm64/configs/kitakami_ivy_defconfig @@ -270,8 +270,6 @@ CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y CONFIG_SOMC_WIFI_CONTROL=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=y -CONFIG_BCMDHD_BCM4356=y -CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD=y CONFIG_BCM4356=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" diff --git a/arch/arm64/configs/kitakami_karin_defconfig b/arch/arm64/configs/kitakami_karin_defconfig index b2c64ff0381e..4e9eeac476fe 100644 --- a/arch/arm64/configs/kitakami_karin_defconfig +++ b/arch/arm64/configs/kitakami_karin_defconfig @@ -266,9 +266,8 @@ CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y CONFIG_SOMC_WIFI_CONTROL=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=y +CONFIG_BCMDHD=y CONFIG_BCM4356=y -CONFIG_BCMDHD_BCM4356=y -CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" CONFIG_CLD_LL_CORE=y diff --git a/arch/arm64/configs/kitakami_karin_windy_defconfig b/arch/arm64/configs/kitakami_karin_windy_defconfig index 022175f13bee..f96f41e7a804 100644 --- a/arch/arm64/configs/kitakami_karin_windy_defconfig +++ b/arch/arm64/configs/kitakami_karin_windy_defconfig @@ -268,8 +268,6 @@ CONFIG_ATH_CARDS=y CONFIG_WIL6210=y CONFIG_BCMDHD=y CONFIG_BCM4356=y -CONFIG_BCMDHD_BCM4356=y -CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" CONFIG_CLD_LL_CORE=y diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index da865d48c753..234a63d726cf 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -282,12 +282,10 @@ CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y CONFIG_SOMC_WIFI_CONTROL=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCM4356=y CONFIG_BCMDHD_BCM4356=y CONFIG_BCMDHD_PCIE=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD=y +CONFIG_BCM4356=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y -- GitLab From 0eb198872728ba020e8af320f4027571010636e9 Mon Sep 17 00:00:00 2001 From: Bernhard Thoben Date: Wed, 24 Mar 2021 22:10:39 +0100 Subject: [PATCH 246/528] arm64/configs: Update and little cleanup of kitakami_suzuran_defconfig - This matches the latest changes in kernel. Change-Id: Id7b67ef7c4b5be7e7761880ea92e1a797fea2775 --- arch/arm64/configs/kitakami_suzuran_defconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/configs/kitakami_suzuran_defconfig b/arch/arm64/configs/kitakami_suzuran_defconfig index 6682cb8f1a00..15e660cc6a8e 100644 --- a/arch/arm64/configs/kitakami_suzuran_defconfig +++ b/arch/arm64/configs/kitakami_suzuran_defconfig @@ -279,10 +279,11 @@ CONFIG_BROADCOM_WIFI_RESERVED_MEM=y CONFIG_SOMC_WIFI_CONTROL=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=y +CONFIG_BCMDHD=y +CONFIG_BCM43455=y +CONFIG_BCMDHD_BCM43455=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_BCMDHD_SUZURAN=y -CONFIG_BCM43455=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y @@ -562,7 +563,6 @@ CONFIG_IOMMU_FORCE_4K_MAPPINGS=y CONFIG_DEVFREQ_SPDM=y CONFIG_PWM=y CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y CONFIG_GENERIC_PHY=y CONFIG_MSM_EVENT_TIMER=y -- GitLab From 98c936a7428551d354810ad91388a005ec515cdf Mon Sep 17 00:00:00 2001 From: Mike B Date: Fri, 26 Mar 2021 23:02:23 +0100 Subject: [PATCH 247/528] ARM: dts: msm8994 kitakami: lower backlight value --- arch/arm/boot/dts/qcom/msm8994-kitakami_ivy_common.dtsi | 2 +- arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_common.dtsi | 2 +- arch/arm/boot/dts/qcom/msm8994-kitakami_sumire_common.dtsi | 2 +- arch/arm/boot/dts/qcom/msm8994-kitakami_suzuran_common.dtsi | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_ivy_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_ivy_common.dtsi index fdad49660323..5d6bbdb7e6c4 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_ivy_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_ivy_common.dtsi @@ -565,7 +565,7 @@ qcom,leds@d800 { qcom,fs-curr-ua = <24000>; somc,calc-curr; - somc,init-br = <800>; + somc,init-br = <128>; somc-s1,br-power-save = <131>; qcom,led-strings-list = [00 01]; }; diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_common.dtsi index bd016fa6094f..a3de6d12f6b6 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_common.dtsi @@ -887,7 +887,7 @@ qcom,ilim-ma = <660>; qcom,fs-curr-ua = <24000>; somc,calc-curr; - somc,init-br = <800>; + somc,init-br = <128>; somc-s1,br-power-save = <131>; qcom,led-strings-list = [00 01 02]; }; diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_sumire_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_sumire_common.dtsi index 6c090e1d1aca..b9a03477c258 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_sumire_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_sumire_common.dtsi @@ -868,7 +868,7 @@ qcom,ilim-ma = <660>; qcom,fs-curr-ua = <24000>; somc,calc-curr; - somc,init-br = <800>; + somc,init-br = <128>; somc-s1,br-power-save = <131>; qcom,led-strings-list = [00 01]; }; diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_suzuran_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_suzuran_common.dtsi index dd1ee18df8c6..5a61ab6365e9 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_suzuran_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_suzuran_common.dtsi @@ -883,7 +883,7 @@ qcom,ilim-ma = <660>; qcom,fs-curr-ua = <25000>; somc,bl-scale-enabled; - somc,init-br = <800>; + somc,init-br = <128>; somc-s1,br-power-save = <131>; qcom,led-strings-list = [00 01]; }; -- GitLab From de4039242d9b3f2b1cf45e67817aa7cbeb016405 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Thu, 19 May 2016 03:58:48 +0300 Subject: [PATCH 248/528] video: mdss: Fix dual-DSI issue in LiveDisplay * The second controller won't have it's own framebuffer, so don't dereference a NULL pointer. Change-Id: I0cacbd0768a6a0f8e2ed934a8263aa75265f42b1 --- drivers/video/msm/mdss/mdss_livedisplay.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/video/msm/mdss/mdss_livedisplay.c b/drivers/video/msm/mdss/mdss_livedisplay.c index 9537471115e2..6fcc3149351d 100644 --- a/drivers/video/msm/mdss/mdss_livedisplay.c +++ b/drivers/video/msm/mdss/mdss_livedisplay.c @@ -179,6 +179,9 @@ static void mdss_livedisplay_worker(struct work_struct *work) if (mlc == NULL) return; + if (mlc->mfd == NULL) + return; + ctrl_pdata = get_ctrl(mlc->mfd); if (ctrl_pdata == NULL) return; -- GitLab From 60ca23ecbad7a83260c2cd364a11087645a903e5 Mon Sep 17 00:00:00 2001 From: Joel16 Date: Tue, 5 May 2020 12:15:45 -0400 Subject: [PATCH 249/528] satsuki: apply sdcard fix for dualsim variants --- .../boot/dts/qcom/msm8994-kitakami_r2_common.dtsi | 1 + .../dts/qcom/msm8994-kitakami_satsuki_generic.dtsi | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_r2_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_r2_common.dtsi index 28c758aeb546..133d2a423ca7 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_r2_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_r2_common.dtsi @@ -40,6 +40,7 @@ vdd_ana-supply = <&pm8994_l32>; vdd_io-supply = <&pm8994_l32>; fpc,use_fpc2050 = <1>; + fpc,enable-wakeup = <1>; spi-max-frequency = <4800000>; spi-qup-id = <1>; diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_generic.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_generic.dtsi index ecd18db6504d..789a9e5a3771 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_generic.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_generic.dtsi @@ -37,6 +37,18 @@ pinctrl-1 = <&msm_gpio_29_nfc_sus &msm_gpio_30_sus>; }; }; + + sim_detect { + compatible = "sim-detect"; + interrupt-parent = <&msm_gpio>; + interrupts = <52 0>; + + sim2_det { + label = "sim2-detection"; + gpios = <&msm_gpio 52 0x0>; + debounce-interval = <10>; + }; + }; }; &pm8994_gpios { -- GitLab From d74d26c3b8820735d608beec21ff2c7a0cef7464 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 1 May 2021 17:46:23 +0200 Subject: [PATCH 250/528] fix-ups tbd Change-Id: I8fc1fee0bfa936c02632f46111aa6d1eef950465 --- Makefile | 41 ++- .../configs/diffconfig/karin_windy_diffconfig | 3 - .../configs/kitakami_karin_windy_defconfig | 2 + arch/arm64/configs/kitakami_sumire_defconfig | 7 +- arch/arm64/mm/mmap.c | 3 - drivers/net/wireless/bcmdhd_bcm43455/Kconfig | 4 +- drivers/net/wireless/bcmdhd_bcm4356/Kconfig | 16 +- drivers/net/wireless/somcwifictrl/somc_wifi.c | 336 ++++++++++++++++-- net/xfrm/xfrm_user.c | 8 - scripts/dtc/dtc-lexer.lex.c_shipped | 2 +- security/keys/key.c | 10 - 11 files changed, 359 insertions(+), 73 deletions(-) diff --git a/Makefile b/Makefile index e8ef2f1bf0c6..73bcac115ea7 100644 --- a/Makefile +++ b/Makefile @@ -347,7 +347,7 @@ AFLAGS_MODULE = LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = -CFLAGS_GCOV = -fprofile-arcs -ftest-coverage +CFLAGS_GCOV = -fprofile-arcs -ftest-coverage -fno-tree-loop-im # Use USERINCLUDE when you must reference the UAPI directories only. @@ -407,8 +407,9 @@ export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_ve # Files to ignore in find ... statements -RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \ - -o -name .pc -o -name .hg -o -name .git \) -prune -o +export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ + -name CVS -o -name .pc -o -name .hg -o -name .git \) \ + -prune -o export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ --exclude CVS --exclude .pc --exclude .hg --exclude .git @@ -573,11 +574,26 @@ endif # $(dot-config) all: vmlinux ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE -KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) +KBUILD_CFLAGS += -Os else -KBUILD_CFLAGS += -O2 +KBUILD_CFLAGS += -finline-functions -O2 endif +# Disable all maybe-uninitialized warnings +KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) + +# Disable unused-constant-variable warnings +KBUILD_CFLAGS += $(call cc-disable-warning,unused-const-variable,) + +# Disable format-truncation warnings +KBUILD_CFLAGS += $(call cc-disable-warning,format-truncation,) + +# Needed to unbreak GCC 7.x and above +KBUILD_CFLAGS += $(call cc-option,-fno-store-merging,) + +# Tell gcc to never replace conditional load with a non-conditional one +KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) + include $(srctree)/arch/$(SRCARCH)/Makefile ifdef CONFIG_READABLE_ASM @@ -596,14 +612,14 @@ endif # Handle stack protector mode. ifdef CONFIG_CC_STACKPROTECTOR_REGULAR - stackp-flag := -fstack-protector + stackp-flag := -fstack-protector --param ssp-buffer-size=4 ifeq ($(call cc-option, $(stackp-flag)),) $(warning Cannot use CONFIG_CC_STACKPROTECTOR_REGULAR: \ -fstack-protector not supported by compiler) endif else ifdef CONFIG_CC_STACKPROTECTOR_STRONG - stackp-flag := -fstack-protector-strong + stackp-flag := -fstack-protector-strong --param ssp-buffer-size=4 ifeq ($(call cc-option, $(stackp-flag)),) $(warning Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: \ -fstack-protector-strong not supported by compiler) @@ -615,9 +631,10 @@ endif endif KBUILD_CFLAGS += $(stackp-flag) -# This warning generated too much noise in a regular build. -# Use make W=1 to enable this warning (see scripts/Makefile.build) +# These warnings generated too much noise in a regular build. +# Use make W=1 to enable them (see scripts/Makefile.build) KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) +KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) ifdef CONFIG_FRAME_POINTER KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls @@ -676,6 +693,9 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign) # disable invalid "can't wrap" optimizations for signed / pointers KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) +# Make sure -fstack-check isn't enabled (like gentoo apparently did) +KBUILD_CFLAGS += $(call cc-option,-fno-stack-check,) + # conserve stack if available KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) @@ -683,8 +703,9 @@ KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) KBUILD_ARFLAGS := $(call ar-option,D) # check for 'asm goto' -ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y) +ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y) KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO + KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO endif # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments diff --git a/arch/arm64/configs/diffconfig/karin_windy_diffconfig b/arch/arm64/configs/diffconfig/karin_windy_diffconfig index df80509fa4be..c8b5359bd8e8 100644 --- a/arch/arm64/configs/diffconfig/karin_windy_diffconfig +++ b/arch/arm64/configs/diffconfig/karin_windy_diffconfig @@ -8,8 +8,6 @@ CONFIG_NFC_PN547=y CONFIG_TOUCHSCREEN_MAXIM_STI=y # CONFIG_CNSS is not set # CONFIG_CNSS_PCI is not set -<<<<<<< HEAD -======= # CONFIG_ANDROID_LOW_MEMORY_KILLER is not set # CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG is not set # CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES is not set @@ -21,4 +19,3 @@ CONFIG_BCMDHD=y CONFIG_BCM4356=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" ->>>>>>> b207ef4f3d1d (arm64/configs: Add BCMDHD for devices) diff --git a/arch/arm64/configs/kitakami_karin_windy_defconfig b/arch/arm64/configs/kitakami_karin_windy_defconfig index f96f41e7a804..022175f13bee 100644 --- a/arch/arm64/configs/kitakami_karin_windy_defconfig +++ b/arch/arm64/configs/kitakami_karin_windy_defconfig @@ -268,6 +268,8 @@ CONFIG_ATH_CARDS=y CONFIG_WIL6210=y CONFIG_BCMDHD=y CONFIG_BCM4356=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" CONFIG_CLD_LL_CORE=y diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index 234a63d726cf..ea5c0d24cbc9 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -51,7 +51,7 @@ CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_ARMV7_COMPAT=y -# CONFIG_KSM is not set +CONFIG_KSM=y CONFIG_SWAP_CONSIDER_CMA_FREE=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_ZSMALLOC=y @@ -276,16 +276,17 @@ CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y CONFIG_BROADCOM_WIFI_RESERVED_MEM=y CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y CONFIG_SOMC_WIFI_CONTROL=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=y CONFIG_BCMDHD_BCM4356=y -CONFIG_BCMDHD_PCIE=y CONFIG_BCMDHD=y +CONFIG_BCMDHD_PCIE=y CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c index c67ab2c60dc6..d3cfc2df5de3 100644 --- a/arch/arm64/mm/mmap.c +++ b/arch/arm64/mm/mmap.c @@ -59,9 +59,6 @@ static unsigned long mmap_rnd(void) #endif rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1); } - if (current->flags & PF_RANDOMIZE) - rnd = (long)get_random_int() & STACK_RND_MASK; - return rnd << PAGE_SHIFT; } diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig index 81fd573fe9b5..626e47e6d214 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig @@ -44,14 +44,14 @@ endchoice config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" + default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" + default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig index 599f99af9cd4..a89ca15ef8f0 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -config BCM4354 - bool "Broadcom 4354 wireless cards support" - depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) - ---help--- - This module adds support for wireless adapters based on - Broadcom 4354 chipset. +#config BCM4354 +# bool "Broadcom 4354 wireless cards support" +# depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) +# ---help--- +# This module adds support for wireless adapters based on +# Broadcom 4354 chipset. config BCM4356 bool "Broadcom 4356 wireless cards support" @@ -42,14 +42,14 @@ config BCM4356 config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" + default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" + default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/somcwifictrl/somc_wifi.c b/drivers/net/wireless/somcwifictrl/somc_wifi.c index f60315e70057..8b71de21a562 100644 --- a/drivers/net/wireless/somcwifictrl/somc_wifi.c +++ b/drivers/net/wireless/somcwifictrl/somc_wifi.c @@ -1,7 +1,3 @@ -/* - * drivers/net/wireless/somcwifictrl/somc_wifi.c - * - */ /* * Copyright (C) 2015 Sony Mobile Communications Inc. * @@ -10,32 +6,175 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include #include #include +#ifdef CONFIG_BCMDHD_PCIE #include +#endif /* CONFIG_BCMDHD_PCIE */ #include #include #include #include -#include - +#include #include "dhd_custom_memprealloc.h" +#if defined(CONFIG_MACH_SONY_SHINANO) +#include +#include +#include <../drivers/mmc/host/msm_sdcc.h> +#endif + +static char *intf_macaddr = NULL; +static struct mmc_host *wlan_mmc_host; + struct bcmdhd_platform_data { struct platform_device *pdev; struct pinctrl *pinctrl; struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; unsigned int wlan_reg_on; +#ifdef CONFIG_BCMDHD_PCIE unsigned int pci_number; +#endif /* CONFIG_BCMDHD_PCIE */ }; static struct bcmdhd_platform_data *bcmdhd_data; -static struct mmc_host *wlan_mmc_host; +void somc_wifi_mmc_host_register(struct mmc_host *host) +{ + wlan_mmc_host = host; +} + +#if !defined(CONFIG_MACH_SONY_SHINANO) +int somc_wifi_set_power(int on) +{ + gpio_set_value(bcmdhd_data->wlan_reg_on, on); + return 0; +} + +int somc_wifi_set_carddetect(int present) +{ +#ifdef CONFIG_BCMDHD_PCIE + int ret = 0; + if (present) + ret = msm_pcie_enumerate(bcmdhd_data->pci_number); + return ret; +#else + if (wlan_mmc_host) + mmc_detect_change(wlan_mmc_host, 0); + return 0; +#endif /* CONFIG_BCMDHD_PCIE */ +} +#else +#define WIFI_POWER_PMIC_GPIO 18 +#define WIFI_IRQ_GPIO 67 + +static unsigned int g_wifi_detect; +static void *sdc_dev; +void (*sdc_status_cb)(int card_present, void *dev); +static void *wifi_mmc_host; +static struct regulator *wifi_batfet; +static int batfet_ena; +extern void sdio_ctrl_power(struct mmc_host *card, bool onoff); + +int wcf_status_register(void (*cb)(int card_present, void *dev), void *dev) +{ + pr_info("%s\n", __func__); + + if (sdc_status_cb) + return -EINVAL; + + sdc_status_cb = cb; + sdc_dev = dev; + wifi_mmc_host = ((struct msmsdcc_host *)dev)->mmc; + + return 0; +} + +unsigned int wcf_status(struct device *dev) +{ + pr_info("%s: wifi_detect = %d\n", __func__, g_wifi_detect); + return g_wifi_detect; +} + +static int somc_wifi_set_reset(int on) +{ + return 0; +} + +int somc_wifi_set_power(int on) +{ + int gpio = qpnp_pin_map("pm8941-gpio", WIFI_POWER_PMIC_GPIO); + int ret; + + if (!wifi_batfet) { + wifi_batfet = regulator_get(NULL, "batfet"); + if (IS_ERR_OR_NULL(wifi_batfet)) { + printk(KERN_ERR "unable to get batfet reg. rc=%d\n", + PTR_RET(wifi_batfet)); + wifi_batfet = NULL; + } + } + if (on) { + if (!batfet_ena && wifi_batfet) { + ret = regulator_enable(wifi_batfet); + if (ret != 0) + pr_warn("%s: Can't enable batfet regulator!\n", + __func__); + batfet_ena = 1; + } + } + gpio_set_value(gpio, on); + if (!on) { + if (batfet_ena && wifi_batfet) { + regulator_disable(wifi_batfet); + batfet_ena = 0; + } + } + + sdio_ctrl_power((struct mmc_host *)wifi_mmc_host, on); + return 0; + +} + +int somc_wifi_set_carddetect(int present) +{ + g_wifi_detect = present; + + if (sdc_status_cb) + sdc_status_cb(present, sdc_dev); + else + printk(KERN_WARNING "%s: Nobody to notify\n", __func__); + return 0; +} +#endif /* CONFIG_MACH_SONY_SHINANO */ + +static ssize_t macaddr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s", intf_macaddr); +} + +static ssize_t macaddr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return snprintf(intf_macaddr, count, "%s\n", buf); +} + +DEVICE_ATTR(macaddr, 0644, macaddr_show, macaddr_store); + +static struct attribute *wifi_attrs[] = { + &dev_attr_macaddr.attr, + NULL +}; + +static struct attribute_group wifi_attr_grp = { + .attrs = wifi_attrs, +}; int somc_wifi_init(struct platform_device *pdev) { @@ -102,6 +241,7 @@ int somc_wifi_init(struct platform_device *pdev) goto err_gpio; } +#ifdef CONFIG_BCMDHD_PCIE ret = of_property_read_u32(pdev->dev.of_node, "wlan-pci-number", &bcmdhd_data->pci_number); if (ret < 0) { @@ -109,11 +249,20 @@ int somc_wifi_init(struct platform_device *pdev) __func__, ret, bcmdhd_data->pci_number); goto err_gpio_request; } +#endif /* CONFIG_BCMDHD_PCIE */ + + intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); + if (sysfs_create_group(&pdev->dev.kobj, &wifi_attr_grp) < 0) { + pr_err("%s: Unable to create sysfs\n", __func__); + kfree(intf_macaddr); + } return 0; +#ifdef CONFIG_BCMDHD_PCIE err_gpio_request: gpio_free(bcmdhd_data->wlan_reg_on); +#endif /* CONFIG_BCMDHD_PCIE */ err_gpio: ret_sus = pinctrl_select_state(bcmdhd_data->pinctrl, bcmdhd_data->gpio_state_suspend); @@ -145,41 +294,178 @@ void somc_wifi_deinit(struct platform_device *pdev) } EXPORT_SYMBOL(somc_wifi_deinit); -void somc_wifi_mmc_host_register(struct mmc_host *host) +#define ETHER_ADDR_LEN 6 + +static inline int xdigit (char c) { - wlan_mmc_host = host; + unsigned d; + + d = (unsigned)(c-'0'); + if (d < 10) + return (int)d; + d = (unsigned)(c-'a'); + if (d < 6) + return (int)(10+d); + d = (unsigned)(c-'A'); + if (d < 6) + return (int)(10+d); + return -1; } -int somc_wifi_set_power(int on) +struct ether_addr { + unsigned char ether_addr_octet[ETHER_ADDR_LEN]; +} __attribute__((__packed__)); + +struct ether_addr * +ether_aton_r (const char *asc, struct ether_addr * addr) { - gpio_set_value(bcmdhd_data->wlan_reg_on, on); - return 0; + int i, val0, val1; + + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + val0 = xdigit(*asc); + asc++; + if (val0 < 0) + return NULL; + + val1 = xdigit(*asc); + asc++; + if (val1 < 0) + return NULL; + + addr->ether_addr_octet[i] = (unsigned char)((val0 << 4) + val1); + + if (i < ETHER_ADDR_LEN - 1) { + if (*asc != ':') + return NULL; + asc++; + } + } + + if (*asc != '\0') + return NULL; + + return addr; } -#ifdef CONFIG_BCMDHD_PCIE -int somc_wifi_set_carddetect(int present) +struct ether_addr * ether_aton (const char *asc) { - int ret = 0; - if (present) - ret = msm_pcie_enumerate_locked(bcmdhd_data->pci_number); - return ret; + static struct ether_addr addr; + return ether_aton_r(asc, &addr); } -#else /* CONFIG_BCMDHD_PCIE */ -int somc_wifi_set_carddetect(int present) + +static int somc_wifi_get_mac_addr(unsigned char *buf) { - if (wlan_mmc_host) - mmc_detect_change(wlan_mmc_host, 0); + int ret = 0; + + char macasc[128] = {0,}; + uint rand_mac; + static unsigned char mymac[ETHER_ADDR_LEN] = {0,}; + const unsigned char nullmac[ETHER_ADDR_LEN] = {0,}; + + if (buf == NULL) + return -EAGAIN; + + memset(buf, 0x00, ETHER_ADDR_LEN); + + if (intf_macaddr != NULL) { + unsigned char* macbin; + struct ether_addr* convmac = ether_aton( intf_macaddr ); + + if (convmac == NULL) { + pr_err("%s: Invalid Mac Address Format %s\n", + __FUNCTION__, macasc ); + goto random_mac; + } + + macbin = convmac->ether_addr_octet; + + pr_info("%s: READ MAC ADDRESS %02X:%02X:%02X:%02X:%02X:%02X\n", + __FUNCTION__, + macbin[0], macbin[1], macbin[2], + macbin[3], macbin[4], macbin[5]); + + memcpy(buf, macbin, ETHER_ADDR_LEN); + } + + return ret; + +random_mac: + + pr_debug("%s: %p\n", __func__, buf); + + if (memcmp( mymac, nullmac, ETHER_ADDR_LEN) != 0) { + /* Mac displayed from UI is never updated.. + So, mac obtained on initial time is used */ + memcpy(buf, mymac, ETHER_ADDR_LEN); + return 0; + } + + prandom_seed((uint)jiffies); + rand_mac = prandom_u32(); + buf[0] = 0x00; + buf[1] = 0x90; + buf[2] = 0x4c; + buf[3] = (unsigned char)rand_mac; + buf[4] = (unsigned char)(rand_mac >> 8); + buf[5] = (unsigned char)(rand_mac >> 16); + + memcpy(mymac, buf, 6); + + pr_info("[%s] Exiting. MAC %02X:%02X:%02X:%02X:%02X:%02X\n", + __FUNCTION__, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5] ); + return 0; } -#endif /* CONFIG_BCMDHD_PCIE */ struct wifi_platform_data somc_wifi_control = { .set_power = somc_wifi_set_power, +#if defined(CONFIG_MACH_SONY_SHINANO) + .set_reset = somc_wifi_set_reset, +#endif /* CONFIG_MACH_SONY_SHINANO */ .set_carddetect = somc_wifi_set_carddetect, -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM .mem_prealloc = dhd_wlan_mem_prealloc, -#endif + .get_mac_addr = somc_wifi_get_mac_addr, }; + EXPORT_SYMBOL(somc_wifi_control); +#if defined(CONFIG_MACH_SONY_SHINANO) +static struct resource somc_wifi_resources[] = { + [0] = { + .name = "bcmdhd_wlan_irq", + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | + IORESOURCE_IRQ_SHAREABLE, + }, +}; + +static struct platform_device somc_wifi = { + .name = "bcmdhd_wlan", + .id = -1, + .num_resources = ARRAY_SIZE(somc_wifi_resources), + .resource = somc_wifi_resources, + .dev = { + .platform_data = &somc_wifi_control, + }, +}; + +static int __init somc_wifi_init_on_boot(void) +{ + somc_wifi.resource->start = gpio_to_irq(WIFI_IRQ_GPIO); + somc_wifi.resource->end = gpio_to_irq(WIFI_IRQ_GPIO); + platform_device_register(&somc_wifi); + + intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); + if (sysfs_create_group(&somc_wifi.dev.kobj, &wifi_attr_grp) < 0) { + pr_err("%s: Unable to create sysfs\n", __func__); + kfree(intf_macaddr); + } + return 0; +} + +device_initcall(somc_wifi_init_on_boot); +#endif /* CONFIG_MACH_SONY_SHINANO */ + MODULE_LICENSE("GPL v2"); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c9318567d5a3..4bf8f2c06d2c 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -400,9 +400,6 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) return -EINVAL; - if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) - return -EINVAL; - return 0; } @@ -862,11 +859,6 @@ static int copy_to_user_state_extra(struct xfrm_state *x, } if (x->security) ret = copy_sec_ctx(x->security, skb); - if (x->props.output_mark) { - ret = nla_put_u32(skb, XFRMA_OUTPUT_MARK, x->props.output_mark); - if (ret) - goto out; - } out: return ret; } diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index 2d30f41778b7..d0eb405cb811 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -637,7 +637,7 @@ char *yytext; #include "srcpos.h" #include "dtc-parser.tab.h" -YYLTYPE yylloc; +extern YYLTYPE yylloc; /* CAUTION: this will stop working if we ever use yyless() or yyunput() */ #define YY_USER_ACTION \ diff --git a/security/keys/key.c b/security/keys/key.c index c0d553d032c2..248c2e731375 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -909,16 +909,6 @@ error: } } - key = key_ref_to_ptr(key_ref); - if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) { - ret = wait_for_key_construction(key, true); - if (ret < 0) { - key_ref_put(key_ref); - key_ref = ERR_PTR(ret); - goto error_free_prep; - } - } - key_ref = __key_update(key_ref, &prep); goto error_free_prep; } -- GitLab From 8ae2f29c23ca292d6d456a2edc33640606c2f19f Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 1 May 2021 20:06:16 +0200 Subject: [PATCH 251/528] Merge rest of remotes/acherepkov/DEV_rc13 drivers/net/wireless/ --- drivers/net/wireless/bcmdhd_bcm43455/Kconfig | 16 +- drivers/net/wireless/bcmdhd_bcm4356/Kconfig | 16 +- drivers/net/wireless/somcwifictrl/somc_wifi.c | 336 ++---------------- drivers/net/wireless/ti/wl1251/acx.c | 1 - drivers/net/wireless/ti/wl1251/cmd.c | 1 - drivers/net/wireless/ti/wl1251/spi.c | 3 +- drivers/net/wireless/ti/wlcore/spi.c | 3 +- drivers/net/wireless/wcnss/wcnss_wlan.c | 1 - 8 files changed, 43 insertions(+), 334 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig index 626e47e6d214..37e9a097bd72 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -#config BCM4354 -# bool "Broadcom 4354 wireless card support" -# depends on BCMDHD -# ---help--- -# This module adds support for wireless adapters based on -# Broadcom 4354 chipset. +config BCM4354 + bool "Broadcom 4354 wireless card support" + depends on BCMDHD + ---help--- + This module adds support for wireless adapters based on + Broadcom 4354 chipset. config BCM43455 bool "Broadcom 43455 wireless cards support" @@ -44,14 +44,14 @@ endchoice config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" + default "/system/etc/firmware/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" + default "/system/etc/wifi/bcmdhd.cal" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig index a89ca15ef8f0..599f99af9cd4 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -#config BCM4354 -# bool "Broadcom 4354 wireless cards support" -# depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) -# ---help--- -# This module adds support for wireless adapters based on -# Broadcom 4354 chipset. +config BCM4354 + bool "Broadcom 4354 wireless cards support" + depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) + ---help--- + This module adds support for wireless adapters based on + Broadcom 4354 chipset. config BCM4356 bool "Broadcom 4356 wireless cards support" @@ -42,14 +42,14 @@ config BCM4356 config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" + default "/system/etc/firmware/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" + default "/system/etc/wifi/bcmdhd.cal" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/somcwifictrl/somc_wifi.c b/drivers/net/wireless/somcwifictrl/somc_wifi.c index 8b71de21a562..f60315e70057 100644 --- a/drivers/net/wireless/somcwifictrl/somc_wifi.c +++ b/drivers/net/wireless/somcwifictrl/somc_wifi.c @@ -1,3 +1,7 @@ +/* + * drivers/net/wireless/somcwifictrl/somc_wifi.c + * + */ /* * Copyright (C) 2015 Sony Mobile Communications Inc. * @@ -6,30 +10,19 @@ * published by the Free Software Foundation. */ #include -#include #include #include #include #include #include -#ifdef CONFIG_BCMDHD_PCIE #include -#endif /* CONFIG_BCMDHD_PCIE */ #include #include #include #include -#include -#include "dhd_custom_memprealloc.h" - -#if defined(CONFIG_MACH_SONY_SHINANO) -#include -#include -#include <../drivers/mmc/host/msm_sdcc.h> -#endif +#include -static char *intf_macaddr = NULL; -static struct mmc_host *wlan_mmc_host; +#include "dhd_custom_memprealloc.h" struct bcmdhd_platform_data { struct platform_device *pdev; @@ -37,144 +30,12 @@ struct bcmdhd_platform_data { struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; unsigned int wlan_reg_on; -#ifdef CONFIG_BCMDHD_PCIE unsigned int pci_number; -#endif /* CONFIG_BCMDHD_PCIE */ }; static struct bcmdhd_platform_data *bcmdhd_data; -void somc_wifi_mmc_host_register(struct mmc_host *host) -{ - wlan_mmc_host = host; -} - -#if !defined(CONFIG_MACH_SONY_SHINANO) -int somc_wifi_set_power(int on) -{ - gpio_set_value(bcmdhd_data->wlan_reg_on, on); - return 0; -} - -int somc_wifi_set_carddetect(int present) -{ -#ifdef CONFIG_BCMDHD_PCIE - int ret = 0; - if (present) - ret = msm_pcie_enumerate(bcmdhd_data->pci_number); - return ret; -#else - if (wlan_mmc_host) - mmc_detect_change(wlan_mmc_host, 0); - return 0; -#endif /* CONFIG_BCMDHD_PCIE */ -} -#else -#define WIFI_POWER_PMIC_GPIO 18 -#define WIFI_IRQ_GPIO 67 - -static unsigned int g_wifi_detect; -static void *sdc_dev; -void (*sdc_status_cb)(int card_present, void *dev); -static void *wifi_mmc_host; -static struct regulator *wifi_batfet; -static int batfet_ena; -extern void sdio_ctrl_power(struct mmc_host *card, bool onoff); - -int wcf_status_register(void (*cb)(int card_present, void *dev), void *dev) -{ - pr_info("%s\n", __func__); - - if (sdc_status_cb) - return -EINVAL; - - sdc_status_cb = cb; - sdc_dev = dev; - wifi_mmc_host = ((struct msmsdcc_host *)dev)->mmc; - - return 0; -} - -unsigned int wcf_status(struct device *dev) -{ - pr_info("%s: wifi_detect = %d\n", __func__, g_wifi_detect); - return g_wifi_detect; -} - -static int somc_wifi_set_reset(int on) -{ - return 0; -} - -int somc_wifi_set_power(int on) -{ - int gpio = qpnp_pin_map("pm8941-gpio", WIFI_POWER_PMIC_GPIO); - int ret; - - if (!wifi_batfet) { - wifi_batfet = regulator_get(NULL, "batfet"); - if (IS_ERR_OR_NULL(wifi_batfet)) { - printk(KERN_ERR "unable to get batfet reg. rc=%d\n", - PTR_RET(wifi_batfet)); - wifi_batfet = NULL; - } - } - if (on) { - if (!batfet_ena && wifi_batfet) { - ret = regulator_enable(wifi_batfet); - if (ret != 0) - pr_warn("%s: Can't enable batfet regulator!\n", - __func__); - batfet_ena = 1; - } - } - gpio_set_value(gpio, on); - if (!on) { - if (batfet_ena && wifi_batfet) { - regulator_disable(wifi_batfet); - batfet_ena = 0; - } - } - - sdio_ctrl_power((struct mmc_host *)wifi_mmc_host, on); - return 0; - -} - -int somc_wifi_set_carddetect(int present) -{ - g_wifi_detect = present; - - if (sdc_status_cb) - sdc_status_cb(present, sdc_dev); - else - printk(KERN_WARNING "%s: Nobody to notify\n", __func__); - return 0; -} -#endif /* CONFIG_MACH_SONY_SHINANO */ - -static ssize_t macaddr_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s", intf_macaddr); -} - -static ssize_t macaddr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return snprintf(intf_macaddr, count, "%s\n", buf); -} - -DEVICE_ATTR(macaddr, 0644, macaddr_show, macaddr_store); - -static struct attribute *wifi_attrs[] = { - &dev_attr_macaddr.attr, - NULL -}; - -static struct attribute_group wifi_attr_grp = { - .attrs = wifi_attrs, -}; +static struct mmc_host *wlan_mmc_host; int somc_wifi_init(struct platform_device *pdev) { @@ -241,7 +102,6 @@ int somc_wifi_init(struct platform_device *pdev) goto err_gpio; } -#ifdef CONFIG_BCMDHD_PCIE ret = of_property_read_u32(pdev->dev.of_node, "wlan-pci-number", &bcmdhd_data->pci_number); if (ret < 0) { @@ -249,20 +109,11 @@ int somc_wifi_init(struct platform_device *pdev) __func__, ret, bcmdhd_data->pci_number); goto err_gpio_request; } -#endif /* CONFIG_BCMDHD_PCIE */ - - intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); - if (sysfs_create_group(&pdev->dev.kobj, &wifi_attr_grp) < 0) { - pr_err("%s: Unable to create sysfs\n", __func__); - kfree(intf_macaddr); - } return 0; -#ifdef CONFIG_BCMDHD_PCIE err_gpio_request: gpio_free(bcmdhd_data->wlan_reg_on); -#endif /* CONFIG_BCMDHD_PCIE */ err_gpio: ret_sus = pinctrl_select_state(bcmdhd_data->pinctrl, bcmdhd_data->gpio_state_suspend); @@ -294,178 +145,41 @@ void somc_wifi_deinit(struct platform_device *pdev) } EXPORT_SYMBOL(somc_wifi_deinit); -#define ETHER_ADDR_LEN 6 - -static inline int xdigit (char c) -{ - unsigned d; - - d = (unsigned)(c-'0'); - if (d < 10) - return (int)d; - d = (unsigned)(c-'a'); - if (d < 6) - return (int)(10+d); - d = (unsigned)(c-'A'); - if (d < 6) - return (int)(10+d); - return -1; -} - -struct ether_addr { - unsigned char ether_addr_octet[ETHER_ADDR_LEN]; -} __attribute__((__packed__)); - -struct ether_addr * -ether_aton_r (const char *asc, struct ether_addr * addr) +void somc_wifi_mmc_host_register(struct mmc_host *host) { - int i, val0, val1; - - for (i = 0; i < ETHER_ADDR_LEN; ++i) { - val0 = xdigit(*asc); - asc++; - if (val0 < 0) - return NULL; - - val1 = xdigit(*asc); - asc++; - if (val1 < 0) - return NULL; - - addr->ether_addr_octet[i] = (unsigned char)((val0 << 4) + val1); - - if (i < ETHER_ADDR_LEN - 1) { - if (*asc != ':') - return NULL; - asc++; - } - } - - if (*asc != '\0') - return NULL; - - return addr; + wlan_mmc_host = host; } -struct ether_addr * ether_aton (const char *asc) +int somc_wifi_set_power(int on) { - static struct ether_addr addr; - return ether_aton_r(asc, &addr); + gpio_set_value(bcmdhd_data->wlan_reg_on, on); + return 0; } -static int somc_wifi_get_mac_addr(unsigned char *buf) +#ifdef CONFIG_BCMDHD_PCIE +int somc_wifi_set_carddetect(int present) { int ret = 0; - - char macasc[128] = {0,}; - uint rand_mac; - static unsigned char mymac[ETHER_ADDR_LEN] = {0,}; - const unsigned char nullmac[ETHER_ADDR_LEN] = {0,}; - - if (buf == NULL) - return -EAGAIN; - - memset(buf, 0x00, ETHER_ADDR_LEN); - - if (intf_macaddr != NULL) { - unsigned char* macbin; - struct ether_addr* convmac = ether_aton( intf_macaddr ); - - if (convmac == NULL) { - pr_err("%s: Invalid Mac Address Format %s\n", - __FUNCTION__, macasc ); - goto random_mac; - } - - macbin = convmac->ether_addr_octet; - - pr_info("%s: READ MAC ADDRESS %02X:%02X:%02X:%02X:%02X:%02X\n", - __FUNCTION__, - macbin[0], macbin[1], macbin[2], - macbin[3], macbin[4], macbin[5]); - - memcpy(buf, macbin, ETHER_ADDR_LEN); - } - + if (present) + ret = msm_pcie_enumerate_locked(bcmdhd_data->pci_number); return ret; - -random_mac: - - pr_debug("%s: %p\n", __func__, buf); - - if (memcmp( mymac, nullmac, ETHER_ADDR_LEN) != 0) { - /* Mac displayed from UI is never updated.. - So, mac obtained on initial time is used */ - memcpy(buf, mymac, ETHER_ADDR_LEN); - return 0; - } - - prandom_seed((uint)jiffies); - rand_mac = prandom_u32(); - buf[0] = 0x00; - buf[1] = 0x90; - buf[2] = 0x4c; - buf[3] = (unsigned char)rand_mac; - buf[4] = (unsigned char)(rand_mac >> 8); - buf[5] = (unsigned char)(rand_mac >> 16); - - memcpy(mymac, buf, 6); - - pr_info("[%s] Exiting. MAC %02X:%02X:%02X:%02X:%02X:%02X\n", - __FUNCTION__, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5] ); - +} +#else /* CONFIG_BCMDHD_PCIE */ +int somc_wifi_set_carddetect(int present) +{ + if (wlan_mmc_host) + mmc_detect_change(wlan_mmc_host, 0); return 0; } +#endif /* CONFIG_BCMDHD_PCIE */ struct wifi_platform_data somc_wifi_control = { .set_power = somc_wifi_set_power, -#if defined(CONFIG_MACH_SONY_SHINANO) - .set_reset = somc_wifi_set_reset, -#endif /* CONFIG_MACH_SONY_SHINANO */ .set_carddetect = somc_wifi_set_carddetect, +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM .mem_prealloc = dhd_wlan_mem_prealloc, - .get_mac_addr = somc_wifi_get_mac_addr, +#endif }; - EXPORT_SYMBOL(somc_wifi_control); -#if defined(CONFIG_MACH_SONY_SHINANO) -static struct resource somc_wifi_resources[] = { - [0] = { - .name = "bcmdhd_wlan_irq", - .start = 0, - .end = 0, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | - IORESOURCE_IRQ_SHAREABLE, - }, -}; - -static struct platform_device somc_wifi = { - .name = "bcmdhd_wlan", - .id = -1, - .num_resources = ARRAY_SIZE(somc_wifi_resources), - .resource = somc_wifi_resources, - .dev = { - .platform_data = &somc_wifi_control, - }, -}; - -static int __init somc_wifi_init_on_boot(void) -{ - somc_wifi.resource->start = gpio_to_irq(WIFI_IRQ_GPIO); - somc_wifi.resource->end = gpio_to_irq(WIFI_IRQ_GPIO); - platform_device_register(&somc_wifi); - - intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); - if (sysfs_create_group(&somc_wifi.dev.kobj, &wifi_attr_grp) < 0) { - pr_err("%s: Unable to create sysfs\n", __func__); - kfree(intf_macaddr); - } - return 0; -} - -device_initcall(somc_wifi_init_on_boot); -#endif /* CONFIG_MACH_SONY_SHINANO */ - MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c index db6430c1a084..a0e6d54aa2b2 100644 --- a/drivers/net/wireless/ti/wl1251/acx.c +++ b/drivers/net/wireless/ti/wl1251/acx.c @@ -2,7 +2,6 @@ #include #include -#include #include "wl1251.h" #include "reg.h" diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c index 6822b845efc1..86c0c39abeb2 100644 --- a/drivers/net/wireless/ti/wl1251/cmd.c +++ b/drivers/net/wireless/ti/wl1251/cmd.c @@ -2,7 +2,6 @@ #include #include -#include #include "wl1251.h" #include "reg.h" diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 4c67c2f9ea71..c6e92848cd0e 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -119,8 +119,7 @@ static void wl1251_spi_wake(struct wl1251 *wl) crc[3] = cmd[6]; crc[4] = cmd[5]; - cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; - cmd[4] |= WSPI_INIT_CMD_END; + cmd[4] = crc7_be(0, crc, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END; t.tx_buf = cmd; t.len = WSPI_INIT_CMD_LEN; diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index bfb57e671034..8747da8fcdcb 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -154,8 +154,7 @@ static void wl12xx_spi_init(struct device *child) crc[3] = cmd[6]; crc[4] = cmd[5]; - cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; - cmd[4] |= WSPI_INIT_CMD_END; + cmd[4] = crc7_be(0, crc, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END; t.tx_buf = cmd; t.len = WSPI_INIT_CMD_LEN; diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index d4725d24f575..a05b2796e61c 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -1100,7 +1100,6 @@ int wcnss_get_mux_control(void) return 0; pmu_conf_reg = penv->msm_wcnss_base + PRONTO_PMU_OFFSET; - writel_relaxed(0, pmu_conf_reg); reg = readl_relaxed(pmu_conf_reg); reg |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP; writel_relaxed(reg, pmu_conf_reg); -- GitLab From 89b5ff2044ba87c24feecffca7f204d5e959b3a4 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 1 May 2021 20:36:51 +0200 Subject: [PATCH 252/528] net: wireless: add back xperiadev LA.BR.1.3.3_rb2.19 somcwifictl --- drivers/net/wireless/somcwifictrl/somc_wifi.c | 336 ++++++++++++++++-- 1 file changed, 311 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/somcwifictrl/somc_wifi.c b/drivers/net/wireless/somcwifictrl/somc_wifi.c index f60315e70057..8b71de21a562 100644 --- a/drivers/net/wireless/somcwifictrl/somc_wifi.c +++ b/drivers/net/wireless/somcwifictrl/somc_wifi.c @@ -1,7 +1,3 @@ -/* - * drivers/net/wireless/somcwifictrl/somc_wifi.c - * - */ /* * Copyright (C) 2015 Sony Mobile Communications Inc. * @@ -10,32 +6,175 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include #include #include +#ifdef CONFIG_BCMDHD_PCIE #include +#endif /* CONFIG_BCMDHD_PCIE */ #include #include #include #include -#include - +#include #include "dhd_custom_memprealloc.h" +#if defined(CONFIG_MACH_SONY_SHINANO) +#include +#include +#include <../drivers/mmc/host/msm_sdcc.h> +#endif + +static char *intf_macaddr = NULL; +static struct mmc_host *wlan_mmc_host; + struct bcmdhd_platform_data { struct platform_device *pdev; struct pinctrl *pinctrl; struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; unsigned int wlan_reg_on; +#ifdef CONFIG_BCMDHD_PCIE unsigned int pci_number; +#endif /* CONFIG_BCMDHD_PCIE */ }; static struct bcmdhd_platform_data *bcmdhd_data; -static struct mmc_host *wlan_mmc_host; +void somc_wifi_mmc_host_register(struct mmc_host *host) +{ + wlan_mmc_host = host; +} + +#if !defined(CONFIG_MACH_SONY_SHINANO) +int somc_wifi_set_power(int on) +{ + gpio_set_value(bcmdhd_data->wlan_reg_on, on); + return 0; +} + +int somc_wifi_set_carddetect(int present) +{ +#ifdef CONFIG_BCMDHD_PCIE + int ret = 0; + if (present) + ret = msm_pcie_enumerate(bcmdhd_data->pci_number); + return ret; +#else + if (wlan_mmc_host) + mmc_detect_change(wlan_mmc_host, 0); + return 0; +#endif /* CONFIG_BCMDHD_PCIE */ +} +#else +#define WIFI_POWER_PMIC_GPIO 18 +#define WIFI_IRQ_GPIO 67 + +static unsigned int g_wifi_detect; +static void *sdc_dev; +void (*sdc_status_cb)(int card_present, void *dev); +static void *wifi_mmc_host; +static struct regulator *wifi_batfet; +static int batfet_ena; +extern void sdio_ctrl_power(struct mmc_host *card, bool onoff); + +int wcf_status_register(void (*cb)(int card_present, void *dev), void *dev) +{ + pr_info("%s\n", __func__); + + if (sdc_status_cb) + return -EINVAL; + + sdc_status_cb = cb; + sdc_dev = dev; + wifi_mmc_host = ((struct msmsdcc_host *)dev)->mmc; + + return 0; +} + +unsigned int wcf_status(struct device *dev) +{ + pr_info("%s: wifi_detect = %d\n", __func__, g_wifi_detect); + return g_wifi_detect; +} + +static int somc_wifi_set_reset(int on) +{ + return 0; +} + +int somc_wifi_set_power(int on) +{ + int gpio = qpnp_pin_map("pm8941-gpio", WIFI_POWER_PMIC_GPIO); + int ret; + + if (!wifi_batfet) { + wifi_batfet = regulator_get(NULL, "batfet"); + if (IS_ERR_OR_NULL(wifi_batfet)) { + printk(KERN_ERR "unable to get batfet reg. rc=%d\n", + PTR_RET(wifi_batfet)); + wifi_batfet = NULL; + } + } + if (on) { + if (!batfet_ena && wifi_batfet) { + ret = regulator_enable(wifi_batfet); + if (ret != 0) + pr_warn("%s: Can't enable batfet regulator!\n", + __func__); + batfet_ena = 1; + } + } + gpio_set_value(gpio, on); + if (!on) { + if (batfet_ena && wifi_batfet) { + regulator_disable(wifi_batfet); + batfet_ena = 0; + } + } + + sdio_ctrl_power((struct mmc_host *)wifi_mmc_host, on); + return 0; + +} + +int somc_wifi_set_carddetect(int present) +{ + g_wifi_detect = present; + + if (sdc_status_cb) + sdc_status_cb(present, sdc_dev); + else + printk(KERN_WARNING "%s: Nobody to notify\n", __func__); + return 0; +} +#endif /* CONFIG_MACH_SONY_SHINANO */ + +static ssize_t macaddr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s", intf_macaddr); +} + +static ssize_t macaddr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return snprintf(intf_macaddr, count, "%s\n", buf); +} + +DEVICE_ATTR(macaddr, 0644, macaddr_show, macaddr_store); + +static struct attribute *wifi_attrs[] = { + &dev_attr_macaddr.attr, + NULL +}; + +static struct attribute_group wifi_attr_grp = { + .attrs = wifi_attrs, +}; int somc_wifi_init(struct platform_device *pdev) { @@ -102,6 +241,7 @@ int somc_wifi_init(struct platform_device *pdev) goto err_gpio; } +#ifdef CONFIG_BCMDHD_PCIE ret = of_property_read_u32(pdev->dev.of_node, "wlan-pci-number", &bcmdhd_data->pci_number); if (ret < 0) { @@ -109,11 +249,20 @@ int somc_wifi_init(struct platform_device *pdev) __func__, ret, bcmdhd_data->pci_number); goto err_gpio_request; } +#endif /* CONFIG_BCMDHD_PCIE */ + + intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); + if (sysfs_create_group(&pdev->dev.kobj, &wifi_attr_grp) < 0) { + pr_err("%s: Unable to create sysfs\n", __func__); + kfree(intf_macaddr); + } return 0; +#ifdef CONFIG_BCMDHD_PCIE err_gpio_request: gpio_free(bcmdhd_data->wlan_reg_on); +#endif /* CONFIG_BCMDHD_PCIE */ err_gpio: ret_sus = pinctrl_select_state(bcmdhd_data->pinctrl, bcmdhd_data->gpio_state_suspend); @@ -145,41 +294,178 @@ void somc_wifi_deinit(struct platform_device *pdev) } EXPORT_SYMBOL(somc_wifi_deinit); -void somc_wifi_mmc_host_register(struct mmc_host *host) +#define ETHER_ADDR_LEN 6 + +static inline int xdigit (char c) { - wlan_mmc_host = host; + unsigned d; + + d = (unsigned)(c-'0'); + if (d < 10) + return (int)d; + d = (unsigned)(c-'a'); + if (d < 6) + return (int)(10+d); + d = (unsigned)(c-'A'); + if (d < 6) + return (int)(10+d); + return -1; } -int somc_wifi_set_power(int on) +struct ether_addr { + unsigned char ether_addr_octet[ETHER_ADDR_LEN]; +} __attribute__((__packed__)); + +struct ether_addr * +ether_aton_r (const char *asc, struct ether_addr * addr) { - gpio_set_value(bcmdhd_data->wlan_reg_on, on); - return 0; + int i, val0, val1; + + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + val0 = xdigit(*asc); + asc++; + if (val0 < 0) + return NULL; + + val1 = xdigit(*asc); + asc++; + if (val1 < 0) + return NULL; + + addr->ether_addr_octet[i] = (unsigned char)((val0 << 4) + val1); + + if (i < ETHER_ADDR_LEN - 1) { + if (*asc != ':') + return NULL; + asc++; + } + } + + if (*asc != '\0') + return NULL; + + return addr; } -#ifdef CONFIG_BCMDHD_PCIE -int somc_wifi_set_carddetect(int present) +struct ether_addr * ether_aton (const char *asc) { - int ret = 0; - if (present) - ret = msm_pcie_enumerate_locked(bcmdhd_data->pci_number); - return ret; + static struct ether_addr addr; + return ether_aton_r(asc, &addr); } -#else /* CONFIG_BCMDHD_PCIE */ -int somc_wifi_set_carddetect(int present) + +static int somc_wifi_get_mac_addr(unsigned char *buf) { - if (wlan_mmc_host) - mmc_detect_change(wlan_mmc_host, 0); + int ret = 0; + + char macasc[128] = {0,}; + uint rand_mac; + static unsigned char mymac[ETHER_ADDR_LEN] = {0,}; + const unsigned char nullmac[ETHER_ADDR_LEN] = {0,}; + + if (buf == NULL) + return -EAGAIN; + + memset(buf, 0x00, ETHER_ADDR_LEN); + + if (intf_macaddr != NULL) { + unsigned char* macbin; + struct ether_addr* convmac = ether_aton( intf_macaddr ); + + if (convmac == NULL) { + pr_err("%s: Invalid Mac Address Format %s\n", + __FUNCTION__, macasc ); + goto random_mac; + } + + macbin = convmac->ether_addr_octet; + + pr_info("%s: READ MAC ADDRESS %02X:%02X:%02X:%02X:%02X:%02X\n", + __FUNCTION__, + macbin[0], macbin[1], macbin[2], + macbin[3], macbin[4], macbin[5]); + + memcpy(buf, macbin, ETHER_ADDR_LEN); + } + + return ret; + +random_mac: + + pr_debug("%s: %p\n", __func__, buf); + + if (memcmp( mymac, nullmac, ETHER_ADDR_LEN) != 0) { + /* Mac displayed from UI is never updated.. + So, mac obtained on initial time is used */ + memcpy(buf, mymac, ETHER_ADDR_LEN); + return 0; + } + + prandom_seed((uint)jiffies); + rand_mac = prandom_u32(); + buf[0] = 0x00; + buf[1] = 0x90; + buf[2] = 0x4c; + buf[3] = (unsigned char)rand_mac; + buf[4] = (unsigned char)(rand_mac >> 8); + buf[5] = (unsigned char)(rand_mac >> 16); + + memcpy(mymac, buf, 6); + + pr_info("[%s] Exiting. MAC %02X:%02X:%02X:%02X:%02X:%02X\n", + __FUNCTION__, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5] ); + return 0; } -#endif /* CONFIG_BCMDHD_PCIE */ struct wifi_platform_data somc_wifi_control = { .set_power = somc_wifi_set_power, +#if defined(CONFIG_MACH_SONY_SHINANO) + .set_reset = somc_wifi_set_reset, +#endif /* CONFIG_MACH_SONY_SHINANO */ .set_carddetect = somc_wifi_set_carddetect, -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM .mem_prealloc = dhd_wlan_mem_prealloc, -#endif + .get_mac_addr = somc_wifi_get_mac_addr, }; + EXPORT_SYMBOL(somc_wifi_control); +#if defined(CONFIG_MACH_SONY_SHINANO) +static struct resource somc_wifi_resources[] = { + [0] = { + .name = "bcmdhd_wlan_irq", + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | + IORESOURCE_IRQ_SHAREABLE, + }, +}; + +static struct platform_device somc_wifi = { + .name = "bcmdhd_wlan", + .id = -1, + .num_resources = ARRAY_SIZE(somc_wifi_resources), + .resource = somc_wifi_resources, + .dev = { + .platform_data = &somc_wifi_control, + }, +}; + +static int __init somc_wifi_init_on_boot(void) +{ + somc_wifi.resource->start = gpio_to_irq(WIFI_IRQ_GPIO); + somc_wifi.resource->end = gpio_to_irq(WIFI_IRQ_GPIO); + platform_device_register(&somc_wifi); + + intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); + if (sysfs_create_group(&somc_wifi.dev.kobj, &wifi_attr_grp) < 0) { + pr_err("%s: Unable to create sysfs\n", __func__); + kfree(intf_macaddr); + } + return 0; +} + +device_initcall(somc_wifi_init_on_boot); +#endif /* CONFIG_MACH_SONY_SHINANO */ + MODULE_LICENSE("GPL v2"); -- GitLab From 3acb8d6752a863bcf2a3d41948a458c9712836f2 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 1 May 2021 20:51:03 +0200 Subject: [PATCH 253/528] bcmdhd: Disable 4354 and set fw/nvram path --- drivers/net/wireless/bcmdhd_bcm43455/Kconfig | 16 ++++++++-------- drivers/net/wireless/bcmdhd_bcm4356/Kconfig | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig index 37e9a097bd72..626e47e6d214 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -config BCM4354 - bool "Broadcom 4354 wireless card support" - depends on BCMDHD - ---help--- - This module adds support for wireless adapters based on - Broadcom 4354 chipset. +#config BCM4354 +# bool "Broadcom 4354 wireless card support" +# depends on BCMDHD +# ---help--- +# This module adds support for wireless adapters based on +# Broadcom 4354 chipset. config BCM43455 bool "Broadcom 43455 wireless cards support" @@ -44,14 +44,14 @@ endchoice config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" + default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" + default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig index 599f99af9cd4..a89ca15ef8f0 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -config BCM4354 - bool "Broadcom 4354 wireless cards support" - depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) - ---help--- - This module adds support for wireless adapters based on - Broadcom 4354 chipset. +#config BCM4354 +# bool "Broadcom 4354 wireless cards support" +# depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) +# ---help--- +# This module adds support for wireless adapters based on +# Broadcom 4354 chipset. config BCM4356 bool "Broadcom 4356 wireless cards support" @@ -42,14 +42,14 @@ config BCM4356 config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" + default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" + default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" ---help--- Path to the calibration file. -- GitLab From 09d24a32df32669770ec536b3ff3b31a90c77475 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 1 May 2021 20:53:16 +0200 Subject: [PATCH 254/528] Merge remotes/acherepkov/DEV_rc13 drivers/net/ --- drivers/net/Space.c | 29 +- drivers/net/can/dev.c | 2 +- drivers/net/can/usb/ems_usb.c | 1 + drivers/net/can/usb/kvaser_usb.c | 2 +- drivers/net/macvlan.c | 10 +- drivers/net/macvtap.c | 13 +- drivers/net/netconsole.c | 20 +- drivers/net/ppp/ppp_generic.c | 10 + drivers/net/ppp/pppoe.c | 15 +- drivers/net/ppp/pptp.c | 1 - drivers/net/team/team.c | 27 +- drivers/net/tun.c | 382 ++++++++++++------ drivers/net/usb/asix_devices.c | 3 + drivers/net/usb/ax88179_178a.c | 3 + drivers/net/usb/cdc-phonet.c | 6 +- drivers/net/usb/cdc_ether.c | 17 +- drivers/net/usb/cdc_ncm.c | 7 +- drivers/net/usb/qmi_wwan.c | 20 +- drivers/net/usb/rmnet_usb_ctrl.c | 5 +- drivers/net/usb/usbnet.c | 160 +++++++- drivers/net/veth.c | 3 + drivers/net/virtio_net.c | 24 +- drivers/net/vxlan.c | 2 +- drivers/net/wan/sbni.c | 5 +- drivers/net/wireless/bcmdhd_bcm43455/Kconfig | 16 +- drivers/net/wireless/bcmdhd_bcm4356/Kconfig | 16 +- drivers/net/wireless/somcwifictrl/somc_wifi.c | 336 ++------------- drivers/net/xen-netfront.c | 8 +- 28 files changed, 602 insertions(+), 541 deletions(-) diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 3a8c7532ee0d..754565a8a2fc 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -32,39 +32,12 @@ #include #include #include +#include /* A unified ethernet device probe. This is the easiest way to have every ethernet adaptor have the name "eth[0123...]". */ -extern struct net_device *hp100_probe(int unit); -extern struct net_device *ultra_probe(int unit); -extern struct net_device *wd_probe(int unit); -extern struct net_device *ne_probe(int unit); -extern struct net_device *fmv18x_probe(int unit); -extern struct net_device *i82596_probe(int unit); -extern struct net_device *ni65_probe(int unit); -extern struct net_device *sonic_probe(int unit); -extern struct net_device *smc_init(int unit); -extern struct net_device *atarilance_probe(int unit); -extern struct net_device *sun3lance_probe(int unit); -extern struct net_device *sun3_82586_probe(int unit); -extern struct net_device *apne_probe(int unit); -extern struct net_device *cs89x0_probe(int unit); -extern struct net_device *mvme147lance_probe(int unit); -extern struct net_device *tc515_probe(int unit); -extern struct net_device *lance_probe(int unit); -extern struct net_device *mac8390_probe(int unit); -extern struct net_device *mac89x0_probe(int unit); -extern struct net_device *cops_probe(int unit); -extern struct net_device *ltpc_probe(void); - -/* Fibre Channel adapters */ -extern int iph5526_probe(struct net_device *dev); - -/* SBNI adapters */ -extern int sbni_probe(int unit); - struct devprobe2 { struct net_device *(*probe)(int unit); int status; /* non-zero if autoprobe has failed */ diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 284d751ea97f..cd5219a8f10c 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -474,7 +474,7 @@ void can_bus_off(struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - netdev_dbg(dev, "bus-off\n"); + netdev_info(dev, "bus-off\n"); netif_carrier_off(dev); priv->can_stats.bus_off++; diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index d921416295ce..188d3b2b1cf8 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -1081,6 +1081,7 @@ static void ems_usb_disconnect(struct usb_interface *intf) usb_free_urb(dev->intr_urb); kfree(dev->intr_in_buffer); + kfree(dev->tx_msg_buffer); } } diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index a3fb8b51038a..07b8d8b3dbb2 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -834,7 +834,7 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, skb = alloc_can_skb(priv->netdev, &cf); if (!skb) { - stats->tx_dropped++; + stats->rx_dropped++; return; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 9be91cb4f4a3..99843f6b501d 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -594,7 +594,10 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct macvlan_dev *vlan = netdev_priv(dev); int err = -EINVAL; - if (!vlan->port->passthru) + /* Support unicast filter only on passthru devices. + * Multicast filter should be allowed on all devices. + */ + if (!vlan->port->passthru && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (is_unicast_ether_addr(addr)) @@ -612,7 +615,10 @@ static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct macvlan_dev *vlan = netdev_priv(dev); int err = -EINVAL; - if (!vlan->port->passthru) + /* Support unicast filter only on passthru devices. + * Multicast filter should be allowed on all devices. + */ + if (!vlan->port->passthru && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (is_unicast_ether_addr(addr)) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index f25f47853dd6..e921214eef95 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -459,7 +460,7 @@ static inline struct sk_buff *macvtap_alloc_skb(struct sock *sk, size_t prepad, linear = len; skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock, - err, 0); + err); if (!skb) return NULL; @@ -568,7 +569,11 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb, gso_type = SKB_GSO_TCPV6; break; case VIRTIO_NET_HDR_GSO_UDP: + pr_warn_once("macvtap: %s: using disabled UFO feature; please fix this program\n", + current->comm); gso_type = SKB_GSO_UDP; + if (skb->protocol == htons(ETH_P_IPV6)) + ipv6_proxy_select_ident(skb); break; default: return -EINVAL; @@ -613,8 +618,6 @@ static int macvtap_skb_to_vnet_hdr(const struct sk_buff *skb, vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (sinfo->gso_type & SKB_GSO_TCPV6) vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; - else if (sinfo->gso_type & SKB_GSO_UDP) - vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP; else BUG(); if (sinfo->gso_type & SKB_GSO_TCP_ECN) @@ -970,6 +973,8 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, case TUNSETSNDBUF: if (get_user(u, up)) return -EFAULT; + if (u <= 0) + return -EINVAL; q->sk.sk_sndbuf = u; return 0; @@ -992,7 +997,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, case TUNSETOFFLOAD: /* let the user check for future flags */ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | - TUN_F_TSO_ECN | TUN_F_UFO)) + TUN_F_TSO_ECN)) return -EINVAL; /* TODO: only accept frames with the features that diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 59ac143dec25..fb9b7591571b 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -101,6 +101,7 @@ struct netconsole_target { struct config_item item; #endif int enabled; + struct mutex mutex; struct netpoll np; }; @@ -180,6 +181,7 @@ static struct netconsole_target *alloc_param_target(char *target_config) strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); nt->np.local_port = 6665; nt->np.remote_port = 6666; + mutex_init(&nt->mutex); memset(nt->np.remote_mac, 0xff, ETH_ALEN); /* Parse parameters and setup netpoll */ @@ -307,6 +309,7 @@ static ssize_t store_enabled(struct netconsole_target *nt, const char *buf, size_t count) { + unsigned long flags; int enabled; int err; @@ -322,7 +325,6 @@ static ssize_t store_enabled(struct netconsole_target *nt, } if (enabled) { /* 1 */ - /* * Skip netpoll_parse_options() -- all the attributes are * already configured via configfs. Just print them out. @@ -334,8 +336,14 @@ static ssize_t store_enabled(struct netconsole_target *nt, return err; printk(KERN_INFO "netconsole: network logging started\n"); - } else { /* 0 */ + /* We need to disable the netconsole before cleaning it up + * otherwise we might end up in write_msg() with + * nt->np.dev == NULL and nt->enabled == 1 + */ + spin_lock_irqsave(&target_list_lock, flags); + nt->enabled = 0; + spin_unlock_irqrestore(&target_list_lock, flags); netpoll_cleanup(&nt->np); } @@ -556,8 +564,10 @@ static ssize_t netconsole_target_attr_store(struct config_item *item, struct netconsole_target_attr *na = container_of(attr, struct netconsole_target_attr, attr); + mutex_lock(&nt->mutex); if (na->store) ret = na->store(nt, buf, count); + mutex_unlock(&nt->mutex); return ret; } @@ -596,6 +606,7 @@ static struct config_item *make_netconsole_target(struct config_group *group, strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); nt->np.local_port = 6665; nt->np.remote_port = 6666; + mutex_init(&nt->mutex); memset(nt->np.remote_mac, 0xff, ETH_ALEN); /* Initialize the config_item member */ @@ -677,12 +688,13 @@ restart: case NETDEV_RELEASE: case NETDEV_JOIN: case NETDEV_UNREGISTER: - /* - * rtnl_lock already held + /* rtnl_lock already held * we might sleep in __netpoll_cleanup() */ spin_unlock_irqrestore(&target_list_lock, flags); + __netpoll_cleanup(&nt->np); + spin_lock_irqsave(&target_list_lock, flags); dev_put(nt->np.dev); nt->np.dev = NULL; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index ab79c0f13d0a..ddc501deefba 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -892,6 +892,7 @@ static __net_exit void ppp_exit_net(struct net *net) { struct ppp_net *pn = net_generic(net, ppp_net_id); + mutex_destroy(&pn->all_ppp_mutex); idr_destroy(&pn->units_idr); } @@ -2872,6 +2873,15 @@ ppp_connect_channel(struct channel *pch, int unit) goto outl; ppp_lock(ppp); + spin_lock_bh(&pch->downl); + if (!pch->chan) { + /* Don't connect unregistered channels */ + spin_unlock_bh(&pch->downl); + ppp_unlock(ppp); + ret = -ENOTCONN; + goto outl; + } + spin_unlock_bh(&pch->downl); if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 2840cf608312..c3db80d1b15a 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -613,6 +613,10 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); error = -EINVAL; + + if (sockaddr_len != sizeof(struct sockaddr_pppox)) + goto end; + if (sp->sa_protocol != PX_PROTO_OE) goto end; @@ -830,6 +834,7 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct pppoe_hdr *ph; struct net_device *dev; char *start; + int hlen; lock_sock(sk); if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) { @@ -848,16 +853,16 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, if (total_len > (dev->mtu + dev->hard_header_len)) goto end; - - skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, - 0, GFP_KERNEL); + hlen = LL_RESERVED_SPACE(dev); + skb = sock_wmalloc(sk, hlen + sizeof(*ph) + total_len + + dev->needed_tailroom, 0, GFP_KERNEL); if (!skb) { error = -ENOMEM; goto end; } /* Reserve space for headers. */ - skb_reserve(skb, dev->hard_header_len); + skb_reserve(skb, hlen); skb_reset_network_header(skb); skb->dev = dev; @@ -918,7 +923,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) /* Copy the data if there is no space for the header or if it's * read-only. */ - if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len)) + if (skb_cow_head(skb, LL_RESERVED_SPACE(dev) + sizeof(*ph))) goto abort; __skb_push(skb, sizeof(*ph)); diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 9a423435039a..3eb44cfae48c 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -488,7 +488,6 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.mtu = dst_mtu(&rt->dst); if (!po->chan.mtu) po->chan.mtu = PPP_MRU; - ip_rt_put(rt); po->chan.mtu -= PPTP_HEADER_OVERHEAD; po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header); diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 0a3ad7ba2bea..06d184c42cd5 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -253,6 +253,17 @@ static void __team_option_inst_mark_removed_port(struct team *team, } } +static bool __team_option_inst_tmp_find(const struct list_head *opts, + const struct team_option_inst *needle) +{ + struct team_option_inst *opt_inst; + + list_for_each_entry(opt_inst, opts, tmp_list) + if (opt_inst == needle) + return true; + return false; +} + static int __team_options_register(struct team *team, const struct team_option *option, size_t option_count) @@ -863,7 +874,7 @@ static void team_port_disable(struct team *team, static void __team_compute_features(struct team *team) { struct team_port *port; - u32 vlan_features = TEAM_VLAN_FEATURES; + netdev_features_t vlan_features = TEAM_VLAN_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE; @@ -2158,7 +2169,7 @@ send_done: if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; } @@ -2322,6 +2333,14 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) if (err) goto team_put; opt_inst->changed = true; + + /* dumb/evil user-space can send us duplicate opt, + * keep only the last one + */ + if (__team_option_inst_tmp_find(&opt_inst_list, + opt_inst)) + continue; + list_add(&opt_inst->tmp_list, &opt_inst_list); } if (!opt_found) { @@ -2438,7 +2457,7 @@ send_done: if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; } @@ -2668,8 +2687,10 @@ static int team_device_event(struct notifier_block *unused, case NETDEV_UP: if (netif_carrier_ok(dev)) team_port_change_check(port, true); + break; case NETDEV_DOWN: team_port_change_check(port, false); + break; case NETDEV_CHANGE: if (netif_running(port->dev)) team_port_change_check(port, diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 211df7e9edba..ca3d19ce8064 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -60,14 +60,17 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include +#include #include @@ -109,7 +112,7 @@ struct tap_filter { unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; }; -/* DEFAULT_MAX_NUM_RSS_QUEUES were choosed to let the rx/tx queues allocated for +/* DEFAULT_MAX_NUM_RSS_QUEUES were chosen to let the rx/tx queues allocated for * the netdevice to be fit in one page. So we can make sure the success of * memory allocation. TODO: increase the limit. */ #define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES @@ -118,7 +121,7 @@ struct tap_filter { #define TUN_FLOW_EXPIRE (3 * HZ) /* A tun_file connects an open character device to a tuntap netdevice. It - * also contains all socket related strctures (except sock_fprog and tap_filter) + * also contains all socket related structures (except sock_fprog and tap_filter) * to serve as one transmit queue for tuntap device. The sock_fprog and * tap_filter were kept in tun_struct since they were used for filtering for the * netdevice not for a specific queue (at least I didn't see the requirement for @@ -137,7 +140,10 @@ struct tun_file { struct fasync_struct *fasync; /* only used for fasnyc */ unsigned int flags; - u16 queue_index; + union { + u16 queue_index; + unsigned int ifindex; + }; struct list_head next; struct tun_struct *detached; }; @@ -148,6 +154,7 @@ struct tun_flow_entry { struct tun_struct *tun; u32 rxhash; + u32 rps_rxhash; int queue_index; unsigned long updated; }; @@ -168,7 +175,7 @@ struct tun_struct { struct net_device *dev; netdev_features_t set_features; #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ - NETIF_F_TSO6|NETIF_F_UFO) + NETIF_F_TSO6) int vnet_hdr_sz; int sndbuf; @@ -216,6 +223,7 @@ static struct tun_flow_entry *tun_flow_create(struct tun_struct *tun, rxhash, queue_index); e->updated = jiffies; e->rxhash = rxhash; + e->rps_rxhash = 0; e->queue_index = queue_index; e->tun = tun; hlist_add_head_rcu(&e->hash_link, head); @@ -228,6 +236,7 @@ static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e) { tun_debug(KERN_INFO, tun, "delete flow: hash %u index %u\n", e->rxhash, e->queue_index); + sock_rps_reset_flow_hash(e->rps_rxhash); hlist_del_rcu(&e->hash_link); kfree_rcu(e, rcu); --tun->flow_count; @@ -275,25 +284,28 @@ static void tun_flow_cleanup(unsigned long data) tun_debug(KERN_INFO, tun, "tun_flow_cleanup\n"); - spin_lock_bh(&tun->lock); + spin_lock(&tun->lock); for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++) { struct tun_flow_entry *e; struct hlist_node *n; hlist_for_each_entry_safe(e, n, &tun->flows[i], hash_link) { unsigned long this_timer; - count++; + this_timer = e->updated + delay; - if (time_before_eq(this_timer, jiffies)) + if (time_before_eq(this_timer, jiffies)) { tun_flow_delete(tun, e); - else if (time_before(this_timer, next_timer)) + continue; + } + count++; + if (time_before(this_timer, next_timer)) next_timer = this_timer; } } if (count) mod_timer(&tun->flow_gc_timer, round_jiffies_up(next_timer)); - spin_unlock_bh(&tun->lock); + spin_unlock(&tun->lock); } static void tun_flow_update(struct tun_struct *tun, u32 rxhash, @@ -321,6 +333,7 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash, /* TODO: keep queueing to old queue until it's empty? */ e->queue_index = queue_index; e->updated = jiffies; + sock_rps_record_flow_hash(e->rps_rxhash); } else { spin_lock_bh(&tun->lock); if (!tun_flow_find(head, rxhash) && @@ -337,8 +350,20 @@ unlock: rcu_read_unlock(); } +/** + * Save the hash received in the stack receive path and update the + * flow_hash table accordingly. + */ +static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) +{ + if (unlikely(e->rps_rxhash != hash)) { + sock_rps_reset_flow_hash(e->rps_rxhash); + e->rps_rxhash = hash; + } +} + /* We try to identify a flow through its rxhash first. The reason that - * we do not check rxq no. is becuase some cards(e.g 82599), chooses + * we do not check rxq no. is because some cards(e.g 82599), chooses * the rxq based on the txq where the last packet of the flow comes. As * the userspace application move between processors, we may get a * different rxq no. here. If we could not get rxhash, then we would @@ -357,9 +382,10 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb) txq = skb_get_rxhash(skb); if (txq) { e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq); - if (e) + if (e) { + tun_flow_save_rps_rxhash(e, txq); txq = e->queue_index; - else + } else /* use multiply and shift instead of expensive divide */ txq = ((u64)txq * numqueues) >> 32; } else if (likely(skb_rx_queue_recorded(skb))) { @@ -405,6 +431,12 @@ static struct tun_struct *tun_enable_queue(struct tun_file *tfile) return tun; } +static void tun_queue_purge(struct tun_file *tfile) +{ + skb_queue_purge(&tfile->sk.sk_receive_queue); + skb_queue_purge(&tfile->sk.sk_error_queue); +} + static void __tun_detach(struct tun_file *tfile, bool clean) { struct tun_file *ntfile; @@ -423,7 +455,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) --tun->numqueues; if (clean) { - rcu_assign_pointer(tfile->tun, NULL); + RCU_INIT_POINTER(tfile->tun, NULL); sock_put(&tfile->sk); } else tun_disable_queue(tun, tfile); @@ -431,7 +463,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) synchronize_net(); tun_flow_delete_by_queue(tun, tun->numqueues + 1); /* Drop read queue */ - skb_queue_purge(&tfile->sk.sk_receive_queue); + tun_queue_purge(tfile); tun_set_real_num_queues(tun); } else if (tfile->detached && clean) { tun = tun_enable_queue(tfile); @@ -469,13 +501,15 @@ static void tun_detach_all(struct net_device *dev) for (i = 0; i < n; i++) { tfile = rtnl_dereference(tun->tfiles[i]); BUG_ON(!tfile); - wake_up_all(&tfile->wq.wait); - rcu_assign_pointer(tfile->tun, NULL); + tfile->socket.sk->sk_shutdown = RCV_SHUTDOWN; + tfile->socket.sk->sk_data_ready((tfile->socket.sk),0); + RCU_INIT_POINTER(tfile->tun, NULL); --tun->numqueues; } list_for_each_entry(tfile, &tun->disabled, next) { - wake_up_all(&tfile->wq.wait); - rcu_assign_pointer(tfile->tun, NULL); + tfile->socket.sk->sk_shutdown = RCV_SHUTDOWN; + tfile->socket.sk->sk_data_ready((tfile->socket.sk),0); + RCU_INIT_POINTER(tfile->tun, NULL); } BUG_ON(tun->numqueues != 0); @@ -483,12 +517,12 @@ static void tun_detach_all(struct net_device *dev) for (i = 0; i < n; i++) { tfile = rtnl_dereference(tun->tfiles[i]); /* Drop read queue */ - skb_queue_purge(&tfile->sk.sk_receive_queue); + tun_queue_purge(tfile); sock_put(&tfile->sk); } list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { tun_enable_queue(tfile); - skb_queue_purge(&tfile->sk.sk_receive_queue); + tun_queue_purge(tfile); sock_put(&tfile->sk); } BUG_ON(tun->numdisabled != 0); @@ -497,7 +531,7 @@ static void tun_detach_all(struct net_device *dev) module_put(THIS_MODULE); } -static int tun_attach(struct tun_struct *tun, struct file *file) +static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filter) { struct tun_file *tfile = file->private_data; int err; @@ -521,13 +555,14 @@ static int tun_attach(struct tun_struct *tun, struct file *file) err = 0; - /* Re-attach the filter to presist device */ - if (tun->filter_attached == true) { + /* Re-attach the filter to persist device */ + if (!skip_filter && (tun->filter_attached == true)) { err = sk_attach_filter(&tun->fprog, tfile->socket.sk); if (!err) goto out; } tfile->queue_index = tun->numqueues; + tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN; rcu_assign_pointer(tfile->tun, tun); rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile); tun->numqueues++; @@ -599,14 +634,9 @@ static int update_filter(struct tap_filter *filter, void __user *arg) } alen = ETH_ALEN * uf.count; - addr = kmalloc(alen, GFP_KERNEL); - if (!addr) - return -ENOMEM; - - if (copy_from_user(addr, arg + sizeof(uf), alen)) { - err = -EFAULT; - goto done; - } + addr = memdup_user(arg + sizeof(uf), alen); + if (IS_ERR(addr)) + return PTR_ERR(addr); /* The filter is updated without holding any locks. Which is * perfectly safe. We disable it first and in the worst @@ -626,7 +656,7 @@ static int update_filter(struct tap_filter *filter, void __user *arg) for (; n < uf.count; n++) { if (!is_multicast_ether_addr(addr[n].u)) { err = 0; /* no filter */ - goto done; + goto free_addr; } addr_hash_set(filter->mask, addr[n].u); } @@ -642,8 +672,7 @@ static int update_filter(struct tap_filter *filter, void __user *arg) /* Return the number of exact filters */ err = nexact; - -done: +free_addr: kfree(addr); return err; } @@ -710,14 +739,34 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) struct tun_struct *tun = netdev_priv(dev); int txq = skb->queue_mapping; struct tun_file *tfile; + u32 numqueues = 0; rcu_read_lock(); tfile = rcu_dereference(tun->tfiles[txq]); + numqueues = ACCESS_ONCE(tun->numqueues); /* Drop packet if interface is not attached */ - if (txq >= tun->numqueues) + if (txq >= numqueues) goto drop; +#ifdef CONFIG_RPS + if (numqueues == 1 && static_key_false(&rps_needed)) { + /* Select queue was not called for the skbuff, so we extract the + * RPS hash and save it into the flow_table here. + */ + __u32 rxhash; + + rxhash = skb_get_rxhash(skb); + if (rxhash) { + struct tun_flow_entry *e; + e = tun_flow_find(&tun->flows[tun_hashfn(rxhash)], + rxhash); + if (e) + tun_flow_save_rps_rxhash(e, rxhash); + } + } +#endif + tun_debug(KERN_INFO, tun, "tun_net_xmit %d\n", skb->len); BUG_ON(!tfile); @@ -735,14 +784,18 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) /* Limit the number of packets queued by dividing txq length with the * number of queues. */ - if (skb_queue_len(&tfile->socket.sk->sk_receive_queue) - >= dev->tx_queue_len / tun->numqueues) + if (skb_queue_len(&tfile->socket.sk->sk_receive_queue) * numqueues + >= dev->tx_queue_len) goto drop; - /* Orphan the skb - required as we might hang on to it - * for indefinite time. */ if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC))) goto drop; + + skb_tx_timestamp(skb); + + /* Orphan the skb - required as we might hang on to it + * for indefinite time. + */ skb_orphan(skb); nf_reset(skb); @@ -753,8 +806,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) /* Notify and wake up reader process */ if (tfile->flags & TUN_FASYNC) kill_fasync(&tfile->fasync, SIGIO, POLL_IN); - wake_up_interruptible_poll(&tfile->wq.wait, POLLIN | - POLLRDNORM | POLLRDBAND); + tfile->socket.sk->sk_data_ready((tfile->socket.sk),0); rcu_read_unlock(); return NETDEV_TX_OK; @@ -802,9 +854,9 @@ static void tun_poll_controller(struct net_device *dev) * Tun only receives frames when: * 1) the char device endpoint gets data from user space * 2) the tun socket gets a sendmsg call from user space - * Since both of those are syncronous operations, we are guaranteed + * Since both of those are synchronous operations, we are guaranteed * never to have pending data when we poll for it - * so theres nothing to do here but return. + * so there is nothing to do here but return. * We need this though so netpoll recognizes us as an interface that * supports polling, which enables bridge devices in virt setups to * still use netconsole @@ -841,7 +893,7 @@ static const struct net_device_ops tap_netdev_ops = { #endif }; -static int tun_flow_init(struct tun_struct *tun) +static void tun_flow_init(struct tun_struct *tun) { int i; @@ -850,10 +902,6 @@ static int tun_flow_init(struct tun_struct *tun) tun->ageing_time = TUN_FLOW_EXPIRE; setup_timer(&tun->flow_gc_timer, tun_flow_cleanup, (unsigned long)tun); - mod_timer(&tun->flow_gc_timer, - round_jiffies_up(jiffies + tun->ageing_time)); - - return 0; } static void tun_flow_uninit(struct tun_struct *tun) @@ -913,7 +961,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait) tun_debug(KERN_INFO, tun, "tun_chr_poll\n"); - poll_wait(file, &tfile->wq.wait, wait); + poll_wait(file, sk_sleep(sk), wait); if (!skb_queue_empty(&sk->sk_receive_queue)) mask |= POLLIN | POLLRDNORM; @@ -945,7 +993,7 @@ static struct sk_buff *tun_alloc_skb(struct tun_file *tfile, linear = len; skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock, - &err, 0); + &err); if (!skb) return ERR_PTR(err); @@ -1076,6 +1124,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, int err; u32 rxhash; + if (!(tun->dev->flags & IFF_UP)) + return -EIO; + if (!(tun->flags & TUN_NO_PI)) { if (len < sizeof(pi)) return -EINVAL; @@ -1167,14 +1218,20 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, } } + if (!(tun->flags & TUN_NO_PI)) + if (pi.flags & htons(CHECKSUM_UNNECESSARY)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: if (tun->flags & TUN_NO_PI) { - switch (skb->data[0] & 0xf0) { - case 0x40: + u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0; + + switch (ip_version) { + case 4: pi.proto = htons(ETH_P_IP); break; - case 0x60: + case 6: pi.proto = htons(ETH_P_IPV6); break; default: @@ -1193,6 +1250,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, break; } + skb_reset_network_header(skb); + if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) { pr_debug("GSO!\n"); switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { @@ -1203,8 +1262,20 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; break; case VIRTIO_NET_HDR_GSO_UDP: + { + static bool warned; + + if (!warned) { + warned = true; + netdev_warn(tun->dev, + "%s: using disabled UFO feature; please fix this program\n", + current->comm); + } skb_shinfo(skb)->gso_type = SKB_GSO_UDP; + if (skb->protocol == htons(ETH_P_IPV6)) + ipv6_proxy_select_ident(skb); break; + } default: tun->dev->stats.rx_frame_errors++; kfree_skb(skb); @@ -1233,7 +1304,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; } - skb_reset_network_header(skb); skb_probe_transport_header(skb, 0); rxhash = skb_get_rxhash(skb); @@ -1274,8 +1344,13 @@ static ssize_t tun_put_user(struct tun_struct *tun, { struct tun_pi pi = { 0, skb->protocol }; ssize_t total = 0; + int vlan_offset = 0, copied; + int vlan_hlen = 0; int vnet_hdr_sz = 0; + if (vlan_tx_tag_present(skb)) + vlan_hlen = VLAN_HLEN; + if (tun->flags & TUN_VNET_HDR) vnet_hdr_sz = ACCESS_ONCE(tun->vnet_hdr_sz); @@ -1283,7 +1358,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, if ((len -= sizeof(pi)) < 0) return -EINVAL; - if (len < skb->len + vnet_hdr_sz) { + if (len < skb->len + vlan_hlen + vnet_hdr_sz) { /* Packet will be striped */ pi.flags |= TUN_PKT_STRIP; } @@ -1308,8 +1383,6 @@ static ssize_t tun_put_user(struct tun_struct *tun, gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (sinfo->gso_type & SKB_GSO_TCPV6) gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; - else if (sinfo->gso_type & SKB_GSO_UDP) - gso.gso_type = VIRTIO_NET_HDR_GSO_UDP; else { pr_err("unexpected GSO type: " "0x%x, gso_size %d, hdr_len %d\n", @@ -1329,7 +1402,8 @@ static ssize_t tun_put_user(struct tun_struct *tun, if (skb->ip_summed == CHECKSUM_PARTIAL) { gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - gso.csum_start = skb_checksum_start_offset(skb); + gso.csum_start = skb_checksum_start_offset(skb) + + vlan_hlen; gso.csum_offset = skb->csum_offset; } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { gso.flags = VIRTIO_NET_HDR_F_DATA_VALID; @@ -1341,11 +1415,39 @@ static ssize_t tun_put_user(struct tun_struct *tun, total += vnet_hdr_sz; } - len = min_t(int, skb->len, len); + copied = total; + len = min_t(int, skb->len + vlan_hlen, len); + total += skb->len + vlan_hlen; + if (vlan_hlen) { + int copy, ret; + struct { + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + } veth; + + veth.h_vlan_proto = skb->vlan_proto; + veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); + + vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); + + copy = min_t(int, vlan_offset, len); + ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); + len -= copy; + copied += copy; + if (ret || !len) + goto done; - skb_copy_datagram_const_iovec(skb, 0, iv, total, len); - total += skb->len; + copy = min_t(int, sizeof(veth), len); + ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy); + len -= copy; + copied += copy; + if (ret || !len) + goto done; + } + skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len); + +done: tun->dev->stats.tx_packets++; tun->dev->stats.tx_bytes += len; @@ -1356,45 +1458,23 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, struct kiocb *iocb, const struct iovec *iv, ssize_t len, int noblock) { - DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; ssize_t ret = 0; + int peeked, err, off = 0; tun_debug(KERN_INFO, tun, "tun_do_read\n"); - if (unlikely(!noblock)) - add_wait_queue(&tfile->wq.wait, &wait); - while (len) { - current->state = TASK_INTERRUPTIBLE; - - /* Read frames from the queue */ - if (!(skb = skb_dequeue(&tfile->socket.sk->sk_receive_queue))) { - if (noblock) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - if (tun->dev->reg_state != NETREG_REGISTERED) { - ret = -EIO; - break; - } - - /* Nothing to read, let's sleep */ - schedule(); - continue; - } + if (!len) + return ret; + /* Read frames from queue */ + skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0, + &peeked, &off, &err); + if (skb) { ret = tun_put_user(tun, tfile, skb, iv, len); kfree_skb(skb); - break; - } - - current->state = TASK_RUNNING; - if (unlikely(!noblock)) - remove_wait_queue(&tfile->wq.wait, &wait); + } else + ret = err; return ret; } @@ -1496,7 +1576,6 @@ static int tun_sendmsg(struct kiocb *iocb, struct socket *sock, return ret; } - static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len, int flags) @@ -1508,13 +1587,18 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, if (!tun) return -EBADFD; - if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) { + if (flags & ~(MSG_DONTWAIT|MSG_TRUNC|MSG_ERRQUEUE)) { ret = -EINVAL; goto out; } + if (flags & MSG_ERRQUEUE) { + ret = sock_recv_errqueue(sock->sk, m, total_len, + SOL_PACKET, TUN_TX_TIMESTAMP); + goto out; + } ret = tun_do_read(tun, tfile, iocb, m->msg_iov, total_len, flags & MSG_DONTWAIT); - if (ret > total_len) { + if (ret > (ssize_t)total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; } @@ -1567,6 +1651,9 @@ static int tun_flags(struct tun_struct *tun) if (tun->flags & TUN_TAP_MQ) flags |= IFF_MULTI_QUEUE; + if (tun->flags & TUN_PERSIST) + flags |= IFF_PERSIST; + return flags; } @@ -1632,7 +1719,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (err < 0) return err; - err = tun_attach(tun, file); + err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER); if (err < 0) return err; @@ -1676,9 +1763,13 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (!dev) return -ENOMEM; + err = dev_get_valid_name(net, dev, name); + if (err < 0) + goto err_free_dev; dev_net_set(dev, net); dev->rtnl_link_ops = &tun_link_ops; + dev->ifindex = tfile->ifindex; tun = netdev_priv(dev); tun->dev = dev; @@ -1696,18 +1787,18 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) goto err_free_dev; tun_net_init(dev); - - err = tun_flow_init(tun); - if (err < 0) - goto err_free_dev; + tun_flow_init(tun); dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | - TUN_USER_FEATURES; - dev->features = dev->hw_features; - dev->vlan_features = dev->features; + TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX; + dev->features = dev->hw_features | NETIF_F_LLTX; + dev->vlan_features = dev->features & + ~(NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX); INIT_LIST_HEAD(&tun->disabled); - err = tun_attach(tun, file); + err = tun_attach(tun, file, false); if (err < 0) goto err_free_flow; @@ -1799,11 +1890,6 @@ static int set_offload(struct tun_struct *tun, unsigned long arg) features |= NETIF_F_TSO6; arg &= ~(TUN_F_TSO4|TUN_F_TSO6); } - - if (arg & TUN_F_UFO) { - features |= NETIF_F_UFO; - arg &= ~TUN_F_UFO; - } } /* This gives the user a way to test for new features in future by @@ -1812,6 +1898,8 @@ static int set_offload(struct tun_struct *tun, unsigned long arg) return -EINVAL; tun->set_features = features; + tun->dev->wanted_features &= ~TUN_USER_FEATURES; + tun->dev->wanted_features |= features; netdev_update_features(tun->dev); return 0; @@ -1876,7 +1964,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr) ret = security_tun_dev_attach_queue(tun->security); if (ret < 0) goto unlock; - ret = tun_attach(tun, file); + ret = tun_attach(tun, file, false); } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { tun = rtnl_dereference(tfile->tun); if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached) @@ -1902,6 +1990,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, kgid_t group; int sndbuf; int vnet_hdr_sz; + unsigned int ifindex; int ret; #ifdef CONFIG_ANDROID_PARANOID_NETWORK @@ -1910,7 +1999,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, } #endif - if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == 0x89) { + if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == SOCK_IOC_TYPE) { if (copy_from_user(&ifr, argp, ifreq_len)) return -EFAULT; } else { @@ -1930,7 +2019,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, rtnl_lock(); tun = __tun_get(tfile); - if (cmd == TUNSETIFF && !tun) { + if (cmd == TUNSETIFF) { + ret = -EEXIST; + if (tun) + goto unlock; + ifr.ifr_name[IFNAMSIZ-1] = '\0'; ret = tun_set_iff(tfile->net, file, &ifr); @@ -1942,6 +2035,19 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, ret = -EFAULT; goto unlock; } + if (cmd == TUNSETIFINDEX) { + ret = -EPERM; + if (tun) + goto unlock; + + ret = -EFAULT; + if (copy_from_user(&ifindex, argp, sizeof(ifindex))) + goto unlock; + + ret = 0; + tfile->ifindex = ifindex; + goto unlock; + } ret = -EBADFD; if (!tun) @@ -1954,6 +2060,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, case TUNGETIFF: tun_get_iff(current->nsproxy->net_ns, tun, &ifr); + if (tfile->detached) + ifr.ifr_flags |= IFF_DETACH_QUEUE; + if (!tfile->socket.sk->sk_filter) + ifr.ifr_flags |= IFF_NOFILTER; + if (copy_to_user(argp, &ifr, ifreq_len)) ret = -EFAULT; break; @@ -2065,6 +2176,10 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, ret = -EFAULT; break; } + if (sndbuf <= 0) { + ret = -EINVAL; + break; + } tun->sndbuf = sndbuf; tun_set_sndbuf(tun); @@ -2110,6 +2225,16 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, tun_detach_filter(tun, tun->numqueues); break; + case TUNGETFILTER: + ret = -EINVAL; + if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) + break; + ret = -EFAULT; + if (copy_to_user(argp, &tun->fprog, sizeof(tun->fprog))) + break; + ret = 0; + break; + default: ret = -EINVAL; break; @@ -2187,12 +2312,13 @@ static int tun_chr_open(struct inode *inode, struct file * file) &tun_proto); if (!tfile) return -ENOMEM; - rcu_assign_pointer(tfile->tun, NULL); + RCU_INIT_POINTER(tfile->tun, NULL); tfile->net = get_net(current->nsproxy->net_ns); tfile->flags = 0; + tfile->ifindex = 0; - rcu_assign_pointer(tfile->socket.wq, &tfile->wq); init_waitqueue_head(&tfile->wq.wait); + RCU_INIT_POINTER(tfile->socket.wq, &tfile->wq); tfile->socket.file = file; tfile->socket.ops = &tun_socket_ops; @@ -2223,6 +2349,27 @@ static int tun_chr_close(struct inode *inode, struct file *file) return 0; } +#ifdef CONFIG_PROC_FS +static int tun_chr_show_fdinfo(struct seq_file *m, struct file *f) +{ + struct tun_struct *tun; + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + + rtnl_lock(); + tun = tun_get(f); + if (tun) + tun_get_iff(current->nsproxy->net_ns, tun, &ifr); + rtnl_unlock(); + + if (tun) + tun_put(tun); + + return seq_printf(m, "iff:\t%s\n", ifr.ifr_name); +} +#endif + static const struct file_operations tun_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -2237,7 +2384,10 @@ static const struct file_operations tun_fops = { #endif .open = tun_chr_open, .release = tun_chr_close, - .fasync = tun_chr_fasync + .fasync = tun_chr_fasync, +#ifdef CONFIG_PROC_FS + .show_fdinfo = tun_chr_show_fdinfo, +#endif }; static struct miscdevice tun_miscdev = { @@ -2305,6 +2455,7 @@ static const struct ethtool_ops tun_ethtool_ops = { .get_msglevel = tun_get_msglevel, .set_msglevel = tun_set_msglevel, .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, }; @@ -2313,7 +2464,6 @@ static int __init tun_init(void) int ret = 0; pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); - pr_info("%s\n", DRV_COPYRIGHT); ret = rtnl_link_register(&tun_link_ops); if (ret) { diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 88c08df5a976..11300560d751 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -771,6 +771,9 @@ static int ax88178_change_mtu(struct net_device *net, int new_mtu) dev->hard_mtu = net->mtu + net->hard_header_len; ax88178_set_mfb(dev); + /* max qlen depend on hard_mtu and rx_urb_size */ + usbnet_update_max_qlen(dev); + return 0; } diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 841841b47396..3b1fe210d216 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -688,6 +688,9 @@ static int ax88179_change_mtu(struct net_device *net, int new_mtu) 2, 2, &tmp16); } + /* max qlen depend on hard_mtu and rx_urb_size */ + usbnet_update_max_qlen(dev); + return 0; } diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 7d78669000d7..8c252cf51f43 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -328,7 +328,7 @@ MODULE_DEVICE_TABLE(usb, usbpn_ids); static struct usb_driver usbpn_driver; -int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) +static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) { static const char ifname[] = "usbpn%d"; const struct usb_cdc_union_desc *union_header = NULL; @@ -343,9 +343,9 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) data = intf->altsetting->extra; len = intf->altsetting->extralen; - while (len >= 3) { + while (len > 0) { u8 dlen = data[0]; - if (dlen < 3) + if ((len < dlen) || (dlen < 3 )) return -EINVAL; /* bDescriptorType */ diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index ea0a686a09eb..3097ee83ac97 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -128,7 +128,13 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) memset(info, 0, sizeof *info); info->control = intf; - while (len > 3) { + while (len > 0) { + + if ((len < buf [0]) || (buf [0] < 3)) { + dev_dbg(&intf->dev, "invalid descriptor buffer length\n"); + goto bad_desc; + } + if (buf [1] != USB_DT_CS_INTERFACE) goto next_desc; @@ -145,6 +151,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra CDC header\n"); goto bad_desc; } + if (len < sizeof(struct usb_cdc_header_desc)) + break; info->header = (void *) buf; if (info->header->bLength != sizeof *info->header) { dev_dbg(&intf->dev, "CDC header len %u\n", @@ -158,6 +166,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) */ if (rndis) { struct usb_cdc_acm_descriptor *acm; + if (len < sizeof(struct usb_cdc_acm_descriptor)) + break; acm = (void *) buf; if (acm->bmCapabilities) { @@ -174,6 +184,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra CDC union\n"); goto bad_desc; } + if (len < sizeof(struct usb_cdc_union_desc)) + break; info->u = (void *) buf; if (info->u->bLength != sizeof *info->u) { dev_dbg(&intf->dev, "CDC union len %u\n", @@ -228,6 +240,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra CDC ether\n"); goto bad_desc; } + if (len < sizeof(struct usb_cdc_ether_desc)) + break; info->ether = (void *) buf; if (info->ether->bLength != sizeof *info->ether) { dev_dbg(&intf->dev, "CDC ether len %u\n", @@ -245,7 +259,6 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra MDLM descriptor\n"); goto bad_desc; } - desc = (void *)buf; if (desc->bLength != sizeof(*desc)) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 7ac104b39c77..6b22884d3520 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -271,6 +271,7 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) /* if value changed, update device */ if (ctx->max_datagram_size != le16_to_cpu(max_datagram_size)) { + max_datagram_size = cpu_to_le16(ctx->max_datagram_size); err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE, USB_TYPE_CLASS | USB_DIR_OUT @@ -610,9 +611,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) return -ENODEV; - /* NCM data altsetting is always 1 */ - return cdc_ncm_bind_common(dev, intf, 1); - + return cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM); } static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max) @@ -1159,7 +1158,7 @@ static void cdc_ncm_disconnect(struct usb_interface *intf) static const struct driver_info cdc_ncm_info = { .description = "CDC NCM", .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET - | FLAG_LINK_INTR, + | FLAG_LINK_INTR, .bind = cdc_ncm_bind, .unbind = cdc_ncm_unbind, .check_connect = cdc_ncm_check_connect, diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 12aaf1f4f890..a713cffac07b 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -235,9 +235,14 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) info->data = intf; /* and a number of CDC descriptors */ - while (len > 3) { + while (len > 0) { struct usb_descriptor_header *h = (void *)buf; + if ((len < buf[0]) || (buf[0] < 3)) { + dev_dbg(&intf->dev, "invalid descriptor buffer length\n"); + goto err; + } + /* ignore any misplaced descriptors */ if (h->bDescriptorType != USB_DT_CS_INTERFACE) goto next_desc; @@ -823,6 +828,7 @@ MODULE_DEVICE_TABLE(usb, products); static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) { struct usb_device_id *id = (struct usb_device_id *)prod; + struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; /* Workaround to enable dynamic IDs. This disables usbnet * blacklisting functionality. Which, if required, can be @@ -834,6 +840,18 @@ static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id id->driver_info = (unsigned long)&qmi_wwan_info; } + /* There are devices where the same interface number can be + * configured as different functions. We should only bind to + * vendor specific functions when matching on interface number + */ + if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER && + desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) { + dev_dbg(&intf->dev, + "Rejecting interface number match for class %02x\n", + desc->bInterfaceClass); + return -ENODEV; + } + return usbnet_probe(intf, id); } diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c index 75e97832efa2..25ebe1361efd 100644 --- a/drivers/net/usb/rmnet_usb_ctrl.c +++ b/drivers/net/usb/rmnet_usb_ctrl.c @@ -1219,12 +1219,13 @@ skip_cudev_init: "%s%d", rmnet_dev_names[i], n); if (IS_ERR(dev->devicep)) { + long status = PTR_ERR(dev->devicep); pr_err("%s: device_create() returned %ld\n", - __func__, PTR_ERR(dev->devicep)); + __func__, status); cdev_del(&dev->cdev); free_rmnet_ctrl_udev(dev->cudev); kfree(dev); - return PTR_ERR(dev->devicep); + return status; } /*create /sys/class/hsicctl/hsicctlx/modem_wait*/ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 1c8a373273e5..e8f10461ca6f 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -59,15 +59,13 @@ * For high speed, each frame comfortably fits almost 36 max size * Ethernet packets (so queues should be bigger). * - * REVISIT qlens should be members of 'struct usbnet'; the goal is to - * let the USB host controller be busy for 5msec or more before an irq - * is required, under load. Jumbograms change the equation. + * The goal is to let the USB host controller be busy for 5msec or + * more before an irq is required, under load. Jumbograms change + * the equation. */ -#define RX_MAX_QUEUE_MEMORY (60 * 1518) -#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ - (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4) -#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ - (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4) +#define MAX_QUEUE_MEMORY (60 * 1518) +#define RX_QLEN(dev) ((dev)->rx_qlen) +#define TX_QLEN(dev) ((dev)->tx_qlen) // reawaken network queue this soon after stopping; else watchdog barks #define TX_TIMEOUT_JIFFIES (5*HZ) @@ -350,6 +348,31 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(usbnet_skb_return); +/* must be called if hard_mtu or rx_urb_size changed */ +void usbnet_update_max_qlen(struct usbnet *dev) +{ + enum usb_device_speed speed = dev->udev->speed; + + switch (speed) { + case USB_SPEED_HIGH: + dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size; + dev->tx_qlen = MAX_QUEUE_MEMORY / dev->hard_mtu; + break; + case USB_SPEED_SUPER: + /* + * Not take default 5ms qlen for super speed HC to + * save memory, and iperf tests show 2.5ms qlen can + * work well + */ + dev->rx_qlen = 5 * MAX_QUEUE_MEMORY / dev->rx_urb_size; + dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu; + break; + default: + dev->rx_qlen = dev->tx_qlen = 4; + } +} +EXPORT_SYMBOL_GPL(usbnet_update_max_qlen); + /*------------------------------------------------------------------------- * @@ -378,6 +401,9 @@ int usbnet_change_mtu (struct net_device *net, int new_mtu) usbnet_unlink_rx_urbs(dev); } + /* max qlen depend on hard_mtu and rx_urb_size */ + usbnet_update_max_qlen(dev); + return 0; } EXPORT_SYMBOL_GPL(usbnet_change_mtu); @@ -847,6 +873,9 @@ int usbnet_open (struct net_device *net) goto done; } + /* hard_mtu or rx_urb_size may change in reset() */ + usbnet_update_max_qlen(dev); + // insist peer be connected if (info->check_connect && (retval = info->check_connect (dev)) < 0) { netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval); @@ -931,6 +960,9 @@ int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd) if (dev->driver_info->link_reset) dev->driver_info->link_reset(dev); + /* hard_mtu or rx_urb_size may change in link_reset() */ + usbnet_update_max_qlen(dev); + return retval; } @@ -1024,16 +1056,34 @@ static void __handle_link_change(struct usbnet *dev) queue_work(usbnet_wq, &dev->bh_w); } + /* hard_mtu or rx_urb_size may change during link change */ + usbnet_update_max_qlen(dev); + clear_bit(EVENT_LINK_CHANGE, &dev->flags); } +static void usbnet_set_rx_mode(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + usbnet_defer_kevent(dev, EVENT_SET_RX_MODE); +} + +static void __handle_set_rx_mode(struct usbnet *dev) +{ + if (dev->driver_info->set_rx_mode) + (dev->driver_info->set_rx_mode)(dev); + + clear_bit(EVENT_SET_RX_MODE, &dev->flags); +} + /* work that cannot be done in interrupt context uses keventd. * * NOTE: with 2.5 we could do more of this using completion callbacks, * especially now that control transfers can be queued. */ static void -kevent (struct work_struct *work) +usbnet_deferred_kevent (struct work_struct *work) { struct usbnet *dev = container_of(work, struct usbnet, kevent); @@ -1132,6 +1182,10 @@ skip_reset: if (test_bit (EVENT_LINK_CHANGE, &dev->flags)) __handle_link_change(dev); + if (test_bit (EVENT_SET_RX_MODE, &dev->flags)) + __handle_set_rx_mode(dev); + + if (dev->flags) netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags); } @@ -1201,6 +1255,39 @@ EXPORT_SYMBOL_GPL(usbnet_tx_timeout); /*-------------------------------------------------------------------------*/ +static int build_dma_sg(const struct sk_buff *skb, struct urb *urb) +{ + unsigned num_sgs, total_len = 0; + int i, s = 0; + + num_sgs = skb_shinfo(skb)->nr_frags + 1; + if (num_sgs == 1) + return 0; + + /* reserve one for zero packet */ + urb->sg = kmalloc((num_sgs + 1) * sizeof(struct scatterlist), + GFP_ATOMIC); + if (!urb->sg) + return -ENOMEM; + + urb->num_sgs = num_sgs; + sg_init_table(urb->sg, urb->num_sgs + 1); + + sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb)); + total_len += skb_headlen(skb); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + struct skb_frag_struct *f = &skb_shinfo(skb)->frags[i]; + + total_len += skb_frag_size(f); + sg_set_page(&urb->sg[i + s], f->page.p, f->size, + f->page_offset); + } + urb->transfer_buffer_length = total_len; + + return 1; +} + netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) { @@ -1227,7 +1314,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, goto drop; } } - length = skb->len; if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { netif_dbg(dev, tx_err, dev->net, "no urb\n"); @@ -1237,10 +1323,14 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; - entry->length = length; usb_fill_bulk_urb (urb, dev->udev, dev->out, skb->data, skb->len, tx_complete, skb); + if (dev->can_dma_sg) { + if (build_dma_sg(skb, urb) < 0) + goto drop; + } + length = urb->transfer_buffer_length; /* don't assume the hardware handles USB_ZERO_PACKET * NOTE: strictly conforming cdc-ether devices should expect @@ -1252,15 +1342,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, if (length % dev->maxpacket == 0) { if (!(info->flags & FLAG_SEND_ZLP)) { if (!(info->flags & FLAG_MULTI_PACKET)) { - urb->transfer_buffer_length++; - if (skb_tailroom(skb)) { + length++; + if (skb_tailroom(skb) && !urb->num_sgs) { skb->data[skb->len] = 0; __skb_put(skb, 1); - } + } else if (urb->num_sgs) + sg_set_buf(&urb->sg[urb->num_sgs++], + dev->padding_pkt, 1); } } else urb->transfer_flags |= URB_ZERO_PACKET; } + entry->length = urb->transfer_buffer_length = length; spin_lock_irqsave(&dev->txq.lock, flags); retval = usb_autopm_get_interface_async(dev->intf); @@ -1309,7 +1402,10 @@ drop: not_drop: if (skb) dev_kfree_skb_any (skb); - usb_free_urb (urb); + if (urb) { + kfree(urb->sg); + usb_free_urb(urb); + } } else netif_dbg(dev, tx_queued, dev->net, "> tx, len %d, type 0x%x\n", length, skb->protocol); @@ -1361,6 +1457,7 @@ static void usbnet_bh (unsigned long param) rx_process (dev, skb); continue; case tx_done: + kfree(entry->urb->sg); case rx_cleanup: usb_free_urb (entry->urb); dev_kfree_skb (skb); @@ -1451,6 +1548,7 @@ void usbnet_disconnect (struct usb_interface *intf) usb_kill_urb(dev->interrupt); usb_free_urb(dev->interrupt); + kfree(dev->padding_pkt); free_netdev(net); } @@ -1461,6 +1559,7 @@ static const struct net_device_ops usbnet_netdev_ops = { .ndo_stop = usbnet_stop, .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, + .ndo_set_rx_mode = usbnet_set_rx_mode, .ndo_change_mtu = usbnet_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, @@ -1525,19 +1624,19 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->driver_name = name; dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK); - init_waitqueue_head(&dev->wait); + init_waitqueue_head (&dev->wait); skb_queue_head_init (&dev->rxq); skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->done); - skb_queue_head_init(&dev->rxq_pause); - INIT_WORK(&dev->bh_w, usbnet_bh_w); - INIT_WORK (&dev->kevent, kevent); + skb_queue_head_init (&dev->rxq_pause); + INIT_WORK (&dev->bh_w, usbnet_bh_w); + INIT_WORK (&dev->kevent, usbnet_deferred_kevent); init_usb_anchor(&dev->deferred); dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); mutex_init (&dev->phy_mutex); - mutex_init(&dev->interrupt_mutex); + mutex_init (&dev->interrupt_mutex); dev->interrupt_count = 0; dev->net = net; @@ -1609,14 +1708,30 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->rx_urb_size = dev->hard_mtu; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); + /* let userspace know we have a random address */ + if (ether_addr_equal(net->dev_addr, node_id)) + net->addr_assign_type = NET_ADDR_RANDOM; + if ((dev->driver_info->flags & FLAG_WLAN) != 0) SET_NETDEV_DEVTYPE(net, &wlan_type); if ((dev->driver_info->flags & FLAG_WWAN) != 0) SET_NETDEV_DEVTYPE(net, &wwan_type); + /* initialize max rx_qlen and tx_qlen */ + usbnet_update_max_qlen(dev); + + if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) && + !(info->flags & FLAG_MULTI_PACKET)) { + dev->padding_pkt = kzalloc(1, GFP_KERNEL); + if (!dev->padding_pkt) { + status = -ENOMEM; + goto out4; + } + } + status = register_netdev (net); if (status) - goto out4; + goto out5; netif_info(dev, probe, dev->net, "register '%s' at usb-%s-%s, %s, %pM\n", udev->dev.driver->name, @@ -1634,6 +1749,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) return 0; +out5: + kfree(dev->padding_pkt); out4: usb_free_urb(dev->interrupt); out3: @@ -1711,6 +1828,7 @@ int usbnet_resume (struct usb_interface *intf) retval = usb_submit_urb(res, GFP_ATOMIC); if (retval < 0) { dev_kfree_skb_any(skb); + kfree(res->sg); usb_free_urb(res); usb_autopm_put_interface_async(dev->intf); } else { diff --git a/drivers/net/veth.c b/drivers/net/veth.c index cc6d3f987436..ce9d113303f7 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -346,6 +346,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (ifmp && (dev->ifindex != 0)) peer->ifindex = ifmp->ifi_index; + peer->gso_max_size = dev->gso_max_size; + peer->gso_max_segs = dev->gso_max_segs; + err = register_netdevice(peer); put_net(net); net = NULL; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b5d11529a39b..830d5f275952 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -435,8 +435,17 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len) skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; break; case VIRTIO_NET_HDR_GSO_UDP: + { + static bool warned; + + if (!warned) { + warned = true; + netdev_warn(dev, + "host using disabled UFO feature; please fix it\n"); + } skb_shinfo(skb)->gso_type = SKB_GSO_UDP; break; + } case VIRTIO_NET_HDR_GSO_TCPV6: skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; break; @@ -735,8 +744,6 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; - else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP) - hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_UDP; else BUG(); if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN) @@ -1550,7 +1557,7 @@ static int virtnet_probe(struct virtio_device *vdev) dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { - dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO + dev->hw_features |= NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6; } /* Individual feature bits: what can host handle? */ @@ -1560,11 +1567,9 @@ static int virtnet_probe(struct virtio_device *vdev) dev->hw_features |= NETIF_F_TSO6; if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) dev->hw_features |= NETIF_F_TSO_ECN; - if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) - dev->hw_features |= NETIF_F_UFO; if (gso) - dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO); + dev->features |= dev->hw_features & NETIF_F_ALL_TSO; /* (!csum && gso) case will be fixed by register_netdev() */ } @@ -1597,8 +1602,7 @@ static int virtnet_probe(struct virtio_device *vdev) /* If we can receive ANY GSO packets, we must allocate large ones. */ if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO)) + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN)) vi->big_packets = true; if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) @@ -1781,9 +1785,9 @@ static struct virtio_device_id id_table[] = { static unsigned int features[] = { VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, - VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, + VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, - VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, + VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 8912ba83fd77..a49051d718c7 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -579,7 +579,7 @@ static bool vxlan_snoop(struct net_device *dev, return false; /* Don't migrate static entries, drop packets */ - if (f->state & NUD_NOARP) + if (f->state & (NUD_PERMANENT | NUD_NOARP)) return true; if (net_ratelimit()) diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index d43f4efd3e07..f041d180feb3 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -57,6 +57,7 @@ #include #include +#include #include #include @@ -176,7 +177,7 @@ static u32 mac[ SBNI_MAX_NUM_CARDS ] __initdata; #ifndef MODULE typedef u32 iarr[]; -static iarr __initdata *dest[5] = { &io, &irq, &baud, &rxl, &mac }; +static iarr *dest[5] __initdata = { &io, &irq, &baud, &rxl, &mac }; #endif /* A zero-terminated list of I/O addresses to be probed on ISA bus */ @@ -1360,6 +1361,8 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) if( !slave_dev || !(slave_dev->flags & IFF_UP) ) { netdev_err(dev, "trying to enslave non-active device %s\n", slave_name); + if (slave_dev) + dev_put(slave_dev); return -EPERM; } diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig index 626e47e6d214..37e9a097bd72 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -#config BCM4354 -# bool "Broadcom 4354 wireless card support" -# depends on BCMDHD -# ---help--- -# This module adds support for wireless adapters based on -# Broadcom 4354 chipset. +config BCM4354 + bool "Broadcom 4354 wireless card support" + depends on BCMDHD + ---help--- + This module adds support for wireless adapters based on + Broadcom 4354 chipset. config BCM43455 bool "Broadcom 43455 wireless cards support" @@ -44,14 +44,14 @@ endchoice config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" + default "/system/etc/firmware/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" + default "/system/etc/wifi/bcmdhd.cal" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig index a89ca15ef8f0..599f99af9cd4 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -#config BCM4354 -# bool "Broadcom 4354 wireless cards support" -# depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) -# ---help--- -# This module adds support for wireless adapters based on -# Broadcom 4354 chipset. +config BCM4354 + bool "Broadcom 4354 wireless cards support" + depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) + ---help--- + This module adds support for wireless adapters based on + Broadcom 4354 chipset. config BCM4356 bool "Broadcom 4356 wireless cards support" @@ -42,14 +42,14 @@ config BCM4356 config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" + default "/system/etc/firmware/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" + default "/system/etc/wifi/bcmdhd.cal" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/somcwifictrl/somc_wifi.c b/drivers/net/wireless/somcwifictrl/somc_wifi.c index 8b71de21a562..f60315e70057 100644 --- a/drivers/net/wireless/somcwifictrl/somc_wifi.c +++ b/drivers/net/wireless/somcwifictrl/somc_wifi.c @@ -1,3 +1,7 @@ +/* + * drivers/net/wireless/somcwifictrl/somc_wifi.c + * + */ /* * Copyright (C) 2015 Sony Mobile Communications Inc. * @@ -6,30 +10,19 @@ * published by the Free Software Foundation. */ #include -#include #include #include #include #include #include -#ifdef CONFIG_BCMDHD_PCIE #include -#endif /* CONFIG_BCMDHD_PCIE */ #include #include #include #include -#include -#include "dhd_custom_memprealloc.h" - -#if defined(CONFIG_MACH_SONY_SHINANO) -#include -#include -#include <../drivers/mmc/host/msm_sdcc.h> -#endif +#include -static char *intf_macaddr = NULL; -static struct mmc_host *wlan_mmc_host; +#include "dhd_custom_memprealloc.h" struct bcmdhd_platform_data { struct platform_device *pdev; @@ -37,144 +30,12 @@ struct bcmdhd_platform_data { struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; unsigned int wlan_reg_on; -#ifdef CONFIG_BCMDHD_PCIE unsigned int pci_number; -#endif /* CONFIG_BCMDHD_PCIE */ }; static struct bcmdhd_platform_data *bcmdhd_data; -void somc_wifi_mmc_host_register(struct mmc_host *host) -{ - wlan_mmc_host = host; -} - -#if !defined(CONFIG_MACH_SONY_SHINANO) -int somc_wifi_set_power(int on) -{ - gpio_set_value(bcmdhd_data->wlan_reg_on, on); - return 0; -} - -int somc_wifi_set_carddetect(int present) -{ -#ifdef CONFIG_BCMDHD_PCIE - int ret = 0; - if (present) - ret = msm_pcie_enumerate(bcmdhd_data->pci_number); - return ret; -#else - if (wlan_mmc_host) - mmc_detect_change(wlan_mmc_host, 0); - return 0; -#endif /* CONFIG_BCMDHD_PCIE */ -} -#else -#define WIFI_POWER_PMIC_GPIO 18 -#define WIFI_IRQ_GPIO 67 - -static unsigned int g_wifi_detect; -static void *sdc_dev; -void (*sdc_status_cb)(int card_present, void *dev); -static void *wifi_mmc_host; -static struct regulator *wifi_batfet; -static int batfet_ena; -extern void sdio_ctrl_power(struct mmc_host *card, bool onoff); - -int wcf_status_register(void (*cb)(int card_present, void *dev), void *dev) -{ - pr_info("%s\n", __func__); - - if (sdc_status_cb) - return -EINVAL; - - sdc_status_cb = cb; - sdc_dev = dev; - wifi_mmc_host = ((struct msmsdcc_host *)dev)->mmc; - - return 0; -} - -unsigned int wcf_status(struct device *dev) -{ - pr_info("%s: wifi_detect = %d\n", __func__, g_wifi_detect); - return g_wifi_detect; -} - -static int somc_wifi_set_reset(int on) -{ - return 0; -} - -int somc_wifi_set_power(int on) -{ - int gpio = qpnp_pin_map("pm8941-gpio", WIFI_POWER_PMIC_GPIO); - int ret; - - if (!wifi_batfet) { - wifi_batfet = regulator_get(NULL, "batfet"); - if (IS_ERR_OR_NULL(wifi_batfet)) { - printk(KERN_ERR "unable to get batfet reg. rc=%d\n", - PTR_RET(wifi_batfet)); - wifi_batfet = NULL; - } - } - if (on) { - if (!batfet_ena && wifi_batfet) { - ret = regulator_enable(wifi_batfet); - if (ret != 0) - pr_warn("%s: Can't enable batfet regulator!\n", - __func__); - batfet_ena = 1; - } - } - gpio_set_value(gpio, on); - if (!on) { - if (batfet_ena && wifi_batfet) { - regulator_disable(wifi_batfet); - batfet_ena = 0; - } - } - - sdio_ctrl_power((struct mmc_host *)wifi_mmc_host, on); - return 0; - -} - -int somc_wifi_set_carddetect(int present) -{ - g_wifi_detect = present; - - if (sdc_status_cb) - sdc_status_cb(present, sdc_dev); - else - printk(KERN_WARNING "%s: Nobody to notify\n", __func__); - return 0; -} -#endif /* CONFIG_MACH_SONY_SHINANO */ - -static ssize_t macaddr_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s", intf_macaddr); -} - -static ssize_t macaddr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return snprintf(intf_macaddr, count, "%s\n", buf); -} - -DEVICE_ATTR(macaddr, 0644, macaddr_show, macaddr_store); - -static struct attribute *wifi_attrs[] = { - &dev_attr_macaddr.attr, - NULL -}; - -static struct attribute_group wifi_attr_grp = { - .attrs = wifi_attrs, -}; +static struct mmc_host *wlan_mmc_host; int somc_wifi_init(struct platform_device *pdev) { @@ -241,7 +102,6 @@ int somc_wifi_init(struct platform_device *pdev) goto err_gpio; } -#ifdef CONFIG_BCMDHD_PCIE ret = of_property_read_u32(pdev->dev.of_node, "wlan-pci-number", &bcmdhd_data->pci_number); if (ret < 0) { @@ -249,20 +109,11 @@ int somc_wifi_init(struct platform_device *pdev) __func__, ret, bcmdhd_data->pci_number); goto err_gpio_request; } -#endif /* CONFIG_BCMDHD_PCIE */ - - intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); - if (sysfs_create_group(&pdev->dev.kobj, &wifi_attr_grp) < 0) { - pr_err("%s: Unable to create sysfs\n", __func__); - kfree(intf_macaddr); - } return 0; -#ifdef CONFIG_BCMDHD_PCIE err_gpio_request: gpio_free(bcmdhd_data->wlan_reg_on); -#endif /* CONFIG_BCMDHD_PCIE */ err_gpio: ret_sus = pinctrl_select_state(bcmdhd_data->pinctrl, bcmdhd_data->gpio_state_suspend); @@ -294,178 +145,41 @@ void somc_wifi_deinit(struct platform_device *pdev) } EXPORT_SYMBOL(somc_wifi_deinit); -#define ETHER_ADDR_LEN 6 - -static inline int xdigit (char c) -{ - unsigned d; - - d = (unsigned)(c-'0'); - if (d < 10) - return (int)d; - d = (unsigned)(c-'a'); - if (d < 6) - return (int)(10+d); - d = (unsigned)(c-'A'); - if (d < 6) - return (int)(10+d); - return -1; -} - -struct ether_addr { - unsigned char ether_addr_octet[ETHER_ADDR_LEN]; -} __attribute__((__packed__)); - -struct ether_addr * -ether_aton_r (const char *asc, struct ether_addr * addr) +void somc_wifi_mmc_host_register(struct mmc_host *host) { - int i, val0, val1; - - for (i = 0; i < ETHER_ADDR_LEN; ++i) { - val0 = xdigit(*asc); - asc++; - if (val0 < 0) - return NULL; - - val1 = xdigit(*asc); - asc++; - if (val1 < 0) - return NULL; - - addr->ether_addr_octet[i] = (unsigned char)((val0 << 4) + val1); - - if (i < ETHER_ADDR_LEN - 1) { - if (*asc != ':') - return NULL; - asc++; - } - } - - if (*asc != '\0') - return NULL; - - return addr; + wlan_mmc_host = host; } -struct ether_addr * ether_aton (const char *asc) +int somc_wifi_set_power(int on) { - static struct ether_addr addr; - return ether_aton_r(asc, &addr); + gpio_set_value(bcmdhd_data->wlan_reg_on, on); + return 0; } -static int somc_wifi_get_mac_addr(unsigned char *buf) +#ifdef CONFIG_BCMDHD_PCIE +int somc_wifi_set_carddetect(int present) { int ret = 0; - - char macasc[128] = {0,}; - uint rand_mac; - static unsigned char mymac[ETHER_ADDR_LEN] = {0,}; - const unsigned char nullmac[ETHER_ADDR_LEN] = {0,}; - - if (buf == NULL) - return -EAGAIN; - - memset(buf, 0x00, ETHER_ADDR_LEN); - - if (intf_macaddr != NULL) { - unsigned char* macbin; - struct ether_addr* convmac = ether_aton( intf_macaddr ); - - if (convmac == NULL) { - pr_err("%s: Invalid Mac Address Format %s\n", - __FUNCTION__, macasc ); - goto random_mac; - } - - macbin = convmac->ether_addr_octet; - - pr_info("%s: READ MAC ADDRESS %02X:%02X:%02X:%02X:%02X:%02X\n", - __FUNCTION__, - macbin[0], macbin[1], macbin[2], - macbin[3], macbin[4], macbin[5]); - - memcpy(buf, macbin, ETHER_ADDR_LEN); - } - + if (present) + ret = msm_pcie_enumerate_locked(bcmdhd_data->pci_number); return ret; - -random_mac: - - pr_debug("%s: %p\n", __func__, buf); - - if (memcmp( mymac, nullmac, ETHER_ADDR_LEN) != 0) { - /* Mac displayed from UI is never updated.. - So, mac obtained on initial time is used */ - memcpy(buf, mymac, ETHER_ADDR_LEN); - return 0; - } - - prandom_seed((uint)jiffies); - rand_mac = prandom_u32(); - buf[0] = 0x00; - buf[1] = 0x90; - buf[2] = 0x4c; - buf[3] = (unsigned char)rand_mac; - buf[4] = (unsigned char)(rand_mac >> 8); - buf[5] = (unsigned char)(rand_mac >> 16); - - memcpy(mymac, buf, 6); - - pr_info("[%s] Exiting. MAC %02X:%02X:%02X:%02X:%02X:%02X\n", - __FUNCTION__, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5] ); - +} +#else /* CONFIG_BCMDHD_PCIE */ +int somc_wifi_set_carddetect(int present) +{ + if (wlan_mmc_host) + mmc_detect_change(wlan_mmc_host, 0); return 0; } +#endif /* CONFIG_BCMDHD_PCIE */ struct wifi_platform_data somc_wifi_control = { .set_power = somc_wifi_set_power, -#if defined(CONFIG_MACH_SONY_SHINANO) - .set_reset = somc_wifi_set_reset, -#endif /* CONFIG_MACH_SONY_SHINANO */ .set_carddetect = somc_wifi_set_carddetect, +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM .mem_prealloc = dhd_wlan_mem_prealloc, - .get_mac_addr = somc_wifi_get_mac_addr, +#endif }; - EXPORT_SYMBOL(somc_wifi_control); -#if defined(CONFIG_MACH_SONY_SHINANO) -static struct resource somc_wifi_resources[] = { - [0] = { - .name = "bcmdhd_wlan_irq", - .start = 0, - .end = 0, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | - IORESOURCE_IRQ_SHAREABLE, - }, -}; - -static struct platform_device somc_wifi = { - .name = "bcmdhd_wlan", - .id = -1, - .num_resources = ARRAY_SIZE(somc_wifi_resources), - .resource = somc_wifi_resources, - .dev = { - .platform_data = &somc_wifi_control, - }, -}; - -static int __init somc_wifi_init_on_boot(void) -{ - somc_wifi.resource->start = gpio_to_irq(WIFI_IRQ_GPIO); - somc_wifi.resource->end = gpio_to_irq(WIFI_IRQ_GPIO); - platform_device_register(&somc_wifi); - - intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); - if (sysfs_create_group(&somc_wifi.dev.kobj, &wifi_attr_grp) < 0) { - pr_err("%s: Unable to create sysfs\n", __func__); - kfree(intf_macaddr); - } - return 0; -} - -device_initcall(somc_wifi_init_on_boot); -#endif /* CONFIG_MACH_SONY_SHINANO */ - MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index a1db958df4a4..8e85ce1ecdfb 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -820,7 +820,6 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np, struct sk_buff *skb, struct sk_buff_head *list) { - struct skb_shared_info *shinfo = skb_shinfo(skb); RING_IDX cons = np->rx.rsp_cons; struct sk_buff *nskb; @@ -829,15 +828,16 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np, RING_GET_RESPONSE(&np->rx, ++cons); skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0]; - if (shinfo->nr_frags == MAX_SKB_FRAGS) { + if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) { unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to; BUG_ON(pull_to <= skb_headlen(skb)); __pskb_pull_tail(skb, pull_to - skb_headlen(skb)); } - BUG_ON(shinfo->nr_frags >= MAX_SKB_FRAGS); + BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS); - skb_add_rx_frag(skb, shinfo->nr_frags, skb_frag_page(nfrag), + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + skb_frag_page(nfrag), rx->offset, rx->status, PAGE_SIZE); skb_shinfo(nskb)->nr_frags = 0; -- GitLab From e1ca556ae90bf497a840a31c4a5fde3e873f38fa Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 1 May 2021 21:14:40 +0200 Subject: [PATCH 255/528] Merge fixup for remotes/acherepkov/DEV_rc13 drivers/net/ --- drivers/net/wireless/bcmdhd_bcm43455/Kconfig | 16 +- drivers/net/wireless/bcmdhd_bcm4356/Kconfig | 16 +- drivers/net/wireless/somcwifictrl/somc_wifi.c | 336 ++++++++++++++++-- include/net/Space.h | 31 ++ 4 files changed, 358 insertions(+), 41 deletions(-) create mode 100644 include/net/Space.h diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig index 37e9a097bd72..626e47e6d214 100644 --- a/drivers/net/wireless/bcmdhd_bcm43455/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -config BCM4354 - bool "Broadcom 4354 wireless card support" - depends on BCMDHD - ---help--- - This module adds support for wireless adapters based on - Broadcom 4354 chipset. +#config BCM4354 +# bool "Broadcom 4354 wireless card support" +# depends on BCMDHD +# ---help--- +# This module adds support for wireless adapters based on +# Broadcom 4354 chipset. config BCM43455 bool "Broadcom 43455 wireless cards support" @@ -44,14 +44,14 @@ endchoice config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" + default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" + default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig index 599f99af9cd4..a89ca15ef8f0 100644 --- a/drivers/net/wireless/bcmdhd_bcm4356/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig @@ -25,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -config BCM4354 - bool "Broadcom 4354 wireless cards support" - depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) - ---help--- - This module adds support for wireless adapters based on - Broadcom 4354 chipset. +#config BCM4354 +# bool "Broadcom 4354 wireless cards support" +# depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) +# ---help--- +# This module adds support for wireless adapters based on +# Broadcom 4354 chipset. config BCM4356 bool "Broadcom 4356 wireless cards support" @@ -42,14 +42,14 @@ config BCM4356 config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" + default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" + default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/somcwifictrl/somc_wifi.c b/drivers/net/wireless/somcwifictrl/somc_wifi.c index f60315e70057..8b71de21a562 100644 --- a/drivers/net/wireless/somcwifictrl/somc_wifi.c +++ b/drivers/net/wireless/somcwifictrl/somc_wifi.c @@ -1,7 +1,3 @@ -/* - * drivers/net/wireless/somcwifictrl/somc_wifi.c - * - */ /* * Copyright (C) 2015 Sony Mobile Communications Inc. * @@ -10,32 +6,175 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include #include #include +#ifdef CONFIG_BCMDHD_PCIE #include +#endif /* CONFIG_BCMDHD_PCIE */ #include #include #include #include -#include - +#include #include "dhd_custom_memprealloc.h" +#if defined(CONFIG_MACH_SONY_SHINANO) +#include +#include +#include <../drivers/mmc/host/msm_sdcc.h> +#endif + +static char *intf_macaddr = NULL; +static struct mmc_host *wlan_mmc_host; + struct bcmdhd_platform_data { struct platform_device *pdev; struct pinctrl *pinctrl; struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; unsigned int wlan_reg_on; +#ifdef CONFIG_BCMDHD_PCIE unsigned int pci_number; +#endif /* CONFIG_BCMDHD_PCIE */ }; static struct bcmdhd_platform_data *bcmdhd_data; -static struct mmc_host *wlan_mmc_host; +void somc_wifi_mmc_host_register(struct mmc_host *host) +{ + wlan_mmc_host = host; +} + +#if !defined(CONFIG_MACH_SONY_SHINANO) +int somc_wifi_set_power(int on) +{ + gpio_set_value(bcmdhd_data->wlan_reg_on, on); + return 0; +} + +int somc_wifi_set_carddetect(int present) +{ +#ifdef CONFIG_BCMDHD_PCIE + int ret = 0; + if (present) + ret = msm_pcie_enumerate(bcmdhd_data->pci_number); + return ret; +#else + if (wlan_mmc_host) + mmc_detect_change(wlan_mmc_host, 0); + return 0; +#endif /* CONFIG_BCMDHD_PCIE */ +} +#else +#define WIFI_POWER_PMIC_GPIO 18 +#define WIFI_IRQ_GPIO 67 + +static unsigned int g_wifi_detect; +static void *sdc_dev; +void (*sdc_status_cb)(int card_present, void *dev); +static void *wifi_mmc_host; +static struct regulator *wifi_batfet; +static int batfet_ena; +extern void sdio_ctrl_power(struct mmc_host *card, bool onoff); + +int wcf_status_register(void (*cb)(int card_present, void *dev), void *dev) +{ + pr_info("%s\n", __func__); + + if (sdc_status_cb) + return -EINVAL; + + sdc_status_cb = cb; + sdc_dev = dev; + wifi_mmc_host = ((struct msmsdcc_host *)dev)->mmc; + + return 0; +} + +unsigned int wcf_status(struct device *dev) +{ + pr_info("%s: wifi_detect = %d\n", __func__, g_wifi_detect); + return g_wifi_detect; +} + +static int somc_wifi_set_reset(int on) +{ + return 0; +} + +int somc_wifi_set_power(int on) +{ + int gpio = qpnp_pin_map("pm8941-gpio", WIFI_POWER_PMIC_GPIO); + int ret; + + if (!wifi_batfet) { + wifi_batfet = regulator_get(NULL, "batfet"); + if (IS_ERR_OR_NULL(wifi_batfet)) { + printk(KERN_ERR "unable to get batfet reg. rc=%d\n", + PTR_RET(wifi_batfet)); + wifi_batfet = NULL; + } + } + if (on) { + if (!batfet_ena && wifi_batfet) { + ret = regulator_enable(wifi_batfet); + if (ret != 0) + pr_warn("%s: Can't enable batfet regulator!\n", + __func__); + batfet_ena = 1; + } + } + gpio_set_value(gpio, on); + if (!on) { + if (batfet_ena && wifi_batfet) { + regulator_disable(wifi_batfet); + batfet_ena = 0; + } + } + + sdio_ctrl_power((struct mmc_host *)wifi_mmc_host, on); + return 0; + +} + +int somc_wifi_set_carddetect(int present) +{ + g_wifi_detect = present; + + if (sdc_status_cb) + sdc_status_cb(present, sdc_dev); + else + printk(KERN_WARNING "%s: Nobody to notify\n", __func__); + return 0; +} +#endif /* CONFIG_MACH_SONY_SHINANO */ + +static ssize_t macaddr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s", intf_macaddr); +} + +static ssize_t macaddr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return snprintf(intf_macaddr, count, "%s\n", buf); +} + +DEVICE_ATTR(macaddr, 0644, macaddr_show, macaddr_store); + +static struct attribute *wifi_attrs[] = { + &dev_attr_macaddr.attr, + NULL +}; + +static struct attribute_group wifi_attr_grp = { + .attrs = wifi_attrs, +}; int somc_wifi_init(struct platform_device *pdev) { @@ -102,6 +241,7 @@ int somc_wifi_init(struct platform_device *pdev) goto err_gpio; } +#ifdef CONFIG_BCMDHD_PCIE ret = of_property_read_u32(pdev->dev.of_node, "wlan-pci-number", &bcmdhd_data->pci_number); if (ret < 0) { @@ -109,11 +249,20 @@ int somc_wifi_init(struct platform_device *pdev) __func__, ret, bcmdhd_data->pci_number); goto err_gpio_request; } +#endif /* CONFIG_BCMDHD_PCIE */ + + intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); + if (sysfs_create_group(&pdev->dev.kobj, &wifi_attr_grp) < 0) { + pr_err("%s: Unable to create sysfs\n", __func__); + kfree(intf_macaddr); + } return 0; +#ifdef CONFIG_BCMDHD_PCIE err_gpio_request: gpio_free(bcmdhd_data->wlan_reg_on); +#endif /* CONFIG_BCMDHD_PCIE */ err_gpio: ret_sus = pinctrl_select_state(bcmdhd_data->pinctrl, bcmdhd_data->gpio_state_suspend); @@ -145,41 +294,178 @@ void somc_wifi_deinit(struct platform_device *pdev) } EXPORT_SYMBOL(somc_wifi_deinit); -void somc_wifi_mmc_host_register(struct mmc_host *host) +#define ETHER_ADDR_LEN 6 + +static inline int xdigit (char c) { - wlan_mmc_host = host; + unsigned d; + + d = (unsigned)(c-'0'); + if (d < 10) + return (int)d; + d = (unsigned)(c-'a'); + if (d < 6) + return (int)(10+d); + d = (unsigned)(c-'A'); + if (d < 6) + return (int)(10+d); + return -1; } -int somc_wifi_set_power(int on) +struct ether_addr { + unsigned char ether_addr_octet[ETHER_ADDR_LEN]; +} __attribute__((__packed__)); + +struct ether_addr * +ether_aton_r (const char *asc, struct ether_addr * addr) { - gpio_set_value(bcmdhd_data->wlan_reg_on, on); - return 0; + int i, val0, val1; + + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + val0 = xdigit(*asc); + asc++; + if (val0 < 0) + return NULL; + + val1 = xdigit(*asc); + asc++; + if (val1 < 0) + return NULL; + + addr->ether_addr_octet[i] = (unsigned char)((val0 << 4) + val1); + + if (i < ETHER_ADDR_LEN - 1) { + if (*asc != ':') + return NULL; + asc++; + } + } + + if (*asc != '\0') + return NULL; + + return addr; } -#ifdef CONFIG_BCMDHD_PCIE -int somc_wifi_set_carddetect(int present) +struct ether_addr * ether_aton (const char *asc) { - int ret = 0; - if (present) - ret = msm_pcie_enumerate_locked(bcmdhd_data->pci_number); - return ret; + static struct ether_addr addr; + return ether_aton_r(asc, &addr); } -#else /* CONFIG_BCMDHD_PCIE */ -int somc_wifi_set_carddetect(int present) + +static int somc_wifi_get_mac_addr(unsigned char *buf) { - if (wlan_mmc_host) - mmc_detect_change(wlan_mmc_host, 0); + int ret = 0; + + char macasc[128] = {0,}; + uint rand_mac; + static unsigned char mymac[ETHER_ADDR_LEN] = {0,}; + const unsigned char nullmac[ETHER_ADDR_LEN] = {0,}; + + if (buf == NULL) + return -EAGAIN; + + memset(buf, 0x00, ETHER_ADDR_LEN); + + if (intf_macaddr != NULL) { + unsigned char* macbin; + struct ether_addr* convmac = ether_aton( intf_macaddr ); + + if (convmac == NULL) { + pr_err("%s: Invalid Mac Address Format %s\n", + __FUNCTION__, macasc ); + goto random_mac; + } + + macbin = convmac->ether_addr_octet; + + pr_info("%s: READ MAC ADDRESS %02X:%02X:%02X:%02X:%02X:%02X\n", + __FUNCTION__, + macbin[0], macbin[1], macbin[2], + macbin[3], macbin[4], macbin[5]); + + memcpy(buf, macbin, ETHER_ADDR_LEN); + } + + return ret; + +random_mac: + + pr_debug("%s: %p\n", __func__, buf); + + if (memcmp( mymac, nullmac, ETHER_ADDR_LEN) != 0) { + /* Mac displayed from UI is never updated.. + So, mac obtained on initial time is used */ + memcpy(buf, mymac, ETHER_ADDR_LEN); + return 0; + } + + prandom_seed((uint)jiffies); + rand_mac = prandom_u32(); + buf[0] = 0x00; + buf[1] = 0x90; + buf[2] = 0x4c; + buf[3] = (unsigned char)rand_mac; + buf[4] = (unsigned char)(rand_mac >> 8); + buf[5] = (unsigned char)(rand_mac >> 16); + + memcpy(mymac, buf, 6); + + pr_info("[%s] Exiting. MAC %02X:%02X:%02X:%02X:%02X:%02X\n", + __FUNCTION__, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5] ); + return 0; } -#endif /* CONFIG_BCMDHD_PCIE */ struct wifi_platform_data somc_wifi_control = { .set_power = somc_wifi_set_power, +#if defined(CONFIG_MACH_SONY_SHINANO) + .set_reset = somc_wifi_set_reset, +#endif /* CONFIG_MACH_SONY_SHINANO */ .set_carddetect = somc_wifi_set_carddetect, -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM .mem_prealloc = dhd_wlan_mem_prealloc, -#endif + .get_mac_addr = somc_wifi_get_mac_addr, }; + EXPORT_SYMBOL(somc_wifi_control); +#if defined(CONFIG_MACH_SONY_SHINANO) +static struct resource somc_wifi_resources[] = { + [0] = { + .name = "bcmdhd_wlan_irq", + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | + IORESOURCE_IRQ_SHAREABLE, + }, +}; + +static struct platform_device somc_wifi = { + .name = "bcmdhd_wlan", + .id = -1, + .num_resources = ARRAY_SIZE(somc_wifi_resources), + .resource = somc_wifi_resources, + .dev = { + .platform_data = &somc_wifi_control, + }, +}; + +static int __init somc_wifi_init_on_boot(void) +{ + somc_wifi.resource->start = gpio_to_irq(WIFI_IRQ_GPIO); + somc_wifi.resource->end = gpio_to_irq(WIFI_IRQ_GPIO); + platform_device_register(&somc_wifi); + + intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); + if (sysfs_create_group(&somc_wifi.dev.kobj, &wifi_attr_grp) < 0) { + pr_err("%s: Unable to create sysfs\n", __func__); + kfree(intf_macaddr); + } + return 0; +} + +device_initcall(somc_wifi_init_on_boot); +#endif /* CONFIG_MACH_SONY_SHINANO */ + MODULE_LICENSE("GPL v2"); diff --git a/include/net/Space.h b/include/net/Space.h new file mode 100644 index 000000000000..8a32771e4215 --- /dev/null +++ b/include/net/Space.h @@ -0,0 +1,31 @@ +/* A unified ethernet device probe. This is the easiest way to have every + * ethernet adaptor have the name "eth[0123...]". + */ + +struct net_device *hp100_probe(int unit); +struct net_device *ultra_probe(int unit); +struct net_device *wd_probe(int unit); +struct net_device *ne_probe(int unit); +struct net_device *fmv18x_probe(int unit); +struct net_device *i82596_probe(int unit); +struct net_device *ni65_probe(int unit); +struct net_device *sonic_probe(int unit); +struct net_device *smc_init(int unit); +struct net_device *atarilance_probe(int unit); +struct net_device *sun3lance_probe(int unit); +struct net_device *sun3_82586_probe(int unit); +struct net_device *apne_probe(int unit); +struct net_device *cs89x0_probe(int unit); +struct net_device *mvme147lance_probe(int unit); +struct net_device *tc515_probe(int unit); +struct net_device *lance_probe(int unit); +struct net_device *mac8390_probe(int unit); +struct net_device *mac89x0_probe(int unit); +struct net_device *cops_probe(int unit); +struct net_device *ltpc_probe(void); + +/* Fibre Channel adapters */ +int iph5526_probe(struct net_device *dev); + +/* SBNI adapters */ +int sbni_probe(int unit); -- GitLab From ac3235f867358c5df87fc4ff04a4ccae64393343 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 25 Jul 2013 13:47:53 +0800 Subject: [PATCH 256/528] USBNET: centralize computing of max rx/tx qlen This patch centralizes computing of max rx/tx qlen, because: - RX_QLEN()/TX_QLEN() is called in hot path - computing depends on device's usb speed, now we have ls/fs, hs, ss, so more checks need to be involved - in fact, max rx/tx qlen should not only depend on device USB speed, but also depend on ethernet link speed, so we need to consider that in future. - if SG support is done, max tx qlen may need change too Generally, hard_mtu and rx_urb_size are changed in bind(), reset() and link_reset() callback, and change mtu network operation, this patches introduces the API of usbnet_update_max_qlen(), and calls it in above path. Signed-off-by: Ming Lei Signed-off-by: David S. Miller [Upstream to 3.10: Adjust context] Signed-off-by: Andrey Cherepkov (cherry picked from commit 3bf91718459fba8467ad3fc90e618f21cd704939) --- include/linux/usb/usbnet.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index b2df2b81a2f3..4e9318e93bd8 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -34,6 +34,7 @@ struct usbnet { struct mutex phy_mutex; unsigned char suspend_count; unsigned char pkt_cnt, pkt_err; + unsigned short rx_qlen, tx_qlen; /* i/o info: pipes etc */ unsigned in, out; @@ -254,4 +255,6 @@ extern void usbnet_link_change(struct usbnet *, bool, bool); extern int usbnet_status_start(struct usbnet *dev, gfp_t mem_flags); extern void usbnet_status_stop(struct usbnet *dev); +extern void usbnet_update_max_qlen(struct usbnet *dev); + #endif /* __LINUX_USB_USBNET_H */ -- GitLab From 0802308a87619e87110516ee9b6c2a33ef860b1b Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Sun, 22 Dec 2013 18:54:31 +0800 Subject: [PATCH 257/528] net: Allow setting sock flow hash without a sock This patch adds sock_rps_record_flow_hash and sock_rps_reset_flow_hash which take a hash value as an argument and sets the sock_flow_table accordingly. This allows the table to be populated in cases where flow is being tracked outside of a sock structure. sock_rps_record_flow and sock_rps_reset_flow call this function where the hash is taken from sk_rxhash. Signed-off-by: Tom Herbert Signed-off-by: Zhi Yong Wu Signed-off-by: David S. Miller (cherry picked from commit 4f1cc93a9068145752e14ae392144351ffbf402a) --- include/net/sock.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index c8f589152cfd..c8c2d924050c 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -812,30 +812,40 @@ static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) return sk->sk_backlog_rcv(sk, skb); } -static inline void sock_rps_record_flow(const struct sock *sk) +static inline void sock_rps_record_flow_hash(__u32 hash) { #ifdef CONFIG_RPS struct rps_sock_flow_table *sock_flow_table; rcu_read_lock(); sock_flow_table = rcu_dereference(rps_sock_flow_table); - rps_record_sock_flow(sock_flow_table, sk->sk_rxhash); + rps_record_sock_flow(sock_flow_table, hash); rcu_read_unlock(); #endif } -static inline void sock_rps_reset_flow(const struct sock *sk) +static inline void sock_rps_reset_flow_hash(__u32 hash) { #ifdef CONFIG_RPS struct rps_sock_flow_table *sock_flow_table; rcu_read_lock(); sock_flow_table = rcu_dereference(rps_sock_flow_table); - rps_reset_sock_flow(sock_flow_table, sk->sk_rxhash); + rps_reset_sock_flow(sock_flow_table, hash); rcu_read_unlock(); #endif } +static inline void sock_rps_record_flow(const struct sock *sk) +{ + sock_rps_record_flow_hash(sk->sk_rxhash); +} + +static inline void sock_rps_reset_flow(const struct sock *sk) +{ + sock_rps_reset_flow_hash(sk->sk_rxhash); +} + static inline void sock_rps_save_rxhash(struct sock *sk, const struct sk_buff *skb) { -- GitLab From 53331aab67b30ed98b7f1b56225f96dd415dde70 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 1 May 2021 21:32:23 +0200 Subject: [PATCH 258/528] drivers: net: fix merge drivers/net --- drivers/net/tun.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ca3d19ce8064..f27c53006cb0 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -993,7 +993,7 @@ static struct sk_buff *tun_alloc_skb(struct tun_file *tfile, linear = len; skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock, - &err); + &err, 0); if (!skb) return ERR_PTR(err); -- GitLab From a8b60e9c4fe8659c2eb43c8b306cfc59a166ddf4 Mon Sep 17 00:00:00 2001 From: Gao Feng Date: Thu, 27 Oct 2016 09:05:22 +0800 Subject: [PATCH 259/528] driver: tun: Use new macro SOCK_IOC_TYPE instead of literal number 0x89 The current codes use _IOC_TYPE(cmd) == 0x89 to check if the cmd is one socket ioctl command like SIOCGIFHWADDR. But the literal number 0x89 may confuse readers. So create one macro SOCK_IOC_TYPE to enhance the readability. Signed-off-by: Gao Feng Signed-off-by: David S. Miller Signed-off-by: Andrey Cherepkov (cherry picked from commit 44d0025e006d0450de4e9e3eaf4dc56c2df22233) --- include/uapi/linux/sockios.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/sockios.h b/include/uapi/linux/sockios.h index f7ffe36db03c..01ee68ae7d1b 100644 --- a/include/uapi/linux/sockios.h +++ b/include/uapi/linux/sockios.h @@ -24,6 +24,8 @@ #define SIOCINQ FIONREAD #define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */ +#define SOCK_IOC_TYPE 0x89 + /* Routing table calls. */ #define SIOCADDRT 0x890B /* add routing table entry */ #define SIOCDELRT 0x890C /* delete routing table entry */ -- GitLab From db1605fe2e23c00cb5b720f50aefef93bbd67b5e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 21 Aug 2013 14:32:21 +0400 Subject: [PATCH 260/528] tun: Allow to skip filter on attach There's a small problem with sk-filters on tun devices. Consider an application doing this sequence of steps: fd = open("/dev/net/tun"); ioctl(fd, TUNSETIFF, { .ifr_name = "tun0" }); ioctl(fd, TUNATTACHFILTER, &my_filter); ioctl(fd, TUNSETPERSIST, 1); close(fd); At that point the tun0 will remain in the system and will keep in mind that there should be a socket filter at address '&my_filter'. If after that we do fd = open("/dev/net/tun"); ioctl(fd, TUNSETIFF, { .ifr_name = "tun0" }); we most likely receive the -EFAULT error, since tun_attach() would try to connect the filter back. But (!) if we provide a filter at address &my_filter, then tun0 will be created and the "new" filter would be attached, but application may not know about that. This may create certain problems to anyone using tun-s, but it's critical problem for c/r -- if we meet a persistent tun device with a filter in mind, we will not be able to attach to it to dump its state (flags, owner, address, vnethdr size, etc.). The proposal is to allow to attach to tun device (with TUNSETIFF) w/o attaching the filter to the tun-file's socket. After this attach app may e.g clean the device by dropping the filter, it doesn't want to have one, or (in case of c/r) get information about the device with tun ioctls. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Andrey Cherepkov (cherry picked from commit 4261cf5bdf899ee6f3bf8b4fa604086082b18de8) --- include/uapi/linux/if_tun.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h index 2835b85fd46d..f00189e140e4 100644 --- a/include/uapi/linux/if_tun.h +++ b/include/uapi/linux/if_tun.h @@ -68,6 +68,12 @@ #define IFF_MULTI_QUEUE 0x0100 #define IFF_ATTACH_QUEUE 0x0200 #define IFF_DETACH_QUEUE 0x0400 +/* read-only flag */ +#define IFF_PERSIST 0x0800 +#define IFF_NOFILTER 0x1000 + +/* Socket options */ +#define TUN_TX_TIMESTAMP 1 /* Features for GSO (TUNSETOFFLOAD). */ #define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ -- GitLab From 66e6c178cf3524b1bd7fc5b8861836d44221c833 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 23 Sep 2013 20:59:35 +0800 Subject: [PATCH 261/528] USBNET: fix handling padding packet Commit 638c5115a7949(USBNET: support DMA SG) introduces DMA SG if the usb host controller is capable of building packet from discontinuous buffers, but missed handling padding packet when building DMA SG. This patch attachs the pre-allocated padding packet at the end of the sg list, so padding packet can be sent to device if drivers require that. Reported-by: David Laight Acked-by: Oliver Neukum Signed-off-by: Ming Lei Signed-off-by: David S. Miller (cherry picked from commit 71cbbeec4a9a153669090a2eb4427f322cd1993b) --- include/linux/usb/usbnet.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 4e9318e93bd8..f5258f8efa75 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -41,6 +41,7 @@ struct usbnet { struct usb_host_endpoint *status; unsigned maxpacket; struct timer_list delay; + const char *padding_pkt; /* protocol/interface state */ struct net_device *net; -- GitLab From 76fd06dce145f9ce9ec8fdf7462ddf7019e8f5f4 Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Fri, 24 Oct 2014 19:43:00 +0200 Subject: [PATCH 262/528] usbnet: add a callback for set_rx_mode To delegate promiscuous mode and multicast filtering to the subdriver. Signed-off-by: Olivier Blin Signed-off-by: David S. Miller (cherry picked from commit 78f91df579f0ca8c9203e0bca0fbeb8e149549f3) --- include/linux/usb/usbnet.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index f5258f8efa75..79c911e022dc 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -77,6 +77,7 @@ struct usbnet { # define EVENT_NO_RUNTIME_PM 9 # define EVENT_RX_KILL 10 # define EVENT_LINK_CHANGE 11 +# define EVENT_SET_RX_MODE 12 }; static inline struct usb_driver *driver_of(struct usb_interface *intf) @@ -155,6 +156,9 @@ struct driver_info { /* called by minidriver when receiving indication */ void (*indication)(struct usbnet *dev, void *ind, int indlen); + /* rx mode change (device changes address list filtering) */ + void (*set_rx_mode)(struct usbnet *dev); + /* for new devices, use the descriptor-reading code instead */ int in; /* rx endpoint */ int out; /* tx endpoint */ -- GitLab From 4223092fc470cba30f0182ecca1a70a640b8e254 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 8 Aug 2013 21:48:24 +0800 Subject: [PATCH 263/528] USBNET: support DMA SG This patch introduces support of DMA SG if the USB host controller which usbnet device is attached to is capable of building packet from discontinuous buffers. The patch supports passing the skb fragment buffers to usb stack directly via urb->sg. Cc: Ben Hutchings Cc: Grant Grundler Cc: Freddy Xin Cc: Alan Stern Acked-by: Oliver Neukum Signed-off-by: Ming Lei Reviewed-by: Eric Dumazet Acked-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit c8aee98c5c42c881b60020473023304b31fe6f10) --- include/linux/usb/usbnet.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 79c911e022dc..a6b09f9bc46e 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -35,6 +35,7 @@ struct usbnet { unsigned char suspend_count; unsigned char pkt_cnt, pkt_err; unsigned short rx_qlen, tx_qlen; + unsigned can_dma_sg:1; /* i/o info: pipes etc */ unsigned in, out; -- GitLab From 608b43e88a0b7c83a54722bcdc11f8c681d684a7 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 30 Oct 2014 18:27:17 +0000 Subject: [PATCH 264/528] drivers/net, ipv6: Select IPv6 fragment idents for virtio UFO packets UFO is now disabled on all drivers that work with virtio net headers, but userland may try to send UFO/IPv6 packets anyway. Instead of sending with ID=0, we should select identifiers on their behalf (as we used to). Signed-off-by: Ben Hutchings Fixes: 916e4cf46d02 ("ipv6: reuse ip6_frag_id from ip6_ufo_append_data") Signed-off-by: David S. Miller Signed-off-by: Andrey Cherepkov (cherry picked from commit 1a14165de02959a73b9dae7e9538bf37f7753e87) --- include/net/ipv6.h | 2 ++ net/ipv6/output_core.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 1c581b99c64b..931f09d94b8e 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -682,6 +682,8 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); } +void ipv6_proxy_select_ident(struct sk_buff *skb); + /* * Header manipulation */ diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index d40ef970746b..6f71b7e0f075 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -3,9 +3,42 @@ * not configured or static. These functions are needed by GSO/GRO implementation. */ #include +#include #include #include +/* This function exists only for tap drivers that must support broken + * clients requesting UFO without specifying an IPv6 fragment ID. + * + * This is similar to ipv6_select_ident() but we use an independent hash + * seed to limit information leakage. + * + * The network header must be set before calling this. + */ +void ipv6_proxy_select_ident(struct sk_buff *skb) +{ + static u32 ip6_proxy_idents_hashrnd __read_mostly; + struct in6_addr buf[2]; + struct in6_addr *addrs; + u32 hash, id; + + addrs = skb_header_pointer(skb, + skb_network_offset(skb) + + offsetof(struct ipv6hdr, saddr), + sizeof(buf), buf); + if (!addrs) + return; + + net_get_random_once(&ip6_proxy_idents_hashrnd, + sizeof(ip6_proxy_idents_hashrnd)); + + hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd); + hash = __ipv6_addr_jhash(&addrs[0], hash); + + id = ip_idents_reserve(hash, 1); + skb_shinfo(skb)->ip6_frag_id = htonl(id); +} +EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) { -- GitLab From 44747f5f191da6a838f12eb5182dfd5378e1b975 Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Wed, 1 Jan 2014 04:31:01 +0800 Subject: [PATCH 265/528] net, rps: fix build failure when CONFIG_RPS isn't set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In file included from net/socket.c:99:0: include/net/sock.h: In function ‘sock_rps_record_flow’: include/net/sock.h:849:30: error: ‘const struct sock’ has no member named ‘sk_rxhash’ include/net/sock.h: In function ‘sock_rps_reset_flow’: include/net/sock.h:854:29: error: ‘const struct sock’ has no member named ‘sk_rxhash’ Reported-by: Fengguang Wu Signed-off-by: Zhi Yong Wu Signed-off-by: David S. Miller (cherry picked from commit 13e95c7126bbf4a2be64ed2185485797fa742972) --- include/net/sock.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/net/sock.h b/include/net/sock.h index c8c2d924050c..e4d8a4760ca9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -838,12 +838,16 @@ static inline void sock_rps_reset_flow_hash(__u32 hash) static inline void sock_rps_record_flow(const struct sock *sk) { +#ifdef CONFIG_RPS sock_rps_record_flow_hash(sk->sk_rxhash); +#endif } static inline void sock_rps_reset_flow(const struct sock *sk) { +#ifdef CONFIG_RPS sock_rps_reset_flow_hash(sk->sk_rxhash); +#endif } static inline void sock_rps_save_rxhash(struct sock *sk, -- GitLab From 8b033901013569a451e62ad4c63818c329e2863c Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 19 Jul 2013 19:40:09 +0200 Subject: [PATCH 266/528] net: Provide a generic socket error queue delivery method for Tx time stamps. This patch moves the private error queue delivery function from the af_packet code to the core socket method. In this way, network layers only needing the error queue for transmit time stamping can share common code. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller Signed-off-by: Andrey Cherepkov (cherry picked from commit 4b14afa96be957b0872cf8a71435a8c86f47be90) --- include/net/sock.h | 2 ++ net/core/sock.c | 47 +++++++++++++++++++++++++++++++++++++++++ net/packet/af_packet.c | 48 ++---------------------------------------- 3 files changed, 51 insertions(+), 46 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index e4d8a4760ca9..29ccc8346bbf 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2307,6 +2307,8 @@ bool sk_ns_capable(const struct sock *sk, struct user_namespace *user_ns, int cap); bool sk_capable(const struct sock *sk, int cap); bool sk_net_capable(const struct sock *sk, int cap); +extern int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, + int level, int type); /* * Enable debug/info messages diff --git a/net/core/sock.c b/net/core/sock.c index e6c357f91df5..1ac4d58a0097 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -98,6 +98,7 @@ #include #include +#include #include #include #include @@ -2486,6 +2487,52 @@ void sock_enable_timestamp(struct sock *sk, int flag) } } +int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, + int level, int type) +{ + struct sock_exterr_skb *serr; + struct sk_buff *skb, *skb2; + int copied, err; + + err = -EAGAIN; + skb = skb_dequeue(&sk->sk_error_queue); + if (skb == NULL) + goto out; + + copied = skb->len; + if (copied > len) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (err) + goto out_free_skb; + + sock_recv_timestamp(msg, sk, skb); + + serr = SKB_EXT_ERR(skb); + put_cmsg(msg, level, type, sizeof(serr->ee), &serr->ee); + + msg->msg_flags |= MSG_ERRQUEUE; + err = copied; + + /* Reset and regenerate socket error */ + spin_lock_bh(&sk->sk_error_queue.lock); + sk->sk_err = 0; + if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { + sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; + spin_unlock_bh(&sk->sk_error_queue.lock); + sk->sk_error_report(sk); + } else + spin_unlock_bh(&sk->sk_error_queue.lock); + +out_free_skb: + kfree_skb(skb); +out: + return err; +} +EXPORT_SYMBOL(sock_recv_errqueue); + /* * Get a socket option on an socket. * diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6f1abd03d8aa..7899cf1c2d05 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2700,51 +2700,6 @@ out: return err; } -static int packet_recv_error(struct sock *sk, struct msghdr *msg, int len) -{ - struct sock_exterr_skb *serr; - struct sk_buff *skb, *skb2; - int copied, err; - - err = -EAGAIN; - skb = skb_dequeue(&sk->sk_error_queue); - if (skb == NULL) - goto out; - - copied = skb->len; - if (copied > len) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - if (err) - goto out_free_skb; - - sock_recv_timestamp(msg, sk, skb); - - serr = SKB_EXT_ERR(skb); - put_cmsg(msg, SOL_PACKET, PACKET_TX_TIMESTAMP, - sizeof(serr->ee), &serr->ee); - - msg->msg_flags |= MSG_ERRQUEUE; - err = copied; - - /* Reset and regenerate socket error */ - spin_lock_bh(&sk->sk_error_queue.lock); - sk->sk_err = 0; - if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { - sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; - spin_unlock_bh(&sk->sk_error_queue.lock); - sk->sk_error_report(sk); - } else - spin_unlock_bh(&sk->sk_error_queue.lock); - -out_free_skb: - kfree_skb(skb); -out: - return err; -} - /* * Pull a packet from our receive queue and hand it to the user. * If necessary we block. @@ -2769,7 +2724,8 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, #endif if (flags & MSG_ERRQUEUE) { - err = packet_recv_error(sk, msg, len); + err = sock_recv_errqueue(sk, msg, len, + SOL_PACKET, PACKET_TX_TIMESTAMP); goto out; } -- GitLab From 11b32eb7d85a93b39ee609f9980042f50a96f3da Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 21 Aug 2013 14:31:38 +0400 Subject: [PATCH 267/528] tun: Add ability to create tun device with given index Tun devices cannot be created with ifidex user wants, but it's required by checkpoint-restore project. Long time ago such ability was implemented for rtnl_ops-based interface for creating links (9c7dafbf net: Allow to create links with given ifindex), but the only API for creating and managing tuntap devices is ioctl-based and is evolving with adding new ones (cde8b15f tuntap: add ioctl to attach or detach a file form tuntap device). Following that trend, here's how a new ioctl that sets the ifindex for device, that _will_ be created by TUNSETIFF ioctl looks like. So those who want a tuntap device with the ifindex N, should open the tun device, call ioctl(fd, TUNSETIFINDEX, &N), then call TUNSETIFF. If the index N is busy, then the register_netdev will find this out and the ioctl would be failed with -EBUSY. If setifindex is not called, then it will be generated as before. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Andrey Cherepkov (cherry picked from commit df73dbed9625c3cadaae75cc4c323d8c606d40d7) --- include/uapi/linux/if_tun.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h index f00189e140e4..cc127b2b4c3d 100644 --- a/include/uapi/linux/if_tun.h +++ b/include/uapi/linux/if_tun.h @@ -56,6 +56,7 @@ #define TUNGETVNETHDRSZ _IOR('T', 215, int) #define TUNSETVNETHDRSZ _IOW('T', 216, int) #define TUNSETQUEUE _IOW('T', 217, int) +#define TUNSETIFINDEX _IOW('T', 218, unsigned int) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 -- GitLab From bb943f7d3aa062f20b7d92414c77417b37472848 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 13 Oct 2017 11:58:53 -0700 Subject: [PATCH 268/528] tun: call dev_get_valid_name() before register_netdevice() [ Upstream commit 0ad646c81b2182f7fa67ec0c8c825e0ee165696d ] register_netdevice() could fail early when we have an invalid dev name, in which case ->ndo_uninit() is not called. For tun device, this is a problem because a timer etc. are already initialized and it expects ->ndo_uninit() to clean them up. We could move these initializations into a ->ndo_init() so that register_netdevice() knows better, however this is still complicated due to the logic in tun_detach(). Therefore, I choose to just call dev_get_valid_name() before register_netdevice(), which is quicker and much easier to audit. And for this specific case, it is already enough. Fixes: 96442e42429e ("tuntap: choose the txq based on rxq") Reported-by: Dmitry Alexeev Cc: Jason Wang Cc: "Michael S. Tsirkin" Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Harsh Shandilya (cherry picked from commit 1069c56316859e25c7779bf3159c42989ccf06cf) --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index fddc4bf17d4a..ed3778f37a14 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2599,6 +2599,8 @@ extern void ether_setup(struct net_device *dev); extern struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, void (*setup)(struct net_device *), unsigned int txqs, unsigned int rxqs); +extern int dev_get_valid_name(struct net *net, struct net_device *dev, + const char *name); #define alloc_netdev(sizeof_priv, name, setup) \ alloc_netdev_mqs(sizeof_priv, name, setup, 1, 1) diff --git a/net/core/dev.c b/net/core/dev.c index 0037a6601218..e6bff4f00a15 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1043,9 +1043,8 @@ static int dev_alloc_name_ns(struct net *net, return ret; } -static int dev_get_valid_name(struct net *net, - struct net_device *dev, - const char *name) +int dev_get_valid_name(struct net *net, struct net_device *dev, + const char *name) { BUG_ON(!net); @@ -1061,6 +1060,7 @@ static int dev_get_valid_name(struct net *net, return 0; } +EXPORT_SYMBOL(dev_get_valid_name); /** * dev_change_name - change name of a device -- GitLab From 3d71e4dfe89d4759e96c698365c7b87d6c5acb46 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 21 Aug 2013 14:32:39 +0400 Subject: [PATCH 269/528] tun: Get skfilter layout The only thing we may have from tun device is the fprog, whic contains the number of filter elements and a pointer to (user-space) memory where the elements are. The program itself may not be available if the device is persistent and detached. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller (cherry picked from commit e8a5597fc1a8cdb6465d60097ffb35e9acd1a36e) --- include/uapi/linux/if_tun.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h index cc127b2b4c3d..e9502dd1ee2c 100644 --- a/include/uapi/linux/if_tun.h +++ b/include/uapi/linux/if_tun.h @@ -57,6 +57,7 @@ #define TUNSETVNETHDRSZ _IOW('T', 216, int) #define TUNSETQUEUE _IOW('T', 217, int) #define TUNSETIFINDEX _IOW('T', 218, unsigned int) +#define TUNGETFILTER _IOR('T', 219, struct sock_fprog) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 -- GitLab From 2d6955af405273536191f988845433e7332e0f92 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Sat, 19 Oct 2013 21:48:55 +0200 Subject: [PATCH 270/528] net: introduce new macro net_get_random_once net_get_random_once is a new macro which handles the initialization of secret keys. It is possible to call it in the fast path. Only the initialization depends on the spinlock and is rather slow. Otherwise it should get used just before the key is used to delay the entropy extration as late as possible to get better randomness. It returns true if the key got initialized. The usage of static_keys for net_get_random_once is a bit uncommon so it needs some further explanation why this actually works: === In the simple non-HAVE_JUMP_LABEL case we actually have === no constrains to use static_key_(true|false) on keys initialized with STATIC_KEY_INIT_(FALSE|TRUE). So this path just expands in favor of the likely case that the initialization is already done. The key is initialized like this: ___done_key = { .enabled = ATOMIC_INIT(0) } The check if (!static_key_true(&___done_key)) \ expands into (pseudo code) if (!likely(___done_key > 0)) , so we take the fast path as soon as ___done_key is increased from the helper function. === If HAVE_JUMP_LABELs are available this depends === on patching of jumps into the prepared NOPs, which is done in jump_label_init at boot-up time (from start_kernel). It is forbidden and dangerous to use net_get_random_once in functions which are called before that! At compilation time NOPs are generated at the call sites of net_get_random_once. E.g. net/ipv6/inet6_hashtable.c:inet6_ehashfn (we need to call net_get_random_once two times in inet6_ehashfn, so two NOPs): 71: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 76: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) Both will be patched to the actual jumps to the end of the function to call __net_get_random_once at boot time as explained above. arch_static_branch is optimized and inlined for false as return value and actually also returns false in case the NOP is placed in the instruction stream. So in the fast case we get a "return false". But because we initialize ___done_key with (enabled != (entries & 1)) this call-site will get patched up at boot thus returning true. The final check looks like this: if (!static_key_true(&___done_key)) \ ___ret = __net_get_random_once(buf, \ expands to if (!!static_key_false(&___done_key)) \ ___ret = __net_get_random_once(buf, \ So we get true at boot time and as soon as static_key_slow_inc is called on the key it will invert the logic and return false for the fast path. static_key_slow_inc will change the branch because it got initialized with .enabled == 0. After static_key_slow_inc is called on the key the branch is replaced with a nop again. === Misc: === The helper defers the increment into a workqueue so we don't have problems calling this code from atomic sections. A seperate boolean (___done) guards the case where we enter net_get_random_once again before the increment happend. Cc: Ingo Molnar Cc: Steven Rostedt Cc: Jason Baron Cc: Peter Zijlstra Cc: Eric Dumazet Cc: "David S. Miller" Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Andrey Cherepkov (cherry picked from commit 507412cace51b17391833b8865cc94a13d134b03) --- include/linux/net.h | 25 +++++++++++++++++++++++ net/core/utils.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/include/linux/net.h b/include/linux/net.h index 65545ac6fb9c..bf2f43c27f31 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -251,6 +251,31 @@ do { \ #define net_random() prandom_u32() #define net_srandom(seed) prandom_seed((__force u32)(seed)) +bool __net_get_random_once(void *buf, int nbytes, bool *done, + struct static_key *done_key); + +#ifdef HAVE_JUMP_LABEL +#define ___NET_RANDOM_STATIC_KEY_INIT ((struct static_key) \ + { .enabled = ATOMIC_INIT(0), .entries = (void *)1 }) +#else /* !HAVE_JUMP_LABEL */ +#define ___NET_RANDOM_STATIC_KEY_INIT STATIC_KEY_INIT_FALSE +#endif /* HAVE_JUMP_LABEL */ + +/* BE CAREFUL: this function is not interrupt safe */ +#define net_get_random_once(buf, nbytes) \ + ({ \ + bool ___ret = false; \ + static bool ___done = false; \ + static struct static_key ___done_key = \ + ___NET_RANDOM_STATIC_KEY_INIT; \ + if (!static_key_true(&___done_key)) \ + ___ret = __net_get_random_once(buf, \ + nbytes, \ + &___done, \ + &___done_key); \ + ___ret; \ + }) + extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t len); extern int kernel_recvmsg(struct socket *sock, struct msghdr *msg, diff --git a/net/core/utils.c b/net/core/utils.c index 3c7f5b51b979..1d669bd81ddd 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -360,3 +360,51 @@ int mac_pton(const char *s, u8 *mac) return 1; } EXPORT_SYMBOL(mac_pton); + +struct __net_random_once_work { + struct work_struct work; + struct static_key *key; +}; + +static void __net_random_once_deferred(struct work_struct *w) +{ + struct __net_random_once_work *work = + container_of(w, struct __net_random_once_work, work); + if (!static_key_enabled(work->key)) + static_key_slow_inc(work->key); + kfree(work); +} + +static void __net_random_once_disable_jump(struct static_key *key) +{ + struct __net_random_once_work *w; + + w = kmalloc(sizeof(*w), GFP_ATOMIC); + if (!w) + return; + + INIT_WORK(&w->work, __net_random_once_deferred); + w->key = key; + schedule_work(&w->work); +} + +bool __net_get_random_once(void *buf, int nbytes, bool *done, + struct static_key *done_key) +{ + static DEFINE_SPINLOCK(lock); + + spin_lock_bh(&lock); + if (*done) { + spin_unlock_bh(&lock); + return false; + } + + get_random_bytes(buf, nbytes); + *done = true; + spin_unlock_bh(&lock); + + __net_random_once_disable_jump(done_key); + + return true; +} +EXPORT_SYMBOL(__net_get_random_once); -- GitLab From d12883241165e0d4f4b7fa907f596b14f21dddf2 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Sun, 20 Oct 2013 06:26:02 +0200 Subject: [PATCH 271/528] net: fix build warnings because of net_get_random_once merge This patch fixes the following warning: In file included from include/linux/skbuff.h:27:0, from include/linux/netfilter.h:5, from include/net/netns/netfilter.h:5, from include/net/net_namespace.h:20, from include/linux/init_task.h:14, from init/init_task.c:1: include/linux/net.h:243:14: warning: 'struct static_key' declared inside parameter list [enabled by default] struct static_key *done_key); on x86_64 allnoconfig, um defconfig and ia64 allmodconfig and maybe others as well. Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller (cherry picked from commit 394b2021ab9deb0694074502685d71acf354a364) --- include/linux/net.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/net.h b/include/linux/net.h index bf2f43c27f31..085232b93fec 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -24,6 +24,7 @@ #include /* For O_CLOEXEC and O_NONBLOCK */ #include #include +#include #include struct poll_table_struct; -- GitLab From 448ae18c687dd7c1e083a353a082bfa68de76cbc Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Wed, 23 Oct 2013 20:05:27 +0200 Subject: [PATCH 272/528] net: make net_get_random_once irq safe I initial build non irq safe version of net_get_random_once because I would liked to have the freedom to defer even the extraction process of get_random_bytes until the nonblocking pool is fully seeded. I don't think this is a good idea anymore and thus this patch makes net_get_random_once irq safe. Now someone using net_get_random_once does not need to care from where it is called. Cc: David S. Miller Cc: Eric Dumazet Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller (cherry picked from commit 6a62fba7fdcc09805586a12e565a6ac99431363c) --- include/linux/net.h | 1 - net/core/utils.c | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/net.h b/include/linux/net.h index 085232b93fec..fbfc8f01161f 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -262,7 +262,6 @@ bool __net_get_random_once(void *buf, int nbytes, bool *done, #define ___NET_RANDOM_STATIC_KEY_INIT STATIC_KEY_INIT_FALSE #endif /* HAVE_JUMP_LABEL */ -/* BE CAREFUL: this function is not interrupt safe */ #define net_get_random_once(buf, nbytes) \ ({ \ bool ___ret = false; \ diff --git a/net/core/utils.c b/net/core/utils.c index 1d669bd81ddd..2e22c46e9b0c 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -392,16 +392,17 @@ bool __net_get_random_once(void *buf, int nbytes, bool *done, struct static_key *done_key) { static DEFINE_SPINLOCK(lock); + unsigned long flags; - spin_lock_bh(&lock); + spin_lock_irqsave(&lock, flags); if (*done) { - spin_unlock_bh(&lock); + spin_unlock_irqrestore(&lock, flags); return false; } get_random_bytes(buf, nbytes); *done = true; - spin_unlock_bh(&lock); + spin_unlock_irqrestore(&lock, flags); __net_random_once_disable_jump(done_key); -- GitLab From 9ae557bd709764e7fa22e26ca39bc2fc69f97c07 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Sun, 11 May 2014 22:59:30 +0200 Subject: [PATCH 273/528] net: avoid dependency of net_get_random_once on nop patching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net_get_random_once depends on the static keys infrastructure to patch up the branch to the slow path during boot. This was realized by abusing the static keys api and defining a new initializer to not enable the call site while still indicating that the branch point should get patched up. This was needed to have the fast path considered likely by gcc. The static key initialization during boot up normally walks through all the registered keys and either patches in ideal nops or enables the jump site but omitted that step on x86 if ideal nops where already placed at static_key branch points. Thus net_get_random_once branches not always became active. This patch switches net_get_random_once to the ordinary static_key api and thus places the kernel fast path in the - by gcc considered - unlikely path. Microbenchmarks on Intel and AMD x86-64 showed that the unlikely path actually beats the likely path in terms of cycle cost and that different nop patterns did not make much difference, thus this switch should not be noticeable. Fixes: a48e42920ff38b ("net: introduce new macro net_get_random_once") Reported-by: Tuomas Räsänen Cc: Linus Torvalds Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller (cherry picked from commit 8816579f96bcc77162ba5c3b46bd5cfc42d0d924) --- include/linux/net.h | 15 ++++----------- net/core/utils.c | 8 ++++---- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/include/linux/net.h b/include/linux/net.h index fbfc8f01161f..e55ae4872891 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -255,24 +255,17 @@ do { \ bool __net_get_random_once(void *buf, int nbytes, bool *done, struct static_key *done_key); -#ifdef HAVE_JUMP_LABEL -#define ___NET_RANDOM_STATIC_KEY_INIT ((struct static_key) \ - { .enabled = ATOMIC_INIT(0), .entries = (void *)1 }) -#else /* !HAVE_JUMP_LABEL */ -#define ___NET_RANDOM_STATIC_KEY_INIT STATIC_KEY_INIT_FALSE -#endif /* HAVE_JUMP_LABEL */ - #define net_get_random_once(buf, nbytes) \ ({ \ bool ___ret = false; \ static bool ___done = false; \ - static struct static_key ___done_key = \ - ___NET_RANDOM_STATIC_KEY_INIT; \ - if (!static_key_true(&___done_key)) \ + static struct static_key ___once_key = \ + STATIC_KEY_INIT_TRUE; \ + if (static_key_true(&___once_key)) \ ___ret = __net_get_random_once(buf, \ nbytes, \ &___done, \ - &___done_key); \ + &___once_key); \ ___ret; \ }) diff --git a/net/core/utils.c b/net/core/utils.c index 2e22c46e9b0c..2e2cd88e1d9a 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -370,8 +370,8 @@ static void __net_random_once_deferred(struct work_struct *w) { struct __net_random_once_work *work = container_of(w, struct __net_random_once_work, work); - if (!static_key_enabled(work->key)) - static_key_slow_inc(work->key); + BUG_ON(!static_key_enabled(work->key)); + static_key_slow_dec(work->key); kfree(work); } @@ -389,7 +389,7 @@ static void __net_random_once_disable_jump(struct static_key *key) } bool __net_get_random_once(void *buf, int nbytes, bool *done, - struct static_key *done_key) + struct static_key *once_key) { static DEFINE_SPINLOCK(lock); unsigned long flags; @@ -404,7 +404,7 @@ bool __net_get_random_once(void *buf, int nbytes, bool *done, *done = true; spin_unlock_irqrestore(&lock, flags); - __net_random_once_disable_jump(done_key); + __net_random_once_disable_jump(once_key); return true; } -- GitLab From 307358077bb4f5efcc06867e8b8bd6154b7db394 Mon Sep 17 00:00:00 2001 From: Mike B Date: Sun, 2 May 2021 22:02:21 +0200 Subject: [PATCH 274/528] net: wireless: somcwifictl: The xperia LA.BR.1.3.3 version will not work with kitakami_suzuran in this configuration, at least - reverting to original --- drivers/net/wireless/somcwifictrl/somc_wifi.c | 336 ++---------------- 1 file changed, 25 insertions(+), 311 deletions(-) diff --git a/drivers/net/wireless/somcwifictrl/somc_wifi.c b/drivers/net/wireless/somcwifictrl/somc_wifi.c index 8b71de21a562..f60315e70057 100644 --- a/drivers/net/wireless/somcwifictrl/somc_wifi.c +++ b/drivers/net/wireless/somcwifictrl/somc_wifi.c @@ -1,3 +1,7 @@ +/* + * drivers/net/wireless/somcwifictrl/somc_wifi.c + * + */ /* * Copyright (C) 2015 Sony Mobile Communications Inc. * @@ -6,30 +10,19 @@ * published by the Free Software Foundation. */ #include -#include #include #include #include #include #include -#ifdef CONFIG_BCMDHD_PCIE #include -#endif /* CONFIG_BCMDHD_PCIE */ #include #include #include #include -#include -#include "dhd_custom_memprealloc.h" - -#if defined(CONFIG_MACH_SONY_SHINANO) -#include -#include -#include <../drivers/mmc/host/msm_sdcc.h> -#endif +#include -static char *intf_macaddr = NULL; -static struct mmc_host *wlan_mmc_host; +#include "dhd_custom_memprealloc.h" struct bcmdhd_platform_data { struct platform_device *pdev; @@ -37,144 +30,12 @@ struct bcmdhd_platform_data { struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; unsigned int wlan_reg_on; -#ifdef CONFIG_BCMDHD_PCIE unsigned int pci_number; -#endif /* CONFIG_BCMDHD_PCIE */ }; static struct bcmdhd_platform_data *bcmdhd_data; -void somc_wifi_mmc_host_register(struct mmc_host *host) -{ - wlan_mmc_host = host; -} - -#if !defined(CONFIG_MACH_SONY_SHINANO) -int somc_wifi_set_power(int on) -{ - gpio_set_value(bcmdhd_data->wlan_reg_on, on); - return 0; -} - -int somc_wifi_set_carddetect(int present) -{ -#ifdef CONFIG_BCMDHD_PCIE - int ret = 0; - if (present) - ret = msm_pcie_enumerate(bcmdhd_data->pci_number); - return ret; -#else - if (wlan_mmc_host) - mmc_detect_change(wlan_mmc_host, 0); - return 0; -#endif /* CONFIG_BCMDHD_PCIE */ -} -#else -#define WIFI_POWER_PMIC_GPIO 18 -#define WIFI_IRQ_GPIO 67 - -static unsigned int g_wifi_detect; -static void *sdc_dev; -void (*sdc_status_cb)(int card_present, void *dev); -static void *wifi_mmc_host; -static struct regulator *wifi_batfet; -static int batfet_ena; -extern void sdio_ctrl_power(struct mmc_host *card, bool onoff); - -int wcf_status_register(void (*cb)(int card_present, void *dev), void *dev) -{ - pr_info("%s\n", __func__); - - if (sdc_status_cb) - return -EINVAL; - - sdc_status_cb = cb; - sdc_dev = dev; - wifi_mmc_host = ((struct msmsdcc_host *)dev)->mmc; - - return 0; -} - -unsigned int wcf_status(struct device *dev) -{ - pr_info("%s: wifi_detect = %d\n", __func__, g_wifi_detect); - return g_wifi_detect; -} - -static int somc_wifi_set_reset(int on) -{ - return 0; -} - -int somc_wifi_set_power(int on) -{ - int gpio = qpnp_pin_map("pm8941-gpio", WIFI_POWER_PMIC_GPIO); - int ret; - - if (!wifi_batfet) { - wifi_batfet = regulator_get(NULL, "batfet"); - if (IS_ERR_OR_NULL(wifi_batfet)) { - printk(KERN_ERR "unable to get batfet reg. rc=%d\n", - PTR_RET(wifi_batfet)); - wifi_batfet = NULL; - } - } - if (on) { - if (!batfet_ena && wifi_batfet) { - ret = regulator_enable(wifi_batfet); - if (ret != 0) - pr_warn("%s: Can't enable batfet regulator!\n", - __func__); - batfet_ena = 1; - } - } - gpio_set_value(gpio, on); - if (!on) { - if (batfet_ena && wifi_batfet) { - regulator_disable(wifi_batfet); - batfet_ena = 0; - } - } - - sdio_ctrl_power((struct mmc_host *)wifi_mmc_host, on); - return 0; - -} - -int somc_wifi_set_carddetect(int present) -{ - g_wifi_detect = present; - - if (sdc_status_cb) - sdc_status_cb(present, sdc_dev); - else - printk(KERN_WARNING "%s: Nobody to notify\n", __func__); - return 0; -} -#endif /* CONFIG_MACH_SONY_SHINANO */ - -static ssize_t macaddr_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s", intf_macaddr); -} - -static ssize_t macaddr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return snprintf(intf_macaddr, count, "%s\n", buf); -} - -DEVICE_ATTR(macaddr, 0644, macaddr_show, macaddr_store); - -static struct attribute *wifi_attrs[] = { - &dev_attr_macaddr.attr, - NULL -}; - -static struct attribute_group wifi_attr_grp = { - .attrs = wifi_attrs, -}; +static struct mmc_host *wlan_mmc_host; int somc_wifi_init(struct platform_device *pdev) { @@ -241,7 +102,6 @@ int somc_wifi_init(struct platform_device *pdev) goto err_gpio; } -#ifdef CONFIG_BCMDHD_PCIE ret = of_property_read_u32(pdev->dev.of_node, "wlan-pci-number", &bcmdhd_data->pci_number); if (ret < 0) { @@ -249,20 +109,11 @@ int somc_wifi_init(struct platform_device *pdev) __func__, ret, bcmdhd_data->pci_number); goto err_gpio_request; } -#endif /* CONFIG_BCMDHD_PCIE */ - - intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); - if (sysfs_create_group(&pdev->dev.kobj, &wifi_attr_grp) < 0) { - pr_err("%s: Unable to create sysfs\n", __func__); - kfree(intf_macaddr); - } return 0; -#ifdef CONFIG_BCMDHD_PCIE err_gpio_request: gpio_free(bcmdhd_data->wlan_reg_on); -#endif /* CONFIG_BCMDHD_PCIE */ err_gpio: ret_sus = pinctrl_select_state(bcmdhd_data->pinctrl, bcmdhd_data->gpio_state_suspend); @@ -294,178 +145,41 @@ void somc_wifi_deinit(struct platform_device *pdev) } EXPORT_SYMBOL(somc_wifi_deinit); -#define ETHER_ADDR_LEN 6 - -static inline int xdigit (char c) -{ - unsigned d; - - d = (unsigned)(c-'0'); - if (d < 10) - return (int)d; - d = (unsigned)(c-'a'); - if (d < 6) - return (int)(10+d); - d = (unsigned)(c-'A'); - if (d < 6) - return (int)(10+d); - return -1; -} - -struct ether_addr { - unsigned char ether_addr_octet[ETHER_ADDR_LEN]; -} __attribute__((__packed__)); - -struct ether_addr * -ether_aton_r (const char *asc, struct ether_addr * addr) +void somc_wifi_mmc_host_register(struct mmc_host *host) { - int i, val0, val1; - - for (i = 0; i < ETHER_ADDR_LEN; ++i) { - val0 = xdigit(*asc); - asc++; - if (val0 < 0) - return NULL; - - val1 = xdigit(*asc); - asc++; - if (val1 < 0) - return NULL; - - addr->ether_addr_octet[i] = (unsigned char)((val0 << 4) + val1); - - if (i < ETHER_ADDR_LEN - 1) { - if (*asc != ':') - return NULL; - asc++; - } - } - - if (*asc != '\0') - return NULL; - - return addr; + wlan_mmc_host = host; } -struct ether_addr * ether_aton (const char *asc) +int somc_wifi_set_power(int on) { - static struct ether_addr addr; - return ether_aton_r(asc, &addr); + gpio_set_value(bcmdhd_data->wlan_reg_on, on); + return 0; } -static int somc_wifi_get_mac_addr(unsigned char *buf) +#ifdef CONFIG_BCMDHD_PCIE +int somc_wifi_set_carddetect(int present) { int ret = 0; - - char macasc[128] = {0,}; - uint rand_mac; - static unsigned char mymac[ETHER_ADDR_LEN] = {0,}; - const unsigned char nullmac[ETHER_ADDR_LEN] = {0,}; - - if (buf == NULL) - return -EAGAIN; - - memset(buf, 0x00, ETHER_ADDR_LEN); - - if (intf_macaddr != NULL) { - unsigned char* macbin; - struct ether_addr* convmac = ether_aton( intf_macaddr ); - - if (convmac == NULL) { - pr_err("%s: Invalid Mac Address Format %s\n", - __FUNCTION__, macasc ); - goto random_mac; - } - - macbin = convmac->ether_addr_octet; - - pr_info("%s: READ MAC ADDRESS %02X:%02X:%02X:%02X:%02X:%02X\n", - __FUNCTION__, - macbin[0], macbin[1], macbin[2], - macbin[3], macbin[4], macbin[5]); - - memcpy(buf, macbin, ETHER_ADDR_LEN); - } - + if (present) + ret = msm_pcie_enumerate_locked(bcmdhd_data->pci_number); return ret; - -random_mac: - - pr_debug("%s: %p\n", __func__, buf); - - if (memcmp( mymac, nullmac, ETHER_ADDR_LEN) != 0) { - /* Mac displayed from UI is never updated.. - So, mac obtained on initial time is used */ - memcpy(buf, mymac, ETHER_ADDR_LEN); - return 0; - } - - prandom_seed((uint)jiffies); - rand_mac = prandom_u32(); - buf[0] = 0x00; - buf[1] = 0x90; - buf[2] = 0x4c; - buf[3] = (unsigned char)rand_mac; - buf[4] = (unsigned char)(rand_mac >> 8); - buf[5] = (unsigned char)(rand_mac >> 16); - - memcpy(mymac, buf, 6); - - pr_info("[%s] Exiting. MAC %02X:%02X:%02X:%02X:%02X:%02X\n", - __FUNCTION__, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5] ); - +} +#else /* CONFIG_BCMDHD_PCIE */ +int somc_wifi_set_carddetect(int present) +{ + if (wlan_mmc_host) + mmc_detect_change(wlan_mmc_host, 0); return 0; } +#endif /* CONFIG_BCMDHD_PCIE */ struct wifi_platform_data somc_wifi_control = { .set_power = somc_wifi_set_power, -#if defined(CONFIG_MACH_SONY_SHINANO) - .set_reset = somc_wifi_set_reset, -#endif /* CONFIG_MACH_SONY_SHINANO */ .set_carddetect = somc_wifi_set_carddetect, +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM .mem_prealloc = dhd_wlan_mem_prealloc, - .get_mac_addr = somc_wifi_get_mac_addr, +#endif }; - EXPORT_SYMBOL(somc_wifi_control); -#if defined(CONFIG_MACH_SONY_SHINANO) -static struct resource somc_wifi_resources[] = { - [0] = { - .name = "bcmdhd_wlan_irq", - .start = 0, - .end = 0, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | - IORESOURCE_IRQ_SHAREABLE, - }, -}; - -static struct platform_device somc_wifi = { - .name = "bcmdhd_wlan", - .id = -1, - .num_resources = ARRAY_SIZE(somc_wifi_resources), - .resource = somc_wifi_resources, - .dev = { - .platform_data = &somc_wifi_control, - }, -}; - -static int __init somc_wifi_init_on_boot(void) -{ - somc_wifi.resource->start = gpio_to_irq(WIFI_IRQ_GPIO); - somc_wifi.resource->end = gpio_to_irq(WIFI_IRQ_GPIO); - platform_device_register(&somc_wifi); - - intf_macaddr = kzalloc(20*(sizeof(char)), GFP_KERNEL); - if (sysfs_create_group(&somc_wifi.dev.kobj, &wifi_attr_grp) < 0) { - pr_err("%s: Unable to create sysfs\n", __func__); - kfree(intf_macaddr); - } - return 0; -} - -device_initcall(somc_wifi_init_on_boot); -#endif /* CONFIG_MACH_SONY_SHINANO */ - MODULE_LICENSE("GPL v2"); -- GitLab From a3c0f7897ce12b4d5df020025fb2263aa101e9a2 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 6 Aug 2020 11:17:11 -0700 Subject: [PATCH 275/528] Bluetooth: A2MP: Fix not initializing all members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit eddb7732119d53400f48a02536a84c509692faa8 upstream. This fixes various places where a stack variable is used uninitialized. Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Björn Bidar (cherry picked from commit 57b5050e340f40a88e1ddb8d16fd9adb44418923) --- net/bluetooth/a2mp.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 17f33a62f6db..7d4d5ac4002c 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -212,6 +212,9 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb, struct a2mp_info_req req; found = true; + + memset(&req, 0, sizeof(req)); + req.id = cl->id; a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr), sizeof(req), &req); @@ -281,6 +284,8 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb, if (!hdev || hdev->dev_type != HCI_AMP) { struct a2mp_info_rsp rsp; + memset(&rsp, 0, sizeof(rsp)); + rsp.id = req->id; rsp.status = A2MP_STATUS_INVALID_CTRL_ID; @@ -320,6 +325,8 @@ static int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb, if (!ctrl) return -ENOMEM; + memset(&req, 0, sizeof(req)); + req.id = rsp->id; a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req), &req); @@ -348,6 +355,8 @@ static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb, struct a2mp_amp_assoc_rsp rsp; rsp.id = req->id; + memset(&rsp, 0, sizeof(rsp)); + if (tmp) { rsp.status = A2MP_STATUS_COLLISION_OCCURED; amp_mgr_put(tmp); @@ -447,6 +456,8 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id); + memset(&rsp, 0, sizeof(rsp)); + rsp.local_id = req->remote_id; rsp.remote_id = req->local_id; @@ -525,6 +536,8 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id); + memset(&rsp, 0, sizeof(rsp)); + rsp.local_id = req->remote_id; rsp.remote_id = req->local_id; rsp.status = A2MP_STATUS_SUCCESS; @@ -646,7 +659,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) if (err) { struct a2mp_cmd_rej rej; - rej.reason = __constant_cpu_to_le16(0); + memset(&rej, 0, sizeof(rej)); + + rej.reason = __constant_cpu_to_le16(0); hdr = (void *) skb->data; BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err); @@ -868,6 +883,8 @@ void a2mp_send_getinfo_rsp(struct hci_dev *hdev) BT_DBG("%s mgr %p", hdev->name, mgr); + memset(&rsp, 0, sizeof(rsp)); + rsp.id = hdev->id; rsp.status = A2MP_STATUS_INVALID_CTRL_ID; @@ -965,6 +982,8 @@ void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status) if (!mgr) return; + memset(&rsp, 0, sizeof(rsp)); + hs_hcon = hci_conn_hash_lookup_state(hdev, AMP_LINK, BT_CONNECT); if (!hs_hcon) { rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; @@ -997,6 +1016,8 @@ void a2mp_discover_amp(struct l2cap_chan *chan) mgr->bredr_chan = chan; + memset(&req, 0, sizeof(req)); + req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); req.ext_feat = 0; a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req); -- GitLab From b3cf7f01a04b5dcdc7e393202bacee1113652c61 Mon Sep 17 00:00:00 2001 From: Kyungtae Kim Date: Sun, 10 May 2020 05:43:34 +0000 Subject: [PATCH 276/528] USB: gadget: fix illegal array access in binding with UDC FuzzUSB (a variant of syzkaller) found an illegal array access using an incorrect index while binding a gadget with UDC. Reference: https://www.spinics.net/lists/linux-usb/msg194331.html This bug occurs when a size variable used for a buffer is misused to access its strcpy-ed buffer. Given a buffer along with its size variable (taken from user input), from which, a new buffer is created using kstrdup(). Due to the original buffer containing 0 value in the middle, the size of the kstrdup-ed buffer becomes smaller than that of the original. So accessing the kstrdup-ed buffer with the same size variable triggers memory access violation. The fix makes sure no zero value in the buffer, by comparing the strlen() of the orignal buffer with the size variable, so that the access to the kstrdup-ed buffer is safe. BUG: KASAN: slab-out-of-bounds in gadget_dev_desc_UDC_store+0x1ba/0x200 drivers/usb/gadget/configfs.c:266 Read of size 1 at addr ffff88806a55dd7e by task syz-executor.0/17208 CPU: 2 PID: 17208 Comm: syz-executor.0 Not tainted 5.6.8 #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0xce/0x128 lib/dump_stack.c:118 print_address_description.constprop.4+0x21/0x3c0 mm/kasan/report.c:374 __kasan_report+0x131/0x1b0 mm/kasan/report.c:506 kasan_report+0x12/0x20 mm/kasan/common.c:641 __asan_report_load1_noabort+0x14/0x20 mm/kasan/generic_report.c:132 gadget_dev_desc_UDC_store+0x1ba/0x200 drivers/usb/gadget/configfs.c:266 flush_write_buffer fs/configfs/file.c:251 [inline] configfs_write_file+0x2f1/0x4c0 fs/configfs/file.c:283 __vfs_write+0x85/0x110 fs/read_write.c:494 vfs_write+0x1cd/0x510 fs/read_write.c:558 ksys_write+0x18a/0x220 fs/read_write.c:611 __do_sys_write fs/read_write.c:623 [inline] __se_sys_write fs/read_write.c:620 [inline] __x64_sys_write+0x73/0xb0 fs/read_write.c:620 do_syscall_64+0x9e/0x510 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe Signed-off-by: Kyungtae Kim Reported-and-tested-by: Kyungtae Kim Cc: Felipe Balbi Cc: stable Link: https://lore.kernel.org/r/20200510054326.GA19198@pizza01 Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 8ddf8f85846e4c3cfc12ed3c042d942c6488583f) --- drivers/usb/gadget/configfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index a520817fbc36..f483fc6c9729 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -249,6 +249,9 @@ static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, char *name; int ret; + if (strlen(page) < len) + return -EOVERFLOW; + name = kstrdup(page, GFP_KERNEL); if (!name) return -ENOMEM; -- GitLab From b1a94a9e02be0fd17cc4a4dad176fb6a2a52ffdf Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 22 Nov 2018 13:28:41 +0900 Subject: [PATCH 277/528] modpost: file2alias: go back to simple devtable lookup commit ec91e78d378cc5d4b43805a1227d8e04e5dfa17d upstream. Commit e49ce14150c6 ("modpost: use linker section to generate table.") was not so cool as we had expected first; it ended up with ugly section hacks when commit dd2a3acaecd7 ("mod/file2alias: make modpost compile on darwin again") came in. Given a certain degree of unknowledge about the link stage of host programs, I really want to see simple, stupid table lookup so that this works in the same way regardless of the underlying executable format. Signed-off-by: Masahiro Yamada Acked-by: Mathieu Malaterre [nc: Omit rpmsg, sdw, fslmc, tbsvc, and typec as they don't exist here Add of to avoid backporting two larger patches] Signed-off-by: Nathan Chancellor Signed-off-by: Sasha Levin Signed-off-by: Kevin F. Haggerty Change-Id: Ic632eaa7777338109f80c76535e67917f5b9761c --- scripts/mod/file2alias.c | 125 +++++++++++++-------------------------- 1 file changed, 40 insertions(+), 85 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 09632f04576b..ecfd31d9663f 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -47,44 +47,6 @@ struct devtable { void *function; }; -#define ___cat(a,b) a ## b -#define __cat(a,b) ___cat(a,b) - -/* we need some special handling for this host tool running eventually on - * Darwin. The Mach-O section handling is a bit different than ELF section - * handling. The differnces in detail are: - * a) we have segments which have sections - * b) we need a API call to get the respective section symbols */ -#if defined(__MACH__) -#include - -#define INIT_SECTION(name) do { \ - unsigned long name ## _len; \ - char *__cat(pstart_,name) = getsectdata("__TEXT", \ - #name, &__cat(name,_len)); \ - char *__cat(pstop_,name) = __cat(pstart_,name) + \ - __cat(name, _len); \ - __cat(__start_,name) = (void *)__cat(pstart_,name); \ - __cat(__stop_,name) = (void *)__cat(pstop_,name); \ - } while (0) -#define SECTION(name) __attribute__((section("__TEXT, " #name))) - -struct devtable **__start___devtable, **__stop___devtable; -#else -#define INIT_SECTION(name) /* no-op for ELF */ -#define SECTION(name) __attribute__((section(#name))) - -/* We construct a table of pointers in an ELF section (pointers generally - * go unpadded by gcc). ld creates boundary syms for us. */ -extern struct devtable *__start___devtable[], *__stop___devtable[]; -#endif /* __MACH__ */ - -#if __GNUC__ == 3 && __GNUC_MINOR__ < 3 -# define __used __attribute__((__unused__)) -#else -# define __used __attribute__((__used__)) -#endif - /* Define a variable f that holds the value of field f of struct devid * based at address m. */ @@ -97,16 +59,6 @@ extern struct devtable *__start___devtable[], *__stop___devtable[]; #define DEF_FIELD_ADDR(m, devid, f) \ typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) -/* Add a table entry. We test function type matches while we're here. */ -#define ADD_TO_DEVTABLE(device_id, type, function) \ - static struct devtable __cat(devtable,__LINE__) = { \ - device_id + 0*sizeof((function)((const char *)NULL, \ - (void *)NULL, \ - (char *)NULL)), \ - SIZE_##type, (function) }; \ - static struct devtable *SECTION(__devtable) __used \ - __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__) - #define ADD(str, sep, cond, field) \ do { \ strcat(str, sep); \ @@ -371,7 +323,6 @@ static int do_hid_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("hid", hid_device_id, do_hid_entry); /* Looks like: ieee1394:venNmoNspNverN */ static int do_ieee1394_entry(const char *filename, @@ -396,7 +347,6 @@ static int do_ieee1394_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ieee1394", ieee1394_device_id, do_ieee1394_entry); /* Looks like: pci:vNdNsvNsdNbcNscNiN. */ static int do_pci_entry(const char *filename, @@ -440,7 +390,6 @@ static int do_pci_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("pci", pci_device_id, do_pci_entry); /* looks like: "ccw:tNmNdtNdmN" */ static int do_ccw_entry(const char *filename, @@ -464,7 +413,6 @@ static int do_ccw_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ccw", ccw_device_id, do_ccw_entry); /* looks like: "ap:tN" */ static int do_ap_entry(const char *filename, @@ -475,7 +423,6 @@ static int do_ap_entry(const char *filename, sprintf(alias, "ap:t%02X*", dev_type); return 1; } -ADD_TO_DEVTABLE("ap", ap_device_id, do_ap_entry); /* looks like: "css:tN" */ static int do_css_entry(const char *filename, @@ -486,7 +433,6 @@ static int do_css_entry(const char *filename, sprintf(alias, "css:t%01X", type); return 1; } -ADD_TO_DEVTABLE("css", css_device_id, do_css_entry); /* Looks like: "serio:tyNprNidNexN" */ static int do_serio_entry(const char *filename, @@ -506,7 +452,6 @@ static int do_serio_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry); /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */ static int do_acpi_entry(const char *filename, @@ -516,7 +461,6 @@ static int do_acpi_entry(const char *filename, sprintf(alias, "acpi*:%s:*", *id); return 1; } -ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry); /* looks like: "pnp:dD" */ static void do_pnp_device_entry(void *symval, unsigned long size, @@ -637,7 +581,6 @@ static int do_pcmcia_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("pcmcia", pcmcia_device_id, do_pcmcia_entry); static int do_of_entry (const char *filename, void *symval, char *alias) { @@ -664,7 +607,6 @@ static int do_of_entry (const char *filename, void *symval, char *alias) add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("of", of_device_id, do_of_entry); static int do_vio_entry(const char *filename, void *symval, char *alias) @@ -684,7 +626,6 @@ static int do_vio_entry(const char *filename, void *symval, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("vio", vio_device_id, do_vio_entry); #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -757,7 +698,6 @@ static int do_input_entry(const char *filename, void *symval, do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); return 1; } -ADD_TO_DEVTABLE("input", input_device_id, do_input_entry); static int do_eisa_entry(const char *filename, void *symval, char *alias) @@ -769,7 +709,6 @@ static int do_eisa_entry(const char *filename, void *symval, strcat(alias, "*"); return 1; } -ADD_TO_DEVTABLE("eisa", eisa_device_id, do_eisa_entry); /* Looks like: parisc:tNhvNrevNsvN */ static int do_parisc_entry(const char *filename, void *symval, @@ -789,7 +728,6 @@ static int do_parisc_entry(const char *filename, void *symval, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("parisc", parisc_device_id, do_parisc_entry); /* Looks like: sdio:cNvNdN. */ static int do_sdio_entry(const char *filename, @@ -806,7 +744,6 @@ static int do_sdio_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("sdio", sdio_device_id, do_sdio_entry); /* Looks like: ssb:vNidNrevN. */ static int do_ssb_entry(const char *filename, @@ -823,7 +760,6 @@ static int do_ssb_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ssb", ssb_device_id, do_ssb_entry); /* Looks like: bcma:mNidNrevNclN. */ static int do_bcma_entry(const char *filename, @@ -842,7 +778,6 @@ static int do_bcma_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("bcma", bcma_device_id, do_bcma_entry); /* Looks like: virtio:dNvN */ static int do_virtio_entry(const char *filename, void *symval, @@ -858,7 +793,6 @@ static int do_virtio_entry(const char *filename, void *symval, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("virtio", virtio_device_id, do_virtio_entry); /* * Looks like: vmbus:guid @@ -881,7 +815,6 @@ static int do_vmbus_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry); /* Looks like: i2c:S */ static int do_i2c_entry(const char *filename, void *symval, @@ -892,7 +825,6 @@ static int do_i2c_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("i2c", i2c_device_id, do_i2c_entry); /* Looks like: spi:S */ static int do_spi_entry(const char *filename, void *symval, @@ -903,7 +835,6 @@ static int do_spi_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("spi", spi_device_id, do_spi_entry); static const struct dmifield { const char *prefix; @@ -958,7 +889,6 @@ static int do_dmi_entry(const char *filename, void *symval, strcat(alias, ":"); return 1; } -ADD_TO_DEVTABLE("dmi", dmi_system_id, do_dmi_entry); static int do_platform_entry(const char *filename, void *symval, char *alias) @@ -967,7 +897,6 @@ static int do_platform_entry(const char *filename, sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name); return 1; } -ADD_TO_DEVTABLE("platform", platform_device_id, do_platform_entry); static int do_mdio_entry(const char *filename, void *symval, char *alias) @@ -992,7 +921,6 @@ static int do_mdio_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("mdio", mdio_device_id, do_mdio_entry); /* Looks like: zorro:iN. */ static int do_zorro_entry(const char *filename, void *symval, @@ -1003,7 +931,6 @@ static int do_zorro_entry(const char *filename, void *symval, ADD(alias, "i", id != ZORRO_WILDCARD, id); return 1; } -ADD_TO_DEVTABLE("zorro", zorro_device_id, do_zorro_entry); /* looks like: "pnp:dD" */ static int do_isapnp_entry(const char *filename, @@ -1019,7 +946,6 @@ static int do_isapnp_entry(const char *filename, (function >> 12) & 0x0f, (function >> 8) & 0x0f); return 1; } -ADD_TO_DEVTABLE("isapnp", isapnp_device_id, do_isapnp_entry); /* Looks like: "ipack:fNvNdN". */ static int do_ipack_entry(const char *filename, @@ -1035,7 +961,6 @@ static int do_ipack_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ipack", ipack_device_id, do_ipack_entry); /* * Append a match expression for a single masked hex digit. @@ -1106,7 +1031,6 @@ static int do_amba_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry); /* LOOKS like x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:*,FEAT,* * All fields are numbers. It would be nicer to use strings for vendor @@ -1131,7 +1055,6 @@ static int do_x86cpu_entry(const char *filename, void *symval, sprintf(alias + strlen(alias), "%04X*", feature); return 1; } -ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry); /* LOOKS like cpu:type:*:feature:*FEAT* */ static int do_cpu_entry(const char *filename, void *symval, char *alias) @@ -1141,7 +1064,6 @@ static int do_cpu_entry(const char *filename, void *symval, char *alias) sprintf(alias, "cpu:type:*:feature:*%04X*", feature); return 1; } -ADD_TO_DEVTABLE("cpu", cpu_feature, do_cpu_entry); /* Looks like: mei:S */ static int do_mei_entry(const char *filename, void *symval, @@ -1153,7 +1075,6 @@ static int do_mei_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry); /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) @@ -1186,6 +1107,39 @@ static void do_table(void *symval, unsigned long size, } } +static const struct devtable devtable[] = { + {"hid", SIZE_hid_device_id, do_hid_entry}, + {"ieee1394", SIZE_ieee1394_device_id, do_ieee1394_entry}, + {"pci", SIZE_pci_device_id, do_pci_entry}, + {"ccw", SIZE_ccw_device_id, do_ccw_entry}, + {"ap", SIZE_ap_device_id, do_ap_entry}, + {"css", SIZE_css_device_id, do_css_entry}, + {"serio", SIZE_serio_device_id, do_serio_entry}, + {"acpi", SIZE_acpi_device_id, do_acpi_entry}, + {"pcmcia", SIZE_pcmcia_device_id, do_pcmcia_entry}, + {"vio", SIZE_vio_device_id, do_vio_entry}, + {"input", SIZE_input_device_id, do_input_entry}, + {"eisa", SIZE_eisa_device_id, do_eisa_entry}, + {"parisc", SIZE_parisc_device_id, do_parisc_entry}, + {"sdio", SIZE_sdio_device_id, do_sdio_entry}, + {"ssb", SIZE_ssb_device_id, do_ssb_entry}, + {"bcma", SIZE_bcma_device_id, do_bcma_entry}, + {"virtio", SIZE_virtio_device_id, do_virtio_entry}, + {"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry}, + {"i2c", SIZE_i2c_device_id, do_i2c_entry}, + {"spi", SIZE_spi_device_id, do_spi_entry}, + {"dmi", SIZE_dmi_system_id, do_dmi_entry}, + {"platform", SIZE_platform_device_id, do_platform_entry}, + {"mdio", SIZE_mdio_device_id, do_mdio_entry}, + {"zorro", SIZE_zorro_device_id, do_zorro_entry}, + {"isapnp", SIZE_isapnp_device_id, do_isapnp_entry}, + {"ipack", SIZE_ipack_device_id, do_ipack_entry}, + {"amba", SIZE_amba_id, do_amba_entry}, + {"x86cpu", SIZE_x86_cpu_id, do_x86cpu_entry}, + {"mei", SIZE_mei_cl_device_id, do_mei_entry}, + {"of", SIZE_of_device_id, do_of_entry}, +}; + /* Create MODULE_ALIAS() statements. * At this time, we cannot write the actual output C source yet, * so we write into the mod->dev_table_buf buffer. */ @@ -1235,13 +1189,14 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, else if (sym_is(name, namelen, "pnp_card")) do_pnp_card_entries(symval, sym->st_size, mod); else { - struct devtable **p; - INIT_SECTION(__devtable); + int i; + + for (i = 0; i < ARRAY_SIZE(devtable); i++) { + const struct devtable *p = &devtable[i]; - for (p = __start___devtable; p < __stop___devtable; p++) { - if (sym_is(name, namelen, (*p)->device_id)) { - do_table(symval, sym->st_size, (*p)->id_size, - (*p)->device_id, (*p)->function, mod); + if (sym_is(name, namelen, p->device_id)) { + do_table(symval, sym->st_size, p->id_size, + p->device_id, p->function, mod); break; } } -- GitLab From 7957db8f12893ef097092851a46c284125943e38 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 3 Feb 2014 11:14:13 +1030 Subject: [PATCH 278/528] module: allow multiple calls to MODULE_DEVICE_TABLE() per module Commit 78551277e4df5: "Input: i8042 - add PNP modaliases" had a bug, where the second call to MODULE_DEVICE_TABLE() overrode the first resulting in not all the modaliases being exposed. This fixes the problem by including the name of the device_id table in the __mod_*_device_table alias, allowing us to export several device_id tables per module. Suggested-by: Kay Sievers Acked-by: Greg Kroah-Hartman Cc: Dmitry Torokhov Signed-off-by: Tom Gundersen Signed-off-by: Rusty Russell Change-Id: I4fbe463e68b85887654583ecce6000ae184c09d6 --- include/linux/module.h | 4 ++-- scripts/mod/file2alias.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index 761dc2848ffa..2aef36fc43a6 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -136,8 +136,8 @@ extern const struct gtype##_id __mod_##gtype##_table \ /* What your module does. */ #define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) -#define MODULE_DEVICE_TABLE(type,name) \ - MODULE_GENERIC_TABLE(type##_device,name) +#define MODULE_DEVICE_TABLE(type, name) \ + MODULE_GENERIC_TABLE(type##__##name##_device, name) /* Version of form [:][-]. Or for CVS/RCS ID version, everything but the number is stripped. diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index ecfd31d9663f..8242233d61d8 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -42,7 +42,7 @@ typedef unsigned char __u8; /* This array collects all instances that use the generic do_table */ struct devtable { - const char *device_id; /* name of table, __mod__device_table. */ + const char *device_id; /* name of table, __mod___*_device_table. */ unsigned long id_size; void *function; }; @@ -96,7 +96,8 @@ static void device_id_check(const char *modname, const char *device_id, if (size % id_size || size < id_size) { fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " - "of the size of section __mod_%s_device_table=%lu.\n" + "of the size of " + "section __mod_%s___device_table=%lu.\n" "Fix definition of struct %s_device_id " "in mod_devicetable.h\n", modname, device_id, id_size, device_id, size, device_id); @@ -1148,7 +1149,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, { void *symval; char *zeros = NULL; - const char *name; + const char *name, *identifier; unsigned int namelen; /* We're looking for a section relative symbol */ @@ -1159,7 +1160,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) return; - /* All our symbols are of form __mod_XXX_device_table. */ + /* All our symbols are of form __mod____device_table. */ name = strstr(symname, "__mod_"); if (!name) return; @@ -1169,7 +1170,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, return; if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) return; - namelen -= strlen("_device_table"); + identifier = strstr(name, "__"); + if (!identifier) + return; + namelen = identifier - name; /* Handle all-NULL symbols allocated into .bss */ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { -- GitLab From 3bcaf44f133ea24ce05346d6fbd06429a5e656ba Mon Sep 17 00:00:00 2001 From: "Kevin F. Haggerty" Date: Thu, 3 Jun 2021 20:33:21 -0600 Subject: [PATCH 279/528] fs: sdfat: __sdfat_submit_bio_write() should always submit a WRITE sdfat version 2.4.5 introduced wbc_to_write_flags() as a compat function for legacy kernels. Unfortunately, as the legacy __sdfat_submit_bio_write() path was adapted to take advantage of wbc_to_write_flags(), it used the return value direcly as the rw paramater to submit_bio(), and the default return value is 0 (READ). This becomes a problem later when write paths assert that bio_data_dir() is WRITE (i.e., write bit of bio->bi_rw is set). Pass a bitwise-or of WRITE and the return value of wbc_to_write_flags() to submit_bio() on this legacy path. This logically unifies the approach with the newer path here and directly with the legacy path of __sdfat_submit_bio_write2() in mpage.c. Fixes: afd489c6a8c8 ("fs: sdfat: Update to version 2.4.5") Signed-off-by: Kevin F. Haggerty Change-Id: Ic7b937a467e9e116c3390c6ac0e009a59229b93c --- fs/sdfat/sdfat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdfat/sdfat.c b/fs/sdfat/sdfat.c index 9b7a63581160..72dfe270856d 100644 --- a/fs/sdfat/sdfat.c +++ b/fs/sdfat/sdfat.c @@ -256,7 +256,7 @@ static inline void __sdfat_submit_bio_write(struct bio *bio, { int write_flags = wbc_to_write_flags(wbc); - submit_bio(write_flags, bio); + submit_bio(WRITE | write_flags, bio); } static inline unsigned int __sdfat_full_name_hash(const struct dentry *unused, const char *name, unsigned int len) -- GitLab From 2afd321d9f38ab78c0749d90fcb424c7bf8ac227 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:09 -0400 Subject: [PATCH 280/528] locks: drop the unused filp argument to posix_unblock_lock Signed-off-by: Jeff Layton Signed-off-by: Al Viro Change-Id: Id168efc0a98ff9507541deff4d1444852751eb96 --- fs/lockd/svclock.c | 2 +- fs/locks.c | 4 +--- include/linux/fs.h | 5 ++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index ffc4045fc62e..6f0e9f88caf3 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -276,7 +276,7 @@ static int nlmsvc_unlink_block(struct nlm_block *block) dprintk("lockd: unlinking block %p...\n", block); /* Remove block from list */ - status = posix_unblock_lock(block->b_file->f_file, &block->b_call->a_args.lock.fl); + status = posix_unblock_lock(&block->b_call->a_args.lock.fl); nlmsvc_remove_block(block); return status; } diff --git a/fs/locks.c b/fs/locks.c index f7b1de7e6735..fb54af214890 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2107,13 +2107,12 @@ void locks_remove_flock(struct file *filp) /** * posix_unblock_lock - stop waiting for a file lock - * @filp: how the file was opened * @waiter: the lock which was waiting * * lockd needs to block waiting for locks. */ int -posix_unblock_lock(struct file *filp, struct file_lock *waiter) +posix_unblock_lock(struct file_lock *waiter) { int status = 0; @@ -2125,7 +2124,6 @@ posix_unblock_lock(struct file *filp, struct file_lock *waiter) unlock_flocks(); return status; } - EXPORT_SYMBOL(posix_unblock_lock); /** diff --git a/include/linux/fs.h b/include/linux/fs.h index 49fe3a4cdb70..40b24a621c9a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1025,7 +1025,7 @@ extern void locks_release_private(struct file_lock *); extern void posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); extern int posix_lock_file_wait(struct file *, struct file_lock *); -extern int posix_unblock_lock(struct file *, struct file_lock *); +extern int posix_unblock_lock(struct file_lock *); extern int vfs_test_lock(struct file *, struct file_lock *); extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *); extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl); @@ -1115,8 +1115,7 @@ static inline int posix_lock_file_wait(struct file *filp, struct file_lock *fl) return -ENOLCK; } -static inline int posix_unblock_lock(struct file *filp, - struct file_lock *waiter) +static inline int posix_unblock_lock(struct file_lock *waiter) { return -ENOENT; } -- GitLab From 7d480bd219ecd946d6be0b0a314d751d617de493 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:10 -0400 Subject: [PATCH 281/528] cifs: use posix_unblock_lock instead of locks_delete_block commit 66189be74 (CIFS: Fix VFS lock usage for oplocked files) exported the locks_delete_block symbol. There's already an exported helper function that provides this capability however, so make cifs use that instead and turn locks_delete_block back into a static function. Note that if fl->fl_next == NULL then this lock has already been through locks_delete_block(), so we should be OK to ignore an ENOENT error here and simply not retry the lock. Cc: Pavel Shilovsky Signed-off-by: Jeff Layton Acked-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: Id6cb4db8cd75754306bba511c782d55243a43083 --- fs/cifs/file.c | 2 +- fs/locks.c | 3 +-- include/linux/fs.h | 5 ----- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index f4a8577c3e91..30f48dbfafcf 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -998,7 +998,7 @@ try_again: rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next); if (!rc) goto try_again; - locks_delete_block(flock); + posix_unblock_lock(flock); } return rc; } diff --git a/fs/locks.c b/fs/locks.c index fb54af214890..53a1f7198cc1 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -496,13 +496,12 @@ static void __locks_delete_block(struct file_lock *waiter) /* */ -void locks_delete_block(struct file_lock *waiter) +static void locks_delete_block(struct file_lock *waiter) { lock_flocks(); __locks_delete_block(waiter); unlock_flocks(); } -EXPORT_SYMBOL(locks_delete_block); /* Insert waiter into blocker's block list. * We use a circular list so that processes can be easily woken up in diff --git a/include/linux/fs.h b/include/linux/fs.h index 40b24a621c9a..68bd6c8f82d8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1037,7 +1037,6 @@ extern int vfs_setlease(struct file *, long, struct file_lock **); extern int lease_modify(struct file_lock **, int); extern int lock_may_read(struct inode *, loff_t start, unsigned long count); extern int lock_may_write(struct inode *, loff_t start, unsigned long count); -extern void locks_delete_block(struct file_lock *waiter); extern void lock_flocks(void); extern void unlock_flocks(void); #else /* !CONFIG_FILE_LOCKING */ @@ -1181,10 +1180,6 @@ static inline int lock_may_write(struct inode *inode, loff_t start, return 1; } -static inline void locks_delete_block(struct file_lock *waiter) -{ -} - static inline void lock_flocks(void) { } -- GitLab From f0d98da20e745b355437f99dfe5a63db5879e4b9 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:11 -0400 Subject: [PATCH 282/528] locks: make generic_add_lease and generic_delete_lease static Signed-off-by: Jeff Layton Acked-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: I130697b9f432278c1a64bae4547c2c47c6afa4a1 --- fs/locks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 53a1f7198cc1..c33da44db5a1 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1336,7 +1336,7 @@ int fcntl_getlease(struct file *filp) return type; } -int generic_add_lease(struct file *filp, long arg, struct file_lock **flp) +static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp) { struct file_lock *fl, **before, **my_before = NULL, *lease; struct dentry *dentry = filp->f_path.dentry; @@ -1401,7 +1401,7 @@ out: return error; } -int generic_delete_lease(struct file *filp, struct file_lock **flp) +static int generic_delete_lease(struct file *filp, struct file_lock **flp) { struct file_lock *fl, **before; struct dentry *dentry = filp->f_path.dentry; -- GitLab From 5888d63ec356f3e4a94569a309a4e888611b6259 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:12 -0400 Subject: [PATCH 283/528] locks: comment cleanups and clarifications Signed-off-by: Jeff Layton Signed-off-by: Al Viro Change-Id: I73d1d35b3c06ee20d495d2637757ef3a658e2c3f --- fs/locks.c | 21 +++++++++++++-------- include/linux/fs.h | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index c33da44db5a1..b41ad68b763b 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -518,9 +518,10 @@ static void locks_insert_block(struct file_lock *blocker, list_add(&waiter->fl_link, &blocked_list); } -/* Wake up processes blocked waiting for blocker. - * If told to wait then schedule the processes until the block list - * is empty, otherwise empty the block list ourselves. +/* + * Wake up processes blocked waiting for blocker. + * + * Must be called with the file_lock_lock held! */ static void locks_wake_up_blocks(struct file_lock *blocker) { @@ -806,6 +807,11 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str } lock_flocks(); + /* + * New lock request. Walk all POSIX locks and look for conflicts. If + * there are any, either return error or put the request on the + * blocker's list of waiters and the global blocked_list. + */ if (request->fl_type != F_UNLCK) { for_each_lock(inode, before) { fl = *before; @@ -844,7 +850,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str before = &fl->fl_next; } - /* Process locks with this owner. */ + /* Process locks with this owner. */ while ((fl = *before) && posix_same_owner(request, fl)) { /* Detect adjacent or overlapping regions (if same lock type) */ @@ -930,10 +936,9 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str } /* - * The above code only modifies existing locks in case of - * merging or replacing. If new lock(s) need to be inserted - * all modifications are done bellow this, so it's safe yet to - * bail out. + * The above code only modifies existing locks in case of merging or + * replacing. If new lock(s) need to be inserted all modifications are + * done below this, so it's safe yet to bail out. */ error = -ENOLCK; /* "no luck" */ if (right && left == right && !new_fl2) diff --git a/include/linux/fs.h b/include/linux/fs.h index 68bd6c8f82d8..cd282160f2a7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -957,6 +957,24 @@ int locks_in_grace(struct net *); /* that will die - we need it for nfs_lock_info */ #include +/* + * struct file_lock represents a generic "file lock". It's used to represent + * POSIX byte range locks, BSD (flock) locks, and leases. It's important to + * note that the same struct is used to represent both a request for a lock and + * the lock itself, but the same object is never used for both. + * + * FIXME: should we create a separate "struct lock_request" to help distinguish + * these two uses? + * + * The i_flock list is ordered by: + * + * 1) lock type -- FL_LEASEs first, then FL_FLOCK, and finally FL_POSIX + * 2) lock owner + * 3) lock range start + * 4) lock range end + * + * Obviously, the last two criteria only matter for POSIX locks. + */ struct file_lock { struct file_lock *fl_next; /* singly linked list for this inode */ struct list_head fl_link; /* doubly linked list of all locks */ -- GitLab From ee574c5ff5266d1951255cf4c69f6530fcbe336e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:13 -0400 Subject: [PATCH 284/528] locks: make "added" in __posix_lock_file a bool Signed-off-by: Jeff Layton Acked-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: I0c1fbb2cb714a928b8d49516dc42ea24ee59968d --- fs/locks.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index b41ad68b763b..f1a790d262ca 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -791,7 +791,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str struct file_lock *left = NULL; struct file_lock *right = NULL; struct file_lock **before; - int error, added = 0; + int error; + bool added = false; /* * We may need two file_lock structures for this operation, @@ -885,7 +886,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str continue; } request = fl; - added = 1; + added = true; } else { /* Processing for different lock types is a bit @@ -896,7 +897,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str if (fl->fl_start > request->fl_end) break; if (request->fl_type == F_UNLCK) - added = 1; + added = true; if (fl->fl_start < request->fl_start) left = fl; /* If the next lock in the list has a higher end @@ -926,7 +927,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str locks_release_private(fl); locks_copy_private(fl, request); request = fl; - added = 1; + added = true; } } /* Go on to next lock. -- GitLab From c75d837e3810c89bd886ecd45af36ed7f93e4f60 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:14 -0400 Subject: [PATCH 285/528] locks: encapsulate the fl_link list handling Move the fl_link list handling routines into a separate set of helpers. Also ensure that locks and requests are always put on global lists last (after fully initializing them) and are taken off before unintializing them. Signed-off-by: Jeff Layton Signed-off-by: Al Viro Change-Id: I27196b07033861862afbc4b432111aea179f5dc3 --- fs/locks.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index f1a790d262ca..183eefce3a73 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -153,13 +153,15 @@ int lease_break_time = 45; #define for_each_lock(inode, lockp) \ for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) +/* The global file_lock_list is only used for displaying /proc/locks. */ static LIST_HEAD(file_lock_list); + +/* The blocked_list is used to find POSIX lock loops for deadlock detection. */ static LIST_HEAD(blocked_list); + +/* Protects the two list heads above, plus the inode->i_flock list */ static DEFINE_SPINLOCK(file_lock_lock); -/* - * Protects the two list heads above, plus the inode->i_flock list - */ void lock_flocks(void) { spin_lock(&file_lock_lock); @@ -484,13 +486,37 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) return fl1->fl_owner == fl2->fl_owner; } +static inline void +locks_insert_global_locks(struct file_lock *fl) +{ + list_add_tail(&fl->fl_link, &file_lock_list); +} + +static inline void +locks_delete_global_locks(struct file_lock *fl) +{ + list_del_init(&fl->fl_link); +} + +static inline void +locks_insert_global_blocked(struct file_lock *waiter) +{ + list_add(&waiter->fl_link, &blocked_list); +} + +static inline void +locks_delete_global_blocked(struct file_lock *waiter) +{ + list_del_init(&waiter->fl_link); +} + /* Remove waiter from blocker's block list. * When blocker ends up pointing to itself then the list is empty. */ static void __locks_delete_block(struct file_lock *waiter) { + locks_delete_global_blocked(waiter); list_del_init(&waiter->fl_block); - list_del_init(&waiter->fl_link); waiter->fl_next = NULL; } @@ -512,10 +538,10 @@ static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter) { BUG_ON(!list_empty(&waiter->fl_block)); - list_add_tail(&waiter->fl_block, &blocker->fl_block); waiter->fl_next = blocker; + list_add_tail(&waiter->fl_block, &blocker->fl_block); if (IS_POSIX(blocker)) - list_add(&waiter->fl_link, &blocked_list); + locks_insert_global_blocked(request); } /* @@ -543,13 +569,13 @@ static void locks_wake_up_blocks(struct file_lock *blocker) */ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) { - list_add(&fl->fl_link, &file_lock_list); - fl->fl_nspid = get_pid(task_tgid(current)); /* insert into file's list */ fl->fl_next = *pos; *pos = fl; + + locks_insert_global_locks(fl); } /* @@ -562,9 +588,10 @@ static void locks_delete_lock(struct file_lock **thisfl_p) { struct file_lock *fl = *thisfl_p; + locks_delete_global_locks(fl); + *thisfl_p = fl->fl_next; fl->fl_next = NULL; - list_del_init(&fl->fl_link); if (fl->fl_nspid) { put_pid(fl->fl_nspid); -- GitLab From c4783521d188fea99a81d9451bc862b1f473f7a2 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:15 -0400 Subject: [PATCH 286/528] locks: protect most of the file_lock handling with i_lock Having a global lock that protects all of this code is a clear scalability problem. Instead of doing that, move most of the code to be protected by the i_lock instead. The exceptions are the global lists that the ->fl_link sits on, and the ->fl_block list. ->fl_link is what connects these structures to the global lists, so we must ensure that we hold those locks when iterating over or updating these lists. Furthermore, sound deadlock detection requires that we hold the blocked_list state steady while checking for loops. We also must ensure that the search and update to the list are atomic. For the checking and insertion side of the blocked_list, push the acquisition of the global lock into __posix_lock_file and ensure that checking and update of the blocked_list is done without dropping the lock in between. On the removal side, when waking up blocked lock waiters, take the global lock before walking the blocked list and dequeue the waiters from the global list prior to removal from the fl_block list. With this, deadlock detection should be race free while we minimize excessive file_lock_lock thrashing. Finally, in order to avoid a lock inversion problem when handling /proc/locks output we must ensure that manipulations of the fl_block list are also protected by the file_lock_lock. Signed-off-by: Jeff Layton Signed-off-by: Al Viro Change-Id: I0b6072aaf983178fbcad930fae25bf34ebd279f1 --- Documentation/filesystems/Locking | 21 ++-- fs/afs/flock.c | 7 +- fs/ceph/locks.c | 2 +- fs/ceph/mds_client.c | 8 +- fs/cifs/cifsfs.c | 2 +- fs/cifs/file.c | 13 +-- fs/gfs2/file.c | 2 +- fs/lockd/svcsubs.c | 12 +-- fs/locks.c | 164 +++++++++++++++++++----------- fs/nfs/delegation.c | 10 +- fs/nfs/nfs4state.c | 8 +- fs/nfsd/nfs4state.c | 8 +- include/linux/fs.h | 11 -- 13 files changed, 155 insertions(+), 113 deletions(-) diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 0706d32a61e6..413685f4d352 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -344,7 +344,7 @@ prototypes: locking rules: - file_lock_lock may block + inode->i_lock may block fl_copy_lock: yes no fl_release_private: maybe no @@ -357,12 +357,19 @@ prototypes: int (*lm_change)(struct file_lock **, int); locking rules: - file_lock_lock may block -lm_compare_owner: yes no -lm_notify: yes no -lm_grant: no no -lm_break: yes no -lm_change yes no + + inode->i_lock file_lock_lock may block +lm_compare_owner: yes[1] maybe no +lm_notify: yes yes no +lm_grant: no no no +lm_break: yes no no +lm_change yes no no + +[1]: ->lm_compare_owner is generally called with *an* inode->i_lock held. It +may not be the i_lock of the inode for either file_lock being compared! This is +the case with deadlock detection, since the code has to chase down the owners +of locks that may be entirely unrelated to the one on which the lock is being +acquired. When doing a search for deadlocks, the file_lock_lock is also held. --------------------------- buffer_head ----------------------------------- prototypes: diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 2497bf306c70..a8cf2cff836c 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -252,7 +252,8 @@ static void afs_defer_unlock(struct afs_vnode *vnode, struct key *key) */ static int afs_do_setlk(struct file *file, struct file_lock *fl) { - struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host); + struct inode *inode = file_inode(file); + struct afs_vnode *vnode = AFS_FS_I(inode); afs_lock_type_t type; struct key *key = file->private_data; int ret; @@ -273,7 +274,7 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl) type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; - lock_flocks(); + spin_lock(&inode->i_lock); /* make sure we've got a callback on this file and that our view of the * data version is up to date */ @@ -420,7 +421,7 @@ given_lock: afs_vnode_fetch_status(vnode, NULL, key); error: - unlock_flocks(); + spin_unlock(&inode->i_lock); _leave(" = %d", ret); return ret; diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index ebbf680378e2..690f73f42425 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -192,7 +192,7 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) /** * Encode the flock and fcntl locks for the given inode into the ceph_filelock - * array. Must be called with lock_flocks() already held. + * array. Must be called with inode->i_lock already held. * If we encounter more of a specific lock type than expected, return -ENOSPC. */ int ceph_encode_locks_to_buffer(struct inode *inode, diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index d6a536886472..7fc9e572d899 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2488,20 +2488,20 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, struct ceph_filelock *flocks; encode_again: - lock_flocks(); + spin_lock(&inode->i_lock); ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks); - unlock_flocks(); + spin_unlock(&inode->i_lock); flocks = kmalloc((num_fcntl_locks+num_flock_locks) * sizeof(struct ceph_filelock), GFP_NOFS); if (!flocks) { err = -ENOMEM; goto out_free; } - lock_flocks(); + spin_lock(&inode->i_lock); err = ceph_encode_locks_to_buffer(inode, flocks, num_fcntl_locks, num_flock_locks); - unlock_flocks(); + spin_unlock(&inode->i_lock); if (err) { kfree(flocks); if (err == -ENOSPC) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f1f75826d27b..d375ce93080e 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -773,7 +773,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) { - /* note that this is called by vfs setlease with lock_flocks held + /* note that this is called by vfs setlease with i_lock held to protect *lease from going away */ struct inode *inode = file_inode(file); struct cifsFileInfo *cfile = file->private_data; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 30f48dbfafcf..96cd9be00bf9 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1091,6 +1091,7 @@ struct lock_to_push { static int cifs_push_posix_locks(struct cifsFileInfo *cfile) { + struct inode *inode = cfile->dentry->d_inode; struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct file_lock *flock, **before; unsigned int count = 0, i = 0; @@ -1101,12 +1102,12 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) xid = get_xid(); - lock_flocks(); - cifs_for_each_lock(cfile->dentry->d_inode, before) { + spin_lock(&inode->i_lock); + cifs_for_each_lock(inode, before) { if ((*before)->fl_flags & FL_POSIX) count++; } - unlock_flocks(); + spin_unlock(&inode->i_lock); INIT_LIST_HEAD(&locks_to_send); @@ -1125,8 +1126,8 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) } el = locks_to_send.next; - lock_flocks(); - cifs_for_each_lock(cfile->dentry->d_inode, before) { + spin_lock(&inode->i_lock); + cifs_for_each_lock(inode, before) { flock = *before; if ((flock->fl_flags & FL_POSIX) == 0) continue; @@ -1151,7 +1152,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) lck->offset = flock->fl_start; el = el->next; } - unlock_flocks(); + spin_unlock(&inode->i_lock); list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { int stored_rc; diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index ad0dc38d87ab..2398b410898f 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -896,7 +896,7 @@ out_uninit: * cluster; until we do, disable leases (by just returning -EINVAL), * unless the administrator has requested purely local locking. * - * Locking: called under lock_flocks + * Locking: called under i_lock * * Returns: errno */ diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 97e87415b145..dc5c75930f0f 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -169,7 +169,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, again: file->f_locks = 0; - lock_flocks(); /* protects i_flock list */ + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl; fl = fl->fl_next) { if (fl->fl_lmops != &nlmsvc_lock_operations) continue; @@ -181,7 +181,7 @@ again: if (match(lockhost, host)) { struct file_lock lock = *fl; - unlock_flocks(); + spin_unlock(&inode->i_lock); lock.fl_type = F_UNLCK; lock.fl_start = 0; lock.fl_end = OFFSET_MAX; @@ -193,7 +193,7 @@ again: goto again; } } - unlock_flocks(); + spin_unlock(&inode->i_lock); return 0; } @@ -228,14 +228,14 @@ nlm_file_inuse(struct nlm_file *file) if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares) return 1; - lock_flocks(); + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl; fl = fl->fl_next) { if (fl->fl_lmops == &nlmsvc_lock_operations) { - unlock_flocks(); + spin_unlock(&inode->i_lock); return 1; } } - unlock_flocks(); + spin_unlock(&inode->i_lock); file->f_locks = 0; return 0; } diff --git a/fs/locks.c b/fs/locks.c index 183eefce3a73..4ce0717b24c9 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -153,27 +153,37 @@ int lease_break_time = 45; #define for_each_lock(inode, lockp) \ for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) -/* The global file_lock_list is only used for displaying /proc/locks. */ +/* + * The global file_lock_list is only used for displaying /proc/locks. Protected + * by the file_lock_lock. + */ static LIST_HEAD(file_lock_list); -/* The blocked_list is used to find POSIX lock loops for deadlock detection. */ +/* + * The blocked_list is used to find POSIX lock loops for deadlock detection. + * Protected by file_lock_lock. + */ static LIST_HEAD(blocked_list); -/* Protects the two list heads above, plus the inode->i_flock list */ +/* + * This lock protects the blocked_list, and the file_lock_list. Generally, if + * you're accessing one of those lists, you want to be holding this lock. + * + * In addition, it also protects the fl->fl_block list, and the fl->fl_next + * pointer for file_lock structures that are acting as lock requests (in + * contrast to those that are acting as records of acquired locks). + * + * Note that when we acquire this lock in order to change the above fields, + * we often hold the i_lock as well. In certain cases, when reading the fields + * protected by this lock, we can skip acquiring it iff we already hold the + * i_lock. + * + * In particular, adding an entry to the fl_block list requires that you hold + * both the i_lock and the blocked_lock_lock (acquired in that order). Deleting + * an entry from the list however only requires the file_lock_lock. + */ static DEFINE_SPINLOCK(file_lock_lock); -void lock_flocks(void) -{ - spin_lock(&file_lock_lock); -} -EXPORT_SYMBOL_GPL(lock_flocks); - -void unlock_flocks(void) -{ - spin_unlock(&file_lock_lock); -} -EXPORT_SYMBOL_GPL(unlock_flocks); - static struct kmem_cache *filelock_cache __read_mostly; static void locks_init_lock_heads(struct file_lock *fl) @@ -489,13 +499,17 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) static inline void locks_insert_global_locks(struct file_lock *fl) { + spin_lock(&file_lock_lock); list_add_tail(&fl->fl_link, &file_lock_list); + spin_unlock(&file_lock_lock); } static inline void locks_delete_global_locks(struct file_lock *fl) { + spin_lock(&file_lock_lock); list_del_init(&fl->fl_link); + spin_unlock(&file_lock_lock); } static inline void @@ -512,6 +526,8 @@ locks_delete_global_blocked(struct file_lock *waiter) /* Remove waiter from blocker's block list. * When blocker ends up pointing to itself then the list is empty. + * + * Must be called with file_lock_lock held. */ static void __locks_delete_block(struct file_lock *waiter) { @@ -520,37 +536,47 @@ static void __locks_delete_block(struct file_lock *waiter) waiter->fl_next = NULL; } -/* - */ static void locks_delete_block(struct file_lock *waiter) { - lock_flocks(); + spin_lock(&file_lock_lock); __locks_delete_block(waiter); - unlock_flocks(); + spin_unlock(&file_lock_lock); } /* Insert waiter into blocker's block list. * We use a circular list so that processes can be easily woken up in * the order they blocked. The documentation doesn't require this but * it seems like the reasonable thing to do. + * + * Must be called with file_lock_lock held! */ -static void locks_insert_block(struct file_lock *blocker, - struct file_lock *waiter) +static void __locks_insert_block(struct file_lock *blocker, + struct file_lock *waiter) { BUG_ON(!list_empty(&waiter->fl_block)); waiter->fl_next = blocker; list_add_tail(&waiter->fl_block, &blocker->fl_block); if (IS_POSIX(blocker)) - locks_insert_global_blocked(request); + locks_insert_global_blocked(waiter); +} + +/* Must be called with i_lock held. */ +static void locks_insert_block(struct file_lock *blocker, + struct file_lock *waiter) +{ + spin_lock(&file_lock_lock); + __locks_insert_block(blocker, waiter); + spin_unlock(&file_lock_lock); } /* * Wake up processes blocked waiting for blocker. * - * Must be called with the file_lock_lock held! + * Must be called with the inode->i_lock held! */ static void locks_wake_up_blocks(struct file_lock *blocker) { + spin_lock(&file_lock_lock); while (!list_empty(&blocker->fl_block)) { struct file_lock *waiter; @@ -562,10 +588,13 @@ static void locks_wake_up_blocks(struct file_lock *blocker) else wake_up(&waiter->fl_wait); } + spin_unlock(&file_lock_lock); } /* Insert file lock fl into an inode's lock list at the position indicated * by pos. At the same time add the lock to the global file lock list. + * + * Must be called with the i_lock held! */ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) { @@ -583,6 +612,8 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) * Wake up processes that are blocked waiting for this lock, * notify the FS that the lock has been cleared and * finally free the lock. + * + * Must be called with the i_lock held! */ static void locks_delete_lock(struct file_lock **thisfl_p) { @@ -652,8 +683,9 @@ void posix_test_lock(struct file *filp, struct file_lock *fl) { struct file_lock *cfl; + struct inode *inode = file_inode(filp); - lock_flocks(); + spin_lock(&inode->i_lock); for (cfl = file_inode(filp)->i_flock; cfl; cfl = cfl->fl_next) { if (!IS_POSIX(cfl)) continue; @@ -666,7 +698,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) fl->fl_pid = pid_vnr(cfl->fl_nspid); } else fl->fl_type = F_UNLCK; - unlock_flocks(); + spin_unlock(&inode->i_lock); return; } EXPORT_SYMBOL(posix_test_lock); @@ -710,6 +742,7 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl) return NULL; } +/* Must be called with the file_lock_lock held! */ static int posix_locks_deadlock(struct file_lock *caller_fl, struct file_lock *block_fl) { @@ -745,7 +778,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) return -ENOMEM; } - lock_flocks(); + spin_lock(&inode->i_lock); if (request->fl_flags & FL_ACCESS) goto find_conflict; @@ -775,9 +808,9 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) * give it the opportunity to lock the file. */ if (found) { - unlock_flocks(); + spin_unlock(&inode->i_lock); cond_resched(); - lock_flocks(); + spin_lock(&inode->i_lock); } find_conflict: @@ -804,7 +837,7 @@ find_conflict: error = 0; out: - unlock_flocks(); + spin_unlock(&inode->i_lock); if (new_fl) locks_free_lock(new_fl); return error; @@ -834,7 +867,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str new_fl2 = locks_alloc_lock(); } - lock_flocks(); + spin_lock(&inode->i_lock); /* * New lock request. Walk all POSIX locks and look for conflicts. If * there are any, either return error or put the request on the @@ -852,11 +885,17 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str error = -EAGAIN; if (!(request->fl_flags & FL_SLEEP)) goto out; + /* + * Deadlock detection and insertion into the blocked + * locks list must be done while holding the same lock! + */ error = -EDEADLK; - if (posix_locks_deadlock(request, fl)) - goto out; - error = FILE_LOCK_DEFERRED; - locks_insert_block(fl, request); + spin_lock(&file_lock_lock); + if (likely(!posix_locks_deadlock(request, fl))) { + error = FILE_LOCK_DEFERRED; + __locks_insert_block(fl, request); + } + spin_unlock(&file_lock_lock); goto out; } } @@ -1006,7 +1045,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str locks_wake_up_blocks(left); } out: - unlock_flocks(); + spin_unlock(&inode->i_lock); /* * Free any unused locks. */ @@ -1081,14 +1120,14 @@ int locks_mandatory_locked(struct inode *inode) /* * Search the lock list for this inode for any POSIX locks. */ - lock_flocks(); + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!IS_POSIX(fl)) continue; if (fl->fl_owner != owner) break; } - unlock_flocks(); + spin_unlock(&inode->i_lock); return fl ? -EAGAIN : 0; } @@ -1231,7 +1270,7 @@ int __break_lease(struct inode *inode, unsigned int mode) if (IS_ERR(new_fl)) return PTR_ERR(new_fl); - lock_flocks(); + spin_lock(&inode->i_lock); time_out_leases(inode); @@ -1280,11 +1319,11 @@ restart: if (break_time == 0) break_time++; locks_insert_block(flock, new_fl); - unlock_flocks(); + spin_unlock(&inode->i_lock); error = wait_event_interruptible_timeout(new_fl->fl_wait, !new_fl->fl_next, break_time); - lock_flocks(); - __locks_delete_block(new_fl); + spin_lock(&inode->i_lock); + locks_delete_block(new_fl); if (error >= 0) { if (error == 0) time_out_leases(inode); @@ -1301,7 +1340,7 @@ restart: } out: - unlock_flocks(); + spin_unlock(&inode->i_lock); locks_free_lock(new_fl); return error; } @@ -1354,9 +1393,10 @@ EXPORT_SYMBOL(lease_get_mtime); int fcntl_getlease(struct file *filp) { struct file_lock *fl; + struct inode *inode = file_inode(filp); int type = F_UNLCK; - lock_flocks(); + spin_lock(&inode->i_lock); time_out_leases(file_inode(filp)); for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl); fl = fl->fl_next) { @@ -1365,7 +1405,7 @@ int fcntl_getlease(struct file *filp) break; } } - unlock_flocks(); + spin_unlock(&inode->i_lock); return type; } @@ -1459,7 +1499,7 @@ static int generic_delete_lease(struct file *filp, struct file_lock **flp) * The (input) flp->fl_lmops->lm_break function is required * by break_lease(). * - * Called with file_lock_lock held. + * Called with inode->i_lock held. */ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) { @@ -1528,11 +1568,12 @@ static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease) int vfs_setlease(struct file *filp, long arg, struct file_lock **lease) { + struct inode *inode = file_inode(filp); int error; - lock_flocks(); + spin_lock(&inode->i_lock); error = __vfs_setlease(filp, arg, lease); - unlock_flocks(); + spin_unlock(&inode->i_lock); return error; } @@ -1550,6 +1591,7 @@ static int do_fcntl_delete_lease(struct file *filp) static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) { struct file_lock *fl, *ret; + struct inode *inode = file_inode(filp); struct fasync_struct *new; int error; @@ -1563,10 +1605,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) return -ENOMEM; } ret = fl; - lock_flocks(); + spin_lock(&inode->i_lock); error = __vfs_setlease(filp, arg, &ret); if (error) { - unlock_flocks(); + spin_unlock(&inode->i_lock); locks_free_lock(fl); goto out_free_fasync; } @@ -1583,7 +1625,7 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) new = NULL; error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); - unlock_flocks(); + spin_unlock(&inode->i_lock); out_free_fasync: if (new) @@ -2116,7 +2158,7 @@ void locks_remove_flock(struct file *filp) fl.fl_ops->fl_release_private(&fl); } - lock_flocks(); + spin_lock(&inode->i_lock); before = &inode->i_flock; while ((fl = *before) != NULL) { @@ -2134,7 +2176,7 @@ void locks_remove_flock(struct file *filp) } before = &fl->fl_next; } - unlock_flocks(); + spin_unlock(&inode->i_lock); } /** @@ -2148,12 +2190,12 @@ posix_unblock_lock(struct file_lock *waiter) { int status = 0; - lock_flocks(); + spin_lock(&file_lock_lock); if (waiter->fl_next) __locks_delete_block(waiter); else status = -ENOENT; - unlock_flocks(); + spin_unlock(&file_lock_lock); return status; } EXPORT_SYMBOL(posix_unblock_lock); @@ -2267,7 +2309,7 @@ static void *locks_start(struct seq_file *f, loff_t *pos) { loff_t *p = f->private; - lock_flocks(); + spin_lock(&file_lock_lock); *p = (*pos + 1); return seq_list_start(&file_lock_list, *pos); } @@ -2281,7 +2323,7 @@ static void *locks_next(struct seq_file *f, void *v, loff_t *pos) static void locks_stop(struct seq_file *f, void *v) { - unlock_flocks(); + spin_unlock(&file_lock_lock); } static const struct seq_operations locks_seq_operations = { @@ -2328,7 +2370,8 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len) { struct file_lock *fl; int result = 1; - lock_flocks(); + + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (IS_POSIX(fl)) { if (fl->fl_type == F_RDLCK) @@ -2345,7 +2388,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len) result = 0; break; } - unlock_flocks(); + spin_unlock(&inode->i_lock); return result; } @@ -2368,7 +2411,8 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len) { struct file_lock *fl; int result = 1; - lock_flocks(); + + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (IS_POSIX(fl)) { if ((fl->fl_end < start) || (fl->fl_start > (start + len))) @@ -2383,7 +2427,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len) result = 0; break; } - unlock_flocks(); + spin_unlock(&inode->i_lock); return result; } diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index ef0c394b7bf5..a44579671525 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -73,20 +73,20 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ if (inode->i_flock == NULL) goto out; - /* Protect inode->i_flock using the file locks lock */ - lock_flocks(); + /* Protect inode->i_flock using the i_lock */ + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) continue; if (nfs_file_open_context(fl->fl_file) != ctx) continue; - unlock_flocks(); + spin_unlock(&inode->i_lock); status = nfs4_lock_delegation_recall(fl, state, stateid); if (status < 0) goto out; - lock_flocks(); + spin_lock(&inode->i_lock); } - unlock_flocks(); + spin_unlock(&inode->i_lock); out: return status; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 8a67b3e633a5..a3fb2776f9bc 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1372,13 +1372,13 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ /* Guard against delegation returns and new lock/unlock calls */ down_write(&nfsi->rwsem); /* Protect inode->i_flock using the BKL */ - lock_flocks(); + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) continue; if (nfs_file_open_context(fl->fl_file)->state != state) continue; - unlock_flocks(); + spin_unlock(&inode->i_lock); status = ops->recover_lock(state, fl); switch (status) { case 0: @@ -1405,9 +1405,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ /* kill_proc(fl->fl_pid, SIGLOST, 1); */ status = 0; } - lock_flocks(); + spin_lock(&inode->i_lock); } - unlock_flocks(); + spin_unlock(&inode->i_lock); out: up_write(&nfsi->rwsem); return status; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b0878e1921be..962e1bac4a33 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2642,13 +2642,13 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); - /* only place dl_time is set. protected by lock_flocks*/ + /* Only place dl_time is set; protected by i_lock: */ dp->dl_time = get_seconds(); nfsd4_cb_recall(dp); } -/* Called from break_lease() with lock_flocks() held. */ +/* Called from break_lease() with i_lock held. */ static void nfsd_break_deleg_cb(struct file_lock *fl) { struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; @@ -4541,7 +4541,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) struct inode *inode = filp->fi_inode; int status = 0; - lock_flocks(); + spin_lock(&inode->i_lock); for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { if ((*flpp)->fl_owner == (fl_owner_t)lowner) { status = 1; @@ -4549,7 +4549,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) } } out: - unlock_flocks(); + spin_unlock(&inode->i_lock); return status; } diff --git a/include/linux/fs.h b/include/linux/fs.h index cd282160f2a7..4acd320ebb22 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1055,8 +1055,6 @@ extern int vfs_setlease(struct file *, long, struct file_lock **); extern int lease_modify(struct file_lock **, int); extern int lock_may_read(struct inode *, loff_t start, unsigned long count); extern int lock_may_write(struct inode *, loff_t start, unsigned long count); -extern void lock_flocks(void); -extern void unlock_flocks(void); #else /* !CONFIG_FILE_LOCKING */ static inline int fcntl_getlk(struct file *file, struct flock __user *user) { @@ -1197,15 +1195,6 @@ static inline int lock_may_write(struct inode *inode, loff_t start, { return 1; } - -static inline void lock_flocks(void) -{ -} - -static inline void unlock_flocks(void) -{ -} - #endif /* !CONFIG_FILE_LOCKING */ -- GitLab From 98499f090653f68a82c98f391d8738b19c878364 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:16 -0400 Subject: [PATCH 287/528] locks: avoid taking global lock if possible when waking up blocked waiters Since we always hold the i_lock when inserting a new waiter onto the fl_block list, we can avoid taking the global lock at all if we find that it's empty when we go to wake up blocked waiters. Signed-off-by: Jeff Layton Signed-off-by: Al Viro Change-Id: Idb760e44765d2cdc1a7c939a65bc1174905a9881 --- fs/locks.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/locks.c b/fs/locks.c index 4ce0717b24c9..dd1b3ead5d83 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -548,7 +548,10 @@ static void locks_delete_block(struct file_lock *waiter) * the order they blocked. The documentation doesn't require this but * it seems like the reasonable thing to do. * - * Must be called with file_lock_lock held! + * Must be called with both the i_lock and file_lock_lock held. The fl_block + * list itself is protected by the file_lock_list, but by ensuring that the + * i_lock is also held on insertions we can avoid taking the file_lock_lock + * in some cases when we see that the fl_block list is empty. */ static void __locks_insert_block(struct file_lock *blocker, struct file_lock *waiter) @@ -576,6 +579,16 @@ static void locks_insert_block(struct file_lock *blocker, */ static void locks_wake_up_blocks(struct file_lock *blocker) { + /* + * Avoid taking global lock if list is empty. This is safe since new + * blocked requests are only added to the list under the i_lock, and + * the i_lock is always held here. Note that removal from the fl_block + * list does not require the i_lock, so we must recheck list_empty() + * after acquiring the file_lock_lock. + */ + if (list_empty(&blocker->fl_block)) + return; + spin_lock(&file_lock_lock); while (!list_empty(&blocker->fl_block)) { struct file_lock *waiter; -- GitLab From f00a57745acd4b02b41666e1b1d4c33c45865fc3 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:17 -0400 Subject: [PATCH 288/528] locks: convert fl_link to a hlist_node Testing has shown that iterating over the blocked_list for deadlock detection turns out to be a bottleneck. In order to alleviate that, begin the process of turning it into a hashtable. We start by turning the fl_link into a hlist_node and the global lists into hlists. A later patch will do the conversion of the blocked_list to a hashtable. Signed-off-by: Jeff Layton Acked-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: I99eb0f734036a5c0563cd463d0fb8895c6b3e25d --- fs/locks.c | 24 ++++++++++++------------ include/linux/fs.h | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index dd1b3ead5d83..ea806218a520 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -157,13 +157,13 @@ int lease_break_time = 45; * The global file_lock_list is only used for displaying /proc/locks. Protected * by the file_lock_lock. */ -static LIST_HEAD(file_lock_list); +static HLIST_HEAD(file_lock_list); /* * The blocked_list is used to find POSIX lock loops for deadlock detection. * Protected by file_lock_lock. */ -static LIST_HEAD(blocked_list); +static HLIST_HEAD(blocked_list); /* * This lock protects the blocked_list, and the file_lock_list. Generally, if @@ -188,7 +188,7 @@ static struct kmem_cache *filelock_cache __read_mostly; static void locks_init_lock_heads(struct file_lock *fl) { - INIT_LIST_HEAD(&fl->fl_link); + INIT_HLIST_NODE(&fl->fl_link); INIT_LIST_HEAD(&fl->fl_block); init_waitqueue_head(&fl->fl_wait); } @@ -222,7 +222,7 @@ void locks_free_lock(struct file_lock *fl) { BUG_ON(waitqueue_active(&fl->fl_wait)); BUG_ON(!list_empty(&fl->fl_block)); - BUG_ON(!list_empty(&fl->fl_link)); + BUG_ON(!hlist_unhashed(&fl->fl_link)); locks_release_private(fl); kmem_cache_free(filelock_cache, fl); @@ -500,7 +500,7 @@ static inline void locks_insert_global_locks(struct file_lock *fl) { spin_lock(&file_lock_lock); - list_add_tail(&fl->fl_link, &file_lock_list); + hlist_add_head(&fl->fl_link, &file_lock_list); spin_unlock(&file_lock_lock); } @@ -508,20 +508,20 @@ static inline void locks_delete_global_locks(struct file_lock *fl) { spin_lock(&file_lock_lock); - list_del_init(&fl->fl_link); + hlist_del_init(&fl->fl_link); spin_unlock(&file_lock_lock); } static inline void locks_insert_global_blocked(struct file_lock *waiter) { - list_add(&waiter->fl_link, &blocked_list); + hlist_add_head(&waiter->fl_link, &blocked_list); } static inline void locks_delete_global_blocked(struct file_lock *waiter) { - list_del_init(&waiter->fl_link); + hlist_del_init(&waiter->fl_link); } /* Remove waiter from blocker's block list. @@ -748,7 +748,7 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl) { struct file_lock *fl; - list_for_each_entry(fl, &blocked_list, fl_link) { + hlist_for_each_entry(fl, &blocked_list, fl_link) { if (posix_same_owner(fl, block_fl)) return fl->fl_next; } @@ -2308,7 +2308,7 @@ static int locks_show(struct seq_file *f, void *v) { struct file_lock *fl, *bfl; - fl = list_entry(v, struct file_lock, fl_link); + fl = hlist_entry(v, struct file_lock, fl_link); lock_get_status(f, fl, *((loff_t *)f->private), ""); @@ -2324,14 +2324,14 @@ static void *locks_start(struct seq_file *f, loff_t *pos) spin_lock(&file_lock_lock); *p = (*pos + 1); - return seq_list_start(&file_lock_list, *pos); + return seq_hlist_start(&file_lock_list, *pos); } static void *locks_next(struct seq_file *f, void *v, loff_t *pos) { loff_t *p = f->private; ++*p; - return seq_list_next(v, &file_lock_list, pos); + return seq_hlist_next(v, &file_lock_list, pos); } static void locks_stop(struct seq_file *f, void *v) diff --git a/include/linux/fs.h b/include/linux/fs.h index 4acd320ebb22..ec43056a2287 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -977,7 +977,7 @@ int locks_in_grace(struct net *); */ struct file_lock { struct file_lock *fl_next; /* singly linked list for this inode */ - struct list_head fl_link; /* doubly linked list of all locks */ + struct hlist_node fl_link; /* node in global lists */ struct list_head fl_block; /* circular list of blocked processes */ fl_owner_t fl_owner; unsigned int fl_flags; -- GitLab From a44ce5f72f3a74e4c12528c32d2a9a77f80d1d97 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:18 -0400 Subject: [PATCH 289/528] locks: turn the blocked_list into a hashtable Break up the blocked_list into a hashtable, using the fl_owner as a key. This speeds up searching the hash chains, which is especially significant for deadlock detection. Note that the initial implementation assumes that hashing on fl_owner is sufficient. In most cases it should be, with the notable exception being server-side lockd, which compares ownership using a tuple of the nlm_host and the pid sent in the lock request. So, this may degrade to a single hash bucket when you only have a single NFS client. That will be addressed in a later patch. The careful observer may note that this patch leaves the file_lock_list alone. There's much less of a case for turning the file_lock_list into a hashtable. The only user of that list is the code that generates /proc/locks, and it always walks the entire list. Signed-off-by: Jeff Layton Acked-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: I57b3c1cf16f40dc5a05b16051de61d2a60a04ba1 --- fs/locks.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index ea806218a520..a9efc7d6d121 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -126,6 +126,7 @@ #include #include #include +#include #include @@ -160,13 +161,21 @@ int lease_break_time = 45; static HLIST_HEAD(file_lock_list); /* - * The blocked_list is used to find POSIX lock loops for deadlock detection. - * Protected by file_lock_lock. + * The blocked_hash is used to find POSIX lock loops for deadlock detection. + * It is protected by file_lock_lock. + * + * We hash locks by lockowner in order to optimize searching for the lock a + * particular lockowner is waiting on. + * + * FIXME: make this value scale via some heuristic? We generally will want more + * buckets when we have more lockowners holding locks, but that's a little + * difficult to determine without knowing what the workload will look like. */ -static HLIST_HEAD(blocked_list); +#define BLOCKED_HASH_BITS 7 +static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS); /* - * This lock protects the blocked_list, and the file_lock_list. Generally, if + * This lock protects the blocked_hash and the file_lock_list. Generally, if * you're accessing one of those lists, you want to be holding this lock. * * In addition, it also protects the fl->fl_block list, and the fl->fl_next @@ -515,13 +524,13 @@ locks_delete_global_locks(struct file_lock *fl) static inline void locks_insert_global_blocked(struct file_lock *waiter) { - hlist_add_head(&waiter->fl_link, &blocked_list); + hash_add(blocked_hash, &waiter->fl_link, (unsigned long)waiter->fl_owner); } static inline void locks_delete_global_blocked(struct file_lock *waiter) { - hlist_del_init(&waiter->fl_link); + hash_del(&waiter->fl_link); } /* Remove waiter from blocker's block list. @@ -748,7 +757,7 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl) { struct file_lock *fl; - hlist_for_each_entry(fl, &blocked_list, fl_link) { + hash_for_each_possible(blocked_hash, fl, fl_link, (unsigned long)block_fl->fl_owner) { if (posix_same_owner(fl, block_fl)) return fl->fl_next; } @@ -884,7 +893,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str /* * New lock request. Walk all POSIX locks and look for conflicts. If * there are any, either return error or put the request on the - * blocker's list of waiters and the global blocked_list. + * blocker's list of waiters and the global blocked_hash. */ if (request->fl_type != F_UNLCK) { for_each_lock(inode, before) { -- GitLab From d6efeae63db5cd4bb0b80595125fb073bc3282b6 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:19 -0400 Subject: [PATCH 290/528] locks: add a new "lm_owner_key" lock operation Currently, the hashing that the locking code uses to add these values to the blocked_hash is simply calculated using fl_owner field. That's valid in most cases except for server-side lockd, which validates the owner of a lock based on fl_owner and fl_pid. In the case where you have a small number of NFS clients doing a lot of locking between different processes, you could end up with all the blocked requests sitting in a very small number of hash buckets. Add a new lm_owner_key operation to the lock_manager_operations that will generate an unsigned long to use as the key in the hashtable. That function is only implemented for server-side lockd, and simply XORs the fl_owner and fl_pid. Signed-off-by: Jeff Layton Acked-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: I07e86c719791032403a263042902c8f79fa1b2ca --- Documentation/filesystems/Locking | 16 +++++++++++----- fs/lockd/svclock.c | 12 ++++++++++++ fs/locks.c | 12 ++++++++++-- include/linux/fs.h | 1 + 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 413685f4d352..dfeb01bb940d 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -351,6 +351,7 @@ fl_release_private: maybe no ----------------------- lock_manager_operations --------------------------- prototypes: int (*lm_compare_owner)(struct file_lock *, struct file_lock *); + unsigned long (*lm_owner_key)(struct file_lock *); void (*lm_notify)(struct file_lock *); /* unblock callback */ int (*lm_grant)(struct file_lock *, struct file_lock *, int); void (*lm_break)(struct file_lock *); /* break_lease callback */ @@ -360,16 +361,21 @@ locking rules: inode->i_lock file_lock_lock may block lm_compare_owner: yes[1] maybe no +lm_owner_key yes[1] yes no lm_notify: yes yes no lm_grant: no no no lm_break: yes no no lm_change yes no no -[1]: ->lm_compare_owner is generally called with *an* inode->i_lock held. It -may not be the i_lock of the inode for either file_lock being compared! This is -the case with deadlock detection, since the code has to chase down the owners -of locks that may be entirely unrelated to the one on which the lock is being -acquired. When doing a search for deadlocks, the file_lock_lock is also held. +[1]: ->lm_compare_owner and ->lm_owner_key are generally called with +*an* inode->i_lock held. It may not be the i_lock of the inode +associated with either file_lock argument! This is the case with deadlock +detection, since the code has to chase down the owners of locks that may +be entirely unrelated to the one on which the lock is being acquired. +For deadlock detection however, the file_lock_lock is also held. The +fact that these locks are held ensures that the file_locks do not +disappear out from under you while doing the comparison or generating an +owner key. --------------------------- buffer_head ----------------------------------- prototypes: diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 6f0e9f88caf3..ab798a88ec1d 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -744,8 +744,20 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2) return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid; } +/* + * Since NLM uses two "keys" for tracking locks, we need to hash them down + * to one for the blocked_hash. Here, we're just xor'ing the host address + * with the pid in order to create a key value for picking a hash bucket. + */ +static unsigned long +nlmsvc_owner_key(struct file_lock *fl) +{ + return (unsigned long)fl->fl_owner ^ (unsigned long)fl->fl_pid; +} + const struct lock_manager_operations nlmsvc_lock_operations = { .lm_compare_owner = nlmsvc_same_owner, + .lm_owner_key = nlmsvc_owner_key, .lm_notify = nlmsvc_notify_blocked, .lm_grant = nlmsvc_grant_deferred, }; diff --git a/fs/locks.c b/fs/locks.c index a9efc7d6d121..5c3f8bf950cc 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -521,10 +521,18 @@ locks_delete_global_locks(struct file_lock *fl) spin_unlock(&file_lock_lock); } +static unsigned long +posix_owner_key(struct file_lock *fl) +{ + if (fl->fl_lmops && fl->fl_lmops->lm_owner_key) + return fl->fl_lmops->lm_owner_key(fl); + return (unsigned long)fl->fl_owner; +} + static inline void locks_insert_global_blocked(struct file_lock *waiter) { - hash_add(blocked_hash, &waiter->fl_link, (unsigned long)waiter->fl_owner); + hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter)); } static inline void @@ -757,7 +765,7 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl) { struct file_lock *fl; - hash_for_each_possible(blocked_hash, fl, fl_link, (unsigned long)block_fl->fl_owner) { + hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) { if (posix_same_owner(fl, block_fl)) return fl->fl_next; } diff --git a/include/linux/fs.h b/include/linux/fs.h index ec43056a2287..3c85c40abf7d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -939,6 +939,7 @@ struct file_lock_operations { struct lock_manager_operations { int (*lm_compare_owner)(struct file_lock *, struct file_lock *); + unsigned long (*lm_owner_key)(struct file_lock *); void (*lm_notify)(struct file_lock *); /* unblock callback */ int (*lm_grant)(struct file_lock *, struct file_lock *, int); void (*lm_break)(struct file_lock *); -- GitLab From e409597c8d03b229eff721fd274c1e0e2a170f7a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:20 -0400 Subject: [PATCH 291/528] locks: give the blocked_hash its own spinlock There's no reason we have to protect the blocked_hash and file_lock_list with the same spinlock. With the tests I have, breaking it in two gives a barely measurable performance benefit, but it seems reasonable to make this locking as granular as possible. Signed-off-by: Jeff Layton Signed-off-by: Al Viro Change-Id: I62c3744045394451b066fc21b4236a9c6b989995 --- Documentation/filesystems/Locking | 16 ++++++------ fs/locks.c | 41 +++++++++++++++++-------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index dfeb01bb940d..cf0444857e0d 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -359,20 +359,20 @@ prototypes: locking rules: - inode->i_lock file_lock_lock may block -lm_compare_owner: yes[1] maybe no -lm_owner_key yes[1] yes no -lm_notify: yes yes no -lm_grant: no no no -lm_break: yes no no -lm_change yes no no + inode->i_lock blocked_lock_lock may block +lm_compare_owner: yes[1] maybe no +lm_owner_key yes[1] yes no +lm_notify: yes yes no +lm_grant: no no no +lm_break: yes no no +lm_change yes no no [1]: ->lm_compare_owner and ->lm_owner_key are generally called with *an* inode->i_lock held. It may not be the i_lock of the inode associated with either file_lock argument! This is the case with deadlock detection, since the code has to chase down the owners of locks that may be entirely unrelated to the one on which the lock is being acquired. -For deadlock detection however, the file_lock_lock is also held. The +For deadlock detection however, the blocked_lock_lock is also held. The fact that these locks are held ensures that the file_locks do not disappear out from under you while doing the comparison or generating an owner key. diff --git a/fs/locks.c b/fs/locks.c index 5c3f8bf950cc..1acdce0f3649 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -159,10 +159,11 @@ int lease_break_time = 45; * by the file_lock_lock. */ static HLIST_HEAD(file_lock_list); +static DEFINE_SPINLOCK(file_lock_lock); /* * The blocked_hash is used to find POSIX lock loops for deadlock detection. - * It is protected by file_lock_lock. + * It is protected by blocked_lock_lock. * * We hash locks by lockowner in order to optimize searching for the lock a * particular lockowner is waiting on. @@ -175,8 +176,8 @@ static HLIST_HEAD(file_lock_list); static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS); /* - * This lock protects the blocked_hash and the file_lock_list. Generally, if - * you're accessing one of those lists, you want to be holding this lock. + * This lock protects the blocked_hash. Generally, if you're accessing it, you + * want to be holding this lock. * * In addition, it also protects the fl->fl_block list, and the fl->fl_next * pointer for file_lock structures that are acting as lock requests (in @@ -191,7 +192,7 @@ static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS); * both the i_lock and the blocked_lock_lock (acquired in that order). Deleting * an entry from the list however only requires the file_lock_lock. */ -static DEFINE_SPINLOCK(file_lock_lock); +static DEFINE_SPINLOCK(blocked_lock_lock); static struct kmem_cache *filelock_cache __read_mostly; @@ -544,7 +545,7 @@ locks_delete_global_blocked(struct file_lock *waiter) /* Remove waiter from blocker's block list. * When blocker ends up pointing to itself then the list is empty. * - * Must be called with file_lock_lock held. + * Must be called with blocked_lock_lock held. */ static void __locks_delete_block(struct file_lock *waiter) { @@ -555,9 +556,9 @@ static void __locks_delete_block(struct file_lock *waiter) static void locks_delete_block(struct file_lock *waiter) { - spin_lock(&file_lock_lock); + spin_lock(&blocked_lock_lock); __locks_delete_block(waiter); - spin_unlock(&file_lock_lock); + spin_unlock(&blocked_lock_lock); } /* Insert waiter into blocker's block list. @@ -565,9 +566,9 @@ static void locks_delete_block(struct file_lock *waiter) * the order they blocked. The documentation doesn't require this but * it seems like the reasonable thing to do. * - * Must be called with both the i_lock and file_lock_lock held. The fl_block + * Must be called with both the i_lock and blocked_lock_lock held. The fl_block * list itself is protected by the file_lock_list, but by ensuring that the - * i_lock is also held on insertions we can avoid taking the file_lock_lock + * i_lock is also held on insertions we can avoid taking the blocked_lock_lock * in some cases when we see that the fl_block list is empty. */ static void __locks_insert_block(struct file_lock *blocker, @@ -584,9 +585,9 @@ static void __locks_insert_block(struct file_lock *blocker, static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter) { - spin_lock(&file_lock_lock); + spin_lock(&blocked_lock_lock); __locks_insert_block(blocker, waiter); - spin_unlock(&file_lock_lock); + spin_unlock(&blocked_lock_lock); } /* @@ -601,12 +602,12 @@ static void locks_wake_up_blocks(struct file_lock *blocker) * blocked requests are only added to the list under the i_lock, and * the i_lock is always held here. Note that removal from the fl_block * list does not require the i_lock, so we must recheck list_empty() - * after acquiring the file_lock_lock. + * after acquiring the blocked_lock_lock. */ if (list_empty(&blocker->fl_block)) return; - spin_lock(&file_lock_lock); + spin_lock(&blocked_lock_lock); while (!list_empty(&blocker->fl_block)) { struct file_lock *waiter; @@ -618,7 +619,7 @@ static void locks_wake_up_blocks(struct file_lock *blocker) else wake_up(&waiter->fl_wait); } - spin_unlock(&file_lock_lock); + spin_unlock(&blocked_lock_lock); } /* Insert file lock fl into an inode's lock list at the position indicated @@ -772,7 +773,7 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl) return NULL; } -/* Must be called with the file_lock_lock held! */ +/* Must be called with the blocked_lock_lock held! */ static int posix_locks_deadlock(struct file_lock *caller_fl, struct file_lock *block_fl) { @@ -920,12 +921,12 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str * locks list must be done while holding the same lock! */ error = -EDEADLK; - spin_lock(&file_lock_lock); + spin_lock(&blocked_lock_lock); if (likely(!posix_locks_deadlock(request, fl))) { error = FILE_LOCK_DEFERRED; __locks_insert_block(fl, request); } - spin_unlock(&file_lock_lock); + spin_unlock(&blocked_lock_lock); goto out; } } @@ -2220,12 +2221,12 @@ posix_unblock_lock(struct file_lock *waiter) { int status = 0; - spin_lock(&file_lock_lock); + spin_lock(&blocked_lock_lock); if (waiter->fl_next) __locks_delete_block(waiter); else status = -ENOENT; - spin_unlock(&file_lock_lock); + spin_unlock(&blocked_lock_lock); return status; } EXPORT_SYMBOL(posix_unblock_lock); @@ -2340,6 +2341,7 @@ static void *locks_start(struct seq_file *f, loff_t *pos) loff_t *p = f->private; spin_lock(&file_lock_lock); + spin_lock(&blocked_lock_lock); *p = (*pos + 1); return seq_hlist_start(&file_lock_list, *pos); } @@ -2353,6 +2355,7 @@ static void *locks_next(struct seq_file *f, void *v, loff_t *pos) static void locks_stop(struct seq_file *f, void *v) { + spin_unlock(&blocked_lock_lock); spin_unlock(&file_lock_lock); } -- GitLab From b8c9dec6a77c5969025a3f4d117dd54dd13ef568 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 5 Jul 2013 18:59:33 +0400 Subject: [PATCH 292/528] helper for reading ->d_count Signed-off-by: Al Viro Change-Id: I56f70919ade4241c75f408dbf0b188c42eaa2878 --- fs/autofs4/expire.c | 8 ++++---- fs/autofs4/root.c | 2 +- fs/ceph/inode.c | 4 ++-- fs/ceph/mds_client.c | 2 +- fs/coda/dir.c | 2 +- fs/ecryptfs/inode.c | 2 +- fs/locks.c | 2 +- fs/nfs/dir.c | 6 +++--- fs/nfs/unlink.c | 2 +- fs/nilfs2/super.c | 2 +- include/linux/dcache.h | 5 +++++ 11 files changed, 21 insertions(+), 16 deletions(-) diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 8ad277990eac..d096316533da 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -109,7 +109,7 @@ cont: spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED); /* Already gone or negative dentry (under construction) - try next */ - if (q->d_count == 0 || !simple_positive(q)) { + if (!d_count(q) || !simple_positive(q)) { spin_unlock(&q->d_lock); next = q->d_child.next; goto cont; @@ -267,7 +267,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt, else ino_count++; - if (p->d_count > ino_count) { + if (d_count(p) > ino_count) { top_ino->last_used = jiffies; dput(p); return 1; @@ -409,7 +409,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, if (!exp_leaves) { /* Path walk currently on this dentry? */ ino_count = atomic_read(&ino->count) + 1; - if (dentry->d_count > ino_count) + if (d_count(dentry) > ino_count) goto next; if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { @@ -423,7 +423,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, } else { /* Path walk currently on this dentry? */ ino_count = atomic_read(&ino->count) + 1; - if (dentry->d_count > ino_count) + if (d_count(dentry) > ino_count) goto next; expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 79ab4cb3590a..44e71b64db76 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -179,7 +179,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) spin_lock(&active->d_lock); /* Already gone? */ - if (active->d_count == 0) + if (!d_count(active)) goto next; qstr = &active->d_name; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 0cf23a7b88c2..0d4c4bec4f6d 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -903,8 +903,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, } else if (realdn) { dout("dn %p (%d) spliced with %p (%d) " "inode %p ino %llx.%llx\n", - dn, dn->d_count, - realdn, realdn->d_count, + dn, d_count(dn), + realdn, d_count(realdn), realdn->d_inode, ceph_vinop(realdn->d_inode)); dput(dn); dn = realdn; diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 7fc9e572d899..a2a84ba0cbc4 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1558,7 +1558,7 @@ retry: *base = ceph_ino(temp->d_inode); *plen = len; dout("build_path on %p %d built %llx '%.*s'\n", - dentry, dentry->d_count, *base, len, path); + dentry, d_count(dentry), *base, len, path); return path; } diff --git a/fs/coda/dir.c b/fs/coda/dir.c index fc66861b3598..9fbea840cb0a 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -571,7 +571,7 @@ static int coda_dentry_revalidate(struct dentry *de, unsigned int flags) if (cii->c_flags & C_FLUSH) coda_flag_inode_children(inode, C_FLUSH); - if (de->d_count > 1) + if (d_count(de) > 1) /* pretend it's valid, but don't change the flags */ goto out; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 148959e5b83f..139e3d8bb1e2 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -392,7 +392,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry, lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); fsstack_copy_attr_atime(dir_inode, lower_dentry->d_parent->d_inode); - BUG_ON(!lower_dentry->d_count); + BUG_ON(!d_count(lower_dentry)); ecryptfs_set_dentry_private(dentry, dentry_info); ecryptfs_set_dentry_lower(dentry, lower_dentry); diff --git a/fs/locks.c b/fs/locks.c index 1acdce0f3649..43d5712eb1a0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1453,7 +1453,7 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) goto out; if ((arg == F_WRLCK) - && ((dentry->d_count > 1) + && ((d_count(dentry) > 1) || (atomic_read(&inode->i_count) > 1))) goto out; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f47f6a338a35..5e0aab715864 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1722,7 +1722,7 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry) dir->i_ino, dentry->d_name.name); spin_lock(&dentry->d_lock); - if (dentry->d_count > 1) { + if (d_count(dentry) > 1) { spin_unlock(&dentry->d_lock); /* Start asynchronous writeout of the inode */ write_inode_now(dentry->d_inode, 0); @@ -1871,7 +1871,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", old_dentry->d_parent->d_name.name, old_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name, - new_dentry->d_count); + d_count(new_dentry)); /* * For non-directories, check whether the target is busy and if so, @@ -1889,7 +1889,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, rehash = new_dentry; } - if (new_dentry->d_count > 2) { + if (d_count(new_dentry) > 2) { int err; /* copy the target dentry's name */ diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 1f1f38f0c5d5..60395ad3a2e4 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -479,7 +479,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", dentry->d_parent->d_name.name, dentry->d_name.name, - dentry->d_count); + d_count(dentry)); nfs_inc_stats(dir, NFSIOS_SILLYRENAME); /* diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 4b0a8d4a8345..d474f283d143 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -973,7 +973,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, static int nilfs_tree_was_touched(struct dentry *root_dentry) { - return root_dentry->d_count > 1; + return d_count(root_dentry) > 1; } /** diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 671ab0218edb..0988bf76e92e 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -328,6 +328,11 @@ static inline int __d_rcu_to_refcount(struct dentry *dentry, unsigned seq) return ret; } +static inline unsigned d_count(struct dentry *dentry) +{ + return dentry->d_count; +} + /* validate "insecure" dentry pointer */ extern int d_validate(struct dentry *, struct dentry *); -- GitLab From c0e684bf42794048d5c6e8a6f760bbaf0bf2b8e8 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:21 -0400 Subject: [PATCH 293/528] seq_file: add seq_list_*_percpu helpers When we convert the file_lock_list to a set of percpu lists, we'll need a way to iterate over them in order to output /proc/locks info. Add some seq_list_*_percpu helpers to handle that. Signed-off-by: Jeff Layton Acked-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: I35eccdac75fcc7e3df80a6e5e6887484b947d999 --- fs/seq_file.c | 54 ++++++++++++++++++++++++++++++++++++++++ include/linux/seq_file.h | 6 +++++ 2 files changed, 60 insertions(+) diff --git a/fs/seq_file.c b/fs/seq_file.c index f48a432ff78f..47639c8b309f 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -963,3 +963,57 @@ struct hlist_node *seq_hlist_next_rcu(void *v, return rcu_dereference(node->next); } EXPORT_SYMBOL(seq_hlist_next_rcu); + +/** + * seq_hlist_start_precpu - start an iteration of a percpu hlist array + * @head: pointer to percpu array of struct hlist_heads + * @cpu: pointer to cpu "cursor" + * @pos: start position of sequence + * + * Called at seq_file->op->start(). + */ +struct hlist_node * +seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos) +{ + struct hlist_node *node; + + for_each_possible_cpu(*cpu) { + hlist_for_each(node, per_cpu_ptr(head, *cpu)) { + if (pos-- == 0) + return node; + } + } + return NULL; +} +EXPORT_SYMBOL(seq_hlist_start_percpu); + +/** + * seq_hlist_next_percpu - move to the next position of the percpu hlist array + * @v: pointer to current hlist_node + * @head: pointer to percpu array of struct hlist_heads + * @cpu: pointer to cpu "cursor" + * @pos: start position of sequence + * + * Called at seq_file->op->next(). + */ +struct hlist_node * +seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head, + int *cpu, loff_t *pos) +{ + struct hlist_node *node = v; + + ++*pos; + + if (node->next) + return node->next; + + for (*cpu = cpumask_next(*cpu, cpu_possible_mask); *cpu < nr_cpu_ids; + *cpu = cpumask_next(*cpu, cpu_possible_mask)) { + struct hlist_head *bucket = per_cpu_ptr(head, *cpu); + + if (!hlist_empty(bucket)) + return bucket->first; + } + return NULL; +} +EXPORT_SYMBOL(seq_hlist_next_percpu); diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 6fda30530e9b..8f5b241932ee 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -183,4 +183,10 @@ extern struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head, extern struct hlist_node *seq_hlist_next_rcu(void *v, struct hlist_head *head, loff_t *ppos); + +/* Helpers for iterating over per-cpu hlist_head-s in seq_files */ +extern struct hlist_node *seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos); + +extern struct hlist_node *seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head, int *cpu, loff_t *pos); + #endif -- GitLab From 4c18975bc2c083eaff26a319b646c70265f632e4 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 21 Jun 2013 08:58:22 -0400 Subject: [PATCH 294/528] locks: move file_lock_list to a set of percpu hlist_heads and convert file_lock_lock to an lglock The file_lock_list is only used for /proc/locks. The vastly common case is for locks to be put onto the list and come off again, without ever being traversed. Help optimize for this use-case by moving to percpu hlist_head-s. At the same time, we can make the locking less contentious by moving to an lglock. When iterating over the lists for /proc/locks, we must take the global lock and then iterate over each CPU's list in turn. This change necessitates a new fl_link_cpu field to keep track of which CPU the entry is on. On x86_64 at least, this field is placed within an existing hole in the struct to avoid growing the size. Signed-off-by: Jeff Layton Acked-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: I3426ac60c6e7623512e3f3437de7b0e287e8e3f0 --- fs/locks.c | 69 ++++++++++++++++++++++++++++++++-------------- include/linux/fs.h | 1 + 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 43d5712eb1a0..3c5a37a0eb4e 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -127,6 +127,8 @@ #include #include #include +#include +#include #include @@ -155,11 +157,13 @@ int lease_break_time = 45; for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) /* - * The global file_lock_list is only used for displaying /proc/locks. Protected - * by the file_lock_lock. + * The global file_lock_list is only used for displaying /proc/locks, so we + * keep a list on each CPU, with each list protected by its own spinlock via + * the file_lock_lglock. Note that alterations to the list also require that + * the relevant i_lock is held. */ -static HLIST_HEAD(file_lock_list); -static DEFINE_SPINLOCK(file_lock_lock); +DEFINE_STATIC_LGLOCK(file_lock_lglock); +static DEFINE_PER_CPU(struct hlist_head, file_lock_list); /* * The blocked_hash is used to find POSIX lock loops for deadlock detection. @@ -506,20 +510,30 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) return fl1->fl_owner == fl2->fl_owner; } +/* Must be called with the i_lock held! */ static inline void locks_insert_global_locks(struct file_lock *fl) { - spin_lock(&file_lock_lock); - hlist_add_head(&fl->fl_link, &file_lock_list); - spin_unlock(&file_lock_lock); + lg_local_lock(&file_lock_lglock); + fl->fl_link_cpu = smp_processor_id(); + hlist_add_head(&fl->fl_link, this_cpu_ptr(&file_lock_list)); + lg_local_unlock(&file_lock_lglock); } +/* Must be called with the i_lock held! */ static inline void locks_delete_global_locks(struct file_lock *fl) { - spin_lock(&file_lock_lock); + /* + * Avoid taking lock if already unhashed. This is safe since this check + * is done while holding the i_lock, and new insertions into the list + * also require that it be held. + */ + if (hlist_unhashed(&fl->fl_link)) + return; + lg_local_lock_cpu(&file_lock_lglock, fl->fl_link_cpu); hlist_del_init(&fl->fl_link); - spin_unlock(&file_lock_lock); + lg_local_unlock_cpu(&file_lock_lglock, fl->fl_link_cpu); } static unsigned long @@ -2251,6 +2265,11 @@ EXPORT_SYMBOL_GPL(vfs_cancel_lock); #include #include +struct locks_iterator { + int li_cpu; + loff_t li_pos; +}; + static void lock_get_status(struct seq_file *f, struct file_lock *fl, loff_t id, char *pfx) { @@ -2324,39 +2343,41 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, static int locks_show(struct seq_file *f, void *v) { + struct locks_iterator *iter = f->private; struct file_lock *fl, *bfl; fl = hlist_entry(v, struct file_lock, fl_link); - lock_get_status(f, fl, *((loff_t *)f->private), ""); + lock_get_status(f, fl, iter->li_pos, ""); list_for_each_entry(bfl, &fl->fl_block, fl_block) - lock_get_status(f, bfl, *((loff_t *)f->private), " ->"); + lock_get_status(f, bfl, iter->li_pos, " ->"); return 0; } static void *locks_start(struct seq_file *f, loff_t *pos) { - loff_t *p = f->private; + struct locks_iterator *iter = f->private; - spin_lock(&file_lock_lock); + iter->li_pos = *pos + 1; + lg_global_lock(&file_lock_lglock); spin_lock(&blocked_lock_lock); - *p = (*pos + 1); - return seq_hlist_start(&file_lock_list, *pos); + return seq_hlist_start_percpu(&file_lock_list, &iter->li_cpu, *pos); } static void *locks_next(struct seq_file *f, void *v, loff_t *pos) { - loff_t *p = f->private; - ++*p; - return seq_hlist_next(v, &file_lock_list, pos); + struct locks_iterator *iter = f->private; + + ++iter->li_pos; + return seq_hlist_next_percpu(v, &file_lock_list, &iter->li_cpu, pos); } static void locks_stop(struct seq_file *f, void *v) { spin_unlock(&blocked_lock_lock); - spin_unlock(&file_lock_lock); + lg_global_unlock(&file_lock_lglock); } static const struct seq_operations locks_seq_operations = { @@ -2368,7 +2389,8 @@ static const struct seq_operations locks_seq_operations = { static int locks_open(struct inode *inode, struct file *filp) { - return seq_open_private(filp, &locks_seq_operations, sizeof(loff_t)); + return seq_open_private(filp, &locks_seq_operations, + sizeof(struct locks_iterator)); } static const struct file_operations proc_locks_operations = { @@ -2468,9 +2490,16 @@ EXPORT_SYMBOL(lock_may_write); static int __init filelock_init(void) { + int i; + filelock_cache = kmem_cache_create("file_lock_cache", sizeof(struct file_lock), 0, SLAB_PANIC, NULL); + lg_lock_init(&file_lock_lglock, "file_lock_lglock"); + + for_each_possible_cpu(i) + INIT_HLIST_HEAD(per_cpu_ptr(&file_lock_list, i)); + return 0; } diff --git a/include/linux/fs.h b/include/linux/fs.h index 3c85c40abf7d..bfd5b264f7ac 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -984,6 +984,7 @@ struct file_lock { unsigned int fl_flags; unsigned char fl_type; unsigned int fl_pid; + int fl_link_cpu; /* what cpu's list is this on? */ struct pid *fl_nspid; wait_queue_head_t fl_wait; struct file *fl_file; -- GitLab From 81d766fb80f94e32c0ccbb41fe962a9ac64a903e Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 1 Jul 2011 15:18:34 -0400 Subject: [PATCH 295/528] locks: introduce new FL_DELEG lock flag For now FL_DELEG is just a synonym for FL_LEASE. So this patch doesn't change behavior. Next we'll modify break_lease to treat FL_DELEG leases differently, to account for the fact that NFSv4 delegations should be broken in more situations than Windows oplocks. Acked-by: Jeff Layton Signed-off-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: If8677f0b5062a11cf25ce76bda63aa8b828f365d --- fs/locks.c | 2 +- fs/nfsd/nfs4state.c | 2 +- include/linux/fs.h | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 3c5a37a0eb4e..6dfb034c0f08 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -134,7 +134,7 @@ #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) -#define IS_LEASE(fl) (fl->fl_flags & FL_LEASE) +#define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG)) static bool lease_breaking(struct file_lock *fl) { diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 962e1bac4a33..4bd29c34a90c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2929,7 +2929,7 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int f return NULL; locks_init_lock(fl); fl->fl_lmops = &nfsd_lease_mng_ops; - fl->fl_flags = FL_LEASE; + fl->fl_flags = FL_DELEG; fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; fl->fl_end = OFFSET_MAX; fl->fl_owner = (fl_owner_t)(dp->dl_file); diff --git a/include/linux/fs.h b/include/linux/fs.h index bfd5b264f7ac..4b9092e5195d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -909,6 +909,7 @@ static inline int file_check_writeable(struct file *filp) #define FL_POSIX 1 #define FL_FLOCK 2 +#define FL_DELEG 4 /* NFSv4 delegation */ #define FL_ACCESS 8 /* not trying to lock, just looking */ #define FL_EXISTS 16 /* when unlocking, test for existence */ #define FL_LEASE 32 /* lease held on this file */ -- GitLab From 4a60ef993670b2ca9f14f4e4694b27064335e5df Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 5 Mar 2012 13:18:59 -0500 Subject: [PATCH 296/528] locks: implement delegations Implement NFSv4 delegations at the vfs level using the new FL_DELEG lock type. Note nfsd is the only delegation user and is only using read delegations. Warn on any attempt to set a write delegation for now. We'll come back to that case later. Acked-by: Jeff Layton Signed-off-by: J. Bruce Fields Signed-off-by: Al Viro Change-Id: I3f4b68d3c7840b0abd5d52bbd69bef1318756ef2 --- fs/locks.c | 55 +++++++++++++++++++++++++++++++++++++--------- include/linux/fs.h | 18 ++++++++++++--- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 6dfb034c0f08..91df8befa271 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1292,28 +1292,40 @@ static void time_out_leases(struct inode *inode) } } +static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker) +{ + if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) + return false; + return locks_conflict(breaker, lease); +} + /** * __break_lease - revoke all outstanding leases on file * @inode: the inode of the file to return - * @mode: the open mode (read or write) + * @mode: O_RDONLY: break only write leases; O_WRONLY or O_RDWR: + * break all leases + * @type: FL_LEASE: break leases and delegations; FL_DELEG: break + * only delegations * * break_lease (inlined for speed) has checked there already is at least * some kind of lock (maybe a lease) on this file. Leases are broken on * a call to open() or truncate(). This function can sleep unless you * specified %O_NONBLOCK to your open(). */ -int __break_lease(struct inode *inode, unsigned int mode) +int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) { int error = 0; struct file_lock *new_fl, *flock; struct file_lock *fl; unsigned long break_time; int i_have_this_lease = 0; + bool lease_conflict = false; int want_write = (mode & O_ACCMODE) != O_RDONLY; new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); if (IS_ERR(new_fl)) return PTR_ERR(new_fl); + new_fl->fl_flags = type; spin_lock(&inode->i_lock); @@ -1323,13 +1335,16 @@ int __break_lease(struct inode *inode, unsigned int mode) if ((flock == NULL) || !IS_LEASE(flock)) goto out; - if (!locks_conflict(flock, new_fl)) + for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) { + if (leases_conflict(fl, new_fl)) { + lease_conflict = true; + if (fl->fl_owner == current->files) + i_have_this_lease = 1; + } + } + if (!lease_conflict) goto out; - for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) - if (fl->fl_owner == current->files) - i_have_this_lease = 1; - break_time = 0; if (lease_break_time > 0) { break_time = jiffies + lease_break_time * HZ; @@ -1338,6 +1353,8 @@ int __break_lease(struct inode *inode, unsigned int mode) } for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) { + if (!leases_conflict(fl, new_fl)) + continue; if (want_write) { if (fl->fl_flags & FL_UNLOCK_PENDING) continue; @@ -1378,7 +1395,7 @@ restart: */ for (flock = inode->i_flock; flock && IS_LEASE(flock); flock = flock->fl_next) { - if (locks_conflict(new_fl, flock)) + if (leases_conflict(new_fl, flock)) goto restart; } error = 0; @@ -1459,9 +1476,26 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp struct file_lock *fl, **before, **my_before = NULL, *lease; struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; + bool is_deleg = (*flp)->fl_flags & FL_DELEG; int error; lease = *flp; + /* + * In the delegation case we need mutual exclusion with + * a number of operations that take the i_mutex. We trylock + * because delegations are an optional optimization, and if + * there's some chance of a conflict--we'd rather not + * bother, maybe that's a sign this just isn't a good file to + * hand out a delegation on. + */ + if (is_deleg && !mutex_trylock(&inode->i_mutex)) + return -EAGAIN; + + if (is_deleg && arg == F_WRLCK) { + /* Write delegations are not currently supported: */ + WARN_ON_ONCE(1); + return -EINVAL; + } error = -EAGAIN; if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) @@ -1513,9 +1547,10 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp goto out; locks_insert_lock(before, lease); - return 0; - + error = 0; out: + if (is_deleg) + mutex_unlock(&inode->i_mutex); return error; } diff --git a/include/linux/fs.h b/include/linux/fs.h index 4b9092e5195d..6e90887c98d8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1051,7 +1051,7 @@ extern int vfs_test_lock(struct file *, struct file_lock *); extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *); extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl); extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); -extern int __break_lease(struct inode *inode, unsigned int flags); +extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type); extern void lease_get_mtime(struct inode *, struct timespec *time); extern int generic_setlease(struct file *, long, struct file_lock **); extern int vfs_setlease(struct file *, long, struct file_lock **); @@ -1160,7 +1160,7 @@ static inline int flock_lock_file_wait(struct file *filp, return -ENOLCK; } -static inline int __break_lease(struct inode *inode, unsigned int mode) +static inline int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) { return 0; } @@ -2009,9 +2009,17 @@ static inline int locks_verify_truncate(struct inode *inode, static inline int break_lease(struct inode *inode, unsigned int mode) { if (inode->i_flock) - return __break_lease(inode, mode); + return __break_lease(inode, mode, FL_LEASE); return 0; } + +static inline int break_deleg(struct inode *inode, unsigned int mode) +{ + if (inode->i_flock) + return __break_lease(inode, mode, FL_DELEG); + return 0; +} + #else /* !CONFIG_FILE_LOCKING */ static inline int locks_mandatory_locked(struct inode *inode) { @@ -2051,6 +2059,10 @@ static inline int break_lease(struct inode *inode, unsigned int mode) return 0; } +static inline int break_deleg(struct inode *inode, unsigned int mode) +{ + return 0; +} #endif /* CONFIG_FILE_LOCKING */ /* fs/open.c */ -- GitLab From 3d46ec5178ce97d24197633a4c79021dad06915d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Nov 2013 10:56:27 +0300 Subject: [PATCH 297/528] locks: missing unlock on error in generic_add_lease() We should unlock here before returning. Fixes: df4e8d2c1d2b ('locks: implement delegations') Signed-off-by: Dan Carpenter Signed-off-by: Al Viro Change-Id: Ied93454d00a3365819329f2834eb8301bc59d1eb --- fs/locks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/locks.c b/fs/locks.c index 91df8befa271..f0eb5ce520a0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1493,6 +1493,7 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp if (is_deleg && arg == F_WRLCK) { /* Write delegations are not currently supported: */ + mutex_unlock(&inode->i_mutex); WARN_ON_ONCE(1); return -EINVAL; } -- GitLab From 85932faf28200bd4b62f67d4703c28e0c4280ca6 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:06 -0500 Subject: [PATCH 298/528] locks: close potential race between setlease and open As Al Viro points out, there is an unlikely, but possible race between opening a file and setting a lease on it. generic_add_lease is done with the i_lock held, but the inode->i_flock check in break_lease is lockless. It's possible for another task doing an open to do the entire pathwalk and call break_lease between the point where generic_add_lease checks for a conflicting open and adds the lease to the list. If this occurs, we can end up with a lease set on the file with a conflicting open. To guard against that, check again for a conflicting open after adding the lease to the i_flock list. If the above race occurs, then we can simply unwind the lease setting and return -EAGAIN. Because we take dentry references and acquire write access on the file before calling break_lease, we know that if the i_flock list is empty when the open caller goes to check it then the necessary refcounts have already been incremented. Thus the additional check for a conflicting open will see that there is one and the setlease call will fail. Cc: Bruce Fields Cc: David Howells Cc: "Paul E. McKenney" Reported-by: Al Viro Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields Change-Id: I2460d0f7d8b755cb27f5c99de238bdaca355e712 --- fs/locks.c | 75 ++++++++++++++++++++++++++++++++++++++-------- include/linux/fs.h | 6 ++++ 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index f0eb5ce520a0..9359ee06a8b2 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -652,15 +652,18 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) locks_insert_global_locks(fl); } -/* - * Delete a lock and then free it. - * Wake up processes that are blocked waiting for this lock, - * notify the FS that the lock has been cleared and - * finally free the lock. +/** + * locks_delete_lock - Delete a lock and then free it. + * @thisfl_p: pointer that points to the fl_next field of the previous + * inode->i_flock list entry + * + * Unlink a lock from all lists and free the namespace reference, but don't + * free it yet. Wake up processes that are blocked waiting for this lock and + * notify the FS that the lock has been cleared. * * Must be called with the i_lock held! */ -static void locks_delete_lock(struct file_lock **thisfl_p) +static void locks_unlink_lock(struct file_lock **thisfl_p) { struct file_lock *fl = *thisfl_p; @@ -675,6 +678,18 @@ static void locks_delete_lock(struct file_lock **thisfl_p) } locks_wake_up_blocks(fl); +} + +/* + * Unlink a lock from all lists and free it. + * + * Must be called with i_lock held! + */ +static void locks_delete_lock(struct file_lock **thisfl_p) +{ + struct file_lock *fl = *thisfl_p; + + locks_unlink_lock(thisfl_p); locks_free_lock(fl); } @@ -1471,6 +1486,32 @@ int fcntl_getlease(struct file *filp) return type; } +/** + * check_conflicting_open - see if the given dentry points to a file that has + * an existing open that would conflict with the + * desired lease. + * @dentry: dentry to check + * @arg: type of lease that we're trying to acquire + * + * Check to see if there's an existing open fd on this file that would + * conflict with the lease we're trying to set. + */ +static int +check_conflicting_open(const struct dentry *dentry, const long arg) +{ + int ret = 0; + struct inode *inode = dentry->d_inode; + + if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) + return -EAGAIN; + + if ((arg == F_WRLCK) && ((d_count(dentry) > 1) || + (atomic_read(&inode->i_count) > 1))) + ret = -EAGAIN; + + return ret; +} + static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp) { struct file_lock *fl, **before, **my_before = NULL, *lease; @@ -1498,12 +1539,8 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp return -EINVAL; } - error = -EAGAIN; - if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) - goto out; - if ((arg == F_WRLCK) - && ((d_count(dentry) > 1) - || (atomic_read(&inode->i_count) > 1))) + error = check_conflicting_open(dentry, arg); + if (error) goto out; /* @@ -1548,7 +1585,19 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp goto out; locks_insert_lock(before, lease); - error = 0; + /* + * The check in break_lease() is lockless. It's possible for another + * open to race in after we did the earlier check for a conflicting + * open but before the lease was inserted. Check again for a + * conflicting open and cancel the lease if there is one. + * + * We also add a barrier here to ensure that the insertion of the lock + * precedes these checks. + */ + smp_mb(); + error = check_conflicting_open(dentry, arg); + if (error) + locks_unlink_lock(flp); out: if (is_deleg) mutex_unlock(&inode->i_mutex); diff --git a/include/linux/fs.h b/include/linux/fs.h index 6e90887c98d8..68840a627985 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2008,6 +2008,12 @@ static inline int locks_verify_truncate(struct inode *inode, static inline int break_lease(struct inode *inode, unsigned int mode) { + /* + * Since this check is lockless, we must ensure that any refcounts + * taken are done before checking inode->i_flock. Otherwise, we could + * end up racing with tasks trying to set a new lease on this file. + */ + smp_mb(); if (inode->i_flock) return __break_lease(inode, mode, FL_LEASE); return 0; -- GitLab From 524c2b716bec8ab162348c8d19df35eb33d05bcf Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:06 -0500 Subject: [PATCH 299/528] locks: clean up comment typo Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: Ie6b4120829420f690a255adaf6b2dba64fd60124 --- fs/locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/locks.c b/fs/locks.c index 9359ee06a8b2..36862b651a95 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -581,7 +581,7 @@ static void locks_delete_block(struct file_lock *waiter) * it seems like the reasonable thing to do. * * Must be called with both the i_lock and blocked_lock_lock held. The fl_block - * list itself is protected by the file_lock_list, but by ensuring that the + * list itself is protected by the blocked_lock_lock, but by ensuring that the * i_lock is also held on insertions we can avoid taking the blocked_lock_lock * in some cases when we see that the fl_block list is empty. */ -- GitLab From 929859eb9387ef616a154bfa5d7bc5199cebf994 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:07 -0500 Subject: [PATCH 300/528] locks: remove "inline" qualifier from fl_link manipulation functions It's best to let the compiler decide that. Acked-by: J. Bruce Fields Reported-by: Stephen Rothwell Signed-off-by: Jeff Layton Change-Id: If828bfa2c307384e31a5ff74dea2183c359d429c --- fs/locks.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 36862b651a95..da9ab37af6eb 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -511,8 +511,7 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) } /* Must be called with the i_lock held! */ -static inline void -locks_insert_global_locks(struct file_lock *fl) +static void locks_insert_global_locks(struct file_lock *fl) { lg_local_lock(&file_lock_lglock); fl->fl_link_cpu = smp_processor_id(); @@ -521,8 +520,7 @@ locks_insert_global_locks(struct file_lock *fl) } /* Must be called with the i_lock held! */ -static inline void -locks_delete_global_locks(struct file_lock *fl) +static void locks_delete_global_locks(struct file_lock *fl) { /* * Avoid taking lock if already unhashed. This is safe since this check @@ -544,14 +542,12 @@ posix_owner_key(struct file_lock *fl) return (unsigned long)fl->fl_owner; } -static inline void -locks_insert_global_blocked(struct file_lock *waiter) +static void locks_insert_global_blocked(struct file_lock *waiter) { hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter)); } -static inline void -locks_delete_global_blocked(struct file_lock *waiter) +static void locks_delete_global_blocked(struct file_lock *waiter) { hash_del(&waiter->fl_link); } -- GitLab From 6c7b7bad9ccaf172a30a78ddf21911d87ed5d9fb Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:07 -0500 Subject: [PATCH 301/528] locks: add __acquires and __releases annotations to locks_start and locks_stop ...to make sparse happy. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: I8474f6d5fe10b442665ebd90db0050122a1472f9 --- fs/locks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/locks.c b/fs/locks.c index da9ab37af6eb..d2668b3cec4c 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2438,6 +2438,7 @@ static int locks_show(struct seq_file *f, void *v) } static void *locks_start(struct seq_file *f, loff_t *pos) + __acquires(&blocked_lock_lock) { struct locks_iterator *iter = f->private; @@ -2456,6 +2457,7 @@ static void *locks_next(struct seq_file *f, void *v, loff_t *pos) } static void locks_stop(struct seq_file *f, void *v) + __releases(&blocked_lock_lock) { spin_unlock(&blocked_lock_lock); lg_global_unlock(&file_lock_lglock); -- GitLab From d8292b308c09943478308b200c3d9eb646f245bf Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:07 -0500 Subject: [PATCH 302/528] locks: eliminate BUG() call when there's an unexpected lock on file close A leftover lock on the list is surely a sign of a problem of some sort, but it's not necessarily a reason to panic the box. Instead, just log a warning with some info about the lock, and then delete it like we would any other lock. In the event that the filesystem declares a ->lock f_op, we may end up leaking something, but that's generally preferable to an immediate panic. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: I3c799e4d2264d6782a8ab607fade3c5e1df3c500 --- fs/locks.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index d2668b3cec4c..1596e0d3c51e 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2289,16 +2289,28 @@ void locks_remove_flock(struct file *filp) while ((fl = *before) != NULL) { if (fl->fl_file == filp) { - if (IS_FLOCK(fl)) { - locks_delete_lock(before); - continue; - } if (IS_LEASE(fl)) { lease_modify(before, F_UNLCK); continue; } - /* What? */ - BUG(); + + /* + * There's a leftover lock on the list of a type that + * we didn't expect to see. Most likely a classic + * POSIX lock that ended up not getting released + * properly, or that raced onto the list somehow. Log + * some info about it and then just remove it from + * the list. + */ + WARN(!IS_FLOCK(fl), + "leftover lock: dev=%u:%u ino=%lu type=%hhd flags=0x%x start=%lld end=%lld\n", + MAJOR(inode->i_sb->s_dev), + MINOR(inode->i_sb->s_dev), inode->i_ino, + fl->fl_type, fl->fl_flags, + fl->fl_start, fl->fl_end); + + locks_delete_lock(before); + continue; } before = &fl->fl_next; } -- GitLab From 00fcb4917018f1771237e27d6215022057458756 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 3 Feb 2014 12:13:08 -0500 Subject: [PATCH 303/528] locks: fix posix lock range overflow handling In the 32-bit case fcntl assigns the 64-bit f_pos and i_size to a 32-bit off_t. The existing range checks also seem to depend on signed arithmetic wrapping when it overflows. In practice maybe that works, but we can be more careful. That also allows us to make a more reliable distinction between -EINVAL and -EOVERFLOW. Note that in the 32-bit case SEEK_CUR or SEEK_END might allow the caller to set a lock with starting point no longer representable as a 32-bit value. We could return -EOVERFLOW in such cases, but the locks code is capable of handling such ranges, so we choose to be lenient here. The only problem is that subsequent GETLK calls on such a lock will fail with EOVERFLOW. While we're here, do some cleanup including consolidating code for the flock and flock64 cases. Signed-off-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: I83334b65f3b8dd729ba57e3df66923bd50b635a2 --- fs/locks.c | 100 ++++++++++--------------------- include/uapi/asm-generic/fcntl.h | 3 - 2 files changed, 32 insertions(+), 71 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 1596e0d3c51e..2f0698c6ac04 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -344,48 +344,43 @@ static int assign_type(struct file_lock *fl, long type) return 0; } -/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX - * style lock. - */ -static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, - struct flock *l) +static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, + struct flock64 *l) { - off_t start, end; - switch (l->l_whence) { case SEEK_SET: - start = 0; + fl->fl_start = 0; break; case SEEK_CUR: - start = filp->f_pos; + fl->fl_start = filp->f_pos; break; case SEEK_END: - start = i_size_read(file_inode(filp)); + fl->fl_start = i_size_read(file_inode(filp)); break; default: return -EINVAL; } + if (l->l_start > OFFSET_MAX - fl->fl_start) + return -EOVERFLOW; + fl->fl_start += l->l_start; + if (fl->fl_start < 0) + return -EINVAL; /* POSIX-1996 leaves the case l->l_len < 0 undefined; POSIX-2001 defines it. */ - start += l->l_start; - if (start < 0) - return -EINVAL; - fl->fl_end = OFFSET_MAX; if (l->l_len > 0) { - end = start + l->l_len - 1; - fl->fl_end = end; + if (l->l_len - 1 > OFFSET_MAX - fl->fl_start) + return -EOVERFLOW; + fl->fl_end = fl->fl_start + l->l_len - 1; + } else if (l->l_len < 0) { - end = start - 1; - fl->fl_end = end; - start += l->l_len; - if (start < 0) + if (fl->fl_start + l->l_len < 0) return -EINVAL; - } - fl->fl_start = start; /* we record the absolute position */ - if (fl->fl_end < fl->fl_start) - return -EOVERFLOW; - + fl->fl_end = fl->fl_start - 1; + fl->fl_start += l->l_len; + } else + fl->fl_end = OFFSET_MAX; + fl->fl_owner = current->files; fl->fl_pid = current->tgid; fl->fl_file = filp; @@ -396,52 +391,21 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, return assign_type(fl, l->l_type); } -#if BITS_PER_LONG == 32 -static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, - struct flock64 *l) +/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX + * style lock. + */ +static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, + struct flock *l) { - loff_t start; - - switch (l->l_whence) { - case SEEK_SET: - start = 0; - break; - case SEEK_CUR: - start = filp->f_pos; - break; - case SEEK_END: - start = i_size_read(file_inode(filp)); - break; - default: - return -EINVAL; - } + struct flock64 ll = { + .l_type = l->l_type, + .l_whence = l->l_whence, + .l_start = l->l_start, + .l_len = l->l_len, + }; - start += l->l_start; - if (start < 0) - return -EINVAL; - fl->fl_end = OFFSET_MAX; - if (l->l_len > 0) { - fl->fl_end = start + l->l_len - 1; - } else if (l->l_len < 0) { - fl->fl_end = start - 1; - start += l->l_len; - if (start < 0) - return -EINVAL; - } - fl->fl_start = start; /* we record the absolute position */ - if (fl->fl_end < fl->fl_start) - return -EOVERFLOW; - - fl->fl_owner = current->files; - fl->fl_pid = current->tgid; - fl->fl_file = filp; - fl->fl_flags = FL_POSIX; - fl->fl_ops = NULL; - fl->fl_lmops = NULL; - - return assign_type(fl, l->l_type); + return flock64_to_posix_lock(filp, fl, &ll); } -#endif /* default lease lock manager operations */ static void lease_break_callback(struct file_lock *fl) diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 95e46c8e05f9..36025f77c6ed 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -186,8 +186,6 @@ struct flock { }; #endif -#ifndef CONFIG_64BIT - #ifndef HAVE_ARCH_STRUCT_FLOCK64 #ifndef __ARCH_FLOCK64_PAD #define __ARCH_FLOCK64_PAD @@ -202,6 +200,5 @@ struct flock64 { __ARCH_FLOCK64_PAD }; #endif -#endif /* !CONFIG_64BIT */ #endif /* _ASM_GENERIC_FCNTL_H */ -- GitLab From 187edabf7a756010ea2d57657e86d8800ea120fb Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:08 -0500 Subject: [PATCH 304/528] locks: consolidate checks for compatible filp->f_mode values in setlk handlers Move this check into flock64_to_posix_lock instead of duplicating it in two places. This also fixes a minor wart in the code where we continue referring to the struct flock after converting it to struct file_lock. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: I267b809edfdca780181dadb7e80cfc1ba9dbfbfa --- fs/locks.c | 46 ++++++++++++---------------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 2f0698c6ac04..fc131f68a153 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -388,6 +388,18 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, fl->fl_ops = NULL; fl->fl_lmops = NULL; + /* Ensure that fl->fl_filp has compatible f_mode */ + switch (l->l_type) { + case F_RDLCK: + if (!(filp->f_mode & FMODE_READ)) + return -EBADF; + break; + case F_WRLCK: + if (!(filp->f_mode & FMODE_WRITE)) + return -EBADF; + break; + } + return assign_type(fl, l->l_type); } @@ -2023,23 +2035,6 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, file_lock->fl_flags |= FL_SLEEP; } - error = -EBADF; - switch (flock.l_type) { - case F_RDLCK: - if (!(filp->f_mode & FMODE_READ)) - goto out; - break; - case F_WRLCK: - if (!(filp->f_mode & FMODE_WRITE)) - goto out; - break; - case F_UNLCK: - break; - default: - error = -EINVAL; - goto out; - } - error = do_lock_file_wait(filp, cmd, file_lock); /* @@ -2143,23 +2138,6 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, file_lock->fl_flags |= FL_SLEEP; } - error = -EBADF; - switch (flock.l_type) { - case F_RDLCK: - if (!(filp->f_mode & FMODE_READ)) - goto out; - break; - case F_WRLCK: - if (!(filp->f_mode & FMODE_WRITE)) - goto out; - break; - case F_UNLCK: - break; - default: - error = -EINVAL; - goto out; - } - error = do_lock_file_wait(filp, cmd, file_lock); /* -- GitLab From 7d45dba6299341485d2263e9a193ad4731216655 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:08 -0500 Subject: [PATCH 305/528] locks: rename locks_remove_flock to locks_remove_file This function currently removes leases in addition to flock locks and in a later patch we'll have it deal with file-private locks too. Rename it to locks_remove_file to indicate that it removes locks that are associated with a particular struct file, and not just flock locks. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: I3e99530c18fbf08f10e63c4905f33bb8228a6f3a --- fs/file_table.c | 2 +- fs/locks.c | 2 +- include/linux/fs.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/file_table.c b/fs/file_table.c index 28f02a7cbba1..ff3177707493 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -234,7 +234,7 @@ static void __fput(struct file *file) * in the file cleanup chain. */ eventpoll_release(file); - locks_remove_flock(file); + locks_remove_file(file); if (unlikely(file->f_flags & FASYNC)) { if (file->f_op && file->f_op->fasync) diff --git a/fs/locks.c b/fs/locks.c index fc131f68a153..cd1ebc894fcb 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2204,7 +2204,7 @@ EXPORT_SYMBOL(locks_remove_posix); /* * This function is called on the last close of an open file. */ -void locks_remove_flock(struct file *filp) +void locks_remove_file(struct file *filp) { struct inode * inode = file_inode(filp); struct file_lock *fl; diff --git a/include/linux/fs.h b/include/linux/fs.h index 68840a627985..e11ab1d30ed5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1041,7 +1041,7 @@ extern struct file_lock * locks_alloc_lock(void); extern void locks_copy_lock(struct file_lock *, struct file_lock *); extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); extern void locks_remove_posix(struct file *, fl_owner_t); -extern void locks_remove_flock(struct file *); +extern void locks_remove_file(struct file *); extern void locks_release_private(struct file_lock *); extern void posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); @@ -1112,7 +1112,7 @@ static inline void locks_remove_posix(struct file *filp, fl_owner_t owner) return; } -static inline void locks_remove_flock(struct file *filp) +static inline void locks_remove_file(struct file *filp) { return; } -- GitLab From e669264b9eec636339e8497a016c8d6ce1b1d143 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:09 -0500 Subject: [PATCH 306/528] locks: make /proc/locks show IS_FILE_PVT locks as type "FLPVT" In a later patch, we'll be adding a new type of lock that's owned by the struct file instead of the files_struct. Those sorts of locks will be flagged with a new FL_FILE_PVT flag. Report these types of locks as "FLPVT" in /proc/locks to distinguish them from "classic" POSIX locks. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: I9d85baaea7e4d4e74f0ee5ee3425a0f5f4a148e2 --- fs/locks.c | 11 +++++++++-- include/linux/fs.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index cd1ebc894fcb..a1551d70d56d 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -135,6 +135,7 @@ #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) #define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG)) +#define IS_FILE_PVT(fl) (fl->fl_flags & FL_FILE_PVT) static bool lease_breaking(struct file_lock *fl) { @@ -2321,8 +2322,14 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, seq_printf(f, "%lld:%s ", id, pfx); if (IS_POSIX(fl)) { - seq_printf(f, "%6s %s ", - (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", + if (fl->fl_flags & FL_ACCESS) + seq_printf(f, "ACCESS"); + else if (IS_FILE_PVT(fl)) + seq_printf(f, "FLPVT "); + else + seq_printf(f, "POSIX "); + + seq_printf(f, " %s ", (inode == NULL) ? "*NOINODE*" : mandatory_lock(inode) ? "MANDATORY" : "ADVISORY "); } else if (IS_FLOCK(fl)) { diff --git a/include/linux/fs.h b/include/linux/fs.h index e11ab1d30ed5..a4036a02f4a1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -917,6 +917,7 @@ static inline int file_check_writeable(struct file *filp) #define FL_SLEEP 128 /* A blocking lock */ #define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ #define FL_UNLOCK_PENDING 512 /* Lease is being broken */ +#define FL_FILE_PVT 1024 /* lock is private to the file */ /* * Special return value from posix_lock_file() and vfs_lock_file() for -- GitLab From 53630de0e5de80762751b840b1d6cf577a1e10b7 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:09 -0500 Subject: [PATCH 307/528] locks: report l_pid as -1 for FL_FILE_PVT locks FL_FILE_PVT locks are no longer tied to a particular pid, and are instead inheritable by child processes. Report a l_pid of '-1' for these sorts of locks since the pid is somewhat meaningless for them. This precedent comes from FreeBSD. There, POSIX and flock() locks can conflict with one another. If fcntl(F_GETLK, ...) returns a lock set with flock() then the l_pid member cannot be a process ID because the lock is not held by a process as such. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: If004b0bd212b994ab7c94c020f9926f22faddf55 --- fs/locks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index a1551d70d56d..d967c2591bc0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1863,7 +1863,7 @@ EXPORT_SYMBOL_GPL(vfs_test_lock); static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) { - flock->l_pid = fl->fl_pid; + flock->l_pid = IS_FILE_PVT(fl) ? -1 : fl->fl_pid; #if BITS_PER_LONG == 32 /* * Make sure we can represent the posix lock via @@ -1885,7 +1885,7 @@ static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) #if BITS_PER_LONG == 32 static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) { - flock->l_pid = fl->fl_pid; + flock->l_pid = IS_FILE_PVT(fl) ? -1 : fl->fl_pid; flock->l_start = fl->fl_start; flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : fl->fl_end - fl->fl_start + 1; -- GitLab From 23805c252b2c5a31512354eb4d590ec5ab4bd7a1 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:09 -0500 Subject: [PATCH 308/528] locks: pass the cmd value to fcntl_getlk/getlk64 Once we introduce file private locks, we'll need to know what cmd value was used, as that affects the ownership and whether a conflict would arise. Signed-off-by: Jeff Layton Change-Id: I63f17caea3822daace0cc6cac05e293c36bcff40 --- fs/fcntl.c | 4 ++-- fs/locks.c | 4 ++-- include/linux/fs.h | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/fs/fcntl.c b/fs/fcntl.c index 0ec0ab37e8c3..d67ee2c7de68 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -275,7 +275,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, err = setfl(fd, filp, arg); break; case F_GETLK: - err = fcntl_getlk(filp, (struct flock __user *) arg); + err = fcntl_getlk(filp, cmd, (struct flock __user *) arg); break; case F_SETLK: case F_SETLKW: @@ -395,7 +395,7 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, switch (cmd) { case F_GETLK64: - err = fcntl_getlk64(f.file, (struct flock64 __user *) arg); + err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); break; case F_SETLK64: case F_SETLKW64: diff --git a/fs/locks.c b/fs/locks.c index d967c2591bc0..2e338bd8dacf 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1897,7 +1897,7 @@ static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) /* Report the first existing lock that would conflict with l. * This implements the F_GETLK command of fcntl(). */ -int fcntl_getlk(struct file *filp, struct flock __user *l) +int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) { struct file_lock file_lock; struct flock flock; @@ -2067,7 +2067,7 @@ out: /* Report the first existing lock that would conflict with l. * This implements the F_GETLK command of fcntl(). */ -int fcntl_getlk64(struct file *filp, struct flock64 __user *l) +int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) { struct file_lock file_lock; struct flock64 flock; diff --git a/include/linux/fs.h b/include/linux/fs.h index a4036a02f4a1..69b928e43052 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1022,12 +1022,12 @@ struct file_lock { extern void send_sigio(struct fown_struct *fown, int fd, int band); #ifdef CONFIG_FILE_LOCKING -extern int fcntl_getlk(struct file *, struct flock __user *); +extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *); extern int fcntl_setlk(unsigned int, struct file *, unsigned int, struct flock __user *); #if BITS_PER_LONG == 32 -extern int fcntl_getlk64(struct file *, struct flock64 __user *); +extern int fcntl_getlk64(struct file *, unsigned int, struct flock64 __user *); extern int fcntl_setlk64(unsigned int, struct file *, unsigned int, struct flock64 __user *); #endif @@ -1060,7 +1060,8 @@ extern int lease_modify(struct file_lock **, int); extern int lock_may_read(struct inode *, loff_t start, unsigned long count); extern int lock_may_write(struct inode *, loff_t start, unsigned long count); #else /* !CONFIG_FILE_LOCKING */ -static inline int fcntl_getlk(struct file *file, struct flock __user *user) +static inline int fcntl_getlk(struct file *file, unsigned int cmd, + struct flock __user *user) { return -EINVAL; } @@ -1072,7 +1073,8 @@ static inline int fcntl_setlk(unsigned int fd, struct file *file, } #if BITS_PER_LONG == 32 -static inline int fcntl_getlk64(struct file *file, struct flock64 __user *user) +static inline int fcntl_getlk64(struct file *file, unsigned int cmd, + struct flock64 __user *user) { return -EINVAL; } -- GitLab From a911caf84abe561bda1dc3e676aac70c165e9782 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:09 -0500 Subject: [PATCH 309/528] locks: skip deadlock detection on FL_FILE_PVT locks It's not really feasible to do deadlock detection with FL_FILE_PVT locks since they aren't owned by a single task, per-se. Deadlock detection also tends to be rather expensive so just skip it for these sorts of locks. Also, add a FIXME comment about adding more limited deadlock detection that just applies to ro -> rw upgrades, per Andy's request. Cc: Andy Lutomirski Signed-off-by: Jeff Layton Change-Id: Icae7808d183ed316c74782c4e802a54e83af26df --- fs/locks.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 2e338bd8dacf..c545b49e0be2 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -564,7 +564,7 @@ static void __locks_insert_block(struct file_lock *blocker, BUG_ON(!list_empty(&waiter->fl_block)); waiter->fl_next = blocker; list_add_tail(&waiter->fl_block, &blocker->fl_block); - if (IS_POSIX(blocker)) + if (IS_POSIX(blocker) && !IS_FILE_PVT(blocker)) locks_insert_global_blocked(waiter); } @@ -757,8 +757,16 @@ EXPORT_SYMBOL(posix_test_lock); * Note: the above assumption may not be true when handling lock * requests from a broken NFS client. It may also fail in the presence * of tasks (such as posix threads) sharing the same open file table. - * * To handle those cases, we just bail out after a few iterations. + * + * For FL_FILE_PVT locks, the owner is the filp, not the files_struct. + * Because the owner is not even nominally tied to a thread of + * execution, the deadlock detection below can't reasonably work well. Just + * skip it for those. + * + * In principle, we could do a more limited deadlock detection on FL_FILE_PVT + * locks that just checks for the case where two tasks are attempting to + * upgrade from read to write locks on the same inode. */ #define MAX_DEADLK_ITERATIONS 10 @@ -781,6 +789,13 @@ static int posix_locks_deadlock(struct file_lock *caller_fl, { int i = 0; + /* + * This deadlock detector can't reasonably detect deadlocks with + * FL_FILE_PVT locks, since they aren't owned by a process, per-se. + */ + if (IS_FILE_PVT(caller_fl)) + return 0; + while ((block_fl = what_owner_is_waiting_for(block_fl))) { if (i++ > MAX_DEADLK_ITERATIONS) return 0; -- GitLab From 6c1a7bb607b2b0fac0f3beaa91c6b91db6489519 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 3 Feb 2014 12:13:10 -0500 Subject: [PATCH 310/528] locks: add new fcntl cmd values for handling file private locks Due to some unfortunate history, POSIX locks have very strange and unhelpful semantics. The thing that usually catches people by surprise is that they are dropped whenever the process closes any file descriptor associated with the inode. This is extremely problematic for people developing file servers that need to implement byte-range locks. Developers often need a "lock management" facility to ensure that file descriptors are not closed until all of the locks associated with the inode are finished. Additionally, "classic" POSIX locks are owned by the process. Locks taken between threads within the same process won't conflict with one another, which renders them useless for synchronization between threads. This patchset adds a new type of lock that attempts to address these issues. These locks conflict with classic POSIX read/write locks, but have semantics that are more like BSD locks with respect to inheritance and behavior on close. This is implemented primarily by changing how fl_owner field is set for these locks. Instead of having them owned by the files_struct of the process, they are instead owned by the filp on which they were acquired. Thus, they are inherited across fork() and are only released when the last reference to a filp is put. These new semantics prevent them from being merged with classic POSIX locks, even if they are acquired by the same process. These locks will also conflict with classic POSIX locks even if they are acquired by the same process or on the same file descriptor. The new locks are managed using a new set of cmd values to the fcntl() syscall. The initial implementation of this converts these values to "classic" cmd values at a fairly high level, and the details are not exposed to the underlying filesystem. We may eventually want to push this handing out to the lower filesystem code but for now I don't see any need for it. Also, note that with this implementation the new cmd values are only available via fcntl64() on 32-bit arches. There's little need to add support for legacy apps on a new interface like this. Signed-off-by: Jeff Layton Change-Id: Ifc97227425ebbb8b6bb2f43dd971bd3b0d5f8c06 --- arch/arm/kernel/sys_oabi-compat.c | 3 ++ fs/compat.c | 35 +++++++++++++++++--- fs/fcntl.c | 35 +++++++++++++------- fs/locks.c | 54 ++++++++++++++++++++++++++++--- include/uapi/asm-generic/fcntl.h | 16 +++++++++ security/selinux/hooks.c | 3 ++ 6 files changed, 126 insertions(+), 20 deletions(-) diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 87c010557b1d..7a41528bdb09 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -232,6 +232,9 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) { switch (cmd) { + case F_GETLKP: + case F_SETLKP: + case F_SETLKPW: case F_GETLK64: case F_SETLK64: case F_SETLKW64: diff --git a/fs/compat.c b/fs/compat.c index 0095a6978eef..e3a4e8a7cdfe 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -399,12 +399,28 @@ static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *u } #endif +static unsigned int +convert_fcntl_cmd(unsigned int cmd) +{ + switch (cmd) { + case F_GETLK64: + return F_GETLK; + case F_SETLK64: + return F_SETLK; + case F_SETLKW64: + return F_SETLKW; + } + + return cmd; +} + asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs; struct flock f; long ret; + unsigned int conv_cmd; switch (cmd) { case F_GETLK: @@ -441,16 +457,18 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, case F_GETLK64: case F_SETLK64: case F_SETLKW64: + case F_GETLKP: + case F_SETLKP: + case F_SETLKPW: ret = get_compat_flock64(&f, compat_ptr(arg)); if (ret != 0) break; old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK : - ((cmd == F_SETLK64) ? F_SETLK : F_SETLKW), - (unsigned long)&f); + conv_cmd = convert_fcntl_cmd(cmd); + ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f); set_fs(old_fs); - if (cmd == F_GETLK64 && ret == 0) { + if ((conv_cmd == F_GETLK || conv_cmd == F_GETLKP) && ret == 0) { /* need to return lock information - see above for commentary */ if (f.l_start > COMPAT_LOFF_T_MAX) ret = -EOVERFLOW; @@ -471,8 +489,15 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) { - if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64)) + switch (cmd) { + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + case F_GETLKP: + case F_SETLKP: + case F_SETLKPW: return -EINVAL; + } return compat_sys_fcntl64(fd, cmd, arg); } diff --git a/fs/fcntl.c b/fs/fcntl.c index d67ee2c7de68..3476c43e12dc 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -274,9 +274,19 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, case F_SETFL: err = setfl(fd, filp, arg); break; +#if BITS_PER_LONG != 32 + /* 32-bit arches must use fcntl64() */ + case F_GETLKP: +#endif case F_GETLK: err = fcntl_getlk(filp, cmd, (struct flock __user *) arg); break; +#if BITS_PER_LONG != 32 + /* 32-bit arches must use fcntl64() */ + case F_SETLKP: + case F_SETLKPW: +#endif + /* Fallthrough */ case F_SETLK: case F_SETLKW: err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg); @@ -394,17 +404,20 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, goto out1; switch (cmd) { - case F_GETLK64: - err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); - break; - case F_SETLK64: - case F_SETLKW64: - err = fcntl_setlk64(fd, f.file, cmd, - (struct flock64 __user *) arg); - break; - default: - err = do_fcntl(fd, cmd, arg, f.file); - break; + case F_GETLK64: + case F_GETLKP: + err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); + break; + case F_SETLK64: + case F_SETLKW64: + case F_SETLKP: + case F_SETLKPW: + err = fcntl_setlk64(fd, f.file, cmd, + (struct flock64 __user *) arg); + break; + default: + err = do_fcntl(fd, cmd, arg, f.file); + break; } out1: fdput(f); diff --git a/fs/locks.c b/fs/locks.c index c545b49e0be2..849301c002c3 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1929,6 +1929,12 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) if (error) goto out; + if (cmd == F_GETLKP) { + cmd = F_GETLK; + file_lock.fl_flags |= FL_FILE_PVT; + file_lock.fl_owner = (fl_owner_t)filp; + } + error = vfs_test_lock(filp, &file_lock); if (error) goto out; @@ -2047,10 +2053,26 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, error = flock_to_posix_lock(filp, file_lock, &flock); if (error) goto out; - if (cmd == F_SETLKW) { + + /* + * If the cmd is requesting file-private locks, then set the + * FL_FILE_PVT flag and override the owner. + */ + switch (cmd) { + case F_SETLKP: + cmd = F_SETLK; + file_lock->fl_flags |= FL_FILE_PVT; + file_lock->fl_owner = (fl_owner_t)filp; + break; + case F_SETLKPW: + cmd = F_SETLKW; + file_lock->fl_flags |= FL_FILE_PVT; + file_lock->fl_owner = (fl_owner_t)filp; + /* Fallthrough */ + case F_SETLKW: file_lock->fl_flags |= FL_SLEEP; } - + error = do_lock_file_wait(filp, cmd, file_lock); /* @@ -2099,6 +2121,12 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) if (error) goto out; + if (cmd == F_GETLKP) { + cmd = F_GETLK64; + file_lock.fl_flags |= FL_FILE_PVT; + file_lock.fl_owner = (fl_owner_t)filp; + } + error = vfs_test_lock(filp, &file_lock); if (error) goto out; @@ -2150,10 +2178,26 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, error = flock64_to_posix_lock(filp, file_lock, &flock); if (error) goto out; - if (cmd == F_SETLKW64) { + + /* + * If the cmd is requesting file-private locks, then set the + * FL_FILE_PVT flag and override the owner. + */ + switch (cmd) { + case F_SETLKP: + cmd = F_SETLK64; + file_lock->fl_flags |= FL_FILE_PVT; + file_lock->fl_owner = (fl_owner_t)filp; + break; + case F_SETLKPW: + cmd = F_SETLKW64; + file_lock->fl_flags |= FL_FILE_PVT; + file_lock->fl_owner = (fl_owner_t)filp; + /* Fallthrough */ + case F_SETLKW64: file_lock->fl_flags |= FL_SLEEP; } - + error = do_lock_file_wait(filp, cmd, file_lock); /* @@ -2229,6 +2273,8 @@ void locks_remove_file(struct file *filp) if (!inode->i_flock) return; + locks_remove_posix(filp, (fl_owner_t)filp); + if (filp->f_op && filp->f_op->flock) { struct file_lock fl = { .fl_pid = current->tgid, diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 36025f77c6ed..a9b13f8b3595 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -132,6 +132,22 @@ #define F_GETOWNER_UIDS 17 #endif +/* + * fd "private" POSIX locks. + * + * Usually POSIX locks held by a process are released on *any* close and are + * not inherited across a fork(). + * + * These cmd values will set locks that conflict with normal POSIX locks, but + * are "owned" by the opened file, not the process. This means that they are + * inherited across fork() like BSD (flock) locks, and they are only released + * automatically when the last reference to the the open file against which + * they were acquired is put. + */ +#define F_GETLKP 36 +#define F_SETLKP 37 +#define F_SETLKPW 38 + #define F_OWNER_TID 0 #define F_OWNER_PID 1 #define F_OWNER_PGRP 2 diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 626533313cf5..a38a0071fb33 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3333,6 +3333,9 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd, case F_GETLK: case F_SETLK: case F_SETLKW: + case F_GETLKP: + case F_SETLKP: + case F_SETLKPW: #if BITS_PER_LONG == 32 case F_GETLK64: case F_SETLK64: -- GitLab From 7801c4aca3d3cd6956765459be6cc2c963679733 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 4 Mar 2014 10:30:23 -0500 Subject: [PATCH 311/528] locks: require that flock->l_pid be set to 0 for file-private locks Neil Brown suggested potentially overloading the l_pid value as a "lock context" field for file-private locks. While I don't think we will probably want to do that here, it's probably a good idea to ensure that in the future we could extend this API without breaking existing callers. Typically the l_pid value is ignored for incoming struct flock arguments, serving mainly as a place to return the pid of the owner if there is a conflicting lock. For file-private locks, require that it currently be set to 0 and return EINVAL if it isn't. If we eventually want to make a non-zero l_pid mean something, then this will help ensure that we don't break legacy programs that are using file-private locks. Cc: Neil Brown Signed-off-by: Jeff Layton Change-Id: I87427935622187350ab54252d125315a6640e4d3 --- fs/locks.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/fs/locks.c b/fs/locks.c index 849301c002c3..650439ddeb58 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1930,6 +1930,10 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) goto out; if (cmd == F_GETLKP) { + error = -EINVAL; + if (flock.l_pid != 0) + goto out; + cmd = F_GETLK; file_lock.fl_flags |= FL_FILE_PVT; file_lock.fl_owner = (fl_owner_t)filp; @@ -2060,11 +2064,19 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, */ switch (cmd) { case F_SETLKP: + error = -EINVAL; + if (flock.l_pid != 0) + goto out; + cmd = F_SETLK; file_lock->fl_flags |= FL_FILE_PVT; file_lock->fl_owner = (fl_owner_t)filp; break; case F_SETLKPW: + error = -EINVAL; + if (flock.l_pid != 0) + goto out; + cmd = F_SETLKW; file_lock->fl_flags |= FL_FILE_PVT; file_lock->fl_owner = (fl_owner_t)filp; @@ -2122,6 +2134,10 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) goto out; if (cmd == F_GETLKP) { + error = -EINVAL; + if (flock.l_pid != 0) + goto out; + cmd = F_GETLK64; file_lock.fl_flags |= FL_FILE_PVT; file_lock.fl_owner = (fl_owner_t)filp; @@ -2185,11 +2201,19 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, */ switch (cmd) { case F_SETLKP: + error = -EINVAL; + if (flock.l_pid != 0) + goto out; + cmd = F_SETLK64; file_lock->fl_flags |= FL_FILE_PVT; file_lock->fl_owner = (fl_owner_t)filp; break; case F_SETLKPW: + error = -EINVAL; + if (flock.l_pid != 0) + goto out; + cmd = F_SETLKW64; file_lock->fl_flags |= FL_FILE_PVT; file_lock->fl_owner = (fl_owner_t)filp; -- GitLab From 913abfb82e69da6f071f0da0a70c82afb332866e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 10 Mar 2014 09:54:15 -0400 Subject: [PATCH 312/528] locks: fix locks_mandatory_locked to respect file-private locks As Trond pointed out, you can currently deadlock yourself by setting a file-private lock on a file that requires mandatory locking and then trying to do I/O on it. Avoid this problem by plumbing some knowledge of file-private locks into the mandatory locking code. In order to do this, we must pass down information about the struct file that's being used to locks_verify_locked. Reported-by: Trond Myklebust Signed-off-by: Jeff Layton Acked-by: J. Bruce Fields Change-Id: I28740de27845738142d5f12fd0fd551d61d355bf --- fs/locks.c | 7 ++++--- fs/namei.c | 2 +- include/linux/fs.h | 22 +++++++++++----------- mm/mmap.c | 2 +- mm/nommu.c | 2 +- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 650439ddeb58..4f7a0f282ec8 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1155,13 +1155,14 @@ EXPORT_SYMBOL(posix_lock_file_wait); /** * locks_mandatory_locked - Check for an active lock - * @inode: the file to check + * @file: the file to check * * Searches the inode's list of locks to find any POSIX locks which conflict. * This function is called from locks_verify_locked() only. */ -int locks_mandatory_locked(struct inode *inode) +int locks_mandatory_locked(struct file *file) { + struct inode *inode = file_inode(file); fl_owner_t owner = current->files; struct file_lock *fl; @@ -1172,7 +1173,7 @@ int locks_mandatory_locked(struct inode *inode) for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!IS_POSIX(fl)) continue; - if (fl->fl_owner != owner) + if (fl->fl_owner != owner && fl->fl_owner != (fl_owner_t)file) break; } spin_unlock(&inode->i_lock); diff --git a/fs/namei.c b/fs/namei.c index 58dd938bb5a9..e2af0479102a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2491,7 +2491,7 @@ static int handle_truncate(struct file *filp) /* * Refuse to truncate files with mandatory locks held on them. */ - error = locks_verify_locked(inode); + error = locks_verify_locked(filp); if (!error) error = security_path_truncate(path); if (!error) { diff --git a/include/linux/fs.h b/include/linux/fs.h index 69b928e43052..6dff9f4097bd 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1955,6 +1955,11 @@ extern bool our_mnt(struct vfsmount *mnt); extern int current_umask(void); +static inline struct inode *file_inode(struct file *f) +{ + return f->f_inode; +} + /* /sys/fs */ extern struct kobject *fs_kobj; @@ -1965,7 +1970,7 @@ extern int rw_verify_area(int, struct file *, loff_t *, size_t); #define FLOCK_VERIFY_WRITE 2 #ifdef CONFIG_FILE_LOCKING -extern int locks_mandatory_locked(struct inode *); +extern int locks_mandatory_locked(struct file *); extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t); /* @@ -1988,10 +1993,10 @@ static inline int mandatory_lock(struct inode *ino) return IS_MANDLOCK(ino) && __mandatory_lock(ino); } -static inline int locks_verify_locked(struct inode *inode) +static inline int locks_verify_locked(struct file *file) { - if (mandatory_lock(inode)) - return locks_mandatory_locked(inode); + if (mandatory_lock(file_inode(file))) + return locks_mandatory_locked(file); return 0; } @@ -2030,7 +2035,7 @@ static inline int break_deleg(struct inode *inode, unsigned int mode) } #else /* !CONFIG_FILE_LOCKING */ -static inline int locks_mandatory_locked(struct inode *inode) +static inline int locks_mandatory_locked(struct file *file) { return 0; } @@ -2052,7 +2057,7 @@ static inline int mandatory_lock(struct inode *inode) return 0; } -static inline int locks_verify_locked(struct inode *inode) +static inline int locks_verify_locked(struct file *file) { return 0; } @@ -2312,11 +2317,6 @@ static inline bool execute_ok(struct inode *inode) return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode); } -static inline struct inode *file_inode(struct file *f) -{ - return f->f_inode; -} - static inline void file_start_write(struct file *file) { if (!S_ISREG(file_inode(file)->i_mode)) diff --git a/mm/mmap.c b/mm/mmap.c index 48cd61da289e..210ecd39da93 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1318,7 +1318,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, /* * Make sure there are no mandatory locks on the file. */ - if (locks_verify_locked(inode)) + if (locks_verify_locked(file)) return -EAGAIN; vm_flags |= VM_SHARED | VM_MAYSHARE; diff --git a/mm/nommu.c b/mm/nommu.c index 75a3a2479d21..4d2d945829a7 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -993,7 +993,7 @@ static int validate_mmap_request(struct file *file, (file->f_mode & FMODE_WRITE)) return -EACCES; - if (locks_verify_locked(file_inode(file))) + if (locks_verify_locked(file)) return -EAGAIN; if (!(capabilities & BDI_CAP_MAP_DIRECT)) -- GitLab From 0d714928287c1c5d50e1d85f8ed0debf4d08a289 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 10 Mar 2014 09:54:19 -0400 Subject: [PATCH 313/528] locks: make locks_mandatory_area check for file-private locks Allow locks_mandatory_area() to handle file-private locks correctly. If there is a file-private lock set on an open file and we're doing I/O via the same, then that should not cause anything to block. Handle this by first doing a non-blocking FL_ACCESS check for a file-private lock, and then fall back to checking for a classic POSIX lock (and possibly blocking). Note that this approach is subject to the same races that have always plagued mandatory locking on Linux. Reported-by: Trond Myklebust Signed-off-by: Jeff Layton Change-Id: Ic7d6e3dded38e7b419fcae3785d4b6c0584f83f3 --- fs/locks.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 4f7a0f282ec8..ad207427daeb 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1199,19 +1199,30 @@ int locks_mandatory_area(int read_write, struct inode *inode, { struct file_lock fl; int error; + bool sleep = false; locks_init_lock(&fl); - fl.fl_owner = current->files; fl.fl_pid = current->tgid; fl.fl_file = filp; fl.fl_flags = FL_POSIX | FL_ACCESS; if (filp && !(filp->f_flags & O_NONBLOCK)) - fl.fl_flags |= FL_SLEEP; + sleep = true; fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK; fl.fl_start = offset; fl.fl_end = offset + count - 1; for (;;) { + if (filp) { + fl.fl_owner = (fl_owner_t)filp; + fl.fl_flags &= ~FL_SLEEP; + error = __posix_lock_file(inode, &fl, NULL); + if (!error) + break; + } + + if (sleep) + fl.fl_flags |= FL_SLEEP; + fl.fl_owner = current->files; error = __posix_lock_file(inode, &fl, NULL); if (error != FILE_LOCK_DEFERRED) break; -- GitLab From 350f330c2a4099f71ccbd2b52ca9fdb12a941cbe Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 22 Apr 2014 08:23:58 -0400 Subject: [PATCH 314/528] locks: rename file-private locks to "open file description locks" File-private locks have been merged into Linux for v3.15, and *now* people are commenting that the name and macro definitions for the new file-private locks suck. ...and I can't even disagree. The names and command macros do suck. We're going to have to live with these for a long time, so it's important that we be happy with the names before we're stuck with them. The consensus on the lists so far is that they should be rechristened as "open file description locks". The name isn't a big deal for the kernel, but the command macros are not visually distinct enough from the traditional POSIX lock macros. The glibc and documentation folks are recommending that we change them to look like F_OFD_{GETLK|SETLK|SETLKW}. That lessens the chance that a programmer will typo one of the commands wrong, and also makes it easier to spot this difference when reading code. This patch makes the following changes that I think are necessary before v3.15 ships: 1) rename the command macros to their new names. These end up in the uapi headers and so are part of the external-facing API. It turns out that glibc doesn't actually use the fcntl.h uapi header, but it's hard to be sure that something else won't. Changing it now is safest. 2) make the the /proc/locks output display these as type "OFDLCK" Cc: Michael Kerrisk Cc: Christoph Hellwig Cc: Carlos O'Donell Cc: Stefan Metzmacher Cc: Andy Lutomirski Cc: Frank Filz Cc: Theodore Ts'o Signed-off-by: Jeff Layton Change-Id: I2d7636d228f67e5401399ae2216ac25baaf457d5 --- arch/arm/kernel/sys_oabi-compat.c | 6 +++--- fs/compat.c | 14 +++++++------- fs/fcntl.c | 12 ++++++------ fs/locks.c | 14 +++++++------- include/uapi/asm-generic/fcntl.h | 20 ++++++++++---------- security/selinux/hooks.c | 6 +++--- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 7a41528bdb09..8a1c2c8a1a64 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -232,9 +232,9 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) { switch (cmd) { - case F_GETLKP: - case F_SETLKP: - case F_SETLKPW: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: case F_GETLK64: case F_SETLK64: case F_SETLKW64: diff --git a/fs/compat.c b/fs/compat.c index e3a4e8a7cdfe..e121b3fb42d0 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -457,9 +457,9 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, case F_GETLK64: case F_SETLK64: case F_SETLKW64: - case F_GETLKP: - case F_SETLKP: - case F_SETLKPW: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: ret = get_compat_flock64(&f, compat_ptr(arg)); if (ret != 0) break; @@ -468,7 +468,7 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, conv_cmd = convert_fcntl_cmd(cmd); ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f); set_fs(old_fs); - if ((conv_cmd == F_GETLK || conv_cmd == F_GETLKP) && ret == 0) { + if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) { /* need to return lock information - see above for commentary */ if (f.l_start > COMPAT_LOFF_T_MAX) ret = -EOVERFLOW; @@ -493,9 +493,9 @@ asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd, case F_GETLK64: case F_SETLK64: case F_SETLKW64: - case F_GETLKP: - case F_SETLKP: - case F_SETLKPW: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: return -EINVAL; } return compat_sys_fcntl64(fd, cmd, arg); diff --git a/fs/fcntl.c b/fs/fcntl.c index 3476c43e12dc..b788814086ef 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -276,15 +276,15 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, break; #if BITS_PER_LONG != 32 /* 32-bit arches must use fcntl64() */ - case F_GETLKP: + case F_OFD_GETLK: #endif case F_GETLK: err = fcntl_getlk(filp, cmd, (struct flock __user *) arg); break; #if BITS_PER_LONG != 32 /* 32-bit arches must use fcntl64() */ - case F_SETLKP: - case F_SETLKPW: + case F_OFD_SETLK: + case F_OFD_SETLKW: #endif /* Fallthrough */ case F_SETLK: @@ -405,13 +405,13 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, switch (cmd) { case F_GETLK64: - case F_GETLKP: + case F_OFD_GETLK: err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); break; case F_SETLK64: case F_SETLKW64: - case F_SETLKP: - case F_SETLKPW: + case F_OFD_SETLK: + case F_OFD_SETLKW: err = fcntl_setlk64(fd, f.file, cmd, (struct flock64 __user *) arg); break; diff --git a/fs/locks.c b/fs/locks.c index ad207427daeb..f18cc5a122ce 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1941,7 +1941,7 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) if (error) goto out; - if (cmd == F_GETLKP) { + if (cmd == F_OFD_GETLK) { error = -EINVAL; if (flock.l_pid != 0) goto out; @@ -2075,7 +2075,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, * FL_FILE_PVT flag and override the owner. */ switch (cmd) { - case F_SETLKP: + case F_OFD_SETLK: error = -EINVAL; if (flock.l_pid != 0) goto out; @@ -2084,7 +2084,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, file_lock->fl_flags |= FL_FILE_PVT; file_lock->fl_owner = (fl_owner_t)filp; break; - case F_SETLKPW: + case F_OFD_SETLKW: error = -EINVAL; if (flock.l_pid != 0) goto out; @@ -2145,7 +2145,7 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) if (error) goto out; - if (cmd == F_GETLKP) { + if (cmd == F_OFD_GETLK) { error = -EINVAL; if (flock.l_pid != 0) goto out; @@ -2212,7 +2212,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, * FL_FILE_PVT flag and override the owner. */ switch (cmd) { - case F_SETLKP: + case F_OFD_SETLK: error = -EINVAL; if (flock.l_pid != 0) goto out; @@ -2221,7 +2221,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, file_lock->fl_flags |= FL_FILE_PVT; file_lock->fl_owner = (fl_owner_t)filp; break; - case F_SETLKPW: + case F_OFD_SETLKW: error = -EINVAL; if (flock.l_pid != 0) goto out; @@ -2422,7 +2422,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, if (fl->fl_flags & FL_ACCESS) seq_printf(f, "ACCESS"); else if (IS_FILE_PVT(fl)) - seq_printf(f, "FLPVT "); + seq_printf(f, "OFDLCK"); else seq_printf(f, "POSIX "); diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index a9b13f8b3595..7543b3e51331 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -133,20 +133,20 @@ #endif /* - * fd "private" POSIX locks. + * Open File Description Locks * - * Usually POSIX locks held by a process are released on *any* close and are + * Usually record locks held by a process are released on *any* close and are * not inherited across a fork(). * - * These cmd values will set locks that conflict with normal POSIX locks, but - * are "owned" by the opened file, not the process. This means that they are - * inherited across fork() like BSD (flock) locks, and they are only released - * automatically when the last reference to the the open file against which - * they were acquired is put. + * These cmd values will set locks that conflict with process-associated + * record locks, but are "owned" by the open file description, not the + * process. This means that they are inherited across fork() like BSD (flock) + * locks, and they are only released automatically when the last reference to + * the the open file against which they were acquired is put. */ -#define F_GETLKP 36 -#define F_SETLKP 37 -#define F_SETLKPW 38 +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 #define F_OWNER_TID 0 #define F_OWNER_PID 1 diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a38a0071fb33..cd23eff1a00f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3333,9 +3333,9 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd, case F_GETLK: case F_SETLK: case F_SETLKW: - case F_GETLKP: - case F_SETLKP: - case F_SETLKPW: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: #if BITS_PER_LONG == 32 case F_GETLK64: case F_SETLK64: -- GitLab From 1d9cf79c82a76f1bb59c077eb4baaf95fcbc850a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 22 Apr 2014 08:24:32 -0400 Subject: [PATCH 315/528] locks: rename FL_FILE_PVT and IS_FILE_PVT to use "*_OFDLCK" instead File-private locks have been re-christened as "open file description" locks. Finish the symbol name cleanup in the internal implementation. Signed-off-by: Jeff Layton Change-Id: I94f11abc42ee4f3d9804c0915197ba21d72f02d3 --- fs/locks.c | 34 +++++++++++++++++----------------- include/linux/fs.h | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index f18cc5a122ce..a6dbbeaf0c89 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -135,7 +135,7 @@ #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) #define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG)) -#define IS_FILE_PVT(fl) (fl->fl_flags & FL_FILE_PVT) +#define IS_OFDLCK(fl) (fl->fl_flags & FL_OFDLCK) static bool lease_breaking(struct file_lock *fl) { @@ -564,7 +564,7 @@ static void __locks_insert_block(struct file_lock *blocker, BUG_ON(!list_empty(&waiter->fl_block)); waiter->fl_next = blocker; list_add_tail(&waiter->fl_block, &blocker->fl_block); - if (IS_POSIX(blocker) && !IS_FILE_PVT(blocker)) + if (IS_POSIX(blocker) && !IS_OFDLCK(blocker)) locks_insert_global_blocked(waiter); } @@ -759,12 +759,12 @@ EXPORT_SYMBOL(posix_test_lock); * of tasks (such as posix threads) sharing the same open file table. * To handle those cases, we just bail out after a few iterations. * - * For FL_FILE_PVT locks, the owner is the filp, not the files_struct. + * For FL_OFDLCK locks, the owner is the filp, not the files_struct. * Because the owner is not even nominally tied to a thread of * execution, the deadlock detection below can't reasonably work well. Just * skip it for those. * - * In principle, we could do a more limited deadlock detection on FL_FILE_PVT + * In principle, we could do a more limited deadlock detection on FL_OFDLCK * locks that just checks for the case where two tasks are attempting to * upgrade from read to write locks on the same inode. */ @@ -791,9 +791,9 @@ static int posix_locks_deadlock(struct file_lock *caller_fl, /* * This deadlock detector can't reasonably detect deadlocks with - * FL_FILE_PVT locks, since they aren't owned by a process, per-se. + * FL_OFDLCK locks, since they aren't owned by a process, per-se. */ - if (IS_FILE_PVT(caller_fl)) + if (IS_OFDLCK(caller_fl)) return 0; while ((block_fl = what_owner_is_waiting_for(block_fl))) { @@ -1890,7 +1890,7 @@ EXPORT_SYMBOL_GPL(vfs_test_lock); static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) { - flock->l_pid = IS_FILE_PVT(fl) ? -1 : fl->fl_pid; + flock->l_pid = IS_OFDLCK(fl) ? -1 : fl->fl_pid; #if BITS_PER_LONG == 32 /* * Make sure we can represent the posix lock via @@ -1912,7 +1912,7 @@ static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) #if BITS_PER_LONG == 32 static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) { - flock->l_pid = IS_FILE_PVT(fl) ? -1 : fl->fl_pid; + flock->l_pid = IS_OFDLCK(fl) ? -1 : fl->fl_pid; flock->l_start = fl->fl_start; flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : fl->fl_end - fl->fl_start + 1; @@ -1947,7 +1947,7 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) goto out; cmd = F_GETLK; - file_lock.fl_flags |= FL_FILE_PVT; + file_lock.fl_flags |= FL_OFDLCK; file_lock.fl_owner = (fl_owner_t)filp; } @@ -2072,7 +2072,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, /* * If the cmd is requesting file-private locks, then set the - * FL_FILE_PVT flag and override the owner. + * FL_OFDLCK flag and override the owner. */ switch (cmd) { case F_OFD_SETLK: @@ -2081,7 +2081,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, goto out; cmd = F_SETLK; - file_lock->fl_flags |= FL_FILE_PVT; + file_lock->fl_flags |= FL_OFDLCK; file_lock->fl_owner = (fl_owner_t)filp; break; case F_OFD_SETLKW: @@ -2090,7 +2090,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, goto out; cmd = F_SETLKW; - file_lock->fl_flags |= FL_FILE_PVT; + file_lock->fl_flags |= FL_OFDLCK; file_lock->fl_owner = (fl_owner_t)filp; /* Fallthrough */ case F_SETLKW: @@ -2151,7 +2151,7 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) goto out; cmd = F_GETLK64; - file_lock.fl_flags |= FL_FILE_PVT; + file_lock.fl_flags |= FL_OFDLCK; file_lock.fl_owner = (fl_owner_t)filp; } @@ -2209,7 +2209,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, /* * If the cmd is requesting file-private locks, then set the - * FL_FILE_PVT flag and override the owner. + * FL_OFDLCK flag and override the owner. */ switch (cmd) { case F_OFD_SETLK: @@ -2218,7 +2218,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, goto out; cmd = F_SETLK64; - file_lock->fl_flags |= FL_FILE_PVT; + file_lock->fl_flags |= FL_OFDLCK; file_lock->fl_owner = (fl_owner_t)filp; break; case F_OFD_SETLKW: @@ -2227,7 +2227,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, goto out; cmd = F_SETLKW64; - file_lock->fl_flags |= FL_FILE_PVT; + file_lock->fl_flags |= FL_OFDLCK; file_lock->fl_owner = (fl_owner_t)filp; /* Fallthrough */ case F_SETLKW64: @@ -2421,7 +2421,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, if (IS_POSIX(fl)) { if (fl->fl_flags & FL_ACCESS) seq_printf(f, "ACCESS"); - else if (IS_FILE_PVT(fl)) + else if (IS_OFDLCK(fl)) seq_printf(f, "OFDLCK"); else seq_printf(f, "POSIX "); diff --git a/include/linux/fs.h b/include/linux/fs.h index 6dff9f4097bd..b617be889dbc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -917,7 +917,7 @@ static inline int file_check_writeable(struct file *filp) #define FL_SLEEP 128 /* A blocking lock */ #define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ #define FL_UNLOCK_PENDING 512 /* Lease is being broken */ -#define FL_FILE_PVT 1024 /* lock is private to the file */ +#define FL_OFDLCK 1024 /* lock is "owned" by struct file */ /* * Special return value from posix_lock_file() and vfs_lock_file() for -- GitLab From 7ac8aade75d42950f5e79eb28e3cb1d33b26efb9 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 9 May 2014 11:41:54 -0400 Subject: [PATCH 316/528] locks: only validate the lock vs. f_mode in F_SETLK codepaths v2: replace missing break in switch statement (as pointed out by Dave Jones) commit bce7560d4946 (locks: consolidate checks for compatible filp->f_mode values in setlk handlers) introduced a regression in the F_GETLK handler. flock64_to_posix_lock is a shared codepath between F_GETLK and F_SETLK, but the f_mode checks should only be applicable to the F_SETLK codepaths according to POSIX. Instead of just reverting the patch, add a new function to do this checking and have the F_SETLK handlers call it. Cc: Dave Jones Reported-and-Tested-by: Reuben Farrelly Signed-off-by: Jeff Layton Change-Id: I53aa24e39c7f3320cb1bbee59f9599897928a1dc --- fs/locks.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index a6dbbeaf0c89..0fb3976efe00 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -389,18 +389,6 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, fl->fl_ops = NULL; fl->fl_lmops = NULL; - /* Ensure that fl->fl_filp has compatible f_mode */ - switch (l->l_type) { - case F_RDLCK: - if (!(filp->f_mode & FMODE_READ)) - return -EBADF; - break; - case F_WRLCK: - if (!(filp->f_mode & FMODE_WRITE)) - return -EBADF; - break; - } - return assign_type(fl, l->l_type); } @@ -2034,6 +2022,22 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd, return error; } +/* Ensure that fl->fl_filp has compatible f_mode for F_SETLK calls */ +static int +check_fmode_for_setlk(struct file_lock *fl) +{ + switch (fl->fl_type) { + case F_RDLCK: + if (!(fl->fl_file->f_mode & FMODE_READ)) + return -EBADF; + break; + case F_WRLCK: + if (!(fl->fl_file->f_mode & FMODE_WRITE)) + return -EBADF; + } + return 0; +} + /* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). */ @@ -2070,6 +2074,10 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, if (error) goto out; + error = check_fmode_for_setlk(file_lock); + if (error) + goto out; + /* * If the cmd is requesting file-private locks, then set the * FL_OFDLCK flag and override the owner. @@ -2207,6 +2215,10 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, if (error) goto out; + error = check_fmode_for_setlk(file_lock); + if (error) + goto out; + /* * If the cmd is requesting file-private locks, then set the * FL_OFDLCK flag and override the owner. -- GitLab From a499e4e17d3fff0d1cda707370606f2165065491 Mon Sep 17 00:00:00 2001 From: Jim Schutt Date: Wed, 15 May 2013 10:38:12 -0600 Subject: [PATCH 317/528] ceph: fix up comment for ceph_count_locks() as to which lock to hold Signed-off-by: Jim Schutt Reviewed-by: Alex Elder Change-Id: I8b362d034327feb2df1e704eaa80864193722d2c --- fs/ceph/locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 690f73f42425..ae6d14e82b0f 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -169,7 +169,7 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) } /** - * Must be called with BKL already held. Fills in the passed + * Must be called with lock_flocks() already held. Fills in the passed * counter variables, so you can prepare pagelist metadata before calling * ceph_encode_locks. */ -- GitLab From 4c289f4b19c61e666734531264ba81bb8982369c Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 4 Mar 2014 15:42:24 +0800 Subject: [PATCH 318/528] ceph: use fl->fl_type to decide flock operation VFS does not directly pass flock's operation code to filesystem's flock callback. It translates the operation code to the form how posix lock's parameters are presented. Signed-off-by: Yan, Zheng Change-Id: I3294e3bccddc5323ab5197a063c2b8b1d9a47716 --- fs/ceph/locks.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index ae6d14e82b0f..133e0063da64 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -91,10 +91,10 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) dout("ceph_lock, fl_pid:%d", fl->fl_pid); /* set wait bit as appropriate, then make command as Ceph expects it*/ - if (F_SETLKW == cmd) - wait = 1; - if (F_GETLK == cmd) + if (IS_GETLK(cmd)) op = CEPH_MDS_OP_GETFILELOCK; + else if (IS_SETLKW(cmd)) + wait = 1; if (F_RDLCK == fl->fl_type) lock_cmd = CEPH_LOCK_SHARED; @@ -131,20 +131,17 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) { u8 lock_cmd; int err; - u8 wait = 1; + u8 wait = 0; fl->fl_nspid = get_pid(task_tgid(current)); dout("ceph_flock, fl_pid:%d", fl->fl_pid); - /* set wait bit, then clear it out of cmd*/ - if (cmd & LOCK_NB) - wait = 0; - cmd = cmd & (LOCK_SH | LOCK_EX | LOCK_UN); - /* set command sequence that Ceph wants to see: - shared lock, exclusive lock, or unlock */ - if (LOCK_SH == cmd) + if (IS_SETLKW(cmd)) + wait = 1; + + if (F_RDLCK == fl->fl_type) lock_cmd = CEPH_LOCK_SHARED; - else if (LOCK_EX == cmd) + else if (F_WRLCK == fl->fl_type) lock_cmd = CEPH_LOCK_EXCL; else lock_cmd = CEPH_LOCK_UNLOCK; -- GitLab From ed5826a8918212dd2f94cb5d558ad0dc3a7809d4 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 4 Mar 2014 15:50:06 +0800 Subject: [PATCH 319/528] ceph: forbid mandatory file lock Signed-off-by: Yan, Zheng Change-Id: I68ff2e5a9a3c80caa2a3575ad533e6a803a6c59d --- fs/ceph/locks.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 133e0063da64..f91a569a20fb 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -87,6 +87,12 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) u8 wait = 0; u16 op = CEPH_MDS_OP_SETFILELOCK; + if (!(fl->fl_flags & FL_POSIX)) + return -ENOLCK; + /* No mandatory locks */ + if (__mandatory_lock(file->f_mapping->host) && fl->fl_type != F_UNLCK) + return -ENOLCK; + fl->fl_nspid = get_pid(task_tgid(current)); dout("ceph_lock, fl_pid:%d", fl->fl_pid); @@ -133,6 +139,12 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) int err; u8 wait = 0; + if (!(fl->fl_flags & FL_FLOCK)) + return -ENOLCK; + /* No mandatory locks */ + if (__mandatory_lock(file->f_mapping->host) && fl->fl_type != F_UNLCK) + return -ENOLCK; + fl->fl_nspid = get_pid(task_tgid(current)); dout("ceph_flock, fl_pid:%d", fl->fl_pid); -- GitLab From b33d0d4002cf3870556b398f0a0da0b4e9d0c24c Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Sun, 9 Mar 2014 23:16:40 +0800 Subject: [PATCH 320/528] ceph: use fl->fl_file as owner identifier of flock and posix lock flock and posix lock should use fl->fl_file instead of process ID as owner identifier. (posix lock uses fl->fl_owner. fl->fl_owner is usually equal to fl->fl_file, but it also can be a customized value). The process ID of who holds the lock is just for F_GETLK fcntl(2). The fix is rename the 'pid' fields of struct ceph_mds_request_args and struct ceph_filelock to 'owner', rename 'pid_namespace' fields to 'pid'. Assign fl->fl_file to the 'owner' field of lock messages. We also set the most significant bit of the 'owner' field. MDS can use that bit to distinguish between old and new clients. The MDS counterpart of this patch modifies the flock code to not take the 'pid_namespace' into consideration when checking conflict locks. Signed-off-by: Yan, Zheng Reviewed-by: Sage Weil Change-Id: Ifd155c0d82b1991e083ed97e5bd7ad6b6fafcb56 --- fs/ceph/locks.c | 61 ++++++++++++++++++++++++------------ fs/ceph/super.c | 1 + fs/ceph/super.h | 1 + include/linux/ceph/ceph_fs.h | 4 +-- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index f91a569a20fb..d94ba0df9f4d 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -2,11 +2,31 @@ #include #include +#include #include "super.h" #include "mds_client.h" #include +static u64 lock_secret; + +static inline u64 secure_addr(void *addr) +{ + u64 v = lock_secret ^ (u64)(unsigned long)addr; + /* + * Set the most significant bit, so that MDS knows the 'owner' + * is sufficient to identify the owner of lock. (old code uses + * both 'owner' and 'pid') + */ + v |= (1ULL << 63); + return v; +} + +void __init ceph_flock_init(void) +{ + get_random_bytes(&lock_secret, sizeof(lock_secret)); +} + /** * Implement fcntl and flock locking functions. */ @@ -14,11 +34,11 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, int cmd, u8 wait, struct file_lock *fl) { struct inode *inode = file_inode(file); - struct ceph_mds_client *mdsc = - ceph_sb_to_client(inode->i_sb)->mdsc; + struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; struct ceph_mds_request *req; int err; u64 length = 0; + u64 owner; req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS); if (IS_ERR(req)) @@ -32,25 +52,27 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, else length = fl->fl_end - fl->fl_start + 1; - dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " - "length: %llu, wait: %d, type: %d", (int)lock_type, - (int)operation, (u64)fl->fl_pid, fl->fl_start, - length, wait, fl->fl_type); + if (lock_type == CEPH_LOCK_FCNTL) + owner = secure_addr(fl->fl_owner); + else + owner = secure_addr(fl->fl_file); + + dout("ceph_lock_message: rule: %d, op: %d, owner: %llx, pid: %llu, " + "start: %llu, length: %llu, wait: %d, type: %d", (int)lock_type, + (int)operation, owner, (u64)fl->fl_pid, fl->fl_start, length, + wait, fl->fl_type); req->r_args.filelock_change.rule = lock_type; req->r_args.filelock_change.type = cmd; + req->r_args.filelock_change.owner = cpu_to_le64(owner); req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid); - /* This should be adjusted, but I'm not sure if - namespaces actually get id numbers*/ - req->r_args.filelock_change.pid_namespace = - cpu_to_le64((u64)(unsigned long)fl->fl_nspid); req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start); req->r_args.filelock_change.length = cpu_to_le64(length); req->r_args.filelock_change.wait = wait; err = ceph_mdsc_do_request(mdsc, inode, req); - if ( operation == CEPH_MDS_OP_GETFILELOCK){ + if (operation == CEPH_MDS_OP_GETFILELOCK) { fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid); if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type) fl->fl_type = F_RDLCK; @@ -93,8 +115,7 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) if (__mandatory_lock(file->f_mapping->host) && fl->fl_type != F_UNLCK) return -ENOLCK; - fl->fl_nspid = get_pid(task_tgid(current)); - dout("ceph_lock, fl_pid:%d", fl->fl_pid); + dout("ceph_lock, fl_owner: %p", fl->fl_owner); /* set wait bit as appropriate, then make command as Ceph expects it*/ if (IS_GETLK(cmd)) @@ -111,7 +132,7 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl); if (!err) { - if ( op != CEPH_MDS_OP_GETFILELOCK ){ + if (op != CEPH_MDS_OP_GETFILELOCK) { dout("mds locked, locking locally"); err = posix_lock_file(file, fl, NULL); if (err && (CEPH_MDS_OP_SETFILELOCK == op)) { @@ -145,8 +166,7 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) if (__mandatory_lock(file->f_mapping->host) && fl->fl_type != F_UNLCK) return -ENOLCK; - fl->fl_nspid = get_pid(task_tgid(current)); - dout("ceph_flock, fl_pid:%d", fl->fl_pid); + dout("ceph_flock, fl_file: %p", fl->fl_file); if (IS_SETLKW(cmd)) wait = 1; @@ -289,13 +309,14 @@ int lock_to_ceph_filelock(struct file_lock *lock, struct ceph_filelock *cephlock) { int err = 0; - cephlock->start = cpu_to_le64(lock->fl_start); cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1); cephlock->client = cpu_to_le64(0); - cephlock->pid = cpu_to_le64(lock->fl_pid); - cephlock->pid_namespace = - cpu_to_le64((u64)(unsigned long)lock->fl_nspid); + cephlock->pid = cpu_to_le64((u64)lock->fl_pid); + if (lock->fl_flags & FL_POSIX) + cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner)); + else + cephlock->owner = cpu_to_le64(secure_addr(lock->fl_file)); switch (lock->fl_type) { case F_RDLCK: diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 6627b26a800c..151c1b1e6c0e 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -966,6 +966,7 @@ static int __init init_ceph(void) if (ret) goto out; + ceph_flock_init(); ceph_xattr_init(); ret = register_filesystem(&ceph_fs_type); if (ret) diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 7ccfdb4aea2e..2abe00ceca4a 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -819,6 +819,7 @@ extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg); extern const struct export_operations ceph_export_ops; /* locks.c */ +extern __init void ceph_flock_init(void); extern int ceph_lock(struct file *file, int cmd, struct file_lock *fl); extern int ceph_flock(struct file *file, int cmd, struct file_lock *fl); extern void ceph_count_locks(struct inode *inode, int *p_num, int *f_num); diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h index 2ad7b860f062..546ac1cbae9b 100644 --- a/include/linux/ceph/ceph_fs.h +++ b/include/linux/ceph/ceph_fs.h @@ -394,8 +394,8 @@ union ceph_mds_request_args { struct { __u8 rule; /* currently fcntl or flock */ __u8 type; /* shared, exclusive, remove*/ + __le64 owner; /* owner of the lock */ __le64 pid; /* process id requesting the lock */ - __le64 pid_namespace; __le64 start; /* initial location to lock */ __le64 length; /* num bytes to lock from start */ __u8 wait; /* will caller wait for lock to become available? */ @@ -505,8 +505,8 @@ struct ceph_filelock { __le64 start;/* file offset to start lock at */ __le64 length; /* num bytes to lock; 0 for all following start */ __le64 client; /* which client holds the lock */ + __le64 owner; /* owner the lock */ __le64 pid; /* process id holding the lock on the client */ - __le64 pid_namespace; __u8 type; /* shared lock, exclusive lock, or unlock */ } __attribute__ ((packed)); -- GitLab From d4227503dc56c844409590dd1f2abb8b6e19b52c Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Sun, 27 Apr 2014 09:17:45 +0800 Subject: [PATCH 321/528] ceph: reserve caps for file layout/lock MDS requests Signed-off-by: Yan, Zheng Reviewed-by: Sage Weil Change-Id: I309efde361b99724c73110082810d1144f618794 --- fs/ceph/ioctl.c | 3 +++ fs/ceph/locks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/fs/ceph/ioctl.c b/fs/ceph/ioctl.c index 669622fd1ae3..513e2e0ae53d 100644 --- a/fs/ceph/ioctl.c +++ b/fs/ceph/ioctl.c @@ -111,6 +111,8 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg) return PTR_ERR(req); req->r_inode = inode; ihold(inode); + req->r_num_caps = 1; + req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL; req->r_args.setlayout.layout.fl_stripe_unit = @@ -157,6 +159,7 @@ static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg) return PTR_ERR(req); req->r_inode = inode; ihold(inode); + req->r_num_caps = 1; req->r_args.setlayout.layout.fl_stripe_unit = cpu_to_le32(l.stripe_unit); diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index d94ba0df9f4d..191398852a2e 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -45,6 +45,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, return PTR_ERR(req); req->r_inode = inode; ihold(inode); + req->r_num_caps = 1; /* mds requires start and length rather than start and end */ if (LLONG_MAX == fl->fl_end) -- GitLab From 9e8ffcf70c18c05b03720b00a92af5422c71065b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 9 May 2014 14:13:04 -0400 Subject: [PATCH 322/528] locks: ensure that fl_owner is always initialized properly in flock and lease codepaths Currently, the fl_owner isn't set for flock locks. Some filesystems use byte-range locks to simulate flock locks and there is a common idiom in those that does: fl->fl_owner = (fl_owner_t)filp; fl->fl_start = 0; fl->fl_end = OFFSET_MAX; Since flock locks are generally "owned" by the open file description, move this into the common flock lock setup code. The fl_start and fl_end fields are already set appropriately, so remove the unneeded setting of that in flock ops in those filesystems as well. Finally, the lease code also sets the fl_owner as if they were owned by the process and not the open file description. This is incorrect as leases have the same ownership semantics as flock locks. Set them the same way. The lease code doesn't actually use the fl_owner value for anything, so this is more for consistency's sake than a bugfix. Reported-by: Trond Myklebust Signed-off-by: Jeff Layton Acked-by: Greg Kroah-Hartman (Staging portion) Acked-by: J. Bruce Fields Change-Id: Iad109109cbfdb88c80936021e6a47d27b048b8c5 --- fs/9p/vfs_file.c | 3 --- fs/afs/flock.c | 4 ---- fs/ceph/locks.c | 10 ++-------- fs/fuse/file.c | 1 - fs/locks.c | 4 +++- fs/nfs/file.c | 4 ---- 6 files changed, 5 insertions(+), 21 deletions(-) diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index d384a8b77ee8..0306c321165c 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -352,9 +352,6 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd, invalidate_mapping_pages(&inode->i_data, 0, -1); } /* Convert flock to posix lock */ - fl->fl_owner = (fl_owner_t)filp; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; fl->fl_flags |= FL_POSIX; fl->fl_flags ^= FL_FLOCK; diff --git a/fs/afs/flock.c b/fs/afs/flock.c index a8cf2cff836c..4baf1d2b39e4 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -555,10 +555,6 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl) return -ENOLCK; /* we're simulating flock() locks using posix locks on the server */ - fl->fl_owner = (fl_owner_t) file; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; - if (fl->fl_type == F_UNLCK) return afs_do_unlk(file, fl); return afs_do_setlk(file, fl); diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 191398852a2e..fbc39c47bacd 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -53,10 +53,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, else length = fl->fl_end - fl->fl_start + 1; - if (lock_type == CEPH_LOCK_FCNTL) - owner = secure_addr(fl->fl_owner); - else - owner = secure_addr(fl->fl_file); + owner = secure_addr(fl->fl_owner); dout("ceph_lock_message: rule: %d, op: %d, owner: %llx, pid: %llu, " "start: %llu, length: %llu, wait: %d, type: %d", (int)lock_type, @@ -314,10 +311,7 @@ int lock_to_ceph_filelock(struct file_lock *lock, cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1); cephlock->client = cpu_to_le64(0); cephlock->pid = cpu_to_le64((u64)lock->fl_pid); - if (lock->fl_flags & FL_POSIX) - cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner)); - else - cephlock->owner = cpu_to_le64(secure_addr(lock->fl_file)); + cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner)); switch (lock->fl_type) { case F_RDLCK: diff --git a/fs/fuse/file.c b/fs/fuse/file.c index ecead55e028f..720b9edbf99e 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2051,7 +2051,6 @@ static int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl) struct fuse_file *ff = file->private_data; /* emulate flock with POSIX locks */ - fl->fl_owner = (fl_owner_t) file; ff->flock = true; err = fuse_setlk(file, fl, 1); } diff --git a/fs/locks.c b/fs/locks.c index 0fb3976efe00..ebd55815c88b 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -322,6 +322,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock, return -ENOMEM; fl->fl_file = filp; + fl->fl_owner = (fl_owner_t)filp; fl->fl_pid = current->tgid; fl->fl_flags = FL_FLOCK; fl->fl_type = type; @@ -427,7 +428,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl) if (assign_type(fl, type) != 0) return -EINVAL; - fl->fl_owner = current->files; + fl->fl_owner = (fl_owner_t)filp; fl->fl_pid = current->tgid; fl->fl_file = filp; @@ -2325,6 +2326,7 @@ void locks_remove_file(struct file *filp) if (filp->f_op && filp->f_op->flock) { struct file_lock fl = { + .fl_owner = (fl_owner_t)filp, .fl_pid = current->tgid, .fl_file = filp, .fl_flags = FL_FLOCK, diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f8bd4ea2a891..d90d1d1d9188 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -894,10 +894,6 @@ int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) is_local = 1; /* We're simulating flock() locks using posix locks on the server */ - fl->fl_owner = (fl_owner_t)filp; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; - if (fl->fl_type == F_UNLCK) return do_unlk(filp, cmd, fl, is_local); return do_setlk(filp, cmd, fl, is_local); -- GitLab From c2a38597df3fad17dd9381b5741d98f1b27c8028 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 9 May 2014 14:13:05 -0400 Subject: [PATCH 323/528] fs/locks.c: replace seq_printf by seq_puts Replace seq_printf where possible Cc: Jeff Layton Cc: Alexander Viro Cc: Andrew Morton Signed-off-by: Fabian Frederick Signed-off-by: Jeff Layton Change-Id: Ibfb056d150d62036a6187852f0ee57e7c2ecfe62 --- fs/locks.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index ebd55815c88b..9d658951f15a 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2434,31 +2434,31 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, seq_printf(f, "%lld:%s ", id, pfx); if (IS_POSIX(fl)) { if (fl->fl_flags & FL_ACCESS) - seq_printf(f, "ACCESS"); + seq_puts(f, "ACCESS"); else if (IS_OFDLCK(fl)) - seq_printf(f, "OFDLCK"); + seq_puts(f, "OFDLCK"); else - seq_printf(f, "POSIX "); + seq_puts(f, "POSIX "); seq_printf(f, " %s ", (inode == NULL) ? "*NOINODE*" : mandatory_lock(inode) ? "MANDATORY" : "ADVISORY "); } else if (IS_FLOCK(fl)) { if (fl->fl_type & LOCK_MAND) { - seq_printf(f, "FLOCK MSNFS "); + seq_puts(f, "FLOCK MSNFS "); } else { - seq_printf(f, "FLOCK ADVISORY "); + seq_puts(f, "FLOCK ADVISORY "); } } else if (IS_LEASE(fl)) { - seq_printf(f, "LEASE "); + seq_puts(f, "LEASE "); if (lease_breaking(fl)) - seq_printf(f, "BREAKING "); + seq_puts(f, "BREAKING "); else if (fl->fl_file) - seq_printf(f, "ACTIVE "); + seq_puts(f, "ACTIVE "); else - seq_printf(f, "BREAKER "); + seq_puts(f, "BREAKER "); } else { - seq_printf(f, "UNKNOWN UNKNOWN "); + seq_puts(f, "UNKNOWN UNKNOWN "); } if (fl->fl_type & LOCK_MAND) { seq_printf(f, "%s ", @@ -2490,7 +2490,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, else seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end); } else { - seq_printf(f, "0 EOF\n"); + seq_puts(f, "0 EOF\n"); } } -- GitLab From e49f80c39b9f1810486f154c007c7898c4c673db Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 9 May 2014 14:13:05 -0400 Subject: [PATCH 324/528] locks: add some tracepoints in the lease handling code v2: add a __break_lease tracepoint for non-blocking case Recently, I needed these to help track down a softlockup when recalling a delegation, but they might be helpful in other situations as well. Cc: "J. Bruce Fields" Signed-off-by: Jeff Layton Change-Id: Ic6309053c6edeef4da644d349122a60afac0fb04 --- fs/locks.c | 11 ++++ include/trace/events/filelock.h | 96 +++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 include/trace/events/filelock.h diff --git a/fs/locks.c b/fs/locks.c index 9d658951f15a..4af3fec5f48c 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -130,6 +130,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) @@ -1287,6 +1290,7 @@ static void time_out_leases(struct inode *inode) before = &inode->i_flock; while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) { + trace_time_out_leases(inode, fl); if (past_time(fl->fl_downgrade_time)) lease_modify(before, F_RDLCK); if (past_time(fl->fl_break_time)) @@ -1374,6 +1378,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) } if (i_have_this_lease || (mode & O_NONBLOCK)) { + trace_break_lease_noblock(inode, new_fl); error = -EWOULDBLOCK; goto out; } @@ -1385,10 +1390,12 @@ restart: if (break_time == 0) break_time++; locks_insert_block(flock, new_fl); + trace_break_lease_block(inode, new_fl); spin_unlock(&inode->i_lock); error = wait_event_interruptible_timeout(new_fl->fl_wait, !new_fl->fl_next, break_time); spin_lock(&inode->i_lock); + trace_break_lease_unblock(inode, new_fl); locks_delete_block(new_fl); if (error >= 0) { if (error == 0) @@ -1510,6 +1517,8 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp int error; lease = *flp; + trace_generic_add_lease(inode, lease); + /* * In the delegation case we need mutual exclusion with * a number of operations that take the i_mutex. We trylock @@ -1599,6 +1608,8 @@ static int generic_delete_lease(struct file *filp, struct file_lock **flp) struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; + trace_generic_delete_lease(inode, *flp); + for (before = &inode->i_flock; ((fl = *before) != NULL) && IS_LEASE(fl); before = &fl->fl_next) { diff --git a/include/trace/events/filelock.h b/include/trace/events/filelock.h new file mode 100644 index 000000000000..59d11c22f076 --- /dev/null +++ b/include/trace/events/filelock.h @@ -0,0 +1,96 @@ +/* + * Events for filesystem locks + * + * Copyright 2013 Jeff Layton + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM filelock + +#if !defined(_TRACE_FILELOCK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_FILELOCK_H + +#include +#include +#include +#include + +#define show_fl_flags(val) \ + __print_flags(val, "|", \ + { FL_POSIX, "FL_POSIX" }, \ + { FL_FLOCK, "FL_FLOCK" }, \ + { FL_DELEG, "FL_DELEG" }, \ + { FL_ACCESS, "FL_ACCESS" }, \ + { FL_EXISTS, "FL_EXISTS" }, \ + { FL_LEASE, "FL_LEASE" }, \ + { FL_CLOSE, "FL_CLOSE" }, \ + { FL_SLEEP, "FL_SLEEP" }, \ + { FL_DOWNGRADE_PENDING, "FL_DOWNGRADE_PENDING" }, \ + { FL_UNLOCK_PENDING, "FL_UNLOCK_PENDING" }, \ + { FL_OFDLCK, "FL_OFDLCK" }) + +#define show_fl_type(val) \ + __print_symbolic(val, \ + { F_RDLCK, "F_RDLCK" }, \ + { F_WRLCK, "F_WRLCK" }, \ + { F_UNLCK, "F_UNLCK" }) + +DECLARE_EVENT_CLASS(filelock_lease, + + TP_PROTO(struct inode *inode, struct file_lock *fl), + + TP_ARGS(inode, fl), + + TP_STRUCT__entry( + __field(struct file_lock *, fl) + __field(unsigned long, i_ino) + __field(dev_t, s_dev) + __field(struct file_lock *, fl_next) + __field(fl_owner_t, fl_owner) + __field(unsigned int, fl_flags) + __field(unsigned char, fl_type) + __field(unsigned long, fl_break_time) + __field(unsigned long, fl_downgrade_time) + ), + + TP_fast_assign( + __entry->fl = fl; + __entry->s_dev = inode->i_sb->s_dev; + __entry->i_ino = inode->i_ino; + __entry->fl_next = fl->fl_next; + __entry->fl_owner = fl->fl_owner; + __entry->fl_flags = fl->fl_flags; + __entry->fl_type = fl->fl_type; + __entry->fl_break_time = fl->fl_break_time; + __entry->fl_downgrade_time = fl->fl_downgrade_time; + ), + + TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_next=0x%p fl_owner=0x%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu", + __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev), + __entry->i_ino, __entry->fl_next, __entry->fl_owner, + show_fl_flags(__entry->fl_flags), + show_fl_type(__entry->fl_type), + __entry->fl_break_time, __entry->fl_downgrade_time) +); + +DEFINE_EVENT(filelock_lease, break_lease_noblock, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, break_lease_block, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, break_lease_unblock, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, generic_add_lease, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, generic_delete_lease, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, time_out_leases, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +#endif /* _TRACE_FILELOCK_H */ + +/* This part must be outside protection */ +#include -- GitLab From b23183353028109b06b4e01c2328876522aed201 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 10 Jun 2014 12:29:05 -0400 Subject: [PATCH 325/528] locks: set fl_owner for leases back to current->files This fixes a regression due to commit 130d1f956ab3 (locks: ensure that fl_owner is always initialized properly in flock and lease codepaths). I had mistakenly thought that the fl_owner wasn't used in the lease code, but I missed the place in __break_lease that does use it. The i_have_this_lease check in generic_add_lease uses it. While I'm not sure that check is terribly helpful [1], reset it back to using current->files in order to ensure that there's no behavior change here. [1]: leases are owned by the file description. It's possible that this is a threaded program, and the lease breaker and the task that would handle the signal are different, even if they have the same file table. So, there is the potential for false positives with this check. Fixes: 130d1f956ab3 (locks: ensure that fl_owner is always initialized properly in flock and lease codepaths) Signed-off-by: Jeff Layton Change-Id: Iac6bc43c0eefab81b9b0d53355a8e0f12374e1a1 --- fs/locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/locks.c b/fs/locks.c index 4af3fec5f48c..3e90302d96b2 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -431,7 +431,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl) if (assign_type(fl, type) != 0) return -EINVAL; - fl->fl_owner = (fl_owner_t)filp; + fl->fl_owner = (fl_owner_t)current->files; fl->fl_pid = current->tgid; fl->fl_file = filp; -- GitLab From 7d7bdad9705a3515f5f7dbf5eb23d58f3005d358 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 13 Jul 2014 17:00:38 +0200 Subject: [PATCH 326/528] locks: purge fl_owner_t from fs/locks.c Signed-off-by: Christoph Hellwig Signed-off-by: Jeff Layton Change-Id: I00289a26772621dc051ac20ed1344473354390a3 --- fs/locks.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 3e90302d96b2..68c99ff106a8 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -325,7 +325,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock, return -ENOMEM; fl->fl_file = filp; - fl->fl_owner = (fl_owner_t)filp; + fl->fl_owner = filp; fl->fl_pid = current->tgid; fl->fl_flags = FL_FLOCK; fl->fl_type = type; @@ -431,7 +431,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl) if (assign_type(fl, type) != 0) return -EINVAL; - fl->fl_owner = (fl_owner_t)current->files; + fl->fl_owner = current->files; fl->fl_pid = current->tgid; fl->fl_file = filp; @@ -1155,7 +1155,6 @@ EXPORT_SYMBOL(posix_lock_file_wait); int locks_mandatory_locked(struct file *file) { struct inode *inode = file_inode(file); - fl_owner_t owner = current->files; struct file_lock *fl; /* @@ -1165,7 +1164,8 @@ int locks_mandatory_locked(struct file *file) for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!IS_POSIX(fl)) continue; - if (fl->fl_owner != owner && fl->fl_owner != (fl_owner_t)file) + if (fl->fl_owner != current->files && + fl->fl_owner != file) break; } spin_unlock(&inode->i_lock); @@ -1205,7 +1205,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, for (;;) { if (filp) { - fl.fl_owner = (fl_owner_t)filp; + fl.fl_owner = filp; fl.fl_flags &= ~FL_SLEEP; error = __posix_lock_file(inode, &fl, NULL); if (!error) @@ -1948,7 +1948,7 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) cmd = F_GETLK; file_lock.fl_flags |= FL_OFDLCK; - file_lock.fl_owner = (fl_owner_t)filp; + file_lock.fl_owner = filp; } error = vfs_test_lock(filp, &file_lock); @@ -2102,7 +2102,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, cmd = F_SETLK; file_lock->fl_flags |= FL_OFDLCK; - file_lock->fl_owner = (fl_owner_t)filp; + file_lock->fl_owner = filp; break; case F_OFD_SETLKW: error = -EINVAL; @@ -2111,7 +2111,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, cmd = F_SETLKW; file_lock->fl_flags |= FL_OFDLCK; - file_lock->fl_owner = (fl_owner_t)filp; + file_lock->fl_owner = filp; /* Fallthrough */ case F_SETLKW: file_lock->fl_flags |= FL_SLEEP; @@ -2172,7 +2172,7 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) cmd = F_GETLK64; file_lock.fl_flags |= FL_OFDLCK; - file_lock.fl_owner = (fl_owner_t)filp; + file_lock.fl_owner = filp; } error = vfs_test_lock(filp, &file_lock); @@ -2243,7 +2243,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, cmd = F_SETLK64; file_lock->fl_flags |= FL_OFDLCK; - file_lock->fl_owner = (fl_owner_t)filp; + file_lock->fl_owner = filp; break; case F_OFD_SETLKW: error = -EINVAL; @@ -2252,7 +2252,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, cmd = F_SETLKW64; file_lock->fl_flags |= FL_OFDLCK; - file_lock->fl_owner = (fl_owner_t)filp; + file_lock->fl_owner = filp; /* Fallthrough */ case F_SETLKW64: file_lock->fl_flags |= FL_SLEEP; @@ -2333,11 +2333,11 @@ void locks_remove_file(struct file *filp) if (!inode->i_flock) return; - locks_remove_posix(filp, (fl_owner_t)filp); + locks_remove_posix(filp, filp); if (filp->f_op && filp->f_op->flock) { struct file_lock fl = { - .fl_owner = (fl_owner_t)filp, + .fl_owner = filp, .fl_pid = current->tgid, .fl_file = filp, .fl_flags = FL_FLOCK, -- GitLab From 03f1bb1ecbf496e2926b076b4e24860c080cc04b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 11 Aug 2014 13:36:54 -0400 Subject: [PATCH 327/528] locks: show delegations as "DELEG" in /proc/locks Now that they are a distinct lease type, show them as such. Cc: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: Ia82c76c26824d26dab81af9c7f1ff372c4bfa255 --- fs/locks.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/locks.c b/fs/locks.c index 68c99ff106a8..8cfe13ad560e 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2461,7 +2461,11 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, seq_puts(f, "FLOCK ADVISORY "); } } else if (IS_LEASE(fl)) { - seq_puts(f, "LEASE "); + if (fl->fl_flags & FL_DELEG) + seq_puts(f, "DELEG "); + else + seq_puts(f, "LEASE "); + if (lease_breaking(fl)) seq_puts(f, "BREAKING "); else if (fl->fl_file) -- GitLab From ef084b94d3c3aa0932e7c418b16df5b234347296 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 11 Aug 2014 14:09:35 -0400 Subject: [PATCH 328/528] locks: don't call locks_release_private from locks_copy_lock All callers of locks_copy_lock pass in a brand new file_lock struct, so there's no need to call locks_release_private on it. Replace that with a warning that fires in the event that we receive a target lock that doesn't look like it's properly initialized. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: I178913c595688f9b512ef1dff38c9d81369acc1e --- fs/locks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/locks.c b/fs/locks.c index 8cfe13ad560e..50a8bedb4094 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -285,7 +285,8 @@ EXPORT_SYMBOL(__locks_copy_lock); void locks_copy_lock(struct file_lock *new, struct file_lock *fl) { - locks_release_private(new); + /* "new" must be a freshly-initialized lock */ + WARN_ON_ONCE(new->fl_ops); __locks_copy_lock(new, fl); new->fl_file = fl->fl_file; -- GitLab From 10a560c14940b0296308b4eadd90a152204244ac Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 12 Aug 2014 08:03:49 -0400 Subject: [PATCH 329/528] locks: don't reuse file_lock in __posix_lock_file Currently in the case where a new file lock completely replaces the old one, we end up overwriting the existing lock with the new info. This means that we have to call fl_release_private inside i_lock. Change the code to instead copy the info to new_fl, insert that lock into the correct spot and then delete the old lock. In a later patch, we'll defer the freeing of the old lock until after the i_lock has been dropped. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: I0f8fac9dd2b22b7f82fbe0a0b8625d1d08dff428 --- fs/locks.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 50a8bedb4094..c45cf90cc77d 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1022,18 +1022,21 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str locks_delete_lock(before); continue; } - /* Replace the old lock with the new one. - * Wake up anybody waiting for the old one, - * as the change in lock type might satisfy - * their needs. + /* + * Replace the old lock with new_fl, and + * remove the old one. It's safe to do the + * insert here since we know that we won't be + * using new_fl later, and that the lock is + * just replacing an existing lock. */ - locks_wake_up_blocks(fl); - fl->fl_start = request->fl_start; - fl->fl_end = request->fl_end; - fl->fl_type = request->fl_type; - locks_release_private(fl); - locks_copy_private(fl, request); - request = fl; + error = -ENOLCK; + if (!new_fl) + goto out; + locks_copy_lock(new_fl, request); + request = new_fl; + new_fl = NULL; + locks_delete_lock(before); + locks_insert_lock(before, request); added = true; } } -- GitLab From 0a97271ebca042a7ab1dab9dc8331241ab6ad1ed Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 11 Aug 2014 14:20:31 -0400 Subject: [PATCH 330/528] locks: defer freeing locks in locks_delete_lock until after i_lock has been dropped In commit 72f98e72551fa (locks: turn lock_flocks into a spinlock), we moved from using the BKL to a global spinlock. With this change, we lost the ability to block in the fl_release_private operation. This is problematic for NFS (and probably some other filesystems as well). Add a new list_head argument to locks_delete_lock. If that argument is non-NULL, then queue any locks that we want to free to the list instead of freeing them. Then, add a new locks_dispose_list function that will walk such a list and call locks_free_lock on them after the i_lock has been dropped. Finally, change all of the callers of locks_delete_lock to pass in a list_head, except for lease_modify. That function can be called long after the i_lock has been acquired. Deferring the freeing of a lease after unlocking it in that function is non-trivial until we overhaul some of the spinlocking in the lease code. Currently though, no filesystem that sets fl_release_private supports leases, so this is not currently a problem. We'll eventually want to make the same change in the lease code, but it needs a lot more work before we can reasonably do so. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: I4cf87e5a665240180a2074b47dd90bdfd2f9dcc8 --- fs/locks.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index c45cf90cc77d..95ce86a02b16 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -247,6 +247,18 @@ void locks_free_lock(struct file_lock *fl) } EXPORT_SYMBOL(locks_free_lock); +static void +locks_dispose_list(struct list_head *dispose) +{ + struct file_lock *fl; + + while (!list_empty(dispose)) { + fl = list_first_entry(dispose, struct file_lock, fl_block); + list_del_init(&fl->fl_block); + locks_free_lock(fl); + } +} + void locks_init_lock(struct file_lock *fl) { memset(fl, 0, sizeof(struct file_lock)); @@ -651,12 +663,16 @@ static void locks_unlink_lock(struct file_lock **thisfl_p) * * Must be called with i_lock held! */ -static void locks_delete_lock(struct file_lock **thisfl_p) +static void locks_delete_lock(struct file_lock **thisfl_p, + struct list_head *dispose) { struct file_lock *fl = *thisfl_p; locks_unlink_lock(thisfl_p); - locks_free_lock(fl); + if (dispose) + list_add(&fl->fl_block, dispose); + else + locks_free_lock(fl); } /* Determine if lock sys_fl blocks lock caller_fl. Common functionality @@ -812,6 +828,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) struct inode * inode = file_inode(filp); int error = 0; int found = 0; + LIST_HEAD(dispose); if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { new_fl = locks_alloc_lock(); @@ -834,7 +851,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) if (request->fl_type == fl->fl_type) goto out; found = 1; - locks_delete_lock(before); + locks_delete_lock(before, &dispose); break; } @@ -881,6 +898,7 @@ out: spin_unlock(&inode->i_lock); if (new_fl) locks_free_lock(new_fl); + locks_dispose_list(&dispose); return error; } @@ -894,6 +912,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str struct file_lock **before; int error; bool added = false; + LIST_HEAD(dispose); /* * We may need two file_lock structures for this operation, @@ -989,7 +1008,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str else request->fl_end = fl->fl_end; if (added) { - locks_delete_lock(before); + locks_delete_lock(before, &dispose); continue; } request = fl; @@ -1019,7 +1038,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str * one (This may happen several times). */ if (added) { - locks_delete_lock(before); + locks_delete_lock(before, &dispose); continue; } /* @@ -1035,7 +1054,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str locks_copy_lock(new_fl, request); request = new_fl; new_fl = NULL; - locks_delete_lock(before); + locks_delete_lock(before, &dispose); locks_insert_lock(before, request); added = true; } @@ -1097,6 +1116,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str locks_free_lock(new_fl); if (new_fl2) locks_free_lock(new_fl2); + locks_dispose_list(&dispose); return error; } @@ -1272,7 +1292,7 @@ int lease_modify(struct file_lock **before, int arg) printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); fl->fl_fasync = NULL; } - locks_delete_lock(before); + locks_delete_lock(before, NULL); } return 0; } @@ -2333,6 +2353,7 @@ void locks_remove_file(struct file *filp) struct inode * inode = file_inode(filp); struct file_lock *fl; struct file_lock **before; + LIST_HEAD(dispose); if (!inode->i_flock) return; @@ -2378,12 +2399,13 @@ void locks_remove_file(struct file *filp) fl->fl_type, fl->fl_flags, fl->fl_start, fl->fl_end); - locks_delete_lock(before); + locks_delete_lock(before, &dispose); continue; } before = &fl->fl_next; } spin_unlock(&inode->i_lock); + locks_dispose_list(&dispose); } /** -- GitLab From 96f6ce22d26d3f73be7588db2af7ec760b2c2edf Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 11 Aug 2014 18:14:12 -0400 Subject: [PATCH 331/528] locks: move locks_free_lock calls in do_fcntl_add_lease outside spinlock There's no need to call locks_free_lock here while still holding the i_lock. Defer that until the lock has been dropped. Acked-by: J. Bruce Fields Signed-off-by: Jeff Layton Change-Id: Ied868e2214f4febbd2f6f358e36619ca0491e272 --- fs/locks.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 95ce86a02b16..ec4cc8f49da5 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1761,13 +1761,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) ret = fl; spin_lock(&inode->i_lock); error = __vfs_setlease(filp, arg, &ret); - if (error) { - spin_unlock(&inode->i_lock); - locks_free_lock(fl); - goto out_free_fasync; - } - if (ret != fl) - locks_free_lock(fl); + if (error) + goto out_unlock; + if (ret == fl) + fl = NULL; /* * fasync_insert_entry() returns the old entry if any. @@ -1779,9 +1776,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) new = NULL; error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); +out_unlock: spin_unlock(&inode->i_lock); - -out_free_fasync: + if (fl) + locks_free_lock(fl); if (new) fasync_free(new); return error; -- GitLab From fe6a3daa3b399c583e7f2b180205c6705d0853f9 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 9 Sep 2014 16:00:51 -0400 Subject: [PATCH 332/528] locks: pass correct "before" pointer to locks_unlink_lock in generic_add_lease The argument to locks_unlink_lock can't be just any pointer to a pointer. It must be a pointer to the fl_next field in the previous lock in the list. Cc: # v3.15+ Signed-off-by: Jeff Layton Reviewed-by: Christoph Hellwig Change-Id: Ie87738bd04e46aa3f73051b6b614e1f042f20606 --- fs/locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/locks.c b/fs/locks.c index ec4cc8f49da5..cd22a6454d09 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1619,7 +1619,7 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp smp_mb(); error = check_conflicting_open(dentry, arg); if (error) - locks_unlink_lock(flp); + locks_unlink_lock(before); out: if (is_deleg) mutex_unlock(&inode->i_mutex); -- GitLab From fe921d938166d629e5a9a50b093152a09d371aa2 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Fri, 22 Aug 2014 10:18:42 -0400 Subject: [PATCH 333/528] locks: Rename __locks_copy_lock() to locks_copy_conflock() Jeff advice, " Right now __locks_copy_lock is only used to copy conflocks. It would be good to rename that to something more distinct (i.e.locks_copy_conflock), to make it clear that we're generating a conflock there." v5: change order from 3/6 to 2/6 v4: new patch only renaming function name Signed-off-by: Kinglong Mee Signed-off-by: Jeff Layton Change-Id: If51105cdf8501e293bf33d39d042e7f740625f5b --- fs/locks.c | 10 +++++----- include/linux/fs.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index cd22a6454d09..9a682e80fb26 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -281,7 +281,7 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl) /* * Initialize a new lock from an existing file_lock structure. */ -void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) +void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) { new->fl_owner = fl->fl_owner; new->fl_pid = fl->fl_pid; @@ -293,14 +293,14 @@ void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) new->fl_ops = NULL; new->fl_lmops = NULL; } -EXPORT_SYMBOL(__locks_copy_lock); +EXPORT_SYMBOL(locks_copy_conflock); void locks_copy_lock(struct file_lock *new, struct file_lock *fl) { /* "new" must be a freshly-initialized lock */ WARN_ON_ONCE(new->fl_ops); - __locks_copy_lock(new, fl); + locks_copy_conflock(new, fl); new->fl_file = fl->fl_file; new->fl_ops = fl->fl_ops; new->fl_lmops = fl->fl_lmops; @@ -735,7 +735,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) break; } if (cfl) { - __locks_copy_lock(fl, cfl); + locks_copy_conflock(fl, cfl); if (cfl->fl_nspid) fl->fl_pid = pid_vnr(cfl->fl_nspid); } else @@ -941,7 +941,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str if (!posix_locks_conflict(request, fl)) continue; if (conflock) - __locks_copy_lock(conflock, fl); + locks_copy_conflock(conflock, fl); error = -EAGAIN; if (!(request->fl_flags & FL_SLEEP)) goto out; diff --git a/include/linux/fs.h b/include/linux/fs.h index b617be889dbc..a9e1c8d74e8d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1040,7 +1040,7 @@ void locks_free_lock(struct file_lock *fl); extern void locks_init_lock(struct file_lock *); extern struct file_lock * locks_alloc_lock(void); extern void locks_copy_lock(struct file_lock *, struct file_lock *); -extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); +extern void locks_copy_conflock(struct file_lock *, struct file_lock *); extern void locks_remove_posix(struct file *, fl_owner_t); extern void locks_remove_file(struct file *); extern void locks_release_private(struct file_lock *); @@ -1100,7 +1100,7 @@ static inline void locks_init_lock(struct file_lock *fl) return; } -static inline void __locks_copy_lock(struct file_lock *new, struct file_lock *fl) +static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) { return; } -- GitLab From 6cbbcab7488af4e37bffe7af9bd11816f2ddb020 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Fri, 22 Aug 2014 10:18:43 -0400 Subject: [PATCH 334/528] locks: New ops in lock_manager_operations for get/put owner NFSD or other lockmanager may increase the owner's reference, so adds two new options for copying and releasing owner. v5: change order from 2/6 to 3/6 v4: rename lm_copy_owner/lm_release_owner to lm_get_owner/lm_put_owner Reviewed-by: Jeff Layton Signed-off-by: Kinglong Mee Signed-off-by: Jeff Layton Change-Id: I9d579a111993f0c8163026fe519dca4d3e263930 --- fs/locks.c | 12 ++++++++++-- include/linux/fs.h | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 9a682e80fb26..d27f4d978e77 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -230,8 +230,12 @@ void locks_release_private(struct file_lock *fl) fl->fl_ops->fl_release_private(fl); fl->fl_ops = NULL; } - fl->fl_lmops = NULL; + if (fl->fl_lmops) { + if (fl->fl_lmops->lm_put_owner) + fl->fl_lmops->lm_put_owner(fl); + fl->fl_lmops = NULL; + } } EXPORT_SYMBOL_GPL(locks_release_private); @@ -274,8 +278,12 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl) fl->fl_ops->fl_copy_lock(new, fl); new->fl_ops = fl->fl_ops; } - if (fl->fl_lmops) + + if (fl->fl_lmops) { + if (fl->fl_lmops->lm_get_owner) + fl->fl_lmops->lm_get_owner(new, fl); new->fl_lmops = fl->fl_lmops; + } } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index a9e1c8d74e8d..e86a44a9b1cb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -942,6 +942,8 @@ struct file_lock_operations { struct lock_manager_operations { int (*lm_compare_owner)(struct file_lock *, struct file_lock *); unsigned long (*lm_owner_key)(struct file_lock *); + void (*lm_get_owner)(struct file_lock *, struct file_lock *); + void (*lm_put_owner)(struct file_lock *); void (*lm_notify)(struct file_lock *); /* unblock callback */ int (*lm_grant)(struct file_lock *, struct file_lock *, int); void (*lm_break)(struct file_lock *); -- GitLab From afcc6d718c46abd4c79b8dc106bd1e0d17ae1f69 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Fri, 22 Aug 2014 10:18:43 -0400 Subject: [PATCH 335/528] locks: Copy fl_lmops information for conflock in locks_copy_conflock() Commit d5b9026a67 ([PATCH] knfsd: locks: flag NFSv4-owned locks) using fl_lmops field in file_lock for checking nfsd4 lockowner. But, commit 1a747ee0cc (locks: don't call ->copy_lock methods on return of conflicting locks) causes the fl_lmops of conflock always be NULL. Also, commit 0996905f93 (lockd: posix_test_lock() should not call locks_copy_lock()) caused the fl_lmops of conflock always be NULL too. Make sure copy the private information by fl_copy_lock() in struct file_lock_operations, merge __locks_copy_lock() to fl_copy_lock(). Jeff advice, "Set fl_lmops on conflocks, but don't set fl_ops. fl_ops are superfluous, since they are callbacks into the filesystem. There should be no need to bother the filesystem at all with info in a conflock. But, lock _ownership_ matters for conflocks and that's indicated by the fl_lmops. So you really do want to copy the fl_lmops for conflocks I think." v5: add missing calling of locks_release_private() in nlmsvc_testlock() v4: only copy fl_lmops for conflock, don't copy fl_ops Signed-off-by: Kinglong Mee Signed-off-by: Jeff Layton Change-Id: Id1b508a43d4fae906eafa01daaf9c42984212978 --- fs/lockd/svclock.c | 1 + fs/locks.c | 36 ++++++++++++++++-------------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index ab798a88ec1d..c0978f0ffda5 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -586,6 +586,7 @@ conf_lock: conflock->fl.fl_type = lock->fl.fl_type; conflock->fl.fl_start = lock->fl.fl_start; conflock->fl.fl_end = lock->fl.fl_end; + locks_release_private(&lock->fl); ret = nlm_lck_denied; out: if (block) diff --git a/fs/locks.c b/fs/locks.c index d27f4d978e77..b1b8616892f6 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -271,21 +271,6 @@ void locks_init_lock(struct file_lock *fl) EXPORT_SYMBOL(locks_init_lock); -static void locks_copy_private(struct file_lock *new, struct file_lock *fl) -{ - if (fl->fl_ops) { - if (fl->fl_ops->fl_copy_lock) - fl->fl_ops->fl_copy_lock(new, fl); - new->fl_ops = fl->fl_ops; - } - - if (fl->fl_lmops) { - if (fl->fl_lmops->lm_get_owner) - fl->fl_lmops->lm_get_owner(new, fl); - new->fl_lmops = fl->fl_lmops; - } -} - /* * Initialize a new lock from an existing file_lock structure. */ @@ -298,8 +283,13 @@ void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) new->fl_type = fl->fl_type; new->fl_start = fl->fl_start; new->fl_end = fl->fl_end; + new->fl_lmops = fl->fl_lmops; new->fl_ops = NULL; - new->fl_lmops = NULL; + + if (fl->fl_lmops) { + if (fl->fl_lmops->lm_get_owner) + fl->fl_lmops->lm_get_owner(new, fl); + } } EXPORT_SYMBOL(locks_copy_conflock); @@ -309,11 +299,14 @@ void locks_copy_lock(struct file_lock *new, struct file_lock *fl) WARN_ON_ONCE(new->fl_ops); locks_copy_conflock(new, fl); + new->fl_file = fl->fl_file; new->fl_ops = fl->fl_ops; - new->fl_lmops = fl->fl_lmops; - locks_copy_private(new, fl); + if (fl->fl_ops) { + if (fl->fl_ops->fl_copy_lock) + fl->fl_ops->fl_copy_lock(new, fl); + } } EXPORT_SYMBOL(locks_copy_lock); @@ -1989,11 +1982,13 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) if (file_lock.fl_type != F_UNLCK) { error = posix_lock_to_flock(&flock, &file_lock); if (error) - goto out; + goto rel_priv; } error = -EFAULT; if (!copy_to_user(l, &flock, sizeof(flock))) error = 0; +rel_priv: + locks_release_private(&file_lock); out: return error; } @@ -2216,7 +2211,8 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) error = -EFAULT; if (!copy_to_user(l, &flock, sizeof(flock))) error = 0; - + + locks_release_private(&file_lock); out: return error; } -- GitLab From 5c16260c791c565048db8466a3b63da7246a9be1 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 22 Aug 2014 10:18:44 -0400 Subject: [PATCH 336/528] locks: remove lock_may_read and lock_may_write There are no callers of these functions. Signed-off-by: Jeff Layton Change-Id: I122538f7c77ffd749a469bd205af1ba6fbbff6b2 --- fs/locks.c | 80 ---------------------------------------------- include/linux/fs.h | 14 -------- 2 files changed, 94 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index b1b8616892f6..52eefa2cf066 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2606,86 +2606,6 @@ static int __init proc_locks_init(void) module_init(proc_locks_init); #endif -/** - * lock_may_read - checks that the region is free of locks - * @inode: the inode that is being read - * @start: the first byte to read - * @len: the number of bytes to read - * - * Emulates Windows locking requirements. Whole-file - * mandatory locks (share modes) can prohibit a read and - * byte-range POSIX locks can prohibit a read if they overlap. - * - * N.B. this function is only ever called - * from knfsd and ownership of locks is never checked. - */ -int lock_may_read(struct inode *inode, loff_t start, unsigned long len) -{ - struct file_lock *fl; - int result = 1; - - spin_lock(&inode->i_lock); - for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { - if (IS_POSIX(fl)) { - if (fl->fl_type == F_RDLCK) - continue; - if ((fl->fl_end < start) || (fl->fl_start > (start + len))) - continue; - } else if (IS_FLOCK(fl)) { - if (!(fl->fl_type & LOCK_MAND)) - continue; - if (fl->fl_type & LOCK_READ) - continue; - } else - continue; - result = 0; - break; - } - spin_unlock(&inode->i_lock); - return result; -} - -EXPORT_SYMBOL(lock_may_read); - -/** - * lock_may_write - checks that the region is free of locks - * @inode: the inode that is being written - * @start: the first byte to write - * @len: the number of bytes to write - * - * Emulates Windows locking requirements. Whole-file - * mandatory locks (share modes) can prohibit a write and - * byte-range POSIX locks can prohibit a write if they overlap. - * - * N.B. this function is only ever called - * from knfsd and ownership of locks is never checked. - */ -int lock_may_write(struct inode *inode, loff_t start, unsigned long len) -{ - struct file_lock *fl; - int result = 1; - - spin_lock(&inode->i_lock); - for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { - if (IS_POSIX(fl)) { - if ((fl->fl_end < start) || (fl->fl_start > (start + len))) - continue; - } else if (IS_FLOCK(fl)) { - if (!(fl->fl_type & LOCK_MAND)) - continue; - if (fl->fl_type & LOCK_WRITE) - continue; - } else - continue; - result = 0; - break; - } - spin_unlock(&inode->i_lock); - return result; -} - -EXPORT_SYMBOL(lock_may_write); - static int __init filelock_init(void) { int i; diff --git a/include/linux/fs.h b/include/linux/fs.h index e86a44a9b1cb..87ef41a50d9a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1059,8 +1059,6 @@ extern void lease_get_mtime(struct inode *, struct timespec *time); extern int generic_setlease(struct file *, long, struct file_lock **); extern int vfs_setlease(struct file *, long, struct file_lock **); extern int lease_modify(struct file_lock **, int); -extern int lock_may_read(struct inode *, loff_t start, unsigned long count); -extern int lock_may_write(struct inode *, loff_t start, unsigned long count); #else /* !CONFIG_FILE_LOCKING */ static inline int fcntl_getlk(struct file *file, unsigned int cmd, struct flock __user *user) @@ -1191,18 +1189,6 @@ static inline int lease_modify(struct file_lock **before, int arg) { return -EINVAL; } - -static inline int lock_may_read(struct inode *inode, loff_t start, - unsigned long len) -{ - return 1; -} - -static inline int lock_may_write(struct inode *inode, loff_t start, - unsigned long len) -{ - return 1; -} #endif /* !CONFIG_FILE_LOCKING */ -- GitLab From 9b5ad222132302f245b1f014e3da5e048f3113f3 Mon Sep 17 00:00:00 2001 From: TARKZiM Date: Tue, 22 Jun 2021 18:31:33 +0800 Subject: [PATCH 337/528] defconfig: kitakami: Enable CPU frequency statistics --- arch/arm64/configs/kitakami_ivy_defconfig | 2 ++ arch/arm64/configs/kitakami_satsuki_defconfig | 2 ++ arch/arm64/configs/kitakami_sumire_defconfig | 2 ++ arch/arm64/configs/kitakami_suzuran_defconfig | 2 ++ 4 files changed, 8 insertions(+) diff --git a/arch/arm64/configs/kitakami_ivy_defconfig b/arch/arm64/configs/kitakami_ivy_defconfig index 548a432ac2ce..b5a2dd791130 100644 --- a/arch/arm64/configs/kitakami_ivy_defconfig +++ b/arch/arm64/configs/kitakami_ivy_defconfig @@ -63,6 +63,8 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y CONFIG_CPU_BOOST=y CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y diff --git a/arch/arm64/configs/kitakami_satsuki_defconfig b/arch/arm64/configs/kitakami_satsuki_defconfig index 3aabd0ea8d40..95a13847a93b 100644 --- a/arch/arm64/configs/kitakami_satsuki_defconfig +++ b/arch/arm64/configs/kitakami_satsuki_defconfig @@ -72,6 +72,8 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y CONFIG_CPU_BOOST=y CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index ea5c0d24cbc9..4c761bc52c2e 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -73,6 +73,8 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y CONFIG_CPU_BOOST=y CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y diff --git a/arch/arm64/configs/kitakami_suzuran_defconfig b/arch/arm64/configs/kitakami_suzuran_defconfig index 15e660cc6a8e..a9d2831e6987 100644 --- a/arch/arm64/configs/kitakami_suzuran_defconfig +++ b/arch/arm64/configs/kitakami_suzuran_defconfig @@ -73,6 +73,8 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y CONFIG_CPU_BOOST=y CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y -- GitLab From f7f1d07e21de0e77c5642c544085fac740447992 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Tue, 6 Aug 2019 16:40:15 +0800 Subject: [PATCH 338/528] HID: hiddev: do cleanup in failure of opening a device Undo what we did for opening before releasing the memory slice. Reported-by: syzbot Cc: Andrey Konovalov Signed-off-by: Hillf Danton Signed-off-by: Jiri Kosina (cherry picked from commit 6d4472d7bec39917b54e4e80245784ea5d60ce49) (cherry picked from commit d0d80b92f786268f0482f37824b5785917cfc2e9) --- drivers/hid/usbhid/hiddev.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 6b1ae7f50804..47bbc2b90298 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -321,6 +321,10 @@ static int hiddev_open(struct inode *inode, struct file *file) return 0; bail_unlock: mutex_unlock(&hiddev->existancelock); + + spin_lock_irq(&list->hiddev->list_lock); + list_del(&list->node); + spin_unlock_irq(&list->hiddev->list_lock); bail: file->private_data = NULL; vfree(list); -- GitLab From dee55cb2e6ae20a635475af73d9ff63d4bd72ea7 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Tue, 6 Aug 2019 16:38:58 +0800 Subject: [PATCH 339/528] HID: hiddev: avoid opening a disconnected device syzbot found the following crash on: HEAD commit: e96407b4 usb-fuzzer: main usb gadget fuzzer driver git tree: https://github.com/google/kasan.git usb-fuzzer console output: https://syzkaller.appspot.com/x/log.txt?x=147ac20c600000 kernel config: https://syzkaller.appspot.com/x/.config?x=792eb47789f57810 dashboard link: https://syzkaller.appspot.com/bug?extid=62a1e04fd3ec2abf099e compiler: gcc (GCC) 9.0.0 20181231 (experimental) ================================================================== BUG: KASAN: use-after-free in __lock_acquire+0x302a/0x3b50 kernel/locking/lockdep.c:3753 Read of size 8 at addr ffff8881cf591a08 by task syz-executor.1/26260 CPU: 1 PID: 26260 Comm: syz-executor.1 Not tainted 5.3.0-rc2+ #24 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0xca/0x13e lib/dump_stack.c:113 print_address_description+0x6a/0x32c mm/kasan/report.c:351 __kasan_report.cold+0x1a/0x33 mm/kasan/report.c:482 kasan_report+0xe/0x12 mm/kasan/common.c:612 __lock_acquire+0x302a/0x3b50 kernel/locking/lockdep.c:3753 lock_acquire+0x127/0x320 kernel/locking/lockdep.c:4412 __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline] _raw_spin_lock_irqsave+0x32/0x50 kernel/locking/spinlock.c:159 hiddev_release+0x82/0x520 drivers/hid/usbhid/hiddev.c:221 __fput+0x2d7/0x840 fs/file_table.c:280 task_work_run+0x13f/0x1c0 kernel/task_work.c:113 exit_task_work include/linux/task_work.h:22 [inline] do_exit+0x8ef/0x2c50 kernel/exit.c:878 do_group_exit+0x125/0x340 kernel/exit.c:982 get_signal+0x466/0x23d0 kernel/signal.c:2728 do_signal+0x88/0x14e0 arch/x86/kernel/signal.c:815 exit_to_usermode_loop+0x1a2/0x200 arch/x86/entry/common.c:159 prepare_exit_to_usermode arch/x86/entry/common.c:194 [inline] syscall_return_slowpath arch/x86/entry/common.c:274 [inline] do_syscall_64+0x45f/0x580 arch/x86/entry/common.c:299 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x459829 Code: fd b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 cb b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f75b2a6ccf8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca RAX: fffffffffffffe00 RBX: 000000000075c078 RCX: 0000000000459829 RDX: 0000000000000000 RSI: 0000000000000080 RDI: 000000000075c078 RBP: 000000000075c070 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 000000000075c07c R13: 00007ffcdfe1023f R14: 00007f75b2a6d9c0 R15: 000000000075c07c Allocated by task 104: save_stack+0x1b/0x80 mm/kasan/common.c:69 set_track mm/kasan/common.c:77 [inline] __kasan_kmalloc mm/kasan/common.c:487 [inline] __kasan_kmalloc.constprop.0+0xbf/0xd0 mm/kasan/common.c:460 kmalloc include/linux/slab.h:552 [inline] kzalloc include/linux/slab.h:748 [inline] hiddev_connect+0x242/0x5b0 drivers/hid/usbhid/hiddev.c:900 hid_connect+0x239/0xbb0 drivers/hid/hid-core.c:1882 hid_hw_start drivers/hid/hid-core.c:1981 [inline] hid_hw_start+0xa2/0x130 drivers/hid/hid-core.c:1972 appleir_probe+0x13e/0x1a0 drivers/hid/hid-appleir.c:308 hid_device_probe+0x2be/0x3f0 drivers/hid/hid-core.c:2209 really_probe+0x281/0x650 drivers/base/dd.c:548 driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 __device_attach+0x217/0x360 drivers/base/dd.c:882 bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 device_add+0xae6/0x16f0 drivers/base/core.c:2114 hid_add_device+0x33c/0x990 drivers/hid/hid-core.c:2365 usbhid_probe+0xa81/0xfa0 drivers/hid/usbhid/hid-core.c:1386 usb_probe_interface+0x305/0x7a0 drivers/usb/core/driver.c:361 really_probe+0x281/0x650 drivers/base/dd.c:548 driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 __device_attach+0x217/0x360 drivers/base/dd.c:882 bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 device_add+0xae6/0x16f0 drivers/base/core.c:2114 usb_set_configuration+0xdf6/0x1670 drivers/usb/core/message.c:2023 generic_probe+0x9d/0xd5 drivers/usb/core/generic.c:210 usb_probe_device+0x99/0x100 drivers/usb/core/driver.c:266 really_probe+0x281/0x650 drivers/base/dd.c:548 driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 __device_attach+0x217/0x360 drivers/base/dd.c:882 bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 device_add+0xae6/0x16f0 drivers/base/core.c:2114 usb_new_device.cold+0x6a4/0xe79 drivers/usb/core/hub.c:2536 hub_port_connect drivers/usb/core/hub.c:5098 [inline] hub_port_connect_change drivers/usb/core/hub.c:5213 [inline] port_event drivers/usb/core/hub.c:5359 [inline] hub_event+0x1b5c/0x3640 drivers/usb/core/hub.c:5441 process_one_work+0x92b/0x1530 kernel/workqueue.c:2269 worker_thread+0x96/0xe20 kernel/workqueue.c:2415 kthread+0x318/0x420 kernel/kthread.c:255 ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352 Freed by task 104: save_stack+0x1b/0x80 mm/kasan/common.c:69 set_track mm/kasan/common.c:77 [inline] __kasan_slab_free+0x130/0x180 mm/kasan/common.c:449 slab_free_hook mm/slub.c:1423 [inline] slab_free_freelist_hook mm/slub.c:1470 [inline] slab_free mm/slub.c:3012 [inline] kfree+0xe4/0x2f0 mm/slub.c:3953 hiddev_connect.cold+0x45/0x5c drivers/hid/usbhid/hiddev.c:914 hid_connect+0x239/0xbb0 drivers/hid/hid-core.c:1882 hid_hw_start drivers/hid/hid-core.c:1981 [inline] hid_hw_start+0xa2/0x130 drivers/hid/hid-core.c:1972 appleir_probe+0x13e/0x1a0 drivers/hid/hid-appleir.c:308 hid_device_probe+0x2be/0x3f0 drivers/hid/hid-core.c:2209 really_probe+0x281/0x650 drivers/base/dd.c:548 driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 __device_attach+0x217/0x360 drivers/base/dd.c:882 bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 device_add+0xae6/0x16f0 drivers/base/core.c:2114 hid_add_device+0x33c/0x990 drivers/hid/hid-core.c:2365 usbhid_probe+0xa81/0xfa0 drivers/hid/usbhid/hid-core.c:1386 usb_probe_interface+0x305/0x7a0 drivers/usb/core/driver.c:361 really_probe+0x281/0x650 drivers/base/dd.c:548 driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 __device_attach+0x217/0x360 drivers/base/dd.c:882 bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 device_add+0xae6/0x16f0 drivers/base/core.c:2114 usb_set_configuration+0xdf6/0x1670 drivers/usb/core/message.c:2023 generic_probe+0x9d/0xd5 drivers/usb/core/generic.c:210 usb_probe_device+0x99/0x100 drivers/usb/core/driver.c:266 really_probe+0x281/0x650 drivers/base/dd.c:548 driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 __device_attach+0x217/0x360 drivers/base/dd.c:882 bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 device_add+0xae6/0x16f0 drivers/base/core.c:2114 usb_new_device.cold+0x6a4/0xe79 drivers/usb/core/hub.c:2536 hub_port_connect drivers/usb/core/hub.c:5098 [inline] hub_port_connect_change drivers/usb/core/hub.c:5213 [inline] port_event drivers/usb/core/hub.c:5359 [inline] hub_event+0x1b5c/0x3640 drivers/usb/core/hub.c:5441 process_one_work+0x92b/0x1530 kernel/workqueue.c:2269 worker_thread+0x96/0xe20 kernel/workqueue.c:2415 kthread+0x318/0x420 kernel/kthread.c:255 ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352 The buggy address belongs to the object at ffff8881cf591900 which belongs to the cache kmalloc-512 of size 512 The buggy address is located 264 bytes inside of 512-byte region [ffff8881cf591900, ffff8881cf591b00) The buggy address belongs to the page: page:ffffea00073d6400 refcount:1 mapcount:0 mapping:ffff8881da002500 index:0x0 compound_mapcount: 0 flags: 0x200000000010200(slab|head) raw: 0200000000010200 0000000000000000 0000000100000001 ffff8881da002500 raw: 0000000000000000 00000000000c000c 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff8881cf591900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8881cf591980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb > ffff8881cf591a00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff8881cf591a80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8881cf591b00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ================================================================== In order to avoid opening a disconnected device, we need to check exist again after acquiring the existance lock, and bail out if necessary. Reported-by: syzbot Cc: Andrey Konovalov Signed-off-by: Hillf Danton Signed-off-by: Jiri Kosina (cherry picked from commit 9c09b214f30e3c11f9b0b03f89442df03643794d) (cherry picked from commit 641831facd8ae8701e8723c0ae0c4b36bfb753bf) --- drivers/hid/usbhid/hiddev.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 47bbc2b90298..5e31f97c5bb9 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -307,6 +307,14 @@ static int hiddev_open(struct inode *inode, struct file *file) spin_unlock_irq(&list->hiddev->list_lock); mutex_lock(&hiddev->existancelock); + /* + * recheck exist with existance lock held to + * avoid opening a disconnected device + */ + if (!list->hiddev->exist) { + res = -ENODEV; + goto bail_unlock; + } if (!list->hiddev->open++) if (list->hiddev->exist) { struct hid_device *hid = hiddev->hid; -- GitLab From 9d20f1ecf7deb31389512604ab51d7733b9654cc Mon Sep 17 00:00:00 2001 From: Mike B Date: Wed, 23 Jun 2021 20:08:29 +0200 Subject: [PATCH 340/528] net: packet: af_packet: backported patch not - replaced code not properly removed --- net/packet/af_packet.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 7899cf1c2d05..2caca1d30053 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1393,11 +1393,6 @@ static struct packet_fanout *fanout_release(struct sock *sk) dev_remove_pack(&f->prot_hook); kfree(f); } - if (atomic_dec_and_test(&f->sk_ref)) - list_del(&f->list); - else - f = NULL; - } mutex_unlock(&fanout_mutex); return f; -- GitLab From ee6fe233dc118cd2a63c171419f67e1b2465c561 Mon Sep 17 00:00:00 2001 From: Mike B Date: Wed, 23 Jun 2021 20:11:31 +0200 Subject: [PATCH 341/528] drivers: platform: msm: dont mutex_init twice, and certainly not after calling ipa_qmi_init --- drivers/platform/msm/ipa/rmnet_ipa.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/msm/ipa/rmnet_ipa.c b/drivers/platform/msm/ipa/rmnet_ipa.c index c6ea9dbd373b..ee42b833a8c2 100644 --- a/drivers/platform/msm/ipa/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/rmnet_ipa.c @@ -2622,10 +2622,8 @@ static int __init ipa_wwan_init(void) atomic_set(&is_ssr, 0); mutex_init(&add_mux_channel_lock); - ipa_qmi_init(); - mutex_init(&add_mux_channel_lock); /* Register for Modem SSR */ subsys = subsys_notif_register_notifier(SUBSYS_MODEM, &ssr_notifier); if (!IS_ERR(subsys)) -- GitLab From 45f7b40135bc48a48b9d1c6caffdfa2869bd6d50 Mon Sep 17 00:00:00 2001 From: Saranya Chidura Date: Wed, 26 Jul 2017 17:37:17 +0530 Subject: [PATCH 342/528] coresight: tmc: Fix the unbalanced lock in tmc_read() 'commit 734aabed17090: ("coresight: tmc: Fix use after free issue with tmc read")' adds lock in tmc_read() to fix race condition seen in reading tmc buffer and enabling the device.But commit has unbalanced lock. This patch fixes the lock. Bug: 64453422 Change-Id: Iaf3ecd83ef5af346725885ea2c84c4185f1a1c50 Signed-off-by: Saranya Chidura (cherry picked from commit 0914fefdd4bfb8b0d9dd25ca5c41fc7e32a7a5c2) --- drivers/coresight/coresight-tmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c index 9d4b9b2f7417..a15acd12084a 100644 --- a/drivers/coresight/coresight-tmc.c +++ b/drivers/coresight/coresight-tmc.c @@ -1576,7 +1576,7 @@ out: dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", __func__, len, (int) (drvdata->size - *ppos)); - mutex_lock(&drvdata->usb_lock); + mutex_unlock(&drvdata->usb_lock); return len; } -- GitLab From b09077a083f2c2792cec3dd5304f4c1d4f0ca08d Mon Sep 17 00:00:00 2001 From: Mike B Date: Wed, 23 Jun 2021 21:15:39 +0200 Subject: [PATCH 343/528] net: packet: af_packet: missing bracket after backport --- net/packet/af_packet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 2caca1d30053..82f1e5e6087e 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1393,6 +1393,7 @@ static struct packet_fanout *fanout_release(struct sock *sk) dev_remove_pack(&f->prot_hook); kfree(f); } + } mutex_unlock(&fanout_mutex); return f; -- GitLab From 3f1e0f4e809119d314f5434153e8a518af561373 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 3 Jun 2013 22:27:17 +0200 Subject: [PATCH 344/528] pwm: devm: alloc correct pointer size The allocated object should be the size of what the pointer is pointing to and not the size of the pointer itself. Signed-off-by: Wolfram Sang Reviewed-by: Andy Shevchenko Signed-off-by: Thierry Reding (cherry picked from commit 9fd6e11245a66bf9cac850309a689c3fdeb4f3ba) --- drivers/pwm/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 32221cb0cbe7..0cf0f65eb037 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -694,7 +694,7 @@ struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id) { struct pwm_device **ptr, *pwm; - ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL); + ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); @@ -724,7 +724,7 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, { struct pwm_device **ptr, *pwm; - ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL); + ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); -- GitLab From 6ef8281f7555f065c29ddca4b6e68b7de17f66e7 Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Mon, 20 Jul 2020 21:14:33 -0700 Subject: [PATCH 345/528] binder: fix UAF when releasing todo list When releasing a thread todo list when tearing down a binder_proc, the following race was possible which could result in a use-after-free: 1. Thread 1: enter binder_release_work from binder_thread_release 2. Thread 2: binder_update_ref_for_handle() -> binder_dec_node_ilocked() 3. Thread 2: dec nodeA --> 0 (will free node) 4. Thread 1: ACQ inner_proc_lock 5. Thread 2: block on inner_proc_lock 6. Thread 1: dequeue work (BINDER_WORK_NODE, part of nodeA) 7. Thread 1: REL inner_proc_lock 8. Thread 2: ACQ inner_proc_lock 9. Thread 2: todo list cleanup, but work was already dequeued 10. Thread 2: free node 11. Thread 2: REL inner_proc_lock 12. Thread 1: deref w->type (UAF) The problem was that for a BINDER_WORK_NODE, the binder_work element must not be accessed after releasing the inner_proc_lock while processing the todo list elements since another thread might be handling a deref on the node containing the binder_work element leading to the node being freed. Bug: 161151868 Test: manual Signed-off-by: Todd Kjos Change-Id: I4ae752abfe1aa38872be6f266ddd271802952625 (cherry picked from commit d4bb57fb70a3b1f303d7c7f08f3517aeb1b692c2) --- drivers/android/binder.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 14aa274a3865..5af762daa1b9 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -291,7 +291,7 @@ struct binder_device { struct binder_work { struct list_head entry; - enum { + enum binder_work_type { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, BINDER_WORK_RETURN_ERROR, @@ -930,27 +930,6 @@ static struct binder_work *binder_dequeue_work_head_ilocked( return w; } -/** - * binder_dequeue_work_head() - Dequeues the item at head of list - * @proc: binder_proc associated with list - * @list: list to dequeue head - * - * Removes the head of the list if there are items on the list - * - * Return: pointer dequeued binder_work, NULL if list was empty - */ -static struct binder_work *binder_dequeue_work_head( - struct binder_proc *proc, - struct list_head *list) -{ - struct binder_work *w; - - binder_inner_proc_lock(proc); - w = binder_dequeue_work_head_ilocked(list); - binder_inner_proc_unlock(proc); - return w; -} - static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); static void binder_free_thread(struct binder_thread *thread); @@ -4470,13 +4449,17 @@ static void binder_release_work(struct binder_proc *proc, struct list_head *list) { struct binder_work *w; + enum binder_work_type wtype; while (1) { - w = binder_dequeue_work_head(proc, list); + binder_inner_proc_lock(proc); + w = binder_dequeue_work_head_ilocked(list); + wtype = w ? w->type : 0; + binder_inner_proc_unlock(proc); if (!w) return; - switch (w->type) { + switch (wtype) { case BINDER_WORK_TRANSACTION: { struct binder_transaction *t; @@ -4510,9 +4493,11 @@ static void binder_release_work(struct binder_proc *proc, kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); } break; + case BINDER_WORK_NODE: + break; default: pr_err("unexpected work type, %d, not freed\n", - w->type); + wtype); break; } } -- GitLab From bfdb5d4eaf3a4da57320a4d31fc7c8a80d5970b9 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 7 Sep 2018 10:01:46 +0200 Subject: [PATCH 346/528] UPSTREAM: android: binder: use kstrdup instead of open-coding it Signed-off-by: Rasmus Villemoes Bug: 136497735 Change-Id: I545073facdb76ea12accfc7bfa4738f2e3bf0b28 (cherry picked from commit 6b6642dadd685af885367d6e30f18553e2a23b22) Signed-off-by: Hridya Valsaraju (cherry picked from commit 760b8036e6921aa65649c3cb3934e33e2ad5f71f) --- drivers/android/binder.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 5af762daa1b9..4c42ac799050 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -6042,12 +6042,11 @@ static int __init binder_init(void) * Copy the module_parameter string, because we don't want to * tokenize it in-place. */ - device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); + device_names = kstrdup(binder_devices_param, GFP_KERNEL); if (!device_names) { ret = -ENOMEM; goto err_alloc_device_names_failed; } - strcpy(device_names, binder_devices_param); device_tmp = device_names; while ((device_name = strsep(&device_tmp, ","))) { -- GitLab From 40ebeaa0ff39db8b489fa5231714d21d404d7721 Mon Sep 17 00:00:00 2001 From: Marco Ballesio Date: Fri, 8 Jan 2021 08:06:32 -0800 Subject: [PATCH 347/528] binder: don't log on EINTR binder_wait_for_work used to return -ERESTARTSYS if interrupted by a signal. This error wasn't logged to avoid spamming the console. After the return value changed to -EINTR to better conform to the kernel API, the logging portion wasn't modified. Filter EINTR from binder error logs. Test: verified that the console isn't spammed anymore Bug: 172330837 Signed-off-by: Marco Ballesio Change-Id: Ie7789bdbf5f0b3b0d55793d4f147c395de2c6641 (cherry picked from commit 798e399991f834762b2f5cb8454d51e184eb51c2) --- drivers/android/binder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 4c42ac799050..537a92a1520f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5029,7 +5029,7 @@ err: if (thread) thread->looper_need_return = false; wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); - if (ret && ret != -ERESTARTSYS) + if (ret && ret != -EINTR) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); err_unlocked: trace_binder_ioctl_done(ret); -- GitLab From a0460db08cfe2506eac02b3dd58843c7c0387c5d Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 3 Jul 2021 12:35:37 +0200 Subject: [PATCH 348/528] drivers: android: binder_alloc: set mm_struct to NULL --- drivers/android/binder_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 0ea0233fb88d..ee5e2738401f 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -188,7 +188,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, void *page_addr; unsigned long user_page_addr; struct page **page; - struct mm_struct *mm; + struct mm_struct *mm = NULL; binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, "%d: %s pages %pK-%pK\n", alloc->pid, -- GitLab From a781649baec1fcd658e56a5b9b820d68de9e4623 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Fri, 18 Oct 2019 22:56:31 +0200 Subject: [PATCH 349/528] binder: Handle start==NULL in binder_update_page_range() commit 2a9edd056ed4fbf9d2e797c3fc06335af35bccc4 upstream. The old loop wouldn't stop when reaching `start` if `start==NULL`, instead continuing backwards to index -1 and crashing. Luckily you need to be highly privileged to map things at NULL, so it's not a big problem. Fix it by adjusting the loop so that the loop variable is always in bounds. This patch is deliberately minimal to simplify backporting, but IMO this function could use a refactor. The jump labels in the second loop body are horrible (the error gotos should be jumping to free_range instead), and both loops would look nicer if they just iterated upwards through indices. And the up_read()+mmput() shouldn't be duplicated like that. Cc: stable@vger.kernel.org Fixes: 457b9a6f09f0 ("Staging: android: add binder driver") Signed-off-by: Jann Horn Acked-by: Christian Brauner Link: https://lore.kernel.org/r/20191018205631.248274-3-jannh@google.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit af0174a63c45bd25c7fd7ece5f93e5f166256d1c) --- drivers/android/binder_alloc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index ee5e2738401f..58f78160f0a3 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -261,8 +261,8 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, return 0; free_range: - for (page_addr = end - PAGE_SIZE; page_addr >= start; - page_addr -= PAGE_SIZE) { + + for (page_addr = end - PAGE_SIZE; 1; page_addr -= PAGE_SIZE) { page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE]; if (vma) zap_page_range(vma, (uintptr_t)page_addr + @@ -273,7 +273,9 @@ err_map_kernel_failed: __free_page(*page); *page = NULL; err_alloc_page_failed: - ; +err_page_ptr_cleared: + if (page_addr == start) + break; } err_no_vma: if (mm) { -- GitLab From 77bcc89b09291c3a0763cc434c0744278ede445a Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 3 Jul 2021 13:40:43 +0200 Subject: [PATCH 350/528] binder: binder_alloc: Fix warning and add check after 'af0174a63c45 Handle start==NULL in binder_update_page_range' --- drivers/android/binder_alloc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 58f78160f0a3..67fb7bc6147e 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -235,6 +235,10 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, alloc->pid, page_addr); goto err_alloc_page_failed; } + + if (WARN_ON(!vma)) + goto err_page_ptr_cleared; + ret = map_kernel_range_noflush((unsigned long)page_addr, PAGE_SIZE, PAGE_KERNEL, page); flush_cache_vmap((unsigned long)page_addr, -- GitLab From e3baad7528fb8b30e29d3695b99c7293f84c79bd Mon Sep 17 00:00:00 2001 From: Mike B Date: Sat, 3 Jul 2021 15:53:04 +0200 Subject: [PATCH 351/528] binder: set module_param_named according to modern binders --- drivers/android/binder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 537a92a1520f..fd846b7e6a4b 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -148,7 +148,7 @@ static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | module_param_named(debug_mask, binder_debug_mask, uint, 0644); static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; -module_param_named(devices, binder_devices_param, charp, S_IRUGO); +module_param_named(devices, binder_devices_param, charp, 0444); static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait); static int binder_stop_on_user_error; -- GitLab From 8d213d08d3d14c3b53f395c3824a3e6a65539de7 Mon Sep 17 00:00:00 2001 From: threader Date: Sat, 3 Jul 2021 17:25:59 +0200 Subject: [PATCH 352/528] binder: I assumed the binder was from CAF but infact it is was a 'shamu'(https://github.com/LineageOS/android_kernel_moto_shamu.git (lineage-17.1) based binder to begin with --- drivers/android/Kconfig | 2 +- drivers/android/Makefile | 4 ++-- drivers/android/binder.c | 2 +- drivers/android/binder.h | 2 +- drivers/android/binder_alloc.c | 2 +- drivers/android/binder_alloc.h | 2 +- drivers/android/binder_alloc_selftest.c | 2 +- drivers/android/binder_trace.h | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index a8e55b756d7d..2a1bc931d471 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -1,5 +1,5 @@ menu "Android" - + config ANDROID bool "Android Drivers" ---help--- diff --git a/drivers/android/Makefile b/drivers/android/Makefile index 0eae34092aca..d575ff2f9026 100644 --- a/drivers/android/Makefile +++ b/drivers/android/Makefile @@ -1,4 +1,4 @@ ccflags-y += -I$(src) # needed for trace events - + obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o -obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o \ No newline at end of file +obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o diff --git a/drivers/android/binder.c b/drivers/android/binder.c index fd846b7e6a4b..d8dab735ce8d 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1,4 +1,4 @@ -/* binder.c + /* binder.c * * Android IPC Subsystem * diff --git a/drivers/android/binder.h b/drivers/android/binder.h index cb2cb7cf7a15..e76ed664c69a 100644 --- a/drivers/android/binder.h +++ b/drivers/android/binder.h @@ -1,4 +1,4 @@ -/* + /* * Copyright (C) 2008 Google, Inc. * * Based on, but no longer compatible with, the original diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 67fb7bc6147e..3326c89ed97a 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -1,4 +1,4 @@ -/* binder_alloc.c + /* binder_alloc.c * * Android IPC Subsystem * diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 4dabd77369d1..838e04425c03 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -1,4 +1,4 @@ -/* + /* * Copyright (C) 2017 Google, Inc. * * This software is licensed under the terms of the GNU General Public diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c index 0bf72079a9da..9a1ffda7c307 100644 --- a/drivers/android/binder_alloc_selftest.c +++ b/drivers/android/binder_alloc_selftest.c @@ -1,4 +1,4 @@ -/* binder_alloc_selftest.c + /* binder_alloc_selftest.c * * Android IPC Subsystem * diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h index 7d8beb77f532..ef9f4baef02c 100644 --- a/drivers/android/binder_trace.h +++ b/drivers/android/binder_trace.h @@ -1,4 +1,4 @@ -/* + /* * Copyright (C) 2012 Google, Inc. * * This software is licensed under the terms of the GNU General Public -- GitLab From 57a7a01b60f7bd4ff083d3ab55ca1080ffd89ddf Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Mon, 27 Jul 2020 14:04:24 +0200 Subject: [PATCH 353/528] UPSTREAM: binder: Prevent context manager from incrementing ref 0 Binder is designed such that a binder_proc never has references to itself. If this rule is violated, memory corruption can occur when a process sends a transaction to itself; see e.g. . There is a remaining edgecase through which such a transaction-to-self can still occur from the context of a task with BINDER_SET_CONTEXT_MGR access: - task A opens /dev/binder twice, creating binder_proc instances P1 and P2 - P1 becomes context manager - P2 calls ACQUIRE on the magic handle 0, allocating index 0 in its handle table - P1 dies (by closing the /dev/binder fd and waiting a bit) - P2 becomes context manager - P2 calls ACQUIRE on the magic handle 0, allocating index 1 in its handle table [this triggers a warning: "binder: 1974:1974 tried to acquire reference to desc 0, got 1 instead"] - task B opens /dev/binder once, creating binder_proc instance P3 - P3 calls P2 (via magic handle 0) with (void*)1 as argument (two-way transaction) - P2 receives the handle and uses it to call P3 (two-way transaction) - P3 calls P2 (via magic handle 0) (two-way transaction) - P2 calls P2 (via handle 1) (two-way transaction) And then, if P2 does *NOT* accept the incoming transaction work, but instead closes the binder fd, we get a crash. Solve it by preventing the context manager from using ACQUIRE on ref 0. There shouldn't be any legitimate reason for the context manager to do that. Additionally, print a warning if someone manages to find another way to trigger a transaction-to-self bug in the future. Cc: stable@vger.kernel.org Fixes: 457b9a6f09f0 ("Staging: android: add binder driver") Acked-by: Todd Kjos Signed-off-by: Jann Horn Reviewed-by: Martijn Coenen Link: https://lore.kernel.org/r/20200727120424.1627555-1-jannh@google.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 4b836a1426cb0f1ef2a6e211d7e553221594f8fc) Signed-off-by: Greg Kroah-Hartman Change-Id: Id582f18932f3013be62fdd662d0a559e05eb10f8 (cherry picked from commit 2668c840a4d389a3c65b75fe1b4aa0feaeecb019) --- drivers/android/binder.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index d8dab735ce8d..ce89b5fc8ca1 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3023,6 +3023,12 @@ static void binder_transaction(struct binder_proc *proc, goto err_dead_binder; } e->to_node = target_node->debug_id; + if (WARN_ON(proc == target_proc)) { + return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; + goto err_invalid_target_handle; + } if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) { return_error = BR_FAILED_REPLY; @@ -3578,10 +3584,17 @@ static int binder_thread_write(struct binder_proc *proc, struct binder_node *ctx_mgr_node; mutex_lock(&context->context_mgr_node_lock); ctx_mgr_node = context->binder_context_mgr_node; - if (ctx_mgr_node) + if (ctx_mgr_node) { + if (ctx_mgr_node->proc == proc) { + binder_user_error("%d:%d context manager tried to acquire desc 0\n", + proc->pid, thread->pid); + mutex_unlock(&context->context_mgr_node_lock); + return -EINVAL; + } ret = binder_inc_ref_for_node( proc, ctx_mgr_node, strong, NULL, &rdata); + } mutex_unlock(&context->context_mgr_node_lock); } if (ret) -- GitLab From d480cb0ab8112e42ac11cd585888095869c4216a Mon Sep 17 00:00:00 2001 From: threader Date: Sun, 4 Jul 2021 02:10:17 +0200 Subject: [PATCH 354/528] kitakami_sumire_defconfig: disable KSM --- arch/arm64/configs/kitakami_sumire_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index 4c761bc52c2e..7999def8f401 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -51,7 +51,7 @@ CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_ARMV7_COMPAT=y -CONFIG_KSM=y +# CONFIG_KSM is not set CONFIG_SWAP_CONSIDER_CMA_FREE=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_ZSMALLOC=y -- GitLab From 3a23279331960b23ab59961b5a58b05b2e297b02 Mon Sep 17 00:00:00 2001 From: Marco Ballesio Date: Wed, 16 Sep 2020 09:46:36 -0700 Subject: [PATCH 355/528] binder: use EINTR for interrupted wait for work when interrupted by a signal, binder_wait_for_work currently returns -ERESTARTSYS. This error code is usually restricted to the kernel. Replace this instance of -ERESTARTSYS with -EINTR. Bug: 143717177 Test: built, booted, interrupted a worker thread within binder_wait_for_work Signed-off-by: Marco Ballesio Change-Id: I0bd1be173e0a75c917399b773046e819babb9d4b (cherry picked from commit 218225c05beaf02320f05a9b3b7041e27a0684f7) --- drivers/android/binder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index ce89b5fc8ca1..716ac22567d0 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4078,7 +4078,7 @@ static int binder_wait_for_work(struct binder_thread *thread, binder_inner_proc_lock(proc); list_del_init(&thread->waiting_thread_node); if (signal_pending(current)) { - ret = -ERESTARTSYS; + ret = -EINTR; break; } } -- GitLab From f0e567f6aca8bc1a45dc27c0a6410c7d86f6365d Mon Sep 17 00:00:00 2001 From: Marco Ballesio Date: Wed, 26 Aug 2020 16:33:17 -0700 Subject: [PATCH 356/528] binder: implement BINDER_FREEZE ioctl Frozen tasks can't process binder transactions, so a way is required to inform transmitting ends of communication failures due to the frozen state of their receiving counterparts. Additionally, races are possible between transitions to frozen state and binder transactions enqueued to a specific process. Implement BINDER_FREEZE ioctl for user space to inform the binder driver about the intention to freeze or unfreeze a process. When the ioctl is called, block the caller until any pending binder transactions toward the target process are flushed. Return an error to transactions to processes marked as frozen. Bug: 143717177 Change-Id: Ie16f72b490bbe1785b82dee2442452f71ad7dc65 Signed-off-by: Marco Ballesio Co-developed-by: Todd Kjos (cherry picked from commit 23fb7bbe4a107e2314c726e2ae241631dba29ed8) --- drivers/android/binder.c | 106 +++++++++++++++++++++++++--- include/uapi/linux/android/binder.h | 13 ++++ 2 files changed, 109 insertions(+), 10 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 716ac22567d0..83b4f3d4036f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -517,9 +517,18 @@ struct binder_priority { * (protected by binder_deferred_lock) * @deferred_work: bitmap of deferred work to perform * (protected by binder_deferred_lock) + * @outstanding_txns: number of transactions to be transmitted before + * processes in freeze_wait are woken up + * (protected by @inner_lock) * @is_dead: process is dead and awaiting free * when outstanding transactions are cleaned up * (protected by @inner_lock) + * @is_frozen: process is frozen and unable to service + * binder transactions + * (protected by @inner_lock) + * @freeze_wait: waitqueue of processes waiting for all outstanding + * transactions to be processed + * (protected by @inner_lock) * @todo: list of work for this process * (protected by @inner_lock) * @stats: per-process binder statistics @@ -562,7 +571,10 @@ struct binder_proc { struct mutex files_lock; struct hlist_node deferred_work_node; int deferred_work; + int outstanding_txns; bool is_dead; + bool is_frozen; + wait_queue_head_t freeze_wait; struct list_head todo; struct binder_stats stats; @@ -2108,6 +2120,10 @@ static void binder_free_transaction(struct binder_transaction *t) spin_unlock(&t->lock); binder_inner_proc_lock(target_proc); + target_proc->outstanding_txns--; + BUG_ON(target_proc->outstanding_txns < 0); + if (!target_proc->outstanding_txns && target_proc->is_frozen) + wake_up_interruptible_all(&target_proc->freeze_wait); if (t->buffer) t->buffer->transaction = NULL; binder_inner_proc_unlock(target_proc); @@ -2783,10 +2799,11 @@ static int binder_fixup_parent(struct binder_transaction *t, * If the @thread parameter is not NULL, the transaction is always queued * to the waitlist of that specific thread. * - * Return: true if the transactions was successfully queued - * false if the target process or thread is dead + * Return: 0 if the transaction was successfully queued + * BR_DEAD_REPLY if the target process or thread is dead + * BR_FROZEN_REPLY if the target process or thread is frozen */ -static bool binder_proc_transaction(struct binder_transaction *t, +static int binder_proc_transaction(struct binder_transaction *t, struct binder_proc *proc, struct binder_thread *thread) { @@ -2811,10 +2828,12 @@ static bool binder_proc_transaction(struct binder_transaction *t, binder_inner_proc_lock(proc); - if (proc->is_dead || (thread && thread->is_dead)) { + if (proc->is_frozen || proc->is_dead || (thread && thread->is_dead)) { + bool proc_is_dead = proc->is_dead + || (thread && thread->is_dead); binder_inner_proc_unlock(proc); binder_node_unlock(node); - return false; + return proc_is_dead ? BR_DEAD_REPLY : BR_FROZEN_REPLY; } if (!thread && !pending_async) @@ -2833,10 +2852,11 @@ static bool binder_proc_transaction(struct binder_transaction *t, if (!pending_async) binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); + proc->outstanding_txns++; binder_inner_proc_unlock(proc); binder_node_unlock(node); - return true; + return 0; } /** @@ -3413,13 +3433,16 @@ static void binder_transaction(struct binder_proc *proc, if (reply) { binder_enqueue_thread_work(thread, tcomplete); binder_inner_proc_lock(target_proc); - if (target_thread->is_dead) { + if (target_thread->is_dead || target_proc->is_frozen) { + return_error = target_proc->is_dead ? + BR_DEAD_REPLY : BR_FROZEN_REPLY; binder_inner_proc_unlock(target_proc); goto err_dead_proc_or_thread; } BUG_ON(t->buffer->async_transaction != 0); binder_pop_transaction_ilocked(target_thread, in_reply_to); binder_enqueue_thread_work_ilocked(target_thread, &t->work); + target_proc->outstanding_txns++; binder_inner_proc_unlock(target_proc); wake_up_interruptible_sync(&target_thread->wait); binder_restore_priority(current, in_reply_to->saved_priority); @@ -3439,7 +3462,9 @@ static void binder_transaction(struct binder_proc *proc, t->from_parent = thread->transaction_stack; thread->transaction_stack = t; binder_inner_proc_unlock(proc); - if (!binder_proc_transaction(t, target_proc, target_thread)) { + return_error = binder_proc_transaction(t, + target_proc, target_thread); + if (return_error) { binder_inner_proc_lock(proc); binder_pop_transaction_ilocked(thread, t); binder_inner_proc_unlock(proc); @@ -3449,7 +3474,8 @@ static void binder_transaction(struct binder_proc *proc, BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); binder_enqueue_thread_work(thread, tcomplete); - if (!binder_proc_transaction(t, target_proc, NULL)) + return_error = binder_proc_transaction(t, target_proc, NULL); + if (return_error) goto err_dead_proc_or_thread; } if (target_thread) @@ -3466,7 +3492,6 @@ static void binder_transaction(struct binder_proc *proc, return; err_dead_proc_or_thread: - return_error = BR_DEAD_REPLY; return_error_line = __LINE__; binder_dequeue_work(proc, tcomplete); err_translate_failed: @@ -4582,6 +4607,7 @@ static void binder_free_proc(struct binder_proc *proc) { BUG_ON(!list_empty(&proc->todo)); BUG_ON(!list_empty(&proc->delivered_death)); + WARN_ON(proc->outstanding_txns); binder_alloc_deferred_release(&proc->alloc); put_task_struct(proc->tsk); binder_stats_deleted(BINDER_STAT_PROC); @@ -4637,6 +4663,7 @@ static int binder_thread_release(struct binder_proc *proc, (t->to_thread == thread) ? "in" : "out"); if (t->to_thread == thread) { + t->to_proc->outstanding_txns--; t->to_proc = NULL; t->to_thread = NULL; if (t->buffer) { @@ -5033,6 +5060,63 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; } + case BINDER_FREEZE: { + struct binder_freeze_info info; + struct binder_proc *target_proc; + bool found = false; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info.pid) { + found = true; + binder_inner_proc_lock(target_proc); + target_proc->tmp_ref++; + binder_inner_proc_unlock(target_proc); + break; + } + } + mutex_unlock(&binder_procs_lock); + if (!found) { + ret = -EINVAL; + goto err; + } + if (!info.enable) { + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + binder_proc_dec_tmpref(target_proc); + break; + } + /* + * Freezing the target. Prevent new transactions by + * setting frozen state. If timeout specified, wait + * for transactions to drain. + */ + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = true; + binder_inner_proc_unlock(target_proc); + if (info.timeout_ms > 0) + ret = wait_event_interruptible_timeout( + target_proc->freeze_wait, + (!target_proc->outstanding_txns), + msecs_to_jiffies(info.timeout_ms)); + if (!ret && target_proc->outstanding_txns) { + ret = -EAGAIN; + } + if (ret < 0) { + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + } + binder_proc_dec_tmpref(target_proc); + if (ret < 0) + goto err; + break; + } default: ret = -EINVAL; goto err; @@ -5145,6 +5229,7 @@ static int binder_open(struct inode *nodp, struct file *filp) proc->tsk = current->group_leader; mutex_init(&proc->files_lock); INIT_LIST_HEAD(&proc->todo); + init_waitqueue_head(&proc->freeze_wait); if (binder_supported_policy(current->policy)) { proc->default_priority.sched_policy = current->policy; proc->default_priority.prio = current->normal_prio; @@ -5323,6 +5408,7 @@ static void binder_deferred_release(struct binder_proc *proc) atomic_inc(&proc->tmp_ref); proc->is_dead = true; + proc->is_frozen = false; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 3f4b536fc549..e3bc65a05e64 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -263,6 +263,12 @@ struct binder_node_info_for_ref { __u32 reserved3; }; +struct binder_freeze_info { + __u32 pid; + __u32 enable; + __u32 timeout_ms; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) @@ -274,6 +280,7 @@ struct binder_node_info_for_ref { #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) #define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) #define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) +#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info) /* * NOTE: Two special error codes you should check for when calling @@ -454,6 +461,12 @@ enum binder_driver_return_protocol { * The the last transaction (either a bcTRANSACTION or * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters. */ + + BR_FROZEN_REPLY = _IO('r', 18), + /* + * The target of the last transaction (either a bcTRANSACTION or + * a bcATTEMPT_ACQUIRE) is frozen. No parameters. + */ }; enum binder_driver_command_protocol { -- GitLab From c7a069eaab6032b66f1a0b2dd0252a4066e9aeee Mon Sep 17 00:00:00 2001 From: Marco Ballesio Date: Fri, 22 Jan 2021 09:26:14 -0800 Subject: [PATCH 357/528] binder: don't unlock procs while scanning contexts Releasing the procs lock while freezing a binder context allows for other processes to modify the process list while the scan is still ongoing. Don't release the process locks during the scan operatoin, but store matching processes in a dynamic array and process them at a later phase. Signed-off-by: Marco Ballesio Bug: 176996063 Test: verified that all contexts are correctly frozen and unfrozen Change-Id: Iea527e3b9188b04303f8b9b08b404e0c062a0189 (cherry picked from commit 07e3897eefcc2b94e0514e5916ac88fdb1df04ed) --- drivers/android/binder.c | 65 +++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 83b4f3d4036f..38e7b8f0fd76 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5062,28 +5062,71 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } case BINDER_FREEZE: { struct binder_freeze_info info; - struct binder_proc *target_proc; - bool found = false; + struct binder_proc **target_procs = NULL, *target_proc; + int target_procs_count = 0, i = 0; + + ret = 0; if (copy_from_user(&info, ubuf, sizeof(info))) { ret = -EFAULT; goto err; } + mutex_lock(&binder_procs_lock); hlist_for_each_entry(target_proc, &binder_procs, proc_node) { - if (target_proc->pid == info.pid) { - found = true; - binder_inner_proc_lock(target_proc); - target_proc->tmp_ref++; - binder_inner_proc_unlock(target_proc); - break; - } + if (target_proc->pid == info.pid) + target_procs_count++; } - mutex_unlock(&binder_procs_lock); - if (!found) { + + if (target_procs_count == 0) { + mutex_unlock(&binder_procs_lock); ret = -EINVAL; goto err; } + + target_procs = kmalloc(sizeof(struct binder_proc *) * + target_procs_count, + GFP_KERNEL); + + if (!target_procs) { + mutex_unlock(&binder_procs_lock); + ret = -ENOMEM; + goto err; + } + + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid != info.pid) + continue; + + binder_inner_proc_lock(target_proc); + target_proc->tmp_ref++; + binder_inner_proc_unlock(target_proc); + + target_procs[i++] = target_proc; + } + mutex_unlock(&binder_procs_lock); + + for (i = 0; i < target_procs_count; i++) { + if (ret >= 0) + ret = binder_ioctl_freeze(&info, + target_procs[i]); + + binder_proc_dec_tmpref(target_procs[i]); + } + + kfree(target_procs); + + if (ret < 0) + goto err; + break; + } + case BINDER_GET_FROZEN_INFO: { + struct binder_frozen_status_info info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } if (!info.enable) { binder_inner_proc_lock(target_proc); target_proc->is_frozen = false; -- GitLab From c168a9f1b90bb42c84f702ccb13dc07225e81aa5 Mon Sep 17 00:00:00 2001 From: Marco Ballesio Date: Thu, 10 Sep 2020 13:39:20 -0700 Subject: [PATCH 358/528] binder: introduce the BINDER_GET_FROZEN_INFO ioctl User space needs to know if binder transactions occurred to frozen processes. Introduce a new BINDER_GET_FROZEN ioctl and keep track of transactions occurring to frozen proceses. Also, allow async transactions toward frozen processes and improve error hendling. Bug: 143717177 Test: atest testBinderLib Signed-off-by: Marco Ballesio Change-Id: I9ee1c2e5fe3d4ab31fc1a137d840bd4cd38a8704 (cherry picked from commit 95763db10bc1d1ede7907da05b3e24b6bfb09453) --- drivers/android/binder.c | 71 +++++++++++++++++++++++++++-- include/uapi/linux/android/binder.h | 7 +++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 38e7b8f0fd76..1aff46bbbc88 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -523,8 +523,9 @@ struct binder_priority { * @is_dead: process is dead and awaiting free * when outstanding transactions are cleaned up * (protected by @inner_lock) - * @is_frozen: process is frozen and unable to service - * binder transactions + * @sync_recv: process received sync transactions since last frozen + * (protected by @inner_lock) + * @async_recv: process received async transactions since last frozen * (protected by @inner_lock) * @freeze_wait: waitqueue of processes waiting for all outstanding * transactions to be processed @@ -574,6 +575,8 @@ struct binder_proc { int outstanding_txns; bool is_dead; bool is_frozen; + bool sync_recv; + bool async_recv; wait_queue_head_t freeze_wait; struct list_head todo; @@ -2827,8 +2830,13 @@ static int binder_proc_transaction(struct binder_transaction *t, } binder_inner_proc_lock(proc); + if (proc->is_frozen) { + proc->sync_recv |= !oneway; + proc->async_recv |= oneway; + } - if (proc->is_frozen || proc->is_dead || (thread && thread->is_dead)) { + if ((proc->is_frozen && !oneway) || proc->is_dead || + (thread && thread->is_dead)) { bool proc_is_dead = proc->is_dead || (thread && thread->is_dead); binder_inner_proc_unlock(proc); @@ -3434,7 +3442,7 @@ static void binder_transaction(struct binder_proc *proc, binder_enqueue_thread_work(thread, tcomplete); binder_inner_proc_lock(target_proc); if (target_thread->is_dead || target_proc->is_frozen) { - return_error = target_proc->is_dead ? + return_error = target_thread->is_dead ? BR_DEAD_REPLY : BR_FROZEN_REPLY; binder_inner_proc_unlock(target_proc); goto err_dead_proc_or_thread; @@ -4936,6 +4944,37 @@ static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, return 0; } +static int binder_ioctl_get_freezer_info( + struct binder_frozen_status_info *info) +{ + struct binder_proc *target_proc; + bool found = false; + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info->pid) { + found = true; + binder_inner_proc_lock(target_proc); + target_proc->tmp_ref++; + binder_inner_proc_unlock(target_proc); + break; + } + } + mutex_unlock(&binder_procs_lock); + + if (!found) + return -EINVAL; + + binder_inner_proc_lock(target_proc); + info->sync_recv = target_proc->sync_recv; + info->async_recv = target_proc->async_recv; + binder_inner_proc_unlock(target_proc); + + binder_proc_dec_tmpref(target_proc); + + return 0; +} + static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; @@ -5129,6 +5168,8 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } if (!info.enable) { binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; target_proc->is_frozen = false; binder_inner_proc_unlock(target_proc); binder_proc_dec_tmpref(target_proc); @@ -5140,6 +5181,8 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) * for transactions to drain. */ binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; target_proc->is_frozen = true; binder_inner_proc_unlock(target_proc); if (info.timeout_ms > 0) @@ -5160,6 +5203,24 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err; break; } + case BINDER_GET_FROZEN_INFO: { + struct binder_frozen_status_info info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_freezer_info(&info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; + goto err; + } + break; + } default: ret = -EINVAL; goto err; @@ -5452,6 +5513,8 @@ static void binder_deferred_release(struct binder_proc *proc) proc->is_dead = true; proc->is_frozen = false; + proc->sync_recv = false; + proc->async_recv = false; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index e3bc65a05e64..34e767e05153 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -269,6 +269,12 @@ struct binder_freeze_info { __u32 timeout_ms; }; +struct binder_frozen_status_info { + __u32 pid; + __u32 sync_recv; + __u32 async_recv; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) @@ -281,6 +287,7 @@ struct binder_freeze_info { #define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) #define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) #define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info) +#define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info) /* * NOTE: Two special error codes you should check for when calling -- GitLab From 74c89940eefefd4d1f4572878ec2cbe4750e8cfc Mon Sep 17 00:00:00 2001 From: Marco Ballesio Date: Thu, 7 Jan 2021 17:02:50 -0800 Subject: [PATCH 359/528] binder: freeze multiple contexts binder freeze stops at the first context found for any pid, but multiple ones are possible with the result that a process might end up with inconsistent context states after freezing or unfreezing its binder. Freeze or unfreeze all contexts in a process upon a BINDER_FREEZE ioctl. Bug: 176996063 Test: verified that all contexts in a specific process with multiple binders are frozen or unfrozen. Signed-off-by: Marco Ballesio Change-Id: If0822e078e830e9fde10cc17b99e39ec7cf358d5 (cherry picked from commit 8d39b8ff157786afa76bc73768d4f3616c0fabe6) --- drivers/android/binder.c | 76 +++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 1aff46bbbc88..32099db408b4 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4944,20 +4944,66 @@ static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, return 0; } +static int binder_ioctl_freeze(struct binder_freeze_info *info, + struct binder_proc *target_proc) +{ + int ret = 0; + + if (!info->enable) { + binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + return 0; + } + + /* + * Freezing the target. Prevent new transactions by + * setting frozen state. If timeout specified, wait + * for transactions to drain. + */ + binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; + target_proc->is_frozen = true; + binder_inner_proc_unlock(target_proc); + + if (info->timeout_ms > 0) + ret = wait_event_interruptible_timeout( + target_proc->freeze_wait, + (!target_proc->outstanding_txns), + msecs_to_jiffies(info->timeout_ms)); + + if (!ret && target_proc->outstanding_txns) + ret = -EAGAIN; + + if (ret < 0) { + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + } + + return ret; +} + static int binder_ioctl_get_freezer_info( struct binder_frozen_status_info *info) { struct binder_proc *target_proc; bool found = false; + info->sync_recv = 0; + info->async_recv = 0; + mutex_lock(&binder_procs_lock); hlist_for_each_entry(target_proc, &binder_procs, proc_node) { if (target_proc->pid == info->pid) { found = true; binder_inner_proc_lock(target_proc); - target_proc->tmp_ref++; + info->sync_recv |= target_proc->sync_recv; + info->async_recv |= target_proc->async_recv; binder_inner_proc_unlock(target_proc); - break; } } mutex_unlock(&binder_procs_lock); @@ -4965,13 +5011,6 @@ static int binder_ioctl_get_freezer_info( if (!found) return -EINVAL; - binder_inner_proc_lock(target_proc); - info->sync_recv = target_proc->sync_recv; - info->async_recv = target_proc->async_recv; - binder_inner_proc_unlock(target_proc); - - binder_proc_dec_tmpref(target_proc); - return 0; } @@ -5199,6 +5238,25 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) binder_inner_proc_unlock(target_proc); } binder_proc_dec_tmpref(target_proc); +======= + if (target_proc->pid == info.pid) { + binder_inner_proc_lock(target_proc); + target_proc->tmp_ref++; + binder_inner_proc_unlock(target_proc); + + mutex_unlock(&binder_procs_lock); + ret = binder_ioctl_freeze(&info, target_proc); + mutex_lock(&binder_procs_lock); + + binder_proc_dec_tmpref(target_proc); + + if (ret < 0) + break; + } + } + mutex_unlock(&binder_procs_lock); + +>>>>>>> 8d39b8ff1577 (binder: freeze multiple contexts) if (ret < 0) goto err; break; -- GitLab From 1db978b594d0824e37f018c38a9e61cc1c17e5e0 Mon Sep 17 00:00:00 2001 From: threader Date: Tue, 6 Jul 2021 00:09:52 +0200 Subject: [PATCH 360/528] Fixup after '8d39b8ff1577 (binder: freeze multiple contexts)' --- drivers/android/binder.c | 63 ---------------------------------------- 1 file changed, 63 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 32099db408b4..de5ecd0ea968 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5201,69 +5201,6 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case BINDER_GET_FROZEN_INFO: { struct binder_frozen_status_info info; - if (copy_from_user(&info, ubuf, sizeof(info))) { - ret = -EFAULT; - goto err; - } - if (!info.enable) { - binder_inner_proc_lock(target_proc); - target_proc->sync_recv = false; - target_proc->async_recv = false; - target_proc->is_frozen = false; - binder_inner_proc_unlock(target_proc); - binder_proc_dec_tmpref(target_proc); - break; - } - /* - * Freezing the target. Prevent new transactions by - * setting frozen state. If timeout specified, wait - * for transactions to drain. - */ - binder_inner_proc_lock(target_proc); - target_proc->sync_recv = false; - target_proc->async_recv = false; - target_proc->is_frozen = true; - binder_inner_proc_unlock(target_proc); - if (info.timeout_ms > 0) - ret = wait_event_interruptible_timeout( - target_proc->freeze_wait, - (!target_proc->outstanding_txns), - msecs_to_jiffies(info.timeout_ms)); - if (!ret && target_proc->outstanding_txns) { - ret = -EAGAIN; - } - if (ret < 0) { - binder_inner_proc_lock(target_proc); - target_proc->is_frozen = false; - binder_inner_proc_unlock(target_proc); - } - binder_proc_dec_tmpref(target_proc); -======= - if (target_proc->pid == info.pid) { - binder_inner_proc_lock(target_proc); - target_proc->tmp_ref++; - binder_inner_proc_unlock(target_proc); - - mutex_unlock(&binder_procs_lock); - ret = binder_ioctl_freeze(&info, target_proc); - mutex_lock(&binder_procs_lock); - - binder_proc_dec_tmpref(target_proc); - - if (ret < 0) - break; - } - } - mutex_unlock(&binder_procs_lock); - ->>>>>>> 8d39b8ff1577 (binder: freeze multiple contexts) - if (ret < 0) - goto err; - break; - } - case BINDER_GET_FROZEN_INFO: { - struct binder_frozen_status_info info; - if (copy_from_user(&info, ubuf, sizeof(info))) { ret = -EFAULT; goto err; -- GitLab From 3dcfbf96fbbf2a6af4e6b99dea891f3809d8364f Mon Sep 17 00:00:00 2001 From: threader Date: Sun, 4 Jul 2021 17:43:16 +0200 Subject: [PATCH 361/528] binder: increment using atomic op. - artifact of old commit since this was fixed as a bug (cherry picked from commit 8746fb539cdb1056983b36512f827a30289d477a) --- drivers/android/binder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index de5ecd0ea968..5291f64f17a8 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5177,7 +5177,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) continue; binder_inner_proc_lock(target_proc); - target_proc->tmp_ref++; + atomic_inc(&proc->tmp_ref); binder_inner_proc_unlock(target_proc); target_procs[i++] = target_proc; -- GitLab From aabd388b2bf419413238d15e4a6f899fe8006270 Mon Sep 17 00:00:00 2001 From: myfluxi Date: Mon, 18 Aug 2014 16:18:48 +0200 Subject: [PATCH 362/528] msm: thermal: Check temperature only if probed This avoids a (harmless) error: <3>[ 0.214144] msm_thermal:msm_thermal_get_freq_table error reading cpufreq table Signed-off-by: Pranav Vashi (cherry picked from commit 5dd8d203c55437d107d05874df786fca8be0fb7c) --- drivers/thermal/msm_thermal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index f67b80b4d673..74c37e694cd9 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -2955,6 +2955,9 @@ static void check_temp(struct work_struct *work) long temp = 0; int ret = 0; + if (!msm_thermal_probed) + return; + do_therm_reset(); ret = therm_get_temp(msm_thermal_info.sensor_id, THERM_TSENS_ID, &temp); -- GitLab From df35accc9a3ca3a1958c792619655650d1c2d5ed Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Wed, 11 May 2016 12:56:06 +0530 Subject: [PATCH 363/528] msm: thermal: Check clients request just after frequency thread init KTM frequency mitigation thread initializes during late init call. Prior to this, client can request frequency mitigation. But request will not be processed, since frequency mitigation thread won't be initialized. Notify frequency mitigation thread to aggregate clients current request immediately after thread initialization. Change-Id: Id2425041b14554d58f944794e1b5db273f5ded26 Signed-off-by: Manaf Meethalavalappu Pallikunhi (cherry picked from commit e82df557f0b131f6cfb0bd29d12d9340eab76421) --- drivers/thermal/msm_thermal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 74c37e694cd9..4f0a5f420aa1 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -3323,6 +3323,8 @@ init_freq_thread: pr_err("Failed to create frequency mitigation thread. err:%ld\n", PTR_ERR(freq_mitigation_task)); return; + } else { + complete(&freq_mitigation_complete); } } -- GitLab From 592e58aa914326468e76c9d13057b56027fa71b5 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Thu, 7 Sep 2017 00:23:51 +0530 Subject: [PATCH 364/528] msm: thermal: Check cpu variables are initialized before setting threshold Userspace thermal daemon initiate KTM hotplug monitor related initialization. Thermal core control can be disabled/enabled from userspace via KTM sysfs for cpu related initialization after boot. There is a possible race condition between KTM hotplug initialization from thermal daemon and KTM core control re-enablement from userpsace shell. When these both events are triggered at the same time, thermal core control enablement tries to set emergency hotplug threshold prior to per cpu hotplug related initialization like sensor id, trip and threshold value etc. This leads to wrong sensor threshold settings and eventually thermal core sensor threshold list will be broken. To avoid this wrong threshold settings during thermal core control enablement, check KTM hotplug related initialization is done prior to threshold setting for each core. Change-Id: I916527d187146d5e292dd57897aa70b21cf87fbc Signed-off-by: Manaf Meethalavalappu Pallikunhi (cherry picked from commit 1d66c7a9e65e88a2b8e11b3f6c0687d9d2b54954) --- drivers/thermal/msm_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 4f0a5f420aa1..8ade21880d13 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -4241,7 +4241,7 @@ static ssize_t __ref store_cc_enabled(struct kobject *kobj, hotplug_init_cpu_offlined(); mutex_lock(&core_control_mutex); update_offline_cores(cpus_offlined); - if (hotplug_enabled) { + if (hotplug_enabled && hotplug_task) { for_each_possible_cpu(cpu) { if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu))) -- GitLab From 9567bbfa55e4555bfc60c847b3756b95c371879b Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Tue, 14 Jul 2015 15:18:56 -0600 Subject: [PATCH 365/528] msm: thermal: Register for panic notifier on successful probe Register for panic notification from KTM only on successful probe. This avoids invalid memory access during early boot from KTM panic notification callback, in case probe has deferred. ================================================================== BUG: KASan: out of bounds access in msm_tsens_get_temp+0x51c/0x60c at addr ffffffc0bc6e0b00 Write of size 8 by task kworker/0:1/42 ========================================================================== BUG kmalloc-128 (Tainted: G B W ): kasan: bad access detected -------------------------------------------------------------------------- Call trace: [] dump_backtrace+0x0/0x1c4 [] show_stack+0x10/0x1c [] dump_stack+0x74/0xc8 [] print_trailer+0x14c/0x160 [] object_err+0x38/0x4c [] kasan_report_error+0x244/0x40c [] kasan_report+0x34/0x40 [] __asan_store8+0x88/0x94 [] msm_tsens_get_temp+0x518/0x60c [] tsens_get_temp+0x68/0x80 [] therm_get_temp+0xd0/0x16c [] msm_thermal_panic_callback+0x64/0xc8 [] notifier_call_chain+0x68/0xb4 [] __atomic_notifier_call_chain+0x40/0x64 [] atomic_notifier_call_chain+0x10/0x1c [] panic+0x1e0/0x3c8 [] device_restart_work_hdlr+0xa8/0xac [] process_one_work+0x394/0x650 [] worker_thread+0x3bc/0x550 [] kthread+0x180/0x194 Memory state around the buggy address: ffffffc0bc6e0a00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffffffc0bc6e0a80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffffffc0bc6e0b00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ^ ffffffc0bc6e0b80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffffffc0bc6e0c00: fc fc fc fc fc fc fc fc 00 00 00 00 00 00 00 00 ================================================================== CRs-Fixed: 860376 Change-Id: Icfd6c859e21a025889c62a8945cd902c0496edc8 Signed-off-by: Ram Chandrasekar Signed-off-by: mydongistiny (cherry picked from commit 9fc06c740119f48b0f9d9625130052a5a4a2bcf4) --- drivers/thermal/msm_thermal.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 8ade21880d13..7df640e301c7 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -4473,9 +4473,6 @@ int msm_thermal_pre_init(struct device *dev) goto pre_init_exit; } - if (!tsens_temp_at_panic) - msm_thermal_panic_notifier_init(dev); - if (!thresh) { thresh = kzalloc( sizeof(struct threshold_info) * MSM_LIST_MAX_NR, @@ -4612,6 +4609,7 @@ int msm_thermal_init(struct msm_thermal_data *pdata) cpus_previously_online_update(); register_cpu_notifier(&msm_thermal_cpu_notifier); } + msm_thermal_panic_notifier_init(&pdata->pdev->dev); return ret; } -- GitLab From 2987bc29c56d82770e283ef3a89749973fcf006d Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Thu, 22 Oct 2015 17:47:42 +0530 Subject: [PATCH 366/528] msm: thermal: Configure core sensor id on emergency frequency init Core sensor id is configured during emergency hotplug initialization and the same id is used for emergency frequency mitigation. This dependency will break emergency frequency mitigation feature, if emergency frequency mitigation is enabled and emergency hotplug is not. Configure core sensor id during emergency mitigation initialization as well to avoid this scenario. Change-Id: Ia1f980159fafd80caf9a2a8f9fe0c0849aba6a88 Signed-off-by: Manaf Meethalavalappu Pallikunhi Signed-off-by: mydongistiny (cherry picked from commit 99c595e2a91f71e96f6e12fec01e3e2a564a4984) --- drivers/thermal/msm_thermal.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 7df640e301c7..8b2eb299a8d7 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -3298,6 +3298,13 @@ static void freq_mitigation_init(void) goto init_freq_thread; for_each_possible_cpu(cpu) { + /* + * Hotplug may not be enabled, + * make sure core sensor id is initialized. + */ + cpus[cpu].sensor_id = + sensor_get_id((char *)cpus[cpu].sensor_type); + cpus[cpu].id_type = THERM_ZONE_ID; if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu))) continue; hi_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]; -- GitLab From 9ccc9c23498facfa52ef8c52513440c81399a76b Mon Sep 17 00:00:00 2001 From: Sivaram Vempati Date: Thu, 21 Jul 2016 10:34:01 -0700 Subject: [PATCH 367/528] msm: thermal: Update the hotplug initialization Hotplug initialization will trigger a hotplug if temperature stays above the trip threshold and will try to online if temperature is below the clear threshold. Since KTM does boot mitigation till thermal-engine is running, hotplug init can be called twice. First from post init script and second when the hotplug task is initialized. There is a possiblity the first init call can set the hotplug local mask and the second init call wont clear or update the mask with correct value if the temperature is between the hotplug trip and clear threshold. Update the hotplug init API to perform the check only if the hotplug task is initialized. Also the hotplug check will clear the hotplug local mask if the temperature is not above the trip threshold. Bug: 29464076 Change-Id: Ica1325f8aa65c338ea0e5b201f566607c3ddf904 Signed-off-by: Ram Chandrasekar Signed-off-by: Sivaram Vemapti Signed-off-by: mydongistiny (cherry picked from commit 563e8663f5d4a81c132555a043966ec6addfdc21) --- drivers/thermal/msm_thermal.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 8b2eb299a8d7..fc8644084d0c 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -3076,7 +3076,7 @@ static int hotplug_init_cpu_offlined(void) long temp = 0; uint32_t cpu = 0; - if (!hotplug_enabled) + if (!hotplug_enabled || !hotplug_task) return 0; mutex_lock(&core_control_mutex); @@ -3093,8 +3093,7 @@ static int hotplug_init_cpu_offlined(void) if (temp >= msm_thermal_info.hotplug_temp_degC) cpus[cpu].offline = 1; - else if (temp <= (msm_thermal_info.hotplug_temp_degC - - msm_thermal_info.hotplug_temp_hysteresis_degC)) + else cpus[cpu].offline = 0; } mutex_unlock(&core_control_mutex); -- GitLab From ff5dc0f5c5b374f9030abfb8c44536982e6eaa1f Mon Sep 17 00:00:00 2001 From: Francisco Franco Date: Sat, 26 Nov 2016 16:10:36 +0000 Subject: [PATCH 368/528] drivers: thermal: queue work on system_power_efficient_wq There doesn't seem to be any real dependency of scheduling these on the cpu which scheduled them, so moving every *_delayed to the power efficient wq save potential needlessly idle cpu wake ups leaving the scheduler to decide the most appropriate cpus to wake up. Signed-off-by: Francisco Franco (cherry picked from commit c67b57e8671a17df4e1cfbc32790e4e161028ba1) --- drivers/thermal/msm_thermal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index fc8644084d0c..d93fdb82a62b 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -2986,8 +2986,9 @@ static void check_temp(struct work_struct *work) reschedule: if (polling_enabled) - schedule_delayed_work(&check_temp_work, - msecs_to_jiffies(msm_thermal_info.poll_ms)); + queue_delayed_work(system_power_efficient_wq, + &check_temp_work, + msecs_to_jiffies(msm_thermal_info.poll_ms)); } static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb, -- GitLab From e2378a0dc94ada640702e50ae07cb57f1d8bf5db Mon Sep 17 00:00:00 2001 From: Siqi Lin Date: Wed, 25 May 2016 17:36:47 -0700 Subject: [PATCH 369/528] msm_thermal: send OFF/ONLINE uevent in hotplug cases Send the correct uevent after setting a CPU core online or offline. This allows ueventd to set correct SELinux labels for newly created sysfs CPU device nodes. Bug: 28887345 Change-Id: If31b8529b31de9544914e27514aca571039abb60 Signed-off-by: Siqi Lin Signed-off-by: Thierry Strudel (cherry picked from commit f3b1931e2422ac358aecb8e951f12d0e69863c7f) --- drivers/thermal/msm_thermal.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index d93fdb82a62b..ebdb68259caf 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -2476,11 +2476,14 @@ static int __ref update_offline_cores(int val) continue; trace_thermal_pre_core_offline(cpu); ret = cpu_down(cpu); - if (ret) + if (ret) { pr_err("Unable to offline CPU%d. err:%d\n", cpu, ret); - else + } else { + struct device *cpu_device = get_cpu_device(cpu); + kobject_uevent(&cpu_device->kobj, KOBJ_OFFLINE); pr_debug("Offlined CPU%d\n", cpu); + } trace_thermal_post_core_offline(cpu, cpumask_test_cpu(cpu, cpu_online_mask)); } else if (online_core && (previous_cpus_offlined & BIT(cpu))) { @@ -2499,6 +2502,8 @@ static int __ref update_offline_cores(int val) pr_err("Unable to online CPU%d. err:%d\n", cpu, ret); } else { + struct device *cpu_device = get_cpu_device(cpu); + kobject_uevent(&cpu_device->kobj, KOBJ_ONLINE); pr_debug("Onlined CPU%d\n", cpu); } trace_thermal_post_core_online(cpu, -- GitLab From 2df558dc9de9a186e5815d90696dd554be40ffeb Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 2 Feb 2017 16:19:05 -0700 Subject: [PATCH 370/528] msm_thermal: use %*pb[l] to print bitmaps including cpumasks and nodemasks printk and friends can now format bitmaps using '%*pb[l]'. cpumask and nodemask also provide cpumask_pr_args() and nodemask_pr_args() respectively which can be used to generate the two printf arguments necessary to format the specified cpu/nodemask. Signed-off-by: Nathan Chancellor Signed-off-by: Joe Maples (cherry picked from commit a4e82d79cc637c09106cb3299c6c1d48b973815b) --- drivers/thermal/msm_thermal.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index ebdb68259caf..554a3d7a9055 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -415,7 +415,8 @@ static void cpus_previously_online_update(void) cpumask_or(cpus_previously_online, cpus_previously_online, cpu_online_mask); put_online_cpus(); - cpulist_scnprintf(buf, sizeof(buf), cpus_previously_online); + scnprintf(buf, sizeof(buf), "%*pbl", + cpumask_pr_args(cpus_previously_online)); pr_debug("%s\n", buf); } @@ -1197,8 +1198,9 @@ static int __ref init_cluster_freq_table(void) if (!cpu_set) { cpumask_clear_cpu(_cpu, cpus_previously_online); - cpumask_scnprintf(buf, sizeof(buf), - cpus_previously_online); + scnprintf(buf, sizeof(buf), "%*pb", + cpumask_pr_args( + cpus_previously_online)); pr_debug("Reset prev online to %s\n", buf); } -- GitLab From a693de2229f42c292a8e0bb4a57f52423ad19772 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Tue, 14 Apr 2015 19:27:09 +0530 Subject: [PATCH 371/528] msm: thermal: Fix KTM code to check psm is enabled before handling it During boot up polling mode mitigation, KTM handles psm code even if feature is disabled. Add a check in psm code whether feature is enabled or not before handling this. Change-Id: I55d6ed43e829dbf8a35cf8af4a3ca28cfb10c013 Signed-off-by: Manaf Meethalavalappu Pallikunhi (cherry picked from commit 8e09d81cb72120c790a615a136a0c26dea7f407e) --- drivers/thermal/msm_thermal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 554a3d7a9055..5a3c977deb20 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -2865,6 +2865,9 @@ static int do_psm(void) int i = 0; int auto_cnt = 0; + if (!psm_enabled) + return ret; + mutex_lock(&psm_mutex); for (i = 0; i < max_tsens_num; i++) { ret = therm_get_temp(tsens_id_map[i], THERM_TSENS_ID, &temp); -- GitLab From caad582cc9a930605ae0ca7cf84160e46a36b685 Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Mon, 27 Apr 2015 14:55:15 -0600 Subject: [PATCH 372/528] msm: thermal: Retry on failure to hotplug Add support in thermal driver to retry hotplug request on failure to fulfill the request. This retrying will be disabled when the device enters suspend and will resume after the device exits from suspend. Change-Id: I9e2c305754465eb458566c0224804c5ad4bda240 Signed-off-by: Ram Chandrasekar Signed-off-by: Andrey Cherepkov (cherry picked from commit f4821ee954a456faf19524ff6c63598eb99a7eae) --- drivers/thermal/msm_thermal.c | 36 ++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 5a3c977deb20..94e2307eb3f5 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -62,6 +62,7 @@ #define MSM_TSENS_PRINT "log_tsens_temperature" #define CPU_BUF_SIZE 64 #define CPU_DEVICE "cpu%d" +#define HOTPLUG_RETRY_INTERVAL_MS 100 #define THERM_CREATE_DEBUGFS_DIR(_node, _name, _parent, _ret) \ do { \ @@ -81,7 +82,7 @@ } while (0) static struct msm_thermal_data msm_thermal_info; -static struct delayed_work check_temp_work; +static struct delayed_work check_temp_work, retry_hotplug_work; static bool core_control_enabled; static uint32_t cpus_offlined; static cpumask_var_t cpus_previously_online; @@ -132,6 +133,7 @@ static bool therm_reset_enabled; static bool online_core; static bool cluster_info_probed; static bool cluster_info_nodes_called; +static bool in_suspend, retry_in_progress; static int *tsens_id_map; static DEFINE_MUTEX(vdd_rstr_mutex); static DEFINE_MUTEX(psm_mutex); @@ -504,11 +506,15 @@ static int msm_thermal_suspend_callback( case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: msm_thermal_update_freq(false, true); + in_suspend = true; + retry_in_progress = false; + cancel_delayed_work_sync(&retry_hotplug_work); break; case PM_POST_HIBERNATION: case PM_POST_SUSPEND: msm_thermal_update_freq(false, false); + in_suspend = false; if (hotplug_task) complete(&hotplug_notify_complete); else @@ -2397,6 +2403,17 @@ static void therm_reset_notify(struct therm_threshold *thresh_data) thresh_data->threshold); } +static void retry_hotplug(struct work_struct *work) +{ + mutex_lock(&core_control_mutex); + if (retry_in_progress) { + pr_debug("Retrying hotplug\n"); + retry_in_progress = false; + complete(&hotplug_notify_complete); + } + mutex_unlock(&core_control_mutex); +} + #ifdef CONFIG_SMP static void __ref do_core_control(long temp) { @@ -2465,6 +2482,7 @@ static int __ref update_offline_cores(int val) uint32_t cpu = 0; int ret = 0; uint32_t previous_cpus_offlined = 0; + bool pend_hotplug_req = false; if (!core_control_enabled) return 0; @@ -2479,8 +2497,10 @@ static int __ref update_offline_cores(int val) trace_thermal_pre_core_offline(cpu); ret = cpu_down(cpu); if (ret) { - pr_err("Unable to offline CPU%d. err:%d\n", + pr_err_ratelimited( + "Unable to offline CPU%d. err:%d\n", cpu, ret); + pend_hotplug_req = true; } else { struct device *cpu_device = get_cpu_device(cpu); kobject_uevent(&cpu_device->kobj, KOBJ_OFFLINE); @@ -2501,7 +2521,9 @@ static int __ref update_offline_cores(int val) pr_debug("Onlining CPU%d is vetoed\n", cpu); } else if (ret) { cpus_offlined |= BIT(cpu); - pr_err("Unable to online CPU%d. err:%d\n", + pend_hotplug_req = true; + pr_err_ratelimited( + "Unable to online CPU%d. err:%d\n", cpu, ret); } else { struct device *cpu_device = get_cpu_device(cpu); @@ -2512,6 +2534,13 @@ static int __ref update_offline_cores(int val) cpumask_test_cpu(cpu, cpu_online_mask)); } } + + if (pend_hotplug_req && !in_suspend && !retry_in_progress) { + retry_in_progress = true; + schedule_delayed_work(&retry_hotplug_work, + msecs_to_jiffies(HOTPLUG_RETRY_INTERVAL_MS)); + } + return ret; } @@ -4619,6 +4648,7 @@ int msm_thermal_init(struct msm_thermal_data *pdata) register_reboot_notifier(&msm_thermal_reboot_notifier); pm_notifier(msm_thermal_suspend_callback, 0); + INIT_DELAYED_WORK(&retry_hotplug_work, retry_hotplug); INIT_DELAYED_WORK(&check_temp_work, check_temp); schedule_delayed_work(&check_temp_work, 0); -- GitLab From 24703f273b794c344abc7d1277dccf9757099382 Mon Sep 17 00:00:00 2001 From: Jeff Bernard Date: Wed, 1 Apr 2015 13:51:21 -0400 Subject: [PATCH 373/528] msm: thermal: Fix sensor number printed during thermal WD bite Fix sensor number printed during thermal watchdog bite. This change adds a lookup table to do a conversion between sensor id and thermal zone id. Change-Id: I06939c5707a7b89f7a796f0c524fcc82f833650e Signed-off-by: Jeff Bernard Signed-off-by: Andrey Cherepkov (cherry picked from commit 46bbcbc2f76c3a4157f8b644c28f23750a8a979e) --- drivers/thermal/msm_thermal.c | 83 ++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 94e2307eb3f5..0339f0c60520 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -135,6 +135,7 @@ static bool cluster_info_probed; static bool cluster_info_nodes_called; static bool in_suspend, retry_in_progress; static int *tsens_id_map; +static int *zone_id_tsens_map; static DEFINE_MUTEX(vdd_rstr_mutex); static DEFINE_MUTEX(psm_mutex); static DEFINE_MUTEX(cx_mutex); @@ -1977,13 +1978,67 @@ static int check_sensor_id(int sensor_id) return ret; } -static int create_sensor_id_map(void) +static int zone_id_to_tsen_id(int zone_id, int *tsens_id) { int i = 0; int ret = 0; - tsens_id_map = kzalloc(sizeof(int) * max_tsens_num, - GFP_KERNEL); + for (i = 0; i < max_tsens_num; i++) { + if (zone_id == zone_id_tsens_map[i]) { + *tsens_id = tsens_id_map[i]; + break; + } + } + if (i == max_tsens_num) { + pr_err("Invalid sensor zone id:%d\n", zone_id); + return -EINVAL; + } + + return ret; +} + +static int create_sensor_zone_id_map(void) +{ + int i = 0; + int zone_id = -1; + + zone_id_tsens_map = devm_kzalloc(&msm_thermal_info.pdev->dev, + sizeof(int) * max_tsens_num, GFP_KERNEL); + + if (!zone_id_tsens_map) { + pr_err("Cannot allocate memory for zone_id_tsens_map\n"); + return -ENOMEM; + } + + for (i = 0; i < max_tsens_num; i++) { + char tsens_name[TSENS_NAME_MAX] = ""; + + snprintf(tsens_name, TSENS_NAME_MAX, TSENS_NAME_FORMAT, + tsens_id_map[i]); + zone_id = sensor_get_id(tsens_name); + if (zone_id < 0) { + pr_err("Error getting zone id for %s. err:%d\n", + tsens_name, zone_id); + goto fail; + } else { + zone_id_tsens_map[i] = zone_id; + } + } + return 0; + +fail: + devm_kfree(&msm_thermal_info.pdev->dev, zone_id_tsens_map); + return zone_id; +} + +static int create_sensor_id_map(struct device *dev) +{ + int i = 0; + int ret = 0; + + tsens_id_map = devm_kzalloc(dev, + sizeof(int) * max_tsens_num, GFP_KERNEL); + if (!tsens_id_map) { pr_err("Cannot allocate memory for tsens_id_map\n"); return -ENOMEM; @@ -2006,7 +2061,7 @@ static int create_sensor_id_map(void) return ret; fail: - kfree(tsens_id_map); + devm_kfree(dev, tsens_id_map); return ret; } @@ -2326,12 +2381,20 @@ static void vdd_mx_notify(struct therm_threshold *trig_thresh) trig_thresh->threshold); } -static void msm_thermal_bite(int tsens_id, long temp) +static void msm_thermal_bite(int zone_id, long temp) { struct scm_desc desc; + int tsens_id = 0; + int ret = 0; - pr_err("TSENS:%d reached temperature:%ld. System reset\n", - tsens_id, temp); + ret = zone_id_to_tsen_id(zone_id, &tsens_id); + if (ret < 0) { + pr_err("Zone:%d reached temperature:%ld. Err = %d System reset\n", + zone_id, temp, ret); + } else { + pr_err("Tsens:%d reached temperature:%ld. System reset\n", + tsens_id, temp); + } if (!is_scm_armv8()) { scm_call_atomic1(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, 0); } else { @@ -2390,8 +2453,7 @@ static void therm_reset_notify(struct therm_threshold *thresh_data) if (ret) pr_err("Unable to read TSENS sensor:%d. err:%d\n", thresh_data->sensor_id, ret); - msm_thermal_bite(tsens_id_map[thresh_data->sensor_id], - temp); + msm_thermal_bite(thresh_data->sensor_id, temp); break; case THERMAL_TRIP_CONFIGURABLE_LOW: break; @@ -4220,6 +4282,7 @@ static void interrupt_mode_init(void) if (polling_enabled) { pr_info("Interrupt mode init\n"); polling_enabled = 0; + create_sensor_zone_id_map(); disable_msm_thermal(); hotplug_init(); freq_mitigation_init(); @@ -4513,7 +4576,7 @@ int msm_thermal_pre_init(struct device *dev) return ret; } - if (create_sensor_id_map()) { + if (create_sensor_id_map(dev)) { pr_err("Creating sensor id map failed\n"); ret = -EINVAL; goto pre_init_exit; -- GitLab From ce24031f5d6e2a98d3e22ed76ac1aafe103f58ae Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Wed, 3 Feb 2016 16:23:58 +0530 Subject: [PATCH 374/528] msm: thermal: Maintain state in the mitigation device monitor If KTM get a trip threshold trigger notification and if the temperature stays the same as the recent trip threshold, KTM will re-activate the recently triggered threshold, resulting in back to back interrupts. To avoid this add support in KTM to maintain the recently triggered threshold state and then re-active the threshold based on the last threshold trip. This state is updated for mitigation features like VDD MX retention, CX phase control, VDD restriction, OCR monitor and external clients like CPR low temperature monitor etc. CRs-Fixed: 969112 972634 Change-Id: I44c0a93e1507a9f0b8a65e5c2ce5a98962bb335b Signed-off-by: Manaf Meethalavalappu Pallikunhi Signed-off-by: Joe Maples Signed-off-by: Andrey Cherepkov (cherry picked from commit b37e8a43580d264195aa3d58188216898d90245a) --- drivers/thermal/msm_thermal.c | 27 +++++++++++++++++++++------ include/linux/msm_thermal.h | 3 ++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 0339f0c60520..789ebe445f7b 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2377,8 +2377,12 @@ static void vdd_mx_notify(struct therm_threshold *trig_thresh) pr_err("Failed to remove vdd mx restriction\n"); } mutex_unlock(&vdd_mx_mutex); - sensor_mgr_set_threshold(trig_thresh->sensor_id, + + if (trig_thresh->cur_state != trig_thresh->trip_triggered) { + sensor_mgr_set_threshold(trig_thresh->sensor_id, trig_thresh->threshold); + trig_thresh->cur_state = trig_thresh->trip_triggered; + } } static void msm_thermal_bite(int zone_id, long temp) @@ -3721,8 +3725,11 @@ static void cx_phase_ctrl_notify(struct therm_threshold *trig_thresh) cx_phase_unlock_exit: mutex_unlock(&cx_mutex); cx_phase_ctrl_exit: - sensor_mgr_set_threshold(trig_thresh->sensor_id, + if (trig_thresh->cur_state != trig_thresh->trip_triggered) { + sensor_mgr_set_threshold(trig_thresh->sensor_id, trig_thresh->threshold); + trig_thresh->cur_state = trig_thresh->trip_triggered; + } return; } @@ -3850,8 +3857,11 @@ static void vdd_restriction_notify(struct therm_threshold *trig_thresh) unlock_and_exit: mutex_unlock(&vdd_rstr_mutex); set_and_exit: - sensor_mgr_set_threshold(trig_thresh->sensor_id, + if (trig_thresh->cur_state != trig_thresh->trip_triggered) { + sensor_mgr_set_threshold(trig_thresh->sensor_id, trig_thresh->threshold); + trig_thresh->cur_state = trig_thresh->trip_triggered; + } return; } @@ -3899,8 +3909,11 @@ static void ocr_notify(struct therm_threshold *trig_thresh) unlock_and_exit: mutex_unlock(&ocr_mutex); set_and_exit: - sensor_mgr_set_threshold(trig_thresh->sensor_id, - trig_thresh->threshold); + if (trig_thresh->cur_state != trig_thresh->trip_triggered) { + sensor_mgr_set_threshold(trig_thresh->sensor_id, + trig_thresh->threshold); + trig_thresh->cur_state = trig_thresh->trip_triggered; + } return; } @@ -4088,6 +4101,7 @@ int sensor_mgr_init_threshold(struct device *dev, thresh_ptr[i].trip_triggered = -1; thresh_ptr[i].parent = thresh_inp; thresh_ptr[i].threshold[0].temp = high_temp; + thresh_ptr[i].cur_state = -1; thresh_ptr[i].threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI; thresh_ptr[i].threshold[1].temp = low_temp; @@ -4106,6 +4120,7 @@ int sensor_mgr_init_threshold(struct device *dev, thresh_ptr->trip_triggered = -1; thresh_ptr->parent = thresh_inp; thresh_ptr->threshold[0].temp = high_temp; + thresh_ptr->cur_state = -1; thresh_ptr->threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI; thresh_ptr->threshold[1].temp = low_temp; diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h index cee918c84302..5fed69b01772 100644 --- a/include/linux/msm_thermal.h +++ b/include/linux/msm_thermal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -90,6 +90,7 @@ struct therm_threshold { int32_t trip_triggered; void (*notify)(struct therm_threshold *); struct threshold_info *parent; + int32_t cur_state; }; struct threshold_info { -- GitLab From 7cfaabce7473e3379fc16525c295fb1aba37c6b3 Mon Sep 17 00:00:00 2001 From: Jason Hrycay Date: Fri, 13 Feb 2015 15:56:48 -0600 Subject: [PATCH 375/528] IKQCOMSD1-2616 msm: thermal: Quiet the threshold logs The driver is very spammy when a threshold is crossed, they are useful in the logs, but only the first time we cross them and offline or online a CPU. We see the most spam at the low threshold when the temperature is hovering around that level but isn't useful since we've never hit the high threshold. Change-Id: Ic15769749f79522c5ccf50e8fb575e4e52bba24a Signed-off-by: Jason Hrycay Reviewed-on: http://gerrit.mot.com/715531 SLTApproved: Slta Waiver Submit-Approved: Jira Key Tested-by: Jira Key Reviewed-by: Jason Knopsnyder Reviewed-by: Christopher Fries Signed-off-by: franciscofranco Signed-off-by: Andrey Cherepkov (cherry picked from commit f10a7fb7a06f18cdfe915815f32855d0d310d5df) --- drivers/thermal/msm_thermal.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 789ebe445f7b..59999a43f99f 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -3159,12 +3159,18 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data) return 0; switch (type) { case THERMAL_TRIP_CONFIGURABLE_HI: - if (!(cpu_node->offline)) + if (!(cpu_node->offline)) { + pr_info("%s reached HI temp threshold: %d\n", + cpu_node->sensor_type, temp); cpu_node->offline = 1; + } break; case THERMAL_TRIP_CONFIGURABLE_LOW: - if (cpu_node->offline) + if (cpu_node->offline) { + pr_info("%s reached LOW temp threshold: %d\n", + cpu_node->sensor_type, temp); cpu_node->offline = 0; + } break; default: break; @@ -3176,6 +3182,7 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data) pr_err("Hotplug task is not initialized\n"); return 0; } + /* Adjust cpus offlined bit based on temperature reading. */ static int hotplug_init_cpu_offlined(void) { -- GitLab From c21b4277b4d6b7ef9f61285145b87ab368e4cddc Mon Sep 17 00:00:00 2001 From: Shiju Mathew Date: Wed, 8 Oct 2014 16:44:44 -0400 Subject: [PATCH 376/528] msm: thermal: Update scm calls in KTM with non-atomic calls Update KTM to use scm_call() and scm_call2()instead of scm_call_atomic1() and scm_call2_atomic() respectively to avoid possible race condition. CRs-fixed: 734431 Change-Id: Ibb81c4c15a47d1f66ffa38cb65481e3c48fcb065 Signed-off-by: Shiju Mathew Signed-off-by: Andrey Cherepkov (cherry picked from commit 0238826ccf7113b44e8b5719b82f121b63593ca8) --- drivers/thermal/msm_thermal.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 59999a43f99f..56bc4f236dcb 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -2400,12 +2400,13 @@ static void msm_thermal_bite(int zone_id, long temp) tsens_id, temp); } if (!is_scm_armv8()) { - scm_call_atomic1(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, 0); + scm_call(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, + NULL, 0, NULL, 0); } else { desc.args[0] = 0; desc.arginfo = SCM_ARGS(1); - scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT, - THERM_SECURE_BITE_CMD), &desc); + scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT, + THERM_SECURE_BITE_CMD), &desc); } } -- GitLab From 3e60ad49c0b41de6f67eb160d2f9c6df7536f408 Mon Sep 17 00:00:00 2001 From: Jeff Bernard Date: Fri, 15 May 2015 14:37:21 -0400 Subject: [PATCH 377/528] msm: thermal: Pass correct size of voltage table to IOCTL Fix issue in msm_thermal_process_voltage_table_request. For voltage tables bigger than 16 it is not correclty passing the partial table size to user space. The full size is passed instead of the partial size. For example if reading a table of 18 values the first read returns 16, and the partial read returns 18 but it should return 2. Change-Id: I75943e94341388cca772ee45bc1275fb5d2091d2 Signed-off-by: Jeff Bernard Signed-off-by: Andrey Cherepkov (cherry picked from commit a7033c89c1dc08aec144eca49c6fc39588fbbe80) --- drivers/thermal/msm_thermal-dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c index bf1299847def..ab25987676fc 100644 --- a/drivers/thermal/msm_thermal-dev.c +++ b/drivers/thermal/msm_thermal-dev.c @@ -278,6 +278,7 @@ static long msm_thermal_process_voltage_table_req( voltage->voltage_table[idx] = voltage_table_ptr[cluster_id][table_idx]; } + voltage->voltage_table_len = idx; copy_and_return: ret = copy_to_user((void __user *)(*arg), query, -- GitLab From d7f0e6d87b5afe3b61c646ecec7fdc430341ccb4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 13 Feb 2015 14:36:57 -0800 Subject: [PATCH 378/528] cpumask, nodemask: implement cpumask/nodemask_pr_args() printf family of functions can now format bitmaps using '%*pb[l]' and all cpumask and nodemask formatting will be converted to use it. To ease printing these masks with '%*pb[l]' which require two params - the number of bits and the actual bitmap, this patch implement cpumask_pr_args() and nodemask_pr_args() which can be used to provide arguments for '%*pb[l]' Signed-off-by: Tejun Heo Cc: Rusty Russell Cc: "David S. Miller" Cc: "James E.J. Bottomley" Cc: "John W. Linville" Cc: "Paul E. McKenney" Cc: Benjamin Herrenschmidt Cc: Chris Metcalf Cc: Chris Zankel Cc: Christoph Lameter Cc: Dmitry Torokhov Cc: Fenghua Yu Cc: Greg Kroah-Hartman Cc: Ingo Molnar Cc: Li Zefan Cc: Max Filippov Cc: Mike Travis Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Russell King Cc: Steffen Klassert Cc: Steven Rostedt Cc: Thomas Gleixner Cc: Tony Luck Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Joe Maples (cherry picked from commit 22a62ae747382c4a6475de258d938cefd96d9986) --- include/linux/cpumask.h | 8 ++++++++ include/linux/nodemask.h | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index d08e4d2a9b92..7abda3b903db 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -22,6 +22,14 @@ typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t; */ #define cpumask_bits(maskp) ((maskp)->bits) +/** + * cpumask_pr_args - printf args to output a cpumask + * @maskp: cpumask to be printed + * + * Can be used to provide arguments for '%*pb[l]' when printing a cpumask. + */ +#define cpumask_pr_args(maskp) nr_cpu_ids, cpumask_bits(maskp) + #if NR_CPUS == 1 #define nr_cpu_ids 1 #else diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 73786fb03e1b..c66ef503cf47 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -98,6 +98,23 @@ typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t; extern nodemask_t _unused_nodemask_arg_; +/** + * nodemask_pr_args - printf args to output a nodemask + * @maskp: nodemask to be printed + * + * Can be used to provide arguments for '%*pb[l]' when printing a nodemask. + */ +#define nodemask_pr_args(maskp) MAX_NUMNODES, (maskp)->bits + +/* + * The inline keyword gives the compiler room to decide to inline, or + * not inline a function as it sees best. However, as these functions + * are called in both __init and non-__init functions, if they are not + * inlined we will end up with a section mis-match error (of the type of + * freeable items not being freed). So we must use __always_inline here + * to fix the problem. If other functions in the future also end up in + * this situation they will also need to be annotated as __always_inline + */ #define node_set(node, dst) __node_set((node), &(dst)) static inline void __node_set(int node, volatile nodemask_t *dstp) { -- GitLab From 0cd12f61233cc2548ee31dd74c9b15d09aaa32c9 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 30 Dec 2016 17:42:32 -0600 Subject: [PATCH 379/528] net: socket: don't set sk_uid to garbage value in ->setattr() ->setattr() was recently implemented for socket files to sync the socket inode's uid to the new 'sk_uid' member of struct sock. It does this by copying over the ia_uid member of struct iattr. However, ia_uid is actually only valid when ATTR_UID is set in ia_valid, indicating that the uid is being changed, e.g. by chown. Other metadata operations such as chmod or utimes leave ia_uid uninitialized. Therefore, sk_uid could be set to a "garbage" value from the stack. Fix this by only copying the uid over when ATTR_UID is set. [backport of net e1a3a60a2ebe991605acb14cd58e39c0545e174e] Bug: 16355602 Change-Id: I20e53848e54282b72a388ce12bfa88da5e3e9efe Fixes: 86741ec25462 ("net: core: Add a UID field to struct sock.") Signed-off-by: Eric Biggers Tested-by: Lorenzo Colitti Acked-by: Lorenzo Colitti Signed-off-by: David S. Miller Signed-off-by: Kevin F. Haggerty (cherry picked from commit 23903deb278be49c82e69c99ddcd215f7edf5543) --- net/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/socket.c b/net/socket.c index 2181d4ab5c56..b6603db005d6 100644 --- a/net/socket.c +++ b/net/socket.c @@ -530,7 +530,7 @@ int sockfs_setattr(struct dentry *dentry, struct iattr *iattr) { int err = simple_setattr(dentry, iattr); - if (!err) { + if (!err && (iattr->ia_valid & ATTR_UID)) { struct socket *sock = SOCKET_I(dentry->d_inode); sock->sk->sk_uid = iattr->ia_uid; -- GitLab From 3f8c41e12a80d37f0ec5d7e838203c763f31b329 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Fri, 29 Aug 2014 23:32:05 -0700 Subject: [PATCH 380/528] tcp: whitespace fixes Fix places where there is space before tab, long lines, and awkward if(){, double spacing etc. Add blank line after declaration/initialization. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Joe Maples Conflicts: net/ipv4/tcp_probe.c net/ipv4/tcp_vegas.c (cherry picked from commit 3d84e65abed328b49d863cc016a374750f67c776) --- net/ipv4/tcp_bic.c | 11 ++- net/ipv4/tcp_cong.c | 5 +- net/ipv4/tcp_cubic.c | 18 ++--- net/ipv4/tcp_diag.c | 5 +- net/ipv4/tcp_highspeed.c | 145 +++++++++++++++++++-------------------- net/ipv4/tcp_htcp.c | 6 +- net/ipv4/tcp_hybla.c | 1 - net/ipv4/tcp_illinois.c | 3 +- net/ipv4/tcp_ipv4.c | 5 +- net/ipv4/tcp_scalable.c | 2 +- net/ipv4/tcp_veno.c | 1 - net/ipv4/tcp_westwood.c | 7 +- net/ipv4/tcp_yeah.c | 9 +-- 13 files changed, 102 insertions(+), 116 deletions(-) diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c index f45e1c242440..5a2fc9903ceb 100644 --- a/net/ipv4/tcp_bic.c +++ b/net/ipv4/tcp_bic.c @@ -17,7 +17,6 @@ #include #include - #define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation * max_cwnd = snd_cwnd * beta */ @@ -46,11 +45,10 @@ MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold"); module_param(smooth_part, int, 0644); MODULE_PARM_DESC(smooth_part, "log(B/(B*Smin))/log(B/(B-1))+B, # of RTT from Wmax-B to Wmax"); - /* BIC TCP Parameters */ struct bictcp { u32 cnt; /* increase cwnd by 1 after ACKs */ - u32 last_max_cwnd; /* last maximum snd_cwnd */ + u32 last_max_cwnd; /* last maximum snd_cwnd */ u32 loss_cwnd; /* congestion window at last loss */ u32 last_cwnd; /* the last snd_cwnd */ u32 last_time; /* time when updated last_cwnd */ @@ -103,7 +101,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) /* binary increase */ if (cwnd < ca->last_max_cwnd) { - __u32 dist = (ca->last_max_cwnd - cwnd) + __u32 dist = (ca->last_max_cwnd - cwnd) / BICTCP_B; if (dist > max_increment) @@ -154,7 +152,6 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) bictcp_update(ca, tp->snd_cwnd); tcp_cong_avoid_ai(tp, ca->cnt); } - } /* @@ -177,7 +174,6 @@ static u32 bictcp_recalc_ssthresh(struct sock *sk) ca->loss_cwnd = tp->snd_cwnd; - if (tp->snd_cwnd <= low_window) return max(tp->snd_cwnd >> 1U, 2U); else @@ -188,6 +184,7 @@ static u32 bictcp_undo_cwnd(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); const struct bictcp *ca = inet_csk_ca(sk); + return max(tp->snd_cwnd, ca->loss_cwnd); } @@ -206,12 +203,12 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt) if (icsk->icsk_ca_state == TCP_CA_Open) { struct bictcp *ca = inet_csk_ca(sk); + cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT; ca->delayed_ack += cnt; } } - static struct tcp_congestion_ops bictcp __read_mostly = { .init = bictcp_init, .ssthresh = bictcp_recalc_ssthresh, diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 2ca6c080a4bc..f2c6f3b552be 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -145,7 +145,6 @@ static int __init tcp_congestion_default(void) } late_initcall(tcp_congestion_default); - /* Build string with list of available congestion control values */ void tcp_get_available_congestion_control(char *buf, size_t maxlen) { @@ -157,7 +156,6 @@ void tcp_get_available_congestion_control(char *buf, size_t maxlen) offs += snprintf(buf + offs, maxlen - offs, "%s%s", offs == 0 ? "" : " ", ca->name); - } rcu_read_unlock(); } @@ -189,7 +187,6 @@ void tcp_get_allowed_congestion_control(char *buf, size_t maxlen) offs += snprintf(buf + offs, maxlen - offs, "%s%s", offs == 0 ? "" : " ", ca->name); - } rcu_read_unlock(); } @@ -233,7 +230,6 @@ out: return ret; } - /* Change congestion control for socket */ int tcp_set_congestion_control(struct sock *sk, const char *name) { @@ -372,6 +368,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid); u32 tcp_reno_ssthresh(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); + return max(tp->snd_cwnd >> 1U, 2U); } EXPORT_SYMBOL_GPL(tcp_reno_ssthresh); diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 894b7cea5d7b..24b1f9cb5ecd 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -82,12 +82,13 @@ MODULE_PARM_DESC(hystart_ack_delta, "spacing between ack's indicating train (mse /* BIC TCP Parameters */ struct bictcp { u32 cnt; /* increase cwnd by 1 after ACKs */ - u32 last_max_cwnd; /* last maximum snd_cwnd */ + u32 last_max_cwnd; /* last maximum snd_cwnd */ u32 loss_cwnd; /* congestion window at last loss */ u32 last_cwnd; /* the last snd_cwnd */ u32 last_time; /* time when updated last_cwnd */ u32 bic_origin_point;/* origin point of bic function */ - u32 bic_K; /* time to origin point from the beginning of the current epoch */ + u32 bic_K; /* time to origin point + from the beginning of the current epoch */ u32 delay_min; /* min delay (msec << 3) */ u32 epoch_start; /* beginning of an epoch */ u32 ack_cnt; /* number of acks */ @@ -219,7 +220,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) ca->last_time = tcp_time_stamp; if (ca->epoch_start == 0) { - ca->epoch_start = tcp_time_stamp; /* record the beginning of an epoch */ + ca->epoch_start = tcp_time_stamp; /* record beginning */ ca->ack_cnt = 1; /* start counting */ ca->tcp_cwnd = cwnd; /* syn with cubic */ @@ -263,9 +264,9 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) /* c/rtt * (t-K)^3 */ delta = (cube_rtt_scale * offs * offs * offs) >> (10+3*BICTCP_HZ); - if (t < ca->bic_K) /* below origin*/ + if (t < ca->bic_K) /* below origin*/ bic_target = ca->bic_origin_point - delta; - else /* above origin*/ + else /* above origin*/ bic_target = ca->bic_origin_point + delta; /* cubic function - calc bictcp_cnt*/ @@ -285,13 +286,14 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) /* TCP Friendly */ if (tcp_friendliness) { u32 scale = beta_scale; + delta = (cwnd * scale) >> 3; while (ca->ack_cnt > delta) { /* update tcp cwnd */ ca->ack_cnt -= delta; ca->tcp_cwnd++; } - if (ca->tcp_cwnd > cwnd){ /* if bic is slower than tcp */ + if (ca->tcp_cwnd > cwnd) { /* if bic is slower than tcp */ delta = ca->tcp_cwnd - cwnd; max_cnt = cwnd / delta; if (ca->cnt > max_cnt) @@ -320,7 +322,6 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) bictcp_update(ca, tp->snd_cwnd); tcp_cong_avoid_ai(tp, ca->cnt); } - } static u32 bictcp_recalc_ssthresh(struct sock *sk) @@ -452,7 +453,8 @@ static int __init cubictcp_register(void) * based on SRTT of 100ms */ - beta_scale = 8*(BICTCP_BETA_SCALE+beta)/ 3 / (BICTCP_BETA_SCALE - beta); + beta_scale = 8*(BICTCP_BETA_SCALE+beta) / 3 + / (BICTCP_BETA_SCALE - beta); cube_rtt_scale = (bic_scale * 10); /* 1024*c/rtt */ diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index a56461c21b97..1d745eac7b8f 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. */ - #include #include #include @@ -37,13 +36,13 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, } static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req_v2 *r, struct nlattr *bc) + struct inet_diag_req_v2 *r, struct nlattr *bc) { inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc); } static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, - struct inet_diag_req_v2 *req) + struct inet_diag_req_v2 *req) { return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req); } diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c index 30f27f6b3655..aecca537484f 100644 --- a/net/ipv4/tcp_highspeed.c +++ b/net/ipv4/tcp_highspeed.c @@ -9,7 +9,6 @@ #include #include - /* From AIMD tables from RFC 3649 appendix B, * with fixed-point MD scaled <<8. */ @@ -17,78 +16,78 @@ static const struct hstcp_aimd_val { unsigned int cwnd; unsigned int md; } hstcp_aimd_vals[] = { - { 38, 128, /* 0.50 */ }, - { 118, 112, /* 0.44 */ }, - { 221, 104, /* 0.41 */ }, - { 347, 98, /* 0.38 */ }, - { 495, 93, /* 0.37 */ }, - { 663, 89, /* 0.35 */ }, - { 851, 86, /* 0.34 */ }, - { 1058, 83, /* 0.33 */ }, - { 1284, 81, /* 0.32 */ }, - { 1529, 78, /* 0.31 */ }, - { 1793, 76, /* 0.30 */ }, - { 2076, 74, /* 0.29 */ }, - { 2378, 72, /* 0.28 */ }, - { 2699, 71, /* 0.28 */ }, - { 3039, 69, /* 0.27 */ }, - { 3399, 68, /* 0.27 */ }, - { 3778, 66, /* 0.26 */ }, - { 4177, 65, /* 0.26 */ }, - { 4596, 64, /* 0.25 */ }, - { 5036, 62, /* 0.25 */ }, - { 5497, 61, /* 0.24 */ }, - { 5979, 60, /* 0.24 */ }, - { 6483, 59, /* 0.23 */ }, - { 7009, 58, /* 0.23 */ }, - { 7558, 57, /* 0.22 */ }, - { 8130, 56, /* 0.22 */ }, - { 8726, 55, /* 0.22 */ }, - { 9346, 54, /* 0.21 */ }, - { 9991, 53, /* 0.21 */ }, - { 10661, 52, /* 0.21 */ }, - { 11358, 52, /* 0.20 */ }, - { 12082, 51, /* 0.20 */ }, - { 12834, 50, /* 0.20 */ }, - { 13614, 49, /* 0.19 */ }, - { 14424, 48, /* 0.19 */ }, - { 15265, 48, /* 0.19 */ }, - { 16137, 47, /* 0.19 */ }, - { 17042, 46, /* 0.18 */ }, - { 17981, 45, /* 0.18 */ }, - { 18955, 45, /* 0.18 */ }, - { 19965, 44, /* 0.17 */ }, - { 21013, 43, /* 0.17 */ }, - { 22101, 43, /* 0.17 */ }, - { 23230, 42, /* 0.17 */ }, - { 24402, 41, /* 0.16 */ }, - { 25618, 41, /* 0.16 */ }, - { 26881, 40, /* 0.16 */ }, - { 28193, 39, /* 0.16 */ }, - { 29557, 39, /* 0.15 */ }, - { 30975, 38, /* 0.15 */ }, - { 32450, 38, /* 0.15 */ }, - { 33986, 37, /* 0.15 */ }, - { 35586, 36, /* 0.14 */ }, - { 37253, 36, /* 0.14 */ }, - { 38992, 35, /* 0.14 */ }, - { 40808, 35, /* 0.14 */ }, - { 42707, 34, /* 0.13 */ }, - { 44694, 33, /* 0.13 */ }, - { 46776, 33, /* 0.13 */ }, - { 48961, 32, /* 0.13 */ }, - { 51258, 32, /* 0.13 */ }, - { 53677, 31, /* 0.12 */ }, - { 56230, 30, /* 0.12 */ }, - { 58932, 30, /* 0.12 */ }, - { 61799, 29, /* 0.12 */ }, - { 64851, 28, /* 0.11 */ }, - { 68113, 28, /* 0.11 */ }, - { 71617, 27, /* 0.11 */ }, - { 75401, 26, /* 0.10 */ }, - { 79517, 26, /* 0.10 */ }, - { 84035, 25, /* 0.10 */ }, - { 89053, 24, /* 0.10 */ }, + { 38, 128, /* 0.50 */ }, + { 118, 112, /* 0.44 */ }, + { 221, 104, /* 0.41 */ }, + { 347, 98, /* 0.38 */ }, + { 495, 93, /* 0.37 */ }, + { 663, 89, /* 0.35 */ }, + { 851, 86, /* 0.34 */ }, + { 1058, 83, /* 0.33 */ }, + { 1284, 81, /* 0.32 */ }, + { 1529, 78, /* 0.31 */ }, + { 1793, 76, /* 0.30 */ }, + { 2076, 74, /* 0.29 */ }, + { 2378, 72, /* 0.28 */ }, + { 2699, 71, /* 0.28 */ }, + { 3039, 69, /* 0.27 */ }, + { 3399, 68, /* 0.27 */ }, + { 3778, 66, /* 0.26 */ }, + { 4177, 65, /* 0.26 */ }, + { 4596, 64, /* 0.25 */ }, + { 5036, 62, /* 0.25 */ }, + { 5497, 61, /* 0.24 */ }, + { 5979, 60, /* 0.24 */ }, + { 6483, 59, /* 0.23 */ }, + { 7009, 58, /* 0.23 */ }, + { 7558, 57, /* 0.22 */ }, + { 8130, 56, /* 0.22 */ }, + { 8726, 55, /* 0.22 */ }, + { 9346, 54, /* 0.21 */ }, + { 9991, 53, /* 0.21 */ }, + { 10661, 52, /* 0.21 */ }, + { 11358, 52, /* 0.20 */ }, + { 12082, 51, /* 0.20 */ }, + { 12834, 50, /* 0.20 */ }, + { 13614, 49, /* 0.19 */ }, + { 14424, 48, /* 0.19 */ }, + { 15265, 48, /* 0.19 */ }, + { 16137, 47, /* 0.19 */ }, + { 17042, 46, /* 0.18 */ }, + { 17981, 45, /* 0.18 */ }, + { 18955, 45, /* 0.18 */ }, + { 19965, 44, /* 0.17 */ }, + { 21013, 43, /* 0.17 */ }, + { 22101, 43, /* 0.17 */ }, + { 23230, 42, /* 0.17 */ }, + { 24402, 41, /* 0.16 */ }, + { 25618, 41, /* 0.16 */ }, + { 26881, 40, /* 0.16 */ }, + { 28193, 39, /* 0.16 */ }, + { 29557, 39, /* 0.15 */ }, + { 30975, 38, /* 0.15 */ }, + { 32450, 38, /* 0.15 */ }, + { 33986, 37, /* 0.15 */ }, + { 35586, 36, /* 0.14 */ }, + { 37253, 36, /* 0.14 */ }, + { 38992, 35, /* 0.14 */ }, + { 40808, 35, /* 0.14 */ }, + { 42707, 34, /* 0.13 */ }, + { 44694, 33, /* 0.13 */ }, + { 46776, 33, /* 0.13 */ }, + { 48961, 32, /* 0.13 */ }, + { 51258, 32, /* 0.13 */ }, + { 53677, 31, /* 0.12 */ }, + { 56230, 30, /* 0.12 */ }, + { 58932, 30, /* 0.12 */ }, + { 61799, 29, /* 0.12 */ }, + { 64851, 28, /* 0.11 */ }, + { 68113, 28, /* 0.11 */ }, + { 71617, 27, /* 0.11 */ }, + { 75401, 26, /* 0.10 */ }, + { 79517, 26, /* 0.10 */ }, + { 84035, 25, /* 0.10 */ }, + { 89053, 24, /* 0.10 */ }, }; #define HSTCP_AIMD_MAX ARRAY_SIZE(hstcp_aimd_vals) diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index c1a8175361e8..d40615e7e460 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c @@ -98,7 +98,8 @@ static inline void measure_rtt(struct sock *sk, u32 srtt) } } -static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked, s32 rtt) +static void measure_achieved_throughput(struct sock *sk, + u32 pkts_acked, s32 rtt) { const struct inet_connection_sock *icsk = inet_csk(sk); const struct tcp_sock *tp = tcp_sk(sk); @@ -148,8 +149,8 @@ static inline void htcp_beta_update(struct htcp *ca, u32 minRTT, u32 maxRTT) if (use_bandwidth_switch) { u32 maxB = ca->maxB; u32 old_maxB = ca->old_maxB; - ca->old_maxB = ca->maxB; + ca->old_maxB = ca->maxB; if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { ca->beta = BETA_MIN; ca->modeswitch = 0; @@ -270,6 +271,7 @@ static void htcp_state(struct sock *sk, u8 new_state) case TCP_CA_Open: { struct htcp *ca = inet_csk_ca(sk); + if (ca->undo_last_cong) { ca->last_cong = jiffies; ca->undo_last_cong = 0; diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c index 57bdd17dff4d..b5100aaea1a0 100644 --- a/net/ipv4/tcp_hybla.c +++ b/net/ipv4/tcp_hybla.c @@ -29,7 +29,6 @@ static int rtt0 = 25; module_param(rtt0, int, 0644); MODULE_PARM_DESC(rtt0, "reference rout trip time (ms)"); - /* This is called to refresh values for hybla parameters */ static inline void hybla_recalc_param (struct sock *sk) { diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 86183c4e4fd5..6845012e6fbb 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -284,7 +284,7 @@ static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) delta = (tp->snd_cwnd_cnt * ca->alpha) >> ALPHA_SHIFT; if (delta >= tp->snd_cwnd) { tp->snd_cwnd = min(tp->snd_cwnd + delta / tp->snd_cwnd, - (u32) tp->snd_cwnd_clamp); + (u32)tp->snd_cwnd_clamp); tp->snd_cwnd_cnt = 0; } } @@ -299,7 +299,6 @@ static u32 tcp_illinois_ssthresh(struct sock *sk) return max(tp->snd_cwnd - ((tp->snd_cwnd * ca->beta) >> BETA_SHIFT), 2U); } - /* Extract info for Tcp socket info provided via netlink. */ static void tcp_illinois_info(struct sock *sk, u32 ext, struct sk_buff *skb) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 7ea3c2a80b40..c1a925f501cb 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -89,7 +89,6 @@ int sysctl_tcp_tw_reuse __read_mostly; int sysctl_tcp_low_latency __read_mostly; EXPORT_SYMBOL(sysctl_tcp_low_latency); - #ifdef CONFIG_TCP_MD5SIG static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, __be32 daddr, __be32 saddr, const struct tcphdr *th); @@ -1284,7 +1283,7 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { .send_ack = tcp_v4_reqsk_send_ack, .destructor = tcp_v4_reqsk_destructor, .send_reset = tcp_v4_send_reset, - .syn_ack_timeout = tcp_syn_ack_timeout, + .syn_ack_timeout = tcp_syn_ack_timeout, }; #ifdef CONFIG_TCP_MD5SIG @@ -2629,7 +2628,7 @@ int tcp_seq_open(struct inode *inode, struct file *file) s = ((struct seq_file *)file->private_data)->private; s->family = afinfo->family; - s->last_pos = 0; + s->last_pos = 0; return 0; } EXPORT_SYMBOL(tcp_seq_open); diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c index 8ce55b8aaec8..e018e734a4de 100644 --- a/net/ipv4/tcp_scalable.c +++ b/net/ipv4/tcp_scalable.c @@ -31,10 +31,10 @@ static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) static u32 tcp_scalable_ssthresh(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); + return max(tp->snd_cwnd - (tp->snd_cwnd>>TCP_SCALABLE_MD_SCALE), 2U); } - static struct tcp_congestion_ops tcp_scalable __read_mostly = { .ssthresh = tcp_scalable_ssthresh, .cong_avoid = tcp_scalable_cong_avoid, diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index b4d1858be550..84363b192466 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c @@ -175,7 +175,6 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) } else tp->snd_cwnd_cnt++; } - } if (tp->snd_cwnd < 2) tp->snd_cwnd = 2; diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c index 76a1e23259e1..3c9c80c04e10 100644 --- a/net/ipv4/tcp_westwood.c +++ b/net/ipv4/tcp_westwood.c @@ -42,7 +42,6 @@ struct westwood { u8 reset_rtt_min; /* Reset RTT min to next RTT sample*/ }; - /* TCP Westwood functions and constants */ #define TCP_WESTWOOD_RTT_MIN (HZ/20) /* 50ms */ #define TCP_WESTWOOD_INIT_RTT (20*HZ) /* maybe too conservative?! */ @@ -153,7 +152,6 @@ static inline void update_rtt_min(struct westwood *w) w->rtt_min = min(w->rtt, w->rtt_min); } - /* * @westwood_fast_bw * It is called when we are in fast path. In particular it is called when @@ -208,7 +206,6 @@ static inline u32 westwood_acked_count(struct sock *sk) return w->cumul_ack; } - /* * TCP Westwood * Here limit is evaluated as Bw estimation*RTTmin (for obtaining it @@ -219,6 +216,7 @@ static u32 tcp_westwood_bw_rttmin(const struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); const struct westwood *w = inet_csk_ca(sk); + return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2); } @@ -254,12 +252,12 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event) } } - /* Extract info for Tcp socket info provided via netlink. */ static void tcp_westwood_info(struct sock *sk, u32 ext, struct sk_buff *skb) { const struct westwood *ca = inet_csk_ca(sk); + if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { struct tcpvegas_info info = { .tcpv_enabled = 1, @@ -271,7 +269,6 @@ static void tcp_westwood_info(struct sock *sk, u32 ext, } } - static struct tcp_congestion_ops tcp_westwood __read_mostly = { .init = tcp_westwood_init, .ssthresh = tcp_reno_ssthresh, diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c index bf8321d6f2ef..80e9c70c0079 100644 --- a/net/ipv4/tcp_yeah.c +++ b/net/ipv4/tcp_yeah.c @@ -54,10 +54,8 @@ static void tcp_yeah_init(struct sock *sk) /* Ensure the MD arithmetic works. This is somewhat pedantic, * since I don't think we will see a cwnd this large. :) */ tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128); - } - static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, s32 rtt_us) { const struct inet_connection_sock *icsk = inet_csk(sk); @@ -84,7 +82,7 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) /* Scalable */ tp->snd_cwnd_cnt += yeah->pkts_acked; - if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){ + if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)) { if (tp->snd_cwnd < tp->snd_cwnd_clamp) tp->snd_cwnd++; tp->snd_cwnd_cnt = 0; @@ -120,7 +118,6 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) */ if (after(ack, yeah->vegas.beg_snd_nxt)) { - /* We do the Vegas calculations only if we got enough RTT * samples that we can be reasonably sure that we got * at least one RTT sample that wasn't from a delayed ACK. @@ -189,7 +186,6 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) } yeah->lastQ = queue; - } /* Save the extent of the current window so we can use this @@ -205,7 +201,8 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) } } -static u32 tcp_yeah_ssthresh(struct sock *sk) { +static u32 tcp_yeah_ssthresh(struct sock *sk) +{ const struct tcp_sock *tp = tcp_sk(sk); struct yeah *yeah = inet_csk_ca(sk); u32 reduction; -- GitLab From 61fd333e4c5cd638fe0b1c8ef08e3c6d187add36 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 8 Sep 2014 08:06:07 -0700 Subject: [PATCH 381/528] tcp: remove dst refcount false sharing for prequeue mode Alexander Duyck reported high false sharing on dst refcount in tcp stack when prequeue is used. prequeue is the mechanism used when a thread is blocked in recvmsg()/read() on a TCP socket, using a blocking model rather than select()/poll()/epoll() non blocking one. We already try to use RCU in input path as much as possible, but we were forced to take a refcount on the dst when skb escaped RCU protected region. When/if the user thread runs on different cpu, dst_release() will then touch dst refcount again. Commit 093162553c33 (tcp: force a dst refcount when prequeue packet) was an example of a race fix. It turns out the only remaining usage of skb->dst for a packet stored in a TCP socket prequeue is IP early demux. We can add a logic to detect when IP early demux is probably going to use skb->dst. Because we do an optimistic check rather than duplicate existing logic, we need to guard inet_sk_rx_dst_set() and inet6_sk_rx_dst_set() from using a NULL dst. Many thanks to Alexander for providing a nice bug report, git bisection, and reproducer. Tested using Alexander script on a 40Gb NIC, 8 RX queues. Hosts have 24 cores, 48 hyper threads. echo 0 >/proc/sys/net/ipv4/tcp_autocorking for i in `seq 0 47` do for j in `seq 0 2` do netperf -H $DEST -t TCP_STREAM -l 1000 \ -c -C -T $i,$i -P 0 -- \ -m 64 -s 64K -D & done done Before patch : ~6Mpps and ~95% cpu usage on receiver After patch : ~9Mpps and ~35% cpu usage on receiver. Signed-off-by: Eric Dumazet Reported-by: Alexander Duyck Signed-off-by: David S. Miller (cherry picked from commit f244710f0713295af9e5866e40bff759ebf512ec) --- net/ipv4/tcp_ipv4.c | 20 ++++++++++++++++---- net/ipv6/tcp_ipv6.c | 15 +++++++++------ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index c1a925f501cb..eb95416bc802 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1937,7 +1937,17 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) skb_queue_len(&tp->ucopy.prequeue) == 0) return false; - skb_dst_force(skb); + /* Before escaping RCU protected region, we need to take care of skb + * dst. Prequeue is only enabled for established sockets. + * For such sockets, we might need the skb dst only to set sk->sk_rx_dst + * Instead of doing full sk_rx_dst validity here, let's perform + * an optimistic check. + */ + if (likely(sk->sk_rx_dst)) + skb_dst_drop(skb); + else + skb_dst_force(skb); + __skb_queue_tail(&tp->ucopy.prequeue, skb); tp->ucopy.memory += skb->truesize; if (tp->ucopy.memory > sk->sk_rcvbuf) { @@ -2152,9 +2162,11 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - dst_hold(dst); - sk->sk_rx_dst = dst; - inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; + if (dst) { + dst_hold(dst); + sk->sk_rx_dst = dst; + inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; + } } EXPORT_SYMBOL(inet_sk_rx_dst_set); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5ef9d7a0f02e..b39df817c166 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -94,13 +94,16 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - const struct rt6_info *rt = (const struct rt6_info *)dst; - dst_hold(dst); - sk->sk_rx_dst = dst; - inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; - if (rt->rt6i_node) - inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; + if (dst) { + const struct rt6_info *rt = (const struct rt6_info *)dst; + + dst_hold(dst); + sk->sk_rx_dst = dst; + inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; + if (rt->rt6i_node) + inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; + } } static void tcp_v6_hash(struct sock *sk) -- GitLab From e0d88ea4a73127ef0364a9be87bfd516f328e72c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 25 Nov 2014 07:40:04 -0800 Subject: [PATCH 382/528] tcp: fix possible NULL dereference in tcp_vX_send_reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit ca777eff51f7 ("tcp: remove dst refcount false sharing for prequeue mode") we have to relax check against skb dst in tcp_v[46]_send_reset() if prequeue dropped the dst. If a socket is provided, a full lookup was done to find this socket, so the dst test can be skipped. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88191 Reported-by: Jaša Bartelj Signed-off-by: Eric Dumazet Reported-by: Daniel Borkmann Fixes: ca777eff51f7 ("tcp: remove dst refcount false sharing for prequeue mode") Signed-off-by: David S. Miller (cherry picked from commit 88361ad54df5643089c23ad8f9d09de69ad2f778) --- net/ipv4/tcp_ipv4.c | 5 ++++- net/ipv6/tcp_ipv6.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index eb95416bc802..cf92f7c073fd 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -628,7 +628,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) if (th->rst) return; - if (skb_rtable(skb)->rt_type != RTN_LOCAL) + /* If sk not NULL, it means we did a successful lookup and incoming + * route had to be correct. prequeue might have dropped our dst. + */ + if (!sk && skb_rtable(skb)->rt_type != RTN_LOCAL) return; /* Swap the send and the receive. */ diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index b39df817c166..be84988871fb 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -837,7 +837,10 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) if (th->rst) return; - if (!ipv6_unicast_destination(skb)) + /* If sk not NULL, it means we did a successful lookup and incoming + * route had to be correct. prequeue might have dropped our dst. + */ + if (!sk && !ipv6_unicast_destination(skb)) return; #ifdef CONFIG_TCP_MD5SIG -- GitLab From cc18012c63332088563c8bb107158af4ca52ed88 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 9 Dec 2014 09:56:08 -0800 Subject: [PATCH 383/528] tcp: fix more NULL deref after prequeue changes When I cooked commit c3658e8d0f1 ("tcp: fix possible NULL dereference in tcp_vX_send_reset()") I missed other spots we could deref a NULL skb_dst(skb) Again, if a socket is provided, we do not need skb_dst() to get a pointer to network namespace : sock_net(sk) is good enough. [Backport of net-next 0f85feae6b710ced3abad5b2b47d31dfcb956b62] Bug: 16355602 Change-Id: Ibe1def7979625ee7902bff2f33ec8945b9945948 Reported-by: Dann Frazier Bisected-by: Dann Frazier Tested-by: Dann Frazier Signed-off-by: Eric Dumazet Fixes: ca777eff51f7 ("tcp: remove dst refcount false sharing for prequeue mode") Signed-off-by: David S. Miller (cherry picked from commit a0826aa38cce5c3e3bbbf844ef2c2a7e9baba402) --- net/ipv4/tcp_ipv4.c | 4 ++-- net/ipv6/tcp_ipv6.c | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index cf92f7c073fd..34a548e42681 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -653,6 +653,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_base = (unsigned char *)&rep; arg.iov[0].iov_len = sizeof(rep.th); + net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); #ifdef CONFIG_TCP_MD5SIG hash_location = tcp_parse_md5sig_option(th); if (!sk && hash_location) { @@ -663,7 +664,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) * Incoming packet is checked with md5 hash with finding key, * no RST generated if md5 hash doesn't match. */ - sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), + sk1 = __inet_lookup_listener(net, &tcp_hashinfo, ip_hdr(skb)->saddr, th->source, ip_hdr(skb)->daddr, ntohs(th->source), inet_iif(skb)); @@ -711,7 +712,6 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) if (sk) arg.bound_dev_if = sk->sk_bound_dev_if; - net = dev_net(skb_dst(skb)->dev); arg.tos = ip_hdr(skb)->tos; ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), skb, ip_hdr(skb)->saddr, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index be84988871fb..8c030aabc301 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -726,15 +726,15 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { }; #endif -static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, - u32 tsval, u32 tsecr, +static void tcp_v6_send_response(struct sock *sk, struct sk_buff *skb, u32 seq, + u32 ack, u32 win, u32 tsval, u32 tsecr, struct tcp_md5sig_key *key, int rst, u8 tclass) { const struct tcphdr *th = tcp_hdr(skb); struct tcphdr *t1; struct sk_buff *buff; struct flowi6 fl6; - struct net *net = dev_net(skb_dst(skb)->dev); + struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); struct dst_entry *dst; @@ -879,7 +879,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - (th->doff << 2); - tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, key, 1, 0); + tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, key, 1, 0); #ifdef CONFIG_TCP_MD5SIG release_sk1: @@ -890,11 +890,12 @@ release_sk1: #endif } -static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, - u32 win, u32 tsval, u32 tsecr, +static void tcp_v6_send_ack(struct sock *sk, struct sk_buff *skb, + u32 seq, u32 ack, u32 win, u32 tsval, u32 tsecr, struct tcp_md5sig_key *key, u8 tclass) { - tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, key, 0, tclass); + tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, key, 0, + tclass); } static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) @@ -902,7 +903,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) struct inet_timewait_sock *tw = inet_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcp_time_stamp + tcptw->tw_ts_offset, tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw), @@ -919,7 +920,7 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, * exception of segments, MUST be right-shifted by * Rcv.Wind.Shift bits: */ - tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, + tcp_v6_send_ack(sk, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd >> inet_rsk(req)->rcv_wscale, tcp_time_stamp, req->ts_recent, tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0); -- GitLab From 97ef4ede00ceb3e2aef2b078bf290f57d2b693a1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 14 Dec 2015 14:08:53 -0800 Subject: [PATCH 384/528] net: fix IP early demux races [ Upstream commit 5037e9ef9454917b047f9f3a19b4dd179fbf7cd4 ] David Wilder reported crashes caused by dst reuse. I am seeing a crash on a distro V4.2.3 kernel caused by a double release of a dst_entry. In ipv4_dst_destroy() the call to list_empty() finds a poisoned next pointer, indicating the dst_entry has already been removed from the list and freed. The crash occurs 18 to 24 hours into a run of a network stress exerciser. Thanks to his detailed report and analysis, we were able to understand the core issue. IP early demux can associate a dst to skb, after a lookup in TCP/UDP sockets. When socket cache is not properly set, we want to store into sk->sk_dst_cache the dst for future IP early demux lookups, by acquiring a stable refcount on the dst. Problem is this acquisition is simply using an atomic_inc(), which works well, unless the dst was queued for destruction from dst_release() noticing dst refcount went to zero, if DST_NOCACHE was set on dst. We need to make sure current refcount is not zero before incrementing it, or risk double free as David reported. This patch, being a stable candidate, adds two new helpers, and use them only from IP early demux problematic paths. It might be possible to merge in net-next skb_dst_force() and skb_dst_force_safe(), but I prefer having the smallest patch for stable kernels : Maybe some skb_dst_force() callers do not expect skb->dst can suddenly be cleared. Can probably be backported back to linux-3.6 kernels Reported-by: David J. Wilder Tested-by: David J. Wilder Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Sasha Levin (cherry picked from commit 16e33ff235838ec175fb36dd9b343dcdb90e86db) --- include/net/dst.h | 33 +++++++++++++++++++++++++++++++++ include/net/sock.h | 2 +- net/ipv4/tcp_ipv4.c | 5 ++--- net/ipv6/tcp_ipv6.c | 3 +-- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index e0c97f5a57cf..07ac25afb4e1 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -306,6 +306,39 @@ static inline void skb_dst_force(struct sk_buff *skb) } } +/** + * dst_hold_safe - Take a reference on a dst if possible + * @dst: pointer to dst entry + * + * This helper returns false if it could not safely + * take a reference on a dst. + */ +static inline bool dst_hold_safe(struct dst_entry *dst) +{ + if (dst->flags & DST_NOCACHE) + return atomic_inc_not_zero(&dst->__refcnt); + dst_hold(dst); + return true; +} + +/** + * skb_dst_force_safe - makes sure skb dst is refcounted + * @skb: buffer + * + * If dst is not yet refcounted and not destroyed, grab a ref on it. + */ +static inline void skb_dst_force_safe(struct sk_buff *skb) +{ + if (skb_dst_is_noref(skb)) { + struct dst_entry *dst = skb_dst(skb); + + if (!dst_hold_safe(dst)) + dst = NULL; + + skb->_skb_refdst = (unsigned long)dst; + } +} + /** * __skb_tunnel_rx - prepare skb for rx reinsert diff --git a/include/net/sock.h b/include/net/sock.h index 29ccc8346bbf..abaa5d66db07 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -758,7 +758,7 @@ static inline bool sk_stream_memory_free(const struct sock *sk) static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb) { /* dont let skb dst not refcounted, we are going to leave rcu lock */ - skb_dst_force(skb); + skb_dst_force_safe(skb); if (!sk->sk_backlog.tail) sk->sk_backlog.head = skb; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 34a548e42681..24225eca8481 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1949,7 +1949,7 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) if (likely(sk->sk_rx_dst)) skb_dst_drop(skb); else - skb_dst_force(skb); + skb_dst_force_safe(skb); __skb_queue_tail(&tp->ucopy.prequeue, skb); tp->ucopy.memory += skb->truesize; @@ -2165,8 +2165,7 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - if (dst) { - dst_hold(dst); + if (dst && dst_hold_safe(dst)) { sk->sk_rx_dst = dst; inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8c030aabc301..352eba7ab50d 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -95,10 +95,9 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - if (dst) { + if (dst && dst_hold_safe(dst)) { const struct rt6_info *rt = (const struct rt6_info *)dst; - dst_hold(dst); sk->sk_rx_dst = dst; inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; if (rt->rt6i_node) -- GitLab From 989a75f95c3af018e0c2ea5239b35d53dab610d0 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Mon, 11 Dec 2017 00:05:46 -0800 Subject: [PATCH 385/528] tcp md5sig: Use skb's saddr when replying to an incoming segment [ Upstream commit 30791ac41927ebd3e75486f9504b6d2280463bf0 ] The MD5-key that belongs to a connection is identified by the peer's IP-address. When we are in tcp_v4(6)_reqsk_send_ack(), we are replying to an incoming segment from tcp_check_req() that failed the seq-number checks. Thus, to find the correct key, we need to use the skb's saddr and not the daddr. This bug seems to have been there since quite a while, but probably got unnoticed because the consequences are not catastrophic. We will call tcp_v4_reqsk_send_ack only to send a challenge-ACK back to the peer, thus the connection doesn't really fail. Fixes: 9501f9722922 ("tcp md5sig: Let the caller pass appropriate key for tcp_v{4,6}_do_calc_md5_hash().") Signed-off-by: Christoph Paasch Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: ahmedradaideh aviraxp bp for 3.10 (cherry picked from commit c8c6ac654df077935a24eca1b367608c170323b1) --- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 24225eca8481..ab3a2b9d6baa 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -835,7 +835,7 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, tcp_time_stamp, req->ts_recent, 0, - tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, + tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr, AF_INET), inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, ip_hdr(skb)->tos); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 352eba7ab50d..1ba7f4f94493 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -922,7 +922,7 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, tcp_v6_send_ack(sk, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd >> inet_rsk(req)->rcv_wscale, tcp_time_stamp, req->ts_recent, - tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0); + tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr), 0); } -- GitLab From c472c4471be86a01c114beefb35bde8e20a2bac2 Mon Sep 17 00:00:00 2001 From: Wang Han Date: Mon, 15 May 2017 16:02:15 +0530 Subject: [PATCH 386/528] Revert "tcp: do not lock listener to process SYN packets" It's been reported that this change causes kernel crashes. This patch is part of a patch series and it probably depends on some other changes. Upstream also has multiple fixes for this change that should probably applied along with it. This commit was meant to fix CVE-2017-5972, but as is it can render the system unstable, so revert it. Example of crash caused by this change: Unable to handle kernel NULL pointer dereference at virtual address 00000000 [00000000] *pgd=0000000000000000, *pud=0000000000000000 Internal error: Oops: 9600004% [#!] PREMPT SMP Modules linked in: CPU: 1 PID: 17801 Comm: pdnsd Not tainted 3.10.107-perf #1 Hardware name: Qualcomm Technologies, Inc. MSM8994v2.1 MTP (DT) task: ffffffc04179e000 ti: ffffffc0342a8000 task.ti: ffffffc0342a8000 PCis at tcp_check_req+0x388/0x544 LR is at tcp_check_rea+0x340/0x544 pc : [] lr : [] pstate: 40000145 sp : fbffffc0342!B8f0 x29: ffffffc0340ab8f0 x28: ffffffc0012d4240 x27: 0000000000000001 x26: 0000000000000000 x25: ffffffc01d6e4000 x24: 0000000000001000 x23: ffffffc02ffe8298 x22: ffffffc041539680 x21: ffffffc01d6e4308 x20: ffffffc08c7e1b00 x19: ffffffc01d6e4318 x18: ffffffc0016d4240 x17: 00000000000101d0 x16: ffffffc035ce67c8 x15: 000000001bc0e897 x14: ffffffc001052e10 x13: ffffffc0baabf280 x12: 0000000000000000 x11: 0000000000000000 x10: 0000000000000000 x9 : ffffffc001051f90 x8 : 0000000000000030 x7 : 0000000000000020 x6 : 000000000000ffd7 x5 : 000000000000fb00 x4 : 000000006fdbb7eb x3 : 00000000c13fe000 x2 : 0000000000000000 1 : ffffffc088325c80 x0 : 0 0000 000000000 Process pdnsd (pid: 1701, stack limit = 0xffffffc0342a8058) Call trace: [] tcp_check_req+0x388/0x544 [] tcp_v4_do_rcv+0x250/0x34c [] tcp_v4_rcv+0x700/0x768 [] ip_local_deliver_finish+0x100/0x24c [] ip_local_deliver+0xb0/0xc4 [] ip_rcv_finish+0xdc/0x2c4 [] ip_rcv+0x26c/0x310 [] __netif_receive_skb_core+0x234/0x7e4 [] __netif_receive_skb+0x28/0x80 [] process_backlog+0xb0/0x184 [] net_rx_action+0x17c/0x300 [] __do_softirq+0x13c/0x328 [] do_softirq+0x5c/0x60 [] local_bh_enable_ip+0xb4/0xc8 [] _raw_spin_unlock_bh+0x38/0x40 This reverts commit bf35e60ab3be08a5a1d798d0c4aee0c76f64b8a8. Change-Id: I2bda543f514239f1ce8f0439be6fa27c4468e949 (cherry picked from commit 51e3f99fe4c7a5709afa9baa1f770c424dec58cc) --- net/ipv4/tcp_ipv4.c | 8 +------- net/ipv6/tcp_ipv6.c | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ab3a2b9d6baa..fee6a3b4dee1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1803,7 +1803,7 @@ static __sum16 tcp_v4_checksum_init(struct sk_buff *skb) /* The socket must have it's spinlock held when we get - * here, unless it is a TCP_LISTEN socket. + * here. * * We have a potential double-lock case here, so even when * doing backlog processing we use the BH locking scheme. @@ -2061,11 +2061,6 @@ process: skb->dev = NULL; - if (sk->sk_state == TCP_LISTEN) { - ret = tcp_v4_do_rcv(sk, skb); - goto put_and_return; - } - bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { @@ -2089,7 +2084,6 @@ process: } bh_unlock_sock(sk); -put_and_return: sock_put(sk); return ret; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 1ba7f4f94493..9e14d6fd9a42 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1319,7 +1319,7 @@ static __sum16 tcp_v6_checksum_init(struct sk_buff *skb) } /* The socket must have it's spinlock held when we get - * here, unless it is a TCP_LISTEN socket. + * here. * * We have a potential double-lock case here, so even when * doing backlog processing we use the BH locking scheme. @@ -1526,11 +1526,6 @@ process: skb->dev = NULL; - if (sk->sk_state == TCP_LISTEN) { - ret = tcp_v6_do_rcv(sk, skb); - goto put_and_return; - } - bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { @@ -1554,7 +1549,6 @@ process: } bh_unlock_sock(sk); -put_and_return: sock_put(sk); return ret ? -1 : 0; -- GitLab From 42cf1ae82e340257a9362ab0fd5068f6837cc4f5 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 4 Nov 2016 02:23:43 +0900 Subject: [PATCH 387/528] net: inet: Support UID-based routing in IP protocols. - Use the UID in routing lookups made by protocol connect() and sendmsg() functions. - Make sure that routing lookups triggered by incoming packets (e.g., Path MTU discovery) take the UID of the socket into account. - For packets not associated with a userspace socket, (e.g., ping replies) use UID 0 inside the user namespace corresponding to the network namespace the socket belongs to. This allows all namespaces to apply routing and iptables rules to kernel-originated traffic in that namespaces by matching UID 0. This is better than using the UID of the kernel socket that is sending the traffic, because the UID of kernel sockets created at namespace creation time (e.g., the per-processor ICMP and TCP sockets) is the UID of the user that created the socket, which might not be mapped in the namespace. [Backport of net-next e2d118a1cb5e60d077131a09db1d81b90a5295fe] Bug: 16355602 Change-Id: I910504b508948057912bc188fd1e8aca28294de3 Tested: compiles allnoconfig, allyesconfig, allmodconfig Tested: https://android-review.googlesource.com/253302 Signed-off-by: Lorenzo Colitti Signed-off-by: David S. Miller Git-commit: 327455146c7467670e7c94b089ef88f57bc57311 Git-repo: https://android.googlesource.com/kernel/common.git [resolved trivial merge conflicts] Signed-off-by: Srinivasarao P [Resolved trivial merge conflicts] Signed-off-by: GreyLeshy (cherry picked from commit 91a9ac15fe7e7fcfd3d185ab2d887db8043dd845) --- include/net/flow.h | 4 +++- include/net/ip.h | 1 + include/net/ip6_route.h | 5 +++-- include/net/route.h | 5 +++-- net/ipv4/icmp.c | 2 ++ net/ipv4/inet_connection_sock.c | 6 ++++-- net/ipv4/ip_output.c | 3 ++- net/ipv4/ping.c | 3 ++- net/ipv4/raw.c | 2 +- net/ipv4/route.c | 26 +++++++++++++++----------- net/ipv4/syncookies.c | 2 +- net/ipv4/tcp_ipv4.c | 11 +++++++---- net/ipv4/udp.c | 3 ++- net/ipv6/af_inet6.c | 1 + net/ipv6/ah6.c | 4 ++-- net/ipv6/datagram.c | 1 + net/ipv6/esp6.c | 4 ++-- net/ipv6/icmp.c | 6 ++++-- net/ipv6/inet6_connection_sock.c | 2 ++ net/ipv6/ip6_gre.c | 4 ++++ net/ipv6/ip6_tunnel.c | 3 +++ net/ipv6/ipcomp6.c | 4 ++-- net/ipv6/netfilter.c | 1 + net/ipv6/ping.c | 1 + net/ipv6/raw.c | 1 + net/ipv6/route.c | 12 ++++++++---- net/ipv6/syncookies.c | 1 + net/ipv6/tcp_ipv6.c | 2 ++ net/ipv6/udp.c | 1 + net/l2tp/l2tp_ip6.c | 1 + 30 files changed, 83 insertions(+), 39 deletions(-) diff --git a/include/net/flow.h b/include/net/flow.h index 1964eeb57a32..15ecdd07e192 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -89,7 +89,8 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, __u32 mark, __u8 tos, __u8 scope, __u8 proto, __u8 flags, __be32 daddr, __be32 saddr, - __be16 dport, __be16 sport) + __be16 dport, __be16 sport, + kuid_t uid) { fl4->flowi4_oif = oif; fl4->flowi4_iif = LOOPBACK_IFINDEX; @@ -99,6 +100,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, fl4->flowi4_proto = proto; fl4->flowi4_flags = flags; fl4->flowi4_secid = 0; + fl4->flowi4_uid = uid; fl4->daddr = daddr; fl4->saddr = saddr; fl4->fl4_dport = dport; diff --git a/include/net/ip.h b/include/net/ip.h index 5bb62242de0e..c02d09be8ad0 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -155,6 +155,7 @@ struct ip_reply_arg { /* -1 if not needed */ int bound_dev_if; u8 tos; + kuid_t uid; }; #define IP_REPLY_ARG_NOSRCCHECK 1 diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 8d977b343647..30f068fafaad 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -136,10 +136,11 @@ extern int rt6_route_rcv(struct net_device *dev, const struct in6_addr *gwaddr); extern void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, - int oif, u32 mark); + int oif, u32 mark, kuid_t uid); extern void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu); -extern void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark); +extern void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, + kuid_t uid); extern void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk); struct netlink_callback; diff --git a/include/net/route.h b/include/net/route.h index 2ea40c1b5e00..4fe676279a47 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -142,7 +142,7 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos, RT_SCOPE_UNIVERSE, proto, sk ? inet_sk_flowi_flags(sk) : 0, - daddr, saddr, dport, sport); + daddr, saddr, dport, sport, sock_net_uid(net, sk)); if (sk) security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); return ip_route_output_flow(net, fl4, sk); @@ -253,7 +253,8 @@ static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 flow_flags |= FLOWI_FLAG_CAN_SLEEP; flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, - protocol, flow_flags, dst, src, dport, sport); + protocol, flow_flags, dst, src, dport, sport, + sk->sk_uid); } static inline struct rtable *ip_route_connect(struct flowi4 *fl4, diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 5af8781b65e1..59e63dcb80da 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -364,6 +364,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) fl4.daddr = daddr; fl4.saddr = saddr; fl4.flowi4_mark = mark; + fl4.flowi4_uid = sock_net_uid(net, NULL); fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); fl4.flowi4_proto = IPPROTO_ICMP; security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); @@ -395,6 +396,7 @@ static struct rtable *icmp_route_lookup(struct net *net, param->replyopts.opt.opt.faddr : iph->saddr); fl4->saddr = saddr; fl4->flowi4_mark = mark; + fl4->flowi4_uid = sock_net_uid(net, NULL); fl4->flowi4_tos = RT_TOS(tos); fl4->flowi4_proto = IPPROTO_ICMP; fl4->fl4_icmp_type = type; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index d0025a242630..912cb4dedfe5 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -429,7 +429,8 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, sk->sk_protocol, flags, (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, - ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); + ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport, + sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) @@ -465,7 +466,8 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, - ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); + ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport, + sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 7ad943e475b6..f6990ed05536 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1494,7 +1494,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr, RT_SCOPE_UNIVERSE, ip_hdr(skb)->protocol, ip_reply_arg_flowi_flags(arg), daddr, saddr, - tcp_hdr(skb)->source, tcp_hdr(skb)->dest); + tcp_hdr(skb)->source, tcp_hdr(skb)->dest, + arg->uid); security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 547a3d63f322..a2007c06f81e 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -790,7 +790,8 @@ int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, - inet_sk_flowi_flags(sk), faddr, saddr, 0, 0); + inet_sk_flowi_flags(sk), faddr, saddr, 0, 0, + sk->sk_uid); security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(net, &fl4, sk); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index a2e361c956b7..7e1588ccf60d 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -576,7 +576,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP | (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), - daddr, saddr, 0, 0); + daddr, saddr, 0, 0, sk->sk_uid); if (!inet->hdrincl) { err = raw_probe_proto_opt(&fl4, msg); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c564dcf2c80c..292c08985b0f 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -515,7 +515,8 @@ void __ip_select_ident(struct iphdr *iph, int segs) } EXPORT_SYMBOL(__ip_select_ident); -static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk, +static void __build_flow_key(const struct net *net, struct flowi4 *fl4, + const struct sock *sk, const struct iphdr *iph, int oif, u8 tos, u8 prot, u32 mark, int flow_flags) @@ -531,7 +532,8 @@ static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk, flowi4_init_output(fl4, oif, mark, tos, RT_SCOPE_UNIVERSE, prot, flow_flags, - iph->daddr, iph->saddr, 0, 0); + iph->daddr, iph->saddr, 0, 0, + sock_net_uid(net, sk)); } static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb, @@ -543,7 +545,7 @@ static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb, u8 prot = iph->protocol; u32 mark = skb->mark; - __build_flow_key(fl4, sk, iph, oif, tos, prot, mark, 0); + __build_flow_key(sock_net(sk), fl4, sk, iph, oif, tos, prot, mark, 0); } static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk) @@ -560,7 +562,7 @@ static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk) RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk), - daddr, inet->inet_saddr, 0, 0); + daddr, inet->inet_saddr, 0, 0, sk->sk_uid); rcu_read_unlock(); } @@ -762,7 +764,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf rt = (struct rtable *) dst; - __build_flow_key(&fl4, sk, iph, oif, tos, prot, mark, 0); + __build_flow_key(sock_net(sk), &fl4, sk, iph, oif, tos, prot, mark, 0); __ip_do_redirect(rt, skb, &fl4, true); } @@ -980,7 +982,7 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, if (!mark) mark = IP4_REPLY_MARK(net, skb->mark); - __build_flow_key(&fl4, NULL, iph, oif, + __build_flow_key(net, &fl4, NULL, iph, oif, RT_TOS(iph->tos), protocol, mark, flow_flags); rt = __ip_route_output_key(net, &fl4); if (!IS_ERR(rt)) { @@ -996,7 +998,7 @@ static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) struct flowi4 fl4; struct rtable *rt; - __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); + __build_flow_key(sock_net(sk), &fl4, sk, iph, 0, 0, 0, 0, 0); if (!fl4.flowi4_mark) fl4.flowi4_mark = IP4_REPLY_MARK(sock_net(sk), skb->mark); @@ -1015,6 +1017,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) struct rtable *rt; struct dst_entry *odst = NULL; bool new = false; + struct net *net = sock_net(sk); bh_lock_sock(sk); odst = sk_dst_get(sk); @@ -1024,7 +1027,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) goto out; } - __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); + __build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0); rt = (struct rtable *)odst; if (odst->obsolete && odst->ops->check(odst, 0) == NULL) { @@ -1064,7 +1067,7 @@ void ipv4_redirect(struct sk_buff *skb, struct net *net, struct flowi4 fl4; struct rtable *rt; - __build_flow_key(&fl4, NULL, iph, oif, + __build_flow_key(net, &fl4, NULL, iph, oif, RT_TOS(iph->tos), protocol, mark, flow_flags); rt = __ip_route_output_key(net, &fl4); if (!IS_ERR(rt)) { @@ -1079,9 +1082,10 @@ void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk) const struct iphdr *iph = (const struct iphdr *) skb->data; struct flowi4 fl4; struct rtable *rt; + struct net *net = sock_net(sk); - __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); - rt = __ip_route_output_key(sock_net(sk), &fl4); + __build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0); + rt = __ip_route_output_key(net, &fl4); if (!IS_ERR(rt)) { __ip_do_redirect(rt, skb, &fl4, false); ip_rt_put(rt); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 5abb45e281be..296a0a42b2b8 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -353,7 +353,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP, inet_sk_flowi_flags(sk), (opt && opt->srr) ? opt->faddr : ireq->rmt_addr, - ireq->loc_addr, th->source, th->dest); + ireq->loc_addr, th->source, th->dest, sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(sock_net(sk), &fl4); if (IS_ERR(rt)) { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fee6a3b4dee1..8b039a79c8d4 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -713,6 +713,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.bound_dev_if = sk->sk_bound_dev_if; arg.tos = ip_hdr(skb)->tos; + arg.uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL); ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), skb, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len); @@ -733,7 +734,8 @@ release_sk1: outside socket context is ugly, certainly. What can I do? */ -static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, +static void tcp_v4_send_ack(const struct sock *sk, struct sk_buff *skb, + u32 seq, u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, struct tcp_md5sig_key *key, int reply_flags, u8 tos) @@ -748,7 +750,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, ]; } rep; struct ip_reply_arg arg; - struct net *net = dev_net(skb_dst(skb)->dev); + struct net *net = sock_net(sk); memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&arg, 0, sizeof(arg)); @@ -797,6 +799,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, if (oif) arg.bound_dev_if = oif; arg.tos = tos; + arg.uid = sock_net_uid(net, sk_fullsock(sk) ? sk : NULL); ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), skb, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len); @@ -809,7 +812,7 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) struct inet_timewait_sock *tw = inet_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v4_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcp_time_stamp + tcptw->tw_ts_offset, tcptw->tw_ts_recent, @@ -828,7 +831,7 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV * sk->sk_state == TCP_SYN_RECV -> for Fast Open. */ - tcp_v4_send_ack(skb, (sk->sk_state == TCP_LISTEN) ? + tcp_v4_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, tcp_rsk(req)->rcv_nxt, req->rcv_wnd >> inet_rsk(req)->rcv_wscale, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a7fbe7e6f763..fc7667512880 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -971,7 +971,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP, - faddr, saddr, dport, inet->inet_sport); + faddr, saddr, dport, inet->inet_sport, + sk->sk_uid); security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 6e92b4f15d25..3d90a43e641e 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -699,6 +699,7 @@ int inet6_sk_rebuild_header(struct sock *sk) fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet->inet_dport; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sk->sk_uid; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); rcu_read_lock(); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index bb02e176cb70..15e41c5bea3a 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -628,9 +628,9 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; if (type == NDISC_REDIRECT) - ip6_redirect(skb, net, 0, 0); + ip6_redirect(skb, net, 0, 0, sock_net_uid(net, NULL)); else - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); xfrm_state_put(x); } diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 0deea6ef4cc1..8abb98c38d3e 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -162,6 +162,7 @@ ipv4_connected: fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet->inet_dport; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sk->sk_uid; if (!fl6.flowi6_oif && (addr_type&IPV6_ADDR_MULTICAST)) fl6.flowi6_oif = np->mcast_oif; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 40ffd72243a4..4ad65258f549 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -447,9 +447,9 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; if (type == NDISC_REDIRECT) - ip6_redirect(skb, net, 0, 0); + ip6_redirect(skb, net, 0, 0, sock_net_uid(net, NULL)); else - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); xfrm_state_put(x); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 84bdcd06dd34..adb715b22f73 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -90,9 +90,9 @@ static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct net *net = dev_net(skb->dev); if (type == ICMPV6_PKT_TOOBIG) - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); else if (type == NDISC_REDIRECT) - ip6_redirect(skb, net, 0, 0); + ip6_redirect(skb, net, 0, 0, sock_net_uid(net, NULL)); if (!(type & ICMPV6_INFOMSG_MASK)) if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST) @@ -467,6 +467,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) fl6.flowi6_oif = iif; fl6.fl6_icmp_type = type; fl6.fl6_icmp_code = code; + fl6.flowi6_uid = sock_net_uid(net, NULL); security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); sk = icmpv6_xmit_lock(net); @@ -572,6 +573,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) fl6.flowi6_oif = skb->dev->ifindex; fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; fl6.flowi6_mark = mark; + fl6.flowi6_uid = sock_net_uid(net, NULL); security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); sk = icmpv6_xmit_lock(net); diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 9cdb8e434513..a2072a81c933 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -86,6 +86,7 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk, fl6->flowi6_mark = inet_rsk(req)->ir_mark; fl6->fl6_dport = inet_rsk(req)->rmt_port; fl6->fl6_sport = inet_rsk(req)->loc_port; + fl6->flowi6_uid = sk->sk_uid; security_req_classify_flow(req, flowi6_to_flowi(fl6)); dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); @@ -213,6 +214,7 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk, fl6->flowi6_mark = sk->sk_mark; fl6->fl6_sport = inet->inet_sport; fl6->fl6_dport = inet->inet_dport; + fl6->flowi6_uid = sk->sk_uid; security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); rcu_read_lock(); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 529348e6a98b..70453acb8385 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -801,6 +801,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev) if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) fl6.flowi6_mark = skb->mark; + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); if (err != 0) { /* XXX: send ICMP error even if DF is not set. */ @@ -851,6 +853,8 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev) if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) fl6.flowi6_mark = skb->mark; + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); if (err != 0) { if (err == -EMSGSIZE) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index efc77acbe9e1..cd0a8bed1ea4 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1096,6 +1096,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6)); fl6.flowi6_proto = IPPROTO_IPIP; + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + dsfield = ipv4_get_dsfield(iph); if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) @@ -1147,6 +1149,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6)); fl6.flowi6_proto = IPPROTO_IPV6; + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); dsfield = ipv6_get_dsfield(ipv6h); if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 7af5aee75d98..a4a4e1c2c9fa 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -76,9 +76,9 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; if (type == NDISC_REDIRECT) - ip6_redirect(skb, net, 0, 0); + ip6_redirect(skb, net, 0, 0, sock_net_uid(net, NULL)); else - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); xfrm_state_put(x); } diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index d38e6a8d8b9f..e48d26beda46 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -27,6 +27,7 @@ int ip6_route_me_harder(struct sk_buff *skb) struct flowi6 fl6 = { .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, .flowi6_mark = skb->mark, + .flowi6_uid = sock_net_uid(net, skb->sk), .daddr = iph->daddr, .saddr = iph->saddr, }; diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 9215ccbec01f..3cb40fb0f7cf 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -161,6 +161,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, fl6.saddr = np->saddr; fl6.daddr = *daddr; fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sk->sk_uid; fl6.fl6_icmp_type = user_icmph.icmp6_type; fl6.fl6_icmp_code = user_icmph.icmp6_code; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 513dffdc2aef..5e0e05945764 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -765,6 +765,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sk->sk_uid; if (sin6) { if (addr_len < SIN6_LEN_RFC2133) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 335d3fc76f46..5481f1dd6a5d 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1146,7 +1146,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, } void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, - int oif, u32 mark) + int oif, u32 mark, kuid_t uid) { const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; struct dst_entry *dst; @@ -1159,6 +1159,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, fl6.daddr = iph->daddr; fl6.saddr = iph->saddr; fl6.flowlabel = ip6_flowinfo(iph); + fl6.flowi6_uid = uid; dst = ip6_route_output(net, NULL, &fl6); if (!dst->error) @@ -1170,11 +1171,12 @@ EXPORT_SYMBOL_GPL(ip6_update_pmtu); void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu) { ip6_update_pmtu(skb, sock_net(sk), mtu, - sk->sk_bound_dev_if, sk->sk_mark); + sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid); } EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu); -void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark) +void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, + kuid_t uid) { const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; struct dst_entry *dst; @@ -1187,6 +1189,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark) fl6.daddr = iph->daddr; fl6.saddr = iph->saddr; fl6.flowlabel = ip6_flowinfo(iph); + fl6.flowi6_uid = uid; dst = ip6_route_output(net, NULL, &fl6); if (!dst->error) @@ -1197,7 +1200,8 @@ EXPORT_SYMBOL_GPL(ip6_redirect); void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk) { - ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark); + ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark, + sk->sk_uid); } EXPORT_SYMBOL_GPL(ip6_sk_redirect); diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index a596f388339d..0428544a2bed 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -243,6 +243,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) fl6.flowi6_mark = ireq->ir_mark; fl6.fl6_dport = inet_rsk(req)->rmt_port; fl6.fl6_sport = inet_sk(sk)->inet_sport; + fl6.flowi6_uid = sk->sk_uid; security_req_classify_flow(req, flowi6_to_flowi(&fl6)); dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9e14d6fd9a42..f4bcb07b21da 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -255,6 +255,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = usin->sin6_port; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sk->sk_uid; opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); final_p = fl6_update_dst(&fl6, opt, &final); @@ -801,6 +802,7 @@ static void tcp_v6_send_response(struct sock *sk, struct sk_buff *skb, u32 seq, fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark); fl6.fl6_dport = t1->dest; fl6.fl6_sport = t1->source; + fl6.flowi6_uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL); security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); /* Pass a socket to ip6_dst_lookup either it is for RST diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5187bf51592b..cb3fd4fe75d1 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1149,6 +1149,7 @@ do_udp_sendmsg: fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex; fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sk->sk_uid; if (msg->msg_controllen) { opt = &opt_space; diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 8783dfe5ac6c..5bd181e296e5 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -517,6 +517,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk, memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sk->sk_uid; if (lsa) { if (addr_len < SIN6_LEN_RFC2133) -- GitLab From ca136a9aaed67e0cc18b1e4840bc65a4e66b3d0c Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Fri, 24 Jul 2015 18:19:25 +0200 Subject: [PATCH 388/528] BACKPORT: tcp: fix recv with flags MSG_WAITALL | MSG_PEEK Currently, tcp_recvmsg enters a busy loop in sk_wait_data if called with flags = MSG_WAITALL | MSG_PEEK. sk_wait_data waits for sk_receive_queue not empty, but in this case, the receive queue is not empty, but does not contain any skb that we can use. Add a "last skb seen on receive queue" argument to sk_wait_data, so that it sleeps until the receive queue has new skbs. Change-Id: If58492ae474effe058541f7e9a0c03dc24155393 Link: https://bugzilla.kernel.org/show_bug.cgi?id=99461 Link: https://sourceware.org/bugzilla/show_bug.cgi?id=18493 Link: https://bugzilla.redhat.com/show_bug.cgi?id=1205258 Reported-by: Enrico Scholz Reported-by: Dan Searle Signed-off-by: Sabrina Dubroca Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Kevin F. Haggerty (cherry picked from commit 10ad84d2acf0af57a037a2ff6037542f5d7e5f83) --- include/net/sock.h | 2 +- net/core/sock.c | 5 +++-- net/dccp/proto.c | 2 +- net/ipv4/tcp.c | 11 +++++++---- net/llc/af_llc.c | 4 ++-- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index abaa5d66db07..3d4b98d54edb 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -889,7 +889,7 @@ extern void sk_stream_kill_queues(struct sock *sk); extern void sk_set_memalloc(struct sock *sk); extern void sk_clear_memalloc(struct sock *sk); -extern int sk_wait_data(struct sock *sk, long *timeo); +int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb); struct request_sock_ops; struct timewait_sock_ops; diff --git a/net/core/sock.c b/net/core/sock.c index 1ac4d58a0097..36dde6e077af 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1970,20 +1970,21 @@ static void __release_sock(struct sock *sk) * sk_wait_data - wait for data to arrive at sk_receive_queue * @sk: sock to wait on * @timeo: for how long + * @skb: last skb seen on sk_receive_queue * * Now socket state including sk->sk_err is changed only under lock, * hence we may omit checks after joining wait queue. * We check receive queue before schedule() only as optimization; * it is very likely that release_sock() added new data. */ -int sk_wait_data(struct sock *sk, long *timeo) +int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb) { int rc; DEFINE_WAIT(wait); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); - rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue)); + rc = sk_wait_event(sk, timeo, skb_peek_tail(&sk->sk_receive_queue) != skb); clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); finish_wait(sk_sleep(sk), &wait); return rc; diff --git a/net/dccp/proto.c b/net/dccp/proto.c index cb55fb912401..2e08919e36c6 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -888,7 +888,7 @@ verify_sock_status: break; } - sk_wait_data(sk, &timeo); + sk_wait_data(sk, &timeo, NULL); continue; found_ok_skb: if (len > skb->len) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7192b9c25c2c..313f05241dbe 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -740,7 +740,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, */ if (!skb_queue_empty(&sk->sk_receive_queue)) break; - sk_wait_data(sk, &timeo); + sk_wait_data(sk, &timeo, NULL); if (signal_pending(current)) { ret = sock_intr_errno(timeo); break; @@ -1594,7 +1594,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, long timeo; struct task_struct *user_recv = NULL; bool copied_early = false; - struct sk_buff *skb; + struct sk_buff *skb, *last; u32 urg_hole = 0; lock_sock(sk); @@ -1669,7 +1669,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Next get a buffer. */ + last = skb_peek_tail(&sk->sk_receive_queue); skb_queue_walk(&sk->sk_receive_queue, skb) { + last = skb; /* Now that we have two receive queues this * shouldn't happen. */ @@ -1798,8 +1800,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Do not sleep, just process backlog. */ release_sock(sk); lock_sock(sk); - } else - sk_wait_data(sk, &timeo); + } else { + sk_wait_data(sk, &timeo, last); + } #ifdef CONFIG_NET_DMA tcp_service_net_dma(sk, false); /* Don't block */ diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 9d140594082c..7b33b83f2f2d 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -613,7 +613,7 @@ static int llc_wait_data(struct sock *sk, long timeo) if (signal_pending(current)) break; rc = 0; - if (sk_wait_data(sk, &timeo)) + if (sk_wait_data(sk, &timeo, NULL)) break; } return rc; @@ -803,7 +803,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, release_sock(sk); lock_sock(sk); } else - sk_wait_data(sk, &timeo); + sk_wait_data(sk, &timeo, NULL); if ((flags & MSG_PEEK) && peek_seq != llc->copied_seq) { net_dbg_ratelimited("LLC(%s:%d): Application bug, race in MSG_PEEK\n", -- GitLab From 3da39b40d839f96c95695c6a4dccc2e5f112ba4b Mon Sep 17 00:00:00 2001 From: Xin Long Date: Fri, 24 Feb 2017 16:29:06 +0800 Subject: [PATCH 389/528] ipv6: check sk sk_type and protocol early in ip_mroute_set/getsockopt [ Upstream commit 99253eb750fda6a644d5188fb26c43bad8d5a745 ] Commit 5e1859fbcc3c ("ipv4: ipmr: various fixes and cleanups") fixed the issue for ipv4 ipmr: ip_mroute_setsockopt() & ip_mroute_getsockopt() should not access/set raw_sk(sk)->ipmr_table before making sure the socket is a raw socket, and protocol is IGMP The same fix should be done for ipv6 ipmr as well. This patch can fix the panic caused by overwriting the same offset as ipmr_table as in raw_sk(sk) when accessing other type's socket by ip_mroute_setsockopt(). Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Lee Jones Change-Id: I8d48f4611a2f2d0cb7ad5146036f571f12ecb1fc CVE-2017-18509 Signed-off-by: Kevin F. Haggerty (cherry picked from commit b40ae8677aeb0783b1ab40c5861ea37cfd65ead1) --- net/ipv6/ip6mr.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 13d47e177665..d9811e4079ae 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1662,6 +1662,10 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns struct net *net = sock_net(sk); struct mr6_table *mrt; + if (sk->sk_type != SOCK_RAW || + inet_sk(sk)->inet_num != IPPROTO_ICMPV6) + return -EOPNOTSUPP; + mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); if (mrt == NULL) return -ENOENT; @@ -1673,9 +1677,6 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns switch (optname) { case MRT6_INIT: - if (sk->sk_type != SOCK_RAW || - inet_sk(sk)->inet_num != IPPROTO_ICMPV6) - return -EOPNOTSUPP; if (optlen < sizeof(int)) return -EINVAL; @@ -1811,6 +1812,10 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, struct net *net = sock_net(sk); struct mr6_table *mrt; + if (sk->sk_type != SOCK_RAW || + inet_sk(sk)->inet_num != IPPROTO_ICMPV6) + return -EOPNOTSUPP; + mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); if (mrt == NULL) return -ENOENT; -- GitLab From dd3f507dcaa6e9576050666112ef3bdd570462aa Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 1 Apr 2016 14:17:28 +0200 Subject: [PATCH 390/528] netfilter: x_tables: check for bogus target offset commit ce683e5f9d045e5d67d1312a42b359cb2ab2a13c upstream. We're currently asserting that targetoff + targetsize <= nextoff. Extend it to also check that targetoff is >= sizeof(xt_entry). Since this is generic code, add an argument pointing to the start of the match/target, we can then derive the base structure size from the delta. We also need the e->elems pointer in a followup change to validate matches. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau (cherry picked from commit f2c5294dada9c4b1901e667e61b2b22b0d0b9d43) --- net/netfilter/x_tables.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index e903c3a4cd8a..5cdd607444bd 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -662,6 +662,9 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets); * * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. * + * This function does not validate the targets or matches themselves, it + * only tests that all the offsets and sizes are correct. + * * The arp/ip/ip6t_entry structure @base must have passed following tests: * - it must point to a valid memory location * - base to base + next_offset must be accessible, i.e. not exceed allocated -- GitLab From 96f0ac74122c34ab03d12c8a999a2c8a3eafe55d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 12 Jun 2015 13:58:52 +0200 Subject: [PATCH 391/528] BACKPORT: netfilter: Kconfig: get rid of parens around depends on (cherry pick from commit f09becc79f899f92557ce6d5562a8b80d6addb34) According to the reporter, they are not needed. Reported-by: Sergei Shtylyov Signed-off-by: Pablo Neira Ayuso Change-Id: I5f28a81e1361c23cedd57338f30c81730dc8aa3b Git-commit: 18bab8a78ea9691631c131495087f5f40931abcf Git-repo: https://android.googlesource.com/kernel/common.git Signed-off-by: Srinivasarao P (cherry picked from commit 5254522cacbdbb07c9116ea1ea0683536644ff9f) --- net/ipv4/netfilter/Kconfig | 3 ++- net/ipv6/netfilter/Kconfig | 3 ++- net/netfilter/Kconfig | 12 +++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 71f6b12c47fb..dc593bd4fcbf 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -71,7 +71,8 @@ config IP_NF_MATCH_ECN config IP_NF_MATCH_RPFILTER tristate '"rpfilter" reverse path filter match support' - depends on NETFILTER_ADVANCED && (IP_NF_MANGLE || IP_NF_RAW) + depends on NETFILTER_ADVANCED + depends on IP_NF_MANGLE || IP_NF_RAW ---help--- This option allows you to match packets whose replies would go out via the interface the packet came in. diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 7f45af3e8128..9488916d1f2b 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -105,7 +105,8 @@ config IP6_NF_MATCH_MH config IP6_NF_MATCH_RPFILTER tristate '"rpfilter" reverse path filter match support' - depends on NETFILTER_ADVANCED && (IP6_NF_MANGLE || IP6_NF_RAW) + depends on NETFILTER_ADVANCED + depends on IP6_NF_MANGLE || IP6_NF_RAW ---help--- This option allows you to match packets whose replies would go out via the interface the packet came in. diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 81fce903aeb2..59210127c502 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -195,7 +195,7 @@ config NF_CONNTRACK_FTP config NF_CONNTRACK_H323 tristate "H.323 protocol support" - depends on (IPV6 || IPV6=n) + depends on IPV6 || IPV6=n depends on NETFILTER_ADVANCED help H.323 is a VoIP signalling protocol from ITU-T. As one of the most @@ -583,7 +583,7 @@ config NETFILTER_XT_TARGET_HL config NETFILTER_XT_TARGET_HMARK tristate '"HMARK" target support' - depends on (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n) + depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n depends on NETFILTER_ADVANCED ---help--- This option adds the "HMARK" target. @@ -727,7 +727,7 @@ config NETFILTER_XT_TARGET_REDIRECT config NETFILTER_XT_TARGET_TEE tristate '"TEE" - packet cloning to alternate destination' depends on NETFILTER_ADVANCED - depends on (IPV6 || IPV6=n) + depends on IPV6 || IPV6=n depends on !NF_CONNTRACK || NF_CONNTRACK ---help--- This option adds a "TEE" target with which a packet can be cloned and @@ -738,6 +738,7 @@ config NETFILTER_XT_TARGET_TPROXY depends on NETFILTER_TPROXY depends on NETFILTER_XTABLES depends on NETFILTER_ADVANCED + depends on IPV6 || IPV6=n select NF_DEFRAG_IPV4 select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES help @@ -772,7 +773,7 @@ config NETFILTER_XT_TARGET_SECMARK config NETFILTER_XT_TARGET_TCPMSS tristate '"TCPMSS" target support' - depends on (IPV6 || IPV6=n) + depends on IPV6 || IPV6=n default m if NETFILTER_ADVANCED=n ---help--- This option adds a `TCPMSS' target, which allows you to alter the @@ -974,7 +975,7 @@ config NETFILTER_XT_MATCH_ESP config NETFILTER_XT_MATCH_HASHLIMIT tristate '"hashlimit" match support' - depends on (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n) + depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n depends on NETFILTER_ADVANCED help This option adds a `hashlimit' match. @@ -1240,6 +1241,7 @@ config NETFILTER_XT_MATCH_SOCKET depends on NETFILTER_XTABLES depends on NETFILTER_ADVANCED depends on !NF_CONNTRACK || NF_CONNTRACK + depends on IPV6 || IPV6=n select NF_DEFRAG_IPV4 select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES help -- GitLab From 9d5547595bc161122bd5db787405b040c2b9938c Mon Sep 17 00:00:00 2001 From: Gao Feng Date: Sat, 25 Mar 2017 18:24:36 +0800 Subject: [PATCH 392/528] netfilter: nf_nat_snmp: Fix panic when snmp_trap_helper fails to register [ Upstream commit 75c689dca98851d65ef5a27e5ce26b625b68751c ] In the commit 93557f53e1fb ("netfilter: nf_conntrack: nf_conntrack snmp helper"), the snmp_helper is replaced by nf_nat_snmp_hook. So the snmp_helper is never registered. But it still tries to unregister the snmp_helper, it could cause the panic. Now remove the useless snmp_helper and the unregister call in the error handler. Fixes: 93557f53e1fb ("netfilter: nf_conntrack: nf_conntrack snmp helper") Signed-off-by: Gao Feng Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Harsh Shandilya (cherry picked from commit 8dd92c9f7192461314a8c2175a4f73d47437a0e4) --- net/ipv4/netfilter/nf_nat_snmp_basic.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index 1e82bdb0f07e..6860875c929f 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -1261,16 +1261,6 @@ static const struct nf_conntrack_expect_policy snmp_exp_policy = { .timeout = 180, }; -static struct nf_conntrack_helper snmp_helper __read_mostly = { - .me = THIS_MODULE, - .help = help, - .expect_policy = &snmp_exp_policy, - .name = "snmp", - .tuple.src.l3num = AF_INET, - .tuple.src.u.udp.port = cpu_to_be16(SNMP_PORT), - .tuple.dst.protonum = IPPROTO_UDP, -}; - static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { .me = THIS_MODULE, .help = help, @@ -1289,17 +1279,10 @@ static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { static int __init nf_nat_snmp_basic_init(void) { - int ret = 0; - BUG_ON(nf_nat_snmp_hook != NULL); RCU_INIT_POINTER(nf_nat_snmp_hook, help); - ret = nf_conntrack_helper_register(&snmp_trap_helper); - if (ret < 0) { - nf_conntrack_helper_unregister(&snmp_helper); - return ret; - } - return ret; + return nf_conntrack_helper_register(&snmp_trap_helper); } static void __exit nf_nat_snmp_basic_fini(void) -- GitLab From 13632971f8cc9ba66877980f886b892568b3fe0f Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 30 Jan 2018 15:21:34 +0100 Subject: [PATCH 393/528] netfilter: ipt_CLUSTERIP: fix out-of-bounds accesses in clusterip_tg_check() commit 1a38956cce5eabd7b74f94bab70265e4df83165e upstream. Commit 136e92bbec0a switched local_nodes from an array to a bitmask but did not add proper bounds checks. As the result clusterip_config_init_nodelist() can both over-read ipt_clusterip_tgt_info.local_nodes and over-write clusterip_config.local_nodes. Add bounds checks for both. Fixes: 136e92bbec0a ("[NETFILTER] CLUSTERIP: use a bitmap to store node responsibility data") Signed-off-by: Dmitry Vyukov Reported-by: syzbot Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 7fbe3bf5fe233aba4dbabbce53f70d855475d45c) --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 0b732efd32e2..47ee87fcfc1f 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -353,7 +353,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) struct ipt_clusterip_tgt_info *cipinfo = par->targinfo; const struct ipt_entry *e = par->entryinfo; struct clusterip_config *config; - int ret; + int ret, i; if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP && cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT && @@ -367,8 +367,18 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) pr_info("Please specify destination IP\n"); return -EINVAL; } - - /* FIXME: further sanity checks */ + if (cipinfo->num_local_nodes > ARRAY_SIZE(cipinfo->local_nodes)) { + pr_info("bad num_local_nodes %u\n", cipinfo->num_local_nodes); + return -EINVAL; + } + for (i = 0; i < cipinfo->num_local_nodes; i++) { + if (cipinfo->local_nodes[i] - 1 >= + sizeof(config->local_nodes) * 8) { + pr_info("bad local_nodes[%d] %u\n", + i, cipinfo->local_nodes[i]); + return -EINVAL; + } + } config = clusterip_config_find_get(e->ip.dst.s_addr, 1); if (!config) { -- GitLab From 124fb043b494afc43e5c9378f0e121f75250e781 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 30 Jan 2018 19:01:40 +0100 Subject: [PATCH 394/528] netfilter: on sockopt() acquire sock lock only in the required scope commit 3f34cfae1238848fd53f25e5c8fd59da57901f4b upstream. Syzbot reported several deadlocks in the netfilter area caused by rtnl lock and socket lock being acquired with a different order on different code paths, leading to backtraces like the following one: ====================================================== WARNING: possible circular locking dependency detected 4.15.0-rc9+ #212 Not tainted ------------------------------------------------------ syzkaller041579/3682 is trying to acquire lock: (sk_lock-AF_INET6){+.+.}, at: [<000000008775e4dd>] lock_sock include/net/sock.h:1463 [inline] (sk_lock-AF_INET6){+.+.}, at: [<000000008775e4dd>] do_ipv6_setsockopt.isra.8+0x3c5/0x39d0 net/ipv6/ipv6_sockglue.c:167 but task is already holding lock: (rtnl_mutex){+.+.}, at: [<000000004342eaa9>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (rtnl_mutex){+.+.}: __mutex_lock_common kernel/locking/mutex.c:756 [inline] __mutex_lock+0x16f/0x1a80 kernel/locking/mutex.c:893 mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:908 rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 register_netdevice_notifier+0xad/0x860 net/core/dev.c:1607 tee_tg_check+0x1a0/0x280 net/netfilter/xt_TEE.c:106 xt_check_target+0x22c/0x7d0 net/netfilter/x_tables.c:845 check_target net/ipv6/netfilter/ip6_tables.c:538 [inline] find_check_entry.isra.7+0x935/0xcf0 net/ipv6/netfilter/ip6_tables.c:580 translate_table+0xf52/0x1690 net/ipv6/netfilter/ip6_tables.c:749 do_replace net/ipv6/netfilter/ip6_tables.c:1165 [inline] do_ip6t_set_ctl+0x370/0x5f0 net/ipv6/netfilter/ip6_tables.c:1691 nf_sockopt net/netfilter/nf_sockopt.c:106 [inline] nf_setsockopt+0x67/0xc0 net/netfilter/nf_sockopt.c:115 ipv6_setsockopt+0x115/0x150 net/ipv6/ipv6_sockglue.c:928 udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1422 sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2978 SYSC_setsockopt net/socket.c:1849 [inline] SyS_setsockopt+0x189/0x360 net/socket.c:1828 entry_SYSCALL_64_fastpath+0x29/0xa0 -> #0 (sk_lock-AF_INET6){+.+.}: lock_acquire+0x1d5/0x580 kernel/locking/lockdep.c:3914 lock_sock_nested+0xc2/0x110 net/core/sock.c:2780 lock_sock include/net/sock.h:1463 [inline] do_ipv6_setsockopt.isra.8+0x3c5/0x39d0 net/ipv6/ipv6_sockglue.c:167 ipv6_setsockopt+0xd7/0x150 net/ipv6/ipv6_sockglue.c:922 udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1422 sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2978 SYSC_setsockopt net/socket.c:1849 [inline] SyS_setsockopt+0x189/0x360 net/socket.c:1828 entry_SYSCALL_64_fastpath+0x29/0xa0 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(rtnl_mutex); lock(sk_lock-AF_INET6); lock(rtnl_mutex); lock(sk_lock-AF_INET6); *** DEADLOCK *** 1 lock held by syzkaller041579/3682: #0: (rtnl_mutex){+.+.}, at: [<000000004342eaa9>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 The problem, as Florian noted, is that nf_setsockopt() is always called with the socket held, even if the lock itself is required only for very tight scopes and only for some operation. This patch addresses the issues moving the lock_sock() call only where really needed, namely in ipv*_getorigdst(), so that nf_setsockopt() does not need anymore to acquire both locks. Fixes: 22265a5c3c10 ("netfilter: xt_TEE: resolve oif using netdevice notifiers") Reported-by: syzbot+a4c2dc980ac1af699b36@syzkaller.appspotmail.com Suggested-by: Florian Westphal Signed-off-by: Paolo Abeni Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman [aviraxp: Backport to 3.10, adjust context] (cherry picked from commit 2e071979c78e0dfa7ce545ec694cf40f7345ea76) --- net/ipv4/ip_sockglue.c | 14 ++++---------- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 6 +++++- net/ipv6/ipv6_sockglue.c | 17 +++++------------ net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 18 ++++++++++++------ 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 3d009e174166..265fb8731578 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1066,11 +1066,8 @@ int ip_setsockopt(struct sock *sk, int level, if (err == -ENOPROTOOPT && optname != IP_HDRINCL && optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY && - !ip_mroute_opt(optname)) { - lock_sock(sk); + !ip_mroute_opt(optname)) err = nf_setsockopt(sk, PF_INET, optname, optval, optlen); - release_sock(sk); - } #endif return err; } @@ -1095,12 +1092,9 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname, if (err == -ENOPROTOOPT && optname != IP_HDRINCL && optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY && - !ip_mroute_opt(optname)) { - lock_sock(sk); - err = compat_nf_setsockopt(sk, PF_INET, optname, - optval, optlen); - release_sock(sk); - } + !ip_mroute_opt(optname)) + err = compat_nf_setsockopt(sk, PF_INET, optname, optval, + optlen); #endif return err; } diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 567d84168bd2..6d3ebba565d2 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -272,15 +272,19 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) struct nf_conntrack_tuple tuple; memset(&tuple, 0, sizeof(tuple)); + + lock_sock(sk); tuple.src.u3.ip = inet->inet_rcv_saddr; tuple.src.u.tcp.port = inet->inet_sport; tuple.dst.u3.ip = inet->inet_daddr; tuple.dst.u.tcp.port = inet->inet_dport; tuple.src.l3num = PF_INET; tuple.dst.protonum = sk->sk_protocol; + release_sock(sk); /* We only do TCP and SCTP at the moment: is there a better way? */ - if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) { + if (tuple.dst.protonum != IPPROTO_TCP && + tuple.dst.protonum != IPPROTO_SCTP) { pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n"); return -ENOPROTOOPT; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f4d2412d9c60..e76412f822d3 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -871,12 +871,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_NETFILTER /* we need to exclude all possible ENOPROTOOPTs except default case */ if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && - optname != IPV6_XFRM_POLICY) { - lock_sock(sk); - err = nf_setsockopt(sk, PF_INET6, optname, optval, - optlen); - release_sock(sk); - } + optname != IPV6_XFRM_POLICY) + err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen); #endif return err; } @@ -907,12 +903,9 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_NETFILTER /* we need to exclude all possible ENOPROTOOPTs except default case */ if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && - optname != IPV6_XFRM_POLICY) { - lock_sock(sk); - err = compat_nf_setsockopt(sk, PF_INET6, optname, - optval, optlen); - release_sock(sk); - } + optname != IPV6_XFRM_POLICY) + err = compat_nf_setsockopt(sk, PF_INET6, optname, optval, + optlen); #endif return err; } diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 97cd7507c1a4..695d0095a385 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -243,20 +243,27 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { static int ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) { - const struct inet_sock *inet = inet_sk(sk); + struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; const struct ipv6_pinfo *inet6 = inet6_sk(sk); + const struct inet_sock *inet = inet_sk(sk); const struct nf_conntrack_tuple_hash *h; struct sockaddr_in6 sin6; - struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; struct nf_conn *ct; + __be32 flow_label; + int bound_dev_if; + lock_sock(sk); tuple.src.u3.in6 = inet6->rcv_saddr; tuple.src.u.tcp.port = inet->inet_sport; tuple.dst.u3.in6 = inet6->daddr; tuple.dst.u.tcp.port = inet->inet_dport; tuple.dst.protonum = sk->sk_protocol; + bound_dev_if = sk->sk_bound_dev_if; + flow_label = inet6->flow_label; + release_sock(sk); - if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) + if (tuple.dst.protonum != IPPROTO_TCP && + tuple.dst.protonum != IPPROTO_SCTP) return -ENOPROTOOPT; if (*len < 0 || (unsigned int) *len < sizeof(sin6)) @@ -274,14 +281,13 @@ ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) sin6.sin6_family = AF_INET6; sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; - sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK; + sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK; memcpy(&sin6.sin6_addr, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, sizeof(sin6.sin6_addr)); nf_ct_put(ct); - sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, - sk->sk_bound_dev_if); + sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if); return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; } -- GitLab From a3df77c0cb4cb52dfc02bf8ef040e37ee7059636 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Oct 2017 02:50:07 -0700 Subject: [PATCH 395/528] netfilter: x_tables: avoid stack-out-of-bounds read in xt_copy_counters_from_user commit e466af75c074e76107ae1cd5a2823e9c61894ffb upstream. syzkaller reports an out of bound read in strlcpy(), triggered by xt_copy_counters_from_user() Fix this by using memcpy(), then forcing a zero byte at the last position of the destination, as Florian did for the non COMPAT code. Fixes: d7591f0c41ce ("netfilter: x_tables: introduce and use xt_copy_counters_from_user") Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Ben Hutchings (cherry picked from commit 3828b6fc74d36f75ad477570aa67df4fd0ba8177) --- net/netfilter/x_tables.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 5cdd607444bd..2410c5946d73 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -811,7 +811,7 @@ void *xt_copy_counters_from_user(const void __user *user, unsigned int len, if (copy_from_user(&compat_tmp, user, sizeof(compat_tmp)) != 0) return ERR_PTR(-EFAULT); - strlcpy(info->name, compat_tmp.name, sizeof(info->name)); + memcpy(info->name, compat_tmp.name, sizeof(info->name) - 1); info->num_counters = compat_tmp.num_counters; user += sizeof(compat_tmp); } else @@ -824,9 +824,9 @@ void *xt_copy_counters_from_user(const void __user *user, unsigned int len, if (copy_from_user(info, user, sizeof(*info)) != 0) return ERR_PTR(-EFAULT); - info->name[sizeof(info->name) - 1] = '\0'; user += sizeof(*info); } + info->name[sizeof(info->name) - 1] = '\0'; size = sizeof(struct xt_counters); size *= info->num_counters; -- GitLab From 1730433379b3936ebfb7a084b1189f91cff6b982 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 24 Jan 2018 17:16:09 -0800 Subject: [PATCH 396/528] netfilter: x_tables: avoid out-of-bounds reads in xt_request_find_{match|target} commit da17c73b6eb74aad3c3c0654394635675b623b3e upstream. It looks like syzbot found its way into netfilter territory. Issue here is that @name comes from user space and might not be null terminated. Out-of-bound reads happen, KASAN is not happy. v2 added similar fix for xt_request_find_target(), as Florian advised. Signed-off-by: Eric Dumazet Reported-by: syzbot Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 5a09845f5c1c58f5a3f667acf9e77f7c460e2054) --- net/netfilter/x_tables.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 2410c5946d73..753a175c61ae 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -221,6 +221,9 @@ xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision) { struct xt_match *match; + if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN) + return ERR_PTR(-EINVAL); + match = xt_find_match(nfproto, name, revision); if (IS_ERR(match)) { request_module("%st_%s", xt_prefix[nfproto], name); @@ -265,6 +268,9 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision) { struct xt_target *target; + if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN) + return ERR_PTR(-EINVAL); + target = xt_find_target(af, name, revision); if (IS_ERR(target)) { request_module("%st_%s", xt_prefix[af], name); -- GitLab From fba94810bf2465edcb3ff2cf2b3c5711291bea3c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 10 Mar 2018 01:15:45 +0100 Subject: [PATCH 397/528] netfilter: x_tables: add and use xt_check_proc_name commit b1d0a5d0cba4597c0394997b2d5fced3e3841b4e upstream. recent and hashlimit both create /proc files, but only check that name is 0 terminated. This can trigger WARN() from procfs when name is "" or "/". Add helper for this and then use it for both. Cc: Eric Dumazet Reported-by: Eric Dumazet Reported-by: Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman [aviraxp: bp for 3.10, make it extern] (cherry picked from commit 08bbb8681f7325ca0fda6f4a97177dcf79733533) --- include/linux/netfilter/x_tables.h | 2 ++ net/netfilter/x_tables.c | 30 ++++++++++++++++++++++++++++++ net/netfilter/xt_hashlimit.c | 5 +++-- net/netfilter/xt_recent.c | 6 +++--- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 547a5846e6ac..8127e7bca2ff 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -248,6 +248,8 @@ extern int xt_check_match(struct xt_mtchk_param *, extern int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto, bool inv_proto); +extern int xt_check_proc_name(const char *name, unsigned int size); + void *xt_copy_counters_from_user(const void __user *user, unsigned int len, struct xt_counters_info *info, bool compat); diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 753a175c61ae..739849d6a437 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -384,6 +384,36 @@ textify_hooks(char *buf, size_t size, unsigned int mask, uint8_t nfproto) return buf; } +/** + * xt_check_proc_name - check that name is suitable for /proc file creation + * + * @name: file name candidate + * @size: length of buffer + * + * some x_tables modules wish to create a file in /proc. + * This function makes sure that the name is suitable for this + * purpose, it checks that name is NUL terminated and isn't a 'special' + * name, like "..". + * + * returns negative number on error or 0 if name is useable. + */ +int xt_check_proc_name(const char *name, unsigned int size) +{ + if (name[0] == '\0') + return -EINVAL; + + if (strnlen(name, size) == size) + return -ENAMETOOLONG; + + if (strcmp(name, ".") == 0 || + strcmp(name, "..") == 0 || + strchr(name, '/')) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(xt_check_proc_name); + int xt_check_match(struct xt_mtchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 47dc6836830a..597d722fb645 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -668,8 +668,9 @@ static int hashlimit_mt_check(const struct xt_mtchk_param *par) if (info->cfg.gc_interval == 0 || info->cfg.expire == 0) return -EINVAL; - if (info->name[sizeof(info->name)-1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; if (par->family == NFPROTO_IPV4) { if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32) return -EINVAL; diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 1e657cf715c4..db76207bcc4b 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -358,9 +358,9 @@ static int recent_mt_check(const struct xt_mtchk_param *par, info->hit_count, ip_pkt_list_tot); return -EINVAL; } - if (info->name[0] == '\0' || - strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN) - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; mutex_lock(&recent_mutex); t = recent_table_lookup(recent_net, info->name); -- GitLab From 78e5f361af3ab011671745a609a1478af61d091a Mon Sep 17 00:00:00 2001 From: threader Date: Wed, 14 Jul 2021 16:28:17 +0200 Subject: [PATCH 398/528] fs: recent backports to fs/locks.c require these changes --- include/linux/dcache.h | 2 +- include/linux/fs.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 0988bf76e92e..5b94a873ad89 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -328,7 +328,7 @@ static inline int __d_rcu_to_refcount(struct dentry *dentry, unsigned seq) return ret; } -static inline unsigned d_count(struct dentry *dentry) +static inline unsigned d_count(const struct dentry *dentry) { return dentry->d_count; } diff --git a/include/linux/fs.h b/include/linux/fs.h index 87ef41a50d9a..5bed10249a6e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -932,7 +932,8 @@ static inline int file_check_writeable(struct file *filp) * * Lockd stuffs a "host" pointer into this. */ -typedef struct files_struct *fl_owner_t; +//typedef struct files_struct *fl_owner_t; +typedef void *fl_owner_t; struct file_lock_operations { void (*fl_copy_lock)(struct file_lock *, struct file_lock *); -- GitLab From 576783ef3afe876f6f7f987b4531ee38a4dfae57 Mon Sep 17 00:00:00 2001 From: Tejaswi Tanikella Date: Mon, 11 Jun 2018 16:30:24 +0530 Subject: [PATCH 399/528] net: sockev_nlmcast: fix uninitialized data leak into userspace Socket event string, notifying userspace of socket event, can leak data into userspace. Memset it before filling it using strlcpy. Change-Id: I37851f32a1b7ce3307644998c2cc7dd617bb7022 Signed-off-by: Tejaswi Tanikella (cherry picked from commit fdef7963eba7e1a17d93b038193f3197d151d949) --- net/core/sockev_nlmcast.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/sockev_nlmcast.c b/net/core/sockev_nlmcast.c index 749ffb81c87c..8e0b47816e67 100644 --- a/net/core/sockev_nlmcast.c +++ b/net/core/sockev_nlmcast.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015,2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -36,6 +36,8 @@ static struct netlink_kernel_cfg nlcfg = { static void _sockev_event(unsigned long event, __u8 *evstr, int buflen) { + memset(evstr, 0, buflen); + switch (event) { case SOCKEV_SOCKET: strlcpy(evstr, "SOCKEV_SOCKET", buflen); -- GitLab From c7e20a51d7f80ba67bfb6e585c265b9610c3391d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 8 Jan 2016 08:37:20 -0800 Subject: [PATCH 400/528] net: add scheduling point in recvmmsg/sendmmsg Applications often have to reduce number of datagrams they receive or send per system call to avoid starvation problems. Really the kernel should take care of this by using cond_resched(), so that applications can experiment bigger batch sizes. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Pranav Vashi (cherry picked from commit 02eb6adf3ec59612a3f9e0d7d7d9cf26ececda10) --- net/socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/socket.c b/net/socket.c index b6603db005d6..87bbcea4cc54 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2216,6 +2216,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, if (err) break; ++datagrams; + cond_resched(); } fput_light(sock->file, fput_needed); @@ -2435,6 +2436,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, /* Out of band data, return right away */ if (msg_sys.msg_flags & MSG_OOB) break; + cond_resched(); } if (err == 0) -- GitLab From 595435d69dad9925c91c09ee4aa914a29931f3d5 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 10 Jan 2017 09:30:51 +0100 Subject: [PATCH 401/528] UPSTREAM: net: socket: Make unnecessarily global sockfs_setattr() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sockfs_setattr() static as it is not used outside of net/socket.c This fixes the following GCC warning: net/socket.c:534:5: warning: no previous prototype for ‘sockfs_setattr’ [-Wmissing-prototypes] Fixes: 86741ec25462 ("net: core: Add a UID field to struct sock.") Cc: Lorenzo Colitti Signed-off-by: Tobias Klauser Acked-by: Lorenzo Colitti Signed-off-by: David S. Miller Change-Id: Ie613c441b3fe081bdaec8c480d3aade482873bf8 Fixes: Change-Id: Idbc3e9a0cec91c4c6e01916b967b6237645ebe59 ("net: core: Add a UID field to struct sock.") (cherry picked from commit dc647ec88e029307e60e6bf9988056605f11051a) Signed-off-by: Amit Pundir Git-commit: 5785fa4bbb12739c5959828a8c18cc0e506622d9 Git-repo: https://android.googlesource.com/kernel/common.git Signed-off-by: Srinivasarao P (cherry picked from commit 316b0a351c687c0f4d0f875ac10b6a93a0f7d385) --- net/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/socket.c b/net/socket.c index 87bbcea4cc54..568696fee803 100644 --- a/net/socket.c +++ b/net/socket.c @@ -526,7 +526,7 @@ static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, return used; } -int sockfs_setattr(struct dentry *dentry, struct iattr *iattr) +static int sockfs_setattr(struct dentry *dentry, struct iattr *iattr) { int err = simple_setattr(dentry, iattr); -- GitLab From c341d6023e06c08d7d643c38746d5391ff12e4da Mon Sep 17 00:00:00 2001 From: Yann Droneaud Date: Mon, 9 Dec 2013 22:42:20 +0100 Subject: [PATCH 402/528] net: handle error more gracefully in socketpair() This patch makes socketpair() use error paths which do not rely on heavy-weight call to sys_close(): it's better to try to push the file descriptor to userspace before installing the socket file to the file descriptor, so that errors are catched earlier and being easier to handle. Using sys_close() seems to be the exception, while writing the file descriptor before installing it look like it's more or less the norm: eg. except for code used in init/, error handling involve fput() and put_unused_fd(), but not sys_close(). This make socketpair() usage of sys_close() quite unusual. So it deserves to be replaced by the common pattern relying on fput() and put_unused_fd() just like, for example, the one used in pipe(2) or recvmsg(2). Three distinct error paths are still needed since calling fput() on file structure returned by sock_alloc_file() will implicitly call sock_release() on the associated socket structure. Cc: David S. Miller Cc: Al Viro Signed-off-by: Yann Droneaud Link: http://marc.info/?i=1385979146-13825-1-git-send-email-ydroneaud@opteya.com Signed-off-by: David S. Miller Signed-off-by: Pranav Vashi (cherry picked from commit a90fbbd7c4b4a3340e95bdaba1a5a751da91105e) --- net/socket.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/net/socket.c b/net/socket.c index 568696fee803..809d33583598 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1465,48 +1465,61 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, err = fd1; goto out_release_both; } + fd2 = get_unused_fd_flags(flags); if (unlikely(fd2 < 0)) { err = fd2; - put_unused_fd(fd1); - goto out_release_both; + goto out_put_unused_1; } newfile1 = sock_alloc_file(sock1, flags, NULL); if (unlikely(IS_ERR(newfile1))) { err = PTR_ERR(newfile1); - put_unused_fd(fd1); - put_unused_fd(fd2); - goto out_release_both; + goto out_put_unused_both; } newfile2 = sock_alloc_file(sock2, flags, NULL); if (IS_ERR(newfile2)) { err = PTR_ERR(newfile2); - fput(newfile1); - put_unused_fd(fd1); - put_unused_fd(fd2); - sock_release(sock2); - goto out; + goto out_fput_1; } + err = put_user(fd1, &usockvec[0]); + if (err) + goto out_fput_both; + + err = put_user(fd2, &usockvec[1]); + if (err) + goto out_fput_both; + audit_fd_pair(fd1, fd2); + fd_install(fd1, newfile1); fd_install(fd2, newfile2); /* fd1 and fd2 may be already another descriptors. * Not kernel problem. */ - err = put_user(fd1, &usockvec[0]); - if (!err) - err = put_user(fd2, &usockvec[1]); - if (!err) - return 0; + return 0; - sys_close(fd2); - sys_close(fd1); - return err; +out_fput_both: + fput(newfile2); + fput(newfile1); + put_unused_fd(fd2); + put_unused_fd(fd1); + goto out; + +out_fput_1: + fput(newfile1); + put_unused_fd(fd2); + put_unused_fd(fd1); + sock_release(sock2); + goto out; +out_put_unused_both: + put_unused_fd(fd2); +out_put_unused_1: + put_unused_fd(fd1); out_release_both: sock_release(sock2); out_release_1: -- GitLab From 62453bed48e67eca7fd2e88a919e65da15e12d5e Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 8 Sep 2014 14:49:59 -0700 Subject: [PATCH 403/528] net: socket: set msg_namelen to 0 if msg_name is passed as NULL in msghdr struct from userland Linux manpage for recvmsg and sendmsg calls does not explicitly mention setting msg_namelen to 0 when msg_name passed set as NULL. When developers don't set msg_namelen member in msghdr, it might contain garbage value which will fail the validation check and sendmsg and recvmsg calls from kernel will return EINVAL. This will break old binaries and any code for which there is no access to source code. To fix this, we set msg_namelen to 0 when msg_name is passed as NULL from userland. Signed-off-by: Ani Sinha Signed-off-by: David S. Miller Signed-off-by: Pranav Vashi (cherry picked from commit 37e81b285c8571b719116e27f9b66f60e9270d35) --- net/socket.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/socket.c b/net/socket.c index 809d33583598..6f4fac486e7f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2032,6 +2032,9 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) return -EFAULT; + if (kmsg->msg_name == NULL) + kmsg->msg_namelen = 0; + if (kmsg->msg_namelen < 0) return -EINVAL; -- GitLab From 7772bc63094f42cb91fc6df2f80f5b493f597f83 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 24 May 2017 09:59:31 -0700 Subject: [PATCH 404/528] tcp: avoid fastopen API to be used on AF_UNSPEC [ Upstream commit ba615f675281d76fd19aa03558777f81fb6b6084 ] Fastopen API should be used to perform fastopen operations on the TCP socket. It does not make sense to use fastopen API to perform disconnect by calling it with AF_UNSPEC. The fastopen data path is also prone to race conditions and bugs when using with AF_UNSPEC. One issue reported and analyzed by Vegard Nossum is as follows: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Thread A: Thread B: ------------------------------------------------------------------------ sendto() - tcp_sendmsg() - sk_stream_memory_free() = 0 - goto wait_for_sndbuf - sk_stream_wait_memory() - sk_wait_event() // sleep | sendto(flags=MSG_FASTOPEN, dest_addr=AF_UNSPEC) | - tcp_sendmsg() | - tcp_sendmsg_fastopen() | - __inet_stream_connect() | - tcp_disconnect() //because of AF_UNSPEC | - tcp_transmit_skb()// send RST | - return 0; // no reconnect! | - sk_stream_wait_connect() | - sock_error() | - xchg(&sk->sk_err, 0) | - return -ECONNRESET - ... // wake up, see sk->sk_err == 0 - skb_entail() on TCP_CLOSE socket If the connection is reopened then we will send a brand new SYN packet after thread A has already queued a buffer. At this point I think the socket internal state (sequence numbers etc.) becomes messed up. When the new connection is closed, the FIN-ACK is rejected because the sequence number is outside the window. The other side tries to retransmit, but __tcp_retransmit_skb() calls tcp_trim_head() on an empty skb which corrupts the skb data length and hits a BUG() in copy_and_csum_bits(). +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Hence, this patch adds a check for AF_UNSPEC in the fastopen data path and return EOPNOTSUPP to user if such case happens. Fixes: cf60af03ca4e7 ("tcp: Fast Open client - sendmsg(MSG_FASTOPEN)") Reported-by: Vegard Nossum Signed-off-by: Wei Wang Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 4fe11d215d4e25d5951ec25490d82d7e0793cda9) --- net/ipv4/tcp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 313f05241dbe..bcf9149dc82f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1022,9 +1022,12 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied, size_t size) { struct tcp_sock *tp = tcp_sk(sk); + struct sockaddr *uaddr = msg->msg_name; int err, flags; - if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE)) + if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) || + (uaddr && msg->msg_namelen >= sizeof(uaddr->sa_family) && + uaddr->sa_family == AF_UNSPEC)) return -EOPNOTSUPP; if (tp->fastopen_req != NULL) return -EALREADY; /* Another Fast Open is in progress */ @@ -1037,7 +1040,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, tp->fastopen_req->size = size; flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0; - err = __inet_stream_connect(sk->sk_socket, msg->msg_name, + err = __inet_stream_connect(sk->sk_socket, uaddr, msg->msg_namelen, flags); *copied = tp->fastopen_req->copied; tcp_free_fastopen_req(tp); -- GitLab From 44fb21b644f64549b25dcab650e2f9239b0dd99c Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Thu, 18 Jan 2018 16:14:26 -0500 Subject: [PATCH 405/528] net: tcp: close sock if net namespace is exiting [ Upstream commit 4ee806d51176ba7b8ff1efd81f271d7252e03a1d ] When a tcp socket is closed, if it detects that its net namespace is exiting, close immediately and do not wait for FIN sequence. For normal sockets, a reference is taken to their net namespace, so it will never exit while the socket is open. However, kernel sockets do not take a reference to their net namespace, so it may begin exiting while the kernel socket is still open. In this case if the kernel socket is a tcp socket, it will stay open trying to complete its close sequence. The sock's dst(s) hold a reference to their interface, which are all transferred to the namespace's loopback interface when the real interfaces are taken down. When the namespace tries to take down its loopback interface, it hangs waiting for all references to the loopback interface to release, which results in messages like: unregister_netdevice: waiting for lo to become free. Usage count = 1 These messages continue until the socket finally times out and closes. Since the net namespace cleanup holds the net_mutex while calling its registered pernet callbacks, any new net namespace initialization is blocked until the current net namespace finishes exiting. After this change, the tcp socket notices the exiting net namespace, and closes immediately, releasing its dst(s) and their reference to the loopback interface, which lets the net namespace continue exiting. Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1711407 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=97811 Signed-off-by: Dan Streetman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit b551b73f6a10fcc04e32543be75f47e132bbd3a3) --- include/net/net_namespace.h | 10 ++++++++++ net/ipv4/tcp.c | 3 +++ net/ipv4/tcp_timer.c | 15 +++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index b064d6dd14fb..350ea246a940 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -181,6 +181,11 @@ int net_eq(const struct net *net1, const struct net *net2) return net1 == net2; } +static inline int check_net(const struct net *net) +{ + return atomic_read(&net->count) != 0; +} + extern void net_drop_ns(void *); #else @@ -205,6 +210,11 @@ int net_eq(const struct net *net1, const struct net *net2) return 1; } +static inline int check_net(const struct net *net) +{ + return 1; +} + #define net_drop_ns NULL #endif diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index bcf9149dc82f..128cb2be269d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2256,6 +2256,9 @@ adjudge_to_death: tcp_send_active_reset(sk, GFP_ATOMIC); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); + } else if (!check_net(sock_net(sk))) { + /* Not possible to send reset; just close */ + tcp_set_state(sk, TCP_CLOSE); } } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 8c61887277c8..bb74e4aa112a 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -82,11 +82,19 @@ static void tcp_write_err(struct sock *sk) * to prevent DoS attacks. It is called when a retransmission timeout * or zero probe timeout occurs on orphaned socket. * + * Also close if our net namespace is exiting; in that case there is no + * hope of ever communicating again since all netns interfaces are already + * down (or about to be down), and we need to release our dst references, + * which have been moved to the netns loopback interface, so the namespace + * can finish exiting. This condition is only possible if we are a kernel + * socket, as those do not hold references to the namespace. + * * Criteria is still not confirmed experimentally and may change. * We kill the socket, if: * 1. If number of orphaned sockets exceeds an administratively configured * limit. * 2. If we have strong memory pressure. + * 3. If our net namespace is exiting. */ static int tcp_out_of_resources(struct sock *sk, int do_reset) { @@ -115,6 +123,13 @@ static int tcp_out_of_resources(struct sock *sk, int do_reset) NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); return 1; } + + if (!check_net(sock_net(sk))) { + /* Not possible to send reset; just close */ + tcp_done(sk); + return 1; + } + return 0; } -- GitLab From 91bddfd2bccc9b9bdf0dcafddede75e6ded89f5e Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Fri, 26 Jan 2018 16:40:41 +0800 Subject: [PATCH 406/528] tcp: release sk_frag.page in tcp_disconnect [ Upstream commit 9b42d55a66d388e4dd5550107df051a9637564fc ] socket can be disconnected and gets transformed back to a listening socket, if sk_frag.page is not released, which will be cloned into a new socket by sk_clone_lock, but the reference count of this page is increased, lead to a use after free or double free issue Signed-off-by: Li RongQing Cc: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 0ac27218338893b88499bd4da2575d1a0bf5f648) --- net/ipv4/tcp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 128cb2be269d..0c70f07610ae 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2357,6 +2357,12 @@ int tcp_disconnect(struct sock *sk, int flags) WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); + if (sk->sk_frag.page) { + put_page(sk->sk_frag.page); + sk->sk_frag.page = NULL; + sk->sk_frag.offset = 0; + } + sk->sk_error_report(sk); return err; } -- GitLab From 168d1caaf4b49f740c459b461b87fcf57e7859dc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 Apr 2018 14:36:28 -0700 Subject: [PATCH 407/528] tcp: md5: reject TCP_MD5SIG or TCP_MD5SIG_EXT on established sockets [ Upstream commit 7212303268918b9a203aebeacfdbd83b5e87b20d ] syzbot/KMSAN reported an uninit-value in tcp_parse_options() [1] I believe this was caused by a TCP_MD5SIG being set on live flow. This is highly unexpected, since TCP option space is limited. For instance, presence of TCP MD5 option automatically disables TCP TimeStamp option at SYN/SYNACK time, which we can not do once flow has been established. Really, adding/deleting an MD5 key only makes sense on sockets in CLOSE or LISTEN state. [1] BUG: KMSAN: uninit-value in tcp_parse_options+0xd74/0x1a30 net/ipv4/tcp_input.c:3720 CPU: 1 PID: 6177 Comm: syzkaller192004 Not tainted 4.16.0+ #83 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 tcp_parse_options+0xd74/0x1a30 net/ipv4/tcp_input.c:3720 tcp_fast_parse_options net/ipv4/tcp_input.c:3858 [inline] tcp_validate_incoming+0x4f1/0x2790 net/ipv4/tcp_input.c:5184 tcp_rcv_established+0xf60/0x2bb0 net/ipv4/tcp_input.c:5453 tcp_v4_do_rcv+0x6cd/0xd90 net/ipv4/tcp_ipv4.c:1469 sk_backlog_rcv include/net/sock.h:908 [inline] __release_sock+0x2d6/0x680 net/core/sock.c:2271 release_sock+0x97/0x2a0 net/core/sock.c:2786 tcp_sendmsg+0xd6/0x100 net/ipv4/tcp.c:1464 inet_sendmsg+0x48d/0x740 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] SYSC_sendto+0x6c3/0x7e0 net/socket.c:1747 SyS_sendto+0x8a/0xb0 net/socket.c:1715 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x448fe9 RSP: 002b:00007fd472c64d38 EFLAGS: 00000216 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 00000000006e5a30 RCX: 0000000000448fe9 RDX: 000000000000029f RSI: 0000000020a88f88 RDI: 0000000000000004 RBP: 00000000006e5a34 R08: 0000000020e68000 R09: 0000000000000010 R10: 00000000200007fd R11: 0000000000000216 R12: 0000000000000000 R13: 00007fff074899ef R14: 00007fd472c659c0 R15: 0000000000000009 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmsan_slab_alloc+0x11/0x20 mm/kmsan/kmsan.c:321 slab_post_alloc_hook mm/slab.h:445 [inline] slab_alloc_node mm/slub.c:2737 [inline] __kmalloc_node_track_caller+0xaed/0x11c0 mm/slub.c:4369 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cf/0x9f0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:984 [inline] tcp_send_ack+0x18c/0x910 net/ipv4/tcp_output.c:3624 __tcp_ack_snd_check net/ipv4/tcp_input.c:5040 [inline] tcp_ack_snd_check net/ipv4/tcp_input.c:5053 [inline] tcp_rcv_established+0x2103/0x2bb0 net/ipv4/tcp_input.c:5469 tcp_v4_do_rcv+0x6cd/0xd90 net/ipv4/tcp_ipv4.c:1469 sk_backlog_rcv include/net/sock.h:908 [inline] __release_sock+0x2d6/0x680 net/core/sock.c:2271 release_sock+0x97/0x2a0 net/core/sock.c:2786 tcp_sendmsg+0xd6/0x100 net/ipv4/tcp.c:1464 inet_sendmsg+0x48d/0x740 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] SYSC_sendto+0x6c3/0x7e0 net/socket.c:1747 SyS_sendto+0x8a/0xb0 net/socket.c:1715 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: cfb6eeb4c860 ("[TCP]: MD5 Signature Option (RFC2385) support.") Signed-off-by: Eric Dumazet Reported-by: syzbot Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 44bfc7fa247d0e96455c3c516cc3529c8dbf7983) --- net/ipv4/tcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 0c70f07610ae..b2dc6ca6e5d3 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2670,8 +2670,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, #ifdef CONFIG_TCP_MD5SIG case TCP_MD5SIG: - /* Read the IP->Key mappings from userspace */ - err = tp->af_specific->md5_parse(sk, optval, optlen); + if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) + err = tp->af_specific->md5_parse(sk, optval, optlen); + else + err = -EINVAL; break; #endif case TCP_USER_TIMEOUT: -- GitLab From 575fcc4ce0af9733ba93d14036726cbb9769be6b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 29 Apr 2018 18:55:20 -0700 Subject: [PATCH 408/528] tcp: fix TCP_REPAIR_QUEUE bound checking commit bf2acc943a45d2b2e8a9f1a5ddff6b6e43cc69d9 upstream. syzbot is able to produce a nasty WARN_ON() in tcp_verify_left_out() with following C-repro : socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3 setsockopt(3, SOL_TCP, TCP_REPAIR, [1], 4) = 0 setsockopt(3, SOL_TCP, TCP_REPAIR_QUEUE, [-1], 4) = 0 bind(3, {sa_family=AF_INET, sin_port=htons(20002), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 sendto(3, "\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"..., 1242, MSG_FASTOPEN, {sa_family=AF_INET, sin_port=htons(20002), sin_addr=inet_addr("127.0.0.1")}, 16) = 1242 setsockopt(3, SOL_TCP, TCP_REPAIR_WINDOW, "\4\0\0@+\205\0\0\377\377\0\0\377\377\377\177\0\0\0\0", 20) = 0 writev(3, [{"\270", 1}], 1) = 1 setsockopt(3, SOL_TCP, TCP_REPAIR_OPTIONS, "\10\0\0\0\0\0\0\0\0\0\0\0|\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 386) = 0 writev(3, [{"\210v\r[\226\320t\231qwQ\204\264l\254\t\1\20\245\214p\350H\223\254;\\\37\345\307p$"..., 3144}], 1) = 3144 The 3rd system call looks odd : setsockopt(3, SOL_TCP, TCP_REPAIR_QUEUE, [-1], 4) = 0 This patch makes sure bound checking is using an unsigned compare. Fixes: ee9952831cfd ("tcp: Initial repair mode") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 1e52631a68707f0f8c8fa4f98a29484de44558bc) --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index b2dc6ca6e5d3..d1031158efb2 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2538,7 +2538,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, case TCP_REPAIR_QUEUE: if (!tp->repair) err = -EPERM; - else if (val < TCP_QUEUES_NR) + else if ((unsigned int)val < TCP_QUEUES_NR) tp->repair_queue = val; else err = -EINVAL; -- GitLab From 62a25ae43b70da630db62ab2e95d52eb80063b72 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 25 Apr 2018 11:33:08 -0700 Subject: [PATCH 409/528] tcp: ignore Fast Open on repair mode [ Upstream commit 16ae6aa1705299789f71fdea59bfb119c1fbd9c0 ] The TCP repair sequence of operation is to first set the socket in repair mode, then inject the TCP stats into the socket with repair socket options, then call connect() to re-activate the socket. The connect syscall simply returns and set state to ESTABLISHED mode. As a result Fast Open is meaningless for TCP repair. However allowing sendto() system call with MSG_FASTOPEN flag half-way during the repair operation could unexpectedly cause data to be sent, before the operation finishes changing the internal TCP stats (e.g. MSS). This in turn triggers TCP warnings on inconsistent packet accounting. The fix is to simply disallow Fast Open operation once the socket is in the repair mode. Reported-by: syzbot Signed-off-by: Yuchung Cheng Reviewed-by: Neal Cardwell Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 00391b9703778f11034ca3352df8df1cd1cb647f) --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index d1031158efb2..a1b3069088ed 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1061,7 +1061,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, lock_sock(sk); flags = msg->msg_flags; - if (flags & MSG_FASTOPEN) { + if ((flags & MSG_FASTOPEN) && !tp->repair) { err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size); if (err == -EINPROGRESS && copied_syn > 0) goto out; -- GitLab From 2d536f4998d1c1fa9a89aef677366d660b1e586d Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 17 May 2018 13:13:29 -0400 Subject: [PATCH 410/528] net: test tailroom before appending to linear skb [ Upstream commit 113f99c3358564a0647d444c2ae34e8b1abfd5b9 ] Device features may change during transmission. In particular with corking, a device may toggle scatter-gather in between allocating and writing to an skb. Do not unconditionally assume that !NETIF_F_SG at write time implies that the same held at alloc time and thus the skb has sufficient tailroom. This issue predates git history. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: Eric Dumazet Signed-off-by: Willem de Bruijn Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 26fc1ee9b7de4b2ea81b52a4e6c0c577350328b5) --- net/ipv4/ip_output.c | 3 ++- net/ipv6/ip6_output.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index f6990ed05536..681a91e6b126 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -985,7 +985,8 @@ alloc_new_skb: if (copy > length) copy = length; - if (!(rt->dst.dev->features&NETIF_F_SG)) { + if (!(rt->dst.dev->features&NETIF_F_SG) && + skb_tailroom(skb) >= copy) { unsigned int off; off = skb->len; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c681f4f760e6..ae0b68e28943 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1464,7 +1464,8 @@ alloc_new_skb: if (copy > length) copy = length; - if (!(rt->dst.dev->features&NETIF_F_SG)) { + if (!(rt->dst.dev->features&NETIF_F_SG) && + skb_tailroom(skb) >= copy) { unsigned int off; off = skb->len; -- GitLab From 76d11e01aca1ced66fd8f0cef42d76b2e2833e4c Mon Sep 17 00:00:00 2001 From: FX Le Bail Date: Mon, 10 Feb 2014 16:46:54 +0100 Subject: [PATCH 411/528] ipv4: ipconfig.c: add parentheses in an if statement Even if the 'time_before' macro expand with parentheses, the look is bad. Signed-off-by: Francois-Xavier Le Bail Signed-off-by: David S. Miller (cherry picked from commit c4ed77c4126e445b9cde7d9457ab571de07c9581) --- net/ipv4/ipconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index efa1138fa523..b3e86ea7b71b 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -273,7 +273,7 @@ static int __init ic_open_devs(void) msleep(1); - if time_before(jiffies, next_msg) + if (time_before(jiffies, next_msg)) continue; elapsed = jiffies_to_msecs(jiffies - start); -- GitLab From 7eb0ce497889c3cd44e10d6ee3bb6c4348626ccf Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 2 Jul 2014 22:22:20 +0200 Subject: [PATCH 412/528] ipconfig: add static to local variable ic_dev_xid is only used in ipconfig.c Cc: "David S. Miller" Cc: Alexey Kuznetsov Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller (cherry picked from commit 94eacaa44f9c5184fe38c2b7447739aa78990931) --- net/ipv4/ipconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index b3e86ea7b71b..f0f3f9f77b30 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -143,7 +143,7 @@ __be32 ic_servaddr = NONE; /* Boot server IP address */ __be32 root_server_addr = NONE; /* Address of NFS server */ u8 root_server_path[256] = { 0, }; /* Path to mount as root */ -__be32 ic_dev_xid; /* Device under configuration */ +static __be32 ic_dev_xid; /* Device under configuration */ /* vendor class identifier */ static char vendor_class_identifier[253] __initdata; -- GitLab From 6db6025c12142fa5feb91fd6aee633cd999ab198 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 9 Jul 2014 20:35:21 +0200 Subject: [PATCH 413/528] ipconfig: move ic_dev_xid under IPCONFIG_BOOTP ic_dev_xid is only used in __init ic_bootp_recv under IPCONFIG_BOOTP and __init ic_dynamic under IPCONFIG_DYNAMIC(which is itself defined with the same IPCONFIG_BOOTP) This patch fixes the following warning when IPCONFIG_BOOTP is not set: >> net/ipv4/ipconfig.c:146:15: warning: 'ic_dev_xid' defined but not used [-Wunused-variable] static __be32 ic_dev_xid; /* Device under configuration */ Reported-by: Fengguang Wu Cc: Fengguang Wu Cc: "David S. Miller" Cc: Alexey Kuznetsov Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller (cherry picked from commit 22877f47da110eccac97b2a0d96a7e6baf5f1cfe) --- net/ipv4/ipconfig.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index f0f3f9f77b30..f02f594d04c5 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -143,8 +143,6 @@ __be32 ic_servaddr = NONE; /* Boot server IP address */ __be32 root_server_addr = NONE; /* Address of NFS server */ u8 root_server_path[256] = { 0, }; /* Path to mount as root */ -static __be32 ic_dev_xid; /* Device under configuration */ - /* vendor class identifier */ static char vendor_class_identifier[253] __initdata; @@ -654,6 +652,7 @@ static struct packet_type bootp_packet_type __initdata = { .func = ic_bootp_recv, }; +static __be32 ic_dev_xid; /* Device under configuration */ /* * Initialize DHCP/BOOTP extension fields in the request. -- GitLab From b7229b24be3544ae7727c02efd80948343be03b4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 9 Jul 2014 22:25:18 -0700 Subject: [PATCH 414/528] ipconfig: Only bootp paths should reference ic_dev_xid. It is only tested, and declared, in the bootp code. So, in ic_dynamic() guard it's setting with IPCONFIG_BOOTP. Signed-off-by: David S. Miller (cherry picked from commit 902a332e3b1b3f2577156388b93f20fb9c70c485) --- net/ipv4/ipconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index f02f594d04c5..5bbef4fdcb43 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1217,10 +1217,10 @@ static int __init ic_dynamic(void) get_random_bytes(&timeout, sizeof(timeout)); timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned int) CONF_TIMEOUT_RANDOM); for (;;) { +#ifdef IPCONFIG_BOOTP /* Track the device we are configuring */ ic_dev_xid = d->xid; -#ifdef IPCONFIG_BOOTP if (do_bootp && (d->able & IC_BOOTP)) ic_bootp_send_if(d, jiffies - start_jiffies); #endif -- GitLab From 4ac3742ab0d4789b3bc09dbe0e0bd184706879a1 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 20 Aug 2014 23:14:10 +0530 Subject: [PATCH 415/528] ipconfig: Use time_before The functions time_before, time_before_eq, time_after, and time_after_eq are more robust for comparing jiffies against other values. A simplified version of the Coccinelle semantic patch making this change is as follows: @change@ expression E1,E2; @@ - jiffies - E1 < E2 + time_before(jiffies, E1+E2) Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller (cherry picked from commit d3ddbf5489eb0ead919541074a03b207020f8e5c) --- net/ipv4/ipconfig.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 5bbef4fdcb43..648fa1490ea7 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -262,7 +262,8 @@ static int __init ic_open_devs(void) /* wait for a carrier on at least one device */ start = jiffies; next_msg = start + msecs_to_jiffies(CONF_CARRIER_TIMEOUT/12); - while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) { + while (time_before(jiffies, start + + msecs_to_jiffies(CONF_CARRIER_TIMEOUT))) { int wait, elapsed; for_each_netdev(&init_net, dev) -- GitLab From 8edf97bb154c99c97dabc83100e812a0abb748da Mon Sep 17 00:00:00 2001 From: Chris Novakovic Date: Tue, 24 Apr 2018 03:56:37 +0100 Subject: [PATCH 416/528] ipconfig: Correctly initialise ic_nameservers [ Upstream commit 300eec7c0a2495f771709c7642aa15f7cc148b83 ] ic_nameservers, which stores the list of name servers discovered by ipconfig, is initialised (i.e. has all of its elements set to NONE, or 0xffffffff) by ic_nameservers_predef() in the following scenarios: - before the "ip=" and "nfsaddrs=" kernel command line parameters are parsed (in ip_auto_config_setup()); - before autoconfiguring via DHCP or BOOTP (in ic_bootp_init()), in order to clear any values that may have been set after parsing "ip=" or "nfsaddrs=" and are no longer needed. This means that ic_nameservers_predef() is not called when neither "ip=" nor "nfsaddrs=" is specified on the kernel command line. In this scenario, every element in ic_nameservers remains set to 0x00000000, which is indistinguishable from ANY and causes pnp_seq_show() to write the following (bogus) information to /proc/net/pnp: #MANUAL nameserver 0.0.0.0 nameserver 0.0.0.0 nameserver 0.0.0.0 This is potentially problematic for systems that blindly link /etc/resolv.conf to /proc/net/pnp. Ensure that ic_nameservers is also initialised when neither "ip=" nor "nfsaddrs=" are specified by calling ic_nameservers_predef() in ip_auto_config(), but only when ip_auto_config_setup() was not called earlier. This causes the following to be written to /proc/net/pnp, and is consistent with what gets written when ipconfig is configured manually but no name servers are specified on the kernel command line: #MANUAL Signed-off-by: Chris Novakovic Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 7adeb517707aafcef10c25c382f369295f54dac9) --- net/ipv4/ipconfig.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 648fa1490ea7..3da772ae8808 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -772,6 +772,11 @@ static void __init ic_bootp_init_ext(u8 *e) */ static inline void __init ic_bootp_init(void) { + /* Re-initialise all name servers to NONE, in case any were set via the + * "ip=" or "nfsaddrs=" kernel command line parameters: any IP addresses + * specified there will already have been decoded but are no longer + * needed + */ ic_nameservers_predef(); dev_add_pack(&bootp_packet_type); @@ -1404,6 +1409,13 @@ static int __init ip_auto_config(void) int err; unsigned int i; + /* Initialise all name servers to NONE (but only if the "ip=" or + * "nfsaddrs=" kernel command line parameters weren't decoded, otherwise + * we'll overwrite the IP addresses specified there) + */ + if (ic_set_manually == 0) + ic_nameservers_predef(); + #ifdef CONFIG_PROC_FS proc_create("pnp", S_IRUGO, init_net.proc_net, &pnp_seq_fops); #endif /* CONFIG_PROC_FS */ @@ -1605,6 +1617,7 @@ static int __init ip_auto_config_setup(char *addrs) return 1; } + /* Initialise all name servers to NONE */ ic_nameservers_predef(); /* Parse string for static IP assignment. */ -- GitLab From 3d7722e809e52c0b998cc438f52e5796caaf88de Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 30 Nov 2016 02:56:47 +0900 Subject: [PATCH 417/528] net: ipv4: Don't crash if passing a null sk to ip_rt_update_pmtu. Commit e2d118a1cb5e ("net: inet: Support UID-based routing in IP protocols.") made __build_flow_key call sock_net(sk) to determine the network namespace of the passed-in socket. This crashes if sk is NULL. Fix this by getting the network namespace from the skb instead. [Backport of net-next d109e61bfe7a468fd8df4a7ceb65635e7aa909a0] Bug: 16355602 Change-Id: I27161b70f448bb95adce3994a97920d54987ce4e Fixes: e2d118a1cb5e ("net: inet: Support UID-based routing in IP protocols.") Reported-by: Erez Shitrit Signed-off-by: Lorenzo Colitti Signed-off-by: David S. Miller Git-commit: ca05d6a257c539ccb3e12d7c7f874f5baf20a015 Git-repo: https://android.googlesource.com/kernel/common.git Signed-off-by: Srinivasarao P (cherry picked from commit 94432eb12cae3e47fc3b2d04779e801f07ca0e29) --- net/ipv4/route.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 292c08985b0f..4f3c789cb77e 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -539,13 +539,14 @@ static void __build_flow_key(const struct net *net, struct flowi4 *fl4, static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb, const struct sock *sk) { + const struct net *net = dev_net(skb->dev); const struct iphdr *iph = ip_hdr(skb); int oif = skb->dev->ifindex; u8 tos = RT_TOS(iph->tos); u8 prot = iph->protocol; u32 mark = skb->mark; - __build_flow_key(sock_net(sk), fl4, sk, iph, oif, tos, prot, mark, 0); + __build_flow_key(net, fl4, sk, iph, oif, tos, prot, mark, 0); } static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk) -- GitLab From 323f2375d2ce75aa0afa895700a0936671a6fd4c Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 23 Dec 2016 00:33:57 +0900 Subject: [PATCH 418/528] UPSTREAM: net: ipv4: Don't crash if passing a null sk to ip_do_redirect. Commit e2d118a1cb5e ("net: inet: Support UID-based routing in IP protocols.") made ip_do_redirect call sock_net(sk) to determine the network namespace of the passed-in socket. This crashes if sk is NULL. Fix this by getting the network namespace from the skb instead. Fixes: e2d118a1cb5e ("net: inet: Support UID-based routing in IP protocols.") Signed-off-by: Lorenzo Colitti Signed-off-by: David S. Miller Change-Id: I16a3c343cb142c482ca6dd363c28b3a12d73a46d Fixes: Change-Id: I910504b508948057912bc188fd1e8aca28294de3 ("net: inet: Support UID-based routing in IP protocols.") (cherry picked from commit 7d99569460eae28b187d574aec930a4cf8b90441) Signed-off-by: Amit Pundir Git-commit: 8703ea3d29931265cd3dac73ac9a5f85d92a7e55 Git-repo: https://android.googlesource.com/kernel/common.git Signed-off-by: Srinivasarao P (cherry picked from commit 8f9281111704ce71898e669340b1c0364cd969c7) --- net/ipv4/route.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 4f3c789cb77e..e48756873808 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -758,6 +758,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf struct rtable *rt; struct flowi4 fl4; const struct iphdr *iph = (const struct iphdr *) skb->data; + struct net *net = dev_net(skb->dev); int oif = skb->dev->ifindex; u8 tos = RT_TOS(iph->tos); u8 prot = iph->protocol; @@ -765,7 +766,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf rt = (struct rtable *) dst; - __build_flow_key(sock_net(sk), &fl4, sk, iph, oif, tos, prot, mark, 0); + __build_flow_key(net, &fl4, sk, iph, oif, tos, prot, mark, 0); __ip_do_redirect(rt, skb, &fl4, true); } -- GitLab From 204430d88218bcf421ced018b2ec268a09c4f128 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Fri, 17 Nov 2017 14:27:06 +0800 Subject: [PATCH 419/528] route: update fnhe_expires for redirect when the fnhe exists commit e39d5246111399dbc6e11cd39fd8580191b86c47 upstream. Now when creating fnhe for redirect, it sets fnhe_expires for this new route cache. But when updating the exist one, it doesn't do it. It will cause this fnhe never to be expired. Paolo already noticed it before, in Jianlin's test case, it became even worse: When ip route flush cache, the old fnhe is not to be removed, but only clean it's members. When redirect comes again, this fnhe will be found and updated, but never be expired due to fnhe_expires not being set. So fix it by simply updating fnhe_expires even it's for redirect. Fixes: aee06da6726d ("ipv4: use seqlock for nh_exceptions") Reported-by: Jianlin Shi Acked-by: Hannes Frederic Sowa Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Ben Hutchings [aviraxp: backport to 3.10, adjust context] (cherry picked from commit f32b17d86d6f67808552ab27d5df587e1b2a3a16) --- net/ipv4/route.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index e48756873808..dadfd8cee563 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -643,10 +643,9 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, if (fnhe) { if (gw) fnhe->fnhe_gw = gw; - if (pmtu) { + if (pmtu) fnhe->fnhe_pmtu = pmtu; - fnhe->fnhe_expires = expires; - } + fnhe->fnhe_expires = expires; } else { if (depth > FNHE_RECLAIM_DEPTH) fnhe = fnhe_oldest(hash); -- GitLab From da5ec75d57b67f53cd5b789378c79958ae9bfc3a Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Mon, 26 Feb 2018 16:13:43 +0100 Subject: [PATCH 420/528] net: ipv4: don't allow setting net.ipv4.route.min_pmtu below 68 [ Upstream commit c7272c2f1229125f74f22dcdd59de9bbd804f1c8 ] According to RFC 1191 sections 3 and 4, ICMP frag-needed messages indicating an MTU below 68 should be rejected: A host MUST never reduce its estimate of the Path MTU below 68 octets. and (talking about ICMP frag-needed's Next-Hop MTU field): This field will never contain a value less than 68, since every router "must be able to forward a datagram of 68 octets without fragmentation". Furthermore, by letting net.ipv4.route.min_pmtu be set to negative values, we can end up with a very large PMTU when (-1) is cast into u32. Let's also make ip_rt_min_pmtu a u32, since it's only ever compared to unsigned ints. Reported-by: Jianlin Shi Signed-off-by: Sabrina Dubroca Reviewed-by: Stefano Brivio Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 474f7309b9f34a15a7623204da8dc4cfa0ac69b8) --- net/ipv4/route.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index dadfd8cee563..2d33a4f6ae59 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -124,9 +124,11 @@ static int ip_rt_redirect_silence __read_mostly = ((HZ / 50) << (9 + 1)); static int ip_rt_error_cost __read_mostly = HZ; static int ip_rt_error_burst __read_mostly = 5 * HZ; static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; -static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; +static u32 ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; static int ip_rt_min_advmss __read_mostly = 256; +static int ip_min_valid_pmtu __read_mostly = IPV4_MIN_MTU; + /* * Interface to generic destination cache. */ @@ -2604,7 +2606,8 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_min_pmtu, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &ip_min_valid_pmtu, }, { .procname = "min_adv_mss", -- GitLab From 6f57f789a8c74ee166ac92450de1e3511843aca1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 11 Dec 2017 07:17:39 -0800 Subject: [PATCH 421/528] ipv4: igmp: guard against silly MTU values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b5476022bbada3764609368f03329ca287528dc8 ] IPv4 stack reacts to changes to small MTU, by disabling itself under RTNL. But there is a window where threads not using RTNL can see a wrong device mtu. This can lead to surprises, in igmp code where it is assumed the mtu is suitable. Fix this by reading device mtu once and checking IPv4 minimal MTU. This patch adds missing IPV4_MIN_MTU define, to not abuse ETH_MIN_MTU anymore. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: ahmedradaideh (cherry picked from commit 975562a77eb7e70c225b1b1bc3e52c47a5a2d565) --- include/net/ip.h | 2 ++ net/ipv4/devinet.c | 2 +- net/ipv4/igmp.c | 24 +++++++++++++++--------- net/ipv4/ip_tunnel.c | 4 ++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index c02d09be8ad0..6922e1ea084a 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -31,6 +31,8 @@ #include #include +#define IPV4_MIN_MTU 68 /* RFC 791 */ + struct sock; struct inet_skb_parm { diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index ee3c309ef4a2..bffeea0927f3 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1324,7 +1324,7 @@ skip: static bool inetdev_valid_mtu(unsigned int mtu) { - return mtu >= 68; + return mtu >= IPV4_MIN_MTU; } static void inetdev_send_gratuitous_arp(struct net_device *dev, diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 4572ee7c71f4..cf66f3fe83ab 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -381,16 +381,17 @@ static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel) } static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc, - int type, struct igmpv3_grec **ppgr) + int type, struct igmpv3_grec **ppgr, unsigned int mtu) { struct net_device *dev = pmc->interface->dev; struct igmpv3_report *pih; struct igmpv3_grec *pgr; - if (!skb) - skb = igmpv3_newpack(dev, dev->mtu); - if (!skb) - return NULL; + if (!skb) { + skb = igmpv3_newpack(dev, mtu); + if (!skb) + return NULL; + } pgr = (struct igmpv3_grec *)skb_put(skb, sizeof(struct igmpv3_grec)); pgr->grec_type = type; pgr->grec_auxwords = 0; @@ -413,10 +414,15 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, struct igmpv3_grec *pgr = NULL; struct ip_sf_list *psf, *psf_next, *psf_prev, **psf_list; int scount, stotal, first, isquery, truncate; + unsigned int mtu; if (pmc->multiaddr == IGMP_ALL_HOSTS) return skb; + mtu = READ_ONCE(dev->mtu); + if (mtu < IPV4_MIN_MTU) + return skb; + isquery = type == IGMPV3_MODE_IS_INCLUDE || type == IGMPV3_MODE_IS_EXCLUDE; truncate = type == IGMPV3_MODE_IS_EXCLUDE || @@ -437,7 +443,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { if (skb) igmpv3_sendpack(skb); - skb = igmpv3_newpack(dev, dev->mtu); + skb = igmpv3_newpack(dev, mtu); } } first = 1; @@ -464,12 +470,12 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, pgr->grec_nsrcs = htons(scount); if (skb) igmpv3_sendpack(skb); - skb = igmpv3_newpack(dev, dev->mtu); + skb = igmpv3_newpack(dev, mtu); first = 1; scount = 0; } if (first) { - skb = add_grhead(skb, pmc, type, &pgr); + skb = add_grhead(skb, pmc, type, &pgr, mtu); first = 0; } if (!skb) @@ -503,7 +509,7 @@ empty_source: igmpv3_sendpack(skb); skb = NULL; /* add_grhead will get a new one */ } - skb = add_grhead(skb, pmc, type, &pgr); + skb = add_grhead(skb, pmc, type, &pgr, mtu); } } if (pgr) diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 84aa69caee59..425f4e44f812 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -379,8 +379,8 @@ static int ip_tunnel_bind_dev(struct net_device *dev) dev->needed_headroom = t_hlen + hlen; mtu -= (dev->hard_header_len + t_hlen); - if (mtu < 68) - mtu = 68; + if (mtu < IPV4_MIN_MTU) + mtu = IPV4_MIN_MTU; return mtu; } -- GitLab From f3dba433bd9bc990b089735c93f821f8e4bb6024 Mon Sep 17 00:00:00 2001 From: TARKZiM Date: Sun, 18 Apr 2021 11:59:01 +0800 Subject: [PATCH 422/528] defconfig: ivy: Update configs for R Change-Id: I5823e3f7b4ceb73017856fc0a64a5ee1bd07f694 --- arch/arm64/configs/kitakami_ivy_defconfig | 31 +++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/arch/arm64/configs/kitakami_ivy_defconfig b/arch/arm64/configs/kitakami_ivy_defconfig index b5a2dd791130..46cf73fc6b47 100644 --- a/arch/arm64/configs/kitakami_ivy_defconfig +++ b/arch/arm64/configs/kitakami_ivy_defconfig @@ -4,6 +4,11 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y CONFIG_HARDENED_USERCOPY=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_BOOST=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_LOG_BUF_SHIFT=18 CONFIG_CGROUPS=y @@ -29,8 +34,12 @@ CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_ARCH_MMAP_RND_BITS=24 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_TEST is not set +CONFIG_IOSCHED_BFQ=y +CONFIG_CGROUP_BFQIO=y CONFIG_ARCH_MSM=y CONFIG_ARCH_MSM8994=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y @@ -42,11 +51,12 @@ CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_ARMV7_COMPAT=y -CONFIG_KSM=y +# CONFIG_KSM is not set CONFIG_SWAP_CONSIDER_CMA_FREE=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y +CONFIG_PROC_DEVICETREE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v1-kitakami_ivy_generic msm8994-v2.0-kitakami_ivy_generic msm8994-v2.1-kitakami_ivy_generic" # CONFIG_COREDUMP is not set @@ -57,7 +67,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set CONFIG_PM_RUNTIME=y CONFIG_SUSPEND_TIME=y -CONFIG_WAKEUP_IRQ_DEBUG=y +# CONFIG_WAKEUP_IRQ_DEBUG is not set CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y @@ -78,6 +88,8 @@ CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_XFRM_RFC_4868_TRUNCATION=y CONFIG_INET=y +CONFIG_WIREGUARD=y +# CONFIG_WIREGUARD_DEBUG is not set CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y @@ -223,7 +235,7 @@ CONFIG_ZRAM_LZ4_COMPRESS=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_UID_STAT=y -CONFIG_UID_CPUTIME=y +CONFIG_UID_SYS_STATS=y CONFIG_PMI8994_FLASH=y CONFIG_QSEECOM=y CONFIG_NFC_PN547=y @@ -231,9 +243,9 @@ CONFIG_TI_DRV2667=y CONFIG_QCOM_LIQUID_DOCK=y CONFIG_RAMDUMP_TAGS=y CONFIG_POWERKEY_FORCECRASH=y -CONFIG_RAMDUMP_MEMDESC=y +# CONFIG_RAMDUMP_MEMDESC is not set CONFIG_CRASH_LAST_LOGS=y -CONFIG_BCM_WLAN_RAMDUMP=y +# CONFIG_BCM_WLAN_RAMDUMP is not set CONFIG_LDO_VIBRATOR=y CONFIG_SIM_DETECT=y CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y @@ -533,7 +545,7 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y CONFIG_ONESHOT_SYNC=y CONFIG_ION=y CONFIG_ION_MSM=y -CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set CONFIG_SPS=y CONFIG_USB_BAM=y CONFIG_SPS_SUPPORT_NDP_BAM=y @@ -612,9 +624,11 @@ CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_PMSG=y CONFIG_PSTORE_RAM=y CONFIG_CIFS=y -CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y +CONFIG_FAT_DEFAULT_IOCHARSET="utf8" +CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_CHECK_RO_ATTR=y +# CONFIG_SDFAT_DEBUG is not set CONFIG_NLS_UTF8=y CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y @@ -664,3 +678,4 @@ CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y CONFIG_MISC_FILESYSTEMS=y CONFIG_ECRYPT_FS=y CONFIG_WTL_ENCRYPTION_FILTER=y +CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y -- GitLab From f06e123f15ec5a6f38b4de1d4ca2e46e337dc6c7 Mon Sep 17 00:00:00 2001 From: Bernhard Thoben Date: Tue, 20 Jul 2021 17:18:55 +0200 Subject: [PATCH 423/528] defconfig: kitakami: Added some settings for "CONFIG_SDFAT". This increases the write speed on /sdcard partition dramatically. suzuran:/ $ dd if=/dev/zero of=/sdcard/output count=65536 65536+0 records in 65536+0 records out 33554432 bytes (32 M) copied, 0.706444 s, 45 M/s suzuran:/ $ Change-Id: Iaf6fd28c9f8b422fe5b912c5c776786f5203da77 --- arch/arm64/configs/kitakami_ivy_defconfig | 13 +++++++++++-- arch/arm64/configs/kitakami_satsuki_defconfig | 13 +++++++++++-- arch/arm64/configs/kitakami_sumire_defconfig | 13 +++++++++++-- arch/arm64/configs/kitakami_suzuran_defconfig | 13 +++++++++++-- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/arch/arm64/configs/kitakami_ivy_defconfig b/arch/arm64/configs/kitakami_ivy_defconfig index 46cf73fc6b47..7bbb6b30f29e 100644 --- a/arch/arm64/configs/kitakami_ivy_defconfig +++ b/arch/arm64/configs/kitakami_ivy_defconfig @@ -626,9 +626,18 @@ CONFIG_PSTORE_RAM=y CONFIG_CIFS=y CONFIG_NLS_ASCII=y CONFIG_FAT_DEFAULT_IOCHARSET="utf8" -CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y -# CONFIG_SDFAT_DEBUG is not set +CONFIG_SDFAT_DBG_MSG=y +CONFIG_SDFAT_DEBUG=y +CONFIG_SDFAT_DEFAULT_CODEPAGE=437 +CONFIG_SDFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_SDFAT_DELAYED_META_DIRTY=y +CONFIG_SDFAT_FS=y +CONFIG_SDFAT_STATISTICS=y +CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" +CONFIG_SDFAT_VIRTUAL_XATTR=y CONFIG_NLS_UTF8=y CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y diff --git a/arch/arm64/configs/kitakami_satsuki_defconfig b/arch/arm64/configs/kitakami_satsuki_defconfig index 95a13847a93b..37febc1f3a2b 100644 --- a/arch/arm64/configs/kitakami_satsuki_defconfig +++ b/arch/arm64/configs/kitakami_satsuki_defconfig @@ -629,9 +629,18 @@ CONFIG_PSTORE_RAM=y CONFIG_CIFS=y CONFIG_NLS_ASCII=y CONFIG_FAT_DEFAULT_IOCHARSET="utf8" -CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y -# CONFIG_SDFAT_DEBUG is not set +CONFIG_SDFAT_DBG_MSG=y +CONFIG_SDFAT_DEBUG=y +CONFIG_SDFAT_DEFAULT_CODEPAGE=437 +CONFIG_SDFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_SDFAT_DELAYED_META_DIRTY=y +CONFIG_SDFAT_FS=y +CONFIG_SDFAT_STATISTICS=y +CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" +CONFIG_SDFAT_VIRTUAL_XATTR=y CONFIG_NLS_UTF8=y CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index 7999def8f401..12abaa637636 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -628,9 +628,18 @@ CONFIG_PSTORE_RAM=y CONFIG_CIFS=y CONFIG_NLS_ASCII=y CONFIG_FAT_DEFAULT_IOCHARSET="utf8" -CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y -# CONFIG_SDFAT_DEBUG is not set +CONFIG_SDFAT_DBG_MSG=y +CONFIG_SDFAT_DEBUG=y +CONFIG_SDFAT_DEFAULT_CODEPAGE=437 +CONFIG_SDFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_SDFAT_DELAYED_META_DIRTY=y +CONFIG_SDFAT_FS=y +CONFIG_SDFAT_STATISTICS=y +CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" +CONFIG_SDFAT_VIRTUAL_XATTR=y CONFIG_NLS_UTF8=y CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y diff --git a/arch/arm64/configs/kitakami_suzuran_defconfig b/arch/arm64/configs/kitakami_suzuran_defconfig index a9d2831e6987..617063d7cc2b 100644 --- a/arch/arm64/configs/kitakami_suzuran_defconfig +++ b/arch/arm64/configs/kitakami_suzuran_defconfig @@ -621,9 +621,18 @@ CONFIG_PSTORE_RAM=y CONFIG_CIFS=y CONFIG_NLS_ASCII=y CONFIG_FAT_DEFAULT_IOCHARSET="utf8" -CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y -# CONFIG_SDFAT_DEBUG is not set +CONFIG_SDFAT_DBG_MSG=y +CONFIG_SDFAT_DEBUG=y +CONFIG_SDFAT_DEFAULT_CODEPAGE=437 +CONFIG_SDFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_SDFAT_DELAYED_META_DIRTY=y +CONFIG_SDFAT_FS=y +CONFIG_SDFAT_STATISTICS=y +CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" +CONFIG_SDFAT_VIRTUAL_XATTR=y CONFIG_NLS_UTF8=y CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y -- GitLab From bc339f495ea5ff332d2abe1ca9b3cc4bb3cb9d89 Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Mon, 19 May 2014 10:24:01 +0530 Subject: [PATCH 424/528] cpufreq: remove race while accessing cur_policy While accessing cur_policy during executing events CPUFREQ_GOV_START, CPUFREQ_GOV_STOP, CPUFREQ_GOV_LIMITS, same mutex lock is not taken, dbs_data->mutex, which leads to race and data corruption while running continious suspend resume test. This is seen with ondemand governor with suspend resume test using rtcwake. Unable to handle kernel NULL pointer dereference at virtual address 00000028 pgd = ed610000 [00000028] *pgd=adf11831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: nvhost_vi CPU: 1 PID: 3243 Comm: rtcwake Not tainted 3.10.24-gf5cf9e5 #1 task: ee708040 ti: ed61c000 task.ti: ed61c000 PC is at cpufreq_governor_dbs+0x400/0x634 LR is at cpufreq_governor_dbs+0x3f8/0x634 pc : [] lr : [] psr: 600f0013 sp : ed61dcb0 ip : 000493e0 fp : c1cc14f0 r10: 00000000 r9 : 00000000 r8 : 00000000 r7 : eb725280 r6 : c1cc1560 r5 : eb575200 r4 : ebad7740 r3 : ee708040 r2 : ed61dca8 r1 : 001ebd24 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c5387d Table: ad61006a DAC: 00000015 [] (cpufreq_governor_dbs+0x400/0x634) from [] (__cpufreq_governor+0x98/0x1b4) [] (__cpufreq_governor+0x98/0x1b4) from [] (__cpufreq_set_policy+0x250/0x320) [] (__cpufreq_set_policy+0x250/0x320) from [] (cpufreq_update_policy+0xcc/0x168) [] (cpufreq_update_policy+0xcc/0x168) from [] (cpu_freq_notify+0x68/0xdc) [] (cpu_freq_notify+0x68/0xdc) from [] (notifier_call_chain+0x4c/0x8c) [] (notifier_call_chain+0x4c/0x8c) from [] (__blocking_notifier_call_chain+0x50/0x68) [] (__blocking_notifier_call_chain+0x50/0x68) from [] (blocking_notifier_call_chain+0x20/0x28) [] (blocking_notifier_call_chain+0x20/0x28) from [] (pm_qos_update_bounded_target+0xd8/0x310) [] (pm_qos_update_bounded_target+0xd8/0x310) from [] (__pm_qos_update_request+0x64/0x70) [] (__pm_qos_update_request+0x64/0x70) from [] (tegra_pm_notify+0x114/0x134) [] (tegra_pm_notify+0x114/0x134) from [] (notifier_call_chain+0x4c/0x8c) [] (notifier_call_chain+0x4c/0x8c) from [] (__blocking_notifier_call_chain+0x50/0x68) [] (__blocking_notifier_call_chain+0x50/0x68) from [] (blocking_notifier_call_chain+0x20/0x28) [] (blocking_notifier_call_chain+0x20/0x28) from [] (pm_notifier_call_chain+0x1c/0x34) [] (pm_notifier_call_chain+0x1c/0x34) from [] (enter_state+0xec/0x128) [] (enter_state+0xec/0x128) from [] (pm_suspend+0x38/0xa4) [] (pm_suspend+0x38/0xa4) from [] (state_store+0x70/0xc0) [] (state_store+0x70/0xc0) from [] (kobj_attr_store+0x14/0x20) [] (kobj_attr_store+0x14/0x20) from [] (sysfs_write_file+0x104/0x184) [] (sysfs_write_file+0x104/0x184) from [] (vfs_write+0xd0/0x19c) [] (vfs_write+0xd0/0x19c) from [] (SyS_write+0x4c/0x78) [] (SyS_write+0x4c/0x78) from [] (ret_fast_syscall+0x0/0x30) Code: e1a00006 eb084346 e59b0020 e5951024 (e5903028) ---[ end trace 0488523c8f6b0f9d ]--- Signed-off-by: Bibek Basu Acked-by: Viresh Kumar Cc: 3.11+ # 3.11+ Signed-off-by: Rafael J. Wysocki Change-Id: I86f7783abb81e3a4f691a42b2e001383e1b1dd9a --- drivers/cpufreq/cpufreq_governor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index e6be63561fa6..922ab10b4d12 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -362,6 +362,11 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, break; case CPUFREQ_GOV_LIMITS: + mutex_lock(&dbs_data->mutex); + if (!cpu_cdbs->cur_policy) { + mutex_unlock(&dbs_data->mutex); + break; + } mutex_lock(&cpu_cdbs->timer_mutex); if (policy->max < cpu_cdbs->cur_policy->cur) __cpufreq_driver_target(cpu_cdbs->cur_policy, @@ -371,6 +376,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); mutex_unlock(&cpu_cdbs->timer_mutex); + mutex_unlock(&dbs_data->mutex); break; } return 0; -- GitLab From c3d5abcf10f7932aff94f8f406cbc90a4f3ae3e2 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Sun, 8 Jun 2014 02:11:43 +0530 Subject: [PATCH 425/528] cpufreq: governor: Be friendly towards latency-sensitive bursty workloads Cpufreq governors like the ondemand governor calculate the load on the CPU periodically by employing deferrable timers. A deferrable timer won't fire if the CPU is completely idle (and there are no other timers to be run), in order to avoid unnecessary wakeups and thus save CPU power. However, the load calculation logic is agnostic to all this, and this can lead to the problem described below. Time (ms) CPU 1 100 Task-A running 110 Governor's timer fires, finds load as 100% in the last 10ms interval and increases the CPU frequency. 110.5 Task-A running 120 Governor's timer fires, finds load as 100% in the last 10ms interval and increases the CPU frequency. 125 Task-A went to sleep. With nothing else to do, CPU 1 went completely idle. 200 Task-A woke up and started running again. 200.5 Governor's deferred timer (which was originally programmed to fire at time 130) fires now. It calculates load for the time period 120 to 200.5, and finds the load is almost zero. Hence it decreases the CPU frequency to the minimum. 210 Governor's timer fires, finds load as 100% in the last 10ms interval and increases the CPU frequency. So, after the workload woke up and started running, the frequency was suddenly dropped to absolute minimum, and after that, there was an unnecessary delay of 10ms (sampling period) to increase the CPU frequency back to a reasonable value. And this pattern repeats for every wake-up-from-cpu-idle for that workload. This can be quite undesirable for latency- or response-time sensitive bursty workloads. So we need to fix the governor's logic to detect such wake-up-from- cpu-idle scenarios and start the workload at a reasonably high CPU frequency. One extreme solution would be to fake a load of 100% in such scenarios. But that might lead to undesirable side-effects such as frequency spikes (which might also need voltage changes) especially if the previous frequency happened to be very low. We just want to avoid the stupidity of dropping down the frequency to a minimum and then enduring a needless (and long) delay before ramping it up back again. So, let us simply carry forward the previous load - that is, let us just pretend that the 'load' for the current time-window is the same as the load for the previous window. That way, the frequency and voltage will continue to be set to whatever values they were set at previously. This means that bursty workloads will get a chance to influence the CPU frequency at which they wake up from cpu-idle, based on their past execution history. Thus, they might be able to avoid suffering from slow wakeups and long response-times. However, we should take care not to over-do this. For example, such a "copy previous load" logic will benefit cases like this: (where # represents busy and . represents idle) but it will be detrimental in cases like the one shown below, because it will retain the high frequency (copied from the previous interval) even in a mostly idle system: (i.e., the workload finished and the remaining tasks are such that their busy periods are smaller than the sampling interval, which causes the timer to always get deferred. So, this will make the copy-previous-load logic copy the initial high load to subsequent idle periods over and over again, thus keeping the frequency high unnecessarily). So, we modify this copy-previous-load logic such that it is used only once upon every wakeup-from-idle. Thus if we have 2 consecutive idle periods, the previous load won't get blindly copied over; cpufreq will freshly evaluate the load in the second idle interval, thus ensuring that the system comes back to its normal state. [ The right way to solve this whole problem is to teach the CPU frequency governors to also track load on a per-task basis, not just a per-CPU basis, and then use both the data sources intelligently to set the appropriate frequency on the CPUs. But that involves redesigning the cpufreq subsystem, so this patch should make the situation bearable until then. ] Experimental results: +-------------------+ I ran a modified version of ebizzy (called 'sleeping-ebizzy') that sleeps in between its execution such that its total utilization can be a user-defined value, say 10% or 20% (higher the utilization specified, lesser the amount of sleeps injected). This ebizzy was run with a single-thread, tied to CPU 8. Behavior observed with tracing (sample taken from 40% utilization runs): Change-Id: I89c5df665cc238b44b8df4f50dba458b643e4290 ------------------------------------------------------------------------ Without patch: ~~~~~~~~~~~~~~ kworker/8:2-12137 416.335742: cpu_frequency: state=2061000 cpu_id=8 kworker/8:2-12137 416.335744: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40753 416.345741: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-12137 416.345744: cpu_frequency: state=4123000 cpu_id=8 kworker/8:2-12137 416.345746: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40753 416.355738: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 --------------------------------------------------------------------- <...>-40753 416.402202: sched_switch: prev_comm=ebizzy ==> next_comm=swapper/8 -0 416.502130: sched_switch: prev_comm=swapper/8 ==> next_comm=ebizzy <...>-40753 416.505738: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-12137 416.505739: cpu_frequency: state=2061000 cpu_id=8 kworker/8:2-12137 416.505741: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40753 416.515739: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-12137 416.515742: cpu_frequency: state=4123000 cpu_id=8 kworker/8:2-12137 416.515744: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy Observation: Ebizzy went idle at 416.402202, and started running again at 416.502130. But cpufreq noticed the long idle period, and dropped the frequency at 416.505739, only to increase it back again at 416.515742, realizing that the workload is in-fact CPU bound. Thus ebizzy needlessly ran at the lowest frequency for almost 13 milliseconds (almost 1 full sample period), and this pattern repeats on every sleep-wakeup. This could hurt latency-sensitive workloads quite a lot. With patch: ~~~~~~~~~~~ kworker/8:2-29802 464.832535: cpu_frequency: state=2061000 cpu_id=8 --------------------------------------------------------------------- kworker/8:2-29802 464.962538: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 464.972533: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-29802 464.972536: cpu_frequency: state=4123000 cpu_id=8 kworker/8:2-29802 464.972538: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 464.982531: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 --------------------------------------------------------------------- kworker/8:2-29802 465.022533: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 465.032531: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-29802 465.032532: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 465.035797: sched_switch: prev_comm=ebizzy ==> next_comm=swapper/8 -0 465.240178: sched_switch: prev_comm=swapper/8 ==> next_comm=ebizzy <...>-40738 465.242533: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-29802 465.242535: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 465.252531: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 Observation: Ebizzy went idle at 465.035797, and started running again at 465.240178. Since ebizzy was the only real workload running on this CPU, cpufreq retained the frequency at 4.1Ghz throughout the run of ebizzy, no matter how many times ebizzy slept and woke-up in-between. Thus, ebizzy got the 10ms worth of 4.1 Ghz benefit during every sleep-wakeup (as compared to the run without the patch) and this boost gave a modest improvement in total throughput, as shown below. Sleeping-ebizzy records-per-second: ----------------------------------- Utilization Without patch With patch Difference (Absolute and % values) 10% 274767 277046 + 2279 (+0.829%) 20% 543429 553484 + 10055 (+1.850%) 40% 1090744 1107959 + 17215 (+1.578%) 60% 1634908 1662018 + 27110 (+1.658%) A rudimentary and somewhat approximately latency-sensitive workload such as sleeping-ebizzy itself showed a consistent, noticeable performance improvement with this patch. Hence, workloads that are truly latency-sensitive will benefit quite a bit from this change. Moreover, this is an overall win-win since this patch does not hurt power-savings at all (because, this patch does not reduce the idle time or idle residency; and the high frequency of the CPU when it goes to cpu-idle does not affect/hurt the power-savings of deep idle states). Signed-off-by: Srivatsa S. Bhat Reviewed-by: Gautham R. Shenoy Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki Change-Id: Icfc3d321c110c5f6aa90c2fa867ad158f4f0d55b --- drivers/cpufreq/cpufreq_governor.c | 58 ++++++++++++++++++++++++++++-- drivers/cpufreq/cpufreq_governor.h | 6 ++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 922ab10b4d12..a1c56cc59766 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -36,14 +36,29 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cpufreq_policy *policy; + unsigned int sampling_rate; unsigned int max_load = 0; unsigned int ignore_nice; unsigned int j; - if (dbs_data->cdata->governor == GOV_ONDEMAND) + if (dbs_data->cdata->governor == GOV_ONDEMAND) { + struct od_cpu_dbs_info_s *od_dbs_info = + dbs_data->cdata->get_cpu_dbs_info_s(cpu); + + /* + * Sometimes, the ondemand governor uses an additional + * multiplier to give long delays. So apply this multiplier to + * the 'sampling_rate', so as to keep the wake-up-from-idle + * detection logic a bit conservative. + */ + sampling_rate = od_tuners->sampling_rate; + sampling_rate *= od_dbs_info->rate_mult; + ignore_nice = od_tuners->ignore_nice_load; - else + } else { + sampling_rate = cs_tuners->sampling_rate; ignore_nice = cs_tuners->ignore_nice_load; + } policy = cdbs->cur_policy; @@ -96,7 +111,36 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) if (unlikely(!wall_time || wall_time < idle_time)) continue; - load = 100 * (wall_time - idle_time) / wall_time; + /* + * If the CPU had gone completely idle, and a task just woke up + * on this CPU now, it would be unfair to calculate 'load' the + * usual way for this elapsed time-window, because it will show + * near-zero load, irrespective of how CPU intensive that task + * actually is. This is undesirable for latency-sensitive bursty + * workloads. + * + * To avoid this, we reuse the 'load' from the previous + * time-window and give this task a chance to start with a + * reasonably high CPU frequency. (However, we shouldn't over-do + * this copy, lest we get stuck at a high load (high frequency) + * for too long, even when the current system load has actually + * dropped down. So we perform the copy only once, upon the + * first wake-up from idle.) + * + * Detecting this situation is easy: the governor's deferrable + * timer would not have fired during CPU-idle periods. Hence + * an unusually large 'wall_time' (as compared to the sampling + * rate) indicates this scenario. + */ + if (unlikely(wall_time > (2 * sampling_rate)) && + j_cdbs->copy_prev_load) { + load = j_cdbs->prev_load; + j_cdbs->copy_prev_load = false; + } else { + load = 100 * (wall_time - idle_time) / wall_time; + j_cdbs->prev_load = load; + j_cdbs->copy_prev_load = true; + } if (load > max_load) max_load = load; @@ -314,11 +358,19 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, for_each_cpu(j, policy->cpus) { struct cpu_dbs_common_info *j_cdbs = dbs_data->cdata->get_cpu_cdbs(j); + unsigned int prev_load; j_cdbs->cpu = j; j_cdbs->cur_policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); + + prev_load = (unsigned int) + (j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle); + j_cdbs->prev_load = 100 * prev_load / + (unsigned int) j_cdbs->prev_cpu_wall; + j_cdbs->copy_prev_load = true; + if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index b5f2b8618949..2e920847ef74 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -134,6 +134,12 @@ struct cpu_dbs_common_info { u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; + unsigned int prev_load; + /* + * Flag to ensure that we copy the previous load only once, upon the + * first wake-up from idle. + */ + bool copy_prev_load; struct cpufreq_policy *cur_policy; struct delayed_work work; /* -- GitLab From 9a3dd9f2ddcd04082a0cb730ce68a2c77c00d90c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 9 Jun 2014 14:21:24 +0530 Subject: [PATCH 426/528] cpufreq: governor: remove copy_prev_load from 'struct cpu_dbs_common_info' 'copy_prev_load' was recently added by commit: 18b46ab (cpufreq: governor: Be friendly towards latency-sensitive bursty workloads). It actually is a bit redundant as we also have 'prev_load' which can store any integer value and can be used instead of 'copy_prev_load' by setting it zero. True load can also turn out to be zero during long idle intervals (and hence the actual value of 'prev_load' and the overloaded value can clash). However this is not a problem because, if the true load was really zero in the previous interval, it makes sense to evaluate the load afresh for the current interval rather than copying the previous load. So, drop 'copy_prev_load' and use 'prev_load' instead. Update comments as well to make it more clear. There is another change here which was probably missed by Srivatsa during the last version of updates he made. The unlikely in the 'if' statement was covering only half of the condition and the whole line should actually come under it. Also checkpatch is made more silent as it was reporting this (--strict option): CHECK: Alignment should match open parenthesis + if (unlikely(wall_time > (2 * sampling_rate) && + j_cdbs->prev_load)) { Signed-off-by: Viresh Kumar Reviewed-by: Srivatsa S. Bhat Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki Change-Id: Id862ae84d4f8c0362966d5938c32ebaed6730bea --- drivers/cpufreq/cpufreq_governor.c | 19 ++++++++++++++----- drivers/cpufreq/cpufreq_governor.h | 9 +++++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index a1c56cc59766..521bf7761ae7 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -131,15 +131,25 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) * timer would not have fired during CPU-idle periods. Hence * an unusually large 'wall_time' (as compared to the sampling * rate) indicates this scenario. + * + * prev_load can be zero in two cases and we must recalculate it + * for both cases: + * - during long idle intervals + * - explicitly set to zero */ - if (unlikely(wall_time > (2 * sampling_rate)) && - j_cdbs->copy_prev_load) { + if (unlikely(wall_time > (2 * sampling_rate) && + j_cdbs->prev_load)) { load = j_cdbs->prev_load; - j_cdbs->copy_prev_load = false; + + /* + * Perform a destructive copy, to ensure that we copy + * the previous load only once, upon the first wake-up + * from idle. + */ + j_cdbs->prev_load = 0; } else { load = 100 * (wall_time - idle_time) / wall_time; j_cdbs->prev_load = load; - j_cdbs->copy_prev_load = true; } if (load > max_load) @@ -369,7 +379,6 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, (j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle); j_cdbs->prev_load = 100 * prev_load / (unsigned int) j_cdbs->prev_cpu_wall; - j_cdbs->copy_prev_load = true; if (ignore_nice) j_cdbs->prev_cpu_nice = diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 2e920847ef74..279318f67534 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -134,12 +134,13 @@ struct cpu_dbs_common_info { u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; - unsigned int prev_load; /* - * Flag to ensure that we copy the previous load only once, upon the - * first wake-up from idle. + * Used to keep track of load in the previous interval. However, when + * explicitly set to zero, it is used as a flag to ensure that we copy + * the previous load to the current interval only once, upon the first + * wake-up from idle. */ - bool copy_prev_load; + unsigned int prev_load; struct cpufreq_policy *cur_policy; struct delayed_work work; /* -- GitLab From 4f7a91f11826d440eeba15357d2548262416b74b Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Wed, 31 Mar 2021 20:15:16 +0800 Subject: [PATCH 427/528] ext4: fix check to prevent false positive report of incorrect used inodes commit a149d2a5cabbf6507a7832a1c4fd2593c55fd450 upstream. Commit <50122847007> ("ext4: fix check to prevent initializing reserved inodes") check the block group zero and prevent initializing reserved inodes. But in some special cases, the reserved inode may not all belong to the group zero, it may exist into the second group if we format filesystem below. mkfs.ext4 -b 4096 -g 8192 -N 1024 -I 4096 /dev/sda So, it will end up triggering a false positive report of a corrupted file system. This patch fix it by avoid check reserved inodes if no free inode blocks will be zeroed. Cc: stable@kernel.org Fixes: 50122847007 ("ext4: fix check to prevent initializing reserved inodes") Signed-off-by: Zhang Yi Suggested-by: Jan Kara Link: https://lore.kernel.org/r/20210331121516.2243099-1-yi.zhang@huawei.com Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Lee Jones Change-Id: I4917b4db93a023fb23ec9ce112a7b796cd2dae4d --- fs/ext4/ialloc.c | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index cc5079639b5f..591c36451dff 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -1136,6 +1136,7 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, handle_t *handle; ext4_fsblk_t blk; int num, ret = 0, used_blks = 0; + unsigned long used_inos = 0; /* This should not happen, but just to be sure check this */ if (sb->s_flags & MS_RDONLY) { @@ -1166,22 +1167,37 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, * used inodes so we need to skip blocks with used inodes in * inode table. */ - if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) - used_blks = DIV_ROUND_UP((EXT4_INODES_PER_GROUP(sb) - - ext4_itable_unused_count(sb, gdp)), - sbi->s_inodes_per_block); - - if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group) || - ((group == 0) && ((EXT4_INODES_PER_GROUP(sb) - - ext4_itable_unused_count(sb, gdp)) < - EXT4_FIRST_INO(sb)))) { - ext4_error(sb, "Something is wrong with group %u: " - "used itable blocks: %d; " - "itable unused count: %u", - group, used_blks, - ext4_itable_unused_count(sb, gdp)); - ret = 1; - goto err_out; + if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) { + used_inos = EXT4_INODES_PER_GROUP(sb) - + ext4_itable_unused_count(sb, gdp); + used_blks = DIV_ROUND_UP(used_inos, sbi->s_inodes_per_block); + + /* Bogus inode unused count? */ + if (used_blks < 0 || used_blks > sbi->s_itb_per_group) { + ext4_error(sb, "Something is wrong with group %u: " + "used itable blocks: %d; " + "itable unused count: %u", + group, used_blks, + ext4_itable_unused_count(sb, gdp)); + ret = 1; + goto err_out; + } + + used_inos += group * EXT4_INODES_PER_GROUP(sb); + /* + * Are there some uninitialized inodes in the inode table + * before the first normal inode? + */ + if ((used_blks != sbi->s_itb_per_group) && + (used_inos < EXT4_FIRST_INO(sb))) { + ext4_error(sb, "Something is wrong with group %u: " + "itable unused count: %u; " + "itables initialized count: %ld", + group, ext4_itable_unused_count(sb, gdp), + used_inos); + ret = 1; + goto err_out; + } } blk = ext4_inode_table(sb, gdp) + used_blks; -- GitLab From 50bb0aee5625bba82134a2a030e948df1f4d50bf Mon Sep 17 00:00:00 2001 From: Eric Caruso Date: Wed, 8 Jun 2016 16:08:59 -0700 Subject: [PATCH 428/528] timerfd: Reject ALARM timerfds without CAP_WAKE_ALARM commit 2895a5e5b3ae78d9923a91fce405d4a2f32c4309 upstream. timerfd gives processes a way to set wake alarms, but unlike timers made using timer_create, timerfds don't check whether the process has CAP_WAKE_ALARM before setting alarm-time timers. CAP_WAKE_ALARM is supposed to gate this behavior and so it makes sense that we should deny permission to create such timerfds if the process doesn't have this capability. Signed-off-by: Eric Caruso Cc: Todd Poynor Link: http://lkml.kernel.org/r/1465427339-96209-1-git-send-email-ejcaruso@chromium.org Signed-off-by: Thomas Gleixner Cc: Kasper Zwijsen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Lee Jones Change-Id: Ia396c47e02a6f505d42ca8f7be670882043b0e79 --- fs/timerfd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/timerfd.c b/fs/timerfd.c index ea2d774ca961..1a65e017048e 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -334,6 +334,11 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) clockid != CLOCK_POWEROFF_ALARM)) return -EINVAL; + if (!capable(CAP_WAKE_ALARM) && + (clockid == CLOCK_REALTIME_ALARM || + clockid == CLOCK_BOOTTIME_ALARM)) + return -EPERM; + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -377,6 +382,11 @@ static int do_timerfd_settime(int ufd, int flags, return ret; ctx = f.file->private_data; + if (!capable(CAP_WAKE_ALARM) && isalarm(ctx)) { + fdput(f); + return -EPERM; + } + timerfd_setup_cancel(ctx, flags); /* -- GitLab From a920a040a30ce8ebbe6465cbc565117f852e8ee5 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Tue, 30 Apr 2013 11:46:09 -0700 Subject: [PATCH 429/528] softirq: Use _RET_IP_ Use the already defined macro to pass the function return address. Signed-off-by: Davidlohr Bueso Cc: Frederic Weisbecker Link: http://lkml.kernel.org/r/1367347569.1784.3.camel@buesod1.americas.hpqcorp.net Signed-off-by: Thomas Gleixner Change-Id: I8659c755fc19525da5be102ca1831d8c1969fbf2 --- kernel/softirq.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index 96a4c2828ce6..2dd7dae55efe 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -125,8 +125,7 @@ static inline void __local_bh_disable(unsigned long ip, unsigned int cnt) void local_bh_disable(void) { - __local_bh_disable((unsigned long)__builtin_return_address(0), - SOFTIRQ_DISABLE_OFFSET); + __local_bh_disable(_RET_IP_, SOFTIRQ_DISABLE_OFFSET); } EXPORT_SYMBOL(local_bh_disable); @@ -137,7 +136,7 @@ static void __local_bh_enable(unsigned int cnt) WARN_ON_ONCE(!irqs_disabled()); if (softirq_count() == cnt) - trace_softirqs_on((unsigned long)__builtin_return_address(0)); + trace_softirqs_on(_RET_IP_); sub_preempt_count(cnt); } @@ -182,7 +181,7 @@ static inline void _local_bh_enable_ip(unsigned long ip) void local_bh_enable(void) { - _local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + _local_bh_enable_ip(_RET_IP_); } EXPORT_SYMBOL(local_bh_enable); @@ -227,8 +226,7 @@ asmlinkage void __do_softirq(void) pending = local_softirq_pending(); account_irq_enter_time(current); - __local_bh_disable((unsigned long)__builtin_return_address(0), - SOFTIRQ_OFFSET); + __local_bh_disable(_RET_IP_, SOFTIRQ_OFFSET); lockdep_softirq_enter(); cpu = smp_processor_id(); -- GitLab From a63dcf811d6ef229102d783a3c149b48fedf8303 Mon Sep 17 00:00:00 2001 From: Bernhard Thoben Date: Sat, 31 Jul 2021 13:33:25 +0200 Subject: [PATCH 430/528] defconfig: kitakami: Maintenance Added "CONFIG_USB_MSM_ACA=y". Removed duplicate entries of "CONFIG_ANDROID_BINDER_IPC". Sorted defconfig files alphabetically for better readability. Change-Id: I2674a5dd51e9e7dbd1a92d125ef25a951a263cb6 --- arch/arm64/configs/kitakami_ivy_defconfig | 1202 ++++++++--------- arch/arm64/configs/kitakami_karin_defconfig | 1168 ++++++++-------- .../configs/kitakami_karin_windy_defconfig | 1166 ++++++++-------- arch/arm64/configs/kitakami_satsuki_defconfig | 1202 ++++++++--------- arch/arm64/configs/kitakami_sumire_defconfig | 1202 ++++++++--------- arch/arm64/configs/kitakami_suzuran_defconfig | 1193 ++++++++-------- 6 files changed, 3567 insertions(+), 3566 deletions(-) diff --git a/arch/arm64/configs/kitakami_ivy_defconfig b/arch/arm64/configs/kitakami_ivy_defconfig index 7bbb6b30f29e..51aa7eb61d83 100644 --- a/arch/arm64/configs/kitakami_ivy_defconfig +++ b/arch/arm64/configs/kitakami_ivy_defconfig @@ -1,467 +1,163 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y -CONFIG_HARDENED_USERCOPY=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_RCU_BOOST=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_AHC=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MMAP_RND_BITS=24 CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 -CONFIG_PARTITION_ADVANCED=y -# CONFIG_IOSCHED_TEST is not set -CONFIG_IOSCHED_BFQ=y -CONFIG_CGROUP_BFQIO=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_IVY=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -# CONFIG_KSM is not set -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v1-kitakami_ivy_generic msm8994-v2.0-kitakami_ivy_generic msm8994-v2.1-kitakami_ivy_generic" -# CONFIG_COREDUMP is not set -CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -# CONFIG_WAKEUP_IRQ_DEBUG is not set -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_STAT_DETAILS=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y -# CONFIG_CPU_IDLE_GOV_LADDER is not set -# CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_WIREGUARD=y -# CONFIG_WIREGUARD_DEBUG is not set -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_INET_AH=y -CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y -# CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y -CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y -CONFIG_NETFILTER_XT_MATCH_COMMENT=y -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y -CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y -CONFIG_NETFILTER_XT_MATCH_ESP=y -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y -CONFIG_NETFILTER_XT_MATCH_HELPER=y -CONFIG_NETFILTER_XT_MATCH_IPRANGE=y -CONFIG_NETFILTER_XT_MATCH_LENGTH=y -CONFIG_NETFILTER_XT_MATCH_LIMIT=y -CONFIG_NETFILTER_XT_MATCH_MAC=y -CONFIG_NETFILTER_XT_MATCH_MARK=y -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y -CONFIG_NETFILTER_XT_MATCH_SOCKET=y -CONFIG_NETFILTER_XT_MATCH_STATE=y -CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -CONFIG_NETFILTER_XT_MATCH_STRING=y -CONFIG_NETFILTER_XT_MATCH_TIME=y -CONFIG_NETFILTER_XT_MATCH_U32=y -CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_RPFILTER=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y -CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y -CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y -CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y -CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_BATTERY_BCL=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +# CONFIG_BCM_WLAN_RAMDUMP is not set +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_SYS_STATS=y -CONFIG_PMI8994_FLASH=y -CONFIG_QSEECOM=y -CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y -CONFIG_POWERKEY_FORCECRASH=y -# CONFIG_RAMDUMP_MEMDESC is not set -CONFIG_CRASH_LAST_LOGS=y -# CONFIG_BCM_WLAN_RAMDUMP is not set -CONFIG_LDO_VIBRATOR=y -CONFIG_SIM_DETECT=y -CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_REQ_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_TUN=y -CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y -CONFIG_PPP_BSDCOMP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_MPPE=y -CONFIG_PPPOE=y -CONFIG_PPPOLAC=y -CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE=y CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y -CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCM4356=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TABLET=y -CONFIG_TABLET_USB_ACECAD=y -CONFIG_TABLET_USB_AIPTEK=y -CONFIG_TABLET_USB_GTCO=y -CONFIG_TABLET_USB_HANWANG=y -CONFIG_TABLET_USB_KBTAB=y -CONFIG_TABLET_USB_WACOM=y -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y -CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21=y -CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_CLEARPAD=y -CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y -CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y -CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y -CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y +CONFIG_BT_BCM43XX=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_PROTOCOL_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v1-kitakami_ivy_generic msm8994-v2.0-kitakami_ivy_generic msm8994-v2.1-kitakami_ivy_generic" +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CFG80211=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BFQIO=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y +CONFIG_COMPAT=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y +CONFIG_CRASH_LAST_LOGS=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DRAGONRISE_FF=y +CONFIG_DUMMY=y CONFIG_DVB_MPQ_DEMUX=y -CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_E1000E=y +CONFIG_ECRYPT_FS=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="utf8" CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y -CONFIG_UHID=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y CONFIG_HID_CYPRESS=y CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y CONFIG_HID_KEYTOUCH=y CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y +CONFIG_HID_LOGITECH=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MONTEREY=y @@ -469,163 +165,388 @@ CONFIG_HID_MULTITOUCH=y CONFIG_HID_NTRIG=y CONFIG_HID_ORTEK=y CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y CONFIG_HID_PETALYNX=y CONFIG_HID_PICOLCD=y CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y CONFIG_HID_ROCCAT=y CONFIG_HID_SAITEK=y CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y CONFIG_HID_SONY=y CONFIG_HID_SPEEDLINK=y CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_THRUSTMASTER=y CONFIG_HID_TIVO=y CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y CONFIG_HID_WIIMOTE=y CONFIG_HID_ZEROPLUS=y CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_EHSET=y -CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y -CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y -CONFIG_USB_G_ANDROID=y -CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_SUPPORT_SVS_INTERVAL=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_QPNP=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_LRO is not set +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IOSCHED_BFQ=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_KSM is not set +CONFIG_LDO_VIBRATOR=y CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_QPNP=y CONFIG_LEDS_TRIGGER_BACKLIGHT=y CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_IVY=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SUPPORT_SVS_INTERVAL=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y CONFIG_MSM_AVTIMER=y -CONFIG_PFT=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y CONFIG_MSM_IOMMU_V1=y CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y +CONFIG_NFC_PN547=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PFT=y +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PMI8994_FLASH=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y +CONFIG_POWERKEY_FORCECRASH=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_DEVICETREE=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y +CONFIG_QCOM_LIQUID_DOCK=y CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_RADIO_SILABS=y +# CONFIG_RAMDUMP_MEMDESC is not set +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI=y CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_ASCII=y -CONFIG_FAT_DEFAULT_IOCHARSET="utf8" CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y CONFIG_SDFAT_DBG_MSG=y @@ -638,53 +559,132 @@ CONFIG_SDFAT_STATISTICS=y CONFIG_SDFAT_SUPPORT_DIR_SYNC=y CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" CONFIG_SDFAT_VIRTUAL_XATTR=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY_PFT=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y +CONFIG_SOMC_WIFI_CONTROL=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y CONFIG_STRICT_MEMORY_RWX=y -CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y -CONFIG_MISC_FILESYSTEMS=y -CONFIG_ECRYPT_FS=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21=y +CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y +CONFIG_TSPP=y +CONFIG_TUN=y +CONFIG_UHID=y +CONFIG_UID_STAT=y +CONFIG_UID_SYS_STATS=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y +CONFIG_USB_MIRRORLINK=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +# CONFIG_WAKEUP_IRQ_DEBUG is not set +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y +# CONFIG_WIREGUARD_DEBUG is not set +CONFIG_WIREGUARD=y CONFIG_WTL_ENCRYPTION_FILTER=y -CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_karin_defconfig b/arch/arm64/configs/kitakami_karin_defconfig index 4e9eeac476fe..60972a938ea3 100644 --- a/arch/arm64/configs/kitakami_karin_defconfig +++ b/arch/arm64/configs/kitakami_karin_defconfig @@ -1,130 +1,374 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y +CONFIG_AD7146=y +CONFIG_AHC=y +CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_KARIN=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -CONFIG_KSM=y -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BATTERY_BCL=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE=y +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_BT_BCM43XX=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_PROTOCOL_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v1-kitakami_karin_generic msm8994-v2.0-kitakami_karin_generic msm8994-v2.1-kitakami_karin_generic" -# CONFIG_COREDUMP is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CFG80211=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y # CONFIG_CPU_IDLE_GOV_LADDER is not set # CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y +CONFIG_CRASH_LAST_LOGS=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DRAGONRISE_FF=y +CONFIG_DUMMY=y +CONFIG_DVB_MPQ_DEMUX=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_E1000E=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HI256=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y # CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_KSM=y +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_LP855X=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_KARIN=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_TEST=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_TEST=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_AVTIMER=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y +CONFIG_MSM_IOMMU_V1=y +CONFIG_MSM_IOMMU_VBIF_CHECK=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SPM=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -138,517 +382,273 @@ CONFIG_NETFILTER_XT_MATCH_LIMIT=y CONFIG_NETFILTER_XT_MATCH_MAC=y CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y -CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y -CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y -CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_CPUTIME=y -CONFIG_QSEECOM=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PLUG_DET_TH_MID=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y CONFIG_POWERKEY_FORCECRASH=y -CONFIG_RAMDUMP_MEMDESC=y -CONFIG_CRASH_LAST_LOGS=y -CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_AD7146=y -CONFIG_SIM_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFS_TEST=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_REQ_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_TUN=y -CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y CONFIG_PPPOE=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_LIQUID_DOCK=y +CONFIG_QCOM_NPA_DUMP=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y +CONFIG_QUOTA=y +CONFIG_RADIO_SILABS=y +CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_TEST=y +CONFIG_SCSI=y +CONFIG_SDCARD_FS=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCM4356=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TABLET=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set CONFIG_TABLET_USB_ACECAD=y CONFIG_TABLET_USB_AIPTEK=y CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_TABLET_USB_WACOM=y -CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_MAXIM_STI=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y -CONFIG_DVB_MPQ_DEMUX=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_MAXIM_STI=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y -CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y -CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_PLUG_DET_TH_MID=y -CONFIG_HIDRAW=y +CONFIG_TUN=y CONFIG_UHID=y -CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EZKEY=y -CONFIG_HID_HOLTEK=y -CONFIG_HID_KEYTOUCH=y -CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_PICOLCD=y -CONFIG_HID_PRIMAX=y -CONFIG_HID_ROCCAT=y -CONFIG_HID_SAITEK=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SPEEDLINK=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_WACOM=y -CONFIG_HID_WIIMOTE=y -CONFIG_HID_ZEROPLUS=y -CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y +CONFIG_UID_CPUTIME=y +CONFIG_UID_STAT=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y +CONFIG_USB_GADGET=y CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y -CONFIG_MMC_BLOCK_TEST=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_LP855X=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y -CONFIG_MSM_AVTIMER=y -CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_MSM_IOMMU_V1=y -CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y -CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y -CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y -CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y -CONFIG_MSM_RUN_QUEUE_STATS=y -CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y -CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y -CONFIG_MSM_SUBSYSTEM_RESTART=y -CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y -CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y -CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y -CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VFAT_FS_NO_DUALNAMES=y -CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y -CONFIG_SECURITYFS=y -CONFIG_SECURITY_NETWORK=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y -CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y -CONFIG_STRICT_MEMORY_RWX=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_karin_windy_defconfig b/arch/arm64/configs/kitakami_karin_windy_defconfig index 022175f13bee..bbc704f4b8aa 100644 --- a/arch/arm64/configs/kitakami_karin_windy_defconfig +++ b/arch/arm64/configs/kitakami_karin_windy_defconfig @@ -1,132 +1,377 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y -CONFIG_HARDENED_USERCOPY=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y +CONFIG_AHC=y +CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_KARIN_WINDY=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -CONFIG_KSM=y -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BATTERY_BCL=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE=y +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_BT_BCM43XX=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_PROTOCOL_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="apq8094-v1-kitakami_karin_windy apq8094-v2.0-kitakami_karin_windy apq8094-v2.1-kitakami_karin_windy" -# CONFIG_COREDUMP is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CFG80211=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y # CONFIG_CPU_IDLE_GOV_LADDER is not set # CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y +CONFIG_CRASH_LAST_LOGS=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DRAGONRISE_FF=y +CONFIG_DUMMY=y +CONFIG_DVB_MPQ_DEMUX=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_E1000E=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y # CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_KSM=y +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_LP855X=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_KARIN_WINDY=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_TEST=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_TEST=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_AVTIMER=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y +CONFIG_MSM_IOMMU_V1=y +CONFIG_MSM_IOMMU_VBIF_CHECK=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SPM=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -140,516 +385,271 @@ CONFIG_NETFILTER_XT_MATCH_LIMIT=y CONFIG_NETFILTER_XT_MATCH_MAC=y CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y -CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y -CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y -CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_CPUTIME=y -CONFIG_QSEECOM=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y CONFIG_POWERKEY_FORCECRASH=y -CONFIG_RAMDUMP_MEMDESC=y -CONFIG_CRASH_LAST_LOGS=y -CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFS_TEST=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_REQ_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_TUN=y -CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y CONFIG_PPPOE=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_LIQUID_DOCK=y +CONFIG_QCOM_NPA_DUMP=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y +CONFIG_QUOTA=y +CONFIG_RADIO_SILABS=y +CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_TEST=y +CONFIG_SCSI=y +CONFIG_SDCARD_FS=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCM4356=y -CONFIG_BCMDHD_BCM4356=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TABLET=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set CONFIG_TABLET_USB_ACECAD=y CONFIG_TABLET_USB_AIPTEK=y CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_TABLET_USB_WACOM=y -CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_MAXIM_STI=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y -CONFIG_DVB_MPQ_DEMUX=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_MAXIM_STI=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y -CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y -CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y +CONFIG_TUN=y CONFIG_UHID=y -CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EZKEY=y -CONFIG_HID_HOLTEK=y -CONFIG_HID_KEYTOUCH=y -CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_PICOLCD=y -CONFIG_HID_PRIMAX=y -CONFIG_HID_ROCCAT=y -CONFIG_HID_SAITEK=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SPEEDLINK=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_WACOM=y -CONFIG_HID_WIIMOTE=y -CONFIG_HID_ZEROPLUS=y -CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y +CONFIG_UID_CPUTIME=y +CONFIG_UID_STAT=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y +CONFIG_USB_GADGET=y CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y -CONFIG_MMC_BLOCK_TEST=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_LP855X=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y -CONFIG_MSM_AVTIMER=y -CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_MSM_IOMMU_V1=y -CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y -CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y -CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y -CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y -CONFIG_MSM_RUN_QUEUE_STATS=y -CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y -CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y -CONFIG_MSM_SUBSYSTEM_RESTART=y -CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y -CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y -CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y -CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VFAT_FS_NO_DUALNAMES=y -CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y -CONFIG_SECURITYFS=y -CONFIG_SECURITY_NETWORK=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y -CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y -CONFIG_STRICT_MEMORY_RWX=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_satsuki_defconfig b/arch/arm64/configs/kitakami_satsuki_defconfig index 37febc1f3a2b..8dd4ccc3a15f 100644 --- a/arch/arm64/configs/kitakami_satsuki_defconfig +++ b/arch/arm64/configs/kitakami_satsuki_defconfig @@ -1,467 +1,165 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y -CONFIG_HARDENED_USERCOPY=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_RCU_BOOST=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_AHC=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MMAP_RND_BITS=24 CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 -CONFIG_PARTITION_ADVANCED=y -CONFIG_IOSCHED_BFQ=y -CONFIG_CGROUP_BFQIO=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_SATSUKI=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -# CONFIG_KSM is not set -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_satsuki_generic msm8994-v2.1-kitakami_satsuki_generic" -# CONFIG_COREDUMP is not set -CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -# CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_STAT_DETAILS=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y -# CONFIG_CPU_IDLE_GOV_LADDER is not set -# CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_WIREGUARD=y -# CONFIG_WIREGUARD_DEBUG is not set -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_INET_AH=y -CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y -# CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y -CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y -CONFIG_NETFILTER_XT_MATCH_COMMENT=y -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y -CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y -CONFIG_NETFILTER_XT_MATCH_ESP=y -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y -CONFIG_NETFILTER_XT_MATCH_HELPER=y -CONFIG_NETFILTER_XT_MATCH_IPRANGE=y -CONFIG_NETFILTER_XT_MATCH_LENGTH=y -CONFIG_NETFILTER_XT_MATCH_LIMIT=y -CONFIG_NETFILTER_XT_MATCH_MAC=y -CONFIG_NETFILTER_XT_MATCH_MARK=y -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y -CONFIG_NETFILTER_XT_MATCH_SOCKET=y -CONFIG_NETFILTER_XT_MATCH_STATE=y -CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -CONFIG_NETFILTER_XT_MATCH_STRING=y -CONFIG_NETFILTER_XT_MATCH_TIME=y -CONFIG_NETFILTER_XT_MATCH_U32=y -CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_RPFILTER=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y -CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y -CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y -CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y -CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_BATTERY_BCL=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +# CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_SYS_STATS=y -CONFIG_PMI8994_FLASH=y -CONFIG_QSEECOM=y -CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y -CONFIG_POWERKEY_FORCECRASH=y -# CONFIG_RAMDUMP_MEMDESC=y -CONFIG_CRASH_LAST_LOGS=y -# CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_SIM_DETECT=y -CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFS_TEST=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_REQ_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_TUN=y -CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y -CONFIG_PPP_BSDCOMP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_MPPE=y -CONFIG_PPPOE=y -CONFIG_PPPOLAC=y -CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE=y CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y -CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCMDHD_BCM4356=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TABLET=y -CONFIG_TABLET_USB_ACECAD=y -CONFIG_TABLET_USB_AIPTEK=y -CONFIG_TABLET_USB_GTCO=y -CONFIG_TABLET_USB_HANWANG=y -CONFIG_TABLET_USB_KBTAB=y -CONFIG_TABLET_USB_WACOM=y -CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_CLEARPAD=y -CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y -CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -CONFIG_FPC1145_TEE=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y -CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y -CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y +CONFIG_BT_BCM43XX=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_PROTOCOL_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_satsuki_generic msm8994-v2.1-kitakami_satsuki_generic" +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CFG80211=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BFQIO=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y +CONFIG_COMPAT=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y +CONFIG_CRASH_LAST_LOGS=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DRAGONRISE_FF=y +CONFIG_DUMMY=y CONFIG_DVB_MPQ_DEMUX=y -CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_E1000E=y +CONFIG_ECRYPT_FS=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="utf8" CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y -CONFIG_UHID=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FPC1145_TEE=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y CONFIG_HID_CYPRESS=y CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y CONFIG_HID_KEYTOUCH=y CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y +CONFIG_HID_LOGITECH=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MONTEREY=y @@ -469,166 +167,391 @@ CONFIG_HID_MULTITOUCH=y CONFIG_HID_NTRIG=y CONFIG_HID_ORTEK=y CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y CONFIG_HID_PETALYNX=y CONFIG_HID_PICOLCD=y CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y CONFIG_HID_ROCCAT=y CONFIG_HID_SAITEK=y CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y CONFIG_HID_SONY=y CONFIG_HID_SPEEDLINK=y CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_THRUSTMASTER=y CONFIG_HID_TIVO=y CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y CONFIG_HID_WIIMOTE=y CONFIG_HID_ZEROPLUS=y CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_EHSET=y -CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y -CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y -CONFIG_USB_G_ANDROID=y -CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_LRO is not set +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IOSCHED_BFQ=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_KSM is not set +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_SATSUKI=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_TEST=y CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CMD_DEBUG=y CONFIG_MMC_DDR50_MAX_DTR_LMT=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y CONFIG_MMC_SUPPORT_SVS_INTERVAL=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=y -CONFIG_MMC_BLOCK_TEST=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y CONFIG_MSM_AVTIMER=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CCI=y CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y CONFIG_MSM_IOMMU_V1=y CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y +CONFIG_NFC_PN547=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PMI8994_FLASH=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y +CONFIG_POWERKEY_FORCECRASH=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_DEVICETREE=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y +CONFIG_QCOM_LIQUID_DOCK=y CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_RADIO_SILABS=y +# CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_TEST=y +CONFIG_SCSI=y CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_ASCII=y -CONFIG_FAT_DEFAULT_IOCHARSET="utf8" CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y CONFIG_SDFAT_DBG_MSG=y @@ -641,53 +564,130 @@ CONFIG_SDFAT_STATISTICS=y CONFIG_SDFAT_SUPPORT_DIR_SYNC=y CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" CONFIG_SDFAT_VIRTUAL_XATTR=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y CONFIG_SECURITYFS=y CONFIG_SECURITY_NETWORK=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y +CONFIG_SOMC_WIFI_CONTROL=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y CONFIG_STRICT_MEMORY_RWX=y -CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y -CONFIG_MISC_FILESYSTEMS=y -CONFIG_ECRYPT_FS=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set +CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y +CONFIG_TSPP=y +CONFIG_TUN=y +CONFIG_UHID=y +CONFIG_UID_STAT=y +CONFIG_UID_SYS_STATS=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y +CONFIG_USB_MIRRORLINK=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +# CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y +# CONFIG_WIREGUARD_DEBUG is not set +CONFIG_WIREGUARD=y CONFIG_WTL_ENCRYPTION_FILTER=y -CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index 12abaa637636..354e0463e289 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -1,467 +1,165 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y -CONFIG_HARDENED_USERCOPY=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_RCU_BOOST=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_AHC=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MMAP_RND_BITS=24 CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 -CONFIG_PARTITION_ADVANCED=y -# CONFIG_IOSCHED_TEST is not set -CONFIG_IOSCHED_BFQ=y -CONFIG_CGROUP_BFQIO=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_SUMIRE=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -# CONFIG_KSM is not set -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_sumire_generic msm8994-v2.1-kitakami_sumire_generic" -# CONFIG_COREDUMP is not set -CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -# CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_STAT_DETAILS=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y -# CONFIG_CPU_IDLE_GOV_LADDER is not set -# CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_WIREGUARD=y -# CONFIG_WIREGUARD_DEBUG is not set -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_INET_AH=y -CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y -# CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y -CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y -CONFIG_NETFILTER_XT_MATCH_COMMENT=y -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y -CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y -CONFIG_NETFILTER_XT_MATCH_ESP=y -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y -CONFIG_NETFILTER_XT_MATCH_HELPER=y -CONFIG_NETFILTER_XT_MATCH_IPRANGE=y -CONFIG_NETFILTER_XT_MATCH_LENGTH=y -CONFIG_NETFILTER_XT_MATCH_LIMIT=y -CONFIG_NETFILTER_XT_MATCH_MAC=y -CONFIG_NETFILTER_XT_MATCH_MARK=y -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y -CONFIG_NETFILTER_XT_MATCH_SOCKET=y -CONFIG_NETFILTER_XT_MATCH_STATE=y -CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -CONFIG_NETFILTER_XT_MATCH_STRING=y -CONFIG_NETFILTER_XT_MATCH_TIME=y -CONFIG_NETFILTER_XT_MATCH_U32=y -CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_RPFILTER=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y -CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y -CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y -CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y -CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_BATTERY_BCL=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +# CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_SYS_STATS=y -CONFIG_PMI8994_FLASH=y -CONFIG_QSEECOM=y -CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y -CONFIG_POWERKEY_FORCECRASH=y -# CONFIG_RAMDUMP_MEMDESC=y -CONFIG_CRASH_LAST_LOGS=y -# CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_SIM_DETECT=y -CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_REQ_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_TUN=y -CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y -CONFIG_PPP_BSDCOMP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_MPPE=y -CONFIG_PPPOE=y -CONFIG_PPPOLAC=y -CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE=y CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y -CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD_BCM4356=y -CONFIG_BCMDHD=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BCM4356=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TABLET=y -CONFIG_TABLET_USB_ACECAD=y -CONFIG_TABLET_USB_AIPTEK=y -CONFIG_TABLET_USB_GTCO=y -CONFIG_TABLET_USB_HANWANG=y -CONFIG_TABLET_USB_KBTAB=y -CONFIG_TABLET_USB_WACOM=y -CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_CLEARPAD=y -CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y -CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -CONFIG_FPC1145_TEE=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y -CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y -CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y +CONFIG_BT_BCM43XX=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_PROTOCOL_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_sumire_generic msm8994-v2.1-kitakami_sumire_generic" +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CFG80211=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BFQIO=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y +CONFIG_COMPAT=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y +CONFIG_CRASH_LAST_LOGS=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DRAGONRISE_FF=y +CONFIG_DUMMY=y CONFIG_DVB_MPQ_DEMUX=y -CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_E1000E=y +CONFIG_ECRYPT_FS=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="utf8" CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y -CONFIG_UHID=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FPC1145_TEE=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y CONFIG_HID_CYPRESS=y CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y CONFIG_HID_KEYTOUCH=y CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y +CONFIG_HID_LOGITECH=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MONTEREY=y @@ -469,165 +167,390 @@ CONFIG_HID_MULTITOUCH=y CONFIG_HID_NTRIG=y CONFIG_HID_ORTEK=y CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y CONFIG_HID_PETALYNX=y CONFIG_HID_PICOLCD=y CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y CONFIG_HID_ROCCAT=y CONFIG_HID_SAITEK=y CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y CONFIG_HID_SONY=y CONFIG_HID_SPEEDLINK=y CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_THRUSTMASTER=y CONFIG_HID_TIVO=y CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y CONFIG_HID_WIIMOTE=y CONFIG_HID_ZEROPLUS=y CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_EHSET=y -CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y -CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y -CONFIG_USB_G_ANDROID=y -CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_LRO is not set +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IOSCHED_BFQ=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_KSM is not set +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_SUMIRE=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CMD_DEBUG=y CONFIG_MMC_DDR50_MAX_DTR_LMT=y -CONFIG_MMC_SUPPORT_SVS_INTERVAL=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SUPPORT_SVS_INTERVAL=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y CONFIG_MSM_AVTIMER=y -CONFIG_PFT=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CCI=y CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y CONFIG_MSM_IOMMU_V1=y CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y +CONFIG_NFC_PN547=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PFT=y +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PMI8994_FLASH=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y +CONFIG_POWERKEY_FORCECRASH=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_DEVICETREE=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y +CONFIG_QCOM_LIQUID_DOCK=y CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_RADIO_SILABS=y +# CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI=y CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_ASCII=y -CONFIG_FAT_DEFAULT_IOCHARSET="utf8" CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y CONFIG_SDFAT_DBG_MSG=y @@ -640,53 +563,130 @@ CONFIG_SDFAT_STATISTICS=y CONFIG_SDFAT_SUPPORT_DIR_SYNC=y CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" CONFIG_SDFAT_VIRTUAL_XATTR=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY_PFT=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y +CONFIG_SOMC_WIFI_CONTROL=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y CONFIG_STRICT_MEMORY_RWX=y -CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y -CONFIG_MISC_FILESYSTEMS=y -CONFIG_ECRYPT_FS=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set +CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y +CONFIG_TSPP=y +CONFIG_TUN=y +CONFIG_UHID=y +CONFIG_UID_STAT=y +CONFIG_UID_SYS_STATS=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y +CONFIG_USB_MIRRORLINK=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +# CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y +# CONFIG_WIREGUARD_DEBUG is not set +CONFIG_WIREGUARD=y CONFIG_WTL_ENCRYPTION_FILTER=y -CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_suzuran_defconfig b/arch/arm64/configs/kitakami_suzuran_defconfig index 617063d7cc2b..8025b8665642 100644 --- a/arch/arm64/configs/kitakami_suzuran_defconfig +++ b/arch/arm64/configs/kitakami_suzuran_defconfig @@ -1,464 +1,163 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y -CONFIG_HARDENED_USERCOPY=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_RCU_BOOST=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_AHC=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MMAP_RND_BITS=24 CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 -CONFIG_PARTITION_ADVANCED=y -# CONFIG_IOSCHED_TEST is not set -CONFIG_IOSCHED_BFQ=y -CONFIG_CGROUP_BFQIO=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_SUZURAN=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y -CONFIG_ARMV7_COMPAT=y -# CONFIG_KSM is not set -CONFIG_SWAP_CONSIDER_CMA_FREE=y -CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_suzuran_generic msm8994-v2.1-kitakami_suzuran_generic" -# CONFIG_COREDUMP is not set -CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -# CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_STAT_DETAILS=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y -# CONFIG_CPU_IDLE_GOV_LADDER is not set -# CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_WIREGUARD=y -# CONFIG_WIREGUARD_DEBUG is not set -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_INET_AH=y -CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y -# CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y -CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y -CONFIG_NETFILTER_XT_MATCH_COMMENT=y -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y -CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y -CONFIG_NETFILTER_XT_MATCH_ESP=y -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y -CONFIG_NETFILTER_XT_MATCH_HELPER=y -CONFIG_NETFILTER_XT_MATCH_IPRANGE=y -CONFIG_NETFILTER_XT_MATCH_LENGTH=y -CONFIG_NETFILTER_XT_MATCH_LIMIT=y -CONFIG_NETFILTER_XT_MATCH_MAC=y -CONFIG_NETFILTER_XT_MATCH_MARK=y -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y -CONFIG_NETFILTER_XT_MATCH_SOCKET=y -CONFIG_NETFILTER_XT_MATCH_STATE=y -CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -CONFIG_NETFILTER_XT_MATCH_STRING=y -CONFIG_NETFILTER_XT_MATCH_TIME=y -CONFIG_NETFILTER_XT_MATCH_U32=y -CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_RPFILTER=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y -CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y -CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y -CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y -CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y +CONFIG_ARM64_CRYPTO=y CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_SYS_STATS=y -CONFIG_PMI8994_FLASH=y -CONFIG_QSEECOM=y -CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y -CONFIG_POWERKEY_FORCECRASH=y -# CONFIG_RAMDUMP_MEMDESC=y -CONFIG_CRASH_LAST_LOGS=y -# CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_SIM_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_REQ_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_TUN=y -CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y -CONFIG_PPP_BSDCOMP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_MPPE=y -CONFIG_PPPOE=y -CONFIG_PPPOLAC=y -CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_SOMC_WIFI_CONTROL=y +CONFIG_ARMV7_COMPAT=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_BATTERY_BCL=y CONFIG_BCM43455=y CONFIG_BCMDHD_BCM43455=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TABLET=y -CONFIG_TABLET_USB_ACECAD=y -CONFIG_TABLET_USB_AIPTEK=y -CONFIG_TABLET_USB_GTCO=y -CONFIG_TABLET_USB_HANWANG=y -CONFIG_TABLET_USB_KBTAB=y -CONFIG_TABLET_USB_WACOM=y -CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_CLEARPAD=y -CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y -CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -CONFIG_FPC1145_TEE=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y -CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y -CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y +CONFIG_BCMDHD=y +# CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE=y +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_BT_BCM43XX=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_PROTOCOL_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_suzuran_generic msm8994-v2.1-kitakami_suzuran_generic" +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CFG80211=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BFQIO=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y +CONFIG_COMPAT=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y +CONFIG_CRASH_LAST_LOGS=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DRAGONRISE_FF=y +CONFIG_DUMMY=y CONFIG_DVB_MPQ_DEMUX=y -CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_E1000E=y +CONFIG_ECRYPT_FS=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="utf8" CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y -CONFIG_UHID=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FPC1145_TEE=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y CONFIG_HID_CYPRESS=y CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y CONFIG_HID_KEYTOUCH=y CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y +CONFIG_HID_LOGITECH=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MONTEREY=y @@ -466,161 +165,387 @@ CONFIG_HID_MULTITOUCH=y CONFIG_HID_NTRIG=y CONFIG_HID_ORTEK=y CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y CONFIG_HID_PETALYNX=y CONFIG_HID_PICOLCD=y CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y CONFIG_HID_ROCCAT=y CONFIG_HID_SAITEK=y CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y CONFIG_HID_SONY=y CONFIG_HID_SPEEDLINK=y CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_THRUSTMASTER=y CONFIG_HID_TIVO=y CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y CONFIG_HID_WIIMOTE=y CONFIG_HID_ZEROPLUS=y CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_EHSET=y -CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y -CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y -CONFIG_USB_G_ANDROID=y -CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_QPNP=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_LRO is not set +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IOSCHED_BFQ=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_KSM is not set +CONFIG_LDO_VIBRATOR=y CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_QPNP=y CONFIG_LEDS_TRIGGER_BACKLIGHT=y CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_SUZURAN=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y CONFIG_MSM_AVTIMER=y -CONFIG_PFT=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y CONFIG_MSM_IOMMU_V1=y CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y +CONFIG_NFC_PN547=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PFT=y +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PMI8994_FLASH=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y +CONFIG_POWERKEY_FORCECRASH=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_DEVICETREE=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y +CONFIG_QCOM_LIQUID_DOCK=y CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_RADIO_SILABS=y +# CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI=y CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_ASCII=y -CONFIG_FAT_DEFAULT_IOCHARSET="utf8" CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y CONFIG_SDFAT_DBG_MSG=y @@ -633,53 +558,129 @@ CONFIG_SDFAT_STATISTICS=y CONFIG_SDFAT_SUPPORT_DIR_SYNC=y CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" CONFIG_SDFAT_VIRTUAL_XATTR=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY_PFT=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y +CONFIG_SOMC_WIFI_CONTROL=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y CONFIG_STRICT_MEMORY_RWX=y -CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y -CONFIG_MISC_FILESYSTEMS=y -CONFIG_ECRYPT_FS=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set +CONFIG_TSPP=y +CONFIG_TUN=y +CONFIG_UHID=y +CONFIG_UID_STAT=y +CONFIG_UID_SYS_STATS=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y +CONFIG_USB_MIRRORLINK=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +# CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y +# CONFIG_WIREGUARD_DEBUG is not set +CONFIG_WIREGUARD=y CONFIG_WTL_ENCRYPTION_FILTER=y -CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y -- GitLab From aed6dedbeb98e22db782e48eb449bb60fbc1cac0 Mon Sep 17 00:00:00 2001 From: Ilya Lipnitskiy Date: Mon, 29 Mar 2021 21:42:08 -0700 Subject: [PATCH 431/528] mm: fix race by making init_zero_pfn() early_initcall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e720e7d0e983bf05de80b231bccc39f1487f0f16 upstream. There are code paths that rely on zero_pfn to be fully initialized before core_initcall. For example, wq_sysfs_init() is a core_initcall function that eventually results in a call to kernel_execve, which causes a page fault with a subsequent mmput. If zero_pfn is not initialized by then it may not get cleaned up properly and result in an error: BUG: Bad rss-counter state mm:(ptrval) type:MM_ANONPAGES val:1 Here is an analysis of the race as seen on a MIPS device. On this particular MT7621 device (Ubiquiti ER-X), zero_pfn is PFN 0 until initialized, at which point it becomes PFN 5120: 1. wq_sysfs_init calls into kobject_uevent_env at core_initcall: kobject_uevent_env+0x7e4/0x7ec kset_register+0x68/0x88 bus_register+0xdc/0x34c subsys_virtual_register+0x34/0x78 wq_sysfs_init+0x1c/0x4c do_one_initcall+0x50/0x1a8 kernel_init_freeable+0x230/0x2c8 kernel_init+0x10/0x100 ret_from_kernel_thread+0x14/0x1c 2. kobject_uevent_env() calls call_usermodehelper_exec() which executes kernel_execve asynchronously. 3. Memory allocations in kernel_execve cause a page fault, bumping the MM reference counter: add_mm_counter_fast+0xb4/0xc0 handle_mm_fault+0x6e4/0xea0 __get_user_pages.part.78+0x190/0x37c __get_user_pages_remote+0x128/0x360 get_arg_page+0x34/0xa0 copy_string_kernel+0x194/0x2a4 kernel_execve+0x11c/0x298 call_usermodehelper_exec_async+0x114/0x194 4. In case zero_pfn has not been initialized yet, zap_pte_range does not decrement the MM_ANONPAGES RSS counter and the BUG message is triggered shortly afterwards when __mmdrop checks the ref counters: __mmdrop+0x98/0x1d0 free_bprm+0x44/0x118 kernel_execve+0x160/0x1d8 call_usermodehelper_exec_async+0x114/0x194 ret_from_kernel_thread+0x14/0x1c To avoid races such as described above, initialize init_zero_pfn at early_initcall level. Depending on the architecture, ZERO_PAGE is either constant or gets initialized even earlier, at paging_init, so there is no issue with initializing zero_pfn earlier. Link: https://lkml.kernel.org/r/CALCv0x2YqOXEAy2Q=hafjhHCtTHVodChv1qpM=niAXOpqEbt7w@mail.gmail.com Signed-off-by: Ilya Lipnitskiy Cc: Hugh Dickins Cc: "Eric W. Biederman" Cc: stable@vger.kernel.org Tested-by: 周琰杰 (Zhou Yanjie) Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Lee Jones Change-Id: I9c0ff3a35dc34d1ba98ff69d87ea312142c8e316 (cherry picked from commit 3817ec1eb1fdca798b721b6cd9e7888c81bec1ca) --- mm/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/memory.c b/mm/memory.c index 3c5bc55c567b..2425ef9f4c66 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -128,7 +128,7 @@ static int __init init_zero_pfn(void) zero_pfn = page_to_pfn(ZERO_PAGE(0)); return 0; } -core_initcall(init_zero_pfn); +early_initcall(init_zero_pfn); #if defined(SPLIT_RSS_COUNTING) -- GitLab From 8da4d6431a85aa555d3f3e174c35581f23a49f1f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 7 Apr 2021 21:38:57 +0200 Subject: [PATCH 432/528] netfilter: x_tables: fix compat match/target pad out-of-bound write commit b29c457a6511435960115c0f548c4360d5f4801d upstream. xt_compat_match/target_from_user doesn't check that zeroing the area to start of next rule won't write past end of allocated ruleset blob. Remove this code and zero the entire blob beforehand. Reported-by: syzbot+cfc0247ac173f597aaaa@syzkaller.appspotmail.com Reported-by: Andy Nguyen Fixes: 9fa492cdc160c ("[NETFILTER]: x_tables: simplify compat API") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Lee Jones Change-Id: Ieaeafc5fd840a57d8cec8a694c40d2eede1dbbeb (cherry picked from commit e6f5906d6c170b0d35803839af66e6e0a33a54f8) --- net/ipv4/netfilter/arp_tables.c | 2 ++ net/ipv4/netfilter/ip_tables.c | 2 ++ net/ipv6/netfilter/ip6_tables.c | 2 ++ net/netfilter/x_tables.c | 10 ++-------- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 3217acd4e33b..c6bc0a2ea0b4 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1312,6 +1312,8 @@ static int translate_compat_table(struct xt_table_info **pinfo, if (!newinfo) goto out_unlock; + memset(newinfo->entries, 0, size); + newinfo->number = compatr->num_entries; for (i = 0; i < NF_ARP_NUMHOOKS; i++) { newinfo->hook_entry[i] = compatr->hook_entry[i]; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index fdca7ed200e2..200bc2777ee6 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1584,6 +1584,8 @@ translate_compat_table(struct net *net, if (!newinfo) goto out_unlock; + memset(newinfo->entries, 0, size); + newinfo->number = compatr->num_entries; for (i = 0; i < NF_INET_NUMHOOKS; i++) { newinfo->hook_entry[i] = compatr->hook_entry[i]; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 9802b2469662..8a8d1571cf2f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1592,6 +1592,8 @@ translate_compat_table(struct net *net, if (!newinfo) goto out_unlock; + memset(newinfo->entries, 0, size); + newinfo->number = compatr->num_entries; for (i = 0; i < NF_INET_NUMHOOKS; i++) { newinfo->hook_entry[i] = compatr->hook_entry[i]; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 739849d6a437..6063365484a3 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -584,7 +584,7 @@ void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, { const struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; - int pad, off = xt_compat_match_offset(match); + int off = xt_compat_match_offset(match); u_int16_t msize = cm->u.user.match_size; char name[sizeof(m->u.user.name)]; @@ -594,9 +594,6 @@ void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, match->compat_from_user(m->data, cm->data); else memcpy(m->data, cm->data, msize - sizeof(*cm)); - pad = XT_ALIGN(match->matchsize) - match->matchsize; - if (pad > 0) - memset(m->data + match->matchsize, 0, pad); msize += off; m->u.user.match_size = msize; @@ -895,7 +892,7 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, { const struct xt_target *target = t->u.kernel.target; struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; - int pad, off = xt_compat_target_offset(target); + int off = xt_compat_target_offset(target); u_int16_t tsize = ct->u.user.target_size; char name[sizeof(t->u.user.name)]; @@ -905,9 +902,6 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, target->compat_from_user(t->data, ct->data); else memcpy(t->data, ct->data, tsize - sizeof(*ct)); - pad = XT_ALIGN(target->targetsize) - target->targetsize; - if (pad > 0) - memset(t->data + target->targetsize, 0, pad); tsize += off; t->u.user.target_size = tsize; -- GitLab From 369eec3bb4e51d2ffeaa69ec1fb888944341994a Mon Sep 17 00:00:00 2001 From: Will McVicker Date: Tue, 13 Apr 2021 15:59:41 -0700 Subject: [PATCH 433/528] ANDROID: xt_qtaguid: fix UAF race Make sure to hold the sock_tag_list_lock while accessing the tag to avoid a race between getting the tag and free'ing the tag. Bug: 184018316 Fixes: c7ca0ac69702 ("ANDROID: netfilter: xt_qtaguid: add qtaguid matching module") Signed-off-by: Will McVicker Change-Id: I62404bdaa602586e00821a7d4c5f9b9868a0e90a (cherry picked from commit 33dd83020f0741525e8b1e5a362b57625fa10060) --- net/netfilter/xt_qtaguid.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index d8b5de301bc4..599a43dd10eb 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -1071,18 +1071,6 @@ static struct sock_tag *get_sock_stat_nl(const struct sock *sk) return sock_tag_tree_search(&sock_tag_tree, sk); } -static struct sock_tag *get_sock_stat(const struct sock *sk) -{ - struct sock_tag *sock_tag_entry; - MT_DEBUG("qtaguid: get_sock_stat(sk=%p)\n", sk); - if (!sk) - return NULL; - spin_lock_bh(&sock_tag_list_lock); - sock_tag_entry = get_sock_stat_nl(sk); - spin_unlock_bh(&sock_tag_list_lock); - return sock_tag_entry; -} - static int ipx_proto(const struct sk_buff *skb, struct xt_action_param *par) { @@ -1321,12 +1309,15 @@ static void if_tag_stat_update(const char *ifname, uid_t uid, * Look for a tagged sock. * It will have an acct_uid. */ - sock_tag_entry = get_sock_stat(sk); + spin_lock_bh(&sock_tag_list_lock); + sock_tag_entry = sk ? get_sock_stat_nl(sk) : NULL; if (sock_tag_entry) { tag = sock_tag_entry->tag; acct_tag = get_atag_from_tag(tag); uid_tag = get_utag_from_tag(tag); - } else { + } + spin_unlock_bh(&sock_tag_list_lock); + if (!sock_tag_entry) { acct_tag = make_atag_from_value(0); tag = combine_atag_with_uid(acct_tag, uid); uid_tag = make_tag_from_uid(uid); -- GitLab From 9746f0e75a5e8ff5c32c0e0500d84f6952532c93 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 29 Sep 2014 16:08:21 -0700 Subject: [PATCH 434/528] seq_file: Rename seq_overflow() to seq_has_overflowed() and make public The return values of seq_printf/puts/putc are frequently misused. Start down a path to remove all the return value uses of these functions. Move the seq_overflow() to a global inlined function called seq_has_overflowed() that can be used by the users of seq_file() calls. Update the documentation to not show return types for seq_printf et al. Add a description of seq_has_overflowed(). Link: http://lkml.kernel.org/p/848ac7e3d1c31cddf638a8526fa3c59fa6fdeb8a.1412031505.git.joe@perches.com Cc: Al Viro Signed-off-by: Joe Perches [ Reworked the original patch from Joe ] Signed-off-by: Steven Rostedt Change-Id: I8bc416c46fb305fba36e1502cee81ecfe02aea8f (cherry picked from commit 949a67c1df51433eafae058d47ad332e9aff3ea6) --- Documentation/filesystems/seq_file.txt | 22 +++++++++++++--------- fs/seq_file.c | 15 ++------------- include/linux/seq_file.h | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt index a1e2e0dda907..a285660a7bdf 100644 --- a/Documentation/filesystems/seq_file.txt +++ b/Documentation/filesystems/seq_file.txt @@ -171,23 +171,19 @@ output must be passed to the seq_file code. Some utility functions have been defined which make this task easy. Most code will simply use seq_printf(), which works pretty much like -printk(), but which requires the seq_file pointer as an argument. It is -common to ignore the return value from seq_printf(), but a function -producing complicated output may want to check that value and quit if -something non-zero is returned; an error return means that the seq_file -buffer has been filled and further output will be discarded. +printk(), but which requires the seq_file pointer as an argument. For straight character output, the following functions may be used: - int seq_putc(struct seq_file *m, char c); - int seq_puts(struct seq_file *m, const char *s); - int seq_escape(struct seq_file *m, const char *s, const char *esc); + seq_putc(struct seq_file *m, char c); + seq_puts(struct seq_file *m, const char *s); + seq_escape(struct seq_file *m, const char *s, const char *esc); The first two output a single character and a string, just like one would expect. seq_escape() is like seq_puts(), except that any character in s which is in the string esc will be represented in octal form in the output. -There is also a pair of functions for printing filenames: +There are also a pair of functions for printing filenames: int seq_path(struct seq_file *m, struct path *path, char *esc); int seq_path_root(struct seq_file *m, struct path *path, @@ -200,6 +196,14 @@ root is desired, it can be used with seq_path_root(). Note that, if it turns out that path cannot be reached from root, the value of root will be changed in seq_file_root() to a root which *does* work. +A function producing complicated output may want to check + bool seq_has_overflowed(struct seq_file *m); +and avoid further seq_ calls if true is returned. + +A true return from seq_has_overflowed means that the seq_file buffer will +be discarded and the seq_show function will attempt to allocate a larger +buffer and retry printing. + Making it all work diff --git a/fs/seq_file.c b/fs/seq_file.c index 47639c8b309f..5b9af0041d2e 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -16,17 +16,6 @@ #include #include - -/* - * seq_files have a buffer which can may overflow. When this happens a larger - * buffer is reallocated and all the data will be printed again. - * The overflow state is true when m->count == m->size. - */ -static bool seq_overflow(struct seq_file *m) -{ - return m->count == m->size; -} - static void seq_set_overflow(struct seq_file *m) { m->count = m->size; @@ -134,7 +123,7 @@ static int traverse(struct seq_file *m, loff_t offset) error = 0; m->count = 0; } - if (seq_overflow(m)) + if (seq_has_overflowed(m)) goto Eoverflow; if (pos + m->count > offset) { m->from = offset - pos; @@ -279,7 +268,7 @@ Fill: break; } err = m->op->show(m, p); - if (seq_overflow(m) || err) { + if (seq_has_overflowed(m) || err) { m->count = offs; if (likely(err <= 0)) break; diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 8f5b241932ee..2fe007f1c49d 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -37,6 +37,21 @@ struct seq_operations { #define SEQ_SKIP 1 +/** + * seq_has_overflowed - check if the buffer has overflowed + * @m: the seq_file handle + * + * seq_files have a buffer which may overflow. When this happens a larger + * buffer is reallocated and all the data will be printed again. + * The overflow state is true when m->count == m->size. + * + * Returns true if the buffer received more than it can hold. + */ +static inline bool seq_has_overflowed(struct seq_file *m) +{ + return m->count == m->size; +} + /** * seq_get_buf - get buffer to write arbitrary data to * @m: the seq_file handle -- GitLab From 5e8ee48a1ca7e9e6490564ee875827aeb21b7f04 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 13 Jul 2021 17:49:23 +0200 Subject: [PATCH 435/528] seq_file: disallow extremely large seq buffer allocations commit 8cae8cd89f05f6de223d63e6d15e31c8ba9cf53b upstream. There is no reasonable need for a buffer larger than this, and it avoids int overflow pitfalls. Fixes: 058504edd026 ("fs/seq_file: fallback to vmalloc allocation") Suggested-by: Al Viro Reported-by: Qualys Security Advisory Signed-off-by: Eric Sandeen Cc: stable@kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Change-Id: Ibfc4eb36ba5f5d38ed02b853e8efdf19b1814a66 (cherry picked from commit c9163e6185199aba6e8f5c40126baa8ba4dba9b2) --- fs/seq_file.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/seq_file.c b/fs/seq_file.c index 5b9af0041d2e..7c1e0c043312 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,9 @@ static void *seq_buf_alloc(unsigned long size) void *buf; gfp_t gfp = GFP_KERNEL; + if (unlikely(size > MAX_RW_COUNT)) + return NULL; + /* * For high order allocations, use __GFP_NORETRY to avoid oom-killing - * it's better to fall back to vmalloc() than to kill things. For small -- GitLab From 3d06769915a4ea2ad27d9e05c66bd2ab8cce04be Mon Sep 17 00:00:00 2001 From: Behan Webster Date: Wed, 27 Aug 2014 05:29:29 +0100 Subject: [PATCH 436/528] UPSTREAM: arm64: LLVMLinux: Add current_stack_pointer() for arm64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define a global named register for current_stack_pointer. The use of this new variable guarantees that both gcc and clang can access this register in C code. Signed-off-by: Behan Webster Reviewed-by: Jan-Simon Möller Reviewed-by: Mark Charlebois Reviewed-by: Olof Johansson Acked-by: Will Deacon Signed-off-by: Will Deacon (cherry picked from commit 3337a10e0d0cbc9225cefc23aa7a604b698367ed) Bug: 29520177 Signed-off-by: Mohan Srinivasan Change-Id: I19acaf0740ed061d47e4d4c6547142d45aaf81d4 (cherry picked from commit 388212ef48c94f6034cd1459f72d38b168970a32) --- arch/arm64/include/asm/thread_info.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index f4091da4d972..c3216a60d3f3 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -68,6 +68,11 @@ struct thread_info { #define init_thread_info (init_thread_union.thread_info) #define init_stack (init_thread_union.stack) +/* + * how to get the current stack pointer from C + */ +register unsigned long current_stack_pointer asm ("sp"); + /* * how to get the thread information struct from C */ -- GitLab From f17e8b183300e9939b7bb94ff16facf2732f5f79 Mon Sep 17 00:00:00 2001 From: Hou Pengyang Date: Sun, 10 May 2015 11:07:40 +0000 Subject: [PATCH 437/528] UPSTREAM: arm64: perf: Fix callchain parse error with kernel tracepoint events For ARM64, when tracing with tracepoint events, the IP and pstate are set to 0, preventing the perf code parsing the callchain and resolving the symbols correctly. ./perf record -e sched:sched_switch -g --call-graph dwarf ls [ perf record: Captured and wrote 0.146 MB perf.data ] ./perf report -f Samples: 194 of event 'sched:sched_switch', Event count (approx.): 194 Children Self Command Shared Object Symbol 100.00% 100.00% ls [unknown] [.] 0000000000000000 The fix is to implement perf_arch_fetch_caller_regs for ARM64, which fills several necessary registers used for callchain unwinding, including pc,sp, fp and spsr . With this patch, callchain can be parsed correctly as follows: ...... + 2.63% 0.00% ls [kernel.kallsyms] [k] vfs_symlink + 2.63% 0.00% ls [kernel.kallsyms] [k] follow_down + 2.63% 0.00% ls [kernel.kallsyms] [k] pfkey_get + 2.63% 0.00% ls [kernel.kallsyms] [k] do_execveat_common.isra.33 - 2.63% 0.00% ls [kernel.kallsyms] [k] pfkey_send_policy_notify pfkey_send_policy_notify pfkey_get v9fs_vfs_rename page_follow_link_light link_path_walk el0_svc_naked ....... Change-Id: Ia6160089dd92122392fb0d246721ef3c6b02f430 Signed-off-by: Hou Pengyang Acked-by: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit 5b09a094f2fb768c76c8d4a82503df6fc7e1df63) Bug: 29520177 Signed-off-by: Mohan Srinivasan (cherry picked from commit 7e4eab441f85d0329ce9d1f40725df3f407a15fb) --- arch/arm64/include/asm/perf_event.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index 547d4f9e96e0..227ac1fa2e42 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -41,4 +41,11 @@ static inline void arm64_pmu_unlock(raw_spinlock_t *lock, unsigned long *flags) { } #endif +#define perf_arch_fetch_caller_regs(regs, __ip) { \ + (regs)->pc = (__ip); \ + (regs)->regs[29] = (unsigned long) __builtin_frame_address(0); \ + (regs)->sp = current_stack_pointer; \ + (regs)->pstate = PSR_MODE_EL1h; \ +} + #endif -- GitLab From feb0787c3d628d46aa1cb6a68c563a7d0e99f1c4 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 14 Nov 2016 19:32:43 +0530 Subject: [PATCH 438/528] UPSTREAM: arm64: Allow hw watchpoint at varied offset from base address ARM64 hardware supports watchpoint at any double word aligned address. However, it can select any consecutive bytes from offset 0 to 7 from that base address. For example, if base address is programmed as 0x420030 and byte select is 0x1C, then access of 0x420032,0x420033 and 0x420034 will generate a watchpoint exception. Currently, we do not have such modularity. We can only program byte, halfword, word and double word access exception from any base address. This patch adds support to overcome above limitations. Signed-off-by: Pratyush Anand Signed-off-by: Will Deacon Signed-off-by: Pavel Labath Change-Id: I28b1ca63f63182c10c3d6b6b3bacf6c56887ddbe Bug: 30919905 (cherry picked from commit fdfc65f055e0d4bb8d210f55d242946780f2dfa4) --- arch/arm64/include/asm/hw_breakpoint.h | 2 +- arch/arm64/kernel/hw_breakpoint.c | 47 +++++++++++++------------- arch/arm64/kernel/ptrace.c | 7 ++-- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index 52b484b6aa1a..f44bb04bc47c 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -107,7 +107,7 @@ struct perf_event; struct pmu; extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, - int *gen_len, int *gen_type); + int *gen_len, int *gen_type, int *offset); extern int arch_check_bp_in_kernelspace(struct perf_event *bp); extern int arch_validate_hwbkpt_settings(struct perf_event *bp); extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index de7b854438d7..4d8a86a8a6eb 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -343,7 +343,7 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp) * to generic breakpoint descriptions. */ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, - int *gen_len, int *gen_type) + int *gen_len, int *gen_type, int *offset) { /* Type */ switch (ctrl.type) { @@ -363,8 +363,12 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, return -EINVAL; } + if (!ctrl.len) + return -EINVAL; + *offset = __ffs(ctrl.len); + /* Len */ - switch (ctrl.len) { + switch (ctrl.len >> *offset) { case ARM_BREAKPOINT_LEN_1: *gen_len = HW_BREAKPOINT_LEN_1; break; @@ -511,18 +515,17 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) default: return -EINVAL; } - - info->address &= ~alignment_mask; - info->ctrl.len <<= offset; } else { if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) alignment_mask = 0x3; else alignment_mask = 0x7; - if (info->address & alignment_mask) - return -EINVAL; + offset = info->address & alignment_mask; } + info->address &= ~alignment_mask; + info->ctrl.len <<= offset; + /* * Disallow per-task kernel breakpoints since these would * complicate the stepping code. @@ -657,8 +660,8 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr, struct pt_regs *regs) { int i, step = 0, *kernel_step, access; - u32 ctrl_reg; - u64 val, alignment_mask; + u32 ctrl_reg, lens, lene; + u64 val; struct perf_event *wp, **slots; struct debug_info *debug_info; struct arch_hw_breakpoint *info; @@ -676,25 +679,21 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr, goto unlock; info = counter_arch_bp(wp); - /* AArch32 watchpoints are either 4 or 8 bytes aligned. */ - if (is_compat_task()) { - if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) - alignment_mask = 0x7; - else - alignment_mask = 0x3; - } else { - alignment_mask = 0x7; - } - /* Check if the watchpoint value matches. */ + /* Check if the watchpoint value and byte select match. */ val = read_wb_reg(AARCH64_DBG_REG_WVR, i); - if (val != (addr & ~alignment_mask)) - goto unlock; - - /* Possible match, check the byte address select to confirm. */ ctrl_reg = read_wb_reg(AARCH64_DBG_REG_WCR, i); decode_ctrl_reg(ctrl_reg, &ctrl); - if (!((1 << (addr & alignment_mask)) & ctrl.len)) + lens = ffs(ctrl.len) - 1; + lene = fls(ctrl.len) - 1; + /* + * FIXME: reported address can be anywhere between "the + * lowest address accessed by the memory access that + * triggered the watchpoint" and "the highest watchpointed + * address accessed by the memory access". So, it may not + * lie in the interval of watchpoint address range. + */ + if (addr < val + lens || addr > val + lene) goto unlock; /* diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index dbb52c0dad5b..f7ae2943fe92 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -224,13 +224,13 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type, struct arch_hw_breakpoint_ctrl ctrl, struct perf_event_attr *attr) { - int err, len, type, disabled = !ctrl.enabled; + int err, len, type, offset, disabled = !ctrl.enabled; attr->disabled = disabled; if (disabled) return 0; - err = arch_bp_generic_fields(ctrl, &len, &type); + err = arch_bp_generic_fields(ctrl, &len, &type, &offset); if (err) return err; @@ -249,6 +249,7 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type, attr->bp_len = len; attr->bp_type = type; + attr->bp_addr += offset; return 0; } @@ -301,7 +302,7 @@ static int ptrace_hbp_get_addr(unsigned int note_type, if (IS_ERR(bp)) return PTR_ERR(bp); - *addr = bp ? bp->attr.bp_addr : 0; + *addr = bp ? counter_arch_bp(bp)->address : 0; return 0; } -- GitLab From 76b1c796bcd8aa9b774a4e7baf7f1e4464f8c634 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 14 Nov 2016 19:32:45 +0530 Subject: [PATCH 439/528] UPSTREAM: arm64: Allow hw watchpoint of length 3,5,6 and 7 (cherry picked from commit 0ddb8e0b784ba034f3096d5a54684d0d73155e2a) Since, arm64 can support all offset within a double word limit. Therefore, now support other lengths within that range as well. Signed-off-by: Pratyush Anand Signed-off-by: Will Deacon Signed-off-by: Pavel Labath Change-Id: Ibcb263a3903572336ccbf96e0180d3990326545a Bug: 30919905 (cherry picked from commit a474fad20abbc3cc68e92339292b021d570ccffa) --- arch/arm64/include/asm/hw_breakpoint.h | 4 +++ arch/arm64/kernel/hw_breakpoint.c | 36 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index f44bb04bc47c..77667c30a9ad 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -65,7 +65,11 @@ static inline void decode_ctrl_reg(u32 reg, /* Lengths */ #define ARM_BREAKPOINT_LEN_1 0x1 #define ARM_BREAKPOINT_LEN_2 0x3 +#define ARM_BREAKPOINT_LEN_3 0x7 #define ARM_BREAKPOINT_LEN_4 0xf +#define ARM_BREAKPOINT_LEN_5 0x1f +#define ARM_BREAKPOINT_LEN_6 0x3f +#define ARM_BREAKPOINT_LEN_7 0x7f #define ARM_BREAKPOINT_LEN_8 0xff /* Kernel stepping */ diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index 4d8a86a8a6eb..7414d8a9a133 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -311,9 +311,21 @@ static int get_hbp_len(u8 hbp_len) case ARM_BREAKPOINT_LEN_2: len_in_bytes = 2; break; + case ARM_BREAKPOINT_LEN_3: + len_in_bytes = 3; + break; case ARM_BREAKPOINT_LEN_4: len_in_bytes = 4; break; + case ARM_BREAKPOINT_LEN_5: + len_in_bytes = 5; + break; + case ARM_BREAKPOINT_LEN_6: + len_in_bytes = 6; + break; + case ARM_BREAKPOINT_LEN_7: + len_in_bytes = 7; + break; case ARM_BREAKPOINT_LEN_8: len_in_bytes = 8; break; @@ -375,9 +387,21 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, case ARM_BREAKPOINT_LEN_2: *gen_len = HW_BREAKPOINT_LEN_2; break; + case ARM_BREAKPOINT_LEN_3: + *gen_len = HW_BREAKPOINT_LEN_3; + break; case ARM_BREAKPOINT_LEN_4: *gen_len = HW_BREAKPOINT_LEN_4; break; + case ARM_BREAKPOINT_LEN_5: + *gen_len = HW_BREAKPOINT_LEN_5; + break; + case ARM_BREAKPOINT_LEN_6: + *gen_len = HW_BREAKPOINT_LEN_6; + break; + case ARM_BREAKPOINT_LEN_7: + *gen_len = HW_BREAKPOINT_LEN_7; + break; case ARM_BREAKPOINT_LEN_8: *gen_len = HW_BREAKPOINT_LEN_8; break; @@ -421,9 +445,21 @@ static int arch_build_bp_info(struct perf_event *bp) case HW_BREAKPOINT_LEN_2: info->ctrl.len = ARM_BREAKPOINT_LEN_2; break; + case HW_BREAKPOINT_LEN_3: + info->ctrl.len = ARM_BREAKPOINT_LEN_3; + break; case HW_BREAKPOINT_LEN_4: info->ctrl.len = ARM_BREAKPOINT_LEN_4; break; + case HW_BREAKPOINT_LEN_5: + info->ctrl.len = ARM_BREAKPOINT_LEN_5; + break; + case HW_BREAKPOINT_LEN_6: + info->ctrl.len = ARM_BREAKPOINT_LEN_6; + break; + case HW_BREAKPOINT_LEN_7: + info->ctrl.len = ARM_BREAKPOINT_LEN_7; + break; case HW_BREAKPOINT_LEN_8: info->ctrl.len = ARM_BREAKPOINT_LEN_8; break; -- GitLab From dbc4190a2013a4de71688cb1424d1e12880c33d0 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 24 Oct 2014 14:56:40 +0100 Subject: [PATCH 440/528] BACKPORT: arm64: Fix up /proc/cpuinfo commit 44b82b7700d05a52cd983799d3ecde1a976b3bed upstream. Commit d7a49086f263164a (arm64: cpuinfo: print info for all CPUs) attempted to clean up /proc/cpuinfo, but due to concerns regarding further changes was reverted in commit 5e39977edf6500fd (Revert "arm64: cpuinfo: print info for all CPUs"). There are two major issues with the arm64 /proc/cpuinfo format currently: * The "Features" line describes (only) the 64-bit hwcaps, which is problematic for some 32-bit applications which attempt to parse it. As the same names are used for analogous ISA features (e.g. aes) despite these generally being architecturally unrelated, it is not possible to simply append the 64-bit and 32-bit hwcaps in a manner that might not be misleading to some applications. Various potential solutions have appeared in vendor kernels. Typically the format of the Features line varies depending on whether the task is 32-bit. * Information is only printed regarding a single CPU. This does not match the ARM format, and does not provide sufficient information in big.LITTLE systems where CPUs are heterogeneous. The CPU information printed is queried from the current CPU's registers, which is racy w.r.t. cross-cpu migration. This patch attempts to solve these issues. The following changes are made: * When a task with a LINUX32 personality attempts to read /proc/cpuinfo, the "Features" line contains the decoded 32-bit hwcaps, as with the arm port. Otherwise, the decoded 64-bit hwcaps are shown. This aligns with the behaviour of COMPAT_UTS_MACHINE and COMPAT_ELF_PLATFORM. In the absense of compat support, the Features line is empty. The set of hwcaps injected into a task's auxval are unaffected. * Properties are printed per-cpu, as with the ARM port. The per-cpu information is queried from pre-recorded cpu information (as used by the sanity checks). * As with the previous attempt at fixing up /proc/cpuinfo, the hardware field is removed. The only users so far are 32-bit applications tied to particular boards, so no portable applications should be affected, and this should prevent future tying to particular boards. The following differences remain: * No model_name is printed, as this cannot be queried from the hardware and cannot be provided in a stable fashion. Use of the CPU {implementor,variant,part,revision} fields is sufficient to identify a CPU and is portable across arm and arm64. * The following system-wide properties are not provided, as they are not possible to provide generally. Programs relying on these are already tied to particular (32-bit only) boards: - Hardware - Revision - Serial No software has yet been identified for which these remaining differences are problematic. Change-Id: I75d709c9a2c13c9c62b4d8cf777480801cfaeece Cc: Greg Hackmann Cc: Ian Campbell Cc: Serban Constantinescu Cc: Will Deacon Cc: cross-distro@lists.linaro.org Cc: linux-api@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Acked-by: Catalin Marinas [Mark: backport to v3.10.x] Signed-off-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: David Lin (cherry picked from commit e57ff665e0f1190b563c35623e36d06452063c86) --- arch/arm64/kernel/setup.c | 26 +++++++++++++++----------- arch/arm64/kernel/smp.c | 5 +++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 3ef5cff918cc..493f55ae11da 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -533,14 +533,20 @@ static const char *compat_hwcap_str[] = { "evtstrm", NULL }; -#endif /* CONFIG_COMPAT */ +static const char *compat_hwcap2_str[] = { + "aes", + "pmull", + "sha1", + "sha2", + "crc32", + NULL +}; +#endif /* CONFIG_COMPAT */ static int c_show(struct seq_file *m, void *v) { int i, j; - seq_printf(m, "Processor\t: %s rev %d (%s)\n", - cpu_name, read_cpuid_id() & 15, ELF_PLATFORM); for_each_present_cpu(i) { struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i); u32 midr = cpuinfo->reg_midr; @@ -561,17 +567,22 @@ static int c_show(struct seq_file *m, void *v) * software which does already (at least for 32-bit). */ seq_puts(m, "Features\t:"); + if (personality(current->personality) == PER_LINUX32) { #ifdef CONFIG_COMPAT for (j = 0; compat_hwcap_str[j]; j++) if (COMPAT_ELF_HWCAP & (1 << j)) seq_printf(m, " %s", compat_hwcap_str[j]); + + for (j = 0; compat_hwcap2_str[j]; j++) + if (compat_elf_hwcap2 & (1 << j)) + seq_printf(m, " %s", compat_hwcap2_str[j]); #endif /* CONFIG_COMPAT */ } else { for (j = 0; hwcap_str[j]; j++) if (elf_hwcap & (1 << j)) seq_printf(m, " %s", hwcap_str[j]); - } + } seq_puts(m, "\n"); seq_printf(m, "CPU implementer\t: 0x%02x\n", (midr >> 24)); @@ -580,13 +591,6 @@ static int c_show(struct seq_file *m, void *v) seq_printf(m, "CPU part\t: 0x%03x\n", ((midr >> 4) & 0xfff)); seq_printf(m, "CPU revision\t: %d\n\n", (midr & 0xf)); } -#ifdef CONFIG_ARMV7_COMPAT_CPUINFO - if (is_compat_task()) { - /* Print out the non-optional ARMv8 HW capabilities */ - seq_printf(m, "wp half thumb fastmult vfp edsp neon vfpv3 tlsi "); - seq_printf(m, "vfpv4 idiva idivt "); - } -#endif if (!arch_read_hardware_id) seq_printf(m, "Hardware\t: %s\n", machine_name); diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 73ad727ccd56..4d41b187ca85 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -158,6 +158,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void) if (cpu_ops[cpu]->cpu_postboot) cpu_ops[cpu]->cpu_postboot(); + /* + * Log the CPU info before it is marked online and might get read. + */ + cpuinfo_store_cpu(); + /* * Enable GIC and timers. */ -- GitLab From e10d4a9495530afd522b6e19131d00945d488e2c Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Mon, 15 Jul 2019 12:18:04 -0700 Subject: [PATCH 441/528] binder: prevent transactions to context manager from its own process. Currently, a transaction to context manager from its own process is prevented by checking if its binder_proc struct is the same as that of the sender. However, this would not catch cases where the process opens the binder device again and uses the new fd to send a transaction to the context manager. Reported-by: syzbot+8b3c354d33c4ac78bfad@syzkaller.appspotmail.com Signed-off-by: Hridya Valsaraju Acked-by: Todd Kjos Cc: stable Link: https://lore.kernel.org/r/20190715191804.112933-1-hridya@google.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 49ed96943a8e0c62cc5a9b0a6cfc88be87d1fcec) --- drivers/android/binder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 5291f64f17a8..b7c1134e93d3 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3033,7 +3033,7 @@ static void binder_transaction(struct binder_proc *proc, else return_error = BR_DEAD_REPLY; mutex_unlock(&context->context_mgr_node_lock); - if (target_node && target_proc == proc) { + if (target_node && target_proc->pid == proc->pid) { binder_user_error("%d:%d got transaction to context manager from process owning it\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; -- GitLab From 0bcdf870dee5c5c421d10fa7758fae45f4c31791 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 21 Aug 2020 14:25:44 +0200 Subject: [PATCH 442/528] binder: print warnings when detecting oneway spamming. The most common cause of the binder transaction buffer filling up is a client rapidly firing oneway transactions into a process, before it has a chance to handle them. Yet the root cause of this is often hard to debug, because either the system or the app will stop, and by that time binder debug information we dump in bugreports is no longer relevant. This change warns as soon as a process dips below 80% of its oneway space (less than 100kB available in the configuration), when any one process is responsible for either more than 50 transactions, or more than 50% of the oneway space. Signed-off-by: Martijn Coenen Acked-by: Todd Kjos Link: https://lore.kernel.org/r/20200821122544.1277051-1-maco@android.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 261e7818f06ec51e488e007f787ccd7e77272918) --- drivers/android/binder.c | 2 +- drivers/android/binder_alloc.c | 63 ++++++++++++++++++++++--- drivers/android/binder_alloc.h | 5 +- drivers/android/binder_alloc_selftest.c | 2 +- 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index b7c1134e93d3..cf191edaac0f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3214,7 +3214,7 @@ static void binder_transaction(struct binder_proc *proc, t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, tr->offsets_size, extra_buffers_size, - !reply && (t->flags & TF_ONE_WAY)); + !reply && (t->flags & TF_ONE_WAY), current->tgid); if (IS_ERR(t->buffer)) { /* * -ESRCH indicates VMA cleared. The target is dying. diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 3326c89ed97a..0148f9b67547 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -289,11 +289,49 @@ err_no_vma: return vma ? -ENOMEM : -ESRCH; } -struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, - size_t data_size, - size_t offsets_size, - size_t extra_buffers_size, - int is_async) +static void debug_low_async_space_locked(struct binder_alloc *alloc, int pid) +{ + /* + * Find the amount and size of buffers allocated by the current caller; + * The idea is that once we cross the threshold, whoever is responsible + * for the low async space is likely to try to send another async txn, + * and at some point we'll catch them in the act. This is more efficient + * than keeping a map per pid. + */ + struct rb_node *n = alloc->free_buffers.rb_node; + struct binder_buffer *buffer; + size_t total_alloc_size = 0; + size_t num_buffers = 0; + + for (n = rb_first(&alloc->allocated_buffers); n != NULL; + n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + if (buffer->pid != pid) + continue; + if (!buffer->async_transaction) + continue; + total_alloc_size += binder_alloc_buffer_size(alloc, buffer) + + sizeof(struct binder_buffer); + num_buffers++; + } + + /* + * Warn if this pid has more than 50 transactions, or more than 50% of + * async space (which is 25% of total buffer size). + */ + if (num_buffers > 50 || total_alloc_size > alloc->buffer_size / 4) { + pr_err("%d: pid %d spamming oneway? %zd buffers allocated for a total size of %zd\n", + alloc->pid, pid, num_buffers, total_alloc_size); + } +} + +static struct binder_buffer *binder_alloc_new_buf_locked( + struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async, + int pid) { struct rb_node *n = alloc->free_buffers.rb_node; struct binder_buffer *buffer; @@ -432,11 +470,20 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, buffer->offsets_size = offsets_size; buffer->async_transaction = is_async; buffer->extra_buffers_size = extra_buffers_size; + buffer->pid = pid; if (is_async) { alloc->free_async_space -= size + sizeof(struct binder_buffer); binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, "%d: binder_alloc_buf size %zd async free %zd\n", alloc->pid, size, alloc->free_async_space); + if (alloc->free_async_space < alloc->buffer_size / 10) { + /* + * Start detecting spammers once we have less than 20% + * of async space left (which is less than 10% of total + * buffer size). + */ + debug_low_async_space_locked(alloc, pid); + } } return buffer; @@ -454,6 +501,7 @@ err_alloc_buf_struct_failed: * @offsets_size: user specified buffer offset * @extra_buffers_size: size of extra space for meta-data (eg, security context) * @is_async: buffer for async transaction + * @pid: pid to attribute allocation to (used for debugging) * * Allocate a new buffer given the requested sizes. Returns * the kernel version of the buffer pointer. The size allocated @@ -466,13 +514,14 @@ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, size_t data_size, size_t offsets_size, size_t extra_buffers_size, - int is_async) + int is_async, + int pid) { struct binder_buffer *buffer; mutex_lock(&alloc->mutex); buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size, - extra_buffers_size, is_async); + extra_buffers_size, is_async, pid); mutex_unlock(&alloc->mutex); return buffer; } diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 838e04425c03..8f23c184ec72 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -38,6 +38,7 @@ struct binder_transaction; * @offsets_size: size of array of offsets * @extra_buffers_size: size of space for other objects (like sg lists) * @data: pointer to base of buffer space + * @pid: pid to attribute the buffer to (caller) * * Bookkeeping structure for binder transaction buffers */ @@ -57,6 +58,7 @@ struct binder_buffer { size_t offsets_size; size_t extra_buffers_size; void *data; + int pid; }; /** @@ -110,7 +112,8 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, size_t data_size, size_t offsets_size, size_t extra_buffers_size, - int is_async); + int is_async, + int pid); extern void binder_alloc_init(struct binder_alloc *alloc); extern void binder_alloc_vma_close(struct binder_alloc *alloc); extern struct binder_buffer * diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c index 9a1ffda7c307..eff5dea1509f 100644 --- a/drivers/android/binder_alloc_selftest.c +++ b/drivers/android/binder_alloc_selftest.c @@ -125,7 +125,7 @@ static void binder_selftest_alloc_buf(struct binder_alloc *alloc, int i; for (i = 0; i < BUFFER_NUM; i++) { - buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0); + buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0, 0); if (IS_ERR(buffers[i]) || !check_buffer_pages_allocated(alloc, buffers[i], sizes[i])) { -- GitLab From e874875c2769b719020dd2331afaf2f6f1499839 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 14 Dec 2018 13:11:14 +0100 Subject: [PATCH 443/528] binder: implement binderfs As discussed at Linux Plumbers Conference 2018 in Vancouver [1] this is the implementation of binderfs. /* Abstract */ binderfs is a backwards-compatible filesystem for Android's binder ipc mechanism. Each ipc namespace will mount a new binderfs instance. Mounting binderfs multiple times at different locations in the same ipc namespace will not cause a new super block to be allocated and hence it will be the same filesystem instance. Each new binderfs mount will have its own set of binder devices only visible in the ipc namespace it has been mounted in. All devices in a new binderfs mount will follow the scheme binder%d and numbering will always start at 0. /* Backwards compatibility */ Devices requested in the Kconfig via CONFIG_ANDROID_BINDER_DEVICES for the initial ipc namespace will work as before. They will be registered via misc_register() and appear in the devtmpfs mount. Specifically, the standard devices binder, hwbinder, and vndbinder will all appear in their standard locations in /dev. Mounting or unmounting the binderfs mount in the initial ipc namespace will have no effect on these devices, i.e. they will neither show up in the binderfs mount nor will they disappear when the binderfs mount is gone. /* binder-control */ Each new binderfs instance comes with a binder-control device. No other devices will be present at first. The binder-control device can be used to dynamically allocate binder devices. All requests operate on the binderfs mount the binder-control device resides in. Assuming a new instance of binderfs has been mounted at /dev/binderfs via mount -t binderfs binderfs /dev/binderfs. Then a request to create a new binder device can be made as illustrated in [2]. Binderfs devices can simply be removed via unlink(). /* Implementation details */ - dynamic major number allocation: When binderfs is registered as a new filesystem it will dynamically allocate a new major number. The allocated major number will be returned in struct binderfs_device when a new binder device is allocated. - global minor number tracking: Minor are tracked in a global idr struct that is capped at BINDERFS_MAX_MINOR. The minor number tracker is protected by a global mutex. This is the only point of contention between binderfs mounts. - struct binderfs_info: Each binderfs super block has its own struct binderfs_info that tracks specific details about a binderfs instance: - ipc namespace - dentry of the binder-control device - root uid and root gid of the user namespace the binderfs instance was mounted in - mountable by user namespace root: binderfs can be mounted by user namespace root in a non-initial user namespace. The devices will be owned by user namespace root. - binderfs binder devices without misc infrastructure: New binder devices associated with a binderfs mount do not use the full misc_register() infrastructure. The misc_register() infrastructure can only create new devices in the host's devtmpfs mount. binderfs does however only make devices appear under its own mountpoint and thus allocates new character device nodes from the inode of the root dentry of the super block. This will have the side-effect that binderfs specific device nodes do not appear in sysfs. This behavior is similar to devpts allocated pts devices and has no effect on the functionality of the ipc mechanism itself. [1]: https://goo.gl/JL2tfX [2]: program to allocate a new binderfs binder device: #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { int fd, ret, saved_errno; size_t len; struct binderfs_device device = { 0 }; if (argc < 2) exit(EXIT_FAILURE); len = strlen(argv[1]); if (len > BINDERFS_MAX_NAME) exit(EXIT_FAILURE); memcpy(device.name, argv[1], len); fd = open("/dev/binderfs/binder-control", O_RDONLY | O_CLOEXEC); if (fd < 0) { printf("%s - Failed to open binder-control device\n", strerror(errno)); exit(EXIT_FAILURE); } ret = ioctl(fd, BINDER_CTL_ADD, &device); saved_errno = errno; close(fd); errno = saved_errno; if (ret < 0) { printf("%s - Failed to allocate new binder device\n", strerror(errno)); exit(EXIT_FAILURE); } printf("Allocated new binder device with major %d, minor %d, and " "name %s\n", device.major, device.minor, device.name); exit(EXIT_SUCCESS); } Cc: Martijn Coenen Cc: Greg Kroah-Hartman Signed-off-by: Christian Brauner Acked-by: Todd Kjos Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 3ad20fe393b31025bebfc2d76964561f65df48aa) --- drivers/android/Kconfig | 12 + drivers/android/Makefile | 2 +- drivers/android/binder.c | 26 +- drivers/android/binder_internal.h | 49 +++ drivers/android/binderfs.c | 544 ++++++++++++++++++++++++ include/uapi/linux/android/binder_ctl.h | 35 ++ include/uapi/linux/magic.h | 1 + 7 files changed, 651 insertions(+), 18 deletions(-) create mode 100644 drivers/android/binder_internal.h create mode 100644 drivers/android/binderfs.c create mode 100644 include/uapi/linux/android/binder_ctl.h diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 2a1bc931d471..de8dc280e751 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -19,6 +19,18 @@ config ANDROID_BINDER_IPC Android process, using Binder to identify, invoke and pass arguments between said processes. +config ANDROID_BINDERFS + bool "Android Binderfs filesystem" + depends on ANDROID_BINDER_IPC + default n + ---help--- + Binderfs is a pseudo-filesystem for the Android Binder IPC driver + which can be mounted per-ipc namespace allowing to run multiple + instances of Android. + Each binderfs mount initially only contains a binder-control device. + It can be used to dynamically allocate new binder IPC devices via + ioctls. + config ANDROID_BINDER_DEVICES string "Android Binder devices" depends on ANDROID_BINDER_IPC diff --git a/drivers/android/Makefile b/drivers/android/Makefile index d575ff2f9026..3432ab70b209 100644 --- a/drivers/android/Makefile +++ b/drivers/android/Makefile @@ -1,4 +1,4 @@ ccflags-y += -I$(src) # needed for trace events - +obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o diff --git a/drivers/android/binder.c b/drivers/android/binder.c index cf191edaac0f..4237899c86d5 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -76,6 +76,7 @@ #include "binder.h" #include "binder_alloc.h" +#include "binder_internal.h" #include "binder_trace.h" static HLIST_HEAD(binder_deferred_list); @@ -266,20 +267,6 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( return e; } -struct binder_context { - struct binder_node *binder_context_mgr_node; - struct mutex context_mgr_node_lock; - - kuid_t binder_context_mgr_uid; - const char *name; - bool inherit_fifo_prio; -}; - -struct binder_device { - struct hlist_node hlist; - struct miscdevice miscdev; - struct binder_context context; -}; /** * struct binder_work - work enqueued on a worklist @@ -5337,8 +5324,13 @@ static int binder_open(struct inode *nodp, struct file *filp) proc->default_priority.prio = NICE_TO_PRIO(0); } - binder_dev = container_of(filp->private_data, struct binder_device, - miscdev); + proc->default_priority = task_nice(current); + /* binderfs stashes devices in i_private */ + if (is_binderfs_device(nodp)) + binder_dev = nodp->i_private; + else + binder_dev = container_of(filp->private_data, + struct binder_device, miscdev); proc->context = &binder_dev->context; binder_alloc_init(&proc->alloc); @@ -6148,7 +6140,7 @@ static int binder_transaction_log_show(struct seq_file *m, void *unused) return 0; } -static const struct file_operations binder_fops = { +const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h new file mode 100644 index 000000000000..7fb97f503ef2 --- /dev/null +++ b/drivers/android/binder_internal.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LINUX_BINDER_INTERNAL_H +#define _LINUX_BINDER_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +struct binder_context { + struct binder_node *binder_context_mgr_node; + struct mutex context_mgr_node_lock; + kuid_t binder_context_mgr_uid; + const char *name; +}; + +/** + * struct binder_device - information about a binder device node + * @hlist: list of binder devices (only used for devices requested via + * CONFIG_ANDROID_BINDER_DEVICES) + * @miscdev: information about a binder character device node + * @context: binder context information + * @binderfs_inode: This is the inode of the root dentry of the super block + * belonging to a binderfs mount. + */ +struct binder_device { + struct hlist_node hlist; + struct miscdevice miscdev; + struct binder_context context; + struct inode *binderfs_inode; +}; + +extern const struct file_operations binder_fops; + +#ifdef CONFIG_ANDROID_BINDERFS +extern bool is_binderfs_device(const struct inode *inode); +#else +static inline bool is_binderfs_device(const struct inode *inode) +{ + return false; +} +#endif + +#endif /* _LINUX_BINDER_INTERNAL_H */ diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c new file mode 100644 index 000000000000..7496b10532aa --- /dev/null +++ b/drivers/android/binderfs.c @@ -0,0 +1,544 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "binder_internal.h" + +#define FIRST_INODE 1 +#define SECOND_INODE 2 +#define INODE_OFFSET 3 +#define INTSTRLEN 21 +#define BINDERFS_MAX_MINOR (1U << MINORBITS) + +static struct vfsmount *binderfs_mnt; + +static dev_t binderfs_dev; +static DEFINE_MUTEX(binderfs_minors_mutex); +static DEFINE_IDA(binderfs_minors); + +/** + * binderfs_info - information about a binderfs mount + * @ipc_ns: The ipc namespace the binderfs mount belongs to. + * @control_dentry: This records the dentry of this binderfs mount + * binder-control device. + * @root_uid: uid that needs to be used when a new binder device is + * created. + * @root_gid: gid that needs to be used when a new binder device is + * created. + */ +struct binderfs_info { + struct ipc_namespace *ipc_ns; + struct dentry *control_dentry; + kuid_t root_uid; + kgid_t root_gid; + +}; + +static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) +{ + return inode->i_sb->s_fs_info; +} + +bool is_binderfs_device(const struct inode *inode) +{ + if (inode->i_sb->s_magic == BINDERFS_SUPER_MAGIC) + return true; + + return false; +} + +/** + * binderfs_binder_device_create - allocate inode from super block of a + * binderfs mount + * @ref_inode: inode from wich the super block will be taken + * @userp: buffer to copy information about new device for userspace to + * @req: struct binderfs_device as copied from userspace + * + * This function allocated a new binder_device and reserves a new minor + * number for it. + * Minor numbers are limited and tracked globally in binderfs_minors. The + * function will stash a struct binder_device for the specific binder + * device in i_private of the inode. + * It will go on to allocate a new inode from the super block of the + * filesystem mount, stash a struct binder_device in its i_private field + * and attach a dentry to that inode. + * + * Return: 0 on success, negative errno on failure + */ +static int binderfs_binder_device_create(struct inode *ref_inode, + struct binderfs_device __user *userp, + struct binderfs_device *req) +{ + int minor, ret; + struct dentry *dentry, *dup, *root; + struct binder_device *device; + size_t name_len = BINDERFS_MAX_NAME + 1; + char *name = NULL; + struct inode *inode = NULL; + struct super_block *sb = ref_inode->i_sb; + struct binderfs_info *info = sb->s_fs_info; + + /* Reserve new minor number for the new device. */ + mutex_lock(&binderfs_minors_mutex); + minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, GFP_KERNEL); + mutex_unlock(&binderfs_minors_mutex); + if (minor < 0) + return minor; + + ret = -ENOMEM; + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) + goto err; + + inode = new_inode(sb); + if (!inode) + goto err; + + inode->i_ino = minor + INODE_OFFSET; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + init_special_inode(inode, S_IFCHR | 0600, + MKDEV(MAJOR(binderfs_dev), minor)); + inode->i_fop = &binder_fops; + inode->i_uid = info->root_uid; + inode->i_gid = info->root_gid; + + name = kmalloc(name_len, GFP_KERNEL); + if (!name) + goto err; + + strscpy(name, req->name, name_len); + + device->binderfs_inode = inode; + device->context.binder_context_mgr_uid = INVALID_UID; + device->context.name = name; + device->miscdev.name = name; + device->miscdev.minor = minor; + mutex_init(&device->context.context_mgr_node_lock); + + req->major = MAJOR(binderfs_dev); + req->minor = minor; + + ret = copy_to_user(userp, req, sizeof(*req)); + if (ret) { + ret = -EFAULT; + goto err; + } + + root = sb->s_root; + inode_lock(d_inode(root)); + dentry = d_alloc_name(root, name); + if (!dentry) { + inode_unlock(d_inode(root)); + ret = -ENOMEM; + goto err; + } + + /* Verify that the name userspace gave us is not already in use. */ + dup = d_lookup(root, &dentry->d_name); + if (dup) { + if (d_really_is_positive(dup)) { + dput(dup); + dput(dentry); + inode_unlock(d_inode(root)); + ret = -EEXIST; + goto err; + } + dput(dup); + } + + inode->i_private = device; + d_add(dentry, inode); + fsnotify_create(root->d_inode, dentry); + inode_unlock(d_inode(root)); + + return 0; + +err: + kfree(name); + kfree(device); + mutex_lock(&binderfs_minors_mutex); + ida_free(&binderfs_minors, minor); + mutex_unlock(&binderfs_minors_mutex); + iput(inode); + + return ret; +} + +/** + * binderfs_ctl_ioctl - handle binder device node allocation requests + * + * The request handler for the binder-control device. All requests operate on + * the binderfs mount the binder-control device resides in: + * - BINDER_CTL_ADD + * Allocate a new binder device. + * + * Return: 0 on success, negative errno on failure + */ +static long binder_ctl_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = -EINVAL; + struct inode *inode = file_inode(file); + struct binderfs_device __user *device = (struct binderfs_device __user *)arg; + struct binderfs_device device_req; + + switch (cmd) { + case BINDER_CTL_ADD: + ret = copy_from_user(&device_req, device, sizeof(device_req)); + if (ret) { + ret = -EFAULT; + break; + } + + ret = binderfs_binder_device_create(inode, device, &device_req); + break; + default: + break; + } + + return ret; +} + +static void binderfs_evict_inode(struct inode *inode) +{ + struct binder_device *device = inode->i_private; + + clear_inode(inode); + + if (!device) + return; + + mutex_lock(&binderfs_minors_mutex); + ida_free(&binderfs_minors, device->miscdev.minor); + mutex_unlock(&binderfs_minors_mutex); + + kfree(device->context.name); + kfree(device); +} + +static const struct super_operations binderfs_super_ops = { + .statfs = simple_statfs, + .evict_inode = binderfs_evict_inode, +}; + +static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + struct inode *inode = d_inode(old_dentry); + + /* binderfs doesn't support directories. */ + if (d_is_dir(old_dentry)) + return -EPERM; + + if (flags & ~RENAME_NOREPLACE) + return -EINVAL; + + if (!simple_empty(new_dentry)) + return -ENOTEMPTY; + + if (d_really_is_positive(new_dentry)) + simple_unlink(new_dir, new_dentry); + + old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime = + new_dir->i_mtime = inode->i_ctime = current_time(old_dir); + + return 0; +} + +static int binderfs_unlink(struct inode *dir, struct dentry *dentry) +{ + /* + * The control dentry is only ever touched during mount so checking it + * here should not require us to take lock. + */ + if (BINDERFS_I(dir)->control_dentry == dentry) + return -EPERM; + + return simple_unlink(dir, dentry); +} + +static const struct file_operations binder_ctl_fops = { + .owner = THIS_MODULE, + .open = nonseekable_open, + .unlocked_ioctl = binder_ctl_ioctl, + .compat_ioctl = binder_ctl_ioctl, + .llseek = noop_llseek, +}; + +/** + * binderfs_binder_ctl_create - create a new binder-control device + * @sb: super block of the binderfs mount + * + * This function creates a new binder-control device node in the binderfs mount + * referred to by @sb. + * + * Return: 0 on success, negative errno on failure + */ +static int binderfs_binder_ctl_create(struct super_block *sb) +{ + int minor, ret; + struct dentry *dentry; + struct binder_device *device; + struct inode *inode = NULL; + struct dentry *root = sb->s_root; + struct binderfs_info *info = sb->s_fs_info; + + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) + return -ENOMEM; + + inode_lock(d_inode(root)); + + /* If we have already created a binder-control node, return. */ + if (info->control_dentry) { + ret = 0; + goto out; + } + + ret = -ENOMEM; + inode = new_inode(sb); + if (!inode) + goto out; + + /* Reserve a new minor number for the new device. */ + mutex_lock(&binderfs_minors_mutex); + minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, GFP_KERNEL); + mutex_unlock(&binderfs_minors_mutex); + if (minor < 0) { + ret = minor; + goto out; + } + + inode->i_ino = SECOND_INODE; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + init_special_inode(inode, S_IFCHR | 0600, + MKDEV(MAJOR(binderfs_dev), minor)); + inode->i_fop = &binder_ctl_fops; + inode->i_uid = info->root_uid; + inode->i_gid = info->root_gid; + + device->binderfs_inode = inode; + device->miscdev.minor = minor; + + dentry = d_alloc_name(root, "binder-control"); + if (!dentry) + goto out; + + inode->i_private = device; + info->control_dentry = dentry; + d_add(dentry, inode); + inode_unlock(d_inode(root)); + + return 0; + +out: + inode_unlock(d_inode(root)); + kfree(device); + iput(inode); + + return ret; +} + +static const struct inode_operations binderfs_dir_inode_operations = { + .lookup = simple_lookup, + .rename = binderfs_rename, + .unlink = binderfs_unlink, +}; + +static int binderfs_fill_super(struct super_block *sb, void *data, int silent) +{ + struct binderfs_info *info; + int ret = -ENOMEM; + struct inode *inode = NULL; + struct ipc_namespace *ipc_ns = sb->s_fs_info; + + get_ipc_ns(ipc_ns); + + sb->s_blocksize = PAGE_SIZE; + sb->s_blocksize_bits = PAGE_SHIFT; + + /* + * The binderfs filesystem can be mounted by userns root in a + * non-initial userns. By default such mounts have the SB_I_NODEV flag + * set in s_iflags to prevent security issues where userns root can + * just create random device nodes via mknod() since it owns the + * filesystem mount. But binderfs does not allow to create any files + * including devices nodes. The only way to create binder devices nodes + * is through the binder-control device which userns root is explicitly + * allowed to do. So removing the SB_I_NODEV flag from s_iflags is both + * necessary and safe. + */ + sb->s_iflags &= ~SB_I_NODEV; + sb->s_iflags |= SB_I_NOEXEC; + sb->s_magic = BINDERFS_SUPER_MAGIC; + sb->s_op = &binderfs_super_ops; + sb->s_time_gran = 1; + + info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); + if (!info) + goto err_without_dentry; + + info->ipc_ns = ipc_ns; + info->root_gid = make_kgid(sb->s_user_ns, 0); + if (!gid_valid(info->root_gid)) + info->root_gid = GLOBAL_ROOT_GID; + info->root_uid = make_kuid(sb->s_user_ns, 0); + if (!uid_valid(info->root_uid)) + info->root_uid = GLOBAL_ROOT_UID; + + sb->s_fs_info = info; + + inode = new_inode(sb); + if (!inode) + goto err_without_dentry; + + inode->i_ino = FIRST_INODE; + inode->i_fop = &simple_dir_operations; + inode->i_mode = S_IFDIR | 0755; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + inode->i_op = &binderfs_dir_inode_operations; + set_nlink(inode, 2); + + sb->s_root = d_make_root(inode); + if (!sb->s_root) + goto err_without_dentry; + + ret = binderfs_binder_ctl_create(sb); + if (ret) + goto err_with_dentry; + + return 0; + +err_with_dentry: + dput(sb->s_root); + sb->s_root = NULL; + +err_without_dentry: + put_ipc_ns(ipc_ns); + iput(inode); + kfree(info); + + return ret; +} + +static int binderfs_test_super(struct super_block *sb, void *data) +{ + struct binderfs_info *info = sb->s_fs_info; + + if (info) + return info->ipc_ns == data; + + return 0; +} + +static int binderfs_set_super(struct super_block *sb, void *data) +{ + sb->s_fs_info = data; + return set_anon_super(sb, NULL); +} + +static struct dentry *binderfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) +{ + struct super_block *sb; + struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; + + if (!ns_capable(ipc_ns->user_ns, CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + + sb = sget_userns(fs_type, binderfs_test_super, binderfs_set_super, + flags, ipc_ns->user_ns, ipc_ns); + if (IS_ERR(sb)) + return ERR_CAST(sb); + + if (!sb->s_root) { + int ret = binderfs_fill_super(sb, data, flags & SB_SILENT ? 1 : 0); + if (ret) { + deactivate_locked_super(sb); + return ERR_PTR(ret); + } + + sb->s_flags |= SB_ACTIVE; + } + + return dget(sb->s_root); +} + +static void binderfs_kill_super(struct super_block *sb) +{ + struct binderfs_info *info = sb->s_fs_info; + + if (info && info->ipc_ns) + put_ipc_ns(info->ipc_ns); + + kfree(info); + kill_litter_super(sb); +} + +static struct file_system_type binder_fs_type = { + .name = "binder", + .mount = binderfs_mount, + .kill_sb = binderfs_kill_super, + .fs_flags = FS_USERNS_MOUNT, +}; + +static int __init init_binderfs(void) +{ + int ret; + + /* Allocate new major number for binderfs. */ + ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR, + "binder"); + if (ret) + return ret; + + ret = register_filesystem(&binder_fs_type); + if (ret) { + unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); + return ret; + } + + binderfs_mnt = kern_mount(&binder_fs_type); + if (IS_ERR(binderfs_mnt)) { + ret = PTR_ERR(binderfs_mnt); + binderfs_mnt = NULL; + unregister_filesystem(&binder_fs_type); + unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); + } + + return ret; +} + +device_initcall(init_binderfs); diff --git a/include/uapi/linux/android/binder_ctl.h b/include/uapi/linux/android/binder_ctl.h new file mode 100644 index 000000000000..65b2efd1a0a5 --- /dev/null +++ b/include/uapi/linux/android/binder_ctl.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2018 Canonical Ltd. + * + */ + +#ifndef _UAPI_LINUX_BINDER_CTL_H +#define _UAPI_LINUX_BINDER_CTL_H + +#include +#include +#include + +#define BINDERFS_MAX_NAME 255 + +/** + * struct binderfs_device - retrieve information about a new binder device + * @name: the name to use for the new binderfs binder device + * @major: major number allocated for binderfs binder devices + * @minor: minor number allocated for the new binderfs binder device + * + */ +struct binderfs_device { + char name[BINDERFS_MAX_NAME + 1]; + __u8 major; + __u8 minor; +}; + +/** + * Allocate a new binder device. + */ +#define BINDER_CTL_ADD _IOWR('b', 1, struct binderfs_device) + +#endif /* _UAPI_LINUX_BINDER_CTL_H */ + diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index fc9697a76688..0ee2b194fbc0 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -65,6 +65,7 @@ #define BDEVFS_MAGIC 0x62646576 #define BINFMTFS_MAGIC 0x42494e4d #define DEVPTS_SUPER_MAGIC 0x1cd1 +#define BINDERFS_SUPER_MAGIC 0x6c6f6f70 #define FUTEXFS_SUPER_MAGIC 0xBAD1DEA #define PIPEFS_MAGIC 0x50495045 #define PROC_SUPER_MAGIC 0x9fa0 -- GitLab From 1af87384c07189ed09a9147e73bb027894edbbbe Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 6 Jan 2019 15:05:40 +0100 Subject: [PATCH 444/528] binderfs: remove wrong kern_mount() call The binderfs filesystem never needs to be mounted by the kernel itself. This is conceptually wrong and should never have been done in the first place. Fixes: 3ad20fe393b ("binder: implement binderfs") Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 3fdd94acd50d607cf6a971455307e711fd8ee16e) --- drivers/android/binderfs.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 7496b10532aa..6f68d6217eb3 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -40,8 +40,6 @@ #define INTSTRLEN 21 #define BINDERFS_MAX_MINOR (1U << MINORBITS) -static struct vfsmount *binderfs_mnt; - static dev_t binderfs_dev; static DEFINE_MUTEX(binderfs_minors_mutex); static DEFINE_IDA(binderfs_minors); @@ -530,14 +528,6 @@ static int __init init_binderfs(void) return ret; } - binderfs_mnt = kern_mount(&binder_fs_type); - if (IS_ERR(binderfs_mnt)) { - ret = PTR_ERR(binderfs_mnt); - binderfs_mnt = NULL; - unregister_filesystem(&binder_fs_type); - unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); - } - return ret; } -- GitLab From 3c6c6d5147fce8fabd43a9afc193d6a252fc005d Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 11 Jan 2019 11:19:40 +0100 Subject: [PATCH 445/528] binderfs: reserve devices for initial mount The binderfs instance in the initial ipc namespace will always have a reserve of 4 binder devices unless explicitly capped by specifying a lower value via the "max" mount option. This ensures when binder devices are removed (on accident or on purpose) they can always be recreated without risking that all minor numbers have already been used up. Cc: Todd Kjos Cc: Greg Kroah-Hartman Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 36bdf3cae09df891b191f3955c8e54a2e05d67d0) --- drivers/android/binderfs.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 6f68d6217eb3..0f33995890ab 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -39,6 +39,8 @@ #define INODE_OFFSET 3 #define INTSTRLEN 21 #define BINDERFS_MAX_MINOR (1U << MINORBITS) +/* Ensure that the initial ipc namespace always has devices available. */ +#define BINDERFS_MAX_MINOR_CAPPED (BINDERFS_MAX_MINOR - 4) static dev_t binderfs_dev; static DEFINE_MUTEX(binderfs_minors_mutex); @@ -105,10 +107,23 @@ static int binderfs_binder_device_create(struct inode *ref_inode, struct inode *inode = NULL; struct super_block *sb = ref_inode->i_sb; struct binderfs_info *info = sb->s_fs_info; + bool use_reserve = (info->ipc_ns == &init_ipc_ns); /* Reserve new minor number for the new device. */ mutex_lock(&binderfs_minors_mutex); - minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, GFP_KERNEL); + if (++info->device_count <= info->mount_opts.max) + minor = ida_alloc_max(&binderfs_minors, + use_reserve ? BINDERFS_MAX_MINOR : + BINDERFS_MAX_MINOR_CAPPED, + GFP_KERNEL); + else + minor = -ENOSPC; + if (minor < 0) { + --info->device_count; + mutex_unlock(&binderfs_minors_mutex); + return minor; + } + mutex_unlock(&binderfs_minors_mutex); if (minor < 0) return minor; -- GitLab From cc45c64643010da93ffecf5ef0f3a04da58a2a25 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 11 Jan 2019 00:25:41 +0100 Subject: [PATCH 446/528] binderfs: rename header to binderfs.h It doesn't make sense to call the header binder_ctl.h when its sole existence is tied to binderfs. So give it a sensible name. Users will far more easily remember binderfs.h than binder_ctl.h. Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit c13295ad219d8bb0e47942d4cfc8251de449a67e) --- drivers/android/binderfs.c | 2 +- include/uapi/linux/android/{binder_ctl.h => binderfs.h} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename include/uapi/linux/android/{binder_ctl.h => binderfs.h} (100%) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 0f33995890ab..64e5580e5bcd 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "binder_internal.h" diff --git a/include/uapi/linux/android/binder_ctl.h b/include/uapi/linux/android/binderfs.h similarity index 100% rename from include/uapi/linux/android/binder_ctl.h rename to include/uapi/linux/android/binderfs.h -- GitLab From bba1fd273c802d7a22905b04452e283cf9f391cc Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 2 Jan 2019 12:32:18 +0100 Subject: [PATCH 447/528] binderfs: implement "max" mount option Since binderfs can be mounted by userns root in non-initial user namespaces some precautions are in order. First, a way to set a maximum on the number of binder devices that can be allocated per binderfs instance and second, a way to reserve a reasonable chunk of binderfs devices for the initial ipc namespace. A first approach as seen in [1] used sysctls similiar to devpts but was shown to be flawed (cf. [2] and [3]) since some aspects were unneeded. This is an alternative approach which avoids sysctls completely and instead switches to a single mount option. Starting with this commit binderfs instances can be mounted with a limit on the number of binder devices that can be allocated. The max= mount option serves as a per-instance limit. If max= is set then only number of binder devices can be allocated in this binderfs instance. This allows to safely bind-mount binderfs instances into unprivileged user namespaces since userns root in a non-initial user namespace cannot change the mount option as long as it does not own the mount namespace the binderfs mount was created in and hence cannot drain the host of minor device numbers [1]: https://lore.kernel.org/lkml/20181221133909.18794-1-christian@brauner.io/ [2]; https://lore.kernel.org/lkml/20181221163316.GA8517@kroah.com/ [3]: https://lore.kernel.org/lkml/CAHRSSEx+gDVW4fKKK8oZNAir9G5icJLyodO8hykv3O0O1jt2FQ@mail.gmail.com/ [4]: https://lore.kernel.org/lkml/20181221192044.5yvfnuri7gdop4rs@brauner.io/ Cc: Todd Kjos Cc: Greg Kroah-Hartman Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 849d540ddfcd4f232f3b2cf40a2e07eccbd6212c) --- drivers/android/binderfs.c | 94 +++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 64e5580e5bcd..1ee90e44fc5d 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,24 @@ static dev_t binderfs_dev; static DEFINE_MUTEX(binderfs_minors_mutex); static DEFINE_IDA(binderfs_minors); +/** + * binderfs_mount_opts - mount options for binderfs + * @max: maximum number of allocatable binderfs binder devices + */ +struct binderfs_mount_opts { + int max; +}; + +enum { + Opt_max, + Opt_err +}; + +static const match_table_t tokens = { + { Opt_max, "max=%d" }, + { Opt_err, NULL } +}; + /** * binderfs_info - information about a binderfs mount * @ipc_ns: The ipc namespace the binderfs mount belongs to. @@ -55,13 +74,16 @@ static DEFINE_IDA(binderfs_minors); * created. * @root_gid: gid that needs to be used when a new binder device is * created. + * @mount_opts: The mount options in use. + * @device_count: The current number of allocated binder devices. */ struct binderfs_info { struct ipc_namespace *ipc_ns; struct dentry *control_dentry; kuid_t root_uid; kgid_t root_gid; - + struct binderfs_mount_opts mount_opts; + int device_count; }; static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) @@ -123,10 +145,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode, mutex_unlock(&binderfs_minors_mutex); return minor; } - mutex_unlock(&binderfs_minors_mutex); - if (minor < 0) - return minor; ret = -ENOMEM; device = kzalloc(sizeof(*device), GFP_KERNEL); @@ -200,6 +219,7 @@ err: kfree(name); kfree(device); mutex_lock(&binderfs_minors_mutex); + --info->device_count; ida_free(&binderfs_minors, minor); mutex_unlock(&binderfs_minors_mutex); iput(inode); @@ -245,6 +265,7 @@ static long binder_ctl_ioctl(struct file *file, unsigned int cmd, static void binderfs_evict_inode(struct inode *inode) { struct binder_device *device = inode->i_private; + struct binderfs_info *info = BINDERFS_I(inode); clear_inode(inode); @@ -252,6 +273,7 @@ static void binderfs_evict_inode(struct inode *inode) return; mutex_lock(&binderfs_minors_mutex); + --info->device_count; ida_free(&binderfs_minors, device->miscdev.minor); mutex_unlock(&binderfs_minors_mutex); @@ -259,9 +281,65 @@ static void binderfs_evict_inode(struct inode *inode) kfree(device); } +/** + * binderfs_parse_mount_opts - parse binderfs mount options + * @data: options to set (can be NULL in which case defaults are used) + */ +static int binderfs_parse_mount_opts(char *data, + struct binderfs_mount_opts *opts) +{ + char *p; + opts->max = BINDERFS_MAX_MINOR; + + while ((p = strsep(&data, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + int token; + int max_devices; + + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case Opt_max: + if (match_int(&args[0], &max_devices) || + (max_devices < 0 || + (max_devices > BINDERFS_MAX_MINOR))) + return -EINVAL; + + opts->max = max_devices; + break; + default: + pr_err("Invalid mount options\n"); + return -EINVAL; + } + } + + return 0; +} + +static int binderfs_remount(struct super_block *sb, int *flags, char *data) +{ + struct binderfs_info *info = sb->s_fs_info; + return binderfs_parse_mount_opts(data, &info->mount_opts); +} + +static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root) +{ + struct binderfs_info *info; + + info = root->d_sb->s_fs_info; + if (info->mount_opts.max <= BINDERFS_MAX_MINOR) + seq_printf(seq, ",max=%d", info->mount_opts.max); + + return 0; +} + static const struct super_operations binderfs_super_ops = { - .statfs = simple_statfs, - .evict_inode = binderfs_evict_inode, + .evict_inode = binderfs_evict_inode, + .remount_fs = binderfs_remount, + .show_options = binderfs_show_mount_opts, + .statfs = simple_statfs, }; static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry, @@ -422,6 +500,10 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) if (!info) goto err_without_dentry; + ret = binderfs_parse_mount_opts(data, &info->mount_opts); + if (ret) + goto err_without_dentry; + info->ipc_ns = ipc_ns; info->root_gid = make_kgid(sb->s_user_ns, 0); if (!gid_valid(info->root_gid)) -- GitLab From 5b298bfa1597bc37a1e5ae89b59041c561f8744e Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 6 Jan 2019 15:05:41 +0100 Subject: [PATCH 448/528] binderfs: make each binderfs mount a new instance When currently mounting binderfs in the same ipc namespace twice: mount -t binder binder /A mount -t binder binder /B then the binderfs instances mounted on /A and /B will be the same, i.e. they will have the same superblock. This was the first approach that seemed reasonable. However, this leads to some problems and inconsistencies: /* private binderfs instance in same ipc namespace */ There is no way for a user to request a private binderfs instance in the same ipc namespace. This request has been made in a private mail to me by two independent people. /* bind-mounts */ If users want the same binderfs instance to appear in multiple places they can use bind mounts. So there is no value in having a request for a new binderfs mount giving them the same instance. /* unexpected behavior */ It's surprising that request to mount binderfs is not giving the user a new instance like tmpfs, devpts, ramfs, and others do. /* past mistakes */ Other pseudo-filesystems once made the same mistakes of giving back the same superblock when actually requesting a new mount (cf. devpts's deprecated "newinstance" option). We should not make the same mistake. Once we've committed to always giving back the same superblock in the same IPC namespace with the next kernel release we will not be able to make that change so better to do it now. /* kdbusfs */ It was pointed out to me that kdbusfs - which is conceptually closely related to binderfs - also allowed users to get a private kdbusfs instance in the same IPC namespace by making each mount of kdbusfs a separate instance. I think that makes a lot of sense. Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit b6c770d7c9dc7185b17d53a9d5ca1278c182d6fa) --- drivers/android/binderfs.c | 41 ++------------------------------------ 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 1ee90e44fc5d..ad3ad2f7f9f4 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -472,7 +472,7 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) struct binderfs_info *info; int ret = -ENOMEM; struct inode *inode = NULL; - struct ipc_namespace *ipc_ns = sb->s_fs_info; + struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; get_ipc_ns(ipc_ns); @@ -547,48 +547,11 @@ err_without_dentry: return ret; } -static int binderfs_test_super(struct super_block *sb, void *data) -{ - struct binderfs_info *info = sb->s_fs_info; - - if (info) - return info->ipc_ns == data; - - return 0; -} - -static int binderfs_set_super(struct super_block *sb, void *data) -{ - sb->s_fs_info = data; - return set_anon_super(sb, NULL); -} - static struct dentry *binderfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - struct super_block *sb; - struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; - - if (!ns_capable(ipc_ns->user_ns, CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); - - sb = sget_userns(fs_type, binderfs_test_super, binderfs_set_super, - flags, ipc_ns->user_ns, ipc_ns); - if (IS_ERR(sb)) - return ERR_CAST(sb); - - if (!sb->s_root) { - int ret = binderfs_fill_super(sb, data, flags & SB_SILENT ? 1 : 0); - if (ret) { - deactivate_locked_super(sb); - return ERR_PTR(ret); - } - - sb->s_flags |= SB_ACTIVE; - } - - return dget(sb->s_root); + return mount_nodev(fs_type, flags, data, binderfs_fill_super); } static void binderfs_kill_super(struct super_block *sb) -- GitLab From 2042150cd85f1e4612ff1c38bc9d58b1d234b7ae Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sat, 12 Jan 2019 01:06:03 +0100 Subject: [PATCH 449/528] binderfs: handle !CONFIG_IPC_NS builds kbuild reported a build faile in [1]. This is triggered when CONFIG_IPC_NS is not set. So let's make the use of init_ipc_ns conditional on CONFIG_IPC_NS being set. [1]: https://lists.01.org/pipermail/kbuild-all/2019-January/056903.html Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 7fefaadd6a962987baac50e7b3c4c3d5ef9b55c6) --- drivers/android/binderfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index ad3ad2f7f9f4..9518e2e7da05 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -129,7 +129,11 @@ static int binderfs_binder_device_create(struct inode *ref_inode, struct inode *inode = NULL; struct super_block *sb = ref_inode->i_sb; struct binderfs_info *info = sb->s_fs_info; +#if defined(CONFIG_IPC_NS) bool use_reserve = (info->ipc_ns == &init_ipc_ns); +#else + bool use_reserve = true; +#endif /* Reserve new minor number for the new device. */ mutex_lock(&binderfs_minors_mutex); -- GitLab From 3de8a7ac901aab4c8e9facb6aa3d4ee87183d7f4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 16 Jan 2019 10:42:59 +0000 Subject: [PATCH 450/528] binderfs: fix error return code in binderfs_fill_super() Fix to return a negative error code -ENOMEM from the new_inode() and d_make_root() error handling cases instead of 0, as done elsewhere in this function. Fixes: 849d540ddfcd ("binderfs: implement "max" mount option") Signed-off-by: Wei Yongjun Reviewed-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 7e7ca7744a539f1a172e3b81c29d000787e3d774) --- drivers/android/binderfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 9518e2e7da05..e4ff4c3fa371 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -518,6 +518,7 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_fs_info = info; + ret = -ENOMEM; inode = new_inode(sb); if (!inode) goto err_without_dentry; -- GitLab From a9a27c6a07aa2b7cc1d101097d4808a84f49027c Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:02 +0100 Subject: [PATCH 451/528] binderfs: remove outdated comment The comment stems from an early version of that patchset and is just confusing now. Cc: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 7c4d08fc4d5aca073bd4ebecbb9eda5e4d858b71) --- drivers/android/binderfs.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index e4ff4c3fa371..898d847f8505 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -373,10 +373,6 @@ static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry, static int binderfs_unlink(struct inode *dir, struct dentry *dentry) { - /* - * The control dentry is only ever touched during mount so checking it - * here should not require us to take lock. - */ if (BINDERFS_I(dir)->control_dentry == dentry) return -EPERM; -- GitLab From 19f56d3a629699ae4e0f6755f04df1d88f6dc5bf Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:03 +0100 Subject: [PATCH 452/528] binderfs: prevent renaming the control dentry - make binderfs control dentry immutable: We don't allow to unlink it since it is crucial for binderfs to be useable but if we allow to rename it we make the unlink trivial to bypass. So prevent renaming too and simply treat the control dentry as immutable. - add is_binderfs_control_device() helper: Take the opportunity and turn the check for the control dentry into a separate helper is_binderfs_control_device() since it's now used in two places. - simplify binderfs_rename(): Instead of hand-rolling our custom version of simple_rename() just dumb the whole function down to first check whether we're trying to rename the control dentry. If we do EPERM the caller and if not call simple_rename(). Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit e98e6fa18636609f14a7f866524950a783cf4fbf) --- drivers/android/binderfs.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 898d847f8505..e73f9dbee099 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -346,34 +346,26 @@ static const struct super_operations binderfs_super_ops = { .statfs = simple_statfs, }; +static inline bool is_binderfs_control_device(const struct dentry *dentry) +{ + struct binderfs_info *info = dentry->d_sb->s_fs_info; + return info->control_dentry == dentry; +} + static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { - struct inode *inode = d_inode(old_dentry); - - /* binderfs doesn't support directories. */ - if (d_is_dir(old_dentry)) + if (is_binderfs_control_device(old_dentry) || + is_binderfs_control_device(new_dentry)) return -EPERM; - if (flags & ~RENAME_NOREPLACE) - return -EINVAL; - - if (!simple_empty(new_dentry)) - return -ENOTEMPTY; - - if (d_really_is_positive(new_dentry)) - simple_unlink(new_dir, new_dentry); - - old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime = - new_dir->i_mtime = inode->i_ctime = current_time(old_dir); - - return 0; + return simple_rename(old_dir, old_dentry, new_dir, new_dentry, flags); } static int binderfs_unlink(struct inode *dir, struct dentry *dentry) { - if (BINDERFS_I(dir)->control_dentry == dentry) + if (is_binderfs_control_device(dentry)) return -EPERM; return simple_unlink(dir, dentry); -- GitLab From c3ff162ae3be1d4c3916b1162d838239189fcce7 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:05 +0100 Subject: [PATCH 453/528] binderfs: rework binderfs_binder_device_create() - switch from d_alloc_name() + d_lookup() to lookup_one_len(): Instead of using d_alloc_name() and then doing a d_lookup() with the allocated dentry to find whether a device with the name we're trying to create already exists switch to using lookup_one_len(). The latter will either return the existing dentry or a new one. - switch from kmalloc() + strscpy() to kmemdup(): Use a more idiomatic way to copy the name for the new dentry that userspace gave us. Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 01b3f1fc568352a1ffdcd3ee82a0297f16cc9bd9) --- drivers/android/binderfs.c | 39 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index e73f9dbee099..0c25ed57bc5f 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -106,7 +107,7 @@ bool is_binderfs_device(const struct inode *inode) * @userp: buffer to copy information about new device for userspace to * @req: struct binderfs_device as copied from userspace * - * This function allocated a new binder_device and reserves a new minor + * This function allocates a new binder_device and reserves a new minor * number for it. * Minor numbers are limited and tracked globally in binderfs_minors. The * function will stash a struct binder_device for the specific binder @@ -122,10 +123,10 @@ static int binderfs_binder_device_create(struct inode *ref_inode, struct binderfs_device *req) { int minor, ret; - struct dentry *dentry, *dup, *root; + struct dentry *dentry, *root; struct binder_device *device; - size_t name_len = BINDERFS_MAX_NAME + 1; char *name = NULL; + size_t name_len; struct inode *inode = NULL; struct super_block *sb = ref_inode->i_sb; struct binderfs_info *info = sb->s_fs_info; @@ -168,12 +169,13 @@ static int binderfs_binder_device_create(struct inode *ref_inode, inode->i_uid = info->root_uid; inode->i_gid = info->root_gid; - name = kmalloc(name_len, GFP_KERNEL); + req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */ + name_len = strlen(req->name); + /* Make sure to include terminating NUL byte */ + name = kmemdup(req->name, name_len + 1, GFP_KERNEL); if (!name) goto err; - strscpy(name, req->name, name_len); - device->binderfs_inode = inode; device->context.binder_context_mgr_uid = INVALID_UID; device->context.name = name; @@ -192,24 +194,21 @@ static int binderfs_binder_device_create(struct inode *ref_inode, root = sb->s_root; inode_lock(d_inode(root)); - dentry = d_alloc_name(root, name); - if (!dentry) { + + /* look it up */ + dentry = lookup_one_len(name, root, name_len); + if (IS_ERR(dentry)) { inode_unlock(d_inode(root)); - ret = -ENOMEM; + ret = PTR_ERR(dentry); goto err; } - /* Verify that the name userspace gave us is not already in use. */ - dup = d_lookup(root, &dentry->d_name); - if (dup) { - if (d_really_is_positive(dup)) { - dput(dup); - dput(dentry); - inode_unlock(d_inode(root)); - ret = -EEXIST; - goto err; - } - dput(dup); + if (d_really_is_positive(dentry)) { + /* already exists */ + dput(dentry); + inode_unlock(d_inode(root)); + ret = -EEXIST; + goto err; } inode->i_private = device; -- GitLab From a20efa4ccae06f1af6766634f6c3fd4ad30f3c36 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:04 +0100 Subject: [PATCH 454/528] binderfs: rework binderfs_fill_super() Al pointed out that on binderfs_fill_super() error deactivate_locked_super() will call binderfs_kill_super() so all of the freeing and putting we currently do in binderfs_fill_super() is unnecessary and buggy. Let's simply return errors and let binderfs_fill_super() take care of cleaning up on error. Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 36975fc3e5f241cc4f45df4ab4624d7d5199d9ed) --- drivers/android/binderfs.c | 41 ++++++++++---------------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 0c25ed57bc5f..1e077498a507 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -460,12 +460,9 @@ static const struct inode_operations binderfs_dir_inode_operations = { static int binderfs_fill_super(struct super_block *sb, void *data, int silent) { + int ret; struct binderfs_info *info; - int ret = -ENOMEM; struct inode *inode = NULL; - struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; - - get_ipc_ns(ipc_ns); sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; @@ -487,15 +484,17 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_op = &binderfs_super_ops; sb->s_time_gran = 1; - info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); - if (!info) - goto err_without_dentry; + sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); + if (!sb->s_fs_info) + return -ENOMEM; + info = sb->s_fs_info; + + info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns); ret = binderfs_parse_mount_opts(data, &info->mount_opts); if (ret) - goto err_without_dentry; + return ret; - info->ipc_ns = ipc_ns; info->root_gid = make_kgid(sb->s_user_ns, 0); if (!gid_valid(info->root_gid)) info->root_gid = GLOBAL_ROOT_GID; @@ -503,12 +502,9 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) if (!uid_valid(info->root_uid)) info->root_uid = GLOBAL_ROOT_UID; - sb->s_fs_info = info; - - ret = -ENOMEM; inode = new_inode(sb); if (!inode) - goto err_without_dentry; + return -ENOMEM; inode->i_ino = FIRST_INODE; inode->i_fop = &simple_dir_operations; @@ -519,24 +515,9 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_root = d_make_root(inode); if (!sb->s_root) - goto err_without_dentry; - - ret = binderfs_binder_ctl_create(sb); - if (ret) - goto err_with_dentry; - - return 0; - -err_with_dentry: - dput(sb->s_root); - sb->s_root = NULL; - -err_without_dentry: - put_ipc_ns(ipc_ns); - iput(inode); - kfree(info); + return -ENOMEM; - return ret; + return binderfs_binder_ctl_create(sb); } static struct dentry *binderfs_mount(struct file_system_type *fs_type, -- GitLab From 0987b78be1f547bb9ad8de4f2167628709d44483 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:06 +0100 Subject: [PATCH 455/528] binderfs: kill_litter_super() before cleanup Al pointed out that first calling kill_litter_super() before cleaning up info is more correct since destroying info doesn't depend on the state of the dentries and inodes. That the opposite remains true is not guaranteed. Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 4198479524aeccaf53c3a4cc73784982535573fa) --- drivers/android/binderfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 1e077498a507..ba88be172aee 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -531,11 +531,12 @@ static void binderfs_kill_super(struct super_block *sb) { struct binderfs_info *info = sb->s_fs_info; + kill_litter_super(sb); + if (info && info->ipc_ns) put_ipc_ns(info->ipc_ns); kfree(info); - kill_litter_super(sb); } static struct file_system_type binder_fs_type = { -- GitLab From 10b4f187ca00276e364a88f57dc6d88415ac23ec Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:07 +0100 Subject: [PATCH 456/528] binderfs: drop lock in binderfs_binder_ctl_create The binderfs_binder_ctl_create() call is a no-op on subsequent calls and the first call is done before we unlock the suberblock. Hence, there is no need to take inode_lock() in there. Let's remove it. Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 29ef1c8e16aed079ac09989d752e38d412b6e1a8) --- drivers/android/binderfs.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index ba88be172aee..d537dcdb5d65 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -400,8 +400,6 @@ static int binderfs_binder_ctl_create(struct super_block *sb) if (!device) return -ENOMEM; - inode_lock(d_inode(root)); - /* If we have already created a binder-control node, return. */ if (info->control_dentry) { ret = 0; @@ -440,12 +438,10 @@ static int binderfs_binder_ctl_create(struct super_block *sb) inode->i_private = device; info->control_dentry = dentry; d_add(dentry, inode); - inode_unlock(d_inode(root)); return 0; out: - inode_unlock(d_inode(root)); kfree(device); iput(inode); -- GitLab From 441596f10c0457855e994b8f93485eaab860d8a9 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:08 +0100 Subject: [PATCH 457/528] binderfs: switch from d_add() to d_instantiate() In a previous commit we switched from a d_alloc_name() + d_lookup() combination to setup a new dentry and find potential duplicates to the more idiomatic lookup_one_len(). As far as I understand, this also means we need to switch from d_add() to d_instantiate() since lookup_one_len() will create a new dentry when it doesn't find an existing one and add the new dentry to the hash queues. So we only need to call d_instantiate() to connect the dentry to the inode and turn it into a positive dentry. If we were to use d_add() we sure see stack traces like the following indicating that adding the same dentry twice over the same inode: [ 744.441889] CPU: 4 PID: 2849 Comm: landscape-sysin Not tainted 5.0.0-rc1-brauner-binderfs #243 [ 744.441889] Hardware name: Dell DCS XS24-SC2 /XS24-SC2 , BIOS S59_3C20 04/07/2011 [ 744.441889] RIP: 0010:__d_lookup_rcu+0x76/0x190 [ 744.441889] Code: 89 75 c0 49 c1 e9 20 49 89 fd 45 89 ce 41 83 e6 07 42 8d 04 f5 00 00 00 00 89 45 c8 eb 0c 48 8b 1b 48 85 db 0f 84 81 00 00 00 <44> 8b 63 fc 4c 3b 6b 10 75 ea 48 83 7b 08 00 74 e3 41 83 e4 fe 41 [ 744.441889] RSP: 0018:ffffb8c984e27ad0 EFLAGS: 00000282 ORIG_RAX: ffffffffffffff13 [ 744.441889] RAX: 0000000000000038 RBX: ffff9407ef770c08 RCX: ffffb8c980011000 [ 744.441889] RDX: ffffb8c984e27b54 RSI: ffffb8c984e27ce0 RDI: ffff9407e6689600 [ 744.441889] RBP: ffffb8c984e27b28 R08: ffffb8c984e27ba4 R09: 0000000000000007 [ 744.441889] R10: ffff9407e5c4f05c R11: 973f3eb9d84a94e5 R12: 0000000000000002 [ 744.441889] R13: ffff9407e6689600 R14: 0000000000000007 R15: 00000007bfef7a13 [ 744.441889] FS: 00007f0db13bb740(0000) GS:ffff9407f3b00000(0000) knlGS:0000000000000000 [ 744.441889] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 744.441889] CR2: 00007f0dacc51024 CR3: 000000032961a000 CR4: 00000000000006e0 [ 744.441889] Call Trace: [ 744.441889] lookup_fast+0x53/0x300 [ 744.441889] walk_component+0x49/0x350 [ 744.441889] ? inode_permission+0x63/0x1a0 [ 744.441889] link_path_walk.part.33+0x1bc/0x5a0 [ 744.441889] ? path_init+0x190/0x310 [ 744.441889] path_lookupat+0x95/0x210 [ 744.441889] filename_lookup+0xb6/0x190 [ 744.441889] ? __check_object_size+0xb8/0x1b0 [ 744.441889] ? strncpy_from_user+0x50/0x1a0 [ 744.441889] user_path_at_empty+0x36/0x40 [ 744.441889] ? user_path_at_empty+0x36/0x40 [ 744.441889] vfs_statx+0x76/0xe0 [ 744.441889] __do_sys_newstat+0x3d/0x70 [ 744.441889] __x64_sys_newstat+0x16/0x20 [ 744.441889] do_syscall_64+0x5a/0x120 [ 744.441889] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 744.441889] RIP: 0033:0x7f0db0ec2775 [ 744.441889] Code: 00 00 00 75 05 48 83 c4 18 c3 e8 26 55 02 00 66 0f 1f 44 00 00 83 ff 01 48 89 f0 77 30 48 89 c7 48 89 d6 b8 04 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 03 f3 c3 90 48 8b 15 e1 b6 2d 00 f7 d8 64 89 [ 744.441889] RSP: 002b:00007ffc36bc9388 EFLAGS: 00000246 ORIG_RAX: 0000000000000004 [ 744.441889] RAX: ffffffffffffffda RBX: 00007ffc36bc9300 RCX: 00007f0db0ec2775 [ 744.441889] RDX: 00007ffc36bc9400 RSI: 00007ffc36bc9400 RDI: 00007f0dad26f050 [ 744.441889] RBP: 0000000000c0bc60 R08: 0000000000000000 R09: 0000000000000001 [ 744.441889] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffc36bc9400 [ 744.441889] R13: 0000000000000001 R14: 00000000ffffff9c R15: 0000000000c0bc60 Cc: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 01684db950ea2b840531ab9298a8785776b6f6e8) --- drivers/android/binderfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index d537dcdb5d65..6a2185eb66c5 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -212,7 +212,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode, } inode->i_private = device; - d_add(dentry, inode); + d_instantiate(dentry, inode); fsnotify_create(root->d_inode, dentry); inode_unlock(d_inode(root)); -- GitLab From a269303e6d515658e65807e182066a769d82844a Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 23 Jan 2019 12:41:15 +0100 Subject: [PATCH 458/528] binderfs: respect limit on binder control creation We currently adhere to the reserved devices limit when creating new binderfs devices in binderfs instances not located in the inital ipc namespace. But it is still possible to rob the host instances of their 4 reserved devices by creating the maximum allowed number of devices in a single binderfs instance located in a non-initial ipc namespace and then mounting 4 separate binderfs instances in non-initial ipc namespaces. That happens because the limit is currently not respected for the creation of the initial binder-control device node. Block this nonsense by performing the same check in binderfs_binder_ctl_create() that we perform in binderfs_binder_device_create(). Fixes: 36bdf3cae09d ("binderfs: reserve devices for initial mount") Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman (cherry picked from commit da8ddba566ff0a883237dbc8c5dadef1ca769e19) --- drivers/android/binderfs.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 6a2185eb66c5..7a550104a722 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -395,6 +395,11 @@ static int binderfs_binder_ctl_create(struct super_block *sb) struct inode *inode = NULL; struct dentry *root = sb->s_root; struct binderfs_info *info = sb->s_fs_info; +#if defined(CONFIG_IPC_NS) + bool use_reserve = (info->ipc_ns == &init_ipc_ns); +#else + bool use_reserve = true; +#endif device = kzalloc(sizeof(*device), GFP_KERNEL); if (!device) @@ -413,7 +418,10 @@ static int binderfs_binder_ctl_create(struct super_block *sb) /* Reserve a new minor number for the new device. */ mutex_lock(&binderfs_minors_mutex); - minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, GFP_KERNEL); + minor = ida_alloc_max(&binderfs_minors, + use_reserve ? BINDERFS_MAX_MINOR : + BINDERFS_MAX_MINOR_CAPPED, + GFP_KERNEL); mutex_unlock(&binderfs_minors_mutex); if (minor < 0) { ret = minor; -- GitLab From ec78c0c02d81e079577a20d308b9355dbcc1cf44 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Wed, 4 Sep 2019 13:07:04 +0200 Subject: [PATCH 459/528] binder: Validate the default binderfs device names. Length of a binderfs device name cannot exceed BINDERFS_MAX_NAME. This patch adds a check in binderfs_init() to ensure the same for the default binder devices that will be created in every binderfs instance. Co-developed-by: Christian Brauner Signed-off-by: Christian Brauner Signed-off-by: Hridya Valsaraju Reviewed-by: Joel Fernandes (Google) Link: https://lore.kernel.org/r/20190808222727.132744-3-hridya@google.com Link: https://lore.kernel.org/r/20190904110704.8606-3-christian.brauner@ubuntu.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 028fb5822b76bc2e095b5c145d7bd263878d9e27) --- drivers/android/binderfs.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 7a550104a722..3ff774e351ac 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -553,6 +553,18 @@ static struct file_system_type binder_fs_type = { static int __init init_binderfs(void) { int ret; + const char *name; + size_t len; + + /* Verify that the default binderfs device names are valid. */ + name = binder_devices_param; + for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { + if (len > BINDERFS_MAX_NAME) + return -E2BIG; + name += len; + if (*name == ',') + name++; + } /* Allocate new major number for binderfs. */ ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR, -- GitLab From f88eb5dddc111c4750aa7118a30a120dfe1ff82b Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Tue, 3 Sep 2019 09:16:52 -0700 Subject: [PATCH 460/528] binder: add a mount option to show global stats Currently, all binder state and statistics live in debugfs. We need this information even when debugfs is not mounted. This patch adds the mount option 'stats' to enable a binderfs instance to have binder debug information present in the same. 'stats=global' will enable the global binder statistics. In the future, 'stats=local' will enable binder statistics local to the binderfs instance. The two modes 'global' and 'local' will be mutually exclusive. 'stats=global' option is only available for a binderfs instance mounted in the initial user namespace. An attempt to use the option to mount a binderfs instance in another user namespace will return an EPERM error. Signed-off-by: Hridya Valsaraju Acked-by: Christian Brauner Link: https://lore.kernel.org/r/20190903161655.107408-2-hridya@google.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit f00834518ed3194b866f5f3d63b71e0ed7f6bc00) --- drivers/android/binderfs.c | 45 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 3ff774e351ac..ae1c2dac4e1a 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -51,18 +51,27 @@ static DEFINE_IDA(binderfs_minors); /** * binderfs_mount_opts - mount options for binderfs * @max: maximum number of allocatable binderfs binder devices + * @stats_mode: enable binder stats in binderfs. */ struct binderfs_mount_opts { int max; + int stats_mode; }; enum { Opt_max, + Opt_stats_mode, Opt_err }; +enum binderfs_stats_mode { + STATS_NONE, + STATS_GLOBAL, +}; + static const match_table_t tokens = { { Opt_max, "max=%d" }, + { Opt_stats_mode, "stats=%s" }, { Opt_err, NULL } }; @@ -291,8 +300,9 @@ static void binderfs_evict_inode(struct inode *inode) static int binderfs_parse_mount_opts(char *data, struct binderfs_mount_opts *opts) { - char *p; + char *p, *stats; opts->max = BINDERFS_MAX_MINOR; + opts->stats_mode = STATS_NONE; while ((p = strsep(&data, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -312,6 +322,22 @@ static int binderfs_parse_mount_opts(char *data, opts->max = max_devices; break; + case Opt_stats_mode: + if (!capable(CAP_SYS_ADMIN)) + return -EINVAL; + + stats = match_strdup(&args[0]); + if (!stats) + return -ENOMEM; + + if (strcmp(stats, "global") != 0) { + kfree(stats); + return -EINVAL; + } + + opts->stats_mode = STATS_GLOBAL; + kfree(stats); + break; default: pr_err("Invalid mount options\n"); return -EINVAL; @@ -323,8 +349,21 @@ static int binderfs_parse_mount_opts(char *data, static int binderfs_remount(struct super_block *sb, int *flags, char *data) { + int prev_stats_mode, ret; struct binderfs_info *info = sb->s_fs_info; - return binderfs_parse_mount_opts(data, &info->mount_opts); + + prev_stats_mode = info->mount_opts.stats_mode; + ret = binderfs_parse_mount_opts(data, &info->mount_opts); + if (ret) + return ret; + + if (prev_stats_mode != info->mount_opts.stats_mode) { + pr_err("Binderfs stats mode cannot be changed during a remount\n"); + info->mount_opts.stats_mode = prev_stats_mode; + return -EINVAL; + } + + return 0; } static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root) @@ -334,6 +373,8 @@ static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root) info = root->d_sb->s_fs_info; if (info->mount_opts.max <= BINDERFS_MAX_MINOR) seq_printf(seq, ",max=%d", info->mount_opts.max); + if (info->mount_opts.stats_mode == STATS_GLOBAL) + seq_printf(seq, ",stats=global"); return 0; } -- GitLab From 7d4ea3d7b537b6e8b0cfac772790725bd6817bfa Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Tue, 3 Sep 2019 09:16:53 -0700 Subject: [PATCH 461/528] binder: Add stats, state and transactions files The following binder stat files currently live in debugfs. /sys/kernel/debug/binder/state /sys/kernel/debug/binder/stats /sys/kernel/debug/binder/transactions This patch makes these files available in a binderfs instance mounted with the mount option 'stats=global'. For example, if a binderfs instance is mounted at path /dev/binderfs, the above files will be available at the following locations: /dev/binderfs/binder_logs/state /dev/binderfs/binder_logs/stats /dev/binderfs/binder_logs/transactions This provides a way to access them even when debugfs is not mounted. Acked-by: Christian Brauner Signed-off-by: Hridya Valsaraju Acked-by: Christian Brauner Link: https://lore.kernel.org/r/20190903161655.107408-3-hridya@google.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 0e13e452dafc009049a9a5a4153e2f9e51b23915) --- drivers/android/binder.c | 9 +- drivers/android/binder_internal.h | 17 ++++ drivers/android/binderfs.c | 158 +++++++++++++++++++++++++++++- 3 files changed, 176 insertions(+), 8 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 4237899c86d5..46d13601b93e 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -6008,7 +6008,7 @@ static void print_binder_proc_stats(struct seq_file *m, } -static int binder_state_show(struct seq_file *m, void *unused) +int binder_state_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct binder_node *node; @@ -6047,7 +6047,7 @@ static int binder_state_show(struct seq_file *m, void *unused) return 0; } -static int binder_stats_show(struct seq_file *m, void *unused) +int binder_stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; @@ -6063,7 +6063,7 @@ static int binder_stats_show(struct seq_file *m, void *unused) return 0; } -static int binder_transactions_show(struct seq_file *m, void *unused) +int binder_transactions_show(struct seq_file *m, void *unused) { struct binder_proc *proc; @@ -6151,9 +6151,6 @@ const struct file_operations binder_fops = { .release = binder_release, }; -BINDER_DEBUG_ENTRY(state); -BINDER_DEBUG_ENTRY(stats); -BINDER_DEBUG_ENTRY(transactions); BINDER_DEBUG_ENTRY(transaction_log); static int __init init_binder_device(const char *name) diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 7fb97f503ef2..9709302f2634 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -46,4 +46,21 @@ static inline bool is_binderfs_device(const struct inode *inode) } #endif +#ifdef CONFIG_ANDROID_BINDERFS +extern int __init init_binderfs(void); +#else +static inline int __init init_binderfs(void) +{ + return 0; +} +#endif + +int binder_stats_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_stats); + +int binder_state_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_state); + +int binder_transactions_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_transactions); #endif /* _LINUX_BINDER_INTERNAL_H */ diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index ae1c2dac4e1a..c388df02e529 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -281,7 +281,7 @@ static void binderfs_evict_inode(struct inode *inode) clear_inode(inode); - if (!device) + if (!S_ISCHR(inode->i_mode) || !device) return; mutex_lock(&binderfs_minors_mutex); @@ -503,6 +503,141 @@ static const struct inode_operations binderfs_dir_inode_operations = { .unlink = binderfs_unlink, }; +static struct inode *binderfs_make_inode(struct super_block *sb, int mode) +{ + struct inode *ret; + + ret = new_inode(sb); + if (ret) { + ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET); + ret->i_mode = mode; + ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret); + } + return ret; +} + +static struct dentry *binderfs_create_dentry(struct dentry *parent, + const char *name) +{ + struct dentry *dentry; + + dentry = lookup_one_len(name, parent, strlen(name)); + if (IS_ERR(dentry)) + return dentry; + + /* Return error if the file/dir already exists. */ + if (d_really_is_positive(dentry)) { + dput(dentry); + return ERR_PTR(-EEXIST); + } + + return dentry; +} + +static struct dentry *binderfs_create_file(struct dentry *parent, + const char *name, + const struct file_operations *fops, + void *data) +{ + struct dentry *dentry; + struct inode *new_inode, *parent_inode; + struct super_block *sb; + + parent_inode = d_inode(parent); + inode_lock(parent_inode); + + dentry = binderfs_create_dentry(parent, name); + if (IS_ERR(dentry)) + goto out; + + sb = parent_inode->i_sb; + new_inode = binderfs_make_inode(sb, S_IFREG | 0444); + if (!new_inode) { + dput(dentry); + dentry = ERR_PTR(-ENOMEM); + goto out; + } + + new_inode->i_fop = fops; + new_inode->i_private = data; + d_instantiate(dentry, new_inode); + fsnotify_create(parent_inode, dentry); + +out: + inode_unlock(parent_inode); + return dentry; +} + +static struct dentry *binderfs_create_dir(struct dentry *parent, + const char *name) +{ + struct dentry *dentry; + struct inode *new_inode, *parent_inode; + struct super_block *sb; + + parent_inode = d_inode(parent); + inode_lock(parent_inode); + + dentry = binderfs_create_dentry(parent, name); + if (IS_ERR(dentry)) + goto out; + + sb = parent_inode->i_sb; + new_inode = binderfs_make_inode(sb, S_IFDIR | 0755); + if (!new_inode) { + dput(dentry); + dentry = ERR_PTR(-ENOMEM); + goto out; + } + + new_inode->i_fop = &simple_dir_operations; + new_inode->i_op = &simple_dir_inode_operations; + + set_nlink(new_inode, 2); + d_instantiate(dentry, new_inode); + inc_nlink(parent_inode); + fsnotify_mkdir(parent_inode, dentry); + +out: + inode_unlock(parent_inode); + return dentry; +} + +static int init_binder_logs(struct super_block *sb) +{ + struct dentry *binder_logs_root_dir, *dentry; + int ret = 0; + + binder_logs_root_dir = binderfs_create_dir(sb->s_root, + "binder_logs"); + if (IS_ERR(binder_logs_root_dir)) { + ret = PTR_ERR(binder_logs_root_dir); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, "stats", + &binder_stats_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, "state", + &binder_state_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, "transactions", + &binder_transactions_fops, NULL); + if (IS_ERR(dentry)) + ret = PTR_ERR(dentry); + +out: + return ret; +} + static int binderfs_fill_super(struct super_block *sb, void *data, int silent) { int ret; @@ -562,7 +697,26 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) if (!sb->s_root) return -ENOMEM; - return binderfs_binder_ctl_create(sb); + ret = binderfs_binder_ctl_create(sb); + if (ret) + return ret; + + name = binder_devices_param; + for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { + strscpy(device_info.name, name, len + 1); + ret = binderfs_binder_device_create(inode, NULL, &device_info); + if (ret) + return ret; + name += len; + if (*name == ',') + name++; + } + + if (info->mount_opts.stats_mode == STATS_GLOBAL) + return init_binder_logs(sb); + + return 0; +>>>>>>> 0e13e452dafc (binder: Add stats, state and transactions files) } static struct dentry *binderfs_mount(struct file_system_type *fs_type, -- GitLab From 29f5b66c03b5079afe8a23d01cfb6c4a499551b8 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Tue, 3 Sep 2019 09:16:54 -0700 Subject: [PATCH 462/528] binder: Make transaction_log available in binderfs Currently, the binder transaction log files 'transaction_log' and 'failed_transaction_log' live in debugfs at the following locations: /sys/kernel/debug/binder/failed_transaction_log /sys/kernel/debug/binder/transaction_log This patch makes these files also available in a binderfs instance mounted with the mount option "stats=global". It does not affect the presence of these files in debugfs. If a binderfs instance is mounted at path /dev/binderfs, the location of these files will be as follows: /dev/binderfs/binder_logs/failed_transaction_log /dev/binderfs/binder_logs/transaction_log This change provides an alternate option to access these files when debugfs is not mounted. Acked-by: Christian Brauner Signed-off-by: Hridya Valsaraju Link: https://lore.kernel.org/r/20190903161655.107408-4-hridya@google.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 03e2e07e38147917482d595ad3cf193212ded8ac) --- drivers/android/binder.c | 30 +++--------------------------- drivers/android/binder_internal.h | 30 ++++++++++++++++++++++++++++++ drivers/android/binderfs.c | 18 ++++++++++++++++++ 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 46d13601b93e..3ec82ab07638 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -222,30 +222,8 @@ static inline void binder_stats_created(enum binder_stat_types type) atomic_inc(&binder_stats.obj_created[type]); } -struct binder_transaction_log_entry { - int debug_id; - int debug_id_done; - int call_type; - int from_proc; - int from_thread; - int target_handle; - int to_proc; - int to_thread; - int to_node; - int data_size; - int offsets_size; - int return_error_line; - uint32_t return_error; - uint32_t return_error_param; - const char *context_name; -}; -struct binder_transaction_log { - atomic_t cur; - bool full; - struct binder_transaction_log_entry entry[32]; -}; -static struct binder_transaction_log binder_transaction_log; -static struct binder_transaction_log binder_transaction_log_failed; +struct binder_transaction_log binder_transaction_log; +struct binder_transaction_log binder_transaction_log_failed; static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) @@ -6119,7 +6097,7 @@ static void print_binder_transaction_log_entry(struct seq_file *m, "\n" : " (incomplete)\n"); } -static int binder_transaction_log_show(struct seq_file *m, void *unused) +int binder_transaction_log_show(struct seq_file *m, void *unused) { struct binder_transaction_log *log = m->private; unsigned int log_cur = atomic_read(&log->cur); @@ -6151,8 +6129,6 @@ const struct file_operations binder_fops = { .release = binder_release, }; -BINDER_DEBUG_ENTRY(transaction_log); - static int __init init_binder_device(const char *name) { int ret; diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 9709302f2634..048e0df232f8 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -63,4 +63,34 @@ DEFINE_SHOW_ATTRIBUTE(binder_state); int binder_transactions_show(struct seq_file *m, void *unused); DEFINE_SHOW_ATTRIBUTE(binder_transactions); + +int binder_transaction_log_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_transaction_log); + +struct binder_transaction_log_entry { + int debug_id; + int debug_id_done; + int call_type; + int from_proc; + int from_thread; + int target_handle; + int to_proc; + int to_thread; + int to_node; + int data_size; + int offsets_size; + int return_error_line; + uint32_t return_error; + uint32_t return_error_param; + const char *context_name; +}; + +struct binder_transaction_log { + atomic_t cur; + bool full; + struct binder_transaction_log_entry entry[32]; +}; + +extern struct binder_transaction_log binder_transaction_log; +extern struct binder_transaction_log binder_transaction_log_failed; #endif /* _LINUX_BINDER_INTERNAL_H */ diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index c388df02e529..281f58230e27 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -631,6 +631,24 @@ static int init_binder_logs(struct super_block *sb) dentry = binderfs_create_file(binder_logs_root_dir, "transactions", &binder_transactions_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, + "transaction_log", + &binder_transaction_log_fops, + &binder_transaction_log); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, + "failed_transaction_log", + &binder_transaction_log_fops, + &binder_transaction_log_failed); if (IS_ERR(dentry)) ret = PTR_ERR(dentry); -- GitLab From 587e3031c01f780af07e6e1f9761febd9985a9d4 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Tue, 3 Sep 2019 09:16:55 -0700 Subject: [PATCH 463/528] binder: Add binder_proc logging to binderfs Currently /sys/kernel/debug/binder/proc contains the debug data for every binder_proc instance. This patch makes this information also available in a binderfs instance mounted with a mount option "stats=global" in addition to debugfs. The patch does not affect the presence of the file in debugfs. If a binderfs instance is mounted at path /dev/binderfs, this file would be present at /dev/binderfs/binder_logs/proc. This change provides an alternate way to access this file when debugfs is not mounted. Acked-by: Christian Brauner Signed-off-by: Hridya Valsaraju Link: https://lore.kernel.org/r/20190903161655.107408-5-hridya@google.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 4feb80faf428a02d407a9ea1952004af01308765) --- drivers/android/binder.c | 46 ++++++++++++++++++++- drivers/android/binder_internal.h | 46 +++++++++++++++++++++ drivers/android/binderfs.c | 68 ++++++++++++++----------------- 3 files changed, 121 insertions(+), 39 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 3ec82ab07638..5b2cd7ecdf0d 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -521,6 +521,7 @@ struct binder_priority { * @inner_lock: can nest under outer_lock and/or node lock * @outer_lock: no nesting under innor or node lock * Lock order: 1) outer, 2) node, 3) inner + * @binderfs_entry: process-specific binderfs log file * * Bookkeeping structure for binder processes */ @@ -557,6 +558,7 @@ struct binder_proc { struct binder_context *context; spinlock_t inner_lock; spinlock_t outer_lock; + struct dentry *binderfs_entry; }; enum { @@ -5279,6 +5281,8 @@ static int binder_open(struct inode *nodp, struct file *filp) { struct binder_proc *proc; struct binder_device *binder_dev; + struct binderfs_info *info; + struct dentry *binder_binderfs_dir_entry_proc = NULL; binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__, current->group_leader->pid, current->pid); @@ -5304,11 +5308,14 @@ static int binder_open(struct inode *nodp, struct file *filp) proc->default_priority = task_nice(current); /* binderfs stashes devices in i_private */ - if (is_binderfs_device(nodp)) + if (is_binderfs_device(nodp)) { binder_dev = nodp->i_private; - else + info = nodp->i_sb->s_fs_info; + binder_binderfs_dir_entry_proc = info->proc_log_dir; + } else { binder_dev = container_of(filp->private_data, struct binder_device, miscdev); + } proc->context = &binder_dev->context; binder_alloc_init(&proc->alloc); @@ -5339,6 +5346,35 @@ static int binder_open(struct inode *nodp, struct file *filp) &binder_proc_fops); } + if (binder_binderfs_dir_entry_proc) { + char strbuf[11]; + struct dentry *binderfs_entry; + + snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); + /* + * Similar to debugfs, the process specific log file is shared + * between contexts. If the file has already been created for a + * process, the following binderfs_create_file() call will + * fail with error code EEXIST if another context of the same + * process invoked binder_open(). This is ok since same as + * debugfs, the log file will contain information on all + * contexts of a given PID. + */ + binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc, + strbuf, &proc_fops, (void *)(unsigned long)proc->pid); + if (!IS_ERR(binderfs_entry)) { + proc->binderfs_entry = binderfs_entry; + } else { + int error; + + error = PTR_ERR(binderfs_entry); + if (error != -EEXIST) { + pr_warn("Unable to create file %s in binderfs (error %d)\n", + strbuf, error); + } + } + } + return 0; } @@ -5378,6 +5414,12 @@ static int binder_release(struct inode *nodp, struct file *filp) struct binder_proc *proc = filp->private_data; debugfs_remove(proc->debugfs_entry); + + if (proc->binderfs_entry) { + binderfs_remove_file(proc->binderfs_entry); + proc->binderfs_entry = NULL; + } + binder_defer_work(proc, BINDER_DEFERRED_RELEASE); return 0; diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 048e0df232f8..5e3b7dc67fd3 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -35,15 +35,61 @@ struct binder_device { struct inode *binderfs_inode; }; +/** + * binderfs_mount_opts - mount options for binderfs + * @max: maximum number of allocatable binderfs binder devices + * @stats_mode: enable binder stats in binderfs. + */ +struct binderfs_mount_opts { + int max; + int stats_mode; +}; + +/** + * binderfs_info - information about a binderfs mount + * @ipc_ns: The ipc namespace the binderfs mount belongs to. + * @control_dentry: This records the dentry of this binderfs mount + * binder-control device. + * @root_uid: uid that needs to be used when a new binder device is + * created. + * @root_gid: gid that needs to be used when a new binder device is + * created. + * @mount_opts: The mount options in use. + * @device_count: The current number of allocated binder devices. + * @proc_log_dir: Pointer to the directory dentry containing process-specific + * logs. + */ +struct binderfs_info { + struct ipc_namespace *ipc_ns; + struct dentry *control_dentry; + kuid_t root_uid; + kgid_t root_gid; + struct binderfs_mount_opts mount_opts; + int device_count; + struct dentry *proc_log_dir; +}; + extern const struct file_operations binder_fops; #ifdef CONFIG_ANDROID_BINDERFS extern bool is_binderfs_device(const struct inode *inode); +extern struct dentry *binderfs_create_file(struct dentry *dir, const char *name, + const struct file_operations *fops, + void *data); +extern void binderfs_remove_file(struct dentry *dentry); #else static inline bool is_binderfs_device(const struct inode *inode) { return false; } +static inline struct dentry *binderfs_create_file(struct dentry *dir, + const char *name, + const struct file_operations *fops, + void *data) +{ + return NULL; +} +static inline void binderfs_remove_file(struct dentry *dentry) {} #endif #ifdef CONFIG_ANDROID_BINDERFS diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 281f58230e27..4328e7e52aa4 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -48,16 +48,6 @@ static dev_t binderfs_dev; static DEFINE_MUTEX(binderfs_minors_mutex); static DEFINE_IDA(binderfs_minors); -/** - * binderfs_mount_opts - mount options for binderfs - * @max: maximum number of allocatable binderfs binder devices - * @stats_mode: enable binder stats in binderfs. - */ -struct binderfs_mount_opts { - int max; - int stats_mode; -}; - enum { Opt_max, Opt_stats_mode, @@ -75,27 +65,6 @@ static const match_table_t tokens = { { Opt_err, NULL } }; -/** - * binderfs_info - information about a binderfs mount - * @ipc_ns: The ipc namespace the binderfs mount belongs to. - * @control_dentry: This records the dentry of this binderfs mount - * binder-control device. - * @root_uid: uid that needs to be used when a new binder device is - * created. - * @root_gid: gid that needs to be used when a new binder device is - * created. - * @mount_opts: The mount options in use. - * @device_count: The current number of allocated binder devices. - */ -struct binderfs_info { - struct ipc_namespace *ipc_ns; - struct dentry *control_dentry; - kuid_t root_uid; - kgid_t root_gid; - struct binderfs_mount_opts mount_opts; - int device_count; -}; - static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) { return inode->i_sb->s_fs_info; @@ -534,10 +503,24 @@ static struct dentry *binderfs_create_dentry(struct dentry *parent, return dentry; } -static struct dentry *binderfs_create_file(struct dentry *parent, - const char *name, - const struct file_operations *fops, - void *data) +void binderfs_remove_file(struct dentry *dentry) +{ + struct inode *parent_inode; + + parent_inode = d_inode(dentry->d_parent); + inode_lock(parent_inode); + if (simple_positive(dentry)) { + dget(dentry); + simple_unlink(parent_inode, dentry); + d_delete(dentry); + dput(dentry); + } + inode_unlock(parent_inode); +} + +struct dentry *binderfs_create_file(struct dentry *parent, const char *name, + const struct file_operations *fops, + void *data) { struct dentry *dentry; struct inode *new_inode, *parent_inode; @@ -605,7 +588,8 @@ out: static int init_binder_logs(struct super_block *sb) { - struct dentry *binder_logs_root_dir, *dentry; + struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir; + struct binderfs_info *info; int ret = 0; binder_logs_root_dir = binderfs_create_dir(sb->s_root, @@ -649,8 +633,18 @@ static int init_binder_logs(struct super_block *sb) "failed_transaction_log", &binder_transaction_log_fops, &binder_transaction_log_failed); - if (IS_ERR(dentry)) + if (IS_ERR(dentry)) { ret = PTR_ERR(dentry); + goto out; + } + + proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc"); + if (IS_ERR(proc_log_dir)) { + ret = PTR_ERR(proc_log_dir); + goto out; + } + info = sb->s_fs_info; + info->proc_log_dir = proc_log_dir; out: return ret; -- GitLab From 413892a08305b946633bb433e7ec33c51b6949db Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 3 Mar 2020 17:43:40 +0100 Subject: [PATCH 464/528] binder: prevent UAF for binderfs devices II This is a necessary follow up to the first fix I proposed and we merged in 2669b8b0c79 ("binder: prevent UAF for binderfs devices"). I have been overly optimistic that the simple fix I proposed would work. But alas, ihold() + iput() won't work since the inodes won't survive the destruction of the superblock. So all we get with my prior fix is a different race with a tinier race-window but it doesn't solve the issue. Fwiw, the problem lies with generic_shutdown_super(). It even has this cozy Al-style comment: if (!list_empty(&sb->s_inodes)) { printk("VFS: Busy inodes after unmount of %s. " "Self-destruct in 5 seconds. Have a nice day...\n", sb->s_id); } On binder_release(), binder_defer_work(proc, BINDER_DEFERRED_RELEASE) is called which punts the actual cleanup operation to a workqueue. At some point, binder_deferred_func() will be called which will end up calling binder_deferred_release() which will retrieve and cleanup the binder_context attach to this struct binder_proc. If we trace back where this binder_context is attached to binder_proc we see that it is set in binder_open() and is taken from the struct binder_device it is associated with. This obviously assumes that the struct binder_device that context is attached to is _never_ freed. While that might be true for devtmpfs binder devices it is most certainly wrong for binderfs binder devices. So, assume binder_open() is called on a binderfs binder devices. We now stash away the struct binder_context associated with that struct binder_devices: proc->context = &binder_dev->context; /* binderfs stashes devices in i_private */ if (is_binderfs_device(nodp)) { binder_dev = nodp->i_private; info = nodp->i_sb->s_fs_info; binder_binderfs_dir_entry_proc = info->proc_log_dir; } else { . . . proc->context = &binder_dev->context; Now let's assume that the binderfs instance for that binder devices is shutdown via umount() and/or the mount namespace associated with it goes away. As long as there is still an fd open for that binderfs binder device things are fine. But let's assume we now close the last fd for that binderfs binder device. Now binder_release() is called and punts to the workqueue. Assume that the workqueue has quite a bit of stuff to do and doesn't get to cleaning up the struct binder_proc and the associated struct binder_context with it for that binderfs binder device right away. In the meantime, the VFS is killing the super block and is ultimately calling sb->evict_inode() which means it will call binderfs_evict_inode() which does: static void binderfs_evict_inode(struct inode *inode) { struct binder_device *device = inode->i_private; struct binderfs_info *info = BINDERFS_I(inode); clear_inode(inode); if (!S_ISCHR(inode->i_mode) || !device) return; mutex_lock(&binderfs_minors_mutex); --info->device_count; ida_free(&binderfs_minors, device->miscdev.minor); mutex_unlock(&binderfs_minors_mutex); kfree(device->context.name); kfree(device); } thereby freeing the struct binder_device including struct binder_context. Now the workqueue finally has time to get around to cleaning up struct binder_proc and is now trying to access the associate struct binder_context. Since it's already freed it will OOPs. Fix this by introducing a refounct on binder devices. This is an alternative fix to 51d8a7eca677 ("binder: prevent UAF read in print_binder_transaction_log_entry()"). Fixes: 3ad20fe393b3 ("binder: implement binderfs") Fixes: 2669b8b0c798 ("binder: prevent UAF for binderfs devices") Fixes: 03e2e07e3814 ("binder: Make transaction_log available in binderfs") Related : 51d8a7eca677 ("binder: prevent UAF read in print_binder_transaction_log_entry()") Cc: stable@vger.kernel.org Signed-off-by: Christian Brauner Acked-by: Todd Kjos Link: https://lore.kernel.org/r/20200303164340.670054-1-christian.brauner@ubuntu.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit f0fe2c0f050d31babcad7d65f1d550d462a40064) --- drivers/android/binder.c | 8 ++++++++ drivers/android/binder_internal.h | 2 ++ drivers/android/binderfs.c | 7 +++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 5b2cd7ecdf0d..4757befdc284 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5316,6 +5316,7 @@ static int binder_open(struct inode *nodp, struct file *filp) binder_dev = container_of(filp->private_data, struct binder_device, miscdev); } + refcount_inc(&binder_dev->ref); proc->context = &binder_dev->context; binder_alloc_init(&proc->alloc); @@ -5511,6 +5512,12 @@ static void binder_deferred_release(struct binder_proc *proc) context->binder_context_mgr_node = NULL; } mutex_unlock(&context->context_mgr_node_lock); + device = container_of(proc->context, struct binder_device, context); + if (refcount_dec_and_test(&device->ref)) { + kfree(context->name); + kfree(device); + } + proc->context = NULL; binder_inner_proc_lock(proc); /* * Make sure proc stays alive after we @@ -6184,6 +6191,7 @@ static int __init init_binder_device(const char *name) binder_device->miscdev.minor = MISC_DYNAMIC_MINOR; binder_device->miscdev.name = name; + refcount_set(&binder_device->ref, 1); binder_device->context.binder_context_mgr_uid = INVALID_UID; binder_device->context.name = name; mutex_init(&binder_device->context.context_mgr_node_lock); diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 5e3b7dc67fd3..b908b55c5714 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ struct binder_device { struct miscdevice miscdev; struct binder_context context; struct inode *binderfs_inode; + refcount_t ref; }; /** diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 4328e7e52aa4..e492b25b9dc5 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -154,6 +154,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode, if (!name) goto err; + refcount_set(&device->ref, 1); device->binderfs_inode = inode; device->context.binder_context_mgr_uid = INVALID_UID; device->context.name = name; @@ -258,8 +259,10 @@ static void binderfs_evict_inode(struct inode *inode) ida_free(&binderfs_minors, device->miscdev.minor); mutex_unlock(&binderfs_minors_mutex); - kfree(device->context.name); - kfree(device); + if (refcount_dec_and_test(&device->ref)) { + kfree(device->context.name); + kfree(device); + } } /** -- GitLab From d3fa03b06de780ac24ddcf4b00d2b1288f636852 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 10 Feb 2017 16:27:52 +0100 Subject: [PATCH 465/528] locking/refcounts: Out-of-line everything Linus asked to please make this real C code. And since size then isn't an issue what so ever anymore, remove the debug knob and make all WARN()s unconditional. Suggested-by: Linus Torvalds Signed-off-by: Peter Zijlstra (Intel) Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: dwindsor@gmail.com Cc: elena.reshetova@intel.com Cc: gregkh@linuxfoundation.org Cc: ishkamiel@gmail.com Cc: keescook@chromium.org Signed-off-by: Ingo Molnar (cherry picked from commit 29dee3c03abce04cd527878ef5f9e5f91b7b83f4) --- include/linux/refcount.h | 41 ++++++ lib/Makefile | 3 +- lib/refcount.c | 267 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 include/linux/refcount.h create mode 100644 lib/refcount.c diff --git a/include/linux/refcount.h b/include/linux/refcount.h new file mode 100644 index 000000000000..0e8cfb2ce91e --- /dev/null +++ b/include/linux/refcount.h @@ -0,0 +1,41 @@ +#ifndef _LINUX_REFCOUNT_H +#define _LINUX_REFCOUNT_H + +#include +#include +#include + +typedef struct refcount_struct { + atomic_t refs; +} refcount_t; + +#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), } + +static inline void refcount_set(refcount_t *r, unsigned int n) +{ + atomic_set(&r->refs, n); +} + +static inline unsigned int refcount_read(const refcount_t *r) +{ + return atomic_read(&r->refs); +} + +extern __must_check bool refcount_add_not_zero(unsigned int i, refcount_t *r); +extern void refcount_add(unsigned int i, refcount_t *r); + +extern __must_check bool refcount_inc_not_zero(refcount_t *r); +extern void refcount_inc(refcount_t *r); + +extern __must_check bool refcount_sub_and_test(unsigned int i, refcount_t *r); +extern void refcount_sub(unsigned int i, refcount_t *r); + +extern __must_check bool refcount_dec_and_test(refcount_t *r); +extern void refcount_dec(refcount_t *r); + +extern __must_check bool refcount_dec_if_one(refcount_t *r); +extern __must_check bool refcount_dec_not_one(refcount_t *r); +extern __must_check bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock); +extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock); + +#endif /* _LINUX_REFCOUNT_H */ diff --git a/lib/Makefile b/lib/Makefile index 5dd3fed4b114..ae77e3f6daa7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -24,7 +24,8 @@ lib-y += kobject.o klist.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o \ - bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o + bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o refcount.o + obj-y += string_helpers.o obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o obj-y += kstrtox.o diff --git a/lib/refcount.c b/lib/refcount.c new file mode 100644 index 000000000000..1d33366189d1 --- /dev/null +++ b/lib/refcount.c @@ -0,0 +1,267 @@ +/* + * Variant of atomic_t specialized for reference counts. + * + * The interface matches the atomic_t interface (to aid in porting) but only + * provides the few functions one should use for reference counting. + * + * It differs in that the counter saturates at UINT_MAX and will not move once + * there. This avoids wrapping the counter and causing 'spurious' + * use-after-free issues. + * + * Memory ordering rules are slightly relaxed wrt regular atomic_t functions + * and provide only what is strictly required for refcounts. + * + * The increments are fully relaxed; these will not provide ordering. The + * rationale is that whatever is used to obtain the object we're increasing the + * reference count on will provide the ordering. For locked data structures, + * its the lock acquire, for RCU/lockless data structures its the dependent + * load. + * + * Do note that inc_not_zero() provides a control dependency which will order + * future stores against the inc, this ensures we'll never modify the object + * if we did not in fact acquire a reference. + * + * The decrements will provide release order, such that all the prior loads and + * stores will be issued before, it also provides a control dependency, which + * will order us against the subsequent free(). + * + * The control dependency is against the load of the cmpxchg (ll/sc) that + * succeeded. This means the stores aren't fully ordered, but this is fine + * because the 1->0 transition indicates no concurrency. + * + * Note that the allocator is responsible for ordering things between free() + * and alloc(). + * + */ + +#include +#include + +bool refcount_add_not_zero(unsigned int i, refcount_t *r) +{ + unsigned int old, new, val = atomic_read(&r->refs); + + for (;;) { + if (!val) + return false; + + if (unlikely(val == UINT_MAX)) + return true; + + new = val + i; + if (new < val) + new = UINT_MAX; + old = atomic_cmpxchg_relaxed(&r->refs, val, new); + if (old == val) + break; + + val = old; + } + + WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + + return true; +} +EXPORT_SYMBOL_GPL(refcount_add_not_zero); + +void refcount_add(unsigned int i, refcount_t *r) +{ + WARN(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); +} +EXPORT_SYMBOL_GPL(refcount_add); + +/* + * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN. + * + * Provides no memory ordering, it is assumed the caller has guaranteed the + * object memory to be stable (RCU, etc.). It does provide a control dependency + * and thereby orders future stores. See the comment on top. + */ +bool refcount_inc_not_zero(refcount_t *r) +{ + unsigned int old, new, val = atomic_read(&r->refs); + + for (;;) { + new = val + 1; + + if (!val) + return false; + + if (unlikely(!new)) + return true; + + old = atomic_cmpxchg_relaxed(&r->refs, val, new); + if (old == val) + break; + + val = old; + } + + WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + + return true; +} +EXPORT_SYMBOL_GPL(refcount_inc_not_zero); + +/* + * Similar to atomic_inc(), will saturate at UINT_MAX and WARN. + * + * Provides no memory ordering, it is assumed the caller already has a + * reference on the object, will WARN when this is not so. + */ +void refcount_inc(refcount_t *r) +{ + WARN(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); +} +EXPORT_SYMBOL_GPL(refcount_inc); + +bool refcount_sub_and_test(unsigned int i, refcount_t *r) +{ + unsigned int old, new, val = atomic_read(&r->refs); + + for (;;) { + if (unlikely(val == UINT_MAX)) + return false; + + new = val - i; + if (new > val) { + WARN(new > val, "refcount_t: underflow; use-after-free.\n"); + return false; + } + + old = atomic_cmpxchg_release(&r->refs, val, new); + if (old == val) + break; + + val = old; + } + + return !new; +} +EXPORT_SYMBOL_GPL(refcount_sub_and_test); + +/* + * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to + * decrement when saturated at UINT_MAX. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides a control dependency such that free() must come after. + * See the comment on top. + */ +bool refcount_dec_and_test(refcount_t *r) +{ + return refcount_sub_and_test(1, r); +} +EXPORT_SYMBOL_GPL(refcount_dec_and_test); + +/* + * Similar to atomic_dec(), it will WARN on underflow and fail to decrement + * when saturated at UINT_MAX. + * + * Provides release memory ordering, such that prior loads and stores are done + * before. + */ + +void refcount_dec(refcount_t *r) +{ + WARN(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); +} +EXPORT_SYMBOL_GPL(refcount_dec); + +/* + * No atomic_t counterpart, it attempts a 1 -> 0 transition and returns the + * success thereof. + * + * Like all decrement operations, it provides release memory order and provides + * a control dependency. + * + * It can be used like a try-delete operator; this explicit case is provided + * and not cmpxchg in generic, because that would allow implementing unsafe + * operations. + */ +bool refcount_dec_if_one(refcount_t *r) +{ + return atomic_cmpxchg_release(&r->refs, 1, 0) == 1; +} +EXPORT_SYMBOL_GPL(refcount_dec_if_one); + +/* + * No atomic_t counterpart, it decrements unless the value is 1, in which case + * it will return false. + * + * Was often done like: atomic_add_unless(&var, -1, 1) + */ +bool refcount_dec_not_one(refcount_t *r) +{ + unsigned int old, new, val = atomic_read(&r->refs); + + for (;;) { + if (unlikely(val == UINT_MAX)) + return true; + + if (val == 1) + return false; + + new = val - 1; + if (new > val) { + WARN(new > val, "refcount_t: underflow; use-after-free.\n"); + return true; + } + + old = atomic_cmpxchg_release(&r->refs, val, new); + if (old == val) + break; + + val = old; + } + + return true; +} +EXPORT_SYMBOL_GPL(refcount_dec_not_one); + +/* + * Similar to atomic_dec_and_mutex_lock(), it will WARN on underflow and fail + * to decrement when saturated at UINT_MAX. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides a control dependency such that free() must come after. + * See the comment on top. + */ +bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock) +{ + if (refcount_dec_not_one(r)) + return false; + + mutex_lock(lock); + if (!refcount_dec_and_test(r)) { + mutex_unlock(lock); + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(refcount_dec_and_mutex_lock); + +/* + * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to + * decrement when saturated at UINT_MAX. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides a control dependency such that free() must come after. + * See the comment on top. + */ +bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock) +{ + if (refcount_dec_not_one(r)) + return false; + + spin_lock(lock); + if (!refcount_dec_and_test(r)) { + spin_unlock(lock); + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(refcount_dec_and_lock); + -- GitLab From 382160cacc958da5b7bf4be3e22beb6b19939046 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 1 Mar 2017 09:25:55 +0100 Subject: [PATCH 466/528] locking/refcounts: Change WARN() to WARN_ONCE() Linus noticed that the new refcount.h APIs used WARN(), which would turn into a dmesg DoS if it triggers frequently on some buggy driver. So make sure we only warn once. These warnings are never supposed to happen, so it's typically not a problem to lose subsequent warnings. Suggested-by: Linus Torvalds Cc: Peter Zijlstra (Intel) Cc: Elena Reshetova Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/CA+55aFzbYUTZ=oqZ2YgDjY0C2_n6ODhTfqj6V+m5xWmDxsuB0w@mail.gmail.com Signed-off-by: Ingo Molnar (cherry picked from commit 9dcfe2c75b51f454f39c2de4756e841228865b47) --- lib/refcount.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/refcount.c b/lib/refcount.c index 1d33366189d1..aa09ad3c30b0 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -58,7 +58,7 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r) val = old; } - WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); return true; } @@ -66,7 +66,7 @@ EXPORT_SYMBOL_GPL(refcount_add_not_zero); void refcount_add(unsigned int i, refcount_t *r) { - WARN(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); + WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); } EXPORT_SYMBOL_GPL(refcount_add); @@ -97,7 +97,7 @@ bool refcount_inc_not_zero(refcount_t *r) val = old; } - WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); return true; } @@ -111,7 +111,7 @@ EXPORT_SYMBOL_GPL(refcount_inc_not_zero); */ void refcount_inc(refcount_t *r) { - WARN(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); + WARN_ONCE(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); } EXPORT_SYMBOL_GPL(refcount_inc); @@ -125,7 +125,7 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r) new = val - i; if (new > val) { - WARN(new > val, "refcount_t: underflow; use-after-free.\n"); + WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n"); return false; } @@ -164,7 +164,7 @@ EXPORT_SYMBOL_GPL(refcount_dec_and_test); void refcount_dec(refcount_t *r) { - WARN(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); + WARN_ONCE(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); } EXPORT_SYMBOL_GPL(refcount_dec); @@ -204,7 +204,7 @@ bool refcount_dec_not_one(refcount_t *r) new = val - 1; if (new > val) { - WARN(new > val, "refcount_t: underflow; use-after-free.\n"); + WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n"); return true; } -- GitLab From 841efb8194c17b7da7420c4c81615be6cafc5757 Mon Sep 17 00:00:00 2001 From: David Windsor Date: Fri, 10 Mar 2017 10:34:12 -0500 Subject: [PATCH 467/528] locking/refcount: Add refcount_t API kernel-doc comments Signed-off-by: David Windsor Acked-by: Peter Zijlstra Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Thomas Gleixner Cc: elena.reshetova@intel.com Cc: kernel-hardening@lists.openwall.com Link: http://lkml.kernel.org/r/1489160052-20293-1-git-send-email-dwindsor@gmail.com Signed-off-by: Ingo Molnar (cherry picked from commit bd174169c7a12a37b3b4aa2221f084ade010b182) --- include/linux/refcount.h | 19 ++++++ lib/refcount.c | 122 +++++++++++++++++++++++++++++++++++---- 2 files changed, 129 insertions(+), 12 deletions(-) diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 0e8cfb2ce91e..b0e9f5bc4e0e 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -5,17 +5,36 @@ #include #include +/** + * refcount_t - variant of atomic_t specialized for reference counts + * @refs: atomic_t counter field + * + * The counter saturates at UINT_MAX and will not move once + * there. This avoids wrapping the counter and causing 'spurious' + * use-after-free bugs. + */ typedef struct refcount_struct { atomic_t refs; } refcount_t; #define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), } +/** + * refcount_set - set a refcount's value + * @r: the refcount + * @n: value to which the refcount will be set + */ static inline void refcount_set(refcount_t *r, unsigned int n) { atomic_set(&r->refs, n); } +/** + * refcount_read - get a refcount's value + * @r: the refcount + * + * Return: the refcount's value + */ static inline unsigned int refcount_read(const refcount_t *r) { return atomic_read(&r->refs); diff --git a/lib/refcount.c b/lib/refcount.c index aa09ad3c30b0..8e206ce5609b 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -37,6 +37,24 @@ #include #include +/** + * refcount_add_not_zero - add a value to a refcount unless it is 0 + * @i: the value to add to the refcount + * @r: the refcount + * + * Will saturate at UINT_MAX and WARN. + * + * Provides no memory ordering, it is assumed the caller has guaranteed the + * object memory to be stable (RCU, etc.). It does provide a control dependency + * and thereby orders future stores. See the comment on top. + * + * Use of this function is not recommended for the normal reference counting + * use case in which references are taken and released one at a time. In these + * cases, refcount_inc(), or one of its variants, should instead be used to + * increment a reference count. + * + * Return: false if the passed refcount is 0, true otherwise + */ bool refcount_add_not_zero(unsigned int i, refcount_t *r) { unsigned int old, new, val = atomic_read(&r->refs); @@ -64,18 +82,39 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r) } EXPORT_SYMBOL_GPL(refcount_add_not_zero); +/** + * refcount_add - add a value to a refcount + * @i: the value to add to the refcount + * @r: the refcount + * + * Similar to atomic_add(), but will saturate at UINT_MAX and WARN. + * + * Provides no memory ordering, it is assumed the caller has guaranteed the + * object memory to be stable (RCU, etc.). It does provide a control dependency + * and thereby orders future stores. See the comment on top. + * + * Use of this function is not recommended for the normal reference counting + * use case in which references are taken and released one at a time. In these + * cases, refcount_inc(), or one of its variants, should instead be used to + * increment a reference count. + */ void refcount_add(unsigned int i, refcount_t *r) { WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); } EXPORT_SYMBOL_GPL(refcount_add); -/* - * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN. +/** + * refcount_inc_not_zero - increment a refcount unless it is 0 + * @r: the refcount to increment + * + * Similar to atomic_inc_not_zero(), but will saturate at UINT_MAX and WARN. * * Provides no memory ordering, it is assumed the caller has guaranteed the * object memory to be stable (RCU, etc.). It does provide a control dependency * and thereby orders future stores. See the comment on top. + * + * Return: true if the increment was successful, false otherwise */ bool refcount_inc_not_zero(refcount_t *r) { @@ -103,11 +142,17 @@ bool refcount_inc_not_zero(refcount_t *r) } EXPORT_SYMBOL_GPL(refcount_inc_not_zero); -/* - * Similar to atomic_inc(), will saturate at UINT_MAX and WARN. +/** + * refcount_inc - increment a refcount + * @r: the refcount to increment + * + * Similar to atomic_inc(), but will saturate at UINT_MAX and WARN. * * Provides no memory ordering, it is assumed the caller already has a - * reference on the object, will WARN when this is not so. + * reference on the object. + * + * Will WARN if the refcount is 0, as this represents a possible use-after-free + * condition. */ void refcount_inc(refcount_t *r) { @@ -115,6 +160,26 @@ void refcount_inc(refcount_t *r) } EXPORT_SYMBOL_GPL(refcount_inc); +/** + * refcount_sub_and_test - subtract from a refcount and test if it is 0 + * @i: amount to subtract from the refcount + * @r: the refcount + * + * Similar to atomic_dec_and_test(), but it will WARN, return false and + * ultimately leak on underflow and will fail to decrement when saturated + * at UINT_MAX. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides a control dependency such that free() must come after. + * See the comment on top. + * + * Use of this function is not recommended for the normal reference counting + * use case in which references are taken and released one at a time. In these + * cases, refcount_dec(), or one of its variants, should instead be used to + * decrement a reference count. + * + * Return: true if the resulting refcount is 0, false otherwise + */ bool refcount_sub_and_test(unsigned int i, refcount_t *r) { unsigned int old, new, val = atomic_read(&r->refs); @@ -140,13 +205,18 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r) } EXPORT_SYMBOL_GPL(refcount_sub_and_test); -/* +/** + * refcount_dec_and_test - decrement a refcount and test if it is 0 + * @r: the refcount + * * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to * decrement when saturated at UINT_MAX. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides a control dependency such that free() must come after. * See the comment on top. + * + * Return: true if the resulting refcount is 0, false otherwise */ bool refcount_dec_and_test(refcount_t *r) { @@ -154,21 +224,26 @@ bool refcount_dec_and_test(refcount_t *r) } EXPORT_SYMBOL_GPL(refcount_dec_and_test); -/* +/** + * refcount_dec - decrement a refcount + * @r: the refcount + * * Similar to atomic_dec(), it will WARN on underflow and fail to decrement * when saturated at UINT_MAX. * * Provides release memory ordering, such that prior loads and stores are done * before. */ - void refcount_dec(refcount_t *r) { WARN_ONCE(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); } EXPORT_SYMBOL_GPL(refcount_dec); -/* +/** + * refcount_dec_if_one - decrement a refcount if it is 1 + * @r: the refcount + * * No atomic_t counterpart, it attempts a 1 -> 0 transition and returns the * success thereof. * @@ -178,6 +253,8 @@ EXPORT_SYMBOL_GPL(refcount_dec); * It can be used like a try-delete operator; this explicit case is provided * and not cmpxchg in generic, because that would allow implementing unsafe * operations. + * + * Return: true if the resulting refcount is 0, false otherwise */ bool refcount_dec_if_one(refcount_t *r) { @@ -185,11 +262,16 @@ bool refcount_dec_if_one(refcount_t *r) } EXPORT_SYMBOL_GPL(refcount_dec_if_one); -/* +/** + * refcount_dec_not_one - decrement a refcount if it is not 1 + * @r: the refcount + * * No atomic_t counterpart, it decrements unless the value is 1, in which case * it will return false. * * Was often done like: atomic_add_unless(&var, -1, 1) + * + * Return: true if the decrement operation was successful, false otherwise */ bool refcount_dec_not_one(refcount_t *r) { @@ -219,13 +301,21 @@ bool refcount_dec_not_one(refcount_t *r) } EXPORT_SYMBOL_GPL(refcount_dec_not_one); -/* +/** + * refcount_dec_and_mutex_lock - return holding mutex if able to decrement + * refcount to 0 + * @r: the refcount + * @lock: the mutex to be locked + * * Similar to atomic_dec_and_mutex_lock(), it will WARN on underflow and fail * to decrement when saturated at UINT_MAX. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides a control dependency such that free() must come after. * See the comment on top. + * + * Return: true and hold mutex if able to decrement refcount to 0, false + * otherwise */ bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock) { @@ -242,13 +332,21 @@ bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock) } EXPORT_SYMBOL_GPL(refcount_dec_and_mutex_lock); -/* +/** + * refcount_dec_and_lock - return holding spinlock if able to decrement + * refcount to 0 + * @r: the refcount + * @lock: the spinlock to be locked + * * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to * decrement when saturated at UINT_MAX. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides a control dependency such that free() must come after. * See the comment on top. + * + * Return: true and hold spinlock if able to decrement refcount to 0, false + * otherwise */ bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock) { -- GitLab From f35c4a0efb013ac07e174bb5a7f67310b748ecd3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 1 Feb 2017 16:07:55 +0100 Subject: [PATCH 468/528] locking/refcounts: Use atomic_try_cmpxchg() Generates better code (GCC-6.2.1): text filename 1576 defconfig-build/lib/refcount.o.pre 1488 defconfig-build/lib/refcount.o.post Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar (cherry picked from commit b78c0d471255e99411d6c1b3975df21c3cd9f349) --- lib/refcount.c | 47 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/lib/refcount.c b/lib/refcount.c index 8e206ce5609b..f42124ccf295 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -57,9 +57,9 @@ */ bool refcount_add_not_zero(unsigned int i, refcount_t *r) { - unsigned int old, new, val = atomic_read(&r->refs); + unsigned int new, val = atomic_read(&r->refs); - for (;;) { + do { if (!val) return false; @@ -69,12 +69,8 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r) new = val + i; if (new < val) new = UINT_MAX; - old = atomic_cmpxchg_relaxed(&r->refs, val, new); - if (old == val) - break; - val = old; - } + } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); @@ -118,9 +114,9 @@ EXPORT_SYMBOL_GPL(refcount_add); */ bool refcount_inc_not_zero(refcount_t *r) { - unsigned int old, new, val = atomic_read(&r->refs); + unsigned int new, val = atomic_read(&r->refs); - for (;;) { + do { new = val + 1; if (!val) @@ -129,12 +125,7 @@ bool refcount_inc_not_zero(refcount_t *r) if (unlikely(!new)) return true; - old = atomic_cmpxchg_relaxed(&r->refs, val, new); - if (old == val) - break; - - val = old; - } + } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); @@ -182,9 +173,9 @@ EXPORT_SYMBOL_GPL(refcount_inc); */ bool refcount_sub_and_test(unsigned int i, refcount_t *r) { - unsigned int old, new, val = atomic_read(&r->refs); + unsigned int new, val = atomic_read(&r->refs); - for (;;) { + do { if (unlikely(val == UINT_MAX)) return false; @@ -194,12 +185,7 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r) return false; } - old = atomic_cmpxchg_release(&r->refs, val, new); - if (old == val) - break; - - val = old; - } + } while (!atomic_try_cmpxchg_release(&r->refs, &val, new)); return !new; } @@ -258,7 +244,9 @@ EXPORT_SYMBOL_GPL(refcount_dec); */ bool refcount_dec_if_one(refcount_t *r) { - return atomic_cmpxchg_release(&r->refs, 1, 0) == 1; + int val = 1; + + return atomic_try_cmpxchg_release(&r->refs, &val, 0); } EXPORT_SYMBOL_GPL(refcount_dec_if_one); @@ -275,9 +263,9 @@ EXPORT_SYMBOL_GPL(refcount_dec_if_one); */ bool refcount_dec_not_one(refcount_t *r) { - unsigned int old, new, val = atomic_read(&r->refs); + unsigned int new, val = atomic_read(&r->refs); - for (;;) { + do { if (unlikely(val == UINT_MAX)) return true; @@ -290,12 +278,7 @@ bool refcount_dec_not_one(refcount_t *r) return true; } - old = atomic_cmpxchg_release(&r->refs, val, new); - if (old == val) - break; - - val = old; - } + } while (!atomic_try_cmpxchg_release(&r->refs, &val, new)); return true; } -- GitLab From be87c19fca63d9cec9e7245d1cc304e711fc0ff5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 4 May 2017 15:51:03 -0700 Subject: [PATCH 469/528] refcount: change EXPORT_SYMBOL markings Now that kref is using the refcount apis, the _GPL markings are getting exported to places that it previously wasn't. Now kref.h is GPLv2 licensed, so any non-GPL code using it better be talking to some lawyers, but changing api markings isn't considered "nice", so let's fix this up. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds (cherry picked from commit d557d1b58b3546bab2c5bc2d624c5709840e6b10) --- lib/refcount.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/refcount.c b/lib/refcount.c index f42124ccf295..9f906783987e 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -76,7 +76,7 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r) return true; } -EXPORT_SYMBOL_GPL(refcount_add_not_zero); +EXPORT_SYMBOL(refcount_add_not_zero); /** * refcount_add - add a value to a refcount @@ -98,7 +98,7 @@ void refcount_add(unsigned int i, refcount_t *r) { WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); } -EXPORT_SYMBOL_GPL(refcount_add); +EXPORT_SYMBOL(refcount_add); /** * refcount_inc_not_zero - increment a refcount unless it is 0 @@ -131,7 +131,7 @@ bool refcount_inc_not_zero(refcount_t *r) return true; } -EXPORT_SYMBOL_GPL(refcount_inc_not_zero); +EXPORT_SYMBOL(refcount_inc_not_zero); /** * refcount_inc - increment a refcount @@ -149,7 +149,7 @@ void refcount_inc(refcount_t *r) { WARN_ONCE(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); } -EXPORT_SYMBOL_GPL(refcount_inc); +EXPORT_SYMBOL(refcount_inc); /** * refcount_sub_and_test - subtract from a refcount and test if it is 0 @@ -189,7 +189,7 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r) return !new; } -EXPORT_SYMBOL_GPL(refcount_sub_and_test); +EXPORT_SYMBOL(refcount_sub_and_test); /** * refcount_dec_and_test - decrement a refcount and test if it is 0 @@ -208,7 +208,7 @@ bool refcount_dec_and_test(refcount_t *r) { return refcount_sub_and_test(1, r); } -EXPORT_SYMBOL_GPL(refcount_dec_and_test); +EXPORT_SYMBOL(refcount_dec_and_test); /** * refcount_dec - decrement a refcount @@ -224,7 +224,7 @@ void refcount_dec(refcount_t *r) { WARN_ONCE(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); } -EXPORT_SYMBOL_GPL(refcount_dec); +EXPORT_SYMBOL(refcount_dec); /** * refcount_dec_if_one - decrement a refcount if it is 1 @@ -248,7 +248,7 @@ bool refcount_dec_if_one(refcount_t *r) return atomic_try_cmpxchg_release(&r->refs, &val, 0); } -EXPORT_SYMBOL_GPL(refcount_dec_if_one); +EXPORT_SYMBOL(refcount_dec_if_one); /** * refcount_dec_not_one - decrement a refcount if it is not 1 @@ -282,7 +282,7 @@ bool refcount_dec_not_one(refcount_t *r) return true; } -EXPORT_SYMBOL_GPL(refcount_dec_not_one); +EXPORT_SYMBOL(refcount_dec_not_one); /** * refcount_dec_and_mutex_lock - return holding mutex if able to decrement @@ -313,7 +313,7 @@ bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock) return true; } -EXPORT_SYMBOL_GPL(refcount_dec_and_mutex_lock); +EXPORT_SYMBOL(refcount_dec_and_mutex_lock); /** * refcount_dec_and_lock - return holding spinlock if able to decrement @@ -344,5 +344,5 @@ bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock) return true; } -EXPORT_SYMBOL_GPL(refcount_dec_and_lock); +EXPORT_SYMBOL(refcount_dec_and_lock); -- GitLab From 496711ca3efb74be7bc5ab774955390e2f8836bb Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 21 Jun 2017 13:00:26 -0700 Subject: [PATCH 470/528] locking/refcount: Create unchecked atomic_t implementation Many subsystems will not use refcount_t unless there is a way to build the kernel so that there is no regression in speed compared to atomic_t. This adds CONFIG_REFCOUNT_FULL to enable the full refcount_t implementation which has the validation but is slightly slower. When not enabled, refcount_t uses the basic unchecked atomic_t routines, which results in no code changes compared to just using atomic_t directly. Signed-off-by: Kees Cook Acked-by: Greg Kroah-Hartman Cc: Alexey Dobriyan Cc: Andrew Morton Cc: Arnd Bergmann Cc: Christoph Hellwig Cc: David S. Miller Cc: David Windsor Cc: Davidlohr Bueso Cc: Elena Reshetova Cc: Eric Biggers Cc: Eric W. Biederman Cc: Hans Liljestrand Cc: James Bottomley Cc: Jann Horn Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Manfred Spraul Cc: Peter Zijlstra Cc: Rik van Riel Cc: Serge E. Hallyn Cc: Thomas Gleixner Cc: arozansk@redhat.com Cc: axboe@kernel.dk Cc: linux-arch Link: http://lkml.kernel.org/r/20170621200026.GA115679@beast Signed-off-by: Ingo Molnar (cherry picked from commit fd25d19f6b8da315332bb75936605fb45d3ea981) --- arch/Kconfig | 9 +++++++++ include/linux/refcount.h | 42 ++++++++++++++++++++++++++++++++++++++++ lib/refcount.c | 3 +++ 3 files changed, 54 insertions(+) diff --git a/arch/Kconfig b/arch/Kconfig index 69fcfae90778..c695fe5a82d7 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -569,4 +569,13 @@ config OLD_SIGACTION config COMPAT_OLD_SIGACTION bool +config REFCOUNT_FULL + bool "Perform full reference count validation at the expense of speed" + help + Enabling this switches the refcounting infrastructure from a fast + unchecked atomic_t implementation to a fully state checked + implementation, which can be (slightly) slower but provides protections + against various use-after-free conditions that can be used in + security flaw exploits. + source "kernel/gcov/Kconfig" diff --git a/include/linux/refcount.h b/include/linux/refcount.h index b0e9f5bc4e0e..8a6f5889df23 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -40,6 +40,7 @@ static inline unsigned int refcount_read(const refcount_t *r) return atomic_read(&r->refs); } +#ifdef CONFIG_REFCOUNT_FULL extern __must_check bool refcount_add_not_zero(unsigned int i, refcount_t *r); extern void refcount_add(unsigned int i, refcount_t *r); @@ -51,6 +52,47 @@ extern void refcount_sub(unsigned int i, refcount_t *r); extern __must_check bool refcount_dec_and_test(refcount_t *r); extern void refcount_dec(refcount_t *r); +#else +static inline __must_check bool refcount_add_not_zero(unsigned int i, refcount_t *r) +{ + return atomic_add_unless(&r->refs, i, 0); +} + +static inline void refcount_add(unsigned int i, refcount_t *r) +{ + atomic_add(i, &r->refs); +} + +static inline __must_check bool refcount_inc_not_zero(refcount_t *r) +{ + return atomic_add_unless(&r->refs, 1, 0); +} + +static inline void refcount_inc(refcount_t *r) +{ + atomic_inc(&r->refs); +} + +static inline __must_check bool refcount_sub_and_test(unsigned int i, refcount_t *r) +{ + return atomic_sub_and_test(i, &r->refs); +} + +static inline void refcount_sub(unsigned int i, refcount_t *r) +{ + atomic_sub(i, &r->refs); +} + +static inline __must_check bool refcount_dec_and_test(refcount_t *r) +{ + return atomic_dec_and_test(&r->refs); +} + +static inline void refcount_dec(refcount_t *r) +{ + atomic_dec(&r->refs); +} +#endif /* CONFIG_REFCOUNT_FULL */ extern __must_check bool refcount_dec_if_one(refcount_t *r); extern __must_check bool refcount_dec_not_one(refcount_t *r); diff --git a/lib/refcount.c b/lib/refcount.c index 9f906783987e..5d0582a9480c 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -37,6 +37,8 @@ #include #include +#ifdef CONFIG_REFCOUNT_FULL + /** * refcount_add_not_zero - add a value to a refcount unless it is 0 * @i: the value to add to the refcount @@ -225,6 +227,7 @@ void refcount_dec(refcount_t *r) WARN_ONCE(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); } EXPORT_SYMBOL(refcount_dec); +#endif /* CONFIG_REFCOUNT_FULL */ /** * refcount_dec_if_one - decrement a refcount if it is 1 -- GitLab From aaab52ce3fb70b6dd8c76bd84ef7024dbf63249d Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Tue, 12 Jun 2018 18:16:21 +0200 Subject: [PATCH 471/528] locking/refcounts: Implement refcount_dec_and_lock_irqsave() There are in-tree users of refcount_dec_and_lock() which must acquire the spin lock with interrupts disabled. To workaround the lack of an irqsave variant of refcount_dec_and_lock() they use local_irq_save() at the call site. This causes extra code and creates in some places unneeded long interrupt disabled times. These places need also extra treatment for PREEMPT_RT due to the disconnect of the irq disabling and the lock function. Implement the missing irqsave variant of the function. Signed-off-by: Anna-Maria Gleixner Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r20180612161621.22645-4-bigeasy@linutronix.de [bigeasy: s@atomic_dec_and_lock@refcount_dec_and_lock@g] (cherry picked from commit 7ea959c45769612aa92557fb6464679f5fec7d9e) --- include/linux/refcount.h | 4 +++- lib/refcount.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 8a6f5889df23..a692439c51bb 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -98,5 +98,7 @@ extern __must_check bool refcount_dec_if_one(refcount_t *r); extern __must_check bool refcount_dec_not_one(refcount_t *r); extern __must_check bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock); extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock); - +extern __must_check bool refcount_dec_and_lock_irqsave(refcount_t *r, + spinlock_t *lock, + unsigned long *flags); #endif /* _LINUX_REFCOUNT_H */ diff --git a/lib/refcount.c b/lib/refcount.c index 5d0582a9480c..79100235f2ca 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -349,3 +349,31 @@ bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock) } EXPORT_SYMBOL(refcount_dec_and_lock); +/** + * refcount_dec_and_lock_irqsave - return holding spinlock with disabled + * interrupts if able to decrement refcount to 0 + * @r: the refcount + * @lock: the spinlock to be locked + * @flags: saved IRQ-flags if the is acquired + * + * Same as refcount_dec_and_lock() above except that the spinlock is acquired + * with disabled interupts. + * + * Return: true and hold spinlock if able to decrement refcount to 0, false + * otherwise + */ +bool refcount_dec_and_lock_irqsave(refcount_t *r, spinlock_t *lock, + unsigned long *flags) +{ + if (refcount_dec_not_one(r)) + return false; + + spin_lock_irqsave(lock, *flags); + if (!refcount_dec_and_test(r)) { + spin_unlock_irqrestore(lock, *flags); + return false; + } + + return true; +} +EXPORT_SYMBOL(refcount_dec_and_lock_irqsave); -- GitLab From ab0f56b7590672dfa78dcca2bd5047ad003af1e7 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 1 Apr 2018 01:00:36 +0300 Subject: [PATCH 472/528] locking/refcounts: Include fewer headers in Debloat 's dependencies: - is not needed, but is. - is not needed, only a forward declaration of "struct mutex". - is not needed, is enough. Signed-off-by: Alexey Dobriyan Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Link: https://lkml.kernel.org/lkml/20180331220036.GA7676@avx2 Signed-off-by: Ingo Molnar (cherry picked from commit 75a040ff14d9a99fc041f5e1d8f09541cab13ba4) --- arch/x86/include/asm/refcount.h | 110 ++++++++++++++++++++++++++++++++ include/linux/refcount.h | 6 +- lib/refcount.c | 2 + 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 arch/x86/include/asm/refcount.h diff --git a/arch/x86/include/asm/refcount.h b/arch/x86/include/asm/refcount.h new file mode 100644 index 000000000000..19b90521954c --- /dev/null +++ b/arch/x86/include/asm/refcount.h @@ -0,0 +1,110 @@ +#ifndef __ASM_X86_REFCOUNT_H +#define __ASM_X86_REFCOUNT_H +/* + * x86-specific implementation of refcount_t. Based on PAX_REFCOUNT from + * PaX/grsecurity. + */ +#include +#include + +/* + * This is the first portion of the refcount error handling, which lives in + * .text.unlikely, and is jumped to from the CPU flag check (in the + * following macros). This saves the refcount value location into CX for + * the exception handler to use (in mm/extable.c), and then triggers the + * central refcount exception. The fixup address for the exception points + * back to the regular execution flow in .text. + */ +#define _REFCOUNT_EXCEPTION \ + ".pushsection .text..refcount\n" \ + "111:\tlea %[counter], %%" _ASM_CX "\n" \ + "112:\t" ASM_UD2 "\n" \ + ASM_UNREACHABLE \ + ".popsection\n" \ + "113:\n" \ + _ASM_EXTABLE_REFCOUNT(112b, 113b) + +/* Trigger refcount exception if refcount result is negative. */ +#define REFCOUNT_CHECK_LT_ZERO \ + "js 111f\n\t" \ + _REFCOUNT_EXCEPTION + +/* Trigger refcount exception if refcount result is zero or negative. */ +#define REFCOUNT_CHECK_LE_ZERO \ + "jz 111f\n\t" \ + REFCOUNT_CHECK_LT_ZERO + +/* Trigger refcount exception unconditionally. */ +#define REFCOUNT_ERROR \ + "jmp 111f\n\t" \ + _REFCOUNT_EXCEPTION + +static __always_inline void refcount_add(unsigned int i, refcount_t *r) +{ + asm volatile(LOCK_PREFIX "addl %1,%0\n\t" + REFCOUNT_CHECK_LT_ZERO + : [counter] "+m" (r->refs.counter) + : "ir" (i) + : "cc", "cx"); +} + +static __always_inline void refcount_inc(refcount_t *r) +{ + asm volatile(LOCK_PREFIX "incl %0\n\t" + REFCOUNT_CHECK_LT_ZERO + : [counter] "+m" (r->refs.counter) + : : "cc", "cx"); +} + +static __always_inline void refcount_dec(refcount_t *r) +{ + asm volatile(LOCK_PREFIX "decl %0\n\t" + REFCOUNT_CHECK_LE_ZERO + : [counter] "+m" (r->refs.counter) + : : "cc", "cx"); +} + +static __always_inline __must_check +bool refcount_sub_and_test(unsigned int i, refcount_t *r) +{ + GEN_BINARY_SUFFIXED_RMWcc(LOCK_PREFIX "subl", REFCOUNT_CHECK_LT_ZERO, + r->refs.counter, "er", i, "%0", e, "cx"); +} + +static __always_inline __must_check bool refcount_dec_and_test(refcount_t *r) +{ + GEN_UNARY_SUFFIXED_RMWcc(LOCK_PREFIX "decl", REFCOUNT_CHECK_LT_ZERO, + r->refs.counter, "%0", e, "cx"); +} + +static __always_inline __must_check +bool refcount_add_not_zero(unsigned int i, refcount_t *r) +{ + int c, result; + + c = atomic_read(&(r->refs)); + do { + if (unlikely(c == 0)) + return false; + + result = c + i; + + /* Did we try to increment from/to an undesirable state? */ + if (unlikely(c < 0 || c == INT_MAX || result < c)) { + asm volatile(REFCOUNT_ERROR + : : [counter] "m" (r->refs.counter) + : "cc", "cx"); + break; + } + + } while (!atomic_try_cmpxchg(&(r->refs), &c, result)); + + return c != 0; +} + +static __always_inline __must_check bool refcount_inc_not_zero(refcount_t *r) +{ + return refcount_add_not_zero(1, r); +} + +#endif diff --git a/include/linux/refcount.h b/include/linux/refcount.h index a692439c51bb..a3e167d05a7c 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -2,8 +2,10 @@ #define _LINUX_REFCOUNT_H #include -#include -#include +#include +#include + +struct mutex; /** * refcount_t - variant of atomic_t specialized for reference counts diff --git a/lib/refcount.c b/lib/refcount.c index 79100235f2ca..632bbcf69663 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -34,7 +34,9 @@ * */ +#include #include +#include #include #ifdef CONFIG_REFCOUNT_FULL -- GitLab From e830f2cfa96143d7a007ae71b4d5c3b3d3ff914c Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 11 Jul 2018 10:36:07 +0100 Subject: [PATCH 473/528] locking/refcount: Always allow checked forms In many cases, it would be useful to be able to use the full sanity-checked refcount helpers regardless of CONFIG_REFCOUNT_FULL, as this would help to avoid duplicate warnings where callers try to sanity-check refcount manipulation. This patch refactors things such that the full refcount helpers were always built, as refcount_${op}_checked(), such that they can be used regardless of CONFIG_REFCOUNT_FULL. This will allow code which *always* wants a checked refcount to opt-in, avoiding the need to duplicate the logic for warnings. There should be no functional change as a result of this patch. Signed-off-by: Mark Rutland Reviewed-by: David Sterba Acked-by: Kees Cook Acked-by: Will Deacon Cc: Boqun Feng Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20180711093607.1644-1-mark.rutland@arm.com Signed-off-by: Ingo Molnar (cherry picked from commit afed7bcf9487bb28e2e2b016a195085c07416c0b) --- include/linux/refcount.h | 27 ++++++++++++++------ lib/refcount.c | 53 +++++++++++++++++++--------------------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/include/linux/refcount.h b/include/linux/refcount.h index a3e167d05a7c..069d47ebc861 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -42,18 +42,31 @@ static inline unsigned int refcount_read(const refcount_t *r) return atomic_read(&r->refs); } +extern __must_check bool refcount_add_not_zero_checked(unsigned int i, refcount_t *r); +extern void refcount_add_checked(unsigned int i, refcount_t *r); + +extern __must_check bool refcount_inc_not_zero_checked(refcount_t *r); +extern void refcount_inc_checked(refcount_t *r); + +extern __must_check bool refcount_sub_and_test_checked(unsigned int i, refcount_t *r); + +extern __must_check bool refcount_dec_and_test_checked(refcount_t *r); +extern void refcount_dec_checked(refcount_t *r); + #ifdef CONFIG_REFCOUNT_FULL -extern __must_check bool refcount_add_not_zero(unsigned int i, refcount_t *r); -extern void refcount_add(unsigned int i, refcount_t *r); -extern __must_check bool refcount_inc_not_zero(refcount_t *r); -extern void refcount_inc(refcount_t *r); +#define refcount_add_not_zero refcount_add_not_zero_checked +#define refcount_add refcount_add_checked + +#define refcount_inc_not_zero refcount_inc_not_zero_checked +#define refcount_inc refcount_inc_checked + +#define refcount_sub_and_test refcount_sub_and_test_checked -extern __must_check bool refcount_sub_and_test(unsigned int i, refcount_t *r); extern void refcount_sub(unsigned int i, refcount_t *r); +#define refcount_dec_and_test refcount_dec_and_test_checked +#define refcount_dec refcount_dec_checked -extern __must_check bool refcount_dec_and_test(refcount_t *r); -extern void refcount_dec(refcount_t *r); #else static inline __must_check bool refcount_add_not_zero(unsigned int i, refcount_t *r) { diff --git a/lib/refcount.c b/lib/refcount.c index 632bbcf69663..e8853a436dbb 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -39,10 +39,8 @@ #include #include -#ifdef CONFIG_REFCOUNT_FULL - /** - * refcount_add_not_zero - add a value to a refcount unless it is 0 + * refcount_add_not_zero_checked - add a value to a refcount unless it is 0 * @i: the value to add to the refcount * @r: the refcount * @@ -59,7 +57,7 @@ * * Return: false if the passed refcount is 0, true otherwise */ -bool refcount_add_not_zero(unsigned int i, refcount_t *r) +bool refcount_add_not_zero_checked(unsigned int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); @@ -80,10 +78,10 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r) return true; } -EXPORT_SYMBOL(refcount_add_not_zero); +EXPORT_SYMBOL(refcount_add_not_zero_checked); /** - * refcount_add - add a value to a refcount + * refcount_add_checked - add a value to a refcount * @i: the value to add to the refcount * @r: the refcount * @@ -98,14 +96,14 @@ EXPORT_SYMBOL(refcount_add_not_zero); * cases, refcount_inc(), or one of its variants, should instead be used to * increment a reference count. */ -void refcount_add(unsigned int i, refcount_t *r) +void refcount_add_checked(unsigned int i, refcount_t *r) { - WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); + WARN_ONCE(!refcount_add_not_zero_checked(i, r), "refcount_t: addition on 0; use-after-free.\n"); } -EXPORT_SYMBOL(refcount_add); +EXPORT_SYMBOL(refcount_add_checked); /** - * refcount_inc_not_zero - increment a refcount unless it is 0 + * refcount_inc_not_zero_checked - increment a refcount unless it is 0 * @r: the refcount to increment * * Similar to atomic_inc_not_zero(), but will saturate at UINT_MAX and WARN. @@ -116,7 +114,7 @@ EXPORT_SYMBOL(refcount_add); * * Return: true if the increment was successful, false otherwise */ -bool refcount_inc_not_zero(refcount_t *r) +bool refcount_inc_not_zero_checked(refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); @@ -135,10 +133,10 @@ bool refcount_inc_not_zero(refcount_t *r) return true; } -EXPORT_SYMBOL(refcount_inc_not_zero); +EXPORT_SYMBOL(refcount_inc_not_zero_checked); /** - * refcount_inc - increment a refcount + * refcount_inc_checked - increment a refcount * @r: the refcount to increment * * Similar to atomic_inc(), but will saturate at UINT_MAX and WARN. @@ -149,14 +147,14 @@ EXPORT_SYMBOL(refcount_inc_not_zero); * Will WARN if the refcount is 0, as this represents a possible use-after-free * condition. */ -void refcount_inc(refcount_t *r) +void refcount_inc_checked(refcount_t *r) { - WARN_ONCE(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); + WARN_ONCE(!refcount_inc_not_zero_checked(r), "refcount_t: increment on 0; use-after-free.\n"); } -EXPORT_SYMBOL(refcount_inc); +EXPORT_SYMBOL(refcount_inc_checked); /** - * refcount_sub_and_test - subtract from a refcount and test if it is 0 + * refcount_sub_and_test_checked - subtract from a refcount and test if it is 0 * @i: amount to subtract from the refcount * @r: the refcount * @@ -175,7 +173,7 @@ EXPORT_SYMBOL(refcount_inc); * * Return: true if the resulting refcount is 0, false otherwise */ -bool refcount_sub_and_test(unsigned int i, refcount_t *r) +bool refcount_sub_and_test_checked(unsigned int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); @@ -193,10 +191,10 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r) return !new; } -EXPORT_SYMBOL(refcount_sub_and_test); +EXPORT_SYMBOL(refcount_sub_and_test_checked); /** - * refcount_dec_and_test - decrement a refcount and test if it is 0 + * refcount_dec_and_test_checked - decrement a refcount and test if it is 0 * @r: the refcount * * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to @@ -208,14 +206,14 @@ EXPORT_SYMBOL(refcount_sub_and_test); * * Return: true if the resulting refcount is 0, false otherwise */ -bool refcount_dec_and_test(refcount_t *r) +bool refcount_dec_and_test_checked(refcount_t *r) { - return refcount_sub_and_test(1, r); + return refcount_sub_and_test_checked(1, r); } -EXPORT_SYMBOL(refcount_dec_and_test); +EXPORT_SYMBOL(refcount_dec_and_test_checked); /** - * refcount_dec - decrement a refcount + * refcount_dec_checked - decrement a refcount * @r: the refcount * * Similar to atomic_dec(), it will WARN on underflow and fail to decrement @@ -224,12 +222,11 @@ EXPORT_SYMBOL(refcount_dec_and_test); * Provides release memory ordering, such that prior loads and stores are done * before. */ -void refcount_dec(refcount_t *r) +void refcount_dec_checked(refcount_t *r) { - WARN_ONCE(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); + WARN_ONCE(refcount_dec_and_test_checked(r), "refcount_t: decrement hit 0; leaking memory.\n"); } -EXPORT_SYMBOL(refcount_dec); -#endif /* CONFIG_REFCOUNT_FULL */ +EXPORT_SYMBOL(refcount_dec_checked); /** * refcount_dec_if_one - decrement a refcount if it is 1 -- GitLab From a8460882cb791d2b5cf2da3969adb8b6ad5b300c Mon Sep 17 00:00:00 2001 From: Elena Reshetova Date: Wed, 30 Jan 2019 13:18:51 +0200 Subject: [PATCH 474/528] refcount_t: Add ACQUIRE ordering on success for dec(sub)_and_test() variants This adds an smp_acquire__after_ctrl_dep() barrier on successful decrease of refcounter value from 1 to 0 for refcount_dec(sub)_and_test variants and therefore gives stronger memory ordering guarantees than prior versions of these functions. Co-developed-by: Peter Zijlstra (Intel) Signed-off-by: Elena Reshetova Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Andrea Parri Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: dvyukov@google.com Cc: keescook@chromium.org Cc: stern@rowland.harvard.edu Link: https://lkml.kernel.org/r/1548847131-27854-2-git-send-email-elena.reshetova@intel.com Signed-off-by: Ingo Molnar (cherry picked from commit 47b8f3ab9c49daa824af848f9e02889662d8638f) --- Documentation/core-api/refcount-vs-atomic.rst | 168 ++++++++++++++++++ arch/x86/include/asm/refcount.h | 26 +++ lib/refcount.c | 18 +- 3 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 Documentation/core-api/refcount-vs-atomic.rst diff --git a/Documentation/core-api/refcount-vs-atomic.rst b/Documentation/core-api/refcount-vs-atomic.rst new file mode 100644 index 000000000000..976e85adffe8 --- /dev/null +++ b/Documentation/core-api/refcount-vs-atomic.rst @@ -0,0 +1,168 @@ +=================================== +refcount_t API compared to atomic_t +=================================== + +.. contents:: :local: + +Introduction +============ + +The goal of refcount_t API is to provide a minimal API for implementing +an object's reference counters. While a generic architecture-independent +implementation from lib/refcount.c uses atomic operations underneath, +there are a number of differences between some of the ``refcount_*()`` and +``atomic_*()`` functions with regards to the memory ordering guarantees. +This document outlines the differences and provides respective examples +in order to help maintainers validate their code against the change in +these memory ordering guarantees. + +The terms used through this document try to follow the formal LKMM defined in +tools/memory-model/Documentation/explanation.txt. + +memory-barriers.txt and atomic_t.txt provide more background to the +memory ordering in general and for atomic operations specifically. + +Relevant types of memory ordering +================================= + +.. note:: The following section only covers some of the memory + ordering types that are relevant for the atomics and reference + counters and used through this document. For a much broader picture + please consult memory-barriers.txt document. + +In the absence of any memory ordering guarantees (i.e. fully unordered) +atomics & refcounters only provide atomicity and +program order (po) relation (on the same CPU). It guarantees that +each ``atomic_*()`` and ``refcount_*()`` operation is atomic and instructions +are executed in program order on a single CPU. +This is implemented using :c:func:`READ_ONCE`/:c:func:`WRITE_ONCE` and +compare-and-swap primitives. + +A strong (full) memory ordering guarantees that all prior loads and +stores (all po-earlier instructions) on the same CPU are completed +before any po-later instruction is executed on the same CPU. +It also guarantees that all po-earlier stores on the same CPU +and all propagated stores from other CPUs must propagate to all +other CPUs before any po-later instruction is executed on the original +CPU (A-cumulative property). This is implemented using :c:func:`smp_mb`. + +A RELEASE memory ordering guarantees that all prior loads and +stores (all po-earlier instructions) on the same CPU are completed +before the operation. It also guarantees that all po-earlier +stores on the same CPU and all propagated stores from other CPUs +must propagate to all other CPUs before the release operation +(A-cumulative property). This is implemented using +:c:func:`smp_store_release`. + +An ACQUIRE memory ordering guarantees that all post loads and +stores (all po-later instructions) on the same CPU are +completed after the acquire operation. It also guarantees that all +po-later stores on the same CPU must propagate to all other CPUs +after the acquire operation executes. This is implemented using +:c:func:`smp_acquire__after_ctrl_dep`. + +A control dependency (on success) for refcounters guarantees that +if a reference for an object was successfully obtained (reference +counter increment or addition happened, function returned true), +then further stores are ordered against this operation. +Control dependency on stores are not implemented using any explicit +barriers, but rely on CPU not to speculate on stores. This is only +a single CPU relation and provides no guarantees for other CPUs. + + +Comparison of functions +======================= + +case 1) - non-"Read/Modify/Write" (RMW) ops +------------------------------------------- + +Function changes: + + * :c:func:`atomic_set` --> :c:func:`refcount_set` + * :c:func:`atomic_read` --> :c:func:`refcount_read` + +Memory ordering guarantee changes: + + * none (both fully unordered) + + +case 2) - increment-based ops that return no value +-------------------------------------------------- + +Function changes: + + * :c:func:`atomic_inc` --> :c:func:`refcount_inc` + * :c:func:`atomic_add` --> :c:func:`refcount_add` + +Memory ordering guarantee changes: + + * none (both fully unordered) + +case 3) - decrement-based RMW ops that return no value +------------------------------------------------------ + +Function changes: + + * :c:func:`atomic_dec` --> :c:func:`refcount_dec` + +Memory ordering guarantee changes: + + * fully unordered --> RELEASE ordering + + +case 4) - increment-based RMW ops that return a value +----------------------------------------------------- + +Function changes: + + * :c:func:`atomic_inc_not_zero` --> :c:func:`refcount_inc_not_zero` + * no atomic counterpart --> :c:func:`refcount_add_not_zero` + +Memory ordering guarantees changes: + + * fully ordered --> control dependency on success for stores + +.. note:: We really assume here that necessary ordering is provided as a + result of obtaining pointer to the object! + + +case 5) - generic dec/sub decrement-based RMW ops that return a value +--------------------------------------------------------------------- + +Function changes: + + * :c:func:`atomic_dec_and_test` --> :c:func:`refcount_dec_and_test` + * :c:func:`atomic_sub_and_test` --> :c:func:`refcount_sub_and_test` + +Memory ordering guarantees changes: + + * fully ordered --> RELEASE ordering + ACQUIRE ordering on success + + +case 6) other decrement-based RMW ops that return a value +--------------------------------------------------------- + +Function changes: + + * no atomic counterpart --> :c:func:`refcount_dec_if_one` + * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)`` + +Memory ordering guarantees changes: + + * fully ordered --> RELEASE ordering + control dependency + +.. note:: :c:func:`atomic_add_unless` only provides full order on success. + + +case 7) - lock-based RMW +------------------------ + +Function changes: + + * :c:func:`atomic_dec_and_lock` --> :c:func:`refcount_dec_and_lock` + * :c:func:`atomic_dec_and_mutex_lock` --> :c:func:`refcount_dec_and_mutex_lock` + +Memory ordering guarantees changes: + + * fully ordered --> RELEASE ordering + control dependency + hold + :c:func:`spin_lock` on success diff --git a/arch/x86/include/asm/refcount.h b/arch/x86/include/asm/refcount.h index 19b90521954c..6b5b479096ab 100644 --- a/arch/x86/include/asm/refcount.h +++ b/arch/x86/include/asm/refcount.h @@ -67,14 +67,40 @@ static __always_inline void refcount_dec(refcount_t *r) static __always_inline __must_check bool refcount_sub_and_test(unsigned int i, refcount_t *r) { +<<<<<<< HEAD GEN_BINARY_SUFFIXED_RMWcc(LOCK_PREFIX "subl", REFCOUNT_CHECK_LT_ZERO, r->refs.counter, "er", i, "%0", e, "cx"); +======= + bool ret = GEN_BINARY_SUFFIXED_RMWcc(LOCK_PREFIX "subl", + REFCOUNT_CHECK_LT_ZERO, + r->refs.counter, e, "er", i, "cx"); + + if (ret) { + smp_acquire__after_ctrl_dep(); + return true; + } + + return false; +>>>>>>> 47b8f3ab9c49 (refcount_t: Add ACQUIRE ordering on success for dec(sub)_and_test() variants) } static __always_inline __must_check bool refcount_dec_and_test(refcount_t *r) { +<<<<<<< HEAD GEN_UNARY_SUFFIXED_RMWcc(LOCK_PREFIX "decl", REFCOUNT_CHECK_LT_ZERO, r->refs.counter, "%0", e, "cx"); +======= + bool ret = GEN_UNARY_SUFFIXED_RMWcc(LOCK_PREFIX "decl", + REFCOUNT_CHECK_LT_ZERO, + r->refs.counter, e, "cx"); + + if (ret) { + smp_acquire__after_ctrl_dep(); + return true; + } + + return false; +>>>>>>> 47b8f3ab9c49 (refcount_t: Add ACQUIRE ordering on success for dec(sub)_and_test() variants) } static __always_inline __must_check diff --git a/lib/refcount.c b/lib/refcount.c index e8853a436dbb..18d890079a4b 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -32,6 +32,9 @@ * Note that the allocator is responsible for ordering things between free() * and alloc(). * + * The decrements dec_and_test() and sub_and_test() also provide acquire + * ordering on success. + * */ #include @@ -163,8 +166,8 @@ EXPORT_SYMBOL(refcount_inc_checked); * at UINT_MAX. * * Provides release memory ordering, such that prior loads and stores are done - * before, and provides a control dependency such that free() must come after. - * See the comment on top. + * before, and provides an acquire ordering on success such that free() + * must come after. * * Use of this function is not recommended for the normal reference counting * use case in which references are taken and released one at a time. In these @@ -189,7 +192,12 @@ bool refcount_sub_and_test_checked(unsigned int i, refcount_t *r) } while (!atomic_try_cmpxchg_release(&r->refs, &val, new)); - return !new; + if (!new) { + smp_acquire__after_ctrl_dep(); + return true; + } + return false; + } EXPORT_SYMBOL(refcount_sub_and_test_checked); @@ -201,8 +209,8 @@ EXPORT_SYMBOL(refcount_sub_and_test_checked); * decrement when saturated at UINT_MAX. * * Provides release memory ordering, such that prior loads and stores are done - * before, and provides a control dependency such that free() must come after. - * See the comment on top. + * before, and provides an acquire ordering on success such that free() + * must come after. * * Return: true if the resulting refcount is 0, false otherwise */ -- GitLab From 811cf3dd6b18a044b8bafa54ca001c224a9a6bbd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 6 Mar 2018 14:58:09 -0800 Subject: [PATCH 475/528] lkdtm: Relocate code to subdirectory The LKDTM modules keep expanding, and it's getting weird to have each file get a prefix. Instead, move to a subdirectory for cleaner handling. Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 039a1c42058db54692a6d4497508bd48555f29fb) --- MAINTAINERS | 5 + drivers/misc/Makefile | 2 +- drivers/misc/lkdtm/Makefile | 20 ++ drivers/misc/lkdtm/bugs.c | 257 +++++++++++++++++ drivers/misc/lkdtm/core.c | 505 ++++++++++++++++++++++++++++++++++ drivers/misc/lkdtm/heap.c | 148 ++++++++++ drivers/misc/lkdtm/lkdtm.h | 86 ++++++ drivers/misc/lkdtm/perms.c | 203 ++++++++++++++ drivers/misc/lkdtm/refcount.c | 400 +++++++++++++++++++++++++++ drivers/misc/lkdtm/rodata.c | 11 + drivers/misc/lkdtm/usercopy.c | 339 +++++++++++++++++++++++ 11 files changed, 1975 insertions(+), 1 deletion(-) create mode 100644 drivers/misc/lkdtm/Makefile create mode 100644 drivers/misc/lkdtm/bugs.c create mode 100644 drivers/misc/lkdtm/core.c create mode 100644 drivers/misc/lkdtm/heap.c create mode 100644 drivers/misc/lkdtm/lkdtm.h create mode 100644 drivers/misc/lkdtm/perms.c create mode 100644 drivers/misc/lkdtm/refcount.c create mode 100644 drivers/misc/lkdtm/rodata.c create mode 100644 drivers/misc/lkdtm/usercopy.c diff --git a/MAINTAINERS b/MAINTAINERS index 4c67775b8617..79ea69fe2889 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4955,6 +4955,11 @@ F: arch/powerpc/platforms/pasemi/ F: drivers/*/*pasemi* F: drivers/*/*/*pasemi* +LINUX KERNEL DUMP TEST MODULE (LKDTM) +M: Kees Cook +S: Maintained +F: drivers/misc/lkdtm/* + LINUX SECURITY MODULE (LSM) FRAMEWORK M: Chris Wright L: linux-security-module@vger.kernel.org diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 7156cc138f18..e25241f92c41 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o obj-$(CONFIG_ICS932S401) += ics932s401.o -obj-$(CONFIG_LKDTM) += lkdtm.o +obj-$(CONFIG_LKDTM) += lkdtm/ obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile new file mode 100644 index 000000000000..3370a4138e94 --- /dev/null +++ b/drivers/misc/lkdtm/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_LKDTM) += lkdtm.o + +lkdtm-$(CONFIG_LKDTM) += core.o +lkdtm-$(CONFIG_LKDTM) += bugs.o +lkdtm-$(CONFIG_LKDTM) += heap.o +lkdtm-$(CONFIG_LKDTM) += perms.o +lkdtm-$(CONFIG_LKDTM) += refcount.o +lkdtm-$(CONFIG_LKDTM) += rodata_objcopy.o +lkdtm-$(CONFIG_LKDTM) += usercopy.o + +KCOV_INSTRUMENT_rodata.o := n + +OBJCOPYFLAGS := +OBJCOPYFLAGS_rodata_objcopy.o := \ + --set-section-flags .text=alloc,readonly \ + --rename-section .text=.rodata +targets += rodata.o rodata_objcopy.o +$(obj)/rodata_objcopy.o: $(obj)/rodata.o FORCE + $(call if_changed,objcopy) diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c new file mode 100644 index 000000000000..7eebbdfbcacd --- /dev/null +++ b/drivers/misc/lkdtm/bugs.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This is for all the tests related to logic bugs (e.g. bad dereferences, + * bad alignment, bad loops, bad locking, bad scheduling, deep stacks, and + * lockups) along with other things that don't fit well into existing LKDTM + * test source files. + */ +#include "lkdtm.h" +#include +#include +#include +#include +#include + +struct lkdtm_list { + struct list_head node; +}; + +/* + * Make sure our attempts to over run the kernel stack doesn't trigger + * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we + * recurse past the end of THREAD_SIZE by default. + */ +#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) +#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) +#else +#define REC_STACK_SIZE (THREAD_SIZE / 8) +#endif +#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) + +static int recur_count = REC_NUM_DEFAULT; + +static DEFINE_SPINLOCK(lock_me_up); + +static int recursive_loop(int remaining) +{ + char buf[REC_STACK_SIZE]; + + /* Make sure compiler does not optimize this away. */ + memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); + if (!remaining) + return 0; + else + return recursive_loop(remaining - 1); +} + +/* If the depth is negative, use the default, otherwise keep parameter. */ +void __init lkdtm_bugs_init(int *recur_param) +{ + if (*recur_param < 0) + *recur_param = recur_count; + else + recur_count = *recur_param; +} + +void lkdtm_PANIC(void) +{ + panic("dumptest"); +} + +void lkdtm_BUG(void) +{ + BUG(); +} + +static int warn_counter; + +void lkdtm_WARNING(void) +{ + WARN(1, "Warning message trigger count: %d\n", warn_counter++); +} + +void lkdtm_EXCEPTION(void) +{ + *((volatile int *) 0) = 0; +} + +void lkdtm_LOOP(void) +{ + for (;;) + ; +} + +void lkdtm_OVERFLOW(void) +{ + (void) recursive_loop(recur_count); +} + +static noinline void __lkdtm_CORRUPT_STACK(void *stack) +{ + memset(stack, '\xff', 64); +} + +/* This should trip the stack canary, not corrupt the return address. */ +noinline void lkdtm_CORRUPT_STACK(void) +{ + /* Use default char array length that triggers stack protection. */ + char data[8] __aligned(sizeof(void *)); + + __lkdtm_CORRUPT_STACK(&data); + + pr_info("Corrupted stack containing char array ...\n"); +} + +/* Same as above but will only get a canary with -fstack-protector-strong */ +noinline void lkdtm_CORRUPT_STACK_STRONG(void) +{ + union { + unsigned short shorts[4]; + unsigned long *ptr; + } data __aligned(sizeof(void *)); + + __lkdtm_CORRUPT_STACK(&data); + + pr_info("Corrupted stack containing union ...\n"); +} + +void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void) +{ + static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5}; + u32 *p; + u32 val = 0x12345678; + + p = (u32 *)(data + 1); + if (*p == 0) + val = 0x87654321; + *p = val; +} + +void lkdtm_SOFTLOCKUP(void) +{ + preempt_disable(); + for (;;) + cpu_relax(); +} + +void lkdtm_HARDLOCKUP(void) +{ + local_irq_disable(); + for (;;) + cpu_relax(); +} + +void lkdtm_SPINLOCKUP(void) +{ + /* Must be called twice to trigger. */ + spin_lock(&lock_me_up); + /* Let sparse know we intended to exit holding the lock. */ + __release(&lock_me_up); +} + +void lkdtm_HUNG_TASK(void) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); +} + +void lkdtm_CORRUPT_LIST_ADD(void) +{ + /* + * Initially, an empty list via LIST_HEAD: + * test_head.next = &test_head + * test_head.prev = &test_head + */ + LIST_HEAD(test_head); + struct lkdtm_list good, bad; + void *target[2] = { }; + void *redirection = ⌖ + + pr_info("attempting good list addition\n"); + + /* + * Adding to the list performs these actions: + * test_head.next->prev = &good.node + * good.node.next = test_head.next + * good.node.prev = test_head + * test_head.next = good.node + */ + list_add(&good.node, &test_head); + + pr_info("attempting corrupted list addition\n"); + /* + * In simulating this "write what where" primitive, the "what" is + * the address of &bad.node, and the "where" is the address held + * by "redirection". + */ + test_head.next = redirection; + list_add(&bad.node, &test_head); + + if (target[0] == NULL && target[1] == NULL) + pr_err("Overwrite did not happen, but no BUG?!\n"); + else + pr_err("list_add() corruption not detected!\n"); +} + +void lkdtm_CORRUPT_LIST_DEL(void) +{ + LIST_HEAD(test_head); + struct lkdtm_list item; + void *target[2] = { }; + void *redirection = ⌖ + + list_add(&item.node, &test_head); + + pr_info("attempting good list removal\n"); + list_del(&item.node); + + pr_info("attempting corrupted list removal\n"); + list_add(&item.node, &test_head); + + /* As with the list_add() test above, this corrupts "next". */ + item.node.next = redirection; + list_del(&item.node); + + if (target[0] == NULL && target[1] == NULL) + pr_err("Overwrite did not happen, but no BUG?!\n"); + else + pr_err("list_del() corruption not detected!\n"); +} + +/* Test if unbalanced set_fs(KERNEL_DS)/set_fs(USER_DS) check exists. */ +void lkdtm_CORRUPT_USER_DS(void) +{ + pr_info("setting bad task size limit\n"); + set_fs(KERNEL_DS); + + /* Make sure we do not keep running with a KERNEL_DS! */ + force_sig(SIGKILL, current); +} + +/* Test that VMAP_STACK is actually allocating with a leading guard page */ +void lkdtm_STACK_GUARD_PAGE_LEADING(void) +{ + const unsigned char *stack = task_stack_page(current); + const unsigned char *ptr = stack - 1; + volatile unsigned char byte; + + pr_info("attempting bad read from page below current stack\n"); + + byte = *ptr; + + pr_err("FAIL: accessed page before stack!\n"); +} + +/* Test that VMAP_STACK is actually allocating with a trailing guard page */ +void lkdtm_STACK_GUARD_PAGE_TRAILING(void) +{ + const unsigned char *stack = task_stack_page(current); + const unsigned char *ptr = stack + THREAD_SIZE; + volatile unsigned char byte; + + pr_info("attempting bad read from page above current stack\n"); + + byte = *ptr; + + pr_err("FAIL: accessed page after stack!\n"); +} diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c new file mode 100644 index 000000000000..2154d1bfd18b --- /dev/null +++ b/drivers/misc/lkdtm/core.c @@ -0,0 +1,505 @@ +/* + * Linux Kernel Dump Test Module for testing kernel crashes conditions: + * induces system failures at predefined crashpoints and under predefined + * operational conditions in order to evaluate the reliability of kernel + * sanity checking and crash dumps obtained using different dumping + * solutions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2006 + * + * Author: Ankita Garg + * + * It is adapted from the Linux Kernel Dump Test Tool by + * Fernando Luis Vazquez Cao + * + * Debugfs support added by Simon Kagstrom + * + * See Documentation/fault-injection/provoke-crashes.txt for instructions + */ +#include "lkdtm.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_IDE +#include +#endif + +#define DEFAULT_COUNT 10 + +static int lkdtm_debugfs_open(struct inode *inode, struct file *file); +static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, + size_t count, loff_t *off); +static ssize_t direct_entry(struct file *f, const char __user *user_buf, + size_t count, loff_t *off); + +#ifdef CONFIG_KPROBES +static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs); +static ssize_t lkdtm_debugfs_entry(struct file *f, + const char __user *user_buf, + size_t count, loff_t *off); +# define CRASHPOINT_KPROBE(_symbol) \ + .kprobe = { \ + .symbol_name = (_symbol), \ + .pre_handler = lkdtm_kprobe_handler, \ + }, +# define CRASHPOINT_WRITE(_symbol) \ + (_symbol) ? lkdtm_debugfs_entry : direct_entry +#else +# define CRASHPOINT_KPROBE(_symbol) +# define CRASHPOINT_WRITE(_symbol) direct_entry +#endif + +/* Crash points */ +struct crashpoint { + const char *name; + const struct file_operations fops; + struct kprobe kprobe; +}; + +#define CRASHPOINT(_name, _symbol) \ + { \ + .name = _name, \ + .fops = { \ + .read = lkdtm_debugfs_read, \ + .llseek = generic_file_llseek, \ + .open = lkdtm_debugfs_open, \ + .write = CRASHPOINT_WRITE(_symbol) \ + }, \ + CRASHPOINT_KPROBE(_symbol) \ + } + +/* Define the possible places where we can trigger a crash point. */ +static struct crashpoint crashpoints[] = { + CRASHPOINT("DIRECT", NULL), +#ifdef CONFIG_KPROBES + CRASHPOINT("INT_HARDWARE_ENTRY", "do_IRQ"), + CRASHPOINT("INT_HW_IRQ_EN", "handle_irq_event"), + CRASHPOINT("INT_TASKLET_ENTRY", "tasklet_action"), + CRASHPOINT("FS_DEVRW", "ll_rw_block"), + CRASHPOINT("MEM_SWAPOUT", "shrink_inactive_list"), + CRASHPOINT("TIMERADD", "hrtimer_start"), + CRASHPOINT("SCSI_DISPATCH_CMD", "scsi_dispatch_cmd"), +# ifdef CONFIG_IDE + CRASHPOINT("IDE_CORE_CP", "generic_ide_ioctl"), +# endif +#endif +}; + + +/* Crash types. */ +struct crashtype { + const char *name; + void (*func)(void); +}; + +#define CRASHTYPE(_name) \ + { \ + .name = __stringify(_name), \ + .func = lkdtm_ ## _name, \ + } + +/* Define the possible types of crashes that can be triggered. */ +static const struct crashtype crashtypes[] = { + CRASHTYPE(PANIC), + CRASHTYPE(BUG), + CRASHTYPE(WARNING), + CRASHTYPE(EXCEPTION), + CRASHTYPE(LOOP), + CRASHTYPE(OVERFLOW), + CRASHTYPE(CORRUPT_LIST_ADD), + CRASHTYPE(CORRUPT_LIST_DEL), + CRASHTYPE(CORRUPT_USER_DS), + CRASHTYPE(CORRUPT_STACK), + CRASHTYPE(CORRUPT_STACK_STRONG), + CRASHTYPE(STACK_GUARD_PAGE_LEADING), + CRASHTYPE(STACK_GUARD_PAGE_TRAILING), + CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), + CRASHTYPE(OVERWRITE_ALLOCATION), + CRASHTYPE(WRITE_AFTER_FREE), + CRASHTYPE(READ_AFTER_FREE), + CRASHTYPE(WRITE_BUDDY_AFTER_FREE), + CRASHTYPE(READ_BUDDY_AFTER_FREE), + CRASHTYPE(SOFTLOCKUP), + CRASHTYPE(HARDLOCKUP), + CRASHTYPE(SPINLOCKUP), + CRASHTYPE(HUNG_TASK), + CRASHTYPE(EXEC_DATA), + CRASHTYPE(EXEC_STACK), + CRASHTYPE(EXEC_KMALLOC), + CRASHTYPE(EXEC_VMALLOC), + CRASHTYPE(EXEC_RODATA), + CRASHTYPE(EXEC_USERSPACE), + CRASHTYPE(ACCESS_USERSPACE), + CRASHTYPE(WRITE_RO), + CRASHTYPE(WRITE_RO_AFTER_INIT), + CRASHTYPE(WRITE_KERN), + CRASHTYPE(REFCOUNT_INC_OVERFLOW), + CRASHTYPE(REFCOUNT_ADD_OVERFLOW), + CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW), + CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_OVERFLOW), + CRASHTYPE(REFCOUNT_DEC_ZERO), + CRASHTYPE(REFCOUNT_DEC_NEGATIVE), + CRASHTYPE(REFCOUNT_DEC_AND_TEST_NEGATIVE), + CRASHTYPE(REFCOUNT_SUB_AND_TEST_NEGATIVE), + CRASHTYPE(REFCOUNT_INC_ZERO), + CRASHTYPE(REFCOUNT_ADD_ZERO), + CRASHTYPE(REFCOUNT_INC_SATURATED), + CRASHTYPE(REFCOUNT_DEC_SATURATED), + CRASHTYPE(REFCOUNT_ADD_SATURATED), + CRASHTYPE(REFCOUNT_INC_NOT_ZERO_SATURATED), + CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_SATURATED), + CRASHTYPE(REFCOUNT_DEC_AND_TEST_SATURATED), + CRASHTYPE(REFCOUNT_SUB_AND_TEST_SATURATED), + CRASHTYPE(REFCOUNT_TIMING), + CRASHTYPE(ATOMIC_TIMING), + CRASHTYPE(USERCOPY_HEAP_SIZE_TO), + CRASHTYPE(USERCOPY_HEAP_SIZE_FROM), + CRASHTYPE(USERCOPY_HEAP_WHITELIST_TO), + CRASHTYPE(USERCOPY_HEAP_WHITELIST_FROM), + CRASHTYPE(USERCOPY_STACK_FRAME_TO), + CRASHTYPE(USERCOPY_STACK_FRAME_FROM), + CRASHTYPE(USERCOPY_STACK_BEYOND), + CRASHTYPE(USERCOPY_KERNEL), +}; + + +/* Global kprobe entry and crashtype. */ +static struct kprobe *lkdtm_kprobe; +static struct crashpoint *lkdtm_crashpoint; +static const struct crashtype *lkdtm_crashtype; + +/* Module parameters */ +static int recur_count = -1; +module_param(recur_count, int, 0644); +MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); + +static char* cpoint_name; +module_param(cpoint_name, charp, 0444); +MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); + +static char* cpoint_type; +module_param(cpoint_type, charp, 0444); +MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ + "hitting the crash point"); + +static int cpoint_count = DEFAULT_COUNT; +module_param(cpoint_count, int, 0644); +MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ + "crash point is to be hit to trigger action"); + + +/* Return the crashtype number or NULL if the name is invalid */ +static const struct crashtype *find_crashtype(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(crashtypes); i++) { + if (!strcmp(name, crashtypes[i].name)) + return &crashtypes[i]; + } + + return NULL; +} + +/* + * This is forced noinline just so it distinctly shows up in the stackdump + * which makes validation of expected lkdtm crashes easier. + */ +static noinline void lkdtm_do_action(const struct crashtype *crashtype) +{ + if (WARN_ON(!crashtype || !crashtype->func)) + return; + crashtype->func(); +} + +static int lkdtm_register_cpoint(struct crashpoint *crashpoint, + const struct crashtype *crashtype) +{ + int ret; + + /* If this doesn't have a symbol, just call immediately. */ + if (!crashpoint->kprobe.symbol_name) { + lkdtm_do_action(crashtype); + return 0; + } + + if (lkdtm_kprobe != NULL) + unregister_kprobe(lkdtm_kprobe); + + lkdtm_crashpoint = crashpoint; + lkdtm_crashtype = crashtype; + lkdtm_kprobe = &crashpoint->kprobe; + ret = register_kprobe(lkdtm_kprobe); + if (ret < 0) { + pr_info("Couldn't register kprobe %s\n", + crashpoint->kprobe.symbol_name); + lkdtm_kprobe = NULL; + lkdtm_crashpoint = NULL; + lkdtm_crashtype = NULL; + } + + return ret; +} + +#ifdef CONFIG_KPROBES +/* Global crash counter and spinlock. */ +static int crash_count = DEFAULT_COUNT; +static DEFINE_SPINLOCK(crash_count_lock); + +/* Called by kprobe entry points. */ +static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs) +{ + unsigned long flags; + bool do_it = false; + + if (WARN_ON(!lkdtm_crashpoint || !lkdtm_crashtype)) + return 0; + + spin_lock_irqsave(&crash_count_lock, flags); + crash_count--; + pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", + lkdtm_crashpoint->name, lkdtm_crashtype->name, crash_count); + + if (crash_count == 0) { + do_it = true; + crash_count = cpoint_count; + } + spin_unlock_irqrestore(&crash_count_lock, flags); + + if (do_it) + lkdtm_do_action(lkdtm_crashtype); + + return 0; +} + +static ssize_t lkdtm_debugfs_entry(struct file *f, + const char __user *user_buf, + size_t count, loff_t *off) +{ + struct crashpoint *crashpoint = file_inode(f)->i_private; + const struct crashtype *crashtype = NULL; + char *buf; + int err; + + if (count >= PAGE_SIZE) + return -EINVAL; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, user_buf, count)) { + free_page((unsigned long) buf); + return -EFAULT; + } + /* NULL-terminate and remove enter */ + buf[count] = '\0'; + strim(buf); + + crashtype = find_crashtype(buf); + free_page((unsigned long)buf); + + if (!crashtype) + return -EINVAL; + + err = lkdtm_register_cpoint(crashpoint, crashtype); + if (err < 0) + return err; + + *off += count; + + return count; +} +#endif + +/* Generic read callback that just prints out the available crash types */ +static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, + size_t count, loff_t *off) +{ + char *buf; + int i, n, out; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + n = snprintf(buf, PAGE_SIZE, "Available crash types:\n"); + for (i = 0; i < ARRAY_SIZE(crashtypes); i++) { + n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", + crashtypes[i].name); + } + buf[n] = '\0'; + + out = simple_read_from_buffer(user_buf, count, off, + buf, n); + free_page((unsigned long) buf); + + return out; +} + +static int lkdtm_debugfs_open(struct inode *inode, struct file *file) +{ + return 0; +} + +/* Special entry to just crash directly. Available without KPROBEs */ +static ssize_t direct_entry(struct file *f, const char __user *user_buf, + size_t count, loff_t *off) +{ + const struct crashtype *crashtype; + char *buf; + + if (count >= PAGE_SIZE) + return -EINVAL; + if (count < 1) + return -EINVAL; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, user_buf, count)) { + free_page((unsigned long) buf); + return -EFAULT; + } + /* NULL-terminate and remove enter */ + buf[count] = '\0'; + strim(buf); + + crashtype = find_crashtype(buf); + free_page((unsigned long) buf); + if (!crashtype) + return -EINVAL; + + pr_info("Performing direct entry %s\n", crashtype->name); + lkdtm_do_action(crashtype); + *off += count; + + return count; +} + +static struct dentry *lkdtm_debugfs_root; + +static int __init lkdtm_module_init(void) +{ + struct crashpoint *crashpoint = NULL; + const struct crashtype *crashtype = NULL; + int ret = -EINVAL; + int i; + + /* Neither or both of these need to be set */ + if ((cpoint_type || cpoint_name) && !(cpoint_type && cpoint_name)) { + pr_err("Need both cpoint_type and cpoint_name or neither\n"); + return -EINVAL; + } + + if (cpoint_type) { + crashtype = find_crashtype(cpoint_type); + if (!crashtype) { + pr_err("Unknown crashtype '%s'\n", cpoint_type); + return -EINVAL; + } + } + + if (cpoint_name) { + for (i = 0; i < ARRAY_SIZE(crashpoints); i++) { + if (!strcmp(cpoint_name, crashpoints[i].name)) + crashpoint = &crashpoints[i]; + } + + /* Refuse unknown crashpoints. */ + if (!crashpoint) { + pr_err("Invalid crashpoint %s\n", cpoint_name); + return -EINVAL; + } + } + +#ifdef CONFIG_KPROBES + /* Set crash count. */ + crash_count = cpoint_count; +#endif + + /* Handle test-specific initialization. */ + lkdtm_bugs_init(&recur_count); + lkdtm_perms_init(); + lkdtm_usercopy_init(); + + /* Register debugfs interface */ + lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); + if (!lkdtm_debugfs_root) { + pr_err("creating root dir failed\n"); + return -ENODEV; + } + + /* Install debugfs trigger files. */ + for (i = 0; i < ARRAY_SIZE(crashpoints); i++) { + struct crashpoint *cur = &crashpoints[i]; + struct dentry *de; + + de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, + cur, &cur->fops); + if (de == NULL) { + pr_err("could not create crashpoint %s\n", cur->name); + goto out_err; + } + } + + /* Install crashpoint if one was selected. */ + if (crashpoint) { + ret = lkdtm_register_cpoint(crashpoint, crashtype); + if (ret < 0) { + pr_info("Invalid crashpoint %s\n", crashpoint->name); + goto out_err; + } + pr_info("Crash point %s of type %s registered\n", + crashpoint->name, cpoint_type); + } else { + pr_info("No crash points registered, enable through debugfs\n"); + } + + return 0; + +out_err: + debugfs_remove_recursive(lkdtm_debugfs_root); + return ret; +} + +static void __exit lkdtm_module_exit(void) +{ + debugfs_remove_recursive(lkdtm_debugfs_root); + + /* Handle test-specific clean-up. */ + lkdtm_usercopy_exit(); + + if (lkdtm_kprobe != NULL) + unregister_kprobe(lkdtm_kprobe); + + pr_info("Crash point unregistered\n"); +} + +module_init(lkdtm_module_init); +module_exit(lkdtm_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Kernel crash testing module"); diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c new file mode 100644 index 000000000000..65026d7de130 --- /dev/null +++ b/drivers/misc/lkdtm/heap.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This is for all the tests relating directly to heap memory, including + * page allocation and slab allocations. + */ +#include "lkdtm.h" +#include +#include + +/* + * This tries to stay within the next largest power-of-2 kmalloc cache + * to avoid actually overwriting anything important if it's not detected + * correctly. + */ +void lkdtm_OVERWRITE_ALLOCATION(void) +{ + size_t len = 1020; + u32 *data = kmalloc(len, GFP_KERNEL); + if (!data) + return; + + data[1024 / sizeof(u32)] = 0x12345678; + kfree(data); +} + +void lkdtm_WRITE_AFTER_FREE(void) +{ + int *base, *again; + size_t len = 1024; + /* + * The slub allocator uses the first word to store the free + * pointer in some configurations. Use the middle of the + * allocation to avoid running into the freelist + */ + size_t offset = (len / sizeof(*base)) / 2; + + base = kmalloc(len, GFP_KERNEL); + if (!base) + return; + pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]); + pr_info("Attempting bad write to freed memory at %p\n", + &base[offset]); + kfree(base); + base[offset] = 0x0abcdef0; + /* Attempt to notice the overwrite. */ + again = kmalloc(len, GFP_KERNEL); + kfree(again); + if (again != base) + pr_info("Hmm, didn't get the same memory range.\n"); +} + +void lkdtm_READ_AFTER_FREE(void) +{ + int *base, *val, saw; + size_t len = 1024; + /* + * The slub allocator uses the first word to store the free + * pointer in some configurations. Use the middle of the + * allocation to avoid running into the freelist + */ + size_t offset = (len / sizeof(*base)) / 2; + + base = kmalloc(len, GFP_KERNEL); + if (!base) { + pr_info("Unable to allocate base memory.\n"); + return; + } + + val = kmalloc(len, GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate val memory.\n"); + kfree(base); + return; + } + + *val = 0x12345678; + base[offset] = *val; + pr_info("Value in memory before free: %x\n", base[offset]); + + kfree(base); + + pr_info("Attempting bad read from freed memory\n"); + saw = base[offset]; + if (saw != *val) { + /* Good! Poisoning happened, so declare a win. */ + pr_info("Memory correctly poisoned (%x)\n", saw); + BUG(); + } + pr_info("Memory was not poisoned\n"); + + kfree(val); +} + +void lkdtm_WRITE_BUDDY_AFTER_FREE(void) +{ + unsigned long p = __get_free_page(GFP_KERNEL); + if (!p) { + pr_info("Unable to allocate free page\n"); + return; + } + + pr_info("Writing to the buddy page before free\n"); + memset((void *)p, 0x3, PAGE_SIZE); + free_page(p); + schedule(); + pr_info("Attempting bad write to the buddy page after free\n"); + memset((void *)p, 0x78, PAGE_SIZE); + /* Attempt to notice the overwrite. */ + p = __get_free_page(GFP_KERNEL); + free_page(p); + schedule(); +} + +void lkdtm_READ_BUDDY_AFTER_FREE(void) +{ + unsigned long p = __get_free_page(GFP_KERNEL); + int saw, *val; + int *base; + + if (!p) { + pr_info("Unable to allocate free page\n"); + return; + } + + val = kmalloc(1024, GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate val memory.\n"); + free_page(p); + return; + } + + base = (int *)p; + + *val = 0x12345678; + base[0] = *val; + pr_info("Value in memory before free: %x\n", base[0]); + free_page(p); + pr_info("Attempting to read from freed memory\n"); + saw = base[0]; + if (saw != *val) { + /* Good! Poisoning happened, so declare a win. */ + pr_info("Memory correctly poisoned (%x)\n", saw); + BUG(); + } + pr_info("Buddy page was not poisoned\n"); + + kfree(val); +} diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h new file mode 100644 index 000000000000..9e513dcfd809 --- /dev/null +++ b/drivers/misc/lkdtm/lkdtm.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LKDTM_H +#define __LKDTM_H + +#define pr_fmt(fmt) "lkdtm: " fmt + +#include + +/* lkdtm_bugs.c */ +void __init lkdtm_bugs_init(int *recur_param); +void lkdtm_PANIC(void); +void lkdtm_BUG(void); +void lkdtm_WARNING(void); +void lkdtm_EXCEPTION(void); +void lkdtm_LOOP(void); +void lkdtm_OVERFLOW(void); +void lkdtm_CORRUPT_STACK(void); +void lkdtm_CORRUPT_STACK_STRONG(void); +void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void); +void lkdtm_SOFTLOCKUP(void); +void lkdtm_HARDLOCKUP(void); +void lkdtm_SPINLOCKUP(void); +void lkdtm_HUNG_TASK(void); +void lkdtm_CORRUPT_LIST_ADD(void); +void lkdtm_CORRUPT_LIST_DEL(void); +void lkdtm_CORRUPT_USER_DS(void); +void lkdtm_STACK_GUARD_PAGE_LEADING(void); +void lkdtm_STACK_GUARD_PAGE_TRAILING(void); + +/* lkdtm_heap.c */ +void lkdtm_OVERWRITE_ALLOCATION(void); +void lkdtm_WRITE_AFTER_FREE(void); +void lkdtm_READ_AFTER_FREE(void); +void lkdtm_WRITE_BUDDY_AFTER_FREE(void); +void lkdtm_READ_BUDDY_AFTER_FREE(void); + +/* lkdtm_perms.c */ +void __init lkdtm_perms_init(void); +void lkdtm_WRITE_RO(void); +void lkdtm_WRITE_RO_AFTER_INIT(void); +void lkdtm_WRITE_KERN(void); +void lkdtm_EXEC_DATA(void); +void lkdtm_EXEC_STACK(void); +void lkdtm_EXEC_KMALLOC(void); +void lkdtm_EXEC_VMALLOC(void); +void lkdtm_EXEC_RODATA(void); +void lkdtm_EXEC_USERSPACE(void); +void lkdtm_ACCESS_USERSPACE(void); + +/* lkdtm_refcount.c */ +void lkdtm_REFCOUNT_INC_OVERFLOW(void); +void lkdtm_REFCOUNT_ADD_OVERFLOW(void); +void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void); +void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void); +void lkdtm_REFCOUNT_DEC_ZERO(void); +void lkdtm_REFCOUNT_DEC_NEGATIVE(void); +void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void); +void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void); +void lkdtm_REFCOUNT_INC_ZERO(void); +void lkdtm_REFCOUNT_ADD_ZERO(void); +void lkdtm_REFCOUNT_INC_SATURATED(void); +void lkdtm_REFCOUNT_DEC_SATURATED(void); +void lkdtm_REFCOUNT_ADD_SATURATED(void); +void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void); +void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void); +void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void); +void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void); +void lkdtm_REFCOUNT_TIMING(void); +void lkdtm_ATOMIC_TIMING(void); + +/* lkdtm_rodata.c */ +void lkdtm_rodata_do_nothing(void); + +/* lkdtm_usercopy.c */ +void __init lkdtm_usercopy_init(void); +void __exit lkdtm_usercopy_exit(void); +void lkdtm_USERCOPY_HEAP_SIZE_TO(void); +void lkdtm_USERCOPY_HEAP_SIZE_FROM(void); +void lkdtm_USERCOPY_HEAP_WHITELIST_TO(void); +void lkdtm_USERCOPY_HEAP_WHITELIST_FROM(void); +void lkdtm_USERCOPY_STACK_FRAME_TO(void); +void lkdtm_USERCOPY_STACK_FRAME_FROM(void); +void lkdtm_USERCOPY_STACK_BEYOND(void); +void lkdtm_USERCOPY_KERNEL(void); + +#endif diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c new file mode 100644 index 000000000000..53b85c9d16b8 --- /dev/null +++ b/drivers/misc/lkdtm/perms.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This is for all the tests related to validating kernel memory + * permissions: non-executable regions, non-writable regions, and + * even non-readable regions. + */ +#include "lkdtm.h" +#include +#include +#include +#include +#include + +/* Whether or not to fill the target memory area with do_nothing(). */ +#define CODE_WRITE true +#define CODE_AS_IS false + +/* How many bytes to copy to be sure we've copied enough of do_nothing(). */ +#define EXEC_SIZE 64 + +/* This is non-const, so it will end up in the .data section. */ +static u8 data_area[EXEC_SIZE]; + +/* This is cost, so it will end up in the .rodata section. */ +static const unsigned long rodata = 0xAA55AA55; + +/* This is marked __ro_after_init, so it should ultimately be .rodata. */ +static unsigned long ro_after_init __ro_after_init = 0x55AA5500; + +/* + * This just returns to the caller. It is designed to be copied into + * non-executable memory regions. + */ +static void do_nothing(void) +{ + return; +} + +/* Must immediately follow do_nothing for size calculuations to work out. */ +static void do_overwritten(void) +{ + pr_info("do_overwritten wasn't overwritten!\n"); + return; +} + +static noinline void execute_location(void *dst, bool write) +{ + void (*func)(void) = dst; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + if (write == CODE_WRITE) { + memcpy(dst, do_nothing, EXEC_SIZE); + flush_icache_range((unsigned long)dst, + (unsigned long)dst + EXEC_SIZE); + } + pr_info("attempting bad execution at %p\n", func); + func(); +} + +static void execute_user_location(void *dst) +{ + int copied; + + /* Intentionally crossing kernel/user memory boundary. */ + void (*func)(void) = dst; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + copied = access_process_vm(current, (unsigned long)dst, do_nothing, + EXEC_SIZE, FOLL_WRITE); + if (copied < EXEC_SIZE) + return; + pr_info("attempting bad execution at %p\n", func); + func(); +} + +void lkdtm_WRITE_RO(void) +{ + /* Explicitly cast away "const" for the test. */ + unsigned long *ptr = (unsigned long *)&rodata; + + pr_info("attempting bad rodata write at %p\n", ptr); + *ptr ^= 0xabcd1234; +} + +void lkdtm_WRITE_RO_AFTER_INIT(void) +{ + unsigned long *ptr = &ro_after_init; + + /* + * Verify we were written to during init. Since an Oops + * is considered a "success", a failure is to just skip the + * real test. + */ + if ((*ptr & 0xAA) != 0xAA) { + pr_info("%p was NOT written during init!?\n", ptr); + return; + } + + pr_info("attempting bad ro_after_init write at %p\n", ptr); + *ptr ^= 0xabcd1234; +} + +void lkdtm_WRITE_KERN(void) +{ + size_t size; + unsigned char *ptr; + + size = (unsigned long)do_overwritten - (unsigned long)do_nothing; + ptr = (unsigned char *)do_overwritten; + + pr_info("attempting bad %zu byte write at %p\n", size, ptr); + memcpy(ptr, (unsigned char *)do_nothing, size); + flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size)); + + do_overwritten(); +} + +void lkdtm_EXEC_DATA(void) +{ + execute_location(data_area, CODE_WRITE); +} + +void lkdtm_EXEC_STACK(void) +{ + u8 stack_area[EXEC_SIZE]; + execute_location(stack_area, CODE_WRITE); +} + +void lkdtm_EXEC_KMALLOC(void) +{ + u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); + execute_location(kmalloc_area, CODE_WRITE); + kfree(kmalloc_area); +} + +void lkdtm_EXEC_VMALLOC(void) +{ + u32 *vmalloc_area = vmalloc(EXEC_SIZE); + execute_location(vmalloc_area, CODE_WRITE); + vfree(vmalloc_area); +} + +void lkdtm_EXEC_RODATA(void) +{ + execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS); +} + +void lkdtm_EXEC_USERSPACE(void) +{ + unsigned long user_addr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + execute_user_location((void *)user_addr); + vm_munmap(user_addr, PAGE_SIZE); +} + +void lkdtm_ACCESS_USERSPACE(void) +{ + unsigned long user_addr, tmp = 0; + unsigned long *ptr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { + pr_warn("copy_to_user failed\n"); + vm_munmap(user_addr, PAGE_SIZE); + return; + } + + ptr = (unsigned long *)user_addr; + + pr_info("attempting bad read at %p\n", ptr); + tmp = *ptr; + tmp += 0xc0dec0de; + + pr_info("attempting bad write at %p\n", ptr); + *ptr = tmp; + + vm_munmap(user_addr, PAGE_SIZE); +} + +void __init lkdtm_perms_init(void) +{ + /* Make sure we can write to __ro_after_init values during __init */ + ro_after_init |= 0xAA; + +} diff --git a/drivers/misc/lkdtm/refcount.c b/drivers/misc/lkdtm/refcount.c new file mode 100644 index 000000000000..2b99d448e7fd --- /dev/null +++ b/drivers/misc/lkdtm/refcount.c @@ -0,0 +1,400 @@ +/* + * This is for all the tests related to refcount bugs (e.g. overflow, + * underflow, reaching zero untested, etc). + */ +#include "lkdtm.h" +#include + +#ifdef CONFIG_REFCOUNT_FULL +#define REFCOUNT_MAX (UINT_MAX - 1) +#define REFCOUNT_SATURATED UINT_MAX +#else +#define REFCOUNT_MAX INT_MAX +#define REFCOUNT_SATURATED (INT_MIN / 2) +#endif + +static void overflow_check(refcount_t *ref) +{ + switch (refcount_read(ref)) { + case REFCOUNT_SATURATED: + pr_info("Overflow detected: saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Overflow detected: unsafely reset to max\n"); + break; + default: + pr_err("Fail: refcount wrapped to %d\n", refcount_read(ref)); + } +} + +/* + * A refcount_inc() above the maximum value of the refcount implementation, + * should at least saturate, and at most also WARN. + */ +void lkdtm_REFCOUNT_INC_OVERFLOW(void) +{ + refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1); + + pr_info("attempting good refcount_inc() without overflow\n"); + refcount_dec(&over); + refcount_inc(&over); + + pr_info("attempting bad refcount_inc() overflow\n"); + refcount_inc(&over); + refcount_inc(&over); + + overflow_check(&over); +} + +/* refcount_add() should behave just like refcount_inc() above. */ +void lkdtm_REFCOUNT_ADD_OVERFLOW(void) +{ + refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1); + + pr_info("attempting good refcount_add() without overflow\n"); + refcount_dec(&over); + refcount_dec(&over); + refcount_dec(&over); + refcount_dec(&over); + refcount_add(4, &over); + + pr_info("attempting bad refcount_add() overflow\n"); + refcount_add(4, &over); + + overflow_check(&over); +} + +/* refcount_inc_not_zero() should behave just like refcount_inc() above. */ +void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void) +{ + refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX); + + pr_info("attempting bad refcount_inc_not_zero() overflow\n"); + if (!refcount_inc_not_zero(&over)) + pr_warn("Weird: refcount_inc_not_zero() reported zero\n"); + + overflow_check(&over); +} + +/* refcount_add_not_zero() should behave just like refcount_inc() above. */ +void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void) +{ + refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX); + + pr_info("attempting bad refcount_add_not_zero() overflow\n"); + if (!refcount_add_not_zero(6, &over)) + pr_warn("Weird: refcount_add_not_zero() reported zero\n"); + + overflow_check(&over); +} + +static void check_zero(refcount_t *ref) +{ + switch (refcount_read(ref)) { + case REFCOUNT_SATURATED: + pr_info("Zero detected: saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Zero detected: unsafely reset to max\n"); + break; + case 0: + pr_warn("Still at zero: refcount_inc/add() must not inc-from-0\n"); + break; + default: + pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref)); + } +} + +/* + * A refcount_dec(), as opposed to a refcount_dec_and_test(), when it hits + * zero it should either saturate (when inc-from-zero isn't protected) + * or stay at zero (when inc-from-zero is protected) and should WARN for both. + */ +void lkdtm_REFCOUNT_DEC_ZERO(void) +{ + refcount_t zero = REFCOUNT_INIT(2); + + pr_info("attempting good refcount_dec()\n"); + refcount_dec(&zero); + + pr_info("attempting bad refcount_dec() to zero\n"); + refcount_dec(&zero); + + check_zero(&zero); +} + +static void check_negative(refcount_t *ref, int start) +{ + /* + * CONFIG_REFCOUNT_FULL refuses to move a refcount at all on an + * over-sub, so we have to track our starting position instead of + * looking only at zero-pinning. + */ + if (refcount_read(ref) == start) { + pr_warn("Still at %d: refcount_inc/add() must not inc-from-0\n", + start); + return; + } + + switch (refcount_read(ref)) { + case REFCOUNT_SATURATED: + pr_info("Negative detected: saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Negative detected: unsafely reset to max\n"); + break; + default: + pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref)); + } +} + +/* A refcount_dec() going negative should saturate and may WARN. */ +void lkdtm_REFCOUNT_DEC_NEGATIVE(void) +{ + refcount_t neg = REFCOUNT_INIT(0); + + pr_info("attempting bad refcount_dec() below zero\n"); + refcount_dec(&neg); + + check_negative(&neg, 0); +} + +/* + * A refcount_dec_and_test() should act like refcount_dec() above when + * going negative. + */ +void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void) +{ + refcount_t neg = REFCOUNT_INIT(0); + + pr_info("attempting bad refcount_dec_and_test() below zero\n"); + if (refcount_dec_and_test(&neg)) + pr_warn("Weird: refcount_dec_and_test() reported zero\n"); + + check_negative(&neg, 0); +} + +/* + * A refcount_sub_and_test() should act like refcount_dec_and_test() + * above when going negative. + */ +void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void) +{ + refcount_t neg = REFCOUNT_INIT(3); + + pr_info("attempting bad refcount_sub_and_test() below zero\n"); + if (refcount_sub_and_test(5, &neg)) + pr_warn("Weird: refcount_sub_and_test() reported zero\n"); + + check_negative(&neg, 3); +} + +static void check_from_zero(refcount_t *ref) +{ + switch (refcount_read(ref)) { + case 0: + pr_info("Zero detected: stayed at zero\n"); + break; + case REFCOUNT_SATURATED: + pr_info("Zero detected: saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Zero detected: unsafely reset to max\n"); + break; + default: + pr_info("Fail: zero not detected, incremented to %d\n", + refcount_read(ref)); + } +} + +/* + * A refcount_inc() from zero should pin to zero or saturate and may WARN. + * Only CONFIG_REFCOUNT_FULL provides this protection currently. + */ +void lkdtm_REFCOUNT_INC_ZERO(void) +{ + refcount_t zero = REFCOUNT_INIT(0); + + pr_info("attempting safe refcount_inc_not_zero() from zero\n"); + if (!refcount_inc_not_zero(&zero)) { + pr_info("Good: zero detected\n"); + if (refcount_read(&zero) == 0) + pr_info("Correctly stayed at zero\n"); + else + pr_err("Fail: refcount went past zero!\n"); + } else { + pr_err("Fail: Zero not detected!?\n"); + } + + pr_info("attempting bad refcount_inc() from zero\n"); + refcount_inc(&zero); + + check_from_zero(&zero); +} + +/* + * A refcount_add() should act like refcount_inc() above when starting + * at zero. + */ +void lkdtm_REFCOUNT_ADD_ZERO(void) +{ + refcount_t zero = REFCOUNT_INIT(0); + + pr_info("attempting safe refcount_add_not_zero() from zero\n"); + if (!refcount_add_not_zero(3, &zero)) { + pr_info("Good: zero detected\n"); + if (refcount_read(&zero) == 0) + pr_info("Correctly stayed at zero\n"); + else + pr_err("Fail: refcount went past zero\n"); + } else { + pr_err("Fail: Zero not detected!?\n"); + } + + pr_info("attempting bad refcount_add() from zero\n"); + refcount_add(3, &zero); + + check_from_zero(&zero); +} + +static void check_saturated(refcount_t *ref) +{ + switch (refcount_read(ref)) { + case REFCOUNT_SATURATED: + pr_info("Saturation detected: still saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Saturation detected: unsafely reset to max\n"); + break; + default: + pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref)); + } +} + +/* + * A refcount_inc() from a saturated value should at most warn about + * being saturated already. + */ +void lkdtm_REFCOUNT_INC_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_inc() from saturated\n"); + refcount_inc(&sat); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_DEC_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_dec() from saturated\n"); + refcount_dec(&sat); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_ADD_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_dec() from saturated\n"); + refcount_add(8, &sat); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_inc_not_zero() from saturated\n"); + if (!refcount_inc_not_zero(&sat)) + pr_warn("Weird: refcount_inc_not_zero() reported zero\n"); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_add_not_zero() from saturated\n"); + if (!refcount_add_not_zero(7, &sat)) + pr_warn("Weird: refcount_add_not_zero() reported zero\n"); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_dec_and_test() from saturated\n"); + if (refcount_dec_and_test(&sat)) + pr_warn("Weird: refcount_dec_and_test() reported zero\n"); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_sub_and_test() from saturated\n"); + if (refcount_sub_and_test(8, &sat)) + pr_warn("Weird: refcount_sub_and_test() reported zero\n"); + + check_saturated(&sat); +} + +/* Used to time the existing atomic_t when used for reference counting */ +void lkdtm_ATOMIC_TIMING(void) +{ + unsigned int i; + atomic_t count = ATOMIC_INIT(1); + + for (i = 0; i < INT_MAX - 1; i++) + atomic_inc(&count); + + for (i = INT_MAX; i > 0; i--) + if (atomic_dec_and_test(&count)) + break; + + if (i != 1) + pr_err("atomic timing: out of sync up/down cycle: %u\n", i - 1); + else + pr_info("atomic timing: done\n"); +} + +/* + * This can be compared to ATOMIC_TIMING when implementing fast refcount + * protections. Looking at the number of CPU cycles tells the real story + * about performance. For example: + * cd /sys/kernel/debug/provoke-crash + * perf stat -B -- cat <(echo REFCOUNT_TIMING) > DIRECT + */ +void lkdtm_REFCOUNT_TIMING(void) +{ + unsigned int i; + refcount_t count = REFCOUNT_INIT(1); + + for (i = 0; i < INT_MAX - 1; i++) + refcount_inc(&count); + + for (i = INT_MAX; i > 0; i--) + if (refcount_dec_and_test(&count)) + break; + + if (i != 1) + pr_err("refcount: out of sync up/down cycle: %u\n", i - 1); + else + pr_info("refcount timing: done\n"); +} diff --git a/drivers/misc/lkdtm/rodata.c b/drivers/misc/lkdtm/rodata.c new file mode 100644 index 000000000000..58d180af72cf --- /dev/null +++ b/drivers/misc/lkdtm/rodata.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This includes functions that are meant to live entirely in .rodata + * (via objcopy tricks), to validate the non-executability of .rodata. + */ +#include "lkdtm.h" + +void notrace lkdtm_rodata_do_nothing(void) +{ + /* Does nothing. We just want an architecture agnostic "return". */ +} diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c new file mode 100644 index 000000000000..9725aed305bb --- /dev/null +++ b/drivers/misc/lkdtm/usercopy.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This is for all the tests related to copy_to_user() and copy_from_user() + * hardening. + */ +#include "lkdtm.h" +#include +#include +#include +#include +#include +#include + +/* + * Many of the tests here end up using const sizes, but those would + * normally be ignored by hardened usercopy, so force the compiler + * into choosing the non-const path to make sure we trigger the + * hardened usercopy checks by added "unconst" to all the const copies, + * and making sure "cache_size" isn't optimized into a const. + */ +static volatile size_t unconst = 0; +static volatile size_t cache_size = 1024; +static struct kmem_cache *whitelist_cache; + +static const unsigned char test_text[] = "This is a test.\n"; + +/* + * Instead of adding -Wno-return-local-addr, just pass the stack address + * through a function to obfuscate it from the compiler. + */ +static noinline unsigned char *trick_compiler(unsigned char *stack) +{ + return stack + 0; +} + +static noinline unsigned char *do_usercopy_stack_callee(int value) +{ + unsigned char buf[32]; + int i; + + /* Exercise stack to avoid everything living in registers. */ + for (i = 0; i < sizeof(buf); i++) { + buf[i] = value & 0xff; + } + + return trick_compiler(buf); +} + +static noinline void do_usercopy_stack(bool to_user, bool bad_frame) +{ + unsigned long user_addr; + unsigned char good_stack[32]; + unsigned char *bad_stack; + int i; + + /* Exercise stack to avoid everything living in registers. */ + for (i = 0; i < sizeof(good_stack); i++) + good_stack[i] = test_text[i % sizeof(test_text)]; + + /* This is a pointer to outside our current stack frame. */ + if (bad_frame) { + bad_stack = do_usercopy_stack_callee((uintptr_t)&bad_stack); + } else { + /* Put start address just inside stack. */ + bad_stack = task_stack_page(current) + THREAD_SIZE; + bad_stack -= sizeof(unsigned long); + } + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + if (to_user) { + pr_info("attempting good copy_to_user of local stack\n"); + if (copy_to_user((void __user *)user_addr, good_stack, + unconst + sizeof(good_stack))) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user of distant stack\n"); + if (copy_to_user((void __user *)user_addr, bad_stack, + unconst + sizeof(good_stack))) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + /* + * There isn't a safe way to not be protected by usercopy + * if we're going to write to another thread's stack. + */ + if (!bad_frame) + goto free_user; + + pr_info("attempting good copy_from_user of local stack\n"); + if (copy_from_user(good_stack, (void __user *)user_addr, + unconst + sizeof(good_stack))) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user of distant stack\n"); + if (copy_from_user(bad_stack, (void __user *)user_addr, + unconst + sizeof(good_stack))) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +} + +/* + * This checks for whole-object size validation with hardened usercopy, + * with or without usercopy whitelisting. + */ +static void do_usercopy_heap_size(bool to_user) +{ + unsigned long user_addr; + unsigned char *one, *two; + void __user *test_user_addr; + void *test_kern_addr; + size_t size = unconst + 1024; + + one = kmalloc(size, GFP_KERNEL); + two = kmalloc(size, GFP_KERNEL); + if (!one || !two) { + pr_warn("Failed to allocate kernel memory\n"); + goto free_kernel; + } + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + goto free_kernel; + } + + memset(one, 'A', size); + memset(two, 'B', size); + + test_user_addr = (void __user *)(user_addr + 16); + test_kern_addr = one + 16; + + if (to_user) { + pr_info("attempting good copy_to_user of correct size\n"); + if (copy_to_user(test_user_addr, test_kern_addr, size / 2)) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user of too large size\n"); + if (copy_to_user(test_user_addr, test_kern_addr, size)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + pr_info("attempting good copy_from_user of correct size\n"); + if (copy_from_user(test_kern_addr, test_user_addr, size / 2)) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user of too large size\n"); + if (copy_from_user(test_kern_addr, test_user_addr, size)) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +free_kernel: + kfree(one); + kfree(two); +} + +/* + * This checks for the specific whitelist window within an object. If this + * test passes, then do_usercopy_heap_size() tests will pass too. + */ +static void do_usercopy_heap_whitelist(bool to_user) +{ + unsigned long user_alloc; + unsigned char *buf = NULL; + unsigned char __user *user_addr; + size_t offset, size; + + /* Make sure cache was prepared. */ + if (!whitelist_cache) { + pr_warn("Failed to allocate kernel cache\n"); + return; + } + + /* + * Allocate a buffer with a whitelisted window in the buffer. + */ + buf = kmem_cache_alloc(whitelist_cache, GFP_KERNEL); + if (!buf) { + pr_warn("Failed to allocate buffer from whitelist cache\n"); + goto free_alloc; + } + + /* Allocate user memory we'll poke at. */ + user_alloc = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_alloc >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + goto free_alloc; + } + user_addr = (void __user *)user_alloc; + + memset(buf, 'B', cache_size); + + /* Whitelisted window in buffer, from kmem_cache_create_usercopy. */ + offset = (cache_size / 4) + unconst; + size = (cache_size / 16) + unconst; + + if (to_user) { + pr_info("attempting good copy_to_user inside whitelist\n"); + if (copy_to_user(user_addr, buf + offset, size)) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user outside whitelist\n"); + if (copy_to_user(user_addr, buf + offset - 1, size)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + pr_info("attempting good copy_from_user inside whitelist\n"); + if (copy_from_user(buf + offset, user_addr, size)) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user outside whitelist\n"); + if (copy_from_user(buf + offset - 1, user_addr, size)) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_alloc, PAGE_SIZE); +free_alloc: + if (buf) + kmem_cache_free(whitelist_cache, buf); +} + +/* Callable tests. */ +void lkdtm_USERCOPY_HEAP_SIZE_TO(void) +{ + do_usercopy_heap_size(true); +} + +void lkdtm_USERCOPY_HEAP_SIZE_FROM(void) +{ + do_usercopy_heap_size(false); +} + +void lkdtm_USERCOPY_HEAP_WHITELIST_TO(void) +{ + do_usercopy_heap_whitelist(true); +} + +void lkdtm_USERCOPY_HEAP_WHITELIST_FROM(void) +{ + do_usercopy_heap_whitelist(false); +} + +void lkdtm_USERCOPY_STACK_FRAME_TO(void) +{ + do_usercopy_stack(true, true); +} + +void lkdtm_USERCOPY_STACK_FRAME_FROM(void) +{ + do_usercopy_stack(false, true); +} + +void lkdtm_USERCOPY_STACK_BEYOND(void) +{ + do_usercopy_stack(true, false); +} + +void lkdtm_USERCOPY_KERNEL(void) +{ + unsigned long user_addr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + pr_info("attempting good copy_to_user from kernel rodata\n"); + if (copy_to_user((void __user *)user_addr, test_text, + unconst + sizeof(test_text))) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user from kernel text\n"); + if (copy_to_user((void __user *)user_addr, vm_mmap, + unconst + PAGE_SIZE)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +} + +void __init lkdtm_usercopy_init(void) +{ + /* Prepare cache that lacks SLAB_USERCOPY flag. */ + whitelist_cache = + kmem_cache_create_usercopy("lkdtm-usercopy", cache_size, + 0, 0, + cache_size / 4, + cache_size / 16, + NULL); +} + +void __exit lkdtm_usercopy_exit(void) +{ + kmem_cache_destroy(whitelist_cache); +} -- GitLab From 42e7c229f2de8672f8d81393d6d3519726a86cef Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 21 Nov 2019 11:58:53 +0000 Subject: [PATCH 476/528] locking/refcount: Define constants for saturation and max refcount values The REFCOUNT_FULL implementation uses a different saturation point than the x86 implementation, which means that the shared refcount code in lib/refcount.c (e.g. refcount_dec_not_one()) needs to be aware of the difference. Rather than duplicate the definitions from the lkdtm driver, instead move them into and update all references accordingly. Signed-off-by: Will Deacon Reviewed-by: Ard Biesheuvel Reviewed-by: Kees Cook Tested-by: Hanjun Guo Cc: Ard Biesheuvel Cc: Elena Reshetova Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: https://lkml.kernel.org/r/20191121115902.2551-2-will@kernel.org Signed-off-by: Ingo Molnar (cherry picked from commit 23e6b169c9917fbd77534f8c5f378cb073f548bd) --- drivers/misc/lkdtm/refcount.c | 8 -------- include/linux/refcount.h | 14 ++++++++++++- lib/refcount.c | 37 +++++++++++++++++++---------------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/drivers/misc/lkdtm/refcount.c b/drivers/misc/lkdtm/refcount.c index 2b99d448e7fd..7d8dd3685763 100644 --- a/drivers/misc/lkdtm/refcount.c +++ b/drivers/misc/lkdtm/refcount.c @@ -5,14 +5,6 @@ #include "lkdtm.h" #include -#ifdef CONFIG_REFCOUNT_FULL -#define REFCOUNT_MAX (UINT_MAX - 1) -#define REFCOUNT_SATURATED UINT_MAX -#else -#define REFCOUNT_MAX INT_MAX -#define REFCOUNT_SATURATED (INT_MIN / 2) -#endif - static void overflow_check(refcount_t *ref) { switch (refcount_read(ref)) { diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 069d47ebc861..996e3a6839ff 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -3,6 +3,7 @@ #include #include +#include #include struct mutex; @@ -11,7 +12,7 @@ struct mutex; * refcount_t - variant of atomic_t specialized for reference counts * @refs: atomic_t counter field * - * The counter saturates at UINT_MAX and will not move once + * The counter saturates at REFCOUNT_SATURATED and will not move once * there. This avoids wrapping the counter and causing 'spurious' * use-after-free bugs. */ @@ -55,6 +56,9 @@ extern void refcount_dec_checked(refcount_t *r); #ifdef CONFIG_REFCOUNT_FULL +#define REFCOUNT_MAX (UINT_MAX - 1) +#define REFCOUNT_SATURATED UINT_MAX + #define refcount_add_not_zero refcount_add_not_zero_checked #define refcount_add refcount_add_checked @@ -68,6 +72,14 @@ extern void refcount_sub(unsigned int i, refcount_t *r); #define refcount_dec refcount_dec_checked #else + + +#define REFCOUNT_MAX INT_MAX +#define REFCOUNT_SATURATED (INT_MIN / 2) + +# ifdef CONFIG_ARCH_HAS_REFCOUNT +# include +# else static inline __must_check bool refcount_add_not_zero(unsigned int i, refcount_t *r) { return atomic_add_unless(&r->refs, i, 0); diff --git a/lib/refcount.c b/lib/refcount.c index 18d890079a4b..33685d89fb92 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -4,8 +4,8 @@ * The interface matches the atomic_t interface (to aid in porting) but only * provides the few functions one should use for reference counting. * - * It differs in that the counter saturates at UINT_MAX and will not move once - * there. This avoids wrapping the counter and causing 'spurious' + * It differs in that the counter saturates at REFCOUNT_SATURATED and will not + * move once there. This avoids wrapping the counter and causing 'spurious' * use-after-free issues. * * Memory ordering rules are slightly relaxed wrt regular atomic_t functions @@ -47,7 +47,7 @@ * @i: the value to add to the refcount * @r: the refcount * - * Will saturate at UINT_MAX and WARN. + * Will saturate at REFCOUNT_SATURATED and WARN. * * Provides no memory ordering, it is assumed the caller has guaranteed the * object memory to be stable (RCU, etc.). It does provide a control dependency @@ -68,16 +68,17 @@ bool refcount_add_not_zero_checked(unsigned int i, refcount_t *r) if (!val) return false; - if (unlikely(val == UINT_MAX)) + if (unlikely(val == REFCOUNT_SATURATED)) return true; new = val + i; if (new < val) - new = UINT_MAX; + new = REFCOUNT_SATURATED; } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); - WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + WARN_ONCE(new == REFCOUNT_SATURATED, + "refcount_t: saturated; leaking memory.\n"); return true; } @@ -88,7 +89,7 @@ EXPORT_SYMBOL(refcount_add_not_zero_checked); * @i: the value to add to the refcount * @r: the refcount * - * Similar to atomic_add(), but will saturate at UINT_MAX and WARN. + * Similar to atomic_add(), but will saturate at REFCOUNT_SATURATED and WARN. * * Provides no memory ordering, it is assumed the caller has guaranteed the * object memory to be stable (RCU, etc.). It does provide a control dependency @@ -109,7 +110,8 @@ EXPORT_SYMBOL(refcount_add_checked); * refcount_inc_not_zero_checked - increment a refcount unless it is 0 * @r: the refcount to increment * - * Similar to atomic_inc_not_zero(), but will saturate at UINT_MAX and WARN. + * Similar to atomic_inc_not_zero(), but will saturate at REFCOUNT_SATURATED + * and WARN. * * Provides no memory ordering, it is assumed the caller has guaranteed the * object memory to be stable (RCU, etc.). It does provide a control dependency @@ -132,7 +134,8 @@ bool refcount_inc_not_zero_checked(refcount_t *r) } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); - WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + WARN_ONCE(new == REFCOUNT_SATURATED, + "refcount_t: saturated; leaking memory.\n"); return true; } @@ -142,7 +145,7 @@ EXPORT_SYMBOL(refcount_inc_not_zero_checked); * refcount_inc_checked - increment a refcount * @r: the refcount to increment * - * Similar to atomic_inc(), but will saturate at UINT_MAX and WARN. + * Similar to atomic_inc(), but will saturate at REFCOUNT_SATURATED and WARN. * * Provides no memory ordering, it is assumed the caller already has a * reference on the object. @@ -163,7 +166,7 @@ EXPORT_SYMBOL(refcount_inc_checked); * * Similar to atomic_dec_and_test(), but it will WARN, return false and * ultimately leak on underflow and will fail to decrement when saturated - * at UINT_MAX. + * at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides an acquire ordering on success such that free() @@ -181,7 +184,7 @@ bool refcount_sub_and_test_checked(unsigned int i, refcount_t *r) unsigned int new, val = atomic_read(&r->refs); do { - if (unlikely(val == UINT_MAX)) + if (unlikely(val == REFCOUNT_SATURATED)) return false; new = val - i; @@ -206,7 +209,7 @@ EXPORT_SYMBOL(refcount_sub_and_test_checked); * @r: the refcount * * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to - * decrement when saturated at UINT_MAX. + * decrement when saturated at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides an acquire ordering on success such that free() @@ -225,7 +228,7 @@ EXPORT_SYMBOL(refcount_dec_and_test_checked); * @r: the refcount * * Similar to atomic_dec(), it will WARN on underflow and fail to decrement - * when saturated at UINT_MAX. + * when saturated at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before. @@ -276,7 +279,7 @@ bool refcount_dec_not_one(refcount_t *r) unsigned int new, val = atomic_read(&r->refs); do { - if (unlikely(val == UINT_MAX)) + if (unlikely(val == REFCOUNT_SATURATED)) return true; if (val == 1) @@ -301,7 +304,7 @@ EXPORT_SYMBOL(refcount_dec_not_one); * @lock: the mutex to be locked * * Similar to atomic_dec_and_mutex_lock(), it will WARN on underflow and fail - * to decrement when saturated at UINT_MAX. + * to decrement when saturated at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides a control dependency such that free() must come after. @@ -332,7 +335,7 @@ EXPORT_SYMBOL(refcount_dec_and_mutex_lock); * @lock: the spinlock to be locked * * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to - * decrement when saturated at UINT_MAX. + * decrement when saturated at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides a control dependency such that free() must come after. -- GitLab From 3e865c201f9cfce93e93ebb6c250426f7b0145be Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 21 Nov 2019 11:58:54 +0000 Subject: [PATCH 477/528] locking/refcount: Ensure integer operands are treated as signed In preparation for changing the saturation point of REFCOUNT_FULL to INT_MIN/2, change the type of integer operands passed into the API from 'unsigned int' to 'int' so that we can avoid casting during comparisons when we don't want to fall foul of C integral conversion rules for signed and unsigned types. Since the kernel is compiled with '-fno-strict-overflow', we don't need to worry about the UB introduced by signed overflow here. Furthermore, we're already making heavy use of the atomic_t API, which operates exclusively on signed types. Signed-off-by: Will Deacon Reviewed-by: Ard Biesheuvel Reviewed-by: Kees Cook Tested-by: Hanjun Guo Cc: Ard Biesheuvel Cc: Elena Reshetova Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: https://lkml.kernel.org/r/20191121115902.2551-3-will@kernel.org Signed-off-by: Ingo Molnar (cherry picked from commit 97a1420adf0cdf0cf6f41bab0b2acf658c96b94b) --- include/linux/refcount.h | 14 +++++++------- lib/refcount.c | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 996e3a6839ff..d211cbc3d34e 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -27,7 +27,7 @@ typedef struct refcount_struct { * @r: the refcount * @n: value to which the refcount will be set */ -static inline void refcount_set(refcount_t *r, unsigned int n) +static inline void refcount_set(refcount_t *r, int n) { atomic_set(&r->refs, n); } @@ -43,13 +43,13 @@ static inline unsigned int refcount_read(const refcount_t *r) return atomic_read(&r->refs); } -extern __must_check bool refcount_add_not_zero_checked(unsigned int i, refcount_t *r); -extern void refcount_add_checked(unsigned int i, refcount_t *r); +extern __must_check bool refcount_add_not_zero_checked(int i, refcount_t *r); +extern void refcount_add_checked(int i, refcount_t *r); extern __must_check bool refcount_inc_not_zero_checked(refcount_t *r); extern void refcount_inc_checked(refcount_t *r); -extern __must_check bool refcount_sub_and_test_checked(unsigned int i, refcount_t *r); +extern __must_check bool refcount_sub_and_test_checked(int i, refcount_t *r); extern __must_check bool refcount_dec_and_test_checked(refcount_t *r); extern void refcount_dec_checked(refcount_t *r); @@ -80,12 +80,12 @@ extern void refcount_sub(unsigned int i, refcount_t *r); # ifdef CONFIG_ARCH_HAS_REFCOUNT # include # else -static inline __must_check bool refcount_add_not_zero(unsigned int i, refcount_t *r) +static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r) { return atomic_add_unless(&r->refs, i, 0); } -static inline void refcount_add(unsigned int i, refcount_t *r) +static inline void refcount_add(int i, refcount_t *r) { atomic_add(i, &r->refs); } @@ -100,7 +100,7 @@ static inline void refcount_inc(refcount_t *r) atomic_inc(&r->refs); } -static inline __must_check bool refcount_sub_and_test(unsigned int i, refcount_t *r) +static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r) { return atomic_sub_and_test(i, &r->refs); } diff --git a/lib/refcount.c b/lib/refcount.c index 33685d89fb92..6a62bda5d93b 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -60,7 +60,7 @@ * * Return: false if the passed refcount is 0, true otherwise */ -bool refcount_add_not_zero_checked(unsigned int i, refcount_t *r) +bool refcount_add_not_zero_checked(int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); @@ -100,7 +100,7 @@ EXPORT_SYMBOL(refcount_add_not_zero_checked); * cases, refcount_inc(), or one of its variants, should instead be used to * increment a reference count. */ -void refcount_add_checked(unsigned int i, refcount_t *r) +void refcount_add_checked(int i, refcount_t *r) { WARN_ONCE(!refcount_add_not_zero_checked(i, r), "refcount_t: addition on 0; use-after-free.\n"); } @@ -179,7 +179,7 @@ EXPORT_SYMBOL(refcount_inc_checked); * * Return: true if the resulting refcount is 0, false otherwise */ -bool refcount_sub_and_test_checked(unsigned int i, refcount_t *r) +bool refcount_sub_and_test_checked(int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); -- GitLab From dbeda1217a7480ad80d558e82bf59c5cabd3a25c Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 21 Nov 2019 11:58:55 +0000 Subject: [PATCH 478/528] locking/refcount: Remove unused refcount_*_checked() variants The full-fat refcount implementation is exposed via a set of functions suffixed with "_checked()", the idea being that code can choose to use the more expensive, yet more secure implementation on a case-by-case basis. In reality, this hasn't happened, so with a grand total of zero users, let's remove the checked variants for now by simply dropping the suffix and predicating the out-of-line functions on CONFIG_REFCOUNT_FULL=y. Signed-off-by: Will Deacon Reviewed-by: Ard Biesheuvel Reviewed-by: Kees Cook Tested-by: Hanjun Guo Cc: Ard Biesheuvel Cc: Elena Reshetova Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: https://lkml.kernel.org/r/20191121115902.2551-4-will@kernel.org Signed-off-by: Ingo Molnar (cherry picked from commit 7221762c48c6bbbcc6cc51d8b803c06930215e34) --- include/linux/refcount.h | 26 ++++++------------- lib/refcount.c | 54 +++++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/include/linux/refcount.h b/include/linux/refcount.h index d211cbc3d34e..0e4aae151d3f 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -43,33 +43,23 @@ static inline unsigned int refcount_read(const refcount_t *r) return atomic_read(&r->refs); } -extern __must_check bool refcount_add_not_zero_checked(int i, refcount_t *r); -extern void refcount_add_checked(int i, refcount_t *r); - -extern __must_check bool refcount_inc_not_zero_checked(refcount_t *r); -extern void refcount_inc_checked(refcount_t *r); - -extern __must_check bool refcount_sub_and_test_checked(int i, refcount_t *r); - -extern __must_check bool refcount_dec_and_test_checked(refcount_t *r); -extern void refcount_dec_checked(refcount_t *r); - #ifdef CONFIG_REFCOUNT_FULL #define REFCOUNT_MAX (UINT_MAX - 1) #define REFCOUNT_SATURATED UINT_MAX -#define refcount_add_not_zero refcount_add_not_zero_checked -#define refcount_add refcount_add_checked +extern __must_check bool refcount_add_not_zero(int i, refcount_t *r); +extern void refcount_add(int i, refcount_t *r); -#define refcount_inc_not_zero refcount_inc_not_zero_checked -#define refcount_inc refcount_inc_checked +extern __must_check bool refcount_inc_not_zero(refcount_t *r); +extern void refcount_inc(refcount_t *r); -#define refcount_sub_and_test refcount_sub_and_test_checked +extern __must_check bool refcount_sub_and_test(int i, refcount_t *r); extern void refcount_sub(unsigned int i, refcount_t *r); -#define refcount_dec_and_test refcount_dec_and_test_checked -#define refcount_dec refcount_dec_checked + +extern __must_check bool refcount_dec_and_test(refcount_t *r); +extern void refcount_dec(refcount_t *r); #else diff --git a/lib/refcount.c b/lib/refcount.c index 6a62bda5d93b..e67419c90d4f 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -42,8 +42,10 @@ #include #include +#ifdef CONFIG_REFCOUNT_FULL + /** - * refcount_add_not_zero_checked - add a value to a refcount unless it is 0 + * refcount_add_not_zero - add a value to a refcount unless it is 0 * @i: the value to add to the refcount * @r: the refcount * @@ -60,7 +62,7 @@ * * Return: false if the passed refcount is 0, true otherwise */ -bool refcount_add_not_zero_checked(int i, refcount_t *r) +bool refcount_add_not_zero(int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); @@ -82,10 +84,10 @@ bool refcount_add_not_zero_checked(int i, refcount_t *r) return true; } -EXPORT_SYMBOL(refcount_add_not_zero_checked); +EXPORT_SYMBOL(refcount_add_not_zero); /** - * refcount_add_checked - add a value to a refcount + * refcount_add - add a value to a refcount * @i: the value to add to the refcount * @r: the refcount * @@ -100,14 +102,14 @@ EXPORT_SYMBOL(refcount_add_not_zero_checked); * cases, refcount_inc(), or one of its variants, should instead be used to * increment a reference count. */ -void refcount_add_checked(int i, refcount_t *r) +void refcount_add(int i, refcount_t *r) { - WARN_ONCE(!refcount_add_not_zero_checked(i, r), "refcount_t: addition on 0; use-after-free.\n"); + WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); } -EXPORT_SYMBOL(refcount_add_checked); +EXPORT_SYMBOL(refcount_add); /** - * refcount_inc_not_zero_checked - increment a refcount unless it is 0 + * refcount_inc_not_zero - increment a refcount unless it is 0 * @r: the refcount to increment * * Similar to atomic_inc_not_zero(), but will saturate at REFCOUNT_SATURATED @@ -119,7 +121,7 @@ EXPORT_SYMBOL(refcount_add_checked); * * Return: true if the increment was successful, false otherwise */ -bool refcount_inc_not_zero_checked(refcount_t *r) +bool refcount_inc_not_zero(refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); @@ -139,10 +141,10 @@ bool refcount_inc_not_zero_checked(refcount_t *r) return true; } -EXPORT_SYMBOL(refcount_inc_not_zero_checked); +EXPORT_SYMBOL(refcount_inc_not_zero); /** - * refcount_inc_checked - increment a refcount + * refcount_inc - increment a refcount * @r: the refcount to increment * * Similar to atomic_inc(), but will saturate at REFCOUNT_SATURATED and WARN. @@ -153,14 +155,14 @@ EXPORT_SYMBOL(refcount_inc_not_zero_checked); * Will WARN if the refcount is 0, as this represents a possible use-after-free * condition. */ -void refcount_inc_checked(refcount_t *r) +void refcount_inc(refcount_t *r) { - WARN_ONCE(!refcount_inc_not_zero_checked(r), "refcount_t: increment on 0; use-after-free.\n"); + WARN_ONCE(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); } -EXPORT_SYMBOL(refcount_inc_checked); +EXPORT_SYMBOL(refcount_inc); /** - * refcount_sub_and_test_checked - subtract from a refcount and test if it is 0 + * refcount_sub_and_test - subtract from a refcount and test if it is 0 * @i: amount to subtract from the refcount * @r: the refcount * @@ -179,7 +181,7 @@ EXPORT_SYMBOL(refcount_inc_checked); * * Return: true if the resulting refcount is 0, false otherwise */ -bool refcount_sub_and_test_checked(int i, refcount_t *r) +bool refcount_sub_and_test(int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); @@ -202,10 +204,10 @@ bool refcount_sub_and_test_checked(int i, refcount_t *r) return false; } -EXPORT_SYMBOL(refcount_sub_and_test_checked); +EXPORT_SYMBOL(refcount_sub_and_test); /** - * refcount_dec_and_test_checked - decrement a refcount and test if it is 0 + * refcount_dec_and_test - decrement a refcount and test if it is 0 * @r: the refcount * * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to @@ -217,14 +219,14 @@ EXPORT_SYMBOL(refcount_sub_and_test_checked); * * Return: true if the resulting refcount is 0, false otherwise */ -bool refcount_dec_and_test_checked(refcount_t *r) +bool refcount_dec_and_test(refcount_t *r) { - return refcount_sub_and_test_checked(1, r); + return refcount_sub_and_test(1, r); } -EXPORT_SYMBOL(refcount_dec_and_test_checked); +EXPORT_SYMBOL(refcount_dec_and_test); /** - * refcount_dec_checked - decrement a refcount + * refcount_dec - decrement a refcount * @r: the refcount * * Similar to atomic_dec(), it will WARN on underflow and fail to decrement @@ -233,11 +235,13 @@ EXPORT_SYMBOL(refcount_dec_and_test_checked); * Provides release memory ordering, such that prior loads and stores are done * before. */ -void refcount_dec_checked(refcount_t *r) +void refcount_dec(refcount_t *r) { - WARN_ONCE(refcount_dec_and_test_checked(r), "refcount_t: decrement hit 0; leaking memory.\n"); + WARN_ONCE(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); } -EXPORT_SYMBOL(refcount_dec_checked); +EXPORT_SYMBOL(refcount_dec); + +#endif /* CONFIG_REFCOUNT_FULL */ /** * refcount_dec_if_one - decrement a refcount if it is 1 -- GitLab From 68d4867a9ff1aa2f17ae16fd67f1aa42a3d46b2e Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 21 Nov 2019 11:58:54 +0000 Subject: [PATCH 479/528] locking/refcount: Ensure integer operands are treated as signed In preparation for changing the saturation point of REFCOUNT_FULL to INT_MIN/2, change the type of integer operands passed into the API from 'unsigned int' to 'int' so that we can avoid casting during comparisons when we don't want to fall foul of C integral conversion rules for signed and unsigned types. Since the kernel is compiled with '-fno-strict-overflow', we don't need to worry about the UB introduced by signed overflow here. Furthermore, we're already making heavy use of the atomic_t API, which operates exclusively on signed types. Signed-off-by: Will Deacon Reviewed-by: Ard Biesheuvel Reviewed-by: Kees Cook Tested-by: Hanjun Guo Cc: Ard Biesheuvel Cc: Elena Reshetova Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: https://lkml.kernel.org/r/20191121115902.2551-3-will@kernel.org Signed-off-by: Ingo Molnar (cherry picked from commit 97a1420adf0cdf0cf6f41bab0b2acf658c96b94b) --- include/linux/refcount.h | 12 ++++++++++++ lib/refcount.c | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 0e4aae151d3f..6b1916808104 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -43,6 +43,18 @@ static inline unsigned int refcount_read(const refcount_t *r) return atomic_read(&r->refs); } + +extern __must_check bool refcount_add_not_zero_checked(int i, refcount_t *r); +extern void refcount_add_checked(int i, refcount_t *r); + +extern __must_check bool refcount_inc_not_zero_checked(refcount_t *r); +extern void refcount_inc_checked(refcount_t *r); + +extern __must_check bool refcount_sub_and_test_checked(int i, refcount_t *r); + +extern __must_check bool refcount_dec_and_test_checked(refcount_t *r); +extern void refcount_dec_checked(refcount_t *r); + #ifdef CONFIG_REFCOUNT_FULL #define REFCOUNT_MAX (UINT_MAX - 1) diff --git a/lib/refcount.c b/lib/refcount.c index e67419c90d4f..3634fd48a8ac 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -62,7 +62,7 @@ * * Return: false if the passed refcount is 0, true otherwise */ -bool refcount_add_not_zero(int i, refcount_t *r) +bool refcount_add_not_zero_checked(int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); @@ -102,7 +102,7 @@ EXPORT_SYMBOL(refcount_add_not_zero); * cases, refcount_inc(), or one of its variants, should instead be used to * increment a reference count. */ -void refcount_add(int i, refcount_t *r) +void refcount_add_checked(int i, refcount_t *r) { WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); } @@ -181,7 +181,7 @@ EXPORT_SYMBOL(refcount_inc); * * Return: true if the resulting refcount is 0, false otherwise */ -bool refcount_sub_and_test(int i, refcount_t *r) +bool refcount_sub_and_test_checked(int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); -- GitLab From 2a09a3a67a5aa05dc290848dabe64458d0754ddc Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 21 Nov 2019 11:58:55 +0000 Subject: [PATCH 480/528] locking/refcount: Remove unused refcount_*_checked() variants The full-fat refcount implementation is exposed via a set of functions suffixed with "_checked()", the idea being that code can choose to use the more expensive, yet more secure implementation on a case-by-case basis. In reality, this hasn't happened, so with a grand total of zero users, let's remove the checked variants for now by simply dropping the suffix and predicating the out-of-line functions on CONFIG_REFCOUNT_FULL=y. Signed-off-by: Will Deacon Reviewed-by: Ard Biesheuvel Reviewed-by: Kees Cook Tested-by: Hanjun Guo Cc: Ard Biesheuvel Cc: Elena Reshetova Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: https://lkml.kernel.org/r/20191121115902.2551-4-will@kernel.org Signed-off-by: Ingo Molnar (cherry picked from commit 7221762c48c6bbbcc6cc51d8b803c06930215e34) --- include/linux/refcount.h | 17 +++++------------ lib/refcount.c | 6 +++--- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 6b1916808104..5ae19ccd85a6 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -43,18 +43,6 @@ static inline unsigned int refcount_read(const refcount_t *r) return atomic_read(&r->refs); } - -extern __must_check bool refcount_add_not_zero_checked(int i, refcount_t *r); -extern void refcount_add_checked(int i, refcount_t *r); - -extern __must_check bool refcount_inc_not_zero_checked(refcount_t *r); -extern void refcount_inc_checked(refcount_t *r); - -extern __must_check bool refcount_sub_and_test_checked(int i, refcount_t *r); - -extern __must_check bool refcount_dec_and_test_checked(refcount_t *r); -extern void refcount_dec_checked(refcount_t *r); - #ifdef CONFIG_REFCOUNT_FULL #define REFCOUNT_MAX (UINT_MAX - 1) @@ -70,6 +58,11 @@ extern __must_check bool refcount_sub_and_test(int i, refcount_t *r); extern void refcount_sub(unsigned int i, refcount_t *r); +extern __must_check bool refcount_inc_not_zero(refcount_t *r); +extern void refcount_inc(refcount_t *r); + +extern __must_check bool refcount_sub_and_test(int i, refcount_t *r); + extern __must_check bool refcount_dec_and_test(refcount_t *r); extern void refcount_dec(refcount_t *r); diff --git a/lib/refcount.c b/lib/refcount.c index 3634fd48a8ac..e67419c90d4f 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -62,7 +62,7 @@ * * Return: false if the passed refcount is 0, true otherwise */ -bool refcount_add_not_zero_checked(int i, refcount_t *r) +bool refcount_add_not_zero(int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); @@ -102,7 +102,7 @@ EXPORT_SYMBOL(refcount_add_not_zero); * cases, refcount_inc(), or one of its variants, should instead be used to * increment a reference count. */ -void refcount_add_checked(int i, refcount_t *r) +void refcount_add(int i, refcount_t *r) { WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); } @@ -181,7 +181,7 @@ EXPORT_SYMBOL(refcount_inc); * * Return: true if the resulting refcount is 0, false otherwise */ -bool refcount_sub_and_test_checked(int i, refcount_t *r) +bool refcount_sub_and_test(int i, refcount_t *r) { unsigned int new, val = atomic_read(&r->refs); -- GitLab From 900d7c8f739ec92df6710e1dacee8a1bd52c2f40 Mon Sep 17 00:00:00 2001 From: threader Date: Thu, 29 Jul 2021 22:25:55 +0200 Subject: [PATCH 481/528] lib: refcount: fix unterminated ifdef after importing --- include/linux/refcount.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 5ae19ccd85a6..9c63f5bcd91d 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -114,6 +114,7 @@ static inline void refcount_dec(refcount_t *r) { atomic_dec(&r->refs); } +# endif /* !CONFIG_ARCH_HAS_REFCOUNT */ #endif /* CONFIG_REFCOUNT_FULL */ extern __must_check bool refcount_dec_if_one(refcount_t *r); -- GitLab From 70fe8582735c80f33454e2285ff4b7137d0ec5f3 Mon Sep 17 00:00:00 2001 From: threader Date: Thu, 29 Jul 2021 22:33:29 +0200 Subject: [PATCH 482/528] BACKPORT: as per https://lore.kernel.org/patchwork/patch/877341/ define DEFINE_SHOW_ATTRIBUTE helper --- include/linux/seq_file.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 2fe007f1c49d..692e03a84bcf 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -158,6 +158,20 @@ int seq_put_decimal_ull(struct seq_file *m, char delimiter, int seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num); +#define DEFINE_SHOW_ATTRIBUTE(__name) \ +static int __name ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __name ## _show, inode->i_private); \ +} \ + \ +static const struct file_operations __name ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __name ## _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + static inline struct user_namespace *seq_user_ns(struct seq_file *seq) { #ifdef CONFIG_USER_NS -- GitLab From f74d4093ed77126c0ebece59670546c9eee68aeb Mon Sep 17 00:00:00 2001 From: threader Date: Thu, 29 Jul 2021 22:52:29 +0200 Subject: [PATCH 483/528] ANDROID: binderfs: Clean up after git pick conflict --- drivers/android/binderfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index e492b25b9dc5..5d8012144895 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -731,7 +731,6 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) return init_binder_logs(sb); return 0; ->>>>>>> 0e13e452dafc (binder: Add stats, state and transactions files) } static struct dentry *binderfs_mount(struct file_system_type *fs_type, -- GitLab From f9b94b00eddea80f88bd074241ebf4c86458c308 Mon Sep 17 00:00:00 2001 From: threader Date: Thu, 29 Jul 2021 23:41:45 +0200 Subject: [PATCH 484/528] BACKPORT: headers: atomic: add atomic_try_cmpxchg as per https://patchwork.kernel.org/project/backports/patch/20170908112511.7132-1-johannes@sipsolutions.net --- include/linux/atomic.h | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/include/linux/atomic.h b/include/linux/atomic.h index fef3a809e7cf..411cc4b26652 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -39,6 +39,55 @@ static inline void __deprecated smp_mb__after_atomic_dec(void) } #endif +/* atomic_cmpxchg_relaxed */ +#ifndef atomic_cmpxchg_relaxed +#define atomic_cmpxchg_relaxed atomic_cmpxchg +#define atomic_cmpxchg_acquire atomic_cmpxchg +#define atomic_cmpxchg_release atomic_cmpxchg + +#else /* atomic_cmpxchg_relaxed */ + +#ifndef atomic_cmpxchg_acquire +#define atomic_cmpxchg_acquire(...) \ + __atomic_op_acquire(atomic_cmpxchg, __VA_ARGS__) +#endif + +#ifndef atomic_cmpxchg_release +#define atomic_cmpxchg_release(...) \ + __atomic_op_release(atomic_cmpxchg, __VA_ARGS__) +#endif + +#ifndef atomic_cmpxchg +#define atomic_cmpxchg(...) \ + __atomic_op_fence(atomic_cmpxchg, __VA_ARGS__) +#endif +#endif /* atomic_cmpxchg_relaxed */ + +/* these were introduced together, so just a single check is enough */ +#ifndef atomic_try_cmpxchg_acquire +#ifndef atomic_try_cmpxchg +#define __atomic_try_cmpxchg(type, _p, _po, _n) \ +({ \ + typeof(_po) __po = (_po); \ + typeof(*(_po)) __r, __o = *__po; \ + __r = atomic_cmpxchg##type((_p), __o, (_n)); \ + if (unlikely(__r != __o)) \ + *__po = __r; \ + likely(__r == __o); \ +}) + +#define atomic_try_cmpxchg(_p, _po, _n) __atomic_try_cmpxchg(, _p, _po, _n) +#define atomic_try_cmpxchg_relaxed(_p, _po, _n) __atomic_try_cmpxchg(_relaxed, _p, _po, _n) +#define atomic_try_cmpxchg_acquire(_p, _po, _n) __atomic_try_cmpxchg(_acquire, _p, _po, _n) +#define atomic_try_cmpxchg_release(_p, _po, _n) __atomic_try_cmpxchg(_release, _p, _po, _n) +#else /* atomic_try_cmpxchg */ +#define atomic_try_cmpxchg_relaxed atomic_try_cmpxchg +#define atomic_try_cmpxchg_acquire atomic_try_cmpxchg +#define atomic_try_cmpxchg_release atomic_try_cmpxchg +#endif /* atomic_try_cmpxchg */ + +#endif /* atomic_try_cmpxchg_acquire */ + /** * atomic_add_unless - add unless the number is already a given value * @v: pointer of type atomic_t -- GitLab From c502bed6bd9dd55438401ae7df02f887e634d6e8 Mon Sep 17 00:00:00 2001 From: threader Date: Thu, 29 Jul 2021 23:48:57 +0200 Subject: [PATCH 485/528] BINDER: comment out incompatible code for now --- drivers/android/binder.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 4757befdc284..1ca66045ecaa 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1212,8 +1212,8 @@ static void binder_transaction_priority(struct task_struct *task, struct binder_priority node_prio, bool inherit_rt) { - bool inherit_fifo = t->buffer->target_node->proc->context->inherit_fifo_prio; - struct binder_priority desired_prio; + //bool inherit_fifo = t->buffer->target_node->proc->context->inherit_fifo_prio; + struct binder_priority desired_prio = t->priority; if (t->set_priority_called) return; @@ -1222,7 +1222,7 @@ static void binder_transaction_priority(struct task_struct *task, t->saved_priority.sched_policy = task->policy; t->saved_priority.prio = task->normal_prio; - if (!inherit_rt && is_rt_policy(desired_prio.sched_policy) && !inherit_fifo) { + if (!inherit_rt && is_rt_policy(desired_prio.sched_policy)) { desired_prio.prio = NICE_TO_PRIO(0); desired_prio.sched_policy = SCHED_NORMAL; } else { @@ -4775,7 +4775,7 @@ static int binder_ioctl_write_read(struct file *filp, out: return ret; } - +/* static int binder_ioctl_set_inherit_fifo_prio(struct file *filp) { int ret = 0; @@ -4802,7 +4802,7 @@ static int binder_ioctl_set_inherit_fifo_prio(struct file *filp) mutex_unlock(&context->context_mgr_node_lock); return ret; } - +*/ static int binder_ioctl_set_ctx_mgr(struct file *filp, struct flat_binder_object *fbo) { @@ -5042,11 +5042,11 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (ret) goto err; break; - case BINDER_SET_INHERIT_FIFO_PRIO: + /*case BINDER_SET_INHERIT_FIFO_PRIO: ret = binder_ioctl_set_inherit_fifo_prio(filp); if (ret) goto err; - break; + break;*/ case BINDER_THREAD_EXIT: binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n", @@ -5306,7 +5306,7 @@ static int binder_open(struct inode *nodp, struct file *filp) proc->default_priority.prio = NICE_TO_PRIO(0); } - proc->default_priority = task_nice(current); + //proc->default_priority = task_nice(current); /* binderfs stashes devices in i_private */ if (is_binderfs_device(nodp)) { binder_dev = nodp->i_private; @@ -5362,7 +5362,7 @@ static int binder_open(struct inode *nodp, struct file *filp) * contexts of a given PID. */ binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc, - strbuf, &proc_fops, (void *)(unsigned long)proc->pid); + strbuf, &binder_proc_fops, (void *)(unsigned long)proc->pid); if (!IS_ERR(binderfs_entry)) { proc->binderfs_entry = binderfs_entry; } else { @@ -5495,6 +5495,8 @@ static void binder_deferred_release(struct binder_proc *proc) { struct binder_context *context = proc->context; struct rb_node *n; + struct binder_device *device; + int threads, nodes, incoming_refs, outgoing_refs, active_transactions; BUG_ON(proc->files); @@ -5983,7 +5985,7 @@ static void print_binder_proc_stats(struct seq_file *m, seq_printf(m, "proc %d\n", proc->pid); seq_printf(m, "context %s\n", proc->context->name); - seq_printf(m, "context FIFO: %d\n", proc->context->inherit_fifo_prio); + //seq_printf(m, "context FIFO: %d\n", proc->context->inherit_fifo_prio); count = 0; ready_threads = 0; binder_inner_proc_lock(proc); -- GitLab From 31fa9ca72f3861bf0af785683c90ba7677906f37 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 11 Mar 2020 11:53:09 +0100 Subject: [PATCH 486/528] binderfs: use refcount for binder control devices too Binderfs binder-control devices are cleaned up via binderfs_evict_inode too() which will use refcount_dec_and_test(). However, we missed to set the refcount for binderfs binder-control devices and so we underflowed when the binderfs instance got unmounted. Pretty obvious oversight and should have been part of the more general UAF fix. The good news is that having test cases (suprisingly) helps. Technically, we could detect that we're about to cleanup the binder-control dentry in binderfs_evict_inode() and then simply clean it up. But that makes the assumption that the binder driver itself will never make use of a binderfs binder-control device after the binderfs instance it belongs to has been unmounted and the superblock for it been destroyed. While it is unlikely to ever come to this let's be on the safe side. Performance-wise this also really doesn't matter since the binder-control device is only every really when creating the binderfs filesystem or creating additional binder devices. Both operations are pretty rare. Fixes: f0fe2c0f050d ("binder: prevent UAF for binderfs devices II") Link: https://lore.kernel.org/r/CA+G9fYusdfg7PMfC9Xce-xLT7NiyKSbgojpK35GOm=Pf9jXXrA@mail.gmail.com Reported-by: Naresh Kamboju Cc: stable@vger.kernel.org Signed-off-by: Christian Brauner Acked-by: Todd Kjos Link: https://lore.kernel.org/r/20200311105309.1742827-1-christian.brauner@ubuntu.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 211b64e4b5b6bd5fdc19cd525c2cc9a90e6b0ec9) --- drivers/android/binderfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 5d8012144895..209bdf6b2310 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -449,6 +449,7 @@ static int binderfs_binder_ctl_create(struct super_block *sb) inode->i_uid = info->root_uid; inode->i_gid = info->root_gid; + refcount_set(&device->ref, 1); device->binderfs_inode = inode; device->miscdev.minor = minor; -- GitLab From cf8002624212cacda23833b351b4cf39a464f897 Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Sat, 11 Apr 2020 22:51:51 +0800 Subject: [PATCH 487/528] binderfs: Fix binderfs.c selftest compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix missing braces compilation warning in the ARM compiler environment: drivers/android/binderfs.c: In function 'binderfs_fill_super': drivers/android/binderfs.c:650:9: warning: missing braces around initializer [-Wmissing-braces] struct binderfs_device device_info = { 0 }; drivers/android/binderfs.c:650:9: warning: (near initialization for ‘device_info.name’) [-Wmissing-braces] Acked-by: Christian Brauner Signed-off-by: Tang Bin Link: https://lore.kernel.org/r/20200411145151.5576-1-tangbin@cmss.chinamobile.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 7a1c4f28ead628d44773ff90ae2414f8e7ea31ad) --- drivers/android/binderfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 209bdf6b2310..422f70d07327 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -659,6 +659,7 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) int ret; struct binderfs_info *info; struct inode *inode = NULL; + struct binderfs_device device_info = {}; sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; -- GitLab From 6dfcc3accb5cf5e3aa9faaf515d3980a21fccfbd Mon Sep 17 00:00:00 2001 From: Mrinal Pandey Date: Fri, 24 Jul 2020 18:44:33 +0530 Subject: [PATCH 488/528] drivers: android: Fix a variable declaration coding style issue Add a blank line after variable declarations as suggested by checkpatch. Signed-off-by: Mrinal Pandey Link: https://lore.kernel.org/r/20200724131433.stf3ycooogawyzb3@mrinalpandey Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 81195f9689ac16c01c894c756b925e28e546b123) --- drivers/android/binderfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 422f70d07327..9a52bfc4f4e7 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -361,6 +361,7 @@ static const struct super_operations binderfs_super_ops = { static inline bool is_binderfs_control_device(const struct dentry *dentry) { struct binderfs_info *info = dentry->d_sb->s_fs_info; + return info->control_dentry == dentry; } -- GitLab From 69984d98bbd1338d635a3d4105e7db49617f6c6f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 18 Aug 2020 19:22:45 +0800 Subject: [PATCH 489/528] binderfs: make symbol 'binderfs_fs_parameters' static The sparse tool complains as follows: drivers/android/binderfs.c:66:32: warning: symbol 'binderfs_fs_parameters' was not declared. Should it be static? This variable is not used outside of binderfs.c, so this commit marks it static. Fixes: 095cf502b31e ("binderfs: port to new mount api") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Acked-by: Christian Brauner Link: https://lore.kernel.org/r/20200818112245.43891-1-weiyongjun1@huawei.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 89320020d967e8f7affbc4488b85860b3a64c4c4) --- drivers/android/binderfs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 9a52bfc4f4e7..874fd0387210 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -65,7 +65,13 @@ static const match_table_t tokens = { { Opt_err, NULL } }; -static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) +static const struct fs_parameter_spec binderfs_fs_parameters[] = { + fsparam_u32("max", Opt_max), + fsparam_enum("stats", Opt_stats_mode, binderfs_param_stats), + {} +}; + +static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb) { return inode->i_sb->s_fs_info; } -- GitLab From 559a8f01144b0e53b5cd42f047e892e3870a7d60 Mon Sep 17 00:00:00 2001 From: threader Date: Fri, 30 Jul 2021 00:14:44 +0200 Subject: [PATCH 490/528] BINDER: use compiler.h not compiler_types which we dont have, dare i say yet --- drivers/android/binderfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 874fd0387210..b01618bae2a9 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#include +#include #include #include #include @@ -29,7 +29,7 @@ #include #include #include -#include +//#include #include #include #include -- GitLab From aeb37af2faa9a146fe49db3b21994739ab37d1c0 Mon Sep 17 00:00:00 2001 From: threader Date: Fri, 30 Jul 2021 00:14:56 +0200 Subject: [PATCH 491/528] Revert "binderfs: make symbol 'binderfs_fs_parameters' static" This reverts commit a9684760b75394c153b0a0132153e55788df20b4. --- drivers/android/binderfs.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index b01618bae2a9..aeeb6feab5ab 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -65,13 +65,7 @@ static const match_table_t tokens = { { Opt_err, NULL } }; -static const struct fs_parameter_spec binderfs_fs_parameters[] = { - fsparam_u32("max", Opt_max), - fsparam_enum("stats", Opt_stats_mode, binderfs_param_stats), - {} -}; - -static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb) +static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) { return inode->i_sb->s_fs_info; } -- GitLab From 915962321be545ece42076de9038498e453ca1cb Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Mon, 22 Jun 2020 13:07:15 -0700 Subject: [PATCH 492/528] binder: fix null deref of proc->context The binder driver makes the assumption proc->context pointer is invariant after initialization (as documented in the kerneldoc header for struct proc). However, in commit f0fe2c0f050d ("binder: prevent UAF for binderfs devices II") proc->context is set to NULL during binder_deferred_release(). Another proc was in the middle of setting up a transaction to the dying process and crashed on a NULL pointer deref on "context" which is a local set to &proc->context: new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1; Here's the stack: [ 5237.855435] Call trace: [ 5237.855441] binder_get_ref_for_node_olocked+0x100/0x2ec [ 5237.855446] binder_inc_ref_for_node+0x140/0x280 [ 5237.855451] binder_translate_binder+0x1d0/0x388 [ 5237.855456] binder_transaction+0x2228/0x3730 [ 5237.855461] binder_thread_write+0x640/0x25bc [ 5237.855466] binder_ioctl_write_read+0xb0/0x464 [ 5237.855471] binder_ioctl+0x30c/0x96c [ 5237.855477] do_vfs_ioctl+0x3e0/0x700 [ 5237.855482] __arm64_sys_ioctl+0x78/0xa4 [ 5237.855488] el0_svc_common+0xb4/0x194 [ 5237.855493] el0_svc_handler+0x74/0x98 [ 5237.855497] el0_svc+0x8/0xc The fix is to move the kfree of the binder_device to binder_free_proc() so the binder_device is freed when we know there are no references remaining on the binder_proc. Fixes: f0fe2c0f050d ("binder: prevent UAF for binderfs devices II") Acked-by: Christian Brauner Signed-off-by: Todd Kjos Cc: stable Link: https://lore.kernel.org/r/20200622200715.114382-1-tkjos@google.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit d35d3660e065b69fdb8bf512f3d899f350afce52) --- drivers/android/binder.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 1ca66045ecaa..9589fdb199dd 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4580,9 +4580,16 @@ static struct binder_thread *binder_get_thread(struct binder_proc *proc) static void binder_free_proc(struct binder_proc *proc) { + struct binder_device *device; + BUG_ON(!list_empty(&proc->todo)); BUG_ON(!list_empty(&proc->delivered_death)); WARN_ON(proc->outstanding_txns); + device = container_of(proc->context, struct binder_device, context); + if (refcount_dec_and_test(&device->ref)) { + kfree(proc->context->name); + kfree(device); + } binder_alloc_deferred_release(&proc->alloc); put_task_struct(proc->tsk); binder_stats_deleted(BINDER_STAT_PROC); @@ -5514,12 +5521,6 @@ static void binder_deferred_release(struct binder_proc *proc) context->binder_context_mgr_node = NULL; } mutex_unlock(&context->context_mgr_node_lock); - device = container_of(proc->context, struct binder_device, context); - if (refcount_dec_and_test(&device->ref)) { - kfree(context->name); - kfree(device); - } - proc->context = NULL; binder_inner_proc_lock(proc); /* * Make sure proc stays alive after we -- GitLab From 29043942de0af00f201e627bf8f2a667b45f9308 Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Fri, 14 Dec 2018 15:58:21 -0800 Subject: [PATCH 493/528] binder: fix use-after-free due to ksys_close() during fdget() 44d8047f1d8 ("binder: use standard functions to allocate fds") exposed a pre-existing issue in the binder driver. fdget() is used in ksys_ioctl() as a performance optimization. One of the rules associated with fdget() is that ksys_close() must not be called between the fdget() and the fdput(). There is a case where this requirement is not met in the binder driver which results in the reference count dropping to 0 when the device is still in use. This can result in use-after-free or other issues. If userpace has passed a file-descriptor for the binder driver using a BINDER_TYPE_FDA object, then kys_close() is called on it when handling a binder_ioctl(BC_FREE_BUFFER) command. This violates the assumptions for using fdget(). The problem is fixed by deferring the close using task_work_add(). A new variant of __close_fd() was created that returns a struct file with a reference. The fput() is deferred instead of using ksys_close(). Fixes: 44d8047f1d87a ("binder: use standard functions to allocate fds") Suggested-by: Al Viro Signed-off-by: Todd Kjos Cc: stable Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 80cd795630d6526ba729a089a435bf74a57af927) --- drivers/android/binder.c | 134 ++++++++++++++++++++++++++++++++++++++- fs/file.c | 29 +++++++++ include/linux/fdtable.h | 1 + 3 files changed, 163 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 9589fdb199dd..732963f51491 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -73,6 +73,7 @@ #include #include #include +#include #include "binder.h" #include "binder_alloc.h" @@ -2333,6 +2334,64 @@ static bool binder_validate_fixup(struct binder_buffer *b, return (fixup_offset >= last_min_offset); } +/** + * struct binder_task_work_cb - for deferred close + * + * @twork: callback_head for task work + * @fd: fd to close + * + * Structure to pass task work to be handled after + * returning from binder_ioctl() via task_work_add(). + */ +struct binder_task_work_cb { + struct callback_head twork; + struct file *file; +}; + +/** + * binder_do_fd_close() - close list of file descriptors + * @twork: callback head for task work + * + * It is not safe to call ksys_close() during the binder_ioctl() + * function if there is a chance that binder's own file descriptor + * might be closed. This is to meet the requirements for using + * fdget() (see comments for __fget_light()). Therefore use + * task_work_add() to schedule the close operation once we have + * returned from binder_ioctl(). This function is a callback + * for that mechanism and does the actual ksys_close() on the + * given file descriptor. + */ +static void binder_do_fd_close(struct callback_head *twork) +{ + struct binder_task_work_cb *twcb = container_of(twork, + struct binder_task_work_cb, twork); + + fput(twcb->file); + kfree(twcb); +} + +/** + * binder_deferred_fd_close() - schedule a close for the given file-descriptor + * @fd: file-descriptor to close + * + * See comments in binder_do_fd_close(). This function is used to schedule + * a file-descriptor to be closed after returning from binder_ioctl(). + */ +static void binder_deferred_fd_close(int fd) +{ + struct binder_task_work_cb *twcb; + + twcb = kzalloc(sizeof(*twcb), GFP_KERNEL); + if (!twcb) + return; + init_task_work(&twcb->twork, binder_do_fd_close); + __close_fd_get_file(fd, &twcb->file); + if (twcb->file) + task_work_add(current, &twcb->twork, true); + else + kfree(twcb); +} + static void binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer *buffer, binder_size_t *failed_at) @@ -2459,7 +2518,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, fd_array = (u32 *)(uintptr_t) (parent_buffer + fda->parent_offset); for (fd_index = 0; fd_index < fda->num_fds; fd_index++) - task_close_fd(proc, fd_array[fd_index]); + binder_deferred_fd_close(fd_array[fd_index]); } break; default: pr_err("transaction release %d bad object type %x\n", @@ -4089,6 +4148,79 @@ static int binder_wait_for_work(struct binder_thread *thread, return ret; } +<<<<<<< HEAD +======= +/** + * binder_apply_fd_fixups() - finish fd translation + * @t: binder transaction with list of fd fixups + * + * Now that we are in the context of the transaction target + * process, we can allocate and install fds. Process the + * list of fds to translate and fixup the buffer with the + * new fds. + * + * If we fail to allocate an fd, then free the resources by + * fput'ing files that have not been processed and ksys_close'ing + * any fds that have already been allocated. + */ +static int binder_apply_fd_fixups(struct binder_transaction *t) +{ + struct binder_txn_fd_fixup *fixup, *tmp; + int ret = 0; + + list_for_each_entry(fixup, &t->fd_fixups, fixup_entry) { + int fd = get_unused_fd_flags(O_CLOEXEC); + u32 *fdp; + + if (fd < 0) { + binder_debug(BINDER_DEBUG_TRANSACTION, + "failed fd fixup txn %d fd %d\n", + t->debug_id, fd); + ret = -ENOMEM; + break; + } + binder_debug(BINDER_DEBUG_TRANSACTION, + "fd fixup txn %d fd %d\n", + t->debug_id, fd); + trace_binder_transaction_fd_recv(t, fd, fixup->offset); + fd_install(fd, fixup->file); + fixup->file = NULL; + fdp = (u32 *)(t->buffer->data + fixup->offset); + /* + * This store can cause problems for CPUs with a + * VIVT cache (eg ARMv5) since the cache cannot + * detect virtual aliases to the same physical cacheline. + * To support VIVT, this address and the user-space VA + * would both need to be flushed. Since this kernel + * VA is not constructed via page_to_virt(), we can't + * use flush_dcache_page() on it, so we'd have to use + * an internal function. If devices with VIVT ever + * need to run Android, we'll either need to go back + * to patching the translated fd from the sender side + * (using the non-standard kernel functions), or rework + * how the kernel uses the buffer to use page_to_virt() + * addresses instead of allocating in our own vm area. + * + * For now, we disable compilation if CONFIG_CPU_CACHE_VIVT. + */ + *fdp = fd; + } + list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) { + if (fixup->file) { + fput(fixup->file); + } else if (ret) { + u32 *fdp = (u32 *)(t->buffer->data + fixup->offset); + + binder_deferred_fd_close(*fdp); + } + list_del(&fixup->fixup_entry); + kfree(fixup); + } + + return ret; +} + +>>>>>>> 80cd795630d6 (binder: fix use-after-free due to ksys_close() during fdget()) static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, diff --git a/fs/file.c b/fs/file.c index a885da15b6a3..b0503e296e59 100644 --- a/fs/file.c +++ b/fs/file.c @@ -671,6 +671,35 @@ out_unlock: return -EBADF; } +/* + * variant of __close_fd that gets a ref on the file for later fput + */ +int __close_fd_get_file(unsigned int fd, struct file **res) +{ + struct files_struct *files = current->files; + struct file *file; + struct fdtable *fdt; + + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + if (fd >= fdt->max_fds) + goto out_unlock; + file = fdt->fd[fd]; + if (!file) + goto out_unlock; + rcu_assign_pointer(fdt->fd[fd], NULL); + __put_unused_fd(files, fd); + spin_unlock(&files->file_lock); + get_file(file); + *res = file; + return filp_close(file, files); + +out_unlock: + spin_unlock(&files->file_lock); + *res = NULL; + return -ENOENT; +} + void do_close_on_exec(struct files_struct *files) { unsigned i; diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index cb674d6d6ba2..e1a36370e3d7 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -112,6 +112,7 @@ extern void __fd_install(struct files_struct *files, unsigned int fd, struct file *file); extern int __close_fd(struct files_struct *files, unsigned int fd); +extern int __close_fd_get_file(unsigned int fd, struct file **res); extern struct kmem_cache *files_cachep; -- GitLab From c1437c6d4e990696322fabd59c275e5215cd738a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 11 Dec 2019 14:10:35 -0700 Subject: [PATCH 494/528] fs: move filp_close() outside of __close_fd_get_file() Just one caller of this, and just use filp_close() there manually. This is important to allow async close/removal of the fd. Signed-off-by: Jens Axboe (cherry picked from commit 6e802a4ba056a6f2f51ac9d54eead3ed6f9829a2) --- drivers/android/binder.c | 6 ++++-- fs/file.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 732963f51491..2df9c3c94ffe 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2386,10 +2386,12 @@ static void binder_deferred_fd_close(int fd) return; init_task_work(&twcb->twork, binder_do_fd_close); __close_fd_get_file(fd, &twcb->file); - if (twcb->file) + if (twcb->file) { + filp_close(twcb->file, current->files); task_work_add(current, &twcb->twork, true); - else + } else { kfree(twcb); + } } static void binder_transaction_buffer_release(struct binder_proc *proc, diff --git a/fs/file.c b/fs/file.c index b0503e296e59..a07792c8f6c4 100644 --- a/fs/file.c +++ b/fs/file.c @@ -672,7 +672,9 @@ out_unlock: } /* - * variant of __close_fd that gets a ref on the file for later fput + * variant of __close_fd that gets a ref on the file for later fput. + * The caller must ensure that filp_close() called on the file, and then + * an fput(). */ int __close_fd_get_file(unsigned int fd, struct file **res) { @@ -692,7 +694,7 @@ int __close_fd_get_file(unsigned int fd, struct file **res) spin_unlock(&files->file_lock); get_file(file); *res = file; - return filp_close(file, files); + return 0; out_unlock: spin_unlock(&files->file_lock); -- GitLab From 1ed959a6c0d7cdd50e28225a9bb07858f60a1f6c Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 30 Nov 2018 20:26:30 -0500 Subject: [PATCH 495/528] binder: remove BINDER_DEBUG_ENTRY() We already have the DEFINE_SHOW_ATTRIBUTE.There is no need to define such a macro,so remove BINDER_DEBUG_ENTRY. Signed-off-by: Yangtao Li Acked-by: Todd Kjos Reviewed-by: Joey Pabalinas Signed-off-by: Greg Kroah-Hartman (cherry picked from commit c13e0a5288195aadec1e53af7a48ea8dae971416) --- drivers/android/binder.c | 105 ++++----------------------------------- 1 file changed, 9 insertions(+), 96 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 2df9c3c94ffe..c543ed2ec6ed 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -95,22 +95,8 @@ static struct dentry *binder_debugfs_dir_entry_proc; static atomic_t binder_last_id; static struct workqueue_struct *binder_deferred_workqueue; -#define BINDER_DEBUG_ENTRY(name) \ -static int binder_##name##_open(struct inode *inode, struct file *file) \ -{ \ - return single_open(file, binder_##name##_show, inode->i_private); \ -} \ -\ -static const struct file_operations binder_##name##_fops = { \ - .owner = THIS_MODULE, \ - .open = binder_##name##_open, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .release = single_release, \ -} - -static int binder_proc_show(struct seq_file *m, void *unused); -BINDER_DEBUG_ENTRY(proc); +static int proc_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(proc); /* This is only defined in include/asm-arm/sizes.h */ #ifndef SZ_1K @@ -4150,79 +4136,6 @@ static int binder_wait_for_work(struct binder_thread *thread, return ret; } -<<<<<<< HEAD -======= -/** - * binder_apply_fd_fixups() - finish fd translation - * @t: binder transaction with list of fd fixups - * - * Now that we are in the context of the transaction target - * process, we can allocate and install fds. Process the - * list of fds to translate and fixup the buffer with the - * new fds. - * - * If we fail to allocate an fd, then free the resources by - * fput'ing files that have not been processed and ksys_close'ing - * any fds that have already been allocated. - */ -static int binder_apply_fd_fixups(struct binder_transaction *t) -{ - struct binder_txn_fd_fixup *fixup, *tmp; - int ret = 0; - - list_for_each_entry(fixup, &t->fd_fixups, fixup_entry) { - int fd = get_unused_fd_flags(O_CLOEXEC); - u32 *fdp; - - if (fd < 0) { - binder_debug(BINDER_DEBUG_TRANSACTION, - "failed fd fixup txn %d fd %d\n", - t->debug_id, fd); - ret = -ENOMEM; - break; - } - binder_debug(BINDER_DEBUG_TRANSACTION, - "fd fixup txn %d fd %d\n", - t->debug_id, fd); - trace_binder_transaction_fd_recv(t, fd, fixup->offset); - fd_install(fd, fixup->file); - fixup->file = NULL; - fdp = (u32 *)(t->buffer->data + fixup->offset); - /* - * This store can cause problems for CPUs with a - * VIVT cache (eg ARMv5) since the cache cannot - * detect virtual aliases to the same physical cacheline. - * To support VIVT, this address and the user-space VA - * would both need to be flushed. Since this kernel - * VA is not constructed via page_to_virt(), we can't - * use flush_dcache_page() on it, so we'd have to use - * an internal function. If devices with VIVT ever - * need to run Android, we'll either need to go back - * to patching the translated fd from the sender side - * (using the non-standard kernel functions), or rework - * how the kernel uses the buffer to use page_to_virt() - * addresses instead of allocating in our own vm area. - * - * For now, we disable compilation if CONFIG_CPU_CACHE_VIVT. - */ - *fdp = fd; - } - list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) { - if (fixup->file) { - fput(fixup->file); - } else if (ret) { - u32 *fdp = (u32 *)(t->buffer->data + fixup->offset); - - binder_deferred_fd_close(*fdp); - } - list_del(&fixup->fixup_entry); - kfree(fixup); - } - - return ret; -} - ->>>>>>> 80cd795630d6 (binder: fix use-after-free due to ksys_close() during fdget()) static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, @@ -5485,7 +5398,7 @@ static int binder_open(struct inode *nodp, struct file *filp) proc->debugfs_entry = debugfs_create_file(strbuf, 0444, binder_debugfs_dir_entry_proc, (void *)(unsigned long)proc->pid, - &binder_proc_fops); + &proc_fops); } if (binder_binderfs_dir_entry_proc) { @@ -6240,7 +6153,7 @@ int binder_transactions_show(struct seq_file *m, void *unused) return 0; } -static int binder_proc_show(struct seq_file *m, void *unused) +static int proc_show(struct seq_file *m, void *unused) { struct binder_proc *itr; int pid = (unsigned long)m->private; @@ -6367,27 +6280,27 @@ static int __init binder_init(void) 0444, binder_debugfs_dir_entry_root, NULL, - &binder_state_fops); + &state_fops); debugfs_create_file("stats", 0444, binder_debugfs_dir_entry_root, NULL, - &binder_stats_fops); + &stats_fops); debugfs_create_file("transactions", 0444, binder_debugfs_dir_entry_root, NULL, - &binder_transactions_fops); + &transactions_fops); debugfs_create_file("transaction_log", 0444, binder_debugfs_dir_entry_root, &binder_transaction_log, - &binder_transaction_log_fops); + &transaction_log_fops); debugfs_create_file("failed_transaction_log", 0444, binder_debugfs_dir_entry_root, &binder_transaction_log_failed, - &binder_transaction_log_fops); + &transaction_log_fops); } /* -- GitLab From b39e6c0e54ea178566da77c5b1e11e88a5080abd Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Wed, 16 Oct 2019 17:01:18 +0200 Subject: [PATCH 496/528] binder: Don't modify VMA bounds in ->mmap handler binder_mmap() tries to prevent the creation of overly big binder mappings by silently truncating the size of the VMA to 4MiB. However, this violates the API contract of mmap(). If userspace attempts to create a large binder VMA, and later attempts to unmap that VMA, it will call munmap() on a range beyond the end of the VMA, which may have been allocated to another VMA in the meantime. This can lead to userspace memory corruption. The following sequence of calls leads to a segfault without this commit: int main(void) { int binder_fd = open("/dev/binder", O_RDWR); if (binder_fd == -1) err(1, "open binder"); void *binder_mapping = mmap(NULL, 0x800000UL, PROT_READ, MAP_SHARED, binder_fd, 0); if (binder_mapping == MAP_FAILED) err(1, "mmap binder"); void *data_mapping = mmap(NULL, 0x400000UL, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (data_mapping == MAP_FAILED) err(1, "mmap data"); munmap(binder_mapping, 0x800000UL); *(char*)data_mapping = 1; return 0; } Cc: stable@vger.kernel.org Signed-off-by: Jann Horn Acked-by: Todd Kjos Acked-by: Christian Brauner Link: https://lore.kernel.org/r/20191016150119.154756-1-jannh@google.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 45d02f79b539073b76077836871de6b674e36eb4) --- drivers/android/binder.c | 7 ------- drivers/android/binder_alloc.c | 19 +++++-------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index c543ed2ec6ed..7bdd551237ba 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -103,10 +103,6 @@ DEFINE_SHOW_ATTRIBUTE(proc); #define SZ_1K 0x400 #endif -#ifndef SZ_4M -#define SZ_4M 0x400000 -#endif - #define FORBIDDEN_MMAP_FLAGS (VM_WRITE) #define BINDER_SMALL_BUF_SIZE (PAGE_SIZE * 64) @@ -5297,9 +5293,6 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) if (proc->tsk != current->group_leader) return -EINVAL; - if ((vma->vm_end - vma->vm_start) > SZ_4M) - vma->vm_end = vma->vm_start + SZ_4M; - binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", __func__, proc->pid, vma->vm_start, vma->vm_end, diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 0148f9b67547..92014b8afc4d 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "binder_alloc.h" #include "binder_trace.h" @@ -693,26 +694,16 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, vma->vm_start - (uintptr_t)alloc->buffer; mutex_unlock(&binder_alloc_mmap_lock); -#ifdef CONFIG_CPU_CACHE_VIPT - if (cache_is_vipt_aliasing()) { - while (CACHE_COLOUR( - (vma->vm_start ^ (uint32_t)alloc->buffer))) { - pr_info("binder_mmap: %d %lx-%lx maps %pK bad alignment\n", - alloc->pid, vma->vm_start, vma->vm_end, - alloc->buffer); - vma->vm_start += PAGE_SIZE; - } - } -#endif - alloc->pages = kzalloc(sizeof(alloc->pages[0]) * - ((vma->vm_end - vma->vm_start) / PAGE_SIZE), + alloc->buffer_size = min_t(unsigned long, vma->vm_end - vma->vm_start, + SZ_4M); + alloc->pages = kcalloc(alloc->buffer_size / PAGE_SIZE, + sizeof(alloc->pages[0]), GFP_KERNEL); if (alloc->pages == NULL) { ret = -ENOMEM; failure_string = "alloc page array"; goto err_alloc_pages_failed; } - alloc->buffer_size = vma->vm_end - vma->vm_start; buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (!buffer) { -- GitLab From c4ce50a32e21f58b9c7df55651ad9262bf8e3810 Mon Sep 17 00:00:00 2001 From: Mrinal Pandey Date: Fri, 24 Jul 2020 18:44:03 +0530 Subject: [PATCH 497/528] drivers: android: Remove braces for a single statement if-else block Remove braces for both if and else block as suggested by checkpatch. Signed-off-by: Mrinal Pandey Link: https://lore.kernel.org/r/20200724131403.dahfhdwa3wirzkxj@mrinalpandey Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 8df5b9492202e9cac9917465e945fcf478d55404) --- drivers/android/binder.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 7bdd551237ba..4099173bc2b3 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2832,11 +2832,10 @@ static int binder_proc_transaction(struct binder_transaction *t, if (oneway) { BUG_ON(thread); - if (node->has_async_transaction) { + if (node->has_async_transaction) pending_async = true; - } else { + else node->has_async_transaction = true; - } } binder_inner_proc_lock(proc); -- GitLab From 7b36094a36938b9f309b9d168ad75dcf3ef7fa2a Mon Sep 17 00:00:00 2001 From: threader Date: Tue, 3 Aug 2021 08:29:21 +0200 Subject: [PATCH 498/528] BINDER: Clean up pick conflict --- drivers/android/binder.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 4099173bc2b3..7ee3912cb1b1 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5408,7 +5408,7 @@ static int binder_open(struct inode *nodp, struct file *filp) * contexts of a given PID. */ binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc, - strbuf, &binder_proc_fops, (void *)(unsigned long)proc->pid); + strbuf, &proc_fops, (void *)(unsigned long)proc->pid); if (!IS_ERR(binderfs_entry)) { proc->binderfs_entry = binderfs_entry; } else { @@ -6272,27 +6272,27 @@ static int __init binder_init(void) 0444, binder_debugfs_dir_entry_root, NULL, - &state_fops); + &binder_state_fops); debugfs_create_file("stats", 0444, binder_debugfs_dir_entry_root, NULL, - &stats_fops); + &binder_stats_fops); debugfs_create_file("transactions", 0444, binder_debugfs_dir_entry_root, NULL, - &transactions_fops); + &binder_transactions_fops); debugfs_create_file("transaction_log", 0444, binder_debugfs_dir_entry_root, &binder_transaction_log, - &transaction_log_fops); + &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", 0444, binder_debugfs_dir_entry_root, &binder_transaction_log_failed, - &transaction_log_fops); + &binder_transaction_log_fops); } /* -- GitLab From 86ff92784993c5a8c3343a2caac8d395daeb96f6 Mon Sep 17 00:00:00 2001 From: Hang Lu Date: Fri, 9 Apr 2021 17:40:45 +0800 Subject: [PATCH 499/528] FROMGIT: binder: fix the missing BR_FROZEN_REPLY in binder_return_strings Add BR_FROZEN_REPLY in binder_return_strings to support stat function. Fixes: ae28c1be1e54 ("binder: BINDER_GET_FROZEN_INFO ioctl") Acked-by: Todd Kjos Signed-off-by: Hang Lu Link: https://lore.kernel.org/r/1617961246-4502-2-git-send-email-hangl@codeaurora.org Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 005169157448ca41eff8716d79dc1b8f158229d2 git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git char-misc-next) Change-Id: Ib12e3f1dc1a389c9b4d5e9f60bd740d269dadf94 Signed-off-by: Hang Lu (cherry picked from commit 6c3c18a4c9f62d186e767b7e55c4f86769c77bf4) --- drivers/android/binder.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 7ee3912cb1b1..767da111e46a 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -187,7 +187,7 @@ enum binder_stat_types { }; struct binder_stats { - atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; + atomic_t br[_IOC_NR(BR_FROZEN_REPLY) + 1]; atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; atomic_t obj_created[BINDER_STAT_COUNT]; atomic_t obj_deleted[BINDER_STAT_COUNT]; @@ -5936,7 +5936,8 @@ static const char * const binder_return_strings[] = { "BR_FINISHED", "BR_DEAD_BINDER", "BR_CLEAR_DEATH_NOTIFICATION_DONE", - "BR_FAILED_REPLY" + "BR_FAILED_REPLY", + "BR_FROZEN_REPLY", }; static const char * const binder_command_strings[] = { -- GitLab From 07ed016cf232b45dbb15746dc0d2fe5ee8296d20 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 6 Jul 2018 16:24:27 -0700 Subject: [PATCH 500/528] ANDROID: sdcardfs: Add option to drop unused dentries This adds the nocache mount option, which will cause sdcardfs to always drop dentries that are not in use, preventing cached entries from holding on to lower dentries, which could cause strange behavior when bypassing the sdcardfs layer and directly changing the lower fs. Change-Id: I70268584a20b989ae8cfdd278a2e4fa1605217fb Signed-off-by: Daniel Rosenberg [basilgello: imply 5dd43fe0853d27266768781a530d2862dff76170 ] Signed-Off-By: Vasyl Gello --- fs/sdcardfs/dentry.c | 5 +++-- fs/sdcardfs/main.c | 6 ++++++ fs/sdcardfs/sdcardfs.h | 1 + fs/sdcardfs/super.c | 2 ++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 159c97dfca56..fbc274fa8617 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -181,9 +181,10 @@ static void sdcardfs_canonical_path(const struct path *path, sdcardfs_get_real_lower(path->dentry, actual_path); } -static int sdcardfs_d_delete(const struct dentry * dentry) +/* 1 = delete, 0 = cache */ +static int sdcardfs_d_delete(const struct dentry *d) { - return dentry->d_inode && !S_ISDIR(dentry->d_inode->i_mode); + return SDCARDFS_SB(d->d_sb)->options.nocache ? 1 : 0; } const struct dentry_operations sdcardfs_ci_dops = { diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index b6f2c877a349..16d3426805aa 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -34,6 +34,7 @@ enum { Opt_reserved_mb, Opt_gid_derivation, Opt_default_normal, + Opt_nocache, Opt_unshared_obb, Opt_err, }; @@ -50,6 +51,7 @@ static const match_table_t sdcardfs_tokens = { {Opt_default_normal, "default_normal"}, {Opt_unshared_obb, "unshared_obb"}, {Opt_reserved_mb, "reserved_mb=%u"}, + {Opt_nocache, "nocache"}, {Opt_err, NULL} }; @@ -73,6 +75,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, /* by default, gid derivation is off */ opts->gid_derivation = false; opts->default_normal = false; + opts->nocache = false; *debug = 0; @@ -130,6 +133,9 @@ static int parse_options(struct super_block *sb, char *options, int silent, case Opt_default_normal: opts->default_normal = true; break; + case Opt_nocache: + opts->nocache = true; + break; case Opt_unshared_obb: opts->unshared_obb = true; break; diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index f96405d7c317..ea566e1c84d5 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -198,6 +198,7 @@ struct sdcardfs_mount_options { bool default_normal; bool unshared_obb; unsigned int reserved_mb; + bool nocache; }; struct sdcardfs_vfsmount_options { diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index a4ac84e0c01d..bd2eb0257020 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -311,6 +311,8 @@ static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m, seq_puts(m, ",default_normal"); if (opts->reserved_mb != 0) seq_printf(m, ",reserved=%uMB", opts->reserved_mb); + if (opts->nocache) + seq_printf(m, ",nocache"); if (opts->unshared_obb) seq_printf(m, ",unshared_obb"); -- GitLab From 689189882e78d6ce5df07c78175120d2e86e76de Mon Sep 17 00:00:00 2001 From: syphyr Date: Sat, 13 Jul 2019 21:04:31 +0200 Subject: [PATCH 501/528] ANDROID: sdcardfs: Wait for file flush to complete Sdcardfs needs to wait for the file to finish writing before returning an error. Backport from 3.18 to 3.10 kernel. Change-Id: I0fbdfd9a4c46ad34b8826099d9e3b255289d4794 --- fs/sdcardfs/file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 39fe0426f61d..4502c3f60254 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -297,8 +297,10 @@ static int sdcardfs_flush(struct file *file, fl_owner_t id) struct file *lower_file = NULL; lower_file = sdcardfs_lower_file(file); - if (lower_file && lower_file->f_op && lower_file->f_op->flush) + if (lower_file && lower_file->f_op && lower_file->f_op->flush) { + filemap_write_and_wait(file->f_mapping); err = lower_file->f_op->flush(lower_file, id); + } return err; } -- GitLab From e182d1b318c487e497ea402f8ebb8fc30234f56a Mon Sep 17 00:00:00 2001 From: threader Date: Fri, 6 Aug 2021 16:44:16 +0200 Subject: [PATCH 502/528] BINDER: Fix warning on moved struct --- drivers/android/binder.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 767da111e46a..6eafdb6f1a69 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5541,7 +5541,6 @@ static void binder_deferred_release(struct binder_proc *proc) { struct binder_context *context = proc->context; struct rb_node *n; - struct binder_device *device; int threads, nodes, incoming_refs, outgoing_refs, active_transactions; -- GitLab From c79ac9a31dbba67f1ca4ee14e9956af6934d068e Mon Sep 17 00:00:00 2001 From: Chintan Pandya Date: Wed, 6 Aug 2014 16:08:18 -0700 Subject: [PATCH 503/528] mm: BUG when __kmap_atomic_idx equals KM_TYPE_NR __kmap_atomic_idx is per_cpu variable. Each CPU can use KM_TYPE_NR entries from FIXMAP i.e. from 0 to KM_TYPE_NR - 1. Allowing __kmap_atomic_idx to over- shoot to KM_TYPE_NR can mess up with next CPU's 0th entry which is a bug. Hence BUG_ON if __kmap_atomic_idx >= KM_TYPE_NR. Fix the off-by-on in this test. Signed-off-by: Chintan Pandya Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 1d352bfd41e8219cdf9bebe79677700bdc38b540) --- include/linux/highmem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 56543d480592..81de67011364 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -101,7 +101,7 @@ static inline int kmap_atomic_idx_push(void) #ifdef CONFIG_DEBUG_HIGHMEM WARN_ON_ONCE(in_irq() && !irqs_disabled()); - BUG_ON(idx > KM_TYPE_NR); + BUG_ON(idx >= KM_TYPE_NR); #endif return idx; } -- GitLab From 30029f690835b9f3a0d9bea57c095a2d2cf458e6 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 11 May 2015 17:52:09 +0200 Subject: [PATCH 504/528] sched/preempt, mm/kmap: Explicitly disable/enable preemption in kmap_atomic_* The existing code relies on pagefault_disable() implicitly disabling preemption, so that no schedule will happen between kmap_atomic() and kunmap_atomic(). Let's make this explicit, to prepare for pagefault_disable() not touching preemption anymore. Reviewed-and-tested-by: Thomas Gleixner Signed-off-by: David Hildenbrand Signed-off-by: Peter Zijlstra (Intel) Cc: David.Laight@ACULAB.COM Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: airlied@linux.ie Cc: akpm@linux-foundation.org Cc: benh@kernel.crashing.org Cc: bigeasy@linutronix.de Cc: borntraeger@de.ibm.com Cc: daniel.vetter@intel.com Cc: heiko.carstens@de.ibm.com Cc: herbert@gondor.apana.org.au Cc: hocko@suse.cz Cc: hughd@google.com Cc: mst@redhat.com Cc: paulus@samba.org Cc: ralf@linux-mips.org Cc: schwidefsky@de.ibm.com Cc: yang.shi@windriver.com Link: http://lkml.kernel.org/r/1431359540-32227-5-git-send-email-dahi@linux.vnet.ibm.com Signed-off-by: Ingo Molnar (cherry picked from commit 2cb7c9cb426660b5ed58b643d9e7dd5d50ba901f) --- arch/arm/mm/highmem.c | 3 + arch/frv/mm/highmem.c | 2 + arch/metag/mm/highmem.c | 4 +- arch/microblaze/mm/highmem.c | 4 +- arch/mips/mm/highmem.c | 5 +- arch/mn10300/include/asm/highmem.h | 3 + arch/parisc/include/asm/cacheflush.h | 2 + arch/powerpc/mm/highmem.c | 4 +- arch/sparc/mm/highmem.c | 4 +- arch/tile/mm/highmem.c | 3 +- arch/x86/mm/highmem_32.c | 3 +- arch/x86/mm/iomap_32.c | 2 + arch/xtensa/mm/highmem.c | 95 ++++++++++++++++++++++++++++ include/linux/highmem.h | 2 + include/linux/io-mapping.h | 2 + 15 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 arch/xtensa/mm/highmem.c diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index d6f9ee8f10b7..123065ac13ac 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -44,6 +44,7 @@ void *kmap_atomic(struct page *page) void *kmap; int type; + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -106,6 +107,7 @@ void __kunmap_atomic(void *kvaddr) kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)])); } pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); @@ -114,6 +116,7 @@ void *kmap_atomic_pfn(unsigned long pfn) unsigned long vaddr; int idx, type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); diff --git a/arch/frv/mm/highmem.c b/arch/frv/mm/highmem.c index bed9a9bd3c10..785344bbdc07 100644 --- a/arch/frv/mm/highmem.c +++ b/arch/frv/mm/highmem.c @@ -42,6 +42,7 @@ void *kmap_atomic(struct page *page) unsigned long paddr; int type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); paddr = page_to_phys(page); @@ -85,5 +86,6 @@ void __kunmap_atomic(void *kvaddr) } kmap_atomic_idx_pop(); pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/metag/mm/highmem.c b/arch/metag/mm/highmem.c index d71f621a2c0b..807f1b1c4e65 100644 --- a/arch/metag/mm/highmem.c +++ b/arch/metag/mm/highmem.c @@ -43,7 +43,7 @@ void *kmap_atomic(struct page *page) unsigned long vaddr; int type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -82,6 +82,7 @@ void __kunmap_atomic(void *kvaddr) } pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); @@ -95,6 +96,7 @@ void *kmap_atomic_pfn(unsigned long pfn) unsigned long vaddr; int type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); diff --git a/arch/microblaze/mm/highmem.c b/arch/microblaze/mm/highmem.c index 5a92576fad92..2fcc5a52d84d 100644 --- a/arch/microblaze/mm/highmem.c +++ b/arch/microblaze/mm/highmem.c @@ -37,7 +37,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) unsigned long vaddr; int idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -63,6 +63,7 @@ void __kunmap_atomic(void *kvaddr) if (vaddr < __fix_to_virt(FIX_KMAP_END)) { pagefault_enable(); + preempt_enable(); return; } @@ -84,5 +85,6 @@ void __kunmap_atomic(void *kvaddr) #endif kmap_atomic_idx_pop(); pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index da815d295239..11661cbc11a8 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -47,7 +47,7 @@ void *kmap_atomic(struct page *page) unsigned long vaddr; int idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -72,6 +72,7 @@ void __kunmap_atomic(void *kvaddr) if (vaddr < FIXADDR_START) { // FIXME pagefault_enable(); + preempt_enable(); return; } @@ -92,6 +93,7 @@ void __kunmap_atomic(void *kvaddr) #endif kmap_atomic_idx_pop(); pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); @@ -104,6 +106,7 @@ void *kmap_atomic_pfn(unsigned long pfn) unsigned long vaddr; int idx, type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); diff --git a/arch/mn10300/include/asm/highmem.h b/arch/mn10300/include/asm/highmem.h index 7c137cd8aa37..4f03a3ea0f6a 100644 --- a/arch/mn10300/include/asm/highmem.h +++ b/arch/mn10300/include/asm/highmem.h @@ -75,6 +75,7 @@ static inline unsigned long kmap_atomic(struct page *page) unsigned long vaddr; int idx, type; + preempt_disable(); pagefault_disable(); if (page < highmem_start_page) return page_address(page); @@ -98,6 +99,7 @@ static inline void __kunmap_atomic(unsigned long vaddr) if (vaddr < FIXADDR_START) { /* FIXME */ pagefault_enable(); + preempt_enable(); return; } @@ -122,6 +124,7 @@ static inline void __kunmap_atomic(unsigned long vaddr) kmap_atomic_idx_pop(); pagefault_enable(); + preempt_enable(); } #endif /* __KERNEL__ */ diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index de65f66ea64e..ec2df4bab302 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -142,6 +142,7 @@ static inline void kunmap(struct page *page) static inline void *kmap_atomic(struct page *page) { + preempt_disable(); pagefault_disable(); return page_address(page); } @@ -150,6 +151,7 @@ static inline void __kunmap_atomic(void *addr) { flush_kernel_dcache_page_addr(addr); pagefault_enable(); + preempt_enable(); } #define kmap_atomic_prot(page, prot) kmap_atomic(page) diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c index e7450bdbe83a..e292c8a60952 100644 --- a/arch/powerpc/mm/highmem.c +++ b/arch/powerpc/mm/highmem.c @@ -34,7 +34,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) unsigned long vaddr; int idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -59,6 +59,7 @@ void __kunmap_atomic(void *kvaddr) if (vaddr < __fix_to_virt(FIX_KMAP_END)) { pagefault_enable(); + preempt_enable(); return; } @@ -82,5 +83,6 @@ void __kunmap_atomic(void *kvaddr) kmap_atomic_idx_pop(); pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index 449f864f0cef..a454ec5ff07a 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -53,7 +53,7 @@ void *kmap_atomic(struct page *page) unsigned long vaddr; long idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -91,6 +91,7 @@ void __kunmap_atomic(void *kvaddr) if (vaddr < FIXADDR_START) { // FIXME pagefault_enable(); + preempt_enable(); return; } @@ -126,5 +127,6 @@ void __kunmap_atomic(void *kvaddr) kmap_atomic_idx_pop(); pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c index 347d123b14be..2807600c4b6b 100644 --- a/arch/tile/mm/highmem.c +++ b/arch/tile/mm/highmem.c @@ -202,7 +202,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) int idx, type; pte_t *pte; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); /* Avoid icache flushes by disallowing atomic executable mappings. */ @@ -261,6 +261,7 @@ void __kunmap_atomic(void *kvaddr) arch_flush_lazy_mmu_mode(); pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index 4500142bc4aa..eecb207a2037 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -35,7 +35,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) unsigned long vaddr; int idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) @@ -100,6 +100,7 @@ void __kunmap_atomic(void *kvaddr) #endif pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c index 7b179b499fa3..89f860138b61 100644 --- a/arch/x86/mm/iomap_32.c +++ b/arch/x86/mm/iomap_32.c @@ -59,6 +59,7 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot) unsigned long vaddr; int idx, type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); @@ -115,5 +116,6 @@ iounmap_atomic(void __iomem *kvaddr) } pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL_GPL(iounmap_atomic); diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c new file mode 100644 index 000000000000..184ceadccc1a --- /dev/null +++ b/arch/xtensa/mm/highmem.c @@ -0,0 +1,95 @@ +/* + * High memory support for Xtensa architecture + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + * Copyright (C) 2014 Cadence Design Systems Inc. + */ + +#include +#include +#include + +static pte_t *kmap_pte; + +#if DCACHE_WAY_SIZE > PAGE_SIZE +unsigned int last_pkmap_nr_arr[DCACHE_N_COLORS]; +wait_queue_head_t pkmap_map_wait_arr[DCACHE_N_COLORS]; + +static void __init kmap_waitqueues_init(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pkmap_map_wait_arr); ++i) + init_waitqueue_head(pkmap_map_wait_arr + i); +} +#else +static inline void kmap_waitqueues_init(void) +{ +} +#endif + +static inline enum fixed_addresses kmap_idx(int type, unsigned long color) +{ + return (type + KM_TYPE_NR * smp_processor_id()) * DCACHE_N_COLORS + + color; +} + +void *kmap_atomic(struct page *page) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + + idx = kmap_idx(kmap_atomic_idx_push(), + DCACHE_ALIAS(page_to_phys(page))); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +#ifdef CONFIG_DEBUG_HIGHMEM + BUG_ON(!pte_none(*(kmap_pte + idx))); +#endif + set_pte(kmap_pte + idx, mk_pte(page, PAGE_KERNEL_EXEC)); + + return (void *)vaddr; +} +EXPORT_SYMBOL(kmap_atomic); + +void __kunmap_atomic(void *kvaddr) +{ + if (kvaddr >= (void *)FIXADDR_START && + kvaddr < (void *)FIXADDR_TOP) { + int idx = kmap_idx(kmap_atomic_idx(), + DCACHE_ALIAS((unsigned long)kvaddr)); + + /* + * Force other mappings to Oops if they'll try to access this + * pte without first remap it. Keeping stale mappings around + * is a bad idea also, in case the page changes cacheability + * attributes or becomes a protected page in a hypervisor. + */ + pte_clear(&init_mm, kvaddr, kmap_pte + idx); + local_flush_tlb_kernel_range((unsigned long)kvaddr, + (unsigned long)kvaddr + PAGE_SIZE); + + kmap_atomic_idx_pop(); + } + + pagefault_enable(); + preempt_enable(); +} +EXPORT_SYMBOL(__kunmap_atomic); + +void __init kmap_init(void) +{ + unsigned long kmap_vstart; + + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); + kmap_waitqueues_init(); +} diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 81de67011364..477ae342bae2 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -72,6 +72,7 @@ static inline void kunmap(struct page *page) static inline void *kmap_atomic(struct page *page) { + preempt_disable(); pagefault_disable(); return page_address(page); } @@ -80,6 +81,7 @@ static inline void *kmap_atomic(struct page *page) static inline void __kunmap_atomic(void *addr) { pagefault_enable(); + preempt_enable(); } #define kmap_atomic_pfn(pfn) kmap_atomic(pfn_to_page(pfn)) diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h index 657fab4efab3..c27dde7215b5 100644 --- a/include/linux/io-mapping.h +++ b/include/linux/io-mapping.h @@ -141,6 +141,7 @@ static inline void __iomem * io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset) { + preempt_disable(); pagefault_disable(); return ((char __force __iomem *) mapping) + offset; } @@ -149,6 +150,7 @@ static inline void io_mapping_unmap_atomic(void __iomem *vaddr) { pagefault_enable(); + preempt_enable(); } /* Non-atomic map/unmap */ -- GitLab From 60a26e6c59c2e335b7380ba8a158d28765d0b4d6 Mon Sep 17 00:00:00 2001 From: Khalid Aziz Date: Wed, 21 Feb 2018 10:15:51 -0700 Subject: [PATCH 505/528] mm: Allow arch code to override copy_highpage() Some architectures can support metadata for memory pages and when a page is copied, its metadata must also be copied. Sparc processors from M7 onwards support metadata for memory pages. This metadata provides tag based protection for access to memory pages. To maintain this protection, the tag data must be copied to the new page when a page is migrated across NUMA nodes. This patch allows arch specific code to override default copy_highpage() and copy metadata along with page data upon migration. Signed-off-by: Khalid Aziz Cc: Khalid Aziz Reviewed-by: Anthony Yznaga Acked-by: Andrew Morton Signed-off-by: David S. Miller (cherry picked from commit a4602b62d9fdea41412ba765bbf32ecfc2b6a94c) --- include/linux/highmem.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 477ae342bae2..02a8e994f14f 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -281,6 +281,8 @@ static inline void copy_user_highpage(struct page *to, struct page *from, #endif +#ifndef __HAVE_ARCH_COPY_HIGHPAGE + static inline void copy_highpage(struct page *to, struct page *from) { char *vfrom, *vto; @@ -292,4 +294,6 @@ static inline void copy_highpage(struct page *to, struct page *from) kunmap_atomic(vfrom); } +#endif + #endif /* _LINUX_HIGHMEM_H */ -- GitLab From fae7d1c5633df5a87ad3e62700fcde8e432dde82 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Thu, 4 Jun 2020 16:47:30 -0700 Subject: [PATCH 506/528] arch/kmap: remove redundant arch specific kmaps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kmap code for all the architectures is almost 100% identical. Lift the common code to the core. Use ARCH_HAS_KMAP_FLUSH_TLB to indicate if an arch defines kmap_flush_tlb() and call if if needed. This also has the benefit of changing kmap() on a number of architectures to be an inline call rather than an actual function. Signed-off-by: Ira Weiny Signed-off-by: Andrew Morton Reviewed-by: Christoph Hellwig Cc: Al Viro Cc: Andy Lutomirski Cc: Benjamin Herrenschmidt Cc: Borislav Petkov Cc: Christian König Cc: Chris Zankel Cc: Daniel Vetter Cc: Dan Williams Cc: Dave Hansen Cc: "David S. Miller" Cc: Helge Deller Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: "James E.J. Bottomley" Cc: Max Filippov Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Bogendoerfer Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20200507150004.1423069-4-ira.weiny@intel.com Signed-off-by: Linus Torvalds (cherry picked from commit 525aaf9bad00e7454b9f9b3873e92795afb59f8e) --- arch/arm/include/asm/highmem.h | 2 - arch/arm/mm/highmem.c | 8 --- arch/csky/include/asm/highmem.h | 51 +++++++++++++++++++ arch/microblaze/include/asm/highmem.h | 9 ---- arch/mips/include/asm/highmem.h | 4 +- arch/mips/mm/highmem.c | 14 ++---- arch/nds32/include/asm/highmem.h | 63 ++++++++++++++++++++++++ arch/powerpc/include/asm/highmem.h | 9 ---- arch/sparc/include/asm/highmem.h | 1 - arch/x86/include/asm/highmem.h | 2 - arch/x86/mm/highmem_32.c | 9 ---- arch/xtensa/include/asm/highmem.h | 71 ++++++++++++++++++++++++++- include/linux/highmem.h | 18 +++++++ 13 files changed, 207 insertions(+), 54 deletions(-) create mode 100644 arch/csky/include/asm/highmem.h create mode 100644 arch/nds32/include/asm/highmem.h diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index 91b99abe7a95..d92e47abc771 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -19,7 +19,6 @@ extern pte_t *pkmap_page_table; -extern void *kmap_high(struct page *page); extern void kunmap_high(struct page *page); /* @@ -62,7 +61,6 @@ static inline void *kmap_high_get(struct page *page) * when CONFIG_HIGHMEM is not set. */ #ifdef CONFIG_HIGHMEM -extern void *kmap(struct page *page); extern void kunmap(struct page *page); extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index 123065ac13ac..15c3a11aab76 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -19,14 +19,6 @@ #include #include "mm.h" -void *kmap(struct page *page) -{ - might_sleep(); - if (!PageHighMem(page)) - return page_address(page); - return kmap_high(page); -} -EXPORT_SYMBOL(kmap); void kunmap(struct page *page) { diff --git a/arch/csky/include/asm/highmem.h b/arch/csky/include/asm/highmem.h new file mode 100644 index 000000000000..9d0516e38110 --- /dev/null +++ b/arch/csky/include/asm/highmem.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. + +#ifndef __ASM_CSKY_HIGHMEM_H +#define __ASM_CSKY_HIGHMEM_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include + +/* undef for production */ +#define HIGHMEM_DEBUG 1 + +/* declarations for highmem.c */ +extern unsigned long highstart_pfn, highend_pfn; + +extern pte_t *pkmap_page_table; + +/* + * Right now we initialize only a single pte table. It can be extended + * easily, subsequent pte tables have to be allocated in one physical + * chunk of RAM. + */ +#define LAST_PKMAP 1024 +#define LAST_PKMAP_MASK (LAST_PKMAP-1) +#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +extern void kunmap_high(struct page *page); + +#define ARCH_HAS_KMAP_FLUSH_TLB +extern void kmap_flush_tlb(unsigned long addr); +extern void kunmap(struct page *page); +extern void *kmap_atomic(struct page *page); +extern void __kunmap_atomic(void *kvaddr); +extern void *kmap_atomic_pfn(unsigned long pfn); +extern struct page *kmap_atomic_to_page(void *ptr); + +#define flush_cache_kmaps() do {} while (0) + +extern void kmap_init(void); + +#define kmap_prot PAGE_KERNEL + +#endif /* __KERNEL__ */ + +#endif /* __ASM_CSKY_HIGHMEM_H */ diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h index d04638932438..c2ccd1f3a4e1 100644 --- a/arch/microblaze/include/asm/highmem.h +++ b/arch/microblaze/include/asm/highmem.h @@ -50,19 +50,10 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void *kmap_high(struct page *page); extern void kunmap_high(struct page *page); extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); extern void __kunmap_atomic(void *kvaddr); -static inline void *kmap(struct page *page) -{ - might_sleep(); - if (!PageHighMem(page)) - return page_address(page); - return kmap_high(page); -} - static inline void kunmap(struct page *page) { BUG_ON(in_interrupt()); diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index b0dd0c84df70..881a5a4999cc 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -42,10 +42,10 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void * kmap_high(struct page *page); extern void kunmap_high(struct page *page); -extern void *kmap(struct page *page); +#define ARCH_HAS_KMAP_FLUSH_TLB +extern void kmap_flush_tlb(unsigned long addr); extern void kunmap(struct page *page); extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 11661cbc11a8..585a14901f16 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -10,19 +10,11 @@ static pte_t *kmap_pte; unsigned long highstart_pfn, highend_pfn; -void *kmap(struct page *page) +void kmap_flush_tlb(unsigned long addr) { - void *addr; - - might_sleep(); - if (!PageHighMem(page)) - return page_address(page); - addr = kmap_high(page); - flush_tlb_one((unsigned long)addr); - - return addr; + flush_tlb_one(addr); } -EXPORT_SYMBOL(kmap); +EXPORT_SYMBOL(kmap_flush_tlb); void kunmap(struct page *page) { diff --git a/arch/nds32/include/asm/highmem.h b/arch/nds32/include/asm/highmem.h new file mode 100644 index 000000000000..b13654a79069 --- /dev/null +++ b/arch/nds32/include/asm/highmem.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// Copyright (C) 2005-2017 Andes Technology Corporation + +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#include +#include +#include +#include + +/* + * Right now we initialize only a single pte table. It can be extended + * easily, subsequent pte tables have to be allocated in one physical + * chunk of RAM. + */ +/* + * Ordering is (from lower to higher memory addresses): + * + * high_memory + * Persistent kmap area + * PKMAP_BASE + * fixed_addresses + * FIXADDR_START + * FIXADDR_TOP + * Vmalloc area + * VMALLOC_START + * VMALLOC_END + */ +#define PKMAP_BASE ((FIXADDR_START - PGDIR_SIZE) & (PGDIR_MASK)) +#define LAST_PKMAP PTRS_PER_PTE +#define LAST_PKMAP_MASK (LAST_PKMAP - 1) +#define PKMAP_NR(virt) (((virt) - (PKMAP_BASE)) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) +#define kmap_prot PAGE_KERNEL + +static inline void flush_cache_kmaps(void) +{ + cpu_dcache_wbinval_all(); +} + +/* declarations for highmem.c */ +extern unsigned long highstart_pfn, highend_pfn; + +extern pte_t *pkmap_page_table; + +extern void kunmap_high(struct page *page); + +extern void kmap_init(void); + +/* + * The following functions are already defined by + * when CONFIG_HIGHMEM is not set. + */ +#ifdef CONFIG_HIGHMEM +extern void kunmap(struct page *page); +extern void *kmap_atomic(struct page *page); +extern void __kunmap_atomic(void *kvaddr); +extern void *kmap_atomic_pfn(unsigned long pfn); +extern struct page *kmap_atomic_to_page(void *ptr); +#endif + +#endif diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index caaf6e00630d..0d367c7aea04 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h @@ -58,19 +58,10 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void *kmap_high(struct page *page); extern void kunmap_high(struct page *page); extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); extern void __kunmap_atomic(void *kvaddr); -static inline void *kmap(struct page *page) -{ - might_sleep(); - if (!PageHighMem(page)) - return page_address(page); - return kmap_high(page); -} - static inline void kunmap(struct page *page) { BUG_ON(in_interrupt()); diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 4f9e15c757e2..591ae2ff99e4 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -49,7 +49,6 @@ extern void kmap_init(void) __init; #define PKMAP_END (PKMAP_ADDR(LAST_PKMAP)) -extern void *kmap_high(struct page *page); extern void kunmap_high(struct page *page); static inline void *kmap(struct page *page) diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h index 302a323b3f67..bdd0fb091492 100644 --- a/arch/x86/include/asm/highmem.h +++ b/arch/x86/include/asm/highmem.h @@ -54,10 +54,8 @@ extern unsigned long highstart_pfn, highend_pfn; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void *kmap_high(struct page *page); extern void kunmap_high(struct page *page); -void *kmap(struct page *page); void kunmap(struct page *page); void *kmap_atomic_prot(struct page *page, pgprot_t prot); diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index eecb207a2037..2df9794d4b2a 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -3,15 +3,6 @@ #include /* for totalram_pages */ #include -void *kmap(struct page *page) -{ - might_sleep(); - if (!PageHighMem(page)) - return page_address(page); - return kmap_high(page); -} -EXPORT_SYMBOL(kmap); - void kunmap(struct page *page) { if (in_interrupt()) diff --git a/arch/xtensa/include/asm/highmem.h b/arch/xtensa/include/asm/highmem.h index 80be15124697..b00394a2afc7 100644 --- a/arch/xtensa/include/asm/highmem.h +++ b/arch/xtensa/include/asm/highmem.h @@ -11,6 +11,75 @@ #ifndef _XTENSA_HIGHMEM_H #define _XTENSA_HIGHMEM_H -extern void flush_cache_kmaps(void); +#include +#include +#include +#include +#include + +#define PKMAP_BASE ((FIXADDR_START - \ + (LAST_PKMAP + 1) * PAGE_SIZE) & PMD_MASK) +#define LAST_PKMAP (PTRS_PER_PTE * DCACHE_N_COLORS) +#define LAST_PKMAP_MASK (LAST_PKMAP - 1) +#define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +#define kmap_prot PAGE_KERNEL_EXEC + +#if DCACHE_WAY_SIZE > PAGE_SIZE +#define get_pkmap_color get_pkmap_color +static inline int get_pkmap_color(struct page *page) +{ + return DCACHE_ALIAS(page_to_phys(page)); +} + +extern unsigned int last_pkmap_nr_arr[]; + +static inline unsigned int get_next_pkmap_nr(unsigned int color) +{ + last_pkmap_nr_arr[color] = + (last_pkmap_nr_arr[color] + DCACHE_N_COLORS) & LAST_PKMAP_MASK; + return last_pkmap_nr_arr[color] + color; +} + +static inline int no_more_pkmaps(unsigned int pkmap_nr, unsigned int color) +{ + return pkmap_nr < DCACHE_N_COLORS; +} + +static inline int get_pkmap_entries_count(unsigned int color) +{ + return LAST_PKMAP / DCACHE_N_COLORS; +} + +extern wait_queue_head_t pkmap_map_wait_arr[]; + +static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) +{ + return pkmap_map_wait_arr + color; +} +#endif + +extern pte_t *pkmap_page_table; + +void kunmap_high(struct page *page); + +static inline void kunmap(struct page *page) +{ + might_sleep(); + if (!PageHighMem(page)) + return; + kunmap_high(page); +} + +static inline void flush_cache_kmaps(void) +{ + flush_cache_all(); +} + +void *kmap_atomic(struct page *page); +void __kunmap_atomic(void *kvaddr); + +void kmap_init(void); #endif diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 02a8e994f14f..fab0a1b9084e 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -34,6 +34,24 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size) #ifdef CONFIG_HIGHMEM #include +#ifndef ARCH_HAS_KMAP_FLUSH_TLB +static inline void kmap_flush_tlb(unsigned long addr) { } +#endif + +void *kmap_high(struct page *page); +static inline void *kmap(struct page *page) +{ + void *addr; + + might_sleep(); + if (!PageHighMem(page)) + addr = page_address(page); + else + addr = kmap_high(page); + kmap_flush_tlb((unsigned long)addr); + return addr; +} + /* declarations for linux/mm/highmem.c */ unsigned int nr_free_highpages(void); extern unsigned long totalhigh_pages; -- GitLab From 93a3203c5b7736c3e4dd000de778540a47967ac8 Mon Sep 17 00:00:00 2001 From: threader Date: Sat, 7 Aug 2021 15:29:22 +0200 Subject: [PATCH 507/528] arch/kmap: clean-up after b365c5d17d7e --- arch/csky/include/asm/highmem.h | 51 -------------------------- arch/nds32/include/asm/highmem.h | 63 -------------------------------- 2 files changed, 114 deletions(-) delete mode 100644 arch/csky/include/asm/highmem.h delete mode 100644 arch/nds32/include/asm/highmem.h diff --git a/arch/csky/include/asm/highmem.h b/arch/csky/include/asm/highmem.h deleted file mode 100644 index 9d0516e38110..000000000000 --- a/arch/csky/include/asm/highmem.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. - -#ifndef __ASM_CSKY_HIGHMEM_H -#define __ASM_CSKY_HIGHMEM_H - -#ifdef __KERNEL__ - -#include -#include -#include -#include -#include - -/* undef for production */ -#define HIGHMEM_DEBUG 1 - -/* declarations for highmem.c */ -extern unsigned long highstart_pfn, highend_pfn; - -extern pte_t *pkmap_page_table; - -/* - * Right now we initialize only a single pte table. It can be extended - * easily, subsequent pte tables have to be allocated in one physical - * chunk of RAM. - */ -#define LAST_PKMAP 1024 -#define LAST_PKMAP_MASK (LAST_PKMAP-1) -#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) -#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) - -extern void kunmap_high(struct page *page); - -#define ARCH_HAS_KMAP_FLUSH_TLB -extern void kmap_flush_tlb(unsigned long addr); -extern void kunmap(struct page *page); -extern void *kmap_atomic(struct page *page); -extern void __kunmap_atomic(void *kvaddr); -extern void *kmap_atomic_pfn(unsigned long pfn); -extern struct page *kmap_atomic_to_page(void *ptr); - -#define flush_cache_kmaps() do {} while (0) - -extern void kmap_init(void); - -#define kmap_prot PAGE_KERNEL - -#endif /* __KERNEL__ */ - -#endif /* __ASM_CSKY_HIGHMEM_H */ diff --git a/arch/nds32/include/asm/highmem.h b/arch/nds32/include/asm/highmem.h deleted file mode 100644 index b13654a79069..000000000000 --- a/arch/nds32/include/asm/highmem.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASM_HIGHMEM_H -#define _ASM_HIGHMEM_H - -#include -#include -#include -#include - -/* - * Right now we initialize only a single pte table. It can be extended - * easily, subsequent pte tables have to be allocated in one physical - * chunk of RAM. - */ -/* - * Ordering is (from lower to higher memory addresses): - * - * high_memory - * Persistent kmap area - * PKMAP_BASE - * fixed_addresses - * FIXADDR_START - * FIXADDR_TOP - * Vmalloc area - * VMALLOC_START - * VMALLOC_END - */ -#define PKMAP_BASE ((FIXADDR_START - PGDIR_SIZE) & (PGDIR_MASK)) -#define LAST_PKMAP PTRS_PER_PTE -#define LAST_PKMAP_MASK (LAST_PKMAP - 1) -#define PKMAP_NR(virt) (((virt) - (PKMAP_BASE)) >> PAGE_SHIFT) -#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -#define kmap_prot PAGE_KERNEL - -static inline void flush_cache_kmaps(void) -{ - cpu_dcache_wbinval_all(); -} - -/* declarations for highmem.c */ -extern unsigned long highstart_pfn, highend_pfn; - -extern pte_t *pkmap_page_table; - -extern void kunmap_high(struct page *page); - -extern void kmap_init(void); - -/* - * The following functions are already defined by - * when CONFIG_HIGHMEM is not set. - */ -#ifdef CONFIG_HIGHMEM -extern void kunmap(struct page *page); -extern void *kmap_atomic(struct page *page); -extern void __kunmap_atomic(void *kvaddr); -extern void *kmap_atomic_pfn(unsigned long pfn); -extern struct page *kmap_atomic_to_page(void *ptr); -#endif - -#endif -- GitLab From f31ce0b3619273c8d416d598f93e357001c2fe4c Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Thu, 4 Jun 2020 16:47:34 -0700 Subject: [PATCH 508/528] arch/kunmap: remove duplicate kunmap implementations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All architectures do exactly the same thing for kunmap(); remove all the duplicate definitions and lift the call to the core. This also has the benefit of changing kmap_unmap() on a number of architectures to be an inline call rather than an actual function. [akpm@linux-foundation.org: fix CONFIG_HIGHMEM=n build on various architectures] Signed-off-by: Ira Weiny Signed-off-by: Andrew Morton Reviewed-by: Christoph Hellwig Cc: Al Viro Cc: Andy Lutomirski Cc: Benjamin Herrenschmidt Cc: Borislav Petkov Cc: Christian König Cc: Chris Zankel Cc: Daniel Vetter Cc: Dan Williams Cc: Dave Hansen Cc: "David S. Miller" Cc: Helge Deller Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: "James E.J. Bottomley" Cc: Max Filippov Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Bogendoerfer Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20200507150004.1423069-5-ira.weiny@intel.com Signed-off-by: Linus Torvalds (cherry picked from commit e23c45976f82ac789469c37e4d5a72ea2ce30bba) --- arch/arm/include/asm/highmem.h | 3 --- arch/arm/mm/highmem.c | 10 ---------- arch/microblaze/include/asm/highmem.h | 9 --------- arch/mips/include/asm/highmem.h | 3 --- arch/mips/mm/highmem.c | 9 --------- arch/powerpc/include/asm/highmem.h | 9 --------- arch/sparc/include/asm/highmem.h | 18 ------------------ arch/x86/include/asm/highmem.h | 4 ---- arch/x86/mm/highmem_32.c | 10 ---------- arch/xtensa/include/asm/highmem.h | 10 ---------- include/linux/highmem.h | 14 ++++++++++++++ 11 files changed, 14 insertions(+), 85 deletions(-) diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index d92e47abc771..f8e6a33ff31c 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -19,8 +19,6 @@ extern pte_t *pkmap_page_table; -extern void kunmap_high(struct page *page); - /* * The reason for kmap_high_get() is to ensure that the currently kmap'd * page usage count does not decrease to zero while we're using its @@ -61,7 +59,6 @@ static inline void *kmap_high_get(struct page *page) * when CONFIG_HIGHMEM is not set. */ #ifdef CONFIG_HIGHMEM -extern void kunmap(struct page *page); extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index 15c3a11aab76..f7e9f341fa0d 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -19,16 +19,6 @@ #include #include "mm.h" - -void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} -EXPORT_SYMBOL(kunmap); - void *kmap_atomic(struct page *page) { unsigned int idx; diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h index c2ccd1f3a4e1..0460d8134afa 100644 --- a/arch/microblaze/include/asm/highmem.h +++ b/arch/microblaze/include/asm/highmem.h @@ -50,18 +50,9 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void kunmap_high(struct page *page); extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); extern void __kunmap_atomic(void *kvaddr); -static inline void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} - static inline void *kmap_atomic(struct page *page) { return kmap_atomic_prot(page, kmap_prot); diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 881a5a4999cc..d8086fb0d896 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -42,11 +42,8 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void kunmap_high(struct page *page); - #define ARCH_HAS_KMAP_FLUSH_TLB extern void kmap_flush_tlb(unsigned long addr); -extern void kunmap(struct page *page); extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 585a14901f16..956bb0be9f26 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -16,15 +16,6 @@ void kmap_flush_tlb(unsigned long addr) } EXPORT_SYMBOL(kmap_flush_tlb); -void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} -EXPORT_SYMBOL(kunmap); - /* * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because * no global lock is needed and because the kmap code must perform a global TLB diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index 0d367c7aea04..4d8e004bc8b2 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h @@ -58,18 +58,9 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void kunmap_high(struct page *page); extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); extern void __kunmap_atomic(void *kvaddr); -static inline void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} - static inline void *kmap_atomic(struct page *page) { return kmap_atomic_prot(page, kmap_prot); diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 591ae2ff99e4..5100713c0afa 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -49,24 +49,6 @@ extern void kmap_init(void) __init; #define PKMAP_END (PKMAP_ADDR(LAST_PKMAP)) -extern void kunmap_high(struct page *page); - -static inline void *kmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return page_address(page); - return kmap_high(page); -} - -static inline void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} - extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h index bdd0fb091492..a14812bf3a69 100644 --- a/arch/x86/include/asm/highmem.h +++ b/arch/x86/include/asm/highmem.h @@ -54,10 +54,6 @@ extern unsigned long highstart_pfn, highend_pfn; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void kunmap_high(struct page *page); - -void kunmap(struct page *page); - void *kmap_atomic_prot(struct page *page, pgprot_t prot); void *kmap_atomic(struct page *page); void __kunmap_atomic(void *kvaddr); diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index 2df9794d4b2a..6012d38df807 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -3,16 +3,6 @@ #include /* for totalram_pages */ #include -void kunmap(struct page *page) -{ - if (in_interrupt()) - BUG(); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} -EXPORT_SYMBOL(kunmap); - /* * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because * no global lock is needed and because the kmap code must perform a global TLB diff --git a/arch/xtensa/include/asm/highmem.h b/arch/xtensa/include/asm/highmem.h index b00394a2afc7..e778913ecc08 100644 --- a/arch/xtensa/include/asm/highmem.h +++ b/arch/xtensa/include/asm/highmem.h @@ -62,16 +62,6 @@ static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) extern pte_t *pkmap_page_table; -void kunmap_high(struct page *page); - -static inline void kunmap(struct page *page) -{ - might_sleep(); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} - static inline void flush_cache_kmaps(void) { flush_cache_all(); diff --git a/include/linux/highmem.h b/include/linux/highmem.h index fab0a1b9084e..aa41ca5a95fa 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -52,6 +52,16 @@ static inline void *kmap(struct page *page) return addr; } +void kunmap_high(struct page *page); + +static inline void kunmap(struct page *page) +{ + might_sleep(); + if (!PageHighMem(page)) + return; + kunmap_high(page); +} + /* declarations for linux/mm/highmem.c */ unsigned int nr_free_highpages(void); extern unsigned long totalhigh_pages; @@ -84,6 +94,10 @@ static inline void *kmap(struct page *page) return page_address(page); } +static inline void kunmap_high(struct page *page) +{ +} + static inline void kunmap(struct page *page) { } -- GitLab From 2a5a03a3213bc5d046b623128eb29339f48e1741 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Thu, 4 Jun 2020 16:47:42 -0700 Subject: [PATCH 509/528] arch/kmap_atomic: consolidate duplicate code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every arch has the same code to ensure atomic operations and a check for !HIGHMEM page. Remove the duplicate code by defining a core kmap_atomic() which only calls the arch specific kmap_atomic_high() when the page is high memory. [akpm@linux-foundation.org: coding style fixes] Signed-off-by: Ira Weiny Signed-off-by: Andrew Morton Reviewed-by: Christoph Hellwig Cc: Al Viro Cc: Andy Lutomirski Cc: Benjamin Herrenschmidt Cc: Borislav Petkov Cc: Christian König Cc: Chris Zankel Cc: Daniel Vetter Cc: Dan Williams Cc: Dave Hansen Cc: "David S. Miller" Cc: Helge Deller Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: "James E.J. Bottomley" Cc: Max Filippov Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Bogendoerfer Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20200507150004.1423069-7-ira.weiny@intel.com Signed-off-by: Linus Torvalds (cherry picked from commit 78b6d91ec7bbfc5bcc2dd05bb2cf13c9de1dc7cd) --- arch/arm/include/asm/highmem.h | 1 - arch/arm/mm/highmem.c | 9 ++------- arch/microblaze/include/asm/highmem.h | 4 ++-- arch/mips/include/asm/highmem.h | 1 - arch/mips/mm/cache.c | 1 + arch/mips/mm/highmem.c | 18 ++---------------- arch/powerpc/include/asm/highmem.h | 4 ++-- arch/powerpc/mm/highmem.c | 8 +------- arch/sparc/include/asm/highmem.h | 1 - arch/sparc/mm/highmem.c | 9 ++------- arch/x86/include/asm/highmem.h | 16 ++++++++++++++-- arch/x86/mm/highmem_32.c | 7 +------ arch/xtensa/include/asm/highmem.h | 1 - arch/xtensa/mm/highmem.c | 9 ++------- include/linux/highmem.h | 23 +++++++++++++++++++++++ 15 files changed, 52 insertions(+), 60 deletions(-) diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index f8e6a33ff31c..ef57a6dfea0c 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -59,7 +59,6 @@ static inline void *kmap_high_get(struct page *page) * when CONFIG_HIGHMEM is not set. */ #ifdef CONFIG_HIGHMEM -extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(const void *ptr); diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index f7e9f341fa0d..775e8363c40e 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -19,18 +19,13 @@ #include #include "mm.h" -void *kmap_atomic(struct page *page) +void *kmap_atomic_high(struct page *page) { unsigned int idx; unsigned long vaddr; void *kmap; int type; - preempt_disable(); - pagefault_disable(); - if (!PageHighMem(page)) - return page_address(page); - #ifdef CONFIG_DEBUG_HIGHMEM /* * There is no cache coherency issue when non VIVT, so force the @@ -64,7 +59,7 @@ void *kmap_atomic(struct page *page) return (void *)vaddr; } -EXPORT_SYMBOL(kmap_atomic); +EXPORT_SYMBOL(kmap_atomic_high); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h index 0460d8134afa..ed5d1103a6c1 100644 --- a/arch/microblaze/include/asm/highmem.h +++ b/arch/microblaze/include/asm/highmem.h @@ -53,9 +53,9 @@ extern pte_t *pkmap_page_table; extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); extern void __kunmap_atomic(void *kvaddr); -static inline void *kmap_atomic(struct page *page) +static inline void *kmap_atomic_high(struct page *page) { - return kmap_atomic_prot(page, kmap_prot); + return kmap_atomic_high_prot(page, kmap_prot); } static inline struct page *kmap_atomic_to_page(void *ptr) diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index d8086fb0d896..6c5daf42d86e 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -44,7 +44,6 @@ extern pte_t *pkmap_page_table; #define ARCH_HAS_KMAP_FLUSH_TLB extern void kmap_flush_tlb(unsigned long addr); -extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(void *ptr); diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 5aeb3eb0b72f..d4c5763eca72 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 956bb0be9f26..6d4abee69ac9 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -16,25 +16,11 @@ void kmap_flush_tlb(unsigned long addr) } EXPORT_SYMBOL(kmap_flush_tlb); -/* - * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because - * no global lock is needed and because the kmap code must perform a global TLB - * invalidation when the kmap pool wraps. - * - * However when holding an atomic kmap is is not legal to sleep, so atomic - * kmaps are appropriate for short, tight code paths only. - */ - -void *kmap_atomic(struct page *page) +void *kmap_atomic_high(struct page *page) { unsigned long vaddr; int idx, type; - preempt_disable(); - pagefault_disable(); - if (!PageHighMem(page)) - return page_address(page); - type = kmap_atomic_idx_push(); idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); @@ -46,7 +32,7 @@ void *kmap_atomic(struct page *page) return (void*) vaddr; } -EXPORT_SYMBOL(kmap_atomic); +EXPORT_SYMBOL(kmap_atomic_high); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index 4d8e004bc8b2..59923a074a6d 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h @@ -61,9 +61,9 @@ extern pte_t *pkmap_page_table; extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); extern void __kunmap_atomic(void *kvaddr); -static inline void *kmap_atomic(struct page *page) +static inline void *kmap_atomic_high(struct page *page) { - return kmap_atomic_prot(page, kmap_prot); + return kmap_atomic_high_prot(page, kmap_prot); } static inline struct page *kmap_atomic_to_page(void *ptr) diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c index e292c8a60952..a3fe348e9020 100644 --- a/arch/powerpc/mm/highmem.c +++ b/arch/powerpc/mm/highmem.c @@ -23,13 +23,7 @@ #include #include -/* - * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap - * gives a more generic (and caching) interface. But kmap_atomic can - * be used in IRQ contexts, so in some (very limited) cases we need - * it. - */ -void *kmap_atomic_prot(struct page *page, pgprot_t prot) +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { unsigned long vaddr; int idx, type; diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 5100713c0afa..62bd3fbcd336 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -49,7 +49,6 @@ extern void kmap_init(void) __init; #define PKMAP_END (PKMAP_ADDR(LAST_PKMAP)) -extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); #define flush_cache_kmaps() flush_cache_all() diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index a454ec5ff07a..af50799e7691 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -48,16 +48,11 @@ void __init kmap_init(void) kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE); } -void *kmap_atomic(struct page *page) +void *kmap_atomic_high(struct page *page) { unsigned long vaddr; long idx, type; - preempt_disable(); - pagefault_disable(); - if (!PageHighMem(page)) - return page_address(page); - type = kmap_atomic_idx_push(); idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); @@ -82,7 +77,7 @@ void *kmap_atomic(struct page *page) return (void*) vaddr; } -EXPORT_SYMBOL(kmap_atomic); +EXPORT_SYMBOL(kmap_atomic_high); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h index a14812bf3a69..dde8a21af996 100644 --- a/arch/x86/include/asm/highmem.h +++ b/arch/x86/include/asm/highmem.h @@ -54,8 +54,20 @@ extern unsigned long highstart_pfn, highend_pfn; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -void *kmap_atomic_prot(struct page *page, pgprot_t prot); -void *kmap_atomic(struct page *page); +extern void *kmap_atomic_high_prot(struct page *page, pgprot_t prot); +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) +{ + preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + + return kmap_atomic_high_prot(page, prot); +} +static inline void *kmap_atomic_high(struct page *page) +{ + return kmap_atomic_high_prot(page, kmap_prot); +} void __kunmap_atomic(void *kvaddr); void *kmap_atomic_pfn(unsigned long pfn); void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot); diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index 6012d38df807..400194ba7903 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -3,6 +3,7 @@ #include /* for totalram_pages */ #include + /* * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because * no global lock is needed and because the kmap code must perform a global TLB @@ -33,12 +34,6 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void *kmap_atomic(struct page *page) -{ - return kmap_atomic_prot(page, kmap_prot); -} -EXPORT_SYMBOL(kmap_atomic); - /* * This is the same as kmap_atomic() but can map memory that doesn't * have a struct page associated with it. diff --git a/arch/xtensa/include/asm/highmem.h b/arch/xtensa/include/asm/highmem.h index e778913ecc08..088c5663e838 100644 --- a/arch/xtensa/include/asm/highmem.h +++ b/arch/xtensa/include/asm/highmem.h @@ -67,7 +67,6 @@ static inline void flush_cache_kmaps(void) flush_cache_all(); } -void *kmap_atomic(struct page *page); void __kunmap_atomic(void *kvaddr); void kmap_init(void); diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c index 184ceadccc1a..f13a64ef09dd 100644 --- a/arch/xtensa/mm/highmem.c +++ b/arch/xtensa/mm/highmem.c @@ -37,16 +37,11 @@ static inline enum fixed_addresses kmap_idx(int type, unsigned long color) color; } -void *kmap_atomic(struct page *page) +void *kmap_atomic_high(struct page *page) { enum fixed_addresses idx; unsigned long vaddr; - preempt_disable(); - pagefault_disable(); - if (!PageHighMem(page)) - return page_address(page); - idx = kmap_idx(kmap_atomic_idx_push(), DCACHE_ALIAS(page_to_phys(page))); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); @@ -57,7 +52,7 @@ void *kmap_atomic(struct page *page) return (void *)vaddr; } -EXPORT_SYMBOL(kmap_atomic); +EXPORT_SYMBOL(kmap_atomic_high); void __kunmap_atomic(void *kvaddr) { diff --git a/include/linux/highmem.h b/include/linux/highmem.h index aa41ca5a95fa..2a2ec9d5e59e 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -32,6 +32,7 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size) #include #ifdef CONFIG_HIGHMEM +extern void *kmap_atomic_high(struct page *page); #include #ifndef ARCH_HAS_KMAP_FLUSH_TLB @@ -62,6 +63,28 @@ static inline void kunmap(struct page *page) kunmap_high(page); } +/* + * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because + * no global lock is needed and because the kmap code must perform a global TLB + * invalidation when the kmap pool wraps. + * + * However when holding an atomic kmap is is not legal to sleep, so atomic + * kmaps are appropriate for short, tight code paths only. + * + * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap + * gives a more generic (and caching) interface. But kmap_atomic can + * be used in IRQ contexts, so in some (very limited) cases we need + * it. + */ +static inline void *kmap_atomic(struct page *page) +{ + preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + return kmap_atomic_high(page); +} + /* declarations for linux/mm/highmem.c */ unsigned int nr_free_highpages(void); extern unsigned long totalhigh_pages; -- GitLab From 462964ea5f0249c88836f277b90d4cf021eafaf1 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Thu, 4 Jun 2020 16:47:46 -0700 Subject: [PATCH 510/528] arch/kunmap_atomic: consolidate duplicate code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every single architecture (including !CONFIG_HIGHMEM) calls... pagefault_enable(); preempt_enable(); ... before returning from __kunmap_atomic(). Lift this code into the kunmap_atomic() macro. While we are at it rename __kunmap_atomic() to kunmap_atomic_high() to be consistent. [ira.weiny@intel.com: don't enable pagefault/preempt twice] Link: http://lkml.kernel.org/r/20200518184843.3029640-1-ira.weiny@intel.com [akpm@linux-foundation.org: coding style fixes] Signed-off-by: Ira Weiny Signed-off-by: Andrew Morton Reviewed-by: Christoph Hellwig Cc: Al Viro Cc: Andy Lutomirski Cc: Benjamin Herrenschmidt Cc: Borislav Petkov Cc: Christian König Cc: Chris Zankel Cc: Daniel Vetter Cc: Dan Williams Cc: Dave Hansen Cc: "David S. Miller" Cc: Helge Deller Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: "James E.J. Bottomley" Cc: Max Filippov Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Bogendoerfer Cc: Thomas Gleixner Cc: Guenter Roeck Link: http://lkml.kernel.org/r/20200507150004.1423069-8-ira.weiny@intel.com Signed-off-by: Linus Torvalds (cherry picked from commit abca2500c0c1b20c3e552f259da4c4a99db3b4d1) --- arch/arm/include/asm/highmem.h | 1 - arch/arm/mm/highmem.c | 6 ++---- arch/microblaze/include/asm/highmem.h | 11 +++++++++-- arch/microblaze/mm/highmem.c | 11 +++-------- arch/mips/include/asm/highmem.h | 1 - arch/mips/mm/cache.c | 7 +++++++ arch/mips/mm/highmem.c | 11 +++-------- arch/parisc/include/asm/cacheflush.h | 4 +--- arch/powerpc/include/asm/highmem.h | 11 +++++++++-- arch/powerpc/mm/highmem.c | 11 +++-------- arch/sparc/include/asm/highmem.h | 2 -- arch/sparc/mm/highmem.c | 11 +++-------- arch/x86/include/asm/highmem.h | 1 - arch/x86/mm/highmem_32.c | 7 ++----- arch/xtensa/include/asm/highmem.h | 2 -- arch/xtensa/mm/highmem.c | 7 ++----- include/linux/highmem.h | 13 +++++++++---- 17 files changed, 53 insertions(+), 64 deletions(-) diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index ef57a6dfea0c..49a83c8cbda5 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -59,7 +59,6 @@ static inline void *kmap_high_get(struct page *page) * when CONFIG_HIGHMEM is not set. */ #ifdef CONFIG_HIGHMEM -extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(const void *ptr); #endif diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index 775e8363c40e..e34ba894ad7a 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -61,7 +61,7 @@ void *kmap_atomic_high(struct page *page) } EXPORT_SYMBOL(kmap_atomic_high); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int idx, type; @@ -83,10 +83,8 @@ void __kunmap_atomic(void *kvaddr) /* this address was obtained through kmap_high_get() */ kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)])); } - pagefault_enable(); - preempt_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); void *kmap_atomic_pfn(unsigned long pfn) { diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h index ed5d1103a6c1..0936682a3bd4 100644 --- a/arch/microblaze/include/asm/highmem.h +++ b/arch/microblaze/include/asm/highmem.h @@ -50,8 +50,15 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); -extern void __kunmap_atomic(void *kvaddr); +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) +{ + preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + + return kmap_atomic_high_prot(page, prot); +} static inline void *kmap_atomic_high(struct page *page) { diff --git a/arch/microblaze/mm/highmem.c b/arch/microblaze/mm/highmem.c index 2fcc5a52d84d..a05686b7eedf 100644 --- a/arch/microblaze/mm/highmem.c +++ b/arch/microblaze/mm/highmem.c @@ -56,16 +56,13 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int type; - if (vaddr < __fix_to_virt(FIX_KMAP_END)) { - pagefault_enable(); - preempt_enable(); + if (vaddr < __fix_to_virt(FIX_KMAP_END)) return; - } type = kmap_atomic_idx(); #ifdef CONFIG_DEBUG_HIGHMEM @@ -84,7 +81,5 @@ void __kunmap_atomic(void *kvaddr) } #endif kmap_atomic_idx_pop(); - pagefault_enable(); - preempt_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 6c5daf42d86e..6209b20e8a25 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -44,7 +44,6 @@ extern pte_t *pkmap_page_table; #define ARCH_HAS_KMAP_FLUSH_TLB extern void kmap_flush_tlb(unsigned long addr); -extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(void *ptr); diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index d4c5763eca72..44fb5f594679 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -98,6 +98,9 @@ void __flush_dcache_page(struct page *page) */ addr = (unsigned long) page_address(page); flush_data_cache_page(addr); + + if (PageHighMem(page)) + kunmap_atomic((void *)addr); } EXPORT_SYMBOL(__flush_dcache_page); @@ -135,6 +138,10 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address, addr = (unsigned long) page_address(page); if (exec || pages_do_alias(addr, address & PAGE_MASK)) flush_data_cache_page(addr); + + if (PageHighMem(page)) + kunmap_atomic((void *)addr); + ClearPageDcacheDirty(page); } } diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 6d4abee69ac9..45d5ff35aa56 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -34,16 +34,13 @@ void *kmap_atomic_high(struct page *page) } EXPORT_SYMBOL(kmap_atomic_high); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int type __maybe_unused; - if (vaddr < FIXADDR_START) { // FIXME - pagefault_enable(); - preempt_enable(); + if (vaddr < FIXADDR_START) return; - } type = kmap_atomic_idx(); #ifdef CONFIG_DEBUG_HIGHMEM @@ -61,10 +58,8 @@ void __kunmap_atomic(void *kvaddr) } #endif kmap_atomic_idx_pop(); - pagefault_enable(); - preempt_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); /* * This is the same as kmap_atomic() but can map memory that doesn't diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index ec2df4bab302..8431c133f6ea 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -147,11 +147,9 @@ static inline void *kmap_atomic(struct page *page) return page_address(page); } -static inline void __kunmap_atomic(void *addr) +static inline void kunmap_atomic_high(void *addr) { flush_kernel_dcache_page_addr(addr); - pagefault_enable(); - preempt_enable(); } #define kmap_atomic_prot(page, prot) kmap_atomic(page) diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index 59923a074a6d..d466cc49368f 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h @@ -58,8 +58,15 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); -extern void __kunmap_atomic(void *kvaddr); +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) +{ + preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + + return kmap_atomic_high_prot(page, prot); +} static inline void *kmap_atomic_high(struct page *page) { diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c index a3fe348e9020..861b6ccfe748 100644 --- a/arch/powerpc/mm/highmem.c +++ b/arch/powerpc/mm/highmem.c @@ -46,16 +46,13 @@ void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int type; - if (vaddr < __fix_to_virt(FIX_KMAP_END)) { - pagefault_enable(); - preempt_enable(); + if (vaddr < __fix_to_virt(FIX_KMAP_END)) return; - } type = kmap_atomic_idx(); @@ -76,7 +73,5 @@ void __kunmap_atomic(void *kvaddr) #endif kmap_atomic_idx_pop(); - pagefault_enable(); - preempt_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 62bd3fbcd336..541c8945a76c 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -49,8 +49,6 @@ extern void kmap_init(void) __init; #define PKMAP_END (PKMAP_ADDR(LAST_PKMAP)) -extern void __kunmap_atomic(void *kvaddr); - #define flush_cache_kmaps() flush_cache_all() #endif /* __KERNEL__ */ diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index af50799e7691..da4cc3cfd61a 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -79,16 +79,13 @@ void *kmap_atomic_high(struct page *page) } EXPORT_SYMBOL(kmap_atomic_high); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int type; - if (vaddr < FIXADDR_START) { // FIXME - pagefault_enable(); - preempt_enable(); + if (vaddr < FIXADDR_START) return; - } type = kmap_atomic_idx(); @@ -121,7 +118,5 @@ void __kunmap_atomic(void *kvaddr) #endif kmap_atomic_idx_pop(); - pagefault_enable(); - preempt_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h index dde8a21af996..7a54953dc3cd 100644 --- a/arch/x86/include/asm/highmem.h +++ b/arch/x86/include/asm/highmem.h @@ -68,7 +68,6 @@ static inline void *kmap_atomic_high(struct page *page) { return kmap_atomic_high_prot(page, kmap_prot); } -void __kunmap_atomic(void *kvaddr); void *kmap_atomic_pfn(unsigned long pfn); void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot); struct page *kmap_atomic_to_page(void *ptr); diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index 400194ba7903..334a69c1f00d 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -44,7 +44,7 @@ void *kmap_atomic_pfn(unsigned long pfn) } EXPORT_SYMBOL_GPL(kmap_atomic_pfn); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; @@ -74,11 +74,8 @@ void __kunmap_atomic(void *kvaddr) BUG_ON(vaddr >= (unsigned long)high_memory); } #endif - - pagefault_enable(); - preempt_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); struct page *kmap_atomic_to_page(void *ptr) { diff --git a/arch/xtensa/include/asm/highmem.h b/arch/xtensa/include/asm/highmem.h index 088c5663e838..241fee8bdb06 100644 --- a/arch/xtensa/include/asm/highmem.h +++ b/arch/xtensa/include/asm/highmem.h @@ -67,8 +67,6 @@ static inline void flush_cache_kmaps(void) flush_cache_all(); } -void __kunmap_atomic(void *kvaddr); - void kmap_init(void); #endif diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c index f13a64ef09dd..a759f41149b3 100644 --- a/arch/xtensa/mm/highmem.c +++ b/arch/xtensa/mm/highmem.c @@ -54,7 +54,7 @@ void *kmap_atomic_high(struct page *page) } EXPORT_SYMBOL(kmap_atomic_high); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { if (kvaddr >= (void *)FIXADDR_START && kvaddr < (void *)FIXADDR_TOP) { @@ -73,11 +73,8 @@ void __kunmap_atomic(void *kvaddr) kmap_atomic_idx_pop(); } - - pagefault_enable(); - preempt_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); void __init kmap_init(void) { diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 2a2ec9d5e59e..cc7f7eb5bee7 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -33,6 +33,7 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size) #ifdef CONFIG_HIGHMEM extern void *kmap_atomic_high(struct page *page); +extern void kunmap_atomic_high(void *kvaddr); #include #ifndef ARCH_HAS_KMAP_FLUSH_TLB @@ -133,10 +134,12 @@ static inline void *kmap_atomic(struct page *page) } #define kmap_atomic_prot(page, prot) kmap_atomic(page) -static inline void __kunmap_atomic(void *addr) +static inline void kunmap_atomic_high(void *addr) { - pagefault_enable(); - preempt_enable(); + /* + * Nothing to do in the CONFIG_HIGHMEM=n case as kunmap_atomic() + * handles re-enabling faults + preemption + */ } #define kmap_atomic_pfn(pfn) kmap_atomic(pfn_to_page(pfn)) @@ -188,7 +191,9 @@ static inline void kmap_atomic_idx_pop(void) #define kunmap_atomic(addr) \ do { \ BUILD_BUG_ON(__same_type((addr), struct page *)); \ - __kunmap_atomic(addr); \ + kunmap_atomic_high(addr); \ + pagefault_enable(); \ + preempt_enable(); \ } while (0) -- GitLab From ac103e66945dab341e6dbc8c0e2ec84620f82326 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Thu, 4 Jun 2020 16:47:58 -0700 Subject: [PATCH 511/528] arch/kmap: define kmap_atomic_prot() for all arch's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support kmap_atomic_prot(), all architectures need to support protections passed to their kmap_atomic_high() function. Pass protections into kmap_atomic_high() and change the name to kmap_atomic_high_prot() to match. Then define kmap_atomic_prot() as a core function which calls kmap_atomic_high_prot() when needed. Finally, redefine kmap_atomic() as a wrapper of kmap_atomic_prot() with the default kmap_prot exported by the architectures. Signed-off-by: Ira Weiny Signed-off-by: Andrew Morton Reviewed-by: Christoph Hellwig Cc: Al Viro Cc: Andy Lutomirski Cc: Benjamin Herrenschmidt Cc: Borislav Petkov Cc: Christian König Cc: Chris Zankel Cc: Daniel Vetter Cc: Dan Williams Cc: Dave Hansen Cc: "David S. Miller" Cc: Helge Deller Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: "James E.J. Bottomley" Cc: Max Filippov Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Bogendoerfer Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20200507150004.1423069-11-ira.weiny@intel.com Signed-off-by: Linus Torvalds (cherry picked from commit 20b271dfe9d932b02b067a1f7ba9805c5b8d79bd) --- arch/arm/mm/highmem.c | 6 ++++-- arch/mips/mm/highmem.c | 6 +++--- arch/sparc/mm/highmem.c | 6 +++--- arch/x86/include/asm/highmem.h | 14 -------------- arch/xtensa/mm/highmem.c | 6 +++--- include/linux/highmem.h | 7 ++++--- 6 files changed, 17 insertions(+), 28 deletions(-) diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index e34ba894ad7a..cabcaddc03ff 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -19,7 +19,8 @@ #include #include "mm.h" -void *kmap_atomic_high(struct page *page) + +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { unsigned int idx; unsigned long vaddr; @@ -56,10 +57,11 @@ void *kmap_atomic_high(struct page *page) * with the new mapping. */ set_top_pte(vaddr, mk_pte(page, kmap_prot)); + //set_fixmap_pte(idx, mk_pte(page, prot)); return (void *)vaddr; } -EXPORT_SYMBOL(kmap_atomic_high); +EXPORT_SYMBOL(kmap_atomic_high_prot); void kunmap_atomic_high(void *kvaddr) { diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 45d5ff35aa56..fbb9df0c1c2f 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -16,7 +16,7 @@ void kmap_flush_tlb(unsigned long addr) } EXPORT_SYMBOL(kmap_flush_tlb); -void *kmap_atomic_high(struct page *page) +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { unsigned long vaddr; int idx, type; @@ -27,12 +27,12 @@ void *kmap_atomic_high(struct page *page) #ifdef CONFIG_DEBUG_HIGHMEM BUG_ON(!pte_none(*(kmap_pte - idx))); #endif - set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL)); + set_pte(kmap_pte-idx, mk_pte(page, prot)); local_flush_tlb_one((unsigned long)vaddr); return (void*) vaddr; } -EXPORT_SYMBOL(kmap_atomic_high); +EXPORT_SYMBOL(kmap_atomic_high_prot); void kunmap_atomic_high(void *kvaddr) { diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index da4cc3cfd61a..c0fdb7e9b5b1 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -48,7 +48,7 @@ void __init kmap_init(void) kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE); } -void *kmap_atomic_high(struct page *page) +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { unsigned long vaddr; long idx, type; @@ -67,7 +67,7 @@ void *kmap_atomic_high(struct page *page) #ifdef CONFIG_DEBUG_HIGHMEM BUG_ON(!pte_none(*(kmap_pte-idx))); #endif - set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); + set_pte(kmap_pte-idx, mk_pte(page, prot)); /* XXX Fix - Anton */ #if 0 __flush_tlb_one(vaddr); @@ -77,7 +77,7 @@ void *kmap_atomic_high(struct page *page) return (void*) vaddr; } -EXPORT_SYMBOL(kmap_atomic_high); +EXPORT_SYMBOL(kmap_atomic_high_prot); void kunmap_atomic_high(void *kvaddr) { diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h index 7a54953dc3cd..ce4a2294a9b5 100644 --- a/arch/x86/include/asm/highmem.h +++ b/arch/x86/include/asm/highmem.h @@ -54,20 +54,6 @@ extern unsigned long highstart_pfn, highend_pfn; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void *kmap_atomic_high_prot(struct page *page, pgprot_t prot); -static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) -{ - preempt_disable(); - pagefault_disable(); - if (!PageHighMem(page)) - return page_address(page); - - return kmap_atomic_high_prot(page, prot); -} -static inline void *kmap_atomic_high(struct page *page) -{ - return kmap_atomic_high_prot(page, kmap_prot); -} void *kmap_atomic_pfn(unsigned long pfn); void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot); struct page *kmap_atomic_to_page(void *ptr); diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c index a759f41149b3..e9145f0a9adb 100644 --- a/arch/xtensa/mm/highmem.c +++ b/arch/xtensa/mm/highmem.c @@ -37,7 +37,7 @@ static inline enum fixed_addresses kmap_idx(int type, unsigned long color) color; } -void *kmap_atomic_high(struct page *page) +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { enum fixed_addresses idx; unsigned long vaddr; @@ -48,11 +48,11 @@ void *kmap_atomic_high(struct page *page) #ifdef CONFIG_DEBUG_HIGHMEM BUG_ON(!pte_none(*(kmap_pte + idx))); #endif - set_pte(kmap_pte + idx, mk_pte(page, PAGE_KERNEL_EXEC)); + set_pte(kmap_pte + idx, mk_pte(page, prot)); return (void *)vaddr; } -EXPORT_SYMBOL(kmap_atomic_high); +EXPORT_SYMBOL(kmap_atomic_high_prot); void kunmap_atomic_high(void *kvaddr) { diff --git a/include/linux/highmem.h b/include/linux/highmem.h index cc7f7eb5bee7..5cad14ebb38c 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -32,7 +32,7 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size) #include #ifdef CONFIG_HIGHMEM -extern void *kmap_atomic_high(struct page *page); +extern void *kmap_atomic_high_prot(struct page *page, pgprot_t prot); extern void kunmap_atomic_high(void *kvaddr); #include @@ -77,14 +77,15 @@ static inline void kunmap(struct page *page) * be used in IRQ contexts, so in some (very limited) cases we need * it. */ -static inline void *kmap_atomic(struct page *page) +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) { preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); - return kmap_atomic_high(page); + return kmap_atomic_high_prot(page, prot); } +#define kmap_atomic(page) kmap_atomic_prot(page, kmap_prot) /* declarations for linux/mm/highmem.c */ unsigned int nr_free_highpages(void); -- GitLab From 23a51173645f0d1e6be64458258c1537e0b7351a Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Thu, 4 Jun 2020 16:48:18 -0700 Subject: [PATCH 512/528] kmap: consolidate kmap_prot definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most architectures define kmap_prot to be PAGE_KERNEL. Let sparc and xtensa define there own and define PAGE_KERNEL as the default if not overridden. [akpm@linux-foundation.org: coding style fixes] Suggested-by: Christoph Hellwig Signed-off-by: Ira Weiny Signed-off-by: Andrew Morton Cc: Al Viro Cc: Andy Lutomirski Cc: Benjamin Herrenschmidt Cc: Borislav Petkov Cc: Christian König Cc: Chris Zankel Cc: Daniel Vetter Cc: Dan Williams Cc: Dave Hansen Cc: "David S. Miller" Cc: Helge Deller Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: "James E.J. Bottomley" Cc: Max Filippov Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Bogendoerfer Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20200507150004.1423069-16-ira.weiny@intel.com Signed-off-by: Linus Torvalds (cherry picked from commit 090e77e166334b83f555de408df64b9ab394ea08) --- arch/arm/include/asm/highmem.h | 2 -- arch/mips/include/asm/highmem.h | 2 -- arch/sparc/include/asm/highmem.h | 3 ++- arch/sparc/mm/highmem.c | 3 --- arch/x86/include/asm/fixmap.h | 1 - include/linux/highmem.h | 4 ++++ 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index 49a83c8cbda5..d998c86bc9f3 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -9,8 +9,6 @@ #define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -#define kmap_prot PAGE_KERNEL - #define flush_cache_kmaps() \ do { \ if (cache_is_vivt()) \ diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 6209b20e8a25..9c5b703f4313 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -51,8 +51,6 @@ extern struct page *kmap_atomic_to_page(void *ptr); extern void kmap_init(void); -#define kmap_prot PAGE_KERNEL - #endif /* __KERNEL__ */ #endif /* _ASM_HIGHMEM_H */ diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 541c8945a76c..ea39323a0f33 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -24,11 +24,12 @@ #include #include #include +#include /* declarations for highmem.c */ extern unsigned long highstart_pfn, highend_pfn; -extern pgprot_t kmap_prot; +#define kmap_prot __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE) extern pte_t *pkmap_page_table; extern void kmap_init(void) __init; diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index c0fdb7e9b5b1..223886909245 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -31,8 +31,6 @@ #include #include -pgprot_t kmap_prot; - static pte_t *kmap_pte; void __init kmap_init(void) @@ -45,7 +43,6 @@ void __init kmap_init(void) /* cache the first kmap pte */ kmap_pte = pte_offset_kernel(dir, address); - kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE); } void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 9d7d36c82fc2..41d69dd35ced 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -160,7 +160,6 @@ extern void reserve_top_address(unsigned long reserve); extern int fixmaps_set; extern pte_t *kmap_pte; -extern pgprot_t kmap_prot; extern pte_t *pkmap_page_table; void __native_set_fixmap(enum fixed_addresses idx, pte_t pte); diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 5cad14ebb38c..bc015254a78f 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -40,6 +40,10 @@ extern void kunmap_atomic_high(void *kvaddr); static inline void kmap_flush_tlb(unsigned long addr) { } #endif +#ifndef kmap_prot +#define kmap_prot PAGE_KERNEL +#endif + void *kmap_high(struct page *page); static inline void *kmap(struct page *page) { -- GitLab From 5866d2f85892f63ba8bc2869ca1993d648fdd958 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 3 Nov 2020 10:27:18 +0100 Subject: [PATCH 513/528] highmem: Provide generic variant of kmap_atomic* The kmap_atomic* interfaces in all architectures are pretty much the same except for post map operations (flush) and pre- and post unmap operations. Provide a generic variant for that. Signed-off-by: Thomas Gleixner Cc: Linus Torvalds Cc: Christoph Hellwig Cc: Andrew Morton Link: https://lore.kernel.org/r/20201103095857.175939340@linutronix.de (cherry picked from commit 298fa1ad5571f59cb3ca5497a9455f36867f065e) --- include/linux/highmem.h | 88 ++++++++++++++++++++----- mm/Kconfig | 3 + mm/highmem.c | 142 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 214 insertions(+), 19 deletions(-) diff --git a/include/linux/highmem.h b/include/linux/highmem.h index bc015254a78f..98ccdb469bb0 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -31,9 +31,16 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size) #include +/* + * Outside of CONFIG_HIGHMEM to support X86 32bit iomap_atomic() cruft. + */ +#ifdef CONFIG_KMAP_LOCAL +void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot); +void *__kmap_local_page_prot(struct page *page, pgprot_t prot); +void kunmap_local_indexed(void *vaddr); +#endif + #ifdef CONFIG_HIGHMEM -extern void *kmap_atomic_high_prot(struct page *page, pgprot_t prot); -extern void kunmap_atomic_high(void *kvaddr); #include #ifndef ARCH_HAS_KMAP_FLUSH_TLB @@ -81,6 +88,11 @@ static inline void kunmap(struct page *page) * be used in IRQ contexts, so in some (very limited) cases we need * it. */ + +#ifndef CONFIG_KMAP_LOCAL +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot); +void kunmap_atomic_high(void *kvaddr); + static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) { preempt_disable(); @@ -89,7 +101,38 @@ static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) return page_address(page); return kmap_atomic_high_prot(page, prot); } -#define kmap_atomic(page) kmap_atomic_prot(page, kmap_prot) + +static inline void __kunmap_atomic(void *vaddr) +{ + kunmap_atomic_high(vaddr); +} +#else /* !CONFIG_KMAP_LOCAL */ + +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) +{ + preempt_disable(); + pagefault_disable(); + return __kmap_local_page_prot(page, prot); +} + +static inline void *kmap_atomic_pfn(unsigned long pfn) +{ + preempt_disable(); + pagefault_disable(); + return __kmap_local_pfn_prot(pfn, kmap_prot); +} + +static inline void __kunmap_atomic(void *addr) +{ + kunmap_local_indexed(addr); +} + +#endif /* CONFIG_KMAP_LOCAL */ + +static inline void *kmap_atomic(struct page *page) +{ + return kmap_atomic_prot(page, kmap_prot); +} /* declarations for linux/mm/highmem.c */ unsigned int nr_free_highpages(void); @@ -137,25 +180,35 @@ static inline void *kmap_atomic(struct page *page) pagefault_disable(); return page_address(page); } -#define kmap_atomic_prot(page, prot) kmap_atomic(page) -static inline void kunmap_atomic_high(void *addr) +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) +{ + return kmap_atomic(page); +} + +static inline void *kmap_atomic_pfn(unsigned long pfn) +{ + return kmap_atomic(pfn_to_page(pfn)); +} + +static inline void __kunmap_atomic(void *addr) { /* - * Nothing to do in the CONFIG_HIGHMEM=n case as kunmap_atomic() - * handles re-enabling faults + preemption + * Mostly nothing to do in the CONFIG_HIGHMEM=n case as kunmap_atomic() + * handles re-enabling faults and preemption */ + #ifdef ARCH_HAS_FLUSH_ON_KUNMAP + kunmap_flush_on_unmap(addr); + #endif } -#define kmap_atomic_pfn(pfn) kmap_atomic(pfn_to_page(pfn)) -#define kmap_atomic_to_page(ptr) virt_to_page(ptr) - #define kmap_flush_unused() do {} while(0) #define kmap_atomic_flush_unused() do {} while (0) #endif #endif /* CONFIG_HIGHMEM */ +#if !defined(CONFIG_KMAP_LOCAL) #if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) DECLARE_PER_CPU(int, __kmap_atomic_idx); @@ -186,22 +239,21 @@ static inline void kmap_atomic_idx_pop(void) __this_cpu_dec(__kmap_atomic_idx); #endif } - +#endif #endif /* * Prevent people trying to call kunmap_atomic() as if it were kunmap() * kunmap_atomic() should get the return value of kmap_atomic, not the page. */ -#define kunmap_atomic(addr) \ -do { \ - BUILD_BUG_ON(__same_type((addr), struct page *)); \ - kunmap_atomic_high(addr); \ - pagefault_enable(); \ - preempt_enable(); \ +#define kunmap_atomic(__addr) \ +do { \ + BUILD_BUG_ON(__same_type((__addr), struct page *)); \ + __kunmap_atomic(__addr); \ + pagefault_enable(); \ + preempt_enable(); \ } while (0) - /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ #ifndef clear_user_highpage static inline void clear_user_highpage(struct page *page, unsigned long vaddr) diff --git a/mm/Kconfig b/mm/Kconfig index 67d2b863141c..9d6d85927e65 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -623,3 +623,6 @@ config VM_MAX_READAHEAD This sets the VM_MAX_READAHEAD value to allow the readahead window to grow to a maximum size of configured. This will benefit sequential read throughput and thus early boot performance. + +config KMAP_LOCAL + bool diff --git a/mm/highmem.c b/mm/highmem.c index b32b70cdaed6..817a62b2cccf 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -30,9 +30,11 @@ #include +#ifndef CONFIG_KMAP_LOCAL #if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) DEFINE_PER_CPU(int, __kmap_atomic_idx); #endif +#endif /* * Virtual_count is not a pure "count". @@ -307,8 +309,146 @@ void kunmap_high(struct page *page) if (need_wakeup) wake_up(&pkmap_map_wait); } - EXPORT_SYMBOL(kunmap_high); +#endif /* CONFIG_HIGHMEM */ + +#ifdef CONFIG_KMAP_LOCAL + +#include + +static DEFINE_PER_CPU(int, __kmap_local_idx); + +static inline int kmap_local_idx_push(void) +{ + int idx = __this_cpu_inc_return(__kmap_local_idx) - 1; + + WARN_ON_ONCE(in_irq() && !irqs_disabled()); + BUG_ON(idx >= KM_MAX_IDX); + return idx; +} + +static inline int kmap_local_idx(void) +{ + return __this_cpu_read(__kmap_local_idx) - 1; +} + +static inline void kmap_local_idx_pop(void) +{ + int idx = __this_cpu_dec_return(__kmap_local_idx); + + BUG_ON(idx < 0); +} + +#ifndef arch_kmap_local_post_map +# define arch_kmap_local_post_map(vaddr, pteval) do { } while (0) +#endif +#ifndef arch_kmap_local_pre_unmap +# define arch_kmap_local_pre_unmap(vaddr) do { } while (0) +#endif + +#ifndef arch_kmap_local_post_unmap +# define arch_kmap_local_post_unmap(vaddr) do { } while (0) +#endif + +#ifndef arch_kmap_local_map_idx +#define arch_kmap_local_map_idx(idx, pfn) kmap_local_calc_idx(idx) +#endif + +#ifndef arch_kmap_local_unmap_idx +#define arch_kmap_local_unmap_idx(idx, vaddr) kmap_local_calc_idx(idx) +#endif + +#ifndef arch_kmap_local_high_get +static inline void *arch_kmap_local_high_get(struct page *page) +{ + return NULL; +} +#endif + +/* Unmap a local mapping which was obtained by kmap_high_get() */ +static inline void kmap_high_unmap_local(unsigned long vaddr) +{ +#ifdef ARCH_NEEDS_KMAP_HIGH_GET + if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) + kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)])); +#endif +} + +static inline int kmap_local_calc_idx(int idx) +{ + return idx + KM_MAX_IDX * smp_processor_id(); +} + +static pte_t *__kmap_pte; + +static pte_t *kmap_get_pte(void) +{ + if (!__kmap_pte) + __kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN)); + return __kmap_pte; +} + +void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot) +{ + pte_t pteval, *kmap_pte = kmap_get_pte(); + unsigned long vaddr; + int idx; + + preempt_disable(); + idx = arch_kmap_local_map_idx(kmap_local_idx_push(), pfn); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + BUG_ON(!pte_none(*(kmap_pte - idx))); + pteval = pfn_pte(pfn, prot); + set_pte_at(&init_mm, vaddr, kmap_pte - idx, pteval); + arch_kmap_local_post_map(vaddr, pteval); + preempt_enable(); + + return (void *)vaddr; +} +EXPORT_SYMBOL_GPL(__kmap_local_pfn_prot); + +void *__kmap_local_page_prot(struct page *page, pgprot_t prot) +{ + void *kmap; + + if (!PageHighMem(page)) + return page_address(page); + + /* Try kmap_high_get() if architecture has it enabled */ + kmap = arch_kmap_local_high_get(page); + if (kmap) + return kmap; + + return __kmap_local_pfn_prot(page_to_pfn(page), prot); +} +EXPORT_SYMBOL(__kmap_local_page_prot); + +void kunmap_local_indexed(void *vaddr) +{ + unsigned long addr = (unsigned long) vaddr & PAGE_MASK; + pte_t *kmap_pte = kmap_get_pte(); + int idx; + + if (addr < __fix_to_virt(FIX_KMAP_END) || + addr > __fix_to_virt(FIX_KMAP_BEGIN)) { + WARN_ON_ONCE(addr < PAGE_OFFSET); + + /* Handle mappings which were obtained by kmap_high_get() */ + kmap_high_unmap_local(addr); + return; + } + + preempt_disable(); + idx = arch_kmap_local_unmap_idx(kmap_local_idx(), addr); + WARN_ON_ONCE(addr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); + + arch_kmap_local_pre_unmap(addr); + pte_clear(&init_mm, addr, kmap_pte - idx); + arch_kmap_local_post_unmap(addr); + kmap_local_idx_pop(); + preempt_enable(); +} +EXPORT_SYMBOL(kunmap_local_indexed); #endif #if defined(HASHED_PAGE_VIRTUAL) -- GitLab From 8f4092722a39de1eb82acd760cb6de584b007482 Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Fri, 20 Nov 2020 15:37:43 -0800 Subject: [PATCH 514/528] UPSTREAM: binder: add flag to clear buffer on txn complete Add a per-transaction flag to indicate that the buffer must be cleared when the transaction is complete to prevent copies of sensitive data from being preserved in memory. Signed-off-by: Todd Kjos Link: https://lore.kernel.org/r/20201120233743.3617529-1-tkjos@google.com Cc: stable Signed-off-by: Greg Kroah-Hartman Bug: 171501513 Change-Id: Ic9338c85cbe3b11ab6f2bda55dce9964bb48447a (cherry picked from commit 0f966cba95c78029f491b433ea95ff38f414a761) Signed-off-by: Todd Kjos (cherry picked from commit 92b2ec21896a13b5aca1425dca1bd9a1df705cd0) --- drivers/android/binder.c | 1 + drivers/android/binder_alloc.c | 48 +++++++++++++++++++++++++++++ drivers/android/binder_alloc.h | 4 ++- include/uapi/linux/android/binder.h | 1 + 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 6eafdb6f1a69..1a0e2df604db 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3251,6 +3251,7 @@ static void binder_transaction(struct binder_proc *proc, t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; + t->buffer->clear_on_free = !!(t->flags & TF_CLEAR_BUF); trace_binder_transaction_alloc_buf(t->buffer); off_start = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 92014b8afc4d..a01a7a1014db 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "binder_alloc.h" #include "binder_trace.h" @@ -640,6 +641,8 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, binder_insert_free_buffer(alloc, buffer); } +static void binder_alloc_clear_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer); /** * binder_alloc_free_buf() - free a binder buffer * @alloc: binder_alloc for this proc @@ -650,6 +653,18 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, void binder_alloc_free_buf(struct binder_alloc *alloc, struct binder_buffer *buffer) { + /* + * We could eliminate the call to binder_alloc_clear_buf() + * from binder_alloc_deferred_release() by moving this to + * binder_alloc_free_buf_locked(). However, that could + * increase contention for the alloc mutex if clear_on_free + * is used frequently for large buffers. The mutex is not + * needed for correctness here. + */ + if (buffer->clear_on_free) { + binder_alloc_clear_buf(alloc, buffer); + buffer->clear_on_free = false; + } mutex_lock(&alloc->mutex); binder_free_buf_locked(alloc, buffer); mutex_unlock(&alloc->mutex); @@ -757,6 +772,10 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) /* Transaction should already have been freed */ BUG_ON(buffer->transaction); + if (buffer->clear_on_free) { + binder_alloc_clear_buf(alloc, buffer); + buffer->clear_on_free = false; + } binder_free_buf_locked(alloc, buffer); buffers++; } @@ -877,3 +896,32 @@ void binder_alloc_init(struct binder_alloc *alloc) INIT_LIST_HEAD(&alloc->buffers); } +/** + * binder_alloc_clear_buf() - zero out buffer + * @alloc: binder_alloc for this proc + * @buffer: binder buffer to be cleared + * + * memset the given buffer to 0 + */ +static void binder_alloc_clear_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + size_t bytes = binder_alloc_buffer_size(alloc, buffer); + binder_size_t buffer_offset = 0; + + while (bytes) { + unsigned long size; + struct page *page; + pgoff_t pgoff; + void *kptr; + + page = binder_alloc_get_page(alloc, buffer, + buffer_offset, &pgoff); + size = min_t(size_t, bytes, PAGE_SIZE - pgoff); + kptr = kmap(page) + pgoff; + memset(kptr, 0, size); + kunmap(page); + bytes -= size; + buffer_offset += size; + } +} diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 8f23c184ec72..f30e16abd58c 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -29,6 +29,7 @@ struct binder_transaction; * @entry: entry alloc->buffers * @rb_node: node for allocated_buffers/free_buffers rb trees * @free: %true if buffer is free + * @clear_on_free: %true if buffer must be zeroed after use * @allow_user_free: %true if user is allowed to free buffer * @async_transaction: %true if buffer is in use for an async txn * @debug_id: unique ID for debugging @@ -47,9 +48,10 @@ struct binder_buffer { struct rb_node rb_node; /* free entry by size or allocated entry */ /* by address */ unsigned free:1; + unsigned clear_on_free:1; unsigned allow_user_free:1; unsigned async_transaction:1; - unsigned debug_id:29; + unsigned debug_id:28; struct binder_transaction *transaction; diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 34e767e05153..2f6a91e91199 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -309,6 +309,7 @@ enum transaction_flags { TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */ TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */ TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */ + TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */ }; struct binder_transaction_data { -- GitLab From 5c1325162958bc5cf03a0bde27056836fcfbab47 Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Fri, 8 Feb 2019 10:35:14 -0800 Subject: [PATCH 515/528] binder: create userspace-to-binder-buffer copy function The binder driver uses a vm_area to map the per-process binder buffer space. For 32-bit android devices, this is now taking too much vmalloc space. This patch removes the use of vm_area when copying the transaction data from the sender to the buffer space. Instead of using copy_from_user() for multi-page copies, it now uses binder_alloc_copy_user_to_buffer() which uses kmap() and kunmap() to map each page, and uses copy_from_user() for copying to that page. Signed-off-by: Todd Kjos Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 1a7c3d9bb7a926e88d5f57643e75ad1abfc55013) --- drivers/android/binder.c | 29 +++++++-- drivers/android/binder_alloc.c | 115 ++++++++++++++++++++++++++++++++- drivers/android/binder_alloc.h | 8 +++ 3 files changed, 144 insertions(+), 8 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 1a0e2df604db..7b402d8b37d6 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3257,8 +3257,12 @@ static void binder_transaction(struct binder_proc *proc, ALIGN(tr->data_size, sizeof(void *))); offp = off_start; - if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) - tr->data.ptr.buffer, tr->data_size)) { + if (binder_alloc_copy_user_to_buffer( + &target_proc->alloc, + t->buffer, 0, + (const void __user *) + (uintptr_t)tr->data.ptr.buffer, + tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; @@ -3266,8 +3270,13 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_copy_data_failed; } - if (copy_from_user(offp, (const void __user *)(uintptr_t) - tr->data.ptr.offsets, tr->offsets_size)) { + if (binder_alloc_copy_user_to_buffer( + &target_proc->alloc, + t->buffer, + ALIGN(tr->data_size, sizeof(void *)), + (const void __user *) + (uintptr_t)tr->data.ptr.offsets, + tr->offsets_size)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; @@ -3398,6 +3407,8 @@ static void binder_transaction(struct binder_proc *proc, struct binder_buffer_object *bp = to_binder_buffer_object(hdr); size_t buf_left = sg_buf_end - sg_bufp; + binder_size_t sg_buf_offset = (uintptr_t)sg_bufp - + (uintptr_t)t->buffer->data; if (bp->length > buf_left) { binder_user_error("%d:%d got transaction with too large buffer\n", @@ -3407,9 +3418,13 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_bad_offset; } - if (copy_from_user(sg_bufp, - (const void __user *)(uintptr_t) - bp->buffer, bp->length)) { + if (binder_alloc_copy_user_to_buffer( + &target_proc->alloc, + t->buffer, + sg_buf_offset, + (const void __user *) + (uintptr_t)bp->buffer, + bp->length)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error_param = -EFAULT; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index a01a7a1014db..80b8efa8ab59 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -28,8 +28,9 @@ #include #include #include -#include #include +#include +#include #include "binder_alloc.h" #include "binder_trace.h" @@ -896,6 +897,74 @@ void binder_alloc_init(struct binder_alloc *alloc) INIT_LIST_HEAD(&alloc->buffers); } + +/** + * check_buffer() - verify that buffer/offset is safe to access + * @alloc: binder_alloc for this proc + * @buffer: binder buffer to be accessed + * @offset: offset into @buffer data + * @bytes: bytes to access from offset + * + * Check that the @offset/@bytes are within the size of the given + * @buffer and that the buffer is currently active and not freeable. + * Offsets must also be multiples of sizeof(u32). The kernel is + * allowed to touch the buffer in two cases: + * + * 1) when the buffer is being created: + * (buffer->free == 0 && buffer->allow_user_free == 0) + * 2) when the buffer is being torn down: + * (buffer->free == 0 && buffer->transaction == NULL). + * + * Return: true if the buffer is safe to access + */ +static inline bool check_buffer(struct binder_alloc *alloc, + struct binder_buffer *buffer, + binder_size_t offset, size_t bytes) +{ + size_t buffer_size = binder_alloc_buffer_size(alloc, buffer); + + return buffer_size >= bytes && + offset <= buffer_size - bytes && + IS_ALIGNED(offset, sizeof(u32)) && + !buffer->free && + (!buffer->allow_user_free || !buffer->transaction); +} + +/** + * binder_alloc_get_page() - get kernel pointer for given buffer offset + * @alloc: binder_alloc for this proc + * @buffer: binder buffer to be accessed + * @buffer_offset: offset into @buffer data + * @pgoffp: address to copy final page offset to + * + * Lookup the struct page corresponding to the address + * at @buffer_offset into @buffer->data. If @pgoffp is not + * NULL, the byte-offset into the page is written there. + * + * The caller is responsible to ensure that the offset points + * to a valid address within the @buffer and that @buffer is + * not freeable by the user. Since it can't be freed, we are + * guaranteed that the corresponding elements of @alloc->pages[] + * cannot change. + * + * Return: struct page + */ +static struct page *binder_alloc_get_page(struct binder_alloc *alloc, + struct binder_buffer *buffer, + binder_size_t buffer_offset, + pgoff_t *pgoffp) +{ + binder_size_t buffer_space_offset = buffer_offset + + (buffer->data - alloc->buffer); + pgoff_t pgoff = buffer_space_offset & ~PAGE_MASK; + size_t index = buffer_space_offset >> PAGE_SHIFT; + struct binder_lru_page *lru_page; + + lru_page = &alloc->pages[index]; + *pgoffp = pgoff; + return lru_page->page_ptr; +} + /** * binder_alloc_clear_buf() - zero out buffer * @alloc: binder_alloc for this proc @@ -925,3 +994,47 @@ static void binder_alloc_clear_buf(struct binder_alloc *alloc, buffer_offset += size; } } + +/** + * binder_alloc_copy_user_to_buffer() - copy src user to tgt user + * @alloc: binder_alloc for this proc + * @buffer: binder buffer to be accessed + * @buffer_offset: offset into @buffer data + * @from: userspace pointer to source buffer + * @bytes: bytes to copy + * + * Copy bytes from source userspace to target buffer. + * + * Return: bytes remaining to be copied + */ +unsigned long +binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc, + struct binder_buffer *buffer, + binder_size_t buffer_offset, + const void __user *from, + size_t bytes) +{ + if (!check_buffer(alloc, buffer, buffer_offset, bytes)) + return bytes; + + while (bytes) { + unsigned long size; + unsigned long ret; + struct page *page; + pgoff_t pgoff; + void *kptr; + + page = binder_alloc_get_page(alloc, buffer, + buffer_offset, &pgoff); + size = min_t(size_t, bytes, PAGE_SIZE - pgoff); + kptr = kmap(page) + pgoff; + ret = copy_from_user(kptr, from, size); + kunmap(page); + if (ret) + return bytes - size + ret; + bytes -= size; + from += size; + buffer_offset += size; + } + return 0; +} diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index f30e16abd58c..3f211bc75d2f 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -21,6 +21,7 @@ #include #include #include +#include struct binder_transaction; @@ -168,5 +169,12 @@ binder_alloc_get_user_buffer_offset(struct binder_alloc *alloc) return alloc->user_buffer_offset; } +unsigned long +binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc, + struct binder_buffer *buffer, + binder_size_t buffer_offset, + const void __user *from, + size_t bytes); + #endif /* _LINUX_BINDER_ALLOC_H */ -- GitLab From cfc0e18d9a58212d94a5373ef486fffc47b04d20 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 28 Aug 2013 10:17:58 +1000 Subject: [PATCH 516/528] list: add a new LRU list type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several subsystems use the same construct for LRU lists - a list head, a spin lock and and item count. They also use exactly the same code for adding and removing items from the LRU. Create a generic type for these LRU lists. This is the beginning of generic, node aware LRUs for shrinkers to work with. [glommer@openvz.org: enum defined constants for lru. Suggested by gthelen, don't relock over retry] Signed-off-by: Dave Chinner Signed-off-by: Glauber Costa Reviewed-by: Greg Thelen Acked-by: Mel Gorman Cc: "Theodore Ts'o" Cc: Adrian Hunter Cc: Al Viro Cc: Artem Bityutskiy Cc: Arve Hjønnevåg Cc: Carlos Maiolino Cc: Christoph Hellwig Cc: Chuck Lever Cc: Daniel Vetter Cc: David Rientjes Cc: Gleb Natapov Cc: Greg Thelen Cc: J. Bruce Fields Cc: Jan Kara Cc: Jerome Glisse Cc: John Stultz Cc: KAMEZAWA Hiroyuki Cc: Kent Overstreet Cc: Kirill A. Shutemov Cc: Marcelo Tosatti Cc: Mel Gorman Cc: Steven Whitehouse Cc: Thomas Hellstrom Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Al Viro (cherry picked from commit a38e40824844a5ec85f3ea95632be953477d2afa) --- include/linux/list_lru.h | 115 ++++++++++++++++++++++++++++++++++++++ mm/Makefile | 2 +- mm/list_lru.c | 117 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 include/linux/list_lru.h create mode 100644 mm/list_lru.c diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h new file mode 100644 index 000000000000..1a548b0b7578 --- /dev/null +++ b/include/linux/list_lru.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2013 Red Hat, Inc. and Parallels Inc. All rights reserved. + * Authors: David Chinner and Glauber Costa + * + * Generic LRU infrastructure + */ +#ifndef _LRU_LIST_H +#define _LRU_LIST_H + +#include + +/* list_lru_walk_cb has to always return one of those */ +enum lru_status { + LRU_REMOVED, /* item removed from list */ + LRU_ROTATE, /* item referenced, give another pass */ + LRU_SKIP, /* item cannot be locked, skip */ + LRU_RETRY, /* item not freeable. May drop the lock + internally, but has to return locked. */ +}; + +struct list_lru { + spinlock_t lock; + struct list_head list; + /* kept as signed so we can catch imbalance bugs */ + long nr_items; +}; + +int list_lru_init(struct list_lru *lru); + +/** + * list_lru_add: add an element to the lru list's tail + * @list_lru: the lru pointer + * @item: the item to be added. + * + * If the element is already part of a list, this function returns doing + * nothing. Therefore the caller does not need to keep state about whether or + * not the element already belongs in the list and is allowed to lazy update + * it. Note however that this is valid for *a* list, not *this* list. If + * the caller organize itself in a way that elements can be in more than + * one type of list, it is up to the caller to fully remove the item from + * the previous list (with list_lru_del() for instance) before moving it + * to @list_lru + * + * Return value: true if the list was updated, false otherwise + */ +bool list_lru_add(struct list_lru *lru, struct list_head *item); + +/** + * list_lru_del: delete an element to the lru list + * @list_lru: the lru pointer + * @item: the item to be deleted. + * + * This function works analogously as list_lru_add in terms of list + * manipulation. The comments about an element already pertaining to + * a list are also valid for list_lru_del. + * + * Return value: true if the list was updated, false otherwise + */ +bool list_lru_del(struct list_lru *lru, struct list_head *item); + +/** + * list_lru_count: return the number of objects currently held by @lru + * @lru: the lru pointer. + * + * Always return a non-negative number, 0 for empty lists. There is no + * guarantee that the list is not updated while the count is being computed. + * Callers that want such a guarantee need to provide an outer lock. + */ +static inline unsigned long list_lru_count(struct list_lru *lru) +{ + return lru->nr_items; +} + +typedef enum lru_status +(*list_lru_walk_cb)(struct list_head *item, spinlock_t *lock, void *cb_arg); +/** + * list_lru_walk: walk a list_lru, isolating and disposing freeable items. + * @lru: the lru pointer. + * @isolate: callback function that is resposible for deciding what to do with + * the item currently being scanned + * @cb_arg: opaque type that will be passed to @isolate + * @nr_to_walk: how many items to scan. + * + * This function will scan all elements in a particular list_lru, calling the + * @isolate callback for each of those items, along with the current list + * spinlock and a caller-provided opaque. The @isolate callback can choose to + * drop the lock internally, but *must* return with the lock held. The callback + * will return an enum lru_status telling the list_lru infrastructure what to + * do with the object being scanned. + * + * Please note that nr_to_walk does not mean how many objects will be freed, + * just how many objects will be scanned. + * + * Return value: the number of objects effectively removed from the LRU. + */ +unsigned long list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, + void *cb_arg, unsigned long nr_to_walk); + +typedef void (*list_lru_dispose_cb)(struct list_head *dispose_list); +/** + * list_lru_dispose_all: forceably flush all elements in an @lru + * @lru: the lru pointer + * @dispose: callback function to be called for each lru list. + * + * This function will forceably isolate all elements into the dispose list, and + * call the @dispose callback to flush the list. Please note that the callback + * should expect items in any state, clean or dirty, and be able to flush all of + * them. + * + * Return value: how many objects were freed. It should be equal to all objects + * in the list_lru. + */ +unsigned long +list_lru_dispose_all(struct list_lru *lru, list_lru_dispose_cb dispose); +#endif /* _LRU_LIST_H */ diff --git a/mm/Makefile b/mm/Makefile index 76d6cceb18d0..2c8ded8c8bfa 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -17,7 +17,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \ util.o mmzone.o vmstat.o backing-dev.o \ mm_init.o mmu_context.o percpu.o slab_common.o \ compaction.o balloon_compaction.o \ - interval_tree.o $(mmu-y) \ + interval_tree.o list_lru.o $(mmu-y) showmem.o vmpressure.o obj-y += init-mm.o diff --git a/mm/list_lru.c b/mm/list_lru.c new file mode 100644 index 000000000000..dd74c5434cd8 --- /dev/null +++ b/mm/list_lru.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2013 Red Hat, Inc. and Parallels Inc. All rights reserved. + * Authors: David Chinner and Glauber Costa + * + * Generic LRU infrastructure + */ +#include +#include +#include + +bool list_lru_add(struct list_lru *lru, struct list_head *item) +{ + spin_lock(&lru->lock); + if (list_empty(item)) { + list_add_tail(item, &lru->list); + lru->nr_items++; + spin_unlock(&lru->lock); + return true; + } + spin_unlock(&lru->lock); + return false; +} +EXPORT_SYMBOL_GPL(list_lru_add); + +bool list_lru_del(struct list_lru *lru, struct list_head *item) +{ + spin_lock(&lru->lock); + if (!list_empty(item)) { + list_del_init(item); + lru->nr_items--; + spin_unlock(&lru->lock); + return true; + } + spin_unlock(&lru->lock); + return false; +} +EXPORT_SYMBOL_GPL(list_lru_del); + +unsigned long list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, + void *cb_arg, unsigned long nr_to_walk) +{ + struct list_head *item, *n; + unsigned long removed = 0; + /* + * If we don't keep state of at which pass we are, we can loop at + * LRU_RETRY, since we have no guarantees that the caller will be able + * to do something other than retry on the next pass. We handle this by + * allowing at most one retry per object. This should not be altered + * by any condition other than LRU_RETRY. + */ + bool first_pass = true; + + spin_lock(&lru->lock); +restart: + list_for_each_safe(item, n, &lru->list) { + enum lru_status ret; + ret = isolate(item, &lru->lock, cb_arg); + switch (ret) { + case LRU_REMOVED: + lru->nr_items--; + removed++; + break; + case LRU_ROTATE: + list_move_tail(item, &lru->list); + break; + case LRU_SKIP: + break; + case LRU_RETRY: + if (!first_pass) { + first_pass = true; + break; + } + first_pass = false; + goto restart; + default: + BUG(); + } + + if (nr_to_walk-- == 0) + break; + + } + spin_unlock(&lru->lock); + return removed; +} +EXPORT_SYMBOL_GPL(list_lru_walk); + +unsigned long list_lru_dispose_all(struct list_lru *lru, + list_lru_dispose_cb dispose) +{ + unsigned long disposed = 0; + LIST_HEAD(dispose_list); + + spin_lock(&lru->lock); + while (!list_empty(&lru->list)) { + list_splice_init(&lru->list, &dispose_list); + disposed += lru->nr_items; + lru->nr_items = 0; + spin_unlock(&lru->lock); + + dispose(&dispose_list); + + spin_lock(&lru->lock); + } + spin_unlock(&lru->lock); + return disposed; +} + +int list_lru_init(struct list_lru *lru) +{ + spin_lock_init(&lru->lock); + INIT_LIST_HEAD(&lru->list); + lru->nr_items = 0; + + return 0; +} +EXPORT_SYMBOL_GPL(list_lru_init); -- GitLab From d65a68a0728d851164fc1a52932659563ed0580b Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 28 Aug 2013 10:18:00 +1000 Subject: [PATCH 517/528] list_lru: per-node list infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have an LRU list API, we can start to enhance the implementation. This splits the single LRU list into per-node lists and locks to enhance scalability. Items are placed on lists according to the node the memory belongs to. To make scanning the lists efficient, also track whether the per-node lists have entries in them in a active nodemask. Note: We use a fixed-size array for the node LRU, this struct can be very big if MAX_NUMNODES is big. If this becomes a problem this is fixable by turning this into a pointer and dynamically allocating this to nr_node_ids. This quantity is firwmare-provided, and still would provide room for all nodes at the cost of a pointer lookup and an extra allocation. Because that allocation will most likely come from a may very well fail. [glommer@openvz.org: fix warnings, added note about node lru] Signed-off-by: Dave Chinner Signed-off-by: Glauber Costa Reviewed-by: Greg Thelen Acked-by: Mel Gorman Cc: "Theodore Ts'o" Cc: Adrian Hunter Cc: Al Viro Cc: Artem Bityutskiy Cc: Arve Hjønnevåg Cc: Carlos Maiolino Cc: Christoph Hellwig Cc: Chuck Lever Cc: Daniel Vetter Cc: David Rientjes Cc: Gleb Natapov Cc: Greg Thelen Cc: J. Bruce Fields Cc: Jan Kara Cc: Jerome Glisse Cc: John Stultz Cc: KAMEZAWA Hiroyuki Cc: Kent Overstreet Cc: Kirill A. Shutemov Cc: Marcelo Tosatti Cc: Mel Gorman Cc: Steven Whitehouse Cc: Thomas Hellstrom Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Al Viro (cherry picked from commit 3b1d58a4c96799eb4c92039e1b851b86f853548a) --- include/linux/list_lru.h | 23 ++++-- mm/list_lru.c | 146 +++++++++++++++++++++++++++++---------- 2 files changed, 129 insertions(+), 40 deletions(-) diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h index 1a548b0b7578..f4d4cb608c02 100644 --- a/include/linux/list_lru.h +++ b/include/linux/list_lru.h @@ -8,6 +8,7 @@ #define _LRU_LIST_H #include +#include /* list_lru_walk_cb has to always return one of those */ enum lru_status { @@ -18,11 +19,26 @@ enum lru_status { internally, but has to return locked. */ }; -struct list_lru { +struct list_lru_node { spinlock_t lock; struct list_head list; /* kept as signed so we can catch imbalance bugs */ long nr_items; +} ____cacheline_aligned_in_smp; + +struct list_lru { + /* + * Because we use a fixed-size array, this struct can be very big if + * MAX_NUMNODES is big. If this becomes a problem this is fixable by + * turning this into a pointer and dynamically allocating this to + * nr_node_ids. This quantity is firwmare-provided, and still would + * provide room for all nodes at the cost of a pointer lookup and an + * extra allocation. Because that allocation will most likely come from + * a different slab cache than the main structure holding this + * structure, we may very well fail. + */ + struct list_lru_node node[MAX_NUMNODES]; + nodemask_t active_nodes; }; int list_lru_init(struct list_lru *lru); @@ -66,10 +82,7 @@ bool list_lru_del(struct list_lru *lru, struct list_head *item); * guarantee that the list is not updated while the count is being computed. * Callers that want such a guarantee need to provide an outer lock. */ -static inline unsigned long list_lru_count(struct list_lru *lru) -{ - return lru->nr_items; -} +unsigned long list_lru_count(struct list_lru *lru); typedef enum lru_status (*list_lru_walk_cb)(struct list_head *item, spinlock_t *lock, void *cb_arg); diff --git a/mm/list_lru.c b/mm/list_lru.c index dd74c5434cd8..1efe4ecc02b1 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -6,41 +6,73 @@ */ #include #include +#include #include bool list_lru_add(struct list_lru *lru, struct list_head *item) { - spin_lock(&lru->lock); + int nid = page_to_nid(virt_to_page(item)); + struct list_lru_node *nlru = &lru->node[nid]; + + spin_lock(&nlru->lock); + WARN_ON_ONCE(nlru->nr_items < 0); if (list_empty(item)) { - list_add_tail(item, &lru->list); - lru->nr_items++; - spin_unlock(&lru->lock); + list_add_tail(item, &nlru->list); + if (nlru->nr_items++ == 0) + node_set(nid, lru->active_nodes); + spin_unlock(&nlru->lock); return true; } - spin_unlock(&lru->lock); + spin_unlock(&nlru->lock); return false; } EXPORT_SYMBOL_GPL(list_lru_add); bool list_lru_del(struct list_lru *lru, struct list_head *item) { - spin_lock(&lru->lock); + int nid = page_to_nid(virt_to_page(item)); + struct list_lru_node *nlru = &lru->node[nid]; + + spin_lock(&nlru->lock); if (!list_empty(item)) { list_del_init(item); - lru->nr_items--; - spin_unlock(&lru->lock); + if (--nlru->nr_items == 0) + node_clear(nid, lru->active_nodes); + WARN_ON_ONCE(nlru->nr_items < 0); + spin_unlock(&nlru->lock); return true; } - spin_unlock(&lru->lock); + spin_unlock(&nlru->lock); return false; } EXPORT_SYMBOL_GPL(list_lru_del); -unsigned long list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, - void *cb_arg, unsigned long nr_to_walk) +unsigned long list_lru_count(struct list_lru *lru) { + unsigned long count = 0; + int nid; + + for_each_node_mask(nid, lru->active_nodes) { + struct list_lru_node *nlru = &lru->node[nid]; + + spin_lock(&nlru->lock); + WARN_ON_ONCE(nlru->nr_items < 0); + count += nlru->nr_items; + spin_unlock(&nlru->lock); + } + + return count; +} +EXPORT_SYMBOL_GPL(list_lru_count); + +static unsigned long +list_lru_walk_node(struct list_lru *lru, int nid, list_lru_walk_cb isolate, + void *cb_arg, unsigned long *nr_to_walk) +{ + + struct list_lru_node *nlru = &lru->node[nid]; struct list_head *item, *n; - unsigned long removed = 0; + unsigned long isolated = 0; /* * If we don't keep state of at which pass we are, we can loop at * LRU_RETRY, since we have no guarantees that the caller will be able @@ -50,18 +82,20 @@ unsigned long list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, */ bool first_pass = true; - spin_lock(&lru->lock); + spin_lock(&nlru->lock); restart: - list_for_each_safe(item, n, &lru->list) { + list_for_each_safe(item, n, &nlru->list) { enum lru_status ret; - ret = isolate(item, &lru->lock, cb_arg); + ret = isolate(item, &nlru->lock, cb_arg); switch (ret) { case LRU_REMOVED: - lru->nr_items--; - removed++; + if (--nlru->nr_items == 0) + node_clear(nid, lru->active_nodes); + WARN_ON_ONCE(nlru->nr_items < 0); + isolated++; break; case LRU_ROTATE: - list_move_tail(item, &lru->list); + list_move_tail(item, &nlru->list); break; case LRU_SKIP: break; @@ -76,42 +110,84 @@ restart: BUG(); } - if (nr_to_walk-- == 0) + if ((*nr_to_walk)-- == 0) break; } - spin_unlock(&lru->lock); - return removed; + + spin_unlock(&nlru->lock); + return isolated; +} +EXPORT_SYMBOL_GPL(list_lru_walk_node); + +unsigned long list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, + void *cb_arg, unsigned long nr_to_walk) +{ + unsigned long isolated = 0; + int nid; + + for_each_node_mask(nid, lru->active_nodes) { + isolated += list_lru_walk_node(lru, nid, isolate, + cb_arg, &nr_to_walk); + if (nr_to_walk <= 0) + break; + } + return isolated; } EXPORT_SYMBOL_GPL(list_lru_walk); -unsigned long list_lru_dispose_all(struct list_lru *lru, - list_lru_dispose_cb dispose) +static unsigned long list_lru_dispose_all_node(struct list_lru *lru, int nid, + list_lru_dispose_cb dispose) { - unsigned long disposed = 0; + struct list_lru_node *nlru = &lru->node[nid]; LIST_HEAD(dispose_list); + unsigned long disposed = 0; - spin_lock(&lru->lock); - while (!list_empty(&lru->list)) { - list_splice_init(&lru->list, &dispose_list); - disposed += lru->nr_items; - lru->nr_items = 0; - spin_unlock(&lru->lock); + spin_lock(&nlru->lock); + while (!list_empty(&nlru->list)) { + list_splice_init(&nlru->list, &dispose_list); + disposed += nlru->nr_items; + nlru->nr_items = 0; + node_clear(nid, lru->active_nodes); + spin_unlock(&nlru->lock); dispose(&dispose_list); - spin_lock(&lru->lock); + spin_lock(&nlru->lock); } - spin_unlock(&lru->lock); + spin_unlock(&nlru->lock); return disposed; } +unsigned long list_lru_dispose_all(struct list_lru *lru, + list_lru_dispose_cb dispose) +{ + unsigned long disposed; + unsigned long total = 0; + int nid; + + do { + disposed = 0; + for_each_node_mask(nid, lru->active_nodes) { + disposed += list_lru_dispose_all_node(lru, nid, + dispose); + } + total += disposed; + } while (disposed != 0); + + return total; +} + int list_lru_init(struct list_lru *lru) { - spin_lock_init(&lru->lock); - INIT_LIST_HEAD(&lru->list); - lru->nr_items = 0; + int i; + nodes_clear(lru->active_nodes); + for (i = 0; i < MAX_NUMNODES; i++) { + spin_lock_init(&lru->node[i].lock); + INIT_LIST_HEAD(&lru->node[i].list); + lru->node[i].nr_items = 0; + } return 0; } EXPORT_SYMBOL_GPL(list_lru_init); -- GitLab From e8734293aeade4ca93ecfe476a258e2a9c592843 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 28 Aug 2013 10:18:01 +1000 Subject: [PATCH 518/528] list_lru: fix broken LRU_RETRY behaviour The LRU_RETRY code assumes that the list traversal status after we have dropped and regained the list lock. Unfortunately, this is not a valid assumption, and that can lead to racing traversals isolating objects that the other traversal expects to be the next item on the list. This is causing problems with the inode cache shrinker isolation, with races resulting in an inode on a dispose list being "isolated" because a racing traversal still thinks it is on the LRU. The inode is then never reclaimed and that causes hangs if a subsequent lookup on that inode occurs. Fix it by always restarting the list walk on a LRU_RETRY return from the isolate callback. Avoid the possibility of livelocks the current code was trying to avoid by always decrementing the nr_to_walk counter on retries so that even if we keep hitting the same item on the list we'll eventually stop trying to walk and exit out of the situation causing the problem. Reported-by: Michal Hocko Signed-off-by: Dave Chinner Cc: Glauber Costa Signed-off-by: Andrew Morton Signed-off-by: Al Viro (cherry picked from commit 5cedf721a7cdb54e9222133516c916210d836470) --- mm/list_lru.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/mm/list_lru.c b/mm/list_lru.c index 1efe4ecc02b1..e77c29f4c243 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -73,19 +73,19 @@ list_lru_walk_node(struct list_lru *lru, int nid, list_lru_walk_cb isolate, struct list_lru_node *nlru = &lru->node[nid]; struct list_head *item, *n; unsigned long isolated = 0; - /* - * If we don't keep state of at which pass we are, we can loop at - * LRU_RETRY, since we have no guarantees that the caller will be able - * to do something other than retry on the next pass. We handle this by - * allowing at most one retry per object. This should not be altered - * by any condition other than LRU_RETRY. - */ - bool first_pass = true; spin_lock(&nlru->lock); restart: list_for_each_safe(item, n, &nlru->list) { enum lru_status ret; + + /* + * decrement nr_to_walk first so that we don't livelock if we + * get stuck on large numbesr of LRU_RETRY items + */ + if (--(*nr_to_walk) == 0) + break; + ret = isolate(item, &nlru->lock, cb_arg); switch (ret) { case LRU_REMOVED: @@ -100,19 +100,14 @@ restart: case LRU_SKIP: break; case LRU_RETRY: - if (!first_pass) { - first_pass = true; - break; - } - first_pass = false; + /* + * The lru lock has been dropped, our list traversal is + * now invalid and so we have to restart from scratch. + */ goto restart; default: BUG(); } - - if ((*nr_to_walk)-- == 0) - break; - } spin_unlock(&nlru->lock); -- GitLab From 89fcb02de53c1a75818a056d314ce3951d65a4eb Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 28 Aug 2013 10:18:02 +1000 Subject: [PATCH 519/528] list_lru: per-node API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adapts the list_lru API to accept an optional node argument, to be used by NUMA aware shrinking functions. Code that does not care about the NUMA placement of objects can still call into the very same functions as before. They will simply iterate over all nodes. Signed-off-by: Glauber Costa Cc: Dave Chinner Cc: Mel Gorman Cc: "Theodore Ts'o" Cc: Adrian Hunter Cc: Al Viro Cc: Artem Bityutskiy Cc: Arve Hjønnevåg Cc: Carlos Maiolino Cc: Christoph Hellwig Cc: Chuck Lever Cc: Daniel Vetter Cc: David Rientjes Cc: Gleb Natapov Cc: Greg Thelen Cc: J. Bruce Fields Cc: Jan Kara Cc: Jerome Glisse Cc: John Stultz Cc: KAMEZAWA Hiroyuki Cc: Kent Overstreet Cc: Kirill A. Shutemov Cc: Marcelo Tosatti Cc: Mel Gorman Cc: Steven Whitehouse Cc: Thomas Hellstrom Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Al Viro (cherry picked from commit 6a4f496fd2fc74fa036732ae52c184952d6e3e37) --- include/linux/list_lru.h | 39 ++++++++++++++++++++++++++++++++++----- mm/list_lru.c | 37 +++++++++---------------------------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h index f4d4cb608c02..2fe13e1a809a 100644 --- a/include/linux/list_lru.h +++ b/include/linux/list_lru.h @@ -75,20 +75,32 @@ bool list_lru_add(struct list_lru *lru, struct list_head *item); bool list_lru_del(struct list_lru *lru, struct list_head *item); /** - * list_lru_count: return the number of objects currently held by @lru + * list_lru_count_node: return the number of objects currently held by @lru * @lru: the lru pointer. + * @nid: the node id to count from. * * Always return a non-negative number, 0 for empty lists. There is no * guarantee that the list is not updated while the count is being computed. * Callers that want such a guarantee need to provide an outer lock. */ -unsigned long list_lru_count(struct list_lru *lru); +unsigned long list_lru_count_node(struct list_lru *lru, int nid); +static inline unsigned long list_lru_count(struct list_lru *lru) +{ + long count = 0; + int nid; + + for_each_node_mask(nid, lru->active_nodes) + count += list_lru_count_node(lru, nid); + + return count; +} typedef enum lru_status (*list_lru_walk_cb)(struct list_head *item, spinlock_t *lock, void *cb_arg); /** - * list_lru_walk: walk a list_lru, isolating and disposing freeable items. + * list_lru_walk_node: walk a list_lru, isolating and disposing freeable items. * @lru: the lru pointer. + * @nid: the node id to scan from. * @isolate: callback function that is resposible for deciding what to do with * the item currently being scanned * @cb_arg: opaque type that will be passed to @isolate @@ -106,8 +118,25 @@ typedef enum lru_status * * Return value: the number of objects effectively removed from the LRU. */ -unsigned long list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, - void *cb_arg, unsigned long nr_to_walk); +unsigned long list_lru_walk_node(struct list_lru *lru, int nid, + list_lru_walk_cb isolate, void *cb_arg, + unsigned long *nr_to_walk); + +static inline unsigned long +list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, + void *cb_arg, unsigned long nr_to_walk) +{ + long isolated = 0; + int nid; + + for_each_node_mask(nid, lru->active_nodes) { + isolated += list_lru_walk_node(lru, nid, isolate, + cb_arg, &nr_to_walk); + if (nr_to_walk <= 0) + break; + } + return isolated; +} typedef void (*list_lru_dispose_cb)(struct list_head *dispose_list); /** diff --git a/mm/list_lru.c b/mm/list_lru.c index e77c29f4c243..86cb55464f71 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -47,25 +47,22 @@ bool list_lru_del(struct list_lru *lru, struct list_head *item) } EXPORT_SYMBOL_GPL(list_lru_del); -unsigned long list_lru_count(struct list_lru *lru) +unsigned long +list_lru_count_node(struct list_lru *lru, int nid) { unsigned long count = 0; - int nid; - - for_each_node_mask(nid, lru->active_nodes) { - struct list_lru_node *nlru = &lru->node[nid]; + struct list_lru_node *nlru = &lru->node[nid]; - spin_lock(&nlru->lock); - WARN_ON_ONCE(nlru->nr_items < 0); - count += nlru->nr_items; - spin_unlock(&nlru->lock); - } + spin_lock(&nlru->lock); + WARN_ON_ONCE(nlru->nr_items < 0); + count += nlru->nr_items; + spin_unlock(&nlru->lock); return count; } -EXPORT_SYMBOL_GPL(list_lru_count); +EXPORT_SYMBOL_GPL(list_lru_count_node); -static unsigned long +unsigned long list_lru_walk_node(struct list_lru *lru, int nid, list_lru_walk_cb isolate, void *cb_arg, unsigned long *nr_to_walk) { @@ -115,22 +112,6 @@ restart: } EXPORT_SYMBOL_GPL(list_lru_walk_node); -unsigned long list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, - void *cb_arg, unsigned long nr_to_walk) -{ - unsigned long isolated = 0; - int nid; - - for_each_node_mask(nid, lru->active_nodes) { - isolated += list_lru_walk_node(lru, nid, isolate, - cb_arg, &nr_to_walk); - if (nr_to_walk <= 0) - break; - } - return isolated; -} -EXPORT_SYMBOL_GPL(list_lru_walk); - static unsigned long list_lru_dispose_all_node(struct list_lru *lru, int nid, list_lru_dispose_cb dispose) { -- GitLab From 7d970b631ee8d1f72e6d7b2ae0c16796f2acbe30 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 28 Aug 2013 10:18:18 +1000 Subject: [PATCH 520/528] list_lru: dynamically adjust node arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently use a compile-time constant to size the node array for the list_lru structure. Due to this, we don't need to allocate any memory at initialization time. But as a consequence, the structures that contain embedded list_lru lists can become way too big (the superblock for instance contains two of them). This patch aims at ameliorating this situation by dynamically allocating the node arrays with the firmware provided nr_node_ids. Signed-off-by: Glauber Costa Cc: Dave Chinner Cc: Mel Gorman Cc: "Theodore Ts'o" Cc: Adrian Hunter Cc: Al Viro Cc: Artem Bityutskiy Cc: Arve Hjønnevåg Cc: Carlos Maiolino Cc: Christoph Hellwig Cc: Chuck Lever Cc: Daniel Vetter Cc: David Rientjes Cc: Gleb Natapov Cc: Greg Thelen Cc: J. Bruce Fields Cc: Jan Kara Cc: Jerome Glisse Cc: John Stultz Cc: KAMEZAWA Hiroyuki Cc: Kent Overstreet Cc: Kirill A. Shutemov Cc: Marcelo Tosatti Cc: Mel Gorman Cc: Steven Whitehouse Cc: Thomas Hellstrom Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Al Viro (cherry picked from commit 5ca302c8e502ca53b7d75f12127ec0289904003a) --- fs/super.c | 12 ++++++++++-- fs/xfs/xfs_buf.c | 7 +++++++ fs/xfs/xfs_qm.c | 11 +++++++++++ include/linux/list_lru.h | 13 ++----------- mm/list_lru.c | 14 +++++++++++++- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/fs/super.c b/fs/super.c index 55a171fe9d7f..c1f79fbc9f02 100644 --- a/fs/super.c +++ b/fs/super.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "internal.h" @@ -170,8 +171,12 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) INIT_HLIST_NODE(&s->s_instances); INIT_HLIST_BL_HEAD(&s->s_anon); INIT_LIST_HEAD(&s->s_inodes); - INIT_LIST_HEAD(&s->s_dentry_lru); - INIT_LIST_HEAD(&s->s_inode_lru); + + if (list_lru_init(&s->s_dentry_lru)) + goto err_out; + if (list_lru_init(&s->s_inode_lru)) + goto err_out_dentry_lru; + spin_lock_init(&s->s_inode_lru_lock); INIT_LIST_HEAD(&s->s_mounts); init_rwsem(&s->s_umount); @@ -210,6 +215,9 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) } out: return s; + +err_out_dentry_lru: + list_lru_destroy(&s->s_dentry_lru); err_out: security_sb_free(s); destroy_sb_writers(s); diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 8ff89db9e663..fc8b461cadc1 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1586,6 +1586,7 @@ xfs_free_buftarg( struct xfs_mount *mp, struct xfs_buftarg *btp) { + list_lru_destroy(&btp->bt_lru); unregister_shrinker(&btp->bt_shrinker); if (mp->m_flags & XFS_MOUNT_BARRIER) @@ -1660,6 +1661,12 @@ xfs_alloc_buftarg( if (!btp->bt_bdi) goto error; + if (xfs_setsize_buftarg_early(btp, bdev)) + goto error; + + if (list_lru_init(&btp->bt_lru)) + goto error; + INIT_LIST_HEAD(&btp->bt_lru); spin_lock_init(&btp->bt_lru_lock); if (xfs_setsize_buftarg_early(btp, bdev)) diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 29d1ca567ed3..f019ccb20f77 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -648,11 +648,18 @@ xfs_qm_init_quotainfo( qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP); + if ((error = list_lru_init(&qinf->qi_lru))) { + kmem_free(qinf); + mp->m_quotainfo = NULL; + return error; + } + /* * See if quotainodes are setup, and if not, allocate them, * and change the superblock accordingly. */ if ((error = xfs_qm_init_quotainos(mp))) { + list_lru_destroy(&qinf->qi_lru); kmem_free(qinf); mp->m_quotainfo = NULL; return error; @@ -662,10 +669,13 @@ xfs_qm_init_quotainfo( INIT_RADIX_TREE(&qinf->qi_gquota_tree, GFP_NOFS); mutex_init(&qinf->qi_tree_lock); +<<<<<<< HEAD INIT_LIST_HEAD(&qinf->qi_lru_list); qinf->qi_lru_count = 0; mutex_init(&qinf->qi_lru_lock); +======= +>>>>>>> 5ca302c8e502 (list_lru: dynamically adjust node arrays) /* mutex used to serialize quotaoffs */ mutex_init(&qinf->qi_quotaofflock); @@ -751,6 +761,7 @@ xfs_qm_destroy_quotainfo( qi = mp->m_quotainfo; ASSERT(qi != NULL); + list_lru_destroy(&qi->qi_lru); unregister_shrinker(&qi->qi_shrinker); if (qi->qi_uquotaip) { diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h index 2fe13e1a809a..ff57503278d9 100644 --- a/include/linux/list_lru.h +++ b/include/linux/list_lru.h @@ -27,20 +27,11 @@ struct list_lru_node { } ____cacheline_aligned_in_smp; struct list_lru { - /* - * Because we use a fixed-size array, this struct can be very big if - * MAX_NUMNODES is big. If this becomes a problem this is fixable by - * turning this into a pointer and dynamically allocating this to - * nr_node_ids. This quantity is firwmare-provided, and still would - * provide room for all nodes at the cost of a pointer lookup and an - * extra allocation. Because that allocation will most likely come from - * a different slab cache than the main structure holding this - * structure, we may very well fail. - */ - struct list_lru_node node[MAX_NUMNODES]; + struct list_lru_node *node; nodemask_t active_nodes; }; +void list_lru_destroy(struct list_lru *lru); int list_lru_init(struct list_lru *lru); /** diff --git a/mm/list_lru.c b/mm/list_lru.c index 86cb55464f71..457ef31e5a19 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -8,6 +8,7 @@ #include #include #include +#include bool list_lru_add(struct list_lru *lru, struct list_head *item) { @@ -157,9 +158,14 @@ unsigned long list_lru_dispose_all(struct list_lru *lru, int list_lru_init(struct list_lru *lru) { int i; + size_t size = sizeof(*lru->node) * nr_node_ids; + + lru->node = kzalloc(size, GFP_KERNEL); + if (!lru->node) + return -ENOMEM; nodes_clear(lru->active_nodes); - for (i = 0; i < MAX_NUMNODES; i++) { + for (i = 0; i < nr_node_ids; i++) { spin_lock_init(&lru->node[i].lock); INIT_LIST_HEAD(&lru->node[i].list); lru->node[i].nr_items = 0; @@ -167,3 +173,9 @@ int list_lru_init(struct list_lru *lru) return 0; } EXPORT_SYMBOL_GPL(list_lru_init); + +void list_lru_destroy(struct list_lru *lru) +{ + kfree(lru->node); +} +EXPORT_SYMBOL_GPL(list_lru_destroy); -- GitLab From 34193aeec05fd0eebaaa672f9a05e71128ceab9a Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 30 Oct 2013 14:16:16 +0000 Subject: [PATCH 521/528] mm: list_lru: fix almost infinite loop causing effective livelock I've seen a fair number of issues with kswapd and other processes appearing to get stuck in v3.12-rc. Using sysrq-p many times seems to indicate that it gets stuck somewhere in list_lru_walk_node(), called from prune_icache_sb() and super_cache_scan(). I never seem to be able to trigger a calltrace for functions above that point. So I decided to add the following to super_cache_scan(): @@ -81,10 +81,14 @@ static unsigned long super_cache_scan(struct shrinker *shrink, inodes = list_lru_count_node(&sb->s_inode_lru, sc->nid); dentries = list_lru_count_node(&sb->s_dentry_lru, sc->nid); total_objects = dentries + inodes + fs_objects + 1; +printk("%s:%u: %s: dentries %lu inodes %lu total %lu\n", current->comm, current->pid, __func__, dentries, inodes, total_objects); /* proportion the scan between the caches */ dentries = mult_frac(sc->nr_to_scan, dentries, total_objects); inodes = mult_frac(sc->nr_to_scan, inodes, total_objects); +printk("%s:%u: %s: dentries %lu inodes %lu\n", current->comm, current->pid, __func__, dentries, inodes); +BUG_ON(dentries == 0); +BUG_ON(inodes == 0); /* * prune the dcache first as the icache is pinned by it, then @@ -99,7 +103,7 @@ static unsigned long super_cache_scan(struct shrinker *shrink, freed += sb->s_op->free_cached_objects(sb, fs_objects, sc->nid); } - +printk("%s:%u: %s: dentries %lu inodes %lu freed %lu\n", current->comm, current->pid, __func__, dentries, inodes, freed); drop_super(sb); return freed; } and shortly thereafter, having applied some pressure, I got this: update-apt-xapi:1616: super_cache_scan: dentries 25632 inodes 2 total 25635 update-apt-xapi:1616: super_cache_scan: dentries 1023 inodes 0 ------------[ cut here ]------------ Kernel BUG at c0101994 [verbose debug info unavailable] Internal error: Oops - BUG: 0 [#3] SMP ARM Modules linked in: fuse rfcomm bnep bluetooth hid_cypress CPU: 0 PID: 1616 Comm: update-apt-xapi Tainted: G D 3.12.0-rc7+ #154 task: daea1200 ti: c3bf8000 task.ti: c3bf8000 PC is at super_cache_scan+0x1c0/0x278 LR is at trace_hardirqs_on+0x14/0x18 Process update-apt-xapi (pid: 1616, stack limit = 0xc3bf8240) ... Backtrace: (super_cache_scan) from [] (shrink_slab+0x254/0x4c8) (shrink_slab) from [] (try_to_free_pages+0x3a0/0x5e0) (try_to_free_pages) from [] (__alloc_pages_nodemask+0x5) (__alloc_pages_nodemask) from [] (__pte_alloc+0x2c/0x13) (__pte_alloc) from [] (handle_mm_fault+0x84c/0x914) (handle_mm_fault) from [] (do_page_fault+0x1f0/0x3bc) (do_page_fault) from [] (do_translation_fault+0xac/0xb8) (do_translation_fault) from [] (do_DataAbort+0x38/0xa0) (do_DataAbort) from [] (__dabt_usr+0x38/0x40) Notice that we had a very low number of inodes, which were reduced to zero my mult_frac(). Now, prune_icache_sb() calls list_lru_walk_node() passing that number of inodes (0) into that as the number of objects to scan: long prune_icache_sb(struct super_block *sb, unsigned long nr_to_scan, int nid) { LIST_HEAD(freeable); long freed; freed = list_lru_walk_node(&sb->s_inode_lru, nid, inode_lru_isolate, &freeable, &nr_to_scan); which does: unsigned long list_lru_walk_node(struct list_lru *lru, int nid, list_lru_walk_cb isolate, void *cb_arg, unsigned long *nr_to_walk) { struct list_lru_node *nlru = &lru->node[nid]; struct list_head *item, *n; unsigned long isolated = 0; spin_lock(&nlru->lock); restart: list_for_each_safe(item, n, &nlru->list) { enum lru_status ret; /* * decrement nr_to_walk first so that we don't livelock if we * get stuck on large numbesr of LRU_RETRY items */ if (--(*nr_to_walk) == 0) break; So, if *nr_to_walk was zero when this function was entered, that means we're wanting to operate on (~0UL)+1 objects - which might as well be infinite. Clearly this is not correct behaviour. If we think about the behaviour of this function when *nr_to_walk is 1, then clearly it's wrong - we decrement first and then test for zero - which results in us doing nothing at all. A post-decrement would give the desired behaviour - we'd try to walk one object and one object only if *nr_to_walk were one. It also gives the correct behaviour for zero - we exit at this point. Fixes: 5cedf721a7cd ("list_lru: fix broken LRU_RETRY behaviour") Signed-off-by: Russell King Cc: Dave Chinner Cc: Al Viro Cc: Andrew Morton [ Modified to make sure we never underflow the count: this function gets called in a loop, so the 0 -> ~0ul transition is dangerous - Linus ] Signed-off-by: Linus Torvalds (cherry picked from commit c56b097af26cb11c1f49a4311ba538c825666fed) --- mm/list_lru.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/list_lru.c b/mm/list_lru.c index 457ef31e5a19..7a0423fb9600 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -81,8 +81,9 @@ restart: * decrement nr_to_walk first so that we don't livelock if we * get stuck on large numbesr of LRU_RETRY items */ - if (--(*nr_to_walk) == 0) + if (!*nr_to_walk) break; + --*nr_to_walk; ret = isolate(item, &nlru->lock, cb_arg); switch (ret) { -- GitLab From 967b9f2be0970f210868ff756bd76fe5aecb3c87 Mon Sep 17 00:00:00 2001 From: threader Date: Sat, 7 Aug 2021 21:55:05 +0200 Subject: [PATCH 522/528] mm: makefie: missed a 'new line' --- mm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/Makefile b/mm/Makefile index 2c8ded8c8bfa..9abb601d99f0 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -17,7 +17,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \ util.o mmzone.o vmstat.o backing-dev.o \ mm_init.o mmu_context.o percpu.o slab_common.o \ compaction.o balloon_compaction.o \ - interval_tree.o list_lru.o $(mmu-y) + interval_tree.o list_lru.o $(mmu-y) \ showmem.o vmpressure.o obj-y += init-mm.o -- GitLab From 4830fce8295b756fd71618812cae99619499f996 Mon Sep 17 00:00:00 2001 From: threader Date: Sun, 8 Aug 2021 14:44:25 +0200 Subject: [PATCH 523/528] Revert "UPSTREAM: binder: add flag to clear buffer on txn complete" This reverts commit 67d42f9d8a7c71e35f33fb4862aef67b0137f764. --- drivers/android/binder.c | 1 - drivers/android/binder_alloc.c | 159 ---------------------------- drivers/android/binder_alloc.h | 4 +- include/uapi/linux/android/binder.h | 1 - 4 files changed, 1 insertion(+), 164 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 7b402d8b37d6..acca2ccdb3f1 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3251,7 +3251,6 @@ static void binder_transaction(struct binder_proc *proc, t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; - t->buffer->clear_on_free = !!(t->flags & TF_CLEAR_BUF); trace_binder_transaction_alloc_buf(t->buffer); off_start = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 80b8efa8ab59..3fb71f60a9d3 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -642,8 +642,6 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, binder_insert_free_buffer(alloc, buffer); } -static void binder_alloc_clear_buf(struct binder_alloc *alloc, - struct binder_buffer *buffer); /** * binder_alloc_free_buf() - free a binder buffer * @alloc: binder_alloc for this proc @@ -654,18 +652,6 @@ static void binder_alloc_clear_buf(struct binder_alloc *alloc, void binder_alloc_free_buf(struct binder_alloc *alloc, struct binder_buffer *buffer) { - /* - * We could eliminate the call to binder_alloc_clear_buf() - * from binder_alloc_deferred_release() by moving this to - * binder_alloc_free_buf_locked(). However, that could - * increase contention for the alloc mutex if clear_on_free - * is used frequently for large buffers. The mutex is not - * needed for correctness here. - */ - if (buffer->clear_on_free) { - binder_alloc_clear_buf(alloc, buffer); - buffer->clear_on_free = false; - } mutex_lock(&alloc->mutex); binder_free_buf_locked(alloc, buffer); mutex_unlock(&alloc->mutex); @@ -773,10 +759,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) /* Transaction should already have been freed */ BUG_ON(buffer->transaction); - if (buffer->clear_on_free) { - binder_alloc_clear_buf(alloc, buffer); - buffer->clear_on_free = false; - } binder_free_buf_locked(alloc, buffer); buffers++; } @@ -897,144 +879,3 @@ void binder_alloc_init(struct binder_alloc *alloc) INIT_LIST_HEAD(&alloc->buffers); } - -/** - * check_buffer() - verify that buffer/offset is safe to access - * @alloc: binder_alloc for this proc - * @buffer: binder buffer to be accessed - * @offset: offset into @buffer data - * @bytes: bytes to access from offset - * - * Check that the @offset/@bytes are within the size of the given - * @buffer and that the buffer is currently active and not freeable. - * Offsets must also be multiples of sizeof(u32). The kernel is - * allowed to touch the buffer in two cases: - * - * 1) when the buffer is being created: - * (buffer->free == 0 && buffer->allow_user_free == 0) - * 2) when the buffer is being torn down: - * (buffer->free == 0 && buffer->transaction == NULL). - * - * Return: true if the buffer is safe to access - */ -static inline bool check_buffer(struct binder_alloc *alloc, - struct binder_buffer *buffer, - binder_size_t offset, size_t bytes) -{ - size_t buffer_size = binder_alloc_buffer_size(alloc, buffer); - - return buffer_size >= bytes && - offset <= buffer_size - bytes && - IS_ALIGNED(offset, sizeof(u32)) && - !buffer->free && - (!buffer->allow_user_free || !buffer->transaction); -} - -/** - * binder_alloc_get_page() - get kernel pointer for given buffer offset - * @alloc: binder_alloc for this proc - * @buffer: binder buffer to be accessed - * @buffer_offset: offset into @buffer data - * @pgoffp: address to copy final page offset to - * - * Lookup the struct page corresponding to the address - * at @buffer_offset into @buffer->data. If @pgoffp is not - * NULL, the byte-offset into the page is written there. - * - * The caller is responsible to ensure that the offset points - * to a valid address within the @buffer and that @buffer is - * not freeable by the user. Since it can't be freed, we are - * guaranteed that the corresponding elements of @alloc->pages[] - * cannot change. - * - * Return: struct page - */ -static struct page *binder_alloc_get_page(struct binder_alloc *alloc, - struct binder_buffer *buffer, - binder_size_t buffer_offset, - pgoff_t *pgoffp) -{ - binder_size_t buffer_space_offset = buffer_offset + - (buffer->data - alloc->buffer); - pgoff_t pgoff = buffer_space_offset & ~PAGE_MASK; - size_t index = buffer_space_offset >> PAGE_SHIFT; - struct binder_lru_page *lru_page; - - lru_page = &alloc->pages[index]; - *pgoffp = pgoff; - return lru_page->page_ptr; -} - -/** - * binder_alloc_clear_buf() - zero out buffer - * @alloc: binder_alloc for this proc - * @buffer: binder buffer to be cleared - * - * memset the given buffer to 0 - */ -static void binder_alloc_clear_buf(struct binder_alloc *alloc, - struct binder_buffer *buffer) -{ - size_t bytes = binder_alloc_buffer_size(alloc, buffer); - binder_size_t buffer_offset = 0; - - while (bytes) { - unsigned long size; - struct page *page; - pgoff_t pgoff; - void *kptr; - - page = binder_alloc_get_page(alloc, buffer, - buffer_offset, &pgoff); - size = min_t(size_t, bytes, PAGE_SIZE - pgoff); - kptr = kmap(page) + pgoff; - memset(kptr, 0, size); - kunmap(page); - bytes -= size; - buffer_offset += size; - } -} - -/** - * binder_alloc_copy_user_to_buffer() - copy src user to tgt user - * @alloc: binder_alloc for this proc - * @buffer: binder buffer to be accessed - * @buffer_offset: offset into @buffer data - * @from: userspace pointer to source buffer - * @bytes: bytes to copy - * - * Copy bytes from source userspace to target buffer. - * - * Return: bytes remaining to be copied - */ -unsigned long -binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc, - struct binder_buffer *buffer, - binder_size_t buffer_offset, - const void __user *from, - size_t bytes) -{ - if (!check_buffer(alloc, buffer, buffer_offset, bytes)) - return bytes; - - while (bytes) { - unsigned long size; - unsigned long ret; - struct page *page; - pgoff_t pgoff; - void *kptr; - - page = binder_alloc_get_page(alloc, buffer, - buffer_offset, &pgoff); - size = min_t(size_t, bytes, PAGE_SIZE - pgoff); - kptr = kmap(page) + pgoff; - ret = copy_from_user(kptr, from, size); - kunmap(page); - if (ret) - return bytes - size + ret; - bytes -= size; - from += size; - buffer_offset += size; - } - return 0; -} diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 3f211bc75d2f..bf5e2cca2649 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -30,7 +30,6 @@ struct binder_transaction; * @entry: entry alloc->buffers * @rb_node: node for allocated_buffers/free_buffers rb trees * @free: %true if buffer is free - * @clear_on_free: %true if buffer must be zeroed after use * @allow_user_free: %true if user is allowed to free buffer * @async_transaction: %true if buffer is in use for an async txn * @debug_id: unique ID for debugging @@ -49,10 +48,9 @@ struct binder_buffer { struct rb_node rb_node; /* free entry by size or allocated entry */ /* by address */ unsigned free:1; - unsigned clear_on_free:1; unsigned allow_user_free:1; unsigned async_transaction:1; - unsigned debug_id:28; + unsigned debug_id:29; struct binder_transaction *transaction; diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 2f6a91e91199..34e767e05153 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -309,7 +309,6 @@ enum transaction_flags { TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */ TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */ TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */ - TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */ }; struct binder_transaction_data { -- GitLab From 80a5357c2aa810801a3ac4361ce66bd208b93e47 Mon Sep 17 00:00:00 2001 From: threader Date: Sun, 8 Aug 2021 14:45:06 +0200 Subject: [PATCH 524/528] Revert "binder: create userspace-to-binder-buffer copy function" This reverts commit fb28e186b9faf19346dd18915cc9d1aab98c1264. --- drivers/android/binder.c | 29 +++++++---------------------- drivers/android/binder_alloc.c | 3 +-- drivers/android/binder_alloc.h | 8 -------- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index acca2ccdb3f1..6eafdb6f1a69 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3256,12 +3256,8 @@ static void binder_transaction(struct binder_proc *proc, ALIGN(tr->data_size, sizeof(void *))); offp = off_start; - if (binder_alloc_copy_user_to_buffer( - &target_proc->alloc, - t->buffer, 0, - (const void __user *) - (uintptr_t)tr->data.ptr.buffer, - tr->data_size)) { + if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) + tr->data.ptr.buffer, tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; @@ -3269,13 +3265,8 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_copy_data_failed; } - if (binder_alloc_copy_user_to_buffer( - &target_proc->alloc, - t->buffer, - ALIGN(tr->data_size, sizeof(void *)), - (const void __user *) - (uintptr_t)tr->data.ptr.offsets, - tr->offsets_size)) { + if (copy_from_user(offp, (const void __user *)(uintptr_t) + tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; @@ -3406,8 +3397,6 @@ static void binder_transaction(struct binder_proc *proc, struct binder_buffer_object *bp = to_binder_buffer_object(hdr); size_t buf_left = sg_buf_end - sg_bufp; - binder_size_t sg_buf_offset = (uintptr_t)sg_bufp - - (uintptr_t)t->buffer->data; if (bp->length > buf_left) { binder_user_error("%d:%d got transaction with too large buffer\n", @@ -3417,13 +3406,9 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_bad_offset; } - if (binder_alloc_copy_user_to_buffer( - &target_proc->alloc, - t->buffer, - sg_buf_offset, - (const void __user *) - (uintptr_t)bp->buffer, - bp->length)) { + if (copy_from_user(sg_bufp, + (const void __user *)(uintptr_t) + bp->buffer, bp->length)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error_param = -EFAULT; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 3fb71f60a9d3..5da250be7e99 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -28,9 +28,8 @@ #include #include #include -#include -#include #include +#include #include "binder_alloc.h" #include "binder_trace.h" diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index bf5e2cca2649..8f23c184ec72 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -21,7 +21,6 @@ #include #include #include -#include struct binder_transaction; @@ -167,12 +166,5 @@ binder_alloc_get_user_buffer_offset(struct binder_alloc *alloc) return alloc->user_buffer_offset; } -unsigned long -binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc, - struct binder_buffer *buffer, - binder_size_t buffer_offset, - const void __user *from, - size_t bytes); - #endif /* _LINUX_BINDER_ALLOC_H */ -- GitLab From 6475964634d2a664c0bb1ad212b9758f7f02d207 Mon Sep 17 00:00:00 2001 From: threader Date: Sun, 8 Aug 2021 15:21:53 +0200 Subject: [PATCH 525/528] Revert "list_lru: dynamically adjust node arrays" This reverts commit b72bdd1bf94b9d538c53c95a85c67e5bc07b45aa. --- fs/super.c | 12 ++---------- fs/xfs/xfs_buf.c | 7 ------- fs/xfs/xfs_qm.c | 11 ----------- include/linux/list_lru.h | 13 +++++++++++-- mm/list_lru.c | 14 +------------- 5 files changed, 14 insertions(+), 43 deletions(-) diff --git a/fs/super.c b/fs/super.c index c1f79fbc9f02..55a171fe9d7f 100644 --- a/fs/super.c +++ b/fs/super.c @@ -34,7 +34,6 @@ #include #include #include -#include #include "internal.h" @@ -171,12 +170,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) INIT_HLIST_NODE(&s->s_instances); INIT_HLIST_BL_HEAD(&s->s_anon); INIT_LIST_HEAD(&s->s_inodes); - - if (list_lru_init(&s->s_dentry_lru)) - goto err_out; - if (list_lru_init(&s->s_inode_lru)) - goto err_out_dentry_lru; - + INIT_LIST_HEAD(&s->s_dentry_lru); + INIT_LIST_HEAD(&s->s_inode_lru); spin_lock_init(&s->s_inode_lru_lock); INIT_LIST_HEAD(&s->s_mounts); init_rwsem(&s->s_umount); @@ -215,9 +210,6 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) } out: return s; - -err_out_dentry_lru: - list_lru_destroy(&s->s_dentry_lru); err_out: security_sb_free(s); destroy_sb_writers(s); diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index fc8b461cadc1..8ff89db9e663 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1586,7 +1586,6 @@ xfs_free_buftarg( struct xfs_mount *mp, struct xfs_buftarg *btp) { - list_lru_destroy(&btp->bt_lru); unregister_shrinker(&btp->bt_shrinker); if (mp->m_flags & XFS_MOUNT_BARRIER) @@ -1661,12 +1660,6 @@ xfs_alloc_buftarg( if (!btp->bt_bdi) goto error; - if (xfs_setsize_buftarg_early(btp, bdev)) - goto error; - - if (list_lru_init(&btp->bt_lru)) - goto error; - INIT_LIST_HEAD(&btp->bt_lru); spin_lock_init(&btp->bt_lru_lock); if (xfs_setsize_buftarg_early(btp, bdev)) diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index f019ccb20f77..29d1ca567ed3 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -648,18 +648,11 @@ xfs_qm_init_quotainfo( qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP); - if ((error = list_lru_init(&qinf->qi_lru))) { - kmem_free(qinf); - mp->m_quotainfo = NULL; - return error; - } - /* * See if quotainodes are setup, and if not, allocate them, * and change the superblock accordingly. */ if ((error = xfs_qm_init_quotainos(mp))) { - list_lru_destroy(&qinf->qi_lru); kmem_free(qinf); mp->m_quotainfo = NULL; return error; @@ -669,13 +662,10 @@ xfs_qm_init_quotainfo( INIT_RADIX_TREE(&qinf->qi_gquota_tree, GFP_NOFS); mutex_init(&qinf->qi_tree_lock); -<<<<<<< HEAD INIT_LIST_HEAD(&qinf->qi_lru_list); qinf->qi_lru_count = 0; mutex_init(&qinf->qi_lru_lock); -======= ->>>>>>> 5ca302c8e502 (list_lru: dynamically adjust node arrays) /* mutex used to serialize quotaoffs */ mutex_init(&qinf->qi_quotaofflock); @@ -761,7 +751,6 @@ xfs_qm_destroy_quotainfo( qi = mp->m_quotainfo; ASSERT(qi != NULL); - list_lru_destroy(&qi->qi_lru); unregister_shrinker(&qi->qi_shrinker); if (qi->qi_uquotaip) { diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h index ff57503278d9..2fe13e1a809a 100644 --- a/include/linux/list_lru.h +++ b/include/linux/list_lru.h @@ -27,11 +27,20 @@ struct list_lru_node { } ____cacheline_aligned_in_smp; struct list_lru { - struct list_lru_node *node; + /* + * Because we use a fixed-size array, this struct can be very big if + * MAX_NUMNODES is big. If this becomes a problem this is fixable by + * turning this into a pointer and dynamically allocating this to + * nr_node_ids. This quantity is firwmare-provided, and still would + * provide room for all nodes at the cost of a pointer lookup and an + * extra allocation. Because that allocation will most likely come from + * a different slab cache than the main structure holding this + * structure, we may very well fail. + */ + struct list_lru_node node[MAX_NUMNODES]; nodemask_t active_nodes; }; -void list_lru_destroy(struct list_lru *lru); int list_lru_init(struct list_lru *lru); /** diff --git a/mm/list_lru.c b/mm/list_lru.c index 7a0423fb9600..8b0076a1f681 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -8,7 +8,6 @@ #include #include #include -#include bool list_lru_add(struct list_lru *lru, struct list_head *item) { @@ -159,14 +158,9 @@ unsigned long list_lru_dispose_all(struct list_lru *lru, int list_lru_init(struct list_lru *lru) { int i; - size_t size = sizeof(*lru->node) * nr_node_ids; - - lru->node = kzalloc(size, GFP_KERNEL); - if (!lru->node) - return -ENOMEM; nodes_clear(lru->active_nodes); - for (i = 0; i < nr_node_ids; i++) { + for (i = 0; i < MAX_NUMNODES; i++) { spin_lock_init(&lru->node[i].lock); INIT_LIST_HEAD(&lru->node[i].list); lru->node[i].nr_items = 0; @@ -174,9 +168,3 @@ int list_lru_init(struct list_lru *lru) return 0; } EXPORT_SYMBOL_GPL(list_lru_init); - -void list_lru_destroy(struct list_lru *lru) -{ - kfree(lru->node); -} -EXPORT_SYMBOL_GPL(list_lru_destroy); -- GitLab From 54d72501eedcce47135041964c1b08969e886a3b Mon Sep 17 00:00:00 2001 From: threader Date: Sun, 8 Aug 2021 15:55:06 +0200 Subject: [PATCH 526/528] BINDER: set module_params according to google master and ratelimit debug --- drivers/android/binder_alloc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 5da250be7e99..03f28867bc07 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include "binder_alloc.h" @@ -43,12 +44,12 @@ enum { static uint32_t binder_alloc_debug_mask; module_param_named(debug_mask, binder_alloc_debug_mask, - uint, S_IWUSR | S_IRUGO); + uint, 0644); #define binder_alloc_debug(mask, x...) \ do { \ if (binder_alloc_debug_mask & mask) \ - pr_info(x); \ + pr_info_ratelimited(x); \ } while (0) static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer) -- GitLab From 5a9f749270cd0121c2d0472e5e7b9b6239f41c80 Mon Sep 17 00:00:00 2001 From: Bernhard Thoben Date: Thu, 26 Aug 2021 18:35:44 +0200 Subject: [PATCH 527/528] defconfig: kitakami: Set "CONFIG_KEYS_DEBUG_PROC_KEYS=y". This option turns on support for the /proc/keys file. Please take a look into the file kernel/sony/msm8994/security/keys/Kconfig for more information. --- arch/arm64/configs/kitakami_ivy_defconfig | 1 + arch/arm64/configs/kitakami_karin_defconfig | 1 + arch/arm64/configs/kitakami_karin_windy_defconfig | 1 + arch/arm64/configs/kitakami_satsuki_defconfig | 1 + arch/arm64/configs/kitakami_sumire_defconfig | 1 + arch/arm64/configs/kitakami_suzuran_defconfig | 1 + 6 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/kitakami_ivy_defconfig b/arch/arm64/configs/kitakami_ivy_defconfig index 51aa7eb61d83..c80a944e5b6d 100644 --- a/arch/arm64/configs/kitakami_ivy_defconfig +++ b/arch/arm64/configs/kitakami_ivy_defconfig @@ -262,6 +262,7 @@ CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_JOYSTICK_XPAD=y CONFIG_KERNEL_TEXT_MPU_PROT=y CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_KEYS=y CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y # CONFIG_KSM is not set diff --git a/arch/arm64/configs/kitakami_karin_defconfig b/arch/arm64/configs/kitakami_karin_defconfig index 60972a938ea3..eb3366ba50ef 100644 --- a/arch/arm64/configs/kitakami_karin_defconfig +++ b/arch/arm64/configs/kitakami_karin_defconfig @@ -250,6 +250,7 @@ CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_JOYSTICK_XPAD=y CONFIG_KERNEL_TEXT_MPU_PROT=y CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_KEYS=y CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y CONFIG_KSM=y diff --git a/arch/arm64/configs/kitakami_karin_windy_defconfig b/arch/arm64/configs/kitakami_karin_windy_defconfig index bbc704f4b8aa..206be11b10dc 100644 --- a/arch/arm64/configs/kitakami_karin_windy_defconfig +++ b/arch/arm64/configs/kitakami_karin_windy_defconfig @@ -253,6 +253,7 @@ CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_JOYSTICK_XPAD=y CONFIG_KERNEL_TEXT_MPU_PROT=y CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_KEYS=y CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y CONFIG_KSM=y diff --git a/arch/arm64/configs/kitakami_satsuki_defconfig b/arch/arm64/configs/kitakami_satsuki_defconfig index 8dd4ccc3a15f..23aaa8a2fe1b 100644 --- a/arch/arm64/configs/kitakami_satsuki_defconfig +++ b/arch/arm64/configs/kitakami_satsuki_defconfig @@ -263,6 +263,7 @@ CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_JOYSTICK_XPAD=y CONFIG_KERNEL_TEXT_MPU_PROT=y CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_KEYS=y CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y # CONFIG_KSM is not set diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index 354e0463e289..02582a3ca270 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -264,6 +264,7 @@ CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_JOYSTICK_XPAD=y CONFIG_KERNEL_TEXT_MPU_PROT=y CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_KEYS=y CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y # CONFIG_KSM is not set diff --git a/arch/arm64/configs/kitakami_suzuran_defconfig b/arch/arm64/configs/kitakami_suzuran_defconfig index 8025b8665642..2ecb42d385ea 100644 --- a/arch/arm64/configs/kitakami_suzuran_defconfig +++ b/arch/arm64/configs/kitakami_suzuran_defconfig @@ -262,6 +262,7 @@ CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_JOYSTICK_XPAD=y CONFIG_KERNEL_TEXT_MPU_PROT=y CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_KEYS=y CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y # CONFIG_KSM is not set -- GitLab From 00e2feed03239779d8addc36fa856bf6b8f0bc6d Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Tue, 19 Nov 2019 12:50:48 +0100 Subject: [PATCH 528/528] ARM: dts: Early mount /lta-label * Userspace needs it for model detection. Change-Id: Id47e30fb941fc1fd6822d0d3ba32cd5e7572b2b5 --- .../boot/dts/qcom/msm8994-kitakami_common.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi index c4ab74e8e0fc..e57c40675fbd 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi @@ -1114,6 +1114,21 @@ }; }; +&firmware { + android { + fstab { + android_lta_label: lta-label { + compatible = "android,lta-label"; + dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/LTALabel"; + type = "ext4"; + mnt_flags = "ro,barrier=1"; + fsmgr_flags = "nofail"; + status = "ok"; + }; + }; + }; +}; + &usb3 { qcom,usb_dp-vadc = <&pmi8994_vadc>; qcom,usb_dm-vadc = <&pmi8994_vadc>; -- GitLab